summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafael H. Schloming <rhs@apache.org>2009-12-26 12:42:57 +0000
committerRafael H. Schloming <rhs@apache.org>2009-12-26 12:42:57 +0000
commit248f1fe188fe2307b9dcf2c87a83b653eaa1920c (patch)
treed5d0959a70218946ff72e107a6c106e32479a398
parent3c83a0e3ec7cf4dc23e83a340b25f5fc1676f937 (diff)
downloadqpid-python-248f1fe188fe2307b9dcf2c87a83b653eaa1920c.tar.gz
synchronized with trunk except for ruby dir
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/qpid.rnr@893970 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--KEYS255
-rw-r--r--LICENSE7
-rw-r--r--NOTICE8
-rw-r--r--bin/LICENSE206
-rw-r--r--bin/NOTICE8
-rwxr-xr-xbin/mvn-deploy-qpid-java.sh71
-rwxr-xr-xbin/release.sh251
-rw-r--r--buildtools/LICENSE206
-rw-r--r--buildtools/NOTICE8
-rw-r--r--buildtools/buildCreator/build.config37
-rwxr-xr-xbuildtools/buildCreator/buildCreator.py1464
-rw-r--r--buildtools/buildCreator/qpid.build55
-rw-r--r--cc/LICENSE206
-rw-r--r--cc/NOTICE8
-rw-r--r--cc/README30
-rw-r--r--cc/config.properties23
-rw-r--r--cc/config.xml5
-rw-r--r--cc/config/dotnet-trunk.xml63
-rw-r--r--cc/config/java/jndi.properties21
-rw-r--r--cc/scripts/dotnetbuild.sh21
-rw-r--r--cc/scripts/javajmstck.sh18
-rwxr-xr-xcc/scripts/verify2
-rwxr-xr-xcc/scripts/verify_all42
-rw-r--r--cpp/BuildInstallSettings.cmake132
-rw-r--r--cpp/CMakeLists.txt101
-rwxr-xr-xcpp/CTestConfig.cmake13
-rw-r--r--cpp/DESIGN3
-rw-r--r--cpp/INSTALL58
-rw-r--r--cpp/INSTALL-WINDOWS153
-rw-r--r--cpp/LICENSE31
-rw-r--r--cpp/Makefile.am53
-rw-r--r--cpp/NOTICE6
-rw-r--r--cpp/README17
-rw-r--r--cpp/RELEASE_NOTES48
-rw-r--r--cpp/SSL71
-rw-r--r--cpp/bindings/qmf/Makefile.am33
-rw-r--r--cpp/bindings/qmf/python/Makefile.am48
-rw-r--r--cpp/bindings/qmf/python/python.i143
-rw-r--r--cpp/bindings/qmf/python/qmf.py1540
-rw-r--r--cpp/bindings/qmf/qmfengine.i58
-rw-r--r--cpp/bindings/qmf/ruby/Makefile.am44
-rw-r--r--cpp/bindings/qmf/ruby/qmf.rb1343
-rw-r--r--cpp/bindings/qmf/ruby/ruby.i106
-rw-r--r--cpp/bindings/qmf/tests/Makefile.am27
-rwxr-xr-xcpp/bindings/qmf/tests/agent_ruby.rb204
-rw-r--r--cpp/bindings/qmf/tests/python_agent.py230
-rwxr-xr-xcpp/bindings/qmf/tests/python_console.py178
-rwxr-xr-xcpp/bindings/qmf/tests/ruby_console.rb174
-rwxr-xr-xcpp/bindings/qmf/tests/ruby_console_test.rb234
-rwxr-xr-xcpp/bindings/qmf/tests/run_interop_tests121
-rw-r--r--cpp/bindings/qmf/tests/test_base.rb73
-rw-r--r--cpp/boost-1.32-support/Makefile1
-rw-r--r--cpp/boost-1.32-support/main.patch149
-rw-r--r--cpp/boost-1.32-support/supressions867
-rwxr-xr-xcpp/bootstrap2
-rwxr-xr-xcpp/build-aux/ltmain.sh6871
-rw-r--r--cpp/configure.ac242
-rw-r--r--cpp/docs/api/CMakeLists.txt40
-rw-r--r--cpp/docs/api/Makefile.am25
-rw-r--r--cpp/docs/api/developer.doxygen.in24
-rw-r--r--cpp/docs/api/doxygen.css494
-rw-r--r--cpp/docs/api/doxygen_mainpage.h133
-rw-r--r--cpp/docs/api/footer.html31
-rw-r--r--cpp/docs/api/header.html50
-rw-r--r--cpp/docs/api/stylesheet.css494
-rw-r--r--cpp/docs/api/tabs.css123
-rw-r--r--cpp/docs/api/user.doxygen.in58
-rw-r--r--cpp/docs/man/Makefile.am20
-rw-r--r--cpp/docs/man/qpidd.x6
-rw-r--r--cpp/etc/CMakeLists.txt20
-rw-r--r--cpp/etc/Makefile.am24
-rw-r--r--cpp/etc/qpidc.conf23
-rwxr-xr-xcpp/etc/qpidd20
-rw-r--r--cpp/etc/qpidd.conf27
-rw-r--r--cpp/etc/sasl2/qpidd.conf23
-rw-r--r--cpp/examples/CMakeLists.txt100
-rw-r--r--cpp/examples/Makefile.am38
-rw-r--r--cpp/examples/README26
-rw-r--r--cpp/examples/README.txt165
-rw-r--r--cpp/examples/direct/CMakeLists.txt22
-rw-r--r--cpp/examples/direct/Makefile.am26
-rw-r--r--cpp/examples/direct/declare_queues.cpp25
-rw-r--r--cpp/examples/direct/direct_declare_queues.vcproj394
-rw-r--r--cpp/examples/direct/direct_direct_producer.vcproj394
-rw-r--r--cpp/examples/direct/direct_listener.vcproj394
-rw-r--r--cpp/examples/direct/direct_producer.cpp26
-rw-r--r--cpp/examples/direct/listener.cpp28
-rw-r--r--cpp/examples/direct/verify20
-rw-r--r--cpp/examples/examples.sln315
-rw-r--r--cpp/examples/failover/CMakeLists.txt22
-rw-r--r--cpp/examples/failover/Makefile.am47
-rw-r--r--cpp/examples/failover/declare_queues.cpp61
-rw-r--r--cpp/examples/failover/failover_declare_queues.vcproj394
-rw-r--r--cpp/examples/failover/failover_replaying_sender.vcproj394
-rw-r--r--cpp/examples/failover/failover_resuming_receiver.vcproj394
-rw-r--r--cpp/examples/failover/replaying_sender.cpp97
-rw-r--r--cpp/examples/failover/resuming_receiver.cpp127
-rw-r--r--cpp/examples/fanout/CMakeLists.txt21
-rw-r--r--cpp/examples/fanout/Makefile.am29
-rw-r--r--cpp/examples/fanout/fanout_fanout_producer.vcproj394
-rw-r--r--cpp/examples/fanout/fanout_listener.vcproj394
-rw-r--r--cpp/examples/fanout/fanout_producer.cpp24
-rw-r--r--cpp/examples/fanout/listener.cpp26
-rw-r--r--cpp/examples/fanout/verify19
-rw-r--r--cpp/examples/makedist.mk23
-rw-r--r--cpp/examples/messaging/CMakeLists.txt35
-rw-r--r--cpp/examples/messaging/Makefile.am67
-rw-r--r--cpp/examples/messaging/client.cpp76
-rw-r--r--cpp/examples/messaging/drain.cpp125
-rw-r--r--cpp/examples/messaging/map_receiver.cpp56
-rw-r--r--cpp/examples/messaging/map_sender.cpp69
-rw-r--r--cpp/examples/messaging/messaging_client.vcproj411
-rw-r--r--cpp/examples/messaging/messaging_map_receiver.vcproj411
-rw-r--r--cpp/examples/messaging/messaging_map_sender.vcproj411
-rw-r--r--cpp/examples/messaging/messaging_queue_listener.vcproj411
-rw-r--r--cpp/examples/messaging/messaging_queue_receiver.vcproj411
-rw-r--r--cpp/examples/messaging/messaging_queue_sender.vcproj411
-rw-r--r--cpp/examples/messaging/messaging_server.vcproj411
-rw-r--r--cpp/examples/messaging/messaging_topic_listener.vcproj411
-rw-r--r--cpp/examples/messaging/messaging_topic_receiver.vcproj411
-rw-r--r--cpp/examples/messaging/messaging_topic_sender.vcproj411
-rw-r--r--cpp/examples/messaging/queue_receiver.cpp59
-rw-r--r--cpp/examples/messaging/queue_sender.cpp60
-rw-r--r--cpp/examples/messaging/readme.txt146
-rw-r--r--cpp/examples/messaging/server.cpp76
-rw-r--r--cpp/examples/messaging/spout.cpp190
-rw-r--r--cpp/examples/messaging/topic_receiver.cpp59
-rw-r--r--cpp/examples/messaging/topic_sender.cpp78
-rw-r--r--cpp/examples/pub-sub/CMakeLists.txt21
-rw-r--r--cpp/examples/pub-sub/Makefile.am29
-rw-r--r--cpp/examples/pub-sub/pub-sub_topic_listener.vcproj394
-rw-r--r--cpp/examples/pub-sub/pub-sub_topic_publisher.vcproj394
-rw-r--r--cpp/examples/pub-sub/topic_listener.cpp44
-rw-r--r--cpp/examples/pub-sub/topic_publisher.cpp37
-rw-r--r--cpp/examples/pub-sub/verify19
-rw-r--r--cpp/examples/qmf-agent/Makefile12
-rw-r--r--cpp/examples/qmf-agent/example.cpp85
-rw-r--r--cpp/examples/qmf-agent/example_gen.mak10
-rw-r--r--cpp/examples/qmf-agent/qmf_agent.vcproj443
-rw-r--r--cpp/examples/qmf-agent/schema.xml11
-rw-r--r--cpp/examples/qmf-console/CMakeLists.txt23
-rw-r--r--cpp/examples/qmf-console/Makefile.am55
-rw-r--r--cpp/examples/qmf-console/cluster-qmon.cpp179
-rw-r--r--cpp/examples/qmf-console/console.cpp150
-rw-r--r--cpp/examples/qmf-console/ping.cpp134
-rw-r--r--cpp/examples/qmf-console/printevents.cpp125
-rw-r--r--cpp/examples/qmf-console/qmf-console_console.vcproj394
-rw-r--r--cpp/examples/qmf-console/qmf-console_ping.vcproj419
-rw-r--r--cpp/examples/qmf-console/qmf-console_printevents.vcproj394
-rw-r--r--cpp/examples/qmf-console/qmf-console_queuestats.vcproj394
-rw-r--r--cpp/examples/qmf-console/queuestats.cpp142
-rw-r--r--cpp/examples/request-response/CMakeLists.txt21
-rw-r--r--cpp/examples/request-response/Makefile.am29
-rw-r--r--cpp/examples/request-response/client.cpp43
-rw-r--r--cpp/examples/request-response/request-response_client.vcproj394
-rw-r--r--cpp/examples/request-response/request-response_server.vcproj394
-rw-r--r--cpp/examples/request-response/server.cpp36
-rw-r--r--cpp/examples/request-response/verify19
-rw-r--r--cpp/examples/test.txt1
-rw-r--r--cpp/examples/tradedemo/CMakeLists.txt22
-rw-r--r--cpp/examples/tradedemo/Makefile.am46
-rw-r--r--cpp/examples/tradedemo/declare_queues.cpp98
-rw-r--r--cpp/examples/tradedemo/topic_listener.cpp183
-rw-r--r--cpp/examples/tradedemo/topic_publisher.cpp271
-rw-r--r--cpp/examples/tradedemo/tradedemo_declare_queues.vcproj394
-rw-r--r--cpp/examples/tradedemo/tradedemo_topic_listener.vcproj394
-rw-r--r--cpp/examples/tradedemo/tradedemo_topic_publisher.vcproj394
-rwxr-xr-xcpp/examples/verify48
-rwxr-xr-xcpp/examples/verify_all32
-rw-r--r--cpp/examples/xml-exchange/CMakeLists.txt24
-rw-r--r--cpp/examples/xml-exchange/Makefile.am22
-rw-r--r--cpp/examples/xml-exchange/declare_queues.cpp26
-rw-r--r--cpp/examples/xml-exchange/listener.cpp28
-rw-r--r--cpp/examples/xml-exchange/xml_producer.cpp26
-rw-r--r--cpp/include/qmf/Agent.h287
-rw-r--r--cpp/include/qmf/AgentObject.h95
-rw-r--r--cpp/include/qmf/Connection.h125
-rw-r--r--cpp/include/qmf/ConnectionSettings.h32
-rw-r--r--cpp/include/qmf/ConsoleObject.h94
-rw-r--r--cpp/include/qmf/QmfImportExport.h33
-rw-r--r--cpp/include/qmf/engine/Agent.h209
-rw-r--r--cpp/include/qmf/engine/ConnectionSettings.h150
-rw-r--r--cpp/include/qmf/engine/Console.h236
-rw-r--r--cpp/include/qmf/engine/Event.h32
-rw-r--r--cpp/include/qmf/engine/Message.h41
-rw-r--r--cpp/include/qmf/engine/Object.h56
-rw-r--r--cpp/include/qmf/engine/ObjectId.h67
-rw-r--r--cpp/include/qmf/engine/QmfEngineImportExport.h33
-rw-r--r--cpp/include/qmf/engine/Query.h112
-rw-r--r--cpp/include/qmf/engine/ResilientConnection.h165
-rw-r--r--cpp/include/qmf/engine/Schema.h210
-rw-r--r--cpp/include/qmf/engine/Typecode.h53
-rw-r--r--cpp/include/qmf/engine/Value.h121
-rwxr-xr-xcpp/include/qpid/Address.h85
-rw-r--r--cpp/include/qpid/CommonImportExport.h33
-rw-r--r--cpp/include/qpid/Exception.h93
-rw-r--r--cpp/include/qpid/InlineAllocator.h101
-rw-r--r--cpp/include/qpid/InlineVector.h68
-rw-r--r--cpp/include/qpid/Msg.h76
-rw-r--r--cpp/include/qpid/Options.h265
-rw-r--r--cpp/include/qpid/RangeSet.h330
-rw-r--r--cpp/include/qpid/SessionId.h60
-rw-r--r--cpp/include/qpid/Url.h93
-rw-r--r--cpp/include/qpid/agent/ManagementAgent.h163
-rw-r--r--cpp/include/qpid/agent/QmfAgentImportExport.h33
-rw-r--r--cpp/include/qpid/client/AsyncSession.h38
-rw-r--r--cpp/include/qpid/client/ClientImportExport.h33
-rw-r--r--cpp/include/qpid/client/Completion.h71
-rw-r--r--cpp/include/qpid/client/Connection.h222
-rw-r--r--cpp/include/qpid/client/ConnectionSettings.h133
-rw-r--r--cpp/include/qpid/client/FailoverListener.h81
-rw-r--r--cpp/include/qpid/client/FailoverManager.h137
-rw-r--r--cpp/include/qpid/client/FlowControl.h75
-rw-r--r--cpp/include/qpid/client/Future.h59
-rw-r--r--cpp/include/qpid/client/FutureCompletion.h49
-rw-r--r--cpp/include/qpid/client/FutureResult.h49
-rw-r--r--cpp/include/qpid/client/Handle.h71
-rw-r--r--cpp/include/qpid/client/LocalQueue.h120
-rw-r--r--cpp/include/qpid/client/Message.h175
-rw-r--r--cpp/include/qpid/client/MessageListener.h101
-rw-r--r--cpp/include/qpid/client/MessageReplayTracker.h73
-rw-r--r--cpp/include/qpid/client/QueueOptions.h129
-rw-r--r--cpp/include/qpid/client/Session.h39
-rw-r--r--cpp/include/qpid/client/SessionBase_0_10.h109
-rw-r--r--cpp/include/qpid/client/Subscription.h123
-rw-r--r--cpp/include/qpid/client/SubscriptionManager.h292
-rw-r--r--cpp/include/qpid/client/SubscriptionSettings.h123
-rw-r--r--cpp/include/qpid/client/TypedResult.h65
-rw-r--r--cpp/include/qpid/client/amqp0_10/Codecs.h61
-rw-r--r--cpp/include/qpid/console/Agent.h58
-rw-r--r--cpp/include/qpid/console/Broker.h133
-rw-r--r--cpp/include/qpid/console/ClassKey.h66
-rw-r--r--cpp/include/qpid/console/ConsoleImportExport.h33
-rw-r--r--cpp/include/qpid/console/ConsoleListener.h97
-rw-r--r--cpp/include/qpid/console/Event.h86
-rw-r--r--cpp/include/qpid/console/Object.h123
-rw-r--r--cpp/include/qpid/console/ObjectId.h69
-rw-r--r--cpp/include/qpid/console/Package.h78
-rw-r--r--cpp/include/qpid/console/Schema.h105
-rw-r--r--cpp/include/qpid/console/SequenceManager.h54
-rw-r--r--cpp/include/qpid/console/SessionManager.h205
-rw-r--r--cpp/include/qpid/console/Value.h213
-rw-r--r--cpp/include/qpid/framing/Array.h97
-rw-r--r--cpp/include/qpid/framing/Buffer.h136
-rw-r--r--cpp/include/qpid/framing/FieldTable.h128
-rw-r--r--cpp/include/qpid/framing/FieldValue.h435
-rw-r--r--cpp/include/qpid/framing/List.h77
-rw-r--r--cpp/include/qpid/framing/ProtocolVersion.h58
-rw-r--r--cpp/include/qpid/framing/SequenceNumber.h79
-rw-r--r--cpp/include/qpid/framing/SequenceSet.h69
-rw-r--r--cpp/include/qpid/framing/StructHelper.h57
-rw-r--r--cpp/include/qpid/framing/Uuid.h90
-rw-r--r--cpp/include/qpid/framing/amqp_types.h66
-rw-r--r--cpp/include/qpid/framing/amqp_types_full.h38
-rw-r--r--cpp/include/qpid/log/Logger.h114
-rw-r--r--cpp/include/qpid/log/Options.h50
-rw-r--r--cpp/include/qpid/log/Selector.h71
-rw-r--r--cpp/include/qpid/log/SinkOptions.h64
-rw-r--r--cpp/include/qpid/log/Statement.h121
-rw-r--r--cpp/include/qpid/management/Args.h44
-rw-r--r--cpp/include/qpid/management/Manageable.h72
-rw-r--r--cpp/include/qpid/management/ManagementEvent.h49
-rw-r--r--cpp/include/qpid/management/ManagementObject.h187
-rw-r--r--cpp/include/qpid/messaging/Address.h176
-rw-r--r--cpp/include/qpid/messaging/Codec.h44
-rw-r--r--cpp/include/qpid/messaging/Connection.h105
-rw-r--r--cpp/include/qpid/messaging/ListContent.h90
-rw-r--r--cpp/include/qpid/messaging/ListView.h67
-rw-r--r--cpp/include/qpid/messaging/MapContent.h90
-rw-r--r--cpp/include/qpid/messaging/MapView.h70
-rw-r--r--cpp/include/qpid/messaging/Message.h76
-rw-r--r--cpp/include/qpid/messaging/Receiver.h130
-rw-r--r--cpp/include/qpid/messaging/Sender.h86
-rw-r--r--cpp/include/qpid/messaging/Session.h148
-rw-r--r--cpp/include/qpid/messaging/Variant.h168
-rw-r--r--cpp/include/qpid/sys/Condition.h33
-rw-r--r--cpp/include/qpid/sys/ExceptionHolder.h74
-rw-r--r--cpp/include/qpid/sys/IOHandle.h49
-rwxr-xr-xcpp/include/qpid/sys/IntegerTypes.h31
-rw-r--r--cpp/include/qpid/sys/Monitor.h49
-rw-r--r--cpp/include/qpid/sys/Mutex.h91
-rw-r--r--cpp/include/qpid/sys/Runnable.h51
-rw-r--r--cpp/include/qpid/sys/StrError.h36
-rw-r--r--cpp/include/qpid/sys/SystemInfo.h85
-rw-r--r--cpp/include/qpid/sys/Thread.h65
-rw-r--r--cpp/include/qpid/sys/Time.h173
-rw-r--r--cpp/include/qpid/sys/posix/Condition.h86
-rwxr-xr-xcpp/include/qpid/sys/posix/IntegerTypes.h26
-rw-r--r--cpp/include/qpid/sys/posix/Mutex.h158
-rw-r--r--cpp/include/qpid/sys/posix/PrivatePosix.h77
-rwxr-xr-xcpp/include/qpid/sys/posix/Time.h34
-rw-r--r--cpp/include/qpid/sys/posix/check.h52
-rwxr-xr-xcpp/include/qpid/sys/windows/Condition.h80
-rwxr-xr-xcpp/include/qpid/sys/windows/IntegerTypes.h36
-rwxr-xr-xcpp/include/qpid/sys/windows/Mutex.h188
-rw-r--r--cpp/include/qpid/sys/windows/Time.h36
-rwxr-xr-xcpp/include/qpid/sys/windows/check.h48
-rw-r--r--cpp/m4/ac_pkg_swig.m4118
-rw-r--r--cpp/m4/extensions.m47
-rw-r--r--cpp/m4/python.m4168
-rwxr-xr-xcpp/make-dist22
-rw-r--r--cpp/managementgen/CMakeLists.txt26
-rw-r--r--cpp/managementgen/Makefile.am61
-rwxr-xr-xcpp/managementgen/generate.py300
-rwxr-xr-xcpp/managementgen/main.py52
-rw-r--r--cpp/managementgen/managementgen26
-rwxr-xr-xcpp/managementgen/qmf-gen90
-rw-r--r--cpp/managementgen/qmfgen/__init__.py19
-rwxr-xr-xcpp/managementgen/qmfgen/generate.py468
-rw-r--r--cpp/managementgen/qmfgen/management-types.xml56
-rwxr-xr-xcpp/managementgen/qmfgen/schema.py1348
-rw-r--r--cpp/managementgen/qmfgen/templates/Args.h42
-rw-r--r--cpp/managementgen/qmfgen/templates/CMakeLists.cmake39
-rw-r--r--cpp/managementgen/qmfgen/templates/Class.cpp180
-rw-r--r--cpp/managementgen/qmfgen/templates/Class.h111
-rw-r--r--cpp/managementgen/qmfgen/templates/Event.cpp78
-rw-r--r--cpp/managementgen/qmfgen/templates/Event.h59
-rw-r--r--cpp/managementgen/qmfgen/templates/Makefile.mk40
-rw-r--r--cpp/managementgen/qmfgen/templates/Package.cpp32
-rw-r--r--cpp/managementgen/qmfgen/templates/Package.h41
-rwxr-xr-xcpp/managementgen/schema.py1099
-rw-r--r--cpp/managementgen/templates/Args.h40
-rw-r--r--cpp/managementgen/templates/Class.cpp164
-rw-r--r--cpp/managementgen/templates/Class.h101
-rw-r--r--cpp/managementgen/templates/Makefile.mk37
-rw-r--r--cpp/managementgen/templates/Package.cpp32
-rw-r--r--cpp/managementgen/templates/Package.h41
-rw-r--r--cpp/packaging/NSIS/qpid-icon.icobin0 -> 52972 bytes
-rw-r--r--cpp/packaging/NSIS/qpid-icon.pngbin0 -> 97992 bytes
-rw-r--r--cpp/packaging/NSIS/qpid-install-banner.bmpbin0 -> 9742 bytes
-rw-r--r--cpp/packaging/NSIS/qpid-install-banner.pngbin0 -> 57218 bytes
-rw-r--r--cpp/qpidc.spec.in302
-rw-r--r--cpp/rpm/README.qpidd-devel7
-rwxr-xr-xcpp/rubygen/0-10/allsegmenttypes.rb18
-rwxr-xr-xcpp/rubygen/0-10/exceptions.rb18
-rwxr-xr-xcpp/rubygen/0-10/handlers.rb20
-rwxr-xr-xcpp/rubygen/0-10/specification.rb22
-rwxr-xr-xcpp/rubygen/0-10/typecode.rb18
-rwxr-xr-xcpp/rubygen/MethodBodyDefaultVisitor.rb19
-rwxr-xr-xcpp/rubygen/amqpgen.rb83
-rwxr-xr-xcpp/rubygen/cppgen.rb5
-rwxr-xr-xcpp/rubygen/framing.0-10/MethodBodyConstVisitor.rb18
-rwxr-xr-xcpp/rubygen/framing.0-10/MethodBodyDefaultVisitor.rb23
-rw-r--r--cpp/rubygen/framing.0-10/MethodBodyFactory.rb58
-rwxr-xr-xcpp/rubygen/framing.0-10/MethodHolder.rb100
-rwxr-xr-xcpp/rubygen/framing.0-10/Operations.rb24
-rwxr-xr-xcpp/rubygen/framing.0-10/OperationsInvoker.rb27
-rwxr-xr-xcpp/rubygen/framing.0-10/Proxy.rb30
-rwxr-xr-x[-rw-r--r--]cpp/rubygen/framing.0-10/Session.rb214
-rwxr-xr-xcpp/rubygen/framing.0-10/all_method_bodies.rb18
-rwxr-xr-xcpp/rubygen/framing.0-10/constants.rb184
-rw-r--r--cpp/rubygen/framing.0-10/frame_body_lists.rb20
-rwxr-xr-x[-rw-r--r--]cpp/rubygen/framing.0-10/structs.rb80
-rwxr-xr-xcpp/rubygen/generate103
-rw-r--r--cpp/src/CMakeLists.txt949
-rw-r--r--cpp/src/Makefile.am997
-rw-r--r--cpp/src/acl.mk35
-rw-r--r--cpp/src/cluster.cmake157
-rw-r--r--cpp/src/cluster.mk125
-rw-r--r--cpp/src/config.h.cmake56
-rwxr-xr-xcpp/src/generate.sh19
-rw-r--r--cpp/src/posix/QpiddBroker.cpp179
-rwxr-xr-xcpp/src/prof21
-rw-r--r--cpp/src/qmf.mk113
-rw-r--r--cpp/src/qmf/engine/Agent.cpp857
-rw-r--r--cpp/src/qmf/engine/BrokerProxyImpl.cpp777
-rw-r--r--cpp/src/qmf/engine/BrokerProxyImpl.h239
-rw-r--r--cpp/src/qmf/engine/ConnectionSettingsImpl.cpp278
-rw-r--r--cpp/src/qmf/engine/ConnectionSettingsImpl.h63
-rw-r--r--cpp/src/qmf/engine/ConsoleImpl.cpp419
-rw-r--r--cpp/src/qmf/engine/ConsoleImpl.h145
-rw-r--r--cpp/src/qmf/engine/MessageImpl.cpp43
-rw-r--r--cpp/src/qmf/engine/MessageImpl.h44
-rw-r--r--cpp/src/qmf/engine/ObjectIdImpl.cpp199
-rw-r--r--cpp/src/qmf/engine/ObjectIdImpl.h72
-rw-r--r--cpp/src/qmf/engine/ObjectImpl.cpp232
-rw-r--r--cpp/src/qmf/engine/ObjectImpl.h76
-rw-r--r--cpp/src/qmf/engine/Protocol.cpp52
-rw-r--r--cpp/src/qmf/engine/Protocol.h69
-rw-r--r--cpp/src/qmf/engine/QueryImpl.cpp103
-rw-r--r--cpp/src/qmf/engine/QueryImpl.h102
-rw-r--r--cpp/src/qmf/engine/ResilientConnection.cpp489
-rw-r--r--cpp/src/qmf/engine/SchemaImpl.cpp610
-rw-r--r--cpp/src/qmf/engine/SchemaImpl.h223
-rw-r--r--cpp/src/qmf/engine/SequenceManager.cpp96
-rw-r--r--cpp/src/qmf/engine/SequenceManager.h68
-rw-r--r--cpp/src/qmf/engine/ValueImpl.cpp264
-rw-r--r--cpp/src/qmf/engine/ValueImpl.h150
-rw-r--r--cpp/src/qmfc.mk55
-rw-r--r--cpp/src/qpid/Address.cpp58
-rw-r--r--cpp/src/qpid/DataDir.cpp25
-rw-r--r--cpp/src/qpid/DataDir.h14
-rw-r--r--cpp/src/qpid/Exception.cpp4
-rw-r--r--cpp/src/qpid/Exception.h85
-rw-r--r--cpp/src/qpid/InlineAllocator.h84
-rw-r--r--cpp/src/qpid/InlineVector.h68
-rw-r--r--cpp/src/qpid/Modules.cpp95
-rw-r--r--cpp/src/qpid/Modules.h44
-rw-r--r--cpp/src/qpid/Msg.h61
-rw-r--r--cpp/src/qpid/Options.cpp5
-rw-r--r--cpp/src/qpid/Options.h257
-rw-r--r--cpp/src/qpid/Plugin.cpp22
-rw-r--r--cpp/src/qpid/Plugin.h33
-rw-r--r--cpp/src/qpid/RangeSet.h324
-rw-r--r--cpp/src/qpid/RefCounted.h4
-rw-r--r--cpp/src/qpid/RefCountedBuffer.cpp53
-rw-r--r--cpp/src/qpid/RefCountedBuffer.h89
-rw-r--r--cpp/src/qpid/SessionId.cpp4
-rw-r--r--cpp/src/qpid/SessionId.h59
-rw-r--r--cpp/src/qpid/SessionState.cpp66
-rw-r--r--cpp/src/qpid/SessionState.h91
-rw-r--r--cpp/src/qpid/StringUtils.cpp2
-rw-r--r--cpp/src/qpid/StringUtils.h6
-rw-r--r--cpp/src/qpid/Url.cpp215
-rw-r--r--cpp/src/qpid/Url.h109
-rwxr-xr-xcpp/src/qpid/Version.h44
-rw-r--r--cpp/src/qpid/acl/Acl.cpp180
-rw-r--r--cpp/src/qpid/acl/Acl.h32
-rw-r--r--cpp/src/qpid/acl/AclData.cpp236
-rw-r--r--cpp/src/qpid/acl/AclData.h83
-rw-r--r--cpp/src/qpid/acl/AclPlugin.cpp33
-rw-r--r--cpp/src/qpid/acl/AclReader.cpp507
-rw-r--r--cpp/src/qpid/acl/AclReader.h95
-rw-r--r--cpp/src/qpid/acl/management-schema.xml44
-rw-r--r--cpp/src/qpid/agent/ManagementAgent.h127
-rw-r--r--cpp/src/qpid/agent/ManagementAgentImpl.cpp881
-rw-r--r--cpp/src/qpid/agent/ManagementAgentImpl.h177
-rw-r--r--cpp/src/qpid/amqp_0_10/Array.cpp2
-rw-r--r--cpp/src/qpid/amqp_0_10/Codec.h2
-rw-r--r--cpp/src/qpid/amqp_0_10/Command.h2
-rw-r--r--cpp/src/qpid/amqp_0_10/Connection.cpp93
-rw-r--r--cpp/src/qpid/amqp_0_10/Connection.h40
-rw-r--r--cpp/src/qpid/amqp_0_10/Control.h2
-rw-r--r--cpp/src/qpid/amqp_0_10/Exception.h98
-rw-r--r--cpp/src/qpid/amqp_0_10/FrameHeader.cpp2
-rw-r--r--cpp/src/qpid/amqp_0_10/Header.cpp2
-rw-r--r--cpp/src/qpid/amqp_0_10/Holder.h2
-rw-r--r--cpp/src/qpid/amqp_0_10/Map.cpp2
-rw-r--r--cpp/src/qpid/amqp_0_10/SessionHandler.cpp121
-rw-r--r--cpp/src/qpid/amqp_0_10/SessionHandler.h75
-rw-r--r--cpp/src/qpid/amqp_0_10/Struct.h2
-rw-r--r--cpp/src/qpid/amqp_0_10/Struct32.cpp2
-rw-r--r--cpp/src/qpid/amqp_0_10/Unit.cpp4
-rw-r--r--cpp/src/qpid/amqp_0_10/UnknownType.cpp2
-rw-r--r--cpp/src/qpid/amqp_0_10/UnknownType.h2
-rw-r--r--cpp/src/qpid/amqp_0_10/built_in_types.h7
-rw-r--r--cpp/src/qpid/assert.cpp2
-rw-r--r--cpp/src/qpid/broker/AclModule.h244
-rw-r--r--cpp/src/qpid/broker/Bridge.cpp230
-rw-r--r--cpp/src/qpid/broker/Bridge.h45
-rw-r--r--cpp/src/qpid/broker/Broker.cpp360
-rw-r--r--cpp/src/qpid/broker/Broker.h184
-rw-r--r--cpp/src/qpid/broker/BrokerImportExport.h33
-rw-r--r--cpp/src/qpid/broker/BrokerSingleton.cpp36
-rw-r--r--cpp/src/qpid/broker/BrokerSingleton.h52
-rw-r--r--cpp/src/qpid/broker/Connection.cpp230
-rw-r--r--cpp/src/qpid/broker/Connection.h117
-rw-r--r--cpp/src/qpid/broker/ConnectionFactory.cpp29
-rw-r--r--cpp/src/qpid/broker/ConnectionFactory.h9
-rw-r--r--cpp/src/qpid/broker/ConnectionHandler.cpp202
-rw-r--r--cpp/src/qpid/broker/ConnectionHandler.h49
-rw-r--r--cpp/src/qpid/broker/ConnectionState.h68
-rw-r--r--cpp/src/qpid/broker/ConnectionToken.h2
-rw-r--r--cpp/src/qpid/broker/Consumer.h62
-rw-r--r--cpp/src/qpid/broker/Daemon.cpp145
-rw-r--r--cpp/src/qpid/broker/Daemon.h4
-rw-r--r--cpp/src/qpid/broker/Deliverable.h6
-rw-r--r--cpp/src/qpid/broker/DeliverableMessage.cpp6
-rw-r--r--cpp/src/qpid/broker/DeliverableMessage.h15
-rw-r--r--cpp/src/qpid/broker/DeliveryAdapter.h39
-rw-r--r--cpp/src/qpid/broker/DeliveryRecord.cpp152
-rw-r--r--cpp/src/qpid/broker/DeliveryRecord.h120
-rw-r--r--cpp/src/qpid/broker/DeliveryToken.h45
-rw-r--r--cpp/src/qpid/broker/DirectExchange.cpp189
-rw-r--r--cpp/src/qpid/broker/DirectExchange.h63
-rw-r--r--cpp/src/qpid/broker/DtxAck.cpp27
-rw-r--r--cpp/src/qpid/broker/DtxAck.h9
-rw-r--r--cpp/src/qpid/broker/DtxBuffer.cpp2
-rw-r--r--cpp/src/qpid/broker/DtxBuffer.h9
-rw-r--r--cpp/src/qpid/broker/DtxManager.cpp15
-rw-r--r--cpp/src/qpid/broker/DtxManager.h14
-rw-r--r--cpp/src/qpid/broker/DtxTimeout.cpp4
-rw-r--r--cpp/src/qpid/broker/DtxTimeout.h6
-rw-r--r--cpp/src/qpid/broker/DtxWorkRecord.cpp4
-rw-r--r--cpp/src/qpid/broker/DtxWorkRecord.h20
-rw-r--r--cpp/src/qpid/broker/Exchange.cpp291
-rw-r--r--cpp/src/qpid/broker/Exchange.h240
-rw-r--r--cpp/src/qpid/broker/ExchangeRegistry.cpp46
-rw-r--r--cpp/src/qpid/broker/ExchangeRegistry.h99
-rw-r--r--cpp/src/qpid/broker/ExpiryPolicy.cpp38
-rw-r--r--cpp/src/qpid/broker/ExpiryPolicy.h46
-rw-r--r--cpp/src/qpid/broker/FanOutExchange.cpp130
-rw-r--r--cpp/src/qpid/broker/FanOutExchange.h38
-rw-r--r--cpp/src/qpid/broker/HandlerImpl.h6
-rw-r--r--cpp/src/qpid/broker/HeadersExchange.cpp107
-rw-r--r--cpp/src/qpid/broker/HeadersExchange.h53
-rw-r--r--cpp/src/qpid/broker/IncomingExecutionContext.cpp143
-rw-r--r--cpp/src/qpid/broker/IncomingExecutionContext.h61
-rw-r--r--cpp/src/qpid/broker/IncompleteMessageList.cpp45
-rw-r--r--cpp/src/qpid/broker/IncompleteMessageList.h24
-rw-r--r--cpp/src/qpid/broker/Link.cpp273
-rw-r--r--cpp/src/qpid/broker/Link.h30
-rw-r--r--cpp/src/qpid/broker/LinkRegistry.cpp164
-rw-r--r--cpp/src/qpid/broker/LinkRegistry.h49
-rw-r--r--cpp/src/qpid/broker/Message.cpp219
-rw-r--r--cpp/src/qpid/broker/Message.h102
-rw-r--r--cpp/src/qpid/broker/MessageAdapter.cpp2
-rw-r--r--cpp/src/qpid/broker/MessageBuilder.cpp38
-rw-r--r--cpp/src/qpid/broker/MessageBuilder.h8
-rw-r--r--cpp/src/qpid/broker/MessageDelivery.cpp89
-rw-r--r--cpp/src/qpid/broker/MessageDelivery.h55
-rw-r--r--cpp/src/qpid/broker/MessageStore.h64
-rw-r--r--cpp/src/qpid/broker/MessageStoreModule.cpp33
-rw-r--r--cpp/src/qpid/broker/MessageStoreModule.h25
-rw-r--r--cpp/src/qpid/broker/NameGenerator.cpp2
-rw-r--r--cpp/src/qpid/broker/NullMessageStore.cpp95
-rw-r--r--cpp/src/qpid/broker/NullMessageStore.h90
-rw-r--r--cpp/src/qpid/broker/PersistableConfig.h2
-rw-r--r--cpp/src/qpid/broker/PersistableExchange.h2
-rw-r--r--cpp/src/qpid/broker/PersistableMessage.cpp139
-rw-r--r--cpp/src/qpid/broker/PersistableMessage.h164
-rw-r--r--cpp/src/qpid/broker/PersistableQueue.h2
-rw-r--r--cpp/src/qpid/broker/Prefetch.h42
-rw-r--r--cpp/src/qpid/broker/Queue.cpp785
-rw-r--r--cpp/src/qpid/broker/Queue.h238
-rw-r--r--cpp/src/qpid/broker/QueueBindings.cpp11
-rw-r--r--cpp/src/qpid/broker/QueueBindings.h30
-rw-r--r--cpp/src/qpid/broker/QueueCleaner.cpp57
-rw-r--r--cpp/src/qpid/broker/QueueCleaner.h59
-rw-r--r--cpp/src/qpid/broker/QueueEvents.cpp122
-rw-r--r--cpp/src/qpid/broker/QueueEvents.h84
-rw-r--r--cpp/src/qpid/broker/QueueListeners.cpp81
-rw-r--r--cpp/src/qpid/broker/QueueListeners.h75
-rw-r--r--cpp/src/qpid/broker/QueuePolicy.cpp257
-rw-r--r--cpp/src/qpid/broker/QueuePolicy.h116
-rw-r--r--cpp/src/qpid/broker/QueueRegistry.cpp30
-rw-r--r--cpp/src/qpid/broker/QueueRegistry.h49
-rw-r--r--cpp/src/qpid/broker/QueuedMessage.h48
-rw-r--r--cpp/src/qpid/broker/RateFlowcontrol.h105
-rw-r--r--cpp/src/qpid/broker/RateTracker.cpp51
-rw-r--r--cpp/src/qpid/broker/RateTracker.h57
-rw-r--r--cpp/src/qpid/broker/RecoverableExchange.h4
-rw-r--r--cpp/src/qpid/broker/RecoverableMessage.h1
-rw-r--r--cpp/src/qpid/broker/RecoverableQueue.h2
-rw-r--r--cpp/src/qpid/broker/RecoverableTransaction.h4
-rw-r--r--cpp/src/qpid/broker/RecoveredDequeue.cpp17
-rw-r--r--cpp/src/qpid/broker/RecoveredDequeue.h14
-rw-r--r--cpp/src/qpid/broker/RecoveredEnqueue.cpp8
-rw-r--r--cpp/src/qpid/broker/RecoveredEnqueue.h15
-rw-r--r--cpp/src/qpid/broker/RecoveryManager.h12
-rw-r--r--cpp/src/qpid/broker/RecoveryManagerImpl.cpp66
-rw-r--r--cpp/src/qpid/broker/RecoveryManagerImpl.h10
-rw-r--r--cpp/src/qpid/broker/RetryList.cpp60
-rw-r--r--cpp/src/qpid/broker/RetryList.h54
-rw-r--r--cpp/src/qpid/broker/SaslAuthenticator.cpp183
-rw-r--r--cpp/src/qpid/broker/SaslAuthenticator.h10
-rw-r--r--cpp/src/qpid/broker/SecureConnection.cpp87
-rw-r--r--cpp/src/qpid/broker/SecureConnection.h60
-rw-r--r--cpp/src/qpid/broker/SecureConnectionFactory.cpp73
-rw-r--r--cpp/src/qpid/broker/SecureConnectionFactory.h50
-rw-r--r--cpp/src/qpid/broker/SemanticState.cpp436
-rw-r--r--cpp/src/qpid/broker/SemanticState.h147
-rw-r--r--cpp/src/qpid/broker/SessionAdapter.cpp390
-rw-r--r--cpp/src/qpid/broker/SessionAdapter.h25
-rw-r--r--cpp/src/qpid/broker/SessionContext.h9
-rw-r--r--cpp/src/qpid/broker/SessionHandler.cpp60
-rw-r--r--cpp/src/qpid/broker/SessionHandler.h29
-rw-r--r--cpp/src/qpid/broker/SessionManager.cpp15
-rw-r--r--cpp/src/qpid/broker/SessionState.cpp259
-rw-r--r--cpp/src/qpid/broker/SessionState.h71
-rw-r--r--cpp/src/qpid/broker/SignalHandler.cpp9
-rw-r--r--cpp/src/qpid/broker/SignalHandler.h3
-rw-r--r--cpp/src/qpid/broker/System.cpp36
-rw-r--r--cpp/src/qpid/broker/System.h8
-rw-r--r--cpp/src/qpid/broker/Timer.cpp104
-rw-r--r--cpp/src/qpid/broker/Timer.h79
-rw-r--r--cpp/src/qpid/broker/TopicExchange.cpp343
-rw-r--r--cpp/src/qpid/broker/TopicExchange.h82
-rw-r--r--cpp/src/qpid/broker/TxAccept.cpp65
-rw-r--r--cpp/src/qpid/broker/TxAccept.h38
-rw-r--r--cpp/src/qpid/broker/TxBuffer.cpp7
-rw-r--r--cpp/src/qpid/broker/TxBuffer.h18
-rw-r--r--cpp/src/qpid/broker/TxOp.h10
-rw-r--r--cpp/src/qpid/broker/TxOpVisitor.h97
-rw-r--r--cpp/src/qpid/broker/TxPublish.cpp60
-rw-r--r--cpp/src/qpid/broker/TxPublish.h45
-rw-r--r--cpp/src/qpid/broker/Vhost.cpp24
-rw-r--r--cpp/src/qpid/broker/Vhost.h11
-rw-r--r--cpp/src/qpid/broker/XmlExchange.cpp277
-rw-r--r--cpp/src/qpid/broker/XmlExchange.h87
-rw-r--r--cpp/src/qpid/broker/posix/BrokerDefaults.cpp40
-rw-r--r--cpp/src/qpid/broker/windows/BrokerDefaults.cpp41
-rw-r--r--cpp/src/qpid/broker/windows/SaslAuthenticator.cpp190
-rw-r--r--cpp/src/qpid/client/AckMode.h53
-rw-r--r--cpp/src/qpid/client/AckPolicy.cpp50
-rw-r--r--cpp/src/qpid/client/AckPolicy.h58
-rw-r--r--cpp/src/qpid/client/AsyncSession.h38
-rw-r--r--cpp/src/qpid/client/Bounds.cpp25
-rw-r--r--cpp/src/qpid/client/Completion.cpp40
-rw-r--r--cpp/src/qpid/client/Completion.h71
-rw-r--r--cpp/src/qpid/client/CompletionImpl.h51
-rw-r--r--cpp/src/qpid/client/Connection.cpp94
-rw-r--r--cpp/src/qpid/client/Connection.h149
-rw-r--r--cpp/src/qpid/client/ConnectionAccess.h41
-rw-r--r--cpp/src/qpid/client/ConnectionHandler.cpp188
-rw-r--r--cpp/src/qpid/client/ConnectionHandler.h34
-rw-r--r--cpp/src/qpid/client/ConnectionImpl.cpp202
-rw-r--r--cpp/src/qpid/client/ConnectionImpl.h25
-rw-r--r--cpp/src/qpid/client/ConnectionSettings.cpp15
-rw-r--r--cpp/src/qpid/client/ConnectionSettings.h114
-rw-r--r--cpp/src/qpid/client/Connector.cpp241
-rw-r--r--cpp/src/qpid/client/Connector.h121
-rw-r--r--cpp/src/qpid/client/Demux.cpp2
-rw-r--r--cpp/src/qpid/client/Demux.h21
-rw-r--r--cpp/src/qpid/client/Dispatcher.cpp91
-rw-r--r--cpp/src/qpid/client/Dispatcher.h42
-rw-r--r--cpp/src/qpid/client/Execution.h2
-rw-r--r--cpp/src/qpid/client/FailoverListener.cpp89
-rw-r--r--cpp/src/qpid/client/FailoverManager.cpp131
-rw-r--r--cpp/src/qpid/client/FlowControl.h73
-rw-r--r--cpp/src/qpid/client/Future.cpp3
-rw-r--r--cpp/src/qpid/client/Future.h64
-rw-r--r--cpp/src/qpid/client/FutureCompletion.cpp2
-rw-r--r--cpp/src/qpid/client/FutureCompletion.h49
-rw-r--r--cpp/src/qpid/client/FutureResult.cpp4
-rw-r--r--cpp/src/qpid/client/FutureResult.h47
-rw-r--r--cpp/src/qpid/client/LoadPlugins.cpp52
-rw-r--r--cpp/src/qpid/client/LocalQueue.cpp56
-rw-r--r--cpp/src/qpid/client/LocalQueue.h93
-rw-r--r--cpp/src/qpid/client/LocalQueueImpl.cpp78
-rw-r--r--cpp/src/qpid/client/LocalQueueImpl.h108
-rw-r--r--cpp/src/qpid/client/Message.cpp65
-rw-r--r--cpp/src/qpid/client/Message.h83
-rw-r--r--cpp/src/qpid/client/MessageImpl.cpp71
-rw-r--r--cpp/src/qpid/client/MessageImpl.h80
-rw-r--r--cpp/src/qpid/client/MessageListener.cpp2
-rw-r--r--cpp/src/qpid/client/MessageListener.h53
-rw-r--r--cpp/src/qpid/client/MessageQueue.h50
-rw-r--r--cpp/src/qpid/client/MessageReplayTracker.cpp78
-rw-r--r--cpp/src/qpid/client/PrivateImplRef.h94
-rw-r--r--cpp/src/qpid/client/QueueOptions.cpp123
-rw-r--r--cpp/src/qpid/client/RdmaConnector.cpp387
-rw-r--r--cpp/src/qpid/client/Results.cpp9
-rw-r--r--cpp/src/qpid/client/Results.h1
-rw-r--r--cpp/src/qpid/client/Sasl.h70
-rw-r--r--cpp/src/qpid/client/SaslFactory.cpp379
-rw-r--r--cpp/src/qpid/client/SaslFactory.h48
-rw-r--r--cpp/src/qpid/client/Session.h39
-rw-r--r--cpp/src/qpid/client/SessionBase_0_10.cpp27
-rw-r--r--cpp/src/qpid/client/SessionBase_0_10.h106
-rw-r--r--cpp/src/qpid/client/SessionBase_0_10Access.h2
-rw-r--r--cpp/src/qpid/client/SessionImpl.cpp364
-rw-r--r--cpp/src/qpid/client/SessionImpl.h102
-rw-r--r--cpp/src/qpid/client/SslConnector.cpp400
-rw-r--r--cpp/src/qpid/client/StateManager.cpp14
-rw-r--r--cpp/src/qpid/client/StateManager.h1
-rw-r--r--cpp/src/qpid/client/Subscription.cpp55
-rw-r--r--cpp/src/qpid/client/SubscriptionImpl.cpp169
-rw-r--r--cpp/src/qpid/client/SubscriptionImpl.h125
-rw-r--r--cpp/src/qpid/client/SubscriptionManager.cpp146
-rw-r--r--cpp/src/qpid/client/SubscriptionManager.h210
-rw-r--r--cpp/src/qpid/client/SubscriptionManagerImpl.cpp162
-rw-r--r--cpp/src/qpid/client/SubscriptionManagerImpl.h278
-rw-r--r--cpp/src/qpid/client/TCPConnector.cpp327
-rw-r--r--cpp/src/qpid/client/TCPConnector.h117
-rw-r--r--cpp/src/qpid/client/TypedResult.h65
-rw-r--r--cpp/src/qpid/client/amqp0_10/AcceptTracker.cpp111
-rw-r--r--cpp/src/qpid/client/amqp0_10/AcceptTracker.h85
-rw-r--r--cpp/src/qpid/client/amqp0_10/AddressResolution.cpp819
-rw-r--r--cpp/src/qpid/client/amqp0_10/AddressResolution.h64
-rw-r--r--cpp/src/qpid/client/amqp0_10/Codecs.cpp299
-rw-r--r--cpp/src/qpid/client/amqp0_10/CodecsInternal.h41
-rw-r--r--cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp208
-rw-r--r--cpp/src/qpid/client/amqp0_10/ConnectionImpl.h72
-rw-r--r--cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp303
-rw-r--r--cpp/src/qpid/client/amqp0_10/IncomingMessages.h98
-rw-r--r--cpp/src/qpid/client/amqp0_10/MessageSink.h52
-rw-r--r--cpp/src/qpid/client/amqp0_10/MessageSource.h47
-rw-r--r--cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp67
-rw-r--r--cpp/src/qpid/client/amqp0_10/OutgoingMessage.h48
-rw-r--r--cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp194
-rw-r--r--cpp/src/qpid/client/amqp0_10/ReceiverImpl.h148
-rw-r--r--cpp/src/qpid/client/amqp0_10/SenderImpl.cpp144
-rw-r--r--cpp/src/qpid/client/amqp0_10/SenderImpl.h140
-rw-r--r--cpp/src/qpid/client/amqp0_10/SessionImpl.cpp433
-rw-r--r--cpp/src/qpid/client/amqp0_10/SessionImpl.h212
-rw-r--r--cpp/src/qpid/client/windows/SaslFactory.cpp146
-rw-r--r--cpp/src/qpid/cluster/ClassifierHandler.cpp51
-rw-r--r--cpp/src/qpid/cluster/ClassifierHandler.h50
-rw-r--r--cpp/src/qpid/cluster/Cluster.cpp1089
-rw-r--r--cpp/src/qpid/cluster/Cluster.h318
-rw-r--r--cpp/src/qpid/cluster/ClusterMap.cpp175
-rw-r--r--cpp/src/qpid/cluster/ClusterMap.h105
-rw-r--r--cpp/src/qpid/cluster/ClusterPlugin.cpp154
-rw-r--r--cpp/src/qpid/cluster/ClusterSettings.h50
-rw-r--r--cpp/src/qpid/cluster/Connection.cpp479
-rw-r--r--cpp/src/qpid/cluster/Connection.h210
-rw-r--r--cpp/src/qpid/cluster/ConnectionCodec.cpp82
-rw-r--r--cpp/src/qpid/cluster/ConnectionCodec.h82
-rw-r--r--cpp/src/qpid/cluster/ConnectionInterceptor.cpp108
-rw-r--r--cpp/src/qpid/cluster/ConnectionInterceptor.h82
-rw-r--r--cpp/src/qpid/cluster/Cpg.cpp223
-rw-r--r--cpp/src/qpid/cluster/Cpg.h157
-rw-r--r--cpp/src/qpid/cluster/Decoder.cpp65
-rw-r--r--cpp/src/qpid/cluster/Decoder.h59
-rw-r--r--cpp/src/qpid/cluster/ErrorCheck.cpp155
-rw-r--r--cpp/src/qpid/cluster/ErrorCheck.h90
-rw-r--r--cpp/src/qpid/cluster/Event.cpp136
-rw-r--r--cpp/src/qpid/cluster/Event.h116
-rw-r--r--cpp/src/qpid/cluster/EventFrame.cpp41
-rw-r--r--cpp/src/qpid/cluster/EventFrame.h60
-rw-r--r--cpp/src/qpid/cluster/ExpiryPolicy.cpp85
-rw-r--r--cpp/src/qpid/cluster/ExpiryPolicy.h89
-rw-r--r--cpp/src/qpid/cluster/FailoverExchange.cpp99
-rw-r--r--cpp/src/qpid/cluster/FailoverExchange.h68
-rw-r--r--cpp/src/qpid/cluster/InitialStatusMap.cpp197
-rw-r--r--cpp/src/qpid/cluster/InitialStatusMap.h75
-rw-r--r--cpp/src/qpid/cluster/LockedConnectionMap.h65
-rw-r--r--cpp/src/qpid/cluster/McastFrameHandler.h46
-rw-r--r--cpp/src/qpid/cluster/MemberSet.cpp52
-rw-r--r--cpp/src/qpid/cluster/MemberSet.h43
-rw-r--r--cpp/src/qpid/cluster/Multicaster.cpp103
-rw-r--r--cpp/src/qpid/cluster/Multicaster.h87
-rw-r--r--cpp/src/qpid/cluster/NoOpConnectionOutputHandler.h47
-rw-r--r--cpp/src/qpid/cluster/Numbering.h70
-rw-r--r--cpp/src/qpid/cluster/OutputInterceptor.cpp116
-rw-r--r--cpp/src/qpid/cluster/OutputInterceptor.h79
-rw-r--r--cpp/src/qpid/cluster/PollableCondition.cpp100
-rw-r--r--cpp/src/qpid/cluster/PollableCondition.h60
-rw-r--r--cpp/src/qpid/cluster/PollableQueue.h95
-rw-r--r--cpp/src/qpid/cluster/PollerDispatch.cpp67
-rw-r--r--cpp/src/qpid/cluster/PollerDispatch.h60
-rw-r--r--cpp/src/qpid/cluster/ProxyInputHandler.h57
-rw-r--r--cpp/src/qpid/cluster/Quorum.h32
-rw-r--r--cpp/src/qpid/cluster/Quorum_cman.cpp103
-rw-r--r--cpp/src/qpid/cluster/Quorum_cman.h64
-rw-r--r--cpp/src/qpid/cluster/Quorum_null.h42
-rw-r--r--cpp/src/qpid/cluster/RetractClient.cpp61
-rw-r--r--cpp/src/qpid/cluster/RetractClient.h49
-rw-r--r--cpp/src/qpid/cluster/ShadowConnectionOutputHandler.h46
-rw-r--r--cpp/src/qpid/cluster/StoreStatus.cpp110
-rw-r--r--cpp/src/qpid/cluster/StoreStatus.h64
-rw-r--r--cpp/src/qpid/cluster/UpdateClient.cpp484
-rw-r--r--cpp/src/qpid/cluster/UpdateClient.h119
-rw-r--r--cpp/src/qpid/cluster/UpdateExchange.cpp47
-rw-r--r--cpp/src/qpid/cluster/UpdateExchange.h45
-rw-r--r--cpp/src/qpid/cluster/UpdateReceiver.h42
-rw-r--r--cpp/src/qpid/cluster/WatchDogPlugin.cpp136
-rw-r--r--cpp/src/qpid/cluster/management-schema.xml61
-rw-r--r--cpp/src/qpid/cluster/qpidd_watchdog.cpp63
-rw-r--r--cpp/src/qpid/cluster/types.h83
-rw-r--r--cpp/src/qpid/console/Agent.cpp30
-rw-r--r--cpp/src/qpid/console/Broker.cpp328
-rw-r--r--cpp/src/qpid/console/ClassKey.cpp105
-rw-r--r--cpp/src/qpid/console/Event.cpp205
-rw-r--r--cpp/src/qpid/console/Object.cpp384
-rw-r--r--cpp/src/qpid/console/ObjectId.cpp91
-rw-r--r--cpp/src/qpid/console/Package.cpp41
-rw-r--r--cpp/src/qpid/console/Schema.cpp165
-rw-r--r--cpp/src/qpid/console/SequenceManager.cpp48
-rw-r--r--cpp/src/qpid/console/SessionManager.cpp481
-rw-r--r--cpp/src/qpid/console/Value.cpp169
-rw-r--r--cpp/src/qpid/doxygen_mainpage.h28
-rw-r--r--cpp/src/qpid/framing/AMQBody.h20
-rw-r--r--cpp/src/qpid/framing/AMQCommandControlBody.h2
-rw-r--r--cpp/src/qpid/framing/AMQContentBody.cpp10
-rw-r--r--cpp/src/qpid/framing/AMQContentBody.h28
-rw-r--r--cpp/src/qpid/framing/AMQDataBlock.h4
-rw-r--r--cpp/src/qpid/framing/AMQFrame.cpp80
-rw-r--r--cpp/src/qpid/framing/AMQFrame.h62
-rw-r--r--cpp/src/qpid/framing/AMQHeaderBody.cpp8
-rw-r--r--cpp/src/qpid/framing/AMQHeaderBody.h29
-rw-r--r--cpp/src/qpid/framing/AMQHeartbeatBody.cpp2
-rw-r--r--cpp/src/qpid/framing/AMQHeartbeatBody.h14
-rw-r--r--cpp/src/qpid/framing/AMQMethodBody.cpp2
-rw-r--r--cpp/src/qpid/framing/AMQMethodBody.h12
-rw-r--r--cpp/src/qpid/framing/AccumulatedAck.cpp2
-rw-r--r--cpp/src/qpid/framing/AccumulatedAck.h21
-rw-r--r--cpp/src/qpid/framing/Array.cpp59
-rw-r--r--cpp/src/qpid/framing/Array.h78
-rw-r--r--cpp/src/qpid/framing/Blob.cpp2
-rw-r--r--cpp/src/qpid/framing/Blob.h197
-rw-r--r--cpp/src/qpid/framing/BodyFactory.h47
-rw-r--r--cpp/src/qpid/framing/BodyHandler.cpp10
-rw-r--r--cpp/src/qpid/framing/BodyHolder.cpp76
-rw-r--r--cpp/src/qpid/framing/BodyHolder.h88
-rw-r--r--cpp/src/qpid/framing/Buffer.cpp26
-rw-r--r--cpp/src/qpid/framing/Buffer.h132
-rw-r--r--cpp/src/qpid/framing/ChannelHandler.h4
-rw-r--r--cpp/src/qpid/framing/Endian.cpp52
-rw-r--r--cpp/src/qpid/framing/Endian.h46
-rw-r--r--cpp/src/qpid/framing/FieldTable.cpp121
-rw-r--r--cpp/src/qpid/framing/FieldTable.h101
-rw-r--r--cpp/src/qpid/framing/FieldValue.cpp181
-rw-r--r--cpp/src/qpid/framing/FieldValue.h241
-rw-r--r--cpp/src/qpid/framing/FrameDecoder.cpp81
-rw-r--r--cpp/src/qpid/framing/FrameDecoder.h52
-rw-r--r--cpp/src/qpid/framing/FrameHandler.h2
-rw-r--r--cpp/src/qpid/framing/FrameSet.cpp9
-rw-r--r--cpp/src/qpid/framing/FrameSet.h29
-rw-r--r--cpp/src/qpid/framing/Handler.h2
-rw-r--r--cpp/src/qpid/framing/HeaderProperties.h6
-rw-r--r--cpp/src/qpid/framing/InitiationHandler.cpp2
-rw-r--r--cpp/src/qpid/framing/InitiationHandler.h2
-rw-r--r--cpp/src/qpid/framing/InputHandler.h2
-rw-r--r--cpp/src/qpid/framing/IsInSequenceSet.h51
-rw-r--r--cpp/src/qpid/framing/List.cpp83
-rw-r--r--cpp/src/qpid/framing/MethodBodyFactory.h44
-rw-r--r--cpp/src/qpid/framing/MethodContent.h2
-rw-r--r--cpp/src/qpid/framing/ModelMethod.h4
-rw-r--r--cpp/src/qpid/framing/OutputHandler.h2
-rw-r--r--cpp/src/qpid/framing/ProtocolInitiation.cpp2
-rw-r--r--cpp/src/qpid/framing/ProtocolInitiation.h25
-rw-r--r--cpp/src/qpid/framing/ProtocolVersion.cpp2
-rw-r--r--cpp/src/qpid/framing/ProtocolVersion.h57
-rw-r--r--cpp/src/qpid/framing/Proxy.cpp15
-rw-r--r--cpp/src/qpid/framing/Proxy.h26
-rw-r--r--cpp/src/qpid/framing/SendContent.cpp13
-rw-r--r--cpp/src/qpid/framing/SendContent.h5
-rw-r--r--cpp/src/qpid/framing/SequenceNumber.cpp66
-rw-r--r--cpp/src/qpid/framing/SequenceNumber.h75
-rw-r--r--cpp/src/qpid/framing/SequenceNumberSet.cpp3
-rw-r--r--cpp/src/qpid/framing/SequenceNumberSet.h13
-rw-r--r--cpp/src/qpid/framing/SequenceSet.cpp7
-rw-r--r--cpp/src/qpid/framing/SequenceSet.h68
-rw-r--r--cpp/src/qpid/framing/StructHelper.h56
-rw-r--r--cpp/src/qpid/framing/TransferContent.cpp11
-rw-r--r--cpp/src/qpid/framing/TransferContent.h33
-rw-r--r--cpp/src/qpid/framing/Uuid.cpp37
-rw-r--r--cpp/src/qpid/framing/Uuid.h88
-rw-r--r--cpp/src/qpid/framing/amqp_framing.h24
-rw-r--r--cpp/src/qpid/framing/amqp_types.h72
-rw-r--r--cpp/src/qpid/framing/amqp_types_full.h38
-rw-r--r--cpp/src/qpid/framing/frame_functors.h4
-rw-r--r--cpp/src/qpid/log/Logger.cpp92
-rw-r--r--cpp/src/qpid/log/Logger.h117
-rw-r--r--cpp/src/qpid/log/Options.cpp148
-rw-r--r--cpp/src/qpid/log/Options.h56
-rw-r--r--cpp/src/qpid/log/OstreamOutput.cpp41
-rw-r--r--cpp/src/qpid/log/OstreamOutput.h41
-rw-r--r--cpp/src/qpid/log/Selector.cpp10
-rw-r--r--cpp/src/qpid/log/Selector.h70
-rw-r--r--cpp/src/qpid/log/Statement.cpp14
-rw-r--r--cpp/src/qpid/log/Statement.h128
-rw-r--r--cpp/src/qpid/log/posix/SinkOptions.cpp215
-rw-r--r--cpp/src/qpid/log/posix/SinkOptions.h64
-rw-r--r--cpp/src/qpid/log/windows/SinkOptions.cpp148
-rw-r--r--cpp/src/qpid/log/windows/SinkOptions.h54
-rw-r--r--cpp/src/qpid/management/Args.h44
-rw-r--r--cpp/src/qpid/management/IdAllocator.h42
-rw-r--r--cpp/src/qpid/management/Manageable.cpp13
-rw-r--r--cpp/src/qpid/management/Manageable.h68
-rw-r--r--cpp/src/qpid/management/ManagementAgent.cpp1295
-rw-r--r--cpp/src/qpid/management/ManagementAgent.h264
-rw-r--r--cpp/src/qpid/management/ManagementBroker.cpp933
-rw-r--r--cpp/src/qpid/management/ManagementBroker.h216
-rw-r--r--cpp/src/qpid/management/ManagementExchange.cpp18
-rw-r--r--cpp/src/qpid/management/ManagementExchange.h10
-rw-r--r--cpp/src/qpid/management/ManagementObject.cpp151
-rw-r--r--cpp/src/qpid/management/ManagementObject.h132
-rw-r--r--cpp/src/qpid/messaging/Address.cpp362
-rw-r--r--cpp/src/qpid/messaging/Connection.cpp96
-rw-r--r--cpp/src/qpid/messaging/ConnectionImpl.h46
-rw-r--r--cpp/src/qpid/messaging/ListContent.cpp98
-rw-r--r--cpp/src/qpid/messaging/ListView.cpp63
-rw-r--r--cpp/src/qpid/messaging/MapContent.cpp88
-rw-r--r--cpp/src/qpid/messaging/MapView.cpp63
-rw-r--r--cpp/src/qpid/messaging/Message.cpp58
-rw-r--r--cpp/src/qpid/messaging/MessageImpl.cpp64
-rw-r--r--cpp/src/qpid/messaging/MessageImpl.h82
-rw-r--r--cpp/src/qpid/messaging/Receiver.cpp53
-rw-r--r--cpp/src/qpid/messaging/ReceiverImpl.h55
-rw-r--r--cpp/src/qpid/messaging/Sender.cpp50
-rw-r--r--cpp/src/qpid/messaging/SenderImpl.h50
-rw-r--r--cpp/src/qpid/messaging/Session.cpp109
-rw-r--r--cpp/src/qpid/messaging/SessionImpl.h64
-rw-r--r--cpp/src/qpid/messaging/Variant.cpp659
-rw-r--r--cpp/src/qpid/replication/ReplicatingEventListener.cpp201
-rw-r--r--cpp/src/qpid/replication/ReplicatingEventListener.h78
-rw-r--r--cpp/src/qpid/replication/ReplicationExchange.cpp232
-rw-r--r--cpp/src/qpid/replication/ReplicationExchange.h67
-rw-r--r--cpp/src/qpid/replication/constants.h34
-rw-r--r--cpp/src/qpid/shared_ptr.h51
-rw-r--r--cpp/src/qpid/store/CMakeLists.txt80
-rw-r--r--cpp/src/qpid/store/MessageStorePlugin.cpp447
-rw-r--r--cpp/src/qpid/store/MessageStorePlugin.h284
-rw-r--r--cpp/src/qpid/store/StorageProvider.h324
-rw-r--r--cpp/src/qpid/store/StoreException.h49
-rw-r--r--cpp/src/qpid/store/ms-sql/AmqpTransaction.cpp89
-rw-r--r--cpp/src/qpid/store/ms-sql/AmqpTransaction.h84
-rw-r--r--cpp/src/qpid/store/ms-sql/BindingRecordset.cpp165
-rw-r--r--cpp/src/qpid/store/ms-sql/BindingRecordset.h88
-rw-r--r--cpp/src/qpid/store/ms-sql/BlobAdapter.cpp64
-rw-r--r--cpp/src/qpid/store/ms-sql/BlobAdapter.h62
-rw-r--r--cpp/src/qpid/store/ms-sql/BlobEncoder.cpp133
-rw-r--r--cpp/src/qpid/store/ms-sql/BlobEncoder.h61
-rw-r--r--cpp/src/qpid/store/ms-sql/BlobRecordset.cpp86
-rw-r--r--cpp/src/qpid/store/ms-sql/BlobRecordset.h54
-rw-r--r--cpp/src/qpid/store/ms-sql/DatabaseConnection.cpp70
-rw-r--r--cpp/src/qpid/store/ms-sql/DatabaseConnection.h62
-rw-r--r--cpp/src/qpid/store/ms-sql/Exception.h62
-rw-r--r--cpp/src/qpid/store/ms-sql/MSSqlProvider.cpp1061
-rw-r--r--cpp/src/qpid/store/ms-sql/MessageMapRecordset.cpp155
-rw-r--r--cpp/src/qpid/store/ms-sql/MessageMapRecordset.h77
-rw-r--r--cpp/src/qpid/store/ms-sql/MessageRecordset.cpp184
-rw-r--r--cpp/src/qpid/store/ms-sql/MessageRecordset.h85
-rw-r--r--cpp/src/qpid/store/ms-sql/Recordset.cpp121
-rw-r--r--cpp/src/qpid/store/ms-sql/Recordset.h101
-rw-r--r--cpp/src/qpid/store/ms-sql/State.cpp45
-rw-r--r--cpp/src/qpid/store/ms-sql/State.h52
-rw-r--r--cpp/src/qpid/store/ms-sql/VariantHelper.cpp59
-rw-r--r--cpp/src/qpid/store/ms-sql/VariantHelper.h61
-rw-r--r--cpp/src/qpid/sys/AggregateOutput.cpp83
-rw-r--r--cpp/src/qpid/sys/AggregateOutput.h77
-rw-r--r--cpp/src/qpid/sys/AsynchIO.h144
-rw-r--r--cpp/src/qpid/sys/AsynchIOHandler.cpp90
-rw-r--r--cpp/src/qpid/sys/AsynchIOHandler.h43
-rw-r--r--cpp/src/qpid/sys/AtomicCount.h2
-rw-r--r--cpp/src/qpid/sys/AtomicValue_gcc.h2
-rw-r--r--cpp/src/qpid/sys/AtomicValue_mutex.h2
-rw-r--r--cpp/src/qpid/sys/BlockingQueue.h13
-rw-r--r--cpp/src/qpid/sys/Codec.h52
-rw-r--r--cpp/src/qpid/sys/Condition.h31
-rw-r--r--cpp/src/qpid/sys/ConnectionCodec.h41
-rw-r--r--cpp/src/qpid/sys/ConnectionInputHandler.h5
-rw-r--r--cpp/src/qpid/sys/ConnectionInputHandlerFactory.h3
-rw-r--r--cpp/src/qpid/sys/ConnectionOutputHandler.h3
-rw-r--r--cpp/src/qpid/sys/ConnectionOutputHandlerPtr.h56
-rw-r--r--cpp/src/qpid/sys/CopyOnWriteArray.h138
-rw-r--r--cpp/src/qpid/sys/DeletionManager.h36
-rw-r--r--cpp/src/qpid/sys/DispatchHandle.cpp337
-rw-r--r--cpp/src/qpid/sys/DispatchHandle.h150
-rw-r--r--cpp/src/qpid/sys/Dispatcher.cpp403
-rw-r--r--cpp/src/qpid/sys/Dispatcher.h130
-rw-r--r--cpp/src/qpid/sys/ExceptionHolder.h75
-rwxr-xr-xcpp/src/qpid/sys/FileSysDir.h62
-rw-r--r--cpp/src/qpid/sys/IOHandle.h45
-rw-r--r--cpp/src/qpid/sys/LockFile.h39
-rw-r--r--cpp/src/qpid/sys/LockPtr.h89
-rw-r--r--cpp/src/qpid/sys/Monitor.h51
-rw-r--r--cpp/src/qpid/sys/Mutex.h89
-rw-r--r--cpp/src/qpid/sys/OutputControl.h11
-rwxr-xr-xcpp/src/qpid/sys/PipeHandle.h51
-rw-r--r--cpp/src/qpid/sys/PollableCondition.h64
-rw-r--r--cpp/src/qpid/sys/PollableQueue.h176
-rw-r--r--cpp/src/qpid/sys/Poller.h52
-rw-r--r--cpp/src/qpid/sys/ProtocolFactory.h5
-rw-r--r--cpp/src/qpid/sys/RdmaIOPlugin.cpp353
-rw-r--r--cpp/src/qpid/sys/Runnable.cpp2
-rw-r--r--cpp/src/qpid/sys/Runnable.h50
-rw-r--r--cpp/src/qpid/sys/SecurityLayer.h42
-rw-r--r--cpp/src/qpid/sys/Semaphore.h16
-rw-r--r--cpp/src/qpid/sys/Shlib.cpp2
-rw-r--r--cpp/src/qpid/sys/Shlib.h12
-rw-r--r--cpp/src/qpid/sys/Socket.h46
-rw-r--r--cpp/src/qpid/sys/SocketAddress.h53
-rw-r--r--cpp/src/qpid/sys/SslPlugin.cpp184
-rw-r--r--cpp/src/qpid/sys/StrError.h35
-rw-r--r--cpp/src/qpid/sys/SystemInfo.cpp35
-rw-r--r--cpp/src/qpid/sys/SystemInfo.h44
-rw-r--r--cpp/src/qpid/sys/TCPIOPlugin.cpp56
-rw-r--r--cpp/src/qpid/sys/Thread.h54
-rw-r--r--cpp/src/qpid/sys/Time.h154
-rw-r--r--cpp/src/qpid/sys/Timer.cpp179
-rw-r--r--cpp/src/qpid/sys/Timer.h94
-rw-r--r--cpp/src/qpid/sys/alloca.h39
-rw-r--r--cpp/src/qpid/sys/apr/APRBase.cpp2
-rw-r--r--cpp/src/qpid/sys/apr/APRPool.cpp4
-rw-r--r--cpp/src/qpid/sys/apr/Condition.h2
-rw-r--r--cpp/src/qpid/sys/apr/Mutex.h4
-rw-r--r--cpp/src/qpid/sys/apr/Shlib.cpp4
-rw-r--r--cpp/src/qpid/sys/apr/Socket.cpp4
-rw-r--r--cpp/src/qpid/sys/apr/Thread.cpp2
-rw-r--r--cpp/src/qpid/sys/apr/Thread.h4
-rw-r--r--cpp/src/qpid/sys/cyrus/CyrusSecurityLayer.cpp127
-rw-r--r--cpp/src/qpid/sys/cyrus/CyrusSecurityLayer.h68
-rw-r--r--cpp/src/qpid/sys/epoll/EpollPoller.cpp444
-rw-r--r--cpp/src/qpid/sys/posix/AsynchIO.cpp253
-rw-r--r--cpp/src/qpid/sys/posix/Condition.h86
-rwxr-xr-xcpp/src/qpid/sys/posix/FileSysDir.cpp54
-rw-r--r--cpp/src/qpid/sys/posix/Fork.cpp2
-rw-r--r--cpp/src/qpid/sys/posix/IOHandle.cpp4
-rwxr-xr-xcpp/src/qpid/sys/posix/LockFile.cpp108
-rw-r--r--cpp/src/qpid/sys/posix/LockFile.h58
-rw-r--r--cpp/src/qpid/sys/posix/Mutex.h158
-rw-r--r--cpp/src/qpid/sys/posix/PidFile.h62
-rwxr-xr-xcpp/src/qpid/sys/posix/PipeHandle.cpp64
-rw-r--r--cpp/src/qpid/sys/posix/PollableCondition.cpp124
-rw-r--r--cpp/src/qpid/sys/posix/PrivatePosix.h52
-rw-r--r--cpp/src/qpid/sys/posix/Shlib.cpp6
-rw-r--r--cpp/src/qpid/sys/posix/Socket.cpp127
-rw-r--r--cpp/src/qpid/sys/posix/SocketAddress.cpp97
-rwxr-xr-xcpp/src/qpid/sys/posix/SystemInfo.cpp137
-rw-r--r--cpp/src/qpid/sys/posix/Thread.cpp2
-rw-r--r--cpp/src/qpid/sys/posix/Time.cpp69
-rw-r--r--cpp/src/qpid/sys/posix/check.h49
-rw-r--r--cpp/src/qpid/sys/rdma/RdmaClient.cpp106
-rw-r--r--cpp/src/qpid/sys/rdma/RdmaIO.cpp516
-rw-r--r--cpp/src/qpid/sys/rdma/RdmaIO.h173
-rw-r--r--cpp/src/qpid/sys/rdma/RdmaServer.cpp86
-rw-r--r--cpp/src/qpid/sys/rdma/rdma_exception.h20
-rw-r--r--cpp/src/qpid/sys/rdma/rdma_factories.cpp27
-rw-r--r--cpp/src/qpid/sys/rdma/rdma_factories.h27
-rw-r--r--cpp/src/qpid/sys/rdma/rdma_wrap.cpp185
-rw-r--r--cpp/src/qpid/sys/rdma/rdma_wrap.h207
-rw-r--r--cpp/src/qpid/sys/solaris/ECFPoller.cpp244
-rwxr-xr-xcpp/src/qpid/sys/solaris/SystemInfo.cpp123
-rw-r--r--cpp/src/qpid/sys/ssl/SslHandler.cpp187
-rw-r--r--cpp/src/qpid/sys/ssl/SslHandler.h76
-rw-r--r--cpp/src/qpid/sys/ssl/SslIo.cpp439
-rw-r--r--cpp/src/qpid/sys/ssl/SslIo.h171
-rw-r--r--cpp/src/qpid/sys/ssl/SslSocket.cpp297
-rw-r--r--cpp/src/qpid/sys/ssl/SslSocket.h119
-rw-r--r--cpp/src/qpid/sys/ssl/check.cpp72
-rw-r--r--cpp/src/qpid/sys/ssl/check.h53
-rw-r--r--cpp/src/qpid/sys/ssl/util.cpp118
-rw-r--r--cpp/src/qpid/sys/ssl/util.h50
-rw-r--r--cpp/src/qpid/sys/uuid.h28
-rw-r--r--cpp/src/qpid/sys/windows/AsynchIO.cpp751
-rwxr-xr-xcpp/src/qpid/sys/windows/AsynchIoResult.h204
-rw-r--r--cpp/src/qpid/sys/windows/FileSysDir.cpp53
-rwxr-xr-xcpp/src/qpid/sys/windows/IOHandle.cpp42
-rwxr-xr-xcpp/src/qpid/sys/windows/IoHandlePrivate.h61
-rwxr-xr-xcpp/src/qpid/sys/windows/IocpPoller.cpp214
-rwxr-xr-xcpp/src/qpid/sys/windows/LockFile.cpp64
-rwxr-xr-xcpp/src/qpid/sys/windows/PipeHandle.cpp101
-rw-r--r--cpp/src/qpid/sys/windows/PollableCondition.cpp116
-rw-r--r--cpp/src/qpid/sys/windows/Shlib.cpp53
-rwxr-xr-xcpp/src/qpid/sys/windows/Socket.cpp343
-rw-r--r--cpp/src/qpid/sys/windows/SocketAddress.cpp70
-rwxr-xr-xcpp/src/qpid/sys/windows/StrError.cpp47
-rwxr-xr-xcpp/src/qpid/sys/windows/SystemInfo.cpp201
-rwxr-xr-xcpp/src/qpid/sys/windows/Thread.cpp88
-rw-r--r--cpp/src/qpid/sys/windows/Time.cpp103
-rw-r--r--cpp/src/qpid/sys/windows/uuid.cpp59
-rw-r--r--cpp/src/qpid/sys/windows/uuid.h38
-rw-r--r--cpp/src/qpid/xml/XmlBinding.h37
-rw-r--r--cpp/src/qpid/xml/XmlExchange.cpp262
-rw-r--r--cpp/src/qpid/xml/XmlExchange.h90
-rw-r--r--cpp/src/qpid/xml/XmlExchangePlugin.cpp69
-rw-r--r--cpp/src/qpidd.cpp241
-rw-r--r--cpp/src/qpidd.h70
-rw-r--r--cpp/src/rdma.cmake118
-rw-r--r--cpp/src/replication.mk52
-rw-r--r--cpp/src/ssl.cmake106
-rw-r--r--cpp/src/ssl.mk64
-rw-r--r--cpp/src/tests/.valgrind.supp95
-rw-r--r--cpp/src/tests/AccumulatedAckTest.cpp13
-rw-r--r--cpp/src/tests/Address.cpp98
-rw-r--r--cpp/src/tests/Array.cpp11
-rw-r--r--cpp/src/tests/AsyncCompletion.cpp120
-rw-r--r--cpp/src/tests/AtomicValue.cpp5
-rw-r--r--cpp/src/tests/BasicP2PTest.cpp66
-rw-r--r--cpp/src/tests/BasicP2PTest.h46
-rw-r--r--cpp/src/tests/BasicPubSubTest.cpp121
-rw-r--r--cpp/src/tests/BasicPubSubTest.h51
-rw-r--r--cpp/src/tests/Blob.cpp128
-rw-r--r--cpp/src/tests/BrokerFixture.h57
-rw-r--r--cpp/src/tests/CMakeLists.txt345
-rw-r--r--cpp/src/tests/ClientMessage.cpp46
-rw-r--r--cpp/src/tests/ClientMessageTest.cpp51
-rw-r--r--cpp/src/tests/ClientSessionTest.cpp497
-rw-r--r--cpp/src/tests/ClusterFailover.cpp68
-rw-r--r--cpp/src/tests/ClusterFixture.cpp160
-rw-r--r--cpp/src/tests/ClusterFixture.h115
-rw-r--r--cpp/src/tests/ConnectionOptions.h19
-rw-r--r--cpp/src/tests/ConsoleTest.cpp46
-rw-r--r--cpp/src/tests/DeliveryRecordTest.cpp14
-rw-r--r--cpp/src/tests/DispatcherTest.cpp173
-rw-r--r--cpp/src/tests/DtxWorkRecordTest.cpp18
-rw-r--r--cpp/src/tests/ExchangeTest.cpp159
-rw-r--r--cpp/src/tests/FieldTable.cpp160
-rw-r--r--cpp/src/tests/FieldValue.cpp21
-rw-r--r--cpp/src/tests/ForkedBroker.cpp131
-rw-r--r--cpp/src/tests/ForkedBroker.h76
-rw-r--r--cpp/src/tests/Frame.cpp13
-rw-r--r--cpp/src/tests/FrameDecoder.cpp78
-rw-r--r--cpp/src/tests/FramingTest.cpp29
-rw-r--r--cpp/src/tests/HeaderTest.cpp24
-rw-r--r--cpp/src/tests/HeadersExchangeTest.cpp31
-rw-r--r--cpp/src/tests/IncompleteMessageList.cpp20
-rw-r--r--cpp/src/tests/InitialStatusMap.cpp248
-rw-r--r--cpp/src/tests/InlineAllocator.cpp13
-rw-r--r--cpp/src/tests/InlineVector.cpp15
-rw-r--r--cpp/src/tests/Makefile.am251
-rw-r--r--cpp/src/tests/ManagementTest.cpp115
-rw-r--r--cpp/src/tests/MessageBuilderTest.cpp110
-rw-r--r--cpp/src/tests/MessageReplayTracker.cpp102
-rw-r--r--cpp/src/tests/MessageTest.cpp28
-rw-r--r--cpp/src/tests/MessageUtils.h27
-rw-r--r--cpp/src/tests/MessagingSessionTests.cpp778
-rw-r--r--cpp/src/tests/MockConnectionInputHandler.h100
-rw-r--r--cpp/src/tests/PartialFailure.cpp291
-rw-r--r--cpp/src/tests/PollableCondition.cpp109
-rw-r--r--cpp/src/tests/PollerTest.cpp135
-rw-r--r--cpp/src/tests/ProxyTest.cpp56
-rw-r--r--cpp/src/tests/QueueEvents.cpp238
-rw-r--r--cpp/src/tests/QueueOptionsTest.cpp102
-rw-r--r--cpp/src/tests/QueuePolicyTest.cpp297
-rw-r--r--cpp/src/tests/QueueRegistryTest.cpp17
-rw-r--r--cpp/src/tests/QueueTest.cpp981
-rw-r--r--cpp/src/tests/RangeSet.cpp9
-rw-r--r--cpp/src/tests/RateFlowcontrolTest.cpp71
-rw-r--r--cpp/src/tests/RefCounted.cpp5
-rw-r--r--cpp/src/tests/ReplicationTest.cpp141
-rw-r--r--cpp/src/tests/RetryList.cpp111
-rw-r--r--cpp/src/tests/SequenceNumberTest.cpp12
-rw-r--r--cpp/src/tests/SequenceSet.cpp9
-rw-r--r--cpp/src/tests/SessionState.cpp34
-rw-r--r--cpp/src/tests/Shlib.cpp20
-rw-r--r--cpp/src/tests/SimpleTestCaseBase.cpp87
-rw-r--r--cpp/src/tests/SimpleTestCaseBase.h89
-rw-r--r--cpp/src/tests/SocketProxy.h128
-rw-r--r--cpp/src/tests/StoreStatus.cpp109
-rw-r--r--cpp/src/tests/TestCase.h64
-rw-r--r--cpp/src/tests/TestMessageStore.h15
-rw-r--r--cpp/src/tests/TestOptions.h6
-rw-r--r--cpp/src/tests/TimerTest.cpp26
-rw-r--r--cpp/src/tests/TopicExchangeTest.cpp210
-rw-r--r--cpp/src/tests/TxBufferTest.cpp9
-rw-r--r--cpp/src/tests/TxMocks.h50
-rw-r--r--cpp/src/tests/TxPublishTest.cpp31
-rw-r--r--cpp/src/tests/Url.cpp58
-rw-r--r--cpp/src/tests/Uuid.cpp7
-rw-r--r--cpp/src/tests/Variant.cpp178
-rw-r--r--cpp/src/tests/XmlClientSessionTest.cpp164
-rwxr-xr-xcpp/src/tests/acl.py884
-rwxr-xr-xcpp/src/tests/ais_check57
-rw-r--r--cpp/src/tests/allSegmentTypes.h128
-rw-r--r--cpp/src/tests/amqp_0_10/Map.cpp2
-rw-r--r--cpp/src/tests/amqp_0_10/ProxyTemplate.cpp2
-rw-r--r--cpp/src/tests/amqp_0_10/apply.cpp2
-rw-r--r--cpp/src/tests/amqp_0_10/handlers.cpp2
-rw-r--r--cpp/src/tests/amqp_0_10/serialize.cpp6
-rw-r--r--cpp/src/tests/background.ps155
-rwxr-xr-xcpp/src/tests/benchmark95
-rwxr-xr-xcpp/src/tests/cli_tests.py190
-rw-r--r--cpp/src/tests/client_test.cpp54
-rw-r--r--cpp/src/tests/cluster.cmake86
-rw-r--r--cpp/src/tests/cluster.mk81
-rwxr-xr-xcpp/src/tests/cluster_python_tests5
-rw-r--r--cpp/src/tests/cluster_python_tests_failing.txt31
-rwxr-xr-xcpp/src/tests/cluster_read_credit27
-rw-r--r--cpp/src/tests/cluster_test.cpp1183
-rw-r--r--cpp/src/tests/cluster_test_scripts/README.txt20
-rwxr-xr-xcpp/src/tests/cluster_test_scripts/cluster_check17
-rwxr-xr-xcpp/src/tests/cluster_test_scripts/cluster_start36
-rwxr-xr-xcpp/src/tests/cluster_test_scripts/cluster_stop18
-rwxr-xr-xcpp/src/tests/cluster_test_scripts/config_example.sh25
-rwxr-xr-xcpp/src/tests/cluster_test_scripts/perftest34
-rw-r--r--cpp/src/tests/cluster_tests.fail2
-rwxr-xr-xcpp/src/tests/cluster_tests.py233
-rwxr-xr-xcpp/src/tests/clustered_replication_test110
-rw-r--r--cpp/src/tests/config.null1
-rw-r--r--cpp/src/tests/consume.cpp65
-rw-r--r--cpp/src/tests/datagen.cpp103
-rw-r--r--cpp/src/tests/declare_queues.cpp101
-rw-r--r--cpp/src/tests/dlclose_noop.c2
-rw-r--r--cpp/src/tests/echotest.cpp157
-rw-r--r--cpp/src/tests/exception_test.cpp44
-rw-r--r--cpp/src/tests/failover_soak.cpp826
-rwxr-xr-xcpp/src/tests/fanout_perftest20
-rwxr-xr-xcpp/src/tests/federated_cluster_test152
-rwxr-xr-xcpp/src/tests/federated_cluster_test_with_node_failure23
-rwxr-xr-xcpp/src/tests/federated_topic_test87
-rwxr-xr-xcpp/src/tests/federation.py583
-rw-r--r--cpp/src/tests/find_prog.ps136
-rw-r--r--cpp/src/tests/header_test.cpp59
-rwxr-xr-xcpp/src/tests/header_test.py86
-rw-r--r--cpp/src/tests/interop_runner.cpp251
-rw-r--r--cpp/src/tests/latencytest.cpp223
-rw-r--r--cpp/src/tests/logging.cpp131
-rwxr-xr-xcpp/src/tests/long_cluster_tests.py38
-rwxr-xr-xcpp/src/tests/multiq_perftest20
-rwxr-xr-xcpp/src/tests/perfdist71
-rw-r--r--cpp/src/tests/perftest.cpp286
-rw-r--r--cpp/src/tests/policy.acl1
-rw-r--r--cpp/src/tests/publish.cpp61
-rwxr-xr-xcpp/src/tests/python_tests38
-rw-r--r--cpp/src/tests/python_tests.ps142
-rw-r--r--cpp/src/tests/qpid_ping.cpp123
-rw-r--r--cpp/src/tests/qpid_stream.cpp170
-rw-r--r--cpp/src/tests/qrsh.cpp169
-rw-r--r--cpp/src/tests/qrsh_run.cpp321
-rw-r--r--cpp/src/tests/qrsh_server.cpp1065
-rwxr-xr-xcpp/src/tests/qrsh_utils/10_all30
-rwxr-xr-xcpp/src/tests/qrsh_utils/1_remote_run26
-rwxr-xr-xcpp/src/tests/qrsh_utils/2_forever26
-rwxr-xr-xcpp/src/tests/qrsh_utils/3_kill_it27
-rwxr-xr-xcpp/src/tests/qrsh_utils/4_wait_for_it26
-rwxr-xr-xcpp/src/tests/qrsh_utils/5_exited64
-rwxr-xr-xcpp/src/tests/qrsh_utils/6_get29
-rwxr-xr-xcpp/src/tests/qrsh_utils/7_get_output44
-rwxr-xr-xcpp/src/tests/qrsh_utils/8_any43
-rwxr-xr-xcpp/src/tests/qrsh_utils/9_alias38
-rw-r--r--cpp/src/tests/qrsh_utils/qrsh_example_command.cpp52
-rw-r--r--cpp/src/tests/qrsh_utils/qrsh_forever.cpp50
-rw-r--r--cpp/src/tests/qrsh_utils/qsh_doc.txt309
-rwxr-xr-xcpp/src/tests/quick_perftest20
-rwxr-xr-xcpp/src/tests/quick_topictest23
-rw-r--r--cpp/src/tests/quick_topictest.ps130
-rwxr-xr-xcpp/src/tests/quick_txtest22
-rw-r--r--cpp/src/tests/receiver.cpp139
-rwxr-xr-xcpp/src/tests/reliable_replication_test93
-rw-r--r--cpp/src/tests/replaying_sender.cpp163
-rwxr-xr-xcpp/src/tests/replication_test182
-rwxr-xr-xcpp/src/tests/restart_cluster20
-rw-r--r--cpp/src/tests/resuming_receiver.cpp192
-rwxr-xr-xcpp/src/tests/ring_queue_test174
-rwxr-xr-xcpp/src/tests/run-unit-tests20
-rwxr-xr-xcpp/src/tests/run_acl_tests64
-rwxr-xr-xcpp/src/tests/run_cli_tests51
-rwxr-xr-xcpp/src/tests/run_cluster_test26
-rwxr-xr-xcpp/src/tests/run_cluster_tests38
-rwxr-xr-xcpp/src/tests/run_failover_soak38
-rwxr-xr-xcpp/src/tests/run_federation_tests33
-rw-r--r--cpp/src/tests/run_federation_tests.ps180
-rwxr-xr-xcpp/src/tests/run_header_test37
-rw-r--r--cpp/src/tests/run_header_test.ps147
-rwxr-xr-xcpp/src/tests/run_long_cluster_tests23
-rwxr-xr-xcpp/src/tests/run_perftest20
-rwxr-xr-xcpp/src/tests/run_ring_queue_test36
-rwxr-xr-xcpp/src/tests/run_test45
-rw-r--r--cpp/src/tests/run_test.ps173
-rw-r--r--cpp/src/tests/sender.cpp137
-rwxr-xr-xcpp/src/tests/shared_perftest20
-rw-r--r--cpp/src/tests/shlibtest.cpp12
-rw-r--r--cpp/src/tests/ssl.mk23
-rwxr-xr-xcpp/src/tests/ssl_test82
-rwxr-xr-xcpp/src/tests/start_broker22
-rw-r--r--cpp/src/tests/start_broker.ps160
-rwxr-xr-xcpp/src/tests/start_cluster56
-rwxr-xr-xcpp/src/tests/start_cluster_hosts70
-rwxr-xr-xcpp/src/tests/stop_broker22
-rw-r--r--cpp/src/tests/stop_broker.ps156
-rwxr-xr-xcpp/src/tests/stop_cluster24
-rw-r--r--cpp/src/tests/test_env.sh.in68
-rw-r--r--cpp/src/tests/test_store.cpp178
-rw-r--r--cpp/src/tests/test_tools.h48
-rwxr-xr-xcpp/src/tests/test_watchdog36
-rwxr-xr-xcpp/src/tests/test_wrap48
-rw-r--r--cpp/src/tests/testlib.py766
-rw-r--r--cpp/src/tests/topic_listener.cpp121
-rwxr-xr-xcpp/src/tests/topic_perftest20
-rw-r--r--cpp/src/tests/topic_publisher.cpp138
-rwxr-xr-xcpp/src/tests/topictest20
-rw-r--r--cpp/src/tests/topictest.ps170
-rw-r--r--cpp/src/tests/txjob.cpp102
-rw-r--r--cpp/src/tests/txshift.cpp193
-rw-r--r--cpp/src/tests/txtest.cpp115
-rw-r--r--cpp/src/tests/unit_test.h16
-rw-r--r--cpp/src/tests/vg_check5
-rw-r--r--cpp/src/tests/windows/DisableWin32ErrorWindows.cpp72
-rw-r--r--cpp/src/windows/QpiddBroker.cpp310
-rw-r--r--cpp/src/xml.mk28
-rw-r--r--cpp/xml/cluster.xml199
-rw-r--r--dotnet/DISCLAIMER5
-rw-r--r--dotnet/NOTICE.txt8
-rw-r--r--dotnet/Qpid.Buffer.Tests/Properties/AssemblyInfo.cs91
-rw-r--r--dotnet/Qpid.Buffer.Tests/Qpid.Buffer.Tests.csproj142
-rw-r--r--dotnet/Qpid.Buffer.Tests/SimpleByteBufferTests.cs666
-rw-r--r--dotnet/Qpid.Buffer.Tests/SlicedByteBufferTests.cs266
-rw-r--r--dotnet/Qpid.Buffer.Tests/default.build75
-rw-r--r--dotnet/Qpid.Buffer/IByteBufferAllocator.cs100
-rw-r--r--dotnet/Qpid.Buffer/Properties/AssemblyInfo.cs2
-rw-r--r--dotnet/Qpid.Buffer/Qpid.Buffer.csproj40
-rw-r--r--dotnet/Qpid.Buffer/SimpleByteBuffer.cs240
-rw-r--r--dotnet/Qpid.Buffer/SlicedByteBuffer.cs172
-rw-r--r--dotnet/Qpid.Buffer/default.build71
-rw-r--r--dotnet/Qpid.Client.Tests/App.config47
-rw-r--r--dotnet/Qpid.Client.Tests/BrokerDetails/BrokerDetailsTest.cs130
-rw-r--r--dotnet/Qpid.Client.Tests/Channel/ChannelMessageCreationTests.cs158
-rw-r--r--dotnet/Qpid.Client.Tests/Messages/MessageFactoryRegistryTests.cs228
-rw-r--r--dotnet/Qpid.Client.Tests/Properties/AssemblyInfo.cs2
-rw-r--r--dotnet/Qpid.Client.Tests/Qpid.Client.Tests.csproj92
-rw-r--r--dotnet/Qpid.Client.Tests/Security/CallbackHandlerRegistryTests.cs132
-rw-r--r--dotnet/Qpid.Client.Tests/default.build21
-rw-r--r--dotnet/Qpid.Client.Tests/interop/TopicListener.cs422
-rw-r--r--dotnet/Qpid.Client.Tests/interop/TopicPublisher.cs396
-rw-r--r--dotnet/Qpid.Client.Tests/log4net.config22
-rw-r--r--dotnet/Qpid.Client.Transport.Socket.Blocking/Properties/AssemblyInfo.cs2
-rw-r--r--dotnet/Qpid.Client.Transport.Socket.Blocking/Qpid.Client.Transport.Socket.Blocking.csproj21
-rw-r--r--dotnet/Qpid.Client/Client/AMQAuthenticationException.cs78
-rw-r--r--dotnet/Qpid.Client/Client/AMQNoConsumersException.cs90
-rw-r--r--dotnet/Qpid.Client/Client/AMQNoRouteException.cs92
-rw-r--r--dotnet/Qpid.Client/Client/Configuration/AuthenticationConfigurationSectionHandler.cs168
-rw-r--r--dotnet/Qpid.Client/Client/Handler/QueueDeleteOkMethodHandler.cs88
-rw-r--r--dotnet/Qpid.Client/Client/Handler/QueuePurgeOkMethodHandler.cs88
-rw-r--r--dotnet/Qpid.Client/Client/Message/QpidHeaders.cs20
-rw-r--r--dotnet/Qpid.Client/Client/Protocol/DefaultTimeouts.cs94
-rw-r--r--dotnet/Qpid.Client/Client/Security/CallbackHandlerRegistry.cs256
-rw-r--r--dotnet/Qpid.Client/Client/Security/IAMQCallbackHandler.cs70
-rw-r--r--dotnet/Qpid.Client/Client/Security/UsernamePasswordCallbackHandler.cs112
-rw-r--r--dotnet/Qpid.Client/Client/SslOptions.cs162
-rw-r--r--dotnet/Qpid.Client/Client/Transport/IStreamFilter.cs76
-rw-r--r--dotnet/Qpid.Client/Client/Transport/IoHandler.cs644
-rw-r--r--dotnet/Qpid.Client/Client/Transport/ProtocolDecoderOutput.cs120
-rw-r--r--dotnet/Qpid.Client/Client/Transport/Socket/Blocking/BlockingSocketTransport.cs300
-rw-r--r--dotnet/Qpid.Client/Client/Transport/Socket/Blocking/ByteChannel.cs184
-rw-r--r--dotnet/Qpid.Client/Client/Transport/Socket/Blocking/ISocketConnector.cs68
-rw-r--r--dotnet/Qpid.Client/Client/Transport/Socket/Blocking/SocketConnector.cs142
-rw-r--r--dotnet/Qpid.Client/Client/Transport/Socket/Blocking/SslSocketConnector.cs214
-rw-r--r--dotnet/Qpid.Client/Client/Util/FlowControlQueue.cs196
-rw-r--r--dotnet/Qpid.Client/Properties/AssemblyInfo.cs2
-rw-r--r--dotnet/Qpid.Client/Qpid.Client.csproj119
-rw-r--r--dotnet/Qpid.Client/default.build21
-rw-r--r--dotnet/Qpid.Codec/Properties/AssemblyInfo.cs2
-rw-r--r--dotnet/Qpid.Codec/Qpid.Codec.csproj49
-rw-r--r--dotnet/Qpid.Codec/default.build73
-rw-r--r--dotnet/Qpid.Common.Tests/Properties/AssemblyInfo.cs23
-rw-r--r--dotnet/Qpid.Common.Tests/Qpid.Common.Tests.csproj36
-rw-r--r--dotnet/Qpid.Common.Tests/Qpid/Collections/TestConsumerProducerQueue.cs170
-rw-r--r--dotnet/Qpid.Common.Tests/Qpid/Framing/TestAMQType.cs540
-rw-r--r--dotnet/Qpid.Common.Tests/Qpid/Framing/TestEncodingUtils.cs120
-rw-r--r--dotnet/Qpid.Common.Tests/default.build83
-rw-r--r--dotnet/Qpid.Common/AMQInvalidArgumentException.cs92
-rw-r--r--dotnet/Qpid.Common/AMQInvalidRoutingKeyException.cs92
-rw-r--r--dotnet/Qpid.Common/Collections/ConsumerProducerQueue.cs226
-rw-r--r--dotnet/Qpid.Common/Framing/AMQType.cs1400
-rw-r--r--dotnet/Qpid.Common/Framing/AMQTypeMap.cs150
-rw-r--r--dotnet/Qpid.Common/Framing/AMQTypedValue.cs152
-rw-r--r--dotnet/Qpid.Common/Properties/AssemblyInfo.cs2
-rw-r--r--dotnet/Qpid.Common/Protocol/AMQConstant.cs200
-rw-r--r--dotnet/Qpid.Common/Qpid.Common.csproj167
-rw-r--r--dotnet/Qpid.Common/amqp.xml21
-rw-r--r--dotnet/Qpid.Common/build.xml22
-rw-r--r--dotnet/Qpid.Common/default.build21
-rw-r--r--dotnet/Qpid.Common/lib/log4net/log4net.xml21
-rw-r--r--dotnet/Qpid.Common/stylesheets/csharp.xsl21
-rw-r--r--dotnet/Qpid.Common/stylesheets/framing.xsl21
-rw-r--r--dotnet/Qpid.Common/stylesheets/java.xsl21
-rw-r--r--dotnet/Qpid.Common/stylesheets/prepare1.xsl21
-rw-r--r--dotnet/Qpid.Common/stylesheets/prepare2.xsl21
-rw-r--r--dotnet/Qpid.Common/stylesheets/prepare3.xsl21
-rw-r--r--dotnet/Qpid.Common/stylesheets/registry.xsl21
-rw-r--r--dotnet/Qpid.Common/stylesheets/utils.xsl21
-rw-r--r--dotnet/Qpid.Integration.Tests/Properties/AssemblyInfo.cs106
-rwxr-xr-xdotnet/Qpid.Integration.Tests/Qpid.Integration.Tests.csproj189
-rw-r--r--dotnet/Qpid.Integration.Tests/default.build117
-rw-r--r--dotnet/Qpid.Integration.Tests/framework/Assertion.cs76
-rw-r--r--dotnet/Qpid.Integration.Tests/framework/Circuit.cs202
-rw-r--r--dotnet/Qpid.Integration.Tests/framework/FrameworkBaseCase.cs562
-rw-r--r--dotnet/Qpid.Integration.Tests/framework/Publisher.cs128
-rw-r--r--dotnet/Qpid.Integration.Tests/framework/Receiver.cs158
-rw-r--r--dotnet/Qpid.Integration.Tests/framework/TestClientDetails.cs168
-rw-r--r--dotnet/Qpid.Integration.Tests/framework/TestModel.cs1312
-rw-r--r--dotnet/Qpid.Integration.Tests/framework/sequencers/CircuitFactory.cs168
-rw-r--r--dotnet/Qpid.Integration.Tests/interactive/FailoverTest.cs4
-rw-r--r--dotnet/Qpid.Integration.Tests/interactive/SendReceiveTest.cs360
-rw-r--r--dotnet/Qpid.Integration.Tests/interop/InteropClientTestCase.cs154
-rw-r--r--dotnet/Qpid.Integration.Tests/interop/TestCases/TestCase1DummyRun.cs158
-rw-r--r--dotnet/Qpid.Integration.Tests/interop/TestCases/TestCase2BasicP2P.cs390
-rw-r--r--dotnet/Qpid.Integration.Tests/interop/TestCases/TestCase3BasicPubSub.cs468
-rw-r--r--dotnet/Qpid.Integration.Tests/interop/TestClient.cs738
-rw-r--r--dotnet/Qpid.Integration.Tests/log4net.config117
-rw-r--r--dotnet/Qpid.Integration.Tests/testcases/BaseMessagingTestFixture.cs522
-rw-r--r--dotnet/Qpid.Integration.Tests/testcases/ChannelQueueTest.cs474
-rw-r--r--dotnet/Qpid.Integration.Tests/testcases/CommitRollbackTest.cs522
-rw-r--r--dotnet/Qpid.Integration.Tests/testcases/ConnectionTest.cs146
-rw-r--r--dotnet/Qpid.Integration.Tests/testcases/DurableSubscriptionTest.cs332
-rw-r--r--dotnet/Qpid.Integration.Tests/testcases/HeadersExchangeTest.cs564
-rw-r--r--dotnet/Qpid.Integration.Tests/testcases/MandatoryMessageTest.cs298
-rw-r--r--dotnet/Qpid.Integration.Tests/testcases/ProducerMultiConsumerTest.cs334
-rwxr-xr-xdotnet/Qpid.Integration.Tests/testcases/Qpid.Integration.Tests.csproj105
-rw-r--r--dotnet/Qpid.Integration.Tests/testcases/SslConnectionTest.cs128
-rw-r--r--dotnet/Qpid.Integration.Tests/testcases/SustainedTest.cs218
-rw-r--r--dotnet/Qpid.Messaging/ICloseable.cs76
-rw-r--r--dotnet/Qpid.Messaging/Properties/AssemblyInfo.cs2
-rw-r--r--dotnet/Qpid.Messaging/Qpid.Messaging.csproj98
-rw-r--r--dotnet/Qpid.Messaging/default.build69
-rw-r--r--dotnet/Qpid.NET.sln17
-rw-r--r--dotnet/Qpid.Sasl.Tests/App.config45
-rw-r--r--dotnet/Qpid.Sasl.Tests/Mechanisms/AnonymousSaslClientTests.cs144
-rw-r--r--dotnet/Qpid.Sasl.Tests/Mechanisms/CramMD5SaslClientTests.cs180
-rw-r--r--dotnet/Qpid.Sasl.Tests/Mechanisms/DigestSaslClientTests.cs498
-rw-r--r--dotnet/Qpid.Sasl.Tests/Mechanisms/ExternalSaslClientTests.cs142
-rw-r--r--dotnet/Qpid.Sasl.Tests/Mechanisms/PlainSaslClientTests.cs176
-rw-r--r--dotnet/Qpid.Sasl.Tests/Properties/AssemblyInfo.cs91
-rw-r--r--dotnet/Qpid.Sasl.Tests/Qpid.Sasl.Tests.csproj153
-rw-r--r--dotnet/Qpid.Sasl.Tests/SaslTests.cs266
-rw-r--r--dotnet/Qpid.Sasl.Tests/TestClientFactory.cs150
-rw-r--r--dotnet/Qpid.Sasl.Tests/default.build83
-rw-r--r--dotnet/Qpid.Sasl/Callbacks.cs245
-rw-r--r--dotnet/Qpid.Sasl/Configuration/SaslConfiguration.cs180
-rw-r--r--dotnet/Qpid.Sasl/Configuration/SaslConfigurationSectionHandler.cs168
-rw-r--r--dotnet/Qpid.Sasl/DefaultClientFactory.cs194
-rw-r--r--dotnet/Qpid.Sasl/ISaslCallbackHandler.cs70
-rw-r--r--dotnet/Qpid.Sasl/ISaslClient.cs84
-rw-r--r--dotnet/Qpid.Sasl/ISaslClientFactory.cs80
-rw-r--r--dotnet/Qpid.Sasl/MD5HMAC.cs230
-rw-r--r--dotnet/Qpid.Sasl/Mechanisms/AnonymousSaslClient.cs138
-rw-r--r--dotnet/Qpid.Sasl/Mechanisms/CramMD5HexSaslClient.cs93
-rw-r--r--dotnet/Qpid.Sasl/Mechanisms/CramMD5SaslClient.cs182
-rw-r--r--dotnet/Qpid.Sasl/Mechanisms/DigestSaslClient.cs1152
-rw-r--r--dotnet/Qpid.Sasl/Mechanisms/ExternalSaslClient.cs138
-rw-r--r--dotnet/Qpid.Sasl/Mechanisms/PlainSaslClient.cs162
-rw-r--r--dotnet/Qpid.Sasl/Properties/AssemblyInfo.cs94
-rw-r--r--dotnet/Qpid.Sasl/Qpid.Sasl.csproj137
-rw-r--r--dotnet/Qpid.Sasl/Sasl.cs230
-rw-r--r--dotnet/Qpid.Sasl/SaslClient.cs290
-rw-r--r--dotnet/Qpid.Sasl/SaslException.cs112
-rw-r--r--dotnet/Qpid.Sasl/SaslProperties.cs84
-rw-r--r--dotnet/Qpid.Sasl/default.build69
-rw-r--r--dotnet/README.txt61
-rw-r--r--dotnet/RELEASE_NOTES.txt54
-rw-r--r--dotnet/TODO.txt6
-rw-r--r--dotnet/TestClient/Program.cs40
-rw-r--r--dotnet/TestClient/Properties/AssemblyInfo.cs86
-rw-r--r--dotnet/TestClient/TestClient.csproj204
-rw-r--r--dotnet/TestClient/default.build73
-rw-r--r--dotnet/TopicListener/Program.cs40
-rw-r--r--dotnet/TopicListener/Properties/AssemblyInfo.cs86
-rw-r--r--dotnet/TopicListener/TopicListener.csproj204
-rw-r--r--dotnet/TopicListener/default.build73
-rw-r--r--dotnet/TopicPublisher/Program.cs40
-rw-r--r--dotnet/TopicPublisher/Properties/AssemblyInfo.cs86
-rw-r--r--dotnet/TopicPublisher/TopicPublisher.csproj196
-rw-r--r--dotnet/TopicPublisher/default.build73
-rw-r--r--dotnet/build-dotnet111
-rw-r--r--dotnet/build-dotnet11.bat1
-rw-r--r--dotnet/build-dotnet203
-rw-r--r--dotnet/build-framing2
-rw-r--r--dotnet/build-framing.bat21
-rwxr-xr-xdotnet/build-mono2
-rw-r--r--dotnet/build-msbuild.bat22
-rwxr-xr-xdotnet/build-nant-release55
-rw-r--r--dotnet/build-nant.bat22
-rw-r--r--dotnet/client-010/App.config34
-rw-r--r--dotnet/client-010/LICENSE.txt757
-rw-r--r--dotnet/client-010/NOTICE.txt32
-rw-r--r--dotnet/client-010/README.txt69
-rw-r--r--dotnet/client-010/addins/ExcelAddIn/Excel.exe.config12
-rw-r--r--dotnet/client-010/addins/ExcelAddIn/ExcelAddIn.cs290
-rw-r--r--dotnet/client-010/addins/ExcelAddIn/ExcelAddIn.csproj69
-rw-r--r--dotnet/client-010/addins/ExcelAddIn/Properties/AssemblyInfo.cs56
-rw-r--r--dotnet/client-010/addins/ExcelAddInMessageProcessor/ExcelAddInMessageProcessor.csproj66
-rw-r--r--dotnet/client-010/addins/ExcelAddInMessageProcessor/Processor.cs44
-rw-r--r--dotnet/client-010/addins/ExcelAddInMessageProcessor/Properties/AssemblyInfo.cs56
-rw-r--r--dotnet/client-010/addins/ExcelAddInProducer/ExcelAddInProducer.csproj63
-rw-r--r--dotnet/client-010/addins/ExcelAddInProducer/Program.cs62
-rw-r--r--dotnet/client-010/addins/ExcelAddInProducer/Properties/AssemblyInfo.cs54
-rw-r--r--dotnet/client-010/addins/README.txt29
-rw-r--r--dotnet/client-010/client/Client.csproj222
-rw-r--r--dotnet/client-010/client/Properties/AssemblyInfo.cs56
-rw-r--r--dotnet/client-010/client/client.sln109
-rw-r--r--dotnet/client-010/client/client.suobin0 -> 572415 bytes
-rw-r--r--dotnet/client-010/client/client/Client.cs170
-rw-r--r--dotnet/client-010/client/client/ClientConnectionDelegate.cs108
-rw-r--r--dotnet/client-010/client/client/ClientInterface.cs59
-rw-r--r--dotnet/client-010/client/client/ClientSession.cs109
-rw-r--r--dotnet/client-010/client/client/ClientSessionDelegate.cs55
-rw-r--r--dotnet/client-010/client/client/ClosedListenerInterface.cs29
-rw-r--r--dotnet/client-010/client/client/ErrorCode.cs140
-rw-r--r--dotnet/client-010/client/client/IClient.cs81
-rw-r--r--dotnet/client-010/client/client/IClientSession.cs18
-rw-r--r--dotnet/client-010/client/client/IClosedListener.cs29
-rw-r--r--dotnet/client-010/client/client/IMessage.cs48
-rw-r--r--dotnet/client-010/client/client/IMessageListener.cs31
-rw-r--r--dotnet/client-010/client/client/Message.cs131
-rw-r--r--dotnet/client-010/client/default.build46
-rw-r--r--dotnet/client-010/client/transport/Binary.cs129
-rw-r--r--dotnet/client-010/client/transport/Binding.cs34
-rw-r--r--dotnet/client-010/client/transport/Channel.cs174
-rw-r--r--dotnet/client-010/client/transport/ChannelDelegate.cs41
-rw-r--r--dotnet/client-010/client/transport/ClientDelegate.cs35
-rw-r--r--dotnet/client-010/client/transport/Connection.cs168
-rw-r--r--dotnet/client-010/client/transport/ConnectionDelegate.cs108
-rw-r--r--dotnet/client-010/client/transport/Field.cs74
-rw-r--r--dotnet/client-010/client/transport/Future.cs38
-rw-r--r--dotnet/client-010/client/transport/Header.cs83
-rw-r--r--dotnet/client-010/client/transport/IBinding.cs34
-rw-r--r--dotnet/client-010/client/transport/IFuture.cs38
-rw-r--r--dotnet/client-010/client/transport/IProtocolDelegate.cs37
-rw-r--r--dotnet/client-010/client/transport/IProtocolEvent.cs42
-rw-r--r--dotnet/client-010/client/transport/IReceiver.cs38
-rw-r--r--dotnet/client-010/client/transport/ISender.cs32
-rw-r--r--dotnet/client-010/client/transport/ISession.cs52
-rw-r--r--dotnet/client-010/client/transport/Method.cs150
-rw-r--r--dotnet/client-010/client/transport/ProtocolDelegate.cs37
-rw-r--r--dotnet/client-010/client/transport/ProtocolError.cs85
-rw-r--r--dotnet/client-010/client/transport/ProtocolEvent.cs42
-rw-r--r--dotnet/client-010/client/transport/ProtocolHeader.cs124
-rw-r--r--dotnet/client-010/client/transport/Range.cs117
-rw-r--r--dotnet/client-010/client/transport/RangeSet.cs150
-rw-r--r--dotnet/client-010/client/transport/ReceivedPayload.cs43
-rw-r--r--dotnet/client-010/client/transport/Receiver.cs38
-rw-r--r--dotnet/client-010/client/transport/Sender.cs32
-rw-r--r--dotnet/client-010/client/transport/Session.cs522
-rw-r--r--dotnet/client-010/client/transport/SessionDelegate.cs126
-rw-r--r--dotnet/client-010/client/transport/Struct.cs121
-rw-r--r--dotnet/client-010/client/transport/codec/AbstractDecoder.cs399
-rw-r--r--dotnet/client-010/client/transport/codec/AbstractEncoder.cs590
-rw-r--r--dotnet/client-010/client/transport/codec/Decoder.cs72
-rw-r--r--dotnet/client-010/client/transport/codec/Encodable.cs37
-rw-r--r--dotnet/client-010/client/transport/codec/Encoder.cs70
-rw-r--r--dotnet/client-010/client/transport/codec/IDecoder.cs72
-rw-r--r--dotnet/client-010/client/transport/codec/IEncodable.cs37
-rw-r--r--dotnet/client-010/client/transport/codec/IEncoder.cs70
-rw-r--r--dotnet/client-010/client/transport/codec/MSDecoder.cs110
-rw-r--r--dotnet/client-010/client/transport/codec/MSEncoder.cs172
-rw-r--r--dotnet/client-010/client/transport/exception/ConnectionException.cs49
-rw-r--r--dotnet/client-010/client/transport/exception/ExceptionArgs.cs41
-rw-r--r--dotnet/client-010/client/transport/exception/ProtocolVersionException.cs59
-rw-r--r--dotnet/client-010/client/transport/exception/SessionClosedException.cs38
-rw-r--r--dotnet/client-010/client/transport/exception/SessionException.cs45
-rw-r--r--dotnet/client-010/client/transport/exception/TransportException.cs46
-rw-r--r--dotnet/client-010/client/transport/network/Assembler.cs254
-rw-r--r--dotnet/client-010/client/transport/network/Disassembler.cs222
-rw-r--r--dotnet/client-010/client/transport/network/Frame.cs143
-rw-r--r--dotnet/client-010/client/transport/network/IIoSender.cs28
-rw-r--r--dotnet/client-010/client/transport/network/INetworkDelegate.cs40
-rw-r--r--dotnet/client-010/client/transport/network/INetworkEvent.cs32
-rw-r--r--dotnet/client-010/client/transport/network/InputHandler.cs266
-rw-r--r--dotnet/client-010/client/transport/network/NetworkDelegate.cs40
-rw-r--r--dotnet/client-010/client/transport/network/NetworkEvent.cs32
-rw-r--r--dotnet/client-010/client/transport/network/io/IIoSender.cs28
-rw-r--r--dotnet/client-010/client/transport/network/io/IIoTransport.cs57
-rw-r--r--dotnet/client-010/client/transport/network/io/IoReceiver.cs185
-rw-r--r--dotnet/client-010/client/transport/network/io/IoSSLTransport.cs192
-rw-r--r--dotnet/client-010/client/transport/network/io/IoSender.cs134
-rw-r--r--dotnet/client-010/client/transport/network/io/IoTransport.cs141
-rw-r--r--dotnet/client-010/client/transport/util/ByteEncoder.cs218
-rw-r--r--dotnet/client-010/client/transport/util/CircularBuffer.cs132
-rw-r--r--dotnet/client-010/client/transport/util/Functions.cs41
-rw-r--r--dotnet/client-010/client/transport/util/Logger.cs114
-rw-r--r--dotnet/client-010/client/transport/util/ResultFuture.cs80
-rw-r--r--dotnet/client-010/client/transport/util/Serial.cs94
-rw-r--r--dotnet/client-010/client/transport/util/UUID.cs129
-rw-r--r--dotnet/client-010/default.build275
-rw-r--r--dotnet/client-010/demo/Demo.csproj90
-rw-r--r--dotnet/client-010/demo/Program.cs126
-rw-r--r--dotnet/client-010/demo/Properties/AssemblyInfo.cs54
-rw-r--r--dotnet/client-010/demo/Properties/Resources.Designer.cs63
-rw-r--r--dotnet/client-010/demo/Properties/Resources.resx117
-rw-r--r--dotnet/client-010/demo/Properties/Settings.Designer.cs26
-rw-r--r--dotnet/client-010/demo/Properties/Settings.settings7
-rw-r--r--dotnet/client-010/demo/default.build48
-rw-r--r--dotnet/client-010/examples/direct/example-direct-Listener/Listener.cs117
-rw-r--r--dotnet/client-010/examples/direct/example-direct-Listener/Properties/AssemblyInfo.cs54
-rw-r--r--dotnet/client-010/examples/direct/example-direct-Listener/default.build48
-rw-r--r--dotnet/client-010/examples/direct/example-direct-Listener/example-direct-Listener.csproj65
-rw-r--r--dotnet/client-010/examples/direct/example-direct-producer/Producer.cs92
-rw-r--r--dotnet/client-010/examples/direct/example-direct-producer/Properties/AssemblyInfo.cs54
-rw-r--r--dotnet/client-010/examples/direct/example-direct-producer/default.build48
-rw-r--r--dotnet/client-010/examples/direct/example-direct-producer/example-direct-producer.csproj65
-rw-r--r--dotnet/client-010/examples/direct/verify37
-rw-r--r--dotnet/client-010/examples/direct/verify.in14
-rw-r--r--dotnet/client-010/examples/direct/verify_cpp_dotnet10
-rw-r--r--dotnet/client-010/examples/direct/verify_cpp_dotnet.in14
-rw-r--r--dotnet/client-010/examples/direct/verify_dotnet_cpp10
-rw-r--r--dotnet/client-010/examples/direct/verify_dotnet_cpp.in15
-rw-r--r--dotnet/client-010/examples/direct/verify_dotnet_java15
-rw-r--r--dotnet/client-010/examples/direct/verify_dotnet_java.in20
-rw-r--r--dotnet/client-010/examples/direct/verify_dotnet_python10
-rw-r--r--dotnet/client-010/examples/direct/verify_dotnet_python.in14
-rw-r--r--dotnet/client-010/examples/direct/verify_java_dotnet15
-rw-r--r--dotnet/client-010/examples/direct/verify_java_dotnet.in29
-rw-r--r--dotnet/client-010/examples/direct/verify_python_dotnet10
-rw-r--r--dotnet/client-010/examples/direct/verify_python_dotnet.in14
-rw-r--r--dotnet/client-010/examples/fanout/example-fanout-Listener/Listener.cs126
-rw-r--r--dotnet/client-010/examples/fanout/example-fanout-Listener/Properties/AssemblyInfo.cs54
-rw-r--r--dotnet/client-010/examples/fanout/example-fanout-Listener/default.build48
-rw-r--r--dotnet/client-010/examples/fanout/example-fanout-Listener/example-fanout-Listener.csproj65
-rw-r--r--dotnet/client-010/examples/fanout/example-fanout-Producer/Producer.cs89
-rw-r--r--dotnet/client-010/examples/fanout/example-fanout-Producer/Properties/AssemblyInfo.cs54
-rw-r--r--dotnet/client-010/examples/fanout/example-fanout-Producer/default.build48
-rw-r--r--dotnet/client-010/examples/fanout/example-fanout-Producer/example-fanout-Producer.csproj65
-rw-r--r--dotnet/client-010/examples/fanout/verify36
-rw-r--r--dotnet/client-010/examples/fanout/verify.in14
-rw-r--r--dotnet/client-010/examples/fanout/verify_cpp_dotnet11
-rw-r--r--dotnet/client-010/examples/fanout/verify_cpp_dotnet.in14
-rw-r--r--dotnet/client-010/examples/fanout/verify_dotnet_cpp12
-rw-r--r--dotnet/client-010/examples/fanout/verify_dotnet_cpp.in15
-rw-r--r--dotnet/client-010/examples/fanout/verify_dotnet_java16
-rw-r--r--dotnet/client-010/examples/fanout/verify_dotnet_java.in19
-rw-r--r--dotnet/client-010/examples/fanout/verify_dotnet_python11
-rw-r--r--dotnet/client-010/examples/fanout/verify_dotnet_python.in14
-rw-r--r--dotnet/client-010/examples/fanout/verify_java_dotnet16
-rw-r--r--dotnet/client-010/examples/fanout/verify_java_dotnet.in29
-rw-r--r--dotnet/client-010/examples/fanout/verify_python_dotnet11
-rw-r--r--dotnet/client-010/examples/fanout/verify_python_dotnet.in14
-rw-r--r--dotnet/client-010/examples/pub-sub/example-pub-sub-Listener/Listener.cs143
-rw-r--r--dotnet/client-010/examples/pub-sub/example-pub-sub-Listener/Properties/AssemblyInfo.cs54
-rw-r--r--dotnet/client-010/examples/pub-sub/example-pub-sub-Listener/default.build48
-rw-r--r--dotnet/client-010/examples/pub-sub/example-pub-sub-Listener/example-pub-sub-Listener.csproj65
-rw-r--r--dotnet/client-010/examples/pub-sub/example-pub-sub-Publisher/Properties/AssemblyInfo.cs54
-rw-r--r--dotnet/client-010/examples/pub-sub/example-pub-sub-Publisher/Publisher.cs98
-rw-r--r--dotnet/client-010/examples/pub-sub/example-pub-sub-Publisher/default.build48
-rw-r--r--dotnet/client-010/examples/pub-sub/example-pub-sub-Publisher/example-pub-sub-Publisher.csproj65
-rw-r--r--dotnet/client-010/examples/pub-sub/verify36
-rw-r--r--dotnet/client-010/examples/pub-sub/verify.in95
-rw-r--r--dotnet/client-010/examples/pub-sub/verify_cpp_dotnet12
-rw-r--r--dotnet/client-010/examples/pub-sub/verify_cpp_dotnet.in55
-rw-r--r--dotnet/client-010/examples/pub-sub/verify_dotnet_cpp11
-rw-r--r--dotnet/client-010/examples/pub-sub/verify_dotnet_cpp.in99
-rw-r--r--dotnet/client-010/examples/pub-sub/verify_dotnet_java15
-rw-r--r--dotnet/client-010/examples/pub-sub/verify_dotnet_java.in95
-rw-r--r--dotnet/client-010/examples/pub-sub/verify_dotnet_python11
-rw-r--r--dotnet/client-010/examples/pub-sub/verify_dotnet_python.in95
-rw-r--r--dotnet/client-010/examples/pub-sub/verify_java_dotnet15
-rw-r--r--dotnet/client-010/examples/pub-sub/verify_java_dotnet.in95
-rw-r--r--dotnet/client-010/examples/pub-sub/verify_python_dotnet11
-rw-r--r--dotnet/client-010/examples/pub-sub/verify_python_dotnet.in55
-rw-r--r--dotnet/client-010/examples/request-response/example-request-response-Client/Properties/AssemblyInfo.cs54
-rw-r--r--dotnet/client-010/examples/request-response/example-request-response-Client/RequestResponseClient.cs142
-rw-r--r--dotnet/client-010/examples/request-response/example-request-response-Client/default.build48
-rw-r--r--dotnet/client-010/examples/request-response/example-request-response-Client/example-request-response-Client.csproj65
-rw-r--r--dotnet/client-010/examples/request-response/example-request-response-Server/Properties/AssemblyInfo.cs54
-rw-r--r--dotnet/client-010/examples/request-response/example-request-response-Server/Server.cs141
-rw-r--r--dotnet/client-010/examples/request-response/example-request-response-Server/default.build48
-rw-r--r--dotnet/client-010/examples/request-response/example-request-response-Server/example-request-response-Server.csproj65
-rw-r--r--dotnet/client-010/examples/request-response/verify36
-rw-r--r--dotnet/client-010/examples/request-response/verify.in16
-rw-r--r--dotnet/client-010/examples/request-response/verify_cpp_dotnet12
-rw-r--r--dotnet/client-010/examples/request-response/verify_cpp_dotnet.in17
-rw-r--r--dotnet/client-010/examples/request-response/verify_dotnet_cpp12
-rw-r--r--dotnet/client-010/examples/request-response/verify_dotnet_cpp.in18
-rw-r--r--dotnet/client-010/examples/request-response/verify_dotnet_java16
-rw-r--r--dotnet/client-010/examples/request-response/verify_dotnet_java.in21
-rw-r--r--dotnet/client-010/examples/request-response/verify_dotnet_python12
-rw-r--r--dotnet/client-010/examples/request-response/verify_dotnet_python.in17
-rw-r--r--dotnet/client-010/examples/request-response/verify_java_dotnet15
-rw-r--r--dotnet/client-010/examples/request-response/verify_java_dotnet.in36
-rw-r--r--dotnet/client-010/examples/request-response/verify_python_dotnet12
-rw-r--r--dotnet/client-010/examples/request-response/verify_python_dotnet.in12
-rw-r--r--dotnet/client-010/gentool/Composite.tpl291
-rw-r--r--dotnet/client-010/gentool/Constant.tpl37
-rw-r--r--dotnet/client-010/gentool/Enum.tpl38
-rw-r--r--dotnet/client-010/gentool/IInvoker.tpl57
-rw-r--r--dotnet/client-010/gentool/Invoker.tpl67
-rw-r--r--dotnet/client-010/gentool/MethodDelegate.tpl35
-rw-r--r--dotnet/client-010/gentool/Option.tpl42
-rw-r--r--dotnet/client-010/gentool/StructFactory.tpl64
-rw-r--r--dotnet/client-010/gentool/Type.tpl103
-rw-r--r--dotnet/client-010/gentool/build.xml52
-rw-r--r--dotnet/client-010/gentool/codegen86
-rw-r--r--dotnet/client-010/gentool/dotnetgenutil.py271
-rw-r--r--dotnet/client-010/lib/log4net/log4net-licence.txt201
-rw-r--r--dotnet/client-010/lib/log4net/log4net.dllbin0 -> 266240 bytes
-rw-r--r--dotnet/client-010/lib/log4net/log4net.xml28676
-rw-r--r--dotnet/client-010/lib/nunit/nunit-licence.txt23
-rw-r--r--dotnet/client-010/lib/nunit/nunit.framework.dllbin0 -> 45056 bytes
-rw-r--r--dotnet/client-010/lib/plossum/C5-License.txt27
-rw-r--r--dotnet/client-010/lib/plossum/C5.dllbin0 -> 274432 bytes
-rw-r--r--dotnet/client-010/lib/plossum/Plossum CommandLine.dllbin0 -> 98304 bytes
-rw-r--r--dotnet/client-010/lib/plossum/license.txt28
-rw-r--r--dotnet/client-010/log.xml46
-rw-r--r--dotnet/client-010/management/console/AbstractConsole.cs45
-rw-r--r--dotnet/client-010/management/console/Agent.cs75
-rw-r--r--dotnet/client-010/management/console/Broker.cs351
-rw-r--r--dotnet/client-010/management/console/BrokerURL.cs71
-rw-r--r--dotnet/client-010/management/console/ClassKey.cs107
-rw-r--r--dotnet/client-010/management/console/Console.cs46
-rw-r--r--dotnet/client-010/management/console/MethodResult.cs67
-rw-r--r--dotnet/client-010/management/console/ObjectID.cs88
-rw-r--r--dotnet/client-010/management/console/QMFEvent.cs74
-rw-r--r--dotnet/client-010/management/console/QMFObject.cs294
-rw-r--r--dotnet/client-010/management/console/SchemaArgument.cs59
-rw-r--r--dotnet/client-010/management/console/SchemaClass.cs141
-rw-r--r--dotnet/client-010/management/console/SchemaMethod.cs66
-rw-r--r--dotnet/client-010/management/console/SchemaProperty.cs59
-rw-r--r--dotnet/client-010/management/console/SchemaStatistic.cs54
-rw-r--r--dotnet/client-010/management/console/SchemaVariable.cs84
-rw-r--r--dotnet/client-010/management/console/SequenceManager.cs62
-rw-r--r--dotnet/client-010/management/console/Session.cs796
-rw-r--r--dotnet/client-010/management/console/Util.cs150
-rw-r--r--dotnet/client-010/management/console/XMLUtil.cs106
-rw-r--r--dotnet/client-010/management/console/console.csproj81
-rw-r--r--dotnet/client-010/management/console/console.sln26
-rw-r--r--dotnet/client-010/management/console/console.userprefs42
-rw-r--r--dotnet/client-010/management/console/console.usertasks2
-rw-r--r--dotnet/client-010/management/console/default.build54
-rw-r--r--dotnet/client-010/perftest/PerfTest.cs715
-rw-r--r--dotnet/client-010/perftest/Properties/AssemblyInfo.cs54
-rw-r--r--dotnet/client-010/perftest/README.txt38
-rw-r--r--dotnet/client-010/perftest/default.build50
-rw-r--r--dotnet/client-010/perftest/perftest.csproj72
-rw-r--r--dotnet/client-010/test/Helpers/ConfigHelpers.cs44
-rw-r--r--dotnet/client-010/test/Properties/AssemblyInfo.cs56
-rw-r--r--dotnet/client-010/test/Qpid Test.dll.config31
-rw-r--r--dotnet/client-010/test/Test.csproj82
-rw-r--r--dotnet/client-010/test/default.build55
-rw-r--r--dotnet/client-010/test/interop/Admin.cs90
-rw-r--r--dotnet/client-010/test/interop/ApplicationHeaders.cs83
-rw-r--r--dotnet/client-010/test/interop/ConnectionTests.cs59
-rw-r--r--dotnet/client-010/test/interop/Message.cs180
-rw-r--r--dotnet/client-010/test/interop/TestCase.cs96
-rw-r--r--dotnet/client-010/test/transport/util/ByteEncoderTest.cs106
-rw-r--r--dotnet/client-010/test/transport/util/CircularBufferTest.cs89
-rw-r--r--dotnet/client-010/test/transport/util/ResultFutureTest.cs103
-rw-r--r--dotnet/client-010/test/transport/util/SerialTest.cs75
-rw-r--r--dotnet/client-010/test/transport/util/UUIDTest.cs64
-rw-r--r--dotnet/client-010/wcf/Properties/AssemblyInfo.cs57
-rw-r--r--dotnet/client-010/wcf/demo/ConfigDemo.suobin0 -> 23552 bytes
-rw-r--r--dotnet/client-010/wcf/demo/Demo.suobin0 -> 33280 bytes
-rw-r--r--dotnet/client-010/wcf/demo/wcfBookingClient/Form1.Designer.cs185
-rw-r--r--dotnet/client-010/wcf/demo/wcfBookingClient/Form1.cs96
-rw-r--r--dotnet/client-010/wcf/demo/wcfBookingClient/Form1.resx123
-rw-r--r--dotnet/client-010/wcf/demo/wcfBookingClient/Program.cs41
-rw-r--r--dotnet/client-010/wcf/demo/wcfBookingClient/Properties/AssemblyInfo.cs57
-rw-r--r--dotnet/client-010/wcf/demo/wcfBookingClient/Properties/Resources.Designer.cs92
-rw-r--r--dotnet/client-010/wcf/demo/wcfBookingClient/Properties/Resources.resx117
-rw-r--r--dotnet/client-010/wcf/demo/wcfBookingClient/Properties/Settings.Designer.cs51
-rw-r--r--dotnet/client-010/wcf/demo/wcfBookingClient/Properties/Settings.settings7
-rw-r--r--dotnet/client-010/wcf/demo/wcfBookingClient/wcBookingClient.csproj103
-rw-r--r--dotnet/client-010/wcf/demo/wcfBookingServer/Booking.cs62
-rw-r--r--dotnet/client-010/wcf/demo/wcfBookingServer/IBooking.cs43
-rw-r--r--dotnet/client-010/wcf/demo/wcfBookingServer/Order.cs45
-rw-r--r--dotnet/client-010/wcf/demo/wcfBookingServer/Program.cs98
-rw-r--r--dotnet/client-010/wcf/demo/wcfBookingServer/Properties/AssemblyInfo.cs57
-rw-r--r--dotnet/client-010/wcf/demo/wcfBookingServer/Receipt.cs46
-rw-r--r--dotnet/client-010/wcf/demo/wcfBookingServer/wcfBookingServer.csproj77
-rw-r--r--dotnet/client-010/wcf/demo/wcfHelloClient/App.config56
-rw-r--r--dotnet/client-010/wcf/demo/wcfHelloClient/HelloClient.cs36
-rw-r--r--dotnet/client-010/wcf/demo/wcfHelloClient/IHelloService.cs33
-rw-r--r--dotnet/client-010/wcf/demo/wcfHelloClient/Program.cs48
-rw-r--r--dotnet/client-010/wcf/demo/wcfHelloClient/Properties/AssemblyInfo.cs57
-rw-r--r--dotnet/client-010/wcf/demo/wcfHelloClient/wcfHelloClient.csproj65
-rw-r--r--dotnet/client-010/wcf/demo/wcfHelloServer/App.config64
-rw-r--r--dotnet/client-010/wcf/demo/wcfHelloServer/HelloService.cs34
-rw-r--r--dotnet/client-010/wcf/demo/wcfHelloServer/IHelloService.cs32
-rw-r--r--dotnet/client-010/wcf/demo/wcfHelloServer/Program.cs47
-rw-r--r--dotnet/client-010/wcf/demo/wcfHelloServer/Properties/AssemblyInfo.cs57
-rw-r--r--dotnet/client-010/wcf/demo/wcfHelloServer/wcfHelloServer.csproj67
-rw-r--r--dotnet/client-010/wcf/demo/wcfRPC/IUpperCase.cs31
-rw-r--r--dotnet/client-010/wcf/demo/wcfRPC/Program.cs113
-rw-r--r--dotnet/client-010/wcf/demo/wcfRPC/Properties/AssemblyInfo.cs57
-rw-r--r--dotnet/client-010/wcf/demo/wcfRPC/QpidBindingConfigurationElement.cs205
-rw-r--r--dotnet/client-010/wcf/demo/wcfRPC/UpperCase.cs33
-rw-r--r--dotnet/client-010/wcf/demo/wcfRPC/wcfRPC.csproj73
-rw-r--r--dotnet/client-010/wcf/model/CommunicationOperation.cs31
-rw-r--r--dotnet/client-010/wcf/model/QpidBinding.cs185
-rw-r--r--dotnet/client-010/wcf/model/QpidChannelBase.cs167
-rw-r--r--dotnet/client-010/wcf/model/QpidChannelFactory.cs74
-rw-r--r--dotnet/client-010/wcf/model/QpidChannelListener.cs79
-rw-r--r--dotnet/client-010/wcf/model/QpidChannelListenerBase.cs111
-rw-r--r--dotnet/client-010/wcf/model/QpidInputChannel.cs218
-rw-r--r--dotnet/client-010/wcf/model/QpidInputChannelBase.cs101
-rw-r--r--dotnet/client-010/wcf/model/QpidOutputChannel.cs89
-rw-r--r--dotnet/client-010/wcf/model/QpidOutputChannelBase.cs77
-rw-r--r--dotnet/client-010/wcf/model/QpidTransportBindingElement.cs186
-rw-r--r--dotnet/client-010/wcf/model/QpidTransportElement.cs183
-rw-r--r--dotnet/client-010/wcf/wcf.csproj59
-rw-r--r--dotnet/client-010/wcf/wcf.sln50
-rw-r--r--dotnet/client-010/wcf/wcf.suobin0 -> 105984 bytes
-rw-r--r--dotnet/default.build482
-rwxr-xr-xdotnet/release13
-rw-r--r--etc/LICENSE206
-rw-r--r--etc/NOTICE8
-rw-r--r--extras/sasl/LICENSE234
-rw-r--r--extras/sasl/Makefile.am30
-rwxr-xr-xextras/sasl/bootstrap15
-rwxr-xr-xextras/sasl/build-aux/compile142
-rwxr-xr-xextras/sasl/build-aux/config.guess1501
-rwxr-xr-xextras/sasl/build-aux/config.rpath614
-rwxr-xr-xextras/sasl/build-aux/config.sub1619
-rwxr-xr-xextras/sasl/build-aux/depcomp584
-rwxr-xr-xextras/sasl/build-aux/install-sh507
-rwxr-xr-xextras/sasl/build-aux/mdate-sh201
-rwxr-xr-xextras/sasl/build-aux/missing367
-rw-r--r--extras/sasl/configure.ac318
-rw-r--r--extras/sasl/include/saslwrapper.h146
-rw-r--r--extras/sasl/m4/ac_pkg_swig.m4118
-rw-r--r--extras/sasl/m4/clock_time.m430
-rw-r--r--extras/sasl/m4/compiler-flags.m423
-rw-r--r--extras/sasl/m4/cppunit.m489
-rw-r--r--extras/sasl/m4/extensions.m459
-rw-r--r--extras/sasl/m4/libtool.m47360
-rw-r--r--extras/sasl/m4/ltoptions.m4368
-rw-r--r--extras/sasl/m4/ltsugar.m4123
-rw-r--r--extras/sasl/m4/ltversion.m423
-rw-r--r--extras/sasl/m4/lt~obsolete.m492
-rw-r--r--extras/sasl/m4/python.m4168
-rw-r--r--extras/sasl/python/Makefile.am43
-rw-r--r--extras/sasl/python/python.i169
-rw-r--r--extras/sasl/ruby/Makefile.am43
-rw-r--r--extras/sasl/ruby/ruby.i124
-rw-r--r--extras/sasl/src/Makefile.am39
-rw-r--r--extras/sasl/src/cyrus/saslwrapper.cpp372
-rw-r--r--extras/sasl/src/saslwrapper.i40
-rw-r--r--gentools/LICENSE202
-rw-r--r--gentools/NOTICE2
-rw-r--r--gentools/README.txt102
-rwxr-xr-xgentools/build22
-rw-r--r--gentools/lib/LICENSE202
-rw-r--r--gentools/lib/NOTICE2
-rw-r--r--gentools/lib/README.txt102
-rw-r--r--gentools/src/org/apache/qpid/gentools/ConsolidatedField.java20
-rw-r--r--gentools/templ.java/model/ProtocolVersionListClass.vm6
-rw-r--r--java/010ExcludeList65
-rw-r--r--java/010ExcludeList-noPrefetch55
-rw-r--r--java/010ExcludeList-store57
-rw-r--r--java/08ExcludeList9
-rw-r--r--java/08ExcludeList-nonvm24
-rw-r--r--java/KEYS32
-rw-r--r--java/broker-plugins/build.xml2
-rw-r--r--java/broker-plugins/pom.xml100
-rw-r--r--java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchange.java78
-rw-r--r--java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchangeType.java2
-rw-r--r--java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchange.java63
-rw-r--r--java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchangeType.java2
-rw-r--r--java/broker/bin/create-example-ssl-stores.bat36
-rwxr-xr-xjava/broker/bin/create-example-ssl-stores.sh38
-rwxr-xr-xjava/broker/bin/msTool.sh2
-rwxr-xr-xjava/broker/bin/qpid-passwd70
-rwxr-xr-xjava/broker/bin/qpid-server6
-rw-r--r--[-rwxr-xr-x]java/broker/bin/qpid-server.bat4
-rwxr-xr-xjava/broker/bin/qpid.stop145
-rwxr-xr-xjava/broker/bin/qpid.stopall49
-rwxr-xr-xjava/broker/bin/run.bat31
-rwxr-xr-xjava/broker/bin/run.sh44
-rwxr-xr-xjava/broker/bin/runAll37
-rw-r--r--java/broker/build.xml86
-rw-r--r--java/broker/distribution/pom.xml153
-rw-r--r--java/broker/distribution/src/main/assembly/broker-bin-tests.xml116
-rw-r--r--java/broker/distribution/src/main/assembly/broker-bin.xml183
-rw-r--r--java/broker/distribution/src/main/assembly/broker-src.xml78
-rw-r--r--java/broker/etc/acl.config.xml231
-rw-r--r--java/broker/etc/config.xml142
-rw-r--r--java/broker/etc/debug.log4j.xml26
-rw-r--r--java/broker/etc/log4j.xml85
-rw-r--r--java/broker/etc/passwd1
-rw-r--r--java/broker/etc/persistent_config.xml6
-rw-r--r--java/broker/etc/qpid-server.conf2
-rw-r--r--java/broker/etc/transient_config.xml6
-rw-r--r--java/broker/etc/virtualhosts.xml123
-rw-r--r--java/broker/pom.xml277
-rw-r--r--java/broker/scripts/resetAlerting.sh95
-rw-r--r--java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java437
-rw-r--r--java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java319
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java150
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java887
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java25
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java133
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/Main.java515
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java79
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java148
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java11
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java67
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java118
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfiguration.java58
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java121
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/configuration/SecurityConfiguration.java41
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java701
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java338
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java48
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java9
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java1
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java114
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java22
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java42
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java58
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java29
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java5
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInitialiser.java47
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeReferrer.java26
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java4
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java56
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java58
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java91
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java15
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java98
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java5
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java49
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java105
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java4
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java16
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java7
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java28
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java10
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java6
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java14
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java12
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java24
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java10
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java6
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java119
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java53
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java44
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java7
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java9
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java20
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java17
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java24
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/flow/CreditCreditManager.java188
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java12
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager_0_10.java28
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java16
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java25
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java20
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java16
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/flow/WindowCreditManager.java213
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java39
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java54
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java30
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java7
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java29
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java8
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java39
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java15
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java12
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java21
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java1
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java24
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java13
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java11
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java110
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java14
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java13
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java32
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java8
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_91.java168
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java4
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java25
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java71
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java110
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/LogActor.java66
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/LogMessage.java26
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/LogSubject.java37
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/NullRootMessageLogger.java60
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/RawMessageLogger.java44
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLogger.java64
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLoggerImpl.java57
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/StartupRootMessageLogger.java49
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java64
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java54
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java69
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/actors/BrokerActor.java53
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java121
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java114
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/actors/QueueActor.java55
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java49
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java819
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties323
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLogger.java56
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/SystemOutMessageLogger.java40
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/subjects/AbstractLogSubject.java64
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/subjects/BindingLogSubject.java62
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java67
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java137
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubject.java46
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessageStoreLogSubject.java45
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java45
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java62
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java13
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java28
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java424
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java41
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java39
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java38
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java6
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java76
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java43
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java37
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java98
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java7
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java5
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/management/ManagementConfiguration.java30
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java329
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageHeader.java51
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageReference.java44
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java114
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/message/EnqueableMessage.java27
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/message/InboundMessage.java37
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/message/MessageContentSource.java31
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java309
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java242
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/message/MessageReference.java57
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java126
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java146
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java47
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/message/TransferMessageReference.java39
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/output/HeaderPropertiesConverter.java124
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java11
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java2
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java237
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java257
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9_1/ProtocolOutputConverterImpl.java383
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java51
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java859
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java280
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java52
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java1070
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngineFactory.java29
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java41
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java110
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java51
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/protocol/HeartbeatConfig.java67
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java135
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java425
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngineFactory.java75
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngineFactory_0_10.java46
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java84
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java482
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java79
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java37
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java93
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java181
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java338
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java56
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java13
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java21
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java4
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java7
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java157
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java71
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java271
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java245
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java46
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java92
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java47
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java22
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java23
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/queue/QueueContext.java49
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java51
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java228
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java4
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java9
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java1321
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java69
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java68
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java127
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java219
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java115
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java116
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java28
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/security/PrincipalHolder.java29
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java324
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java72
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java33
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java6
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java6
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java3
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java1008
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java248
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java118
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java99
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java44
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java110
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java42
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java71
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java347
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java256
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java284
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java44
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java169
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java370
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainUser.java106
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java5
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java3
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java5
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java5
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java1
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java33
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java119
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java5
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java144
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexSaslServer.java105
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexServerFactory.java61
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java44
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java57
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java1148
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java116
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java166
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/store/MessageMetaDataType.java41
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java250
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/store/MessageStoreRecoveryHandler.java33
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/store/StorableMessageMetaData.java36
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java2
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java80
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/store/StoredMessage.java38
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/store/TransactionLog.java92
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/store/TransactionLogRecoveryHandler.java33
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/store/TransactionLogResource.java26
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java93
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java86
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/subscription/MessageAcceptCompletionListener.java57
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java32
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java299
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java663
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java118
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/transport/QpidAcceptor.java44
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java64
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java120
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java398
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java1198
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java170
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java243
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java293
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java213
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java60
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java58
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java179
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java109
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java55
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java38
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java84
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java3
-rwxr-xr-x[-rw-r--r--]java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java349
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java341
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java609
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java15
-rw-r--r--java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java10
-rw-r--r--java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java31
-rw-r--r--java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java4
-rw-r--r--java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java20
-rw-r--r--java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java2
-rw-r--r--java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java43
-rw-r--r--java/broker/src/test/java/org/apache/log4j/xml/QpidLog4JConfiguratorTest.java396
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java99
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/ExtractResendAndRequeueTest.java255
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/RunBrokerWithCommand.java2
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/configuration/QueueConfigurationTest.java136
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java1049
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java133
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java575
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/exchange/DestWildExchangeTest.java590
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java8
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java81
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersExchangeTest.java114
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/exchange/TopicExchangeTest.java446
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/LogMessageTest.java71
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/RootMessageLoggerImplTest.java86
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/actors/AMQPChannelActorTest.java269
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/actors/AMQPConnectionActorTest.java116
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/actors/BaseActorTestCase.java74
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/actors/BaseConnectionActorTestCase.java50
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/actors/CurrentActorTest.java294
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/actors/ManagementActorTest.java118
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/actors/QueueActorTest.java99
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/actors/SubscriptionActorTest.java110
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/actors/TestLogActor.java37
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/management/LoggingManagementMBeanTest.java425
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/messages/AbstractTestMessages.java127
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/messages/BindingMessagesTest.java64
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/messages/BrokerMessagesTest.java116
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/messages/ChannelMessagesTest.java64
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/messages/ConnectionMessagesTest.java90
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/messages/ExchangeMessagesTest.java80
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/messages/ManagementConsoleMessagesTest.java98
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/messages/MessageStoreMessagesTest.java126
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/messages/QueueMessagesTest.java239
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/messages/SubscriptionMessagesTest.java86
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/messages/VirtualHostMessagesTest.java51
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLoggerTest.java238
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/rawloggers/UnitTestMessageLogger.java60
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/rawloggers/UnitTestMessageLoggerTest.java102
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/subjects/AbstractTestLogSubject.java299
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/subjects/BindingLogSubjectTest.java71
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/subjects/ChannelLogSubjectTest.java58
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubjectTest.java46
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubjectTest.java58
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/subjects/MessageStoreLogSubjectTest.java62
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/subjects/QueueLogSubjectTest.java62
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubjectTest.java105
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/subjects/TestBlankSubject.java33
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/plugins/MockPluginManager.java51
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/plugins/PluginTest.java53
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java150
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java64
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/protocol/MaxChannelsTest.java86
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/protocol/TestIoSession.java295
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java108
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java109
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java71
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java201
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/AckTest.java432
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessage.java43
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java443
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/MockMessagePublishInfo.java52
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java228
-rwxr-xr-xjava/broker/src/test/java/org/apache/qpid/server/queue/MockStoredMessage.java92
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java401
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueThreadPoolTest.java58
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/registry/ApplicationRegistryShutdownTest.java131
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/securiity/auth/sasl/CRAMMD5HexInitialiserTest.java143
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/access/ACLManagerTest.java112
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java49
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java258
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/access/QueueDenier.java67
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBeanTest.java276
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/access/plugins/network/FirewallPluginTest.java303
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabaseTest.java466
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/auth/database/HashedUserTest.java95
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabaseTest.java416
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainUserTest.java78
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java267
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/TestPrincipalDatabase.java5
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java108
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/store/SkeletonMessageStore.java220
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/store/TestMemoryMessageStore.java98
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/store/TestReferenceCounting.java167
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java114
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java238
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/subscription/QueueBrowserUsesNoAckTest.java77
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/util/InternalBrokerBaseCase.java72
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/util/NullApplicationRegistry.java120
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java64
-rw-r--r--java/broker/src/test/java/org/apache/qpid/util/MockChannel.java40
-rw-r--r--java/broker/src/velocity/java/org/apache/qpid/server/logging/GenerateLogMessages.java470
-rw-r--r--java/broker/src/velocity/templates/org/apache/qpid/server/logging/messages/LogMessages.vm187
-rw-r--r--java/build.deps163
-rw-r--r--java/build.xml89
-rwxr-xr-xjava/clean-dir3
-rw-r--r--java/client-java14/README.txt33
-rw-r--r--java/client-java14/etc/sasl.properties20
-rw-r--r--java/client-java14/pom.xml224
-rw-r--r--java/client-java14/src/main/assembly/client-java14-bin.xml74
-rw-r--r--java/client-java14/src/main/assembly/jar-with-dependencies.xml104
-rw-r--r--java/client-java14/src/main/java/org/apache/qpid/sasl/ClientFactoryImpl.java343
-rw-r--r--java/client-java14/src/main/java/org/apache/qpid/sasl/CramMD5Client.java347
-rw-r--r--java/client-java14/src/main/java/org/apache/qpid/sasl/PlainClient.java275
-rw-r--r--java/client-java14/src/main/java/org/apache/qpid/sasl/Provider.java61
-rw-r--r--java/client-java14/src/test/java/org/apache/qpid/test/integration/client/ConnectionTest.java66
-rw-r--r--java/client/build.xml16
-rw-r--r--java/client/distribution/pom.xml156
-rw-r--r--java/client/distribution/src/main/assembly/client-bin-tests.xml107
-rw-r--r--java/client/distribution/src/main/assembly/client-bin.xml78
-rw-r--r--java/client/distribution/src/main/assembly/client-java1.4-bin.xml74
-rw-r--r--java/client/distribution/src/main/assembly/client-src.xml62
-rwxr-xr-x[-rw-r--r--]java/client/example/bin/verify_all31
-rw-r--r--java/client/example/pom.xml152
-rw-r--r--java/client/example/src/main/java/README.txt9
-rwxr-xr-xjava/client/example/src/main/java/org/apache/qpid/example/amqpexample/direct/DeclareQueue.java50
-rwxr-xr-xjava/client/example/src/main/java/org/apache/qpid/example/amqpexample/direct/DirectProducer.java85
-rwxr-xr-xjava/client/example/src/main/java/org/apache/qpid/example/amqpexample/direct/Listener.java114
-rwxr-xr-xjava/client/example/src/main/java/org/apache/qpid/example/amqpexample/fanout/DeclareQueue.java50
-rwxr-xr-xjava/client/example/src/main/java/org/apache/qpid/example/amqpexample/fanout/FannoutProducer.java50
-rwxr-xr-xjava/client/example/src/main/java/org/apache/qpid/example/amqpexample/fanout/Listener.java108
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/amqpexample/headers/DeclareQueue.java74
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/amqpexample/headers/Listener.java107
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/amqpexample/headers/Producer.java88
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/amqpexample/lvq/DeclareLVQueue.java64
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/amqpexample/lvq/Listener.java115
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/amqpexample/lvq/Producer.java69
-rwxr-xr-xjava/client/example/src/main/java/org/apache/qpid/example/amqpexample/pubsub/TopicListener.java129
-rwxr-xr-xjava/client/example/src/main/java/org/apache/qpid/example/amqpexample/pubsub/TopicPublisher.java51
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify23
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify_cpp_java2
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify_java_cpp2
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify_java_python4
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify_python_java4
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify23
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify_cpp_java2
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify_java_cpp2
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify_java_python4
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify_python_java4
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify23
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify_cpp_java2
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify_java_cpp2
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify_java_python4
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify_python_java4
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify23
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify_cpp_java2
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify_java_cpp4
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify_java_python4
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify_python_java4
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/publisher/FileMessageFactory.java6
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/publisher/MultiMessageDispatcher.java141
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/publisher/Publisher.java47
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/publisher/TopicPublisher.java59
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/simple/reqresp/Client.java263
-rw-r--r--java/client/example/src/main/java/org/apache/qpid/example/simple/reqresp/Server.java236
-rwxr-xr-xjava/client/example/src/main/java/runSample.sh22
-rw-r--r--java/client/pom.xml290
-rwxr-xr-xjava/client/src/main/java/client.bnd7
-rw-r--r--java/client/src/main/java/log4j.xml36
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQAnyDestination.java56
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQAuthenticationException.java5
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java28
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQConnection.java272
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java32
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java204
-rwxr-xr-xjava/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_9.java8
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java88
-rwxr-xr-xjava/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_9_1.java39
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java11
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java9
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQDestination.java26
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQQueueBrowser.java68
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQSession.java509
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java318
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java63
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQTopicSessionAdaptor.java2
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java45
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java138
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java20
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java38
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java54
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java22
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/Closeable.java18
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/XAConnectionImpl.java2
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/XAResourceImpl.java24
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/XASessionImpl.java11
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/configuration/ClientProperties.java31
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java32
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/failover/FailoverRetrySupport.java33
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/handler/AccessRequestOkMethodHandler.java21
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java91
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl.java14
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl_0_91.java158
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/handler/ConnectionOpenOkMethodHandler.java1
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java8
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java1
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate.java1
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java122
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java70
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/AbstractAMQMessageDelegate.java151
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesMessage.java52
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessage.java7
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java16
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/FiledTableSupport.java21
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessage.java6
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java6
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessage.java1
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.java6
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java47
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/ReturnMessage.java21
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage.java7
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage_0_10.java4
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/protocol/AMQIoTransportProtocolSession.java125
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java547
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java124
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties1
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java16
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java7
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java24
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/state/StateWaiter.java1
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/transport/SocketTransportConnection.java71
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/transport/TransportConnection.java48
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/transport/VmPipeTransportConnection.java17
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/url/URLParser.java44
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/util/BlockingWaiter.java2
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/util/FlowControllingBlockingQueue.java18
-rw-r--r--java/client/src/main/java/org/apache/qpid/filter/PropertyExpression.java18
-rw-r--r--java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java6
-rw-r--r--java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java6
-rw-r--r--java/client/src/main/java/org/apache/qpid/jms/FailoverPolicy.java15
-rw-r--r--java/client/src/main/java/org/apache/qpid/jms/TopicSubscriber.java21
-rw-r--r--java/client/src/main/java/org/apache/qpid/jms/failover/FailoverExchangeMethod.java317
-rw-r--r--java/client/src/main/java/org/apache/qpid/jms/failover/FailoverMethod.java3
-rw-r--r--java/client/src/main/java/org/apache/qpid/jms/failover/FailoverRoundRobinServers.java72
-rw-r--r--java/client/src/main/java/org/apache/qpid/jms/failover/FailoverSingleServer.java10
-rw-r--r--java/client/src/main/java/org/apache/qpid/jms/failover/NoFailover.java62
-rw-r--r--java/client/src/main/java/org/apache/qpid/jndi/PropertiesFileInitialContextFactory.java29
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/Client.java295
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/ClosedListener.java39
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/Connection.java86
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/DtxSession.java137
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/JMSTestCase.java115
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/Session.java544
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/impl/ClientSession.java142
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/impl/ClientSessionDelegate.java47
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/impl/Constants.java78
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/impl/DemoClient.java93
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/interop/BasicInteropTest.java155
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/util/ByteBufferMessage.java21
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/util/FileMessage.java96
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/util/MessagePartListenerAdapter.java21
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/util/ReadOnlyMessage.java38
-rw-r--r--java/client/src/main/java/org/apache/qpid/nclient/util/StreamingMessage.java68
-rw-r--r--java/client/src/test/java/org/apache/qpid/client/AMQQueueTest.java42
-rw-r--r--java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java94
-rw-r--r--java/client/src/test/java/org/apache/qpid/client/message/AbstractJMSMessageTest.java36
-rw-r--r--java/client/src/test/java/org/apache/qpid/client/protocol/AMQProtocolHandlerTest.java289
-rw-r--r--java/client/src/test/java/org/apache/qpid/client/protocol/MockIoSession.java312
-rw-r--r--java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java7
-rw-r--r--java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java16
-rw-r--r--java/client/src/test/java/org/apache/qpid/test/unit/client/destinationurl/DestinationURLTest.java12
-rw-r--r--java/client/src/test/java/org/apache/qpid/test/unit/client/message/BytesMessageTest.java2
-rw-r--r--java/client/src/test/java/org/apache/qpid/test/unit/client/message/StreamMessageTest.java2
-rw-r--r--java/client/src/test/java/org/apache/qpid/test/unit/jndi/ConnectionFactoryTest.java75
-rw-r--r--java/client/src/test/java/org/apache/qpid/test/unit/jndi/JNDIPropertyFileTest.java70
-rw-r--r--java/client/src/test/java/org/apache/qpid/test/unit/jndi/JNDITest.properties28
-rw-r--r--java/client/src/test/java/org/apache/qpid/test/unit/message/TestAMQSession.java7
-rw-r--r--java/common.xml60
-rw-r--r--java/common/Composite.tpl77
-rw-r--r--java/common/Constant.tpl23
-rw-r--r--java/common/Enum.tpl23
-rw-r--r--java/common/Invoker.tpl52
-rw-r--r--java/common/MethodDelegate.tpl29
-rw-r--r--java/common/Option.tpl44
-rw-r--r--java/common/StructFactory.tpl23
-rw-r--r--java/common/Type.tpl23
-rwxr-xr-xjava/common/bin/qpid-run9
-rw-r--r--java/common/build.xml79
-rwxr-xr-xjava/common/codegen45
-rw-r--r--java/common/genutil.py19
-rw-r--r--java/common/jython-2.2-rc2.jarbin1203486 -> 0 bytes
-rw-r--r--java/common/jython-lib.jarbin1570006 -> 0 bytes
-rw-r--r--java/common/pom.xml187
-rw-r--r--java/common/protocol-version.xml4
-rwxr-xr-xjava/common/src/main/java/common.bnd6
-rw-r--r--java/common/src/main/java/org/apache/qpid/AMQConnectionException.java2
-rw-r--r--java/common/src/main/java/org/apache/qpid/AMQException.java29
-rw-r--r--java/common/src/main/java/org/apache/qpid/BrokerDetails.java138
-rw-r--r--java/common/src/main/java/org/apache/qpid/BrokerDetailsImpl.java264
-rw-r--r--java/common/src/main/java/org/apache/qpid/ConsoleOutput.java12
-rw-r--r--java/common/src/main/java/org/apache/qpid/ErrorCode.java23
-rw-r--r--java/common/src/main/java/org/apache/qpid/QpidConfig.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/SecurityHelper.java71
-rw-r--r--java/common/src/main/java/org/apache/qpid/SerialException.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/ToyBroker.java11
-rw-r--r--java/common/src/main/java/org/apache/qpid/ToyClient.java44
-rw-r--r--java/common/src/main/java/org/apache/qpid/ToyExchange.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/codec/AMQCodecFactory.java7
-rw-r--r--java/common/src/main/java/org/apache/qpid/codec/AMQDecoder.java79
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java39
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockEncoder.java2
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyImpl.java162
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java63
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java4
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/FieldTable.java33
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/ProtocolInitiation.java50
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/abstraction/MessagePublishInfoImpl.java85
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/abstraction/ProtocolVersionMethodConverter.java4
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/AMQMethodBody_0_9.java174
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/MethodConverter_0_9.java52
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/amqp_0_91/AMQMethodBody_0_91.java37
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/amqp_0_91/MethodConverter_0_91.java132
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/AMQMethodBody_8_0.java169
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/MethodConverter_8_0.java50
-rw-r--r--java/common/src/main/java/org/apache/qpid/pool/Event.java155
-rw-r--r--java/common/src/main/java/org/apache/qpid/pool/Job.java139
-rw-r--r--java/common/src/main/java/org/apache/qpid/pool/PoolingFilter.java491
-rw-r--r--java/common/src/main/java/org/apache/qpid/pool/ReadWriteRunnable.java1
-rw-r--r--java/common/src/main/java/org/apache/qpid/pool/ReadWriteThreadModel.java102
-rw-r--r--java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java9
-rw-r--r--java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngine.java61
-rw-r--r--java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngineFactory.java31
-rw-r--r--java/common/src/main/java/org/apache/qpid/security/CallbackHandlerRegistry.java94
-rw-r--r--java/common/src/main/java/org/apache/qpid/security/DynamicSaslRegistrar.java74
-rw-r--r--java/common/src/main/java/org/apache/qpid/security/JCAProvider.java44
-rw-r--r--java/common/src/main/java/org/apache/qpid/security/amqplain/AmqPlainSaslClient.java105
-rw-r--r--java/common/src/main/java/org/apache/qpid/security/amqplain/AmqPlainSaslClientFactory.java62
-rw-r--r--java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java92
-rw-r--r--java/common/src/main/java/org/apache/qpid/thread/DefaultThreadFactory.java18
-rw-r--r--java/common/src/main/java/org/apache/qpid/thread/QpidThreadExecutor.java42
-rw-r--r--java/common/src/main/java/org/apache/qpid/thread/RealtimeThreadFactory.java47
-rw-r--r--java/common/src/main/java/org/apache/qpid/thread/ThreadFactory.java7
-rw-r--r--java/common/src/main/java/org/apache/qpid/thread/Threading.java26
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Binary.java16
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Channel.java176
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ChannelDelegate.java54
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java139
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Connection.java435
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ConnectionDelegate.java246
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ConnectionException.java31
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ConnectionListener.java38
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Echo.java37
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Method.java71
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/NetworkDriver.java63
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/NetworkDriverConfiguration.java44
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/OpenException.java34
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ProtocolHeader.java8
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ProtocolVersionException.java16
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ProtocolViolationException.java35
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/RangeSet.java5
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Sender.java1
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/SenderException.java52
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java183
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Session.java641
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/SessionClosedException.java12
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/SessionDelegate.java87
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/SessionException.java29
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/SessionListener.java42
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Sink.java37
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Struct.java2
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/TransportException.java5
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/codec/BBDecoder.java58
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java112
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/codec/Decoder.java227
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/codec/Encodable.java19
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/codec/Encoder.java230
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java5
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/ConnectionBinding.java39
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java37
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/InputHandler.java5
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/InputHandler_0_9.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/IoAcceptor.java13
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java52
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/IoSender.java78
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/IoTransport.java87
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java421
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaHandler.java4
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaSender.java13
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/nio/NioHandler.java26
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/nio/NioSender.java26
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLReceiver.java184
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLSender.java255
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/util/Functions.java13
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/util/Waiter.java63
-rw-r--r--java/common/src/main/java/org/apache/qpid/url/BindingURLImpl.java261
-rw-r--r--java/common/src/main/java/org/apache/qpid/url/BindingURLParser.java25
-rw-r--r--java/common/src/main/java/org/apache/qpid/url/QpidBindingURL.java53
-rw-r--r--java/common/src/main/java/org/apache/qpid/url/QpidURL.java57
-rw-r--r--java/common/src/main/java/org/apache/qpid/url/QpidURLImpl.java460
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/FileUtils.java220
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/NetMatcher.java264
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/PropertiesUtils.java200
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/Serial.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/Strings.java156
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/concurrent/AlreadyUnblockedException.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/concurrent/BatchSynchQueue.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/concurrent/BatchSynchQueueBase.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/concurrent/BooleanLatch.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/concurrent/Capacity.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/concurrent/SynchBuffer.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/concurrent/SynchException.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/concurrent/SynchQueue.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/concurrent/SynchRecord.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/concurrent/SynchRef.java21
-rw-r--r--java/common/src/test/java/org/apache/qpid/AMQExceptionTest.java106
-rw-r--r--java/common/src/test/java/org/apache/qpid/codec/AMQDecoderTest.java130
-rw-r--r--java/common/src/test/java/org/apache/qpid/codec/MockAMQVersionAwareProtocolSession.java84
-rw-r--r--java/common/src/test/java/org/apache/qpid/framing/abstraction/MessagePublishInfoImplTest.java99
-rw-r--r--java/common/src/test/java/org/apache/qpid/pool/PoolingFilterTest.java111
-rw-r--r--java/common/src/test/java/org/apache/qpid/thread/ThreadFactoryTest.java46
-rw-r--r--java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java391
-rw-r--r--java/common/src/test/java/org/apache/qpid/transport/GenTest.java44
-rw-r--r--java/common/src/test/java/org/apache/qpid/transport/TestNetworkDriver.java122
-rw-r--r--java/common/src/test/java/org/apache/qpid/transport/codec/BBEncoderTest.java47
-rw-r--r--java/common/src/test/java/org/apache/qpid/transport/network/mina/MINANetworkDriverTest.java491
-rw-r--r--java/common/src/test/java/org/apache/qpid/util/FileUtilsTest.java612
-rw-r--r--java/common/src/test/java/org/apache/qpid/util/SerialTest.java21
-rw-r--r--java/common/templates/model/ProtocolVersionListClass.vm25
-rw-r--r--java/common/templating.py18
-rw-r--r--java/cpp.async.testprofile3
-rw-r--r--java/cpp.noprefetch.testprofile4
-rw-r--r--java/cpp.testprofile3
-rw-r--r--java/default-longrunning.testprofile1
-rw-r--r--java/default.testprofile23
-rw-r--r--java/distribution/pom.xml210
-rw-r--r--java/distribution/src/main/assembly/bin-test.xml193
-rw-r--r--java/distribution/src/main/assembly/bin.xml217
-rw-r--r--java/distribution/src/main/assembly/management-eclipse-plugin-unix.xml118
-rw-r--r--java/distribution/src/main/assembly/management-eclipse-plugin.xml157
-rw-r--r--java/distribution/src/main/assembly/src.xml94
-rw-r--r--java/distribution/src/main/release/DISCLAIMER5
-rwxr-xr-xjava/distribution/src/main/release/LICENSE.txt203
-rw-r--r--java/distribution/src/main/release/NOTICE.txt36
-rw-r--r--java/distribution/src/main/release/README.txt104
-rw-r--r--java/doc/Qpid-architecture.diabin0 -> 2149 bytes
-rw-r--r--java/doc/broker-0.5-network.diabin0 -> 5187 bytes
-rw-r--r--java/doc/broker-0.N-network-phase-1.diabin0 -> 4283 bytes
-rw-r--r--java/doc/broker-0.N-state.diabin0 -> 2477 bytes
-rw-r--r--java/doc/broker-overview.diabin0 -> 1263 bytes
-rw-r--r--java/doc/broker-priority-queue-subscription.diabin0 -> 2991 bytes
-rw-r--r--java/doc/broker-queue-subscription.diabin0 -> 2129 bytes
-rw-r--r--java/doc/client-0.5-connection-creation.diabin0 -> 3158 bytes
-rw-r--r--java/doc/client-0.5-network-processing.diabin0 -> 5331 bytes
-rw-r--r--java/doc/client-0.N-network-processing.diabin0 -> 4039 bytes
-rw-r--r--java/doc/common-0.N-network.diabin0 -> 1858 bytes
-rw-r--r--java/doc/network-driver-protocol-engine-sequence.diabin0 -> 1826 bytes
-rw-r--r--java/doc/noddy-network-blocks.diabin0 -> 1877 bytes
-rw-r--r--java/etc/code-style.xml251
-rw-r--r--java/etc/coding_standards.xml255
-rwxr-xr-xjava/genpom150
-rwxr-xr-xjava/integrationtests/bin/interoptests.py12
-rw-r--r--java/integrationtests/pom.xml146
-rw-r--r--java/java.testprofile5
-rw-r--r--java/junit-toolkit-maven-plugin/pom.xml79
-rw-r--r--java/junit-toolkit-maven-plugin/src/main/org/apache/qpid/junit/maven/IsolatedClassLoader.java113
-rw-r--r--java/junit-toolkit-maven-plugin/src/main/org/apache/qpid/junit/maven/TKTestRunnerMojo.java274
-rw-r--r--java/junit-toolkit-maven-plugin/src/main/org/apache/qpid/junit/maven/TKTestScriptGenMojo.java148
-rw-r--r--java/junit-toolkit/pom.xml100
-rw-r--r--java/junit-toolkit/src/main/org/apache/qpid/junit/concurrency/package.html35
-rw-r--r--java/junit-toolkit/src/main/org/apache/qpid/junit/extensions/listeners/package.html33
-rw-r--r--java/junit-toolkit/src/main/org/apache/qpid/junit/extensions/package.html45
-rw-r--r--java/junit-toolkit/src/main/org/apache/qpid/junit/extensions/util/package.html33
-rw-r--r--java/lib/bnd-0.0.249.jarbin0 -> 255605 bytes
-rw-r--r--java/lib/cobertura/README.txt10
-rw-r--r--java/lib/com.ibm.icu-3.4.4.jarbin3255246 -> 0 bytes
-rw-r--r--java/lib/com.ibm.icu_3.8.1.v20080530.jarbin0 -> 4467363 bytes
-rw-r--r--java/lib/commons-beanutils-core-1.8.0.jarbin0 -> 206035 bytes
-rw-r--r--java/lib/commons-configuration-1.2.jarbin163822 -> 0 bytes
-rw-r--r--java/lib/commons-configuration-1.6.jarbin0 -> 298829 bytes
-rw-r--r--java/lib/commons-digester-1.8.1.jarbin0 -> 146108 bytes
-rw-r--r--java/lib/commons-pool-1.4.jarbin0 -> 87077 bytes
-rw-r--r--java/lib/core-3.1.1.jarbin0 -> 3566844 bytes
-rw-r--r--java/lib/derby-10.3.2.1.jarbin0 -> 2343388 bytes
-rw-r--r--java/lib/geronimo-servlet_2.5_spec-1.2.jarbin0 -> 70593 bytes
-rw-r--r--java/lib/javassist.jarbin0 -> 471005 bytes
-rw-r--r--java/lib/jetty-6.1.14.jarbin0 -> 516429 bytes
-rw-r--r--java/lib/jetty-util-6.1.14.jarbin0 -> 163122 bytes
-rw-r--r--java/lib/jline-0.9.94.jarbin0 -> 87325 bytes
-rw-r--r--java/lib/jsp-2.1.jarbin0 -> 1024681 bytes
-rw-r--r--java/lib/jsp-api-2.1.jarbin0 -> 134910 bytes
-rw-r--r--java/lib/junit-4.4.jarbin0 -> 161477 bytes
-rw-r--r--java/lib/jython-2.5.0.jarbin0 -> 8580107 bytes
-rw-r--r--java/lib/muse-core-2.2.0.jarbin0 -> 121976 bytes
-rw-r--r--java/lib/muse-platform-mini-2.2.0.jarbin0 -> 8227 bytes
-rw-r--r--java/lib/muse-util-2.2.0.jarbin0 -> 23215 bytes
-rw-r--r--java/lib/muse-util-qname-2.2.0.jarbin0 -> 4968 bytes
-rw-r--r--java/lib/muse-util-xml-2.2.0.jarbin0 -> 19082 bytes
-rw-r--r--java/lib/muse-wsa-soap-2.2.0.jarbin0 -> 25030 bytes
-rw-r--r--java/lib/muse-wsdm-muws-adv-api-2.2.0.jarbin0 -> 4145 bytes
-rw-r--r--java/lib/muse-wsdm-muws-adv-impl-2.2.0.jarbin0 -> 10366 bytes
-rw-r--r--java/lib/muse-wsdm-muws-api-2.2.0.jarbin0 -> 18492 bytes
-rw-r--r--java/lib/muse-wsdm-muws-impl-2.2.0.jarbin0 -> 57860 bytes
-rw-r--r--java/lib/muse-wsdm-wef-api-2.2.0.jarbin0 -> 9125 bytes
-rw-r--r--java/lib/muse-wsdm-wef-impl-2.2.0.jarbin0 -> 18049 bytes
-rw-r--r--java/lib/muse-wsn-api-2.2.0.jarbin0 -> 29692 bytes
-rw-r--r--java/lib/muse-wsn-impl-2.2.0.jarbin0 -> 80531 bytes
-rw-r--r--java/lib/muse-wsrf-api-2.2.0.jarbin0 -> 58684 bytes
-rw-r--r--java/lib/muse-wsrf-impl-2.2.0.jarbin0 -> 127656 bytes
-rw-r--r--java/lib/muse-wsrf-rmd-2.2.0.jarbin0 -> 5625 bytes
-rw-r--r--java/lib/muse-wsx-api-2.2.0.jarbin0 -> 4624 bytes
-rw-r--r--java/lib/muse-wsx-impl-2.2.0.jarbin0 -> 9349 bytes
-rw-r--r--java/lib/org.apache.commons.codec_1.3.0.v20080530-1600.jarbin0 -> 53757 bytes
-rw-r--r--java/lib/org.eclipse.core.commands-3.2.0.jarbin89522 -> 0 bytes
-rw-r--r--java/lib/org.eclipse.core.commands_3.4.0.I20080509-2000.jarbin0 -> 105794 bytes
-rw-r--r--java/lib/org.eclipse.core.contenttype-3.2.0.jarbin76141 -> 0 bytes
-rw-r--r--java/lib/org.eclipse.core.contenttype_3.3.0.v20080604-1400.jarbin0 -> 86969 bytes
-rw-r--r--java/lib/org.eclipse.core.databinding_1.1.1.M20080827-0800b.jarbin0 -> 347799 bytes
-rw-r--r--java/lib/org.eclipse.core.expressions-3.2.0.jarbin66023 -> 0 bytes
-rw-r--r--java/lib/org.eclipse.core.expressions_3.4.0.v20080603-2000.jarbin0 -> 83841 bytes
-rw-r--r--java/lib/org.eclipse.core.jobs-3.2.0.jarbin74797 -> 0 bytes
-rw-r--r--java/lib/org.eclipse.core.jobs_3.4.0.v20080512.jarbin0 -> 82491 bytes
-rw-r--r--java/lib/org.eclipse.core.runtime-3.2.0.jarbin76627 -> 0 bytes
-rw-r--r--java/lib/org.eclipse.core.runtime.compatibility.auth-3.2.0.jarbin18733 -> 0 bytes
-rw-r--r--java/lib/org.eclipse.core.runtime.compatibility.registry-3.2.0.jarbin7887 -> 0 bytes
-rw-r--r--java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/META-INF/ECLIPSE.RSAbin0 -> 3487 bytes
-rw-r--r--java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/META-INF/ECLIPSE.SF17
-rw-r--r--java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/META-INF/MANIFEST.MF25
-rw-r--r--java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/META-INF/eclipse.inf3
-rw-r--r--java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/about.html28
-rw-r--r--java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/fragment.properties12
-rw-r--r--java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/runtime_registry_compatibility.jarbin0 -> 10994 bytes
-rw-r--r--java/lib/org.eclipse.core.runtime_3.4.0.v20080512.jarbin0 -> 69019 bytes
-rw-r--r--java/lib/org.eclipse.equinox.app_1.1.0.v20080421-2006.jarbin0 -> 79866 bytes
-rw-r--r--java/lib/org.eclipse.equinox.common-3.2.0.jarbin79780 -> 0 bytes
-rw-r--r--java/lib/org.eclipse.equinox.common_3.4.0.v20080421-2006.jarbin0 -> 94649 bytes
-rw-r--r--java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/META-INF/ECLIPSE.RSAbin0 -> 3487 bytes
-rw-r--r--java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/META-INF/ECLIPSE.SF17
-rw-r--r--java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/META-INF/MANIFEST.MF25
-rw-r--r--java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/META-INF/eclipse.inf3
-rw-r--r--java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/about.html28
-rw-r--r--java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/eclipse_1115.sobin0 -> 118028 bytes
-rw-r--r--java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/launcher.carbon.macosx.properties12
-rw-r--r--java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/META-INF/ECLIPSE.RSAbin0 -> 3487 bytes
-rw-r--r--java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/META-INF/ECLIPSE.SF17
-rw-r--r--java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/META-INF/MANIFEST.MF25
-rw-r--r--java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/META-INF/eclipse.inf3
-rw-r--r--java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/about.html28
-rw-r--r--java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/eclipse_1115.sobin0 -> 133193 bytes
-rw-r--r--java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/launcher.gtk.linux.x86.properties12
-rw-r--r--java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/META-INF/ECLIPSE.RSAbin0 -> 3487 bytes
-rw-r--r--java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/META-INF/ECLIPSE.SF17
-rw-r--r--java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/META-INF/MANIFEST.MF25
-rw-r--r--java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/META-INF/eclipse.inf3
-rw-r--r--java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/about.html28
-rw-r--r--java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/eclipse_1115.sobin0 -> 169725 bytes
-rw-r--r--java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/launcher.gtk.linux.x86_64.properties12
-rw-r--r--java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/META-INF/ECLIPSE.RSAbin0 -> 3487 bytes
-rw-r--r--java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/META-INF/ECLIPSE.SF17
-rw-r--r--java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/META-INF/MANIFEST.MF25
-rw-r--r--java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/META-INF/eclipse.inf3
-rw-r--r--java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/about.html28
-rw-r--r--java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/eclipse_1115.sobin0 -> 76500 bytes
-rw-r--r--java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/launcher.gtk.solaris.sparc.properties12
-rw-r--r--java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/META-INF/ECLIPSE.RSAbin0 -> 3487 bytes
-rw-r--r--java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/META-INF/ECLIPSE.SF17
-rw-r--r--java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/META-INF/MANIFEST.MF25
-rw-r--r--java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/META-INF/eclipse.inf3
-rw-r--r--java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/about.html28
-rw-r--r--java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/eclipse_1115.dllbin0 -> 81920 bytes
-rw-r--r--java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/launcher.win32.win32.x86.properties12
-rw-r--r--java/lib/org.eclipse.equinox.launcher_1.0.101.R34x_v20080819.jarbin0 -> 43682 bytes
-rw-r--r--java/lib/org.eclipse.equinox.preferences-3.2.0.jarbin91662 -> 0 bytes
-rw-r--r--java/lib/org.eclipse.equinox.preferences_3.2.201.R34x_v20080709.jarbin0 -> 104280 bytes
-rw-r--r--java/lib/org.eclipse.equinox.registry-3.2.0.jarbin143841 -> 0 bytes
-rw-r--r--java/lib/org.eclipse.equinox.registry_3.4.0.v20080516-0950.jarbin0 -> 172936 bytes
-rw-r--r--java/lib/org.eclipse.help-3.2.0.jarbin115440 -> 0 bytes
-rw-r--r--java/lib/org.eclipse.help_3.3.101.v20080702_34x.jarbin0 -> 216698 bytes
-rw-r--r--java/lib/org.eclipse.jface-3.2.0.jarbin813664 -> 0 bytes
-rw-r--r--java/lib/org.eclipse.jface.databinding_1.2.1.M20080827-0800a.jarbin0 -> 196505 bytes
-rw-r--r--java/lib/org.eclipse.jface_3.4.1.M20080827-2000.jarbin0 -> 1040433 bytes
-rw-r--r--java/lib/org.eclipse.osgi-3.2.0.jarbin846717 -> 0 bytes
-rw-r--r--java/lib/org.eclipse.osgi_3.4.2.R34x_v20080826-1230.jarbin0 -> 997883 bytes
-rw-r--r--java/lib/org.eclipse.swt-3.2.0.jarbin10867 -> 0 bytes
-rw-r--r--java/lib/org.eclipse.swt.carbon.macosx_3.4.1.v3449c.jarbin0 -> 1852007 bytes
-rw-r--r--java/lib/org.eclipse.swt.gtk.linux.x86_3.4.1.v3449c.jarbin0 -> 2006608 bytes
-rw-r--r--java/lib/org.eclipse.swt.gtk.linux.x86_64_3.4.1.v3449c.jarbin0 -> 2123120 bytes
-rw-r--r--java/lib/org.eclipse.swt.gtk.solaris.sparc_3.4.1.v3449c.jarbin0 -> 1877410 bytes
-rw-r--r--java/lib/org.eclipse.swt.win32.win32.x86-3.2.0.jarbin1553273 -> 0 bytes
-rw-r--r--java/lib/org.eclipse.swt.win32.win32.x86_3.4.1.v3449c.jarbin0 -> 2123125 bytes
-rw-r--r--java/lib/org.eclipse.swt_3.4.1.v3449c.jarbin0 -> 15807 bytes
-rw-r--r--java/lib/org.eclipse.ui-3.2.0.jarbin124376 -> 0 bytes
-rw-r--r--java/lib/org.eclipse.ui.forms-3.2.0.jarbin235372 -> 0 bytes
-rw-r--r--java/lib/org.eclipse.ui.forms_3.3.101.v20080708_34x.jarbin0 -> 298053 bytes
-rw-r--r--java/lib/org.eclipse.ui.workbench-3.2.1.jarbin3076013 -> 0 bytes
-rw-r--r--java/lib/org.eclipse.ui.workbench_3.4.1.M20080827-0800a.jarbin0 -> 3922042 bytes
-rw-r--r--java/lib/org.eclipse.ui_3.4.1.M20080910-0800.jarbin0 -> 145322 bytes
-rwxr-xr-xjava/lib/org.osgi.core_1.0.0.jar (renamed from java/lib/org.osgi.core-1.0.0.jar)bin60929 -> 60929 bytes
-rw-r--r--java/lib/poms/backport-util-concurrent-2.2.pom25
-rw-r--r--java/lib/poms/commons-beanutils-core-1.8.0.pom42
-rw-r--r--java/lib/poms/commons-cli-1.0.pom76
-rw-r--r--java/lib/poms/commons-codec-1.3.pom178
-rw-r--r--java/lib/poms/commons-collections-3.2.pom420
-rw-r--r--java/lib/poms/commons-configuration-1.6.pom419
-rw-r--r--java/lib/poms/commons-digester-1.8.1.pom316
-rw-r--r--java/lib/poms/commons-lang-2.2.pom414
-rw-r--r--java/lib/poms/commons-logging-1.0.4.pom165
-rw-r--r--java/lib/poms/commons-pool-1.4.pom209
-rw-r--r--java/lib/poms/derby-10.3.2.1.pom43
-rw-r--r--java/lib/poms/geronimo-jms_1.1_spec-1.0.pom6
-rw-r--r--java/lib/poms/junit-3.8.1.pom29
-rw-r--r--java/lib/poms/log4j-1.2.12.pom6
-rw-r--r--java/lib/poms/mina-core-1.0.1.pom34
-rw-r--r--java/lib/poms/mina-filter-ssl-1.0.1.pom27
-rw-r--r--java/lib/poms/org.apache.felix.framework-1.0.0.pom66
-rw-r--r--java/lib/poms/org.osgi.core-1.0.0.pom56
-rw-r--r--java/lib/poms/slf4j-api-1.4.0.pom73
-rw-r--r--java/lib/poms/slf4j-log4j12-1.4.0.pom44
-rw-r--r--java/lib/poms/xalan-2.7.0.pom19
-rw-r--r--java/lib/start.jarbin0 -> 17125 bytes
-rw-r--r--java/lib/wsdl4j-1.6.1.jarbin0 -> 148522 bytes
-rw-r--r--java/lib/xercesImpl-2.8.1.jarbin0 -> 1212965 bytes
-rw-r--r--java/lib/xml-apis-1.3.03.jarbin0 -> 195119 bytes
-rw-r--r--java/log4j-test.xml53
-rw-r--r--java/management/agent/build.xml27
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/Agent.java707
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/AgentException.java45
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/EventSeverity.java6
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/ManagedEJB.java138
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/ManagedObject.java52
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/ManagedObjectBase.java72
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/ManagedPOJO.java90
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFAgent.java34
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFEvent.java42
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFHide.java39
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFObject.java42
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFProperty.java39
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFSeeAlso.java40
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFType.java42
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/binding/BindingContext.java213
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/binding/BindingException.java50
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/binding/BindingUtils.java137
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/binding/ClassBinding.java602
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/binding/EnumBinding.java108
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/binding/ListBinding.java131
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/binding/MapBinding.java95
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/binding/MethodBinding.java91
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/binding/ParameterBinding.java121
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/binding/PropertyBinding.java131
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/binding/QMFTypeBinding.java465
-rw-r--r--java/management/agent/src/main/java/org/apache/qpid/agent/binding/TypeBinding.java46
-rw-r--r--java/management/agent/src/test/java/org/apache/qpid/agent/Crumpet.java70
-rw-r--r--java/management/agent/src/test/java/org/apache/qpid/agent/Muppet.java113
-rw-r--r--java/management/agent/src/test/java/org/apache/qpid/agent/Pikelet.java52
-rw-r--r--java/management/agent/src/test/java/org/apache/qpid/agent/Puppet.java29
-rw-r--r--java/management/client/README42
-rw-r--r--java/management/client/bin/qman-jmx.cmd78
-rw-r--r--java/management/client/bin/qman-jmx.sh76
-rw-r--r--java/management/client/bin/qman-wsdm-start.cmd88
-rw-r--r--java/management/client/bin/qman-wsdm-start.sh89
-rw-r--r--java/management/client/bin/qman-wsdm-stop.cmd37
-rw-r--r--java/management/client/bin/qman-wsdm-stop.sh38
-rw-r--r--java/management/client/build.xml213
-rw-r--r--java/management/client/console/brokers_management.jsp188
-rw-r--r--java/management/client/console/console.jsp101
-rw-r--r--java/management/client/console/error_page.jsp38
-rw-r--r--java/management/client/console/fragments/header.jsp15
-rw-r--r--java/management/client/console/fragments/menu.jsp10
-rw-r--r--java/management/client/console/images/asf-logo.pngbin0 -> 4735 bytes
-rw-r--r--java/management/client/console/images/menu.gifbin0 -> 1953 bytes
-rw-r--r--java/management/client/console/images/menuleft.gifbin0 -> 640 bytes
-rw-r--r--java/management/client/console/images/menuright.gifbin0 -> 1398 bytes
-rw-r--r--java/management/client/console/images/qpid-logo.pngbin0 -> 39056 bytes
-rw-r--r--java/management/client/console/images/style.css181
-rw-r--r--java/management/client/console/jmx_perspective.jsp136
-rw-r--r--java/management/client/console/logging_configuration.jsp220
-rw-r--r--java/management/client/console/resources_management.jsp84
-rw-r--r--java/management/client/console/tbd.jsp27
-rw-r--r--java/management/client/console/wsdm_operations_perspective.jsp153
-rw-r--r--java/management/client/console/wsdm_properties_perspective.jsp197
-rw-r--r--java/management/client/console/wsdm_rmd_perspective.jsp78
-rw-r--r--java/management/client/console/wsdm_wsdl_perspective.jsp78
-rw-r--r--java/management/client/doc/man/qman-jmx17
-rw-r--r--java/management/client/etc/jetty.xml26
-rw-r--r--java/management/client/etc/log4j.xml76
-rw-r--r--java/management/client/etc/qman-config.xml68
-rw-r--r--java/management/client/etc/qman-config.xsd63
-rw-r--r--java/management/client/etc/qman.log4j29
-rw-r--r--java/management/client/src/example/ConnectWithBroker.out.ok81
-rw-r--r--java/management/client/src/example/GetMultipleResourceProperties.out.ok262
-rw-r--r--java/management/client/src/example/GetQManResourceMembers.out.ko54
-rw-r--r--java/management/client/src/example/GetQManResourceMembers.out.ok55
-rw-r--r--java/management/client/src/example/GetResourceMetadataDescriptor.out.ok188
-rw-r--r--java/management/client/src/example/GetResourcePropertyDocument.out.ok138
-rw-r--r--java/management/client/src/example/GetResourcePropertyRequest.out.ok588
-rw-r--r--java/management/client/src/example/GetWsdlMetadata.out.ko.no.resources58
-rw-r--r--java/management/client/src/example/GetWsdlMetadata.out.ok1968
-rw-r--r--java/management/client/src/example/PauseAndResumeSubscription.out.ok133
-rw-r--r--java/management/client/src/example/README69
-rw-r--r--java/management/client/src/example/SetResourcePropertiesRequest.out.ok2316
-rw-r--r--java/management/client/src/example/org/apache/qpid/management/example/AbstractQManExample.java140
-rw-r--r--java/management/client/src/example/org/apache/qpid/management/example/ConnectWithBrokerExample.java240
-rw-r--r--java/management/client/src/example/org/apache/qpid/management/example/ConsumerAndProducerExample.java293
-rw-r--r--java/management/client/src/example/org/apache/qpid/management/example/GetMultipleResourcePropertiesExample.java179
-rw-r--r--java/management/client/src/example/org/apache/qpid/management/example/GetQManResourceMembersExample.java93
-rw-r--r--java/management/client/src/example/org/apache/qpid/management/example/GetResourceMetadataDescriptorExample.java156
-rw-r--r--java/management/client/src/example/org/apache/qpid/management/example/GetResourcePropertyDocumentExample.java111
-rw-r--r--java/management/client/src/example/org/apache/qpid/management/example/GetResourcePropertyExample.java172
-rw-r--r--java/management/client/src/example/org/apache/qpid/management/example/GetWSDLMetadataExample.java156
-rw-r--r--java/management/client/src/example/org/apache/qpid/management/example/PausableSubscriptionExample.java88
-rw-r--r--java/management/client/src/example/org/apache/qpid/management/example/SetResourcePropertyExample.java306
-rw-r--r--java/management/client/src/main/java/muse.xml188
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/Messages.java175
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/Names.java216
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/Protocol.java52
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerAlreadyConnectedException.java53
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerConnectionData.java270
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerConnectionDataParser.java136
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerConnectionException.java42
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/configuration/Configuration.java489
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/configuration/ConfigurationException.java51
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/configuration/Configurator.java240
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/configuration/IParser.java44
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/configuration/MessageHandlerMapping.java64
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/configuration/QpidDatasource.java249
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/configuration/Tag.java54
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/configuration/UnknownAccessCodeException.java53
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/configuration/UnknownBrokerException.java43
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/configuration/UnknownTypeCodeException.java53
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/configuration/WorkerManagerConfigurationParser.java108
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/handler/base/BaseMessageHandler.java54
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/handler/base/ContentIndicationMessageHandler.java114
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/handler/base/IMessageHandler.java52
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/ConfigurationMessageHandler.java57
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/EventContentMessageHandler.java51
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/HeartBeatIndicationMessageHandler.java39
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/IMethodInvocationListener.java41
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/InstrumentationMessageHandler.java57
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/InvocationResult.java157
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/MethodOrEventDataTransferObject.java68
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/MethodResponseMessageHandler.java106
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/QpidDomainObject.java314
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/QpidDomainObjectMBean.java234
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/SchemaResponseMessageHandler.java217
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/AccessMode.java33
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/Direction.java33
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/DomainModel.java239
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/IValidator.java38
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/InvocationEvent.java76
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/JmxService.java410
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/MissingFeatureAttributesException.java35
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidArgument.java123
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidAttribute.java105
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidClass.java833
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidClassMBean.java41
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidEntity.java163
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidEvent.java493
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidEventMBean.java41
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidFeature.java86
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidFeatureBuilder.java454
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidMethod.java147
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidPackage.java279
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidProperty.java295
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidStatistic.java34
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/UnableToBuildFeatureException.java51
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/ValidationException.java105
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/AbsTime.java44
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Binary.java162
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Boolean.java44
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/DeltaTime.java44
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Double.java44
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Float.java44
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int16.java44
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int32.java44
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int64.java44
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int8.java44
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Map.java45
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/ObjectReference.java44
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Str16.java44
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Str8.java44
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Type.java101
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint16.java44
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint32.java44
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint64.java44
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint8.java44
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uuid.java46
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/services/BrokerMessageListener.java183
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/services/ManagementClient.java250
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/services/MessageTokenizer.java152
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/services/MethodInvocationException.java50
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/services/QMan.java412
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/services/QpidService.java362
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/services/SequenceNumberGenerator.java41
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/services/StartupFailureException.java42
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/domain/services/UnableToComplyException.java31
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/jmx/EntityLifecycleNotification.java147
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/jmx/OperationHasBeenInvokedNotification.java168
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/messages/ManagementMessage.java189
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/messages/MethodInvocationRequestMessage.java161
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/messages/SchemaRequestMessage.java68
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/servlet/ConnectQManToBroker.java89
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/servlet/QManLifeCycleManager.java79
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/servlet/WSDMAdapter.java109
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/web/action/BrokerModel.java100
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/web/action/BrokersManagementAction.java204
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/web/action/ConsoleAction.java117
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/web/action/ConsoleModel.java158
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/web/action/JmxPerspectiveAction.java189
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/web/action/LoggingConfigurationAction.java114
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/web/action/ResourcesManagementAction.java91
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/web/action/WsdmOperationsPerspectiveAction.java191
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/web/action/WsdmPropertiesPerspectiveAction.java185
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/web/action/WsdmRmdPerspectiveAction.java139
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/web/action/WsdmWsdlPerspectiveAction.java140
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmu.java130
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmuInitializer.java95
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmuMBean.java48
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/ArtifactsNotAvailableException.java76
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/BuilderException.java41
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/Constants.java44
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/ConsumerCapability.java68
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/DummyCapabilityBuilder.java86
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/IArtifactBuilder.java82
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapability.java219
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityBuilder.java549
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/QManAdapterCapability.java557
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/QManMessageHandler.java104
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/QManMetadataExchangeCapability.java99
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/Result.java57
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/RmdBuilder.java135
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WSDMArtifactsDirector.java196
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsArtifacts.java93
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsArtifactsFactory.java140
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsdlBuilder.java460
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/EntityInstanceNotFoundFault.java58
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/MethodInvocationFault.java79
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/NoSuchAttributeFault.java70
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/ObjectNameIdFactory.java61
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/QManFault.java72
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/QManResourceIdFactory.java57
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/ThreadSession.java105
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/ThreadSessionManager.java68
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/UnableToConnectWithBrokerFault.java86
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/engine/WSDMAdapterEnvironment.java97
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/engine/WSDMAdapterIsolationLayer.java36
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/resources/QManWsResource.java762
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/ByteArraySerializer.java83
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/DateSerializer.java75
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/InvocationResultSerializer.java85
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/MapSerializer.java134
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/ObjectSerializer.java202
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/UUIDSerializer.java72
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/notifications/LifeCycleEvent.java149
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/management/wsdm/notifications/LifeCycleEventType.java34
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/qman/debug/WsdlDebugger.java49
-rw-r--r--java/management/client/src/main/java/org/apache/qpid/qman/debug/XmlDebugger.java92
-rw-r--r--java/management/client/src/main/java/router-entries/adapter/resource-instance-1.xml2
-rw-r--r--java/management/client/src/main/java/router-entries/consumer/resource-instance-1.xml2
-rw-r--r--java/management/client/src/main/java/wsdl/QManAdapter.rmd27
-rw-r--r--java/management/client/src/main/java/wsdl/QManAdapter.wsdl694
-rw-r--r--java/management/client/src/main/java/wsdl/QManWsResource.rmd17
-rw-r--r--java/management/client/src/main/java/wsdl/QManWsResource.wsdl507
-rw-r--r--java/management/client/src/main/java/wsdl/SOAP-Envelope-1_2.xsd160
-rw-r--r--java/management/client/src/main/java/wsdl/WS-Addressing-2005_08.xsd148
-rw-r--r--java/management/client/src/main/java/wsdl/WS-BaseFaults-1_2.xsd84
-rw-r--r--java/management/client/src/main/java/wsdl/WS-BaseNotification-1_3.wsdl449
-rw-r--r--java/management/client/src/main/java/wsdl/WS-BaseNotification-1_3.xsd577
-rw-r--r--java/management/client/src/main/java/wsdl/WS-MetadataExchange-2004_09.xsd113
-rw-r--r--java/management/client/src/main/java/wsdl/WS-Resource-1_2.wsdl54
-rw-r--r--java/management/client/src/main/java/wsdl/WS-Resource-1_2.xsd48
-rw-r--r--java/management/client/src/main/java/wsdl/WS-ResourceLifetime-1_2.wsdl83
-rw-r--r--java/management/client/src/main/java/wsdl/WS-ResourceLifetime-1_2.xsd130
-rw-r--r--java/management/client/src/main/java/wsdl/WS-ResourceMetadataDescriptor-CD-01.xsd325
-rw-r--r--java/management/client/src/main/java/wsdl/WS-ResourceProperties-1_2.wsdl395
-rw-r--r--java/management/client/src/main/java/wsdl/WS-ResourceProperties-1_2.xsd394
-rw-r--r--java/management/client/src/main/java/wsdl/WS-ServiceGroup-1_2.wsdl269
-rw-r--r--java/management/client/src/main/java/wsdl/WS-ServiceGroup-1_2.xsd233
-rw-r--r--java/management/client/src/main/java/wsdl/WS-ServiceGroupEntry-1_2.wsdl206
-rw-r--r--java/management/client/src/main/java/wsdl/WS-Topics-1_3.xsd185
-rw-r--r--java/management/client/src/main/java/wsdl/WSDM-MUWS-Part1-1_1.xsd93
-rw-r--r--java/management/client/src/main/java/wsdl/WSDM-MUWS-Part2-1_1.xsd656
-rw-r--r--java/management/client/src/main/java/wsdl/WsResource.rmd14
-rw-r--r--java/management/client/src/main/java/wsdl/WsResourceFactory.wsdl22
-rw-r--r--java/management/client/src/main/java/wsdl/XML-Namespace-1998.xsd25
-rw-r--r--java/management/client/src/test/java/log4j.xml32
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/TestConstants.java67
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/configuration/ConfigurationTest.java181
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/configuration/ConfiguratorTest.java163
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/configuration/MappingParsersTest.java79
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/domain/handler/base/ContentIndicationMessageHandlerTest.java59
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/domain/model/BaseDomainModelTestCase.java44
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/domain/model/BaseQpidFeatureBuilderTestCase.java96
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/domain/model/DomainModelTest.java55
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/domain/model/OptionalPropertiesTest.java187
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidClassTest.java408
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidEventTest.java293
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidMethodBuilderTest.java147
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidNumberPropertyTest.java171
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidPackageTest.java53
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidPropertyBuilderTest.java269
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidStatisticBuilderTest.java159
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidStringPropertyTest.java127
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/domain/model/type/BinaryTest.java59
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/domain/services/BrokerMessageListenerTest.java241
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/domain/services/MessageTokenizerTest.java140
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/wsdm/BaseWsDmAdapterTestCase.java143
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/wsdm/EnhancedReflectionProxyHandler.java72
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/wsdm/GetMultipleResourcePropertiesTestCase.java125
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/wsdm/GetResourcePropertiesTestCase.java105
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/wsdm/GetResourcePropertyDocumentTestCase.java134
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/wsdm/MetadataExchangeInterfaceTestCase.java169
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/wsdm/OperationInvocationInterfaceTestCase.java580
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/wsdm/ServerThread.java118
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/wsdm/SetResourcePropertiesTestCase.java219
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/wsdm/WebApplicationLifeCycleListener.java61
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/wsdm/WsDmAdapterTest.java156
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityBuilderTest.java335
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityTest.java204
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/QManAdapterCapabilityTest.java81
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/RmdBuilderTest.java110
-rw-r--r--java/management/client/src/test/java/org/apache/qpid/management/wsdm/web.xml11
-rw-r--r--java/management/client/web.xml128
-rw-r--r--java/management/common/build.xml26
-rw-r--r--java/management/common/src/main/java/management-common.bnd8
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/JMXConnnectionFactory.java284
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ConfigurationManagement.java42
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/LoggingManagement.java160
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedBroker.java127
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedConnection.java143
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedExchange.java110
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedQueue.java407
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ServerInformation.java84
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/UserManagement.java131
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/annotations/MBeanAttribute.java41
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/annotations/MBeanConstructor.java39
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/annotations/MBeanDescription.java38
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/annotations/MBeanOperation.java43
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/annotations/MBeanOperationParameter.java37
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/sasl/CRAMMD5HashedSaslClientFactory.java60
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/sasl/ClientSaslFactory.java54
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/sasl/Constants.java33
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/sasl/JCAProvider.java56
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/sasl/PlainSaslClient.java203
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/sasl/SaslProvider.java35
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/sasl/UserPasswordCallbackHandler.java73
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/sasl/UsernameHashedPasswordCallbackHandler.java108
-rw-r--r--java/management/common/src/test/java/org/apache/qpid/management/common/mbeans/ManagedQueueTest.java84
-rw-r--r--java/management/console/build.xml27
-rw-r--r--java/management/console/src/main/java/org/apache/qpid/console/AbstractConsole.java81
-rw-r--r--java/management/console/src/main/java/org/apache/qpid/console/Agent.java116
-rw-r--r--java/management/console/src/main/java/org/apache/qpid/console/Broker.java505
-rw-r--r--java/management/console/src/main/java/org/apache/qpid/console/ClassKey.java146
-rw-r--r--java/management/console/src/main/java/org/apache/qpid/console/Console.java51
-rw-r--r--java/management/console/src/main/java/org/apache/qpid/console/ConsoleException.java48
-rw-r--r--java/management/console/src/main/java/org/apache/qpid/console/EventSeverity.java37
-rw-r--r--java/management/console/src/main/java/org/apache/qpid/console/MethodResult.java88
-rw-r--r--java/management/console/src/main/java/org/apache/qpid/console/ObjectID.java93
-rw-r--r--java/management/console/src/main/java/org/apache/qpid/console/QMFEvent.java108
-rw-r--r--java/management/console/src/main/java/org/apache/qpid/console/QMFObject.java423
-rw-r--r--java/management/console/src/main/java/org/apache/qpid/console/SchemaArgument.java65
-rw-r--r--java/management/console/src/main/java/org/apache/qpid/console/SchemaClass.java251
-rw-r--r--java/management/console/src/main/java/org/apache/qpid/console/SchemaMethod.java125
-rw-r--r--java/management/console/src/main/java/org/apache/qpid/console/SchemaProperty.java81
-rw-r--r--java/management/console/src/main/java/org/apache/qpid/console/SchemaStatistic.java88
-rw-r--r--java/management/console/src/main/java/org/apache/qpid/console/SchemaVariable.java185
-rw-r--r--java/management/console/src/main/java/org/apache/qpid/console/SequenceManager.java57
-rw-r--r--java/management/console/src/main/java/org/apache/qpid/console/Session.java980
-rw-r--r--java/management/console/src/main/java/org/apache/qpid/console/Util.java184
-rw-r--r--java/management/console/src/main/java/org/apache/qpid/console/XMLUtil.java134
-rw-r--r--java/management/console/src/test/java/org/apache/qpid/console/ClassKeyTest.java39
-rw-r--r--java/management/eclipse-plugin/META-INF/MANIFEST.MF17
-rw-r--r--java/management/eclipse-plugin/README.txt21
-rw-r--r--java/management/eclipse-plugin/bin/qpidmc.bat55
-rwxr-xr-xjava/management/eclipse-plugin/bin/qpidmc.sh64
-rwxr-xr-xjava/management/eclipse-plugin/bin/qpidmc_gtk.sh24
-rwxr-xr-xjava/management/eclipse-plugin/bin/qpidmc_motif.sh24
-rw-r--r--java/management/eclipse-plugin/build-release-common.properties33
-rw-r--r--java/management/eclipse-plugin/build-release-linux-gtk-x86.properties36
-rw-r--r--java/management/eclipse-plugin/build-release-linux-gtk-x86_64.properties36
-rw-r--r--java/management/eclipse-plugin/build-release-macosx.properties40
-rw-r--r--java/management/eclipse-plugin/build-release-macosx.xml101
-rw-r--r--java/management/eclipse-plugin/build-release-solaris-gtk-sparc.properties39
-rw-r--r--java/management/eclipse-plugin/build-release-win32-win32-x86.properties34
-rw-r--r--java/management/eclipse-plugin/build-release.xml172
-rw-r--r--java/management/eclipse-plugin/build.xml63
-rw-r--r--java/management/eclipse-plugin/icons/Thumbs.dbbin97280 -> 0 bytes
-rw-r--r--java/management/eclipse-plugin/icons/back.gifbin0 -> 327 bytes
-rw-r--r--java/management/eclipse-plugin/icons/configuration_management.gifbin0 -> 343 bytes
-rw-r--r--java/management/eclipse-plugin/icons/failure.gifbin0 -> 353 bytes
-rw-r--r--java/management/eclipse-plugin/icons/logging_management.gifbin0 -> 381 bytes
-rw-r--r--java/management/eclipse-plugin/icons/qpidConnections.gifbin168 -> 200 bytes
-rw-r--r--java/management/eclipse-plugin/icons/refresh.gifbin182 -> 336 bytes
-rw-r--r--java/management/eclipse-plugin/icons/server_information.gifbin0 -> 614 bytes
-rw-r--r--java/management/eclipse-plugin/icons/splash.bmpbin207078 -> 275178 bytes
-rw-r--r--java/management/eclipse-plugin/icons/success.gifbin0 -> 343 bytes
-rw-r--r--java/management/eclipse-plugin/icons/user_management.gifbin0 -> 597 bytes
-rw-r--r--java/management/eclipse-plugin/icons/virtualhost_manager.gifbin0 -> 607 bytes
-rw-r--r--java/management/eclipse-plugin/plugin.xml54
-rw-r--r--java/management/eclipse-plugin/pom.xml252
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApiVersion.java110
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java76
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationWorkbenchWindowAdvisor.java2
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Constants.java25
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedBean.java68
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedServer.java19
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/RefreshIntervalComboPanel.java131
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ServerRegistry.java63
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/AbstractAction.java144
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/AddServer.java89
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/BackAction.java59
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/EditAttribute.java51
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/ReconnectServer.java69
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/Refresh.java2
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/VersionAction.java5
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientListener.java9
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientNotificationListener.java1
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXServerRegistry.java226
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/MBeanUtility.java144
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/NotificationObject.java12
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/CRAMMD5HashedSaslClientFactory.java60
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/ClientSaslFactory.java54
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/JCAProvider.java56
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/PlainSaslClient.java203
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/SaslProvider.java35
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/UserPasswordCallbackHandler.java73
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/UsernameHashedPasswordCallbackHandler.java82
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/AttributesTabControl.java98
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/ConnectionTypeTabControl.java59
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/ExchangeTypeTabControl.java60
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanTabFolderFactory.java464
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanTypeTabControl.java336
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanView.java583
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NavigationView.java380
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NotificationsTabControl.java241
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/OperationTabControl.java53
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/QueueTypeTabControl.java296
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/TabControl.java1
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/VHNotificationsTabControl.java172
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/ViewUtility.java551
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/connection/ConnectionOperationsTabControl.java547
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/exchange/ExchangeOperationsTabControl.java641
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/exchange/HeadersExchangeOperationsTabControl.java713
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/ConfigurationFileTabControl.java591
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/LoggingTableContentProvider.java52
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/LoggingTableLabelProvider.java59
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/LoggingTableSorter.java90
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/RuntimeTabControl.java595
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/queue/QueueOperationsTabControl.java1114
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/ConnectionTypeTabControl.java50
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/ExchangeTypeTabControl.java45
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/MBeanTypeTabControl.java458
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/QueueTypeTabControl.java764
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/users/UserManagementTabControl.java915
-rw-r--r--java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/vhost/VHostTabControl.java871
-rw-r--r--java/management/eclipse-plugin/src/main/resources/eclipse.exebin180224 -> 0 bytes
-rw-r--r--java/management/eclipse-plugin/src/main/resources/eclipse.ini23
-rw-r--r--java/management/eclipse-plugin/src/main/resources/jmxremote.sasl-plugin/MANIFEST.MF19
-rw-r--r--java/management/eclipse-plugin/src/main/resources/license.eclipse.txt88
-rw-r--r--java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/Configuration/config.ini49
-rw-r--r--java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/libcairo-swt.sobin0 -> 266168 bytes
-rw-r--r--java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/qpidmcbin0 -> 52576 bytes
-rw-r--r--java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/qpidmc.ini37
-rw-r--r--java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/Configuration/config.ini49
-rw-r--r--java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/libcairo-swt.sobin0 -> 335360 bytes
-rw-r--r--java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/qpidmcbin0 -> 67927 bytes
-rw-r--r--java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/qpidmc.ini37
-rw-r--r--java/management/eclipse-plugin/src/main/resources/macosx/Configuration/config.ini49
-rw-r--r--java/management/eclipse-plugin/src/main/resources/macosx/Contents/Info.plist35
-rwxr-xr-xjava/management/eclipse-plugin/src/main/resources/macosx/Contents/MacOS/qpidmcbin0 -> 59200 bytes
-rw-r--r--java/management/eclipse-plugin/src/main/resources/macosx/Contents/MacOS/qpidmc.ini42
-rw-r--r--java/management/eclipse-plugin/src/main/resources/macosx/Contents/Resources/Console.icnsbin0 -> 51007 bytes
-rw-r--r--java/management/eclipse-plugin/src/main/resources/sasl/MANIFEST.MF8
-rw-r--r--java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Configuration/config.ini49
-rw-r--r--java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.l.pm311
-rw-r--r--java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.m.pm295
-rw-r--r--java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.s.pm287
-rw-r--r--java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.t.pm279
-rwxr-xr-xjava/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/qpidmcbin0 -> 31668 bytes
-rw-r--r--java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/qpidmc.ini40
-rw-r--r--java/management/eclipse-plugin/src/main/resources/startup.jarbin33049 -> 0 bytes
-rw-r--r--java/management/eclipse-plugin/src/main/resources/unix/configuration/config.ini27
-rw-r--r--java/management/eclipse-plugin/src/main/resources/win32-win32-x86/Configuration/config.ini49
-rw-r--r--java/management/eclipse-plugin/src/main/resources/win32-win32-x86/qpidmc.exebin0 -> 57344 bytes
-rw-r--r--java/management/eclipse-plugin/src/main/resources/win32-win32-x86/qpidmc.ini36
-rw-r--r--java/management/eclipse-plugin/src/main/resources/win32/configuration/config.ini26
-rw-r--r--java/management/eclipse-plugin/src/test/java/org/apache/qpid/management/ui/ApiVersionTest.java177
-rw-r--r--java/management/eclipse-plugin/src/test/java/org/apache/qpid/management/ui/ApplicationRegistryTest.java43
-rw-r--r--java/management/eclipse-plugin/src/test/java/org/apache/qpid/management/ui/ManagementConsoleTest.java3
-rw-r--r--java/management/tools/qpid-cli/Guide.txt143
-rw-r--r--java/management/tools/qpid-cli/LICENSE225
-rw-r--r--java/management/tools/qpid-cli/NOTICE12
-rw-r--r--java/management/tools/qpid-cli/README64
-rwxr-xr-xjava/management/tools/qpid-cli/bin/qpid-cli35
-rwxr-xr-xjava/management/tools/qpid-cli/bin/qpid-cli.bat28
-rw-r--r--java/management/tools/qpid-cli/build.xml31
-rw-r--r--java/management/tools/qpid-cli/report.property26
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/Command.java33
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/CommandExecutionEngine.java76
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/CommandLineInterpreter.java263
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/Connector.java49
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/ConnectorFactory.java50
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/ReportGenerator.java195
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/commands/CommandImpl.java153
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commanddelete.java199
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandget.java211
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandhelp.java56
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandinfo.java206
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandlist.java232
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandmove.java259
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandset.java260
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandview.java257
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandviewcontent.java250
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/AllObjects.java38
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/ConnectionObject.java46
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/ExchangeObject.java45
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/ObjectNames.java591
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/QueueObject.java67
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/UserManagementObject.java38
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/VirtualHostObject.java47
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/utils/CommandLineOption.java104
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/utils/CommandLineOptionConstants.java37
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/utils/CommandLineOptionParser.java231
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/utils/JMXConfigProperty.java29
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/utils/JMXConfiguration.java182
-rw-r--r--java/management/tools/qpid-cli/src/org/apache/qpid/utils/JMXinfo.java53
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/AllTest.java41
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/ConnectionConstants.java30
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/TestCommandExecutionEngine.java73
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/TestCommandLineInterpreter.java80
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/TestConnector.java79
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/TestReportGenerator.java26
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommand.java79
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommanddelete.java79
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommandinfo.java77
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommandlist.java82
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommandmove.java80
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommandview.java78
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommandviewcontent.java78
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestAllObject.java69
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestConnectionObject.java83
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestExchangeObject.java83
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestObjectNames.java26
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestQueueObject.java83
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestUserManagementObject.java74
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestVirtualHostObject.java84
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/utils/TestCommandLineOption.java64
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/utils/TestCommandLineOptionParser.java79
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/utils/TestJMXConfigProperty.java26
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/utils/TestJMXConfiguration.java64
-rw-r--r--java/management/tools/qpid-cli/test/org/apache/qpid/utils/TestJMXinfo.java30
-rw-r--r--java/module.xml368
-rwxr-xr-xjava/perftests/bin/monitoring/monitor-broker.sh200
-rwxr-xr-xjava/perftests/bin/monitoring/runTests.sh127
-rwxr-xr-xjava/perftests/bin/monitoring/stop-monitored-broker.sh103
-rwxr-xr-xjava/perftests/bin/processing/process.sh264
-rwxr-xr-xjava/perftests/bin/processing/processAll.sh33
-rwxr-xr-xjava/perftests/bin/processing/processTests.py567
-rwxr-xr-xjava/perftests/bin/topicListener.sh5
-rwxr-xr-xjava/perftests/bin/topicPublisher.sh5
-rw-r--r--java/perftests/build.xml12
-rw-r--r--java/perftests/distribution/pom.xml131
-rw-r--r--java/perftests/distribution/src/main/assembly/performance.xml103
-rw-r--r--java/perftests/etc/perftests.log4j46
-rwxr-xr-xjava/perftests/etc/scripts/Reliability.sh2
-rwxr-xr-xjava/perftests/etc/scripts/RunAll.sh10
-rwxr-xr-xjava/perftests/etc/scripts/RunCore.sh22
-rwxr-xr-xjava/perftests/etc/scripts/extractResults.sh13
-rwxr-xr-xjava/perftests/etc/scripts/extractThroughputResults.sh30
-rw-r--r--java/perftests/generate-scripts74
-rw-r--r--java/perftests/pom.xml562
-rw-r--r--java/perftests/scripts.xml328
-rw-r--r--java/perftests/src/main/java/perftests.log4j45
-rw-r--r--java/plugins/pom.xml34
-rw-r--r--java/plugins/src/main/java/org/apache/qpid/plugins/JythonMojo.java100
-rw-r--r--java/pom.xml787
-rw-r--r--java/release-docs/RELEASE_NOTES.txt108
-rw-r--r--java/release-docs/RELEASE_NOTES_M1.txt74
-rw-r--r--java/resources/DISCLAIMER5
-rw-r--r--java/resources/LICENSE623
-rwxr-xr-xjava/resources/LICENSE.txt203
-rw-r--r--java/resources/META-INF/DISCLAIMER10
-rw-r--r--java/resources/META-INF/DISCLAIMER.txt7
-rw-r--r--java/resources/META-INF/LICENSE203
-rw-r--r--java/resources/META-INF/NOTICE105
-rw-r--r--java/resources/NOTICE160
-rw-r--r--java/resources/NOTICE.txt36
-rw-r--r--java/resources/README.txt40
-rw-r--r--java/systests/build.xml2
-rw-r--r--java/systests/distribution/pom.xml112
-rw-r--r--java/systests/distribution/src/main/assembly/systests.xml91
-rw-r--r--java/systests/etc/config-systests-ServerConfigurationTest-New.xml93
-rw-r--r--java/systests/etc/config-systests-ServerConfigurationTest-Old.xml72
-rw-r--r--java/systests/etc/config-systests-acl-settings.xml160
-rw-r--r--java/systests/etc/config-systests-acl.xml30
-rw-r--r--java/systests/etc/config-systests-derby-settings.xml64
-rw-r--r--java/systests/etc/config-systests-derby.xml30
-rw-r--r--java/systests/etc/config-systests-firewall-2.xml137
-rw-r--r--java/systests/etc/config-systests-firewall-3.xml137
-rw-r--r--java/systests/etc/config-systests-firewall-settings.xml28
-rw-r--r--java/systests/etc/config-systests-firewall.xml30
-rw-r--r--java/systests/etc/config-systests-settings.xml29
-rw-r--r--java/systests/etc/config-systests.xml29
-rw-r--r--java/systests/etc/virtualhosts-ServerConfigurationTest-New.xml40
-rw-r--r--java/systests/pom.xml201
-rw-r--r--java/systests/src/main/java/org/apache/qpid/client/AMQQueueDeferredOrderingTest.java21
-rw-r--r--java/systests/src/main/java/org/apache/qpid/client/DispatcherTest.java34
-rw-r--r--java/systests/src/main/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java18
-rw-r--r--java/systests/src/main/java/org/apache/qpid/client/MessageListenerTest.java8
-rw-r--r--java/systests/src/main/java/org/apache/qpid/client/MultipleJCAProviderRegistrationTest.java82
-rw-r--r--java/systests/src/main/java/org/apache/qpid/client/ResetMessageListenerTest.java329
-rw-r--r--java/systests/src/main/java/org/apache/qpid/client/SessionCreateTest.java63
-rw-r--r--java/systests/src/main/java/org/apache/qpid/management/jmx/ManagementActorLoggingTest.java530
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java92
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/BrokerStartupTest.java149
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/ack/TxAckTest.java262
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/configuration/ServerConfigurationFileTest.java87
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java561
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeTest.java106
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/exchange/ReturnUnroutableMandatoryMessageTest.java72
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/failover/FailoverMethodTest.java98
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/failover/MessageDisappearWithIOExceptionTest.java338
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/logging/AbstractTestLogging.java320
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/logging/AlertingTest.java209
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/logging/BindingLoggingTest.java279
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/logging/BrokerLoggingTest.java1015
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/logging/ChannelLoggingTest.java301
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/logging/ConnectionLoggingTest.java182
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/logging/DerbyMessageStoreLoggingTest.java567
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/logging/DurableQueueLoggingTest.java357
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/logging/ExchangeLoggingTest.java203
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/logging/ManagementLoggingTest.java327
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/logging/MemoryMessageStoreLoggingTest.java192
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/logging/QueueLoggingTest.java171
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/logging/SubscriptionLoggingTest.java438
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/logging/TransientQueueLoggingTest.java30
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java139
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/persistent/NoLocalAfterRecoveryTest.java246
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/plugins/PluginTest.java54
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java124
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/protocol/MaxChannelsTest.java70
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/protocol/MockIoSession.java297
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/queue/AckTest.java420
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/queue/DeepQueueConsumeWithSelector.java159
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/queue/MessageTestHelper.java102
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/queue/MockProtocolSession.java262
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/queue/ModelTest.java299
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/queue/PriorityTest.java168
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java498
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java61
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionTestHelper.java79
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/queue/TimeToLiveTest.java158
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java499
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/security/firewall/FirewallConfigTest.java246
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/store/PersistentStoreTest.java183
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/store/SkeletonMessageStore.java155
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/store/SlowMessageStore.java313
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/store/TestMemoryMessageStore.java51
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/store/TestReferenceCounting.java169
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/txn/TxnBufferTest.java306
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/client/CancelTest.java5
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java12
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/client/FlowControlTest.java46
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java22
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserClientAckTest.java3
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserDupsOkTest.java3
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserNoAckTest.java3
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserPreAckTest.java3
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserTransactedTest.java3
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/client/RollbackOrderTest.java194
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/client/failover/FailoverTest.java256
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/client/message/JMSDestinationTest.java330
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/client/message/MessageToStringTest.java12
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/client/message/ObjectMessageTest.java141
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/client/message/SelectorTest.java310
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/client/timeouts/SyncWaitDelayTest.java112
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/client/timeouts/SyncWaitTimeoutDelayTest.java72
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkBaseCase.java1
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/package.html23
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/framework/qpid/InVMBrokerDecorator.java1
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/ack/Acknowledge2ConsumersTest.java193
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverOnMessageTest.java356
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverTest.java306
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeOnMessageTest.java181
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java170
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/ack/FailoverBeforeConsumingRecoverTest.java40
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/ack/QuickAcking.java148
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java253
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java6
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java16
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java14
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/basic/SelectorTest.java306
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/basic/close/CloseTest.java14
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java76
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/client/DynamicQueueExchangeCreateTest.java88
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseOkTest.java2
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseTest.java16
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/CloseAfterConnectionFailureTest.java124
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java2
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java71
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/Client.java12
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/Service.java3
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/client/protocol/AMQProtocolSessionTest.java25
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java44
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/close/JavaServerCloseRaceConditionTest.java119
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java3
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/close/VerifyAckingOkDuringClose.java160
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSDestinationTest.java89
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java4
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/message/StreamMessageTest.java4
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8En4
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8Jp4
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8Test.java122
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/publish/DirtyTrasactedPubilshTest.java403
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java96
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java77
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java2
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/xa/FaultTest.java21
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/utils/FailoverBaseCase.java97
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java212
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java940
-rw-r--r--java/systests/src/main/java/org/apache/qpid/util/LogMonitor.java211
-rw-r--r--java/systests/src/main/java/org/apache/qpid/util/LogMonitorTest.java275
-rw-r--r--java/test-profiles/08StandaloneExcludes6
-rwxr-xr-xjava/test-profiles/CPPExcludes111
-rw-r--r--java/test-profiles/CPPPrefetchExcludes4
-rw-r--r--java/test-profiles/CPPTransientExcludes10
-rw-r--r--java/test-profiles/Excludes38
-rw-r--r--java/test-profiles/JavaExcludes20
-rw-r--r--java/test-profiles/JavaInVMExcludes9
-rw-r--r--java/test-profiles/JavaStandaloneExcludes44
-rw-r--r--java/test-profiles/JavaTransientExcludes1
-rw-r--r--java/test-profiles/XAExcludes3
-rwxr-xr-xjava/test-profiles/clean-dir25
-rw-r--r--java/test-profiles/cpp.async.excludes5
-rw-r--r--java/test-profiles/cpp.async.testprofile3
-rw-r--r--java/test-profiles/cpp.cluster.testprofile10
-rw-r--r--java/test-profiles/cpp.excludes10
-rw-r--r--java/test-profiles/cpp.noprefetch.testprofile3
-rw-r--r--java/test-profiles/cpp.ssl.excludes1
-rw-r--r--java/test-profiles/cpp.ssl.testprofile11
-rw-r--r--java/test-profiles/cpp.testprofile19
-rw-r--r--java/test-profiles/default.testprofile39
-rw-r--r--java/test-profiles/java-derby.testprofile8
-rw-r--r--java/test-profiles/java.0.10.testprofile8
-rw-r--r--java/test-profiles/java.testprofile7
-rw-r--r--java/test-profiles/log4j-test.xml58
-rw-r--r--java/test-profiles/test-provider.properties51
-rw-r--r--java/test-profiles/test_resources/ssl/certstore.jksbin0 -> 498 bytes
-rw-r--r--java/test-profiles/test_resources/ssl/keystore.jksbin0 -> 2186 bytes
-rw-r--r--java/test-profiles/test_resources/ssl/pfile1
-rw-r--r--java/test-profiles/test_resources/ssl/server_db/cert8.dbbin0 -> 65536 bytes
-rw-r--r--java/test-profiles/test_resources/ssl/server_db/key3.dbbin0 -> 16384 bytes
-rw-r--r--java/test-profiles/test_resources/ssl/server_db/secmod.dbbin0 -> 16384 bytes
-rw-r--r--java/test-profiles/test_resources/ssl/server_db/server.crt12
-rw-r--r--java/test-profiles/test_resources/ssl/server_db/server.req20
-rw-r--r--java/test-provider.properties15
-rw-r--r--java/testkit/bin/perf_report.sh100
-rwxr-xr-xjava/testkit/bin/qpid-python-testkit30
-rw-r--r--java/testkit/bin/setenv.sh73
-rw-r--r--java/testkit/build.xml2
-rw-r--r--java/testkit/etc/jndi.properties10
-rw-r--r--java/testkit/src/main/java/org/apache/qpid/testkit/Client.java90
-rw-r--r--java/testkit/src/main/java/org/apache/qpid/testkit/ErrorHandler.java6
-rw-r--r--java/testkit/src/main/java/org/apache/qpid/testkit/MessageFactory.java43
-rw-r--r--java/testkit/src/main/java/org/apache/qpid/testkit/Receiver.java225
-rw-r--r--java/testkit/src/main/java/org/apache/qpid/testkit/Sender.java195
-rw-r--r--java/testkit/src/main/java/org/apache/qpid/testkit/TestLauncher.java384
-rw-r--r--java/testkit/src/main/java/org/apache/qpid/testkit/perf/PerfBase.java102
-rw-r--r--java/testkit/src/main/java/org/apache/qpid/testkit/perf/PerfConsumer.java248
-rw-r--r--java/testkit/src/main/java/org/apache/qpid/testkit/perf/PerfProducer.java207
-rw-r--r--java/testkit/src/main/java/org/apache/qpid/testkit/perf/TestParams.java160
-rw-r--r--java/testkit/src/main/java/org/apache/qpid/testkit/soak/BaseTest.java152
-rw-r--r--java/testkit/src/main/java/org/apache/qpid/testkit/soak/MultiThreadedConsumer.java153
-rw-r--r--java/testkit/src/main/java/org/apache/qpid/testkit/soak/MultiThreadedProducer.java166
-rw-r--r--java/testkit/src/main/java/org/apache/qpid/testkit/soak/ResourceLeakTest.java96
-rw-r--r--java/testkit/src/main/java/org/apache/qpid/testkit/soak/SimpleConsumer.java134
-rw-r--r--java/testkit/src/main/java/org/apache/qpid/testkit/soak/SimpleProducer.java146
-rwxr-xr-xjava/testkit/testkit.py216
-rwxr-xr-xjava/tools/bin/perf_report.sh131
-rw-r--r--java/tools/bin/qpid-bench2
-rw-r--r--java/tools/bin/run_pub.sh (renamed from java/testkit/bin/run_pub.sh)0
-rw-r--r--java/tools/bin/run_sub.sh (renamed from java/testkit/bin/run_sub.sh)0
-rw-r--r--java/tools/bin/setenv.sh49
-rw-r--r--java/tools/src/main/java/org/apache/qpid/tools/JNDICheck.java2
-rw-r--r--java/tools/src/main/java/org/apache/qpid/tools/LatencyTest.java349
-rw-r--r--java/tools/src/main/java/org/apache/qpid/tools/MessageFactory.java64
-rw-r--r--java/tools/src/main/java/org/apache/qpid/tools/PerfBase.java102
-rw-r--r--java/tools/src/main/java/org/apache/qpid/tools/PerfConsumer.java267
-rw-r--r--java/tools/src/main/java/org/apache/qpid/tools/PerfProducer.java262
-rw-r--r--java/tools/src/main/java/org/apache/qpid/tools/QpidBench.java253
-rw-r--r--java/tools/src/main/java/org/apache/qpid/tools/TestParams.java168
-rw-r--r--[-rwxr-xr-x]python/LICENSE.txt0
-rw-r--r--python/Makefile98
-rw-r--r--python/README.txt58
-rw-r--r--python/RELEASE_NOTES32
-rwxr-xr-xpython/amqp-doc80
-rwxr-xr-xpython/commands/qpid-cluster328
-rwxr-xr-xpython/commands/qpid-config474
-rwxr-xr-xpython/commands/qpid-printevents74
-rwxr-xr-xpython/commands/qpid-queue-stats203
-rwxr-xr-xpython/commands/qpid-route593
-rwxr-xr-xpython/commands/qpid-stat460
-rwxr-xr-xpython/commands/qpid-tool6
-rw-r--r--python/cpp_failing_0-10.txt0
-rw-r--r--python/cpp_failing_0-8.txt0
-rw-r--r--python/cpp_failing_0-9.txt4
-rw-r--r--python/doc/test-requirements.txt19
-rw-r--r--python/examples/README319
-rwxr-xr-xpython/examples/api/drain62
-rwxr-xr-xpython/examples/api/server87
-rwxr-xr-xpython/examples/api/spout103
-rwxr-xr-xpython/examples/datatypes/client.py122
-rwxr-xr-xpython/examples/datatypes/server.py124
-rw-r--r--python/examples/datatypes/testdata.py180
-rwxr-xr-xpython/examples/direct/declare_queues.py20
-rwxr-xr-xpython/examples/direct/direct_consumer.py20
-rwxr-xr-xpython/examples/direct/direct_producer.py20
-rwxr-xr-xpython/examples/direct/listener.py20
-rw-r--r--python/examples/direct/verify19
-rwxr-xr-xpython/examples/fanout/fanout_consumer.py20
-rwxr-xr-xpython/examples/fanout/fanout_producer.py20
-rwxr-xr-xpython/examples/fanout/listener.py20
-rw-r--r--python/examples/fanout/verify19
-rwxr-xr-xpython/examples/headers/declare_queues.py77
-rwxr-xr-xpython/examples/headers/headers_consumer.py107
-rwxr-xr-xpython/examples/headers/headers_producer.py79
-rw-r--r--python/examples/headers/verify22
-rw-r--r--python/examples/headers/verify.in25
-rwxr-xr-xpython/examples/pubsub/topic_publisher.py18
-rwxr-xr-xpython/examples/pubsub/topic_subscriber.py20
-rw-r--r--python/examples/pubsub/verify19
-rwxr-xr-xpython/examples/request-response/client.py20
-rwxr-xr-xpython/examples/request-response/server.py20
-rw-r--r--python/examples/request-response/verify19
-rwxr-xr-xpython/examples/xml-exchange/declare_queues.py20
-rwxr-xr-xpython/examples/xml-exchange/listener.py20
-rw-r--r--python/examples/xml-exchange/verify19
-rwxr-xr-xpython/examples/xml-exchange/xml_consumer.py20
-rwxr-xr-xpython/examples/xml-exchange/xml_producer.py20
-rwxr-xr-xpython/hello-world31
-rw-r--r--python/java_failing_0-8.txt2
-rw-r--r--python/java_failing_0-9.txt18
-rw-r--r--python/mllib/__init__.py30
-rw-r--r--python/mllib/dom.py15
-rw-r--r--python/models/fedsim/__init__.py19
-rw-r--r--python/models/fedsim/fedsim.py434
-rw-r--r--python/models/fedsim/testBig.py88
-rw-r--r--python/models/fedsim/testRing.py48
-rw-r--r--python/models/fedsim/testStar.py65
-rw-r--r--python/models/fedsim/testStarAdd.py56
-rwxr-xr-xpython/pal2py274
-rwxr-xr-xpython/perftest95
-rwxr-xr-xpython/preppy67
-rw-r--r--python/qmf/__init__.py18
-rw-r--r--python/qmf/console.py1970
-rwxr-xr-xpython/qpid-python-test575
-rw-r--r--python/qpid/address.py161
-rw-r--r--python/qpid/assembler.py118
-rw-r--r--python/qpid/brokertest.py480
-rw-r--r--python/qpid/client.py7
-rw-r--r--python/qpid/codec010.py255
-rw-r--r--python/qpid/compat.py94
-rw-r--r--python/qpid/concurrency.py100
-rw-r--r--python/qpid/connection.py96
-rw-r--r--python/qpid/connection08.py21
-rw-r--r--python/qpid/datatypes.py107
-rw-r--r--python/qpid/debug.py55
-rw-r--r--python/qpid/delegates.py128
-rw-r--r--python/qpid/disp.py171
-rw-r--r--python/qpid/driver.py859
-rw-r--r--python/qpid/exceptions.py1
-rw-r--r--python/qpid/framer.py107
-rw-r--r--python/qpid/framing.py310
-rw-r--r--python/qpid/generator.py56
-rw-r--r--python/qpid/harness.py20
-rw-r--r--python/qpid/invoker.py48
-rw-r--r--python/qpid/lexer.py112
-rw-r--r--python/qpid/management.py300
-rw-r--r--python/qpid/managementdata.py170
-rw-r--r--python/qpid/message.py1
-rw-r--r--python/qpid/messaging.py822
-rw-r--r--python/qpid/mimetype.py106
-rw-r--r--python/qpid/ops.py280
-rw-r--r--python/qpid/parser.py68
-rw-r--r--python/qpid/peer.py12
-rw-r--r--python/qpid/queue.py4
-rw-r--r--python/qpid/selector.py139
-rw-r--r--python/qpid/session.py227
-rw-r--r--python/qpid/spec.py6
-rw-r--r--python/qpid/spec010.py691
-rw-r--r--python/qpid/testlib.py300
-rw-r--r--python/qpid/tests/__init__.py28
-rw-r--r--python/qpid/tests/address.py199
-rw-r--r--python/qpid/tests/framing.py289
-rw-r--r--python/qpid/tests/messaging.py929
-rw-r--r--python/qpid/tests/mimetype.py56
-rw-r--r--python/qpid/tests/parser.py37
-rw-r--r--python/qpid/util.py70
-rw-r--r--python/qpid_config.py6
-rwxr-xr-xpython/rule2test108
-rwxr-xr-xpython/run-tests35
-rwxr-xr-xpython/server18
-rwxr-xr-xpython/server01018
-rw-r--r--python/setup.py4
-rw-r--r--python/tests/__init__.py10
-rw-r--r--python/tests/assembler.py77
-rw-r--r--python/tests/codec.py14
-rw-r--r--python/tests/codec010.py79
-rw-r--r--python/tests/connection.py44
-rw-r--r--python/tests/datatypes.py95
-rw-r--r--python/tests/framer.py94
-rw-r--r--python/tests/spec.py56
-rw-r--r--python/tests/spec010.py70
-rw-r--r--python/tests_0-10/__init__.py1
-rw-r--r--python/tests_0-10/alternate_exchange.py68
-rw-r--r--python/tests_0-10/broker.py16
-rw-r--r--python/tests_0-10/dtx.py6
-rw-r--r--python/tests_0-10/example.py4
-rw-r--r--python/tests_0-10/exchange.py47
-rw-r--r--python/tests_0-10/management.py339
-rw-r--r--python/tests_0-10/message.py171
-rw-r--r--python/tests_0-10/persistence.py5
-rw-r--r--python/tests_0-10/query.py16
-rw-r--r--python/tests_0-10/queue.py34
-rw-r--r--python/tests_0-10/tx.py10
-rw-r--r--python/tests_0-8/__init__.py2
-rw-r--r--python/tests_0-8/basic.py7
-rw-r--r--python/tests_0-8/broker.py24
-rw-r--r--python/tests_0-8/example.py2
-rw-r--r--python/tests_0-8/queue.py2
-rw-r--r--python/tests_0-8/testlib.py2
-rw-r--r--python/tests_0-8/tx.py2
-rw-r--r--python/tests_0-9/__init__.py2
-rw-r--r--python/tests_0-9/basic.py396
-rw-r--r--python/tests_0-9/broker.py133
-rw-r--r--python/tests_0-9/dtx.py587
-rw-r--r--python/tests_0-9/example.py94
-rw-r--r--python/tests_0-9/exchange.py327
-rw-r--r--python/tests_0-9/execution.py29
-rw-r--r--python/tests_0-9/message.py657
-rw-r--r--python/tests_0-9/query.py2
-rw-r--r--python/tests_0-9/queue.py261
-rw-r--r--python/tests_0-9/testlib.py66
-rw-r--r--python/tests_0-9/tx.py188
-rw-r--r--python/todo.txt188
-rw-r--r--review/LICENSE206
-rw-r--r--review/NOTICE8
-rwxr-xr-xreview/agenda.py23
-rwxr-xr-xreview/changeLogToWiki.py85
-rw-r--r--review/jiraRSS2wiki.xsl20
-rw-r--r--review/svnlog2wiki.xsl22
-rw-r--r--specs/LICENSE325
-rw-r--r--specs/NOTICE7
-rw-r--r--specs/amqp.0-10-qpid-errata.xml2
-rw-r--r--specs/amqp.0-9.xml35
-rw-r--r--specs/amqp.1-0-draft.dtd246
-rw-r--r--specs/amqp.1-0-draft.xml5102
-rw-r--r--specs/amqp0-9-1.stripped.xml477
-rw-r--r--specs/management-schema.xml174
-rw-r--r--specs/management-types.xml56
-rw-r--r--wcf/QpidWcf.sln79
-rw-r--r--wcf/ReadMe.txt162
-rw-r--r--wcf/samples/Channel/WCFToWCFDirect/Client/Client.cs68
-rw-r--r--wcf/samples/Channel/WCFToWCFDirect/Client/Client.csproj90
-rw-r--r--wcf/samples/Channel/WCFToWCFDirect/Client/Properties/AssemblyInfo.cs55
-rw-r--r--wcf/samples/Channel/WCFToWCFDirect/Service/Properties/AssemblyInfo.cs55
-rw-r--r--wcf/samples/Channel/WCFToWCFDirect/Service/Service.cs83
-rw-r--r--wcf/samples/Channel/WCFToWCFDirect/Service/Service.csproj85
-rw-r--r--wcf/samples/Channel/WCFToWCFDirect/WCFToWCFDirect.sln46
-rw-r--r--wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Another_Topic_Consumer.cs67
-rw-r--r--wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Another_Topic_Consumer.csproj90
-rw-r--r--wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Properties/AssemblyInfo.cs55
-rw-r--r--wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Properties/AssemblyInfo.cs55
-rw-r--r--wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Topic_Consumer.cs85
-rw-r--r--wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Topic_Consumer.csproj84
-rw-r--r--wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Properties/AssemblyInfo.cs55
-rw-r--r--wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Topic_Producer.cs68
-rw-r--r--wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Topic_Producer.csproj90
-rw-r--r--wcf/samples/Channel/WCFToWCFPubSub/WCFToWCFPubSub.sln52
-rw-r--r--wcf/src/Apache/Qpid/AmqpTypes/AmqpBoolean.cs57
-rw-r--r--wcf/src/Apache/Qpid/AmqpTypes/AmqpInt.cs57
-rw-r--r--wcf/src/Apache/Qpid/AmqpTypes/AmqpProperties.cs292
-rw-r--r--wcf/src/Apache/Qpid/AmqpTypes/AmqpString.cs91
-rw-r--r--wcf/src/Apache/Qpid/AmqpTypes/AmqpType.cs33
-rw-r--r--wcf/src/Apache/Qpid/AmqpTypes/AmqpTypes.csproj158
-rw-r--r--wcf/src/Apache/Qpid/AmqpTypes/AmqpUbyte.cs57
-rwxr-xr-xwcf/src/Apache/Qpid/AmqpTypes/CreateNetModule.bat33
-rw-r--r--wcf/src/Apache/Qpid/AmqpTypes/Properties/AssemblyInfo.cs55
-rw-r--r--wcf/src/Apache/Qpid/AmqpTypes/PropertyName.cs35
-rw-r--r--wcf/src/Apache/Qpid/Channel/AmqpBinaryBinding.cs60
-rw-r--r--wcf/src/Apache/Qpid/Channel/AmqpBinaryBindingCollectionElement.cs29
-rw-r--r--wcf/src/Apache/Qpid/Channel/AmqpBinaryBindingConfigurationElement.cs79
-rw-r--r--wcf/src/Apache/Qpid/Channel/AmqpBinding.cs121
-rw-r--r--wcf/src/Apache/Qpid/Channel/AmqpBindingCollectionElement.cs29
-rw-r--r--wcf/src/Apache/Qpid/Channel/AmqpBindingConfigurationElement.cs269
-rw-r--r--wcf/src/Apache/Qpid/Channel/AmqpChannelFactory.cs137
-rw-r--r--wcf/src/Apache/Qpid/Channel/AmqpChannelHelpers.cs142
-rw-r--r--wcf/src/Apache/Qpid/Channel/AmqpChannelListener.cs188
-rw-r--r--wcf/src/Apache/Qpid/Channel/AmqpTransportBindingElement.cs158
-rw-r--r--wcf/src/Apache/Qpid/Channel/AmqpTransportChannel.cs595
-rw-r--r--wcf/src/Apache/Qpid/Channel/Channel.csproj105
-rw-r--r--wcf/src/Apache/Qpid/Channel/ConnectionManager.cs266
-rw-r--r--wcf/src/Apache/Qpid/Channel/Properties/AssemblyInfo.cs52
-rw-r--r--wcf/src/Apache/Qpid/Channel/RawMessage.cs374
-rw-r--r--wcf/src/Apache/Qpid/Channel/RawMessageEncoder.cs113
-rw-r--r--wcf/src/Apache/Qpid/Channel/RawMessageEncoderFactory.cs45
-rw-r--r--wcf/src/Apache/Qpid/Channel/RawMessageEncodingBindingElement.cs102
-rw-r--r--wcf/src/Apache/Qpid/Channel/RawXmlReader.cs353
-rw-r--r--wcf/src/Apache/Qpid/Channel/RawXmlWriter.cs221
-rw-r--r--wcf/src/Apache/Qpid/DtcPlugin/DtcPlugin.cpp664
-rw-r--r--wcf/src/Apache/Qpid/Interop/AmqpConnection.cpp179
-rw-r--r--wcf/src/Apache/Qpid/Interop/AmqpConnection.h95
-rw-r--r--wcf/src/Apache/Qpid/Interop/AmqpMessage.cpp76
-rw-r--r--wcf/src/Apache/Qpid/Interop/AmqpMessage.h61
-rw-r--r--wcf/src/Apache/Qpid/Interop/AmqpSession.cpp612
-rw-r--r--wcf/src/Apache/Qpid/Interop/AmqpSession.h107
-rw-r--r--wcf/src/Apache/Qpid/Interop/AssemblyInfo.cpp57
-rw-r--r--wcf/src/Apache/Qpid/Interop/CompletionWaiter.cpp145
-rw-r--r--wcf/src/Apache/Qpid/Interop/CompletionWaiter.h98
-rw-r--r--wcf/src/Apache/Qpid/Interop/DtxResourceManager.cpp285
-rw-r--r--wcf/src/Apache/Qpid/Interop/DtxResourceManager.h76
-rw-r--r--wcf/src/Apache/Qpid/Interop/InputLink.cpp853
-rw-r--r--wcf/src/Apache/Qpid/Interop/InputLink.h102
-rw-r--r--wcf/src/Apache/Qpid/Interop/Interop.vcproj493
-rw-r--r--wcf/src/Apache/Qpid/Interop/MessageBodyStream.cpp337
-rw-r--r--wcf/src/Apache/Qpid/Interop/MessageBodyStream.h131
-rw-r--r--wcf/src/Apache/Qpid/Interop/MessageWaiter.cpp251
-rw-r--r--wcf/src/Apache/Qpid/Interop/MessageWaiter.h125
-rw-r--r--wcf/src/Apache/Qpid/Interop/OutputLink.cpp251
-rw-r--r--wcf/src/Apache/Qpid/Interop/OutputLink.h64
-rw-r--r--wcf/src/Apache/Qpid/Interop/QpidException.h37
-rw-r--r--wcf/src/Apache/Qpid/Interop/QpidMarshal.h53
-rw-r--r--wcf/src/Apache/Qpid/Interop/XaTransaction.cpp525
-rw-r--r--wcf/src/Apache/Qpid/Interop/XaTransaction.h96
-rw-r--r--wcf/src/wcfnet.snkbin0 -> 596 bytes
-rw-r--r--wcf/test/Apache/Qpid/Test/Channel/Functional/AsyncTest.cs190
-rw-r--r--wcf/test/Apache/Qpid/Test/Channel/Functional/CustomAmqpBindingTest.cs77
-rw-r--r--wcf/test/Apache/Qpid/Test/Channel/Functional/FunctionalTests.csproj112
-rw-r--r--wcf/test/Apache/Qpid/Test/Channel/Functional/IGenericObjectService.cs30
-rw-r--r--wcf/test/Apache/Qpid/Test/Channel/Functional/IInteropService.cs31
-rw-r--r--wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService1.cs34
-rw-r--r--wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService2.cs34
-rw-r--r--wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService3.cs33
-rw-r--r--wcf/test/Apache/Qpid/Test/Channel/Functional/MessageBodyTest.cs135
-rw-r--r--wcf/test/Apache/Qpid/Test/Channel/Functional/MessageClient.cs101
-rw-r--r--wcf/test/Apache/Qpid/Test/Channel/Functional/MessageProperties.txt22
-rw-r--r--wcf/test/Apache/Qpid/Test/Channel/Functional/MessagePropertiesTest.cs131
-rw-r--r--wcf/test/Apache/Qpid/Test/Channel/Functional/MessageService.cs158
-rw-r--r--wcf/test/Apache/Qpid/Test/Channel/Functional/MultipleEndpointsSameQueueTest.cs83
-rw-r--r--wcf/test/Apache/Qpid/Test/Channel/Functional/Properties/AssemblyInfo.cs55
-rwxr-xr-xwcf/test/Apache/Qpid/Test/Channel/Functional/RunTests.bat34
-rw-r--r--wcf/test/Apache/Qpid/Test/Channel/Functional/Util.cs74
-rw-r--r--wcf/test/Apache/Qpid/Test/Channel/WcfPerftest/RawBodyUtility.cs161
-rw-r--r--wcf/test/Apache/Qpid/Test/Channel/WcfPerftest/WcfPerftest.cs661
-rw-r--r--wcf/test/Apache/Qpid/Test/Channel/WcfPerftest/WcfPerftest.csproj83
-rw-r--r--wcf/tools/QCreate/QCreate.cpp65
-rw-r--r--wcf/tools/QCreate/QCreate.sln40
-rw-r--r--wcf/tools/QCreate/QCreate.vcproj232
-rw-r--r--wcf/tools/QCreate/ReadMe.txt52
-rw-r--r--wcf/tools/QCreate/stdafx.cpp27
-rw-r--r--wcf/tools/QCreate/stdafx.h34
-rw-r--r--wcf/tools/QCreate/targetver.h32
3759 files changed, 384174 insertions, 93843 deletions
diff --git a/KEYS b/KEYS
new file mode 100644
index 0000000000..81a2c8d842
--- /dev/null
+++ b/KEYS
@@ -0,0 +1,255 @@
+pub 2048R/18806464 2006-11-14
+uid Rajith Attapattu <rajith@apache.org>
+sig 3 18806464 2006-11-14 Rajith Attapattu <rajith@apache.org>
+uid Rajith Attapattu <rajith77@gmail.com>
+sig 3 18806464 2006-11-14 Rajith Attapattu <rajith@apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.2.1 (GNU/Linux)
+
+mQELBEVaPcABCAC+iLSVxk/TZ2i5Kq4KhdYdBdpXizwRsKdCq9m9DwD20yke0rZL
+067ka5z4gA2prOUUCJ51G/CFhDgngiK0awnhcMgdNZzMQoOIJC044qgRLeg12IvI
+bzdtzK+DknPW3MC5QbmuJiozBPokyhyHR/C+889f2lR8OTjSGagLwjtHf0oEuEn4
+RdTBWWzNZclKe4J6UIbi3VG5kgUmThCm12TmtABmJmXpeNl3wpyYNPxZkU1huKNl
+Pi0Buu1SroWoIlwR8n2DNvDIU8PvzmtrfZoDBMopC1a6lBiZX9tKwZLUDb28AgaB
+XelJ+L+nkaoLjbNgNxGRMT7N99hWXsOcWlUVAAYptCVSYWppdGggQXR0YXBhdHR1
+IDxyYWppdGg3N0BnbWFpbC5jb20+iQE2BBMBAgAgBQJFWj3AAhsDBgsJCAcDAgQV
+AggDBBYCAwECHgECF4AACgkQdt2xaBiAZGS/AQf/fCrR7bLqAhiI9ojuOgTfwzRv
+9Hf3FcNdRCnVzmRFzE4WGHSG7R92xLL8avtiPEdC7p80d3+bf+QKGSJ/Ym4a0JqE
+KeX08brWOtIfQQK7wd7UgCJ3ufWcbQgnHzhgc7oY00FZAmQfv8TF8Uxqpe6dKXep
+4S3RN1c9ygg643ey7u85knAk+rs1OevZ+xl/IsLN6rSnQ1B8uIJUCct8+5YuGxd7
+VHCAgDEri0zf7+CMWxVpOJgcegn9Iy8rfmif8BUs0620xvNRha03of2UQZau0WzB
+MIMkSgOUhSBdsYNYe8TU9SfJGXabB4R6xDimMDbOXs75ypQMoPiEsf9urx7T6rQk
+UmFqaXRoIEF0dGFwYXR0dSA8cmFqaXRoQGFwYWNoZS5vcmc+iQE2BBMBAgAgBQJF
+Wj7qAhsDBgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQdt2xaBiAZGQEYQf/SocY
+SONVEePlZtFlLmsebZLZ8sn+HZBPepcJf81eK7YdXcca7QSeY3Q6vwshbfZsUOJZ
+fu+6gaD1MnPtBLF4RWjLBW1OOmxLJPtv5bNifjciuhuvRgBA7y3xWenfNgV4FeKk
+qX8ArRYJQVgy7X5Lv3ccbXcaNq6ajT2xDi0krMkn0TtU1vdkDSK56PRzAwWxA/X+
+4MKQZF/6964or2rz91iX2OnylEj38q+F7/dOaasD/EZpjAh8nipqVBVL3Rcy2gFy
+7EkTao4tOSo1JVrHW7lgfEBxKVSrgHyhnSxx3Z773edp2qnjZPAcv0qiEawszhkI
+vIuNSo3oTbrOW9w2tA==
+=FCqB
+-----END PGP PUBLIC KEY BLOCK-----
+pub 1024D/8004C922 2008-04-01 [expires: 2018-03-30]
+uid Aidan Skinner <aidan@skinner.me.uk>
+sig 3 8004C922 2008-04-01 Aidan Skinner <aidan@skinner.me.uk>
+sub 2048g/A1375A8A 2008-04-01 [expires: 2018-03-30]
+sig 8004C922 2008-04-01 Aidan Skinner <aidan@skinner.me.uk>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.6 (GNU/Linux)
+
+mQGiBEfypHkRBAC0tGJGaJnreJa5eF4KWLxEuPm6zuTrw7V8FRh4Wx7SlSE8XH0O
+08BMAUHWsVDaiAUwGIcnbADpZjPV70ChbRVgasA3p0d5Bf8koRd5clb9cb/+ayg9
+r6sybOEuKLEHL8Va/TCea4ANWWzn2EPUjM6CntipSSTsM4idXo9HtFr8AwCgncYV
+iHncPMTpCc73mbmhpNJrQCsEAJpeZn8Eqy/WvOIxUfsRwM9DI54eu5oEyw1PyDoj
+0Wks5OroPprOaC8wIwI/WWjmNZnGvYsq6ZwEs3EhM5PKRNkOuiu5JwRRDgkaHQaf
+xoxoY6Tn74DT19qGDngf76jLgMCO7/Amqe90rlJNXGwkGHdsA33ItRYcjebtWVIQ
+QgXEA/49akjY/tc4XGsj+QiwhPEYX0/BSdo9CkaeuEpeTDLY7/guzxTeUGALorTW
+PYDH5ie8XZqwyEsz6yFDMk3hoNsrX0Y+gH/mpQVqox4dXCCWPF7bDvNZ/W7uJ5dS
+dwYhHjZ0hvDDhW3VEFlQVEllrBYKQDVNPhZeOcgyLCifsdJXWLQjQWlkYW4gU2tp
+bm5lciA8YWlkYW5Ac2tpbm5lci5tZS51az6IZgQTEQIAJgUCR/KkeQIbAwUJEswD
+AAYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEG+eB3yABMkiQLQAn3NFZrGrzW8W
+1s8YnrAAxJ6xWFfFAJ9FkR159MVTHaJGAIzn0Iq9eLDUqrkCDQRH8qSPEAgA22Cf
+Xspnd5mqQD6FfWUbZAO6AQ0ehwprA/q3PqdAAtQXbJYRzmuIIwrb50Md7FEwCIWt
+FS0wtbSfPTtDE+C4P93r5K87U0Xg/o4MundjoPjeCGNsTYicpewdlS2WcdWl2BJI
++G5yPLhq2/vTI8Sg2sCpktunEFw/g/BzsigbJhsSC63NV8LyHBhbBELifFySwWh/
+ZzPCpXbdxzUdwwi7P57+n/DsmfjbXe0okr2QQL4EtDapqvcwnSlz9c4hNw9ku/m9
+YMiQMKRSmtG/ymH7u8F1CZRurvOaaFFbaoWhSZF7nnUH6H4z5HY+aNbufXa0Ffpb
+kTZqLD6amvrTr6NIbwADBQf+Pn2PkGHhSrF1CWQBDNJC0n/vqnc48QxcGoN0Lu02
+Rj0/UNwVKRFy6VGLBEfyxR08ZWi2EkvlYm+VGyv+wQlfAhwyDBHAEVE+j3lWq90+
+B1Pnf5j5p1vRfKCkAWFddILJUoh8fQKUinZdoAWZf3Qn10HoIkAoYw+wo7xIvwch
+/zIpq45n24W/iDcKAggJ3fl6gO7+Hkttig3nbcaQ0xDi/XwkBP4cUqnvwka2E3Bu
+5KiFKc8cdy4mtYrqiDDZ0EZLr7Hx/3uy8kaIzdsep/g0xKOka6Xs10XG3Sg8vDmv
+OEhlDHlTkVF8WpxsabDOselYSu6kURiLKkgHvrUe4OM+SohPBBgRAgAPBQJH8qSP
+AhsMBQkSzAMAAAoJEG+eB3yABMkih7YAoIwSenHROUBAj/ZU9qttReAoUPeLAKCT
+9JRkXdhK2IGqlgc4N0sfZqdx/w==
+=wO1+
+-----END PGP PUBLIC KEY BLOCK-----
+pub 1024D/4CD790EB 2009-04-30
+uid Martin Ritchie <ritchiem@apache.org>
+sig 3 4CD790EB 2009-04-30 Martin Ritchie <ritchiem@apache.org>
+sub 4096g/E0525999 2009-04-30
+sig 4CD790EB 2009-04-30 Martin Ritchie <ritchiem@apache.org>
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.9 (Darwin)
+
+mQGiBEn5m1wRBACiYXJdzZ5DX3GJR1cF6MJOZgpFEd6JU0wxjMlflR02Yc0/9XmE
+xJvzFwWnUNx06tbmmQNSL+qUj0xfiDD4Jz1aMdwfZbVt3MxH4GXKEoOgvpQ8VB4G
+1uvJqCI+qZD/PbyhxGFviA71AiYwzUjplygTFlBBnDFD4VB7orS4XaRwzwCg/8YL
+4eeJcEM8Tp87gh3ItTvuVbsD/Rw87F7QO+rlfcJgmg/OUAxWTd+ajIDbvN+e+btj
+Ck35GmfHFnrsWnbhNdFxqO8UzDDjDiBm+YV8U4xmoe/EdgSk9iy0qYFfh5Mi/GgH
+Q1l3EYXBcksfzM6QJf+2lDH+qC6zVMzxTf32N8//yDOr1F01KPeoVAXAm7wadzFy
+LBeYBACevVLOZBjf7JNtrlA4gWe3VDY4XJAcfMQrZtsj4qwyj4Yq0TIXofdYwxaw
+4nwCVE2v8zum25doPhHe0SMxXlNKNrHV5OmhZ9eeJsSpMjDNvGmdn4nDX6s81gYM
+9asin9++aZr5LbyID/bJ2g5rOTT5Geg0jdHQUj4bl4UXlzGKXLQkTWFydGluIFJp
+dGNoaWUgPHJpdGNoaWVtQGFwYWNoZS5vcmc+iGAEExECACAFAkn5m1wCGwMGCwkI
+BwMCBBUCCAMEFgIDAQIeAQIXgAAKCRC7Q8SvTNeQ69g9AKDt+JucK9iQC13/eGZo
+VHC46iEMawCg33pDiPHFispbT9YQ/uLfRjN5zbm5BA0ESfmbXBAQAPkC3/r2+9BS
+Ix+0qap/vYWXO8LeBIZWWuFU0vOlKl8AgmfFQ6d5cYqKF26Dz1GEZNuhkQ8q9WKy
+X4oJFKKZMTtKWvJQRawPi9l+yoBDbiHlO6PByblxuXzfcIpOxvNr56oJa2/SY2JD
+p3Bnkt6qPeI5uylxH1UxT4kG0DozbIp+13gpiO3vgLu2MMAPnDZ2dnJ2SsUpNg6H
+hjj8j4wDn6WEdb5YsBRDju+6fGxU/Isrx9S9lEUOc6EvhAzMfHTg8NGktQ2Y+BmJ
+byGjP+iH+M/zg0gF/V4yzT9UGtm3xwhaFCxcRPIpYuN9Boz2YqhGt0MRWSYu+BZe
+BYGSmvog1xYX7lmyPfprwj6MEOQKDnfnUduciRF9WEjmnR09mapwqofxsNqWxg/L
+/glUH6uo7vAmRVi9ObjVk/tWHtk+jqKz58vj2sk2MAX8/sfST+2ICxA2UlEwtKxw
+vrlfTowJdlLq3SVtkyWkqXszScC9kg7B3uZNYGEL3P9/kO4SqRfHbh0aEFQ+hnGA
+dFdbUE8OOFv3rYvt8QDKZvu3YvgketVWXZUTR3ULWXC/QDUw8NP6wYBZn27aDVYl
+5zocuZRyN4bjIyEIw6fWiW/fqU3IvQSPaCdaFZz71LGggnCAFCnd6IZZp4u/tyws
+YIVMQmo8bmz0vzbMrq/I1BHQZ+5KLVk/AAMFD/9eHRI8fQqov0mbIX+H+DA+jnQ9
+kCRDWx9t85gzVz+yXEAGfErP8nqgkToowNQ9icdCj/o2zYhw27dLDgvLMOFGRydd
+47f9fkZMZZ0WRuH15UHCNwEisGyw2HPi1LPUOMVnBMGFf2lLWM6kGN1zqVeHZ++a
+RU2T5lvscFFx0ZTb+Lpaa64s4Y+uffylsSepL+JthPjOt+6+zoYaQz9apCOE7ZoJ
+yVb9esgZ19ljTOzsiFNWPwzppTNyIP2UxdgASP9PTnaKGRnM5K1TL1M6IFAnP20D
+4a3BDSkQfivF9aeiYaiowG1y9pR6f4E5BnhxK/UMe+HW8kgRkb/nsXITGam6NI+Q
+ZLNLFzbWGxPL/HPhSOwa6BleJEFGE3oJsneMMuWvZZ7aVC/TOsEORXkNEc1aswD/
+FyyRcmONmepNbgCQG5cxa9arWAwRc9lYK8KB9Bcq643leEwbfZf7nyefBifAWoC1
+cvn1Db4yij2xe2FLrd8SLCpshX8UUkE8yRvUsZntC1PIChe6ag601DABXWFnnARD
+wxSxAVNyjpIahh8rV6g9tO7v4PPqqRTbtgTqK3N9/vHiqaI6PsPVhtK5GixKNiPK
+/4g4lOwIrLK3C2AFQ1rzReGg2urOikgw+VldjA4Ml4C3hz6wESnmnR9EhTU7/Bqo
+4raMsQScmFbiN1khgIhJBBgRAgAJBQJJ+ZtcAhsMAAoJELtDxK9M15Dr1NEAoJXs
+EXBsSGuoaUoxr1UtL/pIVL8lAKCEJPjkA3w6sQ8zCN/EH0DNqsM3ig==
+=2ZcN
+-----END PGP PUBLIC KEY BLOCK-----
+pub 1024D/F947EB65 2008-11-15
+ Key fingerprint = 6248 903F C80E C609 4F9E 7CC7 EE47 2841 F947 EB65
+uid Rafael H. Schloming (CODE SIGNING KEY) <rhs@apache.org>
+sig 3 F947EB65 2008-11-15 Rafael H. Schloming (CODE SIGNING KEY) <rhs@apache.org>
+sub 4096g/079367FE 2008-11-15
+sig F947EB65 2008-11-15 Rafael H. Schloming (CODE SIGNING KEY) <rhs@apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.7 (GNU/Linux)
+
+mQGiBEkeOBMRBAC++lIdguyJ+qXv/TCPuYIfAkfvwrzSush6iOT8vdJIj4YS4CHM
+qsrcU+ujIQMQx/kG3h/baYlkKKrMXVE2sc1WkzwkR4KXDe8NfDZVSyxVafq1JOHe
+kW0VYpaL4F6UIXumRI5B+LBoBF9LpcolvgbLA3X5z5mCw+cgYWpE9vghIwCgkE8c
+acp6KRxfBn+puvJEOhyY7sED/RxImMlW3ACp6MqCigKW182mjBQGOivRNeZpaOWn
+Z0b1rWNO64DAsNALTQqsoJbddWwi35bHV9YhA8i1d0OkSowS83m5M6j1i/1A+yny
+Vp3XB/Oc+LLGqNYsRcI3t1P/DtoDDi+qmFKBvNccsTIbrfXrNSH9KaHDoHF8He0G
+NcuiA/9c2Yx81qrAa3nY2BaEUU3EB6nPtD2rZXOR3HL0C6p4LLZLvbxtZs5AKj1f
+loN9cipJWBZozd4IHrhDAOvfwE58VOZXJ2zrp9WlZ2fLtMXa9a/IWwMsiupOYh8G
+mqKoqdEKqDGTl1Now2GlzTAXrha+p8r6TPBc+dT0iwKMWSu8z7Q3UmFmYWVsIEgu
+IFNjaGxvbWluZyAoQ09ERSBTSUdOSU5HIEtFWSkgPHJoc0BhcGFjaGUub3JnPohg
+BBMRAgAgBQJJHjgTAhsDBgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQ7kcoQflH
+62WtIQCfRHdJlaXrdPjCKVg/EcWGmn1JP68An3Oj64ygDeY1ahNG5F4hNXS4I1dl
+uQQNBEkeOBMQEADj1WCB8ej2gboO96tZL3hWAoVt2JxzjH94I7xnv6fCcYLc8k1w
+KawrCOnDlCzqSxXePoMwCkUIbFWMOXO7/GFFl/I75Tna+Sb/6BRqS9C2yJZImuHC
+i4wC7ZXJSKoxHycAkZjhChl57o/EM3Eth2nBq8ZJ05nfU4IpRDXRLBd9CgQbyNs4
+rqYnY4hfwKIeUK6gijj+YaqAMTsu31xRwIjAwh+FJJxX0YZZbE3D3hUdtfUW925o
+KIcYUtQRgp9dPllFBPscCXfvYix7o03Wxd3MQdfjLugSL8bU8ANdzxc74ePTV0p3
+bL8KsG62YguNA3n6fXHZQagNxyhCGa51R12saOmj7tKTCX9aKhs4tq+bQAfw/49G
+NsRGJEtvNlWzWr3EhNHoKdVSpvVC5uj87+RUEKrupeZX9u0D3Sm7pS2v2AxxlldH
+sW2eOCy23O6XTdGnbG9skKEAuszHXN2NZWJBEVoLYCXP7gxuA2KWOMNcxerfrhR9
+dyOBQcaelHKC1roBgVuIg3rlH1CKv6KINWRsRWkFiCrPE/RXCcdTuaiE9Ss3bdAp
+7B7RBA1xvCr1Lj4ICHCfo4JtymQOSQRkqq3reoBk2IOXvdTkZ3B3tbWtASM2H5Ww
+7kCHZZ1OT9saBPNXHaV/vx9QGRjAb72AWwYBqNazhVSVDyfeQuf0tkEV6wADBQ/9
+ExGBMgxTZGvf2LzmDqu+dItGtXG3EIi4Lh91Biyx8S21p7KtwY7HTCx18JneoRlJ
+HLLNrtF3Rp7gVDuxEJN5F9q7dUlRnFAz0Z8eXf8fSQCUvjmuP2V/iHPyfHhHPNm+
+KcjLQP5H3WfIYsC7sEFufkvQFdyccQnm66V33NlBrTEfJE2HFjCdAh4nsEkpjdxZ
+m774c2rWGX8IhzfwmqJj09P9SPjY5l/I+JOLeU0PSdru9Gon+z07GdRTCIRdQsXR
+uNYXbRGBdYmV/QdlP08B8NRQnNjusNVEawJQo84aZlut1LgX0k9bL8s+1Sepr04A
+yb+fJ7reMoxvkTyG6riIYTXr/OpVSqCNO0h477E/myCftGzn30OGzTEgxaCWSYLE
+2jWK/kqLtUcthrwYf4Ksmio083ZlNkNBmlJUYHMr8djCCL2xl0V/miJRnu/3/z7O
+QzMUrOqfMX2xran5x4B75GzvTwYJsEyixHcq6vI19KWCG5KsksFwaFBQ3kvyNc/0
+Oar1FnK597ynPadwGISEzK1jSRZp0cIJKUlrwsm9crS+rWp8Z1gHflhEPVHw7Lp5
+BFcqC3gxzxJBBgnckNZzP8IEiTykz0E0F2qsqLstEfsIERQbqXU2VhEO3UDKKuEX
+34hJx+wJxaGsFPeWHwVYD4fOdQo6W1oyFG8C3JQvJHGISQQYEQIACQUCSR44EwIb
+DAAKCRDuRyhB+UfrZRj/AKCF05jpImxWnTE3NFcKOQs80r1wLQCfaYGsG9UW0OyG
+uzHMwWjy3fI5vO8=
+=7jSO
+-----END PGP PUBLIC KEY BLOCK-----
+pub 1024D/F9F488C8 6/1/2009 Steve Huston <shuston@riverace.com>
+ Primary key fingerprint: BDCE 77FF 4951 C559 97DA D55A E33C 8BB4 F9F4 88C8
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.9 (MingW32)
+
+mQGiBEokNtsRBAC/abmZz/J7Xb+00cONQyDS7H5+jq09h9f8rkahReqX+QP0i9F6
+5nY5nULDuOpBcgYCRmrnHcSk+pBWeKYal+kpKwRc6vSXy5AXE6iePHXXpr8LSSkl
+DoxQkNRw52FVh2oA1Tb6lIv1diNuK1mJg+KT5UA+jbglhZbgQ5L7YRweewCg2qZD
+6PYVb4HkijgPHKUj9BpWvQcD+we/mfi6PcU6hzCjna3n8DPFXfdWvmIjtR9cZnbx
+VO9CALrQLKbdTwNd6bsDHxiFQracBJmvoiGZmaFJLhI9c0okee8FzwjTh7Y5SPWn
+rllq3PtXjZ4SRMz4Bj5AYOjX44aaialwtS/w+JQdihAPpsL3nDM6ttOrHVtMdaN9
+ThxkA/9yhogLjeeKhdukaUGDtOdkqm+vIbiArCGHUWhb0mDzQRsStqizRTrCgl4q
+EYI2OdE62Zj5sDAXBPI/wuSxcgr4zqSPvV+lQZW6gdp9bKdZglYcHcYHrdsg2CwZ
+Cx5IM2/+Jt6txOf478GtPrzIgLqy709D8nb8/5V+QgjEtSA63LQjU3RldmUgSHVz
+dG9uIDxzaHVzdG9uQHJpdmVyYWNlLmNvbT6IYAQTEQIAIAUCSiQ22wIbAwYLCQgH
+AwIEFQIIAwQWAgMBAh4BAheAAAoJEOM8i7T59IjIKvEAn30xICmorA9Z8EzOgOFf
+3ikP4mqQAKCxL51xoaL+qFcidVWmwvCKlzjUjrkCDQRKJDbbEAgA6FvUZdm9LBME
+tC49xtgJSE4GkaOgz0W0l5otMWMzy3NPW9PJtKopZWJ2eJvlHoXcGJL27nVGaOFJ
+8ixYPgkAFQ7JX1IDAQQMDXRro/cMsj6usmNbqMvrEETEiL9rP4iH8qwjOSKiHpIG
+sQy4AwmYkJg2zBxAIrrJzLyWicz75yO/PT81CX6ar6CGl1H5JWGZwerjLhc67gNu
+AyXKEVQpKk/T78uFD/HGNd6C9vHjb5LbuNAlRISwgoHAyvayvITjZZtyrr5cWVPL
+mT05FoweGAjJ/AjKfIH4lTlzE+ElC1WEaPwinzo22bQIQPxS10G9DVqm7h36VGH1
+NHa/EME56wADBQgAorINiaUPnCUPvgvQzmTgcDcCDvtPuxl8OzYT30QQSQwOLS1y
+rvu4DLW/DH5s0yIgzyX1PGhGSELU07qgj05W906EBt0D5KNiUbKg2lsD0Nec+Kzq
+jmej7SbZOJGIwNJe+U8s5iHvvP7Ak4YO0Q6hGtsmhC3UO5wBF8XjEbWCAJpjYbt3
+cyPyyArzW2X3IpICsuzdtkzQttb6BJy+ZHJLMHTN9/J3+naQrqvjiFBJY9jcUx5t
+XxWrfhW0/kjphLvcNm3RBRW46UDMzl2DA74kt/2si3dS7RikEcsX0wQ8pjp47bmw
+TpsjEqzUHv1bU56V+FJWi9GdRLsJaapq9dDV2ohJBBgRAgAJBQJKJDbbAhsMAAoJ
+EOM8i7T59IjISAAAoJwqwTBx2NOi5+CKBZxKqxSkHVM7AJ9+oJXoulLDoMhvqVIo
+e8ukbGoaqQ==
+=rn3+
+-----END PGP PUBLIC KEY BLOCK-----
+pub 4096R/997584D5 2009-10-19
+ Key fingerprint = 36BE D3F6 694B 1C93 FA37 EDD8 C5CC D011 9975 84D5
+uid Andrew Stitcher (CODE SIGNING KEY) <astitcher@apache.org>
+sub 4096R/C398A6CE 2009-10-19
+
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v2.0.12 (GNU/Linux)
+
+mQINBErbxwUBEADIcbsMgKbiX55qhpeHsdnajRp3jMMZOGiRfs+/Ny1Q9fmXykS9
+I+CThrGk0WAj+2eoVpyDHda1AQH6G2+xln4/l3h3DlqOu4Wk1JloU9CSth83D7EZ
+sB7M4yEdHe6Rdcbrzw62Hroet+v01n0hH3FujR1GeXCgzmM8XYGWFLS6Od7USThk
+A3O4QFgUEXALKDe9I45Nayq48f6iqoXCKSv3ikp0KfoK7Kr9lqFE3GMU4kjeyh0y
+Ma0ejcf+6K2eljhhItgdnNHqY7ztegnQ6idKLneJD4JD1obvVFu9ubOlGnJzXzHW
+7RTg5vSLDFOBmah6vhd19zhXRJgvkHt3IV4Uv3+OYrwjUVQI5/3pVFKdvyY1Wyt3
+wbo3KMCbhiF9I5LMcAeq+28KVavtH2vCxG5gvkcKD8s6x3H7MUxf+vpPWkm00kWj
+A1LD6ae1B2FOrEpqLGohS4CaWdbj6YAZKGa/PPvJQJdqD8fWKonCI4J10/jmph2j
+OemdDHX8mQuOUUo8NbUJMc3m4am5GgtRjGXpZ4izmJJHJK7CjTvIIIpsAVT+odr4
+JWewcB6UjFGrl9LtKCxv26O//iCXAH9T7WYMCw3uI00sPtXO1rb4uV8Cws+qkSKO
+daygWgJgNrcbT9lVnYhe3j9XPl0pEgCqvv3xx0GaK1009t7FYIEMjdo+bQARAQAB
+tDlBbmRyZXcgU3RpdGNoZXIgKENPREUgU0lHTklORyBLRVkpIDxhc3RpdGNoZXJA
+YXBhY2hlLm9yZz6JAjcEEwEKACEFAkrbxwUCGwMFCwkIBwMFFQoJCAsFFgIDAQAC
+HgECF4AACgkQxczQEZl1hNWRCQ//acKO4ffXdh7c5m40aBQVmix7EGirNvK4ZlPU
+IYVUZpR23wWLaAaQEvpnxgOBNiC/ZiBr6mPrtbI/TYfx1rQS8fc5lye+333jJkWz
+hbuuFUl8Y5AbaXrqwIHyFCa+O24k1WsysFkw1yMN+AXkj7U52B1q8wCCklsT7hEf
+yd80ZHeRDzfMG9mXfdTtXI7wcGnGqa6mWJlqt/20Qr8eqUQhqbBgR5RG6QnZdC8t
++8cx8fQafqobFUURln07QW4duNJ1q0otmpiUlEKzR9NPeBg8ZnUgqRLRMyv/hTKr
+Jl6+EaiJ7iotJxKeTf14BE2eLTLLeuKIsI8lZZMP8SPky61tuwM5gE3RSWVZIHzn
+libN4/jg40B4JnZk6EEMHS5pHB/rHEzPcYtbpH2lO7kc3DbwrVVdnQdxWIFMGwE7
+I2v8ABpsIUcdXTvWVgbw0NcIrnMVBamy6Jmjy3VtOFNNWfDrTtTW1UNCgWQJIzef
+5dM0yfbwJ/TCQ8G+I3SD8j6Ge4TDqYSS70hqYEtbK5MpKoDErC7J7temQ7lBKMmB
+116fpS47t6Do7lFGlP7WNeitvfW8GiY/Fu1lRpTX4K6PFrj7qAPaYHhTeHh35e6Y
+F6AQq3E8lZ7i6HthAmsHtGHm1LIPDhme3kz0ThDUDrrPaoLNPwyHyz6Vlmem//xv
+lDt2EI+ISQQQEQIACQUCSvDjLwIHAAAKCRC1GSdFt51FAjS4AKCosMPRb4m30u6t
+3V2xxKg1pkKlwwCdHIIu0rGdgkbJM9yjtnAPeLj/pRGIRgQQEQIABgUCSvNW5gAK
+CRDuRyhB+UfrZd/JAJ44ox91HHG5qHrL9cu1uECUg3ubGwCbBMWagmRmoGHEQNWe
+Ue2SiDO0F2C5Ag0EStvHBQEQALF+N3d6tCg9ThY6FK0IUEN++g1jgjtNrO6a1Xt5
+WPvA0fWjLw9NZxKCRRrMm/6+jE8OxsdU2V3yjko/FRXKV7Dc3B4s1BGlXnnnglgW
+pQ2x1+pMI79Eq8j/H1/NNTerRpNVWdP5SNyMaK7dzoHivPzfGdHj2dWYv3LgZkWI
+rsp6Z5URkiVqIEclAioLU0J36+XW0l994WCGxWrMRR/HnIF2gv9zajnmFEL2MYnI
+RCrl29OOIqArXil31y+zHQW9+hzv7eyIvKA8mRABXu4gAfX6cDxQXQJDNiS5tatI
+/LCDks0dJw9wnuGTm8aDbwBKI0X4ntr2ZtI3Mjd6DxhTkLXHS7GEPrK0mMZ8Awpg
+zkfQTK8sPSKxxwCJem31jNTYF7w3VCkk8vaYj+q6di2mPvUqblRk2wLBybbqrZ3H
+D5IFv2UKLKHcHEqYMT33nUw1skRAFSUWLYoW7tHx5coYxzOBOGkUsI4Xe4oL1aOn
+VMjsS2jNYV/caFOkyPRH06CViiKn6+4W6rXHpkDkN2m1bvgL91umUBAy8+IvWHFc
+TTBRbtBNzptua1HUSiZRajUg3rc1aiwBQuI1IsNsUdjvGOhUcBJUZwSV6U6RdbOn
+BC6dF6PWg3LaqiqmZeQTYR/+jvVSAFb427jW7mk4Wko1bEwkzNrPWSW8aVm1rwCX
+AuiTABEBAAGJAh8EGAEKAAkFAkrbxwUCGwwACgkQxczQEZl1hNXctA/+Pykafax3
+AvT6EHanG56iOdzE/gWxv4UZh9zTYAjBf36bt1kGDIJOdUVWdGXCZpL2Inmle1U4
+HfbEZqcC/3rzslzF9uSyQFa1fxJxz2X82+UZidlPK5KqAoBW6xW0juAOkI1Z7s+d
+MGky2M8aNLq6NSSAQ4VDTd2rZmFWo+yi5l4nn7wkvkrHnVmmwY1rL7TLZbZj5ynY
+VNJyy81qQum2Jj36eMrlGf2zbGrQ5vEl8gq1xBL+6T8Imr5SbRpmWZoj2JZ14pfq
+Atn14B9yK+B0+lCJ4uzGNLkyVKVYQvjlpqqodaV0u6lxljXX3jDtCu7MSaXSUbZv
+UFpVgVqGrvxr/XldgZ8rD3WCiK69DVOi3KTqk08dAXWE5oodvZWHNdgTTIgoCb1k
+rP9GIkimeV3sC2huuGI29mjkzL86Ca+hxdlAzo1VOCFZxdHuq4AypEn+R13UT6yk
+36pRYsXTXe+ebq0fVSXt2sYALJ7hOtAqFvTS0kUjII73N9n4G9svqBldG43SwR49
+VUp3q12qmz71yz5YT3J9Y+CBMBa53lwJEx0JpOQ26e28EjXEiEHyj4Xi8IzE0A5S
+BEZXjsEqMNmpz/GzsLhRkwmxLBSiT/8kGXb6m+g/RLGH6qnLm1I6eFZSXXmr/rbn
+98DlwjCP/7B3MVcaMlPP+/s/M3jqLasRybw=
+=7tgO
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000000..5f84a6564b
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,7 @@
+Please see the individual LICENSE files for each language
+cpp/LICENSE
+dotnet/LICENSE.txt
+gentools/lib/LICENSE
+java/resources/LICENSE
+python/LICENSE.txt
+ruby/LICENSE.txt
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000000..ff65d299a9
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,8 @@
+Please see the individual NOTICE files for each language:
+
+cpp/NOTICE
+dotnet/NOTICE.txt
+gentools/lib/NOTICE
+java/resources/NOTICE
+python/NOTICE.txt
+ruby/NOTICE.txt
diff --git a/bin/LICENSE b/bin/LICENSE
new file mode 100644
index 0000000000..bc46b77047
--- /dev/null
+++ b/bin/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/bin/NOTICE b/bin/NOTICE
new file mode 100644
index 0000000000..05f39ba176
--- /dev/null
+++ b/bin/NOTICE
@@ -0,0 +1,8 @@
+// ------------------------------------------------------------------
+// NOTICE file corresponding to the section 4d of The Apache License,
+// Version 2.0, in this case for Qpid bin scripts
+// ------------------------------------------------------------------
+
+Apache Qpid
+Copyright 2006-2008 Apache Software Foundation
+
diff --git a/bin/mvn-deploy-qpid-java.sh b/bin/mvn-deploy-qpid-java.sh
new file mode 100755
index 0000000000..3c2a9fd05f
--- /dev/null
+++ b/bin/mvn-deploy-qpid-java.sh
@@ -0,0 +1,71 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
+#!/bin/sh
+
+qpid_version=$1
+repo=$2
+
+if [ -z "$qpid_version" -o -z "$repo" ]; then
+ echo "Usage: mvn-deploy-qpid-java.sh <qpid-version> <mvn-repo>"
+ exit 1
+fi
+
+set -xe
+
+
+build_dir=build/lib
+
+deploy_artifact() {
+ mvn deploy:deploy-file -DuniqueVersion=false -Durl=$repo -Dfile=${build_dir}/$1-${qpid_version}.jar -DgroupId=org.apache.qpid -DartifactId=$1 -Dversion=${qpid_version} -Dpackaging=jar
+}
+
+deploy_artifact_with_classifier() {
+ mvn deploy:deploy-file -DuniqueVersion=false -Durl=$repo -Dfile=${build_dir}/$1-$2-${qpid_version}.jar -DgroupId=org.apache.qpid -DartifactId=$1 -Dclassifier=$2 -Dversion=${qpid_version} -Dpackaging=jar
+}
+
+deploy_artifact qpid-broker
+deploy_artifact_with_classifier qpid-broker-plugins tests
+deploy_artifact_with_classifier qpid-broker tests
+deploy_artifact qpid-client-example
+deploy_artifact_with_classifier qpid-client-example tests
+deploy_artifact qpid-client
+deploy_artifact_with_classifier qpid-client tests
+deploy_artifact qpid-common
+deploy_artifact_with_classifier qpid-common tests
+deploy_artifact qpid-integrationtests
+deploy_artifact_with_classifier qpid-integrationtests tests
+deploy_artifact qpid-junit-toolkit
+deploy_artifact_with_classifier qpid-junit-toolkit tests
+deploy_artifact qpid-management-eclipse-plugin
+deploy_artifact_with_classifier qpid-management-eclipse-plugin tests
+deploy_artifact qpid-perftests
+deploy_artifact_with_classifier qpid-perftests tests
+deploy_artifact qpid-systests
+deploy_artifact_with_classifier qpid-systests tests
+deploy_artifact qpid-testkit
+deploy_artifact_with_classifier qpid-testkit tests
+deploy_artifact qpid-tools
+deploy_artifact_with_classifier qpid-tools tests
+
+build_dir=build/lib/plugins
+
+deploy_artifact qpid-broker-plugins
diff --git a/bin/release.sh b/bin/release.sh
new file mode 100755
index 0000000000..b0b196fc8c
--- /dev/null
+++ b/bin/release.sh
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+# Script to pull together an Apache Release
+#
+
+usage()
+{
+ echo "Usage: release.sh <svn-path> <svn-revision> <version> [options]"
+ echo
+ echo "Options: Default : --prepare --svn --all --sign"
+ echo "--help |-h : Show this help"
+ echo "--prepare : Export specified tree from source control"
+ echo "--svn : Export from svn"
+ echo "--git : Export from git repository with svn metadata"
+ echo "--clean-all : Remove build artefacts and downloaded svn tree"
+ echo "--clean : Remove built artefacts"
+ echo "--all |-a : Generate all artefacts"
+ echo "--source|-e : Generate the source artefact"
+ echo "--cpp |-c : Generate the CPP artefacts"
+ echo "--dotnet|-d : Generate the dotnet artefacts"
+ echo "--java |-j : Generate the java artefacts"
+ echo "--ruby |-r : Generate the ruby artefacts"
+ echo "--python|-p : Generate the python artefacts"
+ echo "--wcf |-w : Generate the WCF artefacts"
+ echo "--source|-e : Generate the source artefact"
+ echo "--sign |-s : Sign generated artefacts"
+ echo "--upload|-u : Upload the artifacts directory to people.apache.org as qpid-\$VER"
+ echo
+}
+
+REPO="SVN"
+for arg in $* ; do
+ case $arg in
+ --help|-h)
+ HELP="HELP"
+ ;;
+ --prepare)
+ PREPARE="PREPARE"
+ ;;
+ --svn)
+ REPO="SVN"
+ ;;
+ --git)
+ REPO="GIT"
+ ;;
+ --clean-all)
+ CLEAN="CLEAN"
+ CLEAN_ARTIFACTS="CLEAN_ARTIFACTS"
+ ;;
+ --clean)
+ CLEAN_ARTIFACTS="CLEAN_ARTIFACTS"
+ ;;
+ --sign|-s)
+ SIGN="SIGN"
+ ;;
+ --all|-a)
+ CPP="CPP"
+ DOTNET="DOTNET"
+ JAVA="JAVA"
+ RUBY="RUBY"
+ PYTHON="PYTHON"
+ WCF="WCF"
+ SOURCE="SOURCE"
+ ;;
+ --cpp|-c)
+ CPP="CPP"
+ ;;
+ --dotnet|-d)
+ DOTNET="DOTNET"
+ ;;
+ --java|-j)
+ JAVA="JAVA"
+ ;;
+ --ruby|-r)
+ RUBY="RUBY"
+ ;;
+ --python|-p)
+ PYTHON="PYTHON"
+ ;;
+ --wcf|-w)
+ WCF="WCF"
+ ;;
+ --source|-e)
+ SOURCE="SOURCE"
+ ;;
+ --upload|-u)
+ UPLOAD="UPLOAD"
+ ;;
+ *)
+ if [ -z "$SVN" ] ; then
+ SVN=$arg
+ continue
+ fi
+
+ if [ -z "$REV" ] ; then
+ REV=$arg
+ continue
+ fi
+
+ if [ -z "$VER" ] ; then
+ VER=$arg
+ continue
+ fi
+ ;;
+ esac
+done
+
+if [ -n "${HELP}" ] ; then
+ usage
+ exit 0
+fi
+
+if [ -z "$SVN" -o -z "$REV" -o -z "$VER" ]; then
+ echo "Usage: release.sh <svn-path> <svn-revision> <version>"
+ exit 1
+fi
+
+echo SVN:$SVN
+echo REV:$REV
+echo VER:$VER
+
+# If nothing is specified then do it all
+if [ -z "${CLEAN}${PREPARE}${CPP}${DOTNET}${JAVA}${RUBY}${PYTHON}${WCF}${SOURCE}${SIGN}${UPLOAD}" ] ; then
+ PREPARE="PREPARE"
+ CPP="CPP"
+ DOTNET="DOTNET"
+ JAVA="JAVA"
+ RUBY="RUBY"
+ PYTHON="PYTHON"
+ WCF="WCF"
+ SOURCE="SOURCE"
+
+ SIGN="SIGN"
+fi
+
+set -xe
+
+if [ "CLEAN" == "$CLEAN" ] ; then
+ rm -rf qpid-${VER}
+fi
+
+if [ "CLEAN_ARTIFACTS" == "$CLEAN_ARTIFACTS" ] ; then
+ rm -rf artifacts
+fi
+
+if [ "PREPARE" == "$PREPARE" ] ; then
+ mkdir artifacts
+ case ${REPO} in
+ SVN)
+ URL=https://svn.apache.org/repos/asf/qpid/${SVN}
+ svn export -r ${REV} ${URL} qpid-${VER}
+ echo ${URL} ${REV} > artifacts/qpid-${VER}.svnversion
+ ;;
+ GIT)
+ URL=${SVN}
+ GITREV=$(GIT_DIR=${URL} git svn find-rev r${REV})
+ git archive --remote=${URL} ${GITREV} | tar xvf -
+ mv qpid qpid-${VER}
+ echo ${REV} > artifacts/qpid-${VER}.svnversion
+ ;;
+ esac
+fi
+
+if [ "SOURCE" == "$SOURCE" ] ; then
+ tar -czf artifacts/qpid-${VER}.tar.gz qpid-${VER}
+fi
+
+if [ "RUBY" == "$RUBY" ] ; then
+ tar -czf artifacts/qpid-ruby-${VER}.tar.gz qpid-${VER}/ruby qpid-${VER}/specs
+fi
+
+if [ "PYTHON" == "$PYTHON" ] ; then
+ tar -czf artifacts/qpid-python-${VER}.tar.gz qpid-${VER}/python qpid-${VER}/specs
+fi
+
+if [ "WCF" == "$WCF" ] ; then
+ zip -rq artifacts/qpid-wcf-${VER}.zip qpid-${VER}/wcf
+fi
+
+if [ "CPP" == "$CPP" ] ; then
+ pushd qpid-${VER}/cpp
+ ./bootstrap
+ ./configure
+ make dist -j2
+ popd
+
+ cp qpid-${VER}/cpp/*.tar.gz artifacts/qpid-cpp-${VER}.tar.gz
+fi
+
+if [ "JAVA" == "$JAVA" ] ; then
+ pushd qpid-${VER}/java
+ ant build release release-bin -Dsvnversion.output=${REV}
+ popd
+
+ cp qpid-${VER}/java/release/*.tar.gz artifacts/qpid-java-${VER}.tar.gz
+ cp qpid-${VER}/java/broker/release/*.tar.gz artifacts/qpid-java-broker-${VER}.tar.gz
+ cp qpid-${VER}/java/client/release/*.tar.gz artifacts/qpid-java-client-${VER}.tar.gz
+ #cp qpid-${VER}/java/client/example/release/*.tar.gz
+ cp qpid-${VER}/java/management/eclipse-plugin/release/*.tar.gz qpid-${VER}/java/management/eclipse-plugin/release/*.zip artifacts/
+ cp qpid-${VER}/java/management/client/release/*.tar.gz artifacts/qpid-management-client-${VER}.tar.gz
+fi
+
+if [ "DOTNET" == "$DOTNET" ] ; then
+ pushd qpid-${VER}/dotnet
+ cd Qpid.Common
+ ant
+ cd ..
+ ./build-nant-release mono-2.0
+
+ cd client-010/gentool
+ ant
+ cd ..
+ nant -t:mono-2.0 release-pkg
+ popd
+
+ cp qpid-${VER}/dotnet/bin/mono-2.0/release/*.zip artifacts/qpid-dotnet-0-8-${VER}.zip
+ cp qpid-${VER}/dotnet/client-010/bin/mono-2.0/debug/*.zip artifacts/qpid-dotnet-0-10-${VER}.zip
+fi
+
+if [ "SIGN" == "$SIGN" ] ; then
+ pushd artifacts
+ sha1sum *.zip *.gz *.svnversion > SHA1SUM
+ if [ ! -z $SIGNING_KEY ] ; then
+ KEYOPTION="--default-key $SIGNING_KEY"
+ fi
+ for i in `find . | egrep 'jar$|pom$|gz$|zip$|svnversion$|SHA1SUM'`; do gpg --sign --armor --detach $KEYOPTION $i; done;
+ popd
+fi
+
+if [ "UPLOAD" == "$UPLOAD" ] ; then
+ scp -r artifacts people.apache.org:qpid-${VER}
+fi
diff --git a/buildtools/LICENSE b/buildtools/LICENSE
new file mode 100644
index 0000000000..bc46b77047
--- /dev/null
+++ b/buildtools/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/buildtools/NOTICE b/buildtools/NOTICE
new file mode 100644
index 0000000000..5813a7a09a
--- /dev/null
+++ b/buildtools/NOTICE
@@ -0,0 +1,8 @@
+// ------------------------------------------------------------------
+// NOTICE file corresponding to the section 4d of The Apache License,
+// Version 2.0, in this case for Qpid buildTools
+// ------------------------------------------------------------------
+
+Apache Qpid
+Copyright 2006-2008 Apache Software Foundation
+
diff --git a/buildtools/buildCreator/build.config b/buildtools/buildCreator/build.config
new file mode 100644
index 0000000000..cb45e99a6e
--- /dev/null
+++ b/buildtools/buildCreator/build.config
@@ -0,0 +1,37 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<builder>
+ <environment>
+ <version>M4.0-beta</version>
+ </environment>
+
+ <sources>
+ <source>
+ <name>qpid</name>
+ <type>svn</type>
+ <url>https://svn.eu.apache.org/repos/asf/incubator/qpid/trunk/qpid/</url>
+ </source>
+ </sources>
+
+ <builds>
+ <include>qpid.build</include>
+ </builds>
+</builder>
diff --git a/buildtools/buildCreator/buildCreator.py b/buildtools/buildCreator/buildCreator.py
new file mode 100755
index 0000000000..4df7553dea
--- /dev/null
+++ b/buildtools/buildCreator/buildCreator.py
@@ -0,0 +1,1464 @@
+#!/usr/bin/env python
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import os
+import re
+import datetime
+import urllib
+import sys
+import string
+
+from xml.dom import minidom
+from optparse import OptionParser
+
+if map(int, string.split(string.split(sys.version)[0], ".")) < [2, 4, 0]:
+ print ("subprocess is required for this tool and is not present in versions prior to 2.4.0")
+ try:
+ import subprocess
+ except ImportError:
+ print ("subprocess module not found please install it locally or upgrade your python version")
+ sys.exit(1)
+
+import subprocess
+from subprocess import Popen
+
+TOOL_NAME="buildCreator.py"
+
+#Default Build script
+DEFAULT_BUILD="build.config"
+
+# Path locations
+DEFAULT_ROOTDIR="builder"
+SOURCE_DIR="src"
+PATCH_DIR="patch"
+BUILD_DIR="build"
+RELEASE_DIR="release"
+
+# Command Binaries
+SVN='svn'
+SVN_BIN='svn'
+HTTP='http'
+FTP='ftp'
+WGET_BIN='wget'
+FILE='file'
+CP_BIN='cp'
+PATCH_BIN='patch'
+FILE_BIN='file'
+LS_BIN='ls'
+TAR_BIN='tar'
+BZIP2_BIN='bzip2'
+UNZIP_BIN='unzip'
+ECHO_BIN='echo'
+SVNVERSION_BIN='svnversion'
+
+
+
+GZIP_DATA='gzip compressed data'
+BZIP2_DATA='bzip2 compressed data'
+ZIP_DATA='Zip archive data'
+TAR_DATA='POSIX tar archive'
+DIFF_FILE="'diff' output text"
+
+#Build Targets
+DISTCLEAN='distclean'
+CLEAN='clean'
+RETRIEVE='retrieve'
+PREPARE='prepare'
+PATCH='patch'
+SHOWBUILDS='showbuilds'
+BUILD='build'
+RELEASE='release'
+FULL='full'
+HELP='help'
+DEFAULT_TARGET=FULL
+
+# XML Elements toplevel
+BUILDER="builder"
+ENVIRONMENT="environment"
+SOURCES="sources"
+SOURCE="source"
+PATCHES="patches"
+PATCH="patch"
+BUILDS="builds"
+INCLUDE="include"
+DEPENDENCY='dependency'
+TARGETS='targets'
+SCRIPT='script'
+
+# XML Elements - Source/Patch elements
+NAME="name"
+TYPE="type"
+URL="url"
+REVISION="revision"
+ROOTDIR="root"
+VERSION="version"
+PREFIX='prefix'
+PATH='path'
+
+PATH_SEP=os.sep
+
+_source=None
+_target=DEFAULT_BUILD
+_log = True
+_verbose = False
+_debug = False
+_ignoreErrors = False
+
+_charIndex = 0
+_waitingChars = ['-', '/' , '|', '\\']
+
+def showUsage():
+ print TOOL_NAME+" [-c|--configure <config file>] [-v| --verbose] [-q|--quiet] [-i|--ignore-errors] [<build target>] [options]"
+ print "Available Targets:"
+ print " distclean [source] - Remove all or specified retrieved source"
+ print " clean [source] - Remove all or specified source build directory"
+ print " retrieve [source] - Retrieve all or specified source"
+ print " prepare [source] - Prepare all or specified source : i.e. extract archives"
+ print " patch [source] - Patch all or specified source"
+ print " showbuilds - List all builds"
+ print " build [build] - Perform the build scripts for all or specified build"
+ print " release [build] - Perform the release scripts for all or specified source"
+ print " full - Perfrom clean, retrieve, prepare, patch, build, release for all builds (DEFAULT)"
+
+def main():
+ global _log, _verbose, _debug, _rootDir, _target, _source, _baseConfiguration, _ignoreErrors
+
+ # Load the
+ parser = OptionParser()
+ parser.add_option("-c", "--config", dest="config",
+ action="store", default=DEFAULT_BUILD,
+ help="set configuration file : default = " + DEFAULT_BUILD)
+
+ parser.add_option("-v", "--verbose", dest="verbose",
+ action="store_true", default=False, help="enable verbose output")
+
+ parser.add_option("-d", "--debug", dest="debug",
+ action="store_true", default=False, help="enable debug output")
+
+ parser.add_option("-q", "--quiet", dest="quiet",
+ action="store_false", default=True, help="Enable quiet ouptut")
+
+ parser.add_option("-i", "--ignore-errors", dest="ignoreErrors",
+ action="store_true", default=False, help="Ignore errors")
+
+
+ (options, args) = parser.parse_args()
+
+ _verbose = options.verbose
+ _debug = options.debug
+ _log = options.quiet
+ _ignoreErrors = options.ignoreErrors
+
+ log("Logging Enabled")
+ verbose("Verbose Output Enabled")
+ debug("Debug Enabled")
+
+ if (len(args) > 2):
+ showUsage()
+ sys.exit(1)
+ else:
+ # NOTE : Would be good to be able to do builder.py clean build release
+ if (len(args) > 0 ):
+ # Override the default target
+ _target = checkTarget(args[0])
+ # limit the comand to just the specified source
+ if (len(args) > 1 ):
+ _source = args[1]
+ else:
+ _source = None
+ else:
+ _target = FULL
+
+
+ _baseConfiguration = loadBaseConfiguration(options.config)
+
+ debug ("Loading Environment")
+ prepareEnvironment(_baseConfiguration.getElementsByTagName(ENVIRONMENT)[0])
+
+ if _target == DISTCLEAN:
+ distclean()
+
+ if _target == CLEAN or _target == FULL:
+ clean()
+
+ if _target == RETRIEVE or _target == FULL:
+ try:
+ retrieve()
+ except KeyboardInterrupt:
+ log ("User Interrupted preparation")
+ sys.exit(0)
+
+ if _target == PREPARE or _target == FULL:
+ prepare()
+
+ if _target == PATCH or _target == FULL:
+ patch()
+
+ if _target == SHOWBUILDS:
+ showBuilds()
+
+ if _target == BUILD or _target == FULL:
+ build()
+
+ if _target == RELEASE or _target == FULL:
+ release()
+
+ log("Complete")
+
+def checkTarget(target):
+
+ if target == HELP:
+ showUsage()
+ sys.exit(0)
+
+ if target == DISTCLEAN:
+ return DISTCLEAN
+
+ if target == CLEAN:
+ return CLEAN
+
+ if target == RETRIEVE:
+ return RETRIEVE
+
+ if target == PREPARE:
+ return PREPARE
+
+ if target == PATCH:
+ return PATCH
+
+ if target == SHOWBUILDS:
+ return SHOWBUILDS
+
+ if target == BUILD:
+ return BUILD
+
+ if target == RELEASE:
+ return RELEASE
+
+ if target == FULL:
+ return FULL
+
+ warn("Target: '"+target+"' not valid")
+ showUsage()
+ sys.exit(1)
+
+
+################################################################################
+#
+# Environment
+#
+################################################################################
+def prepareEnvironment(env):
+ global _rootDir
+
+ rootdir = env.getElementsByTagName(ROOTDIR)
+ if (rootdir.length > 0):
+ _rootDir = getValue(rootdir[0])
+ else:
+ verbose ("Using default build dir: "+DEFAULT_ROOTDIR)
+ _rootDir = os.getcwd() + PATH_SEP + DEFAULT_ROOTDIR
+
+ if _rootDir == "":
+ verbose (ROOTDIR+" value is empty. Please specify a value for "+ ROOTDIR)
+ attemptExit(0)
+
+ if (os.path.exists(_rootDir)):
+ verbose ("Using Existing root dir: "+_rootDir)
+ else:
+ mkdir(_rootDir)
+
+################################################################################
+#
+# Clean Methods
+#
+################################################################################
+def clean():
+ global _source
+ sources = getSourceList()
+
+ if len(sources) > 0:
+ log ("Removing built code...")
+ performed = False
+ for source in sources:
+ if _source != None:
+ if getName(source) == _source:
+ performed = True
+ removeDir(source, BUILD_DIR)
+ else:
+ removeDir(source, BUILD_DIR)
+
+ if _source == None:
+ deleteDir(_rootDir + PATH_SEP + BUILD_DIR)
+
+ builds = getBuildList()
+ if len(builds) > 0:
+ log ("Removing built releases...")
+ for build in builds:
+ if _source != None:
+ if getName(build) == _source:
+ performed = True
+ removeDir(build, RELEASE_DIR)
+ else:
+ removeDir(build, RELEASE_DIR)
+ if _source == None:
+ deleteDir(_rootDir + PATH_SEP + RELEASE_DIR)
+
+ if _source != None:
+ if not performed:
+ fatal("No such source:" + _source);
+
+
+
+def distclean():
+ sources = getSourceList()
+
+ if len(sources) > 0:
+ log ("Removing source...")
+ for source in sources:
+ if _source != None:
+ if getName(source) == _source:
+ performed = True
+ removeDir(source, SOURCE_DIR)
+ else:
+ removeDir(source, SOURCE_DIR)
+
+ if _source == None:
+ deleteDir(_rootDir + PATH_SEP + SOURCE_DIR)
+
+ log ("Removing built code...")
+ for source in sources:
+ if _source != None:
+ if getName(source) == _source:
+ performed = True
+ removeDir(source, BUILD_DIR)
+ else:
+ removeDir(source, BUILD_DIR)
+ if _source == None:
+ deleteDir(_rootDir + PATH_SEP + BUILD_DIR)
+
+ patches =getPatchList()
+ if len(patches) > 0:
+ log ("Removing patches...")
+ for patch in patches:
+ if _source != None:
+ if getName(patch) == _source:
+ performed = True
+ removeDir(patch, PATCH_DIR)
+ else:
+ removeDir(patch, PATCH_DIR)
+ if _source == None:
+ deleteDir(_rootDir + PATH_SEP + PATCH_DIR)
+
+
+ builds = getBuildList()
+ if len(builds) > 0:
+ log ("Removing built releases...")
+ for build in builds:
+ if _source != None:
+ if getName(build) == _source:
+ performed = True
+ removeDir(build, RELEASE_DIR)
+ else:
+ removeDir(build, RELEASE_DIR)
+ if _source == None:
+ deleteDir(_rootDir + PATH_SEP + RELEASE_DIR)
+
+
+ if _source == None:
+ deleteDir(_rootDir)
+
+ if _source != None:
+ if not performed:
+ fatal("No such source:" + _source);
+
+
+
+def removeDir(source, rootdir):
+ name = getName(source)
+ deleteDir(_rootDir + PATH_SEP + rootdir + PATH_SEP + name)
+
+################################################################################
+#
+# Retrieve Methods
+#
+################################################################################
+def retrieve():
+ global _source
+ sources = getSourceList()
+
+ # Retreive Source
+ performed=False
+ if len(sources) > 0:
+ log ("Retrieving source...")
+
+ mkdir(_rootDir + PATH_SEP + SOURCE_DIR)
+
+ for source in sources:
+ if _source != None:
+ if getName(source) == _source:
+ performed = True
+ downloadSource(source, SOURCE_DIR)
+ else:
+ downloadSource(source, SOURCE_DIR)
+
+ # Retreive Patches
+ patches = getPatchList()
+ if len(patches) > 0:
+
+ log ("Retrieving patches...")
+
+ mkdir(_rootDir + PATH_SEP + PATCH_DIR)
+
+ for patch in patches:
+ if _source != None:
+ if getName(patch) == _source:
+ performed = True
+ downloadSource(patch, PATCH_DIR)
+ else:
+ downloadSource(patch, PATCH_DIR)
+
+ if _source != None:
+ if not performed:
+ fatal("No such patch:" + _source);
+
+
+################################################################################
+#
+# Prepare Methods
+#
+################################################################################
+
+def prepare():
+ verbose("Prepare")
+
+ mkdir(_rootDir + PATH_SEP + BUILD_DIR)
+
+ sources = getSourceList()
+ performed = False
+ if len(sources) > 0:
+ log ("Preparing source...")
+ for source in sources:
+ if _source != None:
+ if getName(source) == _source:
+ log_no_newline("Preparing "+getName(source)+": ")
+ performed = True
+ postProcess(source, SOURCE_DIR)
+ else:
+ log_no_newline("Preparing "+getName(source)+": ")
+ postProcess(source, SOURCE_DIR)
+ if _source != None:
+ if not performed:
+ fatal("No such source:" + _source);
+
+ patches = getPatchList()
+ if len(patches) > 0:
+ log ("Preparing patches...")
+ for patch in patches:
+ if _source != None:
+ if getName(patch) == _source:
+ performed = True
+ log("Preparing "+getName(patch))
+ postProcess(patch, PATCH_DIR)
+ else:
+ log("Preparing "+getName(patch))
+ postProcess(patch, PATCH_DIR)
+
+ if _source != None:
+ if not performed:
+ fatal("No such patch:" + _source);
+
+
+def postProcess(item, destination):
+ name = getName(item)
+ type = getType(item)
+
+ verbose("Post Processing:"+name)
+
+ targetdir = _rootDir + PATH_SEP + destination + PATH_SEP + name
+
+ builddir = _rootDir + PATH_SEP + BUILD_DIR + PATH_SEP + name
+
+
+ if type == SVN:
+ # Do we want to perform an export?
+
+ #extractcommand=SVN_BIN+" export "+ targetdir +" "+ builddir
+ # Use -v just now so we can show progress
+ extractcommand=CP_BIN+" -rvf "+ targetdir +" "+ builddir
+
+ runCommand(extractcommand, False)
+
+ else:
+ if type == FILE or type == HTTP or type == FTP:
+
+ mkdir(builddir)
+
+ # Look at all the files and see if they need unpacks
+ for root, dirs, files in os.walk(targetdir, topdown=False):
+ for file in files:
+ command = FILE_BIN+" "+root+PATH_SEP+file
+
+ result = Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ line = result.stdout.readline()
+ firstline=line
+ while (line != "" ):
+ # process nextline
+ line=result.stdout.readline()
+
+ result.wait()
+
+ if result.returncode != 0:
+ fatal("Download (" + name + ") contained unrecognized file type:"+ firstline)
+
+
+ extractcommand=""
+
+ if firstline.find(GZIP_DATA) != -1:
+ extractcommand=TAR_BIN+" -vxzf "+root+PATH_SEP+file+" -C " + builddir
+
+ if firstline.find(BZIP2_DATA) != -1:
+ extractcommand=TAR_BIN+" -vxjf "+root+PATH_SEP+file+" -C " + builddir
+
+ if firstline.find(ZIP_DATA) != -1:
+ extractcommand=ZIP_BIN+" -v "+root+PATH_SEP+file+" -d "+ builddir
+
+ if firstline.find(TAR_DATA) != -1:
+ extractcommand=TAR_BIN+" -vxf "+root+PATH_SEP+file+" -C "+ builddir
+
+ if firstline.find(DIFF_FILE) != -1 or firstline.find("text"):
+ extractcommand=CP_BIN+" -r "+root+PATH_SEP+file+" "+ builddir
+
+
+
+ if not extractcommand=="":
+ log_no_newline("Extracting archive:" + file+": " )
+ runCommand(extractcommand, False)
+ else:
+ fatal("Download (" + name + ") contained unsupported file type:"+ firstline)
+
+
+
+################################################################################
+#
+# Patch Methods
+#
+################################################################################
+def patch():
+
+ # Retreive Patches
+ patches= getPatchList()
+ if len(patches) > 0:
+ performed = False
+ for patch in patches:
+ if _source != None:
+ if getName(source) == _source:
+ performed = True
+ applyPatch(patch)
+ else:
+ applyPatch(patch)
+
+ if _source != None:
+ if not performed:
+ fatal("No such patch:" + _source);
+
+
+def applyPatch(patch):
+ global _rootDir
+
+ name = getName(patch)
+ type = getType(patch)
+ source = getValue(patch.getElementsByTagName(SOURCE)[0])
+ if (patch.getElementsByTagName(PREFIX).length > 0):
+ prefix = getValue(patch.getElementsByTagName(PREFIX)[0])
+ else:
+ prefix = None
+
+ if (patch.getElementsByTagName(PATH).length > 0):
+ path= getValue(patch.getElementsByTagName(PATH)[0])
+ else:
+ path = None
+
+
+ basecommand = PATCH_BIN
+
+ if prefix != None:
+ basecommand = basecommand + " -p "+prefix
+
+ basecommand = basecommand + " -E -d "+ _rootDir + PATH_SEP + BUILD_DIR + PATH_SEP + source + PATH_SEP
+
+ if path != None:
+ basecommand = basecommand + path
+
+ basecommand = basecommand + " < "
+
+ patchSource= _rootDir + PATH_SEP + PATCH_DIR + PATH_SEP + name
+
+ for root, dirs, files in os.walk(patchSource):
+ if '.svn' in dirs:
+ dirs.remove('.svn')
+ files.sort()
+ for patchName in files:
+ log("Applying patch '" + name + "'("+patchName+") to " + source)
+ runCommandShowError(basecommand + patchSource + PATH_SEP + patchName)
+
+
+################################################################################
+#
+# build Methods
+#
+################################################################################
+def showBuilds():
+ builds = getNamesfromBuildList(getBuildList())
+ if len(builds) > 0:
+ log("Available Builds:")
+ for build in builds:
+ log(" "+build)
+ else:
+ log("No builds available")
+
+#
+# Given a list of build elements extract the Name values and return as a list
+#
+def getNamesfromBuildList(list):
+ names=[]
+ for item in list:
+ name = getName(item)
+ if name != None:
+ names.append(name)
+ return names
+
+def build():
+ doBuildAction(BUILD)
+
+
+
+################################################################################
+#
+# Release Methods
+#
+################################################################################
+def release():
+ log ("Releasing...")
+ mkdir(_rootDir + PATH_SEP + RELEASE_DIR)
+
+ builds = getBuildList()
+
+ for build in builds:
+ if _source != None:
+ if getName(build) == _source:
+ mkdir(_rootDir + PATH_SEP + RELEASE_DIR + PATH_SEP + getName(build))
+ else:
+ mkdir(_rootDir + PATH_SEP + RELEASE_DIR + PATH_SEP + getName(build))
+
+ doBuildAction(RELEASE)
+
+
+
+################################################################################
+#
+# Build Helper Methods
+#
+################################################################################
+
+def doBuildAction(action):
+ config = _baseConfiguration
+
+ if len(getSourceList()) > 0:
+ log("Performing "+ action.title() +"...")
+
+ builds = getBuildList()
+
+ performed = False
+ for build in builds:
+ if _source != None:
+ if getName(build) == _source:
+ performed = True
+ performScript(build , action)
+ else:
+ performScript(build, action)
+
+ if _source != None:
+ if not performed:
+ fatal("No such build:" + _source);
+
+
+def performScript(build, scriptName):
+ name = getName(build)
+
+ checkDependencies(build)
+
+ verbose("Running "+scriptName+":"+name)
+
+ targets = build.getElementsByTagName(TARGETS)
+
+ if targets.length > 0:
+ target = targets[0].getElementsByTagName(scriptName)
+
+ if target.length > 1:
+ fatal("More than one build target specified")
+
+ if target.length == 0:
+ fatal("No build target specified")
+
+ script = getValue(target[0].getElementsByTagName(SCRIPT)[0])
+
+ script = peformSubstitutionsInScript(build, script)
+
+ runScript(script)
+
+ else:
+ fatal("Build "+name+" has no build targets")
+
+
+def checkDependencies(build):
+ name = getName(build)
+ dependencies = build.getElementsByTagName(DEPENDENCY)
+
+ if dependencies > 0:
+ for dependency in dependencies :
+ sources = dependency.getElementsByTagName(SOURCE)
+ if sources.length == 0:
+ fatal("No sources specified in dependency block for build:"+name)
+ else:
+ for source in sources:
+ sourceDependency = getValue(source)
+ if not (sourceDefined(sourceDependency)):
+ fatal("Unable to build "+name+" as specifed dependency("+sourceDependency +") is not available")
+
+def sourceDefined(name):
+ for source in getSourceList():
+ sourcename = getValue(source.getElementsByTagName(NAME)[0])
+ if sourcename == name:
+ return True
+ return False
+
+
+def runScript(script):
+ (returncode, stdout, stderr) = runCommandWithOutput(script)
+
+ if returncode != 0:
+ for line in stdout:
+ warn(line)
+ for line in stderr:
+ warn(line)
+
+ warn("Script Failed")
+
+ attemptExit(1)
+
+
+################################################################################
+#
+# XML Helper Methods
+#
+################################################################################
+
+def loadBaseConfiguration(config):
+ log ("Loading configuration:" + config)
+ full = minidom.parse(config)
+ return full.getElementsByTagName(BUILDER)[0]
+
+#
+# Assumes that we have a <node>text</node> element and returns the text value.
+#
+def getValue(node):
+ if node.childNodes.length > 0:
+ return node.childNodes[0].data
+ else:
+ return ""
+
+def getEnvironment():
+ env = _baseConfiguration.getElementsByTagName(ENVIRONMENT)
+ if env.length > 0:
+ return env[0]
+ else:
+ return None
+
+#
+# Returns the value of the NAME element contained in the specified item
+#
+def getName(item):
+ name = item.getElementsByTagName(NAME)
+ if name.length > 0:
+ return getValue(name[0])
+
+#
+# Returns the value of the TYPE element contained in the specified item
+#
+def getType(item):
+ type = item.getElementsByTagName(TYPE)
+ if type.length > 0:
+ return getValue(type[0])
+
+#
+# Returns the value of the URL element contained in the specified item
+#
+def getURL(item):
+ url = item.getElementsByTagName(URL)
+ if url.length > 0:
+ return getValue(url[0])
+
+#
+# Return the list of sources in this build configuration
+# If no sources are available then this is logged as a fatal error.
+#
+def getSourceList():
+ config = _baseConfiguration
+ sourceCount = config.getElementsByTagName(SOURCES).length
+ if sourceCount > 0:
+ return config.getElementsByTagName(SOURCES)[0].getElementsByTagName(SOURCE)
+ else:
+ fatal("No source elements defined.")
+#
+# Return the list of patches in this build configuration
+#
+def getPatchList():
+ config = _baseConfiguration
+ patchCount = config.getElementsByTagName(PATCHES).length
+ if patchCount > 0:
+ return config.getElementsByTagName(PATCHES)[0].getElementsByTagName(PATCH)
+ else:
+ return []
+
+# Returns a list of build elements including any any included build files
+# Currently nested build elements are not supported so all builds must be specified via the <include> tag.
+#
+def getBuildList():
+ config = _baseConfiguration
+
+ builds = config.getElementsByTagName(BUILDS)
+ buildcount = builds.length
+
+ if buildcount > 0:
+ build = builds[0]
+ useInclude = build.getElementsByTagName(INCLUDE).length > 0
+
+ # If we are using includes then build a list of all the files we need to include
+ if useInclude:
+ return getIncludeList(build)
+
+ else:
+ warn("Nested builds not currently supported")
+ else:
+ fatal("No Builds defined in config")
+
+#
+# Look at all <include> values in the given element and return the list of inlcudes
+#
+def getIncludeList(build):
+ includelist=[]
+ for include in build.getElementsByTagName(INCLUDE):
+ for item in getIncludeValue(getValue(include)):
+ includelist.append(item)
+
+ return includelist
+
+#
+# Process in the given include value.
+# This is done by performing `ls <include>`
+# This means includes such as 'builds/*.config' will match multiple includes and return all entries
+#
+# Any error in performing the ls is printed and the tool exits (unless ignore errors)
+#
+def getIncludeValue(include):
+ debug("Loading Includes:"+include+" ")
+
+ command = LS_BIN+" "+include
+ (returncode, stdout, stderr) = runCommandWithOutput(command)
+
+ if returncode == 0:
+ values=[]
+ for line in stdout:
+ include = loadIncludeFile(line)
+ if not include == None:
+ values.append(include)
+ return values
+ else:
+ for line in stderr:
+ warn(line)
+ attemptExit(1)
+
+#
+# Given a file name parse the XML. Any trailing '\n's that the ls command may have added are removed here.
+# The file is checked to ensure that it is a <builds> file
+# The first <build> element is returned.
+#
+# TODO: Allow multiple builds per file.
+#
+def loadIncludeFile(file):
+ buildFile = minidom.parse(file.rstrip('\n'))
+
+ builds = buildFile.getElementsByTagName(BUILDS)
+
+ if builds.length != 1:
+ warn("Build Configuration does not contain any <"+BUILDS+"> definitions")
+ else:
+ buildElements = builds[0].getElementsByTagName(BUILD)
+ if not buildElements.length > 0:
+ warn("Build Configuration does not contain any <"+BUILD+"> definitions")
+ else:
+ if buildElements.length > 0:
+ build = buildElements[0]
+ # getElementsByTagName is recursive so this will pick up the sub element build
+ # Only use the first element
+ namecount = build.getElementsByTagName(NAME).length
+ if namecount > 0:
+ return build
+ else:
+ return None
+
+#
+# Given the build target and a script substitute $value entries in script for values in
+# the Environment
+# the Source entries <source><name>
+# the build <build><name>
+# the release location : _rootDir + PATH_SEP + RELEASE_DIR + PATH_SEP + buildName
+#
+def peformSubstitutionsInScript(build, script):
+ buildName = getName(build)
+ sources = getSourceList()
+
+ #Replace Build name
+ script = script.replace("$build", buildName)
+
+ #Replace release directory
+ releaseDir = _rootDir + PATH_SEP + RELEASE_DIR + PATH_SEP + buildName
+ script = script.replace("$release", releaseDir)
+
+ # Replace Source varables
+ for source in sources:
+ sourceName = getName(source)
+
+ search = "$"+sourceName
+
+ sourcePath = source.getElementsByTagName(PATH)
+
+ replacement = _rootDir + PATH_SEP + BUILD_DIR + PATH_SEP + sourceName
+ if sourcePath.length > 0:
+ replacement = replacement + PATH_SEP + getValue(sourcePath[0])
+
+ script = script.replace(search,replacement)
+
+ # Take values from the environment script for replacement
+ env = getEnvironment()
+ if env != None:
+ for item in env.childNodes:
+ if item.nodeType == 1:
+
+ search = "$"+item.tagName
+ replace = item.childNodes[0].data
+
+ script = script.replace(search,replace)
+
+ # Perform keyword substitution replacements
+ # Currently only one substitution exists so for simplisity fix it here
+ writeVersionSubstitution = script.find("$writeVersions")
+ if writeVersionSubstitution != -1:
+
+ #Extract Filename
+ fileNameStart = script.find("(",writeVersionSubstitution)
+ fileNameEnd = script.find(")",fileNameStart)
+ fileName= script[fileNameStart+1:fileNameEnd]
+
+ substitution = createVersionSubstitution(build, fileName)
+
+ script = script.replace("$writeVersions(" + fileName + ")", substitution)
+
+
+ return script
+
+################################################################################
+#
+# Keyword Substitutions
+#
+################################################################################
+
+#
+# Use the specified build as to lookup all associated source/patches and write out their details
+# to the specified file using shell redirects. redirects are to be used as the absolute filename
+# location may not be known as the name comes in via the release script
+#
+def createVersionSubstitution(build, filename):
+ substitution = ""
+ sources = getSourceList();
+
+ dependencies = build.getElementsByTagName(DEPENDENCY)
+
+ if dependencies > 0:
+ substitution += "\n echo 'Source Version Information:'>> " + filename
+ for dependency in dependencies :
+ depSources = dependency.getElementsByTagName(SOURCE)
+ # Can assume we have dependencies as we would have failed before now
+ for source in depSources:
+ sourceDependency = getValue(source)
+ # We can assume source is valid.
+ for s in sources:
+ if sourceDependency == getName(s):
+ # provide header <source>:<type>:<revision>
+ substitution += "\n " + ECHO_BIN + " -n '" + sourceDependency + ":" \
+ + getType(s) + ":' >> " + filename
+ substitution += "\n" + getVersionCommand(s) + " >>" + filename
+ # Add Source URL to Revisions file
+ url = getValue(s.getElementsByTagName(URL)[0])
+ substitution += "\n" + ECHO_BIN + " \"URL:" + url + "\" >> "+filename
+ # Add Patches applied to this source to revisions file
+ substitution += addPatchVersions(s, filename)
+
+ return substitution
+
+#
+# Use the specified source as to lookup all associated patches and write their details out the
+# the specified file using shell redirects. redirects are to be used as the absolute filename
+# location may not be known as the name comes in via the release script
+#
+def addPatchVersions(source, filename):
+ substitution = ""
+
+ patches = getPatchList()
+
+ sourceName = getName(source)
+
+ for patch in patches:
+ patchSourceName = getValue(patch.getElementsByTagName(SOURCE)[0])
+
+ if sourceName == patchSourceName:
+ type = getType(patch)
+ substitution += "\n" + ECHO_BIN + " \"\t"+getName(patch)+":"+type + "\" >> "+filename
+ url = getValue(patch.getElementsByTagName(URL)[0])
+ substitution += "\n" + ECHO_BIN + " \"\t\tURL:" + url + "\" >> "+filename
+ if (type == SVN):
+ if (patch.getElementsByTagName(REVISION).length > 0):
+ substitution += "\n" + ECHO_BIN + " \"\t\tREVISION:"+ \
+ getValue(patch.getElementsByTagName(REVISION)[0]) + "\" >> " + filename
+ else:
+ substitution += "\n" + ECHO_BIN + " -n \"\t\tREVISION: \" >> " + filename
+ substitution += "\n" + SVNVERSION_BIN + " " + _rootDir + PATH_SEP + PATCH_DIR + PATH_SEP + getName(patch) + " >> " + filename
+
+
+ if (patch.getElementsByTagName(PREFIX).length > 0):
+ substitution += "\n" + ECHO_BIN + " \"\t\tPREFIX: " + \
+ getValue(patch.getElementsByTagName(PREFIX)[0]) + "\" >> " + filename
+
+ if (patch.getElementsByTagName(PATH).length > 0):
+ substitution += "\n" + ECHO_BIN + " \"\t\tPATH: " + \
+ getValue(patch.getElementsByTagName(PATH)[0]) + "\" >> " + filename
+
+ global _rootDir
+ patchSource= _rootDir + PATH_SEP + PATCH_DIR + PATH_SEP + getName(patch)
+
+ #
+ # Include the list of patches files applied
+ #
+ for root, dirs, files in os.walk(patchSource):
+ if '.svn' in dirs:
+ dirs.remove('.svn')
+ files.sort()
+ for patchName in files:
+ substitution += "\n" + ECHO_BIN + " \"\t\tFILE: " + patchName + "\" >> " + filename
+
+
+
+
+ if (substitution != ""):
+ return "\n" + ECHO_BIN + " \"\tPatches applied to " + sourceName + ":\" >> " + filename + substitution
+ else:
+ return "\n" + ECHO_BIN + " \"\tNo Patches\" >> " + filename
+
+
+#
+# Given a source entry return the command that will provide the current version
+# of that source.
+# i.e. svn source : svnversion <path to source>
+# http source : echo <URL>
+#
+def getVersionCommand(source):
+ global _rootDir
+ type = getType(source)
+
+ versionCommand=""
+
+ if type == SVN:
+ versionCommand=SVNVERSION_BIN+" "+_rootDir + PATH_SEP + SOURCE_DIR + PATH_SEP + getName(source)
+ else:
+ if type == FILE or type == HTTP or type == FTP:
+ versionCommand = ECHO_BIN +" " + getURL(source)
+
+
+ return versionCommand
+
+################################################################################
+#
+# Download Helper Methods
+#
+################################################################################
+
+#
+# Download the item specified in source to the given destintation
+#
+def downloadSource(source, destination):
+ name = getName(source)
+ type = getType(source)
+ url = getValue(source.getElementsByTagName(URL)[0])
+ log ( "Retrieving "+ name + "("+ type +")")
+
+ targetdir=_rootDir + PATH_SEP + destination + PATH_SEP + name
+
+ command = ""
+
+ mkdir(targetdir)
+
+ if (os.listdir(targetdir)==[]):
+
+ # Setup command for a fresh checkout
+ if (type == SVN):
+ command = SVN_BIN+" co "+url+" "+targetdir
+ if (source.getElementsByTagName(REVISION).length > 0):
+ revision = getValue(source.getElementsByTagName(REVISION)[0])
+ command = SVN_BIN+" co -r"+revision+" "+url+" "+targetdir
+ else:
+ if (type == HTTP):
+ command = WGET_BIN+" --no-directories -P "+targetdir+" "+url
+ else:
+ if (type == FILE):
+ if url.startswith(HTTP):
+ command = WGET_BIN+" -P "+targetdir+" "+url
+ else:
+ if url.startswith(FTP):
+ command = WGET_BIN+" -P "+targetdir+" "+url
+ else:
+ command = CP_BIN+" "+url+" "+targetdir
+ else:
+ warn("Target directory(" + targetdir + ") is not empty please ensure contents are valid or run 'clean "+name+"'")
+
+ verbose("Executing:"+command)
+ log_no_newline("Retrieving "+source.nodeName+": ")
+
+ if (type == FILE):
+ runCommand(command, True)
+ else:
+ runCommand(command, False)
+
+################################################################################
+#
+# Command Helper Methods
+#
+################################################################################
+
+#
+# Run command and print out last 20 lines of data on error
+#
+def runCommandShowError(command):
+ last20 = runCommand(command, False)
+ if last20 != None:
+ lines=last20[0]
+ lines=lines + 1
+ current = 1
+ while current != lines:
+ log (last20[current])
+ current = current + 1
+ attemptExit(1)
+
+#
+# Runs the given command if showOutput is true then stdout/stderr is shown on screen
+# other wise the last 20 lines of output is gathered:
+#
+# As command runs progress is shown
+#
+# return array [0] = no of elements in array. Array is fixed size 21 elements but not all are used. FIXME: this is poor
+#
+# TODO: Current mechanism for limiting to 20 lines is poor, potential to replace usages of this
+# method with runCommandWithOutput below
+#
+def runCommand(command, showOutput):
+ debug("Running Command:"+command)
+ try:
+ if showOutput:
+ # Process that shows the output
+ result = Popen(command, shell=True)
+ else:
+ # consume the output ourselves
+ result = Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+
+ index=0
+ last20=[""] * 21
+ line = result.stdout.readline()
+ while (line != "" ):
+ logWaiting()
+
+ #Record last 20 lines of output
+ index = index + 1
+ if index == 20:
+ index = 1
+
+ last20[index]=line
+
+ # process nextline
+ line = result.stdout.readline()
+
+ #
+ # If we didn't get any standard or fill our buffers then fill the end of the buffer with any stderr
+ #
+ if index == 0 | index < 15 :
+ line = result.stderr.readline()
+
+ if index != 0:
+ index = index + 1
+ if line != "":
+ last20[index]="STDERR"
+ reset = index
+ while (line != "" ):
+ logWaiting()
+
+ #Record last 20 lines of output
+ index = index + 1
+ if index == 20:
+ index = reset
+
+ last20[index]=line
+
+ # process nextline
+ line = result.stderr.readline()
+
+ result.wait()
+
+ if result.returncode == 0:
+ logWaitingDone()
+ else:
+ logWaitingFailed("Failed")
+ attemptExit(1)
+ if not showOutput:
+ last20[0]=index
+ return last20
+
+ return None
+
+ except IOError:
+ logWaitingFailed ("Error running command.")
+ attemptExit(1)
+
+#
+# Runs the given command if showOutput is true then stdout/stderr is shown on screen
+# Stdout and stderr is gathered up and returned with error code.
+#
+# return (result.returncode, stdout, stderr)
+#
+# As command runs progress is shown
+#
+def runCommandWithOutput(command):
+
+ result = Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+
+
+ # Retrieve STDOUT
+ stdout=[]
+ line = result.stdout.readline()
+ while (line != "" ):
+ logWaiting()
+
+ stdout.append(line)
+
+ # process nextline
+ line = result.stdout.readline()
+
+ line = result.stderr.readline()
+
+ # Retrieve STDERR
+ stderr=[]
+ while (line != "" ):
+ stderr.append(line)
+
+ # process nextline
+ line = result.stderr.readline()
+
+ result.wait()
+
+ logWaitingClear()
+
+ return (result.returncode, stdout, stderr)
+
+
+################################################################################
+#
+# OS Helper Methods
+#
+################################################################################
+
+#
+# Check _ignoreErrors value and exit if false
+#
+def attemptExit(code):
+ if not _ignoreErrors:
+ sys.exit(code)
+ else:
+ print ("Ignoring Errors")
+
+#
+# Check that the required binaries are present for this tool.
+# Only checks the minimum set.
+# Logs warning if archive tools are missing
+#
+def checkSystemRequirements():
+ exists = checkExists(SVN_BIN)
+ exists = exists & checkExists(WGET_BIN)
+ exists = exists & checkExists(CP_BIN)
+ exists = exists & checkExists(PATCH_BIN)
+ exists = exists & checkExists(FILE_BIN)
+
+ if not checkExists(TAR_BIN):
+ warn("Unable to process tar files as tar binary does not exist:" + TAR_BIN)
+ if not checkExists(BZIP2_BIN):
+ warn("Unable to process bzip2 files as bzip2 binary does not exist:" + BZIP2_BIN)
+ if not checkExists(UNZIP_BIN):
+ warn("Unable to process zip files as unzip binary does not exist:" + UNZIP_BIN)
+
+ if not exists:
+ sys.exit(1)
+
+#
+# Helper that checks for files existence
+#
+def checkExists(command):
+ debug_no_newline("Checking for "+command+":")
+ command = LS_BIN+" "+command
+
+ result = Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ line = result.stdout.readline()
+
+ while (line != "" ):
+ # process nextline
+ line = result.stdout.readline()
+
+ result.wait()
+
+ if result.returncode == 0:
+ debug("OK")
+ return True
+ else:
+ debug("Missing")
+ warn("Missing dependancy:"+command)
+ return False
+
+
+# Delete everything reachable from the directory named in 'top',
+# assuming there are no symbolic links.
+#
+# If an attempt to delete '/' is performed this is logged as a fatal error
+#
+def deleteDir(top):
+ if top == '/':
+ fatal("Exiting as attempt to delete '/' occured.")
+ else:
+ if (os.path.exists(top)):
+ log_no_newline("Removing:"+top+". ")
+ for root, dirs, files in os.walk(top, topdown=False):
+ logWaiting()
+ for name in files:
+ os.remove(os.path.join(root, name))
+ for name in dirs:
+ logWaiting()
+ os.rmdir(os.path.join(root, name))
+
+ logWaiting()
+ os.rmdir(top)
+
+ logWaitingDone()
+
+def mkdir(dir):
+ if not os.path.exists(dir):
+ os.mkdir(dir)
+
+
+################################################################################
+#
+# Logging Helper Methods
+#
+################################################################################
+
+#
+# Provide a spinning -/|\
+#
+def logWaiting():
+ global _charIndex, _waitingChars
+
+ _charIndex = (_charIndex + 1) % len(_waitingChars)
+
+ log_no_newline('\b')
+ log_no_newline(_waitingChars[_charIndex])
+
+#
+# Clear the logWaiting symbol and end the line with ' Done'
+#
+def logWaitingDone():
+ log_no_newline('\b')
+ log(" Done")
+
+#
+# Clear the logWaiting symbol
+#
+def logWaitingClear():
+ log_no_newline('\b')
+
+#
+# Clear the logWaiting symbol and end line with messsage
+#
+def logWaitingFailed(message):
+ log_no_newline('\b')
+ log(" "+message)
+
+def debug(string):
+ if _debug:
+ log(string)
+
+def verbose(string):
+ if _verbose:
+ log(string)
+
+def log (string):
+ if _log:
+ print string
+
+def warn (string):
+ print string
+
+def fatal(string):
+ print string
+ attemptExit(1)
+
+def log_no_newline (string):
+ if _log:
+ sys.stdout.write(string)
+ sys.stdout.flush()
+
+def verbose_no_newline (string):
+ if _verbose:
+ sys.stdout.write(string)
+ sys.stdout.flush()
+
+def debug_no_newline (string):
+ if _debug:
+ sys.stdout.write(string)
+ sys.stdout.flush()
+
+if __name__ == "__main__":
+ main()
diff --git a/buildtools/buildCreator/qpid.build b/buildtools/buildCreator/qpid.build
new file mode 100644
index 0000000000..f55025dc8d
--- /dev/null
+++ b/buildtools/buildCreator/qpid.build
@@ -0,0 +1,55 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<builds>
+ <build>
+ <name>qpid-build</name>
+
+ <dependency>
+ <source>qpid</source>
+ </dependency>
+
+ <targets>
+ <build>
+ <script><![CDATA[
+
+pushd $qpid/java
+ant -Dproject.version=$version build
+
+]]>
+ </script>
+ </build>
+
+ <release>
+ <script><![CDATA[
+# Create build package
+mkdir -p $release/$build-$version
+cp -r $qpid/java/build/* $release/$build-$version
+
+# Build release artifact
+cd $release
+tar cvzf $build-$version.tgz $build-$version
+]]>
+ </script>
+ </release>
+ </targets>
+
+ </build>
+</builds>
diff --git a/cc/LICENSE b/cc/LICENSE
new file mode 100644
index 0000000000..bc46b77047
--- /dev/null
+++ b/cc/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/cc/NOTICE b/cc/NOTICE
new file mode 100644
index 0000000000..05f39ba176
--- /dev/null
+++ b/cc/NOTICE
@@ -0,0 +1,8 @@
+// ------------------------------------------------------------------
+// NOTICE file corresponding to the section 4d of The Apache License,
+// Version 2.0, in this case for Qpid bin scripts
+// ------------------------------------------------------------------
+
+Apache Qpid
+Copyright 2006-2008 Apache Software Foundation
+
diff --git a/cc/README b/cc/README
index b0e3385d6d..8d1286f6d7 100644
--- a/cc/README
+++ b/cc/README
@@ -20,15 +20,41 @@ Download CruiseControl from: http://cruisecontrol.sourceforge.net/
Set system variables
******************
-Prior to use CruiseControl you'll need to set two system variables:
+Prior to use CruiseControl you'll need to set three system variables:
Variable Value
CC_HOME path to your qpid project, for example /home/foo/projects/qpid
CPPSTORE_HOME path to your C++ store, for example /home/foo/projects/bdbstore-cpp
+NANT_HOME path to the nant directory -- only required for .net client --
+ (nant can be downloaded from http://nant.sourceforge.net/)
Edit the file CC_HOME/config.properties and set the properties so to match your system requirements.
Notes
- * the cpp store can be checked out from: https://svn.jboss.org/repos/rhmessaging/store/trunk/cpp
+ * the cpp store can be checked out from: https://svn.jboss.org/repos/rhmessaging/store/trunk/cpp
* Only unix scrips are currently provided
+ *
+
+
+******************
+Installing Mono
+******************
+For building the .net client on a Linux platform you need to install Mono.
+Mono website is: http://www.mono-project.com/Main_Page
+Here are the instruction for a RHEL5 platform:
+
+Create the file "/etc/yum.repos.d/mono.repo" and add the following lines:
+
+[Mono]
+name=Mono Stack (RHEL_5)
+type=rpm-md
+baseurl=http://download.opensuse.org/repositories/Mono/RHEL_5/
+gpgcheck=1
+gpgkey=http://download.opensuse.org/repositories/Mono/RHEL_5/repodata/repomd.xml.key
+enabled=1
+
+Enter the following command to install Mono:
+
+# yum install mono-complete
+
******************
Running CruiseControl
diff --git a/cc/config.properties b/cc/config.properties
index 0a0a7b747a..82329722cc 100644
--- a/cc/config.properties
+++ b/cc/config.properties
@@ -1,4 +1,25 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
mail.subject=CC Report for
mail.host=localhost
mail.returnaddress=my-email
-mail.list=list \ No newline at end of file
+mail.list=list
diff --git a/cc/config.xml b/cc/config.xml
index 2436cec1ca..ba89acc511 100644
--- a/cc/config.xml
+++ b/cc/config.xml
@@ -22,13 +22,16 @@ under the License.
<property environment="env" toupper="true"/>
<!-- Set a collection of global properties from the properties file "config.properties" -->
- <property file="config.properties"/>
+ <property file="${env.CC_HOME}/cc/config.properties"/>
<include.projects file="./config/cpp-trunk.xml"/>
<include.projects file="./config/java-trunk.xml"/>
+ <include.projects file="./config/dotnet-trunk.xml"/>
<include.projects file="./config/bdbstore-cpp-trunk.xml"/>
<include.projects file="./config/cpp-perftests.xml"/>
<include.projects file="./config/example-automation.xml"/>
<include.projects file="./config/java-perftests.xml"/>
<include.projects file="./config/java-jmstck.xml"/>
</cruisecontrol>
+
+
diff --git a/cc/config/dotnet-trunk.xml b/cc/config/dotnet-trunk.xml
new file mode 100644
index 0000000000..0d922967e4
--- /dev/null
+++ b/cc/config/dotnet-trunk.xml
@@ -0,0 +1,63 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<cruisecontrol>
+ <project name="qpid-dotnet-trunk"
+ buildafterfailed="false">
+
+ <listeners>
+ <currentbuildstatuslistener file="logs/${project.name}/status.txt"/>
+ </listeners>
+
+ <bootstrappers>
+ <svnbootstrapper localWorkingCopy="../bin" />
+ <svnbootstrapper localWorkingCopy="../dotnet/client-010" />
+ <svnbootstrapper localWorkingCopy="../specs" />
+ </bootstrappers>
+
+ <modificationset quietperiod="30">
+ <svn localWorkingCopy="../bin"/>
+ <svn localWorkingCopy="../dotnet/client-010"/>
+ <svn localWorkingCopy="../specs"/>
+ </modificationset>
+
+ <schedule interval="3600">
+ <!-- generates code from specs -->
+ <ant target="build"
+ uselogger="false"
+ antworkingdir="../dotnet/client-010/gentool">
+ </ant>
+
+ <exec timeout="1800"
+ command="/bin/bash"
+ args="../cc/scripts/dotnetbuild.sh"
+ workingdir="../dotnet/client-010" />
+ </schedule>
+
+ <publishers>
+ <email subjectprefix="${mail.subject}: ${project.name}" mailhost="${mail.host}"
+ returnaddress="${mail.returnaddress}"
+ buildresultsurl="http://${env.HOSTNAME}:8080/buildresults/${project.name}"
+ skipusers="false"
+ reportsuccess="fixes"
+ spamwhilebroken="true">
+ <always address="${mail.list}"/>
+ </email>
+ </publishers>
+ </project>
+</cruisecontrol>
diff --git a/cc/config/java/jndi.properties b/cc/config/java/jndi.properties
index c7e5f84d5a..9340163622 100644
--- a/cc/config/java/jndi.properties
+++ b/cc/config/java/jndi.properties
@@ -1,3 +1,24 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
java.naming.factory.initial = org.apache.qpid.jndi.PropertiesFileInitialContextFactory
connectionfactory.QueueConnectionFactory = amqp://username:password@topicClientid/test?brokerlist='tcp://localhost:qpid_port'
diff --git a/cc/scripts/dotnetbuild.sh b/cc/scripts/dotnetbuild.sh
new file mode 100644
index 0000000000..51d2110757
--- /dev/null
+++ b/cc/scripts/dotnetbuild.sh
@@ -0,0 +1,21 @@
+#!/bin/bash -x
+###########################################################
+#Licensed to the Apache Software Foundation (ASF) under one
+#or more contributor license agreements. See the NOTICE file
+#distributed with this work for additional information
+#regarding copyright ownership. The ASF licenses this file
+#to you under the Apache License, Version 2.0 (the
+#"License"); you may not use this file except in compliance
+#with the License. You may obtain a copy of the License at
+#
+#http://www.apache.org/licenses/LICENSE-2.0
+#
+#Unless required by applicable law or agreed to in writing,
+#software distributed under the License is distributed on an
+#"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#KIND, either express or implied. See the License for the
+#specific language governing permissions and limitations
+#under the License.
+###########################################################
+
+mono $NANT_HOME/bin/NAnt.exe test \ No newline at end of file
diff --git a/cc/scripts/javajmstck.sh b/cc/scripts/javajmstck.sh
index 1db1e01ccf..9d279ed38e 100644
--- a/cc/scripts/javajmstck.sh
+++ b/cc/scripts/javajmstck.sh
@@ -1,4 +1,22 @@
#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
cleanup(){
echo "kill any existing broker instance"
diff --git a/cc/scripts/verify b/cc/scripts/verify
index c183fee323..35191b17c9 100755
--- a/cc/scripts/verify
+++ b/cc/scripts/verify
@@ -18,6 +18,7 @@
#under the License.
###########################################################
+export DOTNET_EXAMPLES=$CC_HOME/dotnet/client-010/bin/mono-2.0/debug
export CLASSPATH=`find "$CC_HOME/java/build/lib" -name '*.jar' | tr '\n' ":"`
export CPP=$CC_HOME/cpp/examples
export JAVA=$CC_HOME/java/client/example/src/main/java
@@ -77,6 +78,7 @@ verify() {
else dir=`dirname $1`; script=`basename $1`; fi
cd $dir || return 1
rm -f *.out
+ echo "Running: $dir/$script"
{ source ./$script && diff -ac $script.out $script.in ; } || fail
test -z "$FAIL" && rm -f *.out
return $FAIL
diff --git a/cc/scripts/verify_all b/cc/scripts/verify_all
index fcb38f3709..8d3ec669a7 100755
--- a/cc/scripts/verify_all
+++ b/cc/scripts/verify_all
@@ -35,7 +35,7 @@ run_broker()
echo "Starting C++ broker"
echo "******************************************************"
echo ""
- $CC_HOME/cpp/src/qpidd -t -d --auth no --no-data-dir --log-output $CC_HOME/broker.log
+ $CC_HOME/cpp/src/qpidd -t -d --auth no --no-data-dir --log-to-file $CC_HOME/broker.log
}
stop_broker()
@@ -118,9 +118,49 @@ echo "-----------</Running Java/Python combination>--------"
echo ""
}
+run_dotnet_dotnet()
+{
+echo "-----------<Running .Net/.Net combination>---------"
+verify $CC_HOME/dotnet/client-010/examples/ "verify" "*.svn"
+echo "-----------</Running .Net/.Net combination>--------"
+echo ""
+}
+
+run_cpp_dotnet()
+{
+echo "-----------<Running C++/.Net combination>---------"
+verify $CC_HOME/dotnet/client-010/examples/ "verify_cpp_dotnet" "*.svn"
+verify $CC_HOME/dotnet/client-010/examples/ "verify_dotnet_cpp" "*.svn"
+echo "-----------</Running C++/.Net combination>--------"
+echo ""
+}
+
+run_java_dotnet()
+{
+echo "-----------<Running Java/.Net combination>---------"
+verify $CC_HOME/dotnet/client-010/examples/ "verify_java_dotnet" "*.svn"
+verify $CC_HOME/dotnet/client-010/examples/ "verify_dotnet_java" "*.svn"
+echo "-----------</Running Java/.Net combination>--------"
+echo ""
+}
+
+run_python_dotnet()
+{
+echo "-----------<Running Python/.Net combination>---------"
+verify $CC_HOME/dotnet/client-010/examples/ "verify_python_dotnet" "*.svn"
+verify $CC_HOME/dotnet/client-010/examples/ "verify_dotnet_python" "*.svn"
+echo "-----------</Running Python/.Net combination>--------"
+echo ""
+}
+
+
run_python_python
run_python_cpp_comb
run_cpp_cpp
run_java_java
run_java_cpp_comb
run_java_python_comb
+run_dotnet_dotnet
+run_cpp_dotnet
+run_java_dotnet
+run_python_dotnet \ No newline at end of file
diff --git a/cpp/BuildInstallSettings.cmake b/cpp/BuildInstallSettings.cmake
new file mode 100644
index 0000000000..e611a141c9
--- /dev/null
+++ b/cpp/BuildInstallSettings.cmake
@@ -0,0 +1,132 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Settings related to the Qpid build and install CMake/CTest/CPack procedure.
+# These are used by both the C++ and WCF components.
+
+set (QPID_VERSION_MAJOR 0)
+set (QPID_VERSION_MINOR 6)
+
+# When doing installs, there are a number of components that the item can
+# be associated with. Since there may be different sets of components desired
+# for the various platforms, the component names are defined here. When
+# setting the COMPONENT in an install directive, use these to ensure that
+# the item is installed correctly.
+
+if (WIN32)
+ # Install types; these defines the component sets that are installed.
+ # Each component (below) indicates which of these install type(s) it is
+ # included in. The user can refine the components at install time.
+ set (CPACK_ALL_INSTALL_TYPES Broker Development Full)
+
+ set (QPID_COMPONENT_COMMON Common)
+ set (CPACK_COMPONENT_COMMON_INSTALL_TYPES Broker Development Full)
+ set (CPACK_COMPONENT_COMMON_DISPLAY_NAME "Required common runtime items")
+ set (CPACK_COMPONENT_COMMON_DESCRIPTION
+ "Run-time library common to all runtime components in Qpid.\nThis item is required by both broker and client components.")
+
+ set (QPID_COMPONENT_BROKER Broker)
+ set (CPACK_COMPONENT_BROKER_DEPENDS Common)
+ set (CPACK_COMPONENT_BROKER_INSTALL_TYPES Broker Full)
+ set (CPACK_COMPONENT_BROKER_DISPLAY_NAME "Broker")
+ set (CPACK_COMPONENT_BROKER_DESCRIPTION
+ "Messaging broker; controls message flow within the system.\nAt least one broker is required to run any messaging application.")
+
+ set (QPID_COMPONENT_CLIENT Client)
+ set (CPACK_COMPONENT_CLIENT_DEPENDS Common)
+ set (CPACK_COMPONENT_CLIENT_INSTALL_TYPES Development Full)
+ set (CPACK_COMPONENT_CLIENT_DISPLAY_NAME "Client runtime libraries")
+ set (CPACK_COMPONENT_CLIENT_DESCRIPTION
+ "Runtime library components required to build and execute a client application.")
+
+ set (QPID_COMPONENT_CLIENT_INCLUDE ClientInclude)
+ set (CPACK_COMPONENT_CLIENTINCLUDE_INSTALL_TYPES Development Full)
+ set (CPACK_COMPONENT_CLIENTINCLUDE_DISPLAY_NAME
+ "Client programming header files")
+ set (CPACK_COMPONENT_CLIENTINCLUDE_DESCRIPTION
+ "C++ header files required to build any Qpid messaging application.")
+
+ set (QPID_COMPONENT_EXAMPLES Examples)
+ set (CPACK_COMPONENT_EXAMPLES_INSTALL_TYPES Development Full)
+ set (CPACK_COMPONENT_EXAMPLES_DISPLAY_NAME "C++ Client programming examples")
+ set (CPACK_COMPONENT_EXAMPLES_DESCRIPTION
+ "Example source code for using the C++ Client.")
+
+ set (QPID_COMPONENT_QMF QMF)
+ set (CPACK_COMPONENT_QMF_INSTALL_TYPES Development Full)
+ set (CPACK_COMPONENT_QMF_DISPLAY_NAME
+ "Qpid Management Framework (QMF)")
+ set (CPACK_COMPONENT_QMF_DESCRIPTION
+ "QMF Agent allows you to embed QMF management in your program.\nQMF Console allows you to build management programs using QMF.")
+
+ set (QPID_INSTALL_BINDIR bin CACHE STRING
+ "Directory to install user executables")
+ set (QPID_INSTALL_CONFDIR conf CACHE STRING
+ "Directory to install configuration files")
+ set (QPID_INSTALL_DATADIR conf CACHE STRING
+ "Directory to install read-only arch.-independent data root")
+ set (QPID_INSTALL_EXAMPLESDIR examples CACHE STRING
+ "Directory to install programming examples in")
+ set (QPID_INSTALL_HTMLDIR html CACHE STRING
+ "Directory to install HTML documentation")
+ set (QPID_INSTALL_INCLUDEDIR include CACHE STRING
+ "Directory to install programming header files")
+ set (QPID_INSTALL_LIBDIR bin CACHE STRING
+ "Directory to install library files")
+ set (QPID_INSTALL_SBINDIR bin CACHE STRING
+ "Directory to install system admin executables")
+ set (QPIDC_MODULE_DIR plugins/client CACHE STRING
+ "Directory to load client plug-in modules from")
+ set (QPIDD_MODULE_DIR plugins/broker CACHE STRING
+ "Directory to load broker plug-in modules from")
+endif (WIN32)
+
+if (UNIX)
+ set (QPID_COMPONENT_BROKER runtime)
+ set (QPID_COMPONENT_CLIENT runtime)
+ set (QPID_COMPONENT_COMMON runtime)
+ set (CPACK_COMPONENT_RUNTIME_DISPLAY_NAME
+ "Items required to run broker and/or client programs")
+ set (QPID_COMPONENT_CLIENT_INCLUDE development)
+ set (QPID_COMPONENT_EXAMPLES development)
+ set (QPID_COMPONENT_QMF development)
+ set (CPACK_COMPONENT_DEVELOPMENT_DISPLAY_NAME
+ "Items required to build new C++ Qpid client programs")
+
+ set (QPID_INSTALL_BINDIR bin CACHE STRING
+ "Directory to install user executables")
+ set (QPID_INSTALL_CONFDIR etc/qpid CACHE STRING
+ "Directory to install configuration files")
+ set (QPID_INSTALL_DATADIR share/qpid CACHE STRING
+ "Directory to install read-only arch.-independent data root")
+ set (QPID_INSTALL_EXAMPLESDIR share/examples CACHE STRING
+ "Directory to install programming examples in")
+ set (QPID_INSTALL_HTMLDIR html CACHE STRING
+ "Directory to install HTML documentation")
+ set (QPID_INSTALL_INCLUDEDIR include CACHE STRING
+ "Directory to install programming header files")
+ set (QPID_INSTALL_LIBDIR lib CACHE STRING
+ "Directory to install library files")
+ set (QPID_INSTALL_SBINDIR sbin CACHE STRING
+ "Directory to install system admin executables")
+ set (QPIDC_MODULE_DIR ${QPID_INSTALL_LIBDIR}/qpid/client CACHE STRING
+ "Directory to load client plug-in modules from")
+ set (QPIDD_MODULE_DIR ${QPID_INSTALL_LIBDIR}/qpid/daemon CACHE STRING
+ "Directory to load broker plug-in modules from")
+endif (UNIX)
diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt
new file mode 100644
index 0000000000..1c412743fe
--- /dev/null
+++ b/cpp/CMakeLists.txt
@@ -0,0 +1,101 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+project(qpid-cpp)
+
+cmake_minimum_required(VERSION 2.4.0 FATAL_ERROR)
+if(COMMAND cmake_policy)
+ cmake_policy(SET CMP0003 NEW)
+endif(COMMAND cmake_policy)
+
+include(BuildInstallSettings.cmake)
+
+set (qpidc_version ${QPID_VERSION_MAJOR}.${QPID_VERSION_MINOR})
+
+enable_testing()
+include (CTest)
+
+# Overall packaging/install options.
+# This section also has all the setup for various packaging-specific options.
+set (CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
+if (WIN32)
+ # Include installing the MSVCRT library
+ include(InstallRequiredSystemLibraries)
+ set (CPACK_GENERATOR "NSIS")
+ set (CPACK_NSIS_MUI_ICON "${CMAKE_CURRENT_SOURCE_DIR}/packaging/NSIS\\\\qpid-icon.ico")
+ set (CPACK_NSIS_MUI_UNIICON "${CMAKE_CURRENT_SOURCE_DIR}/packaging/NSIS\\\\qpid-icon.ico")
+ set (CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/packaging/NSIS\\\\qpid-install-banner.bmp")
+ set (CPACK_NSIS_URL_INFO_ABOUT "http://qpid.apache.org/")
+ # Needs this to correctly set up Start menu links later.
+ set (CPACK_PACKAGE_EXECUTABLES "")
+
+ # The WCF/C++ client is built separately (it doesn't build via CMake)
+ # but is installed with the C++ components on Windows.
+ install (PROGRAMS
+ ${CMAKE_SOURCE_DIR}/../wcf/src/Apache/Qpid/Channel/bin/Debug/Apache.Qpid.Channel.dll
+ ${CMAKE_SOURCE_DIR}/../wcf/src/Apache/Qpid/Channel/bin/Debug/Apache.Qpid.Interop.dll
+ DESTINATION ${QPID_INSTALL_LIBDIR}
+ COMPONENT ${QPID_COMPONENT_CLIENT})
+ install (DIRECTORY ${CMAKE_SOURCE_DIR}/../wcf/samples/Channel
+ DESTINATION ${QPID_INSTALL_EXAMPLESDIR}
+ COMPONENT ${QPID_COMPONENT_EXAMPLES}
+ PATTERN ".svn" EXCLUDE)
+
+set (CPACK_NSIS_EXTRA_INSTALL_COMMANDS "
+ ExecWait 'gacutil -I \\\"$INSTDIR\\\\${QPID_INSTALL_LIBDIR}\\\\Apache.Qpid.Channel.dll\\\"'
+ ExecWait 'gacutil -I \\\"$INSTDIR\\\\${QPID_INSTALL_LIBDIR}\\\\Apache.Qpid.Interop.dll\\\"'
+ ")
+set (CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "
+ ExecWait 'gacutil /u \\\"Apache.Qpid.Channel\\\"'
+ ExecWait 'gacutil /u \\\"Apache.Qpid.Interop\\\"'
+ ")
+
+endif (WIN32)
+
+set (QPIDC_CONF_FILE ${QPID_INSTALL_CONFDIR}/qpidc.conf CACHE STRING
+ "Name of the Qpid client configuration file")
+set (QPIDD_CONF_FILE ${QPID_INSTALL_CONFDIR}/qpidd.conf CACHE STRING
+ "Name of the Qpid broker configuration file")
+
+install(FILES LICENSE NOTICE README SSL RELEASE_NOTES DESIGN
+ xml/cluster.xml INSTALL-WINDOWS
+ DESTINATION ${QPID_INSTALL_DATADIR})
+
+if (WIN32)
+ set (CMAKE_DEBUG_POSTFIX "d")
+endif (WIN32)
+
+# set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_subdirectory(managementgen)
+add_subdirectory(etc)
+add_subdirectory(src)
+add_subdirectory(docs/api)
+# add_subdirectory(docs/man)
+add_subdirectory(examples)
+
+set(CPACK_PACKAGE_NAME "qpid-cpp")
+set(CPACK_PACKAGE_VENDOR "Apache Software Foundation")
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Apache Qpid C++")
+set(CPACK_PACKAGE_VERSION "${qpidc_version}")
+set(CPACK_PACKAGE_VERSION_MAJOR "${QPID_VERSION_MAJOR}")
+set(CPACK_PACKAGE_VERSION_MINOR "${QPID_VERSION_MINOR}")
+set(CPACK_PACKAGE_VERSION_PATCH "0")
+set(CPACK_PACKAGE_INSTALL_DIRECTORY "qpidc-${qpidc_version}")
+
+include (CPack)
diff --git a/cpp/CTestConfig.cmake b/cpp/CTestConfig.cmake
new file mode 100755
index 0000000000..288d9333ae
--- /dev/null
+++ b/cpp/CTestConfig.cmake
@@ -0,0 +1,13 @@
+## This file should be placed in the root directory of your project.
+## Then modify the CMakeLists.txt file in the root directory of your
+## project to incorporate the testing dashboard.
+## # The following are required to uses Dart and the Cdash dashboard
+## ENABLE_TESTING()
+## INCLUDE(CTest)
+set(CTEST_PROJECT_NAME "qpid-cpp")
+set(CTEST_NIGHTLY_START_TIME "20:00:00 EST")
+
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "www.riverace.com")
+set(CTEST_DROP_LOCATION "/CDash-1.4.2/submit.php?project=qpid-cpp")
+set(CTEST_DROP_SITE_CDASH TRUE)
diff --git a/cpp/DESIGN b/cpp/DESIGN
index 7e9ba6755c..c814f1c53d 100644
--- a/cpp/DESIGN
+++ b/cpp/DESIGN
@@ -9,9 +9,8 @@ Project contains:
* Client library (lib/libqpid_client): src/qpid/client
* Broker library (lib/libqpid_broker): src/qpid/broker
* Common classes
- * src/qpid/concurrent: concurrecy
* src/qpid/framing: wire encoding/decoding
- * src/qpid/io: reading/writing
+ * src/qpid/sys: io, threading etc
* src/qpid/Exception.cpp, QpidError.cpp: Exception classes.
* Qpid Daemon (bin/qpidd): src/qpidd.cpp
diff --git a/cpp/INSTALL b/cpp/INSTALL
index 4b73adca19..d54d2affc3 100644
--- a/cpp/INSTALL
+++ b/cpp/INSTALL
@@ -28,7 +28,8 @@ Table of Contents
Note that the daemon and client API can be installed separately.
This document describes how to build the Qpid/C++ broker and client, either
-from a checkout of the source or from a source distribution.
+from a checkout of the source or from a source distribution, on Linux/UNIX.
+Please see INSTALL-WINDOWS for information on building on Windows.
This also explains how to install the required prerequisites for Qpid/C++.
@@ -50,17 +51,24 @@ a source distribution:
* e2fsprogs <http://e2fsprogs.sourceforge.net/> (1.39)
* pkgconfig <http://pkgconfig.freedesktop.org/wiki/> (0.21)
-(*) earlier versions of boost e.g. 1.33 also work
+(*) earlier versions of boost e.g. 1.33 also work and there is a patch
+to get 1.32 working in the svn tree though that is only recommended as
+a last resort.
-Optional cluster functionality requires:
- * openais <http://openais.org/> (0.80.3)
-
-Optional XML exchange requires:
+Optional cluster functionality requires ONE of:
+ * openais <http://openais.org> (0.80.3)
+ * corosync <http://corosync.org> (1.0.0.rc1)
+
+ Optional XML exchange requires:
* xqilla <http://xqilla.sourceforge.net/HomePage> (2.0.0)
* xerces-c <http://xerces.apache.org/xerces-c/> (2.7.0)
+Optional SSL support requires:
+* nss <http://www.mozilla.org/projects/security/pki/nss/>
+* nspr <http://www.mozilla.org/projects/nspr/>
+
Qpid has been built using the GNU C++ compiler:
- * gcc <http://gcc.gnu.org/> (3.2.3)
+ * gcc <http://gcc.gnu.org/> (3.4.6)
If you want to build directly from the SVN repository you will need
all of the above plus:
@@ -77,19 +85,45 @@ all of the above plus:
NOTE: make sure to install the related '-devel' packages also!
+To build the QMF (Qpid Management Framework) bindings for Ruby and Python,
+the following must also be installed:
+
+ * ruby-devel
+ * python-devel
+ * swig <http://www.swig.org> (1.3.35)
+
+UUID problems:
+In some later Linux releases (such as Fedora 12), the uuid/uuid.h file has been
+moved from e2fsprogs-devel into libuuid-devel. If you are using a newer Linux
+release and run into a problem during configure in which uuid.h cannot be found,
+look for and install the libuuid-devel package.
+
2.2. How to Install
===================
2.2.1. Using Package Management Tools
=====================================
-On linux most packages can be installed using your distribution's package
-management tool. For example on Fedora:
- # yum install boost-devel e2fsprogs-devel pkgconfig openais openais-devel
- # yum install gcc-c++ make autoconf automake help2man libtool doxygen graphviz ruby
+
+On linux most packages can be installed using your distribution's
+package management tool. For example on Fedora:
+
+ # yum install boost-devel e2fsprogs-devel pkgconfig gcc-c++ make autoconf automake ruby libtool help2man doxygen graphviz
+
+The optional clustering packages changed name in Fedora 10. On Fedora 9 or earlier:
+ # yum install openais-devel cman-devel
+On Fedora 10 or later
+ # yum install corosync-devel cmanlib-devel
+
+For SASL and SSL, include
+ # yum install cyrus-sasl-devel
+
+For the XML Exchange, include:
+
+ # yum install xqilla-devel xerces-c-devel
Follow the manual installation instruction below for any packages not
-available through yum.
+available through your distributions packaging tool.
2.2.2. From Source
==================
diff --git a/cpp/INSTALL-WINDOWS b/cpp/INSTALL-WINDOWS
new file mode 100644
index 0000000000..0b09572816
--- /dev/null
+++ b/cpp/INSTALL-WINDOWS
@@ -0,0 +1,153 @@
+ Installing Qpid/C++ on Windows
+ ==============================
+
+Table of Contents
+=================
+1. Introduction
+
+2. Prerequisites
+ 2.1. What to Install
+ 2.2. Important Environment Variable Settings
+
+3. Building from a Source Distribution
+4. Building a Repository Working Copy
+5. Tests
+6. Doxygen
+7. Troubleshooting
+
+
+1. Introduction
+===============
+Note that the broker and client API can be built and installed separately.
+They both link against a common library.
+
+This document describes how to build the Qpid/C++ broker and client on
+Windows using Microsoft Visual Studio 2008 (VC9). It describes how to build
+from both a checkout of the source and from a source distribution.
+
+Please see INSTALL for information on building on Linux/UNIX.
+
+
+2. Prerequisites
+================
+We prefer to avoid spending time accommodating older versions of these
+packages, so please make sure that you have the latest stable versions.
+Known version numbers for a successful build are given in parentheses.
+Take these as a recommended minimum version.
+
+2.1. What to Install
+====================
+
+The following libraries and header files must be installed to build
+from either a source checkout or a source distribution:
+
+ * boost <http://www.boost.org> (1.35)(*)
+
+earlier versions of boost e.g. 1.33 also work
+
+To build from a source repository (SVN) checkout you will need boost plus:
+
+ * CMake <http://www.cmake.org> (2.4)
+ * python <http://www.python.org> (2.5.2)
+ * ruby <http://www.ruby-lang.org> (1.8.4)
+
+Regardless of which type of build you perform, if you wish to run the full
+test suite, you will need to have python, listed above, installed.
+
+2.2. Important Environment Variable Settings
+============================================
+Ensure that all the build tools are available on your path, when they are
+manually installed to non-standard locations. For example:
+
+ # set PATH=C:\python25;%PATH%
+
+It is also necessary to set BOOST_ROOT to refer to the base of your Boost
+installation. The Visual Studio projects refer to it. For example:
+
+ # set BOOST_ROOT=C:\Program Files\boost\boost_1_35_0
+
+
+3. Building from a Source Distribution
+======================================
+The Qpid client/broker, examples, and tests are built with separate
+Visual Studio solution files. The procedure for all three is the same.
+
+Start the Visual Studio IDE and open the desired solution. They are located
+under the distribution directory in the following places:
+
+- broker/client: src/qpidc.sln
+- examples: src/examples/examples.sln
+- tests: src/tests/tests.sln
+
+Open the desired solution, select Debug or Release, and build.
+You can build both Release and Debug from the same project.
+
+If you build all the projects you can then "Build" the RUN_TESTS project.
+This will run the test suite against the Qpid version just built.
+
+
+4. Building a Repository Working Copy
+=====================================
+This section will assume that you will create a directory for your Qpid
+work. This directory will be referred to below as C:\qpid.
+
+To get the source code from the subversion repository (trunk) do:
+
+ C:\qpid> svn checkout https://svn.apache.org/repos/asf/qpid/trunk
+
+The first step in the build is to configure and generate the Visual
+Studio projects. This step also generates a significant number of source
+files that are part of the build.
+
+- Run CMakeSetup. The CMake binary install often leaves a shortcut to
+ CMakeSetup on the desktop - it is named CMake.
+- The CMakeSetup window has 2 directory selection areas at the top; one for
+ where the source is located (C:\qpid\trunk\qpid\cpp) and one for where you
+ wish to place the build. A directory separate from the source directory is
+ generally preferred; it can be, but need not be, a subdirectory to the
+ source. (C:\qpid\build)
+- The first time you run CMakeSetup it will ask you to select a generator.
+ You should select the method you prefer to build with: Visual Studio 2008
+ or NMake Makefiles.
+- The Cache Values area of the window is where the system and build settings
+ are displayed. You can change these by clicking on the values if desired.
+- Click the Configure button. The first time Qpid is configured this step may
+ take a few minutes and you will see lots of messages about generated source
+ files. If the Cache Values area has any red lines, change or correct the
+ value if needed (it may only be red because it's new - you only need to
+ change/correct items that correspond to errors in configuration). Click
+ Configure again. Repeat until all the Cache Values are gray.
+- Click the OK button to generate the project/make files.
+
+Now follow instruction for building from a source distribution in step (3).
+
+
+5. Tests
+========
+See src/tests/README for details.
+
+
+6. Doxygen
+==========
+Doxygen generates documentation in several formats from source code
+using special comments. You can use javadoc style comments if you know
+javadoc, if you don't or want to know the fully story on doxygen
+markup see http://www.stack.nl/~dimitri/doxygen/
+
+Even even if the code is completely uncommented, doxygen generates
+UML-esque dependency diagrams that are ''extremely'' useful in navigating
+around the code, especially for newcomers.
+
+The user-level API documentation can be generated by building the
+user-api-docs project from the generated Visual Studio solution. The
+documentation is generated into the docs/api/html directory under your
+build directory.
+
+
+7. Troubleshooting
+==================
+
+When the broker is executed it will try to store a file in the "qpidd"
+subdirectory of the current user's temporary file directory, or in
+C:\WINDOWS\TEMP. If the qpidd directory can't be created or accessed the
+broker startup will fail.
diff --git a/cpp/LICENSE b/cpp/LICENSE
index 6b0b1270ff..cff2a5e25d 100644
--- a/cpp/LICENSE
+++ b/cpp/LICENSE
@@ -1,3 +1,6 @@
+=========================================================================
+== Apache License ==
+=========================================================================
Apache License
Version 2.0, January 2004
@@ -201,3 +204,31 @@
See the License for the specific language governing permissions and
limitations under the License.
+=========================================================================
+== Boost License ==
+=========================================================================
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
diff --git a/cpp/Makefile.am b/cpp/Makefile.am
index a996db4eac..6db7ffd46e 100644
--- a/cpp/Makefile.am
+++ b/cpp/Makefile.am
@@ -1,38 +1,33 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+LIBTOOL_DEPS = @LIBTOOL_DEPS@
+
AUTOMAKE_OPTIONS = 1.9.2 foreign
ACLOCAL_AMFLAGS = -I m4
-SPEC=$(PACKAGE).spec
-
EXTRA_DIST = \
- LICENSE NOTICE README RELEASE_NOTES DESIGN\
- $(SPEC) $(SPEC).in \
- rpm/README.qpidd-devel \
- xml/cluster.xml
+ LICENSE NOTICE README SSL RELEASE_NOTES DESIGN \
+ xml/cluster.xml INSTALL-WINDOWS CMakeLists.txt BuildInstallSettings.cmake
-SUBDIRS = managementgen etc src docs/api docs/man examples
+SUBDIRS = managementgen etc src docs/api docs/man examples bindings/qmf
# Update libtool, if needed.
libtool: $(LIBTOOL_DEPS)
$(SHELL) ./config.status --recheck
-
-#
-# Build RPMs from the distribution tarball.
-#
-RPMDIRS=rpm/BUILD rpm/RPMS rpm/SPECS rpm/SRPMS
-RPMMACROS=--define "_topdir @abs_builddir@/rpm" --define "_sourcedir @abs_builddir@"
-# Override this variable e.g. with -bs to produce srpm only
-RPMOPTS=-ba
-
-clean-local:
- -rm -rf $(RPMDIRS)
-
-.PHONY: rpmbuild
-
-rpmbuild: $(SPEC) dist-gzip
- mkdir -p $(RPMDIRS)
- QPID_PYTHON_DIR=@abs_top_srcdir@/../python rpmbuild $(RPMMACROS) $(RPMOPTS) $(SPEC)
-if HAS_RPMLINT
- rpmlint `find rpm -name '*.rpm'`
-else
- @echo "WARNING: rpmlint not found, could not validate RPMs."
-endif
diff --git a/cpp/NOTICE b/cpp/NOTICE
index cae69a873a..5de355a56c 100644
--- a/cpp/NOTICE
+++ b/cpp/NOTICE
@@ -10,16 +10,12 @@ This product includes software developed by the Apache Software Foundation
Please read the LICENSE file present in the root directory of this
distribution.
-
Aside from contributions to the Apache Qpid project, this software also
includes (binary only):
- None at this time
Project requires, not packaged:
- * apr version 1.2.7 or later under the Apache Software License, Version 2.0,
- and can be downloded from http://apr.apache.org
-
* boost version 1.33.1 or later under the Boost Software License, and
can be downloaded from http://www.boost.org
- - Included in most OS platfroms by defualt.
+ - Included in most OS platforms by default.
diff --git a/cpp/README b/cpp/README
index e008f5b45b..a16dec09c4 100644
--- a/cpp/README
+++ b/cpp/README
@@ -5,6 +5,7 @@ Table of Contents
=================
1. Introduction
2. Available Documentation
+3. Quick start
1. Introduction
@@ -22,8 +23,16 @@ http://cwiki.apache.org/qpid/
2. Available Documentation
==========================
- INSTALL - How to install Qpid/C++.
+ - SSL - How to setup SSL
- RELEASE_NOTES - Release notes.
- - DESIGN - Qpid/C++ implementation.
- - LICENSE - Apache license.
- - NOTICE - Corresponds to the section 4 d of
- the Apache License, Version 2.0.
+ - DESIGN - Qpid/C++ implementation.
+ - LICENSE - Apache license.
+ - NOTICE - Corresponds to the section 4 d of
+ the Apache License, Version 2.0.
+
+3. Quick start
+==============
+If you are impatient to get on, ./configure && make will usually be
+sufficient to compile. Running make check will run tests, make install
+will install the client and daemon. For more detailed information,
+please see the INSTALL notes.
diff --git a/cpp/RELEASE_NOTES b/cpp/RELEASE_NOTES
index 819539b1ec..b861503f9d 100644
--- a/cpp/RELEASE_NOTES
+++ b/cpp/RELEASE_NOTES
@@ -1,41 +1,21 @@
-Apache Incubator Qpid C++ M2 Release Notes
--------------------------------------------
+Apache Qpid C++ M4 Release Notes
+--------------------------------
-The Qpid M2 release contains support the for AMQP 0-8 specification.
-You can access the 0-8 specification using the following link.
-http://www.amqp.org/tikiwiki/tiki-index.php?page=Download
+The Qpid M4 release of the c++ client and broker support the 0-10
+version of the AMQP specification. You can access this specification
+from:
-For full details of Qpid capabilities, as they currently stand, see our
-detailed project documentation at:
+http://jira.amqp.org/confluence/display/AMQP/Download
-http://cwiki.apache.org/confluence/pages/viewpage.action?pageId=28284
-
-Please take time to go through the README file provided with the distro to get a good understanding about build system etc.
-
-
-Known Issues
-------------
-
-You can view the outstanding task list for Qpid by visiting our JIRA:
-http://issues.apache.org/jira/browse/QPID
+Notable additions for the M$ release includes, the c++ client API had improvements done to make it more user friendly. The c++ broker has a windows port, acl support, SSL support, performance enhancements and clustering (experimental).
-Bug QPID-437 c++ broker doesn't obey the mandatory flag
+Please note that due to c++ client API changes, it is likely that programs written against the M3 client will not compile.
+You will need to change to the new API thats described at http://qpid.apache.org/docs/api/html/
+For full details of Qpid c++ capabilities, as they currently stand,
+see our project documentation at:
-M2 Tasks Completed
--------------------
-
-Test QPID-412 Implement initial C++ interop tests
-Task QPID-124 Connect AMQP version from ProtocolInitiation object to all version-aware objects
-
-New Feature QPID-154 Logging/tracing for C++.
-New Feature QPID-98 implement durable exchanges
-New Feature QPID-41 Persistent storage for messages & durable queues
-
-Improvement QPID-450 C++ demos
-Improvement QPID-64 C++ cluster design.
-Improvement QPID-62 C++ event queue design.
+http://cwiki.apache.org/confluence/pages/viewpage.action?pageId=28284
-Bug QPID-481 c++ broker dosen't implement channel.flow
-Bug QPID-467 Complete Interop Testing
-Bug QPID-123 Sporadic failure on Python tests
+Please take time to go through the README file provided with the
+distro to get a good understanding about build system etc.
diff --git a/cpp/SSL b/cpp/SSL
new file mode 100644
index 0000000000..4f80e77479
--- /dev/null
+++ b/cpp/SSL
@@ -0,0 +1,71 @@
+ Using SSL
+ =========
+
+SSL support for Qpid-C++, based on Mozilla's Network Security Services
+library, is provided as two loadable modules: one for the client
+(sslconnector.so), one for the broker (ssl.so). Either these libraries
+should be present in the relevant module directory or the
+'load-module' option (or QPID_LOAD_MODULE environment variable) is
+used to ensure they are loaded.
+
+Broker side SSL Settings (note you can get these by qpidd --help
+providing the ssl.so module is loaded):
+
+SSL Settings:
+ --ssl-use-export-policy Use NSS export policy
+ --ssl-cert-password-file PATH File containing password to use for
+ accessing certificate database
+ --ssl-cert-db PATH Path to directory containing certificate
+ database
+ --ssl-cert-name NAME (thinkpad) Name of the certificate to use
+ --ssl-port PORT (5671) Port on which to listen for SSL
+ connections
+ --ssl-require-client-authentication Forces clients to authenticate in order
+ to establish an SSL connection
+
+
+The first four of these are also available as client options (where
+they must either be in the client config file or set as environment
+variables e.g. QPID_SSL_CERT_DB).
+
+To run either the broker or client you need ssl-cert-db-path to point
+to the directory where relevant certificate and key databases can be
+found.
+
+Certificate databases are set up using certutil (included in the
+nss-tools package on fedora). See the NSS site for examples[1] and
+full details[2].
+
+For a simple testing you can set up a single db with a single self
+signed certificate. E.g (with myhost and mydomain replaced by the
+hostname and domainname of the machine in question respectively):
+
+ mkdir test_cert_db
+ certutil -N -d test_cert_db -f cert.password
+ certutil -S -d test_cert_db -n "myhost.mydomain" \
+ -s "CN=myhost.mydomain" -t "CT,," -x \
+ -f cert.password -z /usr/bin/certutil
+
+Here cert.password is a file with a password in it that will be needed
+for accessing the created db.
+
+The daemon can then be started with something like the following:
+
+./src/qpidd --auth no --load-module src/.libs/ssl.so \
+ --ssl-cert-db ./test_cert_db \
+ --ssl-cert-password-file ./cert.password \
+ --ssl-cert-name myhost.mydomain
+
+then for client set:
+
+QPID_LOAD_MODULE=./src/.libs/sslconnector.so
+QPID_SSL_CERT_DB=./test_cert_db
+
+and run e.g.
+
+./src/tests/perftest --count 10000 -P ssl --port 5671 \
+ --broker myhost.mydomain
+
+
+[1] http://www.mozilla.org/projects/security/pki/nss/ref/ssl/gtstd.html
+[2] http://www.mozilla.org/projects/security/pki/nss/tools/certutil.html
diff --git a/cpp/bindings/qmf/Makefile.am b/cpp/bindings/qmf/Makefile.am
new file mode 100644
index 0000000000..eebb4b94de
--- /dev/null
+++ b/cpp/bindings/qmf/Makefile.am
@@ -0,0 +1,33 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+if HAVE_SWIG
+
+EXTRA_DIST = qmfengine.i
+SUBDIRS = tests
+
+if HAVE_RUBY_DEVEL
+SUBDIRS += ruby
+endif
+
+if HAVE_PYTHON_DEVEL
+SUBDIRS += python
+endif
+
+endif
diff --git a/cpp/bindings/qmf/python/Makefile.am b/cpp/bindings/qmf/python/Makefile.am
new file mode 100644
index 0000000000..53303c7be9
--- /dev/null
+++ b/cpp/bindings/qmf/python/Makefile.am
@@ -0,0 +1,48 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+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
+
+generated_file_list = \
+ qmfengine.cpp \
+ qmfengine.py
+
+EXTRA_DIST = python.i
+BUILT_SOURCES = $(generated_file_list)
+
+$(generated_file_list): $(srcdir)/python.i $(srcdir)/../qmfengine.i
+ swig -c++ -python -Wall -I/usr/include $(INCLUDES) $(QPID_CXXFLAGS) -I$(top_srcdir)/src/qmf -o qmfengine.cpp $(srcdir)/python.i
+
+pylibdir = $(PYTHON_LIB)
+
+lib_LTLIBRARIES = _qmfengine.la
+
+#_qmfengine_la_LDFLAGS = -avoid-version -module -shrext "$(PYTHON_SO)"
+#_qmfengine_la_LDFLAGS = -avoid-version -module -shrext ".so"
+_qmfengine_la_LDFLAGS = -avoid-version -module -shared
+_qmfengine_la_LIBADD = $(PYTHON_LIBS) -L$(top_builddir)/src/.libs -lqpidclient $(top_builddir)/src/libqmf.la
+_qmfengine_la_CXXFLAGS = $(INCLUDES) -I$(srcdir)/qmf -I$(PYTHON_INC)
+nodist__qmfengine_la_SOURCES = qmfengine.cpp
+
+CLEANFILES = $(generated_file_list)
+
+endif # HAVE_PYTHON_DEVEL
+
diff --git a/cpp/bindings/qmf/python/python.i b/cpp/bindings/qmf/python/python.i
new file mode 100644
index 0000000000..5e25d155f9
--- /dev/null
+++ b/cpp/bindings/qmf/python/python.i
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 qmfengine
+
+
+/* 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);
+}
+
+%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;
+}
+
+
+
+%include "../qmfengine.i"
+
diff --git a/cpp/bindings/qmf/python/qmf.py b/cpp/bindings/qmf/python/qmf.py
new file mode 100644
index 0000000000..233f1c83d8
--- /dev/null
+++ b/cpp/bindings/qmf/python/qmf.py
@@ -0,0 +1,1540 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+import sys
+import socket
+import os
+import logging
+from threading import Thread
+from threading import RLock
+from threading import Condition
+import qmfengine
+from qmfengine import (ACCESS_READ_CREATE, ACCESS_READ_ONLY, ACCESS_READ_WRITE)
+from qmfengine import (CLASS_EVENT, CLASS_OBJECT)
+from qmfengine import (DIR_IN, DIR_IN_OUT, DIR_OUT)
+from qmfengine import (TYPE_ABSTIME, TYPE_ARRAY, TYPE_BOOL, TYPE_DELTATIME,
+ TYPE_DOUBLE, TYPE_FLOAT, TYPE_INT16, TYPE_INT32, TYPE_INT64,
+ TYPE_INT8, TYPE_LIST, TYPE_LSTR, TYPE_MAP, TYPE_OBJECT,
+ TYPE_REF, TYPE_SSTR, TYPE_UINT16, TYPE_UINT32, TYPE_UINT64,
+ TYPE_UINT8, TYPE_UUID)
+from qmfengine import (O_EQ, O_NE, O_LT, O_LE, O_GT, O_GE, O_RE_MATCH, O_RE_NOMATCH,
+ E_NOT, E_AND, E_OR, E_XOR)
+
+ ##==============================================================================
+ ## CONNECTION
+ ##==============================================================================
+
+class ConnectionSettings(object):
+ #attr_reader :impl
+ def __init__(self, url=None):
+ if url:
+ self.impl = qmfengine.ConnectionSettings(url)
+ else:
+ self.impl = qmfengine.ConnectionSettings()
+
+
+ def set_attr(self, key, val):
+ if type(val) == str:
+ _v = qmfengine.Value(TYPE_LSTR)
+ _v.setString(val)
+ elif type(val) == int:
+ _v = qmfengine.Value(TYPE_UINT32)
+ _v.setUint(val)
+ elif type(val) == bool:
+ _v = qmfengine.Value(TYPE_BOOL)
+ _v.setBool(val)
+ else:
+ raise Exception("Argument error: value for attribute '%s' has unsupported type: %s" % ( key, type(val)))
+
+ good = self.impl.setAttr(key, _v)
+ if not good:
+ raise Exception("Argument error: unsupported attribute '%s'" % key )
+
+
+ def get_attr(self, key):
+ _v = self.impl.getAttr(key)
+ if _v.isString():
+ return _v.asString()
+ elif _v.isUint():
+ return _v.asUint()
+ elif _v.isBool():
+ return _v.asBool()
+ else:
+ raise Exception("Argument error: value for attribute '%s' has unsupported type: %s" % ( key, str(_v.getType())))
+
+
+ def __getattr__(self, name):
+ return self.get_attr(name)
+
+
+ def __setattr__(self, name, value):
+ if name == "impl":
+ return super.__setattr__(self, name, value)
+ return self.set_attr(name, value)
+
+
+
+class ConnectionHandler:
+ def conn_event_connected(self): None
+ def conn_event_disconnected(self, error): None
+ def conn_event_visit(self): None
+ def sess_event_session_closed(self, context, error): None
+ def sess_event_recv(self, context, message): None
+
+
+
+class Connection(Thread):
+ def __init__(self, settings):
+ Thread.__init__(self)
+ self._lock = RLock()
+ self.impl = qmfengine.ResilientConnection(settings.impl)
+ self._sockEngine, self._sock = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
+ self.impl.setNotifyFd(self._sockEngine.fileno())
+ self._new_conn_handlers = []
+ self._conn_handlers_to_delete = []
+ self._conn_handlers = []
+ self._connected = False
+ self._operational = True
+ self.start()
+
+
+ def destroy(self, timeout=None):
+ logging.debug("Destroying Connection...")
+ self._operational = False
+ self.kick()
+ self.join(timeout)
+ logging.debug("... Conn Destroyed!" )
+ if self.isAlive():
+ logging.error("Error: Connection thread '%s' is hung..." % self.getName())
+
+
+ def connected(self):
+ return self._connected
+
+
+ def kick(self):
+ self._sockEngine.send(".")
+ # self._sockEngine.flush() Not available with python?
+
+
+ def add_conn_handler(self, handler):
+ self._lock.acquire()
+ try:
+ self._new_conn_handlers.append(handler)
+ finally:
+ self._lock.release()
+ self.kick()
+
+
+ def del_conn_handler(self, handler):
+ self._lock.acquire()
+ try:
+ self._conn_handlers_to_delete.append(handler)
+ finally:
+ self._lock.release()
+ self.kick()
+
+
+ def run(self):
+ eventImpl = qmfengine.ResilientConnectionEvent()
+ new_handlers = []
+ del_handlers = []
+ bt_count = 0
+
+ while self._operational:
+ logging.debug("Connection thread waiting for socket data...")
+ self._sock.recv(1)
+
+ self._lock.acquire()
+ try:
+ new_handlers = self._new_conn_handlers
+ del_handlers = self._conn_handlers_to_delete
+ self._new_conn_handlers = []
+ self._conn_handlers_to_delete = []
+ finally:
+ self._lock.release()
+
+ for nh in new_handlers:
+ self._conn_handlers.append(nh)
+ if self._connected:
+ nh.conn_event_connected()
+ new_handlers = []
+
+ for dh in del_handlers:
+ if dh in self._conn_handlers:
+ self._conn_handlers.remove(dh)
+ del_handlers = []
+
+ valid = self.impl.getEvent(eventImpl)
+ while valid:
+ try:
+ if eventImpl.kind == qmfengine.ResilientConnectionEvent.CONNECTED:
+ logging.debug("Connection thread: CONNECTED event received.")
+ self._connected = True
+ for h in self._conn_handlers:
+ h.conn_event_connected()
+
+ elif eventImpl.kind == qmfengine.ResilientConnectionEvent.DISCONNECTED:
+ logging.debug("Connection thread: DISCONNECTED event received.")
+ self._connected = False
+ for h in self._conn_handlers:
+ h.conn_event_disconnected(eventImpl.errorText)
+
+ elif eventImpl.kind == qmfengine.ResilientConnectionEvent.SESSION_CLOSED:
+ logging.debug("Connection thread: SESSION_CLOSED event received.")
+ eventImpl.sessionContext.handler.sess_event_session_closed(eventImpl.sessionContext, eventImpl.errorText)
+
+ elif eventImpl.kind == qmfengine.ResilientConnectionEvent.RECV:
+ logging.debug("Connection thread: RECV event received.")
+ eventImpl.sessionContext.handler.sess_event_recv(eventImpl.sessionContext, eventImpl.message)
+ else:
+ logging.debug("Connection thread received unknown event: '%s'" % str(eventImpl.kind))
+
+ except:
+ import traceback
+ logging.error( "Exception occurred during Connection event processing:" )
+ logging.error( str(sys.exc_info()) )
+ if bt_count < 2:
+ traceback.print_exc()
+ traceback.print_stack()
+ bt_count += 1
+
+ self.impl.popEvent()
+ valid = self.impl.getEvent(eventImpl)
+
+ for h in self._conn_handlers:
+ h.conn_event_visit()
+
+ logging.debug("Shutting down Connection thread")
+
+
+
+class Session:
+ def __init__(self, conn, label, handler):
+ self._conn = conn
+ self._label = label
+ self.handler = handler
+ self.handle = qmfengine.SessionHandle()
+ result = self._conn.impl.createSession(label, self, self.handle)
+
+
+ def destroy(self):
+ self._conn.impl.destroySession(self.handle)
+
+
+
+ ##==============================================================================
+ ## OBJECTS
+ ##==============================================================================
+
+class QmfObject(object):
+ # attr_reader :impl, :object_class
+ def __init__(self, cls, kwargs={}):
+ self._cv = Condition()
+ self._sync_count = 0
+ self._sync_result = None
+ self._allow_sets = False
+ if kwargs.has_key("broker"):
+ self._broker = kwargs["broker"]
+ else:
+ self._broker = None
+ if cls:
+ self.object_class = cls
+ self.impl = qmfengine.Object(self.object_class.impl)
+ elif kwargs.has_key("impl"):
+ self.impl = qmfengine.Object(kwargs["impl"])
+ self.object_class = SchemaObjectClass(None,
+ None,
+ {"impl":self.impl.getClass()})
+ else:
+ raise Exception("Argument error: required parameter ('impl') not supplied")
+
+
+ def destroy(self):
+ self.impl.destroy()
+
+
+ def object_id(self):
+ return ObjectId(self.impl.getObjectId())
+
+
+ def set_object_id(self, oid):
+ self.impl.setObjectId(oid.impl)
+
+
+ def properties(self):
+ list = []
+ for prop in self.object_class.properties:
+ list.append([prop, self.get_attr(prop.name())])
+ return list
+
+
+ def statistics(self):
+ list = []
+ for stat in self.object_class.statistics:
+ list.append([stat, self.get_attr(stat.name())])
+ return list
+
+
+ def get_attr(self, name):
+ val = self._value(name)
+ vType = val.getType()
+ if vType == TYPE_UINT8: return val.asUint()
+ elif vType == TYPE_UINT16: return val.asUint()
+ elif vType == TYPE_UINT32: return val.asUint()
+ elif vType == TYPE_UINT64: return val.asUint64()
+ elif vType == TYPE_SSTR: return val.asString()
+ elif vType == TYPE_LSTR: return val.asString()
+ elif vType == TYPE_ABSTIME: return val.asInt64()
+ elif vType == TYPE_DELTATIME: return val.asUint64()
+ elif vType == TYPE_REF: return ObjectId(val.asObjectId())
+ elif vType == TYPE_BOOL: return val.asBool()
+ elif vType == TYPE_FLOAT: return val.asFloat()
+ elif vType == TYPE_DOUBLE: return val.asDouble()
+ elif vType == TYPE_UUID: return val.asUuid()
+ elif vType == TYPE_INT8: return val.asInt()
+ elif vType == TYPE_INT16: return val.asInt()
+ elif vType == TYPE_INT32: return val.asInt()
+ elif vType == TYPE_INT64: return val.asInt64()
+ else:
+ # when TYPE_MAP
+ # when TYPE_OBJECT
+ # when TYPE_LIST
+ # when TYPE_ARRAY
+ logging.error( "Unsupported type for get_attr? '%s'" % str(val.getType()) )
+ return None
+
+
+ def set_attr(self, name, v):
+ val = self._value(name)
+ vType = val.getType()
+ if vType == TYPE_UINT8: return val.setUint(v)
+ elif vType == TYPE_UINT16: return val.setUint(v)
+ elif vType == TYPE_UINT32: return val.setUint(v)
+ elif vType == TYPE_UINT64: return val.setUint64(v)
+ elif vType == TYPE_SSTR:
+ if v: return val.setString(v)
+ else: return val.setString('')
+ elif vType == TYPE_LSTR:
+ if v: return val.setString(v)
+ else: return val.setString('')
+ elif vType == TYPE_ABSTIME: return val.setInt64(v)
+ elif vType == TYPE_DELTATIME: return val.setUint64(v)
+ elif vType == TYPE_REF: return val.setObjectId(v.impl)
+ elif vType == TYPE_BOOL: return val.setBool(v)
+ elif vType == TYPE_FLOAT: return val.setFloat(v)
+ elif vType == TYPE_DOUBLE: return val.setDouble(v)
+ elif vType == TYPE_UUID: return val.setUuid(v)
+ elif vType == TYPE_INT8: return val.setInt(v)
+ elif vType == TYPE_INT16: return val.setInt(v)
+ elif vType == TYPE_INT32: return val.setInt(v)
+ elif vType == TYPE_INT64: return val.setInt64(v)
+ else:
+ # when TYPE_MAP
+ # when TYPE_OBJECT
+ # when TYPE_LIST
+ # when TYPE_ARRAY
+ logging.error("Unsupported type for get_attr? '%s'" % str(val.getType()))
+ return None
+
+
+ def __getitem__(self, name):
+ return self.get_attr(name)
+
+
+ def __setitem__(self, name, value):
+ self.set_attr(name, value)
+
+
+ def inc_attr(self, name, by=1):
+ self.set_attr(name, self.get_attr(name) + by)
+
+
+ def dec_attr(self, name, by=1):
+ self.set_attr(name, self.get_attr(name) - by)
+
+
+ def __setattr__(self, name, value):
+ #
+ # Ignore the internal attributes, set them normally...
+ #
+ if (name[0] == '_' or
+ name == 'impl' or
+ name == 'object_class'):
+ return super.__setattr__(self, name, value)
+
+ if not self._allow_sets:
+ raise Exception("'Set' operations not permitted on this object")
+ #
+ # If the name matches a property name, set the value of the property.
+ #
+ # print "set name=%s" % str(name)
+ for prop in self.object_class.properties:
+ if prop.name() == name:
+ return self.set_attr(name, value)
+ #
+ # otherwise, check for a statistic set...
+ #
+ for stat in self.object_class.statistics:
+ if stat.name() == name:
+ return self.set_attr(name, value)
+
+ # unrecognized name? should I raise an exception?
+ super.__setattr__(self, name, value)
+
+
+ def __getattr__(self, name, *args):
+ #
+ # If the name matches a property name, return the value of the property.
+ #
+ for prop in self.object_class.properties:
+ if prop.name() == name:
+ return self.get_attr(name)
+ #
+ # Do the same for statistics
+ #
+ for stat in self.object_class.statistics:
+ if stat.name() == name:
+ return self.get_attr(name)
+ #
+ # If we still haven't found a match for the name, check to see if
+ # it matches a method name. If so, marshall up the arguments into
+ # a map, and invoke the method.
+ #
+ for method in self.object_class.methods:
+ if method.name() == name:
+ argMap = self._marshall(method, args)
+ return lambda name, argMap : self._invokeMethod(name, argMap)
+
+ #
+ # This name means nothing to us, pass it up the line to the parent
+ # class's handler.
+ #
+ # print "__getattr__=%s" % str(name)
+ super.__getattr__(self, name)
+
+
+ def _invokeMethod(self, name, argMap):
+ """
+ Private: Helper function that invokes an object's method, and waits for the result.
+ """
+ self._cv.acquire()
+ try:
+ timeout = 30
+ self._sync_count = 1
+ self.impl.invokeMethod(name, argMap, self)
+ if self._broker:
+ self._broker.conn.kick()
+ self._cv.wait(timeout)
+ if self._sync_count == 1:
+ raise Exception("Timed out: waiting for response to method call.")
+ finally:
+ self._cv.release()
+
+ return self._sync_result
+
+
+ def _method_result(self, result):
+ """
+ Called to return the result of a method call on an object
+ """
+ self._cv.acquire();
+ try:
+ self._sync_result = result
+ self._sync_count -= 1
+ self._cv.notify()
+ finally:
+ self._cv.release()
+
+
+ def _marshall(schema, args):
+ '''
+ Private: Convert a list of arguments (positional) into a Value object of type "map".
+ Used to create the argument parameter for an object's method invokation.
+ '''
+ # Build a map of the method's arguments
+ map = qmfengine.Value(TYPE_MAP)
+ for arg in schema.arguments:
+ if arg.direction == DIR_IN or arg.direction == DIR_IN_OUT:
+ map.insert(arg.name, qmfengine.Value(arg.typecode))
+
+ # install each argument's value into the map
+ marshalled = Arguments(map)
+ idx = 0
+ for arg in schema.arguments:
+ if arg.direction == DIR_IN or arg.direction == DIR_IN_OUT:
+ if args[idx]:
+ marshalled[arg.name] = args[idx]
+ idx += 1
+
+ return marshalled.map
+
+
+ def _value(self, name):
+ val = self.impl.getValue(name)
+ if not val:
+ raise Exception("Argument error: attribute named '%s' not defined for package %s, class %s" %
+ (name,
+ self.object_class.impl.getClassKey().getPackageName(),
+ self.object_class.impl.getClassKey().getClassName()))
+ return val
+
+
+
+class AgentObject(QmfObject):
+ def __init__(self, cls, kwargs={}):
+ QmfObject.__init__(self, cls, kwargs)
+ self._allow_sets = True
+
+
+ def destroy(self):
+ self.impl.destroy()
+
+
+ def set_object_id(self, oid):
+ self.impl.setObjectId(oid.impl)
+
+
+
+class ConsoleObject(QmfObject):
+ # attr_reader :current_time, :create_time, :delete_time
+ def __init__(self, cls, kwargs={}):
+ QmfObject.__init__(self, cls, kwargs)
+
+
+ def update(self):
+ if not self._broker:
+ raise Exception("No linkage to broker")
+ newer = self._broker.console.objects(Query({"object_id":object_id}))
+ if newer.size != 1:
+ raise Exception("Expected exactly one update for this object, %d present" % int(newer.size))
+ self.merge_update(newer[0])
+
+
+ def merge_update(self, newObject):
+ self.impl.merge(new_object.impl)
+
+
+ def is_deleted(self):
+ return self.impl.isDeleted()
+
+
+ def key(self): pass
+
+
+
+class ObjectId:
+ def __init__(self, impl=None):
+ if impl:
+ self.impl = impl
+ else:
+ self.impl = qmfengine.ObjectId()
+ self.agent_key = "%d.%d" % (self.impl.getBrokerBank(), self.impl.getAgentBank())
+
+
+ def object_num_high(self):
+ return self.impl.getObjectNumHi()
+
+
+ def object_num_low(self):
+ return self.impl.getObjectNumLo()
+
+
+ def agent_key(self):
+ self.agent_key
+
+ def __eq__(self, other):
+ if not isinstance(other, self.__class__): return False
+ return self.impl == other.impl
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def __repr__(self):
+ return self.impl.str()
+
+
+
+class Arguments(object):
+ def __init__(self, map):
+ self.map = map
+ self._by_hash = {}
+ key_count = self.map.keyCount()
+ a = 0
+ while a < key_count:
+ self._by_hash[self.map.key(a)] = self.by_key(self.map.key(a))
+ a += 1
+
+
+ def __getitem__(self, key):
+ return self._by_hash[key]
+
+
+ def __setitem__(self, key, value):
+ self._by_hash[key] = value
+ self.set(key, value)
+
+
+ def __iter__(self):
+ return self._by_hash.__iter__
+
+
+ def __getattr__(self, name):
+ if name in self._by_hash:
+ return self._by_hash[name]
+ return super.__getattr__(self, name)
+
+
+ def __setattr__(self, name, value):
+ #
+ # ignore local data members
+ #
+ if (name[0] == '_' or
+ name == 'map'):
+ return super.__setattr__(self, name, value)
+
+ if name in self._by_hash:
+ self._by_hash[name] = value
+ return self.set(name, value)
+
+ return super.__setattr__(self, name, value)
+
+
+ def by_key(self, key):
+ val = self.map.byKey(key)
+ vType = val.getType()
+ if vType == TYPE_UINT8: return val.asUint()
+ elif vType == TYPE_UINT16: return val.asUint()
+ elif vType == TYPE_UINT32: return val.asUint()
+ elif vType == TYPE_UINT64: return val.asUint64()
+ elif vType == TYPE_SSTR: return val.asString()
+ elif vType == TYPE_LSTR: return val.asString()
+ elif vType == TYPE_ABSTIME: return val.asInt64()
+ elif vType == TYPE_DELTATIME: return val.asUint64()
+ elif vType == TYPE_REF: return ObjectId(val.asObjectId())
+ elif vType == TYPE_BOOL: return val.asBool()
+ elif vType == TYPE_FLOAT: return val.asFloat()
+ elif vType == TYPE_DOUBLE: return val.asDouble()
+ elif vType == TYPE_UUID: return val.asUuid()
+ elif vType == TYPE_INT8: return val.asInt()
+ elif vType == TYPE_INT16: return val.asInt()
+ elif vType == TYPE_INT32: return val.asInt()
+ elif vType == TYPE_INT64: return val.asInt64()
+ else:
+ # when TYPE_MAP
+ # when TYPE_OBJECT
+ # when TYPE_LIST
+ # when TYPE_ARRAY
+ logging.error( "Unsupported Type for Get? '%s'" % str(val.getType()))
+ return None
+
+
+ def set(self, key, value):
+ val = self.map.byKey(key)
+ vType = val.getType()
+ if vType == TYPE_UINT8: return val.setUint(value)
+ elif vType == TYPE_UINT16: return val.setUint(value)
+ elif vType == TYPE_UINT32: return val.setUint(value)
+ elif vType == TYPE_UINT64: return val.setUint64(value)
+ elif vType == TYPE_SSTR:
+ if value:
+ return val.setString(value)
+ else:
+ return val.setString('')
+ elif vType == TYPE_LSTR:
+ if value:
+ return val.setString(value)
+ else:
+ return val.setString('')
+ elif vType == TYPE_ABSTIME: return val.setInt64(value)
+ elif vType == TYPE_DELTATIME: return val.setUint64(value)
+ elif vType == TYPE_REF: return val.setObjectId(value.impl)
+ elif vType == TYPE_BOOL: return val.setBool(value)
+ elif vType == TYPE_FLOAT: return val.setFloat(value)
+ elif vType == TYPE_DOUBLE: return val.setDouble(value)
+ elif vType == TYPE_UUID: return val.setUuid(value)
+ elif vType == TYPE_INT8: return val.setInt(value)
+ elif vType == TYPE_INT16: return val.setInt(value)
+ elif vType == TYPE_INT32: return val.setInt(value)
+ elif vType == TYPE_INT64: return val.setInt64(value)
+ else:
+ # when TYPE_MAP
+ # when TYPE_OBJECT
+ # when TYPE_LIST
+ # when TYPE_ARRAY
+ logging.error("Unsupported Type for Set? '%s'" % str(val.getType()))
+ return None
+
+
+
+class MethodResponse(object):
+ def __init__(self, impl):
+ self.impl = qmfengine.MethodResponse(impl)
+
+
+ def status(self):
+ return self.impl.getStatus()
+
+
+ def exception(self):
+ return self.impl.getException()
+
+
+ def text(self):
+ return exception().asString()
+
+
+ def args(self):
+ return Arguments(self.impl.getArgs())
+
+
+ def __getattr__(self, name):
+ myArgs = self.args()
+ return myArgs.__getattr__(name)
+
+
+ def __setattr__(self, name, value):
+ if name == 'impl':
+ return super.__setattr__(self, name, value)
+
+ myArgs = self.args()
+ return myArgs.__setattr__(name, value)
+
+
+
+ ##==============================================================================
+ ## QUERY
+ ##==============================================================================
+
+
+class Query:
+ def __init__(self, kwargs={}):
+ if "impl" in kwargs:
+ self.impl = kwargs["impl"]
+ else:
+ package = ''
+ if "key" in kwargs:
+ # construct using SchemaClassKey:
+ self.impl = qmfengine.Query(kwargs["key"])
+ elif "object_id" in kwargs:
+ self.impl = qmfengine.Query(kwargs["object_id"].impl)
+ else:
+ if "package" in kwargs:
+ package = kwargs["package"]
+ if "class" in kwargs:
+ self.impl = qmfengine.Query(kwargs["class"], package)
+ else:
+ raise Exception("Argument error: invalid arguments, use 'key', 'object_id' or 'class'[,'package']")
+
+
+ def package_name(self): return self.impl.getPackage()
+ def class_name(self): return self.impl.getClass()
+ def object_id(self):
+ _objid = self.impl.getObjectId()
+ if _objid:
+ return ObjectId(_objid)
+ else:
+ return None
+
+
+ ##==============================================================================
+ ## SCHEMA
+ ##==============================================================================
+
+
+
+class SchemaArgument:
+ #attr_reader :impl
+ def __init__(self, name, typecode, kwargs={}):
+ if "impl" in kwargs:
+ self.impl = kwargs["impl"]
+ else:
+ self.impl = qmfengine.SchemaArgument(name, typecode)
+ if kwargs.has_key("dir"): self.impl.setDirection(kwargs["dir"])
+ if kwargs.has_key("unit"): self.impl.setUnit(kwargs["unit"])
+ if kwargs.has_key("desc"): self.impl.setDesc(kwargs["desc"])
+
+
+ def name(self):
+ return self.impl.getName()
+
+
+ def direction(self):
+ return self.impl.getDirection()
+
+
+ def typecode(self):
+ return self.impl.getType()
+
+
+ def __repr__(self):
+ return self.name()
+
+
+
+class SchemaMethod:
+ # attr_reader :impl, arguments
+ def __init__(self, name, kwargs={}):
+ self.arguments = []
+ if "impl" in kwargs:
+ self.impl = kwargs["impl"]
+ for i in range(self.impl.getArgumentCount()):
+ self.arguments.append(SchemaArgument(None,None,{"impl":self.impl.getArgument(i)}))
+ else:
+ self.impl = qmfengine.SchemaMethod(name)
+ if kwargs.has_key("desc"): self.impl.setDesc(kwargs["desc"])
+
+
+ def add_argument(self, arg):
+ self.arguments.append(arg)
+ self.impl.addArgument(arg.impl)
+
+ def name(self):
+ return self.impl.getName()
+
+ def __repr__(self):
+ return self.name()
+
+
+
+class SchemaProperty:
+ #attr_reader :impl
+ def __init__(self, name, typecode, kwargs={}):
+ if "impl" in kwargs:
+ self.impl = kwargs["impl"]
+ else:
+ self.impl = qmfengine.SchemaProperty(name, typecode)
+ if kwargs.has_key("access"): self.impl.setAccess(kwargs["access"])
+ if kwargs.has_key("index"): self.impl.setIndex(kwargs["index"])
+ if kwargs.has_key("optional"): self.impl.setOptional(kwargs["optional"])
+ if kwargs.has_key("unit"): self.impl.setUnit(kwargs["unit"])
+ if kwargs.has_key("desc"): self.impl.setDesc(kwargs["desc"])
+
+
+ def name(self):
+ return self.impl.getName()
+
+ def __repr__(self):
+ return self.name()
+
+
+
+class SchemaStatistic:
+ # attr_reader :impl
+ def __init__(self, name, typecode, kwargs={}):
+ if "impl" in kwargs:
+ self.impl = kwargs["impl"]
+ else:
+ self.impl = qmfengine.SchemaStatistic(name, typecode)
+ if kwargs.has_key("unit"): self.impl.setUnit(kwargs["unit"])
+ if kwargs.has_key("desc"): self.impl.setDesc(kwargs["desc"])
+
+
+ def name(self):
+ return self.impl.getName()
+
+ def __repr__(self):
+ return self.name()
+
+
+
+class SchemaClassKey:
+ #attr_reader :impl
+ def __init__(self, i):
+ self.impl = i
+
+
+ def package_name(self):
+ return self.impl.getPackageName()
+
+
+ def class_name(self):
+ return self.impl.getClassName()
+
+ def __repr__(self):
+ return self.impl.asString()
+
+
+
+class SchemaObjectClass:
+ # attr_reader :impl, :properties, :statistics, :methods
+ def __init__(self, package, name, kwargs={}):
+ self.properties = []
+ self.statistics = []
+ self.methods = []
+ if "impl" in kwargs:
+ self.impl = kwargs["impl"]
+
+ for i in range(self.impl.getPropertyCount()):
+ self.properties.append(SchemaProperty(None, None, {"impl":self.impl.getProperty(i)}))
+
+ for i in range(self.impl.getStatisticCount()):
+ self.statistics.append(SchemaStatistic(None, None, {"impl":self.impl.getStatistic(i)}))
+
+ for i in range(self.impl.getMethodCount()):
+ self.methods.append(SchemaMethod(None, {"impl":self.impl.getMethod(i)}))
+ else:
+ self.impl = qmfengine.SchemaObjectClass(package, name)
+
+
+ def add_property(self, prop):
+ self.properties.append(prop)
+ self.impl.addProperty(prop.impl)
+
+
+ def add_statistic(self, stat):
+ self.statistics.append(stat)
+ self.impl.addStatistic(stat.impl)
+
+
+ def add_method(self, meth):
+ self.methods.append(meth)
+ self.impl.addMethod(meth.impl)
+
+
+ def class_key(self):
+ return SchemaClassKey(self.impl.getClassKey())
+
+
+ def package_name(self):
+ return self.impl.getClassKey().getPackageName()
+
+
+ def class_name(self):
+ return self.impl.getClassKey().getClassName()
+
+
+
+class SchemaEventClass:
+ # attr_reader :impl :arguments
+ def __init__(self, package, name, kwargs={}):
+ self.arguments = []
+ if "impl" in kwargs:
+ self.impl = kwargs["impl"]
+ for i in range(self.impl.getArgumentCount()):
+ self.arguments.append(SchemaArgument(nil, nil, {"impl":self.impl.getArgument(i)}))
+ else:
+ self.impl = qmfengine.SchemaEventClass(package, name)
+ if kwargs.has_key("desc"): self.impl.setDesc(kwargs["desc"])
+
+
+ def add_argument(self, arg):
+ self.arguments.append(arg)
+ self.impl.addArgument(arg.impl)
+
+
+ def name(self):
+ return self.impl.getClassKey().getClassName()
+
+
+ ##==============================================================================
+ ## CONSOLE
+ ##==============================================================================
+
+
+
+class ConsoleHandler:
+ def agent_added(self, agent): pass
+ def agent_deleted(self, agent): pass
+ def new_package(self, package): pass
+ def new_class(self, class_key): pass
+ def object_update(self, obj, hasProps, hasStats): pass
+ def event_received(self, event): pass
+ def agent_heartbeat(self, agent, timestamp): pass
+ def method_response(self, resp): pass
+ def broker_info(self, broker): pass
+
+
+
+class Console(Thread):
+ # attr_reader :impl
+ def __init__(self, handler=None, kwargs={}):
+ Thread.__init__(self)
+ self._handler = handler
+ self.impl = qmfengine.Console()
+ self._event = qmfengine.ConsoleEvent()
+ self._broker_list = []
+ self._cv = Condition()
+ self._sync_count = 0
+ self._sync_result = None
+ self._select = {}
+ self._cb_cond = Condition()
+ self._operational = True
+ self.start()
+
+
+ def destroy(self, timeout=None):
+ logging.debug("Destroying Console...")
+ self._operational = False
+ self.start_console_events() # wake thread up
+ self.join(timeout)
+ logging.debug("... Console Destroyed!")
+ if self.isAlive():
+ logging.error( "Console thread '%s' is hung..." % self.getName() )
+
+
+ def add_connection(self, conn):
+ broker = Broker(self, conn)
+ self._cv.acquire()
+ try:
+ self._broker_list.append(broker)
+ finally:
+ self._cv.release()
+ return broker
+
+
+ def del_connection(self, broker):
+ logging.debug("shutting down broker...")
+ broker.shutdown()
+ logging.debug("...broker down.")
+ self._cv.acquire()
+ try:
+ self._broker_list.remove(broker)
+ finally:
+ self._cv.release()
+ logging.debug("del_connection() finished")
+
+
+ def packages(self):
+ plist = []
+ for i in range(self.impl.packageCount()):
+ plist.append(self.impl.getPackageName(i))
+ return plist
+
+
+ def classes(self, package, kind=CLASS_OBJECT):
+ clist = []
+ for i in range(self.impl.classCount(package)):
+ key = self.impl.getClass(package, i)
+ class_kind = self.impl.getClassKind(key)
+ if class_kind == kind:
+ if kind == CLASS_OBJECT:
+ clist.append(SchemaObjectClass(None, None, {"impl":self.impl.getObjectClass(key)}))
+ elif kind == CLASS_EVENT:
+ clist.append(SchemaEventClass(None, None, {"impl":self.impl.getEventClass(key)}))
+ return clist
+
+
+ def bind_package(self, package):
+ return self.impl.bindPackage(package)
+
+
+ def bind_class(self, kwargs = {}):
+ if "key" in kwargs:
+ self.impl.bindClass(kwargs["key"])
+ elif "package" in kwargs:
+ package = kwargs["package"]
+ if "class" in kwargs:
+ self.impl.bindClass(package, kwargs["class"])
+ else:
+ self.impl.bindClass(package)
+ else:
+ raise Exception("Argument error: invalid arguments, use 'key' or 'package'[,'class']")
+
+
+ def agents(self, broker=None):
+ blist = []
+ if broker:
+ blist.append(broker)
+ else:
+ self._cv.acquire()
+ try:
+ # copy while holding lock
+ blist = self._broker_list[:]
+ finally:
+ self._cv.release()
+
+ agents = []
+ for b in blist:
+ for idx in range(b.impl.agentCount()):
+ agents.append(AgentProxy(b.impl.getAgent(idx), b))
+
+ return agents
+
+
+ def objects(self, query, kwargs = {}):
+ timeout = 30
+ agent = None
+ temp_args = kwargs.copy()
+ if type(query) == type({}):
+ temp_args.update(query)
+
+ if "_timeout" in temp_args:
+ timeout = temp_args["_timeout"]
+ temp_args.pop("_timeout")
+
+ if "_agent" in temp_args:
+ agent = temp_args["_agent"]
+ temp_args.pop("_agent")
+
+ if type(query) == type({}):
+ query = Query(temp_args)
+
+ self._select = {}
+ for k in temp_args.iterkeys():
+ if type(k) == str:
+ self._select[k] = temp_args[k]
+
+ self._cv.acquire()
+ try:
+ self._sync_count = 1
+ self._sync_result = []
+ broker = self._broker_list[0]
+ broker.send_query(query.impl, None, agent)
+ self._cv.wait(timeout)
+ if self._sync_count == 1:
+ raise Exception("Timed out: waiting for query response")
+ finally:
+ self._cv.release()
+
+ return self._sync_result
+
+
+ def object(self, query, kwargs = {}):
+ '''
+ Return one and only one object or None.
+ '''
+ objs = objects(query, kwargs)
+ if len(objs) == 1:
+ return objs[0]
+ else:
+ return None
+
+
+ def first_object(self, query, kwargs = {}):
+ '''
+ Return the first of potentially many objects.
+ '''
+ objs = objects(query, kwargs)
+ if objs:
+ return objs[0]
+ else:
+ return None
+
+
+ # Check the object against select to check for a match
+ def _select_match(self, object):
+ schema_props = object.properties()
+ for key in self._select.iterkeys():
+ for prop in schema_props:
+ if key == p[0].name() and self._select[key] != p[1]:
+ return False
+ return True
+
+
+ def _get_result(self, list, context):
+ '''
+ Called by Broker proxy to return the result of a query.
+ '''
+ self._cv.acquire()
+ try:
+ for item in list:
+ if self._select_match(item):
+ self._sync_result.append(item)
+ self._sync_count -= 1
+ self._cv.notify()
+ finally:
+ self._cv.release()
+
+
+ def start_sync(self, query): pass
+
+
+ def touch_sync(self, sync): pass
+
+
+ def end_sync(self, sync): pass
+
+
+ def run(self):
+ while self._operational:
+ self._cb_cond.acquire()
+ try:
+ self._cb_cond.wait(1)
+ while self._do_console_events():
+ pass
+ finally:
+ self._cb_cond.release()
+ logging.debug("Shutting down Console thread")
+
+
+ def start_console_events(self):
+ self._cb_cond.acquire()
+ try:
+ self._cb_cond.notify()
+ finally:
+ self._cb_cond.release()
+
+
+ def _do_console_events(self):
+ '''
+ Called by the Console thread to poll for events. Passes the events
+ onto the ConsoleHandler associated with this Console. Is called
+ periodically, but can also be kicked by Console.start_console_events().
+ '''
+ count = 0
+ valid = self.impl.getEvent(self._event)
+ while valid:
+ count += 1
+ try:
+ if self._event.kind == qmfengine.ConsoleEvent.AGENT_ADDED:
+ logging.debug("Console Event AGENT_ADDED received")
+ if self._handler:
+ self._handler.agent_added(AgentProxy(self._event.agent, None))
+ elif self._event.kind == qmfengine.ConsoleEvent.AGENT_DELETED:
+ logging.debug("Console Event AGENT_DELETED received")
+ if self._handler:
+ self._handler.agent_deleted(AgentProxy(self._event.agent, None))
+ elif self._event.kind == qmfengine.ConsoleEvent.NEW_PACKAGE:
+ logging.debug("Console Event NEW_PACKAGE received")
+ if self._handler:
+ self._handler.new_package(self._event.name)
+ elif self._event.kind == qmfengine.ConsoleEvent.NEW_CLASS:
+ logging.debug("Console Event NEW_CLASS received")
+ if self._handler:
+ self._handler.new_class(SchemaClassKey(self._event.classKey))
+ elif self._event.kind == qmfengine.ConsoleEvent.OBJECT_UPDATE:
+ logging.debug("Console Event OBJECT_UPDATE received")
+ if self._handler:
+ self._handler.object_update(ConsoleObject(None, {"impl":self._event.object}),
+ self._event.hasProps, self._event.hasStats)
+ elif self._event.kind == qmfengine.ConsoleEvent.EVENT_RECEIVED:
+ logging.debug("Console Event EVENT_RECEIVED received")
+ elif self._event.kind == qmfengine.ConsoleEvent.AGENT_HEARTBEAT:
+ logging.debug("Console Event AGENT_HEARTBEAT received")
+ if self._handler:
+ self._handler.agent_heartbeat(AgentProxy(self._event.agent, None), self._event.timestamp)
+ elif self._event.kind == qmfengine.ConsoleEvent.METHOD_RESPONSE:
+ logging.debug("Console Event METHOD_RESPONSE received")
+ else:
+ logging.debug("Console thread received unknown event: '%s'" % str(self._event.kind))
+ except e:
+ print "Exception caught in callback thread:", e
+ self.impl.popEvent()
+ valid = self.impl.getEvent(self._event)
+ return count
+
+
+
+class AgentProxy:
+ # attr_reader :broker
+ def __init__(self, impl, broker):
+ self.impl = impl
+ self.broker = broker
+ self.key = "%d.%d" % (self.impl.getBrokerBank(), self.impl.getAgentBank())
+
+
+ def label(self):
+ return self.impl.getLabel()
+
+
+ def key(self):
+ return self.key
+
+
+class Broker(ConnectionHandler):
+ # attr_reader :impl :conn, :console, :broker_bank
+ def __init__(self, console, conn):
+ self.broker_bank = 1
+ self.console = console
+ self.conn = conn
+ self._session = None
+ self._cv = Condition()
+ self._stable = None
+ self._event = qmfengine.BrokerEvent()
+ self._xmtMessage = qmfengine.Message()
+ self.impl = qmfengine.BrokerProxy(self.console.impl)
+ self.console.impl.addConnection(self.impl, self)
+ self.conn.add_conn_handler(self)
+ self._operational = True
+
+
+ def shutdown(self):
+ logging.debug("broker.shutdown() called.")
+ self.console.impl.delConnection(self.impl)
+ self.conn.del_conn_handler(self)
+ if self._session:
+ self.impl.sessionClosed()
+ logging.debug("broker.shutdown() sessionClosed done.")
+ self._session.destroy()
+ logging.debug("broker.shutdown() session destroy done.")
+ self._session = None
+ self._operational = False
+ logging.debug("broker.shutdown() done.")
+
+
+ def wait_for_stable(self, timeout = None):
+ self._cv.acquire()
+ try:
+ if self._stable:
+ return
+ if timeout:
+ self._cv.wait(timeout)
+ if not self._stable:
+ raise Exception("Timed out: waiting for broker connection to become stable")
+ else:
+ while not self._stable:
+ self._cv.wait()
+ finally:
+ self._cv.release()
+
+
+ def send_query(self, query, ctx, agent):
+ agent_impl = None
+ if agent:
+ agent_impl = agent.impl
+ self.impl.sendQuery(query, ctx, agent_impl)
+ self.conn.kick()
+
+
+ def _do_broker_events(self):
+ count = 0
+ valid = self.impl.getEvent(self._event)
+ while valid:
+ count += 1
+ if self._event.kind == qmfengine.BrokerEvent.BROKER_INFO:
+ logging.debug("Broker Event BROKER_INFO received");
+ elif self._event.kind == qmfengine.BrokerEvent.DECLARE_QUEUE:
+ logging.debug("Broker Event DECLARE_QUEUE received");
+ self.conn.impl.declareQueue(self._session.handle, self._event.name)
+ elif self._event.kind == qmfengine.BrokerEvent.DELETE_QUEUE:
+ logging.debug("Broker Event DELETE_QUEUE received");
+ self.conn.impl.deleteQueue(self._session.handle, self._event.name)
+ elif self._event.kind == qmfengine.BrokerEvent.BIND:
+ logging.debug("Broker Event BIND received");
+ self.conn.impl.bind(self._session.handle, self._event.exchange, self._event.name, self._event.bindingKey)
+ elif self._event.kind == qmfengine.BrokerEvent.UNBIND:
+ logging.debug("Broker Event UNBIND received");
+ self.conn.impl.unbind(self._session.handle, self._event.exchange, self._event.name, self._event.bindingKey)
+ elif self._event.kind == qmfengine.BrokerEvent.SETUP_COMPLETE:
+ logging.debug("Broker Event SETUP_COMPLETE received");
+ self.impl.startProtocol()
+ elif self._event.kind == qmfengine.BrokerEvent.STABLE:
+ logging.debug("Broker Event STABLE received");
+ self._cv.acquire()
+ try:
+ self._stable = True
+ self._cv.notify()
+ finally:
+ self._cv.release()
+ elif self._event.kind == qmfengine.BrokerEvent.QUERY_COMPLETE:
+ result = []
+ for idx in range(self._event.queryResponse.getObjectCount()):
+ result.append(ConsoleObject(None, {"impl":self._event.queryResponse.getObject(idx), "broker":self}))
+ self.console._get_result(result, self._event.context)
+ elif self._event.kind == qmfengine.BrokerEvent.METHOD_RESPONSE:
+ obj = self._event.context
+ obj._method_result(MethodResponse(self._event.methodResponse()))
+
+ self.impl.popEvent()
+ valid = self.impl.getEvent(self._event)
+
+ return count
+
+
+ def _do_broker_messages(self):
+ count = 0
+ valid = self.impl.getXmtMessage(self._xmtMessage)
+ while valid:
+ count += 1
+ logging.debug("Broker: sending msg on connection")
+ self.conn.impl.sendMessage(self._session.handle, self._xmtMessage)
+ self.impl.popXmt()
+ valid = self.impl.getXmtMessage(self._xmtMessage)
+
+ return count
+
+
+ def _do_events(self):
+ while True:
+ self.console.start_console_events()
+ bcnt = self._do_broker_events()
+ mcnt = self._do_broker_messages()
+ if bcnt == 0 and mcnt == 0:
+ break;
+
+
+ def conn_event_connected(self):
+ logging.debug("Broker: Connection event CONNECTED")
+ self._session = Session(self.conn, "qmfc-%s.%d" % (socket.gethostname(), os.getpid()), self)
+ self.impl.sessionOpened(self._session.handle)
+ self._do_events()
+
+
+ def conn_event_disconnected(self, error):
+ logging.debug("Broker: Connection event DISCONNECTED")
+ pass
+
+
+ def conn_event_visit(self):
+ self._do_events()
+
+
+ def sess_event_session_closed(self, context, error):
+ logging.debug("Broker: Session event CLOSED")
+ self.impl.sessionClosed()
+
+
+ def sess_event_recv(self, context, message):
+ logging.debug("Broker: Session event MSG_RECV")
+ if not self._operational:
+ logging.warning("Unexpected session event message received by Broker proxy: context='%s'" % str(context))
+ self.impl.handleRcvMessage(message)
+ self._do_events()
+
+
+
+ ##==============================================================================
+ ## AGENT
+ ##==============================================================================
+
+
+
+class AgentHandler:
+ def get_query(self, context, query, userId): None
+ def method_call(self, context, name, object_id, args, userId): None
+
+
+
+class Agent(ConnectionHandler):
+ def __init__(self, handler, label=""):
+ if label == "":
+ self._agentLabel = "rb-%s.%d" % (socket.gethostname(), os.getpid())
+ else:
+ self._agentLabel = label
+ self._conn = None
+ self._handler = handler
+ self.impl = qmfengine.Agent(self._agentLabel)
+ self._event = qmfengine.AgentEvent()
+ self._xmtMessage = qmfengine.Message()
+
+
+ def set_connection(self, conn):
+ self._conn = conn
+ self._conn.add_conn_handler(self)
+
+
+ def register_class(self, cls):
+ self.impl.registerClass(cls.impl)
+
+
+ def alloc_object_id(self, low = 0, high = 0):
+ return ObjectId(self.impl.allocObjectId(low, high))
+
+
+ def query_response(self, context, obj):
+ self.impl.queryResponse(context, obj.impl)
+
+
+ def query_complete(self, context):
+ self.impl.queryComplete(context)
+
+
+ def method_response(self, context, status, text, arguments):
+ self.impl.methodResponse(context, status, text, arguments.map)
+
+
+ def do_agent_events(self):
+ count = 0
+ valid = self.impl.getEvent(self._event)
+ while valid:
+ count += 1
+ if self._event.kind == qmfengine.AgentEvent.GET_QUERY:
+ self._handler.get_query(self._event.sequence,
+ Query({"impl":self._event.query}),
+ self._event.authUserId)
+
+ elif self._event.kind == qmfengine.AgentEvent.START_SYNC:
+ pass
+ elif self._event.kind == qmfengine.AgentEvent.END_SYNC:
+ pass
+ elif self._event.kind == qmfengine.AgentEvent.METHOD_CALL:
+ args = Arguments(self._event.arguments)
+ self._handler.method_call(self._event.sequence, self._event.name,
+ ObjectId(self._event.objectId),
+ args, self._event.authUserId)
+
+ elif self._event.kind == qmfengine.AgentEvent.DECLARE_QUEUE:
+ self._conn.impl.declareQueue(self._session.handle, self._event.name)
+
+ elif self._event.kind == qmfengine.AgentEvent.DELETE_QUEUE:
+ self._conn.impl.deleteQueue(self._session.handle, self._event.name)
+
+ elif self._event.kind == qmfengine.AgentEvent.BIND:
+ self._conn.impl.bind(self._session.handle, self._event.exchange,
+ self._event.name, self._event.bindingKey)
+
+ elif self._event.kind == qmfengine.AgentEvent.UNBIND:
+ self._conn.impl.unbind(self._session.handle, self._event.exchange,
+ self._event.name, self._event.bindingKey)
+
+ elif self._event.kind == qmfengine.AgentEvent.SETUP_COMPLETE:
+ self.impl.startProtocol()
+
+ self.impl.popEvent()
+ valid = self.impl.getEvent(self._event)
+ return count
+
+
+ def do_agent_messages(self):
+ count = 0
+ valid = self.impl.getXmtMessage(self._xmtMessage)
+ while valid:
+ count += 1
+ self._conn.impl.sendMessage(self._session.handle, self._xmtMessage)
+ self.impl.popXmt()
+ valid = self.impl.getXmtMessage(self._xmtMessage)
+ return count
+
+
+ def do_events(self):
+ while True:
+ ecnt = self.do_agent_events()
+ mcnt = self.do_agent_messages()
+ if ecnt == 0 and mcnt == 0:
+ break
+
+
+ def conn_event_connected(self):
+ logging.debug("Agent Connection Established...")
+ self._session = Session(self._conn,
+ "qmfa-%s.%d" % (socket.gethostname(), os.getpid()),
+ self)
+ self.impl.newSession()
+ self.do_events()
+
+
+ def conn_event_disconnected(self, error):
+ logging.debug("Agent Connection Lost")
+ pass
+
+
+ def conn_event_visit(self):
+ self.do_events()
+
+
+ def sess_event_session_closed(self, context, error):
+ logging.debug("Agent Session Lost")
+ pass
+
+
+ def sess_event_recv(self, context, message):
+ self.impl.handleRcvMessage(message)
+ self.do_events()
+
+
diff --git a/cpp/bindings/qmf/qmfengine.i b/cpp/bindings/qmf/qmfengine.i
new file mode 100644
index 0000000000..3477215254
--- /dev/null
+++ b/cpp/bindings/qmf/qmfengine.i
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+%{
+
+#include "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>
+
+
+%inline {
+
+using namespace std;
+using namespace qmf::engine;
+
+namespace qmf {
+namespace engine {
+
+}
+}
+}
+
+
+%{
+
+%};
+
diff --git a/cpp/bindings/qmf/ruby/Makefile.am b/cpp/bindings/qmf/ruby/Makefile.am
new file mode 100644
index 0000000000..34096da9ee
--- /dev/null
+++ b/cpp/bindings/qmf/ruby/Makefile.am
@@ -0,0 +1,44 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+if HAVE_RUBY_DEVEL
+
+INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src
+
+EXTRA_DIST = ruby.i
+BUILT_SOURCES = qmfengine.cpp
+
+rubylibdir = $(RUBY_LIB)
+
+dist_rubylib_DATA = qmf.rb
+
+qmfengine.cpp: $(srcdir)/ruby.i $(srcdir)/../qmfengine.i
+ $(SWIG) -ruby -c++ -Wall -I/usr/include $(INCLUDES) $(QPID_CXXFLAGS) -o qmfengine.cpp $(srcdir)/ruby.i
+
+rubylibarchdir = $(RUBY_LIB_ARCH)
+rubylibarch_LTLIBRARIES = qmfengine.la
+
+qmfengine_la_LDFLAGS = -avoid-version -module -shrext ".$(RUBY_DLEXT)"
+qmfengine_la_LIBADD = $(RUBY_LIBS) -L$(top_builddir)/src/.libs -lqpidclient $(top_builddir)/src/libqmfengine.la
+qmfengine_la_CXXFLAGS = $(INCLUDES) -I$(RUBY_INC) -I$(RUBY_INC_ARCH)
+nodist_qmfengine_la_SOURCES = qmfengine.cpp
+
+CLEANFILES = qmfengine.cpp
+
+endif # HAVE_RUBY_DEVEL
diff --git a/cpp/bindings/qmf/ruby/qmf.rb b/cpp/bindings/qmf/ruby/qmf.rb
new file mode 100644
index 0000000000..857dd64aeb
--- /dev/null
+++ b/cpp/bindings/qmf/ruby/qmf.rb
@@ -0,0 +1,1343 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT 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 'qmfengine'
+require 'thread'
+require 'socket'
+require 'monitor'
+
+module Qmf
+
+ # Pull all the TYPE_* constants into Qmf namespace. Maybe there's an easier way?
+ Qmfengine.constants.each do |c|
+ if c.index('TYPE_') == 0 or c.index('ACCESS_') == 0 or c.index('DIR_') == 0 or c.index('CLASS_') == 0
+ const_set(c, Qmfengine.const_get(c))
+ end
+ end
+
+ ##==============================================================================
+ ## CONNECTION
+ ##==============================================================================
+
+ class ConnectionSettings
+ attr_reader :impl
+
+ def initialize(url = nil)
+ if url
+ @impl = Qmfengine::ConnectionSettings.new(url)
+ else
+ @impl = Qmfengine::ConnectionSettings.new()
+ end
+ end
+
+ def set_attr(key, val)
+ if val.class == String
+ v = Qmfengine::Value.new(TYPE_LSTR)
+ v.setString(val)
+ elsif val.class == TrueClass or val.class == FalseClass
+ v = Qmfengine::Value.new(TYPE_BOOL)
+ v.setBool(val)
+ elsif val.class == Fixnum
+ v = Qmfengine::Value.new(TYPE_UINT32)
+ v.setUint(val)
+ else
+ raise ArgumentError, "Value for attribute '#{key}' has unsupported type: #{val.class}"
+ end
+
+ good = @impl.setAttr(key, v)
+ raise "Invalid attribute '#{key}'" unless good
+ end
+
+ def method_missing(name_in, *args)
+ name = name_in.to_s
+ if name[name.length - 1] == 61
+ attr = name[0..name.length - 2]
+ set_attr(attr, args[0])
+ return
+ end
+
+ super.method_missing(name_in, args)
+ end
+ end
+
+ class ConnectionHandler
+ def conn_event_connected(); end
+ def conn_event_disconnected(error); end
+ def conn_event_visit(); end
+ def sess_event_session_closed(context, error); end
+ def sess_event_recv(context, message); end
+ end
+
+ class Connection
+ include MonitorMixin
+
+ attr_reader :impl
+
+ def initialize(settings)
+ super()
+ @impl = Qmfengine::ResilientConnection.new(settings.impl)
+ @sockEngine, @sock = Socket::socketpair(Socket::PF_UNIX, Socket::SOCK_STREAM, 0)
+ @impl.setNotifyFd(@sockEngine.fileno)
+ @new_conn_handlers = []
+ @conn_handlers_to_delete = []
+ @conn_handlers = []
+ @connected = nil
+
+ @thread = Thread.new do
+ run
+ end
+ end
+
+ def connected?
+ @connected
+ end
+
+ def kick
+ @sockEngine.write(".")
+ @sockEngine.flush
+ end
+
+ def add_conn_handler(handler)
+ synchronize do
+ @new_conn_handlers << handler
+ end
+ kick
+ end
+
+ def del_conn_handler(handler)
+ synchronize do
+ @conn_handlers_to_delete << handler
+ end
+ kick
+ end
+
+ def run()
+ eventImpl = Qmfengine::ResilientConnectionEvent.new
+ new_handlers = nil
+ del_handlers = nil
+ bt_count = 0
+
+ while :true
+ @sock.read(1)
+
+ synchronize do
+ new_handlers = @new_conn_handlers
+ del_handlers = @conn_handlers_to_delete
+ @new_conn_handlers = []
+ @conn_handlers_to_delete = []
+ end
+
+ new_handlers.each do |nh|
+ @conn_handlers << nh
+ nh.conn_event_connected() if @connected
+ end
+ new_handlers = nil
+
+ del_handlers.each do |dh|
+ d = @conn_handlers.delete(dh)
+ end
+ del_handlers = nil
+
+ valid = @impl.getEvent(eventImpl)
+ while valid
+ begin
+ case eventImpl.kind
+ when Qmfengine::ResilientConnectionEvent::CONNECTED
+ @connected = :true
+ @conn_handlers.each { |h| h.conn_event_connected() }
+ when Qmfengine::ResilientConnectionEvent::DISCONNECTED
+ @connected = nil
+ @conn_handlers.each { |h| h.conn_event_disconnected(eventImpl.errorText) }
+ when Qmfengine::ResilientConnectionEvent::SESSION_CLOSED
+ eventImpl.sessionContext.handler.sess_event_session_closed(eventImpl.sessionContext, eventImpl.errorText)
+ when Qmfengine::ResilientConnectionEvent::RECV
+ 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
+ @impl.popEvent
+ valid = @impl.getEvent(eventImpl)
+ end
+ @conn_handlers.each { |h| h.conn_event_visit }
+ end
+ end
+ end
+
+ class Session
+ attr_reader :handle, :handler
+
+ def initialize(conn, label, handler)
+ @conn = conn
+ @label = label
+ @handler = handler
+ @handle = Qmfengine::SessionHandle.new
+ result = @conn.impl.createSession(label, self, @handle)
+ end
+
+ def destroy()
+ @conn.impl.destroySession(@handle)
+ end
+ end
+
+ ##==============================================================================
+ ## OBJECTS
+ ##==============================================================================
+
+ class QmfObject
+ include MonitorMixin
+ attr_reader :impl, :object_class
+ def initialize(cls, kwargs={})
+ super()
+ @cv = new_cond
+ @sync_count = 0
+ @sync_result = nil
+ @allow_sets = :false
+ @broker = kwargs[:broker] if kwargs.include?(:broker)
+
+ if cls:
+ @object_class = cls
+ @impl = Qmfengine::Object.new(@object_class.impl)
+ elsif kwargs.include?(:impl)
+ @impl = Qmfengine::Object.new(kwargs[:impl])
+ @object_class = SchemaObjectClass.new(nil, nil, :impl => @impl.getClass)
+ end
+ end
+
+ def object_id
+ return ObjectId.new(@impl.getObjectId)
+ end
+
+ def properties
+ list = []
+ @object_class.properties.each do |prop|
+ list << [prop, get_attr(prop.name)]
+ end
+ return list
+ end
+
+ def statistics
+ list = []
+ @object_class.statistics.each do |stat|
+ list << [stat, get_attr(stat.name)]
+ end
+ return list
+ end
+
+ def get_attr(name)
+ val = value(name)
+ case val.getType
+ when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.asUint
+ when TYPE_UINT64 then val.asUint64
+ when TYPE_SSTR, TYPE_LSTR then val.asString
+ when TYPE_ABSTIME then val.asInt64
+ when TYPE_DELTATIME then val.asUint64
+ when TYPE_REF then ObjectId.new(val.asObjectId)
+ when TYPE_BOOL then val.asBool
+ when TYPE_FLOAT then val.asFloat
+ when TYPE_DOUBLE then val.asDouble
+ when TYPE_UUID then val.asUuid
+ when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.asInt
+ when TYPE_INT64 then val.asInt64
+ when TYPE_MAP
+ when TYPE_OBJECT
+ when TYPE_LIST
+ when TYPE_ARRAY
+ end
+ end
+
+ def set_attr(name, v)
+ val = value(name)
+ case val.getType
+ when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.setUint(v)
+ when TYPE_UINT64 then val.setUint64(v)
+ when TYPE_SSTR, TYPE_LSTR then v ? val.setString(v) : val.setString('')
+ when TYPE_ABSTIME then val.setInt64(v)
+ when TYPE_DELTATIME then val.setUint64(v)
+ when TYPE_REF then val.setObjectId(v.impl)
+ when TYPE_BOOL then v ? val.setBool(v) : val.setBool(0)
+ when TYPE_FLOAT then val.setFloat(v)
+ when TYPE_DOUBLE then val.setDouble(v)
+ when TYPE_UUID then val.setUuid(v)
+ when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.setInt(v)
+ when TYPE_INT64 then val.setInt64(v)
+ when TYPE_MAP
+ when TYPE_OBJECT
+ when TYPE_LIST
+ when TYPE_ARRAY
+ end
+ end
+
+ def [](name)
+ get_attr(name)
+ end
+
+ def []=(name, value)
+ set_attr(name, value)
+ end
+
+ def inc_attr(name, by=1)
+ set_attr(name, get_attr(name) + by)
+ end
+
+ def dec_attr(name, by=1)
+ set_attr(name, get_attr(name) - by)
+ end
+
+ def method_missing(name_in, *args)
+ #
+ # Convert the name to a string and determine if it represents an
+ # attribute assignment (i.e. "attr=")
+ #
+ name = name_in.to_s
+ attr_set = (name[name.length - 1] == 61)
+ name = name[0..name.length - 2] if attr_set
+ raise "Sets not permitted on this object" if attr_set && !@allow_sets
+
+ #
+ # If the name matches a property name, set or return the value of the property.
+ #
+ @object_class.properties.each do |prop|
+ if prop.name == name
+ if attr_set
+ return set_attr(name, args[0])
+ else
+ return get_attr(name)
+ end
+ end
+ end
+
+ #
+ # Do the same for statistics
+ #
+ @object_class.statistics.each do |stat|
+ if stat.name == name
+ if attr_set
+ return set_attr(name, args[0])
+ else
+ return get_attr(name)
+ end
+ end
+ end
+
+ #
+ # If we still haven't found a match for the name, check to see if
+ # it matches a method name. If so, marshall the arguments and invoke
+ # the method.
+ #
+ @object_class.methods.each do |method|
+ if method.name == name
+ raise "Sets not permitted on methods" if attr_set
+ timeout = 30
+ synchronize do
+ @sync_count = 1
+ @impl.invokeMethod(name, _marshall(method, args), self)
+ @broker.conn.kick if @broker
+ unless @cv.wait(timeout) { @sync_count == 0 }
+ raise "Timed out waiting for response"
+ end
+ end
+
+ return @sync_result
+ end
+ end
+
+ #
+ # This name means nothing to us, pass it up the line to the parent
+ # class's handler.
+ #
+ super.method_missing(name_in, args)
+ end
+
+ def _method_result(result)
+ synchronize do
+ @sync_result = result
+ @sync_count -= 1
+ @cv.signal
+ end
+ end
+
+ #
+ # Convert a Ruby array of arguments (positional) into a Value object of type "map".
+ #
+ private
+ def _marshall(schema, args)
+ map = Qmfengine::Value.new(TYPE_MAP)
+ schema.arguments.each do |arg|
+ if arg.direction == DIR_IN || arg.direction == DIR_IN_OUT
+ map.insert(arg.name, Qmfengine::Value.new(arg.typecode))
+ end
+ end
+
+ marshalled = Arguments.new(map)
+ idx = 0
+ schema.arguments.each do |arg|
+ if arg.direction == DIR_IN || arg.direction == DIR_IN_OUT
+ marshalled[arg.name] = args[idx] unless args[idx] == nil
+ idx += 1
+ end
+ end
+
+ return marshalled.map
+ end
+
+ private
+ def value(name)
+ val = @impl.getValue(name.to_s)
+ if val.nil?
+ raise ArgumentError, "Attribute '#{name}' not defined for class #{@object_class.impl.getClassKey.getPackageName}:#{@object_class.impl.getClassKey.getClassName}"
+ end
+ return val
+ end
+ end
+
+ class AgentObject < QmfObject
+ def initialize(cls, kwargs={})
+ super(cls, kwargs)
+ @allow_sets = :true
+ end
+
+ def destroy
+ @impl.destroy
+ end
+
+ def set_object_id(oid)
+ @impl.setObjectId(oid.impl)
+ end
+ end
+
+ class ConsoleObject < QmfObject
+ attr_reader :current_time, :create_time, :delete_time
+
+ def initialize(cls, kwargs={})
+ super(cls, kwargs)
+ end
+
+ def update()
+ raise "No linkage to broker" unless @broker
+ newer = @broker.console.objects(Query.new(:object_id => object_id))
+ raise "Expected exactly one update for this object" unless newer.size == 1
+ merge_update(newer[0])
+ end
+
+ def merge_update(new_object)
+ @impl.merge(new_object.impl)
+ end
+
+ def deleted?()
+ @impl.isDeleted
+ end
+
+ def key()
+ end
+ end
+
+ class ObjectId
+ attr_reader :impl, :agent_key
+ def initialize(impl=nil)
+ if impl
+ @impl = Qmfengine::ObjectId.new(impl)
+ else
+ @impl = Qmfengine::ObjectId.new
+ end
+ @agent_key = "#{@impl.getBrokerBank}.#{@impl.getAgentBank}"
+ end
+
+ def object_num_high
+ @impl.getObjectNumHi
+ end
+
+ def object_num_low
+ @impl.getObjectNumLo
+ end
+
+ def ==(other)
+ return @impl == other.impl
+ end
+
+ def to_s
+ @impl.str
+ end
+ end
+
+ class Arguments
+ attr_reader :map
+ def initialize(map)
+ @map = map
+ @by_hash = {}
+ key_count = @map.keyCount
+ a = 0
+ while a < key_count
+ @by_hash[@map.key(a)] = by_key(@map.key(a))
+ a += 1
+ end
+ end
+
+ def [] (key)
+ return @by_hash[key]
+ end
+
+ def []= (key, value)
+ @by_hash[key] = value
+ set(key, value)
+ end
+
+ def each
+ @by_hash.each { |k, v| yield(k, v) }
+ end
+
+ def method_missing(name, *args)
+ if @by_hash.include?(name.to_s)
+ return @by_hash[name.to_s]
+ end
+
+ super.method_missing(name, args)
+ end
+
+ def by_key(key)
+ val = @map.byKey(key)
+ case val.getType
+ when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.asUint
+ when TYPE_UINT64 then val.asUint64
+ when TYPE_SSTR, TYPE_LSTR then val.asString
+ when TYPE_ABSTIME then val.asInt64
+ when TYPE_DELTATIME then val.asUint64
+ when TYPE_REF then ObjectId.new(val.asObjectId)
+ when TYPE_BOOL then val.asBool
+ when TYPE_FLOAT then val.asFloat
+ when TYPE_DOUBLE then val.asDouble
+ when TYPE_UUID then val.asUuid
+ when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.asInt
+ when TYPE_INT64 then val.asInt64
+ when TYPE_MAP
+ when TYPE_OBJECT
+ when TYPE_LIST
+ when TYPE_ARRAY
+ end
+ end
+
+ def set(key, value)
+ val = @map.byKey(key)
+ case val.getType
+ when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.setUint(value)
+ when TYPE_UINT64 then val.setUint64(value)
+ when TYPE_SSTR, TYPE_LSTR then value ? val.setString(value) : val.setString('')
+ when TYPE_ABSTIME then val.setInt64(value)
+ when TYPE_DELTATIME then val.setUint64(value)
+ when TYPE_REF then val.setObjectId(value.impl)
+ when TYPE_BOOL then value ? val.setBool(value) : val.setBool(0)
+ when TYPE_FLOAT then val.setFloat(value)
+ when TYPE_DOUBLE then val.setDouble(value)
+ when TYPE_UUID then val.setUuid(value)
+ when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.setInt(value)
+ when TYPE_INT64 then val.setInt64(value)
+ when TYPE_MAP
+ when TYPE_OBJECT
+ when TYPE_LIST
+ when TYPE_ARRAY
+ end
+ end
+ end
+
+ class MethodResponse
+ def initialize(impl)
+ @impl = Qmfengine::MethodResponse.new(impl)
+ end
+
+ def status
+ @impl.getStatus
+ end
+
+ def exception
+ @impl.getException
+ end
+
+ def text
+ exception.asString
+ end
+
+ def args
+ Arguments.new(@impl.getArgs)
+ end
+
+ def method_missing(name, *extra_args)
+ args.__send__(name, extra_args)
+ end
+ end
+
+ ##==============================================================================
+ ## QUERY
+ ##==============================================================================
+
+ class Query
+ attr_reader :impl
+ def initialize(kwargs = {})
+ if kwargs.include?(:impl)
+ @impl = Qmfengine::Query.new(kwargs[:impl])
+ else
+ package = ''
+ if kwargs.include?(:key)
+ @impl = Qmfengine::Query.new(kwargs[:key])
+ elsif kwargs.include?(:object_id)
+ @impl = Qmfengine::Query.new(kwargs[:object_id].impl)
+ else
+ package = kwargs[:package] if kwargs.include?(:package)
+ if kwargs.include?(:class)
+ @impl = Qmfengine::Query.new(kwargs[:class], package)
+ else
+ raise ArgumentError, "Invalid arguments, use :key, :object_id or :class[,:package]"
+ end
+ end
+ end
+ end
+
+ def package_name
+ @impl.getPackage
+ end
+
+ def class_name
+ @impl.getClass
+ end
+
+ def object_id
+ objid = @impl.getObjectId
+ if objid.class == NilClass
+ return nil
+ end
+ return ObjectId.new(objid)
+ end
+ end
+
+ ##==============================================================================
+ ## SCHEMA
+ ##==============================================================================
+
+ class SchemaArgument
+ attr_reader :impl
+ def initialize(name, typecode, kwargs={})
+ if kwargs.include?(:impl)
+ @impl = kwargs[:impl]
+ else
+ @impl = Qmfengine::SchemaArgument.new(name, typecode)
+ @impl.setDirection(kwargs[:dir]) if kwargs.include?(:dir)
+ @impl.setUnit(kwargs[:unit]) if kwargs.include?(:unit)
+ @impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
+ end
+ end
+
+ def name
+ @impl.getName
+ end
+
+ def direction
+ @impl.getDirection
+ end
+
+ def typecode
+ @impl.getType
+ end
+
+ def to_s
+ name
+ end
+ end
+
+ class SchemaMethod
+ attr_reader :impl, :arguments
+ def initialize(name, kwargs={})
+ @arguments = []
+ if kwargs.include?(:impl)
+ @impl = kwargs[:impl]
+ arg_count = @impl.getArgumentCount
+ for i in 0...arg_count
+ @arguments << SchemaArgument.new(nil, nil, :impl => @impl.getArgument(i))
+ end
+ else
+ @impl = Qmfengine::SchemaMethod.new(name)
+ @impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
+ end
+ end
+
+ def add_argument(arg)
+ @arguments << arg
+ @impl.addArgument(arg.impl)
+ end
+
+ def name
+ @impl.getName
+ end
+
+ def to_s
+ name
+ end
+ end
+
+ class SchemaProperty
+ attr_reader :impl
+ def initialize(name, typecode, kwargs={})
+ if kwargs.include?(:impl)
+ @impl = kwargs[:impl]
+ else
+ @impl = Qmfengine::SchemaProperty.new(name, typecode)
+ @impl.setAccess(kwargs[:access]) if kwargs.include?(:access)
+ @impl.setIndex(kwargs[:index]) if kwargs.include?(:index)
+ @impl.setOptional(kwargs[:optional]) if kwargs.include?(:optional)
+ @impl.setUnit(kwargs[:unit]) if kwargs.include?(:unit)
+ @impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
+ end
+ end
+
+ def name
+ @impl.getName
+ end
+
+ def to_s
+ name
+ end
+ end
+
+ class SchemaStatistic
+ attr_reader :impl
+ def initialize(name, typecode, kwargs={})
+ if kwargs.include?(:impl)
+ @impl = kwargs[:impl]
+ else
+ @impl = Qmfengine::SchemaStatistic.new(name, typecode)
+ @impl.setUnit(kwargs[:unit]) if kwargs.include?(:unit)
+ @impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
+ end
+ end
+
+ def name
+ @impl.getName
+ end
+
+ def to_s
+ name
+ end
+ end
+
+ class SchemaClassKey
+ attr_reader :impl
+ def initialize(i)
+ @impl = Qmfengine::SchemaClassKey.new(i)
+ end
+
+ def package_name
+ @impl.getPackageName
+ end
+
+ def class_name
+ @impl.getClassName
+ end
+
+ def to_s
+ @impl.asString
+ end
+ end
+
+ class SchemaObjectClass
+ attr_reader :impl, :properties, :statistics, :methods
+ def initialize(package, name, kwargs={})
+ @properties = []
+ @statistics = []
+ @methods = []
+ if kwargs.include?(:impl)
+ @impl = kwargs[:impl]
+
+ @impl.getPropertyCount.times do |i|
+ @properties << SchemaProperty.new(nil, nil, :impl => @impl.getProperty(i))
+ end
+
+ @impl.getStatisticCount.times do |i|
+ @statistics << SchemaStatistic.new(nil, nil, :impl => @impl.getStatistic(i))
+ end
+
+ @impl.getMethodCount.times do |i|
+ @methods << SchemaMethod.new(nil, :impl => @impl.getMethod(i))
+ end
+ else
+ @impl = Qmfengine::SchemaObjectClass.new(package, name)
+ end
+ end
+
+ def add_property(prop)
+ @properties << prop
+ @impl.addProperty(prop.impl)
+ end
+
+ def add_statistic(stat)
+ @statistics << stat
+ @impl.addStatistic(stat.impl)
+ end
+
+ def add_method(meth)
+ @methods << meth
+ @impl.addMethod(meth.impl)
+ end
+
+ def class_key
+ SchemaClassKey.new(@impl.getClassKey)
+ end
+
+ def package_name
+ @impl.getClassKey.getPackageName
+ end
+
+ def class_name
+ @impl.getClassKey.getClassName
+ end
+ end
+
+ class SchemaEventClass
+ attr_reader :impl, :arguments
+ def initialize(package, name, kwargs={})
+ @arguments = []
+ if kwargs.include?(:impl)
+ @impl = kwargs[:impl]
+ @impl.getArgumentCount.times do |i|
+ @arguments << SchemaArgument.new(nil, nil, :impl => @impl.getArgument(i))
+ end
+ else
+ @impl = Qmfengine::SchemaEventClass.new(package, name)
+ @impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
+ end
+ end
+
+ def add_argument(arg)
+ @arguments << arg
+ @impl.addArgument(arg.impl)
+ end
+
+ def name
+ @impl.getClassKey.getClassName
+ end
+ end
+
+ ##==============================================================================
+ ## CONSOLE
+ ##==============================================================================
+
+ class ConsoleHandler
+ def agent_added(agent); end
+ def agent_deleted(agent); end
+ def new_package(package); end
+ def new_class(class_key); end
+ def object_update(object, hasProps, hasStats); end
+ def event_received(event); end
+ def agent_heartbeat(agent, timestamp); end
+ def method_response(resp); end
+ def broker_info(broker); end
+ end
+
+ class Console
+ include MonitorMixin
+ attr_reader :impl
+
+ def initialize(handler = nil, kwargs={})
+ super()
+ @handler = handler
+ @impl = Qmfengine::Console.new
+ @event = Qmfengine::ConsoleEvent.new
+ @broker_list = []
+ @cv = new_cond
+ @sync_count = nil
+ @sync_result = nil
+ @select = []
+ @bt_count = 0
+ @cb_cond = new_cond
+ @cb_thread = Thread.new do
+ run_cb_thread
+ end
+ end
+
+ def add_connection(conn)
+ broker = Broker.new(self, conn)
+ synchronize { @broker_list << broker }
+ return broker
+ end
+
+ def del_connection(broker)
+ broker.shutdown
+ synchronize { @broker_list.delete(broker) }
+ end
+
+ def packages()
+ plist = []
+ count = @impl.packageCount
+ for i in 0...count
+ plist << @impl.getPackageName(i)
+ end
+ return plist
+ end
+
+ def classes(package, kind=CLASS_OBJECT)
+ clist = []
+ count = @impl.classCount(package)
+ for i in 0...count
+ key = @impl.getClass(package, i)
+ class_kind = @impl.getClassKind(key)
+ if class_kind == kind
+ if kind == CLASS_OBJECT
+ clist << SchemaObjectClass.new(nil, nil, :impl => @impl.getObjectClass(key))
+ elsif kind == CLASS_EVENT
+ clist << SchemaEventClass.new(nil, nil, :impl => @impl.getEventClass(key))
+ end
+ end
+ end
+
+ return clist
+ end
+
+ def bind_package(package)
+ @impl.bindPackage(package)
+ end
+
+ def bind_class(kwargs = {})
+ if kwargs.include?(:key)
+ @impl.bindClass(kwargs[:key])
+ elsif kwargs.include?(:package)
+ package = kwargs[:package]
+ if kwargs.include?(:class)
+ @impl.bindClass(package, kwargs[:class])
+ else
+ @impl.bindClass(package)
+ end
+ else
+ raise ArgumentError, "Invalid arguments, use :key or :package[,:class]"
+ end
+ end
+
+ def agents(broker = nil)
+ blist = []
+ if broker
+ blist << broker
+ else
+ synchronize { blist = @broker_list }
+ end
+
+ agents = []
+ blist.each do |b|
+ count = b.impl.agentCount
+ for idx in 0...count
+ agents << AgentProxy.new(b.impl.getAgent(idx), b)
+ end
+ end
+
+ return agents
+ end
+
+ def objects(query, kwargs = {})
+ timeout = 30
+ agent = nil
+ kwargs.merge!(query) if query.class == Hash
+
+ if kwargs.include?(:timeout)
+ timeout = kwargs[:timeout]
+ kwargs.delete(:timeout)
+ end
+
+ if kwargs.include?(:agent)
+ agent = kwargs[:agent]
+ kwargs.delete(:agent)
+ end
+
+ query = Query.new(kwargs) if query.class == Hash
+
+ @select = []
+ kwargs.each do |k,v|
+ @select << [k, v] if k.is_a?(String)
+ end
+
+ synchronize do
+ @sync_count = 1
+ @sync_result = []
+ broker = nil
+ synchronize { broker = @broker_list[0] }
+ broker.send_query(query.impl, nil, agent)
+ unless @cv.wait(timeout) { @sync_count == 0 }
+ raise "Timed out waiting for response"
+ end
+
+ return @sync_result
+ end
+ end
+
+ # Return one and only one object or nil.
+ def object(query, kwargs = {})
+ objs = objects(query, kwargs)
+ return objs.length == 1 ? objs[0] : nil
+ end
+
+ # Return the first of potentially many objects.
+ def first_object(query, kwargs = {})
+ objs = objects(query, kwargs)
+ return objs.length > 0 ? objs[0] : nil
+ end
+
+ # Check the object against select to check for a match
+ def select_match(object)
+ @select.each do |key, value|
+ object.properties.each do |prop, propval|
+ if key == prop.name && value != propval
+ return nil
+ end
+ end
+ end
+ return :true
+ end
+
+ def _get_result(list, context)
+ synchronize do
+ list.each do |item|
+ @sync_result << item if select_match(item)
+ end
+ @sync_count -= 1
+ @cv.signal
+ end
+ end
+
+ def start_sync(query)
+ end
+
+ def touch_sync(sync)
+ end
+
+ def end_sync(sync)
+ end
+
+ def run_cb_thread
+ while :true
+ synchronize { @cb_cond.wait(1) }
+ begin
+ count = do_console_events
+ end until count == 0
+ end
+ end
+
+ def start_console_events
+ synchronize { @cb_cond.signal }
+ end
+
+ def do_console_events
+ count = 0
+ valid = @impl.getEvent(@event)
+ while valid
+ count += 1
+ begin
+ case @event.kind
+ when Qmfengine::ConsoleEvent::AGENT_ADDED
+ @handler.agent_added(AgentProxy.new(@event.agent, nil)) if @handler
+ when Qmfengine::ConsoleEvent::AGENT_DELETED
+ @handler.agent_deleted(AgentProxy.new(@event.agent, nil)) if @handler
+ when Qmfengine::ConsoleEvent::NEW_PACKAGE
+ @handler.new_package(@event.name) if @handler
+ when Qmfengine::ConsoleEvent::NEW_CLASS
+ @handler.new_class(SchemaClassKey.new(@event.classKey)) if @handler
+ when Qmfengine::ConsoleEvent::OBJECT_UPDATE
+ @handler.object_update(ConsoleObject.new(nil, :impl => @event.object), @event.hasProps, @event.hasStats) if @handler
+ when Qmfengine::ConsoleEvent::EVENT_RECEIVED
+ when Qmfengine::ConsoleEvent::AGENT_HEARTBEAT
+ @handler.agent_heartbeat(AgentProxy.new(@event.agent, nil), @event.timestamp) if @handler
+ 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
+ @impl.popEvent
+ valid = @impl.getEvent(@event)
+ end
+ return count
+ end
+ end
+
+ class AgentProxy
+ attr_reader :impl, :broker, :label, :key
+
+ def initialize(impl, broker)
+ @impl = Qmfengine::AgentProxy.new(impl)
+ @broker = broker
+ @label = @impl.getLabel
+ @key = "#{@impl.getBrokerBank}.#{@impl.getAgentBank}"
+ end
+ end
+
+ class Broker < ConnectionHandler
+ include MonitorMixin
+ attr_reader :impl, :conn, :console, :broker_bank
+
+ def initialize(console, conn)
+ super()
+ @broker_bank = 1
+ @console = console
+ @conn = conn
+ @session = nil
+ @cv = new_cond
+ @stable = nil
+ @event = Qmfengine::BrokerEvent.new
+ @xmtMessage = Qmfengine::Message.new
+ @impl = Qmfengine::BrokerProxy.new(@console.impl)
+ @console.impl.addConnection(@impl, self)
+ @conn.add_conn_handler(self)
+ @operational = :true
+ end
+
+ def shutdown()
+ @console.impl.delConnection(@impl)
+ @conn.del_conn_handler(self)
+ @operational = :false
+ end
+
+ def wait_for_stable(timeout = nil)
+ synchronize do
+ return if @stable
+ if timeout
+ unless @cv.wait(timeout) { @stable }
+ raise "Timed out waiting for broker connection to become stable"
+ end
+ else
+ while not @stable
+ @cv.wait
+ end
+ end
+ end
+ end
+
+ def send_query(query, ctx, agent)
+ agent_impl = agent.impl if agent
+ @impl.sendQuery(query, ctx, agent_impl)
+ @conn.kick
+ end
+
+ def do_broker_events()
+ count = 0
+ valid = @impl.getEvent(@event)
+ while valid
+ count += 1
+ case @event.kind
+ when Qmfengine::BrokerEvent::BROKER_INFO
+ when Qmfengine::BrokerEvent::DECLARE_QUEUE
+ @conn.impl.declareQueue(@session.handle, @event.name)
+ when Qmfengine::BrokerEvent::DELETE_QUEUE
+ @conn.impl.deleteQueue(@session.handle, @event.name)
+ when Qmfengine::BrokerEvent::BIND
+ @conn.impl.bind(@session.handle, @event.exchange, @event.name, @event.bindingKey)
+ when Qmfengine::BrokerEvent::UNBIND
+ @conn.impl.unbind(@session.handle, @event.exchange, @event.name, @event.bindingKey)
+ when Qmfengine::BrokerEvent::SETUP_COMPLETE
+ @impl.startProtocol
+ when Qmfengine::BrokerEvent::STABLE
+ synchronize do
+ @stable = :true
+ @cv.signal
+ end
+ when Qmfengine::BrokerEvent::QUERY_COMPLETE
+ result = []
+ for idx in 0...@event.queryResponse.getObjectCount
+ result << ConsoleObject.new(nil, :impl => @event.queryResponse.getObject(idx), :broker => self)
+ end
+ @console._get_result(result, @event.context)
+ when Qmfengine::BrokerEvent::METHOD_RESPONSE
+ obj = @event.context
+ obj._method_result(MethodResponse.new(@event.methodResponse))
+ end
+ @impl.popEvent
+ valid = @impl.getEvent(@event)
+ end
+ return count
+ end
+
+ def do_broker_messages()
+ count = 0
+ valid = @impl.getXmtMessage(@xmtMessage)
+ while valid
+ count += 1
+ @conn.impl.sendMessage(@session.handle, @xmtMessage)
+ @impl.popXmt
+ valid = @impl.getXmtMessage(@xmtMessage)
+ end
+ return count
+ end
+
+ def do_events()
+ begin
+ @console.start_console_events
+ bcnt = do_broker_events
+ mcnt = do_broker_messages
+ end until bcnt == 0 and mcnt == 0
+ 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
+ do_events
+ 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
+ end
+
+ ##==============================================================================
+ ## AGENT
+ ##==============================================================================
+
+ class AgentHandler
+ def get_query(context, query, userId); end
+ def method_call(context, name, object_id, args, userId); end
+ end
+
+ class Agent < ConnectionHandler
+ def initialize(handler, label="")
+ if label == ""
+ @agentLabel = "rb-%s.%d" % [Socket.gethostname, Process::pid]
+ else
+ @agentLabel = label
+ end
+ @conn = nil
+ @handler = handler
+ @impl = Qmfengine::Agent.new(@agentLabel)
+ @event = Qmfengine::AgentEvent.new
+ @xmtMessage = Qmfengine::Message.new
+ end
+
+ def set_connection(conn)
+ @conn = conn
+ @conn.add_conn_handler(self)
+ end
+
+ def register_class(cls)
+ @impl.registerClass(cls.impl)
+ end
+
+ def alloc_object_id(low = 0, high = 0)
+ ObjectId.new(@impl.allocObjectId(low, high))
+ end
+
+ def query_response(context, object)
+ @impl.queryResponse(context, object.impl)
+ end
+
+ def query_complete(context)
+ @impl.queryComplete(context)
+ end
+
+ def method_response(context, status, text, arguments)
+ @impl.methodResponse(context, status, text, arguments.map)
+ end
+
+ def do_agent_events()
+ count = 0
+ valid = @impl.getEvent(@event)
+ while valid
+ count += 1
+ case @event.kind
+ when Qmfengine::AgentEvent::GET_QUERY
+ @handler.get_query(@event.sequence, Query.new(:impl => @event.query), @event.authUserId)
+ when Qmfengine::AgentEvent::START_SYNC
+ when Qmfengine::AgentEvent::END_SYNC
+ when Qmfengine::AgentEvent::METHOD_CALL
+ args = Arguments.new(@event.arguments)
+ @handler.method_call(@event.sequence, @event.name, ObjectId.new(@event.objectId),
+ args, @event.authUserId)
+ when Qmfengine::AgentEvent::DECLARE_QUEUE
+ @conn.impl.declareQueue(@session.handle, @event.name)
+ when Qmfengine::AgentEvent::DELETE_QUEUE
+ @conn.impl.deleteQueue(@session.handle, @event.name)
+ when Qmfengine::AgentEvent::BIND
+ @conn.impl.bind(@session.handle, @event.exchange, @event.name, @event.bindingKey)
+ when Qmfengine::AgentEvent::UNBIND
+ @conn.impl.unbind(@session.handle, @event.exchange, @event.name, @event.bindingKey)
+ when Qmfengine::AgentEvent::SETUP_COMPLETE
+ @impl.startProtocol()
+ end
+ @impl.popEvent
+ valid = @impl.getEvent(@event)
+ end
+ return count
+ end
+
+ def do_agent_messages()
+ count = 0
+ valid = @impl.getXmtMessage(@xmtMessage)
+ while valid
+ count += 1
+ @conn.impl.sendMessage(@session.handle, @xmtMessage)
+ @impl.popXmt
+ valid = @impl.getXmtMessage(@xmtMessage)
+ end
+ return count
+ end
+
+ def do_events()
+ begin
+ ecnt = do_agent_events
+ mcnt = do_agent_messages
+ end until ecnt == 0 and mcnt == 0
+ 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
+ do_events
+ end
+
+ def sess_event_session_closed(context, error)
+ puts "Agent Session Lost"
+ end
+
+ def sess_event_recv(context, message)
+ @impl.handleRcvMessage(message)
+ do_events
+ end
+ end
+end
diff --git a/cpp/bindings/qmf/ruby/ruby.i b/cpp/bindings/qmf/ruby/ruby.i
new file mode 100644
index 0000000000..b7fed403bd
--- /dev/null
+++ b/cpp/bindings/qmf/ruby/ruby.i
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+%include stl.i
+
+%module qmfengine
+
+%typemap (in) void *
+{
+ $1 = (void *) $input;
+}
+
+%typemap (out) void *
+{
+ $result = (VALUE) $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) FIX2LONG($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);
+}
+
+%typemap (typecheck, precedence=SWIG_TYPECHECK_INTEGER) uint64_t {
+ $1 = FIXNUM_P($input);
+}
+
+
+%include "../qmfengine.i"
+
diff --git a/cpp/bindings/qmf/tests/Makefile.am b/cpp/bindings/qmf/tests/Makefile.am
new file mode 100644
index 0000000000..182771e16b
--- /dev/null
+++ b/cpp/bindings/qmf/tests/Makefile.am
@@ -0,0 +1,27 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+TESTS = run_interop_tests
+
+EXTRA_DIST = \
+ agent_ruby.rb \
+ python_agent.py \
+ python_console.py \
+ ruby_console.rb \
+ run_interop_tests
diff --git a/cpp/bindings/qmf/tests/agent_ruby.rb b/cpp/bindings/qmf/tests/agent_ruby.rb
new file mode 100755
index 0000000000..adf91a8b66
--- /dev/null
+++ b/cpp/bindings/qmf/tests/agent_ruby.rb
@@ -0,0 +1,204 @@
+#!/usr/bin/ruby
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require 'qmf'
+require 'socket'
+
+class Model
+ attr_reader :parent_class, :child_class
+
+ def initialize
+ @parent_class = Qmf::SchemaObjectClass.new("org.apache.qpid.qmf", "parent")
+ @parent_class.add_property(Qmf::SchemaProperty.new("name", Qmf::TYPE_SSTR, :index => true))
+ @parent_class.add_property(Qmf::SchemaProperty.new("state", Qmf::TYPE_SSTR))
+
+ @parent_class.add_property(Qmf::SchemaProperty.new("uint64val", Qmf::TYPE_UINT64))
+ @parent_class.add_property(Qmf::SchemaProperty.new("uint32val", Qmf::TYPE_UINT32))
+ @parent_class.add_property(Qmf::SchemaProperty.new("uint16val", Qmf::TYPE_UINT16))
+ @parent_class.add_property(Qmf::SchemaProperty.new("uint8val", Qmf::TYPE_UINT8))
+
+ @parent_class.add_property(Qmf::SchemaProperty.new("int64val", Qmf::TYPE_INT64))
+ @parent_class.add_property(Qmf::SchemaProperty.new("int32val", Qmf::TYPE_INT32))
+ @parent_class.add_property(Qmf::SchemaProperty.new("int16val", Qmf::TYPE_INT16))
+ @parent_class.add_property(Qmf::SchemaProperty.new("int8val", Qmf::TYPE_INT8))
+
+ @parent_class.add_property(Qmf::SchemaProperty.new("sstrval", Qmf::TYPE_SSTR))
+ @parent_class.add_property(Qmf::SchemaProperty.new("lstrval", Qmf::TYPE_LSTR))
+
+ @parent_class.add_statistic(Qmf::SchemaStatistic.new("queryCount", Qmf::TYPE_UINT32, :unit => "query", :desc => "Query count"))
+
+ method = Qmf::SchemaMethod.new("echo", :desc => "Check responsiveness of the agent object")
+ method.add_argument(Qmf::SchemaArgument.new("sequence", Qmf::TYPE_UINT32, :dir => Qmf::DIR_IN_OUT))
+ @parent_class.add_method(method)
+
+ method = Qmf::SchemaMethod.new("set_numerics", :desc => "Set the numeric values in the object")
+ method.add_argument(Qmf::SchemaArgument.new("test", Qmf::TYPE_SSTR, :dir => Qmf::DIR_IN))
+ @parent_class.add_method(method)
+
+ method = Qmf::SchemaMethod.new("set_short_string", :desc => "Set the short string value in the object")
+ method.add_argument(Qmf::SchemaArgument.new("value", Qmf::TYPE_SSTR, :dir => Qmf::DIR_IN_OUT))
+ @parent_class.add_method(method)
+
+ method = Qmf::SchemaMethod.new("set_long_string", :desc => "Set the long string value in the object")
+ method.add_argument(Qmf::SchemaArgument.new("value", Qmf::TYPE_LSTR, :dir => Qmf::DIR_IN_OUT))
+ @parent_class.add_method(method)
+
+ method = Qmf::SchemaMethod.new("create_child", :desc => "Create a new child object")
+ method.add_argument(Qmf::SchemaArgument.new("child_name", Qmf::TYPE_LSTR, :dir => Qmf::DIR_IN))
+ method.add_argument(Qmf::SchemaArgument.new("child_ref", Qmf::TYPE_REF, :dir => Qmf::DIR_OUT))
+ @parent_class.add_method(method)
+
+ method = Qmf::SchemaMethod.new("probe_userid", :desc => "Return the user-id for this method call")
+ method.add_argument(Qmf::SchemaArgument.new("userid", Qmf::TYPE_SSTR, :dir => Qmf::DIR_OUT))
+ @parent_class.add_method(method)
+
+ @child_class = Qmf::SchemaObjectClass.new("org.apache.qpid.qmf", "child")
+ @child_class.add_property(Qmf::SchemaProperty.new("name", Qmf::TYPE_SSTR, :index => true))
+ end
+
+ def register(agent)
+ agent.register_class(@parent_class)
+ agent.register_class(@child_class)
+ end
+end
+
+
+class App < Qmf::AgentHandler
+ def get_query(context, query, userId)
+# puts "Query: user=#{userId} context=#{context} class=#{query.class_name} object_num=#{query.object_id if query.object_id}"
+ if query.class_name == 'parent'
+ @agent.query_response(context, @parent)
+ elsif query.object_id == @parent_oid
+ @agent.query_response(context, @parent)
+ end
+ @agent.query_complete(context)
+ end
+
+ def method_call(context, name, object_id, args, userId)
+# puts "Method: user=#{userId} context=#{context} method=#{name} object_num=#{object_id if object_id} args=#{args}"
+
+ retCode = 0
+ retText = "OK"
+
+ if name == "echo"
+ @agent.method_response(context, 0, "OK", args)
+
+ elsif name == "set_numerics"
+
+ if args['test'] == "big"
+ @parent.uint64val = 0x9494949449494949
+ @parent.uint32val = 0xa5a55a5a
+ @parent.uint16val = 0xb66b
+ @parent.uint8val = 0xc7
+
+ @parent.int64val = 1000000000000000000
+ @parent.int32val = 1000000000
+ @parent.int16val = 10000
+ @parent.int8val = 100
+
+ elsif args['test'] == "small"
+ @parent.uint64val = 4
+ @parent.uint32val = 5
+ @parent.uint16val = 6
+ @parent.uint8val = 7
+
+ @parent.int64val = 8
+ @parent.int32val = 9
+ @parent.int16val = 10
+ @parent.int8val = 11
+
+ elsif args['test'] == "negative"
+ @parent.uint64val = 0
+ @parent.uint32val = 0
+ @parent.uint16val = 0
+ @parent.uint8val = 0
+
+ @parent.int64val = -10000000000
+ @parent.int32val = -100000
+ @parent.int16val = -1000
+ @parent.int8val = -100
+
+ else
+ retCode = 1
+ retText = "Invalid argument value for test"
+ end
+
+ elsif name == "set_short_string"
+ @parent.sstrval = args['value']
+
+ elsif name == "set_long_string"
+ @parent.lstrval = args['value']
+
+ elsif name == "create_child"
+ oid = @agent.alloc_object_id(2)
+ args['child_ref'] = oid
+ @child = Qmf::AgentObject.new(@model.child_class)
+ @child.name = args.by_key("child_name")
+ @child.set_object_id(oid)
+
+ elsif name == "probe_userid"
+ args['userid'] = userId
+
+ else
+ retCode = 1
+ retText = "Unimplemented Method: #{name}"
+ end
+
+ @agent.method_response(context, retCode, retText, args)
+ end
+
+ def main
+ @settings = Qmf::ConnectionSettings.new
+ @settings.set_attr("host", ARGV[0]) if ARGV.size > 0
+ @settings.set_attr("port", ARGV[1].to_i) if ARGV.size > 1
+ @connection = Qmf::Connection.new(@settings)
+ @agent = Qmf::Agent.new(self)
+
+ @model = Model.new
+ @model.register(@agent)
+
+ @agent.set_connection(@connection)
+
+ @parent = Qmf::AgentObject.new(@model.parent_class)
+ @parent.name = "Parent One"
+ @parent.state = "OPERATIONAL"
+
+ @parent.uint64val = 0
+ @parent.uint32val = 0
+ @parent.uint16val = 0
+ @parent.uint8val = 0
+
+ @parent.int64val = 0
+ @parent.int32val = 0
+ @parent.int16val = 0
+ @parent.int8val = 0
+
+ @parent_oid = @agent.alloc_object_id(1)
+ @parent.set_object_id(@parent_oid)
+
+ sleep
+ end
+end
+
+app = App.new
+app.main
+
+
diff --git a/cpp/bindings/qmf/tests/python_agent.py b/cpp/bindings/qmf/tests/python_agent.py
new file mode 100644
index 0000000000..0f5ffe5b8a
--- /dev/null
+++ b/cpp/bindings/qmf/tests/python_agent.py
@@ -0,0 +1,230 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+
+import qmf
+import sys
+import time
+
+
+class Model:
+ # attr_reader :parent_class, :child_class
+ def __init__(self):
+ self.parent_class = qmf.SchemaObjectClass("org.apache.qpid.qmf", "parent")
+ self.parent_class.add_property(qmf.SchemaProperty("name", qmf.TYPE_SSTR, {"index":True}))
+ self.parent_class.add_property(qmf.SchemaProperty("state", qmf.TYPE_SSTR))
+
+ self.parent_class.add_property(qmf.SchemaProperty("uint64val", qmf.TYPE_UINT64))
+ self.parent_class.add_property(qmf.SchemaProperty("uint32val", qmf.TYPE_UINT32))
+ self.parent_class.add_property(qmf.SchemaProperty("uint16val", qmf.TYPE_UINT16))
+ self.parent_class.add_property(qmf.SchemaProperty("uint8val", qmf.TYPE_UINT8))
+
+ self.parent_class.add_property(qmf.SchemaProperty("int64val", qmf.TYPE_INT64))
+ self.parent_class.add_property(qmf.SchemaProperty("int32val", qmf.TYPE_INT32))
+ self.parent_class.add_property(qmf.SchemaProperty("int16val", qmf.TYPE_INT16))
+ self.parent_class.add_property(qmf.SchemaProperty("int8val", qmf.TYPE_INT8))
+
+ self.parent_class.add_statistic(qmf.SchemaStatistic("queryCount", qmf.TYPE_UINT32, {"unit":"query", "desc":"Query count"}))
+
+ _method = qmf.SchemaMethod("echo", {"desc":"Check responsiveness of the agent object"})
+ _method.add_argument(qmf.SchemaArgument("sequence", qmf.TYPE_UINT32, {"dir":qmf.DIR_IN_OUT}))
+ self.parent_class.add_method(_method)
+
+ _method = qmf.SchemaMethod("set_numerics", {"desc":"Set the numeric values in the object"})
+ _method.add_argument(qmf.SchemaArgument("test", qmf.TYPE_SSTR, {"dir":qmf.DIR_IN}))
+ self.parent_class.add_method(_method)
+
+ _method = qmf.SchemaMethod("create_child", {"desc":"Create a new child object"})
+ _method.add_argument(qmf.SchemaArgument("child_name", qmf.TYPE_LSTR, {"dir":qmf.DIR_IN}))
+ _method.add_argument(qmf.SchemaArgument("child_ref", qmf.TYPE_REF, {"dir":qmf.DIR_OUT}))
+ self.parent_class.add_method(_method)
+
+ _method = qmf.SchemaMethod("probe_userid", {"desc":"Return the user-id for this method call"})
+ _method.add_argument(qmf.SchemaArgument("userid", qmf.TYPE_SSTR, {"dir":qmf.DIR_OUT}))
+ self.parent_class.add_method(_method)
+
+ self.child_class = qmf.SchemaObjectClass("org.apache.qpid.qmf", "child")
+ self.child_class.add_property(qmf.SchemaProperty("name", qmf.TYPE_SSTR, {"index":True}))
+
+
+ def register(self, agent):
+ agent.register_class(self.parent_class)
+ agent.register_class(self.child_class)
+
+
+
+class App(qmf.AgentHandler):
+ '''
+ Object that handles events received by the Agent.
+ '''
+ def get_query(self, context, query, userId):
+ '''
+ Respond to a Query request from a console.
+ '''
+ #print "Query: user=%s context=%d class=%s" % (userId, context, query.class_name())
+ #if query.object_id():
+ # print query.object_id().object_num_low()
+ self._parent.inc_attr("queryCount")
+ if query.class_name() == 'parent':
+ self._agent.query_response(context, self._parent)
+ elif query.object_id() == self._parent_oid:
+ self._agent.query_response(context, self._parent)
+ self._agent.query_complete(context)
+
+
+ def method_call(self, context, name, object_id, args, userId):
+ '''
+ Invoke a method call requested by the console.
+ '''
+ #print "Method: name=%s user=%s context=%d object_id=%s args=%s" % (name, userId, context, object_id, args)
+ if name == "echo":
+ self._agent.method_response(context, 0, "OK", args)
+
+ elif name == "set_numerics":
+ _retCode = 0
+ _retText = "OK"
+
+ if args['test'] == "big":
+ #
+ # note the alternate forms for setting object attributes:
+ #
+ self._parent.set_attr("uint64val", 0x9494949449494949)
+ self._parent.uint32val = 0xa5a55a5a
+ self._parent.set_attr("uint16val", 0xb66b)
+ self._parent["uint8val"] = 0xc7
+
+ self._parent.int64val = 1000000000000000000
+ self._parent.set_attr("int32val", 1000000000)
+ self._parent["int16val"] = 10000
+ self._parent.set_attr("int8val", 100)
+
+ ## Test the __getattr__ implementation:
+ ## @todo: remove once python_client implements this
+ ## form of property access
+ assert self._parent["uint8val"] == 0xc7
+ assert self._parent.uint64val == 0x9494949449494949
+
+ # note the alternative argument access syntax:
+ elif args.test == "small":
+ self._parent.set_attr("uint64val", 4)
+ self._parent.set_attr("uint32val", 5)
+ self._parent.set_attr("uint16val", 6)
+ self._parent.set_attr("uint8val", 7)
+
+ self._parent.set_attr("int64val", 8)
+ self._parent.set_attr("int32val", 9)
+ self._parent.set_attr("int16val", 10)
+ self._parent.set_attr("int8val", 11)
+
+ elif args['test'] == "negative":
+ self._parent.set_attr("uint64val", 0)
+ self._parent.set_attr("uint32val", 0)
+ self._parent.set_attr("uint16val", 0)
+ self._parent.set_attr("uint8val", 0)
+
+ self._parent.set_attr("int64val", -10000000000)
+ self._parent.set_attr("int32val", -100000)
+ self._parent.set_attr("int16val", -1000)
+ self._parent.set_attr("int8val", -100)
+
+ else:
+ _retCode = 1
+ _retText = "Invalid argument value for test"
+
+ self._agent.method_response(context, _retCode, _retText, args)
+
+ elif name == "create_child":
+ #
+ # Instantiate an object based on the Child Schema Class
+ #
+ _oid = self._agent.alloc_object_id(2)
+ args['child_ref'] = _oid
+ self._child = qmf.AgentObject(self._model.child_class)
+ self._child.set_attr("name", args["child_name"])
+ self._child.set_object_id(_oid)
+ self._agent.method_response(context, 0, "OK", args)
+
+ elif name == "probe_userid":
+ args['userid'] = userId
+ self._agent.method_response(context, 0, "OK", args)
+
+ else:
+ self._agent.method_response(context, 1, "Unimplemented Method: %s" % name, args)
+
+
+ def main(self):
+ '''
+ Agent application's main processing loop.
+ '''
+ # Connect to the broker
+ self._settings = qmf.ConnectionSettings()
+ self._settings.sendUserId = True
+ if len(sys.argv) > 1:
+ self._settings.host = str(sys.argv[1])
+ if len(sys.argv) > 2:
+ self._settings.port = int(sys.argv[2])
+ self._connection = qmf.Connection(self._settings)
+
+ # Instantiate an Agent to serve me queries and method calls
+ self._agent = qmf.Agent(self)
+
+ # Dynamically define the parent and child schemas, then
+ # register them with the agent
+ self._model = Model()
+ self._model.register(self._agent)
+
+ # Tell the agent about our connection to the broker
+ self._agent.set_connection(self._connection)
+
+ # Instantiate and populate an instance of the Parent
+ # Schema Object
+ self._parent = qmf.AgentObject(self._model.parent_class)
+
+ ## @todo how do we force a test failure?
+ # verify the properties() and statistics() object methods:
+ assert len(self._parent.properties()) == 10
+ assert len(self._parent.statistics()) == 1
+
+ self._parent.set_attr("name", "Parent One")
+ self._parent.set_attr("state", "OPERATIONAL")
+
+ self._parent.set_attr("uint64val", 0)
+ self._parent.set_attr("uint32val", 0)
+ self._parent.set_attr("uint16val", 0)
+ self._parent.set_attr("uint8val", 0)
+
+ self._parent.set_attr("int64val", 0)
+ self._parent.set_attr("int32val", 0)
+ self._parent.set_attr("int16val", 0)
+ self._parent.set_attr("int8val", 0)
+
+ self._parent_oid = self._agent.alloc_object_id(1)
+ self._parent.set_object_id(self._parent_oid)
+
+ # Now wait for events arriving on the connection
+ # to the broker...
+ while True:
+ time.sleep(1000)
+
+
+
+app = App()
+app.main()
+
diff --git a/cpp/bindings/qmf/tests/python_console.py b/cpp/bindings/qmf/tests/python_console.py
new file mode 100755
index 0000000000..6f366d1a3d
--- /dev/null
+++ b/cpp/bindings/qmf/tests/python_console.py
@@ -0,0 +1,178 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import sys
+from qpid.testlib import TestBase010
+from qpid.datatypes import Message
+from qpid.queue import Empty
+from time import sleep
+
+class QmfInteropTests(TestBase010):
+
+ def test_A_agent_presence(self):
+ self.startQmf();
+ qmf = self.qmf
+
+ agents = []
+ count = 0
+ while len(agents) == 0:
+ agents = qmf.getObjects(_class="agent")
+ sleep(1)
+ count += 1
+ if count > 10:
+ self.fail("Timed out waiting for remote agent")
+
+ def test_B_basic_method_invocation(self):
+ self.startQmf();
+ qmf = self.qmf
+
+ parents = qmf.getObjects(_class="parent")
+ self.assertEqual(len(parents), 1)
+ parent = parents[0]
+ for seq in range(10):
+ result = parent.echo(seq)
+ self.assertEqual(result.status, 0)
+ self.assertEqual(result.text, "OK")
+ self.assertEqual(result.sequence, seq)
+
+ result = parent.set_numerics("bogus")
+ self.assertEqual(result.status, 1)
+ self.assertEqual(result.text, "Invalid argument value for test")
+
+ def test_C_basic_types_numeric_big(self):
+ self.startQmf();
+ qmf = self.qmf
+
+ parents = qmf.getObjects(_class="parent")
+ self.assertEqual(len(parents), 1)
+ parent = parents[0]
+
+ result = parent.set_numerics("big")
+ self.assertEqual(result.status, 0)
+ self.assertEqual(result.text, "OK")
+
+ parent.update()
+
+ self.assertEqual(parent.uint64val, 0x9494949449494949)
+ self.assertEqual(parent.uint32val, 0xA5A55A5A)
+ self.assertEqual(parent.uint16val, 0xB66B)
+ self.assertEqual(parent.uint8val, 0xC7)
+
+ self.assertEqual(parent.int64val, 1000000000000000000)
+ self.assertEqual(parent.int32val, 1000000000)
+ self.assertEqual(parent.int16val, 10000)
+ self.assertEqual(parent.int8val, 100)
+
+ def test_C_basic_types_numeric_small(self):
+ self.startQmf();
+ qmf = self.qmf
+
+ parents = qmf.getObjects(_class="parent")
+ self.assertEqual(len(parents), 1)
+ parent = parents[0]
+
+ result = parent.set_numerics("small")
+ self.assertEqual(result.status, 0)
+ self.assertEqual(result.text, "OK")
+
+ parent.update()
+
+ self.assertEqual(parent.uint64val, 4)
+ self.assertEqual(parent.uint32val, 5)
+ self.assertEqual(parent.uint16val, 6)
+ self.assertEqual(parent.uint8val, 7)
+
+ self.assertEqual(parent.int64val, 8)
+ self.assertEqual(parent.int32val, 9)
+ self.assertEqual(parent.int16val, 10)
+ self.assertEqual(parent.int8val, 11)
+
+ def test_C_basic_types_numeric_negative(self):
+ self.startQmf();
+ qmf = self.qmf
+
+ parents = qmf.getObjects(_class="parent")
+ self.assertEqual(len(parents), 1)
+ parent = parents[0]
+
+ result = parent.set_numerics("negative")
+ self.assertEqual(result.status, 0)
+ self.assertEqual(result.text, "OK")
+
+ parent.update()
+
+ self.assertEqual(parent.uint64val, 0)
+ self.assertEqual(parent.uint32val, 0)
+ self.assertEqual(parent.uint16val, 0)
+ self.assertEqual(parent.uint8val, 0)
+
+ self.assertEqual(parent.int64val, -10000000000)
+ self.assertEqual(parent.int32val, -100000)
+ self.assertEqual(parent.int16val, -1000)
+ self.assertEqual(parent.int8val, -100)
+
+ def disabled_test_D_userid_for_method(self):
+ self.startQmf();
+ qmf = self.qmf
+
+ parents = qmf.getObjects(_class="parent")
+ self.assertEqual(len(parents), 1)
+ parent = parents[0]
+
+ result = parent.probe_userid()
+ self.assertEqual(result.status, 0)
+ self.assertEqual(result.userid, "guest")
+
+ def test_D_get_by_object_id(self):
+ self.startQmf()
+ qmf = self.qmf
+
+ parents = qmf.getObjects(_class="parent")
+ self.assertEqual(len(parents), 1)
+ parent = parents[0]
+
+ newList = qmf.getObjects(_objectId=parent.getObjectId())
+ self.assertEqual(len(newList), 1)
+
+ def test_E_filter_by_object_id(self):
+ self.startQmf()
+ qmf = self.qmf
+
+ list = qmf.getObjects(_class="exchange", name="qpid.management")
+ self.assertEqual(len(list), 1, "No Management Exchange")
+ mgmt_exchange = list[0]
+
+ bindings = qmf.getObjects(_class="binding", exchangeRef=mgmt_exchange.getObjectId())
+ if len(bindings) == 0:
+ self.fail("No bindings found on management exchange")
+
+ for binding in bindings:
+ self.assertEqual(binding.exchangeRef, mgmt_exchange.getObjectId())
+
+ def getProperty(self, msg, name):
+ for h in msg.headers:
+ if hasattr(h, name): return getattr(h, name)
+ return None
+
+ def getAppHeader(self, msg, name):
+ headers = self.getProperty(msg, "application_headers")
+ if headers:
+ return headers[name]
+ return None
diff --git a/cpp/bindings/qmf/tests/ruby_console.rb b/cpp/bindings/qmf/tests/ruby_console.rb
new file mode 100755
index 0000000000..31670312d6
--- /dev/null
+++ b/cpp/bindings/qmf/tests/ruby_console.rb
@@ -0,0 +1,174 @@
+#!/usr/bin/ruby
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require 'qmf'
+require 'socket'
+
+class App < Qmf::ConsoleHandler
+
+ def agent_added(agent)
+ puts "AgentAdded: label=#{agent.label} key=#{agent.key}"
+ end
+
+ def agent_deleted(agent)
+ puts "AgentDeleted: #{agent.label}"
+ end
+
+ def new_package(package)
+ puts "NewPackage: #{package}"
+ end
+
+ def new_class(class_key)
+ puts "NewClass: #{class_key}"
+ end
+
+ def object_update(object, hasProps, hasStats)
+ puts "ObjectUpdate: #{object.object_class.class_name} props=#{hasProps} stats=#{hasStats}"
+ puts " agent-key=#{object.object_id.agent_key}"
+ puts " package=#{object.object_class.package_name}"
+ end
+
+ def event_received(event); end
+
+ def agent_heartbeat(agent, timestamp)
+ puts "AgentHeartbeat: #{agent.label} time=#{timestamp/1000000000}"
+ end
+
+ def method_response(resp); end
+ def broker_info(broker); end
+
+
+ def dump_schema
+ packages = @qmfc.packages
+ puts "----- Packages -----"
+ packages.each do |p|
+ puts p
+ puts " ----- Object Classes -----"
+ classes = @qmfc.classes(p)
+ classes.each do |c|
+ puts " #{c.name}"
+
+ puts " ---- Properties ----"
+ props = c.properties
+ props.each do |prop|
+ puts " #{prop.name}"
+ end
+
+ puts " ---- Statistics ----"
+ stats = c.statistics
+ stats.each do |stat|
+ puts " #{stat.name}"
+ end
+
+ puts " ---- Methods ----"
+ methods = c.methods
+ methods.each do |method|
+ puts " #{method.name}"
+ puts " ---- Args ----"
+ args = method.arguments
+ args.each do |arg|
+ puts " #{arg.name}"
+ end
+ end
+ end
+
+ puts " ----- Event Classes -----"
+ classes = @qmfc.classes(p, Qmf::CLASS_EVENT)
+ classes.each do |c|
+ puts " #{c.name}"
+ puts " ---- Args ----"
+ args = c.arguments
+ args.each do |arg|
+ puts " #{arg.name}"
+ end
+ end
+ end
+ puts "-----"
+ end
+
+ def main
+ @settings = Qmf::ConnectionSettings.new
+ @settings.host = ARGV[0] if ARGV.size > 0
+ @settings.port = ARGV[1].to_i if ARGV.size > 1
+ @connection = Qmf::Connection.new(@settings)
+ @qmfc = Qmf::Console.new(self)
+
+ @broker = @qmfc.add_connection(@connection)
+ @broker.wait_for_stable
+
+ ##dump_schema
+
+ agents = @qmfc.agents()
+ puts "---- Agents ----"
+ agents.each do |a|
+ puts " => #{a.label}"
+ end
+ puts "----"
+
+ for idx in 0...20
+ blist = @qmfc.objects(Qmf::Query.new(:class => "broker"))
+ puts "---- Brokers ----"
+ blist.each do |b|
+ puts " ---- Broker ----"
+ puts " systemRef: #{b.systemRef}"
+ puts " port : #{b.port}"
+ puts " uptime : #{b.uptime / 1000000000}"
+ puts " properties : #{b.properties}"
+ puts " statistics : #{b.statistics}"
+
+ for rep in 0...1
+ puts " Pinging..."
+ ret = b.echo(45, 'text string')
+ puts " status=#{ret.status} text=#{ret.exception.asString} seq=#{ret.args.sequence} body=#{ret.args.body}"
+ end
+ end
+ puts "----"
+
+ elist = @qmfc.objects(:package => "org.apache.qpid.broker", :class => "exchange", 'durable' => true)
+ puts "---- Durable Exchanges ----"
+ elist.each do |e|
+ puts "Exchange: #{e.name}"
+ end
+ puts "----"
+
+ qlist = @qmfc.objects(Qmf::Query.new(:package => "org.apache.qpid.broker",
+ :class => "queue"))
+ puts "---- Queues ----"
+ qlist.each do |q|
+ puts " ---- Queue ----"
+ puts " name : #{q.name}"
+ end
+ puts "----"
+ sleep(5)
+ end
+
+ sleep(5)
+ puts "Deleting connection..."
+ @qmfc.del_connection(@broker)
+ puts " done"
+ sleep
+ end
+end
+
+app = App.new
+app.main
+
+
diff --git a/cpp/bindings/qmf/tests/ruby_console_test.rb b/cpp/bindings/qmf/tests/ruby_console_test.rb
new file mode 100755
index 0000000000..c5c7b141dd
--- /dev/null
+++ b/cpp/bindings/qmf/tests/ruby_console_test.rb
@@ -0,0 +1,234 @@
+#!/usr/bin/ruby
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require 'test_base'
+
+class ConsoleTest < ConsoleTestBase
+
+ def test_A_agent_presence
+ assert(@connection.connected?, "Connection not connected")
+
+ agents = []
+ count = 0
+ while agents.size == 0
+ agents = @qmfc.objects(Qmf::Query.new(:class => "agent"))
+ sleep(1)
+ count += 1
+ fail("Timed out waiting for remote agent") if count > 10
+ end
+
+ agentList = @qmfc.agents
+ assert_equal(agentList.size, 2, "Number of agents reported by Console")
+ end
+
+ def test_A_connection_settings
+ begin
+ @settings.bogusAttribute = 25
+ fail("Connection settings accepted bogus attribute")
+ rescue
+ end
+ end
+
+ def test_B_basic_method_invocation
+ parent = @qmfc.object(:class => "parent")
+ assert(parent, "Number of 'parent' objects")
+ for seq in 0...10
+ result = parent.echo(seq)
+ assert_equal(result.status, 0, "Method Response Status")
+ assert_equal(result.text, "OK", "Method Response Text")
+ assert_equal(result.args.sequence, seq, "Echo Response Sequence")
+ end
+
+ result = parent.set_numerics("bogus")
+ assert_equal(result.status, 1)
+ assert_equal(result.text, "Invalid argument value for test")
+ end
+
+ def test_C_basic_types_numeric_big
+ parent = @qmfc.object(:class =>"parent")
+ assert(parent, "Number of parent objects")
+
+ result = parent.set_numerics("big")
+ assert_equal(result.status, 0, "Method Response Status")
+ assert_equal(result.text, "OK", "Method Response Text")
+
+ parent.update
+
+ assert_equal(parent.uint64val, 0x9494949449494949)
+ assert_equal(parent.uint32val, 0xA5A55A5A)
+ assert_equal(parent.uint16val, 0xB66B)
+ assert_equal(parent.uint8val, 0xC7)
+
+ assert_equal(parent.int64val, 1000000000000000000)
+ assert_equal(parent.int32val, 1000000000)
+ assert_equal(parent.int16val, 10000)
+ assert_equal(parent.int8val, 100)
+ end
+
+ def test_C_basic_types_numeric_small
+ parent = @qmfc.object(:class =>"parent")
+ assert(parent, "Number of parent objects")
+
+ result = parent.set_numerics("small")
+ assert_equal(result.status, 0, "Method Response Status")
+ assert_equal(result.text, "OK", "Method Response Text")
+
+ parent.update
+
+ assert_equal(parent.uint64val, 4)
+ assert_equal(parent.uint32val, 5)
+ assert_equal(parent.uint16val, 6)
+ assert_equal(parent.uint8val, 7)
+
+ assert_equal(parent.int64val, 8)
+ assert_equal(parent.int32val, 9)
+ assert_equal(parent.int16val, 10)
+ assert_equal(parent.int8val, 11)
+ end
+
+ def test_C_basic_types_numeric_negative
+ parent = @qmfc.object(:class =>"parent")
+ assert(parent, "Number of parent objects")
+
+ result = parent.set_numerics("negative")
+ assert_equal(result.status, 0, "Method Response Status")
+ assert_equal(result.text, "OK", "Method Response Text")
+
+ parent.update
+
+ assert_equal(parent.uint64val, 0)
+ assert_equal(parent.uint32val, 0)
+ assert_equal(parent.uint16val, 0)
+ assert_equal(parent.uint8val, 0)
+
+ assert_equal(parent.int64val, -10000000000)
+ assert_equal(parent.int32val, -100000)
+ assert_equal(parent.int16val, -1000)
+ assert_equal(parent.int8val, -100)
+ end
+
+ def test_C_basic_types_string_short
+ parent = @qmfc.object(:class =>"parent")
+ assert(parent, "Number of parent objects")
+
+ strings = []
+ strings << ""
+ strings << "A"
+ strings << "BC"
+ strings << "DEF"
+ strings << "GHIJKLMNOPQRSTUVWXYZ"
+ big = "a"
+ for i in 0...270
+ big << "X"
+ end
+ strings << big
+
+ strings.each do |str|
+ result = parent.set_short_string(str)
+ assert_equal(result.status, 0, "Method Response Status")
+ compare = str
+ compare = compare[0..254] if compare.size > 255
+ assert_equal(result.args.value, compare, "Value returned by method")
+ parent.update
+ assert_equal(parent.sstrval, compare, "Value stored in the object")
+ end
+ end
+
+ def test_C_basic_types_string_long
+ parent = @qmfc.object(:class =>"parent")
+ assert(parent, "Number of parent objects")
+
+ strings = []
+ strings << ""
+ strings << "A"
+ strings << "BC"
+ strings << "DEF"
+ strings << "GHIJKLMNOPQRSTUVWXYZ"
+ big = "a"
+ for i in 0...270
+ big << "X"
+ end
+ strings << big
+
+ strings.each do |str|
+ result = parent.set_long_string(str)
+ assert_equal(result.status, 0, "Method Response Status")
+ assert_equal(result.args.value, str, "Value returned by method")
+ parent.update
+ assert_equal(parent.lstrval, str, "Value stored in the object")
+ end
+ end
+
+ def test_D_userid_for_method
+ parent = @qmfc.object(:class => "parent")
+ assert(parent, "Number of parent objects")
+
+ result = parent.probe_userid
+ assert_equal(result.status, 0, "Method Response Status")
+ assert_equal(result.args.userid, "anonymous")
+ end
+
+ def test_D_get_by_object_id
+ parent = @qmfc.object(:class => "parent")
+ assert(parent, "Number of parent objects")
+
+ list = @qmfc.objects(:object_id => parent.object_id)
+ assert_equal(list.size, 1)
+
+ bad_oid = Qmf::ObjectId.new
+ list = @qmfc.objects(:object_id => bad_oid)
+ assert_equal(list.size, 0)
+
+ # TODO: test a bad_oid that has an agent-bank that is not associated with an attached agent.
+
+ end
+
+ def test_D_get_with_agent
+ agents = @qmfc.agents
+ agents.each do |agent|
+ if agent.label == "qmfa"
+ parent = @qmfc.object(:class => "parent", :agent => agent)
+ assert(parent, "Number of parent objects")
+ return
+ end
+ end
+
+ fail("Didn't find a non-broker agent")
+ end
+
+ def test_E_filter_by_object_id
+ mgmt_exchange = @qmfc.object(:class => "exchange", 'name' => "qpid.management")
+ assert(mgmt_exchange, "No Management Exchange")
+
+ bindings = @qmfc.objects(:class => "binding", 'exchangeRef' => mgmt_exchange.object_id)
+ if bindings.size == 0
+ fail("No bindings found on management exchange")
+ end
+
+ bindings.each do |binding|
+ assert_equal(binding.exchangeRef, mgmt_exchange.object_id)
+ end
+ end
+
+end
+
+app = ConsoleTest.new
+
diff --git a/cpp/bindings/qmf/tests/run_interop_tests b/cpp/bindings/qmf/tests/run_interop_tests
new file mode 100755
index 0000000000..b5545d736d
--- /dev/null
+++ b/cpp/bindings/qmf/tests/run_interop_tests
@@ -0,0 +1,121 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Run the qmf interoperability tests.
+MY_DIR=`dirname \`which $0\``
+QPID_DIR=${MY_DIR}/../../../..
+BUILD_DIR=../../..
+PYTHON_DIR=${QPID_DIR}/python
+BROKER_DIR=${BUILD_DIR}/src
+API_DIR=${BUILD_DIR}/bindings/qmf
+SPEC_DIR=${QPID_DIR}/specs
+
+RUBY_LIB_DIR=${API_DIR}/ruby/.libs
+PYTHON_LIB_DIR=${API_DIR}/python/.libs
+
+trap stop_broker INT TERM QUIT
+
+start_broker() {
+ ${BROKER_DIR}/qpidd --daemon --port 0 --no-data-dir --no-module-dir --auth no > _qpidd.port
+ BROKER_PORT=`cat _qpidd.port`
+}
+
+stop_broker() {
+ ${BROKER_DIR}/qpidd -q --port $BROKER_PORT
+ echo "Broker stopped"
+}
+
+start_ruby_agent() {
+ ruby -I${MY_DIR}/../ruby -I${RUBY_LIB_DIR} ${MY_DIR}/agent_ruby.rb localhost $BROKER_PORT &
+ AGENT_PID=$!
+}
+
+stop_ruby_agent() {
+ kill $AGENT_PID
+}
+
+start_python_agent() {
+ PYTHONPATH="${MY_DIR}/../python:${API_DIR}/python:${PYTHON_LIB_DIR}" python ${MY_DIR}/python_agent.py localhost $BROKER_PORT &
+ PY_AGENT_PID=$!
+}
+
+stop_python_agent() {
+ kill $PY_AGENT_PID
+}
+
+TESTS_FAILED=0
+
+if test -d ${PYTHON_DIR} ; then
+ start_broker
+ echo "Running qmf interop tests using broker on port $BROKER_PORT"
+ PYTHONPATH=${PYTHON_DIR}:${MY_DIR}
+ export PYTHONPATH
+
+ if test -d ${PYTHON_LIB_DIR} ; then
+ echo " Python Agent (external storage) vs. Pure-Python Console"
+ start_python_agent
+ echo " Python agent started at pid $PY_AGENT_PID"
+ ${PYTHON_DIR}/qpid-python-test -m python_console -b localhost:$BROKER_PORT $@
+ RETCODE=$?
+ stop_python_agent
+ if test x$RETCODE != x0; then
+ echo "FAIL qmf interop tests (Python Agent)";
+ TESTS_FAILED=1
+ fi
+ fi
+
+ if test -d ${RUBY_LIB_DIR} ; then
+ echo " Ruby Agent (external storage) vs. Pure-Python Console"
+ start_ruby_agent
+ echo " Ruby agent started at pid $AGENT_PID"
+ ${PYTHON_DIR}/qpid-python-test -m python_console -b localhost:$BROKER_PORT $@
+ RETCODE=$?
+ if test x$RETCODE != x0; then
+ echo "FAIL qmf interop tests (Ruby Agent)";
+ TESTS_FAILED=1
+ fi
+
+ echo " Ruby Agent (external storage) vs. Ruby Console"
+ ruby -I${MY_DIR} -I${MY_DIR}/../ruby -I${RUBY_LIB_DIR} ${MY_DIR}/ruby_console_test.rb localhost $BROKER_PORT $@
+ RETCODE=$?
+ stop_ruby_agent
+ if test x$RETCODE != x0; then
+ echo "FAIL qmf interop tests (Ruby Console/Ruby Agent)";
+ TESTS_FAILED=1
+ fi
+ fi
+
+ # Also against the Pure-Python console:
+ # Ruby agent (internal storage)
+ # Python agent (external and internal)
+ # C++ agent (external and internal)
+ #
+ # Other consoles against the same set of agents:
+ # Wrapped Python console
+ # Ruby console
+ # C++ console
+
+ stop_broker
+ if test x$TESTS_FAILED != x0; then
+ echo "TEST FAILED!"
+ exit 1
+ fi
+fi
diff --git a/cpp/bindings/qmf/tests/test_base.rb b/cpp/bindings/qmf/tests/test_base.rb
new file mode 100644
index 0000000000..cb7fd9d4f9
--- /dev/null
+++ b/cpp/bindings/qmf/tests/test_base.rb
@@ -0,0 +1,73 @@
+#!/usr/bin/ruby
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require 'qmf'
+require 'socket'
+
+class ConsoleTestBase < Qmf::ConsoleHandler
+ def initialize
+ @settings = Qmf::ConnectionSettings.new
+ @settings.host = ARGV[0] if ARGV.size > 0
+ @settings.port = ARGV[1].to_i if ARGV.size > 1
+ @connection = Qmf::Connection.new(@settings)
+ @qmfc = Qmf::Console.new
+
+ @broker = @qmfc.add_connection(@connection)
+ @broker.wait_for_stable
+
+ tests = []
+ methods.each do |m|
+ name = m.to_s
+ tests << name if name[0..4] == "test_"
+ end
+
+ failures = 0
+
+ tests.sort.each do |t|
+ begin
+ print "#{t}..."
+ $stdout.flush
+ send(t)
+ puts " Pass"
+ rescue
+ puts " Fail: #{$!}"
+ failures += 1
+ end
+ end
+
+ @qmfc.del_connection(@broker)
+ exit(1) if failures > 0
+ end
+
+ def assert_equal(left, right, in_text=nil)
+ text = " (#{in_text})" if in_text
+ raise "Assertion failed: #{left} != #{right}#{text}" unless left == right
+ end
+
+ def assert(condition, in_text=nil)
+ text = " (#{in_text})" if in_text
+ raise "Assertion failed: #{left} != #{right}#{text}" unless condition
+ end
+
+ def fail(text)
+ raise text
+ end
+end
diff --git a/cpp/boost-1.32-support/Makefile b/cpp/boost-1.32-support/Makefile
index fb440e26da..f0907f7fda 100644
--- a/cpp/boost-1.32-support/Makefile
+++ b/cpp/boost-1.32-support/Makefile
@@ -5,6 +5,7 @@ default:
apply: main.patch ../src/boost
patch -d .. -p0 < main.patch
+ cat supressions >> ../src/tests/.valgrind.supp
../src/boost: boost.tar.gz
tar -C .. -xvzf boost.tar.gz
diff --git a/cpp/boost-1.32-support/main.patch b/cpp/boost-1.32-support/main.patch
index 0d1e1e9d0a..433a8f0f25 100644
--- a/cpp/boost-1.32-support/main.patch
+++ b/cpp/boost-1.32-support/main.patch
@@ -1,8 +1,8 @@
Index: configure.ac
===================================================================
---- configure.ac (revision 685281)
+--- configure.ac (revision 782009)
+++ configure.ac (working copy)
-@@ -64,7 +64,6 @@
+@@ -66,7 +66,6 @@
# -Wunreachable-code -Wpadded -Winline
# -Wshadow - warns about boost headers.
if test "${enableval}" = yes; then
@@ -10,137 +10,28 @@ Index: configure.ac
gl_COMPILER_FLAGS(-pedantic)
gl_COMPILER_FLAGS(-Wall)
gl_COMPILER_FLAGS(-Wextra)
-Index: src/tests/.valgrind.supp
-===================================================================
---- src/tests/.valgrind.supp (revision 685281)
-+++ src/tests/.valgrind.supp (working copy)
-@@ -193,8 +193,116 @@
- }
-
- {
-- CPG related errors - seem benign but should invesgitate.
-+ similar to other param error, below.
- Memcheck:Param
-+ socketcall.sendto(msg)
-+ fun:send
-+ fun:get_mapping
-+}
-+
-+{
-+ RHEL4 -- we think Boost is responsible for these leaks.
-+ Memcheck:Leak
-+ fun:_Znwm
-+ fun:_ZN5boost15program_options??options_description*
-+}
-+
-+{
-+ RHEL4 -- we think Boost is responsible for these leaks.
-+ Memcheck:Leak
-+ fun:_Znwm
-+ fun:_ZN5boost9unit_test9test_case*
-+}
-+
-+{
-+ RHEL4 -- we think Boost is responsible for these leaks.
-+ Memcheck:Leak
-+ fun:calloc
-+ fun:_dlerror_run
-+ fun:dlopen@@GLIBC_2.2.5
-+ fun:_ZN4qpid3sys5Shlib4loadEPKc
-+ fun:_Z9testShlibv
-+ fun:_ZN5boost9unit_test9ut_detail17unit_test_monitor8functionEv
-+ obj:/usr/lib64/libboost_unit_test_framework.so.1.32.0
-+ fun:_ZN5boost17execution_monitor7executeEbi
-+ fun:_ZN5boost9unit_test9ut_detail17unit_test_monitor21execute_and_translateEPNS0_9test_caseEMS3_FvvEi
-+ fun:_ZN5boost9unit_test9test_case3runEv
-+ fun:_ZN5boost9unit_test10test_suite6do_runEv
-+ fun:_ZN5boost9unit_test9test_case3runEv
-+ fun:main
-+}
-+
-+{
-+ RHEL4 -- we think Boost is responsible for these leaks.
-+ Memcheck:Leak
-+ fun:calloc
-+ fun:_dl_allocate_tls
-+ fun:pthread_create@@GLIBC_2.2.5
-+ fun:_ZN4qpid6broker5Timer5startEv
-+ fun:_ZN4qpid6broker5TimerC1Ev
-+ fun:_ZN4qpid6broker10DtxManagerC1Ev
-+}
-+
-+{
-+ INVESTIGATE
-+ Memcheck:Leak
-+ fun:calloc
-+ fun:_dl_allocate_tls
-+ fun:pthread_create@@GLIBC_2.2.5
-+ fun:_ZN4qpid6client9Connector4initEv
-+ fun:_ZN4qpid6client14ConnectionImpl4openERKSsiS3_S3_S3_
-+}
-+
-+{
-+ INVESTIGATE
-+ Memcheck:Param
-+ write(buf)
-+ obj:/lib64/tls/libc-2.3.4.so
-+ fun:_ZNK4qpid3sys6Socket5writeEPKvm
-+ fun:_ZN4qpid3sys8AsynchIO9writeableERNS0_14DispatchHandleE
-+}
-+
-+{
-+ INVESTIGATE
-+ Memcheck:Leak
-+ fun:calloc
-+ fun:_dl_allocate_tls
-+ fun:pthread_create@@GLIBC_2.2.5
-+ fun:_ZN4qpid6broker5Timer5startEv
-+ fun:_ZN4qpid6broker5TimerC1Ev
-+ fun:_ZN4qpid6broker10DtxManagerC1Ev
-+}
-+{
-+ RHEL4 (and FC5)
-+ Memcheck:Leak
-+ fun:calloc
-+ fun:_dl_allocate_tls
-+ fun:pthread_create@@GLIBC_2.2.5
-+ fun:_ZN4qpid3sys13ThreadPrivateC1EPNS0_8RunnableE
-+ fun:_ZN4qpid3sys6ThreadC1EPNS0_8RunnableE
-+ fun:_ZN4qpid6client9Connector4initEv
-+}
-+{
-+ INVESTIGATE
-+ Memcheck:Param
-+ futex(utime)
-+ fun:__lll_mutex_unlock_wake
-+}
-+{
-+ SAME ISSUE, NEW OCCURENCE
-+ Memcheck:Leak
-+ fun:calloc
-+ fun:_dl_allocate_tls
-+ fun:pthread_create@@GLIBC_2.2.5
-+ fun:_ZN4qpid3sys13ThreadPrivateC1EPNS0_8RunnableE
-+ fun:_ZN4qpid3sys6ThreadC1EPNS0_8RunnableE
-+ fun:_ZN4qpid6broker5Timer5startEv
-+ fun:_ZN4qpid6broker5TimerC1Ev
-+ fun:_ZN4qpid6broker12LinkRegistryC1EPNS0_6BrokerE
-+}
-+{
-+ CPG related errors - seem benign but should invesgitate.
-+ Memcheck:Param
- socketcall.sendmsg(msg.msg_iov[i])
- fun:sendmsg
- obj:/usr/lib/openais/libcpg.so.2.0.0
Index: src/Makefile.am
===================================================================
---- src/Makefile.am (revision 685281)
+--- src/Makefile.am (revision 782009)
+++ src/Makefile.am (working copy)
-@@ -1,6 +1,6 @@
- SUBDIRS = . tests
+@@ -59,7 +59,7 @@
+ qpid/broker/windows/BrokerDefaults.cpp \
+ qpid/broker/windows/SaslAuthenticator.cpp
--EXTRA_DIST= $(platform_dist) $(rgen_srcs)
-+EXTRA_DIST= $(platform_dist) $(rgen_srcs) $(top_srcdir)/src/boost
+-EXTRA_DIST= $(platform_dist) $(rgen_srcs) $(windows_dist)
++EXTRA_DIST= $(platform_dist) $(rgen_srcs) $(windows_dist) $(top_srcdir)/src/boost
## Generated code
+Index: examples/makedist.mk
+===================================================================
+--- examples/makedist.mk (revision 830311)
++++ examples/makedist.mk (working copy)
+@@ -1,6 +1,6 @@
+ # Settings to build the examples in automake
+ AM_CXXFLAGS = $(WARNING_CFLAGS)
+-INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include
++INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src
+ CLIENT_LIB=$(top_builddir)/src/libqpidclient.la
+ CONSOLE_LIB=$(top_builddir)/src/libqmfconsole.la
+ CLIENTFLAGS=-lqpidclient
diff --git a/cpp/boost-1.32-support/supressions b/cpp/boost-1.32-support/supressions
new file mode 100644
index 0000000000..c2b4392566
--- /dev/null
+++ b/cpp/boost-1.32-support/supressions
@@ -0,0 +1,867 @@
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:calloc
+ fun:_dl_allocate_tls
+ fun:pthread_create@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys13ThreadPrivateC1EPNS0_8RunnableE
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:calloc
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:malloc
+ fun:expand_dynamic_string_token
+ fun:_dl_map_object
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:calloc
+ fun:_dl_check_map_versions
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:malloc
+ fun:_dl_map_object_deps
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:calloc
+ fun:_dl_new_object
+ fun:_dl_map_object_from_fd
+ fun:_dl_map_object
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:malloc
+ fun:realloc
+ fun:_dl_new_object
+ fun:_dl_map_object_from_fd
+ fun:_dl_map_object
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:_Znwm
+ fun:_ZN5boost15program_options19options_description3addERKS1_
+ fun:_ZN4qpid3log7OptionsC1ERKSsS3_
+ fun:_ZN20ClientSessionFixtureC1EN4qpid6broker6Broker7OptionsE
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:_Znwm
+ fun:_ZNSs4_Rep9_S_createEmmRKSaIcE
+ obj:/usr/lib64/libstdc++.so.6.0.3
+ fun:_ZNSsC1EPKcRKSaIcE
+ fun:_ZN4qpid34options_description_less_easy_initclEPKcPKN5boost15program_options14value_semanticES2_
+ fun:_ZN4qpid3log5posix11SinkOptionsC1ERKSs
+ fun:_ZN4qpid3log11SinkOptions6createERKSs
+ fun:_ZN4qpid3log7OptionsC1ERKSsS3_
+ fun:_ZN4qpid3log6LoggerC1Ev
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:_Znwm
+ fun:_ZNSt6vectorISsSaISsEE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPSsS1_EERKSs
+ fun:_ZN4qpid7Options14register_namesESs
+ fun:_ZN4qpid34options_description_less_easy_initclEPKcPKN5boost15program_options14value_semanticES2_
+ fun:_ZN4qpid3log7OptionsC1ERKSsS3_
+ fun:_ZN4qpid3log6LoggerC1Ev
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:_Znwm
+ fun:_ZN5boost15program_options29options_description_easy_initclEPKcPKNS0_14value_semanticES3_
+ fun:_ZN4qpid34options_description_less_easy_initclEPKcPKN5boost15program_options14value_semanticES2_
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:_Znwm
+ fun:_ZN5boost15program_options19options_description3addERKS1_
+ fun:_ZN4qpid3log7OptionsC1ERKSsS3_
+ fun:_ZN13BrokerFixtureC2EN4qpid6broker6Broker7OptionsE
+ fun:_ZN15SessionFixtureTI15ProxyConnectionN4qpid6client12Session_0_10EEC1ENS1_6broker6Broker7OptionsE
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:_Znwm
+ fun:_ZN5boost15program_options19options_description3addERKS1_
+ fun:_ZN4qpid3log7OptionsC1ERKSsS3_
+ fun:_ZN4qpid3log6LoggerC1Ev
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:_Znwm
+ fun:_ZN5boost9unit_test9test_caseC2ENS0_13basic_cstringIKcEEbmb
+}
+
+{
+ dl_open_1
+ Memcheck:Leak
+ fun:*alloc
+ fun:_dl_new_object
+ fun:_dl_map_object_from_fd
+ fun:_dl_map_object
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_sasl_get_plugin
+ fun:_sasl_load_plugins
+ fun:sasl_client_init
+}
+{
+ dl_open_2
+ Memcheck:Leak
+ fun:*alloc
+ fun:_dl_*
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_sasl_get_plugin
+ fun:_sasl_load_plugins
+ fun:sasl_client_init
+}
+{
+ dl_open_3
+ Memcheck:Leak
+ fun:malloc
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_sasl_get_plugin
+ fun:_sasl_load_plugins
+ fun:sasl_client_init
+}
+{
+ dl_open_4
+ Memcheck:Leak
+ fun:*alloc
+ fun:_dl_new_object
+ fun:_dl_map_object_from_fd
+ fun:_dl_map_object
+ fun:openaux
+ fun:_dl_catch_error
+ fun:_dl_map_object_deps
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_sasl_get_plugin
+ fun:_sasl_load_plugins
+ fun:sasl_client_init
+}
+{
+ dl_open_5
+ Memcheck:Leak
+ fun:malloc
+ fun:_dl_map_object
+ fun:openaux
+ fun:_dl_catch_error
+ fun:_dl_map_object_deps
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_sasl_get_plugin
+ fun:_sasl_load_plugins
+ fun:sasl_client_init
+}
+{
+ dl_open_6
+ Memcheck:Leak
+ fun:malloc
+ fun:expand_dynamic_string_token
+ fun:_dl_map_object
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_sasl_get_plugin
+ fun:_sasl_load_plugins
+ fun:sasl_client_init
+}
+{
+ dl_open_7
+ Memcheck:Leak
+ fun:malloc
+ fun:_dl_map_object_deps
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ dl_open_8
+ Memcheck:Leak
+ fun:malloc
+ fun:_dl_map_object_deps
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:calloc
+ fun:_dlerror_run
+ fun:dlclose
+ fun:_sasl_done_with_plugins
+ fun:sasl_done
+ fun:__tcf_2
+ fun:__cxa_finalize
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:calloc
+ fun:_dl_allocate_tls
+ fun:pthread_create@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys13ThreadPrivateC1EPNS0_8RunnableE
+ fun:_ZN4qpid3sys6ThreadC1EPNS0_8RunnableE
+ fun:_ZN4qpid6client12TCPConnector4initEv
+ fun:_ZN4qpid6client14ConnectionImpl4openEv
+ fun:_ZN4qpid6client10Connection4openERKNS0_18ConnectionSettingsE
+ fun:_ZN6ClientC2Ev
+ fun:main
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:calloc
+ fun:_dl_allocate_tls
+ fun:pthread_create@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys13ThreadPrivateC1EPNS0_8RunnableE
+ fun:_ZN4qpid3sys6ThreadC1EPNS0_8RunnableE
+ fun:_ZN4qpid6client12TCPConnector4initEv
+ fun:_ZN4qpid6client14ConnectionImpl4openEv
+ fun:_ZN4qpid6client10Connection4openERKNS0_18ConnectionSettingsE
+ fun:main
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:calloc
+ fun:_dl_allocate_tls
+ fun:pthread_create@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys13ThreadPrivateC1EPNS0_8RunnableE
+ fun:_ZN4qpid3sys6ThreadC1EPNS0_8RunnableE
+ fun:_ZN4qpid6client12TCPConnector4initEv
+ fun:_ZN4qpid6client14ConnectionImpl4openEv
+ fun:_ZN4qpid6client10Connection4openERKNS0_18ConnectionSettingsE
+ fun:_ZN4qpid6client10Connection4openERKSsiS3_S3_S3_t
+ fun:_ZN15ProxyConnectionC1Ei
+ fun:_ZN15SessionFixtureTI15ProxyConnectionN4qpid6client12Session_0_10EEC1ENS1_6broker6Broker7OptionsE
+ fun:_Z18DisconnectedListenv
+ fun:_ZN5boost9unit_test9ut_detail17unit_test_monitor8functionEv
+ obj:/usr/lib64/libboost_unit_test_framework.so.1.32.0
+ fun:_ZN5boost17execution_monitor7executeEbi
+ fun:_ZN5boost9unit_test9ut_detail17unit_test_monitor21execute_and_translateEPNS0_9test_caseEMS3_FvvEi
+ fun:_ZN5boost9unit_test9test_case3runEv
+ fun:_ZN5boost9unit_test10test_suite6do_runEv
+ fun:_ZN5boost9unit_test9test_case3runEv
+ fun:main
+}
+{
+ dl_open_9
+ Memcheck:Leak
+ fun:calloc
+ fun:_dl_check_map_versions
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ dl_open_10
+ Memcheck:Leak
+ fun:calloc
+ fun:_dl_new_object
+ fun:_dl_map_object_from_fd
+ fun:_dl_map_object
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ <insert a suppression name here>
+ Memcheck:Param
+ socketcall.sendto(msg)
+ fun:send
+ fun:get_mapping
+ fun:__nscd_get_map_ref
+ fun:nscd_gethst_r
+ fun:__nscd_gethostbyname2_r
+ fun:gethostbyname2_r@@GLIBC_2.2.5
+ fun:gaih_inet
+ fun:getaddrinfo
+ fun:_ZNK4qpid3sys6Socket7connectERKSst
+ fun:_ZN4qpid6client12TCPConnector7connectERKSsi
+ fun:_ZN4qpid6client14ConnectionImpl4openEv
+ fun:_ZN4qpid6client10Connection4openERKNS0_18ConnectionSettingsE
+ fun:main
+}
+{
+ <insert a suppression name here>
+ Memcheck:Param
+ socketcall.sendto(msg)
+ fun:send
+ fun:get_mapping
+ fun:__nscd_get_map_ref
+ fun:nscd_gethst_r
+ fun:__nscd_gethostbyname2_r
+ fun:gethostbyname2_r@@GLIBC_2.2.5
+ fun:gaih_inet
+ fun:getaddrinfo
+ fun:_ZNK4qpid3sys6Socket7connectERKSst
+ fun:_ZN20ClientSessionFixtureC1Ev
+ fun:_Z14testXmlBindingv
+}
+{
+ dl_open_11
+ Memcheck:Leak
+ fun:malloc
+ fun:decompose_rpath
+ fun:_dl_map_object
+ fun:openaux
+ fun:_dl_catch_error
+ fun:_dl_map_object_deps
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:calloc
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ dl_open_12
+ Memcheck:Leak
+ fun:malloc
+ fun:_dl_map_object
+ fun:openaux
+ fun:_dl_catch_error
+ fun:_dl_map_object_deps
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ dl_open_13
+ Memcheck:Leak
+ fun:malloc
+ fun:expand_dynamic_string_token
+ fun:_dl_map_object
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ dl_open_14
+ Memcheck:Leak
+ fun:malloc
+ fun:realloc
+ fun:_dl_new_object
+ fun:_dl_map_object_from_fd
+ fun:_dl_map_object
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ dl_open_15
+ Memcheck:Leak
+ fun:malloc
+ fun:_dl_new_object
+ fun:_dl_map_object_from_fd
+ fun:_dl_map_object
+ fun:openaux
+ fun:_dl_catch_error
+ fun:_dl_map_object_deps
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ dl_open_16
+ Memcheck:Leak
+ fun:malloc
+ fun:decompose_rpath
+ fun:_dl_map_object
+ fun:openaux
+ fun:_dl_catch_error
+ fun:_dl_map_object_deps
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:calloc
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ dl_open_17
+ Memcheck:Leak
+ fun:malloc
+ fun:_dl_map_object
+ fun:openaux
+ fun:_dl_catch_error
+ fun:_dl_map_object_deps
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ dl_open_18
+ Memcheck:Leak
+ fun:malloc
+ fun:expand_dynamic_string_token
+ fun:_dl_map_object
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ dl_open_19
+ Memcheck:Leak
+ fun:malloc
+ fun:realloc
+ fun:_dl_new_object
+ fun:_dl_map_object_from_fd
+ fun:_dl_map_object
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ dl_open_20
+ Memcheck:Leak
+ fun:malloc
+ fun:_dl_new_object
+ fun:_dl_map_object_from_fd
+ fun:_dl_map_object
+ fun:openaux
+ fun:_dl_catch_error
+ fun:_dl_map_object_deps
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:calloc
+ fun:_dl_allocate_tls
+ fun:pthread_create@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys13ThreadPrivateC1EPNS0_8RunnableE
+ fun:_ZN4qpid3sys6ThreadC1EPNS0_8RunnableE
+ fun:_ZN4qpid3sys5Timer5startEv
+ fun:_ZN4qpid3sys5TimerC1Ev
+ fun:_ZN4qpid6broker6BrokerC1ERKNS1_7OptionsE
+ fun:_ZN4qpid6broker6Broker6createERKNS1_7OptionsE
+ fun:_ZN20ClientSessionFixtureC1Ev
+ fun:_Z14testXmlBindingv
+}
+{
+ dl_open_21
+ Memcheck:Leak
+ fun:malloc
+ fun:decompose_rpath
+ fun:_dl_map_object
+ fun:openaux
+ fun:_dl_catch_error
+ fun:_dl_map_object_deps
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:calloc
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ dl_open_22
+ Memcheck:Leak
+ fun:malloc
+ fun:_dl_map_object
+ fun:openaux
+ fun:_dl_catch_error
+ fun:_dl_map_object_deps
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ dl_open_23
+ Memcheck:Leak
+ fun:malloc
+ fun:expand_dynamic_string_token
+ fun:_dl_map_object
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ dl_open_24
+ Memcheck:Leak
+ fun:malloc
+ fun:realloc
+ fun:_dl_new_object
+ fun:_dl_map_object_from_fd
+ fun:_dl_map_object
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ dl_open_25
+ Memcheck:Leak
+ fun:malloc
+ fun:_dl_new_object
+ fun:_dl_map_object_from_fd
+ fun:_dl_map_object
+ fun:openaux
+ fun:_dl_catch_error
+ fun:_dl_map_object_deps
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_GLOBAL__I__ZN53_GLOBAL__N_XmlClientSessionTest.cpp_CF4CBC2E_2FCE92D42_1E
+}
+{
+ <insert a suppression name here>
+ Memcheck:Param
+ socketcall.sendto(msg)
+ fun:send
+ fun:get_mapping
+ fun:__nscd_get_map_ref
+ fun:nscd_gethst_r
+ fun:__nscd_gethostbyname2_r
+ fun:gethostbyname2_r@@GLIBC_2.2.5
+ fun:gaih_inet
+ fun:getaddrinfo
+ fun:_ZNK4qpid3sys6Socket7connectERKSst
+ fun:_ZN4qpid6client12TCPConnector7connectERKSsi
+ fun:_ZN4qpid6client14ConnectionImpl4openEv
+ fun:_ZN4qpid6client10Connection4openERKNS0_18ConnectionSettingsE
+ fun:_ZN6ClientC2Ev
+ fun:main
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:calloc
+ fun:_dlerror_run
+ fun:dlclose
+ fun:_sasl_done_with_plugins
+ fun:sasl_done
+ fun:__tcf_2
+ fun:__cxa_finalize
+}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:calloc
+ fun:_dl_allocate_tls
+ fun:pthread_create@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys13ThreadPrivateC1EPNS0_8RunnableE
+ fun:_ZN4qpid3sys6ThreadC1EPNS0_8RunnableE
+ fun:_ZN4qpid6client12TCPConnector4initEv
+ fun:_ZN4qpid6client14ConnectionImpl4openEv
+ fun:_ZN4qpid6client10Connection4openERKNS0_18ConnectionSettingsE
+ fun:_ZN6ClientC2Ev
+ fun:main
+}
+{
+ <insert a suppression name here>
+ Memcheck:Param
+ socketcall.sendto(msg)
+ fun:send
+ fun:get_mapping
+ fun:__nscd_get_map_ref
+ fun:nscd_gethst_r
+ fun:__nscd_gethostbyname2_r
+ fun:gethostbyname2_r@@GLIBC_2.2.5
+ fun:gaih_inet
+ fun:getaddrinfo
+ fun:_ZNK4qpid3sys6Socket7connectERKSst
+}
+{
+ dl 0
+ Memcheck:Leak
+ fun:*dl*
+}
+
+{
+ dl 1
+ Memcheck:Leak
+ fun:*
+ fun:*dl*
+}
+
+{
+ dl 2
+ fun:*
+ fun:*
+ Memcheck:Leak
+ fun:*dl*
+}
+
+{
+ Znwm
+ Memcheck:Leak
+ fun:_Znwm
+}
+
+{
+ Znwj
+ Memcheck:Leak
+ fun:_Znwj
+}
+
+{
+ Znaj
+ Memcheck:Leak
+ fun:_Znaj
+}
+
+{
+ libc res nsend
+ Memcheck:Leak
+ fun:malloc
+ fun:__libc_res_nsend
+}
+
+{
+ new exitfn
+ Memcheck:Leak
+ fun:malloc
+ fun:__new_exitfn
+}
+
+{
+ pthread mutex unlock
+ Memcheck:Param
+ futex(uaddr2)
+ fun:__lll_mutex_unlock_wake
+ fun:pthread_mutex_unlock
+}
+
+{
+ sasl 1
+ Memcheck:Leak
+ fun:*
+ fun:sasl*
+}
+
+{
+ sasl 2
+ Memcheck:Leak
+ fun:*
+ obj:*
+ fun:sasl*
+}
+
diff --git a/cpp/bootstrap b/cpp/bootstrap
index 2dc8f91b30..5f33fec63f 100755
--- a/cpp/bootstrap
+++ b/cpp/bootstrap
@@ -8,7 +8,7 @@ libtoolize --automake
# the real ones.
cat > src/rubygen.mk <<EOF
\$(srcdir)/rubygen.mk: force
- \$(rgen_cmd)
+ \$(rgen_cmd) \$(srcdir)/rubygen.mk
EOF
cat > src/managementgen.mk <<EOF
\$(srcdir)/managementgen.mk: force
diff --git a/cpp/build-aux/ltmain.sh b/cpp/build-aux/ltmain.sh
deleted file mode 100755
index c715b59412..0000000000
--- a/cpp/build-aux/ltmain.sh
+++ /dev/null
@@ -1,6871 +0,0 @@
-# ltmain.sh - Provide generalized library-building support services.
-# NOTE: Changing this file will not affect anything until you rerun configure.
-#
-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005
-# Free Software Foundation, Inc.
-# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-basename="s,^.*/,,g"
-
-# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
-# is ksh but when the shell is invoked as "sh" and the current value of
-# the _XPG environment variable is not equal to 1 (one), the special
-# positional parameter $0, within a function call, is the name of the
-# function.
-progpath="$0"
-
-# The name of this program:
-progname=`echo "$progpath" | $SED $basename`
-modename="$progname"
-
-# Global variables:
-EXIT_SUCCESS=0
-EXIT_FAILURE=1
-
-PROGRAM=ltmain.sh
-PACKAGE=libtool
-VERSION="1.5.22 Debian 1.5.22-4"
-TIMESTAMP=" (1.1220.2.365 2005/12/18 22:14:06)"
-
-# See if we are running on zsh, and set the options which allow our
-# commands through without removal of \ escapes.
-if test -n "${ZSH_VERSION+set}" ; then
- setopt NO_GLOB_SUBST
-fi
-
-# Check that we have a working $echo.
-if test "X$1" = X--no-reexec; then
- # Discard the --no-reexec flag, and continue.
- shift
-elif test "X$1" = X--fallback-echo; then
- # Avoid inline document here, it may be left over
- :
-elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
- # Yippee, $echo works!
- :
-else
- # Restart under the correct shell, and then maybe $echo will work.
- exec $SHELL "$progpath" --no-reexec ${1+"$@"}
-fi
-
-if test "X$1" = X--fallback-echo; then
- # used as fallback echo
- shift
- cat <<EOF
-$*
-EOF
- exit $EXIT_SUCCESS
-fi
-
-default_mode=
-help="Try \`$progname --help' for more information."
-magic="%%%MAGIC variable%%%"
-mkdir="mkdir"
-mv="mv -f"
-rm="rm -f"
-
-# Sed substitution that helps us do robust quoting. It backslashifies
-# metacharacters that are still active within double-quoted strings.
-Xsed="${SED}"' -e 1s/^X//'
-sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g'
-# test EBCDIC or ASCII
-case `echo X|tr X '\101'` in
- A) # ASCII based system
- # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
- SP2NL='tr \040 \012'
- NL2SP='tr \015\012 \040\040'
- ;;
- *) # EBCDIC based system
- SP2NL='tr \100 \n'
- NL2SP='tr \r\n \100\100'
- ;;
-esac
-
-# NLS nuisances.
-# Only set LANG and LC_ALL to C if already set.
-# These must not be set unconditionally because not all systems understand
-# e.g. LANG=C (notably SCO).
-# We save the old values to restore during execute mode.
-if test "${LC_ALL+set}" = set; then
- save_LC_ALL="$LC_ALL"; LC_ALL=C; export LC_ALL
-fi
-if test "${LANG+set}" = set; then
- save_LANG="$LANG"; LANG=C; export LANG
-fi
-
-# Make sure IFS has a sensible default
-lt_nl='
-'
-IFS=" $lt_nl"
-
-if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
- $echo "$modename: not configured to build any kind of library" 1>&2
- $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
- exit $EXIT_FAILURE
-fi
-
-# Global variables.
-mode=$default_mode
-nonopt=
-prev=
-prevopt=
-run=
-show="$echo"
-show_help=
-execute_dlfiles=
-duplicate_deps=no
-preserve_args=
-lo2o="s/\\.lo\$/.${objext}/"
-o2lo="s/\\.${objext}\$/.lo/"
-
-#####################################
-# Shell function definitions:
-# This seems to be the best place for them
-
-# func_mktempdir [string]
-# Make a temporary directory that won't clash with other running
-# libtool processes, and avoids race conditions if possible. If
-# given, STRING is the basename for that directory.
-func_mktempdir ()
-{
- my_template="${TMPDIR-/tmp}/${1-$progname}"
-
- if test "$run" = ":"; then
- # Return a directory name, but don't create it in dry-run mode
- my_tmpdir="${my_template}-$$"
- else
-
- # If mktemp works, use that first and foremost
- my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null`
-
- if test ! -d "$my_tmpdir"; then
- # Failing that, at least try and use $RANDOM to avoid a race
- my_tmpdir="${my_template}-${RANDOM-0}$$"
-
- save_mktempdir_umask=`umask`
- umask 0077
- $mkdir "$my_tmpdir"
- umask $save_mktempdir_umask
- fi
-
- # If we're not in dry-run mode, bomb out on failure
- test -d "$my_tmpdir" || {
- $echo "cannot create temporary directory \`$my_tmpdir'" 1>&2
- exit $EXIT_FAILURE
- }
- fi
-
- $echo "X$my_tmpdir" | $Xsed
-}
-
-
-# func_win32_libid arg
-# return the library type of file 'arg'
-#
-# Need a lot of goo to handle *both* DLLs and import libs
-# Has to be a shell function in order to 'eat' the argument
-# that is supplied when $file_magic_command is called.
-func_win32_libid ()
-{
- win32_libid_type="unknown"
- win32_fileres=`file -L $1 2>/dev/null`
- case $win32_fileres in
- *ar\ archive\ import\ library*) # definitely import
- win32_libid_type="x86 archive import"
- ;;
- *ar\ archive*) # could be an import, or static
- if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \
- $EGREP -e 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then
- win32_nmres=`eval $NM -f posix -A $1 | \
- $SED -n -e '1,100{/ I /{s,.*,import,;p;q;};}'`
- case $win32_nmres in
- import*) win32_libid_type="x86 archive import";;
- *) win32_libid_type="x86 archive static";;
- esac
- fi
- ;;
- *DLL*)
- win32_libid_type="x86 DLL"
- ;;
- *executable*) # but shell scripts are "executable" too...
- case $win32_fileres in
- *MS\ Windows\ PE\ Intel*)
- win32_libid_type="x86 DLL"
- ;;
- esac
- ;;
- esac
- $echo $win32_libid_type
-}
-
-
-# func_infer_tag arg
-# Infer tagged configuration to use if any are available and
-# if one wasn't chosen via the "--tag" command line option.
-# Only attempt this if the compiler in the base compile
-# command doesn't match the default compiler.
-# arg is usually of the form 'gcc ...'
-func_infer_tag ()
-{
- if test -n "$available_tags" && test -z "$tagname"; then
- CC_quoted=
- for arg in $CC; do
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- arg="\"$arg\""
- ;;
- esac
- CC_quoted="$CC_quoted $arg"
- done
- case $@ in
- # Blanks in the command may have been stripped by the calling shell,
- # but not from the CC environment variable when configure was run.
- " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) ;;
- # Blanks at the start of $base_compile will cause this to fail
- # if we don't check for them as well.
- *)
- for z in $available_tags; do
- if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
- # Evaluate the configuration.
- eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
- CC_quoted=
- for arg in $CC; do
- # Double-quote args containing other shell metacharacters.
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- arg="\"$arg\""
- ;;
- esac
- CC_quoted="$CC_quoted $arg"
- done
- case "$@ " in
- " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*)
- # The compiler in the base compile command matches
- # the one in the tagged configuration.
- # Assume this is the tagged configuration we want.
- tagname=$z
- break
- ;;
- esac
- fi
- done
- # If $tagname still isn't set, then no tagged configuration
- # was found and let the user know that the "--tag" command
- # line option must be used.
- if test -z "$tagname"; then
- $echo "$modename: unable to infer tagged configuration"
- $echo "$modename: specify a tag with \`--tag'" 1>&2
- exit $EXIT_FAILURE
-# else
-# $echo "$modename: using $tagname tagged configuration"
- fi
- ;;
- esac
- fi
-}
-
-
-# func_extract_an_archive dir oldlib
-func_extract_an_archive ()
-{
- f_ex_an_ar_dir="$1"; shift
- f_ex_an_ar_oldlib="$1"
-
- $show "(cd $f_ex_an_ar_dir && $AR x $f_ex_an_ar_oldlib)"
- $run eval "(cd \$f_ex_an_ar_dir && $AR x \$f_ex_an_ar_oldlib)" || exit $?
- if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
- :
- else
- $echo "$modename: ERROR: object name conflicts: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" 1>&2
- exit $EXIT_FAILURE
- fi
-}
-
-# func_extract_archives gentop oldlib ...
-func_extract_archives ()
-{
- my_gentop="$1"; shift
- my_oldlibs=${1+"$@"}
- my_oldobjs=""
- my_xlib=""
- my_xabs=""
- my_xdir=""
- my_status=""
-
- $show "${rm}r $my_gentop"
- $run ${rm}r "$my_gentop"
- $show "$mkdir $my_gentop"
- $run $mkdir "$my_gentop"
- my_status=$?
- if test "$my_status" -ne 0 && test ! -d "$my_gentop"; then
- exit $my_status
- fi
-
- for my_xlib in $my_oldlibs; do
- # Extract the objects.
- case $my_xlib in
- [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
- *) my_xabs=`pwd`"/$my_xlib" ;;
- esac
- my_xlib=`$echo "X$my_xlib" | $Xsed -e 's%^.*/%%'`
- my_xdir="$my_gentop/$my_xlib"
-
- $show "${rm}r $my_xdir"
- $run ${rm}r "$my_xdir"
- $show "$mkdir $my_xdir"
- $run $mkdir "$my_xdir"
- exit_status=$?
- if test "$exit_status" -ne 0 && test ! -d "$my_xdir"; then
- exit $exit_status
- fi
- case $host in
- *-darwin*)
- $show "Extracting $my_xabs"
- # Do not bother doing anything if just a dry run
- if test -z "$run"; then
- darwin_orig_dir=`pwd`
- cd $my_xdir || exit $?
- darwin_archive=$my_xabs
- darwin_curdir=`pwd`
- darwin_base_archive=`$echo "X$darwin_archive" | $Xsed -e 's%^.*/%%'`
- darwin_arches=`lipo -info "$darwin_archive" 2>/dev/null | $EGREP Architectures 2>/dev/null`
- if test -n "$darwin_arches"; then
- darwin_arches=`echo "$darwin_arches" | $SED -e 's/.*are://'`
- darwin_arch=
- $show "$darwin_base_archive has multiple architectures $darwin_arches"
- for darwin_arch in $darwin_arches ; do
- mkdir -p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
- lipo -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
- cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
- func_extract_an_archive "`pwd`" "${darwin_base_archive}"
- cd "$darwin_curdir"
- $rm "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
- done # $darwin_arches
- ## Okay now we have a bunch of thin objects, gotta fatten them up :)
- darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print| xargs basename | sort -u | $NL2SP`
- darwin_file=
- darwin_files=
- for darwin_file in $darwin_filelist; do
- darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP`
- lipo -create -output "$darwin_file" $darwin_files
- done # $darwin_filelist
- ${rm}r unfat-$$
- cd "$darwin_orig_dir"
- else
- cd "$darwin_orig_dir"
- func_extract_an_archive "$my_xdir" "$my_xabs"
- fi # $darwin_arches
- fi # $run
- ;;
- *)
- func_extract_an_archive "$my_xdir" "$my_xabs"
- ;;
- esac
- my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
- done
- func_extract_archives_result="$my_oldobjs"
-}
-# End of Shell function definitions
-#####################################
-
-# Darwin sucks
-eval std_shrext=\"$shrext_cmds\"
-
-disable_libs=no
-
-# Parse our command line options once, thoroughly.
-while test "$#" -gt 0
-do
- arg="$1"
- shift
-
- case $arg in
- -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;;
- *) optarg= ;;
- esac
-
- # If the previous option needs an argument, assign it.
- if test -n "$prev"; then
- case $prev in
- execute_dlfiles)
- execute_dlfiles="$execute_dlfiles $arg"
- ;;
- tag)
- tagname="$arg"
- preserve_args="${preserve_args}=$arg"
-
- # Check whether tagname contains only valid characters
- case $tagname in
- *[!-_A-Za-z0-9,/]*)
- $echo "$progname: invalid tag name: $tagname" 1>&2
- exit $EXIT_FAILURE
- ;;
- esac
-
- case $tagname in
- CC)
- # Don't test for the "default" C tag, as we know, it's there, but
- # not specially marked.
- ;;
- *)
- if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$progpath" > /dev/null; then
- taglist="$taglist $tagname"
- # Evaluate the configuration.
- eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $progpath`"
- else
- $echo "$progname: ignoring unknown tag $tagname" 1>&2
- fi
- ;;
- esac
- ;;
- *)
- eval "$prev=\$arg"
- ;;
- esac
-
- prev=
- prevopt=
- continue
- fi
-
- # Have we seen a non-optional argument yet?
- case $arg in
- --help)
- show_help=yes
- ;;
-
- --version)
- $echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP"
- $echo
- $echo "Copyright (C) 2005 Free Software Foundation, Inc."
- $echo "This is free software; see the source for copying conditions. There is NO"
- $echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
- exit $?
- ;;
-
- --config)
- ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $progpath
- # Now print the configurations for the tags.
- for tagname in $taglist; do
- ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$progpath"
- done
- exit $?
- ;;
-
- --debug)
- $echo "$progname: enabling shell trace mode"
- set -x
- preserve_args="$preserve_args $arg"
- ;;
-
- --dry-run | -n)
- run=:
- ;;
-
- --features)
- $echo "host: $host"
- if test "$build_libtool_libs" = yes; then
- $echo "enable shared libraries"
- else
- $echo "disable shared libraries"
- fi
- if test "$build_old_libs" = yes; then
- $echo "enable static libraries"
- else
- $echo "disable static libraries"
- fi
- exit $?
- ;;
-
- --finish) mode="finish" ;;
-
- --mode) prevopt="--mode" prev=mode ;;
- --mode=*) mode="$optarg" ;;
-
- --preserve-dup-deps) duplicate_deps="yes" ;;
-
- --quiet | --silent)
- show=:
- preserve_args="$preserve_args $arg"
- ;;
-
- --tag)
- prevopt="--tag"
- prev=tag
- preserve_args="$preserve_args --tag"
- ;;
- --tag=*)
- set tag "$optarg" ${1+"$@"}
- shift
- prev=tag
- preserve_args="$preserve_args --tag"
- ;;
-
- -dlopen)
- prevopt="-dlopen"
- prev=execute_dlfiles
- ;;
-
- -*)
- $echo "$modename: unrecognized option \`$arg'" 1>&2
- $echo "$help" 1>&2
- exit $EXIT_FAILURE
- ;;
-
- *)
- nonopt="$arg"
- break
- ;;
- esac
-done
-
-if test -n "$prevopt"; then
- $echo "$modename: option \`$prevopt' requires an argument" 1>&2
- $echo "$help" 1>&2
- exit $EXIT_FAILURE
-fi
-
-case $disable_libs in
-no)
- ;;
-shared)
- build_libtool_libs=no
- build_old_libs=yes
- ;;
-static)
- build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
- ;;
-esac
-
-# If this variable is set in any of the actions, the command in it
-# will be execed at the end. This prevents here-documents from being
-# left over by shells.
-exec_cmd=
-
-if test -z "$show_help"; then
-
- # Infer the operation mode.
- if test -z "$mode"; then
- $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2
- $echo "*** Future versions of Libtool will require --mode=MODE be specified." 1>&2
- case $nonopt in
- *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*)
- mode=link
- for arg
- do
- case $arg in
- -c)
- mode=compile
- break
- ;;
- esac
- done
- ;;
- *db | *dbx | *strace | *truss)
- mode=execute
- ;;
- *install*|cp|mv)
- mode=install
- ;;
- *rm)
- mode=uninstall
- ;;
- *)
- # If we have no mode, but dlfiles were specified, then do execute mode.
- test -n "$execute_dlfiles" && mode=execute
-
- # Just use the default operation mode.
- if test -z "$mode"; then
- if test -n "$nonopt"; then
- $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2
- else
- $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2
- fi
- fi
- ;;
- esac
- fi
-
- # Only execute mode is allowed to have -dlopen flags.
- if test -n "$execute_dlfiles" && test "$mode" != execute; then
- $echo "$modename: unrecognized option \`-dlopen'" 1>&2
- $echo "$help" 1>&2
- exit $EXIT_FAILURE
- fi
-
- # Change the help message to a mode-specific one.
- generic_help="$help"
- help="Try \`$modename --help --mode=$mode' for more information."
-
- # These modes are in order of execution frequency so that they run quickly.
- case $mode in
- # libtool compile mode
- compile)
- modename="$modename: compile"
- # Get the compilation command and the source file.
- base_compile=
- srcfile="$nonopt" # always keep a non-empty value in "srcfile"
- suppress_opt=yes
- suppress_output=
- arg_mode=normal
- libobj=
- later=
-
- for arg
- do
- case $arg_mode in
- arg )
- # do not "continue". Instead, add this to base_compile
- lastarg="$arg"
- arg_mode=normal
- ;;
-
- target )
- libobj="$arg"
- arg_mode=normal
- continue
- ;;
-
- normal )
- # Accept any command-line options.
- case $arg in
- -o)
- if test -n "$libobj" ; then
- $echo "$modename: you cannot specify \`-o' more than once" 1>&2
- exit $EXIT_FAILURE
- fi
- arg_mode=target
- continue
- ;;
-
- -static | -prefer-pic | -prefer-non-pic)
- later="$later $arg"
- continue
- ;;
-
- -no-suppress)
- suppress_opt=no
- continue
- ;;
-
- -Xcompiler)
- arg_mode=arg # the next one goes into the "base_compile" arg list
- continue # The current "srcfile" will either be retained or
- ;; # replaced later. I would guess that would be a bug.
-
- -Wc,*)
- args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"`
- lastarg=
- save_ifs="$IFS"; IFS=','
- for arg in $args; do
- IFS="$save_ifs"
-
- # Double-quote args containing other shell metacharacters.
- # Many Bourne shells cannot handle close brackets correctly
- # in scan sets, so we specify it separately.
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- arg="\"$arg\""
- ;;
- esac
- lastarg="$lastarg $arg"
- done
- IFS="$save_ifs"
- lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"`
-
- # Add the arguments to base_compile.
- base_compile="$base_compile $lastarg"
- continue
- ;;
-
- * )
- # Accept the current argument as the source file.
- # The previous "srcfile" becomes the current argument.
- #
- lastarg="$srcfile"
- srcfile="$arg"
- ;;
- esac # case $arg
- ;;
- esac # case $arg_mode
-
- # Aesthetically quote the previous argument.
- lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"`
-
- case $lastarg in
- # Double-quote args containing other shell metacharacters.
- # Many Bourne shells cannot handle close brackets correctly
- # in scan sets, and some SunOS ksh mistreat backslash-escaping
- # in scan sets (worked around with variable expansion),
- # and furthermore cannot handle '|' '&' '(' ')' in scan sets
- # at all, so we specify them separately.
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- lastarg="\"$lastarg\""
- ;;
- esac
-
- base_compile="$base_compile $lastarg"
- done # for arg
-
- case $arg_mode in
- arg)
- $echo "$modename: you must specify an argument for -Xcompile"
- exit $EXIT_FAILURE
- ;;
- target)
- $echo "$modename: you must specify a target with \`-o'" 1>&2
- exit $EXIT_FAILURE
- ;;
- *)
- # Get the name of the library object.
- [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'`
- ;;
- esac
-
- # Recognize several different file suffixes.
- # If the user specifies -o file.o, it is replaced with file.lo
- xform='[cCFSifmso]'
- case $libobj in
- *.ada) xform=ada ;;
- *.adb) xform=adb ;;
- *.ads) xform=ads ;;
- *.asm) xform=asm ;;
- *.c++) xform=c++ ;;
- *.cc) xform=cc ;;
- *.ii) xform=ii ;;
- *.class) xform=class ;;
- *.cpp) xform=cpp ;;
- *.cxx) xform=cxx ;;
- *.f90) xform=f90 ;;
- *.for) xform=for ;;
- *.java) xform=java ;;
- esac
-
- libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"`
-
- case $libobj in
- *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;;
- *)
- $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2
- exit $EXIT_FAILURE
- ;;
- esac
-
- func_infer_tag $base_compile
-
- for arg in $later; do
- case $arg in
- -static)
- build_old_libs=yes
- continue
- ;;
-
- -prefer-pic)
- pic_mode=yes
- continue
- ;;
-
- -prefer-non-pic)
- pic_mode=no
- continue
- ;;
- esac
- done
-
- qlibobj=`$echo "X$libobj" | $Xsed -e "$sed_quote_subst"`
- case $qlibobj in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- qlibobj="\"$qlibobj\"" ;;
- esac
- test "X$libobj" != "X$qlibobj" \
- && $echo "X$libobj" | grep '[]~#^*{};<>?"'"'"' &()|`$[]' \
- && $echo "$modename: libobj name \`$libobj' may not contain shell special characters."
- objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'`
- xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$xdir" = "X$obj"; then
- xdir=
- else
- xdir=$xdir/
- fi
- lobj=${xdir}$objdir/$objname
-
- if test -z "$base_compile"; then
- $echo "$modename: you must specify a compilation command" 1>&2
- $echo "$help" 1>&2
- exit $EXIT_FAILURE
- fi
-
- # Delete any leftover library objects.
- if test "$build_old_libs" = yes; then
- removelist="$obj $lobj $libobj ${libobj}T"
- else
- removelist="$lobj $libobj ${libobj}T"
- fi
-
- $run $rm $removelist
- trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15
-
- # On Cygwin there's no "real" PIC flag so we must build both object types
- case $host_os in
- cygwin* | mingw* | pw32* | os2*)
- pic_mode=default
- ;;
- esac
- if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
- # non-PIC code in shared libraries is not supported
- pic_mode=default
- fi
-
- # Calculate the filename of the output object if compiler does
- # not support -o with -c
- if test "$compiler_c_o" = no; then
- output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext}
- lockfile="$output_obj.lock"
- removelist="$removelist $output_obj $lockfile"
- trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15
- else
- output_obj=
- need_locks=no
- lockfile=
- fi
-
- # Lock this critical section if it is needed
- # We use this script file to make the link, it avoids creating a new file
- if test "$need_locks" = yes; then
- until $run ln "$progpath" "$lockfile" 2>/dev/null; do
- $show "Waiting for $lockfile to be removed"
- sleep 2
- done
- elif test "$need_locks" = warn; then
- if test -f "$lockfile"; then
- $echo "\
-*** ERROR, $lockfile exists and contains:
-`cat $lockfile 2>/dev/null`
-
-This indicates that another process is trying to use the same
-temporary object file, and libtool could not work around it because
-your compiler does not support \`-c' and \`-o' together. If you
-repeat this compilation, it may succeed, by chance, but you had better
-avoid parallel builds (make -j) in this platform, or get a better
-compiler."
-
- $run $rm $removelist
- exit $EXIT_FAILURE
- fi
- $echo "$srcfile" > "$lockfile"
- fi
-
- if test -n "$fix_srcfile_path"; then
- eval srcfile=\"$fix_srcfile_path\"
- fi
- qsrcfile=`$echo "X$srcfile" | $Xsed -e "$sed_quote_subst"`
- case $qsrcfile in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- qsrcfile="\"$qsrcfile\"" ;;
- esac
-
- $run $rm "$libobj" "${libobj}T"
-
- # Create a libtool object file (analogous to a ".la" file),
- # but don't create it if we're doing a dry run.
- test -z "$run" && cat > ${libobj}T <<EOF
-# $libobj - a libtool object file
-# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
-#
-# Please DO NOT delete this file!
-# It is necessary for linking the library.
-
-# Name of the PIC object.
-EOF
-
- # Only build a PIC object if we are building libtool libraries.
- if test "$build_libtool_libs" = yes; then
- # Without this assignment, base_compile gets emptied.
- fbsd_hideous_sh_bug=$base_compile
-
- if test "$pic_mode" != no; then
- command="$base_compile $qsrcfile $pic_flag"
- else
- # Don't build PIC code
- command="$base_compile $qsrcfile"
- fi
-
- if test ! -d "${xdir}$objdir"; then
- $show "$mkdir ${xdir}$objdir"
- $run $mkdir ${xdir}$objdir
- exit_status=$?
- if test "$exit_status" -ne 0 && test ! -d "${xdir}$objdir"; then
- exit $exit_status
- fi
- fi
-
- if test -z "$output_obj"; then
- # Place PIC objects in $objdir
- command="$command -o $lobj"
- fi
-
- $run $rm "$lobj" "$output_obj"
-
- $show "$command"
- if $run eval "$command"; then :
- else
- test -n "$output_obj" && $run $rm $removelist
- exit $EXIT_FAILURE
- fi
-
- if test "$need_locks" = warn &&
- test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
- $echo "\
-*** ERROR, $lockfile contains:
-`cat $lockfile 2>/dev/null`
-
-but it should contain:
-$srcfile
-
-This indicates that another process is trying to use the same
-temporary object file, and libtool could not work around it because
-your compiler does not support \`-c' and \`-o' together. If you
-repeat this compilation, it may succeed, by chance, but you had better
-avoid parallel builds (make -j) in this platform, or get a better
-compiler."
-
- $run $rm $removelist
- exit $EXIT_FAILURE
- fi
-
- # Just move the object if needed, then go on to compile the next one
- if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
- $show "$mv $output_obj $lobj"
- if $run $mv $output_obj $lobj; then :
- else
- error=$?
- $run $rm $removelist
- exit $error
- fi
- fi
-
- # Append the name of the PIC object to the libtool object file.
- test -z "$run" && cat >> ${libobj}T <<EOF
-pic_object='$objdir/$objname'
-
-EOF
-
- # Allow error messages only from the first compilation.
- if test "$suppress_opt" = yes; then
- suppress_output=' >/dev/null 2>&1'
- fi
- else
- # No PIC object so indicate it doesn't exist in the libtool
- # object file.
- test -z "$run" && cat >> ${libobj}T <<EOF
-pic_object=none
-
-EOF
- fi
-
- # Only build a position-dependent object if we build old libraries.
- if test "$build_old_libs" = yes; then
- if test "$pic_mode" != yes; then
- # Don't build PIC code
- command="$base_compile $qsrcfile"
- else
- command="$base_compile $qsrcfile $pic_flag"
- fi
- if test "$compiler_c_o" = yes; then
- command="$command -o $obj"
- fi
-
- # Suppress compiler output if we already did a PIC compilation.
- command="$command$suppress_output"
- $run $rm "$obj" "$output_obj"
- $show "$command"
- if $run eval "$command"; then :
- else
- $run $rm $removelist
- exit $EXIT_FAILURE
- fi
-
- if test "$need_locks" = warn &&
- test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
- $echo "\
-*** ERROR, $lockfile contains:
-`cat $lockfile 2>/dev/null`
-
-but it should contain:
-$srcfile
-
-This indicates that another process is trying to use the same
-temporary object file, and libtool could not work around it because
-your compiler does not support \`-c' and \`-o' together. If you
-repeat this compilation, it may succeed, by chance, but you had better
-avoid parallel builds (make -j) in this platform, or get a better
-compiler."
-
- $run $rm $removelist
- exit $EXIT_FAILURE
- fi
-
- # Just move the object if needed
- if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
- $show "$mv $output_obj $obj"
- if $run $mv $output_obj $obj; then :
- else
- error=$?
- $run $rm $removelist
- exit $error
- fi
- fi
-
- # Append the name of the non-PIC object the libtool object file.
- # Only append if the libtool object file exists.
- test -z "$run" && cat >> ${libobj}T <<EOF
-# Name of the non-PIC object.
-non_pic_object='$objname'
-
-EOF
- else
- # Append the name of the non-PIC object the libtool object file.
- # Only append if the libtool object file exists.
- test -z "$run" && cat >> ${libobj}T <<EOF
-# Name of the non-PIC object.
-non_pic_object=none
-
-EOF
- fi
-
- $run $mv "${libobj}T" "${libobj}"
-
- # Unlock the critical section if it was locked
- if test "$need_locks" != no; then
- $run $rm "$lockfile"
- fi
-
- exit $EXIT_SUCCESS
- ;;
-
- # libtool link mode
- link | relink)
- modename="$modename: link"
- case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
- # It is impossible to link a dll without this setting, and
- # we shouldn't force the makefile maintainer to figure out
- # which system we are compiling for in order to pass an extra
- # flag for every libtool invocation.
- # allow_undefined=no
-
- # FIXME: Unfortunately, there are problems with the above when trying
- # to make a dll which has undefined symbols, in which case not
- # even a static library is built. For now, we need to specify
- # -no-undefined on the libtool link line when we can be certain
- # that all symbols are satisfied, otherwise we get a static library.
- allow_undefined=yes
- ;;
- *)
- allow_undefined=yes
- ;;
- esac
- libtool_args="$nonopt"
- base_compile="$nonopt $@"
- compile_command="$nonopt"
- finalize_command="$nonopt"
-
- compile_rpath=
- finalize_rpath=
- compile_shlibpath=
- finalize_shlibpath=
- convenience=
- old_convenience=
- deplibs=
- old_deplibs=
- compiler_flags=
- linker_flags=
- dllsearchpath=
- lib_search_path=`pwd`
- inst_prefix_dir=
-
- avoid_version=no
- dlfiles=
- dlprefiles=
- dlself=no
- export_dynamic=no
- export_symbols=
- export_symbols_regex=
- generated=
- libobjs=
- ltlibs=
- module=no
- no_install=no
- objs=
- non_pic_objects=
- notinst_path= # paths that contain not-installed libtool libraries
- precious_files_regex=
- prefer_static_libs=no
- preload=no
- prev=
- prevarg=
- release=
- rpath=
- xrpath=
- perm_rpath=
- temp_rpath=
- thread_safe=no
- vinfo=
- vinfo_number=no
-
- func_infer_tag $base_compile
-
- # We need to know -static, to get the right output filenames.
- for arg
- do
- case $arg in
- -all-static | -static)
- if test "X$arg" = "X-all-static"; then
- if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
- $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2
- fi
- if test -n "$link_static_flag"; then
- dlopen_self=$dlopen_self_static
- fi
- prefer_static_libs=yes
- else
- if test -z "$pic_flag" && test -n "$link_static_flag"; then
- dlopen_self=$dlopen_self_static
- fi
- prefer_static_libs=built
- fi
- build_libtool_libs=no
- build_old_libs=yes
- break
- ;;
- esac
- done
-
- # See if our shared archives depend on static archives.
- test -n "$old_archive_from_new_cmds" && build_old_libs=yes
-
- # Go through the arguments, transforming them on the way.
- while test "$#" -gt 0; do
- arg="$1"
- shift
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test
- ;;
- *) qarg=$arg ;;
- esac
- libtool_args="$libtool_args $qarg"
-
- # If the previous option needs an argument, assign it.
- if test -n "$prev"; then
- case $prev in
- output)
- compile_command="$compile_command @OUTPUT@"
- finalize_command="$finalize_command @OUTPUT@"
- ;;
- esac
-
- case $prev in
- dlfiles|dlprefiles)
- if test "$preload" = no; then
- # Add the symbol object into the linking commands.
- compile_command="$compile_command @SYMFILE@"
- finalize_command="$finalize_command @SYMFILE@"
- preload=yes
- fi
- case $arg in
- *.la | *.lo) ;; # We handle these cases below.
- force)
- if test "$dlself" = no; then
- dlself=needless
- export_dynamic=yes
- fi
- prev=
- continue
- ;;
- self)
- if test "$prev" = dlprefiles; then
- dlself=yes
- elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
- dlself=yes
- else
- dlself=needless
- export_dynamic=yes
- fi
- prev=
- continue
- ;;
- *)
- if test "$prev" = dlfiles; then
- dlfiles="$dlfiles $arg"
- else
- dlprefiles="$dlprefiles $arg"
- fi
- prev=
- continue
- ;;
- esac
- ;;
- expsyms)
- export_symbols="$arg"
- if test ! -f "$arg"; then
- $echo "$modename: symbol file \`$arg' does not exist"
- exit $EXIT_FAILURE
- fi
- prev=
- continue
- ;;
- expsyms_regex)
- export_symbols_regex="$arg"
- prev=
- continue
- ;;
- inst_prefix)
- inst_prefix_dir="$arg"
- prev=
- continue
- ;;
- precious_regex)
- precious_files_regex="$arg"
- prev=
- continue
- ;;
- release)
- release="-$arg"
- prev=
- continue
- ;;
- objectlist)
- if test -f "$arg"; then
- save_arg=$arg
- moreargs=
- for fil in `cat $save_arg`
- do
-# moreargs="$moreargs $fil"
- arg=$fil
- # A libtool-controlled object.
-
- # Check to see that this really is a libtool object.
- if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
- pic_object=
- non_pic_object=
-
- # Read the .lo file
- # If there is no directory component, then add one.
- case $arg in
- */* | *\\*) . $arg ;;
- *) . ./$arg ;;
- esac
-
- if test -z "$pic_object" || \
- test -z "$non_pic_object" ||
- test "$pic_object" = none && \
- test "$non_pic_object" = none; then
- $echo "$modename: cannot find name of object for \`$arg'" 1>&2
- exit $EXIT_FAILURE
- fi
-
- # Extract subdirectory from the argument.
- xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$xdir" = "X$arg"; then
- xdir=
- else
- xdir="$xdir/"
- fi
-
- if test "$pic_object" != none; then
- # Prepend the subdirectory the object is found in.
- pic_object="$xdir$pic_object"
-
- if test "$prev" = dlfiles; then
- if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
- dlfiles="$dlfiles $pic_object"
- prev=
- continue
- else
- # If libtool objects are unsupported, then we need to preload.
- prev=dlprefiles
- fi
- fi
-
- # CHECK ME: I think I busted this. -Ossama
- if test "$prev" = dlprefiles; then
- # Preload the old-style object.
- dlprefiles="$dlprefiles $pic_object"
- prev=
- fi
-
- # A PIC object.
- libobjs="$libobjs $pic_object"
- arg="$pic_object"
- fi
-
- # Non-PIC object.
- if test "$non_pic_object" != none; then
- # Prepend the subdirectory the object is found in.
- non_pic_object="$xdir$non_pic_object"
-
- # A standard non-PIC object
- non_pic_objects="$non_pic_objects $non_pic_object"
- if test -z "$pic_object" || test "$pic_object" = none ; then
- arg="$non_pic_object"
- fi
- else
- # If the PIC object exists, use it instead.
- # $xdir was prepended to $pic_object above.
- non_pic_object="$pic_object"
- non_pic_objects="$non_pic_objects $non_pic_object"
- fi
- else
- # Only an error if not doing a dry-run.
- if test -z "$run"; then
- $echo "$modename: \`$arg' is not a valid libtool object" 1>&2
- exit $EXIT_FAILURE
- else
- # Dry-run case.
-
- # Extract subdirectory from the argument.
- xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$xdir" = "X$arg"; then
- xdir=
- else
- xdir="$xdir/"
- fi
-
- pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"`
- non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"`
- libobjs="$libobjs $pic_object"
- non_pic_objects="$non_pic_objects $non_pic_object"
- fi
- fi
- done
- else
- $echo "$modename: link input file \`$save_arg' does not exist"
- exit $EXIT_FAILURE
- fi
- arg=$save_arg
- prev=
- continue
- ;;
- rpath | xrpath)
- # We need an absolute path.
- case $arg in
- [\\/]* | [A-Za-z]:[\\/]*) ;;
- *)
- $echo "$modename: only absolute run-paths are allowed" 1>&2
- exit $EXIT_FAILURE
- ;;
- esac
- if test "$prev" = rpath; then
- case "$rpath " in
- *" $arg "*) ;;
- *) rpath="$rpath $arg" ;;
- esac
- else
- case "$xrpath " in
- *" $arg "*) ;;
- *) xrpath="$xrpath $arg" ;;
- esac
- fi
- prev=
- continue
- ;;
- xcompiler)
- compiler_flags="$compiler_flags $qarg"
- prev=
- compile_command="$compile_command $qarg"
- finalize_command="$finalize_command $qarg"
- continue
- ;;
- xlinker)
- linker_flags="$linker_flags $qarg"
- compiler_flags="$compiler_flags $wl$qarg"
- prev=
- compile_command="$compile_command $wl$qarg"
- finalize_command="$finalize_command $wl$qarg"
- continue
- ;;
- xcclinker)
- linker_flags="$linker_flags $qarg"
- compiler_flags="$compiler_flags $qarg"
- prev=
- compile_command="$compile_command $qarg"
- finalize_command="$finalize_command $qarg"
- continue
- ;;
- shrext)
- shrext_cmds="$arg"
- prev=
- continue
- ;;
- darwin_framework|darwin_framework_skip)
- test "$prev" = "darwin_framework" && compiler_flags="$compiler_flags $arg"
- compile_command="$compile_command $arg"
- finalize_command="$finalize_command $arg"
- prev=
- continue
- ;;
- *)
- eval "$prev=\"\$arg\""
- prev=
- continue
- ;;
- esac
- fi # test -n "$prev"
-
- prevarg="$arg"
-
- case $arg in
- -all-static)
- if test -n "$link_static_flag"; then
- compile_command="$compile_command $link_static_flag"
- finalize_command="$finalize_command $link_static_flag"
- fi
- continue
- ;;
-
- -allow-undefined)
- # FIXME: remove this flag sometime in the future.
- $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2
- continue
- ;;
-
- -avoid-version)
- avoid_version=yes
- continue
- ;;
-
- -dlopen)
- prev=dlfiles
- continue
- ;;
-
- -dlpreopen)
- prev=dlprefiles
- continue
- ;;
-
- -export-dynamic)
- export_dynamic=yes
- continue
- ;;
-
- -export-symbols | -export-symbols-regex)
- if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
- $echo "$modename: more than one -exported-symbols argument is not allowed"
- exit $EXIT_FAILURE
- fi
- if test "X$arg" = "X-export-symbols"; then
- prev=expsyms
- else
- prev=expsyms_regex
- fi
- continue
- ;;
-
- -framework|-arch|-isysroot)
- case " $CC " in
- *" ${arg} ${1} "* | *" ${arg} ${1} "*)
- prev=darwin_framework_skip ;;
- *) compiler_flags="$compiler_flags $arg"
- prev=darwin_framework ;;
- esac
- compile_command="$compile_command $arg"
- finalize_command="$finalize_command $arg"
- continue
- ;;
-
- -inst-prefix-dir)
- prev=inst_prefix
- continue
- ;;
-
- # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
- # so, if we see these flags be careful not to treat them like -L
- -L[A-Z][A-Z]*:*)
- case $with_gcc/$host in
- no/*-*-irix* | /*-*-irix*)
- compile_command="$compile_command $arg"
- finalize_command="$finalize_command $arg"
- ;;
- esac
- continue
- ;;
-
- -L*)
- dir=`$echo "X$arg" | $Xsed -e 's/^-L//'`
- # We need an absolute path.
- case $dir in
- [\\/]* | [A-Za-z]:[\\/]*) ;;
- *)
- absdir=`cd "$dir" && pwd`
- if test -z "$absdir"; then
- $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2
- absdir="$dir"
- notinst_path="$notinst_path $dir"
- fi
- dir="$absdir"
- ;;
- esac
- case "$deplibs " in
- *" -L$dir "*) ;;
- *)
- deplibs="$deplibs -L$dir"
- lib_search_path="$lib_search_path $dir"
- ;;
- esac
- case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
- testbindir=`$echo "X$dir" | $Xsed -e 's*/lib$*/bin*'`
- case :$dllsearchpath: in
- *":$dir:"*) ;;
- *) dllsearchpath="$dllsearchpath:$dir";;
- esac
- case :$dllsearchpath: in
- *":$testbindir:"*) ;;
- *) dllsearchpath="$dllsearchpath:$testbindir";;
- esac
- ;;
- esac
- continue
- ;;
-
- -l*)
- if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
- case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos*)
- # These systems don't actually have a C or math library (as such)
- continue
- ;;
- *-*-os2*)
- # These systems don't actually have a C library (as such)
- test "X$arg" = "X-lc" && continue
- ;;
- *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
- # Do not include libc due to us having libc/libc_r.
- test "X$arg" = "X-lc" && continue
- ;;
- *-*-rhapsody* | *-*-darwin1.[012])
- # Rhapsody C and math libraries are in the System framework
- deplibs="$deplibs -framework System"
- continue
- ;;
- *-*-sco3.2v5* | *-*-sco5v6*)
- # Causes problems with __ctype
- test "X$arg" = "X-lc" && continue
- ;;
- *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
- # Compiler inserts libc in the correct place for threads to work
- test "X$arg" = "X-lc" && continue
- ;;
- esac
- elif test "X$arg" = "X-lc_r"; then
- case $host in
- *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
- # Do not include libc_r directly, use -pthread flag.
- continue
- ;;
- esac
- fi
- deplibs="$deplibs $arg"
- continue
- ;;
-
- # Tru64 UNIX uses -model [arg] to determine the layout of C++
- # classes, name mangling, and exception handling.
- -model)
- compile_command="$compile_command $arg"
- compiler_flags="$compiler_flags $arg"
- finalize_command="$finalize_command $arg"
- prev=xcompiler
- continue
- ;;
-
- -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe)
- compiler_flags="$compiler_flags $arg"
- compile_command="$compile_command $arg"
- finalize_command="$finalize_command $arg"
- continue
- ;;
-
- -module)
- module=yes
- continue
- ;;
-
- # -64, -mips[0-9] enable 64-bit mode on the SGI compiler
- # -r[0-9][0-9]* specifies the processor on the SGI compiler
- # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler
- # +DA*, +DD* enable 64-bit mode on the HP compiler
- # -q* pass through compiler args for the IBM compiler
- # -m* pass through architecture-specific compiler args for GCC
- # -m*, -t[45]*, -txscale* pass through architecture-specific
- # compiler args for GCC
- # -pg pass through profiling flag for GCC
- # @file GCC response files
- -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
- -t[45]*|-txscale*|@*)
-
- # Unknown arguments in both finalize_command and compile_command need
- # to be aesthetically quoted because they are evaled later.
- arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- arg="\"$arg\""
- ;;
- esac
- compile_command="$compile_command $arg"
- finalize_command="$finalize_command $arg"
- compiler_flags="$compiler_flags $arg"
- continue
- ;;
-
- -shrext)
- prev=shrext
- continue
- ;;
-
- -no-fast-install)
- fast_install=no
- continue
- ;;
-
- -no-install)
- case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
- # The PATH hackery in wrapper scripts is required on Windows
- # in order for the loader to find any dlls it needs.
- $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2
- $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2
- fast_install=no
- ;;
- *) no_install=yes ;;
- esac
- continue
- ;;
-
- -no-undefined)
- allow_undefined=no
- continue
- ;;
-
- -objectlist)
- prev=objectlist
- continue
- ;;
-
- -o) prev=output ;;
-
- -precious-files-regex)
- prev=precious_regex
- continue
- ;;
-
- -release)
- prev=release
- continue
- ;;
-
- -rpath)
- prev=rpath
- continue
- ;;
-
- -R)
- prev=xrpath
- continue
- ;;
-
- -R*)
- dir=`$echo "X$arg" | $Xsed -e 's/^-R//'`
- # We need an absolute path.
- case $dir in
- [\\/]* | [A-Za-z]:[\\/]*) ;;
- *)
- $echo "$modename: only absolute run-paths are allowed" 1>&2
- exit $EXIT_FAILURE
- ;;
- esac
- case "$xrpath " in
- *" $dir "*) ;;
- *) xrpath="$xrpath $dir" ;;
- esac
- continue
- ;;
-
- -static)
- # The effects of -static are defined in a previous loop.
- # We used to do the same as -all-static on platforms that
- # didn't have a PIC flag, but the assumption that the effects
- # would be equivalent was wrong. It would break on at least
- # Digital Unix and AIX.
- continue
- ;;
-
- -thread-safe)
- thread_safe=yes
- continue
- ;;
-
- -version-info)
- prev=vinfo
- continue
- ;;
- -version-number)
- prev=vinfo
- vinfo_number=yes
- continue
- ;;
-
- -Wc,*)
- args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'`
- arg=
- save_ifs="$IFS"; IFS=','
- for flag in $args; do
- IFS="$save_ifs"
- case $flag in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- flag="\"$flag\""
- ;;
- esac
- arg="$arg $wl$flag"
- compiler_flags="$compiler_flags $flag"
- done
- IFS="$save_ifs"
- arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
- ;;
-
- -Wl,*)
- args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'`
- arg=
- save_ifs="$IFS"; IFS=','
- for flag in $args; do
- IFS="$save_ifs"
- case $flag in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- flag="\"$flag\""
- ;;
- esac
- arg="$arg $wl$flag"
- compiler_flags="$compiler_flags $wl$flag"
- linker_flags="$linker_flags $flag"
- done
- IFS="$save_ifs"
- arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
- ;;
-
- -Xcompiler)
- prev=xcompiler
- continue
- ;;
-
- -Xlinker)
- prev=xlinker
- continue
- ;;
-
- -XCClinker)
- prev=xcclinker
- continue
- ;;
-
- # Some other compiler flag.
- -* | +*)
- # Unknown arguments in both finalize_command and compile_command need
- # to be aesthetically quoted because they are evaled later.
- arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- arg="\"$arg\""
- ;;
- esac
- ;;
-
- *.$objext)
- # A standard object.
- objs="$objs $arg"
- ;;
-
- *.lo)
- # A libtool-controlled object.
-
- # Check to see that this really is a libtool object.
- if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
- pic_object=
- non_pic_object=
-
- # Read the .lo file
- # If there is no directory component, then add one.
- case $arg in
- */* | *\\*) . $arg ;;
- *) . ./$arg ;;
- esac
-
- if test -z "$pic_object" || \
- test -z "$non_pic_object" ||
- test "$pic_object" = none && \
- test "$non_pic_object" = none; then
- $echo "$modename: cannot find name of object for \`$arg'" 1>&2
- exit $EXIT_FAILURE
- fi
-
- # Extract subdirectory from the argument.
- xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$xdir" = "X$arg"; then
- xdir=
- else
- xdir="$xdir/"
- fi
-
- if test "$pic_object" != none; then
- # Prepend the subdirectory the object is found in.
- pic_object="$xdir$pic_object"
-
- if test "$prev" = dlfiles; then
- if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
- dlfiles="$dlfiles $pic_object"
- prev=
- continue
- else
- # If libtool objects are unsupported, then we need to preload.
- prev=dlprefiles
- fi
- fi
-
- # CHECK ME: I think I busted this. -Ossama
- if test "$prev" = dlprefiles; then
- # Preload the old-style object.
- dlprefiles="$dlprefiles $pic_object"
- prev=
- fi
-
- # A PIC object.
- libobjs="$libobjs $pic_object"
- arg="$pic_object"
- fi
-
- # Non-PIC object.
- if test "$non_pic_object" != none; then
- # Prepend the subdirectory the object is found in.
- non_pic_object="$xdir$non_pic_object"
-
- # A standard non-PIC object
- non_pic_objects="$non_pic_objects $non_pic_object"
- if test -z "$pic_object" || test "$pic_object" = none ; then
- arg="$non_pic_object"
- fi
- else
- # If the PIC object exists, use it instead.
- # $xdir was prepended to $pic_object above.
- non_pic_object="$pic_object"
- non_pic_objects="$non_pic_objects $non_pic_object"
- fi
- else
- # Only an error if not doing a dry-run.
- if test -z "$run"; then
- $echo "$modename: \`$arg' is not a valid libtool object" 1>&2
- exit $EXIT_FAILURE
- else
- # Dry-run case.
-
- # Extract subdirectory from the argument.
- xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$xdir" = "X$arg"; then
- xdir=
- else
- xdir="$xdir/"
- fi
-
- pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"`
- non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"`
- libobjs="$libobjs $pic_object"
- non_pic_objects="$non_pic_objects $non_pic_object"
- fi
- fi
- ;;
-
- *.$libext)
- # An archive.
- deplibs="$deplibs $arg"
- old_deplibs="$old_deplibs $arg"
- continue
- ;;
-
- *.la)
- # A libtool-controlled library.
-
- if test "$prev" = dlfiles; then
- # This library was specified with -dlopen.
- dlfiles="$dlfiles $arg"
- prev=
- elif test "$prev" = dlprefiles; then
- # The library was specified with -dlpreopen.
- dlprefiles="$dlprefiles $arg"
- prev=
- else
- deplibs="$deplibs $arg"
- fi
- continue
- ;;
-
- # Some other compiler argument.
- *)
- # Unknown arguments in both finalize_command and compile_command need
- # to be aesthetically quoted because they are evaled later.
- arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- arg="\"$arg\""
- ;;
- esac
- ;;
- esac # arg
-
- # Now actually substitute the argument into the commands.
- if test -n "$arg"; then
- compile_command="$compile_command $arg"
- finalize_command="$finalize_command $arg"
- fi
- done # argument parsing loop
-
- if test -n "$prev"; then
- $echo "$modename: the \`$prevarg' option requires an argument" 1>&2
- $echo "$help" 1>&2
- exit $EXIT_FAILURE
- fi
-
- if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
- eval arg=\"$export_dynamic_flag_spec\"
- compile_command="$compile_command $arg"
- finalize_command="$finalize_command $arg"
- fi
-
- oldlibs=
- # calculate the name of the file, without its directory
- outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'`
- libobjs_save="$libobjs"
-
- if test -n "$shlibpath_var"; then
- # get the directories listed in $shlibpath_var
- eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\`
- else
- shlib_search_path=
- fi
- eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
- eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
-
- output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$output_objdir" = "X$output"; then
- output_objdir="$objdir"
- else
- output_objdir="$output_objdir/$objdir"
- fi
- # Create the object directory.
- if test ! -d "$output_objdir"; then
- $show "$mkdir $output_objdir"
- $run $mkdir $output_objdir
- exit_status=$?
- if test "$exit_status" -ne 0 && test ! -d "$output_objdir"; then
- exit $exit_status
- fi
- fi
-
- # Determine the type of output
- case $output in
- "")
- $echo "$modename: you must specify an output file" 1>&2
- $echo "$help" 1>&2
- exit $EXIT_FAILURE
- ;;
- *.$libext) linkmode=oldlib ;;
- *.lo | *.$objext) linkmode=obj ;;
- *.la) linkmode=lib ;;
- *) linkmode=prog ;; # Anything else should be a program.
- esac
-
- case $host in
- *cygwin* | *mingw* | *pw32*)
- # don't eliminate duplications in $postdeps and $predeps
- duplicate_compiler_generated_deps=yes
- ;;
- *)
- duplicate_compiler_generated_deps=$duplicate_deps
- ;;
- esac
- specialdeplibs=
-
- libs=
- # Find all interdependent deplibs by searching for libraries
- # that are linked more than once (e.g. -la -lb -la)
- for deplib in $deplibs; do
- if test "X$duplicate_deps" = "Xyes" ; then
- case "$libs " in
- *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
- esac
- fi
- libs="$libs $deplib"
- done
-
- if test "$linkmode" = lib; then
- libs="$predeps $libs $compiler_lib_search_path $postdeps"
-
- # Compute libraries that are listed more than once in $predeps
- # $postdeps and mark them as special (i.e., whose duplicates are
- # not to be eliminated).
- pre_post_deps=
- if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then
- for pre_post_dep in $predeps $postdeps; do
- case "$pre_post_deps " in
- *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;;
- esac
- pre_post_deps="$pre_post_deps $pre_post_dep"
- done
- fi
- pre_post_deps=
- fi
-
- deplibs=
- newdependency_libs=
- newlib_search_path=
- need_relink=no # whether we're linking any uninstalled libtool libraries
- notinst_deplibs= # not-installed libtool libraries
- case $linkmode in
- lib)
- passes="conv link"
- for file in $dlfiles $dlprefiles; do
- case $file in
- *.la) ;;
- *)
- $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2
- exit $EXIT_FAILURE
- ;;
- esac
- done
- ;;
- prog)
- compile_deplibs=
- finalize_deplibs=
- alldeplibs=no
- newdlfiles=
- newdlprefiles=
- passes="conv scan dlopen dlpreopen link"
- ;;
- *) passes="conv"
- ;;
- esac
- for pass in $passes; do
- if test "$linkmode,$pass" = "lib,link" ||
- test "$linkmode,$pass" = "prog,scan"; then
- libs="$deplibs"
- deplibs=
- fi
- if test "$linkmode" = prog; then
- case $pass in
- dlopen) libs="$dlfiles" ;;
- dlpreopen) libs="$dlprefiles" ;;
- link)
- libs="$deplibs %DEPLIBS%"
- test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs"
- ;;
- esac
- fi
- if test "$pass" = dlopen; then
- # Collect dlpreopened libraries
- save_deplibs="$deplibs"
- deplibs=
- fi
- for deplib in $libs; do
- lib=
- found=no
- case $deplib in
- -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe)
- if test "$linkmode,$pass" = "prog,link"; then
- compile_deplibs="$deplib $compile_deplibs"
- finalize_deplibs="$deplib $finalize_deplibs"
- else
- compiler_flags="$compiler_flags $deplib"
- fi
- continue
- ;;
- -l*)
- if test "$linkmode" != lib && test "$linkmode" != prog; then
- $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2
- continue
- fi
- name=`$echo "X$deplib" | $Xsed -e 's/^-l//'`
- for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do
- for search_ext in .la $std_shrext .so .a; do
- # Search the libtool library
- lib="$searchdir/lib${name}${search_ext}"
- if test -f "$lib"; then
- if test "$search_ext" = ".la"; then
- found=yes
- else
- found=no
- fi
- break 2
- fi
- done
- done
- if test "$found" != yes; then
- # deplib doesn't seem to be a libtool library
- if test "$linkmode,$pass" = "prog,link"; then
- compile_deplibs="$deplib $compile_deplibs"
- finalize_deplibs="$deplib $finalize_deplibs"
- else
- deplibs="$deplib $deplibs"
- test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
- fi
- continue
- else # deplib is a libtool library
- # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
- # We need to do some special things here, and not later.
- if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
- case " $predeps $postdeps " in
- *" $deplib "*)
- if (${SED} -e '2q' $lib |
- grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
- library_names=
- old_library=
- case $lib in
- */* | *\\*) . $lib ;;
- *) . ./$lib ;;
- esac
- for l in $old_library $library_names; do
- ll="$l"
- done
- if test "X$ll" = "X$old_library" ; then # only static version available
- found=no
- ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
- test "X$ladir" = "X$lib" && ladir="."
- lib=$ladir/$old_library
- if test "$linkmode,$pass" = "prog,link"; then
- compile_deplibs="$deplib $compile_deplibs"
- finalize_deplibs="$deplib $finalize_deplibs"
- else
- deplibs="$deplib $deplibs"
- test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
- fi
- continue
- fi
- fi
- ;;
- *) ;;
- esac
- fi
- fi
- ;; # -l
- -L*)
- case $linkmode in
- lib)
- deplibs="$deplib $deplibs"
- test "$pass" = conv && continue
- newdependency_libs="$deplib $newdependency_libs"
- newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
- ;;
- prog)
- if test "$pass" = conv; then
- deplibs="$deplib $deplibs"
- continue
- fi
- if test "$pass" = scan; then
- deplibs="$deplib $deplibs"
- else
- compile_deplibs="$deplib $compile_deplibs"
- finalize_deplibs="$deplib $finalize_deplibs"
- fi
- newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
- ;;
- *)
- $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2
- ;;
- esac # linkmode
- continue
- ;; # -L
- -R*)
- if test "$pass" = link; then
- dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'`
- # Make sure the xrpath contains only unique directories.
- case "$xrpath " in
- *" $dir "*) ;;
- *) xrpath="$xrpath $dir" ;;
- esac
- fi
- deplibs="$deplib $deplibs"
- continue
- ;;
- *.la) lib="$deplib" ;;
- *.$libext)
- if test "$pass" = conv; then
- deplibs="$deplib $deplibs"
- continue
- fi
- case $linkmode in
- lib)
- valid_a_lib=no
- case $deplibs_check_method in
- match_pattern*)
- set dummy $deplibs_check_method
- match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
- if eval $echo \"$deplib\" 2>/dev/null \
- | $SED 10q \
- | $EGREP "$match_pattern_regex" > /dev/null; then
- valid_a_lib=yes
- fi
- ;;
- pass_all)
- valid_a_lib=yes
- ;;
- esac
- if test "$valid_a_lib" != yes; then
- $echo
- $echo "*** Warning: Trying to link with static lib archive $deplib."
- $echo "*** I have the capability to make that library automatically link in when"
- $echo "*** you link to this library. But I can only do this if you have a"
- $echo "*** shared version of the library, which you do not appear to have"
- $echo "*** because the file extensions .$libext of this argument makes me believe"
- $echo "*** that it is just a static archive that I should not used here."
- else
- $echo
- $echo "*** Warning: Linking the shared library $output against the"
- $echo "*** static library $deplib is not portable!"
- deplibs="$deplib $deplibs"
- fi
- continue
- ;;
- prog)
- if test "$pass" != link; then
- deplibs="$deplib $deplibs"
- else
- compile_deplibs="$deplib $compile_deplibs"
- finalize_deplibs="$deplib $finalize_deplibs"
- fi
- continue
- ;;
- esac # linkmode
- ;; # *.$libext
- *.lo | *.$objext)
- if test "$pass" = conv; then
- deplibs="$deplib $deplibs"
- elif test "$linkmode" = prog; then
- if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
- # If there is no dlopen support or we're linking statically,
- # we need to preload.
- newdlprefiles="$newdlprefiles $deplib"
- compile_deplibs="$deplib $compile_deplibs"
- finalize_deplibs="$deplib $finalize_deplibs"
- else
- newdlfiles="$newdlfiles $deplib"
- fi
- fi
- continue
- ;;
- %DEPLIBS%)
- alldeplibs=yes
- continue
- ;;
- esac # case $deplib
- if test "$found" = yes || test -f "$lib"; then :
- else
- $echo "$modename: cannot find the library \`$lib' or unhandled argument \`$deplib'" 1>&2
- exit $EXIT_FAILURE
- fi
-
- # Check to see that this really is a libtool archive.
- if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
- else
- $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
- exit $EXIT_FAILURE
- fi
-
- ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
- test "X$ladir" = "X$lib" && ladir="."
-
- dlname=
- dlopen=
- dlpreopen=
- libdir=
- library_names=
- old_library=
- # If the library was installed with an old release of libtool,
- # it will not redefine variables installed, or shouldnotlink
- installed=yes
- shouldnotlink=no
- avoidtemprpath=
-
-
- # Read the .la file
- case $lib in
- */* | *\\*) . $lib ;;
- *) . ./$lib ;;
- esac
-
- if test "$linkmode,$pass" = "lib,link" ||
- test "$linkmode,$pass" = "prog,scan" ||
- { test "$linkmode" != prog && test "$linkmode" != lib; }; then
- test -n "$dlopen" && dlfiles="$dlfiles $dlopen"
- test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen"
- fi
-
- if test "$pass" = conv; then
- # Only check for convenience libraries
- deplibs="$lib $deplibs"
- if test -z "$libdir"; then
- if test -z "$old_library"; then
- $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
- exit $EXIT_FAILURE
- fi
- # It is a libtool convenience library, so add in its objects.
- convenience="$convenience $ladir/$objdir/$old_library"
- old_convenience="$old_convenience $ladir/$objdir/$old_library"
- tmp_libs=
- for deplib in $dependency_libs; do
- deplibs="$deplib $deplibs"
- if test "X$duplicate_deps" = "Xyes" ; then
- case "$tmp_libs " in
- *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
- esac
- fi
- tmp_libs="$tmp_libs $deplib"
- done
- elif test "$linkmode" != prog && test "$linkmode" != lib; then
- $echo "$modename: \`$lib' is not a convenience library" 1>&2
- exit $EXIT_FAILURE
- fi
- continue
- fi # $pass = conv
-
-
- # Get the name of the library we link against.
- linklib=
- for l in $old_library $library_names; do
- linklib="$l"
- done
- if test -z "$linklib"; then
- $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
- exit $EXIT_FAILURE
- fi
-
- # This library was specified with -dlopen.
- if test "$pass" = dlopen; then
- if test -z "$libdir"; then
- $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2
- exit $EXIT_FAILURE
- fi
- if test -z "$dlname" ||
- test "$dlopen_support" != yes ||
- test "$build_libtool_libs" = no; then
- # If there is no dlname, no dlopen support or we're linking
- # statically, we need to preload. We also need to preload any
- # dependent libraries so libltdl's deplib preloader doesn't
- # bomb out in the load deplibs phase.
- dlprefiles="$dlprefiles $lib $dependency_libs"
- else
- newdlfiles="$newdlfiles $lib"
- fi
- continue
- fi # $pass = dlopen
-
- # We need an absolute path.
- case $ladir in
- [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
- *)
- abs_ladir=`cd "$ladir" && pwd`
- if test -z "$abs_ladir"; then
- $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2
- $echo "$modename: passing it literally to the linker, although it might fail" 1>&2
- abs_ladir="$ladir"
- fi
- ;;
- esac
- laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
-
- # Find the relevant object directory and library name.
- if test "X$installed" = Xyes; then
- if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
- $echo "$modename: warning: library \`$lib' was moved." 1>&2
- dir="$ladir"
- absdir="$abs_ladir"
- libdir="$abs_ladir"
- else
- dir="$libdir"
- absdir="$libdir"
- fi
- test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
- else
- if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
- dir="$ladir"
- absdir="$abs_ladir"
- # Remove this search path later
- notinst_path="$notinst_path $abs_ladir"
- else
- dir="$ladir/$objdir"
- absdir="$abs_ladir/$objdir"
- # Remove this search path later
- notinst_path="$notinst_path $abs_ladir"
- fi
- fi # $installed = yes
- name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
-
- # This library was specified with -dlpreopen.
- if test "$pass" = dlpreopen; then
- if test -z "$libdir"; then
- $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2
- exit $EXIT_FAILURE
- fi
- # Prefer using a static library (so that no silly _DYNAMIC symbols
- # are required to link).
- if test -n "$old_library"; then
- newdlprefiles="$newdlprefiles $dir/$old_library"
- # Otherwise, use the dlname, so that lt_dlopen finds it.
- elif test -n "$dlname"; then
- newdlprefiles="$newdlprefiles $dir/$dlname"
- else
- newdlprefiles="$newdlprefiles $dir/$linklib"
- fi
- fi # $pass = dlpreopen
-
- if test -z "$libdir"; then
- # Link the convenience library
- if test "$linkmode" = lib; then
- deplibs="$dir/$old_library $deplibs"
- elif test "$linkmode,$pass" = "prog,link"; then
- compile_deplibs="$dir/$old_library $compile_deplibs"
- finalize_deplibs="$dir/$old_library $finalize_deplibs"
- else
- deplibs="$lib $deplibs" # used for prog,scan pass
- fi
- continue
- fi
-
-
- if test "$linkmode" = prog && test "$pass" != link; then
- newlib_search_path="$newlib_search_path $ladir"
- deplibs="$lib $deplibs"
-
- linkalldeplibs=no
- if test "$link_all_deplibs" != no || test -z "$library_names" ||
- test "$build_libtool_libs" = no; then
- linkalldeplibs=yes
- fi
-
- tmp_libs=
- for deplib in $dependency_libs; do
- case $deplib in
- -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test
- esac
- # Need to link against all dependency_libs?
- if test "$linkalldeplibs" = yes; then
- deplibs="$deplib $deplibs"
- else
- # Need to hardcode shared library paths
- # or/and link against static libraries
- newdependency_libs="$deplib $newdependency_libs"
- fi
- if test "X$duplicate_deps" = "Xyes" ; then
- case "$tmp_libs " in
- *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
- esac
- fi
- tmp_libs="$tmp_libs $deplib"
- done # for deplib
- continue
- fi # $linkmode = prog...
-
- if test "$linkmode,$pass" = "prog,link"; then
- if test -n "$library_names" &&
- { test "$prefer_static_libs" = no || test -z "$old_library"; }; then
- # We need to hardcode the library path
- if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
- # Make sure the rpath contains only unique directories.
- case "$temp_rpath " in
- *" $dir "*) ;;
- *" $absdir "*) ;;
- *) temp_rpath="$temp_rpath $absdir" ;;
- esac
- fi
-
- # Hardcode the library path.
- # Skip directories that are in the system default run-time
- # search path.
- case " $sys_lib_dlsearch_path " in
- *" $absdir "*) ;;
- *)
- case "$compile_rpath " in
- *" $absdir "*) ;;
- *) compile_rpath="$compile_rpath $absdir"
- esac
- ;;
- esac
- case " $sys_lib_dlsearch_path " in
- *" $libdir "*) ;;
- *)
- case "$finalize_rpath " in
- *" $libdir "*) ;;
- *) finalize_rpath="$finalize_rpath $libdir"
- esac
- ;;
- esac
- fi # $linkmode,$pass = prog,link...
-
- if test "$alldeplibs" = yes &&
- { test "$deplibs_check_method" = pass_all ||
- { test "$build_libtool_libs" = yes &&
- test -n "$library_names"; }; }; then
- # We only need to search for static libraries
- continue
- fi
- fi
-
- link_static=no # Whether the deplib will be linked statically
- use_static_libs=$prefer_static_libs
- if test "$use_static_libs" = built && test "$installed" = yes ; then
- use_static_libs=no
- fi
- if test -n "$library_names" &&
- { test "$use_static_libs" = no || test -z "$old_library"; }; then
- if test "$installed" = no; then
- notinst_deplibs="$notinst_deplibs $lib"
- need_relink=yes
- fi
- # This is a shared library
-
- # Warn about portability, can't link against -module's on
- # some systems (darwin)
- if test "$shouldnotlink" = yes && test "$pass" = link ; then
- $echo
- if test "$linkmode" = prog; then
- $echo "*** Warning: Linking the executable $output against the loadable module"
- else
- $echo "*** Warning: Linking the shared library $output against the loadable module"
- fi
- $echo "*** $linklib is not portable!"
- fi
- if test "$linkmode" = lib &&
- test "$hardcode_into_libs" = yes; then
- # Hardcode the library path.
- # Skip directories that are in the system default run-time
- # search path.
- case " $sys_lib_dlsearch_path " in
- *" $absdir "*) ;;
- *)
- case "$compile_rpath " in
- *" $absdir "*) ;;
- *) compile_rpath="$compile_rpath $absdir"
- esac
- ;;
- esac
- case " $sys_lib_dlsearch_path " in
- *" $libdir "*) ;;
- *)
- case "$finalize_rpath " in
- *" $libdir "*) ;;
- *) finalize_rpath="$finalize_rpath $libdir"
- esac
- ;;
- esac
- fi
-
- if test -n "$old_archive_from_expsyms_cmds"; then
- # figure out the soname
- set dummy $library_names
- realname="$2"
- shift; shift
- libname=`eval \\$echo \"$libname_spec\"`
- # use dlname if we got it. it's perfectly good, no?
- if test -n "$dlname"; then
- soname="$dlname"
- elif test -n "$soname_spec"; then
- # bleh windows
- case $host in
- *cygwin* | mingw*)
- major=`expr $current - $age`
- versuffix="-$major"
- ;;
- esac
- eval soname=\"$soname_spec\"
- else
- soname="$realname"
- fi
-
- # Make a new name for the extract_expsyms_cmds to use
- soroot="$soname"
- soname=`$echo $soroot | ${SED} -e 's/^.*\///'`
- newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a"
-
- # If the library has no export list, then create one now
- if test -f "$output_objdir/$soname-def"; then :
- else
- $show "extracting exported symbol list from \`$soname'"
- save_ifs="$IFS"; IFS='~'
- cmds=$extract_expsyms_cmds
- for cmd in $cmds; do
- IFS="$save_ifs"
- eval cmd=\"$cmd\"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- fi
-
- # Create $newlib
- if test -f "$output_objdir/$newlib"; then :; else
- $show "generating import library for \`$soname'"
- save_ifs="$IFS"; IFS='~'
- cmds=$old_archive_from_expsyms_cmds
- for cmd in $cmds; do
- IFS="$save_ifs"
- eval cmd=\"$cmd\"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- fi
- # make sure the library variables are pointing to the new library
- dir=$output_objdir
- linklib=$newlib
- fi # test -n "$old_archive_from_expsyms_cmds"
-
- if test "$linkmode" = prog || test "$mode" != relink; then
- add_shlibpath=
- add_dir=
- add=
- lib_linked=yes
- case $hardcode_action in
- immediate | unsupported)
- if test "$hardcode_direct" = no; then
- add="$dir/$linklib"
- case $host in
- *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;;
- *-*-sysv4*uw2*) add_dir="-L$dir" ;;
- *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
- *-*-unixware7*) add_dir="-L$dir" ;;
- *-*-darwin* )
- # if the lib is a module then we can not link against
- # it, someone is ignoring the new warnings I added
- if /usr/bin/file -L $add 2> /dev/null |
- $EGREP ": [^:]* bundle" >/dev/null ; then
- $echo "** Warning, lib $linklib is a module, not a shared library"
- if test -z "$old_library" ; then
- $echo
- $echo "** And there doesn't seem to be a static archive available"
- $echo "** The link will probably fail, sorry"
- else
- add="$dir/$old_library"
- fi
- fi
- esac
- elif test "$hardcode_minus_L" = no; then
- case $host in
- *-*-sunos*) add_shlibpath="$dir" ;;
- esac
- add_dir="-L$dir"
- add="-l$name"
- elif test "$hardcode_shlibpath_var" = no; then
- add_shlibpath="$dir"
- add="-l$name"
- else
- lib_linked=no
- fi
- ;;
- relink)
- if test "$hardcode_direct" = yes; then
- add="$dir/$linklib"
- elif test "$hardcode_minus_L" = yes; then
- add_dir="-L$dir"
- # Try looking first in the location we're being installed to.
- if test -n "$inst_prefix_dir"; then
- case $libdir in
- [\\/]*)
- add_dir="$add_dir -L$inst_prefix_dir$libdir"
- ;;
- esac
- fi
- add="-l$name"
- elif test "$hardcode_shlibpath_var" = yes; then
- add_shlibpath="$dir"
- add="-l$name"
- else
- lib_linked=no
- fi
- ;;
- *) lib_linked=no ;;
- esac
-
- if test "$lib_linked" != yes; then
- $echo "$modename: configuration error: unsupported hardcode properties"
- exit $EXIT_FAILURE
- fi
-
- if test -n "$add_shlibpath"; then
- case :$compile_shlibpath: in
- *":$add_shlibpath:"*) ;;
- *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;;
- esac
- fi
- if test "$linkmode" = prog; then
- test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
- test -n "$add" && compile_deplibs="$add $compile_deplibs"
- else
- test -n "$add_dir" && deplibs="$add_dir $deplibs"
- test -n "$add" && deplibs="$add $deplibs"
- if test "$hardcode_direct" != yes && \
- test "$hardcode_minus_L" != yes && \
- test "$hardcode_shlibpath_var" = yes; then
- case :$finalize_shlibpath: in
- *":$libdir:"*) ;;
- *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
- esac
- fi
- fi
- fi
-
- if test "$linkmode" = prog || test "$mode" = relink; then
- add_shlibpath=
- add_dir=
- add=
- # Finalize command for both is simple: just hardcode it.
- if test "$hardcode_direct" = yes; then
- add="$libdir/$linklib"
- elif test "$hardcode_minus_L" = yes; then
- add_dir="-L$libdir"
- add="-l$name"
- elif test "$hardcode_shlibpath_var" = yes; then
- case :$finalize_shlibpath: in
- *":$libdir:"*) ;;
- *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
- esac
- add="-l$name"
- elif test "$hardcode_automatic" = yes; then
- if test -n "$inst_prefix_dir" &&
- test -f "$inst_prefix_dir$libdir/$linklib" ; then
- add="$inst_prefix_dir$libdir/$linklib"
- else
- add="$libdir/$linklib"
- fi
- else
- # We cannot seem to hardcode it, guess we'll fake it.
- add_dir="-L$libdir"
- # Try looking first in the location we're being installed to.
- if test -n "$inst_prefix_dir"; then
- case $libdir in
- [\\/]*)
- add_dir="$add_dir -L$inst_prefix_dir$libdir"
- ;;
- esac
- fi
- add="-l$name"
- fi
-
- if test "$linkmode" = prog; then
- test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
- test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
- else
- test -n "$add_dir" && deplibs="$add_dir $deplibs"
- test -n "$add" && deplibs="$add $deplibs"
- fi
- fi
- elif test "$linkmode" = prog; then
- # Here we assume that one of hardcode_direct or hardcode_minus_L
- # is not unsupported. This is valid on all known static and
- # shared platforms.
- if test "$hardcode_direct" != unsupported; then
- test -n "$old_library" && linklib="$old_library"
- compile_deplibs="$dir/$linklib $compile_deplibs"
- finalize_deplibs="$dir/$linklib $finalize_deplibs"
- else
- compile_deplibs="-l$name -L$dir $compile_deplibs"
- finalize_deplibs="-l$name -L$dir $finalize_deplibs"
- fi
- elif test "$build_libtool_libs" = yes; then
- # Not a shared library
- if test "$deplibs_check_method" != pass_all; then
- # We're trying link a shared library against a static one
- # but the system doesn't support it.
-
- # Just print a warning and add the library to dependency_libs so
- # that the program can be linked against the static library.
- $echo
- $echo "*** Warning: This system can not link to static lib archive $lib."
- $echo "*** I have the capability to make that library automatically link in when"
- $echo "*** you link to this library. But I can only do this if you have a"
- $echo "*** shared version of the library, which you do not appear to have."
- if test "$module" = yes; then
- $echo "*** But as you try to build a module library, libtool will still create "
- $echo "*** a static module, that should work as long as the dlopening application"
- $echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
- if test -z "$global_symbol_pipe"; then
- $echo
- $echo "*** However, this would only work if libtool was able to extract symbol"
- $echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
- $echo "*** not find such a program. So, this module is probably useless."
- $echo "*** \`nm' from GNU binutils and a full rebuild may help."
- fi
- if test "$build_old_libs" = no; then
- build_libtool_libs=module
- build_old_libs=yes
- else
- build_libtool_libs=no
- fi
- fi
- else
- deplibs="$dir/$old_library $deplibs"
- link_static=yes
- fi
- fi # link shared/static library?
-
- if test "$linkmode" = lib; then
- if test -n "$dependency_libs" &&
- { test "$hardcode_into_libs" != yes ||
- test "$build_old_libs" = yes ||
- test "$link_static" = yes; }; then
- # Extract -R from dependency_libs
- temp_deplibs=
- for libdir in $dependency_libs; do
- case $libdir in
- -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'`
- case " $xrpath " in
- *" $temp_xrpath "*) ;;
- *) xrpath="$xrpath $temp_xrpath";;
- esac;;
- *) temp_deplibs="$temp_deplibs $libdir";;
- esac
- done
- dependency_libs="$temp_deplibs"
- fi
-
- newlib_search_path="$newlib_search_path $absdir"
- # Link against this library
- test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
- # ... and its dependency_libs
- tmp_libs=
- for deplib in $dependency_libs; do
- newdependency_libs="$deplib $newdependency_libs"
- if test "X$duplicate_deps" = "Xyes" ; then
- case "$tmp_libs " in
- *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
- esac
- fi
- tmp_libs="$tmp_libs $deplib"
- done
-
- if test "$link_all_deplibs" != no; then
- # Add the search paths of all dependency libraries
- for deplib in $dependency_libs; do
- case $deplib in
- -L*) path="$deplib" ;;
- *.la)
- dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'`
- test "X$dir" = "X$deplib" && dir="."
- # We need an absolute path.
- case $dir in
- [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
- *)
- absdir=`cd "$dir" && pwd`
- if test -z "$absdir"; then
- $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2
- absdir="$dir"
- fi
- ;;
- esac
- if grep "^installed=no" $deplib > /dev/null; then
- path="$absdir/$objdir"
- else
- eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
- if test -z "$libdir"; then
- $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
- exit $EXIT_FAILURE
- fi
- if test "$absdir" != "$libdir"; then
- $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2
- fi
- path="$absdir"
- fi
- depdepl=
- case $host in
- *-*-darwin*)
- # we do not want to link against static libs,
- # but need to link against shared
- eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
- if test -n "$deplibrary_names" ; then
- for tmp in $deplibrary_names ; do
- depdepl=$tmp
- done
- if test -f "$path/$depdepl" ; then
- depdepl="$path/$depdepl"
- fi
- # do not add paths which are already there
- case " $newlib_search_path " in
- *" $path "*) ;;
- *) newlib_search_path="$newlib_search_path $path";;
- esac
- fi
- path=""
- ;;
- *)
- path="-L$path"
- ;;
- esac
- ;;
- -l*)
- case $host in
- *-*-darwin*)
- # Again, we only want to link against shared libraries
- eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"`
- for tmp in $newlib_search_path ; do
- if test -f "$tmp/lib$tmp_libs.dylib" ; then
- eval depdepl="$tmp/lib$tmp_libs.dylib"
- break
- fi
- done
- path=""
- ;;
- *) continue ;;
- esac
- ;;
- *) continue ;;
- esac
- case " $deplibs " in
- *" $path "*) ;;
- *) deplibs="$path $deplibs" ;;
- esac
- case " $deplibs " in
- *" $depdepl "*) ;;
- *) deplibs="$depdepl $deplibs" ;;
- esac
- done
- fi # link_all_deplibs != no
- fi # linkmode = lib
- done # for deplib in $libs
- dependency_libs="$newdependency_libs"
- if test "$pass" = dlpreopen; then
- # Link the dlpreopened libraries before other libraries
- for deplib in $save_deplibs; do
- deplibs="$deplib $deplibs"
- done
- fi
- if test "$pass" != dlopen; then
- if test "$pass" != conv; then
- # Make sure lib_search_path contains only unique directories.
- lib_search_path=
- for dir in $newlib_search_path; do
- case "$lib_search_path " in
- *" $dir "*) ;;
- *) lib_search_path="$lib_search_path $dir" ;;
- esac
- done
- newlib_search_path=
- fi
-
- if test "$linkmode,$pass" != "prog,link"; then
- vars="deplibs"
- else
- vars="compile_deplibs finalize_deplibs"
- fi
- for var in $vars dependency_libs; do
- # Add libraries to $var in reverse order
- eval tmp_libs=\"\$$var\"
- new_libs=
- for deplib in $tmp_libs; do
- # FIXME: Pedantically, this is the right thing to do, so
- # that some nasty dependency loop isn't accidentally
- # broken:
- #new_libs="$deplib $new_libs"
- # Pragmatically, this seems to cause very few problems in
- # practice:
- case $deplib in
- -L*) new_libs="$deplib $new_libs" ;;
- -R*) ;;
- *)
- # And here is the reason: when a library appears more
- # than once as an explicit dependence of a library, or
- # is implicitly linked in more than once by the
- # compiler, it is considered special, and multiple
- # occurrences thereof are not removed. Compare this
- # with having the same library being listed as a
- # dependency of multiple other libraries: in this case,
- # we know (pedantically, we assume) the library does not
- # need to be listed more than once, so we keep only the
- # last copy. This is not always right, but it is rare
- # enough that we require users that really mean to play
- # such unportable linking tricks to link the library
- # using -Wl,-lname, so that libtool does not consider it
- # for duplicate removal.
- case " $specialdeplibs " in
- *" $deplib "*) new_libs="$deplib $new_libs" ;;
- *)
- case " $new_libs " in
- *" $deplib "*) ;;
- *) new_libs="$deplib $new_libs" ;;
- esac
- ;;
- esac
- ;;
- esac
- done
- tmp_libs=
- for deplib in $new_libs; do
- case $deplib in
- -L*)
- case " $tmp_libs " in
- *" $deplib "*) ;;
- *) tmp_libs="$tmp_libs $deplib" ;;
- esac
- ;;
- *) tmp_libs="$tmp_libs $deplib" ;;
- esac
- done
- eval $var=\"$tmp_libs\"
- done # for var
- fi
- # Last step: remove runtime libs from dependency_libs
- # (they stay in deplibs)
- tmp_libs=
- for i in $dependency_libs ; do
- case " $predeps $postdeps $compiler_lib_search_path " in
- *" $i "*)
- i=""
- ;;
- esac
- if test -n "$i" ; then
- tmp_libs="$tmp_libs $i"
- fi
- done
- dependency_libs=$tmp_libs
- done # for pass
- if test "$linkmode" = prog; then
- dlfiles="$newdlfiles"
- dlprefiles="$newdlprefiles"
- fi
-
- case $linkmode in
- oldlib)
- if test -n "$deplibs"; then
- $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2
- fi
-
- if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
- $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2
- fi
-
- if test -n "$rpath"; then
- $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2
- fi
-
- if test -n "$xrpath"; then
- $echo "$modename: warning: \`-R' is ignored for archives" 1>&2
- fi
-
- if test -n "$vinfo"; then
- $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2
- fi
-
- if test -n "$release"; then
- $echo "$modename: warning: \`-release' is ignored for archives" 1>&2
- fi
-
- if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
- $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2
- fi
-
- # Now set the variables for building old libraries.
- build_libtool_libs=no
- oldlibs="$output"
- objs="$objs$old_deplibs"
- ;;
-
- lib)
- # Make sure we only generate libraries of the form `libNAME.la'.
- case $outputname in
- lib*)
- name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
- eval shared_ext=\"$shrext_cmds\"
- eval libname=\"$libname_spec\"
- ;;
- *)
- if test "$module" = no; then
- $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2
- $echo "$help" 1>&2
- exit $EXIT_FAILURE
- fi
- if test "$need_lib_prefix" != no; then
- # Add the "lib" prefix for modules if required
- name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
- eval shared_ext=\"$shrext_cmds\"
- eval libname=\"$libname_spec\"
- else
- libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
- fi
- ;;
- esac
-
- if test -n "$objs"; then
- if test "$deplibs_check_method" != pass_all; then
- $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1
- exit $EXIT_FAILURE
- else
- $echo
- $echo "*** Warning: Linking the shared library $output against the non-libtool"
- $echo "*** objects $objs is not portable!"
- libobjs="$libobjs $objs"
- fi
- fi
-
- if test "$dlself" != no; then
- $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2
- fi
-
- set dummy $rpath
- if test "$#" -gt 2; then
- $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2
- fi
- install_libdir="$2"
-
- oldlibs=
- if test -z "$rpath"; then
- if test "$build_libtool_libs" = yes; then
- # Building a libtool convenience library.
- # Some compilers have problems with a `.al' extension so
- # convenience libraries should have the same extension an
- # archive normally would.
- oldlibs="$output_objdir/$libname.$libext $oldlibs"
- build_libtool_libs=convenience
- build_old_libs=yes
- fi
-
- if test -n "$vinfo"; then
- $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2
- fi
-
- if test -n "$release"; then
- $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2
- fi
- else
-
- # Parse the version information argument.
- save_ifs="$IFS"; IFS=':'
- set dummy $vinfo 0 0 0
- IFS="$save_ifs"
-
- if test -n "$8"; then
- $echo "$modename: too many parameters to \`-version-info'" 1>&2
- $echo "$help" 1>&2
- exit $EXIT_FAILURE
- fi
-
- # convert absolute version numbers to libtool ages
- # this retains compatibility with .la files and attempts
- # to make the code below a bit more comprehensible
-
- case $vinfo_number in
- yes)
- number_major="$2"
- number_minor="$3"
- number_revision="$4"
- #
- # There are really only two kinds -- those that
- # use the current revision as the major version
- # and those that subtract age and use age as
- # a minor version. But, then there is irix
- # which has an extra 1 added just for fun
- #
- case $version_type in
- darwin|linux|osf|windows)
- current=`expr $number_major + $number_minor`
- age="$number_minor"
- revision="$number_revision"
- ;;
- freebsd-aout|freebsd-elf|sunos)
- current="$number_major"
- revision="$number_minor"
- age="0"
- ;;
- irix|nonstopux)
- current=`expr $number_major + $number_minor - 1`
- age="$number_minor"
- revision="$number_minor"
- ;;
- *)
- $echo "$modename: unknown library version type \`$version_type'" 1>&2
- $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
- exit $EXIT_FAILURE
- ;;
- esac
- ;;
- no)
- current="$2"
- revision="$3"
- age="$4"
- ;;
- esac
-
- # Check that each of the things are valid numbers.
- case $current in
- 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
- *)
- $echo "$modename: CURRENT \`$current' must be a nonnegative integer" 1>&2
- $echo "$modename: \`$vinfo' is not valid version information" 1>&2
- exit $EXIT_FAILURE
- ;;
- esac
-
- case $revision in
- 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
- *)
- $echo "$modename: REVISION \`$revision' must be a nonnegative integer" 1>&2
- $echo "$modename: \`$vinfo' is not valid version information" 1>&2
- exit $EXIT_FAILURE
- ;;
- esac
-
- case $age in
- 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
- *)
- $echo "$modename: AGE \`$age' must be a nonnegative integer" 1>&2
- $echo "$modename: \`$vinfo' is not valid version information" 1>&2
- exit $EXIT_FAILURE
- ;;
- esac
-
- if test "$age" -gt "$current"; then
- $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2
- $echo "$modename: \`$vinfo' is not valid version information" 1>&2
- exit $EXIT_FAILURE
- fi
-
- # Calculate the version variables.
- major=
- versuffix=
- verstring=
- case $version_type in
- none) ;;
-
- darwin)
- # Like Linux, but with the current version available in
- # verstring for coding it into the library header
- major=.`expr $current - $age`
- versuffix="$major.$age.$revision"
- # Darwin ld doesn't like 0 for these options...
- minor_current=`expr $current + 1`
- verstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
- ;;
-
- freebsd-aout)
- major=".$current"
- versuffix=".$current.$revision";
- ;;
-
- freebsd-elf)
- major=".$current"
- versuffix=".$current";
- ;;
-
- irix | nonstopux)
- major=`expr $current - $age + 1`
-
- case $version_type in
- nonstopux) verstring_prefix=nonstopux ;;
- *) verstring_prefix=sgi ;;
- esac
- verstring="$verstring_prefix$major.$revision"
-
- # Add in all the interfaces that we are compatible with.
- loop=$revision
- while test "$loop" -ne 0; do
- iface=`expr $revision - $loop`
- loop=`expr $loop - 1`
- verstring="$verstring_prefix$major.$iface:$verstring"
- done
-
- # Before this point, $major must not contain `.'.
- major=.$major
- versuffix="$major.$revision"
- ;;
-
- linux)
- major=.`expr $current - $age`
- versuffix="$major.$age.$revision"
- ;;
-
- osf)
- major=.`expr $current - $age`
- versuffix=".$current.$age.$revision"
- verstring="$current.$age.$revision"
-
- # Add in all the interfaces that we are compatible with.
- loop=$age
- while test "$loop" -ne 0; do
- iface=`expr $current - $loop`
- loop=`expr $loop - 1`
- verstring="$verstring:${iface}.0"
- done
-
- # Make executables depend on our current version.
- verstring="$verstring:${current}.0"
- ;;
-
- sunos)
- major=".$current"
- versuffix=".$current.$revision"
- ;;
-
- windows)
- # Use '-' rather than '.', since we only want one
- # extension on DOS 8.3 filesystems.
- major=`expr $current - $age`
- versuffix="-$major"
- ;;
-
- *)
- $echo "$modename: unknown library version type \`$version_type'" 1>&2
- $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
- exit $EXIT_FAILURE
- ;;
- esac
-
- # Clear the version info if we defaulted, and they specified a release.
- if test -z "$vinfo" && test -n "$release"; then
- major=
- case $version_type in
- darwin)
- # we can't check for "0.0" in archive_cmds due to quoting
- # problems, so we reset it completely
- verstring=
- ;;
- *)
- verstring="0.0"
- ;;
- esac
- if test "$need_version" = no; then
- versuffix=
- else
- versuffix=".0.0"
- fi
- fi
-
- # Remove version info from name if versioning should be avoided
- if test "$avoid_version" = yes && test "$need_version" = no; then
- major=
- versuffix=
- verstring=""
- fi
-
- # Check to see if the archive will have undefined symbols.
- if test "$allow_undefined" = yes; then
- if test "$allow_undefined_flag" = unsupported; then
- $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2
- build_libtool_libs=no
- build_old_libs=yes
- fi
- else
- # Don't allow undefined symbols.
- allow_undefined_flag="$no_undefined_flag"
- fi
- fi
-
- if test "$mode" != relink; then
- # Remove our outputs, but don't remove object files since they
- # may have been created when compiling PIC objects.
- removelist=
- tempremovelist=`$echo "$output_objdir/*"`
- for p in $tempremovelist; do
- case $p in
- *.$objext)
- ;;
- $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
- if test "X$precious_files_regex" != "X"; then
- if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
- then
- continue
- fi
- fi
- removelist="$removelist $p"
- ;;
- *) ;;
- esac
- done
- if test -n "$removelist"; then
- $show "${rm}r $removelist"
- $run ${rm}r $removelist
- fi
- fi
-
- # Now set the variables for building old libraries.
- if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
- oldlibs="$oldlibs $output_objdir/$libname.$libext"
-
- # Transform .lo files to .o files.
- oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP`
- fi
-
- # Eliminate all temporary directories.
- for path in $notinst_path; do
- lib_search_path=`$echo "$lib_search_path " | ${SED} -e "s% $path % %g"`
- deplibs=`$echo "$deplibs " | ${SED} -e "s% -L$path % %g"`
- dependency_libs=`$echo "$dependency_libs " | ${SED} -e "s% -L$path % %g"`
- done
-
- if test -n "$xrpath"; then
- # If the user specified any rpath flags, then add them.
- temp_xrpath=
- for libdir in $xrpath; do
- temp_xrpath="$temp_xrpath -R$libdir"
- case "$finalize_rpath " in
- *" $libdir "*) ;;
- *) finalize_rpath="$finalize_rpath $libdir" ;;
- esac
- done
- if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
- dependency_libs="$temp_xrpath $dependency_libs"
- fi
- fi
-
- # Make sure dlfiles contains only unique files that won't be dlpreopened
- old_dlfiles="$dlfiles"
- dlfiles=
- for lib in $old_dlfiles; do
- case " $dlprefiles $dlfiles " in
- *" $lib "*) ;;
- *) dlfiles="$dlfiles $lib" ;;
- esac
- done
-
- # Make sure dlprefiles contains only unique files
- old_dlprefiles="$dlprefiles"
- dlprefiles=
- for lib in $old_dlprefiles; do
- case "$dlprefiles " in
- *" $lib "*) ;;
- *) dlprefiles="$dlprefiles $lib" ;;
- esac
- done
-
- if test "$build_libtool_libs" = yes; then
- if test -n "$rpath"; then
- case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*)
- # these systems don't actually have a c library (as such)!
- ;;
- *-*-rhapsody* | *-*-darwin1.[012])
- # Rhapsody C library is in the System framework
- deplibs="$deplibs -framework System"
- ;;
- *-*-netbsd*)
- # Don't link with libc until the a.out ld.so is fixed.
- ;;
- *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
- # Do not include libc due to us having libc/libc_r.
- ;;
- *-*-sco3.2v5* | *-*-sco5v6*)
- # Causes problems with __ctype
- ;;
- *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
- # Compiler inserts libc in the correct place for threads to work
- ;;
- *)
- # Add libc to deplibs on all other systems if necessary.
- if test "$build_libtool_need_lc" = "yes"; then
- deplibs="$deplibs -lc"
- fi
- ;;
- esac
- fi
-
- # Transform deplibs into only deplibs that can be linked in shared.
- name_save=$name
- libname_save=$libname
- release_save=$release
- versuffix_save=$versuffix
- major_save=$major
- # I'm not sure if I'm treating the release correctly. I think
- # release should show up in the -l (ie -lgmp5) so we don't want to
- # add it in twice. Is that correct?
- release=""
- versuffix=""
- major=""
- newdeplibs=
- droppeddeps=no
- case $deplibs_check_method in
- pass_all)
- # Don't check for shared/static. Everything works.
- # This might be a little naive. We might want to check
- # whether the library exists or not. But this is on
- # osf3 & osf4 and I'm not really sure... Just
- # implementing what was already the behavior.
- newdeplibs=$deplibs
- ;;
- test_compile)
- # This code stresses the "libraries are programs" paradigm to its
- # limits. Maybe even breaks it. We compile a program, linking it
- # against the deplibs as a proxy for the library. Then we can check
- # whether they linked in statically or dynamically with ldd.
- $rm conftest.c
- cat > conftest.c <<EOF
- int main() { return 0; }
-EOF
- $rm conftest
- $LTCC $LTCFLAGS -o conftest conftest.c $deplibs
- if test "$?" -eq 0 ; then
- ldd_output=`ldd conftest`
- for i in $deplibs; do
- name=`expr $i : '-l\(.*\)'`
- # If $name is empty we are operating on a -L argument.
- if test "$name" != "" && test "$name" -ne "0"; then
- if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
- case " $predeps $postdeps " in
- *" $i "*)
- newdeplibs="$newdeplibs $i"
- i=""
- ;;
- esac
- fi
- if test -n "$i" ; then
- libname=`eval \\$echo \"$libname_spec\"`
- deplib_matches=`eval \\$echo \"$library_names_spec\"`
- set dummy $deplib_matches
- deplib_match=$2
- if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
- newdeplibs="$newdeplibs $i"
- else
- droppeddeps=yes
- $echo
- $echo "*** Warning: dynamic linker does not accept needed library $i."
- $echo "*** I have the capability to make that library automatically link in when"
- $echo "*** you link to this library. But I can only do this if you have a"
- $echo "*** shared version of the library, which I believe you do not have"
- $echo "*** because a test_compile did reveal that the linker did not use it for"
- $echo "*** its dynamic dependency list that programs get resolved with at runtime."
- fi
- fi
- else
- newdeplibs="$newdeplibs $i"
- fi
- done
- else
- # Error occurred in the first compile. Let's try to salvage
- # the situation: Compile a separate program for each library.
- for i in $deplibs; do
- name=`expr $i : '-l\(.*\)'`
- # If $name is empty we are operating on a -L argument.
- if test "$name" != "" && test "$name" != "0"; then
- $rm conftest
- $LTCC $LTCFLAGS -o conftest conftest.c $i
- # Did it work?
- if test "$?" -eq 0 ; then
- ldd_output=`ldd conftest`
- if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
- case " $predeps $postdeps " in
- *" $i "*)
- newdeplibs="$newdeplibs $i"
- i=""
- ;;
- esac
- fi
- if test -n "$i" ; then
- libname=`eval \\$echo \"$libname_spec\"`
- deplib_matches=`eval \\$echo \"$library_names_spec\"`
- set dummy $deplib_matches
- deplib_match=$2
- if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
- newdeplibs="$newdeplibs $i"
- else
- droppeddeps=yes
- $echo
- $echo "*** Warning: dynamic linker does not accept needed library $i."
- $echo "*** I have the capability to make that library automatically link in when"
- $echo "*** you link to this library. But I can only do this if you have a"
- $echo "*** shared version of the library, which you do not appear to have"
- $echo "*** because a test_compile did reveal that the linker did not use this one"
- $echo "*** as a dynamic dependency that programs can get resolved with at runtime."
- fi
- fi
- else
- droppeddeps=yes
- $echo
- $echo "*** Warning! Library $i is needed by this library but I was not able to"
- $echo "*** make it link in! You will probably need to install it or some"
- $echo "*** library that it depends on before this library will be fully"
- $echo "*** functional. Installing it before continuing would be even better."
- fi
- else
- newdeplibs="$newdeplibs $i"
- fi
- done
- fi
- ;;
- file_magic*)
- set dummy $deplibs_check_method
- file_magic_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
- for a_deplib in $deplibs; do
- name=`expr $a_deplib : '-l\(.*\)'`
- # If $name is empty we are operating on a -L argument.
- if test "$name" != "" && test "$name" != "0"; then
- if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
- case " $predeps $postdeps " in
- *" $a_deplib "*)
- newdeplibs="$newdeplibs $a_deplib"
- a_deplib=""
- ;;
- esac
- fi
- if test -n "$a_deplib" ; then
- libname=`eval \\$echo \"$libname_spec\"`
- for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
- potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
- for potent_lib in $potential_libs; do
- # Follow soft links.
- if ls -lLd "$potent_lib" 2>/dev/null \
- | grep " -> " >/dev/null; then
- continue
- fi
- # The statement above tries to avoid entering an
- # endless loop below, in case of cyclic links.
- # We might still enter an endless loop, since a link
- # loop can be closed while we follow links,
- # but so what?
- potlib="$potent_lib"
- while test -h "$potlib" 2>/dev/null; do
- potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
- case $potliblink in
- [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
- *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";;
- esac
- done
- if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \
- | ${SED} 10q \
- | $EGREP "$file_magic_regex" > /dev/null; then
- newdeplibs="$newdeplibs $a_deplib"
- a_deplib=""
- break 2
- fi
- done
- done
- fi
- if test -n "$a_deplib" ; then
- droppeddeps=yes
- $echo
- $echo "*** Warning: linker path does not have real file for library $a_deplib."
- $echo "*** I have the capability to make that library automatically link in when"
- $echo "*** you link to this library. But I can only do this if you have a"
- $echo "*** shared version of the library, which you do not appear to have"
- $echo "*** because I did check the linker path looking for a file starting"
- if test -z "$potlib" ; then
- $echo "*** with $libname but no candidates were found. (...for file magic test)"
- else
- $echo "*** with $libname and none of the candidates passed a file format test"
- $echo "*** using a file magic. Last file checked: $potlib"
- fi
- fi
- else
- # Add a -L argument.
- newdeplibs="$newdeplibs $a_deplib"
- fi
- done # Gone through all deplibs.
- ;;
- match_pattern*)
- set dummy $deplibs_check_method
- match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
- for a_deplib in $deplibs; do
- name=`expr $a_deplib : '-l\(.*\)'`
- # If $name is empty we are operating on a -L argument.
- if test -n "$name" && test "$name" != "0"; then
- if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
- case " $predeps $postdeps " in
- *" $a_deplib "*)
- newdeplibs="$newdeplibs $a_deplib"
- a_deplib=""
- ;;
- esac
- fi
- if test -n "$a_deplib" ; then
- libname=`eval \\$echo \"$libname_spec\"`
- for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
- potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
- for potent_lib in $potential_libs; do
- potlib="$potent_lib" # see symlink-check above in file_magic test
- if eval $echo \"$potent_lib\" 2>/dev/null \
- | ${SED} 10q \
- | $EGREP "$match_pattern_regex" > /dev/null; then
- newdeplibs="$newdeplibs $a_deplib"
- a_deplib=""
- break 2
- fi
- done
- done
- fi
- if test -n "$a_deplib" ; then
- droppeddeps=yes
- $echo
- $echo "*** Warning: linker path does not have real file for library $a_deplib."
- $echo "*** I have the capability to make that library automatically link in when"
- $echo "*** you link to this library. But I can only do this if you have a"
- $echo "*** shared version of the library, which you do not appear to have"
- $echo "*** because I did check the linker path looking for a file starting"
- if test -z "$potlib" ; then
- $echo "*** with $libname but no candidates were found. (...for regex pattern test)"
- else
- $echo "*** with $libname and none of the candidates passed a file format test"
- $echo "*** using a regex pattern. Last file checked: $potlib"
- fi
- fi
- else
- # Add a -L argument.
- newdeplibs="$newdeplibs $a_deplib"
- fi
- done # Gone through all deplibs.
- ;;
- none | unknown | *)
- newdeplibs=""
- tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \
- -e 's/ -[LR][^ ]*//g'`
- if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
- for i in $predeps $postdeps ; do
- # can't use Xsed below, because $i might contain '/'
- tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"`
- done
- fi
- if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \
- | grep . >/dev/null; then
- $echo
- if test "X$deplibs_check_method" = "Xnone"; then
- $echo "*** Warning: inter-library dependencies are not supported in this platform."
- else
- $echo "*** Warning: inter-library dependencies are not known to be supported."
- fi
- $echo "*** All declared inter-library dependencies are being dropped."
- droppeddeps=yes
- fi
- ;;
- esac
- versuffix=$versuffix_save
- major=$major_save
- release=$release_save
- libname=$libname_save
- name=$name_save
-
- case $host in
- *-*-rhapsody* | *-*-darwin1.[012])
- # On Rhapsody replace the C library is the System framework
- newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'`
- ;;
- esac
-
- if test "$droppeddeps" = yes; then
- if test "$module" = yes; then
- $echo
- $echo "*** Warning: libtool could not satisfy all declared inter-library"
- $echo "*** dependencies of module $libname. Therefore, libtool will create"
- $echo "*** a static module, that should work as long as the dlopening"
- $echo "*** application is linked with the -dlopen flag."
- if test -z "$global_symbol_pipe"; then
- $echo
- $echo "*** However, this would only work if libtool was able to extract symbol"
- $echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
- $echo "*** not find such a program. So, this module is probably useless."
- $echo "*** \`nm' from GNU binutils and a full rebuild may help."
- fi
- if test "$build_old_libs" = no; then
- oldlibs="$output_objdir/$libname.$libext"
- build_libtool_libs=module
- build_old_libs=yes
- else
- build_libtool_libs=no
- fi
- else
- $echo "*** The inter-library dependencies that have been dropped here will be"
- $echo "*** automatically added whenever a program is linked with this library"
- $echo "*** or is declared to -dlopen it."
-
- if test "$allow_undefined" = no; then
- $echo
- $echo "*** Since this library must not contain undefined symbols,"
- $echo "*** because either the platform does not support them or"
- $echo "*** it was explicitly requested with -no-undefined,"
- $echo "*** libtool will only create a static version of it."
- if test "$build_old_libs" = no; then
- oldlibs="$output_objdir/$libname.$libext"
- build_libtool_libs=module
- build_old_libs=yes
- else
- build_libtool_libs=no
- fi
- fi
- fi
- fi
- # Done checking deplibs!
- deplibs=$newdeplibs
- fi
-
-
- # move library search paths that coincide with paths to not yet
- # installed libraries to the beginning of the library search list
- new_libs=
- for path in $notinst_path; do
- case " $new_libs " in
- *" -L$path/$objdir "*) ;;
- *)
- case " $deplibs " in
- *" -L$path/$objdir "*)
- new_libs="$new_libs -L$path/$objdir" ;;
- esac
- ;;
- esac
- done
- for deplib in $deplibs; do
- case $deplib in
- -L*)
- case " $new_libs " in
- *" $deplib "*) ;;
- *) new_libs="$new_libs $deplib" ;;
- esac
- ;;
- *) new_libs="$new_libs $deplib" ;;
- esac
- done
- deplibs="$new_libs"
-
-
- # All the library-specific variables (install_libdir is set above).
- library_names=
- old_library=
- dlname=
-
- # Test again, we may have decided not to build it any more
- if test "$build_libtool_libs" = yes; then
- if test "$hardcode_into_libs" = yes; then
- # Hardcode the library paths
- hardcode_libdirs=
- dep_rpath=
- rpath="$finalize_rpath"
- test "$mode" != relink && rpath="$compile_rpath$rpath"
- for libdir in $rpath; do
- if test -n "$hardcode_libdir_flag_spec"; then
- if test -n "$hardcode_libdir_separator"; then
- if test -z "$hardcode_libdirs"; then
- hardcode_libdirs="$libdir"
- else
- # Just accumulate the unique libdirs.
- case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
- *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
- ;;
- *)
- hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
- ;;
- esac
- fi
- else
- eval flag=\"$hardcode_libdir_flag_spec\"
- dep_rpath="$dep_rpath $flag"
- fi
- elif test -n "$runpath_var"; then
- case "$perm_rpath " in
- *" $libdir "*) ;;
- *) perm_rpath="$perm_rpath $libdir" ;;
- esac
- fi
- done
- # Substitute the hardcoded libdirs into the rpath.
- if test -n "$hardcode_libdir_separator" &&
- test -n "$hardcode_libdirs"; then
- libdir="$hardcode_libdirs"
- if test -n "$hardcode_libdir_flag_spec_ld"; then
- eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\"
- else
- eval dep_rpath=\"$hardcode_libdir_flag_spec\"
- fi
- fi
- if test -n "$runpath_var" && test -n "$perm_rpath"; then
- # We should set the runpath_var.
- rpath=
- for dir in $perm_rpath; do
- rpath="$rpath$dir:"
- done
- eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
- fi
- test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
- fi
-
- shlibpath="$finalize_shlibpath"
- test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
- if test -n "$shlibpath"; then
- eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
- fi
-
- # Get the real and link names of the library.
- eval shared_ext=\"$shrext_cmds\"
- eval library_names=\"$library_names_spec\"
- set dummy $library_names
- realname="$2"
- shift; shift
-
- if test -n "$soname_spec"; then
- eval soname=\"$soname_spec\"
- else
- soname="$realname"
- fi
- if test -z "$dlname"; then
- dlname=$soname
- fi
-
- lib="$output_objdir/$realname"
- linknames=
- for link
- do
- linknames="$linknames $link"
- done
-
- # Use standard objects if they are pic
- test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
-
- # Prepare the list of exported symbols
- if test -z "$export_symbols"; then
- if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
- $show "generating symbol list for \`$libname.la'"
- export_symbols="$output_objdir/$libname.exp"
- $run $rm $export_symbols
- cmds=$export_symbols_cmds
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- eval cmd=\"$cmd\"
- if len=`expr "X$cmd" : ".*"` &&
- test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
- $show "$cmd"
- $run eval "$cmd" || exit $?
- skipped_export=false
- else
- # The command line is too long to execute in one step.
- $show "using reloadable object file for export list..."
- skipped_export=:
- # Break out early, otherwise skipped_export may be
- # set to false by a later but shorter cmd.
- break
- fi
- done
- IFS="$save_ifs"
- if test -n "$export_symbols_regex"; then
- $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\""
- $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
- $show "$mv \"${export_symbols}T\" \"$export_symbols\""
- $run eval '$mv "${export_symbols}T" "$export_symbols"'
- fi
- fi
- fi
-
- if test -n "$export_symbols" && test -n "$include_expsyms"; then
- $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"'
- fi
-
- tmp_deplibs=
- for test_deplib in $deplibs; do
- case " $convenience " in
- *" $test_deplib "*) ;;
- *)
- tmp_deplibs="$tmp_deplibs $test_deplib"
- ;;
- esac
- done
- deplibs="$tmp_deplibs"
-
- if test -n "$convenience"; then
- if test -n "$whole_archive_flag_spec"; then
- save_libobjs=$libobjs
- eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
- else
- gentop="$output_objdir/${outputname}x"
- generated="$generated $gentop"
-
- func_extract_archives $gentop $convenience
- libobjs="$libobjs $func_extract_archives_result"
- fi
- fi
-
- if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
- eval flag=\"$thread_safe_flag_spec\"
- linker_flags="$linker_flags $flag"
- fi
-
- # Make a backup of the uninstalled library when relinking
- if test "$mode" = relink; then
- $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $?
- fi
-
- # Do each of the archive commands.
- if test "$module" = yes && test -n "$module_cmds" ; then
- if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
- eval test_cmds=\"$module_expsym_cmds\"
- cmds=$module_expsym_cmds
- else
- eval test_cmds=\"$module_cmds\"
- cmds=$module_cmds
- fi
- else
- if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
- eval test_cmds=\"$archive_expsym_cmds\"
- cmds=$archive_expsym_cmds
- else
- eval test_cmds=\"$archive_cmds\"
- cmds=$archive_cmds
- fi
- fi
-
- if test "X$skipped_export" != "X:" &&
- len=`expr "X$test_cmds" : ".*" 2>/dev/null` &&
- test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
- :
- else
- # The command line is too long to link in one step, link piecewise.
- $echo "creating reloadable object files..."
-
- # Save the value of $output and $libobjs because we want to
- # use them later. If we have whole_archive_flag_spec, we
- # want to use save_libobjs as it was before
- # whole_archive_flag_spec was expanded, because we can't
- # assume the linker understands whole_archive_flag_spec.
- # This may have to be revisited, in case too many
- # convenience libraries get linked in and end up exceeding
- # the spec.
- if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
- save_libobjs=$libobjs
- fi
- save_output=$output
- output_la=`$echo "X$output" | $Xsed -e "$basename"`
-
- # Clear the reloadable object creation command queue and
- # initialize k to one.
- test_cmds=
- concat_cmds=
- objlist=
- delfiles=
- last_robj=
- k=1
- output=$output_objdir/$output_la-${k}.$objext
- # Loop over the list of objects to be linked.
- for obj in $save_libobjs
- do
- eval test_cmds=\"$reload_cmds $objlist $last_robj\"
- if test "X$objlist" = X ||
- { len=`expr "X$test_cmds" : ".*" 2>/dev/null` &&
- test "$len" -le "$max_cmd_len"; }; then
- objlist="$objlist $obj"
- else
- # The command $test_cmds is almost too long, add a
- # command to the queue.
- if test "$k" -eq 1 ; then
- # The first file doesn't have a previous command to add.
- eval concat_cmds=\"$reload_cmds $objlist $last_robj\"
- else
- # All subsequent reloadable object files will link in
- # the last one created.
- eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\"
- fi
- last_robj=$output_objdir/$output_la-${k}.$objext
- k=`expr $k + 1`
- output=$output_objdir/$output_la-${k}.$objext
- objlist=$obj
- len=1
- fi
- done
- # Handle the remaining objects by creating one last
- # reloadable object file. All subsequent reloadable object
- # files will link in the last one created.
- test -z "$concat_cmds" || concat_cmds=$concat_cmds~
- eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\"
-
- if ${skipped_export-false}; then
- $show "generating symbol list for \`$libname.la'"
- export_symbols="$output_objdir/$libname.exp"
- $run $rm $export_symbols
- libobjs=$output
- # Append the command to create the export file.
- eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\"
- fi
-
- # Set up a command to remove the reloadable object files
- # after they are used.
- i=0
- while test "$i" -lt "$k"
- do
- i=`expr $i + 1`
- delfiles="$delfiles $output_objdir/$output_la-${i}.$objext"
- done
-
- $echo "creating a temporary reloadable object file: $output"
-
- # Loop through the commands generated above and execute them.
- save_ifs="$IFS"; IFS='~'
- for cmd in $concat_cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
-
- libobjs=$output
- # Restore the value of output.
- output=$save_output
-
- if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
- eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
- fi
- # Expand the library linking commands again to reset the
- # value of $libobjs for piecewise linking.
-
- # Do each of the archive commands.
- if test "$module" = yes && test -n "$module_cmds" ; then
- if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
- cmds=$module_expsym_cmds
- else
- cmds=$module_cmds
- fi
- else
- if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
- cmds=$archive_expsym_cmds
- else
- cmds=$archive_cmds
- fi
- fi
-
- # Append the command to remove the reloadable object files
- # to the just-reset $cmds.
- eval cmds=\"\$cmds~\$rm $delfiles\"
- fi
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- eval cmd=\"$cmd\"
- $show "$cmd"
- $run eval "$cmd" || {
- lt_exit=$?
-
- # Restore the uninstalled library and exit
- if test "$mode" = relink; then
- $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)'
- fi
-
- exit $lt_exit
- }
- done
- IFS="$save_ifs"
-
- # Restore the uninstalled library and exit
- if test "$mode" = relink; then
- $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $?
-
- if test -n "$convenience"; then
- if test -z "$whole_archive_flag_spec"; then
- $show "${rm}r $gentop"
- $run ${rm}r "$gentop"
- fi
- fi
-
- exit $EXIT_SUCCESS
- fi
-
- # Create links to the real library.
- for linkname in $linknames; do
- if test "$realname" != "$linkname"; then
- $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)"
- $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $?
- fi
- done
-
- # If -module or -export-dynamic was specified, set the dlname.
- if test "$module" = yes || test "$export_dynamic" = yes; then
- # On all known operating systems, these are identical.
- dlname="$soname"
- fi
- fi
- ;;
-
- obj)
- if test -n "$deplibs"; then
- $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2
- fi
-
- if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
- $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2
- fi
-
- if test -n "$rpath"; then
- $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2
- fi
-
- if test -n "$xrpath"; then
- $echo "$modename: warning: \`-R' is ignored for objects" 1>&2
- fi
-
- if test -n "$vinfo"; then
- $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2
- fi
-
- if test -n "$release"; then
- $echo "$modename: warning: \`-release' is ignored for objects" 1>&2
- fi
-
- case $output in
- *.lo)
- if test -n "$objs$old_deplibs"; then
- $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2
- exit $EXIT_FAILURE
- fi
- libobj="$output"
- obj=`$echo "X$output" | $Xsed -e "$lo2o"`
- ;;
- *)
- libobj=
- obj="$output"
- ;;
- esac
-
- # Delete the old objects.
- $run $rm $obj $libobj
-
- # Objects from convenience libraries. This assumes
- # single-version convenience libraries. Whenever we create
- # different ones for PIC/non-PIC, this we'll have to duplicate
- # the extraction.
- reload_conv_objs=
- gentop=
- # reload_cmds runs $LD directly, so let us get rid of
- # -Wl from whole_archive_flag_spec
- wl=
-
- if test -n "$convenience"; then
- if test -n "$whole_archive_flag_spec"; then
- eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\"
- else
- gentop="$output_objdir/${obj}x"
- generated="$generated $gentop"
-
- func_extract_archives $gentop $convenience
- reload_conv_objs="$reload_objs $func_extract_archives_result"
- fi
- fi
-
- # Create the old-style object.
- reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
-
- output="$obj"
- cmds=$reload_cmds
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- eval cmd=\"$cmd\"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
-
- # Exit if we aren't doing a library object file.
- if test -z "$libobj"; then
- if test -n "$gentop"; then
- $show "${rm}r $gentop"
- $run ${rm}r $gentop
- fi
-
- exit $EXIT_SUCCESS
- fi
-
- if test "$build_libtool_libs" != yes; then
- if test -n "$gentop"; then
- $show "${rm}r $gentop"
- $run ${rm}r $gentop
- fi
-
- # Create an invalid libtool object if no PIC, so that we don't
- # accidentally link it into a program.
- # $show "echo timestamp > $libobj"
- # $run eval "echo timestamp > $libobj" || exit $?
- exit $EXIT_SUCCESS
- fi
-
- if test -n "$pic_flag" || test "$pic_mode" != default; then
- # Only do commands if we really have different PIC objects.
- reload_objs="$libobjs $reload_conv_objs"
- output="$libobj"
- cmds=$reload_cmds
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- eval cmd=\"$cmd\"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- fi
-
- if test -n "$gentop"; then
- $show "${rm}r $gentop"
- $run ${rm}r $gentop
- fi
-
- exit $EXIT_SUCCESS
- ;;
-
- prog)
- case $host in
- *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;;
- esac
- if test -n "$vinfo"; then
- $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2
- fi
-
- if test -n "$release"; then
- $echo "$modename: warning: \`-release' is ignored for programs" 1>&2
- fi
-
- if test "$preload" = yes; then
- if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown &&
- test "$dlopen_self_static" = unknown; then
- $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support."
- fi
- fi
-
- case $host in
- *-*-rhapsody* | *-*-darwin1.[012])
- # On Rhapsody replace the C library is the System framework
- compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
- finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
- ;;
- esac
-
- case $host in
- *darwin*)
- # Don't allow lazy linking, it breaks C++ global constructors
- if test "$tagname" = CXX ; then
- compile_command="$compile_command ${wl}-bind_at_load"
- finalize_command="$finalize_command ${wl}-bind_at_load"
- fi
- ;;
- esac
-
-
- # move library search paths that coincide with paths to not yet
- # installed libraries to the beginning of the library search list
- new_libs=
- for path in $notinst_path; do
- case " $new_libs " in
- *" -L$path/$objdir "*) ;;
- *)
- case " $compile_deplibs " in
- *" -L$path/$objdir "*)
- new_libs="$new_libs -L$path/$objdir" ;;
- esac
- ;;
- esac
- done
- for deplib in $compile_deplibs; do
- case $deplib in
- -L*)
- case " $new_libs " in
- *" $deplib "*) ;;
- *) new_libs="$new_libs $deplib" ;;
- esac
- ;;
- *) new_libs="$new_libs $deplib" ;;
- esac
- done
- compile_deplibs="$new_libs"
-
-
- compile_command="$compile_command $compile_deplibs"
- finalize_command="$finalize_command $finalize_deplibs"
-
- if test -n "$rpath$xrpath"; then
- # If the user specified any rpath flags, then add them.
- for libdir in $rpath $xrpath; do
- # This is the magic to use -rpath.
- case "$finalize_rpath " in
- *" $libdir "*) ;;
- *) finalize_rpath="$finalize_rpath $libdir" ;;
- esac
- done
- fi
-
- # Now hardcode the library paths
- rpath=
- hardcode_libdirs=
- for libdir in $compile_rpath $finalize_rpath; do
- if test -n "$hardcode_libdir_flag_spec"; then
- if test -n "$hardcode_libdir_separator"; then
- if test -z "$hardcode_libdirs"; then
- hardcode_libdirs="$libdir"
- else
- # Just accumulate the unique libdirs.
- case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
- *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
- ;;
- *)
- hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
- ;;
- esac
- fi
- else
- eval flag=\"$hardcode_libdir_flag_spec\"
- rpath="$rpath $flag"
- fi
- elif test -n "$runpath_var"; then
- case "$perm_rpath " in
- *" $libdir "*) ;;
- *) perm_rpath="$perm_rpath $libdir" ;;
- esac
- fi
- case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
- testbindir=`$echo "X$libdir" | $Xsed -e 's*/lib$*/bin*'`
- case :$dllsearchpath: in
- *":$libdir:"*) ;;
- *) dllsearchpath="$dllsearchpath:$libdir";;
- esac
- case :$dllsearchpath: in
- *":$testbindir:"*) ;;
- *) dllsearchpath="$dllsearchpath:$testbindir";;
- esac
- ;;
- esac
- done
- # Substitute the hardcoded libdirs into the rpath.
- if test -n "$hardcode_libdir_separator" &&
- test -n "$hardcode_libdirs"; then
- libdir="$hardcode_libdirs"
- eval rpath=\" $hardcode_libdir_flag_spec\"
- fi
- compile_rpath="$rpath"
-
- rpath=
- hardcode_libdirs=
- for libdir in $finalize_rpath; do
- if test -n "$hardcode_libdir_flag_spec"; then
- if test -n "$hardcode_libdir_separator"; then
- if test -z "$hardcode_libdirs"; then
- hardcode_libdirs="$libdir"
- else
- # Just accumulate the unique libdirs.
- case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
- *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
- ;;
- *)
- hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
- ;;
- esac
- fi
- else
- eval flag=\"$hardcode_libdir_flag_spec\"
- rpath="$rpath $flag"
- fi
- elif test -n "$runpath_var"; then
- case "$finalize_perm_rpath " in
- *" $libdir "*) ;;
- *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
- esac
- fi
- done
- # Substitute the hardcoded libdirs into the rpath.
- if test -n "$hardcode_libdir_separator" &&
- test -n "$hardcode_libdirs"; then
- libdir="$hardcode_libdirs"
- eval rpath=\" $hardcode_libdir_flag_spec\"
- fi
- finalize_rpath="$rpath"
-
- if test -n "$libobjs" && test "$build_old_libs" = yes; then
- # Transform all the library objects into standard objects.
- compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
- finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
- fi
-
- dlsyms=
- if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
- if test -n "$NM" && test -n "$global_symbol_pipe"; then
- dlsyms="${outputname}S.c"
- else
- $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2
- fi
- fi
-
- if test -n "$dlsyms"; then
- case $dlsyms in
- "") ;;
- *.c)
- # Discover the nlist of each of the dlfiles.
- nlist="$output_objdir/${outputname}.nm"
-
- $show "$rm $nlist ${nlist}S ${nlist}T"
- $run $rm "$nlist" "${nlist}S" "${nlist}T"
-
- # Parse the name list into a source file.
- $show "creating $output_objdir/$dlsyms"
-
- test -z "$run" && $echo > "$output_objdir/$dlsyms" "\
-/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */
-/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */
-
-#ifdef __cplusplus
-extern \"C\" {
-#endif
-
-/* Prevent the only kind of declaration conflicts we can make. */
-#define lt_preloaded_symbols some_other_symbol
-
-/* External symbol declarations for the compiler. */\
-"
-
- if test "$dlself" = yes; then
- $show "generating symbol list for \`$output'"
-
- test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist"
-
- # Add our own program objects to the symbol list.
- progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
- for arg in $progfiles; do
- $show "extracting global C symbols from \`$arg'"
- $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
- done
-
- if test -n "$exclude_expsyms"; then
- $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
- $run eval '$mv "$nlist"T "$nlist"'
- fi
-
- if test -n "$export_symbols_regex"; then
- $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
- $run eval '$mv "$nlist"T "$nlist"'
- fi
-
- # Prepare the list of exported symbols
- if test -z "$export_symbols"; then
- export_symbols="$output_objdir/$outputname.exp"
- $run $rm $export_symbols
- $run eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
- case $host in
- *cygwin* | *mingw* )
- $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
- $run eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
- ;;
- esac
- else
- $run eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
- $run eval 'grep -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
- $run eval 'mv "$nlist"T "$nlist"'
- case $host in
- *cygwin* | *mingw* )
- $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
- $run eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
- ;;
- esac
- fi
- fi
-
- for arg in $dlprefiles; do
- $show "extracting global C symbols from \`$arg'"
- name=`$echo "$arg" | ${SED} -e 's%^.*/%%'`
- $run eval '$echo ": $name " >> "$nlist"'
- $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
- done
-
- if test -z "$run"; then
- # Make sure we have at least an empty file.
- test -f "$nlist" || : > "$nlist"
-
- if test -n "$exclude_expsyms"; then
- $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
- $mv "$nlist"T "$nlist"
- fi
-
- # Try sorting and uniquifying the output.
- if grep -v "^: " < "$nlist" |
- if sort -k 3 </dev/null >/dev/null 2>&1; then
- sort -k 3
- else
- sort +2
- fi |
- uniq > "$nlist"S; then
- :
- else
- grep -v "^: " < "$nlist" > "$nlist"S
- fi
-
- if test -f "$nlist"S; then
- eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"'
- else
- $echo '/* NONE */' >> "$output_objdir/$dlsyms"
- fi
-
- $echo >> "$output_objdir/$dlsyms" "\
-
-#undef lt_preloaded_symbols
-
-#if defined (__STDC__) && __STDC__
-# define lt_ptr void *
-#else
-# define lt_ptr char *
-# define const
-#endif
-
-/* The mapping between symbol names and symbols. */
-"
-
- case $host in
- *cygwin* | *mingw* )
- $echo >> "$output_objdir/$dlsyms" "\
-/* DATA imports from DLLs on WIN32 can't be const, because
- runtime relocations are performed -- see ld's documentation
- on pseudo-relocs */
-struct {
-"
- ;;
- * )
- $echo >> "$output_objdir/$dlsyms" "\
-const struct {
-"
- ;;
- esac
-
-
- $echo >> "$output_objdir/$dlsyms" "\
- const char *name;
- lt_ptr address;
-}
-lt_preloaded_symbols[] =
-{\
-"
-
- eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms"
-
- $echo >> "$output_objdir/$dlsyms" "\
- {0, (lt_ptr) 0}
-};
-
-/* This works around a problem in FreeBSD linker */
-#ifdef FREEBSD_WORKAROUND
-static const void *lt_preloaded_setup() {
- return lt_preloaded_symbols;
-}
-#endif
-
-#ifdef __cplusplus
-}
-#endif\
-"
- fi
-
- pic_flag_for_symtable=
- case $host in
- # compiling the symbol table file with pic_flag works around
- # a FreeBSD bug that causes programs to crash when -lm is
- # linked before any other PIC object. But we must not use
- # pic_flag when linking with -static. The problem exists in
- # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
- *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
- case "$compile_command " in
- *" -static "*) ;;
- *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";;
- esac;;
- *-*-hpux*)
- case "$compile_command " in
- *" -static "*) ;;
- *) pic_flag_for_symtable=" $pic_flag";;
- esac
- esac
-
- # Now compile the dynamic symbol file.
- $show "(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")"
- $run eval '(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $?
-
- # Clean up the generated files.
- $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T"
- $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T"
-
- # Transform the symbol file into the correct name.
- case $host in
- *cygwin* | *mingw* )
- if test -f "$output_objdir/${outputname}.def" ; then
- compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%"`
- finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%"`
- else
- compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
- finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
- fi
- ;;
- * )
- compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
- finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
- ;;
- esac
- ;;
- *)
- $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2
- exit $EXIT_FAILURE
- ;;
- esac
- else
- # We keep going just in case the user didn't refer to
- # lt_preloaded_symbols. The linker will fail if global_symbol_pipe
- # really was required.
-
- # Nullify the symbol file.
- compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"`
- finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"`
- fi
-
- if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
- # Replace the output file specification.
- compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
- link_command="$compile_command$compile_rpath"
-
- # We have no uninstalled library dependencies, so finalize right now.
- $show "$link_command"
- $run eval "$link_command"
- exit_status=$?
-
- # Delete the generated files.
- if test -n "$dlsyms"; then
- $show "$rm $output_objdir/${outputname}S.${objext}"
- $run $rm "$output_objdir/${outputname}S.${objext}"
- fi
-
- exit $exit_status
- fi
-
- if test -n "$shlibpath_var"; then
- # We should set the shlibpath_var
- rpath=
- for dir in $temp_rpath; do
- case $dir in
- [\\/]* | [A-Za-z]:[\\/]*)
- # Absolute path.
- rpath="$rpath$dir:"
- ;;
- *)
- # Relative path: add a thisdir entry.
- rpath="$rpath\$thisdir/$dir:"
- ;;
- esac
- done
- temp_rpath="$rpath"
- fi
-
- if test -n "$compile_shlibpath$finalize_shlibpath"; then
- compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
- fi
- if test -n "$finalize_shlibpath"; then
- finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
- fi
-
- compile_var=
- finalize_var=
- if test -n "$runpath_var"; then
- if test -n "$perm_rpath"; then
- # We should set the runpath_var.
- rpath=
- for dir in $perm_rpath; do
- rpath="$rpath$dir:"
- done
- compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
- fi
- if test -n "$finalize_perm_rpath"; then
- # We should set the runpath_var.
- rpath=
- for dir in $finalize_perm_rpath; do
- rpath="$rpath$dir:"
- done
- finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
- fi
- fi
-
- if test "$no_install" = yes; then
- # We don't need to create a wrapper script.
- link_command="$compile_var$compile_command$compile_rpath"
- # Replace the output file specification.
- link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
- # Delete the old output file.
- $run $rm $output
- # Link the executable and exit
- $show "$link_command"
- $run eval "$link_command" || exit $?
- exit $EXIT_SUCCESS
- fi
-
- if test "$hardcode_action" = relink; then
- # Fast installation is not supported
- link_command="$compile_var$compile_command$compile_rpath"
- relink_command="$finalize_var$finalize_command$finalize_rpath"
-
- $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2
- $echo "$modename: \`$output' will be relinked during installation" 1>&2
- else
- if test "$fast_install" != no; then
- link_command="$finalize_var$compile_command$finalize_rpath"
- if test "$fast_install" = yes; then
- relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'`
- else
- # fast_install is set to needless
- relink_command=
- fi
- else
- link_command="$compile_var$compile_command$compile_rpath"
- relink_command="$finalize_var$finalize_command$finalize_rpath"
- fi
- fi
-
- # Replace the output file specification.
- link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
-
- # Delete the old output files.
- $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname
-
- $show "$link_command"
- $run eval "$link_command" || exit $?
-
- # Now create the wrapper script.
- $show "creating $output"
-
- # Quote the relink command for shipping.
- if test -n "$relink_command"; then
- # Preserve any variables that may affect compiler behavior
- for var in $variables_saved_for_relink; do
- if eval test -z \"\${$var+set}\"; then
- relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
- elif eval var_value=\$$var; test -z "$var_value"; then
- relink_command="$var=; export $var; $relink_command"
- else
- var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
- relink_command="$var=\"$var_value\"; export $var; $relink_command"
- fi
- done
- relink_command="(cd `pwd`; $relink_command)"
- relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
- fi
-
- # Quote $echo for shipping.
- if test "X$echo" = "X$SHELL $progpath --fallback-echo"; then
- case $progpath in
- [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";;
- *) qecho="$SHELL `pwd`/$progpath --fallback-echo";;
- esac
- qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"`
- else
- qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"`
- fi
-
- # Only actually do things if our run command is non-null.
- if test -z "$run"; then
- # win32 will think the script is a binary if it has
- # a .exe suffix, so we strip it off here.
- case $output in
- *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;;
- esac
- # test for cygwin because mv fails w/o .exe extensions
- case $host in
- *cygwin*)
- exeext=.exe
- outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;;
- *) exeext= ;;
- esac
- case $host in
- *cygwin* | *mingw* )
- output_name=`basename $output`
- output_path=`dirname $output`
- cwrappersource="$output_path/$objdir/lt-$output_name.c"
- cwrapper="$output_path/$output_name.exe"
- $rm $cwrappersource $cwrapper
- trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
-
- cat > $cwrappersource <<EOF
-
-/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
- Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
-
- The $output program cannot be directly executed until all the libtool
- libraries that it depends on are installed.
-
- This wrapper executable should never be moved out of the build directory.
- If it is, it will not operate correctly.
-
- Currently, it simply execs the wrapper *script* "/bin/sh $output",
- but could eventually absorb all of the scripts functionality and
- exec $objdir/$outputname directly.
-*/
-EOF
- cat >> $cwrappersource<<"EOF"
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <stdarg.h>
-#include <assert.h>
-#include <string.h>
-#include <ctype.h>
-#include <sys/stat.h>
-
-#if defined(PATH_MAX)
-# define LT_PATHMAX PATH_MAX
-#elif defined(MAXPATHLEN)
-# define LT_PATHMAX MAXPATHLEN
-#else
-# define LT_PATHMAX 1024
-#endif
-
-#ifndef DIR_SEPARATOR
-# define DIR_SEPARATOR '/'
-# define PATH_SEPARATOR ':'
-#endif
-
-#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
- defined (__OS2__)
-# define HAVE_DOS_BASED_FILE_SYSTEM
-# ifndef DIR_SEPARATOR_2
-# define DIR_SEPARATOR_2 '\\'
-# endif
-# ifndef PATH_SEPARATOR_2
-# define PATH_SEPARATOR_2 ';'
-# endif
-#endif
-
-#ifndef DIR_SEPARATOR_2
-# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
-#else /* DIR_SEPARATOR_2 */
-# define IS_DIR_SEPARATOR(ch) \
- (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
-#endif /* DIR_SEPARATOR_2 */
-
-#ifndef PATH_SEPARATOR_2
-# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
-#else /* PATH_SEPARATOR_2 */
-# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
-#endif /* PATH_SEPARATOR_2 */
-
-#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type)))
-#define XFREE(stale) do { \
- if (stale) { free ((void *) stale); stale = 0; } \
-} while (0)
-
-/* -DDEBUG is fairly common in CFLAGS. */
-#undef DEBUG
-#if defined DEBUGWRAPPER
-# define DEBUG(format, ...) fprintf(stderr, format, __VA_ARGS__)
-#else
-# define DEBUG(format, ...)
-#endif
-
-const char *program_name = NULL;
-
-void * xmalloc (size_t num);
-char * xstrdup (const char *string);
-const char * base_name (const char *name);
-char * find_executable(const char *wrapper);
-int check_executable(const char *path);
-char * strendzap(char *str, const char *pat);
-void lt_fatal (const char *message, ...);
-
-int
-main (int argc, char *argv[])
-{
- char **newargz;
- int i;
-
- program_name = (char *) xstrdup (base_name (argv[0]));
- DEBUG("(main) argv[0] : %s\n",argv[0]);
- DEBUG("(main) program_name : %s\n",program_name);
- newargz = XMALLOC(char *, argc+2);
-EOF
-
- cat >> $cwrappersource <<EOF
- newargz[0] = (char *) xstrdup("$SHELL");
-EOF
-
- cat >> $cwrappersource <<"EOF"
- newargz[1] = find_executable(argv[0]);
- if (newargz[1] == NULL)
- lt_fatal("Couldn't find %s", argv[0]);
- DEBUG("(main) found exe at : %s\n",newargz[1]);
- /* we know the script has the same name, without the .exe */
- /* so make sure newargz[1] doesn't end in .exe */
- strendzap(newargz[1],".exe");
- for (i = 1; i < argc; i++)
- newargz[i+1] = xstrdup(argv[i]);
- newargz[argc+1] = NULL;
-
- for (i=0; i<argc+1; i++)
- {
- DEBUG("(main) newargz[%d] : %s\n",i,newargz[i]);
- ;
- }
-
-EOF
-
- case $host_os in
- mingw*)
- cat >> $cwrappersource <<EOF
- execv("$SHELL",(char const **)newargz);
-EOF
- ;;
- *)
- cat >> $cwrappersource <<EOF
- execv("$SHELL",newargz);
-EOF
- ;;
- esac
-
- cat >> $cwrappersource <<"EOF"
- return 127;
-}
-
-void *
-xmalloc (size_t num)
-{
- void * p = (void *) malloc (num);
- if (!p)
- lt_fatal ("Memory exhausted");
-
- return p;
-}
-
-char *
-xstrdup (const char *string)
-{
- return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL
-;
-}
-
-const char *
-base_name (const char *name)
-{
- const char *base;
-
-#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
- /* Skip over the disk name in MSDOS pathnames. */
- if (isalpha ((unsigned char)name[0]) && name[1] == ':')
- name += 2;
-#endif
-
- for (base = name; *name; name++)
- if (IS_DIR_SEPARATOR (*name))
- base = name + 1;
- return base;
-}
-
-int
-check_executable(const char * path)
-{
- struct stat st;
-
- DEBUG("(check_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!");
- if ((!path) || (!*path))
- return 0;
-
- if ((stat (path, &st) >= 0) &&
- (
- /* MinGW & native WIN32 do not support S_IXOTH or S_IXGRP */
-#if defined (S_IXOTH)
- ((st.st_mode & S_IXOTH) == S_IXOTH) ||
-#endif
-#if defined (S_IXGRP)
- ((st.st_mode & S_IXGRP) == S_IXGRP) ||
-#endif
- ((st.st_mode & S_IXUSR) == S_IXUSR))
- )
- return 1;
- else
- return 0;
-}
-
-/* Searches for the full path of the wrapper. Returns
- newly allocated full path name if found, NULL otherwise */
-char *
-find_executable (const char* wrapper)
-{
- int has_slash = 0;
- const char* p;
- const char* p_next;
- /* static buffer for getcwd */
- char tmp[LT_PATHMAX + 1];
- int tmp_len;
- char* concat_name;
-
- DEBUG("(find_executable) : %s\n", wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!");
-
- if ((wrapper == NULL) || (*wrapper == '\0'))
- return NULL;
-
- /* Absolute path? */
-#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
- if (isalpha ((unsigned char)wrapper[0]) && wrapper[1] == ':')
- {
- concat_name = xstrdup (wrapper);
- if (check_executable(concat_name))
- return concat_name;
- XFREE(concat_name);
- }
- else
- {
-#endif
- if (IS_DIR_SEPARATOR (wrapper[0]))
- {
- concat_name = xstrdup (wrapper);
- if (check_executable(concat_name))
- return concat_name;
- XFREE(concat_name);
- }
-#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
- }
-#endif
-
- for (p = wrapper; *p; p++)
- if (*p == '/')
- {
- has_slash = 1;
- break;
- }
- if (!has_slash)
- {
- /* no slashes; search PATH */
- const char* path = getenv ("PATH");
- if (path != NULL)
- {
- for (p = path; *p; p = p_next)
- {
- const char* q;
- size_t p_len;
- for (q = p; *q; q++)
- if (IS_PATH_SEPARATOR(*q))
- break;
- p_len = q - p;
- p_next = (*q == '\0' ? q : q + 1);
- if (p_len == 0)
- {
- /* empty path: current directory */
- if (getcwd (tmp, LT_PATHMAX) == NULL)
- lt_fatal ("getcwd failed");
- tmp_len = strlen(tmp);
- concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1);
- memcpy (concat_name, tmp, tmp_len);
- concat_name[tmp_len] = '/';
- strcpy (concat_name + tmp_len + 1, wrapper);
- }
- else
- {
- concat_name = XMALLOC(char, p_len + 1 + strlen(wrapper) + 1);
- memcpy (concat_name, p, p_len);
- concat_name[p_len] = '/';
- strcpy (concat_name + p_len + 1, wrapper);
- }
- if (check_executable(concat_name))
- return concat_name;
- XFREE(concat_name);
- }
- }
- /* not found in PATH; assume curdir */
- }
- /* Relative path | not found in path: prepend cwd */
- if (getcwd (tmp, LT_PATHMAX) == NULL)
- lt_fatal ("getcwd failed");
- tmp_len = strlen(tmp);
- concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1);
- memcpy (concat_name, tmp, tmp_len);
- concat_name[tmp_len] = '/';
- strcpy (concat_name + tmp_len + 1, wrapper);
-
- if (check_executable(concat_name))
- return concat_name;
- XFREE(concat_name);
- return NULL;
-}
-
-char *
-strendzap(char *str, const char *pat)
-{
- size_t len, patlen;
-
- assert(str != NULL);
- assert(pat != NULL);
-
- len = strlen(str);
- patlen = strlen(pat);
-
- if (patlen <= len)
- {
- str += len - patlen;
- if (strcmp(str, pat) == 0)
- *str = '\0';
- }
- return str;
-}
-
-static void
-lt_error_core (int exit_status, const char * mode,
- const char * message, va_list ap)
-{
- fprintf (stderr, "%s: %s: ", program_name, mode);
- vfprintf (stderr, message, ap);
- fprintf (stderr, ".\n");
-
- if (exit_status >= 0)
- exit (exit_status);
-}
-
-void
-lt_fatal (const char *message, ...)
-{
- va_list ap;
- va_start (ap, message);
- lt_error_core (EXIT_FAILURE, "FATAL", message, ap);
- va_end (ap);
-}
-EOF
- # we should really use a build-platform specific compiler
- # here, but OTOH, the wrappers (shell script and this C one)
- # are only useful if you want to execute the "real" binary.
- # Since the "real" binary is built for $host, then this
- # wrapper might as well be built for $host, too.
- $run $LTCC $LTCFLAGS -s -o $cwrapper $cwrappersource
- ;;
- esac
- $rm $output
- trap "$rm $output; exit $EXIT_FAILURE" 1 2 15
-
- $echo > $output "\
-#! $SHELL
-
-# $output - temporary wrapper script for $objdir/$outputname
-# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
-#
-# The $output program cannot be directly executed until all the libtool
-# libraries that it depends on are installed.
-#
-# This wrapper script should never be moved out of the build directory.
-# If it is, it will not operate correctly.
-
-# Sed substitution that helps us do robust quoting. It backslashifies
-# metacharacters that are still active within double-quoted strings.
-Xsed='${SED} -e 1s/^X//'
-sed_quote_subst='$sed_quote_subst'
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-relink_command=\"$relink_command\"
-
-# This environment variable determines our operation mode.
-if test \"\$libtool_install_magic\" = \"$magic\"; then
- # install mode needs the following variable:
- notinst_deplibs='$notinst_deplibs'
-else
- # When we are sourced in execute mode, \$file and \$echo are already set.
- if test \"\$libtool_execute_magic\" != \"$magic\"; then
- echo=\"$qecho\"
- file=\"\$0\"
- # Make sure echo works.
- if test \"X\$1\" = X--no-reexec; then
- # Discard the --no-reexec flag, and continue.
- shift
- elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then
- # Yippee, \$echo works!
- :
- else
- # Restart under the correct shell, and then maybe \$echo will work.
- exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"}
- fi
- fi\
-"
- $echo >> $output "\
-
- # Find the directory that this script lives in.
- thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\`
- test \"x\$thisdir\" = \"x\$file\" && thisdir=.
-
- # Follow symbolic links until we get to the real thisdir.
- file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\`
- while test -n \"\$file\"; do
- destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\`
-
- # If there was a directory component, then change thisdir.
- if test \"x\$destdir\" != \"x\$file\"; then
- case \"\$destdir\" in
- [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
- *) thisdir=\"\$thisdir/\$destdir\" ;;
- esac
- fi
-
- file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\`
- file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\`
- done
-
- # Try to get the absolute directory name.
- absdir=\`cd \"\$thisdir\" && pwd\`
- test -n \"\$absdir\" && thisdir=\"\$absdir\"
-"
-
- if test "$fast_install" = yes; then
- $echo >> $output "\
- program=lt-'$outputname'$exeext
- progdir=\"\$thisdir/$objdir\"
-
- if test ! -f \"\$progdir/\$program\" || \\
- { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
- test \"X\$file\" != \"X\$progdir/\$program\"; }; then
-
- file=\"\$\$-\$program\"
-
- if test ! -d \"\$progdir\"; then
- $mkdir \"\$progdir\"
- else
- $rm \"\$progdir/\$file\"
- fi"
-
- $echo >> $output "\
-
- # relink executable if necessary
- if test -n \"\$relink_command\"; then
- if relink_command_output=\`eval \$relink_command 2>&1\`; then :
- else
- $echo \"\$relink_command_output\" >&2
- $rm \"\$progdir/\$file\"
- exit $EXIT_FAILURE
- fi
- fi
-
- $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
- { $rm \"\$progdir/\$program\";
- $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; }
- $rm \"\$progdir/\$file\"
- fi"
- else
- $echo >> $output "\
- program='$outputname'
- progdir=\"\$thisdir/$objdir\"
-"
- fi
-
- $echo >> $output "\
-
- if test -f \"\$progdir/\$program\"; then"
-
- # Export our shlibpath_var if we have one.
- if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
- $echo >> $output "\
- # Add our own library path to $shlibpath_var
- $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
-
- # Some systems cannot cope with colon-terminated $shlibpath_var
- # The second colon is a workaround for a bug in BeOS R4 sed
- $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\`
-
- export $shlibpath_var
-"
- fi
-
- # fixup the dll searchpath if we need to.
- if test -n "$dllsearchpath"; then
- $echo >> $output "\
- # Add the dll search path components to the executable PATH
- PATH=$dllsearchpath:\$PATH
-"
- fi
-
- $echo >> $output "\
- if test \"\$libtool_execute_magic\" != \"$magic\"; then
- # Run the actual program with our arguments.
-"
- case $host in
- # Backslashes separate directories on plain windows
- *-*-mingw | *-*-os2*)
- $echo >> $output "\
- exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
-"
- ;;
-
- *)
- $echo >> $output "\
- exec \"\$progdir/\$program\" \${1+\"\$@\"}
-"
- ;;
- esac
- $echo >> $output "\
- \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\"
- exit $EXIT_FAILURE
- fi
- else
- # The program doesn't exist.
- \$echo \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
- \$echo \"This script is just a wrapper for \$program.\" 1>&2
- $echo \"See the $PACKAGE documentation for more information.\" 1>&2
- exit $EXIT_FAILURE
- fi
-fi\
-"
- chmod +x $output
- fi
- exit $EXIT_SUCCESS
- ;;
- esac
-
- # See if we need to build an old-fashioned archive.
- for oldlib in $oldlibs; do
-
- if test "$build_libtool_libs" = convenience; then
- oldobjs="$libobjs_save"
- addlibs="$convenience"
- build_libtool_libs=no
- else
- if test "$build_libtool_libs" = module; then
- oldobjs="$libobjs_save"
- build_libtool_libs=no
- else
- oldobjs="$old_deplibs $non_pic_objects"
- fi
- addlibs="$old_convenience"
- fi
-
- if test -n "$addlibs"; then
- gentop="$output_objdir/${outputname}x"
- generated="$generated $gentop"
-
- func_extract_archives $gentop $addlibs
- oldobjs="$oldobjs $func_extract_archives_result"
- fi
-
- # Do each command in the archive commands.
- if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
- cmds=$old_archive_from_new_cmds
- else
- # POSIX demands no paths to be encoded in archives. We have
- # to avoid creating archives with duplicate basenames if we
- # might have to extract them afterwards, e.g., when creating a
- # static archive out of a convenience library, or when linking
- # the entirety of a libtool archive into another (currently
- # not supported by libtool).
- if (for obj in $oldobjs
- do
- $echo "X$obj" | $Xsed -e 's%^.*/%%'
- done | sort | sort -uc >/dev/null 2>&1); then
- :
- else
- $echo "copying selected object files to avoid basename conflicts..."
-
- if test -z "$gentop"; then
- gentop="$output_objdir/${outputname}x"
- generated="$generated $gentop"
-
- $show "${rm}r $gentop"
- $run ${rm}r "$gentop"
- $show "$mkdir $gentop"
- $run $mkdir "$gentop"
- exit_status=$?
- if test "$exit_status" -ne 0 && test ! -d "$gentop"; then
- exit $exit_status
- fi
- fi
-
- save_oldobjs=$oldobjs
- oldobjs=
- counter=1
- for obj in $save_oldobjs
- do
- objbase=`$echo "X$obj" | $Xsed -e 's%^.*/%%'`
- case " $oldobjs " in
- " ") oldobjs=$obj ;;
- *[\ /]"$objbase "*)
- while :; do
- # Make sure we don't pick an alternate name that also
- # overlaps.
- newobj=lt$counter-$objbase
- counter=`expr $counter + 1`
- case " $oldobjs " in
- *[\ /]"$newobj "*) ;;
- *) if test ! -f "$gentop/$newobj"; then break; fi ;;
- esac
- done
- $show "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
- $run ln "$obj" "$gentop/$newobj" ||
- $run cp "$obj" "$gentop/$newobj"
- oldobjs="$oldobjs $gentop/$newobj"
- ;;
- *) oldobjs="$oldobjs $obj" ;;
- esac
- done
- fi
-
- eval cmds=\"$old_archive_cmds\"
-
- if len=`expr "X$cmds" : ".*"` &&
- test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
- cmds=$old_archive_cmds
- else
- # the command line is too long to link in one step, link in parts
- $echo "using piecewise archive linking..."
- save_RANLIB=$RANLIB
- RANLIB=:
- objlist=
- concat_cmds=
- save_oldobjs=$oldobjs
-
- # Is there a better way of finding the last object in the list?
- for obj in $save_oldobjs
- do
- last_oldobj=$obj
- done
- for obj in $save_oldobjs
- do
- oldobjs="$objlist $obj"
- objlist="$objlist $obj"
- eval test_cmds=\"$old_archive_cmds\"
- if len=`expr "X$test_cmds" : ".*" 2>/dev/null` &&
- test "$len" -le "$max_cmd_len"; then
- :
- else
- # the above command should be used before it gets too long
- oldobjs=$objlist
- if test "$obj" = "$last_oldobj" ; then
- RANLIB=$save_RANLIB
- fi
- test -z "$concat_cmds" || concat_cmds=$concat_cmds~
- eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
- objlist=
- fi
- done
- RANLIB=$save_RANLIB
- oldobjs=$objlist
- if test "X$oldobjs" = "X" ; then
- eval cmds=\"\$concat_cmds\"
- else
- eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
- fi
- fi
- fi
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- eval cmd=\"$cmd\"
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- done
-
- if test -n "$generated"; then
- $show "${rm}r$generated"
- $run ${rm}r$generated
- fi
-
- # Now create the libtool archive.
- case $output in
- *.la)
- old_library=
- test "$build_old_libs" = yes && old_library="$libname.$libext"
- $show "creating $output"
-
- # Preserve any variables that may affect compiler behavior
- for var in $variables_saved_for_relink; do
- if eval test -z \"\${$var+set}\"; then
- relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
- elif eval var_value=\$$var; test -z "$var_value"; then
- relink_command="$var=; export $var; $relink_command"
- else
- var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
- relink_command="$var=\"$var_value\"; export $var; $relink_command"
- fi
- done
- # Quote the link command for shipping.
- relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
- relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
- if test "$hardcode_automatic" = yes ; then
- relink_command=
- fi
-
-
- # Only create the output if not a dry run.
- if test -z "$run"; then
- for installed in no yes; do
- if test "$installed" = yes; then
- if test -z "$install_libdir"; then
- break
- fi
- output="$output_objdir/$outputname"i
- # Replace all uninstalled libtool libraries with the installed ones
- newdependency_libs=
- for deplib in $dependency_libs; do
- case $deplib in
- *.la)
- name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'`
- eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
- if test -z "$libdir"; then
- $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
- exit $EXIT_FAILURE
- fi
- newdependency_libs="$newdependency_libs $libdir/$name"
- ;;
- *) newdependency_libs="$newdependency_libs $deplib" ;;
- esac
- done
- dependency_libs="$newdependency_libs"
- newdlfiles=
- for lib in $dlfiles; do
- name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
- eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
- if test -z "$libdir"; then
- $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
- exit $EXIT_FAILURE
- fi
- newdlfiles="$newdlfiles $libdir/$name"
- done
- dlfiles="$newdlfiles"
- newdlprefiles=
- for lib in $dlprefiles; do
- name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
- eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
- if test -z "$libdir"; then
- $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
- exit $EXIT_FAILURE
- fi
- newdlprefiles="$newdlprefiles $libdir/$name"
- done
- dlprefiles="$newdlprefiles"
- else
- newdlfiles=
- for lib in $dlfiles; do
- case $lib in
- [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
- *) abs=`pwd`"/$lib" ;;
- esac
- newdlfiles="$newdlfiles $abs"
- done
- dlfiles="$newdlfiles"
- newdlprefiles=
- for lib in $dlprefiles; do
- case $lib in
- [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
- *) abs=`pwd`"/$lib" ;;
- esac
- newdlprefiles="$newdlprefiles $abs"
- done
- dlprefiles="$newdlprefiles"
- fi
- $rm $output
- # place dlname in correct position for cygwin
- tdlname=$dlname
- case $host,$output,$installed,$module,$dlname in
- *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;;
- esac
- $echo > $output "\
-# $outputname - a libtool library file
-# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
-#
-# Please DO NOT delete this file!
-# It is necessary for linking the library.
-
-# The name that we can dlopen(3).
-dlname='$tdlname'
-
-# Names of this library.
-library_names='$library_names'
-
-# The name of the static archive.
-old_library='$old_library'
-
-# Libraries that this one depends upon.
-dependency_libs='$dependency_libs'
-
-# Version information for $libname.
-current=$current
-age=$age
-revision=$revision
-
-# Is this an already installed library?
-installed=$installed
-
-# Should we warn about portability when linking against -modules?
-shouldnotlink=$module
-
-# Files to dlopen/dlpreopen
-dlopen='$dlfiles'
-dlpreopen='$dlprefiles'
-
-# Directory that this library needs to be installed in:
-libdir='$install_libdir'"
- if test "$installed" = no && test "$need_relink" = yes; then
- $echo >> $output "\
-relink_command=\"$relink_command\""
- fi
- done
- fi
-
- # Do a symbolic link so that the libtool archive can be found in
- # LD_LIBRARY_PATH before the program is installed.
- $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)"
- $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $?
- ;;
- esac
- exit $EXIT_SUCCESS
- ;;
-
- # libtool install mode
- install)
- modename="$modename: install"
-
- # There may be an optional sh(1) argument at the beginning of
- # install_prog (especially on Windows NT).
- if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
- # Allow the use of GNU shtool's install command.
- $echo "X$nonopt" | grep shtool > /dev/null; then
- # Aesthetically quote it.
- arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"`
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- arg="\"$arg\""
- ;;
- esac
- install_prog="$arg "
- arg="$1"
- shift
- else
- install_prog=
- arg=$nonopt
- fi
-
- # The real first argument should be the name of the installation program.
- # Aesthetically quote it.
- arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- arg="\"$arg\""
- ;;
- esac
- install_prog="$install_prog$arg"
-
- # We need to accept at least all the BSD install flags.
- dest=
- files=
- opts=
- prev=
- install_type=
- isdir=no
- stripme=
- for arg
- do
- if test -n "$dest"; then
- files="$files $dest"
- dest=$arg
- continue
- fi
-
- case $arg in
- -d) isdir=yes ;;
- -f)
- case " $install_prog " in
- *[\\\ /]cp\ *) ;;
- *) prev=$arg ;;
- esac
- ;;
- -g | -m | -o) prev=$arg ;;
- -s)
- stripme=" -s"
- continue
- ;;
- -*)
- ;;
- *)
- # If the previous option needed an argument, then skip it.
- if test -n "$prev"; then
- prev=
- else
- dest=$arg
- continue
- fi
- ;;
- esac
-
- # Aesthetically quote the argument.
- arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- arg="\"$arg\""
- ;;
- esac
- install_prog="$install_prog $arg"
- done
-
- if test -z "$install_prog"; then
- $echo "$modename: you must specify an install program" 1>&2
- $echo "$help" 1>&2
- exit $EXIT_FAILURE
- fi
-
- if test -n "$prev"; then
- $echo "$modename: the \`$prev' option requires an argument" 1>&2
- $echo "$help" 1>&2
- exit $EXIT_FAILURE
- fi
-
- if test -z "$files"; then
- if test -z "$dest"; then
- $echo "$modename: no file or destination specified" 1>&2
- else
- $echo "$modename: you must specify a destination" 1>&2
- fi
- $echo "$help" 1>&2
- exit $EXIT_FAILURE
- fi
-
- # Strip any trailing slash from the destination.
- dest=`$echo "X$dest" | $Xsed -e 's%/$%%'`
-
- # Check to see that the destination is a directory.
- test -d "$dest" && isdir=yes
- if test "$isdir" = yes; then
- destdir="$dest"
- destname=
- else
- destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'`
- test "X$destdir" = "X$dest" && destdir=.
- destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'`
-
- # Not a directory, so check to see that there is only one file specified.
- set dummy $files
- if test "$#" -gt 2; then
- $echo "$modename: \`$dest' is not a directory" 1>&2
- $echo "$help" 1>&2
- exit $EXIT_FAILURE
- fi
- fi
- case $destdir in
- [\\/]* | [A-Za-z]:[\\/]*) ;;
- *)
- for file in $files; do
- case $file in
- *.lo) ;;
- *)
- $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2
- $echo "$help" 1>&2
- exit $EXIT_FAILURE
- ;;
- esac
- done
- ;;
- esac
-
- # This variable tells wrapper scripts just to set variables rather
- # than running their programs.
- libtool_install_magic="$magic"
-
- staticlibs=
- future_libdirs=
- current_libdirs=
- for file in $files; do
-
- # Do each installation.
- case $file in
- *.$libext)
- # Do the static libraries later.
- staticlibs="$staticlibs $file"
- ;;
-
- *.la)
- # Check to see that this really is a libtool archive.
- if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
- else
- $echo "$modename: \`$file' is not a valid libtool archive" 1>&2
- $echo "$help" 1>&2
- exit $EXIT_FAILURE
- fi
-
- library_names=
- old_library=
- relink_command=
- # If there is no directory component, then add one.
- case $file in
- */* | *\\*) . $file ;;
- *) . ./$file ;;
- esac
-
- # Add the libdir to current_libdirs if it is the destination.
- if test "X$destdir" = "X$libdir"; then
- case "$current_libdirs " in
- *" $libdir "*) ;;
- *) current_libdirs="$current_libdirs $libdir" ;;
- esac
- else
- # Note the libdir as a future libdir.
- case "$future_libdirs " in
- *" $libdir "*) ;;
- *) future_libdirs="$future_libdirs $libdir" ;;
- esac
- fi
-
- dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/
- test "X$dir" = "X$file/" && dir=
- dir="$dir$objdir"
-
- if test -n "$relink_command"; then
- # Determine the prefix the user has applied to our future dir.
- inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"`
-
- # Don't allow the user to place us outside of our expected
- # location b/c this prevents finding dependent libraries that
- # are installed to the same prefix.
- # At present, this check doesn't affect windows .dll's that
- # are installed into $libdir/../bin (currently, that works fine)
- # but it's something to keep an eye on.
- if test "$inst_prefix_dir" = "$destdir"; then
- $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2
- exit $EXIT_FAILURE
- fi
-
- if test -n "$inst_prefix_dir"; then
- # Stick the inst_prefix_dir data into the link command.
- relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
- else
- relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
- fi
-
- $echo "$modename: warning: relinking \`$file'" 1>&2
- $show "$relink_command"
- if $run eval "$relink_command"; then :
- else
- $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
- exit $EXIT_FAILURE
- fi
- fi
-
- # See the names of the shared library.
- set dummy $library_names
- if test -n "$2"; then
- realname="$2"
- shift
- shift
-
- srcname="$realname"
- test -n "$relink_command" && srcname="$realname"T
-
- # Install the shared library and build the symlinks.
- $show "$install_prog $dir/$srcname $destdir/$realname"
- $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $?
- if test -n "$stripme" && test -n "$striplib"; then
- $show "$striplib $destdir/$realname"
- $run eval "$striplib $destdir/$realname" || exit $?
- fi
-
- if test "$#" -gt 0; then
- # Delete the old symlinks, and create new ones.
- # Try `ln -sf' first, because the `ln' binary might depend on
- # the symlink we replace! Solaris /bin/ln does not understand -f,
- # so we also need to try rm && ln -s.
- for linkname
- do
- if test "$linkname" != "$realname"; then
- $show "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })"
- $run eval "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })"
- fi
- done
- fi
-
- # Do each command in the postinstall commands.
- lib="$destdir/$realname"
- cmds=$postinstall_cmds
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- eval cmd=\"$cmd\"
- $show "$cmd"
- $run eval "$cmd" || {
- lt_exit=$?
-
- # Restore the uninstalled library and exit
- if test "$mode" = relink; then
- $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)'
- fi
-
- exit $lt_exit
- }
- done
- IFS="$save_ifs"
- fi
-
- # Install the pseudo-library for information purposes.
- name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
- instname="$dir/$name"i
- $show "$install_prog $instname $destdir/$name"
- $run eval "$install_prog $instname $destdir/$name" || exit $?
-
- # Maybe install the static library, too.
- test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
- ;;
-
- *.lo)
- # Install (i.e. copy) a libtool object.
-
- # Figure out destination file name, if it wasn't already specified.
- if test -n "$destname"; then
- destfile="$destdir/$destname"
- else
- destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
- destfile="$destdir/$destfile"
- fi
-
- # Deduce the name of the destination old-style object file.
- case $destfile in
- *.lo)
- staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"`
- ;;
- *.$objext)
- staticdest="$destfile"
- destfile=
- ;;
- *)
- $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2
- $echo "$help" 1>&2
- exit $EXIT_FAILURE
- ;;
- esac
-
- # Install the libtool object if requested.
- if test -n "$destfile"; then
- $show "$install_prog $file $destfile"
- $run eval "$install_prog $file $destfile" || exit $?
- fi
-
- # Install the old object if enabled.
- if test "$build_old_libs" = yes; then
- # Deduce the name of the old-style object file.
- staticobj=`$echo "X$file" | $Xsed -e "$lo2o"`
-
- $show "$install_prog $staticobj $staticdest"
- $run eval "$install_prog \$staticobj \$staticdest" || exit $?
- fi
- exit $EXIT_SUCCESS
- ;;
-
- *)
- # Figure out destination file name, if it wasn't already specified.
- if test -n "$destname"; then
- destfile="$destdir/$destname"
- else
- destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
- destfile="$destdir/$destfile"
- fi
-
- # If the file is missing, and there is a .exe on the end, strip it
- # because it is most likely a libtool script we actually want to
- # install
- stripped_ext=""
- case $file in
- *.exe)
- if test ! -f "$file"; then
- file=`$echo $file|${SED} 's,.exe$,,'`
- stripped_ext=".exe"
- fi
- ;;
- esac
-
- # Do a test to see if this is really a libtool program.
- case $host in
- *cygwin*|*mingw*)
- wrapper=`$echo $file | ${SED} -e 's,.exe$,,'`
- ;;
- *)
- wrapper=$file
- ;;
- esac
- if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then
- notinst_deplibs=
- relink_command=
-
- # Note that it is not necessary on cygwin/mingw to append a dot to
- # foo even if both foo and FILE.exe exist: automatic-append-.exe
- # behavior happens only for exec(3), not for open(2)! Also, sourcing
- # `FILE.' does not work on cygwin managed mounts.
- #
- # If there is no directory component, then add one.
- case $wrapper in
- */* | *\\*) . ${wrapper} ;;
- *) . ./${wrapper} ;;
- esac
-
- # Check the variables that should have been set.
- if test -z "$notinst_deplibs"; then
- $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2
- exit $EXIT_FAILURE
- fi
-
- finalize=yes
- for lib in $notinst_deplibs; do
- # Check to see that each library is installed.
- libdir=
- if test -f "$lib"; then
- # If there is no directory component, then add one.
- case $lib in
- */* | *\\*) . $lib ;;
- *) . ./$lib ;;
- esac
- fi
- libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test
- if test -n "$libdir" && test ! -f "$libfile"; then
- $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2
- finalize=no
- fi
- done
-
- relink_command=
- # Note that it is not necessary on cygwin/mingw to append a dot to
- # foo even if both foo and FILE.exe exist: automatic-append-.exe
- # behavior happens only for exec(3), not for open(2)! Also, sourcing
- # `FILE.' does not work on cygwin managed mounts.
- #
- # If there is no directory component, then add one.
- case $wrapper in
- */* | *\\*) . ${wrapper} ;;
- *) . ./${wrapper} ;;
- esac
-
- outputname=
- if test "$fast_install" = no && test -n "$relink_command"; then
- if test "$finalize" = yes && test -z "$run"; then
- tmpdir=`func_mktempdir`
- file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'`
- outputname="$tmpdir/$file"
- # Replace the output file specification.
- relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'`
-
- $show "$relink_command"
- if $run eval "$relink_command"; then :
- else
- $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
- ${rm}r "$tmpdir"
- continue
- fi
- file="$outputname"
- else
- $echo "$modename: warning: cannot relink \`$file'" 1>&2
- fi
- else
- # Install the binary that we compiled earlier.
- file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"`
- fi
- fi
-
- # remove .exe since cygwin /usr/bin/install will append another
- # one anyway
- case $install_prog,$host in
- */usr/bin/install*,*cygwin*)
- case $file:$destfile in
- *.exe:*.exe)
- # this is ok
- ;;
- *.exe:*)
- destfile=$destfile.exe
- ;;
- *:*.exe)
- destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'`
- ;;
- esac
- ;;
- esac
- $show "$install_prog$stripme $file $destfile"
- $run eval "$install_prog\$stripme \$file \$destfile" || exit $?
- test -n "$outputname" && ${rm}r "$tmpdir"
- ;;
- esac
- done
-
- for file in $staticlibs; do
- name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
-
- # Set up the ranlib parameters.
- oldlib="$destdir/$name"
-
- $show "$install_prog $file $oldlib"
- $run eval "$install_prog \$file \$oldlib" || exit $?
-
- if test -n "$stripme" && test -n "$old_striplib"; then
- $show "$old_striplib $oldlib"
- $run eval "$old_striplib $oldlib" || exit $?
- fi
-
- # Do each command in the postinstall commands.
- cmds=$old_postinstall_cmds
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- eval cmd=\"$cmd\"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- done
-
- if test -n "$future_libdirs"; then
- $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2
- fi
-
- if test -n "$current_libdirs"; then
- # Maybe just do a dry run.
- test -n "$run" && current_libdirs=" -n$current_libdirs"
- exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
- else
- exit $EXIT_SUCCESS
- fi
- ;;
-
- # libtool finish mode
- finish)
- modename="$modename: finish"
- libdirs="$nonopt"
- admincmds=
-
- if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
- for dir
- do
- libdirs="$libdirs $dir"
- done
-
- for libdir in $libdirs; do
- if test -n "$finish_cmds"; then
- # Do each command in the finish commands.
- cmds=$finish_cmds
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- eval cmd=\"$cmd\"
- $show "$cmd"
- $run eval "$cmd" || admincmds="$admincmds
- $cmd"
- done
- IFS="$save_ifs"
- fi
- if test -n "$finish_eval"; then
- # Do the single finish_eval.
- eval cmds=\"$finish_eval\"
- $run eval "$cmds" || admincmds="$admincmds
- $cmds"
- fi
- done
- fi
-
- # Exit here if they wanted silent mode.
- test "$show" = : && exit $EXIT_SUCCESS
-
- $echo "X----------------------------------------------------------------------" | $Xsed
- $echo "Libraries have been installed in:"
- for libdir in $libdirs; do
- $echo " $libdir"
- done
- $echo
- $echo "If you ever happen to want to link against installed libraries"
- $echo "in a given directory, LIBDIR, you must either use libtool, and"
- $echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
- $echo "flag during linking and do at least one of the following:"
- if test -n "$shlibpath_var"; then
- $echo " - add LIBDIR to the \`$shlibpath_var' environment variable"
- $echo " during execution"
- fi
- if test -n "$runpath_var"; then
- $echo " - add LIBDIR to the \`$runpath_var' environment variable"
- $echo " during linking"
- fi
- if test -n "$hardcode_libdir_flag_spec"; then
- libdir=LIBDIR
- eval flag=\"$hardcode_libdir_flag_spec\"
-
- $echo " - use the \`$flag' linker flag"
- fi
- if test -n "$admincmds"; then
- $echo " - have your system administrator run these commands:$admincmds"
- fi
- if test -f /etc/ld.so.conf; then
- $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
- fi
- $echo
- $echo "See any operating system documentation about shared libraries for"
- $echo "more information, such as the ld(1) and ld.so(8) manual pages."
- $echo "X----------------------------------------------------------------------" | $Xsed
- exit $EXIT_SUCCESS
- ;;
-
- # libtool execute mode
- execute)
- modename="$modename: execute"
-
- # The first argument is the command name.
- cmd="$nonopt"
- if test -z "$cmd"; then
- $echo "$modename: you must specify a COMMAND" 1>&2
- $echo "$help"
- exit $EXIT_FAILURE
- fi
-
- # Handle -dlopen flags immediately.
- for file in $execute_dlfiles; do
- if test ! -f "$file"; then
- $echo "$modename: \`$file' is not a file" 1>&2
- $echo "$help" 1>&2
- exit $EXIT_FAILURE
- fi
-
- dir=
- case $file in
- *.la)
- # Check to see that this really is a libtool archive.
- if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
- else
- $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
- $echo "$help" 1>&2
- exit $EXIT_FAILURE
- fi
-
- # Read the libtool library.
- dlname=
- library_names=
-
- # If there is no directory component, then add one.
- case $file in
- */* | *\\*) . $file ;;
- *) . ./$file ;;
- esac
-
- # Skip this library if it cannot be dlopened.
- if test -z "$dlname"; then
- # Warn if it was a shared library.
- test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'"
- continue
- fi
-
- dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
- test "X$dir" = "X$file" && dir=.
-
- if test -f "$dir/$objdir/$dlname"; then
- dir="$dir/$objdir"
- else
- $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2
- exit $EXIT_FAILURE
- fi
- ;;
-
- *.lo)
- # Just add the directory containing the .lo file.
- dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
- test "X$dir" = "X$file" && dir=.
- ;;
-
- *)
- $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2
- continue
- ;;
- esac
-
- # Get the absolute pathname.
- absdir=`cd "$dir" && pwd`
- test -n "$absdir" && dir="$absdir"
-
- # Now add the directory to shlibpath_var.
- if eval "test -z \"\$$shlibpath_var\""; then
- eval "$shlibpath_var=\"\$dir\""
- else
- eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
- fi
- done
-
- # This variable tells wrapper scripts just to set shlibpath_var
- # rather than running their programs.
- libtool_execute_magic="$magic"
-
- # Check if any of the arguments is a wrapper script.
- args=
- for file
- do
- case $file in
- -*) ;;
- *)
- # Do a test to see if this is really a libtool program.
- if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
- # If there is no directory component, then add one.
- case $file in
- */* | *\\*) . $file ;;
- *) . ./$file ;;
- esac
-
- # Transform arg to wrapped name.
- file="$progdir/$program"
- fi
- ;;
- esac
- # Quote arguments (to preserve shell metacharacters).
- file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"`
- args="$args \"$file\""
- done
-
- if test -z "$run"; then
- if test -n "$shlibpath_var"; then
- # Export the shlibpath_var.
- eval "export $shlibpath_var"
- fi
-
- # Restore saved environment variables
- if test "${save_LC_ALL+set}" = set; then
- LC_ALL="$save_LC_ALL"; export LC_ALL
- fi
- if test "${save_LANG+set}" = set; then
- LANG="$save_LANG"; export LANG
- fi
-
- # Now prepare to actually exec the command.
- exec_cmd="\$cmd$args"
- else
- # Display what would be done.
- if test -n "$shlibpath_var"; then
- eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\""
- $echo "export $shlibpath_var"
- fi
- $echo "$cmd$args"
- exit $EXIT_SUCCESS
- fi
- ;;
-
- # libtool clean and uninstall mode
- clean | uninstall)
- modename="$modename: $mode"
- rm="$nonopt"
- files=
- rmforce=
- exit_status=0
-
- # This variable tells wrapper scripts just to set variables rather
- # than running their programs.
- libtool_install_magic="$magic"
-
- for arg
- do
- case $arg in
- -f) rm="$rm $arg"; rmforce=yes ;;
- -*) rm="$rm $arg" ;;
- *) files="$files $arg" ;;
- esac
- done
-
- if test -z "$rm"; then
- $echo "$modename: you must specify an RM program" 1>&2
- $echo "$help" 1>&2
- exit $EXIT_FAILURE
- fi
-
- rmdirs=
-
- origobjdir="$objdir"
- for file in $files; do
- dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$dir" = "X$file"; then
- dir=.
- objdir="$origobjdir"
- else
- objdir="$dir/$origobjdir"
- fi
- name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
- test "$mode" = uninstall && objdir="$dir"
-
- # Remember objdir for removal later, being careful to avoid duplicates
- if test "$mode" = clean; then
- case " $rmdirs " in
- *" $objdir "*) ;;
- *) rmdirs="$rmdirs $objdir" ;;
- esac
- fi
-
- # Don't error if the file doesn't exist and rm -f was used.
- if (test -L "$file") >/dev/null 2>&1 \
- || (test -h "$file") >/dev/null 2>&1 \
- || test -f "$file"; then
- :
- elif test -d "$file"; then
- exit_status=1
- continue
- elif test "$rmforce" = yes; then
- continue
- fi
-
- rmfiles="$file"
-
- case $name in
- *.la)
- # Possibly a libtool archive, so verify it.
- if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
- . $dir/$name
-
- # Delete the libtool libraries and symlinks.
- for n in $library_names; do
- rmfiles="$rmfiles $objdir/$n"
- done
- test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library"
-
- case "$mode" in
- clean)
- case " $library_names " in
- # " " in the beginning catches empty $dlname
- *" $dlname "*) ;;
- *) rmfiles="$rmfiles $objdir/$dlname" ;;
- esac
- test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i"
- ;;
- uninstall)
- if test -n "$library_names"; then
- # Do each command in the postuninstall commands.
- cmds=$postuninstall_cmds
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- eval cmd=\"$cmd\"
- $show "$cmd"
- $run eval "$cmd"
- if test "$?" -ne 0 && test "$rmforce" != yes; then
- exit_status=1
- fi
- done
- IFS="$save_ifs"
- fi
-
- if test -n "$old_library"; then
- # Do each command in the old_postuninstall commands.
- cmds=$old_postuninstall_cmds
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- eval cmd=\"$cmd\"
- $show "$cmd"
- $run eval "$cmd"
- if test "$?" -ne 0 && test "$rmforce" != yes; then
- exit_status=1
- fi
- done
- IFS="$save_ifs"
- fi
- # FIXME: should reinstall the best remaining shared library.
- ;;
- esac
- fi
- ;;
-
- *.lo)
- # Possibly a libtool object, so verify it.
- if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
-
- # Read the .lo file
- . $dir/$name
-
- # Add PIC object to the list of files to remove.
- if test -n "$pic_object" \
- && test "$pic_object" != none; then
- rmfiles="$rmfiles $dir/$pic_object"
- fi
-
- # Add non-PIC object to the list of files to remove.
- if test -n "$non_pic_object" \
- && test "$non_pic_object" != none; then
- rmfiles="$rmfiles $dir/$non_pic_object"
- fi
- fi
- ;;
-
- *)
- if test "$mode" = clean ; then
- noexename=$name
- case $file in
- *.exe)
- file=`$echo $file|${SED} 's,.exe$,,'`
- noexename=`$echo $name|${SED} 's,.exe$,,'`
- # $file with .exe has already been added to rmfiles,
- # add $file without .exe
- rmfiles="$rmfiles $file"
- ;;
- esac
- # Do a test to see if this is a libtool program.
- if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
- relink_command=
- . $dir/$noexename
-
- # note $name still contains .exe if it was in $file originally
- # as does the version of $file that was added into $rmfiles
- rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}"
- if test "$fast_install" = yes && test -n "$relink_command"; then
- rmfiles="$rmfiles $objdir/lt-$name"
- fi
- if test "X$noexename" != "X$name" ; then
- rmfiles="$rmfiles $objdir/lt-${noexename}.c"
- fi
- fi
- fi
- ;;
- esac
- $show "$rm $rmfiles"
- $run $rm $rmfiles || exit_status=1
- done
- objdir="$origobjdir"
-
- # Try to remove the ${objdir}s in the directories where we deleted files
- for dir in $rmdirs; do
- if test -d "$dir"; then
- $show "rmdir $dir"
- $run rmdir $dir >/dev/null 2>&1
- fi
- done
-
- exit $exit_status
- ;;
-
- "")
- $echo "$modename: you must specify a MODE" 1>&2
- $echo "$generic_help" 1>&2
- exit $EXIT_FAILURE
- ;;
- esac
-
- if test -z "$exec_cmd"; then
- $echo "$modename: invalid operation mode \`$mode'" 1>&2
- $echo "$generic_help" 1>&2
- exit $EXIT_FAILURE
- fi
-fi # test -z "$show_help"
-
-if test -n "$exec_cmd"; then
- eval exec $exec_cmd
- exit $EXIT_FAILURE
-fi
-
-# We need to display help for each of the modes.
-case $mode in
-"") $echo \
-"Usage: $modename [OPTION]... [MODE-ARG]...
-
-Provide generalized library-building support services.
-
- --config show all configuration variables
- --debug enable verbose shell tracing
--n, --dry-run display commands without modifying any files
- --features display basic configuration information and exit
- --finish same as \`--mode=finish'
- --help display this help message and exit
- --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS]
- --quiet same as \`--silent'
- --silent don't print informational messages
- --tag=TAG use configuration variables from tag TAG
- --version print version information
-
-MODE must be one of the following:
-
- clean remove files from the build directory
- compile compile a source file into a libtool object
- execute automatically set library path, then run a program
- finish complete the installation of libtool libraries
- install install libraries or executables
- link create a library or an executable
- uninstall remove libraries from an installed directory
-
-MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for
-a more detailed description of MODE.
-
-Report bugs to <bug-libtool@gnu.org>."
- exit $EXIT_SUCCESS
- ;;
-
-clean)
- $echo \
-"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
-
-Remove files from the build directory.
-
-RM is the name of the program to use to delete files associated with each FILE
-(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
-to RM.
-
-If FILE is a libtool library, object or program, all the files associated
-with it are deleted. Otherwise, only FILE itself is deleted using RM."
- ;;
-
-compile)
- $echo \
-"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
-
-Compile a source file into a libtool library object.
-
-This mode accepts the following additional options:
-
- -o OUTPUT-FILE set the output file name to OUTPUT-FILE
- -prefer-pic try to building PIC objects only
- -prefer-non-pic try to building non-PIC objects only
- -static always build a \`.o' file suitable for static linking
-
-COMPILE-COMMAND is a command to be used in creating a \`standard' object file
-from the given SOURCEFILE.
-
-The output file name is determined by removing the directory component from
-SOURCEFILE, then substituting the C source code suffix \`.c' with the
-library object suffix, \`.lo'."
- ;;
-
-execute)
- $echo \
-"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]...
-
-Automatically set library path, then run a program.
-
-This mode accepts the following additional options:
-
- -dlopen FILE add the directory containing FILE to the library path
-
-This mode sets the library path environment variable according to \`-dlopen'
-flags.
-
-If any of the ARGS are libtool executable wrappers, then they are translated
-into their corresponding uninstalled binary, and any of their required library
-directories are added to the library path.
-
-Then, COMMAND is executed, with ARGS as arguments."
- ;;
-
-finish)
- $echo \
-"Usage: $modename [OPTION]... --mode=finish [LIBDIR]...
-
-Complete the installation of libtool libraries.
-
-Each LIBDIR is a directory that contains libtool libraries.
-
-The commands that this mode executes may require superuser privileges. Use
-the \`--dry-run' option if you just want to see what would be executed."
- ;;
-
-install)
- $echo \
-"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND...
-
-Install executables or libraries.
-
-INSTALL-COMMAND is the installation command. The first component should be
-either the \`install' or \`cp' program.
-
-The rest of the components are interpreted as arguments to that command (only
-BSD-compatible install options are recognized)."
- ;;
-
-link)
- $echo \
-"Usage: $modename [OPTION]... --mode=link LINK-COMMAND...
-
-Link object files or libraries together to form another library, or to
-create an executable program.
-
-LINK-COMMAND is a command using the C compiler that you would use to create
-a program from several object files.
-
-The following components of LINK-COMMAND are treated specially:
-
- -all-static do not do any dynamic linking at all
- -avoid-version do not add a version suffix if possible
- -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime
- -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols
- -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
- -export-symbols SYMFILE
- try to export only the symbols listed in SYMFILE
- -export-symbols-regex REGEX
- try to export only the symbols matching REGEX
- -LLIBDIR search LIBDIR for required installed libraries
- -lNAME OUTPUT-FILE requires the installed library libNAME
- -module build a library that can dlopened
- -no-fast-install disable the fast-install mode
- -no-install link a not-installable executable
- -no-undefined declare that a library does not refer to external symbols
- -o OUTPUT-FILE create OUTPUT-FILE from the specified objects
- -objectlist FILE Use a list of object files found in FILE to specify objects
- -precious-files-regex REGEX
- don't remove output files matching REGEX
- -release RELEASE specify package release information
- -rpath LIBDIR the created library will eventually be installed in LIBDIR
- -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries
- -static do not do any dynamic linking of libtool libraries
- -version-info CURRENT[:REVISION[:AGE]]
- specify library version info [each variable defaults to 0]
-
-All other options (arguments beginning with \`-') are ignored.
-
-Every other argument is treated as a filename. Files ending in \`.la' are
-treated as uninstalled libtool libraries, other files are standard or library
-object files.
-
-If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
-only library objects (\`.lo' files) may be specified, and \`-rpath' is
-required, except when creating a convenience library.
-
-If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
-using \`ar' and \`ranlib', or on Windows using \`lib'.
-
-If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
-is created, otherwise an executable program is created."
- ;;
-
-uninstall)
- $echo \
-"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
-
-Remove libraries from an installation directory.
-
-RM is the name of the program to use to delete files associated with each FILE
-(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
-to RM.
-
-If FILE is a libtool library, all the files associated with it are deleted.
-Otherwise, only FILE itself is deleted using RM."
- ;;
-
-*)
- $echo "$modename: invalid operation mode \`$mode'" 1>&2
- $echo "$help" 1>&2
- exit $EXIT_FAILURE
- ;;
-esac
-
-$echo
-$echo "Try \`$modename --help' for more information about other modes."
-
-exit $?
-
-# The TAGs below are defined such that we never get into a situation
-# in which we disable both kinds of libraries. Given conflicting
-# choices, we go for a static library, that is the most portable,
-# since we can't tell whether shared libraries were disabled because
-# the user asked for that or because the platform doesn't support
-# them. This is particularly important on AIX, because we don't
-# support having both static and shared libraries enabled at the same
-# time on that platform, so we default to a shared-only configuration.
-# If a disable-shared tag is given, we'll fallback to a static-only
-# configuration. But we'll never go from static-only to shared-only.
-
-# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
-disable_libs=shared
-# ### END LIBTOOL TAG CONFIG: disable-shared
-
-# ### BEGIN LIBTOOL TAG CONFIG: disable-static
-disable_libs=static
-# ### END LIBTOOL TAG CONFIG: disable-static
-
-# Local Variables:
-# mode:shell-script
-# sh-indentation:2
-# End:
diff --git a/cpp/configure.ac b/cpp/configure.ac
index 5e478c68cf..5603f70f60 100644
--- a/cpp/configure.ac
+++ b/cpp/configure.ac
@@ -7,8 +7,11 @@ dnl
dnl This program is distributed in the hope that it will be useful, but
dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+dnl
+dnl When updating the name/version number here, also update it in
+dnl src/qpid/Version.h
-AC_INIT([qpidc], [0.2], [qpid-dev@incubator.apache.org])
+AC_INIT([qpidc], [0.6], [dev@qpid.apache.org])
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([dist-bzip2 subdir-objects])
@@ -16,7 +19,6 @@ AM_INIT_AUTOMAKE([dist-bzip2 subdir-objects])
AC_PREREQ(2.59)
AC_CONFIG_HEADERS([src/config.h])
-AC_CONFIG_SRCDIR([qpidc.spec.in])
AC_PROG_CC_STDC
AM_PROG_CC_C_O
@@ -85,13 +87,14 @@ else
AC_CHECK_DECL([__SUNPRO_CC], [SUNCC=yes], [SUNCC=no])
# Set up for sun CC compiler
- if test x$SUNCC = xno; then
+ if test x$SUNCC = xyes; then
if test "${enableval}" = yes; then
WARNING_FLAGS=+w
fi
CXXFLAGS="$CXXFLAGS -library=stlport4 -mt"
LD="$CXX"
LDFLAGS="$LDFLAGS -library=stlport4 -mt"
+ AC_SUBST([SUNCC_RUNTIME_LIBS], [-lCrun])
fi
fi
@@ -109,9 +112,9 @@ gl_saved_libs=$LIBS
LIBS=$gl_saved_libs
# Set the argument to be used in "libtool -version-info ARG".
-QPID_CURRENT=1
+QPID_CURRENT=2
QPID_REVISION=0
-QPID_AGE=1
+QPID_AGE=0
LIBTOOL_VERSION_INFO_ARG=$QPID_CURRENT:$QPID_REVISION:$QPID_AGE
AC_SUBST(LIBTOOL_VERSION_INFO_ARG)
@@ -143,13 +146,98 @@ AM_CONDITIONAL([HAS_RPMLINT], [test -n "$RPMLINT"])
# It requires several external tools and files, which we check for here.
AC_CHECK_PROG([RUBY], [ruby], [ruby])
-test -n "$RUBY" && generate=yes
-test -z "$RUBY" && AC_MSG_ERROR([Missing ruby installation (try "yum install ruby").])
+
+# Swig binding generator is needed for the script (Ruby, Python, etc.) bindings.
+AC_PROG_SWIG(1.3.26)
+test ! -x "$SWIG" && SWIG=""
+AC_ARG_WITH([swig],
+ [AS_HELP_STRING([--with-swig], [Use swig to generate qmf bindings.])],
+ [case "$withval" in
+ yes) test -z "$SWIG" && AC_MSG_ERROR([swig not found.]) ;;
+ no) SWIG="" ;;
+ *) AC_MSG_ERROR([Bad value ${withval} for --with-swig.]) ;;
+ esac])
+AM_CONDITIONAL([HAVE_SWIG], [test -n "$SWIG"])
+
+# Ruby bindings: To build ruby wrappers, the ruby-devel files must be present.
+
+AC_PATH_PROGS(RUBY, [ruby1.8 ruby], [])
+AC_ARG_VAR(RUBY, [Ruby interpreter])
+if test -n "$RUBY" ; then
+ AC_ARG_VAR(RUBY_INC, [Directory where ruby.h can be found])
+ if test -z "$RUBY_INC" ; then
+ [RUBY_INC=`$RUBY -rrbconfig -e 'puts Config::CONFIG["rubyhdrdir"] || Config::CONFIG["archdir"]'`]
+ fi
+ AC_SUBST(RUBY_INC)
+
+ AC_ARG_VAR(RUBY_INC_ARCH, [Directory where ruby/config.h can be found (needed from Ruby 1.9)])
+ if test -z "$RUBY_INC_ARCH" ; then
+ [RUBY_INC_ARCH=`$RUBY -rrbconfig -e 'd = Config::CONFIG["rubyhdrdir"];if d != nil; print d + "/" + Config::CONFIG["arch"]; end'`]
+ dnl For earlier versions, just make it the same as RUBY_INC.
+ test x"$RUBY_INC_ARCH" != x || RUBY_INC_ARCH=$RUBY_INC
+ fi
+ AC_SUBST(RUBY_INC_ARCH)
+ AC_ARG_VAR(RUBY_LIB, [Directory to install ruby files into])
+ if test -z "$RUBY_LIB" ; then
+ dnl Kludge to install ruby files under $prefix
+ [RUBY_LIB=`$RUBY -rrbconfig -e 'puts Config::CONFIG["sitelibdir"].gsub("/usr", "${prefix}")'`]
+ fi
+ AC_SUBST(RUBY_LIB)
+
+ AC_ARG_VAR(RUBY_LIB_ARCH, [Directory to install ruby binary modules into])
+ if test -z "$RUBY_LIB_ARCH" ; then
+ dnl Kludge to install ruby files under $prefix
+ [RUBY_LIB_ARCH=`$RUBY -rrbconfig -e 'puts Config::CONFIG["sitearchdir"].gsub("/usr", "${prefix}")'`]
+ fi
+ AC_SUBST(RUBY_LIB_ARCH)
+
+ RUBY_LIBS=
+ case $host_os in
+ cygwin*) RUBY_LIBS=-lruby ;;
+ esac
+ AC_SUBST(RUBY_LIBS)
+
+ RUBY_DLEXT=`$RUBY -rrbconfig -e 'puts Config::CONFIG[["DLEXT"]]'`
+ AC_SUBST(RUBY_DLEXT)
+fi
+AM_CONDITIONAL([HAVE_RUBY_DEVEL], [test -f $RUBY_INC/ruby.h && test -n "$SWIG"])
+
+# Python bindings: To build python wrappers, the ruby-devel files must be present.
+
+AM_PATH_PYTHON()
+if test -n "$PYTHON" ; then
+ AC_MSG_CHECKING([$PYTHON include dir])
+ if $PYTHON -c 'import distutils.sysconfig' 2>/dev/null ; then
+ PYTHON_INC=`$PYTHON -c 'import os,distutils.sysconfig;print(distutils.sysconfig.get_python_inc().replace(os.sep,"/"))'`
+ AC_SUBST(PYTHON_INC)
+ else
+ if test yes = "$with_python" ; then
+ AC_MSG_ERROR([Couldn't import Python module distutils.sysconfig - you probably need to install a python-dev or python-devel package])
+ else
+ AC_MSG_WARN([Couldn't import Python module distutils.sysconfig - you probably don't have a python-dev or python-devel package installed])
+ fi
+ fi
+ AC_MSG_RESULT([$PYTHON_INC])
+ AC_MSG_CHECKING([for directory to install python bindings in])
+ if test -z "$PYTHON_LIB" ; then
+ PYTHON_LIB=`$PYTHON -c 'import os,distutils.sysconfig;print(distutils.sysconfig.get_python_lib(1).replace(os.sep,"/"))'`
+ fi
+ AC_MSG_RESULT([$PYTHON_LIB])
+ AC_ARG_VAR(PYTHON_LIB, [Directory to install python bindings in])
+
+ AC_MSG_CHECKING([for python libraries to link against])
+ PYTHON_LIBS=`$PYTHON -c 'import os,sys;print("-L"+os.path.join(sys.path[[3]],"config")+" -lpython"+sys.version[[:3]])'`
+ AC_SUBST(PYTHON_LIBS)
+ AC_MSG_RESULT([$PYTHON_LIBS])
+fi
+AM_CONDITIONAL([HAVE_PYTHON_DEVEL], [test -f $PYTHON_INC/Python.h && test -n "$SWIG"])
+
specdir=`pwd`/$srcdir/../specs
AMQP_FINAL_XML=$specdir/amqp.0-10-qpid-errata.xml
AC_SUBST(AMQP_FINAL_XML)
-AM_CONDITIONAL([GENERATE], [ls $AMQP_FINAL_XML >/dev/null])
+AM_CONDITIONAL([GENERATE], [test -f $AMQP_FINAL_XML])
+test -f $AMQP_FINAL_XML -a -z "$RUBY" && AC_MSG_ERROR([Missing ruby installation (try "yum install ruby").])
# URL and download URL for the package.
URL=http://rhm.et.redhat.com/qpidc
@@ -161,30 +249,51 @@ AC_SUBST(DOWNLOAD_URL)
AC_CHECK_HEADERS([boost/shared_ptr.hpp uuid/uuid.h],,
AC_MSG_ERROR([Missing required header files.]))
-# Check for optional CPG requirement.
+# Check for optional cluster requirements.
tmp_LIBS=$LIBS
-LDFLAGS="$LDFLAGS -L/usr/lib/openais -L/usr/lib64/openais"
+tmp_LDFLAGS=$LDFLAGS
+LDFLAGS="$LDFLAGS -L/usr/lib/openais -L/usr/lib64/openais -L/usr/lib/corosync -L/usr/lib64/corosync"
+AC_CHECK_LIB([cpg],[cpg_local_get],[have_libcpg=yes],)
+AC_CHECK_HEADERS([openais/cpg.h corosync/cpg.h],[have_cpg_h=yes],)
AC_ARG_WITH([cpg],
[AS_HELP_STRING([--with-cpg], [Build with CPG support for clustering.])],
[case "${withval}" in
- yes) # yes - enable
- with_CPG=yes
- AC_CHECK_LIB([cpg],[cpg_local_get],,[AC_MSG_ERROR([libcpg not found, install openais])])
- AC_CHECK_HEADERS([openais/cpg.h],,[AC_MSG_ERROR([openais/cpg.h not found, install openais-devel])])
+ yes) # yes - require dependencies
+ test x$have_libcpg = xyes || AC_MSG_ERROR([libcpg not found, install openais-devel or corosync-devel])
+ test x$have_cpg_h = xyes || AC_MSG_ERROR([cpg.h not found, install openais-devel or corosync-devel])
+ with_cpg=yes
;;
- no) with_CPG=no ;;
+ no) with_cpg=no ;;
*) AC_MSG_ERROR([Bad value ${withval} for --with-cpg option]) ;;
esac],
- [ # not specified - default no
- with_CPG=no
+ [ # not specified - use if present
+ test x$have_libcpg = xyes -a x$have_cpg_h = xyes && with_cpg=yes
]
)
-LIBS=$tmp_LIBS
+AM_CONDITIONAL([HAVE_LIBCPG], [test x$with_cpg = xyes])
+# Clean up unnceccassary flags if we don't use clustering
+AS_IF([test ! x$with_cpg = xyes], [LDFLAGS=$tmp_LDFLAGS])
+
+AC_CHECK_LIB([cman],[cman_is_quorate],have_libcman=yes,)
+AC_CHECK_HEADERS([libcman.h],have_libcman_h=yes,)
+AC_ARG_WITH([libcman],
+ [AS_HELP_STRING([--with-libcman], [Integration with libcman quorum service.])],
+ [case "${withval}" in
+ yes) # yes - require dependencies
+ test x$have_libcman = xyes || AC_MSG_ERROR([libcman not found, install cman-devel or cmanlib-devel])
+ test x$have_libcman_h = xyes || AC_MSG_ERROR([libcman.h not found, install cman-devel or cmanlib-devel])
+ with_libcman=yes
+ ;;
+ no) with_libcman=no ;;
+ *) AC_MSG_ERROR([Bad value ${withval} for --with-libcman option]) ;;
+ esac],
+ [ # not specified - use if present and we're using with_cpg
+ test x$have_libcman = xyes -a x$have_libcman_h = xyes -a x$with_cpg = xyes && with_libcman=yes
+ ]
+)
+AM_CONDITIONAL([HAVE_LIBCMAN], [test x$with_libcman = xyes])
-AM_CONDITIONAL([CPG], [test x$with_CPG = xyes])
-if test x$with_CPG = xyes; then
- CPPFLAGS+=" -DCPG"
-fi
+LIBS=$tmp_LIBS
# Setup --with-sasl/--without-sasl as arguments to configure
AC_ARG_WITH([sasl],
@@ -244,7 +353,7 @@ if test $use_xml != no; then
AC_CHECK_LIB([xerces-c], [_init], , [use_xml=no])
AC_CHECK_HEADER([xercesc/framework/MemBufInputSource.hpp], , [use_xml=no])
AC_CHECK_HEADER([xqilla/xqilla-simple.hpp], , [use_xml=no])
- AC_CHECK_LIB([xqilla], [canonicalCombiningClassTable], , [use_xml=no])
+ AC_CHECK_LIB([xqilla], [_init], , [use_xml=no])
# Remove from LIBS, we will link it explicitly in make files.
LIBS=$tmp_LIBS
@@ -279,7 +388,7 @@ AC_ARG_WITH([rdma],
;;
esac],
[
- with_RDMA=no
+ with_RDMA=yes
AC_CHECK_LIB([ibverbs],[ibv_create_qp],,[with_RDMA=no])
AC_CHECK_LIB([rdmacm],[rdma_create_id],,[with_RDMA=no])
AC_CHECK_HEADERS([infiniband/verbs.h],,[with_RDMA=no])
@@ -290,6 +399,44 @@ AC_ARG_WITH([rdma],
LIBS=$tmp_LIBS
AM_CONDITIONAL([RDMA], [test x$with_RDMA = xyes])
+# Setup --with-ssl/--without-ssl as arguments to configure
+SSL_CFLAGS=""
+SSL_LDFLAGS=""
+AC_ARG_WITH([ssl],
+ [AS_HELP_STRING([--with-ssl], [Build with support for SSL])],
+ [case ${withval} in
+ yes)
+ with_SSL=yes
+ AC_PATH_PROG([NSPR_CONFIG], [nspr-config])
+ AS_IF([test x$NSPR_CONFIG = x], [AC_MSG_ERROR([libnspr not found])], [])
+ AC_PATH_PROG([NSS_CONFIG], [nss-config])
+ AS_IF([test x$NSS_CONFIG = x], [AC_MSG_ERROR([libnss not found])], [])
+ SSL_CFLAGS="`$NSPR_CONFIG --cflags` `$NSS_CONFIG --cflags`"
+ SSL_LDFLAGS="`$NSPR_CONFIG --libs` `$NSS_CONFIG --libs`"
+ ;;
+ no)
+ with_SSL=no
+ ;;
+ *)
+ AC_MSG_ERROR([Bad value for --with-ssl: ${withval}])
+ ;;
+ esac],
+ [
+ with_SSL=yes
+ AC_PATH_PROG([NSPR_CONFIG], [nspr-config])
+ AS_IF([test x$NSPR_CONFIG = x], [with_SSL=no],
+ [AC_PATH_PROG([NSS_CONFIG], [nss-config])
+ AS_IF([test x$NSS_CONFIG = x], [with_SSL=no],
+ [SSL_CFLAGS="`$NSPR_CONFIG --cflags` `$NSS_CONFIG --cflags`"
+ SSL_LDFLAGS="`$NSPR_CONFIG --libs` `$NSS_CONFIG --libs`"])])
+ ]
+)
+# Remove from LIBS, we will link it explicitly in make files.
+AM_CONDITIONAL([SSL], [test x$with_SSL = xyes])
+AC_SUBST([SSL_CFLAGS])
+AC_SUBST([SSL_LDFLAGS])
+
+
poller=no
AC_ARG_WITH([poller],
[AS_HELP_STRING([--with-poller], [The low level poller implementation: poll/solaris-ecf/epoll])],
@@ -319,20 +466,65 @@ if test $poller = xno; then
AC_MSG_ERROR([Polling mechanism not implemented for $host])
fi
+#Guess host architecture, to choose platform-dependent objects
+case "$host" in
+ *sun-solaris*)
+ arch=solaris
+ ;;
+esac
+AM_CONDITIONAL([SUNOS], [test x$arch = xsolaris])
+
+# Check for some syslog capabilities not present in all systems
+AC_TRY_COMPILE([#include <sys/syslog.h>],
+ [int v = LOG_AUTHPRIV;],
+ [AC_DEFINE([HAVE_LOG_AUTHPRIV], [1], [Set to 1 whether LOG_AUTHPRIV is supported.])],)
+
+AC_TRY_COMPILE([#include <sys/syslog.h>],
+ [int v = LOG_FTP;],
+ [AC_DEFINE([HAVE_LOG_FTP], [1], [Set to 1 whether LOG_FTP is supported.])],)
+
+#Check if we need to include libacl to provide acl API
+gl_saved_libs=$LIBS
+ AC_SEARCH_LIBS(acl, [acl],
+ [test "$ac_cv_search_acl" = "none required" ||
+ LIB_ACL=$ac_cv_search_acl])
+ AC_SUBST([LIB_ACL])
+LIBS=$gl_saved_libs
+
+SOCKLIBS=""
+AC_CHECK_LIB([socket],[socket],[SOCKET_LIB="-lsocket"],[SOCKET_LIB=""],[])
+AC_CHECK_LIB([nsl],[getipnodebyname],[NSL_LIB="-lnsl"],[NSL_LIB=""],[])
+SOCKLIBS="$SOCKET_LIB $NSL_LIB"
+AC_SUBST([SOCKLIBS])
+
+AM_PATH_PYTHON()
+
+# Used by env scripts to find libraries in cmake or autoconf builds.
+builddir_lib_suffix="/.libs"
+AC_SUBST([builddir_lib_suffix])
+
# Files to generate
AC_CONFIG_FILES([
- qpidc.spec
Makefile
examples/Makefile
examples/direct/Makefile
examples/fanout/Makefile
examples/pub-sub/Makefile
examples/request-response/Makefile
+ examples/failover/Makefile
examples/xml-exchange/Makefile
+ examples/qmf-console/Makefile
+ examples/tradedemo/Makefile
+ examples/messaging/Makefile
+ bindings/qmf/Makefile
+ bindings/qmf/ruby/Makefile
+ bindings/qmf/python/Makefile
+ bindings/qmf/tests/Makefile
managementgen/Makefile
etc/Makefile
src/Makefile
src/tests/Makefile
+ src/tests/test_env.sh
docs/man/Makefile
docs/api/Makefile
docs/api/user.doxygen
diff --git a/cpp/docs/api/CMakeLists.txt b/cpp/docs/api/CMakeLists.txt
new file mode 100644
index 0000000000..1f9573b98a
--- /dev/null
+++ b/cpp/docs/api/CMakeLists.txt
@@ -0,0 +1,40 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+if (GEN_DOXYGEN)
+ # The user.doxygen.in file was originally written for a
+ # configure-generated situation so makes use of configure names that
+ # need to be set from the CMake equivalents.
+ set (top_builddir ${CMAKE_BINARY_DIR})
+ set (top_srcdir ${CMAKE_SOURCE_DIR})
+ set (srcdir ${CMAKE_CURRENT_SOURCE_DIR})
+ configure_file (${CMAKE_CURRENT_SOURCE_DIR}/user.doxygen.in
+ ${CMAKE_CURRENT_BINARY_DIR}/user.doxygen)
+ add_custom_target (user-api-docs COMMAND ${DOXYGEN_EXECUTABLE} user.doxygen)
+
+ # HTML files are generated to ./html - put those in the install.
+ install (DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html/
+ DESTINATION ${QPID_INSTALL_HTMLDIR}
+ COMPONENT ${QPID_COMPONENT_CLIENT_INCLUDE})
+ if (CPACK_GENERATOR STREQUAL "NSIS")
+ set (CPACK_NSIS_MENU_LINKS
+ "${QPID_INSTALL_HTMLDIR}/index.html" "Qpid C++ API Documentation"
+ "https://issues.apache.org/jira/browse/QPID" "Report Qpid Problem")
+ endif (CPACK_GENERATOR STREQUAL "NSIS")
+endif (GEN_DOXYGEN)
diff --git a/cpp/docs/api/Makefile.am b/cpp/docs/api/Makefile.am
index 3b9c7648e0..f65b4ad8b2 100644
--- a/cpp/docs/api/Makefile.am
+++ b/cpp/docs/api/Makefile.am
@@ -1,18 +1,35 @@
#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
# Run doxygen to generate HTML doc.
# Generate dependency files so its rebuilt only when needed.
#
-# TODO aconway 2007-04-12: html should have a
-# dependency on source/header files.
-
if HAVE_DOXYGEN
-EXTRA_DIST = html user.doxygen developer.doxygen html.timestamp
+EXTRA_DIST = html user.doxygen developer.doxygen html.timestamp CMakeLists.txt
html: html.timestamp
+
html.timestamp:
+ test $(srcdir) = . || cp $(srcdir)/header.html $(srcdir)/footer.html .
doxygen user.doxygen
touch $@
diff --git a/cpp/docs/api/developer.doxygen.in b/cpp/docs/api/developer.doxygen.in
index b267b12b90..96d67c027f 100644
--- a/cpp/docs/api/developer.doxygen.in
+++ b/cpp/docs/api/developer.doxygen.in
@@ -105,7 +105,7 @@ ALWAYS_DETAILED_SEC = NO
# members were ordinary class members. Constructors, destructors and assignment
# operators of the base classes will not be shown.
-INLINE_INHERITED_MEMB = NO
+INLINE_INHERITED_MEMB = YES # was NO - jwr
# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
# path before files name in the file list and in the header files. If set
@@ -120,7 +120,7 @@ FULL_PATH_NAMES = YES
# If left blank the directory from which doxygen is run is used as the
# path to strip.
-STRIP_FROM_PATH =
+STRIP_FROM_PATH = ../../src ../../
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
# the path mentioned in the documentation of a class, which tells
@@ -151,14 +151,14 @@ JAVADOC_AUTOBRIEF = YES
# The new default is to treat a multi-line C++ comment block as a detailed
# description. Set this tag to YES if you prefer the old behaviour instead.
-MULTILINE_CPP_IS_BRIEF = NO
+MULTILINE_CPP_IS_BRIEF = YES # was NO
# If the DETAILS_AT_TOP tag is set to YES then Doxygen
# will output the detailed description near the top, like JavaDoc.
# If set to NO, the detailed description appears after the member
# documentation.
-DETAILS_AT_TOP = NO
+DETAILS_AT_TOP = YES # was NO
# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
# member inherits the documentation from any documented member that it
@@ -238,7 +238,7 @@ EXTRACT_ALL = YES
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
# will be included in the documentation.
-EXTRACT_PRIVATE = YES
+EXTRACT_PRIVATE = NO # was YES
# If the EXTRACT_STATIC tag is set to YES all static members of a file
# will be included in the documentation.
@@ -249,14 +249,14 @@ EXTRACT_STATIC = YES
# defined locally in source files will be included in the documentation.
# If set to NO only classes defined in header files are included.
-EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_CLASSES = NO # was YES
# This flag is only useful for Objective-C code. When set to YES local
# methods, which are defined in the implementation section but not in
# the interface are included in the documentation.
# If set to NO (the default) only methods in the interface are included.
-EXTRACT_LOCAL_METHODS = YES
+EXTRACT_LOCAL_METHODS = NO # was YES
# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
# undocumented members of documented classes, files or namespaces.
@@ -411,7 +411,7 @@ FILE_VERSION_FILTER =
# The QUIET tag can be used to turn on/off the messages that are generated
# by doxygen. Possible values are YES and NO. If left blank NO is used.
-QUIET = YES
+QUIET = NO
# The WARNINGS tag can be used to turn on/off the warning messages that are
# generated by doxygen. Possible values are YES and NO. If left blank
@@ -464,7 +464,7 @@ WARN_LOGFILE = doxygen.log
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = @abs_top_srcdir@/src
+INPUT = @top_srcdir@/include @top_srcdir@/src @top_builddir@/include @top_builddir@/src
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
@@ -975,13 +975,13 @@ ENABLE_PREPROCESSING = YES
# compilation will be performed. Macro expansion can be done in a controlled
# way by setting EXPAND_ONLY_PREDEF to YES.
-MACRO_EXPANSION = NO
+MACRO_EXPANSION = YES
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
# then the macro expansion is limited to the macros specified with the
# PREDEFINED and EXPAND_AS_DEFINED tags.
-EXPAND_ONLY_PREDEF = NO
+EXPAND_ONLY_PREDEF = YES
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
# in the INCLUDE_PATH (see below) will be search if a #include is found.
@@ -1009,7 +1009,7 @@ INCLUDE_FILE_PATTERNS =
# undefined via #undef or recursively expanded use the := operator
# instead of the = operator.
-PREDEFINED =
+PREDEFINED = QPID_CLIENT_EXTERN= QPID_COMMON_EXTERN= QPID_CONSOLE_EXTERN= QPID_BROKER_EXTERN=
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
diff --git a/cpp/docs/api/doxygen.css b/cpp/docs/api/doxygen.css
new file mode 100644
index 0000000000..3292768f0c
--- /dev/null
+++ b/cpp/docs/api/doxygen.css
@@ -0,0 +1,494 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
+ font-family: Geneva, Arial, Helvetica, sans-serif;
+}
+BODY,TD {
+ font-size: 90%;
+}
+H1 {
+ text-align: center;
+ font-size: 160%;
+}
+H2 {
+ font-size: 120%;
+}
+H3 {
+ font-size: 100%;
+}
+CAPTION {
+ font-weight: bold
+}
+DIV.qindex {
+ width: 100%;
+ background-color: #e8eef2;
+ border: 1px solid #84b0c7;
+ text-align: center;
+ margin: 2px;
+ padding: 2px;
+ line-height: 140%;
+}
+DIV.navpath {
+ width: 100%;
+ background-color: #e8eef2;
+ border: 1px solid #84b0c7;
+ text-align: center;
+ margin: 2px;
+ padding: 2px;
+ line-height: 140%;
+}
+DIV.navtab {
+ background-color: #e8eef2;
+ border: 1px solid #84b0c7;
+ text-align: center;
+ margin: 2px;
+ margin-right: 15px;
+ padding: 2px;
+}
+TD.navtab {
+ font-size: 70%;
+}
+A.qindex {
+ text-decoration: none;
+ font-weight: bold;
+ color: #1A419D;
+}
+A.qindex:visited {
+ text-decoration: none;
+ font-weight: bold;
+ color: #1A419D
+}
+A.qindex:hover {
+ text-decoration: none;
+ background-color: #ddddff;
+}
+A.qindexHL {
+ text-decoration: none;
+ font-weight: bold;
+ background-color: #6666cc;
+ color: #ffffff;
+ border: 1px double #9295C2;
+}
+A.qindexHL:hover {
+ text-decoration: none;
+ background-color: #6666cc;
+ color: #ffffff;
+}
+A.qindexHL:visited {
+ text-decoration: none;
+ background-color: #6666cc;
+ color: #ffffff
+}
+A.el {
+ text-decoration: none;
+ font-weight: bold
+}
+A.elRef {
+ font-weight: bold
+}
+A.code:link {
+ text-decoration: none;
+ font-weight: normal;
+ color: #0000FF
+}
+A.code:visited {
+ text-decoration: none;
+ font-weight: normal;
+ color: #0000FF
+}
+A.codeRef:link {
+ font-weight: normal;
+ color: #0000FF
+}
+A.codeRef:visited {
+ font-weight: normal;
+ color: #0000FF
+}
+A:hover {
+ text-decoration: none;
+ background-color: #f2f2ff
+}
+DL.el {
+ margin-left: -1cm
+}
+.fragment {
+ font-family: monospace, fixed;
+ font-size: 95%;
+}
+PRE.fragment {
+ border: 1px solid #CCCCCC;
+ background-color: #f5f5f5;
+ margin-top: 4px;
+ margin-bottom: 4px;
+ margin-left: 2px;
+ margin-right: 8px;
+ padding-left: 6px;
+ padding-right: 6px;
+ padding-top: 4px;
+ padding-bottom: 4px;
+}
+DIV.ah {
+ background-color: black;
+ font-weight: bold;
+ color: #ffffff;
+ margin-bottom: 3px;
+ margin-top: 3px
+}
+
+DIV.groupHeader {
+ margin-left: 16px;
+ margin-top: 12px;
+ margin-bottom: 6px;
+ font-weight: bold;
+}
+DIV.groupText {
+ margin-left: 16px;
+ font-style: italic;
+ font-size: 90%
+}
+BODY {
+ background: white;
+ color: black;
+ margin-right: 20px;
+ margin-left: 20px;
+}
+TD.indexkey {
+ background-color: #e8eef2;
+ font-weight: bold;
+ padding-right : 10px;
+ padding-top : 2px;
+ padding-left : 10px;
+ padding-bottom : 2px;
+ margin-left : 0px;
+ margin-right : 0px;
+ margin-top : 2px;
+ margin-bottom : 2px;
+ border: 1px solid #CCCCCC;
+}
+TD.indexvalue {
+ background-color: #e8eef2;
+ font-style: italic;
+ padding-right : 10px;
+ padding-top : 2px;
+ padding-left : 10px;
+ padding-bottom : 2px;
+ margin-left : 0px;
+ margin-right : 0px;
+ margin-top : 2px;
+ margin-bottom : 2px;
+ border: 1px solid #CCCCCC;
+}
+TR.memlist {
+ background-color: #f0f0f0;
+}
+P.formulaDsp {
+ text-align: center;
+}
+IMG.formulaDsp {
+}
+IMG.formulaInl {
+ vertical-align: middle;
+}
+SPAN.keyword { color: #008000 }
+SPAN.keywordtype { color: #604020 }
+SPAN.keywordflow { color: #e08000 }
+SPAN.comment { color: #800000 }
+SPAN.preprocessor { color: #806020 }
+SPAN.stringliteral { color: #002080 }
+SPAN.charliteral { color: #008080 }
+SPAN.vhdldigit { color: #ff00ff }
+SPAN.vhdlchar { color: #000000 }
+SPAN.vhdlkeyword { color: #700070 }
+SPAN.vhdllogic { color: #ff0000 }
+
+.mdescLeft {
+ padding: 0px 8px 4px 8px;
+ font-size: 80%;
+ font-style: italic;
+ background-color: #FAFAFA;
+ border-top: 1px none #E0E0E0;
+ border-right: 1px none #E0E0E0;
+ border-bottom: 1px none #E0E0E0;
+ border-left: 1px none #E0E0E0;
+ margin: 0px;
+}
+.mdescRight {
+ padding: 0px 8px 4px 8px;
+ font-size: 80%;
+ font-style: italic;
+ background-color: #FAFAFA;
+ border-top: 1px none #E0E0E0;
+ border-right: 1px none #E0E0E0;
+ border-bottom: 1px none #E0E0E0;
+ border-left: 1px none #E0E0E0;
+ margin: 0px;
+}
+.memItemLeft {
+ padding: 1px 0px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: solid;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.memItemRight {
+ padding: 1px 8px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: solid;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.memTemplItemLeft {
+ padding: 1px 0px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: none;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.memTemplItemRight {
+ padding: 1px 8px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: none;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.memTemplParams {
+ padding: 1px 0px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: solid;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ color: #606060;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.search {
+ color: #003399;
+ font-weight: bold;
+}
+FORM.search {
+ margin-bottom: 0px;
+ margin-top: 0px;
+}
+INPUT.search {
+ font-size: 75%;
+ color: #000080;
+ font-weight: normal;
+ background-color: #e8eef2;
+}
+TD.tiny {
+ font-size: 75%;
+}
+a {
+ color: #1A41A8;
+}
+a:visited {
+ color: #2A3798;
+}
+.dirtab {
+ padding: 4px;
+ border-collapse: collapse;
+ border: 1px solid #84b0c7;
+}
+TH.dirtab {
+ background: #e8eef2;
+ font-weight: bold;
+}
+HR {
+ height: 1px;
+ border: none;
+ border-top: 1px solid black;
+}
+
+/* Style for detailed member documentation */
+.memtemplate {
+ font-size: 80%;
+ color: #606060;
+ font-weight: normal;
+ margin-left: 3px;
+}
+.memnav {
+ background-color: #e8eef2;
+ border: 1px solid #84b0c7;
+ text-align: center;
+ margin: 2px;
+ margin-right: 15px;
+ padding: 2px;
+}
+.memitem {
+ padding: 4px;
+ background-color: #eef3f5;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #dedeee;
+ -moz-border-radius: 8px 8px 8px 8px;
+}
+.memname {
+ white-space: nowrap;
+ font-weight: bold;
+}
+.memdoc{
+ padding-left: 10px;
+}
+.memproto {
+ background-color: #d5e1e8;
+ width: 100%;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #84b0c7;
+ font-weight: bold;
+ -moz-border-radius: 8px 8px 8px 8px;
+}
+.paramkey {
+ text-align: right;
+}
+.paramtype {
+ white-space: nowrap;
+}
+.paramname {
+ color: #602020;
+ font-style: italic;
+ white-space: nowrap;
+}
+/* End Styling for detailed member documentation */
+
+/* for the tree view */
+.ftvtree {
+ font-family: sans-serif;
+ margin:0.5em;
+}
+/* these are for tree view when used as main index */
+.directory {
+ font-size: 9pt;
+ font-weight: bold;
+}
+.directory h3 {
+ margin: 0px;
+ margin-top: 1em;
+ font-size: 11pt;
+}
+
+/* The following two styles can be used to replace the root node title */
+/* with an image of your choice. Simply uncomment the next two styles, */
+/* specify the name of your image and be sure to set 'height' to the */
+/* proper pixel height of your image. */
+
+/* .directory h3.swap { */
+/* height: 61px; */
+/* background-repeat: no-repeat; */
+/* background-image: url("yourimage.gif"); */
+/* } */
+/* .directory h3.swap span { */
+/* display: none; */
+/* } */
+
+.directory > h3 {
+ margin-top: 0;
+}
+.directory p {
+ margin: 0px;
+ white-space: nowrap;
+}
+.directory div {
+ display: none;
+ margin: 0px;
+}
+.directory img {
+ vertical-align: -30%;
+}
+/* these are for tree view when not used as main index */
+.directory-alt {
+ font-size: 100%;
+ font-weight: bold;
+}
+.directory-alt h3 {
+ margin: 0px;
+ margin-top: 1em;
+ font-size: 11pt;
+}
+.directory-alt > h3 {
+ margin-top: 0;
+}
+.directory-alt p {
+ margin: 0px;
+ white-space: nowrap;
+}
+.directory-alt div {
+ display: none;
+ margin: 0px;
+}
+.directory-alt img {
+ vertical-align: -30%;
+}
+
diff --git a/cpp/docs/api/doxygen_mainpage.h b/cpp/docs/api/doxygen_mainpage.h
new file mode 100644
index 0000000000..83efaba31d
--- /dev/null
+++ b/cpp/docs/api/doxygen_mainpage.h
@@ -0,0 +1,133 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+// This header file is just for doxygen documentation purposes.
+
+/** \mainpage Qpid C++ API Reference
+ *
+ * <h2>Messaging Client API classes</h2>
+ * <ul>
+ * <li><p>\ref clientapi</p></li>
+ * <li><p>\ref qmfapi</p></li>
+ * </ul>
+ *
+ * <h2>Code for common tasks</h2>
+ *
+ * <ul><li><p>Includes and Namespaces</p>
+ * <pre> \#include <qpid/client/Connection.h>
+ * \#include <qpid/client/Session.h>
+ * \#include <qpid/client/Message.h>
+ * \#include <qpid/client/SubscriptionManager.h>
+ *
+ *
+ * using namespace qpid::client;
+ * using namespace qpid::framing;</pre></li>
+ *
+ * <li><p>Opening and closing connections and sessions</p>
+ * <pre> Connection connection;
+ * try {
+ * connection.open(host, port);
+ * Session session = connection.newSession();
+ * ...
+ * connection.close();
+ * return 0;
+ * } catch(const std::exception& error) {
+ * std::cout << error.what() << std::endl;
+ * }
+ * return 1;</pre>
+ *
+ *
+ * <li><p>Declaring and binding queues:</p>
+ *
+ * <pre> session.queueDeclare(arg::queue="message_queue");
+ * session.exchangeBind(arg::exchange="amq.direct", arg::queue="message_queue", arg::bindingKey="routing_key");</pre></li>
+ *
+ * <li><p>Sending a message:</p>
+ *
+ * <pre> message.getDeliveryProperties().setRoutingKey("routing_key");
+ * message.setData("Hi, Mom!");
+ * session.messageTransfer(arg::content=message, arg::destination="amq.direct");</pre></li>
+ *
+ * <li><p>Sending a message (asynchronous):</p>
+ *
+ * <pre> ##include <qpid/client/AsyncSession.h>
+ * async(session).messageTransfer(arg::content=message, arg::destination="amq.direct");
+ * ...
+ * session.sync();</pre></li>
+ *
+ *
+ * <li><p>Replying to a message:</p>
+ * <pre> Message request, response;
+ * ...
+ * if (request.getMessageProperties().hasReplyTo()) {
+ * string routingKey = request.getMessageProperties().getReplyTo().getRoutingKey();
+ * string exchange = request.getMessageProperties().getReplyTo().getExchange();
+ * response.getDeliveryProperties().setRoutingKey(routingKey);
+ * messageTransfer(arg::content=response, arg::destination=exchange);
+ * }
+ * </pre></li>
+ *
+ * <li><p>A message listener:</p>
+ *
+ * <pre> class Listener : public MessageListener{
+ * private:
+ * SubscriptionManager& subscriptions;
+ * public:
+ * Listener(SubscriptionManager& subscriptions);
+ * virtual void received(Message& message);
+ * };
+ *
+ * void Listener::received(Message& message) {
+ * std::cout << "Message: " << message.getData() << std::endl;
+ * if (endCondition(message)) {
+ * subscriptions.cancel(message.getDestination());
+ * }
+ * }</pre></li>
+ *
+ * <li><p>Using a message listener with a subscription manager:</p>
+ *
+ * <pre> SubscriptionManager subscriptions(session);
+ *
+ * Listener listener(subscriptions);
+ * subscriptions.subscribe(listener, "message_queue");
+ * subscriptions.run();</pre></li>
+ *
+ * <li><p>Using a LocalQueue with a subscription manager</p>
+ *
+ * <pre> SubscriptionManager subscriptions(session);
+ *
+ * LocalQueue local_queue;
+ * subscriptions.subscribe(local_queue, string("message_queue"));
+ *
+ * Message message;
+ * for (int i=0; i<10; i++) {
+ * local_queue.get(message, 10000);
+ * std::cout << message.getData() << std::endl;
+ * }</pre></li><ul>
+ *
+ *
+ */
+
+/**
+ * \defgroup clientapi Qpid C++ Client API
+ * \defgroup qmfapi Qpid Management Framework C++ API
+ *
+ */
diff --git a/cpp/docs/api/footer.html b/cpp/docs/api/footer.html
new file mode 100644
index 0000000000..883410ce25
--- /dev/null
+++ b/cpp/docs/api/footer.html
@@ -0,0 +1,31 @@
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<hr size="1">
+<address style="text-align: left;"><small>
+Qpid C++ API Reference</small></address>
+
+<address style="text-align: right;">
+<small>
+Generated on $datetime for $projectname by&nbsp;<a href="http://www.doxygen.org/index.html"><img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> $doxygenversion</small>
+</address>
+</body>
+</html>
diff --git a/cpp/docs/api/header.html b/cpp/docs/api/header.html
new file mode 100644
index 0000000000..9c85c54000
--- /dev/null
+++ b/cpp/docs/api/header.html
@@ -0,0 +1,50 @@
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
+<title>$title</title>
+<link href="$relpath$doxygen.css" rel="stylesheet" type="text/css">
+<link href="$relpath$tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
+ <title>Apache Qpid C++ API</title>
+ <link href="doxygen.css" rel="stylesheet" type="text/css">
+ <link href="tabs.css" rel="stylesheet" type="text/css">
+ </head>
+ <body bgcolor="#FFFFFF">
+ <table border="0" width="90%" align="center">
+ <tr>
+ <td align="left">
+ <a title="Apache Qpid Project Page" href="http://qpid.apache.org">Apache Qpid - AMQP Messaging for Java JMS, C++, Python, Ruby, and .NET</a>
+ </td>
+
+ <td align="right">
+ <a title="Apache Qpid Documentation" href="http://qpid.apache.org/documentation.html">Apache Qpid Documentation</a>
+ </td>
+ </tr>
+</table>
+
diff --git a/cpp/docs/api/stylesheet.css b/cpp/docs/api/stylesheet.css
new file mode 100644
index 0000000000..3292768f0c
--- /dev/null
+++ b/cpp/docs/api/stylesheet.css
@@ -0,0 +1,494 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
+ font-family: Geneva, Arial, Helvetica, sans-serif;
+}
+BODY,TD {
+ font-size: 90%;
+}
+H1 {
+ text-align: center;
+ font-size: 160%;
+}
+H2 {
+ font-size: 120%;
+}
+H3 {
+ font-size: 100%;
+}
+CAPTION {
+ font-weight: bold
+}
+DIV.qindex {
+ width: 100%;
+ background-color: #e8eef2;
+ border: 1px solid #84b0c7;
+ text-align: center;
+ margin: 2px;
+ padding: 2px;
+ line-height: 140%;
+}
+DIV.navpath {
+ width: 100%;
+ background-color: #e8eef2;
+ border: 1px solid #84b0c7;
+ text-align: center;
+ margin: 2px;
+ padding: 2px;
+ line-height: 140%;
+}
+DIV.navtab {
+ background-color: #e8eef2;
+ border: 1px solid #84b0c7;
+ text-align: center;
+ margin: 2px;
+ margin-right: 15px;
+ padding: 2px;
+}
+TD.navtab {
+ font-size: 70%;
+}
+A.qindex {
+ text-decoration: none;
+ font-weight: bold;
+ color: #1A419D;
+}
+A.qindex:visited {
+ text-decoration: none;
+ font-weight: bold;
+ color: #1A419D
+}
+A.qindex:hover {
+ text-decoration: none;
+ background-color: #ddddff;
+}
+A.qindexHL {
+ text-decoration: none;
+ font-weight: bold;
+ background-color: #6666cc;
+ color: #ffffff;
+ border: 1px double #9295C2;
+}
+A.qindexHL:hover {
+ text-decoration: none;
+ background-color: #6666cc;
+ color: #ffffff;
+}
+A.qindexHL:visited {
+ text-decoration: none;
+ background-color: #6666cc;
+ color: #ffffff
+}
+A.el {
+ text-decoration: none;
+ font-weight: bold
+}
+A.elRef {
+ font-weight: bold
+}
+A.code:link {
+ text-decoration: none;
+ font-weight: normal;
+ color: #0000FF
+}
+A.code:visited {
+ text-decoration: none;
+ font-weight: normal;
+ color: #0000FF
+}
+A.codeRef:link {
+ font-weight: normal;
+ color: #0000FF
+}
+A.codeRef:visited {
+ font-weight: normal;
+ color: #0000FF
+}
+A:hover {
+ text-decoration: none;
+ background-color: #f2f2ff
+}
+DL.el {
+ margin-left: -1cm
+}
+.fragment {
+ font-family: monospace, fixed;
+ font-size: 95%;
+}
+PRE.fragment {
+ border: 1px solid #CCCCCC;
+ background-color: #f5f5f5;
+ margin-top: 4px;
+ margin-bottom: 4px;
+ margin-left: 2px;
+ margin-right: 8px;
+ padding-left: 6px;
+ padding-right: 6px;
+ padding-top: 4px;
+ padding-bottom: 4px;
+}
+DIV.ah {
+ background-color: black;
+ font-weight: bold;
+ color: #ffffff;
+ margin-bottom: 3px;
+ margin-top: 3px
+}
+
+DIV.groupHeader {
+ margin-left: 16px;
+ margin-top: 12px;
+ margin-bottom: 6px;
+ font-weight: bold;
+}
+DIV.groupText {
+ margin-left: 16px;
+ font-style: italic;
+ font-size: 90%
+}
+BODY {
+ background: white;
+ color: black;
+ margin-right: 20px;
+ margin-left: 20px;
+}
+TD.indexkey {
+ background-color: #e8eef2;
+ font-weight: bold;
+ padding-right : 10px;
+ padding-top : 2px;
+ padding-left : 10px;
+ padding-bottom : 2px;
+ margin-left : 0px;
+ margin-right : 0px;
+ margin-top : 2px;
+ margin-bottom : 2px;
+ border: 1px solid #CCCCCC;
+}
+TD.indexvalue {
+ background-color: #e8eef2;
+ font-style: italic;
+ padding-right : 10px;
+ padding-top : 2px;
+ padding-left : 10px;
+ padding-bottom : 2px;
+ margin-left : 0px;
+ margin-right : 0px;
+ margin-top : 2px;
+ margin-bottom : 2px;
+ border: 1px solid #CCCCCC;
+}
+TR.memlist {
+ background-color: #f0f0f0;
+}
+P.formulaDsp {
+ text-align: center;
+}
+IMG.formulaDsp {
+}
+IMG.formulaInl {
+ vertical-align: middle;
+}
+SPAN.keyword { color: #008000 }
+SPAN.keywordtype { color: #604020 }
+SPAN.keywordflow { color: #e08000 }
+SPAN.comment { color: #800000 }
+SPAN.preprocessor { color: #806020 }
+SPAN.stringliteral { color: #002080 }
+SPAN.charliteral { color: #008080 }
+SPAN.vhdldigit { color: #ff00ff }
+SPAN.vhdlchar { color: #000000 }
+SPAN.vhdlkeyword { color: #700070 }
+SPAN.vhdllogic { color: #ff0000 }
+
+.mdescLeft {
+ padding: 0px 8px 4px 8px;
+ font-size: 80%;
+ font-style: italic;
+ background-color: #FAFAFA;
+ border-top: 1px none #E0E0E0;
+ border-right: 1px none #E0E0E0;
+ border-bottom: 1px none #E0E0E0;
+ border-left: 1px none #E0E0E0;
+ margin: 0px;
+}
+.mdescRight {
+ padding: 0px 8px 4px 8px;
+ font-size: 80%;
+ font-style: italic;
+ background-color: #FAFAFA;
+ border-top: 1px none #E0E0E0;
+ border-right: 1px none #E0E0E0;
+ border-bottom: 1px none #E0E0E0;
+ border-left: 1px none #E0E0E0;
+ margin: 0px;
+}
+.memItemLeft {
+ padding: 1px 0px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: solid;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.memItemRight {
+ padding: 1px 8px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: solid;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.memTemplItemLeft {
+ padding: 1px 0px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: none;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.memTemplItemRight {
+ padding: 1px 8px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: none;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.memTemplParams {
+ padding: 1px 0px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: solid;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ color: #606060;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.search {
+ color: #003399;
+ font-weight: bold;
+}
+FORM.search {
+ margin-bottom: 0px;
+ margin-top: 0px;
+}
+INPUT.search {
+ font-size: 75%;
+ color: #000080;
+ font-weight: normal;
+ background-color: #e8eef2;
+}
+TD.tiny {
+ font-size: 75%;
+}
+a {
+ color: #1A41A8;
+}
+a:visited {
+ color: #2A3798;
+}
+.dirtab {
+ padding: 4px;
+ border-collapse: collapse;
+ border: 1px solid #84b0c7;
+}
+TH.dirtab {
+ background: #e8eef2;
+ font-weight: bold;
+}
+HR {
+ height: 1px;
+ border: none;
+ border-top: 1px solid black;
+}
+
+/* Style for detailed member documentation */
+.memtemplate {
+ font-size: 80%;
+ color: #606060;
+ font-weight: normal;
+ margin-left: 3px;
+}
+.memnav {
+ background-color: #e8eef2;
+ border: 1px solid #84b0c7;
+ text-align: center;
+ margin: 2px;
+ margin-right: 15px;
+ padding: 2px;
+}
+.memitem {
+ padding: 4px;
+ background-color: #eef3f5;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #dedeee;
+ -moz-border-radius: 8px 8px 8px 8px;
+}
+.memname {
+ white-space: nowrap;
+ font-weight: bold;
+}
+.memdoc{
+ padding-left: 10px;
+}
+.memproto {
+ background-color: #d5e1e8;
+ width: 100%;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #84b0c7;
+ font-weight: bold;
+ -moz-border-radius: 8px 8px 8px 8px;
+}
+.paramkey {
+ text-align: right;
+}
+.paramtype {
+ white-space: nowrap;
+}
+.paramname {
+ color: #602020;
+ font-style: italic;
+ white-space: nowrap;
+}
+/* End Styling for detailed member documentation */
+
+/* for the tree view */
+.ftvtree {
+ font-family: sans-serif;
+ margin:0.5em;
+}
+/* these are for tree view when used as main index */
+.directory {
+ font-size: 9pt;
+ font-weight: bold;
+}
+.directory h3 {
+ margin: 0px;
+ margin-top: 1em;
+ font-size: 11pt;
+}
+
+/* The following two styles can be used to replace the root node title */
+/* with an image of your choice. Simply uncomment the next two styles, */
+/* specify the name of your image and be sure to set 'height' to the */
+/* proper pixel height of your image. */
+
+/* .directory h3.swap { */
+/* height: 61px; */
+/* background-repeat: no-repeat; */
+/* background-image: url("yourimage.gif"); */
+/* } */
+/* .directory h3.swap span { */
+/* display: none; */
+/* } */
+
+.directory > h3 {
+ margin-top: 0;
+}
+.directory p {
+ margin: 0px;
+ white-space: nowrap;
+}
+.directory div {
+ display: none;
+ margin: 0px;
+}
+.directory img {
+ vertical-align: -30%;
+}
+/* these are for tree view when not used as main index */
+.directory-alt {
+ font-size: 100%;
+ font-weight: bold;
+}
+.directory-alt h3 {
+ margin: 0px;
+ margin-top: 1em;
+ font-size: 11pt;
+}
+.directory-alt > h3 {
+ margin-top: 0;
+}
+.directory-alt p {
+ margin: 0px;
+ white-space: nowrap;
+}
+.directory-alt div {
+ display: none;
+ margin: 0px;
+}
+.directory-alt img {
+ vertical-align: -30%;
+}
+
diff --git a/cpp/docs/api/tabs.css b/cpp/docs/api/tabs.css
new file mode 100644
index 0000000000..56f0e04564
--- /dev/null
+++ b/cpp/docs/api/tabs.css
@@ -0,0 +1,123 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/* tabs styles, based on http://www.alistapart.com/articles/slidingdoors */
+
+DIV.tabs
+{
+ float : left;
+ width : 100%;
+ background : url("tab_b.gif") repeat-x bottom;
+ margin-bottom : 4px;
+}
+
+DIV.tabs UL
+{
+ margin : 0px;
+ padding-left : 10px;
+ list-style : none;
+}
+
+DIV.tabs LI, DIV.tabs FORM
+{
+ display : inline;
+ margin : 0px;
+ padding : 0px;
+}
+
+DIV.tabs FORM
+{
+ float : right;
+}
+
+DIV.tabs A
+{
+ float : left;
+ background : url("tab_r.gif") no-repeat right top;
+ border-bottom : 1px solid #84B0C7;
+ font-size : x-small;
+ font-weight : bold;
+ text-decoration : none;
+}
+
+DIV.tabs A:hover
+{
+ background-position: 100% -150px;
+}
+
+DIV.tabs A:link, DIV.tabs A:visited,
+DIV.tabs A:active, DIV.tabs A:hover
+{
+ color: #1A419D;
+}
+
+DIV.tabs SPAN
+{
+ float : left;
+ display : block;
+ background : url("tab_l.gif") no-repeat left top;
+ padding : 5px 9px;
+ white-space : nowrap;
+}
+
+DIV.tabs INPUT
+{
+ float : right;
+ display : inline;
+ font-size : 1em;
+}
+
+DIV.tabs TD
+{
+ font-size : x-small;
+ font-weight : bold;
+ text-decoration : none;
+}
+
+
+
+/* Commented Backslash Hack hides rule from IE5-Mac \*/
+DIV.tabs SPAN {float : none;}
+/* End IE5-Mac hack */
+
+DIV.tabs A:hover SPAN
+{
+ background-position: 0% -150px;
+}
+
+DIV.tabs LI.current A
+{
+ background-position: 100% -150px;
+ border-width : 0px;
+}
+
+DIV.tabs LI.current SPAN
+{
+ background-position: 0% -150px;
+ padding-bottom : 6px;
+}
+
+DIV.navpath
+{
+ background : none;
+ border : none;
+ border-bottom : 1px solid #84B0C7;
+}
diff --git a/cpp/docs/api/user.doxygen.in b/cpp/docs/api/user.doxygen.in
index ee0860f8b4..2fbac9eb27 100644
--- a/cpp/docs/api/user.doxygen.in
+++ b/cpp/docs/api/user.doxygen.in
@@ -25,13 +25,13 @@
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
# by quotes) that should identify the project.
-PROJECT_NAME = Qpid
+PROJECT_NAME = "Qpid C++ Client API"
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
# This could be handy for archiving the generated documentation or
# if some version control system is used.
-PROJECT_NUMBER = 0
+# PROJECT_NUMBER = 0
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
@@ -98,7 +98,7 @@ ALWAYS_DETAILED_SEC = NO
# members were ordinary class members. Constructors, destructors and assignment
# operators of the base classes will not be shown.
-INLINE_INHERITED_MEMB = NO
+INLINE_INHERITED_MEMB = YES
# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
# path before files name in the file list and in the header files. If set
@@ -113,7 +113,7 @@ FULL_PATH_NAMES = YES
# If left blank the directory from which doxygen is run is used as the
# path to strip.
-STRIP_FROM_PATH =
+STRIP_FROM_PATH = @top_srcdir@/include @top_builddir@/include @top_builddir@/src/gen
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
# the path mentioned in the documentation of a class, which tells
@@ -122,7 +122,7 @@ STRIP_FROM_PATH =
# definition is used. Otherwise one should specify the include paths that
# are normally passed to the compiler using the -I flag.
-STRIP_FROM_INC_PATH =
+STRIP_FROM_INC_PATH = @top_srcdir@/include @top_builddir@/include
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
# (but less readable) file names. This can be useful is your file systems
@@ -226,7 +226,7 @@ SUBGROUPING = YES
# Private class members and static file members will be hidden unless
# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
-EXTRACT_ALL = NO
+EXTRACT_ALL = YES
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
# will be included in the documentation.
@@ -264,7 +264,7 @@ HIDE_UNDOC_MEMBERS = NO
# If set to NO (the default) these classes will be included in the various
# overviews. This option has no effect if EXTRACT_ALL is enabled.
-HIDE_UNDOC_CLASSES = YES
+HIDE_UNDOC_CLASSES = NO # jwr 2008-11-25
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
# friend (class|struct|union) declarations.
@@ -404,8 +404,7 @@ FILE_VERSION_FILTER =
# The QUIET tag can be used to turn on/off the messages that are generated
# by doxygen. Possible values are YES and NO. If left blank NO is used.
-QUIET = YES
-
+QUIET = NO
# The WARNINGS tag can be used to turn on/off the warning messages that are
# generated by doxygen. Possible values are YES and NO. If left blank
# NO is used.
@@ -457,7 +456,8 @@ WARN_LOGFILE = doxygen.log
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = @top_srcdir@/src/qpid @top_builddir@/src/gen/qpid
+INPUT = @top_srcdir@/docs/api @top_srcdir@/include @top_builddir@/include
+
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
@@ -600,7 +600,7 @@ VERBATIM_HEADERS = NO
# of all compounds will be generated. Enable this if the project
# contains a lot of classes, structs, unions or interfaces.
-ALPHABETICAL_INDEX = NO
+ALPHABETICAL_INDEX = YES
# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
@@ -640,13 +640,13 @@ HTML_FILE_EXTENSION = .html
# each generated HTML page. If it is left blank doxygen will generate a
# standard header.
-HTML_HEADER =
+HTML_HEADER = @srcdir@/header.html
# The HTML_FOOTER tag can be used to specify a personal HTML footer for
# each generated HTML page. If it is left blank doxygen will generate a
# standard footer.
-HTML_FOOTER =
+HTML_FOOTER = @srcdir@/footer.html
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
# style sheet that is used by each HTML page. It can be used to
@@ -968,7 +968,7 @@ ENABLE_PREPROCESSING = YES
# compilation will be performed. Macro expansion can be done in a controlled
# way by setting EXPAND_ONLY_PREDEF to YES.
-MACRO_EXPANSION = NO
+MACRO_EXPANSION = YES
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
# then the macro expansion is limited to the macros specified with the
@@ -1002,14 +1002,14 @@ INCLUDE_FILE_PATTERNS =
# undefined via #undef or recursively expanded use the := operator
# instead of the = operator.
-PREDEFINED =
+PREDEFINED = QPID_CLIENT_EXTERN= QPID_COMMON_EXTERN= QPID_CONSOLE_EXTERN= QPID_BROKER_EXTERN=
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
# The macro definition that is found in the sources will be used.
# Use the PREDEFINED tag if you want to use a different macro definition.
-EXPAND_AS_DEFINED =
+EXPAND_AS_DEFINED = BOOST_PARAMETER_MEMFUN
# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
# doxygen's preprocessor will remove all function-like macros that are alone
@@ -1073,7 +1073,7 @@ PERL_PATH = /usr/bin/perl
# fallback. It is recommended to install and use dot, since it yields more
# powerful graphs.
-CLASS_DIAGRAMS = YES
+CLASS_DIAGRAMS = NO
# If set to YES, the inheritance and collaboration graphs will hide
# inheritance and usage relations if the target is undocumented
@@ -1086,51 +1086,51 @@ HIDE_UNDOC_RELATIONS = YES
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
# have no effect if this option is set to NO (the default)
-HAVE_DOT = YES
+HAVE_DOT = NO
# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and
# indirect inheritance relations. Setting this tag to YES will force the
# the CLASS_DIAGRAMS tag to NO.
-CLASS_GRAPH = YES
+CLASS_GRAPH = NO
# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and
# indirect implementation dependencies (inheritance, containment, and
# class references variables) of the class with other documented classes.
-COLLABORATION_GRAPH = YES
+COLLABORATION_GRAPH = NO
# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for groups, showing the direct groups dependencies
-GROUP_GRAPHS = YES
+GROUP_GRAPHS = NO
# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
# collaboration diagrams in a style similar to the OMG's Unified Modeling
# Language.
-UML_LOOK = YES
+UML_LOOK = NO
# If set to YES, the inheritance and collaboration graphs will show the
# relations between templates and their instances.
-TEMPLATE_RELATIONS = YES
+TEMPLATE_RELATIONS = NO
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
# tags are set to YES then doxygen will generate a graph for each documented
# file showing the direct and indirect include dependencies of the file with
# other documented files.
-INCLUDE_GRAPH = YES
+INCLUDE_GRAPH = NO
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
# documented header file showing the documented files that directly or
# indirectly include this file.
-INCLUDED_BY_GRAPH = YES
+INCLUDED_BY_GRAPH = NO
# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
# generate a call dependency graph for every global function or class method.
@@ -1143,20 +1143,20 @@ CALL_GRAPH = NO
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
# will graphical hierarchy of all classes instead of a textual one.
-GRAPHICAL_HIERARCHY = YES
+GRAPHICAL_HIERARCHY = NO
# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
# then doxygen will show the dependencies a directory has on other directories
# in a graphical way. The dependency relations are determined by the #include
# relations between the files in the directories.
-DIRECTORY_GRAPH = YES
+DIRECTORY_GRAPH = NO
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
# generated by dot. Possible values are png, jpg, or gif
# If left blank png will be used.
-DOT_IMAGE_FORMAT = png
+DOT_IMAGE_FORMAT = PNG
# The tag DOT_PATH can be used to specify the path where the dot tool can be
# found. If left blank, it is assumed the dot tool can be found in the path.
@@ -1215,4 +1215,4 @@ DOT_CLEANUP = YES
# The SEARCHENGINE tag specifies whether or not a search engine should be
# used. If set to NO the values of all tags below this one will be ignored.
-SEARCHENGINE = YES
+SEARCHENGINE = NO
diff --git a/cpp/docs/man/Makefile.am b/cpp/docs/man/Makefile.am
index 08b100121b..cb13a16e4f 100644
--- a/cpp/docs/man/Makefile.am
+++ b/cpp/docs/man/Makefile.am
@@ -1,3 +1,21 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
dist_man_MANS = qpidd.1
man_aux = $(dist_man_MANS:.1=.x)
@@ -17,7 +35,7 @@ qpidd.1: $(srcdir)/qpidd.x $(top_builddir)/src/qpidd
.x.1:
@rm -f $@
@echo "Updating man page $@"
- $(HELP2MAN) --no-info --include=$(srcdir)/$*.x --output=$@-t ../../src/$*
+ $(HELP2MAN) --no-info --include=$(srcdir)/$*.x --output=$@-t --help-option="--help --no-module-dir" --version-option="--version --no-module-dir" ../../src/$*
@chmod a-w $@-t
@mv $@-t $@
else
diff --git a/cpp/docs/man/qpidd.x b/cpp/docs/man/qpidd.x
index edbe7b3bff..9f1b465701 100644
--- a/cpp/docs/man/qpidd.x
+++ b/cpp/docs/man/qpidd.x
@@ -28,8 +28,8 @@ Each line is a name=value pair. Blank lines and lines beginning with # are ignor
# My qpidd configuration file.
port=6000
max-connections=10
- log-output=stdout
- log-output=/tmp/qpidd.log
+ log-to-stdout=yes
+ log-to-file=/tmp/qpidd.log
[ENVIRONMENT]
.I QPID_<option>
@@ -41,6 +41,6 @@ The environment variable is the option name in uppercase, prefixed with QPID_ an
export QPID_PORT=6000
export QPID_MAX_CONNECTIONS=10
- export QPID_LOG_OUTPUT=/tmp/qpidd.log
+ export QPID_LOG_TO_FILE=/tmp/qpidd.log
diff --git a/cpp/etc/CMakeLists.txt b/cpp/etc/CMakeLists.txt
new file mode 100644
index 0000000000..03121b364a
--- /dev/null
+++ b/cpp/etc/CMakeLists.txt
@@ -0,0 +1,20 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+install(FILES qpidd.conf qpidc.conf DESTINATION ${QPID_INSTALL_CONFDIR})
diff --git a/cpp/etc/Makefile.am b/cpp/etc/Makefile.am
index f683459cd4..8731641360 100644
--- a/cpp/etc/Makefile.am
+++ b/cpp/etc/Makefile.am
@@ -1,8 +1,30 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
SASL_CONF = sasl2/qpidd.conf
EXTRA_DIST = \
$(SASL_CONF) \
- qpidd qpidd.conf
+ qpidd qpidd.conf qpidc.conf CMakeLists.txt
+
+confdir=$(sysconfdir)/qpid
+nobase_conf_DATA=\
+ qpidc.conf
nobase_sysconf_DATA = \
qpidd.conf
diff --git a/cpp/etc/qpidc.conf b/cpp/etc/qpidc.conf
new file mode 100644
index 0000000000..588999c074
--- /dev/null
+++ b/cpp/etc/qpidc.conf
@@ -0,0 +1,23 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# Configuration file for the qpid c++ client library. Entries are of
+# the form:
+# name=value
+#
+# (Note: no spaces on either side of '=')
diff --git a/cpp/etc/qpidd b/cpp/etc/qpidd
index 912cd64ecb..8e6e74b33c 100755
--- a/cpp/etc/qpidd
+++ b/cpp/etc/qpidd
@@ -1,5 +1,23 @@
#!/bin/bash
#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
# qpidd Startup script for the Qpid messaging daemon.
#
@@ -74,7 +92,7 @@ case "$1" in
force-reload)
restart
;;
- try-restart)
+ try-restart|condrestart)
[ -e $lockfile ] && restart || :
;;
*)
diff --git a/cpp/etc/qpidd.conf b/cpp/etc/qpidd.conf
index 0ace726f26..8082660f6f 100644
--- a/cpp/etc/qpidd.conf
+++ b/cpp/etc/qpidd.conf
@@ -1,3 +1,24 @@
-# Configuration file for qpidd. Entries are of the form:
-# name = value
-# Using default settings: "qpidd --help" or "man qpidd" for more details.
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# Configuration file for qpidd. Entries are of the form:
+# name=value
+#
+# (Note: no spaces on either side of '='). Using default settings:
+# "qpidd --help" or "man qpidd" for more details.
+cluster-mechanism=ANONYMOUS
diff --git a/cpp/etc/sasl2/qpidd.conf b/cpp/etc/sasl2/qpidd.conf
index 42466b60cb..3197d7792a 100644
--- a/cpp/etc/sasl2/qpidd.conf
+++ b/cpp/etc/sasl2/qpidd.conf
@@ -1,4 +1,22 @@
#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
# This configuation allows for either SASL PLAIN or ANONYMOUS
# authentication. The PLAIN authentication is done on a
# username+password, which is stored in the sasldb_path
@@ -18,7 +36,10 @@
# NOTE: The sasldb file must be readable by the user running the qpidd
# daemon, and should be readable only by that user.
#
-mech_list: plain anonymous
pwcheck_method: auxprop
auxprop_plugin: sasldb
sasldb_path: /var/lib/qpidd/qpidd.sasldb
+
+#following line stops spurious 'sql_select option missing' errors when
+#cyrus-sql-sasl plugin is installed
+sql_select: dummy select
diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt
new file mode 100644
index 0000000000..7ecffed4bb
--- /dev/null
+++ b/cpp/examples/CMakeLists.txt
@@ -0,0 +1,100 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+project(qpidc_examples)
+cmake_minimum_required(VERSION 2.4.0 FATAL_ERROR)
+if(COMMAND cmake_policy)
+ cmake_policy(SET CMP0003 NEW)
+endif(COMMAND cmake_policy)
+
+include_directories(${CMAKE_BINARY_DIR}/include)
+include_directories(${CMAKE_SOURCE_DIR}/include)
+
+# Shouldn't need this... but there are still client header inclusions
+# of Boost. When building examples at an install site, the Boost files
+# should be locatable aside from these settings.
+# So set up to find the headers, find the libs at link time, but dynamically
+# link them all and clear the CMake Boost library names to avoid adding them to
+# the project files.
+include_directories( ${Boost_INCLUDE_DIR} )
+link_directories( ${Boost_LIBRARY_DIRS} )
+
+# Visual Studio needs some Windows-specific simplifications.
+# Linux needs to reference the boost libs, even though they should be
+# resolved via the Qpid libs.
+if (MSVC)
+ add_definitions( /D "NOMINMAX" /D "WIN32_LEAN_AND_MEAN" /D "BOOST_ALL_DYN_LINK" )
+ # On Windows, prevent the accidental inclusion of Boost headers from
+ # autolinking in the Boost libs. There should be no direct references to
+ # Boost in the examples, and references via qpidclient/qpidcommon are
+ # resolved in the Qpid libs.
+ add_definitions( /D "BOOST_ALL_NO_LIB" )
+else (MSVC)
+ set(_boost_libs_needed ${Boost_PROGRAM_OPTIONS_LIBRARY}
+ ${Boost_FILESYSTEM_LIBRARY})
+endif (MSVC)
+
+# There are numerous duplicate names within the examples. Since all target
+# names must be unique, define a macro to prepend a prefix and manage the
+# actual names.
+# There can be an optional arguments at the end: libs to include
+macro(add_example subdir example)
+ add_executable(${subdir}_${example} ${example}.cpp)
+ set_target_properties(${subdir}_${example} PROPERTIES OUTPUT_NAME ${example})
+ if (${ARGC} GREATER 2)
+ target_link_libraries(${subdir}_${example} ${ARGN} qpidclient
+ ${_boost_libs_needed})
+ else (${ARGC} GREATER 2)
+ target_link_libraries(${subdir}_${example} qpidclient
+ ${_boost_libs_needed})
+ endif (${ARGC} GREATER 2)
+ # For installs, don't install the built example; that would be pointless.
+ # Install the things a user needs to build the example on-site.
+ install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/${example}.cpp
+ DESTINATION ${QPID_INSTALL_EXAMPLESDIR}/${subdir}
+ COMPONENT ${QPID_COMPONENT_EXAMPLES})
+ if (MSVC)
+ install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/${subdir}_${example}.vcproj
+ DESTINATION ${QPID_INSTALL_EXAMPLESDIR}/${subdir}
+ COMPONENT ${QPID_COMPONENT_EXAMPLES})
+ endif (MSVC)
+
+endmacro(add_example)
+
+install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/README.txt
+ ${CMAKE_CURRENT_SOURCE_DIR}/README.verify
+ ${CMAKE_CURRENT_SOURCE_DIR}/verify
+ ${CMAKE_CURRENT_SOURCE_DIR}/verify_all
+ DESTINATION ${QPID_INSTALL_EXAMPLESDIR}
+ COMPONENT ${QPID_COMPONENT_EXAMPLES})
+if (MSVC)
+ install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/examples.sln
+ DESTINATION ${QPID_INSTALL_EXAMPLESDIR}
+ COMPONENT ${QPID_COMPONENT_EXAMPLES})
+endif (MSVC)
+
+add_subdirectory(direct)
+add_subdirectory(failover)
+add_subdirectory(fanout)
+add_subdirectory(pub-sub)
+#add_subdirectory(qmf-agent)
+add_subdirectory(qmf-console)
+add_subdirectory(request-response)
+add_subdirectory(tradedemo)
+add_subdirectory(xml-exchange)
+add_subdirectory(messaging)
diff --git a/cpp/examples/Makefile.am b/cpp/examples/Makefile.am
index 5415cae1a9..c6cc308d98 100644
--- a/cpp/examples/Makefile.am
+++ b/cpp/examples/Makefile.am
@@ -1,29 +1,49 @@
-SUBDIRS = direct fanout pub-sub request-response
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+SUBDIRS = direct fanout pub-sub request-response failover qmf-console tradedemo messaging
if HAVE_XML
SUBDIRS += xml-exchange
+ broker_args = "--no-module-dir --data-dir \"\" --auth no --load-module $(top_builddir)/src/.libs/xml.so"
endif
if !HAVE_XML
exclude_examples_regexp="xml" # Exclude XML examples.
+ broker_args = "--no-module-dir --data-dir \"\" --auth no"
endif
MAKEDIST=.libs/Makefile
-SUBMAKE=' for d in $(SUBDIRS) ; do $$(MAKE) -C $$$$d $$@ ; done'
+
$(MAKEDIST): Makefile
mkdir -p .libs
- @$(ECHO) all: > $(MAKEDIST)
- @$(ECHO) $(SUBMAKE) >> $(MAKEDIST)
- @$(ECHO) clean: >> $(MAKEDIST)
- @$(ECHO) $(SUBMAKE) >> $(MAKEDIST)
+ @(echo 'all clean:' ; \
+ echo ' for d in $(SUBDIRS) ; do $$(MAKE) -C $$$$d $$@ ; done' ; \
+ ) > $(MAKEDIST)
examplesdir=$(pkgdatadir)/examples
-examples_DATA = README $(MAKEDIST)
+dist_examples_DATA = README.txt $(MAKEDIST)
-EXTRA_DIST = $(examples_DATA) README.verify verify verify_all
+EXTRA_DIST = README.verify verify verify_all examples.sln CMakeLists.txt
# For older versions of automake
abs_top_srcdir = @abs_top_srcdir@
+abs_top_builddir = @abs_top_builddir@
# Verify the examples in the buid tree.
check-local:
- $(srcdir)/verify_all $(abs_top_srcdir)/.. $(top_builddir)/src/qpidd $(exclude_examples_regexp)
+ $(srcdir)/verify_all $(abs_top_srcdir)/.. $(abs_top_builddir) $(broker_args) $(exclude_examples_regexp)
diff --git a/cpp/examples/README b/cpp/examples/README
deleted file mode 100644
index d15adce58d..0000000000
--- a/cpp/examples/README
+++ /dev/null
@@ -1,26 +0,0 @@
-= Qpid C++ Examples =
-
-For more information read examples/README.
-
-== The Verify All Script ==
-
-The verify_all script will run C++ examples against itself and against the
-Python examples. The success of the script is determined by comparing its output
-against what is expected.
-
-=== Arguments ===
-
-The verify_all script expects the path to Qpid trunk as an argument, in order to
-setup the environment for Python examples.
-
-== The Verify Script ==
-
-The verify script is capable of running one or many scripts designed to verify
-the success of Qpid examples. The verify script is utilized by the verify_all
-scripts.
-
-=== Verifying an individual example ===
-
-This will require you using the verify script, and providing the necessary sub
-script(s) it will utilize in the process. Please note that it is your
-responsibility to setup the necessary environment for the verification process
diff --git a/cpp/examples/README.txt b/cpp/examples/README.txt
new file mode 100644
index 0000000000..0663286664
--- /dev/null
+++ b/cpp/examples/README.txt
@@ -0,0 +1,165 @@
+= Qpid C++ Examples =
+
+
+This directory contains example C++ programs for Apache Qpid. They are
+based on the 0-10 version of the AMQP specification (see www.amqp.org for
+details). A short description of each example follows.
+
+Please note that by default these examples attempt to connect to a Qpid
+broker running on the local host (127.0.0.1) at the standard AMQP port (5672).
+It is possible to instruct the examples to connect to an alternate broker
+host and port by specifying the host name/address and port number as arguments
+to the programs. For example, to have the declare_queues program connect to a
+broker running on host1, port 9999, run the following command:
+
+On Linux:
+ # ./declare_queues host1 9999
+
+On Windows:
+ C:\Program Files\qpidc-0.6\examples\direct> declare_queues host1 9999
+
+The qpid C++ broker executable is named qpidd on Linux and qpidd.exe
+on Windows. The default install locations are:
+- Linux: /usr/sbin
+- Windows: C:\Program Files\qpidc-0.6\bin
+
+In a C++ source distribution the broker is located in the src subdirectory
+(generally, from this examples directory, ../src).
+
+== Direct ==
+
+This example shows how to create Point-to-Point applications using Qpid. This
+example contains three components.
+
+ 1. declare_queues
+ This will bind a queue to the amq.direct exchange, so that the messages
+ sent to the amq.direct exchange with a given routing key (routing_key) are
+ delivered to a specific queue (message_queue).
+
+ 2. direct_producer
+ Publishes messages to the amq.direct exchange using the given routing key
+ (routing_key) discussed above.
+
+ 3. listener
+ Uses a message listener to listen for messages from a specific queue
+ (message_queue) as discussed above.
+
+In order to run this example,
+
+On Linux:
+ # ./declare_queues
+ # ./direct_producer
+ # ./listener
+
+On Windows:
+ C:\Program Files\qpidc-0.6\examples\direct> declare_queues
+ C:\Program Files\qpidc-0.6\examples\direct> direct_producer
+ C:\Program Files\qpidc-0.6\examples\direct> listener
+
+Note that there is no requirement for the listener to be running before the
+messages are published. The messages are stored in the queue until consumed
+by the listener.
+
+== Fanout ==
+
+This example shows how to create Fanout exchange applications using Qpid.
+This example has two components. Unlike the Direct example, the Fanout exchange
+does not need a routing key to be specified.
+
+ 1. fanout_producer
+ Publishes a message to the amq.fanout exchange, without using a routing key.
+
+ 2. listener
+ Uses a message listener to listen for messages from the amq.fanout exchange.
+
+
+Note that unlike the Direct example, it is necessary to start the listener
+before the messages are published. The fanout exchange does not hold messages
+in a queue. Therefore, it is recommended that the two parts of the example be
+run in separate windows.
+
+In order to run this example:
+
+On Linux:
+ # ./listener
+
+ # ./fanout_producer
+
+On Windows:
+ C:\Program Files\qpidc-0.6\examples\fanout> listener
+
+ C:\Program Files\qpidc-0.6\examples\direct> fanout_producer
+
+== Publisher/Subscriber ==
+
+This example demonstrates the ability to create topic Publishers and
+Subscribers using Qpid. This example has two components.
+
+ 1. topic_publisher
+ This application is used to publish messages to the amq.topic exchange
+ using multipart routing keys, usa.weather, europe.weather, usa.news and
+ europe.news.
+
+ 2. topic_listener
+ This application is used to subscribe to several private queues, such as
+ usa, europe, weather and news. In this program, each private queue created
+ is bound to the amq.topic exchange using bindings that match the
+ corresponding parts of the multipart routing keys. For example, subscribing
+ to #.news will retrieve news irrespective of destination.
+
+This example also shows the use of the 'control' routing key which is used by
+control messages.
+
+Due to this example's design, the topic_listener must be running before
+starting the topic_publisher. Therefore, it is recommended that the two parts
+of the example be run in separate windows.
+
+In order to run this example,
+
+On Linux:
+ # ./topic_listener
+
+ # ./topic_publisher
+
+On Windows:
+ C:\Program Files\qpidc-0.6\examples\pub-sub> topic_listener
+
+ C:\Program Files\qpidc-0.6\examples\pub-sub> topic_publisher
+
+== Request/Response ==
+
+This example shows a simple server that will accept strings from a client,
+convert them to upper case, and send them back to the client. This example
+has two components.
+
+ 1. client
+ This sends lines of poetry to the server.
+
+ 2. server
+ This is a simple service that will convert incoming strings to upper case
+ and send the result to amq.direct exchange on which the client listens.
+ It uses the request's reply_to property as the response's routing key.
+
+In order to run this example,
+
+On Linux:
+ # ./server
+ # ./client
+
+On Windows:
+ C:\Program Files\qpidc-0.6\examples\request-response> server
+ C:\Program Files\qpidc-0.6\examples\request-response> client
+
+== QMF Agent ==
+
+This example demonstrates integration with the Qpid Management Framework (QMF).
+The qmf-agent program will connect to a running Qpid broker and advertise a
+managed object (org.apache.qpid.agent.example:parent). Using the qpid-tool,
+you can monitor the object and also call a method (create_child) to spawn
+managed child objects.
+
+To build this example, simply invoke make on Unix or Linux. On Windows, you
+must invoke
+ nmake /f example_gen.mak
+before building the sample to generate the supporting model classes
+(e.g., Parent,Child,etc.).
diff --git a/cpp/examples/direct/CMakeLists.txt b/cpp/examples/direct/CMakeLists.txt
new file mode 100644
index 0000000000..2ec1b2b813
--- /dev/null
+++ b/cpp/examples/direct/CMakeLists.txt
@@ -0,0 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+add_example(direct declare_queues)
+add_example(direct direct_producer)
+add_example(direct listener)
diff --git a/cpp/examples/direct/Makefile.am b/cpp/examples/direct/Makefile.am
index 7a0cf65968..467533371e 100644
--- a/cpp/examples/direct/Makefile.am
+++ b/cpp/examples/direct/Makefile.am
@@ -1,5 +1,24 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
examplesdir=$(pkgdatadir)/examples/direct
+MAKELDFLAGS=$(CLIENTFLAGS)
include $(top_srcdir)/examples/makedist.mk
noinst_PROGRAMS=direct_producer listener declare_queues
@@ -20,10 +39,13 @@ examples_DATA= \
EXTRA_DIST= \
$(examples_DATA) \
+ CMakeLists.txt \
verify \
verify.in \
verify_cpp_python \
verify_cpp_python.in \
verify_python_cpp \
- verify_python_cpp.in
-
+ verify_python_cpp.in \
+ direct_declare_queues.vcproj \
+ direct_direct_producer.vcproj \
+ direct_listener.vcproj
diff --git a/cpp/examples/direct/declare_queues.cpp b/cpp/examples/direct/declare_queues.cpp
index 0cdb472665..9a51d1982b 100644
--- a/cpp/examples/direct/declare_queues.cpp
+++ b/cpp/examples/direct/declare_queues.cpp
@@ -19,39 +19,38 @@
*
*/
+
/**
* declare_queues.cpp
*
* This program is one of three programs designed to be used
- * together. These programs use the "amq.direct" exchange.
+ * together.
*
- * direct_config_queues.cpp (this program):
+ * declare_queues.cpp: (this program):
*
- * Creates a queue on a broker, binding a routing key to route
- * messages to that queue.
+ * Creates a queue named "message_queue" on a broker, binding the
+ * queue to the "amq.direct" exchange, using the routing key
+ * "routing_key".
*
- * direct_producer.cpp:
+ * direct_producer.cpp
*
- * Publishes to a broker, specifying a routing key.
+ * Publishes to the "amq.direct" exchange, specifying the routing
+ * key "routing_key"
*
- * listener.cpp
+ * listener.cpp
*
- * Reads from a queue on the broker using a message listener.
+ * Reads from the "message_queue" queue on the broker using a
+ * message listener.
*
*/
#include <qpid/client/Connection.h>
#include <qpid/client/Session.h>
-#include <unistd.h>
-#include <cstdlib>
-#include <iostream>
using namespace qpid::client;
using namespace qpid::framing;
-using std::string;
-
int main(int argc, char** argv) {
const char* host = argc>1 ? argv[1] : "127.0.0.1";
diff --git a/cpp/examples/direct/direct_declare_queues.vcproj b/cpp/examples/direct/direct_declare_queues.vcproj
new file mode 100644
index 0000000000..ae6bfaac6a
--- /dev/null
+++ b/cpp/examples/direct/direct_declare_queues.vcproj
@@ -0,0 +1,394 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="direct_declare_queues"
+ ProjectGUID="{18165D4D-FECA-1BAD-4346-8C4DF2536AA5}"
+ RootNamespace="direct_declare_queues"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\direct_declare_queues\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;BOOST_ALL_DYN_LINK"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\declare_queues.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\direct_declare_queues\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\declare_queues.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\direct_declare_queues\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\declare_queues.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\direct_declare_queues\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\declare_queues.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="declare_queues.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="ConnectionOptions.h">
+ </File>
+ <File
+ RelativePath="TestOptions.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/direct/direct_direct_producer.vcproj b/cpp/examples/direct/direct_direct_producer.vcproj
new file mode 100644
index 0000000000..e72c3cef3f
--- /dev/null
+++ b/cpp/examples/direct/direct_direct_producer.vcproj
@@ -0,0 +1,394 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="direct_direct_producer"
+ ProjectGUID="{9701E0BD-FECA-1BAD-4346-8C4DF2536AA5}"
+ RootNamespace="direct_direct_producer"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\direct_direct_producer\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\direct_producer.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\direct_direct_producer\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\direct_producer.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\direct_direct_producer\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\direct_producer.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\direct_direct_producer\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\direct_producer.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="direct_producer.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="ConnectionOptions.h">
+ </File>
+ <File
+ RelativePath="TestOptions.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/direct/direct_listener.vcproj b/cpp/examples/direct/direct_listener.vcproj
new file mode 100644
index 0000000000..a514ed8dbf
--- /dev/null
+++ b/cpp/examples/direct/direct_listener.vcproj
@@ -0,0 +1,394 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="direct_listener"
+ ProjectGUID="{95CE1459-FECA-1BAD-4346-8C4DF2536AA5}"
+ RootNamespace="direct_listener"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\direct_listener\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\listener.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\direct_listener\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\listener.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\direct_listener\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\listener.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\direct_listener\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\listener.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="listener.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="ConnectionOptions.h">
+ </File>
+ <File
+ RelativePath="TestOptions.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/direct/direct_producer.cpp b/cpp/examples/direct/direct_producer.cpp
index 40fc644bf3..ecc9675189 100644
--- a/cpp/examples/direct/direct_producer.cpp
+++ b/cpp/examples/direct/direct_producer.cpp
@@ -19,26 +19,27 @@
*
*/
-
/**
* direct_producer.cpp:
*
* This program is one of three programs designed to be used
- * together. These programs do not specify the exchange type - the
- * default exchange type is the direct exchange.
+ * together.
*
* create_queues.cpp:
*
- * Creates a queue on a broker, binding a routing key to route
- * messages to that queue.
+ * Creates a queue named "message_queue" on a broker, binding the
+ * queue to the "amq.direct" exchange, using the routing key
+ * "routing_key".
*
* direct_producer.cpp (this program):
*
- * Publishes to a broker, specifying a routing key.
+ * Publishes to the "amq.direct" exchange, specifying the routing
+ * key "routing_key"
*
* listener.cpp
*
- * Reads from a queue on the broker using a message listener.
+ * Reads from the "message_queue" queue on the broker using a
+ * message listener.
*
*/
@@ -49,7 +50,6 @@
#include <qpid/client/Message.h>
-#include <unistd.h>
#include <cstdlib>
#include <iostream>
@@ -64,8 +64,9 @@ using std::string;
int main(int argc, char** argv) {
const char* host = argc>1 ? argv[1] : "127.0.0.1";
int port = argc>2 ? atoi(argv[2]) : 5672;
+ int count = argc>3 ? atoi(argv[3]) : 10;
+
Connection connection;
- Message message;
try {
connection.open(host, port);
Session session = connection.newSession();
@@ -77,18 +78,17 @@ int main(int argc, char** argv) {
// just once. (In most simple cases, there is no need to set
// other message properties.)
+ Message message;
message.getDeliveryProperties().setRoutingKey("routing_key");
// Now send some messages ...
- for (int i=0; i<10; i++) {
+ for (int i=0; i<count; i++) {
stringstream message_data;
message_data << "Message " << i;
message.setData(message_data.str());
- // Asynchronous transfer sends messages as quickly as
- // possible without waiting for confirmation.
- async(session).messageTransfer(arg::content=message, arg::destination="amq.direct");
+ session.messageTransfer(arg::content=message, arg::destination="amq.direct");
}
// And send a final message to indicate termination.
diff --git a/cpp/examples/direct/listener.cpp b/cpp/examples/direct/listener.cpp
index d199b5c0bb..38bf24ec41 100644
--- a/cpp/examples/direct/listener.cpp
+++ b/cpp/examples/direct/listener.cpp
@@ -20,16 +20,35 @@
*/
/**
- * listener.cpp: This program reads messages from a queue on
- * the broker using a message listener.
+ * listener.cpp:
+ *
+ * This program is one of three programs designed to be used
+ * together.
+ *
+ * create_queues.cpp:
+ *
+ * Creates a queue named "message_queue" on a broker, binding the
+ * queue to the "amq.direct" exchange, using the routing key
+ * "routing_key".
+ *
+ * direct_producer.cpp
+ *
+ * Publishes to the "amq.direct" exchange, specifying the routing
+ * key "routing_key"
+ *
+ * listener.cpp (this program):
+ *
+ * Reads from the "message_queue" queue on the broker using a
+ * message listener.
*/
+
#include <qpid/client/Connection.h>
#include <qpid/client/Session.h>
#include <qpid/client/Message.h>
+#include <qpid/client/MessageListener.h>
#include <qpid/client/SubscriptionManager.h>
-#include <unistd.h>
#include <cstdlib>
#include <iostream>
@@ -60,8 +79,9 @@ void Listener::received(Message& message) {
int main(int argc, char** argv) {
const char* host = argc>1 ? argv[1] : "127.0.0.1";
int port = argc>2 ? atoi(argv[2]) : 5672;
+
Connection connection;
- Message msg;
+
try {
connection.open(host, port);
Session session = connection.newSession();
diff --git a/cpp/examples/direct/verify b/cpp/examples/direct/verify
index ac0464ef80..f598bacc1f 100644
--- a/cpp/examples/direct/verify
+++ b/cpp/examples/direct/verify
@@ -1,3 +1,23 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+
# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
clients ./declare_queues ./direct_producer ./listener
outputs ./declare_queues.out ./direct_producer.out ./listener.out
diff --git a/cpp/examples/examples.sln b/cpp/examples/examples.sln
new file mode 100644
index 0000000000..0501c7f960
--- /dev/null
+++ b/cpp/examples/examples.sln
@@ -0,0 +1,315 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+# $Id: VC9WorkspaceCreator.pm 1439 2008-07-10 14:31:19Z elliott_c $
+#
+# This file was generated by MPC. Any changes made directly to
+# this file will be lost the next time it is generated.
+#
+# MPC Command:
+# C:\ace\MPC\mwc.pl -type vc9 -features boost=1 examples.mwc
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "direct_declare_queues", "direct\direct_declare_queues.vcproj", "{18165D4D-FECA-1BAD-4346-8C4DF2536AA5}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "direct_direct_producer", "direct\direct_direct_producer.vcproj", "{9701E0BD-FECA-1BAD-4346-8C4DF2536AA5}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "direct_listener", "direct\direct_listener.vcproj", "{95CE1459-FECA-1BAD-4346-8C4DF2536AA5}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "failover_declare_queues", "failover\failover_declare_queues.vcproj", "{7817898E-FECA-1BAD-8026-8D997AD361D0}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "failover_replaying_sender", "failover\failover_replaying_sender.vcproj", "{085D6A66-FECA-1BAD-8026-8D997AD361D0}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "failover_resuming_receiver", "failover\failover_resuming_receiver.vcproj", "{B0DAF702-FECA-1BAD-8026-8D997AD361D0}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fanout_fanout_producer", "fanout\fanout_fanout_producer.vcproj", "{972AB76B-FECA-1BAD-8826-8C64F27AA1C5}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fanout_listener", "fanout\fanout_listener.vcproj", "{95E7DF39-FECA-1BAD-8826-8C64F27AA1C5}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "messaging_client", "messaging\messaging_client.vcproj", "{80B58CBC-FECA-1BAD-1FEE-AE349A6B75AA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "messaging_map_receiver", "messaging\messaging_map_receiver.vcproj", "{92D8F5AA-FECA-1BAD-1FEE-AE349A6B75AA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "messaging_map_sender", "messaging\messaging_map_sender.vcproj", "{3B9EA507-FECA-1BAD-1FEE-AE349A6B75AA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "messaging_queue_listener", "messaging\messaging_queue_listener.vcproj", "{7A423237-FECA-1BAD-1FEE-AE349A6B75AA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "messaging_queue_receiver", "messaging\messaging_queue_receiver.vcproj", "{64932FB7-FECA-1BAD-1FEE-AE349A6B75AA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "messaging_queue_sender", "messaging\messaging_queue_sender.vcproj", "{2668EEDD-FECA-1BAD-1FEE-AE349A6B75AA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "messaging_server", "messaging\messaging_server.vcproj", "{E0A50687-FECA-1BAD-1FEE-AE349A6B75AA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "messaging_topic_listener", "messaging\messaging_topic_listener.vcproj", "{7A4686F1-FECA-1BAD-1FEE-AE349A6B75AA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "messaging_topic_receiver", "messaging\messaging_topic_receiver.vcproj", "{64979B71-FECA-1BAD-1FEE-AE349A6B75AA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "messaging_topic_sender", "messaging\messaging_topic_sender.vcproj", "{E068EA69-FECA-1BAD-1FEE-AE349A6B75AA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pub_sub_topic_listener", "pub-sub\pub-sub_topic_listener.vcproj", "{A415E66A-FECA-1BAD-A430-FD5330E23A2D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pub_sub_topic_publisher", "pub-sub\pub-sub_topic_publisher.vcproj", "{05158653-FECA-1BAD-A430-FD5330E23A2D}"
+EndProject
+#Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qmf_agent", "qmf-agent\qmf_agent.vcproj", "{771767FB-FECA-1BAD-2E13-3FFA2B8669C3}"
+#EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qmf-console_console", "qmf-console\qmf-console_console.vcproj", "{490473E1-FECA-1BAD-2E13-3FFA2B8669C3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qmf-console_ping", "qmf-console\qmf-console_ping.vcproj", "{771767FB-FECA-1BAD-2E13-3FFA2B8669C3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qmf-console_printevents", "qmf-console\qmf-console_printevents.vcproj", "{72C74624-FECA-1BAD-2E13-3FFA2B8669C3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qmf-console_queuestats", "qmf-console\qmf-console_queuestats.vcproj", "{B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "request-response_client", "request-response\request-response_client.vcproj", "{2691FE1E-FECA-1BAD-BD3A-8A467D0C5CCC}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "request-response_server", "request-response\request-response_server.vcproj", "{46817425-FECA-1BAD-BD3A-8A467D0C5CCC}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tradedemo_declare_queues", "tradedemo\tradedemo_declare_queues.vcproj", "{9057502D-FECA-1BAD-23CE-CD4095BD3C8B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tradedemo_topic_listener", "tradedemo\tradedemo_topic_listener.vcproj", "{5A25F2CD-FECA-1BAD-23CE-CD4095BD3C8B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tradedemo_topic_publisher", "tradedemo\tradedemo_topic_publisher.vcproj", "{E614CC2C-FECA-1BAD-23CE-CD4095BD3C8B}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {18165D4D-FECA-1BAD-4346-8C4DF2536AA5}.Debug|Win32.ActiveCfg = Debug|Win32
+ {18165D4D-FECA-1BAD-4346-8C4DF2536AA5}.Debug|Win32.Build.0 = Debug|Win32
+ {18165D4D-FECA-1BAD-4346-8C4DF2536AA5}.Debug|x64.ActiveCfg = Debug|x64
+ {18165D4D-FECA-1BAD-4346-8C4DF2536AA5}.Debug|x64.Build.0 = Debug|x64
+ {18165D4D-FECA-1BAD-4346-8C4DF2536AA5}.Release|Win32.ActiveCfg = Release|Win32
+ {18165D4D-FECA-1BAD-4346-8C4DF2536AA5}.Release|Win32.Build.0 = Release|Win32
+ {18165D4D-FECA-1BAD-4346-8C4DF2536AA5}.Release|x64.ActiveCfg = Release|x64
+ {18165D4D-FECA-1BAD-4346-8C4DF2536AA5}.Release|x64.Build.0 = Release|x64
+ {9701E0BD-FECA-1BAD-4346-8C4DF2536AA5}.Debug|Win32.ActiveCfg = Debug|Win32
+ {9701E0BD-FECA-1BAD-4346-8C4DF2536AA5}.Debug|Win32.Build.0 = Debug|Win32
+ {9701E0BD-FECA-1BAD-4346-8C4DF2536AA5}.Debug|x64.ActiveCfg = Debug|x64
+ {9701E0BD-FECA-1BAD-4346-8C4DF2536AA5}.Debug|x64.Build.0 = Debug|x64
+ {9701E0BD-FECA-1BAD-4346-8C4DF2536AA5}.Release|Win32.ActiveCfg = Release|Win32
+ {9701E0BD-FECA-1BAD-4346-8C4DF2536AA5}.Release|Win32.Build.0 = Release|Win32
+ {9701E0BD-FECA-1BAD-4346-8C4DF2536AA5}.Release|x64.ActiveCfg = Release|x64
+ {9701E0BD-FECA-1BAD-4346-8C4DF2536AA5}.Release|x64.Build.0 = Release|x64
+ {95CE1459-FECA-1BAD-4346-8C4DF2536AA5}.Debug|Win32.ActiveCfg = Debug|Win32
+ {95CE1459-FECA-1BAD-4346-8C4DF2536AA5}.Debug|Win32.Build.0 = Debug|Win32
+ {95CE1459-FECA-1BAD-4346-8C4DF2536AA5}.Debug|x64.ActiveCfg = Debug|x64
+ {95CE1459-FECA-1BAD-4346-8C4DF2536AA5}.Debug|x64.Build.0 = Debug|x64
+ {95CE1459-FECA-1BAD-4346-8C4DF2536AA5}.Release|Win32.ActiveCfg = Release|Win32
+ {95CE1459-FECA-1BAD-4346-8C4DF2536AA5}.Release|Win32.Build.0 = Release|Win32
+ {95CE1459-FECA-1BAD-4346-8C4DF2536AA5}.Release|x64.ActiveCfg = Release|x64
+ {95CE1459-FECA-1BAD-4346-8C4DF2536AA5}.Release|x64.Build.0 = Release|x64
+ {7817898E-FECA-1BAD-8026-8D997AD361D0}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7817898E-FECA-1BAD-8026-8D997AD361D0}.Debug|Win32.Build.0 = Debug|Win32
+ {7817898E-FECA-1BAD-8026-8D997AD361D0}.Debug|x64.ActiveCfg = Debug|x64
+ {7817898E-FECA-1BAD-8026-8D997AD361D0}.Debug|x64.Build.0 = Debug|x64
+ {7817898E-FECA-1BAD-8026-8D997AD361D0}.Release|Win32.ActiveCfg = Release|Win32
+ {7817898E-FECA-1BAD-8026-8D997AD361D0}.Release|Win32.Build.0 = Release|Win32
+ {7817898E-FECA-1BAD-8026-8D997AD361D0}.Release|x64.ActiveCfg = Release|x64
+ {7817898E-FECA-1BAD-8026-8D997AD361D0}.Release|x64.Build.0 = Release|x64
+ {085D6A66-FECA-1BAD-8026-8D997AD361D0}.Debug|Win32.ActiveCfg = Debug|Win32
+ {085D6A66-FECA-1BAD-8026-8D997AD361D0}.Debug|Win32.Build.0 = Debug|Win32
+ {085D6A66-FECA-1BAD-8026-8D997AD361D0}.Debug|x64.ActiveCfg = Debug|x64
+ {085D6A66-FECA-1BAD-8026-8D997AD361D0}.Debug|x64.Build.0 = Debug|x64
+ {085D6A66-FECA-1BAD-8026-8D997AD361D0}.Release|Win32.ActiveCfg = Release|Win32
+ {085D6A66-FECA-1BAD-8026-8D997AD361D0}.Release|Win32.Build.0 = Release|Win32
+ {085D6A66-FECA-1BAD-8026-8D997AD361D0}.Release|x64.ActiveCfg = Release|x64
+ {085D6A66-FECA-1BAD-8026-8D997AD361D0}.Release|x64.Build.0 = Release|x64
+ {B0DAF702-FECA-1BAD-8026-8D997AD361D0}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B0DAF702-FECA-1BAD-8026-8D997AD361D0}.Debug|Win32.Build.0 = Debug|Win32
+ {B0DAF702-FECA-1BAD-8026-8D997AD361D0}.Debug|x64.ActiveCfg = Debug|x64
+ {B0DAF702-FECA-1BAD-8026-8D997AD361D0}.Debug|x64.Build.0 = Debug|x64
+ {B0DAF702-FECA-1BAD-8026-8D997AD361D0}.Release|Win32.ActiveCfg = Release|Win32
+ {B0DAF702-FECA-1BAD-8026-8D997AD361D0}.Release|Win32.Build.0 = Release|Win32
+ {B0DAF702-FECA-1BAD-8026-8D997AD361D0}.Release|x64.ActiveCfg = Release|x64
+ {B0DAF702-FECA-1BAD-8026-8D997AD361D0}.Release|x64.Build.0 = Release|x64
+ {972AB76B-FECA-1BAD-8826-8C64F27AA1C5}.Debug|Win32.ActiveCfg = Debug|Win32
+ {972AB76B-FECA-1BAD-8826-8C64F27AA1C5}.Debug|Win32.Build.0 = Debug|Win32
+ {972AB76B-FECA-1BAD-8826-8C64F27AA1C5}.Debug|x64.ActiveCfg = Debug|x64
+ {972AB76B-FECA-1BAD-8826-8C64F27AA1C5}.Debug|x64.Build.0 = Debug|x64
+ {972AB76B-FECA-1BAD-8826-8C64F27AA1C5}.Release|Win32.ActiveCfg = Release|Win32
+ {972AB76B-FECA-1BAD-8826-8C64F27AA1C5}.Release|Win32.Build.0 = Release|Win32
+ {972AB76B-FECA-1BAD-8826-8C64F27AA1C5}.Release|x64.ActiveCfg = Release|x64
+ {972AB76B-FECA-1BAD-8826-8C64F27AA1C5}.Release|x64.Build.0 = Release|x64
+ {95E7DF39-FECA-1BAD-8826-8C64F27AA1C5}.Debug|Win32.ActiveCfg = Debug|Win32
+ {95E7DF39-FECA-1BAD-8826-8C64F27AA1C5}.Debug|Win32.Build.0 = Debug|Win32
+ {95E7DF39-FECA-1BAD-8826-8C64F27AA1C5}.Debug|x64.ActiveCfg = Debug|x64
+ {95E7DF39-FECA-1BAD-8826-8C64F27AA1C5}.Debug|x64.Build.0 = Debug|x64
+ {95E7DF39-FECA-1BAD-8826-8C64F27AA1C5}.Release|Win32.ActiveCfg = Release|Win32
+ {95E7DF39-FECA-1BAD-8826-8C64F27AA1C5}.Release|Win32.Build.0 = Release|Win32
+ {95E7DF39-FECA-1BAD-8826-8C64F27AA1C5}.Release|x64.ActiveCfg = Release|x64
+ {95E7DF39-FECA-1BAD-8826-8C64F27AA1C5}.Release|x64.Build.0 = Release|x64
+ {A415E66A-FECA-1BAD-A430-FD5330E23A2D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {A415E66A-FECA-1BAD-A430-FD5330E23A2D}.Debug|Win32.Build.0 = Debug|Win32
+ {A415E66A-FECA-1BAD-A430-FD5330E23A2D}.Debug|x64.ActiveCfg = Debug|x64
+ {A415E66A-FECA-1BAD-A430-FD5330E23A2D}.Debug|x64.Build.0 = Debug|x64
+ {A415E66A-FECA-1BAD-A430-FD5330E23A2D}.Release|Win32.ActiveCfg = Release|Win32
+ {A415E66A-FECA-1BAD-A430-FD5330E23A2D}.Release|Win32.Build.0 = Release|Win32
+ {A415E66A-FECA-1BAD-A430-FD5330E23A2D}.Release|x64.ActiveCfg = Release|x64
+ {A415E66A-FECA-1BAD-A430-FD5330E23A2D}.Release|x64.Build.0 = Release|x64
+ {80B58CBC-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {80B58CBC-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|Win32.Build.0 = Debug|Win32
+ {80B58CBC-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|x64.ActiveCfg = Debug|x64
+ {80B58CBC-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|x64.Build.0 = Debug|x64
+ {80B58CBC-FECA-1BAD-1FEE-AE349A6B75AA}.Release|Win32.ActiveCfg = Release|Win32
+ {80B58CBC-FECA-1BAD-1FEE-AE349A6B75AA}.Release|Win32.Build.0 = Release|Win32
+ {80B58CBC-FECA-1BAD-1FEE-AE349A6B75AA}.Release|x64.ActiveCfg = Release|x64
+ {80B58CBC-FECA-1BAD-1FEE-AE349A6B75AA}.Release|x64.Build.0 = Release|x64
+ {92D8F5AA-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {92D8F5AA-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|Win32.Build.0 = Debug|Win32
+ {92D8F5AA-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|x64.ActiveCfg = Debug|x64
+ {92D8F5AA-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|x64.Build.0 = Debug|x64
+ {92D8F5AA-FECA-1BAD-1FEE-AE349A6B75AA}.Release|Win32.ActiveCfg = Release|Win32
+ {92D8F5AA-FECA-1BAD-1FEE-AE349A6B75AA}.Release|Win32.Build.0 = Release|Win32
+ {92D8F5AA-FECA-1BAD-1FEE-AE349A6B75AA}.Release|x64.ActiveCfg = Release|x64
+ {92D8F5AA-FECA-1BAD-1FEE-AE349A6B75AA}.Release|x64.Build.0 = Release|x64
+ {3B9EA507-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3B9EA507-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|Win32.Build.0 = Debug|Win32
+ {3B9EA507-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|x64.ActiveCfg = Debug|x64
+ {3B9EA507-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|x64.Build.0 = Debug|x64
+ {3B9EA507-FECA-1BAD-1FEE-AE349A6B75AA}.Release|Win32.ActiveCfg = Release|Win32
+ {3B9EA507-FECA-1BAD-1FEE-AE349A6B75AA}.Release|Win32.Build.0 = Release|Win32
+ {3B9EA507-FECA-1BAD-1FEE-AE349A6B75AA}.Release|x64.ActiveCfg = Release|x64
+ {3B9EA507-FECA-1BAD-1FEE-AE349A6B75AA}.Release|x64.Build.0 = Release|x64
+ {7A423237-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7A423237-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|Win32.Build.0 = Debug|Win32
+ {7A423237-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|x64.ActiveCfg = Debug|x64
+ {7A423237-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|x64.Build.0 = Debug|x64
+ {7A423237-FECA-1BAD-1FEE-AE349A6B75AA}.Release|Win32.ActiveCfg = Release|Win32
+ {7A423237-FECA-1BAD-1FEE-AE349A6B75AA}.Release|Win32.Build.0 = Release|Win32
+ {7A423237-FECA-1BAD-1FEE-AE349A6B75AA}.Release|x64.ActiveCfg = Release|x64
+ {7A423237-FECA-1BAD-1FEE-AE349A6B75AA}.Release|x64.Build.0 = Release|x64
+ {64932FB7-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {64932FB7-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|Win32.Build.0 = Debug|Win32
+ {64932FB7-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|x64.ActiveCfg = Debug|x64
+ {64932FB7-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|x64.Build.0 = Debug|x64
+ {64932FB7-FECA-1BAD-1FEE-AE349A6B75AA}.Release|Win32.ActiveCfg = Release|Win32
+ {64932FB7-FECA-1BAD-1FEE-AE349A6B75AA}.Release|Win32.Build.0 = Release|Win32
+ {64932FB7-FECA-1BAD-1FEE-AE349A6B75AA}.Release|x64.ActiveCfg = Release|x64
+ {64932FB7-FECA-1BAD-1FEE-AE349A6B75AA}.Release|x64.Build.0 = Release|x64
+ {2668EEDD-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2668EEDD-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|Win32.Build.0 = Debug|Win32
+ {2668EEDD-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|x64.ActiveCfg = Debug|x64
+ {2668EEDD-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|x64.Build.0 = Debug|x64
+ {2668EEDD-FECA-1BAD-1FEE-AE349A6B75AA}.Release|Win32.ActiveCfg = Release|Win32
+ {2668EEDD-FECA-1BAD-1FEE-AE349A6B75AA}.Release|Win32.Build.0 = Release|Win32
+ {2668EEDD-FECA-1BAD-1FEE-AE349A6B75AA}.Release|x64.ActiveCfg = Release|x64
+ {2668EEDD-FECA-1BAD-1FEE-AE349A6B75AA}.Release|x64.Build.0 = Release|x64
+ {E0A50687-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E0A50687-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|Win32.Build.0 = Debug|Win32
+ {E0A50687-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|x64.ActiveCfg = Debug|x64
+ {E0A50687-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|x64.Build.0 = Debug|x64
+ {E0A50687-FECA-1BAD-1FEE-AE349A6B75AA}.Release|Win32.ActiveCfg = Release|Win32
+ {E0A50687-FECA-1BAD-1FEE-AE349A6B75AA}.Release|Win32.Build.0 = Release|Win32
+ {E0A50687-FECA-1BAD-1FEE-AE349A6B75AA}.Release|x64.ActiveCfg = Release|x64
+ {E0A50687-FECA-1BAD-1FEE-AE349A6B75AA}.Release|x64.Build.0 = Release|x64
+ {7A4686F1-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7A4686F1-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|Win32.Build.0 = Debug|Win32
+ {7A4686F1-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|x64.ActiveCfg = Debug|x64
+ {7A4686F1-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|x64.Build.0 = Debug|x64
+ {7A4686F1-FECA-1BAD-1FEE-AE349A6B75AA}.Release|Win32.ActiveCfg = Release|Win32
+ {7A4686F1-FECA-1BAD-1FEE-AE349A6B75AA}.Release|Win32.Build.0 = Release|Win32
+ {7A4686F1-FECA-1BAD-1FEE-AE349A6B75AA}.Release|x64.ActiveCfg = Release|x64
+ {7A4686F1-FECA-1BAD-1FEE-AE349A6B75AA}.Release|x64.Build.0 = Release|x64
+ {64979B71-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {64979B71-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|Win32.Build.0 = Debug|Win32
+ {64979B71-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|x64.ActiveCfg = Debug|x64
+ {64979B71-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|x64.Build.0 = Debug|x64
+ {64979B71-FECA-1BAD-1FEE-AE349A6B75AA}.Release|Win32.ActiveCfg = Release|Win32
+ {64979B71-FECA-1BAD-1FEE-AE349A6B75AA}.Release|Win32.Build.0 = Release|Win32
+ {64979B71-FECA-1BAD-1FEE-AE349A6B75AA}.Release|x64.ActiveCfg = Release|x64
+ {64979B71-FECA-1BAD-1FEE-AE349A6B75AA}.Release|x64.Build.0 = Release|x64
+ {E068EA69-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E068EA69-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|Win32.Build.0 = Debug|Win32
+ {E068EA69-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|x64.ActiveCfg = Debug|x64
+ {E068EA69-FECA-1BAD-1FEE-AE349A6B75AA}.Debug|x64.Build.0 = Debug|x64
+ {E068EA69-FECA-1BAD-1FEE-AE349A6B75AA}.Release|Win32.ActiveCfg = Release|Win32
+ {E068EA69-FECA-1BAD-1FEE-AE349A6B75AA}.Release|Win32.Build.0 = Release|Win32
+ {E068EA69-FECA-1BAD-1FEE-AE349A6B75AA}.Release|x64.ActiveCfg = Release|x64
+ {E068EA69-FECA-1BAD-1FEE-AE349A6B75AA}.Release|x64.Build.0 = Release|x64
+ {05158653-FECA-1BAD-A430-FD5330E23A2D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {05158653-FECA-1BAD-A430-FD5330E23A2D}.Debug|Win32.Build.0 = Debug|Win32
+ {05158653-FECA-1BAD-A430-FD5330E23A2D}.Debug|x64.ActiveCfg = Debug|x64
+ {05158653-FECA-1BAD-A430-FD5330E23A2D}.Debug|x64.Build.0 = Debug|x64
+ {05158653-FECA-1BAD-A430-FD5330E23A2D}.Release|Win32.ActiveCfg = Release|Win32
+ {05158653-FECA-1BAD-A430-FD5330E23A2D}.Release|Win32.Build.0 = Release|Win32
+ {05158653-FECA-1BAD-A430-FD5330E23A2D}.Release|x64.ActiveCfg = Release|x64
+ {05158653-FECA-1BAD-A430-FD5330E23A2D}.Release|x64.Build.0 = Release|x64
+ {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.Build.0 = Debug|Win32
+ {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|x64.ActiveCfg = Debug|x64
+ {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|x64.Build.0 = Debug|x64
+ {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.ActiveCfg = Release|Win32
+ {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.Build.0 = Release|Win32
+ {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Release|x64.ActiveCfg = Release|x64
+ {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Release|x64.Build.0 = Release|x64
+ {771767FB-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {771767FB-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.Build.0 = Debug|Win32
+ {771767FB-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|x64.ActiveCfg = Debug|x64
+ {771767FB-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|x64.Build.0 = Debug|x64
+ {771767FB-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.ActiveCfg = Release|Win32
+ {771767FB-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.Build.0 = Release|Win32
+ {771767FB-FECA-1BAD-2E13-3FFA2B8669C3}.Release|x64.ActiveCfg = Release|x64
+ {771767FB-FECA-1BAD-2E13-3FFA2B8669C3}.Release|x64.Build.0 = Release|x64
+ {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.Build.0 = Debug|Win32
+ {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|x64.ActiveCfg = Debug|x64
+ {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|x64.Build.0 = Debug|x64
+ {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.ActiveCfg = Release|Win32
+ {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.Build.0 = Release|Win32
+ {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Release|x64.ActiveCfg = Release|x64
+ {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Release|x64.Build.0 = Release|x64
+ {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.Build.0 = Debug|Win32
+ {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|x64.ActiveCfg = Debug|x64
+ {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|x64.Build.0 = Debug|x64
+ {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.ActiveCfg = Release|Win32
+ {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.Build.0 = Release|Win32
+ {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Release|x64.ActiveCfg = Release|x64
+ {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Release|x64.Build.0 = Release|x64
+ {2691FE1E-FECA-1BAD-BD3A-8A467D0C5CCC}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2691FE1E-FECA-1BAD-BD3A-8A467D0C5CCC}.Debug|Win32.Build.0 = Debug|Win32
+ {2691FE1E-FECA-1BAD-BD3A-8A467D0C5CCC}.Debug|x64.ActiveCfg = Debug|x64
+ {2691FE1E-FECA-1BAD-BD3A-8A467D0C5CCC}.Debug|x64.Build.0 = Debug|x64
+ {2691FE1E-FECA-1BAD-BD3A-8A467D0C5CCC}.Release|Win32.ActiveCfg = Release|Win32
+ {2691FE1E-FECA-1BAD-BD3A-8A467D0C5CCC}.Release|Win32.Build.0 = Release|Win32
+ {2691FE1E-FECA-1BAD-BD3A-8A467D0C5CCC}.Release|x64.ActiveCfg = Release|x64
+ {2691FE1E-FECA-1BAD-BD3A-8A467D0C5CCC}.Release|x64.Build.0 = Release|x64
+ {46817425-FECA-1BAD-BD3A-8A467D0C5CCC}.Debug|Win32.ActiveCfg = Debug|Win32
+ {46817425-FECA-1BAD-BD3A-8A467D0C5CCC}.Debug|Win32.Build.0 = Debug|Win32
+ {46817425-FECA-1BAD-BD3A-8A467D0C5CCC}.Debug|x64.ActiveCfg = Debug|x64
+ {46817425-FECA-1BAD-BD3A-8A467D0C5CCC}.Debug|x64.Build.0 = Debug|x64
+ {46817425-FECA-1BAD-BD3A-8A467D0C5CCC}.Release|Win32.ActiveCfg = Release|Win32
+ {46817425-FECA-1BAD-BD3A-8A467D0C5CCC}.Release|Win32.Build.0 = Release|Win32
+ {46817425-FECA-1BAD-BD3A-8A467D0C5CCC}.Release|x64.ActiveCfg = Release|x64
+ {46817425-FECA-1BAD-BD3A-8A467D0C5CCC}.Release|x64.Build.0 = Release|x64
+ {9057502D-FECA-1BAD-23CE-CD4095BD3C8B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {9057502D-FECA-1BAD-23CE-CD4095BD3C8B}.Debug|Win32.Build.0 = Debug|Win32
+ {9057502D-FECA-1BAD-23CE-CD4095BD3C8B}.Debug|x64.ActiveCfg = Debug|x64
+ {9057502D-FECA-1BAD-23CE-CD4095BD3C8B}.Debug|x64.Build.0 = Debug|x64
+ {9057502D-FECA-1BAD-23CE-CD4095BD3C8B}.Release|Win32.ActiveCfg = Release|Win32
+ {9057502D-FECA-1BAD-23CE-CD4095BD3C8B}.Release|Win32.Build.0 = Release|Win32
+ {9057502D-FECA-1BAD-23CE-CD4095BD3C8B}.Release|x64.ActiveCfg = Release|x64
+ {9057502D-FECA-1BAD-23CE-CD4095BD3C8B}.Release|x64.Build.0 = Release|x64
+ {5A25F2CD-FECA-1BAD-23CE-CD4095BD3C8B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5A25F2CD-FECA-1BAD-23CE-CD4095BD3C8B}.Debug|Win32.Build.0 = Debug|Win32
+ {5A25F2CD-FECA-1BAD-23CE-CD4095BD3C8B}.Debug|x64.ActiveCfg = Debug|x64
+ {5A25F2CD-FECA-1BAD-23CE-CD4095BD3C8B}.Debug|x64.Build.0 = Debug|x64
+ {5A25F2CD-FECA-1BAD-23CE-CD4095BD3C8B}.Release|Win32.ActiveCfg = Release|Win32
+ {5A25F2CD-FECA-1BAD-23CE-CD4095BD3C8B}.Release|Win32.Build.0 = Release|Win32
+ {5A25F2CD-FECA-1BAD-23CE-CD4095BD3C8B}.Release|x64.ActiveCfg = Release|x64
+ {5A25F2CD-FECA-1BAD-23CE-CD4095BD3C8B}.Release|x64.Build.0 = Release|x64
+ {E614CC2C-FECA-1BAD-23CE-CD4095BD3C8B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E614CC2C-FECA-1BAD-23CE-CD4095BD3C8B}.Debug|Win32.Build.0 = Debug|Win32
+ {E614CC2C-FECA-1BAD-23CE-CD4095BD3C8B}.Debug|x64.ActiveCfg = Debug|x64
+ {E614CC2C-FECA-1BAD-23CE-CD4095BD3C8B}.Debug|x64.Build.0 = Debug|x64
+ {E614CC2C-FECA-1BAD-23CE-CD4095BD3C8B}.Release|Win32.ActiveCfg = Release|Win32
+ {E614CC2C-FECA-1BAD-23CE-CD4095BD3C8B}.Release|Win32.Build.0 = Release|Win32
+ {E614CC2C-FECA-1BAD-23CE-CD4095BD3C8B}.Release|x64.ActiveCfg = Release|x64
+ {E614CC2C-FECA-1BAD-23CE-CD4095BD3C8B}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/cpp/examples/failover/CMakeLists.txt b/cpp/examples/failover/CMakeLists.txt
new file mode 100644
index 0000000000..05db8fad51
--- /dev/null
+++ b/cpp/examples/failover/CMakeLists.txt
@@ -0,0 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+add_example(failover declare_queues)
+add_example(failover resuming_receiver)
+add_example(failover replaying_sender)
diff --git a/cpp/examples/failover/Makefile.am b/cpp/examples/failover/Makefile.am
new file mode 100644
index 0000000000..48846fdf79
--- /dev/null
+++ b/cpp/examples/failover/Makefile.am
@@ -0,0 +1,47 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+examplesdir=$(pkgdatadir)/examples/failover
+
+MAKELDFLAGS=$(CLIENTFLAGS)
+include $(top_srcdir)/examples/makedist.mk
+
+noinst_PROGRAMS=declare_queues resuming_receiver replaying_sender
+
+declare_queues_SOURCES=declare_queues.cpp
+declare_queues_LDADD=$(CLIENT_LIB)
+
+resuming_receiver_SOURCES=resuming_receiver.cpp
+resuming_receiver_LDADD=$(CLIENT_LIB)
+
+replaying_sender_SOURCES=replaying_sender.cpp
+replaying_sender_LDADD=$(CLIENT_LIB)
+
+examples_DATA= \
+ declare_queues.cpp \
+ resuming_receiver.cpp \
+ replaying_sender.cpp \
+ $(MAKEDIST)
+
+# FIXME aconway 2008-10-10: add verify scripts.
+
+EXTRA_DIST= \
+ CMakeLists.txt \
+ failover_declare_queues.vcproj \
+ failover_replaying_sender.vcproj \
+ failover_resuming_receiver.vcproj
diff --git a/cpp/examples/failover/declare_queues.cpp b/cpp/examples/failover/declare_queues.cpp
new file mode 100644
index 0000000000..a677870c53
--- /dev/null
+++ b/cpp/examples/failover/declare_queues.cpp
@@ -0,0 +1,61 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/client/FailoverManager.h>
+#include <qpid/client/Session.h>
+#include <qpid/Exception.h>
+
+#include <cstdlib>
+#include <iostream>
+
+using namespace qpid::client;
+
+using namespace std;
+
+int main(int argc, char ** argv)
+{
+ ConnectionSettings settings;
+ if (argc > 1) settings.host = argv[1];
+ if (argc > 2) settings.port = atoi(argv[2]);
+
+ FailoverManager connection(settings);
+ try {
+ bool complete = false;
+ while (!complete) {
+ Session session = connection.connect().newSession();
+ try {
+ session.queueDeclare(arg::queue="message_queue");
+ complete = true;
+ } catch (const qpid::TransportFailure&) {}
+ }
+ connection.close();
+ return 0;
+ } catch (const std::exception& error) {
+ std::cout << "Failed:" << error.what() << std::endl;
+ return 1;
+ }
+
+}
+
+
+
+
+
diff --git a/cpp/examples/failover/failover_declare_queues.vcproj b/cpp/examples/failover/failover_declare_queues.vcproj
new file mode 100644
index 0000000000..d838083404
--- /dev/null
+++ b/cpp/examples/failover/failover_declare_queues.vcproj
@@ -0,0 +1,394 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="failover_declare_queues"
+ ProjectGUID="{7817898E-FECA-1BAD-8026-8D997AD361D0}"
+ RootNamespace="failover_declare_queues"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\failover_declare_queues\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\declare_queues.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\failover_declare_queues\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\declare_queues.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\failover_declare_queues\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\declare_queues.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\failover_declare_queues\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\declare_queues.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="declare_queues.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="ConnectionOptions.h">
+ </File>
+ <File
+ RelativePath="TestOptions.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/failover/failover_replaying_sender.vcproj b/cpp/examples/failover/failover_replaying_sender.vcproj
new file mode 100644
index 0000000000..06d7ad53cc
--- /dev/null
+++ b/cpp/examples/failover/failover_replaying_sender.vcproj
@@ -0,0 +1,394 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="failover_replaying_sender"
+ ProjectGUID="{085D6A66-FECA-1BAD-8026-8D997AD361D0}"
+ RootNamespace="failover_replaying_sender"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\failover_replaying_sender\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\replaying_sender.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\failover_replaying_sender\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\replaying_sender.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\failover_replaying_sender\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\replaying_sender.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\failover_replaying_sender\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\replaying_sender.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="replaying_sender.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="ConnectionOptions.h">
+ </File>
+ <File
+ RelativePath="TestOptions.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/failover/failover_resuming_receiver.vcproj b/cpp/examples/failover/failover_resuming_receiver.vcproj
new file mode 100644
index 0000000000..34802aa755
--- /dev/null
+++ b/cpp/examples/failover/failover_resuming_receiver.vcproj
@@ -0,0 +1,394 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="failover_resuming_receiver"
+ ProjectGUID="{B0DAF702-FECA-1BAD-8026-8D997AD361D0}"
+ RootNamespace="failover_resuming_receiver"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\failover_resuming_receiver\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\resuming_receiver.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\failover_resuming_receiver\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\resuming_receiver.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\failover_resuming_receiver\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\resuming_receiver.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\failover_resuming_receiver\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\resuming_receiver.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="resuming_receiver.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="ConnectionOptions.h">
+ </File>
+ <File
+ RelativePath="TestOptions.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/failover/replaying_sender.cpp b/cpp/examples/failover/replaying_sender.cpp
new file mode 100644
index 0000000000..22a7e1ebd3
--- /dev/null
+++ b/cpp/examples/failover/replaying_sender.cpp
@@ -0,0 +1,97 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/client/FailoverManager.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/AsyncSession.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/MessageReplayTracker.h>
+#include <qpid/Exception.h>
+
+#include <iostream>
+#include <sstream>
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using namespace std;
+
+class Sender : public FailoverManager::Command
+{
+ public:
+ Sender(const std::string& queue, uint count);
+ void execute(AsyncSession& session, bool isRetry);
+ uint getSent();
+ private:
+ MessageReplayTracker sender;
+ const uint count;
+ uint sent;
+ Message message;
+
+};
+
+Sender::Sender(const std::string& queue, uint count_) : sender(10), count(count_), sent(0)
+{
+ message.getDeliveryProperties().setRoutingKey(queue);
+}
+
+void Sender::execute(AsyncSession& session, bool isRetry)
+{
+ if (isRetry) sender.replay(session);
+ else sender.init(session);
+ while (sent < count) {
+ stringstream message_data;
+ message_data << ++sent;
+ message.setData(message_data.str());
+ message.getHeaders().setInt("sn", sent);
+ sender.send(message);
+ if (count > 1000 && !(sent % 1000)) {
+ std::cout << "sent " << sent << " of " << count << std::endl;
+ }
+ }
+ message.setData("That's all, folks!");
+ sender.send(message);
+}
+
+uint Sender::getSent()
+{
+ return sent;
+}
+
+int main(int argc, char ** argv)
+{
+ ConnectionSettings settings;
+ if (argc > 1) settings.host = argv[1];
+ if (argc > 2) settings.port = atoi(argv[2]);
+
+ FailoverManager connection(settings);
+ Sender sender("message_queue", argc > 3 ? atoi(argv[3]) : 1000);
+ try {
+ connection.execute(sender);
+ std::cout << "Sent " << sender.getSent() << " messages." << std::endl;
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << "Failed: " << error.what() << std::endl;
+ }
+ return 1;
+}
diff --git a/cpp/examples/failover/resuming_receiver.cpp b/cpp/examples/failover/resuming_receiver.cpp
new file mode 100644
index 0000000000..d1886ce861
--- /dev/null
+++ b/cpp/examples/failover/resuming_receiver.cpp
@@ -0,0 +1,127 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/client/FailoverManager.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/SubscriptionManager.h>
+
+#include <iostream>
+#include <fstream>
+
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using namespace std;
+
+
+class Listener : public MessageListener,
+ public FailoverManager::Command,
+ public FailoverManager::ReconnectionStrategy
+{
+ public:
+ Listener();
+ void received(Message& message);
+ void execute(AsyncSession& session, bool isRetry);
+ void check();
+ void editUrlList(std::vector<Url>& urls);
+ private:
+ Subscription subscription;
+ uint count;
+ uint skipped;
+ uint lastSn;
+ bool gaps;
+};
+
+Listener::Listener() : count(0), skipped(0), lastSn(0), gaps(false) {}
+
+void Listener::received(Message & message)
+{
+ if (message.getData() == "That's all, folks!") {
+ std::cout << "Shutting down listener for " << message.getDestination()
+ << std::endl;
+
+ std::cout << "Listener received " << count << " messages (" << skipped << " skipped)" << std::endl;
+ subscription.cancel();
+ } else {
+ uint sn = message.getHeaders().getAsInt("sn");
+ if (lastSn < sn) {
+ if (sn - lastSn > 1) {
+ std::cout << "Error: gap in sequence between " << lastSn << " and " << sn << std::endl;
+ gaps = true;
+ }
+ lastSn = sn;
+ ++count;
+ } else {
+ ++skipped;
+ }
+ }
+}
+
+void Listener::check()
+{
+ if (gaps) throw Exception("Detected gaps in sequence; messages appear to have been lost.");
+}
+
+void Listener::execute(AsyncSession& session, bool isRetry)
+{
+ if (isRetry) {
+ std::cout << "Resuming from " << count << std::endl;
+ }
+ SubscriptionManager subs(session);
+ subscription = subs.subscribe(*this, "message_queue");
+ subs.run();
+}
+
+void Listener::editUrlList(std::vector<Url>& urls)
+{
+ /**
+ * A more realistic algorithm would be to search through the list
+ * for prefered hosts and ensure they come first in the list.
+ */
+ if (urls.size() > 1) std::rotate(urls.begin(), urls.begin() + 1, urls.end());
+}
+
+int main(int argc, char ** argv)
+{
+ ConnectionSettings settings;
+ if (argc > 1) settings.host = argv[1];
+ if (argc > 2) settings.port = atoi(argv[2]);
+
+ Listener listener;
+ FailoverManager connection(settings, &listener);
+
+ try {
+ connection.execute(listener);
+ connection.close();
+ listener.check();
+ std::cout << "Completed without error." << std::endl;
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << "Failure: " << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
+
diff --git a/cpp/examples/fanout/CMakeLists.txt b/cpp/examples/fanout/CMakeLists.txt
new file mode 100644
index 0000000000..3f89d67650
--- /dev/null
+++ b/cpp/examples/fanout/CMakeLists.txt
@@ -0,0 +1,21 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+add_example(fanout fanout_producer)
+add_example(fanout listener)
diff --git a/cpp/examples/fanout/Makefile.am b/cpp/examples/fanout/Makefile.am
index 83cda09cf4..bfa5404e5b 100644
--- a/cpp/examples/fanout/Makefile.am
+++ b/cpp/examples/fanout/Makefile.am
@@ -1,5 +1,24 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
examplesdir=$(pkgdatadir)/examples/fanout
+MAKELDFLAGS=$(CLIENTFLAGS)
include $(top_srcdir)/examples/makedist.mk
noinst_PROGRAMS=fanout_producer listener
@@ -16,14 +35,12 @@ examples_DATA= \
EXTRA_DIST= \
$(examples_DATA) \
+ CMakeLists.txt \
verify \
verify.in \
verify_cpp_python \
verify_cpp_python.in \
verify_python_cpp \
- verify_python_cpp.in
-
-
-
-
-
+ verify_python_cpp.in \
+ fanout_fanout_producer.vcproj \
+ fanout_listener.vcproj
diff --git a/cpp/examples/fanout/fanout_fanout_producer.vcproj b/cpp/examples/fanout/fanout_fanout_producer.vcproj
new file mode 100644
index 0000000000..10542b7a4e
--- /dev/null
+++ b/cpp/examples/fanout/fanout_fanout_producer.vcproj
@@ -0,0 +1,394 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="fanout_fanout_producer"
+ ProjectGUID="{972AB76B-FECA-1BAD-8826-8C64F27AA1C5}"
+ RootNamespace="fanout_fanout_producer"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\fanout_fanout_producer\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\fanout_producer.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\fanout_fanout_producer\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\fanout_producer.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\fanout_fanout_producer\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\fanout_producer.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\fanout_fanout_producer\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\fanout_producer.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="fanout_producer.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="ConnectionOptions.h">
+ </File>
+ <File
+ RelativePath="TestOptions.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/fanout/fanout_listener.vcproj b/cpp/examples/fanout/fanout_listener.vcproj
new file mode 100644
index 0000000000..23bdf58b9e
--- /dev/null
+++ b/cpp/examples/fanout/fanout_listener.vcproj
@@ -0,0 +1,394 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="fanout_listener"
+ ProjectGUID="{95E7DF39-FECA-1BAD-8826-8C64F27AA1C5}"
+ RootNamespace="fanout_listener"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\fanout_listener\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\listener.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\fanout_listener\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\listener.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\fanout_listener\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\listener.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\fanout_listener\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\listener.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="listener.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="ConnectionOptions.h">
+ </File>
+ <File
+ RelativePath="TestOptions.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/fanout/fanout_producer.cpp b/cpp/examples/fanout/fanout_producer.cpp
index a1ca407847..decd4d314d 100644
--- a/cpp/examples/fanout/fanout_producer.cpp
+++ b/cpp/examples/fanout/fanout_producer.cpp
@@ -23,22 +23,21 @@
/**
* fanout_producer.cpp:
*
- * This program is one of three programs designed to be used
- * together. These programs do not specify the exchange type - the
- * default exchange type is the direct exchange.
- *
- * declare_queues.cpp:
- *
- * Creates a queue on a broker, binding a routing key to route
- * messages to that queue.
+ * This program is one of two programs designed to be used
+ * together.
*
* fanout_producer.cpp (this program):
*
- * Publishes to a broker, specifying a routing key.
+ * Publishes messages to the "amq.fanout" exchange.
*
* listener.cpp
*
- * Reads from a queue on the broker using a message listener.
+ * Creates a private queue, binds it to the "amq.fanout"
+ * exchange, and reads messages from its queue as they
+ * arrive. Messages sent before the listener binds the queue are
+ * not received.
+ *
+ * Multiple listeners can run at the same time.
*
*/
@@ -49,7 +48,6 @@
#include <qpid/client/Message.h>
-#include <unistd.h>
#include <cstdlib>
#include <iostream>
@@ -64,8 +62,8 @@ using std::string;
int main(int argc, char** argv) {
const char* host = argc>1 ? argv[1] : "127.0.0.1";
int port = argc>2 ? atoi(argv[2]) : 5672;
+
Connection connection;
- Message message;
try {
connection.open(host, port);
Session session = connection.newSession();
@@ -92,7 +90,7 @@ int main(int argc, char** argv) {
// And send a final message to indicate termination.
message.setData("That's all, folks!");
- session.messageTransfer(arg::content=message, arg::destination="amq.fanout");
+ session.messageTransfer(arg::content=message, arg::destination="amq.fanout");
//-----------------------------------------------------------------------------
diff --git a/cpp/examples/fanout/listener.cpp b/cpp/examples/fanout/listener.cpp
index b29c82d3d9..cd3071c29a 100644
--- a/cpp/examples/fanout/listener.cpp
+++ b/cpp/examples/fanout/listener.cpp
@@ -19,17 +19,35 @@
*
*/
+
/**
- * listener.cpp: This program reads messages fro a queue on
- * the broker using a message listener.
+ * listener.cpp
+ *
+ * This program is one of two programs designed to be used
+ * together.
+ *
+ * fanout_producer.cpp
+ *
+ * Publishes messages to the "amq.fanout" exchange.
+ *
+ * listener.cpp (this program)
+ *
+ * Creates a private queue, binds it to the "amq.fanout"
+ * exchange, and reads messages from its queue as they
+ * arrive. Messages sent before the listener binds the queue are
+ * not received.
+ *
+ * Multiple listeners can run at the same time.
+ *
*/
+
#include <qpid/client/Connection.h>
#include <qpid/client/Session.h>
#include <qpid/client/Message.h>
+#include <qpid/client/MessageListener.h>
#include <qpid/client/SubscriptionManager.h>
-#include <unistd.h>
#include <cstdlib>
#include <iostream>
@@ -60,8 +78,8 @@ void Listener::received(Message& message) {
int main(int argc, char** argv) {
const char* host = argc>1 ? argv[1] : "127.0.0.1";
int port = argc>2 ? atoi(argv[2]) : 5672;
+
Connection connection;
- Message msg;
try {
connection.open(host, port);
Session session = connection.newSession();
diff --git a/cpp/examples/fanout/verify b/cpp/examples/fanout/verify
index ace4a6dfee..2eaadff56b 100644
--- a/cpp/examples/fanout/verify
+++ b/cpp/examples/fanout/verify
@@ -1,3 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
background "Listening" ./listener
background "Listening" ./listener
diff --git a/cpp/examples/makedist.mk b/cpp/examples/makedist.mk
index f579dca1e3..0a7f18de76 100644
--- a/cpp/examples/makedist.mk
+++ b/cpp/examples/makedist.mk
@@ -1,20 +1,23 @@
# Settings to build the examples in automake
AM_CXXFLAGS = $(WARNING_CFLAGS)
-INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/src/gen -I$(top_builddir)/src -I$(top_builddir)/src/gen
+INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include
CLIENT_LIB=$(top_builddir)/src/libqpidclient.la
+CONSOLE_LIB=$(top_builddir)/src/libqmfconsole.la
+CLIENTFLAGS=-lqpidclient
+CONSOLEFLAGS=-lqmfconsole
# Generate a simple non-automake Makefile for distribution.
MAKEDIST=.libs/Makefile
$(MAKEDIST): Makefile
mkdir -p .libs
- @$(ECHO) CXX=$(CXX) > $(MAKEDIST)
- @$(ECHO) CXXFLAGS=$(CXXFLAGS) >> $(MAKEDIST)
- @$(ECHO) LDFLAGS=-lqpidclient >> $(MAKEDIST)
- @$(ECHO) >> $(MAKEDIST)
- @$(ECHO) all: $(noinst_PROGRAMS) >> $(MAKEDIST)
- @$(ECHO) >> $(MAKEDIST)
- @$(ECHO) clean: >> $(MAKEDIST)
- @$(ECHO) " rm -f $(noinst_PROGRAMS)" >> $(MAKEDIST)
-
+ @(echo CXX=$(CXX) ; \
+ echo CXXFLAGS=$(CXXFLAGS) ; \
+ echo LDFLAGS=$(MAKELDFLAGS) ; \
+ echo ; \
+ echo all: $(noinst_PROGRAMS) ; \
+ echo ; \
+ echo clean: ; \
+ echo " rm -f $(noinst_PROGRAMS)" ; \
+ ) > $(MAKEDIST)
diff --git a/cpp/examples/messaging/CMakeLists.txt b/cpp/examples/messaging/CMakeLists.txt
new file mode 100644
index 0000000000..b2b2bc3e43
--- /dev/null
+++ b/cpp/examples/messaging/CMakeLists.txt
@@ -0,0 +1,35 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# drain and spout have explicit Boost.program_options usage in them, so be
+# sure that lib is linked in.
+add_example(messaging drain ${Boost_PROGRAM_OPTIONS_LIBRARY})
+add_example(messaging spout ${Boost_PROGRAM_OPTIONS_LIBRARY})
+
+add_example(messaging queue_receiver)
+add_example(messaging queue_sender)
+
+add_example(messaging topic_receiver)
+add_example(messaging topic_sender)
+
+add_example(messaging map_receiver)
+add_example(messaging map_sender)
+
+add_example(messaging client)
+add_example(messaging server)
diff --git a/cpp/examples/messaging/Makefile.am b/cpp/examples/messaging/Makefile.am
new file mode 100644
index 0000000000..85d1956e61
--- /dev/null
+++ b/cpp/examples/messaging/Makefile.am
@@ -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.
+#
+examplesdir=$(pkgdatadir)/examples/messaging
+
+MAKELDFLAGS=$(CLIENTFLAGS)
+include $(top_srcdir)/examples/makedist.mk
+
+noinst_PROGRAMS=drain spout queue_sender queue_receiver topic_sender topic_receiver client server map_sender map_receiver
+
+drain_SOURCES=drain.cpp
+drain_LDADD=$(CLIENT_LIB)
+
+spout_SOURCES=spout.cpp
+spout_LDADD=$(CLIENT_LIB)
+
+queue_sender_SOURCES=queue_sender.cpp
+queue_sender_LDADD=$(CLIENT_LIB)
+
+queue_receiver_SOURCES=queue_receiver.cpp
+queue_receiver_LDADD=$(CLIENT_LIB)
+
+topic_sender_SOURCES=topic_sender.cpp
+topic_sender_LDADD=$(CLIENT_LIB)
+
+topic_receiver_SOURCES=topic_receiver.cpp
+topic_receiver_LDADD=$(CLIENT_LIB)
+
+client_SOURCES=client.cpp
+client_LDADD=$(CLIENT_LIB)
+
+server_SOURCES=server.cpp
+server_LDADD=$(CLIENT_LIB)
+
+map_sender_SOURCES=map_sender.cpp
+map_sender_LDADD=$(CLIENT_LIB)
+
+map_receiver_SOURCES=map_receiver.cpp
+map_receiver_LDADD=$(CLIENT_LIB)
+
+EXTRA_DIST= \
+ CMakeLists.txt \
+ messaging_client.vcproj \
+ messaging_map_receiver.vcproj \
+ messaging_map_sender.vcproj \
+ messaging_queue_listener.vcproj \
+ messaging_queue_receiver.vcproj \
+ messaging_queue_sender.vcproj \
+ messaging_server.vcproj \
+ messaging_topic_listener.vcproj \
+ messaging_topic_receiver.vcproj \
+ messaging_topic_sender.vcproj
diff --git a/cpp/examples/messaging/client.cpp b/cpp/examples/messaging/client.cpp
new file mode 100644
index 0000000000..49d5441bf0
--- /dev/null
+++ b/cpp/examples/messaging/client.cpp
@@ -0,0 +1,76 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/messaging/Address.h>
+#include <qpid/messaging/Connection.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/Receiver.h>
+#include <qpid/messaging/Sender.h>
+#include <qpid/messaging/Session.h>
+
+#include <cstdlib>
+#include <iostream>
+
+#include <sstream>
+
+using namespace qpid::messaging;
+
+using std::stringstream;
+using std::string;
+
+int main(int argc, char** argv) {
+ const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
+
+ try {
+ Connection connection = Connection::open(url);
+ Session session = connection.newSession();
+
+ Sender sender = session.createSender("service_queue");
+
+ //create temp queue & receiver...
+ Address responseQueue("#response-queue; {create:always, type:queue, node-properties:{ x-properties:{auto-delete:true}}}");
+ Receiver receiver = session.createReceiver(responseQueue);
+
+ // Now send some messages ...
+ string s[] = {
+ "Twas brillig, and the slithy toves",
+ "Did gire and gymble in the wabe.",
+ "All mimsy were the borogroves,",
+ "And the mome raths outgrabe."
+ };
+
+ Message request;
+ request.setReplyTo(responseQueue);
+ for (int i=0; i<4; i++) {
+ request.setContent(s[i]);
+ sender.send(request);
+ Message response = receiver.fetch();
+ std::cout << request.getContent() << " -> " << response.getContent() << std::endl;
+ }
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/cpp/examples/messaging/drain.cpp b/cpp/examples/messaging/drain.cpp
new file mode 100644
index 0000000000..2bd9fcdac8
--- /dev/null
+++ b/cpp/examples/messaging/drain.cpp
@@ -0,0 +1,125 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/messaging/Connection.h>
+#include <qpid/messaging/MapView.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/Receiver.h>
+#include <qpid/messaging/Session.h>
+#include <qpid/Exception.h>
+#include <qpid/Options.h>
+#include <qpid/log/Logger.h>
+#include <qpid/log/Options.h>
+#include <qpid/sys/Time.h>
+
+#include <iostream>
+
+using namespace qpid::messaging;
+using qpid::sys::Duration;
+using qpid::sys::TIME_INFINITE;
+using qpid::sys::TIME_SEC;
+
+struct Options : public qpid::Options
+{
+ bool help;
+ std::string url;
+ std::string address;
+ int64_t timeout;
+ bool forever;
+ qpid::log::Options log;
+
+ Options(const std::string& argv0=std::string())
+ : qpid::Options("Options"),
+ help(false),
+ url("amqp:tcp:127.0.0.1"),
+ timeout(0),
+ forever(false),
+ log(argv0)
+ {
+ addOptions()
+ ("broker,b", qpid::optValue(url, "URL"), "url of broker to connect to")
+ ("address,a", qpid::optValue(address, "ADDRESS"), "address to drain from")
+ ("timeout,t", qpid::optValue(timeout, "TIMEOUT"), "timeout in seconds to wait before exiting")
+ ("forever,f", qpid::optValue(forever), "ignore timeout and wait forever")
+ ("help", qpid::optValue(help), "print this usage statement");
+ add(log);
+ }
+
+ Duration getTimeout()
+ {
+ if (forever) return TIME_INFINITE;
+ else return timeout*TIME_SEC;
+
+ }
+ bool parse(int argc, char** argv)
+ {
+ try {
+ qpid::Options::parse(argc, argv);
+ if (address.empty()) throw qpid::Exception("Address must be specified!");
+ qpid::log::Logger::instance().configure(log);
+ if (help) {
+ std::ostringstream msg;
+ std::cout << msg << *this << std::endl << std::endl
+ << "Drains messages from the specified address" << std::endl;
+ return false;
+ } else {
+ return true;
+ }
+ } catch (const std::exception& e) {
+ std::cerr << *this << std::endl << std::endl << e.what() << std::endl;
+ return false;
+ }
+ }
+};
+
+
+int main(int argc, char** argv)
+{
+ Options options(argv[0]);
+ if (options.parse(argc, argv)) {
+ try {
+ Connection connection = Connection::open(options.url);
+ Session session = connection.newSession();
+ Receiver receiver = session.createReceiver(options.address);
+ Duration timeout = options.getTimeout();
+ Message message;
+ while (receiver.fetch(message, timeout)) {
+ std::cout << "Message(properties=" << message.getHeaders() << ", content='" ;
+ if (message.getContentType() == "amqp/map") {
+ std::cout << MapView(message);
+ } else {
+ std::cout << message.getContent();
+ }
+ std::cout << "')" << std::endl;
+ session.acknowledge();
+ }
+ receiver.cancel();
+ session.close();
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ }
+ return 1;
+}
+
+
diff --git a/cpp/examples/messaging/map_receiver.cpp b/cpp/examples/messaging/map_receiver.cpp
new file mode 100644
index 0000000000..f97c44eebd
--- /dev/null
+++ b/cpp/examples/messaging/map_receiver.cpp
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/messaging/Connection.h>
+#include <qpid/messaging/MapView.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/Receiver.h>
+#include <qpid/messaging/Session.h>
+
+#include <cstdlib>
+#include <iostream>
+
+#include <sstream>
+
+using namespace qpid::messaging;
+
+using std::stringstream;
+using std::string;
+
+int main(int argc, char** argv) {
+ const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
+
+ try {
+ Connection connection = Connection::open(url);
+ Session session = connection.newSession();
+ Receiver receiver = session.createReceiver("message_queue");
+ Message message = receiver.fetch();
+ MapView content(message);
+ std::cout << content << std::endl;
+ session.acknowledge();
+ receiver.cancel();
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
diff --git a/cpp/examples/messaging/map_sender.cpp b/cpp/examples/messaging/map_sender.cpp
new file mode 100644
index 0000000000..02c6433836
--- /dev/null
+++ b/cpp/examples/messaging/map_sender.cpp
@@ -0,0 +1,69 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/messaging/Connection.h>
+#include <qpid/messaging/MapContent.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/Sender.h>
+#include <qpid/messaging/Session.h>
+
+#include <cstdlib>
+#include <iostream>
+
+#include <sstream>
+
+using namespace qpid::messaging;
+
+using std::stringstream;
+using std::string;
+
+int main(int argc, char** argv) {
+ const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
+
+ try {
+ Connection connection = Connection::open(url);
+ Session session = connection.newSession();
+ Sender sender = session.createSender("message_queue");
+
+ Message message;
+ MapContent content(message);
+ content["id"] = 987654321;
+ content["name"] = "Widget";
+ content["price"] = 0.99;//bad use of floating point number, just an example!
+ Variant::List colours;
+ colours.push_back(Variant("red"));
+ colours.push_back(Variant("green"));
+ colours.push_back(Variant("white"));
+ content["colours"] = colours;
+ content.encode();
+
+ sender.send(message);
+ session.sync();
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/cpp/examples/messaging/messaging_client.vcproj b/cpp/examples/messaging/messaging_client.vcproj
new file mode 100644
index 0000000000..972c879495
--- /dev/null
+++ b/cpp/examples/messaging/messaging_client.vcproj
@@ -0,0 +1,411 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="messaging_client"
+ ProjectGUID="{80B58CBC-FECA-1BAD-1FEE-AE349A6B75AA}"
+ RootNamespace="messaging_client"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\messaging_client\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\client.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\messaging_client\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\client.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\messaging_client\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\client.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\messaging_client\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\client.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;c;C">
+ <File
+ RelativePath="client.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Documentation"
+ Filter="">
+ <File
+ RelativePath="CMakeLists.txt">
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/messaging/messaging_map_receiver.vcproj b/cpp/examples/messaging/messaging_map_receiver.vcproj
new file mode 100644
index 0000000000..2f3a5e3973
--- /dev/null
+++ b/cpp/examples/messaging/messaging_map_receiver.vcproj
@@ -0,0 +1,411 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="messaging_map_receiver"
+ ProjectGUID="{92D8F5AA-FECA-1BAD-1FEE-AE349A6B75AA}"
+ RootNamespace="messaging_map_receiver"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\messaging_map_receiver\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\map_receiver.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\messaging_map_receiver\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\map_receiver.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\messaging_map_receiver\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\map_receiver.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\messaging_map_receiver\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\map_receiver.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;c;C">
+ <File
+ RelativePath="map_receiver.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Documentation"
+ Filter="">
+ <File
+ RelativePath="CMakeLists.txt">
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/messaging/messaging_map_sender.vcproj b/cpp/examples/messaging/messaging_map_sender.vcproj
new file mode 100644
index 0000000000..76b6ea0c46
--- /dev/null
+++ b/cpp/examples/messaging/messaging_map_sender.vcproj
@@ -0,0 +1,411 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="messaging_map_sender"
+ ProjectGUID="{3B9EA507-FECA-1BAD-1FEE-AE349A6B75AA}"
+ RootNamespace="messaging_map_sender"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\messaging_map_sender\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\map_sender.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\messaging_map_sender\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\map_sender.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\messaging_map_sender\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\map_sender.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\messaging_map_sender\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\map_sender.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;c;C">
+ <File
+ RelativePath="map_sender.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Documentation"
+ Filter="">
+ <File
+ RelativePath="CMakeLists.txt">
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/messaging/messaging_queue_listener.vcproj b/cpp/examples/messaging/messaging_queue_listener.vcproj
new file mode 100644
index 0000000000..5bc19b655a
--- /dev/null
+++ b/cpp/examples/messaging/messaging_queue_listener.vcproj
@@ -0,0 +1,411 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="messaging_queue_listener"
+ ProjectGUID="{7A423237-FECA-1BAD-1FEE-AE349A6B75AA}"
+ RootNamespace="messaging_queue_listener"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\messaging_queue_listener\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\queue_listener.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\messaging_queue_listener\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\queue_listener.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\messaging_queue_listener\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\queue_listener.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\messaging_queue_listener\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\queue_listener.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;c;C">
+ <File
+ RelativePath="queue_listener.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Documentation"
+ Filter="">
+ <File
+ RelativePath="CMakeLists.txt">
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/messaging/messaging_queue_receiver.vcproj b/cpp/examples/messaging/messaging_queue_receiver.vcproj
new file mode 100644
index 0000000000..c76d0aeec4
--- /dev/null
+++ b/cpp/examples/messaging/messaging_queue_receiver.vcproj
@@ -0,0 +1,411 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="messaging_queue_receiver"
+ ProjectGUID="{64932FB7-FECA-1BAD-1FEE-AE349A6B75AA}"
+ RootNamespace="messaging_queue_receiver"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\messaging_queue_receiver\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\queue_receiver.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\messaging_queue_receiver\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\queue_receiver.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\messaging_queue_receiver\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\queue_receiver.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\messaging_queue_receiver\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\queue_receiver.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;c;C">
+ <File
+ RelativePath="queue_receiver.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Documentation"
+ Filter="">
+ <File
+ RelativePath="CMakeLists.txt">
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/messaging/messaging_queue_sender.vcproj b/cpp/examples/messaging/messaging_queue_sender.vcproj
new file mode 100644
index 0000000000..ae2f740b53
--- /dev/null
+++ b/cpp/examples/messaging/messaging_queue_sender.vcproj
@@ -0,0 +1,411 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="messaging_queue_sender"
+ ProjectGUID="{2668EEDD-FECA-1BAD-1FEE-AE349A6B75AA}"
+ RootNamespace="messaging_queue_sender"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\messaging_queue_sender\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\queue_sender.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\messaging_queue_sender\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\queue_sender.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\messaging_queue_sender\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\queue_sender.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\messaging_queue_sender\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\queue_sender.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;c;C">
+ <File
+ RelativePath="queue_sender.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Documentation"
+ Filter="">
+ <File
+ RelativePath="CMakeLists.txt">
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/messaging/messaging_server.vcproj b/cpp/examples/messaging/messaging_server.vcproj
new file mode 100644
index 0000000000..5b088d01e7
--- /dev/null
+++ b/cpp/examples/messaging/messaging_server.vcproj
@@ -0,0 +1,411 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="messaging_server"
+ ProjectGUID="{E0A50687-FECA-1BAD-1FEE-AE349A6B75AA}"
+ RootNamespace="messaging_server"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\messaging_server\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\server.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\messaging_server\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\server.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\messaging_server\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\server.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\messaging_server\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\server.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;c;C">
+ <File
+ RelativePath="server.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Documentation"
+ Filter="">
+ <File
+ RelativePath="CMakeLists.txt">
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/messaging/messaging_topic_listener.vcproj b/cpp/examples/messaging/messaging_topic_listener.vcproj
new file mode 100644
index 0000000000..a43d10ed60
--- /dev/null
+++ b/cpp/examples/messaging/messaging_topic_listener.vcproj
@@ -0,0 +1,411 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="messaging_topic_listener"
+ ProjectGUID="{7A4686F1-FECA-1BAD-1FEE-AE349A6B75AA}"
+ RootNamespace="messaging_topic_listener"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\messaging_topic_listener\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\topic_listener.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\messaging_topic_listener\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\topic_listener.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\messaging_topic_listener\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\topic_listener.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\messaging_topic_listener\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\topic_listener.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;c;C">
+ <File
+ RelativePath="topic_listener.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Documentation"
+ Filter="">
+ <File
+ RelativePath="CMakeLists.txt">
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/messaging/messaging_topic_receiver.vcproj b/cpp/examples/messaging/messaging_topic_receiver.vcproj
new file mode 100644
index 0000000000..57465fe85f
--- /dev/null
+++ b/cpp/examples/messaging/messaging_topic_receiver.vcproj
@@ -0,0 +1,411 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="messaging_topic_receiver"
+ ProjectGUID="{64979B71-FECA-1BAD-1FEE-AE349A6B75AA}"
+ RootNamespace="messaging_topic_receiver"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\messaging_topic_receiver\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\topic_receiver.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\messaging_topic_receiver\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\topic_receiver.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\messaging_topic_receiver\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\topic_receiver.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\messaging_topic_receiver\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\topic_receiver.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;c;C">
+ <File
+ RelativePath="topic_receiver.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Documentation"
+ Filter="">
+ <File
+ RelativePath="CMakeLists.txt">
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/messaging/messaging_topic_sender.vcproj b/cpp/examples/messaging/messaging_topic_sender.vcproj
new file mode 100644
index 0000000000..fd0afecbf8
--- /dev/null
+++ b/cpp/examples/messaging/messaging_topic_sender.vcproj
@@ -0,0 +1,411 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="messaging_topic_sender"
+ ProjectGUID="{E068EA69-FECA-1BAD-1FEE-AE349A6B75AA}"
+ RootNamespace="messaging_topic_sender"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\messaging_topic_sender\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\topic_sender.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\messaging_topic_sender\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\topic_sender.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\messaging_topic_sender\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\topic_sender.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\messaging_topic_sender\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\topic_sender.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin;..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;c;C">
+ <File
+ RelativePath="topic_sender.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Documentation"
+ Filter="">
+ <File
+ RelativePath="CMakeLists.txt">
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/messaging/queue_receiver.cpp b/cpp/examples/messaging/queue_receiver.cpp
new file mode 100644
index 0000000000..40f863eb30
--- /dev/null
+++ b/cpp/examples/messaging/queue_receiver.cpp
@@ -0,0 +1,59 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/messaging/Connection.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/Receiver.h>
+#include <qpid/messaging/Session.h>
+
+#include <iostream>
+
+using namespace qpid::messaging;
+
+int main(int argc, char** argv) {
+ const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
+
+ try {
+ Variant::Map options;
+ if (argc>2) parseOptionString(argv[2], options);
+ Connection connection = Connection::open(url, options);
+ Session session = connection.newSession();
+ Receiver receiver = session.createReceiver("message_queue");
+ while (true) {
+ Message message = receiver.fetch();
+ std::cout << "Message: " << message.getContent() << std::endl;
+ session.acknowledge();
+ if (message.getContent() == "That's all, folks!") {
+ std::cout << "Cancelling receiver" << std::endl;
+ receiver.cancel();
+ break;
+ }
+ }
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/cpp/examples/messaging/queue_sender.cpp b/cpp/examples/messaging/queue_sender.cpp
new file mode 100644
index 0000000000..1396e26d5c
--- /dev/null
+++ b/cpp/examples/messaging/queue_sender.cpp
@@ -0,0 +1,60 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/messaging/Connection.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/Sender.h>
+#include <qpid/messaging/Session.h>
+
+#include <cstdlib>
+#include <iostream>
+#include <sstream>
+
+using namespace qpid::messaging;
+
+int main(int argc, char** argv) {
+ const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
+ int count = argc>2 ? atoi(argv[2]) : 10;
+
+ try {
+ Connection connection = Connection::open(url);
+ Session session = connection.newSession();
+ Sender sender = session.createSender("message_queue");
+
+ // Now send some messages ...
+ for (int i=0; i<count; i++) {
+ std::stringstream content;
+ content << "Message " << i;
+ sender.send(Message(content.str()));
+ }
+
+ // And send a final message to indicate termination.
+ sender.send(Message("That's all, folks!"));
+ session.sync();
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/cpp/examples/messaging/readme.txt b/cpp/examples/messaging/readme.txt
new file mode 100644
index 0000000000..788b8c2833
--- /dev/null
+++ b/cpp/examples/messaging/readme.txt
@@ -0,0 +1,146 @@
+The messaging API is intended as a high level abstraction for
+messaging that avoids some of the protocol specific interactions
+forced by the earlier API. This allows applications to concern
+themselves with handling incoming messages and producing their own
+messages and delegates knowledge of the protocol interactions required
+to do so to the Qpid client library.
+
+To send or receive messages you first need to establish a connection
+to a broker. You can then create one or more sessions on that
+connection. Once you have a session you can create 'senders' or
+'receivers'. These are objects through which you can send or receive
+messages respectively.
+
+Senders and receivers are both created for a specified 'address'. An
+address will often just be a simple name. As far as the API is
+concerned, addresses are fairly opaque. This allows different types of
+messaging pattern to be selected without affecting the code simply by
+changing the address used, or configuring the broker to correctly
+handle addresses of a certain name.
+
+At present there are two 'types' of address supported: queues and
+topics. Messages sent to a queue are stored on the queue until there
+is a subscriber who can receive them. Each message is in general
+allocated to one subscriber (i.e. a competing consumer pattern). A
+topic on the other hand will not store messages if there are no
+subscriptions active and each message will be delivered to all
+interested subscribers.
+
+In the current AMQP 0-10 implementation, queues are represented by
+AMQP queues and topic are represented by AMQP exchanges to which
+subscribers bind their own private subscription queue to receive
+messages.
+
+The drain and spout examples in this directory are useful for
+exploring the behaviour of the messaging API over AMQP 0-10 and
+different uses of addresses. There is also some documentation around
+the address syntax and currently supported options in the doxygen
+reference material for the Address class itself.
+
+For example, to demonstrate classic message queueing behaviour:
+
+* create a queue e.g. by running: qpid-config add queue my-queue
+
+* use spout to send a message to that queue: ./spout --address my-queue
+
+* now use drain to receive that message: ./drain --address my-queue
+
+You can use the --content option to spout to specify text to put n the
+message body. You can also alter the id used to unqieuly identify
+each message using the --id option.
+
+To demonstrate the publish-subscribe pattern used for topics:
+
+* create an exchange e.g. by running: qpid-config add exchange topic my-topic
+
+* start up a subscriber using drain: ./drain -f --address my-topic
+ (the -f here causes the drain program to wait indefinitely for messages)
+
+* now send a message to the topic using spout: ./spout --address my-topic
+
+If you run spout before drain, the message will not be stored. If you
+start multiple instances of drain, they will each receive the message.
+
+For a topic, you can select the messages you wish to receive by
+'subject', eg. using the same exchange as above:
+
+* start a subscriber using drain for a specific subject:
+ ./drain -f --address my-topic/my-subject
+
+* now if you send a message with that subject you can see the
+ subscriber receives it: ./spout --address my-topic/my-subject
+
+* however were you to specify another subject for sent messages, those
+ would not be received, e.g: ./spout --address my-topic/another-subject
+
+In AMQP 0-10, the routing key is used to route messages for a given
+subject. As my-topic is a topic exchange we can use the special
+widlcard selection patterns when creating a subscriber:
+
+E.g. A subscriber reciving from address 'my-topic/#.dog' will receive
+messages sent to 'my-topic/big.dog' and 'my-topic/blue.dog', but not
+those sent to 'my-topic.blue-cat'.
+
+Though preconfiguring the valid addresses on a broker is a very common
+pattern, it is still possible to have them created automatically
+'on-demand'. This is done by specifying a create 'policy' for the address.
+
+* run: ./spout --address 'my-new-queue; {create: always}'
+* then run: ./drain --address my-new-queue
+
+You can see that the queue was created by spout before it sent the
+message to it, no explicit creation of the queue was needed.
+
+We can do the same for a topic, but there we need to specify the type
+of address (as there is no existing entity from which to infer that
+type and as we do not want the default type to be created, namely a
+queue):
+
+* run: ./drain -f --address 'my-new-topic; {create: always, node-properties:{type:topic}}'
+* then run: ./spout --address my-new-queue
+
+The value to the create policy is one of always, sender, receiver or
+never (which is the default). (Note: You can see the exchange created
+using qpid-config exchanges, likewise to see the list of all queues
+use qpid-config queues).
+
+In addition to a create policy there are assert and delete
+policies. These have the same valid values as the create policy -
+always, sender, receiver and never - indicating when they come in to
+effect.
+
+An example using the headers exchange (uses default instance, though
+this need not of course be the case. You could create another using
+qpid-config or even auto-create one):
+
+* First start a subscriber, e.g.:
+ ./drain -f --address 'amq.match; {filter:{x-match:all, colour:blue}}'
+
+* Any message with a property name colour with value blue will be
+ received:
+
+ ./spout --address amq.match --property colour=blue --content 'matched!'
+
+* But if the value of the colour property is something else, the
+ message will not be received:
+ ./spout --address amq.match --property colour=red --content 'not matched'
+
+An example using xquery based filtering with the xml exchange:
+
+* First start a subscriber with an xquery filter specified:
+ ./drain -f --address 'xml/my-subject; {filter:{xquery:"declare variable $colour external; $colour = '\''red'\''"}}'
+
+* Then test receipt of messages that match the xquery filter:
+ ./spout --address 'xml/my-subject' --property colour=red --content 'matched!'
+ and
+ ./spout --address 'xml/my-subject' --property colour=blue --content 'not matched'
+
+TODO:
+
+* xml content in the xquery example
+
+* 'durable' and 'reliable' subscriptions
+
+* map content
+
+* client/server example: temp queues and reply-to
diff --git a/cpp/examples/messaging/server.cpp b/cpp/examples/messaging/server.cpp
new file mode 100644
index 0000000000..137323dd03
--- /dev/null
+++ b/cpp/examples/messaging/server.cpp
@@ -0,0 +1,76 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/messaging/Address.h>
+#include <qpid/messaging/Connection.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/Receiver.h>
+#include <qpid/messaging/Sender.h>
+#include <qpid/messaging/Session.h>
+#include <qpid/messaging/Variant.h>
+
+#include <algorithm>
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+#include <sstream>
+
+using namespace qpid::messaging;
+
+using std::stringstream;
+using std::string;
+
+int main(int argc, char** argv) {
+ const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
+
+ try {
+ Connection connection = Connection::open(url);
+ Session session = connection.newSession();
+ Receiver receiver = session.createReceiver("service_queue; {create: always}");
+
+ while (true) {
+ Message request = receiver.fetch();
+ const Address& address = request.getReplyTo();
+ if (address) {
+ Sender sender = session.createSender(address);
+ std::string s = request.getContent();
+ std::transform(s.begin(), s.end(), s.begin(), toupper);
+ Message response(s);
+ sender.send(response);
+ std::cout << "Processed request: "
+ << request.getContent()
+ << " -> "
+ << response.getContent() << std::endl;
+ session.acknowledge();
+ } else {
+ std::cerr << "Error: no reply address specified for request: " << request.getContent() << std::endl;
+ session.reject(request);
+ }
+ }
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/cpp/examples/messaging/spout.cpp b/cpp/examples/messaging/spout.cpp
new file mode 100644
index 0000000000..661397d232
--- /dev/null
+++ b/cpp/examples/messaging/spout.cpp
@@ -0,0 +1,190 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Address.h>
+#include <qpid/messaging/Connection.h>
+#include <qpid/messaging/MapContent.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/Sender.h>
+#include <qpid/messaging/Session.h>
+#include <qpid/messaging/Variant.h>
+#include <qpid/framing/Uuid.h>
+#include <qpid/Exception.h>
+#include <qpid/Options.h>
+#include <qpid/log/Logger.h>
+#include <qpid/log/Options.h>
+#include <qpid/sys/Time.h>
+
+#include <iostream>
+#include <vector>
+
+#include <boost/format.hpp>
+
+using namespace qpid::messaging;
+using qpid::framing::Uuid;
+using qpid::sys::AbsTime;
+using qpid::sys::now;
+using qpid::sys::TIME_INFINITE;
+
+typedef std::vector<std::string> string_vector;
+
+struct Options : public qpid::Options
+{
+ bool help;
+ std::string url;
+ std::string address;
+ int64_t timeout;
+ uint count;
+ std::string id;
+ std::string replyto;
+ string_vector properties;
+ string_vector entries;
+ std::string content;
+ qpid::log::Options log;
+
+ Options(const std::string& argv0=std::string())
+ : qpid::Options("Options"),
+ help(false),
+ url("amqp:tcp:127.0.0.1"),
+ timeout(TIME_INFINITE),
+ count(1),
+ log(argv0)
+ {
+ addOptions()
+ ("broker,b", qpid::optValue(url, "URL"), "url of broker to connect to")
+ ("address,a", qpid::optValue(address, "ADDRESS"), "address to drain from")
+ ("timeout,t", qpid::optValue(timeout, "TIMEOUT"), "exit after the specified time")
+ ("count,c", qpid::optValue(count, "COUNT"), "stop after count messages have been sent, zero disables")
+ ("id,i", qpid::optValue(id, "ID"), "use the supplied id instead of generating one")
+ ("reply-to", qpid::optValue(replyto, "REPLY-TO"), "specify reply-to address")
+ ("property,P", qpid::optValue(properties, "NAME=VALUE"), "specify message property")
+ ("map,M", qpid::optValue(entries, "NAME=VALUE"), "specify entry for map content")
+ ("content", qpid::optValue(content, "CONTENT"), "specify textual content")
+ ("help", qpid::optValue(help), "print this usage statement");
+ add(log);
+ }
+
+ bool parse(int argc, char** argv)
+ {
+ try {
+ qpid::Options::parse(argc, argv);
+ if (address.empty()) throw qpid::Exception("Address must be specified!");
+ qpid::log::Logger::instance().configure(log);
+ if (help) {
+ std::ostringstream msg;
+ std::cout << msg << *this << std::endl << std::endl
+ << "Drains messages from the specified address" << std::endl;
+ return false;
+ } else {
+ return true;
+ }
+ } catch (const std::exception& e) {
+ std::cerr << *this << std::endl << std::endl << e.what() << std::endl;
+ return false;
+ }
+ }
+
+ static bool nameval(const std::string& in, std::string& name, std::string& value)
+ {
+ std::string::size_type i = in.find("=");
+ if (i == std::string::npos) {
+ name = in;
+ return false;
+ } else {
+ name = in.substr(0, i);
+ if (i+1 < in.size()) {
+ value = in.substr(i+1);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ static void setProperty(Message& message, const std::string& property)
+ {
+ std::string name;
+ std::string value;
+ if (nameval(property, name, value)) {
+ message.getHeaders()[name] = value;
+ } else {
+ message.getHeaders()[name] = Variant();
+ }
+ }
+
+ void setProperties(Message& message) const
+ {
+ for (string_vector::const_iterator i = properties.begin(); i != properties.end(); ++i) {
+ setProperty(message, *i);
+ }
+ }
+
+ void setEntries(MapContent& content) const
+ {
+ for (string_vector::const_iterator i = entries.begin(); i != entries.end(); ++i) {
+ std::string name;
+ std::string value;
+ if (nameval(*i, name, value)) {
+ content[name] = value;
+ } else {
+ content[name] = Variant();
+ }
+ }
+ }
+};
+
+
+int main(int argc, char** argv)
+{
+ Options options(argv[0]);
+ if (options.parse(argc, argv)) {
+ try {
+ Connection connection = Connection::open(options.url);
+ Session session = connection.newSession();
+ Sender sender = session.createSender(options.address);
+
+ Message message;
+ options.setProperties(message);
+ if (options.entries.size()) {
+ MapContent content(message);
+ options.setEntries(content);
+ content.encode();
+ } else if (options.content.size()) {
+ message.setContent(options.content);
+ message.setContentType("text/plain; charset=utf8");
+ }
+ AbsTime end(now(), options.timeout);
+ for (uint count = 0; (count < options.count || options.count == 0) && end > now(); count++) {
+ if (!options.replyto.empty()) message.setReplyTo(Address(options.replyto));
+ std::string id = options.id.empty() ? Uuid(true).str() : options.id;
+ message.getHeaders()["spout-id"] = (boost::format("%1%:%2%") % id % count).str();
+ sender.send(message);
+ }
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ }
+ return 1;
+}
+
+
diff --git a/cpp/examples/messaging/topic_receiver.cpp b/cpp/examples/messaging/topic_receiver.cpp
new file mode 100644
index 0000000000..45ab9448db
--- /dev/null
+++ b/cpp/examples/messaging/topic_receiver.cpp
@@ -0,0 +1,59 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/messaging/Connection.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/Receiver.h>
+#include <qpid/messaging/Session.h>
+#include <qpid/messaging/Variant.h>
+
+#include <cstdlib>
+#include <iostream>
+
+using namespace qpid::messaging;
+
+int main(int argc, char** argv) {
+ const std::string url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
+ const std::string pattern = argc>2 ? argv[2] : "#.#";
+
+ try {
+ Connection connection = Connection::open(url);
+ Session session = connection.newSession();
+ Receiver receiver = session.createReceiver("news_service; {filter:[control, " + pattern + "]}");
+ while (true) {
+ Message message = receiver.fetch();
+ std::cout << "Message: " << message.getContent() << std::endl;
+ if (message.getContent() == "That's all, folks!") {
+ std::cout << "Cancelling receiver" << std::endl;
+ receiver.cancel();
+ break;
+ }
+ }
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/cpp/examples/messaging/topic_sender.cpp b/cpp/examples/messaging/topic_sender.cpp
new file mode 100644
index 0000000000..5665fc45f9
--- /dev/null
+++ b/cpp/examples/messaging/topic_sender.cpp
@@ -0,0 +1,78 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/messaging/Connection.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/Sender.h>
+#include <qpid/messaging/Session.h>
+
+#include <cstdlib>
+#include <iostream>
+
+#include <sstream>
+
+using namespace qpid::messaging;
+
+using std::stringstream;
+using std::string;
+
+void sendMessages(Sender& sender, int count, const std::string& subject, const std::string& text)
+{
+ Message message;
+ message.setSubject(subject);
+ for (int i=0; i<count; i++) {
+ stringstream message_data;
+ message_data << text << i;
+
+ message.setContent(message_data.str());
+ sender.send(message);
+ }
+}
+
+int main(int argc, char** argv) {
+ const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
+ int count = argc>2 ? atoi(argv[2]) : 10;
+
+ try {
+ Connection connection = Connection::open(url);
+ Session session = connection.newSession();
+ Sender sender = session.createSender("news_service");
+
+ // Now send some messages to each topic...
+ sendMessages(sender, count, "usa.news", "news about the usa");
+ sendMessages(sender, count, "usa.weather", "weather report for the usa");
+ sendMessages(sender, count, "europe.news", "news about europe");
+ sendMessages(sender, count, "europe.weather", "weather report for europe");
+
+ // And send a final message to indicate termination.
+ Message message("That's all, folks!");
+ message.setSubject("control");
+ sender.send(message);
+ session.sync();
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/cpp/examples/pub-sub/CMakeLists.txt b/cpp/examples/pub-sub/CMakeLists.txt
new file mode 100644
index 0000000000..961de06d5a
--- /dev/null
+++ b/cpp/examples/pub-sub/CMakeLists.txt
@@ -0,0 +1,21 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+add_example(pub-sub topic_listener)
+add_example(pub-sub topic_publisher)
diff --git a/cpp/examples/pub-sub/Makefile.am b/cpp/examples/pub-sub/Makefile.am
index 8446a1c40c..8673174a06 100644
--- a/cpp/examples/pub-sub/Makefile.am
+++ b/cpp/examples/pub-sub/Makefile.am
@@ -1,5 +1,24 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
examplesdir=$(pkgdatadir)/examples/pub-sub
+MAKELDFLAGS=$(CLIENTFLAGS)
include $(top_srcdir)/examples/makedist.mk
noinst_PROGRAMS=topic_listener topic_publisher
@@ -17,14 +36,12 @@ examples_DATA= \
EXTRA_DIST= \
$(examples_DATA) \
+ CMakeLists.txt \
verify \
verify.in \
verify_cpp_python \
verify_cpp_python.in \
verify_python_cpp \
- verify_python_cpp.in
-
-
-
-
-
+ verify_python_cpp.in \
+ pub-sub_topic_listener.vcproj \
+ pub-sub_topic_publisher.vcproj
diff --git a/cpp/examples/pub-sub/pub-sub_topic_listener.vcproj b/cpp/examples/pub-sub/pub-sub_topic_listener.vcproj
new file mode 100644
index 0000000000..debc795b5b
--- /dev/null
+++ b/cpp/examples/pub-sub/pub-sub_topic_listener.vcproj
@@ -0,0 +1,394 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="pub_sub_topic_listener"
+ ProjectGUID="{A415E66A-FECA-1BAD-A430-FD5330E23A2D}"
+ RootNamespace="pub_sub_topic_listener"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\pub_sub_topic_listener\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\topic_listener.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\pub_sub_topic_listener\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\topic_listener.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\pub_sub_topic_listener\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\topic_listener.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\pub_sub_topic_listener\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\topic_listener.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="topic_listener.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="ConnectionOptions.h">
+ </File>
+ <File
+ RelativePath="TestOptions.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/pub-sub/pub-sub_topic_publisher.vcproj b/cpp/examples/pub-sub/pub-sub_topic_publisher.vcproj
new file mode 100644
index 0000000000..f67de44d20
--- /dev/null
+++ b/cpp/examples/pub-sub/pub-sub_topic_publisher.vcproj
@@ -0,0 +1,394 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="pub_sub_topic_publisher"
+ ProjectGUID="{05158653-FECA-1BAD-A430-FD5330E23A2D}"
+ RootNamespace="pub_sub_topic_publisher"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\pub_sub_topic_publisher\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\topic_publisher.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\pub_sub_topic_publisher\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\topic_publisher.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\pub_sub_topic_publisher\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\topic_publisher.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\pub_sub_topic_publisher\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\topic_publisher.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="topic_publisher.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="ConnectionOptions.h">
+ </File>
+ <File
+ RelativePath="TestOptions.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/pub-sub/topic_listener.cpp b/cpp/examples/pub-sub/topic_listener.cpp
index 9996abab19..d38a806303 100644
--- a/cpp/examples/pub-sub/topic_listener.cpp
+++ b/cpp/examples/pub-sub/topic_listener.cpp
@@ -22,21 +22,24 @@
/**
* topic_listener.cpp:
*
- * This program is one of three programs designed to be used
- * together. These programs use the topic exchange.
- *
- * topic_config_queues.cpp:
+ * This program is one of two programs designed to be used
+ * together. These programs implement a publish-subscribe example
+ * using the "amq.topic" exchange.
*
- * Creates a queue on a broker, binding a routing key to route
- * messages to that queue.
+ * topic_publisher.cpp
*
- * topic_publisher.cpp:
+ * Sends messages to the "amq.topic" exchange, using the
+ * multipart routing keys "usa.news", "usa.weather",
+ * "europe.news", and "europe.weather".
*
- * Publishes to a broker, specifying a routing key.
+ * topic_listener.cpp (this program)
*
- * topic_listener.cpp (this program):
+ * Creates private queues for "news", "weather", "usa", and
+ * "europe", binding them to the amq.topic exchange using
+ * bindings that match the corresponding parts of the multipart
+ * routing keys.
*
- * Reads from a queue on the broker using a message listener.
+ * Multiple listeners can be run at the same time.
*
*/
@@ -46,10 +49,8 @@
#include <qpid/client/MessageListener.h>
#include <qpid/client/SubscriptionManager.h>
-#include <unistd.h>
#include <cstdlib>
#include <iostream>
-#include <set>
using namespace qpid::client;
using namespace qpid::framing;
@@ -61,7 +62,7 @@ class Listener : public MessageListener {
SubscriptionManager subscriptions;
public:
Listener(Session& session);
- virtual void prepareQueue(std::string queue, std::string routing_key);
+ virtual void prepareQueue(std::string queue, std::string exchange, std::string routing_key);
virtual void received(Message& message);
virtual void listen();
~Listener() { };
@@ -84,7 +85,7 @@ Listener::Listener(Session& session) :
}
-void Listener::prepareQueue(std::string queue, std::string routing_key) {
+void Listener::prepareQueue(std::string queue, std::string exchange, std::string routing_key) {
/* Create a unique queue name for this consumer by concatenating
* the queue name parameter with the Session ID.
@@ -106,8 +107,8 @@ void Listener::prepareQueue(std::string queue, std::string routing_key) {
* "control" routing key, when it is finished.
*/
- session.exchangeBind(arg::exchange="amq.topic", arg::queue=queue, arg::bindingKey=routing_key);
- session.exchangeBind(arg::exchange="amq.topic", arg::queue=queue, arg::bindingKey="control");
+ session.exchangeBind(arg::exchange=exchange, arg::queue=queue, arg::bindingKey=routing_key);
+ session.exchangeBind(arg::exchange=exchange, arg::queue=queue, arg::bindingKey="control");
/*
* subscribe to the queue using the subscription manager.
@@ -134,6 +135,7 @@ void Listener::listen() {
int main(int argc, char** argv) {
const char* host = argc>1 ? argv[1] : "127.0.0.1";
int port = argc>2 ? atoi(argv[2]) : 5672;
+ std::string exchange = argc>3 ? argv[3] : "amq.topic";
Connection connection;
try {
connection.open(host, port);
@@ -147,12 +149,12 @@ int main(int argc, char** argv) {
// Subscribe to messages on the queues we are interested in
- listener.prepareQueue("usa", "usa.#");
- listener.prepareQueue("europe", "europe.#");
- listener.prepareQueue("news", "#.news");
- listener.prepareQueue("weather", "#.weather");
+ listener.prepareQueue("usa", exchange, "usa.#");
+ listener.prepareQueue("europe", exchange, "europe.#");
+ listener.prepareQueue("news", exchange, "#.news");
+ listener.prepareQueue("weather", exchange, "#.weather");
- std::cout << "Listening for messages ..." << std::endl;
+ std::cout << "Listening for messages ..." << std::endl;
// Give up control and receive messages
listener.listen();
diff --git a/cpp/examples/pub-sub/topic_publisher.cpp b/cpp/examples/pub-sub/topic_publisher.cpp
index ab485fec8f..aed5f8f033 100644
--- a/cpp/examples/pub-sub/topic_publisher.cpp
+++ b/cpp/examples/pub-sub/topic_publisher.cpp
@@ -19,25 +19,27 @@
*
*/
-
/**
* topic_publisher.cpp:
*
- * This program is one of three programs designed to be used
- * together. These programs use the topic exchange.
- *
- * topic_config_queues.cpp:
+ * This program is one of two programs designed to be used
+ * together. These programs implement a publish-subscribe example
+ * using the "amq.topic" exchange.
*
- * Creates a queue on a broker, binding a routing key to route
- * messages to that queue.
+ * topic_publisher.cpp (this program)
*
- * topic_publisher.cpp (this program):
+ * Sends messages to the "amq.topic" exchange, using the
+ * multipart routing keys "usa.news", "usa.weather",
+ * "europe.news", and "europe.weather".
*
- * Publishes to a broker, specifying a routing key.
+ * topic_listener.cpp
*
- * topic_listener.cpp
+ * Creates private queues for "news", "weather", "usa", and
+ * "europe", binding them to the amq.topic exchange using
+ * bindings that match the corresponding parts of the multipart
+ * routing keys.
*
- * Reads from a queue on the broker using a message listener.
+ * Multiple listeners can be run at the same time.
*
*/
@@ -48,7 +50,6 @@
#include <qpid/client/Message.h>
-#include <unistd.h>
#include <cstdlib>
#include <iostream>
@@ -100,20 +101,20 @@ void no_more_messages(Session& session)
int main(int argc, char** argv) {
const char* host = argc>1 ? argv[1] : "127.0.0.1";
int port = argc>2 ? atoi(argv[2]) : 5672;
+
Connection connection;
- Message message;
try {
connection.open(host, port);
Session session = connection.newSession();
//--------- Main body of program --------------------------------------------
- publish_messages(session, "usa.news");
- publish_messages(session, "usa.weather");
- publish_messages(session, "europe.news");
- publish_messages(session, "europe.weather");
+ publish_messages(session, "usa.news");
+ publish_messages(session, "usa.weather");
+ publish_messages(session, "europe.news");
+ publish_messages(session, "europe.weather");
- no_more_messages(session);
+ no_more_messages(session);
//-----------------------------------------------------------------------------
diff --git a/cpp/examples/pub-sub/verify b/cpp/examples/pub-sub/verify
index 3589a4c9da..528d2f401e 100644
--- a/cpp/examples/pub-sub/verify
+++ b/cpp/examples/pub-sub/verify
@@ -1,3 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
background "Listening" ./topic_listener
clients ./topic_publisher
diff --git a/cpp/examples/qmf-agent/Makefile b/cpp/examples/qmf-agent/Makefile
index 0b37f1a295..5b1afc4b01 100644
--- a/cpp/examples/qmf-agent/Makefile
+++ b/cpp/examples/qmf-agent/Makefile
@@ -25,21 +25,19 @@ OUT_FILE = $(SRC_DIR)/qmf-agent
CC = gcc
LIB_DIR = $(QPID_DIR)/cpp/src/.libs
-CC_INCLUDES = -I$(SRC_DIR) -I$(QPID_DIR)/cpp/src -I$(QPID_DIR)/cpp/src/gen -I$(GEN_DIR)
+CC_INCLUDES = -I$(SRC_DIR) -I$(QPID_DIR)/cpp/include -I$(GEN_DIR)
CC_FLAGS = -g -O3
-LD_FLAGS = -lqpidclient -lqpidcommon -L$(LIB_DIR)
+LD_FLAGS = -lqmf -L$(LIB_DIR)
SPEC_DIR = $(QPID_DIR)/specs
-TYPE_FILE = $(SPEC_DIR)/management-types.xml
MGEN_DIR = $(QPID_DIR)/cpp/managementgen
-TEMPLATE_DIR = $(MGEN_DIR)/templates
-MGEN = $(MGEN_DIR)/main.py
+MGEN = $(MGEN_DIR)/qmf-gen
vpath %.cpp $(SRC_DIR):$(GEN_DIR)
vpath %.d $(OBJ_DIR)
vpath %.o $(OBJ_DIR)
cpps = $(wildcard $(SRC_DIR)/*.cpp)
-cpps += $(wildcard $(GEN_DIR)/*.cpp)
+cpps += $(wildcard $(GEN_DIR)/qmf/org/apache/qpid/agent/example/*.cpp)
deps = $(addsuffix .d, $(basename $(cpps)))
objects = $(addsuffix .o, $(basename $(cpps)))
@@ -53,7 +51,7 @@ all: gen
@$(MAKE)
gen:
- $(MGEN) $(SCHEMA_FILE) $(TYPE_FILE) $(TEMPLATE_DIR) $(GEN_DIR)
+ $(MGEN) -o $(GEN_DIR)/qmf $(SCHEMA_FILE)
clean:
rm -rf $(GEN_DIR) $(OUT_FILE) *.d *.o
diff --git a/cpp/examples/qmf-agent/example.cpp b/cpp/examples/qmf-agent/example.cpp
index 35ea97d4c0..5ab9c10c91 100644
--- a/cpp/examples/qmf-agent/example.cpp
+++ b/cpp/examples/qmf-agent/example.cpp
@@ -23,24 +23,28 @@
#include <qpid/management/ManagementObject.h>
#include <qpid/agent/ManagementAgent.h>
#include <qpid/sys/Mutex.h>
-#include "Parent.h"
-#include "Child.h"
-#include "ArgsParentCreate_child.h"
-#include "PackageQmf_example.h"
-
-#include <unistd.h>
+#include <qpid/sys/Time.h>
+#include "qmf/org/apache/qpid/agent/example/Parent.h"
+#include "qmf/org/apache/qpid/agent/example/Child.h"
+#include "qmf/org/apache/qpid/agent/example/ArgsParentCreate_child.h"
+#include "qmf/org/apache/qpid/agent/example/EventChildCreated.h"
+#include "qmf/org/apache/qpid/agent/example/Package.h"
+
+#include <signal.h>
#include <cstdlib>
#include <iostream>
#include <sstream>
-using namespace qpid::management;
-using namespace qpid::sys;
+static bool running = true;
+
using namespace std;
+using qpid::management::ManagementAgent;
using qpid::management::ManagementObject;
using qpid::management::Manageable;
using qpid::management::Args;
using qpid::sys::Mutex;
+namespace _qmf = qmf::org::apache::qpid::agent::example;
class ChildClass;
@@ -52,7 +56,7 @@ class CoreClass : public Manageable
{
string name;
ManagementAgent* agent;
- Parent* mgmtObject;
+ _qmf::Parent* mgmtObject;
std::vector<ChildClass*> children;
Mutex vectorLock;
@@ -65,13 +69,13 @@ public:
{ return mgmtObject; }
void doLoop();
- status_t ManagementMethod (uint32_t methodId, Args& args);
+ status_t ManagementMethod (uint32_t methodId, Args& args, string& text);
};
class ChildClass : public Manageable
{
string name;
- Child* mgmtObject;
+ _qmf::Child* mgmtObject;
public:
@@ -89,19 +93,20 @@ public:
CoreClass::CoreClass(ManagementAgent* _agent, string _name) : name(_name), agent(_agent)
{
- mgmtObject = new Parent(agent, this, name);
+ static uint64_t persistId = 0x111222333444555LL;
+ mgmtObject = new _qmf::Parent(agent, this, name);
- agent->addObject(mgmtObject);
+ agent->addObject(mgmtObject, persistId++);
mgmtObject->set_state("IDLE");
}
void CoreClass::doLoop()
{
// Periodically bump a counter to provide a changing statistical value
- while (1) {
- sleep(1);
+ while (running) {
+ qpid::sys::sleep(1);
mgmtObject->inc_count();
- mgmtObject->set_state("IN LOOP");
+ mgmtObject->set_state("IN_LOOP");
{
Mutex::ScopedLock _lock(vectorLock);
@@ -115,19 +120,21 @@ void CoreClass::doLoop()
}
}
-Manageable::status_t CoreClass::ManagementMethod(uint32_t methodId, Args& args)
+Manageable::status_t CoreClass::ManagementMethod(uint32_t methodId, Args& args, string& /*text*/)
{
Mutex::ScopedLock _lock(vectorLock);
switch (methodId) {
- case Parent::METHOD_CREATE_CHILD:
- ArgsParentCreate_child& ioArgs = (ArgsParentCreate_child&) args;
+ case _qmf::Parent::METHOD_CREATE_CHILD:
+ _qmf::ArgsParentCreate_child& ioArgs = (_qmf::ArgsParentCreate_child&) args;
ChildClass *child = new ChildClass(agent, this, ioArgs.i_name);
ioArgs.o_childRef = child->GetManagementObject()->getObjectId();
children.push_back(child);
+ agent->raiseEvent(_qmf::EventChildCreated(ioArgs.i_name));
+
return STATUS_OK;
}
@@ -136,7 +143,7 @@ Manageable::status_t CoreClass::ManagementMethod(uint32_t methodId, Args& args)
ChildClass::ChildClass(ManagementAgent* agent, CoreClass* parent, string name)
{
- mgmtObject = new Child(agent, this, parent, name);
+ mgmtObject = new _qmf::Child(agent, this, parent, name);
agent->addObject(mgmtObject);
}
@@ -145,20 +152,35 @@ ChildClass::ChildClass(ManagementAgent* agent, CoreClass* parent, string name)
//==============================================================
// Main program
//==============================================================
-int main(int argc, char** argv) {
- ManagementAgent::Singleton singleton;
+
+ManagementAgent::Singleton* singleton;
+
+void shutdown(int)
+{
+ running = false;
+}
+
+int main_int(int argc, char** argv)
+{
+ singleton = new ManagementAgent::Singleton();
const char* host = argc>1 ? argv[1] : "127.0.0.1";
int port = argc>2 ? atoi(argv[2]) : 5672;
+ qpid::client::ConnectionSettings settings;
+
+ settings.host = host;
+ settings.port = port;
+
+ signal(SIGINT, shutdown);
// Create the qmf management agent
- ManagementAgent* agent = singleton.getInstance();
+ ManagementAgent* agent = singleton->getInstance();
// Register the Qmf_example schema with the agent
- PackageQmf_example packageInit(agent);
+ _qmf::Package packageInit(agent);
// Start the agent. It will attempt to make a connection to the
// management broker
- agent->init(string(host), port);
+ agent->init(settings, 5, false, ".magentdata");
// Allocate some core objects
CoreClass core1(agent, "Example Core Object #1");
@@ -166,6 +188,19 @@ int main(int argc, char** argv) {
CoreClass core3(agent, "Example Core Object #3");
core1.doLoop();
+
+ // done, cleanup and exit
+ delete singleton;
+
+ return 0;
}
+int main(int argc, char** argv)
+{
+ try {
+ return main_int(argc, argv);
+ } catch(std::exception& e) {
+ cout << "Top Level Exception: " << e.what() << endl;
+ }
+}
diff --git a/cpp/examples/qmf-agent/example_gen.mak b/cpp/examples/qmf-agent/example_gen.mak
new file mode 100644
index 0000000000..45da3932e9
--- /dev/null
+++ b/cpp/examples/qmf-agent/example_gen.mak
@@ -0,0 +1,10 @@
+# This nmake file generates the C++ mapping from the example schema.
+#
+# The Visual Studio projects assume the existence of the generated files.
+# These generated files must be created using this makefile for Windows
+# developers working from the source repository.
+
+mgen_dir=..\..\..\cpp\managementgen
+
+all:
+ python $(mgen_dir)\qmf-gen -o .\gen\qmf .\schema.xml
diff --git a/cpp/examples/qmf-agent/qmf_agent.vcproj b/cpp/examples/qmf-agent/qmf_agent.vcproj
new file mode 100644
index 0000000000..2a1c04b367
--- /dev/null
+++ b/cpp/examples/qmf-agent/qmf_agent.vcproj
@@ -0,0 +1,443 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="qmf_agent"
+ ProjectGUID="{771767FB-FECA-1BAD-2E13-3FFA2B8669C3}"
+ RootNamespace="qmf_console_ping"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="0"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\qmf_agent\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib qmfagentd.lib"
+ OutputFile="$(OutDir)\qmf_agent.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\qmf_console_ping\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib qmfagent.lib"
+ OutputFile="$(OutDir)\ping.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\qmf_console_ping\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib qmfagentd.lib"
+ OutputFile="$(OutDir)\ping.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\qmf_console_ping\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib qmfagent.lib"
+ OutputFile="$(OutDir)\ping.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c"
+ >
+ <File
+ RelativePath=".\gen\qmf\org\apache\qpid\agent\example\Child.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\gen\qmf\org\apache\qpid\agent\example\EventChildCreated.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\gen\qmf\org\apache\qpid\agent\example\EventChildDestroyed.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\example.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\gen\qmf\org\apache\qpid\agent\example\Package.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\gen\qmf\org\apache\qpid\agent\example\Parent.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh"
+ >
+ <File
+ RelativePath=".\gen\qmf\org\apache\qpid\agent\example\ArgsParentCreate_child.h"
+ >
+ </File>
+ <File
+ RelativePath=".\gen\qmf\org\apache\qpid\agent\example\Child.h"
+ >
+ </File>
+ <File
+ RelativePath=".\gen\qmf\org\apache\qpid\agent\example\EventChildCreated.h"
+ >
+ </File>
+ <File
+ RelativePath=".\gen\qmf\org\apache\qpid\agent\example\EventChildDestroyed.h"
+ >
+ </File>
+ <File
+ RelativePath=".\gen\qmf\org\apache\qpid\agent\example\Package.h"
+ >
+ </File>
+ <File
+ RelativePath=".\gen\qmf\org\apache\qpid\agent\example\Parent.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/qmf-agent/schema.xml b/cpp/examples/qmf-agent/schema.xml
index de8776c818..1bf701a655 100644
--- a/cpp/examples/qmf-agent/schema.xml
+++ b/cpp/examples/qmf-agent/schema.xml
@@ -1,4 +1,4 @@
-<schema package="qmf_example">
+<schema package="org.apache.qpid.agent.example">
<!--
Licensed to the Apache Software Foundation (ASF) under one
@@ -51,7 +51,14 @@
<statistic name="count" type="count64" unit="tick" desc="Counter that increases monotonically"/>
- <method name="delete"/>
+ <method name="delete"/>
</class>
+
+ <eventArguments>
+ <arg name="childName" type="sstr"/>
+ </eventArguments>
+
+ <event name="ChildCreated" args="childName"/>
+ <event name="ChildDestroyed" args="childName"/>
</schema>
diff --git a/cpp/examples/qmf-console/CMakeLists.txt b/cpp/examples/qmf-console/CMakeLists.txt
new file mode 100644
index 0000000000..4bbc7c461f
--- /dev/null
+++ b/cpp/examples/qmf-console/CMakeLists.txt
@@ -0,0 +1,23 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+add_example(qmf-console console qmfconsole)
+add_example(qmf-console printevents qmfconsole)
+add_example(qmf-console ping qmfconsole)
+add_example(qmf-console queuestats qmfconsole)
diff --git a/cpp/examples/qmf-console/Makefile.am b/cpp/examples/qmf-console/Makefile.am
new file mode 100644
index 0000000000..dd75df94f7
--- /dev/null
+++ b/cpp/examples/qmf-console/Makefile.am
@@ -0,0 +1,55 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+examplesdir=$(pkgdatadir)/examples/qmf-console
+
+MAKELDFLAGS=$(CONSOLEFLAGS)
+include $(top_srcdir)/examples/makedist.mk
+
+noinst_PROGRAMS=console printevents ping queuestats cluster-qmon
+
+console_SOURCES=console.cpp
+console_LDADD=$(CONSOLE_LIB)
+
+printevents_SOURCES=printevents.cpp
+printevents_LDADD=$(CONSOLE_LIB)
+
+ping_SOURCES=ping.cpp
+ping_LDADD=$(CONSOLE_LIB)
+
+queuestats_SOURCES=queuestats.cpp
+queuestats_LDADD=$(CONSOLE_LIB)
+
+cluster_qmon_SOURCES=cluster-qmon.cpp
+cluster_qmon_LDADD=$(CONSOLE_LIB)
+
+examples_DATA= \
+ console.cpp \
+ printevents.cpp \
+ ping.cpp \
+ queuestats.cpp \
+ cluster-qmon.cpp \
+ $(MAKEDIST)
+
+EXTRA_DIST= \
+ CMakeLists.txt \
+ qmf-console_console.vcproj \
+ qmf-console_ping.vcproj \
+ qmf-console_printevents.vcproj \
+ qmf-console_queuestats.vcproj
diff --git a/cpp/examples/qmf-console/cluster-qmon.cpp b/cpp/examples/qmf-console/cluster-qmon.cpp
new file mode 100644
index 0000000000..fe92f8a8ae
--- /dev/null
+++ b/cpp/examples/qmf-console/cluster-qmon.cpp
@@ -0,0 +1,179 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/console/ConsoleListener.h"
+#include "qpid/console/SessionManager.h"
+#include "qpid/sys/Time.h"
+#include "qpid/sys/Mutex.h"
+#include <signal.h>
+#include <map>
+
+using namespace std;
+using namespace qpid::console;
+using qpid::sys::Mutex;
+
+//
+// This example maintains connections to a number of brokers (assumed
+// to be running on localhost and at ports listed in the command line
+// arguments).
+//
+// The program then periodically polls queue information from a
+// single operational broker. This is a useful illustration of how
+// one might monitor statistics on a cluster of brokers.
+//
+
+//==============================================================
+// Main program
+//==============================================================
+
+//
+// The Main class extends ConsoleListener so it can receive broker connected/disconnected
+// notifications.
+//
+class Main : public ConsoleListener {
+ bool stopping; // Used to tell the program to exit
+ Mutex lock; // Mutex to protect the broker-map
+ map<Broker*, bool> brokerMap; // Map of broker-pointers to boolean "operational" status
+
+public:
+ Main() : stopping(false) {}
+
+ /** Invoked when a connection is established to a broker
+ */
+ void brokerConnected(const Broker& broker)
+ {
+ Mutex::ScopedLock l(lock);
+ brokerMap[const_cast<Broker*>(&broker)] = true;
+ }
+
+ /** Invoked when the connection to a broker is lost
+ */
+ void brokerDisconnected(const Broker& broker)
+ {
+ Mutex::ScopedLock l(lock);
+ brokerMap[const_cast<Broker*>(&broker)] = false;
+ }
+
+ int run(int argc, char** argv)
+ {
+ //
+ // Tune the settings for this application: We will operate synchronously only, we don't
+ // wish to use the bandwidth needed to aysnchronously receive objects or events.
+ //
+ SessionManager::Settings sessionSettings;
+ sessionSettings.rcvObjects = false;
+ sessionSettings.rcvEvents = false;
+ sessionSettings.rcvHeartbeats = false;
+
+ SessionManager sm(this, sessionSettings);
+
+ //
+ // Connect to the brokers.
+ //
+ for (int idx = 1; idx < argc; idx++) {
+ qpid::client::ConnectionSettings connSettings;
+ connSettings.host = "localhost";
+ connSettings.port = atoi(argv[idx]);
+ Broker* broker = sm.addBroker(connSettings);
+
+ Mutex::ScopedLock l(lock);
+ brokerMap[broker] = false; // initially assume broker is disconnected
+ }
+
+ //
+ // Periodically poll the first connected broker.
+ //
+ while (!stopping) {
+ //
+ // Find an operational broker
+ //
+ Broker* operationalBroker = 0;
+ {
+ Mutex::ScopedLock l(lock);
+ for (map<Broker*, bool>::iterator iter = brokerMap.begin();
+ iter != brokerMap.end(); iter++) {
+ if (iter->second) {
+ operationalBroker = iter->first;
+ break;
+ }
+ }
+ }
+
+ if (operationalBroker != 0) {
+ Object::Vector list;
+ sm.getObjects(list, "queue", operationalBroker);
+ for (Object::Vector::iterator i = list.begin(); i != list.end(); i++) {
+ cout << "queue: " << i->attrString("name");
+ cout << " bindingCount=" << i->attrUint64("bindingCount") << endl;
+ }
+ } else {
+ cout << "No operational brokers" << endl;
+ }
+
+ qpid::sys::sleep(10);
+ if (stopping)
+ break;
+ }
+
+ {
+ //
+ // The following code structure uses the mutex to protect the broker map while
+ // ensuring that sm.delBroker is called without the mutex held (which leads to
+ // a deadlock).
+ //
+ Mutex::ScopedLock l(lock);
+ map<Broker*, bool>::iterator iter = brokerMap.begin();
+ while (iter != brokerMap.end()) {
+ Broker* broker = iter->first;
+ brokerMap.erase(iter);
+ {
+ Mutex::ScopedUnlock ul(lock);
+ sm.delBroker(broker);
+ }
+ iter = brokerMap.begin();
+ }
+ }
+
+ return 0;
+ }
+
+ void stop() {
+ stopping = true;
+ }
+};
+
+Main main_program;
+
+void signal_handler(int)
+{
+ main_program.stop();
+}
+
+int main(int argc, char** argv)
+{
+ signal(SIGINT, signal_handler);
+ try {
+ return main_program.run(argc, argv);
+ } catch(std::exception& e) {
+ cout << "Top Level Exception: " << e.what() << endl;
+ }
+}
+
diff --git a/cpp/examples/qmf-console/console.cpp b/cpp/examples/qmf-console/console.cpp
new file mode 100644
index 0000000000..5700d5556f
--- /dev/null
+++ b/cpp/examples/qmf-console/console.cpp
@@ -0,0 +1,150 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/console/ConsoleListener.h"
+#include "qpid/console/SessionManager.h"
+
+using namespace std;
+using namespace qpid::console;
+
+class Listener : public ConsoleListener {
+public:
+ ~Listener() {}
+
+ void brokerConnected(const Broker& broker) {
+ cout << "brokerConnected: " << broker << endl;
+ }
+
+ void brokerDisconnected(const Broker& broker) {
+ cout << "brokerDisconnected: " << broker << endl;
+ }
+
+ void newPackage(const std::string& name) {
+ cout << "newPackage: " << name << endl;
+ }
+
+ void newClass(const ClassKey& classKey) {
+ cout << "newClass: key=" << classKey << endl;
+ }
+
+ void newAgent(const Agent& agent) {
+ cout << "newAgent: " << agent << endl;
+ }
+
+ void delAgent(const Agent& agent) {
+ cout << "delAgent: " << agent << endl;
+ }
+
+ void objectProps(Broker& broker, Object& object) {
+ cout << "objectProps: broker=" << broker << " object=" << object << endl;
+ }
+
+ void objectStats(Broker& broker, Object& object) {
+ cout << "objectStats: broker=" << broker << " object=" << object << endl;
+ }
+
+ void event(Event& event) {
+ cout << "event: " << event << endl;
+ }
+};
+
+
+//==============================================================
+// Main program
+//==============================================================
+int main_int(int /*argc*/, char** /*argv*/)
+{
+ //Listener listener;
+ qpid::client::ConnectionSettings settings;
+
+ cout << "Creating SessionManager" << endl;
+ SessionManager sm;
+ cout << "Adding broker" << endl;
+ Broker* broker;
+
+ broker = sm.addBroker(settings);
+
+ cout << "Package List:" << endl;
+ vector<string> packages;
+ sm.getPackages(packages);
+ for (vector<string>::iterator iter = packages.begin(); iter != packages.end(); iter++) {
+ cout << " " << *iter << endl;
+ SessionManager::KeyVector classKeys;
+ sm.getClasses(classKeys, *iter);
+ for (SessionManager::KeyVector::iterator cIter = classKeys.begin();
+ cIter != classKeys.end(); cIter++)
+ cout << " " << *cIter << endl;
+ }
+
+ Object::Vector list;
+ cout << "getting exchanges..." << endl;
+ sm.getObjects(list, "exchange");
+ cout << " returned " << list.size() << " elements" << endl;
+
+ for (Object::Vector::iterator i = list.begin(); i != list.end(); i++) {
+ cout << "exchange: " << *i << endl;
+ }
+
+ list.clear();
+ cout << "getting queues..." << endl;
+ sm.getObjects(list, "queue");
+ cout << " returned " << list.size() << " elements" << endl;
+
+ for (Object::Vector::iterator i = list.begin(); i != list.end(); i++) {
+ cout << "queue: " << *i << endl;
+ cout << " bindingCount=" << i->attrUint("bindingCount") << endl;
+ cout << " arguments=" << i->attrMap("arguments") << endl;
+ }
+
+ list.clear();
+ sm.getObjects(list, "broker");
+ if (list.size() == 1) {
+ Object& broker = *list.begin();
+
+ cout << "Broker: " << broker << endl;
+
+ Object::AttributeMap args;
+ MethodResponse result;
+ args.addUint("sequence", 1);
+ args.addString("body", "Testing...");
+
+ cout << "Call echo method..." << endl;
+ broker.invokeMethod("echo", args, result);
+ cout << "Result: code=" << result.code << " text=" << result.text << endl;
+ for (Object::AttributeMap::iterator aIter = result.arguments.begin();
+ aIter != result.arguments.end(); aIter++) {
+ cout << " Output Arg: " << aIter->first << " => " << aIter->second->str() << endl;
+ }
+ }
+
+ sm.delBroker(broker);
+ return 0;
+}
+
+int main(int argc, char** argv)
+{
+ try {
+ return main_int(argc, argv);
+ } catch(std::exception& e) {
+ cout << "Top Level Exception: " << e.what() << endl;
+ }
+}
+
diff --git a/cpp/examples/qmf-console/ping.cpp b/cpp/examples/qmf-console/ping.cpp
new file mode 100644
index 0000000000..405c15f1c4
--- /dev/null
+++ b/cpp/examples/qmf-console/ping.cpp
@@ -0,0 +1,134 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/console/SessionManager.h"
+#include "qpid/sys/Time.h"
+
+using namespace std;
+using namespace qpid::console;
+
+//==============================================================
+// Main program
+//==============================================================
+int main_int(int /*argc*/, char** /*argv*/)
+{
+ //
+ // Declare connection settings for the messaging broker. The settings default to
+ // localhost:5672 with user guest (password guest). Refer to the header file
+ // <qpid/client/ConnectionSettings.h> for full details.
+ //
+ qpid::client::ConnectionSettings connSettings;
+
+ //
+ // Declare the (optional) session manager settings. Override the default timeout
+ // for methods calls to be 2 seconds.
+ //
+ SessionManager::Settings smSettings;
+ smSettings.methodTimeout = 2;
+ smSettings.getTimeout = 2;
+
+ //
+ // Declare the console session manager. With a null listener argument, it defaults to
+ // synchronous-only access mode.
+ //
+ SessionManager sm(0, smSettings);
+
+ //
+ // Add a broker connection to the session manager.
+ //
+ Broker* broker = sm.addBroker(connSettings);
+
+ uint32_t count = 5; // The number of echo requests we will send to the broker.
+ Object::Vector list; // A container for holding objects retrieved from the broker.
+
+ for (uint32_t iter = 0; iter < count; iter++) {
+ cout << "Ping Broker: " << broker->getUrl() << "... ";
+ cout.flush();
+
+ //
+ // Query for a list of 'broker' objects from the Management Database
+ //
+ sm.getObjects(list, "broker");
+
+ //
+ // We expect one object (since we are connected to only one broker)
+ //
+ if (list.size() == 1) {
+ Object& brokerObject = *(list.begin());
+
+ //
+ // Declare a container for arguments to be sent with the "echo" method
+ // that we will invoke on the remote "broker" object.
+ //
+ Object::AttributeMap args;
+
+ //
+ // Declare a container for the result of the method invocation.
+ //
+ MethodResponse result;
+
+ //
+ // Set the values of the input arguments.
+ //
+ args.addUint("sequence", iter);
+ args.addString("body", "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+ //
+ // Invoke the method. This is a synchronous operation that will block until
+ // the method completes and returns a result.
+ //
+ brokerObject.invokeMethod("echo", args, result);
+
+ //
+ // result.code is the return code (0 => Success)
+ // result.text is the return text
+ // result.arguments is a container (of type Object::AttributeMap) that holds
+ // the output arguments (if any) from the method.
+ //
+ cout << "Result: code=" << result.code << " text=" << result.text;
+ if (result.code == 0)
+ cout << " seq=" << result.arguments["sequence"]->asUint();
+ cout << endl;
+
+ if (result.code == 0 && iter < count - 1)
+ qpid::sys::sleep(1);
+ } else {
+ cout << "Disconnected..." << endl;
+ qpid::sys::sleep(1);
+ }
+ }
+
+ //
+ // Disconnect the broker from the session manager.
+ //
+ sm.delBroker(broker);
+ return 0;
+}
+
+int main(int argc, char** argv)
+{
+ try {
+ return main_int(argc, argv);
+ } catch(std::exception& e) {
+ cout << "Top Level Exception: " << e.what() << endl;
+ }
+}
+
diff --git a/cpp/examples/qmf-console/printevents.cpp b/cpp/examples/qmf-console/printevents.cpp
new file mode 100644
index 0000000000..3a0a2ab68b
--- /dev/null
+++ b/cpp/examples/qmf-console/printevents.cpp
@@ -0,0 +1,125 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/console/ConsoleListener.h"
+#include "qpid/console/SessionManager.h"
+#include "qpid/sys/Time.h"
+#include <signal.h>
+
+using namespace std;
+using namespace qpid::console;
+
+//
+// Define a listener class to receive asynchronous events.
+//
+class Listener : public ConsoleListener {
+public:
+ void brokerConnected(const Broker& broker) {
+ cout << qpid::sys::now() << " NOTIC qpid-printevents:brokerConnected broker=" <<
+ broker.getUrl() << endl;
+ }
+
+ void brokerDisconnected(const Broker& broker) {
+ cout << qpid::sys::now() << " NOTIC qpid-printevents:brokerDisconnected broker=" <<
+ broker.getUrl() << endl;
+ }
+
+ void event(Event& event) {
+ cout << event << endl;
+ }
+};
+
+
+//==============================================================
+// Main program
+//==============================================================
+struct Main {
+ bool stopping;
+
+ Main() : stopping(false) {}
+
+ int run(int /*argc*/, char** /*argv*/)
+ {
+ //
+ // Declare an instance of our listener.
+ //
+ Listener listener;
+
+ //
+ // Declare connection settings for the messaging broker. The settings default to
+ // localhost:5672 with user guest (password guest). Refer to the header file
+ // <qpid/client/ConnectionSettings.h> for full details.
+ //
+ qpid::client::ConnectionSettings connSettings;
+
+ //
+ // Declare the (optional) session manager settings. Disable the reception of
+ // object updates and heartbeats. Note that by disabling the reception of things
+ // we don't need, we don't unnecessarily use network bandwidth.
+ //
+ SessionManager::Settings smSettings;
+ smSettings.rcvObjects = false;
+ smSettings.rcvHeartbeats = false;
+
+ //
+ // Declare the console session manager.
+ //
+ SessionManager sm(&listener, smSettings);
+
+ //
+ // Add a broker connection to the session manager. If desired, multiple brokers may
+ // be connected.
+ //
+ Broker* broker = sm.addBroker(connSettings);
+
+ //
+ // Sleep indefinitely while asynchronous events are handled by the listener.
+ //
+ while (!stopping)
+ qpid::sys::sleep(1);
+
+ sm.delBroker(broker);
+ return 0;
+ }
+
+ void stop()
+ {
+ stopping = true;
+ }
+};
+
+Main main_program;
+
+void signal_handler(int)
+{
+ main_program.stop();
+}
+
+int main(int argc, char** argv)
+{
+ signal(SIGINT, signal_handler);
+ try {
+ return main_program.run(argc, argv);
+ } catch(std::exception& e) {
+ cout << "Top Level Exception: " << e.what() << endl;
+ }
+}
+
diff --git a/cpp/examples/qmf-console/qmf-console_console.vcproj b/cpp/examples/qmf-console/qmf-console_console.vcproj
new file mode 100644
index 0000000000..e957af6181
--- /dev/null
+++ b/cpp/examples/qmf-console/qmf-console_console.vcproj
@@ -0,0 +1,394 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="qmf_console_console"
+ ProjectGUID="{490473E1-FECA-1BAD-2E13-3FFA2B8669C3}"
+ RootNamespace="qmf_console_console"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\qmf_console_console\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib qmfconsoled.lib"
+ OutputFile="$(OutDir)\console.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\qmf_console_console\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib qmfconsole.lib"
+ OutputFile="$(OutDir)\console.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\qmf_console_console\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib qmfconsoled.lib"
+ OutputFile="$(OutDir)\console.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\qmf_console_console\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib qmfconsole.lib"
+ OutputFile="$(OutDir)\console.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="console.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="ConnectionOptions.h">
+ </File>
+ <File
+ RelativePath="TestOptions.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/qmf-console/qmf-console_ping.vcproj b/cpp/examples/qmf-console/qmf-console_ping.vcproj
new file mode 100644
index 0000000000..21e01389ad
--- /dev/null
+++ b/cpp/examples/qmf-console/qmf-console_ping.vcproj
@@ -0,0 +1,419 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="qmf_console_ping"
+ ProjectGUID="{C1FFDE95-3442-49AE-9985-7EEE3D45B4A3}"
+ RootNamespace="qmf_console_ping"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="0"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\qmf_console_ping\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib qmfconsoled.lib"
+ OutputFile="$(OutDir)\ping.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\qmf_console_ping\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib qmfconsoled.lib"
+ OutputFile="$(OutDir)\ping.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\qmf_console_ping\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib qmfconsole.lib"
+ OutputFile="$(OutDir)\ping.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\qmf_console_ping\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib qmfconsole.lib"
+ OutputFile="$(OutDir)\ping.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c"
+ >
+ <File
+ RelativePath="ping.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh"
+ >
+ <File
+ RelativePath="ConnectionOptions.h"
+ >
+ </File>
+ <File
+ RelativePath="TestOptions.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/qmf-console/qmf-console_printevents.vcproj b/cpp/examples/qmf-console/qmf-console_printevents.vcproj
new file mode 100644
index 0000000000..478b71b678
--- /dev/null
+++ b/cpp/examples/qmf-console/qmf-console_printevents.vcproj
@@ -0,0 +1,394 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="qmf_console_printevents"
+ ProjectGUID="{72C74624-FECA-1BAD-2E13-3FFA2B8669C3}"
+ RootNamespace="qmf_console_printevents"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\qmf_console_printevents\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib qmfconsoled.lib"
+ OutputFile="$(OutDir)\printevents.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\qmf_console_printevents\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib qmfconsole.lib"
+ OutputFile="$(OutDir)\printevents.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\qmf_console_printevents\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib qmfconsoled.lib"
+ OutputFile="$(OutDir)\printevents.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\qmf_console_printevents\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib qmfconsole.lib"
+ OutputFile="$(OutDir)\printevents.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="printevents.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="ConnectionOptions.h">
+ </File>
+ <File
+ RelativePath="TestOptions.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/qmf-console/qmf-console_queuestats.vcproj b/cpp/examples/qmf-console/qmf-console_queuestats.vcproj
new file mode 100644
index 0000000000..ee0d2acc98
--- /dev/null
+++ b/cpp/examples/qmf-console/qmf-console_queuestats.vcproj
@@ -0,0 +1,394 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="qmf_console_queuestats"
+ ProjectGUID="{B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}"
+ RootNamespace="qmf_console_queuestats"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\qmf_console_queuestats\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib qmfconsoled.lib"
+ OutputFile="$(OutDir)\queuestats.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\qmf_console_queuestats\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib qmfconsole.lib"
+ OutputFile="$(OutDir)\queuestats.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\qmf_console_queuestats\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib qmfconsoled.lib"
+ OutputFile="$(OutDir)\queuestats.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\qmf_console_queuestats\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib qmfconsole.lib"
+ OutputFile="$(OutDir)\queuestats.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="queuestats.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="ConnectionOptions.h">
+ </File>
+ <File
+ RelativePath="TestOptions.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/qmf-console/queuestats.cpp b/cpp/examples/qmf-console/queuestats.cpp
new file mode 100644
index 0000000000..2c38777ad8
--- /dev/null
+++ b/cpp/examples/qmf-console/queuestats.cpp
@@ -0,0 +1,142 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/console/ConsoleListener.h"
+#include "qpid/console/SessionManager.h"
+#include "qpid/sys/Time.h"
+
+using namespace std;
+using namespace qpid::console;
+
+//
+// Declare a subclass of ConsoleListener to receive asynchronous data.
+//
+class Listener : public ConsoleListener {
+
+ //
+ // Declare a map from ObjectId to string to store queue names by their object IDs.
+ //
+ typedef map<ObjectId, string> QueueMap;
+ QueueMap queueMap;
+public:
+ ~Listener() {}
+
+ //
+ // Receive property updates from the agent.
+ //
+ void objectProps(Broker& /*broker*/, Object& object) {
+ string name = object.attrString("name");
+ ObjectId oid = object.getObjectId();
+ QueueMap::iterator iter = queueMap.find(oid);
+
+ if (iter == queueMap.end()) {
+ //
+ // Object is not in the map. Learn it.
+ //
+ cout << "New Queue: " << name << endl;
+ queueMap[oid] = name;
+ }
+ }
+
+ //
+ // Receive statistic updates from the agent.
+ //
+ void objectStats(Broker& /*broker*/, Object& object) {
+ ObjectId oid = object.getObjectId();
+ QueueMap::iterator iter = queueMap.find(oid);
+ if (iter == queueMap.end())
+ //
+ // Object id is not in the map. We are not interested in this update.
+ //
+ return;
+
+ cout << "Stats for: " << iter->second << endl;
+ cout << " msgTotalEnqueues = " << object.attrUint64("msgTotalEnqueues") << endl;
+ cout << " msgTotalDequeues = " << object.attrUint64("msgTotalDequeues") << endl;
+ cout << " msgDepth = " << object.attrUint("msgDepth") << endl;
+
+ if (object.isDeleted()) {
+ //
+ // Object was deleted and is in the map. Remove it.
+ //
+ cout << "Queue Deleted: " << iter->second << endl;
+ queueMap.erase(oid);
+ }
+
+ //
+ // Note that the object-delete logic is done after processing statistics.
+ // This allows us to get the "final" statistics for a deleted object. It also
+ // assures that very short-lived objects are accounted for (i.e. created, used,
+ // and destroyed all within a single reporting interval).
+ //
+ }
+};
+
+//==============================================================
+// Main program
+//==============================================================
+int main_int(int /*argc*/, char** /*argv*/)
+{
+ Listener listener;
+
+ //
+ // Tune the settings for this application: We wish to receive objects but not events.
+ // By using "userBindings", we can restrict which objects we receive updates for.
+ //
+ SessionManager::Settings sessionSettings;
+ sessionSettings.rcvObjects = true;
+ sessionSettings.rcvEvents = false;
+ sessionSettings.rcvHeartbeats = false;
+ sessionSettings.userBindings = true;
+
+ SessionManager sm(&listener, sessionSettings);
+
+ //
+ // We want to receive updates only for the broker queue object.
+ //
+ sm.bindClass("org.apache.qpid.broker", "queue");
+
+ //
+ // Connect to the broker.
+ //
+ qpid::client::ConnectionSettings connSettings;
+ Broker* broker = sm.addBroker(connSettings);
+
+ //
+ // Sleep while the listener does all the work asynchronously.
+ //
+ for (;;) {
+ qpid::sys::sleep(1);
+ }
+
+ sm.delBroker(broker);
+ return 0;
+}
+
+int main(int argc, char** argv)
+{
+ try {
+ return main_int(argc, argv);
+ } catch(std::exception& e) {
+ cout << "Top Level Exception: " << e.what() << endl;
+ }
+}
+
diff --git a/cpp/examples/request-response/CMakeLists.txt b/cpp/examples/request-response/CMakeLists.txt
new file mode 100644
index 0000000000..873a0cfa86
--- /dev/null
+++ b/cpp/examples/request-response/CMakeLists.txt
@@ -0,0 +1,21 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+add_example(request-response client)
+add_example(request-response server)
diff --git a/cpp/examples/request-response/Makefile.am b/cpp/examples/request-response/Makefile.am
index d2cddf3cfb..de59f3b834 100644
--- a/cpp/examples/request-response/Makefile.am
+++ b/cpp/examples/request-response/Makefile.am
@@ -1,5 +1,24 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
examplesdir=$(pkgdatadir)/examples/request-response
+MAKELDFLAGS=$(CLIENTFLAGS)
include $(top_srcdir)/examples/makedist.mk
noinst_PROGRAMS=client server
@@ -17,14 +36,12 @@ examples_DATA= \
EXTRA_DIST= \
$(examples_DATA) \
+ CMakeLists.txt \
verify \
verify.in \
verify_cpp_python \
verify_cpp_python.in \
verify_python_cpp \
- verify_python_cpp.in
-
-
-
-
-
+ verify_python_cpp.in \
+ request-response_client.vcproj \
+ request-response_server.vcproj
diff --git a/cpp/examples/request-response/client.cpp b/cpp/examples/request-response/client.cpp
index 0ee0e78c92..679d1c5fc2 100644
--- a/cpp/examples/request-response/client.cpp
+++ b/cpp/examples/request-response/client.cpp
@@ -26,25 +26,41 @@
* This program is one of two programs that illustrate the
* request/response pattern.
*
- * client.cpp (this program)
*
- * Make requests of a service, print the response.
+ * client.cpp (this program)
+ *
+ * A client application that sends messages to the "amq.direct"
+ * exchange, using the routing key "request" to route messages to
+ * the server.
*
- * service.cpp
+ * Each instance of the client creates its own private response
+ * queue, binding it to the "amq.direct" exchange using it's
+ * session identifier as the routing key, and places its session
+ * identifier in the "reply-to" property of each message it sends.
+ *
+ *
+ * server.cpp
+ *
+ * A service that accepts messages from a request queue, converts
+ * their content to upper case, and sends the result to the
+ * original sender.
+ *
+ * This program creates a request queue, binds it to "amq.direct"
+ * using the routing key "request", then receives messages from
+ * the request queue. Each incoming message is converted to upper
+ * case, then sent to the "amq.direct" exchange using the
+ * request's reply-to property as the routing key for the
+ * response.
*
- * Accept requests, reverse the letters in each message, and
- * return it as a response.
*
*/
-
#include <qpid/client/Connection.h>
-#include <qpid/client/SubscriptionManager.h>
#include <qpid/client/Session.h>
#include <qpid/client/Message.h>
#include <qpid/client/MessageListener.h>
+#include <qpid/client/SubscriptionManager.h>
-#include <unistd.h>
#include <cstdlib>
#include <iostream>
@@ -53,6 +69,9 @@
using namespace qpid::client;
using namespace qpid::framing;
+using std::stringstream;
+using std::string;
+
class Listener : public MessageListener{
private:
SubscriptionManager& subscriptions;
@@ -76,14 +95,11 @@ void Listener::received(Message& message) {
}
-using std::stringstream;
-using std::string;
int main(int argc, char** argv) {
const char* host = argc>1 ? argv[1] : "127.0.0.1";
int port = argc>2 ? atoi(argv[2]) : 5672;
Connection connection;
- Message request;
try {
connection.open(host, port);
Session session = connection.newSession();
@@ -105,6 +121,7 @@ int main(int argc, char** argv) {
// Each client sends the name of their own response queue so
// the service knows where to route messages.
+ Message request;
request.getDeliveryProperties().setRoutingKey("request");
request.getMessageProperties().setReplyTo(ReplyTo("amq.direct", response_queue.str()));
@@ -126,9 +143,7 @@ int main(int argc, char** argv) {
for (int i=0; i<4; i++) {
request.setData(s[i]);
- // Asynchronous transfer sends messages as quickly as
- // possible without waiting for confirmation.
- async(session).messageTransfer(arg::content=request, arg::destination="amq.direct");
+ session.messageTransfer(arg::content=request, arg::destination="amq.direct");
std::cout << "Request: " << s[i] << std::endl;
}
diff --git a/cpp/examples/request-response/request-response_client.vcproj b/cpp/examples/request-response/request-response_client.vcproj
new file mode 100644
index 0000000000..3c98482400
--- /dev/null
+++ b/cpp/examples/request-response/request-response_client.vcproj
@@ -0,0 +1,394 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="request_response_client"
+ ProjectGUID="{2691FE1E-FECA-1BAD-BD3A-8A467D0C5CCC}"
+ RootNamespace="request_response_client"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\request_response_client\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\client.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\request_response_client\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\client.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\request_response_client\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\client.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\request_response_client\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\client.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="client.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="ConnectionOptions.h">
+ </File>
+ <File
+ RelativePath="TestOptions.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/request-response/request-response_server.vcproj b/cpp/examples/request-response/request-response_server.vcproj
new file mode 100644
index 0000000000..f685f9d949
--- /dev/null
+++ b/cpp/examples/request-response/request-response_server.vcproj
@@ -0,0 +1,394 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="request_response_server"
+ ProjectGUID="{46817425-FECA-1BAD-BD3A-8A467D0C5CCC}"
+ RootNamespace="request_response_server"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\request_response_server\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\server.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\request_response_server\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\server.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\request_response_server\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\server.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\request_response_server\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\server.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="server.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="ConnectionOptions.h">
+ </File>
+ <File
+ RelativePath="TestOptions.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/request-response/server.cpp b/cpp/examples/request-response/server.cpp
index df189cfdd8..65a4717b35 100644
--- a/cpp/examples/request-response/server.cpp
+++ b/cpp/examples/request-response/server.cpp
@@ -26,30 +26,46 @@
* This program is one of two programs that illustrate the
* request/response pattern.
*
- * client.cpp
*
- * Make requests of a service, print the response.
+ * client.cpp
+ *
+ * A client application that sends messages to the "amq.direct"
+ * exchange, using the routing key "request" to route messages to
+ * the server.
*
- * server.cpp (this program)
+ * Each instance of the client creates its own private response
+ * queue, binding it to the "amq.direct" exchange using it's
+ * session identifier as the routing key, and places its session
+ * identifier in the "reply-to" property of each message it sends.
+ *
+ *
+ * server.cpp (this program)
+ *
+ * A service that accepts messages from a request queue, converts
+ * their content to upper case, and sends the result to the
+ * original sender.
+ *
+ * This program creates a request queue, binds it to "amq.direct"
+ * using the routing key "request", then receives messages from
+ * the request queue. Each incoming message is converted to upper
+ * case, then sent to the "amq.direct" exchange using the
+ * request's reply-to property as the routing key for the
+ * response.
*
- * Accept requests, reverse the letters in each message, and
- * return it as a response.
*
*/
#include <qpid/client/Connection.h>
-#include <qpid/client/SubscriptionManager.h>
#include <qpid/client/Session.h>
+
#include <qpid/client/AsyncSession.h>
#include <qpid/client/Message.h>
#include <qpid/client/MessageListener.h>
+#include <qpid/client/SubscriptionManager.h>
-
-#include <unistd.h>
#include <cstdlib>
#include <iostream>
-#include <algorithm>
#include <sstream>
#include <string>
@@ -105,7 +121,7 @@ int main(int argc, char** argv) {
const char* host = argc>1 ? argv[1] : "127.0.0.1";
int port = argc>2 ? atoi(argv[2]) : 5672;
Connection connection;
- Message message;
+
try {
connection.open(host, port);
Session session = connection.newSession();
diff --git a/cpp/examples/request-response/verify b/cpp/examples/request-response/verify
index 76007ff8d2..dee82413e7 100644
--- a/cpp/examples/request-response/verify
+++ b/cpp/examples/request-response/verify
@@ -1,3 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
background "Waiting" ./server
clients ./client
diff --git a/cpp/examples/test.txt b/cpp/examples/test.txt
new file mode 100644
index 0000000000..96921efce5
--- /dev/null
+++ b/cpp/examples/test.txt
@@ -0,0 +1 @@
+Test file for repository replication. Please ignore. (Update)
diff --git a/cpp/examples/tradedemo/CMakeLists.txt b/cpp/examples/tradedemo/CMakeLists.txt
new file mode 100644
index 0000000000..e61fc1467d
--- /dev/null
+++ b/cpp/examples/tradedemo/CMakeLists.txt
@@ -0,0 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+add_example(tradedemo topic_listener)
+add_example(tradedemo topic_publisher)
+add_example(tradedemo declare_queues)
diff --git a/cpp/examples/tradedemo/Makefile.am b/cpp/examples/tradedemo/Makefile.am
new file mode 100644
index 0000000000..f4d8686d05
--- /dev/null
+++ b/cpp/examples/tradedemo/Makefile.am
@@ -0,0 +1,46 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+examplesdir=$(pkgdatadir)/examples/tradedemo
+
+MAKELDFLAGS=$(CLIENTFLAGS)
+include $(top_srcdir)/examples/makedist.mk
+
+noinst_PROGRAMS=topic_listener topic_publisher declare_queues
+
+topic_listener_SOURCES=topic_listener.cpp
+topic_listener_LDADD=$(CLIENT_LIB)
+
+topic_publisher_SOURCES=topic_publisher.cpp
+topic_publisher_LDADD=$(CLIENT_LIB)
+
+declare_queues_SOURCES=declare_queues.cpp
+declare_queues_LDADD=$(CLIENT_LIB)
+
+
+examples_DATA= \
+ topic_listener.cpp \
+ topic_publisher.cpp \
+ declare_queues.cpp \
+ $(MAKEDIST)
+
+EXTRA_DIST= \
+ CMakeLists.txt \
+ tradedemo_declare_queues.vcproj \
+ tradedemo_topic_listener.vcproj \
+ tradedemo_topic_publisher.vcproj
diff --git a/cpp/examples/tradedemo/declare_queues.cpp b/cpp/examples/tradedemo/declare_queues.cpp
new file mode 100644
index 0000000000..b1f2cc3510
--- /dev/null
+++ b/cpp/examples/tradedemo/declare_queues.cpp
@@ -0,0 +1,98 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+/**
+ * topic_publisher.cpp:
+ *
+ * This program is one of three programs designed to be used
+ * together. These programs implement a publish-subscribe example
+ * using the "amq.topic" exchange. In the example multiple listeners
+ * can subscribe to the same queues for TTL messages.
+ * The TTL messages are all ticker price data. Messages are
+ * browsed and therefore shared among the multiple listeners.
+ * Messages timeout using TTL so that they don't stay in the queue
+ * for too long and fill it up.
+ * Local exclusive LVQ are also declared for market data.
+ *
+ * declare_queues.cpp
+ *
+ * Declares several non-exclusive queues bound to the amq:topic exchange
+ *
+ * topic_publisher.cpp
+ *
+ * Sends messages to the "amq.topic" exchange, using the
+ * multipart routing keys for ticker price and market data
+ * Ticker messages are sent using a TTL value.
+ *
+ * topic_listener.cpp (this program)
+ *
+ * Subscribes to non-exclusive queues in NOT_ACQUIRE mode for
+ * ticker price data and declares two LVQs for market data.
+ *
+ * Multiple listeners can be run at the same time.
+ *
+ */
+
+#include <qpid/client/Connection.h>
+#include <qpid/client/Session.h>
+
+
+using namespace qpid::client;
+using namespace qpid::framing;
+
+
+int main(int argc, char** argv) {
+ const char* host = argc>1 ? argv[1] : "127.0.0.1";
+ int port = argc>2 ? atoi(argv[2]) : 5672;
+ Connection connection;
+
+ try {
+ connection.open(host, port);
+ Session session = connection.newSession();
+
+
+ //--------- Main body of program --------------------------------------------
+
+ // Create a queue named "message_queue", and route all messages whose
+ // routing key is "routing_key" to this newly created queue.
+
+ session.queueDeclare(arg::queue="TICKER.NYSE", arg::exclusive=false);
+ session.exchangeBind(arg::exchange="amq.topic", arg::queue="TICKER.NYSE", arg::bindingKey="TICKER.NYSE.#");
+ std::cout << "Declared queue Ticker NYSE non-exclusive with amq:topic binding TICKER.NYSE.#" << std::endl;
+ session.queueDeclare(arg::queue="TICKER.NASDAQ", arg::exclusive=false);
+ session.exchangeBind(arg::exchange="amq.topic", arg::queue="TICKER.NASDAQ", arg::bindingKey="TICKER.NASDAQ.#");
+ std::cout << "Declared queue Ticker NASDAQ non-exclusive with amq:topic binding TICKER.NASDAQ.#" << std::endl;
+
+
+ //-----------------------------------------------------------------------------
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+
+}
+
+
+
diff --git a/cpp/examples/tradedemo/topic_listener.cpp b/cpp/examples/tradedemo/topic_listener.cpp
new file mode 100644
index 0000000000..c488e7fb69
--- /dev/null
+++ b/cpp/examples/tradedemo/topic_listener.cpp
@@ -0,0 +1,183 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/**
+ * topic_publisher.cpp:
+ *
+ * This program is one of three programs designed to be used
+ * together. These programs implement a publish-subscribe example
+ * using the "amq.topic" exchange. In the example multiple listeners
+ * can subscribe to the same queues for TTL messages.
+ * The TTL messages are all ticker price data. Messages are
+ * browsed and therefore shared among the multiple listeners.
+ * Messages timeout using TTL so that they don't stay in the queue
+ * for too long and fill it up.
+ * Local exclusive LVQ are also declared for market data.
+ *
+ * declare_queues.cpp
+ *
+ * Declares several non-exclusive queues bound to the amq:topic exchange
+ *
+ * topic_publisher.cpp
+ *
+ * Sends messages to the "amq.topic" exchange, using the
+ * multipart routing keys for ticker price and market data
+ * Ticker messages are sent using a TTL value.
+ *
+ * topic_listener.cpp (this program)
+ *
+ * Subscribes to non-exclusive queues in NOT_ACQUIRE mode for
+ * ticker price data and declares two LVQs for market data.
+ *
+ * Multiple listeners can be run at the same time.
+ *
+ */
+
+#include <qpid/client/Connection.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/MessageListener.h>
+#include <qpid/client/SubscriptionManager.h>
+#include "qpid/client/QueueOptions.h"
+
+#include <cstdlib>
+#include <iostream>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+
+
+class Listener : public MessageListener {
+ private:
+ Session& session;
+ SubscriptionManager subscriptions;
+ public:
+ Listener(Session& session);
+ virtual void subscribeTTLQueue(std::string queue);
+ virtual void subscribeLVQQueue(std::string queue);
+ virtual void received(Message& message);
+ virtual void listen();
+ ~Listener() { };
+};
+
+
+/*
+ * Listener::Listener
+ *
+ * Subscribe to the queue, route it to a client destination for the
+ * listener. (The destination name merely identifies the destination
+ * in the listener, you can use any name as long as you use the same
+ * name for the listener).
+ */
+
+Listener::Listener(Session& session) :
+ session(session),
+ subscriptions(session)
+{
+}
+
+
+void Listener::subscribeTTLQueue(std::string queue) {
+
+ /*
+ * Subscribe to the queue using the subscription manager.
+ * The queues were declared elsewhere alog with their bindings.
+ */
+
+ std::cout << "Subscribing to queue " << queue << std::endl;
+ subscriptions.subscribe(*this, queue);
+ // Will not acquire messages but instead browse them.
+ subscriptions.setAcquireMode(message::ACQUIRE_MODE_NOT_ACQUIRED);
+}
+
+void Listener::subscribeLVQQueue(std::string queue) {
+
+ /*
+ * Declare and subscribe to the queue using the subscription manager.
+ */
+
+ QueueOptions qo;
+ qo.setOrdering(LVQ);
+ std::string binding = queue + ".#";
+ queue += session.getId().getName();
+ session.queueDeclare(arg::queue=queue, arg::exclusive=true, arg::arguments=qo);
+ session.exchangeBind(arg::exchange="amq.topic", arg::queue=queue, arg::bindingKey=binding);
+ std::cout << "Declared queue " << queue << " non-exclusive with amq:topic binding " << binding << std::endl;
+ std::cout << "Subscribing to queue " << queue << std::endl;
+ subscriptions.subscribe(*this, queue, SubscriptionSettings(FlowControl::unlimited(), ACCEPT_MODE_NONE));
+
+}
+
+void Listener::received(Message& message) {
+ // If you want to see the destination you can swap the following lines.
+ // std::cout << message.getDestination() << "\t" << message.getData() << std::endl;
+ std::cout << message.getData() << std::endl;
+
+}
+
+void Listener::listen() {
+ // Receive messages
+ subscriptions.run();
+}
+
+int main(int argc, char** argv) {
+ const char* host = argc>1 ? argv[1] : "127.0.0.1";
+ int port = argc>2 ? atoi(argv[2]) : 5672;
+
+ Connection connection;
+ try {
+ connection.open(host, port);
+ Session session = connection.newSession();
+
+ //--------- Main body of program --------------------------------------------
+
+
+
+ // Create a listener for the session
+
+ Listener listener(session);
+
+ // Subscribe to messages on the queues we are interested in
+
+ listener.subscribeTTLQueue("TICKER.NASDAQ");
+ listener.subscribeTTLQueue("TICKER.NYSE");
+
+ listener.subscribeLVQQueue("MRKT.NASDAQ");
+ listener.subscribeLVQQueue("MRKT.NYSE");
+
+ std::cout << "Starting Listener <Ctrl>-C to exit." << std::endl;
+ std::cout << "Listening for messages ..." << std::endl;
+
+ // Give up control and receive messages
+ listener.listen();
+
+
+ //-----------------------------------------------------------------------------
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/cpp/examples/tradedemo/topic_publisher.cpp b/cpp/examples/tradedemo/topic_publisher.cpp
new file mode 100644
index 0000000000..e22c185bc7
--- /dev/null
+++ b/cpp/examples/tradedemo/topic_publisher.cpp
@@ -0,0 +1,271 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/**
+ * topic_publisher.cpp:
+ *
+ * This program is one of three programs designed to be used
+ * together. These programs implement a publish-subscribe example
+ * using the "amq.topic" exchange. In the example multiple listeners
+ * can subscribe to the same queues for TTL messages.
+ * The TTL messages are all ticker price data. Messages are
+ * browsed and therefore shared among the multiple listeners.
+ * Messages timeout using TTL so that they don't stay in the queue
+ * for too long and fill it up.
+ * Local exclusive LVQ are also declared for market data.
+ *
+ * declare_queues.cpp
+ *
+ * Declares several non-exclusive queues bound to the amq:topic exchange
+ *
+ * topic_publisher.cpp
+ *
+ * Sends messages to the "amq.topic" exchange, using the
+ * multipart routing keys for ticker price and market data
+ * Ticker messages are sent using a TTL value.
+ *
+ * topic_listener.cpp (this program)
+ *
+ * Subscribes to non-exclusive queues in NOT_ACQUIRE mode for
+ * ticker price data and declares two LVQs for market data.
+ *
+ * Multiple listeners can be run at the same time.
+ *
+ */
+
+
+#include <qpid/client/Connection.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/AsyncSession.h>
+#include <qpid/client/Message.h>
+#include "qpid/client/QueueOptions.h"
+
+
+#include <stdlib.h>
+#include <cstdlib>
+#include <iostream>
+#include <set>
+#include <sstream>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using std::stringstream;
+using std::string;
+
+class Publisher {
+ private:
+ Session& session;
+ int ttl_time;
+ unsigned long seq;
+
+ unsigned short high_[6];
+ unsigned short low_[6];
+ unsigned long shares_[6];
+ unsigned long volume_[6];
+ QueueOptions args;
+
+ public:
+ Publisher( Session& session,
+ const int ttl_time,
+ const unsigned long shares[6]);
+
+ virtual void publish_ticker(const std::string queue, unsigned short& curr_price);
+ virtual void publish_market(const std::string queue, unsigned short& curr_price, int i);
+ virtual ~Publisher() { };
+};
+
+Publisher::Publisher(Session& session, int ttl_time, const unsigned long shares[6]) :
+ session(session),
+ ttl_time(ttl_time),
+ seq(0)
+{
+ for (unsigned short i=0; i < 6; i++) {
+ high_[i] = 0;
+ low_[i] = 9999;
+ volume_[i] = 0;
+ shares_[i] = shares[i];
+ }
+}
+
+
+void Publisher::publish_ticker(const std::string symbol, unsigned short& curr_price)
+{
+ Message message;
+
+ // Set the routing key once, we'll use the same routing key for all
+ // messages.
+
+ std::string routing_key = "TICKER." + symbol;
+ std::cout << "Setting routing key:" << routing_key << std::endl;
+ message.getDeliveryProperties().setRoutingKey(routing_key);
+
+ // Randomally generate some price flucuations
+ bool mvmnt;
+ unsigned short change = rand() % 3;
+ if (rand() % 2 == 0)
+ {
+ mvmnt = true;
+ curr_price += change;
+ }
+ else
+ {
+ mvmnt = false;
+ curr_price = (curr_price - change)>0 ? (curr_price - change) : 0;
+ }
+
+ // Was there change in price or no change ?
+ std::string movement;
+ if (!change)
+ {
+ movement = "] [--]";
+ } else
+ {
+ movement = (mvmnt ? "] [UP]" : "] [DOWN]");
+ }
+
+ stringstream ticker_data;
+ // Build up the ticker info
+ ticker_data << "[TICKER] " << "Symbol:" << symbol << " \tPrice[" << curr_price << "] \t["
+ << change << movement;
+
+ message.setData(ticker_data.str());
+ // Set TTL value so that message will timeout after a period and be purged from queues
+ message.getDeliveryProperties().setTtl(ttl_time);
+ // Asynchronous transfer sends messages as quickly as
+ // possible without waiting for confirmation.
+ async(session).messageTransfer(arg::content=message, arg::destination="amq.topic");
+
+}
+
+void Publisher::publish_market(const std::string symbol, unsigned short& curr_price, int i)
+{
+ Message message;
+
+ // Set the routing key
+ std::string routing_key = "MRKT." + symbol;
+ std::cout << "Setting routing key:" << routing_key << std::endl;
+ message.getDeliveryProperties().setRoutingKey(routing_key);
+
+ // Calculate the market data low/hi change, vol, market cap etc.
+ if (curr_price < low_[i] || low_[i] == 0)
+ {
+ low_[i] = curr_price;
+ }
+ else if (curr_price > high_[i] || high_[i] == 9999)
+ {
+ high_[i] = curr_price;
+ }
+
+ volume_[i] += rand() % 1000; // increase the daily volume tracker
+ int mkt_cap = shares_[i] * curr_price; // calculate new market cap based on current price
+
+ stringstream market_data;
+ // Build up the ticker info
+ market_data << "[MARKET] " << "Symbol:" << symbol << "\tVolume: " << volume_[i]
+ << "\tHi:" << high_[i] << "\tLo:" << low_[i] << "\tMktCap:"
+ << mkt_cap <<"M\tSEQ[" << seq << "]";
+
+ message.setData(market_data.str());
+
+ std::string key;
+ args.getLVQKey(key);
+ message.getHeaders().setString(key, symbol);
+
+ // Asynchronous transfer sends messages as quickly as
+ // possible without waiting for confirmation.
+ async(session).messageTransfer(arg::content=message, arg::destination="amq.topic");
+ seq++; // This sequence number is really just to demonstrate the LVQ nature of the queue.
+ // You will notice some messages don't show because they are overwritten by last value.
+
+}
+
+
+int main(int argc, char** argv) {
+ unsigned int pub_cycles = argc>1 ? atoi(argv[1]) : 100;
+ unsigned int ttl_time = argc>2 ? atoi(argv[2]) : 4000;
+ const char* host = argc>3 ? argv[3] : "127.0.0.1";
+ int port = argc>4 ? atoi(argv[4]) : 5672;
+ std::cout <<"Usage: topic_publisher <pub cycles> <TTL-timeout> <host name/IP> <port>" << std::endl;
+ std::cout <<"\tparameters are optional but must be in this order when used." << std::endl;
+
+ // Set up the stocks symbols and their prices
+ std::string symbol[6];
+ unsigned short price[6];
+ symbol[0] = "NYSE.RHT"; // Red Hat
+ symbol[1] = "NYSE.IBM"; // IBM Corp.
+ symbol[2] = "NASDAQ.MSFT"; // Microsoft
+ symbol[3] = "NASDAQ.CSCO"; // Cisco Systems
+ symbol[4] = "NASDAQ.YHOO"; // Yahoo
+ symbol[5] = "NASDAQ.GOOG"; // Google
+
+ // Rough starting values.
+ price[0] = rand() % 30 +1;
+ price[1] = rand() % 120 +1;
+ price[2] = rand() % 20 +1;
+ price[3] = rand() % 75 +1;
+ price[4] = rand() % 10 +1;
+ price[5] = rand() % 323 +1;
+
+ // Shares oustanding in millions.
+ unsigned long shares[6] = {190,1340,8890, 5860, 1390, 314};
+
+
+ Connection connection;
+ try {
+ connection.open(host, port);
+ Session session = connection.newSession();
+
+ Publisher theFeed(session,ttl_time, shares);
+
+ //--------- Main body of program --------------------------------------------
+
+ // Print the opening values for each symbol
+ std::cout << std::endl << "Opening values:" << std::endl;
+ for (int i=0; i < 6; i++)
+ {
+ std::cout << symbol[i] << ":" << price[i] << std::endl;
+ }
+
+ // For the duration of the publishing cycles publish
+ // ticker and market data for each symbol
+ for (unsigned int j=0; j<pub_cycles; j++)
+ {
+ for (unsigned int i=0; i < 6; i++)
+ {
+ // for each symbol publish the ticker and the market data
+ theFeed.publish_ticker(symbol[i], price[i]);
+ theFeed.publish_market(symbol[i], price[i], i);
+ }
+ }
+
+
+ //-----------------------------------------------------------------------------
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/cpp/examples/tradedemo/tradedemo_declare_queues.vcproj b/cpp/examples/tradedemo/tradedemo_declare_queues.vcproj
new file mode 100644
index 0000000000..aa9c8911d7
--- /dev/null
+++ b/cpp/examples/tradedemo/tradedemo_declare_queues.vcproj
@@ -0,0 +1,394 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="tradedemo_declare_queues"
+ ProjectGUID="{9057502D-FECA-1BAD-23CE-CD4095BD3C8B}"
+ RootNamespace="tradedemo_declare_queues"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\tradedemo_declare_queues\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\declare_queues.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\tradedemo_declare_queues\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\declare_queues.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\tradedemo_declare_queues\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\declare_queues.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\tradedemo_declare_queues\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\declare_queues.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="declare_queues.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="ConnectionOptions.h">
+ </File>
+ <File
+ RelativePath="TestOptions.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/tradedemo/tradedemo_topic_listener.vcproj b/cpp/examples/tradedemo/tradedemo_topic_listener.vcproj
new file mode 100644
index 0000000000..60505d085a
--- /dev/null
+++ b/cpp/examples/tradedemo/tradedemo_topic_listener.vcproj
@@ -0,0 +1,394 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="tradedemo_topic_listener"
+ ProjectGUID="{5A25F2CD-FECA-1BAD-23CE-CD4095BD3C8B}"
+ RootNamespace="tradedemo_topic_listener"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\tradedemo_topic_listener\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\topic_listener.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\tradedemo_topic_listener\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\topic_listener.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\tradedemo_topic_listener\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\topic_listener.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\tradedemo_topic_listener\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\topic_listener.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="topic_listener.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="ConnectionOptions.h">
+ </File>
+ <File
+ RelativePath="TestOptions.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/tradedemo/tradedemo_topic_publisher.vcproj b/cpp/examples/tradedemo/tradedemo_topic_publisher.vcproj
new file mode 100644
index 0000000000..b33449b560
--- /dev/null
+++ b/cpp/examples/tradedemo/tradedemo_topic_publisher.vcproj
@@ -0,0 +1,394 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="tradedemo_topic_publisher"
+ ProjectGUID="{E614CC2C-FECA-1BAD-23CE-CD4095BD3C8B}"
+ RootNamespace="tradedemo_topic_publisher"
+ Keyword="Win32Proj"
+ SignManifests="true"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\tradedemo_topic_publisher\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\topic_publisher.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\tradedemo_topic_publisher\I386"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\topic_publisher.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="."
+ IntermediateDirectory="Debug\tradedemo_topic_publisher\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ OutputFile="$(OutDir)\topic_publisher.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release\tradedemo_topic_publisher\AMD64"
+ ConfigurationType="1"
+ CharacterSet="0"
+
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ AdditionalOptions=""
+ AdditionalIncludeDirectories=""
+ TypeLibraryName="$(InputName).tlb"
+ HeaderFileName="$(InputName).h"
+ InterfaceIdentifierFileName="$(InputName)_i.c"
+ ProxyFileName="$(InputName)_p.c"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_AMD64_;_WIN64;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DisableSpecificWarnings="4244;4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;_WIN64"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(BOOST_ROOT)\include\$(BOOST_VERSION),$(BOOST_ROOT)\.,$(QPID_ROOT)\include,..\..\include"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/machine:AMD64"
+ AdditionalDependencies="qpidcommon.lib qpidclient.lib"
+ OutputFile="$(OutDir)\topic_publisher.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=".;$(BOOST_ROOT)\lib;$(QPID_ROOT)\bin,..\..\bin"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;cxx;cc;C;c">
+ <File
+ RelativePath="topic_publisher.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hh">
+ <File
+ RelativePath="ConnectionOptions.h">
+ </File>
+ <File
+ RelativePath="TestOptions.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/cpp/examples/verify b/cpp/examples/verify
index 247e75d4a9..43e1206a0c 100755
--- a/cpp/examples/verify
+++ b/cpp/examples/verify
@@ -1,4 +1,25 @@
#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+
# Driver script to verify installed examples (also used for build tests.)
#
# Usage: verify example_dir [ example_dir ...]
@@ -9,7 +30,8 @@
#
QPID_DATA_DIR=
-export QPID_DATA_DIR
+QPID_NO_MODULE_DIR=1
+export QPID_DATA_DIR QPID_NO_MODULE_DIR
cleanup() {
test -n "$QPIDD" && $QPIDD -q # Private broker
@@ -54,13 +76,21 @@ outputs() {
done
}
+normalize() { echo `cd $1 && pwd`; }
+
verify() {
FAIL=
- if [ -d $1 ]; then dir=$1; script=verify;
- else dir=`dirname $1`; script=`basename $1`; fi
- cd $dir || return 1
+ arg=$1
+ srcdir=$(normalize $2)
+ builddir=$(normalize $3)
+ if [ -d $arg ]; then dir=$(normalize $arg); script=verify;
+ else dir=$(normalize `dirname $arg`); script=`basename $arg`; fi
+
+ # if the example is in the "cpp" area, make sure we run from the build directory, not the source dir.
+ rundir=${dir/$srcdir\/cpp/$builddir/}
+ cd $rundir || return 1
rm -f *.out
- { source ./$script && diff -ac $script.out $script.in ; } || fail
+ { source $dir/$script && diff -ac $script.out $dir/$script.in ; } || fail
test -z "$FAIL" && rm -f *.out
return $FAIL
}
@@ -79,8 +109,12 @@ if [ -n "$QPIDD" ] ; then
trap "$QPIDD -q" EXIT
fi
+topsrcdir=$1
+topbuilddir=$2
+shift 2
+
for example in "$@"; do
- echo "== $example "
- if ( verify $example; ) then echo "PASS"; else echo "FAIL"; RET=1; fi
+ echo "== $example"
+ if ( verify $example $topsrcdir $topbuilddir; ) then echo "PASS"; else echo "FAIL"; RET=1; fi
done
exit $RET
diff --git a/cpp/examples/verify_all b/cpp/examples/verify_all
index ea641e2443..baffd422ad 100755
--- a/cpp/examples/verify_all
+++ b/cpp/examples/verify_all
@@ -1,21 +1,43 @@
#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# Verify all C++/python example combinations.
#
verify=`dirname $0`/verify
topsrcdir=$1
-qpidd=$2
-exclude_regexp=$3
+topbuilddir=$2
+qpidd=$topbuilddir/src/qpidd
+broker_args=$3
+exclude_regexp=$4
python=${QPID_PYTHON_DIR:-$topsrcdir/python}
trap "$qpidd -q" exit
-QPID_PORT=`$qpidd -dp0 --no-module-dir --data-dir "" --auth no` || { echo "Can't run qpidd" ; exit 1; }
+QPID_PORT=`$qpidd -dp0 $broker_args` || { echo "Can't run qpidd" ; exit 1; }
PYTHON_EXAMPLES=$python/examples
PYTHONPATH=$python:$PYTHONPATH
export QPID_PORT PYTHON_EXAMPLES PYTHONPATH
test -d $PYTHON_EXAMPLES || echo "WARNING: No python examples. $PYTHON_EXAMPLES not found."
-find="find"
+find="find $topsrcdir/cpp/examples"
test -d $PYTHON_EXAMPLES && find="$find $PYTHON_EXAMPLES"
find="$find -mindepth 2 -name verify"
test -d $PYTHON_EXAMPLES && \
@@ -29,4 +51,4 @@ else
{ cat $f | grep $exclude_regexp > /dev/null ; } || run_examples="$run_examples $f"
done
fi
-$verify $run_examples
+$verify $topsrcdir $topbuilddir $run_examples
diff --git a/cpp/examples/xml-exchange/CMakeLists.txt b/cpp/examples/xml-exchange/CMakeLists.txt
new file mode 100644
index 0000000000..3fea47a208
--- /dev/null
+++ b/cpp/examples/xml-exchange/CMakeLists.txt
@@ -0,0 +1,24 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+if (BUILD_XML)
+add_example(xml-exchange declare_queues)
+add_example(xml-exchange xml_producer)
+add_example(xml-exchange listener)
+endif (BUILD_XML)
diff --git a/cpp/examples/xml-exchange/Makefile.am b/cpp/examples/xml-exchange/Makefile.am
index 1b25a8750d..e91cec370d 100644
--- a/cpp/examples/xml-exchange/Makefile.am
+++ b/cpp/examples/xml-exchange/Makefile.am
@@ -1,5 +1,24 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
examplesdir=$(pkgdatadir)/examples/xml-exchange
+MAKELDFLAGS=$(CLIENTFLAGS)
include $(top_srcdir)/examples/makedist.mk
noinst_PROGRAMS=declare_queues xml_producer listener
@@ -14,7 +33,8 @@ listener_SOURCES=listener.cpp
listener_LDADD=$(CLIENT_LIB)
EXTRA_DIST= \
- README
+ README \
+ CMakeLists.txt
examples_DATA= \
$(EXTRA_DIST) \
diff --git a/cpp/examples/xml-exchange/declare_queues.cpp b/cpp/examples/xml-exchange/declare_queues.cpp
index 1307c473c5..ad08642019 100644
--- a/cpp/examples/xml-exchange/declare_queues.cpp
+++ b/cpp/examples/xml-exchange/declare_queues.cpp
@@ -19,10 +19,32 @@
*
*/
+
+/**
+ *
+ * declare_queues.cpp
+ *
+ * This is one of three programs used to implement XML-based content
+ * routing in C++.
+ *
+ * declare_queues.cpp (this program)
+ *
+ * Creates a queue named "message_qaueue" on the broker,
+ * declares an XML Exchange, subscribes the queue to the XML
+ * Exchange using an XQuery in the binding, then exits.
+ *
+ * xml_producer.cpp
+ *
+ * Publishes messages to the XML Exchange.
+ *
+ * listener.cpp
+ *
+ * Reads messages from the "message_queue" queue.
+ */
+
#include <qpid/client/Connection.h>
#include <qpid/client/Session.h>
-#include <unistd.h>
#include <cstdlib>
#include <iostream>
@@ -59,7 +81,7 @@ int main(int argc, char** argv) {
FieldTable binding;
binding.setString("xquery", "declare variable $control external;"
"./message/id mod 2 = 1 or $control = 'end'");
- session.exchangeBind(arg::exchange="xml", arg::queue="message_queue", arg::bindingKey="query_name", arg::arguments=binding);
+ session.exchangeBind(arg::exchange="xml", arg::queue="message_queue", arg::bindingKey="content_feed", arg::arguments=binding);
//-----------------------------------------------------------------------------
diff --git a/cpp/examples/xml-exchange/listener.cpp b/cpp/examples/xml-exchange/listener.cpp
index 98646bea95..11bcb9f669 100644
--- a/cpp/examples/xml-exchange/listener.cpp
+++ b/cpp/examples/xml-exchange/listener.cpp
@@ -19,17 +19,35 @@
*
*/
+
/**
- * listener.cpp: This program reads messages fro a queue on
- * the broker using a message listener.
+ *
+ * listener.cpp
+ *
+ * This is one of three programs used to implement XML-based content
+ * routing in C++.
+ *
+ * declare_queues.cpp
+ *
+ * Creates a queue named "message_qaueue" on the broker,
+ * declares an XML Exchange, subscribes the queue to the XML
+ * Exchange using an XQuery in the binding, then exits.
+ *
+ * xml_producer.cpp
+ *
+ * Publishes messages to the XML Exchange.
+ *
+ * listener.cpp (this program)
+ *
+ * Reads messages from the "message_queue" queue.
*/
+
#include <qpid/client/Connection.h>
#include <qpid/client/Session.h>
#include <qpid/client/Message.h>
#include <qpid/client/SubscriptionManager.h>
-#include <unistd.h>
#include <cstdlib>
#include <iostream>
@@ -50,7 +68,7 @@ Listener::Listener(SubscriptionManager& subs) : subscriptions(subs)
void Listener::received(Message& message) {
std::cout << "Message: " << message.getData() << std::endl;
- if (message.getHeaders().getString("control") == "end") {
+ if (message.getHeaders().getAsString("control") == "end") {
std::cout << "Shutting down listener for " << message.getDestination()
<< std::endl;
subscriptions.cancel(message.getDestination());
@@ -60,8 +78,8 @@ void Listener::received(Message& message) {
int main(int argc, char** argv) {
const char* host = argc>1 ? argv[1] : "127.0.0.1";
int port = argc>2 ? atoi(argv[2]) : 5672;
+
Connection connection;
- Message msg;
try {
connection.open(host, port);
Session session = connection.newSession();
diff --git a/cpp/examples/xml-exchange/xml_producer.cpp b/cpp/examples/xml-exchange/xml_producer.cpp
index 19889e4891..af1a7e60c7 100644
--- a/cpp/examples/xml-exchange/xml_producer.cpp
+++ b/cpp/examples/xml-exchange/xml_producer.cpp
@@ -20,13 +20,35 @@
*/
+/**
+ *
+ * xml_producer.cpp
+ *
+ * This is one of three programs used to implement XML-based content
+ * routing in C++.
+ *
+ * declare_queues.cpp
+ *
+ * Creates a queue named "message_qaueue" on the broker,
+ * declares an XML Exchange, subscribes the queue to the XML
+ * Exchange using an XQuery in the binding, then exits.
+ *
+ * xml_producer.cpp (this program)
+ *
+ * Publishes messages to the XML Exchange.
+ *
+ * listener.cpp
+ *
+ * Reads messages from the "message_queue" queue.
+ */
+
+
#include <qpid/client/Connection.h>
#include <qpid/client/Session.h>
#include <qpid/client/AsyncSession.h>
#include <qpid/client/Message.h>
-#include <unistd.h>
#include <cstdlib>
#include <iostream>
@@ -55,7 +77,7 @@ int main(int argc, char** argv) {
// In the XML exchange, the routing key and the name of
// the query match.
- message.getDeliveryProperties().setRoutingKey("query_name");
+ message.getDeliveryProperties().setRoutingKey("content_feed");
message.getHeaders().setString("control","continue");
// Now send some messages ...
diff --git a/cpp/include/qmf/Agent.h b/cpp/include/qmf/Agent.h
new file mode 100644
index 0000000000..e61cd737d0
--- /dev/null
+++ b/cpp/include/qmf/Agent.h
@@ -0,0 +1,287 @@
+#ifndef _QmfAgent_
+#define _QmfAgent_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/QmfImportExport.h"
+
+namespace qmf {
+
+ class AgentImpl;
+ class Connection;
+ class ObjectId;
+ class AgentObject;
+ class Value;
+ class Event;
+ class SchemaObjectClass;
+
+ /**
+ * AgentListener is used by agents that select the internalStore=false option (see Agent
+ * constructor) or by agents that wish to provide access control for queries and methods.
+ *
+ * \ingroup qmfapi
+ */
+ class AgentListener {
+ QMF_EXTERN virtual ~AgentListener();
+
+ /**
+ * allowQuery is called before a query operation is executed. If true is returned
+ * by this function, the query will proceed. If false is returned, the query will
+ * be forbidden.
+ *
+ * @param q The query being requested.
+ * @param userId The authenticated identity of the user requesting the query.
+ */
+ virtual bool allowQuery(const Query& q, const char* userId);
+
+ /**
+ * allowMethod is called before a method call is executed. If true is returned
+ * by this function, the method call will proceed. If false is returned, the method
+ * call will be forbidden.
+ *
+ * @param name The name of the method being called.
+ * @param args A value object (of type "map") that contains both input and output arguments.
+ * @param oid The objectId that identifies the instance of the object being called.
+ * @param cls The Schema describing the object being called.
+ * @param userId The authenticated identity of the requesting user.
+ */
+ virtual bool allowMethod(const char* name, const Value& args, const ObjectId& oid,
+ const SchemaObjectClass& cls, const char* userId);
+
+ /**
+ * query is called when the agent receives a query request. The handler must invoke
+ * Agent::queryResponse zero or more times (using the supplied context) followed by
+ * a single invocation of Agent::queryComplete. These calls do not need to be made
+ * synchronously in the context of this function. They may occur before or after this
+ * function returns.
+ *
+ * This function will only be invoked if internalStore=false in the Agent's constructor.
+ *
+ * @param context A context value to use in resulting calls to queryResponse and quertComplete.
+ * @param q The query requested by the console.
+ * @param userId the authenticated identity of the user requesting the query.
+ */
+ virtual void query(uint32_t context, const Query& q, const char* userId);
+
+ /**
+ * syncStart is called when a console requests a standing query. This function must
+ * behave exactly like AgentListener::query (i.e. send zero or more responses followed
+ * by a queryComplete) except it then remembers the context and the query and makes
+ * subsequent queryResponse calls whenever appropriate according the the query.
+ *
+ * The standing query shall stay in effect until syncStop is called with the same context
+ * value or until a specified period of time elapses without receiving a syncTouch for the
+ * context.
+ *
+ * This function will only be invoked if internalStore=false in the Agent's constructor.
+ *
+ * @param context A context value to use in resulting calls to queryResponse and queryComplete.
+ * @param q The query requested by the console.
+ * @param userId the authenticated identity of the user requesting the query.
+ */
+ virtual void syncStart(uint32_t context, const Query& q, const char* userId);
+
+ /**
+ * syncTouch is called when the console that requested a standing query refreshes its
+ * interest in the query. The console must periodically "touch" a standing query to keep
+ * it alive. This prevents standing queries from accumulating when the console disconnects
+ * before it can stop the query.
+ *
+ * This function will only be invoked if internalStore=false in the Agent's constructor.
+ *
+ * @param context The context supplied in a previous call to syncStart.
+ * @param userId The authenticated identity of the requesting user.
+ */
+ virtual void syncTouch(uint32_t context, const char* userId);
+
+ /**
+ * syncStop is called when the console that requested a standing query no longer wishes to
+ * receive data associated with that query. The application shall stop processing this
+ * query and shall remove its record of the context value.
+ *
+ * This function will only be invoked if internalStore=false in the Agent's constructor.
+ *
+ * @param context The context supplied in a previous call to syncStart.
+ * @param userId The authenticated identity of the requesting user.
+ */
+ virtual void syncStop(uint32_t context, const char* userId);
+
+ /**
+ * methodCall is called when a console invokes a method on a QMF object. The application
+ * must call Agent::methodResponse once in response to this function. The response does
+ * not need to be called synchronously in the context of this function. It may be called
+ * before or after this function returns.
+ *
+ * This function will only be invoked if internalStore=false in the Agent's constructor.
+ *
+ * @param context A context value to use in resulting call to methodResponse.
+ * @param name The name of the method being called.
+ * @param args A value object (of type "map") that contains both input and output arguments.
+ * @param oid The objectId that identifies the instance of the object being called.
+ * @param cls The Schema describing the object being called.
+ * @param userId The authenticated identity of the requesting user.
+ */
+ virtual void methodCall(uint32_t context, const char* name, Value& args,
+ const ObjectId& oid, const SchemaObjectClass& cls, const char* userId);
+ };
+
+ /**
+ * The Agent class is the QMF Agent portal. It should be instantiated once and associated with a
+ * Connection (setConnection) to connect an agent to the QMF infrastructure.
+ *
+ * \ingroup qmfapi
+ */
+ class Agent {
+ public:
+ /**
+ * Create an instance of the Agent class.
+ *
+ * @param label An optional string label that can be used to identify the agent.
+ *
+ * @param internalStore If true, objects shall be tracked internally by the agent.
+ * If false, the user of the agent must track the objects.
+ * If the agent is tracking the objects, queries and syncs are handled by
+ * the agent. The only involvement the user has is to optionally authorize
+ * individual operations. If the user is tracking the objects, the user code
+ * must implement queries and syncs (standing queries).
+ *
+ * @param listener A pointer to a class that implements the AgentListener interface.
+ * This must be supplied if any of the following conditions are true:
+ * - The agent model contains methods
+ * - The user wishes to individually authorize query and sync operations.
+ * - internalStore = false
+ */
+ QMF_EXTERN Agent(char* label="qmfa", bool internalStore=true, AgentListener* listener=0);
+
+ /**
+ * Destroy an instance of the Agent class.
+ */
+ QMF_EXTERN ~Agent();
+
+ /**
+ * Set the persistent store file. This file, if specified, is used to store state information
+ * about the Agent. For example, if object-ids must be persistent across restarts of the Agent
+ * program, this file path must be supplied.
+ *
+ * @param path Full path to a file that is both writable and readable by the Agent program.
+ */
+ QMF_EXTERN void setStoreDir(const char* path);
+
+ /**
+ * Provide a connection (to a Qpid broker) over which the agent can communicate.
+ *
+ * @param conn Pointer to a Connection object.
+ */
+ QMF_EXTERN void setConnection(Connection* conn);
+
+ /**
+ * Register a class schema (object or event) with the agent. The agent must have a registered
+ * schema for an object class or an event class before it can handle objects or events of that
+ * class.
+ *
+ * @param cls Pointer to the schema structure describing the class.
+ */
+ QMF_EXTERN void registerClass(SchemaObjectClass* cls);
+ QMF_EXTERN void registerClass(SchemaEventClass* cls);
+
+ /**
+ * Add an object to the agent (for internal storage mode only).
+ *
+ * @param obj Reference to the object to be managed by the agent.
+ *
+ * @param persistent Iff true, the object ID assigned to the object shall indicate persistence
+ * (i.e. the object ID shall be the same across restarts of the agent program).
+ *
+ * @param oid 64-bit value for the oid (if zero, the agent will assign the value).
+ *
+ * @param oidLo 32-bit value for the lower 32-bits of the oid.
+ *
+ * @param oidHi 32-bit value for the upper 32-bits of the oid.
+ */
+ QMF_EXTERN const ObjectId* addObject(AgentObject& obj, bool persistent=false, uint64_t oid=0);
+ QMF_EXTERN const ObjectId* addObject(AgentObject& obj, bool persistent, uint32_t oidLo, uint32_t oidHi);
+
+ /**
+ * Allocate an object ID for an object (for external storage mode only).
+ *
+ * @param persistent Iff true, the object ID allocated shall indicate persistence
+ * (i.e. the object ID shall be the same across restarts of the agent program).
+ *
+ * @param oid 64-bit value for the oid (if zero, the agent will assign the value).
+ *
+ * @param oidLo 32-bit value for the lower 32-bits of the oid.
+ *
+ * @param oidHi 32-bit value for the upper 32-bits of the oid.
+ */
+ QMF_EXTERN const ObjectId* allocObjectId(bool persistent=false, uint64_t oid=0);
+ QMF_EXTERN const ObjectId* allocObjectId(bool persistent, uint32_t oidLo, uint32_t oidHi);
+
+ /**
+ * Raise a QMF event.
+ *
+ * @param event Reference to an event object to be raised to the QMF infrastructure.
+ */
+ QMF_EXTERN void raiseEvent(Event& event);
+
+ /**
+ * Provide a response to a query (for external storage mode only).
+ *
+ * @param context The context value supplied in the query (via the AgentListener interface).
+ *
+ * @param object A reference to the agent that matched the query criteria.
+ *
+ * @param prop If true, transmit the property attributes of this object.
+ *
+ * @param stat If true, transmit the statistic attributes of this object.
+ */
+ QMF_EXTERN void queryResponse(uint32_t context, AgentObject& object, bool prop = true, bool stat = true);
+
+ /**
+ * Indicate that a query (or the initial dump of a sync) is complete (for external storage mode only).
+ *
+ * @param context The context value supplied in the query/sync (via the AgentListener interface).
+ */
+ QMF_EXTERN void queryComplete(uint32_t context);
+
+ /**
+ * Provide the response to a method call.
+ *
+ * @param context The context value supplied in the method request (via the AgentListener interface).
+ *
+ * @param args The argument list from the method call. Must include the output arguments (may include
+ * the input arguments).
+ *
+ * @param status Numerical return status: zero indicates no error, non-zero indicates error.
+ *
+ * @param exception Pointer to an exception value. If status is non-zero, the exception value is
+ * sent to the caller. It is optional (i.e. leave the pointer as 0), or may be
+ * set to any legal value. A string may be supplied, but an unmanaged object of
+ * any schema may also be passed.
+ */
+ QMF_EXTERN void methodResponse(uint32_t context, const Value& args, uint32_t status=0,
+ const Value* exception=0);
+
+ private:
+ AgentImpl* impl;
+ };
+
+}
+
+#endif
diff --git a/cpp/include/qmf/AgentObject.h b/cpp/include/qmf/AgentObject.h
new file mode 100644
index 0000000000..a1878605eb
--- /dev/null
+++ b/cpp/include/qmf/AgentObject.h
@@ -0,0 +1,95 @@
+#ifndef _QmfAgentObject_
+#define _QmfAgentObject_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/QmfImportExport.h"
+
+namespace qmf {
+
+ class AgentObjectImpl;
+ class SchemaObjectClass;
+ class ObjectId;
+ class Value;
+ class Agent;
+
+ /**
+ * AgentObject is an extension of Object with agent-specific methods added.
+ *
+ * \ingroup qmfapi
+ */
+ class AgentObject : public Object {
+ public:
+ /**
+ * Create a new Object of a specific type.
+ *
+ * @param type Pointer to the schema class to use as a type for this object.
+ */
+ QMF_EXTERN AgentObject(const SchemaObjectClass* type);
+
+ /**
+ * Schedule this object for deletion. Agent objects should never be directly
+ * destroyed, rather this method should be called and all pointers to this
+ * object dropped. The agent will clean up and properly delete the object at
+ * the appropraite time.
+ */
+ QMF_EXTERN void destroy();
+
+ /**
+ * Set the object ID for this object if it is to be managed by the agent.
+ *
+ * @param oid The new object ID for the managed object.
+ */
+ QMF_EXTERN void setObjectId(ObjectId& oid);
+
+ /**
+ * Handler for invoked method calls. This will only be called for objects that
+ * are being managed and stored by an agent (see internalStore argument in Agent::Agent).
+ * If this function is not overridden in a child class, the default implementation will
+ * cause AgentListener::methodCall to be invoked in the application program.
+ *
+ * If this function is overridden in a sub-class, the implementation must perform
+ * the actions associated with the method call (i.e. implement the method). Once the
+ * method execution is complete, it must call Agent::methodResponse with the result
+ * of the method execution. Agent::methodResponse does not need to be called
+ * synchronously in the context of this function call. It may be called at a later
+ * time from a different thread.
+ *
+ * @param context Context supplied by the agent and required to be passed in the
+ * call to Agent::methodResponse
+ *
+ * @param name The name of the method.
+ *
+ * @param args A Value (of type map) that contains the input and output arguments.
+ *
+ * @param userId The authenticated identity of the user who invoked the method.
+ */
+ QMF_EXTERN virtual void methodInvoked(uint32_t context, const char* name, Value& args,
+ const char* userId);
+ private:
+ friend class Agent;
+ virtual ~AgentObject();
+ void setAgent(Agent* agent);
+ AgentObjectImpl* impl;
+ };
+
+}
+
+#endif
diff --git a/cpp/include/qmf/Connection.h b/cpp/include/qmf/Connection.h
new file mode 100644
index 0000000000..f648b1427f
--- /dev/null
+++ b/cpp/include/qmf/Connection.h
@@ -0,0 +1,125 @@
+#ifndef _QmfConnection_
+#define _QmfConnection_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/QmfImportExport.h"
+#include "qmf/ConnectionSettings.h"
+
+namespace qmf {
+
+ /**
+ * Operational states for Connections.
+ *
+ * \ingroup qmfapi
+ */
+ enum ConnectionState {
+ CONNECTION_UP = 1,
+ CONNECTION_DOWN = 2
+ };
+
+ /**
+ * Implement a subclass of ConnectionListener and provide it with the
+ * Connection constructor to receive notification of changes in the
+ * connection state.
+ *
+ * \ingroup qmfapi
+ */
+ class ConnectionListener {
+ QMF_EXTERN virtual ~ConnectionListener();
+
+ /**
+ * Called each time the state of the connection changes.
+ *
+ * @param state the new state
+ */
+ virtual void newState(ConnectionState state);
+
+ /**
+ * Called if the connection requires input from an interactive client.
+ *
+ * @param prompt Text of the prompt - describes what information is required.
+ * @param answer The interactive user input.
+ * @param answerLen on Input - the maximum number of bytes that can be copied to answer.
+ * on Output - the number of bytes copied to answer.
+ */
+ virtual void interactivePrompt(const char* prompt, char* answer, uint32_t answerLen);
+ };
+
+ class ConnectionImpl;
+
+ /**
+ * The Connection class represents a connection to a QPID broker that can
+ * be used by agents and consoles, possibly multiple at the same time.
+ *
+ * \ingroup qmfapi
+ */
+ class Connection {
+ public:
+
+ /**
+ * Creates a connection object and begins the process of attempting to
+ * connect to the QPID broker.
+ *
+ * @param settings The settings that control how the connection is set
+ * up.
+ *
+ * @param listener An optional pointer to a subclass of
+ * ConnectionListener to receive notifications of events related to
+ * this connection.
+ */
+ QMF_EXTERN Connection(const ConnectionSettings& settings,
+ const ConnectionListener* listener = 0);
+
+ /**
+ * Destroys a connection, causing the connection to be closed.
+ */
+ QMF_EXTERN ~Connection();
+
+ /**
+ * Set the administrative state of the connection (enabled or disabled).
+ *
+ * @param enabled True => enable connection, False => disable connection
+ */
+ QMF_EXTERN void setAdminState(bool enabled);
+
+ /**
+ * Return the current operational state of the connection (up or down).
+ *
+ * @return the current connection state.
+ */
+ QMF_EXTERN ConnectionState getOperState() const;
+
+ /**
+ * Get the error message from the last failure to connect.
+ *
+ * @return Null-terminated string containing the error message.
+ */
+ QMF_EXTERN const char* getLastError() const;
+
+ private:
+ friend class AgentImpl;
+ friend class ConsoleImpl;
+ ConnectionImpl* impl;
+ };
+
+}
+
+#endif
diff --git a/cpp/include/qmf/ConnectionSettings.h b/cpp/include/qmf/ConnectionSettings.h
new file mode 100644
index 0000000000..11af73d797
--- /dev/null
+++ b/cpp/include/qmf/ConnectionSettings.h
@@ -0,0 +1,32 @@
+#ifndef _QmfConnectionSettings_
+#define _QmfConnectionSettings_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+namespace qmf {
+ namespace engine {
+ class ConnectionSettings;
+ }
+
+ typedef class engine::ConnectionSettings ConnectionSettings;
+}
+
+#endif
+
diff --git a/cpp/include/qmf/ConsoleObject.h b/cpp/include/qmf/ConsoleObject.h
new file mode 100644
index 0000000000..acbc285e05
--- /dev/null
+++ b/cpp/include/qmf/ConsoleObject.h
@@ -0,0 +1,94 @@
+#ifndef _QmfConsoleObject_
+#define _QmfConsoleObject_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/QmfImportExport.h"
+
+namespace qmf {
+
+ class ConsoleObjectImpl;
+ class SchemaObjectClass;
+ class ObjectId;
+ class Value;
+
+ /**
+ * ConsoleObject is an extension of Object with console-specific methods added.
+ *
+ * \ingroup qmfapi
+ */
+ class ConsoleObject : public Object {
+ public:
+ /**
+ * Create a new Object of a specific type.
+ *
+ * @param type Pointer to the schema class to use as a type for this object.
+ */
+ QMF_EXTERN ConsoleObject(const SchemaObjectClass* type);
+
+ /**
+ * Destroy the object.
+ */
+ QMF_EXTERN virtual ~ConsoleObject();
+
+ /**
+ *
+ */
+ QMF_EXTERN const SchemaObjectClass* getSchema() const;
+
+ /**
+ *
+ */
+ QMF_EXTERN ObjectId* getObjectId() const;
+
+ /**
+ *
+ */
+ QMF_EXTERN uint64_t getCurrentTime() const;
+ QMF_EXTERN uint64_t getCreateTime() const;
+ QMF_EXTERN uint64_t getDeleteTime() const;
+
+ /**
+ *
+ */
+ QMF_EXTERN bool isDeleted() const;
+
+ /**
+ *
+ */
+ QMF_EXTERN void update();
+
+ /**
+ *
+ */
+ QMF_EXTERN void invokeMethod(const char* name, const Value* arguments, MethodResult& result);
+
+ /**
+ *
+ */
+ QMF_EXTERN uint32_t invokeMethodAsync(const char* name, const Value* arguments = 0);
+
+ private:
+ ConsoleObjectImpl* impl;
+ };
+
+}
+
+#endif
diff --git a/cpp/include/qmf/QmfImportExport.h b/cpp/include/qmf/QmfImportExport.h
new file mode 100644
index 0000000000..f5e1d9127c
--- /dev/null
+++ b/cpp/include/qmf/QmfImportExport.h
@@ -0,0 +1,33 @@
+#ifndef QMF_IMPORT_EXPORT_H
+#define QMF_IMPORT_EXPORT_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#if defined(WIN32) && !defined(QPID_DECLARE_STATIC)
+# if defined(QMF_EXPORT) || defined (qmfcommon_EXPORTS)
+# define QMF_EXTERN __declspec(dllexport)
+# else
+# define QMF_EXTERN __declspec(dllimport)
+# endif
+#else
+# define QMF_EXTERN
+#endif
+
+#endif
diff --git a/cpp/include/qmf/engine/Agent.h b/cpp/include/qmf/engine/Agent.h
new file mode 100644
index 0000000000..71abf82254
--- /dev/null
+++ b/cpp/include/qmf/engine/Agent.h
@@ -0,0 +1,209 @@
+#ifndef _QmfEngineAgent_
+#define _QmfEngineAgent_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Schema.h>
+#include <qmf/engine/ObjectId.h>
+#include <qmf/engine/Object.h>
+#include <qmf/engine/Event.h>
+#include <qmf/engine/Query.h>
+#include <qmf/engine/Value.h>
+#include <qmf/engine/Message.h>
+
+namespace qmf {
+namespace engine {
+
+ /**
+ * AgentEvent
+ *
+ * This structure represents a QMF event coming from the agent to
+ * the application.
+ */
+ struct AgentEvent {
+ enum EventKind {
+ GET_QUERY = 1,
+ START_SYNC = 2,
+ END_SYNC = 3,
+ METHOD_CALL = 4,
+ DECLARE_QUEUE = 5,
+ DELETE_QUEUE = 6,
+ BIND = 7,
+ UNBIND = 8,
+ SETUP_COMPLETE = 9
+ };
+
+ EventKind kind;
+ uint32_t sequence; // Protocol sequence (for all kinds)
+ char* authUserId; // Authenticated user ID (for all kinds)
+ char* authToken; // Authentication token if issued (for all kinds)
+ char* name; // Name of the method/sync query
+ // (METHOD_CALL, START_SYNC, END_SYNC, DECLARE_QUEUE, BIND, UNBIND)
+ Object* object; // Object involved in method call (METHOD_CALL)
+ ObjectId* objectId; // ObjectId for method call (METHOD_CALL)
+ Query* query; // Query parameters (GET_QUERY, START_SYNC)
+ Value* arguments; // Method parameters (METHOD_CALL)
+ char* exchange; // Exchange for bind (BIND, UNBIND)
+ char* bindingKey; // Key for bind (BIND, UNBIND)
+ const SchemaObjectClass* objectClass; // (METHOD_CALL)
+ };
+
+ class AgentImpl;
+
+ /**
+ * Agent - Protocol engine for the QMF agent
+ */
+ class Agent {
+ public:
+ Agent(char* label, bool internalStore=true);
+ ~Agent();
+
+ /**
+ * Configure the directory path for storing persistent data.
+ *@param path Null-terminated string containing a directory path where files can be
+ * created, written, and read. If NULL, no persistent storage will be
+ * attempted.
+ */
+ void setStoreDir(const char* path);
+
+ /**
+ * Configure the directory path for files transferred over QMF.
+ *@param path Null-terminated string containing a directory path where files can be
+ * created, deleted, written, and read. If NULL, file transfers shall not
+ * be permitted.
+ */
+ void setTransferDir(const char* path);
+
+ /**
+ * Pass messages received from the AMQP session to the Agent engine.
+ *@param message AMQP messages received on the agent session.
+ */
+ void handleRcvMessage(Message& message);
+
+ /**
+ * Get the next message to be sent to the AMQP network.
+ *@param item The Message structure describing the message to be produced.
+ *@return true if the Message is valid, false if there are no messages to send.
+ */
+ bool getXmtMessage(Message& item) const;
+
+ /**
+ * Remove and discard one message from the head of the transmit queue.
+ */
+ void popXmt();
+
+ /**
+ * Get the next application event from the agent engine.
+ *@param event The event iff the return value is true
+ *@return true if event is valid, false if there are no events to process
+ */
+ bool getEvent(AgentEvent& event) const;
+
+ /**
+ * Remove and discard one event from the head of the event queue.
+ */
+ void popEvent();
+
+ /**
+ * A new AMQP session has been established for Agent communication.
+ */
+ void newSession();
+
+ /**
+ * Start the QMF Agent protocol. This should be invoked after a SETUP_COMPLETE event
+ * is received from the Agent engine.
+ */
+ void startProtocol();
+
+ /**
+ * This method is called periodically so the agent can supply a heartbeat.
+ */
+ void heartbeat();
+
+ /**
+ * Respond to a method request.
+ *@param sequence The sequence number from the method request event.
+ *@param status The method's completion status.
+ *@param text Status text ("OK" or an error message)
+ *@param arguments The list of output arguments from the method call.
+ */
+ void methodResponse(uint32_t sequence, uint32_t status, char* text, const Value& arguments);
+
+ /**
+ * Send a content indication to the QMF bus. This is only needed for objects that are
+ * managed by the application. This is *NOT* needed for objects managed by the Agent
+ * (inserted using addObject).
+ *@param sequence The sequence number of the GET request or the SYNC_START request.
+ *@param object The object (annotated with "changed" flags) for publication.
+ *@param prop If true, changed object properties are transmitted.
+ *@param stat If true, changed object statistics are transmitted.
+ */
+ void queryResponse(uint32_t sequence, Object& object, bool prop = true, bool stat = true);
+
+ /**
+ * Indicate the completion of a query. This is not used for SYNC_START requests.
+ *@param sequence The sequence number of the GET request.
+ */
+ void queryComplete(uint32_t sequence);
+
+ /**
+ * Register a schema class with the Agent.
+ *@param cls A SchemaObejctClass object that defines data managed by the agent.
+ */
+ void registerClass(SchemaObjectClass* cls);
+
+ /**
+ * Register a schema class with the Agent.
+ *@param cls A SchemaEventClass object that defines events sent by the agent.
+ */
+ void registerClass(SchemaEventClass* cls);
+
+ /**
+ * Give an object to the Agent for storage and management. Once added, the agent takes
+ * responsibility for the life cycle of the object.
+ *@param obj The object to be managed by the Agent.
+ *@param persistId A unique non-zero value if the object-id is to be persistent.
+ *@return The objectId of the managed object.
+ */
+ const ObjectId* addObject(Object& obj, uint64_t persistId);
+ // const ObjectId* addObject(Object& obj, uint32_t persistIdLo, uint32_t persistIdHi);
+
+ /**
+ * Allocate an object-id for an object that will be managed by the application.
+ *@param persistId A unique non-zero value if the object-id is to be persistent.
+ *@return The objectId structure for the allocated ID.
+ */
+ const ObjectId* allocObjectId(uint64_t persistId);
+ const ObjectId* allocObjectId(uint32_t persistIdLo, uint32_t persistIdHi);
+
+ /**
+ * Raise an event into the QMF network..
+ *@param event The event object for the event to be raised.
+ */
+ void raiseEvent(Event& event);
+
+ private:
+ AgentImpl* impl;
+ };
+}
+}
+
+#endif
+
diff --git a/cpp/include/qmf/engine/ConnectionSettings.h b/cpp/include/qmf/engine/ConnectionSettings.h
new file mode 100644
index 0000000000..36312400b1
--- /dev/null
+++ b/cpp/include/qmf/engine/ConnectionSettings.h
@@ -0,0 +1,150 @@
+#ifndef _QmfEngineConnectionSettings_
+#define _QmfEngineConnectionSettings_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/QmfEngineImportExport.h"
+#include "qpid/sys/IntegerTypes.h"
+
+namespace qmf {
+namespace engine {
+
+ class ConnectionSettingsImpl;
+ class Value;
+
+ /**
+ * Settings for AMQP connections to the broker.
+ *
+ * \ingroup qmfapi
+ */
+ class ConnectionSettings {
+ public:
+
+ /**
+ * Create a set of default connection settings.
+ *
+ * If no further attributes are set, the settings will cause a connection to be made to
+ * the default broker (on localhost or at a host/port supplied by service discovery) and
+ * authentication will be the best-available (GSSAPI/Kerberos, Anonymous, Plain with prompts
+ * for username and password).
+ */
+ QMFE_EXTERN ConnectionSettings();
+
+ /**
+ * Create a set of connection settings by URL.
+ *
+ * @param url Universal resource locator describing the broker address and additional attributes.
+ *
+ * The URL is of the form:
+ * amqp[s]://host[:port][?key=value[&key=value]*]
+ *
+ * For example:
+ * amqp://localhost
+ * amqp://broker?transport=rdma&authmech=GSSAPI&authservice=qpidd
+ * amqps://broker?authmech=PLAIN&authuser=guest&authpass=guest
+ */
+ QMFE_EXTERN ConnectionSettings(const char* url);
+
+ /**
+ * Copy Constructor.
+ */
+ ConnectionSettings(const ConnectionSettings& from);
+
+ /**
+ * Destroy the connection settings object.
+ */
+ QMFE_EXTERN ~ConnectionSettings();
+
+ /**
+ * Set an attribute to control connection setup.
+ *
+ * @param key A null-terminated string that is an attribute name.
+ *
+ * @param value Reference to a value to be stored as the attribute. The type of the value
+ * is specific to the key.
+ *
+ * @return True if success, False if invalid attribute
+ */
+ QMFE_EXTERN bool setAttr(const char* key, const Value& value);
+
+ /**
+ * Get the value of an attribute.
+ *
+ * @param key A null-terminated attribute name.
+ *
+ * @return The value associated with the attribute name.
+ */
+ QMFE_EXTERN Value getAttr(const char* key) const;
+
+ /**
+ * Get the attribute string (the portion of the URL following the '?') for the settings.
+ *
+ * @return A pointer to the attribute string. If the content of this string needs to be
+ * available beyond the scope of the calling function, it should be copied. The
+ * returned pointer may become invalid if the set of attributes is changed.
+ */
+ QMFE_EXTERN const char* getAttrString() const;
+
+ /**
+ * Shortcuts for setting the transport for the connection.
+ *
+ * @param port The port value for the connection address.
+ */
+ QMFE_EXTERN void transportTcp(uint16_t port = 5672);
+ QMFE_EXTERN void transportSsl(uint16_t port = 5671);
+ QMFE_EXTERN void transportRdma(uint16_t port = 5672);
+
+ /**
+ * Shortcuts for setting authentication mechanisms.
+ *
+ * @param username Null-terminated authentication user name.
+ *
+ * @param password Null-terminated authentication password.
+ *
+ * @param serviceName Null-terminated GSSAPI service name (Kerberos service principal)
+ *
+ * @param minSsf Minimum security factor for connections. 0 = encryption not required.
+ *
+ * @param maxSsf Maximum security factor for connections. 0 = encryption not permitted.
+ */
+ QMFE_EXTERN void authAnonymous(const char* username = 0);
+ QMFE_EXTERN void authPlain(const char* username = 0, const char* password = 0);
+ QMFE_EXTERN void authGssapi(const char* serviceName, uint32_t minSsf = 0, uint32_t maxSsf = 256);
+
+ /**
+ * Shortcut for setting connection retry attributes.
+ *
+ * @param delayMin Minimum delay (in seconds) between connection attempts.
+ *
+ * @param delaxMax Maximum delay (in seconds) between connection attempts.
+ *
+ * @param delayFactor Factor to multiply the delay by between failed connection attempts.
+ */
+ QMFE_EXTERN void setRetry(int delayMin = 1, int delayMax = 128, int delayFactor = 2);
+
+ private:
+ friend class ResilientConnectionImpl;
+ ConnectionSettingsImpl* impl;
+ };
+
+}
+}
+
+#endif
diff --git a/cpp/include/qmf/engine/Console.h b/cpp/include/qmf/engine/Console.h
new file mode 100644
index 0000000000..03b3993395
--- /dev/null
+++ b/cpp/include/qmf/engine/Console.h
@@ -0,0 +1,236 @@
+#ifndef _QmfEngineConsole_
+#define _QmfEngineConsole_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/ResilientConnection.h>
+#include <qmf/engine/Schema.h>
+#include <qmf/engine/ObjectId.h>
+#include <qmf/engine/Object.h>
+#include <qmf/engine/Event.h>
+#include <qmf/engine/Query.h>
+#include <qmf/engine/Value.h>
+#include <qmf/engine/Message.h>
+
+namespace qmf {
+namespace engine {
+
+ class Console;
+ class ConsoleImpl;
+ class BrokerProxyImpl;
+ class AgentProxy;
+ struct AgentProxyImpl;
+ struct MethodResponseImpl;
+ struct QueryResponseImpl;
+ struct QueryContext;
+
+ /**
+ *
+ */
+ class MethodResponse {
+ public:
+ MethodResponse(const MethodResponse& from);
+ ~MethodResponse();
+ uint32_t getStatus() const;
+ const Value* getException() const;
+ const Value* getArgs() const;
+
+ private:
+ friend struct MethodResponseImpl;
+ friend class ConsoleImpl;
+ MethodResponse(MethodResponseImpl* impl);
+ MethodResponseImpl* impl;
+ };
+
+ /**
+ *
+ */
+ class QueryResponse {
+ public:
+ ~QueryResponse();
+ uint32_t getStatus() const;
+ const Value* getException() const;
+ uint32_t getObjectCount() const;
+ const Object* getObject(uint32_t idx) const;
+
+ private:
+ friend struct QueryResponseImpl;
+ friend struct QueryContext;
+ QueryResponse(QueryResponseImpl* impl);
+ QueryResponseImpl *impl;
+ };
+
+ /**
+ *
+ */
+ struct ConsoleEvent {
+ enum EventKind {
+ AGENT_ADDED = 1,
+ AGENT_DELETED = 2,
+ NEW_PACKAGE = 3,
+ NEW_CLASS = 4,
+ OBJECT_UPDATE = 5,
+ EVENT_RECEIVED = 7,
+ AGENT_HEARTBEAT = 8
+ };
+
+ EventKind kind;
+ AgentProxy* agent; // (AGENT_[ADDED|DELETED|HEARTBEAT])
+ char* name; // (NEW_PACKAGE)
+ const SchemaClassKey* classKey; // (NEW_CLASS)
+ Object* object; // (OBJECT_UPDATE)
+ void* context; // (OBJECT_UPDATE)
+ Event* event; // (EVENT_RECEIVED)
+ uint64_t timestamp; // (AGENT_HEARTBEAT)
+ QueryResponse* queryResponse; // (QUERY_COMPLETE)
+ bool hasProps;
+ bool hasStats;
+ };
+
+ /**
+ *
+ */
+ struct BrokerEvent {
+ enum EventKind {
+ BROKER_INFO = 10,
+ DECLARE_QUEUE = 11,
+ DELETE_QUEUE = 12,
+ BIND = 13,
+ UNBIND = 14,
+ SETUP_COMPLETE = 15,
+ STABLE = 16,
+ QUERY_COMPLETE = 17,
+ METHOD_RESPONSE = 18
+ };
+
+ EventKind kind;
+ char* name; // ([DECLARE|DELETE]_QUEUE, [UN]BIND)
+ char* exchange; // ([UN]BIND)
+ char* bindingKey; // ([UN]BIND)
+ void* context; // (QUERY_COMPLETE, METHOD_RESPONSE)
+ QueryResponse* queryResponse; // (QUERY_COMPLETE)
+ MethodResponse* methodResponse; // (METHOD_RESPONSE)
+ };
+
+ /**
+ *
+ */
+ class AgentProxy {
+ public:
+ AgentProxy(const AgentProxy& from);
+ ~AgentProxy();
+ const char* getLabel() const;
+ uint32_t getBrokerBank() const;
+ uint32_t getAgentBank() const;
+
+ private:
+ friend struct StaticContext;
+ friend struct QueryContext;
+ friend struct AgentProxyImpl;
+ friend class BrokerProxyImpl;
+ AgentProxy(AgentProxyImpl* impl);
+ AgentProxyImpl* impl;
+ };
+
+ /**
+ *
+ */
+ class BrokerProxy {
+ public:
+ BrokerProxy(Console& console);
+ ~BrokerProxy();
+
+ void sessionOpened(SessionHandle& sh);
+ void sessionClosed();
+ void startProtocol();
+
+ void handleRcvMessage(Message& message);
+ bool getXmtMessage(Message& item) const;
+ void popXmt();
+
+ bool getEvent(BrokerEvent& event) const;
+ void popEvent();
+
+ uint32_t agentCount() const;
+ const AgentProxy* getAgent(uint32_t idx) const;
+ void sendQuery(const Query& query, void* context, const AgentProxy* agent = 0);
+
+ private:
+ friend class ConsoleImpl;
+ friend struct StaticContext;
+ BrokerProxyImpl* impl;
+ };
+
+ // TODO - move this to a public header
+ struct ConsoleSettings {
+ bool rcvObjects;
+ bool rcvEvents;
+ bool rcvHeartbeats;
+ bool userBindings;
+
+ ConsoleSettings() :
+ rcvObjects(true),
+ rcvEvents(true),
+ rcvHeartbeats(true),
+ userBindings(false) {}
+ };
+
+ class Console {
+ public:
+ Console(const ConsoleSettings& settings = ConsoleSettings());
+ ~Console();
+
+ bool getEvent(ConsoleEvent& event) const;
+ void popEvent();
+
+ void addConnection(BrokerProxy& broker, void* context);
+ void delConnection(BrokerProxy& broker);
+
+ uint32_t packageCount() const;
+ const char* getPackageName(uint32_t idx) const;
+
+ uint32_t classCount(const char* packageName) const;
+ const SchemaClassKey* getClass(const char* packageName, uint32_t idx) const;
+
+ ClassKind getClassKind(const SchemaClassKey* key) const;
+ const SchemaObjectClass* getObjectClass(const SchemaClassKey* key) const;
+ const SchemaEventClass* getEventClass(const SchemaClassKey* key) const;
+
+ void bindPackage(const char* packageName);
+ void bindClass(const SchemaClassKey* key);
+ void bindClass(const char* packageName, const char* className);
+
+ /*
+ void startSync(const Query& query, void* context, SyncQuery& sync);
+ void touchSync(SyncQuery& sync);
+ void endSync(SyncQuery& sync);
+ */
+
+ private:
+ friend class BrokerProxyImpl;
+ friend struct AgentProxyImpl;
+ friend struct StaticContext;
+ ConsoleImpl* impl;
+ };
+}
+}
+
+#endif
+
diff --git a/cpp/include/qmf/engine/Event.h b/cpp/include/qmf/engine/Event.h
new file mode 100644
index 0000000000..50ab5c1200
--- /dev/null
+++ b/cpp/include/qmf/engine/Event.h
@@ -0,0 +1,32 @@
+#ifndef _QmfEngineEvent_
+#define _QmfEngineEvent_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+namespace qmf {
+namespace engine {
+
+ class Event {
+ };
+}
+}
+
+#endif
+
diff --git a/cpp/include/qmf/engine/Message.h b/cpp/include/qmf/engine/Message.h
new file mode 100644
index 0000000000..1e95cc6afe
--- /dev/null
+++ b/cpp/include/qmf/engine/Message.h
@@ -0,0 +1,41 @@
+#ifndef _QmfEngineMessage_
+#define _QmfEngineMessage_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/sys/IntegerTypes.h"
+
+namespace qmf {
+namespace engine {
+
+ struct Message {
+ char* body;
+ uint32_t length;
+ char* destination;
+ char* routingKey;
+ char* replyExchange;
+ char* replyKey;
+ char* userId;
+ };
+
+}
+}
+
+#endif
diff --git a/cpp/include/qmf/engine/Object.h b/cpp/include/qmf/engine/Object.h
new file mode 100644
index 0000000000..ad67cfdb95
--- /dev/null
+++ b/cpp/include/qmf/engine/Object.h
@@ -0,0 +1,56 @@
+#ifndef _QmfEngineObject_
+#define _QmfEngineObject_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Schema.h>
+#include <qmf/engine/ObjectId.h>
+#include <qmf/engine/Value.h>
+
+namespace qmf {
+namespace engine {
+
+ struct ObjectImpl;
+ class Object {
+ public:
+ Object(const SchemaObjectClass* type);
+ Object(const Object& from);
+ virtual ~Object();
+
+ void destroy();
+ const ObjectId* getObjectId() const;
+ void setObjectId(ObjectId* oid);
+ const SchemaObjectClass* getClass() const;
+ Value* getValue(const char* key) const;
+ void invokeMethod(const char* methodName, const Value* inArgs, void* context) const;
+ bool isDeleted() const;
+ void merge(const Object& from);
+
+ private:
+ friend struct ObjectImpl;
+ friend class AgentImpl;
+ Object(ObjectImpl* impl);
+ ObjectImpl* impl;
+ };
+}
+}
+
+#endif
+
diff --git a/cpp/include/qmf/engine/ObjectId.h b/cpp/include/qmf/engine/ObjectId.h
new file mode 100644
index 0000000000..2055972c00
--- /dev/null
+++ b/cpp/include/qmf/engine/ObjectId.h
@@ -0,0 +1,67 @@
+#ifndef _QmfEngineObjectId_
+#define _QmfEngineObjectId_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/sys/IntegerTypes.h>
+
+namespace qmf {
+namespace engine {
+
+ // TODO: Add to/from string and << operator
+
+ struct ObjectIdImpl;
+ class ObjectId {
+ public:
+ ObjectId();
+ ObjectId(const ObjectId& from);
+ ~ObjectId();
+
+ uint64_t getObjectNum() const;
+ uint32_t getObjectNumHi() const;
+ uint32_t getObjectNumLo() const;
+ bool isDurable() const;
+ const char* str() const;
+ uint8_t getFlags() const;
+ uint16_t getSequence() const;
+ uint32_t getBrokerBank() const;
+ uint32_t getAgentBank() const;
+
+ bool operator==(const ObjectId& other) const;
+ bool operator<(const ObjectId& other) const;
+ bool operator>(const ObjectId& other) const;
+ bool operator<=(const ObjectId& other) const;
+ bool operator>=(const ObjectId& other) const;
+
+ private:
+ friend struct ObjectIdImpl;
+ friend struct ObjectImpl;
+ friend class BrokerProxyImpl;
+ friend struct QueryImpl;
+ friend struct ValueImpl;
+ friend class AgentImpl;
+ ObjectId(ObjectIdImpl* impl);
+ ObjectIdImpl* impl;
+ };
+}
+}
+
+#endif
+
diff --git a/cpp/include/qmf/engine/QmfEngineImportExport.h b/cpp/include/qmf/engine/QmfEngineImportExport.h
new file mode 100644
index 0000000000..373617e046
--- /dev/null
+++ b/cpp/include/qmf/engine/QmfEngineImportExport.h
@@ -0,0 +1,33 @@
+#ifndef QMF_ENGINE_IMPORT_EXPORT_H
+#define QMF_ENGINE_IMPORT_EXPORT_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#if defined(WIN32) && !defined(QPID_DECLARE_STATIC)
+# if defined(QMF_EXPORT) || defined (qmfengine_EXPORTS)
+# define QMFE_EXTERN __declspec(dllexport)
+# else
+# define QMFE_EXTERN __declspec(dllimport)
+# endif
+#else
+# define QMFE_EXTERN
+#endif
+
+#endif
diff --git a/cpp/include/qmf/engine/Query.h b/cpp/include/qmf/engine/Query.h
new file mode 100644
index 0000000000..3ed08c5d8e
--- /dev/null
+++ b/cpp/include/qmf/engine/Query.h
@@ -0,0 +1,112 @@
+#ifndef _QmfEngineQuery_
+#define _QmfEngineQuery_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/ObjectId.h>
+#include <qmf/engine/Value.h>
+
+namespace qmf {
+namespace engine {
+
+ class Object;
+ struct QueryElementImpl;
+ struct QueryImpl;
+ struct QueryExpressionImpl;
+ class SchemaClassKey;
+
+ enum ValueOper {
+ O_EQ = 1,
+ O_NE = 2,
+ O_LT = 3,
+ O_LE = 4,
+ O_GT = 5,
+ O_GE = 6,
+ O_RE_MATCH = 7,
+ O_RE_NOMATCH = 8,
+ O_PRESENT = 9,
+ O_NOT_PRESENT = 10
+ };
+
+ struct QueryOperand {
+ virtual ~QueryOperand() {}
+ virtual bool evaluate(const Object* object) const = 0;
+ };
+
+ struct QueryElement : public QueryOperand {
+ QueryElement(const char* attrName, const Value* value, ValueOper oper);
+ QueryElement(QueryElementImpl* impl);
+ virtual ~QueryElement();
+ bool evaluate(const Object* object) const;
+
+ QueryElementImpl* impl;
+ };
+
+ enum ExprOper {
+ E_NOT = 1,
+ E_AND = 2,
+ E_OR = 3,
+ E_XOR = 4
+ };
+
+ struct QueryExpression : public QueryOperand {
+ QueryExpression(ExprOper oper, const QueryOperand* operand1, const QueryOperand* operand2);
+ QueryExpression(QueryExpressionImpl* impl);
+ virtual ~QueryExpression();
+ bool evaluate(const Object* object) const;
+
+ QueryExpressionImpl* impl;
+ };
+
+ class Query {
+ public:
+ Query(const char* className, const char* packageName);
+ Query(const SchemaClassKey* key);
+ Query(const ObjectId* oid);
+ Query(const Query& from);
+ ~Query();
+
+ void setSelect(const QueryOperand* criterion);
+ void setLimit(uint32_t maxResults);
+ void setOrderBy(const char* attrName, bool decreasing);
+
+ const char* getPackage() const;
+ const char* getClass() const;
+ const ObjectId* getObjectId() const;
+
+ bool haveSelect() const;
+ bool haveLimit() const;
+ bool haveOrderBy() const;
+ const QueryOperand* getSelect() const;
+ uint32_t getLimit() const;
+ const char* getOrderBy() const;
+ bool getDecreasing() const;
+
+ private:
+ friend struct QueryImpl;
+ friend class BrokerProxyImpl;
+ Query(QueryImpl* impl);
+ QueryImpl* impl;
+ };
+}
+}
+
+#endif
+
diff --git a/cpp/include/qmf/engine/ResilientConnection.h b/cpp/include/qmf/engine/ResilientConnection.h
new file mode 100644
index 0000000000..359c8ea6ff
--- /dev/null
+++ b/cpp/include/qmf/engine/ResilientConnection.h
@@ -0,0 +1,165 @@
+#ifndef _QmfEngineResilientConnection_
+#define _QmfEngineResilientConnection_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Message.h>
+#include <qmf/engine/ConnectionSettings.h>
+#include <string>
+
+namespace qmf {
+namespace engine {
+
+ class ResilientConnectionImpl;
+
+ /**
+ * Represents events that occur, unsolicited, from ResilientConnection.
+ */
+ struct ResilientConnectionEvent {
+ enum EventKind {
+ CONNECTED = 1,
+ DISCONNECTED = 2,
+ SESSION_CLOSED = 3,
+ RECV = 4
+ };
+
+ EventKind kind;
+ void* sessionContext; // SESSION_CLOSED, RECV
+ char* errorText; // DISCONNECTED, SESSION_CLOSED
+ Message message; // RECV
+ };
+
+ class SessionHandle {
+ friend class ResilientConnectionImpl;
+ void* impl;
+ };
+
+ /**
+ * ResilientConnection represents a Qpid connection that is resilient.
+ *
+ * Upon creation, ResilientConnection attempts to establish a connection to the
+ * messaging broker. If it fails, it will continue to retry at an interval that
+ * increases over time (to a maximum interval). If an extablished connection is
+ * dropped, a reconnect will be attempted.
+ */
+ class ResilientConnection {
+ public:
+
+ /**
+ * Create a new resilient connection.
+ *@param settings Settings that define how the connection is to be made.
+ *@param delayMin Minimum delay (in seconds) between retries.
+ *@param delayMax Maximum delay (in seconds) between retries.
+ *@param delayFactor Factor to multiply retry delay by after each failure.
+ */
+ ResilientConnection(const ConnectionSettings& settings);
+ ~ResilientConnection();
+
+ /**
+ * Get the connected status of the resilient connection.
+ *@return true iff the connection is established.
+ */
+ bool isConnected() const;
+
+ /**
+ * Get the next event (if present) from the connection.
+ *@param event Returned event if one is available.
+ *@return true if event is valid, false if there are no more events to handle.
+ */
+ bool getEvent(ResilientConnectionEvent& event);
+
+ /**
+ * Discard the event on the front of the queue. This should be invoked after processing
+ * the event from getEvent.
+ */
+ void popEvent();
+
+ /**
+ * Create a new AMQP session.
+ *@param name Unique name for the session.
+ *@param sessionContext Optional user-context value that will be provided in events
+ * pertaining to this session.
+ *@param handle Output handle to be stored and used in subsequent calls pertaining to
+ * this session.
+ *@return true iff the session was successfully created.
+ */
+ bool createSession(const char* name, void* sessionContext, SessionHandle& handle);
+
+ /**
+ * Destroy a created session.
+ *@param handle SessionHandle returned by createSession.
+ */
+ void destroySession(SessionHandle handle);
+
+ /**
+ * Send a message into the AMQP broker via a session.
+ *@param handle The session handle of the session to transmit through.
+ *@param message The QMF message to transmit.
+ */
+ void sendMessage(SessionHandle handle, Message& message);
+
+ /**
+ * Declare an exclusive, auto-delete queue for a session.
+ *@param handle The session handle for the owner of the queue.
+ *@param queue The name of the queue.
+ */
+ void declareQueue(SessionHandle handle, char* queue);
+
+ /**
+ * Delete a queue.
+ *@param handle The session handle for the owner of the queue.
+ *@param queue The name of the queue.
+ */
+ void deleteQueue(SessionHandle handle, char* queue);
+
+ /**
+ * Bind a queue to an exchange.
+ *@param handle The session handle of the session to use for binding.
+ *@param exchange The name of the exchange for binding.
+ *@param queue The name of the queue for binding.
+ *@param key The binding key.
+ */
+ void bind(SessionHandle handle, char* exchange, char* queue, char* key);
+
+ /**
+ * Remove a binding.
+ *@param handle The session handle of the session to use for un-binding.
+ *@param exchange The name of the exchange.
+ *@param queue The name of the queue.
+ *@param key The binding key.
+ */
+ void unbind(SessionHandle handle, char* exchange, char* queue, char* key);
+
+ /**
+ * Establish a file descriptor for event notification.
+ *@param fd A file descriptor into which the connection shall write a character each
+ * time an event is enqueued. This fd may be in a pair, the other fd of which
+ * is used in a select loop to control execution.
+ */
+ void setNotifyFd(int fd);
+
+ private:
+ ResilientConnectionImpl* impl;
+ };
+}
+}
+
+#endif
+
diff --git a/cpp/include/qmf/engine/Schema.h b/cpp/include/qmf/engine/Schema.h
new file mode 100644
index 0000000000..9f5b444558
--- /dev/null
+++ b/cpp/include/qmf/engine/Schema.h
@@ -0,0 +1,210 @@
+#ifndef _QmfEngineSchema_
+#define _QmfEngineSchema_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Typecode.h>
+#include <qpid/sys/IntegerTypes.h>
+
+namespace qmf {
+namespace engine {
+
+ enum Access { ACCESS_READ_CREATE = 1, ACCESS_READ_WRITE = 2, ACCESS_READ_ONLY = 3 };
+ enum Direction { DIR_IN = 1, DIR_OUT = 2, DIR_IN_OUT = 3 };
+ enum ClassKind { CLASS_OBJECT = 1, CLASS_EVENT = 2 };
+
+ struct SchemaArgumentImpl;
+ struct SchemaMethodImpl;
+ struct SchemaPropertyImpl;
+ struct SchemaStatisticImpl;
+ struct SchemaObjectClassImpl;
+ struct SchemaEventClassImpl;
+ struct SchemaClassKeyImpl;
+
+ /**
+ */
+ class SchemaArgument {
+ public:
+ SchemaArgument(const char* name, Typecode typecode);
+ SchemaArgument(const SchemaArgument& from);
+ ~SchemaArgument();
+ void setDirection(Direction dir);
+ void setUnit(const char* val);
+ void setDesc(const char* desc);
+ const char* getName() const;
+ Typecode getType() const;
+ Direction getDirection() const;
+ const char* getUnit() const;
+ const char* getDesc() const;
+
+ private:
+ friend struct SchemaArgumentImpl;
+ friend struct SchemaMethodImpl;
+ friend struct SchemaEventClassImpl;
+ SchemaArgument(SchemaArgumentImpl* impl);
+ SchemaArgumentImpl* impl;
+ };
+
+ /**
+ */
+ class SchemaMethod {
+ public:
+ SchemaMethod(const char* name);
+ SchemaMethod(const SchemaMethod& from);
+ ~SchemaMethod();
+ void addArgument(const SchemaArgument* argument);
+ void setDesc(const char* desc);
+ const char* getName() const;
+ const char* getDesc() const;
+ int getArgumentCount() const;
+ const SchemaArgument* getArgument(int idx) const;
+
+ private:
+ friend struct SchemaMethodImpl;
+ friend struct SchemaObjectClassImpl;
+ friend class AgentImpl;
+ SchemaMethod(SchemaMethodImpl* impl);
+ SchemaMethodImpl* impl;
+ };
+
+ /**
+ */
+ class SchemaProperty {
+ public:
+ SchemaProperty(const char* name, Typecode typecode);
+ SchemaProperty(const SchemaProperty& from);
+ ~SchemaProperty();
+ void setAccess(Access access);
+ void setIndex(bool val);
+ void setOptional(bool val);
+ void setUnit(const char* val);
+ void setDesc(const char* desc);
+ const char* getName() const;
+ Typecode getType() const;
+ Access getAccess() const;
+ bool isIndex() const;
+ bool isOptional() const;
+ const char* getUnit() const;
+ const char* getDesc() const;
+
+ private:
+ friend struct SchemaPropertyImpl;
+ friend struct SchemaObjectClassImpl;
+ SchemaProperty(SchemaPropertyImpl* impl);
+ SchemaPropertyImpl* impl;
+ };
+
+ /**
+ */
+ class SchemaStatistic {
+ public:
+ SchemaStatistic(const char* name, Typecode typecode);
+ SchemaStatistic(const SchemaStatistic& from);
+ ~SchemaStatistic();
+ void setUnit(const char* val);
+ void setDesc(const char* desc);
+ const char* getName() const;
+ Typecode getType() const;
+ const char* getUnit() const;
+ const char* getDesc() const;
+
+ private:
+ friend struct SchemaStatisticImpl;
+ friend struct SchemaObjectClassImpl;
+ SchemaStatistic(SchemaStatisticImpl* impl);
+ SchemaStatisticImpl* impl;
+ };
+
+ /**
+ */
+ class SchemaClassKey {
+ public:
+ SchemaClassKey(const SchemaClassKey& from);
+ ~SchemaClassKey();
+
+ const char* getPackageName() const;
+ const char* getClassName() const;
+ const uint8_t* getHash() const;
+ const char* asString() const;
+
+ bool operator==(const SchemaClassKey& other) const;
+ bool operator<(const SchemaClassKey& other) const;
+
+ private:
+ friend struct SchemaClassKeyImpl;
+ friend class BrokerProxyImpl;
+ friend class ConsoleImpl;
+ SchemaClassKey(SchemaClassKeyImpl* impl);
+ SchemaClassKeyImpl* impl;
+ };
+
+ /**
+ */
+ class SchemaObjectClass {
+ public:
+ SchemaObjectClass(const char* package, const char* name);
+ SchemaObjectClass(const SchemaObjectClass& from);
+ ~SchemaObjectClass();
+ void addProperty(const SchemaProperty* property);
+ void addStatistic(const SchemaStatistic* statistic);
+ void addMethod(const SchemaMethod* method);
+
+ const SchemaClassKey* getClassKey() const;
+ int getPropertyCount() const;
+ int getStatisticCount() const;
+ int getMethodCount() const;
+ const SchemaProperty* getProperty(int idx) const;
+ const SchemaStatistic* getStatistic(int idx) const;
+ const SchemaMethod* getMethod(int idx) const;
+
+ private:
+ friend struct SchemaObjectClassImpl;
+ friend class BrokerProxyImpl;
+ friend class AgentImpl;
+ SchemaObjectClass(SchemaObjectClassImpl* impl);
+ SchemaObjectClassImpl* impl;
+ };
+
+ /**
+ */
+ class SchemaEventClass {
+ public:
+ SchemaEventClass(const char* package, const char* name);
+ SchemaEventClass(const SchemaEventClass& from);
+ ~SchemaEventClass();
+ void addArgument(const SchemaArgument* argument);
+ void setDesc(const char* desc);
+
+ const SchemaClassKey* getClassKey() const;
+ int getArgumentCount() const;
+ const SchemaArgument* getArgument(int idx) const;
+
+ private:
+ friend struct SchemaEventClassImpl;
+ friend class BrokerProxyImpl;
+ friend class AgentImpl;
+ SchemaEventClass(SchemaEventClassImpl* impl);
+ SchemaEventClassImpl* impl;
+ };
+}
+}
+
+#endif
+
diff --git a/cpp/include/qmf/engine/Typecode.h b/cpp/include/qmf/engine/Typecode.h
new file mode 100644
index 0000000000..613f96a483
--- /dev/null
+++ b/cpp/include/qmf/engine/Typecode.h
@@ -0,0 +1,53 @@
+#ifndef _QmfEngineTypecode_
+#define _QmfEngineTypecode_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+namespace qmf {
+namespace engine {
+
+ enum Typecode {
+ TYPE_UINT8 = 1,
+ TYPE_UINT16 = 2,
+ TYPE_UINT32 = 3,
+ TYPE_UINT64 = 4,
+ TYPE_SSTR = 6,
+ TYPE_LSTR = 7,
+ TYPE_ABSTIME = 8,
+ TYPE_DELTATIME = 9,
+ TYPE_REF = 10,
+ TYPE_BOOL = 11,
+ TYPE_FLOAT = 12,
+ TYPE_DOUBLE = 13,
+ TYPE_UUID = 14,
+ TYPE_MAP = 15,
+ TYPE_INT8 = 16,
+ TYPE_INT16 = 17,
+ TYPE_INT32 = 18,
+ TYPE_INT64 = 19,
+ TYPE_OBJECT = 20,
+ TYPE_LIST = 21,
+ TYPE_ARRAY = 22
+ };
+}
+}
+
+#endif
+
diff --git a/cpp/include/qmf/engine/Value.h b/cpp/include/qmf/engine/Value.h
new file mode 100644
index 0000000000..8eae382caf
--- /dev/null
+++ b/cpp/include/qmf/engine/Value.h
@@ -0,0 +1,121 @@
+#ifndef _QmfEngineValue_
+#define _QmfEngineValue_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/ObjectId.h>
+#include <qmf/engine/Typecode.h>
+
+namespace qmf {
+namespace engine {
+
+ class Object;
+ struct ValueImpl;
+
+ class Value {
+ public:
+ // Value();
+ Value(const Value& from);
+ Value(Typecode t, Typecode arrayType = TYPE_UINT8);
+ ~Value();
+
+ Typecode getType() const;
+ bool isNull() const;
+ void setNull();
+
+ bool isObjectId() const;
+ const ObjectId& asObjectId() const;
+ void setObjectId(const ObjectId& oid);
+
+ bool isUint() const;
+ uint32_t asUint() const;
+ void setUint(uint32_t val);
+
+ bool isInt() const;
+ int32_t asInt() const;
+ void setInt(int32_t val);
+
+ bool isUint64() const;
+ uint64_t asUint64() const;
+ void setUint64(uint64_t val);
+
+ bool isInt64() const;
+ int64_t asInt64() const;
+ void setInt64(int64_t val);
+
+ bool isString() const;
+ const char* asString() const;
+ void setString(const char* val);
+
+ bool isBool() const;
+ bool asBool() const;
+ void setBool(bool val);
+
+ bool isFloat() const;
+ float asFloat() const;
+ void setFloat(float val);
+
+ bool isDouble() const;
+ double asDouble() const;
+ void setDouble(double val);
+
+ bool isUuid() const;
+ const uint8_t* asUuid() const;
+ void setUuid(const uint8_t* val);
+
+ bool isObject() const;
+ const Object* asObject() const;
+ void setObject(Object* val);
+
+ bool isMap() const;
+ bool keyInMap(const char* key) const;
+ Value* byKey(const char* key);
+ const Value* byKey(const char* key) const;
+ void deleteKey(const char* key);
+ void insert(const char* key, Value* val);
+ uint32_t keyCount() const;
+ const char* key(uint32_t idx) const;
+
+ bool isList() const;
+ uint32_t listItemCount() const;
+ Value* listItem(uint32_t idx);
+ void appendToList(Value* val);
+ void deleteListItem(uint32_t idx);
+
+ bool isArray() const;
+ Typecode arrayType() const;
+ uint32_t arrayItemCount() const;
+ Value* arrayItem(uint32_t idx);
+ void appendToArray(Value* val);
+ void deleteArrayItem(uint32_t idx);
+
+ private:
+ friend struct ValueImpl;
+ friend class BrokerProxyImpl;
+ friend struct ObjectImpl;
+ friend class AgentImpl;
+ Value(ValueImpl* impl);
+ ValueImpl* impl;
+ };
+}
+}
+
+#endif
+
diff --git a/cpp/include/qpid/Address.h b/cpp/include/qpid/Address.h
new file mode 100755
index 0000000000..fe82b21b9e
--- /dev/null
+++ b/cpp/include/qpid/Address.h
@@ -0,0 +1,85 @@
+#ifndef QPID_ADDRESS_H
+#define QPID_ADDRESS_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/sys/IntegerTypes.h"
+#include "qpid/CommonImportExport.h"
+#include <boost/variant.hpp>
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+namespace qpid {
+
+/** TCP address of a broker - host:port */
+struct TcpAddress {
+ static const uint16_t DEFAULT_PORT=5672;
+ QPID_COMMON_EXTERN explicit TcpAddress(const std::string& host_=std::string(),uint16_t port_=DEFAULT_PORT);
+ std::string host;
+ uint16_t port;
+};
+bool operator==(const TcpAddress& x, const TcpAddress& y);
+QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& os, const TcpAddress& a);
+
+/**@internal Not a real address type, this is a placeholder to
+ * demonstrate and validate multi-protocol Urls for unit tests and
+ * developer education only. An example address holds just a char.
+ */
+struct ExampleAddress {
+ explicit ExampleAddress(char data);
+ char data;
+};
+bool operator==(const ExampleAddress& x, const ExampleAddress& y);
+std::ostream& operator<<(std::ostream& os, const ExampleAddress& a);
+
+/**
+ * Contains the address of an AMQP broker. Can any supported type of
+ * broker address. Currently only TcpAddress is supported.
+ */
+struct Address {
+public:
+ Address(const Address& a) : value(a.value) {}
+ Address(const TcpAddress& tcp) : value(tcp) {}
+ Address(const ExampleAddress& eg) : value(eg) {} ///<@internal
+
+ template <class AddressType> Address& operator=(const AddressType& t) { value=t; return *this; }
+
+ /** Get the address of type AddressType.
+ *@return AddressType* pointing to the contained address or 0 if
+ *contained address is not of type AddressType.
+ */
+ template <class AddressType> AddressType* get() { return boost::get<AddressType>(&value); }
+
+ /** Get the address of type AddressType.
+ *@return AddressType* pointing to the contained address or 0 if
+ *contained address is not of type AddressType.
+ */
+ template <class AddressType> const AddressType* get() const { return boost::get<AddressType>(&value); }
+
+private:
+ boost::variant<TcpAddress,ExampleAddress> value;
+ friend std::ostream& operator<<(std::ostream& os, const Address& addr);
+};
+
+
+
+} // namespace qpid
+
+#endif /*!QPID_ADDRESS_H*/
diff --git a/cpp/include/qpid/CommonImportExport.h b/cpp/include/qpid/CommonImportExport.h
new file mode 100644
index 0000000000..02c06ed7af
--- /dev/null
+++ b/cpp/include/qpid/CommonImportExport.h
@@ -0,0 +1,33 @@
+#ifndef QPID_COMMON_IMPORT_EXPORT_H
+#define QPID_COMMON_IMPORT_EXPORT_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#if defined(WIN32) && !defined(QPID_DECLARE_STATIC)
+#if defined(COMMON_EXPORT) || defined (qpidcommon_EXPORTS)
+#define QPID_COMMON_EXTERN __declspec(dllexport)
+#else
+#define QPID_COMMON_EXTERN __declspec(dllimport)
+#endif
+#else
+#define QPID_COMMON_EXTERN
+#endif
+
+#endif
diff --git a/cpp/include/qpid/Exception.h b/cpp/include/qpid/Exception.h
new file mode 100644
index 0000000000..7b937c242a
--- /dev/null
+++ b/cpp/include/qpid/Exception.h
@@ -0,0 +1,93 @@
+#ifndef _Exception_
+#define _Exception_
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/constants.h"
+#include "qpid/framing/enum.h"
+#include "qpid/sys/StrError.h"
+#include "qpid/Msg.h"
+#include "qpid/CommonImportExport.h"
+#include <memory>
+#include <string>
+#include <errno.h>
+
+namespace qpid
+{
+
+/**
+ * Base class for Qpid runtime exceptions.
+ */
+class Exception : public std::exception
+{
+ public:
+ QPID_COMMON_EXTERN explicit Exception(const std::string& message=std::string()) throw();
+ QPID_COMMON_EXTERN virtual ~Exception() throw();
+ QPID_COMMON_EXTERN virtual const char* what() const throw(); // prefix: message
+ QPID_COMMON_EXTERN virtual std::string getMessage() const; // Unprefixed message
+ QPID_COMMON_EXTERN virtual std::string getPrefix() const; // Prefix
+
+ private:
+ std::string message;
+ mutable std::string whatStr;
+};
+
+/** Exception that includes an errno message. */
+struct ErrnoException : public Exception {
+ ErrnoException(const std::string& msg, int err) : Exception(msg+": "+qpid::sys::strError(err)) {}
+ ErrnoException(const std::string& msg) : Exception(msg+": "+qpid::sys::strError(errno)) {}
+};
+
+struct SessionException : public Exception {
+ const framing::execution::ErrorCode code;
+ SessionException(framing::execution::ErrorCode code_, const std::string& message)
+ : Exception(message), code(code_) {}
+};
+
+struct ChannelException : public Exception {
+ const framing::session::DetachCode code;
+ ChannelException(framing::session::DetachCode _code, const std::string& message)
+ : Exception(message), code(_code) {}
+};
+
+struct ConnectionException : public Exception {
+ const framing::connection::CloseCode code;
+ ConnectionException(framing::connection::CloseCode _code, const std::string& message)
+ : Exception(message), code(_code) {}
+};
+
+struct ClosedException : public Exception {
+ QPID_COMMON_EXTERN ClosedException(const std::string& msg=std::string());
+ QPID_COMMON_EXTERN std::string getPrefix() const;
+};
+
+/**
+ * Exception representing transport failure
+ */
+struct TransportFailure : public Exception {
+ TransportFailure(const std::string& msg=std::string()) : Exception(msg) {}
+};
+
+} // namespace qpid
+
+#endif /*!_Exception_*/
diff --git a/cpp/include/qpid/InlineAllocator.h b/cpp/include/qpid/InlineAllocator.h
new file mode 100644
index 0000000000..2502545dcb
--- /dev/null
+++ b/cpp/include/qpid/InlineAllocator.h
@@ -0,0 +1,101 @@
+#ifndef QPID_INLINEALLOCATOR_H
+#define QPID_INLINEALLOCATOR_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <memory>
+#include <assert.h>
+#include <boost/type_traits/type_with_alignment.hpp>
+#include <boost/type_traits/alignment_of.hpp>
+
+namespace qpid {
+
+template <typename RequestedType, typename InlineType, typename BaseAllocator, size_t Max>
+struct InlineRebind;
+
+
+/**
+ * An allocator that has inline storage for up to Max objects
+ * of type BaseAllocator::value_type.
+ */
+template <class BaseAllocator, size_t Max>
+class InlineAllocator : public BaseAllocator {
+ public:
+ typedef typename BaseAllocator::pointer pointer;
+ typedef typename BaseAllocator::size_type size_type;
+ typedef typename BaseAllocator::value_type value_type;
+
+ InlineAllocator() : allocated(false) {}
+ InlineAllocator(const InlineAllocator& x) : BaseAllocator(x), allocated(false) {}
+
+ pointer allocate(size_type n) {
+ if (n <= Max && !allocated) {
+ allocated=true;
+ return reinterpret_cast<value_type*>(address());
+ }
+ else
+ return BaseAllocator::allocate(n, 0);
+ }
+
+ void deallocate(pointer p, size_type n) {
+ if (p == address()) {
+ assert(allocated);
+ allocated=false;
+ }
+ else
+ BaseAllocator::deallocate(p, n);
+ }
+
+ template<typename T1>
+ struct rebind {
+ typedef typename InlineRebind<T1, value_type, BaseAllocator, Max>::other other;
+ };
+
+ private:
+ // POD object with alignment and size to hold Max value_types.
+ static const size_t ALIGNMENT=boost::alignment_of<value_type>::value;
+ typedef typename boost::type_with_alignment<ALIGNMENT>::type Aligner;
+ union Store {
+ Aligner aligner_;
+ char sizer_[sizeof(value_type)*Max];
+ } store;
+ value_type* address() { return reinterpret_cast<value_type*>(&store); }
+ bool allocated;
+};
+
+
+// Rebind: if RequestedType == InlineType, use the InlineAllocator,
+// otherwise, use the BaseAllocator without any inlining.
+
+template <typename RequestedType, typename InlineType, typename BaseAllocator, size_t Max>
+struct InlineRebind {
+ typedef typename BaseAllocator::template rebind<RequestedType>::other other;
+};
+
+template <typename T, typename BaseAllocator, size_t Max>
+struct InlineRebind<T, T, BaseAllocator, Max> {
+ typedef typename qpid::InlineAllocator<BaseAllocator, Max> other;
+};
+
+} // namespace qpid
+
+#endif /*!QPID_INLINEALLOCATOR_H*/
diff --git a/cpp/include/qpid/InlineVector.h b/cpp/include/qpid/InlineVector.h
new file mode 100644
index 0000000000..c55db295f3
--- /dev/null
+++ b/cpp/include/qpid/InlineVector.h
@@ -0,0 +1,68 @@
+#ifndef QPID_INLINEVECTOR_H
+#define QPID_INLINEVECTOR_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/InlineAllocator.h"
+#include <vector>
+
+namespace qpid {
+
+/**
+ * A vector that stores up to Max elements in inline storage,
+ * otherwise uses normal vector allocation.
+ *
+ * NOTE: depends on some non-standard but highly probably assumptions
+ * about how std::vector uses its allocator, they are true for g++.
+ * - default constructor does not allocate.
+ * - reserve(N) does not allocate more than N elements.
+ * - vector never re-allocates when size() < capacity()
+ */
+template <class T, size_t Max, class Alloc=std::allocator<T> >
+class InlineVector : public std::vector<T, InlineAllocator<Alloc, Max> >
+{
+ typedef std::vector<T, InlineAllocator<Alloc, Max> > Base;
+ public:
+ typedef typename Base::allocator_type allocator_type;
+ typedef typename Base::value_type value_type;
+ typedef typename Base::size_type size_type;
+
+ explicit InlineVector(const allocator_type& a=allocator_type()) : Base(a) {
+ this->reserve(Max);
+ }
+
+ explicit InlineVector(size_type n, const value_type& x = value_type(),
+ const allocator_type& a=allocator_type()) : Base(a)
+ {
+ this->reserve(std::max(n, Max));
+ this->insert(this->end(), n, x);
+ }
+
+ InlineVector(const InlineVector& x) : Base() {
+ this->reserve(std::max(x.size(), Max));
+ *this = x;
+ }
+};
+
+} // namespace qpid
+
+#endif /*!QPID_INLINEVECTOR_H*/
diff --git a/cpp/include/qpid/Msg.h b/cpp/include/qpid/Msg.h
new file mode 100644
index 0000000000..6e08a89571
--- /dev/null
+++ b/cpp/include/qpid/Msg.h
@@ -0,0 +1,76 @@
+#ifndef QPID_MSG_H
+#define QPID_MSG_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <sstream>
+#include <iostream>
+
+namespace qpid {
+
+/** A simple wrapper for std::ostringstream that allows
+ * in place construction of a message and automatic conversion
+ * to string.
+ * E.g.
+ *@code
+ * void foo(const std::string&);
+ * foo(Msg() << "hello " << 32);
+ *@endcode
+ * Will construct the string "hello 32" and pass it to foo()
+ */
+struct Msg {
+ std::ostringstream os;
+ Msg() {}
+ Msg(const Msg& m) : os(m.str()) {}
+ std::string str() const { return os.str(); }
+ operator std::string() const { return str(); }
+
+ Msg& operator<<(long n) { os << n; return *this; }
+ Msg& operator<<(unsigned long n) { os << n; return *this; }
+ Msg& operator<<(bool n) { os << n; return *this; }
+ Msg& operator<<(short n) { os << n; return *this; }
+ Msg& operator<<(unsigned short n) { os << n; return *this; }
+ Msg& operator<<(int n) { os << n; return *this; }
+ Msg& operator<<(unsigned int n) { os << n; return *this; }
+#ifdef _GLIBCXX_USE_LONG_LONG
+ Msg& operator<<(long long n) { os << n; return *this; }
+ Msg& operator<<(unsigned long long n) { os << n; return *this; }
+#endif
+ Msg& operator<<(double n) { os << n; return *this; }
+ Msg& operator<<(float n) { os << n; return *this; }
+ Msg& operator<<(long double n) { os << n; return *this; }
+
+ template <class T> Msg& operator<<(const T& t) { os <<t; return *this; }
+};
+
+
+
+inline std::ostream& operator<<(std::ostream& o, const Msg& m) {
+ return o << m.str();
+}
+
+/** Construct a message using operator << and append (file:line) */
+#define QPID_MSG(message) ::qpid::Msg() << message << " (" << __FILE__ << ":" << __LINE__ << ")"
+
+} // namespace qpid
+
+#endif /*!QPID_MSG_H*/
diff --git a/cpp/include/qpid/Options.h b/cpp/include/qpid/Options.h
new file mode 100644
index 0000000000..078a6b4d95
--- /dev/null
+++ b/cpp/include/qpid/Options.h
@@ -0,0 +1,265 @@
+#ifndef QPID_COMMONOPTIONS_H
+#define QPID_COMMONOPTIONS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Exception.h"
+
+// Disable warnings triggered by boost.
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable : 4251 4275)
+#endif
+
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
+
+#include <sstream>
+#include <iterator>
+#include <algorithm>
+#include <string>
+#include "qpid/CommonImportExport.h"
+
+namespace qpid {
+namespace po=boost::program_options;
+
+
+
+///@internal
+QPID_COMMON_EXTERN std::string prettyArg(const std::string&, const std::string&);
+
+/** @internal Normally only constructed by optValue() */
+template <class T>
+class OptionValue : public po::typed_value<T> {
+ public:
+ OptionValue(T& value, const std::string& arg)
+ : po::typed_value<T>(&value), argName(arg) {}
+ std::string name() const { return argName; }
+
+ private:
+ std::string argName;
+};
+
+
+/** Create an option value.
+ * name, value appear after the option name in help like this:
+ * <name> (=<value>)
+ * T must support operator <<.
+ *@see Options for example of use.
+ */
+template<class T>
+po::value_semantic* optValue(T& value, const char* name) {
+ std::string valstr(boost::lexical_cast<std::string>(value));
+ return new OptionValue<T>(value, prettyArg(name, valstr));
+}
+
+/** Create a vector value. Multiple occurences of the option are
+ * accumulated into the vector
+ */
+template <class T>
+po::value_semantic* optValue(std::vector<T>& value, const char* name) {
+ using namespace std;
+ ostringstream os;
+ copy(value.begin(), value.end(), ostream_iterator<T>(os, " "));
+ string val=os.str();
+ if (!val.empty())
+ val.erase(val.end()-1); // Remove trailing " "
+ return (new OptionValue<vector<T> >(value, prettyArg(name, val)));
+}
+
+/** Create a boolean switch value. Presence of the option sets the value. */
+inline po::value_semantic* optValue(bool& value) { return po::bool_switch(&value); }
+
+/**
+ * Base class for options.
+ * Example of use:
+ @code
+ struct MySubOptions : public Options {
+ int x;
+ string y;
+ MySubOptions() : Options("Sub options") {
+ addOptions()
+ ("x", optValue(x,"XUNIT"), "Option X")
+ ("y", optValue(y, "YUNIT"), "Option Y");
+ }
+ };
+
+ struct MyOptions : public Options {
+ bool z;
+ vector<string> foo;
+ MySubOptions subOptions;
+ MyOptions() : Options("My Options") {
+ addOptions()
+ ("z", boolSwitch(z), "Option Z")
+ ("foo", optValue(foo), "Multiple option foo");
+ add(subOptions);
+ }
+
+ main(int argc, char** argv) {
+ Options opts;
+ opts.parse(argc, char** argv);
+ // Use values
+ dosomething(opts.subOptions.x);
+ if (error)
+ cout << opts << end; // Help message.
+ }
+
+ @endcode
+ */
+
+
+
+
+/*
+ * ---------------------------------------------
+ * Explanation for Boost 103200 conditional code
+ * ---------------------------------------------
+ *
+ * This boost version has an implementation of the program_options library
+ * that has no provision for allowing unregistered options to pass by.
+ *
+ * But that means that, if you have a program that loads optional modules
+ * after start-up, and those modules each have their own set of options,
+ * then if you parse the command line too soon, you will get spurious
+ * reports of unrecognized options -- and the program will exit!
+ *
+ * And we must process the command-line before module-loading, because we
+ * need to look at the "bootstrap" options.
+ *
+ * This conditional code:
+ *
+ * 1. implements it's own functor class, derived from the Boost
+ * "options_description_easy_init" class. This functor is used
+ * to process added options and do the functor chaining, so that
+ * I can snoop on the arguments before doing an explicit call
+ * to its parent.
+ *
+ * 2. It implements two static vectors, one to hold long names, and
+ * one for short names, so that options declared by modules are
+ * not forgotten when their options_description goes out of scope.
+ *
+ * I will be thrilled to personally delete this code if we ever decide
+ * that qpid doesn't really need to support this antique version of Boost.
+ *
+ */
+
+#if ( BOOST_VERSION == 103200 )
+struct Options;
+
+
+struct
+options_description_less_easy_init
+ : public po::options_description_easy_init
+{
+ options_description_less_easy_init ( Options * my_owner,
+ po::options_description * my_parents_owner
+ )
+ : po::options_description_easy_init(my_parents_owner)
+ {
+ owner = my_owner;
+ }
+
+
+ options_description_less_easy_init&
+ operator()(char const * name,
+ char const * description);
+
+
+ options_description_less_easy_init&
+ operator()(char const * name,
+ const po::value_semantic* s);
+
+
+ options_description_less_easy_init&
+ operator()(const char* name,
+ const po::value_semantic* s,
+ const char* description);
+
+
+ Options * owner;
+};
+#endif
+
+
+struct Options : public po::options_description {
+
+ struct Exception : public qpid::Exception {
+ Exception(const std::string& msg) : qpid::Exception(msg) {}
+ };
+
+ QPID_COMMON_EXTERN Options(const std::string& name=std::string());
+
+ /**
+ * Parses options from argc/argv, environment variables and config file.
+ * Note the filename argument can reference an options variable that
+ * is updated by argc/argv or environment variable parsing.
+ */
+ QPID_COMMON_EXTERN void parse(int argc, char const* const* argv,
+ const std::string& configfile=std::string(),
+ bool allowUnknown = false);
+
+
+ #if ( BOOST_VERSION == 103200 )
+ options_description_less_easy_init m_less_easy;
+
+ options_description_less_easy_init addOptions() {
+ return m_less_easy;
+ }
+
+ bool
+ is_registered_option ( std::string s );
+
+ void
+ register_names ( std::string s );
+
+ static std::vector<std::string> long_names;
+ static std::vector<std::string> short_names;
+ #else
+ boost::program_options::options_description_easy_init addOptions() {
+ return add_options();
+ }
+ #endif
+};
+
+
+
+/**
+ * Standard options for configuration
+ */
+struct CommonOptions : public Options {
+ QPID_COMMON_EXTERN CommonOptions(const std::string& name=std::string(),
+ const std::string& configfile=std::string());
+ bool help;
+ bool version;
+ std::string config;
+};
+
+
+
+
+} // namespace qpid
+
+#endif /*!QPID_COMMONOPTIONS_H*/
diff --git a/cpp/include/qpid/RangeSet.h b/cpp/include/qpid/RangeSet.h
new file mode 100644
index 0000000000..1b2e4201a6
--- /dev/null
+++ b/cpp/include/qpid/RangeSet.h
@@ -0,0 +1,330 @@
+#ifndef QPID_RANGESET_H
+#define QPID_RANGESET_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/InlineVector.h"
+#include <boost/iterator/iterator_facade.hpp>
+#include <boost/operators.hpp>
+#include <boost/bind.hpp>
+#include <algorithm>
+#include <numeric>
+
+namespace qpid {
+
+/** A range of values, used in RangeSet.
+ * Range(begin, end) includes begin but excludes end.
+ * Range::makeClosed(first,last) includes both first and last.
+ */
+template <class T>
+class Range {
+ public:
+ static Range makeClosed(const T& first, T last) { return Range(first, ++last); }
+
+ Range() : begin_(), end_() {}
+ explicit Range(const T& t) : begin_(t), end_(t) { ++end_; }
+ Range(const T& b, const T& e) : begin_(b), end_(e) { assert(b <= e); }
+
+ T begin() const { return begin_; }
+ /** End of _open_ range, i.e. !contains(end()) */
+ T end() const { return end_; }
+
+ T first() const { assert(!empty()); return begin_; }
+ /** Last in closed range, i.e. contains(end()) */
+ T last() const { assert(!empty()); T ret=end_; return --ret; }
+
+ void begin(const T& t) { begin_ = t; }
+ void end(const T& t) { end_ = t; }
+ size_t size() const { return end_ - begin_; }
+ bool empty() const { return begin_ == end_; }
+
+ bool contains(const T& x) const { return begin_ <= x && x < end_; }
+ bool contains(const Range& r) const { return begin_ <= r.begin_ && r.end_ <= end_; }
+ bool strictContains(const Range& r) const { return begin_ < r.begin_ && r.end_ < end_; }
+
+ bool operator==(const Range& x) { return begin_ == x.begin_ && end_== x.end_; }
+
+ bool operator<(const T& t) const { return end_ < t; }
+ bool operator<(const Range<T>& r) const { return end_ < r.begin_; }
+
+ /** touching ranges can be merged into a single range. */
+ bool touching(const Range& r) const {
+ return std::max(begin_, r.begin_) <= std::min(end_, r.end_);
+ }
+
+ /** @pre touching */
+ void merge(const Range& r) {
+ assert(touching(r));
+ begin_ = std::min(begin_, r.begin_);
+ end_ = std::max(end_, r.end_);
+ }
+
+ operator bool() const { return !empty(); }
+
+ template <class S> void serialize(S& s) { s(begin_)(end_); }
+
+ private:
+ T begin_, end_;
+};
+
+
+/**
+ * A set implemented as a list of [begin, end) ranges.
+ * T must be LessThanComparable and Incrementable.
+ * RangeSet only provides const iterators.
+ */
+template <class T>
+class RangeSet
+ : boost::additive1<RangeSet<T>,
+ boost::additive2<RangeSet<T>, Range<T>,
+ boost::additive2<RangeSet<T>, T> > >
+{
+ typedef InlineVector<Range<T>, 3> Ranges; // TODO aconway 2008-04-21: what's the optimial inlined value?
+
+ public:
+
+ class iterator : public boost::iterator_facade<
+ iterator,
+ const T,
+ boost::forward_traversal_tag>
+ {
+ public:
+ iterator() : ranges(), iter(), value() {}
+
+ private:
+ typedef typename Ranges::const_iterator RangesIter;
+ iterator(const Ranges& r, const RangesIter& i, const T& t)
+ : ranges(&r), iter(i), value(t) {}
+
+ void increment();
+ bool equal(const iterator& i) const;
+ const T& dereference() const { return value; }
+
+ const Ranges* ranges;
+ RangesIter iter;
+ T value;
+
+ friend class RangeSet<T>;
+ friend class boost::iterator_core_access;
+ };
+
+ typedef iterator const_iterator;
+
+ RangeSet() {}
+ explicit RangeSet(const Range<T>& r) { *this += r; }
+ RangeSet(const T& a, const T& b) { *this += Range<T>(a,b); }
+
+ bool contiguous() const { return ranges.size() <= 1; }
+
+ bool contains(const T& t) const;
+ bool contains(const Range<T>&) const;
+
+ /**@pre contiguous() */
+ Range<T> toRange() const;
+
+ bool operator==(const RangeSet<T>&) const;
+
+ void addRange (const Range<T>&);
+ void addSet (const RangeSet<T>&);
+
+ RangeSet<T>& operator+=(const T& t) { return *this += Range<T>(t); }
+ RangeSet<T>& operator+=(const Range<T>& r) { addRange(r); return *this; }
+ RangeSet<T>& operator+=(const RangeSet<T>& s) { addSet(s); return *this; }
+
+ void removeRange (const Range<T>&);
+ void removeSet (const RangeSet<T>&);
+
+ RangeSet<T>& operator-=(const T& t) { return *this -= Range<T>(t); }
+ RangeSet<T>& operator-=(const Range<T>& r) { removeRange(r); return *this; }
+ RangeSet<T>& operator-=(const RangeSet<T>& s) { removeSet(s); return *this; }
+
+ T front() const { return ranges.front().begin(); }
+ T back() const { return ranges.back().end(); }
+
+ // Iterate over elements in the set.
+ iterator begin() const;
+ iterator end() const;
+
+ // Iterate over ranges in the set.
+ typedef typename Ranges::const_iterator RangeIterator;
+ RangeIterator rangesBegin() const { return ranges.begin(); }
+ RangeIterator rangesEnd() const { return ranges.end(); }
+ size_t rangesSize() const { return ranges.size(); }
+
+ // The difference between the start and end of this range set
+ uint32_t span() const;
+
+ size_t size() const;
+ bool empty() const { return ranges.empty(); }
+ void clear() { ranges.clear(); }
+
+ /** Return the largest contiguous range containing x.
+ * Returns the empty range [x,x) if x is not in the set.
+ */
+ Range<T> rangeContaining(const T&) const;
+
+ template <class S> void serialize(S& s) { s.split(*this); s(ranges.begin(), ranges.end()); }
+ template <class S> void encode(S& s) const { s(uint16_t(ranges.size()*sizeof(Range<T>))); }
+ template <class S> void decode(S& s) { uint16_t sz; s(sz); ranges.resize(sz/sizeof(Range<T>)); }
+
+ private:
+ static size_t accumulateSize(size_t s, const Range<T>& r) { return s+r.size(); }
+ Ranges ranges;
+
+ template <class U> friend std::ostream& operator<<(std::ostream& o, const RangeSet<U>& r);
+
+ friend class iterator;
+};
+
+template <class T>
+std::ostream& operator<<(std::ostream& o, const Range<T>& r) {
+ return o << "[" << r.begin() << "," << r.end() << ")";
+}
+
+template <class T>
+std::ostream& operator<<(std::ostream& o, const RangeSet<T>& rs) {
+ std::ostream_iterator<Range<T> > i(o, " ");
+ o << "{ ";
+ std::copy(rs.ranges.begin(), rs.ranges.end(), i);
+ return o << "}";
+}
+
+template <class T>
+bool RangeSet<T>::contains(const T& t) const {
+ typename Ranges::const_iterator i =
+ std::lower_bound(ranges.begin(), ranges.end(), Range<T>(t));
+ return i != ranges.end() && i->contains(t);
+}
+
+template <class T>
+bool RangeSet<T>::contains(const Range<T>& r) const {
+ typename Ranges::const_iterator i =
+ std::lower_bound(ranges.begin(), ranges.end(), r);
+ return i != ranges.end() && i->contains(r);
+}
+
+template <class T> void RangeSet<T>::addRange(const Range<T>& r) {
+ if (r.empty()) return;
+ typename Ranges::iterator i =
+ std::lower_bound(ranges.begin(), ranges.end(), r);
+ if (i == ranges.end() || !i->touching(r))
+ ranges.insert(i, r);
+ else {
+ i->merge(r);
+ typename Ranges::iterator j = i;
+ if (++j != ranges.end() && i->touching(*j)) {
+ i->merge(*j);
+ ranges.erase(j);
+ }
+ }
+}
+
+
+template <class T> void RangeSet<T>::addSet(const RangeSet<T>& s) {
+ typedef RangeSet<T>& (RangeSet<T>::*RangeSetRangeOp)(const Range<T>&);
+ std::for_each(s.ranges.begin(), s.ranges.end(),
+ boost::bind((RangeSetRangeOp)&RangeSet<T>::operator+=, this, _1));
+}
+
+template <class T> void RangeSet<T>::removeRange(const Range<T>& r) {
+ if (r.empty()) return;
+ typename Ranges::iterator i,j;
+ i = std::lower_bound(ranges.begin(), ranges.end(), r);
+ if (i == ranges.end() || i->begin() >= r.end())
+ return; // Outside of set
+ if (*i == r) // Erase i
+ ranges.erase(i);
+ else if (i->strictContains(r)) { // Split i
+ Range<T> i1(i->begin(), r.begin());
+ Range<T> i2(r.end(), i->end());
+ *i = i2;
+ ranges.insert(i, i1);
+ } else {
+ if (i->begin() < r.begin()) { // Truncate i
+ i->end(r.begin());
+ ++i;
+ }
+ for (j = i; j != ranges.end() && r.contains(*j); ++j)
+ ; // Ranges to erase.
+ if (j != ranges.end() && j->end() > r.end())
+ j->begin(r.end()); // Truncate j
+ ranges.erase(i,j);
+ }
+}
+
+template <class T> void RangeSet<T>::removeSet(const RangeSet<T>& r) {
+ std::for_each(
+ r.ranges.begin(), r.ranges.end(),
+ boost::bind(&RangeSet<T>::removeRange, this, _1));
+}
+
+template <class T> Range<T> RangeSet<T>::toRange() const {
+ assert(contiguous());
+ return empty() ? Range<T>() : ranges.front();
+}
+
+template <class T> void RangeSet<T>::iterator::increment() {
+ assert(ranges && iter != ranges->end());
+ if (!iter->contains(++value)) {
+ ++iter;
+ if (iter == ranges->end())
+ *this=iterator(); // end() iterator
+ else
+ value=iter->begin();
+ }
+}
+
+template <class T> bool RangeSet<T>::operator==(const RangeSet<T>& r) const {
+ return ranges.size() == r.ranges.size() && std::equal(ranges.begin(), ranges.end(), r.ranges.begin());
+}
+
+template <class T> typename RangeSet<T>::iterator RangeSet<T>::begin() const {
+ return empty() ? end() : iterator(ranges, ranges.begin(), front());
+}
+
+template <class T> typename RangeSet<T>::iterator RangeSet<T>::end() const {
+ return iterator();
+}
+
+template <class T> bool RangeSet<T>::iterator::equal(const iterator& i) const {
+ return ranges==i.ranges && (ranges==0 || value==i.value);
+}
+
+template <class T> Range<T> RangeSet<T>::rangeContaining(const T& t) const {
+ typename Ranges::const_iterator i =
+ std::lower_bound(ranges.begin(), ranges.end(), Range<T>(t));
+ return (i != ranges.end() && i->contains(t)) ? *i : Range<T>(t,t);
+}
+
+template <class T> uint32_t RangeSet<T>::span() const {
+ if (ranges.empty()) return 0;
+ return ranges.back().last() - ranges.front().first();
+}
+
+template <class T> size_t RangeSet<T>::size() const {
+ return std::accumulate(rangesBegin(), rangesEnd(), 0, &RangeSet<T>::accumulateSize);
+}
+
+} // namespace qpid
+
+
+#endif /*!QPID_RANGESET_H*/
diff --git a/cpp/include/qpid/SessionId.h b/cpp/include/qpid/SessionId.h
new file mode 100644
index 0000000000..e18b360999
--- /dev/null
+++ b/cpp/include/qpid/SessionId.h
@@ -0,0 +1,60 @@
+#ifndef QPID_SESSIONID_H
+#define QPID_SESSIONID_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/operators.hpp>
+#include <string>
+#include <qpid/CommonImportExport.h>
+
+namespace qpid {
+
+/** Identifier for a session.
+ * There are two parts to a session identifier:
+ *
+ * getUserId() returns the authentication principal associated with
+ * the session's connection.
+ *
+ * getName() returns the session name.
+ *
+ * The name must be unique among sessions with the same authentication
+ * principal.
+ */
+class SessionId : boost::totally_ordered1<SessionId> {
+ std::string userId;
+ std::string name;
+ public:
+ QPID_COMMON_EXTERN SessionId(const std::string& userId=std::string(), const std::string& name=std::string());
+ std::string getUserId() const { return userId; }
+ std::string getName() const { return name; }
+ QPID_COMMON_EXTERN bool operator<(const SessionId&) const ;
+ QPID_COMMON_EXTERN bool operator==(const SessionId& id) const;
+ // Convert to a string
+ QPID_COMMON_EXTERN std::string str() const;
+};
+
+QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, const SessionId&);
+
+
+} // namespace qpid
+
+#endif /*!QPID_SESSIONID_H*/
diff --git a/cpp/include/qpid/Url.h b/cpp/include/qpid/Url.h
new file mode 100644
index 0000000000..d0f4bb0c22
--- /dev/null
+++ b/cpp/include/qpid/Url.h
@@ -0,0 +1,93 @@
+#ifndef QPID_URL_H
+#define QPID_URL_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/Address.h"
+#include "qpid/Exception.h"
+#include <string>
+#include <vector>
+#include <new>
+#include <ostream>
+#include "qpid/CommonImportExport.h"
+
+namespace qpid {
+
+QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& os, const TcpAddress& a);
+
+/** An AMQP URL contains a list of addresses */
+struct Url : public std::vector<Address> {
+
+ /** Url with the hostname as returned by gethostname(2) */
+ static Url getHostNameUrl(uint16_t port);
+
+ /** Url with local IP address(es), may be more than one address
+ * on a multi-homed host. */
+ QPID_COMMON_EXTERN static Url getIpAddressesUrl(uint16_t port);
+
+ struct Invalid : public Exception { Invalid(const std::string& s); };
+
+ /** Convert to string form. */
+ QPID_COMMON_EXTERN std::string str() const;
+
+ /** Empty URL. */
+ Url() {}
+
+ /** URL containing a single address */
+ explicit Url(const Address& addr) { push_back(addr); }
+
+ /** Parse url, throw Invalid if invalid. */
+ explicit Url(const std::string& url) { parse(url.c_str()); }
+
+ /** Parse url, throw Invalid if invalid. */
+ explicit Url(const char* url) { parse(url); }
+
+ Url& operator=(const Url& u) { this->std::vector<Address>::operator=(u); cache=u.cache; return *this; }
+ Url& operator=(const char* s) { parse(s); return *this; }
+ Url& operator=(const std::string& s) { parse(s); return *this; }
+
+ /** Throw Invalid if the URL does not contain any addresses. */
+ QPID_COMMON_EXTERN void throwIfEmpty() const;
+
+ /** Replace contents with parsed URL as defined in
+ * https://wiki.108.redhat.com/jira/browse/AMQP-95
+ *@exception Invalid if the url is invalid.
+ */
+ QPID_COMMON_EXTERN void parse(const char* url);
+ QPID_COMMON_EXTERN void parse(const std::string& url) { parse(url.c_str()); }
+
+ /** Replace contesnts with parsed URL as defined in
+ * https://wiki.108.redhat.com/jira/browse/AMQP-95
+ * url.empty() will be true if url is invalid.
+ */
+ void parseNoThrow(const char* url);
+
+ private:
+ mutable std::string cache; // cache string form for efficiency.
+};
+
+inline bool operator==(const Url& a, const Url& b) { return a.str()==b.str(); }
+inline bool operator!=(const Url& a, const Url& b) { return a.str()!=b.str(); }
+
+QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& os, const Url& url);
+QPID_COMMON_EXTERN std::istream& operator>>(std::istream& is, Url& url);
+
+} // namespace qpid
+
+#endif /*!QPID_URL_H*/
diff --git a/cpp/include/qpid/agent/ManagementAgent.h b/cpp/include/qpid/agent/ManagementAgent.h
new file mode 100644
index 0000000000..1a8d0c4025
--- /dev/null
+++ b/cpp/include/qpid/agent/ManagementAgent.h
@@ -0,0 +1,163 @@
+#ifndef _qpid_agent_ManagementAgent_
+#define _qpid_agent_ManagementAgent_
+
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES 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/agent/QmfAgentImportExport.h"
+#include "qpid/management/ManagementObject.h"
+#include "qpid/management/ManagementEvent.h"
+#include "qpid/management/Manageable.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/client/ConnectionSettings.h"
+
+namespace qpid {
+namespace management {
+
+class ManagementAgent
+{
+ public:
+
+ class Singleton {
+ public:
+ QMF_AGENT_EXTERN Singleton(bool disableManagement = false);
+ QMF_AGENT_EXTERN ~Singleton();
+ QMF_AGENT_EXTERN static ManagementAgent* getInstance();
+ private:
+ static sys::Mutex lock;
+ static bool disabled;
+ static int refCount;
+ static ManagementAgent* agent;
+ };
+
+ typedef enum {
+ SEV_EMERG = 0,
+ SEV_ALERT = 1,
+ SEV_CRIT = 2,
+ SEV_ERROR = 3,
+ SEV_WARN = 4,
+ SEV_NOTE = 5,
+ SEV_INFO = 6,
+ SEV_DEBUG = 7,
+ SEV_DEFAULT = 8
+ } severity_t;
+
+ ManagementAgent() {}
+ virtual ~ManagementAgent() {}
+
+ virtual int getMaxThreads() = 0;
+
+ // Connect to a management broker
+ //
+ // brokerHost - Hostname or IP address (dotted-quad) of broker.
+ //
+ // brokerPort - TCP port of broker.
+ //
+ // intervalSeconds - The interval (in seconds) that this agent shall use
+ // between broadcast updates to the broker.
+ //
+ // useExternalThread - If true, the thread of control used for callbacks
+ // must be supplied by the user of the object (via the
+ // pollCallbacks method).
+ //
+ // If false, callbacks shall be invoked on the management
+ // agent's thread. In this case, the callback implementations
+ // MUST be thread safe.
+ //
+ // storeFile - File where this process has read and write access. This
+ // file shall be used to store persistent state.
+ //
+ virtual void init(const std::string& brokerHost = "localhost",
+ uint16_t brokerPort = 5672,
+ uint16_t intervalSeconds = 10,
+ bool useExternalThread = false,
+ const std::string& storeFile = "",
+ const std::string& uid = "guest",
+ const std::string& pwd = "guest",
+ const std::string& mech = "PLAIN",
+ const std::string& proto = "tcp") = 0;
+
+ virtual void init(const client::ConnectionSettings& settings,
+ uint16_t intervalSeconds = 10,
+ bool useExternalThread = false,
+ const std::string& storeFile = "") = 0;
+
+ // Register a schema with the management agent. This is normally called by the
+ // package initializer generated by the management code generator.
+ //
+ virtual void
+ registerClass(const std::string& packageName,
+ const std::string& className,
+ uint8_t* md5Sum,
+ management::ManagementObject::writeSchemaCall_t schemaCall) = 0;
+
+ virtual void
+ registerEvent(const std::string& packageName,
+ const std::string& eventName,
+ uint8_t* md5Sum,
+ management::ManagementEvent::writeSchemaCall_t schemaCall) = 0;
+
+ // Add a management object to the agent. Once added, this object shall be visible
+ // in the greater management context.
+ //
+ // Please note that ManagementObject instances are not explicitly deleted from
+ // the management agent. When the core object represented by a management object
+ // is deleted, the "resourceDestroy" method on the management object must be called.
+ // It will then be reclaimed in due course by the management agent.
+ //
+ // Once a ManagementObject instance is added to the agent, the agent then owns the
+ // instance. The caller MUST NOT free the resources of the instance at any time.
+ // When it is no longer needed, invoke its "resourceDestroy" method and discard the
+ // pointer. This allows the management agent to report the deletion of the object
+ // in an orderly way.
+ //
+ virtual ObjectId addObject(ManagementObject* objectPtr, uint64_t persistId = 0) = 0;
+
+ //
+ //
+ virtual void raiseEvent(const ManagementEvent& event,
+ severity_t severity = SEV_DEFAULT) = 0;
+
+ // If "useExternalThread" was set to true in init, this method must
+ // be called to provide a thread for any pending method calls that have arrived.
+ // The method calls for ManagementObject instances shall be invoked synchronously
+ // during the execution of this method.
+ //
+ // callLimit may optionally be used to limit the number of callbacks invoked.
+ // if 0, no limit is imposed.
+ //
+ // The return value is the number of callbacks that remain queued after this
+ // call is complete. It can be used to determine whether or not further calls
+ // to pollCallbacks are necessary to clear the backlog. If callLimit is zero,
+ // the return value will also be zero.
+ //
+ virtual uint32_t pollCallbacks(uint32_t callLimit = 0) = 0;
+
+ // If "useExternalThread" was set to true in the constructor, this method provides
+ // a standard file descriptor that can be used in a select statement to signal that
+ // there are method callbacks ready (i.e. that "pollCallbacks" will result in at
+ // least one method call). When this fd is ready-for-read, pollCallbacks may be
+ // invoked. Calling pollCallbacks shall reset the ready-to-read state of the fd.
+ //
+ virtual int getSignalFd() = 0;
+};
+
+}}
+
+#endif /*!_qpid_agent_ManagementAgent_*/
diff --git a/cpp/include/qpid/agent/QmfAgentImportExport.h b/cpp/include/qpid/agent/QmfAgentImportExport.h
new file mode 100644
index 0000000000..9eee4a18fd
--- /dev/null
+++ b/cpp/include/qpid/agent/QmfAgentImportExport.h
@@ -0,0 +1,33 @@
+#ifndef QMF_AGENT_IMPORT_EXPORT_H
+#define QMF_AGENT_IMPORT_EXPORT_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#if defined(WIN32) && !defined(QPID_DECLARE_STATIC)
+#if defined(QMF_AGENT_EXPORT) || defined (qmfagent_EXPORTS)
+#define QMF_AGENT_EXTERN __declspec(dllexport)
+#else
+#define QMF_AGENT_EXTERN __declspec(dllimport)
+#endif
+#else
+#define QMF_AGENT_EXTERN
+#endif
+
+#endif
diff --git a/cpp/include/qpid/client/AsyncSession.h b/cpp/include/qpid/client/AsyncSession.h
new file mode 100644
index 0000000000..d91efeb4f1
--- /dev/null
+++ b/cpp/include/qpid/client/AsyncSession.h
@@ -0,0 +1,38 @@
+#ifndef QPID_CLIENT_ASYNCSESSION_H
+#define QPID_CLIENT_ASYNCSESSION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/AsyncSession_0_10.h"
+
+namespace qpid {
+namespace client {
+
+/**
+ * AsyncSession is an alias for Session_0_10
+ *
+ * \ingroup clientapi
+ */
+typedef AsyncSession_0_10 AsyncSession;
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_ASYNCSESSION_H*/
diff --git a/cpp/include/qpid/client/ClientImportExport.h b/cpp/include/qpid/client/ClientImportExport.h
new file mode 100644
index 0000000000..42b02e33c3
--- /dev/null
+++ b/cpp/include/qpid/client/ClientImportExport.h
@@ -0,0 +1,33 @@
+#ifndef QPID_CLIENT_IMPORT_EXPORT_H
+#define QPID_CLIENT_IMPORT_EXPORT_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#if defined(WIN32) && !defined(QPID_DECLARE_STATIC)
+#if defined(CLIENT_EXPORT) || defined (qpidclient_EXPORTS)
+#define QPID_CLIENT_EXTERN __declspec(dllexport)
+#else
+#define QPID_CLIENT_EXTERN __declspec(dllimport)
+#endif
+#else
+#define QPID_CLIENT_EXTERN
+#endif
+
+#endif
diff --git a/cpp/include/qpid/client/Completion.h b/cpp/include/qpid/client/Completion.h
new file mode 100644
index 0000000000..99d940f031
--- /dev/null
+++ b/cpp/include/qpid/client/Completion.h
@@ -0,0 +1,71 @@
+#ifndef QPID_CLIENT_COMPLETION_H
+#define QPID_CLIENT_COMPLETION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/Handle.h"
+#include "qpid/client/ClientImportExport.h"
+#include <string>
+
+namespace qpid {
+namespace client {
+
+class CompletionImpl;
+template <class T> class PrivateImplRef;
+
+/**
+ * Asynchronous commands that do not return a result will return a
+ * Completion. You can use the completion to wait for that specific
+ * command to complete.
+ *
+ *@see TypedResult
+ *
+ *\ingroup clientapi
+ */
+class Completion : public Handle<CompletionImpl>
+{
+public:
+ QPID_CLIENT_EXTERN Completion(CompletionImpl* = 0);
+ QPID_CLIENT_EXTERN Completion(const Completion&);
+ QPID_CLIENT_EXTERN ~Completion();
+ QPID_CLIENT_EXTERN Completion& operator=(const Completion&);
+
+ /** Wait for the asynchronous command that returned this
+ *Completion to complete.
+ *
+ *@exception If the command returns an error.
+ */
+ QPID_CLIENT_EXTERN void wait();
+ QPID_CLIENT_EXTERN bool isComplete();
+
+ protected:
+ QPID_CLIENT_EXTERN std::string getResult();
+
+ private:
+ typedef CompletionImpl Impl;
+ friend class PrivateImplRef<Completion>;
+};
+
+}}
+
+
+#endif /*!QPID_CLIENT_COMPLETION_H*/
diff --git a/cpp/include/qpid/client/Connection.h b/cpp/include/qpid/client/Connection.h
new file mode 100644
index 0000000000..bcf2962557
--- /dev/null
+++ b/cpp/include/qpid/client/Connection.h
@@ -0,0 +1,222 @@
+#ifndef QPID_CLIENT_CONNECTION_H
+#define QPID_CLIENT_CONNECTION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <map>
+#include <string>
+#include "qpid/client/Session.h"
+#include "qpid/client/ClientImportExport.h"
+#include "qpid/client/ConnectionSettings.h"
+#include "qpid/framing/ProtocolVersion.h"
+
+namespace qpid {
+
+struct Url;
+
+namespace client {
+
+class ConnectionImpl;
+
+/**
+ * Represents a connection to an AMQP broker. All communication is
+ * initiated by establishing a connection, then creating one or more
+ * Session objects using the connection. @see newSession()
+ *
+ * \ingroup clientapi
+ *
+ * Some methods use an AMQP 0-10 URL to specify connection parameters.
+ * This is defined in the AMQP 0-10 specification (http://jira.amqp.org/confluence/display/AMQP/AMQP+Specification).
+ *
+ * amqp_url = "amqp:" prot_addr_list
+ * prot_addr_list = [prot_addr ","]* prot_addr
+ * prot_addr = tcp_prot_addr | tls_prot_addr
+ *
+ * tcp_prot_addr = tcp_id tcp_addr
+ * tcp_id = "tcp:" | ""
+ * tcp_addr = [host [":" port] ]
+ * host = <as per http://www.ietf.org/rfc/rfc3986.txt>
+ * port = number]]>
+ *
+ */
+
+class Connection
+{
+ framing::ProtocolVersion version;
+
+ boost::function<void ()> failureCallback;
+
+
+ protected:
+ boost::shared_ptr<ConnectionImpl> impl;
+
+
+ public:
+ /**
+ * Creates a connection object, but does not open the connection.
+ * @see open()
+ */
+ QPID_CLIENT_EXTERN Connection();
+
+ QPID_CLIENT_EXTERN ~Connection();
+
+ /**
+ * Opens a connection to a broker.
+ *
+ * @param host the host on which the broker is running.
+ *
+ * @param port the port on the which the broker is listening.
+ *
+ * @param uid the userid to connect with.
+ *
+ * @param pwd the password to connect with (currently SASL
+ * PLAIN is the only authentication method supported so this
+ * is sent in clear text).
+ *
+ * @param virtualhost the AMQP virtual host to use (virtual
+ * hosts, where implemented(!), provide namespace partitioning
+ * within a single broker).
+ */
+ QPID_CLIENT_EXTERN void open(const std::string& host, int port = 5672,
+ const std::string& uid = "guest",
+ const std::string& pwd = "guest",
+ const std::string& virtualhost = "/", uint16_t maxFrameSize=65535);
+
+ /**
+ * Opens a connection to a broker using a URL.
+ * If the URL contains multiple addresses, try each in turn
+ * till connection is successful.
+ *
+ * @url address of the broker to connect to.
+ *
+ * @param uid the userid to connect with.
+ *
+ * @param pwd the password to connect with (currently SASL
+ * PLAIN is the only authentication method supported so this
+ * is sent in clear text).
+ *
+ * @param virtualhost the AMQP virtual host to use (virtual
+ * hosts, where implemented(!), provide namespace partitioning
+ * within a single broker).
+ */
+ QPID_CLIENT_EXTERN void open(const Url& url,
+ const std::string& uid = "guest",
+ const std::string& pwd = "guest",
+ const std::string& virtualhost = "/", uint16_t maxFrameSize=65535);
+
+ /**
+ * Opens a connection to a broker using a URL.
+ * If the URL contains multiple addresses, try each in turn
+ * till connection is successful.
+ *
+ * @url address of the broker to connect to.
+ *
+ * @param settings used for any settings not provided by the URL.
+ * Settings provided by the url (e.g. host, port) are ignored.
+ */
+ QPID_CLIENT_EXTERN void open(const Url& url, const ConnectionSettings& settings);
+
+ /**
+ * Opens a connection to a broker.
+ *
+ * @param the settings to use (host, port etc). @see ConnectionSettings.
+ */
+ QPID_CLIENT_EXTERN void open(const ConnectionSettings& settings);
+
+ /**
+ * Close the connection.
+ *
+ * Any further use of this connection (without reopening it) will
+ * not succeed.
+ */
+ QPID_CLIENT_EXTERN void close();
+
+ /**
+ * Create a new session on this connection. Sessions allow
+ * multiple streams of work to be multiplexed over the same
+ * connection. The returned Session provides functions to send
+ * commands to the broker.
+ *
+ * Session functions are synchronous. In other words, a Session
+ * function will send a command to the broker and does not return
+ * until it receives the broker's response confirming the command
+ * was executed.
+ *
+ * AsyncSession provides asynchronous versions of the same
+ * functions. These functions send a command to the broker but do
+ * not wait for a response.
+ *
+ * You can convert a Session s into an AsyncSession as follows:
+ * @code
+ * #include <qpid/client/AsyncSession.h>
+ * AsyncSession as = async(s);
+ * @endcode
+ *
+ * You can execute a single command asynchronously will a Session s
+ * like ths:
+ * @code
+ * async(s).messageTransfer(...);
+ * @endcode
+ *
+ * Using an AsyncSession is faster for sending large numbers of
+ * commands, since each command is sent as soon as possible
+ * without waiting for the previous command to be confirmed.
+ *
+ * However with AsyncSession you cannot assume that a command has
+ * completed until you explicitly synchronize. The simplest way to
+ * do this is to call Session::sync() or AsyncSession::sync().
+ * Both of these functions wait for the broker to confirm all
+ * commands issued so far on the session.
+ *
+ *@param name: A name to identify the session. @see qpid::SessionId
+ * If the name is empty (the default) then a unique name will be
+ * chosen using a Universally-unique identifier (UUID) algorithm.
+ */
+ QPID_CLIENT_EXTERN Session newSession(const std::string& name=std::string(), uint32_t timeoutSeconds = 0);
+
+ /**
+ * Resume a suspended session. A session may be resumed
+ * on a different connection to the one that created it.
+ */
+ QPID_CLIENT_EXTERN void resume(Session& session);
+
+ QPID_CLIENT_EXTERN bool isOpen() const;
+
+ /** In a cluster, returns the initial set of known broker URLs
+ * at the time of connection.
+ */
+ QPID_CLIENT_EXTERN std::vector<Url> getInitialBrokers();
+
+ QPID_CLIENT_EXTERN void registerFailureCallback ( boost::function<void ()> fn );
+
+ /**
+ * Return the set of client negotiated settings
+ */
+ QPID_CLIENT_EXTERN const ConnectionSettings& getNegotiatedSettings();
+
+ friend class ConnectionAccess; ///<@internal
+ friend class SessionBase_0_10; ///<@internal
+};
+
+}} // namespace qpid::client
+
+
+#endif /*!QPID_CLIENT_CONNECTION_H*/
diff --git a/cpp/include/qpid/client/ConnectionSettings.h b/cpp/include/qpid/client/ConnectionSettings.h
new file mode 100644
index 0000000000..46053e1fa8
--- /dev/null
+++ b/cpp/include/qpid/client/ConnectionSettings.h
@@ -0,0 +1,133 @@
+#ifndef QPID_CLIENT_CONNECTIONSETTINGS_H
+#define QPID_CLIENT_CONNECTIONSETTINGS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Options.h"
+#include "qpid/log/Options.h"
+#include "qpid/Url.h"
+#include "qpid/client/ClientImportExport.h"
+
+#include <iostream>
+#include <exception>
+
+namespace qpid {
+
+namespace sys {
+class Socket;
+}
+
+namespace client {
+
+/**
+ * Settings for a Connection.
+ */
+struct ConnectionSettings {
+
+ QPID_CLIENT_EXTERN ConnectionSettings();
+ QPID_CLIENT_EXTERN virtual ~ConnectionSettings();
+
+ /**
+ * Allows socket to be configured; default only sets tcp-nodelay
+ * based on the flag set. Can be overridden.
+ */
+ QPID_CLIENT_EXTERN virtual void configureSocket(qpid::sys::Socket&) const;
+
+ /**
+ * The protocol used for the connection (defaults to 'tcp')
+ */
+ std::string protocol;
+
+ /**
+ * The host (or ip address) to connect to (defaults to 'localhost').
+ */
+ std::string host;
+ /**
+ * The port to connect to (defaults to 5672).
+ */
+ uint16_t port;
+ /**
+ * Allows an AMQP 'virtual host' to be specified for the
+ * connection.
+ */
+ std::string virtualhost;
+
+ /**
+ * The username to use when authenticating the connection. If not
+ * specified the current users login is used if available.
+ */
+ std::string username;
+ /**
+ * The password to use when authenticating the connection.
+ */
+ std::string password;
+ /**
+ * The SASL mechanism to use when authenticating the connection;
+ * the options are currently PLAIN or ANONYMOUS.
+ */
+ std::string mechanism;
+ /**
+ * Allows a locale to be specified for the connection.
+ */
+ std::string locale;
+ /**
+ * Allows a heartbeat frequency to be specified
+ */
+ uint16_t heartbeat;
+ /**
+ * The maximum number of channels that the client will request for
+ * use on this connection.
+ */
+ uint16_t maxChannels;
+ /**
+ * The maximum frame size that the client will request for this
+ * connection.
+ */
+ uint16_t maxFrameSize;
+ /**
+ * Limit the size of the connections send buffer . The buffer
+ * is limited to bounds * maxFrameSize.
+ */
+ uint bounds;
+ /**
+ * If true, TCP_NODELAY will be set for the connection.
+ */
+ bool tcpNoDelay;
+ /**
+ * SASL service name
+ */
+ std::string service;
+ /**
+ * Minimum acceptable strength of any SASL negotiated security
+ * layer. 0 means no security layer required.
+ */
+ uint minSsf;
+ /**
+ * Maximum acceptable strength of any SASL negotiated security
+ * layer. 0 means no security layer allowed.
+ */
+ uint maxSsf;
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_CONNECTIONSETTINGS_H*/
diff --git a/cpp/include/qpid/client/FailoverListener.h b/cpp/include/qpid/client/FailoverListener.h
new file mode 100644
index 0000000000..8414b80f2b
--- /dev/null
+++ b/cpp/include/qpid/client/FailoverListener.h
@@ -0,0 +1,81 @@
+#ifndef QPID_CLIENT_FAILOVERLISTENER_H
+#define QPID_CLIENT_FAILOVERLISTENER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/ClientImportExport.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/Url.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Thread.h"
+#include <vector>
+
+namespace qpid {
+namespace client {
+
+
+/**
+ * Listen for updates from the amq.failover exchange.
+ *
+ * In a cluster, the amq.failover exchange provides updates whenever
+ * the cluster membership changes. This class subscribes to the
+ * failover exchange and providees the latest list of known brokers.
+ *
+ * You can also subscribe to amq.failover yourself and use
+ * FailoverListener::decode to extract a list of broker URLs from a
+ * failover exchange message.
+ */
+class FailoverListener : private MessageListener, private qpid::sys::Runnable
+{
+ public:
+ /** The name of the standard failover exchange amq.failover */
+ static QPID_CLIENT_EXTERN const std::string AMQ_FAILOVER;
+
+ /** Extract the broker list from a failover exchange message */
+ static QPID_CLIENT_EXTERN std::vector<Url> getKnownBrokers(const Message& m);
+
+ /** Subscribe to amq.failover exchange. */
+ QPID_CLIENT_EXTERN FailoverListener(Connection);
+
+ QPID_CLIENT_EXTERN ~FailoverListener();
+
+ /** Returns the latest list of known broker URLs. */
+ QPID_CLIENT_EXTERN std::vector<Url> getKnownBrokers() const;
+
+ private:
+ void received(Message& msg);
+ void run();
+
+ mutable sys::Mutex lock;
+ Connection connection;
+ Session session;
+ SubscriptionManager subscriptions;
+ sys::Thread thread;
+ std::vector<Url> knownBrokers;
+};
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_FAILOVERLISTENER_H*/
diff --git a/cpp/include/qpid/client/FailoverManager.h b/cpp/include/qpid/client/FailoverManager.h
new file mode 100644
index 0000000000..0d30e2ed60
--- /dev/null
+++ b/cpp/include/qpid/client/FailoverManager.h
@@ -0,0 +1,137 @@
+#ifndef QPID_CLIENT_FAILOVERMANAGER_H
+#define QPID_CLIENT_FAILOVERMANAGER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Exception.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/ClientImportExport.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/ConnectionSettings.h"
+#include "qpid/client/FailoverListener.h"
+#include "qpid/sys/Monitor.h"
+#include <vector>
+
+namespace qpid {
+namespace client {
+
+struct CannotConnectException : qpid::Exception
+{
+ CannotConnectException(const std::string& m) : qpid::Exception(m) {}
+};
+
+/**
+ * Utility to manage failover.
+ */
+class FailoverManager
+{
+ public:
+ /**
+ * Interface to implement for doing work that can be resumed on
+ * failover
+ */
+ struct Command
+ {
+ /**
+ * This method will be called with isRetry=false when the
+ * command is first executed. The session to use for the work
+ * will be passed to the implementing class. If the connection
+ * fails while the execute call is in progress, the
+ * FailoverManager controlling the execution will re-establish
+ * a connection, open a new session and call back to the
+ * Command implementations execute method with the new session
+ * and isRetry=true.
+ */
+ virtual void execute(AsyncSession& session, bool isRetry) = 0;
+ virtual ~Command() {}
+ };
+
+ struct ReconnectionStrategy
+ {
+ /**
+ * This method is called by the FailoverManager prior to
+ * establishing a connection (or re-connection) and can be
+ * used if the application wishes to edit or re-order the list
+ * which will default to the list of known brokers for the
+ * last connection.
+ */
+ virtual void editUrlList(std::vector<Url>& urls) = 0;
+ virtual ~ReconnectionStrategy() {}
+ };
+
+ /**
+ * Create a manager to control failover for a logical connection.
+ *
+ * @param settings the initial connection settings
+ * @param strategy optional stratgey callback allowing application
+ * to edit or reorder the list of urls to which reconnection is
+ * attempted
+ */
+ QPID_CLIENT_EXTERN FailoverManager(const ConnectionSettings& settings, ReconnectionStrategy* strategy = 0);
+ /**
+ * Return the current connection if open or attept to reconnect to
+ * the specified list of urls. If no list is specified the list of
+ * known brokers from the last connection will be used. If no list
+ * is specified and this is the first connect attempt, the host
+ * and port from the initial settings will be used.
+ *
+ * If the full list is tried and all attempts fail,
+ * CannotConnectException is thrown.
+ */
+ QPID_CLIENT_EXTERN Connection& connect(std::vector<Url> brokers = std::vector<Url>());
+ /**
+ * Return the current connection whether open or not
+ */
+ QPID_CLIENT_EXTERN Connection& getConnection();
+ /**
+ * Close the current connection
+ */
+ QPID_CLIENT_EXTERN void close();
+ /**
+ * Reliably execute the specified command. This involves creating
+ * a session on which to carry out the work of the command,
+ * handling failover occuring while exeuting that command and
+ * re-starting the work.
+ *
+ * Multiple concurrent threads can call execute with different
+ * commands; each thread will be allocated its own
+ * session. FailoverManager will coordinate the different threads
+ * on failover to ensure they continue to use the same logical
+ * connection.
+ */
+ QPID_CLIENT_EXTERN void execute(Command&);
+ private:
+ enum State {IDLE, CONNECTING, CANT_CONNECT};
+
+ qpid::sys::Monitor lock;
+ Connection connection;
+ std::auto_ptr<FailoverListener> failoverListener;
+ ConnectionSettings settings;
+ ReconnectionStrategy* strategy;
+ State state;
+
+ void attempt(Connection&, ConnectionSettings settings, std::vector<Url> urls);
+ void attempt(Connection&, ConnectionSettings settings);
+};
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_FAILOVERMANAGER_H*/
diff --git a/cpp/include/qpid/client/FlowControl.h b/cpp/include/qpid/client/FlowControl.h
new file mode 100644
index 0000000000..bff7071b3b
--- /dev/null
+++ b/cpp/include/qpid/client/FlowControl.h
@@ -0,0 +1,75 @@
+#ifndef QPID_CLIENT_FLOWCONTROL_H
+#define QPID_CLIENT_FLOWCONTROL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/sys/IntegerTypes.h>
+
+namespace qpid {
+namespace client {
+
+/**
+ * Flow control works by associating a finite amount of "credit"
+ * with a subscription.
+ *
+ * Credit includes a message count and a byte count. Each message
+ * received decreases the message count by one, and the byte count by
+ * the size of the message. Either count can have the special value
+ * UNLIMITED which is never decreased.
+ *
+ * A subscription's credit is exhausted when the message count is 0 or
+ * the byte count is too small for the next available message. The
+ * subscription will not receive any further messages until is credit
+ * is renewed.
+ *
+ * In "window mode" credit is automatically renewed when a message is
+ * completed (which by default happens when it is accepted). In
+ * non-window mode credit is not automatically renewed, it must be
+ * explicitly re-set (@see Subscription)
+ */
+struct FlowControl {
+ static const uint32_t UNLIMITED=0xFFFFFFFF;
+ FlowControl(uint32_t messages_=0, uint32_t bytes_=0, bool window_=false)
+ : messages(messages_), bytes(bytes_), window(window_) {}
+
+ static FlowControl messageCredit(uint32_t messages_) { return FlowControl(messages_,UNLIMITED,false); }
+ static FlowControl messageWindow(uint32_t messages_) { return FlowControl(messages_,UNLIMITED,true); }
+ static FlowControl byteCredit(uint32_t bytes_) { return FlowControl(UNLIMITED,bytes_,false); }
+ static FlowControl byteWindow(uint32_t bytes_) { return FlowControl(UNLIMITED,bytes_,true); }
+ static FlowControl unlimited() { return FlowControl(UNLIMITED, UNLIMITED, false); }
+ static FlowControl zero() { return FlowControl(0, 0, false); }
+
+ /** Message credit: subscription can accept up to this many messages. */
+ uint32_t messages;
+ /** Byte credit: subscription can accept up to this many bytes of message content. */
+ uint32_t bytes;
+ /** Window mode. If true credit is automatically renewed as messages are acknowledged. */
+ bool window;
+
+ bool operator==(const FlowControl& x) {
+ return messages == x.messages && bytes == x.bytes && window == x.window;
+ };
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_FLOWCONTROL_H*/
diff --git a/cpp/include/qpid/client/Future.h b/cpp/include/qpid/client/Future.h
new file mode 100644
index 0000000000..09088e68f6
--- /dev/null
+++ b/cpp/include/qpid/client/Future.h
@@ -0,0 +1,59 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef _Future_
+#define _Future_
+
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include "qpid/Exception.h"
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/client/FutureCompletion.h"
+#include "qpid/client/FutureResult.h"
+#include "qpid/client/ClientImportExport.h"
+
+namespace qpid {
+namespace client {
+
+/**@internal */
+class Future
+{
+ framing::SequenceNumber command;
+ boost::shared_ptr<FutureResult> result;
+ bool complete;
+
+public:
+ Future() : complete(false) {}
+ Future(const framing::SequenceNumber& id) : command(id), complete(false) {}
+
+ std::string getResult(SessionImpl& session) {
+ if (result) return result->getResult(session);
+ else throw Exception("Result not expected");
+ }
+
+ QPID_CLIENT_EXTERN void wait(SessionImpl& session);
+ QPID_CLIENT_EXTERN bool isComplete(SessionImpl& session);
+ QPID_CLIENT_EXTERN void setFutureResult(boost::shared_ptr<FutureResult> r);
+};
+
+}}
+
+#endif
diff --git a/cpp/include/qpid/client/FutureCompletion.h b/cpp/include/qpid/client/FutureCompletion.h
new file mode 100644
index 0000000000..0970f494b7
--- /dev/null
+++ b/cpp/include/qpid/client/FutureCompletion.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef _FutureCompletion_
+#define _FutureCompletion_
+
+#include "qpid/framing/amqp_framing.h"
+#include "qpid/sys/Monitor.h"
+
+namespace qpid {
+namespace client {
+
+///@internal
+class FutureCompletion
+{
+protected:
+ mutable sys::Monitor lock;
+ bool complete;
+
+public:
+ FutureCompletion();
+ virtual ~FutureCompletion(){}
+ bool isComplete() const;
+ void waitForCompletion() const;
+ void completed();
+};
+
+}}
+
+
+#endif
diff --git a/cpp/include/qpid/client/FutureResult.h b/cpp/include/qpid/client/FutureResult.h
new file mode 100644
index 0000000000..b2b663daa1
--- /dev/null
+++ b/cpp/include/qpid/client/FutureResult.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef _FutureResult_
+#define _FutureResult_
+
+#include <string>
+
+#include "qpid/client/ClientImportExport.h"
+#include "qpid/framing/amqp_framing.h"
+#include "qpid/client/FutureCompletion.h"
+
+namespace qpid {
+namespace client {
+
+class SessionImpl;
+
+///@internal
+class FutureResult : public FutureCompletion
+{
+ std::string result;
+public:
+ QPID_CLIENT_EXTERN const std::string& getResult(SessionImpl& session) const;
+ void received(const std::string& result);
+};
+
+}}
+
+
+
+#endif
diff --git a/cpp/include/qpid/client/Handle.h b/cpp/include/qpid/client/Handle.h
new file mode 100644
index 0000000000..088e836fcf
--- /dev/null
+++ b/cpp/include/qpid/client/Handle.h
@@ -0,0 +1,71 @@
+#ifndef QPID_CLIENT_HANDLE_H
+#define QPID_CLIENT_HANDLE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/ClientImportExport.h"
+
+namespace qpid {
+namespace client {
+
+template <class> class PrivateImplRef;
+
+/**
+ * A handle is like a pointer: refers to an underlying implementation object.
+ * Copying the handle does not copy the object.
+ *
+ * Handles can be null, like a 0 pointer. Use isValid(), isNull() or the
+ * conversion to bool to test for a null handle.
+ */
+template <class T> class Handle {
+ public:
+
+ /**@return true if handle is valid, i.e. not null. */
+ QPID_CLIENT_EXTERN bool isValid() const { return impl; }
+
+ /**@return true if handle is null. It is an error to call any function on a null handle. */
+ QPID_CLIENT_EXTERN bool isNull() const { return !impl; }
+
+ /** Conversion to bool supports idiom if (handle) { handle->... } */
+ QPID_CLIENT_EXTERN operator bool() const { return impl; }
+
+ /** Operator ! supports idiom if (!handle) { do_if_handle_is_null(); } */
+ QPID_CLIENT_EXTERN bool operator !() const { return !impl; }
+
+ void swap(Handle<T>& h) { T* t = h.impl; h.impl = impl; impl = t; }
+
+ protected:
+ typedef T Impl;
+ QPID_CLIENT_EXTERN Handle() :impl() {}
+
+ // Not implemented,subclasses must implement.
+ QPID_CLIENT_EXTERN Handle(const Handle&);
+ QPID_CLIENT_EXTERN Handle& operator=(const Handle&);
+
+ Impl* impl;
+
+ friend class PrivateImplRef<T>; // FIXME aconway 2009-04-30: Specify
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_HANDLE_H*/
diff --git a/cpp/include/qpid/client/LocalQueue.h b/cpp/include/qpid/client/LocalQueue.h
new file mode 100644
index 0000000000..70e4cebcf1
--- /dev/null
+++ b/cpp/include/qpid/client/LocalQueue.h
@@ -0,0 +1,120 @@
+#ifndef QPID_CLIENT_LOCALQUEUE_H
+#define QPID_CLIENT_LOCALQUEUE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/ClientImportExport.h"
+#include "qpid/client/Handle.h"
+#include "qpid/client/Message.h"
+#include "qpid/sys/Time.h"
+
+namespace qpid {
+namespace client {
+
+class LocalQueueImpl;
+template <class T> class PrivateImplRef;
+
+/**
+ * A local queue to collect messages retrieved from a remote broker
+ * queue. Create a queue and subscribe it using the SubscriptionManager.
+ * Messages from the remote queue on the broker will be stored in the
+ * local queue until you retrieve them.
+ *
+ * \ingroup clientapi
+ *
+ * \details Using a Local Queue
+ *
+ * <pre>
+ * LocalQueue local_queue;
+ * subscriptions.subscribe(local_queue, string("message_queue"));
+ * for (int i=0; i&lt;10; i++) {
+ * Message message = local_queue.get();
+ * std::cout &lt;&lt; message.getData() &lt;&lt; std::endl;
+ * }
+ * </pre>
+ *
+ * <h2>Getting Messages</h2>
+ *
+ * <ul><li>
+ * <p>get()</p>
+ * <pre>Message message = local_queue.get();</pre>
+ * <pre>// Specifying timeouts (TIME_SEC, TIME_MSEC, TIME_USEC, TIME_NSEC)
+ *#include <qpid/sys/Time.h>
+ *Message message;
+ *local_queue.get(message, 5*sys::TIME_SEC);</pre></li></ul>
+ *
+ * <h2>Checking size</h2>
+ * <ul><li>
+ * <p>empty()</p>
+ * <pre>if (local_queue.empty()) { ... }</pre></li>
+ * <li><p>size()</p>
+ * <pre>std::cout &lt;&lt; local_queue.size();</pre></li>
+ * </ul>
+ */
+
+class LocalQueue : public Handle<LocalQueueImpl> {
+ public:
+ /** Create a local queue. Subscribe the local queue to a remote broker
+ * queue with a SubscriptionManager.
+ *
+ * LocalQueue is an alternative to implementing a MessageListener.
+ */
+ QPID_CLIENT_EXTERN LocalQueue();
+ QPID_CLIENT_EXTERN LocalQueue(const LocalQueue&);
+ QPID_CLIENT_EXTERN ~LocalQueue();
+ QPID_CLIENT_EXTERN LocalQueue& operator=(const LocalQueue&);
+
+ /** Wait up to timeout for the next message from the local queue.
+ *@param result Set to the message from the queue.
+ *@param timeout wait up this timeout for a message to appear.
+ *@return true if result was set, false if queue was empty after timeout.
+ */
+ QPID_CLIENT_EXTERN bool get(Message& result, sys::Duration timeout=0);
+
+ /** Get the next message off the local queue, or wait up to the timeout
+ * for message from the broker queue.
+ *@param timeout wait up this timeout for a message to appear.
+ *@return message from the queue.
+ *@throw ClosedException if subscription is closed or timeout exceeded.
+ */
+ QPID_CLIENT_EXTERN Message get(sys::Duration timeout=sys::TIME_INFINITE);
+
+ /** Synonym for get() */
+ QPID_CLIENT_EXTERN Message pop(sys::Duration timeout=sys::TIME_INFINITE);
+
+ /** Return true if local queue is empty. */
+ QPID_CLIENT_EXTERN bool empty() const;
+
+ /** Number of messages on the local queue */
+ QPID_CLIENT_EXTERN size_t size() const;
+
+ LocalQueue(LocalQueueImpl*); ///<@internal
+
+
+ private:
+ typedef LocalQueueImpl Impl;
+ friend class PrivateImplRef<LocalQueue>;
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_LOCALQUEUE_H*/
diff --git a/cpp/include/qpid/client/Message.h b/cpp/include/qpid/client/Message.h
new file mode 100644
index 0000000000..2401cbdc92
--- /dev/null
+++ b/cpp/include/qpid/client/Message.h
@@ -0,0 +1,175 @@
+#ifndef QPID_CLIENT_MESSAGE_H
+#define QPID_CLIENT_MESSAGE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/ClientImportExport.h"
+#include "qpid/framing/MessageProperties.h"
+#include "qpid/framing/DeliveryProperties.h"
+#include <string>
+
+namespace qpid {
+
+namespace framing {
+class FieldTable;
+class SequenceNumber; // FIXME aconway 2009-04-17: remove with getID?
+}
+
+namespace client {
+
+class MessageImpl;
+
+/**
+ * A message sent to or received from the broker.
+ *
+ * \ingroup clientapi
+ * \details
+ *
+ * <h2>Getting and setting message contents</h2>
+ *
+ * <ul>
+ * <li>
+ * <p>getData()</p>
+ * <pre>std::cout &lt;&lt; "Response: " &lt;&lt; message.getData() &lt;&lt; std::endl;</pre>
+ * </li>
+ * <li>
+ * <p>setData()</p>
+ * <pre>message.setData("That's all, folks!");</pre></li>
+ * <li>
+ * <p>appendData()</p>
+ * <pre>message.appendData(" ... let's add a bit more ...");</pre></li>
+ * </ul>
+ *
+ * <h2>Getting and Setting Delivery Properties</h2>
+ *
+ * <ul>
+ * <li>
+ * <p>getDeliveryProperties()</p>
+ * <pre>message.getDeliveryProperties().setRoutingKey("control");</pre>
+ * <pre>message.getDeliveryProperties().setDeliveryMode(PERSISTENT);</pre>
+ * <pre>message.getDeliveryProperties().setPriority(9);</pre>
+ * <pre>message.getDeliveryProperties().setTtl(100);</pre></li>
+ *
+ * <li>
+ * <p>hasDeliveryProperties()</p>
+ * <pre>if (! message.hasDeliveryProperties()) {
+ * ...
+ *}</pre></li>
+ * </ul>
+ *
+ * <h2>Getting and Setting Message Properties</h2>
+ *
+ * <ul>
+ * <li>
+ * <p>getMessageProperties()</p>
+ * <pre>
+ *request.getMessageProperties().setReplyTo(ReplyTo("amq.direct", response_queue.str()));
+ * </pre>
+ * <pre>
+ *routingKey = request.getMessageProperties().getReplyTo().getRoutingKey();
+ *exchange = request.getMessageProperties().getReplyTo().getExchange();
+ * </pre>
+ * <pre>message.getMessageProperties().setContentType("text/plain");</pre>
+ * <pre>message.getMessageProperties().setContentEncoding("text/plain");</pre>
+ * </li>
+ * <li>
+ * <p>hasMessageProperties()</p>
+ * <pre>request.getMessageProperties().hasReplyTo();</pre>
+ * </li>
+ * </ul>
+ *
+ * <h2>Getting and Setting Application Headers</h2>
+ *
+ * <ul>
+ * <li>
+ * <p>getHeaders()</p>
+ * <pre>
+ *message.getHeaders().getString("control");
+ * </pre>
+ * <pre>
+ *message.getHeaders().setString("control","continue");
+ * </pre></li>
+ * </ul>
+ *
+ *
+ */
+class Message
+{
+public:
+ /** Create a Message.
+ *@param data Data for the message body.
+ *@param routingKey Passed to the exchange that routes the message.
+ */
+ QPID_CLIENT_EXTERN Message(
+ const std::string& data=std::string(),
+ const std::string& routingKey=std::string());
+ Message(MessageImpl*); ///< @internal
+ QPID_CLIENT_EXTERN Message(const Message&);
+ QPID_CLIENT_EXTERN ~Message();
+ QPID_CLIENT_EXTERN Message& operator=(const Message&);
+ QPID_CLIENT_EXTERN void swap(Message&);
+
+ QPID_CLIENT_EXTERN void setData(const std::string&);
+ QPID_CLIENT_EXTERN const std::string& getData() const;
+ QPID_CLIENT_EXTERN std::string& getData();
+
+ QPID_CLIENT_EXTERN void appendData(const std::string&);
+
+ QPID_CLIENT_EXTERN bool hasMessageProperties() const;
+ QPID_CLIENT_EXTERN framing::MessageProperties& getMessageProperties();
+ QPID_CLIENT_EXTERN const framing::MessageProperties& getMessageProperties() const;
+
+ QPID_CLIENT_EXTERN bool hasDeliveryProperties() const;
+ QPID_CLIENT_EXTERN framing::DeliveryProperties& getDeliveryProperties();
+ QPID_CLIENT_EXTERN const framing::DeliveryProperties& getDeliveryProperties() const;
+
+
+ /** The destination of messages sent to the broker is the exchange
+ * name. The destination of messages received from the broker is
+ * the delivery tag identifyig the local subscription (often this
+ * is the name of the subscribed queue.)
+ */
+ QPID_CLIENT_EXTERN std::string getDestination() const;
+
+ /** Check the redelivered flag. */
+ QPID_CLIENT_EXTERN bool isRedelivered() const;
+ /** Set the redelivered flag. */
+ QPID_CLIENT_EXTERN void setRedelivered(bool redelivered);
+
+ /** Get a modifyable reference to the message headers. */
+ QPID_CLIENT_EXTERN framing::FieldTable& getHeaders();
+
+ /** Get a non-modifyable reference to the message headers. */
+ QPID_CLIENT_EXTERN const framing::FieldTable& getHeaders() const;
+
+ // FIXME aconway 2009-04-17: does this need to be in public API?
+ ///@internal
+ QPID_CLIENT_EXTERN const framing::SequenceNumber& getId() const;
+
+ private:
+ MessageImpl* impl;
+ friend class MessageImpl; // Helper template for implementation
+};
+
+}}
+
+#endif /*!QPID_CLIENT_MESSAGE_H*/
diff --git a/cpp/include/qpid/client/MessageListener.h b/cpp/include/qpid/client/MessageListener.h
new file mode 100644
index 0000000000..d200f8cf21
--- /dev/null
+++ b/cpp/include/qpid/client/MessageListener.h
@@ -0,0 +1,101 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include "qpid/client/ClientImportExport.h"
+
+#ifndef _MessageListener_
+#define _MessageListener_
+
+#include "qpid/client/Message.h"
+
+namespace qpid {
+namespace client {
+
+ /**
+ * Implement a subclass of MessageListener and subscribe it using
+ * the SubscriptionManager to receive messages.
+ *
+ * Another way to receive messages is by using a LocalQueue.
+ *
+ * \ingroup clientapi
+ * \details
+ *
+ * <h2>Using a MessageListener</h2>
+ *
+ * <ul>
+ * <li>
+ * <p>The received() function is called when a message arrives:</p>
+ * <pre>virtual void received(Message&amp; message)=0;</pre>
+ * </li>
+ * <li>
+ * <p>Derive your own listener, implement the received() function:</p>
+ * <pre>
+ * class Listener : public MessageListener {
+ * private:
+ * SubscriptionManager&amp; subscriptions;
+ * public:
+ * Listener(SubscriptionManager&amp; subscriptions);
+ * virtual void received(Message&amp; message);
+ * };
+ *
+ * Listener::Listener(SubscriptionManager&amp; subs) : subscriptions(subs)
+ * {}
+ *
+ * void Listener::received(Message&amp; message) {
+ * std::cout &lt;&lt; "Message: " &lt;&lt; message.getData() &lt;&lt; std::endl;
+ * if (message.getData() == "That's all, folks!") {
+ * std::cout &lt;&lt; "Shutting down listener for " &lt;&lt; message.getDestination()
+ * &lt;&lt; std::endl;
+ * subscriptions.cancel(message.getDestination());
+ * }
+ * }
+ *</pre>
+ * <pre>
+ * SubscriptionManager subscriptions(session);
+ *
+ * // Create a listener and subscribe it to the queue named "message_queue"
+ * Listener listener(subscriptions);
+ * subscriptions.subscribe(listener, "message_queue");
+ *
+ * // Receive messages until the subscription is cancelled
+ * // by Listener::received()
+ * subscriptions.run();
+ * </pre>
+ * </li>
+ * </ul>
+ *
+ */
+
+ class MessageListener{
+ public:
+ QPID_CLIENT_EXTERN virtual ~MessageListener();
+
+ /** Called for each message arriving from the broker. Override
+ * in your own subclass to process messages.
+ */
+ virtual void received(Message& msg) = 0;
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/include/qpid/client/MessageReplayTracker.h b/cpp/include/qpid/client/MessageReplayTracker.h
new file mode 100644
index 0000000000..6f5a0f4ac3
--- /dev/null
+++ b/cpp/include/qpid/client/MessageReplayTracker.h
@@ -0,0 +1,73 @@
+#ifndef QPID_CLIENT_MESSAGEREPLAYTRACKER_H
+#define QPID_CLIENT_MESSAGEREPLAYTRACKER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/ClientImportExport.h"
+#include <list>
+#include <string>
+
+namespace qpid {
+namespace client {
+
+/**
+ * Utility to track messages sent asynchronously, allowing those that
+ * are indoubt to be replayed over a new session.
+ */
+class MessageReplayTracker
+{
+ public:
+ QPID_CLIENT_EXTERN MessageReplayTracker(uint flushInterval);
+ QPID_CLIENT_EXTERN void send(const Message& message, const std::string& destination = "");
+ QPID_CLIENT_EXTERN void init(AsyncSession session);
+ QPID_CLIENT_EXTERN void replay(AsyncSession session);
+ QPID_CLIENT_EXTERN void setFlushInterval(uint interval);
+ QPID_CLIENT_EXTERN uint getFlushInterval();
+ QPID_CLIENT_EXTERN void checkCompletion();
+
+ template <class F> void foreach(F& f) {
+ for (std::list<ReplayRecord>::const_iterator i = buffer.begin(); i != buffer.end(); i++) {
+ f(i->message);
+ }
+ }
+
+ private:
+ struct ReplayRecord
+ {
+ Completion status;
+ Message message;
+ std::string destination;
+
+ ReplayRecord(const Message& message, const std::string& destination);
+ void send(MessageReplayTracker&);
+ bool isComplete();
+ };
+
+ AsyncSession session;
+ uint flushInterval;
+ uint count;
+ std::list<ReplayRecord> buffer;
+};
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_MESSAGEREPLAYTRACKER_H*/
diff --git a/cpp/include/qpid/client/QueueOptions.h b/cpp/include/qpid/client/QueueOptions.h
new file mode 100644
index 0000000000..f8a4963f06
--- /dev/null
+++ b/cpp/include/qpid/client/QueueOptions.h
@@ -0,0 +1,129 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/client/ClientImportExport.h"
+#include "qpid/framing/FieldTable.h"
+
+#ifndef _QueueOptions_
+#define _QueueOptions_
+
+namespace qpid {
+namespace client {
+
+enum QueueSizePolicy {NONE, REJECT, FLOW_TO_DISK, RING, RING_STRICT};
+enum QueueOrderingPolicy {FIFO, LVQ, LVQ_NO_BROWSE};
+
+/**
+ * A help class to set options on the Queue. Create a configured args while
+ * still allowing any custom configuration via the FieldTable base class
+ */
+class QueueOptions: public framing::FieldTable
+{
+ public:
+ QPID_CLIENT_EXTERN QueueOptions();
+ QPID_CLIENT_EXTERN virtual ~QueueOptions();
+
+ /**
+ * Sets the queue sizing policy
+ *
+ * @param sp SizePolicy
+ * REJECT - reject if queue greater than size/count
+ * FLOW_TO_DISK - page messages to disk from this point is greater than size/count
+ * RING - limit the queue to size/count and over-write old messages round a ring
+ * RING_STRICT - limit the queue to size/count and reject is head == tail
+ * NONE - Use default broker sizing policy
+ * @param maxSize Set the max number of bytes for the sizing policies
+ * @param setMaxCount Set the max number of messages for the sizing policies
+ */
+ QPID_CLIENT_EXTERN void setSizePolicy(QueueSizePolicy sp, uint64_t maxSize, uint32_t maxCount );
+
+ /**
+ * Enables the persisting of a queue to the store module when a cluster fails down to it's last
+ * node. Does so optimistically. Will start persisting when cluster count >1 again.
+ */
+ QPID_CLIENT_EXTERN void setPersistLastNode();
+
+ /**
+ * Sets the odering policy on the Queue, default ordering is FIFO.
+ */
+ QPID_CLIENT_EXTERN void setOrdering(QueueOrderingPolicy op);
+
+ /**
+ * Use broker defualt sizing ploicy
+ */
+ QPID_CLIENT_EXTERN void clearSizePolicy();
+
+ /**
+ * Clear Persist Last Node Policy
+ */
+ QPID_CLIENT_EXTERN void clearPersistLastNode();
+
+ /**
+ * get the key used match LVQ in args for message transfer
+ */
+ QPID_CLIENT_EXTERN void getLVQKey(std::string& key);
+
+ /**
+ * Use default odering policy
+ */
+ QPID_CLIENT_EXTERN void clearOrdering();
+
+ /**
+ * Turns on event generation for this queue (either enqueue only
+ * or for enqueue and dequeue events); the events can then be
+ * processed by a regsitered broker plugin.
+ *
+ * DEPRECATED
+ *
+ * This is confusing to anyone who sees only the function call
+ * and not the variable name / doxygen. Consider the following call:
+ *
+ * options.enableQueueEvents(false);
+ *
+ * It looks like it disables queue events, but what it really does is
+ * enable both enqueue and dequeue events.
+ *
+ * Use setInt() instead:
+ *
+ * options.setInt("qpid.queue_event_generation", 2);
+ */
+
+ QPID_CLIENT_EXTERN void enableQueueEvents(bool enqueueOnly);
+
+ static QPID_CLIENT_EXTERN const std::string strMaxCountKey;
+ static QPID_CLIENT_EXTERN const std::string strMaxSizeKey;
+ static QPID_CLIENT_EXTERN const std::string strTypeKey;
+ static QPID_CLIENT_EXTERN const std::string strREJECT;
+ static QPID_CLIENT_EXTERN const std::string strFLOW_TO_DISK;
+ static QPID_CLIENT_EXTERN const std::string strRING;
+ static QPID_CLIENT_EXTERN const std::string strRING_STRICT;
+ static QPID_CLIENT_EXTERN const std::string strLastValueQueue;
+ static QPID_CLIENT_EXTERN const std::string strPersistLastNode;
+ static QPID_CLIENT_EXTERN const std::string strLVQMatchProperty;
+ static QPID_CLIENT_EXTERN const std::string strLastValueQueueNoBrowse;
+ static QPID_CLIENT_EXTERN const std::string strQueueEventMode;
+};
+
+}
+}
+
+
+#endif
diff --git a/cpp/include/qpid/client/Session.h b/cpp/include/qpid/client/Session.h
new file mode 100644
index 0000000000..c40549bbc5
--- /dev/null
+++ b/cpp/include/qpid/client/Session.h
@@ -0,0 +1,39 @@
+#ifndef QPID_CLIENT_SESSION_H
+#define QPID_CLIENT_SESSION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/Session_0_10.h"
+
+namespace qpid {
+namespace client {
+
+/**
+ * Session is an alias for Session_0_10
+ *
+ * \ingroup clientapi
+ */
+typedef Session_0_10 Session;
+
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_SESSION_H*/
diff --git a/cpp/include/qpid/client/SessionBase_0_10.h b/cpp/include/qpid/client/SessionBase_0_10.h
new file mode 100644
index 0000000000..afa458bcee
--- /dev/null
+++ b/cpp/include/qpid/client/SessionBase_0_10.h
@@ -0,0 +1,109 @@
+#ifndef QPID_CLIENT_SESSIONBASE_H
+#define QPID_CLIENT_SESSIONBASE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/SessionId.h"
+#include "qpid/framing/amqp_structs.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/Completion.h"
+#include "qpid/client/TypedResult.h"
+#include "qpid/client/ClientImportExport.h"
+#include <string>
+
+namespace qpid {
+namespace client {
+
+class Connection;
+class SessionImpl;
+
+using std::string;
+using framing::Content;
+using framing::FieldTable;
+using framing::SequenceNumber;
+using framing::SequenceSet;
+using framing::SequenceNumberSet;
+using qpid::SessionId;
+using framing::Xid;
+
+/** Unit of message credit: messages or bytes */
+enum CreditUnit { MESSAGE_CREDIT=0, BYTE_CREDIT=1, UNLIMITED_CREDIT=0xFFFFFFFF };
+
+/**
+ * Base class for handles to an AMQP session.
+ *
+ * Subclasses provide the AMQP commands for a given
+ * version of the protocol.
+ */
+class SessionBase_0_10 {
+ public:
+
+ ///@internal
+ QPID_CLIENT_EXTERN SessionBase_0_10();
+ QPID_CLIENT_EXTERN ~SessionBase_0_10();
+
+ /** Get the session ID */
+ QPID_CLIENT_EXTERN SessionId getId() const;
+
+ /** Close the session.
+ * A session is automatically closed when all handles to it are destroyed.
+ */
+ QPID_CLIENT_EXTERN void close();
+
+ /**
+ * Synchronize the session: sync() waits until all commands issued
+ * on this session so far have been completed by the broker.
+ *
+ * Note sync() is always synchronous, even on an AsyncSession object
+ * because that's almost always what you want. You can call
+ * AsyncSession::executionSync() directly in the unusual event
+ * that you want to do an asynchronous sync.
+ */
+ QPID_CLIENT_EXTERN void sync();
+
+ /** Set the timeout for this session. */
+ QPID_CLIENT_EXTERN uint32_t timeout(uint32_t seconds);
+
+ /** Suspend the session - detach it from its connection */
+ QPID_CLIENT_EXTERN void suspend();
+
+ /** Resume a suspended session with a new connection */
+ QPID_CLIENT_EXTERN void resume(Connection);
+
+ /** Get the channel associated with this session */
+ QPID_CLIENT_EXTERN uint16_t getChannel() const;
+
+ QPID_CLIENT_EXTERN void flush();
+ QPID_CLIENT_EXTERN void markCompleted(const framing::SequenceSet& ids, bool notifyPeer);
+ QPID_CLIENT_EXTERN void markCompleted(const framing::SequenceNumber& id, bool cumulative, bool notifyPeer);
+ QPID_CLIENT_EXTERN void sendCompletion();
+
+ QPID_CLIENT_EXTERN bool isValid() const;
+
+ protected:
+ boost::shared_ptr<SessionImpl> impl;
+ friend class SessionBase_0_10Access;
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_SESSIONBASE_H*/
diff --git a/cpp/include/qpid/client/Subscription.h b/cpp/include/qpid/client/Subscription.h
new file mode 100644
index 0000000000..425b6b92e2
--- /dev/null
+++ b/cpp/include/qpid/client/Subscription.h
@@ -0,0 +1,123 @@
+#ifndef QPID_CLIENT_SUBSCRIPTION_H
+#define QPID_CLIENT_SUBSCRIPTION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/Handle.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/SubscriptionSettings.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/ClientImportExport.h"
+
+namespace qpid {
+namespace client {
+
+template <class> class PrivateImplRef;
+class SubscriptionImpl;
+class SubscriptionManager;
+
+/**
+ * A handle to an active subscription. Provides methods to query the subscription status
+ * and control acknowledgement (acquire and accept) of messages.
+ */
+class Subscription : public Handle<SubscriptionImpl> {
+ public:
+ QPID_CLIENT_EXTERN Subscription(SubscriptionImpl* = 0);
+ QPID_CLIENT_EXTERN Subscription(const Subscription&);
+ QPID_CLIENT_EXTERN ~Subscription();
+ QPID_CLIENT_EXTERN Subscription& operator=(const Subscription&);
+
+
+ /** The name of the subscription, used as the "destination" for messages from the broker.
+ * Usually the same as the queue name but can be set differently.
+ */
+ QPID_CLIENT_EXTERN std::string getName() const;
+
+ /** Name of the queue this subscription subscribes to */
+ QPID_CLIENT_EXTERN std::string getQueue() const;
+
+ /** Get the flow control and acknowledgement settings for this subscription */
+ QPID_CLIENT_EXTERN const SubscriptionSettings& getSettings() const;
+
+ /** Set the flow control parameters */
+ QPID_CLIENT_EXTERN void setFlowControl(const FlowControl&);
+
+ /** Automatically acknowledge (acquire and accept) batches of n messages.
+ * You can disable auto-acknowledgement by setting n=0, and use acquire() and accept()
+ * to manually acquire and accept messages.
+ */
+ QPID_CLIENT_EXTERN void setAutoAck(unsigned int n);
+
+ /** Get the set of ID's for messages received by this subscription but not yet acquired.
+ * This will always be empty if getSettings().acquireMode=ACQUIRE_MODE_PRE_ACQUIRED
+ */
+ QPID_CLIENT_EXTERN SequenceSet getUnacquired() const;
+
+ /** Get the set of ID's for messages received by this subscription but not yet accepted. */
+ QPID_CLIENT_EXTERN SequenceSet getUnaccepted() const;
+
+ /** Acquire messageIds and remove them from the unacquired set.
+ * oAdd them to the unaccepted set if getSettings().acceptMode == ACCEPT_MODE_EXPLICIT.
+ */
+ QPID_CLIENT_EXTERN void acquire(const SequenceSet& messageIds);
+
+ /** Accept messageIds and remove them from the unaccepted set.
+ *@pre messageIds is a subset of getUnaccepted()
+ */
+ QPID_CLIENT_EXTERN void accept(const SequenceSet& messageIds);
+
+ /** Release messageIds and remove them from the unaccepted set.
+ *@pre messageIds is a subset of getUnaccepted()
+ */
+ QPID_CLIENT_EXTERN void release(const SequenceSet& messageIds);
+
+ /* Acquire a single message */
+ QPID_CLIENT_EXTERN void acquire(const Message& m) { acquire(SequenceSet(m.getId())); }
+
+ /* Accept a single message */
+ QPID_CLIENT_EXTERN void accept(const Message& m) { accept(SequenceSet(m.getId())); }
+
+ /* Release a single message */
+ QPID_CLIENT_EXTERN void release(const Message& m) { release(SequenceSet(m.getId())); }
+
+ /** Get the session associated with this subscription */
+ QPID_CLIENT_EXTERN Session getSession() const;
+
+ /** Get the subscription manager associated with this subscription */
+ QPID_CLIENT_EXTERN SubscriptionManager getSubscriptionManager();
+
+ /** Cancel the subscription. */
+ QPID_CLIENT_EXTERN void cancel();
+
+ /** Grant the specified amount of message credit */
+ QPID_CLIENT_EXTERN void grantMessageCredit(uint32_t);
+
+ /** Grant the specified amount of byte credit */
+ QPID_CLIENT_EXTERN void grantByteCredit(uint32_t);
+
+ private:
+ friend class PrivateImplRef<Subscription>;
+ friend class SubscriptionManager;
+};
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_SUBSCRIPTION_H*/
diff --git a/cpp/include/qpid/client/SubscriptionManager.h b/cpp/include/qpid/client/SubscriptionManager.h
new file mode 100644
index 0000000000..e70e05f73a
--- /dev/null
+++ b/cpp/include/qpid/client/SubscriptionManager.h
@@ -0,0 +1,292 @@
+#ifndef QPID_CLIENT_SUBSCRIPTIONMANAGER_H
+#define QPID_CLIENT_SUBSCRIPTIONMANAGER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/Session.h"
+#include "qpid/client/Subscription.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/client/ClientImportExport.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/client/LocalQueue.h"
+#include "qpid/client/Handle.h"
+#include <string>
+
+namespace qpid {
+namespace client {
+
+class SubscriptionManagerImpl;
+
+/**
+ * A class to help create and manage subscriptions.
+ *
+ * Set up your subscriptions, then call run() to have messages
+ * delivered.
+ *
+ * \ingroup clientapi
+ *
+ * \details
+ *
+ * <h2>Subscribing and canceling subscriptions</h2>
+ *
+ * <ul>
+ * <li>
+ * <p>subscribe()</p>
+ * <pre> SubscriptionManager subscriptions(session);
+ * Listener listener(subscriptions);
+ * subscriptions.subscribe(listener, myQueue);</pre>
+ * <pre> SubscriptionManager subscriptions(session);
+ * LocalQueue local_queue;
+ * subscriptions.subscribe(local_queue, string("message_queue"));</pre></li>
+ * <li>
+ * <p>cancel()</p>
+ * <pre>subscriptions.cancel();</pre></li>
+ * </ul>
+ *
+ * <h2>Waiting for messages (and returning)</h2>
+ *
+ * <ul>
+ * <li>
+ * <p>run()</p>
+ * <pre> // Give up control to receive messages
+ * subscriptions.run();</pre></li>
+ * <li>
+ * <p>stop()</p>
+ * <pre>.// Use this code in a listener to return from run()
+ * subscriptions.stop();</pre></li>
+ * <li>
+ * <p>setAutoStop()</p>
+ * <pre>.// Return from subscriptions.run() when last subscription is cancelled
+ *.subscriptions.setAutoStop(true);
+ *.subscriptons.run();
+ * </pre></li>
+ * <li>
+ * <p>Ending a subscription in a listener</p>
+ * <pre>
+ * void Listener::received(Message&amp; message) {
+ *
+ * if (message.getData() == "That's all, folks!") {
+ * subscriptions.cancel(message.getDestination());
+ * }
+ * }
+ * </pre>
+ * </li>
+ * </ul>
+ *
+ */
+class SubscriptionManager : public sys::Runnable, public Handle<SubscriptionManagerImpl>
+{
+ public:
+ /** Create a new SubscriptionManager associated with a session */
+ QPID_CLIENT_EXTERN SubscriptionManager(const Session& session);
+ QPID_CLIENT_EXTERN SubscriptionManager(const SubscriptionManager&);
+ QPID_CLIENT_EXTERN ~SubscriptionManager();
+ QPID_CLIENT_EXTERN SubscriptionManager& operator=(const SubscriptionManager&);
+
+ /**
+ * Subscribe a MessagesListener to receive messages from queue.
+ *
+ * Provide your own subclass of MessagesListener to process
+ * incoming messages. It will be called for each message received.
+ *
+ *@param listener Listener object to receive messages.
+ *@param queue Name of the queue to subscribe to.
+ *@param settings settings for the subscription.
+ *@param name unique destination name for the subscription, defaults to queue name.
+ */
+ QPID_CLIENT_EXTERN Subscription subscribe(MessageListener& listener,
+ const std::string& queue,
+ const SubscriptionSettings& settings,
+ const std::string& name=std::string());
+
+ /**
+ * Subscribe a LocalQueue to receive messages from queue.
+ *
+ * Incoming messages are stored in the queue for you to retrieve.
+ *
+ *@param queue Name of the queue to subscribe to.
+ *@param flow initial FlowControl for the subscription.
+ *@param name unique destination name for the subscription, defaults to queue name.
+ * If not specified, the queue name is used.
+ */
+ QPID_CLIENT_EXTERN Subscription subscribe(LocalQueue& localQueue,
+ const std::string& queue,
+ const SubscriptionSettings& settings,
+ const std::string& name=std::string());
+
+ /**
+ * Subscribe a MessagesListener to receive messages from queue.
+ *
+ * Provide your own subclass of MessagesListener to process
+ * incoming messages. It will be called for each message received.
+ *
+ *@param listener Listener object to receive messages.
+ *@param queue Name of the queue to subscribe to.
+ *@param name unique destination name for the subscription, defaults to queue name.
+ * If not specified, the queue name is used.
+ */
+ QPID_CLIENT_EXTERN Subscription subscribe(MessageListener& listener,
+ const std::string& queue,
+ const std::string& name=std::string());
+
+ /**
+ * Subscribe a LocalQueue to receive messages from queue.
+ *
+ * Incoming messages are stored in the queue for you to retrieve.
+ *
+ *@param queue Name of the queue to subscribe to.
+ *@param name unique destination name for the subscription, defaults to queue name.
+ * If not specified, the queue name is used.
+ */
+ QPID_CLIENT_EXTERN Subscription subscribe(LocalQueue& localQueue,
+ const std::string& queue,
+ const std::string& name=std::string());
+
+
+ /** Get a single message from a queue.
+ * (Note: this currently uses a subscription per invocation and is
+ * thus relatively expensive. The subscription is cancelled as
+ * part of each call which can trigger auto-deletion).
+ *@param result is set to the message from the queue.
+ *@param timeout wait up this timeout for a message to appear.
+ *@return true if result was set, false if no message available after timeout.
+ */
+ QPID_CLIENT_EXTERN bool get(Message& result, const std::string& queue, sys::Duration timeout=0);
+
+ /** Get a single message from a queue.
+ * (Note: this currently uses a subscription per invocation and is
+ * thus relatively expensive. The subscription is cancelled as
+ * part of each call which can trigger auto-deletion).
+ *@param timeout wait up this timeout for a message to appear.
+ *@return message from the queue.
+ *@throw Exception if the timeout is exceeded.
+ */
+ QPID_CLIENT_EXTERN Message get(const std::string& queue, sys::Duration timeout=sys::TIME_INFINITE);
+
+ /** Get a subscription by name.
+ *@throw Exception if not found.
+ */
+ QPID_CLIENT_EXTERN Subscription getSubscription(const std::string& name) const;
+
+ /** Cancel a subscription. See also: Subscription.cancel() */
+ QPID_CLIENT_EXTERN void cancel(const std::string& name);
+
+ /** Deliver messages in the current thread until stop() is called.
+ * Only one thread may be running in a SubscriptionManager at a time.
+ * @see run
+ */
+ QPID_CLIENT_EXTERN void run();
+
+ /** Start a new thread to deliver messages.
+ * Only one thread may be running in a SubscriptionManager at a time.
+ * @see start
+ */
+ QPID_CLIENT_EXTERN void start();
+
+ /**
+ * Wait for the thread started by a call to start() to complete.
+ */
+ QPID_CLIENT_EXTERN void wait();
+
+ /** If set true, run() will stop when all subscriptions
+ * are cancelled. If false, run will only stop when stop()
+ * is called. True by default.
+ */
+ QPID_CLIENT_EXTERN void setAutoStop(bool set=true);
+
+ /** Stop delivery. Causes run() to return, or the thread started with start() to exit. */
+ QPID_CLIENT_EXTERN void stop();
+
+ static const uint32_t UNLIMITED=0xFFFFFFFF;
+
+ /** Set the flow control for a subscription. */
+ QPID_CLIENT_EXTERN void setFlowControl(const std::string& name, const FlowControl& flow);
+
+ /** Set the flow control for a subscription.
+ *@param name: name of the subscription.
+ *@param messages: message credit.
+ *@param bytes: byte credit.
+ *@param window: if true use window-based flow control.
+ */
+ QPID_CLIENT_EXTERN void setFlowControl(const std::string& name, uint32_t messages, uint32_t bytes, bool window=true);
+
+ /** Set the default settings for subscribe() calls that don't
+ * include a SubscriptionSettings parameter.
+ */
+ QPID_CLIENT_EXTERN void setDefaultSettings(const SubscriptionSettings& s);
+
+ /** Get the default settings for subscribe() calls that don't
+ * include a SubscriptionSettings parameter.
+ */
+ QPID_CLIENT_EXTERN const SubscriptionSettings& getDefaultSettings() const;
+
+ /** Get the default settings for subscribe() calls that don't
+ * include a SubscriptionSettings parameter.
+ */
+ QPID_CLIENT_EXTERN SubscriptionSettings& getDefaultSettings();
+
+ /**
+ * Set the default flow control settings for subscribe() calls
+ * that don't include a SubscriptionSettings parameter.
+ *
+ *@param messages: message credit.
+ *@param bytes: byte credit.
+ *@param window: if true use window-based flow control.
+ */
+ QPID_CLIENT_EXTERN void setFlowControl(uint32_t messages, uint32_t bytes, bool window=true);
+
+ /**
+ *Set the default accept-mode for subscribe() calls that don't
+ *include a SubscriptionSettings parameter.
+ */
+ QPID_CLIENT_EXTERN void setAcceptMode(AcceptMode mode);
+
+ /**
+ * Set the default acquire-mode subscribe()s that don't specify SubscriptionSettings.
+ */
+ QPID_CLIENT_EXTERN void setAcquireMode(AcquireMode mode);
+
+ QPID_CLIENT_EXTERN void registerFailoverHandler ( boost::function<void ()> fh );
+
+ QPID_CLIENT_EXTERN Session getSession() const;
+
+ SubscriptionManager(SubscriptionManagerImpl*); ///<@internal
+
+ private:
+ typedef SubscriptionManagerImpl Impl;
+ friend class PrivateImplRef<SubscriptionManager>;
+};
+
+/** AutoCancel cancels a subscription in its destructor */
+class AutoCancel {
+ public:
+ AutoCancel(SubscriptionManager& sm_, const std::string& tag_) : sm(sm_), tag(tag_) {}
+ ~AutoCancel() { sm.cancel(tag); }
+ private:
+ SubscriptionManager& sm;
+ std::string tag;
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_SUBSCRIPTIONMANAGER_H*/
diff --git a/cpp/include/qpid/client/SubscriptionSettings.h b/cpp/include/qpid/client/SubscriptionSettings.h
new file mode 100644
index 0000000000..b4cb302b56
--- /dev/null
+++ b/cpp/include/qpid/client/SubscriptionSettings.h
@@ -0,0 +1,123 @@
+#ifndef QPID_CLIENT_SUBSCRIPTIONSETTINGS_H
+#define QPID_CLIENT_SUBSCRIPTIONSETTINGS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/FlowControl.h"
+#include "qpid/framing/enum.h"
+
+namespace qpid {
+namespace client {
+
+/** Bring AMQP enum definitions for message class into this namespace. */
+using namespace qpid::framing::message;
+
+enum CompletionMode {
+ MANUAL_COMPLETION = 0,
+ COMPLETE_ON_DELIVERY = 1,
+ COMPLETE_ON_ACCEPT = 2
+};
+/**
+ * Settings for a subscription.
+ */
+struct SubscriptionSettings
+{
+ SubscriptionSettings(
+ FlowControl flow=FlowControl::unlimited(),
+ AcceptMode accept=ACCEPT_MODE_EXPLICIT,
+ AcquireMode acquire=ACQUIRE_MODE_PRE_ACQUIRED,
+ unsigned int autoAck_=1,
+ CompletionMode completion=COMPLETE_ON_DELIVERY
+ ) : flowControl(flow), acceptMode(accept), acquireMode(acquire), autoAck(autoAck_), completionMode(completion), exclusive(false) {}
+
+ FlowControl flowControl; ///@< Flow control settings. @see FlowControl
+ /**
+ * The acceptMode determines whether the broker should expect
+ * delivery of messages to be acknowledged by the client
+ * indicating that it accepts them. A value of
+ * ACCEPT_MODE_EXPLICIT means that messages must be accepted
+ * (note: this may be done automatically by the library - see
+ * autoAck - or through an explicit call be the application - see
+ * Subscription::accept()) before they can be dequeued. A value of
+ * ACCEPT_MODE_NONE means that the broker can dequeue a message as
+ * soon as it is acquired.
+ */
+ AcceptMode acceptMode; ///@< ACCEPT_MODE_EXPLICIT or ACCEPT_MODE_NONE
+ /**
+ * The acquireMode determines whether messages are locked for the
+ * subscriber when delivered, and thus are not delivered to any
+ * other subscriber unless this subscriber releases them.
+ *
+ * The default is ACQUIRE_MODE_PRE_ACQUIRED meaning that the
+ * subscriber expects to have been given that message exclusively
+ * (i.e. the message will not be given to any other subscriber
+ * unless released explicitly or by this subscribers session
+ * failing without having accepted the message).
+ *
+ * Delivery of message in ACQUIRE_MODE_NOT_ACQUIRED mode means the
+ * message will still be available for other subscribers to
+ * receive. The application can if desired acquire a (set of)
+ * messages through an explicit acquire call - see
+ * Subscription::acquire().
+ */
+ AcquireMode acquireMode; ///@< ACQUIRE_MODE_PRE_ACQUIRED or ACQUIRE_MODE_NOT_ACQUIRED
+
+ /**
+ * Configures the frequency at which messages are automatically
+ * accepted (e.g. a value of 5 means that messages are accepted in
+ * batches of 5). A value of 0 means no automatic acknowledgement
+ * will occur and the application will itself be responsible for
+ * accepting messages.
+ */
+ unsigned int autoAck;
+ /**
+ * In windowing mode, completion of a message will cause the
+ * credit used up by that message to be reallocated. The
+ * subscriptions completion mode controls how completion is
+ * managed.
+ *
+ * If set to COMPLETE_ON_DELIVERY (which is the default), messages
+ * will be marked as completed once they have been received. The
+ * server will be explicitly notified of all completed messages
+ * for the session when the next accept is sent through the
+ * subscription (either explictly or through autAck). However the
+ * server may also periodically request information on the
+ * completed messages.
+ *
+ * If set to COMPLETE_ON_ACCEPT, messages will be marked as
+ * completed once they are accepted (via the Subscription class)
+ * and the server will also be notified of all completed messages
+ * for the session.
+ *
+ * If set to MANUAL_COMPLETION the application is responsible for
+ * completing messages (@see Session::markCompleted()).
+ */
+ CompletionMode completionMode;
+ /**
+ * If set, requests that no other subscriber be allowed to access
+ * the queue while this subscription is active.
+ */
+ bool exclusive;
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_SUBSCRIPTIONSETTINGS_H*/
diff --git a/cpp/include/qpid/client/TypedResult.h b/cpp/include/qpid/client/TypedResult.h
new file mode 100644
index 0000000000..8e1a16580c
--- /dev/null
+++ b/cpp/include/qpid/client/TypedResult.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef _TypedResult_
+#define _TypedResult_
+
+#include "qpid/client/Completion.h"
+#include "qpid/framing/StructHelper.h"
+
+namespace qpid {
+namespace client {
+
+/**
+ * Returned by asynchronous commands that return a result.
+ * You can use get() to wait for completion and get the result value.
+ * \ingroup clientapi
+ */
+template <class T> class TypedResult : public Completion
+{
+ T result;
+ bool decoded;
+
+public:
+ ///@internal
+ TypedResult(const Completion& c) : Completion(c), decoded(false) {}
+
+ /**
+ * Wait for the asynchronous command that returned this TypedResult to complete
+ * and return its result.
+ *
+ *@return The result returned by the command.
+ *@exception If the command returns an error, get() throws an exception.
+ *
+ */
+ T& get() {
+ if (!decoded) {
+ framing::StructHelper helper;
+ helper.decode(result, getResult());
+ decoded = true;
+ }
+ return result;
+ }
+};
+
+}}
+
+#endif
diff --git a/cpp/include/qpid/client/amqp0_10/Codecs.h b/cpp/include/qpid/client/amqp0_10/Codecs.h
new file mode 100644
index 0000000000..5ef0b9fffe
--- /dev/null
+++ b/cpp/include/qpid/client/amqp0_10/Codecs.h
@@ -0,0 +1,61 @@
+#ifndef QPID_CLIENT_AMQP0_10_CODECS_H
+#define QPID_CLIENT_AMQP0_10_CODECS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/Codec.h"
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+
+/**
+ * Codec for encoding/decoding a map of Variants using the AMQP 0-10
+ * map encoding.
+ */
+class MapCodec : public qpid::messaging::Codec
+{
+ public:
+ void encode(const qpid::messaging::Variant&, std::string&);
+ void decode(const std::string&, qpid::messaging::Variant&);
+
+ static const std::string contentType;
+ private:
+};
+
+/**
+ * Codec for encoding/decoding a list of Variants using the AMQP 0-10
+ * list encoding.
+ */
+class ListCodec : public qpid::messaging::Codec
+{
+ public:
+ void encode(const qpid::messaging::Variant&, std::string&);
+ void decode(const std::string&, qpid::messaging::Variant&);
+
+ static const std::string contentType;
+ private:
+};
+
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_CODECS_H*/
diff --git a/cpp/include/qpid/console/Agent.h b/cpp/include/qpid/console/Agent.h
new file mode 100644
index 0000000000..97d75da250
--- /dev/null
+++ b/cpp/include/qpid/console/Agent.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_AGENT_H_
+#define _QPID_CONSOLE_AGENT_H_
+
+#include "qpid/console/Broker.h"
+#include "qpid/console/ConsoleImportExport.h"
+
+namespace qpid {
+namespace console {
+
+ /**
+ *
+ * \ingroup qmfconsoleapi
+ */
+ class QPID_CONSOLE_EXTERN Agent {
+ public:
+ typedef std::vector<Agent*> Vector;
+
+ Agent(Broker* _broker, uint32_t _bank, const std::string& _label) :
+ broker(_broker), brokerBank(broker->getBrokerBank()),
+ agentBank(_bank), label(_label) {}
+ Broker* getBroker() const { return broker; }
+ uint32_t getBrokerBank() const { return brokerBank; }
+ uint32_t getAgentBank() const { return agentBank; }
+ const std::string& getLabel() const { return label; }
+
+ private:
+ Broker* broker;
+ const uint32_t brokerBank;
+ const uint32_t agentBank;
+ const std::string label;
+ };
+
+ QPID_CONSOLE_EXTERN std::ostream& operator<<(std::ostream& o, const Agent& agent);
+}
+}
+
+
+#endif
diff --git a/cpp/include/qpid/console/Broker.h b/cpp/include/qpid/console/Broker.h
new file mode 100644
index 0000000000..af163b8bfd
--- /dev/null
+++ b/cpp/include/qpid/console/Broker.h
@@ -0,0 +1,133 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_BROKER_H_
+#define _QPID_CONSOLE_BROKER_H_
+
+#include "qpid/console/ConsoleImportExport.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/ConnectionSettings.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Condition.h"
+#include "qpid/Url.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/Uuid.h"
+#include <string>
+#include <iostream>
+
+namespace qpid {
+namespace console {
+ class SessionManager;
+ class Agent;
+ class Object;
+
+ /**
+ *
+ * \ingroup qpidconsoleapi
+ */
+ class Broker : public client::MessageListener {
+ public:
+ QPID_CONSOLE_EXTERN Broker(SessionManager& sm,
+ client::ConnectionSettings& settings);
+ QPID_CONSOLE_EXTERN ~Broker();
+
+ bool isConnected() const { return connected; }
+ const std::string& getError() const { return error; }
+ const std::string& getSessionId() const { return amqpSessionId; }
+ const framing::Uuid& getBrokerId() const { return brokerId; }
+ uint32_t getBrokerBank() const { return 1; }
+ void addBinding(const std::string& key) {
+ connThreadBody.bindExchange("qpid.management", key);
+ }
+ QPID_CONSOLE_EXTERN std::string getUrl() const;
+
+ private:
+ friend class SessionManager;
+ friend class Object;
+ typedef std::map<uint64_t,Agent*> AgentMap;
+ static const int SYNC_TIME = 60;
+
+ SessionManager& sessionManager;
+ AgentMap agents;
+ bool connected;
+ std::string error;
+ std::string amqpSessionId;
+ client::ConnectionSettings connectionSettings;
+ sys::Mutex lock;
+ sys::Condition cond;
+ framing::Uuid brokerId;
+ uint32_t reqsOutstanding;
+ bool syncInFlight;
+ bool topicBound;
+ Object* methodObject;
+
+ friend class ConnectionThread;
+ class ConnectionThread : public sys::Runnable {
+ bool operational;
+ bool shuttingDown;
+ Broker& broker;
+ framing::Uuid sessionId;
+ client::Connection connection;
+ client::Session session;
+ client::SubscriptionManager* subscriptions;
+ std::stringstream queueName;
+ sys::Mutex connLock;
+ void run();
+ public:
+ ConnectionThread(Broker& _broker) :
+ operational(false), shuttingDown(false), broker(_broker), subscriptions(0) {}
+ ~ConnectionThread();
+ void sendBuffer(qpid::framing::Buffer& buf,
+ uint32_t length,
+ const std::string& exchange = "qpid.management",
+ const std::string& routingKey = "broker");
+ void bindExchange(const std::string& exchange, const std::string& key);
+ void shutdown();
+ };
+
+ ConnectionThread connThreadBody;
+ sys::Thread connThread;
+
+ void encodeHeader(framing::Buffer& buf, uint8_t opcode, uint32_t seq = 0) const;
+ bool checkHeader(framing::Buffer& buf, uint8_t *opcode, uint32_t *seq) const;
+ void received(client::Message& msg);
+ void resetAgents();
+ void updateAgent(const Object& object);
+ void waitForStable();
+ void incOutstanding();
+ void decOutstanding();
+ void setBrokerId(const framing::Uuid& id) { brokerId = id; }
+ void appendAgents(std::vector<Agent*>& agents) const;
+
+ friend QPID_CONSOLE_EXTERN std::ostream& operator<<(std::ostream& o, const Broker& k);
+ };
+
+ QPID_CONSOLE_EXTERN std::ostream& operator<<(std::ostream& o, const Broker& k);
+}
+}
+
+#endif
diff --git a/cpp/include/qpid/console/ClassKey.h b/cpp/include/qpid/console/ClassKey.h
new file mode 100644
index 0000000000..95cd2627f1
--- /dev/null
+++ b/cpp/include/qpid/console/ClassKey.h
@@ -0,0 +1,66 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_CLASSKEY_H_
+#define _QPID_CONSOLE_CLASSKEY_H_
+
+#include <string>
+#include "qpid/console/ConsoleImportExport.h"
+#include "qpid/console/Package.h"
+#include "qpid/framing/Buffer.h"
+
+namespace qpid {
+namespace console {
+
+ /**
+ *
+ * \ingroup qmfconsoleapi
+ */
+ class QPID_CONSOLE_EXTERN ClassKey {
+ public:
+ static const int HASH_SIZE = 16;
+
+ ClassKey(const std::string& package, const std::string& name, const uint8_t* hash);
+
+ const std::string& getPackageName() const { return package; }
+ const std::string& getClassName() const { return name; }
+ const uint8_t* getHash() const { return hash; }
+ std::string getHashString() const;
+ std::string str() const;
+ bool operator==(const ClassKey& other) const;
+ bool operator!=(const ClassKey& other) const;
+ bool operator<(const ClassKey& other) const;
+ bool operator>(const ClassKey& other) const;
+ bool operator<=(const ClassKey& other) const;
+ bool operator>=(const ClassKey& other) const;
+ void encode(framing::Buffer& buffer) const;
+
+ private:
+ std::string package;
+ std::string name;
+ uint8_t hash[HASH_SIZE];
+ };
+
+ QPID_CONSOLE_EXTERN std::ostream& operator<<(std::ostream& o, const ClassKey& k);
+}
+}
+
+
+#endif
diff --git a/cpp/include/qpid/console/ConsoleImportExport.h b/cpp/include/qpid/console/ConsoleImportExport.h
new file mode 100644
index 0000000000..c2d7cb3a14
--- /dev/null
+++ b/cpp/include/qpid/console/ConsoleImportExport.h
@@ -0,0 +1,33 @@
+#ifndef QPID_CONSOLE_IMPORT_EXPORT_H
+#define QPID_CONSOLE_IMPORT_EXPORT_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#if defined(WIN32) && !defined(QPID_DECLARE_STATIC)
+#if defined(CONSOLE_EXPORT) || defined (qmfconsole_EXPORTS)
+#define QPID_CONSOLE_EXTERN __declspec(dllexport)
+#else
+#define QPID_CONSOLE_EXTERN __declspec(dllimport)
+#endif
+#else
+#define QPID_CONSOLE_EXTERN
+#endif
+
+#endif
diff --git a/cpp/include/qpid/console/ConsoleListener.h b/cpp/include/qpid/console/ConsoleListener.h
new file mode 100644
index 0000000000..7a649da657
--- /dev/null
+++ b/cpp/include/qpid/console/ConsoleListener.h
@@ -0,0 +1,97 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_CONSOLE_LISTENER_H_
+#define _QPID_CONSOLE_CONSOLE_LISTENER_H_
+
+#include <string>
+#include "qpid/console/ConsoleImportExport.h"
+#include "qpid/console/Broker.h"
+#include "qpid/console/ClassKey.h"
+#include "qpid/console/Object.h"
+#include "qpid/console/Event.h"
+
+namespace qpid {
+namespace console {
+
+ /**
+ * Implement a subclass of ConsoleListener and subscribe it using
+ * the SessionManager to receive indications.
+ *
+ * \ingroup qmfconsoleapi
+ */
+ class QPID_CONSOLE_EXTERN ConsoleListener{
+ public:
+ virtual ~ConsoleListener() {};
+
+ /** Invoked when a connection is established to a broker
+ */
+ virtual void brokerConnected(const Broker&) {}
+
+ /** Invoked when the connection to a broker is lost
+ */
+ virtual void brokerDisconnected(const Broker&) {}
+
+ /** Invoked when a QMF package is discovered.
+ */
+ virtual void newPackage(const std::string&) {}
+
+ /** Invoked when a new class is discovered. Session.getSchema can be
+ * used to obtain details about the class.
+ */
+ virtual void newClass(const ClassKey&) {}
+
+ /** Invoked when a QMF agent is discovered.
+ */
+ virtual void newAgent(const Agent&) {}
+
+ /** Invoked when a QMF agent disconects.
+ */
+ virtual void delAgent(const Agent&) {}
+
+ /** Invoked when an object is updated.
+ */
+ virtual void objectProps(Broker&, Object&) {}
+
+ /** Invoked when an object is updated.
+ */
+ virtual void objectStats(Broker&, Object&) {}
+
+ /** Invoked when an event is raised.
+ */
+ virtual void event(Event&) {}
+
+ /**
+ */
+ //virtual void heartbeat(Agent&, uint64_t) {}
+
+ /**
+ */
+ virtual void brokerInfo(Broker&) {}
+
+ /**
+ */
+ //virtual void methodResponse(Broker&, uint32_t seq, MethodResponse&) {}
+ };
+}
+}
+
+
+#endif
diff --git a/cpp/include/qpid/console/Event.h b/cpp/include/qpid/console/Event.h
new file mode 100644
index 0000000000..ef4ecc791c
--- /dev/null
+++ b/cpp/include/qpid/console/Event.h
@@ -0,0 +1,86 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_EVENT_H_
+#define _QPID_CONSOLE_EVENT_H_
+
+#include "qpid/console/ConsoleImportExport.h"
+#include "qpid/console/Object.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/framing/FieldTable.h"
+
+namespace qpid {
+namespace framing {
+ class Buffer;
+}
+namespace console {
+
+ class Broker;
+ struct SchemaClass;
+ class ClassKey;
+
+ /**
+ *
+ * \ingroup qmfconsoleapi
+ */
+ class Event {
+ public:
+ typedef enum {
+ SEV_EMERGENCY = 0, SEV_ALERT = 1, SEV_CRITICAL = 2, SEV_ERROR = 3,
+ SEV_WARNING = 4, SEV_NOTICE = 5, SEV_INFO = 6, SEV_DEBUG = 7
+ } Severity;
+
+ QPID_CONSOLE_EXTERN Event(Broker* broker,
+ SchemaClass* schemaClass,
+ framing::Buffer& buffer);
+ Broker* getBroker() const { return broker; }
+ QPID_CONSOLE_EXTERN const ClassKey& getClassKey() const;
+ SchemaClass* getSchema() const { return schema; }
+ const Object::AttributeMap& getAttributes() const { return attributes; }
+ uint64_t getTimestamp() const { return timestamp; }
+ uint8_t getSeverity() const { return severity; }
+ QPID_CONSOLE_EXTERN std::string getSeverityString() const;
+
+ QPID_CONSOLE_EXTERN ObjectId attrRef(const std::string& key) const;
+ QPID_CONSOLE_EXTERN uint32_t attrUint(const std::string& key) const;
+ QPID_CONSOLE_EXTERN int32_t attrInt(const std::string& key) const;
+ QPID_CONSOLE_EXTERN uint64_t attrUint64(const std::string& key) const;
+ QPID_CONSOLE_EXTERN int64_t attrInt64(const std::string& key) const;
+ QPID_CONSOLE_EXTERN std::string attrString(const std::string& key) const;
+ QPID_CONSOLE_EXTERN bool attrBool(const std::string& key) const;
+ QPID_CONSOLE_EXTERN float attrFloat(const std::string& key) const;
+ QPID_CONSOLE_EXTERN double attrDouble(const std::string& key) const;
+ QPID_CONSOLE_EXTERN framing::Uuid attrUuid(const std::string& key) const;
+ QPID_CONSOLE_EXTERN framing::FieldTable attrMap(const std::string& key) const;
+
+ private:
+ Broker* broker;
+ SchemaClass* schema;
+ uint64_t timestamp;
+ Severity severity;
+ Object::AttributeMap attributes;
+ };
+
+ QPID_CONSOLE_EXTERN std::ostream& operator<<(std::ostream& o, const Event& event);
+}
+}
+
+
+#endif
diff --git a/cpp/include/qpid/console/Object.h b/cpp/include/qpid/console/Object.h
new file mode 100644
index 0000000000..5a29fdf792
--- /dev/null
+++ b/cpp/include/qpid/console/Object.h
@@ -0,0 +1,123 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_OBJECT_H_
+#define _QPID_CONSOLE_OBJECT_H_
+
+#include "qpid/console/ConsoleImportExport.h"
+#include "qpid/console/ObjectId.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/framing/FieldTable.h"
+#include <boost/shared_ptr.hpp>
+#include <map>
+#include <set>
+#include <vector>
+
+namespace qpid {
+namespace framing {
+ class Buffer;
+}
+namespace console {
+
+ class Broker;
+ struct SchemaClass;
+ struct SchemaMethod;
+ class ObjectId;
+ class ClassKey;
+ class Value;
+
+ /**
+ * \ingroup qmfconsoleapi
+ */
+ struct MethodResponse {
+ uint32_t code;
+ std::string text;
+ std::map<std::string, boost::shared_ptr<Value> > arguments;
+ };
+
+ class Object {
+ public:
+ typedef std::vector<Object> Vector;
+ struct AttributeMap : public std::map<std::string, boost::shared_ptr<Value> > {
+ QPID_CONSOLE_EXTERN void addRef(const std::string& key, const ObjectId& val);
+ QPID_CONSOLE_EXTERN void addUint(const std::string& key, uint32_t val);
+ QPID_CONSOLE_EXTERN void addInt(const std::string& key, int32_t val);
+ QPID_CONSOLE_EXTERN void addUint64(const std::string& key, uint64_t val);
+ QPID_CONSOLE_EXTERN void addInt64(const std::string& key, int64_t val);
+ QPID_CONSOLE_EXTERN void addString(const std::string& key, const std::string& val);
+ QPID_CONSOLE_EXTERN void addBool(const std::string& key, bool val);
+ QPID_CONSOLE_EXTERN void addFloat(const std::string& key, float val);
+ QPID_CONSOLE_EXTERN void addDouble(const std::string& key, double val);
+ QPID_CONSOLE_EXTERN void addUuid(const std::string& key, const framing::Uuid& val);
+ QPID_CONSOLE_EXTERN void addMap(const std::string& key, const framing::FieldTable& val);
+ };
+
+ QPID_CONSOLE_EXTERN Object(Broker* broker, SchemaClass* schemaClass, framing::Buffer& buffer, bool prop, bool stat);
+ QPID_CONSOLE_EXTERN ~Object();
+
+ Broker* getBroker() const { return broker; }
+ const ObjectId& getObjectId() const { return objectId; }
+ QPID_CONSOLE_EXTERN const ClassKey& getClassKey() const;
+ SchemaClass* getSchema() const { return schema; }
+ uint64_t getCurrentTime() const { return currentTime; }
+ uint64_t getCreateTime() const { return createTime; }
+ uint64_t getDeleteTime() const { return deleteTime; }
+ bool isDeleted() const { return deleteTime != 0; }
+ QPID_CONSOLE_EXTERN std::string getIndex() const;
+ QPID_CONSOLE_EXTERN void mergeUpdate(const Object& updated);
+ const AttributeMap& getAttributes() const { return attributes; }
+ QPID_CONSOLE_EXTERN void invokeMethod(const std::string name,
+ const AttributeMap& args,
+ MethodResponse& result);
+ QPID_CONSOLE_EXTERN void handleMethodResp(framing::Buffer& buffer,
+ uint32_t sequence);
+
+ QPID_CONSOLE_EXTERN ObjectId attrRef(const std::string& key) const;
+ QPID_CONSOLE_EXTERN uint32_t attrUint(const std::string& key) const;
+ QPID_CONSOLE_EXTERN int32_t attrInt(const std::string& key) const;
+ QPID_CONSOLE_EXTERN uint64_t attrUint64(const std::string& key) const;
+ QPID_CONSOLE_EXTERN int64_t attrInt64(const std::string& key) const;
+ QPID_CONSOLE_EXTERN std::string attrString(const std::string& key) const;
+ QPID_CONSOLE_EXTERN bool attrBool(const std::string& key) const;
+ QPID_CONSOLE_EXTERN float attrFloat(const std::string& key) const;
+ QPID_CONSOLE_EXTERN double attrDouble(const std::string& key) const;
+ QPID_CONSOLE_EXTERN framing::Uuid attrUuid(const std::string& key) const;
+ QPID_CONSOLE_EXTERN framing::FieldTable attrMap(const std::string& key) const;
+
+ private:
+ Broker* broker;
+ SchemaClass* schema;
+ ObjectId objectId;
+ uint64_t currentTime;
+ uint64_t createTime;
+ uint64_t deleteTime;
+ AttributeMap attributes;
+ SchemaMethod* pendingMethod;
+ MethodResponse methodResponse;
+
+ void parsePresenceMasks(framing::Buffer& buffer, std::set<std::string>& excludeList);
+ };
+
+ QPID_CONSOLE_EXTERN std::ostream& operator<<(std::ostream& o, const Object& object);
+}
+}
+
+
+#endif
diff --git a/cpp/include/qpid/console/ObjectId.h b/cpp/include/qpid/console/ObjectId.h
new file mode 100644
index 0000000000..7904c85598
--- /dev/null
+++ b/cpp/include/qpid/console/ObjectId.h
@@ -0,0 +1,69 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_OBJECTID_H
+#define _QPID_CONSOLE_OBJECTID_H
+
+#include <iostream>
+#include "qpid/console/ConsoleImportExport.h"
+#include "qpid/sys/IntegerTypes.h"
+
+namespace qpid {
+namespace framing {
+ class Buffer;
+}
+namespace console {
+
+ /**
+ *
+ * \ingroup qmfconsoleapi
+ */
+ class QPID_CONSOLE_EXTERN ObjectId {
+ public:
+ ObjectId() : first(0), second(0) {}
+ ObjectId(framing::Buffer& buffer);
+
+ uint8_t getFlags() const { return (first & 0xF000000000000000LL) >> 60; }
+ uint16_t getSequence() const { return (first & 0x0FFF000000000000LL) >> 48; }
+ uint32_t getBrokerBank() const { return (first & 0x0000FFFFF0000000LL) >> 28; }
+ uint32_t getAgentBank() const { return first & 0x000000000FFFFFFFLL; }
+ uint64_t getObject() const { return second; }
+ bool isDurable() const { return getSequence() == 0; }
+ void decode(framing::Buffer& buffer);
+ void encode(framing::Buffer& buffer);
+ void setValue(uint64_t f, uint64_t s) { first = f; second = s; }
+
+ bool operator==(const ObjectId& other) const;
+ bool operator!=(const ObjectId& other) const;
+ bool operator<(const ObjectId& other) const;
+ bool operator>(const ObjectId& other) const;
+ bool operator<=(const ObjectId& other) const;
+ bool operator>=(const ObjectId& other) const;
+
+ private:
+ uint64_t first;
+ uint64_t second;
+ };
+
+ QPID_CONSOLE_EXTERN std::ostream& operator<<(std::ostream& o, const ObjectId& id);
+}
+}
+
+#endif
diff --git a/cpp/include/qpid/console/Package.h b/cpp/include/qpid/console/Package.h
new file mode 100644
index 0000000000..3b59e366ff
--- /dev/null
+++ b/cpp/include/qpid/console/Package.h
@@ -0,0 +1,78 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_PACKAGE_H_
+#define _QPID_CONSOLE_PACKAGE_H_
+
+#include <string>
+#include <map>
+#include "qpid/console/ConsoleImportExport.h"
+#include "qpid/sys/IntegerTypes.h"
+
+namespace qpid {
+namespace console {
+ struct SchemaClass;
+
+ /**
+ *
+ * \ingroup qmfconsoleapi
+ */
+ class Package {
+ public:
+ Package(const std::string& n) : name(n) {}
+ const std::string& getName() const { return name; }
+
+ private:
+ friend class SessionManager;
+ struct NameHash {
+ std::string name;
+ uint8_t hash[16];
+ NameHash(const std::string& n, const uint8_t* h) : name(n) {
+ for (int i = 0; i < 16; i++)
+ hash[i] = h[i];
+ }
+ };
+
+ struct NameHashComp {
+ bool operator() (const NameHash& lhs, const NameHash& rhs) const
+ {
+ if (lhs.name != rhs.name)
+ return lhs.name < rhs.name;
+ else
+ for (int i = 0; i < 16; i++)
+ if (lhs.hash[i] != rhs.hash[i])
+ return lhs.hash[i] < rhs.hash[i];
+ return false;
+ }
+ };
+
+ typedef std::map<NameHash, SchemaClass*, NameHashComp> ClassMap;
+
+ const std::string name;
+ ClassMap classes;
+
+ SchemaClass* getClass(const std::string& className, uint8_t* hash);
+ void addClass(const std::string& className, uint8_t* hash,
+ SchemaClass* schemaClass);
+ };
+}
+}
+
+#endif
diff --git a/cpp/include/qpid/console/Schema.h b/cpp/include/qpid/console/Schema.h
new file mode 100644
index 0000000000..6d4e41ab3e
--- /dev/null
+++ b/cpp/include/qpid/console/Schema.h
@@ -0,0 +1,105 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_SCHEMA_H_
+#define _QPID_CONSOLE_SCHEMA_H_
+
+#include "qpid/console/ClassKey.h"
+#include <boost/shared_ptr.hpp>
+#include <vector>
+
+namespace qpid {
+namespace framing {
+ class Buffer;
+}
+namespace console {
+ class Value;
+
+ struct SchemaArgument {
+ SchemaArgument(framing::Buffer& buffer, bool forMethod = false);
+ boost::shared_ptr<Value> decodeValue(framing::Buffer& buffer);
+
+ std::string name;
+ uint8_t typeCode;
+ bool dirInput;
+ bool dirOutput;
+ std::string unit;
+ int min;
+ int max;
+ int maxLen;
+ std::string desc;
+ std::string defaultVal;
+ };
+
+ struct SchemaProperty {
+ SchemaProperty(framing::Buffer& buffer);
+ boost::shared_ptr<Value> decodeValue(framing::Buffer& buffer);
+
+ std::string name;
+ uint8_t typeCode;
+ uint8_t accessCode;
+ bool isIndex;
+ bool isOptional;
+ std::string unit;
+ int min;
+ int max;
+ int maxLen;
+ std::string desc;
+ };
+
+ struct SchemaStatistic {
+ SchemaStatistic(framing::Buffer& buffer);
+ boost::shared_ptr<Value> decodeValue(framing::Buffer& buffer);
+
+ std::string name;
+ uint8_t typeCode;
+ std::string unit;
+ std::string desc;
+ };
+
+ struct SchemaMethod {
+ SchemaMethod(framing::Buffer& buffer);
+ ~SchemaMethod();
+
+ std::string name;
+ std::string desc;
+ std::vector<SchemaArgument*> arguments;
+ };
+
+ struct SchemaClass {
+ static const uint8_t KIND_TABLE = 1;
+ static const uint8_t KIND_EVENT = 2;
+
+ SchemaClass(const uint8_t kind, const ClassKey& key, framing::Buffer& buffer);
+ ~SchemaClass();
+ const ClassKey& getClassKey() const { return key; }
+
+ const uint8_t kind;
+ const ClassKey key;
+ std::vector<SchemaProperty*> properties;
+ std::vector<SchemaStatistic*> statistics;
+ std::vector<SchemaMethod*> methods;
+ std::vector<SchemaArgument*> arguments;
+ };
+}
+}
+
+
+#endif
diff --git a/cpp/include/qpid/console/SequenceManager.h b/cpp/include/qpid/console/SequenceManager.h
new file mode 100644
index 0000000000..ea0ccf3f77
--- /dev/null
+++ b/cpp/include/qpid/console/SequenceManager.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_SEQUENCEMANAGER_H_
+#define _QPID_CONSOLE_SEQUENCEMANAGER_H_
+
+#include "qpid/console/ConsoleImportExport.h"
+#include "qpid/sys/Mutex.h"
+#include <map>
+#include <string>
+#include <set>
+
+namespace qpid {
+namespace console {
+
+ /**
+ *
+ * \ingroup qpidconsoleapi
+ */
+ class SequenceManager {
+ public:
+ typedef std::set<uint32_t> set;
+
+ SequenceManager() : sequence(0) {}
+ QPID_CONSOLE_EXTERN uint32_t reserve(const std::string& context = "");
+ QPID_CONSOLE_EXTERN std::string release(uint32_t seq);
+
+ private:
+ sys::Mutex lock;
+ uint32_t sequence;
+ std::map<uint32_t, std::string> pending;
+ };
+}
+}
+
+
+#endif
diff --git a/cpp/include/qpid/console/SessionManager.h b/cpp/include/qpid/console/SessionManager.h
new file mode 100644
index 0000000000..f27037a559
--- /dev/null
+++ b/cpp/include/qpid/console/SessionManager.h
@@ -0,0 +1,205 @@
+#ifndef _QPID_CONSOLE_SESSION_MANAGER_H
+#define _QPID_CONSOLE_SESSION_MANAGER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/console/ConsoleImportExport.h"
+#include "qpid/console/Broker.h"
+#include "qpid/console/Package.h"
+#include "qpid/console/SequenceManager.h"
+#include "qpid/console/ClassKey.h"
+#include "qpid/console/Schema.h"
+#include "qpid/console/Agent.h"
+#include "qpid/console/Object.h"
+#include "qpid/console/ObjectId.h"
+#include "qpid/console/Value.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Condition.h"
+#include "qpid/client/ConnectionSettings.h"
+#include <string>
+#include <vector>
+
+namespace qpid {
+namespace console {
+
+class ConsoleListener;
+
+/**
+ *
+ * \ingroup qmfconsoleapi
+ */
+class SessionManager
+{
+ public:
+ typedef std::vector<std::string> NameVector;
+ typedef std::vector<ClassKey> KeyVector;
+ QPID_CONSOLE_EXTERN ~SessionManager();
+
+ struct Settings {
+ bool rcvObjects;
+ bool rcvEvents;
+ bool rcvHeartbeats;
+ bool userBindings;
+ uint32_t methodTimeout;
+ uint32_t getTimeout;
+
+ Settings() : rcvObjects(true), rcvEvents(true), rcvHeartbeats(true),
+ userBindings(false), methodTimeout(20), getTimeout(20)
+ {}
+ };
+
+ /** Create a new SessionManager
+ *
+ * Provide your own subclass of ConsoleListener to receive updates and indications
+ * asynchronously or leave it as its default and use only synchronous methods.
+ *
+ *@param listener Listener object to receive asynchronous indications.
+ *@param settings.rcvObjects Listener wishes to receive managed object data.
+ *@param settings.rcvEvents Listener wishes to receive events.
+ *@param settings.rcvHeartbeats Listener wishes to receive agent heartbeats.
+ *@param settings.userBindings If rcvObjects is true, userBindings allows the
+ * console client to control which object classes are received. See the bindPackage
+ * and bindClass methods. If userBindings is false, the listener will receive
+ * updates for all object classes.
+ */
+ QPID_CONSOLE_EXTERN SessionManager(ConsoleListener* listener = 0,
+ Settings settings = Settings());
+
+ /** Connect a broker to the console session
+ *
+ *@param settings Connection settings for client access
+ *@return broker object if operation is successful
+ * an exception shall be thrown.
+ */
+ QPID_CONSOLE_EXTERN Broker* addBroker(client::ConnectionSettings& settings);
+
+ /** Disconnect a broker from the console session
+ *
+ *@param broker The broker object returned from an earlier call to addBroker.
+ */
+ QPID_CONSOLE_EXTERN void delBroker(Broker* broker);
+
+ /** Get a list of known management packages
+ *
+ *@param packages Vector of package names returned by the session manager.
+ */
+ QPID_CONSOLE_EXTERN void getPackages(NameVector& packages);
+
+ /** Get a list of class keys associated with a package
+ *
+ *@param classKeys List of class keys returned by the session manager.
+ *@param packageName Name of package being queried.
+ */
+ QPID_CONSOLE_EXTERN void getClasses(KeyVector& classKeys,
+ const std::string& packageName);
+
+ /** Get the schema of a class given its class key
+ *
+ *@param classKey Class key of the desired schema.
+ */
+ QPID_CONSOLE_EXTERN SchemaClass& getSchema(const ClassKey& classKey);
+
+ /** Request that updates be received for all classes within a package
+ *
+ * Note that this method is only meaningful if a ConsoleListener was provided at session
+ * creation and if the 'userBindings' flag was set to true.
+ *
+ *@param packageName Name of the package to which to bind.
+ */
+ QPID_CONSOLE_EXTERN void bindPackage(const std::string& packageName);
+
+ /** Request update to be received for a particular class
+ *
+ * Note that this method is only meaningful if a ConsoleListener was provided at session
+ * creation and if the 'userBindings' flag was set to true.
+ *
+ *@param classKey Class key of class to which to bind.
+ */
+ QPID_CONSOLE_EXTERN void bindClass(const ClassKey& classKey);
+ QPID_CONSOLE_EXTERN void bindClass(const std::string& packageName,
+ const std::string& className);
+
+ /** Get a list of qmf agents known to the session manager.
+ *
+ *@param agents Vector of Agent objects returned by the session manager.
+ *@param broker Return agents registered with this broker only. If NULL, return agents
+ * from all connected brokers.
+ */
+ QPID_CONSOLE_EXTERN void getAgents(Agent::Vector& agents,
+ Broker* broker = 0);
+
+ /** Get objects from agents. There are four variants of this method with different ways of
+ * specifying from which class objects are being queried.
+ *
+ *@param objects List of objects received.
+ *@param classKey ClassKey object identifying class to be queried.
+ *@param className Class name identifying class to be queried.
+ *@param objectId Object Id of the single object to be queried.
+ *@param broker Restrict the query to this broker, or all brokers if NULL.
+ *@param agent Restrict the query to this agent, or all agents if NULL.
+ */
+ QPID_CONSOLE_EXTERN void getObjects(Object::Vector& objects,
+ const std::string& className,
+ Broker* broker = 0,
+ Agent* agent = 0);
+ //void getObjects(Object::Vector& objects, const ClassKey& classKey,
+ // Broker* broker = 0, Agent* agent = 0);
+ //void getObjects(Object::Vector& objects, const ObjectId& objectId,
+ // Broker* broker = 0, Agent* agent = 0);
+
+private:
+ friend class Broker;
+ friend class Broker::ConnectionThread;
+ friend class Object;
+ sys::Mutex lock;
+ sys::Mutex brokerListLock;
+ ConsoleListener* listener;
+ std::vector<Broker*> brokers;
+ std::map<std::string, Package*> packages;
+ SequenceManager sequenceManager;
+ sys::Condition cv;
+ SequenceManager::set syncSequenceList;
+ Object::Vector getResult;
+ std::string error;
+ Settings settings;
+ NameVector bindingKeyList;
+
+ void bindingKeys();
+ void allBrokersStable();
+ void startProtocol(Broker* broker);
+ void handleBrokerResp(Broker* broker, framing::Buffer& inBuffer, uint32_t sequence);
+ void handlePackageInd(Broker* broker, framing::Buffer& inBuffer, uint32_t sequence);
+ void handleCommandComplete(Broker* broker, framing::Buffer& inBuffer, uint32_t sequence);
+ void handleClassInd(Broker* broker, framing::Buffer& inBuffer, uint32_t sequence);
+ void handleMethodResp(Broker* broker, framing::Buffer& inBuffer, uint32_t sequence);
+ void handleHeartbeatInd(Broker* broker, framing::Buffer& inBuffer, uint32_t sequence);
+ void handleEventInd(Broker* broker, framing::Buffer& inBuffer, uint32_t sequence);
+ void handleSchemaResp(Broker* broker, framing::Buffer& inBuffer, uint32_t sequence);
+ void handleContentInd(Broker* broker, framing::Buffer& inBuffer, uint32_t sequence, bool prop, bool stat);
+ void handleBrokerConnect(Broker* broker);
+ void handleBrokerDisconnect(Broker* broker);
+
+};
+
+}} // namespace qpid::console
+
+#endif /*!_QPID_CONSOLE_SESSION_MANAGER_H*/
diff --git a/cpp/include/qpid/console/Value.h b/cpp/include/qpid/console/Value.h
new file mode 100644
index 0000000000..d9eb65053b
--- /dev/null
+++ b/cpp/include/qpid/console/Value.h
@@ -0,0 +1,213 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QPID_CONSOLE_VALUE_H_
+#define _QPID_CONSOLE_VALUE_H_
+
+#include "qpid/Exception.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/console/ObjectId.h"
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace framing {
+ class Buffer;
+}
+namespace console {
+
+ /**
+ * \ingroup qmfconsoleapi
+ */
+ class Value {
+
+ public:
+ typedef boost::shared_ptr<Value> Ptr;
+ virtual ~Value() {}
+ virtual std::string str() const = 0;
+
+ virtual bool isNull() const { return false; }
+ virtual bool isObjectId() const { return false; }
+ virtual bool isUint() const { return false; }
+ virtual bool isInt() const { return false; }
+ virtual bool isUint64() const { return false; }
+ virtual bool isInt64() const { return false; }
+ virtual bool isString() const { return false; }
+ virtual bool isBool() const { return false; }
+ virtual bool isFloat() const { return false; }
+ virtual bool isDouble() const { return false; }
+ virtual bool isUuid() const { return false; }
+ virtual bool isMap() const { return false; }
+
+ virtual ObjectId asObjectId() const { incompatible(); return ObjectId(); }
+ virtual uint32_t asUint() const { incompatible(); return 0; }
+ virtual int32_t asInt() const { incompatible(); return 0; }
+ virtual uint64_t asUint64() const { incompatible(); return 0; }
+ virtual int64_t asInt64() const { incompatible(); return 0; }
+ virtual std::string asString() const { incompatible(); return std::string(); }
+ virtual bool asBool() const { incompatible(); return false; }
+ virtual float asFloat() const { incompatible(); return 0.0; }
+ virtual double asDouble() const { incompatible(); return 0.0; }
+ virtual framing::Uuid asUuid() const { incompatible(); return framing::Uuid(); }
+ virtual framing::FieldTable asMap() const { incompatible(); return framing::FieldTable(); }
+
+ private:
+ void incompatible() const {
+ throw Exception("Incompatible Type");
+ }
+ };
+
+ class NullValue : public Value {
+ public:
+ NullValue() {}
+ std::string str() const;
+ bool isNull() const { return true; }
+ };
+
+ class RefValue : public Value {
+ public:
+ RefValue(ObjectId v) : value(v) {}
+ RefValue(framing::Buffer& buffer);
+ std::string str() const;
+ bool isObjectId() const { return true; }
+ ObjectId asObjectId() const { return value; }
+ private:
+ ObjectId value;
+ };
+
+ class UintValue : public Value {
+ public:
+ UintValue(uint32_t v) : value(v) {}
+ std::string str() const;
+ bool isUint() const { return true; }
+ uint32_t asUint() const { return value; }
+ bool isUint64() const { return true; }
+ uint64_t asUint64() const { return (uint64_t) value; }
+ private:
+ uint32_t value;
+ };
+
+ class IntValue : public Value {
+ public:
+ IntValue(int32_t v) : value(v) {}
+ std::string str() const;
+ bool isInt() const { return true; }
+ int32_t asInt() const { return value; }
+ bool isInt64() const { return true; }
+ int64_t asInt64() const { return (int64_t) value; }
+ private:
+ int32_t value;
+ };
+
+ class Uint64Value : public Value {
+ public:
+ Uint64Value(uint64_t v) : value(v) {}
+ std::string str() const;
+ bool isUint64() const { return true; }
+ uint64_t asUint64() const { return value; }
+ private:
+ uint64_t value;
+ };
+
+ class Int64Value : public Value {
+ public:
+ Int64Value(int64_t v) : value(v) {}
+ std::string str() const;
+ bool isInt64() const { return true; }
+ int64_t asInt64() const { return value; }
+ private:
+ int64_t value;
+ };
+
+ class StringValue : public Value {
+ public:
+ StringValue(const std::string& v) : value(v) {}
+ StringValue(framing::Buffer& buffer, int tc);
+ std::string str() const { return value; }
+ bool isString() const { return true; }
+ std::string asString() const { return value; }
+ private:
+ std::string value;
+ };
+
+ class BoolValue : public Value {
+ public:
+ BoolValue(bool v) : value(v) {}
+ BoolValue(uint8_t v) : value(v != 0) {}
+ std::string str() const;
+ bool isBool() const { return true; }
+ bool asBool() const { return value; }
+ private:
+ bool value;
+ };
+
+ class FloatValue : public Value {
+ public:
+ FloatValue(float v) : value(v) {}
+ std::string str() const;
+ bool isFloat() const { return true; }
+ float asFloat() const { return value; }
+ bool isDouble() const { return true; }
+ double asDouble() const { return (double) value; }
+ private:
+ float value;
+ };
+
+ class DoubleValue : public Value {
+ public:
+ DoubleValue(double v) : value(v) {}
+ std::string str() const;
+ bool isDouble() const { return true; }
+ double asDouble() const { return value; }
+ private:
+ double value;
+ };
+
+ class UuidValue : public Value {
+ public:
+ UuidValue(const framing::Uuid& v) : value(v) {}
+ UuidValue(framing::Buffer& buffer);
+ std::string str() const { return value.str(); }
+ bool isUuid() const { return true; }
+ framing::Uuid asUuid() const { return value; }
+ private:
+ framing::Uuid value;
+ };
+
+ class MapValue : public Value {
+ public:
+ MapValue(const framing::FieldTable& v) : value(v) {}
+ MapValue(framing::Buffer& buffer);
+ std::string str() const;
+ bool isMap() const { return true; }
+ framing::FieldTable asMap() const { return value; }
+ private:
+ framing::FieldTable value;
+ };
+
+ class ValueFactory {
+ public:
+ static Value::Ptr newValue(int typeCode, framing::Buffer& buffer);
+ static void encodeValue(int typeCode, Value::Ptr value, framing::Buffer& buffer);
+ };
+}
+}
+
+#endif
diff --git a/cpp/include/qpid/framing/Array.h b/cpp/include/qpid/framing/Array.h
new file mode 100644
index 0000000000..d3bdd36aa6
--- /dev/null
+++ b/cpp/include/qpid/framing/Array.h
@@ -0,0 +1,97 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/FieldValue.h"
+#include "qpid/framing/TypeCode.h"
+#include <boost/shared_ptr.hpp>
+#include <iostream>
+#include <vector>
+#include "qpid/CommonImportExport.h"
+
+#ifndef _Array_
+#define _Array_
+
+namespace qpid {
+namespace framing {
+
+class Buffer;
+
+class Array
+{
+ public:
+ typedef boost::shared_ptr<FieldValue> ValuePtr;
+ typedef std::vector<ValuePtr> ValueVector;
+ typedef ValueVector::const_iterator const_iterator;
+ typedef ValueVector::iterator iterator;
+
+ QPID_COMMON_EXTERN uint32_t encodedSize() const;
+ QPID_COMMON_EXTERN void encode(Buffer& buffer) const;
+ QPID_COMMON_EXTERN void decode(Buffer& buffer);
+
+ QPID_COMMON_EXTERN int count() const;
+ QPID_COMMON_EXTERN bool operator==(const Array& other) const;
+
+ QPID_COMMON_EXTERN Array();
+ QPID_COMMON_EXTERN Array(TypeCode type);
+ QPID_COMMON_EXTERN Array(uint8_t type);
+ //creates a longstr array
+ QPID_COMMON_EXTERN Array(const std::vector<std::string>& in);
+
+ QPID_COMMON_EXTERN TypeCode getType() const { return type; }
+
+ // std collection interface.
+ QPID_COMMON_EXTERN const_iterator begin() const { return values.begin(); }
+ QPID_COMMON_EXTERN const_iterator end() const { return values.end(); }
+ QPID_COMMON_EXTERN iterator begin() { return values.begin(); }
+ QPID_COMMON_EXTERN iterator end(){ return values.end(); }
+
+ QPID_COMMON_EXTERN ValuePtr front() const { return values.front(); }
+ QPID_COMMON_EXTERN ValuePtr back() const { return values.back(); }
+ QPID_COMMON_EXTERN size_t size() const { return values.size(); }
+
+ QPID_COMMON_EXTERN void insert(iterator i, ValuePtr value);
+ QPID_COMMON_EXTERN void erase(iterator i) { values.erase(i); }
+ QPID_COMMON_EXTERN void push_back(ValuePtr value) { values.insert(end(), value); }
+ QPID_COMMON_EXTERN void pop_back() { values.pop_back(); }
+
+ // Non-std interface
+ QPID_COMMON_EXTERN void add(ValuePtr value) { push_back(value); }
+
+ template <class T>
+ void collect(std::vector<T>& out) const
+ {
+ for (ValueVector::const_iterator i = values.begin(); i != values.end(); ++i) {
+ out.push_back((*i)->get<T>());
+ }
+ }
+
+ private:
+ TypeCode type;
+ ValueVector values;
+
+ friend QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& out, const Array& body);
+};
+
+}
+}
+
+
+#endif
diff --git a/cpp/include/qpid/framing/Buffer.h b/cpp/include/qpid/framing/Buffer.h
new file mode 100644
index 0000000000..8a6a5c0d5f
--- /dev/null
+++ b/cpp/include/qpid/framing/Buffer.h
@@ -0,0 +1,136 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/framing/amqp_types.h"
+#include "qpid/Exception.h"
+#include "qpid/CommonImportExport.h"
+#include <boost/iterator/iterator_facade.hpp>
+
+#ifndef _Buffer_
+#define _Buffer_
+
+namespace qpid {
+namespace framing {
+
+struct OutOfBounds : qpid::Exception {
+ OutOfBounds() : qpid::Exception(std::string("Out of Bounds")) {}
+};
+
+class Content;
+class FieldTable;
+
+class Buffer
+{
+ uint32_t size;
+ char* data;
+ uint32_t position;
+ uint32_t r_position;
+
+ void checkAvailable(uint32_t count) { if (position + count > size) throw OutOfBounds(); }
+
+ public:
+
+ /** Buffer input/output iterator.
+ * Supports using an amqp_0_10::Codec with a framing::Buffer.
+ */
+ class Iterator : public boost::iterator_facade<
+ Iterator, char, boost::random_access_traversal_tag>
+ {
+ public:
+ Iterator(Buffer& b) : buffer(&b) {}
+
+ private:
+ friend class boost::iterator_core_access;
+ char& dereference() const { return buffer->data[buffer->position]; }
+ void increment() { ++buffer->position; }
+ bool equal(const Iterator& x) const { return buffer == x.buffer; }
+
+ Buffer* buffer;
+ };
+
+ friend class Iterator;
+
+ QPID_COMMON_EXTERN Buffer(char* data=0, uint32_t size=0);
+
+ QPID_COMMON_EXTERN void record();
+ QPID_COMMON_EXTERN void restore(bool reRecord = false);
+ QPID_COMMON_EXTERN void reset();
+
+ QPID_COMMON_EXTERN uint32_t available() { return size - position; }
+ QPID_COMMON_EXTERN uint32_t getSize() { return size; }
+ QPID_COMMON_EXTERN uint32_t getPosition() { return position; }
+ QPID_COMMON_EXTERN Iterator getIterator() { return Iterator(*this); }
+ QPID_COMMON_EXTERN char* getPointer() { return data; }
+
+ QPID_COMMON_EXTERN void putOctet(uint8_t i);
+ QPID_COMMON_EXTERN void putShort(uint16_t i);
+ QPID_COMMON_EXTERN void putLong(uint32_t i);
+ QPID_COMMON_EXTERN void putLongLong(uint64_t i);
+ QPID_COMMON_EXTERN void putInt8(int8_t i);
+ QPID_COMMON_EXTERN void putInt16(int16_t i);
+ QPID_COMMON_EXTERN void putInt32(int32_t i);
+ QPID_COMMON_EXTERN void putInt64(int64_t i);
+ QPID_COMMON_EXTERN void putFloat(float f);
+ QPID_COMMON_EXTERN void putDouble(double f);
+ QPID_COMMON_EXTERN void putBin128(const uint8_t* b);
+
+ QPID_COMMON_EXTERN uint8_t getOctet();
+ QPID_COMMON_EXTERN uint16_t getShort();
+ QPID_COMMON_EXTERN uint32_t getLong();
+ QPID_COMMON_EXTERN uint64_t getLongLong();
+ QPID_COMMON_EXTERN int8_t getInt8();
+ QPID_COMMON_EXTERN int16_t getInt16();
+ QPID_COMMON_EXTERN int32_t getInt32();
+ QPID_COMMON_EXTERN int64_t getInt64();
+ QPID_COMMON_EXTERN float getFloat();
+ QPID_COMMON_EXTERN double getDouble();
+
+ template <int n>
+ QPID_COMMON_EXTERN uint64_t getUInt();
+
+ template <int n>
+ QPID_COMMON_EXTERN void putUInt(uint64_t);
+
+ QPID_COMMON_EXTERN void putShortString(const string& s);
+ QPID_COMMON_EXTERN void putMediumString(const string& s);
+ QPID_COMMON_EXTERN void putLongString(const string& s);
+ QPID_COMMON_EXTERN void getShortString(string& s);
+ QPID_COMMON_EXTERN void getMediumString(string& s);
+ QPID_COMMON_EXTERN void getLongString(string& s);
+ QPID_COMMON_EXTERN void getBin128(uint8_t* b);
+
+ QPID_COMMON_EXTERN void putRawData(const string& s);
+ QPID_COMMON_EXTERN void getRawData(string& s, uint32_t size);
+
+ QPID_COMMON_EXTERN void putRawData(const uint8_t* data, size_t size);
+ QPID_COMMON_EXTERN void getRawData(uint8_t* data, size_t size);
+
+ template <class T> void put(const T& data) { data.encode(*this); }
+ template <class T> void get(T& data) { data.decode(*this); }
+
+ QPID_COMMON_EXTERN void dump(std::ostream&) const;
+};
+
+std::ostream& operator<<(std::ostream&, const Buffer&);
+
+}} // namespace qpid::framing
+
+
+#endif
diff --git a/cpp/include/qpid/framing/FieldTable.h b/cpp/include/qpid/framing/FieldTable.h
new file mode 100644
index 0000000000..62b4a4bc08
--- /dev/null
+++ b/cpp/include/qpid/framing/FieldTable.h
@@ -0,0 +1,128 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <iostream>
+#include <vector>
+#include <boost/shared_ptr.hpp>
+#include <map>
+#include "qpid/framing/amqp_types.h"
+#include "qpid/CommonImportExport.h"
+
+#ifndef _FieldTable_
+#define _FieldTable_
+
+namespace qpid {
+ /**
+ * The framing namespace contains classes that are used to create,
+ * send and receive the basic packets from which AMQP is built.
+ */
+namespace framing {
+
+class Array;
+class FieldValue;
+class Buffer;
+
+/**
+ * A set of name-value pairs. (See the AMQP spec for more details on
+ * AMQP field tables).
+ *
+ * \ingroup clientapi
+ */
+class FieldTable
+{
+ public:
+ typedef boost::shared_ptr<FieldValue> ValuePtr;
+ typedef std::map<std::string, ValuePtr> ValueMap;
+ typedef ValueMap::iterator iterator;
+ typedef ValueMap::const_reference const_reference;
+ typedef ValueMap::reference reference;
+ typedef ValueMap::value_type value_type;
+
+ QPID_COMMON_EXTERN FieldTable() {};
+ QPID_COMMON_EXTERN FieldTable(const FieldTable& ft);
+ QPID_COMMON_EXTERN ~FieldTable();
+ QPID_COMMON_EXTERN FieldTable& operator=(const FieldTable& ft);
+ QPID_COMMON_EXTERN uint32_t encodedSize() const;
+ QPID_COMMON_EXTERN void encode(Buffer& buffer) const;
+ QPID_COMMON_EXTERN void decode(Buffer& buffer);
+
+ QPID_COMMON_EXTERN int count() const;
+ QPID_COMMON_EXTERN void set(const std::string& name, const ValuePtr& value);
+ QPID_COMMON_EXTERN ValuePtr get(const std::string& name) const;
+ QPID_COMMON_EXTERN bool isSet(const std::string& name) const { return get(name).get() != 0; }
+
+ QPID_COMMON_EXTERN void setString(const std::string& name, const std::string& value);
+ QPID_COMMON_EXTERN void setInt(const std::string& name, const int value);
+ QPID_COMMON_EXTERN void setInt64(const std::string& name, const int64_t value);
+ QPID_COMMON_EXTERN void setTimestamp(const std::string& name, const uint64_t value);
+ QPID_COMMON_EXTERN void setUInt64(const std::string& name, const uint64_t value);
+ QPID_COMMON_EXTERN void setTable(const std::string& name, const FieldTable& value);
+ QPID_COMMON_EXTERN void setArray(const std::string& name, const Array& value);
+ QPID_COMMON_EXTERN void setFloat(const std::string& name, const float value);
+ QPID_COMMON_EXTERN void setDouble(const std::string& name, const double value);
+ //void setDecimal(string& name, xxx& value);
+
+ QPID_COMMON_EXTERN int getAsInt(const std::string& name) const;
+ QPID_COMMON_EXTERN uint64_t getAsUInt64(const std::string& name) const;
+ QPID_COMMON_EXTERN int64_t getAsInt64(const std::string& name) const;
+ QPID_COMMON_EXTERN std::string getAsString(const std::string& name) const;
+
+ QPID_COMMON_EXTERN bool getTable(const std::string& name, FieldTable& value) const;
+ QPID_COMMON_EXTERN bool getArray(const std::string& name, Array& value) const;
+ QPID_COMMON_EXTERN bool getFloat(const std::string& name, float& value) const;
+ QPID_COMMON_EXTERN bool getDouble(const std::string& name, double& value) const;
+ //bool getTimestamp(const std::string& name, uint64_t& value) const;
+ //bool getDecimal(string& name, xxx& value);
+ QPID_COMMON_EXTERN void erase(const std::string& name);
+
+
+ QPID_COMMON_EXTERN bool operator==(const FieldTable& other) const;
+
+ // Map-like interface.
+ ValueMap::const_iterator begin() const { return values.begin(); }
+ ValueMap::const_iterator end() const { return values.end(); }
+ ValueMap::const_iterator find(const std::string& s) const { return values.find(s); }
+
+ ValueMap::iterator begin() { return values.begin(); }
+ ValueMap::iterator end() { return values.end(); }
+ ValueMap::iterator find(const std::string& s) { return values.find(s); }
+
+ std::pair <ValueMap::iterator, bool> insert(const ValueMap::value_type&);
+ QPID_COMMON_EXTERN ValueMap::iterator insert(ValueMap::iterator, const ValueMap::value_type&);
+ void clear() { values.clear(); }
+
+ // ### Hack Alert
+
+ ValueMap::iterator getValues() { return values.begin(); }
+
+ private:
+ ValueMap values;
+
+ QPID_COMMON_EXTERN friend std::ostream& operator<<(std::ostream& out, const FieldTable& body);
+};
+
+//class FieldNotFoundException{};
+//class UnknownFieldName : public FieldNotFoundException{};
+//class IncorrectFieldType : public FieldNotFoundException{};
+}
+}
+
+
+#endif
diff --git a/cpp/include/qpid/framing/FieldValue.h b/cpp/include/qpid/framing/FieldValue.h
new file mode 100644
index 0000000000..60a887761f
--- /dev/null
+++ b/cpp/include/qpid/framing/FieldValue.h
@@ -0,0 +1,435 @@
+#ifndef _framing_FieldValue_h
+#define _framing_FieldValue_h
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Exception.h"
+#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/CommonImportExport.h"
+
+#include <iostream>
+#include <memory>
+#include <vector>
+
+#include <assert.h>
+
+namespace qpid {
+namespace framing {
+
+/**
+ * Exception that is the base exception for all field table errors.
+ *
+ * \ingroup clientapi
+ */
+class FieldValueException : public qpid::Exception {};
+
+/**
+ * Exception thrown when we can't perform requested conversion
+ *
+ * \ingroup clientapi
+ */
+struct InvalidConversionException : public FieldValueException {
+ InvalidConversionException() {}
+};
+
+class List;
+
+/**
+ * Value that can appear in an AMQP field table
+ *
+ * \ingroup clientapi
+ */
+class FieldValue {
+ public:
+ /*
+ * Abstract type for content of different types
+ */
+ class Data {
+ public:
+ virtual ~Data() {};
+ virtual uint32_t encodedSize() const = 0;
+ virtual void encode(Buffer& buffer) = 0;
+ virtual void decode(Buffer& buffer) = 0;
+ virtual bool operator==(const Data&) const = 0;
+
+ virtual bool convertsToInt() const { return false; }
+ virtual bool convertsToString() const { return false; }
+ virtual int64_t getInt() const { throw InvalidConversionException();}
+ virtual std::string getString() const { throw InvalidConversionException(); }
+
+ virtual void print(std::ostream& out) const = 0;
+ };
+
+ FieldValue(): data(0) {};
+ // Default assignment operator is fine
+ void setType(uint8_t type);
+ QPID_COMMON_EXTERN uint8_t getType();
+ Data& getData() { return *data; }
+ uint32_t encodedSize() const { return 1 + data->encodedSize(); };
+ bool empty() const { return data.get() == 0; }
+ void encode(Buffer& buffer);
+ void decode(Buffer& buffer);
+ QPID_COMMON_EXTERN bool operator==(const FieldValue&) const;
+ QPID_COMMON_EXTERN bool operator!=(const FieldValue& v) const { return !(*this == v); }
+
+ QPID_COMMON_EXTERN void print(std::ostream& out) const;
+
+ template <typename T> bool convertsTo() const { return false; }
+ template <typename T> T get() const { throw InvalidConversionException(); }
+
+ template <class T, int W> T getIntegerValue() const;
+ template <class T, int W> T getFloatingPointValue() const;
+ template <class T> bool get(T&) const;
+
+ protected:
+ FieldValue(uint8_t t, Data* d): typeOctet(t), data(d) {}
+
+ QPID_COMMON_EXTERN static uint8_t* convertIfRequired(uint8_t* const octets, int width);
+
+ private:
+ uint8_t typeOctet;
+ std::auto_ptr<Data> data;
+
+};
+
+template <>
+inline bool FieldValue::convertsTo<int>() const { return data->convertsToInt(); }
+
+template <>
+inline bool FieldValue::convertsTo<int64_t>() const { return data->convertsToInt(); }
+
+template <>
+inline bool FieldValue::convertsTo<std::string>() const { return data->convertsToString(); }
+
+template <>
+inline int FieldValue::get<int>() const { return data->getInt(); }
+
+template <>
+inline int64_t FieldValue::get<int64_t>() const { return data->getInt(); }
+
+template <>
+inline std::string FieldValue::get<std::string>() const { return data->getString(); }
+
+inline std::ostream& operator<<(std::ostream& out, const FieldValue& v) {
+ v.print(out);
+ return out;
+}
+
+template <int width>
+class FixedWidthValue : public FieldValue::Data {
+ uint8_t octets[width];
+
+ public:
+ FixedWidthValue() {}
+ FixedWidthValue(const uint8_t (&data)[width]) : octets(data) {}
+ FixedWidthValue(const uint8_t* const data)
+ {
+ for (int i = 0; i < width; i++) octets[i] = data[i];
+ }
+ FixedWidthValue(uint64_t v)
+ {
+ for (int i = width; i > 1; --i) {
+ octets[i-1] = (uint8_t) (0xFF & v); v >>= 8;
+ }
+ octets[0] = (uint8_t) (0xFF & v);
+ }
+ uint32_t encodedSize() const { return width; }
+ void encode(Buffer& buffer) { buffer.putRawData(octets, width); }
+ void decode(Buffer& buffer) { buffer.getRawData(octets, width); }
+ bool operator==(const Data& d) const {
+ const FixedWidthValue<width>* rhs = dynamic_cast< const FixedWidthValue<width>* >(&d);
+ if (rhs == 0) return false;
+ else return std::equal(&octets[0], &octets[width], &rhs->octets[0]);
+ }
+
+ bool convertsToInt() const { return true; }
+ int64_t getInt() const
+ {
+ int64_t v = 0;
+ for (int i = 0; i < width-1; ++i) {
+ v |= octets[i]; v <<= 8;
+ }
+ v |= octets[width-1];
+ return v;
+ }
+ uint8_t* rawOctets() { return octets; }
+ uint8_t* rawOctets() const { return octets; }
+
+ void print(std::ostream& o) const { o << "F" << width << ":"; };
+};
+
+template <class T, int W>
+inline T FieldValue::getIntegerValue() const
+{
+ FixedWidthValue<W>* const fwv = dynamic_cast< FixedWidthValue<W>* const>(data.get());
+ if (fwv) {
+ uint8_t* octets = fwv->rawOctets();
+ T v = 0;
+ for (int i = 0; i < W-1; ++i) {
+ v |= octets[i]; v <<= 8;
+ }
+ v |= octets[W-1];
+ return v;
+ } else {
+ throw InvalidConversionException();
+ }
+}
+
+template <class T, int W>
+inline T FieldValue::getFloatingPointValue() const {
+ FixedWidthValue<W>* const fwv = dynamic_cast< FixedWidthValue<W>* const>(data.get());
+ if (fwv) {
+ T value;
+ uint8_t* const octets = convertIfRequired(fwv->rawOctets(), W);
+ uint8_t* const target = reinterpret_cast<uint8_t*>(&value);
+ for (uint i = 0; i < W; ++i) target[i] = octets[i];
+ return value;
+ } else {
+ throw InvalidConversionException();
+ }
+}
+
+template <>
+inline float FieldValue::get<float>() const {
+ return getFloatingPointValue<float, 4>();
+}
+
+template <>
+inline double FieldValue::get<double>() const {
+ return getFloatingPointValue<double, 8>();
+}
+
+template <>
+class FixedWidthValue<0> : public FieldValue::Data {
+ public:
+ // Implicit default constructor is fine
+ uint32_t encodedSize() const { return 0; }
+ void encode(Buffer&) {};
+ void decode(Buffer&) {};
+ bool operator==(const Data& d) const {
+ const FixedWidthValue<0>* rhs = dynamic_cast< const FixedWidthValue<0>* >(&d);
+ return rhs != 0;
+ }
+ void print(std::ostream& o) const { o << "F0"; };
+};
+
+template <int lenwidth>
+class VariableWidthValue : public FieldValue::Data {
+ std::vector<uint8_t> octets;
+
+ public:
+ VariableWidthValue() {}
+ VariableWidthValue(const std::vector<uint8_t>& data) : octets(data) {}
+ VariableWidthValue(const uint8_t* start, const uint8_t* end) : octets(start, end) {}
+ uint32_t encodedSize() const { return lenwidth + octets.size(); }
+ void encode(Buffer& buffer) {
+ buffer.putUInt<lenwidth>(octets.size());
+ if (octets.size() > 0)
+ buffer.putRawData(&octets[0], octets.size());
+ };
+ void decode(Buffer& buffer) {
+ uint32_t len = buffer.getUInt<lenwidth>();
+ octets.resize(len);
+ if (len > 0)
+ buffer.getRawData(&octets[0], len);
+ }
+ bool operator==(const Data& d) const {
+ const VariableWidthValue<lenwidth>* rhs = dynamic_cast< const VariableWidthValue<lenwidth>* >(&d);
+ if (rhs == 0) return false;
+ else return octets==rhs->octets;
+ }
+
+ bool convertsToString() const { return true; }
+ std::string getString() const { return std::string(octets.begin(), octets.end()); }
+
+ void print(std::ostream& o) const { o << "V" << lenwidth << ":" << octets.size() << ":"; };
+};
+
+template <class T>
+class EncodedValue : public FieldValue::Data {
+ T value;
+ public:
+
+ EncodedValue() {}
+ EncodedValue(const T& v) : value(v) {}
+
+ T& getValue() { return value; }
+ const T& getValue() const { return value; }
+
+ uint32_t encodedSize() const { return value.encodedSize(); }
+
+ void encode(Buffer& buffer) {
+ value.encode(buffer);
+ };
+ void decode(Buffer& buffer) {
+ value.decode(buffer);
+ }
+ bool operator==(const Data& d) const {
+ const EncodedValue<T>* rhs = dynamic_cast< const EncodedValue<T>* >(&d);
+ if (rhs == 0) return false;
+ else return value==rhs->value;
+ }
+
+ void print(std::ostream& o) const { o << "[" << value << "]"; };
+};
+
+/**
+ * Accessor that can be used to get values of type FieldTable, Array
+ * and List.
+ */
+template <class T>
+inline bool FieldValue::get(T& t) const
+{
+ const EncodedValue<T>* v = dynamic_cast< EncodedValue<T>* >(data.get());
+ if (v != 0) {
+ t = v->getValue();
+ return true;
+ } else {
+ try {
+ t = get<T>();
+ return true;
+ } catch (const InvalidConversionException&) {
+ return false;
+ }
+ }
+}
+
+class Str8Value : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN Str8Value(const std::string& v);
+};
+
+class Str16Value : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN Str16Value(const std::string& v);
+};
+
+class Struct32Value : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN Struct32Value(const std::string& v);
+};
+
+class FloatValue : public FieldValue
+{
+ public:
+ QPID_COMMON_EXTERN FloatValue(float f);
+};
+class DoubleValue : public FieldValue
+{
+ public:
+ QPID_COMMON_EXTERN DoubleValue(double f);
+};
+
+/*
+ * Basic integer value encodes as signed 32 bit
+ */
+class IntegerValue : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN IntegerValue(int v);
+};
+
+class TimeValue : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN TimeValue(uint64_t v);
+};
+
+class Integer64Value : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN Integer64Value(int64_t v);
+};
+
+class Unsigned64Value : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN Unsigned64Value(uint64_t v);
+};
+
+class FieldTableValue : public FieldValue {
+ public:
+ typedef FieldTable ValueType;
+ QPID_COMMON_EXTERN FieldTableValue(const FieldTable&);
+};
+
+class ArrayValue : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN ArrayValue(const Array&);
+};
+
+class VoidValue : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN VoidValue();
+};
+
+class BoolValue : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN BoolValue(bool);
+};
+
+class Unsigned8Value : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN Unsigned8Value(uint8_t);
+};
+
+class Unsigned16Value : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN Unsigned16Value(uint16_t);
+};
+
+class Unsigned32Value : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN Unsigned32Value(uint32_t);
+};
+
+class Integer8Value : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN Integer8Value(int8_t);
+};
+
+class Integer16Value : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN Integer16Value(int16_t);
+};
+
+typedef IntegerValue Integer32Value;
+
+class ListValue : public FieldValue {
+ public:
+ typedef List ValueType;
+ QPID_COMMON_EXTERN ListValue(const List&);
+};
+
+template <class T>
+bool getEncodedValue(FieldTable::ValuePtr vptr, T& value)
+{
+ if (vptr) {
+ const EncodedValue<T>* ev = dynamic_cast< EncodedValue<T>* >(&(vptr->getData()));
+ if (ev != 0) {
+ value = ev->getValue();
+ return true;
+ }
+ }
+ return false;
+}
+
+}} // qpid::framing
+
+#endif
diff --git a/cpp/include/qpid/framing/List.h b/cpp/include/qpid/framing/List.h
new file mode 100644
index 0000000000..0f17c7884c
--- /dev/null
+++ b/cpp/include/qpid/framing/List.h
@@ -0,0 +1,77 @@
+#ifndef QPID_FRAMING_LIST_H
+#define QPID_FRAMING_LIST_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/CommonImportExport.h"
+#include "qpid/framing/amqp_types.h"
+#include <iostream>
+#include <list>
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace framing {
+
+class Buffer;
+class FieldValue;
+
+/**
+ * Representation of an AMQP 0-10 list
+ */
+class List
+{
+ public:
+ typedef boost::shared_ptr<FieldValue> ValuePtr;
+ typedef std::list<ValuePtr> Values;
+ typedef Values::const_iterator const_iterator;
+ typedef Values::iterator iterator;
+ typedef Values::const_reference const_reference;
+ typedef Values::reference reference;
+
+ QPID_COMMON_EXTERN uint32_t encodedSize() const;
+ QPID_COMMON_EXTERN void encode(Buffer& buffer) const;
+ QPID_COMMON_EXTERN void decode(Buffer& buffer);
+
+ QPID_COMMON_EXTERN bool operator==(const List& other) const;
+
+ // std collection interface.
+ QPID_COMMON_EXTERN const_iterator begin() const { return values.begin(); }
+ QPID_COMMON_EXTERN const_iterator end() const { return values.end(); }
+ QPID_COMMON_EXTERN iterator begin() { return values.begin(); }
+ QPID_COMMON_EXTERN iterator end(){ return values.end(); }
+
+ QPID_COMMON_EXTERN ValuePtr front() const { return values.front(); }
+ QPID_COMMON_EXTERN ValuePtr back() const { return values.back(); }
+ QPID_COMMON_EXTERN size_t size() const { return values.size(); }
+
+ QPID_COMMON_EXTERN iterator insert(iterator i, ValuePtr value) { return values.insert(i, value); }
+ QPID_COMMON_EXTERN void erase(iterator i) { values.erase(i); }
+ QPID_COMMON_EXTERN void push_back(ValuePtr value) { values.insert(end(), value); }
+ QPID_COMMON_EXTERN void pop_back() { values.pop_back(); }
+
+ private:
+ Values values;
+
+ friend QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& out, const List& list);
+};
+}} // namespace qpid::framing
+
+#endif /*!QPID_FRAMING_LIST_H*/
diff --git a/cpp/include/qpid/framing/ProtocolVersion.h b/cpp/include/qpid/framing/ProtocolVersion.h
new file mode 100644
index 0000000000..e7e75d75f6
--- /dev/null
+++ b/cpp/include/qpid/framing/ProtocolVersion.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _ProtocolVersion_
+#define _ProtocolVersion_
+
+#include "qpid/framing/amqp_types.h"
+#include "qpid/CommonImportExport.h"
+
+namespace qpid
+{
+namespace framing
+{
+
+class ProtocolVersion
+{
+private:
+ uint8_t major_;
+ uint8_t minor_;
+
+public:
+ explicit ProtocolVersion(uint8_t _major=0, uint8_t _minor=0)
+ : major_(_major), minor_(_minor) {}
+
+ QPID_COMMON_EXTERN uint8_t getMajor() const { return major_; }
+ QPID_COMMON_EXTERN void setMajor(uint8_t major) { major_ = major; }
+ QPID_COMMON_EXTERN uint8_t getMinor() const { return minor_; }
+ QPID_COMMON_EXTERN void setMinor(uint8_t minor) { minor_ = minor; }
+ QPID_COMMON_EXTERN const std::string toString() const;
+
+ QPID_COMMON_EXTERN ProtocolVersion& operator=(ProtocolVersion p);
+
+ QPID_COMMON_EXTERN bool operator==(ProtocolVersion p) const;
+ QPID_COMMON_EXTERN bool operator!=(ProtocolVersion p) const { return ! (*this == p); }
+};
+
+} // namespace framing
+} // namespace qpid
+
+
+#endif // ifndef _ProtocolVersion_
diff --git a/cpp/include/qpid/framing/SequenceNumber.h b/cpp/include/qpid/framing/SequenceNumber.h
new file mode 100644
index 0000000000..1e53058df8
--- /dev/null
+++ b/cpp/include/qpid/framing/SequenceNumber.h
@@ -0,0 +1,79 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _framing_SequenceNumber_h
+#define _framing_SequenceNumber_h
+
+#include "qpid/framing/amqp_types.h"
+#include <boost/operators.hpp>
+#include <iosfwd>
+#include "qpid/CommonImportExport.h"
+
+namespace qpid {
+namespace framing {
+
+class Buffer;
+
+/**
+ * 4-byte sequence number that 'wraps around'.
+ */
+class SequenceNumber : public
+boost::equality_comparable<
+ SequenceNumber, boost::less_than_comparable<
+ SequenceNumber, boost::incrementable<
+ SequenceNumber, boost::decrementable<SequenceNumber> > > >
+{
+ int32_t value;
+
+ public:
+ SequenceNumber(uint32_t v=0) : value(v) {}
+
+ SequenceNumber& operator++() { ++value; return *this; }
+ SequenceNumber& operator--() { --value; return *this; }
+ bool operator==(const SequenceNumber& other) const { return value == other.value; }
+ bool operator<(const SequenceNumber& other) const { return (value - other.value) < 0; }
+ uint32_t getValue() const { return uint32_t(value); }
+ operator uint32_t() const { return uint32_t(value); }
+
+ void encode(Buffer& buffer) const;
+ void decode(Buffer& buffer);
+ uint32_t encodedSize() const;
+
+ template <class S> void serialize(S& s) { s(value); }
+
+ friend inline int32_t operator-(const SequenceNumber& a, const SequenceNumber& b);
+};
+
+inline int32_t operator-(const SequenceNumber& a, const SequenceNumber& b) {
+ return int32_t(a.value - b.value);
+}
+
+struct Window
+{
+ SequenceNumber hwm;
+ SequenceNumber lwm;
+};
+
+QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& o, const SequenceNumber& n);
+
+}} // namespace qpid::framing
+
+
+#endif
diff --git a/cpp/include/qpid/framing/SequenceSet.h b/cpp/include/qpid/framing/SequenceSet.h
new file mode 100644
index 0000000000..39395e9ad7
--- /dev/null
+++ b/cpp/include/qpid/framing/SequenceSet.h
@@ -0,0 +1,69 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _framing_SequenceSet_h
+#define _framing_SequenceSet_h
+
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/RangeSet.h"
+#include "qpid/CommonImportExport.h"
+
+namespace qpid {
+namespace framing {
+class Buffer;
+
+class SequenceSet : public RangeSet<SequenceNumber> {
+ public:
+ SequenceSet() {}
+ SequenceSet(const RangeSet<SequenceNumber>& r)
+ : RangeSet<SequenceNumber>(r) {}
+ SequenceSet(const SequenceNumber& s) { add(s); }
+ SequenceSet(const SequenceNumber& start, const SequenceNumber finish) { add(start,finish); }
+
+
+ void encode(Buffer& buffer) const;
+ void decode(Buffer& buffer);
+ uint32_t encodedSize() const;
+
+ QPID_COMMON_EXTERN bool contains(const SequenceNumber& s) const;
+ QPID_COMMON_EXTERN void add(const SequenceNumber& s);
+ QPID_COMMON_EXTERN void add(const SequenceNumber& start, const SequenceNumber& finish); // Closed range
+ QPID_COMMON_EXTERN void add(const SequenceSet& set);
+ QPID_COMMON_EXTERN void remove(const SequenceNumber& s);
+ QPID_COMMON_EXTERN void remove(const SequenceNumber& start, const SequenceNumber& finish); // Closed range
+ QPID_COMMON_EXTERN void remove(const SequenceSet& set);
+
+ template <class T> void for_each(T& t) const {
+ for (RangeIterator i = rangesBegin(); i != rangesEnd(); i++)
+ t(i->first(), i->last());
+ }
+
+ template <class T> void for_each(const T& t) const {
+ for (RangeIterator i = rangesBegin(); i != rangesEnd(); i++)
+ t(i->first(), i->last());
+ }
+
+ friend QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, const SequenceSet&);
+};
+
+}} // namespace qpid::framing
+
+
+#endif
diff --git a/cpp/include/qpid/framing/StructHelper.h b/cpp/include/qpid/framing/StructHelper.h
new file mode 100644
index 0000000000..fc9a7909cc
--- /dev/null
+++ b/cpp/include/qpid/framing/StructHelper.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _StructHelper_
+#define _StructHelper_
+
+#include "qpid/Exception.h"
+#include "qpid/CommonImportExport.h"
+#include "qpid/framing/Buffer.h"
+
+#include <stdlib.h> // For alloca
+
+namespace qpid {
+namespace framing {
+
+class StructHelper
+{
+public:
+
+ template <class T> void encode(const T t, std::string& data) {
+ uint32_t size = t.bodySize() + 2/*type*/;
+ data.resize(size);
+ Buffer wbuffer(const_cast<char*>(data.data()), size);
+ wbuffer.putShort(T::TYPE);
+ t.encodeStructBody(wbuffer);
+ }
+
+ template <class T> void decode(T& t, const std::string& data) {
+ Buffer rbuffer(const_cast<char*>(data.data()), data.length());
+ uint16_t type = rbuffer.getShort();
+ if (type == T::TYPE) {
+ t.decodeStructBody(rbuffer);
+ } else {
+ throw Exception("Type code does not match");
+ }
+ }
+};
+
+}}
+#endif
diff --git a/cpp/include/qpid/framing/Uuid.h b/cpp/include/qpid/framing/Uuid.h
new file mode 100644
index 0000000000..2cca6e9dfe
--- /dev/null
+++ b/cpp/include/qpid/framing/Uuid.h
@@ -0,0 +1,90 @@
+#ifndef QPID_FRAMING_UUID_H
+#define QPID_FRAMING_UUID_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/CommonImportExport.h"
+#include "qpid/sys/IntegerTypes.h"
+
+#include <boost/array.hpp>
+
+#include <ostream>
+#include <istream>
+
+namespace qpid {
+namespace framing {
+
+class Buffer;
+
+/**
+ * A UUID is represented as a boost::array of 16 bytes.
+ *
+ * Full value semantics, operators ==, < etc. are provided by
+ * boost::array so Uuid can be the key type in a map etc.
+ *
+ * TODO: change this implementation as it leaks boost into the
+ * client API
+ */
+struct Uuid : public boost::array<uint8_t, 16> {
+ /** If unique is true, generate a unique ID else a null ID. */
+ QPID_COMMON_EXTERN Uuid(bool unique=false);
+
+ /** Copy from 16 bytes of data. */
+ QPID_COMMON_EXTERN Uuid(const uint8_t* data);
+
+ // Default op= and copy ctor are fine.
+ // boost::array gives us ==, < etc.
+
+ /** Copy from 16 bytes of data. */
+ void assign(const uint8_t* data);
+
+ /** Set to a new unique identifier. */
+ QPID_COMMON_EXTERN void generate();
+
+ /** Set to all zeros. */
+ void clear();
+
+ /** Test for null (all zeros). */
+ bool isNull() const;
+ operator bool() const { return !isNull(); }
+ bool operator!() const { return isNull(); }
+
+ QPID_COMMON_EXTERN void encode(framing::Buffer& buf) const;
+ QPID_COMMON_EXTERN void decode(framing::Buffer& buf);
+ QPID_COMMON_EXTERN uint32_t encodedSize() const { return size(); }
+
+ /** String value in format 1b4e28ba-2fa1-11d2-883f-b9a761bde3fb. */
+ QPID_COMMON_EXTERN std::string str() const;
+
+ template <class S> void serialize(S& s) {
+ s.raw(begin(), size());
+ }
+};
+
+/** Print in format 1b4e28ba-2fa1-11d2-883f-b9a761bde3fb. */
+QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, Uuid);
+
+/** Read from format 1b4e28ba-2fa1-11d2-883f-b9a761bde3fb. */
+QPID_COMMON_EXTERN std::istream& operator>>(std::istream&, Uuid&);
+
+}} // namespace qpid::framing
+
+
+
+#endif /*!QPID_FRAMING_UUID_H*/
diff --git a/cpp/include/qpid/framing/amqp_types.h b/cpp/include/qpid/framing/amqp_types.h
new file mode 100644
index 0000000000..d9088b7a12
--- /dev/null
+++ b/cpp/include/qpid/framing/amqp_types.h
@@ -0,0 +1,66 @@
+#ifndef AMQP_TYPES_H
+#define AMQP_TYPES_H
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/** \file
+ * Definitions and forward declarations of all types used
+ * in AMQP messages.
+ */
+
+#include "qpid/sys/IntegerTypes.h"
+#include <string>
+
+namespace qpid {
+namespace framing {
+
+using std::string;
+typedef uint8_t FrameType;
+typedef uint16_t ChannelId;
+typedef uint32_t BatchOffset;
+typedef uint8_t ClassId;
+typedef uint8_t MethodId;
+typedef uint16_t ReplyCode;
+
+// Types represented by classes.
+class Content;
+class FieldTable;
+class SequenceNumberSet;
+struct Uuid;
+
+// Useful constants
+
+/** Maximum channel ID used by broker. Reserve high bit for internal use.*/
+const ChannelId CHANNEL_MAX=(ChannelId(~1))>>1;
+const ChannelId CHANNEL_HIGH_BIT= ChannelId(~CHANNEL_MAX);
+
+// Forward declare class types
+class FramingContent;
+class FieldTable;
+class SequenceNumberSet;
+class SequenceSet;
+struct Uuid;
+
+// Enum types
+enum DeliveryMode { TRANSIENT = 1, PERSISTENT = 2};
+
+}} // namespace qpid::framing
+#endif
diff --git a/cpp/include/qpid/framing/amqp_types_full.h b/cpp/include/qpid/framing/amqp_types_full.h
new file mode 100644
index 0000000000..c5d84dedea
--- /dev/null
+++ b/cpp/include/qpid/framing/amqp_types_full.h
@@ -0,0 +1,38 @@
+#ifndef _framing_amqp_types_decl_h
+#define _framing_amqp_types_decl_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/** \file
+ * Definitions and full declarations of all types used
+ * in AMQP messages.
+ *
+ * It's better to include amqp_types.h in another header instead of this file
+ * unless the header actually needs the full declarations. Including
+ * full declarations when forward declarations would increase compile
+ * times.
+ */
+
+#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/Array.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/SequenceSet.h"
+#include "qpid/framing/Uuid.h"
+
+#endif /*!_framing_amqp_types_decl_h*/
diff --git a/cpp/include/qpid/log/Logger.h b/cpp/include/qpid/log/Logger.h
new file mode 100644
index 0000000000..d7da1f077a
--- /dev/null
+++ b/cpp/include/qpid/log/Logger.h
@@ -0,0 +1,114 @@
+#ifndef QPID_LOG_LOGGER_H
+#define QPID_LOG_LOGGER_H
+
+/*
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/log/Selector.h"
+#include "qpid/log/Options.h"
+#include "qpid/sys/Mutex.h"
+#include <boost/ptr_container/ptr_vector.hpp>
+#include <boost/noncopyable.hpp>
+#include <set>
+#include "qpid/CommonImportExport.h"
+
+namespace qpid {
+namespace log {
+
+/**
+ * Central logging agent.
+ *
+ * Thread safe, singleton.
+ *
+ * The Logger provides all needed functionality for selecting and
+ * formatting logging output. The actual outputting of log records
+ * is handled by Logger::Output-derived classes instantiated by the
+ * platform's sink-related options.
+ */
+class Logger : private boost::noncopyable {
+ public:
+ /** Flags indicating what to include in the log output */
+ enum FormatFlag { FILE=1, LINE=2, FUNCTION=4, LEVEL=8, TIME=16, THREAD=32};
+
+ /**
+ * Logging output sink.
+ *
+ * The Output sink provides an interface to direct logging output to.
+ * Logging sinks are primarily platform-specific as provided for on
+ * each platform.
+ *
+ * Implementations of Output must be thread safe.
+ */
+ class Output {
+ public:
+ QPID_COMMON_EXTERN Output();
+ QPID_COMMON_EXTERN virtual ~Output();
+ /** Receives the statemnt of origin and formatted message to log. */
+ virtual void log(const Statement&, const std::string&) =0;
+ };
+
+ QPID_COMMON_EXTERN static Logger& instance();
+
+ QPID_COMMON_EXTERN Logger();
+ QPID_COMMON_EXTERN ~Logger();
+
+ /** Select the messages to be logged. */
+ QPID_COMMON_EXTERN void select(const Selector& s);
+
+ /** Set the formatting flags, bitwise OR of FormatFlag values. */
+ QPID_COMMON_EXTERN void format(int formatFlags);
+
+ /** Set format flags from options object.
+ *@returns computed flags.
+ */
+ QPID_COMMON_EXTERN int format(const Options&);
+
+ /** Configure logger from Options */
+ QPID_COMMON_EXTERN void configure(const Options& o);
+
+ /** Add a statement. */
+ QPID_COMMON_EXTERN void add(Statement& s);
+
+ /** Log a message. */
+ QPID_COMMON_EXTERN void log(const Statement&, const std::string&);
+
+ /** Add an output destination for messages */
+ QPID_COMMON_EXTERN void output(std::auto_ptr<Output> out);
+
+ /** Set a prefix for all messages */
+ QPID_COMMON_EXTERN void setPrefix(const std::string& prefix);
+
+ /** Reset the logger. */
+ QPID_COMMON_EXTERN void clear();
+
+ /** Get the options used to configure the logger. */
+ QPID_COMMON_EXTERN const Options& getOptions() const { return options; }
+
+
+ private:
+ typedef boost::ptr_vector<Output> Outputs;
+ typedef std::set<Statement*> Statements;
+
+ sys::Mutex lock;
+ inline void enable_unlocked(Statement* s);
+
+ Statements statements;
+ Outputs outputs;
+ Selector selector;
+ int flags;
+ std::string prefix;
+ Options options;
+};
+
+}} // namespace qpid::log
+
+
+#endif /*!QPID_LOG_LOGGER_H*/
diff --git a/cpp/include/qpid/log/Options.h b/cpp/include/qpid/log/Options.h
new file mode 100644
index 0000000000..bbc47b47d3
--- /dev/null
+++ b/cpp/include/qpid/log/Options.h
@@ -0,0 +1,50 @@
+#ifndef QPID_LOG_OPTIONS_H
+#define QPID_LOG_OPTIONS_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "qpid/Options.h"
+#include "qpid/CommonImportExport.h"
+#include "qpid/log/SinkOptions.h"
+#include <iosfwd>
+#include <memory>
+
+namespace qpid {
+namespace log {
+
+/** Logging options for config parser. */
+struct Options : public qpid::Options {
+ /** Pass argv[0] for use in syslog output */
+ QPID_COMMON_EXTERN Options(const std::string& argv0_=std::string(),
+ const std::string& name_="Logging options");
+ QPID_COMMON_EXTERN Options(const Options &);
+
+ QPID_COMMON_EXTERN Options& operator=(const Options&);
+
+ std::string argv0;
+ std::string name;
+ std::vector<std::string> selectors;
+ bool time, level, thread, source, function;
+ bool trace;
+ std::string prefix;
+ std::auto_ptr<SinkOptions> sinkOptions;
+};
+
+}} // namespace qpid::log
+
+#endif /*!QPID_LOG_OPTIONS_H*/
diff --git a/cpp/include/qpid/log/Selector.h b/cpp/include/qpid/log/Selector.h
new file mode 100644
index 0000000000..061152d7e2
--- /dev/null
+++ b/cpp/include/qpid/log/Selector.h
@@ -0,0 +1,71 @@
+#ifndef SELECTOR_H
+#define SELECTOR_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/log/Statement.h"
+#include "qpid/CommonImportExport.h"
+#include <vector>
+
+namespace qpid {
+namespace log {
+struct Options;
+
+/**
+ * A selector identifies the set of log messages to enable.
+ *
+ * Thread object unsafe, pass-by-value type.
+ */
+class Selector {
+ public:
+ /** Empty selector selects nothing */
+ Selector() {}
+
+ /** Set selector from Options */
+ QPID_COMMON_EXTERN Selector(const Options&);
+
+ /** Equavlient to: Selector s; s.enable(l, s) */
+ Selector(Level l, const std::string& s=std::string()) {
+ enable(l,s);
+ }
+
+ Selector(const std::string& enableStr) { enable(enableStr); }
+ /**
+ * Enable messages with level in levels where the file
+ * name contains substring. Empty string matches all.
+ */
+ void enable(Level level, const std::string& substring=std::string()) {
+ substrings[level].push_back(substring);
+ }
+
+ /** Enable based on a 'level[+]:file' string */
+ QPID_COMMON_EXTERN void enable(const std::string& enableStr);
+
+ /** True if level is enabled for file. */
+ QPID_COMMON_EXTERN bool isEnabled(Level level, const char* function);
+
+ private:
+ std::vector<std::string> substrings[LevelTraits::COUNT];
+};
+
+
+}} // namespace qpid::log
+
+
+#endif /*!SELECTOR_H*/
diff --git a/cpp/include/qpid/log/SinkOptions.h b/cpp/include/qpid/log/SinkOptions.h
new file mode 100644
index 0000000000..7ec2cfbc17
--- /dev/null
+++ b/cpp/include/qpid/log/SinkOptions.h
@@ -0,0 +1,64 @@
+#ifndef QPID_LOG_SINKOPTIONS_H
+#define QPID_LOG_SINKOPTIONS_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/Options.h"
+#include <string>
+
+namespace qpid {
+namespace log {
+
+class Logger;
+
+/**
+ * Logging sink options.
+ *
+ * Most logging sink options will be platform-specific, even if some are
+ * duplicated. The range of platforms to which this code may be ported
+ * can't be assumed to all have C++ iostreams or files. Thus, this class
+ * is primarily for implementing in a platform-specific way.
+ */
+struct SinkOptions : public qpid::Options {
+
+ // Create a platform's SinkOptions. Pass argv0 as the program name,
+ // useful for syslog-type logging.
+ static SinkOptions *create(const std::string& argv0=std::string());
+
+ SinkOptions(const std::string& name="Logging sink options")
+ : qpid::Options(name)
+ {}
+ virtual ~SinkOptions() {}
+
+ virtual SinkOptions& operator=(const SinkOptions&) = 0;
+
+ // This allows the caller to indicate that there's no normal outputs
+ // available. For example, when running as a daemon. In these cases, the
+ // platform's "syslog"-type output should replace the default stderr
+ // unless some other sink has been selected.
+ virtual void detached(void) = 0;
+
+ // The Logger acting on these options calls setup() to request any
+ // Sinks be set up and fed back to the logger.
+ virtual void setup(Logger *logger) = 0;
+};
+
+}} // namespace qpid::log
+
+#endif /*!QPID_LOG_OPTIONS_H*/
diff --git a/cpp/include/qpid/log/Statement.h b/cpp/include/qpid/log/Statement.h
new file mode 100644
index 0000000000..8f73175630
--- /dev/null
+++ b/cpp/include/qpid/log/Statement.h
@@ -0,0 +1,121 @@
+#ifndef STATEMENT_H
+#define STATEMENT_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/Msg.h"
+#include "qpid/CommonImportExport.h"
+#include <boost/current_function.hpp>
+
+namespace qpid {
+namespace log {
+
+/** Debugging severity levels
+ * - trace: High-volume debugging messages.
+ * - debug: Debugging messages.
+ * - info: Informational messages.
+ * - notice: Normal but significant condition.
+ * - warning: Warn of a possible problem.
+ * - error: A definite error has occured.
+ * - critical: System in danger of severe failure.
+ */
+enum Level { trace, debug, info, notice, warning, error, critical };
+struct LevelTraits {
+ static const int COUNT=critical+1;
+
+ /** Get level from string name.
+ *@exception if name invalid.
+ */
+ static Level level(const char* name);
+
+ /** Get level from string name.
+ *@exception if name invalid.
+ */
+ static Level level(const std::string& name) {
+ return level(name.c_str());
+ }
+
+ /** String name of level */
+ static const char* name(Level);
+};
+
+/** POD struct representing a logging statement in source code. */
+struct Statement {
+ bool enabled;
+ const char* file;
+ int line;
+ const char* function;
+ Level level;
+
+ QPID_COMMON_EXTERN void log(const std::string& message);
+
+ struct Initializer {
+ QPID_COMMON_EXTERN Initializer(Statement& s);
+ Statement& statement;
+ };
+};
+
+///@internal static initializer for a Statement.
+#define QPID_LOG_STATEMENT_INIT(level) \
+ { 0, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, (::qpid::log::level) }
+
+/**
+ * Like QPID_LOG but computes an additional boolean test expression
+ * to determine if the message should be logged. Evaluation of both
+ * the test and message expressions occurs only if the requested log level
+ * is enabled.
+ *@param LEVEL severity Level for message, should be one of:
+ * debug, info, notice, warning, error, critical. NB no qpid::log:: prefix.
+ *@param TEST message is logged only if expression TEST evaluates to true.
+ *@param MESSAGE any object with an @eostream operator<<, or a sequence
+ * like of ostreamable objects separated by @e<<.
+ */
+#define QPID_LOG_IF(LEVEL, TEST, MESSAGE) \
+ do { \
+ using ::qpid::log::Statement; \
+ static Statement stmt_= QPID_LOG_STATEMENT_INIT(LEVEL); \
+ static Statement::Initializer init_(stmt_); \
+ if (stmt_.enabled && (TEST)) \
+ stmt_.log(::qpid::Msg() << MESSAGE); \
+ } while(0)
+
+/**
+ * Macro for log statements. Example of use:
+ * @code
+ * QPID_LOG(debug, "There are " << foocount << " foos in the bar.");
+ * QPID_LOG(error, boost::format("Dohickey %s exploded") % dohicky.name());
+ * @endcode
+ *
+ * You can subscribe to log messages by level, by component, by filename
+ * or a combination @see Configuration.
+
+ *@param LEVEL severity Level for message, should be one of:
+ * debug, info, notice, warning, error, critical. NB no qpid::log:: prefix.
+ *@param MESSAGE any object with an @eostream operator<<, or a sequence
+ * like of ostreamable objects separated by @e<<.
+ */
+#define QPID_LOG(LEVEL, MESSAGE) QPID_LOG_IF(LEVEL, true, MESSAGE);
+
+}} // namespace qpid::log
+
+
+
+
+#endif /*!STATEMENT_H*/
+
diff --git a/cpp/include/qpid/management/Args.h b/cpp/include/qpid/management/Args.h
new file mode 100644
index 0000000000..5d1cb7e01d
--- /dev/null
+++ b/cpp/include/qpid/management/Args.h
@@ -0,0 +1,44 @@
+#ifndef _Args_
+#define _Args_
+
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+
+namespace qpid {
+namespace management {
+
+class Args
+{
+ public:
+
+ virtual ~Args (void) = 0;
+
+};
+
+inline Args::~Args (void) {}
+
+class ArgsNone : public Args
+{
+};
+
+}}
+
+
+#endif /*!_Args_*/
diff --git a/cpp/include/qpid/management/Manageable.h b/cpp/include/qpid/management/Manageable.h
new file mode 100644
index 0000000000..7a72cc1592
--- /dev/null
+++ b/cpp/include/qpid/management/Manageable.h
@@ -0,0 +1,72 @@
+#ifndef _Manageable_
+#define _Manageable_
+
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES 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/management/ManagementObject.h"
+#include "qpid/management/Args.h"
+#include <string>
+#include "qpid/CommonImportExport.h"
+
+namespace qpid {
+namespace management {
+
+class QPID_COMMON_EXTERN Manageable
+{
+ public:
+
+ virtual ~Manageable(void) = 0;
+
+ // status_t is a type used to pass completion status from the method handler.
+ //
+ typedef uint32_t status_t;
+ static std::string StatusText(status_t status, std::string text = std::string());
+
+ static const status_t STATUS_OK = 0;
+ static const status_t STATUS_UNKNOWN_OBJECT = 1;
+ static const status_t STATUS_UNKNOWN_METHOD = 2;
+ static const status_t STATUS_NOT_IMPLEMENTED = 3;
+ static const status_t STATUS_PARAMETER_INVALID = 4;
+ static const status_t STATUS_FEATURE_NOT_IMPLEMENTED = 5;
+ static const status_t STATUS_FORBIDDEN = 6;
+ static const status_t STATUS_EXCEPTION = 7;
+ static const status_t STATUS_USER = 0x00010000;
+
+ // Every "Manageable" object must hold a reference to exactly one
+ // management object. This object is always of a class derived from
+ // the pure-virtual "ManagementObject".
+ //
+ // This accessor function returns a pointer to the management object.
+ //
+ virtual ManagementObject* GetManagementObject(void) const = 0;
+
+ // Every "Manageable" object must implement ManagementMethod. This
+ // function is called when a remote management client invokes a method
+ // on this object. The input and output arguments are specific to the
+ // method being called and must be down-cast to the appropriate sub class
+ // before use.
+ virtual status_t ManagementMethod(uint32_t methodId, Args& args, std::string& text);
+};
+
+inline Manageable::~Manageable(void) {}
+
+}}
+
+#endif /*!_Manageable_*/
diff --git a/cpp/include/qpid/management/ManagementEvent.h b/cpp/include/qpid/management/ManagementEvent.h
new file mode 100644
index 0000000000..01b9ae49ec
--- /dev/null
+++ b/cpp/include/qpid/management/ManagementEvent.h
@@ -0,0 +1,49 @@
+#ifndef _ManagementEvent_
+#define _ManagementEvent_
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/management/ManagementObject.h"
+#include <qpid/framing/Buffer.h>
+#include <string>
+
+namespace qpid {
+namespace management {
+
+class ManagementAgent;
+
+class ManagementEvent : public ManagementItem {
+public:
+ typedef void (*writeSchemaCall_t)(qpid::framing::Buffer&);
+ virtual ~ManagementEvent() {}
+
+ virtual writeSchemaCall_t getWriteSchemaCall(void) = 0;
+ virtual std::string& getEventName() const = 0;
+ virtual std::string& getPackageName() const = 0;
+ virtual uint8_t* getMd5Sum() const = 0;
+ virtual uint8_t getSeverity() const = 0;
+ virtual void encode(qpid::framing::Buffer&) const = 0;
+};
+
+}}
+
+#endif /*!_ManagementEvent_*/
diff --git a/cpp/include/qpid/management/ManagementObject.h b/cpp/include/qpid/management/ManagementObject.h
new file mode 100644
index 0000000000..d0a443d6cb
--- /dev/null
+++ b/cpp/include/qpid/management/ManagementObject.h
@@ -0,0 +1,187 @@
+#ifndef _ManagementObject_
+#define _ManagementObject_
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/sys/Time.h"
+#include "qpid/sys/Mutex.h"
+#include <qpid/framing/Buffer.h>
+#include "qpid/CommonImportExport.h"
+#include <map>
+
+namespace qpid {
+namespace management {
+
+class Manageable;
+class ObjectId;
+
+
+class AgentAttachment {
+ friend class ObjectId;
+private:
+ uint64_t first;
+public:
+ AgentAttachment() : first(0) {}
+ QPID_COMMON_EXTERN void setBanks(uint32_t broker, uint32_t bank);
+ uint64_t getFirst() const { return first; }
+};
+
+
+class ObjectId {
+protected:
+ const AgentAttachment* agent;
+ uint64_t first;
+ uint64_t second;
+ void fromString(const std::string&);
+public:
+ QPID_COMMON_EXTERN ObjectId() : agent(0), first(0), second(0) {}
+ QPID_COMMON_EXTERN ObjectId(framing::Buffer& buf) : agent(0) { decode(buf); }
+ QPID_COMMON_EXTERN ObjectId(uint8_t flags, uint16_t seq, uint32_t broker, uint32_t bank, uint64_t object);
+ QPID_COMMON_EXTERN ObjectId(AgentAttachment* _agent, uint8_t flags, uint16_t seq, uint64_t object);
+ QPID_COMMON_EXTERN ObjectId(std::istream&);
+ QPID_COMMON_EXTERN ObjectId(const std::string&);
+ QPID_COMMON_EXTERN bool operator==(const ObjectId &other) const;
+ QPID_COMMON_EXTERN bool operator<(const ObjectId &other) const;
+ QPID_COMMON_EXTERN void encode(framing::Buffer& buffer);
+ QPID_COMMON_EXTERN void decode(framing::Buffer& buffer);
+ friend QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, const ObjectId&);
+};
+
+class ManagementItem {
+public:
+ static const uint8_t TYPE_U8 = 1;
+ static const uint8_t TYPE_U16 = 2;
+ static const uint8_t TYPE_U32 = 3;
+ static const uint8_t TYPE_U64 = 4;
+ static const uint8_t TYPE_SSTR = 6;
+ static const uint8_t TYPE_LSTR = 7;
+ static const uint8_t TYPE_ABSTIME = 8;
+ static const uint8_t TYPE_DELTATIME = 9;
+ static const uint8_t TYPE_REF = 10;
+ static const uint8_t TYPE_BOOL = 11;
+ static const uint8_t TYPE_FLOAT = 12;
+ static const uint8_t TYPE_DOUBLE = 13;
+ static const uint8_t TYPE_UUID = 14;
+ static const uint8_t TYPE_FTABLE = 15;
+ static const uint8_t TYPE_S8 = 16;
+ static const uint8_t TYPE_S16 = 17;
+ static const uint8_t TYPE_S32 = 18;
+ static const uint8_t TYPE_S64 = 19;
+
+ static const uint8_t ACCESS_RC = 1;
+ static const uint8_t ACCESS_RW = 2;
+ static const uint8_t ACCESS_RO = 3;
+
+ static const uint8_t DIR_I = 1;
+ static const uint8_t DIR_O = 2;
+ static const uint8_t DIR_IO = 3;
+
+ static const uint8_t FLAG_CONFIG = 0x01;
+ static const uint8_t FLAG_INDEX = 0x02;
+ static const uint8_t FLAG_END = 0x80;
+
+ const static uint8_t CLASS_KIND_TABLE = 1;
+ const static uint8_t CLASS_KIND_EVENT = 2;
+
+
+
+public:
+ virtual ~ManagementItem() {}
+};
+
+class ManagementObject : public ManagementItem
+{
+protected:
+
+ uint64_t createTime;
+ uint64_t destroyTime;
+ uint64_t updateTime;
+ ObjectId objectId;
+ bool configChanged;
+ bool instChanged;
+ bool deleted;
+ Manageable* coreObject;
+ sys::Mutex accessLock;
+ uint32_t flags;
+
+ static int nextThreadIndex;
+ bool forcePublish;
+
+ QPID_COMMON_EXTERN int getThreadIndex();
+ QPID_COMMON_EXTERN void writeTimestamps(qpid::framing::Buffer& buf);
+
+ public:
+ QPID_COMMON_EXTERN static int maxThreads;
+ typedef void (*writeSchemaCall_t) (qpid::framing::Buffer&);
+
+ ManagementObject(Manageable* _core) :
+ createTime(uint64_t(qpid::sys::Duration(qpid::sys::now()))),
+ destroyTime(0), updateTime(createTime), configChanged(true),
+ instChanged(true), deleted(false),
+ coreObject(_core), forcePublish(false) {}
+ virtual ~ManagementObject() {}
+
+ virtual writeSchemaCall_t getWriteSchemaCall() = 0;
+ virtual void writeProperties(qpid::framing::Buffer& buf) = 0;
+ virtual void writeStatistics(qpid::framing::Buffer& buf,
+ bool skipHeaders = false) = 0;
+ virtual void doMethod(std::string& methodName,
+ qpid::framing::Buffer& inBuf,
+ qpid::framing::Buffer& outBuf) = 0;
+ QPID_COMMON_EXTERN virtual void setReference(ObjectId objectId);
+
+ virtual std::string& getClassName() const = 0;
+ virtual std::string& getPackageName() const = 0;
+ virtual uint8_t* getMd5Sum() const = 0;
+
+ void setObjectId(ObjectId oid) { objectId = oid; }
+ ObjectId getObjectId() { return objectId; }
+ inline bool getConfigChanged() { return configChanged; }
+ virtual bool getInstChanged() { return instChanged; }
+ virtual bool hasInst() { return true; }
+ inline void setForcePublish(bool f) { forcePublish = f; }
+ inline bool getForcePublish() { return forcePublish; }
+ inline void setUpdateTime() { updateTime = (uint64_t(sys::Duration(sys::now()))); }
+
+ inline void resourceDestroy() {
+ destroyTime = uint64_t (qpid::sys::Duration(qpid::sys::now()));
+ deleted = true;
+ }
+ inline bool isDeleted() { return deleted; }
+ inline void setFlags(uint32_t f) { flags = f; }
+ inline uint32_t getFlags() { return flags; }
+ bool isSameClass(ManagementObject& other) {
+ for (int idx = 0; idx < 16; idx++)
+ if (other.getMd5Sum()[idx] != getMd5Sum()[idx])
+ return false;
+ return other.getClassName() == getClassName() &&
+ other.getPackageName() == getPackageName();
+ }
+};
+
+typedef std::map<ObjectId, ManagementObject*> ManagementObjectMap;
+
+}}
+
+
+
+#endif /*!_ManagementObject_*/
diff --git a/cpp/include/qpid/messaging/Address.h b/cpp/include/qpid/messaging/Address.h
new file mode 100644
index 0000000000..538cb6507c
--- /dev/null
+++ b/cpp/include/qpid/messaging/Address.h
@@ -0,0 +1,176 @@
+#ifndef QPID_MESSAGING_ADDRESS_H
+#define QPID_MESSAGING_ADDRESS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include "qpid/Exception.h"
+#include "qpid/messaging/Variant.h"
+#include "qpid/client/ClientImportExport.h"
+#include <ostream>
+
+namespace qpid {
+namespace messaging {
+
+struct InvalidAddress : public qpid::Exception
+{
+ InvalidAddress(const std::string& msg);
+};
+
+struct MalformedAddress : public qpid::Exception
+{
+ MalformedAddress(const std::string& msg);
+};
+
+class AddressImpl;
+
+/**
+ * Represents an address to which messages can be sent and from which
+ * messages can be received. Often a simple name is sufficient for
+ * this, however this can be augmented with a subject pattern and
+ * options.
+ *
+ * All parts of an address can be specified in a string of the
+ * following form:
+ *
+ * &lt;address&gt; [ / &lt;subject&gt; ] ; [ { &lt;key&gt; : &lt;value&gt; , ... } ]
+ *
+ * Here the &lt;address&gt; is a simple name for the addressed
+ * entity and &lt;subject&gt; is a subject or subject pattern for
+ * messages sent to or received from this address. The options are
+ * specified as a series of key value pairs enclosed in curly brackets
+ * (denoting a map). Values can be nested maps, or lists (which are
+ * denoted as a comma separated list of values inside square brackets,
+ * e.g. [a, b, c]).
+ *
+ * The currently supported options are as follows:
+ *
+ * <table border=0>
+ *
+ * <tr valign=top><td>create</td><td>Indicate whether the address should be
+ * automatically created or not. Can be one of <i>always</i>,
+ * <i>never</i>, <i>sender</i> or <i>receiver</i>. The properties of
+ * the node to be created can be specified via the node-properties
+ * option (see below).</td></tr>
+ *
+ * <tr valign=top><td>assert</td><td>Indicate whether or not to assert any specified
+ * node-properties match the address. Can be one of <i>always</i>,
+ * <i>never</i>, <i>sender</i> or <i>receiver</i>.</td></tr>
+ *
+ * <tr valign=top><td>delete</td><td>Indicate whether or not to delete the addressed
+ * nide when a sender or receiver is cancelled. Can be one of <i>always</i>,
+ * <i>never</i>, <i>sender</i> or <i>receiver</i>.</td></tr>
+ *
+ * <tr valign=top><td>node-properties</td><td>A nested map of properties of the addressed
+ * entity or 'node'. These can be used when automatically creating it,
+ * or to assert certain properties.
+ *
+ * The valid node-properties are:
+ * <ul>
+ * <li>type - queue or topic</li>
+ *
+ * <li>durable - true or false</li>
+ *
+ * <li>x-properties - a nested map that can contain implementation or
+ * protocol specifiec extedned properties. For the amqp 0-10 mapping,
+ * the fields in queue- or exchange- declare can be specified in here;
+ * anything that is not recognised as one of those will be passed
+ * through in the arguments field.,/li>
+ * </ul>
+ * </td></tr>
+ *
+ * </table>
+ *
+ * For receivers there are some further options of interest:
+ *
+ * <table border=0 valign=top>
+ *
+ * <tr valign=top><td>no-local</td><td>(only relevant for topics at present) specifies that the
+ * receiver does not want to receiver messages published to the topic
+ * that originate from a sender on the same connection</td></tr>
+ *
+ * <tr valign=top><td>browse</td><td>(only relevant for queues) specifies that the receiver
+ * does not wish to consume the messages, but merely browse them</td></tr>
+ *
+ * <tr valign=top><td>durable</td><td>(only relevant for topics at present) specifies that a
+ * durable subscription is required</td></tr>
+ *
+ * <tr valign=top><td>reliability</td><td>indicates the level of reliability that the receiver
+ * expects. Can be one of unreliable, at-most-once, at-least-once or
+ * exactly-once (the latter is not yet correctly supported).</td></tr>
+ *
+ * <tr valign=top><td>filter</td><td>(only relevant for topics at present) allows bindings to
+ * be created for the queue that match the given criteris (or list of
+ * criteria).</td></tr>
+ *
+ * <tr valign=top><td>x-properties</td><td>allows protocol or implementation specific options
+ * to be specified for a receiver; this is a nested map and currently
+ * the implementation only recognises two specific nested properties
+ * within it (all others are passed through in the arguments of the
+ * message-subscribe command):
+ *
+ * <ul>
+ * <li>exclusive, which requests an exclusive subscription and
+ * is only relevant for queues</li>
+ *
+ * <li>x-queue-arguments, which ais only relevant for topics and
+ * allows arguments to the queue-declare for the subscription
+ * queue to be specified</li>
+ * </ul>
+ * </td></tr>
+ * </table>
+ */
+class Address
+{
+ public:
+ QPID_CLIENT_EXTERN Address();
+ QPID_CLIENT_EXTERN Address(const std::string& address);
+ QPID_CLIENT_EXTERN Address(const std::string& name, const std::string& subject,
+ const Variant::Map& options, const std::string& type = "");
+ QPID_CLIENT_EXTERN Address(const Address& address);
+ QPID_CLIENT_EXTERN ~Address();
+ QPID_CLIENT_EXTERN Address& operator=(const Address&);
+ QPID_CLIENT_EXTERN const std::string& getName() const;
+ QPID_CLIENT_EXTERN void setName(const std::string&);
+ QPID_CLIENT_EXTERN const std::string& getSubject() const;
+ QPID_CLIENT_EXTERN void setSubject(const std::string&);
+ QPID_CLIENT_EXTERN bool hasSubject() const;
+ QPID_CLIENT_EXTERN const Variant::Map& getOptions() const;
+ QPID_CLIENT_EXTERN Variant::Map& getOptions();
+ QPID_CLIENT_EXTERN void setOptions(const Variant::Map&);
+
+ QPID_CLIENT_EXTERN std::string getType() const;
+ QPID_CLIENT_EXTERN void setType(const std::string&);
+
+ QPID_CLIENT_EXTERN const Variant& getOption(const std::string& key) const;
+
+ QPID_CLIENT_EXTERN std::string toStr() const;
+ QPID_CLIENT_EXTERN operator bool() const;
+ QPID_CLIENT_EXTERN bool operator !() const;
+ private:
+ AddressImpl* impl;
+};
+
+QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const Address& address);
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_ADDRESS_H*/
diff --git a/cpp/include/qpid/messaging/Codec.h b/cpp/include/qpid/messaging/Codec.h
new file mode 100644
index 0000000000..bacec5c786
--- /dev/null
+++ b/cpp/include/qpid/messaging/Codec.h
@@ -0,0 +1,44 @@
+#ifndef QPID_MESSAGING_CODEC_H
+#define QPID_MESSAGING_CODEC_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include "qpid/client/ClientImportExport.h"
+
+namespace qpid {
+namespace messaging {
+
+class Variant;
+/**
+ *
+ */
+class Codec
+{
+ public:
+ QPID_CLIENT_EXTERN virtual ~Codec() {}
+ virtual void encode(const Variant&, std::string&) = 0;
+ virtual void decode(const std::string&, Variant&) = 0;
+ private:
+};
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_CODEC_H*/
diff --git a/cpp/include/qpid/messaging/Connection.h b/cpp/include/qpid/messaging/Connection.h
new file mode 100644
index 0000000000..5c5246ff82
--- /dev/null
+++ b/cpp/include/qpid/messaging/Connection.h
@@ -0,0 +1,105 @@
+#ifndef QPID_MESSAGING_CONNECTION_H
+#define QPID_MESSAGING_CONNECTION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include "qpid/client/ClientImportExport.h"
+#include "qpid/client/Handle.h"
+#include "qpid/messaging/Variant.h"
+
+namespace qpid {
+namespace client {
+
+template <class> class PrivateImplRef;
+
+}
+
+namespace messaging {
+
+class ConnectionImpl;
+class Session;
+
+class Connection : public qpid::client::Handle<ConnectionImpl>
+{
+ public:
+ /**
+ * Current implementation supports the following options:
+ *
+ * username
+ * password
+ * heartbeat
+ * tcp-nodelay
+ * sasl-mechanism
+ * sasl-min-ssf
+ * sasl-max-ssf
+ *
+ * (note also bounds, locale, max-channels and max-framesize, but not sure whether those should be docuemented here)
+ *
+ * Retry behaviour can be controlled through the following options:
+ *
+ * reconnection-timeout - determines how long it will try to
+ * reconnect for -1 means forever, 0
+ * means don't try to reconnect
+ * min-retry-interval
+ * max-retry-interval
+ *
+ * The retry-interval is the time that the client waits for
+ * after a failed attempt to reconnect before retrying. It
+ * starts at the value of the min-retry-interval and is
+ * doubled every failure until the value of max-retry-interval
+ * is reached.
+ *
+ *
+ */
+ static QPID_CLIENT_EXTERN Connection open(const std::string& url, const Variant::Map& options = Variant::Map());
+
+ QPID_CLIENT_EXTERN Connection(ConnectionImpl* impl = 0);
+ QPID_CLIENT_EXTERN Connection(const Connection&);
+ QPID_CLIENT_EXTERN ~Connection();
+ QPID_CLIENT_EXTERN Connection& operator=(const Connection&);
+ QPID_CLIENT_EXTERN void close();
+ QPID_CLIENT_EXTERN Session newSession(bool transactional, const std::string& name = std::string());
+ QPID_CLIENT_EXTERN Session newSession(const std::string& name = std::string());
+ QPID_CLIENT_EXTERN Session newSession(const char* name);
+
+ QPID_CLIENT_EXTERN Session getSession(const std::string& name) const;
+ private:
+ friend class qpid::client::PrivateImplRef<Connection>;
+
+};
+
+struct InvalidOptionString : public qpid::Exception
+{
+ InvalidOptionString(const std::string& msg);
+};
+
+/**
+ * TODO: need to change format of connection option string (currently
+ * name1=value1&name2=value2 etc, should probably use map syntax as
+ * per address options.
+ */
+QPID_CLIENT_EXTERN void parseOptionString(const std::string&, Variant::Map&);
+QPID_CLIENT_EXTERN Variant::Map parseOptionString(const std::string&);
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_CONNECTION_H*/
diff --git a/cpp/include/qpid/messaging/ListContent.h b/cpp/include/qpid/messaging/ListContent.h
new file mode 100644
index 0000000000..1c4e13716d
--- /dev/null
+++ b/cpp/include/qpid/messaging/ListContent.h
@@ -0,0 +1,90 @@
+#ifndef QPID_MESSAGING_LISTCONTENT_H
+#define QPID_MESSAGING_LISTCONTENT_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/ClientImportExport.h"
+#include "Variant.h"
+
+namespace qpid {
+namespace messaging {
+
+class ListContentImpl;
+class Message;
+
+/**
+ * Allows message content to be manipulated as a list.
+ */
+class ListContent
+{
+ public:
+ typedef Variant::List::iterator iterator;
+ typedef Variant::List::reverse_iterator reverse_iterator;
+ typedef Variant::List::const_iterator const_iterator;
+ typedef Variant::List::const_reverse_iterator const_reverse_iterator;
+
+ QPID_CLIENT_EXTERN ListContent(Message&);
+ QPID_CLIENT_EXTERN ~ListContent();
+
+ QPID_CLIENT_EXTERN const_iterator begin() const;
+ QPID_CLIENT_EXTERN iterator begin();
+ QPID_CLIENT_EXTERN const_iterator end() const;
+ QPID_CLIENT_EXTERN iterator end();
+ QPID_CLIENT_EXTERN const_reverse_iterator rbegin() const;
+ QPID_CLIENT_EXTERN reverse_iterator rbegin();
+ QPID_CLIENT_EXTERN const_reverse_iterator rend() const;
+ QPID_CLIENT_EXTERN reverse_iterator rend();
+
+ QPID_CLIENT_EXTERN bool empty() const;
+ QPID_CLIENT_EXTERN size_t size() const;
+
+ QPID_CLIENT_EXTERN const Variant& front() const;
+ QPID_CLIENT_EXTERN Variant& front();
+ QPID_CLIENT_EXTERN const Variant& back() const;
+ QPID_CLIENT_EXTERN Variant& back();
+
+ QPID_CLIENT_EXTERN void push_front(const Variant&);
+ QPID_CLIENT_EXTERN void push_back(const Variant&);
+
+ QPID_CLIENT_EXTERN void pop_front();
+ QPID_CLIENT_EXTERN void pop_back();
+
+ QPID_CLIENT_EXTERN iterator insert(iterator position, const Variant&);
+ QPID_CLIENT_EXTERN void insert(iterator position, size_t n, const Variant&);
+ QPID_CLIENT_EXTERN iterator erase(iterator position);
+ QPID_CLIENT_EXTERN iterator erase(iterator first, iterator last);
+ QPID_CLIENT_EXTERN void clear();
+
+ QPID_CLIENT_EXTERN void encode();
+
+ QPID_CLIENT_EXTERN const Variant::List& asList() const;
+ QPID_CLIENT_EXTERN Variant::List& asList();
+ private:
+ ListContentImpl* impl;
+
+ QPID_CLIENT_EXTERN ListContent& operator=(const ListContent&);
+};
+
+QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const ListContent& m);
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_LISTCONTENT_H*/
diff --git a/cpp/include/qpid/messaging/ListView.h b/cpp/include/qpid/messaging/ListView.h
new file mode 100644
index 0000000000..4970a20072
--- /dev/null
+++ b/cpp/include/qpid/messaging/ListView.h
@@ -0,0 +1,67 @@
+#ifndef QPID_MESSAGING_LISTVIEW_H
+#define QPID_MESSAGING_LISTVIEW_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/ClientImportExport.h"
+#include "Variant.h"
+
+namespace qpid {
+namespace messaging {
+
+class ListViewImpl;
+class Message;
+
+/**
+ * Provides a view of message content as a list
+ */
+class ListView
+{
+ public:
+ typedef Variant::List::const_iterator const_iterator;
+ typedef Variant::List::const_reverse_iterator const_reverse_iterator;
+
+ QPID_CLIENT_EXTERN ListView(const Message&);
+ QPID_CLIENT_EXTERN ~ListView();
+ QPID_CLIENT_EXTERN ListView& operator=(const ListView&);
+
+ QPID_CLIENT_EXTERN const_iterator begin() const;
+ QPID_CLIENT_EXTERN const_iterator end() const;
+ QPID_CLIENT_EXTERN const_reverse_iterator rbegin() const;
+ QPID_CLIENT_EXTERN const_reverse_iterator rend() const;
+
+ QPID_CLIENT_EXTERN bool empty() const;
+ QPID_CLIENT_EXTERN size_t size() const;
+
+ QPID_CLIENT_EXTERN const Variant& front() const;
+ QPID_CLIENT_EXTERN const Variant& back() const;
+
+ QPID_CLIENT_EXTERN const Variant::List& asList() const;
+ private:
+ ListViewImpl* impl;
+};
+
+QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const ListView& m);
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_LISTVIEW_H*/
diff --git a/cpp/include/qpid/messaging/MapContent.h b/cpp/include/qpid/messaging/MapContent.h
new file mode 100644
index 0000000000..b05cb31295
--- /dev/null
+++ b/cpp/include/qpid/messaging/MapContent.h
@@ -0,0 +1,90 @@
+#ifndef QPID_MESSAGING_MAPCONTENT_H
+#define QPID_MESSAGING_MAPCONTENT_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/ClientImportExport.h"
+#include "Variant.h"
+#include <map>
+#include <string>
+
+namespace qpid {
+namespace messaging {
+
+class MapContentImpl;
+class Message;
+
+/**
+ * Allows message content to be manipulated as a map
+ */
+class MapContent
+{
+ public:
+ typedef std::string key_type;
+ typedef std::pair<std::string, Variant> value_type;
+ typedef std::map<key_type, Variant>::const_iterator const_iterator;
+ typedef std::map<key_type, Variant>::iterator iterator;
+ typedef std::map<key_type, Variant>::const_reverse_iterator const_reverse_iterator;
+ typedef std::map<key_type, Variant>::reverse_iterator reverse_iterator;
+
+ QPID_CLIENT_EXTERN MapContent(Message&);
+ QPID_CLIENT_EXTERN ~MapContent();
+
+ QPID_CLIENT_EXTERN const_iterator begin() const;
+ QPID_CLIENT_EXTERN const_iterator end() const;
+ QPID_CLIENT_EXTERN const_reverse_iterator rbegin() const;
+ QPID_CLIENT_EXTERN const_reverse_iterator rend() const;
+ QPID_CLIENT_EXTERN iterator begin();
+ QPID_CLIENT_EXTERN iterator end();
+ QPID_CLIENT_EXTERN reverse_iterator rbegin();
+ QPID_CLIENT_EXTERN reverse_iterator rend();
+
+ QPID_CLIENT_EXTERN bool empty() const;
+ QPID_CLIENT_EXTERN size_t size() const;
+
+ QPID_CLIENT_EXTERN const_iterator find(const key_type&) const;
+ QPID_CLIENT_EXTERN iterator find(const key_type&);
+ QPID_CLIENT_EXTERN const Variant& operator[](const key_type&) const;
+ QPID_CLIENT_EXTERN Variant& operator[](const key_type&);
+
+ QPID_CLIENT_EXTERN std::pair<iterator,bool> insert(const value_type&);
+ QPID_CLIENT_EXTERN iterator insert(iterator position, const value_type&);
+ QPID_CLIENT_EXTERN void erase(iterator position);
+ QPID_CLIENT_EXTERN void erase(iterator first, iterator last);
+ QPID_CLIENT_EXTERN size_t erase(const key_type&);
+ QPID_CLIENT_EXTERN void clear();
+
+ QPID_CLIENT_EXTERN void encode();
+
+ QPID_CLIENT_EXTERN const std::map<key_type, Variant>& asMap() const;
+ QPID_CLIENT_EXTERN std::map<key_type, Variant>& asMap();
+ private:
+ MapContentImpl* impl;
+
+ QPID_CLIENT_EXTERN MapContent& operator=(const MapContent&);
+};
+
+QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const MapContent& m);
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_MAPCONTENT_H*/
diff --git a/cpp/include/qpid/messaging/MapView.h b/cpp/include/qpid/messaging/MapView.h
new file mode 100644
index 0000000000..910dfca5c2
--- /dev/null
+++ b/cpp/include/qpid/messaging/MapView.h
@@ -0,0 +1,70 @@
+#ifndef QPID_MESSAGING_MAPVIEW_H
+#define QPID_MESSAGING_MAPVIEW_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/ClientImportExport.h"
+#include "Variant.h"
+#include <map>
+#include <string>
+
+namespace qpid {
+namespace messaging {
+
+class MapViewImpl;
+class Message;
+
+/**
+ * Provides a view of message content as a list
+ */
+class MapView
+{
+ public:
+ typedef std::string key_type;
+ typedef std::pair<key_type, Variant> value_type;
+ typedef std::map<key_type, Variant>::const_iterator const_iterator;
+ typedef std::map<key_type, Variant>::const_reverse_iterator const_reverse_iterator;
+
+ QPID_CLIENT_EXTERN MapView(const Message&);
+ QPID_CLIENT_EXTERN ~MapView();
+ QPID_CLIENT_EXTERN MapView& operator=(const MapView&);
+
+ QPID_CLIENT_EXTERN const_iterator begin() const;
+ QPID_CLIENT_EXTERN const_iterator end() const;
+ QPID_CLIENT_EXTERN const_reverse_iterator rbegin() const;
+ QPID_CLIENT_EXTERN const_reverse_iterator rend() const;
+
+ QPID_CLIENT_EXTERN bool empty() const;
+ QPID_CLIENT_EXTERN size_t size() const;
+
+ QPID_CLIENT_EXTERN const_iterator find(const key_type&) const;
+ QPID_CLIENT_EXTERN const Variant& operator[](const key_type&) const;
+
+ QPID_CLIENT_EXTERN const std::map<key_type, Variant>& asMap() const;
+ private:
+ MapViewImpl* impl;
+};
+
+QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const MapView& m);
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_MAPVIEW_H*/
diff --git a/cpp/include/qpid/messaging/Message.h b/cpp/include/qpid/messaging/Message.h
new file mode 100644
index 0000000000..368fc89772
--- /dev/null
+++ b/cpp/include/qpid/messaging/Message.h
@@ -0,0 +1,76 @@
+#ifndef QPID_MESSAGING_MESSAGE_H
+#define QPID_MESSAGING_MESSAGE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <string>
+#include "qpid/messaging/Variant.h"
+#include "qpid/client/ClientImportExport.h"
+
+namespace qpid {
+namespace client {
+}
+
+namespace messaging {
+
+class Address;
+class Codec;
+struct MessageImpl;
+
+/**
+ * Representation of a message.
+ */
+class Message
+{
+ public:
+ QPID_CLIENT_EXTERN Message(const std::string& bytes = std::string());
+ QPID_CLIENT_EXTERN Message(const char*, size_t);
+ QPID_CLIENT_EXTERN Message(const Message&);
+ QPID_CLIENT_EXTERN ~Message();
+
+ QPID_CLIENT_EXTERN Message& operator=(const Message&);
+
+ QPID_CLIENT_EXTERN void setReplyTo(const Address&);
+ QPID_CLIENT_EXTERN const Address& getReplyTo() const;
+
+ QPID_CLIENT_EXTERN void setSubject(const std::string&);
+ QPID_CLIENT_EXTERN const std::string& getSubject() const;
+
+ QPID_CLIENT_EXTERN void setContentType(const std::string&);
+ QPID_CLIENT_EXTERN const std::string& getContentType() const;
+
+ QPID_CLIENT_EXTERN const Variant::Map& getHeaders() const;
+ QPID_CLIENT_EXTERN Variant::Map& getHeaders();
+
+ QPID_CLIENT_EXTERN const std::string& getContent() const;
+ QPID_CLIENT_EXTERN std::string& getContent();
+ QPID_CLIENT_EXTERN void setContent(const std::string&);
+ QPID_CLIENT_EXTERN void setContent(const char* chars, size_t count);
+ QPID_CLIENT_EXTERN void getContent(std::pair<const char*, size_t>& content) const;
+
+ private:
+ MessageImpl* impl;
+ friend struct MessageImplAccess;
+};
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_MESSAGE_H*/
diff --git a/cpp/include/qpid/messaging/Receiver.h b/cpp/include/qpid/messaging/Receiver.h
new file mode 100644
index 0000000000..51630b12a2
--- /dev/null
+++ b/cpp/include/qpid/messaging/Receiver.h
@@ -0,0 +1,130 @@
+#ifndef QPID_MESSAGING_RECEIVER_H
+#define QPID_MESSAGING_RECEIVER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/Exception.h"
+#include "qpid/client/ClientImportExport.h"
+#include "qpid/client/Handle.h"
+#include "qpid/sys/Time.h"
+
+namespace qpid {
+namespace client {
+
+template <class> class PrivateImplRef;
+
+}
+
+namespace messaging {
+
+class Message;
+class ReceiverImpl;
+class Session;
+
+/**
+ * Interface through which messages are received.
+ */
+class Receiver : public qpid::client::Handle<ReceiverImpl>
+{
+ public:
+ struct NoMessageAvailable : qpid::Exception {};
+
+ QPID_CLIENT_EXTERN Receiver(ReceiverImpl* impl = 0);
+ QPID_CLIENT_EXTERN Receiver(const Receiver&);
+ QPID_CLIENT_EXTERN ~Receiver();
+ QPID_CLIENT_EXTERN Receiver& operator=(const Receiver&);
+ /**
+ * Retrieves a message from this receivers local queue, or waits
+ * for upto the specified timeout for a message to become
+ * available. Returns false if there is no message to give after
+ * waiting for the specified timeout.
+ */
+ QPID_CLIENT_EXTERN bool get(Message& message, qpid::sys::Duration timeout=qpid::sys::TIME_INFINITE);
+ /**
+ * Retrieves a message from this receivers local queue, or waits
+ * for upto the specified timeout for a message to become
+ * available. Throws NoMessageAvailable if there is no
+ * message to give after waiting for the specified timeout.
+ */
+ QPID_CLIENT_EXTERN Message get(qpid::sys::Duration timeout=qpid::sys::TIME_INFINITE);
+ /**
+ * Retrieves a message for this receivers subscription or waits
+ * for upto the specified timeout for one to become
+ * available. Unlike get() this method will check with the server
+ * that there is no message for the subscription this receiver is
+ * serving before returning false.
+ */
+ QPID_CLIENT_EXTERN bool fetch(Message& message, qpid::sys::Duration timeout=qpid::sys::TIME_INFINITE);
+ /**
+ * Retrieves a message for this receivers subscription or waits
+ * for up to the specified timeout for one to become
+ * available. Unlike get() this method will check with the server
+ * that there is no message for the subscription this receiver is
+ * serving before throwing an exception.
+ */
+ QPID_CLIENT_EXTERN Message fetch(qpid::sys::Duration timeout=qpid::sys::TIME_INFINITE);
+ /**
+ * Sets the capacity for the receiver. The capacity determines how
+ * many incoming messages can be held in the receiver before being
+ * requested by a client via fetch() (or pushed to a listener).
+ */
+ QPID_CLIENT_EXTERN void setCapacity(uint32_t);
+ /**
+ * Returns the capacity of the receiver. The capacity determines
+ * how many incoming messages can be held in the receiver before
+ * being requested by a client via fetch() (or pushed to a
+ * listener).
+ */
+ QPID_CLIENT_EXTERN uint32_t getCapacity();
+ /**
+ * Returns the number of messages received and waiting to be
+ * fetched.
+ */
+ QPID_CLIENT_EXTERN uint32_t available();
+ /**
+ * Returns a count of the number of messages received on this
+ * receiver that have been acknowledged, but for which that
+ * acknowledgement has not yet been confirmed as processed by the
+ * server.
+ */
+ QPID_CLIENT_EXTERN uint32_t pendingAck();
+
+ /**
+ * Cancels this receiver.
+ */
+ QPID_CLIENT_EXTERN void cancel();
+
+ /**
+ * Returns the name of this receiver.
+ */
+ QPID_CLIENT_EXTERN const std::string& getName() const;
+
+ /**
+ * Returns a handle to the session associated with this receiver.
+ */
+ QPID_CLIENT_EXTERN Session getSession() const;
+
+ private:
+ friend class qpid::client::PrivateImplRef<Receiver>;
+};
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_RECEIVER_H*/
diff --git a/cpp/include/qpid/messaging/Sender.h b/cpp/include/qpid/messaging/Sender.h
new file mode 100644
index 0000000000..335e61260c
--- /dev/null
+++ b/cpp/include/qpid/messaging/Sender.h
@@ -0,0 +1,86 @@
+#ifndef QPID_MESSAGING_SENDER_H
+#define QPID_MESSAGING_SENDER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/ClientImportExport.h"
+#include "qpid/client/Handle.h"
+#include "qpid/sys/IntegerTypes.h"
+#include <string>
+
+namespace qpid {
+namespace client {
+
+template <class> class PrivateImplRef;
+
+}
+
+namespace messaging {
+
+class Message;
+class SenderImpl;
+class Session;
+/**
+ * Interface through which messages are sent.
+ */
+class Sender : public qpid::client::Handle<SenderImpl>
+{
+ public:
+ QPID_CLIENT_EXTERN Sender(SenderImpl* impl = 0);
+ QPID_CLIENT_EXTERN Sender(const Sender&);
+ QPID_CLIENT_EXTERN ~Sender();
+ QPID_CLIENT_EXTERN Sender& operator=(const Sender&);
+
+ QPID_CLIENT_EXTERN void send(const Message& message);
+ QPID_CLIENT_EXTERN void cancel();
+
+ /**
+ * Sets the capacity for the sender. The capacity determines how
+ * many outgoing messages can be held pending confirmation of
+ * receipt by the broker.
+ */
+ QPID_CLIENT_EXTERN void setCapacity(uint32_t);
+ /**
+ * Returns the capacity of the sender.
+ * @see setCapacity
+ */
+ QPID_CLIENT_EXTERN uint32_t getCapacity();
+ /**
+ * Returns the number of sent messages pending confirmation of
+ * receipt by the broker. (These are the 'in-doubt' messages).
+ */
+ QPID_CLIENT_EXTERN uint32_t pending();
+
+ /**
+ * Returns the name of this sender.
+ */
+ QPID_CLIENT_EXTERN const std::string& getName() const;
+
+ /**
+ * Returns a handle to the session associated with this sender.
+ */
+ QPID_CLIENT_EXTERN Session getSession() const;
+ private:
+ friend class qpid::client::PrivateImplRef<Sender>;
+};
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_SENDER_H*/
diff --git a/cpp/include/qpid/messaging/Session.h b/cpp/include/qpid/messaging/Session.h
new file mode 100644
index 0000000000..46372cb849
--- /dev/null
+++ b/cpp/include/qpid/messaging/Session.h
@@ -0,0 +1,148 @@
+#ifndef QPID_MESSAGING_SESSION_H
+#define QPID_MESSAGING_SESSION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/Exception.h"
+#include "qpid/client/ClientImportExport.h"
+#include "qpid/client/Handle.h"
+#include "qpid/sys/Time.h"
+#include <string>
+
+namespace qpid {
+namespace client {
+
+template <class> class PrivateImplRef;
+
+}
+
+namespace messaging {
+
+class Address;
+class Connection;
+class Message;
+class MessageListener;
+class Sender;
+class Receiver;
+class SessionImpl;
+class Subscription;
+
+struct KeyError : qpid::Exception
+{
+ QPID_CLIENT_EXTERN KeyError(const std::string&);
+};
+
+/**
+ * A session represents a distinct 'conversation' which can involve
+ * sending and receiving messages to and from different addresses.
+ */
+class Session : public qpid::client::Handle<SessionImpl>
+{
+ public:
+ QPID_CLIENT_EXTERN Session(SessionImpl* impl = 0);
+ QPID_CLIENT_EXTERN Session(const Session&);
+ QPID_CLIENT_EXTERN ~Session();
+ QPID_CLIENT_EXTERN Session& operator=(const Session&);
+
+ QPID_CLIENT_EXTERN void close();
+
+ QPID_CLIENT_EXTERN void commit();
+ QPID_CLIENT_EXTERN void rollback();
+
+ /**
+ * Acknowledges all outstanding messages that have been received
+ * by the application on this session.
+ */
+ QPID_CLIENT_EXTERN void acknowledge();
+ /**
+ * Rejects the specified message. This will prevent the message
+ * being redelivered.
+ */
+ QPID_CLIENT_EXTERN void reject(Message&);
+
+ QPID_CLIENT_EXTERN void sync();
+ QPID_CLIENT_EXTERN void flush();
+
+ /**
+ * Returns the number of messages received and waiting to be
+ * fetched.
+ */
+ QPID_CLIENT_EXTERN uint32_t available();
+ /**
+ * Returns a count of the number of messages received this session
+ * that have been acknowledged, but for which that acknowledgement
+ * has not yet been confirmed as processed by the server.
+ */
+ QPID_CLIENT_EXTERN uint32_t pendingAck();
+ /**
+ * Retrieves the receiver for the next available message. If there
+ * are no available messages at present the call will block for up
+ * to the specified timeout waiting for one to arrive. Returns
+ * true if a message was available at the point of return, in
+ * which case the passed in receiver reference will be set to the
+ * receiver for that message or fals if no message was available.
+ */
+ QPID_CLIENT_EXTERN bool nextReceiver(Receiver&, qpid::sys::Duration timeout=qpid::sys::TIME_INFINITE);
+ /**
+ * Returns the receiver for the next available message. If there
+ * are no available messages at present the call will block for up
+ * to the specified timeout waiting for one to arrive. Will throw
+ * Receiver::NoMessageAvailable if no message became available in
+ * time.
+ */
+ QPID_CLIENT_EXTERN Receiver nextReceiver(qpid::sys::Duration timeout=qpid::sys::TIME_INFINITE);
+
+ /**
+ * Create a new sender through which messages can be sent to the
+ * specified address.
+ */
+ QPID_CLIENT_EXTERN Sender createSender(const Address& address);
+ QPID_CLIENT_EXTERN Sender createSender(const std::string& address);
+
+ /**
+ * Create a new receiver through which messages can be received
+ * from the specified address.
+ */
+ QPID_CLIENT_EXTERN Receiver createReceiver(const Address& address);
+ QPID_CLIENT_EXTERN Receiver createReceiver(const std::string& address);
+
+ /**
+ * Returns the sender with the specified name or throws KeyError
+ * if there is none for that name.
+ */
+ QPID_CLIENT_EXTERN Sender getSender(const std::string& name) const;
+ /**
+ * Returns the receiver with the specified name or throws KeyError
+ * if there is none for that name.
+ */
+ QPID_CLIENT_EXTERN Receiver getReceiver(const std::string& name) const;
+ /**
+ * Returns a handle to the connection this session is associated
+ * with.
+ */
+ QPID_CLIENT_EXTERN Connection getConnection() const;
+
+ private:
+ friend class qpid::client::PrivateImplRef<Session>;
+};
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_SESSION_H*/
diff --git a/cpp/include/qpid/messaging/Variant.h b/cpp/include/qpid/messaging/Variant.h
new file mode 100644
index 0000000000..de5cef4d67
--- /dev/null
+++ b/cpp/include/qpid/messaging/Variant.h
@@ -0,0 +1,168 @@
+#ifndef QPID_MESSAGING_VARIANT_H
+#define QPID_MESSAGING_VARIANT_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <list>
+#include <map>
+#include <ostream>
+#include <string>
+#include "qpid/Exception.h"
+#include "qpid/sys/IntegerTypes.h"
+#include "qpid/client/ClientImportExport.h"
+
+namespace qpid {
+namespace messaging {
+
+/**
+ * Thrown when an illegal conversion of a variant is attempted.
+ */
+struct InvalidConversion : public qpid::Exception
+{
+ InvalidConversion(const std::string& msg);
+};
+
+enum VariantType {
+ VAR_VOID = 0,
+ VAR_BOOL,
+ VAR_UINT8,
+ VAR_UINT16,
+ VAR_UINT32,
+ VAR_UINT64,
+ VAR_INT8,
+ VAR_INT16,
+ VAR_INT32,
+ VAR_INT64,
+ VAR_FLOAT,
+ VAR_DOUBLE,
+ VAR_STRING,
+ VAR_MAP,
+ VAR_LIST
+};
+
+class VariantImpl;
+
+/**
+ * Represents a value of variable type.
+ */
+class Variant
+{
+ public:
+ typedef std::map<std::string, Variant> Map;
+ typedef std::list<Variant> List;
+
+ QPID_CLIENT_EXTERN Variant();
+ QPID_CLIENT_EXTERN Variant(bool);
+ QPID_CLIENT_EXTERN Variant(uint8_t);
+ QPID_CLIENT_EXTERN Variant(uint16_t);
+ QPID_CLIENT_EXTERN Variant(uint32_t);
+ QPID_CLIENT_EXTERN Variant(uint64_t);
+ QPID_CLIENT_EXTERN Variant(int8_t);
+ QPID_CLIENT_EXTERN Variant(int16_t);
+ QPID_CLIENT_EXTERN Variant(int32_t);
+ QPID_CLIENT_EXTERN Variant(int64_t);
+ QPID_CLIENT_EXTERN Variant(float);
+ QPID_CLIENT_EXTERN Variant(double);
+ QPID_CLIENT_EXTERN Variant(const std::string&);
+ QPID_CLIENT_EXTERN Variant(const char*);
+ QPID_CLIENT_EXTERN Variant(const Map&);
+ QPID_CLIENT_EXTERN Variant(const List&);
+ QPID_CLIENT_EXTERN Variant(const Variant&);
+
+ QPID_CLIENT_EXTERN ~Variant();
+
+ QPID_CLIENT_EXTERN VariantType getType() const;
+ QPID_CLIENT_EXTERN bool isVoid() const;
+
+ QPID_CLIENT_EXTERN Variant& operator=(bool);
+ QPID_CLIENT_EXTERN Variant& operator=(uint8_t);
+ QPID_CLIENT_EXTERN Variant& operator=(uint16_t);
+ QPID_CLIENT_EXTERN Variant& operator=(uint32_t);
+ QPID_CLIENT_EXTERN Variant& operator=(uint64_t);
+ QPID_CLIENT_EXTERN Variant& operator=(int8_t);
+ QPID_CLIENT_EXTERN Variant& operator=(int16_t);
+ QPID_CLIENT_EXTERN Variant& operator=(int32_t);
+ QPID_CLIENT_EXTERN Variant& operator=(int64_t);
+ QPID_CLIENT_EXTERN Variant& operator=(float);
+ QPID_CLIENT_EXTERN Variant& operator=(double);
+ QPID_CLIENT_EXTERN Variant& operator=(const std::string&);
+ QPID_CLIENT_EXTERN Variant& operator=(const char*);
+ QPID_CLIENT_EXTERN Variant& operator=(const Map&);
+ QPID_CLIENT_EXTERN Variant& operator=(const List&);
+ QPID_CLIENT_EXTERN Variant& operator=(const Variant&);
+
+ QPID_CLIENT_EXTERN bool asBool() const;
+ QPID_CLIENT_EXTERN uint8_t asUint8() const;
+ QPID_CLIENT_EXTERN uint16_t asUint16() const;
+ QPID_CLIENT_EXTERN uint32_t asUint32() const;
+ QPID_CLIENT_EXTERN uint64_t asUint64() const;
+ QPID_CLIENT_EXTERN int8_t asInt8() const;
+ QPID_CLIENT_EXTERN int16_t asInt16() const;
+ QPID_CLIENT_EXTERN int32_t asInt32() const;
+ QPID_CLIENT_EXTERN int64_t asInt64() const;
+ QPID_CLIENT_EXTERN float asFloat() const;
+ QPID_CLIENT_EXTERN double asDouble() const;
+ QPID_CLIENT_EXTERN std::string asString() const;
+
+ QPID_CLIENT_EXTERN operator bool() const;
+ QPID_CLIENT_EXTERN operator uint8_t() const;
+ QPID_CLIENT_EXTERN operator uint16_t() const;
+ QPID_CLIENT_EXTERN operator uint32_t() const;
+ QPID_CLIENT_EXTERN operator uint64_t() const;
+ QPID_CLIENT_EXTERN operator int8_t() const;
+ QPID_CLIENT_EXTERN operator int16_t() const;
+ QPID_CLIENT_EXTERN operator int32_t() const;
+ QPID_CLIENT_EXTERN operator int64_t() const;
+ QPID_CLIENT_EXTERN operator float() const;
+ QPID_CLIENT_EXTERN operator double() const;
+ QPID_CLIENT_EXTERN operator const char*() const;
+
+ QPID_CLIENT_EXTERN const Map& asMap() const;
+ QPID_CLIENT_EXTERN Map& asMap();
+ QPID_CLIENT_EXTERN const List& asList() const;
+ QPID_CLIENT_EXTERN List& asList();
+ /**
+ * Unlike asString(), getString() will not do any conversions and
+ * will throw InvalidConversion if the type is not STRING.
+ */
+ QPID_CLIENT_EXTERN const std::string& getString() const;
+ QPID_CLIENT_EXTERN std::string& getString();
+
+ QPID_CLIENT_EXTERN void setEncoding(const std::string&);
+ QPID_CLIENT_EXTERN const std::string& getEncoding() const;
+
+ QPID_CLIENT_EXTERN bool isEqualTo(const Variant& a) const;
+
+ QPID_CLIENT_EXTERN void reset();
+ private:
+ VariantImpl* impl;
+};
+
+QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const Variant& value);
+QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const Variant::Map& map);
+QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const Variant::List& list);
+QPID_CLIENT_EXTERN bool operator==(const Variant& a, const Variant& b);
+
+typedef Variant::Map VariantMap;
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_VARIANT_H*/
diff --git a/cpp/include/qpid/sys/Condition.h b/cpp/include/qpid/sys/Condition.h
new file mode 100644
index 0000000000..9be4b357fe
--- /dev/null
+++ b/cpp/include/qpid/sys/Condition.h
@@ -0,0 +1,33 @@
+#ifndef _sys_Condition_h
+#define _sys_Condition_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifdef USE_APR_PLATFORM
+#include "apr/Condition.h"
+#elif defined (_WIN32)
+#include "windows/Condition.h"
+#else
+#include "posix/Condition.h"
+#endif
+
+#endif /*!_sys_Condition_h*/
diff --git a/cpp/include/qpid/sys/ExceptionHolder.h b/cpp/include/qpid/sys/ExceptionHolder.h
new file mode 100644
index 0000000000..9eff1d64c7
--- /dev/null
+++ b/cpp/include/qpid/sys/ExceptionHolder.h
@@ -0,0 +1,74 @@
+#ifndef QPID_EXCEPTIONHOLDER_H
+#define QPID_EXCEPTIONHOLDER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/shared_ptr.hpp>
+
+
+namespace qpid {
+namespace sys {
+
+struct Raisable {
+ virtual ~Raisable() {};
+ virtual void raise() const=0;
+ virtual std::string what() const=0;
+};
+
+/**
+ * Holder for exceptions. Allows the thread that notices an error condition to
+ * create an exception and store it to be thrown by another thread.
+ */
+class ExceptionHolder : public Raisable {
+ public:
+ ExceptionHolder() {}
+ // Use default copy & assign.
+
+ /** Take ownership of ex */
+ template <class Ex> ExceptionHolder(Ex* ex) { wrap(ex); }
+ template <class Ex> ExceptionHolder(const boost::shared_ptr<Ex>& ex) { wrap(ex.release()); }
+
+ template <class Ex> ExceptionHolder& operator=(Ex* ex) { wrap(ex); return *this; }
+ template <class Ex> ExceptionHolder& operator=(boost::shared_ptr<Ex> ex) { wrap(ex.release()); return *this; }
+
+ void raise() const { if (wrapper.get()) wrapper->raise() ; }
+ std::string what() const { return wrapper.get() ? wrapper->what() : std::string(); }
+ bool empty() const { return !wrapper.get(); }
+ operator bool() const { return !empty(); }
+ void reset() { wrapper.reset(); }
+
+ private:
+ template <class Ex> struct Wrapper : public Raisable {
+ Wrapper(Ex* ptr) : exception(ptr) {}
+ void raise() const { throw *exception; }
+ std::string what() const { return exception->what(); }
+ boost::shared_ptr<Ex> exception;
+ };
+ template <class Ex> void wrap(Ex* ex) { wrapper.reset(new Wrapper<Ex>(ex)); }
+ boost::shared_ptr<Raisable> wrapper;
+};
+
+
+}} // namespace qpid::sys
+
+
+#endif /*!QPID_EXCEPTIONHOLDER_H*/
diff --git a/cpp/include/qpid/sys/IOHandle.h b/cpp/include/qpid/sys/IOHandle.h
new file mode 100644
index 0000000000..45fc8c240a
--- /dev/null
+++ b/cpp/include/qpid/sys/IOHandle.h
@@ -0,0 +1,49 @@
+#ifndef _sys_IOHandle_h
+#define _sys_IOHandle_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/CommonImportExport.h"
+
+namespace qpid {
+namespace sys {
+
+/**
+ * This is a class intended to abstract the Unix concept of file descriptor
+ * or the Windows concept of HANDLE
+ */
+class PollerHandle;
+class IOHandlePrivate;
+class IOHandle {
+ friend class PollerHandle;
+ friend class IOHandlePrivate;
+
+protected:
+ IOHandlePrivate* const impl;
+
+ IOHandle(IOHandlePrivate*);
+ QPID_COMMON_EXTERN virtual ~IOHandle();
+};
+
+}}
+
+#endif // _sys_IOHandle_h
diff --git a/cpp/include/qpid/sys/IntegerTypes.h b/cpp/include/qpid/sys/IntegerTypes.h
new file mode 100755
index 0000000000..89635f033e
--- /dev/null
+++ b/cpp/include/qpid/sys/IntegerTypes.h
@@ -0,0 +1,31 @@
+#ifndef QPID_SYS_INTEGERTYPES_H
+#define QPID_SYS_INTEGERTYPES_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#if (defined(_WINDOWS) || defined (WIN32)) && defined(_MSC_VER)
+#include "qpid/sys/windows/IntegerTypes.h"
+#endif
+#if !defined _WINDOWS && !defined WIN32
+#include "qpid/sys/posix/IntegerTypes.h"
+#endif
+
+#endif /*!QPID_SYS_INTEGERTYPES_H*/
diff --git a/cpp/include/qpid/sys/Monitor.h b/cpp/include/qpid/sys/Monitor.h
new file mode 100644
index 0000000000..123bf92dcb
--- /dev/null
+++ b/cpp/include/qpid/sys/Monitor.h
@@ -0,0 +1,49 @@
+#ifndef _sys_Monitor_h
+#define _sys_Monitor_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Condition.h"
+
+namespace qpid {
+namespace sys {
+
+/**
+ * A monitor is a condition variable and a mutex
+ */
+class Monitor : public Mutex, public Condition {
+ public:
+ inline void wait();
+ inline bool wait(const AbsTime& absoluteTime);
+};
+
+
+void Monitor::wait() {
+ Condition::wait(*this);
+}
+
+bool Monitor::wait(const AbsTime& absoluteTime) {
+ return Condition::wait(*this, absoluteTime);
+}
+
+}}
+#endif /*!_sys_Monitor_h*/
diff --git a/cpp/include/qpid/sys/Mutex.h b/cpp/include/qpid/sys/Mutex.h
new file mode 100644
index 0000000000..43a83d4fc3
--- /dev/null
+++ b/cpp/include/qpid/sys/Mutex.h
@@ -0,0 +1,91 @@
+#ifndef _sys_Mutex_h
+#define _sys_Mutex_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Scoped lock template: calls lock() in ctor, unlock() in dtor.
+ * L can be any class with lock() and unlock() functions.
+ */
+template <class L>
+class ScopedLock
+{
+ public:
+ ScopedLock(L& l) : mutex(l) { l.lock(); }
+ ~ScopedLock() { mutex.unlock(); }
+ private:
+ L& mutex;
+};
+
+template <class L>
+class ScopedUnlock
+{
+ public:
+ ScopedUnlock(L& l) : mutex(l) { l.unlock(); }
+ ~ScopedUnlock() { mutex.lock(); }
+ private:
+ L& mutex;
+};
+
+template <class L>
+class ScopedRlock
+{
+ public:
+ ScopedRlock(L& l) : mutex(l) { l.rlock(); }
+ ~ScopedRlock() { mutex.unlock(); }
+ private:
+ L& mutex;
+};
+
+template <class L>
+class ScopedWlock
+{
+ public:
+ ScopedWlock(L& l) : mutex(l) { l.wlock(); }
+ ~ScopedWlock() { mutex.unlock(); }
+ private:
+ L& mutex;
+};
+
+template <class L>
+class ConditionalScopedLock
+{
+ public:
+ ConditionalScopedLock(L& l) : mutex(l) { acquired = l.trylock(); }
+ ~ConditionalScopedLock() { if (acquired) mutex.unlock(); }
+ bool lockAcquired() { return acquired; }
+ private:
+ L& mutex;
+ bool acquired;
+};
+
+}}
+
+#ifdef USE_APR_PLATFORM
+#include "apr/Mutex.h"
+#elif defined (_WIN32)
+#include "windows/Mutex.h"
+#else
+#include "posix/Mutex.h"
+#endif
+
+#endif /*!_sys_Mutex_h*/
diff --git a/cpp/include/qpid/sys/Runnable.h b/cpp/include/qpid/sys/Runnable.h
new file mode 100644
index 0000000000..0f1243a277
--- /dev/null
+++ b/cpp/include/qpid/sys/Runnable.h
@@ -0,0 +1,51 @@
+#ifndef _Runnable_
+#define _Runnable_
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/function.hpp>
+#include "qpid/CommonImportExport.h"
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Interface for objects that can be run, e.g. in a thread.
+ */
+class Runnable
+{
+ public:
+ /** Type to represent a runnable as a Functor */
+ typedef boost::function0<void> Functor;
+
+ QPID_COMMON_EXTERN virtual ~Runnable();
+
+ /** Derived classes override run(). */
+ virtual void run() = 0;
+
+ /** Create a functor object that will call this->run(). */
+ Functor functor();
+};
+
+}}
+
+
+#endif
diff --git a/cpp/include/qpid/sys/StrError.h b/cpp/include/qpid/sys/StrError.h
new file mode 100644
index 0000000000..36489dd0fc
--- /dev/null
+++ b/cpp/include/qpid/sys/StrError.h
@@ -0,0 +1,36 @@
+#ifndef _sys_StrError_h
+#define _sys_StrError_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <string>
+#include "qpid/CommonImportExport.h"
+
+namespace qpid {
+namespace sys {
+
+/** Get the error message for a system number err, e.g. errno. */
+QPID_COMMON_EXTERN std::string strError(int err);
+
+}} // namespace qpid
+
+#endif // _sys_StrError_h
diff --git a/cpp/include/qpid/sys/SystemInfo.h b/cpp/include/qpid/sys/SystemInfo.h
new file mode 100644
index 0000000000..09f9980173
--- /dev/null
+++ b/cpp/include/qpid/sys/SystemInfo.h
@@ -0,0 +1,85 @@
+#ifndef QPID_SYS_SYSTEMINFO_H
+#define QPID_SYS_SYSTEMINFO_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/IntegerTypes.h"
+#include "qpid/Address.h"
+#include "qpid/CommonImportExport.h"
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Retrieve information about the system we are running on.
+ * Results may be dependent on OS/hardware.
+ */
+namespace SystemInfo {
+ /**
+ * Estimate available concurrency, e.g. number of CPU cores.
+ * -1 means estimate not available on this platform.
+ */
+ QPID_COMMON_EXTERN long concurrency();
+
+ /**
+ * Get the local host name and set it in the specified TcpAddress.
+ * Returns false if it can't be obtained and sets errno to any error value.
+ */
+ QPID_COMMON_EXTERN bool getLocalHostname (TcpAddress &address);
+
+ QPID_COMMON_EXTERN void getLocalIpAddresses (uint16_t port, std::vector<Address> &addrList);
+
+ /**
+ * Retrieve system identifiers and versions. This is information that can
+ * generally be retrieved via POSIX uname().
+ *
+ * @param osName Receives the OS name; e.g., GNU/Linux or Windows
+ * @param nodeName Receives the nodename. This may or may not match the
+ * set hostname from getLocalHostname().
+ * @param release Receives the OS release identifier.
+ * @param version Receives the OS release version (kernel, build, sp, etc.)
+ * @param machine Receives the hardware type.
+ */
+ QPID_COMMON_EXTERN void getSystemId (std::string &osName,
+ std::string &nodeName,
+ std::string &release,
+ std::string &version,
+ std::string &machine);
+
+ /**
+ * Get the process ID of the current process.
+ */
+ QPID_COMMON_EXTERN uint32_t getProcessId();
+
+ /**
+ * Get the process ID of the parent of the current process.
+ */
+ QPID_COMMON_EXTERN uint32_t getParentProcessId();
+
+ /**
+ * Get the name of the current process (i.e. the name of the executable)
+ */
+ QPID_COMMON_EXTERN std::string getProcessName();
+
+
+}}} // namespace qpid::sys::SystemInfo
+
+#endif /*!QPID_SYS_SYSTEMINFO_H*/
diff --git a/cpp/include/qpid/sys/Thread.h b/cpp/include/qpid/sys/Thread.h
new file mode 100644
index 0000000000..bfea4b4944
--- /dev/null
+++ b/cpp/include/qpid/sys/Thread.h
@@ -0,0 +1,65 @@
+#ifndef _sys_Thread_h
+#define _sys_Thread_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <boost/shared_ptr.hpp>
+#include "qpid/CommonImportExport.h"
+
+#ifdef _WIN32
+# define QPID_TSS __declspec(thread)
+#elif defined (__GNUC__)
+# define QPID_TSS __thread
+#elif defined (__SUNPRO_CC)
+# define QPID_TSS __thread
+#else
+# error "Dont know how to define QPID_TSS for this platform"
+#endif
+
+namespace qpid {
+namespace sys {
+
+class Runnable;
+class ThreadPrivate;
+
+class Thread
+{
+ boost::shared_ptr<ThreadPrivate> impl;
+
+ public:
+ QPID_COMMON_EXTERN Thread();
+ QPID_COMMON_EXTERN explicit Thread(qpid::sys::Runnable*);
+ QPID_COMMON_EXTERN explicit Thread(qpid::sys::Runnable&);
+
+ QPID_COMMON_EXTERN void join();
+
+ QPID_COMMON_EXTERN unsigned long id();
+
+ QPID_COMMON_EXTERN static Thread current();
+
+ /** ID of current thread for logging.
+ * Workaround for broken Thread::current() in APR
+ */
+ static unsigned long logId() { return current().id(); }
+};
+
+}}
+#endif /*!_sys_Thread_h*/
diff --git a/cpp/include/qpid/sys/Time.h b/cpp/include/qpid/sys/Time.h
new file mode 100644
index 0000000000..c19757747b
--- /dev/null
+++ b/cpp/include/qpid/sys/Time.h
@@ -0,0 +1,173 @@
+#ifndef _sys_Time_h
+#define _sys_Time_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/IntegerTypes.h"
+/*
+ * The platform defines its notion of time as a TimePrivate type. The
+ * platform's implementation knows how to handle this type.
+ */
+#if defined (_WIN32)
+# include "windows/Time.h"
+#else
+# include "posix/Time.h"
+#endif
+
+#include "qpid/CommonImportExport.h"
+
+#include <limits>
+#include <iosfwd>
+
+namespace qpid {
+namespace sys {
+
+class Duration;
+
+/**
+ * @class AbsTime
+ *
+ * Class to represent an instant in time.
+ *
+ * The time resolution is in nanosecs, and this is held with 64 bits
+ * giving a total time span from about 25 million years ago to 25 million
+ * years hence. As an aside the internal time can sensibly be negative
+ * meaning before the epoch (probably 1/1/1970 although this class doesn't
+ * care).
+ *
+ * The AbsTime class is a value class and so you don't need to add any
+ * accessors to its internal state. If you think you want to replace its value,
+ * you need to construct a new AbsTime and assign it, viz:
+ *
+ * AbsTime when = AbsTime::now();
+ * ...
+ * when = AbsTime(when, 2*TIME_SEC); // Advance timer 2 secs
+ *
+ * If for some reason you need access to the internal nanosec value you need
+ * to convert the AbsTime to a Duration and use its conversion to int64_t, viz:
+ *
+ * AbsTime now = AbsTime::now();
+ *
+ * int64_t ns = Duration(now);
+ *
+ * However note that the nanosecond value that is returned here is not
+ * defined to be anything in particular and could vary from platform to
+ * platform.
+ *
+ * There are some sensible operations that are currently missing from
+ * AbsTime, but nearly all that's needed can be done with a mixture of
+ * AbsTimes and Durations.
+ *
+ * For example, convenience operators to add a Duration and AbsTime returning
+ * an AbsTime would fit here (although you can already perform the operation
+ * with one of the AbsTime constructors). However trying to add 2 AbsTimes
+ * doesn't make sense.
+ */
+class AbsTime {
+ friend class Duration;
+
+ TimePrivate timepoint;
+
+public:
+ QPID_COMMON_EXTERN inline AbsTime() {}
+ QPID_COMMON_EXTERN AbsTime(const AbsTime& time0, const Duration& duration);
+ // Default assignment operation fine
+ // Default copy constructor fine
+
+ QPID_COMMON_EXTERN static AbsTime now();
+ QPID_COMMON_EXTERN static AbsTime FarFuture();
+ const TimePrivate& getPrivate(void) const { return timepoint; }
+ bool operator==(const AbsTime& t) const { return t.timepoint == timepoint; }
+ template <class S> void serialize(S& s) { s(timepoint); }
+
+ friend bool operator<(const AbsTime& a, const AbsTime& b);
+ friend bool operator>(const AbsTime& a, const AbsTime& b);
+ QPID_COMMON_EXTERN friend std::ostream& operator << (std::ostream&, const AbsTime&);
+};
+
+QPID_COMMON_EXTERN std::ostream& operator << (std::ostream&, const AbsTime&);
+
+/**
+ * @class Duration
+ * Class to represent the duration between instants of time.
+ *
+ * As AbsTime, this class also uses nanosecs for its time
+ * resolution where possible. For the most part a duration can be dealt
+ * with like a 64 bit integer, and indeed there is an implicit conversion which
+ * makes this quite convenient.
+ */
+class Duration {
+ static int64_t max() { return std::numeric_limits<int64_t>::max(); }
+ int64_t nanosecs;
+
+ friend class AbsTime;
+
+public:
+ QPID_COMMON_EXTERN inline Duration(int64_t time0);
+ QPID_COMMON_EXTERN explicit Duration(const AbsTime& time0);
+ QPID_COMMON_EXTERN explicit Duration(const AbsTime& start, const AbsTime& finish);
+ inline operator int64_t() const;
+};
+
+std::ostream& operator << (std::ostream&, const Duration&);
+
+inline AbsTime now() { return AbsTime::now(); }
+
+inline bool operator<(const AbsTime& a, const AbsTime& b)
+{ return a.timepoint < b.timepoint; }
+inline bool operator>(const AbsTime& a, const AbsTime& b)
+{ return a.timepoint > b.timepoint; }
+
+Duration::Duration(int64_t time0) :
+ nanosecs(time0)
+{}
+
+Duration::operator int64_t() const
+{ return nanosecs; }
+
+/** Nanoseconds per second. */
+const Duration TIME_SEC = 1000*1000*1000;
+/** Nanoseconds per millisecond */
+const Duration TIME_MSEC = 1000*1000;
+/** Nanoseconds per microseconds. */
+const Duration TIME_USEC = 1000;
+/** Nanoseconds per nanosecond. */
+const Duration TIME_NSEC = 1;
+
+/** Value to represent an infinite timeout */
+const Duration TIME_INFINITE = std::numeric_limits<int64_t>::max();
+
+/** Time greater than any other time */
+const AbsTime FAR_FUTURE = AbsTime::FarFuture();
+
+/** Portable sleep for a number of seconds */
+QPID_COMMON_EXTERN void sleep(int secs);
+
+/** Portable sleep for a number of microseconds */
+QPID_COMMON_EXTERN void usleep(uint64_t usecs);
+
+/** Output formatted date/time for now*/
+void outputFormattedNow(std::ostream&);
+
+}}
+
+#endif /*!_sys_Time_h*/
diff --git a/cpp/include/qpid/sys/posix/Condition.h b/cpp/include/qpid/sys/posix/Condition.h
new file mode 100644
index 0000000000..279039735a
--- /dev/null
+++ b/cpp/include/qpid/sys/posix/Condition.h
@@ -0,0 +1,86 @@
+#ifndef _sys_posix_Condition_h
+#define _sys_posix_Condition_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/posix/PrivatePosix.h"
+
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Time.h"
+
+#include <time.h>
+#include <sys/errno.h>
+#include <boost/noncopyable.hpp>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * A condition variable for thread synchronization.
+ */
+class Condition
+{
+ public:
+ inline Condition();
+ inline ~Condition();
+ inline void wait(Mutex&);
+ inline bool wait(Mutex&, const AbsTime& absoluteTime);
+ inline void notify();
+ inline void notifyAll();
+
+ private:
+ pthread_cond_t condition;
+};
+
+Condition::Condition() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_cond_init(&condition, 0));
+}
+
+Condition::~Condition() {
+ QPID_POSIX_ABORT_IF(pthread_cond_destroy(&condition));
+}
+
+void Condition::wait(Mutex& mutex) {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_cond_wait(&condition, &mutex.mutex));
+}
+
+bool Condition::wait(Mutex& mutex, const AbsTime& absoluteTime){
+ struct timespec ts;
+ toTimespec(ts, Duration(absoluteTime));
+ int status = pthread_cond_timedwait(&condition, &mutex.mutex, &ts);
+ if (status != 0) {
+ if (status == ETIMEDOUT) return false;
+ throw QPID_POSIX_ERROR(status);
+ }
+ return true;
+}
+
+void Condition::notify(){
+ QPID_POSIX_ASSERT_THROW_IF(pthread_cond_signal(&condition));
+}
+
+void Condition::notifyAll(){
+ QPID_POSIX_ASSERT_THROW_IF(pthread_cond_broadcast(&condition));
+}
+
+}}
+#endif /*!_sys_posix_Condition_h*/
diff --git a/cpp/include/qpid/sys/posix/IntegerTypes.h b/cpp/include/qpid/sys/posix/IntegerTypes.h
new file mode 100755
index 0000000000..ce97f7bde8
--- /dev/null
+++ b/cpp/include/qpid/sys/posix/IntegerTypes.h
@@ -0,0 +1,26 @@
+#ifndef QPID_SYS_POSIX_INTEGERTYPES_H
+#define QPID_SYS_POSIX_INTEGERTYPES_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <stdint.h>
+
+#endif /*!QPID_SYS_INTEGERTYPES_H*/
diff --git a/cpp/include/qpid/sys/posix/Mutex.h b/cpp/include/qpid/sys/posix/Mutex.h
new file mode 100644
index 0000000000..e2b21b5a56
--- /dev/null
+++ b/cpp/include/qpid/sys/posix/Mutex.h
@@ -0,0 +1,158 @@
+#ifndef _sys_posix_Mutex_h
+#define _sys_posix_Mutex_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/sys/posix/check.h"
+
+#include <pthread.h>
+#include <boost/noncopyable.hpp>
+
+namespace qpid {
+namespace sys {
+
+class Condition;
+
+/**
+ * Mutex lock.
+ */
+class Mutex : private boost::noncopyable {
+ friend class Condition;
+ static const pthread_mutexattr_t* getAttribute();
+
+public:
+ typedef ::qpid::sys::ScopedLock<Mutex> ScopedLock;
+ typedef ::qpid::sys::ScopedUnlock<Mutex> ScopedUnlock;
+
+ inline Mutex();
+ inline ~Mutex();
+ inline void lock();
+ inline void unlock();
+ inline bool trylock();
+
+
+protected:
+ pthread_mutex_t mutex;
+};
+
+/**
+ * RW lock.
+ */
+class RWlock : private boost::noncopyable {
+ friend class Condition;
+
+public:
+ typedef ::qpid::sys::ScopedRlock<RWlock> ScopedRlock;
+ typedef ::qpid::sys::ScopedWlock<RWlock> ScopedWlock;
+
+ inline RWlock();
+ inline ~RWlock();
+ inline void wlock(); // will write-lock
+ inline void rlock(); // will read-lock
+ inline void unlock();
+ inline void trywlock(); // will write-try
+ inline void tryrlock(); // will read-try
+
+protected:
+ pthread_rwlock_t rwlock;
+};
+
+
+/**
+ * PODMutex is a POD, can be static-initialized with
+ * PODMutex m = QPID_PODMUTEX_INITIALIZER
+ */
+struct PODMutex
+{
+ typedef ::qpid::sys::ScopedLock<PODMutex> ScopedLock;
+
+ inline void lock();
+ inline void unlock();
+ inline bool trylock();
+
+ // Must be public to be a POD:
+ pthread_mutex_t mutex;
+};
+
+#define QPID_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
+
+void PODMutex::lock() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_lock(&mutex));
+}
+
+void PODMutex::unlock() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_unlock(&mutex));
+}
+
+bool PODMutex::trylock() {
+ return pthread_mutex_trylock(&mutex) == 0;
+}
+
+Mutex::Mutex() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_init(&mutex, getAttribute()));
+}
+
+Mutex::~Mutex(){
+ QPID_POSIX_ABORT_IF(pthread_mutex_destroy(&mutex));
+}
+
+void Mutex::lock() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_lock(&mutex));
+}
+
+void Mutex::unlock() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_unlock(&mutex));
+}
+
+bool Mutex::trylock() {
+ return pthread_mutex_trylock(&mutex) == 0;
+}
+
+
+RWlock::RWlock() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_init(&rwlock, NULL));
+}
+
+RWlock::~RWlock(){
+ QPID_POSIX_ABORT_IF(pthread_rwlock_destroy(&rwlock));
+}
+
+void RWlock::wlock() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_wrlock(&rwlock));
+}
+
+void RWlock::rlock() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_rdlock(&rwlock));
+}
+
+void RWlock::unlock() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_unlock(&rwlock));
+}
+
+void RWlock::trywlock() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_trywrlock(&rwlock));
+}
+
+void RWlock::tryrlock() {
+ QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_tryrdlock(&rwlock));
+}
+
+
+}}
+#endif /*!_sys_posix_Mutex_h*/
diff --git a/cpp/include/qpid/sys/posix/PrivatePosix.h b/cpp/include/qpid/sys/posix/PrivatePosix.h
new file mode 100644
index 0000000000..79cb950275
--- /dev/null
+++ b/cpp/include/qpid/sys/posix/PrivatePosix.h
@@ -0,0 +1,77 @@
+#ifndef _sys_posix_PrivatePosix_h
+#define _sys_posix_PrivatePosix_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Time.h"
+#include "qpid/sys/IOHandle.h"
+
+struct timespec;
+struct timeval;
+struct addrinfo;
+
+namespace qpid {
+namespace sys {
+
+// Private Time related implementation details
+struct timespec& toTimespec(struct timespec& ts, const Duration& t);
+struct timeval& toTimeval(struct timeval& tv, const Duration& t);
+Duration toTime(const struct timespec& ts);
+
+// Private SocketAddress details
+class SocketAddress;
+const struct addrinfo& getAddrInfo(const SocketAddress&);
+
+// Private fd related implementation details
+class IOHandlePrivate {
+public:
+ IOHandlePrivate(int f = -1) :
+ fd(f)
+ {}
+
+ int fd;
+};
+
+int toFd(const IOHandlePrivate* h);
+
+// Posix fd as an IOHandle
+class PosixIOHandle : public IOHandle {
+public:
+ PosixIOHandle(int fd) :
+ IOHandle(new IOHandlePrivate(fd))
+ {}
+};
+
+// Dummy IOHandle for places it's required in the API
+// but we promise not to actually try to do any operations on the IOHandle
+class NullIOHandle : public IOHandle {
+public:
+ NullIOHandle() :
+ IOHandle(new IOHandlePrivate)
+ {}
+};
+
+extern NullIOHandle DummyIOHandle;
+
+}}
+
+#endif /*!_sys_posix_PrivatePosix_h*/
diff --git a/cpp/include/qpid/sys/posix/Time.h b/cpp/include/qpid/sys/posix/Time.h
new file mode 100755
index 0000000000..62d734c816
--- /dev/null
+++ b/cpp/include/qpid/sys/posix/Time.h
@@ -0,0 +1,34 @@
+#ifndef QPID_SYS_POSIX_TIME_H
+#define QPID_SYS_POSIX_TIME_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/sys/IntegerTypes.h"
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Class to represent an instant in time.
+ */
+typedef int64_t TimePrivate;
+
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_POSIX_TIME_H*/
diff --git a/cpp/include/qpid/sys/posix/check.h b/cpp/include/qpid/sys/posix/check.h
new file mode 100644
index 0000000000..bbc66d389b
--- /dev/null
+++ b/cpp/include/qpid/sys/posix/check.h
@@ -0,0 +1,52 @@
+#ifndef _posix_check_h
+#define _posix_check_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Exception.h"
+
+#include <cerrno>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define QPID_POSIX_ERROR(ERRNO) qpid::Exception(QPID_MSG(qpid::sys::strError(ERRNO)))
+
+/** THROW QPID_POSIX_ERROR(errno) if RESULT is less than zero */
+#define QPID_POSIX_CHECK(RESULT) \
+ if ((RESULT) < 0) throw QPID_POSIX_ERROR((errno))
+
+/** Throw a posix error if ERRNO is non-zero */
+#define QPID_POSIX_THROW_IF(ERRNO) \
+ do { int e=(ERRNO); if (e) throw QPID_POSIX_ERROR(e); } while(0)
+
+/** Same as _THROW_IF in a release build, but abort a debug build */
+#ifdef NDEBUG
+#define QPID_POSIX_ASSERT_THROW_IF(ERRNO) QPID_POSIX_THROW_IF(ERRNO)
+#else
+#define QPID_POSIX_ASSERT_THROW_IF(ERRNO) \
+ do { int e=(ERRNO); if (e) { errno=e; ::perror(0); assert(0); } } while(0)
+#endif
+
+#define QPID_POSIX_ABORT_IF(ERRNO) if ((int) ERRNO) { errno=ERRNO; ::perror(0); abort(); }
+
+#endif /*!_posix_check_h*/
diff --git a/cpp/include/qpid/sys/windows/Condition.h b/cpp/include/qpid/sys/windows/Condition.h
new file mode 100755
index 0000000000..979fae9b0a
--- /dev/null
+++ b/cpp/include/qpid/sys/windows/Condition.h
@@ -0,0 +1,80 @@
+#ifndef _sys_windows_Condition_h
+#define _sys_windows_Condition_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Time.h"
+
+#include <time.h>
+#include <boost/noncopyable.hpp>
+#include <boost/thread/condition.hpp>
+#include <boost/thread/thread_time.hpp>
+#include <windows.h>
+
+namespace qpid {
+namespace sys {
+
+// Private Time related implementation details
+void toPtime(boost::posix_time::ptime& pt, const AbsTime& t);
+
+/**
+ * A condition variable for thread synchronization.
+ */
+class Condition : private boost::noncopyable
+{
+ public:
+ inline Condition();
+ inline ~Condition();
+ inline void wait(Mutex&);
+ inline bool wait(Mutex&, const AbsTime& absoluteTime);
+ inline void notify();
+ inline void notifyAll();
+
+ private:
+ boost::condition_variable_any condition;
+};
+
+Condition::Condition() {
+}
+
+Condition::~Condition() {
+}
+
+void Condition::wait(Mutex& mutex) {
+ condition.wait(mutex.mutex);
+}
+
+bool Condition::wait(Mutex& mutex, const AbsTime& absoluteTime){
+ return condition.timed_wait(mutex.mutex, absoluteTime.getPrivate());
+}
+
+void Condition::notify(){
+ condition.notify_one();
+}
+
+void Condition::notifyAll(){
+ condition.notify_all();
+}
+
+}}
+#endif /*!_sys_windows_Condition_h*/
diff --git a/cpp/include/qpid/sys/windows/IntegerTypes.h b/cpp/include/qpid/sys/windows/IntegerTypes.h
new file mode 100755
index 0000000000..ece1a618e9
--- /dev/null
+++ b/cpp/include/qpid/sys/windows/IntegerTypes.h
@@ -0,0 +1,36 @@
+#ifndef QPID_SYS_WINDOWS_INTEGERTYPES_H
+#define QPID_SYS_WINDOWS_INTEGERTYPES_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+typedef unsigned char uint8_t;
+typedef char int8_t;
+typedef unsigned short uint16_t;
+typedef short int16_t;
+typedef unsigned int uint32_t;
+typedef int int32_t;
+typedef unsigned __int64 uint64_t;
+typedef __int64 int64_t;
+
+// Visual Studio doesn't define other common types, so set them up here too.
+typedef unsigned int uint;
+
+#endif /*!QPID_SYS_WINDOWS_INTEGERTYPES_H*/
diff --git a/cpp/include/qpid/sys/windows/Mutex.h b/cpp/include/qpid/sys/windows/Mutex.h
new file mode 100755
index 0000000000..5dcc69e836
--- /dev/null
+++ b/cpp/include/qpid/sys/windows/Mutex.h
@@ -0,0 +1,188 @@
+#ifndef _sys_windows_Mutex_h
+#define _sys_windows_Mutex_h
+
+/*
+ *
+ * Copyright (c) 2008 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/sys/windows/check.h"
+
+#include <boost/version.hpp>
+#if (BOOST_VERSION < 103500)
+#error The Windows port requires Boost version 1.35.0 or later
+#endif
+
+#include <boost/noncopyable.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+#include <boost/thread/shared_mutex.hpp>
+#include <boost/thread/thread_time.hpp>
+#include <boost/thread/tss.hpp>
+
+namespace qpid {
+namespace sys {
+
+class Condition;
+
+/**
+ * Mutex lock.
+ */
+class Mutex : private boost::noncopyable {
+ friend class Condition;
+
+public:
+ typedef ::qpid::sys::ScopedLock<Mutex> ScopedLock;
+ typedef ::qpid::sys::ScopedUnlock<Mutex> ScopedUnlock;
+
+ inline Mutex();
+ inline ~Mutex();
+ inline void lock();
+ inline void unlock();
+ inline bool trylock();
+
+
+protected:
+ boost::recursive_mutex mutex;
+};
+
+/**
+ * RW lock.
+ */
+class RWlock : private boost::noncopyable {
+ friend class Condition;
+
+public:
+ typedef ::qpid::sys::ScopedRlock<RWlock> ScopedRlock;
+ typedef ::qpid::sys::ScopedWlock<RWlock> ScopedWlock;
+
+ inline RWlock();
+ inline ~RWlock();
+ inline void wlock(); // will write-lock
+ inline void rlock(); // will read-lock
+ inline void unlock();
+ inline void trywlock(); // will write-try
+ inline void tryrlock(); // will read-try
+
+protected:
+ boost::shared_mutex rwMutex;
+ boost::thread_specific_ptr<bool> haveWrite;
+
+ inline bool &write (void);
+};
+
+
+/**
+ * PODMutex is a POD, can be static-initialized with
+ * PODMutex m = QPID_PODMUTEX_INITIALIZER
+ */
+struct PODMutex
+{
+ typedef ::qpid::sys::ScopedLock<PODMutex> ScopedLock;
+
+ inline void lock();
+ inline void unlock();
+ inline bool trylock();
+
+ // Must be public to be a POD:
+ boost::recursive_mutex mutex;
+};
+
+#define QPID_MUTEX_INITIALIZER 0
+
+void PODMutex::lock() {
+ mutex.lock();
+}
+
+void PODMutex::unlock() {
+ mutex.unlock();
+}
+
+bool PODMutex::trylock() {
+ return mutex.try_lock();
+}
+
+Mutex::Mutex() {
+}
+
+Mutex::~Mutex(){
+}
+
+void Mutex::lock() {
+ mutex.lock();
+}
+
+void Mutex::unlock() {
+ mutex.unlock();
+}
+
+bool Mutex::trylock() {
+ return mutex.try_lock();
+}
+
+
+RWlock::RWlock() {
+}
+
+RWlock::~RWlock(){
+}
+
+void RWlock::wlock() {
+ bool &writer = write();
+ rwMutex.lock();
+ writer = true; // Remember this thread has write lock held.
+}
+
+void RWlock::rlock() {
+ bool &writer = write();
+ rwMutex.lock_shared();
+ writer = false; // Remember this thread has shared lock held.
+}
+
+void RWlock::unlock() {
+ bool &writer = write();
+ if (writer)
+ rwMutex.unlock();
+ else
+ rwMutex.unlock_shared();
+}
+
+void RWlock::trywlock() {
+ bool &writer = write();
+ // shared_mutex::try_lock() seems to not be available... emulate it with
+ // a timed lock().
+ boost::system_time now = boost::get_system_time();
+ if (rwMutex.timed_lock(now))
+ writer = true;
+}
+
+void RWlock::tryrlock() {
+ bool &writer = write();
+ if (rwMutex.try_lock_shared())
+ writer = false;
+}
+
+bool & RWlock::write (void) {
+ // Accessing thread-specific and stack-local info, so no locks needed.
+ bool *writePtr = haveWrite.get();
+ if (writePtr == 0) {
+ writePtr = new bool(false);
+ haveWrite.reset(writePtr);
+ }
+ return *writePtr;
+}
+
+}}
+#endif /*!_sys_windows_Mutex_h*/
diff --git a/cpp/include/qpid/sys/windows/Time.h b/cpp/include/qpid/sys/windows/Time.h
new file mode 100644
index 0000000000..2987b1c8b2
--- /dev/null
+++ b/cpp/include/qpid/sys/windows/Time.h
@@ -0,0 +1,36 @@
+#ifndef QPID_SYS_WINDOWS_TIME_H
+#define QPID_SYS_WINDOWS_TIME_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Class to represent an instant in time. Boost has this stuff already done
+ * so just reuse it. We can also grab this for quick use with the Condition
+ * wait operations.
+ */
+typedef boost::posix_time::ptime TimePrivate;
+
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_WINDOWS_TIME_H*/
diff --git a/cpp/include/qpid/sys/windows/check.h b/cpp/include/qpid/sys/windows/check.h
new file mode 100755
index 0000000000..aba38814b2
--- /dev/null
+++ b/cpp/include/qpid/sys/windows/check.h
@@ -0,0 +1,48 @@
+#ifndef _windows_check_h
+#define _windows_check_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Exception.h"
+#include "qpid/sys/StrError.h"
+
+#define QPID_WINDOWS_ERROR(ERRVAL) qpid::Exception(QPID_MSG(qpid::sys::strError(ERRVAL)))
+#define QPID_WINDOWS_CRT_ERROR(ERRNO) qpid::Exception(QPID_MSG(qpid::sys::strError(ERRNO)))
+
+/** THROW QPID_WINDOWS_ERROR(::GetLastError()) if RESULT is NULL */
+#define QPID_WINDOWS_CHECK_NULL(RESULT) \
+ if ((RESULT) == NULL) throw QPID_WINDOWS_ERROR((::GetLastError()))
+
+#define QPID_WINDOWS_CHECK_NOT(RESULT,VAL) \
+ if ((RESULT) == (VAL)) throw QPID_WINDOWS_ERROR((::GetLastError()))
+
+#define QPID_WINDOWS_CHECK_ASYNC_START(STATUS) \
+ if (!(STATUS) && ::WSAGetLastError() != ERROR_IO_PENDING) \
+ throw QPID_WINDOWS_ERROR((::WSAGetLastError()))
+
+#define QPID_WINDOWS_CHECK_CRT_NZ(VAL) \
+ if ((VAL) == 0) throw QPID_WINDOWS_CRT_ERROR(errno)
+
+#define QPID_WINSOCK_CHECK(OP) \
+ if ((OP) == SOCKET_ERROR) throw QPID_WINDOWS_ERROR((::WSAGetLastError()))
+
+#endif /*!_windows_check_h*/
diff --git a/cpp/m4/ac_pkg_swig.m4 b/cpp/m4/ac_pkg_swig.m4
new file mode 100644
index 0000000000..3bff433f80
--- /dev/null
+++ b/cpp/m4/ac_pkg_swig.m4
@@ -0,0 +1,118 @@
+# ===========================================================================
+# http://www.nongnu.org/autoconf-archive/ac_pkg_swig.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AC_PROG_SWIG([major.minor.micro])
+#
+# DESCRIPTION
+#
+# This macro searches for a SWIG installation on your system. If found you
+# should call SWIG via $(SWIG). You can use the optional first argument to
+# check if the version of the available SWIG is greater than or equal to
+# the value of the argument. It should have the format: N[.N[.N]] (N is a
+# number between 0 and 999. Only the first N is mandatory.)
+#
+# If the version argument is given (e.g. 1.3.17), AC_PROG_SWIG checks that
+# the swig package is this version number or higher.
+#
+# In configure.in, use as:
+#
+# AC_PROG_SWIG(1.3.17)
+# SWIG_ENABLE_CXX
+# SWIG_MULTI_MODULE_SUPPORT
+# SWIG_PYTHON
+#
+# LICENSE
+#
+# Copyright (c) 2008 Sebastian Huber <sebastian-huber@web.de>
+# Copyright (c) 2008 Alan W. Irwin <irwin@beluga.phys.uvic.ca>
+# Copyright (c) 2008 Rafael Laboissiere <rafael@laboissiere.net>
+# Copyright (c) 2008 Andrew Collier <colliera@ukzn.ac.za>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright owner
+# gives unlimited permission to copy, distribute and modify the configure
+# scripts that are the output of Autoconf when processing the Macro. You
+# need not follow the terms of the GNU General Public License when using
+# or distributing such scripts, even though portions of the text of the
+# Macro appear in them. The GNU General Public License (GPL) does govern
+# all other use of the material that constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the Autoconf
+# Macro released by the Autoconf Archive. When you make and distribute a
+# modified version of the Autoconf Macro, you may extend this special
+# exception to the GPL to apply to your modified version as well.
+
+AC_DEFUN([AC_PROG_SWIG],[
+ AC_PATH_PROG([SWIG],[swig])
+ if test -z "$SWIG" ; then
+ AC_MSG_WARN([cannot find 'swig' program. You should look at http://www.swig.org])
+ SWIG='echo "Error: SWIG is not installed. You should look at http://www.swig.org" ; false'
+ elif test -n "$1" ; then
+ AC_MSG_CHECKING([for SWIG version])
+ [swig_version=`$SWIG -version 2>&1 | grep 'SWIG Version' | sed 's/.*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/g'`]
+ AC_MSG_RESULT([$swig_version])
+ if test -n "$swig_version" ; then
+ # Calculate the required version number components
+ [required=$1]
+ [required_major=`echo $required | sed 's/[^0-9].*//'`]
+ if test -z "$required_major" ; then
+ [required_major=0]
+ fi
+ [required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
+ [required_minor=`echo $required | sed 's/[^0-9].*//'`]
+ if test -z "$required_minor" ; then
+ [required_minor=0]
+ fi
+ [required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
+ [required_patch=`echo $required | sed 's/[^0-9].*//'`]
+ if test -z "$required_patch" ; then
+ [required_patch=0]
+ fi
+ # Calculate the available version number components
+ [available=$swig_version]
+ [available_major=`echo $available | sed 's/[^0-9].*//'`]
+ if test -z "$available_major" ; then
+ [available_major=0]
+ fi
+ [available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
+ [available_minor=`echo $available | sed 's/[^0-9].*//'`]
+ if test -z "$available_minor" ; then
+ [available_minor=0]
+ fi
+ [available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
+ [available_patch=`echo $available | sed 's/[^0-9].*//'`]
+ if test -z "$available_patch" ; then
+ [available_patch=0]
+ fi
+ if test $available_major -ne $required_major \
+ -o $available_minor -ne $required_minor \
+ -o $available_patch -lt $required_patch ; then
+ AC_MSG_WARN([SWIG version >= $1 is required. You have $swig_version. You should look at http://www.swig.org])
+ SWIG='echo "Error: SWIG version >= $1 is required. You have '"$swig_version"'. You should look at http://www.swig.org" ; false'
+ else
+ AC_MSG_NOTICE([SWIG executable is '$SWIG'])
+ SWIG_LIB=`$SWIG -swiglib`
+ AC_MSG_NOTICE([SWIG library directory is '$SWIG_LIB'])
+ fi
+ else
+ AC_MSG_WARN([cannot determine SWIG version])
+ SWIG='echo "Error: Cannot determine SWIG version. You should look at http://www.swig.org" ; false'
+ fi
+ fi
+ AC_SUBST([SWIG_LIB])
+])
diff --git a/cpp/m4/extensions.m4 b/cpp/m4/extensions.m4
index 143a9e5403..fe7398b046 100644
--- a/cpp/m4/extensions.m4
+++ b/cpp/m4/extensions.m4
@@ -1,7 +1,7 @@
-# serial 4 -*- Autoconf -*-
+# serial 5 -*- Autoconf -*-
# Enable extensions on systems that normally disable them.
-# Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+# Copyright (C) 2003, 2006, 2008 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -16,6 +16,7 @@
# ------------------------
# Enable extensions on systems that normally disable them,
# typically due to standards-conformance issues.
+m4_ifdef([AC_USE_SYSTEM_EXTENSIONS], [], [
AC_DEFUN([AC_USE_SYSTEM_EXTENSIONS],
[
AC_BEFORE([$0], [AC_COMPILE_IFELSE])
@@ -48,7 +49,7 @@ AC_DEFUN([AC_USE_SYSTEM_EXTENSIONS],
AC_DEFINE([__EXTENSIONS__])
AC_DEFINE([_POSIX_PTHREAD_SEMANTICS])
AC_DEFINE([_TANDEM_SOURCE])
-])
+])])
# gl_USE_SYSTEM_EXTENSIONS
# ------------------------
diff --git a/cpp/m4/python.m4 b/cpp/m4/python.m4
new file mode 100644
index 0000000000..229fd5547b
--- /dev/null
+++ b/cpp/m4/python.m4
@@ -0,0 +1,168 @@
+## ------------------------ -*- Autoconf -*-
+## Python file handling
+## From Andrew Dalke
+## Updated by James Henstridge
+## ------------------------
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PATH_PYTHON([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+# ---------------------------------------------------------------------------
+# Adds support for distributing Python modules and packages. To
+# install modules, copy them to $(pythondir), using the python_PYTHON
+# automake variable. To install a package with the same name as the
+# automake package, install to $(pkgpythondir), or use the
+# pkgpython_PYTHON automake variable.
+#
+# The variables $(pyexecdir) and $(pkgpyexecdir) are provided as
+# locations to install python extension modules (shared libraries).
+# Another macro is required to find the appropriate flags to compile
+# extension modules.
+#
+# If your package is configured with a different prefix to python,
+# users will have to add the install directory to the PYTHONPATH
+# environment variable, or create a .pth file (see the python
+# documentation for details).
+#
+# If the MINIMUM-VERSION argument is passed, AM_PATH_PYTHON will
+# cause an error if the version of python installed on the system
+# doesn't meet the requirement. MINIMUM-VERSION should consist of
+# numbers and dots only.
+AC_DEFUN([AM_PATH_PYTHON],
+ [
+ dnl Find a Python interpreter. Python versions prior to 1.5 are not
+ dnl supported because the default installation locations changed from
+ dnl $prefix/lib/site-python in 1.4 to $prefix/lib/python1.5/site-packages
+ dnl in 1.5.
+ m4_define_default([_AM_PYTHON_INTERPRETER_LIST],
+ [python python2 python2.5 python2.4 python2.3 python2.2 dnl
+python2.1 python2.0 python1.6 python1.5])
+
+ m4_if([$1],[],[
+ dnl No version check is needed.
+ # Find any Python interpreter.
+ if test -z "$PYTHON"; then
+ AC_PATH_PROGS([PYTHON], _AM_PYTHON_INTERPRETER_LIST, :)
+ fi
+ am_display_PYTHON=python
+ ], [
+ dnl A version check is needed.
+ if test -n "$PYTHON"; then
+ # If the user set $PYTHON, use it and don't search something else.
+ AC_MSG_CHECKING([whether $PYTHON version >= $1])
+ AM_PYTHON_CHECK_VERSION([$PYTHON], [$1],
+ [AC_MSG_RESULT(yes)],
+ [AC_MSG_ERROR(too old)])
+ am_display_PYTHON=$PYTHON
+ else
+ # Otherwise, try each interpreter until we find one that satisfies
+ # VERSION.
+ AC_CACHE_CHECK([for a Python interpreter with version >= $1],
+ [am_cv_pathless_PYTHON],[
+ for am_cv_pathless_PYTHON in _AM_PYTHON_INTERPRETER_LIST none; do
+ test "$am_cv_pathless_PYTHON" = none && break
+ AM_PYTHON_CHECK_VERSION([$am_cv_pathless_PYTHON], [$1], [break])
+ done])
+ # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON.
+ if test "$am_cv_pathless_PYTHON" = none; then
+ PYTHON=:
+ else
+ AC_PATH_PROG([PYTHON], [$am_cv_pathless_PYTHON])
+ fi
+ am_display_PYTHON=$am_cv_pathless_PYTHON
+ fi
+ ])
+
+ if test "$PYTHON" = :; then
+ dnl Run any user-specified action, or abort.
+ m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])])
+ else
+
+ dnl Query Python for its version number. Getting [:3] seems to be
+ dnl the best way to do this; it's what "site.py" does in the standard
+ dnl library.
+
+ AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version],
+ [am_cv_python_version=`$PYTHON -c "import sys; print sys.version[[:3]]"`])
+ AC_SUBST([PYTHON_VERSION], [$am_cv_python_version])
+
+ dnl Use the values of $prefix and $exec_prefix for the corresponding
+ dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made
+ dnl distinct variables so they can be overridden if need be. However,
+ dnl general consensus is that you shouldn't need this ability.
+
+ AC_SUBST([PYTHON_PREFIX], ['${prefix}'])
+ AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}'])
+
+ dnl At times (like when building shared libraries) you may want
+ dnl to know which OS platform Python thinks this is.
+
+ AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform],
+ [am_cv_python_platform=`$PYTHON -c "import sys; print sys.platform"`])
+ AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform])
+
+
+ dnl Set up 4 directories:
+
+ dnl pythondir -- where to install python scripts. This is the
+ dnl site-packages directory, not the python standard library
+ dnl directory like in previous automake betas. This behavior
+ dnl is more consistent with lispdir.m4 for example.
+ dnl Query distutils for this directory. distutils does not exist in
+ dnl Python 1.5, so we fall back to the hardcoded directory if it
+ dnl doesn't work.
+ AC_CACHE_CHECK([for $am_display_PYTHON script directory],
+ [am_cv_python_pythondir],
+ [am_cv_python_pythondir=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_python_lib(0,0,prefix='$PYTHON_PREFIX')" 2>/dev/null ||
+ echo "$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages"`])
+ AC_SUBST([pythondir], [$am_cv_python_pythondir])
+
+ dnl pkgpythondir -- $PACKAGE directory under pythondir. Was
+ dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is
+ dnl more consistent with the rest of automake.
+
+ AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE])
+
+ dnl pyexecdir -- directory for installing python extension modules
+ dnl (shared libraries)
+ dnl Query distutils for this directory. distutils does not exist in
+ dnl Python 1.5, so we fall back to the hardcoded directory if it
+ dnl doesn't work.
+ AC_CACHE_CHECK([for $am_display_PYTHON extension module directory],
+ [am_cv_python_pyexecdir],
+ [am_cv_python_pyexecdir=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_python_lib(1,0,prefix='$PYTHON_EXEC_PREFIX')" 2>/dev/null ||
+ echo "${PYTHON_EXEC_PREFIX}/lib/python${PYTHON_VERSION}/site-packages"`])
+ AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir])
+
+ dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE)
+
+ AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE])
+
+ dnl Run any user-specified action.
+ $2
+ fi
+
+])
+
+
+# AM_PYTHON_CHECK_VERSION(PROG, VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
+# ---------------------------------------------------------------------------
+# Run ACTION-IF-TRUE if the Python interpreter PROG has version >= VERSION.
+# Run ACTION-IF-FALSE otherwise.
+# This test uses sys.hexversion instead of the string equivalent (first
+# word of sys.version), in order to cope with versions such as 2.2c1.
+# hexversion has been introduced in Python 1.5.2; it's probably not
+# worth to support older versions (1.5.1 was released on October 31, 1998).
+AC_DEFUN([AM_PYTHON_CHECK_VERSION],
+ [prog="import sys, string
+# split strings by '.' and convert to numeric. Append some zeros
+# because we need at least 4 digits for the hex conversion.
+minver = map(int, string.split('$2', '.')) + [[0, 0, 0]]
+minverhex = 0
+for i in xrange(0, 4): minverhex = (minverhex << 8) + minver[[i]]
+sys.exit(sys.hexversion < minverhex)"
+ AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])])
diff --git a/cpp/make-dist b/cpp/make-dist
index c23cad63a1..a0c02402e5 100755
--- a/cpp/make-dist
+++ b/cpp/make-dist
@@ -1,4 +1,26 @@
#!/bin/bash
+
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+
#
# Temporary hack for producing a binary dev distribution.
# Includes regular stuff from 'make install' + examples and headers.
diff --git a/cpp/managementgen/CMakeLists.txt b/cpp/managementgen/CMakeLists.txt
new file mode 100644
index 0000000000..2511b745a3
--- /dev/null
+++ b/cpp/managementgen/CMakeLists.txt
@@ -0,0 +1,26 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+project(qpidc-qmfgen)
+cmake_minimum_required(VERSION 2.4.0 FATAL_ERROR)
+
+install(PROGRAMS qmf-gen DESTINATION managementgen
+ COMPONENT ${QPID_COMPONENT_QMF})
+install(DIRECTORY qmfgen DESTINATION managementgen
+ COMPONENT ${QPID_COMPONENT_QMF}
+ PATTERN ".svn" EXCLUDE PATTERN "*.pyc" EXCLUDE)
diff --git a/cpp/managementgen/Makefile.am b/cpp/managementgen/Makefile.am
index 993eeb1d20..7f85834093 100644
--- a/cpp/managementgen/Makefile.am
+++ b/cpp/managementgen/Makefile.am
@@ -1,27 +1,36 @@
-managementgendir = $(datadir)/managementgen
-dist_managementgen_SCRIPTS = \
- main.py
-nobase_managementgen_DATA = \
- schema.py generate.py \
- templates/Args.h \
- templates/Class.cpp \
- templates/Class.h \
- templates/Makefile.mk \
- templates/Package.cpp \
- templates/Package.h \
- management-types.xml
-
-dist_bin_SCRIPTS = managementgen
-
-EXTRA_DIST = $(nobase_managementgen_DATA)
-
-# This should depend on ../../specs/management-types.xml, but can't
-# because it won't exist in a dist. This rule means that dist-gzip
-# (and rpmbuild) cannot be run purely on the cpp/ directory, the
-# cpp/../specs/ directory must exist, which is not a new dependency
-# but this is an additional instance of the dependency.
#
-# WARNING: Because this target does not have a proper dependency
-# changes to the specs/management-types.xml will not be picked up!
-management-types.xml:
- cp $(top_srcdir)/../specs/management-types.xml .
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+qmfpythondir = $(pythondir)
+dist_bin_SCRIPTS = \
+ qmf-gen
+nobase_qmfpython_DATA = \
+ qmfgen/__init__.py \
+ qmfgen/generate.py \
+ qmfgen/schema.py \
+ qmfgen/templates/Args.h \
+ qmfgen/templates/Class.cpp \
+ qmfgen/templates/Class.h \
+ qmfgen/templates/Event.cpp \
+ qmfgen/templates/Event.h \
+ qmfgen/templates/Makefile.mk \
+ qmfgen/templates/Package.cpp \
+ qmfgen/templates/Package.h \
+ qmfgen/management-types.xml
+
+EXTRA_DIST = $(nobase_qmfpython_DATA) CMakeLists.txt
diff --git a/cpp/managementgen/generate.py b/cpp/managementgen/generate.py
deleted file mode 100755
index 6024173f67..0000000000
--- a/cpp/managementgen/generate.py
+++ /dev/null
@@ -1,300 +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.
-#
-
-from xml.dom.minidom import parse, parseString, Node
-from cStringIO import StringIO
-from stat import *
-from errno import *
-import os
-import os.path
-import filecmp
-
-class Template:
- """
- Expandable File Template - This class is instantiated each time a
- template is to be expanded. It is instantiated with the "filename"
- which is the full path to the template file and the "handler" which
- is an object that is responsible for storing variables (setVariable),
- checking conditions (testCondition), and expanding tags (substHandler).
- """
- def __init__ (self, filename, handler):
- self.filename = filename
- self.handler = handler
- self.handler.initExpansion ()
- self.writing = True
-
- def expandLine (self, line, stream, object):
- cursor = 0
- while 1:
- sub = line.find ("/*MGEN:", cursor)
- if sub == -1:
- if self.writing:
- stream.write (line[cursor:len (line)])
- return
-
- subend = line.find("*/", sub)
- if self.writing:
- stream.write (line[cursor:sub])
- cursor = subend + 2
-
- tag = line[sub:subend]
-
- if tag[7:10] == "IF(":
- close = tag.find(")")
- if close == -1:
- raise ValueError ("Missing ')' on condition")
- cond = tag[10:close]
- dotPos = cond.find (".")
- if dotPos == -1:
- raise ValueError ("Invalid condition tag: %s" % cond)
- tagObject = cond[0:dotPos]
- tagName = cond[dotPos + 1 : len(cond)]
- if not self.handler.testCondition(object, tagObject, tagName):
- self.writing = False
-
- elif tag[7:12] == "ENDIF":
- self.writing = True
-
- else:
- equalPos = tag.find ("=")
- if equalPos == -1:
- dotPos = tag.find (".")
- if dotPos == -1:
- raise ValueError ("Invalid tag: %s" % tag)
- tagObject = tag[7:dotPos]
- tagName = tag[dotPos + 1:len (tag)]
- if self.writing:
- self.handler.substHandler (object, stream, tagObject, tagName)
- else:
- tagKey = tag[7:equalPos]
- tagVal = tag[equalPos + 1:len (tag)]
- if self.writing:
- self.handler.setVariable (tagKey, tagVal)
-
- def expand (self, object):
- fd = open (self.filename)
- stream = StringIO ()
-
- for line in fd:
- self.expandLine (line, stream, object)
- fd.close ()
-
- return stream
-
-
-class Makefile:
- """ Object representing a makefile fragment """
- def __init__ (self, filelists, templateFiles):
- self.filelists = filelists
- self.templateFiles = templateFiles
-
- def genGenSources (self, stream, variables):
- mdir = variables["mgenDir"]
- sdir = variables["specDir"]
- stream.write (mdir + "/main.py \\\n")
- stream.write (" " + mdir + "/generate.py \\\n")
- stream.write (" " + mdir + "/schema.py \\\n")
- stream.write (" " + sdir + "/management-types.xml \\\n")
- stream.write (" " + sdir + "/management-schema.xml \\\n")
- first = True
- for template in self.templateFiles:
- if first:
- first = False
- stream.write (" ")
- else:
- stream.write (" \\\n ")
- stream.write (mdir + "/templates/" + template)
-
- def genGenCppFiles (self, stream, variables):
- first = True
- for file in self.filelists["cpp"]:
- if first:
- first = False
- else:
- stream.write (" \\\n ")
- stream.write (file)
-
- def genGenHFiles (self, stream, variables):
- first = True
- for file in self.filelists["h"]:
- if first:
- first = False
- else:
- stream.write (" \\\n ")
- stream.write (file)
-
-
-class Generator:
- """
- This class manages code generation using template files. It is instantiated
- once for an entire code generation session.
- """
- def createPath (self, path):
- exists = True
- try:
- mode = os.stat (path)[ST_MODE]
- except OSError, (err,text):
- if err == ENOENT:
- exists = False
- else:
- raise
- if exists and not S_ISDIR (mode):
- raise ValueError ("path is not directory: %s" % path)
- if not exists:
- pair = os.path.split (path)
- if pair[0] != '':
- self.createPath (pair[0])
- os.mkdir (path)
-
- def normalize (self, path):
- newpath = os.path.normcase (os.path.normpath (path))
- self.createPath (newpath)
- return newpath + "/"
-
- def __init__ (self, destDir, templateDir):
- self.dest = self.normalize (destDir)
- self.input = self.normalize (templateDir)
- self.filelists = {}
- self.filelists["h"] = []
- self.filelists["cpp"] = []
- self.filelists["mk"] = []
- self.templateFiles = []
- self.variables = {}
-
- def genDisclaimer (self, stream, variables):
- prefix = variables["commentPrefix"]
- stream.write (prefix + " This source file was created by a code generator.\n")
- stream.write (prefix + " Please do not edit.")
-
- def fileExt (self, path):
- dot = path.rfind (".")
- if dot == -1:
- return ""
- return path[dot + 1:]
-
- def writeIfChanged (self, stream, target, force=False):
- ext = self.fileExt (target)
- self.filelists[ext].append (target)
- tempFile = self.dest + "gen.tmp"
- fd = open (tempFile, "w")
- fd.write (stream.getvalue ())
- fd.close ()
-
- try:
- if not force and filecmp.cmp (target, tempFile):
- os.remove (tempFile)
- return
- except:
- pass
-
- try:
- os.remove (target)
- except:
- pass
-
- os.rename (tempFile, target)
- print "Generated:", target
-
- def targetPackageFile (self, schema, templateFile):
- dot = templateFile.find(".")
- if dot == -1:
- raise ValueError ("Invalid template file name %s" % templateFile)
- extension = templateFile[dot:len (templateFile)]
- path = self.dest + "Package" + schema.getPackageNameCap() + extension
- return path
-
- def targetClassFile (self, _class, templateFile):
- dot = templateFile.find(".")
- if dot == -1:
- raise ValueError ("Invalid template file name %s" % templateFile)
- extension = templateFile[dot:len (templateFile)]
- path = self.dest + _class.getNameCap () + extension
- return path
-
- def targetMethodFile (self, method, templateFile):
- """ Return the file name for a method file """
- dot = templateFile.rfind(".")
- if dot == -1:
- raise ValueError ("Invalid template file name %s" % templateFile)
- extension = templateFile[dot:]
- path = self.dest + "Args" + method.getFullName () + extension
- return path
-
- def initExpansion (self):
- self.variables = {}
-
- def substHandler (self, object, stream, tagObject, tag):
- if tagObject == "Root":
- obj = "self"
- else:
- obj = "object" # MUST be the same as the 2nd formal parameter
-
- call = obj + ".gen" + tag + "(stream, self.variables)"
- eval (call)
-
- def testCondition (self, object, tagObject, tag):
- if tagObject == "Root":
- obj = "self"
- else:
- obj = "object" # MUST be the same as the 2nd formal parameter
-
- call = obj + ".test" + tag + "(self.variables)"
- return eval (call)
-
- def setVariable (self, key, value):
- self.variables[key] = value
-
- def makeClassFiles (self, templateFile, schema, force=False):
- """ Generate an expanded template per schema class """
- classes = schema.getClasses ()
- template = Template (self.input + templateFile, self)
- self.templateFiles.append (templateFile)
- for _class in classes:
- target = self.targetClassFile (_class, templateFile)
- stream = template.expand (_class)
- self.writeIfChanged (stream, target, force)
-
- def makeMethodFiles (self, templateFile, schema, force=False):
- """ Generate an expanded template per method-with-arguments """
- classes = schema.getClasses ()
- template = Template (self.input + templateFile, self)
- self.templateFiles.append (templateFile)
- for _class in classes:
- methods = _class.getMethods ()
- for method in methods:
- if method.getArgCount () > 0:
- target = self.targetMethodFile (method, templateFile)
- stream = template.expand (method)
- self.writeIfChanged (stream, target, force)
-
- def makePackageFile (self, templateFile, schema, force=False):
- """ Generate a package-specific file """
- template = Template (self.input + templateFile, self)
- self.templateFiles.append (templateFile)
- target = self.targetPackageFile (schema, templateFile)
- stream = template.expand (schema)
- self.writeIfChanged (stream, target, force)
-
- def makeSingleFile (self, templateFile, target, force=False):
- """ Generate a single expanded template """
- makefile = Makefile (self.filelists, self.templateFiles)
- template = Template (self.input + templateFile, self)
- self.templateFiles.append (templateFile)
- stream = template.expand (makefile)
- self.writeIfChanged (stream, target, force)
diff --git a/cpp/managementgen/main.py b/cpp/managementgen/main.py
deleted file mode 100755
index 4459177a53..0000000000
--- a/cpp/managementgen/main.py
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env python
-
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http:#www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-from schema import PackageSchema, SchemaClass
-from generate import Generator
-from optparse import OptionParser
-
-# Set command line options
-usage = "usage: %prog [options] schema-document type-document template-directory out-directory"
-parser = OptionParser (usage=usage)
-parser.add_option ("-m", "--makefile", dest="makefile", metavar="FILE",
- help="Makefile fragment")
-
-(opts, args) = parser.parse_args ()
-
-if len (args) < 4:
- parser.error ("Too few arguments")
-
-schemafile = args[0]
-typefile = args[1]
-templatedir = args[2]
-outdir = args[3]
-
-gen = Generator (outdir, templatedir)
-schema = PackageSchema (typefile, schemafile, opts)
-
-gen.makeClassFiles ("Class.h", schema)
-gen.makeClassFiles ("Class.cpp", schema)
-gen.makeMethodFiles ("Args.h", schema)
-gen.makePackageFile ("Package.h", schema)
-gen.makePackageFile ("Package.cpp", schema)
-
-if opts.makefile != None:
- gen.makeSingleFile ("Makefile.mk", opts.makefile, force=True)
diff --git a/cpp/managementgen/managementgen b/cpp/managementgen/managementgen
deleted file mode 100644
index 55ea846270..0000000000
--- a/cpp/managementgen/managementgen
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python
-
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http:#www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-import sys
-
-sys.path.append("/usr/share/managementgen")
-
-import main
diff --git a/cpp/managementgen/qmf-gen b/cpp/managementgen/qmf-gen
new file mode 100755
index 0000000000..ebc07137ae
--- /dev/null
+++ b/cpp/managementgen/qmf-gen
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import sys
+import os
+from qmfgen.schema import SchemaPackage, SchemaClass
+from qmfgen.generate import Generator
+from optparse import OptionParser
+
+dataPath = os.path.dirname(Generator.getModulePath())
+defaultTypeFile = dataPath + "/management-types.xml"
+defaultTemplateDir = dataPath + "/templates"
+
+# Set command line options
+usage = "usage: %prog [options] schema-document..."
+parser = OptionParser(usage=usage)
+parser.add_option("-o", "--outputdir", dest="outputdir", metavar="DIR", default="./",
+ help="Output directory")
+parser.add_option("-c", "--cmakelists", dest="cmakelists", metavar="FILE",
+ help="CMakeLists fragment")
+parser.add_option("-m", "--makefile", dest="makefile", metavar="FILE",
+ help="Makefile fragment")
+parser.add_option("-t", "--typefile", dest="typefile", metavar="FILE", default=defaultTypeFile,
+ help="Override type descriptor file")
+parser.add_option("-d", "--templatedir", dest="templatedir", metavar="DIR", default=defaultTemplateDir,
+ help="Override template directory")
+parser.add_option("-p", "--gen-prefix", dest="genprefix", default="",
+ help="Prefix for generated files in make dependencies")
+parser.add_option("-q", "--qpid-broker", dest="qpidbroker", default=False, action="store_true",
+ help="Generate makefile for Qpid broker")
+parser.add_option("-b", "--broker-plugin", dest="brokerplugin", default=False, action="store_true",
+ help="Generate code for use in a qpid broker plugin")
+
+(opts, args) = parser.parse_args()
+
+typefile = opts.typefile
+templatedir = opts.templatedir
+outdir = opts.outputdir
+gen = Generator(outdir, templatedir)
+
+if len(args) == 0:
+ print "no input files"
+ parser.exit()
+
+vargs = {}
+if opts.brokerplugin:
+ vargs["agentHeaderDir"] = "management"
+else:
+ vargs["agentHeaderDir"] = "agent"
+
+for schemafile in args:
+ package = SchemaPackage(typefile, schemafile, opts)
+
+ gen.setPackage (package.packageName)
+ gen.makeClassFiles ("Class.h", package, vars=vargs)
+ gen.makeClassFiles ("Class.cpp", package, vars=vargs)
+ gen.makeMethodFiles ("Args.h", package, vars=vargs)
+ gen.makeEventFiles ("Event.h", package, vars=vargs)
+ gen.makeEventFiles ("Event.cpp", package, vars=vargs)
+ gen.makePackageFile ("Package.h", package, vars=vargs)
+ gen.makePackageFile ("Package.cpp", package, vars=vargs)
+
+if opts.makefile != None:
+ args = {}
+ args["qpidbroker"] = opts.qpidbroker
+ args["genprefix"] = opts.genprefix
+ gen.makeSingleFile("Makefile.mk", opts.makefile, force=True, vars=args)
+
+if opts.cmakelists != None:
+ args = {}
+ args["qpidbroker"] = opts.qpidbroker
+ args["genprefix"] = opts.genprefix
+ gen.makeSingleFile("CMakeLists.cmake", opts.cmakelists, force=True, vars=args)
diff --git a/cpp/managementgen/qmfgen/__init__.py b/cpp/managementgen/qmfgen/__init__.py
new file mode 100644
index 0000000000..63a3f41f28
--- /dev/null
+++ b/cpp/managementgen/qmfgen/__init__.py
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT 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/managementgen/qmfgen/generate.py b/cpp/managementgen/qmfgen/generate.py
new file mode 100755
index 0000000000..4052b8c853
--- /dev/null
+++ b/cpp/managementgen/qmfgen/generate.py
@@ -0,0 +1,468 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from xml.dom.minidom import parse, parseString, Node
+from cStringIO import StringIO
+from stat import *
+from errno import *
+import os
+import os.path
+import filecmp
+import re
+
+class Template:
+ """
+ Expandable File Template - This class is instantiated each time a
+ template is to be expanded. It is instantiated with the "filename"
+ which is the full path to the template file and the "handler" which
+ is an object that is responsible for storing variables (setVariable),
+ checking conditions (testCondition), and expanding tags (substHandler).
+ """
+ def __init__ (self, filename, handler):
+ self.filename = filename
+ self.handler = handler
+ self.handler.initExpansion ()
+ self.writing = True
+
+ def expandLine (self, line, stream, object):
+ cursor = 0
+ while 1:
+ sub = line.find ("/*MGEN:", cursor)
+ if sub == -1:
+ if self.writing:
+ stream.write (line[cursor:len (line)])
+ return
+
+ subend = line.find("*/", sub)
+ if self.writing:
+ stream.write (line[cursor:sub])
+ cursor = subend + 2
+
+ tag = line[sub:subend]
+
+ if tag[7:10] == "IF(":
+ close = tag.find(")")
+ if close == -1:
+ raise ValueError ("Missing ')' on condition")
+ cond = tag[10:close]
+ dotPos = cond.find (".")
+ if dotPos == -1:
+ raise ValueError ("Invalid condition tag: %s" % cond)
+ tagObject = cond[0:dotPos]
+ tagName = cond[dotPos + 1 : len(cond)]
+ if not self.handler.testCondition(object, tagObject, tagName):
+ self.writing = False
+
+ elif tag[7:12] == "ENDIF":
+ self.writing = True
+
+ else:
+ equalPos = tag.find ("=")
+ if equalPos == -1:
+ dotPos = tag.find (".")
+ if dotPos == -1:
+ raise ValueError ("Invalid tag: %s" % tag)
+ tagObject = tag[7:dotPos]
+ tagName = tag[dotPos + 1:len (tag)]
+ if self.writing:
+ self.handler.substHandler (object, stream, tagObject, tagName)
+ else:
+ tagKey = tag[7:equalPos]
+ tagVal = tag[equalPos + 1:len (tag)]
+ if self.writing:
+ self.handler.setVariable (tagKey, tagVal)
+
+ def expand (self, object):
+ fd = open (self.filename)
+ stream = StringIO ()
+
+ for line in fd:
+ self.expandLine (line, stream, object)
+ fd.close ()
+
+ return stream
+
+
+class Makefile:
+ """ Object representing a makefile fragment """
+ def __init__ (self, filelists, templateFiles, packagelist):
+ self.filelists = filelists
+ self.templateFiles = templateFiles
+ self.packagelist = packagelist
+
+ def genGenSources (self, stream, variables):
+ mdir = variables["mgenDir"]
+ sdir = variables["specDir"]
+ stream.write (mdir + "/qmf-gen \\\n")
+ stream.write (" " + mdir + "/qmfgen/generate.py \\\n")
+ stream.write (" " + mdir + "/qmfgen/schema.py \\\n")
+ stream.write (" " + mdir + "/qmfgen/management-types.xml \\\n")
+ stream.write (" " + sdir + "/management-schema.xml \\\n")
+ first = True
+ for template in self.templateFiles:
+ if first:
+ first = False
+ stream.write (" ")
+ else:
+ stream.write (" \\\n ")
+ stream.write (mdir + "/qmfgen/templates/" + template)
+
+ def genGenCppFiles (self, stream, variables):
+ first = True
+ for file in self.filelists["cpp"]:
+ if first:
+ first = False
+ else:
+ stream.write (" \\\n ")
+ stream.write (file)
+
+ def genGenHFiles (self, stream, variables):
+ first = True
+ for file in self.filelists["h"]:
+ if first:
+ first = False
+ else:
+ stream.write (" \\\n ")
+ stream.write (file)
+
+ def genGeneratedFiles(self, stream, variables):
+ first = True
+ extensions = ("h", "cpp")
+ for ext in extensions:
+ for file in self.filelists[ext]:
+ if first:
+ first = False
+ else:
+ stream.write(" \\\n ")
+ if "genprefix" in variables:
+ prefix = variables["genprefix"]
+ if prefix != "":
+ stream.write(prefix + "/")
+ stream.write(file)
+
+ def genHeaderInstalls (self, stream, variables):
+ for package in self.packagelist:
+ name = "_".join(package.split("/"))
+ stream.write(name + "dir = $(includedir)/qmf/" + package + "\n")
+ stream.write("dist_" + name + "_HEADERS = ")
+ first = True
+ for file in self.filelists["h"]:
+ if file.find("qmf/" + package) == 0:
+ if first:
+ first = False
+ else:
+ stream.write (" \\\n ")
+ stream.write(file)
+ stream.write("\n\n")
+
+ def testQpidBroker(self, variables):
+ if "qpidbroker" in variables:
+ return variables["qpidbroker"]
+ return False
+
+class CMakeLists(Makefile):
+ """ Object representing a makefile fragment """
+
+ # Regardless of what normalize() did, switch all the dir separators back
+ # to '/' - cmake expects that regardless of platform.
+ def unNormCase (self, path):
+ return re.sub("\\\\", "/", path)
+
+ def genGenSources (self, stream, variables):
+ mdir = self.unNormCase(variables["mgenDir"])
+ sdir = self.unNormCase(variables["specDir"])
+ stream.write (mdir + "/qmf-gen \n")
+ stream.write (" " + mdir + "/qmfgen/generate.py\n")
+ stream.write (" " + mdir + "/qmfgen/schema.py\n")
+ stream.write (" " + mdir + "/qmfgen/management-types.xml\n")
+ stream.write (" " + sdir + "/management-schema.xml\n")
+ first = True
+ for template in self.templateFiles:
+ if first:
+ first = False
+ stream.write (" ")
+ else:
+ stream.write ("\n ")
+ stream.write (mdir + "/qmfgen/templates/" + template)
+
+ def genGenCppFiles (self, stream, variables):
+ first = True
+ for file in self.filelists["cpp"]:
+ if first:
+ first = False
+ else:
+ stream.write (" \n ")
+ stream.write (self.unNormCase(file))
+
+ def genGenHFiles (self, stream, variables):
+ first = True
+ for file in self.filelists["h"]:
+ if first:
+ first = False
+ else:
+ stream.write (" \n ")
+ stream.write (self.unNormCase(file))
+
+ def genGeneratedFiles(self, stream, variables):
+ first = True
+ extensions = ("h", "cpp")
+ for ext in extensions:
+ for file in self.filelists[ext]:
+ if first:
+ first = False
+ else:
+ stream.write(" \n ")
+ if "genprefix" in variables:
+ prefix = variables["genprefix"]
+ if prefix != "":
+ stream.write(prefix + "/")
+ stream.write(self.unNormCase(file))
+
+ def genHeaderInstalls (self, stream, variables):
+ for package in self.packagelist:
+ stream.write("#Come back to this later...\n")
+ name = "_".join(package.split("/"))
+ stream.write("#" + name + "dir = $(includedir)/qmf/" + package + "\n")
+ stream.write("#dist_" + name + "_HEADERS = ")
+ first = True
+ for file in self.filelists["h"]:
+ file = self.unNormCase(file)
+ if file.find("qmf/" + package) == 0:
+ if first:
+ first = False
+ else:
+ stream.write ("\n ")
+ stream.write("#" + file)
+ stream.write("\n\n")
+
+
+class Generator:
+ """
+ This class manages code generation using template files. It is instantiated
+ once for an entire code generation session.
+ """
+ def createPath (self, path):
+ exists = True
+ try:
+ mode = os.stat (path)[ST_MODE]
+ except OSError, (err,text):
+ if err == ENOENT or err == ESRCH:
+ exists = False
+ else:
+ raise
+ if exists and not S_ISDIR (mode):
+ raise ValueError ("path is not directory: %s" % path)
+ if not exists:
+ pair = os.path.split (path)
+ if pair[0] != '':
+ self.createPath (pair[0])
+ os.mkdir (path)
+
+ def normalize (self, path):
+ newpath = os.path.normcase (os.path.normpath (path))
+ self.createPath (newpath)
+ return newpath + "/"
+
+ def __init__ (self, destDir, templateDir):
+ self.dest = self.normalize (destDir)
+ self.input = self.normalize (templateDir)
+ self.packagePath = self.dest
+ self.filelists = {}
+ self.filelists["h"] = []
+ self.filelists["cpp"] = []
+ self.filelists["mk"] = []
+ self.filelists["cmake"] = []
+ self.packagelist = []
+ self.templateFiles = []
+ self.variables = {}
+
+ def setPackage (self, packageName):
+ path = "/".join(packageName.split("."))
+ self.packagelist.append(path)
+ self.packagePath = self.normalize(self.dest + path)
+
+ def genDisclaimer (self, stream, variables):
+ prefix = variables["commentPrefix"]
+ stream.write (prefix + " This source file was created by a code generator.\n")
+ stream.write (prefix + " Please do not edit.")
+
+ def fileExt (self, path):
+ dot = path.rfind (".")
+ if dot == -1:
+ return ""
+ return path[dot + 1:]
+
+ def writeIfChanged (self, stream, target, force=False):
+ ext = self.fileExt (target)
+ self.filelists[ext].append (target)
+ tempFile = target + ".gen.tmp"
+ fd = open (tempFile, "w")
+ fd.write (stream.getvalue ())
+ fd.close ()
+
+ try:
+ if not force and filecmp.cmp (target, tempFile):
+ os.remove (tempFile)
+ return
+ except:
+ pass
+
+ try:
+ os.remove (target)
+ except:
+ pass
+
+ os.rename (tempFile, target)
+ print "Generated:", target
+
+ def targetPackageFile (self, schema, templateFile):
+ dot = templateFile.find(".")
+ if dot == -1:
+ raise ValueError ("Invalid template file name %s" % templateFile)
+ extension = templateFile[dot:len (templateFile)]
+ path = self.packagePath + "Package" + extension
+ return path
+
+ def targetClassFile (self, _class, templateFile):
+ dot = templateFile.find(".")
+ if dot == -1:
+ raise ValueError ("Invalid template file name %s" % templateFile)
+ extension = templateFile[dot:len (templateFile)]
+ path = self.packagePath + _class.getNameCap () + extension
+ return path
+
+ def targetEventFile (self, event, templateFile):
+ dot = templateFile.find(".")
+ if dot == -1:
+ raise ValueError ("Invalid template file name %s" % templateFile)
+ extension = templateFile[dot:len (templateFile)]
+ path = self.packagePath + "Event" + event.getNameCap () + extension
+ return path
+
+ def targetMethodFile (self, method, templateFile):
+ """ Return the file name for a method file """
+ dot = templateFile.rfind(".")
+ if dot == -1:
+ raise ValueError ("Invalid template file name %s" % templateFile)
+ extension = templateFile[dot:]
+ path = self.packagePath + "Args" + method.getFullName () + extension
+ return path
+
+ def initExpansion (self):
+ self.variables = {}
+
+ def substHandler (self, object, stream, tagObject, tag):
+ if tagObject == "Root":
+ obj = "self"
+ else:
+ obj = "object" # MUST be the same as the 2nd formal parameter
+
+ call = obj + ".gen" + tag + "(stream, self.variables)"
+ eval (call)
+
+ def testCondition (self, object, tagObject, tag):
+ if tagObject == "Root":
+ obj = "self"
+ else:
+ obj = "object" # MUST be the same as the 2nd formal parameter
+
+ call = obj + ".test" + tag + "(self.variables)"
+ return eval (call)
+
+ def setVariable (self, key, value):
+ self.variables[key] = value
+
+ def makeClassFiles (self, templateFile, schema, force=False, vars=None):
+ """ Generate an expanded template per schema class """
+ classes = schema.getClasses ()
+ template = Template (self.input + templateFile, self)
+ if vars:
+ for arg in vars:
+ self.setVariable(arg, vars[arg])
+ self.templateFiles.append (templateFile)
+ for _class in classes:
+ target = self.targetClassFile (_class, templateFile)
+ stream = template.expand (_class)
+ self.writeIfChanged (stream, target, force)
+
+ def makeEventFiles (self, templateFile, schema, force=False, vars=None):
+ """ Generate an expanded template per schema event """
+ events = schema.getEvents()
+ template = Template (self.input + templateFile, self)
+ if vars:
+ for arg in vars:
+ self.setVariable(arg, vars[arg])
+ self.templateFiles.append (templateFile)
+ for event in events:
+ target = self.targetEventFile(event, templateFile)
+ stream = template.expand(event)
+ self.writeIfChanged(stream, target, force)
+
+ def makeMethodFiles (self, templateFile, schema, force=False, vars=None):
+ """ Generate an expanded template per method-with-arguments """
+ classes = schema.getClasses ()
+ template = Template (self.input + templateFile, self)
+ if vars:
+ for arg in vars:
+ self.setVariable(arg, vars[arg])
+ self.templateFiles.append (templateFile)
+ for _class in classes:
+ methods = _class.getMethods ()
+ for method in methods:
+ if method.getArgCount () > 0:
+ target = self.targetMethodFile (method, templateFile)
+ stream = template.expand (method)
+ self.writeIfChanged (stream, target, force)
+
+ def makePackageFile (self, templateFile, schema, force=False, vars=None):
+ """ Generate a package-specific file """
+ template = Template (self.input + templateFile, self)
+ if vars:
+ for arg in vars:
+ self.setVariable(arg, vars[arg])
+ self.templateFiles.append (templateFile)
+ target = self.targetPackageFile (schema, templateFile)
+ stream = template.expand (schema)
+ self.writeIfChanged (stream, target, force)
+
+ def makeSingleFile (self, templateFile, target, force=False, vars=None):
+ """ Generate a single expanded template """
+ dot = templateFile.find(".")
+ if dot == -1:
+ raise ValueError ("Invalid template file name %s" % templateFile)
+ className = templateFile[0:dot]
+ if className == "Makefile":
+ classType = Makefile
+ elif className == "CMakeLists":
+ classType = CMakeLists
+ else:
+ raise ValueError ("Invalid class name %s" % className)
+ makefile = classType (self.filelists, self.templateFiles, self.packagelist)
+ template = Template (self.input + templateFile, self)
+ if vars:
+ for arg in vars:
+ self.setVariable(arg, vars[arg])
+ self.templateFiles.append (templateFile)
+ stream = template.expand (makefile)
+ self.writeIfChanged (stream, target, force)
+
+ def getModulePath():
+ return __file__
+
+ getModulePath = staticmethod(getModulePath)
diff --git a/cpp/managementgen/qmfgen/management-types.xml b/cpp/managementgen/qmfgen/management-types.xml
new file mode 100644
index 0000000000..626880afb3
--- /dev/null
+++ b/cpp/managementgen/qmfgen/management-types.xml
@@ -0,0 +1,56 @@
+<schema-types>
+
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+
+<type name="objId" base="REF" cpp="::qpid::management::ObjectId" encode="#.encode(@)" decode="#.decode(@)" accessor="direct" init="::qpid::management::ObjectId()" byRef="y"/>
+<type name="uint8" base="U8" cpp="uint8_t" encode="@.putOctet(#)" decode="# = @.getOctet()" accessor="direct" init="0"/>
+<type name="uint16" base="U16" cpp="uint16_t" encode="@.putShort(#)" decode="# = @.getShort()" accessor="direct" init="0"/>
+<type name="uint32" base="U32" cpp="uint32_t" encode="@.putLong(#)" decode="# = @.getLong()" accessor="direct" init="0"/>
+<type name="uint64" base="U64" cpp="uint64_t" encode="@.putLongLong(#)" decode="# = @.getLongLong()" accessor="direct" init="0"/>
+<type name="int8" base="S8" cpp="int8_t" encode="@.putInt8(#)" decode="# = @.getInt8()" accessor="direct" init="0"/>
+<type name="int16" base="S16" cpp="int16_t" encode="@.putInt16(#)" decode="# = @.getInt16()" accessor="direct" init="0"/>
+<type name="int32" base="S32" cpp="int32_t" encode="@.putInt32(#)" decode="# = @.getInt32()" accessor="direct" init="0"/>
+<type name="int64" base="S64" cpp="int64_t" encode="@.putInt64(#)" decode="# = @.getInt64()" accessor="direct" init="0"/>
+<type name="bool" base="BOOL" cpp="uint8_t" encode="@.putOctet(#?1:0)" decode="# = @.getOctet()==1" accessor="direct" init="0"/>
+<type name="sstr" base="SSTR" cpp="std::string" encode="@.putShortString(#)" decode="@.getShortString(#)" accessor="direct" init='""' byRef="y"/>
+<type name="lstr" base="LSTR" cpp="std::string" encode="@.putMediumString(#)" decode="@.getMediumString(#)" accessor="direct" init='""' byRef="y"/>
+<type name="absTime" base="ABSTIME" cpp="int64_t" encode="@.putLongLong(#)" decode="# = @.getLongLong()" accessor="direct" init="0"/>
+<type name="deltaTime" base="DELTATIME" cpp="uint64_t" encode="@.putLongLong(#)" decode="# = @.getLongLong()" accessor="direct" init="0"/>
+<type name="float" base="FLOAT" cpp="float" encode="@.putFloat(#)" decode="# = @.getFloat()" accessor="direct" init="0."/>
+<type name="double" base="DOUBLE" cpp="double" encode="@.putDouble(#)" decode="# = @.getDouble()" accessor="direct" init="0."/>
+<type name="uuid" base="UUID" cpp="::qpid::framing::Uuid" encode="#.encode(@)" decode="#.decode(@)" accessor="direct" init="::qpid::framing::Uuid()" byRef="y"/>
+<type name="map" base="FTABLE" cpp="::qpid::framing::FieldTable" encode="#.encode(@)" decode="#.decode(@)" accessor="direct" init="::qpid::framing::FieldTable()" byRef="y"/>
+
+<type name="hilo8" base="U8" cpp="uint8_t" encode="@.putOctet(#)" decode="# = @.getOctet()" style="wm" accessor="counter" init="0"/>
+<type name="hilo16" base="U16" cpp="uint16_t" encode="@.putShort(#)" decode="# = @.getShort()" style="wm" accessor="counter" init="0"/>
+<type name="hilo32" base="U32" cpp="uint32_t" encode="@.putLong(#)" decode="# = @.getLong()" style="wm" accessor="counter" init="0"/>
+<type name="hilo64" base="U64" cpp="uint64_t" encode="@.putLongLong(#)" decode="# = @.getLongLong()" style="wm" accessor="counter" init="0"/>
+
+<type name="count8" base="U8" cpp="uint8_t" encode="@.putOctet(#)" decode="# = @.getOctet()" accessor="counter" init="0" perThread="y"/>
+<type name="count16" base="U16" cpp="uint16_t" encode="@.putShort(#)" decode="# = @.getShort()" accessor="counter" init="0" perThread="y"/>
+<type name="count32" base="U32" cpp="uint32_t" encode="@.putLong(#)" decode="# = @.getLong()" accessor="counter" init="0" perThread="y"/>
+<type name="count64" base="U64" cpp="uint64_t" encode="@.putLongLong(#)" decode="# = @.getLongLong()" accessor="counter" init="0" perThread="y"/>
+
+<!-- Min/Max/Average statistics -->
+<type name="mma32" base="U32" cpp="uint32_t" encode="@.putLong(#)" decode="# = @.getLong()" style="mma" accessor="direct" init="0" perThread="y"/>
+<type name="mma64" base="U64" cpp="uint64_t" encode="@.putLongLong(#)" decode="# = @.getLongLong()" style="mma" accessor="direct" init="0" perThread="y"/>
+<type name="mmaTime" base="DELTATIME" cpp="uint64_t" encode="@.putLongLong(#)" decode="# = @.getLongLong()" style="mma" accessor="direct" init="0" perThread="y"/>
+
+</schema-types>
diff --git a/cpp/managementgen/qmfgen/schema.py b/cpp/managementgen/qmfgen/schema.py
new file mode 100755
index 0000000000..3b53830c69
--- /dev/null
+++ b/cpp/managementgen/qmfgen/schema.py
@@ -0,0 +1,1348 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from xml.dom.minidom import parse, parseString, Node
+from cStringIO import StringIO
+import md5
+
+class Hash:
+ """ Manage the hash of an XML sub-tree """
+ def __init__(self, node):
+ self.md5Sum = md5.new()
+ self._compute(node)
+
+ def addSubHash(self, hash):
+ """ Use this method to add the hash of a dependend-on XML fragment that is not in the sub-tree """
+ self.md5Sum.update(hash.getDigest())
+
+ def getDigest(self):
+ return self.md5Sum.digest()
+
+ def _compute(self, node):
+ attrs = node.attributes
+ self.md5Sum.update(node.nodeName)
+
+ for idx in range(attrs.length):
+ self.md5Sum.update(attrs.item(idx).nodeName)
+ self.md5Sum.update(attrs.item(idx).nodeValue)
+
+ for child in node.childNodes:
+ if child.nodeType == Node.ELEMENT_NODE:
+ self._compute(child)
+
+
+#=====================================================================================
+#
+#=====================================================================================
+class SchemaType:
+ def __init__ (self, node):
+ self.name = None
+ self.base = None
+ self.cpp = None
+ self.encode = None
+ self.decode = None
+ self.style = "normal"
+ self.accessor = None
+ self.init = "0"
+ self.perThread = False
+ self.byRef = False
+
+ attrs = node.attributes
+ for idx in range (attrs.length):
+ key = attrs.item(idx).nodeName
+ val = attrs.item(idx).nodeValue
+ if key == 'name':
+ self.name = val
+
+ elif key == 'base':
+ self.base = val
+
+ elif key == 'cpp':
+ self.cpp = val
+
+ elif key == 'encode':
+ self.encode = val
+
+ elif key == 'decode':
+ self.decode = val
+
+ elif key == 'style':
+ self.style = val
+
+ elif key == 'accessor':
+ self.accessor = val
+
+ elif key == 'init':
+ self.init = val
+
+ elif key == 'perThread':
+ if val != 'y':
+ raise ValueError ("Expected 'y' in perThread attribute")
+ self.perThread = True
+
+ elif key == 'byRef':
+ if val != 'y':
+ raise ValueError ("Expected 'y' in byRef attribute")
+ self.byRef = True
+
+ else:
+ raise ValueError ("Unknown attribute in type '%s'" % key)
+
+ if self.name == None or self.base == None or self.cpp == None or \
+ self.encode == None or self.decode == None:
+ raise ValueError ("Missing required attribute(s) in type")
+
+ if self.byRef:
+ self.asArg = "const " + self.cpp + "&"
+ else:
+ self.asArg = self.cpp
+
+ def getName (self):
+ return self.name
+
+ def genAccessor (self, stream, varName, changeFlag = None, optional = False):
+ if self.perThread:
+ prefix = "getThreadStats()->"
+ if self.style == "wm":
+ raise ValueError ("'wm' style types can't be per-thread")
+ else:
+ prefix = ""
+ if self.accessor == "direct":
+ stream.write (" inline void set_" + varName + " (" + self.asArg + " val) {\n");
+ if not self.perThread:
+ stream.write (" ::qpid::sys::Mutex::ScopedLock mutex(accessLock);\n")
+ if self.style != "mma":
+ stream.write (" " + prefix + varName + " = val;\n")
+ if optional:
+ stream.write (" presenceMask[presenceByte_%s] |= presenceMask_%s;\n" % (varName, varName))
+ if self.style == "wm":
+ stream.write (" if (" + varName + "Low > val)\n")
+ stream.write (" " + varName + "Low = val;\n")
+ stream.write (" if (" + varName + "High < val)\n")
+ stream.write (" " + varName + "High = val;\n")
+ if self.style == "mma":
+ stream.write (" " + prefix + varName + "Count++;\n")
+ stream.write (" " + prefix + varName + "Total += val;\n")
+ stream.write (" if (" + prefix + varName + "Min > val)\n")
+ stream.write (" " + prefix + varName + "Min = val;\n")
+ stream.write (" if (" + prefix + varName + "Max < val)\n")
+ stream.write (" " + prefix + varName + "Max = val;\n")
+ if changeFlag != None:
+ stream.write (" " + changeFlag + " = true;\n")
+ stream.write (" }\n")
+ if self.style != "mma":
+ stream.write (" inline " + self.asArg + " get_" + varName + "() {\n");
+ if not self.perThread:
+ stream.write (" ::qpid::sys::Mutex::ScopedLock mutex(accessLock);\n")
+ stream.write (" return " + prefix + varName + ";\n")
+ stream.write (" }\n")
+ if optional:
+ stream.write (" inline void clr_" + varName + "() {\n")
+ stream.write (" presenceMask[presenceByte_%s] &= ~presenceMask_%s;\n" % (varName, varName))
+ if changeFlag != None:
+ stream.write (" " + changeFlag + " = true;\n")
+ stream.write (" }\n")
+ stream.write (" inline bool isSet_" + varName + "() {\n")
+ stream.write (" return (presenceMask[presenceByte_%s] & presenceMask_%s) != 0;\n" % (varName, varName))
+ stream.write (" }\n")
+ elif self.accessor == "counter":
+ stream.write (" inline void inc_" + varName + " (" + self.asArg + " by = 1) {\n");
+ if not self.perThread:
+ stream.write (" ::qpid::sys::Mutex::ScopedLock mutex(accessLock);\n")
+ stream.write (" " + prefix + varName + " += by;\n")
+ if self.style == "wm":
+ stream.write (" if (" + varName + "High < " + varName + ")\n")
+ stream.write (" " + varName + "High = " + varName + ";\n")
+ if changeFlag != None:
+ stream.write (" " + changeFlag + " = true;\n")
+ stream.write (" }\n");
+ stream.write (" inline void dec_" + varName + " (" + self.asArg + " by = 1) {\n");
+ if not self.perThread:
+ stream.write (" ::qpid::sys::Mutex::ScopedLock mutex(accessLock);\n")
+ stream.write (" " + prefix + varName + " -= by;\n")
+ if self.style == "wm":
+ stream.write (" if (" + varName + "Low > " + varName + ")\n")
+ stream.write (" " + varName + "Low = " + varName + ";\n")
+ if changeFlag != None:
+ stream.write (" " + changeFlag + " = true;\n")
+ stream.write (" }\n");
+
+ def genHiLoStatResets (self, stream, varName):
+ if self.style == "wm":
+ stream.write (" " + varName + "High = " + varName + ";\n")
+ stream.write (" " + varName + "Low = " + varName + ";\n")
+ if self.style == "mma":
+ stream.write (" " + varName + "Count = 0;\n")
+ stream.write (" " + varName + "Total = 0;\n")
+ stream.write (" " + varName + "Min = std::numeric_limits<" + self.type.type.cpp + ">::max();\n")
+ stream.write (" " + varName + "Max = std::numeric_limits<" + self.type.type.cpp + ">::min();\n")
+
+ def genPerThreadHiLoStatResets (self, stream, varName, cpptype):
+ if self.style == "mma":
+ stream.write (" threadStats->" + varName + "Count = 0;\n")
+ stream.write (" threadStats->" + varName + "Total = 0;\n")
+ stream.write (" threadStats->" + varName + "Min = std::numeric_limits<" + cpptype + ">::max();\n")
+ stream.write (" threadStats->" + varName + "Max = std::numeric_limits<" + cpptype + ">::min();\n")
+
+ def genWrite (self, stream, varName, indent=" "):
+ if self.style != "mma":
+ stream.write (indent + self.encode.replace ("@", "buf").replace ("#", varName) + ";\n")
+ if self.style == "wm":
+ stream.write (indent + self.encode.replace ("@", "buf") \
+ .replace ("#", varName + "High") + ";\n")
+ stream.write (indent + self.encode.replace ("@", "buf") \
+ .replace ("#", varName + "Low") + ";\n")
+ if self.style == "mma":
+ stream.write (indent + self.encode.replace ("@", "buf") \
+ .replace ("#", varName + "Count") + ";\n")
+ stream.write (indent + self.encode.replace ("@", "buf") \
+ .replace ("#", varName + "Count ? " + varName + "Min : 0") + ";\n")
+ stream.write (indent + self.encode.replace ("@", "buf") \
+ .replace ("#", varName + "Max") + ";\n")
+ stream.write (indent + self.encode.replace ("@", "buf") \
+ .replace ("#", varName + "Count ? " + varName + "Total / " +
+ varName + "Count : 0") + ";\n")
+
+
+ def getReadCode (self, varName, bufName):
+ result = self.decode.replace ("@", bufName).replace ("#", varName)
+ return result
+
+ def getWriteCode (self, varName, bufName):
+ result = self.encode.replace ("@", bufName).replace ("#", varName)
+ return result
+
+#=====================================================================================
+#
+#=====================================================================================
+class TypeSpec:
+ def __init__ (self, file):
+ self.types = {}
+ dom = parse (file)
+ document = dom.documentElement
+ if document.tagName != 'schema-types':
+ raise ValueError ("Expected 'schema-types' in type file")
+
+ for child in document.childNodes:
+ if child.nodeType == Node.ELEMENT_NODE:
+ if child.nodeName == 'type':
+ stype = SchemaType (child)
+ self.types[stype.getName ()] = stype
+ else:
+ raise ValueError ("Unknown type tag '%s'" % child.nodeName)
+
+ def getType (self, name):
+ return self.types[name]
+
+
+#=====================================================================================
+#
+#=====================================================================================
+class Type:
+ def __init__ (self, name, typespec):
+ self.type = typespec.getType (name)
+
+#=====================================================================================
+#
+#=====================================================================================
+class SchemaProperty:
+ def __init__ (self, node, typespec):
+ self.name = None
+ self.type = None
+ self.ref = None
+ self.access = "RO"
+ self.isIndex = 0
+ self.isParentRef = 0
+ self.isGeneralRef = 0
+ self.isOptional = 0
+ self.unit = None
+ self.min = None
+ self.max = None
+ self.maxLen = None
+ self.desc = None
+
+ attrs = node.attributes
+ for idx in range (attrs.length):
+ key = attrs.item(idx).nodeName
+ val = attrs.item(idx).nodeValue
+ if key == 'name':
+ self.name = makeValidCppSymbol(val)
+
+ elif key == 'type':
+ self.type = Type (val, typespec)
+ if self.type.type.accessor != 'direct':
+ raise ValueError ("Class properties must have a type with a direct accessor")
+
+ elif key == 'references':
+ self.ref = val
+
+ elif key == 'access':
+ self.access = val
+
+ elif key == 'index':
+ if val != 'y':
+ raise ValueError ("Expected 'y' in index attribute")
+ self.isIndex = 1
+
+ elif key == 'parentRef':
+ if val != 'y':
+ raise ValueError ("Expected 'y' in parentRef attribute")
+ self.isParentRef = 1
+
+ elif key == 'isGeneralReference':
+ if val != 'y':
+ raise ValueError ("Expected 'y' in isGeneralReference attribute")
+ self.isGeneralRef = 1
+
+ elif key == 'optional':
+ if val != 'y':
+ raise ValueError ("Expected 'y' in optional attribute")
+ self.isOptional = 1
+
+ elif key == 'unit':
+ self.unit = val
+
+ elif key == 'min':
+ self.min = val
+
+ elif key == 'max':
+ self.max = val
+
+ elif key == 'maxlen':
+ self.maxLen = val
+
+ elif key == 'desc':
+ self.desc = val
+
+ else:
+ raise ValueError ("Unknown attribute in property '%s'" % key)
+
+ if self.access == "RC" and self.isOptional == 1:
+ raise ValueError ("Properties with ReadCreate access must not be optional (%s)" % self.name)
+
+ if self.name == None:
+ raise ValueError ("Missing 'name' attribute in property")
+ if self.type == None:
+ raise ValueError ("Missing 'type' attribute in property")
+
+ def getName (self):
+ return self.name
+
+ def isConstructorArg (self):
+ if self.access == "RC" and self.isParentRef == 0:
+ return 1
+ return 0
+
+ def genDeclaration (self, stream, prefix=" "):
+ stream.write (prefix + self.type.type.cpp + " " + self.name + ";\n")
+
+ def genFormalParam (self, stream, variables):
+ stream.write (self.type.type.asArg + " _" + self.name)
+
+ def genAccessor (self, stream):
+ self.type.type.genAccessor (stream, self.name, "configChanged", self.isOptional == 1)
+
+ def genInitialize (self, stream, prefix="", indent=" "):
+ val = self.type.type.init
+ stream.write (indent + prefix + self.name + " = " + val + ";\n")
+
+ def genSchema (self, stream):
+ stream.write (" ft.clear();\n")
+ stream.write (" ft.setString (NAME, \"" + self.name + "\");\n")
+ stream.write (" ft.setInt (TYPE, TYPE_" + self.type.type.base +");\n")
+ stream.write (" ft.setInt (ACCESS, ACCESS_" + self.access + ");\n")
+ stream.write (" ft.setInt (IS_INDEX, " + str (self.isIndex) + ");\n")
+ stream.write (" ft.setInt (IS_OPTIONAL, " + str (self.isOptional) + ");\n")
+ if self.unit != None:
+ stream.write (" ft.setString (UNIT, \"" + self.unit + "\");\n")
+ if self.min != None:
+ stream.write (" ft.setInt (MIN, " + self.min + ");\n")
+ if self.max != None:
+ stream.write (" ft.setInt (MAX, " + self.max + ");\n")
+ if self.maxLen != None:
+ stream.write (" ft.setInt (MAXLEN, " + self.maxLen + ");\n")
+ if self.desc != None:
+ stream.write (" ft.setString (DESC, \"" + self.desc + "\");\n")
+ stream.write (" buf.put (ft);\n\n")
+
+ def genWrite (self, stream):
+ indent = " "
+ if self.isOptional:
+ stream.write(" if (presenceMask[presenceByte_%s] & presenceMask_%s) {\n" % (self.name, self.name))
+ indent = " "
+ self.type.type.genWrite (stream, self.name, indent)
+ if self.isOptional:
+ stream.write(" }\n")
+
+
+#=====================================================================================
+#
+#=====================================================================================
+class SchemaStatistic:
+ def __init__ (self, node, typespec):
+ self.name = None
+ self.type = None
+ self.unit = None
+ self.desc = None
+ self.assign = None
+
+ attrs = node.attributes
+ for idx in range (attrs.length):
+ key = attrs.item(idx).nodeName
+ val = attrs.item(idx).nodeValue
+ if key == 'name':
+ self.name = makeValidCppSymbol(val)
+
+ elif key == 'type':
+ self.type = Type (val, typespec)
+
+ elif key == 'unit':
+ self.unit = val
+
+ elif key == 'desc':
+ self.desc = val
+
+ elif key == 'assign':
+ self.assign = val
+
+ else:
+ raise ValueError ("Unknown attribute in statistic '%s'" % key)
+
+ if self.name == None:
+ raise ValueError ("Missing 'name' attribute in statistic")
+ if self.type == None:
+ raise ValueError ("Missing 'type' attribute in statistic")
+
+ def getName (self):
+ return self.name
+
+ def genDeclaration (self, stream, prefix=" "):
+ if self.type.type.style != "mma":
+ stream.write (prefix + self.type.type.cpp + " " + self.name + ";\n")
+ if self.type.type.style == 'wm':
+ stream.write (prefix + self.type.type.cpp + " " + self.name + "High;\n")
+ stream.write (prefix + self.type.type.cpp + " " + self.name + "Low;\n")
+ if self.type.type.style == "mma":
+ stream.write (prefix + self.type.type.cpp + " " + self.name + "Count;\n")
+ stream.write (prefix + "uint64_t " + self.name + "Total;\n")
+ stream.write (prefix + self.type.type.cpp + " " + self.name + "Min;\n")
+ stream.write (prefix + self.type.type.cpp + " " + self.name + "Max;\n")
+
+ def genAccessor (self, stream):
+ self.type.type.genAccessor (stream, self.name, "instChanged")
+
+ def genHiLoStatResets (self, stream):
+ self.type.type.genHiLoStatResets (stream, self.name)
+
+ def genPerThreadHiLoStatResets (self, stream):
+ self.type.type.genPerThreadHiLoStatResets (stream, self.name, self.type.type.cpp)
+
+ def genSchemaText (self, stream, name, desc):
+ stream.write (" ft.clear();\n")
+ stream.write (" ft.setString (NAME, \"" + name + "\");\n")
+ stream.write (" ft.setInt (TYPE, TYPE_" + self.type.type.base +");\n")
+ if self.unit != None:
+ stream.write (" ft.setString (UNIT, \"" + self.unit + "\");\n")
+ if desc != None:
+ stream.write (" ft.setString (DESC, \"" + desc + "\");\n")
+ stream.write (" buf.put (ft);\n\n")
+
+ def genSchema (self, stream):
+ if self.type.type.style != "mma":
+ self.genSchemaText (stream, self.name, self.desc)
+ if self.type.type.style == "wm":
+ descHigh = self.desc
+ descLow = self.desc
+ if self.desc != None:
+ descHigh = descHigh + " (High)"
+ descLow = descLow + " (Low)"
+ self.genSchemaText (stream, self.name + "High", descHigh)
+ self.genSchemaText (stream, self.name + "Low", descLow)
+ if self.type.type.style == "mma":
+ descCount = self.desc
+ descMin = self.desc
+ descMax = self.desc
+ descAverage = self.desc
+ if self.desc != None:
+ descCount = descCount + " (Samples)"
+ descMin = descMin + " (Min)"
+ descMax = descMax + " (Max)"
+ descAverage = descAverage + " (Average)"
+ self.genSchemaText (stream, self.name + "Samples", descCount)
+ self.genSchemaText (stream, self.name + "Min", descMin)
+ self.genSchemaText (stream, self.name + "Max", descMax)
+ self.genSchemaText (stream, self.name + "Average", descAverage)
+
+ def genAssign (self, stream):
+ if self.assign != None:
+ if self.type.type.perThread:
+ prefix = " threadStats->"
+ else:
+ prefix = ""
+ stream.write (" " + prefix + self.name + " = (" + self.type.type.cpp +
+ ") (" + self.assign + ");\n")
+
+ def genWrite (self, stream):
+ if self.type.type.perThread:
+ self.type.type.genWrite (stream, "totals." + self.name)
+ else:
+ self.type.type.genWrite (stream, self.name)
+
+ def genInitialize (self, stream, prefix="", indent=" "):
+ val = self.type.type.init
+ if self.type.type.style != "mma":
+ stream.write (indent + prefix + self.name + " = " + val + ";\n")
+ if self.type.type.style == "wm":
+ stream.write (indent + prefix + self.name + "High = " + val + ";\n")
+ stream.write (indent + prefix + self.name + "Low = " + val + ";\n")
+ if self.type.type.style == "mma":
+ stream.write (indent + prefix + self.name + "Count = 0;\n")
+ stream.write (indent + prefix + self.name + "Min = std::numeric_limits<" + self.type.type.cpp + ">::max();\n")
+ stream.write (indent + prefix + self.name + "Max = std::numeric_limits<" + self.type.type.cpp + ">::min();\n")
+ stream.write (indent + prefix + self.name + "Total = 0;\n")
+
+ def genInitializeTotalPerThreadStats (self, stream):
+ if self.type.type.style == "mma":
+ stream.write (" totals->" + self.name + "Count = 0;\n")
+ stream.write (" totals->" + self.name + "Min = std::numeric_limits<" + self.type.type.cpp + ">::max();\n")
+ stream.write (" totals->" + self.name + "Max = std::numeric_limits<" + self.type.type.cpp + ">::min();\n")
+ stream.write (" totals->" + self.name + "Total = 0;\n")
+ else:
+ stream.write (" totals->" + self.name + " = 0;\n")
+
+ def genAggregatePerThreadStats (self, stream):
+ if self.type.type.style == "mma":
+ stream.write (" totals->%sCount += threadStats->%sCount;\n" % (self.name, self.name))
+ stream.write (" if (totals->%sMin > threadStats->%sMin)\n" % (self.name, self.name))
+ stream.write (" totals->%sMin = threadStats->%sMin;\n" % (self.name, self.name))
+ stream.write (" if (totals->%sMax < threadStats->%sMax)\n" % (self.name, self.name))
+ stream.write (" totals->%sMax = threadStats->%sMax;\n" % (self.name, self.name))
+ stream.write (" totals->%sTotal += threadStats->%sTotal;\n" % (self.name, self.name))
+ else:
+ stream.write (" totals->%s += threadStats->%s;\n" % (self.name, self.name))
+
+#=====================================================================================
+#
+#=====================================================================================
+class SchemaArg:
+ def __init__ (self, node, typespec):
+ self.name = None
+ self.type = None
+ self.unit = None
+ self.dir = "I"
+ self.min = None
+ self.max = None
+ self.maxLen = None
+ self.desc = None
+ self.default = None
+ self.hash = Hash(node)
+
+ attrs = node.attributes
+ for idx in range (attrs.length):
+ key = attrs.item(idx).nodeName
+ val = attrs.item(idx).nodeValue
+ if key == 'name':
+ self.name = makeValidCppSymbol(val)
+
+ elif key == 'type':
+ self.type = Type (val, typespec)
+
+ elif key == 'unit':
+ self.unit = val
+
+ elif key == 'dir':
+ self.dir = val.upper ()
+
+ elif key == 'min':
+ self.min = val
+
+ elif key == 'max':
+ self.max = val
+
+ elif key == 'maxlen':
+ self.maxLen = val
+
+ elif key == 'desc':
+ self.desc = val
+
+ elif key == 'default':
+ self.default = val
+
+ else:
+ raise ValueError ("Unknown attribute in arg '%s'" % key)
+
+ if self.name == None:
+ raise ValueError ("Missing 'name' attribute in arg")
+ if self.type == None:
+ raise ValueError ("Missing 'type' attribute in arg")
+
+ def getName (self):
+ return self.name
+
+ def getDir (self):
+ return self.dir
+
+ def genSchema (self, stream, event=False):
+ stream.write (" ft.clear();\n")
+ stream.write (" ft.setString (NAME, \"" + self.name + "\");\n")
+ stream.write (" ft.setInt (TYPE, TYPE_" + self.type.type.base +");\n")
+ if (not event):
+ stream.write (" ft.setString (DIR, \"" + self.dir + "\");\n")
+ if self.unit != None:
+ stream.write (" ft.setString (UNIT, \"" + self.unit + "\");\n")
+ if not event:
+ if self.min != None:
+ stream.write (" ft.setInt (MIN, " + self.min + ");\n")
+ if self.max != None:
+ stream.write (" ft.setInt (MAX, " + self.max + ");\n")
+ if self.maxLen != None:
+ stream.write (" ft.setInt (MAXLEN, " + self.maxLen + ");\n")
+ if self.default != None:
+ stream.write (" ft.setString (DEFAULT, \"" + self.default + "\");\n")
+ if self.desc != None:
+ stream.write (" ft.setString (DESC, \"" + self.desc + "\");\n")
+ stream.write (" buf.put (ft);\n\n")
+
+ def genFormalParam (self, stream, variables):
+ stream.write ("%s _%s" % (self.type.type.asArg, self.name))
+
+#=====================================================================================
+#
+#=====================================================================================
+class SchemaMethod:
+ def __init__ (self, parent, node, typespec):
+ self.parent = parent
+ self.name = None
+ self.desc = None
+ self.args = []
+
+ attrs = node.attributes
+ for idx in range (attrs.length):
+ key = attrs.item(idx).nodeName
+ val = attrs.item(idx).nodeValue
+ if key == 'name':
+ self.name = makeValidCppSymbol(val)
+
+ elif key == 'desc':
+ self.desc = val
+
+ else:
+ raise ValueError ("Unknown attribute in method '%s'" % key)
+
+ for child in node.childNodes:
+ if child.nodeType == Node.ELEMENT_NODE:
+ if child.nodeName == 'arg':
+ arg = SchemaArg (child, typespec)
+ self.args.append (arg)
+ else:
+ raise ValueError ("Unknown method tag '%s'" % child.nodeName)
+
+ def getName (self):
+ return self.name
+
+ def getFullName (self):
+ return capitalize(self.parent.getName()) + self.name[0:1].upper() +\
+ self.name[1:]
+
+ def getArgCount (self):
+ return len (self.args)
+
+ #===================================================================================
+ # Code Generation Functions. The names of these functions (minus the leading "gen")
+ # match the substitution keywords in the template files.
+ #===================================================================================
+ def genNameUpper (self, stream, variables):
+ stream.write (self.getFullName ().upper ())
+
+ def genNameCamel (self, stream, variables):
+ stream.write (self.getFullName ())
+
+ def genOpenNamespaces (self, stream, variables):
+ self.parent.genOpenNamespaces(stream, variables)
+
+ def genCloseNamespaces (self, stream, variables):
+ self.parent.genCloseNamespaces(stream, variables)
+
+ def genArguments (self, stream, variables):
+ for arg in self.args:
+ ctype = arg.type.type.cpp
+ dirTag = arg.dir.lower() + "_"
+ stream.write (" " + ctype + " " + dirTag + arg.getName () + ";\n")
+
+ def genNamePackageLower (self, stream, variables):
+ self.parent.genNamePackageLower(stream, variables)
+
+ def genSchema (self, stream, variables):
+ stream.write (" ft.clear();\n")
+ stream.write (" ft.setString (NAME, \"" + self.name + "\");\n")
+ stream.write (" ft.setInt (ARGCOUNT, " + str (len (self.args)) + ");\n")
+ if self.desc != None:
+ stream.write (" ft.setString (DESC, \"" + self.desc + "\");\n")
+ stream.write (" buf.put (ft);\n\n")
+ for arg in self.args:
+ arg.genSchema (stream)
+
+#=====================================================================================
+#
+#=====================================================================================
+class SchemaEvent:
+ def __init__ (self, package, node, typespec, argset):
+ self.packageName = package
+ self.name = None
+ self.desc = None
+ self.sevText = "inform"
+ self.args = []
+ self.hash = Hash(node)
+
+ attrs = node.attributes
+ for idx in range (attrs.length):
+ key = attrs.item(idx).nodeName
+ val = attrs.item(idx).nodeValue
+ if key == 'name':
+ self.name = val
+
+ elif key == 'desc':
+ self.desc = val
+
+ elif key == 'sev':
+ self.sevText = val
+
+ elif key == 'args':
+ list = val.replace(" ", "").split(",")
+ for item in list:
+ if item not in argset.args:
+ raise Exception("undefined argument '%s' in event" % item)
+ self.args.append(argset.args[item])
+ self.hash.addSubHash(argset.args[item].hash)
+
+ else:
+ raise ValueError ("Unknown attribute in event '%s'" % key)
+
+ if self.sevText == "emerg" : self.sev = 0
+ elif self.sevText == "alert" : self.sev = 1
+ elif self.sevText == "crit" : self.sev = 2
+ elif self.sevText == "error" : self.sev = 3
+ elif self.sevText == "warn" : self.sev = 4
+ elif self.sevText == "notice" : self.sev = 5
+ elif self.sevText == "inform" : self.sev = 6
+ elif self.sevText == "debug" : self.sev = 7
+ else:
+ raise ValueError("Unknown severity '%s' in event '%s'" % (self.sevText, self.name))
+
+ def getName (self):
+ return self.name
+
+ def getNameCap(self):
+ return capitalize(self.name)
+
+ def getFullName (self):
+ return capitalize(self.package + capitalize(self.name))
+
+ def genAgentHeaderLocation (self, stream, variables):
+ stream.write(variables["agentHeaderDir"])
+
+ def getArgCount (self):
+ return len (self.args)
+
+ def genArgCount (self, stream, variables):
+ stream.write("%d" % len(self.args))
+
+ def genArgDeclarations(self, stream, variables):
+ for arg in self.args:
+ if arg.type.type.byRef:
+ ref = "&"
+ else:
+ ref = ""
+ stream.write(" const %s%s %s;\n" % (arg.type.type.cpp, ref, arg.name))
+
+ def genCloseNamespaces (self, stream, variables):
+ for item in self.packageName.split("."):
+ stream.write ("}")
+
+ def genConstructorArgs(self, stream, variables):
+ pre = ""
+ for arg in self.args:
+ if arg.type.type.byRef:
+ ref = "&"
+ else:
+ ref = ""
+ stream.write("%sconst %s%s _%s" % (pre, arg.type.type.cpp, ref, arg.name))
+ pre = ",\n "
+
+ def genConstructorInits(self, stream, variables):
+ pre = ""
+ for arg in self.args:
+ stream.write("%s%s(_%s)" % (pre, arg.name, arg.name))
+ pre = ",\n "
+
+ def genName(self, stream, variables):
+ stream.write(self.name)
+
+ def genNameCap(self, stream, variables):
+ stream.write(capitalize(self.name))
+
+ def genNamespace (self, stream, variables):
+ stream.write("::".join(self.packageName.split(".")))
+
+ def genNameLower(self, stream, variables):
+ stream.write(self.name.lower())
+
+ def genNameUpper(self, stream, variables):
+ stream.write(self.name.upper())
+
+ def genNamePackageLower(self, stream, variables):
+ stream.write(self.packageName.lower())
+
+ def genOpenNamespaces (self, stream, variables):
+ for item in self.packageName.split("."):
+ stream.write ("namespace %s {\n" % item)
+
+ def genSeverity(self, stream, variables):
+ stream.write("%d" % self.sev)
+
+ def genArgEncodes(self, stream, variables):
+ for arg in self.args:
+ stream.write(" " + arg.type.type.encode.replace("@", "buf").replace("#", arg.name) + ";\n")
+
+ def genArgSchema(self, stream, variables):
+ for arg in self.args:
+ arg.genSchema(stream, True)
+
+ def genSchemaMD5(self, stream, variables):
+ sum = self.hash.getDigest()
+ for idx in range (len (sum)):
+ if idx != 0:
+ stream.write (",")
+ stream.write (hex (ord (sum[idx])))
+
+
+class SchemaClass:
+ def __init__ (self, package, node, typespec, fragments, options):
+ self.packageName = package
+ self.properties = []
+ self.statistics = []
+ self.methods = []
+ self.events = []
+ self.options = options
+ self.hash = Hash(node)
+
+ attrs = node.attributes
+ self.name = makeValidCppSymbol(attrs['name'].nodeValue)
+
+ children = node.childNodes
+ for child in children:
+ if child.nodeType == Node.ELEMENT_NODE:
+ if child.nodeName == 'property':
+ sub = SchemaProperty (child, typespec)
+ self.properties.append (sub)
+
+ elif child.nodeName == 'statistic':
+ sub = SchemaStatistic (child, typespec)
+ self.statistics.append (sub)
+
+ elif child.nodeName == 'method':
+ sub = SchemaMethod (self, child, typespec)
+ self.methods.append (sub)
+
+ elif child.nodeName == 'group':
+ self.expandFragment (child, fragments)
+
+ else:
+ raise ValueError ("Unknown class tag '%s'" % child.nodeName)
+
+ # Adjust the 'assign' attributes for each statistic
+ for stat in self.statistics:
+ if stat.assign != None and stat.type.type.perThread:
+ stat.assign = self.adjust (stat.assign, self.statistics)
+
+ def adjust (self, text, statistics):
+ result = text
+ start = 0
+ while True:
+ next = None
+ for stat in statistics:
+ pos = result.find (stat.name, start)
+ if pos != -1 and (next == None or pos < next[0]):
+ next = (pos, stat.name)
+ if next == None:
+ return result
+ pos = next[0]
+ result = result[0:pos] + "threadStats->" + result[pos:]
+ start = pos + 9 + len(next[1])
+
+ def expandFragment (self, node, fragments):
+ attrs = node.attributes
+ name = attrs['name'].nodeValue
+ for fragment in fragments:
+ if fragment.name == name:
+ self.hash.addSubHash(fragment.hash)
+ for config in fragment.properties:
+ self.properties.append (config)
+ for inst in fragment.statistics:
+ self.statistics.append (inst)
+ for method in fragment.methods:
+ self.methods.append (method)
+ for event in fragment.events:
+ self.events.append (event)
+ return
+ raise ValueError ("Undefined group '%s'" % name)
+
+ def getName (self):
+ return self.name
+
+ def getNameCap (self):
+ return capitalize(self.name)
+
+ def getMethods (self):
+ return self.methods
+
+ def getEvents (self):
+ return self.events
+
+ def getPackageNameCap (self):
+ return capitalize(self.packageName)
+
+ #===================================================================================
+ # Code Generation Functions. The names of these functions (minus the leading "gen")
+ # match the substitution keywords in the template files.
+ #===================================================================================
+ def testExistOptionals (self, variables):
+ for prop in self.properties:
+ if prop.isOptional == 1:
+ return True
+ return False
+
+ def testExistPerThreadStats (self, variables):
+ for inst in self.statistics:
+ if inst.type.type.perThread:
+ return True
+ return False
+
+ def testExistPerThreadAssign (self, variables):
+ for inst in self.statistics:
+ if inst.type.type.perThread and inst.assign != None:
+ return True
+ return False
+
+ def testExistPerThreadResets (self, variables):
+ for inst in self.statistics:
+ if inst.type.type.perThread and inst.type.type.style == "mma":
+ return True
+ return False
+
+ def testNoStatistics (self, variables):
+ return len (self.statistics) == 0
+
+ def genAccessorMethods (self, stream, variables):
+ for config in self.properties:
+ if config.access != "RC":
+ config.genAccessor (stream)
+ for inst in self.statistics:
+ if inst.assign == None:
+ inst.genAccessor (stream)
+
+ def genAgentHeaderLocation (self, stream, variables):
+ stream.write(variables["agentHeaderDir"])
+
+ def genCloseNamespaces (self, stream, variables):
+ for item in self.packageName.split("."):
+ stream.write ("}")
+
+ def genConfigCount (self, stream, variables):
+ stream.write ("%d" % len (self.properties))
+
+ def genConfigDeclarations (self, stream, variables):
+ for element in self.properties:
+ element.genDeclaration (stream)
+
+ def genConstructorArgs (self, stream, variables):
+ # Constructor args are config elements with read-create access
+ result = ""
+ for element in self.properties:
+ if element.isConstructorArg ():
+ stream.write (", ")
+ element.genFormalParam (stream, variables)
+
+ def genConstructorInits (self, stream, variables):
+ for element in self.properties:
+ if element.isConstructorArg ():
+ stream.write ("," + element.getName () + "(_" + element.getName () + ")")
+
+ def genDoMethodArgs (self, stream, variables):
+ methodCount = 0
+ inArgCount = 0
+ for method in self.methods:
+ methodCount = methodCount + 1
+ for arg in method.args:
+ if arg.getDir () == "I" or arg.getDir () == "IO":
+ inArgCount = inArgCount + 1
+
+ if methodCount == 0:
+ stream.write ("string&, Buffer&, Buffer& outBuf")
+ else:
+ if inArgCount == 0:
+ stream.write ("string& methodName, Buffer&, Buffer& outBuf")
+ else:
+ stream.write ("string& methodName, Buffer& inBuf, Buffer& outBuf")
+
+ def genHiLoStatResets (self, stream, variables):
+ for inst in self.statistics:
+ if not inst.type.type.perThread:
+ inst.genHiLoStatResets (stream)
+
+ def genPerThreadHiLoStatResets (self, stream, variables):
+ for inst in self.statistics:
+ if inst.type.type.perThread:
+ inst.genPerThreadHiLoStatResets (stream)
+
+ def genInitializeElements (self, stream, variables):
+ for prop in self.properties:
+ if not prop.isConstructorArg() and not prop.isParentRef:
+ prop.genInitialize(stream)
+ for inst in self.statistics:
+ if not inst.type.type.perThread:
+ inst.genInitialize (stream)
+
+ def genInitializePerThreadElements (self, stream, variables):
+ for inst in self.statistics:
+ if inst.type.type.perThread:
+ inst.genInitialize (stream, "threadStats->", " ")
+
+ def genInitializeTotalPerThreadStats (self, stream, variables):
+ for inst in self.statistics:
+ if inst.type.type.perThread:
+ inst.genInitializeTotalPerThreadStats (stream)
+
+ def genAggregatePerThreadStats (self, stream, variables):
+ for inst in self.statistics:
+ if inst.type.type.perThread:
+ inst.genAggregatePerThreadStats (stream)
+
+ def genInstCount (self, stream, variables):
+ count = 0
+ for inst in self.statistics:
+ count = count + 1
+ if inst.type.type.style == "wm":
+ count = count + 2
+ if inst.type.type.style == "mma":
+ count = count + 3
+ stream.write ("%d" % count)
+
+ def genInstDeclarations (self, stream, variables):
+ for element in self.statistics:
+ if not element.type.type.perThread:
+ element.genDeclaration (stream)
+
+ def genPerThreadDeclarations (self, stream, variables):
+ for element in self.statistics:
+ if element.type.type.perThread:
+ element.genDeclaration (stream, " ")
+
+ def genNamespace (self, stream, variables):
+ stream.write("::".join(self.packageName.split(".")))
+
+ def genMethodArgIncludes (self, stream, variables):
+ for method in self.methods:
+ if method.getArgCount () > 0:
+ stream.write ("#include \"Args" + method.getFullName () + ".h\"\n")
+
+ def genMethodCount (self, stream, variables):
+ stream.write ("%d" % len (self.methods))
+
+ def genMethodHandlers (self, stream, variables):
+ for method in self.methods:
+ stream.write ("\n if (methodName == \"" + method.getName () + "\") {\n")
+ if method.getArgCount () == 0:
+ stream.write (" ::qpid::management::ArgsNone ioArgs;\n")
+ else:
+ stream.write (" Args" + method.getFullName () + " ioArgs;\n")
+ for arg in method.args:
+ if arg.getDir () == "I" or arg.getDir () == "IO":
+ stream.write (" " +\
+ arg.type.type.getReadCode ("ioArgs." +\
+ arg.dir.lower () + "_" +\
+ arg.name, "inBuf") + ";\n")
+
+ stream.write (" status = coreObject->ManagementMethod (METHOD_" +\
+ method.getName().upper() + ", ioArgs, text);\n")
+ stream.write (" outBuf.putLong (status);\n")
+ stream.write (" outBuf.putMediumString(::qpid::management::Manageable::StatusText (status, text));\n")
+ for arg in method.args:
+ if arg.getDir () == "O" or arg.getDir () == "IO":
+ stream.write (" " +\
+ arg.type.type.getWriteCode ("ioArgs." +\
+ arg.dir.lower () + "_" +\
+ arg.name, "outBuf") + ";\n")
+ stream.write (" return;\n }\n")
+
+ def genOpenNamespaces (self, stream, variables):
+ for item in self.packageName.split("."):
+ stream.write ("namespace %s {\n" % item)
+
+ def genPresenceMaskBytes (self, stream, variables):
+ count = 0
+ for prop in self.properties:
+ if prop.isOptional == 1:
+ count += 1
+ if count == 0:
+ stream.write("0")
+ else:
+ stream.write (str(((count - 1) / 8) + 1))
+
+ def genPresenceMaskConstants (self, stream, variables):
+ count = 0
+ for prop in self.properties:
+ if prop.isOptional == 1:
+ stream.write(" static const uint8_t presenceByte_%s = %d;\n" % (prop.name, count / 8))
+ stream.write(" static const uint8_t presenceMask_%s = %d;\n" % (prop.name, 1 << (count % 8)))
+ count += 1
+
+ def genPropertySchema (self, stream, variables):
+ for prop in self.properties:
+ prop.genSchema (stream)
+
+ def genSetGeneralReferenceDeclaration (self, stream, variables):
+ for prop in self.properties:
+ if prop.isGeneralRef:
+ stream.write ("void setReference(::qpid::management::ObjectId objectId) { " + prop.name + " = objectId; }\n")
+
+ def genStatisticSchema (self, stream, variables):
+ for stat in self.statistics:
+ stat.genSchema (stream)
+
+ def genMethodIdDeclarations (self, stream, variables):
+ number = 1
+ for method in self.methods:
+ stream.write (" static const uint32_t METHOD_" + method.getName().upper() +\
+ " = %d;\n" % number)
+ number = number + 1
+
+ def genMethodSchema (self, stream, variables):
+ for method in self.methods:
+ method.genSchema (stream, variables)
+
+ def genNameCap (self, stream, variables):
+ stream.write (capitalize(self.name))
+
+ def genNameLower (self, stream, variables):
+ stream.write (self.name.lower ())
+
+ def genNamePackageCap (self, stream, variables):
+ stream.write (self.getPackageNameCap ())
+
+ def genNamePackageLower (self, stream, variables):
+ stream.write (self.packageName.lower ())
+
+ def genNameUpper (self, stream, variables):
+ stream.write (self.name.upper ())
+
+ def genParentArg (self, stream, variables):
+ for config in self.properties:
+ if config.isParentRef == 1:
+ stream.write (", ::qpid::management::Manageable* _parent")
+ return
+
+ def genParentRefAssignment (self, stream, variables):
+ for config in self.properties:
+ if config.isParentRef == 1:
+ stream.write (config.getName () + \
+ " = _parent->GetManagementObject ()->getObjectId ();")
+ return
+
+ def genSchemaMD5 (self, stream, variables):
+ sum = self.hash.getDigest()
+ for idx in range (len (sum)):
+ if idx != 0:
+ stream.write (",")
+ stream.write (hex (ord (sum[idx])))
+
+ def genAssign (self, stream, variables):
+ for inst in self.statistics:
+ if not inst.type.type.perThread:
+ inst.genAssign (stream)
+
+ def genPerThreadAssign (self, stream, variables):
+ for inst in self.statistics:
+ if inst.type.type.perThread:
+ inst.genAssign (stream)
+
+ def genWriteProperties (self, stream, variables):
+ for prop in self.properties:
+ prop.genWrite (stream)
+
+ def genWriteStatistics (self, stream, variables):
+ for stat in self.statistics:
+ stat.genWrite (stream)
+
+
+class SchemaEventArgs:
+ def __init__(self, package, node, typespec, fragments, options):
+ self.packageName = package
+ self.options = options
+ self.args = {}
+
+ children = node.childNodes
+ for child in children:
+ if child.nodeType == Node.ELEMENT_NODE:
+ if child.nodeName == 'arg':
+ arg = SchemaArg(child, typespec)
+ self.args[arg.name] = arg
+ else:
+ raise Exception("Unknown tag '%s' in <eventArguments>" % child.nodeName)
+
+class SchemaPackage:
+ def __init__ (self, typefile, schemafile, options):
+
+ self.classes = []
+ self.fragments = []
+ self.typespec = TypeSpec (typefile)
+ self.eventArgSet = None
+ self.events = []
+
+ dom = parse (schemafile)
+ document = dom.documentElement
+ if document.tagName != 'schema':
+ raise ValueError ("Expected 'schema' node")
+ attrs = document.attributes
+ pname = attrs['package'].nodeValue
+ namelist = pname.split('.')
+ self.packageName = ".".join(namelist)
+
+ children = document.childNodes
+ for child in children:
+ if child.nodeType == Node.ELEMENT_NODE:
+ if child.nodeName == 'class':
+ cls = SchemaClass (self.packageName, child, self.typespec,
+ self.fragments, options)
+ self.classes.append (cls)
+
+ elif child.nodeName == 'group':
+ cls = SchemaClass (self.packageName, child, self.typespec,
+ self.fragments, options)
+ self.fragments.append (cls)
+
+ elif child.nodeName == 'eventArguments':
+ if self.eventArgSet:
+ raise Exception("Only one <eventArguments> may appear in a package")
+ self.eventArgSet = SchemaEventArgs(self.packageName, child, self.typespec, self.fragments, options)
+
+ elif child.nodeName == 'event':
+ event = SchemaEvent(self.packageName, child, self.typespec, self.eventArgSet)
+ self.events.append(event)
+
+ else:
+ raise ValueError ("Unknown schema tag '%s'" % child.nodeName)
+
+ def getPackageName (self):
+ return self.packageName
+
+ def getPackageNameCap (self):
+ return capitalize(self.packageName)
+
+ def getPackageNameLower (self):
+ return self.packageName.lower()
+
+ def getClasses (self):
+ return self.classes
+
+ def getEvents(self):
+ return self.events
+
+ def genAgentHeaderLocation (self, stream, variables):
+ stream.write(variables["agentHeaderDir"])
+
+ def genCloseNamespaces (self, stream, variables):
+ for item in self.packageName.split("."):
+ stream.write ("}")
+
+ def genNamespace (self, stream, variables):
+ stream.write("::".join(self.packageName.split(".")))
+
+ def genOpenNamespaces (self, stream, variables):
+ for item in self.packageName.split("."):
+ stream.write ("namespace %s {\n" % item)
+
+ def genPackageNameUpper (self, stream, variables):
+ up = "_".join(self.packageName.split("."))
+ stream.write (up.upper())
+
+ def genNamePackageLower (self, stream, variables):
+ stream.write (self.packageName.lower ())
+
+ def genClassIncludes (self, stream, variables):
+ for _class in self.classes:
+ stream.write ("#include \"")
+ _class.genNameCap (stream, variables)
+ stream.write (".h\"\n")
+ for _event in self.events:
+ stream.write ("#include \"Event")
+ _event.genNameCap(stream, variables)
+ stream.write (".h\"\n")
+
+ def genClassRegisters(self, stream, variables):
+ for _class in self.classes:
+ stream.write(" ")
+ _class.genNameCap(stream, variables)
+ stream.write("::registerSelf(agent);\n")
+ for _event in self.events:
+ stream.write(" Event")
+ _event.genNameCap(stream, variables)
+ stream.write("::registerSelf(agent);\n")
+
+
+#=====================================================================================
+# Utility Functions
+#=====================================================================================
+
+# Create a valid C++ symbol from the input string so that it can be
+# used in generated C++ source. For instance, change "qpid.mgmt" to
+# "qpidMgmt".
+#
+# Input: Raw string (str) to process
+# Output: String (str) suitable for use as a C++ symbol
+#
+# Limitations: Currently, only strips periods ('.') from strings,
+# eventually should strip :'s and ,'s and ''s, oh my!
+def makeValidCppSymbol(input):
+ output = str()
+ capitalize = False
+
+ for char in input:
+ skip = False
+
+ if char == ".":
+ capitalize = True
+ skip = True
+
+ if not skip:
+ output += capitalize and char.upper() or char
+
+ capitalize = False
+
+ return output
+
+# Capitalize a string by /only/ forcing the first character to be
+# uppercase. The rest of the string is left alone. This is different
+# from str.capitalize(), which forces the first character to uppercase
+# and the rest to lowercase.
+#
+# Input: A string (str) to capitalize
+# Output: A string (str) with the first character as uppercase
+def capitalize(input):
+ return input[0].upper() + input[1:]
diff --git a/cpp/managementgen/qmfgen/templates/Args.h b/cpp/managementgen/qmfgen/templates/Args.h
new file mode 100644
index 0000000000..074ccf9940
--- /dev/null
+++ b/cpp/managementgen/qmfgen/templates/Args.h
@@ -0,0 +1,42 @@
+/*MGEN:commentPrefix=//*/
+#ifndef _ARGS_/*MGEN:Method.NameUpper*/_
+#define _ARGS_/*MGEN:Method.NameUpper*/_
+
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+/*MGEN:Root.Disclaimer*/
+
+#include "qpid/management/Args.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/Uuid.h"
+#include <string>
+
+namespace qmf {
+/*MGEN:Method.OpenNamespaces*/
+
+ class Args/*MGEN:Method.NameCamel*/ : public ::qpid::management::Args
+{
+ public:
+/*MGEN:Method.Arguments*/
+};
+
+}/*MGEN:Method.CloseNamespaces*/
+
+#endif /*!_ARGS_/*MGEN:Method.NameUpper*/_*/
diff --git a/cpp/managementgen/qmfgen/templates/CMakeLists.cmake b/cpp/managementgen/qmfgen/templates/CMakeLists.cmake
new file mode 100644
index 0000000000..54f446a437
--- /dev/null
+++ b/cpp/managementgen/qmfgen/templates/CMakeLists.cmake
@@ -0,0 +1,39 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http:#www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+/*MGEN:commentPrefix=#*/
+/*MGEN:Root.Disclaimer*/
+/*MGEN:IF(CMakeLists.QpidBroker)*/
+/*MGEN:mgenDir=${mgen_dir}*/
+/*MGEN:specDir=${qpid-cpp_SOURCE_DIR}/../specs*/
+
+set(mgen_generator /*MGEN:CMakeLists.GenSources*/)
+
+set(mgen_broker_cpp /*MGEN:CMakeLists.GenCppFiles*/)
+
+# Header file install rules.
+#/*MGEN:CMakeLists.HeaderInstalls*/
+#if GENERATE
+#$(srcdir)/managementgen.mk: $(mgen_generator)
+# $(mgen_cmd)
+#
+#$(mgen_generator):
+#endif
+#/*MGEN:ENDIF*/
+
+set(qmfgen_sources /*MGEN:CMakeLists.GeneratedFiles*/)
diff --git a/cpp/managementgen/qmfgen/templates/Class.cpp b/cpp/managementgen/qmfgen/templates/Class.cpp
new file mode 100644
index 0000000000..973d92586a
--- /dev/null
+++ b/cpp/managementgen/qmfgen/templates/Class.cpp
@@ -0,0 +1,180 @@
+/*MGEN:commentPrefix=//*/
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+/*MGEN:Root.Disclaimer*/
+
+#include "qpid/log/Statement.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/management/Manageable.h"
+#include "qpid//*MGEN:Class.AgentHeaderLocation*//ManagementAgent.h"
+#include "/*MGEN:Class.NameCap*/.h"
+/*MGEN:Class.MethodArgIncludes*/
+
+using namespace qmf::/*MGEN:Class.Namespace*/;
+using namespace qpid::framing;
+using qpid::management::ManagementAgent;
+using qpid::management::Manageable;
+using qpid::management::ManagementObject;
+using qpid::management::Args;
+using std::string;
+
+string /*MGEN:Class.NameCap*/::packageName = string ("/*MGEN:Class.NamePackageLower*/");
+string /*MGEN:Class.NameCap*/::className = string ("/*MGEN:Class.NameLower*/");
+uint8_t /*MGEN:Class.NameCap*/::md5Sum[16] =
+ {/*MGEN:Class.SchemaMD5*/};
+
+/*MGEN:Class.NameCap*/::/*MGEN:Class.NameCap*/ (ManagementAgent*, Manageable* _core/*MGEN:Class.ParentArg*//*MGEN:Class.ConstructorArgs*/) :
+ ManagementObject(_core)/*MGEN:Class.ConstructorInits*/
+{
+ /*MGEN:Class.ParentRefAssignment*/
+/*MGEN:Class.InitializeElements*/
+/*MGEN:IF(Class.ExistOptionals)*/
+ // Optional properties start out not-present
+ for (uint8_t idx = 0; idx < /*MGEN:Class.PresenceMaskBytes*/; idx++)
+ presenceMask[idx] = 0;
+/*MGEN:ENDIF*/
+/*MGEN:IF(Class.ExistPerThreadStats)*/
+ perThreadStatsArray = new struct PerThreadStats*[maxThreads];
+ for (int idx = 0; idx < maxThreads; idx++)
+ perThreadStatsArray[idx] = 0;
+/*MGEN:ENDIF*/
+}
+
+/*MGEN:Class.NameCap*/::~/*MGEN:Class.NameCap*/ ()
+{
+/*MGEN:IF(Class.ExistPerThreadStats)*/
+ for (int idx = 0; idx < maxThreads; idx++)
+ if (perThreadStatsArray[idx] != 0)
+ delete perThreadStatsArray[idx];
+ delete[] perThreadStatsArray;
+/*MGEN:ENDIF*/
+}
+
+namespace {
+ const string NAME("name");
+ const string TYPE("type");
+ const string ACCESS("access");
+ const string IS_INDEX("index");
+ const string IS_OPTIONAL("optional");
+ const string UNIT("unit");
+ const string MIN("min");
+ const string MAX("max");
+ const string MAXLEN("maxlen");
+ const string DESC("desc");
+ const string ARGCOUNT("argCount");
+ const string ARGS("args");
+ const string DIR("dir");
+ const string DEFAULT("default");
+}
+
+void /*MGEN:Class.NameCap*/::registerSelf(ManagementAgent* agent)
+{
+ agent->registerClass(packageName, className, md5Sum, writeSchema);
+}
+
+void /*MGEN:Class.NameCap*/::writeSchema (Buffer& buf)
+{
+ FieldTable ft;
+
+ // Schema class header:
+ buf.putOctet (CLASS_KIND_TABLE);
+ buf.putShortString (packageName); // Package Name
+ buf.putShortString (className); // Class Name
+ buf.putBin128 (md5Sum); // Schema Hash
+ buf.putShort (/*MGEN:Class.ConfigCount*/); // Config Element Count
+ buf.putShort (/*MGEN:Class.InstCount*/); // Inst Element Count
+ buf.putShort (/*MGEN:Class.MethodCount*/); // Method Count
+
+ // Properties
+/*MGEN:Class.PropertySchema*/
+ // Statistics
+/*MGEN:Class.StatisticSchema*/
+ // Methods
+/*MGEN:Class.MethodSchema*/
+}
+
+/*MGEN:IF(Class.ExistPerThreadStats)*/
+void /*MGEN:Class.NameCap*/::aggregatePerThreadStats(struct PerThreadStats* totals)
+{
+/*MGEN:Class.InitializeTotalPerThreadStats*/
+ for (int idx = 0; idx < maxThreads; idx++) {
+ struct PerThreadStats* threadStats = perThreadStatsArray[idx];
+ if (threadStats != 0) {
+/*MGEN:Class.AggregatePerThreadStats*/
+ }
+ }
+}
+/*MGEN:ENDIF*/
+
+void /*MGEN:Class.NameCap*/::writeProperties (Buffer& buf)
+{
+ ::qpid::sys::Mutex::ScopedLock mutex(accessLock);
+ configChanged = false;
+
+ writeTimestamps (buf);
+/*MGEN:IF(Class.ExistOptionals)*/
+ for (uint8_t idx = 0; idx < /*MGEN:Class.PresenceMaskBytes*/; idx++)
+ buf.putOctet(presenceMask[idx]);
+/*MGEN:ENDIF*/
+/*MGEN:Class.WriteProperties*/
+}
+
+void /*MGEN:Class.NameCap*/::writeStatistics (Buffer& buf, bool skipHeaders)
+{
+ ::qpid::sys::Mutex::ScopedLock mutex(accessLock);
+ instChanged = false;
+/*MGEN:IF(Class.ExistPerThreadAssign)*/
+ for (int idx = 0; idx < maxThreads; idx++) {
+ struct PerThreadStats* threadStats = perThreadStatsArray[idx];
+ if (threadStats != 0) {
+/*MGEN:Class.PerThreadAssign*/
+ }
+ }
+/*MGEN:ENDIF*/
+/*MGEN:IF(Class.ExistPerThreadStats)*/
+ struct PerThreadStats totals;
+ aggregatePerThreadStats(&totals);
+/*MGEN:ENDIF*/
+/*MGEN:Class.Assign*/
+ if (!skipHeaders)
+ writeTimestamps (buf);
+/*MGEN:Class.WriteStatistics*/
+
+ // Maintenance of hi-lo statistics
+/*MGEN:Class.HiLoStatResets*/
+/*MGEN:IF(Class.ExistPerThreadResets)*/
+ for (int idx = 0; idx < maxThreads; idx++) {
+ struct PerThreadStats* threadStats = perThreadStatsArray[idx];
+ if (threadStats != 0) {
+/*MGEN:Class.PerThreadHiLoStatResets*/
+ }
+ }
+/*MGEN:ENDIF*/
+}
+
+void /*MGEN:Class.NameCap*/::doMethod (/*MGEN:Class.DoMethodArgs*/)
+{
+ Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD;
+ std::string text;
+
+/*MGEN:Class.MethodHandlers*/
+ outBuf.putLong(status);
+ outBuf.putShortString(Manageable::StatusText(status, text));
+}
diff --git a/cpp/managementgen/qmfgen/templates/Class.h b/cpp/managementgen/qmfgen/templates/Class.h
new file mode 100644
index 0000000000..225090f0a9
--- /dev/null
+++ b/cpp/managementgen/qmfgen/templates/Class.h
@@ -0,0 +1,111 @@
+/*MGEN:commentPrefix=//*/
+#ifndef _MANAGEMENT_/*MGEN:Class.NameUpper*/_
+#define _MANAGEMENT_/*MGEN:Class.NameUpper*/_
+
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+/*MGEN:Root.Disclaimer*/
+
+#include "qpid/management/ManagementObject.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/Uuid.h"
+
+namespace qpid {
+ namespace management {
+ class ManagementAgent;
+ }
+}
+
+namespace qmf {
+/*MGEN:Class.OpenNamespaces*/
+
+class /*MGEN:Class.NameCap*/ : public ::qpid::management::ManagementObject
+{
+ private:
+
+ static std::string packageName;
+ static std::string className;
+ static uint8_t md5Sum[16];
+/*MGEN:IF(Class.ExistOptionals)*/
+ uint8_t presenceMask[/*MGEN:Class.PresenceMaskBytes*/];
+/*MGEN:Class.PresenceMaskConstants*/
+/*MGEN:ENDIF*/
+
+ // Properties
+/*MGEN:Class.ConfigDeclarations*/
+ // Statistics
+/*MGEN:Class.InstDeclarations*/
+/*MGEN:IF(Class.ExistPerThreadStats)*/
+ // Per-Thread Statistics
+ struct PerThreadStats {
+/*MGEN:Class.PerThreadDeclarations*/
+ };
+
+ struct PerThreadStats** perThreadStatsArray;
+
+ inline struct PerThreadStats* getThreadStats() {
+ int idx = getThreadIndex();
+ struct PerThreadStats* threadStats = perThreadStatsArray[idx];
+ if (threadStats == 0) {
+ threadStats = new(PerThreadStats);
+ perThreadStatsArray[idx] = threadStats;
+/*MGEN:Class.InitializePerThreadElements*/
+ }
+ return threadStats;
+ }
+
+ void aggregatePerThreadStats(struct PerThreadStats*);
+/*MGEN:ENDIF*/
+ // Private Methods
+ static void writeSchema(::qpid::framing::Buffer& buf);
+ void writeProperties(::qpid::framing::Buffer& buf);
+ void writeStatistics(::qpid::framing::Buffer& buf,
+ bool skipHeaders = false);
+ void doMethod(std::string& methodName,
+ ::qpid::framing::Buffer& inBuf,
+ ::qpid::framing::Buffer& outBuf);
+ writeSchemaCall_t getWriteSchemaCall() { return writeSchema; }
+/*MGEN:IF(Class.NoStatistics)*/
+ // Stub for getInstChanged. There are no statistics in this class.
+ bool getInstChanged() { return false; }
+ bool hasInst() { return false; }
+/*MGEN:ENDIF*/
+ public:
+
+ /*MGEN:Class.NameCap*/(::qpid::management::ManagementAgent* agent,
+ ::qpid::management::Manageable* coreObject/*MGEN:Class.ParentArg*//*MGEN:Class.ConstructorArgs*/);
+ ~/*MGEN:Class.NameCap*/();
+
+ /*MGEN:Class.SetGeneralReferenceDeclaration*/
+
+ static void registerSelf(::qpid::management::ManagementAgent* agent);
+ std::string& getPackageName() const { return packageName; }
+ std::string& getClassName() const { return className; }
+ uint8_t* getMd5Sum() const { return md5Sum; }
+
+ // Method IDs
+/*MGEN:Class.MethodIdDeclarations*/
+ // Accessor Methods
+/*MGEN:Class.AccessorMethods*/
+};
+
+}/*MGEN:Class.CloseNamespaces*/
+
+#endif /*!_MANAGEMENT_/*MGEN:Class.NameUpper*/_*/
diff --git a/cpp/managementgen/qmfgen/templates/Event.cpp b/cpp/managementgen/qmfgen/templates/Event.cpp
new file mode 100644
index 0000000000..a4fc28990d
--- /dev/null
+++ b/cpp/managementgen/qmfgen/templates/Event.cpp
@@ -0,0 +1,78 @@
+/*MGEN:commentPrefix=//*/
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+/*MGEN:Root.Disclaimer*/
+
+#include "qpid/log/Statement.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/management/Manageable.h"
+#include "qpid//*MGEN:Event.AgentHeaderLocation*//ManagementAgent.h"
+#include "Event/*MGEN:Event.NameCap*/.h"
+
+using namespace qmf::/*MGEN:Event.Namespace*/;
+using namespace qpid::framing;
+using qpid::management::ManagementAgent;
+using qpid::management::Manageable;
+using qpid::management::ManagementObject;
+using qpid::management::Args;
+using std::string;
+
+string Event/*MGEN:Event.NameCap*/::packageName = string ("/*MGEN:Event.NamePackageLower*/");
+string Event/*MGEN:Event.NameCap*/::eventName = string ("/*MGEN:Event.Name*/");
+uint8_t Event/*MGEN:Event.NameCap*/::md5Sum[16] =
+ {/*MGEN:Event.SchemaMD5*/};
+
+Event/*MGEN:Event.NameCap*/::Event/*MGEN:Event.NameCap*/ (/*MGEN:Event.ConstructorArgs*/) :
+ /*MGEN:Event.ConstructorInits*/
+{}
+
+namespace {
+ const string NAME("name");
+ const string TYPE("type");
+ const string DESC("desc");
+ const string ARGCOUNT("argCount");
+ const string ARGS("args");
+}
+
+void Event/*MGEN:Event.NameCap*/::registerSelf(ManagementAgent* agent)
+{
+ agent->registerEvent(packageName, eventName, md5Sum, writeSchema);
+}
+
+void Event/*MGEN:Event.NameCap*/::writeSchema (Buffer& buf)
+{
+ FieldTable ft;
+
+ // Schema class header:
+ buf.putOctet (CLASS_KIND_EVENT);
+ buf.putShortString (packageName); // Package Name
+ buf.putShortString (eventName); // Event Name
+ buf.putBin128 (md5Sum); // Schema Hash
+ buf.putOctet (0); // No Superclass
+ buf.putShort (/*MGEN:Event.ArgCount*/); // Argument Count
+
+ // Arguments
+/*MGEN:Event.ArgSchema*/
+}
+
+void Event/*MGEN:Event.NameCap*/::encode(::qpid::framing::Buffer& buf) const
+{
+/*MGEN:Event.ArgEncodes*/
+}
diff --git a/cpp/managementgen/qmfgen/templates/Event.h b/cpp/managementgen/qmfgen/templates/Event.h
new file mode 100644
index 0000000000..b5c2a211d1
--- /dev/null
+++ b/cpp/managementgen/qmfgen/templates/Event.h
@@ -0,0 +1,59 @@
+/*MGEN:commentPrefix=//*/
+#ifndef _MANAGEMENT_/*MGEN:Event.NameUpper*/_
+#define _MANAGEMENT_/*MGEN:Event.NameUpper*/_
+
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+/*MGEN:Root.Disclaimer*/
+
+#include "qpid/management/ManagementEvent.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/Uuid.h"
+
+namespace qmf {
+/*MGEN:Event.OpenNamespaces*/
+
+class Event/*MGEN:Event.NameCap*/ : public ::qpid::management::ManagementEvent
+{
+ private:
+ static void writeSchema (::qpid::framing::Buffer& buf);
+ static std::string packageName;
+ static std::string eventName;
+ static uint8_t md5Sum[16];
+
+/*MGEN:Event.ArgDeclarations*/
+
+ public:
+ writeSchemaCall_t getWriteSchemaCall(void) { return writeSchema; }
+
+ Event/*MGEN:Event.NameCap*/(/*MGEN:Event.ConstructorArgs*/);
+ ~Event/*MGEN:Event.NameCap*/() {};
+
+ static void registerSelf(::qpid::management::ManagementAgent* agent);
+ std::string& getPackageName() const { return packageName; }
+ std::string& getEventName() const { return eventName; }
+ uint8_t* getMd5Sum() const { return md5Sum; }
+ uint8_t getSeverity() const { return /*MGEN:Event.Severity*/; }
+ void encode(::qpid::framing::Buffer& buffer) const;
+};
+
+}/*MGEN:Event.CloseNamespaces*/
+
+#endif /*!_MANAGEMENT_/*MGEN:Event.NameUpper*/_*/
diff --git a/cpp/managementgen/qmfgen/templates/Makefile.mk b/cpp/managementgen/qmfgen/templates/Makefile.mk
new file mode 100644
index 0000000000..2b32c7c0f2
--- /dev/null
+++ b/cpp/managementgen/qmfgen/templates/Makefile.mk
@@ -0,0 +1,40 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http:#www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+/*MGEN:commentPrefix=#*/
+/*MGEN:Root.Disclaimer*/
+/*MGEN:IF(Makefile.QpidBroker)*/
+/*MGEN:mgenDir=$(mgen_dir)*/
+/*MGEN:specDir=$(top_srcdir)/../specs*/
+
+mgen_generator=/*MGEN:Makefile.GenSources*/
+
+mgen_broker_cpp=/*MGEN:Makefile.GenCppFiles*/
+
+# Header file install rules.
+/*MGEN:Makefile.HeaderInstalls*/
+if GENERATE
+$(srcdir)/managementgen.mk: $(mgen_generator)
+ $(mgen_cmd)
+
+$(mgen_generator):
+endif
+/*MGEN:ENDIF*/
+
+qmfgen_sources=/*MGEN:Makefile.GeneratedFiles*/
+
diff --git a/cpp/managementgen/qmfgen/templates/Package.cpp b/cpp/managementgen/qmfgen/templates/Package.cpp
new file mode 100644
index 0000000000..f6bd7f4654
--- /dev/null
+++ b/cpp/managementgen/qmfgen/templates/Package.cpp
@@ -0,0 +1,32 @@
+/*MGEN:commentPrefix=//*/
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+/*MGEN:Root.Disclaimer*/
+
+#include "Package.h"
+/*MGEN:Schema.ClassIncludes*/
+
+using namespace qmf::/*MGEN:Schema.Namespace*/;
+
+Package::Package (::qpid::management::ManagementAgent* agent)
+{
+/*MGEN:Schema.ClassRegisters*/
+}
+
diff --git a/cpp/managementgen/qmfgen/templates/Package.h b/cpp/managementgen/qmfgen/templates/Package.h
new file mode 100644
index 0000000000..569c7cfb33
--- /dev/null
+++ b/cpp/managementgen/qmfgen/templates/Package.h
@@ -0,0 +1,41 @@
+/*MGEN:commentPrefix=//*/
+#ifndef _MANAGEMENT_PACKAGE_/*MGEN:Schema.PackageNameUpper*/_
+#define _MANAGEMENT_PACKAGE_/*MGEN:Schema.PackageNameUpper*/_
+
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+/*MGEN:Root.Disclaimer*/
+
+#include "qpid//*MGEN:Class.AgentHeaderLocation*//ManagementAgent.h"
+
+namespace qmf {
+/*MGEN:Class.OpenNamespaces*/
+
+class Package
+{
+ public:
+ Package (::qpid::management::ManagementAgent* agent);
+ ~Package () {}
+};
+
+}/*MGEN:Class.CloseNamespaces*/
+
+
+#endif /*!_MANAGEMENT_PACKAGE_/*MGEN:Schema.PackageNameUpper*/_*/
diff --git a/cpp/managementgen/schema.py b/cpp/managementgen/schema.py
deleted file mode 100755
index 2ee61fff80..0000000000
--- a/cpp/managementgen/schema.py
+++ /dev/null
@@ -1,1099 +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.
-#
-
-from xml.dom.minidom import parse, parseString, Node
-from cStringIO import StringIO
-import md5
-
-#=====================================================================================
-#
-#=====================================================================================
-class SchemaType:
- def __init__ (self, node):
- self.name = None
- self.base = None
- self.cpp = None
- self.encode = None
- self.decode = None
- self.style = "normal"
- self.accessor = None
- self.init = "0"
- self.perThread = False
-
- attrs = node.attributes
- for idx in range (attrs.length):
- key = attrs.item(idx).nodeName
- val = attrs.item(idx).nodeValue
- if key == 'name':
- self.name = val
-
- elif key == 'base':
- self.base = val
-
- elif key == 'cpp':
- self.cpp = val
-
- elif key == 'encode':
- self.encode = val
-
- elif key == 'decode':
- self.decode = val
-
- elif key == 'style':
- self.style = val
-
- elif key == 'accessor':
- self.accessor = val
-
- elif key == 'init':
- self.init = val
-
- elif key == 'perThread':
- if val != 'y':
- raise ValueError ("Expected 'y' in perThread attribute")
- self.perThread = True
-
- else:
- raise ValueError ("Unknown attribute in type '%s'" % key)
-
- if self.name == None or self.base == None or self.cpp == None or \
- self.encode == None or self.decode == None:
- raise ValueError ("Missing required attribute(s) in type")
-
- def getName (self):
- return self.name
-
- def genAccessor (self, stream, varName, changeFlag = None):
- if self.perThread:
- prefix = "getThreadStats()->"
- if self.style == "wm":
- raise ValueError ("'wm' style types can't be per-thread")
- else:
- prefix = ""
- if self.accessor == "direct":
- stream.write (" inline void set_" + varName + " (" + self.cpp + " val){\n");
- if not self.perThread:
- stream.write (" sys::Mutex::ScopedLock mutex(accessLock);\n")
- if self.style != "mma":
- stream.write (" " + prefix + varName + " = val;\n");
- if self.style == "wm":
- stream.write (" if (" + varName + "Low > val)\n")
- stream.write (" " + varName + "Low = val;\n")
- stream.write (" if (" + varName + "High < val)\n")
- stream.write (" " + varName + "High = val;\n")
- if self.style == "mma":
- stream.write (" " + prefix + varName + "Count++;\n")
- stream.write (" " + prefix + varName + "Total += val;\n")
- stream.write (" if (" + prefix + varName + "Min > val)\n")
- stream.write (" " + prefix + varName + "Min = val;\n")
- stream.write (" if (" + prefix + varName + "Max < val)\n")
- stream.write (" " + prefix + varName + "Max = val;\n")
- if changeFlag != None:
- stream.write (" " + changeFlag + " = true;\n")
- stream.write (" }\n");
- elif self.accessor == "counter":
- stream.write (" inline void inc_" + varName + " (" + self.cpp + " by = 1){\n");
- if not self.perThread:
- stream.write (" sys::Mutex::ScopedLock mutex(accessLock);\n")
- stream.write (" " + prefix + varName + " += by;\n")
- if self.style == "wm":
- stream.write (" if (" + varName + "High < " + varName + ")\n")
- stream.write (" " + varName + "High = " + varName + ";\n")
- if changeFlag != None:
- stream.write (" " + changeFlag + " = true;\n")
- stream.write (" }\n");
- stream.write (" inline void dec_" + varName + " (" + self.cpp + " by = 1){\n");
- if not self.perThread:
- stream.write (" sys::Mutex::ScopedLock mutex(accessLock);\n")
- stream.write (" " + prefix + varName + " -= by;\n")
- if self.style == "wm":
- stream.write (" if (" + varName + "Low > " + varName + ")\n")
- stream.write (" " + varName + "Low = " + varName + ";\n")
- if changeFlag != None:
- stream.write (" " + changeFlag + " = true;\n")
- stream.write (" }\n");
-
- def genHiLoStatResets (self, stream, varName):
- if self.style == "wm":
- stream.write (" " + varName + "High = " + varName + ";\n")
- stream.write (" " + varName + "Low = " + varName + ";\n")
- if self.style == "mma":
- stream.write (" " + varName + "Count = 0;\n")
- stream.write (" " + varName + "Total = 0;\n")
- stream.write (" " + varName + "Min = std::numeric_limits<" + self.type.type.cpp + ">::max();\n")
- stream.write (" " + varName + "Max = std::numeric_limits<" + self.type.type.cpp + ">::min();\n")
-
- def genPerThreadHiLoStatResets (self, stream, varName, cpptype):
- if self.style == "mma":
- stream.write (" threadStats->" + varName + "Count = 0;\n")
- stream.write (" threadStats->" + varName + "Total = 0;\n")
- stream.write (" threadStats->" + varName + "Min = std::numeric_limits<" + cpptype + ">::max();\n")
- stream.write (" threadStats->" + varName + "Max = std::numeric_limits<" + cpptype + ">::min();\n")
-
- def genWrite (self, stream, varName):
- if self.style != "mma":
- stream.write (" " + self.encode.replace ("@", "buf").replace ("#", varName) + ";\n")
- if self.style == "wm":
- stream.write (" " + self.encode.replace ("@", "buf") \
- .replace ("#", varName + "High") + ";\n")
- stream.write (" " + self.encode.replace ("@", "buf") \
- .replace ("#", varName + "Low") + ";\n")
- if self.style == "mma":
- stream.write (" " + self.encode.replace ("@", "buf") \
- .replace ("#", varName + "Count") + ";\n")
- stream.write (" " + self.encode.replace ("@", "buf") \
- .replace ("#", varName + "Count ? " + varName + "Min : 0") + ";\n")
- stream.write (" " + self.encode.replace ("@", "buf") \
- .replace ("#", varName + "Max") + ";\n")
- stream.write (" " + self.encode.replace ("@", "buf") \
- .replace ("#", varName + "Count ? " + varName + "Total / " +
- varName + "Count : 0") + ";\n")
-
-
- def getReadCode (self, varName, bufName):
- result = self.decode.replace ("@", bufName).replace ("#", varName)
- return result
-
- def getWriteCode (self, varName, bufName):
- result = self.encode.replace ("@", bufName).replace ("#", varName)
- return result
-
-#=====================================================================================
-#
-#=====================================================================================
-class TypeSpec:
- def __init__ (self, file):
- self.types = {}
- dom = parse (file)
- document = dom.documentElement
- if document.tagName != 'schema-types':
- raise ValueError ("Expected 'schema-types' in type file")
-
- for child in document.childNodes:
- if child.nodeType == Node.ELEMENT_NODE:
- if child.nodeName == 'type':
- stype = SchemaType (child)
- self.types[stype.getName ()] = stype
- else:
- raise ValueError ("Unknown type tag '%s'" % child.nodeName)
-
- def getType (self, name):
- return self.types[name]
-
-
-#=====================================================================================
-#
-#=====================================================================================
-class Type:
- def __init__ (self, name, typespec):
- self.type = typespec.getType (name)
-
-#=====================================================================================
-#
-#=====================================================================================
-class SchemaConfig:
- def __init__ (self, node, typespec):
- self.name = None
- self.type = None
- self.ref = None
- self.access = "RO"
- self.isIndex = 0
- self.isParentRef = 0
- self.isGeneralRef = 0
- self.unit = None
- self.min = None
- self.max = None
- self.maxLen = None
- self.desc = None
-
- attrs = node.attributes
- for idx in range (attrs.length):
- key = attrs.item(idx).nodeName
- val = attrs.item(idx).nodeValue
- if key == 'name':
- self.name = makeValidCppSymbol(val)
-
- elif key == 'type':
- self.type = Type (val, typespec)
- if self.type.type.accessor != 'direct':
- raise ValueError ("Class properties must have a type with a direct accessor")
-
- elif key == 'references':
- self.ref = val
-
- elif key == 'access':
- self.access = val
-
- elif key == 'index':
- if val != 'y':
- raise ValueError ("Expected 'y' in index attribute")
- self.isIndex = 1
-
- elif key == 'parentRef':
- if val != 'y':
- raise ValueError ("Expected 'y' in parentRef attribute")
- self.isParentRef = 1
-
- elif key == 'isGeneralReference':
- if val != 'y':
- raise ValueError ("Expected 'y' in isGeneralReference attribute")
- self.isGeneralRef = 1
-
- elif key == 'unit':
- self.unit = val
-
- elif key == 'min':
- self.min = val
-
- elif key == 'max':
- self.max = val
-
- elif key == 'maxlen':
- self.maxLen = val
-
- elif key == 'desc':
- self.desc = val
-
- else:
- raise ValueError ("Unknown attribute in property '%s'" % key)
-
- if self.name == None:
- raise ValueError ("Missing 'name' attribute in property")
- if self.type == None:
- raise ValueError ("Missing 'type' attribute in property")
-
- def getName (self):
- return self.name
-
- def isConstructorArg (self):
- if self.access == "RC" and self.isParentRef == 0:
- return 1
- return 0
-
- def genDeclaration (self, stream, prefix=" "):
- stream.write (prefix + self.type.type.cpp + " " + self.name + ";\n")
-
- def genFormalParam (self, stream):
- stream.write (self.type.type.cpp + " _" + self.name)
-
- def genAccessor (self, stream):
- self.type.type.genAccessor (stream, self.name, "configChanged")
-
- def genSchema (self, stream):
- stream.write (" ft = FieldTable ();\n")
- stream.write (" ft.setString (NAME, \"" + self.name + "\");\n")
- stream.write (" ft.setInt (TYPE, TYPE_" + self.type.type.base +");\n")
- stream.write (" ft.setInt (ACCESS, ACCESS_" + self.access + ");\n")
- stream.write (" ft.setInt (INDEX, " + str (self.isIndex) + ");\n")
- if self.unit != None:
- stream.write (" ft.setString (UNIT, \"" + self.unit + "\");\n")
- if self.min != None:
- stream.write (" ft.setInt (MIN, " + self.min + ");\n")
- if self.max != None:
- stream.write (" ft.setInt (MAX, " + self.max + ");\n")
- if self.maxLen != None:
- stream.write (" ft.setInt (MAXLEN, " + self.maxLen + ");\n")
- if self.desc != None:
- stream.write (" ft.setString (DESC, \"" + self.desc + "\");\n")
- stream.write (" buf.put (ft);\n\n")
-
- def genWrite (self, stream):
- self.type.type.genWrite (stream, self.name)
-
-
-#=====================================================================================
-#
-#=====================================================================================
-class SchemaInst:
- def __init__ (self, node, typespec):
- self.name = None
- self.type = None
- self.unit = None
- self.desc = None
- self.assign = None
-
- attrs = node.attributes
- for idx in range (attrs.length):
- key = attrs.item(idx).nodeName
- val = attrs.item(idx).nodeValue
- if key == 'name':
- self.name = makeValidCppSymbol(val)
-
- elif key == 'type':
- self.type = Type (val, typespec)
-
- elif key == 'unit':
- self.unit = val
-
- elif key == 'desc':
- self.desc = val
-
- elif key == 'assign':
- self.assign = val
-
- else:
- raise ValueError ("Unknown attribute in statistic '%s'" % key)
-
- if self.name == None:
- raise ValueError ("Missing 'name' attribute in statistic")
- if self.type == None:
- raise ValueError ("Missing 'type' attribute in statistic")
-
- def getName (self):
- return self.name
-
- def genDeclaration (self, stream, prefix=" "):
- if self.type.type.style != "mma":
- stream.write (prefix + self.type.type.cpp + " " + self.name + ";\n")
- if self.type.type.style == 'wm':
- stream.write (prefix + self.type.type.cpp + " " + self.name + "High;\n")
- stream.write (prefix + self.type.type.cpp + " " + self.name + "Low;\n")
- if self.type.type.style == "mma":
- stream.write (prefix + self.type.type.cpp + " " + self.name + "Count;\n")
- stream.write (prefix + "uint64_t " + self.name + "Total;\n")
- stream.write (prefix + self.type.type.cpp + " " + self.name + "Min;\n")
- stream.write (prefix + self.type.type.cpp + " " + self.name + "Max;\n")
-
- def genAccessor (self, stream):
- self.type.type.genAccessor (stream, self.name, "instChanged")
-
- def genHiLoStatResets (self, stream):
- self.type.type.genHiLoStatResets (stream, self.name)
-
- def genPerThreadHiLoStatResets (self, stream):
- self.type.type.genPerThreadHiLoStatResets (stream, self.name, self.type.type.cpp)
-
- def genSchemaText (self, stream, name, desc):
- stream.write (" ft = FieldTable ();\n")
- stream.write (" ft.setString (NAME, \"" + name + "\");\n")
- stream.write (" ft.setInt (TYPE, TYPE_" + self.type.type.base +");\n")
- if self.unit != None:
- stream.write (" ft.setString (UNIT, \"" + self.unit + "\");\n")
- if desc != None:
- stream.write (" ft.setString (DESC, \"" + desc + "\");\n")
- stream.write (" buf.put (ft);\n\n")
-
- def genSchema (self, stream):
- if self.type.type.style != "mma":
- self.genSchemaText (stream, self.name, self.desc)
- if self.type.type.style == "wm":
- descHigh = self.desc
- descLow = self.desc
- if self.desc != None:
- descHigh = descHigh + " (High)"
- descLow = descLow + " (Low)"
- self.genSchemaText (stream, self.name + "High", descHigh)
- self.genSchemaText (stream, self.name + "Low", descLow)
- if self.type.type.style == "mma":
- descCount = self.desc
- descMin = self.desc
- descMax = self.desc
- descAverage = self.desc
- if self.desc != None:
- descCount = descCount + " (Samples)"
- descMin = descMin + " (Min)"
- descMax = descMax + " (Max)"
- descAverage = descAverage + " (Average)"
- self.genSchemaText (stream, self.name + "Samples", descCount)
- self.genSchemaText (stream, self.name + "Min", descMin)
- self.genSchemaText (stream, self.name + "Max", descMax)
- self.genSchemaText (stream, self.name + "Average", descAverage)
-
- def genAssign (self, stream):
- if self.assign != None:
- if self.type.type.perThread:
- prefix = " threadStats->"
- else:
- prefix = ""
- stream.write (" " + prefix + self.name + " = (" + self.type.type.cpp +
- ") (" + self.assign + ");\n")
-
- def genWrite (self, stream):
- if self.type.type.perThread:
- self.type.type.genWrite (stream, "totals." + self.name)
- else:
- self.type.type.genWrite (stream, self.name)
-
- def genInitialize (self, stream, prefix="", indent=" "):
- val = self.type.type.init
- if self.type.type.style != "mma":
- stream.write (indent + prefix + self.name + " = " + val + ";\n")
- if self.type.type.style == "wm":
- stream.write (indent + prefix + self.name + "High = " + val + ";\n")
- stream.write (indent + prefix + self.name + "Low = " + val + ";\n")
- if self.type.type.style == "mma":
- stream.write (indent + prefix + self.name + "Count = 0;\n")
- stream.write (indent + prefix + self.name + "Min = std::numeric_limits<" + self.type.type.cpp + ">::max();\n")
- stream.write (indent + prefix + self.name + "Max = std::numeric_limits<" + self.type.type.cpp + ">::min();\n")
- stream.write (indent + prefix + self.name + "Total = 0;\n")
-
- def genInitializeTotalPerThreadStats (self, stream):
- if self.type.type.style == "mma":
- stream.write (" totals->" + self.name + "Count = 0;\n")
- stream.write (" totals->" + self.name + "Min = std::numeric_limits<" + self.type.type.cpp + ">::max();\n")
- stream.write (" totals->" + self.name + "Max = std::numeric_limits<" + self.type.type.cpp + ">::min();\n")
- stream.write (" totals->" + self.name + "Total = 0;\n")
- else:
- stream.write (" totals->" + self.name + " = 0;\n")
-
- def genAggregatePerThreadStats (self, stream):
- if self.type.type.style == "mma":
- stream.write (" totals->%sCount += threadStats->%sCount;\n" % (self.name, self.name))
- stream.write (" if (totals->%sMin > threadStats->%sMin)\n" % (self.name, self.name))
- stream.write (" totals->%sMin = threadStats->%sMin;\n" % (self.name, self.name))
- stream.write (" if (totals->%sMax < threadStats->%sMax)\n" % (self.name, self.name))
- stream.write (" totals->%sMax = threadStats->%sMax;\n" % (self.name, self.name))
- stream.write (" totals->%sTotal += threadStats->%sTotal;\n" % (self.name, self.name))
- else:
- stream.write (" totals->%s += threadStats->%s;\n" % (self.name, self.name))
-
-#=====================================================================================
-#
-#=====================================================================================
-class SchemaArg:
- def __init__ (self, node, typespec):
- self.name = None
- self.type = None
- self.unit = None
- self.dir = "I"
- self.min = None
- self.max = None
- self.maxLen = None
- self.desc = None
- self.default = None
-
- attrs = node.attributes
- for idx in range (attrs.length):
- key = attrs.item(idx).nodeName
- val = attrs.item(idx).nodeValue
- if key == 'name':
- self.name = makeValidCppSymbol(val)
-
- elif key == 'type':
- self.type = Type (val, typespec)
-
- elif key == 'unit':
- self.unit = val
-
- elif key == 'dir':
- self.dir = val.upper ()
-
- elif key == 'min':
- self.min = val
-
- elif key == 'max':
- self.max = val
-
- elif key == 'maxlen':
- self.maxLen = val
-
- elif key == 'desc':
- self.desc = val
-
- elif key == 'default':
- self.default = val
-
- else:
- raise ValueError ("Unknown attribute in arg '%s'" % key)
-
- if self.name == None:
- raise ValueError ("Missing 'name' attribute in arg")
- if self.type == None:
- raise ValueError ("Missing 'type' attribute in arg")
-
- def getName (self):
- return self.name
-
- def getDir (self):
- return self.dir
-
- def genSchema (self, stream):
- stream.write (" ft = FieldTable ();\n")
- stream.write (" ft.setString (NAME, \"" + self.name + "\");\n")
- stream.write (" ft.setInt (TYPE, TYPE_" + self.type.type.base +");\n")
- stream.write (" ft.setString (DIR, \"" + self.dir + "\");\n")
- if self.unit != None:
- stream.write (" ft.setString (UNIT, \"" + self.unit + "\");\n")
- if self.min != None:
- stream.write (" ft.setInt (MIN, " + self.min + ");\n")
- if self.max != None:
- stream.write (" ft.setInt (MAX, " + self.max + ");\n")
- if self.maxLen != None:
- stream.write (" ft.setInt (MAXLEN, " + self.maxLen + ");\n")
- if self.desc != None:
- stream.write (" ft.setString (DESC, \"" + self.desc + "\");\n")
- if self.default != None:
- stream.write (" ft.setString (DEFAULT, \"" + self.default + "\");\n")
- stream.write (" buf.put (ft);\n\n")
-
-#=====================================================================================
-#
-#=====================================================================================
-class SchemaMethod:
- def __init__ (self, parent, node, typespec):
- self.parent = parent
- self.name = None
- self.desc = None
- self.args = []
-
- attrs = node.attributes
- for idx in range (attrs.length):
- key = attrs.item(idx).nodeName
- val = attrs.item(idx).nodeValue
- if key == 'name':
- self.name = makeValidCppSymbol(val)
-
- elif key == 'desc':
- self.desc = val
-
- else:
- raise ValueError ("Unknown attribute in method '%s'" % key)
-
- for child in node.childNodes:
- if child.nodeType == Node.ELEMENT_NODE:
- if child.nodeName == 'arg':
- arg = SchemaArg (child, typespec)
- self.args.append (arg)
- else:
- raise ValueError ("Unknown method tag '%s'" % child.nodeName)
-
- def getName (self):
- return self.name
-
- def getFullName (self):
- return capitalize(self.parent.getName()) + self.name[0:1].upper() +\
- self.name[1:]
-
- def getArgCount (self):
- return len (self.args)
-
- #===================================================================================
- # Code Generation Functions. The names of these functions (minus the leading "gen")
- # match the substitution keywords in the template files.
- #===================================================================================
- def genNameUpper (self, stream, variables):
- stream.write (self.getFullName ().upper ())
-
- def genNameCamel (self, stream, variables):
- stream.write (self.getFullName ())
-
- def genArguments (self, stream, variables):
- for arg in self.args:
- ctype = arg.type.type.cpp
- dirTag = arg.dir.lower() + "_"
- stream.write (" " + ctype + " " + dirTag + arg.getName () + ";\n")
-
- def genSchema (self, stream, variables):
- stream.write (" ft = FieldTable ();\n")
- stream.write (" ft.setString (NAME, \"" + self.name + "\");\n")
- stream.write (" ft.setInt (ARGCOUNT, " + str (len (self.args)) + ");\n")
- if self.desc != None:
- stream.write (" ft.setString (DESC, \"" + self.desc + "\");\n")
- stream.write (" buf.put (ft);\n\n")
- for arg in self.args:
- arg.genSchema (stream)
-
-#=====================================================================================
-#
-#=====================================================================================
-class SchemaEvent:
- def __init__ (self, parent, node, typespec):
- self.parent = parent
- self.name = None
- self.desc = None
- self.args = []
-
- attrs = node.attributes
- for idx in range (attrs.length):
- key = attrs.item(idx).nodeName
- val = attrs.item(idx).nodeValue
- if key == 'name':
- self.name = val
-
- elif key == 'desc':
- self.desc = val
-
- else:
- raise ValueError ("Unknown attribute in event '%s'" % key)
-
- for child in node.childNodes:
- if child.nodeType == Node.ELEMENT_NODE:
- if child.nodeName == 'arg':
- arg = SchemaArg (child, typespec)
- self.args.append (arg)
- else:
- raise ValueError ("Unknown event tag '%s'" % child.nodeName)
-
- def getName (self):
- return self.name
-
- def getFullName (self):
- return capitalize(self.parent.getName()) + capitalize(self.name)
-
- def getArgCount (self):
- return len (self.args)
-
-
-class SchemaClass:
- def __init__ (self, package, node, typespec, fragments, options):
- self.packageName = package
- self.properties = []
- self.statistics = []
- self.methods = []
- self.events = []
- self.options = options
- self.md5Sum = md5.new ()
-
- self.hash (node)
-
- attrs = node.attributes
- self.name = makeValidCppSymbol(attrs['name'].nodeValue)
-
- children = node.childNodes
- for child in children:
- if child.nodeType == Node.ELEMENT_NODE:
- if child.nodeName == 'property':
- sub = SchemaConfig (child, typespec)
- self.properties.append (sub)
-
- elif child.nodeName == 'statistic':
- sub = SchemaInst (child, typespec)
- self.statistics.append (sub)
-
- elif child.nodeName == 'method':
- sub = SchemaMethod (self, child, typespec)
- self.methods.append (sub)
-
- elif child.nodeName == 'event':
- sub = SchemaEvent (self, child, typespec)
- self.events.append (sub)
-
- elif child.nodeName == 'group':
- self.expandFragment (child, fragments)
-
- else:
- raise ValueError ("Unknown class tag '%s'" % child.nodeName)
-
- # Adjust the 'assign' attributes for each statistic
- for stat in self.statistics:
- if stat.assign != None and stat.type.type.perThread:
- stat.assign = self.adjust (stat.assign, self.statistics)
-
- def adjust (self, text, statistics):
- result = text
- start = 0
- while True:
- next = None
- for stat in statistics:
- pos = result.find (stat.name, start)
- if pos != -1 and (next == None or pos < next[0]):
- next = (pos, stat.name)
- if next == None:
- return result
- pos = next[0]
- result = result[0:pos] + "threadStats->" + result[pos:]
- start = pos + 9 + len(next[1])
-
- def hash (self, node):
- attrs = node.attributes
- self.md5Sum.update (node.nodeName)
-
- for idx in range (attrs.length):
- self.md5Sum.update (attrs.item(idx).nodeName)
- self.md5Sum.update (attrs.item(idx).nodeValue)
-
- for child in node.childNodes:
- if child.nodeType == Node.ELEMENT_NODE:
- self.hash (child)
-
- def expandFragment (self, node, fragments):
- attrs = node.attributes
- name = attrs['name'].nodeValue
- for fragment in fragments:
- if fragment.name == name:
- self.md5Sum.update (fragment.md5Sum.digest())
- for config in fragment.properties:
- self.properties.append (config)
- for inst in fragment.statistics:
- self.statistics.append (inst)
- for method in fragment.methods:
- self.methods.append (method)
- for event in fragment.events:
- self.events.append (event)
- return
- raise ValueError ("Undefined group '%s'" % name)
-
- def getName (self):
- return self.name
-
- def getNameCap (self):
- return capitalize(self.name)
-
- def getMethods (self):
- return self.methods
-
- def getEvents (self):
- return self.events
-
- def getPackageNameCap (self):
- return capitalize(self.packageName)
-
- #===================================================================================
- # Code Generation Functions. The names of these functions (minus the leading "gen")
- # match the substitution keywords in the template files.
- #===================================================================================
- def testExistPerThreadStats (self, variables):
- for inst in self.statistics:
- if inst.type.type.perThread:
- return True
- return False
-
- def testExistPerThreadAssign (self, variables):
- for inst in self.statistics:
- if inst.type.type.perThread and inst.assign != None:
- return True
- return False
-
- def testExistPerThreadResets (self, variables):
- for inst in self.statistics:
- if inst.type.type.perThread and inst.type.type.style == "mma":
- return True
- return False
-
- def testNoStatistics (self, variables):
- return len (self.statistics) == 0
-
- def genAccessorMethods (self, stream, variables):
- for config in self.properties:
- if config.access != "RC":
- config.genAccessor (stream)
- for inst in self.statistics:
- if inst.assign == None:
- inst.genAccessor (stream)
-
- def genConfigCount (self, stream, variables):
- stream.write ("%d" % len (self.properties))
-
- def genConfigDeclarations (self, stream, variables):
- for element in self.properties:
- element.genDeclaration (stream)
-
- def genConfigElementSchema (self, stream, variables):
- for config in self.properties:
- config.genSchema (stream)
-
- def genConstructorArgs (self, stream, variables):
- # Constructor args are config elements with read-create access
- result = ""
- for element in self.properties:
- if element.isConstructorArg ():
- stream.write (", ")
- element.genFormalParam (stream)
-
- def genConstructorInits (self, stream, variables):
- for element in self.properties:
- if element.isConstructorArg ():
- stream.write ("," + element.getName () + "(_" + element.getName () + ")")
-
- def genDoMethodArgs (self, stream, variables):
- methodCount = 0
- inArgCount = 0
- for method in self.methods:
- methodCount = methodCount + 1
- for arg in method.args:
- if arg.getDir () == "I" or arg.getDir () == "IO":
- inArgCount = inArgCount + 1
-
- if methodCount == 0:
- stream.write ("string, Buffer&, Buffer& outBuf")
- else:
- if inArgCount == 0:
- stream.write ("string methodName, Buffer&, Buffer& outBuf")
- else:
- stream.write ("string methodName, Buffer& inBuf, Buffer& outBuf")
-
- def genEventCount (self, stream, variables):
- stream.write ("%d" % len (self.events))
-
- def genEventSchema (self, stream, variables):
- pass ###########################################################################
-
- def genHiLoStatResets (self, stream, variables):
- for inst in self.statistics:
- if not inst.type.type.perThread:
- inst.genHiLoStatResets (stream)
-
- def genPerThreadHiLoStatResets (self, stream, variables):
- for inst in self.statistics:
- if inst.type.type.perThread:
- inst.genPerThreadHiLoStatResets (stream)
-
- def genInitializeElements (self, stream, variables):
- for inst in self.statistics:
- if not inst.type.type.perThread:
- inst.genInitialize (stream)
-
- def genInitializePerThreadElements (self, stream, variables):
- for inst in self.statistics:
- if inst.type.type.perThread:
- inst.genInitialize (stream, "threadStats->", " ")
-
- def genInitializeTotalPerThreadStats (self, stream, variables):
- for inst in self.statistics:
- if inst.type.type.perThread:
- inst.genInitializeTotalPerThreadStats (stream)
-
- def genAggregatePerThreadStats (self, stream, variables):
- for inst in self.statistics:
- if inst.type.type.perThread:
- inst.genAggregatePerThreadStats (stream)
-
- def genInstCount (self, stream, variables):
- count = 0
- for inst in self.statistics:
- count = count + 1
- if inst.type.type.style == "wm":
- count = count + 2
- if inst.type.type.style == "mma":
- count = count + 3
- stream.write ("%d" % count)
-
- def genInstDeclarations (self, stream, variables):
- for element in self.statistics:
- if not element.type.type.perThread:
- element.genDeclaration (stream)
-
- def genPerThreadDeclarations (self, stream, variables):
- for element in self.statistics:
- if element.type.type.perThread:
- element.genDeclaration (stream, " ")
-
- def genInstElementSchema (self, stream, variables):
- for inst in self.statistics:
- inst.genSchema (stream)
-
- def genMethodArgIncludes (self, stream, variables):
- for method in self.methods:
- if method.getArgCount () > 0:
- stream.write ("#include \"Args" + method.getFullName () + ".h\"\n")
-
- def genMethodCount (self, stream, variables):
- stream.write ("%d" % len (self.methods))
-
- def genMethodHandlers (self, stream, variables):
- for method in self.methods:
- stream.write ("\n if (methodName == \"" + method.getName () + "\")\n {\n")
- if method.getArgCount () == 0:
- stream.write (" ArgsNone ioArgs;\n")
- else:
- stream.write (" Args" + method.getFullName () + " ioArgs;\n")
- for arg in method.args:
- if arg.getDir () == "I" or arg.getDir () == "IO":
- stream.write (" " +\
- arg.type.type.getReadCode ("ioArgs." +\
- arg.dir.lower () + "_" +\
- arg.name, "inBuf") + ";\n")
-
- stream.write (" status = coreObject->ManagementMethod (METHOD_" +\
- method.getName().upper() + ", ioArgs);\n")
- stream.write (" outBuf.putLong (status);\n")
- stream.write (" outBuf.putShortString (Manageable::StatusText (status));\n")
- for arg in method.args:
- if arg.getDir () == "O" or arg.getDir () == "IO":
- stream.write (" " +\
- arg.type.type.getWriteCode ("ioArgs." +\
- arg.dir.lower () + "_" +\
- arg.name, "outBuf") + ";\n")
- stream.write (" return;\n }\n")
-
- def genSetGeneralReferenceDeclaration (self, stream, variables):
- for prop in self.properties:
- if prop.isGeneralRef:
- stream.write ("void setReference(uint64_t objectId) { " + prop.name + " = objectId; }\n")
-
- def genMethodIdDeclarations (self, stream, variables):
- number = 1
- for method in self.methods:
- stream.write (" static const uint32_t METHOD_" + method.getName().upper() +\
- " = %d;\n" % number)
- number = number + 1
-
- def genMethodSchema (self, stream, variables):
- for method in self.methods:
- method.genSchema (stream, variables)
-
- def genNameCap (self, stream, variables):
- stream.write (capitalize(self.name))
-
- def genNameLower (self, stream, variables):
- stream.write (self.name.lower ())
-
- def genNamePackageCap (self, stream, variables):
- stream.write (self.getPackageNameCap ())
-
- def genNamePackageLower (self, stream, variables):
- stream.write (self.packageName.lower ())
-
- def genNameUpper (self, stream, variables):
- stream.write (self.name.upper ())
-
- def genParentArg (self, stream, variables):
- for config in self.properties:
- if config.isParentRef == 1:
- stream.write (", Manageable* _parent")
- return
-
- def genParentRefAssignment (self, stream, variables):
- for config in self.properties:
- if config.isParentRef == 1:
- stream.write (config.getName () + \
- " = _parent->GetManagementObject ()->getObjectId ();")
- return
-
- def genSchemaMD5 (self, stream, variables):
- sum = self.md5Sum.digest ()
- for idx in range (len (sum)):
- if idx != 0:
- stream.write (",")
- stream.write (hex (ord (sum[idx])))
-
- def genAssign (self, stream, variables):
- for inst in self.statistics:
- if not inst.type.type.perThread:
- inst.genAssign (stream)
-
- def genPerThreadAssign (self, stream, variables):
- for inst in self.statistics:
- if inst.type.type.perThread:
- inst.genAssign (stream)
-
- def genWriteConfig (self, stream, variables):
- for config in self.properties:
- config.genWrite (stream)
-
- def genWriteInst (self, stream, variables):
- for inst in self.statistics:
- inst.genWrite (stream)
-
-
-
-class PackageSchema:
- def __init__ (self, typefile, schemafile, options):
-
- self.classes = []
- self.fragments = []
- self.typespec = TypeSpec (typefile)
-
- dom = parse (schemafile)
- document = dom.documentElement
- if document.tagName != 'schema':
- raise ValueError ("Expected 'schema' node")
- attrs = document.attributes
- self.packageName = makeValidCppSymbol(attrs['package'].nodeValue)
-
- children = document.childNodes
- for child in children:
- if child.nodeType == Node.ELEMENT_NODE:
- if child.nodeName == 'class':
- cls = SchemaClass (self.packageName, child, self.typespec,
- self.fragments, options)
- self.classes.append (cls)
-
- elif child.nodeName == 'group':
- cls = SchemaClass (self.packageName, child, self.typespec,
- self.fragments, options)
- self.fragments.append (cls)
-
- else:
- raise ValueError ("Unknown schema tag '%s'" % child.nodeName)
-
- def getPackageName (self):
- return self.packageName
-
- def getPackageNameCap (self):
- return capitalize(self.packageName)
-
- def getClasses (self):
- return self.classes
-
- def genPackageNameUpper (self, stream, variables):
- stream.write (self.packageName.upper ())
-
- def genPackageNameCap (self, stream, variables):
- stream.write (self.getPackageNameCap ())
-
- def genClassIncludes (self, stream, variables):
- for _class in self.classes:
- stream.write ("#include \"")
- _class.genNameCap (stream, variables)
- stream.write (".h\"\n")
-
- def genClassRegisters (self, stream, variables):
- for _class in self.classes:
- stream.write ("agent->RegisterClass (")
- _class.genNameCap (stream, variables)
- stream.write ("::packageName, ")
- _class.genNameCap (stream, variables)
- stream.write ("::className, ")
- _class.genNameCap (stream, variables)
- stream.write ("::md5Sum, ")
- _class.genNameCap (stream, variables)
- stream.write ("::writeSchema);\n")
-
-
-#=====================================================================================
-# Utility Functions
-#=====================================================================================
-
-# Create a valid C++ symbol from the input string so that it can be
-# used in generated C++ source. For instance, change "qpid.mgmt" to
-# "qpidMgmt".
-#
-# Input: Raw string (str) to process
-# Output: String (str) suitable for use as a C++ symbol
-#
-# Limitations: Currently, only strips periods ('.') from strings,
-# eventually should strip :'s and ,'s and ''s, oh my!
-def makeValidCppSymbol(input):
- output = str()
- capitalize = False
-
- for char in input:
- skip = False
-
- if char == ".":
- capitalize = True
- skip = True
-
- if not skip:
- output += capitalize and char.upper() or char
-
- capitalize = False
-
- return output
-
-# Capitalize a string by /only/ forcing the first character to be
-# uppercase. The rest of the string is left alone. This is different
-# from str.capitalize(), which forces the first character to uppercase
-# and the rest to lowercase.
-#
-# Input: A string (str) to capitalize
-# Output: A string (str) with the first character as uppercase
-def capitalize(input):
- return input[0].upper() + input[1:]
diff --git a/cpp/managementgen/templates/Args.h b/cpp/managementgen/templates/Args.h
deleted file mode 100644
index 576d891a3f..0000000000
--- a/cpp/managementgen/templates/Args.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*MGEN:commentPrefix=//*/
-#ifndef _ARGS_/*MGEN:Method.NameUpper*/_
-#define _ARGS_/*MGEN:Method.NameUpper*/_
-
-//
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-//
-
-/*MGEN:Root.Disclaimer*/
-
-#include "qpid/management/Args.h"
-#include <string>
-
-namespace qpid {
-namespace management {
-
-class Args/*MGEN:Method.NameCamel*/ : public Args
-{
- public:
-/*MGEN:Method.Arguments*/
-};
-
-}}
-
-#endif /*!_ARGS_/*MGEN:Method.NameUpper*/_*/
diff --git a/cpp/managementgen/templates/Class.cpp b/cpp/managementgen/templates/Class.cpp
deleted file mode 100644
index 289427d742..0000000000
--- a/cpp/managementgen/templates/Class.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-/*MGEN:commentPrefix=//*/
-//
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-//
-
-/*MGEN:Root.Disclaimer*/
-
-#include "qpid/log/Statement.h"
-#include "qpid/framing/FieldTable.h"
-#include "qpid/management/Manageable.h"
-#include "qpid/agent/ManagementAgent.h"
-#include "/*MGEN:Class.NameCap*/.h"
-/*MGEN:Class.MethodArgIncludes*/
-
-using namespace qpid::management;
-using namespace qpid::sys;
-using namespace qpid::framing;
-using std::string;
-
-string /*MGEN:Class.NameCap*/::packageName = string ("/*MGEN:Class.NamePackageLower*/");
-string /*MGEN:Class.NameCap*/::className = string ("/*MGEN:Class.NameLower*/");
-uint8_t /*MGEN:Class.NameCap*/::md5Sum[16] =
- {/*MGEN:Class.SchemaMD5*/};
-
-/*MGEN:Class.NameCap*/::/*MGEN:Class.NameCap*/ (ManagementAgent* _agent, Manageable* _core/*MGEN:Class.ParentArg*//*MGEN:Class.ConstructorArgs*/) :
- ManagementObject(_agent, _core)/*MGEN:Class.ConstructorInits*/
-{
- /*MGEN:Class.ParentRefAssignment*/
-/*MGEN:Class.InitializeElements*/
-/*MGEN:IF(Class.ExistPerThreadStats)*/
- maxThreads = agent->getMaxThreads();
- perThreadStatsArray = new struct PerThreadStats*[maxThreads];
- for (int idx = 0; idx < maxThreads; idx++)
- perThreadStatsArray[idx] = 0;
-/*MGEN:ENDIF*/
-}
-
-/*MGEN:Class.NameCap*/::~/*MGEN:Class.NameCap*/ ()
-{
-/*MGEN:IF(Class.ExistPerThreadStats)*/
- for (int idx = 0; idx < maxThreads; idx++)
- if (perThreadStatsArray[idx] != 0)
- delete perThreadStatsArray[idx];
- delete[] perThreadStatsArray;
-/*MGEN:ENDIF*/
-}
-
-namespace {
- const string NAME("name");
- const string TYPE("type");
- const string ACCESS("access");
- const string INDEX("index");
- const string UNIT("unit");
- const string MIN("min");
- const string MAX("max");
- const string MAXLEN("maxlen");
- const string DESC("desc");
- const string ARGCOUNT("argCount");
- const string ARGS("args");
- const string DIR("dir");
- const string DEFAULT("default");
-}
-
-void /*MGEN:Class.NameCap*/::writeSchema (Buffer& buf)
-{
- FieldTable ft;
-
- // Schema class header:
- buf.putShortString (packageName); // Package Name
- buf.putShortString (className); // Class Name
- buf.putBin128 (md5Sum); // Schema Hash
- buf.putShort (/*MGEN:Class.ConfigCount*/); // Config Element Count
- buf.putShort (/*MGEN:Class.InstCount*/); // Inst Element Count
- buf.putShort (/*MGEN:Class.MethodCount*/); // Method Count
- buf.putShort (/*MGEN:Class.EventCount*/); // Event Count
-
- // Properties
-/*MGEN:Class.ConfigElementSchema*/
- // Statistics
-/*MGEN:Class.InstElementSchema*/
- // Methods
-/*MGEN:Class.MethodSchema*/
- // Events
-/*MGEN:Class.EventSchema*/
-}
-
-/*MGEN:IF(Class.ExistPerThreadStats)*/
-void /*MGEN:Class.NameCap*/::aggregatePerThreadStats(struct PerThreadStats* totals)
-{
-/*MGEN:Class.InitializeTotalPerThreadStats*/
- for (int idx = 0; idx < maxThreads; idx++) {
- struct PerThreadStats* threadStats = perThreadStatsArray[idx];
- if (threadStats != 0) {
-/*MGEN:Class.AggregatePerThreadStats*/
- }
- }
-}
-/*MGEN:ENDIF*/
-
-void /*MGEN:Class.NameCap*/::writeProperties (Buffer& buf)
-{
- sys::Mutex::ScopedLock mutex(accessLock);
- configChanged = false;
-
- writeTimestamps (buf);
-/*MGEN:Class.WriteConfig*/
-}
-
-void /*MGEN:Class.NameCap*/::writeStatistics (Buffer& buf, bool skipHeaders)
-{
- sys::Mutex::ScopedLock mutex(accessLock);
- instChanged = false;
-/*MGEN:IF(Class.ExistPerThreadAssign)*/
- for (int idx = 0; idx < maxThreads; idx++) {
- struct PerThreadStats* threadStats = perThreadStatsArray[idx];
- if (threadStats != 0) {
-/*MGEN:Class.PerThreadAssign*/
- }
- }
-/*MGEN:ENDIF*/
-/*MGEN:IF(Class.ExistPerThreadStats)*/
- struct PerThreadStats totals;
- aggregatePerThreadStats(&totals);
-/*MGEN:ENDIF*/
-/*MGEN:Class.Assign*/
- if (!skipHeaders)
- writeTimestamps (buf);
-/*MGEN:Class.WriteInst*/
-
- // Maintenance of hi-lo statistics
-/*MGEN:Class.HiLoStatResets*/
-/*MGEN:IF(Class.ExistPerThreadResets)*/
- for (int idx = 0; idx < maxThreads; idx++) {
- struct PerThreadStats* threadStats = perThreadStatsArray[idx];
- if (threadStats != 0) {
-/*MGEN:Class.PerThreadHiLoStatResets*/
- }
- }
-/*MGEN:ENDIF*/
-}
-
-void /*MGEN:Class.NameCap*/::doMethod (/*MGEN:Class.DoMethodArgs*/)
-{
- Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD;
-/*MGEN:Class.MethodHandlers*/
- outBuf.putLong (status);
- outBuf.putShortString (Manageable::StatusText (status));
-}
-
diff --git a/cpp/managementgen/templates/Class.h b/cpp/managementgen/templates/Class.h
deleted file mode 100644
index fac63d5d55..0000000000
--- a/cpp/managementgen/templates/Class.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*MGEN:commentPrefix=//*/
-#ifndef _MANAGEMENT_/*MGEN:Class.NameUpper*/_
-#define _MANAGEMENT_/*MGEN:Class.NameUpper*/_
-
-//
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-//
-
-/*MGEN:Root.Disclaimer*/
-
-#include "qpid/management/ManagementObject.h"
-#include "qpid/framing/FieldTable.h"
-#include "qpid/framing/Uuid.h"
-
-namespace qpid {
-namespace management {
-
-class /*MGEN:Class.NameCap*/ : public ManagementObject
-{
- private:
-
- static std::string packageName;
- static std::string className;
- static uint8_t md5Sum[16];
-
- // Properties
-/*MGEN:Class.ConfigDeclarations*/
- // Statistics
-/*MGEN:Class.InstDeclarations*/
-/*MGEN:IF(Class.ExistPerThreadStats)*/
- // Per-Thread Statistics
- struct PerThreadStats {
-/*MGEN:Class.PerThreadDeclarations*/
- };
-
- struct PerThreadStats** perThreadStatsArray;
-
- inline struct PerThreadStats* getThreadStats() {
- int index = getThreadIndex();
- struct PerThreadStats* threadStats = perThreadStatsArray[index];
- if (threadStats == 0) {
- threadStats = new(PerThreadStats);
- perThreadStatsArray[index] = threadStats;
-/*MGEN:Class.InitializePerThreadElements*/
- }
- return threadStats;
- }
-
- void aggregatePerThreadStats(struct PerThreadStats*);
-/*MGEN:ENDIF*/
- // Private Methods
- static void writeSchema (qpid::framing::Buffer& buf);
- void writeProperties (qpid::framing::Buffer& buf);
- void writeStatistics (qpid::framing::Buffer& buf,
- bool skipHeaders = false);
- void doMethod (std::string methodName,
- qpid::framing::Buffer& inBuf,
- qpid::framing::Buffer& outBuf);
- writeSchemaCall_t getWriteSchemaCall(void) { return writeSchema; }
-/*MGEN:IF(Class.NoStatistics)*/
- // Stub for getInstChanged. There are no statistics in this class.
- bool getInstChanged (void) { return false; }
-/*MGEN:ENDIF*/
- public:
-
- friend class Package/*MGEN:Class.NamePackageCap*/;
-
- /*MGEN:Class.NameCap*/ (ManagementAgent* agent,
- Manageable* coreObject/*MGEN:Class.ParentArg*//*MGEN:Class.ConstructorArgs*/);
- ~/*MGEN:Class.NameCap*/ (void);
-
- /*MGEN:Class.SetGeneralReferenceDeclaration*/
-
- std::string& getPackageName (void) { return packageName; }
- std::string& getClassName (void) { return className; }
- uint8_t* getMd5Sum (void) { return md5Sum; }
-
- // Method IDs
-/*MGEN:Class.MethodIdDeclarations*/
- // Accessor Methods
-/*MGEN:Class.AccessorMethods*/
-};
-
-}}
-
-#endif /*!_MANAGEMENT_/*MGEN:Class.NameUpper*/_*/
diff --git a/cpp/managementgen/templates/Makefile.mk b/cpp/managementgen/templates/Makefile.mk
deleted file mode 100644
index 0e6454c13a..0000000000
--- a/cpp/managementgen/templates/Makefile.mk
+++ /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.
-#
-/*MGEN:commentPrefix=#*/
-/*MGEN:mgenDir=$(mgen_dir)*/
-/*MGEN:specDir=$(top_srcdir)/../specs*/
-/*MGEN:Root.Disclaimer*/
-
-mgen_generator=/*MGEN:Makefile.GenSources*/
-
-mgen_broker_cpp=/*MGEN:Makefile.GenCppFiles*/
-
-# Header file install rules.
-qpid_managementdir = $(includedir)/qpid/management
-dist_qpid_management_HEADERS = /*MGEN:Makefile.GenHFiles*/
-
-if GENERATE
-$(srcdir)/managementgen.mk: $(mgen_generator)
- $(mgen_cmd)
-
-$(mgen_generator):
-endif
diff --git a/cpp/managementgen/templates/Package.cpp b/cpp/managementgen/templates/Package.cpp
deleted file mode 100644
index 15e7fc15ec..0000000000
--- a/cpp/managementgen/templates/Package.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/*MGEN:commentPrefix=//*/
-//
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-//
-
-/*MGEN:Root.Disclaimer*/
-
-#include "Package/*MGEN:Schema.PackageNameCap*/.h"
-/*MGEN:Schema.ClassIncludes*/
-
-using namespace qpid::management;
-
-Package/*MGEN:Schema.PackageNameCap*/::Package/*MGEN:Schema.PackageNameCap*/ (ManagementAgent* agent)
-{
-/*MGEN:Schema.ClassRegisters*/
-}
-
diff --git a/cpp/managementgen/templates/Package.h b/cpp/managementgen/templates/Package.h
deleted file mode 100644
index 3f3ac35ffc..0000000000
--- a/cpp/managementgen/templates/Package.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*MGEN:commentPrefix=//*/
-#ifndef _MANAGEMENT_PACKAGE_/*MGEN:Schema.PackageNameUpper*/_
-#define _MANAGEMENT_PACKAGE_/*MGEN:Schema.PackageNameUpper*/_
-
-//
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-//
-
-/*MGEN:Root.Disclaimer*/
-
-#include "qpid/agent/ManagementAgent.h"
-
-namespace qpid {
-namespace management {
-
-class Package/*MGEN:Schema.PackageNameCap*/
-{
- public:
- Package/*MGEN:Schema.PackageNameCap*/ (ManagementAgent* agent);
- ~Package/*MGEN:Schema.PackageNameCap*/ () {}
-};
-
-}}
-
-
-#endif /*!_MANAGEMENT_PACKAGE_/*MGEN:Schema.PackageNameUpper*/_*/
diff --git a/cpp/packaging/NSIS/qpid-icon.ico b/cpp/packaging/NSIS/qpid-icon.ico
new file mode 100644
index 0000000000..112f5d8f1f
--- /dev/null
+++ b/cpp/packaging/NSIS/qpid-icon.ico
Binary files differ
diff --git a/cpp/packaging/NSIS/qpid-icon.png b/cpp/packaging/NSIS/qpid-icon.png
new file mode 100644
index 0000000000..d9bcc5657f
--- /dev/null
+++ b/cpp/packaging/NSIS/qpid-icon.png
Binary files differ
diff --git a/cpp/packaging/NSIS/qpid-install-banner.bmp b/cpp/packaging/NSIS/qpid-install-banner.bmp
new file mode 100644
index 0000000000..1dac04c685
--- /dev/null
+++ b/cpp/packaging/NSIS/qpid-install-banner.bmp
Binary files differ
diff --git a/cpp/packaging/NSIS/qpid-install-banner.png b/cpp/packaging/NSIS/qpid-install-banner.png
new file mode 100644
index 0000000000..be70d02ee6
--- /dev/null
+++ b/cpp/packaging/NSIS/qpid-install-banner.png
Binary files differ
diff --git a/cpp/qpidc.spec.in b/cpp/qpidc.spec.in
deleted file mode 100644
index 72570c5671..0000000000
--- a/cpp/qpidc.spec.in
+++ /dev/null
@@ -1,302 +0,0 @@
-
-#
-# Spec file for Qpid C++ packages: qpidc qpidc-devel, qpidd, qpidd-devel
-# svn revision: $Rev$
-#
-%define qpidd qpidd
-
-Name: @PACKAGE@
-Version: @VERSION@
-Release: 34%{?dist}
-Summary: Libraries for Qpid C++ client applications
-Group: System Environment/Libraries
-License: Apache Software License
-URL: @URL@
-Source0: @DOWNLOAD_URL@/%{name}-%{version}.tar.gz
-BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-
-ExclusiveArch: i386 x86_64
-
-BuildRequires: boost-devel
-BuildRequires: doxygen
-BuildRequires: e2fsprogs-devel
-BuildRequires: graphviz
-BuildRequires: help2man
-BuildRequires: libtool
-BuildRequires: pkgconfig
-BuildRequires: ruby
-
-Requires: boost
-
-Requires(post):/sbin/chkconfig
-Requires(preun):/sbin/chkconfig
-Requires(preun):/sbin/service
-Requires(postun):/sbin/service
-
-%description
-Run-time libraries for AMQP client applications developed using Qpid
-C++. Clients exchange messages with an AMQP message broker using
-the AMQP protocol.
-
-%package devel
-Summary: Header files and documentation for developing Qpid C++ clients
-Group: Development/System
-Requires: %name = %version-%release
-Requires: boost-devel
-Requires: e2fsprogs-devel
-Requires: python
-
-%description devel
-Libraries, header files and documentation for developing AMQP clients
-in C++ using Qpid. Qpid implements the AMQP messaging specification.
-
-%package -n %{qpidd}
-Summary: An AMQP message broker daemon
-Group: System Environment/Daemons
-Requires: %name = %version-%release
-Requires: openais
-Requires: xqilla
-Requires: xerces-c
-Requires: cyrus-sasl
-BuildRequires: cyrus-sasl-devel
-BuildRequires: xqilla-devel
-BuildRequires: xerces-c-devel
-BuildRequires: openais-devel
-
-%description -n %{qpidd}
-A message broker daemon that receives stores and routes messages using
-the open AMQP messaging protocol.
-
-%package -n %{qpidd}-devel
-Summary: Libraries and header files for developing Qpid broker extensions
-Group: Development/System
-Requires: %name-devel = %version-%release
-Requires: %{qpidd} = %version-%release
-Requires: openais-devel
-Requires: boost-devel
-Requires: xqilla-devel
-
-%description -n %{qpidd}-devel
-Libraries and header files for developing extensions to the
-Qpid broker daemon.
-
-%pre
-getent group qpidd >/dev/null || groupadd -r qpidd
-getent passwd qpidd >/dev/null || \
- useradd -r -m -g qpidd -d %{_libdir}/qpidd -s /sbin/nologin \
- -c "Owner of Qpidd Daemons" qpidd
-exit 0
-
-%prep
-%setup -q
-
-%build
-CXXFLAGS="%{optflags} -DNDEBUG -O3" \
-%configure --disable-static --without-cpg
-make %{?_smp_mflags}
-# Remove this generated perl file, we don't need it and it upsets rpmlint.
-rm docs/api/html/installdox
-
-%install
-rm -rf %{buildroot}
-make install DESTDIR=%{buildroot}
-install -Dp -m0755 etc/qpidd %{buildroot}%{_initrddir}/qpidd
-install -d -m0755 %{buildroot}%{_libdir}/qpidd
-install -Dp -m600 etc/qpidd.sasldb %{buildroot}/var/lib/qpidd/qpidd.sasldb
-install -d -m0755 %{buildroot}/var/run/qpidd
-rm -f %{buildroot}%_libdir/*.a
-rm -f %{buildroot}%_libdir/*.la
-
-%clean
-rm -rf %{buildroot}
-
-%check
-make check
-
-%files
-%defattr(-,root,root,-)
-%doc LICENSE NOTICE README
-%_libdir/libqpidcommon.so.0
-%_libdir/libqpidcommon.so.0.1.0
-%_libdir/libqpidclient.so.0
-%_libdir/libqpidclient.so.0.1.0
-
-%files devel
-%defattr(-,root,root,-)
-%_includedir/qpid/*.h
-%_includedir/qpid/amqp_0_10
-%_includedir/qpid/client
-%_includedir/qpid/framing
-%_includedir/qpid/sys
-%_includedir/qpid/log
-%_includedir/qpid/management
-%_includedir/qpid/agent
-%_libdir/libqpidcommon.so
-%_libdir/libqpidclient.so
-%_bindir/managementgen
-%_datadir/managementgen
-%doc %_datadir/%{name}/examples
-%doc docs/api/html
-
-%files -n %{qpidd}
-%defattr(-,root,root,-)
-%_libdir/libqpidbroker.so.0
-%_libdir/libqpidbroker.so.0.1.0
-%_libdir/libqpidcluster.so.0
-%_libdir/libqpidcluster.so.0.1.0
-%_libdir/libqpidacl.so.0
-%_libdir/libqpidacl.so.0.1.0
-%_sbindir/%{qpidd}
-%config(noreplace) %_sysconfdir/qpidd.conf
-%config(noreplace) %_sysconfdir/sasl2/qpidd.conf
-%{_initrddir}/%{qpidd}
-%attr(755, qpidd, qpidd) %_libdir/qpidd
-%attr(755, qpidd, qpidd) /var/run/qpidd
-%attr(600, qpidd, qpidd) %config(noreplace) /var/lib/qpidd/qpidd.sasldb
-%doc %_mandir/man1/%{qpidd}.*
-
-%files -n %{qpidd}-devel
-%defattr(-,root,root,-)
-%doc rpm/README.qpidd-devel
-%defattr(-,root,root,-)
-%_libdir/libqpidbroker.so
-%_libdir/libqpidcluster.so
-%_libdir/libqpidacl.so
-%_includedir/qpid/broker
-
-%post -p /sbin/ldconfig
-
-%postun -p /sbin/ldconfig
-
-%post -n %{qpidd}
-# This adds the proper /etc/rc*.d links for the script
-/sbin/chkconfig --add qpidd
-/sbin/ldconfig
-
-%preun -n %{qpidd}
-# Check that this is actual deinstallation, not just removing for upgrade.
-if [ $1 = 0 ]; then
- /sbin/service qpidd stop >/dev/null 2>&1 || :
- /sbin/chkconfig --del qpidd
-fi
-
-%postun -n %{qpidd}
-if [ "$1" -ge "1" ]; then
- /sbin/service qpidd condrestart >/dev/null 2>&1 || :
-fi
-/sbin/ldconfig
-
-%changelog
-* Fri May 30 2008 Gordon Sim <gsim@redhat.com> - 0.2-34
-- Removed cppunit as a dependency, all tests now use boost framework
-
-* Fri May 9 2008 Matthew Farrellee <mfarrellee@redhat> - 0.2-33
-- Moved qpidd.conf from qpidc package to qpidd package
-- Added BuildRequires xqilla-devel and xerces-c-devel to qpidd for XML Exchange
-- Added BuildRequires openais-devel to qpidd for CPG
-- Added missing Requires xqilla-devel to qpidd-devel
-
-* Thu May 8 2008 Matthew Farrellee <mfarrellee@redhat> - 0.2-32
-- Added sasl2 config file for qpidd
-- Added cyrus-sasl dependencies
-
-* Wed May 7 2008 Matthew Farrellee <mfarrellee@redhat> - 0.2-31
-- Added python dependency, needed by managementgen
-
-* Wed May 7 2008 Matthew Farrellee <mfarrellee@redhat> - 0.2-30
-- Added management-types.xml to qpidc-devel package
-
-* Tue May 6 2008 Matthew Farrellee <mfarrellee@redhat> - 0.2-29
-- Added managementgen to the qpidc-devel package
-
-* Mon Apr 14 2008 Nuno Santos <nsantos@redhat.com> - 0.2-28
- - Fix home dir permissions
- - Bumped for Fedora 9
-
-* Mon Mar 31 2008 Nuno Santos <nsantos@redhat.com> - 0.2-25
-- Create user qpidd, start qpidd service as qpidd
-
-* Mon Feb 18 2008 Rafael Schloming <rafaels@redhat.com> - 0.2-24
-- Bug fix for TCK issue in Beta 3
-
-* Thu Feb 14 2008 Rafael Schloming <rafaels@redhat.com> - 0.2-23
-- Bumped to pull in fixes for Beta 3
-
-* Tue Feb 12 2008 Alan Conway <aconway@redhat.com> - 0.2-22
-- Added -g to compile flags for debug symbols.
-
-* Tue Feb 12 2008 Alan Conway <aconway@redhat.com> - 0.2-21
-- Create /var/lib/qpidd correctly.
-
-* Mon Feb 11 2008 Rafael Schloming <rafaels@redhat.com> - 0.2-20
-- bumped for Beta 3
-
-* Mon Jan 21 2008 Gordon Sim <gsim@redhat.com> - 0.2-18
-- bump up rev for recent changes to plugin modules & mgmt
-
-* Thu Jan 03 2008 Nuno Santos <nsantos@redhat.com> - 0.2-17
-- add missing header file SessionManager.h
-
-* Thu Jan 03 2008 Nuno Santos <nsantos@redhat.com> - 0.2-16
-- limit builds to i386 and x86_64 archs
-
-* Thu Jan 03 2008 Nuno Santos <nsantos@redhat.com> - 0.2-15
-- add ruby as a build dependency
-
-* Tue Dec 18 2007 Nuno Santos <nsantos@redhat.com> - 0.2-14
-- include fixes from Gordon Sim (fragmentation, lazy-loading, staging)
- and Alan Conway (exception handling in the client).
-
-* Thu Dec 6 2007 Alan Conway <aconway@redhat.com> - 0.2-13
-- installcheck target to build examples in installation.
-
-* Thu Nov 8 2007 Alan Conway <aconway@redhat.com> - 0.2-10
-- added examples to RPM package.
-
-* Thu Oct 9 2007 Alan Conway <aconway@redhat.com> - 0.2-9
-- added config(noreplace) for qpidd.conf
-
-* Thu Oct 4 2007 Alan Conway <aconway@redhat.com> - 0.2-8
-- Added qpidd.conf configuration file.
-- Updated man page to detail configuration options.
-
-* Thu Sep 20 2007 Alan Conway <aconway@redhat.com> - 0.2-7
-- Removed apr dependency.
-
-* Wed Aug 1 2007 Alan Conway <aconway@redhat.com> - 0.2-6
-- added --disable-cluster flag
-
-* Tue Apr 17 2007 Alan Conway <aconway@redhat.com> - 0.2-5
-- Add missing Requires: e2fsprogs-devel for qpidc-devel.
-
-* Tue Apr 17 2007 Alan Conway <aconway@redhat.com> - 0.2-4
-- longer broker_start timeout to avoid failures in plague builds.
-
-* Tue Apr 17 2007 Alan Conway <aconway@redhat.com> - 0.2-3
-- Add missing Requires: apr in qpidc.
-
-* Mon Apr 16 2007 Alan Conway <aconway@redhat.com> - 0.2-2
-- Bugfix for memory errors on x86_64.
-
-* Thu Apr 12 2007 Alan Conway <aconway@redhat.com> - 0.2-1
-- Bumped version number for rhm dependencies.
-
-* Wed Apr 11 2007 Alan Conway <aconway@redhat.com> - 0.1-5
-- Add qpidd-devel sub-package.
-
-* Mon Feb 19 2007 Jim Meyering <meyering@redhat.com> - 0.1-4
-- Address http://bugzilla.redhat.com/220630:
-- Remove redundant "cppunit" build-requires.
-- Add --disable-static.
-
-* Thu Jan 25 2007 Alan Conway <aconway@redhat.com> - 0.1-3
-- Applied Jim Meyerings fixes from http://mail-archives.apache.org/mod_mbox/incubator-qpid-dev/200701.mbox/<87hcugzmyp.fsf@rho.meyering.net>
-
-* Mon Dec 22 2006 Alan Conway <aconway@redhat.com> - 0.1-1
-- Fixed all rpmlint complaints (with help from David Lutterkort)
-- Added qpidd --daemon behaviour, fix init.rc scripts
-
-* Fri Dec 8 2006 David Lutterkort <dlutter@redhat.com> - 0.1-1
-- Initial version based on Jim Meyering's sketch and discussions with Alan
- Conway
-
diff --git a/cpp/rpm/README.qpidd-devel b/cpp/rpm/README.qpidd-devel
deleted file mode 100644
index f64a9de3b3..0000000000
--- a/cpp/rpm/README.qpidd-devel
+++ /dev/null
@@ -1,7 +0,0 @@
-
-This package provides header files needed to implement extensions to
-the Qpid broker daemon. This feature is experimental and undocumented,
-it is not require for normal use of qpid.
-
-See http://cwiki.apache.org/qpid/ for more information about the qpid project.
-
diff --git a/cpp/rubygen/0-10/allsegmenttypes.rb b/cpp/rubygen/0-10/allsegmenttypes.rb
index c4c4095e02..26363d6a1f 100755
--- a/cpp/rubygen/0-10/allsegmenttypes.rb
+++ b/cpp/rubygen/0-10/allsegmenttypes.rb
@@ -1,4 +1,22 @@
#!/usr/bin/env ruby
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
$: << ".." # Include .. in load path
require 'cppgen'
diff --git a/cpp/rubygen/0-10/exceptions.rb b/cpp/rubygen/0-10/exceptions.rb
index 2f62b2ccdf..02e3a5d547 100755
--- a/cpp/rubygen/0-10/exceptions.rb
+++ b/cpp/rubygen/0-10/exceptions.rb
@@ -1,4 +1,22 @@
#!/usr/bin/env ruby
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
$: << ".." # Include .. in load path
require 'cppgen'
diff --git a/cpp/rubygen/0-10/handlers.rb b/cpp/rubygen/0-10/handlers.rb
index c23eb5faf4..981ea890e6 100755
--- a/cpp/rubygen/0-10/handlers.rb
+++ b/cpp/rubygen/0-10/handlers.rb
@@ -1,4 +1,22 @@
#!/usr/bin/env ruby
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
$: << ".." # Include .. in load path
require 'cppgen'
@@ -17,7 +35,7 @@ class GenHandlers < CppGen
def generate()
h_file("#{@dir}/handlers.h") {
- include "specification"
+ include "#{@dir}/specification"
namespace("#{@ns}") {
action_handler "Command", @amqp.collect_all(AmqpCommand)
action_handler "Control", @amqp.collect_all(AmqpControl)
diff --git a/cpp/rubygen/0-10/specification.rb b/cpp/rubygen/0-10/specification.rb
index a98292ee4e..7366599eba 100755
--- a/cpp/rubygen/0-10/specification.rb
+++ b/cpp/rubygen/0-10/specification.rb
@@ -1,4 +1,22 @@
#!/usr/bin/env ruby
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
$: << ".." # Include .. in load path
require 'cppgen'
@@ -324,8 +342,8 @@ class Specification < CppGen
}
cpp_file("#{@dir}/#{name}") {
- include "#{name}"
- include "exceptions.h"
+ include "#{@dir}/#{name}"
+ include "#{@dir}/exceptions.h"
namespace(@ns) {
genl "using framing::in_place;"
genl
diff --git a/cpp/rubygen/0-10/typecode.rb b/cpp/rubygen/0-10/typecode.rb
index e36b92c07c..0ab9c4be5d 100755
--- a/cpp/rubygen/0-10/typecode.rb
+++ b/cpp/rubygen/0-10/typecode.rb
@@ -1,4 +1,22 @@
#!/usr/bin/env ruby
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
$: << ".." # Include .. in load path
require 'cppgen'
diff --git a/cpp/rubygen/MethodBodyDefaultVisitor.rb b/cpp/rubygen/MethodBodyDefaultVisitor.rb
index 1fff1d51db..4f9b369117 100755
--- a/cpp/rubygen/MethodBodyDefaultVisitor.rb
+++ b/cpp/rubygen/MethodBodyDefaultVisitor.rb
@@ -1,4 +1,23 @@
#!/usr/bin/env ruby
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
$: << ".." # Include .. in load path
require 'cppgen'
diff --git a/cpp/rubygen/amqpgen.rb b/cpp/rubygen/amqpgen.rb
index bfa15bb391..69e65a4056 100755
--- a/cpp/rubygen/amqpgen.rb
+++ b/cpp/rubygen/amqpgen.rb
@@ -1,7 +1,22 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
#
# Generic AMQP code generation library.
#
-
# TODO aconway 2008-02-21:
#
# The amqp_attr_reader and amqp_child_reader for each Amqp* class
@@ -15,6 +30,7 @@
require 'delegate'
require 'rexml/document'
require 'pathname'
+require 'set'
include REXML
# Handy String functions for converting names.
@@ -150,7 +166,7 @@ class AmqpElement
# The root <amqp> element.
def root() @root ||=parent ? parent.root : self; end
- def to_s() "#<#{self.class}(#{fqname})>"; end
+ def to_s() "#<#{self.class}(#{fqname})>"; end
def inspect() to_s; end
# Text of doc child if there is one.
@@ -166,6 +182,21 @@ class AmqpElement
return self if is_a? AmqpClass
return parent && parent.containing_class
end
+
+ # 0-10 array domains are missing element type information, add it here.
+ ArrayTypes={
+ "str16-array" => "str-16",
+ "amqp-host-array" => "connection.amqp-host-url",
+ "command-fragments" => "session.command-fragment",
+ "in-doubt" => "dtx.xid",
+ "tx-publish" => "str-8",
+ "queues" => "str-8"
+ }
+
+ def array_type(name)
+ return ArrayTypes[name] if ArrayTypes[name]
+ raise "Missing ArrayType entry for " + name
+ end
end
@@ -189,14 +220,6 @@ class AmqpEnum < AmqpElement
amqp_child_reader :choice
end
-# 0-10 array domains are missing element type information, add it here.
-ArrayTypes={
- "str16-array" => "str-16",
- "amqp-host-array" => "connection.amqp-host-url",
- "command-fragments" => "session.command-fragment",
- "in-doubt" => "dtx.xid"
-}
-
class AmqpDomain < AmqpElement
def initialize(xml, parent)
super
@@ -295,7 +318,7 @@ class AmqpFakeMethod < AmqpMethod
def content() return "1" if @action.is_a? AmqpCommand and @action.segments end
def index() @action.code end
def code() @action.code end
- def synchronous() end # FIXME aconway 2008-04-10: ???
+ def synchronous() end
def on_chassis?(chassis)
@action.received_by?(chassis)
end
@@ -318,7 +341,14 @@ class AmqpAction < AmqpElement
def initialize(xml,amqp) super; end
amqp_child_reader :implement, :field, :response
amqp_attr_reader :code
- def implement?(role) xml.elements["./implement[@role='#{role}']"] end
+ def implement?(role)
+ # we can't use xpath for this because it triggers a bug in some
+ # versions of ruby, including version 1.8.6.110
+ xml.elements.each {|el|
+ return true if el.name == "implement" and el.attributes["role"] == role
+ }
+ return false
+ end
def received_by?(client_or_server)
return (implement?(client_or_server) or implement?("sender") or implement?("receiver"))
end
@@ -434,9 +464,12 @@ end
# Collect information about generated files.
class GenFiles
- @@files =[]
- def GenFiles.add(f) @@files << f; end
+ @@files = Set.new
+ @@public_api = []
+ def GenFiles.add(f) @@files.add(f); end
def GenFiles.get() @@files; end
+ def GenFiles.public_api(file) @@public_api << file; end
+ def GenFiles.public_api?(file) @@public_api.find { |f| f == file }; end
end
# Base class for code generators.
@@ -446,27 +479,27 @@ class Generator
# Takes directory for output or "-", meaning print file names that
# would be generated.
def initialize (outdir, amqp)
+ @outdir=outdir[0]
+ @apidir=outdir[1]
@amqp=amqp
- @outdir=outdir
+ raise "outdir is not an array" unless outdir.class == Array
@prefix=[''] # For indentation or comments.
@indentstr=' ' # One indent level.
@outdent=2
- Pathname.new(@outdir).mkpath unless @outdir=="-"
end
+ # Declare next file to be public API
+ def public_api(file) GenFiles.public_api(file); end
+
# Create a new file, set @out.
def file(file, &block)
- GenFiles.add file
- if (@outdir != "-")
- @path=Pathname.new "#{@outdir}/#{file}"
+ GenFiles.add(file)
+ dir = GenFiles.public_api?(file) ? @apidir : @outdir
+ if (dir != "-")
+ @path=Pathname.new "#{dir}/#{file}"
@path.parent.mkpath
@out=String.new # Generate in memory first
- if block then yield; endfile; end
- end
- end
-
- def endfile()
- if @outdir != "-"
+ yield if block
if @path.exist? and @path.read == @out
puts "Skipped #{@path} - unchanged" # Dont generate if unchanged
else
diff --git a/cpp/rubygen/cppgen.rb b/cpp/rubygen/cppgen.rb
index 3a4228567a..7818e1c4b0 100755
--- a/cpp/rubygen/cppgen.rb
+++ b/cpp/rubygen/cppgen.rb
@@ -118,6 +118,7 @@ class AmqpRoot
# preview; map 0-10 types to preview code generator types
@@typemap = {
"bit"=> CppType.new("bool").code("Octet").defval("false"),
+ "boolean"=> CppType.new("bool").code("Octet").defval("false"),
"uint8"=>CppType.new("uint8_t").code("Octet").defval("0"),
"uint16"=>CppType.new("uint16_t").code("Short").defval("0"),
"uint32"=>CppType.new("uint32_t").code("Long").defval("0"),
@@ -146,7 +147,7 @@ end
class AmqpElement
# convert my amqp type_ attribute to a C++ type.
def amqp2cpp()
- return "ArrayDomain<#{ArrayTypes[name].amqp2cpp}> " if type_=="array"
+ return "ArrayDomain<#{array_type(name).amqp2cpp}> " if type_=="array"
return type_.amqp2cpp
end
@@ -189,7 +190,7 @@ class AmqpField
c=containing_class
c.struct(type_)
end
- def cpptype() lookup_cpptype(type_) or raise "no cpptype #{self}" end
+ def cpptype() lookup_cpptype(type_) or raise "no cpptype #{type_} for field #{self}" end
def cppname() name.lcaps.cppsafe; end
def bit?() type_ == "bit"; end
def signature() cpptype.param+" "+cppname; end
diff --git a/cpp/rubygen/framing.0-10/MethodBodyConstVisitor.rb b/cpp/rubygen/framing.0-10/MethodBodyConstVisitor.rb
index f9ef95f5a0..d784e589df 100755
--- a/cpp/rubygen/framing.0-10/MethodBodyConstVisitor.rb
+++ b/cpp/rubygen/framing.0-10/MethodBodyConstVisitor.rb
@@ -1,4 +1,22 @@
#!/usr/bin/env ruby
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
$: << ".." # Include .. in load path
require 'cppgen'
diff --git a/cpp/rubygen/framing.0-10/MethodBodyDefaultVisitor.rb b/cpp/rubygen/framing.0-10/MethodBodyDefaultVisitor.rb
index a74b0c06d6..00962de4f9 100755
--- a/cpp/rubygen/framing.0-10/MethodBodyDefaultVisitor.rb
+++ b/cpp/rubygen/framing.0-10/MethodBodyDefaultVisitor.rb
@@ -1,4 +1,22 @@
#!/usr/bin/env ruby
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
$: << ".." # Include .. in load path
require 'cppgen'
@@ -12,18 +30,19 @@ class MethodBodyDefaultVisitorGen < CppGen
def generate()
h_file(@filename) {
include "qpid/framing/MethodBodyConstVisitor"
+ include "qpid/CommonImportExport.h"
namespace(@namespace) {
genl "class AMQMethodBody;"
cpp_class(@classname, "public MethodBodyConstVisitor") {
genl "public:"
genl "virtual void defaultVisit(const AMQMethodBody&) = 0;"
@amqp.methods_.each { |m|
- genl "virtual void visit(const #{m.body_name}&);" }
+ genl "QPID_COMMON_EXTERN virtual void visit(const #{m.body_name}&);" }
}}}
cpp_file(@filename) {
include(@filename)
- include("all_method_bodies.h")
+ include("qpid/framing/all_method_bodies.h")
namespace(@namespace) {
@amqp.methods_.each { |m|
genl "void #{@classname}::visit(const #{m.body_name}& b) { defaultVisit(b); }"
diff --git a/cpp/rubygen/framing.0-10/MethodBodyFactory.rb b/cpp/rubygen/framing.0-10/MethodBodyFactory.rb
new file mode 100644
index 0000000000..95c79fd1a4
--- /dev/null
+++ b/cpp/rubygen/framing.0-10/MethodBodyFactory.rb
@@ -0,0 +1,58 @@
+#!/usr/bin/env ruby
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+$: << ".." # Include .. in load path
+require 'cppgen'
+
+class MethodBodyFactoryGen < CppGen
+
+ def initialize(outdir, amqp)
+ super(outdir, amqp)
+ @namespace="qpid::framing"
+ @classname="MethodBodyFactory"
+ @filename="qpid/framing/MethodBodyFactory"
+ end
+
+ def generate()
+ cpp_file(@filename) {
+ include @filename
+ include "qpid/framing/BodyFactory"
+ @amqp.methods_.each { |m| include "qpid/framing/#{m.body_name}" }
+ include "qpid/Exception.h"
+ genl
+ namespace(@namespace) {
+ scope("boost::intrusive_ptr<AMQMethodBody> #{@classname}::create(ClassId c, MethodId m) {") {
+ scope("switch (c) {") {
+ @amqp.classes.each { |c|
+ scope("case #{c.code}: switch(m) {") {
+ c.methods_.each { |m|
+ genl "case #{m.code}: return BodyFactory::create<#{m.body_name}>();"
+ }
+ genl "default: throw Exception(QPID_MSG(\"Invalid method id \" << int(m) << \" for class #{c.name} \"));"
+ }
+ genl "break;"
+ }
+ genl "default: throw Exception(QPID_MSG(\"Invalid class id \" << int(c)));"
+ }
+ }
+ }}
+ end
+end
+
+MethodBodyFactoryGen.new($outdir, $amqp).generate();
diff --git a/cpp/rubygen/framing.0-10/MethodHolder.rb b/cpp/rubygen/framing.0-10/MethodHolder.rb
index 90a9333916..e69de29bb2 100755
--- a/cpp/rubygen/framing.0-10/MethodHolder.rb
+++ b/cpp/rubygen/framing.0-10/MethodHolder.rb
@@ -1,100 +0,0 @@
-#!/usr/bin/env ruby
-$: << ".." # Include .. in load path
-require 'cppgen'
-
-class MethodHolderGen < CppGen
-
- def initialize(outdir, amqp)
- super(outdir, amqp)
- @namespace="qpid::framing"
- @classname="BodyHolder"
- @filename="qpid/framing/BodyHolder"
- end
-
- def gen_max_size()
- # Generate program to generate MaxSize.h
- cpp_file("generate_MaxMethodBodySize_h") {
- include "qpid/framing/AMQHeaderBody"
- include "qpid/framing/AMQContentBody"
- include "qpid/framing/AMQHeartbeatBody"
- @amqp.methods_.each { |m| include "qpid/framing/#{m.body_name}" }
- genl
- include "<algorithm>"
- include "<fstream>"
- genl
- genl "using namespace std;"
- genl "using namespace qpid::framing;"
- genl
- scope("int main(int, char** argv) {") {
- genl "size_t maxSize=0;"
- genl "maxSize=max(maxSize, sizeof(AMQHeaderBody));"
- genl "maxSize=max(maxSize, sizeof(AMQContentBody));"
- genl "maxSize=max(maxSize, sizeof(AMQHeartbeatBody));"
- @amqp.methods_.each { |m|
- genl "maxSize=max(maxSize, sizeof(#{m.body_name}));" }
- gen <<EOS
-ofstream out("qpid/framing/MaxMethodBodySize.h");
-out << "// GENERATED CODE: generated by " << argv[0] << endl;
-out << "namespace qpid{ namespace framing { " << endl;
-out << "const size_t MAX_METHOD_BODY_SIZE=" << maxSize << ";" << endl;
-out << "}}" << endl;
-EOS
- }
- }
- end
-
- def gen_construct
- cpp_file(@filename+"_gen") {
- include @filename
- include "qpid/framing/AMQHeaderBody"
- include "qpid/framing/AMQContentBody"
- include "qpid/framing/AMQHeartbeatBody"
- @amqp.methods_.each { |m| include "qpid/framing/#{m.body_name}" }
- include "qpid/framing/FrameDefaultVisitor.h"
- include "qpid/Exception.h"
- genl
- namespace(@namespace) {
- scope("void #{@classname}::setMethod(ClassId c, MethodId m) {") {
- scope("switch (c) {") {
- @amqp.classes.each { |c|
- scope("case #{c.code}: switch(m) {") {
- c.methods_.each { |m|
- genl "case #{m.code}: blob = in_place<#{m.body_name}>(); break;"
- }
- genl "default: throw Exception(QPID_MSG(\"Invalid method id \" << int(m) << \" for class #{c.name} \"));"
- }
- genl "break;"
- }
- genl "default: throw Exception(QPID_MSG(\"Invalid class id \" << int(c)));"
- }
- }
-
- struct("CopyVisitor", "public FrameDefaultVisitor") {
- genl "using FrameDefaultVisitor::visit;"
- genl "using FrameDefaultVisitor::defaultVisit;"
- genl "BodyHolder& holder;"
- genl "CopyVisitor(BodyHolder& h) : holder(h) {}"
- ["Header", "Content", "Heartbeat"].each { |type|
- genl "void visit(const AMQ#{type}Body& x) { holder=x; }"
- }
- @amqp.methods_.each { |m|
- genl "void visit(const #{m.body_name}& x) { holder=x; }"
- }
- genl "void defaultVisit(const AMQBody&) { assert(0); }"
- }
- genl
-
- scope("void BodyHolder::setBody(const AMQBody& b) {") {
- genl "CopyVisitor cv(*this); b.accept(cv);"
- }
- }}
- end
-
- def generate
- gen_max_size
- gen_construct
- end
-end
-
-MethodHolderGen.new($outdir, $amqp).generate();
-
diff --git a/cpp/rubygen/framing.0-10/Operations.rb b/cpp/rubygen/framing.0-10/Operations.rb
index 4a67df8b92..cd6a363c56 100755
--- a/cpp/rubygen/framing.0-10/Operations.rb
+++ b/cpp/rubygen/framing.0-10/Operations.rb
@@ -1,4 +1,22 @@
#!/usr/bin/env ruby
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
# Usage: output_directory xml_spec_file [xml_spec_file...]
#
$: << '..'
@@ -97,7 +115,7 @@ EOS
end
end
-OperationsGen.new("client",ARGV[0], $amqp).generate()
-OperationsGen.new("server",ARGV[0], $amqp).generate()
-OperationsGen.new("all",ARGV[0], $amqp).generate()
+OperationsGen.new("client",$outdir, $amqp).generate()
+OperationsGen.new("server",$outdir, $amqp).generate()
+OperationsGen.new("all",$outdir, $amqp).generate()
diff --git a/cpp/rubygen/framing.0-10/OperationsInvoker.rb b/cpp/rubygen/framing.0-10/OperationsInvoker.rb
index 44006207ca..f9b6cac76b 100755
--- a/cpp/rubygen/framing.0-10/OperationsInvoker.rb
+++ b/cpp/rubygen/framing.0-10/OperationsInvoker.rb
@@ -1,4 +1,22 @@
#!/usr/bin/env ruby
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
# Usage: output_directory xml_spec_file [xml_spec_file...]
#
$: << '..'
@@ -56,7 +74,7 @@ class OperationsInvokerGen < CppGen
public
genl("Invoker(#{target}& target_) : target(target_) {}")
genl "using MethodBodyDefaultVisitor::visit;"
- methods.each { |m| genl "void visit(const #{m.body_name}& body);" }
+ methods.each { |m| genl "QPID_COMMON_EXTERN void visit(const #{m.body_name}& body);" }
}
end
@@ -64,6 +82,7 @@ class OperationsInvokerGen < CppGen
h_file(@filename) {
include "qpid/framing/#{@ops}"
include "qpid/framing/Invoker.h"
+ include "qpid/CommonImportExport.h"
namespace("qpid::framing") {
# AMQP_*Operations invoker.
methods=@amqp.classes.map { |c| visit_methods(c).to_a }.flatten
@@ -93,6 +112,6 @@ class OperationsInvokerGen < CppGen
end
end
-OperationsInvokerGen.new("client",ARGV[0], $amqp).generate()
-OperationsInvokerGen.new("server",ARGV[0], $amqp).generate()
-OperationsInvokerGen.new("all",ARGV[0], $amqp).generate()
+OperationsInvokerGen.new("client",$outdir, $amqp).generate()
+OperationsInvokerGen.new("server",$outdir, $amqp).generate()
+OperationsInvokerGen.new("all",$outdir, $amqp).generate()
diff --git a/cpp/rubygen/framing.0-10/Proxy.rb b/cpp/rubygen/framing.0-10/Proxy.rb
index 71a6b954c6..6e3cb4fd4d 100755
--- a/cpp/rubygen/framing.0-10/Proxy.rb
+++ b/cpp/rubygen/framing.0-10/Proxy.rb
@@ -1,4 +1,22 @@
#!/usr/bin/env ruby
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
$: << ".." # Include .. in load path
require 'cppgen'
@@ -19,14 +37,14 @@ class ProxyGen < CppGen
def inner_class_decl(c)
cname=c.name.caps
- cpp_class(cname, "Proxy") {
+ cpp_class(cname, "public Proxy") {
gen <<EOS
public:
#{cname}(FrameHandler& f) : Proxy(f) {}
static #{cname}& get(#{@classname}& proxy) { return proxy.get#{cname}(); }
EOS
methods_on(c, @chassis).each { |m|
- genl "virtual void #{m.cppname}(#{m.signature.join(",\n ")});"
+ genl "QPID_COMMON_EXTERN virtual void #{m.cppname}(#{m.signature.join(",\n ")});"
genl
}}
end
@@ -48,10 +66,12 @@ EOS
include "qpid/framing/Array.h"
include "qpid/framing/amqp_types.h"
include "qpid/framing/amqp_structs.h"
+ include "qpid/CommonImportExport.h"
+
namespace("qpid::framing") {
cpp_class(@classname, "public Proxy") {
public
- genl "#{@classname}(FrameHandler& out);"
+ genl "QPID_COMMON_EXTERN #{@classname}(FrameHandler& out);"
genl
@amqp.classes.each { |c|
inner_class_decl(c)
@@ -66,7 +86,7 @@ EOS
# .cpp file
cpp_file(@filename) {
include "<sstream>"
- include "#{@classname}.h"
+ include "qpid/framing/#{@classname}.h"
include "qpid/framing/amqp_types_full.h"
methods_on(@amqp, @chassis).each {
|m| include "qpid/framing/"+m.body_name
@@ -74,7 +94,7 @@ EOS
genl
namespace("qpid::framing") {
genl "#{@classname}::#{@classname}(FrameHandler& f) :"
- gen " Proxy(f)"
+ gen " Proxy(f)"
@amqp.classes.each { |c| gen ",\n "+proxy_member(c)+"(f)" }
genl "{}\n"
@amqp.classes.each { |c| inner_class_defn(c) }
diff --git a/cpp/rubygen/framing.0-10/Session.rb b/cpp/rubygen/framing.0-10/Session.rb
index 9f54ad1675..61f0e03a8b 100644..100755
--- a/cpp/rubygen/framing.0-10/Session.rb
+++ b/cpp/rubygen/framing.0-10/Session.rb
@@ -1,17 +1,38 @@
#!/usr/bin/env ruby
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
# Usage: output_directory xml_spec_file [xml_spec_file...]
#
$: << '..'
require 'cppgen'
class CppGen
- def session_methods
+ def session_methods(sync_default)
excludes = ["connection", "session", "file", "stream"]
gen_methods=@amqp.methods_on(@chassis).reject { |m|
excludes.include? m.parent.name or m.body_name.include?("010")
}
+ gen_methods.each { |m| m.set_sync_default(sync_default) }
end
+
+ # Generates a doxygen comment for AmqpMethod m.
def doxygen(m)
doxygen_comment {
genl m.doc
@@ -34,9 +55,9 @@ module SyncAsync
def decl_ctor_opeq()
genl
- genl "#{@classname}();"
- genl "#{@classname}(const #{@version_base}& other);"
- genl "#{@classname}& operator=(const #{@version_base}& other);"
+ genl "QPID_CLIENT_EXTERN #{@classname}();"
+ genl "QPID_CLIENT_EXTERN #{@classname}(const #{@version_base}& other);"
+ genl "QPID_CLIENT_EXTERN #{@classname}& operator=(const #{@version_base}& other);"
end
def defn_ctor_opeq(inline="")
@@ -50,23 +71,35 @@ module SyncAsync
genl "return *this;"
}
end
+
+ def sync_default() !@async end
end
class ContentField # For extra content parameters
def cppname() "content" end
- def signature() "const MethodContent& content" end
- def sig_default() signature+"="+"DefaultContent(std::string())" end
- def unpack() "p[arg::content|DefaultContent(std::string())]"; end
+ def signature() "const Message& content" end
+ def sig_default() signature+"="+"Message(std::string())" end
+ def unpack() "p[arg::content|Message(std::string())]"; end
def doc() "Message content"; end
end
+class SyncField # For extra sync parameters
+ def initialize(default_value) @default_value=default_value ? "true" : "false" end
+ def cppname() "sync" end
+ def signature() "bool sync" end
+ def sig_default() signature+"="+@default_value end
+ def unpack() "p[arg::sync|#{@default_value}]"; end
+ def doc() "If true the broker will respond with completion status as soon as possible."; end
+end
+
class AmqpField
def unpack() "p[arg::#{cppname}|#{default_value}]"; end
def sig_default() signature+"="+default_value; end
end
class AmqpMethod
- def fields_c() content ? fields+[ContentField.new] : fields end
+ def set_sync_default(sync_default) @sync_default=sync_default end
+ def fields_c() result = fields + (content ? [ContentField.new] : []) + [SyncField.new(@sync_default)] end
def param_names_c() fields_c.map { |f| f.cppname} end
def signature_c() fields_c.map { |f| f.signature }; end
def sig_c_default() fields_c.map { |f| f.sig_default }; end
@@ -103,8 +136,10 @@ class SessionNoKeywordGen < CppGen
end
def generate()
+ public_api("#{@file}.h")
h_file(@file) {
include "qpid/client/#{@version_base}.h"
+ include "qpid/client/ClientImportExport.h"
namespace(@namespace) {
doxygen_comment {
genl "AMQP #{@amqp.version} #{sync_adjective} session API."
@@ -114,31 +149,36 @@ class SessionNoKeywordGen < CppGen
cpp_class(@classname, "public #{@version_base}") {
public
decl_ctor_opeq()
- session_methods.each { |m|
+ session_methods(sync_default).each { |m|
genl
doxygen(m)
args=m.sig_c_default.join(", ")
- genl "#{m.return_type(@async)} #{m.session_function}(#{args});"
+ genl "QPID_CLIENT_EXTERN #{m.return_type(@async)} #{m.session_function}(#{args});"
}
}
}}
cpp_file(@file) {
- include @classname
+ include "qpid/client/#{@classname}"
include "qpid/framing/all_method_bodies.h"
+ include "qpid/client/SessionImpl.h"
+ include "qpid/client/MessageImpl.h"
+ include "qpid/client/PrivateImplRef.h"
+ include "qpid/client/CompletionImpl.h"
+ include "<boost/intrusive_ptr.hpp>"
namespace(@namespace) {
genl "using namespace framing;"
- session_methods.each { |m|
+ session_methods(sync_default).each { |m|
genl
sig=m.signature_c.join(", ")
func="#{@classname}::#{m.session_function}"
scope("#{m.return_type(@async)} #{func}(#{sig}) {") {
args=(["ProtocolVersion(#{@amqp.major},#{@amqp.minor})"]+m.param_names).join(", ")
genl "#{m.body_name} body(#{args});";
- genl "body.setSync(#{@async ? 'false':'true'});"
+ genl "body.setSync(sync);"
sendargs="body"
- sendargs << ", content" if m.content
- async_retval="#{m.return_type(true)}(impl->send(#{sendargs}), impl)"
+ sendargs << ", *MessageImpl::get(content)" if m.content
+ async_retval="#{m.return_type(true)}(new CompletionImpl(impl->send(#{sendargs}), impl))"
if @async then
genl "return #{async_retval};"
else
@@ -180,9 +220,10 @@ class SessionGen < CppGen
end
def generate()
- keyword_methods=session_methods.reject { |m| m.fields_c.empty? }
+ keyword_methods=session_methods(sync_default).reject { |m| m.fields_c.empty? }
max_arity = keyword_methods.map{ |m| m.fields_c.size }.max
+ public_api("qpid/client/arg.h")
h_file("qpid/client/arg.h") {
# Generate keyword tag declarations.
genl "#define BOOST_PARAMETER_MAX_ARITY #{max_arity}"
@@ -192,10 +233,11 @@ class SessionGen < CppGen
genl "BOOST_PARAMETER_KEYWORD(keyword_tags, #{k})"
}}
}
-
+ public_api("#{@fqclass.file}.h")
h_file(@fqclass.file) {
include @fqbase.file
include "qpid/client/arg"
+ include "qpid/client/ClientImportExport"
namespace("qpid::client") {
# Doxygen comment.
doxygen_comment {
@@ -219,6 +261,136 @@ which provides the same set of functions using normal non-keyword
declarations.
\\ingroup clientapi
+
+
+\\details
+
+<h2>Publishing Messages</h2>
+<ul>
+<li><p>messageTransfer()</p>
+<pre>session.messageTransfer(arg::content=message, arg::destination="amq.topic");</pre></li>
+<li><p>messageTransfer() &mdash; asynchronous</p>
+<pre>#include &lt;qpid/client/AsyncSession.h>
+
+for (int i=0; i&lt;10; i++) {
+ message.setData(message_data.str());
+ async(session).messageTransfer(arg::content=message, arg::destination="amq.direct");
+}
+
+session.sync();
+</pre>
+</li>
+</ul>
+
+<h2>Exchanges</h2>
+<ul>
+<li><p>exchangeBind()</p>
+<pre>session.exchangeBind(arg::exchange="amq.topic", arg::queue=queue, arg::bindingKey=routing_key);</pre>
+</li>
+<li><p>exchangeUnbind()</p>
+<pre>session.exchangeUnBind(arg::exchange="amq.topic", arg::queue=queue, arg::bindingKey=routing_key);</pre></li>
+<li><p>exchangeBound()</p>
+<pre>if (session.exchangeBound(arg::exchange="amq.topic", arg::queue=queue, arg::bindingKey=rk)){...}</pre>
+<pre>if (session.exchangeBound(arg::exchange="amq.topic", arg::queue=queue)){...}</pre>
+</li>
+<li><p>exchangeDeclare()</p>
+<pre>session.exchangeDeclare(arg::exchange="my.topic", arg::type="topic");</pre>
+<pre>session.exchangeDeclare(arg::exchange="xml", arg::type="xml");</pre>
+</li>
+<li><p>exchangeDelete()</p>
+<pre>session.exchangeDeclare(arg::exchange="my.topic");</pre>
+<pre>session.exchangeDeclare(arg::exchange="xml", arg::ifUnused=true);</pre>
+</li>
+<li><p>exchangeQuery()</p>
+<pre>ExchangeQueryResult eqr = session.exchangeQuery(arg::exchange="my.topic");</pre></li>
+</ul>
+
+
+<h2>Configuring exchanges in session.exchangeDeclare</h2>
+
+<pre>arg::durable=true</pre>
+<p>Default: false.</p>
+<p>If durable=true, an exchange remains active even if the server is restarted. If durable=false, an exchange is purged when a server restarts.</p>
+
+<pre>arg::autoDelete=true</pre>
+<p>Default: false.</p>
+<p>If autoDelete=true, deleting the last binding for an exchange also deletes the exchange.</p>
+
+<pre>arg::alternatExchange="my.exchange"</pre>
+<p>Default: none.</p>
+<p>If an alternate exchange is specified, messages that can not be delivered to any queue are sent to the alternate exchange.</p>
+
+<h2>Queues</h2>
+<ul>
+<li><p>queueDeclare()</p>
+<pre>session.queueDeclare(arg::queue="message_queue");</pre>
+</li>
+<li><p>queueDelete()</p>
+<pre>session.queueDelete(arg::queue="message_queue");</pre></li>
+<li><p>queuePurge()</p>
+<pre>session.queuePurge(arg::queue="message_queue");</pre></li>
+<li><p>queueQuery()</p>
+<pre>QueueQueryResult qqr = session.queueQuery(arg::queue="message_queue");</pre></li>
+</ul>
+
+
+<h2>Configuring queues with session.queueDeclare</h2>
+<pre>arg::durable=true</pre>
+<p>Default: false.</p>
+<p>If durable=true, a queue remains active if the server is restarted. If durable=false, a queue and its contents are lost when a server restarts.</p>
+<br/>
+
+<pre>arg::autoDelete=true</pre>
+<p>Default: false.</p>
+<p>If autoDelete=true, the queue is deleted when the last active Subscription to the Queue is canceled.</p>
+<br/>
+
+<pre>arg::exclusive=true</pre>
+<p>Default: false.</p>
+<p>If exclusive=true, only the Session that created a queue can access it.</p>
+<br/>
+
+<pre>arg::alternateExchange="my.exchange"</pre>
+<p>Default: none. </p>
+<p>If an alternate exchange is specified, messages are routed to it if (1) they are rejected by a client, or (2) they remain on the queue when it is deleted.</p>
+<br/>
+
+
+<h2>Accepting, Acquiring, Rejecting, or Releasing Messages</h2>
+<ul>
+<li><p>messageAccept() &mdash; acknowledges messages</p>
+<pre>SequenceSet tobeAccepted;
+toAccepted.add(msg.getId());
+session.messageAccept(toBeAccepted);</pre>
+</li>
+<li><p>messageAcquire()</p>
+<pre>SequenceSet tobeAcquired;
+toBeAcquired.add(msg.getId());
+session.messageAcquire(toBeAcquired);</pre>
+</li>
+<li><p>messageReject()</p>
+<pre>SequenceSet tobeRejected;
+toRejected.add(msg.getId());
+session.messageReject(toBeRejected);</pre>
+</li>
+<li><p>messageRelease()</p>
+<pre>SequenceSet tobeReleased;
+toReleased.add(msg.getId());
+session.messageRelease(toBeReleased);</pre></li>
+</ul>
+
+<h2>Transactions</h2>
+<ul>
+<li><p>txSelect()</p>
+<pre>session.txSelect();</pre>
+</li>
+<li><p>txCommit()</p>
+<pre>session.txSelect();</pre></li>
+<li><p>txRollback()</p>
+<pre>session.txRollback();</pre></li>
+</ul>
+
+
EOS
}
# Session class.
@@ -238,8 +410,8 @@ EOS
end
end
-SessionNoKeywordGen.new(ARGV[0], $amqp, true).generate()
-SessionNoKeywordGen.new(ARGV[0], $amqp, false).generate()
-SessionGen.new(ARGV[0], $amqp, true).generate()
-SessionGen.new(ARGV[0], $amqp, false).generate()
+SessionNoKeywordGen.new($outdir, $amqp, true).generate()
+SessionNoKeywordGen.new($outdir, $amqp, false).generate()
+SessionGen.new($outdir, $amqp, true).generate()
+SessionGen.new($outdir, $amqp, false).generate()
diff --git a/cpp/rubygen/framing.0-10/all_method_bodies.rb b/cpp/rubygen/framing.0-10/all_method_bodies.rb
index 5971d49189..4c7fccfff5 100755
--- a/cpp/rubygen/framing.0-10/all_method_bodies.rb
+++ b/cpp/rubygen/framing.0-10/all_method_bodies.rb
@@ -1,4 +1,22 @@
#!/usr/bin/env ruby
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
$: << ".." # Include .. in load path
require 'cppgen'
diff --git a/cpp/rubygen/framing.0-10/constants.rb b/cpp/rubygen/framing.0-10/constants.rb
index 7f026a3e54..5c1c1047f7 100755
--- a/cpp/rubygen/framing.0-10/constants.rb
+++ b/cpp/rubygen/framing.0-10/constants.rb
@@ -1,4 +1,22 @@
#!/usr/bin/env ruby
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
$: << ".." # Include .. in load path
require 'cppgen'
@@ -11,8 +29,10 @@ class ConstantsGen < CppGen
end
def constants_h()
- h_file("#{@dir}/constants") {
- namespace(@namespace) {
+ public_api("#{@dir}/constants.h")
+ h_file("#{@dir}/constants.h") {
+ namespace(@namespace) {
+ # Constants for class/method names.
scope("enum AmqpConstant {","};") {
l=[]
l.concat @amqp.constants.map { |c| "#{c.name.shout}=#{c.value}" }
@@ -23,53 +43,137 @@ class ConstantsGen < CppGen
}
genl l.join(",\n")
}
- define_constants_for(@amqp.domain("segment-type").enum)
- namespace("execution") {
- define_constants_for(@amqp.class_("execution").domain("error-code").enum)
+ }
+ }
+ end
+
+ def typecode_enum(t) "TYPE_CODE_#{t.name.shout}" end
+
+ def typecode_h_cpp
+ path="#{@dir}/TypeCode"
+ public_api(path+".h")
+ h_file(path) {
+ include("<iosfwd>")
+ include("\"qpid/sys/IntegerTypes.h\"")
+ namespace(@namespace) {
+ scope("enum TypeCode {", "};") {
+ genl @amqp.types.map { |t| "#{typecode_enum t} = #{t.code}" if t.code }.compact.join(",\n")
}
- namespace("connection") {
- define_constants_for(@amqp.class_("connection").domain("close-code").enum)
+ genl <<EOS
+
+/** True if t is a valid TypeCode value */
+bool isTypeCode(uint8_t t);
+
+/** Throw exception if not a valid TypeCode */
+TypeCode typeCode(uint8_t);
+
+/**@return 0 if t is not a valid enum TypeCode value. */
+const char* typeName(TypeCode t);
+
+std::ostream& operator<<(std::ostream&, TypeCode);
+EOS
+ }
+ }
+
+ cpp_file(path) {
+ include(path);
+ include("qpid/Exception.h")
+ include("<ostream>")
+ namespace(@namespace) {
+ scope("const char* typeName(TypeCode t) {") {
+ scope("switch (t) {") {
+ @amqp.types.each { |t| genl "case #{typecode_enum t}: return \"#{t.name}\";" if t.code }
+ genl "default: break;"
+ }
+ genl "return 0;";
}
- namespace("session") {
- define_constants_for(@amqp.class_("session").domain("detach-code").enum)
+ genl <<EOS
+
+bool isTypeCode(uint8_t t) { return typeName(TypeCode(t)); }
+
+TypeCode typeCode(uint8_t t) {
+ if (!isTypeCode(t)) throw Exception(QPID_MSG("Invalid TypeCode " << t));
+ return TypeCode(t);
+}
+
+std::ostream& operator<<(std::ostream& o, TypeCode t) {
+ if (isTypeCode(t)) return o << typeName(t);
+ else return o << "Invalid TypeCode " << t;
+}
+EOS
+ }
+ }
+ end
+
+ def enum_h()
+ public_api("#{@dir}/enum.h")
+ h_file("#{@dir}/enum.h") {
+ # Constants for enum domains.
+ namespace(@namespace) {
+ @amqp.domains.each { |d| declare_enum(d.enum) if d.enum }
+ @amqp.classes.each { |c|
+ enums=c.collect_all(AmqpEnum)
+ if !enums.empty? then
+ namespace(c.nsname) { enums.each { |e| declare_enum(e) } }
+ end
}
- define_constants_for(@amqp.class_("dtx").domain("xa-status").enum)
}
}
end
- def define_constants_for(enum)
- scope("enum #{enum.parent.name.caps} {","};") {
- genl enum.choices.collect { |c| "#{c.name.shout}=#{c.value}" }.join(",\n")
+ def declare_enum(enum)
+ # Generated like this: enum containing_class::Foo { FOO_X, FOO_Y; }
+ name="#{enum.parent.name.caps}"
+ prefix=enum.parent.name.shout+"_"
+ scope("enum #{name} {","};") {
+ genl enum.choices.collect { |c| "#{prefix}#{c.name.shout}=#{c.value}" }.join(",\n")
}
end
- def define_exception(c, base, package)
- name=c.name.caps+"Exception"
- genl
- doxygen_comment { genl c.doc }
- struct(c.name.caps+"Exception", base) {
+ def declare_exception(c, base, package, enum)
+ name=c.name.caps+"Exception"
+ value="#{package}::#{enum.parent.name.shout}_#{c.name.shout}"
+ genl
+ doxygen_comment { genl c.doc }
+ struct(c.name.caps+"Exception", base) {
genl "std::string getPrefix() const { return \"#{c.name}\"; }"
- genl "#{c.name.caps}Exception(const std::string& msg=std::string()) : #{base}(#{c.value}, \"\"+msg) {}"
- }
+ genl "#{c.name.caps}Exception(const std::string& msg=std::string()) : #{base}(#{value}, \"\"+msg) {}"
+ }
end
- def define_exceptions_for(class_name, domain_name, base)
+ def declare_exceptions(class_name, domain_name, base)
enum = @amqp.class_(class_name).domain(domain_name).enum
- enum.choices.each { |c| define_exception(c, base, class_name) unless c.name == "normal" }
+ enum.choices.each { |c| declare_exception(c, base, class_name, enum) unless c.name == "normal" }
+ genl
+ genl "QPID_COMMON_EXTERN sys::ExceptionHolder create#{base}(int code, const std::string& text);"
+ end
+
+ def create_exception(class_name, domain_name, base, invalid)
+ scope("sys::ExceptionHolder create#{base}(int code, const std::string& text) {") {
+ genl "sys::ExceptionHolder holder;"
+ scope("switch (code) {") {
+ enum = @amqp.class_(class_name).domain(domain_name).enum
+ enum.choices.each { |c|
+ assign = "holder = new #{c.name.caps}Exception(text); " unless c.name == "normal"
+ genl "case #{c.value}: #{assign}break;"
+ }
+ genl "default: holder = new #{invalid}(QPID_MSG(\"Bad #{enum.parent.name}: \" << code << \": \" << text));"
+ }
+ genl "return holder;"
+ }
end
def reply_exceptions_h()
- h_file("#{@dir}/reply_exceptions") {
+ public_api("#{@dir}/reply_exceptions.h")
+ h_file("#{@dir}/reply_exceptions.h") {
include "qpid/Exception"
include "qpid/sys/ExceptionHolder"
+ include "qpid/framing/enum"
+ include "qpid/CommonImportExport.h"
namespace(@namespace) {
- define_exceptions_for("execution", "error-code", "SessionException")
- define_exceptions_for("connection", "close-code", "ConnectionException")
- define_exceptions_for("session", "detach-code", "ChannelException")
- genl
- genl "void throwExecutionException(int code, const std::string& text);"
- genl "void setExecutionException(sys::ExceptionHolder& holder, int code, const std::string& text);"
+ declare_exceptions("execution", "error-code", "SessionException")
+ declare_exceptions("connection", "close-code", "ConnectionException")
+ declare_exceptions("session", "detach-code", "ChannelException")
}
}
end
@@ -80,29 +184,21 @@ class ConstantsGen < CppGen
include "<sstream>"
include "<assert.h>"
namespace("qpid::framing") {
- scope("void throwExecutionException(int code, const std::string& text) {"){
- genl "sys::ExceptionHolder h;"
- genl "setExecutionException(h, code, text);"
- genl "h.raise();"
- }
- scope("void setExecutionException(sys::ExceptionHolder& holder, int code, const std::string& text) {"){
- scope("switch (code) {") {
- enum = @amqp.class_("execution").domain("error-code").enum
- enum.choices.each { |c|
- genl "case #{c.value}: holder = new #{c.name.caps}Exception(text); break;"
- }
- genl 'default: assert(0);'
- genl ' holder = new InvalidArgumentException(QPID_MSG("Bad exception code: " << code << ": " << text));'
- }
- }
+ create_exception("execution", "error-code", "SessionException", "InvalidArgumentException")
+ # FIXME aconway 2008-10-07: there are no good exception codes in 0-10 for an invalid code.
+ # The following choices are arbitrary.
+ create_exception("connection", "close-code", "ConnectionException", "FramingErrorException")
+ create_exception("session", "detach-code", "ChannelException", "NotAttachedException")
}
}
end
def generate()
constants_h
+ enum_h
reply_exceptions_h
reply_exceptions_cpp
+ typecode_h_cpp
end
end
diff --git a/cpp/rubygen/framing.0-10/frame_body_lists.rb b/cpp/rubygen/framing.0-10/frame_body_lists.rb
index b20e4550f3..4f1b976032 100644
--- a/cpp/rubygen/framing.0-10/frame_body_lists.rb
+++ b/cpp/rubygen/framing.0-10/frame_body_lists.rb
@@ -1,3 +1,21 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
$: << ".." # Include .. in load path
require 'cppgen'
@@ -26,6 +44,6 @@ EOS
end
end
-FrameBodyListsGen.new(ARGV[0], $amqp).generate;
+FrameBodyListsGen.new($outdir, $amqp).generate;
diff --git a/cpp/rubygen/framing.0-10/structs.rb b/cpp/rubygen/framing.0-10/structs.rb
index e4d57ca75d..c3684aea66 100644..100755
--- a/cpp/rubygen/framing.0-10/structs.rb
+++ b/cpp/rubygen/framing.0-10/structs.rb
@@ -1,4 +1,22 @@
#!/usr/bin/env ruby
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
# Usage: output_directory xml_spec_file [xml_spec_file...]
#
$: << '..'
@@ -26,6 +44,12 @@ class StructGen < CppGen
"timestamp"=>8
}
+ StringSizeMap={
+ "LongString"=>4,
+ "MediumString"=>2,
+ "ShortString"=>1
+ }
+
SizeType={
1=>"Octet",
2=>"Short",
@@ -153,13 +177,10 @@ class StructGen < CppGen
genl "total += #{size};//#{f.cppname}"
elsif (f.cpptype.name == "SequenceNumberSet")
genl "total += #{f.cppname}.encodedSize();"
- else
- encoded = f.cpptype.encoded
- gen "total += ("
- gen "4 + " if encoded == "LongString"
- gen "2 + " if encoded == "MediumString"
- gen "1 + " if encoded == "ShortString"
- genl "#{f.cppname}.size());"
+ elsif (size = StringSizeMap[f.cpptype.encoded])
+ genl "total += #{size} + #{f.cppname}.size();"
+ else
+ genl "total += #{f.cppname}.encodedSize();"
end
end
end
@@ -212,6 +233,7 @@ class StructGen < CppGen
using AMQMethodBody::accept;
void accept(MethodBodyConstVisitor& v) const { v.visit(*this); }
+ boost::intrusive_ptr<AMQBody> clone() const { return BodyFactory::copy(*this); }
ClassId amqpClassId() const { return CLASS_ID; }
MethodId amqpMethodId() const { return METHOD_ID; }
@@ -329,15 +351,15 @@ EOS
end
def declare_packed_accessors(f)
- genl "void set#{f.name.caps}(#{f.cpptype.param} _#{f.cppname});";
- genl "#{f.cpptype.ret} get#{f.name.caps}() const;"
+ genl "QPID_COMMON_EXTERN void set#{f.name.caps}(#{f.cpptype.param} _#{f.cppname});";
+ genl "QPID_COMMON_EXTERN #{f.cpptype.ret} get#{f.name.caps}() const;"
if (f.cpptype.name == "FieldTable")
- genl "#{f.cpptype.name}& get#{f.name.caps}();"
+ genl "QPID_COMMON_EXTERN #{f.cpptype.name}& get#{f.name.caps}();"
end
if (f.type_ != "bit")
#extra 'accessors' for packed fields:
- genl "bool has#{f.name.caps}() const;"
- genl "void clear#{f.name.caps}Flag();"
+ genl "QPID_COMMON_EXTERN bool has#{f.name.caps}() const;"
+ genl "QPID_COMMON_EXTERN void clear#{f.name.caps}Flag();"
end
end
@@ -359,9 +381,11 @@ EOS
else
inheritance = ": public AMQMethodBody"
end
+ else
+ public_api("qpid/framing/#{classname}.h") # Non-method structs are public
end
- h_file("qpid/framing/#{classname}.h") {
+ h_file("qpid/framing/#{classname}.h") {
if (s.kind_of? AmqpMethod)
gen <<EOS
#include "qpid/framing/AMQMethodBody.h"
@@ -377,6 +401,7 @@ EOS
#include <ostream>
#include "qpid/framing/amqp_types_full.h"
+#include "qpid/CommonImportExport.h"
namespace qpid {
namespace framing {
@@ -416,17 +441,17 @@ EOS
methodbody_extra_defs(s)
end
if (s.kind_of? AmqpStruct)
- indent {genl "friend std::ostream& operator<<(std::ostream&, const #{classname}&);" }
+ indent {genl "QPID_COMMON_EXTERN friend std::ostream& operator<<(std::ostream&, const #{classname}&);" }
end
gen <<EOS
- void encode(Buffer&) const;
- void decode(Buffer&, uint32_t=0);
- void encodeStructBody(Buffer&) const;
- void decodeStructBody(Buffer&, uint32_t=0);
- uint32_t size() const;
- uint32_t bodySize() const;
- void print(std::ostream& out) const;
+ QPID_COMMON_EXTERN void encode(Buffer&) const;
+ QPID_COMMON_EXTERN void decode(Buffer&, uint32_t=0);
+ QPID_COMMON_EXTERN void encodeStructBody(Buffer&) const;
+ QPID_COMMON_EXTERN void decodeStructBody(Buffer&, uint32_t=0);
+ QPID_COMMON_EXTERN uint32_t encodedSize() const;
+ QPID_COMMON_EXTERN uint32_t bodySize() const;
+ QPID_COMMON_EXTERN void print(std::ostream& out) const;
}; /* class #{classname} */
}}
@@ -439,9 +464,8 @@ EOS
buffer = "/*buffer*/"
end
gen <<EOS
-#include "#{classname}.h"
-
-#include "reply_exceptions.h"
+#include "qpid/framing/#{classname}.h"
+#include "qpid/framing/reply_exceptions.h"
using namespace qpid::framing;
@@ -528,8 +552,7 @@ EOS
return total;
}
-uint32_t #{classname}::size() const
-{
+uint32_t #{classname}::encodedSize() const {
uint32_t total = bodySize();
EOS
if (s.kind_of? AmqpStruct)
@@ -583,9 +606,10 @@ EOS
structs.each { |s| define_struct(s) }
@amqp.methods_.each { |m| define_struct(m) }
#generate a single include file containing the list of structs for convenience
- h_file("qpid/framing/amqp_structs.h") { structs.each { |s| genl "#include \"#{s.cppname}.h\"" } }
+ public_api("qpid/framing/amqp_structs.h")
+ h_file("qpid/framing/amqp_structs.h") { structs.each { |s| genl "#include \"qpid/framing/#{s.cppname}.h\"" } }
end
end
-StructGen.new(ARGV[0], $amqp).generate()
+StructGen.new($outdir, $amqp).generate()
diff --git a/cpp/rubygen/generate b/cpp/rubygen/generate
index 9acbd4fe83..89b9b99520 100755
--- a/cpp/rubygen/generate
+++ b/cpp/rubygen/generate
@@ -1,4 +1,22 @@
#!/usr/bin/env ruby
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
require 'pathname'
require 'amqpgen'
@@ -7,14 +25,14 @@ require 'amqpgen'
#
if ARGV.size < 3
puts <<EOS
-Usage: #{ARGV[0]} OUTDIR SPEC.xml [ ... ] TEMPLATE.rb [ ... ]
-or: #{ARGV[0]} OUTDIR SPEC.xml [ ... ] all [ makefragment.mk ]
+Usage: #{ARGV[0]} SRCDIR APIDIR SPEC.xml [ ... ] TEMPLATE.rb [ ... ]
+or: #{ARGV[0]} SRCDIR APIDIR SPEC.xml [ ... ] all [ makefragment.mk | makefragment.cmake ]
Parse all SPEC.xml files to create an AMQP model, run each TEMPLATE
-putting the resulting files under OUTDIR. Prints a list of files
-generated to standard output.
+putting the resulting files under SRCDIR, public API files in APIdir.
+Prints a list of files generated to standard output.
-If OUTDIR is '-' then just prints file list without generating files.
+If SRCDIR and APIDIR are '-' then just prints file list without generating files.
EOS
exit 1
end
@@ -39,15 +57,16 @@ gendir=File.dirname(__FILE__)
if ARGV.any? { |arg| arg=="all" }
templates=Dir["#{gendir}/*/*.rb"]
else
- templates=ARGV.grep(/\.rb$/)
+templates=ARGV.grep(/\.rb$/)
ARGV.each { |arg|
d=File.join gendir,arg
templates += Dir["#{d}/*.rb"] if File.directory? d
}
end
-$outdir=ARGV[0]
+$outdir=[ ARGV[0], ARGV[1] ]
$models=parse_specs(ARGV.grep(/\.xml$/))
+
templates.each { |t|
ver=Pathname.new(t).dirname.basename.to_s.split('.')[-1]
$amqp=$models[ver]
@@ -58,50 +77,84 @@ templates.each { |t|
end
}
+def cmake_continue(lines) lines.join(" \n "); end
def make_continue(lines) lines.join(" \\\n "); end
# Generate makefile
makefile=ARGV.grep(/.mk$/)[0]
-if makefile
+cmakefile=ARGV.grep(/.cmake$/)[0]
+if cmakefile || makefile
+ srcdir,apidir=$outdir
dir=Dir.getwd
Dir.chdir File.dirname(__FILE__)
generator_files=Dir["**/*.rb"] << File.basename(__FILE__)
Dir.chdir dir
rgen_generator=generator_files.map{ |f| "$(rgen_dir)/#{f}" }
- rgen_srcs=GenFiles.get.map{ |f| "#{$outdir}/#{f}" }
+ cmake_rgen_generator=generator_files.map{ |f| "${rgen_dir}/#{f}" }
+ rgen_srcs=GenFiles.get.map{ |f| "#{GenFiles.public_api?(f) ? apidir : srcdir}/#{f}" }
rgen_subdirs={}
rgen_srcs.each { |src|
- if src.match(%r{#{$outdir}/qpid/([^/]+)/})
- subdir=$1
+ if src.match(%r{(#{srcdir}|#{apidir})/qpid/([^/]+)/})
+ subdir=$2
rgen_subdirs[subdir] ||= []
rgen_subdirs[subdir] << src
end
}
- File.open(makefile, 'w') { |out|
- out << <<EOS
+ if (makefile)
+ File.open(makefile, 'w') { |out|
+ out << <<EOS
# Generated makefile fragment.
# Including makefile defines $(rgen_dir) $(rgen_cmd) and $(specs).
rgen_generator=#{make_continue rgen_generator}
EOS
- rgen_subdirs.each_key { |subdir|
- out << "\nrgen_#{subdir}_srcs = #{make_continue(rgen_subdirs[subdir])}\n"
- }
- out << <<EOS
+ rgen_subdirs.each_key { |subdir|
+ out << "\nrgen_#{subdir}_srcs = #{make_continue(rgen_subdirs[subdir])}\n"
+ }
+ out << <<EOS
rgen_srcs=#{make_continue rgen_srcs}
# Header file install rules.
EOS
- ["amqp_0_10", "framing", "client/no_keyword","client", "broker"].each { |ns|
- dir="qpid/#{ns}"
- dir_ = dir.tr("/", "_")
- regex=%r|#{dir}/[^/]+\.h$|
- out << <<EOS
+ ["amqp_0_10", "framing", "client/no_keyword","client", "broker"].each { |ns|
+ dir="qpid/#{ns}"
+ dir_ = dir.tr("/", "_")
+ regex=%r|#{dir}/[^/]+\.h$|
+ out << <<EOS
#{dir_}dir = $(includedir)/#{dir}
dist_#{dir_}_HEADERS = #{make_continue rgen_srcs.grep(regex)}
EOS
- }
- }
-end
+ } # each
+ } # File makefile
+ end # if (makefile)
+ if (cmakefile)
+ File.open(cmakefile, 'w') { |out|
+ out << <<EOS
+# Generated makefile fragment.
+# Including makefile defines ${rgen_dir} ${rgen_cmd} and ${specs}.
+
+set(rgen_generator #{cmake_continue cmake_rgen_generator})
+EOS
+ rgen_subdirs.each_key { |subdir|
+ out << "\nset(rgen_#{subdir}_srcs #{cmake_continue(rgen_subdirs[subdir])})\n"
+ }
+ out << <<EOS
+set(rgen_srcs #{cmake_continue rgen_srcs})
+
+# Header file install rules.
+EOS
+ ["amqp_0_10", "framing", "client/no_keyword","client", "broker"].each { |ns|
+ dir="qpid/#{ns}"
+ dir_ = dir.tr("/", "_")
+ regex=%r|#{dir}/[^/]+\.h$|
+ out << <<EOS
+set(#{dir_}dir \${includedir}/#{dir})
+set(dist_#{dir_}_HEADERS #{cmake_continue rgen_srcs.grep(regex)})
+
+EOS
+ } # each
+ } # File makefile
+ end # if (makefile)
+end
diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt
new file mode 100644
index 0000000000..899dd5568c
--- /dev/null
+++ b/cpp/src/CMakeLists.txt
@@ -0,0 +1,949 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Option to require building optional plugins
+foreach (r ${REQUIRE})
+ set(${r}_force ON)
+ message(STATUS "Forcing ${r} to ${${r}_force}")
+endforeach(r)
+
+include(CheckFunctionExists)
+include(CheckIncludeFileCXX)
+include(CheckIncludeFiles)
+include(CheckIncludeFileCXX)
+include(CheckLibraryExists)
+include(CheckSymbolExists)
+include(FindBoost)
+include(FindDoxygen)
+
+#set (CMAKE_VERBOSE_MAKEFILE ON) # for debugging
+
+# check if we generate source as part of the build
+# - rubygen generates the amqp spec and clustering
+# - managementgen generates the broker management code
+#
+# rubygen subdir is excluded from stable distributions
+# If the main AMQP spec is present, then check if ruby and python are
+# present, and if any sources have changed, forcing a re-gen of source code.
+
+set(AMQP_SPEC_DIR ${qpid-cpp_SOURCE_DIR}/../specs)
+set(AMQP_SPEC ${AMQP_SPEC_DIR}/amqp.0-10-qpid-errata.xml)
+if (EXISTS ${AMQP_SPEC})
+ include(FindRuby)
+ include(FindPythonInterp)
+ if (NOT RUBY_EXECUTABLE)
+ message(FATAL_ERROR "Can't locate ruby, needed to generate source files.")
+ endif (NOT RUBY_EXECUTABLE)
+ if (NOT PYTHON_EXECUTABLE)
+ message(FATAL_ERROR "Can't locate python, needed to generate source files.")
+ endif (NOT PYTHON_EXECUTABLE)
+
+ set(specs ${AMQP_SPEC} ${qpid-cpp_SOURCE_DIR}/xml/cluster.xml)
+ set(regen_amqp OFF)
+ set(rgen_dir ${qpid-cpp_SOURCE_DIR}/rubygen)
+ file(GLOB_RECURSE rgen_progs ${rgen_dir}/*.rb)
+ # If any of the specs, or any of the sources used to generate code, change
+ # then regenerate the sources.
+ foreach (spec_file ${specs} ${rgen_progs})
+ if (${spec_file} IS_NEWER_THAN ${CMAKE_CURRENT_BINARY_DIR}/rubygen.cmake)
+ set(regen_amqp ON)
+ endif (${spec_file} IS_NEWER_THAN ${CMAKE_CURRENT_BINARY_DIR}/rubygen.cmake)
+ endforeach (spec_file ${specs})
+ if (regen_amqp)
+ message(STATUS "Regenerating AMQP protocol sources")
+execute_process(COMMAND ${RUBY_EXECUTABLE} -I ${rgen_dir} ${rgen_dir}/generate ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/../include ${specs} all rubygen.cmake
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ else (regen_amqp)
+ message(STATUS "No need to generate AMQP protocol sources")
+ endif (regen_amqp)
+
+ set(mgmt_specs ${AMQP_SPEC_DIR}/management-schema.xml
+ ${CMAKE_CURRENT_SOURCE_DIR}/qpid/acl/management-schema.xml
+ ${CMAKE_CURRENT_SOURCE_DIR}/qpid/cluster/management-schema.xml)
+ set(mgen_dir ${qpid-cpp_SOURCE_DIR}/managementgen)
+ set(regen_mgmt OFF)
+ foreach (spec_file ${mgmt_specs})
+ if (${spec_file} IS_NEWER_THAN ${CMAKE_CURRENT_BINARY_DIR}/managementgen.cmake)
+ message(STATUS "${spec_file} is newer")
+ set(regen_mgmt ON)
+ endif (${spec_file} IS_NEWER_THAN ${CMAKE_CURRENT_BINARY_DIR}/managementgen.cmake)
+ endforeach (spec_file ${mgmt_specs})
+ if (regen_mgmt)
+ message(STATUS "Regenerating Qpid Management Framework sources")
+execute_process(COMMAND ${PYTHON_EXECUTABLE} ${mgen_dir}/qmf-gen -c managementgen.cmake -b -q -o ${CMAKE_CURRENT_BINARY_DIR}/qmf ${mgmt_specs}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ else (regen_mgmt)
+ message(STATUS "No need to generate Qpid Management Framework sources")
+ endif (regen_mgmt)
+
+ # Pull in the names of the generated files, i.e. ${rgen_framing_srcs}
+ include (${CMAKE_CURRENT_BINARY_DIR}/rubygen.cmake)
+ include (${CMAKE_CURRENT_BINARY_DIR}/managementgen.cmake)
+
+else (EXISTS ${AMQP_SPEC})
+ message(STATUS "No AMQP spec... presume generated sources are included")
+ include (rubygen.cmake)
+ include (managementgen.cmake)
+endif (EXISTS ${AMQP_SPEC})
+
+find_program(HELP2MAN help2man DOC "Location of the help2man program")
+option(GEN_MANPAGES "Use help2man to generate man pages" ON)
+if (GEN_MANPAGES AND NOT HELP2MAN)
+ message(STATUS "Can't locate the help2man command; man pages will not be generated")
+ set (GEN_MANPAGES OFF)
+endif (GEN_MANPAGES AND NOT HELP2MAN)
+
+# FindDoxygen module tries to locate doxygen and Graphviz dot
+set (docs_default ON)
+if (NOT DOXYGEN_EXECUTABLE)
+ set (docs_default OFF)
+endif (NOT DOXYGEN_EXECUTABLE)
+option(GEN_DOXYGEN "Use doxygen to generate user documentation" ${docs_default})
+if (GEN_DOXYGEN AND NOT DOXYGEN_EXECUTABLE)
+ message(STATUS "Can't locate the doxygen command; user documentation will not be generated")
+ set (GEN_DOXYGEN OFF)
+endif (GEN_DOXYGEN AND NOT DOXYGEN_EXECUTABLE)
+
+find_program(VALGRIND valgrind DOC "Location of the valgrind program")
+option(ENABLE_VALGRIND "Use valgrind to detect run-time problems" ON)
+if (ENABLE_VALGRIND AND NOT VALGRIND)
+ message(STATUS "Can't locate the valgrind command; no run-time error detection")
+endif (ENABLE_VALGRIND AND NOT VALGRIND)
+
+if (CMAKE_COMPILER_IS_GNUCXX)
+ set (COMPILER_FLAGS "")
+ # Warnings: Enable as many as possible, keep the code clean. Please
+ # do not disable warnings or remove -Werror without discussing on
+ # qpid-dev list.
+ #
+ # The following warnings are deliberately omitted, they warn on valid code.
+ # -Wunreachable-code -Wpadded -Winline
+ # -Wshadow - warns about boost headers.
+ set (WARNING_FLAGS
+ "-Werror -pedantic -Wall -Wextra -Wno-shadow -Wpointer-arith -Wcast-qual -Wcast-align -Wno-long-long -Wvolatile-register-var -Winvalid-pch -Wno-system-headers -Woverloaded-virtual")
+endif (CMAKE_COMPILER_IS_GNUCXX)
+
+if (CMAKE_CXX_COMPILER_ID STREQUAL SunPro)
+ set (COMPILER_FLAGS "-library=stlport4 -mt")
+ set (WARNING_FLAGS "+w2")
+endif (CMAKE_CXX_COMPILER_ID STREQUAL SunPro)
+
+option(ENABLE_WARNINGS "Enable lots of compiler warnings (recommended)" ON)
+if (NOT ENABLE_WARNINGS)
+ set (WARNING_FLAGS "")
+endif (NOT ENABLE_WARNINGS)
+
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILER_FLAGS} ${WARNING_FLAGS}")
+
+# Expand a bit from the basic Find_Boost; be specific about what's needed.
+# TODO: Not all these libs are needed everywhere:
+# Linux only uses filesystem program_options unit_test_framework
+# (which itself uses regex).
+# Boost.system is sometimes needed; it's handled separately, below.
+find_package(Boost 1.33 REQUIRED
+ COMPONENTS filesystem program_options date_time thread
+ regex unit_test_framework)
+if(NOT Boost_FOUND)
+ message(FATAL_ERROR "Boost C++ libraries not found. Please install or try setting BOOST_ROOT")
+endif(NOT Boost_FOUND)
+
+# Boost.system was introduced at Boost 1.35; it's needed secondarily by other
+# Boost libs Qpid needs, so be sure it's there.
+if (NOT Boost_VERSION LESS 103500)
+ find_package(Boost COMPONENTS system)
+ if (NOT Boost_SYSTEM_LIBRARY)
+ set(Boost_SYSTEM_LIBRARY boost_system)
+ endif (NOT Boost_SYSTEM_LIBRARY)
+
+endif (NOT Boost_VERSION LESS 103500)
+
+# Versions of cmake pre 2.6 don't set the Boost_*_LIBRARY variables correctly
+# these values are correct for Linux
+if (NOT Boost_PROGRAM_OPTIONS_LIBRARY)
+ set(Boost_PROGRAM_OPTIONS_LIBRARY boost_program_options)
+endif (NOT Boost_PROGRAM_OPTIONS_LIBRARY)
+
+if (NOT Boost_FILESYSTEM_LIBRARY)
+ set(Boost_FILESYSTEM_LIBRARY boost_filesystem)
+endif (NOT Boost_FILESYSTEM_LIBRARY)
+
+if (NOT Boost_UNIT_TEST_FRAMEWORK_LIBRARY)
+ set(Boost_UNIT_TEST_FRAMEWORK_LIBRARY boost_unit_test_framework)
+endif (NOT Boost_UNIT_TEST_FRAMEWORK_LIBRARY)
+
+if (NOT Boost_REGEX_LIBRARY)
+ set(Boost_REGEX_LIBRARY boost_regex)
+endif (NOT Boost_REGEX_LIBRARY)
+
+if (NOT Boost_SYSTEM_LIBRARY)
+ set(Boost_SYSTEM_LIBRARY boost_system)
+endif (NOT Boost_SYSTEM_LIBRARY)
+
+# The Windows install also wants the Boost DLLs and headers that the release
+# is built with. The DLLs enable everything to run, and the headers ensure
+# that users building Qpid C++ client programs can compile (the C++ API
+# still exposes Boost headers, but hopefully this will be fixed in the
+# future).
+#
+# On Windows you can pick whether the static or dynamic versions of the libs
+# are used; allow this choice to the user. Since we also install the Boost
+# DLLs that are needed for the Windows package, none are needed for the
+# static link case; else drop them into the install. Do this all first, since
+# Boost on Windows can use automatic linking to pick up the correct
+# Boost libs based on compile-time touching of the headers. Since we don't
+# really need to add them to the link lines, set the names to blanks.
+if (MSVC)
+ option(QPID_LINK_BOOST_DYNAMIC "Link with dynamic Boost libs (OFF to link static)" ON)
+ if (QPID_LINK_BOOST_DYNAMIC)
+ add_definitions( /D BOOST_ALL_DYN_LINK)
+ string (REPLACE .lib .dll
+ _boost_date_time_debug ${Boost_DATE_TIME_LIBRARY_DEBUG})
+ string (REPLACE .lib .dll
+ _boost_date_time_release ${Boost_DATE_TIME_LIBRARY_RELEASE})
+ string (REPLACE .lib .dll
+ _boost_filesystem_debug ${Boost_FILESYSTEM_LIBRARY_DEBUG})
+ string (REPLACE .lib .dll
+ _boost_filesystem_release ${Boost_FILESYSTEM_LIBRARY_RELEASE})
+ string (REPLACE .lib .dll
+ _boost_program_options_debug ${Boost_PROGRAM_OPTIONS_LIBRARY_DEBUG})
+ string (REPLACE .lib .dll
+ _boost_program_options_release ${Boost_PROGRAM_OPTIONS_LIBRARY_RELEASE})
+ string (REPLACE .lib .dll
+ _boost_regex_debug ${Boost_REGEX_LIBRARY_DEBUG})
+ string (REPLACE .lib .dll
+ _boost_regex_release ${Boost_REGEX_LIBRARY_RELEASE})
+ string (REPLACE .lib .dll
+ _boost_thread_debug ${Boost_THREAD_LIBRARY_DEBUG})
+ string (REPLACE .lib .dll
+ _boost_thread_release ${Boost_THREAD_LIBRARY_RELEASE})
+ # Boost 1.35 added the system library, which gets indirectly linked in
+ # via other Boost libs. So, if building with Boost 1.35 or later, also
+ # include system in the Windows install package.
+ if (NOT Boost_VERSION LESS 103500)
+ string (REPLACE boost_thread boost_system
+ _boost_system_debug ${_boost_thread_debug})
+ string (REPLACE boost_thread boost_system
+ _boost_system_release ${_boost_thread_release})
+ endif (NOT Boost_VERSION LESS 103500)
+ install (PROGRAMS
+ ${_boost_date_time_debug} ${_boost_date_time_release}
+ ${_boost_filesystem_debug} ${_boost_filesystem_release}
+ ${_boost_program_options_debug} ${_boost_program_options_release}
+ ${_boost_regex_debug} ${_boost_regex_release}
+ ${_boost_system_debug} ${_boost_system_release}
+ ${_boost_thread_debug} ${_boost_thread_release}
+ DESTINATION ${QPID_INSTALL_LIBDIR}
+ COMPONENT ${QPID_COMPONENT_COMMON})
+ endif (QPID_LINK_BOOST_DYNAMIC)
+
+ # Need the boost headers regardless of which way the libs go.
+ install (DIRECTORY ${Boost_INCLUDE_DIR}/boost
+ DESTINATION ${QPID_INSTALL_INCLUDEDIR}
+ COMPONENT ${QPID_COMPONENT_CLIENT_INCLUDE})
+
+ set(Boost_DATE_TIME_LIBRARY "")
+ set(Boost_THREAD_LIBRARY "")
+ set(Boost_PROGRAM_OPTIONS_LIBRARY "")
+ set(Boost_FILESYSTEM_LIBRARY "")
+ set(Boost_UNIT_TEST_FRAMEWORK_LIBRARY "")
+ set(Boost_REGEX_LIBRARY "")
+endif (MSVC)
+
+include_directories( ${Boost_INCLUDE_DIR} )
+
+include_directories( ${CMAKE_CURRENT_SOURCE_DIR} )
+include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../include )
+include_directories( ${CMAKE_CURRENT_BINARY_DIR} )
+include_directories( ${CMAKE_CURRENT_BINARY_DIR}/../include )
+
+link_directories( ${Boost_LIBRARY_DIRS} )
+
+CHECK_LIBRARY_EXISTS (rt clock_gettime "" CLOCK_GETTIME_IN_RT)
+if (NOT CLOCK_GETTIME_IN_RT)
+ CHECK_FUNCTION_EXISTS (clock_gettime QPID_HAS_CLOCK_GETTIME)
+else (NOT CLOCK_GETTIME_IN_RT)
+ set(CMAKE_REQUIRED_LIBS ${CMAKE_REQUIRED_LIBS} rt)
+ set(QPID_HAS_CLOCK_GETTIME YES CACHE BOOL "Platform has clock_gettime")
+endif (NOT CLOCK_GETTIME_IN_RT)
+
+# See if Cyrus SASL is desired and available
+CHECK_LIBRARY_EXISTS (sasl2 sasl_checkpass "" HAVE_SASL2)
+CHECK_INCLUDE_FILES (sasl/sasl.h HAVE_SASL_H)
+
+set (sasl_default ${sasl_force})
+if (HAVE_SASL2 AND HAVE_SASL_H)
+ set (sasl_default ON)
+endif (HAVE_SASL2 AND HAVE_SASL_H)
+
+option(BUILD_SASL "Build with Cyrus SASL support" ${sasl_default})
+if (BUILD_SASL)
+ if (NOT HAVE_SASL2)
+ message(FATAL_ERROR "Cyrus SASL support requested but libsasl2 not found")
+ endif (NOT HAVE_SASL2)
+ if (NOT HAVE_SASL_H)
+ message(FATAL_ERROR "Cyrus SASL support requested but sasl.h not found")
+ endif (NOT HAVE_SASL_H)
+
+ set(BROKER_SASL_NAME "qpidd" CACHE STRING "SASL app name for the qpid broker")
+ set(qpidcommon_sasl_source
+ qpid/sys/cyrus/CyrusSecurityLayer.h
+ qpid/sys/cyrus/CyrusSecurityLayer.cpp
+ )
+ set(qpidcommon_sasl_lib sasl2)
+endif (BUILD_SASL)
+
+# See if XML Exchange is desired and prerequisites are available
+CHECK_LIBRARY_EXISTS (xerces-c _init "" HAVE_XERCES)
+CHECK_INCLUDE_FILE_CXX (xercesc/framework/MemBufInputSource.hpp HAVE_XERCES_H)
+CHECK_INCLUDE_FILE_CXX (xqilla/xqilla-simple.hpp HAVE_XQILLA_H)
+
+set (xml_default ${xml_force})
+if (CMAKE_SYSTEM_NAME STREQUAL Windows)
+else (CMAKE_SYSTEM_NAME STREQUAL Windows)
+ if (HAVE_XERCES AND HAVE_XERCES_H)
+ if (HAVE_XQILLA_H)
+ set (xml_default ON)
+ endif (HAVE_XQILLA_H)
+ endif (HAVE_XERCES AND HAVE_XERCES_H)
+endif (CMAKE_SYSTEM_NAME STREQUAL Windows)
+
+option(BUILD_XML "Build with XML Exchange" ${xml_default})
+if (BUILD_XML)
+ if (NOT HAVE_XERCES)
+ message(FATAL_ERROR "XML Exchange support requested but xerces-c library not found")
+ endif (NOT HAVE_XERCES)
+ if (NOT HAVE_XERCES_H)
+ message(FATAL_ERROR "XML Exchange support requested but Xerces-C headers not found")
+ endif (NOT HAVE_XERCES_H)
+ if (NOT HAVE_XQILLA_H)
+ message(FATAL_ERROR "XML Exchange support requested but XQilla headers not found")
+ endif (NOT HAVE_XQILLA_H)
+
+ add_library (xml MODULE
+ qpid/xml/XmlExchange.cpp
+ qpid/xml/XmlExchange.h
+ qpid/xml/XmlExchangePlugin.cpp)
+ set_target_properties (xml PROPERTIES PREFIX "")
+ target_link_libraries (xml xerces-c xqilla qpidbroker pthread)
+ if (CMAKE_COMPILER_IS_GNUCXX)
+ set_target_properties (xml PROPERTIES
+ PREFIX ""
+ LINK_FLAGS -Wl,--no-undefined)
+ endif (CMAKE_COMPILER_IS_GNUCXX)
+ install (TARGETS xml
+ DESTINATION ${QPIDD_MODULE_DIR}
+ COMPONENT ${QPID_COMPONENT_BROKER})
+
+ set(xml_tests XmlClientSessionTest)
+
+endif (BUILD_XML)
+
+# Build the ACL plugin
+set (acl_default ON)
+# Like this until we fix exporting symbols from the generated management code
+if (CMAKE_SYSTEM_NAME STREQUAL Windows)
+ set(acl_default OFF)
+endif (CMAKE_SYSTEM_NAME STREQUAL Windows)
+option(BUILD_ACL "Build ACL enforcement broker plugin" ${acl_default})
+if (BUILD_ACL)
+ set (acl_SOURCES
+ qpid/acl/Acl.cpp
+ qpid/acl/Acl.h
+ qpid/acl/AclData.cpp
+ qpid/acl/AclData.h
+ qpid/acl/AclPlugin.cpp
+ qpid/acl/AclReader.cpp
+ qpid/acl/AclReader.h
+ )
+ add_library (acl MODULE ${acl_SOURCES})
+ set_target_properties (acl PROPERTIES PREFIX "")
+ target_link_libraries (acl qpidbroker ${Boost_PROGRAM_OPTIONS_LIBRARY})
+ if (CMAKE_COMPILER_IS_GNUCXX)
+ set_target_properties (acl PROPERTIES
+ PREFIX ""
+ LINK_FLAGS -Wl,--no-undefined)
+ endif (CMAKE_COMPILER_IS_GNUCXX)
+ install (TARGETS acl
+ DESTINATION ${QPIDD_MODULE_DIR}
+ COMPONENT ${QPID_COMPONENT_BROKER})
+endif (BUILD_ACL)
+
+# Check for optional cluster support requirements
+include (cluster.cmake)
+
+# Check for optional RDMA support requirements
+include (rdma.cmake)
+
+# Check for optional SSL support requirements
+include (ssl.cmake)
+
+# Check for syslog capabilities not present on all systems
+check_symbol_exists (LOG_AUTHPRIV "sys/syslog.h" HAVE_LOG_AUTHPRIV)
+check_symbol_exists (LOG_FTP "sys/syslog.h" HAVE_LOG_FTP)
+
+if (CMAKE_SYSTEM_NAME STREQUAL Windows)
+ if (MSVC)
+ add_definitions(
+ /D "_CRT_NONSTDC_NO_WARNINGS"
+ /D "NOMINMAX"
+ /D "WIN32_LEAN_AND_MEAN"
+ /D "_SCL_SECURE_NO_WARNINGS"
+ /wd4244
+ /wd4800
+ /wd4355
+ )
+ endif (MSVC)
+
+ set (qpidcommon_platform_SOURCES
+ qpid/log/windows/SinkOptions.cpp
+ qpid/sys/windows/AsynchIO.cpp
+ qpid/sys/windows/FileSysDir.cpp
+ qpid/sys/windows/IocpPoller.cpp
+ qpid/sys/windows/IOHandle.cpp
+ qpid/sys/windows/LockFile.cpp
+ qpid/sys/windows/PipeHandle.cpp
+ qpid/sys/windows/PollableCondition.cpp
+ qpid/sys/windows/Shlib.cpp
+ qpid/sys/windows/Socket.cpp
+ qpid/sys/windows/SocketAddress.cpp
+ qpid/sys/windows/StrError.cpp
+ qpid/sys/windows/SystemInfo.cpp
+ qpid/sys/windows/Thread.cpp
+ qpid/sys/windows/Time.cpp
+ qpid/sys/windows/uuid.cpp
+ ${sslcommon_windows_SOURCES}
+ )
+ set (qpidcommon_platform_LIBS
+ ${windows_ssl_libs} rpcrt4 ws2_32
+ )
+ set (qpidbroker_platform_SOURCES
+ qpid/broker/windows/BrokerDefaults.cpp
+ qpid/broker/windows/SaslAuthenticator.cpp
+ ${sslbroker_windows_SOURCES}
+ )
+ set (qpidbroker_platform_LIBS
+ ${windows_ssl_libs}
+ )
+ set (qpidclient_platform_SOURCES
+ qpid/client/windows/SaslFactory.cpp
+ ${sslclient_windows_SOURCES}
+ )
+ set (qpidclient_platform_LIBS
+ ${windows_ssl_libs}
+ )
+
+ set (qpidd_platform_SOURCES
+ windows/QpiddBroker.cpp
+ )
+
+else (CMAKE_SYSTEM_NAME STREQUAL Windows)
+
+ # POSIX (Non-Windows) platforms have a lot of overlap in sources; the only
+ # major difference is the poller module.
+ if (CMAKE_SYSTEM_NAME STREQUAL Linux)
+ set (qpid_poller_module
+ qpid/sys/epoll/EpollPoller.cpp
+ qpid/sys/posix/SystemInfo.cpp
+ )
+ add_definitions(-pthread)
+ set (CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} -pthread)
+ endif (CMAKE_SYSTEM_NAME STREQUAL Linux)
+
+ if (CMAKE_SYSTEM_NAME STREQUAL SunOS)
+ set (qpid_poller_module
+ qpid/sys/solaris/ECFPoller.cpp
+ qpid/sys/solaris/SystemInfo.cpp
+ )
+ endif (CMAKE_SYSTEM_NAME STREQUAL SunOS)
+
+ set (qpidcommon_platform_SOURCES
+ qpid/sys/posix/AsynchIO.cpp
+ qpid/sys/posix/Fork.cpp
+ qpid/sys/posix/FileSysDir.cpp
+ qpid/sys/posix/IOHandle.cpp
+ qpid/sys/posix/LockFile.cpp
+ qpid/sys/posix/Mutex.cpp
+ qpid/sys/posix/PipeHandle.cpp
+ qpid/sys/posix/PollableCondition.cpp
+ qpid/sys/posix/Shlib.cpp
+ qpid/log/posix/SinkOptions.cpp
+ qpid/sys/posix/Socket.cpp
+ qpid/sys/posix/SocketAddress.cpp
+ qpid/sys/posix/StrError.cpp
+ qpid/sys/posix/Thread.cpp
+ qpid/sys/posix/Time.cpp
+
+ ${qpid_poller_module}
+ )
+ set (qpidcommon_platform_LIBS
+ ${Boost_PROGRAM_OPTIONS_LIBRARY}
+ ${Boost_FILESYSTEM_LIBRARY}
+ uuid
+ ${CMAKE_DL_LIBS}
+ )
+
+ set (qpidbroker_platform_SOURCES
+ qpid/broker/Daemon.cpp
+ qpid/broker/SaslAuthenticator.cpp
+ qpid/broker/SignalHandler.h
+ qpid/broker/SignalHandler.cpp
+ qpid/broker/posix/BrokerDefaults.cpp
+ )
+
+ set (qpidclient_platform_SOURCES
+ qpid/client/SaslFactory.cpp
+ )
+
+ set (qpidd_platform_SOURCES
+ posix/QpiddBroker.cpp
+ )
+endif (CMAKE_SYSTEM_NAME STREQUAL Windows)
+
+set (qpidcommon_SOURCES
+ ${rgen_framing_srcs}
+ ${qpidcommon_platform_SOURCES}
+ ${qpidcommon_sasl_source}
+ qpid/assert.cpp
+ qpid/Address.cpp
+ qpid/DataDir.cpp
+ qpid/Exception.cpp
+ qpid/Modules.cpp
+ qpid/Options.cpp
+ qpid/Plugin.cpp
+ qpid/RefCountedBuffer.cpp
+ qpid/SessionState.cpp
+ qpid/SessionId.cpp
+ qpid/StringUtils.cpp
+ qpid/Url.cpp
+ qpid/amqp_0_10/SessionHandler.cpp
+ qpid/framing/AccumulatedAck.cpp
+ qpid/framing/AMQBody.cpp
+ qpid/framing/AMQMethodBody.cpp
+ qpid/framing/AMQContentBody.cpp
+ qpid/framing/AMQFrame.cpp
+ qpid/framing/AMQHeaderBody.cpp
+ qpid/framing/AMQHeartbeatBody.cpp
+ qpid/framing/Array.cpp
+ qpid/framing/BodyHandler.cpp
+ qpid/framing/Buffer.cpp
+ qpid/framing/Endian.cpp
+ qpid/framing/FieldTable.cpp
+ qpid/framing/FieldValue.cpp
+ qpid/framing/FrameSet.cpp
+ qpid/framing/FrameDecoder.cpp
+ qpid/framing/List.cpp
+ qpid/framing/ProtocolInitiation.cpp
+ qpid/framing/ProtocolVersion.cpp
+ qpid/framing/SendContent.cpp
+ qpid/framing/SequenceNumber.cpp
+ qpid/framing/SequenceNumberSet.cpp
+ qpid/framing/SequenceSet.cpp
+ qpid/framing/Proxy.cpp
+ qpid/framing/Uuid.cpp
+ qpid/framing/TransferContent.cpp
+ qpid/log/Logger.cpp
+ qpid/log/Options.cpp
+ qpid/log/OstreamOutput.cpp
+ qpid/log/Selector.cpp
+ qpid/log/Statement.cpp
+ qpid/management/Manageable.cpp
+ qpid/management/ManagementObject.cpp
+ qpid/sys/AggregateOutput.cpp
+ qpid/sys/AsynchIOHandler.cpp
+ qpid/sys/Dispatcher.cpp
+ qpid/sys/DispatchHandle.cpp
+ qpid/sys/Runnable.cpp
+ qpid/sys/Shlib.cpp
+ qpid/sys/Timer.cpp
+)
+
+add_library (qpidcommon SHARED ${qpidcommon_SOURCES})
+if (CLOCK_GETTIME_IN_RT)
+ set (qpidcommon_platform_LIBS ${qpidcommon_platform_LIBS} rt)
+endif (CLOCK_GETTIME_IN_RT)
+target_link_libraries (qpidcommon
+ ${qpidcommon_platform_LIBS}
+ ${qpidcommon_sasl_lib})
+set_target_properties (qpidcommon PROPERTIES
+ VERSION ${qpidc_version})
+install (TARGETS qpidcommon
+ DESTINATION ${QPID_INSTALL_LIBDIR}
+ COMPONENT ${QPID_COMPONENT_COMMON})
+# When the client programming component is installed, Windows also needs
+# the debug variant of qpidcommon and qpidclient, and the PDBs for those
+# as well. It would be nice to figure out a way to put some sanity checking
+# here... as it is, success relies on the packager building the debug then
+# the release, then packaging the release build.
+if (WIN32)
+ install (PROGRAMS
+ ${CMAKE_CURRENT_BINARY_DIR}/Debug/qpidcommond.dll
+ ${CMAKE_CURRENT_BINARY_DIR}/Debug/qpidcommond.lib
+ ${CMAKE_CURRENT_BINARY_DIR}/Debug/qpidcommond.pdb
+ DESTINATION ${QPID_INSTALL_LIBDIR}
+ COMPONENT ${QPID_COMPONENT_CLIENT})
+endif (WIN32)
+
+set (qpidclient_SOURCES
+ ${rgen_client_srcs}
+ ${qpidclient_platform_SOURCES}
+ qpid/client/Bounds.cpp
+ qpid/client/Completion.cpp
+ qpid/client/Connection.cpp
+ qpid/client/ConnectionHandler.cpp
+ qpid/client/ConnectionImpl.cpp
+ qpid/client/ConnectionSettings.cpp
+ qpid/client/Connector.cpp
+ qpid/client/Demux.cpp
+ qpid/client/Dispatcher.cpp
+ qpid/client/FailoverManager.cpp
+ qpid/client/FailoverListener.cpp
+ qpid/client/Future.cpp
+ qpid/client/FutureCompletion.cpp
+ qpid/client/FutureResult.cpp
+ qpid/client/LoadPlugins.cpp
+ qpid/client/LocalQueue.cpp
+ qpid/client/LocalQueueImpl.cpp
+ qpid/client/Message.cpp
+ qpid/client/MessageImpl.cpp
+ qpid/client/MessageListener.cpp
+ qpid/client/MessageReplayTracker.cpp
+ qpid/client/QueueOptions.cpp
+ qpid/client/Results.cpp
+ qpid/client/SessionBase_0_10.cpp
+ qpid/client/SessionBase_0_10Access.h
+ qpid/client/ConnectionAccess.h
+ qpid/client/SessionImpl.cpp
+ qpid/client/StateManager.cpp
+ qpid/client/Subscription.cpp
+ qpid/client/SubscriptionImpl.cpp
+ qpid/client/SubscriptionManager.cpp
+ qpid/client/SubscriptionManagerImpl.cpp
+ qpid/client/TCPConnector.cpp
+ qpid/messaging/Address.cpp
+ qpid/messaging/Connection.cpp
+ qpid/messaging/ConnectionImpl.h
+ qpid/messaging/ListContent.cpp
+ qpid/messaging/ListView.cpp
+ qpid/messaging/MapContent.cpp
+ qpid/messaging/MapView.cpp
+ qpid/messaging/Message.cpp
+ qpid/messaging/MessageImpl.h
+ qpid/messaging/MessageImpl.cpp
+ qpid/messaging/Receiver.cpp
+ qpid/messaging/ReceiverImpl.h
+ qpid/messaging/Session.cpp
+ qpid/messaging/SessionImpl.h
+ qpid/messaging/Sender.cpp
+ qpid/messaging/SenderImpl.h
+ qpid/messaging/Variant.cpp
+ qpid/client/amqp0_10/AcceptTracker.h
+ qpid/client/amqp0_10/AcceptTracker.cpp
+ qpid/client/amqp0_10/AddressResolution.h
+ qpid/client/amqp0_10/AddressResolution.cpp
+ qpid/client/amqp0_10/Codecs.cpp
+ qpid/client/amqp0_10/CodecsInternal.h
+ qpid/client/amqp0_10/ConnectionImpl.h
+ qpid/client/amqp0_10/ConnectionImpl.cpp
+ qpid/client/amqp0_10/IncomingMessages.h
+ qpid/client/amqp0_10/IncomingMessages.cpp
+ qpid/client/amqp0_10/MessageSink.h
+ qpid/client/amqp0_10/MessageSource.h
+ qpid/client/amqp0_10/OutgoingMessage.h
+ qpid/client/amqp0_10/OutgoingMessage.cpp
+ qpid/client/amqp0_10/ReceiverImpl.h
+ qpid/client/amqp0_10/ReceiverImpl.cpp
+ qpid/client/amqp0_10/SessionImpl.h
+ qpid/client/amqp0_10/SessionImpl.cpp
+ qpid/client/amqp0_10/SenderImpl.h
+ qpid/client/amqp0_10/SenderImpl.cpp
+)
+
+add_library (qpidclient SHARED ${qpidclient_SOURCES})
+target_link_libraries (qpidclient qpidcommon ${qpidclient_platform_LIBS})
+set_target_properties (qpidclient PROPERTIES VERSION ${qpidc_version})
+install (TARGETS qpidclient
+ DESTINATION ${QPID_INSTALL_LIBDIR}
+ COMPONENT ${QPID_COMPONENT_CLIENT})
+install (DIRECTORY ../include/qpid ${CMAKE_CURRENT_BINARY_DIR}/../include/qpid
+ DESTINATION ${QPID_INSTALL_INCLUDEDIR}
+ COMPONENT ${QPID_COMPONENT_CLIENT_INCLUDE}
+ PATTERN ".svn" EXCLUDE)
+if (WIN32)
+ install (PROGRAMS
+ ${CMAKE_CURRENT_BINARY_DIR}/Debug/qpidclientd.dll
+ ${CMAKE_CURRENT_BINARY_DIR}/Debug/qpidclientd.lib
+ ${CMAKE_CURRENT_BINARY_DIR}/Debug/qpidclientd.pdb
+ DESTINATION ${QPID_INSTALL_LIBDIR}
+ COMPONENT ${QPID_COMPONENT_CLIENT})
+endif (WIN32)
+
+if (WIN32)
+ set(AMQP_WCF_DIR ${qpid-cpp_SOURCE_DIR}/../wcf)
+ set(DTC_PLUGIN_SOURCE ${AMQP_WCF_DIR}/src/Apache/Qpid/DtcPlugin/DtcPlugin.cpp)
+ if (EXISTS ${DTC_PLUGIN_SOURCE})
+ add_library (qpidxarm SHARED ${DTC_PLUGIN_SOURCE})
+ target_link_libraries (qpidxarm qpidclient qpidcommon)
+ endif (EXISTS ${DTC_PLUGIN_SOURCE})
+endif (WIN32)
+
+set (qpidbroker_SOURCES
+ ${mgen_broker_cpp}
+ ${qpidbroker_platform_SOURCES}
+ qpid/amqp_0_10/Connection.h
+ qpid/amqp_0_10/Connection.cpp
+ qpid/broker/Broker.cpp
+ qpid/broker/Exchange.cpp
+ qpid/broker/ExpiryPolicy.cpp
+ qpid/broker/Queue.cpp
+ qpid/broker/QueueCleaner.cpp
+ qpid/broker/QueueListeners.cpp
+ qpid/broker/PersistableMessage.cpp
+ qpid/broker/Bridge.cpp
+ qpid/broker/Connection.cpp
+ qpid/broker/ConnectionHandler.cpp
+ qpid/broker/ConnectionFactory.cpp
+ qpid/broker/DeliverableMessage.cpp
+ qpid/broker/DeliveryRecord.cpp
+ qpid/broker/DirectExchange.cpp
+ qpid/broker/DtxAck.cpp
+ qpid/broker/DtxBuffer.cpp
+ qpid/broker/DtxManager.cpp
+ qpid/broker/DtxTimeout.cpp
+ qpid/broker/DtxWorkRecord.cpp
+ qpid/broker/ExchangeRegistry.cpp
+ qpid/broker/FanOutExchange.cpp
+ qpid/broker/HeadersExchange.cpp
+ qpid/broker/IncompleteMessageList.cpp
+ qpid/broker/Link.cpp
+ qpid/broker/LinkRegistry.cpp
+ qpid/broker/Message.cpp
+ qpid/broker/MessageAdapter.cpp
+ qpid/broker/MessageBuilder.cpp
+ qpid/broker/MessageStoreModule.cpp
+ qpid/broker/NameGenerator.cpp
+ qpid/broker/NullMessageStore.cpp
+ qpid/broker/QueueBindings.cpp
+ qpid/broker/QueueEvents.cpp
+ qpid/broker/QueuePolicy.cpp
+ qpid/broker/QueueRegistry.cpp
+ qpid/broker/RateTracker.cpp
+ qpid/broker/RecoveryManagerImpl.cpp
+ qpid/broker/RecoveredEnqueue.cpp
+ qpid/broker/RecoveredDequeue.cpp
+ qpid/broker/RetryList.cpp
+ qpid/broker/SecureConnection.cpp
+ qpid/broker/SecureConnectionFactory.cpp
+ qpid/broker/SemanticState.h
+ qpid/broker/SemanticState.cpp
+ qpid/broker/SessionAdapter.cpp
+ qpid/broker/SessionState.h
+ qpid/broker/SessionState.cpp
+ qpid/broker/SessionManager.h
+ qpid/broker/SessionManager.cpp
+ qpid/broker/SessionContext.h
+ qpid/broker/SessionHandler.h
+ qpid/broker/SessionHandler.cpp
+ qpid/broker/System.cpp
+ qpid/broker/TopicExchange.cpp
+ qpid/broker/TxAccept.cpp
+ qpid/broker/TxBuffer.cpp
+ qpid/broker/TxPublish.cpp
+ qpid/broker/Vhost.cpp
+ qpid/management/ManagementAgent.cpp
+ qpid/management/ManagementExchange.cpp
+ qpid/sys/TCPIOPlugin.cpp
+)
+add_library (qpidbroker SHARED ${qpidbroker_SOURCES})
+target_link_libraries (qpidbroker qpidcommon ${qpidbroker_platform_LIBS})
+set_target_properties (qpidbroker PROPERTIES VERSION ${qpidc_version})
+if (MSVC)
+ set_target_properties (qpidbroker PROPERTIES COMPILE_FLAGS /wd4290)
+endif (MSVC)
+install (TARGETS qpidbroker
+ DESTINATION ${QPID_INSTALL_LIBDIR}
+ COMPONENT ${QPID_COMPONENT_BROKER})
+
+set (qpidd_SOURCES
+ ${qpidd_platform_SOURCES}
+ qpidd.cpp
+ qpidd.h
+)
+add_executable (qpidd ${qpidd_SOURCES})
+target_link_libraries (qpidd qpidbroker qpidcommon ${Boost_PROGRAM_OPTIONS_LIBRARY}
+ ${Boost_FILESYSTEM_LIBRARY})
+install (TARGETS qpidd RUNTIME
+ DESTINATION ${QPID_INSTALL_BINDIR}
+ COMPONENT ${QPID_COMPONENT_BROKER})
+if (CPACK_GENERATOR STREQUAL "NSIS")
+ set (CPACK_NSIS_MENU_LINKS
+ "qpidd" "Start Qpid Broker")
+endif (CPACK_GENERATOR STREQUAL "NSIS")
+
+# QMF library
+# Library Version Information (CURRENT.REVISION.AGE):
+#
+# CURRENT => API/ABI version. Bump this if the interface changes
+# REVISION => Version of underlying implementation.
+# Bump if implementation changes but API/ABI doesn't
+# AGE => Number of API/ABI versions this is backward compatible with
+set (qmf_version 1.0.0)
+set (qmfengine_version 1.0.0)
+
+set (qmf_SOURCES
+ qpid/agent/ManagementAgentImpl.cpp
+ qpid/agent/ManagementAgentImpl.h
+ )
+add_library (qmf SHARED ${qmf_SOURCES})
+target_link_libraries (qmf qmfengine)
+set_target_properties (qmf PROPERTIES
+ VERSION ${qmf_version})
+install (TARGETS qmf OPTIONAL
+ DESTINATION ${QPID_INSTALL_LIBDIR}
+ COMPONENT ${QPID_COMPONENT_QMF})
+
+set (qmfengine_SOURCES
+ qmf/engine/Agent.cpp
+ qmf/engine/BrokerProxyImpl.cpp
+ qmf/engine/BrokerProxyImpl.h
+ qmf/engine/ConnectionSettingsImpl.cpp
+ qmf/engine/ConnectionSettingsImpl.h
+ qmf/engine/ConsoleImpl.cpp
+ qmf/engine/ConsoleImpl.h
+ qmf/engine/MessageImpl.cpp
+ qmf/engine/MessageImpl.h
+ qmf/engine/ObjectIdImpl.cpp
+ qmf/engine/ObjectIdImpl.h
+ qmf/engine/ObjectImpl.cpp
+ qmf/engine/ObjectImpl.h
+ qmf/engine/Protocol.cpp
+ qmf/engine/Protocol.h
+ qmf/engine/QueryImpl.cpp
+ qmf/engine/QueryImpl.h
+ qmf/engine/ResilientConnection.cpp
+ qmf/engine/SequenceManager.cpp
+ qmf/engine/SequenceManager.h
+ qmf/engine/SchemaImpl.cpp
+ qmf/engine/SchemaImpl.h
+ qmf/engine/ValueImpl.cpp
+ qmf/engine/ValueImpl.h
+ )
+add_library (qmfengine SHARED ${qmfengine_SOURCES})
+target_link_libraries (qmfengine qpidclient)
+set_target_properties (qmfengine PROPERTIES
+ VERSION ${qmfengine_version})
+install (TARGETS qmfengine OPTIONAL
+ DESTINATION ${QPID_INSTALL_LIBDIR}
+ COMPONENT ${QPID_COMPONENT_QMF})
+
+# QMF console library
+#module_hdr += \
+# qpid/console/Agent.h \
+# qpid/console/Broker.h \
+# qpid/console/ClassKey.h \
+# qpid/console/ConsoleImportExport.h \
+# qpid/console/ConsoleListener.h \
+# qpid/console/Event.h \
+# qpid/console/Object.h \
+# qpid/console/ObjectId.h \
+# qpid/console/Package.h \
+# qpid/console/Schema.h \
+# qpid/console/SequenceManager.h \
+# qpid/console/SessionManager.h \
+# qpid/console/Value.h
+set (qmfconsole_SOURCES
+ ../include/qpid/console/Agent.h
+ ../include/qpid/console/Broker.h
+ ../include/qpid/console/ClassKey.h
+ ../include/qpid/console/ConsoleImportExport.h
+ ../include/qpid/console/ConsoleListener.h
+ ../include/qpid/console/Event.h
+ ../include/qpid/console/Object.h
+ ../include/qpid/console/ObjectId.h
+ ../include/qpid/console/Package.h
+ ../include/qpid/console/Schema.h
+ ../include/qpid/console/SequenceManager.h
+ ../include/qpid/console/SessionManager.h
+ ../include/qpid/console/Value.h
+ qpid/console/Agent.cpp
+ qpid/console/Broker.cpp
+ qpid/console/ClassKey.cpp
+ qpid/console/Event.cpp
+ qpid/console/Object.cpp
+ qpid/console/ObjectId.cpp
+ qpid/console/Package.cpp
+ qpid/console/Schema.cpp
+ qpid/console/SequenceManager.cpp
+ qpid/console/SessionManager.cpp
+ qpid/console/Value.cpp
+ )
+add_library (qmfconsole SHARED ${qmfconsole_SOURCES})
+target_link_libraries (qmfconsole qpidclient)
+set_target_properties (qmfconsole PROPERTIES
+ VERSION ${qpidc_version})
+install (TARGETS qmfconsole
+ DESTINATION ${QPID_INSTALL_LIBDIR}
+ COMPONENT ${QPID_COMPONENT_QMF})
+
+# A queue event listener plugin that creates messages on a replication
+# queue corresponding to enqueue and dequeue events:
+add_library (replicating_listener MODULE
+ qpid/replication/constants.h
+ qpid/replication/ReplicatingEventListener.cpp
+ qpid/replication/ReplicatingEventListener.h
+ )
+target_link_libraries (replicating_listener qpidbroker ${Boost_PROGRAM_OPTIONS_LIBRARY})
+set_target_properties (replicating_listener PROPERTIES PREFIX "")
+if (CMAKE_COMPILER_IS_GNUCXX)
+ set_target_properties(replicating_listener PROPERTIES
+ LINK_FLAGS -Wl,--no-undefined)
+endif (CMAKE_COMPILER_IS_GNUCXX)
+install (TARGETS replicating_listener
+ DESTINATION ${QPIDD_MODULE_DIR}
+ COMPONENT ${QPID_COMPONENT_BROKER})
+
+# A custom exchange plugin that allows an exchange to be created that
+# can process the messages from a replication queue (populated on the
+# source system by the replicating listener plugin above) and take the
+# corresponding action on the local queues
+add_library (replication_exchange MODULE
+ qpid/replication/constants.h
+ qpid/replication/ReplicationExchange.cpp
+ qpid/replication/ReplicationExchange.h
+ )
+target_link_libraries (replication_exchange qpidbroker)
+set_target_properties (replication_exchange PROPERTIES PREFIX "")
+if (CMAKE_COMPILER_IS_GNUCXX)
+ set_target_properties(replication_exchange PROPERTIES
+ LINK_FLAGS -Wl,--no-undefined)
+endif (CMAKE_COMPILER_IS_GNUCXX)
+install (TARGETS replication_exchange
+ DESTINATION ${QPIDD_MODULE_DIR}
+ COMPONENT ${QPID_COMPONENT_BROKER})
+
+# This is only really needed until all the trunk builds (Linux, UNIX, Windows)
+# are all on cmake only. This is because cmake builds always have a config.h
+# file whereas older builds only have config.h on autoconf-generated builds.
+add_definitions(-DHAVE_CONFIG_H)
+
+# Now create the config file from all the info learned above.
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+
+add_subdirectory(qpid/store)
+add_subdirectory(tests)
diff --git a/cpp/src/Makefile.am b/cpp/src/Makefile.am
index 172888cfb8..4979aaf926 100644
--- a/cpp/src/Makefile.am
+++ b/cpp/src/Makefile.am
@@ -1,6 +1,63 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
SUBDIRS = . tests
-EXTRA_DIST= $(platform_dist) $(rgen_srcs)
+# The Windows-only sources are not compiled using this Makefile, but
+# are listed here to ensure they're included in releases. They are built
+# using Visual Studio solutions/projects.
+windows_dist = \
+ qpid/client/windows/SaslFactory.cpp \
+ qpid/log/windows/SinkOptions.cpp \
+ qpid/log/windows/SinkOptions.h \
+ ../include/qpid/sys/windows/check.h \
+ qpid/sys/windows/AsynchIO.cpp \
+ qpid/sys/windows/AsynchIoResult.h \
+ ../include/qpid/sys/windows/Condition.h \
+ qpid/sys/windows/FileSysDir.cpp \
+ ../include/qpid/sys/windows/IntegerTypes.h \
+ qpid/sys/windows/IocpPoller.cpp \
+ qpid/sys/windows/IOHandle.cpp \
+ qpid/sys/windows/IoHandlePrivate.h \
+ qpid/sys/windows/LockFile.cpp \
+ qpid/sys/windows/PollableCondition.cpp \
+ qpid/sys/windows/PipeHandle.cpp \
+ ../include/qpid/sys/windows/Mutex.h \
+ qpid/sys/windows/Shlib.cpp \
+ qpid/sys/windows/SocketAddress.cpp \
+ qpid/sys/windows/Socket.cpp \
+ qpid/sys/windows/StrError.cpp \
+ qpid/sys/windows/SystemInfo.cpp \
+ qpid/sys/windows/Thread.cpp \
+ qpid/sys/windows/Time.cpp \
+ ../include/qpid/sys/windows/Time.h \
+ qpid/sys/windows/uuid.cpp \
+ qpid/sys/windows/uuid.h \
+ windows/QpiddBroker.cpp \
+ qpid/broker/windows/BrokerDefaults.cpp \
+ qpid/broker/windows/SaslAuthenticator.cpp
+
+EXTRA_DIST= $(platform_dist) $(rgen_srcs) $(windows_dist)
+
+# Define variables that are be appended to by this file and included .mk files.
+nobase_include_HEADERS =
+libqpidcommon_la_SOURCES =
## Generated code
@@ -19,19 +76,24 @@ specs=$(amqp_0_10_xml) $(top_srcdir)/xml/cluster.xml
# Ruby generator.
rgen_dir=$(top_srcdir)/rubygen
-rgen_cmd=ruby -I $(rgen_dir) $(rgen_dir)/generate gen $(specs) all $(srcdir)/rubygen.mk
+rgen_cmd=ruby -I $(rgen_dir) $(rgen_dir)/generate . ../include $(specs) all
$(rgen_srcs) $(srcdir)/rubygen.mk: rgen.timestamp
rgen.timestamp: $(rgen_generator) $(specs)
- $(rgen_cmd); touch $@
+ $(rgen_cmd) $(srcdir)/rubygen.mk; touch $@
$(rgen_generator):
+# The CMake version is needed for dist
+$(srcdir)/rubygen.cmake: $(rgen_generator) $(specs)
+ $(rgen_cmd) $(srcdir)/rubygen.cmake
+
# Management generator.
mgen_dir=$(top_srcdir)/managementgen
-mgen_cmd=$(mgen_dir)/main.py -m $(srcdir)/managementgen.mk \
+mgen_cmd=$(mgen_dir)/qmf-gen -m $(srcdir)/managementgen.mk \
+ -c $(srcdir)/managementgen.cmake -q -b -o qmf \
$(top_srcdir)/../specs/management-schema.xml \
- $(top_srcdir)/../specs/management-types.xml \
- $(mgen_dir)/templates gen/qpid/management
+ $(srcdir)/qpid/acl/management-schema.xml \
+ $(srcdir)/qpid/cluster/management-schema.xml
$(srcdir)/managementgen.mk $(mgen_broker_cpp) $(dist_qpid_management_HEADERS): mgen.timestamp
mgen.timestamp: $(mgen_generator)
@@ -43,47 +105,67 @@ endif # GENERATE
include $(srcdir)/rubygen.mk
include $(srcdir)/managementgen.mk
-# Code generated by C++
-noinst_PROGRAMS=generate_MaxMethodBodySize_h
-generate_MaxMethodBodySize_h_SOURCES=gen/generate_MaxMethodBodySize_h.cpp
-qpid/framing/MaxMethodBodySize.h: generate_MaxMethodBodySize_h
- ./generate_MaxMethodBodySize_h
-BUILT_SOURCES=qpid/framing/MaxMethodBodySize.h
-DISTCLEANFILES=qpid/framing/MaxMethodBodySize.h
-
## Compiler flags
-
AM_CXXFLAGS = $(WARNING_CFLAGS)
AM_LDFLAGS = -version-info $(LIBTOOL_VERSION_INFO_ARG)
-INCLUDES = -Igen -I$(srcdir)/gen
+INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(srcdir) -I=$(builddir)
+
+#
+# Destination for intalled programs and tests defined here
+#
+qpidexecdir = $(libexecdir)/qpid
+AM_CXXFLAGS += -DQPID_EXEC_DIR=\"$(qpidexecdir)\"
+qpidexec_PROGRAMS =
+qpidexec_SCRIPTS =
+qpidtestdir = $(qpidexecdir)/tests
+qpidtest_PROGRAMS =
+qpidtest_SCRIPTS =
+tmoduledir = $(libdir)/qpid/tests
+tmodule_LTLIBRARIES=
## Automake macros to build libraries and executables.
+qpidd_CXXFLAGS = $(AM_CXXFLAGS) -DQPIDD_MODULE_DIR=\"$(dmoduledir)\" -DQPIDD_CONF_FILE=\"$(sysconfdir)/qpidd.conf\"
+libqpidclient_la_CXXFLAGS = $(AM_CXXFLAGS) -DQPIDC_MODULE_DIR=\"$(cmoduledir)\" -DQPIDC_CONF_FILE=\"$(confdir)/qpidc.conf\"
qpidd_LDADD = \
libqpidbroker.la \
libqpidcommon.la
+posix_qpidd_src = posix/QpiddBroker.cpp
+
sbin_PROGRAMS = qpidd
-qpidd_SOURCES = qpidd.cpp
-
-posix_plat_src = \
- qpid/sys/posix/IOHandle.cpp \
- qpid/sys/posix/Socket.cpp \
- qpid/sys/posix/AsynchIO.cpp \
- qpid/sys/posix/Time.cpp \
- qpid/sys/posix/Thread.cpp \
- qpid/sys/posix/Shlib.cpp \
- qpid/sys/posix/Mutex.cpp \
- qpid/sys/posix/Fork.cpp \
- qpid/sys/posix/StrError.cpp
-
-posix_plat_hdr = \
- qpid/sys/posix/check.h \
- qpid/sys/posix/Condition.h \
- qpid/sys/posix/PrivatePosix.h \
- qpid/sys/posix/Mutex.h \
- qpid/sys/posix/Fork.h \
- qpid/sys/posix/LockFile.h
+qpidd_SOURCES = qpidd.cpp qpidd.h $(posix_qpidd_src)
+
+## Platform specific code.
+
+# Posix-specific code
+libqpidcommon_la_SOURCES += \
+ qpid/log/posix/SinkOptions.cpp \
+ qpid/sys/posix/IOHandle.cpp \
+ qpid/sys/posix/Socket.cpp \
+ qpid/sys/posix/SocketAddress.cpp \
+ qpid/sys/posix/AsynchIO.cpp \
+ qpid/sys/posix/FileSysDir.cpp \
+ qpid/sys/posix/LockFile.cpp \
+ qpid/sys/posix/Time.cpp \
+ qpid/sys/posix/Thread.cpp \
+ qpid/sys/posix/Shlib.cpp \
+ qpid/sys/posix/Mutex.cpp \
+ qpid/sys/posix/Fork.cpp \
+ qpid/sys/posix/StrError.cpp \
+ qpid/sys/posix/PollableCondition.cpp \
+ qpid/sys/posix/PidFile.h \
+ qpid/sys/posix/PipeHandle.cpp \
+ qpid/log/posix/SinkOptions.h \
+ qpid/sys/posix/Fork.h
+
+nobase_include_HEADERS += \
+ ../include/qpid/sys/posix/Condition.h \
+ ../include/qpid/sys/posix/IntegerTypes.h \
+ ../include/qpid/sys/posix/Mutex.h \
+ ../include/qpid/sys/posix/PrivatePosix.h \
+ ../include/qpid/sys/posix/Time.h \
+ ../include/qpid/sys/posix/check.h
if HAVE_EPOLL
poller = qpid/sys/epoll/EpollPoller.cpp
@@ -93,59 +175,107 @@ if HAVE_ECF
poller = qpid/sys/solaris/ECFPoller.cpp
endif
-platform_src = $(posix_plat_src) $(poller)
-platform_hdr = $(posix_plat_hdr)
+if SUNOS
+ systeminfo = qpid/sys/solaris/SystemInfo.cpp
+else
+ systeminfo = qpid/sys/posix/SystemInfo.cpp
+endif
+
+libqpidcommon_la_SOURCES += $(poller) $(systeminfo)
-lib_LTLIBRARIES = libqpidcommon.la libqpidbroker.la libqpidclient.la
+posix_broker_src = \
+ qpid/broker/posix/BrokerDefaults.cpp
+
+lib_LTLIBRARIES = libqpidcommon.la libqpidbroker.la libqpidclient.la
+
+# Definitions for client and daemon plugins
+PLUGINLDFLAGS=-no-undefined -module -avoid-version
+confdir=$(sysconfdir)/qpid
+dmoduledir=$(libdir)/qpid/daemon
+cmoduledir=$(libdir)/qpid/client
+dmodule_LTLIBRARIES =
+cmodule_LTLIBRARIES =
include cluster.mk
include acl.mk
-
-# The logger library uses boost::date_time to format time.
-# We have to disable the unused parameters warning to get around
-# unused parameters in boost::date_time headers. So we build it
-# in a convenience library to link into libqpid_common.
-#
-noinst_LTLIBRARIES=libLogger.la # libqpidamqp_0_10.la
-libLogger_la_SOURCES=qpid/log/Logger.cpp qpid/log/Logger.h
-libLogger_la_CXXFLAGS=$(AM_CXXFLAGS) -Wno-unused-parameter
+include qmf.mk
+include qmfc.mk
+if HAVE_XML
+include xml.mk
+endif
+include replication.mk
if RDMA
# RDMA (Infiniband) protocol code
-libqpidrdma_la_SOURCES = \
+librdmawrap_la_SOURCES = \
qpid/sys/rdma/rdma_exception.h \
qpid/sys/rdma/rdma_factories.cpp \
+ qpid/sys/rdma/rdma_factories.h \
qpid/sys/rdma/RdmaIO.cpp \
qpid/sys/rdma/RdmaIO.h \
+ qpid/sys/rdma/rdma_wrap.cpp \
qpid/sys/rdma/rdma_wrap.h
-libqpidrdma_la_LIBADD = \
+librdmawrap_la_LIBADD = \
+ libqpidcommon.la \
-lrdmacm \
-libverbs
-libqpidrdma_la_CXXFLAGS = \
+librdmawrap_la_CXXFLAGS = \
+ $(AM_CXXFLAGS) -Wno-missing-field-initializers
+lib_LTLIBRARIES += \
+ librdmawrap.la
+librdmawrap_la_LDFLAGS = \
+ -no-undefined
+
+rdma_la_SOURCES = \
+ qpid/sys/RdmaIOPlugin.cpp
+rdma_la_LIBADD = \
+ libqpidbroker.la \
+ librdmawrap.la
+rdma_la_LDFLAGS = $(PLUGINLDFLAGS)
+rdma_la_CXXFLAGS = \
$(AM_CXXFLAGS) -Wno-missing-field-initializers
-noinst_LTLIBRARIES += \
- libqpidrdma.la
-qpidd_LDADD += \
- libqpidrdma.la
+dmodule_LTLIBRARIES += \
+ rdma.la
+
+rdmaconnector_la_SOURCES = \
+ qpid/client/RdmaConnector.cpp
+rdmaconnector_la_LIBADD = \
+ libqpidclient.la \
+ librdmawrap.la
+rdmaconnector_la_LDFLAGS = $(PLUGINLDFLAGS)
+rdmaconnector_la_CXXFLAGS = \
+ $(AM_CXXFLAGS) -Wno-missing-field-initializers
+cmodule_LTLIBRARIES += \
+ rdmaconnector.la
-noinst_PROGRAMS += RdmaServer RdmaClient
+# RDMA test/sample programs
+noinst_PROGRAMS = RdmaServer RdmaClient
RdmaServer_SOURCES = qpid/sys/rdma/RdmaServer.cpp
-RdmaServer_CXXFLAGS = \
- $(AM_CXXFLAGS) -Wno-missing-field-initializers
RdmaServer_LDADD = \
- libqpidrdma.la libqpidcommon.la
+ librdmawrap.la libqpidcommon.la
RdmaClient_SOURCES = qpid/sys/rdma/RdmaClient.cpp
RdmaClient_CXXFLAGS = \
$(AM_CXXFLAGS) -Wno-missing-field-initializers
RdmaClient_LDADD = \
- libqpidrdma.la libqpidcommon.la
+ librdmawrap.la libqpidcommon.la
+
+endif
+if SSL
+include ssl.mk
endif
# New 0-10 codec, to be integrated in future.
# libqpidamqp_0_10_la_SOURCES=
EXTRA_DIST +=\
+ CMakeLists.txt \
+ cluster.cmake \
+ config.h.cmake \
+ rdma.cmake \
+ ssl.cmake \
+ managementgen.cmake \
+ rubygen.cmake \
$(rgen_amqp_0_10_srcs) \
qpid/amqp_0_10/apply.h \
qpid/amqp_0_10/built_in_types.h \
@@ -176,405 +306,514 @@ EXTRA_DIST +=\
qpid/amqp_0_10/UnknownType.h \
qpid/amqp_0_10/UnknownType.cpp \
qpid/amqp_0_10/UnknownStruct.h \
- qpid/amqp_0_10/UnknownStruct.cpp
+ qpid/amqp_0_10/UnknownStruct.cpp \
+ qpid/store
libqpidcommon_la_LIBADD = \
-lboost_program_options \
-lboost_filesystem \
-luuid \
- libLogger.la \
$(LIB_DLOPEN) \
$(LIB_CLOCK_GETTIME)
-libqpidcommon_la_SOURCES = \
- $(rgen_framing_srcs) \
- $(platform_src) \
- qpid/amqp_0_10/SessionHandler.h \
- qpid/amqp_0_10/SessionHandler.cpp \
- qpid/Serializer.h \
- qpid/SessionState.h \
- qpid/SessionState.cpp \
- qpid/SessionId.cpp \
- qpid/framing/AccumulatedAck.cpp \
- qpid/framing/AMQBody.cpp \
- qpid/framing/AMQMethodBody.cpp \
- qpid/framing/AMQContentBody.cpp \
- qpid/framing/AMQFrame.cpp \
- qpid/framing/AMQHeaderBody.cpp \
- qpid/framing/AMQHeartbeatBody.cpp \
- qpid/framing/Array.cpp \
- qpid/framing/BodyHolder.cpp \
- qpid/framing/BodyHandler.cpp \
- qpid/framing/Buffer.cpp \
- qpid/framing/FieldTable.cpp \
- qpid/framing/FieldValue.cpp \
- qpid/framing/FrameSet.cpp \
- qpid/framing/ProtocolInitiation.cpp \
- qpid/framing/ProtocolVersion.cpp \
- qpid/framing/SendContent.cpp \
- qpid/framing/SequenceNumber.cpp \
- qpid/framing/SequenceNumberSet.cpp \
- qpid/framing/SequenceSet.cpp \
- qpid/framing/Proxy.cpp \
- qpid/framing/Uuid.cpp \
- qpid/framing/AMQP_HighestVersion.h \
- qpid/framing/Blob.cpp \
- qpid/framing/MaxMethodBodySize.h \
- qpid/framing/TransferContent.cpp \
- qpid/assert.cpp qpid/assert.h \
- qpid/Exception.cpp \
- qpid/Plugin.cpp \
- qpid/StringUtils.cpp \
- qpid/Url.cpp \
- qpid/management/Manageable.cpp \
- qpid/management/ManagementObject.cpp \
- qpid/sys/AggregateOutput.cpp \
- qpid/sys/AsynchIOHandler.cpp \
- qpid/sys/Dispatcher.cpp \
- qpid/sys/Runnable.cpp \
- qpid/sys/SystemInfo.cpp \
- qpid/sys/Shlib.cpp \
- qpid/DataDir.cpp \
- qpid/Options.cpp \
- qpid/log/Options.cpp \
- qpid/log/Selector.cpp \
- qpid/log/Statement.cpp \
- qpid/pointer_to_other.h
+libqpidcommon_la_SOURCES += \
+ $(rgen_framing_srcs) \
+ $(platform_src) \
+ qpid/Address.cpp \
+ qpid/DataDir.cpp \
+ qpid/DataDir.h \
+ qpid/Exception.cpp \
+ qpid/Modules.cpp \
+ qpid/Modules.h \
+ qpid/Options.cpp \
+ qpid/Plugin.cpp \
+ qpid/Plugin.h \
+ qpid/RefCounted.h \
+ qpid/RefCountedBuffer.cpp \
+ qpid/RefCountedBuffer.h \
+ qpid/Serializer.h \
+ qpid/SessionId.cpp \
+ qpid/SessionState.cpp \
+ qpid/SessionState.h \
+ qpid/SessionState.h \
+ qpid/SharedObject.h \
+ qpid/StringUtils.cpp \
+ qpid/StringUtils.h \
+ qpid/Url.cpp \
+ qpid/Version.h \
+ qpid/amqp_0_10/Exception.h \
+ qpid/amqp_0_10/SessionHandler.cpp \
+ qpid/amqp_0_10/SessionHandler.h \
+ qpid/amqp_0_10/apply.h \
+ qpid/assert.cpp qpid/assert.h \
+ qpid/assert.h \
+ qpid/framing/AMQBody.cpp \
+ qpid/framing/AMQBody.h \
+ qpid/framing/AMQCommandControlBody.h \
+ qpid/framing/AMQContentBody.cpp \
+ qpid/framing/AMQContentBody.h \
+ qpid/framing/AMQDataBlock.h \
+ qpid/framing/AMQFrame.cpp \
+ qpid/framing/AMQFrame.h \
+ qpid/framing/AMQHeaderBody.cpp \
+ qpid/framing/AMQHeaderBody.h \
+ qpid/framing/AMQHeartbeatBody.cpp \
+ qpid/framing/AMQHeartbeatBody.h \
+ qpid/framing/AMQMethodBody.cpp \
+ qpid/framing/AMQMethodBody.h \
+ qpid/framing/AMQP_HighestVersion.h \
+ qpid/framing/AMQP_HighestVersion.h \
+ qpid/framing/AccumulatedAck.cpp \
+ qpid/framing/AccumulatedAck.h \
+ qpid/framing/Array.cpp \
+ qpid/framing/BodyFactory.h \
+ qpid/framing/BodyHandler.cpp \
+ qpid/framing/BodyHandler.h \
+ qpid/framing/Buffer.cpp \
+ qpid/framing/ChannelHandler.h \
+ qpid/framing/Endian.cpp \
+ qpid/framing/Endian.h \
+ qpid/framing/FieldTable.cpp \
+ qpid/framing/FieldValue.cpp \
+ qpid/framing/FrameDecoder.cpp \
+ qpid/framing/FrameDecoder.h \
+ qpid/framing/FrameDefaultVisitor.h \
+ qpid/framing/FrameHandler.h \
+ qpid/framing/FrameSet.cpp \
+ qpid/framing/FrameSet.h \
+ qpid/framing/Handler.h \
+ qpid/framing/HeaderProperties.h \
+ qpid/framing/InitiationHandler.h \
+ qpid/framing/InputHandler.h \
+ qpid/framing/Invoker.h \
+ qpid/framing/IsInSequenceSet.h \
+ qpid/framing/List.cpp \
+ qpid/framing/MethodBodyFactory.h \
+ qpid/framing/MethodContent.h \
+ qpid/framing/ModelMethod.h \
+ qpid/framing/OutputHandler.h \
+ qpid/framing/ProtocolInitiation.cpp \
+ qpid/framing/ProtocolInitiation.h \
+ qpid/framing/ProtocolVersion.cpp \
+ qpid/framing/Proxy.cpp \
+ qpid/framing/Proxy.h \
+ qpid/framing/SendContent.cpp \
+ qpid/framing/SendContent.h \
+ qpid/framing/SequenceNumber.cpp \
+ qpid/framing/SequenceNumberSet.cpp \
+ qpid/framing/SequenceNumberSet.h \
+ qpid/framing/SequenceSet.cpp \
+ qpid/framing/TransferContent.cpp \
+ qpid/framing/TransferContent.h \
+ qpid/framing/TypeFilter.h \
+ qpid/framing/Uuid.cpp \
+ qpid/framing/Visitor.h \
+ qpid/framing/amqp_framing.h \
+ qpid/framing/frame_functors.h \
+ qpid/framing/variant.h \
+ qpid/log/Helpers.h \
+ qpid/log/Logger.cpp \
+ qpid/log/Options.cpp \
+ qpid/log/OstreamOutput.cpp \
+ qpid/log/OstreamOutput.h \
+ qpid/log/Selector.cpp \
+ qpid/log/Statement.cpp \
+ qpid/management/Manageable.cpp \
+ qpid/management/ManagementObject.cpp \
+ qpid/memory.h \
+ qpid/pointer_to_other.h \
+ qpid/ptr_map.h \
+ qpid/sys/AggregateOutput.cpp \
+ qpid/sys/AggregateOutput.h \
+ qpid/sys/AsynchIO.h \
+ qpid/sys/AsynchIOHandler.cpp \
+ qpid/sys/AsynchIOHandler.h \
+ qpid/sys/AtomicCount.h \
+ qpid/sys/AtomicValue.h \
+ qpid/sys/AtomicValue_gcc.h \
+ qpid/sys/AtomicValue_mutex.h \
+ qpid/sys/BlockingQueue.h \
+ qpid/sys/Codec.h \
+ qpid/sys/ConnectionCodec.h \
+ qpid/sys/ConnectionInputHandler.h \
+ qpid/sys/ConnectionInputHandlerFactory.h \
+ qpid/sys/ConnectionOutputHandler.h \
+ qpid/sys/ConnectionOutputHandlerPtr.h \
+ qpid/sys/CopyOnWriteArray.h \
+ qpid/sys/DeletionManager.h \
+ qpid/sys/DispatchHandle.cpp \
+ qpid/sys/DispatchHandle.h \
+ qpid/sys/Dispatcher.cpp \
+ qpid/sys/Dispatcher.h \
+ qpid/sys/FileSysDir.h \
+ qpid/sys/Fork.h \
+ qpid/sys/LockFile.h \
+ qpid/sys/LockPtr.h \
+ qpid/sys/OutputControl.h \
+ qpid/sys/OutputTask.h \
+ qpid/sys/PipeHandle.h \
+ qpid/sys/PollableCondition.h \
+ qpid/sys/PollableQueue.h \
+ qpid/sys/Poller.h \
+ qpid/sys/ProtocolFactory.h \
+ qpid/sys/Runnable.cpp \
+ qpid/sys/ScopedIncrement.h \
+ qpid/sys/SecurityLayer.h \
+ qpid/sys/Semaphore.h \
+ qpid/sys/Shlib.cpp \
+ qpid/sys/Shlib.h \
+ qpid/sys/ShutdownHandler.h \
+ qpid/sys/Socket.h \
+ qpid/sys/SocketAddress.h \
+ qpid/sys/StateMonitor.h \
+ qpid/sys/TimeoutHandler.h \
+ qpid/sys/Timer.cpp \
+ qpid/sys/Timer.h \
+ qpid/sys/Waitable.h \
+ qpid/sys/alloca.h \
+ qpid/sys/uuid.h
-libqpidbroker_la_LIBADD = libqpidcommon.la -luuid
-if HAVE_XML
-libqpidbroker_la_LIBADD += -lxerces-c -lxqilla
-endif
if HAVE_SASL
-libqpidbroker_la_LIBADD += -lsasl2
+libqpidcommon_la_SOURCES += qpid/sys/cyrus/CyrusSecurityLayer.h
+libqpidcommon_la_SOURCES += qpid/sys/cyrus/CyrusSecurityLayer.cpp
+libqpidcommon_la_LIBADD += -lsasl2
endif
+libqpidbroker_la_LIBADD = libqpidcommon.la -luuid
+
libqpidbroker_la_SOURCES = \
$(mgen_broker_cpp) \
- qpid/amqp_0_10/Connection.h \
+ $(posix_broker_src) \
qpid/amqp_0_10/Connection.cpp \
- qpid/broker/Broker.cpp \
- qpid/broker/BrokerSingleton.cpp \
- qpid/broker/Exchange.cpp \
- qpid/broker/Queue.cpp \
- qpid/broker/PersistableMessage.cpp \
+ qpid/amqp_0_10/Connection.h \
+ qpid/broker/AclModule.h \
qpid/broker/Bridge.cpp \
+ qpid/broker/Bridge.h \
+ qpid/broker/Broker.cpp \
+ qpid/broker/Broker.h \
+ qpid/broker/BrokerImportExport.h \
qpid/broker/Connection.cpp \
- qpid/broker/ConnectionHandler.cpp \
+ qpid/broker/Connection.h \
qpid/broker/ConnectionFactory.cpp \
+ qpid/broker/ConnectionFactory.h \
+ qpid/broker/ConnectionHandler.cpp \
+ qpid/broker/ConnectionHandler.h \
+ qpid/broker/ConnectionState.h \
+ qpid/broker/ConnectionToken.h \
+ qpid/broker/Consumer.h \
qpid/broker/Daemon.cpp \
+ qpid/broker/Daemon.h \
+ qpid/broker/Deliverable.h \
qpid/broker/DeliverableMessage.cpp \
+ qpid/broker/DeliverableMessage.h \
+ qpid/broker/DeliveryAdapter.h \
+ qpid/broker/DeliveryId.h \
qpid/broker/DeliveryRecord.cpp \
+ qpid/broker/DeliveryRecord.h \
qpid/broker/DirectExchange.cpp \
+ qpid/broker/DirectExchange.h \
qpid/broker/DtxAck.cpp \
+ qpid/broker/DtxAck.h \
qpid/broker/DtxBuffer.cpp \
+ qpid/broker/DtxBuffer.h \
qpid/broker/DtxManager.cpp \
+ qpid/broker/DtxManager.h \
qpid/broker/DtxTimeout.cpp \
+ qpid/broker/DtxTimeout.h \
qpid/broker/DtxWorkRecord.cpp \
+ qpid/broker/DtxWorkRecord.h \
+ qpid/broker/Exchange.cpp \
+ qpid/broker/Exchange.h \
qpid/broker/ExchangeRegistry.cpp \
+ qpid/broker/ExchangeRegistry.h \
+ qpid/broker/ExpiryPolicy.cpp \
+ qpid/broker/ExpiryPolicy.h \
qpid/broker/FanOutExchange.cpp \
+ qpid/broker/FanOutExchange.h \
+ qpid/broker/HandlerImpl.h \
qpid/broker/HeadersExchange.cpp \
- qpid/broker/IncomingExecutionContext.cpp \
+ qpid/broker/HeadersExchange.h \
qpid/broker/IncompleteMessageList.cpp \
+ qpid/broker/IncompleteMessageList.h \
qpid/broker/Link.cpp \
+ qpid/broker/Link.h \
qpid/broker/LinkRegistry.cpp \
+ qpid/broker/LinkRegistry.h \
qpid/broker/Message.cpp \
+ qpid/broker/Message.h \
qpid/broker/MessageAdapter.cpp \
+ qpid/broker/MessageAdapter.h \
qpid/broker/MessageBuilder.cpp \
- qpid/broker/MessageDelivery.cpp \
+ qpid/broker/MessageBuilder.h \
+ qpid/broker/MessageStore.h \
qpid/broker/MessageStoreModule.cpp \
+ qpid/broker/MessageStoreModule.h \
qpid/broker/NameGenerator.cpp \
+ qpid/broker/NameGenerator.h \
qpid/broker/NullMessageStore.cpp \
+ qpid/broker/NullMessageStore.h \
+ qpid/broker/OwnershipToken.h \
+ qpid/broker/Persistable.h \
+ qpid/broker/PersistableConfig.h \
+ qpid/broker/PersistableExchange.h \
+ qpid/broker/PersistableMessage.cpp \
+ qpid/broker/PersistableMessage.h \
+ qpid/broker/PersistableQueue.h \
+ qpid/broker/Queue.cpp \
+ qpid/broker/Queue.h \
qpid/broker/QueueBindings.cpp \
+ qpid/broker/QueueBindings.h \
+ qpid/broker/QueueCleaner.cpp \
+ qpid/broker/QueueCleaner.h \
+ qpid/broker/QueueEvents.cpp \
+ qpid/broker/QueueEvents.h \
+ qpid/broker/QueueListeners.cpp \
+ qpid/broker/QueueListeners.h \
qpid/broker/QueuePolicy.cpp \
+ qpid/broker/QueuePolicy.h \
qpid/broker/QueueRegistry.cpp \
- qpid/broker/RecoveryManagerImpl.cpp \
- qpid/broker/RecoveredEnqueue.cpp \
+ qpid/broker/QueueRegistry.h \
+ qpid/broker/QueuedMessage.h \
+ qpid/broker/RateFlowcontrol.h \
+ qpid/broker/RateTracker.cpp \
+ qpid/broker/RateTracker.h \
+ qpid/broker/RecoverableConfig.h \
+ qpid/broker/RecoverableExchange.h \
+ qpid/broker/RecoverableMessage.h \
+ qpid/broker/RecoverableQueue.h \
+ qpid/broker/RecoverableTransaction.h \
qpid/broker/RecoveredDequeue.cpp \
+ qpid/broker/RecoveredDequeue.h \
+ qpid/broker/RecoveredEnqueue.cpp \
+ qpid/broker/RecoveredEnqueue.h \
+ qpid/broker/RecoveryManager.h \
+ qpid/broker/RecoveryManagerImpl.cpp \
+ qpid/broker/RecoveryManagerImpl.h \
+ qpid/broker/RetryList.cpp \
+ qpid/broker/RetryList.h \
qpid/broker/SaslAuthenticator.cpp \
- qpid/broker/SemanticState.h \
+ qpid/broker/SaslAuthenticator.h \
+ qpid/broker/SecureConnection.cpp \
+ qpid/broker/SecureConnection.h \
+ qpid/broker/SecureConnectionFactory.cpp \
+ qpid/broker/SecureConnectionFactory.h \
qpid/broker/SemanticState.cpp \
+ qpid/broker/SemanticState.h \
qpid/broker/SessionAdapter.cpp \
- qpid/broker/SessionState.h \
- qpid/broker/SessionState.cpp \
- qpid/broker/SessionManager.h \
- qpid/broker/SessionManager.cpp \
+ qpid/broker/SessionAdapter.h \
+ qpid/broker/SessionAdapter.h \
qpid/broker/SessionContext.h \
- qpid/broker/SessionHandler.h \
qpid/broker/SessionHandler.cpp \
- qpid/broker/SignalHandler.h \
+ qpid/broker/SessionHandler.h \
+ qpid/broker/SessionManager.cpp \
+ qpid/broker/SessionManager.h \
+ qpid/broker/SessionManager.h \
+ qpid/broker/SessionState.cpp \
+ qpid/broker/SessionState.h \
qpid/broker/SignalHandler.cpp \
+ qpid/broker/SignalHandler.h \
qpid/broker/System.cpp \
- qpid/broker/Timer.cpp \
+ qpid/broker/System.h \
qpid/broker/TopicExchange.cpp \
+ qpid/broker/TopicExchange.h \
+ qpid/broker/TransactionalStore.h \
qpid/broker/TxAccept.cpp \
+ qpid/broker/TxAccept.h \
qpid/broker/TxBuffer.cpp \
+ qpid/broker/TxBuffer.h \
+ qpid/broker/TxOp.h \
+ qpid/broker/TxOpVisitor.h \
qpid/broker/TxPublish.cpp \
+ qpid/broker/TxPublish.h \
qpid/broker/Vhost.cpp \
- qpid/management/ManagementBroker.cpp \
+ qpid/broker/Vhost.h \
+ qpid/management/IdAllocator.h \
+ qpid/management/ManagementAgent.cpp \
+ qpid/management/ManagementAgent.h \
qpid/management/ManagementExchange.cpp \
+ qpid/management/ManagementExchange.h \
qpid/sys/TCPIOPlugin.cpp
-if HAVE_XML
-libqpidbroker_la_SOURCES += qpid/broker/XmlExchange.cpp
-endif
-
libqpidclient_la_LIBADD = libqpidcommon.la -luuid
libqpidclient_la_SOURCES = \
$(rgen_client_srcs) \
- qpid/agent/ManagementAgentImpl.cpp \
- qpid/client/AckPolicy.cpp \
qpid/client/Bounds.cpp \
- qpid/client/ConnectionImpl.cpp \
- qpid/client/Connector.cpp \
+ qpid/client/Bounds.h \
+ qpid/client/ChainableFrameHandler.h \
+ qpid/client/Completion.cpp \
+ qpid/client/CompletionImpl.h \
qpid/client/Connection.cpp \
+ qpid/client/ConnectionAccess.h \
qpid/client/ConnectionHandler.cpp \
+ qpid/client/ConnectionHandler.h \
+ qpid/client/ConnectionImpl.cpp \
+ qpid/client/ConnectionImpl.h \
qpid/client/ConnectionSettings.cpp \
+ qpid/client/Connector.cpp \
+ qpid/client/Connector.h \
qpid/client/Demux.cpp \
+ qpid/client/Demux.h \
qpid/client/Dispatcher.cpp \
+ qpid/client/Dispatcher.h \
+ qpid/client/Execution.h \
+ qpid/client/FailoverListener.cpp \
+ qpid/client/FailoverManager.cpp \
qpid/client/Future.cpp \
qpid/client/FutureCompletion.cpp \
qpid/client/FutureResult.cpp \
+ qpid/client/LoadPlugins.cpp \
qpid/client/LocalQueue.cpp \
+ qpid/client/LocalQueueImpl.cpp \
+ qpid/client/LocalQueueImpl.h \
qpid/client/Message.cpp \
+ qpid/client/MessageImpl.cpp \
+ qpid/client/MessageImpl.h \
qpid/client/MessageListener.cpp \
+ qpid/client/MessageReplayTracker.cpp \
+ qpid/client/PrivateImplRef.h \
+ qpid/client/QueueOptions.cpp \
qpid/client/Results.cpp \
+ qpid/client/Results.h \
+ qpid/client/Sasl.h \
+ qpid/client/SaslFactory.cpp \
+ qpid/client/SaslFactory.h \
qpid/client/SessionBase_0_10.cpp \
- qpid/client/SessionBase_0_10.h \
qpid/client/SessionBase_0_10Access.h \
qpid/client/SessionImpl.cpp \
+ qpid/client/SessionImpl.h \
qpid/client/StateManager.cpp \
- qpid/client/SubscriptionManager.cpp
-
-nobase_include_HEADERS = \
- $(platform_hdr) \
- qpid/amqp_0_10/apply.h \
- qpid/assert.h \
- qpid/DataDir.h \
- qpid/Exception.h \
- qpid/sys/ExceptionHolder.h \
- qpid/amqp_0_10/Exception.h \
- qpid/Msg.h \
- qpid/Options.h \
- qpid/Plugin.h \
- qpid/ptr_map.h \
- qpid/RangeSet.h \
- qpid/RefCounted.h \
- qpid/SessionId.h \
- qpid/SessionState.h \
- qpid/SharedObject.h \
- qpid/StringUtils.h \
- qpid/Url.h \
- qpid/InlineVector.h \
- qpid/InlineAllocator.h \
- qpid/memory.h \
- qpid/shared_ptr.h \
- qpid/agent/ManagementAgent.h \
- qpid/agent/ManagementAgentImpl.h \
- qpid/broker/Broker.h \
- qpid/broker/AclModule.h \
- qpid/broker/SessionAdapter.h \
- qpid/broker/Exchange.h \
- qpid/broker/Queue.h \
- qpid/broker/BrokerSingleton.h \
- qpid/broker/Bridge.h \
- qpid/broker/Connection.h \
- qpid/broker/ConnectionState.h \
- qpid/broker/ConnectionFactory.h \
- qpid/broker/ConnectionHandler.h \
- qpid/broker/ConnectionToken.h \
- qpid/broker/OwnershipToken.h \
- qpid/broker/Consumer.h \
- qpid/broker/Daemon.h \
- qpid/broker/Deliverable.h \
- qpid/broker/DeliverableMessage.h \
- qpid/broker/DeliveryAdapter.h \
- qpid/broker/DeliveryId.h \
- qpid/broker/DeliveryRecord.h \
- qpid/broker/DeliveryToken.h \
- qpid/broker/DirectExchange.h \
- qpid/broker/DtxAck.h \
- qpid/broker/DtxBuffer.h \
- qpid/broker/DtxManager.h \
- qpid/broker/DtxTimeout.h \
- qpid/broker/DtxWorkRecord.h \
- qpid/broker/ExchangeRegistry.h \
- qpid/broker/FanOutExchange.h \
- qpid/broker/HandlerImpl.h \
- qpid/broker/HeadersExchange.h \
- qpid/broker/IncomingExecutionContext.h \
- qpid/broker/IncompleteMessageList.h \
- qpid/broker/Link.h \
- qpid/broker/LinkRegistry.h \
- qpid/broker/Message.h \
- qpid/broker/MessageAdapter.h \
- qpid/broker/MessageBuilder.h \
- qpid/broker/MessageDelivery.h \
- qpid/broker/MessageStore.h \
- qpid/broker/MessageStoreModule.h \
- qpid/broker/NameGenerator.h \
- qpid/broker/NullMessageStore.h \
- qpid/broker/Persistable.h \
- qpid/broker/PersistableConfig.h \
- qpid/broker/PersistableExchange.h \
- qpid/broker/PersistableMessage.h \
- qpid/broker/PersistableQueue.h \
- qpid/broker/Prefetch.h \
- qpid/broker/QueueBindings.h \
- qpid/broker/QueuePolicy.h \
- qpid/broker/QueueRegistry.h \
- qpid/broker/RecoverableConfig.h \
- qpid/broker/RecoverableExchange.h \
- qpid/broker/RecoverableMessage.h \
- qpid/broker/RecoverableQueue.h \
- qpid/broker/RecoverableTransaction.h \
- qpid/broker/RecoveredDequeue.h \
- qpid/broker/RecoveredEnqueue.h \
- qpid/broker/RecoveryManager.h \
- qpid/broker/RecoveryManagerImpl.h \
- qpid/broker/SaslAuthenticator.h \
- qpid/broker/SessionAdapter.h \
- qpid/broker/SessionManager.h \
- qpid/broker/System.h \
- qpid/broker/Timer.h \
- qpid/broker/TopicExchange.h \
- qpid/broker/TransactionalStore.h \
- qpid/broker/TxAccept.h \
- qpid/broker/TxBuffer.h \
- qpid/broker/TxOp.h \
- qpid/broker/TxPublish.h \
- qpid/broker/Vhost.h \
- qpid/client/AckMode.h \
- qpid/client/AckPolicy.h \
- qpid/client/Bounds.h \
- qpid/client/ChainableFrameHandler.h \
- qpid/client/Completion.h \
- qpid/client/Connection.h \
- qpid/client/ConnectionHandler.h \
- qpid/client/ConnectionImpl.h \
- qpid/client/ConnectionSettings.h \
- qpid/client/Connector.h \
- qpid/client/Demux.h \
- qpid/client/Dispatcher.h \
- qpid/client/Execution.h \
- qpid/client/FlowControl.h \
- qpid/client/Future.h \
- qpid/client/FutureCompletion.h \
- qpid/client/FutureResult.h \
- qpid/client/LocalQueue.h \
- qpid/client/Message.h \
- qpid/client/MessageListener.h \
- qpid/client/MessageQueue.h \
- qpid/client/Results.h \
- qpid/client/SessionBase_0_10.h \
- qpid/client/Session.h \
- qpid/client/AsyncSession.h \
- qpid/client/SessionImpl.h \
- qpid/client/StateManager.h \
- qpid/client/SubscriptionManager.h \
- qpid/client/TypedResult.h \
- qpid/framing/AMQBody.h \
- qpid/framing/AMQCommandControlBody.h \
- qpid/framing/AMQContentBody.h \
- qpid/framing/AMQDataBlock.h \
- qpid/framing/AMQFrame.h \
- qpid/framing/AMQHeaderBody.h \
- qpid/framing/AMQHeartbeatBody.h \
- qpid/framing/AMQMethodBody.h \
- qpid/framing/AMQP_HighestVersion.h \
- qpid/framing/AccumulatedAck.h \
- qpid/framing/Array.h \
- qpid/framing/Blob.h \
- qpid/framing/BodyHandler.h \
- qpid/framing/Buffer.h \
- qpid/framing/ChannelHandler.h \
- qpid/framing/FieldTable.h \
- qpid/framing/FieldValue.h \
- qpid/framing/FrameDefaultVisitor.h \
- qpid/framing/FrameHandler.h \
- qpid/framing/FrameHandler.h \
- qpid/framing/FrameSet.h \
- qpid/framing/Handler.h \
- qpid/framing/HeaderProperties.h \
- qpid/framing/Invoker.h \
- qpid/framing/InputHandler.h \
- qpid/framing/InitiationHandler.h \
- qpid/framing/MethodContent.h \
- qpid/framing/BodyHolder.h \
- qpid/framing/MaxMethodBodySize.h \
- qpid/framing/ModelMethod.h \
- qpid/framing/OutputHandler.h \
- qpid/framing/ProtocolInitiation.h \
- qpid/framing/ProtocolVersion.h \
- qpid/framing/Proxy.h \
- qpid/framing/SendContent.h \
- qpid/framing/SequenceNumber.h \
- qpid/framing/SequenceSet.h \
- qpid/framing/SequenceNumberSet.h \
- qpid/framing/StructHelper.h \
- qpid/framing/TransferContent.h \
- qpid/framing/TypeFilter.h \
- qpid/framing/Uuid.h \
- qpid/framing/Visitor.h \
- qpid/framing/amqp_framing.h \
- qpid/framing/amqp_types.h \
- qpid/framing/amqp_types_full.h \
- qpid/framing/frame_functors.h \
- qpid/framing/variant.h \
- qpid/log/Helpers.h \
- qpid/log/Options.h \
- qpid/log/Logger.h \
- qpid/log/Selector.h \
- qpid/log/Statement.h \
- qpid/management/Args.h \
- qpid/management/Manageable.h \
- qpid/management/ManagementBroker.h \
- qpid/management/ManagementExchange.h \
- qpid/management/ManagementObject.h \
- qpid/sys/AggregateOutput.h \
- qpid/sys/AsynchIO.h \
- qpid/sys/AsynchIOHandler.h \
- qpid/sys/AtomicCount.h \
- qpid/sys/AtomicValue.h \
- qpid/sys/AtomicValue_gcc.h \
- qpid/sys/AtomicValue_mutex.h \
- qpid/sys/BlockingQueue.h \
- qpid/sys/Condition.h \
- qpid/sys/ConnectionCodec.h \
- qpid/sys/ConnectionInputHandler.h \
- qpid/sys/ConnectionInputHandlerFactory.h \
- qpid/sys/ConnectionOutputHandler.h \
- qpid/sys/DeletionManager.h \
- qpid/sys/Dispatcher.h \
- qpid/sys/IOHandle.h \
- qpid/sys/Monitor.h \
- qpid/sys/Mutex.h \
- qpid/sys/OutputControl.h \
- qpid/sys/OutputTask.h \
- qpid/sys/Poller.h \
- qpid/sys/ProtocolFactory.h \
- qpid/sys/Runnable.h \
- qpid/sys/Fork.h \
- qpid/sys/LockFile.h \
- qpid/sys/ScopedIncrement.h \
- qpid/sys/Semaphore.h \
- qpid/sys/SystemInfo.h \
- qpid/sys/Shlib.h \
- qpid/sys/ShutdownHandler.h \
- qpid/sys/Socket.h \
- qpid/sys/StateMonitor.h \
- qpid/sys/StrError.h \
- qpid/sys/Waitable.h \
- qpid/sys/Thread.h \
- qpid/sys/Time.h \
- qpid/sys/TimeoutHandler.h
-
-if HAVE_XML
-nobase_include_HEADERS += qpid/broker/XmlExchange.h
-endif
-
+ qpid/client/StateManager.h \
+ qpid/client/Subscription.cpp \
+ qpid/client/SubscriptionImpl.cpp \
+ qpid/client/SubscriptionImpl.h \
+ qpid/client/SubscriptionManager.cpp \
+ qpid/client/SubscriptionManagerImpl.cpp \
+ qpid/client/SubscriptionManagerImpl.h \
+ qpid/client/TCPConnector.cpp \
+ qpid/client/TCPConnector.h \
+ qpid/messaging/Address.cpp \
+ qpid/messaging/Connection.cpp \
+ qpid/messaging/ListContent.cpp \
+ qpid/messaging/ListView.cpp \
+ qpid/messaging/MapContent.cpp \
+ qpid/messaging/MapView.cpp \
+ qpid/messaging/Message.cpp \
+ qpid/messaging/MessageImpl.h \
+ qpid/messaging/MessageImpl.cpp \
+ qpid/messaging/Sender.cpp \
+ qpid/messaging/Receiver.cpp \
+ qpid/messaging/Session.cpp \
+ qpid/messaging/Variant.cpp \
+ qpid/messaging/ConnectionImpl.h \
+ qpid/messaging/SenderImpl.h \
+ qpid/messaging/ReceiverImpl.h \
+ qpid/messaging/SessionImpl.h \
+ qpid/client/amqp0_10/AcceptTracker.h \
+ qpid/client/amqp0_10/AcceptTracker.cpp \
+ qpid/client/amqp0_10/AddressResolution.h \
+ qpid/client/amqp0_10/AddressResolution.cpp \
+ qpid/client/amqp0_10/Codecs.cpp \
+ qpid/client/amqp0_10/CodecsInternal.h \
+ qpid/client/amqp0_10/ConnectionImpl.h \
+ qpid/client/amqp0_10/ConnectionImpl.cpp \
+ qpid/client/amqp0_10/IncomingMessages.h \
+ qpid/client/amqp0_10/IncomingMessages.cpp \
+ qpid/client/amqp0_10/MessageSink.h \
+ qpid/client/amqp0_10/MessageSource.h \
+ qpid/client/amqp0_10/OutgoingMessage.h \
+ qpid/client/amqp0_10/OutgoingMessage.cpp \
+ qpid/client/amqp0_10/ReceiverImpl.h \
+ qpid/client/amqp0_10/ReceiverImpl.cpp \
+ qpid/client/amqp0_10/SessionImpl.h \
+ qpid/client/amqp0_10/SessionImpl.cpp \
+ qpid/client/amqp0_10/SenderImpl.h \
+ qpid/client/amqp0_10/SenderImpl.cpp
+
+# NOTE: only public header files (which should be in ../include)
+# should go in this list. Private headers should go in the SOURCES
+# list for one of the libraries or executables that includes it.
+
+nobase_include_HEADERS += \
+ ../include/qpid/Address.h \
+ ../include/qpid/CommonImportExport.h \
+ ../include/qpid/Exception.h \
+ ../include/qpid/InlineAllocator.h \
+ ../include/qpid/InlineVector.h \
+ ../include/qpid/Msg.h \
+ ../include/qpid/Options.h \
+ ../include/qpid/RangeSet.h \
+ ../include/qpid/SessionId.h \
+ ../include/qpid/Url.h \
+ ../include/qpid/client/AsyncSession.h \
+ ../include/qpid/client/ClientImportExport.h \
+ ../include/qpid/client/Completion.h \
+ ../include/qpid/client/Connection.h \
+ ../include/qpid/client/ConnectionSettings.h \
+ ../include/qpid/client/FailoverListener.h \
+ ../include/qpid/client/FailoverManager.h \
+ ../include/qpid/client/FlowControl.h \
+ ../include/qpid/client/Future.h \
+ ../include/qpid/client/FutureCompletion.h \
+ ../include/qpid/client/FutureResult.h \
+ ../include/qpid/client/Handle.h \
+ ../include/qpid/client/LocalQueue.h \
+ ../include/qpid/client/Message.h \
+ ../include/qpid/client/MessageListener.h \
+ ../include/qpid/client/MessageReplayTracker.h \
+ ../include/qpid/client/QueueOptions.h \
+ ../include/qpid/client/Session.h \
+ ../include/qpid/client/SessionBase_0_10.h \
+ ../include/qpid/client/Subscription.h \
+ ../include/qpid/client/SubscriptionManager.h \
+ ../include/qpid/client/SubscriptionSettings.h \
+ ../include/qpid/client/TypedResult.h \
+ ../include/qpid/framing/Array.h \
+ ../include/qpid/framing/Buffer.h \
+ ../include/qpid/framing/FieldTable.h \
+ ../include/qpid/framing/FieldValue.h \
+ ../include/qpid/framing/List.h \
+ ../include/qpid/framing/ProtocolVersion.h \
+ ../include/qpid/framing/SequenceNumber.h \
+ ../include/qpid/framing/SequenceSet.h \
+ ../include/qpid/framing/StructHelper.h \
+ ../include/qpid/framing/Uuid.h \
+ ../include/qpid/framing/amqp_types.h \
+ ../include/qpid/framing/amqp_types_full.h \
+ ../include/qpid/log/Logger.h \
+ ../include/qpid/log/Options.h \
+ ../include/qpid/log/Selector.h \
+ ../include/qpid/log/SinkOptions.h \
+ ../include/qpid/log/Statement.h \
+ ../include/qpid/management/Args.h \
+ ../include/qpid/management/Manageable.h \
+ ../include/qpid/management/ManagementEvent.h \
+ ../include/qpid/management/ManagementObject.h \
+ ../include/qpid/sys/Condition.h \
+ ../include/qpid/sys/ExceptionHolder.h \
+ ../include/qpid/sys/IOHandle.h \
+ ../include/qpid/sys/IntegerTypes.h \
+ ../include/qpid/sys/Monitor.h \
+ ../include/qpid/sys/Mutex.h \
+ ../include/qpid/sys/Runnable.h \
+ ../include/qpid/sys/StrError.h \
+ ../include/qpid/sys/SystemInfo.h \
+ ../include/qpid/sys/Thread.h \
+ ../include/qpid/sys/Time.h \
+ ../include/qpid/messaging/Address.h \
+ ../include/qpid/messaging/Connection.h \
+ ../include/qpid/messaging/Codec.h \
+ ../include/qpid/messaging/ListContent.h \
+ ../include/qpid/messaging/ListView.h \
+ ../include/qpid/messaging/MapContent.h \
+ ../include/qpid/messaging/MapView.h \
+ ../include/qpid/messaging/Message.h \
+ ../include/qpid/messaging/Sender.h \
+ ../include/qpid/messaging/Receiver.h \
+ ../include/qpid/messaging/Session.h \
+ ../include/qpid/messaging/Variant.h \
+ ../include/qpid/client/amqp0_10/Codecs.h
# Force build of qpidd during dist phase so help2man will work.
dist-hook: $(BUILT_SOURCES)
diff --git a/cpp/src/acl.mk b/cpp/src/acl.mk
index 28b5f4f89f..95b47acc1c 100644
--- a/cpp/src/acl.mk
+++ b/cpp/src/acl.mk
@@ -1,15 +1,38 @@
#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
# acl library makefile fragment, to be included in Makefile.am
#
-lib_LTLIBRARIES += libqpidacl.la
+dmodule_LTLIBRARIES += acl.la
-libqpidacl_la_SOURCES = \
+acl_la_SOURCES = \
qpid/acl/Acl.cpp \
qpid/acl/Acl.h \
+ qpid/acl/AclData.cpp \
+ qpid/acl/AclData.h \
+ qpid/acl/AclPlugin.cpp \
qpid/acl/AclReader.cpp \
- qpid/acl/AclReader.h \
- qpid/acl/AclPlugin.cpp
-
-libqpidacl_la_LIBADD= -lacl libqpidbroker.la
+ qpid/acl/AclReader.h
+acl_la_LIBADD = libqpidbroker.la
+if SUNOS
+ acl_la_LIBADD += libqmfagent.la libqmfconsole.la libqpidcommon.la -lboost_program_options $(SUNCC_RUNTIME_LIBS)
+endif
+acl_la_LDFLAGS = $(PLUGINLDFLAGS)
diff --git a/cpp/src/cluster.cmake b/cpp/src/cluster.cmake
new file mode 100644
index 0000000000..6552c39f12
--- /dev/null
+++ b/cpp/src/cluster.cmake
@@ -0,0 +1,157 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+# Cluster library CMake fragment, to be included in CMakeLists.txt
+#
+
+# Optional cluster support. Requires CPG; if building it, can optionally
+# include CMAN support as well.
+
+include(CheckIncludeFiles)
+include(CheckLibraryExists)
+
+set(LIBCPG_PATH /usr/lib/openais /usr/lib64/openais /usr/lib/corosync /usr/lib64/corosync CACHE STRING "Default locations for libcpg (cluster library)" )
+find_library(LIBCPG cpg ${LIBCPG_PATH})
+if (LIBCPG)
+ CHECK_LIBRARY_EXISTS (${LIBCPG} cpg_local_get "" HAVE_LIBCPG)
+ CHECK_INCLUDE_FILES (openais/cpg.h HAVE_OPENAIS_CPG_H)
+ CHECK_INCLUDE_FILES (corosync/cpg.h HAVE_COROSYNC_CPG_H)
+endif (LIBCPG)
+
+set (cluster_default ${cluster_force})
+if (CMAKE_SYSTEM_NAME STREQUAL Windows)
+else (CMAKE_SYSTEM_NAME STREQUAL Windows)
+ if (HAVE_LIBCPG)
+ if (HAVE_OPENAIS_CPG_H OR HAVE_COROSYNC_CPG_H)
+ set (cluster_default ON)
+ endif (HAVE_OPENAIS_CPG_H OR HAVE_COROSYNC_CPG_H)
+ endif (HAVE_LIBCPG)
+endif (CMAKE_SYSTEM_NAME STREQUAL Windows)
+
+option(BUILD_CLUSTER "Build with CPG support for clustering" ${cluster_default})
+if (BUILD_CLUSTER)
+
+ if (NOT HAVE_LIBCPG)
+ message(FATAL_ERROR "libcpg not found, install openais-devel or corosync-devel")
+ endif (NOT HAVE_LIBCPG)
+ if (NOT HAVE_OPENAIS_CPG_H AND NOT HAVE_COROSYNC_CPG_H)
+ message(FATAL_ERROR "cpg.h not found, install openais-devel or corosync-devel")
+ endif (NOT HAVE_OPENAIS_CPG_H AND NOT HAVE_COROSYNC_CPG_H)
+
+ CHECK_LIBRARY_EXISTS (cman cman_is_quorate "" HAVE_LIBCMAN)
+ CHECK_INCLUDE_FILES (libcman.h HAVE_LIBCMAN_H)
+
+ set(cluster_quorum_default ${cluster_quorum_force})
+ if (HAVE_LIBCMAN AND HAVE_LIBCMAN_H)
+ set(cluster_quorum_default ON)
+ endif (HAVE_LIBCMAN AND HAVE_LIBCMAN_H)
+
+ option(BUILD_CLUSTER_QUORUM "Include libcman quorum service integration" ${cluster_quorum_default})
+ if (BUILD_CLUSTER_QUORUM)
+ if (NOT HAVE_LIBCMAN)
+ message(FATAL_ERROR "libcman not found, install cman-devel or cmanlib-devel")
+ endif (NOT HAVE_LIBCMAN)
+ if (NOT HAVE_LIBCMAN_H)
+ message(FATAL_ERROR "libcman.h not found, install cman-devel or cmanlib-devel")
+ endif (NOT HAVE_LIBCMAN_H)
+
+ set (CMAN_SOURCES qpid/cluster/Quorum_cman.h qpid/cluster/Quorum_cman.cpp)
+ set (CMAN_LIB cman)
+ else (BUILD_CLUSTER_QUORUM)
+ set (CMAN_SOURCES qpid/cluster/Quorum_null.h)
+ endif (BUILD_CLUSTER_QUORUM)
+
+ set (cluster_SOURCES
+ ${CMAN_SOURCES}
+ qpid/cluster/Cluster.cpp
+ qpid/cluster/Cluster.h
+ qpid/cluster/Decoder.cpp
+ qpid/cluster/Decoder.h
+ qpid/cluster/PollableQueue.h
+ qpid/cluster/ClusterMap.cpp
+ qpid/cluster/ClusterMap.h
+ qpid/cluster/ClusterPlugin.cpp
+ qpid/cluster/ClusterSettings.h
+ qpid/cluster/Connection.cpp
+ qpid/cluster/Connection.h
+ qpid/cluster/ConnectionCodec.cpp
+ qpid/cluster/ConnectionCodec.h
+ qpid/cluster/Cpg.cpp
+ qpid/cluster/Cpg.h
+ qpid/cluster/Dispatchable.h
+ qpid/cluster/UpdateClient.cpp
+ qpid/cluster/UpdateClient.h
+ qpid/cluster/RetractClient.cpp
+ qpid/cluster/RetractClient.h
+ qpid/cluster/ErrorCheck.cpp
+ qpid/cluster/ErrorCheck.h
+ qpid/cluster/Event.cpp
+ qpid/cluster/Event.h
+ qpid/cluster/EventFrame.h
+ qpid/cluster/EventFrame.cpp
+ qpid/cluster/ExpiryPolicy.h
+ qpid/cluster/ExpiryPolicy.cpp
+ qpid/cluster/FailoverExchange.cpp
+ qpid/cluster/FailoverExchange.h
+ qpid/cluster/UpdateExchange.cpp
+ qpid/cluster/UpdateExchange.h
+ qpid/cluster/UpdateReceiver.h
+ qpid/cluster/LockedConnectionMap.h
+ qpid/cluster/Multicaster.cpp
+ qpid/cluster/Multicaster.h
+ qpid/cluster/McastFrameHandler.h
+ qpid/cluster/NoOpConnectionOutputHandler.h
+ qpid/cluster/Numbering.h
+ qpid/cluster/OutputInterceptor.cpp
+ qpid/cluster/OutputInterceptor.h
+ qpid/cluster/PollerDispatch.cpp
+ qpid/cluster/PollerDispatch.h
+ qpid/cluster/ProxyInputHandler.h
+ qpid/cluster/Quorum.h
+ qpid/cluster/InitialStatusMap.h
+ qpid/cluster/InitialStatusMap.cpp
+ qpid/cluster/MemberSet.h
+ qpid/cluster/MemberSet.cpp
+ qpid/cluster/types.h
+ qpid/cluster/StoreStatus.h
+ qpid/cluster/StoreStatus.cpp
+ )
+
+ add_library (cluster MODULE ${cluster_SOURCES})
+ target_link_libraries (cluster ${LIBCPG} ${CMAN_LIB} qpidbroker qpidclient ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY})
+ set_target_properties (cluster PROPERTIES PREFIX "")
+
+ # Create a second shared library for linking with test executables,
+ # cmake will not allow a module to be linked with an executable.
+ add_library (cluster_shared SHARED ${cluster_SOURCES})
+ target_link_libraries (cluster_shared ${LIBCPG} ${CMAN_LIB} qpidbroker qpidclient ${Boost_FILESYSTEM_LIBRARY})
+
+ if (CMAKE_COMPILER_IS_GNUCXX)
+ set_target_properties(cluster PROPERTIES
+ LINK_FLAGS "-Wl,--no-undefined -pthread")
+ endif (CMAKE_COMPILER_IS_GNUCXX)
+
+ install (TARGETS cluster
+ DESTINATION ${QPIDD_MODULE_DIR}
+ COMPONENT ${QPID_COMPONENT_BROKER})
+
+endif (BUILD_CLUSTER)
+
+# Distribute all sources.
+#EXTRA_DIST += qpid/cluster/Quorum_cman.h qpid/cluster/Quorum_cman.cpp qpid/cluster/Quorum_null.h
diff --git a/cpp/src/cluster.mk b/cpp/src/cluster.mk
index aa3644785b..081889130e 100644
--- a/cpp/src/cluster.mk
+++ b/cpp/src/cluster.mk
@@ -1,30 +1,107 @@
#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
# Cluster library makefile fragment, to be included in Makefile.am
#
-lib_LTLIBRARIES += libqpidcluster.la
-
-if CPG
-
-libqpidcluster_la_SOURCES = \
- qpid/cluster/Cluster.cpp \
- qpid/cluster/Cluster.h \
- qpid/cluster/Cpg.cpp \
- qpid/cluster/Cpg.h \
- qpid/cluster/Dispatchable.h \
- qpid/cluster/ClusterPlugin.cpp \
- qpid/cluster/ConnectionInterceptor.h \
- qpid/cluster/ConnectionInterceptor.cpp \
- qpid/cluster/ClassifierHandler.h \
- qpid/cluster/ClassifierHandler.cpp \
- qpid/cluster/ShadowConnectionOutputHandler.h \
- qpid/cluster/PollableCondition.h \
- qpid/cluster/PollableCondition.cpp \
- qpid/cluster/PollableQueue.h
-
-libqpidcluster_la_LIBADD= -lcpg libqpidbroker.la
-else
-# Empty stub library to satisfy rpm spec file.
-libqpidcluster_la_SOURCES =
+# Optional CMAN support
+
+# Distribute all sources.
+EXTRA_DIST += qpid/cluster/Quorum_cman.h qpid/cluster/Quorum_cman.cpp qpid/cluster/Quorum_null.h
+if HAVE_LIBCMAN
+CMAN_SOURCES = qpid/cluster/Quorum_cman.h qpid/cluster/Quorum_cman.cpp
+libcman = -lcman
+else
+CMAN_SOURCES = qpid/cluster/Quorum_null.h
endif
+
+if HAVE_LIBCPG
+
+dmodule_LTLIBRARIES += cluster.la
+
+cluster_la_SOURCES = \
+ $(CMAN_SOURCES) \
+ qpid/cluster/Cluster.cpp \
+ qpid/cluster/Cluster.h \
+ qpid/cluster/Decoder.cpp \
+ qpid/cluster/Decoder.h \
+ qpid/cluster/PollableQueue.h \
+ qpid/cluster/ClusterMap.cpp \
+ qpid/cluster/ClusterMap.h \
+ qpid/cluster/ClusterPlugin.cpp \
+ qpid/cluster/ClusterSettings.h \
+ qpid/cluster/Connection.cpp \
+ qpid/cluster/Connection.h \
+ qpid/cluster/ConnectionCodec.cpp \
+ qpid/cluster/ConnectionCodec.h \
+ qpid/cluster/Cpg.cpp \
+ qpid/cluster/Cpg.h \
+ qpid/cluster/Dispatchable.h \
+ qpid/cluster/UpdateClient.cpp \
+ qpid/cluster/UpdateClient.h \
+ qpid/cluster/RetractClient.cpp \
+ qpid/cluster/RetractClient.h \
+ qpid/cluster/ErrorCheck.cpp \
+ qpid/cluster/ErrorCheck.h \
+ qpid/cluster/Event.cpp \
+ qpid/cluster/Event.h \
+ qpid/cluster/EventFrame.h \
+ qpid/cluster/EventFrame.cpp \
+ qpid/cluster/ExpiryPolicy.h \
+ qpid/cluster/ExpiryPolicy.cpp \
+ qpid/cluster/FailoverExchange.cpp \
+ qpid/cluster/FailoverExchange.h \
+ qpid/cluster/UpdateExchange.h \
+ qpid/cluster/UpdateExchange.cpp \
+ qpid/cluster/UpdateReceiver.h \
+ qpid/cluster/LockedConnectionMap.h \
+ qpid/cluster/Multicaster.cpp \
+ qpid/cluster/Multicaster.h \
+ qpid/cluster/McastFrameHandler.h \
+ qpid/cluster/NoOpConnectionOutputHandler.h \
+ qpid/cluster/Numbering.h \
+ qpid/cluster/OutputInterceptor.cpp \
+ qpid/cluster/OutputInterceptor.h \
+ qpid/cluster/PollerDispatch.cpp \
+ qpid/cluster/PollerDispatch.h \
+ qpid/cluster/ProxyInputHandler.h \
+ qpid/cluster/Quorum.h \
+ qpid/cluster/InitialStatusMap.h \
+ qpid/cluster/InitialStatusMap.cpp \
+ qpid/cluster/MemberSet.h \
+ qpid/cluster/MemberSet.cpp \
+ qpid/cluster/types.h \
+ qpid/cluster/StoreStatus.h \
+ qpid/cluster/StoreStatus.cpp
+
+cluster_la_LIBADD= -lcpg $(libcman) libqpidbroker.la libqpidclient.la
+cluster_la_CXXFLAGS = $(AM_CXXFLAGS) -fno-strict-aliasing
+cluster_la_LDFLAGS = $(PLUGINLDFLAGS)
+
+# The watchdog plugin and helper executable
+dmodule_LTLIBRARIES += watchdog.la
+watchdog_la_SOURCES = qpid/cluster/WatchDogPlugin.cpp
+watchdog_la_LIBADD = libqpidbroker.la
+watchdog_la_LDFLAGS = $(PLUGINLDFLAGS)
+
+qpidexec_PROGRAMS += qpidd_watchdog
+qpidd_watchdog_SOURCES = qpid/cluster/qpidd_watchdog.cpp
+
+endif # HAVE_LIBCPG
diff --git a/cpp/src/config.h.cmake b/cpp/src/config.h.cmake
new file mode 100644
index 0000000000..b3d0450822
--- /dev/null
+++ b/cpp/src/config.h.cmake
@@ -0,0 +1,56 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/*
+ * This file is automatically generated and will be overwritten by the
+ * next CMake invocation.
+ */
+
+#ifndef QPID_CONFIG_H
+#define QPID_CONFIG_H
+
+// PACKAGE_NAME and PACKAGE_VERSION are carry-overs from the autoconf world.
+// They tend to cause confusion and problems when mixing headers from multiple
+// autoconf-configured packages, so it's best to remove these in favor of
+// Qpid-specific names as soon as the autoconf stuff is removed.
+#define PACKAGE_NAME "${CMAKE_PROJECT_NAME}"
+#define PACKAGE_VERSION "${qpidc_version}"
+
+#cmakedefine QPIDC_CONF_FILE "${QPIDC_CONF_FILE}"
+#cmakedefine QPIDD_CONF_FILE "${QPIDD_CONF_FILE}"
+
+#cmakedefine QPIDC_MODULE_DIR "${QPIDC_MODULE_DIR}"
+#cmakedefine QPIDD_MODULE_DIR "${QPIDD_MODULE_DIR}"
+
+#define QPID_MODULE_SUFFIX "${CMAKE_SHARED_LIBRARY_SUFFIX}"
+
+#cmakedefine QPID_HAS_CLOCK_GETTIME
+
+#cmakedefine QPID_HAS_SASL
+#cmakedefine BROKER_SASL_NAME "${BROKER_SASL_NAME}"
+#ifdef QPID_HAS_SASL
+# define HAVE_SASL 1
+#endif
+
+#cmakedefine HAVE_OPENAIS_CPG_H ${HAVE_OPENAIS_CPG_H}
+#cmakedefine HAVE_COROSYNC_CPG_H ${HAVE_COROSYNC_CPG_H}
+#cmakedefine HAVE_LIBCMAN_H ${HAVE_LIBCMAN_H}
+#cmakedefine HAVE_LOG_AUTHPRIV
+#cmakedefine HAVE_LOG_FTP
+
+#endif /* QPID_CONFIG_H */
diff --git a/cpp/src/generate.sh b/cpp/src/generate.sh
index 3582893f24..581a45ff7f 100755
--- a/cpp/src/generate.sh
+++ b/cpp/src/generate.sh
@@ -1,4 +1,23 @@
# !/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# Generate code from AMQP specification.
# specs and gentools_dir are set by Makefile
#
diff --git a/cpp/src/posix/QpiddBroker.cpp b/cpp/src/posix/QpiddBroker.cpp
new file mode 100644
index 0000000000..7eef187ded
--- /dev/null
+++ b/cpp/src/posix/QpiddBroker.cpp
@@ -0,0 +1,179 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "config.h"
+#include "qpidd.h"
+#include "qpid/Exception.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/broker/Daemon.h"
+#include "qpid/broker/SignalHandler.h"
+#include "qpid/log/Logger.h"
+
+#include <iostream>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/utsname.h>
+
+using namespace std;
+using namespace qpid;
+using qpid::broker::Broker;
+using qpid::broker::Daemon;
+
+BootstrapOptions::BootstrapOptions(const char* argv0)
+ : qpid::Options("Options"),
+ common("", QPIDD_CONF_FILE),
+ module(QPIDD_MODULE_DIR),
+ log(argv0)
+{
+ add(common);
+ add(module);
+ add(log);
+}
+
+namespace {
+const std::string TCP = "tcp";
+}
+
+struct DaemonOptions : public qpid::Options {
+ bool daemon;
+ bool quit;
+ bool check;
+ int wait;
+ std::string piddir;
+ std::string transport;
+
+ DaemonOptions() : qpid::Options("Daemon options"), daemon(false), quit(false), check(false), wait(600), transport(TCP)
+ {
+ char *home = ::getenv("HOME");
+
+ if (home == 0)
+ piddir += "/tmp";
+ else
+ piddir += home;
+ piddir += "/.qpidd";
+
+ addOptions()
+ ("daemon,d", optValue(daemon), "Run as a daemon. Logs to syslog by default in this mode.")
+ ("transport", optValue(transport, "TRANSPORT"), "The transport for which to return the port")
+ ("pid-dir", optValue(piddir, "DIR"), "Directory where port-specific PID file is stored")
+ ("wait,w", optValue(wait, "SECONDS"), "Sets the maximum wait time to initialize the daemon. If the daemon fails to initialize, prints an error and returns 1")
+ ("check,c", optValue(check), "Prints the daemon's process ID to stdout and returns 0 if the daemon is running, otherwise returns 1")
+ ("quit,q", optValue(quit), "Tells the daemon to shut down");
+ }
+};
+
+struct QpiddPosixOptions : public QpiddOptionsPrivate {
+ DaemonOptions daemon;
+ QpiddOptions *parent;
+
+ QpiddPosixOptions(QpiddOptions *parent_) : parent(parent_) {
+ parent->add(daemon);
+ }
+};
+
+QpiddOptions::QpiddOptions(const char* argv0)
+ : qpid::Options("Options"),
+ common("", QPIDD_CONF_FILE),
+ module(QPIDD_MODULE_DIR),
+ log(argv0)
+{
+ add(common);
+ add(module);
+ add(broker);
+ add(log);
+
+ platform.reset(new QpiddPosixOptions(this));
+ qpid::Plugin::addOptions(*this);
+}
+
+void QpiddOptions::usage() const {
+ cout << "Usage: qpidd [OPTIONS]" << endl << endl << *this << endl;
+}
+
+struct QpiddDaemon : public Daemon {
+ QpiddPosixOptions *options;
+
+ QpiddDaemon(std::string pidDir, QpiddPosixOptions *opts)
+ : Daemon(pidDir), options(opts) {}
+
+ /** Code for parent process */
+ void parent() {
+ uint16_t port = wait(options->daemon.wait);
+ if (options->parent->broker.port == 0 || options->daemon.transport != TCP)
+ cout << port << endl;
+ }
+
+ /** Code for forked child process */
+ void child() {
+ boost::intrusive_ptr<Broker> brokerPtr(new Broker(options->parent->broker));
+ qpid::broker::SignalHandler::setBroker(brokerPtr);
+ brokerPtr->accept();
+ uint16_t port=brokerPtr->getPort(options->daemon.transport);
+ ready(port); // Notify parent.
+ brokerPtr->run();
+ }
+};
+
+int QpiddBroker::execute (QpiddOptions *options) {
+ // Options that affect a running daemon.
+ QpiddPosixOptions *myOptions =
+ static_cast<QpiddPosixOptions *>(options->platform.get());
+ if (myOptions == 0)
+ throw Exception("Internal error obtaining platform options");
+
+ if (myOptions->daemon.check || myOptions->daemon.quit) {
+ pid_t pid = Daemon::getPid(myOptions->daemon.piddir,
+ options->broker.port);
+ if (pid < 0)
+ return 1;
+ if (myOptions->daemon.check)
+ cout << pid << endl;
+ if (myOptions->daemon.quit) {
+ if (kill(pid, SIGINT) < 0)
+ throw Exception("Failed to stop daemon: " + qpid::sys::strError(errno));
+ // Wait for the process to die before returning
+ int retry=10000; // Try up to 10 seconds
+ while (kill(pid,0) == 0 && --retry)
+ sys::usleep(1000);
+ if (retry == 0)
+ throw Exception("Gave up waiting for daemon process to exit");
+ }
+ return 0;
+ }
+
+ // Starting the broker.
+ if (myOptions->daemon.daemon) {
+ // For daemon mode replace default stderr with syslog.
+ options->log.sinkOptions->detached();
+ qpid::log::Logger::instance().configure(options->log);
+ // Fork the daemon
+ QpiddDaemon d(myOptions->daemon.piddir, myOptions);
+ d.fork(); // Broker is stared in QpiddDaemon::child()
+ }
+ else { // Non-daemon broker.
+ boost::intrusive_ptr<Broker> brokerPtr(new Broker(options->broker));
+ broker::SignalHandler::setBroker(brokerPtr);
+ brokerPtr->accept();
+ if (options->broker.port == 0 || myOptions->daemon.transport != TCP)
+ cout << uint16_t(brokerPtr->getPort(myOptions->daemon.transport)) << endl;
+ brokerPtr->run();
+ }
+ return 0;
+}
diff --git a/cpp/src/prof b/cpp/src/prof
index bd889a1446..acfbaff2d4 100755
--- a/cpp/src/prof
+++ b/cpp/src/prof
@@ -1,4 +1,25 @@
#!/bin/bash
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
rm /var/lib/oprofile/oprofiled.log
diff --git a/cpp/src/qmf.mk b/cpp/src/qmf.mk
new file mode 100644
index 0000000000..96a977f3cd
--- /dev/null
+++ b/cpp/src/qmf.mk
@@ -0,0 +1,113 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#
+# qmf library makefile fragment, to be included in Makefile.am
+#
+lib_LTLIBRARIES += \
+ libqmf.la \
+ libqmfengine.la
+
+#
+# Public headers for the QMF API
+#
+QMF_API = \
+ ../include/qpid/agent/ManagementAgent.h \
+ ../include/qpid/agent/QmfAgentImportExport.h \
+ ../include/qmf/Agent.h \
+ ../include/qmf/Connection.h \
+ ../include/qmf/QmfImportExport.h \
+ ../include/qmf/ConnectionSettings.h \
+ ../include/qmf/AgentObject.h
+
+#
+# Public headers for the QMF Engine API
+#
+QMF_ENGINE_API = \
+ ../include/qmf/engine/Agent.h \
+ ../include/qmf/engine/ConnectionSettings.h \
+ ../include/qmf/engine/Console.h \
+ ../include/qmf/engine/Event.h \
+ ../include/qmf/engine/Message.h \
+ ../include/qmf/engine/Object.h \
+ ../include/qmf/engine/ObjectId.h \
+ ../include/qmf/engine/QmfEngineImportExport.h \
+ ../include/qmf/engine/Query.h \
+ ../include/qmf/engine/ResilientConnection.h \
+ ../include/qmf/engine/Schema.h \
+ ../include/qmf/engine/Typecode.h \
+ ../include/qmf/engine/Value.h
+
+# Public header files
+nobase_include_HEADERS += \
+ $(QMF_API) \
+ $(QMF_ENGINE_API)
+
+libqmf_la_SOURCES = \
+ $(QMF_API) \
+ qpid/agent/ManagementAgentImpl.cpp \
+ qpid/agent/ManagementAgentImpl.h
+
+libqmfengine_la_SOURCES = \
+ $(QMF_ENGINE_API) \
+ qmf/engine/Agent.cpp \
+ qmf/engine/BrokerProxyImpl.cpp \
+ qmf/engine/BrokerProxyImpl.h \
+ qmf/engine/ConnectionSettingsImpl.cpp \
+ qmf/engine/ConnectionSettingsImpl.h \
+ qmf/engine/ConsoleImpl.cpp \
+ qmf/engine/ConsoleImpl.h \
+ qmf/engine/MessageImpl.cpp \
+ qmf/engine/MessageImpl.h \
+ qmf/engine/ObjectIdImpl.cpp \
+ qmf/engine/ObjectIdImpl.h \
+ qmf/engine/ObjectImpl.cpp \
+ qmf/engine/ObjectImpl.h \
+ qmf/engine/Protocol.cpp \
+ qmf/engine/Protocol.h \
+ qmf/engine/QueryImpl.cpp \
+ qmf/engine/QueryImpl.h \
+ qmf/engine/ResilientConnection.cpp \
+ qmf/engine/SequenceManager.cpp \
+ qmf/engine/SequenceManager.h \
+ qmf/engine/SchemaImpl.cpp \
+ qmf/engine/SchemaImpl.h \
+ qmf/engine/ValueImpl.cpp \
+ qmf/engine/ValueImpl.h
+
+libqmf_la_LIBADD = libqmfengine.la
+libqmfengine_la_LIBADD = libqpidclient.la
+
+# Library Version Information:
+#
+# CURRENT => API/ABI version. Bump this if the interface changes
+# REVISION => Version of underlying implementation.
+# Bump if implementation changes but API/ABI doesn't
+# AGE => Number of API/ABI versions this is backward compatible with
+#
+QMF_CURRENT = 1
+QMF_REVISION = 0
+QMF_AGE = 0
+
+QMF_ENGINE_CURRENT = 1
+QMF_ENGINE_REVISION = 1
+QMF_ENGINE_AGE = 0
+
+libqmf_la_LDFLAGS = -version-info $(QMF_CURRENT):$(QMF_REVISION):$(QMF_AGE)
+libqmfengine_la_LDFLAGS = -version-info $(QMF_ENGINE_CURRENT):$(QMF_ENGINE_REVISION):$(QMF_ENGINE_AGE)
diff --git a/cpp/src/qmf/engine/Agent.cpp b/cpp/src/qmf/engine/Agent.cpp
new file mode 100644
index 0000000000..c5d1bff2e0
--- /dev/null
+++ b/cpp/src/qmf/engine/Agent.cpp
@@ -0,0 +1,857 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/MessageImpl.h"
+#include "qmf/engine/SchemaImpl.h"
+#include "qmf/engine/Typecode.h"
+#include "qmf/engine/ObjectImpl.h"
+#include "qmf/engine/ObjectIdImpl.h"
+#include "qmf/engine/QueryImpl.h"
+#include "qmf/engine/ValueImpl.h"
+#include "qmf/engine/Protocol.h"
+#include <qpid/framing/Buffer.h>
+#include <qpid/framing/Uuid.h>
+#include <qpid/framing/FieldTable.h>
+#include <qpid/framing/FieldValue.h>
+#include <qpid/sys/Mutex.h>
+#include <qpid/log/Statement.h>
+#include <qpid/sys/Time.h>
+#include <string.h>
+#include <string>
+#include <deque>
+#include <map>
+#include <iostream>
+#include <fstream>
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+
+using namespace std;
+using namespace qmf::engine;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+namespace qmf {
+namespace engine {
+
+ struct AgentEventImpl {
+ typedef boost::shared_ptr<AgentEventImpl> Ptr;
+ AgentEvent::EventKind kind;
+ uint32_t sequence;
+ string authUserId;
+ string authToken;
+ string name;
+ Object* object;
+ boost::shared_ptr<ObjectId> objectId;
+ boost::shared_ptr<Query> query;
+ boost::shared_ptr<Value> arguments;
+ string exchange;
+ string bindingKey;
+ const SchemaObjectClass* objectClass;
+
+ AgentEventImpl(AgentEvent::EventKind k) :
+ kind(k), sequence(0), object(0), objectClass(0) {}
+ ~AgentEventImpl() {}
+ AgentEvent copy();
+ };
+
+ struct AgentQueryContext {
+ typedef boost::shared_ptr<AgentQueryContext> Ptr;
+ uint32_t sequence;
+ string exchange;
+ string key;
+ const SchemaMethod* schemaMethod;
+ AgentQueryContext() : schemaMethod(0) {}
+ };
+
+ class AgentImpl : public boost::noncopyable {
+ public:
+ AgentImpl(char* label, bool internalStore);
+ ~AgentImpl();
+
+ void setStoreDir(const char* path);
+ void setTransferDir(const char* path);
+ void handleRcvMessage(Message& message);
+ bool getXmtMessage(Message& item) const;
+ void popXmt();
+ bool getEvent(AgentEvent& event) const;
+ void popEvent();
+ void newSession();
+ void startProtocol();
+ void heartbeat();
+ void methodResponse(uint32_t sequence, uint32_t status, char* text, const Value& arguments);
+ void queryResponse(uint32_t sequence, Object& object, bool prop, bool stat);
+ void queryComplete(uint32_t sequence);
+ void registerClass(SchemaObjectClass* cls);
+ void registerClass(SchemaEventClass* cls);
+ const ObjectId* addObject(Object& obj, uint64_t persistId);
+ const ObjectId* allocObjectId(uint64_t persistId);
+ const ObjectId* allocObjectId(uint32_t persistIdLo, uint32_t persistIdHi);
+ void raiseEvent(Event& event);
+
+ private:
+ mutable Mutex lock;
+ Mutex addLock;
+ string label;
+ string queueName;
+ string storeDir;
+ string transferDir;
+ bool internalStore;
+ uint64_t nextTransientId;
+ Uuid systemId;
+ uint32_t requestedBrokerBank;
+ uint32_t requestedAgentBank;
+ uint32_t assignedBrokerBank;
+ uint32_t assignedAgentBank;
+ AgentAttachment attachment;
+ uint16_t bootSequence;
+ uint64_t nextObjectId;
+ uint32_t nextContextNum;
+ deque<AgentEventImpl::Ptr> eventQueue;
+ deque<MessageImpl::Ptr> xmtQueue;
+ map<uint32_t, AgentQueryContext::Ptr> contextMap;
+
+ static const char* QMF_EXCHANGE;
+ static const char* DIR_EXCHANGE;
+ static const char* BROKER_KEY;
+ static const uint32_t MERR_UNKNOWN_METHOD = 2;
+ static const uint32_t MERR_UNKNOWN_PACKAGE = 8;
+ static const uint32_t MERR_UNKNOWN_CLASS = 9;
+ static const uint32_t MERR_INTERNAL_ERROR = 10;
+# define MA_BUFFER_SIZE 65536
+ char outputBuffer[MA_BUFFER_SIZE];
+
+ struct AgentClassKey {
+ string name;
+ uint8_t hash[16];
+ AgentClassKey(const string& n, const uint8_t* h) : name(n) {
+ memcpy(hash, h, 16);
+ }
+ AgentClassKey(Buffer& buffer) {
+ buffer.getShortString(name);
+ buffer.getBin128(hash);
+ }
+ string repr() {
+ return name;
+ }
+ };
+
+ struct AgentClassKeyComp {
+ bool operator() (const AgentClassKey& lhs, const AgentClassKey& rhs) const
+ {
+ if (lhs.name != rhs.name)
+ return lhs.name < rhs.name;
+ else
+ for (int i = 0; i < 16; i++)
+ if (lhs.hash[i] != rhs.hash[i])
+ return lhs.hash[i] < rhs.hash[i];
+ return false;
+ }
+ };
+
+ typedef map<AgentClassKey, SchemaObjectClass*, AgentClassKeyComp> ObjectClassMap;
+ typedef map<AgentClassKey, SchemaEventClass*, AgentClassKeyComp> EventClassMap;
+
+ struct ClassMaps {
+ ObjectClassMap objectClasses;
+ EventClassMap eventClasses;
+ };
+
+ map<string, ClassMaps> packages;
+
+ AgentEventImpl::Ptr eventDeclareQueue(const string& queueName);
+ AgentEventImpl::Ptr eventBind(const string& exchange, const string& queue, const string& key);
+ AgentEventImpl::Ptr eventSetupComplete();
+ AgentEventImpl::Ptr eventQuery(uint32_t num, const string& userId, const string& package, const string& cls,
+ boost::shared_ptr<ObjectId> oid);
+ AgentEventImpl::Ptr eventMethod(uint32_t num, const string& userId, const string& method,
+ boost::shared_ptr<ObjectId> oid, boost::shared_ptr<Value> argMap,
+ const SchemaObjectClass* objectClass);
+ void sendBufferLH(Buffer& buf, const string& destination, const string& routingKey);
+
+ void sendPackageIndicationLH(const string& packageName);
+ void sendClassIndicationLH(ClassKind kind, const string& packageName, const AgentClassKey& key);
+ void sendCommandCompleteLH(const string& exchange, const string& key, uint32_t seq,
+ uint32_t code = 0, const string& text = "OK");
+ void sendMethodErrorLH(uint32_t sequence, const string& key, uint32_t code, const string& text="");
+ void handleAttachResponse(Buffer& inBuffer);
+ void handlePackageRequest(Buffer& inBuffer);
+ void handleClassQuery(Buffer& inBuffer);
+ void handleSchemaRequest(Buffer& inBuffer, uint32_t sequence,
+ const string& replyToExchange, const string& replyToKey);
+ void handleGetQuery(Buffer& inBuffer, uint32_t sequence, const string& replyTo, const string& userId);
+ void handleMethodRequest(Buffer& inBuffer, uint32_t sequence, const string& replyTo, const string& userId);
+ void handleConsoleAddedIndication();
+ };
+}
+}
+
+const char* AgentImpl::QMF_EXCHANGE = "qpid.management";
+const char* AgentImpl::DIR_EXCHANGE = "amq.direct";
+const char* AgentImpl::BROKER_KEY = "broker";
+
+#define STRING_REF(s) {if (!s.empty()) item.s = const_cast<char*>(s.c_str());}
+
+AgentEvent AgentEventImpl::copy()
+{
+ AgentEvent item;
+
+ ::memset(&item, 0, sizeof(AgentEvent));
+ item.kind = kind;
+ item.sequence = sequence;
+ item.object = object;
+ item.objectId = objectId.get();
+ item.query = query.get();
+ item.arguments = arguments.get();
+ item.objectClass = objectClass;
+
+ STRING_REF(authUserId);
+ STRING_REF(authToken);
+ STRING_REF(name);
+ STRING_REF(exchange);
+ STRING_REF(bindingKey);
+
+ return item;
+}
+
+AgentImpl::AgentImpl(char* _label, bool i) :
+ label(_label), queueName("qmfa-"), internalStore(i), nextTransientId(1),
+ requestedBrokerBank(0), requestedAgentBank(0),
+ assignedBrokerBank(0), assignedAgentBank(0),
+ bootSequence(1), nextObjectId(1), nextContextNum(1)
+{
+ queueName += label;
+}
+
+AgentImpl::~AgentImpl()
+{
+}
+
+void AgentImpl::setStoreDir(const char* path)
+{
+ Mutex::ScopedLock _lock(lock);
+ if (path)
+ storeDir = path;
+ else
+ storeDir.clear();
+}
+
+void AgentImpl::setTransferDir(const char* path)
+{
+ Mutex::ScopedLock _lock(lock);
+ if (path)
+ transferDir = path;
+ else
+ transferDir.clear();
+}
+
+void AgentImpl::handleRcvMessage(Message& message)
+{
+ Buffer inBuffer(message.body, message.length);
+ uint8_t opcode;
+ uint32_t sequence;
+ string replyToExchange(message.replyExchange ? message.replyExchange : "");
+ string replyToKey(message.replyKey ? message.replyKey : "");
+ string userId(message.userId ? message.userId : "");
+
+ while (Protocol::checkHeader(inBuffer, &opcode, &sequence)) {
+ if (opcode == Protocol::OP_ATTACH_RESPONSE) handleAttachResponse(inBuffer);
+ else if (opcode == Protocol::OP_SCHEMA_REQUEST) handleSchemaRequest(inBuffer, sequence, replyToExchange, replyToKey);
+ else if (opcode == Protocol::OP_CONSOLE_ADDED_INDICATION) handleConsoleAddedIndication();
+ else if (opcode == Protocol::OP_GET_QUERY) handleGetQuery(inBuffer, sequence, replyToKey, userId);
+ else if (opcode == Protocol::OP_METHOD_REQUEST) handleMethodRequest(inBuffer, sequence, replyToKey, userId);
+ else {
+ QPID_LOG(error, "AgentImpl::handleRcvMessage invalid opcode=" << opcode);
+ break;
+ }
+ }
+}
+
+bool AgentImpl::getXmtMessage(Message& item) const
+{
+ Mutex::ScopedLock _lock(lock);
+ if (xmtQueue.empty())
+ return false;
+ item = xmtQueue.front()->copy();
+ return true;
+}
+
+void AgentImpl::popXmt()
+{
+ Mutex::ScopedLock _lock(lock);
+ if (!xmtQueue.empty())
+ xmtQueue.pop_front();
+}
+
+bool AgentImpl::getEvent(AgentEvent& event) const
+{
+ Mutex::ScopedLock _lock(lock);
+ if (eventQueue.empty())
+ return false;
+ event = eventQueue.front()->copy();
+ return true;
+}
+
+void AgentImpl::popEvent()
+{
+ Mutex::ScopedLock _lock(lock);
+ if (!eventQueue.empty())
+ eventQueue.pop_front();
+}
+
+void AgentImpl::newSession()
+{
+ Mutex::ScopedLock _lock(lock);
+ eventQueue.clear();
+ xmtQueue.clear();
+ eventQueue.push_back(eventDeclareQueue(queueName));
+ eventQueue.push_back(eventBind("amq.direct", queueName, queueName));
+ eventQueue.push_back(eventSetupComplete());
+}
+
+void AgentImpl::startProtocol()
+{
+ Mutex::ScopedLock _lock(lock);
+ char rawbuffer[512];
+ Buffer buffer(rawbuffer, 512);
+
+ Protocol::encodeHeader(buffer, Protocol::OP_ATTACH_REQUEST);
+ buffer.putShortString("qmfa");
+ systemId.encode(buffer);
+ buffer.putLong(requestedBrokerBank);
+ buffer.putLong(requestedAgentBank);
+ sendBufferLH(buffer, QMF_EXCHANGE, BROKER_KEY);
+ QPID_LOG(trace, "SENT AttachRequest: reqBroker=" << requestedBrokerBank <<
+ " reqAgent=" << requestedAgentBank);
+}
+
+void AgentImpl::heartbeat()
+{
+ Mutex::ScopedLock _lock(lock);
+ Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
+
+ Protocol::encodeHeader(buffer, Protocol::OP_HEARTBEAT_INDICATION);
+ buffer.putLongLong(uint64_t(Duration(now())));
+ stringstream key;
+ key << "console.heartbeat." << assignedBrokerBank << "." << assignedAgentBank;
+ sendBufferLH(buffer, QMF_EXCHANGE, key.str());
+ QPID_LOG(trace, "SENT HeartbeatIndication");
+}
+
+void AgentImpl::methodResponse(uint32_t sequence, uint32_t status, char* text,
+ const Value& argMap)
+{
+ Mutex::ScopedLock _lock(lock);
+ map<uint32_t, AgentQueryContext::Ptr>::iterator iter = contextMap.find(sequence);
+ if (iter == contextMap.end())
+ return;
+ AgentQueryContext::Ptr context = iter->second;
+ contextMap.erase(iter);
+
+ Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
+ Protocol::encodeHeader(buffer, Protocol::OP_METHOD_RESPONSE, context->sequence);
+ buffer.putLong(status);
+ buffer.putMediumString(text);
+ if (status == 0) {
+ for (vector<const SchemaArgument*>::const_iterator aIter = context->schemaMethod->impl->arguments.begin();
+ aIter != context->schemaMethod->impl->arguments.end(); aIter++) {
+ const SchemaArgument* schemaArg = *aIter;
+ if (schemaArg->getDirection() == DIR_OUT || schemaArg->getDirection() == DIR_IN_OUT) {
+ if (argMap.keyInMap(schemaArg->getName())) {
+ const Value* val = argMap.byKey(schemaArg->getName());
+ val->impl->encode(buffer);
+ } else {
+ Value val(schemaArg->getType());
+ val.impl->encode(buffer);
+ }
+ }
+ }
+ }
+ sendBufferLH(buffer, context->exchange, context->key);
+ QPID_LOG(trace, "SENT MethodResponse seq=" << context->sequence << " status=" << status << " text=" << text);
+}
+
+void AgentImpl::queryResponse(uint32_t sequence, Object& object, bool prop, bool stat)
+{
+ Mutex::ScopedLock _lock(lock);
+ map<uint32_t, AgentQueryContext::Ptr>::iterator iter = contextMap.find(sequence);
+ if (iter == contextMap.end())
+ return;
+ AgentQueryContext::Ptr context = iter->second;
+
+ Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
+ Protocol::encodeHeader(buffer, Protocol::OP_OBJECT_INDICATION, context->sequence);
+
+ object.impl->encodeSchemaKey(buffer);
+ object.impl->encodeManagedObjectData(buffer);
+ if (prop)
+ object.impl->encodeProperties(buffer);
+ if (stat)
+ object.impl->encodeStatistics(buffer);
+
+ sendBufferLH(buffer, context->exchange, context->key);
+ QPID_LOG(trace, "SENT ContentIndication seq=" << context->sequence);
+}
+
+void AgentImpl::queryComplete(uint32_t sequence)
+{
+ Mutex::ScopedLock _lock(lock);
+ map<uint32_t, AgentQueryContext::Ptr>::iterator iter = contextMap.find(sequence);
+ if (iter == contextMap.end())
+ return;
+
+ AgentQueryContext::Ptr context = iter->second;
+ contextMap.erase(iter);
+ sendCommandCompleteLH(context->exchange, context->key, context->sequence, 0, "OK");
+}
+
+void AgentImpl::registerClass(SchemaObjectClass* cls)
+{
+ Mutex::ScopedLock _lock(lock);
+
+ map<string, ClassMaps>::iterator iter = packages.find(cls->getClassKey()->getPackageName());
+ if (iter == packages.end()) {
+ packages[cls->getClassKey()->getPackageName()] = ClassMaps();
+ iter = packages.find(cls->getClassKey()->getPackageName());
+ // TODO: Indicate this package if connected
+ }
+
+ AgentClassKey key(cls->getClassKey()->getClassName(), cls->getClassKey()->getHash());
+ iter->second.objectClasses[key] = cls;
+
+ // TODO: Indicate this schema if connected.
+}
+
+void AgentImpl::registerClass(SchemaEventClass* cls)
+{
+ Mutex::ScopedLock _lock(lock);
+
+ map<string, ClassMaps>::iterator iter = packages.find(cls->getClassKey()->getPackageName());
+ if (iter == packages.end()) {
+ packages[cls->getClassKey()->getPackageName()] = ClassMaps();
+ iter = packages.find(cls->getClassKey()->getPackageName());
+ // TODO: Indicate this package if connected
+ }
+
+ AgentClassKey key(cls->getClassKey()->getClassName(), cls->getClassKey()->getHash());
+ iter->second.eventClasses[key] = cls;
+
+ // TODO: Indicate this schema if connected.
+}
+
+const ObjectId* AgentImpl::addObject(Object&, uint64_t)
+{
+ Mutex::ScopedLock _lock(lock);
+ return 0;
+}
+
+const ObjectId* AgentImpl::allocObjectId(uint64_t persistId)
+{
+ Mutex::ScopedLock _lock(lock);
+ uint16_t sequence = persistId ? 0 : bootSequence;
+ uint64_t objectNum = persistId ? persistId : nextObjectId++;
+
+ ObjectId* oid = ObjectIdImpl::factory(&attachment, 0, sequence, objectNum);
+ return oid;
+}
+
+const ObjectId* AgentImpl::allocObjectId(uint32_t persistIdLo, uint32_t persistIdHi)
+{
+ return allocObjectId(((uint64_t) persistIdHi) << 32 | (uint64_t) persistIdLo);
+}
+
+void AgentImpl::raiseEvent(Event&)
+{
+ Mutex::ScopedLock _lock(lock);
+}
+
+AgentEventImpl::Ptr AgentImpl::eventDeclareQueue(const string& name)
+{
+ AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::DECLARE_QUEUE));
+ event->name = name;
+
+ return event;
+}
+
+AgentEventImpl::Ptr AgentImpl::eventBind(const string& exchange, const string& queue,
+ const string& key)
+{
+ AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::BIND));
+ event->name = queue;
+ event->exchange = exchange;
+ event->bindingKey = key;
+
+ return event;
+}
+
+AgentEventImpl::Ptr AgentImpl::eventSetupComplete()
+{
+ AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::SETUP_COMPLETE));
+ return event;
+}
+
+AgentEventImpl::Ptr AgentImpl::eventQuery(uint32_t num, const string& userId, const string& package,
+ const string& cls, boost::shared_ptr<ObjectId> oid)
+{
+ AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::GET_QUERY));
+ event->sequence = num;
+ event->authUserId = userId;
+ if (oid.get())
+ event->query.reset(new Query(oid.get()));
+ else
+ event->query.reset(new Query(cls.c_str(), package.c_str()));
+ return event;
+}
+
+AgentEventImpl::Ptr AgentImpl::eventMethod(uint32_t num, const string& userId, const string& method,
+ boost::shared_ptr<ObjectId> oid, boost::shared_ptr<Value> argMap,
+ const SchemaObjectClass* objectClass)
+{
+ AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::METHOD_CALL));
+ event->sequence = num;
+ event->authUserId = userId;
+ event->name = method;
+ event->objectId = oid;
+ event->arguments = argMap;
+ event->objectClass = objectClass;
+ return event;
+}
+
+void AgentImpl::sendBufferLH(Buffer& buf, const string& destination, const string& routingKey)
+{
+ uint32_t length = buf.getPosition();
+ MessageImpl::Ptr message(new MessageImpl);
+
+ buf.reset();
+ buf.getRawData(message->body, length);
+ message->destination = destination;
+ message->routingKey = routingKey;
+ message->replyExchange = "amq.direct";
+ message->replyKey = queueName;
+
+ xmtQueue.push_back(message);
+}
+
+void AgentImpl::sendPackageIndicationLH(const string& packageName)
+{
+ Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
+ Protocol::encodeHeader(buffer, Protocol::OP_PACKAGE_INDICATION);
+ buffer.putShortString(packageName);
+ sendBufferLH(buffer, QMF_EXCHANGE, BROKER_KEY);
+ QPID_LOG(trace, "SENT PackageIndication: package_name=" << packageName);
+}
+
+void AgentImpl::sendClassIndicationLH(ClassKind kind, const string& packageName, const AgentClassKey& key)
+{
+ Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
+ Protocol::encodeHeader(buffer, Protocol::OP_CLASS_INDICATION);
+ buffer.putOctet((int) kind);
+ buffer.putShortString(packageName);
+ buffer.putShortString(key.name);
+ buffer.putBin128(const_cast<uint8_t*>(key.hash)); // const_cast needed for older Qpid libraries
+ sendBufferLH(buffer, QMF_EXCHANGE, BROKER_KEY);
+ QPID_LOG(trace, "SENT ClassIndication: package_name=" << packageName << " class_name=" << key.name);
+}
+
+void AgentImpl::sendCommandCompleteLH(const string& exchange, const string& replyToKey,
+ uint32_t sequence, uint32_t code, const string& text)
+{
+ Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
+ Protocol::encodeHeader(buffer, Protocol::OP_COMMAND_COMPLETE, sequence);
+ buffer.putLong(code);
+ buffer.putShortString(text);
+ sendBufferLH(buffer, exchange, replyToKey);
+ QPID_LOG(trace, "SENT CommandComplete: seq=" << sequence << " code=" << code << " text=" << text);
+}
+
+void AgentImpl::sendMethodErrorLH(uint32_t sequence, const string& key, uint32_t code, const string& text)
+{
+ Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
+ Protocol::encodeHeader(buffer, Protocol::OP_METHOD_RESPONSE, sequence);
+ buffer.putLong(code);
+
+ string fulltext;
+ switch (code) {
+ case MERR_UNKNOWN_PACKAGE: fulltext = "Unknown Package"; break;
+ case MERR_UNKNOWN_CLASS: fulltext = "Unknown Class"; break;
+ case MERR_UNKNOWN_METHOD: fulltext = "Unknown Method"; break;
+ case MERR_INTERNAL_ERROR: fulltext = "Internal Error"; break;
+ default: fulltext = "Unspecified Error"; break;
+ }
+
+ if (!text.empty()) {
+ fulltext += " (";
+ fulltext += text;
+ fulltext += ")";
+ }
+
+ buffer.putMediumString(fulltext);
+ sendBufferLH(buffer, DIR_EXCHANGE, key);
+ QPID_LOG(trace, "SENT MethodResponse: errorCode=" << code << " text=" << fulltext);
+}
+
+void AgentImpl::handleAttachResponse(Buffer& inBuffer)
+{
+ Mutex::ScopedLock _lock(lock);
+
+ assignedBrokerBank = inBuffer.getLong();
+ assignedAgentBank = inBuffer.getLong();
+
+ QPID_LOG(trace, "RCVD AttachResponse: broker=" << assignedBrokerBank << " agent=" << assignedAgentBank);
+
+ if ((assignedBrokerBank != requestedBrokerBank) ||
+ (assignedAgentBank != requestedAgentBank)) {
+ if (requestedAgentBank == 0) {
+ QPID_LOG(notice, "Initial object-id bank assigned: " << assignedBrokerBank << "." <<
+ assignedAgentBank);
+ } else {
+ QPID_LOG(warning, "Collision in object-id! New bank assigned: " << assignedBrokerBank <<
+ "." << assignedAgentBank);
+ }
+ //storeData(); // TODO
+ requestedBrokerBank = assignedBrokerBank;
+ requestedAgentBank = assignedAgentBank;
+ }
+
+ attachment.setBanks(assignedBrokerBank, assignedAgentBank);
+
+ // Bind to qpid.management to receive commands
+ stringstream key;
+ key << "agent." << assignedBrokerBank << "." << assignedAgentBank;
+ eventQueue.push_back(eventBind(QMF_EXCHANGE, queueName, key.str()));
+
+ // Send package indications for all local packages
+ for (map<string, ClassMaps>::iterator pIter = packages.begin();
+ pIter != packages.end();
+ pIter++) {
+ sendPackageIndicationLH(pIter->first);
+
+ // Send class indications for all local classes
+ ClassMaps cMap = pIter->second;
+ for (ObjectClassMap::iterator cIter = cMap.objectClasses.begin();
+ cIter != cMap.objectClasses.end(); cIter++)
+ sendClassIndicationLH(CLASS_OBJECT, pIter->first, cIter->first);
+ for (EventClassMap::iterator cIter = cMap.eventClasses.begin();
+ cIter != cMap.eventClasses.end(); cIter++)
+ sendClassIndicationLH(CLASS_EVENT, pIter->first, cIter->first);
+ }
+}
+
+void AgentImpl::handlePackageRequest(Buffer&)
+{
+ Mutex::ScopedLock _lock(lock);
+}
+
+void AgentImpl::handleClassQuery(Buffer&)
+{
+ Mutex::ScopedLock _lock(lock);
+}
+
+void AgentImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence,
+ const string& replyExchange, const string& replyKey)
+{
+ Mutex::ScopedLock _lock(lock);
+ string rExchange(replyExchange);
+ string rKey(replyKey);
+ string packageName;
+ inBuffer.getShortString(packageName);
+ AgentClassKey key(inBuffer);
+
+ if (rExchange.empty())
+ rExchange = QMF_EXCHANGE;
+ if (rKey.empty())
+ rKey = BROKER_KEY;
+
+ QPID_LOG(trace, "RCVD SchemaRequest: package=" << packageName << " class=" << key.name);
+
+ map<string, ClassMaps>::iterator pIter = packages.find(packageName);
+ if (pIter == packages.end()) {
+ sendCommandCompleteLH(rExchange, rKey, sequence, 1, "package not found");
+ return;
+ }
+
+ ClassMaps cMap = pIter->second;
+ ObjectClassMap::iterator ocIter = cMap.objectClasses.find(key);
+ if (ocIter != cMap.objectClasses.end()) {
+ SchemaObjectClass* oImpl = ocIter->second;
+ Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
+ Protocol::encodeHeader(buffer, Protocol::OP_SCHEMA_RESPONSE, sequence);
+ oImpl->impl->encode(buffer);
+ sendBufferLH(buffer, rExchange, rKey);
+ QPID_LOG(trace, "SENT SchemaResponse: (object) package=" << packageName << " class=" << key.name);
+ return;
+ }
+
+ EventClassMap::iterator ecIter = cMap.eventClasses.find(key);
+ if (ecIter != cMap.eventClasses.end()) {
+ SchemaEventClass* eImpl = ecIter->second;
+ Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
+ Protocol::encodeHeader(buffer, Protocol::OP_SCHEMA_RESPONSE, sequence);
+ eImpl->impl->encode(buffer);
+ sendBufferLH(buffer, rExchange, rKey);
+ QPID_LOG(trace, "SENT SchemaResponse: (event) package=" << packageName << " class=" << key.name);
+ return;
+ }
+
+ sendCommandCompleteLH(rExchange, rKey, sequence, 1, "class not found");
+}
+
+void AgentImpl::handleGetQuery(Buffer& inBuffer, uint32_t sequence, const string& replyTo, const string& userId)
+{
+ Mutex::ScopedLock _lock(lock);
+ FieldTable ft;
+ FieldTable::ValuePtr value;
+ map<string, ClassMaps>::const_iterator pIter = packages.end();
+ string pname;
+ string cname;
+ string oidRepr;
+ boost::shared_ptr<ObjectId> oid;
+
+ ft.decode(inBuffer);
+
+ QPID_LOG(trace, "RCVD GetQuery: seq=" << sequence << " map=" << ft);
+
+ value = ft.get("_package");
+ if (value.get() && value->convertsTo<string>()) {
+ pname = value->get<string>();
+ pIter = packages.find(pname);
+ if (pIter == packages.end()) {
+ sendCommandCompleteLH(DIR_EXCHANGE, replyTo, sequence);
+ return;
+ }
+ }
+
+ value = ft.get("_class");
+ if (value.get() && value->convertsTo<string>()) {
+ cname = value->get<string>();
+ // TODO - check for validity of class (in package or any package)
+ if (pIter == packages.end()) {
+ } else {
+
+ }
+ }
+
+ value = ft.get("_objectid");
+ if (value.get() && value->convertsTo<string>()) {
+ oidRepr = value->get<string>();
+ oid.reset(new ObjectId());
+ oid->impl->fromString(oidRepr);
+ }
+
+ AgentQueryContext::Ptr context(new AgentQueryContext);
+ uint32_t contextNum = nextContextNum++;
+ context->sequence = sequence;
+ context->exchange = DIR_EXCHANGE;
+ context->key = replyTo;
+ contextMap[contextNum] = context;
+
+ eventQueue.push_back(eventQuery(contextNum, userId, pname, cname, oid));
+}
+
+void AgentImpl::handleMethodRequest(Buffer& buffer, uint32_t sequence, const string& replyTo, const string& userId)
+{
+ Mutex::ScopedLock _lock(lock);
+ string pname;
+ string method;
+ boost::shared_ptr<ObjectId> oid(ObjectIdImpl::factory(buffer));
+ buffer.getShortString(pname);
+ AgentClassKey classKey(buffer);
+ buffer.getShortString(method);
+
+ QPID_LOG(trace, "RCVD MethodRequest seq=" << sequence << " method=" << method);
+
+ map<string, ClassMaps>::const_iterator pIter = packages.find(pname);
+ if (pIter == packages.end()) {
+ sendMethodErrorLH(sequence, replyTo, MERR_UNKNOWN_PACKAGE, pname);
+ return;
+ }
+
+ ObjectClassMap::const_iterator cIter = pIter->second.objectClasses.find(classKey);
+ if (cIter == pIter->second.objectClasses.end()) {
+ sendMethodErrorLH(sequence, replyTo, MERR_UNKNOWN_CLASS, classKey.repr());
+ return;
+ }
+
+ const SchemaObjectClass* schema = cIter->second;
+ vector<const SchemaMethod*>::const_iterator mIter = schema->impl->methods.begin();
+ for (; mIter != schema->impl->methods.end(); mIter++) {
+ if ((*mIter)->getName() == method)
+ break;
+ }
+
+ if (mIter == schema->impl->methods.end()) {
+ sendMethodErrorLH(sequence, replyTo, MERR_UNKNOWN_METHOD, method);
+ return;
+ }
+
+ const SchemaMethod* schemaMethod = *mIter;
+ boost::shared_ptr<Value> argMap(new Value(TYPE_MAP));
+ Value* value;
+ for (vector<const SchemaArgument*>::const_iterator aIter = schemaMethod->impl->arguments.begin();
+ aIter != schemaMethod->impl->arguments.end(); aIter++) {
+ const SchemaArgument* schemaArg = *aIter;
+ if (schemaArg->getDirection() == DIR_IN || schemaArg->getDirection() == DIR_IN_OUT)
+ value = ValueImpl::factory(schemaArg->getType(), buffer);
+ else
+ value = ValueImpl::factory(schemaArg->getType());
+ argMap->insert(schemaArg->getName(), value);
+ }
+
+ AgentQueryContext::Ptr context(new AgentQueryContext);
+ uint32_t contextNum = nextContextNum++;
+ context->sequence = sequence;
+ context->exchange = DIR_EXCHANGE;
+ context->key = replyTo;
+ context->schemaMethod = schemaMethod;
+ contextMap[contextNum] = context;
+
+ eventQueue.push_back(eventMethod(contextNum, userId, method, oid, argMap, schema));
+}
+
+void AgentImpl::handleConsoleAddedIndication()
+{
+ Mutex::ScopedLock _lock(lock);
+}
+
+//==================================================================
+// Wrappers
+//==================================================================
+
+Agent::Agent(char* label, bool internalStore) { impl = new AgentImpl(label, internalStore); }
+Agent::~Agent() { delete impl; }
+void Agent::setStoreDir(const char* path) { impl->setStoreDir(path); }
+void Agent::setTransferDir(const char* path) { impl->setTransferDir(path); }
+void Agent::handleRcvMessage(Message& message) { impl->handleRcvMessage(message); }
+bool Agent::getXmtMessage(Message& item) const { return impl->getXmtMessage(item); }
+void Agent::popXmt() { impl->popXmt(); }
+bool Agent::getEvent(AgentEvent& event) const { return impl->getEvent(event); }
+void Agent::popEvent() { impl->popEvent(); }
+void Agent::newSession() { impl->newSession(); }
+void Agent::startProtocol() { impl->startProtocol(); }
+void Agent::heartbeat() { impl->heartbeat(); }
+void Agent::methodResponse(uint32_t sequence, uint32_t status, char* text, const Value& arguments) { impl->methodResponse(sequence, status, text, arguments); }
+void Agent::queryResponse(uint32_t sequence, Object& object, bool prop, bool stat) { impl->queryResponse(sequence, object, prop, stat); }
+void Agent::queryComplete(uint32_t sequence) { impl->queryComplete(sequence); }
+void Agent::registerClass(SchemaObjectClass* cls) { impl->registerClass(cls); }
+void Agent::registerClass(SchemaEventClass* cls) { impl->registerClass(cls); }
+const ObjectId* Agent::addObject(Object& obj, uint64_t persistId) { return impl->addObject(obj, persistId); }
+const ObjectId* Agent::allocObjectId(uint64_t persistId) { return impl->allocObjectId(persistId); }
+const ObjectId* Agent::allocObjectId(uint32_t persistIdLo, uint32_t persistIdHi) { return impl->allocObjectId(persistIdLo, persistIdHi); }
+void Agent::raiseEvent(Event& event) { impl->raiseEvent(event); }
+
diff --git a/cpp/src/qmf/engine/BrokerProxyImpl.cpp b/cpp/src/qmf/engine/BrokerProxyImpl.cpp
new file mode 100644
index 0000000000..2d955b0c26
--- /dev/null
+++ b/cpp/src/qmf/engine/BrokerProxyImpl.cpp
@@ -0,0 +1,777 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/BrokerProxyImpl.h"
+#include "qmf/engine/ConsoleImpl.h"
+#include "qmf/engine/Protocol.h"
+#include "qpid/Address.h"
+#include "qpid/sys/SystemInfo.h"
+#include <qpid/log/Statement.h>
+#include <qpid/StringUtils.h>
+#include <string.h>
+#include <iostream>
+#include <fstream>
+
+using namespace std;
+using namespace qmf::engine;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+namespace {
+ const char* QMF_EXCHANGE = "qpid.management";
+ const char* DIR_EXCHANGE = "amq.direct";
+ const char* BROKER_KEY = "broker";
+ const char* BROKER_PACKAGE = "org.apache.qpid.broker";
+ const char* AGENT_CLASS = "agent";
+ const char* BROKER_AGENT_KEY = "agent.1.0";
+}
+
+const Object* QueryResponseImpl::getObject(uint32_t idx) const
+{
+ vector<ObjectPtr>::const_iterator iter = results.begin();
+
+ while (idx > 0) {
+ if (iter == results.end())
+ return 0;
+ iter++;
+ idx--;
+ }
+
+ return iter->get();
+}
+
+#define STRING_REF(s) {if (!s.empty()) item.s = const_cast<char*>(s.c_str());}
+
+BrokerEvent BrokerEventImpl::copy()
+{
+ BrokerEvent item;
+
+ ::memset(&item, 0, sizeof(BrokerEvent));
+ item.kind = kind;
+
+ STRING_REF(name);
+ STRING_REF(exchange);
+ STRING_REF(bindingKey);
+ item.context = context;
+ item.queryResponse = queryResponse.get();
+ item.methodResponse = methodResponse.get();
+
+ return item;
+}
+
+BrokerProxyImpl::BrokerProxyImpl(BrokerProxy& pub, Console& _console) : publicObject(pub), console(_console)
+{
+ stringstream qn;
+ qpid::TcpAddress addr;
+
+ SystemInfo::getLocalHostname(addr);
+ qn << "qmfc-" << SystemInfo::getProcessName() << "-" << addr << "-" << SystemInfo::getProcessId();
+ queueName = qn.str();
+
+ seqMgr.setUnsolicitedContext(SequenceContext::Ptr(new StaticContext(*this)));
+}
+
+void BrokerProxyImpl::sessionOpened(SessionHandle& /*sh*/)
+{
+ Mutex::ScopedLock _lock(lock);
+ agentList.clear();
+ eventQueue.clear();
+ xmtQueue.clear();
+ eventQueue.push_back(eventDeclareQueue(queueName));
+ eventQueue.push_back(eventBind(DIR_EXCHANGE, queueName, queueName));
+ eventQueue.push_back(eventSetupComplete());
+
+ // TODO: Store session handle
+}
+
+void BrokerProxyImpl::sessionClosed()
+{
+ Mutex::ScopedLock _lock(lock);
+ agentList.clear();
+ eventQueue.clear();
+ xmtQueue.clear();
+}
+
+void BrokerProxyImpl::startProtocol()
+{
+ AgentProxyPtr agent(AgentProxyImpl::factory(console, publicObject, 0, "Agent embedded in broker"));
+ {
+ Mutex::ScopedLock _lock(lock);
+ char rawbuffer[512];
+ Buffer buffer(rawbuffer, 512);
+
+ agentList[0] = agent;
+
+ requestsOutstanding = 1;
+ topicBound = false;
+ uint32_t sequence(seqMgr.reserve());
+ Protocol::encodeHeader(buffer, Protocol::OP_BROKER_REQUEST, sequence);
+ sendBufferLH(buffer, QMF_EXCHANGE, BROKER_KEY);
+ QPID_LOG(trace, "SENT BrokerRequest seq=" << sequence);
+ }
+
+ console.impl->eventAgentAdded(agent);
+}
+
+void BrokerProxyImpl::sendBufferLH(Buffer& buf, const string& destination, const string& routingKey)
+{
+ uint32_t length = buf.getPosition();
+ MessageImpl::Ptr message(new MessageImpl);
+
+ buf.reset();
+ buf.getRawData(message->body, length);
+ message->destination = destination;
+ message->routingKey = routingKey;
+ message->replyExchange = DIR_EXCHANGE;
+ message->replyKey = queueName;
+
+ xmtQueue.push_back(message);
+}
+
+void BrokerProxyImpl::handleRcvMessage(Message& message)
+{
+ Buffer inBuffer(message.body, message.length);
+ uint8_t opcode;
+ uint32_t sequence;
+
+ while (Protocol::checkHeader(inBuffer, &opcode, &sequence))
+ seqMgr.dispatch(opcode, sequence, message.routingKey ? string(message.routingKey) : string(), inBuffer);
+}
+
+bool BrokerProxyImpl::getXmtMessage(Message& item) const
+{
+ Mutex::ScopedLock _lock(lock);
+ if (xmtQueue.empty())
+ return false;
+ item = xmtQueue.front()->copy();
+ return true;
+}
+
+void BrokerProxyImpl::popXmt()
+{
+ Mutex::ScopedLock _lock(lock);
+ if (!xmtQueue.empty())
+ xmtQueue.pop_front();
+}
+
+bool BrokerProxyImpl::getEvent(BrokerEvent& event) const
+{
+ Mutex::ScopedLock _lock(lock);
+ if (eventQueue.empty())
+ return false;
+ event = eventQueue.front()->copy();
+ return true;
+}
+
+void BrokerProxyImpl::popEvent()
+{
+ Mutex::ScopedLock _lock(lock);
+ if (!eventQueue.empty())
+ eventQueue.pop_front();
+}
+
+uint32_t BrokerProxyImpl::agentCount() const
+{
+ Mutex::ScopedLock _lock(lock);
+ return agentList.size();
+}
+
+const AgentProxy* BrokerProxyImpl::getAgent(uint32_t idx) const
+{
+ Mutex::ScopedLock _lock(lock);
+ for (map<uint32_t, AgentProxyPtr>::const_iterator iter = agentList.begin();
+ iter != agentList.end(); iter++)
+ if (idx-- == 0)
+ return iter->second.get();
+ return 0;
+}
+
+void BrokerProxyImpl::sendQuery(const Query& query, void* context, const AgentProxy* agent)
+{
+ SequenceContext::Ptr queryContext(new QueryContext(*this, context));
+ Mutex::ScopedLock _lock(lock);
+ bool sent = false;
+ if (agent != 0) {
+ if (sendGetRequestLH(queryContext, query, agent))
+ sent = true;
+ } else {
+ // TODO (optimization) only send queries to agents that have the requested class+package
+ for (map<uint32_t, AgentProxyPtr>::const_iterator iter = agentList.begin();
+ iter != agentList.end(); iter++) {
+ if (sendGetRequestLH(queryContext, query, iter->second.get()))
+ sent = true;
+ }
+ }
+
+ if (!sent) {
+ queryContext->reserve();
+ queryContext->release();
+ }
+}
+
+bool BrokerProxyImpl::sendGetRequestLH(SequenceContext::Ptr queryContext, const Query& query, const AgentProxy* agent)
+{
+ if (query.impl->singleAgent()) {
+ if (query.impl->agentBank() != agent->getAgentBank())
+ return false;
+ }
+ stringstream key;
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t sequence(seqMgr.reserve(queryContext));
+ agent->impl->addSequence(sequence);
+
+ Protocol::encodeHeader(outBuffer, Protocol::OP_GET_QUERY, sequence);
+ query.impl->encode(outBuffer);
+ key << "agent.1." << agent->impl->agentBank;
+ sendBufferLH(outBuffer, QMF_EXCHANGE, key.str());
+ QPID_LOG(trace, "SENT GetQuery seq=" << sequence << " key=" << key.str());
+ return true;
+}
+
+string BrokerProxyImpl::encodeMethodArguments(const SchemaMethod* schema, const Value* argmap, Buffer& buffer)
+{
+ int argCount = schema->getArgumentCount();
+
+ if (argmap == 0 || !argmap->isMap())
+ return string("Arguments must be in a map value");
+
+ for (int aIdx = 0; aIdx < argCount; aIdx++) {
+ const SchemaArgument* arg(schema->getArgument(aIdx));
+ if (arg->getDirection() == DIR_IN || arg->getDirection() == DIR_IN_OUT) {
+ if (argmap->keyInMap(arg->getName())) {
+ const Value* argVal(argmap->byKey(arg->getName()));
+ if (argVal->getType() != arg->getType())
+ return string("Argument is the wrong type: ") + arg->getName();
+ argVal->impl->encode(buffer);
+ } else {
+ Value defaultValue(arg->getType());
+ defaultValue.impl->encode(buffer);
+ }
+ }
+ }
+
+ return string();
+}
+
+void BrokerProxyImpl::sendMethodRequest(ObjectId* oid, const SchemaObjectClass* cls,
+ const string& methodName, const Value* args, void* userContext)
+{
+ int methodCount = cls->getMethodCount();
+ int idx;
+ for (idx = 0; idx < methodCount; idx++) {
+ const SchemaMethod* method = cls->getMethod(idx);
+ if (string(method->getName()) == methodName) {
+ Mutex::ScopedLock _lock(lock);
+ SequenceContext::Ptr methodContext(new MethodContext(*this, userContext, method));
+ stringstream key;
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t sequence(seqMgr.reserve(methodContext));
+
+ Protocol::encodeHeader(outBuffer, Protocol::OP_METHOD_REQUEST, sequence);
+ oid->impl->encode(outBuffer);
+ cls->getClassKey()->impl->encode(outBuffer);
+ outBuffer.putShortString(methodName);
+
+ string argErrorString = encodeMethodArguments(method, args, outBuffer);
+ if (argErrorString.empty()) {
+ key << "agent.1." << oid->impl->getAgentBank();
+ sendBufferLH(outBuffer, QMF_EXCHANGE, key.str());
+ QPID_LOG(trace, "SENT MethodRequest seq=" << sequence << " method=" << methodName << " key=" << key.str());
+ } else {
+ MethodResponsePtr argError(MethodResponseImpl::factory(1, argErrorString));
+ eventQueue.push_back(eventMethodResponse(userContext, argError));
+ }
+ return;
+ }
+ }
+
+ MethodResponsePtr error(MethodResponseImpl::factory(1, string("Unknown method: ") + methodName));
+ Mutex::ScopedLock _lock(lock);
+ eventQueue.push_back(eventMethodResponse(userContext, error));
+}
+
+void BrokerProxyImpl::addBinding(const string& exchange, const string& key)
+{
+ Mutex::ScopedLock _lock(lock);
+ eventQueue.push_back(eventBind(exchange, queueName, key));
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventDeclareQueue(const string& queueName)
+{
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::DECLARE_QUEUE));
+ event->name = queueName;
+ return event;
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventBind(const string& exchange, const string& queue, const string& key)
+{
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::BIND));
+ event->name = queue;
+ event->exchange = exchange;
+ event->bindingKey = key;
+
+ return event;
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventSetupComplete()
+{
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::SETUP_COMPLETE));
+ return event;
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventStable()
+{
+ QPID_LOG(trace, "Console Link to Broker Stable");
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::STABLE));
+ return event;
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventQueryComplete(void* context, QueryResponsePtr response)
+{
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::QUERY_COMPLETE));
+ event->context = context;
+ event->queryResponse = response;
+ return event;
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventMethodResponse(void* context, MethodResponsePtr response)
+{
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::METHOD_RESPONSE));
+ event->context = context;
+ event->methodResponse = response;
+ return event;
+}
+
+void BrokerProxyImpl::handleBrokerResponse(Buffer& inBuffer, uint32_t seq)
+{
+ brokerId.decode(inBuffer);
+ QPID_LOG(trace, "RCVD BrokerResponse seq=" << seq << " brokerId=" << brokerId);
+ Mutex::ScopedLock _lock(lock);
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t sequence(seqMgr.reserve());
+ incOutstandingLH();
+ Protocol::encodeHeader(outBuffer, Protocol::OP_PACKAGE_REQUEST, sequence);
+ sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_KEY);
+ QPID_LOG(trace, "SENT PackageRequest seq=" << sequence);
+}
+
+void BrokerProxyImpl::handlePackageIndication(Buffer& inBuffer, uint32_t seq)
+{
+ string package;
+
+ inBuffer.getShortString(package);
+ QPID_LOG(trace, "RCVD PackageIndication seq=" << seq << " package=" << package);
+ console.impl->learnPackage(package);
+
+ Mutex::ScopedLock _lock(lock);
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t sequence(seqMgr.reserve());
+ incOutstandingLH();
+ Protocol::encodeHeader(outBuffer, Protocol::OP_CLASS_QUERY, sequence);
+ outBuffer.putShortString(package);
+ sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_KEY);
+ QPID_LOG(trace, "SENT ClassQuery seq=" << sequence << " package=" << package);
+}
+
+void BrokerProxyImpl::handleCommandComplete(Buffer& inBuffer, uint32_t seq)
+{
+ string text;
+ uint32_t code = inBuffer.getLong();
+ inBuffer.getShortString(text);
+ QPID_LOG(trace, "RCVD CommandComplete seq=" << seq << " code=" << code << " text=" << text);
+}
+
+void BrokerProxyImpl::handleClassIndication(Buffer& inBuffer, uint32_t seq)
+{
+ uint8_t kind = inBuffer.getOctet();
+ auto_ptr<SchemaClassKey> classKey(SchemaClassKeyImpl::factory(inBuffer));
+
+ QPID_LOG(trace, "RCVD ClassIndication seq=" << seq << " kind=" << (int) kind << " key=" << classKey->impl->str());
+
+ if (!console.impl->haveClass(classKey.get())) {
+ Mutex::ScopedLock _lock(lock);
+ incOutstandingLH();
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t sequence(seqMgr.reserve());
+ Protocol::encodeHeader(outBuffer, Protocol::OP_SCHEMA_REQUEST, sequence);
+ classKey->impl->encode(outBuffer);
+ sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_KEY);
+ QPID_LOG(trace, "SENT SchemaRequest seq=" << sequence <<" key=" << classKey->impl->str());
+ }
+}
+
+MethodResponsePtr BrokerProxyImpl::handleMethodResponse(Buffer& inBuffer, uint32_t seq, const SchemaMethod* schema)
+{
+ MethodResponsePtr response(MethodResponseImpl::factory(inBuffer, schema));
+
+ QPID_LOG(trace, "RCVD MethodResponse seq=" << seq << " status=" << response->getStatus() << " text=" <<
+ response->getException()->asString());
+
+ return response;
+}
+
+void BrokerProxyImpl::handleHeartbeatIndication(Buffer& inBuffer, uint32_t seq, const string& routingKey)
+{
+ vector<string> tokens = qpid::split(routingKey, ".");
+ uint32_t agentBank;
+ uint64_t timestamp;
+
+ if (routingKey.empty() || tokens.size() != 4)
+ agentBank = 0;
+ else
+ agentBank = ::atoi(tokens[3].c_str());
+
+ timestamp = inBuffer.getLongLong();
+ map<uint32_t, AgentProxyPtr>::const_iterator iter = agentList.find(agentBank);
+ if (iter != agentList.end()) {
+ console.impl->eventAgentHeartbeat(iter->second, timestamp);
+ }
+ QPID_LOG(trace, "RCVD HeartbeatIndication seq=" << seq << " agentBank=" << agentBank);
+}
+
+void BrokerProxyImpl::handleEventIndication(Buffer& /*inBuffer*/, uint32_t /*seq*/)
+{
+ // TODO
+}
+
+void BrokerProxyImpl::handleSchemaResponse(Buffer& inBuffer, uint32_t seq)
+{
+ SchemaObjectClass* oClassPtr;
+ SchemaEventClass* eClassPtr;
+ uint8_t kind = inBuffer.getOctet();
+ const SchemaClassKey* key;
+ if (kind == CLASS_OBJECT) {
+ oClassPtr = SchemaObjectClassImpl::factory(inBuffer);
+ console.impl->learnClass(oClassPtr);
+ key = oClassPtr->getClassKey();
+ QPID_LOG(trace, "RCVD SchemaResponse seq=" << seq << " kind=object key=" << key->impl->str());
+
+ //
+ // If we have just learned about the org.apache.qpid.broker:agent class, send a get
+ // request for the current list of agents so we can have it on-hand before we declare
+ // this session "stable".
+ //
+ if (key->impl->getClassName() == AGENT_CLASS && key->impl->getPackageName() == BROKER_PACKAGE) {
+ Mutex::ScopedLock _lock(lock);
+ incOutstandingLH();
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t sequence(seqMgr.reserve());
+ Protocol::encodeHeader(outBuffer, Protocol::OP_GET_QUERY, sequence);
+ FieldTable ft;
+ ft.setString("_class", AGENT_CLASS);
+ ft.setString("_package", BROKER_PACKAGE);
+ ft.encode(outBuffer);
+ sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_AGENT_KEY);
+ QPID_LOG(trace, "SENT GetQuery seq=" << sequence << " key=" << BROKER_AGENT_KEY);
+ }
+ } else if (kind == CLASS_EVENT) {
+ eClassPtr = SchemaEventClassImpl::factory(inBuffer);
+ console.impl->learnClass(eClassPtr);
+ key = eClassPtr->getClassKey();
+ QPID_LOG(trace, "RCVD SchemaResponse seq=" << seq << " kind=event key=" << key->impl->str());
+ }
+ else {
+ QPID_LOG(error, "BrokerProxyImpl::handleSchemaResponse received unknown class kind: " << (int) kind);
+ }
+}
+
+ObjectPtr BrokerProxyImpl::handleObjectIndication(Buffer& inBuffer, uint32_t seq, bool prop, bool stat)
+{
+ auto_ptr<SchemaClassKey> classKey(SchemaClassKeyImpl::factory(inBuffer));
+ QPID_LOG(trace, "RCVD ObjectIndication seq=" << seq << " key=" << classKey->impl->str());
+
+ SchemaObjectClass* schema = console.impl->getSchema(classKey.get());
+ if (schema == 0) {
+ QPID_LOG(trace, "No Schema Found for ObjectIndication. seq=" << seq << " key=" << classKey->impl->str());
+ return ObjectPtr();
+ }
+
+ ObjectPtr optr(ObjectImpl::factory(schema, this, inBuffer, prop, stat, true));
+ if (prop && classKey->impl->getPackageName() == BROKER_PACKAGE && classKey->impl->getClassName() == AGENT_CLASS) {
+ //
+ // We've intercepted information about a remote agent... update the agent list accordingly
+ //
+ updateAgentList(optr);
+ }
+ return optr;
+}
+
+void BrokerProxyImpl::updateAgentList(ObjectPtr obj)
+{
+ Value* value = obj->getValue("agentBank");
+ Mutex::ScopedLock _lock(lock);
+ if (value != 0 && value->isUint()) {
+ uint32_t agentBank = value->asUint();
+ if (obj->isDeleted()) {
+ map<uint32_t, AgentProxyPtr>::iterator iter = agentList.find(agentBank);
+ if (iter != agentList.end()) {
+ AgentProxyPtr agent(iter->second);
+ console.impl->eventAgentDeleted(agent);
+ agentList.erase(agentBank);
+ QPID_LOG(trace, "Agent at bank " << agentBank << " removed from agent list");
+
+ //
+ // Release all sequence numbers for requests in-flight to this agent.
+ // Since the agent is no longer connected, these requests would not
+ // otherwise complete.
+ //
+ agent->impl->releaseInFlight(seqMgr);
+ }
+ } else {
+ Value* str = obj->getValue("label");
+ string label;
+ if (str != 0 && str->isString())
+ label = str->asString();
+ map<uint32_t, AgentProxyPtr>::const_iterator iter = agentList.find(agentBank);
+ if (iter == agentList.end()) {
+ AgentProxyPtr agent(AgentProxyImpl::factory(console, publicObject, agentBank, label));
+ agentList[agentBank] = agent;
+ console.impl->eventAgentAdded(agent);
+ QPID_LOG(trace, "Agent '" << label << "' found at bank " << agentBank);
+ }
+ }
+ }
+}
+
+void BrokerProxyImpl::incOutstandingLH()
+{
+ requestsOutstanding++;
+}
+
+void BrokerProxyImpl::decOutstanding()
+{
+ Mutex::ScopedLock _lock(lock);
+ requestsOutstanding--;
+ if (requestsOutstanding == 0 && !topicBound) {
+ topicBound = true;
+ for (vector<pair<string, string> >::const_iterator iter = console.impl->bindingList.begin();
+ iter != console.impl->bindingList.end(); iter++) {
+ string exchange(iter->first.empty() ? QMF_EXCHANGE : iter->first);
+ string key(iter->second);
+ eventQueue.push_back(eventBind(exchange, queueName, key));
+ }
+ eventQueue.push_back(eventStable());
+ }
+}
+
+MethodResponseImpl::MethodResponseImpl(const MethodResponseImpl& from) :
+ status(from.status), schema(from.schema)
+{
+ if (from.exception.get())
+ exception.reset(new Value(*(from.exception)));
+ if (from.arguments.get())
+ arguments.reset(new Value(*(from.arguments)));
+}
+
+MethodResponseImpl::MethodResponseImpl(Buffer& buf, const SchemaMethod* s) : schema(s)
+{
+ string text;
+
+ status = buf.getLong();
+ buf.getMediumString(text);
+ exception.reset(new Value(TYPE_LSTR));
+ exception->setString(text.c_str());
+
+ if (status != 0)
+ return;
+
+ arguments.reset(new Value(TYPE_MAP));
+ int argCount(schema->getArgumentCount());
+ for (int idx = 0; idx < argCount; idx++) {
+ const SchemaArgument* arg = schema->getArgument(idx);
+ if (arg->getDirection() == DIR_OUT || arg->getDirection() == DIR_IN_OUT) {
+ Value* value(ValueImpl::factory(arg->getType(), buf));
+ arguments->insert(arg->getName(), value);
+ }
+ }
+}
+
+MethodResponseImpl::MethodResponseImpl(uint32_t s, const string& text) : schema(0)
+{
+ status = s;
+ exception.reset(new Value(TYPE_LSTR));
+ exception->setString(text.c_str());
+}
+
+MethodResponse* MethodResponseImpl::factory(Buffer& buf, const SchemaMethod* schema)
+{
+ MethodResponseImpl* impl(new MethodResponseImpl(buf, schema));
+ return new MethodResponse(impl);
+}
+
+MethodResponse* MethodResponseImpl::factory(uint32_t status, const std::string& text)
+{
+ MethodResponseImpl* impl(new MethodResponseImpl(status, text));
+ return new MethodResponse(impl);
+}
+
+bool StaticContext::handleMessage(uint8_t opcode, uint32_t sequence, const string& routingKey, Buffer& buffer)
+{
+ ObjectPtr object;
+ bool completeContext = false;
+
+ if (opcode == Protocol::OP_BROKER_RESPONSE) {
+ broker.handleBrokerResponse(buffer, sequence);
+ completeContext = true;
+ }
+ else if (opcode == Protocol::OP_COMMAND_COMPLETE) {
+ broker.handleCommandComplete(buffer, sequence);
+ completeContext = true;
+ }
+ else if (opcode == Protocol::OP_SCHEMA_RESPONSE) {
+ broker.handleSchemaResponse(buffer, sequence);
+ completeContext = true;
+ }
+ else if (opcode == Protocol::OP_PACKAGE_INDICATION)
+ broker.handlePackageIndication(buffer, sequence);
+ else if (opcode == Protocol::OP_CLASS_INDICATION)
+ broker.handleClassIndication(buffer, sequence);
+ else if (opcode == Protocol::OP_HEARTBEAT_INDICATION)
+ broker.handleHeartbeatIndication(buffer, sequence, routingKey);
+ else if (opcode == Protocol::OP_EVENT_INDICATION)
+ broker.handleEventIndication(buffer, sequence);
+ else if (opcode == Protocol::OP_PROPERTY_INDICATION) {
+ object = broker.handleObjectIndication(buffer, sequence, true, false);
+ broker.console.impl->eventObjectUpdate(object, true, false);
+ }
+ else if (opcode == Protocol::OP_STATISTIC_INDICATION) {
+ object = broker.handleObjectIndication(buffer, sequence, false, true);
+ broker.console.impl->eventObjectUpdate(object, false, true);
+ }
+ else if (opcode == Protocol::OP_OBJECT_INDICATION) {
+ object = broker.handleObjectIndication(buffer, sequence, true, true);
+ broker.console.impl->eventObjectUpdate(object, true, true);
+ }
+ else {
+ QPID_LOG(trace, "StaticContext::handleMessage invalid opcode: " << opcode);
+ completeContext = true;
+ }
+
+ return completeContext;
+}
+
+void QueryContext::reserve()
+{
+ Mutex::ScopedLock _lock(lock);
+ requestsOutstanding++;
+}
+
+void QueryContext::release()
+{
+ {
+ Mutex::ScopedLock _lock(lock);
+ if (--requestsOutstanding > 0)
+ return;
+ }
+
+ Mutex::ScopedLock _block(broker.lock);
+ broker.eventQueue.push_back(broker.eventQueryComplete(userContext, queryResponse));
+}
+
+bool QueryContext::handleMessage(uint8_t opcode, uint32_t sequence, const string& /*routingKey*/, Buffer& buffer)
+{
+ bool completeContext = false;
+ ObjectPtr object;
+
+ if (opcode == Protocol::OP_COMMAND_COMPLETE) {
+ broker.handleCommandComplete(buffer, sequence);
+ completeContext = true;
+
+ //
+ // Visit each agent and remove the sequence from that agent's in-flight list.
+ // This could be made more efficient because only one agent will have this sequence
+ // in its list.
+ //
+ map<uint32_t, AgentProxyPtr> copy;
+ {
+ Mutex::ScopedLock _block(broker.lock);
+ copy = broker.agentList;
+ }
+ for (map<uint32_t, AgentProxyPtr>::iterator iter = copy.begin(); iter != copy.end(); iter++)
+ iter->second->impl->delSequence(sequence);
+ }
+ else if (opcode == Protocol::OP_OBJECT_INDICATION) {
+ object = broker.handleObjectIndication(buffer, sequence, true, true);
+ if (object.get() != 0)
+ queryResponse->impl->results.push_back(object);
+ }
+ else {
+ QPID_LOG(trace, "QueryContext::handleMessage invalid opcode: " << opcode);
+ completeContext = true;
+ }
+
+ return completeContext;
+}
+
+void MethodContext::release()
+{
+ Mutex::ScopedLock _block(broker.lock);
+ broker.eventQueue.push_back(broker.eventMethodResponse(userContext, methodResponse));
+}
+
+bool MethodContext::handleMessage(uint8_t opcode, uint32_t sequence, const string& /*routingKey*/, Buffer& buffer)
+{
+ if (opcode == Protocol::OP_METHOD_RESPONSE)
+ methodResponse = broker.handleMethodResponse(buffer, sequence, schema);
+ else
+ QPID_LOG(trace, "QueryContext::handleMessage invalid opcode: " << opcode);
+
+ return true;
+}
+
+
+//==================================================================
+// Wrappers
+//==================================================================
+
+AgentProxy::AgentProxy(AgentProxyImpl* i) : impl(i) {}
+AgentProxy::AgentProxy(const AgentProxy& from) : impl(new AgentProxyImpl(*(from.impl))) {}
+AgentProxy::~AgentProxy() { delete impl; }
+const char* AgentProxy::getLabel() const { return impl->getLabel().c_str(); }
+uint32_t AgentProxy::getBrokerBank() const { return impl->getBrokerBank(); }
+uint32_t AgentProxy::getAgentBank() const { return impl->getAgentBank(); }
+
+BrokerProxy::BrokerProxy(Console& console) : impl(new BrokerProxyImpl(*this, console)) {}
+BrokerProxy::~BrokerProxy() { delete impl; }
+void BrokerProxy::sessionOpened(SessionHandle& sh) { impl->sessionOpened(sh); }
+void BrokerProxy::sessionClosed() { impl->sessionClosed(); }
+void BrokerProxy::startProtocol() { impl->startProtocol(); }
+void BrokerProxy::handleRcvMessage(Message& message) { impl->handleRcvMessage(message); }
+bool BrokerProxy::getXmtMessage(Message& item) const { return impl->getXmtMessage(item); }
+void BrokerProxy::popXmt() { impl->popXmt(); }
+bool BrokerProxy::getEvent(BrokerEvent& event) const { return impl->getEvent(event); }
+void BrokerProxy::popEvent() { impl->popEvent(); }
+uint32_t BrokerProxy::agentCount() const { return impl->agentCount(); }
+const AgentProxy* BrokerProxy::getAgent(uint32_t idx) const { return impl->getAgent(idx); }
+void BrokerProxy::sendQuery(const Query& query, void* context, const AgentProxy* agent) { impl->sendQuery(query, context, agent); }
+
+MethodResponse::MethodResponse(const MethodResponse& from) : impl(new MethodResponseImpl(*(from.impl))) {}
+MethodResponse::MethodResponse(MethodResponseImpl* i) : impl(i) {}
+MethodResponse::~MethodResponse() {}
+uint32_t MethodResponse::getStatus() const { return impl->getStatus(); }
+const Value* MethodResponse::getException() const { return impl->getException(); }
+const Value* MethodResponse::getArgs() const { return impl->getArgs(); }
+
+QueryResponse::QueryResponse(QueryResponseImpl* i) : impl(i) {}
+QueryResponse::~QueryResponse() {}
+uint32_t QueryResponse::getStatus() const { return impl->getStatus(); }
+const Value* QueryResponse::getException() const { return impl->getException(); }
+uint32_t QueryResponse::getObjectCount() const { return impl->getObjectCount(); }
+const Object* QueryResponse::getObject(uint32_t idx) const { return impl->getObject(idx); }
+
diff --git a/cpp/src/qmf/engine/BrokerProxyImpl.h b/cpp/src/qmf/engine/BrokerProxyImpl.h
new file mode 100644
index 0000000000..b651b52345
--- /dev/null
+++ b/cpp/src/qmf/engine/BrokerProxyImpl.h
@@ -0,0 +1,239 @@
+#ifndef _QmfEngineBrokerProxyImpl_
+#define _QmfEngineBrokerProxyImpl_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Console.h"
+#include "qmf/engine/ObjectImpl.h"
+#include "qmf/engine/SchemaImpl.h"
+#include "qmf/engine/ValueImpl.h"
+#include "qmf/engine/QueryImpl.h"
+#include "qmf/engine/SequenceManager.h"
+#include "qmf/engine/MessageImpl.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/sys/Mutex.h"
+#include "boost/shared_ptr.hpp"
+#include "boost/noncopyable.hpp"
+#include <memory>
+#include <string>
+#include <deque>
+#include <map>
+#include <set>
+#include <vector>
+
+namespace qmf {
+namespace engine {
+
+ typedef boost::shared_ptr<MethodResponse> MethodResponsePtr;
+ struct MethodResponseImpl {
+ uint32_t status;
+ const SchemaMethod* schema;
+ std::auto_ptr<Value> exception;
+ std::auto_ptr<Value> arguments;
+
+ MethodResponseImpl(const MethodResponseImpl& from);
+ MethodResponseImpl(qpid::framing::Buffer& buf, const SchemaMethod* schema);
+ MethodResponseImpl(uint32_t status, const std::string& text);
+ static MethodResponse* factory(qpid::framing::Buffer& buf, const SchemaMethod* schema);
+ static MethodResponse* factory(uint32_t status, const std::string& text);
+ ~MethodResponseImpl() {}
+ uint32_t getStatus() const { return status; }
+ const Value* getException() const { return exception.get(); }
+ const Value* getArgs() const { return arguments.get(); }
+ };
+
+ typedef boost::shared_ptr<QueryResponse> QueryResponsePtr;
+ struct QueryResponseImpl {
+ uint32_t status;
+ std::auto_ptr<Value> exception;
+ std::vector<ObjectPtr> results;
+
+ QueryResponseImpl() : status(0) {}
+ static QueryResponse* factory() {
+ QueryResponseImpl* impl(new QueryResponseImpl());
+ return new QueryResponse(impl);
+ }
+ ~QueryResponseImpl() {}
+ uint32_t getStatus() const { return status; }
+ const Value* getException() const { return exception.get(); }
+ uint32_t getObjectCount() const { return results.size(); }
+ const Object* getObject(uint32_t idx) const;
+ };
+
+ struct BrokerEventImpl {
+ typedef boost::shared_ptr<BrokerEventImpl> Ptr;
+ BrokerEvent::EventKind kind;
+ std::string name;
+ std::string exchange;
+ std::string bindingKey;
+ void* context;
+ QueryResponsePtr queryResponse;
+ MethodResponsePtr methodResponse;
+
+ BrokerEventImpl(BrokerEvent::EventKind k) : kind(k), context(0) {}
+ ~BrokerEventImpl() {}
+ BrokerEvent copy();
+ };
+
+ typedef boost::shared_ptr<AgentProxy> AgentProxyPtr;
+ struct AgentProxyImpl {
+ Console& console;
+ BrokerProxy& broker;
+ uint32_t agentBank;
+ std::string label;
+ std::set<uint32_t> inFlightSequences;
+
+ AgentProxyImpl(Console& c, BrokerProxy& b, uint32_t ab, const std::string& l) : console(c), broker(b), agentBank(ab), label(l) {}
+ static AgentProxy* factory(Console& c, BrokerProxy& b, uint32_t ab, const std::string& l) {
+ AgentProxyImpl* impl(new AgentProxyImpl(c, b, ab, l));
+ return new AgentProxy(impl);
+ }
+ ~AgentProxyImpl() {}
+ const std::string& getLabel() const { return label; }
+ uint32_t getBrokerBank() const { return 1; }
+ uint32_t getAgentBank() const { return agentBank; }
+ void addSequence(uint32_t seq) { inFlightSequences.insert(seq); }
+ void delSequence(uint32_t seq) { inFlightSequences.erase(seq); }
+ void releaseInFlight(SequenceManager& seqMgr) {
+ for (std::set<uint32_t>::iterator iter = inFlightSequences.begin(); iter != inFlightSequences.end(); iter++)
+ seqMgr.release(*iter);
+ inFlightSequences.clear();
+ }
+ };
+
+ class BrokerProxyImpl : public boost::noncopyable {
+ public:
+ BrokerProxyImpl(BrokerProxy& pub, Console& _console);
+ ~BrokerProxyImpl() {}
+
+ void sessionOpened(SessionHandle& sh);
+ void sessionClosed();
+ void startProtocol();
+
+ void sendBufferLH(qpid::framing::Buffer& buf, const std::string& destination, const std::string& routingKey);
+ void handleRcvMessage(Message& message);
+ bool getXmtMessage(Message& item) const;
+ void popXmt();
+
+ bool getEvent(BrokerEvent& event) const;
+ void popEvent();
+
+ uint32_t agentCount() const;
+ const AgentProxy* getAgent(uint32_t idx) const;
+ void sendQuery(const Query& query, void* context, const AgentProxy* agent);
+ bool sendGetRequestLH(SequenceContext::Ptr queryContext, const Query& query, const AgentProxy* agent);
+ std::string encodeMethodArguments(const SchemaMethod* schema, const Value* args, qpid::framing::Buffer& buffer);
+ void sendMethodRequest(ObjectId* oid, const SchemaObjectClass* cls, const std::string& method, const Value* args, void* context);
+
+ void addBinding(const std::string& exchange, const std::string& key);
+ void staticRelease() { decOutstanding(); }
+
+ private:
+ friend struct StaticContext;
+ friend struct QueryContext;
+ friend struct MethodContext;
+ BrokerProxy& publicObject;
+ mutable qpid::sys::Mutex lock;
+ Console& console;
+ std::string queueName;
+ qpid::framing::Uuid brokerId;
+ SequenceManager seqMgr;
+ uint32_t requestsOutstanding;
+ bool topicBound;
+ std::map<uint32_t, AgentProxyPtr> agentList;
+ std::deque<MessageImpl::Ptr> xmtQueue;
+ std::deque<BrokerEventImpl::Ptr> eventQueue;
+
+# define MA_BUFFER_SIZE 65536
+ char outputBuffer[MA_BUFFER_SIZE];
+
+ BrokerEventImpl::Ptr eventDeclareQueue(const std::string& queueName);
+ BrokerEventImpl::Ptr eventBind(const std::string& exchange, const std::string& queue, const std::string& key);
+ BrokerEventImpl::Ptr eventSetupComplete();
+ BrokerEventImpl::Ptr eventStable();
+ BrokerEventImpl::Ptr eventQueryComplete(void* context, QueryResponsePtr response);
+ BrokerEventImpl::Ptr eventMethodResponse(void* context, MethodResponsePtr response);
+
+ void handleBrokerResponse(qpid::framing::Buffer& inBuffer, uint32_t seq);
+ void handlePackageIndication(qpid::framing::Buffer& inBuffer, uint32_t seq);
+ void handleCommandComplete(qpid::framing::Buffer& inBuffer, uint32_t seq);
+ void handleClassIndication(qpid::framing::Buffer& inBuffer, uint32_t seq);
+ MethodResponsePtr handleMethodResponse(qpid::framing::Buffer& inBuffer, uint32_t seq, const SchemaMethod* schema);
+ void handleHeartbeatIndication(qpid::framing::Buffer& inBuffer, uint32_t seq, const std::string& routingKey);
+ void handleEventIndication(qpid::framing::Buffer& inBuffer, uint32_t seq);
+ void handleSchemaResponse(qpid::framing::Buffer& inBuffer, uint32_t seq);
+ ObjectPtr handleObjectIndication(qpid::framing::Buffer& inBuffer, uint32_t seq, bool prop, bool stat);
+ void updateAgentList(ObjectPtr obj);
+ void incOutstandingLH();
+ void decOutstanding();
+ };
+
+ //
+ // StaticContext is used to handle:
+ //
+ // 1) Responses to console-level requests (for schema info, etc.)
+ // 2) Unsolicited messages from agents (events, published updates, etc.)
+ //
+ struct StaticContext : public SequenceContext {
+ StaticContext(BrokerProxyImpl& b) : broker(b) {}
+ virtual ~StaticContext() {}
+ void reserve() {}
+ void release() { broker.staticRelease(); }
+ bool handleMessage(uint8_t opcode, uint32_t sequence, const std::string& routingKey, qpid::framing::Buffer& buffer);
+ BrokerProxyImpl& broker;
+ };
+
+ //
+ // QueryContext is used to track and handle responses associated with a single Get Query
+ //
+ struct QueryContext : public SequenceContext {
+ QueryContext(BrokerProxyImpl& b, void* u) :
+ broker(b), userContext(u), requestsOutstanding(0), queryResponse(QueryResponseImpl::factory()) {}
+ virtual ~QueryContext() {}
+ void reserve();
+ void release();
+ bool handleMessage(uint8_t opcode, uint32_t sequence, const std::string& routingKey, qpid::framing::Buffer& buffer);
+
+ mutable qpid::sys::Mutex lock;
+ BrokerProxyImpl& broker;
+ void* userContext;
+ uint32_t requestsOutstanding;
+ QueryResponsePtr queryResponse;
+ };
+
+ struct MethodContext : public SequenceContext {
+ MethodContext(BrokerProxyImpl& b, void* u, const SchemaMethod* s) : broker(b), userContext(u), schema(s) {}
+ virtual ~MethodContext() {}
+ void reserve() {}
+ void release();
+ bool handleMessage(uint8_t opcode, uint32_t sequence, const std::string& routingKey, qpid::framing::Buffer& buffer);
+
+ BrokerProxyImpl& broker;
+ void* userContext;
+ const SchemaMethod* schema;
+ MethodResponsePtr methodResponse;
+ };
+
+}
+}
+
+#endif
+
diff --git a/cpp/src/qmf/engine/ConnectionSettingsImpl.cpp b/cpp/src/qmf/engine/ConnectionSettingsImpl.cpp
new file mode 100644
index 0000000000..22a65f28ca
--- /dev/null
+++ b/cpp/src/qmf/engine/ConnectionSettingsImpl.cpp
@@ -0,0 +1,278 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/ConnectionSettingsImpl.h"
+#include "qmf/engine/Typecode.h"
+
+using namespace std;
+using namespace qmf::engine;
+using namespace qpid;
+
+const string attrProtocol("protocol");
+const string attrHost("host");
+const string attrPort("port");
+const string attrVirtualhost("virtualhost");
+const string attrUsername("username");
+const string attrPassword("password");
+const string attrMechanism("mechanism");
+const string attrLocale("locale");
+const string attrHeartbeat("heartbeat");
+const string attrMaxChannels("maxChannels");
+const string attrMaxFrameSize("maxFrameSize");
+const string attrBounds("bounds");
+const string attrTcpNoDelay("tcpNoDelay");
+const string attrService("service");
+const string attrMinSsf("minSsf");
+const string attrMaxSsf("maxSsf");
+const string attrRetryDelayMin("retryDelayMin");
+const string attrRetryDelayMax("retryDelayMax");
+const string attrRetryDelayFactor("retryDelayFactor");
+const string attrSendUserId("sendUserId");
+
+ConnectionSettingsImpl::ConnectionSettingsImpl() :
+ retryDelayMin(1), retryDelayMax(64), retryDelayFactor(2), sendUserId(true)
+{
+}
+
+ConnectionSettingsImpl::ConnectionSettingsImpl(const string& /*url*/) :
+ retryDelayMin(1), retryDelayMax(64), retryDelayFactor(2), sendUserId(true)
+{
+ // TODO: Parse the URL
+}
+
+bool ConnectionSettingsImpl::setAttr(const string& key, const Value& value)
+{
+ if (key == attrProtocol) clientSettings.protocol = value.asString();
+ else if (key == attrHost) clientSettings.host = value.asString();
+ else if (key == attrPort) clientSettings.port = value.asUint();
+ else if (key == attrVirtualhost) clientSettings.virtualhost = value.asString();
+ else if (key == attrUsername) clientSettings.username = value.asString();
+ else if (key == attrPassword) clientSettings.password = value.asString();
+ else if (key == attrMechanism) clientSettings.mechanism = value.asString();
+ else if (key == attrLocale) clientSettings.locale = value.asString();
+ else if (key == attrHeartbeat) clientSettings.heartbeat = value.asUint();
+ else if (key == attrMaxChannels) clientSettings.maxChannels = value.asUint();
+ else if (key == attrMaxFrameSize) clientSettings.maxFrameSize = value.asUint();
+ else if (key == attrBounds) clientSettings.bounds = value.asUint();
+ else if (key == attrTcpNoDelay) clientSettings.tcpNoDelay = value.asBool();
+ else if (key == attrService) clientSettings.service = value.asString();
+ else if (key == attrMinSsf) clientSettings.minSsf = value.asUint();
+ else if (key == attrMaxSsf) clientSettings.maxSsf = value.asUint();
+
+ else if (key == attrRetryDelayMin) retryDelayMin = value.asUint();
+ else if (key == attrRetryDelayMax) retryDelayMax = value.asUint();
+ else if (key == attrRetryDelayFactor) retryDelayFactor = value.asUint();
+ else if (key == attrSendUserId) sendUserId = value.asBool();
+ else
+ return false;
+ return true;
+}
+
+Value ConnectionSettingsImpl::getAttr(const string& key) const
+{
+ Value strval(TYPE_LSTR);
+ Value intval(TYPE_UINT32);
+ Value boolval(TYPE_BOOL);
+
+ if (key == attrProtocol) {
+ strval.setString(clientSettings.protocol.c_str());
+ return strval;
+ }
+
+ if (key == attrHost) {
+ strval.setString(clientSettings.host.c_str());
+ return strval;
+ }
+
+ if (key == attrPort) {
+ intval.setUint(clientSettings.port);
+ return intval;
+ }
+
+ if (key == attrVirtualhost) {
+ strval.setString(clientSettings.virtualhost.c_str());
+ return strval;
+ }
+
+ if (key == attrUsername) {
+ strval.setString(clientSettings.username.c_str());
+ return strval;
+ }
+
+ if (key == attrPassword) {
+ strval.setString(clientSettings.password.c_str());
+ return strval;
+ }
+
+ if (key == attrMechanism) {
+ strval.setString(clientSettings.mechanism.c_str());
+ return strval;
+ }
+
+ if (key == attrLocale) {
+ strval.setString(clientSettings.locale.c_str());
+ return strval;
+ }
+
+ if (key == attrHeartbeat) {
+ intval.setUint(clientSettings.heartbeat);
+ return intval;
+ }
+
+ if (key == attrMaxChannels) {
+ intval.setUint(clientSettings.maxChannels);
+ return intval;
+ }
+
+ if (key == attrMaxFrameSize) {
+ intval.setUint(clientSettings.maxFrameSize);
+ return intval;
+ }
+
+ if (key == attrBounds) {
+ intval.setUint(clientSettings.bounds);
+ return intval;
+ }
+
+ if (key == attrTcpNoDelay) {
+ boolval.setBool(clientSettings.tcpNoDelay);
+ return boolval;
+ }
+
+ if (key == attrService) {
+ strval.setString(clientSettings.service.c_str());
+ return strval;
+ }
+
+ if (key == attrMinSsf) {
+ intval.setUint(clientSettings.minSsf);
+ return intval;
+ }
+
+ if (key == attrMaxSsf) {
+ intval.setUint(clientSettings.maxSsf);
+ return intval;
+ }
+
+ if (key == attrRetryDelayMin) {
+ intval.setUint(retryDelayMin);
+ return intval;
+ }
+
+ if (key == attrRetryDelayMax) {
+ intval.setUint(retryDelayMax);
+ return intval;
+ }
+
+ if (key == attrRetryDelayFactor) {
+ intval.setUint(retryDelayFactor);
+ return intval;
+ }
+
+ if (key == attrSendUserId) {
+ boolval.setBool(sendUserId);
+ return boolval;
+ }
+
+ return strval;
+}
+
+const string& ConnectionSettingsImpl::getAttrString() const
+{
+ // TODO: build and return attribute string
+ return attrString;
+}
+
+void ConnectionSettingsImpl::transportTcp(uint16_t port)
+{
+ clientSettings.protocol = "tcp";
+ clientSettings.port = port;
+}
+
+void ConnectionSettingsImpl::transportSsl(uint16_t port)
+{
+ clientSettings.protocol = "ssl";
+ clientSettings.port = port;
+}
+
+void ConnectionSettingsImpl::transportRdma(uint16_t port)
+{
+ clientSettings.protocol = "rdma";
+ clientSettings.port = port;
+}
+
+void ConnectionSettingsImpl::authAnonymous(const string& username)
+{
+ clientSettings.mechanism = "ANONYMOUS";
+ clientSettings.username = username;
+}
+
+void ConnectionSettingsImpl::authPlain(const string& username, const string& password)
+{
+ clientSettings.mechanism = "PLAIN";
+ clientSettings.username = username;
+ clientSettings.password = password;
+}
+
+void ConnectionSettingsImpl::authGssapi(const string& serviceName, uint32_t minSsf, uint32_t maxSsf)
+{
+ clientSettings.mechanism = "GSSAPI";
+ clientSettings.service = serviceName;
+ clientSettings.minSsf = minSsf;
+ clientSettings.maxSsf = maxSsf;
+}
+
+void ConnectionSettingsImpl::setRetry(int delayMin, int delayMax, int delayFactor)
+{
+ retryDelayMin = delayMin;
+ retryDelayMax = delayMax;
+ retryDelayFactor = delayFactor;
+}
+
+const client::ConnectionSettings& ConnectionSettingsImpl::getClientSettings() const
+{
+ return clientSettings;
+}
+
+void ConnectionSettingsImpl::getRetrySettings(int* min, int* max, int* factor) const
+{
+ *min = retryDelayMin;
+ *max = retryDelayMax;
+ *factor = retryDelayFactor;
+}
+
+//==================================================================
+// Wrappers
+//==================================================================
+
+ConnectionSettings::ConnectionSettings(const ConnectionSettings& from) { impl = new ConnectionSettingsImpl(*from.impl); }
+ConnectionSettings::ConnectionSettings() { impl = new ConnectionSettingsImpl(); }
+ConnectionSettings::ConnectionSettings(const char* url) { impl = new ConnectionSettingsImpl(url); }
+ConnectionSettings::~ConnectionSettings() { delete impl; }
+bool ConnectionSettings::setAttr(const char* key, const Value& value) { return impl->setAttr(key, value); }
+Value ConnectionSettings::getAttr(const char* key) const { return impl->getAttr(key); }
+const char* ConnectionSettings::getAttrString() const { return impl->getAttrString().c_str(); }
+void ConnectionSettings::transportTcp(uint16_t port) { impl->transportTcp(port); }
+void ConnectionSettings::transportSsl(uint16_t port) { impl->transportSsl(port); }
+void ConnectionSettings::transportRdma(uint16_t port) { impl->transportRdma(port); }
+void ConnectionSettings::authAnonymous(const char* username) { impl->authAnonymous(username); }
+void ConnectionSettings::authPlain(const char* username, const char* password) { impl->authPlain(username, password); }
+void ConnectionSettings::authGssapi(const char* serviceName, uint32_t minSsf, uint32_t maxSsf) { impl->authGssapi(serviceName, minSsf, maxSsf); }
+void ConnectionSettings::setRetry(int delayMin, int delayMax, int delayFactor) { impl->setRetry(delayMin, delayMax, delayFactor); }
+
diff --git a/cpp/src/qmf/engine/ConnectionSettingsImpl.h b/cpp/src/qmf/engine/ConnectionSettingsImpl.h
new file mode 100644
index 0000000000..98bf87868b
--- /dev/null
+++ b/cpp/src/qmf/engine/ConnectionSettingsImpl.h
@@ -0,0 +1,63 @@
+#ifndef _QmfEngineConnectionSettingsImpl_
+#define _QmfEngineConnectionSettingsImpl_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/ConnectionSettings.h"
+#include "qmf/engine/Value.h"
+#include "qpid/client/ConnectionSettings.h"
+#include <string>
+#include <map>
+
+namespace qmf {
+namespace engine {
+
+ class ConnectionSettingsImpl {
+ qpid::client::ConnectionSettings clientSettings;
+ mutable std::string attrString;
+ int retryDelayMin;
+ int retryDelayMax;
+ int retryDelayFactor;
+ bool sendUserId;
+
+ public:
+ ConnectionSettingsImpl();
+ ConnectionSettingsImpl(const std::string& url);
+ ~ConnectionSettingsImpl() {}
+ bool setAttr(const std::string& key, const Value& value);
+ Value getAttr(const std::string& key) const;
+ const std::string& getAttrString() const;
+ void transportTcp(uint16_t port);
+ void transportSsl(uint16_t port);
+ void transportRdma(uint16_t port);
+ void authAnonymous(const std::string& username);
+ void authPlain(const std::string& username, const std::string& password);
+ void authGssapi(const std::string& serviceName, uint32_t minSsf, uint32_t maxSsf);
+ void setRetry(int delayMin, int delayMax, int delayFactor);
+
+ const qpid::client::ConnectionSettings& getClientSettings() const;
+ void getRetrySettings(int* delayMin, int* delayMax, int* delayFactor) const;
+ bool getSendUserId() const { return sendUserId; }
+ };
+
+}
+}
+
+#endif
diff --git a/cpp/src/qmf/engine/ConsoleImpl.cpp b/cpp/src/qmf/engine/ConsoleImpl.cpp
new file mode 100644
index 0000000000..c2d1f51f2b
--- /dev/null
+++ b/cpp/src/qmf/engine/ConsoleImpl.cpp
@@ -0,0 +1,419 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/ConsoleImpl.h"
+#include "qmf/engine/MessageImpl.h"
+#include "qmf/engine/SchemaImpl.h"
+#include "qmf/engine/Typecode.h"
+#include "qmf/engine/ObjectImpl.h"
+#include "qmf/engine/ObjectIdImpl.h"
+#include "qmf/engine/QueryImpl.h"
+#include "qmf/engine/ValueImpl.h"
+#include "qmf/engine/Protocol.h"
+#include "qmf/engine/SequenceManager.h"
+#include "qmf/engine/BrokerProxyImpl.h"
+#include <qpid/framing/Buffer.h>
+#include <qpid/framing/Uuid.h>
+#include <qpid/framing/FieldTable.h>
+#include <qpid/framing/FieldValue.h>
+#include <qpid/log/Statement.h>
+#include <qpid/sys/Time.h>
+#include <qpid/sys/SystemInfo.h>
+#include <string.h>
+#include <iostream>
+#include <fstream>
+
+using namespace std;
+using namespace qmf::engine;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+namespace {
+ const char* QMF_EXCHANGE = "qpid.management";
+}
+
+#define STRING_REF(s) {if (!s.empty()) item.s = const_cast<char*>(s.c_str());}
+
+ConsoleEvent ConsoleEventImpl::copy()
+{
+ ConsoleEvent item;
+
+ ::memset(&item, 0, sizeof(ConsoleEvent));
+ item.kind = kind;
+ item.agent = agent.get();
+ item.classKey = classKey;
+ item.object = object.get();
+ item.context = context;
+ item.event = event;
+ item.timestamp = timestamp;
+ item.hasProps = hasProps;
+ item.hasStats = hasStats;
+
+ STRING_REF(name);
+
+ return item;
+}
+
+ConsoleImpl::ConsoleImpl(const ConsoleSettings& s) : settings(s)
+{
+ bindingList.push_back(pair<string, string>(string(), "schema.#"));
+ if (settings.rcvObjects && settings.rcvEvents && settings.rcvHeartbeats && !settings.userBindings) {
+ bindingList.push_back(pair<string, string>(string(), "console.#"));
+ } else {
+ if (settings.rcvObjects && !settings.userBindings)
+ bindingList.push_back(pair<string, string>(string(), "console.obj.#"));
+ else
+ bindingList.push_back(pair<string, string>(string(), "console.obj.*.*.org.apache.qpid.broker.agent"));
+ if (settings.rcvEvents)
+ bindingList.push_back(pair<string, string>(string(), "console.event.#"));
+ if (settings.rcvHeartbeats)
+ bindingList.push_back(pair<string, string>(string(), "console.heartbeat.#"));
+ }
+}
+
+ConsoleImpl::~ConsoleImpl()
+{
+ // This function intentionally left blank.
+}
+
+bool ConsoleImpl::getEvent(ConsoleEvent& event) const
+{
+ Mutex::ScopedLock _lock(lock);
+ if (eventQueue.empty())
+ return false;
+ event = eventQueue.front()->copy();
+ return true;
+}
+
+void ConsoleImpl::popEvent()
+{
+ Mutex::ScopedLock _lock(lock);
+ if (!eventQueue.empty())
+ eventQueue.pop_front();
+}
+
+void ConsoleImpl::addConnection(BrokerProxy& broker, void* /*context*/)
+{
+ Mutex::ScopedLock _lock(lock);
+ brokerList.push_back(broker.impl);
+}
+
+void ConsoleImpl::delConnection(BrokerProxy& broker)
+{
+ Mutex::ScopedLock _lock(lock);
+ for (vector<BrokerProxyImpl*>::iterator iter = brokerList.begin();
+ iter != brokerList.end(); iter++)
+ if (*iter == broker.impl) {
+ brokerList.erase(iter);
+ break;
+ }
+}
+
+uint32_t ConsoleImpl::packageCount() const
+{
+ Mutex::ScopedLock _lock(lock);
+ return packages.size();
+}
+
+const string& ConsoleImpl::getPackageName(uint32_t idx) const
+{
+ const static string empty;
+
+ Mutex::ScopedLock _lock(lock);
+ if (idx >= packages.size())
+ return empty;
+
+ PackageList::const_iterator iter = packages.begin();
+ for (uint32_t i = 0; i < idx; i++) iter++;
+ return iter->first;
+}
+
+uint32_t ConsoleImpl::classCount(const char* packageName) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(packageName);
+ if (pIter == packages.end())
+ return 0;
+
+ const ObjectClassList& oList = pIter->second.first;
+ const EventClassList& eList = pIter->second.second;
+
+ return oList.size() + eList.size();
+}
+
+const SchemaClassKey* ConsoleImpl::getClass(const char* packageName, uint32_t idx) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(packageName);
+ if (pIter == packages.end())
+ return 0;
+
+ const ObjectClassList& oList = pIter->second.first;
+ const EventClassList& eList = pIter->second.second;
+ uint32_t count = 0;
+
+ for (ObjectClassList::const_iterator oIter = oList.begin();
+ oIter != oList.end(); oIter++) {
+ if (count == idx)
+ return oIter->second->getClassKey();
+ count++;
+ }
+
+ for (EventClassList::const_iterator eIter = eList.begin();
+ eIter != eList.end(); eIter++) {
+ if (count == idx)
+ return eIter->second->getClassKey();
+ count++;
+ }
+
+ return 0;
+}
+
+ClassKind ConsoleImpl::getClassKind(const SchemaClassKey* key) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return CLASS_OBJECT;
+
+ const EventClassList& eList = pIter->second.second;
+ if (eList.find(key) != eList.end())
+ return CLASS_EVENT;
+ return CLASS_OBJECT;
+}
+
+const SchemaObjectClass* ConsoleImpl::getObjectClass(const SchemaClassKey* key) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return 0;
+
+ const ObjectClassList& oList = pIter->second.first;
+ ObjectClassList::const_iterator iter = oList.find(key);
+ if (iter == oList.end())
+ return 0;
+ return iter->second;
+}
+
+const SchemaEventClass* ConsoleImpl::getEventClass(const SchemaClassKey* key) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return 0;
+
+ const EventClassList& eList = pIter->second.second;
+ EventClassList::const_iterator iter = eList.find(key);
+ if (iter == eList.end())
+ return 0;
+ return iter->second;
+}
+
+void ConsoleImpl::bindPackage(const char* packageName)
+{
+ stringstream key;
+ key << "console.obj.*.*." << packageName << ".#";
+ Mutex::ScopedLock _lock(lock);
+ bindingList.push_back(pair<string, string>(string(), key.str()));
+ for (vector<BrokerProxyImpl*>::iterator iter = brokerList.begin();
+ iter != brokerList.end(); iter++)
+ (*iter)->addBinding(QMF_EXCHANGE, key.str());
+}
+
+void ConsoleImpl::bindClass(const SchemaClassKey* classKey)
+{
+ stringstream key;
+ key << "console.obj.*.*." << classKey->getPackageName() << "." << classKey->getClassName() << ".#";
+ Mutex::ScopedLock _lock(lock);
+ bindingList.push_back(pair<string, string>(string(), key.str()));
+ for (vector<BrokerProxyImpl*>::iterator iter = brokerList.begin();
+ iter != brokerList.end(); iter++)
+ (*iter)->addBinding(QMF_EXCHANGE, key.str());
+}
+
+void ConsoleImpl::bindClass(const char* packageName, const char* className)
+{
+ stringstream key;
+ key << "console.obj.*.*." << packageName << "." << className << ".#";
+ Mutex::ScopedLock _lock(lock);
+ bindingList.push_back(pair<string, string>(string(), key.str()));
+ for (vector<BrokerProxyImpl*>::iterator iter = brokerList.begin();
+ iter != brokerList.end(); iter++)
+ (*iter)->addBinding(QMF_EXCHANGE, key.str());
+}
+
+/*
+void ConsoleImpl::startSync(const Query& query, void* context, SyncQuery& sync)
+{
+}
+
+void ConsoleImpl::touchSync(SyncQuery& sync)
+{
+}
+
+void ConsoleImpl::endSync(SyncQuery& sync)
+{
+}
+*/
+
+void ConsoleImpl::learnPackage(const string& packageName)
+{
+ Mutex::ScopedLock _lock(lock);
+ if (packages.find(packageName) == packages.end()) {
+ packages.insert(pair<string, pair<ObjectClassList, EventClassList> >
+ (packageName, pair<ObjectClassList, EventClassList>(ObjectClassList(), EventClassList())));
+ eventNewPackage(packageName);
+ }
+}
+
+void ConsoleImpl::learnClass(SchemaObjectClass* cls)
+{
+ Mutex::ScopedLock _lock(lock);
+ const SchemaClassKey* key = cls->getClassKey();
+ PackageList::iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return;
+
+ ObjectClassList& list = pIter->second.first;
+ if (list.find(key) == list.end()) {
+ list[key] = cls;
+ eventNewClass(key);
+ }
+}
+
+void ConsoleImpl::learnClass(SchemaEventClass* cls)
+{
+ Mutex::ScopedLock _lock(lock);
+ const SchemaClassKey* key = cls->getClassKey();
+ PackageList::iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return;
+
+ EventClassList& list = pIter->second.second;
+ if (list.find(key) == list.end()) {
+ list[key] = cls;
+ eventNewClass(key);
+ }
+}
+
+bool ConsoleImpl::haveClass(const SchemaClassKey* key) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return false;
+
+ const ObjectClassList& oList = pIter->second.first;
+ const EventClassList& eList = pIter->second.second;
+
+ return oList.find(key) != oList.end() || eList.find(key) != eList.end();
+}
+
+SchemaObjectClass* ConsoleImpl::getSchema(const SchemaClassKey* key) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return 0;
+
+ const ObjectClassList& oList = pIter->second.first;
+ ObjectClassList::const_iterator iter = oList.find(key);
+ if (iter == oList.end())
+ return 0;
+
+ return iter->second;
+}
+
+void ConsoleImpl::eventAgentAdded(boost::shared_ptr<AgentProxy> agent)
+{
+ ConsoleEventImpl::Ptr event(new ConsoleEventImpl(ConsoleEvent::AGENT_ADDED));
+ event->agent = agent;
+ Mutex::ScopedLock _lock(lock);
+ eventQueue.push_back(event);
+}
+
+void ConsoleImpl::eventAgentDeleted(boost::shared_ptr<AgentProxy> agent)
+{
+ ConsoleEventImpl::Ptr event(new ConsoleEventImpl(ConsoleEvent::AGENT_DELETED));
+ event->agent = agent;
+ Mutex::ScopedLock _lock(lock);
+ eventQueue.push_back(event);
+}
+
+void ConsoleImpl::eventNewPackage(const string& packageName)
+{
+ ConsoleEventImpl::Ptr event(new ConsoleEventImpl(ConsoleEvent::NEW_PACKAGE));
+ event->name = packageName;
+ Mutex::ScopedLock _lock(lock);
+ eventQueue.push_back(event);
+}
+
+void ConsoleImpl::eventNewClass(const SchemaClassKey* key)
+{
+ ConsoleEventImpl::Ptr event(new ConsoleEventImpl(ConsoleEvent::NEW_CLASS));
+ event->classKey = key;
+ Mutex::ScopedLock _lock(lock);
+ eventQueue.push_back(event);
+}
+
+void ConsoleImpl::eventObjectUpdate(ObjectPtr object, bool prop, bool stat)
+{
+ ConsoleEventImpl::Ptr event(new ConsoleEventImpl(ConsoleEvent::OBJECT_UPDATE));
+ event->object = object;
+ event->hasProps = prop;
+ event->hasStats = stat;
+ Mutex::ScopedLock _lock(lock);
+ eventQueue.push_back(event);
+}
+
+void ConsoleImpl::eventAgentHeartbeat(boost::shared_ptr<AgentProxy> agent, uint64_t timestamp)
+{
+ ConsoleEventImpl::Ptr event(new ConsoleEventImpl(ConsoleEvent::AGENT_HEARTBEAT));
+ event->agent = agent;
+ event->timestamp = timestamp;
+ Mutex::ScopedLock _lock(lock);
+ eventQueue.push_back(event);
+}
+
+//==================================================================
+// Wrappers
+//==================================================================
+
+Console::Console(const ConsoleSettings& settings) : impl(new ConsoleImpl(settings)) {}
+Console::~Console() { delete impl; }
+bool Console::getEvent(ConsoleEvent& event) const { return impl->getEvent(event); }
+void Console::popEvent() { impl->popEvent(); }
+void Console::addConnection(BrokerProxy& broker, void* context) { impl->addConnection(broker, context); }
+void Console::delConnection(BrokerProxy& broker) { impl->delConnection(broker); }
+uint32_t Console::packageCount() const { return impl->packageCount(); }
+const char* Console::getPackageName(uint32_t idx) const { return impl->getPackageName(idx).c_str(); }
+uint32_t Console::classCount(const char* packageName) const { return impl->classCount(packageName); }
+const SchemaClassKey* Console::getClass(const char* packageName, uint32_t idx) const { return impl->getClass(packageName, idx); }
+ClassKind Console::getClassKind(const SchemaClassKey* key) const { return impl->getClassKind(key); }
+const SchemaObjectClass* Console::getObjectClass(const SchemaClassKey* key) const { return impl->getObjectClass(key); }
+const SchemaEventClass* Console::getEventClass(const SchemaClassKey* key) const { return impl->getEventClass(key); }
+void Console::bindPackage(const char* packageName) { impl->bindPackage(packageName); }
+void Console::bindClass(const SchemaClassKey* key) { impl->bindClass(key); }
+void Console::bindClass(const char* packageName, const char* className) { impl->bindClass(packageName, className); }
+//void Console::startSync(const Query& query, void* context, SyncQuery& sync) { impl->startSync(query, context, sync); }
+//void Console::touchSync(SyncQuery& sync) { impl->touchSync(sync); }
+//void Console::endSync(SyncQuery& sync) { impl->endSync(sync); }
+
+
diff --git a/cpp/src/qmf/engine/ConsoleImpl.h b/cpp/src/qmf/engine/ConsoleImpl.h
new file mode 100644
index 0000000000..8f99c5e6b9
--- /dev/null
+++ b/cpp/src/qmf/engine/ConsoleImpl.h
@@ -0,0 +1,145 @@
+#ifndef _QmfEngineConsoleEngineImpl_
+#define _QmfEngineConsoleEngineImpl_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Console.h"
+#include "qmf/engine/MessageImpl.h"
+#include "qmf/engine/SchemaImpl.h"
+#include "qmf/engine/Typecode.h"
+#include "qmf/engine/ObjectImpl.h"
+#include "qmf/engine/ObjectIdImpl.h"
+#include "qmf/engine/QueryImpl.h"
+#include "qmf/engine/ValueImpl.h"
+#include "qmf/engine/Protocol.h"
+#include "qmf/engine/SequenceManager.h"
+#include "qmf/engine/BrokerProxyImpl.h"
+#include <qpid/framing/Buffer.h>
+#include <qpid/framing/Uuid.h>
+#include <qpid/framing/FieldTable.h>
+#include <qpid/framing/FieldValue.h>
+#include <qpid/sys/Mutex.h>
+#include <qpid/sys/Time.h>
+#include <qpid/sys/SystemInfo.h>
+#include <string.h>
+#include <string>
+#include <deque>
+#include <map>
+#include <vector>
+#include <iostream>
+#include <fstream>
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+
+namespace qmf {
+namespace engine {
+
+ struct ConsoleEventImpl {
+ typedef boost::shared_ptr<ConsoleEventImpl> Ptr;
+ ConsoleEvent::EventKind kind;
+ boost::shared_ptr<AgentProxy> agent;
+ std::string name;
+ const SchemaClassKey* classKey;
+ boost::shared_ptr<Object> object;
+ void* context;
+ Event* event;
+ uint64_t timestamp;
+ bool hasProps;
+ bool hasStats;
+
+ ConsoleEventImpl(ConsoleEvent::EventKind k) :
+ kind(k), classKey(0), context(0), event(0), timestamp(0) {}
+ ~ConsoleEventImpl() {}
+ ConsoleEvent copy();
+ };
+
+ class ConsoleImpl : public boost::noncopyable {
+ public:
+ ConsoleImpl(const ConsoleSettings& settings = ConsoleSettings());
+ ~ConsoleImpl();
+
+ bool getEvent(ConsoleEvent& event) const;
+ void popEvent();
+
+ void addConnection(BrokerProxy& broker, void* context);
+ void delConnection(BrokerProxy& broker);
+
+ uint32_t packageCount() const;
+ const std::string& getPackageName(uint32_t idx) const;
+
+ uint32_t classCount(const char* packageName) const;
+ const SchemaClassKey* getClass(const char* packageName, uint32_t idx) const;
+
+ ClassKind getClassKind(const SchemaClassKey* key) const;
+ const SchemaObjectClass* getObjectClass(const SchemaClassKey* key) const;
+ const SchemaEventClass* getEventClass(const SchemaClassKey* key) const;
+
+ void bindPackage(const char* packageName);
+ void bindClass(const SchemaClassKey* key);
+ void bindClass(const char* packageName, const char* className);
+
+ /*
+ void startSync(const Query& query, void* context, SyncQuery& sync);
+ void touchSync(SyncQuery& sync);
+ void endSync(SyncQuery& sync);
+ */
+
+ private:
+ friend class BrokerProxyImpl;
+ friend struct StaticContext;
+ const ConsoleSettings& settings;
+ mutable qpid::sys::Mutex lock;
+ std::deque<ConsoleEventImpl::Ptr> eventQueue;
+ std::vector<BrokerProxyImpl*> brokerList;
+ std::vector<std::pair<std::string, std::string> > bindingList; // exchange/key (empty exchange => QMF_EXCHANGE)
+
+ // Declare a compare class for the class maps that compares the dereferenced
+ // class key pointers. The default behavior would be to compare the pointer
+ // addresses themselves.
+ struct KeyCompare {
+ bool operator()(const SchemaClassKey* left, const SchemaClassKey* right) const {
+ return *left < *right;
+ }
+ };
+
+ typedef std::map<const SchemaClassKey*, SchemaObjectClass*, KeyCompare> ObjectClassList;
+ typedef std::map<const SchemaClassKey*, SchemaEventClass*, KeyCompare> EventClassList;
+ typedef std::map<std::string, std::pair<ObjectClassList, EventClassList> > PackageList;
+
+ PackageList packages;
+
+ void learnPackage(const std::string& packageName);
+ void learnClass(SchemaObjectClass* cls);
+ void learnClass(SchemaEventClass* cls);
+ bool haveClass(const SchemaClassKey* key) const;
+ SchemaObjectClass* getSchema(const SchemaClassKey* key) const;
+
+ void eventAgentAdded(boost::shared_ptr<AgentProxy> agent);
+ void eventAgentDeleted(boost::shared_ptr<AgentProxy> agent);
+ void eventNewPackage(const std::string& packageName);
+ void eventNewClass(const SchemaClassKey* key);
+ void eventObjectUpdate(ObjectPtr object, bool prop, bool stat);
+ void eventAgentHeartbeat(boost::shared_ptr<AgentProxy> agent, uint64_t timestamp);
+ };
+}
+}
+
+#endif
+
diff --git a/cpp/src/qmf/engine/MessageImpl.cpp b/cpp/src/qmf/engine/MessageImpl.cpp
new file mode 100644
index 0000000000..0047d3eb9d
--- /dev/null
+++ b/cpp/src/qmf/engine/MessageImpl.cpp
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "qmf/engine/MessageImpl.h"
+#include <string.h>
+
+using namespace std;
+using namespace qmf::engine;
+
+#define STRING_REF(s) {if (!s.empty()) item.s = const_cast<char*>(s.c_str());}
+
+Message MessageImpl::copy()
+{
+ Message item;
+
+ ::memset(&item, 0, sizeof(Message));
+ item.body = const_cast<char*>(body.c_str());
+ item.length = body.length();
+ STRING_REF(destination);
+ STRING_REF(routingKey);
+ STRING_REF(replyExchange);
+ STRING_REF(replyKey);
+ STRING_REF(userId);
+
+ return item;
+}
+
diff --git a/cpp/src/qmf/engine/MessageImpl.h b/cpp/src/qmf/engine/MessageImpl.h
new file mode 100644
index 0000000000..b91291d2e4
--- /dev/null
+++ b/cpp/src/qmf/engine/MessageImpl.h
@@ -0,0 +1,44 @@
+#ifndef _QmfEngineMessageImpl_
+#define _QmfEngineMessageImpl_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Message.h"
+#include <string>
+#include <boost/shared_ptr.hpp>
+
+namespace qmf {
+namespace engine {
+
+ struct MessageImpl {
+ typedef boost::shared_ptr<MessageImpl> Ptr;
+ std::string body;
+ std::string destination;
+ std::string routingKey;
+ std::string replyExchange;
+ std::string replyKey;
+ std::string userId;
+
+ Message copy();
+ };
+}
+}
+
+#endif
diff --git a/cpp/src/qmf/engine/ObjectIdImpl.cpp b/cpp/src/qmf/engine/ObjectIdImpl.cpp
new file mode 100644
index 0000000000..76db6d91f9
--- /dev/null
+++ b/cpp/src/qmf/engine/ObjectIdImpl.cpp
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/ObjectIdImpl.h"
+#include <stdlib.h>
+
+using namespace std;
+using namespace qmf::engine;
+using qpid::framing::Buffer;
+
+void AgentAttachment::setBanks(uint32_t broker, uint32_t agent)
+{
+ first =
+ ((uint64_t) (broker & 0x000fffff)) << 28 |
+ ((uint64_t) (agent & 0x0fffffff));
+}
+
+ObjectIdImpl::ObjectIdImpl(Buffer& buffer) : agent(0)
+{
+ decode(buffer);
+}
+
+ObjectIdImpl::ObjectIdImpl(AgentAttachment* a, uint8_t flags, uint16_t seq, uint64_t object) : agent(a)
+{
+ first =
+ ((uint64_t) (flags & 0x0f)) << 60 |
+ ((uint64_t) (seq & 0x0fff)) << 48;
+ second = object;
+}
+
+ObjectId* ObjectIdImpl::factory(Buffer& buffer)
+{
+ ObjectIdImpl* impl(new ObjectIdImpl(buffer));
+ return new ObjectId(impl);
+}
+
+ObjectId* ObjectIdImpl::factory(AgentAttachment* agent, uint8_t flags, uint16_t seq, uint64_t object)
+{
+ ObjectIdImpl* impl(new ObjectIdImpl(agent, flags, seq, object));
+ return new ObjectId(impl);
+}
+
+void ObjectIdImpl::decode(Buffer& buffer)
+{
+ first = buffer.getLongLong();
+ second = buffer.getLongLong();
+}
+
+void ObjectIdImpl::encode(Buffer& buffer) const
+{
+ if (agent == 0)
+ buffer.putLongLong(first);
+ else
+ buffer.putLongLong(first | agent->first);
+ buffer.putLongLong(second);
+}
+
+void ObjectIdImpl::fromString(const std::string& repr)
+{
+#define FIELDS 5
+#if defined (_WIN32) && !defined (atoll)
+# define atoll(X) _atoi64(X)
+#endif
+
+ std::string copy(repr.c_str());
+ char* cText;
+ char* field[FIELDS];
+ bool atFieldStart = true;
+ int idx = 0;
+
+ cText = const_cast<char*>(copy.c_str());
+ for (char* cursor = cText; *cursor; cursor++) {
+ if (atFieldStart) {
+ if (idx >= FIELDS)
+ return; // TODO error
+ field[idx++] = cursor;
+ atFieldStart = false;
+ } else {
+ if (*cursor == '-') {
+ *cursor = '\0';
+ atFieldStart = true;
+ }
+ }
+ }
+
+ if (idx != FIELDS)
+ return; // TODO error
+
+ first = (atoll(field[0]) << 60) +
+ (atoll(field[1]) << 48) +
+ (atoll(field[2]) << 28) +
+ atoll(field[3]);
+ second = atoll(field[4]);
+ agent = 0;
+}
+
+const string& ObjectIdImpl::asString() const
+{
+ stringstream val;
+
+ val << (int) getFlags() << "-" << getSequence() << "-" << getBrokerBank() << "-" <<
+ getAgentBank() << "-" << getObjectNum();
+ repr = val.str();
+ return repr;
+}
+
+#define ACTUAL_FIRST (agent == 0 ? first : first | agent->first)
+#define ACTUAL_OTHER (other.agent == 0 ? other.first : other.first | other.agent->first)
+
+uint8_t ObjectIdImpl::getFlags() const
+{
+ return (ACTUAL_FIRST & 0xF000000000000000LL) >> 60;
+}
+
+uint16_t ObjectIdImpl::getSequence() const
+{
+ return (ACTUAL_FIRST & 0x0FFF000000000000LL) >> 48;
+}
+
+uint32_t ObjectIdImpl::getBrokerBank() const
+{
+ return (ACTUAL_FIRST & 0x0000FFFFF0000000LL) >> 28;
+}
+
+uint32_t ObjectIdImpl::getAgentBank() const
+{
+ return ACTUAL_FIRST & 0x000000000FFFFFFFLL;
+}
+
+uint64_t ObjectIdImpl::getObjectNum() const
+{
+ return second;
+}
+
+uint32_t ObjectIdImpl::getObjectNumHi() const
+{
+ return (uint32_t) (second >> 32);
+}
+
+uint32_t ObjectIdImpl::getObjectNumLo() const
+{
+ return (uint32_t) (second & 0x00000000FFFFFFFFLL);
+}
+
+bool ObjectIdImpl::operator==(const ObjectIdImpl& other) const
+{
+ return ACTUAL_FIRST == ACTUAL_OTHER && second == other.second;
+}
+
+bool ObjectIdImpl::operator<(const ObjectIdImpl& other) const
+{
+ return (ACTUAL_FIRST < ACTUAL_OTHER) || ((ACTUAL_FIRST == ACTUAL_OTHER) && (second < other.second));
+}
+
+bool ObjectIdImpl::operator>(const ObjectIdImpl& other) const
+{
+ return (ACTUAL_FIRST > ACTUAL_OTHER) || ((ACTUAL_FIRST == ACTUAL_OTHER) && (second > other.second));
+}
+
+
+//==================================================================
+// Wrappers
+//==================================================================
+
+ObjectId::ObjectId() : impl(new ObjectIdImpl()) {}
+ObjectId::ObjectId(const ObjectId& from) : impl(new ObjectIdImpl(*(from.impl))) {}
+ObjectId::ObjectId(ObjectIdImpl* i) : impl(i) {}
+ObjectId::~ObjectId() { delete impl; }
+uint64_t ObjectId::getObjectNum() const { return impl->getObjectNum(); }
+uint32_t ObjectId::getObjectNumHi() const { return impl->getObjectNumHi(); }
+uint32_t ObjectId::getObjectNumLo() const { return impl->getObjectNumLo(); }
+bool ObjectId::isDurable() const { return impl->isDurable(); }
+const char* ObjectId::str() const { return impl->asString().c_str(); }
+uint8_t ObjectId::getFlags() const { return impl->getFlags(); }
+uint16_t ObjectId::getSequence() const { return impl->getSequence(); }
+uint32_t ObjectId::getBrokerBank() const { return impl->getBrokerBank(); }
+uint32_t ObjectId::getAgentBank() const { return impl->getAgentBank(); }
+bool ObjectId::operator==(const ObjectId& other) const { return *impl == *other.impl; }
+bool ObjectId::operator<(const ObjectId& other) const { return *impl < *other.impl; }
+bool ObjectId::operator>(const ObjectId& other) const { return *impl > *other.impl; }
+bool ObjectId::operator<=(const ObjectId& other) const { return !(*impl > *other.impl); }
+bool ObjectId::operator>=(const ObjectId& other) const { return !(*impl < *other.impl); }
+
diff --git a/cpp/src/qmf/engine/ObjectIdImpl.h b/cpp/src/qmf/engine/ObjectIdImpl.h
new file mode 100644
index 0000000000..d70c8efff4
--- /dev/null
+++ b/cpp/src/qmf/engine/ObjectIdImpl.h
@@ -0,0 +1,72 @@
+#ifndef _QmfEngineObjectIdImpl_
+#define _QmfEngineObjectIdImpl_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/ObjectId.h>
+#include <qpid/framing/Buffer.h>
+
+namespace qmf {
+namespace engine {
+
+ struct AgentAttachment {
+ uint64_t first;
+
+ AgentAttachment() : first(0) {}
+ void setBanks(uint32_t broker, uint32_t bank);
+ uint64_t getFirst() const { return first; }
+ };
+
+ struct ObjectIdImpl {
+ AgentAttachment* agent;
+ uint64_t first;
+ uint64_t second;
+ mutable std::string repr;
+
+ ObjectIdImpl() : agent(0), first(0), second(0) {}
+ ObjectIdImpl(qpid::framing::Buffer& buffer);
+ ObjectIdImpl(AgentAttachment* agent, uint8_t flags, uint16_t seq, uint64_t object);
+
+ static ObjectId* factory(qpid::framing::Buffer& buffer);
+ static ObjectId* factory(AgentAttachment* agent, uint8_t flags, uint16_t seq, uint64_t object);
+
+ void decode(qpid::framing::Buffer& buffer);
+ void encode(qpid::framing::Buffer& buffer) const;
+ void fromString(const std::string& repr);
+ const std::string& asString() const;
+ uint8_t getFlags() const;
+ uint16_t getSequence() const;
+ uint32_t getBrokerBank() const;
+ uint32_t getAgentBank() const;
+ uint64_t getObjectNum() const;
+ uint32_t getObjectNumHi() const;
+ uint32_t getObjectNumLo() const;
+ bool isDurable() const { return getSequence() == 0; }
+ void setValue(uint64_t f, uint64_t s) { first = f; second = s; agent = 0; }
+
+ bool operator==(const ObjectIdImpl& other) const;
+ bool operator<(const ObjectIdImpl& other) const;
+ bool operator>(const ObjectIdImpl& other) const;
+ };
+}
+}
+
+#endif
+
diff --git a/cpp/src/qmf/engine/ObjectImpl.cpp b/cpp/src/qmf/engine/ObjectImpl.cpp
new file mode 100644
index 0000000000..cae0e0da68
--- /dev/null
+++ b/cpp/src/qmf/engine/ObjectImpl.cpp
@@ -0,0 +1,232 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/ObjectImpl.h"
+#include "qmf/engine/ValueImpl.h"
+#include "qmf/engine/BrokerProxyImpl.h"
+#include <qpid/sys/Time.h>
+
+using namespace std;
+using namespace qmf::engine;
+using namespace qpid::sys;
+using qpid::framing::Buffer;
+
+ObjectImpl::ObjectImpl(const SchemaObjectClass* type) : objectClass(type), broker(0), createTime(uint64_t(Duration(now()))), destroyTime(0), lastUpdatedTime(createTime)
+{
+ int propCount = objectClass->getPropertyCount();
+ int statCount = objectClass->getStatisticCount();
+ int idx;
+
+ for (idx = 0; idx < propCount; idx++) {
+ const SchemaProperty* prop = objectClass->getProperty(idx);
+ properties[prop->getName()] = ValuePtr(new Value(prop->getType()));
+ }
+
+ for (idx = 0; idx < statCount; idx++) {
+ const SchemaStatistic* stat = objectClass->getStatistic(idx);
+ statistics[stat->getName()] = ValuePtr(new Value(stat->getType()));
+ }
+}
+
+ObjectImpl::ObjectImpl(const SchemaObjectClass* type, BrokerProxyImpl* b, Buffer& buffer, bool prop, bool stat, bool managed) :
+ objectClass(type), broker(b), createTime(0), destroyTime(0), lastUpdatedTime(0)
+{
+ int idx;
+
+ if (managed) {
+ lastUpdatedTime = buffer.getLongLong();
+ createTime = buffer.getLongLong();
+ destroyTime = buffer.getLongLong();
+ objectId.reset(ObjectIdImpl::factory(buffer));
+ }
+
+ if (prop) {
+ int propCount = objectClass->getPropertyCount();
+ set<string> excludes;
+ parsePresenceMasks(buffer, excludes);
+ for (idx = 0; idx < propCount; idx++) {
+ const SchemaProperty* prop = objectClass->getProperty(idx);
+ if (excludes.count(prop->getName()) != 0) {
+ properties[prop->getName()] = ValuePtr(new Value(prop->getType()));
+ } else {
+ Value* pval = ValueImpl::factory(prop->getType(), buffer);
+ properties[prop->getName()] = ValuePtr(pval);
+ }
+ }
+ }
+
+ if (stat) {
+ int statCount = objectClass->getStatisticCount();
+ for (idx = 0; idx < statCount; idx++) {
+ const SchemaStatistic* stat = objectClass->getStatistic(idx);
+ Value* sval = ValueImpl::factory(stat->getType(), buffer);
+ statistics[stat->getName()] = ValuePtr(sval);
+ }
+ }
+}
+
+Object* ObjectImpl::factory(const SchemaObjectClass* type, BrokerProxyImpl* b, Buffer& buffer, bool prop, bool stat, bool managed)
+{
+ ObjectImpl* impl(new ObjectImpl(type, b, buffer, prop, stat, managed));
+ return new Object(impl);
+}
+
+ObjectImpl::~ObjectImpl()
+{
+}
+
+void ObjectImpl::destroy()
+{
+ destroyTime = uint64_t(Duration(now()));
+ // TODO - flag deletion
+}
+
+Value* ObjectImpl::getValue(const string& key) const
+{
+ map<string, ValuePtr>::const_iterator iter;
+
+ iter = properties.find(key);
+ if (iter != properties.end())
+ return iter->second.get();
+
+ iter = statistics.find(key);
+ if (iter != statistics.end())
+ return iter->second.get();
+
+ return 0;
+}
+
+void ObjectImpl::invokeMethod(const string& methodName, const Value* inArgs, void* context) const
+{
+ if (broker != 0 && objectId.get() != 0)
+ broker->sendMethodRequest(objectId.get(), objectClass, methodName, inArgs, context);
+}
+
+void ObjectImpl::merge(const Object& from)
+{
+ for (map<string, ValuePtr>::const_iterator piter = from.impl->properties.begin();
+ piter != from.impl->properties.end(); piter++)
+ properties[piter->first] = piter->second;
+ for (map<string, ValuePtr>::const_iterator siter = from.impl->statistics.begin();
+ siter != from.impl->statistics.end(); siter++)
+ statistics[siter->first] = siter->second;
+}
+
+void ObjectImpl::parsePresenceMasks(Buffer& buffer, set<string>& excludeList)
+{
+ int propCount = objectClass->getPropertyCount();
+ excludeList.clear();
+ uint8_t bit = 0;
+ uint8_t mask = 0;
+
+ for (int idx = 0; idx < propCount; idx++) {
+ const SchemaProperty* prop = objectClass->getProperty(idx);
+ if (prop->isOptional()) {
+ if (bit == 0) {
+ mask = buffer.getOctet();
+ bit = 1;
+ }
+ if ((mask & bit) == 0)
+ excludeList.insert(string(prop->getName()));
+ if (bit == 0x80)
+ bit = 0;
+ else
+ bit = bit << 1;
+ }
+ }
+}
+
+void ObjectImpl::encodeSchemaKey(qpid::framing::Buffer& buffer) const
+{
+ buffer.putShortString(objectClass->getClassKey()->getPackageName());
+ buffer.putShortString(objectClass->getClassKey()->getClassName());
+ buffer.putBin128(const_cast<uint8_t*>(objectClass->getClassKey()->getHash()));
+}
+
+void ObjectImpl::encodeManagedObjectData(qpid::framing::Buffer& buffer) const
+{
+ buffer.putLongLong(lastUpdatedTime);
+ buffer.putLongLong(createTime);
+ buffer.putLongLong(destroyTime);
+ objectId->impl->encode(buffer);
+}
+
+void ObjectImpl::encodeProperties(qpid::framing::Buffer& buffer) const
+{
+ int propCount = objectClass->getPropertyCount();
+ uint8_t bit = 0;
+ uint8_t mask = 0;
+ ValuePtr value;
+
+ for (int idx = 0; idx < propCount; idx++) {
+ const SchemaProperty* prop = objectClass->getProperty(idx);
+ if (prop->isOptional()) {
+ value = properties[prop->getName()];
+ if (bit == 0)
+ bit = 1;
+ if (!value->isNull())
+ mask |= bit;
+ if (bit == 0x80) {
+ buffer.putOctet(mask);
+ bit = 0;
+ mask = 0;
+ } else
+ bit = bit << 1;
+ }
+ }
+ if (bit != 0) {
+ buffer.putOctet(mask);
+ }
+
+ for (int idx = 0; idx < propCount; idx++) {
+ const SchemaProperty* prop = objectClass->getProperty(idx);
+ value = properties[prop->getName()];
+ if (!prop->isOptional() || !value->isNull()) {
+ value->impl->encode(buffer);
+ }
+ }
+}
+
+void ObjectImpl::encodeStatistics(qpid::framing::Buffer& buffer) const
+{
+ int statCount = objectClass->getStatisticCount();
+ for (int idx = 0; idx < statCount; idx++) {
+ const SchemaStatistic* stat = objectClass->getStatistic(idx);
+ ValuePtr value = statistics[stat->getName()];
+ value->impl->encode(buffer);
+ }
+}
+
+//==================================================================
+// Wrappers
+//==================================================================
+
+Object::Object(const SchemaObjectClass* type) : impl(new ObjectImpl(type)) {}
+Object::Object(ObjectImpl* i) : impl(i) {}
+Object::Object(const Object& from) : impl(new ObjectImpl(*(from.impl))) {}
+Object::~Object() { delete impl; }
+void Object::destroy() { impl->destroy(); }
+const ObjectId* Object::getObjectId() const { return impl->getObjectId(); }
+void Object::setObjectId(ObjectId* oid) { impl->setObjectId(oid); }
+const SchemaObjectClass* Object::getClass() const { return impl->getClass(); }
+Value* Object::getValue(const char* key) const { return impl->getValue(key); }
+void Object::invokeMethod(const char* m, const Value* a, void* c) const { impl->invokeMethod(m, a, c); }
+bool Object::isDeleted() const { return impl->isDeleted(); }
+void Object::merge(const Object& from) { impl->merge(from); }
+
diff --git a/cpp/src/qmf/engine/ObjectImpl.h b/cpp/src/qmf/engine/ObjectImpl.h
new file mode 100644
index 0000000000..6f25867004
--- /dev/null
+++ b/cpp/src/qmf/engine/ObjectImpl.h
@@ -0,0 +1,76 @@
+#ifndef _QmfEngineObjectImpl_
+#define _QmfEngineObjectImpl_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Object.h>
+#include <qmf/engine/ObjectIdImpl.h>
+#include <map>
+#include <set>
+#include <string>
+#include <qpid/framing/Buffer.h>
+#include <boost/shared_ptr.hpp>
+#include <qpid/sys/Mutex.h>
+
+namespace qmf {
+namespace engine {
+
+ class BrokerProxyImpl;
+
+ typedef boost::shared_ptr<Object> ObjectPtr;
+
+ struct ObjectImpl {
+ typedef boost::shared_ptr<Value> ValuePtr;
+ const SchemaObjectClass* objectClass;
+ BrokerProxyImpl* broker;
+ boost::shared_ptr<ObjectId> objectId;
+ uint64_t createTime;
+ uint64_t destroyTime;
+ uint64_t lastUpdatedTime;
+ mutable std::map<std::string, ValuePtr> properties;
+ mutable std::map<std::string, ValuePtr> statistics;
+
+ ObjectImpl(const SchemaObjectClass* type);
+ ObjectImpl(const SchemaObjectClass* type, BrokerProxyImpl* b, qpid::framing::Buffer& buffer,
+ bool prop, bool stat, bool managed);
+ static Object* factory(const SchemaObjectClass* type, BrokerProxyImpl* b, qpid::framing::Buffer& buffer,
+ bool prop, bool stat, bool managed);
+ ~ObjectImpl();
+
+ void destroy();
+ const ObjectId* getObjectId() const { return objectId.get(); }
+ void setObjectId(ObjectId* oid) { objectId.reset(new ObjectId(*oid)); }
+ const SchemaObjectClass* getClass() const { return objectClass; }
+ Value* getValue(const std::string& key) const;
+ void invokeMethod(const std::string& methodName, const Value* inArgs, void* context) const;
+ bool isDeleted() const { return destroyTime != 0; }
+ void merge(const Object& from);
+
+ void parsePresenceMasks(qpid::framing::Buffer& buffer, std::set<std::string>& excludeList);
+ void encodeSchemaKey(qpid::framing::Buffer& buffer) const;
+ void encodeManagedObjectData(qpid::framing::Buffer& buffer) const;
+ void encodeProperties(qpid::framing::Buffer& buffer) const;
+ void encodeStatistics(qpid::framing::Buffer& buffer) const;
+ };
+}
+}
+
+#endif
+
diff --git a/cpp/src/qmf/engine/Protocol.cpp b/cpp/src/qmf/engine/Protocol.cpp
new file mode 100644
index 0000000000..9e5f490604
--- /dev/null
+++ b/cpp/src/qmf/engine/Protocol.cpp
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Protocol.h"
+#include "qpid/framing/Buffer.h"
+
+using namespace std;
+using namespace qmf::engine;
+using namespace qpid::framing;
+
+
+bool Protocol::checkHeader(Buffer& buf, uint8_t *opcode, uint32_t *seq)
+{
+ if (buf.available() < 8)
+ return false;
+
+ uint8_t h1 = buf.getOctet();
+ uint8_t h2 = buf.getOctet();
+ uint8_t h3 = buf.getOctet();
+
+ *opcode = buf.getOctet();
+ *seq = buf.getLong();
+
+ return h1 == 'A' && h2 == 'M' && h3 == '2';
+}
+
+void Protocol::encodeHeader(qpid::framing::Buffer& buf, uint8_t opcode, uint32_t seq)
+{
+ buf.putOctet('A');
+ buf.putOctet('M');
+ buf.putOctet('2');
+ buf.putOctet(opcode);
+ buf.putLong (seq);
+}
+
+
diff --git a/cpp/src/qmf/engine/Protocol.h b/cpp/src/qmf/engine/Protocol.h
new file mode 100644
index 0000000000..1cdfa60c84
--- /dev/null
+++ b/cpp/src/qmf/engine/Protocol.h
@@ -0,0 +1,69 @@
+#ifndef _QmfEngineProtocol_
+#define _QmfEngineProtocol_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/sys/IntegerTypes.h>
+
+namespace qpid {
+ namespace framing {
+ class Buffer;
+ }
+}
+
+namespace qmf {
+namespace engine {
+
+ class Protocol {
+ public:
+ static bool checkHeader(qpid::framing::Buffer& buf, uint8_t *opcode, uint32_t *seq);
+ static void encodeHeader(qpid::framing::Buffer& buf, uint8_t opcode, uint32_t seq = 0);
+
+ const static uint8_t OP_ATTACH_REQUEST = 'A';
+ const static uint8_t OP_ATTACH_RESPONSE = 'a';
+
+ const static uint8_t OP_BROKER_REQUEST = 'B';
+ const static uint8_t OP_BROKER_RESPONSE = 'b';
+
+ const static uint8_t OP_CONSOLE_ADDED_INDICATION = 'x';
+ const static uint8_t OP_COMMAND_COMPLETE = 'z';
+ const static uint8_t OP_HEARTBEAT_INDICATION = 'h';
+
+ const static uint8_t OP_PACKAGE_REQUEST = 'P';
+ const static uint8_t OP_PACKAGE_INDICATION = 'p';
+ const static uint8_t OP_CLASS_QUERY = 'Q';
+ const static uint8_t OP_CLASS_INDICATION = 'q';
+ const static uint8_t OP_SCHEMA_REQUEST = 'S';
+ const static uint8_t OP_SCHEMA_RESPONSE = 's';
+
+ const static uint8_t OP_METHOD_REQUEST = 'M';
+ const static uint8_t OP_METHOD_RESPONSE = 'm';
+ const static uint8_t OP_GET_QUERY = 'G';
+ const static uint8_t OP_OBJECT_INDICATION = 'g';
+ const static uint8_t OP_PROPERTY_INDICATION = 'c';
+ const static uint8_t OP_STATISTIC_INDICATION = 'i';
+ const static uint8_t OP_EVENT_INDICATION = 'e';
+ };
+
+}
+}
+
+#endif
+
diff --git a/cpp/src/qmf/engine/QueryImpl.cpp b/cpp/src/qmf/engine/QueryImpl.cpp
new file mode 100644
index 0000000000..6f2beeee87
--- /dev/null
+++ b/cpp/src/qmf/engine/QueryImpl.cpp
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "qmf/engine/QueryImpl.h"
+#include "qmf/engine/ObjectIdImpl.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/FieldTable.h"
+
+using namespace std;
+using namespace qmf::engine;
+using namespace qpid::framing;
+
+bool QueryElementImpl::evaluate(const Object* /*object*/) const
+{
+ // TODO: Implement this
+ return false;
+}
+
+bool QueryExpressionImpl::evaluate(const Object* /*object*/) const
+{
+ // TODO: Implement this
+ return false;
+}
+
+QueryImpl::QueryImpl(Buffer& buffer)
+{
+ FieldTable ft;
+ ft.decode(buffer);
+ // TODO
+}
+
+Query* QueryImpl::factory(Buffer& buffer)
+{
+ QueryImpl* impl(new QueryImpl(buffer));
+ return new Query(impl);
+}
+
+void QueryImpl::encode(Buffer& buffer) const
+{
+ FieldTable ft;
+
+ if (oid.get() != 0) {
+ ft.setString("_objectid", oid->impl->asString());
+ } else {
+ if (!packageName.empty())
+ ft.setString("_package", packageName);
+ ft.setString("_class", className);
+ }
+
+ ft.encode(buffer);
+}
+
+
+//==================================================================
+// Wrappers
+//==================================================================
+
+QueryElement::QueryElement(const char* attrName, const Value* value, ValueOper oper) : impl(new QueryElementImpl(attrName, value, oper)) {}
+QueryElement::QueryElement(QueryElementImpl* i) : impl(i) {}
+QueryElement::~QueryElement() { delete impl; }
+bool QueryElement::evaluate(const Object* object) const { return impl->evaluate(object); }
+
+QueryExpression::QueryExpression(ExprOper oper, const QueryOperand* operand1, const QueryOperand* operand2) : impl(new QueryExpressionImpl(oper, operand1, operand2)) {}
+QueryExpression::QueryExpression(QueryExpressionImpl* i) : impl(i) {}
+QueryExpression::~QueryExpression() { delete impl; }
+bool QueryExpression::evaluate(const Object* object) const { return impl->evaluate(object); }
+
+Query::Query(const char* className, const char* packageName) : impl(new QueryImpl(className, packageName)) {}
+Query::Query(const SchemaClassKey* key) : impl(new QueryImpl(key)) {}
+Query::Query(const ObjectId* oid) : impl(new QueryImpl(oid)) {}
+Query::Query(QueryImpl* i) : impl(i) {}
+Query::Query(const Query& from) : impl(new QueryImpl(*(from.impl))) {}
+Query::~Query() { delete impl; }
+void Query::setSelect(const QueryOperand* criterion) { impl->setSelect(criterion); }
+void Query::setLimit(uint32_t maxResults) { impl->setLimit(maxResults); }
+void Query::setOrderBy(const char* attrName, bool decreasing) { impl->setOrderBy(attrName, decreasing); }
+const char* Query::getPackage() const { return impl->getPackage().c_str(); }
+const char* Query::getClass() const { return impl->getClass().c_str(); }
+const ObjectId* Query::getObjectId() const { return impl->getObjectId(); }
+bool Query::haveSelect() const { return impl->haveSelect(); }
+bool Query::haveLimit() const { return impl->haveLimit(); }
+bool Query::haveOrderBy() const { return impl->haveOrderBy(); }
+const QueryOperand* Query::getSelect() const { return impl->getSelect(); }
+uint32_t Query::getLimit() const { return impl->getLimit(); }
+const char* Query::getOrderBy() const { return impl->getOrderBy().c_str(); }
+bool Query::getDecreasing() const { return impl->getDecreasing(); }
+
diff --git a/cpp/src/qmf/engine/QueryImpl.h b/cpp/src/qmf/engine/QueryImpl.h
new file mode 100644
index 0000000000..8ebe0d932f
--- /dev/null
+++ b/cpp/src/qmf/engine/QueryImpl.h
@@ -0,0 +1,102 @@
+#ifndef _QmfEngineQueryImpl_
+#define _QmfEngineQueryImpl_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Query.h"
+#include "qmf/engine/Schema.h"
+#include <string>
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+ namespace framing {
+ class Buffer;
+ }
+}
+
+namespace qmf {
+namespace engine {
+
+ struct QueryElementImpl {
+ QueryElementImpl(const std::string& a, const Value* v, ValueOper o) : attrName(a), value(v), oper(o) {}
+ ~QueryElementImpl() {}
+ bool evaluate(const Object* object) const;
+
+ std::string attrName;
+ const Value* value;
+ ValueOper oper;
+ };
+
+ struct QueryExpressionImpl {
+ QueryExpressionImpl(ExprOper o, const QueryOperand* operand1, const QueryOperand* operand2) : oper(o), left(operand1), right(operand2) {}
+ ~QueryExpressionImpl() {}
+ bool evaluate(const Object* object) const;
+
+ ExprOper oper;
+ const QueryOperand* left;
+ const QueryOperand* right;
+ };
+
+ struct QueryImpl {
+ // Constructors mapped to public
+ QueryImpl(const std::string& c, const std::string& p) : packageName(p), className(c), select(0), resultLimit(0) {}
+ QueryImpl(const SchemaClassKey* key) : packageName(key->getPackageName()), className(key->getClassName()), select(0), resultLimit(0) {}
+ QueryImpl(const ObjectId* oid) : oid(new ObjectId(*oid)), select(0), resultLimit(0) {}
+
+ // Factory constructors
+ QueryImpl(qpid::framing::Buffer& buffer);
+
+ ~QueryImpl() {};
+ static Query* factory(qpid::framing::Buffer& buffer);
+
+ void setSelect(const QueryOperand* criterion) { select = criterion; }
+ void setLimit(uint32_t maxResults) { resultLimit = maxResults; }
+ void setOrderBy(const std::string& attrName, bool decreasing) {
+ orderBy = attrName; orderDecreasing = decreasing;
+ }
+
+ const std::string& getPackage() const { return packageName; }
+ const std::string& getClass() const { return className; }
+ const ObjectId* getObjectId() const { return oid.get(); }
+
+ bool haveSelect() const { return select != 0; }
+ bool haveLimit() const { return resultLimit > 0; }
+ bool haveOrderBy() const { return !orderBy.empty(); }
+ const QueryOperand* getSelect() const { return select; }
+ uint32_t getLimit() const { return resultLimit; }
+ const std::string& getOrderBy() const { return orderBy; }
+ bool getDecreasing() const { return orderDecreasing; }
+
+ void encode(qpid::framing::Buffer& buffer) const;
+ bool singleAgent() const { return oid.get() != 0; }
+ uint32_t agentBank() const { return singleAgent() ? oid->getAgentBank() : 0; }
+
+ std::string packageName;
+ std::string className;
+ boost::shared_ptr<ObjectId> oid;
+ const QueryOperand* select;
+ uint32_t resultLimit;
+ std::string orderBy;
+ bool orderDecreasing;
+ };
+}
+}
+
+#endif
diff --git a/cpp/src/qmf/engine/ResilientConnection.cpp b/cpp/src/qmf/engine/ResilientConnection.cpp
new file mode 100644
index 0000000000..53524fdbd8
--- /dev/null
+++ b/cpp/src/qmf/engine/ResilientConnection.cpp
@@ -0,0 +1,489 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/ResilientConnection.h"
+#include "qmf/engine/MessageImpl.h"
+#include "qmf/engine/ConnectionSettingsImpl.h"
+#include <qpid/client/Connection.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/MessageListener.h>
+#include <qpid/client/SubscriptionManager.h>
+#include <qpid/client/Message.h>
+#include <qpid/sys/Thread.h>
+#include <qpid/sys/Runnable.h>
+#include <qpid/sys/Mutex.h>
+#include <qpid/sys/Condition.h>
+#include <qpid/sys/Time.h>
+#include <qpid/log/Statement.h>
+#include <qpid/RefCounted.h>
+#include <boost/bind.hpp>
+#include <string>
+#include <deque>
+#include <vector>
+#include <set>
+#include <boost/intrusive_ptr.hpp>
+#include <boost/noncopyable.hpp>
+
+using namespace std;
+using namespace qmf::engine;
+using namespace qpid;
+using qpid::sys::Mutex;
+
+namespace qmf {
+namespace engine {
+ struct ResilientConnectionEventImpl {
+ ResilientConnectionEvent::EventKind kind;
+ void* sessionContext;
+ string errorText;
+ MessageImpl message;
+
+ ResilientConnectionEventImpl(ResilientConnectionEvent::EventKind k,
+ const MessageImpl& m = MessageImpl()) :
+ kind(k), sessionContext(0), message(m) {}
+ ResilientConnectionEvent copy();
+ };
+
+ struct RCSession : public client::MessageListener, public qpid::sys::Runnable, public qpid::RefCounted {
+ typedef boost::intrusive_ptr<RCSession> Ptr;
+ ResilientConnectionImpl& connImpl;
+ string name;
+ client::Connection& connection;
+ client::Session session;
+ client::SubscriptionManager* subscriptions;
+ string userId;
+ void* userContext;
+ vector<string> dests;
+ qpid::sys::Thread thread;
+
+ RCSession(ResilientConnectionImpl& ci, const string& n, client::Connection& c, void* uc);
+ ~RCSession();
+ void received(client::Message& msg);
+ void run();
+ void stop();
+ };
+
+ class ResilientConnectionImpl : public qpid::sys::Runnable, public boost::noncopyable {
+ public:
+ ResilientConnectionImpl(const ConnectionSettings& settings);
+ ~ResilientConnectionImpl();
+
+ bool isConnected() const;
+ bool getEvent(ResilientConnectionEvent& event);
+ void popEvent();
+ bool createSession(const char* name, void* sessionContext, SessionHandle& handle);
+ void destroySession(SessionHandle handle);
+ void sendMessage(SessionHandle handle, qmf::engine::Message& message);
+ void declareQueue(SessionHandle handle, char* queue);
+ void deleteQueue(SessionHandle handle, char* queue);
+ void bind(SessionHandle handle, char* exchange, char* queue, char* key);
+ void unbind(SessionHandle handle, char* exchange, char* queue, char* key);
+ void setNotifyFd(int fd);
+
+ void run();
+ void failure();
+ void sessionClosed(RCSession* sess);
+
+ void EnqueueEvent(ResilientConnectionEvent::EventKind kind,
+ void* sessionContext = 0,
+ const MessageImpl& message = MessageImpl(),
+ const string& errorText = "");
+
+ private:
+ int notifyFd;
+ bool connected;
+ bool shutdown;
+ string lastError;
+ const ConnectionSettings settings;
+ client::Connection connection;
+ mutable qpid::sys::Mutex lock;
+ int delayMin;
+ int delayMax;
+ int delayFactor;
+ qpid::sys::Condition cond;
+ deque<ResilientConnectionEventImpl> eventQueue;
+ set<RCSession::Ptr> sessions;
+ qpid::sys::Thread connThread;
+ };
+}
+}
+
+ResilientConnectionEvent ResilientConnectionEventImpl::copy()
+{
+ ResilientConnectionEvent item;
+
+ ::memset(&item, 0, sizeof(ResilientConnectionEvent));
+ item.kind = kind;
+ item.sessionContext = sessionContext;
+ item.message = message.copy();
+ item.errorText = const_cast<char*>(errorText.c_str());
+
+ return item;
+}
+
+RCSession::RCSession(ResilientConnectionImpl& ci, const string& n, client::Connection& c, void* uc) :
+ connImpl(ci), name(n), connection(c), session(connection.newSession(name)),
+ subscriptions(new client::SubscriptionManager(session)), userContext(uc), thread(*this)
+{
+ const qpid::client::ConnectionSettings& operSettings = connection.getNegotiatedSettings();
+ userId = operSettings.username;
+}
+
+RCSession::~RCSession()
+{
+ subscriptions->stop();
+ thread.join();
+ session.close();
+ delete subscriptions;
+}
+
+void RCSession::run()
+{
+ try {
+ subscriptions->run();
+ } catch (exception& /*e*/) {
+ connImpl.sessionClosed(this);
+ }
+}
+
+void RCSession::stop()
+{
+ subscriptions->stop();
+}
+
+void RCSession::received(client::Message& msg)
+{
+ MessageImpl qmsg;
+ qmsg.body = msg.getData();
+
+ qpid::framing::DeliveryProperties dp = msg.getDeliveryProperties();
+ if (dp.hasRoutingKey()) {
+ qmsg.routingKey = dp.getRoutingKey();
+ }
+
+ qpid::framing::MessageProperties mp = msg.getMessageProperties();
+ if (mp.hasReplyTo()) {
+ const qpid::framing::ReplyTo& rt = mp.getReplyTo();
+ qmsg.replyExchange = rt.getExchange();
+ qmsg.replyKey = rt.getRoutingKey();
+ }
+
+ if (mp.hasUserId()) {
+ qmsg.userId = mp.getUserId();
+ }
+
+ connImpl.EnqueueEvent(ResilientConnectionEvent::RECV, userContext, qmsg);
+}
+
+ResilientConnectionImpl::ResilientConnectionImpl(const ConnectionSettings& _settings) :
+ notifyFd(-1), connected(false), shutdown(false), settings(_settings), delayMin(1), connThread(*this)
+{
+ connection.registerFailureCallback(boost::bind(&ResilientConnectionImpl::failure, this));
+ settings.impl->getRetrySettings(&delayMin, &delayMax, &delayFactor);
+}
+
+ResilientConnectionImpl::~ResilientConnectionImpl()
+{
+ shutdown = true;
+ connected = false;
+ cond.notify();
+ connThread.join();
+ connection.close();
+}
+
+bool ResilientConnectionImpl::isConnected() const
+{
+ Mutex::ScopedLock _lock(lock);
+ return connected;
+}
+
+bool ResilientConnectionImpl::getEvent(ResilientConnectionEvent& event)
+{
+ Mutex::ScopedLock _lock(lock);
+ if (eventQueue.empty())
+ return false;
+ event = eventQueue.front().copy();
+ return true;
+}
+
+void ResilientConnectionImpl::popEvent()
+{
+ Mutex::ScopedLock _lock(lock);
+ if (!eventQueue.empty())
+ eventQueue.pop_front();
+}
+
+bool ResilientConnectionImpl::createSession(const char* name, void* sessionContext,
+ SessionHandle& handle)
+{
+ Mutex::ScopedLock _lock(lock);
+ if (!connected)
+ return false;
+
+ RCSession::Ptr sess = RCSession::Ptr(new RCSession(*this, name, connection, sessionContext));
+
+ handle.impl = (void*) sess.get();
+ sessions.insert(sess);
+
+ return true;
+}
+
+void ResilientConnectionImpl::destroySession(SessionHandle handle)
+{
+ Mutex::ScopedLock _lock(lock);
+ RCSession::Ptr sess = RCSession::Ptr((RCSession*) handle.impl);
+ set<RCSession::Ptr>::iterator iter = sessions.find(sess);
+ if (iter != sessions.end()) {
+ for (vector<string>::iterator dIter = sess->dests.begin(); dIter != sess->dests.end(); dIter++)
+ sess->subscriptions->cancel(dIter->c_str());
+ sess->subscriptions->stop();
+ sess->subscriptions->wait();
+
+ sessions.erase(iter);
+ return;
+ }
+}
+
+void ResilientConnectionImpl::sendMessage(SessionHandle handle, qmf::engine::Message& message)
+{
+ Mutex::ScopedLock _lock(lock);
+ RCSession::Ptr sess = RCSession::Ptr((RCSession*) handle.impl);
+ set<RCSession::Ptr>::iterator iter = sessions.find(sess);
+ qpid::client::Message msg;
+ string data(message.body, message.length);
+ msg.getDeliveryProperties().setRoutingKey(message.routingKey);
+ msg.getMessageProperties().setReplyTo(qpid::framing::ReplyTo(message.replyExchange, message.replyKey));
+ if (settings.impl->getSendUserId())
+ msg.getMessageProperties().setUserId(sess->userId);
+ msg.setData(data);
+
+ try {
+ sess->session.messageTransfer(client::arg::content=msg, client::arg::destination=message.destination);
+ } catch(exception& e) {
+ QPID_LOG(error, "Session Exception during message-transfer: " << e.what());
+ sessions.erase(iter);
+ EnqueueEvent(ResilientConnectionEvent::SESSION_CLOSED, (*iter)->userContext);
+ }
+}
+
+void ResilientConnectionImpl::declareQueue(SessionHandle handle, char* queue)
+{
+ Mutex::ScopedLock _lock(lock);
+ RCSession* sess = (RCSession*) handle.impl;
+
+ sess->session.queueDeclare(client::arg::queue=queue, client::arg::autoDelete=true, client::arg::exclusive=true);
+ sess->subscriptions->setAcceptMode(client::ACCEPT_MODE_NONE);
+ sess->subscriptions->setAcquireMode(client::ACQUIRE_MODE_PRE_ACQUIRED);
+ sess->subscriptions->subscribe(*sess, queue, queue);
+ sess->subscriptions->setFlowControl(queue, client::FlowControl::unlimited());
+ sess->dests.push_back(string(queue));
+}
+
+void ResilientConnectionImpl::deleteQueue(SessionHandle handle, char* queue)
+{
+ Mutex::ScopedLock _lock(lock);
+ RCSession* sess = (RCSession*) handle.impl;
+
+ sess->session.queueDelete(client::arg::queue=queue);
+ for (vector<string>::iterator iter = sess->dests.begin();
+ iter != sess->dests.end(); iter++)
+ if (*iter == queue) {
+ sess->subscriptions->cancel(queue);
+ sess->dests.erase(iter);
+ break;
+ }
+}
+
+void ResilientConnectionImpl::bind(SessionHandle handle,
+ char* exchange, char* queue, char* key)
+{
+ Mutex::ScopedLock _lock(lock);
+ RCSession* sess = (RCSession*) handle.impl;
+
+ sess->session.exchangeBind(client::arg::exchange=exchange, client::arg::queue=queue, client::arg::bindingKey=key);
+}
+
+void ResilientConnectionImpl::unbind(SessionHandle handle,
+ char* exchange, char* queue, char* key)
+{
+ Mutex::ScopedLock _lock(lock);
+ RCSession* sess = (RCSession*) handle.impl;
+
+ sess->session.exchangeUnbind(client::arg::exchange=exchange, client::arg::queue=queue, client::arg::bindingKey=key);
+}
+
+void ResilientConnectionImpl::setNotifyFd(int fd)
+{
+ notifyFd = fd;
+}
+
+void ResilientConnectionImpl::run()
+{
+ int delay(delayMin);
+
+ while (true) {
+ try {
+ QPID_LOG(trace, "Trying to open connection...");
+ connection.open(settings.impl->getClientSettings());
+ {
+ Mutex::ScopedLock _lock(lock);
+ connected = true;
+ EnqueueEvent(ResilientConnectionEvent::CONNECTED);
+
+ while (connected)
+ cond.wait(lock);
+ delay = delayMin;
+
+ while (!sessions.empty()) {
+ set<RCSession::Ptr>::iterator iter = sessions.begin();
+ RCSession::Ptr sess = *iter;
+ sessions.erase(iter);
+ EnqueueEvent(ResilientConnectionEvent::SESSION_CLOSED, sess->userContext);
+ Mutex::ScopedUnlock _u(lock);
+ sess->stop();
+
+ // Nullify the intrusive pointer within the scoped unlock, otherwise,
+ // the reference is held until overwritted above (under lock) which causes
+ // the session destructor to be called with the lock held.
+ sess = 0;
+ }
+
+ EnqueueEvent(ResilientConnectionEvent::DISCONNECTED);
+
+ if (shutdown)
+ return;
+ }
+ connection.close();
+ } catch (exception &e) {
+ QPID_LOG(debug, "connection.open exception: " << e.what());
+ Mutex::ScopedLock _lock(lock);
+ lastError = e.what();
+ if (delay < delayMax)
+ delay *= delayFactor;
+ }
+
+ ::qpid::sys::sleep(delay);
+ }
+}
+
+void ResilientConnectionImpl::failure()
+{
+ Mutex::ScopedLock _lock(lock);
+
+ connected = false;
+ lastError = "Closed by Peer";
+ cond.notify();
+}
+
+void ResilientConnectionImpl::sessionClosed(RCSession*)
+{
+ Mutex::ScopedLock _lock(lock);
+ connected = false;
+ lastError = "Closed due to Session failure";
+ cond.notify();
+}
+
+void ResilientConnectionImpl::EnqueueEvent(ResilientConnectionEvent::EventKind kind,
+ void* sessionContext,
+ const MessageImpl& message,
+ const string& errorText)
+{
+ Mutex::ScopedLock _lock(lock);
+ ResilientConnectionEventImpl event(kind, message);
+
+ event.sessionContext = sessionContext;
+ event.errorText = errorText;
+
+ eventQueue.push_back(event);
+ if (notifyFd != -1)
+ {
+ int unused_ret; //Suppress warnings about ignoring return value.
+ unused_ret = ::write(notifyFd, ".", 1);
+ }
+}
+
+
+//==================================================================
+// Wrappers
+//==================================================================
+
+ResilientConnection::ResilientConnection(const ConnectionSettings& settings)
+{
+ impl = new ResilientConnectionImpl(settings);
+}
+
+ResilientConnection::~ResilientConnection()
+{
+ delete impl;
+}
+
+bool ResilientConnection::isConnected() const
+{
+ return impl->isConnected();
+}
+
+bool ResilientConnection::getEvent(ResilientConnectionEvent& event)
+{
+ return impl->getEvent(event);
+}
+
+void ResilientConnection::popEvent()
+{
+ impl->popEvent();
+}
+
+bool ResilientConnection::createSession(const char* name, void* sessionContext, SessionHandle& handle)
+{
+ return impl->createSession(name, sessionContext, handle);
+}
+
+void ResilientConnection::destroySession(SessionHandle handle)
+{
+ impl->destroySession(handle);
+}
+
+void ResilientConnection::sendMessage(SessionHandle handle, qmf::engine::Message& message)
+{
+ impl->sendMessage(handle, message);
+}
+
+void ResilientConnection::declareQueue(SessionHandle handle, char* queue)
+{
+ impl->declareQueue(handle, queue);
+}
+
+void ResilientConnection::deleteQueue(SessionHandle handle, char* queue)
+{
+ impl->deleteQueue(handle, queue);
+}
+
+void ResilientConnection::bind(SessionHandle handle, char* exchange, char* queue, char* key)
+{
+ impl->bind(handle, exchange, queue, key);
+}
+
+void ResilientConnection::unbind(SessionHandle handle, char* exchange, char* queue, char* key)
+{
+ impl->unbind(handle, exchange, queue, key);
+}
+
+void ResilientConnection::setNotifyFd(int fd)
+{
+ impl->setNotifyFd(fd);
+}
+
diff --git a/cpp/src/qmf/engine/SchemaImpl.cpp b/cpp/src/qmf/engine/SchemaImpl.cpp
new file mode 100644
index 0000000000..c37ec34890
--- /dev/null
+++ b/cpp/src/qmf/engine/SchemaImpl.cpp
@@ -0,0 +1,610 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/SchemaImpl.h"
+#include <qpid/framing/Buffer.h>
+#include <qpid/framing/FieldTable.h>
+#include <qpid/framing/Uuid.h>
+#include <string.h>
+#include <string>
+#include <vector>
+
+using namespace std;
+using namespace qmf::engine;
+using qpid::framing::Buffer;
+using qpid::framing::FieldTable;
+using qpid::framing::Uuid;
+
+SchemaHash::SchemaHash()
+{
+ for (int idx = 0; idx < 16; idx++)
+ hash[idx] = 0x5A;
+}
+
+void SchemaHash::encode(Buffer& buffer) const
+{
+ buffer.putBin128(hash);
+}
+
+void SchemaHash::decode(Buffer& buffer)
+{
+ buffer.getBin128(hash);
+}
+
+void SchemaHash::update(uint8_t data)
+{
+ update((char*) &data, 1);
+}
+
+void SchemaHash::update(const char* data, uint32_t len)
+{
+ uint64_t* first = (uint64_t*) hash;
+ uint64_t* second = (uint64_t*) hash + 1;
+
+ for (uint32_t idx = 0; idx < len; idx++) {
+ *first = *first ^ (uint64_t) data[idx];
+ *second = *second << 1;
+ *second |= ((*first & 0x8000000000000000LL) >> 63);
+ *first = *first << 1;
+ *first = *first ^ *second;
+ }
+}
+
+bool SchemaHash::operator==(const SchemaHash& other) const
+{
+ return ::memcmp(&hash, &other.hash, 16) == 0;
+}
+
+bool SchemaHash::operator<(const SchemaHash& other) const
+{
+ return ::memcmp(&hash, &other.hash, 16) < 0;
+}
+
+bool SchemaHash::operator>(const SchemaHash& other) const
+{
+ return ::memcmp(&hash, &other.hash, 16) > 0;
+}
+
+SchemaArgumentImpl::SchemaArgumentImpl(Buffer& buffer)
+{
+ FieldTable map;
+ map.decode(buffer);
+
+ name = map.getAsString("name");
+ typecode = (Typecode) map.getAsInt("type");
+ unit = map.getAsString("unit");
+ description = map.getAsString("desc");
+
+ dir = DIR_IN;
+ string dstr(map.getAsString("dir"));
+ if (dstr == "O")
+ dir = DIR_OUT;
+ else if (dstr == "IO")
+ dir = DIR_IN_OUT;
+}
+
+SchemaArgument* SchemaArgumentImpl::factory(Buffer& buffer)
+{
+ SchemaArgumentImpl* impl(new SchemaArgumentImpl(buffer));
+ return new SchemaArgument(impl);
+}
+
+void SchemaArgumentImpl::encode(Buffer& buffer) const
+{
+ FieldTable map;
+
+ map.setString("name", name);
+ map.setInt("type", (int) typecode);
+ if (dir == DIR_IN)
+ map.setString("dir", "I");
+ else if (dir == DIR_OUT)
+ map.setString("dir", "O");
+ else
+ map.setString("dir", "IO");
+ if (!unit.empty())
+ map.setString("unit", unit);
+ if (!description.empty())
+ map.setString("desc", description);
+
+ map.encode(buffer);
+}
+
+void SchemaArgumentImpl::updateHash(SchemaHash& hash) const
+{
+ hash.update(name);
+ hash.update(typecode);
+ hash.update(dir);
+ hash.update(unit);
+ hash.update(description);
+}
+
+SchemaMethodImpl::SchemaMethodImpl(Buffer& buffer)
+{
+ FieldTable map;
+ int argCount;
+
+ map.decode(buffer);
+ name = map.getAsString("name");
+ argCount = map.getAsInt("argCount");
+ description = map.getAsString("desc");
+
+ for (int idx = 0; idx < argCount; idx++) {
+ SchemaArgument* arg = SchemaArgumentImpl::factory(buffer);
+ addArgument(arg);
+ }
+}
+
+SchemaMethod* SchemaMethodImpl::factory(Buffer& buffer)
+{
+ SchemaMethodImpl* impl(new SchemaMethodImpl(buffer));
+ return new SchemaMethod(impl);
+}
+
+void SchemaMethodImpl::encode(Buffer& buffer) const
+{
+ FieldTable map;
+
+ map.setString("name", name);
+ map.setInt("argCount", arguments.size());
+ if (!description.empty())
+ map.setString("desc", description);
+ map.encode(buffer);
+
+ for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin();
+ iter != arguments.end(); iter++)
+ (*iter)->impl->encode(buffer);
+}
+
+void SchemaMethodImpl::addArgument(const SchemaArgument* argument)
+{
+ arguments.push_back(argument);
+}
+
+const SchemaArgument* SchemaMethodImpl::getArgument(int idx) const
+{
+ int count = 0;
+ for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin();
+ iter != arguments.end(); iter++, count++)
+ if (idx == count)
+ return (*iter);
+ return 0;
+}
+
+void SchemaMethodImpl::updateHash(SchemaHash& hash) const
+{
+ hash.update(name);
+ hash.update(description);
+ for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin();
+ iter != arguments.end(); iter++)
+ (*iter)->impl->updateHash(hash);
+}
+
+SchemaPropertyImpl::SchemaPropertyImpl(Buffer& buffer)
+{
+ FieldTable map;
+ map.decode(buffer);
+
+ name = map.getAsString("name");
+ typecode = (Typecode) map.getAsInt("type");
+ access = (Access) map.getAsInt("access");
+ index = map.getAsInt("index") != 0;
+ optional = map.getAsInt("optional") != 0;
+ unit = map.getAsString("unit");
+ description = map.getAsString("desc");
+}
+
+SchemaProperty* SchemaPropertyImpl::factory(Buffer& buffer)
+{
+ SchemaPropertyImpl* impl(new SchemaPropertyImpl(buffer));
+ return new SchemaProperty(impl);
+}
+
+void SchemaPropertyImpl::encode(Buffer& buffer) const
+{
+ FieldTable map;
+
+ map.setString("name", name);
+ map.setInt("type", (int) typecode);
+ map.setInt("access", (int) access);
+ map.setInt("index", index ? 1 : 0);
+ map.setInt("optional", optional ? 1 : 0);
+ if (!unit.empty())
+ map.setString("unit", unit);
+ if (!description.empty())
+ map.setString("desc", description);
+
+ map.encode(buffer);
+}
+
+void SchemaPropertyImpl::updateHash(SchemaHash& hash) const
+{
+ hash.update(name);
+ hash.update(typecode);
+ hash.update(access);
+ hash.update(index);
+ hash.update(optional);
+ hash.update(unit);
+ hash.update(description);
+}
+
+SchemaStatisticImpl::SchemaStatisticImpl(Buffer& buffer)
+{
+ FieldTable map;
+ map.decode(buffer);
+
+ name = map.getAsString("name");
+ typecode = (Typecode) map.getAsInt("type");
+ unit = map.getAsString("unit");
+ description = map.getAsString("desc");
+}
+
+SchemaStatistic* SchemaStatisticImpl::factory(Buffer& buffer)
+{
+ SchemaStatisticImpl* impl(new SchemaStatisticImpl(buffer));
+ return new SchemaStatistic(impl);
+}
+
+void SchemaStatisticImpl::encode(Buffer& buffer) const
+{
+ FieldTable map;
+
+ map.setString("name", name);
+ map.setInt("type", (int) typecode);
+ if (!unit.empty())
+ map.setString("unit", unit);
+ if (!description.empty())
+ map.setString("desc", description);
+
+ map.encode(buffer);
+}
+
+void SchemaStatisticImpl::updateHash(SchemaHash& hash) const
+{
+ hash.update(name);
+ hash.update(typecode);
+ hash.update(unit);
+ hash.update(description);
+}
+
+SchemaClassKeyImpl::SchemaClassKeyImpl(const string& p, const string& n, const SchemaHash& h) : package(p), name(n), hash(h) {}
+
+SchemaClassKeyImpl::SchemaClassKeyImpl(Buffer& buffer) : package(packageContainer), name(nameContainer), hash(hashContainer)
+{
+ buffer.getShortString(packageContainer);
+ buffer.getShortString(nameContainer);
+ hashContainer.decode(buffer);
+}
+
+SchemaClassKey* SchemaClassKeyImpl::factory(const string& package, const string& name, const SchemaHash& hash)
+{
+ SchemaClassKeyImpl* impl(new SchemaClassKeyImpl(package, name, hash));
+ return new SchemaClassKey(impl);
+}
+
+SchemaClassKey* SchemaClassKeyImpl::factory(Buffer& buffer)
+{
+ SchemaClassKeyImpl* impl(new SchemaClassKeyImpl(buffer));
+ return new SchemaClassKey(impl);
+}
+
+void SchemaClassKeyImpl::encode(Buffer& buffer) const
+{
+ buffer.putShortString(package);
+ buffer.putShortString(name);
+ hash.encode(buffer);
+}
+
+bool SchemaClassKeyImpl::operator==(const SchemaClassKeyImpl& other) const
+{
+ return package == other.package &&
+ name == other.name &&
+ hash == other.hash;
+}
+
+bool SchemaClassKeyImpl::operator<(const SchemaClassKeyImpl& other) const
+{
+ if (package < other.package) return true;
+ if (package > other.package) return false;
+ if (name < other.name) return true;
+ if (name > other.name) return false;
+ return hash < other.hash;
+}
+
+const string& SchemaClassKeyImpl::str() const
+{
+ Uuid printableHash(hash.get());
+ stringstream str;
+ str << package << ":" << name << "(" << printableHash << ")";
+ repr = str.str();
+ return repr;
+}
+
+SchemaObjectClassImpl::SchemaObjectClassImpl(Buffer& buffer) : hasHash(true), classKey(SchemaClassKeyImpl::factory(package, name, hash))
+{
+ buffer.getShortString(package);
+ buffer.getShortString(name);
+ hash.decode(buffer);
+
+ uint16_t propCount = buffer.getShort();
+ uint16_t statCount = buffer.getShort();
+ uint16_t methodCount = buffer.getShort();
+
+ for (uint16_t idx = 0; idx < propCount; idx++) {
+ const SchemaProperty* property = SchemaPropertyImpl::factory(buffer);
+ addProperty(property);
+ }
+
+ for (uint16_t idx = 0; idx < statCount; idx++) {
+ const SchemaStatistic* statistic = SchemaStatisticImpl::factory(buffer);
+ addStatistic(statistic);
+ }
+
+ for (uint16_t idx = 0; idx < methodCount; idx++) {
+ SchemaMethod* method = SchemaMethodImpl::factory(buffer);
+ addMethod(method);
+ }
+}
+
+SchemaObjectClass* SchemaObjectClassImpl::factory(Buffer& buffer)
+{
+ SchemaObjectClassImpl* impl(new SchemaObjectClassImpl(buffer));
+ return new SchemaObjectClass(impl);
+}
+
+void SchemaObjectClassImpl::encode(Buffer& buffer) const
+{
+ buffer.putOctet((uint8_t) CLASS_OBJECT);
+ buffer.putShortString(package);
+ buffer.putShortString(name);
+ hash.encode(buffer);
+ //buffer.putOctet(0); // No parent class
+ buffer.putShort((uint16_t) properties.size());
+ buffer.putShort((uint16_t) statistics.size());
+ buffer.putShort((uint16_t) methods.size());
+
+ for (vector<const SchemaProperty*>::const_iterator iter = properties.begin();
+ iter != properties.end(); iter++)
+ (*iter)->impl->encode(buffer);
+ for (vector<const SchemaStatistic*>::const_iterator iter = statistics.begin();
+ iter != statistics.end(); iter++)
+ (*iter)->impl->encode(buffer);
+ for (vector<const SchemaMethod*>::const_iterator iter = methods.begin();
+ iter != methods.end(); iter++)
+ (*iter)->impl->encode(buffer);
+}
+
+const SchemaClassKey* SchemaObjectClassImpl::getClassKey() const
+{
+ if (!hasHash) {
+ hasHash = true;
+ hash.update(package);
+ hash.update(name);
+ for (vector<const SchemaProperty*>::const_iterator iter = properties.begin();
+ iter != properties.end(); iter++)
+ (*iter)->impl->updateHash(hash);
+ for (vector<const SchemaStatistic*>::const_iterator iter = statistics.begin();
+ iter != statistics.end(); iter++)
+ (*iter)->impl->updateHash(hash);
+ for (vector<const SchemaMethod*>::const_iterator iter = methods.begin();
+ iter != methods.end(); iter++)
+ (*iter)->impl->updateHash(hash);
+ }
+
+ return classKey.get();
+}
+
+void SchemaObjectClassImpl::addProperty(const SchemaProperty* property)
+{
+ properties.push_back(property);
+}
+
+void SchemaObjectClassImpl::addStatistic(const SchemaStatistic* statistic)
+{
+ statistics.push_back(statistic);
+}
+
+void SchemaObjectClassImpl::addMethod(const SchemaMethod* method)
+{
+ methods.push_back(method);
+}
+
+const SchemaProperty* SchemaObjectClassImpl::getProperty(int idx) const
+{
+ int count = 0;
+ for (vector<const SchemaProperty*>::const_iterator iter = properties.begin();
+ iter != properties.end(); iter++, count++)
+ if (idx == count)
+ return *iter;
+ return 0;
+}
+
+const SchemaStatistic* SchemaObjectClassImpl::getStatistic(int idx) const
+{
+ int count = 0;
+ for (vector<const SchemaStatistic*>::const_iterator iter = statistics.begin();
+ iter != statistics.end(); iter++, count++)
+ if (idx == count)
+ return *iter;
+ return 0;
+}
+
+const SchemaMethod* SchemaObjectClassImpl::getMethod(int idx) const
+{
+ int count = 0;
+ for (vector<const SchemaMethod*>::const_iterator iter = methods.begin();
+ iter != methods.end(); iter++, count++)
+ if (idx == count)
+ return *iter;
+ return 0;
+}
+
+SchemaEventClassImpl::SchemaEventClassImpl(Buffer& buffer) : hasHash(true), classKey(SchemaClassKeyImpl::factory(package, name, hash))
+{
+ buffer.getShortString(package);
+ buffer.getShortString(name);
+ hash.decode(buffer);
+ buffer.putOctet(0); // No parent class
+
+ uint16_t argCount = buffer.getShort();
+
+ for (uint16_t idx = 0; idx < argCount; idx++) {
+ SchemaArgument* argument = SchemaArgumentImpl::factory(buffer);
+ addArgument(argument);
+ }
+}
+
+SchemaEventClass* SchemaEventClassImpl::factory(Buffer& buffer)
+{
+ SchemaEventClassImpl* impl(new SchemaEventClassImpl(buffer));
+ return new SchemaEventClass(impl);
+}
+
+void SchemaEventClassImpl::encode(Buffer& buffer) const
+{
+ buffer.putOctet((uint8_t) CLASS_EVENT);
+ buffer.putShortString(package);
+ buffer.putShortString(name);
+ hash.encode(buffer);
+ buffer.putShort((uint16_t) arguments.size());
+
+ for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin();
+ iter != arguments.end(); iter++)
+ (*iter)->impl->encode(buffer);
+}
+
+const SchemaClassKey* SchemaEventClassImpl::getClassKey() const
+{
+ if (!hasHash) {
+ hasHash = true;
+ hash.update(package);
+ hash.update(name);
+ for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin();
+ iter != arguments.end(); iter++)
+ (*iter)->impl->updateHash(hash);
+ }
+ return classKey.get();
+}
+
+void SchemaEventClassImpl::addArgument(const SchemaArgument* argument)
+{
+ arguments.push_back(argument);
+}
+
+const SchemaArgument* SchemaEventClassImpl::getArgument(int idx) const
+{
+ int count = 0;
+ for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin();
+ iter != arguments.end(); iter++, count++)
+ if (idx == count)
+ return (*iter);
+ return 0;
+}
+
+
+//==================================================================
+// Wrappers
+//==================================================================
+
+SchemaArgument::SchemaArgument(const char* name, Typecode typecode) { impl = new SchemaArgumentImpl(name, typecode); }
+SchemaArgument::SchemaArgument(SchemaArgumentImpl* i) : impl(i) {}
+SchemaArgument::SchemaArgument(const SchemaArgument& from) : impl(new SchemaArgumentImpl(*(from.impl))) {}
+SchemaArgument::~SchemaArgument() { delete impl; }
+void SchemaArgument::setDirection(Direction dir) { impl->setDirection(dir); }
+void SchemaArgument::setUnit(const char* val) { impl->setUnit(val); }
+void SchemaArgument::setDesc(const char* desc) { impl->setDesc(desc); }
+const char* SchemaArgument::getName() const { return impl->getName().c_str(); }
+Typecode SchemaArgument::getType() const { return impl->getType(); }
+Direction SchemaArgument::getDirection() const { return impl->getDirection(); }
+const char* SchemaArgument::getUnit() const { return impl->getUnit().c_str(); }
+const char* SchemaArgument::getDesc() const { return impl->getDesc().c_str(); }
+
+SchemaMethod::SchemaMethod(const char* name) : impl(new SchemaMethodImpl(name)) {}
+SchemaMethod::SchemaMethod(SchemaMethodImpl* i) : impl(i) {}
+SchemaMethod::SchemaMethod(const SchemaMethod& from) : impl(new SchemaMethodImpl(*(from.impl))) {}
+SchemaMethod::~SchemaMethod() { delete impl; }
+void SchemaMethod::addArgument(const SchemaArgument* argument) { impl->addArgument(argument); }
+void SchemaMethod::setDesc(const char* desc) { impl->setDesc(desc); }
+const char* SchemaMethod::getName() const { return impl->getName().c_str(); }
+const char* SchemaMethod::getDesc() const { return impl->getDesc().c_str(); }
+int SchemaMethod::getArgumentCount() const { return impl->getArgumentCount(); }
+const SchemaArgument* SchemaMethod::getArgument(int idx) const { return impl->getArgument(idx); }
+
+SchemaProperty::SchemaProperty(const char* name, Typecode typecode) : impl(new SchemaPropertyImpl(name, typecode)) {}
+SchemaProperty::SchemaProperty(SchemaPropertyImpl* i) : impl(i) {}
+SchemaProperty::SchemaProperty(const SchemaProperty& from) : impl(new SchemaPropertyImpl(*(from.impl))) {}
+SchemaProperty::~SchemaProperty() { delete impl; }
+void SchemaProperty::setAccess(Access access) { impl->setAccess(access); }
+void SchemaProperty::setIndex(bool val) { impl->setIndex(val); }
+void SchemaProperty::setOptional(bool val) { impl->setOptional(val); }
+void SchemaProperty::setUnit(const char* val) { impl->setUnit(val); }
+void SchemaProperty::setDesc(const char* desc) { impl->setDesc(desc); }
+const char* SchemaProperty::getName() const { return impl->getName().c_str(); }
+Typecode SchemaProperty::getType() const { return impl->getType(); }
+Access SchemaProperty::getAccess() const { return impl->getAccess(); }
+bool SchemaProperty::isIndex() const { return impl->isIndex(); }
+bool SchemaProperty::isOptional() const { return impl->isOptional(); }
+const char* SchemaProperty::getUnit() const { return impl->getUnit().c_str(); }
+const char* SchemaProperty::getDesc() const { return impl->getDesc().c_str(); }
+
+SchemaStatistic::SchemaStatistic(const char* name, Typecode typecode) : impl(new SchemaStatisticImpl(name, typecode)) {}
+SchemaStatistic::SchemaStatistic(SchemaStatisticImpl* i) : impl(i) {}
+SchemaStatistic::SchemaStatistic(const SchemaStatistic& from) : impl(new SchemaStatisticImpl(*(from.impl))) {}
+SchemaStatistic::~SchemaStatistic() { delete impl; }
+void SchemaStatistic::setUnit(const char* val) { impl->setUnit(val); }
+void SchemaStatistic::setDesc(const char* desc) { impl->setDesc(desc); }
+const char* SchemaStatistic::getName() const { return impl->getName().c_str(); }
+Typecode SchemaStatistic::getType() const { return impl->getType(); }
+const char* SchemaStatistic::getUnit() const { return impl->getUnit().c_str(); }
+const char* SchemaStatistic::getDesc() const { return impl->getDesc().c_str(); }
+
+SchemaClassKey::SchemaClassKey(SchemaClassKeyImpl* i) : impl(i) {}
+SchemaClassKey::SchemaClassKey(const SchemaClassKey& from) : impl(new SchemaClassKeyImpl(*(from.impl))) {}
+SchemaClassKey::~SchemaClassKey() { delete impl; }
+const char* SchemaClassKey::getPackageName() const { return impl->getPackageName().c_str(); }
+const char* SchemaClassKey::getClassName() const { return impl->getClassName().c_str(); }
+const uint8_t* SchemaClassKey::getHash() const { return impl->getHash(); }
+const char* SchemaClassKey::asString() const { return impl->str().c_str(); }
+bool SchemaClassKey::operator==(const SchemaClassKey& other) const { return *impl == *(other.impl); }
+bool SchemaClassKey::operator<(const SchemaClassKey& other) const { return *impl < *(other.impl); }
+
+SchemaObjectClass::SchemaObjectClass(const char* package, const char* name) : impl(new SchemaObjectClassImpl(package, name)) {}
+SchemaObjectClass::SchemaObjectClass(SchemaObjectClassImpl* i) : impl(i) {}
+SchemaObjectClass::SchemaObjectClass(const SchemaObjectClass& from) : impl(new SchemaObjectClassImpl(*(from.impl))) {}
+SchemaObjectClass::~SchemaObjectClass() { delete impl; }
+void SchemaObjectClass::addProperty(const SchemaProperty* property) { impl->addProperty(property); }
+void SchemaObjectClass::addStatistic(const SchemaStatistic* statistic) { impl->addStatistic(statistic); }
+void SchemaObjectClass::addMethod(const SchemaMethod* method) { impl->addMethod(method); }
+const SchemaClassKey* SchemaObjectClass::getClassKey() const { return impl->getClassKey(); }
+int SchemaObjectClass::getPropertyCount() const { return impl->getPropertyCount(); }
+int SchemaObjectClass::getStatisticCount() const { return impl->getStatisticCount(); }
+int SchemaObjectClass::getMethodCount() const { return impl->getMethodCount(); }
+const SchemaProperty* SchemaObjectClass::getProperty(int idx) const { return impl->getProperty(idx); }
+const SchemaStatistic* SchemaObjectClass::getStatistic(int idx) const { return impl->getStatistic(idx); }
+const SchemaMethod* SchemaObjectClass::getMethod(int idx) const { return impl->getMethod(idx); }
+
+SchemaEventClass::SchemaEventClass(const char* package, const char* name) : impl(new SchemaEventClassImpl(package, name)) {}
+SchemaEventClass::SchemaEventClass(SchemaEventClassImpl* i) : impl(i) {}
+SchemaEventClass::SchemaEventClass(const SchemaEventClass& from) : impl(new SchemaEventClassImpl(*(from.impl))) {}
+SchemaEventClass::~SchemaEventClass() { delete impl; }
+void SchemaEventClass::addArgument(const SchemaArgument* argument) { impl->addArgument(argument); }
+void SchemaEventClass::setDesc(const char* desc) { impl->setDesc(desc); }
+const SchemaClassKey* SchemaEventClass::getClassKey() const { return impl->getClassKey(); }
+int SchemaEventClass::getArgumentCount() const { return impl->getArgumentCount(); }
+const SchemaArgument* SchemaEventClass::getArgument(int idx) const { return impl->getArgument(idx); }
+
diff --git a/cpp/src/qmf/engine/SchemaImpl.h b/cpp/src/qmf/engine/SchemaImpl.h
new file mode 100644
index 0000000000..af3a1d98e4
--- /dev/null
+++ b/cpp/src/qmf/engine/SchemaImpl.h
@@ -0,0 +1,223 @@
+#ifndef _QmfEngineSchemaImpl_
+#define _QmfEngineSchemaImpl_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Schema.h"
+#include <string>
+#include <vector>
+#include <qpid/framing/Buffer.h>
+
+namespace qmf {
+namespace engine {
+
+ // TODO: Destructors for schema classes
+ // TODO: Add "frozen" attribute for schema classes so they can't be modified after
+ // they've been registered.
+
+ class SchemaHash {
+ uint8_t hash[16];
+ public:
+ SchemaHash();
+ void encode(qpid::framing::Buffer& buffer) const;
+ void decode(qpid::framing::Buffer& buffer);
+ void update(const char* data, uint32_t len);
+ void update(uint8_t data);
+ void update(const std::string& data) { update(data.c_str(), data.size()); }
+ void update(Typecode t) { update((uint8_t) t); }
+ void update(Direction d) { update((uint8_t) d); }
+ void update(Access a) { update((uint8_t) a); }
+ void update(bool b) { update((uint8_t) (b ? 1 : 0)); }
+ const uint8_t* get() const { return hash; }
+ bool operator==(const SchemaHash& other) const;
+ bool operator<(const SchemaHash& other) const;
+ bool operator>(const SchemaHash& other) const;
+ };
+
+ struct SchemaArgumentImpl {
+ std::string name;
+ Typecode typecode;
+ Direction dir;
+ std::string unit;
+ std::string description;
+
+ SchemaArgumentImpl(const char* n, Typecode t) : name(n), typecode(t), dir(DIR_IN) {}
+ SchemaArgumentImpl(qpid::framing::Buffer& buffer);
+ static SchemaArgument* factory(qpid::framing::Buffer& buffer);
+ void encode(qpid::framing::Buffer& buffer) const;
+ void setDirection(Direction d) { dir = d; }
+ void setUnit(const char* val) { unit = val; }
+ void setDesc(const char* desc) { description = desc; }
+ const std::string& getName() const { return name; }
+ Typecode getType() const { return typecode; }
+ Direction getDirection() const { return dir; }
+ const std::string& getUnit() const { return unit; }
+ const std::string& getDesc() const { return description; }
+ void updateHash(SchemaHash& hash) const;
+ };
+
+ struct SchemaMethodImpl {
+ std::string name;
+ std::string description;
+ std::vector<const SchemaArgument*> arguments;
+
+ SchemaMethodImpl(const char* n) : name(n) {}
+ SchemaMethodImpl(qpid::framing::Buffer& buffer);
+ static SchemaMethod* factory(qpid::framing::Buffer& buffer);
+ void encode(qpid::framing::Buffer& buffer) const;
+ void addArgument(const SchemaArgument* argument);
+ void setDesc(const char* desc) { description = desc; }
+ const std::string& getName() const { return name; }
+ const std::string& getDesc() const { return description; }
+ int getArgumentCount() const { return arguments.size(); }
+ const SchemaArgument* getArgument(int idx) const;
+ void updateHash(SchemaHash& hash) const;
+ };
+
+ struct SchemaPropertyImpl {
+ std::string name;
+ Typecode typecode;
+ Access access;
+ bool index;
+ bool optional;
+ std::string unit;
+ std::string description;
+
+ SchemaPropertyImpl(const char* n, Typecode t) : name(n), typecode(t), access(ACCESS_READ_ONLY), index(false), optional(false) {}
+ SchemaPropertyImpl(qpid::framing::Buffer& buffer);
+ static SchemaProperty* factory(qpid::framing::Buffer& buffer);
+ void encode(qpid::framing::Buffer& buffer) const;
+ void setAccess(Access a) { access = a; }
+ void setIndex(bool val) { index = val; }
+ void setOptional(bool val) { optional = val; }
+ void setUnit(const char* val) { unit = val; }
+ void setDesc(const char* desc) { description = desc; }
+ const std::string& getName() const { return name; }
+ Typecode getType() const { return typecode; }
+ Access getAccess() const { return access; }
+ bool isIndex() const { return index; }
+ bool isOptional() const { return optional; }
+ const std::string& getUnit() const { return unit; }
+ const std::string& getDesc() const { return description; }
+ void updateHash(SchemaHash& hash) const;
+ };
+
+ struct SchemaStatisticImpl {
+ std::string name;
+ Typecode typecode;
+ std::string unit;
+ std::string description;
+
+ SchemaStatisticImpl(const char* n, Typecode t) : name(n), typecode(t) {}
+ SchemaStatisticImpl(qpid::framing::Buffer& buffer);
+ static SchemaStatistic* factory(qpid::framing::Buffer& buffer);
+ void encode(qpid::framing::Buffer& buffer) const;
+ void setUnit(const char* val) { unit = val; }
+ void setDesc(const char* desc) { description = desc; }
+ const std::string& getName() const { return name; }
+ Typecode getType() const { return typecode; }
+ const std::string& getUnit() const { return unit; }
+ const std::string& getDesc() const { return description; }
+ void updateHash(SchemaHash& hash) const;
+ };
+
+ struct SchemaClassKeyImpl {
+ const std::string& package;
+ const std::string& name;
+ const SchemaHash& hash;
+ mutable std::string repr;
+
+ // The *Container elements are only used if there isn't an external place to
+ // store these values.
+ std::string packageContainer;
+ std::string nameContainer;
+ SchemaHash hashContainer;
+
+ SchemaClassKeyImpl(const std::string& package, const std::string& name, const SchemaHash& hash);
+ SchemaClassKeyImpl(qpid::framing::Buffer& buffer);
+ static SchemaClassKey* factory(const std::string& package, const std::string& name, const SchemaHash& hash);
+ static SchemaClassKey* factory(qpid::framing::Buffer& buffer);
+
+ const std::string& getPackageName() const { return package; }
+ const std::string& getClassName() const { return name; }
+ const uint8_t* getHash() const { return hash.get(); }
+
+ void encode(qpid::framing::Buffer& buffer) const;
+ bool operator==(const SchemaClassKeyImpl& other) const;
+ bool operator<(const SchemaClassKeyImpl& other) const;
+ const std::string& str() const;
+ };
+
+ struct SchemaObjectClassImpl {
+ std::string package;
+ std::string name;
+ mutable SchemaHash hash;
+ mutable bool hasHash;
+ std::auto_ptr<SchemaClassKey> classKey;
+ std::vector<const SchemaProperty*> properties;
+ std::vector<const SchemaStatistic*> statistics;
+ std::vector<const SchemaMethod*> methods;
+
+ SchemaObjectClassImpl(const char* p, const char* n) :
+ package(p), name(n), hasHash(false), classKey(SchemaClassKeyImpl::factory(package, name, hash)) {}
+ SchemaObjectClassImpl(qpid::framing::Buffer& buffer);
+ static SchemaObjectClass* factory(qpid::framing::Buffer& buffer);
+
+ void encode(qpid::framing::Buffer& buffer) const;
+ void addProperty(const SchemaProperty* property);
+ void addStatistic(const SchemaStatistic* statistic);
+ void addMethod(const SchemaMethod* method);
+
+ const SchemaClassKey* getClassKey() const;
+ int getPropertyCount() const { return properties.size(); }
+ int getStatisticCount() const { return statistics.size(); }
+ int getMethodCount() const { return methods.size(); }
+ const SchemaProperty* getProperty(int idx) const;
+ const SchemaStatistic* getStatistic(int idx) const;
+ const SchemaMethod* getMethod(int idx) const;
+ };
+
+ struct SchemaEventClassImpl {
+ std::string package;
+ std::string name;
+ mutable SchemaHash hash;
+ mutable bool hasHash;
+ std::auto_ptr<SchemaClassKey> classKey;
+ std::string description;
+ std::vector<const SchemaArgument*> arguments;
+
+ SchemaEventClassImpl(const char* p, const char* n) :
+ package(p), name(n), hasHash(false), classKey(SchemaClassKeyImpl::factory(package, name, hash)) {}
+ SchemaEventClassImpl(qpid::framing::Buffer& buffer);
+ static SchemaEventClass* factory(qpid::framing::Buffer& buffer);
+
+ void encode(qpid::framing::Buffer& buffer) const;
+ void addArgument(const SchemaArgument* argument);
+ void setDesc(const char* desc) { description = desc; }
+
+ const SchemaClassKey* getClassKey() const;
+ int getArgumentCount() const { return arguments.size(); }
+ const SchemaArgument* getArgument(int idx) const;
+ };
+}
+}
+
+#endif
+
diff --git a/cpp/src/qmf/engine/SequenceManager.cpp b/cpp/src/qmf/engine/SequenceManager.cpp
new file mode 100644
index 0000000000..4a4644a8b9
--- /dev/null
+++ b/cpp/src/qmf/engine/SequenceManager.cpp
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "qmf/engine/SequenceManager.h"
+
+using namespace std;
+using namespace qmf::engine;
+using namespace qpid::sys;
+
+SequenceManager::SequenceManager() : nextSequence(1) {}
+
+void SequenceManager::setUnsolicitedContext(SequenceContext::Ptr ctx)
+{
+ unsolicitedContext = ctx;
+}
+
+uint32_t SequenceManager::reserve(SequenceContext::Ptr ctx)
+{
+ Mutex::ScopedLock _lock(lock);
+ if (ctx.get() == 0)
+ ctx = unsolicitedContext;
+ uint32_t seq = nextSequence;
+ while (contextMap.find(seq) != contextMap.end())
+ seq = seq < 0xFFFFFFFF ? seq + 1 : 1;
+ nextSequence = seq < 0xFFFFFFFF ? seq + 1 : 1;
+ contextMap[seq] = ctx;
+ ctx->reserve();
+ return seq;
+}
+
+void SequenceManager::release(uint32_t sequence)
+{
+ Mutex::ScopedLock _lock(lock);
+
+ if (sequence == 0) {
+ if (unsolicitedContext.get() != 0)
+ unsolicitedContext->release();
+ return;
+ }
+
+ map<uint32_t, SequenceContext::Ptr>::iterator iter = contextMap.find(sequence);
+ if (iter != contextMap.end()) {
+ if (iter->second != 0)
+ iter->second->release();
+ contextMap.erase(iter);
+ }
+}
+
+void SequenceManager::releaseAll()
+{
+ Mutex::ScopedLock _lock(lock);
+ contextMap.clear();
+}
+
+void SequenceManager::dispatch(uint8_t opcode, uint32_t sequence, const string& routingKey, qpid::framing::Buffer& buffer)
+{
+ Mutex::ScopedLock _lock(lock);
+ bool done;
+
+ if (sequence == 0) {
+ if (unsolicitedContext.get() != 0) {
+ done = unsolicitedContext->handleMessage(opcode, sequence, routingKey, buffer);
+ if (done)
+ unsolicitedContext->release();
+ }
+ return;
+ }
+
+ map<uint32_t, SequenceContext::Ptr>::iterator iter = contextMap.find(sequence);
+ if (iter != contextMap.end()) {
+ if (iter->second != 0) {
+ done = iter->second->handleMessage(opcode, sequence, routingKey, buffer);
+ if (done) {
+ iter->second->release();
+ contextMap.erase(iter);
+ }
+ }
+ }
+}
+
diff --git a/cpp/src/qmf/engine/SequenceManager.h b/cpp/src/qmf/engine/SequenceManager.h
new file mode 100644
index 0000000000..9e47e38610
--- /dev/null
+++ b/cpp/src/qmf/engine/SequenceManager.h
@@ -0,0 +1,68 @@
+#ifndef _QmfEngineSequenceManager_
+#define _QmfEngineSequenceManager_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/sys/Mutex.h"
+#include <boost/shared_ptr.hpp>
+#include <map>
+
+namespace qpid {
+ namespace framing {
+ class Buffer;
+ }
+}
+
+namespace qmf {
+namespace engine {
+
+ class SequenceContext {
+ public:
+ typedef boost::shared_ptr<SequenceContext> Ptr;
+ SequenceContext() {}
+ virtual ~SequenceContext() {}
+
+ virtual void reserve() = 0;
+ virtual bool handleMessage(uint8_t opcode, uint32_t sequence, const std::string& routingKey, qpid::framing::Buffer& buffer) = 0;
+ virtual void release() = 0;
+ };
+
+ class SequenceManager {
+ public:
+ SequenceManager();
+
+ void setUnsolicitedContext(SequenceContext::Ptr ctx);
+ uint32_t reserve(SequenceContext::Ptr ctx = SequenceContext::Ptr());
+ void release(uint32_t sequence);
+ void releaseAll();
+ void dispatch(uint8_t opcode, uint32_t sequence, const std::string& routingKey, qpid::framing::Buffer& buffer);
+
+ private:
+ mutable qpid::sys::Mutex lock;
+ uint32_t nextSequence;
+ SequenceContext::Ptr unsolicitedContext;
+ std::map<uint32_t, SequenceContext::Ptr> contextMap;
+ };
+
+}
+}
+
+#endif
+
diff --git a/cpp/src/qmf/engine/ValueImpl.cpp b/cpp/src/qmf/engine/ValueImpl.cpp
new file mode 100644
index 0000000000..1949d4b946
--- /dev/null
+++ b/cpp/src/qmf/engine/ValueImpl.cpp
@@ -0,0 +1,264 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/ValueImpl.h"
+#include <qpid/framing/FieldTable.h>
+
+using namespace std;
+using namespace qmf::engine;
+using qpid::framing::Buffer;
+
+ValueImpl::ValueImpl(Typecode t, Buffer& buf) : typecode(t)
+{
+ uint64_t first;
+ uint64_t second;
+ qpid::framing::FieldTable ft;
+
+ switch (typecode) {
+ case TYPE_UINT8 : value.u32 = (uint32_t) buf.getOctet(); break;
+ case TYPE_UINT16 : value.u32 = (uint32_t) buf.getShort(); break;
+ case TYPE_UINT32 : value.u32 = (uint32_t) buf.getLong(); break;
+ case TYPE_UINT64 : value.u64 = buf.getLongLong(); break;
+ case TYPE_SSTR : buf.getShortString(stringVal); break;
+ case TYPE_LSTR : buf.getMediumString(stringVal); break;
+ case TYPE_ABSTIME : value.s64 = buf.getLongLong(); break;
+ case TYPE_DELTATIME : value.u64 = buf.getLongLong(); break;
+ case TYPE_BOOL : value.boolVal = (buf.getOctet() != 0); break;
+ case TYPE_FLOAT : value.floatVal = buf.getFloat(); break;
+ case TYPE_DOUBLE : value.doubleVal = buf.getDouble(); break;
+ case TYPE_INT8 : value.s32 = (int32_t) ((int8_t) buf.getOctet()); break;
+ case TYPE_INT16 : value.s32 = (int32_t) ((int16_t) buf.getShort()); break;
+ case TYPE_INT32 : value.s32 = (int32_t) buf.getLong(); break;
+ case TYPE_INT64 : value.s64 = buf.getLongLong(); break;
+ case TYPE_UUID : buf.getBin128(value.uuidVal); break;
+ case TYPE_REF:
+ first = buf.getLongLong();
+ second = buf.getLongLong();
+ refVal.impl->setValue(first, second);
+ break;
+
+ case TYPE_MAP:
+ ft.decode(buf);
+ break;
+
+ case TYPE_LIST:
+ case TYPE_ARRAY:
+ case TYPE_OBJECT:
+ default:
+ break;
+ }
+}
+
+ValueImpl::ValueImpl(Typecode t, Typecode at) : typecode(t), valid(false), arrayTypecode(at)
+{
+}
+
+ValueImpl::ValueImpl(Typecode t) : typecode(t)
+{
+ ::memset(&value, 0, sizeof(value));
+}
+
+Value* ValueImpl::factory(Typecode t, Buffer& b)
+{
+ ValueImpl* impl(new ValueImpl(t, b));
+ return new Value(impl);
+}
+
+Value* ValueImpl::factory(Typecode t)
+{
+ ValueImpl* impl(new ValueImpl(t));
+ return new Value(impl);
+}
+
+ValueImpl::~ValueImpl()
+{
+}
+
+void ValueImpl::encode(Buffer& buf) const
+{
+ switch (typecode) {
+ case TYPE_UINT8 : buf.putOctet((uint8_t) value.u32); break;
+ case TYPE_UINT16 : buf.putShort((uint16_t) value.u32); break;
+ case TYPE_UINT32 : buf.putLong(value.u32); break;
+ case TYPE_UINT64 : buf.putLongLong(value.u64); break;
+ case TYPE_SSTR : buf.putShortString(stringVal); break;
+ case TYPE_LSTR : buf.putMediumString(stringVal); break;
+ case TYPE_ABSTIME : buf.putLongLong(value.s64); break;
+ case TYPE_DELTATIME : buf.putLongLong(value.u64); break;
+ case TYPE_BOOL : buf.putOctet(value.boolVal ? 1 : 0); break;
+ case TYPE_FLOAT : buf.putFloat(value.floatVal); break;
+ case TYPE_DOUBLE : buf.putDouble(value.doubleVal); break;
+ case TYPE_INT8 : buf.putOctet((uint8_t) value.s32); break;
+ case TYPE_INT16 : buf.putShort((uint16_t) value.s32); break;
+ case TYPE_INT32 : buf.putLong(value.s32); break;
+ case TYPE_INT64 : buf.putLongLong(value.s64); break;
+ case TYPE_UUID : buf.putBin128(value.uuidVal); break;
+ case TYPE_REF : refVal.impl->encode(buf); break;
+ case TYPE_MAP: // TODO
+ case TYPE_LIST:
+ case TYPE_ARRAY:
+ case TYPE_OBJECT:
+ default:
+ break;
+ }
+}
+
+bool ValueImpl::keyInMap(const char* key) const
+{
+ return typecode == TYPE_MAP && mapVal.count(key) > 0;
+}
+
+Value* ValueImpl::byKey(const char* key)
+{
+ if (keyInMap(key)) {
+ map<std::string, Value>::iterator iter = mapVal.find(key);
+ if (iter != mapVal.end())
+ return &iter->second;
+ }
+ return 0;
+}
+
+const Value* ValueImpl::byKey(const char* key) const
+{
+ if (keyInMap(key)) {
+ map<std::string, Value>::const_iterator iter = mapVal.find(key);
+ if (iter != mapVal.end())
+ return &iter->second;
+ }
+ return 0;
+}
+
+void ValueImpl::deleteKey(const char* key)
+{
+ mapVal.erase(key);
+}
+
+void ValueImpl::insert(const char* key, Value* val)
+{
+ pair<string, Value> entry(key, *val);
+ mapVal.insert(entry);
+}
+
+const char* ValueImpl::key(uint32_t idx) const
+{
+ map<std::string, Value>::const_iterator iter = mapVal.begin();
+ for (uint32_t i = 0; i < idx; i++) {
+ if (iter == mapVal.end())
+ break;
+ iter++;
+ }
+
+ if (iter == mapVal.end())
+ return 0;
+ else
+ return iter->first.c_str();
+}
+
+Value* ValueImpl::listItem(uint32_t)
+{
+ return 0;
+}
+
+void ValueImpl::appendToList(Value*)
+{
+}
+
+void ValueImpl::deleteListItem(uint32_t)
+{
+}
+
+Value* ValueImpl::arrayItem(uint32_t)
+{
+ return 0;
+}
+
+void ValueImpl::appendToArray(Value*)
+{
+}
+
+void ValueImpl::deleteArrayItem(uint32_t)
+{
+}
+
+
+//==================================================================
+// Wrappers
+//==================================================================
+
+Value::Value(const Value& from) : impl(new ValueImpl(*(from.impl))) {}
+Value::Value(Typecode t, Typecode at) : impl(new ValueImpl(t, at)) {}
+Value::Value(ValueImpl* i) : impl(i) {}
+Value::~Value() { delete impl;}
+
+Typecode Value::getType() const { return impl->getType(); }
+bool Value::isNull() const { return impl->isNull(); }
+void Value::setNull() { impl->setNull(); }
+bool Value::isObjectId() const { return impl->isObjectId(); }
+const ObjectId& Value::asObjectId() const { return impl->asObjectId(); }
+void Value::setObjectId(const ObjectId& oid) { impl->setObjectId(oid); }
+bool Value::isUint() const { return impl->isUint(); }
+uint32_t Value::asUint() const { return impl->asUint(); }
+void Value::setUint(uint32_t val) { impl->setUint(val); }
+bool Value::isInt() const { return impl->isInt(); }
+int32_t Value::asInt() const { return impl->asInt(); }
+void Value::setInt(int32_t val) { impl->setInt(val); }
+bool Value::isUint64() const { return impl->isUint64(); }
+uint64_t Value::asUint64() const { return impl->asUint64(); }
+void Value::setUint64(uint64_t val) { impl->setUint64(val); }
+bool Value::isInt64() const { return impl->isInt64(); }
+int64_t Value::asInt64() const { return impl->asInt64(); }
+void Value::setInt64(int64_t val) { impl->setInt64(val); }
+bool Value::isString() const { return impl->isString(); }
+const char* Value::asString() const { return impl->asString(); }
+void Value::setString(const char* val) { impl->setString(val); }
+bool Value::isBool() const { return impl->isBool(); }
+bool Value::asBool() const { return impl->asBool(); }
+void Value::setBool(bool val) { impl->setBool(val); }
+bool Value::isFloat() const { return impl->isFloat(); }
+float Value::asFloat() const { return impl->asFloat(); }
+void Value::setFloat(float val) { impl->setFloat(val); }
+bool Value::isDouble() const { return impl->isDouble(); }
+double Value::asDouble() const { return impl->asDouble(); }
+void Value::setDouble(double val) { impl->setDouble(val); }
+bool Value::isUuid() const { return impl->isUuid(); }
+const uint8_t* Value::asUuid() const { return impl->asUuid(); }
+void Value::setUuid(const uint8_t* val) { impl->setUuid(val); }
+bool Value::isObject() const { return impl->isObject(); }
+const Object* Value::asObject() const { return impl->asObject(); }
+void Value::setObject(Object* val) { impl->setObject(val); }
+bool Value::isMap() const { return impl->isMap(); }
+bool Value::keyInMap(const char* key) const { return impl->keyInMap(key); }
+Value* Value::byKey(const char* key) { return impl->byKey(key); }
+const Value* Value::byKey(const char* key) const { return impl->byKey(key); }
+void Value::deleteKey(const char* key) { impl->deleteKey(key); }
+void Value::insert(const char* key, Value* val) { impl->insert(key, val); }
+uint32_t Value::keyCount() const { return impl->keyCount(); }
+const char* Value::key(uint32_t idx) const { return impl->key(idx); }
+bool Value::isList() const { return impl->isList(); }
+uint32_t Value::listItemCount() const { return impl->listItemCount(); }
+Value* Value::listItem(uint32_t idx) { return impl->listItem(idx); }
+void Value::appendToList(Value* val) { impl->appendToList(val); }
+void Value::deleteListItem(uint32_t idx) { impl->deleteListItem(idx); }
+bool Value::isArray() const { return impl->isArray(); }
+Typecode Value::arrayType() const { return impl->arrayType(); }
+uint32_t Value::arrayItemCount() const { return impl->arrayItemCount(); }
+Value* Value::arrayItem(uint32_t idx) { return impl->arrayItem(idx); }
+void Value::appendToArray(Value* val) { impl->appendToArray(val); }
+void Value::deleteArrayItem(uint32_t idx) { impl->deleteArrayItem(idx); }
+
diff --git a/cpp/src/qmf/engine/ValueImpl.h b/cpp/src/qmf/engine/ValueImpl.h
new file mode 100644
index 0000000000..b6adae5d93
--- /dev/null
+++ b/cpp/src/qmf/engine/ValueImpl.h
@@ -0,0 +1,150 @@
+#ifndef _QmfEngineValueImpl_
+#define _QmfEngineValueImpl_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Value.h>
+#include <qmf/engine/ObjectIdImpl.h>
+#include <qmf/engine/Object.h>
+#include <qpid/framing/Buffer.h>
+#include <string>
+#include <string.h>
+#include <map>
+#include <vector>
+#include <boost/shared_ptr.hpp>
+
+namespace qmf {
+namespace engine {
+
+ // TODO: set valid flag on all value settors
+ // TODO: add a modified flag and accessors
+
+ struct ValueImpl {
+ const Typecode typecode;
+ bool valid;
+
+ ObjectId refVal;
+ std::string stringVal;
+ std::auto_ptr<Object> objectVal;
+ std::map<std::string, Value> mapVal;
+ std::vector<Value> vectorVal;
+ Typecode arrayTypecode;
+
+ union {
+ uint32_t u32;
+ uint64_t u64;
+ int32_t s32;
+ int64_t s64;
+ bool boolVal;
+ float floatVal;
+ double doubleVal;
+ uint8_t uuidVal[16];
+ } value;
+
+ ValueImpl(const ValueImpl& from) :
+ typecode(from.typecode), valid(from.valid), refVal(from.refVal), stringVal(from.stringVal),
+ objectVal(from.objectVal.get() ? new Object(*(from.objectVal)) : 0),
+ mapVal(from.mapVal), vectorVal(from.vectorVal), arrayTypecode(from.arrayTypecode),
+ value(from.value) {}
+
+ ValueImpl(Typecode t, Typecode at);
+ ValueImpl(Typecode t, qpid::framing::Buffer& b);
+ ValueImpl(Typecode t);
+ static Value* factory(Typecode t, qpid::framing::Buffer& b);
+ static Value* factory(Typecode t);
+ ~ValueImpl();
+
+ void encode(qpid::framing::Buffer& b) const;
+
+ Typecode getType() const { return typecode; }
+ bool isNull() const { return !valid; }
+ void setNull() { valid = false; }
+
+ bool isObjectId() const { return typecode == TYPE_REF; }
+ const ObjectId& asObjectId() const { return refVal; }
+ void setObjectId(const ObjectId& o) { refVal = o; } // TODO
+
+ bool isUint() const { return typecode >= TYPE_UINT8 && typecode <= TYPE_UINT32; }
+ uint32_t asUint() const { return value.u32; }
+ void setUint(uint32_t val) { value.u32 = val; }
+
+ bool isInt() const { return typecode >= TYPE_INT8 && typecode <= TYPE_INT32; }
+ int32_t asInt() const { return value.s32; }
+ void setInt(int32_t val) { value.s32 = val; }
+
+ bool isUint64() const { return typecode == TYPE_UINT64 || typecode == TYPE_DELTATIME; }
+ uint64_t asUint64() const { return value.u64; }
+ void setUint64(uint64_t val) { value.u64 = val; }
+
+ bool isInt64() const { return typecode == TYPE_INT64 || typecode == TYPE_ABSTIME; }
+ int64_t asInt64() const { return value.s64; }
+ void setInt64(int64_t val) { value.s64 = val; }
+
+ bool isString() const { return typecode == TYPE_SSTR || typecode == TYPE_LSTR; }
+ const char* asString() const { return stringVal.c_str(); }
+ void setString(const char* val) { stringVal = val; }
+
+ bool isBool() const { return typecode == TYPE_BOOL; }
+ bool asBool() const { return value.boolVal; }
+ void setBool(bool val) { value.boolVal = val; }
+
+ bool isFloat() const { return typecode == TYPE_FLOAT; }
+ float asFloat() const { return value.floatVal; }
+ void setFloat(float val) { value.floatVal = val; }
+
+ bool isDouble() const { return typecode == TYPE_DOUBLE; }
+ double asDouble() const { return value.doubleVal; }
+ void setDouble(double val) { value.doubleVal = val; }
+
+ bool isUuid() const { return typecode == TYPE_UUID; }
+ const uint8_t* asUuid() const { return value.uuidVal; }
+ void setUuid(const uint8_t* val) { ::memcpy(value.uuidVal, val, 16); }
+
+ bool isObject() const { return typecode == TYPE_OBJECT; }
+ Object* asObject() const { return objectVal.get(); }
+ void setObject(Object* val) { objectVal.reset(val); }
+
+ bool isMap() const { return typecode == TYPE_MAP; }
+ bool keyInMap(const char* key) const;
+ Value* byKey(const char* key);
+ const Value* byKey(const char* key) const;
+ void deleteKey(const char* key);
+ void insert(const char* key, Value* val);
+ uint32_t keyCount() const { return mapVal.size(); }
+ const char* key(uint32_t idx) const;
+
+ bool isList() const { return typecode == TYPE_LIST; }
+ uint32_t listItemCount() const { return vectorVal.size(); }
+ Value* listItem(uint32_t idx);
+ void appendToList(Value* val);
+ void deleteListItem(uint32_t idx);
+
+ bool isArray() const { return typecode == TYPE_ARRAY; }
+ Typecode arrayType() const { return arrayTypecode; }
+ uint32_t arrayItemCount() const { return vectorVal.size(); }
+ Value* arrayItem(uint32_t idx);
+ void appendToArray(Value* val);
+ void deleteArrayItem(uint32_t idx);
+ };
+}
+}
+
+#endif
+
diff --git a/cpp/src/qmfc.mk b/cpp/src/qmfc.mk
new file mode 100644
index 0000000000..f3e6dc259d
--- /dev/null
+++ b/cpp/src/qmfc.mk
@@ -0,0 +1,55 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http:#www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#
+# qmf console library makefile fragment, to be included in Makefile.am
+#
+lib_LTLIBRARIES += libqmfconsole.la
+
+# Public header files.
+nobase_include_HEADERS += \
+ ../include/qpid/console/Agent.h \
+ ../include/qpid/console/Broker.h \
+ ../include/qpid/console/ClassKey.h \
+ ../include/qpid/console/ConsoleImportExport.h \
+ ../include/qpid/console/ConsoleListener.h \
+ ../include/qpid/console/Event.h \
+ ../include/qpid/console/Object.h \
+ ../include/qpid/console/ObjectId.h \
+ ../include/qpid/console/Package.h \
+ ../include/qpid/console/Schema.h \
+ ../include/qpid/console/SequenceManager.h \
+ ../include/qpid/console/SessionManager.h \
+ ../include/qpid/console/Value.h
+
+libqmfconsole_la_SOURCES = \
+ qpid/console/Agent.cpp \
+ qpid/console/Broker.cpp \
+ qpid/console/ClassKey.cpp \
+ qpid/console/Event.cpp \
+ qpid/console/Object.cpp \
+ qpid/console/ObjectId.cpp \
+ qpid/console/Package.cpp \
+ qpid/console/Schema.cpp \
+ qpid/console/SequenceManager.cpp \
+ qpid/console/SessionManager.cpp \
+ qpid/console/Value.cpp
+
+libqmfconsole_la_LIBADD = libqpidclient.la
+
diff --git a/cpp/src/qpid/Address.cpp b/cpp/src/qpid/Address.cpp
new file mode 100644
index 0000000000..c3f6829fd3
--- /dev/null
+++ b/cpp/src/qpid/Address.cpp
@@ -0,0 +1,58 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/Address.h"
+
+#include <ostream>
+
+using namespace std;
+
+namespace qpid {
+
+TcpAddress::TcpAddress(const std::string& h, uint16_t p): host(h), port(p) {}
+
+struct AddressOstreamVisitor : public boost::static_visitor<ostream&> {
+ ostream& out;
+ AddressOstreamVisitor(ostream& o) : out(o) {}
+ template <class T> ostream& operator()(const T& data) { return out << data; }
+};
+
+ostream& operator<<(ostream& os, const Address& addr) {
+ AddressOstreamVisitor visitor(os);
+ return boost::apply_visitor(visitor, addr.value);
+}
+
+bool operator==(const TcpAddress& x, const TcpAddress& y) {
+ return y.host==x.host && y.port == x.port;
+}
+
+ostream& operator<<(ostream& os, const TcpAddress& a) {
+ return os << "tcp:" << a.host << ":" << a.port;
+}
+
+ExampleAddress::ExampleAddress(const char c) : data(c) {}
+
+bool operator==(const ExampleAddress& x, const ExampleAddress& y) {
+ return x.data == y.data;
+}
+
+ostream& operator<<(ostream& os, const ExampleAddress& ex) {
+ return os << "example:" << ex.data;
+}
+
+} // namespace qpid
diff --git a/cpp/src/qpid/DataDir.cpp b/cpp/src/qpid/DataDir.cpp
index 18b52b9b8f..ad732052ab 100644
--- a/cpp/src/qpid/DataDir.cpp
+++ b/cpp/src/qpid/DataDir.cpp
@@ -18,15 +18,11 @@
*
*/
-#include "Exception.h"
-#include "DataDir.h"
+#include "qpid/Exception.h"
+#include "qpid/DataDir.h"
#include "qpid/log/Statement.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/file.h>
-#include <fcntl.h>
-#include <cerrno>
-#include <unistd.h>
+#include "qpid/sys/FileSysDir.h"
+#include "qpid/sys/LockFile.h"
namespace qpid {
@@ -40,16 +36,9 @@ DataDir::DataDir (std::string path) :
return;
}
- const char *cpath = dirPath.c_str ();
- struct stat s;
- if (::stat(cpath, &s)) {
- if (errno == ENOENT) {
- if (::mkdir(cpath, 0755))
- throw Exception ("Can't create data directory: " + path);
- }
- else
- throw Exception ("Data directory not found: " + path);
- }
+ sys::FileSysDir dir(dirPath);
+ if (!dir.exists())
+ dir.mkdir();
std::string lockFileName(path);
lockFileName += "/lock";
lockFile = std::auto_ptr<sys::LockFile>(new sys::LockFile(lockFileName, true));
diff --git a/cpp/src/qpid/DataDir.h b/cpp/src/qpid/DataDir.h
index 7de5ebf62d..828299f3ba 100644
--- a/cpp/src/qpid/DataDir.h
+++ b/cpp/src/qpid/DataDir.h
@@ -23,10 +23,14 @@
#include <string>
#include <memory>
-#include "qpid/sys/LockFile.h"
+#include "qpid/CommonImportExport.h"
namespace qpid {
+ namespace sys {
+ class LockFile;
+ }
+
/**
* DataDir class.
*/
@@ -38,11 +42,11 @@ class DataDir
public:
- DataDir (std::string path);
- ~DataDir ();
+ QPID_COMMON_EXTERN DataDir (std::string path);
+ QPID_COMMON_EXTERN ~DataDir ();
- bool isEnabled () { return enabled; }
- std::string getPath () { return dirPath; }
+ bool isEnabled() { return enabled; }
+ const std::string& getPath() { return dirPath; }
};
} // namespace qpid
diff --git a/cpp/src/qpid/Exception.cpp b/cpp/src/qpid/Exception.cpp
index 9e884efec0..16a3a13d17 100644
--- a/cpp/src/qpid/Exception.cpp
+++ b/cpp/src/qpid/Exception.cpp
@@ -20,7 +20,7 @@
*/
#include "qpid/log/Statement.h"
-#include "Exception.h"
+#include "qpid/Exception.h"
#include <typeinfo>
#include <assert.h>
#include <string.h>
@@ -28,7 +28,7 @@
namespace qpid {
Exception::Exception(const std::string& msg) throw() : message(msg) {
- QPID_LOG(debug, "Exception constructed: " << message);
+ QPID_LOG_IF(debug, !msg.empty(), "Exception constructed: " << message);
}
Exception::~Exception() throw() {}
diff --git a/cpp/src/qpid/Exception.h b/cpp/src/qpid/Exception.h
deleted file mode 100644
index 9cf564104d..0000000000
--- a/cpp/src/qpid/Exception.h
+++ /dev/null
@@ -1,85 +0,0 @@
-#ifndef _Exception_
-#define _Exception_
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/framing/amqp_types.h"
-#include "qpid/framing/constants.h"
-#include "qpid/sys/StrError.h"
-#include "qpid/Msg.h"
-
-#include <memory>
-#include <string>
-#include <errno.h>
-
-namespace qpid
-{
-
-/**
- * Base class for Qpid runtime exceptions.
- */
-class Exception : public std::exception
-{
- public:
- explicit Exception(const std::string& message=std::string()) throw();
- virtual ~Exception() throw();
- virtual const char* what() const throw(); // prefix: message
- virtual std::string getMessage() const; // Unprefixed message
- virtual std::string getPrefix() const; // Prefix
-
- private:
- std::string message;
- mutable std::string whatStr;
-};
-
-/** Exception that includes an errno message. */
-struct ErrnoException : public Exception {
- ErrnoException(const std::string& msg, int err) : Exception(msg+": "+qpid::sys::strError(err)) {}
- ErrnoException(const std::string& msg) : Exception(msg+": "+qpid::sys::strError(errno)) {}
-};
-
-struct SessionException : public Exception {
- const framing::ReplyCode code;
- SessionException(framing::ReplyCode code_, const std::string& message)
- : Exception(message), code(code_) {}
-};
-
-struct ChannelException : public Exception {
- const framing::ReplyCode code;
- ChannelException(framing::ReplyCode _code, const std::string& message)
- : Exception(message), code(_code) {}
-};
-
-struct ConnectionException : public Exception {
- const framing::ReplyCode code;
- ConnectionException(framing::ReplyCode _code, const std::string& message)
- : Exception(message), code(_code) {}
-};
-
-struct ClosedException : public Exception {
- ClosedException(const std::string& msg=std::string());
- std::string getPrefix() const;
-};
-
-} // namespace qpid
-
-#endif /*!_Exception_*/
diff --git a/cpp/src/qpid/InlineAllocator.h b/cpp/src/qpid/InlineAllocator.h
deleted file mode 100644
index bf2f570599..0000000000
--- a/cpp/src/qpid/InlineAllocator.h
+++ /dev/null
@@ -1,84 +0,0 @@
-#ifndef QPID_INLINEALLOCATOR_H
-#define QPID_INLINEALLOCATOR_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <memory>
-#include <assert.h>
-#include <boost/type_traits/type_with_alignment.hpp>
-#include <boost/type_traits/alignment_of.hpp>
-
-namespace qpid {
-
-/**
- * An allocator that has inline storage for up to Max objects
- * of type BaseAllocator::value_type.
- */
-template <class BaseAllocator, size_t Max>
-class InlineAllocator : public BaseAllocator {
- public:
- typedef typename BaseAllocator::pointer pointer;
- typedef typename BaseAllocator::size_type size_type;
- typedef typename BaseAllocator::value_type value_type;
-
- InlineAllocator() : allocated(false) {}
- InlineAllocator(const InlineAllocator& x) : BaseAllocator(x), allocated(false) {}
-
- pointer allocate(size_type n) {
- if (n <= Max && !allocated) {
- allocated=true;
- return reinterpret_cast<value_type*>(address());
- }
- else
- return BaseAllocator::allocate(n, 0);
- }
-
- void deallocate(pointer p, size_type n) {
- if (p == address()) {
- assert(allocated);
- allocated=false;
- }
- else
- BaseAllocator::deallocate(p, n);
- }
-
- template<typename T1>
- struct rebind {
- typedef typename BaseAllocator::template rebind<T1>::other BaseOther;
- typedef InlineAllocator<BaseOther, Max> other;
- };
-
- private:
- // POD object with alignment and size to hold Max value_types.
- static const size_t ALIGNMENT=boost::alignment_of<value_type>::value;
- typedef typename boost::type_with_alignment<ALIGNMENT>::type Aligner;
- union Store {
- Aligner aligner_;
- char sizer_[sizeof(value_type)*Max];
- } store;
- value_type* address() { return reinterpret_cast<value_type*>(&store); }
- bool allocated;
-};
-
-} // namespace qpid
-
-#endif /*!QPID_INLINEALLOCATOR_H*/
diff --git a/cpp/src/qpid/InlineVector.h b/cpp/src/qpid/InlineVector.h
deleted file mode 100644
index 551b9912e7..0000000000
--- a/cpp/src/qpid/InlineVector.h
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef QPID_INLINEVECTOR_H
-#define QPID_INLINEVECTOR_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "InlineAllocator.h"
-#include <vector>
-
-namespace qpid {
-
-/**
- * A vector that stores up to Max elements in inline storage,
- * otherwise uses normal vector allocation.
- *
- * NOTE: depends on some non-standard but highly probably assumptions
- * about how std::vector uses its allocator, they are true for g++.
- * - default constructor does not allocate.
- * - reserve(N) does not allocate more than N elements.
- * - vector never re-allocates when size() < capacity()
- */
-template <class T, size_t Max, class Alloc=std::allocator<T> >
-class InlineVector : public std::vector<T, InlineAllocator<Alloc, Max> >
-{
- typedef std::vector<T, InlineAllocator<Alloc, Max> > Base;
- public:
- typedef typename Base::allocator_type allocator_type;
- typedef typename Base::value_type value_type;
- typedef typename Base::size_type size_type;
-
- explicit InlineVector(const allocator_type& a=allocator_type()) : Base(a) {
- this->reserve(Max);
- }
-
- explicit InlineVector(size_type n, const value_type& x = value_type(),
- const allocator_type& a=allocator_type()) : Base(a)
- {
- this->reserve(std::max(n, Max));
- this->insert(this->end(), n, x);
- }
-
- InlineVector(const InlineVector& x) : Base() {
- this->reserve(std::max(x.size(), Max));
- *this = x;
- }
-};
-
-} // namespace qpid
-
-#endif /*!QPID_INLINEVECTOR_H*/
diff --git a/cpp/src/qpid/Modules.cpp b/cpp/src/qpid/Modules.cpp
new file mode 100644
index 0000000000..70549bd553
--- /dev/null
+++ b/cpp/src/qpid/Modules.cpp
@@ -0,0 +1,95 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "config.h"
+#include "qpid/Modules.h"
+#include "qpid/Exception.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/Shlib.h"
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+
+namespace fs=boost::filesystem;
+
+namespace {
+
+// CMake sets QPID_MODULE_SUFFIX; Autoconf doesn't, so assume Linux .so
+#if defined (QPID_MODULE_SUFFIX)
+ std::string suffix(QPID_MODULE_SUFFIX);
+#else
+ std::string suffix(".so");
+#endif
+
+bool isShlibName(const std::string& name) {
+ return name.find (suffix) == name.length() - suffix.length();
+}
+
+}
+
+namespace qpid {
+
+ModuleOptions::ModuleOptions(const std::string& defaultModuleDir)
+ : qpid::Options("Module options"), loadDir(defaultModuleDir), noLoad(false)
+{
+ addOptions()
+ ("module-dir", optValue(loadDir, "DIR"), "Load all shareable modules in this directory")
+ ("load-module", optValue(load, "FILE"), "Specifies additional module(s) to be loaded")
+ ("no-module-dir", optValue(noLoad), "Don't load modules from module directory");
+}
+
+void tryShlib(const char* libname_, bool noThrow) {
+ std::string libname(libname_);
+ if (!isShlibName(libname)) libname += suffix;
+ try {
+ sys::Shlib shlib(libname);
+ QPID_LOG (info, "Loaded Module: " << libname);
+ }
+ catch (const std::exception& /*e*/) {
+ if (!noThrow)
+ throw;
+ }
+}
+
+void loadModuleDir (std::string dirname, bool isDefault)
+{
+ fs::path dirPath (dirname, fs::native);
+
+ if (!fs::exists (dirPath))
+ {
+ if (isDefault)
+ return;
+ throw Exception ("Directory not found: " + dirname);
+ }
+ if (!fs::is_directory(dirPath))
+ {
+ throw Exception ("Invalid value for module-dir: " + dirname + " is not a directory");
+ }
+
+ fs::directory_iterator endItr;
+ for (fs::directory_iterator itr (dirPath); itr != endItr; ++itr)
+ {
+ if (!fs::is_directory(*itr) && isShlibName(itr->string()))
+ tryShlib (itr->string().data(), true);
+ }
+}
+
+} // namespace qpid
diff --git a/cpp/src/qpid/Modules.h b/cpp/src/qpid/Modules.h
new file mode 100644
index 0000000000..159dd156c1
--- /dev/null
+++ b/cpp/src/qpid/Modules.h
@@ -0,0 +1,44 @@
+#ifndef QPID_MODULES_H
+#define QPID_MODULES_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Options.h"
+#include <string>
+#include <vector>
+#include "qpid/CommonImportExport.h"
+
+namespace qpid {
+
+struct ModuleOptions : public qpid::Options {
+ std::string loadDir;
+ std::vector<std::string> load;
+ bool noLoad;
+ QPID_COMMON_EXTERN ModuleOptions(const std::string& defaultModuleDir);
+};
+
+QPID_COMMON_EXTERN void tryShlib(const char* libname, bool noThrow);
+QPID_COMMON_EXTERN void loadModuleDir (std::string dirname, bool isDefault);
+
+} // namespace qpid
+
+#endif /*!QPID_MODULES_H*/
diff --git a/cpp/src/qpid/Msg.h b/cpp/src/qpid/Msg.h
deleted file mode 100644
index 7214db611f..0000000000
--- a/cpp/src/qpid/Msg.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef QPID_MSG_H
-#define QPID_MSG_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <sstream>
-#include <iostream>
-
-namespace qpid {
-
-/** A simple wrapper for std::ostringstream that allows
- * in place construction of a message and automatic conversion
- * to string.
- * E.g.
- *@code
- * void foo(const std::string&);
- * foo(Msg() << "hello " << 32);
- *@endcode
- * Will construct the string "hello 32" and pass it to foo()
- */
-struct Msg {
- std::ostringstream os;
- Msg() {}
- Msg(const Msg& m) : os(m.str()) {}
- std::string str() const { return os.str(); }
- operator std::string() const { return str(); }
-};
-
-template <class T> const Msg& operator<<(const Msg& m, const T& t) {
- const_cast<std::ostringstream&>(m.os)<<t; return m;
-}
-
-inline std::ostream& operator<<(std::ostream& o, const Msg& m) {
- return o<<m.str();
-}
-
-/** Construct a message using operator << and append (file:line) */
-#define QPID_MSG(message) ::qpid::Msg() << message << " (" << __FILE__ << ":" << __LINE__ << ")"
-
-} // namespace qpid
-
-#endif /*!QPID_MSG_H*/
diff --git a/cpp/src/qpid/Options.cpp b/cpp/src/qpid/Options.cpp
index e521b1220a..499fb71bc3 100644
--- a/cpp/src/qpid/Options.cpp
+++ b/cpp/src/qpid/Options.cpp
@@ -16,7 +16,7 @@
*
*/
-#include "Options.h"
+#include "qpid/Options.h"
#include "qpid/Exception.h"
#include <boost/bind.hpp>
@@ -55,7 +55,8 @@ struct EnvOptMapper {
}
static bool matchStr(const string& env, boost::shared_ptr<po::option_description> desc) {
- return std::equal(env.begin(), env.end(), desc->long_name().begin(), &matchChar);
+ return desc->long_name().size() == env.size() &&
+ std::equal(env.begin(), env.end(), desc->long_name().begin(), &matchChar);
}
static bool matchCase(const string& env, boost::shared_ptr<po::option_description> desc) {
diff --git a/cpp/src/qpid/Options.h b/cpp/src/qpid/Options.h
deleted file mode 100644
index cb86d27241..0000000000
--- a/cpp/src/qpid/Options.h
+++ /dev/null
@@ -1,257 +0,0 @@
-#ifndef QPID_COMMONOPTIONS_H
-#define QPID_COMMONOPTIONS_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/Exception.h"
-#include <boost/program_options.hpp>
-#include <boost/format.hpp>
-#include <sstream>
-#include <iterator>
-#include <algorithm>
-#include <string>
-
-
-namespace qpid {
-namespace po=boost::program_options;
-
-
-
-///@internal
-std::string prettyArg(const std::string&, const std::string&);
-
-/** @internal Normally only constructed by optValue() */
-template <class T>
-class OptionValue : public po::typed_value<T> {
- public:
- OptionValue(T& value, const std::string& arg)
- : po::typed_value<T>(&value), argName(arg) {}
- std::string name() const { return argName; }
-
- private:
- std::string argName;
-};
-
-
-/** Create an option value.
- * name, value appear after the option name in help like this:
- * <name> (=<value>)
- * T must support operator <<.
- *@see Options for example of use.
- */
-template<class T>
-po::value_semantic* optValue(T& value, const char* name) {
- std::string valstr(boost::lexical_cast<std::string>(value));
- return new OptionValue<T>(value, prettyArg(name, valstr));
-}
-
-/** Create a vector value. Multiple occurences of the option are
- * accumulated into the vector
- */
-template <class T>
-po::value_semantic* optValue(std::vector<T>& value, const char* name) {
- using namespace std;
- ostringstream os;
- copy(value.begin(), value.end(), ostream_iterator<T>(os, " "));
- string val=os.str();
- if (!val.empty())
- val.erase(val.end()-1); // Remove trailing " "
- return (new OptionValue<vector<T> >(value, prettyArg(name, val)));
-}
-
-/** Create a boolean switch value. Presence of the option sets the value. */
-inline po::value_semantic* optValue(bool& value) { return po::bool_switch(&value); }
-
-/**
- * Base class for options.
- * Example of use:
- @code
- struct MySubOptions : public Options {
- int x;
- string y;
- MySubOptions() : Options("Sub options") {
- addOptions()
- ("x", optValue(x,"XUNIT"), "Option X")
- ("y", optValue(y, "YUNIT"), "Option Y");
- }
- };
-
- struct MyOptions : public Options {
- bool z;
- vector<string> foo;
- MySubOptions subOptions;
- MyOptions() : Options("My Options") {
- addOptions()
- ("z", boolSwitch(z), "Option Z")
- ("foo", optValue(foo), "Multiple option foo");
- add(subOptions);
- }
-
- main(int argc, char** argv) {
- Options opts;
- opts.parse(argc, char** argv);
- // Use values
- dosomething(opts.subOptions.x);
- if (error)
- cout << opts << end; // Help message.
- }
-
- @endcode
- */
-
-
-
-
-/*
- * ---------------------------------------------
- * Explanation for Boost 103200 conditional code
- * ---------------------------------------------
- *
- * This boost version has an implementation of the program_options library
- * that has no provision for allowing unregistered options to pass by.
- *
- * But that means that, if you have a program that loads optional modules
- * after start-up, and those modules each have their own set of options,
- * then if you parse the command line too soon, you will get spurious
- * reports of unrecognized options -- and the program will exit!
- *
- * And we must process the command-line before module-loading, because we
- * need to look at the "bootstrap" options.
- *
- * This conditional code:
- *
- * 1. implements it's own functor class, derived from the Boost
- * "options_description_easy_init" class. This functor is used
- * to process added options and do the functor chaining, so that
- * I can snoop on the arguments before doing an explicit call
- * to its parent.
- *
- * 2. It implements two static vectors, one to hold long names, and
- * one for short names, so that options declared by modules are
- * not forgotten when their options_description goes out of scope.
- *
- * I will be thrilled to personally delete this code if we ever decide
- * that qpid doesn't really need to support this antique version of Boost.
- *
- */
-
-#if ( BOOST_VERSION == 103200 )
-struct Options;
-
-
-struct
-options_description_less_easy_init
- : public po::options_description_easy_init
-{
- options_description_less_easy_init ( Options * my_owner,
- po::options_description * my_parents_owner
- )
- : po::options_description_easy_init(my_parents_owner)
- {
- owner = my_owner;
- }
-
-
- options_description_less_easy_init&
- operator()(char const * name,
- char const * description);
-
-
- options_description_less_easy_init&
- operator()(char const * name,
- const po::value_semantic* s);
-
-
- options_description_less_easy_init&
- operator()(const char* name,
- const po::value_semantic* s,
- const char* description);
-
-
- Options * owner;
-};
-#endif
-
-
-
-
-
-
-struct Options : public po::options_description {
-
- struct Exception : public qpid::Exception {
- Exception(const std::string& msg) : qpid::Exception(msg) {}
- };
-
- Options(const std::string& name=std::string());
-
- /**
- * Parses options from argc/argv, environment variables and config file.
- * Note the filename argument can reference an options variable that
- * is updated by argc/argv or environment variable parsing.
- */
- void parse(int argc, char const* const* argv,
- const std::string& configfile=std::string(),
- bool allowUnknown = false);
-
-
- #if ( BOOST_VERSION == 103200 )
- options_description_less_easy_init m_less_easy;
-
- options_description_less_easy_init addOptions() {
- return m_less_easy;
- }
-
- bool
- is_registered_option ( std::string s );
-
- void
- register_names ( std::string s );
-
- static std::vector<std::string> long_names;
- static std::vector<std::string> short_names;
- #else
- boost::program_options::options_description_easy_init addOptions() {
- return add_options();
- }
- #endif
-};
-
-
-
-/**
- * Standard options for configuration
- */
-struct CommonOptions : public Options {
- CommonOptions(const std::string& name=std::string(),
- const std::string& configfile=std::string());
- bool help;
- bool version;
- std::string config;
-};
-
-
-
-
-} // namespace qpid
-
-#endif /*!QPID_COMMONOPTIONS_H*/
diff --git a/cpp/src/qpid/Plugin.cpp b/cpp/src/qpid/Plugin.cpp
index e4b76db28a..196b5c2333 100644
--- a/cpp/src/qpid/Plugin.cpp
+++ b/cpp/src/qpid/Plugin.cpp
@@ -18,7 +18,7 @@
*
*/
-#include "Plugin.h"
+#include "qpid/Plugin.h"
#include "qpid/Options.h"
#include <boost/bind.hpp>
#include <algorithm>
@@ -42,7 +42,7 @@ void invoke(boost::function<void()> f) { f(); }
Plugin::Target::~Target() { finalize(); }
void Plugin::Target::finalize() {
- for_each(finalizers.begin(), finalizers.end(), invoke);
+ std::for_each(finalizers.begin(), finalizers.end(), invoke);
finalizers.clear();
}
@@ -50,9 +50,16 @@ void Plugin::Target::addFinalizer(const boost::function<void()>& f) {
finalizers.push_back(f);
}
+namespace {
+bool initBefore(const Plugin* a, const Plugin* b) {
+ return a->initOrder() < b->initOrder();
+}
+}
+
Plugin::Plugin() {
// Register myself.
thePlugins().push_back(this);
+ std::sort(thePlugins().begin(), thePlugins().end(), &initBefore);
}
Plugin::~Plugin() {}
@@ -74,7 +81,14 @@ void Plugin::addOptions(Options& opts) {
}
}
-void Plugin::earlyInitAll(Target& t) { each_plugin(boost::bind(&Plugin::earlyInitialize, _1, boost::ref(t))); }
-void Plugin::initializeAll(Target& t) { each_plugin(boost::bind(&Plugin::initialize, _1, boost::ref(t))); }
+int Plugin::initOrder() const { return DEFAULT_INIT_ORDER; }
+
+void Plugin::earlyInitAll(Target& t) {
+ each_plugin(boost::bind(&Plugin::earlyInitialize, _1, boost::ref(t)));
+}
+
+void Plugin::initializeAll(Target& t) {
+ each_plugin(boost::bind(&Plugin::initialize, _1, boost::ref(t)));
+}
} // namespace qpid
diff --git a/cpp/src/qpid/Plugin.h b/cpp/src/qpid/Plugin.h
index 3c7c8031bb..4e057872b9 100644
--- a/cpp/src/qpid/Plugin.h
+++ b/cpp/src/qpid/Plugin.h
@@ -24,11 +24,12 @@
#include <boost/noncopyable.hpp>
#include <boost/function.hpp>
#include <vector>
+#include "qpid/CommonImportExport.h"
/**@file Generic plug-in framework. */
namespace qpid {
-class Options;
+struct Options;
/**
* Plug-in base class.
@@ -36,6 +37,8 @@ class Options;
class Plugin : private boost::noncopyable {
public:
typedef std::vector<Plugin*> Plugins;
+ /** Default value returned by initOrder() */
+ static const int DEFAULT_INIT_ORDER=1000;
/**
* Base interface for targets that can receive plug-ins.
@@ -46,13 +49,13 @@ class Plugin : private boost::noncopyable {
{
public:
/** Calls finalize() if not already called. */
- virtual ~Target();
+ QPID_COMMON_EXTERN virtual ~Target();
/** Run all the finalizers */
- void finalize();
+ QPID_COMMON_EXTERN void finalize();
/** Add a function to run when finalize() is called */
- void addFinalizer(const boost::function<void()>&);
+ QPID_COMMON_EXTERN void addFinalizer(const boost::function<void()>&);
private:
std::vector<boost::function<void()> > finalizers;
@@ -65,9 +68,9 @@ class Plugin : private boost::noncopyable {
* member variable in a library so it is registered during
* initialization when the library is loaded.
*/
- Plugin();
+ QPID_COMMON_EXTERN Plugin();
- virtual ~Plugin();
+ QPID_COMMON_EXTERN virtual ~Plugin();
/**
* Configuration options for the plugin.
@@ -76,7 +79,7 @@ class Plugin : private boost::noncopyable {
* @return An options group or 0 for no options. Default returns 0.
* Plugin retains ownership of return value.
*/
- virtual Options* getOptions();
+ QPID_COMMON_EXTERN virtual Options* getOptions();
/**
* Initialize Plugin functionality on a Target, called before
@@ -98,19 +101,27 @@ class Plugin : private boost::noncopyable {
*/
virtual void initialize(Target&) = 0;
+ /**
+ * Initialization order. If a plugin does not override this, it
+ * returns DEFAULT_INIT_ORDER. Plugins that need to be initialized
+ * earlier/later than normal can override initOrder to return
+ * a lower/higher value than DEFAULT_INIT_ORDER.
+ */
+ QPID_COMMON_EXTERN virtual int initOrder() const;
+
/** List of registered Plugin objects.
* Caller must not delete plugin pointers.
*/
- static const Plugins& getPlugins();
+ QPID_COMMON_EXTERN static const Plugins& getPlugins();
/** Call earlyInitialize() on all registered plugins */
- static void earlyInitAll(Target&);
+ QPID_COMMON_EXTERN static void earlyInitAll(Target&);
/** Call initialize() on all registered plugins */
- static void initializeAll(Target&);
+ QPID_COMMON_EXTERN static void initializeAll(Target&);
/** For each registered plugin, add plugin.getOptions() to opts. */
- static void addOptions(Options& opts);
+ QPID_COMMON_EXTERN static void addOptions(Options& opts);
};
} // namespace qpid
diff --git a/cpp/src/qpid/RangeSet.h b/cpp/src/qpid/RangeSet.h
deleted file mode 100644
index 2a88426f17..0000000000
--- a/cpp/src/qpid/RangeSet.h
+++ /dev/null
@@ -1,324 +0,0 @@
-#ifndef QPID_RANGESET_H
-#define QPID_RANGESET_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/InlineVector.h"
-#include <boost/iterator/iterator_facade.hpp>
-#include <boost/operators.hpp>
-#include <boost/bind.hpp>
-#include <algorithm>
-
-namespace qpid {
-
-/** A range of values, used in RangeSet.
- * Range(begin, end) includes begin but excludes end.
- * Range::makeClosed(first,last) includes both first and last.
- */
-template <class T>
-class Range {
- public:
- static Range makeClosed(const T& first, T last) { return Range(first, ++last); }
-
- Range() : begin_(), end_() {}
- explicit Range(const T& t) : begin_(t), end_(t) { ++end_; }
- Range(const T& b, const T& e) : begin_(b), end_(e) { assert(b <= e); }
-
- T begin() const { return begin_; }
- /** End of _open_ range, i.e. !contains(end()) */
- T end() const { return end_; }
-
- T first() const { assert(!empty()); return begin_; }
- /** Last in closed range, i.e. contains(end()) */
- T last() const { assert(!empty()); T ret=end_; return --ret; }
-
- void begin(const T& t) { begin_ = t; }
- void end(const T& t) { end_ = t; }
-
- bool empty() const { return begin_ == end_; }
-
- bool contains(const T& x) const { return begin_ <= x && x < end_; }
- bool contains(const Range& r) const { return begin_ <= r.begin_ && r.end_ <= end_; }
- bool strictContains(const Range& r) const { return begin_ < r.begin_ && r.end_ < end_; }
-
- bool operator==(const Range& x) { return begin_ == x.begin_ && end_== x.end_; }
-
- bool operator<(const T& t) const { return end_ < t; }
- bool operator<(const Range<T>& r) const { return end_ < r.begin_; }
-
- /** touching ranges can be merged into a single range. */
- bool touching(const Range& r) const {
- return std::max(begin_, r.begin_) <= std::min(end_, r.end_);
- }
-
- /** @pre touching */
- void merge(const Range& r) {
- assert(touching(r));
- begin_ = std::min(begin_, r.begin_);
- end_ = std::max(end_, r.end_);
- }
-
- operator bool() const { return !empty(); }
-
- template <class S> void serialize(S& s) { s(begin_)(end_); }
-
- private:
- T begin_, end_;
-};
-
-
-/**
- * A set implemented as a list of [begin, end) ranges.
- * T must be LessThanComparable and Incrementable.
- * RangeSet only provides const iterators.
- */
-template <class T>
-class RangeSet
- : boost::additive1<RangeSet<T>,
- boost::additive2<RangeSet<T>, Range<T>,
- boost::additive2<RangeSet<T>, T> > >
-{
- typedef InlineVector<Range<T>, 3> Ranges; // TODO aconway 2008-04-21: what's the optimial inlined value?
-
- public:
-
- class iterator : public boost::iterator_facade<
- iterator,
- const T,
- boost::forward_traversal_tag>
- {
- public:
- iterator() : ranges(), iter(), value() {}
-
- private:
- typedef typename Ranges::const_iterator RangesIter;
- iterator(const Ranges& r, const RangesIter& i, const T& t)
- : ranges(&r), iter(i), value(t) {}
-
- void increment();
- bool equal(const iterator& i) const;
- const T& dereference() const { return value; }
-
- const Ranges* ranges;
- RangesIter iter;
- T value;
-
- friend class RangeSet<T>;
- friend class boost::iterator_core_access;
- };
-
- typedef iterator const_iterator;
-
- RangeSet() {}
- explicit RangeSet(const Range<T>& r) { *this += r; }
- RangeSet(const T& a, const T& b) { *this += Range<T>(a,b); }
-
- bool contiguous() const { return ranges.size() <= 1; }
-
- bool contains(const T& t) const;
- bool contains(const Range<T>&) const;
-
- /**@pre contiguous() */
- Range<T> toRange() const;
-
- bool operator==(const RangeSet<T>&) const;
-
- void addRange (const Range<T>&);
- void addSet (const RangeSet<T>&);
-
- RangeSet<T>& operator+=(const T& t) { return *this += Range<T>(t); }
- RangeSet<T>& operator+=(const Range<T>& r) { addRange(r); return *this; }
- RangeSet<T>& operator+=(const RangeSet<T>& s) { addSet(s); return *this; }
-
- void removeRange (const Range<T>&);
- void removeSet (const RangeSet<T>&);
-
- RangeSet<T>& operator-=(const T& t) { return *this -= Range<T>(t); }
- RangeSet<T>& operator-=(const Range<T>& r) { removeRange(r); return *this; }
- RangeSet<T>& operator-=(const RangeSet<T>& s) { removeSet(s); return *this; }
-
- T front() const { return ranges.front().begin(); }
- T back() const { return ranges.back().end(); }
-
- // Iterate over elements in the set.
- iterator begin() const;
- iterator end() const;
-
- // Iterate over ranges in the set.
- typedef typename Ranges::const_iterator RangeIterator;
- RangeIterator rangesBegin() const { return ranges.begin(); }
- RangeIterator rangesEnd() const { return ranges.end(); }
- size_t rangesSize() const { return ranges.size(); }
-
- // The difference between the start and end of this range set
- uint32_t span() const;
-
- bool empty() const { return ranges.empty(); }
- void clear() { ranges.clear(); }
-
- /** Return the largest contiguous range containing x.
- * Returns the empty range [x,x) if x is not in the set.
- */
- Range<T> rangeContaining(const T&) const;
-
- template <class S> void serialize(S& s) { s.split(*this); s(ranges.begin(), ranges.end()); }
- template <class S> void encode(S& s) const { s(uint16_t(ranges.size()*sizeof(Range<T>))); }
- template <class S> void decode(S& s) { uint16_t sz; s(sz); ranges.resize(sz/sizeof(Range<T>)); }
-
- private:
- Ranges ranges;
-
- template <class U> friend std::ostream& operator<<(std::ostream& o, const RangeSet<U>& r);
-
- friend class iterator;
-};
-
-template <class T>
-std::ostream& operator<<(std::ostream& o, const Range<T>& r) {
- return o << "[" << r.begin() << "," << r.end() << ")";
-}
-
-template <class T>
-std::ostream& operator<<(std::ostream& o, const RangeSet<T>& rs) {
- std::ostream_iterator<Range<T> > i(o, " ");
- o << "{ ";
- std::copy(rs.ranges.begin(), rs.ranges.end(), i);
- return o << "}";
-}
-
-template <class T>
-bool RangeSet<T>::contains(const T& t) const {
- typename Ranges::const_iterator i =
- std::lower_bound(ranges.begin(), ranges.end(), Range<T>(t));
- return i != ranges.end() && i->contains(t);
-}
-
-template <class T>
-bool RangeSet<T>::contains(const Range<T>& r) const {
- typename Ranges::const_iterator i =
- std::lower_bound(ranges.begin(), ranges.end(), r);
- return i != ranges.end() && i->contains(r);
-}
-
-template <class T> void RangeSet<T>::addRange(const Range<T>& r) {
- if (r.empty()) return;
- typename Ranges::iterator i =
- std::lower_bound(ranges.begin(), ranges.end(), r);
- if (i == ranges.end() || !i->touching(r))
- ranges.insert(i, r);
- else {
- i->merge(r);
- typename Ranges::iterator j = i;
- if (++j != ranges.end() && i->touching(*j)) {
- i->merge(*j);
- ranges.erase(j);
- }
- }
-}
-
-
-template <class T> void RangeSet<T>::addSet(const RangeSet<T>& s) {
- typedef RangeSet<T>& (RangeSet<T>::*RangeSetRangeOp)(const Range<T>&);
- std::for_each(s.ranges.begin(), s.ranges.end(),
- boost::bind((RangeSetRangeOp)&RangeSet<T>::operator+=, this, _1));
-}
-
-template <class T> void RangeSet<T>::removeRange(const Range<T>& r) {
- if (r.empty()) return;
- typename Ranges::iterator i,j;
- i = std::lower_bound(ranges.begin(), ranges.end(), r);
- if (i == ranges.end() || i->begin() >= r.end())
- return; // Outside of set
- if (*i == r) // Erase i
- ranges.erase(i);
- else if (i->strictContains(r)) { // Split i
- Range<T> i1(i->begin(), r.begin());
- Range<T> i2(r.end(), i->end());
- *i = i2;
- ranges.insert(i, i1);
- } else {
- if (i->begin() < r.begin()) { // Truncate i
- i->end(r.begin());
- ++i;
- }
- for (j = i; j != ranges.end() && r.contains(*j); ++j)
- ; // Ranges to erase.
- if (j != ranges.end() && j->end() > r.end())
- j->begin(r.end()); // Truncate j
- ranges.erase(i,j);
- }
-}
-
-template <class T> void RangeSet<T>::removeSet(const RangeSet<T>& r) {
- std::for_each(
- r.ranges.begin(), r.ranges.end(),
- boost::bind(&RangeSet<T>::removeRange, this, _1));
-}
-
-template <class T> Range<T> RangeSet<T>::toRange() const {
- assert(contiguous());
- return empty() ? Range<T>() : ranges.front();
-}
-
-template <class T> void RangeSet<T>::iterator::increment() {
- assert(ranges && iter != ranges->end());
- if (!iter->contains(++value)) {
- ++iter;
- if (iter == ranges->end())
- *this=iterator(); // end() iterator
- else
- value=iter->begin();
- }
-}
-
-template <class T> bool RangeSet<T>::operator==(const RangeSet<T>& r) const {
- return ranges.size() == r.ranges.size() && std::equal(ranges.begin(), ranges.end(), r.ranges.begin());
-}
-
-template <class T> typename RangeSet<T>::iterator RangeSet<T>::begin() const {
- return empty() ? end() : iterator(ranges, ranges.begin(), front());
-}
-
-template <class T> typename RangeSet<T>::iterator RangeSet<T>::end() const {
- return iterator();
-}
-
-template <class T> bool RangeSet<T>::iterator::equal(const iterator& i) const {
- return ranges==i.ranges && (ranges==0 || value==i.value);
-}
-
-template <class T> Range<T> RangeSet<T>::rangeContaining(const T& t) const {
- typename Ranges::const_iterator i =
- std::lower_bound(ranges.begin(), ranges.end(), Range<T>(t));
- return (i != ranges.end() && i->contains(t)) ? *i : Range<T>(t,t);
-}
-
-template <class T> uint32_t RangeSet<T>::span() const {
- if (ranges.empty()) return 0;
- return ranges.back().last() - ranges.front().first();
-}
-
-
-} // namespace qpid
-
-
-#endif /*!QPID_RANGESET_H*/
diff --git a/cpp/src/qpid/RefCounted.h b/cpp/src/qpid/RefCounted.h
index 10b5e4afcc..e7a9bf31c1 100644
--- a/cpp/src/qpid/RefCounted.h
+++ b/cpp/src/qpid/RefCounted.h
@@ -39,11 +39,13 @@ class RefCounted : boost::noncopyable {
public:
RefCounted() : count(0) {}
void addRef() const { ++count; }
- void release() const { if (--count==0) delete this; }
+ void release() const { if (--count==0) released(); }
long refCount() { return count; }
protected:
virtual ~RefCounted() {};
+ // Allow subclasses to over-ride behavior when refcount reaches 0.
+ virtual void released() const { delete this; }
};
diff --git a/cpp/src/qpid/RefCountedBuffer.cpp b/cpp/src/qpid/RefCountedBuffer.cpp
new file mode 100644
index 0000000000..9b8f1ebd5e
--- /dev/null
+++ b/cpp/src/qpid/RefCountedBuffer.cpp
@@ -0,0 +1,53 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/RefCountedBuffer.h"
+#include <new>
+
+namespace qpid {
+
+RefCountedBuffer::RefCountedBuffer() : count(0) {}
+
+void RefCountedBuffer::destroy() const {
+ this->~RefCountedBuffer();
+ ::delete[] reinterpret_cast<const char*>(this);
+}
+
+char* RefCountedBuffer::addr() const {
+ return const_cast<char*>(reinterpret_cast<const char*>(this)+sizeof(RefCountedBuffer));
+}
+
+RefCountedBuffer::pointer RefCountedBuffer::create(size_t n) {
+ char* store=::new char[n+sizeof(RefCountedBuffer)];
+ new(store) RefCountedBuffer;
+ return pointer(reinterpret_cast<RefCountedBuffer*>(store));
+}
+
+RefCountedBuffer::pointer::pointer() {}
+RefCountedBuffer::pointer::pointer(RefCountedBuffer* x) : p(x) {}
+RefCountedBuffer::pointer::pointer(const pointer& x) : p(x.p) {}
+RefCountedBuffer::pointer::~pointer() {}
+RefCountedBuffer::pointer& RefCountedBuffer::pointer::operator=(const RefCountedBuffer::pointer& x) { p = x.p; return *this; }
+
+char* RefCountedBuffer::pointer::cp() const { return p ? p->get() : 0; }
+} // namespace qpid
+
+
diff --git a/cpp/src/qpid/RefCountedBuffer.h b/cpp/src/qpid/RefCountedBuffer.h
new file mode 100644
index 0000000000..c332325378
--- /dev/null
+++ b/cpp/src/qpid/RefCountedBuffer.h
@@ -0,0 +1,89 @@
+#ifndef QPID_REFCOUNTEDBUFFER_H
+#define QPID_REFCOUNTEDBUFFER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/utility.hpp>
+#include <boost/detail/atomic_count.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+// FIXME aconway 2008-09-06: easy to add alignment
+/**
+ * Reference-counted byte buffer.
+ * No alignment guarantees.
+ */
+class RefCountedBuffer : boost::noncopyable {
+ mutable boost::detail::atomic_count count;
+ RefCountedBuffer();
+ void destroy() const;
+ char* addr() const;
+
+public:
+ /** Smart char pointer to a reference counted buffer */
+ class pointer {
+ boost::intrusive_ptr<RefCountedBuffer> p;
+ char* cp() const;
+ pointer(RefCountedBuffer* x);
+ friend class RefCountedBuffer;
+
+ public:
+ pointer();
+ pointer(const pointer&);
+ ~pointer();
+ pointer& operator=(const pointer&);
+
+ char* get() { return cp(); }
+ operator char*() { return cp(); }
+ char& operator*() { return *cp(); }
+ char& operator[](size_t i) { return cp()[i]; }
+
+ const char* get() const { return cp(); }
+ operator const char*() const { return cp(); }
+ const char& operator*() const { return *cp(); }
+ const char& operator[](size_t i) const { return cp()[i]; }
+ };
+
+ /** Create a reference counted buffer of size n */
+ static pointer create(size_t n);
+
+ /** Get a pointer to the start of the buffer. */
+ char* get() { return addr(); }
+ const char* get() const { return addr(); }
+ char& operator[](size_t i) { return get()[i]; }
+ const char& operator[](size_t i) const { return get()[i]; }
+
+ void addRef() const { ++count; }
+ void release() const { if (--count==0) destroy(); }
+ long refCount() { return count; }
+};
+
+} // namespace qpid
+
+// intrusive_ptr support.
+namespace boost {
+inline void intrusive_ptr_add_ref(const qpid::RefCountedBuffer* p) { p->addRef(); }
+inline void intrusive_ptr_release(const qpid::RefCountedBuffer* p) { p->release(); }
+}
+
+
+#endif /*!QPID_REFCOUNTEDBUFFER_H*/
diff --git a/cpp/src/qpid/SessionId.cpp b/cpp/src/qpid/SessionId.cpp
index fce6619f5d..c7e83f83d7 100644
--- a/cpp/src/qpid/SessionId.cpp
+++ b/cpp/src/qpid/SessionId.cpp
@@ -19,7 +19,7 @@
*
*/
-#include "SessionId.h"
+#include "qpid/SessionId.h"
#include <sstream>
namespace qpid {
@@ -35,7 +35,7 @@ bool SessionId::operator==(const SessionId& id) const {
}
std::ostream& operator<<(std::ostream& o, const SessionId& id) {
- return o << id.getName() << "@" << id.getUserId();
+ return o << id.getUserId() << "." << id.getName();
}
std::string SessionId::str() const {
diff --git a/cpp/src/qpid/SessionId.h b/cpp/src/qpid/SessionId.h
deleted file mode 100644
index 291c42a2bb..0000000000
--- a/cpp/src/qpid/SessionId.h
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef QPID_SESSIONID_H
-#define QPID_SESSIONID_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <boost/operators.hpp>
-#include <string>
-
-namespace qpid {
-
-/** Identifier for a session.
- * There are two parts to a session identifier:
- *
- * getUserId() returns the authentication principal associated with
- * the session's connection.
- *
- * getName() returns the session name.
- *
- * The name must be unique among sessions with the same authentication
- * principal.
- */
-class SessionId : boost::totally_ordered1<SessionId> {
- std::string userId;
- std::string name;
- public:
- SessionId(const std::string& userId=std::string(), const std::string& name=std::string());
- std::string getUserId() const { return userId; }
- std::string getName() const { return name; }
- bool operator<(const SessionId&) const ;
- bool operator==(const SessionId& id) const;
- // Convert to a string
- std::string str() const;
-};
-
-std::ostream& operator<<(std::ostream&, const SessionId&);
-
-
-} // namespace qpid
-
-#endif /*!QPID_SESSIONID_H*/
diff --git a/cpp/src/qpid/SessionState.cpp b/cpp/src/qpid/SessionState.cpp
index 1be0111489..4f370c6765 100644
--- a/cpp/src/qpid/SessionState.cpp
+++ b/cpp/src/qpid/SessionState.cpp
@@ -19,9 +19,10 @@
*
*/
-#include "SessionState.h"
+#include "qpid/SessionState.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/framing/AMQMethodBody.h"
+#include "qpid/framing/enum.h"
#include "qpid/log/Statement.h"
#include <boost/bind.hpp>
#include <numeric>
@@ -37,10 +38,10 @@ using framing::FramingErrorException;
namespace {
bool isControl(const AMQFrame& f) {
- return f.getMethod() && f.getMethod()->type() == framing::CONTROL;
+ return f.getMethod() && f.getMethod()->type() == framing::SEGMENT_TYPE_CONTROL;
}
bool isCommand(const AMQFrame& f) {
- return f.getMethod() && f.getMethod()->type() == framing::COMMAND;
+ return f.getMethod() && f.getMethod()->type() == framing::SEGMENT_TYPE_COMMAND;
}
} // namespace
@@ -60,7 +61,7 @@ void SessionPoint::advance(const AMQFrame& f) {
if (f.isLastSegment() && f.isLastFrame())
++command; // Single-frame command.
else
- offset += f.size();
+ offset += f.encodedSize();
}
else { // continuation frame for partial command
if (offset == 0)
@@ -76,7 +77,7 @@ void SessionPoint::advance(const AMQFrame& f) {
// that the relationship of fragment offsets to the replay
// list can be computed more easily.
//
- offset += f.size();
+ offset += f.encodedSize();
}
}
}
@@ -112,12 +113,13 @@ SessionState::ReplayRange SessionState::senderExpected(const SessionPoint& expec
void SessionState::senderRecord(const AMQFrame& f) {
if (isControl(f)) return; // Ignore control frames.
- QPID_LOG_IF(debug, f.getMethod(), getId() << ": sent cmd " << sender.sendPoint.command << ": " << *f.getMethod());
+ QPID_LOG(trace, getId() << ": sent cmd " << sender.sendPoint.command << ": " << *f.getBody());
+
stateful = true;
if (timeout) sender.replayList.push_back(f);
- sender.unflushedSize += f.size();
- sender.bytesSinceKnownCompleted += f.size();
- sender.replaySize += f.size();
+ sender.unflushedSize += f.encodedSize();
+ sender.bytesSinceKnownCompleted += f.encodedSize();
+ sender.replaySize += f.encodedSize();
sender.incomplete += sender.sendPoint.command;
sender.sendPoint.advance(f);
if (config.replayHardLimit && config.replayHardLimit < sender.replaySize)
@@ -146,15 +148,15 @@ void SessionState::senderRecordKnownCompleted() {
void SessionState::senderConfirmed(const SessionPoint& confirmed) {
if (confirmed > sender.sendPoint)
- throw InvalidArgumentException(QPID_MSG(getId() << "Confirmed commands not yet sent."));
+ throw InvalidArgumentException(QPID_MSG(getId() << ": confirmed < " << confirmed << " but only sent < " << sender.sendPoint));
QPID_LOG(debug, getId() << ": sender confirmed point moved to " << confirmed);
ReplayList::iterator i = sender.replayList.begin();
while (i != sender.replayList.end() && sender.replayPoint.command < confirmed.command) {
sender.replayPoint.advance(*i);
assert(sender.replayPoint <= sender.sendPoint);
- sender.replaySize -= i->size();
+ sender.replaySize -= i->encodedSize();
if (sender.replayPoint > sender.flushPoint)
- sender.unflushedSize -= i->size();
+ sender.unflushedSize -= i->encodedSize();
++i;
}
if (sender.replayPoint > sender.flushPoint)
@@ -168,7 +170,7 @@ void SessionState::senderCompleted(const SequenceSet& commands) {
QPID_LOG(debug, getId() << ": sender marked completed: " << commands);
sender.incomplete -= commands;
// Completion implies confirmation but we don't handle out-of-order
- // confirmation, so confirm only the first contiguous range of commands.
+ // confirmation, so confirm up to the end of the first contiguous range of commands.
senderConfirmed(SessionPoint(commands.rangesBegin()->end()));
}
@@ -182,21 +184,23 @@ void SessionState::receiverSetCommandPoint(const SessionPoint& point) {
}
bool SessionState::receiverRecord(const AMQFrame& f) {
+ if (receiverTrackingDisabled) return true; //Very nasty hack for push bridges
if (isControl(f)) return true; // Ignore control frames.
stateful = true;
receiver.expected.advance(f);
- receiver.bytesSinceKnownCompleted += f.size();
+ receiver.bytesSinceKnownCompleted += f.encodedSize();
bool firstTime = receiver.expected > receiver.received;
if (firstTime) {
receiver.received = receiver.expected;
receiver.incomplete += receiverGetCurrent();
}
- QPID_LOG_IF(debug, f.getMethod(), getId() << ": recv cmd " << receiverGetCurrent() << ": " << *f.getMethod());
- QPID_LOG_IF(debug, !firstTime, "Ignoring duplicate frame: " << receiverGetCurrent() << ": " << f);
+ QPID_LOG(trace, getId() << ": recv cmd " << receiverGetCurrent() << ": " << *f.getBody());
+ if (!firstTime) QPID_LOG(trace, "Ignoring duplicate frame.");
return firstTime;
}
void SessionState::receiverCompleted(SequenceNumber command, bool cumulative) {
+ if (receiverTrackingDisabled) return; //Very nasty hack for push bridges
assert(receiver.incomplete.contains(command)); // Internal error to complete command twice.
SequenceNumber first =cumulative ? receiver.incomplete.front() : command;
SequenceNumber last = command;
@@ -236,7 +240,7 @@ SessionState::Configuration::Configuration(size_t flush, size_t hard) :
replayFlushLimit(flush), replayHardLimit(hard) {}
SessionState::SessionState(const SessionId& i, const Configuration& c)
- : id(i), timeout(), config(c), stateful()
+ : id(i), timeout(), config(c), stateful(), receiverTrackingDisabled(false)
{
QPID_LOG(debug, "SessionState::SessionState " << id << ": " << this);
}
@@ -249,4 +253,32 @@ std::ostream& operator<<(std::ostream& o, const SessionPoint& p) {
return o << "(" << p.command.getValue() << "+" << p.offset << ")";
}
+void SessionState::setState(
+ const SequenceNumber& replayStart,
+ const SequenceNumber& sendCommandPoint,
+ const SequenceSet& sentIncomplete,
+ const SequenceNumber& expected,
+ const SequenceNumber& received,
+ const SequenceSet& unknownCompleted,
+ const SequenceSet& receivedIncomplete
+)
+{
+ sender.replayPoint = replayStart;
+ sender.flushPoint = sendCommandPoint;
+ sender.sendPoint = sendCommandPoint;
+ sender.unflushedSize = 0;
+ sender.replaySize = 0; // Replay list will be updated separately.
+ sender.incomplete = sentIncomplete;
+ sender.bytesSinceKnownCompleted = 0;
+
+ receiver.expected = expected;
+ receiver.received = received;
+ receiver.unknownCompleted = unknownCompleted;
+ receiver.incomplete = receivedIncomplete;
+ receiver.bytesSinceKnownCompleted = 0;
+}
+
+void SessionState::disableReceiverTracking() { receiverTrackingDisabled = true; }
+void SessionState::enableReceiverTracking() { receiverTrackingDisabled = false; }
+
} // namespace qpid
diff --git a/cpp/src/qpid/SessionState.h b/cpp/src/qpid/SessionState.h
index 10937b7a1e..da28738546 100644
--- a/cpp/src/qpid/SessionState.h
+++ b/cpp/src/qpid/SessionState.h
@@ -31,6 +31,7 @@
#include <boost/range/iterator_range.hpp>
#include <vector>
#include <iosfwd>
+#include <qpid/CommonImportExport.h>
namespace qpid {
using framing::SequenceNumber;
@@ -38,19 +39,19 @@ using framing::SequenceSet;
/** A point in the session. Points to command id + offset */
struct SessionPoint : boost::totally_ordered1<SessionPoint> {
- SessionPoint(SequenceNumber command = 0, uint64_t offset = 0);
+ QPID_COMMON_EXTERN SessionPoint(SequenceNumber command = 0, uint64_t offset = 0);
SequenceNumber command;
uint64_t offset;
/** Advance past frame f */
- void advance(const framing::AMQFrame& f);
+ QPID_COMMON_EXTERN void advance(const framing::AMQFrame& f);
- bool operator<(const SessionPoint&) const;
- bool operator==(const SessionPoint&) const;
+ QPID_COMMON_EXTERN bool operator<(const SessionPoint&) const;
+ QPID_COMMON_EXTERN bool operator==(const SessionPoint&) const;
};
-std::ostream& operator<<(std::ostream&, const SessionPoint&);
+QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, const SessionPoint&);
/**
* Support for session idempotence barrier and resume as defined in
@@ -78,14 +79,14 @@ class SessionState {
typedef boost::iterator_range<ReplayList::iterator> ReplayRange;
struct Configuration {
- Configuration(size_t flush=1024*1024, size_t hard=0);
+ QPID_COMMON_EXTERN Configuration(size_t flush=1024*1024, size_t hard=0);
size_t replayFlushLimit; // Flush when the replay list >= N bytes. 0 disables.
size_t replayHardLimit; // Kill session if replay list > N bytes. 0 disables.
};
- SessionState(const SessionId& =SessionId(), const Configuration& =Configuration());
+ QPID_COMMON_EXTERN SessionState(const SessionId& =SessionId(), const Configuration& =Configuration());
- virtual ~SessionState();
+ QPID_COMMON_EXTERN virtual ~SessionState();
bool hasState() const;
@@ -100,73 +101,100 @@ class SessionState {
// ==== Functions for sender state.
/** Record frame f for replay. Should not be called during replay. */
- virtual void senderRecord(const framing::AMQFrame& f);
+ QPID_COMMON_EXTERN virtual void senderRecord(const framing::AMQFrame& f);
/** @return true if we should send flush for confirmed and completed commands. */
- virtual bool senderNeedFlush() const;
+ QPID_COMMON_EXTERN virtual bool senderNeedFlush() const;
/** Called when flush for confirmed and completed commands is sent to peer. */
- virtual void senderRecordFlush();
+ QPID_COMMON_EXTERN virtual void senderRecordFlush();
/** True if we should reply to the next incoming completed command */
- virtual bool senderNeedKnownCompleted() const;
+ QPID_COMMON_EXTERN virtual bool senderNeedKnownCompleted() const;
/** Called when knownCompleted is sent to peer. */
- virtual void senderRecordKnownCompleted();
+ QPID_COMMON_EXTERN virtual void senderRecordKnownCompleted();
/** Called when the peer confirms up to comfirmed. */
- virtual void senderConfirmed(const SessionPoint& confirmed);
+ QPID_COMMON_EXTERN virtual void senderConfirmed(const SessionPoint& confirmed);
/** Called when the peer indicates commands completed */
- virtual void senderCompleted(const SequenceSet& commands);
+ QPID_COMMON_EXTERN virtual void senderCompleted(const SequenceSet& commands);
/** Point from which the next new (not replayed) data will be sent. */
- virtual SessionPoint senderGetCommandPoint();
+ QPID_COMMON_EXTERN virtual SessionPoint senderGetCommandPoint();
/** Set of outstanding incomplete commands */
- virtual SequenceSet senderGetIncomplete() const;
+ QPID_COMMON_EXTERN virtual SequenceSet senderGetIncomplete() const;
/** Point from which we can replay. */
- virtual SessionPoint senderGetReplayPoint() const;
+ QPID_COMMON_EXTERN virtual SessionPoint senderGetReplayPoint() const;
/** Peer expecting commands from this point.
- virtual *@return Range of frames to be replayed.
- */
- virtual ReplayRange senderExpected(const SessionPoint& expected);
+ *@return Range of frames to be replayed.
+ */
+ QPID_COMMON_EXTERN virtual ReplayRange senderExpected(const SessionPoint& expected);
// ==== Functions for receiver state
/** Set the command point. */
- virtual void receiverSetCommandPoint(const SessionPoint& point);
+ QPID_COMMON_EXTERN virtual void receiverSetCommandPoint(const SessionPoint& point);
/** Returns true if frame should be be processed, false if it is a duplicate. */
- virtual bool receiverRecord(const framing::AMQFrame& f);
+ QPID_COMMON_EXTERN virtual bool receiverRecord(const framing::AMQFrame& f);
/** Command completed locally */
- virtual void receiverCompleted(SequenceNumber command, bool cumulative=false);
+ QPID_COMMON_EXTERN virtual void receiverCompleted(SequenceNumber command, bool cumulative=false);
/** Peer has indicated commands are known completed */
- virtual void receiverKnownCompleted(const SequenceSet& commands);
+ QPID_COMMON_EXTERN virtual void receiverKnownCompleted(const SequenceSet& commands);
/** True if the next completed control should set the timely-reply argument
* to request a knonw-completed response.
*/
- virtual bool receiverNeedKnownCompleted() const;
+ QPID_COMMON_EXTERN virtual bool receiverNeedKnownCompleted() const;
/** Get the incoming command point */
- virtual const SessionPoint& receiverGetExpected() const;
+ QPID_COMMON_EXTERN virtual const SessionPoint& receiverGetExpected() const;
/** Get the received high-water-mark, may be > getExpected() during replay */
- virtual const SessionPoint& receiverGetReceived() const;
+ QPID_COMMON_EXTERN virtual const SessionPoint& receiverGetReceived() const;
/** Completed received commands that the peer may not know about. */
- virtual const SequenceSet& receiverGetUnknownComplete() const;
+ QPID_COMMON_EXTERN virtual const SequenceSet& receiverGetUnknownComplete() const;
/** Incomplete received commands. */
- virtual const SequenceSet& receiverGetIncomplete() const;
+ QPID_COMMON_EXTERN virtual const SequenceSet& receiverGetIncomplete() const;
/** ID of the command currently being handled. */
- virtual SequenceNumber receiverGetCurrent() const;
+ QPID_COMMON_EXTERN virtual SequenceNumber receiverGetCurrent() const;
+
+ /** Set the state variables, used to create a session that will resume
+ * from some previously established point.
+ */
+ QPID_COMMON_EXTERN virtual void setState(
+ const SequenceNumber& replayStart,
+ const SequenceNumber& sendCommandPoint,
+ const SequenceSet& sentIncomplete,
+ const SequenceNumber& expected,
+ const SequenceNumber& received,
+ const SequenceSet& unknownCompleted,
+ const SequenceSet& receivedIncomplete
+ );
+
+ /**
+ * So called 'push' bridges work by faking a subscribe request
+ * (and the accompanying flows etc) to the local broker to initiate
+ * the outflow of messages for the bridge.
+ *
+ * As the peer doesn't send these it cannot include them in its
+ * session state. To keep the session state on either side of the
+ * bridge in sync, this hack allows the tracking of state for
+ * received messages to be disabled for the faked commands and
+ * subsequently re-enabled.
+ */
+ QPID_COMMON_EXTERN void disableReceiverTracking();
+ QPID_COMMON_EXTERN void enableReceiverTracking();
private:
@@ -196,6 +224,7 @@ class SessionState {
uint32_t timeout;
Configuration config;
bool stateful;
+ bool receiverTrackingDisabled;//very nasty hack for 'push' bridges
};
inline bool operator==(const SessionId& id, const SessionState& s) { return s == id; }
diff --git a/cpp/src/qpid/StringUtils.cpp b/cpp/src/qpid/StringUtils.cpp
index 17eb141e12..c436441c56 100644
--- a/cpp/src/qpid/StringUtils.cpp
+++ b/cpp/src/qpid/StringUtils.cpp
@@ -18,7 +18,7 @@
* under the License.
*
*/
-#include "StringUtils.h"
+#include "qpid/StringUtils.h"
namespace qpid {
diff --git a/cpp/src/qpid/StringUtils.h b/cpp/src/qpid/StringUtils.h
index 3120e43334..4130fae017 100644
--- a/cpp/src/qpid/StringUtils.h
+++ b/cpp/src/qpid/StringUtils.h
@@ -22,6 +22,8 @@
*
*/
+#include "qpid/CommonImportExport.h"
+
#include <string>
#include <vector>
@@ -31,12 +33,12 @@ namespace qpid {
* Split 'in' into words using delimiters in 'delims' and put
* resulting strings into 'out' vector.
*/
-void split(std::vector<std::string>& out, const std::string& in, const std::string& delims);
+QPID_COMMON_EXTERN void split(std::vector<std::string>& out, const std::string& in, const std::string& delims);
/**
* Split 'in' into words using delimiters in 'delims' and return the
* resulting strings in a vector.
*/
-std::vector<std::string> split(const std::string& in, const std::string& delims);
+QPID_COMMON_EXTERN std::vector<std::string> split(const std::string& in, const std::string& delims);
} // namespace qpid
diff --git a/cpp/src/qpid/Url.cpp b/cpp/src/qpid/Url.cpp
index 95d6a34136..f831167dd8 100644
--- a/cpp/src/qpid/Url.cpp
+++ b/cpp/src/qpid/Url.cpp
@@ -19,57 +19,32 @@
#include "qpid/Url.h"
#include "qpid/Exception.h"
#include "qpid/Msg.h"
+#include "qpid/sys/SystemInfo.h"
+#include "qpid/sys/StrError.h"
-#include <limits.h> // NB: must be before boost/spirit headers.
-#include <boost/spirit.hpp>
-#include <boost/spirit/actor.hpp>
+#include <boost/lexical_cast.hpp>
-#include <sstream>
+#include <algorithm>
-#include <sys/ioctl.h>
-#include <net/if.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <errno.h>
+#include <string.h>
-using namespace boost::spirit;
using namespace std;
+using boost::lexical_cast;
namespace qpid {
-std::ostream& operator<<(std::ostream& os, const TcpAddress& a) {
- return os << "tcp:" << a.host << ":" << a.port;
-}
-
-std::istream& operator>>(std::istream&, const TcpAddress&);
+Url::Invalid::Invalid(const string& s) : Exception(s) {}
Url Url::getHostNameUrl(uint16_t port) {
- char name[HOST_NAME_MAX];
- if (::gethostname(name, sizeof(name)) != 0)
- throw InvalidUrl(QPID_MSG("Cannot get host name: " << qpid::sys::strError(errno)));
- return Url(TcpAddress(name, port));
+ TcpAddress address(std::string(), port);
+ if (!sys::SystemInfo::getLocalHostname(address))
+ throw Url::Invalid(QPID_MSG("Cannot get host name: " << qpid::sys::strError(errno)));
+ return Url(address);
}
-static const string LOCALHOST("127.0.0.1");
-
Url Url::getIpAddressesUrl(uint16_t port) {
Url url;
- int s = socket (PF_INET, SOCK_STREAM, 0);
- for (int i=1;;i++) {
- struct ifreq ifr;
- ifr.ifr_ifindex = i;
- if (::ioctl (s, SIOCGIFNAME, &ifr) < 0)
- break;
- /* now ifr.ifr_name is set */
- if (::ioctl (s, SIOCGIFADDR, &ifr) < 0)
- continue;
- struct sockaddr_in *sin = (struct sockaddr_in *) &ifr.ifr_addr;
- string addr(inet_ntoa(sin->sin_addr));
- if (addr != LOCALHOST)
- url.push_back(TcpAddress(addr, port));
- }
- close (s);
+ sys::SystemInfo::getLocalIpAddresses(port, url);
return url;
}
@@ -93,78 +68,138 @@ ostream& operator<<(ostream& os, const Url& url) {
return os;
}
-// Addition to boost::spirit parsers: accept any character from a
-// string. Vastly more compile-time-efficient than long rules of the
-// form: ch_p('x') | ch_p('y') |...
-//
-struct ch_in : public char_parser<ch_in> {
- ch_in(const string& chars_) : chars(chars_) {}
- bool test(char ch_) const {
- return chars.find(ch_) != string::npos;
- }
- string chars;
-};
-inline ch_in ch_in_p(const string& chars) {
- return ch_in(chars);
-}
+/** Simple recursive-descent parser for url grammar in AMQP 0-10 spec:
+
+ amqp_url = "amqp:" prot_addr_list
+ prot_addr_list = [prot_addr ","]* prot_addr
+ prot_addr = tcp_prot_addr | tls_prot_addr
+
+ tcp_prot_addr = tcp_id tcp_addr
+ tcp_id = "tcp:" | ""
+ tcp_addr = [host [":" port] ]
+ host = <as per http://www.ietf.org/rfc/rfc3986.txt>
+ port = number]]>
+*/
+class UrlParser {
+ public:
+ UrlParser(Url& u, const char* s) : url(u), text(s), end(s+strlen(s)), i(s) {}
+ bool parse() { return literal("amqp:") && list(&UrlParser::protAddr, &UrlParser::comma) && i == end; }
-/** Grammar for AMQP URLs. */
-struct UrlGrammar : public grammar<UrlGrammar>
-{
- Url& addr;
+ private:
+ typedef bool (UrlParser::*Rule)();
+
+ bool comma() { return literal(","); }
+
+ // NOTE: tcpAddr must be last since it is allowed to omit it's tcp: tag.
+ bool protAddr() { return exampleAddr() || tcpAddr(); }
+
+ bool tcpAddr() {
+ TcpAddress addr;
+ literal("tcp:"); // Don't check result, allowed to be absent.
+ return addIf(host(addr.host) && (literal(":") ? port(addr.port) : true), addr);
+ }
- UrlGrammar(Url& addr_) : addr(addr_) {}
-
- template <class ScannerT>
- struct definition {
- TcpAddress tcp;
-
- definition(const UrlGrammar& self)
- {
- first = eps_p[clear_a(self.addr)] >> amqp_url;
- amqp_url = str_p("amqp:") >> prot_addr_list >>
- !(str_p("/") >> !parameters);
- prot_addr_list = prot_addr % ',';
- prot_addr = tcp_prot_addr; // Extend for TLS etc.
-
- // TCP addresses
- tcp_prot_addr = tcp_id >> tcp_addr[push_back_a(self.addr, tcp)];
- tcp_id = !str_p("tcp:");
- tcp_addr = !(host[assign_a(tcp.host)] >> !(':' >> port));
-
- // See http://www.apps.ietf.org/rfc/rfc3986.html#sec-A
- // for real host grammar. Shortcut:
- port = uint_parser<uint16_t>()[assign_a(tcp.port)];
- host = *( unreserved | pct_encoded );
- unreserved = alnum_p | ch_in_p("-._~");
- pct_encoded = "%" >> xdigit_p >> xdigit_p;
- parameters = *anychar_p >> end_p; // Ignore, not used yet.
+ // Placeholder address type till we have multiple address types. Address is a single char.
+ bool exampleAddr () {
+ if (literal("example:") && i < end) {
+ ExampleAddress ex(*i++);
+ url.push_back(ex);
+ return true;
}
+ return false;
+ }
+
+ // FIXME aconway 2008-11-20: this does not implement http://www.ietf.org/rfc/rfc3986.txt.
+ // Works for DNS names and ipv4 literals but won't handle ipv6.
+ bool host(string& h) {
+ const char* start=i;
+ while (unreserved() || pctEncoded())
+ ;
+ if (start == i) h = LOCALHOST; // Default
+ else h.assign(start, i);
+ return true;
+ }
+
+ bool unreserved() { return (::isalnum(*i) || ::strchr("-._~", *i)) && advance(); }
- const rule<ScannerT>& start() const { return first; }
+ bool pctEncoded() { return literal("%") && hexDigit() && hexDigit(); }
- rule<ScannerT> first, amqp_url, prot_addr_list, prot_addr,
- tcp_prot_addr, tcp_id, tcp_addr, host, port,
- unreserved, pct_encoded, parameters;
+ bool hexDigit() { return i < end && ::strchr("01234567890abcdefABCDEF", *i) && advance(); }
+
+ bool port(uint16_t& p) { return decimalInt(p); }
+
+ template <class AddrType> bool addIf(bool ok, const AddrType& addr) { if (ok) url.push_back(addr); return ok; }
+
+ template <class IntType> bool decimalInt(IntType& n) {
+ const char* start = i;
+ while (decDigit())
+ ;
+ try {
+ n = lexical_cast<IntType>(string(start, i));
+ return true;
+ } catch(...) { return false; }
+ }
+
+ bool decDigit() { return i < end && ::isdigit(*i) && advance(); }
+
+ bool literal(const char* s) {
+ int n = ::strlen(s);
+ if (n <= end-i && equal(s, s+n, i)) return advance(n);
+ return false;
};
+
+ bool noop() { return true; }
+
+ /** List of item, separated by separator, with min & max bounds. */
+ bool list(Rule item, Rule separator, size_t min=0, size_t max=UNLIMITED) {
+ assert(max > 0);
+ assert(max >= min);
+ if (!(this->*item)()) return min == 0; // Empty list.
+ size_t n = 1;
+ while (n < max && i < end) {
+ if (!(this->*separator)()) break;
+ if (i == end || !(this->*item)()) return false; // Separator with no item.
+ ++n;
+ }
+ return n >= min;
+ }
+
+ /** List of items with no separator */
+ bool list(Rule item, size_t min=0, size_t max=UNLIMITED) { return list(item, &UrlParser::noop, min, max); }
+
+ bool advance(size_t n=1) {
+ if (i+n > end) return false;
+ i += n;
+ return true;
+ }
+
+ static const size_t UNLIMITED = size_t(~1);
+ static const std::string LOCALHOST;
+
+ Url& url;
+ const char* text;
+ const char* end;
+ const char* i;
};
+const string UrlParser::LOCALHOST("127.0.0.1");
+
void Url::parse(const char* url) {
- cache.clear();
- if (!boost::spirit::parse(url, UrlGrammar(*this)).full)
- throw InvalidUrl(string("Invalid AMQP url: ")+url);
+ parseNoThrow(url);
+ if (empty())
+ throw Url::Invalid(QPID_MSG("Invalid URL: " << url));
}
void Url::parseNoThrow(const char* url) {
cache.clear();
- if (!boost::spirit::parse(url, UrlGrammar(*this)).full)
+ if (!UrlParser(*this, url).parse())
clear();
}
void Url::throwIfEmpty() const {
if (empty())
- throw InvalidUrl("URL contains no addresses");
+ throw Url::Invalid("URL contains no addresses");
}
std::istream& operator>>(std::istream& is, Url& url) {
diff --git a/cpp/src/qpid/Url.h b/cpp/src/qpid/Url.h
deleted file mode 100644
index 20f42db0ad..0000000000
--- a/cpp/src/qpid/Url.h
+++ /dev/null
@@ -1,109 +0,0 @@
-#ifndef QPID_URL_H
-#define QPID_URL_H
-
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "qpid/Exception.h"
-#include <boost/variant.hpp>
-#include <string>
-#include <vector>
-#include <new>
-#include <ostream>
-
-namespace qpid {
-
-/** TCP address of a broker - host:port */
-struct TcpAddress {
- static const uint16_t DEFAULT_PORT=5672;
- explicit TcpAddress(const std::string& host_=std::string(),
- uint16_t port_=DEFAULT_PORT)
- : host(host_), port(port_) {}
- std::string host;
- uint16_t port;
-};
-
-inline bool operator==(const TcpAddress& x, const TcpAddress& y) {
- return y.host==x.host && y.port == x.port;
-}
-
-std::ostream& operator<<(std::ostream& os, const TcpAddress& a);
-
-/** Address is a variant of all address types, more coming in future. */
-typedef boost::variant<TcpAddress> Address;
-
-/** An AMQP URL contains a list of addresses */
-struct Url : public std::vector<Address> {
-
- /** Url with the hostname as returned by gethostname(2) */
- static Url getHostNameUrl(uint16_t port);
-
- /** Url with local IP address(es), may be more than one address
- * on a multi-homed host. */
- static Url getIpAddressesUrl(uint16_t port);
-
- struct InvalidUrl : public Exception {
- InvalidUrl(const std::string& s) : Exception(s) {}
- };
-
- /** Convert to string form. */
- std::string str() const;
-
- /** Empty URL. */
- Url() {}
-
- /** URL containing a single address */
- explicit Url(const Address& addr) { push_back(addr); }
-
- /** Parse url, throw InvalidUrl if invalid. */
- explicit Url(const std::string& url) { parse(url.c_str()); }
-
- /** Parse url, throw InvalidUrl if invalid. */
- explicit Url(const char* url) { parse(url); }
-
- template<class T> Url& operator=(T s) { parse(s); return *this; }
-
- /** Throw InvalidUrl if the URL does not contain any addresses. */
- void throwIfEmpty() const;
-
- /** Replace contents with parsed URL as defined in
- * https://wiki.108.redhat.com/jira/browse/AMQP-95
- *@exception InvalidUrl if the url is invalid.
- */
- void parse(const char* url);
- void parse(const std::string& url) { parse(url.c_str()); }
-
- /** Replace contesnts with parsed URL as defined in
- * https://wiki.108.redhat.com/jira/browse/AMQP-95
- * url.empty() will be true if url is invalid.
- */
- void parseNoThrow(const char* url);
-
- private:
- mutable std::string cache; // cache string form for efficiency.
-};
-
-inline bool operator==(const Url& a, const Url& b) { return a.str()==b.str(); }
-inline bool operator!=(const Url& a, const Url& b) { return a.str()!=b.str(); }
-
-std::ostream& operator<<(std::ostream& os, const Url& url);
-std::istream& operator>>(std::istream& is, Url& url);
-
-} // namespace qpid
-
-#endif /*!QPID_URL_H*/
diff --git a/cpp/src/qpid/Version.h b/cpp/src/qpid/Version.h
new file mode 100755
index 0000000000..67c0281ac5
--- /dev/null
+++ b/cpp/src/qpid/Version.h
@@ -0,0 +1,44 @@
+#ifndef QPID_VERSION_H
+#define QPID_VERSION_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <string>
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+namespace qpid {
+#ifdef HAVE_CONFIG_H
+ const std::string product = PACKAGE_NAME;
+ const std::string version = PACKAGE_VERSION;
+# if HAVE_SASL
+ const std::string saslName = BROKER_SASL_NAME;
+# else
+ const std::string saslName = "qpidd-no-sasl";
+# endif
+#else
+ const std::string product = "qpidc";
+ const std::string version = "0.6";
+ const std::string saslName = "qpid-broker";
+#endif
+}
+
+#endif /*!QPID_VERSION_H*/
diff --git a/cpp/src/qpid/acl/Acl.cpp b/cpp/src/qpid/acl/Acl.cpp
index 79e4af57ee..fe2644c136 100644
--- a/cpp/src/qpid/acl/Acl.cpp
+++ b/cpp/src/qpid/acl/Acl.cpp
@@ -16,126 +16,150 @@
*
*/
-#include "Acl.h"
-
+#include "qpid/acl/Acl.h"
+#include "qpid/acl/AclData.h"
#include "qpid/broker/Broker.h"
#include "qpid/Plugin.h"
#include "qpid/Options.h"
-#include "qpid/shared_ptr.h"
#include "qpid/log/Logger.h"
+#include "qmf/org/apache/qpid/acl/Package.h"
+#include "qmf/org/apache/qpid/acl/EventAllow.h"
+#include "qmf/org/apache/qpid/acl/EventDeny.h"
+#include "qmf/org/apache/qpid/acl/EventFileLoaded.h"
+#include "qmf/org/apache/qpid/acl/EventFileLoadFailed.h"
#include <map>
+#include <boost/shared_ptr.hpp>
#include <boost/utility/in_place_factory.hpp>
-namespace qpid {
-namespace acl {
-
using namespace std;
-
- Acl::Acl (AclValues& av, broker::Broker& b): aclValues(av), broker(&b), transferAcl(false)
+using namespace qpid::acl;
+using qpid::broker::Broker;
+using qpid::management::ManagementAgent;
+using qpid::management::ManagementObject;
+using qpid::management::Manageable;
+using qpid::management::Args;
+namespace _qmf = qmf::org::apache::qpid::acl;
+
+Acl::Acl (AclValues& av, Broker& b): aclValues(av), broker(&b), transferAcl(false)
+{
+
+ agent = broker->getManagementAgent();
+
+ if (agent != 0){
+ _qmf::Package packageInit(agent);
+ mgmtObject = new _qmf::Acl (agent, this, broker);
+ agent->addObject (mgmtObject);
+ }
+
+ std::string errorString;
+ if (!readAclFile(errorString)){
+ throw Exception("Could not read ACL file " + errorString);
+ if (mgmtObject!=0) mgmtObject->set_enforcingAcl(0);
+ }
+ QPID_LOG(info, "ACL Plugin loaded");
+ if (mgmtObject!=0) mgmtObject->set_enforcingAcl(1);
+}
+
+ bool Acl::authorise(const std::string& id, const Action& action, const ObjectType& objType, const std::string& name, std::map<Property, std::string>* params)
{
- if (!readAclFile()) throw Exception("Could not read ACL file");
- QPID_LOG(info, "ACL Plugin loaded");
+ boost::shared_ptr<AclData> dataLocal = data; //rcu copy
- }
+ // add real ACL check here...
+ AclResult aclreslt = dataLocal->lookup(id,action,objType,name,params);
- std::string Acl::printAction(acl::Action action)
- {
- switch (action)
- {
- case CONSUME: return "Consume";
- case PUBLISH: return "Publish";
- case CREATE: return "Create";
- case ACCESS: return "Access";
- case BIND: return "Bind";
- case UNBIND: return "Unbind";
- case DELETE: return "Delete";
- case PURGE: return "Purge";
- case UPDATE: return "Update";
- default: return "Unknown";
- }
- }
-
- std::string Acl::printObjType(acl::ObjectType objType)
- {
- switch (objType)
- {
- case QUEUE: return "Queue";
- case EXCHANGE: return "Exchnage";
- case BROKER: return "Broker";
- case LINK: return "Link";
- case ROUTE: return "Route";
- default: return "Unknown";
- }
- }
- bool Acl::authorise(std::string id, acl::Action action, acl::ObjectType objType, std::string name, std::map<std::string, std::string>*
- /*params*/)
- {
- if (aclValues.noEnforce) return true;
- boost::shared_ptr<AclData> dataLocal = data; //rcu copy
-
- // only use dataLocal here...
-
- // add real ACL check here...
- AclResult aclreslt = ALLOWLOG; // hack to test, set based on real decision.
-
-
- return result(aclreslt, id, action, objType, name);
+ return result(aclreslt, id, action, objType, name);
}
- bool Acl::authorise(std::string id, acl::Action action, acl::ObjectType objType, std::string ExchangeName, std::string /*RoutingKey*/)
+ bool Acl::authorise(const std::string& id, const Action& action, const ObjectType& objType, const std::string& ExchangeName, const std::string& RoutingKey)
{
- if (aclValues.noEnforce) return true;
boost::shared_ptr<AclData> dataLocal = data; //rcu copy
-
+
// only use dataLocal here...
-
- // add real ACL check here...
- AclResult aclreslt = ALLOWLOG; // hack to test, set based on real decision.
-
-
- return result(aclreslt, id, action, objType, ExchangeName);
+ AclResult aclreslt = dataLocal->lookup(id,action,objType,ExchangeName,RoutingKey);
+
+ return result(aclreslt, id, action, objType, ExchangeName);
}
-
- bool Acl::result(AclResult aclreslt, std::string id, acl::Action action, acl::ObjectType objType, std::string name)
+
+ bool Acl::result(const AclResult& aclreslt, const std::string& id, const Action& action, const ObjectType& objType, const std::string& name)
{
switch (aclreslt)
{
case ALLOWLOG:
- QPID_LOG(info, "ACL Allow id:" << id <<" action:" << printAction(action) << " ObjectType:" << printObjType(objType) << " Name:" << name );
+ QPID_LOG(info, "ACL Allow id:" << id <<" action:" << AclHelper::getActionStr(action) <<
+ " ObjectType:" << AclHelper::getObjectTypeStr(objType) << " Name:" << name );
+ agent->raiseEvent(_qmf::EventAllow(id, AclHelper::getActionStr(action),
+ AclHelper::getObjectTypeStr(objType),
+ name, framing::FieldTable()));
case ALLOW:
return true;
- case DENYNOLOG:
- return false;
case DENY:
- default:
- QPID_LOG(info, "ACL Deny id:" << id << " action:" << printAction(action) << " ObjectType:" << printObjType(objType) << " Name:" << name);
+ if (mgmtObject!=0) mgmtObject->inc_aclDenyCount();
return false;
+ case DENYLOG:
+ if (mgmtObject!=0) mgmtObject->inc_aclDenyCount();
+ default:
+ QPID_LOG(info, "ACL Deny id:" << id << " action:" << AclHelper::getActionStr(action) << " ObjectType:" << AclHelper::getObjectTypeStr(objType) << " Name:" << name);
+ agent->raiseEvent(_qmf::EventDeny(id, AclHelper::getActionStr(action),
+ AclHelper::getObjectTypeStr(objType),
+ name, framing::FieldTable()));
+ return false;
}
- return false;
+ return false;
}
-
- bool Acl::readAclFile()
+
+ bool Acl::readAclFile(std::string& errorText)
{
// only set transferAcl = true if a rule implies the use of ACL on transfer, else keep false for permormance reasons.
- return readAclFile(aclValues.aclFile);
+ return readAclFile(aclValues.aclFile, errorText);
}
- bool Acl::readAclFile(std::string aclFile) {
+ bool Acl::readAclFile(std::string& aclFile, std::string& errorText) {
boost::shared_ptr<AclData> d(new AclData);
- if (AclReader::read(aclFile, d))
+ AclReader ar;
+ if (ar.read(aclFile, d)){
+ agent->raiseEvent(_qmf::EventFileLoadFailed("", ar.getError()));
+ errorText = ar.getError();
+ QPID_LOG(error,ar.getError());
return false;
-
+ }
+
data = d;
+ transferAcl = data->transferAcl; // any transfer ACL
+ if (mgmtObject!=0){
+ mgmtObject->set_transferAcl(transferAcl?1:0);
+ mgmtObject->set_policyFile(aclFile);
+ sys::AbsTime now = sys::AbsTime::now();
+ int64_t ns = sys::Duration(now);
+ mgmtObject->set_lastAclLoad(ns);
+ agent->raiseEvent(_qmf::EventFileLoaded(""));
+ }
return true;
}
Acl::~Acl(){}
+ ManagementObject* Acl::GetManagementObject(void) const
+ {
+ return (ManagementObject*) mgmtObject;
+ }
-
-}} // namespace qpid::acl
+ Manageable::status_t Acl::ManagementMethod (uint32_t methodId, Args& /*args*/, string& text)
+ {
+ Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD;
+ QPID_LOG (debug, "Queue::ManagementMethod [id=" << methodId << "]");
+
+ switch (methodId)
+ {
+ case _qmf::Acl::METHOD_RELOADACLFILE :
+ readAclFile(text);
+ status = Manageable::STATUS_USER;
+ break;
+ }
+
+ return status;
+}
diff --git a/cpp/src/qpid/acl/Acl.h b/cpp/src/qpid/acl/Acl.h
index a82add556c..e153187b3d 100644
--- a/cpp/src/qpid/acl/Acl.h
+++ b/cpp/src/qpid/acl/Acl.h
@@ -23,9 +23,12 @@
#include "qpid/acl/AclReader.h"
-#include "qpid/shared_ptr.h"
#include "qpid/RefCounted.h"
#include "qpid/broker/AclModule.h"
+#include "qpid/management/Manageable.h"
+#include "qpid/management/ManagementAgent.h"
+#include "qmf/org/apache/qpid/acl/Acl.h"
+
#include <map>
#include <string>
@@ -38,14 +41,11 @@ class Broker;
namespace acl {
struct AclValues {
- bool noEnforce;
- std::string aclFile;
-
- AclValues() {noEnforce = false; aclFile = "policy.acl"; }
+ std::string aclFile;
};
-class Acl : public broker::AclModule, public RefCounted
+class Acl : public broker::AclModule, public RefCounted, public management::Manageable
{
private:
@@ -53,7 +53,8 @@ private:
broker::Broker* broker;
bool transferAcl;
boost::shared_ptr<AclData> data;
-
+ qmf::org::apache::qpid::acl::Acl* mgmtObject; // mgnt owns lifecycle
+ qpid::management::ManagementAgent* agent;
public:
Acl (AclValues& av, broker::Broker& b);
@@ -63,20 +64,21 @@ public:
inline virtual bool doTransferAcl() {return transferAcl;};
// create specilied authorise methods for cases that need faster matching as needed.
- virtual bool authorise(std::string id, acl::Action action, acl::ObjectType objType, std::string name, std::map<std::string, std::string>* params);
- virtual bool authorise(std::string id, acl::Action action, acl::ObjectType objType, std::string ExchangeName, std::string RoutingKey);
+ virtual bool authorise(const std::string& id, const Action& action, const ObjectType& objType, const std::string& name, std::map<Property, std::string>* params=0);
+ virtual bool authorise(const std::string& id, const Action& action, const ObjectType& objType, const std::string& ExchangeName,const std::string& RoutingKey);
virtual ~Acl();
private:
- std::string printAction(acl::Action action);
- std::string printObjType(acl::ObjectType objType);
- bool result(AclResult aclreslt, std::string id, acl::Action action, acl::ObjectType objType, std::string name);
- bool readAclFile();
- bool readAclFile(std::string aclFile);
+ bool result(const AclResult& aclreslt, const std::string& id, const Action& action, const ObjectType& objType, const std::string& name);
+ bool readAclFile(std::string& errorText);
+ bool readAclFile(std::string& aclFile, std::string& errorText);
+ virtual qpid::management::ManagementObject* GetManagementObject(void) const;
+ virtual management::Manageable::status_t ManagementMethod (uint32_t methodId, management::Args& args, std::string& text);
+
};
-
+
}} // namespace qpid::acl
#endif // QPID_ACL_ACL_H
diff --git a/cpp/src/qpid/acl/AclData.cpp b/cpp/src/qpid/acl/AclData.cpp
new file mode 100644
index 0000000000..5d7a028736
--- /dev/null
+++ b/cpp/src/qpid/acl/AclData.cpp
@@ -0,0 +1,236 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/acl/AclData.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/IntegerTypes.h"
+#include <boost/lexical_cast.hpp>
+
+namespace qpid {
+namespace acl {
+
+AclData::AclData():decisionMode(qpid::acl::DENY),transferAcl(false)
+{
+ for (unsigned int cnt=0; cnt< qpid::acl::ACTIONSIZE; cnt++){
+ actionList[cnt]=0;
+ }
+
+}
+
+void AclData::clear ()
+{
+ for (unsigned int cnt=0; cnt< qpid::acl::ACTIONSIZE; cnt++){
+ if (actionList[cnt]){
+ for (unsigned int cnt1=0; cnt1< qpid::acl::OBJECTSIZE; cnt1++)
+ delete actionList[cnt][cnt1];
+ }
+ delete[] actionList[cnt];
+ }
+
+}
+
+bool AclData::matchProp(const std::string & src, const std::string& src1)
+{
+ // allow wildcard on the end of strings...
+ if (src.data()[src.size()-1]=='*') {
+ return (src.compare(0, src.size()-1, src1, 0,src.size()-1 ) == 0);
+ } else {
+ return (src.compare(src1)==0) ;
+ }
+}
+
+AclResult AclData::lookup(const std::string& id, const Action& action, const ObjectType& objType,
+ const std::string& name, std::map<Property, std::string>* params) {
+
+ QPID_LOG(debug, "ACL: Lookup for id:" << id << " action:" << AclHelper::getActionStr((Action) action)
+ << " objectType:" << AclHelper::getObjectTypeStr((ObjectType) objType) << " name:" << name
+ << " with params " << AclHelper::propertyMapToString(params));
+
+ AclResult aclresult = decisionMode;
+ if (actionList[action] && actionList[action][objType]) {
+ AclData::actObjItr itrRule = actionList[action][objType]->find(id);
+ if (itrRule == actionList[action][objType]->end())
+ itrRule = actionList[action][objType]->find("*");
+
+ if (itrRule != actionList[action][objType]->end()) {
+
+ QPID_LOG(debug, "ACL: checking the following rules for : " << itrRule->first );
+
+ //loop the vector
+ for (ruleSetItr i = itrRule->second.begin(); i < itrRule->second.end(); i++) {
+ QPID_LOG(debug, "ACL: checking rule " << i->toString());
+ // loop the names looking for match
+ bool match = true;
+ for (propertyMapItr pMItr = i->props.begin(); (pMItr != i->props.end()) && match; pMItr++) {
+ //match name is exists first
+ if (pMItr->first == acl::PROP_NAME) {
+ if (matchProp(pMItr->second, name)){
+ QPID_LOG(debug, "ACL: name '" << name << "' matched with name '"
+ << pMItr->second << "' given in the rule");
+ }else{
+ match = false;
+ QPID_LOG(debug, "ACL: name '" << name << "' didn't match with name '"
+ << pMItr->second << "' given in the rule");
+ }
+ } else if (params) { //match pMItr against params
+ propertyMapItr paramItr = params->find(pMItr->first);
+ if (paramItr == params->end()) {
+ match = false;
+ QPID_LOG(debug, "ACL: the given parameter map in lookup doesn't contain the property '"
+ << AclHelper::getPropertyStr(pMItr->first) << "'");
+ }else if ( pMItr->first == acl::PROP_MAXQUEUECOUNT || pMItr->first == acl::PROP_MAXQUEUESIZE ) {
+ if ( pMItr->first == paramItr->first ) {
+ uint64_t aclMax = boost::lexical_cast<uint64_t>(pMItr->second);
+ uint64_t paramMax = boost::lexical_cast<uint64_t>(paramItr->second);
+ QPID_LOG(debug, "ACL: Numeric comparison for property " <<
+ AclHelper::getPropertyStr(paramItr->first) <<
+ " (value given in lookup = " <<
+ boost::lexical_cast<std::string>(paramItr->second) <<
+ ", value give in rule = " <<
+ boost::lexical_cast<std::string>(pMItr->second) << " )");
+ if (( aclMax ) && ( paramMax == 0 || paramMax > aclMax)){
+ match = decisionMode == qpid::acl::ALLOW ;
+ QPID_LOG(debug, "ACL: Limit exceeded and match=" <<
+ (match ? "true": "false") <<
+ " as decision mode is " << AclHelper::getAclResultStr(decisionMode));
+ }
+ }
+ }else if (matchProp(pMItr->second, paramItr->second)) {
+ QPID_LOG(debug, "ACL: the pair("
+ << AclHelper::getPropertyStr(paramItr->first) << "," << paramItr->second
+ << ") given in lookup matched the pair("
+ << AclHelper::getPropertyStr(pMItr->first) << "," << pMItr->second << ") given in the rule");
+ } else {
+ QPID_LOG(debug, "ACL: the pair("
+ << AclHelper::getPropertyStr(paramItr->first) << "," << paramItr->second
+ << ") given in lookup doesn't match the pair("
+ << AclHelper::getPropertyStr(pMItr->first) << "," << pMItr->second << ") given in the rule");
+ match = false;
+
+ }
+ }
+ }
+ if (match)
+ {
+ aclresult = getACLResult(i->logOnly, i->log);
+ QPID_LOG(debug,"Successful match, the decision is:" << AclHelper::getAclResultStr(aclresult));
+ return aclresult;
+ }
+ }
+ }
+ }
+
+ QPID_LOG(debug,"No successful match, defaulting to the decision mode " << AclHelper::getAclResultStr(aclresult));
+ return aclresult;
+}
+
+AclResult AclData::lookup(const std::string& id, const Action& action, const ObjectType& objType, const std::string& /*Exchange*/ name, const std::string& RoutingKey)
+{
+
+ QPID_LOG(debug, "ACL: Lookup for id:" << id << " action:" << AclHelper::getActionStr((Action) action)
+ << " objectType:" << AclHelper::getObjectTypeStr((ObjectType) objType) << " exchange name:" << name
+ << " with routing key " << RoutingKey);
+
+ AclResult aclresult = decisionMode;
+
+ if (actionList[action] && actionList[action][objType]){
+ AclData::actObjItr itrRule = actionList[action][objType]->find(id);
+
+ if (itrRule == actionList[action][objType]->end())
+ itrRule = actionList[action][objType]->find("*");
+
+ if (itrRule != actionList[action][objType]->end() ) {
+
+ QPID_LOG(debug, "ACL: checking the following rules for : " << itrRule->first );
+
+ //loop the vector
+ for (ruleSetItr i=itrRule->second.begin(); i<itrRule->second.end(); i++) {
+ QPID_LOG(debug, "ACL: checking rule " << i->toString());
+
+ // loop the names looking for match
+ bool match =true;
+ for (propertyMapItr pMItr = i->props.begin(); (pMItr != i->props.end()) && match; pMItr++)
+ {
+ //match name is exists first
+ if (pMItr->first == acl::PROP_NAME){
+ if (matchProp(pMItr->second, name)){
+ QPID_LOG(debug, "ACL: name '" << name << "' matched with name '"
+ << pMItr->second << "' given in the rule");
+
+ }else{
+ match= false;
+ QPID_LOG(debug, "ACL: name '" << name << "' didn't match with name '"
+ << pMItr->second << "' given in the rule");
+ }
+ }else if (pMItr->first == acl::PROP_ROUTINGKEY){
+ if (matchProp(pMItr->second, RoutingKey)){
+ QPID_LOG(debug, "ACL: name '" << name << "' matched with routing_key '"
+ << pMItr->second << "' given in the rule");
+ }else{
+ match= false;
+ QPID_LOG(debug, "ACL: name '" << name << "' didn't match with routing_key '"
+ << pMItr->second << "' given in the rule");
+ }
+ }
+ }
+ if (match){
+ aclresult = getACLResult(i->logOnly, i->log);
+ QPID_LOG(debug,"Successful match, the decision is:" << AclHelper::getAclResultStr(aclresult));
+ return aclresult;
+ }
+ }
+ }
+ }
+ QPID_LOG(debug,"No successful match, defaulting to the decision mode " << AclHelper::getAclResultStr(aclresult));
+ return aclresult;
+
+}
+
+
+AclResult AclData::getACLResult(bool logOnly, bool log)
+{
+ switch (decisionMode)
+ {
+ case qpid::acl::ALLOWLOG:
+ case qpid::acl::ALLOW:
+ if (logOnly) return qpid::acl::ALLOWLOG;
+ if (log)
+ return qpid::acl::DENYLOG;
+ else
+ return qpid::acl::DENY;
+
+
+ case qpid::acl::DENYLOG:
+ case qpid::acl::DENY:
+ if (logOnly) return qpid::acl::DENYLOG;
+ if (log)
+ return qpid::acl::ALLOWLOG;
+ else
+ return qpid::acl::ALLOW;
+ }
+
+ QPID_LOG(error, "ACL Decision Failed, setting DENY");
+ return qpid::acl::DENY;
+}
+
+AclData::~AclData()
+{
+ clear();
+}
+
+}}
diff --git a/cpp/src/qpid/acl/AclData.h b/cpp/src/qpid/acl/AclData.h
new file mode 100644
index 0000000000..a63afab12b
--- /dev/null
+++ b/cpp/src/qpid/acl/AclData.h
@@ -0,0 +1,83 @@
+#ifndef QPID_ACL_ACLDATA_H
+#define QPID_ACL_ACLDATA_H
+
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/broker/AclModule.h"
+#include <vector>
+#include <sstream>
+
+namespace qpid {
+namespace acl {
+
+class AclData {
+
+
+public:
+
+ typedef std::map<qpid::acl::Property, std::string> propertyMap;
+ typedef propertyMap::const_iterator propertyMapItr;
+ struct rule {
+
+ bool log;
+ bool logOnly; // this is a rule is to log only
+
+ // key value map
+ //??
+ propertyMap props;
+
+
+ rule (propertyMap& p):log(false),logOnly(false),props(p) {};
+
+ std::string toString () const {
+ std::ostringstream ruleStr;
+ ruleStr << "[log=" << log << ", logOnly=" << logOnly << " props{";
+ for (propertyMapItr pMItr = props.begin(); pMItr != props.end(); pMItr++) {
+ ruleStr << " " << AclHelper::getPropertyStr((Property) pMItr-> first) << "=" << pMItr->second;
+ }
+ ruleStr << " }]";
+ return ruleStr.str();
+ }
+ };
+ typedef std::vector<rule> ruleSet;
+ typedef ruleSet::const_iterator ruleSetItr;
+ typedef std::map<std::string, ruleSet > actionObject; // user
+ typedef actionObject::iterator actObjItr;
+ typedef actionObject* aclAction;
+
+ // Action*[] -> Object*[] -> map<user -> set<Rule> >
+ aclAction* actionList[qpid::acl::ACTIONSIZE];
+ qpid::acl::AclResult decisionMode; // determines if the rule set is an deny or accept basis.
+ bool transferAcl;
+
+ AclResult lookup(const std::string& id, const Action& action, const ObjectType& objType, const std::string& name, std::map<Property, std::string>* params=0);
+ AclResult lookup(const std::string& id, const Action& action, const ObjectType& objType, const std::string& ExchangeName, const std::string& RoutingKey);
+ AclResult getACLResult(bool logOnly, bool log);
+
+ bool matchProp(const std::string & src, const std::string& src1);
+ void clear ();
+
+ AclData();
+ virtual ~AclData();
+};
+
+}} // namespace qpid::acl
+
+#endif // QPID_ACL_ACLDATA_H
diff --git a/cpp/src/qpid/acl/AclPlugin.cpp b/cpp/src/qpid/acl/AclPlugin.cpp
index a025354f13..e4d721ea44 100644
--- a/cpp/src/qpid/acl/AclPlugin.cpp
+++ b/cpp/src/qpid/acl/AclPlugin.cpp
@@ -21,9 +21,9 @@
#include "qpid/broker/Broker.h"
#include "qpid/Plugin.h"
#include "qpid/Options.h"
-#include "qpid/shared_ptr.h"
#include "qpid/log/Statement.h"
+#include <boost/shared_ptr.hpp>
#include <boost/utility/in_place_factory.hpp>
namespace qpid {
@@ -36,13 +36,11 @@ using namespace std;
* New boost allows a shared_ptr but that's not compatible with old boost.
*/
struct AclOptions : public Options {
- AclValues& values;
+ AclValues& values;
AclOptions(AclValues& v) : Options("ACL Options"), values(v) {
addOptions()
- ("no-enforce-acl", optValue(values.noEnforce), "Do not enforce ACL")
- ("acl-file", optValue(values.aclFile, "FILE"), "The policy file to load from, loaded from data dir")
- ;
+ ("acl-file", optValue(values.aclFile, "FILE"), "The policy file to load from, loaded from data dir");
}
};
@@ -51,20 +49,25 @@ struct AclPlugin : public Plugin {
AclValues values;
AclOptions options;
boost::intrusive_ptr<Acl> acl;
-
+
AclPlugin() : options(values) {}
Options* getOptions() { return &options; }
void init(broker::Broker& b) {
- if (values.noEnforce){
- QPID_LOG(info, "ACL Disabled, no ACL checking being done.");
- return;
- }
- if (acl) throw Exception("ACL plugin cannot be initialized twice in one process.");
- std::ostringstream oss;
- oss << b.getDataDir().getPath() << "/" << values.aclFile;
- values.aclFile = oss.str();
+ if (values.aclFile.empty()){
+ QPID_LOG(info, "Policy file not specified. ACL Disabled, no ACL checking being done!");
+ return;
+ }
+
+ if (acl) throw Exception("ACL plugin cannot be initialized twice in one process.");
+
+ if (values.aclFile.at(0) != '/' && !b.getDataDir().getPath().empty()) {
+ std::ostringstream oss;
+ oss << b.getDataDir().getPath() << "/" << values.aclFile;
+ values.aclFile = oss.str();
+ }
+
acl = new Acl(values, b);
b.setAcl(acl.get());
b.addFinalizer(boost::bind(&AclPlugin::shutdown, this));
@@ -89,5 +92,5 @@ static AclPlugin instance; // Static initialization.
// For test purposes.
boost::intrusive_ptr<Acl> getGlobalAcl() { return instance.acl; }
-
+
}} // namespace qpid::acl
diff --git a/cpp/src/qpid/acl/AclReader.cpp b/cpp/src/qpid/acl/AclReader.cpp
index 0a9517bc76..8f419a6f50 100644
--- a/cpp/src/qpid/acl/AclReader.cpp
+++ b/cpp/src/qpid/acl/AclReader.cpp
@@ -18,47 +18,306 @@
#include "qpid/acl/AclReader.h"
+#include <cctype>
#include <cstring>
-//#include <iostream> // debug
#include <fstream>
+#include <sstream>
+#include "qpid/log/Statement.h"
+#include "qpid/Exception.h"
+
+#include <iomanip> // degug
+#include <iostream> // debug
+
+#define ACL_FORMAT_ERR_LOG_PREFIX "ACL format error: " << fileName << ":" << lineNumber << ": "
namespace qpid {
namespace acl {
+AclReader::aclRule::aclRule(const AclResult r, const std::string n, const groupMap& groups) : res(r), actionAll(true), objStatus(NONE) {
+ processName(n, groups);
+}
+AclReader::aclRule::aclRule(const AclResult r, const std::string n, const groupMap& groups, const Action a) : res(r), actionAll(false), action(a), objStatus(NONE) {
+ processName(n, groups);
+}
+
+void AclReader::aclRule::setObjectType(const ObjectType o) {
+ objStatus = VALUE;
+ object = o;
+}
+
+void AclReader::aclRule::setObjectTypeAll() {
+ objStatus = ALL;
+}
+
+bool AclReader::aclRule::addProperty(const Property p, const std::string v) {
+ return props.insert(propNvPair(p, v)).second;
+}
+
+bool AclReader::aclRule::validate(const AclHelper::objectMapPtr& /*validationMap*/) {
+ // TODO - invalid rules won't ever be called in real life...
+ return true;
+}
+
+// Debug aid
+std::string AclReader::aclRule::toString() {
+ std::ostringstream oss;
+ oss << AclHelper::getAclResultStr(res) << " [";
+ for (nsCitr itr = names.begin(); itr != names.end(); itr++) {
+ if (itr != names.begin()) oss << ", ";
+ oss << *itr;
+ }
+ oss << "]";
+ if (actionAll) {
+ oss << " *";
+ } else {
+ oss << " " << AclHelper::getActionStr(action);
+ }
+ if (objStatus == ALL) {
+ oss << " *";
+ } else if (objStatus == VALUE) {
+ oss << " " << AclHelper::getObjectTypeStr(object);
+ }
+ for (pmCitr i=props.begin(); i!=props.end(); i++) {
+ oss << " " << AclHelper::getPropertyStr(i->first) << "=" << i->second;
+ }
+ return oss.str();
+}
+
+void AclReader::loadDecisionData(boost::shared_ptr<AclData> d) {
+ d->clear();
+ QPID_LOG(debug, "ACL Load Rules");
+ int cnt = rules.size();
+ bool foundmode = false;
+
+ for (rlCitr i = rules.end() - 1; cnt; i--, cnt--) {
+ QPID_LOG(debug, "ACL Processing " << std::setfill(' ') << std::setw(2)
+ << cnt << " " << (*i)->toString());
+
+ if (!foundmode && (*i)->actionAll && (*i)->names.size() == 1
+ && (*((*i)->names.begin())).compare("*") == 0) {
+ d->decisionMode = (*i)->res;
+ QPID_LOG(debug, "ACL FoundMode " << AclHelper::getAclResultStr(
+ d->decisionMode));
+ foundmode = true;
+ } else {
+ AclData::rule rule((*i)->props);
+ bool addrule = true;
+
+ switch ((*i)->res) {
+ case qpid::acl::ALLOWLOG:
+ rule.log = true;
+ if (d->decisionMode == qpid::acl::ALLOW || d->decisionMode
+ == qpid::acl::ALLOWLOG)
+ rule.logOnly = true;
+ break;
+ case qpid::acl::ALLOW:
+ if (d->decisionMode == qpid::acl::ALLOW || d->decisionMode
+ == qpid::acl::ALLOWLOG)
+ addrule = false;
+ break;
+ case qpid::acl::DENYLOG:
+ rule.log = true;
+ if (d->decisionMode == qpid::acl::DENY || d->decisionMode
+ == qpid::acl::DENYLOG)
+ rule.logOnly = true;
+ break;
+ case qpid::acl::DENY:
+ if (d->decisionMode == qpid::acl::DENY || d->decisionMode
+ == qpid::acl::DENYLOG)
+ addrule = false;
+ break;
+ default:
+ throw Exception("Invalid ACL Result loading rules.");
+ }
+
+ // Action -> Object -> map<user -> set<Rule> >
+ if (addrule) {
+ std::ostringstream actionstr;
+ for (int acnt = ((*i)->actionAll ? 0 : (*i)->action); acnt
+ < acl::ACTIONSIZE; (*i)->actionAll ? acnt++ : acnt
+ = acl::ACTIONSIZE) {
+
+ if (acnt == acl::ACT_PUBLISH)
+ d->transferAcl = true; // we have transfer ACL
+
+ actionstr << AclHelper::getActionStr((Action) acnt) << ",";
+
+ //find the Action, create if not exist
+ if (d->actionList[acnt] == NULL) {
+ d->actionList[acnt]
+ = new AclData::aclAction[qpid::acl::OBJECTSIZE];
+ for (int j = 0; j < qpid::acl::OBJECTSIZE; j++)
+ d->actionList[acnt][j] = NULL;
+ }
+
+ // optimize this loop to limit to valid options only!!
+ for (int ocnt = ((*i)->objStatus != aclRule::VALUE ? 0
+ : (*i)->object); ocnt < acl::OBJECTSIZE; (*i)->objStatus
+ != aclRule::VALUE ? ocnt++ : ocnt = acl::OBJECTSIZE) {
+
+ //find the Object, create if not exist
+ if (d->actionList[acnt][ocnt] == NULL)
+ d->actionList[acnt][ocnt]
+ = new AclData::actionObject;
+
+ // add users and Rule to object set
+ bool allNames = false;
+ // check to see if names.begin is '*'
+ if ((*(*i)->names.begin()).compare("*") == 0)
+ allNames = true;
+
+ for (nsCitr itr = (allNames ? names.begin()
+ : (*i)->names.begin()); itr
+ != (allNames ? names.end() : (*i)->names.end()); itr++) {
+
+ AclData::actObjItr itrRule =
+ d->actionList[acnt][ocnt]->find(*itr);
+
+ if (itrRule == d->actionList[acnt][ocnt]->end()) {
+ AclData::ruleSet rSet;
+ rSet.push_back(rule);
+ d->actionList[acnt][ocnt]->insert(make_pair(
+ std::string(*itr), rSet));
+ } else {
+
+ // TODO add code to check for dead rules
+ // allow peter create queue name=tmp <-- dead rule!!
+ // allow peter create queue
+
+ itrRule->second.push_back(rule);
+ }
+ }
+
+ }
+ }
+
+ std::ostringstream objstr;
+ for (int ocnt = ((*i)->objStatus != aclRule::VALUE ? 0 : (*i)->object); ocnt < acl::OBJECTSIZE;
+ (*i)->objStatus != aclRule::VALUE ? ocnt++ : ocnt = acl::OBJECTSIZE) {
+ objstr << AclHelper::getObjectTypeStr((ObjectType) ocnt) << ",";
+ }
+
+ bool allNames = ((*(*i)->names.begin()).compare("*") == 0);
+ std::ostringstream userstr;
+ for (nsCitr itr = (allNames ? names.begin() : (*i)->names.begin());
+ itr != (allNames ? names.end() : (*i)->names.end()); itr++) {
+ userstr << *itr << ",";
+ }
+
+ QPID_LOG(debug,"ACL: Adding actions {" << actionstr.str().substr(0,actionstr.str().length()-1)
+ << "} to objects {" << objstr.str().substr(0,objstr.str().length()-1)
+ << "} with props " << AclHelper::propertyMapToString(&rule.props)
+ << " for users {" << userstr.str().substr(0,userstr.str().length()-1) << "}" );
+ } else {
+ QPID_LOG(debug, "ACL Skipping based on Mode:"
+ << AclHelper::getAclResultStr(d->decisionMode));
+ }
+ }
+
+ }
+
+}
+
+
+void AclReader::aclRule::processName(const std::string& name, const groupMap& groups) {
+ if (name.compare("all") == 0) {
+ names.insert("*");
+ } else {
+ gmCitr itr = groups.find(name);
+ if (itr == groups.end()) {
+ names.insert(name);
+ } else {
+ names.insert(itr->second->begin(), itr->second->end());
+ }
+ }
+}
+
+AclReader::AclReader() : lineNumber(0), contFlag(false), validationMap(new AclHelper::objectMap) {
+ AclHelper::loadValidationMap(validationMap);
+ names.insert("*");
+}
+
+AclReader::~AclReader() {}
+
+std::string AclReader::getError() {
+ return errorStream.str();
+}
+
int AclReader::read(const std::string& fn, boost::shared_ptr<AclData> d) {
-//std::cout << "AclReader::read(" << fn << ")" << std::endl << std::flush;
+ fileName = fn;
+ lineNumber = 0;
char buff[1024];
std::ifstream ifs(fn.c_str(), std::ios_base::in);
if (!ifs.good()) {
- // error/exception - file open error
+ errorStream << "Unable to open ACL file \"" << fn << "\": eof=" << (ifs.eof()?"T":"F") << "; fail=" << (ifs.fail()?"T":"F") << "; bad=" << (ifs.bad()?"T":"F");
return -1;
}
try {
+ bool err = false;
while (ifs.good()) {
ifs.getline(buff, 1024);
- processLine(buff, d);
+ lineNumber++;
+ if (std::strlen(buff) > 0 && buff[0] != '#') // Ignore blank lines and comments
+ err |= !processLine(buff);
}
+ if (!ifs.eof())
+ {
+ errorStream << "Unable to read ACL file \"" << fn << "\": eof=" << (ifs.eof()?"T":"F") << "; fail=" << (ifs.fail()?"T":"F") << "; bad=" << (ifs.bad()?"T":"F");
+ ifs.close();
+ return -2;
+ }
+ ifs.close();
+ if (err) return -3;
+ QPID_LOG(notice, "Read ACL file \"" << fn << "\"");
+ } catch (const std::exception& e) {
+ errorStream << "Unable to read ACL file \"" << fn << "\": " << e.what();
ifs.close();
+ return -4;
} catch (...) {
- // error/exception - file read/processing error
+ errorStream << "Unable to read ACL file \"" << fn << "\": Unknown exception";
ifs.close();
- return -2;
+ return -5;
}
+ printNames();
+ printRules();
+ loadDecisionData(d);
+
return 0;
}
+bool AclReader::processLine(char* line) {
+ bool ret = false;
+ std::vector<std::string> toks;
+
+ // Check for continuation
+ char* contCharPtr = std::strrchr(line, '\\');
+ bool cont = contCharPtr != 0;
+ if (cont) *contCharPtr = 0;
-void AclReader::processLine(char* line, boost::shared_ptr<AclData> /*d*/) {
- std::vector<std::string> toks;
- int numToks = tokenizeLine(line, toks);
- for (int i=0; i<numToks; i++) {
-// DO MAGIC STUFF HERE
-//std::cout << "tok " << i << ": " << toks[i] << std::endl << std::flush;
- }
+ int numToks = tokenize(line, toks);
+ if (numToks && (toks[0].compare("group") == 0 || contFlag)) {
+ ret = processGroupLine(toks, cont);
+ } else if (numToks && toks[0].compare("acl") == 0) {
+ ret = processAclLine(toks);
+ } else {
+ // Check for whitespace only line, ignore these
+ bool ws = true;
+ for (unsigned i=0; i<std::strlen(line) && ws; i++) {
+ if (!std::isspace(line[i])) ws = false;
+ }
+ if (ws) {
+ ret = true;
+ } else {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Non-continuation line must start with \"group\" or \"acl\".";
+ ret = false;
+ }
+ }
+ contFlag = cont;
+ return ret;
}
-int AclReader::tokenizeLine(char* line, std::vector<std::string>& toks) {
- const char* tokChars = " \t\n";
+int AclReader::tokenize(char* line, std::vector<std::string>& toks) {
+ const char* tokChars = " \t\n\f\v\r";
int cnt = 0;
char* cp = std::strtok(line, tokChars);
while (cp != 0) {
@@ -69,5 +328,223 @@ int AclReader::tokenizeLine(char* line, std::vector<std::string>& toks) {
return cnt;
}
+// Return true if the line is successfully processed without errors
+// If cont is true, then groupName must be set to the continuation group name
+bool AclReader::processGroupLine(tokList& toks, const bool cont) {
+ const unsigned toksSize = toks.size();
+ if (contFlag) {
+ gmCitr citr = groups.find(groupName);
+ for (unsigned i = 0; i < toksSize; i++) {
+ if (!checkName(toks[i])) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Name \"" << toks[i] << "\" contains illegal characters.";
+ return false;
+ }
+ if (!isValidUserName(toks[i])) return false;
+ addName(toks[i], citr->second);
+ }
+ } else {
+ if (toksSize < (cont ? 2 : 3)) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Insufficient tokens for group definition.";
+ return false;
+ }
+ if (!checkName(toks[1])) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Group name \"" << toks[1] << "\" contains illegal characters.";
+ return false;
+ }
+ gmCitr citr = addGroup(toks[1]);
+ if (citr == groups.end()) return false;
+ for (unsigned i = 2; i < toksSize; i++) {
+ if (!checkName(toks[i])) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Name \"" << toks[i] << "\" contains illegal characters.";
+ return false;
+ }
+ if (!isValidUserName(toks[i])) return false;
+ addName(toks[i], citr->second);
+ }
+ }
+ return true;
+}
+
+// Return true if sucessfully added group
+AclReader::gmCitr AclReader::addGroup(const std::string& newGroupName) {
+ gmCitr citr = groups.find(newGroupName);
+ if (citr != groups.end()) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Duplicate group name \"" << newGroupName << "\".";
+ return groups.end();
+ }
+ groupPair p(newGroupName, nameSetPtr(new nameSet));
+ gmRes res = groups.insert(p);
+ assert(res.second);
+ groupName = newGroupName;
+ return res.first;
+}
+
+void AclReader::addName(const std::string& name, nameSetPtr groupNameSet) {
+ gmCitr citr = groups.find(name);
+ if (citr != groups.end() && citr->first != name){
+ // This is a previously defined group: add all the names in that group to this group
+ groupNameSet->insert(citr->second->begin(), citr->second->end());
+ } else {
+ // Not a known group name
+ groupNameSet->insert(name);
+ addName(name);
+ }
+}
+
+void AclReader::addName(const std::string& name) {
+ names.insert(name);
+}
+
+// Debug aid
+void AclReader::printNames() const {
+ QPID_LOG(debug, "Group list: " << groups.size() << " groups found:" );
+ std::string tmp;
+ for (gmCitr i=groups.begin(); i!= groups.end(); i++) {
+ tmp += " \"";
+ tmp += i->first;
+ tmp += "\":";
+ for (nsCitr j=i->second->begin(); j!=i->second->end(); j++) {
+ tmp += " ";
+ tmp += *j;
+ }
+ QPID_LOG(debug, tmp);
+ tmp.clear();
+ }
+ QPID_LOG(debug, "Name list: " << names.size() << " names found:" );
+ tmp.clear();
+ for (nsCitr k=names.begin(); k!=names.end(); k++) {
+ tmp += " ";
+ tmp += *k;
+ }
+ QPID_LOG(debug, tmp);
+}
+
+bool AclReader::processAclLine(tokList& toks) {
+ const unsigned toksSize = toks.size();
+ if (toksSize < 4) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Insufficient tokens for acl definition.";
+ return false;
+ }
+
+ AclResult res;
+ try {
+ res = AclHelper::getAclResult(toks[1]);
+ } catch (...) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Unknown ACL permission \"" << toks[1] << "\".";
+ return false;
+ }
+
+ bool actionAllFlag = toks[3].compare("all") == 0;
+ bool userAllFlag = toks[2].compare("all") == 0;
+ Action action;
+ if (actionAllFlag) {
+
+ if (userAllFlag && toksSize > 4) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Tokens found after action \"all\".";
+ return false;
+ }
+ action = ACT_CONSUME; // dummy; compiler must initialize action for this code path
+ } else {
+ try {
+ action = AclHelper::getAction(toks[3]);
+ } catch (...) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Unknown action \"" << toks[3] << "\".";
+ return false;
+ }
+ }
+
+ // Create rule obj; then add object (if any) and properties (if any)
+ aclRulePtr rule;
+ if (actionAllFlag) {
+ rule.reset(new aclRule(res, toks[2], groups));
+ } else {
+ rule.reset(new aclRule(res, toks[2], groups, action));
+ }
+
+ if (toksSize >= 5) { // object name-value pair
+ if (toks[4].compare("all") == 0) {
+ rule->setObjectTypeAll();
+ } else {
+ try {
+ rule->setObjectType(AclHelper::getObjectType(toks[4]));
+ } catch (...) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Unknown object \"" << toks[4] << "\".";
+ return false;
+ }
+ }
+ }
+
+ if (toksSize >= 6) { // property name-value pair(s)
+ for (unsigned i=5; i<toksSize; i++) {
+ nvPair propNvp = splitNameValuePair(toks[i]);
+ if (propNvp.second.size() == 0) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Badly formed property name-value pair \"" << propNvp.first << "\". (Must be name=value)";
+ return false;
+ }
+ Property prop;
+ try {
+ prop = AclHelper::getProperty(propNvp.first);
+ } catch (...) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Unknown property \"" << propNvp.first << "\".";
+ return false;
+ }
+ rule->addProperty(prop, propNvp.second);
+ }
+ }
+ // Check if name (toks[2]) is group; if not, add as name of individual
+ if (toks[2].compare("all") != 0) {
+ if (groups.find(toks[2]) == groups.end()) {
+ addName(toks[2]);
+ }
+ }
+
+ // If rule validates, add to rule list
+ if (!rule->validate(validationMap)) {
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Invalid object/action/property combination.";
+ return false;
+ }
+ rules.push_back(rule);
+
+ return true;
+}
+
+// Debug aid
+void AclReader::printRules() const {
+ QPID_LOG(debug, "Rule list: " << rules.size() << " ACL rules found:");
+ int cnt = 0;
+ for (rlCitr i=rules.begin(); i<rules.end(); i++,cnt++) {
+ QPID_LOG(debug, " " << std::setfill(' ') << std::setw(2) << cnt << " " << (*i)->toString());
+ }
+}
+
+// Static function
+// Return true if the name is well-formed (ie contains legal characters)
+bool AclReader::checkName(const std::string& name) {
+ for (unsigned i=0; i<name.size(); i++) {
+ const char ch = name.at(i);
+ if (!std::isalnum(ch) && ch != '-' && ch != '_' && ch != '@') return false;
+ }
+ return true;
+}
+
+// Static function
+// Split name-value pair around '=' char of the form "name=value"
+AclReader::nvPair AclReader::splitNameValuePair(const std::string& nvpString) {
+ std::size_t pos = nvpString.find("=");
+ if (pos == std::string::npos || pos == nvpString.size() - 1) {
+ return nvPair(nvpString, "");
+ }
+ return nvPair(nvpString.substr(0, pos), nvpString.substr(pos+1));
+}
+
+// Returns true if a username has the name@realm format
+bool AclReader::isValidUserName(const std::string& name){
+ size_t pos = name.find('@');
+ if ( pos == std::string::npos || pos == name.length() -1){
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Username '" << name << "' must contain a realm";
+ return false;
+ }
+ return true;
+}
}} // namespace qpid::acl
diff --git a/cpp/src/qpid/acl/AclReader.h b/cpp/src/qpid/acl/AclReader.h
index 783b70d98a..dccb450192 100644
--- a/cpp/src/qpid/acl/AclReader.h
+++ b/cpp/src/qpid/acl/AclReader.h
@@ -21,25 +21,98 @@
*/
#include <boost/shared_ptr.hpp>
+#include <map>
+#include <set>
#include <string>
#include <vector>
+#include <sstream>
+#include "qpid/acl/AclData.h"
+#include "qpid/broker/AclModule.h"
namespace qpid {
namespace acl {
-struct AclData {
- bool lc; // Line continue flag
- AclData() : lc(false) {}
-};
-
class AclReader {
-public:
- static int read(const std::string& fn, boost::shared_ptr<AclData> d);
-private:
- static void processLine(char* line, boost::shared_ptr<AclData> d);
- static int tokenizeLine(char* line, std::vector<std::string>& toks);
+ typedef std::set<std::string> nameSet;
+ typedef nameSet::const_iterator nsCitr;
+ typedef boost::shared_ptr<nameSet> nameSetPtr;
+
+ typedef std::pair<std::string, nameSetPtr> groupPair;
+ typedef std::map<std::string, nameSetPtr> groupMap;
+ typedef groupMap::const_iterator gmCitr;
+ typedef std::pair<gmCitr, bool> gmRes;
+
+ typedef std::pair<Property, std::string> propNvPair;
+ typedef std::map<Property, std::string> propMap;
+ typedef propMap::const_iterator pmCitr;
+
+ class aclRule {
+ public:
+ enum objectStatus {NONE, VALUE, ALL};
+ AclResult res;
+ nameSet names;
+ bool actionAll; // True if action is set to keyword "all"
+ Action action; // Ignored if action is set to keyword "all"
+ objectStatus objStatus;
+ ObjectType object; // Ignored for all status values except VALUE
+ propMap props;
+ public:
+ aclRule(const AclResult r, const std::string n, const groupMap& groups); // action = "all"
+ aclRule(const AclResult r, const std::string n, const groupMap& groups, const Action a);
+ void setObjectType(const ObjectType o);
+ void setObjectTypeAll();
+ bool addProperty(const Property p, const std::string v);
+ bool validate(const AclHelper::objectMapPtr& validationMap);
+ std::string toString(); // debug aid
+ private:
+ void processName(const std::string& name, const groupMap& groups);
+ };
+ typedef boost::shared_ptr<aclRule> aclRulePtr;
+ typedef std::vector<aclRulePtr> ruleList;
+ typedef ruleList::const_iterator rlCitr;
+
+ typedef std::vector<std::string> tokList;
+ typedef tokList::const_iterator tlCitr;
+
+ typedef std::set<std::string> keywordSet;
+ typedef keywordSet::const_iterator ksCitr;
+ typedef std::pair<std::string, std::string> nvPair; // Name-Value pair
+
+ std::string fileName;
+ int lineNumber;
+ bool contFlag;
+ std::string groupName;
+ nameSet names;
+ groupMap groups;
+ ruleList rules;
+ AclHelper::objectMapPtr validationMap;
+ std::ostringstream errorStream;
+
+ public:
+ AclReader();
+ virtual ~AclReader();
+ int read(const std::string& fn, boost::shared_ptr<AclData> d);
+ std::string getError();
+
+ private:
+ bool processLine(char* line);
+ void loadDecisionData( boost::shared_ptr<AclData> d);
+ int tokenize(char* line, tokList& toks);
+
+ bool processGroupLine(tokList& toks, const bool cont);
+ gmCitr addGroup(const std::string& groupName);
+ void addName(const std::string& name, nameSetPtr groupNameSet);
+ void addName(const std::string& name);
+ void printNames() const; // debug aid
+
+ bool processAclLine(tokList& toks);
+ void printRules() const; // debug aid
+ bool isValidUserName(const std::string& name);
+
+ static bool checkName(const std::string& name);
+ static nvPair splitNameValuePair(const std::string& nvpString);
};
-
+
}} // namespace qpid::acl
#endif // QPID_ACL_ACLREADER_H
diff --git a/cpp/src/qpid/acl/management-schema.xml b/cpp/src/qpid/acl/management-schema.xml
new file mode 100644
index 0000000000..f4637253d0
--- /dev/null
+++ b/cpp/src/qpid/acl/management-schema.xml
@@ -0,0 +1,44 @@
+<schema package="org.apache.qpid.acl">
+
+<!--
+ * Copyright (c) 2008 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+
+ <class name="Acl">
+ <property name="brokerRef" type="objId" references="org.apache.qpid.broker:Broker" access="RO" index="y" parentRef="y"/>
+ <property name="policyFile" type="sstr" access="RO" desc="Name of the policy file"/>
+ <property name="enforcingAcl" type="bool" access="RO" desc="Currently Enforcing ACL"/>
+ <property name="transferAcl" type="bool" access="RO" desc="Any transfer ACL rules in force"/>
+ <property name="lastAclLoad" type="absTime" access="RO" desc="Timestamp of last successful load of ACL"/>
+ <statistic name="aclDenyCount" type="count64" unit="request" desc="Number of ACL requests denied"/>
+
+ <method name="reloadACLFile" desc="Reload the ACL file"/>
+ </class>
+
+ <eventArguments>
+ <arg name="action" type="sstr"/>
+ <arg name="arguments" type="map"/>
+ <arg name="objectName" type="sstr"/>
+ <arg name="objectType" type="sstr"/>
+ <arg name="reason" type="sstr"/>
+ <arg name="userId" type="sstr"/>
+ </eventArguments>
+
+ <event name="allow" sev="inform" args="userId, action, objectType, objectName, arguments"/>
+ <event name="deny" sev="notice" args="userId, action, objectType, objectName, arguments"/>
+ <event name="fileLoaded" sev="inform" args="userId"/>
+ <event name="fileLoadFailed" sev="error" args="userId, reason"/>
+
+</schema>
diff --git a/cpp/src/qpid/agent/ManagementAgent.h b/cpp/src/qpid/agent/ManagementAgent.h
deleted file mode 100644
index e7379e6c94..0000000000
--- a/cpp/src/qpid/agent/ManagementAgent.h
+++ /dev/null
@@ -1,127 +0,0 @@
-#ifndef _qpid_agent_ManagementAgent_
-#define _qpid_agent_ManagementAgent_
-
-//
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES 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/management/ManagementObject.h"
-#include "qpid/management/Manageable.h"
-#include "qpid/sys/Mutex.h"
-
-namespace qpid {
-namespace management {
-
-class ManagementAgent
-{
- public:
-
- class Singleton {
- public:
- Singleton(bool disableManagement = false);
- ~Singleton();
- static ManagementAgent* getInstance();
- private:
- static sys::Mutex lock;
- static bool disabled;
- static int refCount;
- static ManagementAgent* agent;
- };
-
- ManagementAgent () {}
- virtual ~ManagementAgent () {}
-
- virtual int getMaxThreads() = 0;
-
- // Connect to a management broker
- //
- // brokerHost - Hostname or IP address (dotted-quad) of broker.
- //
- // brokerPort - TCP port of broker.
- //
- // intervalSeconds - The interval (in seconds) that this agent shall use
- // between broadcast updates to the broker.
- //
- // useExternalThread - If true, the thread of control used for callbacks
- // must be supplied by the user of the object (via the
- // pollCallbacks method).
- //
- // If false, callbacks shall be invoked on the management
- // agent's thread. In this case, the callback implementations
- // MUST be thread safe.
- //
- virtual void init (std::string brokerHost = "localhost",
- uint16_t brokerPort = 5672,
- uint16_t intervalSeconds = 10,
- bool useExternalThread = false) = 0;
-
- // Register a schema with the management agent. This is normally called by the
- // package initializer generated by the management code generator.
- //
- virtual void
- RegisterClass (std::string packageName,
- std::string className,
- uint8_t* md5Sum,
- management::ManagementObject::writeSchemaCall_t schemaCall) = 0;
-
- // Add a management object to the agent. Once added, this object shall be visible
- // in the greater management context.
- //
- // Please note that ManagementObject instances are not explicitly deleted from
- // the management agent. When the core object represented by a management object
- // is deleted, the "resourceDestroy" method on the management object must be called.
- // It will then be reclaimed in due course by the management agent.
- //
- // Once a ManagementObject instance is added to the agent, the agent then owns the
- // instance. The caller MUST NOT free the resources of the instance at any time.
- // When it is no longer needed, invoke its "resourceDestroy" method and discard the
- // pointer. This allows the management agent to report the deletion of the object
- // in an orderly way.
- //
- virtual uint64_t addObject (ManagementObject* objectPtr,
- uint32_t persistId = 0,
- uint32_t persistBank = 4) = 0;
-
- // If "useExternalThread" was set to true in init, this method must
- // be called to provide a thread for any pending method calls that have arrived.
- // The method calls for ManagementObject instances shall be invoked synchronously
- // during the execution of this method.
- //
- // callLimit may optionally be used to limit the number of callbacks invoked.
- // if 0, no limit is imposed.
- //
- // The return value is the number of callbacks that remain queued after this
- // call is complete. It can be used to determine whether or not further calls
- // to pollCallbacks are necessary to clear the backlog. If callLimit is zero,
- // the return value will also be zero.
- //
- virtual uint32_t pollCallbacks (uint32_t callLimit = 0) = 0;
-
- // If "useExternalThread" was set to true in the constructor, this method provides
- // a standard file descriptor that can be used in a select statement to signal that
- // there are method callbacks ready (i.e. that "pollCallbacks" will result in at
- // least one method call). When this fd is ready-for-read, pollCallbacks may be
- // invoked. Calling pollCallbacks shall reset the ready-to-read state of the fd.
- //
- virtual int getSignalFd (void) = 0;
-
-};
-
-}}
-
-#endif /*!_qpid_agent_ManagementAgent_*/
diff --git a/cpp/src/qpid/agent/ManagementAgentImpl.cpp b/cpp/src/qpid/agent/ManagementAgentImpl.cpp
index ebdc71e3b1..f84e158154 100644
--- a/cpp/src/qpid/agent/ManagementAgentImpl.cpp
+++ b/cpp/src/qpid/agent/ManagementAgentImpl.cpp
@@ -20,16 +20,25 @@
#include "qpid/management/Manageable.h"
#include "qpid/management/ManagementObject.h"
-#include "ManagementAgentImpl.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/PipeHandle.h"
+#include "qpid/agent/ManagementAgentImpl.h"
#include <list>
-#include <unistd.h>
#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <iostream>
+#include <fstream>
+
using namespace qpid::client;
using namespace qpid::framing;
using namespace qpid::management;
using namespace qpid::sys;
+using namespace std;
using std::stringstream;
+using std::ofstream;
+using std::ifstream;
using std::string;
using std::cout;
using std::endl;
@@ -66,128 +75,274 @@ ManagementAgent* ManagementAgent::Singleton::getInstance()
return agent;
}
+const string ManagementAgentImpl::storeMagicNumber("MA02");
+
ManagementAgentImpl::ManagementAgentImpl() :
- clientWasAdded(true), objIdPrefix(0), bgThread(*this), thread(bgThread), startupWait(false)
+ interval(10), extThread(false), pipeHandle(0),
+ initialized(false), connected(false), lastFailure("never connected"),
+ clientWasAdded(true), requestedBrokerBank(0), requestedAgentBank(0),
+ assignedBrokerBank(0), assignedAgentBank(0), bootSequence(0),
+ connThreadBody(*this), connThread(connThreadBody),
+ pubThreadBody(*this), pubThread(pubThreadBody)
{
- // TODO: Establish system ID
}
-void ManagementAgentImpl::init(std::string brokerHost,
- uint16_t brokerPort,
- uint16_t intervalSeconds,
- bool useExternalThread)
+ManagementAgentImpl::~ManagementAgentImpl()
{
+ // shutdown & cleanup all threads
+ connThreadBody.close();
+ pubThreadBody.close();
+
+ connThread.join();
+ pubThread.join();
+
+ // Release the memory associated with stored management objects.
{
Mutex::ScopedLock lock(agentLock);
- startupWait = true;
+
+ moveNewObjectsLH();
+ for (ManagementObjectMap::iterator iter = managementObjects.begin ();
+ iter != managementObjects.end ();
+ iter++) {
+ ManagementObject* object = iter->second;
+ delete object;
+ }
+ managementObjects.clear();
+ }
+ if (pipeHandle) {
+ delete pipeHandle;
+ pipeHandle = 0;
}
+}
+void ManagementAgentImpl::init(const string& brokerHost,
+ uint16_t brokerPort,
+ uint16_t intervalSeconds,
+ bool useExternalThread,
+ const string& _storeFile,
+ const string& uid,
+ const string& pwd,
+ const string& mech,
+ const string& proto)
+{
+ client::ConnectionSettings settings;
+ settings.protocol = proto;
+ settings.host = brokerHost;
+ settings.port = brokerPort;
+ settings.username = uid;
+ settings.password = pwd;
+ settings.mechanism = mech;
+ init(settings, intervalSeconds, useExternalThread, _storeFile);
+}
+
+void ManagementAgentImpl::init(const qpid::client::ConnectionSettings& settings,
+ uint16_t intervalSeconds,
+ bool useExternalThread,
+ const std::string& _storeFile)
+{
interval = intervalSeconds;
extThread = useExternalThread;
+ storeFile = _storeFile;
nextObjectId = 1;
- sessionId.generate();
- queueName << "qmfagent-" << sessionId;
- string dest = "qmfagent";
+ QPID_LOG(info, "QMF Agent Initialized: broker=" << settings.host << ":" << settings.port <<
+ " interval=" << intervalSeconds << " storeFile=" << _storeFile);
+ connectionSettings = settings;
- connection.open(brokerHost.c_str(), brokerPort);
- session = connection.newSession (queueName.str());
- dispatcher = new client::Dispatcher(session);
+ // TODO: Abstract the socket calls for portability
+ // qpid::sys::PipeHandle to create a pipe
+ if (extThread) {
+ pipeHandle = new PipeHandle(true);
+ }
+ retrieveData();
+ bootSequence++;
+ if ((bootSequence & 0xF000) != 0)
+ bootSequence = 1;
+ storeData(true);
- session.queueDeclare (arg::queue=queueName.str());
- session.exchangeBind (arg::exchange="amq.direct", arg::queue=queueName.str(),
- arg::bindingKey=queueName.str());
- session.messageSubscribe (arg::queue=queueName.str(),
- arg::destination=dest);
- session.messageFlow (arg::destination=dest, arg::unit=0, arg::value=0xFFFFFFFF);
- session.messageFlow (arg::destination=dest, arg::unit=1, arg::value=0xFFFFFFFF);
+ initialized = true;
+}
- Message attachRequest;
- char rawbuffer[512];
- Buffer buffer (rawbuffer, 512);
+void ManagementAgentImpl::registerClass(const string& packageName,
+ const string& className,
+ uint8_t* md5Sum,
+ qpid::management::ManagementObject::writeSchemaCall_t schemaCall)
+{
+ Mutex::ScopedLock lock(agentLock);
+ PackageMap::iterator pIter = findOrAddPackage(packageName);
+ addClassLocal(ManagementItem::CLASS_KIND_TABLE, pIter, className, md5Sum, schemaCall);
+}
- attachRequest.getDeliveryProperties().setRoutingKey("broker");
- attachRequest.getMessageProperties().setReplyTo(ReplyTo("amq.direct", queueName.str()));
+void ManagementAgentImpl::registerEvent(const string& packageName,
+ const string& eventName,
+ uint8_t* md5Sum,
+ qpid::management::ManagementObject::writeSchemaCall_t schemaCall)
+{
+ Mutex::ScopedLock lock(agentLock);
+ PackageMap::iterator pIter = findOrAddPackage(packageName);
+ addClassLocal(ManagementItem::CLASS_KIND_EVENT, pIter, eventName, md5Sum, schemaCall);
+}
- EncodeHeader (buffer, 'A');
- buffer.putShortString ("RemoteAgent [C++]");
- systemId.encode (buffer);
- buffer.putLong (11);
+ObjectId ManagementAgentImpl::addObject(ManagementObject* object,
+ uint64_t persistId)
+{
+ Mutex::ScopedLock lock(addLock);
+ uint16_t sequence = persistId ? 0 : bootSequence;
+ uint64_t objectNum = persistId ? persistId : nextObjectId++;
- size_t length = 512 - buffer.available ();
- string stringBuffer (rawbuffer, length);
- attachRequest.setData (stringBuffer);
+ ObjectId objectId(&attachment, 0, sequence, objectNum);
- session.messageTransfer(arg::content=attachRequest, arg::destination="qpid.management");
+ // TODO: fix object-id handling
+ object->setObjectId(objectId);
+ newManagementObjects[objectId] = object;
+ return objectId;
+}
- dispatcher->listen(dest, this);
- dispatcher->start();
+void ManagementAgentImpl::raiseEvent(const ManagementEvent& event, severity_t severity)
+{
+ Mutex::ScopedLock lock(agentLock);
+ Buffer outBuffer(eventBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+ uint8_t sev = (severity == SEV_DEFAULT) ? event.getSeverity() : (uint8_t) severity;
+ stringstream key;
- {
- Mutex::ScopedLock lock(agentLock);
- if (startupWait)
- startupCond.wait(agentLock);
- }
+ key << "console.event." << assignedBrokerBank << "." << assignedAgentBank << "." <<
+ event.getPackageName() << "." << event.getEventName();
+
+ encodeHeader(outBuffer, 'e');
+ outBuffer.putShortString(event.getPackageName());
+ outBuffer.putShortString(event.getEventName());
+ outBuffer.putBin128(event.getMd5Sum());
+ outBuffer.putLongLong(uint64_t(Duration(now())));
+ outBuffer.putOctet(sev);
+ event.encode(outBuffer);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ connThreadBody.sendBuffer(outBuffer, outLen, "qpid.management", key.str());
}
-ManagementAgentImpl::~ManagementAgentImpl()
+uint32_t ManagementAgentImpl::pollCallbacks(uint32_t callLimit)
{
- dispatcher->stop();
- session.close();
- delete dispatcher;
+ Mutex::ScopedLock lock(agentLock);
+
+ for (uint32_t idx = 0; callLimit == 0 || idx < callLimit; idx++) {
+ if (methodQueue.empty())
+ break;
+
+ QueuedMethod* item = methodQueue.front();
+ methodQueue.pop_front();
+ {
+ Mutex::ScopedUnlock unlock(agentLock);
+ Buffer inBuffer(const_cast<char*>(item->body.c_str()), item->body.size());
+ invokeMethodRequest(inBuffer, item->sequence, item->replyTo);
+ delete item;
+ }
+ }
+
+ char rbuf[100];
+ while (pipeHandle->read(rbuf, 100) > 0) ; // Consume all signaling bytes
+ return methodQueue.size();
}
-void ManagementAgentImpl::RegisterClass (std::string packageName,
- std::string className,
- uint8_t* md5Sum,
- management::ManagementObject::writeSchemaCall_t schemaCall)
-{
- Mutex::ScopedLock lock(agentLock);
- PackageMap::iterator pIter = FindOrAddPackage (packageName);
- AddClassLocal (pIter, className, md5Sum, schemaCall);
+int ManagementAgentImpl::getSignalFd(void)
+{
+ return pipeHandle->getReadHandle();
}
-uint64_t ManagementAgentImpl::addObject (ManagementObject* object,
- uint32_t /*persistId*/,
- uint32_t /*persistBank*/)
+void ManagementAgentImpl::startProtocol()
{
- Mutex::ScopedLock lock(addLock);
- uint64_t objectId;
+ char rawbuffer[512];
+ Buffer buffer(rawbuffer, 512);
+
+ connected = true;
+ encodeHeader(buffer, 'A');
+ buffer.putShortString("RemoteAgent [C++]");
+ systemId.encode (buffer);
+ buffer.putLong(requestedBrokerBank);
+ buffer.putLong(requestedAgentBank);
+ uint32_t length = buffer.getPosition();
+ buffer.reset();
+ connThreadBody.sendBuffer(buffer, length, "qpid.management", "broker");
+ QPID_LOG(trace, "SENT AttachRequest: reqBroker=" << requestedBrokerBank <<
+ " reqAgent=" << requestedAgentBank);
+}
- // TODO: fix object-id handling
- objectId = objIdPrefix | ((nextObjectId++) & 0x00FFFFFF);
- object->setObjectId (objectId);
- newManagementObjects[objectId] = object;
- return objectId;
+void ManagementAgentImpl::storeData(bool requested)
+{
+ if (!storeFile.empty()) {
+ ofstream outFile(storeFile.c_str());
+ uint32_t brokerBankToWrite = requested ? requestedBrokerBank : assignedBrokerBank;
+ uint32_t agentBankToWrite = requested ? requestedAgentBank : assignedAgentBank;
+
+ if (outFile.good()) {
+ outFile << storeMagicNumber << " " << brokerBankToWrite << " " <<
+ agentBankToWrite << " " << bootSequence << endl;
+ outFile.close();
+ }
+ }
}
-uint32_t ManagementAgentImpl::pollCallbacks(uint32_t /*callLimit*/)
+void ManagementAgentImpl::retrieveData()
{
- return 0;
+ if (!storeFile.empty()) {
+ ifstream inFile(storeFile.c_str());
+ string mn;
+
+ if (inFile.good()) {
+ inFile >> mn;
+ if (mn == storeMagicNumber) {
+ inFile >> requestedBrokerBank;
+ inFile >> requestedAgentBank;
+ inFile >> bootSequence;
+ }
+ inFile.close();
+ }
+ }
}
-int ManagementAgentImpl::getSignalFd(void)
+void ManagementAgentImpl::sendCommandComplete(string replyToKey, uint32_t sequence,
+ uint32_t code, string text)
{
- return -1;
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader(outBuffer, 'z', sequence);
+ outBuffer.putLong(code);
+ outBuffer.putShortString(text);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ connThreadBody.sendBuffer(outBuffer, outLen, "amq.direct", replyToKey);
+ QPID_LOG(trace, "SENT CommandComplete: seq=" << sequence << " code=" << code << " text=" << text);
}
void ManagementAgentImpl::handleAttachResponse(Buffer& inBuffer)
{
Mutex::ScopedLock lock(agentLock);
- uint32_t assigned;
- stringstream key;
- assigned = inBuffer.getLong();
- objIdPrefix = ((uint64_t) assigned) << 24;
+ assignedBrokerBank = inBuffer.getLong();
+ assignedAgentBank = inBuffer.getLong();
- startupWait = false;
- startupCond.notify();
+ QPID_LOG(trace, "RCVD AttachResponse: broker=" << assignedBrokerBank << " agent=" << assignedAgentBank);
+
+ if ((assignedBrokerBank != requestedBrokerBank) ||
+ (assignedAgentBank != requestedAgentBank)) {
+ if (requestedAgentBank == 0) {
+ QPID_LOG(notice, "Initial object-id bank assigned: " << assignedBrokerBank << "." <<
+ assignedAgentBank);
+ } else {
+ QPID_LOG(warning, "Collision in object-id! New bank assigned: " << assignedBrokerBank <<
+ "." << assignedAgentBank);
+ }
+ storeData();
+ requestedBrokerBank = assignedBrokerBank;
+ requestedAgentBank = assignedAgentBank;
+ }
+
+ attachment.setBanks(assignedBrokerBank, assignedAgentBank);
// Bind to qpid.management to receive commands
- key << "agent." << assigned;
- session.exchangeBind (arg::exchange="qpid.management", arg::queue=queueName.str(),
- arg::bindingKey=key.str());
+ connThreadBody.bindToBank(assignedBrokerBank, assignedAgentBank);
// Send package indications for all local packages
for (PackageMap::iterator pIter = packages.begin();
@@ -196,21 +351,21 @@ void ManagementAgentImpl::handleAttachResponse(Buffer& inBuffer)
Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
uint32_t outLen;
- EncodeHeader(outBuffer, 'p');
- EncodePackageIndication(outBuffer, pIter);
- outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ encodeHeader(outBuffer, 'p');
+ encodePackageIndication(outBuffer, pIter);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
outBuffer.reset();
- SendBuffer(outBuffer, outLen, "qpid.management", "broker");
+ connThreadBody.sendBuffer(outBuffer, outLen, "qpid.management", "broker");
// Send class indications for all local classes
ClassMap cMap = pIter->second;
for (ClassMap::iterator cIter = cMap.begin(); cIter != cMap.end(); cIter++) {
outBuffer.reset();
- EncodeHeader(outBuffer, 'q');
- EncodeClassIndication(outBuffer, pIter, cIter);
- outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ encodeHeader(outBuffer, 'q');
+ encodeClassIndication(outBuffer, pIter, cIter);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
outBuffer.reset();
- SendBuffer(outBuffer, outLen, "qpid.management", "broker");
+ connThreadBody.sendBuffer(outBuffer, outLen, "qpid.management", "broker");
}
}
}
@@ -225,20 +380,24 @@ void ManagementAgentImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequenc
inBuffer.getShortString(key.name);
inBuffer.getBin128(key.hash);
+ QPID_LOG(trace, "RCVD SchemaRequest: package=" << packageName << " class=" << key.name);
+
PackageMap::iterator pIter = packages.find(packageName);
if (pIter != packages.end()) {
- ClassMap cMap = pIter->second;
+ ClassMap& cMap = pIter->second;
ClassMap::iterator cIter = cMap.find(key);
if (cIter != cMap.end()) {
- SchemaClass schema = cIter->second;
- Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
- uint32_t outLen;
-
- EncodeHeader(outBuffer, 's', sequence);
- schema.writeSchemaCall(outBuffer);
- outLen = MA_BUFFER_SIZE - outBuffer.available ();
- outBuffer.reset();
- SendBuffer(outBuffer, outLen, "qpid.management", "broker");
+ SchemaClass& schema = cIter->second;
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader(outBuffer, 's', sequence);
+ schema.writeSchemaCall(outBuffer);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ connThreadBody.sendBuffer(outBuffer, outLen, "qpid.management", "broker");
+
+ QPID_LOG(trace, "SENT SchemaInd: package=" << packageName << " class=" << key.name);
}
}
}
@@ -247,30 +406,134 @@ void ManagementAgentImpl::handleConsoleAddedIndication()
{
Mutex::ScopedLock lock(agentLock);
clientWasAdded = true;
+
+ QPID_LOG(trace, "RCVD ConsoleAddedInd");
}
-void ManagementAgentImpl::handleMethodRequest(Buffer& inBuffer, uint32_t sequence, string replyTo)
+void ManagementAgentImpl::invokeMethodRequest(Buffer& inBuffer, uint32_t sequence, string replyTo)
{
string methodName;
- Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ string packageName;
+ string className;
+ uint8_t hash[16];
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
uint32_t outLen;
- uint64_t objId = inBuffer.getLongLong();
+ ObjectId objId(inBuffer);
+ inBuffer.getShortString(packageName);
+ inBuffer.getShortString(className);
+ inBuffer.getBin128(hash);
inBuffer.getShortString(methodName);
- EncodeHeader(outBuffer, 'm', sequence);
+ encodeHeader(outBuffer, 'm', sequence);
ManagementObjectMap::iterator iter = managementObjects.find(objId);
if (iter == managementObjects.end() || iter->second->isDeleted()) {
outBuffer.putLong (Manageable::STATUS_UNKNOWN_OBJECT);
- outBuffer.putShortString (Manageable::StatusText (Manageable::STATUS_UNKNOWN_OBJECT));
+ outBuffer.putMediumString(Manageable::StatusText(Manageable::STATUS_UNKNOWN_OBJECT));
} else {
- iter->second->doMethod(methodName, inBuffer, outBuffer);
+ if ((iter->second->getPackageName() != packageName) ||
+ (iter->second->getClassName() != className)) {
+ outBuffer.putLong (Manageable::STATUS_PARAMETER_INVALID);
+ outBuffer.putMediumString(Manageable::StatusText (Manageable::STATUS_PARAMETER_INVALID));
+ }
+ else
+ try {
+ outBuffer.record();
+ iter->second->doMethod(methodName, inBuffer, outBuffer);
+ } catch(exception& e) {
+ outBuffer.restore();
+ outBuffer.putLong(Manageable::STATUS_EXCEPTION);
+ outBuffer.putMediumString(e.what());
+ }
}
outLen = MA_BUFFER_SIZE - outBuffer.available();
outBuffer.reset();
- SendBuffer(outBuffer, outLen, "amq.direct", replyTo);
+ connThreadBody.sendBuffer(outBuffer, outLen, "amq.direct", replyTo);
+}
+
+void ManagementAgentImpl::handleGetQuery(Buffer& inBuffer, uint32_t sequence, string replyTo)
+{
+ FieldTable ft;
+ FieldTable::ValuePtr value;
+
+ moveNewObjectsLH();
+
+ ft.decode(inBuffer);
+
+ QPID_LOG(trace, "RCVD GetQuery: map=" << ft);
+
+ value = ft.get("_class");
+ if (value.get() == 0 || !value->convertsTo<string>()) {
+ value = ft.get("_objectid");
+ if (value.get() == 0 || !value->convertsTo<string>())
+ return;
+
+ ObjectId selector(value->get<string>());
+ ManagementObjectMap::iterator iter = managementObjects.find(selector);
+ if (iter != managementObjects.end()) {
+ ManagementObject* object = iter->second;
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ if (object->getConfigChanged() || object->getInstChanged())
+ object->setUpdateTime();
+
+ encodeHeader(outBuffer, 'g', sequence);
+ object->writeProperties(outBuffer);
+ object->writeStatistics(outBuffer, true);
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ connThreadBody.sendBuffer(outBuffer, outLen, "amq.direct", replyTo);
+
+ QPID_LOG(trace, "SENT ObjectInd");
+ }
+ sendCommandComplete(replyTo, sequence);
+ return;
+ }
+
+ string className(value->get<string>());
+
+ for (ManagementObjectMap::iterator iter = managementObjects.begin();
+ iter != managementObjects.end();
+ iter++) {
+ ManagementObject* object = iter->second;
+ if (object->getClassName() == className) {
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ if (object->getConfigChanged() || object->getInstChanged())
+ object->setUpdateTime();
+
+ encodeHeader(outBuffer, 'g', sequence);
+ object->writeProperties(outBuffer);
+ object->writeStatistics(outBuffer, true);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ connThreadBody.sendBuffer(outBuffer, outLen, "amq.direct", replyTo);
+
+ QPID_LOG(trace, "SENT ObjectInd");
+ }
+ }
+
+ sendCommandComplete(replyTo, sequence);
+}
+
+void ManagementAgentImpl::handleMethodRequest(Buffer& inBuffer, uint32_t sequence, string replyTo)
+{
+ if (extThread) {
+ Mutex::ScopedLock lock(agentLock);
+ string body;
+
+ inBuffer.getRawData(body, inBuffer.available());
+ methodQueue.push_back(new QueuedMethod(sequence, replyTo, body));
+ pipeHandle->write("X", 1);
+ } else {
+ invokeMethodRequest(inBuffer, sequence, replyTo);
+ }
+
+ QPID_LOG(trace, "RCVD MethodRequest");
}
void ManagementAgentImpl::received(Message& msg)
@@ -287,215 +550,371 @@ void ManagementAgentImpl::received(Message& msg)
replyToKey = rt.getRoutingKey();
}
- if (CheckHeader (inBuffer, &opcode, &sequence))
+ if (checkHeader(inBuffer, &opcode, &sequence))
{
if (opcode == 'a') handleAttachResponse(inBuffer);
else if (opcode == 'S') handleSchemaRequest(inBuffer, sequence);
else if (opcode == 'x') handleConsoleAddedIndication();
+ else if (opcode == 'G') handleGetQuery(inBuffer, sequence, replyToKey);
else if (opcode == 'M') handleMethodRequest(inBuffer, sequence, replyToKey);
}
}
-void ManagementAgentImpl::EncodeHeader (Buffer& buf, uint8_t opcode, uint32_t seq)
+void ManagementAgentImpl::encodeHeader(Buffer& buf, uint8_t opcode, uint32_t seq)
{
- buf.putOctet ('A');
- buf.putOctet ('M');
- buf.putOctet ('1');
- buf.putOctet (opcode);
- buf.putLong (seq);
+ buf.putOctet('A');
+ buf.putOctet('M');
+ buf.putOctet('2');
+ buf.putOctet(opcode);
+ buf.putLong (seq);
}
-bool ManagementAgentImpl::CheckHeader (Buffer& buf, uint8_t *opcode, uint32_t *seq)
+bool ManagementAgentImpl::checkHeader(Buffer& buf, uint8_t *opcode, uint32_t *seq)
{
if (buf.getSize() < 8)
return false;
- uint8_t h1 = buf.getOctet ();
- uint8_t h2 = buf.getOctet ();
- uint8_t h3 = buf.getOctet ();
+ uint8_t h1 = buf.getOctet();
+ uint8_t h2 = buf.getOctet();
+ uint8_t h3 = buf.getOctet();
- *opcode = buf.getOctet ();
- *seq = buf.getLong ();
+ *opcode = buf.getOctet();
+ *seq = buf.getLong();
- return h1 == 'A' && h2 == 'M' && h3 == '1';
+ return h1 == 'A' && h2 == 'M' && h3 == '2';
}
-void ManagementAgentImpl::SendBuffer (Buffer& buf,
- uint32_t length,
- string exchange,
- string routingKey)
+ManagementAgentImpl::PackageMap::iterator ManagementAgentImpl::findOrAddPackage(const string& name)
{
- Message msg;
- string data;
-
- if (objIdPrefix == 0)
- return;
-
- buf.getRawData(data, length);
- msg.getDeliveryProperties().setRoutingKey(routingKey);
- msg.getMessageProperties().setReplyTo(ReplyTo("amq.direct", queueName.str()));
- msg.setData (data);
- session.messageTransfer (arg::content=msg, arg::destination=exchange);
-}
-
-ManagementAgentImpl::PackageMap::iterator ManagementAgentImpl::FindOrAddPackage (std::string name)
-{
- PackageMap::iterator pIter = packages.find (name);
- if (pIter != packages.end ())
+ PackageMap::iterator pIter = packages.find(name);
+ if (pIter != packages.end())
return pIter;
// No such package found, create a new map entry.
- std::pair<PackageMap::iterator, bool> result =
- packages.insert (std::pair<string, ClassMap> (name, ClassMap ()));
+ pair<PackageMap::iterator, bool> result =
+ packages.insert(pair<string, ClassMap>(name, ClassMap()));
- // Publish a package-indication message
- Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
- uint32_t outLen;
+ if (connected) {
+ // Publish a package-indication message
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
- EncodeHeader (outBuffer, 'p');
- EncodePackageIndication (outBuffer, result.first);
- outLen = MA_BUFFER_SIZE - outBuffer.available ();
- outBuffer.reset ();
- SendBuffer (outBuffer, outLen, "qpid.management", "mgmt.schema.package");
+ encodeHeader(outBuffer, 'p');
+ encodePackageIndication(outBuffer, result.first);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ connThreadBody.sendBuffer(outBuffer, outLen, "qpid.management", "schema.package");
+ }
return result.first;
}
void ManagementAgentImpl::moveNewObjectsLH()
{
- Mutex::ScopedLock lock (addLock);
- for (ManagementObjectMap::iterator iter = newManagementObjects.begin ();
- iter != newManagementObjects.end ();
+ Mutex::ScopedLock lock(addLock);
+ for (ManagementObjectMap::iterator iter = newManagementObjects.begin();
+ iter != newManagementObjects.end();
iter++)
managementObjects[iter->first] = iter->second;
newManagementObjects.clear();
}
-void ManagementAgentImpl::AddClassLocal (PackageMap::iterator pIter,
- string className,
- uint8_t* md5Sum,
- management::ManagementObject::writeSchemaCall_t schemaCall)
+void ManagementAgentImpl::addClassLocal(uint8_t classKind,
+ PackageMap::iterator pIter,
+ const string& className,
+ uint8_t* md5Sum,
+ qpid::management::ManagementObject::writeSchemaCall_t schemaCall)
{
SchemaClassKey key;
ClassMap& cMap = pIter->second;
key.name = className;
- memcpy (&key.hash, md5Sum, 16);
+ memcpy(&key.hash, md5Sum, 16);
- ClassMap::iterator cIter = cMap.find (key);
- if (cIter != cMap.end ())
+ ClassMap::iterator cIter = cMap.find(key);
+ if (cIter != cMap.end())
return;
// No such class found, create a new class with local information.
- SchemaClass classInfo;
-
- classInfo.writeSchemaCall = schemaCall;
- cMap[key] = classInfo;
-
- // TODO: Publish a class-indication message
+ cMap.insert(pair<SchemaClassKey, SchemaClass>(key, SchemaClass(schemaCall, classKind)));
}
-void ManagementAgentImpl::EncodePackageIndication (Buffer& buf,
- PackageMap::iterator pIter)
+void ManagementAgentImpl::encodePackageIndication(Buffer& buf,
+ PackageMap::iterator pIter)
{
- buf.putShortString ((*pIter).first);
+ buf.putShortString((*pIter).first);
+
+ QPID_LOG(trace, "SENT PackageInd: package=" << (*pIter).first);
}
-void ManagementAgentImpl::EncodeClassIndication (Buffer& buf,
- PackageMap::iterator pIter,
- ClassMap::iterator cIter)
+void ManagementAgentImpl::encodeClassIndication(Buffer& buf,
+ PackageMap::iterator pIter,
+ ClassMap::iterator cIter)
{
SchemaClassKey key = (*cIter).first;
- buf.putShortString ((*pIter).first);
- buf.putShortString (key.name);
- buf.putBin128 (key.hash);
+ buf.putOctet((*cIter).second.kind);
+ buf.putShortString((*pIter).first);
+ buf.putShortString(key.name);
+ buf.putBin128(key.hash);
+
+ QPID_LOG(trace, "SENT ClassInd: package=" << (*pIter).first << " class=" << key.name);
}
-void ManagementAgentImpl::PeriodicProcessing()
+void ManagementAgentImpl::periodicProcessing()
{
#define BUFSIZE 65536
Mutex::ScopedLock lock(agentLock);
char msgChars[BUFSIZE];
uint32_t contentSize;
- string routingKey;
- std::list<uint64_t> deleteList;
+ list<pair<ObjectId, ManagementObject*> > deleteList;
- {
- Buffer msgBuffer(msgChars, BUFSIZE);
- EncodeHeader(msgBuffer, 'h');
- msgBuffer.putLongLong(uint64_t(Duration(now())));
+ if (!connected)
+ return;
- contentSize = BUFSIZE - msgBuffer.available ();
- msgBuffer.reset ();
- routingKey = "mgmt." + systemId.str() + ".heartbeat";
- SendBuffer (msgBuffer, contentSize, "qpid.management", routingKey);
+ moveNewObjectsLH();
+
+ //
+ // Clear the been-here flag on all objects in the map.
+ //
+ for (ManagementObjectMap::iterator iter = managementObjects.begin();
+ iter != managementObjects.end();
+ iter++) {
+ ManagementObject* object = iter->second;
+ object->setFlags(0);
+ if (clientWasAdded) {
+ object->setForcePublish(true);
+ }
}
- moveNewObjectsLH();
+ clientWasAdded = false;
+
+ //
+ // Process the entire object map.
+ //
+ for (ManagementObjectMap::iterator baseIter = managementObjects.begin();
+ baseIter != managementObjects.end();
+ baseIter++) {
+ ManagementObject* baseObject = baseIter->second;
+
+ //
+ // Skip until we find a base object requiring a sent message.
+ //
+ if (baseObject->getFlags() == 1 ||
+ (!baseObject->getConfigChanged() &&
+ !baseObject->getInstChanged() &&
+ !baseObject->getForcePublish() &&
+ !baseObject->isDeleted()))
+ continue;
- if (clientWasAdded)
- {
- clientWasAdded = false;
- for (ManagementObjectMap::iterator iter = managementObjects.begin ();
- iter != managementObjects.end ();
- iter++)
- {
+ Buffer msgBuffer(msgChars, BUFSIZE);
+ for (ManagementObjectMap::iterator iter = baseIter;
+ iter != managementObjects.end();
+ iter++) {
ManagementObject* object = iter->second;
- object->setAllChanged ();
+ if (baseObject->isSameClass(*object) && object->getFlags() == 0) {
+ object->setFlags(1);
+ if (object->getConfigChanged() || object->getInstChanged())
+ object->setUpdateTime();
+
+ if (object->getConfigChanged() || object->getForcePublish() || object->isDeleted()) {
+ encodeHeader(msgBuffer, 'c');
+ object->writeProperties(msgBuffer);
+ }
+
+ if (object->hasInst() && (object->getInstChanged() || object->getForcePublish())) {
+ encodeHeader(msgBuffer, 'i');
+ object->writeStatistics(msgBuffer);
+ }
+
+ if (object->isDeleted())
+ deleteList.push_back(pair<ObjectId, ManagementObject*>(iter->first, object));
+ object->setForcePublish(false);
+
+ if (msgBuffer.available() < (BUFSIZE / 2))
+ break;
+ }
+ }
+
+ contentSize = BUFSIZE - msgBuffer.available();
+ if (contentSize > 0) {
+ msgBuffer.reset();
+ stringstream key;
+ key << "console.obj." << assignedBrokerBank << "." << assignedAgentBank << "." <<
+ baseObject->getPackageName() << "." << baseObject->getClassName();
+ connThreadBody.sendBuffer(msgBuffer, contentSize, "qpid.management", key.str());
}
}
- if (managementObjects.empty ())
- return;
-
- for (ManagementObjectMap::iterator iter = managementObjects.begin ();
- iter != managementObjects.end ();
- iter++)
+ // Delete flagged objects
+ for (list<pair<ObjectId, ManagementObject*> >::reverse_iterator iter = deleteList.rbegin();
+ iter != deleteList.rend();
+ iter++) {
+ delete iter->second;
+ managementObjects.erase(iter->first);
+ }
+
+ deleteList.clear();
+
{
- ManagementObject* object = iter->second;
+ Buffer msgBuffer(msgChars, BUFSIZE);
+ encodeHeader(msgBuffer, 'h');
+ msgBuffer.putLongLong(uint64_t(Duration(now())));
+ stringstream key;
+ key << "console.heartbeat." << assignedBrokerBank << "." << assignedAgentBank;
- if (object->getConfigChanged () || object->isDeleted ())
- {
- Buffer msgBuffer (msgChars, BUFSIZE);
- EncodeHeader (msgBuffer, 'c');
- object->writeProperties(msgBuffer);
-
- contentSize = BUFSIZE - msgBuffer.available ();
- msgBuffer.reset ();
- routingKey = "mgmt." + systemId.str() + ".prop." + object->getClassName ();
- SendBuffer (msgBuffer, contentSize, "qpid.management", routingKey);
+ contentSize = BUFSIZE - msgBuffer.available();
+ msgBuffer.reset();
+ connThreadBody.sendBuffer(msgBuffer, contentSize, "qpid.management", key.str());
+ }
+}
+
+void ManagementAgentImpl::ConnectionThread::run()
+{
+ static const int delayMin(1);
+ static const int delayMax(128);
+ static const int delayFactor(2);
+ int delay(delayMin);
+ string dest("qmfagent");
+ ConnectionThread::shared_ptr tmp;
+
+ sessionId.generate();
+ queueName << "qmfagent-" << sessionId;
+
+ while (true) {
+ try {
+ if (agent.initialized) {
+ QPID_LOG(debug, "QMF Agent attempting to connect to the broker...");
+ connection.open(agent.connectionSettings);
+ session = connection.newSession(queueName.str());
+ subscriptions.reset(new client::SubscriptionManager(session));
+
+ session.queueDeclare(arg::queue=queueName.str(), arg::autoDelete=true,
+ arg::exclusive=true);
+ session.exchangeBind(arg::exchange="amq.direct", arg::queue=queueName.str(),
+ arg::bindingKey=queueName.str());
+
+ subscriptions->subscribe(agent, queueName.str(), dest);
+ QPID_LOG(info, "Connection established with broker");
+ {
+ Mutex::ScopedLock _lock(connLock);
+ if (shutdown)
+ return;
+ operational = true;
+ agent.startProtocol();
+ try {
+ Mutex::ScopedUnlock _unlock(connLock);
+ subscriptions->run();
+ } catch (exception) {}
+
+ QPID_LOG(warning, "Connection to the broker has been lost");
+
+ operational = false;
+ agent.connected = false;
+ tmp = subscriptions;
+ subscriptions.reset();
+ }
+ tmp.reset(); // frees the subscription outside the lock
+ delay = delayMin;
+ connection.close();
+ }
+ } catch (exception &e) {
+ if (delay < delayMax)
+ delay *= delayFactor;
+ QPID_LOG(debug, "Connection failed: exception=" << e.what());
}
-
- if (object->getInstChanged ())
+
{
- Buffer msgBuffer (msgChars, BUFSIZE);
- EncodeHeader (msgBuffer, 'i');
- object->writeStatistics(msgBuffer);
-
- contentSize = BUFSIZE - msgBuffer.available ();
- msgBuffer.reset ();
- routingKey = "mgmt." + systemId.str () + ".stat." + object->getClassName ();
- SendBuffer (msgBuffer, contentSize, "qpid.management", routingKey);
+ // sleep for "delay" seconds, but peridically check if the
+ // agent is shutting down so we don't hang for up to delayMax
+ // seconds during agent shutdown
+ Mutex::ScopedLock _lock(connLock);
+ if (shutdown)
+ return;
+ sleeping = true;
+ int totalSleep = 0;
+ do {
+ Mutex::ScopedUnlock _unlock(connLock);
+ ::sleep(delayMin);
+ totalSleep += delayMin;
+ } while (totalSleep < delay && !shutdown);
+ sleeping = false;
+ if (shutdown)
+ return;
}
+ }
+}
+
+ManagementAgentImpl::ConnectionThread::~ConnectionThread()
+{
+}
- if (object->isDeleted ())
- deleteList.push_back (iter->first);
+void ManagementAgentImpl::ConnectionThread::sendBuffer(Buffer& buf,
+ uint32_t length,
+ const string& exchange,
+ const string& routingKey)
+{
+ ConnectionThread::shared_ptr s;
+ {
+ Mutex::ScopedLock _lock(connLock);
+ if (!operational)
+ return;
+ s = subscriptions;
}
- // Delete flagged objects
- for (std::list<uint64_t>::reverse_iterator iter = deleteList.rbegin ();
- iter != deleteList.rend ();
- iter++)
- managementObjects.erase (*iter);
+ Message msg;
+ string data;
- deleteList.clear ();
+ buf.getRawData(data, length);
+ msg.getDeliveryProperties().setRoutingKey(routingKey);
+ msg.getMessageProperties().setReplyTo(ReplyTo("amq.direct", queueName.str()));
+ msg.setData(data);
+ try {
+ session.messageTransfer(arg::content=msg, arg::destination=exchange);
+ } catch(exception& e) {
+ QPID_LOG(error, "Exception caught in sendBuffer: " << e.what());
+ // Bounce the connection
+ if (s)
+ s->stop();
+ }
}
-void ManagementAgentImpl::BackgroundThread::run()
+void ManagementAgentImpl::ConnectionThread::bindToBank(uint32_t brokerBank, uint32_t agentBank)
{
- while (true) {
- ::sleep(5);
- agent.PeriodicProcessing();
+ stringstream key;
+ key << "agent." << brokerBank << "." << agentBank;
+ session.exchangeBind(arg::exchange="qpid.management", arg::queue=queueName.str(),
+ arg::bindingKey=key.str());
+}
+
+void ManagementAgentImpl::ConnectionThread::close()
+{
+ ConnectionThread::shared_ptr s;
+ {
+ Mutex::ScopedLock _lock(connLock);
+ shutdown = true;
+ s = subscriptions;
+ }
+ if (s)
+ s->stop();
+}
+
+bool ManagementAgentImpl::ConnectionThread::isSleeping() const
+{
+ Mutex::ScopedLock _lock(connLock);
+ return sleeping;
+}
+
+
+void ManagementAgentImpl::PublishThread::run()
+{
+ uint16_t totalSleep;
+
+ while (!shutdown) {
+ agent.periodicProcessing();
+ totalSleep = 0;
+ while (totalSleep++ < agent.getInterval() && !shutdown) {
+ ::sleep(1);
+ }
}
}
diff --git a/cpp/src/qpid/agent/ManagementAgentImpl.h b/cpp/src/qpid/agent/ManagementAgentImpl.h
index f7f19e145d..a876496e98 100644
--- a/cpp/src/qpid/agent/ManagementAgentImpl.h
+++ b/cpp/src/qpid/agent/ManagementAgentImpl.h
@@ -20,9 +20,10 @@
// under the License.
//
-#include "ManagementAgent.h"
+#include "qpid/agent/ManagementAgent.h"
#include "qpid/client/Connection.h"
-#include "qpid/client/Dispatcher.h"
+#include "qpid/client/ConnectionSettings.h"
+#include "qpid/client/SubscriptionManager.h"
#include "qpid/client/Session.h"
#include "qpid/client/AsyncSession.h"
#include "qpid/client/Message.h"
@@ -30,10 +31,11 @@
#include "qpid/sys/Thread.h"
#include "qpid/sys/Runnable.h"
#include "qpid/sys/Mutex.h"
-#include "qpid/sys/Condition.h"
+#include "qpid/sys/PipeHandle.h"
#include "qpid/framing/Uuid.h"
#include <iostream>
#include <sstream>
+#include <deque>
namespace qpid {
namespace management {
@@ -45,33 +47,49 @@ class ManagementAgentImpl : public ManagementAgent, public client::MessageListen
ManagementAgentImpl();
virtual ~ManagementAgentImpl();
+ //
+ // Methods from ManagementAgent
+ //
int getMaxThreads() { return 1; }
- void init(std::string brokerHost = "localhost",
- uint16_t brokerPort = 5672,
- uint16_t intervalSeconds = 10,
- bool useExternalThread = false);
- void RegisterClass(std::string packageName,
- std::string className,
- uint8_t* md5Sum,
+ void init(const std::string& brokerHost = "localhost",
+ uint16_t brokerPort = 5672,
+ uint16_t intervalSeconds = 10,
+ bool useExternalThread = false,
+ const std::string& storeFile = "",
+ const std::string& uid = "guest",
+ const std::string& pwd = "guest",
+ const std::string& mech = "PLAIN",
+ const std::string& proto = "tcp");
+ void init(const client::ConnectionSettings& settings,
+ uint16_t intervalSeconds = 10,
+ bool useExternalThread = false,
+ const std::string& storeFile = "");
+ bool isConnected() { return connected; }
+ std::string& getLastFailure() { return lastFailure; }
+ void registerClass(const std::string& packageName,
+ const std::string& className,
+ uint8_t* md5Sum,
management::ManagementObject::writeSchemaCall_t schemaCall);
- uint64_t addObject (management::ManagementObject* objectPtr,
- uint32_t persistId = 0,
- uint32_t persistBank = 4);
- uint32_t pollCallbacks (uint32_t callLimit = 0);
- int getSignalFd (void);
+ void registerEvent(const std::string& packageName,
+ const std::string& eventName,
+ uint8_t* md5Sum,
+ management::ManagementObject::writeSchemaCall_t schemaCall);
+ ObjectId addObject(management::ManagementObject* objectPtr, uint64_t persistId = 0);
+ void raiseEvent(const management::ManagementEvent& event, severity_t severity = SEV_DEFAULT);
+ uint32_t pollCallbacks(uint32_t callLimit = 0);
+ int getSignalFd();
- void PeriodicProcessing();
+ uint16_t getInterval() { return interval; }
+ void periodicProcessing();
private:
- struct SchemaClassKey
- {
+ struct SchemaClassKey {
std::string name;
uint8_t hash[16];
};
- struct SchemaClassKeyComp
- {
+ struct SchemaClassKeyComp {
bool operator() (const SchemaClassKey& lhs, const SchemaClassKey& rhs) const
{
if (lhs.name != rhs.name)
@@ -84,74 +102,137 @@ class ManagementAgentImpl : public ManagementAgent, public client::MessageListen
}
};
- struct SchemaClass
- {
+ struct SchemaClass {
management::ManagementObject::writeSchemaCall_t writeSchemaCall;
+ uint8_t kind;
- SchemaClass () : writeSchemaCall(0) {}
+ SchemaClass(const management::ManagementObject::writeSchemaCall_t call,
+ const uint8_t _kind) : writeSchemaCall(call), kind(_kind) {}
};
+ struct QueuedMethod {
+ QueuedMethod(uint32_t _seq, std::string _reply, std::string _body) :
+ sequence(_seq), replyTo(_reply), body(_body) {}
+
+ uint32_t sequence;
+ std::string replyTo;
+ std::string body;
+ };
+
+ typedef std::deque<QueuedMethod*> MethodQueue;
typedef std::map<SchemaClassKey, SchemaClass, SchemaClassKeyComp> ClassMap;
typedef std::map<std::string, ClassMap> PackageMap;
PackageMap packages;
+ AgentAttachment attachment;
management::ManagementObjectMap managementObjects;
management::ManagementObjectMap newManagementObjects;
+ MethodQueue methodQueue;
void received (client::Message& msg);
uint16_t interval;
bool extThread;
+ sys::PipeHandle* pipeHandle;
uint64_t nextObjectId;
+ std::string storeFile;
sys::Mutex agentLock;
sys::Mutex addLock;
- framing::Uuid sessionId;
framing::Uuid systemId;
+ client::ConnectionSettings connectionSettings;
+ bool initialized;
+ bool connected;
+ std::string lastFailure;
+
+ bool clientWasAdded;
+ uint32_t requestedBrokerBank;
+ uint32_t requestedAgentBank;
+ uint32_t assignedBrokerBank;
+ uint32_t assignedAgentBank;
+ uint16_t bootSequence;
+
+ static const uint8_t DEBUG_OFF = 0;
+ static const uint8_t DEBUG_CONN = 1;
+ static const uint8_t DEBUG_PROTO = 2;
+ static const uint8_t DEBUG_PUBLISH = 3;
- int signalFdIn, signalFdOut;
- client::Connection connection;
- client::Session session;
- client::Dispatcher* dispatcher;
- bool clientWasAdded;
- uint64_t objIdPrefix;
- std::stringstream queueName;
# define MA_BUFFER_SIZE 65536
char outputBuffer[MA_BUFFER_SIZE];
+ char eventBuffer[MA_BUFFER_SIZE];
- class BackgroundThread : public sys::Runnable
+ friend class ConnectionThread;
+ class ConnectionThread : public sys::Runnable
{
+ typedef boost::shared_ptr<client::SubscriptionManager> shared_ptr;
+
+ bool operational;
ManagementAgentImpl& agent;
+ framing::Uuid sessionId;
+ client::Connection connection;
+ client::Session session;
+ ConnectionThread::shared_ptr subscriptions;
+ std::stringstream queueName;
+ mutable sys::Mutex connLock;
+ bool shutdown;
+ bool sleeping;
void run();
public:
- BackgroundThread(ManagementAgentImpl& _agent) : agent(_agent) {}
+ ConnectionThread(ManagementAgentImpl& _agent) :
+ operational(false), agent(_agent),
+ shutdown(false), sleeping(false) {}
+ ~ConnectionThread();
+ void sendBuffer(qpid::framing::Buffer& buf,
+ uint32_t length,
+ const std::string& exchange,
+ const std::string& routingKey);
+ void bindToBank(uint32_t brokerBank, uint32_t agentBank);
+ void close();
+ bool isSleeping() const;
};
- BackgroundThread bgThread;
- sys::Thread thread;
- sys::Condition startupCond;
- bool startupWait;
+ class PublishThread : public sys::Runnable
+ {
+ ManagementAgentImpl& agent;
+ void run();
+ bool shutdown;
+ public:
+ PublishThread(ManagementAgentImpl& _agent) :
+ agent(_agent), shutdown(false) {}
+ void close() { shutdown = true; }
+ };
+
+ ConnectionThread connThreadBody;
+ sys::Thread connThread;
+ PublishThread pubThreadBody;
+ sys::Thread pubThread;
+
+ static const std::string storeMagicNumber;
- PackageMap::iterator FindOrAddPackage (std::string name);
+ void startProtocol();
+ void storeData(bool requested=false);
+ void retrieveData();
+ PackageMap::iterator findOrAddPackage(const std::string& name);
void moveNewObjectsLH();
- void AddClassLocal (PackageMap::iterator pIter,
- std::string className,
+ void addClassLocal (uint8_t classKind,
+ PackageMap::iterator pIter,
+ const std::string& className,
uint8_t* md5Sum,
management::ManagementObject::writeSchemaCall_t schemaCall);
- void EncodePackageIndication (qpid::framing::Buffer& buf,
+ void encodePackageIndication (framing::Buffer& buf,
PackageMap::iterator pIter);
- void EncodeClassIndication (qpid::framing::Buffer& buf,
+ void encodeClassIndication (framing::Buffer& buf,
PackageMap::iterator pIter,
ClassMap::iterator cIter);
- void EncodeHeader (qpid::framing::Buffer& buf, uint8_t opcode, uint32_t seq = 0);
- bool CheckHeader (qpid::framing::Buffer& buf, uint8_t *opcode, uint32_t *seq);
- void SendBuffer (qpid::framing::Buffer& buf,
- uint32_t length,
- std::string exchange,
- std::string routingKey);
+ void encodeHeader (framing::Buffer& buf, uint8_t opcode, uint32_t seq = 0);
+ bool checkHeader (framing::Buffer& buf, uint8_t *opcode, uint32_t *seq);
+ void sendCommandComplete (std::string replyToKey, uint32_t sequence,
+ uint32_t code = 0, std::string text = std::string("OK"));
void handleAttachResponse (qpid::framing::Buffer& inBuffer);
void handlePackageRequest (qpid::framing::Buffer& inBuffer);
void handleClassQuery (qpid::framing::Buffer& inBuffer);
void handleSchemaRequest (qpid::framing::Buffer& inBuffer, uint32_t sequence);
+ void invokeMethodRequest (qpid::framing::Buffer& inBuffer, uint32_t sequence, std::string replyTo);
+ void handleGetQuery (qpid::framing::Buffer& inBuffer, uint32_t sequence, std::string replyTo);
void handleMethodRequest (qpid::framing::Buffer& inBuffer, uint32_t sequence, std::string replyTo);
void handleConsoleAddedIndication();
};
diff --git a/cpp/src/qpid/amqp_0_10/Array.cpp b/cpp/src/qpid/amqp_0_10/Array.cpp
index 380e0f1f36..2ee47546f2 100644
--- a/cpp/src/qpid/amqp_0_10/Array.cpp
+++ b/cpp/src/qpid/amqp_0_10/Array.cpp
@@ -18,7 +18,7 @@
* under the License.
*
*/
-#include "Array.h"
+#include "qpid/amqp_0_10/Array.h"
namespace qpid {
namespace amqp_0_10 {
diff --git a/cpp/src/qpid/amqp_0_10/Codec.h b/cpp/src/qpid/amqp_0_10/Codec.h
index 5cad5cf4ed..fd006a348e 100644
--- a/cpp/src/qpid/amqp_0_10/Codec.h
+++ b/cpp/src/qpid/amqp_0_10/Codec.h
@@ -22,7 +22,7 @@
*
*/
-#include "built_in_types.h"
+#include "qpid/amqp_0_10/built_in_types.h"
#include "qpid/Serializer.h"
#include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/is_float.hpp>
diff --git a/cpp/src/qpid/amqp_0_10/Command.h b/cpp/src/qpid/amqp_0_10/Command.h
index 0fe023e520..b1d3607a84 100644
--- a/cpp/src/qpid/amqp_0_10/Command.h
+++ b/cpp/src/qpid/amqp_0_10/Command.h
@@ -22,7 +22,7 @@
*
*/
-#include "Control.h"
+#include "qpid/amqp_0_10/Control.h"
#include "qpid/amqp_0_10/structs.h"
namespace qpid {
diff --git a/cpp/src/qpid/amqp_0_10/Connection.cpp b/cpp/src/qpid/amqp_0_10/Connection.cpp
index a3692911b2..bf2e7d5713 100644
--- a/cpp/src/qpid/amqp_0_10/Connection.cpp
+++ b/cpp/src/qpid/amqp_0_10/Connection.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -18,19 +18,26 @@
* under the License.
*
*/
-#include "Connection.h"
+#include "qpid/amqp_0_10/Connection.h"
#include "qpid/log/Statement.h"
#include "qpid/amqp_0_10/exceptions.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/ProtocolInitiation.h"
namespace qpid {
namespace amqp_0_10 {
using sys::Mutex;
-Connection::Connection(sys::OutputControl& o, broker::Broker& broker, const std::string& id, bool _isClient)
- : frameQueueClosed(false), output(o),
- connection(new broker::Connection(this, broker, id, _isClient)),
- identifier(id), initialized(false), isClient(_isClient) {}
+Connection::Connection(sys::OutputControl& o, const std::string& id, bool _isClient)
+ : pushClosed(false), popClosed(false), output(o), identifier(id), initialized(false),
+ isClient(_isClient), buffered(0), version(0,10)
+{}
+
+void Connection::setInputHandler(std::auto_ptr<sys::ConnectionInputHandler> c) {
+ connection = c;
+}
size_t Connection::decode(const char* buffer, size_t size) {
framing::Buffer in(const_cast<char*>(buffer), size);
@@ -38,7 +45,9 @@ size_t Connection::decode(const char* buffer, size_t size) {
//read in protocol header
framing::ProtocolInitiation pi;
if (pi.decode(in)) {
- //TODO: check the version is correct
+ if(!(pi==version))
+ throw Exception(QPID_MSG("Unsupported version: " << pi
+ << " supported version " << version));
QPID_LOG(trace, "RECV " << identifier << " INIT(" << pi << ")");
}
initialized = true;
@@ -52,18 +61,26 @@ size_t Connection::decode(const char* buffer, size_t size) {
}
bool Connection::canEncode() {
- if (!frameQueueClosed) connection->doOutput();
Mutex::ScopedLock l(frameQueueLock);
- return (!isClient && !initialized) || !frameQueue.empty();
+ if (!popClosed) {
+ Mutex::ScopedUnlock u(frameQueueLock);
+ connection->doOutput();
+ }
+ return !popClosed && ((!isClient && !initialized) || !frameQueue.empty());
}
bool Connection::isClosed() const {
Mutex::ScopedLock l(frameQueueLock);
- return frameQueueClosed;
+ return pushClosed && popClosed;
}
size_t Connection::encode(const char* buffer, size_t size) {
- Mutex::ScopedLock l(frameQueueLock);
+ { // Swap frameQueue data into workQueue to avoid holding lock while we encode.
+ Mutex::ScopedLock l(frameQueueLock);
+ if (popClosed) return 0; // Can't pop any more frames.
+ assert(workQueue.empty());
+ workQueue.swap(frameQueue);
+ }
framing::Buffer out(const_cast<char*>(buffer), size);
if (!isClient && !initialized) {
framing::ProtocolInitiation pi(getVersion());
@@ -71,23 +88,39 @@ size_t Connection::encode(const char* buffer, size_t size) {
initialized = true;
QPID_LOG(trace, "SENT " << identifier << " INIT(" << pi << ")");
}
- while (!frameQueue.empty() && (frameQueue.front().size() <= out.available())) {
- frameQueue.front().encode(out);
- QPID_LOG(trace, "SENT [" << identifier << "]: " << frameQueue.front());
- frameQueue.pop();
+ size_t frameSize=0;
+ size_t encoded=0;
+ while (!workQueue.empty() && ((frameSize=workQueue.front().encodedSize()) <= out.available())) {
+ workQueue.front().encode(out);
+ QPID_LOG(trace, "SENT [" << identifier << "]: " << workQueue.front());
+ workQueue.pop_front();
+ encoded += frameSize;
+ if (workQueue.empty() && out.available() > 0) connection->doOutput();
+ }
+ assert(workQueue.empty() || workQueue.front().encodedSize() <= size);
+ if (!workQueue.empty() && workQueue.front().encodedSize() > size)
+ throw InternalErrorException(QPID_MSG("Frame too large for buffer."));
+ {
+ Mutex::ScopedLock l(frameQueueLock);
+ buffered -= encoded;
+ // Put back any frames we did not encode.
+ frameQueue.insert(frameQueue.begin(), workQueue.begin(), workQueue.end());
+ workQueue.clear();
+ if (frameQueue.empty() && pushClosed)
+ popClosed = true;
}
- assert(frameQueue.empty() || frameQueue.front().size() <= size);
- if (!frameQueue.empty() && frameQueue.front().size() > size)
- throw InternalErrorException(QPID_MSG("Could not write frame, too large for buffer."));
return out.getPosition();
}
-void Connection::activateOutput() { output.activateOutput(); }
+void Connection::abort() { output.abort(); }
+void Connection::activateOutput() { output.activateOutput(); }
+void Connection::giveReadCredit(int32_t credit) { output.giveReadCredit(credit); }
void Connection::close() {
- // Close the output queue.
+ // No more frames can be pushed onto the queue.
+ // Frames aleady on the queue can be popped.
Mutex::ScopedLock l(frameQueueLock);
- frameQueueClosed = true;
+ pushClosed = true;
}
void Connection::closed() {
@@ -97,14 +130,24 @@ void Connection::closed() {
void Connection::send(framing::AMQFrame& f) {
{
Mutex::ScopedLock l(frameQueueLock);
- if (!frameQueueClosed)
- frameQueue.push(f);
+ if (!pushClosed)
+ frameQueue.push_back(f);
+ buffered += f.encodedSize();
}
activateOutput();
}
framing::ProtocolVersion Connection::getVersion() const {
- return framing::ProtocolVersion(0,10);
+ return version;
+}
+
+void Connection::setVersion(const framing::ProtocolVersion& v) {
+ version = v;
+}
+
+size_t Connection::getBuffered() const {
+ Mutex::ScopedLock l(frameQueueLock);
+ return buffered;
}
}} // namespace qpid::amqp_0_10
diff --git a/cpp/src/qpid/amqp_0_10/Connection.h b/cpp/src/qpid/amqp_0_10/Connection.h
index b707031789..995d824796 100644
--- a/cpp/src/qpid/amqp_0_10/Connection.h
+++ b/cpp/src/qpid/amqp_0_10/Connection.h
@@ -10,9 +10,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -21,41 +21,61 @@
* under the License.
*
*/
+
+#include "qpid/framing/AMQFrame.h"
#include "qpid/sys/ConnectionCodec.h"
+#include "qpid/sys/ConnectionInputHandler.h"
#include "qpid/sys/ConnectionOutputHandler.h"
#include "qpid/sys/Mutex.h"
-#include "qpid/broker/Connection.h"
+#include "qpid/broker/BrokerImportExport.h"
#include <boost/intrusive_ptr.hpp>
-#include <queue>
#include <memory>
+#include <deque>
namespace qpid {
-namespace broker { class Broker; }
+
+namespace sys {
+class ConnectionInputHandlerFactory;
+}
+
namespace amqp_0_10 {
class Connection : public sys::ConnectionCodec,
public sys::ConnectionOutputHandler
{
- std::queue<framing::AMQFrame> frameQueue;
- bool frameQueueClosed;
+ typedef std::deque<framing::AMQFrame> FrameQueue;
+
+ FrameQueue frameQueue;
+ FrameQueue workQueue;
+ bool pushClosed, popClosed;
mutable sys::Mutex frameQueueLock;
sys::OutputControl& output;
- boost::intrusive_ptr<broker::Connection> connection;
+ std::auto_ptr<sys::ConnectionInputHandler> connection;
std::string identifier;
bool initialized;
bool isClient;
-
+ size_t buffered;
+ framing::ProtocolVersion version;
+
public:
- Connection(sys::OutputControl&, broker::Broker&, const std::string& id, bool isClient = false);
+ QPID_BROKER_EXTERN Connection(sys::OutputControl&, const std::string& id, bool isClient);
+ QPID_BROKER_EXTERN void setInputHandler(std::auto_ptr<sys::ConnectionInputHandler> c);
size_t decode(const char* buffer, size_t size);
size_t encode(const char* buffer, size_t size);
bool isClosed() const;
bool canEncode();
+ void abort();
void activateOutput();
+ void giveReadCredit(int32_t);
void closed(); // connection closed by peer.
void close(); // closing from this end.
void send(framing::AMQFrame&);
framing::ProtocolVersion getVersion() const;
+ size_t getBuffered() const;
+
+ /** Used by cluster code to set a special version on "update" connections. */
+ // FIXME aconway 2009-07-30: find a cleaner mechanism for this.
+ void setVersion(const framing::ProtocolVersion&);
};
}} // namespace qpid::amqp_0_10
diff --git a/cpp/src/qpid/amqp_0_10/Control.h b/cpp/src/qpid/amqp_0_10/Control.h
index 226f6f92a6..ce188ae6d8 100644
--- a/cpp/src/qpid/amqp_0_10/Control.h
+++ b/cpp/src/qpid/amqp_0_10/Control.h
@@ -22,7 +22,7 @@
*
*/
-#include "Struct.h"
+#include "qpid/amqp_0_10/Struct.h"
namespace qpid {
namespace amqp_0_10 {
diff --git a/cpp/src/qpid/amqp_0_10/Exception.h b/cpp/src/qpid/amqp_0_10/Exception.h
index 4841d91215..6d526c1706 100644
--- a/cpp/src/qpid/amqp_0_10/Exception.h
+++ b/cpp/src/qpid/amqp_0_10/Exception.h
@@ -32,12 +32,12 @@ namespace amqp_0_10 {
* Raised when the connection is unexpectedly closed. Sessions with
* non-0 timeout may be available for re-attachment on another connection.
*/
-struct ConnectionException : public qpid::ConnectionException {
+struct ConnectionException : public qpid::Exception {
// FIXME aconway 2008-04-04: Merge qpid::ConnectionException
// into this when the old code is removed.
typedef connection::CloseCode Code;
ConnectionException(Code c, const std::string m)
- : qpid::ConnectionException(c,m), code(c) {}
+ : qpid::Exception(m), code(c) {}
Code code;
};
@@ -45,10 +45,10 @@ struct ConnectionException : public qpid::ConnectionException {
* Raised when a session is unexpectedly detached for any reason, or
* if an attempt is made to use a session that is not attached.
*/
-struct SessionException : public qpid::SessionException {
+struct SessionException : public qpid::Exception {
// FIXME aconway 2008-04-04: should not have a code at this level.
// Leave in place till old preview code is gone.
- SessionException(int code, const std::string& msg) : qpid::SessionException(code, msg) {}
+ SessionException(int /*code*/, const std::string& msg) : qpid::Exception(msg) {}
};
/** Raised when the state of a session has been destroyed */
@@ -94,93 +94,3 @@ struct SessionDetachedException : public SessionException {
}} // namespace qpid::amqp_0_10
#endif /*!QPID_AMQP_0_10_EXCEPTION_H*/
-#ifndef QPID_AMQP_0_10_EXCEPTION_H
-#define QPID_AMQP_0_10_EXCEPTION_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/Exception.h"
-#include "qpid/amqp_0_10/specification_fwd.h"
-
-namespace qpid {
-namespace amqp_0_10 {
-
-/**
- * Raised when the connection is unexpectedly closed. Sessions with
- * non-0 timeout may be available for re-attachment on another connection.
- */
-struct ConnectionException : public Exception {
- typedef connection::CloseCode Code;
- ConnectionException(Code c, const std::string m)
- : Exception(m), code(c) {}
- Code code;
-};
-
-/**
- * Raised when a session is unexpectedly detached for any reason, or
- * if an attempt is made to use a session that is not attached.
- */
-struct SessionException : public Exception {
- SessionException(const std::string& msg) : Exception(msg) {}
-};
-
-/** Raised when the state of a session has been destroyed */
-struct SessionDestroyedException : public SessionException {
- SessionDestroyedException(const std::string& msg) : SessionException(msg){}
-};
-
-/** Raised when a session is destroyed due to an execution.exception */
-struct SessionAbortedException : public SessionDestroyedException {
- typedef execution::ErrorCode Code;
- SessionAbortedException(Code c, const std::string m)
- : SessionDestroyedException(m), code(c) {}
- Code code;
-};
-
-/**
- * Raised when a session with 0 timeout is unexpectedly detached
- * and therefore expires and is destroyed.
- */
-struct SessionExpiredException : public SessionDestroyedException {
- typedef session::DetachCode Code;
- SessionExpiredException(Code c, const std::string m)
- : SessionDestroyedException(m), code(c) {}
- Code code;
-};
-
-/**
- * Raised when a session with non-0 timeout is unexpectedly detached
- * or if an attempt is made to use a session that is not attached.
- *
- * The session is not necessarily destroyed, it may be possible to
- * re-attach.
- */
-struct SessionDetachedException : public SessionException {
- typedef session::DetachCode Code;
- SessionDetachedException(Code c, const std::string m)
- : SessionException(m), code(c) {}
- Code code;
-};
-
-}} // namespace qpid::amqp_0_10
-
-#endif /*!QPID_AMQP_0_10_EXCEPTION_H*/
diff --git a/cpp/src/qpid/amqp_0_10/FrameHeader.cpp b/cpp/src/qpid/amqp_0_10/FrameHeader.cpp
index f1a59b9e27..371e3c1bcb 100644
--- a/cpp/src/qpid/amqp_0_10/FrameHeader.cpp
+++ b/cpp/src/qpid/amqp_0_10/FrameHeader.cpp
@@ -18,7 +18,7 @@
* under the License.
*
*/
-#include "FrameHeader.h"
+#include "qpid/amqp_0_10/FrameHeader.h"
#include <ios>
#include <iomanip>
#include <ostream>
diff --git a/cpp/src/qpid/amqp_0_10/Header.cpp b/cpp/src/qpid/amqp_0_10/Header.cpp
index 669c960e7f..d83814e969 100644
--- a/cpp/src/qpid/amqp_0_10/Header.cpp
+++ b/cpp/src/qpid/amqp_0_10/Header.cpp
@@ -18,7 +18,7 @@
* under the License.
*
*/
-#include "Header.h"
+#include "qpid/amqp_0_10/Header.h"
namespace qpid {
namespace amqp_0_10 {
diff --git a/cpp/src/qpid/amqp_0_10/Holder.h b/cpp/src/qpid/amqp_0_10/Holder.h
index 8712db6c86..605d2e0ed5 100644
--- a/cpp/src/qpid/amqp_0_10/Holder.h
+++ b/cpp/src/qpid/amqp_0_10/Holder.h
@@ -22,7 +22,7 @@
*
*/
#include "qpid/framing/Blob.h"
-#include "apply.h"
+#include "qpid/amqp_0_10/apply.h"
namespace qpid {
namespace amqp_0_10 {
diff --git a/cpp/src/qpid/amqp_0_10/Map.cpp b/cpp/src/qpid/amqp_0_10/Map.cpp
index b517b8baba..af3b302d25 100644
--- a/cpp/src/qpid/amqp_0_10/Map.cpp
+++ b/cpp/src/qpid/amqp_0_10/Map.cpp
@@ -18,7 +18,7 @@
* under the License.
*
*/
-#include "Map.h"
+#include "qpid/amqp_0_10/Map.h"
#include "qpid/amqp_0_10/Struct32.h"
#include "qpid/amqp_0_10/Array.h"
#include <ostream>
diff --git a/cpp/src/qpid/amqp_0_10/SessionHandler.cpp b/cpp/src/qpid/amqp_0_10/SessionHandler.cpp
index 35587940e5..5f97d292bc 100644
--- a/cpp/src/qpid/amqp_0_10/SessionHandler.cpp
+++ b/cpp/src/qpid/amqp_0_10/SessionHandler.cpp
@@ -19,10 +19,11 @@
*/
-#include "SessionHandler.h"
+#include "qpid/amqp_0_10/SessionHandler.h"
#include "qpid/SessionState.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/framing/AllInvoker.h"
+#include "qpid/framing/enum.h"
#include "qpid/log/Statement.h"
@@ -33,30 +34,35 @@ namespace amqp_0_10 {
using namespace framing;
using namespace std;
+void SessionHandler::checkAttached() {
+ if (!getState())
+ throw NotAttachedException(QPID_MSG("Channel " << channel.get() << " is not attached"));
+}
+
SessionHandler::SessionHandler(FrameHandler* out, ChannelId ch)
- : channel(ch, out), peer(channel), ignoring(false), sendReady(), receiveReady() {}
+ : channel(ch, out), peer(channel),
+ awaitingDetached(false),
+ sendReady(), receiveReady() {}
SessionHandler::~SessionHandler() {}
namespace {
bool isSessionControl(AMQMethodBody* m) {
- return m &&
- m->amqpClassId() == SESSION_CLASS_ID;
+ return m && m->amqpClassId() == SESSION_CLASS_ID;
}
-bool isSessionDetachedControl(AMQMethodBody* m) {
- return isSessionControl(m) &&
- m->amqpMethodId() == SESSION_DETACHED_METHOD_ID;
-}
-} // namespace
-void SessionHandler::checkAttached() {
- if (!getState())
- throw NotAttachedException(
- QPID_MSG("Channel " << channel.get() << " is not attached"));
- assert(getInHandler());
- assert(channel.next);
+session::DetachCode convert(uint8_t code) {
+ switch(code) {
+ case 0: return session::DETACH_CODE_NORMAL;
+ case 1: return session::DETACH_CODE_SESSION_BUSY;
+ case 2: return session::DETACH_CODE_TRANSPORT_BUSY;
+ case 3: return session::DETACH_CODE_NOT_ATTACHED;
+ case 4: default: return session::DETACH_CODE_UNKNOWN_IDS;
+ }
}
+} // namespace
+
void SessionHandler::invoke(const AMQMethodBody& m) {
framing::invoke(*this, m);
}
@@ -65,12 +71,19 @@ void SessionHandler::handleIn(AMQFrame& f) {
// Note on channel states: a channel is attached if session != 0
AMQMethodBody* m = f.getBody()->getMethod();
try {
- if (ignoring && !isSessionDetachedControl(m))
- return;
- else if (isSessionControl(m))
+ // Ignore all but detach controls while awaiting detach
+ if (awaitingDetached) {
+ if (!isSessionControl(m)) return;
+ if (m->amqpMethodId() != SESSION_DETACH_METHOD_ID &&
+ m->amqpMethodId() != SESSION_DETACHED_METHOD_ID)
+ return;
+ }
+ if (isSessionControl(m)) {
invoke(*m);
+ }
else {
- checkAttached();
+ // Drop frames if we are detached.
+ if (!getState()) return;
if (!receiveReady)
throw IllegalStateException(QPID_MSG(getState()->getId() << ": Not ready to receive data"));
if (!getState()->receiverRecord(f))
@@ -80,11 +93,21 @@ void SessionHandler::handleIn(AMQFrame& f) {
getInHandler()->handle(f);
}
}
+ catch(const SessionException& e) {
+ QPID_LOG(error, "Execution exception: " << e.what());
+ executionException(e.code, e.what()); // Let subclass handle this first.
+ framing::AMQP_AllProxy::Execution execution(channel);
+ AMQMethodBody* m = f.getMethod();
+ SequenceNumber commandId;
+ if (getState()) commandId = getState()->receiverGetCurrent();
+ execution.exception(e.code, commandId, m ? m->amqpClassId() : 0, m ? m->amqpMethodId() : 0, 0, e.what(), FieldTable());
+ detaching();
+ sendDetach();
+ }
catch(const ChannelException& e){
QPID_LOG(error, "Channel exception: " << e.what());
- if (getState())
- peer.detached(getState()->getId().getName(), e.code);
- channelException(e.code, e.getMessage());
+ channelException(e.code, e.what()); // Let subclass handle this first.
+ peer.detached(name, e.code);
}
catch(const ConnectionException& e) {
QPID_LOG(error, "Connection exception: " << e.what());
@@ -92,16 +115,16 @@ void SessionHandler::handleIn(AMQFrame& f) {
}
catch(const std::exception& e) {
QPID_LOG(error, "Unexpected exception: " << e.what());
- connectionException(connection::FRAMING_ERROR, e.what());
+ connectionException(connection::CLOSE_CODE_FRAMING_ERROR, e.what());
}
}
namespace {
bool isControl(const AMQFrame& f) {
- return f.getMethod() && f.getMethod()->type() == framing::CONTROL;
+ return f.getMethod() && f.getMethod()->type() == framing::SEGMENT_TYPE_CONTROL;
}
bool isCommand(const AMQFrame& f) {
- return f.getMethod() && f.getMethod()->type() == framing::COMMAND;
+ return f.getMethod() && f.getMethod()->type() == framing::SEGMENT_TYPE_COMMAND;
}
} // namespace
@@ -117,19 +140,15 @@ void SessionHandler::handleOut(AMQFrame& f) {
channel.handle(f);
}
-void SessionHandler::checkName(const std::string& name) {
- checkAttached();
- if (name != getState()->getId().getName())
- throw InvalidArgumentException(
- QPID_MSG("Incorrect session name: " << name
- << ", expecting: " << getState()->getId().getName()));
-}
-
-void SessionHandler::attach(const std::string& name, bool force) {
+void SessionHandler::attach(const std::string& name_, bool force) {
+ // Save the name for possible session-busy exception. Session-busy
+ // can be thrown before we have attached the handler to a valid
+ // SessionState, and in that case we need the name to send peer.detached
+ name = name_;
if (getState() && name == getState()->getId().getName())
return; // Idempotent
if (getState())
- throw SessionBusyException(
+ throw TransportBusyException(
QPID_MSG("Channel " << channel.get() << " already attached to " << getState()->getId()));
setState(name, force);
QPID_LOG(debug, "Attached channel " << channel.get() << " to " << getState()->getId());
@@ -140,21 +159,30 @@ void SessionHandler::attach(const std::string& name, bool force) {
sendCommandPoint(getState()->senderGetCommandPoint());
}
+#define CHECK_NAME(NAME, MSG) do { \
+ checkAttached(); \
+ if (NAME != getState()->getId().getName()) \
+ throw InvalidArgumentException( \
+ QPID_MSG(MSG << ": incorrect session name: " << NAME \
+ << ", expecting: " << getState()->getId().getName())); \
+ } while(0)
+
+
void SessionHandler::attached(const std::string& name) {
- checkName(name);
+ CHECK_NAME(name, "session.attached");
}
void SessionHandler::detach(const std::string& name) {
- checkName(name);
- peer.detached(name, session::NORMAL);
+ CHECK_NAME(name, "session.detach");
+ peer.detached(name, session::DETACH_CODE_NORMAL);
handleDetach();
}
void SessionHandler::detached(const std::string& name, uint8_t code) {
- checkName(name);
- ignoring = false;
- if (code != session::NORMAL)
- channelException(code, "session.detached from peer.");
+ CHECK_NAME(name, "session.detached");
+ awaitingDetached = false;
+ if (code != session::DETACH_CODE_NORMAL)
+ channelException(convert(code), "session.detached from peer.");
else {
handleDetach();
}
@@ -247,7 +275,7 @@ void SessionHandler::gap(const SequenceSet& /*commands*/) {
void SessionHandler::sendDetach()
{
checkAttached();
- ignoring = true;
+ awaitingDetached = true;
peer.detach(getState()->getId().getName());
}
@@ -258,7 +286,6 @@ void SessionHandler::sendCompletion() {
}
void SessionHandler::sendAttach(bool force) {
- checkAttached();
QPID_LOG(debug, "SessionHandler::sendAttach attach id=" << getState()->getId());
peer.attach(getState()->getId().getName(), force);
if (getState()->hasState())
@@ -275,6 +302,12 @@ void SessionHandler::sendCommandPoint(const SessionPoint& point) {
}
}
+void SessionHandler::markReadyToSend() {
+ if (!sendReady) {
+ sendReady = true;
+ }
+}
+
void SessionHandler::sendTimeout(uint32_t t) {
checkAttached();
peer.requestTimeout(t);
diff --git a/cpp/src/qpid/amqp_0_10/SessionHandler.h b/cpp/src/qpid/amqp_0_10/SessionHandler.h
index ccbe597bfc..fa6e6f4af6 100644
--- a/cpp/src/qpid/amqp_0_10/SessionHandler.h
+++ b/cpp/src/qpid/amqp_0_10/SessionHandler.h
@@ -26,6 +26,7 @@
#include "qpid/framing/AMQP_AllProxy.h"
#include "qpid/framing/AMQP_AllOperations.h"
#include "qpid/SessionState.h"
+#include "qpid/CommonImportExport.h"
namespace qpid {
@@ -43,10 +44,8 @@ class SessionHandler : public framing::AMQP_AllOperations::SessionHandler,
public framing::FrameHandler::InOutHandler
{
public:
- typedef framing::AMQP_AllProxy::Session Peer;
-
- SessionHandler(framing::FrameHandler* out=0, uint16_t channel=0);
- ~SessionHandler();
+ QPID_COMMON_EXTERN SessionHandler(framing::FrameHandler* out=0, uint16_t channel=0);
+ QPID_COMMON_EXTERN ~SessionHandler();
void setChannel(uint16_t ch) { channel = ch; }
uint16_t getChannel() const { return channel.get(); }
@@ -57,58 +56,60 @@ class SessionHandler : public framing::AMQP_AllOperations::SessionHandler,
virtual framing::FrameHandler* getInHandler() = 0;
// Non-protocol methods, called locally to initiate some action.
- void sendDetach();
- void sendCompletion();
- void sendAttach(bool force);
- void sendTimeout(uint32_t t);
- void sendFlush();
+ QPID_COMMON_EXTERN void sendDetach();
+ QPID_COMMON_EXTERN void sendCompletion();
+ QPID_COMMON_EXTERN void sendAttach(bool force);
+ QPID_COMMON_EXTERN void sendTimeout(uint32_t t);
+ QPID_COMMON_EXTERN void sendFlush();
+ QPID_COMMON_EXTERN void markReadyToSend();//TODO: only needed for inter-broker bridge; cleanup
/** True if the handler is ready to send and receive */
bool ready() const;
// Protocol methods
- void attach(const std::string& name, bool force);
- void attached(const std::string& name);
- void detach(const std::string& name);
- void detached(const std::string& name, uint8_t code);
-
- void requestTimeout(uint32_t t);
- void timeout(uint32_t t);
-
- void commandPoint(const framing::SequenceNumber& id, uint64_t offset);
- void expected(const framing::SequenceSet& commands, const framing::Array& fragments);
- void confirmed(const framing::SequenceSet& commands,const framing::Array& fragments);
- void completed(const framing::SequenceSet& commands, bool timelyReply);
- void knownCompleted(const framing::SequenceSet& commands);
- void flush(bool expected, bool confirmed, bool completed);
- void gap(const framing::SequenceSet& commands);
+ QPID_COMMON_EXTERN void attach(const std::string& name, bool force);
+ QPID_COMMON_EXTERN void attached(const std::string& name);
+ QPID_COMMON_EXTERN void detach(const std::string& name);
+ QPID_COMMON_EXTERN void detached(const std::string& name, uint8_t code);
+
+ QPID_COMMON_EXTERN void requestTimeout(uint32_t t);
+ QPID_COMMON_EXTERN void timeout(uint32_t t);
+
+ QPID_COMMON_EXTERN void commandPoint(const framing::SequenceNumber& id, uint64_t offset);
+ QPID_COMMON_EXTERN void expected(const framing::SequenceSet& commands, const framing::Array& fragments);
+ QPID_COMMON_EXTERN void confirmed(const framing::SequenceSet& commands,const framing::Array& fragments);
+ QPID_COMMON_EXTERN void completed(const framing::SequenceSet& commands, bool timelyReply);
+ QPID_COMMON_EXTERN void knownCompleted(const framing::SequenceSet& commands);
+ QPID_COMMON_EXTERN void flush(bool expected, bool confirmed, bool completed);
+ QPID_COMMON_EXTERN void gap(const framing::SequenceSet& commands);
protected:
- virtual void invoke(const framing::AMQMethodBody& m);
+ QPID_COMMON_EXTERN virtual void invoke(const framing::AMQMethodBody& m);
virtual void setState(const std::string& sessionName, bool force) = 0;
- virtual void channelException(uint16_t code, const std::string& msg) = 0;
- virtual void connectionException(uint16_t code, const std::string& msg) = 0;
-
+ virtual void connectionException(framing::connection::CloseCode code, const std::string& msg) = 0;
+ virtual void channelException(framing::session::DetachCode, const std::string& msg) = 0;
+ virtual void executionException(framing::execution::ErrorCode, const std::string& msg) = 0;
+ virtual void detaching() = 0;
// Notification of events
virtual void readyToSend() {}
virtual void readyToReceive() {}
- virtual void handleDetach();
- virtual void handleIn(framing::AMQFrame&);
- virtual void handleOut(framing::AMQFrame&);
-
- void checkAttached();
- void checkName(const std::string& name);
+ QPID_COMMON_EXTERN virtual void handleDetach();
+ QPID_COMMON_EXTERN virtual void handleIn(framing::AMQFrame&);
+ QPID_COMMON_EXTERN virtual void handleOut(framing::AMQFrame&);
framing::ChannelHandler channel;
- Peer peer;
- bool ignoring;
- bool sendReady, receiveReady;
private:
+ void checkAttached();
void sendCommandPoint(const SessionPoint&);
+
+ framing::AMQP_AllProxy::Session peer;
+ std::string name;
+ bool awaitingDetached;
+ bool sendReady, receiveReady;
};
}} // namespace qpid::amqp_0_10
diff --git a/cpp/src/qpid/amqp_0_10/Struct.h b/cpp/src/qpid/amqp_0_10/Struct.h
index c0cea09c60..29ece84f6e 100644
--- a/cpp/src/qpid/amqp_0_10/Struct.h
+++ b/cpp/src/qpid/amqp_0_10/Struct.h
@@ -22,7 +22,7 @@
*
*/
-#include "built_in_types.h"
+#include "qpid/amqp_0_10/built_in_types.h"
#include <iosfwd>
namespace qpid {
diff --git a/cpp/src/qpid/amqp_0_10/Struct32.cpp b/cpp/src/qpid/amqp_0_10/Struct32.cpp
index 541f02bcc4..2d38c09c21 100644
--- a/cpp/src/qpid/amqp_0_10/Struct32.cpp
+++ b/cpp/src/qpid/amqp_0_10/Struct32.cpp
@@ -18,7 +18,7 @@
*
*/
-#include "Struct32.h"
+#include "qpid/amqp_0_10/Struct32.h"
namespace qpid {
namespace amqp_0_10 {
diff --git a/cpp/src/qpid/amqp_0_10/Unit.cpp b/cpp/src/qpid/amqp_0_10/Unit.cpp
index 75ea1c1b30..381de76dcc 100644
--- a/cpp/src/qpid/amqp_0_10/Unit.cpp
+++ b/cpp/src/qpid/amqp_0_10/Unit.cpp
@@ -18,8 +18,8 @@
* under the License.
*
*/
-#include "Unit.h"
-#include "Codec.h"
+#include "qpid/amqp_0_10/Unit.h"
+#include "qpid/amqp_0_10/Codec.h"
namespace qpid {
namespace amqp_0_10 {
diff --git a/cpp/src/qpid/amqp_0_10/UnknownType.cpp b/cpp/src/qpid/amqp_0_10/UnknownType.cpp
index 844891d732..cd45dd76db 100644
--- a/cpp/src/qpid/amqp_0_10/UnknownType.cpp
+++ b/cpp/src/qpid/amqp_0_10/UnknownType.cpp
@@ -18,7 +18,7 @@
* under the License.
*
*/
-#include "UnknownType.h"
+#include "qpid/amqp_0_10/UnknownType.h"
#include <boost/range/iterator_range.hpp>
#include <ostream>
diff --git a/cpp/src/qpid/amqp_0_10/UnknownType.h b/cpp/src/qpid/amqp_0_10/UnknownType.h
index 1e4aa04bf4..77498871b3 100644
--- a/cpp/src/qpid/amqp_0_10/UnknownType.h
+++ b/cpp/src/qpid/amqp_0_10/UnknownType.h
@@ -21,9 +21,9 @@
* under the License.
*
*/
+#include "qpid/sys/IntegerTypes.h"
#include <vector>
#include <iosfwd>
-#include <stdint.h>
namespace qpid {
namespace amqp_0_10 {
diff --git a/cpp/src/qpid/amqp_0_10/built_in_types.h b/cpp/src/qpid/amqp_0_10/built_in_types.h
index 7665d91736..e95d1cf3e9 100644
--- a/cpp/src/qpid/amqp_0_10/built_in_types.h
+++ b/cpp/src/qpid/amqp_0_10/built_in_types.h
@@ -23,15 +23,15 @@
#include "qpid/Serializer.h"
#include "qpid/framing/Uuid.h"
+#include "qpid/sys/IntegerTypes.h"
#include "qpid/sys/Time.h"
-#include "Decimal.h"
-#include "SerializableString.h"
+#include "qpid/amqp_0_10/Decimal.h"
+#include "qpid/amqp_0_10/SerializableString.h"
#include <boost/array.hpp>
#include <boost/range/iterator_range.hpp>
#include <string>
#include <ostream>
#include <vector>
-#include <stdint.h>
/**@file Mapping from built-in AMQP types to C++ types */
@@ -145,7 +145,6 @@ typedef framing::SequenceSet SequenceSet;
// Forward declare class types.
class Map;
class Struct32;
-class List;
class UnknownType;
template <class T> struct ArrayDomain;
diff --git a/cpp/src/qpid/assert.cpp b/cpp/src/qpid/assert.cpp
index 5d039da528..bf36d3be86 100644
--- a/cpp/src/qpid/assert.cpp
+++ b/cpp/src/qpid/assert.cpp
@@ -35,7 +35,7 @@ void assert_fail(char const * expr, char const * function, char const * file, lo
#ifdef NDEBUG
throw framing::InternalErrorException(msg.str());
#else
- std::cerr << msg << std::endl;
+ std::cerr << msg.str() << std::endl;
abort();
#endif
}
diff --git a/cpp/src/qpid/broker/AclModule.h b/cpp/src/qpid/broker/AclModule.h
index f766978d18..2f4f7eaacc 100644
--- a/cpp/src/qpid/broker/AclModule.h
+++ b/cpp/src/qpid/broker/AclModule.h
@@ -21,20 +21,30 @@
*/
-
-#include "qpid/shared_ptr.h"
#include "qpid/RefCounted.h"
+#include <boost/shared_ptr.hpp>
#include <map>
+#include <set>
#include <string>
-
+#include <sstream>
namespace qpid {
-namespace acl{
-enum ObjectType {QUEUE,EXCHANGE,BROKER,LINK,ROUTE};
-enum Action {CONSUME,PUBLISH,CREATE,ACCESS,BIND,UNBIND,DELETE,PURGE,UPDATE};
-enum AclResult {ALLOW,ALLOWLOG,DENY,DENYNOLOG};
-}
+namespace acl {
+
+enum ObjectType {OBJ_QUEUE, OBJ_EXCHANGE, OBJ_BROKER, OBJ_LINK,
+ OBJ_METHOD, OBJECTSIZE}; // OBJECTSIZE must be last in list
+enum Action {ACT_CONSUME, ACT_PUBLISH, ACT_CREATE, ACT_ACCESS, ACT_BIND,
+ ACT_UNBIND, ACT_DELETE, ACT_PURGE, ACT_UPDATE,
+ ACTIONSIZE}; // ACTIONSIZE must be last in list
+enum Property {PROP_NAME, PROP_DURABLE, PROP_OWNER, PROP_ROUTINGKEY,
+ PROP_PASSIVE, PROP_AUTODELETE, PROP_EXCLUSIVE, PROP_TYPE,
+ PROP_ALTERNATE, PROP_QUEUENAME, PROP_SCHEMAPACKAGE,
+ PROP_SCHEMACLASS, PROP_POLICYTYPE, PROP_MAXQUEUESIZE,
+ PROP_MAXQUEUECOUNT};
+enum AclResult {ALLOW, ALLOWLOG, DENY, DENYLOG};
+
+} // namespace acl
namespace broker {
@@ -47,17 +57,225 @@ public:
// effienty turn off ACL on message transfer.
virtual bool doTransferAcl()=0;
- virtual bool authorise(std::string id, acl::Action action, acl::ObjectType objType, std::string name,
- std::map<std::string, std::string>* params)=0;
- virtual bool authorise(std::string id, acl::Action action, acl::ObjectType objType, std::string ExchangeName,
- std::string RoutingKey)=0;
+ virtual bool authorise(const std::string& id, const acl::Action& action, const acl::ObjectType& objType, const std::string& name,
+ std::map<acl::Property, std::string>* params=0)=0;
+ virtual bool authorise(const std::string& id, const acl::Action& action, const acl::ObjectType& objType, const std::string& ExchangeName,
+ const std::string& RoutingKey)=0;
// create specilied authorise methods for cases that need faster matching as needed.
virtual ~AclModule() {};
};
+} // namespace broker
+
+namespace acl {
+
+class AclHelper {
+ private:
+ AclHelper(){}
+ public:
+ static inline ObjectType getObjectType(const std::string& str) {
+ if (str.compare("queue") == 0) return OBJ_QUEUE;
+ if (str.compare("exchange") == 0) return OBJ_EXCHANGE;
+ if (str.compare("broker") == 0) return OBJ_BROKER;
+ if (str.compare("link") == 0) return OBJ_LINK;
+ if (str.compare("method") == 0) return OBJ_METHOD;
+ throw str;
+ }
+ static inline std::string getObjectTypeStr(const ObjectType o) {
+ switch (o) {
+ case OBJ_QUEUE: return "queue";
+ case OBJ_EXCHANGE: return "exchange";
+ case OBJ_BROKER: return "broker";
+ case OBJ_LINK: return "link";
+ case OBJ_METHOD: return "method";
+ default: assert(false); // should never get here
+ }
+ return "";
+ }
+ static inline Action getAction(const std::string& str) {
+ if (str.compare("consume") == 0) return ACT_CONSUME;
+ if (str.compare("publish") == 0) return ACT_PUBLISH;
+ if (str.compare("create") == 0) return ACT_CREATE;
+ if (str.compare("access") == 0) return ACT_ACCESS;
+ if (str.compare("bind") == 0) return ACT_BIND;
+ if (str.compare("unbind") == 0) return ACT_UNBIND;
+ if (str.compare("delete") == 0) return ACT_DELETE;
+ if (str.compare("purge") == 0) return ACT_PURGE;
+ if (str.compare("update") == 0) return ACT_UPDATE;
+ throw str;
+ }
+ static inline std::string getActionStr(const Action a) {
+ switch (a) {
+ case ACT_CONSUME: return "consume";
+ case ACT_PUBLISH: return "publish";
+ case ACT_CREATE: return "create";
+ case ACT_ACCESS: return "access";
+ case ACT_BIND: return "bind";
+ case ACT_UNBIND: return "unbind";
+ case ACT_DELETE: return "delete";
+ case ACT_PURGE: return "purge";
+ case ACT_UPDATE: return "update";
+ default: assert(false); // should never get here
+ }
+ return "";
+ }
+ static inline Property getProperty(const std::string& str) {
+ if (str.compare("name") == 0) return PROP_NAME;
+ if (str.compare("durable") == 0) return PROP_DURABLE;
+ if (str.compare("owner") == 0) return PROP_OWNER;
+ if (str.compare("routingkey") == 0) return PROP_ROUTINGKEY;
+ if (str.compare("passive") == 0) return PROP_PASSIVE;
+ if (str.compare("autodelete") == 0) return PROP_AUTODELETE;
+ if (str.compare("exclusive") == 0) return PROP_EXCLUSIVE;
+ if (str.compare("type") == 0) return PROP_TYPE;
+ if (str.compare("alternate") == 0) return PROP_ALTERNATE;
+ if (str.compare("queuename") == 0) return PROP_QUEUENAME;
+ if (str.compare("schemapackage") == 0) return PROP_SCHEMAPACKAGE;
+ if (str.compare("schemaclass") == 0) return PROP_SCHEMACLASS;
+ if (str.compare("policytype") == 0) return PROP_POLICYTYPE;
+ if (str.compare("maxqueuesize") == 0) return PROP_MAXQUEUESIZE;
+ if (str.compare("maxqueuecount") == 0) return PROP_MAXQUEUECOUNT;
+ throw str;
+ }
+ static inline std::string getPropertyStr(const Property p) {
+ switch (p) {
+ case PROP_NAME: return "name";
+ case PROP_DURABLE: return "durable";
+ case PROP_OWNER: return "owner";
+ case PROP_ROUTINGKEY: return "routingkey";
+ case PROP_PASSIVE: return "passive";
+ case PROP_AUTODELETE: return "autodelete";
+ case PROP_EXCLUSIVE: return "exclusive";
+ case PROP_TYPE: return "type";
+ case PROP_ALTERNATE: return "alternate";
+ case PROP_QUEUENAME: return "queuename";
+ case PROP_SCHEMAPACKAGE: return "schemapackage";
+ case PROP_SCHEMACLASS: return "schemaclass";
+ case PROP_POLICYTYPE: return "policytype";
+ case PROP_MAXQUEUESIZE: return "maxqueuesize";
+ case PROP_MAXQUEUECOUNT: return "maxqueuecount";
+ default: assert(false); // should never get here
+ }
+ return "";
+ }
+ static inline AclResult getAclResult(const std::string& str) {
+ if (str.compare("allow") == 0) return ALLOW;
+ if (str.compare("allow-log") == 0) return ALLOWLOG;
+ if (str.compare("deny") == 0) return DENY;
+ if (str.compare("deny-log") == 0) return DENYLOG;
+ throw str;
+ }
+ static inline std::string getAclResultStr(const AclResult r) {
+ switch (r) {
+ case ALLOW: return "allow";
+ case ALLOWLOG: return "allow-log";
+ case DENY: return "deny";
+ case DENYLOG: return "deny-log";
+ default: assert(false); // should never get here
+ }
+ return "";
+ }
+
+ typedef std::set<Property> propSet;
+ typedef boost::shared_ptr<propSet> propSetPtr;
+ typedef std::pair<Action, propSetPtr> actionPair;
+ typedef std::map<Action, propSetPtr> actionMap;
+ typedef boost::shared_ptr<actionMap> actionMapPtr;
+ typedef std::pair<ObjectType, actionMapPtr> objectPair;
+ typedef std::map<ObjectType, actionMapPtr> objectMap;
+ typedef objectMap::const_iterator omCitr;
+ typedef boost::shared_ptr<objectMap> objectMapPtr;
+ typedef std::map<Property, std::string> propMap;
+ typedef propMap::const_iterator propMapItr;
+
+ // This map contains the legal combinations of object/action/properties found in an ACL file
+ static void loadValidationMap(objectMapPtr& map) {
+ if (!map.get()) return;
+ map->clear();
+ propSetPtr p0; // empty ptr, used for no properties
+
+ // == Exchanges ==
+
+ propSetPtr p1(new propSet);
+ p1->insert(PROP_TYPE);
+ p1->insert(PROP_ALTERNATE);
+ p1->insert(PROP_PASSIVE);
+ p1->insert(PROP_DURABLE);
+
+ propSetPtr p2(new propSet);
+ p2->insert(PROP_ROUTINGKEY);
+
+ propSetPtr p3(new propSet);
+ p3->insert(PROP_QUEUENAME);
+ p3->insert(PROP_ROUTINGKEY);
+
+ actionMapPtr a0(new actionMap);
+ a0->insert(actionPair(ACT_CREATE, p1));
+ a0->insert(actionPair(ACT_DELETE, p0));
+ a0->insert(actionPair(ACT_ACCESS, p0));
+ a0->insert(actionPair(ACT_BIND, p2));
+ a0->insert(actionPair(ACT_UNBIND, p2));
+ a0->insert(actionPair(ACT_ACCESS, p3));
+ a0->insert(actionPair(ACT_PUBLISH, p0));
+
+ map->insert(objectPair(OBJ_EXCHANGE, a0));
+
+ // == Queues ==
+
+ propSetPtr p4(new propSet);
+ p4->insert(PROP_ALTERNATE);
+ p4->insert(PROP_PASSIVE);
+ p4->insert(PROP_DURABLE);
+ p4->insert(PROP_EXCLUSIVE);
+ p4->insert(PROP_AUTODELETE);
+ p4->insert(PROP_POLICYTYPE);
+ p4->insert(PROP_MAXQUEUESIZE);
+ p4->insert(PROP_MAXQUEUECOUNT);
+
+ actionMapPtr a1(new actionMap);
+ a1->insert(actionPair(ACT_ACCESS, p0));
+ a1->insert(actionPair(ACT_CREATE, p4));
+ a1->insert(actionPair(ACT_PURGE, p0));
+ a1->insert(actionPair(ACT_DELETE, p0));
+ a1->insert(actionPair(ACT_CONSUME, p0));
+
+ map->insert(objectPair(OBJ_QUEUE, a1));
+
+ // == Links ==
+
+ actionMapPtr a2(new actionMap);
+ a2->insert(actionPair(ACT_CREATE, p0));
+
+ map->insert(objectPair(OBJ_LINK, a2));
+
+ // == Method ==
+
+ propSetPtr p5(new propSet);
+ p5->insert(PROP_SCHEMAPACKAGE);
+ p5->insert(PROP_SCHEMACLASS);
+
+ actionMapPtr a4(new actionMap);
+ a4->insert(actionPair(ACT_ACCESS, p5));
+
+ map->insert(objectPair(OBJ_METHOD, a4));
+ }
+
+ static std::string propertyMapToString(const std::map<Property, std::string>* params) {
+ std::ostringstream ss;
+ ss << "{";
+ if (params)
+ {
+ for (propMapItr pMItr = params->begin(); pMItr != params->end(); pMItr++) {
+ ss << " " << getPropertyStr((Property) pMItr-> first) << "=" << pMItr->second;
+ }
+ }
+ ss << " }";
+ return ss.str();
+ }
+};
-}} // namespace qpid::broker
+}} // namespace qpid::acl
#endif // QPID_ACLMODULE_ACL_H
diff --git a/cpp/src/qpid/broker/Bridge.cpp b/cpp/src/qpid/broker/Bridge.cpp
index 53bed020e2..79e311d032 100644
--- a/cpp/src/qpid/broker/Bridge.cpp
+++ b/cpp/src/qpid/broker/Bridge.cpp
@@ -18,36 +18,62 @@
* under the License.
*
*/
-#include "Bridge.h"
-#include "ConnectionState.h"
-#include "LinkRegistry.h"
+#include "qpid/broker/Bridge.h"
+#include "qpid/broker/ConnectionState.h"
+#include "qpid/broker/Connection.h"
+#include "qpid/broker/Link.h"
+#include "qpid/broker/LinkRegistry.h"
+#include "qpid/broker/SessionState.h"
-#include "qpid/agent/ManagementAgent.h"
-#include "qpid/framing/FieldTable.h"
+#include "qpid/management/ManagementAgent.h"
#include "qpid/framing/Uuid.h"
#include "qpid/log/Statement.h"
+#include <iostream>
using qpid::framing::FieldTable;
using qpid::framing::Uuid;
using qpid::framing::Buffer;
using qpid::management::ManagementAgent;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+namespace
+{
+const std::string qpidFedOp("qpid.fed.op");
+const std::string qpidFedTags("qpid.fed.tags");
+const std::string qpidFedOrigin("qpid.fed.origin");
+
+const std::string fedOpBind("B");
+const std::string fedOpUnbind("U");
+const std::string fedOpReorigin("R");
+const std::string fedOpHello("H");
+}
namespace qpid {
namespace broker {
+void Bridge::PushHandler::handle(framing::AMQFrame& frame)
+{
+ conn->received(frame);
+}
+
Bridge::Bridge(Link* _link, framing::ChannelId _id, CancellationListener l,
- const management::ArgsLinkBridge& _args) :
+ const _qmf::ArgsLinkBridge& _args) :
link(_link), id(_id), args(_args), mgmtObject(0),
- listener(l), name(Uuid(true).str()), persistenceId(0)
+ listener(l), name(Uuid(true).str()), queueName("bridge_queue_"), persistenceId(0)
{
- ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ std::stringstream title;
+ title << id << "_" << link->getBroker()->getFederationTag();
+ queueName += title.str();
+ ManagementAgent* agent = link->getBroker()->getManagementAgent();
if (agent != 0) {
- mgmtObject = new management::Bridge(agent, this, link, id, args.i_durable, args.i_src, args.i_dest,
- args.i_key, args.i_srcIsQueue, args.i_srcIsLocal,
- args.i_tag, args.i_excludes);
+ mgmtObject = new _qmf::Bridge
+ (agent, this, link, id, args.i_durable, args.i_src, args.i_dest,
+ args.i_key, args.i_srcIsQueue, args.i_srcIsLocal,
+ args.i_tag, args.i_excludes, args.i_dynamic, args.i_sync);
if (!args.i_durable)
agent->addObject(mgmtObject);
}
+ QPID_LOG(debug, "Bridge created from " << args.i_src << " to " << args.i_dest);
}
Bridge::~Bridge()
@@ -55,62 +81,111 @@ Bridge::~Bridge()
mgmtObject->resourceDestroy();
}
-void Bridge::create(ConnectionState& c)
+void Bridge::create(Connection& c)
{
- channelHandler.reset(new framing::ChannelHandler(id, &(c.getOutput())));
- session.reset(new framing::AMQP_ServerProxy::Session(*channelHandler));
- peer.reset(new framing::AMQP_ServerProxy(*channelHandler));
+ connState = &c;
+ conn = &c;
+ FieldTable options;
+ if (args.i_sync) options.setInt("qpid.sync_frequency", args.i_sync);
+ SessionHandler& sessionHandler = c.getChannel(id);
+ if (args.i_srcIsLocal) {
+ if (args.i_dynamic)
+ throw Exception("Dynamic routing not supported for push routes");
+ // Point the bridging commands at the local connection handler
+ pushHandler.reset(new PushHandler(&c));
+ channelHandler.reset(new framing::ChannelHandler(id, pushHandler.get()));
- session->attach(name, false);
- session->commandPoint(0,0);
+ session.reset(new framing::AMQP_ServerProxy::Session(*channelHandler));
+ peer.reset(new framing::AMQP_ServerProxy(*channelHandler));
+
+ session->attach(name, false);
+ session->commandPoint(0,0);
+ } else {
+ sessionHandler.attachAs(name);
+ // Point the bridging commands at the remote peer broker
+ peer.reset(new framing::AMQP_ServerProxy(sessionHandler.out));
+ }
- if (args.i_srcIsLocal) {
- //TODO: handle 'push' here... simplest way is to create frames and pass them to Connection::received()
+ if (args.i_srcIsLocal) sessionHandler.getSession()->disableReceiverTracking();
+ if (args.i_srcIsQueue) {
+ peer->getMessage().subscribe(args.i_src, args.i_dest, args.i_sync ? 0 : 1, 0, false, "", 0, options);
+ peer->getMessage().flow(args.i_dest, 0, 0xFFFFFFFF);
+ peer->getMessage().flow(args.i_dest, 1, 0xFFFFFFFF);
+ QPID_LOG(debug, "Activated route from queue " << args.i_src << " to " << args.i_dest);
} else {
- if (args.i_srcIsQueue) {
- peer->getMessage().subscribe(args.i_src, args.i_dest, 1, 0, false, "", 0, FieldTable());
- peer->getMessage().flow(args.i_dest, 0, 0xFFFFFFFF);
- peer->getMessage().flow(args.i_dest, 1, 0xFFFFFFFF);
+ FieldTable queueSettings;
+
+ if (args.i_tag.size()) {
+ queueSettings.setString("qpid.trace.id", args.i_tag);
} else {
- string queue = "bridge_queue_";
- queue += Uuid(true).str();
- FieldTable queueSettings;
- if (args.i_tag.size()) {
- queueSettings.setString("qpid.trace.id", args.i_tag);
- }
- if (args.i_excludes.size()) {
- queueSettings.setString("qpid.trace.exclude", args.i_excludes);
- }
-
- bool durable = false;//should this be an arg, or would be use srcIsQueue for durable queues?
- bool autoDelete = !durable;//auto delete transient queues?
- peer->getQueue().declare(queue, "", false, durable, true, autoDelete, queueSettings);
- peer->getExchange().bind(queue, args.i_src, args.i_key, FieldTable());
- peer->getMessage().subscribe(queue, args.i_dest, 1, 0, false, "", 0, FieldTable());
- peer->getMessage().flow(args.i_dest, 0, 0xFFFFFFFF);
- peer->getMessage().flow(args.i_dest, 1, 0xFFFFFFFF);
+ const string& peerTag = c.getFederationPeerTag();
+ if (peerTag.size())
+ queueSettings.setString("qpid.trace.id", peerTag);
+ }
+
+ if (args.i_excludes.size()) {
+ queueSettings.setString("qpid.trace.exclude", args.i_excludes);
+ } else {
+ const string& localTag = link->getBroker()->getFederationTag();
+ if (localTag.size())
+ queueSettings.setString("qpid.trace.exclude", localTag);
+ }
+
+ bool durable = false;//should this be an arg, or would we use srcIsQueue for durable queues?
+ bool autoDelete = !durable;//auto delete transient queues?
+ peer->getQueue().declare(queueName, "", false, durable, true, autoDelete, queueSettings);
+ if (!args.i_dynamic)
+ peer->getExchange().bind(queueName, args.i_src, args.i_key, FieldTable());
+ peer->getMessage().subscribe(queueName, args.i_dest, 1, 0, false, "", 0, FieldTable());
+ peer->getMessage().flow(args.i_dest, 0, 0xFFFFFFFF);
+ peer->getMessage().flow(args.i_dest, 1, 0xFFFFFFFF);
+
+ if (args.i_dynamic) {
+ Exchange::shared_ptr exchange = link->getBroker()->getExchanges().get(args.i_src);
+ if (exchange.get() == 0)
+ throw Exception("Exchange not found for dynamic route");
+ exchange->registerDynamicBridge(this);
+ QPID_LOG(debug, "Activated dynamic route for exchange " << args.i_src);
+ } else {
+ QPID_LOG(debug, "Activated static route from exchange " << args.i_src << " to " << args.i_dest);
}
}
+ if (args.i_srcIsLocal) sessionHandler.getSession()->enableReceiverTracking();
}
-void Bridge::cancel()
+void Bridge::cancel(Connection& c)
{
+ if (args.i_srcIsLocal) {
+ //recreate peer to be sure that the session handler reference
+ //is valid (it could have been deleted due to a detach)
+ SessionHandler& sessionHandler = c.getChannel(id);
+ peer.reset(new framing::AMQP_ServerProxy(sessionHandler.out));
+ }
peer->getMessage().cancel(args.i_dest);
peer->getSession().detach(name);
}
+void Bridge::closed()
+{
+ if (args.i_dynamic) {
+ Exchange::shared_ptr exchange = link->getBroker()->getExchanges().get(args.i_src);
+ if (exchange.get() != 0)
+ exchange->removeDynamicBridge(this);
+ }
+}
+
void Bridge::destroy()
{
listener(this);
}
-void Bridge::setPersistenceId(uint64_t id) const
+void Bridge::setPersistenceId(uint64_t pId) const
{
if (mgmtObject != 0 && persistenceId == 0) {
- ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
- agent->addObject (mgmtObject, id);
+ ManagementAgent* agent = link->getBroker()->getManagementAgent();
+ agent->addObject (mgmtObject, pId);
}
- persistenceId = id;
+ persistenceId = pId;
}
const string& Bridge::getName() const
@@ -138,9 +213,11 @@ Bridge::shared_ptr Bridge::decode(LinkRegistry& links, Buffer& buffer)
bool is_local(buffer.getOctet());
buffer.getShortString(id);
buffer.getShortString(excludes);
+ bool dynamic(buffer.getOctet());
+ uint16_t sync = buffer.getShort();
return links.declare(host, port, durable, src, dest, key,
- is_queue, is_local, id, excludes).first;
+ is_queue, is_local, id, excludes, dynamic, sync).first;
}
void Bridge::encode(Buffer& buffer) const
@@ -156,6 +233,8 @@ void Bridge::encode(Buffer& buffer) const
buffer.putOctet(args.i_srcIsLocal ? 1 : 0);
buffer.putShortString(args.i_tag);
buffer.putShortString(args.i_excludes);
+ buffer.putOctet(args.i_dynamic ? 1 : 0);
+ buffer.putShort(args.i_sync);
}
uint32_t Bridge::encodedSize() const
@@ -170,7 +249,9 @@ uint32_t Bridge::encodedSize() const
+ 1 // srcIsQueue
+ 1 // srcIsLocal
+ args.i_tag.size() + 1
- + args.i_excludes.size() + 1;
+ + args.i_excludes.size() + 1
+ + 1 // dynamic
+ + 2; // sync
}
management::ManagementObject* Bridge::GetManagementObject (void) const
@@ -178,9 +259,11 @@ management::ManagementObject* Bridge::GetManagementObject (void) const
return (management::ManagementObject*) mgmtObject;
}
-management::Manageable::status_t Bridge::ManagementMethod(uint32_t methodId, management::Args& /*args*/)
+management::Manageable::status_t Bridge::ManagementMethod(uint32_t methodId,
+ management::Args& /*args*/,
+ string&)
{
- if (methodId == management::Bridge::METHOD_CLOSE) {
+ if (methodId == _qmf::Bridge::METHOD_CLOSE) {
//notify that we are closed
destroy();
return management::Manageable::STATUS_OK;
@@ -189,4 +272,53 @@ management::Manageable::status_t Bridge::ManagementMethod(uint32_t methodId, man
}
}
+void Bridge::propagateBinding(const string& key, const string& tagList,
+ const string& op, const string& origin)
+{
+ const string& localTag = link->getBroker()->getFederationTag();
+ const string& peerTag = connState->getFederationPeerTag();
+
+ if (tagList.find(peerTag) == tagList.npos) {
+ FieldTable bindArgs;
+ string newTagList(tagList + string(tagList.empty() ? "" : ",") + localTag);
+
+ bindArgs.setString(qpidFedOp, op);
+ bindArgs.setString(qpidFedTags, newTagList);
+ if (origin.empty())
+ bindArgs.setString(qpidFedOrigin, localTag);
+ else
+ bindArgs.setString(qpidFedOrigin, origin);
+
+ conn->requestIOProcessing(boost::bind(&Bridge::ioThreadPropagateBinding, this,
+ queueName, args.i_src, key, bindArgs));
+ }
+}
+
+void Bridge::sendReorigin()
+{
+ FieldTable bindArgs;
+
+ bindArgs.setString(qpidFedOp, fedOpReorigin);
+ bindArgs.setString(qpidFedTags, link->getBroker()->getFederationTag());
+
+ conn->requestIOProcessing(boost::bind(&Bridge::ioThreadPropagateBinding, this,
+ queueName, args.i_src, args.i_key, bindArgs));
+}
+
+void Bridge::ioThreadPropagateBinding(const string& queue, const string& exchange, const string& key, FieldTable args)
+{
+ peer->getExchange().bind(queue, exchange, key, args);
+}
+
+bool Bridge::containsLocalTag(const string& tagList) const
+{
+ const string& localTag = link->getBroker()->getFederationTag();
+ return (tagList.find(localTag) != tagList.npos);
+}
+
+const string& Bridge::getLocalTag() const
+{
+ return link->getBroker()->getFederationTag();
+}
+
}}
diff --git a/cpp/src/qpid/broker/Bridge.h b/cpp/src/qpid/broker/Bridge.h
index 06fba25268..7dae5c37a1 100644
--- a/cpp/src/qpid/broker/Bridge.h
+++ b/cpp/src/qpid/broker/Bridge.h
@@ -21,13 +21,16 @@
#ifndef _Bridge_
#define _Bridge_
-#include "PersistableConfig.h"
+#include "qpid/broker/PersistableConfig.h"
#include "qpid/framing/AMQP_ServerProxy.h"
#include "qpid/framing/ChannelHandler.h"
#include "qpid/framing/Buffer.h"
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/framing/FieldTable.h"
#include "qpid/management/Manageable.h"
-#include "qpid/management/ArgsLinkBridge.h"
-#include "qpid/management/Bridge.h"
+#include "qpid/broker/Exchange.h"
+#include "qmf/org/apache/qpid/broker/ArgsLinkBridge.h"
+#include "qmf/org/apache/qpid/broker/Bridge.h"
#include <boost/function.hpp>
#include <memory>
@@ -35,26 +38,31 @@
namespace qpid {
namespace broker {
+class Connection;
class ConnectionState;
class Link;
class LinkRegistry;
-class Bridge : public PersistableConfig, public management::Manageable
+class Bridge : public PersistableConfig, public management::Manageable, public Exchange::DynamicBridge
{
public:
typedef boost::shared_ptr<Bridge> shared_ptr;
typedef boost::function<void(Bridge*)> CancellationListener;
- Bridge(Link* link, framing::ChannelId id, CancellationListener l, const management::ArgsLinkBridge& args);
+ Bridge(Link* link, framing::ChannelId id, CancellationListener l,
+ const qmf::org::apache::qpid::broker::ArgsLinkBridge& args);
~Bridge();
- void create(ConnectionState& c);
- void cancel();
+ void create(Connection& c);
+ void cancel(Connection& c);
+ void closed();
void destroy();
bool isDurable() { return args.i_durable; }
management::ManagementObject* GetManagementObject() const;
- management::Manageable::status_t ManagementMethod(uint32_t methodId, management::Args& args);
+ management::Manageable::status_t ManagementMethod(uint32_t methodId,
+ management::Args& args,
+ std::string& text);
// PersistableConfig:
void setPersistenceId(uint64_t id) const;
@@ -64,18 +72,35 @@ public:
const std::string& getName() const;
static Bridge::shared_ptr decode(LinkRegistry& links, framing::Buffer& buffer);
+ // Exchange::DynamicBridge methods
+ void propagateBinding(const std::string& key, const std::string& tagList, const std::string& op, const std::string& origin);
+ void sendReorigin();
+ void ioThreadPropagateBinding(const string& queue, const string& exchange, const string& key, framing::FieldTable args);
+ bool containsLocalTag(const std::string& tagList) const;
+ const std::string& getLocalTag() const;
+
private:
+ struct PushHandler : framing::FrameHandler {
+ PushHandler(Connection* c) { conn = c; }
+ void handle(framing::AMQFrame& frame);
+ Connection* conn;
+ };
+
+ std::auto_ptr<PushHandler> pushHandler;
std::auto_ptr<framing::ChannelHandler> channelHandler;
std::auto_ptr<framing::AMQP_ServerProxy::Session> session;
std::auto_ptr<framing::AMQP_ServerProxy> peer;
Link* link;
framing::ChannelId id;
- management::ArgsLinkBridge args;
- management::Bridge* mgmtObject;
+ qmf::org::apache::qpid::broker::ArgsLinkBridge args;
+ qmf::org::apache::qpid::broker::Bridge* mgmtObject;
CancellationListener listener;
std::string name;
+ std::string queueName;
mutable uint64_t persistenceId;
+ ConnectionState* connState;
+ Connection* conn;
};
diff --git a/cpp/src/qpid/broker/Broker.cpp b/cpp/src/qpid/broker/Broker.cpp
index 4d7c07649b..849bf6d1f5 100644
--- a/cpp/src/qpid/broker/Broker.cpp
+++ b/cpp/src/qpid/broker/Broker.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -19,23 +19,27 @@
*
*/
-#include "config.h"
-#include "Broker.h"
-#include "DirectExchange.h"
-#include "FanOutExchange.h"
-#include "HeadersExchange.h"
-#include "MessageStoreModule.h"
-#include "NullMessageStore.h"
-#include "RecoveryManagerImpl.h"
-#include "TopicExchange.h"
-#include "Link.h"
-
-#include "qpid/management/PackageQpid.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/broker/DirectExchange.h"
+#include "qpid/broker/FanOutExchange.h"
+#include "qpid/broker/HeadersExchange.h"
+#include "qpid/broker/MessageStoreModule.h"
+#include "qpid/broker/NullMessageStore.h"
+#include "qpid/broker/RecoveryManagerImpl.h"
+#include "qpid/broker/SaslAuthenticator.h"
+#include "qpid/broker/SecureConnectionFactory.h"
+#include "qpid/broker/TopicExchange.h"
+#include "qpid/broker/Link.h"
+#include "qpid/broker/ExpiryPolicy.h"
+
+#include "qmf/org/apache/qpid/broker/Package.h"
+#include "qmf/org/apache/qpid/broker/ArgsBrokerEcho.h"
+#include "qmf/org/apache/qpid/broker/ArgsBrokerQueueMoveMessages.h"
#include "qpid/management/ManagementExchange.h"
-#include "qpid/management/ArgsBrokerEcho.h"
#include "qpid/log/Statement.h"
#include "qpid/framing/AMQFrame.h"
#include "qpid/framing/ProtocolInitiation.h"
+#include "qpid/framing/Uuid.h"
#include "qpid/sys/ProtocolFactory.h"
#include "qpid/sys/Poller.h"
#include "qpid/sys/Dispatcher.h"
@@ -45,20 +49,14 @@
#include "qpid/sys/ConnectionInputHandlerFactory.h"
#include "qpid/sys/TimeoutHandler.h"
#include "qpid/sys/SystemInfo.h"
+#include "qpid/Address.h"
#include "qpid/Url.h"
+#include "qpid/Version.h"
#include <boost/bind.hpp>
#include <iostream>
#include <memory>
-#include <stdlib.h>
-
-#if HAVE_SASL
-#include <sasl/sasl.h>
-static const bool AUTH_DEFAULT=true;
-#else
-static const bool AUTH_DEFAULT=false;
-#endif
using qpid::sys::ProtocolFactory;
using qpid::sys::Poller;
@@ -66,11 +64,11 @@ using qpid::sys::Dispatcher;
using qpid::sys::Thread;
using qpid::framing::FrameHandler;
using qpid::framing::ChannelId;
-using qpid::management::ManagementBroker;
+using qpid::management::ManagementAgent;
using qpid::management::ManagementObject;
using qpid::management::Manageable;
using qpid::management::Args;
-using qpid::management::ArgsBrokerEcho;
+namespace _qmf = qmf::org::apache::qpid::broker;
namespace qpid {
namespace broker {
@@ -85,22 +83,26 @@ Broker::Options::Options(const std::string& name) :
stagingThreshold(5000000),
enableMgmt(1),
mgmtPubInterval(10),
- auth(AUTH_DEFAULT),
+ queueCleanInterval(60*10),//10 minutes
+ auth(SaslAuthenticator::available()),
realm("QPID"),
replayFlushLimit(0),
replayHardLimit(0),
queueLimit(100*1048576/*100M default limit*/),
- tcpNoDelay(false)
+ tcpNoDelay(false),
+ requireEncrypted(false),
+ maxSessionRate(0),
+ asyncQueueEvents(true)
{
int c = sys::SystemInfo::concurrency();
workerThreads=c+1;
- char *home = ::getenv("HOME");
+ std::string home = getHome();
- if (home == 0)
- dataDir += "/tmp";
+ if (home.length() == 0)
+ dataDir += DEFAULT_DATA_DIR_LOCATION;
else
dataDir += home;
- dataDir += "/.qpidd";
+ dataDir += DEFAULT_DATA_DIR_NAME;
addOptions()
("data-dir", optValue(dataDir,"DIR"), "Directory to contain persistent data generated by the broker")
@@ -112,10 +114,16 @@ Broker::Options::Options(const std::string& name) :
("staging-threshold", optValue(stagingThreshold, "N"), "Stages messages over N bytes to disk")
("mgmt-enable,m", optValue(enableMgmt,"yes|no"), "Enable Management")
("mgmt-pub-interval", optValue(mgmtPubInterval, "SECONDS"), "Management Publish Interval")
+ ("queue-purge-interval", optValue(queueCleanInterval, "SECONDS"),
+ "Interval between attempts to purge any expired messages from queues")
("auth", optValue(auth, "yes|no"), "Enable authentication, if disabled all incoming connections will be trusted")
("realm", optValue(realm, "REALM"), "Use the given realm when performing authentication")
("default-queue-limit", optValue(queueLimit, "BYTES"), "Default maximum size for queues (in bytes)")
- ("tcp-nodelay", optValue(tcpNoDelay), "Set TCP_NODELAY on TCP connections");
+ ("tcp-nodelay", optValue(tcpNoDelay), "Set TCP_NODELAY on TCP connections")
+ ("require-encryption", optValue(requireEncrypted), "Only accept connections that are encrypted")
+ ("known-hosts-url", optValue(knownHosts, "URL or 'none'"), "URL to send as 'known-hosts' to clients ('none' implies empty list)")
+ ("max-session-rate", optValue(maxSessionRate, "MESSAGES/S"), "Sets the maximum message rate per session (0=unlimited)")
+ ("async-queue-events", optValue(asyncQueueEvents, "yes|no"), "Set Queue Events async, used for services like replication");
}
const std::string empty;
@@ -124,79 +132,99 @@ const std::string amq_topic("amq.topic");
const std::string amq_fanout("amq.fanout");
const std::string amq_match("amq.match");
const std::string qpid_management("qpid.management");
+const std::string knownHostsNone("none");
Broker::Broker(const Broker::Options& conf) :
poller(new Poller),
config(conf),
- managementAgentSingleton(!config.enableMgmt),
- store(0),
- acl(0),
- dataDir(conf.noDataDir ? std::string () : conf.dataDir),
+ managementAgent(conf.enableMgmt ? new ManagementAgent() : 0),
+ store(new NullMessageStore),
+ acl(0),
+ dataDir(conf.noDataDir ? std::string() : conf.dataDir),
+ queues(this),
+ exchanges(this),
links(this),
- factory(*this),
+ factory(new SecureConnectionFactory(*this)),
+ dtxManager(timer),
sessionManager(
qpid::SessionState::Configuration(
conf.replayFlushLimit*1024, // convert kb to bytes.
conf.replayHardLimit*1024),
- *this)
+ *this),
+ queueCleaner(queues, timer),
+ queueEvents(poller,!conf.asyncQueueEvents),
+ recovery(true),
+ clusterUpdatee(false),
+ expiryPolicy(new ExpiryPolicy),
+ connectionCounter(conf.maxConnections),
+ getKnownBrokers(boost::bind(&Broker::getKnownBrokersImpl, this))
{
- if(conf.enableMgmt){
+ if (conf.enableMgmt) {
QPID_LOG(info, "Management enabled");
- managementAgent = managementAgentSingleton.getInstance();
- ((ManagementBroker*) managementAgent)->configure
- (dataDir.isEnabled () ? dataDir.getPath () : string (),
- conf.mgmtPubInterval, this, conf.workerThreads + 3);
- qpid::management::PackageQpid packageInitializer (managementAgent);
-
- System* system = new System (dataDir.isEnabled () ? dataDir.getPath () : string ());
- systemObject = System::shared_ptr (system);
-
- mgmtObject = new management::Broker (managementAgent, this, system, conf.port);
- mgmtObject->set_workerThreads (conf.workerThreads);
- mgmtObject->set_maxConns (conf.maxConnections);
- mgmtObject->set_connBacklog (conf.connectionBacklog);
- mgmtObject->set_stagingThreshold (conf.stagingThreshold);
- mgmtObject->set_mgmtPubInterval (conf.mgmtPubInterval);
- mgmtObject->set_version (PACKAGE_VERSION);
- mgmtObject->set_dataDirEnabled (dataDir.isEnabled ());
- mgmtObject->set_dataDir (dataDir.getPath ());
-
- managementAgent->addObject (mgmtObject, 2, 1);
+ managementAgent->configure(dataDir.isEnabled() ? dataDir.getPath() : string(),
+ conf.mgmtPubInterval, this, conf.workerThreads + 3);
+ _qmf::Package packageInitializer(managementAgent.get());
+
+ System* system = new System (dataDir.isEnabled() ? dataDir.getPath() : string(), this);
+ systemObject = System::shared_ptr(system);
+
+ mgmtObject = new _qmf::Broker(managementAgent.get(), this, system, conf.port);
+ mgmtObject->set_workerThreads(conf.workerThreads);
+ mgmtObject->set_maxConns(conf.maxConnections);
+ mgmtObject->set_connBacklog(conf.connectionBacklog);
+ mgmtObject->set_stagingThreshold(conf.stagingThreshold);
+ mgmtObject->set_mgmtPubInterval(conf.mgmtPubInterval);
+ mgmtObject->set_version(qpid::version);
+ if (dataDir.isEnabled())
+ mgmtObject->set_dataDir(dataDir.getPath());
+ else
+ mgmtObject->clr_dataDir();
+
+ managementAgent->addObject(mgmtObject, 0x1000000000000002LL);
// Since there is currently no support for virtual hosts, a placeholder object
// representing the implied single virtual host is added here to keep the
// management schema correct.
- Vhost* vhost = new Vhost (this);
- vhostObject = Vhost::shared_ptr (vhost);
-
- queues.setParent (vhost);
- exchanges.setParent (vhost);
- links.setParent (vhost);
+ Vhost* vhost = new Vhost(this, this);
+ vhostObject = Vhost::shared_ptr(vhost);
+ framing::Uuid uuid(managementAgent->getUuid());
+ federationTag = uuid.str();
+ vhostObject->setFederationTag(federationTag);
+
+ queues.setParent(vhost);
+ exchanges.setParent(vhost);
+ links.setParent(vhost);
+ } else {
+ // Management is disabled so there is no broker management ID.
+ // Create a unique uuid to use as the federation tag.
+ framing::Uuid uuid(true);
+ federationTag = uuid.str();
}
QueuePolicy::setDefaultMaxSize(conf.queueLimit);
+ queues.setQueueEvents(&queueEvents);
// Early-Initialize plugins
- const Plugin::Plugins& plugins=Plugin::getPlugins();
- for (Plugin::Plugins::const_iterator i = plugins.begin();
- i != plugins.end();
- i++)
- (*i)->earlyInitialize(*this);
+ Plugin::earlyInitAll(*this);
// If no plugin store module registered itself, set up the null store.
- if (store == 0)
- setStore (new NullMessageStore (false));
-
- queues.setStore (store);
- dtxManager.setStore (store);
- links.setStore (store);
+ if (NullMessageStore::isNullStore(store.get()))
+ setStore();
exchanges.declare(empty, DirectExchange::typeName); // Default exchange.
-
- if (store != 0) {
- RecoveryManagerImpl recoverer(queues, exchanges, links, dtxManager,
- conf.stagingThreshold);
- store->recover(recoverer);
+
+ if (store.get() != 0) {
+ // The cluster plug-in will setRecovery(false) on all but the first
+ // broker to join a cluster.
+ if (getRecovery()) {
+ RecoveryManagerImpl recoverer(queues, exchanges, links, dtxManager,
+ conf.stagingThreshold);
+ store->recover(recoverer);
+ }
+ else {
+ QPID_LOG(notice, "Cluster recovery: recovered journal data discarded and journal files pushed down");
+ store->truncateInit(true); // save old files in subdir
+ }
}
//ensure standard exchanges exist (done after recovery from store)
@@ -209,9 +237,8 @@ Broker::Broker(const Broker::Options& conf) :
exchanges.declare(qpid_management, ManagementExchange::typeName);
Exchange::shared_ptr mExchange = exchanges.get (qpid_management);
Exchange::shared_ptr dExchange = exchanges.get (amq_direct);
- ((ManagementBroker*) managementAgent)->setExchange (mExchange, dExchange);
- dynamic_pointer_cast<ManagementExchange>(mExchange)->setManagmentAgent
- ((ManagementBroker*) managementAgent);
+ managementAgent->setExchange(mExchange, dExchange);
+ boost::dynamic_pointer_cast<ManagementExchange>(mExchange)->setManagmentAgent(managementAgent.get());
}
else
QPID_LOG(info, "Management not enabled");
@@ -220,29 +247,33 @@ Broker::Broker(const Broker::Options& conf) :
* SASL setup, can fail and terminate startup
*/
if (conf.auth) {
-#if HAVE_SASL
- int code = sasl_server_init(NULL, BROKER_SASL_NAME);
- if (code != SASL_OK) {
- // TODO: Figure out who owns the char* returned by
- // sasl_errstring, though it probably does not matter much
- throw Exception(sasl_errstring(code, NULL, NULL));
- }
+ SaslAuthenticator::init(qpid::saslName);
QPID_LOG(info, "SASL enabled");
-#else
- throw Exception("Requested authentication but SASL unavailable");
-#endif
+ } else {
+ QPID_LOG(notice, "SASL disabled: No Authentication Performed");
}
// Initialize plugins
- for (Plugin::Plugins::const_iterator i = plugins.begin();
- i != plugins.end();
- i++)
- (*i)->initialize(*this);
+ Plugin::initializeAll(*this);
+
+ if (conf.queueCleanInterval) {
+ queueCleaner.start(conf.queueCleanInterval * qpid::sys::TIME_SEC);
+ }
+
+ //initialize known broker urls (TODO: add support for urls for other transports (SSL, RDMA)):
+ if (conf.knownHosts.empty()) {
+ boost::shared_ptr<ProtocolFactory> factory = getProtocolFactory(TCP_TRANSPORT);
+ if (factory) {
+ knownBrokers.push_back ( qpid::Url::getIpAddressesUrl ( factory->getPort() ) );
+ }
+ } else if (conf.knownHosts != knownHostsNone) {
+ knownBrokers.push_back(Url(conf.knownHosts));
+ }
}
void Broker::declareStandardExchange(const std::string& name, const std::string& type)
{
- bool storeEnabled = store != NULL;
+ bool storeEnabled = store.get() != NULL;
std::pair<Exchange::shared_ptr, bool> status = exchanges.declare(name, type, storeEnabled);
if (status.second && storeEnabled) {
store->create(*status.first, framing::FieldTable ());
@@ -250,28 +281,32 @@ void Broker::declareStandardExchange(const std::string& name, const std::string&
}
-boost::intrusive_ptr<Broker> Broker::create(int16_t port)
+boost::intrusive_ptr<Broker> Broker::create(int16_t port)
{
Options config;
config.port=port;
return create(config);
}
-boost::intrusive_ptr<Broker> Broker::create(const Options& opts)
+boost::intrusive_ptr<Broker> Broker::create(const Options& opts)
{
return boost::intrusive_ptr<Broker>(new Broker(opts));
}
-void Broker::setStore (MessageStore* _store)
+void Broker::setStore (boost::shared_ptr<MessageStore>& _store)
{
- assert (store == 0 && _store != 0);
- if (store == 0 && _store != 0)
- store = new MessageStoreModule (_store);
+ store.reset(new MessageStoreModule (_store));
+ setStore();
+}
+
+void Broker::setStore () {
+ queues.setStore (store.get());
+ dtxManager.setStore (store.get());
+ links.setStore (store.get());
}
void Broker::run() {
- accept();
-
+ QPID_LOG(notice, "Broker running");
Dispatcher d(poller);
int numIOThreads = config.workerThreads;
std::vector<Thread> t(numIOThreads-1);
@@ -282,7 +317,7 @@ void Broker::run() {
// Run final thread
d.run();
-
+
// Now wait for n-1 io threads to exit
for (int i=0; i<numIOThreads-1; ++i) {
t[i].join();
@@ -298,13 +333,10 @@ void Broker::shutdown() {
Broker::~Broker() {
shutdown();
+ queueEvents.shutdown();
finalize(); // Finalize any plugins.
- delete store;
- if (config.auth) {
-#if HAVE_SASL
- sasl_done();
-#endif
- }
+ if (config.auth)
+ SaslAuthenticator::fini();
QPID_LOG(notice, "Shut down");
}
@@ -319,7 +351,8 @@ Manageable* Broker::GetVhostObject(void) const
}
Manageable::status_t Broker::ManagementMethod (uint32_t methodId,
- Args& args)
+ Args& args,
+ string&)
{
Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD;
@@ -327,27 +360,36 @@ Manageable::status_t Broker::ManagementMethod (uint32_t methodId,
switch (methodId)
{
- case management::Broker::METHOD_ECHO :
+ case _qmf::Broker::METHOD_ECHO :
status = Manageable::STATUS_OK;
break;
- case management::Broker::METHOD_CONNECT : {
- management::ArgsBrokerConnect& hp=
- dynamic_cast<management::ArgsBrokerConnect&>(args);
-
- if (hp.i_useSsl)
- return Manageable::STATUS_FEATURE_NOT_IMPLEMENTED;
-
+ case _qmf::Broker::METHOD_CONNECT : {
+ _qmf::ArgsBrokerConnect& hp=
+ dynamic_cast<_qmf::ArgsBrokerConnect&>(args);
+
+ string transport = hp.i_transport.empty() ? TCP_TRANSPORT : hp.i_transport;
+ if (!getProtocolFactory(transport)) {
+ QPID_LOG(error, "Transport '" << transport << "' not supported");
+ return Manageable::STATUS_NOT_IMPLEMENTED;
+ }
std::pair<Link::shared_ptr, bool> response =
- links.declare (hp.i_host, hp.i_port, hp.i_useSsl, hp.i_durable,
+ links.declare (hp.i_host, hp.i_port, transport, hp.i_durable,
hp.i_authMechanism, hp.i_username, hp.i_password);
if (hp.i_durable && response.second)
store->create(*response.first);
-
status = Manageable::STATUS_OK;
break;
}
- case management::Broker::METHOD_JOINCLUSTER :
- case management::Broker::METHOD_LEAVECLUSTER :
+ case _qmf::Broker::METHOD_QUEUEMOVEMESSAGES : {
+ _qmf::ArgsBrokerQueueMoveMessages& moveArgs=
+ dynamic_cast<_qmf::ArgsBrokerQueueMoveMessages&>(args);
+ if (queueMoveMessages(moveArgs.i_srcQueue, moveArgs.i_destQueue, moveArgs.i_qty))
+ status = Manageable::STATUS_OK;
+ else
+ return Manageable::STATUS_PARAMETER_INVALID;
+ break;
+ }
+ default:
status = Manageable::STATUS_NOT_IMPLEMENTED;
break;
}
@@ -355,34 +397,40 @@ Manageable::status_t Broker::ManagementMethod (uint32_t methodId,
return status;
}
-boost::shared_ptr<ProtocolFactory> Broker::getProtocolFactory() const {
- assert(protocolFactories.size() > 0);
- return protocolFactories[0];
+boost::shared_ptr<ProtocolFactory> Broker::getProtocolFactory(const std::string& name) const {
+ ProtocolFactoryMap::const_iterator i
+ = name.empty() ? protocolFactories.begin() : protocolFactories.find(name);
+ if (i == protocolFactories.end()) return boost::shared_ptr<ProtocolFactory>();
+ else return i->second;
}
-void Broker::registerProtocolFactory(ProtocolFactory::shared_ptr protocolFactory) {
- protocolFactories.push_back(protocolFactory);
+uint16_t Broker::getPort(const std::string& name) const {
+ boost::shared_ptr<ProtocolFactory> factory = getProtocolFactory(name);
+ if (factory) {
+ return factory->getPort();
+ } else {
+ throw NoSuchTransportException(QPID_MSG("No such transport: '" << name << "'"));
+ }
}
-// TODO: This can only work if there is only one protocolFactory
-uint16_t Broker::getPort() const {
- return getProtocolFactory()->getPort();
+void Broker::registerProtocolFactory(const std::string& name, ProtocolFactory::shared_ptr protocolFactory) {
+ protocolFactories[name] = protocolFactory;
}
-// TODO: This should iterate over all protocolFactories
void Broker::accept() {
- for (unsigned int i = 0; i < protocolFactories.size(); ++i)
- protocolFactories[i]->accept(poller, &factory);
+ for (ProtocolFactoryMap::const_iterator i = protocolFactories.begin(); i != protocolFactories.end(); i++) {
+ i->second->accept(poller, factory.get());
+ }
}
-
-// TODO: How to chose the protocolFactory to use for the connection
void Broker::connect(
- const std::string& host, uint16_t port, bool /*useSsl*/,
+ const std::string& host, uint16_t port, const std::string& transport,
boost::function2<void, int, std::string> failed,
sys::ConnectionCodec::Factory* f)
{
- getProtocolFactory()->connect(poller, host, port, f ? f : &factory, failed);
+ boost::shared_ptr<ProtocolFactory> pf = getProtocolFactory(transport);
+ if (pf) pf->connect(poller, host, port, f ? f : factory.get(), failed);
+ else throw NoSuchTransportException(QPID_MSG("Unsupported transport type: " << transport));
}
void Broker::connect(
@@ -391,11 +439,35 @@ void Broker::connect(
sys::ConnectionCodec::Factory* f)
{
url.throwIfEmpty();
- TcpAddress addr=boost::get<TcpAddress>(url[0]);
- connect(addr.host, addr.port, false, failed, f);
+ const TcpAddress* addr=url[0].get<TcpAddress>();
+ connect(addr->host, addr->port, TCP_TRANSPORT, failed, f);
}
+uint32_t Broker::queueMoveMessages(
+ const std::string& srcQueue,
+ const std::string& destQueue,
+ uint32_t qty)
+{
+ Queue::shared_ptr src_queue = queues.find(srcQueue);
+ if (!src_queue)
+ return 0;
+ Queue::shared_ptr dest_queue = queues.find(destQueue);
+ if (!dest_queue)
+ return 0;
+
+ return src_queue->move(dest_queue, qty);
+}
+
+
boost::shared_ptr<sys::Poller> Broker::getPoller() { return poller; }
+std::vector<Url>
+Broker::getKnownBrokersImpl()
+{
+ return knownBrokers;
+}
+
+const std::string Broker::TCP_TRANSPORT("tcp");
+
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/Broker.h b/cpp/src/qpid/broker/Broker.h
index f7399c375f..b85aa7d96c 100644
--- a/cpp/src/qpid/broker/Broker.h
+++ b/cpp/src/qpid/broker/Broker.h
@@ -22,21 +22,25 @@
*
*/
-#include "ConnectionFactory.h"
-#include "ConnectionToken.h"
-#include "DirectExchange.h"
-#include "DtxManager.h"
-#include "ExchangeRegistry.h"
-#include "MessageStore.h"
-#include "QueueRegistry.h"
-#include "LinkRegistry.h"
-#include "SessionManager.h"
-#include "Vhost.h"
-#include "System.h"
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/ConnectionFactory.h"
+#include "qpid/broker/ConnectionToken.h"
+#include "qpid/broker/DirectExchange.h"
+#include "qpid/broker/DtxManager.h"
+#include "qpid/broker/ExchangeRegistry.h"
+#include "qpid/broker/MessageStore.h"
+#include "qpid/broker/QueueRegistry.h"
+#include "qpid/broker/LinkRegistry.h"
+#include "qpid/broker/SessionManager.h"
+#include "qpid/broker/QueueCleaner.h"
+#include "qpid/broker/QueueEvents.h"
+#include "qpid/broker/Vhost.h"
+#include "qpid/broker/System.h"
+#include "qpid/broker/ExpiryPolicy.h"
#include "qpid/management/Manageable.h"
-#include "qpid/management/ManagementBroker.h"
-#include "qpid/management/Broker.h"
-#include "qpid/management/ArgsBrokerConnect.h"
+#include "qpid/management/ManagementAgent.h"
+#include "qmf/org/apache/qpid/broker/Broker.h"
+#include "qmf/org/apache/qpid/broker/ArgsBrokerConnect.h"
#include "qpid/Options.h"
#include "qpid/Plugin.h"
#include "qpid/DataDir.h"
@@ -44,10 +48,13 @@
#include "qpid/framing/OutputHandler.h"
#include "qpid/framing/ProtocolInitiation.h"
#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Timer.h"
#include "qpid/RefCounted.h"
-#include "AclModule.h"
+#include "qpid/broker/AclModule.h"
+#include "qpid/sys/Mutex.h"
#include <boost/intrusive_ptr.hpp>
+#include <string>
#include <vector>
namespace qpid {
@@ -57,22 +64,34 @@ namespace sys {
class Poller;
}
-class Url;
+struct Url;
namespace broker {
+class ExpiryPolicy;
+
static const uint16_t DEFAULT_PORT=5672;
+struct NoSuchTransportException : qpid::Exception
+{
+ NoSuchTransportException(const std::string& s) : Exception(s) {}
+ virtual ~NoSuchTransportException() throw() {}
+};
+
/**
* A broker instance.
*/
class Broker : public sys::Runnable, public Plugin::Target,
- public management::Manageable, public RefCounted
+ public management::Manageable,
+ public RefCounted
{
- public:
+public:
struct Options : public qpid::Options {
- Options(const std::string& name="Broker Options");
+ static const std::string DEFAULT_DATA_DIR_LOCATION;
+ static const std::string DEFAULT_DATA_DIR_NAME;
+
+ QPID_BROKER_EXTERN Options(const std::string& name="Broker Options");
bool noDataDir;
std::string dataDir;
@@ -83,45 +102,82 @@ class Broker : public sys::Runnable, public Plugin::Target,
uint64_t stagingThreshold;
bool enableMgmt;
uint16_t mgmtPubInterval;
+ uint16_t queueCleanInterval;
bool auth;
std::string realm;
size_t replayFlushLimit;
size_t replayHardLimit;
uint queueLimit;
bool tcpNoDelay;
+ bool requireEncrypted;
+ std::string knownHosts;
+ uint32_t maxSessionRate;
+ bool asyncQueueEvents;
+
+ private:
+ std::string getHome();
+ };
+
+ class ConnectionCounter {
+ int maxConnections;
+ int connectionCount;
+ sys::Mutex connectionCountLock;
+ public:
+ ConnectionCounter(int mc): maxConnections(mc),connectionCount(0) {};
+ void inc_connectionCount() {
+ sys::ScopedLock<sys::Mutex> l(connectionCountLock);
+ connectionCount++;
+ }
+ void dec_connectionCount() {
+ sys::ScopedLock<sys::Mutex> l(connectionCountLock);
+ connectionCount--;
+ }
+ bool allowConnection() {
+ sys::ScopedLock<sys::Mutex> l(connectionCountLock);
+ return (maxConnections <= connectionCount);
+ }
};
-
+
private:
+ typedef std::map<std::string, boost::shared_ptr<sys::ProtocolFactory> > ProtocolFactoryMap;
+
+ void declareStandardExchange(const std::string& name, const std::string& type);
+ void setStore ();
+
boost::shared_ptr<sys::Poller> poller;
+ sys::Timer timer;
Options config;
- management::ManagementAgent::Singleton managementAgentSingleton;
- std::vector< boost::shared_ptr<sys::ProtocolFactory> > protocolFactories;
- MessageStore* store;
- AclModule* acl;
+ std::auto_ptr<management::ManagementAgent> managementAgent;
+ ProtocolFactoryMap protocolFactories;
+ std::auto_ptr<MessageStore> store;
+ AclModule* acl;
DataDir dataDir;
QueueRegistry queues;
ExchangeRegistry exchanges;
LinkRegistry links;
- ConnectionFactory factory;
+ boost::shared_ptr<sys::ConnectionCodec::Factory> factory;
DtxManager dtxManager;
SessionManager sessionManager;
- management::ManagementAgent* managementAgent;
- management::Broker* mgmtObject;
+ qmf::org::apache::qpid::broker::Broker* mgmtObject;
Vhost::shared_ptr vhostObject;
System::shared_ptr systemObject;
-
- void declareStandardExchange(const std::string& name, const std::string& type);
-
-
+ QueueCleaner queueCleaner;
+ QueueEvents queueEvents;
+ std::vector<Url> knownBrokers;
+ std::vector<Url> getKnownBrokersImpl();
+ std::string federationTag;
+ bool recovery;
+ bool clusterUpdatee;
+ boost::intrusive_ptr<ExpiryPolicy> expiryPolicy;
+ ConnectionCounter connectionCounter;
+
public:
-
-
virtual ~Broker();
- Broker(const Options& configuration);
- static boost::intrusive_ptr<Broker> create(const Options& configuration);
- static boost::intrusive_ptr<Broker> create(int16_t port = DEFAULT_PORT);
+ QPID_BROKER_EXTERN Broker(const Options& configuration);
+ static QPID_BROKER_EXTERN boost::intrusive_ptr<Broker> create(const Options& configuration);
+ static QPID_BROKER_EXTERN boost::intrusive_ptr<Broker> create(int16_t port = DEFAULT_PORT);
/**
* Return listening port. If called before bind this is
@@ -129,7 +185,7 @@ class Broker : public sys::Runnable, public Plugin::Target,
* port, which will be different if the configured port is
* 0.
*/
- virtual uint16_t getPort() const;
+ virtual uint16_t getPort(const std::string& name) const;
/**
* Run the broker. Implements Runnable::run() so the broker
@@ -140,7 +196,7 @@ class Broker : public sys::Runnable, public Plugin::Target,
/** Shut down the broker */
virtual void shutdown();
- void setStore (MessageStore*);
+ QPID_BROKER_EXTERN void setStore (boost::shared_ptr<MessageStore>& store);
MessageStore& getStore() { return *store; }
void setAcl (AclModule* _acl) {acl = _acl;}
AclModule* getAcl() { return acl; }
@@ -151,21 +207,29 @@ class Broker : public sys::Runnable, public Plugin::Target,
DtxManager& getDtxManager() { return dtxManager; }
DataDir& getDataDir() { return dataDir; }
Options& getOptions() { return config; }
+ QueueEvents& getQueueEvents() { return queueEvents; }
+
+ void setExpiryPolicy(const boost::intrusive_ptr<ExpiryPolicy>& e) { expiryPolicy = e; }
+ boost::intrusive_ptr<ExpiryPolicy> getExpiryPolicy() { return expiryPolicy; }
SessionManager& getSessionManager() { return sessionManager; }
+ const std::string& getFederationTag() const { return federationTag; }
management::ManagementObject* GetManagementObject (void) const;
management::Manageable* GetVhostObject (void) const;
- management::Manageable::status_t ManagementMethod (uint32_t methodId, management::Args& args);
-
+ management::Manageable::status_t ManagementMethod (uint32_t methodId,
+ management::Args& args,
+ std::string& text);
+
/** Add to the broker's protocolFactorys */
- void registerProtocolFactory(boost::shared_ptr<sys::ProtocolFactory>);
+ void registerProtocolFactory(const std::string& name, boost::shared_ptr<sys::ProtocolFactory>);
/** Accept connections */
- void accept();
+ QPID_BROKER_EXTERN void accept();
/** Create a connection to another broker. */
- void connect(const std::string& host, uint16_t port, bool useSsl,
+ void connect(const std::string& host, uint16_t port,
+ const std::string& transport,
boost::function2<void, int, std::string> failed,
sys::ConnectionCodec::Factory* =0);
/** Create a connection to another broker. */
@@ -173,16 +237,38 @@ class Broker : public sys::Runnable, public Plugin::Target,
boost::function2<void, int, std::string> failed,
sys::ConnectionCodec::Factory* =0);
- // TODO: There isn't a single ProtocolFactory so the use of the following needs to be fixed
- // For the present just return the first ProtocolFactory registered.
- boost::shared_ptr<sys::ProtocolFactory> getProtocolFactory() const;
+ /** Move messages from one queue to another.
+ A zero quantity means to move all messages
+ */
+ uint32_t queueMoveMessages( const std::string& srcQueue,
+ const std::string& destQueue,
+ uint32_t qty);
+
+ boost::shared_ptr<sys::ProtocolFactory> getProtocolFactory(const std::string& name = TCP_TRANSPORT) const;
/** Expose poller so plugins can register their descriptors. */
- boost::shared_ptr<sys::Poller> getPoller();
+ boost::shared_ptr<sys::Poller> getPoller();
+
+ boost::shared_ptr<sys::ConnectionCodec::Factory> getConnectionFactory() { return factory; }
+ void setConnectionFactory(boost::shared_ptr<sys::ConnectionCodec::Factory> f) { factory = f; }
+
+ sys::Timer& getTimer() { return timer; }
+
+ boost::function<std::vector<Url> ()> getKnownBrokers;
+
+ static QPID_BROKER_EXTERN const std::string TCP_TRANSPORT;
+
+ void setRecovery(bool set) { recovery = set; }
+ bool getRecovery() const { return recovery; }
+
+ void setClusterUpdatee(bool set) { clusterUpdatee = set; }
+ bool isClusterUpdatee() const { return clusterUpdatee; }
+
+ management::ManagementAgent* getManagementAgent() { return managementAgent.get(); }
+
+ ConnectionCounter& getConnectionCounter() {return connectionCounter;}
};
}}
-
-
#endif /*!_Broker_*/
diff --git a/cpp/src/qpid/broker/BrokerImportExport.h b/cpp/src/qpid/broker/BrokerImportExport.h
new file mode 100644
index 0000000000..4edf8c9844
--- /dev/null
+++ b/cpp/src/qpid/broker/BrokerImportExport.h
@@ -0,0 +1,33 @@
+#ifndef QPID_BROKER_IMPORT_EXPORT_H
+#define QPID_BROKER_IMPORT_EXPORT_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#if defined(WIN32) && !defined(QPID_BROKER_STATIC)
+#if defined(BROKER_EXPORT) || defined (qpidbroker_EXPORTS)
+#define QPID_BROKER_EXTERN __declspec(dllexport)
+#else
+#define QPID_BROKER_EXTERN __declspec(dllimport)
+#endif
+#else
+#define QPID_BROKER_EXTERN
+#endif
+
+#endif
diff --git a/cpp/src/qpid/broker/BrokerSingleton.cpp b/cpp/src/qpid/broker/BrokerSingleton.cpp
deleted file mode 100644
index 5ba8c9d1e1..0000000000
--- a/cpp/src/qpid/broker/BrokerSingleton.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "BrokerSingleton.h"
-
-namespace qpid {
-namespace broker {
-
-BrokerSingleton::BrokerSingleton() {
- if (broker.get() == 0)
- broker = Broker::create();
- boost::intrusive_ptr<Broker>::operator=(broker);
-}
-
-BrokerSingleton::~BrokerSingleton() {
- broker->shutdown();
-}
-
-boost::intrusive_ptr<Broker> BrokerSingleton::broker;
-
-}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/BrokerSingleton.h b/cpp/src/qpid/broker/BrokerSingleton.h
deleted file mode 100644
index 22b707506b..0000000000
--- a/cpp/src/qpid/broker/BrokerSingleton.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef _broker_BrokerSingleton_h
-#define _broker_BrokerSingleton_h
-
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "Broker.h"
-
-namespace qpid {
-namespace broker {
-
-/**
- * BrokerSingleton is a smart pointer to a process-wide singleton broker
- * started on an os-chosen port. The broker starts the first time
- * an instance of BrokerSingleton is created and runs untill the process exits.
- *
- * Useful for unit tests that want to share a broker between multiple
- * tests to reduce overhead of starting/stopping a broker for every test.
- *
- * Tests that need a new broker can create it directly.
- *
- * THREAD UNSAFE.
- */
-class BrokerSingleton : public boost::intrusive_ptr<Broker>
-{
- public:
- BrokerSingleton();
- ~BrokerSingleton();
- private:
- static boost::intrusive_ptr<Broker> broker;
-};
-
-}} // namespace qpid::broker
-
-
-
-#endif /*!_broker_BrokerSingleton_h*/
diff --git a/cpp/src/qpid/broker/Connection.cpp b/cpp/src/qpid/broker/Connection.cpp
index ab18d1f035..17de83e033 100644
--- a/cpp/src/qpid/broker/Connection.cpp
+++ b/cpp/src/qpid/broker/Connection.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -18,14 +18,17 @@
* under the License.
*
*/
-#include "Connection.h"
-#include "SessionState.h"
-#include "Bridge.h"
+#include "qpid/broker/Connection.h"
+#include "qpid/broker/SessionState.h"
+#include "qpid/broker/Bridge.h"
+#include "qpid/broker/Broker.h"
#include "qpid/log/Statement.h"
#include "qpid/ptr_map.h"
#include "qpid/framing/AMQP_ClientProxy.h"
-#include "qpid/agent/ManagementAgent.h"
+#include "qpid/framing/enum.h"
+#include "qmf/org/apache/qpid/broker/EventClientConnect.h"
+#include "qmf/org/apache/qpid/broker/EventClientDisconnect.h"
#include <boost/bind.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
@@ -34,30 +37,53 @@
#include <iostream>
#include <assert.h>
-using namespace boost;
using namespace qpid::sys;
using namespace qpid::framing;
-using namespace qpid::sys;
using qpid::ptr_map_ptr;
using qpid::management::ManagementAgent;
using qpid::management::ManagementObject;
using qpid::management::Manageable;
using qpid::management::Args;
+namespace _qmf = qmf::org::apache::qpid::broker;
namespace qpid {
namespace broker {
-Connection::Connection(ConnectionOutputHandler* out_, Broker& broker_, const std::string& mgmtId_, bool isLink_) :
+struct ConnectionTimeoutTask : public sys::TimerTask {
+ sys::Timer& timer;
+ Connection& connection;
+
+ ConnectionTimeoutTask(uint16_t hb, sys::Timer& t, Connection& c) :
+ TimerTask(Duration(hb*2*TIME_SEC)),
+ timer(t),
+ connection(c)
+ {}
+
+ void touch() {
+ restart();
+ }
+
+ void fire() {
+ // If we get here then we've not received any traffic in the timeout period
+ // Schedule closing the connection for the io thread
+ QPID_LOG(error, "Connection timed out: closing");
+ connection.abort();
+ }
+};
+
+Connection::Connection(ConnectionOutputHandler* out_, Broker& broker_, const std::string& mgmtId_, unsigned int ssf, bool isLink_, uint64_t objectId) :
ConnectionState(out_, broker_),
- receivedFn(boost::bind(&Connection::receivedImpl, this, _1)),
- closedFn(boost::bind(&Connection::closedImpl, this)),
- doOutputFn(boost::bind(&Connection::doOutputImpl, this)),
+ ssf(ssf),
adapter(*this, isLink_),
isLink(isLink_),
mgmtClosing(false),
mgmtId(mgmtId_),
mgmtObject(0),
- links(broker_.getLinks())
+ links(broker_.getLinks()),
+ agent(0),
+ timer(broker_.getTimer()),
+ errorListener(0),
+ shadow(false)
{
Manageable* parent = broker.GetVhostObject();
@@ -66,33 +92,48 @@ Connection::Connection(ConnectionOutputHandler* out_, Broker& broker_, const std
if (parent != 0)
{
- ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ agent = broker_.getManagementAgent();
- if (agent != 0)
- mgmtObject = new management::Connection(agent, this, parent, mgmtId, !isLink);
- agent->addObject(mgmtObject);
- }
- Plugin::initializeAll(*this); // Let plug-ins update extension points.
+ // TODO set last bool true if system connection
+ if (agent != 0) {
+ mgmtObject = new _qmf::Connection(agent, this, parent, mgmtId, !isLink, false);
+ agent->addObject(mgmtObject, objectId, true);
+ }
+ ConnectionState::setUrl(mgmtId);
+ }
+ if (!isShadow()) broker.getConnectionCounter().inc_connectionCount();
}
void Connection::requestIOProcessing(boost::function0<void> callback)
{
- ioCallback = callback;
- out->activateOutput();
+ ScopedLock<Mutex> l(ioCallbackLock);
+ ioCallbacks.push(callback);
+ out.activateOutput();
}
Connection::~Connection()
{
- if (mgmtObject != 0)
+ if (mgmtObject != 0) {
mgmtObject->resourceDestroy();
+ if (!isLink)
+ agent->raiseEvent(_qmf::EventClientDisconnect(mgmtId, ConnectionState::getUserId()));
+ }
if (isLink)
links.notifyClosed(mgmtId);
+
+ if (heartbeatTimer)
+ heartbeatTimer->cancel();
+ if (timeoutTimer)
+ timeoutTimer->cancel();
+
+ if (!isShadow()) broker.getConnectionCounter().dec_connectionCount();
}
-void Connection::received(framing::AMQFrame& frame) { receivedFn(frame); }
+void Connection::received(framing::AMQFrame& frame) {
+ // Received frame on connection so delay timeout
+ restartTimeout();
-void Connection::receivedImpl(framing::AMQFrame& frame){
if (frame.getChannel() == 0 && frame.getMethod()) {
adapter.handle(frame);
} else {
@@ -110,7 +151,7 @@ void Connection::recordFromServer(framing::AMQFrame& frame)
if (mgmtObject != 0)
{
mgmtObject->inc_framesToClient();
- mgmtObject->inc_bytesToClient(frame.size());
+ mgmtObject->inc_bytesToClient(frame.encodedSize());
}
}
@@ -119,7 +160,7 @@ void Connection::recordFromClient(framing::AMQFrame& frame)
if (mgmtObject != 0)
{
mgmtObject->inc_framesFromClient();
- mgmtObject->inc_bytesFromClient(frame.size());
+ mgmtObject->inc_bytesFromClient(frame.encodedSize());
}
}
@@ -156,29 +197,55 @@ void Connection::notifyConnectionForced(const string& text)
void Connection::setUserId(const string& userId)
{
ConnectionState::setUserId(userId);
- if (mgmtObject != 0)
+ if (mgmtObject != 0) {
mgmtObject->set_authIdentity(userId);
+ agent->raiseEvent(_qmf::EventClientConnect(mgmtId, userId));
+ }
}
-void Connection::close(
- ReplyCode code, const string& text, ClassId classId, MethodId methodId)
+void Connection::setFederationLink(bool b)
{
- adapter.close(code, text, classId, methodId);
+ ConnectionState::setFederationLink(b);
+ if (mgmtObject != 0)
+ mgmtObject->set_federationLink(b);
+}
+
+void Connection::close(connection::CloseCode code, const string& text)
+{
+ QPID_LOG_IF(error, code != connection::CLOSE_CODE_NORMAL, "Connection " << mgmtId << " closed by error: " << text << "(" << code << ")");
+ if (heartbeatTimer)
+ heartbeatTimer->cancel();
+ if (timeoutTimer)
+ timeoutTimer->cancel();
+ adapter.close(code, text);
+ //make sure we delete dangling pointers from outputTasks before deleting sessions
+ outputTasks.removeAll();
channels.clear();
getOutput().close();
}
+// Send a close to the client but keep the channels. Used by cluster.
+void Connection::sendClose() {
+ if (heartbeatTimer)
+ heartbeatTimer->cancel();
+ if (timeoutTimer)
+ timeoutTimer->cancel();
+ adapter.close(connection::CLOSE_CODE_NORMAL, "OK");
+ getOutput().close();
+}
+
void Connection::idleOut(){}
void Connection::idleIn(){}
-void Connection::closed() { closedFn(); }
-
-void Connection::closedImpl(){ // Physically closed, suspend open sessions.
+void Connection::closed(){ // Physically closed, suspend open sessions.
+ if (heartbeatTimer)
+ heartbeatTimer->cancel();
+ if (timeoutTimer)
+ timeoutTimer->cancel();
try {
- while (!channels.empty())
+ while (!channels.empty())
ptr_map_ptr(channels.begin())->handleDetach();
- // FIXME aconway 2008-07-15: exclusive is per-session not per-connection in 0-10.
while (!exclusiveQueues.empty()) {
Queue::shared_ptr q(exclusiveQueues.front());
q->releaseExclusiveOwnership();
@@ -195,27 +262,36 @@ void Connection::closedImpl(){ // Physically closed, suspend open sessions.
bool Connection::hasOutput() { return outputTasks.hasOutput(); }
-bool Connection::doOutput() { return doOutputFn(); }
-
-bool Connection::doOutputImpl() {
- try{
- if (ioCallback)
- ioCallback(); // Lend the IO thread for management processing
- ioCallback = 0;
-
- if (mgmtClosing)
- close(403, "Closed by Management Request", 0, 0);
- else
+bool Connection::doOutput() {
+ try {
+ {
+ ScopedLock<Mutex> l(ioCallbackLock);
+ while (!ioCallbacks.empty()) {
+ boost::function0<void> cb = ioCallbacks.front();
+ ioCallbacks.pop();
+ ScopedUnlock<Mutex> ul(ioCallbackLock);
+ cb(); // Lend the IO thread for management processing
+ }
+ }
+ if (mgmtClosing) {
+ closed();
+ close(connection::CLOSE_CODE_CONNECTION_FORCED, "Closed by Management Request");
+ } else {
//then do other output as needed:
return outputTasks.doOutput();
+ }
}catch(ConnectionException& e){
- close(e.code, e.getMessage(), 0, 0);
+ close(e.code, e.getMessage());
}catch(std::exception& e){
- close(541/*internal error*/, e.what(), 0, 0);
+ close(connection::CLOSE_CODE_CONNECTION_FORCED, e.what());
}
return false;
}
+void Connection::sendHeartbeat() {
+ adapter.heartbeat();
+}
+
void Connection::closeChannel(uint16_t id) {
ChannelMap::iterator i = channels.find(id);
if (i != channels.end()) channels.erase(i);
@@ -234,7 +310,7 @@ ManagementObject* Connection::GetManagementObject(void) const
return (ManagementObject*) mgmtObject;
}
-Manageable::status_t Connection::ManagementMethod(uint32_t methodId, Args&)
+Manageable::status_t Connection::ManagementMethod(uint32_t methodId, Args&, string&)
{
Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD;
@@ -242,10 +318,10 @@ Manageable::status_t Connection::ManagementMethod(uint32_t methodId, Args&)
switch (methodId)
{
- case management::Connection::METHOD_CLOSE :
+ case _qmf::Connection::METHOD_CLOSE :
mgmtClosing = true;
if (mgmtObject != 0) mgmtObject->set_closing(1);
- out->activateOutput();
+ out.activateOutput();
status = Manageable::STATUS_OK;
break;
}
@@ -253,5 +329,55 @@ Manageable::status_t Connection::ManagementMethod(uint32_t methodId, Args&)
return status;
}
-}}
+void Connection::setSecureConnection(SecureConnection* s)
+{
+ adapter.setSecureConnection(s);
+}
+
+struct ConnectionHeartbeatTask : public sys::TimerTask {
+ sys::Timer& timer;
+ Connection& connection;
+ ConnectionHeartbeatTask(uint16_t hb, sys::Timer& t, Connection& c) :
+ TimerTask(Duration(hb*TIME_SEC)),
+ timer(t),
+ connection(c)
+ {}
+
+ void fire() {
+ // Setup next firing
+ setupNextFire();
+ timer.add(this);
+
+ // Send Heartbeat
+ connection.sendHeartbeat();
+ }
+};
+void Connection::abort()
+{
+ // Make sure that we don't try to send a heartbeat as we're
+ // aborting the connection
+ if (heartbeatTimer)
+ heartbeatTimer->cancel();
+
+ out.abort();
+}
+
+void Connection::setHeartbeatInterval(uint16_t heartbeat)
+{
+ setHeartbeat(heartbeat);
+ if (heartbeat > 0 && !isShadow()) {
+ heartbeatTimer = new ConnectionHeartbeatTask(heartbeat, timer, *this);
+ timer.add(heartbeatTimer);
+ timeoutTimer = new ConnectionTimeoutTask(heartbeat, timer, *this);
+ timer.add(timeoutTimer);
+ }
+}
+
+void Connection::restartTimeout()
+{
+ if (timeoutTimer)
+ timeoutTimer->touch();
+}
+
+}}
diff --git a/cpp/src/qpid/broker/Connection.h b/cpp/src/qpid/broker/Connection.h
index 1367f3b9ca..66ede59df5 100644
--- a/cpp/src/qpid/broker/Connection.h
+++ b/cpp/src/qpid/broker/Connection.h
@@ -10,9 +10,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -25,52 +25,68 @@
#include <memory>
#include <sstream>
#include <vector>
+#include <queue>
#include <boost/ptr_container/ptr_map.hpp>
+#include "qpid/broker/ConnectionHandler.h"
+#include "qpid/broker/ConnectionState.h"
+#include "qpid/broker/SessionHandler.h"
+#include "qmf/org/apache/qpid/broker/Connection.h"
+#include "qpid/Exception.h"
+#include "qpid/RefCounted.h"
#include "qpid/framing/AMQFrame.h"
-#include "qpid/framing/AMQP_ServerOperations.h"
#include "qpid/framing/AMQP_ClientProxy.h"
+#include "qpid/framing/AMQP_ServerOperations.h"
+#include "qpid/framing/ProtocolVersion.h"
+#include "qpid/management/ManagementAgent.h"
+#include "qpid/management/Manageable.h"
+#include "qpid/ptr_map.h"
#include "qpid/sys/AggregateOutput.h"
-#include "qpid/sys/ConnectionOutputHandler.h"
#include "qpid/sys/ConnectionInputHandler.h"
-#include "qpid/sys/TimeoutHandler.h"
-#include "qpid/framing/ProtocolVersion.h"
-#include "Broker.h"
+#include "qpid/sys/ConnectionOutputHandler.h"
#include "qpid/sys/Socket.h"
-#include "qpid/Exception.h"
-#include "ConnectionHandler.h"
-#include "ConnectionState.h"
-#include "SessionHandler.h"
-#include "qpid/management/Manageable.h"
-#include "qpid/management/Connection.h"
-#include "qpid/Plugin.h"
-#include "qpid/RefCounted.h"
+#include "qpid/sys/TimeoutHandler.h"
+#include "qpid/sys/Mutex.h"
#include <boost/ptr_container/ptr_map.hpp>
+#include <boost/bind.hpp>
+
+#include <algorithm>
namespace qpid {
namespace broker {
+class Broker;
class LinkRegistry;
+class SecureConnection;
+struct ConnectionTimeoutTask;
-class Connection : public sys::ConnectionInputHandler,
+class Connection : public sys::ConnectionInputHandler,
public ConnectionState,
- public Plugin::Target,
public RefCounted
{
public:
- Connection(sys::ConnectionOutputHandler* out, Broker& broker, const std::string& mgmtId, bool isLink = false);
+ /**
+ * Listener that can be registered with a Connection to be informed of errors.
+ */
+ class ErrorListener
+ {
+ public:
+ virtual ~ErrorListener() {}
+ virtual void sessionError(uint16_t channel, const std::string&) = 0;
+ virtual void connectionError(const std::string&) = 0;
+ };
+
+ Connection(sys::ConnectionOutputHandler* out, Broker& broker, const std::string& mgmtId, unsigned int ssf,
+ bool isLink = false, uint64_t objectId = 0);
~Connection ();
/** Get the SessionHandler for channel. Create if it does not already exist */
SessionHandler& getChannel(framing::ChannelId channel);
/** Close the connection */
- void close(framing::ReplyCode code = 403,
- const string& text = string(),
- framing::ClassId classId = 0,
- framing::MethodId methodId = 0);
+ void close(framing::connection::CloseCode code, const string& text);
// ConnectionInputHandler methods
void received(framing::AMQFrame& frame);
@@ -85,7 +101,7 @@ class Connection : public sys::ConnectionInputHandler,
// Manageable entry points
management::ManagementObject* GetManagementObject (void) const;
management::Manageable::status_t
- ManagementMethod (uint32_t methodId, management::Args& args);
+ ManagementMethod (uint32_t methodId, management::Args& args, std::string&);
void requestIOProcessing (boost::function0<void>);
void recordFromServer (framing::AMQFrame& frame);
@@ -94,29 +110,60 @@ class Connection : public sys::ConnectionInputHandler,
std::string getAuthCredentials();
void notifyConnectionForced(const std::string& text);
void setUserId(const string& uid);
+ const std::string& getUserId() const { return ConnectionState::getUserId(); }
+ const std::string& getMgmtId() const { return mgmtId; }
+ management::ManagementAgent* getAgent() const { return agent; }
+ void setFederationLink(bool b);
+ /** Connection does not delete the listener. 0 resets. */
+ void setErrorListener(ErrorListener* l) { errorListener=l; }
+ ErrorListener* getErrorListener() { return errorListener; }
+
+ void setHeartbeatInterval(uint16_t heartbeat);
+ void sendHeartbeat();
+ void restartTimeout();
+ void abort();
+
+ template <class F> void eachSessionHandler(F f) {
+ for (ChannelMap::iterator i = channels.begin(); i != channels.end(); ++i)
+ f(*ptr_map_ptr(i));
+ }
- // Extension points: allow plugins to insert additional functionality.
- boost::function<void(framing::AMQFrame&)> receivedFn;
- boost::function<void ()> closedFn;
- boost::function<bool ()> doOutputFn;
+ void sendClose();
+ void setSecureConnection(SecureConnection* secured);
+
+ /** True if this is a shadow connection in a cluster. */
+ bool isShadow() { return shadow; }
+ /** Called by cluster to mark shadow connections */
+ void setShadow() { shadow = true; }
+
+ // Used by cluster to update connection status
+ sys::AggregateOutput& getOutputTasks() { return outputTasks; }
+
+ unsigned int getSSF() { return ssf; }
private:
typedef boost::ptr_map<framing::ChannelId, SessionHandler> ChannelMap;
typedef std::vector<Queue::shared_ptr>::iterator queue_iterator;
- void receivedImpl(framing::AMQFrame& frame);
- void closedImpl();
- bool doOutputImpl();
-
ChannelMap channels;
- framing::AMQP_ClientProxy::Connection* client;
+ unsigned int ssf;
ConnectionHandler adapter;
- bool isLink;
+ const bool isLink;
bool mgmtClosing;
const std::string mgmtId;
- boost::function0<void> ioCallback;
- management::Connection* mgmtObject;
+ sys::Mutex ioCallbackLock;
+ std::queue<boost::function0<void> > ioCallbacks;
+ qmf::org::apache::qpid::broker::Connection* mgmtObject;
LinkRegistry& links;
+ management::ManagementAgent* agent;
+ sys::Timer& timer;
+ boost::intrusive_ptr<sys::TimerTask> heartbeatTimer;
+ boost::intrusive_ptr<ConnectionTimeoutTask> timeoutTimer;
+ ErrorListener* errorListener;
+ bool shadow;
+
+ public:
+ qmf::org::apache::qpid::broker::Connection* getMgmtObject() { return mgmtObject; }
};
}}
diff --git a/cpp/src/qpid/broker/ConnectionFactory.cpp b/cpp/src/qpid/broker/ConnectionFactory.cpp
index 5de5a0230a..ffb0b34b95 100644
--- a/cpp/src/qpid/broker/ConnectionFactory.cpp
+++ b/cpp/src/qpid/broker/ConnectionFactory.cpp
@@ -18,30 +18,47 @@
* under the License.
*
*/
-#include "ConnectionFactory.h"
+#include "qpid/broker/ConnectionFactory.h"
#include "qpid/framing/ProtocolVersion.h"
#include "qpid/amqp_0_10/Connection.h"
+#include "qpid/broker/Connection.h"
+#include "qpid/log/Statement.h"
namespace qpid {
namespace broker {
using framing::ProtocolVersion;
+typedef std::auto_ptr<amqp_0_10::Connection> ConnectionPtr;
+typedef std::auto_ptr<sys::ConnectionInputHandler> InputPtr;
ConnectionFactory::ConnectionFactory(Broker& b) : broker(b) {}
ConnectionFactory::~ConnectionFactory() {}
sys::ConnectionCodec*
-ConnectionFactory::create(ProtocolVersion v, sys::OutputControl& out, const std::string& id) {
- if (v == ProtocolVersion(0, 10))
- return new amqp_0_10::Connection(out, broker, id);
+ConnectionFactory::create(ProtocolVersion v, sys::OutputControl& out, const std::string& id,
+ unsigned int ) {
+ if (broker.getConnectionCounter().allowConnection())
+ {
+ QPID_LOG(error, "Client max connection count limit exceeded: " << broker.getOptions().maxConnections << " connection refused");
+ return 0;
+ }
+ if (v == ProtocolVersion(0, 10)) {
+ ConnectionPtr c(new amqp_0_10::Connection(out, id, false));
+ c->setInputHandler(InputPtr(new broker::Connection(c.get(), broker, id, false)));
+ return c.release();
+ }
return 0;
}
sys::ConnectionCodec*
-ConnectionFactory::create(sys::OutputControl& out, const std::string& id) {
+ConnectionFactory::create(sys::OutputControl& out, const std::string& id,
+ unsigned int) {
// used to create connections from one broker to another
- return new amqp_0_10::Connection(out, broker, id, true);
+ ConnectionPtr c(new amqp_0_10::Connection(out, id, true));
+ c->setInputHandler(InputPtr(new broker::Connection(c.get(), broker, id, true)));
+ return c.release();
}
+
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/ConnectionFactory.h b/cpp/src/qpid/broker/ConnectionFactory.h
index 5797495054..d812292ad1 100644
--- a/cpp/src/qpid/broker/ConnectionFactory.h
+++ b/cpp/src/qpid/broker/ConnectionFactory.h
@@ -27,17 +27,20 @@ namespace qpid {
namespace broker {
class Broker;
-class ConnectionFactory : public sys::ConnectionCodec::Factory {
+class ConnectionFactory : public sys::ConnectionCodec::Factory
+{
public:
ConnectionFactory(Broker& b);
virtual ~ConnectionFactory();
sys::ConnectionCodec*
- create(framing::ProtocolVersion, sys::OutputControl&, const std::string& id);
+ create(framing::ProtocolVersion, sys::OutputControl&, const std::string& id,
+ unsigned int conn_ssf);
sys::ConnectionCodec*
- create(sys::OutputControl&, const std::string& id);
+ create(sys::OutputControl&, const std::string& id,
+ unsigned int conn_ssf);
private:
Broker& broker;
diff --git a/cpp/src/qpid/broker/ConnectionHandler.cpp b/cpp/src/qpid/broker/ConnectionHandler.cpp
index 77a4d1a3de..50a5aff2c9 100644
--- a/cpp/src/qpid/broker/ConnectionHandler.cpp
+++ b/cpp/src/qpid/broker/ConnectionHandler.cpp
@@ -8,9 +8,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -20,70 +20,91 @@
*
*/
-#include "config.h"
-
-#include "ConnectionHandler.h"
-#include "Connection.h"
-#include "qpid/framing/ClientInvoker.h"
-#include "qpid/framing/ServerInvoker.h"
-#include "qpid/framing/constants.h"
+#include "qpid/broker/ConnectionHandler.h"
+#include "qpid/broker/Connection.h"
+#include "qpid/broker/SecureConnection.h"
+#include "qpid/Url.h"
+#include "qpid/framing/AllInvoker.h"
+#include "qpid/framing/enum.h"
#include "qpid/log/Statement.h"
+#include "qpid/sys/SecurityLayer.h"
+#include "qpid/broker/AclModule.h"
+#include "qmf/org/apache/qpid/broker/EventClientConnectFail.h"
using namespace qpid;
using namespace qpid::broker;
using namespace qpid::framing;
+using qpid::sys::SecurityLayer;
+namespace _qmf = qmf::org::apache::qpid::broker;
-
-namespace
+namespace
{
const std::string ANONYMOUS = "ANONYMOUS";
const std::string PLAIN = "PLAIN";
const std::string en_US = "en_US";
+const std::string QPID_FED_LINK = "qpid.fed_link";
+const std::string QPID_FED_TAG = "qpid.federation_tag";
+const std::string SESSION_FLOW_CONTROL("qpid.session_flow");
+const std::string CLIENT_PROCESS_NAME("qpid.client_process");
+const std::string CLIENT_PID("qpid.client_pid");
+const std::string CLIENT_PPID("qpid.client_ppid");
+const int SESSION_FLOW_CONTROL_VER = 1;
}
-void ConnectionHandler::close(ReplyCode code, const string& text, ClassId, MethodId)
+void ConnectionHandler::close(connection::CloseCode code, const string& text)
{
- handler->client.close(code, text);
+ handler->proxy.close(code, text);
+}
+
+void ConnectionHandler::heartbeat()
+{
+ handler->proxy.heartbeat();
}
void ConnectionHandler::handle(framing::AMQFrame& frame)
{
AMQMethodBody* method=frame.getBody()->getMethod();
+ Connection::ErrorListener* errorListener = handler->connection.getErrorListener();
try{
- bool handled = false;
- if (handler->serverMode) {
- handled = invoke(static_cast<AMQP_ServerOperations::ConnectionHandler&>(*handler.get()), *method);
- } else {
- handled = invoke(static_cast<AMQP_ClientOperations::ConnectionHandler&>(*handler.get()), *method);
- }
- if (!handled) {
+ if (!invoke(static_cast<AMQP_AllOperations::ConnectionHandler&>(*handler.get()), *method)) {
handler->connection.getChannel(frame.getChannel()).in(frame);
}
-
}catch(ConnectionException& e){
- handler->client.close(e.code, e.what());
+ if (errorListener) errorListener->connectionError(e.what());
+ handler->proxy.close(e.code, e.what());
}catch(std::exception& e){
- handler->client.close(541/*internal error*/, e.what());
+ if (errorListener) errorListener->connectionError(e.what());
+ handler->proxy.close(541/*internal error*/, e.what());
}
}
+void ConnectionHandler::setSecureConnection(SecureConnection* secured)
+{
+ handler->secured = secured;
+}
+
ConnectionHandler::ConnectionHandler(Connection& connection, bool isClient) : handler(new Handler(connection, isClient)) {}
ConnectionHandler::Handler::Handler(Connection& c, bool isClient) :
- client(c.getOutput()), server(c.getOutput()),
- connection(c), serverMode(!isClient)
+ proxy(c.getOutput()),
+ connection(c), serverMode(!isClient), acl(0), secured(0)
{
if (serverMode) {
+
+ acl = connection.getBroker().getAcl();
+
FieldTable properties;
Array mechanisms(0x95);
-
+
+ properties.setString(QPID_FED_TAG, connection.getBroker().getFederationTag());
+
authenticator = SaslAuthenticator::createAuthenticator(c);
authenticator->getMechanisms(mechanisms);
-
+
Array locales(0x95);
boost::shared_ptr<FieldValue> l(new Str16Value(en_US));
locales.add(l);
- client.start(properties, mechanisms, locales);
+ proxy.start(properties, mechanisms, locales);
}
}
@@ -91,65 +112,138 @@ ConnectionHandler::Handler::Handler(Connection& c, bool isClient) :
ConnectionHandler::Handler::~Handler() {}
-void ConnectionHandler::Handler::startOk(const framing::FieldTable& /*clientProperties*/,
- const string& mechanism,
+void ConnectionHandler::Handler::startOk(const framing::FieldTable& clientProperties,
+ const string& mechanism,
const string& response,
const string& /*locale*/)
{
- authenticator->start(mechanism, response);
+ try {
+ authenticator->start(mechanism, response);
+ } catch (std::exception& /*e*/) {
+ management::ManagementAgent* agent = connection.getAgent();
+ if (agent) {
+ string error;
+ string uid;
+ authenticator->getError(error);
+ authenticator->getUid(uid);
+ agent->raiseEvent(_qmf::EventClientConnectFail(connection.getMgmtId(), uid, error));
+ }
+ throw;
+ }
+ connection.setFederationLink(clientProperties.get(QPID_FED_LINK));
+ connection.setFederationPeerTag(clientProperties.getAsString(QPID_FED_TAG));
+ if (connection.isFederationLink()) {
+ if (acl && !acl->authorise(connection.getUserId(),acl::ACT_CREATE,acl::OBJ_LINK,"")){
+ proxy.close(framing::connection::CLOSE_CODE_CONNECTION_FORCED,"ACL denied creating a federation link");
+ return;
+ }
+ QPID_LOG(info, "Connection is a federation link");
+ }
+ if (clientProperties.getAsInt(SESSION_FLOW_CONTROL) == SESSION_FLOW_CONTROL_VER) {
+ connection.setClientThrottling();
+ }
+
+ if (connection.getMgmtObject() != 0) {
+ string procName = clientProperties.getAsString(CLIENT_PROCESS_NAME);
+ uint32_t pid = clientProperties.getAsInt(CLIENT_PID);
+ uint32_t ppid = clientProperties.getAsInt(CLIENT_PPID);
+
+ if (!procName.empty())
+ connection.getMgmtObject()->set_remoteProcessName(procName);
+ if (pid != 0)
+ connection.getMgmtObject()->set_remotePid(pid);
+ if (ppid != 0)
+ connection.getMgmtObject()->set_remoteParentPid(ppid);
+ }
}
-
+
void ConnectionHandler::Handler::secureOk(const string& response)
{
- authenticator->step(response);
+ try {
+ authenticator->step(response);
+ } catch (std::exception& /*e*/) {
+ management::ManagementAgent* agent = connection.getAgent();
+ if (agent) {
+ string error;
+ string uid;
+ authenticator->getError(error);
+ authenticator->getUid(uid);
+ agent->raiseEvent(_qmf::EventClientConnectFail(connection.getMgmtId(), uid, error));
+ }
+ throw;
+ }
}
-
+
void ConnectionHandler::Handler::tuneOk(uint16_t /*channelmax*/,
uint16_t framemax, uint16_t heartbeat)
{
connection.setFrameMax(framemax);
- connection.setHeartbeat(heartbeat);
+ connection.setHeartbeatInterval(heartbeat);
}
-
+
void ConnectionHandler::Handler::open(const string& /*virtualHost*/,
const framing::Array& /*capabilities*/, bool /*insist*/)
{
- framing::Array knownhosts;
- client.openOk(knownhosts);
+ std::vector<Url> urls = connection.broker.getKnownBrokers();
+ framing::Array array(0x95); // str16 array
+ for (std::vector<Url>::iterator i = urls.begin(); i < urls.end(); ++i)
+ array.add(boost::shared_ptr<Str16Value>(new Str16Value(i->str())));
+ proxy.openOk(array);
+
+ //install security layer if one has been negotiated:
+ if (secured) {
+ std::auto_ptr<SecurityLayer> sl = authenticator->getSecurityLayer(connection.getFrameMax());
+ if (sl.get()) secured->activateSecurityLayer(sl);
+ }
}
-
+
void ConnectionHandler::Handler::close(uint16_t replyCode, const string& replyText)
{
if (replyCode != 200) {
QPID_LOG(warning, "Client closed connection with " << replyCode << ": " << replyText);
}
- if (replyCode == framing::connection::CONNECTION_FORCED)
+ if (replyCode == framing::connection::CLOSE_CODE_CONNECTION_FORCED)
connection.notifyConnectionForced(replyText);
- client.closeOk();
+ proxy.closeOk();
connection.getOutput().close();
-}
-
+}
+
void ConnectionHandler::Handler::closeOk(){
connection.getOutput().close();
-}
+}
+void ConnectionHandler::Handler::heartbeat(){
+ // For general case, do nothing - the purpose of heartbeats is
+ // just to make sure that there is some traffic on the connection
+ // within the heart beat interval, we check for the traffic and
+ // don't need to do anything in response to heartbeats. The
+ // exception is when we are in fact the client to another broker
+ // (i.e. an inter-broker link), in which case we echo the
+ // heartbeat back to the peer
+ if (!serverMode) proxy.heartbeat();
+}
-void ConnectionHandler::Handler::start(const FieldTable& /*serverProperties*/,
+void ConnectionHandler::Handler::start(const FieldTable& serverProperties,
const framing::Array& /*mechanisms*/,
const framing::Array& /*locales*/)
{
string mechanism = connection.getAuthMechanism();
string response = connection.getAuthCredentials();
-
- server.startOk(FieldTable(), mechanism, response, en_US);
+
+ connection.setFederationPeerTag(serverProperties.getAsString(QPID_FED_TAG));
+
+ FieldTable ft;
+ ft.setInt(QPID_FED_LINK,1);
+ ft.setString(QPID_FED_TAG, connection.getBroker().getFederationTag());
+ proxy.startOk(ft, mechanism, response, en_US);
}
void ConnectionHandler::Handler::secure(const string& /*challenge*/)
{
- server.secureOk("");
+ proxy.secureOk("");
}
void ConnectionHandler::Handler::tune(uint16_t channelMax,
@@ -159,15 +253,19 @@ void ConnectionHandler::Handler::tune(uint16_t channelMax,
{
connection.setFrameMax(frameMax);
connection.setHeartbeat(heartbeatMax);
- server.tuneOk(channelMax, frameMax, heartbeatMax);
- server.open("/", Array(), true);
+ proxy.tuneOk(channelMax, frameMax, heartbeatMax);
+ proxy.open("/", Array(), true);
}
-void ConnectionHandler::Handler::openOk(const framing::Array& /*knownHosts*/)
+void ConnectionHandler::Handler::openOk(const framing::Array& knownHosts)
{
+ for (Array::ValueVector::const_iterator i = knownHosts.begin(); i != knownHosts.end(); ++i) {
+ Url url((*i)->get<std::string>());
+ connection.getKnownHosts().push_back(url);
+ }
}
void ConnectionHandler::Handler::redirect(const string& /*host*/, const framing::Array& /*knownHosts*/)
{
-
+
}
diff --git a/cpp/src/qpid/broker/ConnectionHandler.h b/cpp/src/qpid/broker/ConnectionHandler.h
index a04936a943..d74f65da36 100644
--- a/cpp/src/qpid/broker/ConnectionHandler.h
+++ b/cpp/src/qpid/broker/ConnectionHandler.h
@@ -22,68 +22,71 @@
#define _ConnectionAdapter_
#include <memory>
-#include "SaslAuthenticator.h"
+#include "qpid/broker/SaslAuthenticator.h"
#include "qpid/framing/amqp_types.h"
#include "qpid/framing/AMQFrame.h"
-#include "qpid/framing/AMQP_ClientOperations.h"
-#include "qpid/framing/AMQP_ClientProxy.h"
-#include "qpid/framing/AMQP_ServerOperations.h"
-#include "qpid/framing/AMQP_ServerProxy.h"
+#include "qpid/framing/AMQP_AllOperations.h"
+#include "qpid/framing/AMQP_AllProxy.h"
+#include "qpid/framing/enum.h"
#include "qpid/framing/FrameHandler.h"
#include "qpid/framing/ProtocolInitiation.h"
#include "qpid/framing/ProtocolVersion.h"
#include "qpid/Exception.h"
+#include "qpid/broker/AclModule.h"
namespace qpid {
namespace broker {
class Connection;
+class SecureConnection;
class ConnectionHandler : public framing::FrameHandler
{
- struct Handler : public framing::AMQP_ServerOperations::ConnectionHandler,
- public framing::AMQP_ClientOperations::ConnectionHandler
+ struct Handler : public framing::AMQP_AllOperations::ConnectionHandler
{
- framing::AMQP_ClientProxy::Connection client;
- framing::AMQP_ServerProxy::Connection server;
+ framing::AMQP_AllProxy::Connection proxy;
Connection& connection;
bool serverMode;
std::auto_ptr<SaslAuthenticator> authenticator;
-
+ AclModule* acl;
+ SecureConnection* secured;
+
Handler(Connection& connection, bool isClient);
~Handler();
void startOk(const qpid::framing::FieldTable& clientProperties,
const std::string& mechanism, const std::string& response,
- const std::string& locale);
- void secureOk(const std::string& response);
- void tuneOk(uint16_t channelMax, uint16_t frameMax, uint16_t heartbeat);
- void heartbeat() {}
+ const std::string& locale);
+ void secureOk(const std::string& response);
+ void tuneOk(uint16_t channelMax, uint16_t frameMax, uint16_t heartbeat);
+ void heartbeat();
void open(const std::string& virtualHost,
- const framing::Array& capabilities, bool insist);
- void close(uint16_t replyCode, const std::string& replyText);
- void closeOk();
+ const framing::Array& capabilities, bool insist);
+ void close(uint16_t replyCode, const std::string& replyText);
+ void closeOk();
void start(const qpid::framing::FieldTable& serverProperties,
const framing::Array& mechanisms,
const framing::Array& locales);
-
+
void secure(const std::string& challenge);
-
+
void tune(uint16_t channelMax,
uint16_t frameMax,
uint16_t heartbeatMin,
uint16_t heartbeatMax);
-
+
void openOk(const framing::Array& knownHosts);
-
- void redirect(const std::string& host, const framing::Array& knownHosts);
+
+ void redirect(const std::string& host, const framing::Array& knownHosts);
};
std::auto_ptr<Handler> handler;
public:
ConnectionHandler(Connection& connection, bool isClient);
- void close(framing::ReplyCode code, const std::string& text, framing::ClassId classId, framing::MethodId methodId);
+ void close(framing::connection::CloseCode code, const std::string& text);
+ void heartbeat();
void handle(framing::AMQFrame& frame);
+ void setSecureConnection(SecureConnection* secured);
};
diff --git a/cpp/src/qpid/broker/ConnectionState.h b/cpp/src/qpid/broker/ConnectionState.h
index c9cf6ece8d..77ac5a59b0 100644
--- a/cpp/src/qpid/broker/ConnectionState.h
+++ b/cpp/src/qpid/broker/ConnectionState.h
@@ -24,61 +24,97 @@
#include <vector>
#include "qpid/sys/AggregateOutput.h"
-#include "qpid/sys/ConnectionOutputHandler.h"
+#include "qpid/sys/ConnectionOutputHandlerPtr.h"
#include "qpid/framing/ProtocolVersion.h"
#include "qpid/management/Manageable.h"
-#include "Broker.h"
+#include "qpid/Url.h"
+#include "qpid/broker/Broker.h"
namespace qpid {
namespace broker {
class ConnectionState : public ConnectionToken, public management::Manageable
{
+ protected:
+ sys::ConnectionOutputHandlerPtr out;
+
public:
- ConnectionState(qpid::sys::ConnectionOutputHandler* o, Broker& b) :
- broker(b),
- outputTasks(*o),
- out(o),
- framemax(65535),
+ ConnectionState(qpid::sys::ConnectionOutputHandler* o, Broker& b) :
+ out(o),
+ broker(b),
+ outputTasks(out),
+ framemax(65535),
heartbeat(0),
- stagingThreshold(broker.getStagingThreshold())
- {}
-
-
+ heartbeatmax(120),
+ stagingThreshold(broker.getStagingThreshold()),
+ federationLink(true),
+ clientSupportsThrottling(false),
+ clusterOrderOut(0)
+ {}
virtual ~ConnectionState () {}
uint32_t getFrameMax() const { return framemax; }
uint16_t getHeartbeat() const { return heartbeat; }
+ uint16_t getHeartbeatMax() const { return heartbeatmax; }
uint64_t getStagingThreshold() const { return stagingThreshold; }
- void setFrameMax(uint32_t fm) { framemax = fm; }
+ void setFrameMax(uint32_t fm) { framemax = std::max(fm, (uint32_t) 4096); }
void setHeartbeat(uint16_t hb) { heartbeat = hb; }
+ void setHeartbeatMax(uint16_t hbm) { heartbeatmax = hbm; }
void setStagingThreshold(uint64_t st) { stagingThreshold = st; }
virtual void setUserId(const string& uid) { userId = uid; }
const string& getUserId() const { return userId; }
+
+ void setUrl(const string& _url) { url = _url; }
+ const string& getUrl() const { return url; }
+
+ void setFederationLink(bool b) { federationLink = b; }
+ bool isFederationLink() const { return federationLink; }
+ void setFederationPeerTag(const string& tag) { federationPeerTag = string(tag); }
+ const string& getFederationPeerTag() const { return federationPeerTag; }
+ std::vector<Url>& getKnownHosts() { return knownHosts; }
+ void setClientThrottling(bool set=true) { clientSupportsThrottling = set; }
+ bool getClientThrottling() const { return clientSupportsThrottling; }
+
Broker& getBroker() { return broker; }
Broker& broker;
std::vector<Queue::shared_ptr> exclusiveQueues;
-
+
//contained output tasks
sys::AggregateOutput outputTasks;
- sys::ConnectionOutputHandler& getOutput() const { return *out; }
+ sys::ConnectionOutputHandler& getOutput() { return out; }
framing::ProtocolVersion getVersion() const { return version; }
+ void setOutputHandler(qpid::sys::ConnectionOutputHandler* o) { out.set(o); }
+
+ /**
+ * If the broker is part of a cluster, this is a handler provided
+ * by cluster code. It ensures consistent ordering of commands
+ * that are sent based on criteria that are not predictably
+ * ordered cluster-wide, e.g. a timer firing.
+ */
+ framing::FrameHandler* getClusterOrderOutput() { return clusterOrderOut; }
+ void setClusterOrderOutput(framing::FrameHandler& fh) { clusterOrderOut = &fh; }
- void setOutputHandler(qpid::sys::ConnectionOutputHandler* o) { out = o; }
+ virtual void requestIOProcessing (boost::function0<void>) = 0;
protected:
framing::ProtocolVersion version;
- sys::ConnectionOutputHandler* out;
uint32_t framemax;
uint16_t heartbeat;
+ uint16_t heartbeatmax;
uint64_t stagingThreshold;
string userId;
+ string url;
+ bool federationLink;
+ string federationPeerTag;
+ std::vector<Url> knownHosts;
+ bool clientSupportsThrottling;
+ framing::FrameHandler* clusterOrderOut;
};
}}
diff --git a/cpp/src/qpid/broker/ConnectionToken.h b/cpp/src/qpid/broker/ConnectionToken.h
index 0e3b301897..9b40383c80 100644
--- a/cpp/src/qpid/broker/ConnectionToken.h
+++ b/cpp/src/qpid/broker/ConnectionToken.h
@@ -21,7 +21,7 @@
#ifndef _ConnectionToken_
#define _ConnectionToken_
-#include "OwnershipToken.h"
+#include "qpid/broker/OwnershipToken.h"
namespace qpid {
namespace broker {
/**
diff --git a/cpp/src/qpid/broker/Consumer.h b/cpp/src/qpid/broker/Consumer.h
index 4274ce823e..b96443fa7c 100644
--- a/cpp/src/qpid/broker/Consumer.h
+++ b/cpp/src/qpid/broker/Consumer.h
@@ -21,47 +21,33 @@
#ifndef _Consumer_
#define _Consumer_
-namespace qpid {
- namespace broker {
- class Queue;
-}}
-
-#include "Message.h"
-#include "OwnershipToken.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/QueuedMessage.h"
+#include "qpid/broker/OwnershipToken.h"
namespace qpid {
- namespace broker {
-
- struct QueuedMessage
- {
- boost::intrusive_ptr<Message> payload;
- framing::SequenceNumber position;
- Queue* queue;
-
- QueuedMessage(Queue* q, boost::intrusive_ptr<Message> msg, framing::SequenceNumber sn) :
- payload(msg), position(sn), queue(q) {}
- QueuedMessage(Queue* q) : queue(q) {}
- };
-
+namespace broker {
+
+class Queue;
+
+class Consumer {
+ const bool acquires;
+ public:
+ typedef boost::shared_ptr<Consumer> shared_ptr;
+
+ framing::SequenceNumber position;
+
+ Consumer(bool preAcquires = true) : acquires(preAcquires) {}
+ bool preAcquires() const { return acquires; }
+ virtual bool deliver(QueuedMessage& msg) = 0;
+ virtual void notify() = 0;
+ virtual bool filter(boost::intrusive_ptr<Message>) { return true; }
+ virtual bool accept(boost::intrusive_ptr<Message>) { return true; }
+ virtual OwnershipToken* getSession() = 0;
+ virtual ~Consumer(){}
+};
- class Consumer {
- const bool acquires;
- public:
- typedef shared_ptr<Consumer> ptr;
-
- framing::SequenceNumber position;
-
- Consumer(bool preAcquires = true) : acquires(preAcquires) {}
- bool preAcquires() const { return acquires; }
- virtual bool deliver(QueuedMessage& msg) = 0;
- virtual void notify() = 0;
- virtual bool filter(boost::intrusive_ptr<Message>) { return true; }
- virtual bool accept(boost::intrusive_ptr<Message>) { return true; }
- virtual OwnershipToken* getSession() = 0;
- virtual ~Consumer(){}
- };
- }
-}
+}}
#endif
diff --git a/cpp/src/qpid/broker/Daemon.cpp b/cpp/src/qpid/broker/Daemon.cpp
index c311730f76..b30e5f18cb 100644
--- a/cpp/src/qpid/broker/Daemon.cpp
+++ b/cpp/src/qpid/broker/Daemon.cpp
@@ -15,10 +15,16 @@
* limitations under the License.
*
*/
-#include "Daemon.h"
+
+/*
+ * TODO: Note this is really a Posix specific implementation and so should be
+ * refactored together with windows/QpiddBroker into a more coherent daemon driver/
+ * platform specific split
+ */
+#include "qpid/broker/Daemon.h"
#include "qpid/log/Statement.h"
#include "qpid/Exception.h"
-#include "qpid/sys/LockFile.h"
+#include "qpid/sys/posix/PidFile.h"
#include <errno.h>
#include <fcntl.h>
@@ -31,7 +37,7 @@ namespace qpid {
namespace broker {
using namespace std;
-using qpid::sys::LockFile;
+using qpid::sys::PidFile;
Daemon::Daemon(std::string _pidDir) : pidDir(_pidDir) {
struct stat s;
@@ -85,12 +91,13 @@ void Daemon::fork()
child();
}
catch (const exception& e) {
- QPID_LOG(critical, "Daemon startup failed: " << e.what());
+ QPID_LOG(critical, "Unexpected error: " << e.what());
uint16_t port = 0;
- write(pipeFds[1], &port, sizeof(uint16_t));
+ int unused_ret; //Supress warning about ignoring return value.
+ unused_ret = write(pipeFds[1], &port, sizeof(uint16_t));
std::string pipeFailureMessage = e.what();
- write ( pipeFds[1],
+ unused_ret = write ( pipeFds[1],
pipeFailureMessage.c_str(),
strlen(pipeFailureMessage.c_str())
);
@@ -108,52 +115,61 @@ Daemon::~Daemon() {
}
uint16_t Daemon::wait(int timeout) { // parent waits for child.
- errno = 0;
- struct timeval tv;
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
-
- /*
- * Rewritten using low-level IO, for compatibility
- * with earlier Boost versions, i.e. 103200.
- */
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(pipeFds[0], &fds);
- int n=select(FD_SETSIZE, &fds, 0, 0, &tv);
- if(n==0) throw Exception("Timed out waiting for daemon");
- if(n<0) throw ErrnoException("Error waiting for daemon");
- uint16_t port = 0;
- /*
- * Read the child's port number from the pipe.
- */
- int desired_read = sizeof(uint16_t);
- if ( desired_read > ::read(pipeFds[0], & port, desired_read) ) {
- throw Exception("Cannot write lock file "+lockFile);
+ try {
+ errno = 0;
+ struct timeval tv;
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ /*
+ * Rewritten using low-level IO, for compatibility
+ * with earlier Boost versions, i.e. 103200.
+ */
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(pipeFds[0], &fds);
+ int n=select(FD_SETSIZE, &fds, 0, 0, &tv);
+ if(n==0) throw Exception("Timed out waiting for daemon (If store recovery is in progress, use longer wait time)");
+ if(n<0) throw ErrnoException("Error waiting for daemon");
+ uint16_t port = 0;
+ /*
+ * Read the child's port number from the pipe.
+ */
+ int desired_read = sizeof(uint16_t);
+ if ( desired_read > ::read(pipeFds[0], & port, desired_read) )
+ throw Exception("Cannot read from child process.");
+
+ /*
+ * If the port number is 0, the child has put an error message
+ * on the pipe. Get it and throw it.
+ */
+ if ( 0 == port ) {
+ // Skip whitespace
+ char c = ' ';
+ while ( isspace(c) ) {
+ if ( 1 > ::read(pipeFds[0], &c, 1) )
+ throw Exception("Child port == 0, and no error message on pipe.");
+ }
+
+ // Get Message
+ string errmsg;
+ do {
+ errmsg += c;
+ } while (::read(pipeFds[0], &c, 1));
+ throw Exception("Daemon startup failed"+
+ (errmsg.empty() ? string(".") : ": " + errmsg));
+ }
+ return port;
+ }
+ catch (const std::exception& e) {
+ // Print directly to cerr. The caller will catch and log the
+ // exception, but in the case of a daemon parent process we
+ // also need to be sure the error goes to stderr. A
+ // dameon's logging configuration normally does not log to
+ // stderr.
+ std::cerr << e.what() << endl;
+ throw;
}
-
- /*
- * If the port number is 0, the child has put an error message
- * on the pipe. Get it and throw it.
- */
- if ( 0 == port ) {
- // Skip whitespace
- char c = ' ';
- while ( isspace(c) ) {
- if ( 1 > ::read(pipeFds[0], &c, 1) )
- throw Exception("Child port == 0, and no error message on pipe.");
- }
-
- // Get Message
- string errmsg;
- do {
- errmsg += c;
- } while (::read(pipeFds[0], &c, 1));
- throw Exception("Daemon startup failed"+
- (errmsg.empty() ? string(".") : ": " + errmsg));
- }
-
- return port;
}
@@ -166,25 +182,17 @@ uint16_t Daemon::wait(int timeout) { // parent waits for child.
*/
void Daemon::ready(uint16_t port) { // child
lockFile = pidFile(pidDir, port);
- LockFile lf(lockFile, true);
+ PidFile lf(lockFile, true);
/*
- * Rewritten using low-level IO, for compatibility
- * with earlier Boost versions, i.e. 103200.
- */
- /*
* Write the PID to the lockfile.
*/
- pid_t pid = getpid();
- int desired_write = sizeof(pid_t);
- if ( desired_write > ::write(lf.fd, & pid, desired_write) ) {
- throw Exception("Cannot write lock file "+lockFile);
- }
+ lf.writePid();
/*
* Write the port number to the parent.
*/
- desired_write = sizeof(uint16_t);
+ int desired_write = sizeof(uint16_t);
if ( desired_write > ::write(pipeFds[1], & port, desired_write) ) {
throw Exception("Error writing to parent." );
}
@@ -198,17 +206,8 @@ void Daemon::ready(uint16_t port) { // child
*/
pid_t Daemon::getPid(string _pidDir, uint16_t port) {
string name = pidFile(_pidDir, port);
- LockFile lf(name, false);
- pid_t pid;
-
- /*
- * Rewritten using low-level IO, for compatibility
- * with earlier Boost versions, i.e. 103200.
- */
- int desired_read = sizeof(pid_t);
- if ( desired_read > ::read(lf.fd, & pid, desired_read) ) {
- throw Exception("Cannot read lock file " + name);
- }
+ PidFile lf(name, false);
+ pid_t pid = lf.readPid();
if (kill(pid, 0) < 0 && errno != EPERM) {
unlink(name.c_str());
throw Exception("Removing stale lock file "+name);
diff --git a/cpp/src/qpid/broker/Daemon.h b/cpp/src/qpid/broker/Daemon.h
index 98468debb7..a9cd98bce2 100644
--- a/cpp/src/qpid/broker/Daemon.h
+++ b/cpp/src/qpid/broker/Daemon.h
@@ -19,10 +19,12 @@
*
*/
-#include <string>
+#include "qpid/sys/IntegerTypes.h"
#include <boost/scoped_ptr.hpp>
#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
+#include <string>
+
namespace qpid {
namespace broker {
diff --git a/cpp/src/qpid/broker/Deliverable.h b/cpp/src/qpid/broker/Deliverable.h
index c40780c4ae..433469a212 100644
--- a/cpp/src/qpid/broker/Deliverable.h
+++ b/cpp/src/qpid/broker/Deliverable.h
@@ -21,8 +21,8 @@
#ifndef _Deliverable_
#define _Deliverable_
-#include "Queue.h"
-#include "Message.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/Message.h"
namespace qpid {
namespace broker {
@@ -33,7 +33,7 @@ namespace qpid {
virtual Message& getMessage() = 0;
- virtual void deliverTo(Queue::shared_ptr& queue) = 0;
+ virtual void deliverTo(const boost::shared_ptr<Queue>& queue) = 0;
virtual uint64_t contentSize() { return 0; }
virtual ~Deliverable(){}
};
diff --git a/cpp/src/qpid/broker/DeliverableMessage.cpp b/cpp/src/qpid/broker/DeliverableMessage.cpp
index fd15acf464..658e6bf48f 100644
--- a/cpp/src/qpid/broker/DeliverableMessage.cpp
+++ b/cpp/src/qpid/broker/DeliverableMessage.cpp
@@ -18,15 +18,15 @@
* under the License.
*
*/
-#include "DeliverableMessage.h"
+#include "qpid/broker/DeliverableMessage.h"
using namespace qpid::broker;
-DeliverableMessage::DeliverableMessage(boost::intrusive_ptr<Message>& _msg) : msg(_msg)
+DeliverableMessage::DeliverableMessage(const boost::intrusive_ptr<Message>& _msg) : msg(_msg)
{
}
-void DeliverableMessage::deliverTo(Queue::shared_ptr& queue)
+void DeliverableMessage::deliverTo(const boost::shared_ptr<Queue>& queue)
{
queue->deliver(msg);
delivered = true;
diff --git a/cpp/src/qpid/broker/DeliverableMessage.h b/cpp/src/qpid/broker/DeliverableMessage.h
index 18e1ec5e29..08abce35ef 100644
--- a/cpp/src/qpid/broker/DeliverableMessage.h
+++ b/cpp/src/qpid/broker/DeliverableMessage.h
@@ -21,9 +21,10 @@
#ifndef _DeliverableMessage_
#define _DeliverableMessage_
-#include "Deliverable.h"
-#include "Queue.h"
-#include "Message.h"
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/Deliverable.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/Message.h"
#include <boost/intrusive_ptr.hpp>
@@ -32,10 +33,10 @@ namespace qpid {
class DeliverableMessage : public Deliverable{
boost::intrusive_ptr<Message> msg;
public:
- DeliverableMessage(boost::intrusive_ptr<Message>& msg);
- virtual void deliverTo(Queue::shared_ptr& queue);
- Message& getMessage();
- uint64_t contentSize();
+ QPID_BROKER_EXTERN DeliverableMessage(const boost::intrusive_ptr<Message>& msg);
+ QPID_BROKER_EXTERN virtual void deliverTo(const boost::shared_ptr<Queue>& queue);
+ QPID_BROKER_EXTERN Message& getMessage();
+ QPID_BROKER_EXTERN uint64_t contentSize();
virtual ~DeliverableMessage(){}
};
}
diff --git a/cpp/src/qpid/broker/DeliveryAdapter.h b/cpp/src/qpid/broker/DeliveryAdapter.h
index 4c2b2f615f..b0bec60890 100644
--- a/cpp/src/qpid/broker/DeliveryAdapter.h
+++ b/cpp/src/qpid/broker/DeliveryAdapter.h
@@ -21,30 +21,31 @@
#ifndef _DeliveryAdapter_
#define _DeliveryAdapter_
-#include "DeliveryId.h"
-#include "DeliveryToken.h"
-#include "Message.h"
+#include "qpid/broker/DeliveryId.h"
+#include "qpid/broker/Message.h"
#include "qpid/framing/amqp_types.h"
namespace qpid {
namespace broker {
- /**
- * The intention behind this interface is to separate the generic
- * handling of some form of message delivery to clients that is
- * contained in the version independent Channel class from the
- * details required for a particular situation or
- * version. i.e. where the existing adapters allow (through
- * supporting the generated interface for a version of the
- * protocol) inputs of a channel to be adapted to the version
- * independent part, this does the same for the outputs.
- */
- class DeliveryAdapter
- {
- public:
- virtual DeliveryId deliver(QueuedMessage& msg, DeliveryToken::shared_ptr token) = 0;
- virtual ~DeliveryAdapter(){}
- };
+class DeliveryRecord;
+
+/**
+ * The intention behind this interface is to separate the generic
+ * handling of some form of message delivery to clients that is
+ * contained in the version independent Channel class from the
+ * details required for a particular situation or
+ * version. i.e. where the existing adapters allow (through
+ * supporting the generated interface for a version of the
+ * protocol) inputs of a channel to be adapted to the version
+ * independent part, this does the same for the outputs.
+ */
+class DeliveryAdapter
+{
+ public:
+ virtual void deliver(DeliveryRecord&, bool sync) = 0;
+ virtual ~DeliveryAdapter(){}
+};
}}
diff --git a/cpp/src/qpid/broker/DeliveryRecord.cpp b/cpp/src/qpid/broker/DeliveryRecord.cpp
index 530dca99a4..22ec5e86a0 100644
--- a/cpp/src/qpid/broker/DeliveryRecord.cpp
+++ b/cpp/src/qpid/broker/DeliveryRecord.cpp
@@ -18,91 +18,72 @@
* under the License.
*
*/
-#include "DeliveryRecord.h"
-#include "DeliverableMessage.h"
-#include "SemanticState.h"
-#include "Exchange.h"
+#include "qpid/broker/DeliveryRecord.h"
+#include "qpid/broker/DeliverableMessage.h"
+#include "qpid/broker/SemanticState.h"
+#include "qpid/broker/Exchange.h"
#include "qpid/log/Statement.h"
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/framing/MessageTransferBody.h"
+using namespace qpid;
using namespace qpid::broker;
using std::string;
DeliveryRecord::DeliveryRecord(const QueuedMessage& _msg,
- Queue::shared_ptr _queue,
- const std::string _tag,
- DeliveryToken::shared_ptr _token,
- const DeliveryId _id,
- bool _acquired, bool accepted) : msg(_msg),
- queue(_queue),
- tag(_tag),
- token(_token),
- id(_id),
- acquired(_acquired),
- pull(false),
- cancelled(false),
- credit(msg.payload ? msg.payload->getRequiredCredit() : 0),
- size(msg.payload ? msg.payload->contentSize() : 0),
- completed(false),
- ended(accepted)
-{
- if (accepted) setEnded();
-}
-
-DeliveryRecord::DeliveryRecord(const QueuedMessage& _msg,
- Queue::shared_ptr _queue,
- const DeliveryId _id) : msg(_msg),
- queue(_queue),
- id(_id),
- acquired(true),
- pull(true),
- cancelled(false),
- credit(msg.payload ? msg.payload->getRequiredCredit() : 0),
- size(msg.payload ? msg.payload->contentSize() : 0),
- completed(false),
- ended(false)
+ const Queue::shared_ptr& _queue,
+ const std::string& _tag,
+ bool _acquired,
+ bool accepted,
+ bool _windowing,
+ uint32_t _credit) : msg(_msg),
+ queue(_queue),
+ tag(_tag),
+ acquired(_acquired),
+ acceptExpected(!accepted),
+ cancelled(false),
+ completed(false),
+ ended(accepted && acquired),
+ windowing(_windowing),
+ credit(msg.payload ? msg.payload->getRequiredCredit() : _credit)
{}
-void DeliveryRecord::setEnded()
+bool DeliveryRecord::setEnded()
{
ended = true;
//reset msg pointer, don't need to hold on to it anymore
msg.payload = boost::intrusive_ptr<Message>();
-
QPID_LOG(debug, "DeliveryRecord::setEnded() id=" << id);
-}
-
-bool DeliveryRecord::matches(DeliveryId tag) const{
- return id == tag;
-}
-
-bool DeliveryRecord::matchOrAfter(DeliveryId tag) const{
- return matches(tag) || after(tag);
-}
-
-bool DeliveryRecord::after(DeliveryId tag) const{
- return id > tag;
-}
-
-bool DeliveryRecord::coveredBy(const framing::SequenceSet* const range) const{
- return range->contains(id);
+ return isRedundant();
}
void DeliveryRecord::redeliver(SemanticState* const session) {
if (!ended) {
- if(pull || cancelled){
- //if message was originally sent as response to get, we must requeue it
-
- //or if subscription was cancelled, requeue it (waiting for
+ if(cancelled){
+ //if subscription was cancelled, requeue it (waiting for
//final confirmation for AMQP WG on this case)
-
requeue();
}else{
msg.payload->redeliver();//mark as redelivered
- id = session->redeliver(msg, token);
+ session->deliver(*this, false);
}
}
}
+void DeliveryRecord::deliver(framing::FrameHandler& h, DeliveryId deliveryId, uint16_t framesize)
+{
+ id = deliveryId;
+ if (msg.payload->getRedelivered()){
+ msg.payload->getProperties<framing::DeliveryProperties>()->setRedelivered(true);
+ }
+
+ framing::AMQFrame method((framing::MessageTransferBody(framing::ProtocolVersion(), tag, acceptExpected ? 0 : 1, acquired ? 0 : 1)));
+ method.setEof(false);
+ h.handle(method);
+ msg.payload->sendHeader(h, framesize);
+ msg.payload->sendContent(*queue, h, framesize);
+}
+
void DeliveryRecord::requeue() const
{
if (acquired && !ended) {
@@ -123,25 +104,29 @@ void DeliveryRecord::release(bool setRedelivered)
}
}
-void DeliveryRecord::complete()
-{
+void DeliveryRecord::complete() {
completed = true;
}
-void DeliveryRecord::accept(TransactionContext* ctxt) {
+bool DeliveryRecord::accept(TransactionContext* ctxt) {
if (acquired && !ended) {
- queue->dequeue(ctxt, msg.payload);
+ queue->dequeue(ctxt, msg);
setEnded();
QPID_LOG(debug, "Accepted " << id);
}
+ return isRedundant();
}
void DeliveryRecord::dequeue(TransactionContext* ctxt) const{
if (acquired && !ended) {
- queue->dequeue(ctxt, msg.payload);
+ queue->dequeue(ctxt, msg);
}
}
+void DeliveryRecord::committed() const{
+ queue->dequeueCommitted(msg);
+}
+
void DeliveryRecord::reject()
{
Exchange::shared_ptr alternate = queue->getAlternateExchange();
@@ -161,29 +146,14 @@ uint32_t DeliveryRecord::getCredit() const
return credit;
}
-
-void DeliveryRecord::addTo(Prefetch& prefetch) const{
- if(!pull){
- //ignore 'pulled' messages (i.e. those that were sent in
- //response to get) when calculating prefetch
- prefetch.size += size;
- prefetch.count++;
- }
-}
-
-void DeliveryRecord::subtractFrom(Prefetch& prefetch) const{
- if(!pull){
- //ignore 'pulled' messages (i.e. those that were sent in
- //response to get) when calculating prefetch
- prefetch.size -= size;
- prefetch.count--;
- }
-}
-
void DeliveryRecord::acquire(DeliveryIds& results) {
if (queue->acquire(msg)) {
acquired = true;
results.push_back(id);
+ if (!acceptExpected) {
+ if (ended) { QPID_LOG(error, "Can't dequeue ended message"); }
+ else { queue->dequeue(0, msg); setEnded(); }
+ }
} else {
QPID_LOG(info, "Message already acquired " << id.getValue());
}
@@ -195,6 +165,16 @@ void DeliveryRecord::cancel(const std::string& cancelledTag)
cancelled = true;
}
+AckRange DeliveryRecord::findRange(DeliveryRecords& records, DeliveryId first, DeliveryId last)
+{
+ DeliveryRecords::iterator start = lower_bound(records.begin(), records.end(), first);
+ // Find end - position it just after the last record in range
+ DeliveryRecords::iterator end = lower_bound(records.begin(), records.end(), last);
+ if (end != records.end() && end->getId() == last) ++end;
+ return AckRange(start, end);
+}
+
+
namespace qpid {
namespace broker {
@@ -206,9 +186,5 @@ std::ostream& operator<<(std::ostream& out, const DeliveryRecord& r)
return out;
}
-bool operator<(const DeliveryRecord& a, const DeliveryRecord& b)
-{
- return a.id < b.id;
-}
}}
diff --git a/cpp/src/qpid/broker/DeliveryRecord.h b/cpp/src/qpid/broker/DeliveryRecord.h
index 78dc99e3c6..5f802766b6 100644
--- a/cpp/src/qpid/broker/DeliveryRecord.h
+++ b/cpp/src/qpid/broker/DeliveryRecord.h
@@ -1,3 +1,6 @@
+#ifndef QPID_BROKER_DELIVERYRECORD_H
+#define QPID_BROKER_DELIVERYRECORD_H
+
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -18,53 +21,60 @@
* under the License.
*
*/
-#ifndef _DeliveryRecord_
-#define _DeliveryRecord_
#include <algorithm>
-#include <list>
+#include <deque>
#include <vector>
#include <ostream>
#include "qpid/framing/SequenceSet.h"
-#include "Queue.h"
-#include "Consumer.h"
-#include "DeliveryId.h"
-#include "DeliveryToken.h"
-#include "Message.h"
-#include "Prefetch.h"
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/QueuedMessage.h"
+#include "qpid/broker/DeliveryId.h"
+#include "qpid/broker/Message.h"
namespace qpid {
namespace broker {
class SemanticState;
+struct AckRange;
/**
* Record of a delivery for which an ack is outstanding.
*/
-class DeliveryRecord{
+class DeliveryRecord
+{
QueuedMessage msg;
mutable Queue::shared_ptr queue;
- const std::string tag;
- DeliveryToken::shared_ptr token;
+ std::string tag;
DeliveryId id;
- bool acquired;
- const bool pull;
- bool cancelled;
- const uint32_t credit;
- const uint64_t size;
-
- bool completed;
- bool ended;
+ bool acquired : 1;
+ bool acceptExpected : 1;
+ bool cancelled : 1;
+ bool completed : 1;
+ bool ended : 1;
+ bool windowing : 1;
+
+ /**
+ * Record required credit on construction as the pointer to the
+ * message may be reset once we no longer need to deliver it
+ * (e.g. when it is accepted), but we will still need to be able
+ * to reallocate credit when it is completed (which could happen
+ * after that).
+ */
+ uint32_t credit;
public:
- DeliveryRecord(const QueuedMessage& msg, Queue::shared_ptr queue, const std::string tag, DeliveryToken::shared_ptr token,
- const DeliveryId id, bool acquired, bool confirmed = false);
- DeliveryRecord(const QueuedMessage& msg, Queue::shared_ptr queue, const DeliveryId id);
-
- bool matches(DeliveryId tag) const;
- bool matchOrAfter(DeliveryId tag) const;
- bool after(DeliveryId tag) const;
- bool coveredBy(const framing::SequenceSet* const range) const;
-
+ QPID_BROKER_EXTERN DeliveryRecord(const QueuedMessage& msg,
+ const Queue::shared_ptr& queue,
+ const std::string& tag,
+ bool acquired,
+ bool accepted,
+ bool windowing,
+ uint32_t credit=0 // Only used if msg is empty.
+ );
+
+ bool coveredBy(const framing::SequenceSet* const range) const { return range->contains(id); }
+
void dequeue(TransactionContext* ctxt = 0) const;
void requeue() const;
void release(bool setRedelivered);
@@ -73,32 +83,37 @@ class DeliveryRecord{
void redeliver(SemanticState* const);
void acquire(DeliveryIds& results);
void complete();
- void accept(TransactionContext* ctxt);
- void setEnded();
+ bool accept(TransactionContext* ctxt); // Returns isRedundant()
+ bool setEnded(); // Returns isRedundant()
+ void committed() const;
bool isAcquired() const { return acquired; }
bool isComplete() const { return completed; }
- bool isRedundant() const { return ended && completed; }
-
+ bool isRedundant() const { return ended && (!windowing || completed); }
+ bool isCancelled() const { return cancelled; }
+ bool isAccepted() const { return !acceptExpected; }
+ bool isEnded() const { return ended; }
+ bool isWindowing() const { return windowing; }
+
uint32_t getCredit() const;
- void addTo(Prefetch&) const;
- void subtractFrom(Prefetch&) const;
- const std::string& getTag() const { return tag; }
- bool isPull() const { return pull; }
- friend bool operator<(const DeliveryRecord&, const DeliveryRecord&);
- friend std::ostream& operator<<(std::ostream&, const DeliveryRecord&);
-};
+ const std::string& getTag() const { return tag; }
-typedef std::list<DeliveryRecord> DeliveryRecords;
-typedef std::list<DeliveryRecord>::iterator ack_iterator;
+ void deliver(framing::FrameHandler& h, DeliveryId deliveryId, uint16_t framesize);
+ void setId(DeliveryId _id) { id = _id; }
-struct AckRange
-{
- ack_iterator start;
- ack_iterator end;
- AckRange(ack_iterator _start, ack_iterator _end) : start(_start), end(_end) {}
+ typedef std::deque<DeliveryRecord> DeliveryRecords;
+ static AckRange findRange(DeliveryRecords& records, DeliveryId first, DeliveryId last);
+ const QueuedMessage& getMessage() const { return msg; }
+ framing::SequenceNumber getId() const { return id; }
+ Queue::shared_ptr getQueue() const { return queue; }
+
+ friend std::ostream& operator<<(std::ostream&, const DeliveryRecord&);
};
+inline bool operator<(const DeliveryRecord& a, const DeliveryRecord& b) { return a.getId() < b.getId(); }
+inline bool operator<(const framing::SequenceNumber& a, const DeliveryRecord& b) { return a < b.getId(); }
+inline bool operator<(const DeliveryRecord& a, const framing::SequenceNumber& b) { return a.getId() < b; }
+
struct AcquireFunctor
{
DeliveryIds& results;
@@ -111,8 +126,17 @@ struct AcquireFunctor
}
};
+typedef DeliveryRecord::DeliveryRecords DeliveryRecords;
+
+struct AckRange
+{
+ DeliveryRecords::iterator start;
+ DeliveryRecords::iterator end;
+ AckRange(DeliveryRecords::iterator _start, DeliveryRecords::iterator _end) : start(_start), end(_end) {}
+};
+
}
}
-#endif
+#endif /*!QPID_BROKER_DELIVERYRECORD_H*/
diff --git a/cpp/src/qpid/broker/DeliveryToken.h b/cpp/src/qpid/broker/DeliveryToken.h
deleted file mode 100644
index 8bdf5e6359..0000000000
--- a/cpp/src/qpid/broker/DeliveryToken.h
+++ /dev/null
@@ -1,45 +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.
- *
- */
-#ifndef _DeliveryToken_
-#define _DeliveryToken_
-
-#include <boost/shared_ptr.hpp>
-
-namespace qpid {
-namespace broker {
-
- /**
- * A DeliveryToken allows the delivery of a message to be
- * associated with whatever mechanism caused it to be
- * delivered. (i.e. its a form of Memento).
- */
- class DeliveryToken
- {
- public:
- typedef boost::shared_ptr<DeliveryToken> shared_ptr;
-
- virtual ~DeliveryToken(){}
- };
-
-}}
-
-
-#endif
diff --git a/cpp/src/qpid/broker/DirectExchange.cpp b/cpp/src/qpid/broker/DirectExchange.cpp
index 4aa68bee9c..094f59cdec 100644
--- a/cpp/src/qpid/broker/DirectExchange.cpp
+++ b/cpp/src/qpid/broker/DirectExchange.cpp
@@ -19,111 +19,142 @@
*
*/
#include "qpid/log/Statement.h"
-#include "DirectExchange.h"
+#include "qpid/broker/DirectExchange.h"
#include <iostream>
using namespace qpid::broker;
using namespace qpid::framing;
using namespace qpid::sys;
using qpid::management::Manageable;
+namespace _qmf = qmf::org::apache::qpid::broker;
-DirectExchange::DirectExchange(const string& _name, Manageable* _parent) : Exchange(_name, _parent)
+namespace
+{
+const std::string qpidFedOp("qpid.fed.op");
+const std::string qpidFedTags("qpid.fed.tags");
+const std::string qpidFedOrigin("qpid.fed.origin");
+const std::string qpidExclusiveBinding("qpid.exclusive-binding");
+
+const std::string fedOpBind("B");
+const std::string fedOpUnbind("U");
+const std::string fedOpReorigin("R");
+const std::string fedOpHello("H");
+}
+
+DirectExchange::DirectExchange(const string& _name, Manageable* _parent, Broker* b) : Exchange(_name, _parent, b)
{
if (mgmtExchange != 0)
- mgmtExchange->set_type (typeName);
+ mgmtExchange->set_type(typeName);
}
-DirectExchange::DirectExchange(const std::string& _name, bool _durable,
- const FieldTable& _args, Manageable* _parent) :
- Exchange(_name, _durable, _args, _parent)
+DirectExchange::DirectExchange(const string& _name, bool _durable,
+ const FieldTable& _args, Manageable* _parent, Broker* b) :
+ Exchange(_name, _durable, _args, _parent, b)
{
if (mgmtExchange != 0)
- mgmtExchange->set_type (typeName);
+ mgmtExchange->set_type(typeName);
}
-bool DirectExchange::bind(Queue::shared_ptr queue, const string& routingKey, const FieldTable*){
- RWlock::ScopedWlock l(lock);
- std::vector<Binding::shared_ptr>& queues(bindings[routingKey]);
- std::vector<Binding::shared_ptr>::iterator i;
-
- for (i = queues.begin(); i != queues.end(); i++)
- if ((*i)->queue == queue)
- break;
-
- if (i == queues.end()) {
- Binding::shared_ptr binding (new Binding (routingKey, queue, this));
- bindings[routingKey].push_back(binding);
- if (mgmtExchange != 0) {
- mgmtExchange->inc_bindingCount();
- ((management::Queue*) queue->GetManagementObject())->inc_bindingCount();
- }
- return true;
- } else{
- return false;
+bool DirectExchange::bind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* args)
+{
+ string fedOp(fedOpBind);
+ string fedTags;
+ string fedOrigin;
+ bool exclusiveBinding = false;
+ if (args) {
+ fedOp = args->getAsString(qpidFedOp);
+ fedTags = args->getAsString(qpidFedTags);
+ fedOrigin = args->getAsString(qpidFedOrigin);
+ exclusiveBinding = args->get(qpidExclusiveBinding);
}
-}
-bool DirectExchange::unbind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* /*args*/){
- RWlock::ScopedWlock l(lock);
- std::vector<Binding::shared_ptr>& queues(bindings[routingKey]);
- std::vector<Binding::shared_ptr>::iterator i;
+ bool propagate = false;
- for (i = queues.begin(); i != queues.end(); i++)
- if ((*i)->queue == queue)
- break;
+ if (args == 0 || fedOp.empty() || fedOp == fedOpBind) {
+ Mutex::ScopedLock l(lock);
+ Binding::shared_ptr b(new Binding(routingKey, queue, this, FieldTable(), fedOrigin));
+ BoundKey& bk = bindings[routingKey];
+ if (exclusiveBinding) bk.queues.clear();
- if (i < queues.end()) {
- queues.erase(i);
- if (queues.empty()) {
- bindings.erase(routingKey);
+ if (bk.queues.add_unless(b, MatchQueue(queue))) {
+ propagate = bk.fedBinding.addOrigin(fedOrigin);
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_bindingCount();
+ }
+ } else {
+ return false;
}
- if (mgmtExchange != 0) {
- mgmtExchange->dec_bindingCount();
- ((management::Queue*) queue->GetManagementObject())->dec_bindingCount();
+ } else if (fedOp == fedOpUnbind) {
+ Mutex::ScopedLock l(lock);
+ BoundKey& bk = bindings[routingKey];
+ propagate = bk.fedBinding.delOrigin(fedOrigin);
+ if (bk.fedBinding.count() == 0)
+ unbind(queue, routingKey, 0);
+ } else if (fedOp == fedOpReorigin) {
+ /** gather up all the keys that need rebinding in a local vector
+ * while holding the lock. Then propagate once the lock is
+ * released
+ */
+ std::vector<std::string> keys2prop;
+ {
+ Mutex::ScopedLock l(lock);
+ for (Bindings::iterator iter = bindings.begin();
+ iter != bindings.end(); iter++) {
+ const BoundKey& bk = iter->second;
+ if (bk.fedBinding.hasLocal()) {
+ keys2prop.push_back(iter->first);
+ }
+ }
+ } /* lock dropped */
+ for (std::vector<std::string>::const_iterator key = keys2prop.begin();
+ key != keys2prop.end(); key++) {
+ propagateFedOp( *key, string(), fedOpBind, string());
}
- return true;
- } else {
- return false;
}
+
+ routeIVE();
+ if (propagate)
+ propagateFedOp(routingKey, fedTags, fedOp, fedOrigin);
+ return true;
}
-void DirectExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* /*args*/){
- RWlock::ScopedRlock l(lock);
- std::vector<Binding::shared_ptr>& queues(bindings[routingKey]);
- std::vector<Binding::shared_ptr>::iterator i;
- int count(0);
-
- for(i = queues.begin(); i != queues.end(); i++, count++) {
- msg.deliverTo((*i)->queue);
- if ((*i)->mgmtBinding != 0)
- (*i)->mgmtBinding->inc_msgMatched ();
- }
-
- if(!count){
- QPID_LOG(warning, "DirectExchange " << getName() << " could not route message with key " << routingKey);
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgDrops ();
- mgmtExchange->inc_byteDrops (msg.contentSize ());
- }
- }
- else {
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgRoutes (count);
- mgmtExchange->inc_byteRoutes (count * msg.contentSize ());
+bool DirectExchange::unbind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* /*args*/)
+{
+ bool propagate = false;
+
+ {
+ Mutex::ScopedLock l(lock);
+ BoundKey& bk = bindings[routingKey];
+ if (bk.queues.remove_if(MatchQueue(queue))) {
+ propagate = bk.fedBinding.delOrigin();
+ if (mgmtExchange != 0) {
+ mgmtExchange->dec_bindingCount();
+ }
+ } else {
+ return false;
}
}
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgReceives ();
- mgmtExchange->inc_byteReceives (msg.contentSize ());
+ if (propagate)
+ propagateFedOp(routingKey, string(), fedOpUnbind, string());
+ return true;
+}
+
+void DirectExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* /*args*/)
+{
+ PreRoute pr(msg, this);
+ ConstBindingList b;
+ {
+ Mutex::ScopedLock l(lock);
+ b = bindings[routingKey].queues.snapshot();
}
+ doRoute(msg, b);
}
bool DirectExchange::isBound(Queue::shared_ptr queue, const string* const routingKey, const FieldTable* const)
{
- std::vector<Binding::shared_ptr>::iterator j;
-
+ Mutex::ScopedLock l(lock);
if (routingKey) {
Bindings::iterator i = bindings.find(*routingKey);
@@ -131,17 +162,17 @@ bool DirectExchange::isBound(Queue::shared_ptr queue, const string* const routin
return false;
if (!queue)
return true;
- for (j = i->second.begin(); j != i->second.end(); j++)
- if ((*j)->queue == queue)
- return true;
+
+ Queues::ConstPtr p = i->second.queues.snapshot();
+ return p && std::find_if(p->begin(), p->end(), MatchQueue(queue)) != p->end();
} else if (!queue) {
//if no queue or routing key is specified, just report whether any bindings exist
return bindings.size() > 0;
} else {
- for (Bindings::iterator i = bindings.begin(); i != bindings.end(); i++)
- for (j = i->second.begin(); j != i->second.end(); j++)
- if ((*j)->queue == queue)
- return true;
+ for (Bindings::iterator i = bindings.begin(); i != bindings.end(); i++) {
+ Queues::ConstPtr p = i->second.queues.snapshot();
+ if (p && std::find_if(p->begin(), p->end(), MatchQueue(queue)) != p->end()) return true;
+ }
return false;
}
diff --git a/cpp/src/qpid/broker/DirectExchange.h b/cpp/src/qpid/broker/DirectExchange.h
index 118f2ed4d3..9a73f3bc41 100644
--- a/cpp/src/qpid/broker/DirectExchange.h
+++ b/cpp/src/qpid/broker/DirectExchange.h
@@ -23,40 +23,53 @@
#include <map>
#include <vector>
-#include "Exchange.h"
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/Exchange.h"
#include "qpid/framing/FieldTable.h"
-#include "qpid/sys/Monitor.h"
-#include "Queue.h"
+#include "qpid/sys/CopyOnWriteArray.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/broker/Queue.h"
namespace qpid {
namespace broker {
- class DirectExchange : public virtual Exchange{
- typedef std::vector<Binding::shared_ptr> Queues;
- typedef std::map<string, Queues> Bindings;
- Bindings bindings;
- qpid::sys::RWlock lock;
-
- public:
- static const std::string typeName;
-
- DirectExchange(const std::string& name, management::Manageable* parent = 0);
- DirectExchange(const string& _name, bool _durable,
- const qpid::framing::FieldTable& _args, management::Manageable* parent = 0);
+class DirectExchange : public virtual Exchange {
+ typedef qpid::sys::CopyOnWriteArray<Binding::shared_ptr> Queues;
+ struct BoundKey {
+ Queues queues;
+ FedBinding fedBinding;
+ };
+ typedef std::map<string, BoundKey> Bindings;
+ Bindings bindings;
+ qpid::sys::Mutex lock;
- virtual std::string getType() const { return typeName; }
+public:
+ static const std::string typeName;
- virtual bool bind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
-
- virtual bool unbind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
+ QPID_BROKER_EXTERN DirectExchange(const std::string& name,
+ management::Manageable* parent = 0, Broker* broker = 0);
+ QPID_BROKER_EXTERN DirectExchange(const string& _name,
+ bool _durable,
+ const qpid::framing::FieldTable& _args,
+ management::Manageable* parent = 0, Broker* broker = 0);
- virtual void route(Deliverable& msg, const std::string& routingKey, const qpid::framing::FieldTable* args);
+ virtual std::string getType() const { return typeName; }
+
+ QPID_BROKER_EXTERN virtual bool bind(Queue::shared_ptr queue,
+ const std::string& routingKey,
+ const qpid::framing::FieldTable* args);
+ virtual bool unbind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
+ QPID_BROKER_EXTERN virtual void route(Deliverable& msg,
+ const std::string& routingKey,
+ const qpid::framing::FieldTable* args);
+ QPID_BROKER_EXTERN virtual bool isBound(Queue::shared_ptr queue,
+ const string* const routingKey,
+ const qpid::framing::FieldTable* const args);
- virtual bool isBound(Queue::shared_ptr queue, const string* const routingKey, const qpid::framing::FieldTable* const args);
+ QPID_BROKER_EXTERN virtual ~DirectExchange();
- virtual ~DirectExchange();
- };
-}
-}
+ virtual bool supportsDynamicBinding() { return true; }
+};
+}}
#endif
diff --git a/cpp/src/qpid/broker/DtxAck.cpp b/cpp/src/qpid/broker/DtxAck.cpp
index 47637369ca..bca3f90bbe 100644
--- a/cpp/src/qpid/broker/DtxAck.cpp
+++ b/cpp/src/qpid/broker/DtxAck.cpp
@@ -18,7 +18,7 @@
* under the License.
*
*/
-#include "DtxAck.h"
+#include "qpid/broker/DtxAck.h"
#include "qpid/log/Statement.h"
using std::bind1st;
@@ -26,7 +26,7 @@ using std::bind2nd;
using std::mem_fun_ref;
using namespace qpid::broker;
-DtxAck::DtxAck(const framing::SequenceSet& acked, std::list<DeliveryRecord>& unacked)
+DtxAck::DtxAck(const qpid::framing::SequenceSet& acked, DeliveryRecords& unacked)
{
remove_copy_if(unacked.begin(), unacked.end(), inserter(pending, pending.end()),
not1(bind2nd(mem_fun_ref(&DeliveryRecord::coveredBy), &acked)));
@@ -36,7 +36,7 @@ bool DtxAck::prepare(TransactionContext* ctxt) throw()
{
try{
//record dequeue in the store
- for (ack_iterator i = pending.begin(); i != pending.end(); i++) {
+ for (DeliveryRecords::iterator i = pending.begin(); i != pending.end(); i++) {
i->dequeue(ctxt);
}
return true;
@@ -48,11 +48,26 @@ bool DtxAck::prepare(TransactionContext* ctxt) throw()
void DtxAck::commit() throw()
{
- pending.clear();
+ try {
+ for_each(pending.begin(), pending.end(), mem_fun_ref(&DeliveryRecord::committed));
+ pending.clear();
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Failed to commit: " << e.what());
+ } catch(...) {
+ QPID_LOG(error, "Failed to commit (unknown error)");
+ }
+
}
void DtxAck::rollback() throw()
{
- for_each(pending.begin(), pending.end(), mem_fun_ref(&DeliveryRecord::requeue));
- pending.clear();
+ try {
+ for_each(pending.begin(), pending.end(), mem_fun_ref(&DeliveryRecord::requeue));
+ pending.clear();
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Failed to complete rollback: " << e.what());
+ } catch(...) {
+ QPID_LOG(error, "Failed to complete rollback (unknown error)");
+ }
+
}
diff --git a/cpp/src/qpid/broker/DtxAck.h b/cpp/src/qpid/broker/DtxAck.h
index 05c4499839..166147e58d 100644
--- a/cpp/src/qpid/broker/DtxAck.h
+++ b/cpp/src/qpid/broker/DtxAck.h
@@ -25,20 +25,21 @@
#include <functional>
#include <list>
#include "qpid/framing/SequenceSet.h"
-#include "DeliveryRecord.h"
-#include "TxOp.h"
+#include "qpid/broker/DeliveryRecord.h"
+#include "qpid/broker/TxOp.h"
namespace qpid {
namespace broker {
class DtxAck : public TxOp{
- std::list<DeliveryRecord> pending;
+ DeliveryRecords pending;
public:
- DtxAck(const framing::SequenceSet& acked, std::list<DeliveryRecord>& unacked);
+ DtxAck(const framing::SequenceSet& acked, DeliveryRecords& unacked);
virtual bool prepare(TransactionContext* ctxt) throw();
virtual void commit() throw();
virtual void rollback() throw();
virtual ~DtxAck(){}
+ virtual void accept(TxOpConstVisitor& visitor) const { visitor(*this); }
};
}
}
diff --git a/cpp/src/qpid/broker/DtxBuffer.cpp b/cpp/src/qpid/broker/DtxBuffer.cpp
index 29a07ea6d9..f1b8169cf7 100644
--- a/cpp/src/qpid/broker/DtxBuffer.cpp
+++ b/cpp/src/qpid/broker/DtxBuffer.cpp
@@ -18,7 +18,7 @@
* under the License.
*
*/
-#include "DtxBuffer.h"
+#include "qpid/broker/DtxBuffer.h"
using namespace qpid::broker;
using qpid::sys::Mutex;
diff --git a/cpp/src/qpid/broker/DtxBuffer.h b/cpp/src/qpid/broker/DtxBuffer.h
index b302632037..1511cb032f 100644
--- a/cpp/src/qpid/broker/DtxBuffer.h
+++ b/cpp/src/qpid/broker/DtxBuffer.h
@@ -21,7 +21,8 @@
#ifndef _DtxBuffer_
#define _DtxBuffer_
-#include "TxBuffer.h"
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/TxBuffer.h"
#include "qpid/sys/Mutex.h"
namespace qpid {
@@ -37,9 +38,9 @@ namespace qpid {
public:
typedef boost::shared_ptr<DtxBuffer> shared_ptr;
- DtxBuffer(const std::string& xid = "");
- ~DtxBuffer();
- void markEnded();
+ QPID_BROKER_EXTERN DtxBuffer(const std::string& xid = "");
+ QPID_BROKER_EXTERN ~DtxBuffer();
+ QPID_BROKER_EXTERN void markEnded();
bool isEnded();
void setSuspended(bool suspended);
bool isSuspended();
diff --git a/cpp/src/qpid/broker/DtxManager.cpp b/cpp/src/qpid/broker/DtxManager.cpp
index 942dbdcbc6..a2ab20ec44 100644
--- a/cpp/src/qpid/broker/DtxManager.cpp
+++ b/cpp/src/qpid/broker/DtxManager.cpp
@@ -18,10 +18,11 @@
* under the License.
*
*/
-#include "DtxManager.h"
-#include "DtxTimeout.h"
+#include "qpid/broker/DtxManager.h"
+#include "qpid/broker/DtxTimeout.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/log/Statement.h"
+#include "qpid/sys/Timer.h"
#include "qpid/ptr_map.h"
#include <boost/format.hpp>
@@ -33,7 +34,7 @@ using qpid::ptr_map_ptr;
using namespace qpid::broker;
using namespace qpid::framing;
-DtxManager::DtxManager() : store(0) {}
+DtxManager::DtxManager(qpid::sys::Timer& t) : store(0), timer(t) {}
DtxManager::~DtxManager() {}
@@ -126,12 +127,11 @@ void DtxManager::setTimeout(const std::string& xid, uint32_t secs)
intrusive_ptr<DtxTimeout> timeout = record->getTimeout();
if (timeout.get()) {
if (timeout->timeout == secs) return;//no need to do anything further if timeout hasn't changed
- timeout->cancelled = true;
+ timeout->cancel();
}
timeout = intrusive_ptr<DtxTimeout>(new DtxTimeout(secs, *this, xid));
record->setTimeout(timeout);
- timer.add(boost::static_pointer_cast<TimerTask>(timeout));
-
+ timer.add(timeout);
}
uint32_t DtxManager::getTimeout(const std::string& xid)
@@ -160,13 +160,12 @@ void DtxManager::DtxCleanup::fire()
{
try {
mgr.remove(xid);
- } catch (ConnectionException& e) {
+ } catch (ConnectionException& /*e*/) {
//assume it was explicitly cleaned up after a call to prepare, commit or rollback
}
}
void DtxManager::setStore (TransactionalStore* _store)
{
- assert (store == 0 && _store != 0);
store = _store;
}
diff --git a/cpp/src/qpid/broker/DtxManager.h b/cpp/src/qpid/broker/DtxManager.h
index fa5c62c233..680b62eeb2 100644
--- a/cpp/src/qpid/broker/DtxManager.h
+++ b/cpp/src/qpid/broker/DtxManager.h
@@ -22,11 +22,11 @@
#define _DtxManager_
#include <boost/ptr_container/ptr_map.hpp>
-#include "DtxBuffer.h"
-#include "DtxWorkRecord.h"
-#include "Timer.h"
-#include "TransactionalStore.h"
+#include "qpid/broker/DtxBuffer.h"
+#include "qpid/broker/DtxWorkRecord.h"
+#include "qpid/broker/TransactionalStore.h"
#include "qpid/framing/amqp_types.h"
+#include "qpid/sys/Timer.h"
#include "qpid/sys/Mutex.h"
namespace qpid {
@@ -35,7 +35,7 @@ namespace broker {
class DtxManager{
typedef boost::ptr_map<std::string, DtxWorkRecord> WorkMap;
- struct DtxCleanup : public TimerTask
+ struct DtxCleanup : public sys::TimerTask
{
DtxManager& mgr;
const std::string& xid;
@@ -47,14 +47,14 @@ class DtxManager{
WorkMap work;
TransactionalStore* store;
qpid::sys::Mutex lock;
- Timer timer;
+ qpid::sys::Timer& timer;
void remove(const std::string& xid);
DtxWorkRecord* getWork(const std::string& xid);
DtxWorkRecord* createWork(std::string xid);
public:
- DtxManager();
+ DtxManager(qpid::sys::Timer&);
~DtxManager();
void start(const std::string& xid, DtxBuffer::shared_ptr work);
void join(const std::string& xid, DtxBuffer::shared_ptr work);
diff --git a/cpp/src/qpid/broker/DtxTimeout.cpp b/cpp/src/qpid/broker/DtxTimeout.cpp
index 8e0a7741c4..f5238d0909 100644
--- a/cpp/src/qpid/broker/DtxTimeout.cpp
+++ b/cpp/src/qpid/broker/DtxTimeout.cpp
@@ -18,8 +18,8 @@
* under the License.
*
*/
-#include "DtxTimeout.h"
-#include "DtxManager.h"
+#include "qpid/broker/DtxTimeout.h"
+#include "qpid/broker/DtxManager.h"
#include "qpid/sys/Time.h"
using namespace qpid::broker;
diff --git a/cpp/src/qpid/broker/DtxTimeout.h b/cpp/src/qpid/broker/DtxTimeout.h
index 6e949eab0d..680a210e4f 100644
--- a/cpp/src/qpid/broker/DtxTimeout.h
+++ b/cpp/src/qpid/broker/DtxTimeout.h
@@ -22,7 +22,7 @@
#define _DtxTimeout_
#include "qpid/Exception.h"
-#include "Timer.h"
+#include "qpid/sys/Timer.h"
namespace qpid {
namespace broker {
@@ -31,12 +31,12 @@ class DtxManager;
struct DtxTimeoutException : public Exception {};
-struct DtxTimeout : public TimerTask
+struct DtxTimeout : public sys::TimerTask
{
const uint32_t timeout;
DtxManager& mgr;
const std::string xid;
-
+
DtxTimeout(uint32_t timeout, DtxManager& mgr, const std::string& xid);
void fire();
};
diff --git a/cpp/src/qpid/broker/DtxWorkRecord.cpp b/cpp/src/qpid/broker/DtxWorkRecord.cpp
index cc79813dab..9f33e698db 100644
--- a/cpp/src/qpid/broker/DtxWorkRecord.cpp
+++ b/cpp/src/qpid/broker/DtxWorkRecord.cpp
@@ -18,7 +18,7 @@
* under the License.
*
*/
-#include "DtxWorkRecord.h"
+#include "qpid/broker/DtxWorkRecord.h"
#include "qpid/framing/reply_exceptions.h"
#include <boost/format.hpp>
#include <boost/mem_fn.hpp>
@@ -34,7 +34,7 @@ DtxWorkRecord::DtxWorkRecord(const std::string& _xid, TransactionalStore* const
DtxWorkRecord::~DtxWorkRecord()
{
if (timeout.get()) {
- timeout->cancelled = true;
+ timeout->cancel();
}
}
diff --git a/cpp/src/qpid/broker/DtxWorkRecord.h b/cpp/src/qpid/broker/DtxWorkRecord.h
index 6677784c32..aec2d2aed4 100644
--- a/cpp/src/qpid/broker/DtxWorkRecord.h
+++ b/cpp/src/qpid/broker/DtxWorkRecord.h
@@ -21,9 +21,10 @@
#ifndef _DtxWorkRecord_
#define _DtxWorkRecord_
-#include "DtxBuffer.h"
-#include "DtxTimeout.h"
-#include "TransactionalStore.h"
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/DtxBuffer.h"
+#include "qpid/broker/DtxTimeout.h"
+#include "qpid/broker/TransactionalStore.h"
#include "qpid/framing/amqp_types.h"
#include "qpid/sys/Mutex.h"
@@ -61,12 +62,13 @@ class DtxWorkRecord
void abort();
bool prepare(TransactionContext* txn);
public:
- DtxWorkRecord(const std::string& xid, TransactionalStore* const store);
- ~DtxWorkRecord();
- bool prepare();
- bool commit(bool onePhase);
- void rollback();
- void add(DtxBuffer::shared_ptr ops);
+ QPID_BROKER_EXTERN DtxWorkRecord(const std::string& xid,
+ TransactionalStore* const store);
+ QPID_BROKER_EXTERN ~DtxWorkRecord();
+ QPID_BROKER_EXTERN bool prepare();
+ QPID_BROKER_EXTERN bool commit(bool onePhase);
+ QPID_BROKER_EXTERN void rollback();
+ QPID_BROKER_EXTERN void add(DtxBuffer::shared_ptr ops);
void recover(std::auto_ptr<TPCTransactionContext> txn, DtxBuffer::shared_ptr ops);
void timedout();
void setTimeout(boost::intrusive_ptr<DtxTimeout> t) { timeout = t; }
diff --git a/cpp/src/qpid/broker/Exchange.cpp b/cpp/src/qpid/broker/Exchange.cpp
index fbfcaede82..8efb9ac545 100644
--- a/cpp/src/qpid/broker/Exchange.cpp
+++ b/cpp/src/qpid/broker/Exchange.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -19,52 +19,157 @@
*
*/
-#include "Exchange.h"
-#include "ExchangeRegistry.h"
-#include "qpid/agent/ManagementAgent.h"
+#include "qpid/broker/Exchange.h"
+#include "qpid/broker/ExchangeRegistry.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/management/ManagementAgent.h"
+#include "qpid/log/Statement.h"
+#include "qpid/framing/MessageProperties.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/broker/DeliverableMessage.h"
using namespace qpid::broker;
+using namespace qpid::framing;
using qpid::framing::Buffer;
using qpid::framing::FieldTable;
+using qpid::sys::Mutex;
using qpid::management::ManagementAgent;
using qpid::management::ManagementObject;
using qpid::management::Manageable;
using qpid::management::Args;
+namespace _qmf = qmf::org::apache::qpid::broker;
-Exchange::Exchange (const string& _name, Manageable* parent) :
- name(_name), durable(false), persistenceId(0), mgmtExchange(0)
+namespace
{
- if (parent != 0)
+const std::string qpidMsgSequence("qpid.msg_sequence");
+const std::string qpidSequenceCounter("qpid.sequence_counter");
+const std::string qpidIVE("qpid.ive");
+const std::string qpidFedOp("qpid.fed.op");
+const std::string qpidFedTags("qpid.fed.tags");
+const std::string qpidFedOrigin("qpid.fed.origin");
+
+const std::string fedOpBind("B");
+const std::string fedOpUnbind("U");
+const std::string fedOpReorigin("R");
+const std::string fedOpHello("H");
+
+const std::string QPID_MANAGEMENT("qpid.management");
+}
+
+
+Exchange::PreRoute::PreRoute(Deliverable& msg, Exchange* _p):parent(_p) {
+ if (parent){
+ if (parent->sequence || parent->ive) parent->sequenceLock.lock();
+
+ if (parent->sequence){
+ parent->sequenceNo++;
+ msg.getMessage().getProperties<MessageProperties>()->getApplicationHeaders().setInt64(qpidMsgSequence,parent->sequenceNo);
+ }
+ if (parent->ive) {
+ parent->lastMsg = &( msg.getMessage());
+ }
+ }
+}
+
+Exchange::PreRoute::~PreRoute(){
+ if (parent && (parent->sequence || parent->ive)){
+ parent->sequenceLock.unlock();
+ }
+}
+
+void Exchange::doRoute(Deliverable& msg, ConstBindingList b)
+{
+ int count = 0;
+
+ if (b.get()) {
+ // Block the content release if the message is transient AND there is more than one binding
+ if (!msg.getMessage().isPersistent() && b->size() > 1)
+ msg.getMessage().blockContentRelease();
+
+ for(std::vector<Binding::shared_ptr>::const_iterator i = b->begin(); i != b->end(); i++, count++) {
+ msg.deliverTo((*i)->queue);
+ if ((*i)->mgmtBinding != 0)
+ (*i)->mgmtBinding->inc_msgMatched();
+ }
+ }
+
+ if (mgmtExchange != 0)
+ {
+ mgmtExchange->inc_msgReceives ();
+ mgmtExchange->inc_byteReceives (msg.contentSize ());
+ if (count == 0)
+ {
+ //QPID_LOG(warning, "Exchange " << getName() << " could not route message; no matching binding found");
+ mgmtExchange->inc_msgDrops ();
+ mgmtExchange->inc_byteDrops (msg.contentSize ());
+ }
+ else
+ {
+ mgmtExchange->inc_msgRoutes (count);
+ mgmtExchange->inc_byteRoutes (count * msg.contentSize ());
+ }
+ }
+}
+
+void Exchange::routeIVE(){
+ if (ive && lastMsg.get()){
+ DeliverableMessage dmsg(lastMsg);
+ route(dmsg, lastMsg->getRoutingKey(), lastMsg->getApplicationHeaders());
+ }
+}
+
+
+Exchange::Exchange (const string& _name, Manageable* parent, Broker* b) :
+ name(_name), durable(false), persistenceId(0), sequence(false),
+ sequenceNo(0), ive(false), mgmtExchange(0), broker(b)
+{
+ if (parent != 0 && broker != 0)
{
- ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ ManagementAgent* agent = broker->getManagementAgent();
if (agent != 0)
{
- mgmtExchange = new management::Exchange (agent, this, parent, _name, durable);
+ mgmtExchange = new _qmf::Exchange (agent, this, parent, _name);
+ mgmtExchange->set_durable(durable);
+ mgmtExchange->set_autoDelete(false);
agent->addObject (mgmtExchange);
}
}
}
Exchange::Exchange(const string& _name, bool _durable, const qpid::framing::FieldTable& _args,
- Manageable* parent)
- : name(_name), durable(_durable), args(_args), alternateUsers(0), persistenceId(0), mgmtExchange(0)
+ Manageable* parent, Broker* b)
+ : name(_name), durable(_durable), alternateUsers(0), persistenceId(0),
+ args(_args), sequence(false), sequenceNo(0), ive(false), mgmtExchange(0), broker(b)
{
- if (parent != 0)
+ if (parent != 0 && broker != 0)
{
- ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ ManagementAgent* agent = broker->getManagementAgent();
if (agent != 0)
{
- mgmtExchange = new management::Exchange (agent, this, parent, _name, durable);
+ mgmtExchange = new _qmf::Exchange (agent, this, parent, _name);
+ mgmtExchange->set_durable(durable);
+ mgmtExchange->set_autoDelete(false);
+ mgmtExchange->set_arguments(args);
if (!durable) {
- if (name == "")
- agent->addObject (mgmtExchange, 4, 1); // Special default exchange ID
- else if (name == "qpid.management")
- agent->addObject (mgmtExchange, 5, 1); // Special management exchange ID
- else
- agent->addObject (mgmtExchange);
+ if (name.empty()) {
+ agent->addObject (mgmtExchange, 0x1000000000000004LL); // Special default exchange ID
+ } else if (name == QPID_MANAGEMENT) {
+ agent->addObject (mgmtExchange, 0x1000000000000005LL); // Special management exchange ID
+ } else {
+ agent->addObject (mgmtExchange, agent->allocateId(this));
+ }
}
}
}
+
+ sequence = _args.get(qpidMsgSequence);
+ if (sequence) {
+ QPID_LOG(debug, "Configured exchange " << _name << " with Msg sequencing");
+ args.setInt64(std::string(qpidSequenceCounter), sequenceNo);
+ }
+
+ ive = _args.get(qpidIVE);
+ if (ive) QPID_LOG(debug, "Configured exchange " << _name << " with Initial Value");
}
Exchange::~Exchange ()
@@ -73,12 +178,23 @@ Exchange::~Exchange ()
mgmtExchange->resourceDestroy ();
}
+void Exchange::setAlternate(Exchange::shared_ptr _alternate)
+{
+ alternate = _alternate;
+ if (mgmtExchange != 0) {
+ if (alternate.get() != 0)
+ mgmtExchange->set_altExchange(alternate->GetManagementObject()->getObjectId());
+ else
+ mgmtExchange->clr_altExchange();
+ }
+}
+
void Exchange::setPersistenceId(uint64_t id) const
{
if (mgmtExchange != 0 && persistenceId == 0)
{
- ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
- agent->addObject (mgmtExchange, id, 2);
+ ManagementAgent* agent = broker->getManagementAgent();
+ agent->addObject (mgmtExchange, 0x2000000000000000LL + id);
}
persistenceId = id;
}
@@ -87,30 +203,58 @@ Exchange::shared_ptr Exchange::decode(ExchangeRegistry& exchanges, Buffer& buffe
{
string name;
string type;
+ string altName;
FieldTable args;
-
+
buffer.getShortString(name);
bool durable(buffer.getOctet());
buffer.getShortString(type);
buffer.get(args);
+ // For backwards compatibility on restoring exchanges from before the alt-exchange update, perform check
+ if (buffer.available())
+ buffer.getShortString(altName);
- return exchanges.declare(name, type, durable, args).first;
+ try {
+ Exchange::shared_ptr exch = exchanges.declare(name, type, durable, args).first;
+ exch->sequenceNo = args.getAsInt64(qpidSequenceCounter);
+ exch->alternateName.assign(altName);
+ return exch;
+ } catch (const UnknownExchangeTypeException&) {
+ QPID_LOG(warning, "Could not create exchange " << name << "; type " << type << " is not recognised");
+ return Exchange::shared_ptr();
+ }
}
-void Exchange::encode(Buffer& buffer) const
+void Exchange::encode(Buffer& buffer) const
{
buffer.putShortString(name);
buffer.putOctet(durable);
buffer.putShortString(getType());
+ if (args.isSet(qpidSequenceCounter))
+ args.setInt64(std::string(qpidSequenceCounter),sequenceNo);
buffer.put(args);
+ buffer.putShortString(alternate.get() ? alternate->getName() : string(""));
}
-uint32_t Exchange::encodedSize() const
-{
+uint32_t Exchange::encodedSize() const
+{
return name.size() + 1/*short string size*/
+ 1 /*durable*/
+ getType().size() + 1/*short string size*/
- + args.size();
+ + (alternate.get() ? alternate->getName().size() : 0) + 1/*short string size*/
+ + args.encodedSize();
+}
+
+void Exchange::recoveryComplete(ExchangeRegistry& exchanges)
+{
+ if (!alternateName.empty()) {
+ try {
+ Exchange::shared_ptr ae = exchanges.get(alternateName);
+ setAlternate(ae);
+ } catch (const NotFoundException&) {
+ QPID_LOG(warning, "Could not set alternate exchange \"" << alternateName << "\": does not exist.");
+ }
+ }
}
ManagementObject* Exchange::GetManagementObject (void) const
@@ -118,30 +262,85 @@ ManagementObject* Exchange::GetManagementObject (void) const
return (ManagementObject*) mgmtExchange;
}
+void Exchange::registerDynamicBridge(DynamicBridge* db)
+{
+ if (!supportsDynamicBinding())
+ throw Exception("Exchange type does not support dynamic binding");
+
+ {
+ Mutex::ScopedLock l(bridgeLock);
+ for (std::vector<DynamicBridge*>::iterator iter = bridgeVector.begin();
+ iter != bridgeVector.end(); iter++)
+ (*iter)->sendReorigin();
+
+ bridgeVector.push_back(db);
+ }
+
+ FieldTable args;
+ args.setString(qpidFedOp, fedOpReorigin);
+ bind(Queue::shared_ptr(), string(), &args);
+}
+
+void Exchange::removeDynamicBridge(DynamicBridge* db)
+{
+ Mutex::ScopedLock l(bridgeLock);
+ for (std::vector<DynamicBridge*>::iterator iter = bridgeVector.begin();
+ iter != bridgeVector.end(); iter++)
+ if (*iter == db) {
+ bridgeVector.erase(iter);
+ break;
+ }
+}
+
+void Exchange::handleHelloRequest()
+{
+}
+
+void Exchange::propagateFedOp(const string& routingKey, const string& tags, const string& op, const string& origin)
+{
+ Mutex::ScopedLock l(bridgeLock);
+ string myOp(op.empty() ? fedOpBind : op);
+
+ for (std::vector<DynamicBridge*>::iterator iter = bridgeVector.begin();
+ iter != bridgeVector.end(); iter++)
+ (*iter)->propagateBinding(routingKey, tags, op, origin);
+}
+
Exchange::Binding::Binding(const string& _key, Queue::shared_ptr _queue, Exchange* parent,
- FieldTable _args)
+ FieldTable _args, const string& origin)
: queue(_queue), key(_key), args(_args), mgmtBinding(0)
{
if (parent != 0)
{
- ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
- if (agent != 0)
- {
- ManagementObject* mo = queue->GetManagementObject();
- if (mo != 0)
- {
- uint64_t queueId = mo->getObjectId();
- mgmtBinding = new management::Binding (agent, this, (Manageable*) parent, queueId, key, args);
- agent->addObject (mgmtBinding);
- }
+ Broker* broker = parent->getBroker();
+ if (broker != 0) {
+ ManagementAgent* agent = broker->getManagementAgent();
+ if (agent != 0)
+ {
+ ManagementObject* mo = queue->GetManagementObject();
+ if (mo != 0)
+ {
+ management::ObjectId queueId = mo->getObjectId();
+ mgmtBinding = new _qmf::Binding
+ (agent, this, (Manageable*) parent, queueId, key, args);
+ if (!origin.empty())
+ mgmtBinding->set_origin(origin);
+ agent->addObject (mgmtBinding, agent->allocateId(this));
+ static_cast<_qmf::Queue*>(mo)->inc_bindingCount();
+ }
+ }
}
}
}
Exchange::Binding::~Binding ()
{
- if (mgmtBinding != 0)
+ if (mgmtBinding != 0) {
+ ManagementObject* mo = queue->GetManagementObject();
+ if (mo != 0)
+ static_cast<_qmf::Queue*>(mo)->dec_bindingCount();
mgmtBinding->resourceDestroy ();
+ }
}
ManagementObject* Exchange::Binding::GetManagementObject () const
@@ -149,7 +348,13 @@ ManagementObject* Exchange::Binding::GetManagementObject () const
return (ManagementObject*) mgmtBinding;
}
-Manageable::status_t Exchange::Binding::ManagementMethod (uint32_t, Args&)
+Exchange::MatchQueue::MatchQueue(Queue::shared_ptr q) : queue(q) {}
+
+bool Exchange::MatchQueue::operator()(Exchange::Binding::shared_ptr b)
{
- return Manageable::STATUS_UNKNOWN_METHOD;
+ return b->queue == queue;
+}
+
+void Exchange::setProperties(const boost::intrusive_ptr<Message>& msg) {
+ msg->getProperties<DeliveryProperties>()->setExchange(getName());
}
diff --git a/cpp/src/qpid/broker/Exchange.h b/cpp/src/qpid/broker/Exchange.h
index f4ac4373e4..d630f7ae24 100644
--- a/cpp/src/qpid/broker/Exchange.h
+++ b/cpp/src/qpid/broker/Exchange.h
@@ -23,87 +23,171 @@
*/
#include <boost/shared_ptr.hpp>
-#include "Deliverable.h"
-#include "Queue.h"
-#include "MessageStore.h"
-#include "PersistableExchange.h"
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/Deliverable.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/MessageStore.h"
+#include "qpid/broker/PersistableExchange.h"
#include "qpid/framing/FieldTable.h"
+#include "qpid/sys/Mutex.h"
#include "qpid/management/Manageable.h"
-#include "qpid/management/Exchange.h"
-#include "qpid/management/Binding.h"
+#include "qmf/org/apache/qpid/broker/Exchange.h"
+#include "qmf/org/apache/qpid/broker/Binding.h"
namespace qpid {
- namespace broker {
- using std::string;
- class ExchangeRegistry;
-
- class Exchange : public PersistableExchange, public management::Manageable {
- private:
- const string name;
- const bool durable;
- qpid::framing::FieldTable args;
- boost::shared_ptr<Exchange> alternate;
- uint32_t alternateUsers;
- mutable uint64_t persistenceId;
-
- protected:
- struct Binding : public management::Manageable {
- typedef boost::shared_ptr<Binding> shared_ptr;
- typedef std::vector<Binding::shared_ptr> vector;
-
- Queue::shared_ptr queue;
- const std::string key;
- const framing::FieldTable args;
- management::Binding* mgmtBinding;
-
- Binding(const std::string& key, Queue::shared_ptr queue, Exchange* parent = 0,
- framing::FieldTable args = framing::FieldTable ());
- ~Binding ();
- management::ManagementObject* GetManagementObject () const;
- management::Manageable::status_t ManagementMethod (uint32_t methodId, management::Args& args);
- };
-
- management::Exchange* mgmtExchange;
-
- public:
- typedef boost::shared_ptr<Exchange> shared_ptr;
-
- explicit Exchange(const string& name, management::Manageable* parent = 0);
- Exchange(const string& _name, bool _durable, const qpid::framing::FieldTable& _args,
- management::Manageable* parent = 0);
- virtual ~Exchange();
-
- const string& getName() const { return name; }
- bool isDurable() { return durable; }
- qpid::framing::FieldTable& getArgs() { return args; }
-
- Exchange::shared_ptr getAlternate() { return alternate; }
- void setAlternate(Exchange::shared_ptr _alternate) { alternate = _alternate; }
- void incAlternateUsers() { alternateUsers++; }
- void decAlternateUsers() { alternateUsers--; }
- bool inUseAsAlternate() { return alternateUsers > 0; }
-
- virtual string getType() const = 0;
- virtual bool bind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args) = 0;
- virtual bool unbind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args) = 0;
- virtual bool isBound(Queue::shared_ptr queue, const string* const routingKey, const qpid::framing::FieldTable* const args) = 0;
- virtual void route(Deliverable& msg, const string& routingKey, const qpid::framing::FieldTable* args) = 0;
-
- //PersistableExchange:
- void setPersistenceId(uint64_t id) const;
- uint64_t getPersistenceId() const { return persistenceId; }
- uint32_t encodedSize() const;
- void encode(framing::Buffer& buffer) const;
-
- static Exchange::shared_ptr decode(ExchangeRegistry& exchanges, framing::Buffer& buffer);
-
- // Manageable entry points
- management::ManagementObject* GetManagementObject (void) const;
- management::Manageable::status_t
- ManagementMethod (uint32_t, management::Args&) { return management::Manageable::STATUS_UNKNOWN_METHOD; }
- };
- }
-}
-
+namespace broker {
+
+class ExchangeRegistry;
+
+class Exchange : public PersistableExchange, public management::Manageable {
+public:
+ struct Binding : public management::Manageable {
+ typedef boost::shared_ptr<Binding> shared_ptr;
+ typedef std::vector<Binding::shared_ptr> vector;
+
+ Queue::shared_ptr queue;
+ const std::string key;
+ const framing::FieldTable args;
+ qmf::org::apache::qpid::broker::Binding* mgmtBinding;
+
+ Binding(const std::string& key, Queue::shared_ptr queue, Exchange* parent = 0,
+ framing::FieldTable args = framing::FieldTable(), const std::string& origin = std::string());
+ ~Binding();
+ management::ManagementObject* GetManagementObject() const;
+ };
+
+private:
+ const std::string name;
+ const bool durable;
+ std::string alternateName;
+ boost::shared_ptr<Exchange> alternate;
+ uint32_t alternateUsers;
+ mutable uint64_t persistenceId;
+
+protected:
+ mutable qpid::framing::FieldTable args;
+ bool sequence;
+ mutable qpid::sys::Mutex sequenceLock;
+ int64_t sequenceNo;
+ bool ive;
+ boost::intrusive_ptr<Message> lastMsg;
+
+ class PreRoute{
+ public:
+ PreRoute(Deliverable& msg, Exchange* _p);
+ ~PreRoute();
+ private:
+ Exchange* parent;
+ };
+
+ typedef boost::shared_ptr<const std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> > > ConstBindingList;
+ typedef boost::shared_ptr< std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> > > BindingList;
+ void doRoute(Deliverable& msg, ConstBindingList b);
+ void routeIVE();
+
+
+ struct MatchQueue {
+ const Queue::shared_ptr queue;
+ MatchQueue(Queue::shared_ptr q);
+ bool operator()(Exchange::Binding::shared_ptr b);
+ };
+
+ class FedBinding {
+ uint32_t localBindings;
+ std::set<std::string> originSet;
+ public:
+ FedBinding() : localBindings(0) {}
+ bool hasLocal() const { return localBindings != 0; }
+ bool addOrigin(const std::string& origin) {
+ if (origin.empty()) {
+ localBindings++;
+ return localBindings == 1;
+ }
+ originSet.insert(origin);
+ return true;
+ }
+ bool delOrigin(const std::string& origin) {
+ originSet.erase(origin);
+ return true;
+ }
+ bool delOrigin() {
+ if (localBindings > 0)
+ localBindings--;
+ return localBindings == 0;
+ }
+ uint32_t count() {
+ return localBindings + originSet.size();
+ }
+ };
+
+ qmf::org::apache::qpid::broker::Exchange* mgmtExchange;
+
+public:
+ typedef boost::shared_ptr<Exchange> shared_ptr;
+
+ QPID_BROKER_EXTERN explicit Exchange(const std::string& name, management::Manageable* parent = 0,
+ Broker* broker = 0);
+ QPID_BROKER_EXTERN Exchange(const std::string& _name, bool _durable, const qpid::framing::FieldTable& _args,
+ management::Manageable* parent = 0, Broker* broker = 0);
+ QPID_BROKER_EXTERN virtual ~Exchange();
+
+ const std::string& getName() const { return name; }
+ bool isDurable() { return durable; }
+ qpid::framing::FieldTable& getArgs() { return args; }
+
+ Exchange::shared_ptr getAlternate() { return alternate; }
+ void setAlternate(Exchange::shared_ptr _alternate);
+ void incAlternateUsers() { alternateUsers++; }
+ void decAlternateUsers() { alternateUsers--; }
+ bool inUseAsAlternate() { return alternateUsers > 0; }
+
+ virtual std::string getType() const = 0;
+ virtual bool bind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args) = 0;
+ virtual bool unbind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args) = 0;
+ virtual bool isBound(Queue::shared_ptr queue, const std::string* const routingKey, const qpid::framing::FieldTable* const args) = 0;
+ QPID_BROKER_EXTERN virtual void setProperties(const boost::intrusive_ptr<Message>&);
+ virtual void route(Deliverable& msg, const std::string& routingKey, const qpid::framing::FieldTable* args) = 0;
+
+ //PersistableExchange:
+ QPID_BROKER_EXTERN void setPersistenceId(uint64_t id) const;
+ uint64_t getPersistenceId() const { return persistenceId; }
+ QPID_BROKER_EXTERN uint32_t encodedSize() const;
+ QPID_BROKER_EXTERN virtual void encode(framing::Buffer& buffer) const;
+
+ static QPID_BROKER_EXTERN Exchange::shared_ptr decode(ExchangeRegistry& exchanges, framing::Buffer& buffer);
+
+ // Manageable entry points
+ QPID_BROKER_EXTERN management::ManagementObject* GetManagementObject(void) const;
+
+ // Federation hooks
+ class DynamicBridge {
+ public:
+ virtual ~DynamicBridge() {}
+ virtual void propagateBinding(const std::string& key, const std::string& tagList, const std::string& op, const std::string& origin) = 0;
+ virtual void sendReorigin() = 0;
+ virtual bool containsLocalTag(const std::string& tagList) const = 0;
+ virtual const std::string& getLocalTag() const = 0;
+ };
+
+ void registerDynamicBridge(DynamicBridge* db);
+ void removeDynamicBridge(DynamicBridge* db);
+ virtual bool supportsDynamicBinding() { return false; }
+ Broker* getBroker() const { return broker; }
+ /**
+ * Notify exchange that recovery has completed.
+ */
+ void recoveryComplete(ExchangeRegistry& exchanges);
+
+protected:
+ qpid::sys::Mutex bridgeLock;
+ std::vector<DynamicBridge*> bridgeVector;
+ Broker* broker;
+
+ QPID_BROKER_EXTERN virtual void handleHelloRequest();
+ void propagateFedOp(const std::string& routingKey, const std::string& tags,
+ const std::string& op, const std::string& origin);
+};
+
+}}
#endif /*!_broker_Exchange.cpp_h*/
diff --git a/cpp/src/qpid/broker/ExchangeRegistry.cpp b/cpp/src/qpid/broker/ExchangeRegistry.cpp
index 45eb308680..951cdbd395 100644
--- a/cpp/src/qpid/broker/ExchangeRegistry.cpp
+++ b/cpp/src/qpid/broker/ExchangeRegistry.cpp
@@ -19,15 +19,11 @@
*
*/
-#include "config.h"
-#include "ExchangeRegistry.h"
-#include "DirectExchange.h"
-#include "FanOutExchange.h"
-#include "HeadersExchange.h"
-#include "TopicExchange.h"
-#ifdef HAVE_XML
-#include "XmlExchange.h"
-#endif
+#include "qpid/broker/ExchangeRegistry.h"
+#include "qpid/broker/DirectExchange.h"
+#include "qpid/broker/FanOutExchange.h"
+#include "qpid/broker/HeadersExchange.h"
+#include "qpid/broker/TopicExchange.h"
#include "qpid/management/ManagementExchange.h"
#include "qpid/framing/reply_exceptions.h"
@@ -36,42 +32,35 @@ using namespace qpid::sys;
using std::pair;
using qpid::framing::FieldTable;
-pair<Exchange::shared_ptr, bool> ExchangeRegistry::declare(const string& name, const string& type)
- throw(UnknownExchangeTypeException){
+pair<Exchange::shared_ptr, bool> ExchangeRegistry::declare(const string& name, const string& type){
return declare(name, type, false, FieldTable());
}
pair<Exchange::shared_ptr, bool> ExchangeRegistry::declare(const string& name, const string& type,
- bool durable, const FieldTable& args)
- throw(UnknownExchangeTypeException){
+ bool durable, const FieldTable& args){
RWlock::ScopedWlock locker(lock);
ExchangeMap::iterator i = exchanges.find(name);
if (i == exchanges.end()) {
Exchange::shared_ptr exchange;
if(type == TopicExchange::typeName){
- exchange = Exchange::shared_ptr(new TopicExchange(name, durable, args, parent));
+ exchange = Exchange::shared_ptr(new TopicExchange(name, durable, args, parent, broker));
}else if(type == DirectExchange::typeName){
- exchange = Exchange::shared_ptr(new DirectExchange(name, durable, args, parent));
+ exchange = Exchange::shared_ptr(new DirectExchange(name, durable, args, parent, broker));
}else if(type == FanOutExchange::typeName){
- exchange = Exchange::shared_ptr(new FanOutExchange(name, durable, args, parent));
+ exchange = Exchange::shared_ptr(new FanOutExchange(name, durable, args, parent, broker));
}else if (type == HeadersExchange::typeName) {
- exchange = Exchange::shared_ptr(new HeadersExchange(name, durable, args, parent));
+ exchange = Exchange::shared_ptr(new HeadersExchange(name, durable, args, parent, broker));
}else if (type == ManagementExchange::typeName) {
- exchange = Exchange::shared_ptr(new ManagementExchange(name, durable, args, parent));
+ exchange = Exchange::shared_ptr(new ManagementExchange(name, durable, args, parent, broker));
}
-#ifdef HAVE_XML
- else if (type == XmlExchange::typeName) {
- exchange = Exchange::shared_ptr(new XmlExchange(name, durable, args, parent));
- }
-#endif
else{
FunctionMap::iterator i = factory.find(type);
if (i == factory.end()) {
throw UnknownExchangeTypeException();
} else {
- exchange = i->second(name, durable, args, parent);
+ exchange = i->second(name, durable, args, parent, broker);
}
}
exchanges[name] = exchange;
@@ -82,6 +71,11 @@ pair<Exchange::shared_ptr, bool> ExchangeRegistry::declare(const string& name, c
}
void ExchangeRegistry::destroy(const string& name){
+ if (name.empty() ||
+ (name.find("amq.") == 0 &&
+ (name == "amq.direct" || name == "amq.fanout" || name == "amq.topic" || name == "amq.match")) ||
+ name == "qpid.management")
+ throw framing::NotAllowedException(QPID_MSG("Cannot delete default exchange: '" << name << "'"));
RWlock::ScopedWlock locker(lock);
ExchangeMap::iterator i = exchanges.find(name);
if (i != exchanges.end()) {
@@ -97,6 +91,10 @@ Exchange::shared_ptr ExchangeRegistry::get(const string& name){
return i->second;
}
+bool ExchangeRegistry::registerExchange(const Exchange::shared_ptr& ex) {
+ return exchanges.insert(ExchangeMap::value_type(ex->getName(), ex)).second;
+}
+
void ExchangeRegistry::registerType(const std::string& type, FactoryFunction f)
{
factory[type] = f;
diff --git a/cpp/src/qpid/broker/ExchangeRegistry.h b/cpp/src/qpid/broker/ExchangeRegistry.h
index 7573e3e415..2b75a8f3cf 100644
--- a/cpp/src/qpid/broker/ExchangeRegistry.h
+++ b/cpp/src/qpid/broker/ExchangeRegistry.h
@@ -22,51 +22,72 @@
*
*/
-#include <map>
-#include <boost/function.hpp>
-#include "Exchange.h"
-#include "MessageStore.h"
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/Exchange.h"
+#include "qpid/broker/MessageStore.h"
#include "qpid/framing/FieldTable.h"
#include "qpid/sys/Monitor.h"
#include "qpid/management/Manageable.h"
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+
+#include <algorithm>
+#include <map>
+
namespace qpid {
namespace broker {
- struct UnknownExchangeTypeException{};
-
- class ExchangeRegistry{
- public:
- typedef boost::function4<Exchange::shared_ptr, const std::string&,
- bool, const qpid::framing::FieldTable&, qpid::management::Manageable*> FactoryFunction;
-
- ExchangeRegistry () : parent(0) {}
- std::pair<Exchange::shared_ptr, bool> declare(const std::string& name, const std::string& type)
- throw(UnknownExchangeTypeException);
- std::pair<Exchange::shared_ptr, bool> declare(const std::string& name, const std::string& type,
- bool durable, const qpid::framing::FieldTable& args = framing::FieldTable())
- throw(UnknownExchangeTypeException);
- void destroy(const std::string& name);
- Exchange::shared_ptr get(const std::string& name);
- Exchange::shared_ptr getDefault();
-
- /**
- * Register the manageable parent for declared exchanges
- */
- void setParent (management::Manageable* _parent) { parent = _parent; }
-
- void registerType(const std::string& type, FactoryFunction);
- private:
- typedef std::map<std::string, Exchange::shared_ptr> ExchangeMap;
- typedef std::map<std::string, FactoryFunction > FunctionMap;
-
- ExchangeMap exchanges;
- FunctionMap factory;
- qpid::sys::RWlock lock;
- management::Manageable* parent;
-
- };
-}
-}
+
+struct UnknownExchangeTypeException{};
+
+class ExchangeRegistry{
+ public:
+ typedef boost::function5<Exchange::shared_ptr, const std::string&,
+ bool, const qpid::framing::FieldTable&, qpid::management::Manageable*, qpid::broker::Broker*> FactoryFunction;
+
+ ExchangeRegistry (Broker* b = 0) : parent(0), broker(b) {}
+ QPID_BROKER_EXTERN std::pair<Exchange::shared_ptr, bool> declare
+ (const std::string& name, const std::string& type);
+ QPID_BROKER_EXTERN std::pair<Exchange::shared_ptr, bool> declare
+ (const std::string& name,
+ const std::string& type,
+ bool durable,
+ const qpid::framing::FieldTable& args = framing::FieldTable());
+ QPID_BROKER_EXTERN void destroy(const std::string& name);
+ QPID_BROKER_EXTERN Exchange::shared_ptr get(const std::string& name);
+ Exchange::shared_ptr getDefault();
+
+ /**
+ * Register the manageable parent for declared exchanges
+ */
+ void setParent (management::Manageable* _parent) { parent = _parent; }
+
+ /** Register an exchange instance.
+ *@return true if registered, false if exchange with same name is already registered.
+ */
+ bool registerExchange(const Exchange::shared_ptr&);
+
+ QPID_BROKER_EXTERN void registerType(const std::string& type, FactoryFunction);
+
+ /** Call f for each exchange in the registry. */
+ template <class F> void eachExchange(F f) const {
+ qpid::sys::RWlock::ScopedRlock l(lock);
+ for (ExchangeMap::const_iterator i = exchanges.begin(); i != exchanges.end(); ++i)
+ f(i->second);
+ }
+
+ private:
+ typedef std::map<std::string, Exchange::shared_ptr> ExchangeMap;
+ typedef std::map<std::string, FactoryFunction > FunctionMap;
+
+ ExchangeMap exchanges;
+ FunctionMap factory;
+ mutable qpid::sys::RWlock lock;
+ management::Manageable* parent;
+ Broker* broker;
+};
+
+}} // namespace qpid::broker
#endif /*!_broker_ExchangeRegistry_h*/
diff --git a/cpp/src/qpid/broker/ExpiryPolicy.cpp b/cpp/src/qpid/broker/ExpiryPolicy.cpp
new file mode 100644
index 0000000000..64a12d918a
--- /dev/null
+++ b/cpp/src/qpid/broker/ExpiryPolicy.cpp
@@ -0,0 +1,38 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/broker/ExpiryPolicy.h"
+#include "qpid/broker/Message.h"
+#include "qpid/sys/Time.h"
+
+namespace qpid {
+namespace broker {
+
+ExpiryPolicy::~ExpiryPolicy() {}
+
+void ExpiryPolicy::willExpire(Message&) {}
+
+bool ExpiryPolicy::hasExpired(Message& m) {
+ return m.getExpiration() < sys::AbsTime::now();
+}
+
+void ExpiryPolicy::forget(Message&) {}
+
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/ExpiryPolicy.h b/cpp/src/qpid/broker/ExpiryPolicy.h
new file mode 100644
index 0000000000..40e793bf2c
--- /dev/null
+++ b/cpp/src/qpid/broker/ExpiryPolicy.h
@@ -0,0 +1,46 @@
+#ifndef QPID_BROKER_EXPIRYPOLICY_H
+#define QPID_BROKER_EXPIRYPOLICY_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/RefCounted.h"
+#include "qpid/broker/BrokerImportExport.h"
+
+namespace qpid {
+namespace broker {
+
+class Message;
+
+/**
+ * Default expiry policy.
+ */
+class ExpiryPolicy : public RefCounted
+{
+ public:
+ QPID_BROKER_EXTERN virtual ~ExpiryPolicy();
+ QPID_BROKER_EXTERN virtual void willExpire(Message&);
+ QPID_BROKER_EXTERN virtual bool hasExpired(Message&);
+ QPID_BROKER_EXTERN virtual void forget(Message&);
+};
+}} // namespace qpid::broker
+
+#endif /*!QPID_BROKER_EXPIRYPOLICY_H*/
diff --git a/cpp/src/qpid/broker/FanOutExchange.cpp b/cpp/src/qpid/broker/FanOutExchange.cpp
index 373e9ab1cc..6d840b50df 100644
--- a/cpp/src/qpid/broker/FanOutExchange.cpp
+++ b/cpp/src/qpid/broker/FanOutExchange.cpp
@@ -18,106 +18,102 @@
* under the License.
*
*/
-#include "FanOutExchange.h"
+#include "qpid/broker/FanOutExchange.h"
#include <algorithm>
using namespace qpid::broker;
using namespace qpid::framing;
using namespace qpid::sys;
+namespace _qmf = qmf::org::apache::qpid::broker;
-FanOutExchange::FanOutExchange(const std::string& _name, Manageable* _parent) :
- Exchange(_name, _parent)
+namespace
+{
+const std::string qpidFedOp("qpid.fed.op");
+const std::string qpidFedTags("qpid.fed.tags");
+const std::string qpidFedOrigin("qpid.fed.origin");
+
+const std::string fedOpBind("B");
+const std::string fedOpUnbind("U");
+const std::string fedOpReorigin("R");
+const std::string fedOpHello("H");
+}
+
+FanOutExchange::FanOutExchange(const std::string& _name, Manageable* _parent, Broker* b) :
+ Exchange(_name, _parent, b)
{
if (mgmtExchange != 0)
mgmtExchange->set_type (typeName);
}
FanOutExchange::FanOutExchange(const std::string& _name, bool _durable,
- const FieldTable& _args, Manageable* _parent) :
- Exchange(_name, _durable, _args, _parent)
+ const FieldTable& _args, Manageable* _parent, Broker* b) :
+ Exchange(_name, _durable, _args, _parent, b)
{
if (mgmtExchange != 0)
mgmtExchange->set_type (typeName);
}
-bool FanOutExchange::bind(Queue::shared_ptr queue, const string& /*routingKey*/, const FieldTable* /*args*/){
- RWlock::ScopedWlock locker(lock);
- std::vector<Binding::shared_ptr>::iterator i;
-
- // Add if not already present.
- for (i = bindings.begin (); i != bindings.end(); i++)
- if ((*i)->queue == queue)
- break;
-
- if (i == bindings.end()) {
- Binding::shared_ptr binding (new Binding ("", queue, this));
- bindings.push_back(binding);
- if (mgmtExchange != 0) {
- mgmtExchange->inc_bindingCount();
- ((management::Queue*) queue->GetManagementObject())->inc_bindingCount();
+bool FanOutExchange::bind(Queue::shared_ptr queue, const string& /*key*/, const FieldTable* args)
+{
+ string fedOp(args ? args->getAsString(qpidFedOp) : fedOpBind);
+ string fedTags(args ? args->getAsString(qpidFedTags) : "");
+ string fedOrigin(args ? args->getAsString(qpidFedOrigin) : "");
+ bool propagate = false;
+
+ if (args == 0 || fedOp.empty() || fedOp == fedOpBind) {
+ Binding::shared_ptr binding (new Binding ("", queue, this, FieldTable(), fedOrigin));
+ if (bindings.add_unless(binding, MatchQueue(queue))) {
+ propagate = fedBinding.addOrigin(fedOrigin);
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_bindingCount();
+ }
+ } else {
+ return false;
+ }
+ } else if (fedOp == fedOpUnbind) {
+ propagate = fedBinding.delOrigin(fedOrigin);
+ if (fedBinding.count() == 0)
+ unbind(queue, "", 0);
+ } else if (fedOp == fedOpReorigin) {
+ if (fedBinding.hasLocal()) {
+ propagateFedOp(string(), string(), fedOpBind, string());
}
- return true;
- } else {
- return false;
}
-}
-bool FanOutExchange::unbind(Queue::shared_ptr queue, const string& /*routingKey*/, const FieldTable* /*args*/){
- RWlock::ScopedWlock locker(lock);
- std::vector<Binding::shared_ptr>::iterator i;
+ routeIVE();
+ if (propagate)
+ propagateFedOp(string(), fedTags, fedOp, fedOrigin);
+ return true;
+}
- for (i = bindings.begin (); i != bindings.end(); i++)
- if ((*i)->queue == queue)
- break;
+bool FanOutExchange::unbind(Queue::shared_ptr queue, const string& /*key*/, const FieldTable* /*args*/)
+{
+ bool propagate = false;
- if (i != bindings.end()) {
- bindings.erase(i);
+ if (bindings.remove_if(MatchQueue(queue))) {
+ propagate = fedBinding.delOrigin();
if (mgmtExchange != 0) {
mgmtExchange->dec_bindingCount();
- ((management::Queue*) queue->GetManagementObject())->dec_bindingCount();
}
- return true;
} else {
return false;
}
-}
-
-void FanOutExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* /*args*/){
- RWlock::ScopedRlock locker(lock);
- uint32_t count(0);
-
- for(std::vector<Binding::shared_ptr>::iterator i = bindings.begin(); i != bindings.end(); ++i, count++){
- msg.deliverTo((*i)->queue);
- if ((*i)->mgmtBinding != 0)
- (*i)->mgmtBinding->inc_msgMatched ();
- }
- if (mgmtExchange != 0)
- {
- mgmtExchange->inc_msgReceives ();
- mgmtExchange->inc_byteReceives (msg.contentSize ());
- if (count == 0)
- {
- mgmtExchange->inc_msgDrops ();
- mgmtExchange->inc_byteDrops (msg.contentSize ());
- }
- else
- {
- mgmtExchange->inc_msgRoutes (count);
- mgmtExchange->inc_byteRoutes (count * msg.contentSize ());
- }
- }
+ if (propagate)
+ propagateFedOp(string(), string(), fedOpUnbind, string());
+ return true;
}
+void FanOutExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* /*args*/)
+{
+ PreRoute pr(msg, this);
+ doRoute(msg, bindings.snapshot());
+}
+
bool FanOutExchange::isBound(Queue::shared_ptr queue, const string* const, const FieldTable* const)
{
- std::vector<Binding::shared_ptr>::iterator i;
-
- for (i = bindings.begin (); i != bindings.end(); i++)
- if ((*i)->queue == queue)
- break;
-
- return i != bindings.end();
+ BindingsArray::ConstPtr ptr = bindings.snapshot();
+ return ptr && std::find_if(ptr->begin(), ptr->end(), MatchQueue(queue)) != ptr->end();
}
diff --git a/cpp/src/qpid/broker/FanOutExchange.h b/cpp/src/qpid/broker/FanOutExchange.h
index 4bc92f6b28..7bcf6367cf 100644
--- a/cpp/src/qpid/broker/FanOutExchange.h
+++ b/cpp/src/qpid/broker/FanOutExchange.h
@@ -23,37 +23,47 @@
#include <map>
#include <vector>
-#include "Exchange.h"
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/Exchange.h"
#include "qpid/framing/FieldTable.h"
-#include "qpid/sys/Monitor.h"
-#include "Queue.h"
+#include "qpid/sys/CopyOnWriteArray.h"
+#include "qpid/broker/Queue.h"
namespace qpid {
namespace broker {
class FanOutExchange : public virtual Exchange {
- std::vector<Binding::shared_ptr> bindings;
- qpid::sys::RWlock lock;
-
+ typedef qpid::sys::CopyOnWriteArray<Binding::shared_ptr> BindingsArray;
+ BindingsArray bindings;
+ FedBinding fedBinding;
public:
static const std::string typeName;
- FanOutExchange(const std::string& name, management::Manageable* parent = 0);
- FanOutExchange(const string& _name, bool _durable,
- const qpid::framing::FieldTable& _args,
- management::Manageable* parent = 0);
+ QPID_BROKER_EXTERN FanOutExchange(const std::string& name,
+ management::Manageable* parent = 0, Broker* broker = 0);
+ QPID_BROKER_EXTERN FanOutExchange(const string& _name,
+ bool _durable,
+ const qpid::framing::FieldTable& _args,
+ management::Manageable* parent = 0, Broker* broker = 0);
virtual std::string getType() const { return typeName; }
- virtual bool bind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
+ QPID_BROKER_EXTERN virtual bool bind(Queue::shared_ptr queue,
+ const std::string& routingKey,
+ const qpid::framing::FieldTable* args);
virtual bool unbind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
- virtual void route(Deliverable& msg, const std::string& routingKey, const qpid::framing::FieldTable* args);
+ QPID_BROKER_EXTERN virtual void route(Deliverable& msg,
+ const std::string& routingKey,
+ const qpid::framing::FieldTable* args);
- virtual bool isBound(Queue::shared_ptr queue, const string* const routingKey, const qpid::framing::FieldTable* const args);
+ QPID_BROKER_EXTERN virtual bool isBound(Queue::shared_ptr queue,
+ const string* const routingKey,
+ const qpid::framing::FieldTable* const args);
- virtual ~FanOutExchange();
+ QPID_BROKER_EXTERN virtual ~FanOutExchange();
+ virtual bool supportsDynamicBinding() { return true; }
};
}
diff --git a/cpp/src/qpid/broker/HandlerImpl.h b/cpp/src/qpid/broker/HandlerImpl.h
index 4c51e2a826..aae636e818 100644
--- a/cpp/src/qpid/broker/HandlerImpl.h
+++ b/cpp/src/qpid/broker/HandlerImpl.h
@@ -19,9 +19,9 @@
*
*/
-#include "SemanticState.h"
-#include "SessionContext.h"
-#include "ConnectionState.h"
+#include "qpid/broker/SemanticState.h"
+#include "qpid/broker/SessionContext.h"
+#include "qpid/broker/ConnectionState.h"
namespace qpid {
namespace broker {
diff --git a/cpp/src/qpid/broker/HeadersExchange.cpp b/cpp/src/qpid/broker/HeadersExchange.cpp
index 54519a7bf6..38cc0e4050 100644
--- a/cpp/src/qpid/broker/HeadersExchange.cpp
+++ b/cpp/src/qpid/broker/HeadersExchange.cpp
@@ -18,7 +18,7 @@
* under the License.
*
*/
-#include "HeadersExchange.h"
+#include "qpid/broker/HeadersExchange.h"
#include "qpid/framing/FieldValue.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/log/Statement.h"
@@ -28,6 +28,7 @@
using namespace qpid::broker;
using namespace qpid::framing;
using namespace qpid::sys;
+namespace _qmf = qmf::org::apache::qpid::broker;
// TODO aconway 2006-09-20: More efficient matching algorithm.
// The current search algorithm really sucks.
@@ -42,16 +43,16 @@ namespace {
const std::string empty;
}
-HeadersExchange::HeadersExchange(const string& _name, Manageable* _parent) :
- Exchange(_name, _parent)
+HeadersExchange::HeadersExchange(const string& _name, Manageable* _parent, Broker* b) :
+ Exchange(_name, _parent, b)
{
if (mgmtExchange != 0)
mgmtExchange->set_type (typeName);
}
HeadersExchange::HeadersExchange(const std::string& _name, bool _durable,
- const FieldTable& _args, Manageable* _parent) :
- Exchange(_name, _durable, _args, _parent)
+ const FieldTable& _args, Manageable* _parent, Broker* b) :
+ Exchange(_name, _durable, _args, _parent, b)
{
if (mgmtExchange != 0)
mgmtExchange->set_type (typeName);
@@ -73,50 +74,26 @@ std::string HeadersExchange::getMatch(const FieldTable* args)
}
bool HeadersExchange::bind(Queue::shared_ptr queue, const string& bindingKey, const FieldTable* args){
- RWlock::ScopedWlock locker(lock);
std::string what = getMatch(args);
if (what != all && what != any)
throw InternalErrorException(QPID_MSG("Invalid x-match value binding to headers exchange."));
- Bindings::iterator i;
-
- for (i = bindings.begin(); i != bindings.end(); i++)
- if (i->first == *args && i->second->queue == queue)
- break;
-
- if (i == bindings.end()) {
- Binding::shared_ptr binding (new Binding (bindingKey, queue, this, *args));
- HeaderMap headerMap(*args, binding);
-
- bindings.push_back(headerMap);
+ Binding::shared_ptr binding (new Binding (bindingKey, queue, this, *args));
+ if (bindings.add_unless(binding, MatchArgs(queue, args))) {
if (mgmtExchange != 0) {
mgmtExchange->inc_bindingCount();
- ((management::Queue*) queue->GetManagementObject())->inc_bindingCount();
}
+ routeIVE();
return true;
} else {
return false;
}
}
-bool HeadersExchange::unbind(Queue::shared_ptr queue, const string& bindingKey, const FieldTable* args){
- RWlock::ScopedWlock locker(lock);
- Bindings::iterator i;
- for (i = bindings.begin(); i != bindings.end(); i++) {
- if (bindingKey.empty() && args) {
- if (i->first == *args && i->second->queue == queue)
- break;
- } else {
- if (i->second->key == bindingKey && i->second->queue == queue)
- break;
- }
- }
-
- if (i != bindings.end()) {
- bindings.erase(i);
+bool HeadersExchange::unbind(Queue::shared_ptr queue, const string& bindingKey, const FieldTable*){
+ if (bindings.remove_if(MatchKey(queue, bindingKey))) {
if (mgmtExchange != 0) {
mgmtExchange->dec_bindingCount();
- ((management::Queue*) queue->GetManagementObject())->dec_bindingCount();
}
return true;
} else {
@@ -125,41 +102,43 @@ bool HeadersExchange::unbind(Queue::shared_ptr queue, const string& bindingKey,
}
-void HeadersExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* args){
- if (!args) return;//can't match if there were no headers passed in
-
- RWlock::ScopedRlock locker(lock);
- uint32_t count(0);
-
- for (Bindings::iterator i = bindings.begin(); i != bindings.end(); ++i, count++) {
- if (match(i->first, *args)) msg.deliverTo(i->second->queue);
- if (i->second->mgmtBinding != 0)
- i->second->mgmtBinding->inc_msgMatched ();
+void HeadersExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* args)
+{
+ if (!args) {
+ //can't match if there were no headers passed in
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_msgReceives();
+ mgmtExchange->inc_byteReceives(msg.contentSize());
+ mgmtExchange->inc_msgDrops();
+ mgmtExchange->inc_byteDrops(msg.contentSize());
+ }
+ return;
}
- if (mgmtExchange != 0)
+ PreRoute pr(msg, this);
+
+ ConstBindingList p = bindings.snapshot();
+ BindingList b(new std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> >);
+ if (p.get())
{
- mgmtExchange->inc_msgReceives ();
- mgmtExchange->inc_byteReceives (msg.contentSize ());
- if (count == 0)
- {
- mgmtExchange->inc_msgDrops ();
- mgmtExchange->inc_byteDrops (msg.contentSize ());
- }
- else
- {
- mgmtExchange->inc_msgRoutes (count);
- mgmtExchange->inc_byteRoutes (count * msg.contentSize ());
+ for (std::vector<Binding::shared_ptr>::const_iterator i = p->begin(); i != p->end(); ++i) {
+ if (match((*i)->args, *args)) {
+ b->push_back(*i);
+ }
}
}
+ doRoute(msg, b);
}
bool HeadersExchange::isBound(Queue::shared_ptr queue, const string* const, const FieldTable* const args)
{
- for (Bindings::iterator i = bindings.begin(); i != bindings.end(); ++i) {
- if ( (!args || equal(i->first, *args)) && (!queue || i->second->queue == queue)) {
- return true;
+ Bindings::ConstPtr p = bindings.snapshot();
+ if (p.get()){
+ for (std::vector<Binding::shared_ptr>::const_iterator i = p->begin(); i != p->end(); ++i) {
+ if ( (!args || equal((*i)->args, *args)) && (!queue || (*i)->queue == queue)) {
+ return true;
+ }
}
}
return false;
@@ -227,5 +206,15 @@ bool HeadersExchange::equal(const FieldTable& a, const FieldTable& b) {
return true;
}
+HeadersExchange::MatchArgs::MatchArgs(Queue::shared_ptr q, const qpid::framing::FieldTable* a) : queue(q), args(a) {}
+bool HeadersExchange::MatchArgs::operator()(Exchange::Binding::shared_ptr b)
+{
+ return b->queue == queue && b->args == *args;
+}
+HeadersExchange::MatchKey::MatchKey(Queue::shared_ptr q, const std::string& k) : queue(q), key(k) {}
+bool HeadersExchange::MatchKey::operator()(Exchange::Binding::shared_ptr b)
+{
+ return b->queue == queue && b->key == key;
+}
diff --git a/cpp/src/qpid/broker/HeadersExchange.h b/cpp/src/qpid/broker/HeadersExchange.h
index 6e101e193a..6425b44251 100644
--- a/cpp/src/qpid/broker/HeadersExchange.h
+++ b/cpp/src/qpid/broker/HeadersExchange.h
@@ -22,10 +22,12 @@
#define _HeadersExchange_
#include <vector>
-#include "Exchange.h"
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/Exchange.h"
#include "qpid/framing/FieldTable.h"
-#include "qpid/sys/Monitor.h"
-#include "Queue.h"
+#include "qpid/sys/CopyOnWriteArray.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/broker/Queue.h"
namespace qpid {
namespace broker {
@@ -33,34 +35,57 @@ namespace broker {
class HeadersExchange : public virtual Exchange {
typedef std::pair<qpid::framing::FieldTable, Binding::shared_ptr> HeaderMap;
- typedef std::vector<HeaderMap> Bindings;
+ typedef qpid::sys::CopyOnWriteArray<Binding::shared_ptr> Bindings;
+
+ struct MatchArgs
+ {
+ const Queue::shared_ptr queue;
+ const qpid::framing::FieldTable* args;
+ MatchArgs(Queue::shared_ptr q, const qpid::framing::FieldTable* a);
+ bool operator()(Exchange::Binding::shared_ptr b);
+ };
+ struct MatchKey
+ {
+ const Queue::shared_ptr queue;
+ const std::string& key;
+ MatchKey(Queue::shared_ptr q, const std::string& k);
+ bool operator()(Exchange::Binding::shared_ptr b);
+ };
Bindings bindings;
- qpid::sys::RWlock lock;
+ qpid::sys::Mutex lock;
static std::string getMatch(const framing::FieldTable* args);
public:
static const std::string typeName;
- HeadersExchange(const string& name, management::Manageable* parent = 0);
- HeadersExchange(const string& _name, bool _durable,
- const qpid::framing::FieldTable& _args,
- management::Manageable* parent = 0);
+ QPID_BROKER_EXTERN HeadersExchange(const string& name,
+ management::Manageable* parent = 0, Broker* broker = 0);
+ QPID_BROKER_EXTERN HeadersExchange(const string& _name,
+ bool _durable,
+ const qpid::framing::FieldTable& _args,
+ management::Manageable* parent = 0, Broker* broker = 0);
virtual std::string getType() const { return typeName; }
- virtual bool bind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args);
+ QPID_BROKER_EXTERN virtual bool bind(Queue::shared_ptr queue,
+ const string& routingKey,
+ const qpid::framing::FieldTable* args);
virtual bool unbind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args);
- virtual void route(Deliverable& msg, const string& routingKey, const qpid::framing::FieldTable* args);
+ QPID_BROKER_EXTERN virtual void route(Deliverable& msg,
+ const string& routingKey,
+ const qpid::framing::FieldTable* args);
- virtual bool isBound(Queue::shared_ptr queue, const string* const routingKey, const qpid::framing::FieldTable* const args);
+ QPID_BROKER_EXTERN virtual bool isBound(Queue::shared_ptr queue,
+ const string* const routingKey,
+ const qpid::framing::FieldTable* const args);
- virtual ~HeadersExchange();
+ QPID_BROKER_EXTERN virtual ~HeadersExchange();
- static bool match(const qpid::framing::FieldTable& bindArgs, const qpid::framing::FieldTable& msgArgs);
+ static QPID_BROKER_EXTERN bool match(const qpid::framing::FieldTable& bindArgs, const qpid::framing::FieldTable& msgArgs);
static bool equal(const qpid::framing::FieldTable& bindArgs, const qpid::framing::FieldTable& msgArgs);
};
diff --git a/cpp/src/qpid/broker/IncomingExecutionContext.cpp b/cpp/src/qpid/broker/IncomingExecutionContext.cpp
deleted file mode 100644
index 6c6cae6740..0000000000
--- a/cpp/src/qpid/broker/IncomingExecutionContext.cpp
+++ /dev/null
@@ -1,143 +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 "IncomingExecutionContext.h"
-#include "qpid/Exception.h"
-
-namespace qpid {
-namespace broker {
-
-using boost::intrusive_ptr;
-using qpid::framing::AccumulatedAck;
-using qpid::framing::SequenceNumber;
-using qpid::framing::SequenceNumberSet;
-
-void IncomingExecutionContext::noop()
-{
- complete(next());
-}
-
-void IncomingExecutionContext::flush()
-{
- for (Messages::iterator i = incomplete.begin(); i != incomplete.end(); ) {
- if ((*i)->isEnqueueComplete()) {
- complete((*i)->getCommandId());
- i = incomplete.erase(i);
- } else {
- i++;
- }
- }
- window.lwm = completed.mark;
-}
-
-void IncomingExecutionContext::sync()
-{
- while (completed.mark < window.hwm) {
- wait();
- }
-}
-
-void IncomingExecutionContext::sync(const SequenceNumber& point)
-{
- while (!isComplete(point)) {
- wait();
- }
-}
-
-/**
- * Every call to next() should be followed be either a call to
- * complete() - in the case of commands, which are always synchronous
- * - or track() - in the case of messages which may be asynchronously
- * stored.
- */
-SequenceNumber IncomingExecutionContext::next()
-{
- return ++window.hwm;
-}
-
-void IncomingExecutionContext::complete(const SequenceNumber& command)
-{
- completed.update(command, command);
-}
-
-void IncomingExecutionContext::track(intrusive_ptr<Message> msg)
-{
- if (msg->isEnqueueComplete()) {
- complete(msg->getCommandId());
- } else {
- incomplete.push_back(msg);
- }
-}
-
-bool IncomingExecutionContext::isComplete(const SequenceNumber& command)
-{
- if (command > window.hwm) {
- throw Exception(QPID_MSG("Bad sync request: point exceeds last command received ["
- << command.getValue() << " > " << window.hwm.getValue() << "]"));
- }
-
- return completed.covers(command);
-}
-
-
-const SequenceNumber& IncomingExecutionContext::getMark()
-{
- return completed.mark;
-}
-
-SequenceNumberSet IncomingExecutionContext::getRange()
-{
- SequenceNumberSet range;
- completed.collectRanges(range);
- return range;
-}
-
-void IncomingExecutionContext::wait()
-{
- check();
- // for IO flush on the store
- for (Messages::iterator i = incomplete.begin(); i != incomplete.end(); i++) {
- (*i)->flush();
- }
- incomplete.front()->waitForEnqueueComplete();
- flush();
-}
-
-/**
- * This is a check of internal state consistency.
- */
-void IncomingExecutionContext::check()
-{
- if (incomplete.empty()) {
- if (window.hwm != completed.mark) {
- //can only happen if there is a call to next() without a
- //corresponding call to completed() or track() - or if
- //there is a logical error in flush() or
- //AccumulatedAck::update()
- throw Exception(QPID_MSG("Completion tracking error: window.hwm="
- << window.hwm.getValue() << ", completed.mark="
- << completed.mark.getValue()));
- }
- }
-}
-
-}}
-
diff --git a/cpp/src/qpid/broker/IncomingExecutionContext.h b/cpp/src/qpid/broker/IncomingExecutionContext.h
deleted file mode 100644
index 7380e9ae64..0000000000
--- a/cpp/src/qpid/broker/IncomingExecutionContext.h
+++ /dev/null
@@ -1,61 +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.
- *
- */
-#ifndef _IncomingExecutionContext_
-#define _IncomingExecutionContext_
-
-#include "Message.h"
-
-#include "qpid/framing/AccumulatedAck.h"
-#include "qpid/framing/SequenceNumber.h"
-
-#include <boost/intrusive_ptr.hpp>
-
-namespace qpid {
-namespace broker {
-
-class IncomingExecutionContext
-{
- typedef std::list<boost::intrusive_ptr<Message> > Messages;
- framing::Window window;
- framing::AccumulatedAck completed;
- Messages incomplete;
-
- bool isComplete(const framing::SequenceNumber& command);
- void check();
- void wait();
-public:
- void noop();
- void flush();
- void sync();
- void sync(const framing::SequenceNumber& point);
- framing::SequenceNumber next();
- void complete(const framing::SequenceNumber& command);
- void track(boost::intrusive_ptr<Message>);
-
- const framing::SequenceNumber& getMark();
- framing::SequenceNumberSet getRange();
-
-};
-
-
-}}
-
-#endif
diff --git a/cpp/src/qpid/broker/IncompleteMessageList.cpp b/cpp/src/qpid/broker/IncompleteMessageList.cpp
index dd7bbfc067..02265ab85c 100644
--- a/cpp/src/qpid/broker/IncompleteMessageList.cpp
+++ b/cpp/src/qpid/broker/IncompleteMessageList.cpp
@@ -18,34 +18,67 @@
* under the License.
*
*/
-#include "IncompleteMessageList.h"
-#include "Message.h"
+#include "qpid/broker/IncompleteMessageList.h"
namespace qpid {
namespace broker {
+IncompleteMessageList::IncompleteMessageList() :
+ callback(boost::bind(&IncompleteMessageList::enqueueComplete, this, _1))
+{}
+
+IncompleteMessageList::~IncompleteMessageList()
+{
+ sys::Mutex::ScopedLock l(lock);
+ for (Messages::iterator i = incomplete.begin(); i != incomplete.end(); ++i) {
+ (*i)->resetEnqueueCompleteCallback();
+ (*i)->resetDequeueCompleteCallback();
+ }
+}
+
void IncompleteMessageList::add(boost::intrusive_ptr<Message> msg)
{
+ sys::Mutex::ScopedLock l(lock);
+ msg->setEnqueueCompleteCallback(callback);
incomplete.push_back(msg);
}
-void IncompleteMessageList::process(CompletionListener l, bool sync)
+void IncompleteMessageList::enqueueComplete(const boost::intrusive_ptr<Message>& ) {
+ sys::Mutex::ScopedLock l(lock);
+ lock.notify();
+}
+
+void IncompleteMessageList::process(const CompletionListener& listen, bool sync)
{
+ sys::Mutex::ScopedLock l(lock);
while (!incomplete.empty()) {
boost::intrusive_ptr<Message>& msg = incomplete.front();
if (!msg->isEnqueueComplete()) {
if (sync){
- msg->flush();
- msg->waitForEnqueueComplete();
+ {
+ sys::Mutex::ScopedUnlock u(lock);
+ msg->flush(); // Can re-enter IncompleteMessageList::enqueueComplete
+ }
+ while (!msg->isEnqueueComplete())
+ lock.wait();
} else {
//leave the message as incomplete for now
return;
}
}
- l(msg);
+ listen(msg);
incomplete.pop_front();
}
}
+void IncompleteMessageList::each(const CompletionListener& listen) {
+ Messages snapshot;
+ {
+ sys::Mutex::ScopedLock l(lock);
+ snapshot = incomplete;
+ }
+ std::for_each(incomplete.begin(), incomplete.end(), listen); // FIXME aconway 2008-11-07: passed by ref or value?
+}
+
}}
diff --git a/cpp/src/qpid/broker/IncompleteMessageList.h b/cpp/src/qpid/broker/IncompleteMessageList.h
index 2cfd7bfee5..a4debd1233 100644
--- a/cpp/src/qpid/broker/IncompleteMessageList.h
+++ b/cpp/src/qpid/broker/IncompleteMessageList.h
@@ -21,25 +21,35 @@
#ifndef _IncompleteMessageList_
#define _IncompleteMessageList_
-#include <list>
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/broker/Message.h"
#include <boost/intrusive_ptr.hpp>
#include <boost/function.hpp>
+#include <list>
namespace qpid {
namespace broker {
-class Message;
-
class IncompleteMessageList
{
typedef std::list< boost::intrusive_ptr<Message> > Messages;
+
+ void enqueueComplete(const boost::intrusive_ptr<Message>&);
+
+ sys::Monitor lock;
Messages incomplete;
+ Message::MessageCallback callback;
public:
- typedef boost::function<void(boost::intrusive_ptr<Message>)> CompletionListener;
-
- void add(boost::intrusive_ptr<Message> msg);
- void process(CompletionListener l, bool sync);
+ typedef Message::MessageCallback CompletionListener;
+
+ QPID_BROKER_EXTERN IncompleteMessageList();
+ QPID_BROKER_EXTERN ~IncompleteMessageList();
+
+ QPID_BROKER_EXTERN void add(boost::intrusive_ptr<Message> msg);
+ QPID_BROKER_EXTERN void process(const CompletionListener& l, bool sync);
+ void each(const CompletionListener& l);
};
diff --git a/cpp/src/qpid/broker/Link.cpp b/cpp/src/qpid/broker/Link.cpp
index 05b759f695..cdba18ccf9 100644
--- a/cpp/src/qpid/broker/Link.cpp
+++ b/cpp/src/qpid/broker/Link.cpp
@@ -19,50 +19,61 @@
*
*/
-#include "Link.h"
-#include "LinkRegistry.h"
-#include "Broker.h"
-#include "Connection.h"
-#include "qpid/agent/ManagementAgent.h"
-#include "qpid/management/Link.h"
+#include "qpid/broker/Link.h"
+#include "qpid/broker/LinkRegistry.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/broker/Connection.h"
+#include "qmf/org/apache/qpid/broker/EventBrokerLinkUp.h"
+#include "qmf/org/apache/qpid/broker/EventBrokerLinkDown.h"
#include "boost/bind.hpp"
#include "qpid/log/Statement.h"
+#include "qpid/framing/enum.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/broker/AclModule.h"
using namespace qpid::broker;
using qpid::framing::Buffer;
using qpid::framing::FieldTable;
+using qpid::framing::NotAllowedException;
+using qpid::framing::connection::CLOSE_CODE_CONNECTION_FORCED;
using qpid::management::ManagementAgent;
using qpid::management::ManagementObject;
using qpid::management::Manageable;
using qpid::management::Args;
using qpid::sys::Mutex;
+using std::stringstream;
+namespace _qmf = qmf::org::apache::qpid::broker;
Link::Link(LinkRegistry* _links,
MessageStore* _store,
string& _host,
uint16_t _port,
- bool _useSsl,
+ string& _transport,
bool _durable,
string& _authMechanism,
string& _username,
string& _password,
Broker* _broker,
- management::Manageable* parent)
- : links(_links), store(_store), host(_host), port(_port), useSsl(_useSsl), durable(_durable),
+ Manageable* parent)
+ : links(_links), store(_store), host(_host), port(_port),
+ transport(_transport),
+ durable(_durable),
authMechanism(_authMechanism), username(_username), password(_password),
persistenceId(0), mgmtObject(0), broker(_broker), state(0),
visitCount(0),
currentInterval(1),
closing(false),
+ updateUrls(false),
channelCounter(1),
- connection(0)
+ connection(0),
+ agent(0)
{
- if (parent != 0)
+ if (parent != 0 && broker != 0)
{
- ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ agent = broker->getManagementAgent();
if (agent != 0)
{
- mgmtObject = new management::Link(agent, this, parent, _host, _port, _useSsl, _durable);
+ mgmtObject = new _qmf::Link(agent, this, parent, _host, _port, _transport, _durable);
if (!durable)
agent->addObject(mgmtObject);
}
@@ -73,7 +84,7 @@ Link::Link(LinkRegistry* _links,
Link::~Link ()
{
if (state == STATE_OPERATIONAL && connection != 0)
- connection->close();
+ connection->close(CLOSE_CODE_CONNECTION_FORCED, "closed by management");
if (mgmtObject != 0)
mgmtObject->resourceDestroy ();
@@ -95,6 +106,7 @@ void Link::setStateLH (int newState)
case STATE_OPERATIONAL : mgmtObject->set_state("Operational"); break;
case STATE_FAILED : mgmtObject->set_state("Failed"); break;
case STATE_CLOSED : mgmtObject->set_state("Closed"); break;
+ case STATE_PASSIVE : mgmtObject->set_state("Passive"); break;
}
}
@@ -104,8 +116,9 @@ void Link::startConnectionLH ()
// Set the state before calling connect. It is possible that connect
// will fail synchronously and call Link::closed before returning.
setStateLH(STATE_CONNECTING);
- broker->connect (host, port, useSsl,
+ broker->connect (host, port, transport,
boost::bind (&Link::closed, this, _1, _2));
+ QPID_LOG (debug, "Inter-broker link connecting to " << host << ":" << port);
} catch(std::exception& e) {
setStateLH(STATE_WAITING);
if (mgmtObject != 0)
@@ -115,27 +128,39 @@ void Link::startConnectionLH ()
void Link::established ()
{
- Mutex::ScopedLock mutex(lock);
+ stringstream addr;
+ addr << host << ":" << port;
- QPID_LOG (info, "Inter-broker link established to " << host << ":" << port);
- setStateLH(STATE_OPERATIONAL);
- currentInterval = 1;
- visitCount = 0;
- if (closing)
- destroy();
+ QPID_LOG (info, "Inter-broker link established to " << addr.str());
+ agent->raiseEvent(_qmf::EventBrokerLinkUp(addr.str()));
+ {
+ Mutex::ScopedLock mutex(lock);
+ setStateLH(STATE_OPERATIONAL);
+ currentInterval = 1;
+ visitCount = 0;
+ if (closing)
+ destroy();
+ }
}
void Link::closed (int, std::string text)
{
Mutex::ScopedLock mutex(lock);
+ QPID_LOG (info, "Inter-broker link disconnected from " << host << ":" << port << " " << text);
connection = 0;
- if (state == STATE_OPERATIONAL)
- QPID_LOG (warning, "Inter-broker link disconnected from " << host << ":" << port);
+ if (state == STATE_OPERATIONAL) {
+ stringstream addr;
+ addr << host << ":" << port;
+ QPID_LOG (warning, "Inter-broker link disconnected from " << addr.str());
+ agent->raiseEvent(_qmf::EventBrokerLinkDown(addr.str()));
+ }
- for (Bridges::iterator i = active.begin(); i != active.end(); i++)
+ for (Bridges::iterator i = active.begin(); i != active.end(); i++) {
+ (*i)->closed();
created.push_back(*i);
+ }
active.clear();
if (state != STATE_FAILED)
@@ -149,32 +174,46 @@ void Link::closed (int, std::string text)
destroy();
}
-void Link::destroy ()
+void Link::checkClosePermission()
{
Mutex::ScopedLock mutex(lock);
- Bridges toDelete;
+
+ AclModule* acl = getBroker()->getAcl();
+ std::string userID = getUsername() + "@" + getBroker()->getOptions().realm;
+ if (acl && !acl->authorise(userID,acl::ACT_DELETE,acl::OBJ_LINK,"")){
+ throw NotAllowedException("ACL denied delete link request");
+ }
+}
- QPID_LOG (info, "Inter-broker link to " << host << ":" << port << " removed by management");
- if (connection)
- connection->close(403, "closed by management");
- setStateLH(STATE_CLOSED);
+void Link::destroy ()
+{
+ Bridges toDelete;
+ {
+ Mutex::ScopedLock mutex(lock);
- // Move the bridges to be deleted into a local vector so there is no
- // corruption of the iterator caused by bridge deletion.
- for (Bridges::iterator i = active.begin(); i != active.end(); i++)
- toDelete.push_back(*i);
- active.clear();
+ QPID_LOG (info, "Inter-broker link to " << host << ":" << port << " removed by management");
+ if (connection)
+ connection->close(CLOSE_CODE_CONNECTION_FORCED, "closed by management");
+
+ setStateLH(STATE_CLOSED);
- for (Bridges::iterator i = created.begin(); i != created.end(); i++)
- toDelete.push_back(*i);
- created.clear();
+ // Move the bridges to be deleted into a local vector so there is no
+ // corruption of the iterator caused by bridge deletion.
+ for (Bridges::iterator i = active.begin(); i != active.end(); i++) {
+ (*i)->closed();
+ toDelete.push_back(*i);
+ }
+ active.clear();
- // Now delete all bridges on this link.
+ for (Bridges::iterator i = created.begin(); i != created.end(); i++)
+ toDelete.push_back(*i);
+ created.clear();
+ }
+ // Now delete all bridges on this link (don't hold the lock for this).
for (Bridges::iterator i = toDelete.begin(); i != toDelete.end(); i++)
(*i)->destroy();
toDelete.clear();
-
links->destroy (host, port);
}
@@ -186,21 +225,27 @@ void Link::add(Bridge::shared_ptr bridge)
void Link::cancel(Bridge::shared_ptr bridge)
{
- Mutex::ScopedLock mutex(lock);
-
- for (Bridges::iterator i = created.begin(); i != created.end(); i++) {
- if ((*i).get() == bridge.get()) {
- created.erase(i);
- break;
+ {
+ Mutex::ScopedLock mutex(lock);
+
+ for (Bridges::iterator i = created.begin(); i != created.end(); i++) {
+ if ((*i).get() == bridge.get()) {
+ created.erase(i);
+ break;
+ }
}
- }
- for (Bridges::iterator i = active.begin(); i != active.end(); i++) {
- if ((*i).get() == bridge.get()) {
- bridge->cancel();
- active.erase(i);
- break;
+ for (Bridges::iterator i = active.begin(); i != active.end(); i++) {
+ if ((*i).get() == bridge.get()) {
+ cancellations.push_back(bridge);
+ bridge->closed();
+ active.erase(i);
+ break;
+ }
}
}
+ if (!cancellations.empty()) {
+ connection->requestIOProcessing (boost::bind(&Link::ioThreadProcessing, this));
+ }
}
void Link::ioThreadProcessing()
@@ -209,8 +254,9 @@ void Link::ioThreadProcessing()
if (state != STATE_OPERATIONAL)
return;
+ QPID_LOG(debug, "Link::ioThreadProcessing()");
- //process any pending creates
+ //process any pending creates and/or cancellations
if (!created.empty()) {
for (Bridges::iterator i = created.begin(); i != created.end(); ++i) {
active.push_back(*i);
@@ -218,34 +264,77 @@ void Link::ioThreadProcessing()
}
created.clear();
}
+ if (!cancellations.empty()) {
+ for (Bridges::iterator i = cancellations.begin(); i != cancellations.end(); ++i) {
+ (*i)->cancel(*connection);
+ }
+ cancellations.clear();
+ }
}
void Link::setConnection(Connection* c)
{
Mutex::ScopedLock mutex(lock);
connection = c;
+ updateUrls = true;
}
void Link::maintenanceVisit ()
{
Mutex::ScopedLock mutex(lock);
+ if (connection && updateUrls) {
+ urls.reset(connection->getKnownHosts());
+ QPID_LOG(debug, "Known hosts for peer of inter-broker link: " << urls);
+ updateUrls = false;
+ }
+
if (state == STATE_WAITING)
{
visitCount++;
if (visitCount >= currentInterval)
{
visitCount = 0;
- currentInterval *= 2;
- if (currentInterval > MAX_INTERVAL)
- currentInterval = MAX_INTERVAL;
- startConnectionLH();
+ //switch host and port to next in url list if possible
+ if (!tryFailover()) {
+ currentInterval *= 2;
+ if (currentInterval > MAX_INTERVAL)
+ currentInterval = MAX_INTERVAL;
+ startConnectionLH();
+ }
}
}
- else if (state == STATE_OPERATIONAL && !created.empty() && connection != 0)
+ else if (state == STATE_OPERATIONAL && (!created.empty() || !cancellations.empty()) && connection != 0)
connection->requestIOProcessing (boost::bind(&Link::ioThreadProcessing, this));
}
+void Link::reconnect(const qpid::TcpAddress& a)
+{
+ Mutex::ScopedLock mutex(lock);
+ host = a.host;
+ port = a.port;
+ startConnectionLH();
+ if (mgmtObject != 0) {
+ stringstream errorString;
+ errorString << "Failed over to " << a;
+ mgmtObject->set_lastError(errorString.str());
+ }
+}
+
+bool Link::tryFailover()
+{
+ //TODO: urls only work for TCP at present, update when that has changed
+ TcpAddress next;
+ if (transport == Broker::TCP_TRANSPORT && urls.next(next) &&
+ (next.host != host || next.port != port)) {
+ links->changeAddress(TcpAddress(host, port), next);
+ QPID_LOG(debug, "Link failing over to " << host << ":" << port);
+ return true;
+ } else {
+ return false;
+ }
+}
+
uint Link::nextChannel()
{
Mutex::ScopedLock mutex(lock);
@@ -265,7 +354,7 @@ void Link::notifyConnectionForced(const string text)
void Link::setPersistenceId(uint64_t id) const
{
if (mgmtObject != 0 && persistenceId == 0) {
- ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ ManagementAgent* agent = broker->getManagementAgent();
agent->addObject(mgmtObject, id);
}
persistenceId = id;
@@ -280,19 +369,20 @@ Link::shared_ptr Link::decode(LinkRegistry& links, Buffer& buffer)
{
string host;
uint16_t port;
+ string transport;
string authMechanism;
string username;
string password;
buffer.getShortString(host);
port = buffer.getShort();
- bool useSsl(buffer.getOctet());
+ buffer.getShortString(transport);
bool durable(buffer.getOctet());
buffer.getShortString(authMechanism);
buffer.getShortString(username);
buffer.getShortString(password);
- return links.declare(host, port, useSsl, durable, authMechanism, username, password).first;
+ return links.declare(host, port, transport, durable, authMechanism, username, password).first;
}
void Link::encode(Buffer& buffer) const
@@ -300,7 +390,7 @@ void Link::encode(Buffer& buffer) const
buffer.putShortString(string("link"));
buffer.putShortString(host);
buffer.putShort(port);
- buffer.putOctet(useSsl ? 1 : 0);
+ buffer.putShortString(transport);
buffer.putOctet(durable ? 1 : 0);
buffer.putShortString(authMechanism);
buffer.putShortString(username);
@@ -312,7 +402,7 @@ uint32_t Link::encodedSize() const
return host.size() + 1 // short-string (host)
+ 5 // short-string ("link")
+ 2 // port
- + 1 // useSsl
+ + transport.size() + 1 // short-string(transport)
+ 1 // durable
+ authMechanism.size() + 1
+ username.size() + 1
@@ -324,27 +414,48 @@ ManagementObject* Link::GetManagementObject (void) const
return (ManagementObject*) mgmtObject;
}
-Manageable::status_t Link::ManagementMethod (uint32_t op, management::Args& args)
+Manageable::status_t Link::ManagementMethod (uint32_t op, Args& args, string& text)
{
switch (op)
{
- case management::Link::METHOD_CLOSE :
- closing = true;
- if (state != STATE_CONNECTING)
- destroy();
+ case _qmf::Link::METHOD_CLOSE :
+ checkClosePermission();
+ if (!closing) {
+ closing = true;
+ if (state != STATE_CONNECTING && connection) {
+ //connection can only be closed on the connections own IO processing thread
+ connection->requestIOProcessing(boost::bind(&Link::destroy, this));
+ }
+ }
return Manageable::STATUS_OK;
- case management::Link::METHOD_BRIDGE :
- management::ArgsLinkBridge& iargs = (management::ArgsLinkBridge&) args;
+ case _qmf::Link::METHOD_BRIDGE :
+ _qmf::ArgsLinkBridge& iargs = (_qmf::ArgsLinkBridge&) args;
+ QPID_LOG(debug, "Link::bridge() request received");
// Durable bridges are only valid on durable links
- if (iargs.i_durable && !durable)
- return Manageable::STATUS_INVALID_PARAMETER;
+ if (iargs.i_durable && !durable) {
+ text = "Can't create a durable route on a non-durable link";
+ return Manageable::STATUS_USER;
+ }
+
+ if (iargs.i_dynamic) {
+ Exchange::shared_ptr exchange = getBroker()->getExchanges().get(iargs.i_src);
+ if (exchange.get() == 0) {
+ text = "Exchange not found";
+ return Manageable::STATUS_USER;
+ }
+ if (!exchange->supportsDynamicBinding()) {
+ text = "Exchange type does not support dynamic routing";
+ return Manageable::STATUS_USER;
+ }
+ }
std::pair<Bridge::shared_ptr, bool> result =
links->declare (host, port, iargs.i_durable, iargs.i_src,
iargs.i_dest, iargs.i_key, iargs.i_srcIsQueue,
- iargs.i_srcIsLocal, iargs.i_tag, iargs.i_excludes);
+ iargs.i_srcIsLocal, iargs.i_tag, iargs.i_excludes,
+ iargs.i_dynamic, iargs.i_sync);
if (result.second && iargs.i_durable)
store->create(*result.first);
@@ -354,3 +465,17 @@ Manageable::status_t Link::ManagementMethod (uint32_t op, management::Args& args
return Manageable::STATUS_UNKNOWN_METHOD;
}
+
+void Link::setPassive(bool passive)
+{
+ Mutex::ScopedLock mutex(lock);
+ if (passive) {
+ setStateLH(STATE_PASSIVE);
+ } else {
+ if (state == STATE_PASSIVE) {
+ setStateLH(STATE_WAITING);
+ } else {
+ QPID_LOG(warning, "Ignoring attempt to activate non-passive link");
+ }
+ }
+}
diff --git a/cpp/src/qpid/broker/Link.h b/cpp/src/qpid/broker/Link.h
index d425c49800..318eb5bd32 100644
--- a/cpp/src/qpid/broker/Link.h
+++ b/cpp/src/qpid/broker/Link.h
@@ -23,13 +23,15 @@
*/
#include <boost/shared_ptr.hpp>
-#include "MessageStore.h"
-#include "PersistableConfig.h"
-#include "Bridge.h"
+#include "qpid/broker/MessageStore.h"
+#include "qpid/broker/PersistableConfig.h"
+#include "qpid/broker/Bridge.h"
+#include "qpid/broker/RetryList.h"
#include "qpid/sys/Mutex.h"
#include "qpid/framing/FieldTable.h"
#include "qpid/management/Manageable.h"
-#include "qpid/management/Link.h"
+#include "qpid/management/ManagementAgent.h"
+#include "qmf/org/apache/qpid/broker/Link.h"
#include <boost/ptr_container/ptr_vector.hpp>
namespace qpid {
@@ -47,30 +49,35 @@ namespace qpid {
MessageStore* store;
string host;
uint16_t port;
- bool useSsl;
+ string transport;
bool durable;
string authMechanism;
string username;
string password;
mutable uint64_t persistenceId;
- management::Link* mgmtObject;
+ qmf::org::apache::qpid::broker::Link* mgmtObject;
Broker* broker;
int state;
uint32_t visitCount;
uint32_t currentInterval;
bool closing;
+ RetryList urls;
+ bool updateUrls;
typedef std::vector<Bridge::shared_ptr> Bridges;
Bridges created; // Bridges pending creation
Bridges active; // Bridges active
+ Bridges cancellations; // Bridges pending cancellation
uint channelCounter;
Connection* connection;
+ management::ManagementAgent* agent;
static const int STATE_WAITING = 1;
static const int STATE_CONNECTING = 2;
static const int STATE_OPERATIONAL = 3;
static const int STATE_FAILED = 4;
static const int STATE_CLOSED = 5;
+ static const int STATE_PASSIVE = 6;
static const uint32_t MAX_INTERVAL = 32;
@@ -78,6 +85,8 @@ namespace qpid {
void startConnectionLH(); // Start the IO Connection
void destroy(); // Called when mgmt deletes this link
void ioThreadProcessing(); // Called on connection's IO thread by request
+ bool tryFailover(); // Called during maintenance visit
+ void checkClosePermission(); // ACL check for explict mgmt call to close this link
public:
typedef boost::shared_ptr<Link> shared_ptr;
@@ -86,7 +95,7 @@ namespace qpid {
MessageStore* store,
string& host,
uint16_t port,
- bool useSsl,
+ string& transport,
bool durable,
string& authMechanism,
string& username,
@@ -106,12 +115,15 @@ namespace qpid {
void established(); // Called when connection is created
void closed(int, std::string); // Called when connection goes away
void setConnection(Connection*); // Set pointer to the AMQP Connection
+ void reconnect(const TcpAddress&); //called by LinkRegistry
string getAuthMechanism() { return authMechanism; }
string getUsername() { return username; }
string getPassword() { return password; }
+ Broker* getBroker() { return broker; }
void notifyConnectionForced(const std::string text);
+ void setPassive(bool p);
// PersistableConfig:
void setPersistenceId(uint64_t id) const;
@@ -123,8 +135,8 @@ namespace qpid {
static Link::shared_ptr decode(LinkRegistry& links, framing::Buffer& buffer);
// Manageable entry points
- management::ManagementObject* GetManagementObject (void) const;
- management::Manageable::status_t ManagementMethod (uint32_t, management::Args&);
+ management::ManagementObject* GetManagementObject(void) const;
+ management::Manageable::status_t ManagementMethod(uint32_t, management::Args&, std::string&);
};
}
}
diff --git a/cpp/src/qpid/broker/LinkRegistry.cpp b/cpp/src/qpid/broker/LinkRegistry.cpp
index 0703c276cf..f32587dd68 100644
--- a/cpp/src/qpid/broker/LinkRegistry.cpp
+++ b/cpp/src/qpid/broker/LinkRegistry.cpp
@@ -18,20 +18,49 @@
* under the License.
*
*/
-#include "LinkRegistry.h"
+#include "qpid/broker/LinkRegistry.h"
+#include "qpid/broker/Link.h"
+#include "qpid/broker/Connection.h"
+#include "qpid/log/Statement.h"
#include <iostream>
+#include <boost/format.hpp>
using namespace qpid::broker;
using namespace qpid::sys;
using std::pair;
using std::stringstream;
using boost::intrusive_ptr;
+using boost::format;
+using boost::str;
+namespace _qmf = qmf::org::apache::qpid::broker;
#define LINK_MAINT_INTERVAL 2
-LinkRegistry::LinkRegistry (Broker* _broker) : broker(_broker), parent(0), store(0)
+// TODO: This constructor is only used by the store unit tests -
+// That probably indicates that LinkRegistry isn't correctly
+// factored: The persistence element and maintenance element
+// should be factored separately
+LinkRegistry::LinkRegistry () :
+ broker(0), timer(0),
+ parent(0), store(0), passive(false), passiveChanged(false),
+ realm("")
{
- timer.add (intrusive_ptr<TimerTask> (new Periodic(*this)));
+}
+
+LinkRegistry::LinkRegistry (Broker* _broker) :
+ broker(_broker), timer(&broker->getTimer()),
+ maintenanceTask(new Periodic(*this)),
+ parent(0), store(0), passive(false), passiveChanged(false),
+ realm(broker->getOptions().realm)
+{
+ timer->add(maintenanceTask);
+}
+
+LinkRegistry::~LinkRegistry()
+{
+ // This test is only necessary if the default constructor above is present
+ if (maintenanceTask)
+ maintenanceTask->cancel();
}
LinkRegistry::Periodic::Periodic (LinkRegistry& _links) :
@@ -40,7 +69,8 @@ LinkRegistry::Periodic::Periodic (LinkRegistry& _links) :
void LinkRegistry::Periodic::fire ()
{
links.periodicMaintenance ();
- links.timer.add (intrusive_ptr<TimerTask> (new Periodic(links)));
+ setupNextFire();
+ links.timer->add(this);
}
void LinkRegistry::periodicMaintenance ()
@@ -49,13 +79,53 @@ void LinkRegistry::periodicMaintenance ()
linksToDestroy.clear();
bridgesToDestroy.clear();
+ if (passiveChanged) {
+ if (passive) { QPID_LOG(info, "Passivating links"); }
+ else { QPID_LOG(info, "Activating links"); }
+ for (LinkMap::iterator i = links.begin(); i != links.end(); i++) {
+ i->second->setPassive(passive);
+ }
+ passiveChanged = false;
+ }
for (LinkMap::iterator i = links.begin(); i != links.end(); i++)
i->second->maintenanceVisit();
+ //now process any requests for re-addressing
+ for (AddressMap::iterator i = reMappings.begin(); i != reMappings.end(); i++)
+ updateAddress(i->first, i->second);
+ reMappings.clear();
+}
+
+void LinkRegistry::changeAddress(const qpid::TcpAddress& oldAddress, const qpid::TcpAddress& newAddress)
+{
+ //done on periodic maintenance thread; hold changes in separate
+ //map to avoid modifying the link map that is iterated over
+ reMappings[createKey(oldAddress)] = newAddress;
+}
+
+bool LinkRegistry::updateAddress(const std::string& oldKey, const qpid::TcpAddress& newAddress)
+{
+ std::string newKey = createKey(newAddress);
+ if (links.find(newKey) != links.end()) {
+ QPID_LOG(error, "Attempted to update key from " << oldKey << " to " << newKey << " which is already in use");
+ return false;
+ } else {
+ LinkMap::iterator i = links.find(oldKey);
+ if (i == links.end()) {
+ QPID_LOG(error, "Attempted to update key from " << oldKey << " which does not exist, to " << newKey);
+ return false;
+ } else {
+ links[newKey] = i->second;
+ i->second->reconnect(newAddress);
+ links.erase(oldKey);
+ QPID_LOG(info, "Updated link key from " << oldKey << " to " << newKey);
+ return true;
+ }
+ }
}
pair<Link::shared_ptr, bool> LinkRegistry::declare(string& host,
uint16_t port,
- bool useSsl,
+ string& transport,
bool durable,
string& authMechanism,
string& username,
@@ -72,9 +142,10 @@ pair<Link::shared_ptr, bool> LinkRegistry::declare(string& host,
{
Link::shared_ptr link;
- link = Link::shared_ptr (new Link (this, store, host, port, useSsl, durable,
+ link = Link::shared_ptr (new Link (this, store, host, port, transport, durable,
authMechanism, username, password,
broker, parent));
+ if (passive) link->setPassive(true);
links[key] = link;
return std::pair<Link::shared_ptr, bool>(link, true);
}
@@ -90,9 +161,13 @@ pair<Bridge::shared_ptr, bool> LinkRegistry::declare(std::string& host,
bool isQueue,
bool isLocal,
std::string& tag,
- std::string& excludes)
+ std::string& excludes,
+ bool dynamic,
+ uint16_t sync)
{
Mutex::ScopedLock locker(lock);
+ QPID_LOG(debug, "Bridge declared " << host << ": " << port << " from " << src << " to " << dest << " (" << key << ")");
+
stringstream keystream;
keystream << host << ":" << port;
string linkKey = string(keystream.str());
@@ -107,7 +182,7 @@ pair<Bridge::shared_ptr, bool> LinkRegistry::declare(std::string& host,
BridgeMap::iterator b = bridges.find(bridgeKey);
if (b == bridges.end())
{
- management::ArgsLinkBridge args;
+ _qmf::ArgsLinkBridge args;
Bridge::shared_ptr bridge;
args.i_durable = durable;
@@ -118,6 +193,8 @@ pair<Bridge::shared_ptr, bool> LinkRegistry::declare(std::string& host,
args.i_srcIsLocal = isLocal;
args.i_tag = tag;
args.i_excludes = excludes;
+ args.i_dynamic = dynamic;
+ args.i_sync = sync;
bridge = Bridge::shared_ptr
(new Bridge (l->second.get(), l->second->nextChannel(),
@@ -177,7 +254,6 @@ void LinkRegistry::destroy(const std::string& host,
void LinkRegistry::setStore (MessageStore* _store)
{
- assert (store == 0 && _store != 0);
store = _store;
}
@@ -185,66 +261,84 @@ MessageStore* LinkRegistry::getStore() const {
return store;
}
-void LinkRegistry::notifyConnection(const std::string& key, Connection* c)
+Link::shared_ptr LinkRegistry::findLink(const std::string& key)
{
Mutex::ScopedLock locker(lock);
LinkMap::iterator l = links.find(key);
- if (l != links.end())
- {
- l->second->established();
- l->second->setConnection(c);
+ if (l != links.end()) return l->second;
+ else return Link::shared_ptr();
+}
+
+void LinkRegistry::notifyConnection(const std::string& key, Connection* c)
+{
+ Link::shared_ptr link = findLink(key);
+ if (link) {
+ link->established();
+ link->setConnection(c);
+ c->setUserId(str(format("%1%@%2%") % link->getUsername() % realm));
}
}
void LinkRegistry::notifyClosed(const std::string& key)
{
- Mutex::ScopedLock locker(lock);
- LinkMap::iterator l = links.find(key);
- if (l != links.end())
- l->second->closed(0, "Closed by peer");
+ Link::shared_ptr link = findLink(key);
+ if (link) {
+ link->closed(0, "Closed by peer");
+ }
}
void LinkRegistry::notifyConnectionForced(const std::string& key, const std::string& text)
{
- Mutex::ScopedLock locker(lock);
- LinkMap::iterator l = links.find(key);
- if (l != links.end())
- l->second->notifyConnectionForced(text);
+ Link::shared_ptr link = findLink(key);
+ if (link) {
+ link->notifyConnectionForced(text);
+ }
}
std::string LinkRegistry::getAuthMechanism(const std::string& key)
{
- Mutex::ScopedLock locker(lock);
- LinkMap::iterator l = links.find(key);
- if (l != links.end())
- return l->second->getAuthMechanism();
+ Link::shared_ptr link = findLink(key);
+ if (link)
+ return link->getAuthMechanism();
return string("ANONYMOUS");
}
std::string LinkRegistry::getAuthCredentials(const std::string& key)
{
- Mutex::ScopedLock locker(lock);
- LinkMap::iterator l = links.find(key);
- if (l == links.end())
+ Link::shared_ptr link = findLink(key);
+ if (!link)
return string();
string result;
result += '\0';
- result += l->second->getUsername();
+ result += link->getUsername();
result += '\0';
- result += l->second->getPassword();
+ result += link->getPassword();
return result;
}
std::string LinkRegistry::getAuthIdentity(const std::string& key)
{
- Mutex::ScopedLock locker(lock);
- LinkMap::iterator l = links.find(key);
- if (l == links.end())
+ Link::shared_ptr link = findLink(key);
+ if (!link)
return string();
- return l->second->getUsername();
+ return link->getUsername();
}
+std::string LinkRegistry::createKey(const qpid::TcpAddress& a)
+{
+ stringstream keystream;
+ keystream << a.host << ":" << a.port;
+ return string(keystream.str());
+}
+
+void LinkRegistry::setPassive(bool p)
+{
+ Mutex::ScopedLock locker(lock);
+ passiveChanged = p != passive;
+ passive = p;
+ //will activate or passivate links on maintenance visit
+}
diff --git a/cpp/src/qpid/broker/LinkRegistry.h b/cpp/src/qpid/broker/LinkRegistry.h
index 242c0d58ba..09a89298b6 100644
--- a/cpp/src/qpid/broker/LinkRegistry.h
+++ b/cpp/src/qpid/broker/LinkRegistry.h
@@ -23,23 +23,26 @@
*/
#include <map>
-#include "Link.h"
-#include "Bridge.h"
-#include "MessageStore.h"
-#include "Timer.h"
+#include "qpid/broker/Bridge.h"
+#include "qpid/broker/MessageStore.h"
+#include "qpid/Address.h"
#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Timer.h"
#include "qpid/management/Manageable.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/intrusive_ptr.hpp>
namespace qpid {
namespace broker {
+ class Link;
class Broker;
class Connection;
class LinkRegistry {
// Declare a timer task to manage the establishment of link connections and the
// re-establishment of lost link connections.
- struct Periodic : public TimerTask
+ struct Periodic : public sys::TimerTask
{
LinkRegistry& links;
@@ -48,28 +51,40 @@ namespace broker {
void fire();
};
- typedef std::map<std::string, Link::shared_ptr> LinkMap;
+ typedef std::map<std::string, boost::shared_ptr<Link> > LinkMap;
typedef std::map<std::string, Bridge::shared_ptr> BridgeMap;
+ typedef std::map<std::string, TcpAddress> AddressMap;
LinkMap links;
LinkMap linksToDestroy;
BridgeMap bridges;
BridgeMap bridgesToDestroy;
+ AddressMap reMappings;
qpid::sys::Mutex lock;
Broker* broker;
- Timer timer;
+ sys::Timer* timer;
+ boost::intrusive_ptr<qpid::sys::TimerTask> maintenanceTask;
management::Manageable* parent;
MessageStore* store;
+ bool passive;
+ bool passiveChanged;
+ std::string realm;
void periodicMaintenance ();
+ bool updateAddress(const std::string& oldKey, const TcpAddress& newAddress);
+ boost::shared_ptr<Link> findLink(const std::string& key);
+ static std::string createKey(const TcpAddress& address);
public:
+ LinkRegistry (); // Only used in store tests
LinkRegistry (Broker* _broker);
- std::pair<Link::shared_ptr, bool>
+ ~LinkRegistry();
+
+ std::pair<boost::shared_ptr<Link>, bool>
declare(std::string& host,
uint16_t port,
- bool useSsl,
+ std::string& transport,
bool durable,
std::string& authMechanism,
std::string& username,
@@ -84,7 +99,9 @@ namespace broker {
bool isQueue,
bool isLocal,
std::string& id,
- std::string& excludes);
+ std::string& excludes,
+ bool dynamic,
+ uint16_t sync);
void destroy(const std::string& host, const uint16_t port);
void destroy(const std::string& host,
@@ -114,6 +131,18 @@ namespace broker {
std::string getAuthMechanism (const std::string& key);
std::string getAuthCredentials (const std::string& key);
std::string getAuthIdentity (const std::string& key);
+
+ /**
+ * Called by links failing over to new address
+ */
+ void changeAddress(const TcpAddress& oldAddress, const TcpAddress& newAddress);
+ /**
+ * Called to alter passive state. In passive state the links
+ * and bridges managed by a link registry will be recorded and
+ * updated but links won't actually establish connections and
+ * bridges won't therefore pull or push any messages.
+ */
+ void setPassive(bool);
};
}
}
diff --git a/cpp/src/qpid/broker/Message.cpp b/cpp/src/qpid/broker/Message.cpp
index 331bb5e716..47ca7a7ae8 100644
--- a/cpp/src/qpid/broker/Message.cpp
+++ b/cpp/src/qpid/broker/Message.cpp
@@ -19,8 +19,9 @@
*
*/
-#include "Message.h"
-#include "ExchangeRegistry.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/ExchangeRegistry.h"
+#include "qpid/broker/ExpiryPolicy.h"
#include "qpid/StringUtils.h"
#include "qpid/framing/frame_functors.h"
#include "qpid/framing/FieldTable.h"
@@ -30,17 +31,43 @@
#include "qpid/framing/TypeFilter.h"
#include "qpid/log/Statement.h"
+#include <time.h>
+
using boost::intrusive_ptr;
-using namespace qpid::broker;
-using namespace qpid::framing;
+using qpid::sys::AbsTime;
+using qpid::sys::Duration;
+using qpid::sys::TIME_MSEC;
+using qpid::sys::FAR_FUTURE;
using std::string;
+using namespace qpid::framing;
+
+namespace qpid {
+namespace broker {
TransferAdapter Message::TRANSFER;
-Message::Message(const SequenceNumber& id) : frames(id), persistenceId(0), redelivered(false), loaded(false), staged(false), publisher(0), adapter(0) {}
+Message::Message(const framing::SequenceNumber& id) :
+ frames(id), persistenceId(0), redelivered(false), loaded(false),
+ staged(false), forcePersistentPolicy(false), publisher(0), adapter(0),
+ expiration(FAR_FUTURE), enqueueCallback(0), dequeueCallback(0), requiredCredit(0) {}
Message::~Message()
{
+ if (expiryPolicy)
+ expiryPolicy->forget(*this);
+}
+
+void Message::forcePersistent()
+{
+ // only set forced bit if we actually need to force.
+ if (! getAdapter().isPersistent(frames) ){
+ forcePersistentPolicy = true;
+ }
+}
+
+bool Message::isForcedPersistent()
+{
+ return forcePersistentPolicy;
}
std::string Message::getRoutingKey() const
@@ -71,9 +98,9 @@ const FieldTable* Message::getApplicationHeaders() const
return getAdapter().getApplicationHeaders(frames);
}
-bool Message::isPersistent()
+bool Message::isPersistent() const
{
- return getAdapter().isPersistent(frames);
+ return (getAdapter().isPersistent(frames) || forcePersistentPolicy);
}
bool Message::requiresAccept()
@@ -81,12 +108,16 @@ bool Message::requiresAccept()
return getAdapter().requiresAccept(frames);
}
-uint32_t Message::getRequiredCredit() const
+uint32_t Message::getRequiredCredit()
{
- //add up payload for all header and content frames in the frameset
- SumBodySize sum;
- frames.map_if(sum, TypeFilter2<HEADER_BODY, CONTENT_BODY>());
- return sum.getSize();
+ sys::Mutex::ScopedLock l(lock);
+ if (!requiredCredit) {
+ //add up payload for all header and content frames in the frameset
+ SumBodySize sum;
+ frames.map_if(sum, TypeFilter2<HEADER_BODY, CONTENT_BODY>());
+ requiredCredit = sum.getSize();
+ }
+ return requiredCredit;
}
void Message::encode(framing::Buffer& buffer) const
@@ -96,7 +127,7 @@ void Message::encode(framing::Buffer& buffer) const
frames.map_if(f1, TypeFilter2<METHOD_BODY, HEADER_BODY>());
//then encode the payload of each content frame
- EncodeBody f2(buffer);
+ framing::EncodeBody f2(buffer);
frames.map_if(f2, TypeFilter<CONTENT_BODY>());
}
@@ -141,9 +172,9 @@ void Message::decodeContent(framing::Buffer& buffer)
if (buffer.available()) {
//get the data as a string and set that as the content
//body on a frame then add that frame to the frameset
- AMQFrame frame;
- frame.setBody(AMQContentBody());
+ AMQFrame frame((AMQContentBody()));
frame.castBody<AMQContentBody>()->decode(buffer, buffer.available());
+ frame.setFirstSegment(false);
frames.append(frame);
} else {
//adjust header flags
@@ -154,17 +185,31 @@ void Message::decodeContent(framing::Buffer& buffer)
loaded = true;
}
-void Message::releaseContent(MessageStore* _store)
+void Message::tryReleaseContent()
{
- if (!store) {
- store = _store;
+ if (checkContentReleasable()) {
+ releaseContent();
}
+}
+
+void Message::releaseContent(MessageStore* s)
+{
+ //deprecated, use setStore(store); releaseContent(); instead
+ if (!store) setStore(s);
+ releaseContent();
+}
+
+void Message::releaseContent()
+{
+ sys::Mutex::ScopedLock l(lock);
if (store) {
if (!getPersistenceId()) {
intrusive_ptr<PersistableMessage> pmsg(this);
store->stage(pmsg);
staged = true;
}
+ //ensure required credit is cached before content frames are released
+ getRequiredCredit();
//remove any content frames from the frameset
frames.remove(TypeFilter<CONTENT_BODY>());
setContentReleased();
@@ -182,30 +227,37 @@ void Message::destroy()
}
}
-void Message::sendContent(Queue& queue, framing::FrameHandler& out, uint16_t maxFrameSize) const
+bool Message::getContentFrame(const Queue& queue, AMQFrame& frame, uint16_t maxContentSize, uint64_t offset) const
+{
+ intrusive_ptr<const PersistableMessage> pmsg(this);
+
+ bool done = false;
+ string& data = frame.castBody<AMQContentBody>()->getData();
+ store->loadContent(queue, pmsg, data, offset, maxContentSize);
+ done = data.size() < maxContentSize;
+ frame.setBof(false);
+ frame.setEof(true);
+ QPID_LOG(debug, "loaded frame" << frame);
+ if (offset > 0) {
+ frame.setBos(false);
+ }
+ if (!done) {
+ frame.setEos(false);
+ } else return false;
+ return true;
+}
+
+void Message::sendContent(const Queue& queue, framing::FrameHandler& out, uint16_t maxFrameSize) const
{
- if (isContentReleased()) {
- //load content from store in chunks of maxContentSize
+ sys::Mutex::ScopedLock l(lock);
+ if (isContentReleased() && !frames.isComplete()) {
+ sys::Mutex::ScopedUnlock u(lock);
uint16_t maxContentSize = maxFrameSize - AMQFrame::frameOverhead();
- intrusive_ptr<const PersistableMessage> pmsg(this);
-
- bool done = false;
- for (uint64_t offset = 0; !done; offset += maxContentSize)
+ bool morecontent = true;
+ for (uint64_t offset = 0; morecontent; offset += maxContentSize)
{
- AMQFrame frame(in_place<AMQContentBody>());
- string& data = frame.castBody<AMQContentBody>()->getData();
-
- store->loadContent(queue, pmsg, data, offset, maxContentSize);
- done = data.size() < maxContentSize;
- frame.setBof(false);
- frame.setEof(true);
- if (offset > 0) {
- frame.setBos(false);
- }
- if (!done) {
- frame.setEos(false);
- }
- QPID_LOG(debug, "loaded frame for delivery: " << frame);
+ AMQFrame frame((AMQContentBody()));
+ morecontent = getContentFrame(queue, frame, maxContentSize, offset);
out.handle(frame);
}
} else {
@@ -253,14 +305,14 @@ bool Message::isContentLoaded() const
namespace
{
- const std::string X_QPID_TRACE("x-qpid.trace");
+const std::string X_QPID_TRACE("x-qpid.trace");
}
bool Message::isExcluded(const std::vector<std::string>& excludes) const
{
const FieldTable* headers = getApplicationHeaders();
if (headers) {
- std::string traceStr = headers->getString(X_QPID_TRACE);
+ std::string traceStr = headers->getAsString(X_QPID_TRACE);
if (traceStr.size()) {
std::vector<std::string> trace = split(traceStr, ", ");
@@ -281,7 +333,7 @@ void Message::addTraceId(const std::string& id)
sys::Mutex::ScopedLock l(lock);
if (isA<MessageTransferBody>()) {
FieldTable& headers = getProperties<MessageProperties>()->getApplicationHeaders();
- std::string trace = headers.getString(X_QPID_TRACE);
+ std::string trace = headers.getAsString(X_QPID_TRACE);
if (trace.empty()) {
headers.setString(X_QPID_TRACE, id);
} else if (trace.find(id) == std::string::npos) {
@@ -291,3 +343,86 @@ void Message::addTraceId(const std::string& id)
}
}
}
+
+void Message::setTimestamp(const boost::intrusive_ptr<ExpiryPolicy>& e)
+{
+ DeliveryProperties* props = getProperties<DeliveryProperties>();
+ if (props->getTtl()) {
+ // AMQP requires setting the expiration property to be posix
+ // time_t in seconds. TTL is in milliseconds
+ if (!props->getExpiration()) {
+ //only set expiration in delivery properties if not already set
+ time_t now = ::time(0);
+ props->setExpiration(now + (props->getTtl()/1000));
+ }
+ // Use higher resolution time for the internal expiry calculation.
+ expiration = AbsTime(AbsTime::now(), Duration(props->getTtl() * TIME_MSEC));
+ setExpiryPolicy(e);
+ }
+}
+
+void Message::setExpiryPolicy(const boost::intrusive_ptr<ExpiryPolicy>& e) {
+ expiryPolicy = e;
+ if (expiryPolicy)
+ expiryPolicy->willExpire(*this);
+}
+
+bool Message::hasExpired()
+{
+ return expiryPolicy && expiryPolicy->hasExpired(*this);
+}
+
+boost::intrusive_ptr<Message>& Message::getReplacementMessage(const Queue* qfor) const
+{
+ sys::Mutex::ScopedLock l(lock);
+ Replacement::iterator i = replacement.find(qfor);
+ if (i != replacement.end()){
+ return i->second;
+ }
+ return empty;
+}
+
+void Message::setReplacementMessage(boost::intrusive_ptr<Message> msg, const Queue* qfor)
+{
+ sys::Mutex::ScopedLock l(lock);
+ replacement[qfor] = msg;
+}
+
+void Message::allEnqueuesComplete() {
+ sys::Mutex::ScopedLock l(callbackLock);
+ MessageCallback* cb = enqueueCallback;
+ if (cb && *cb) (*cb)(intrusive_ptr<Message>(this));
+}
+
+void Message::allDequeuesComplete() {
+ sys::Mutex::ScopedLock l(callbackLock);
+ MessageCallback* cb = dequeueCallback;
+ if (cb && *cb) (*cb)(intrusive_ptr<Message>(this));
+}
+
+void Message::setEnqueueCompleteCallback(MessageCallback& cb) {
+ sys::Mutex::ScopedLock l(callbackLock);
+ enqueueCallback = &cb;
+}
+
+void Message::resetEnqueueCompleteCallback() {
+ sys::Mutex::ScopedLock l(callbackLock);
+ enqueueCallback = 0;
+}
+
+void Message::setDequeueCompleteCallback(MessageCallback& cb) {
+ sys::Mutex::ScopedLock l(callbackLock);
+ dequeueCallback = &cb;
+}
+
+void Message::resetDequeueCompleteCallback() {
+ sys::Mutex::ScopedLock l(callbackLock);
+ dequeueCallback = 0;
+}
+
+framing::FieldTable& Message::getOrInsertHeaders()
+{
+ return getProperties<MessageProperties>()->getApplicationHeaders();
+}
+
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/Message.h b/cpp/src/qpid/broker/Message.h
index 0a95fedea6..375fa9ce26 100644
--- a/cpp/src/qpid/broker/Message.h
+++ b/cpp/src/qpid/broker/Message.h
@@ -22,33 +22,38 @@
*
*/
-#include <string>
-#include <vector>
-#include <boost/shared_ptr.hpp>
-#include <boost/variant.hpp>
-#include "PersistableMessage.h"
-#include "MessageAdapter.h"
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/PersistableMessage.h"
+#include "qpid/broker/MessageAdapter.h"
#include "qpid/framing/amqp_types.h"
#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Time.h"
+#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
+#include <string>
+#include <vector>
namespace qpid {
-
+
namespace framing {
class FieldTable;
class SequenceNumber;
}
-
+
namespace broker {
class ConnectionToken;
class Exchange;
class ExchangeRegistry;
class MessageStore;
class Queue;
+class ExpiryPolicy;
class Message : public PersistableMessage {
public:
- Message(const framing::SequenceNumber& id = framing::SequenceNumber());
- ~Message();
+ typedef boost::function<void (const boost::intrusive_ptr<Message>&)> MessageCallback;
+
+ QPID_BROKER_EXTERN Message(const framing::SequenceNumber& id = framing::SequenceNumber());
+ QPID_BROKER_EXTERN ~Message();
uint64_t getPersistenceId() const { return persistenceId; }
void setPersistenceId(uint64_t _persistenceId) const { persistenceId = _persistenceId; }
@@ -61,16 +66,22 @@ public:
const framing::SequenceNumber& getCommandId() { return frames.getId(); }
- uint64_t contentSize() const;
+ QPID_BROKER_EXTERN uint64_t contentSize() const;
- std::string getRoutingKey() const;
+ QPID_BROKER_EXTERN std::string getRoutingKey() const;
const boost::shared_ptr<Exchange> getExchange(ExchangeRegistry&) const;
- std::string getExchangeName() const;
+ QPID_BROKER_EXTERN std::string getExchangeName() const;
bool isImmediate() const;
- const framing::FieldTable* getApplicationHeaders() const;
- bool isPersistent();
+ QPID_BROKER_EXTERN const framing::FieldTable* getApplicationHeaders() const;
+ framing::FieldTable& getOrInsertHeaders();
+ QPID_BROKER_EXTERN bool isPersistent() const;
bool requiresAccept();
+ QPID_BROKER_EXTERN void setTimestamp(const boost::intrusive_ptr<ExpiryPolicy>& e);
+ void setExpiryPolicy(const boost::intrusive_ptr<ExpiryPolicy>& e);
+ bool hasExpired();
+ sys::AbsTime getExpiration() const { return expiration; }
+
framing::FrameSet& getFrames() { return frames; }
const framing::FrameSet& getFrames() const { return frames; }
@@ -84,15 +95,24 @@ public:
return p->get<T>(true);
}
+ template <class T> const T* hasProperties() const {
+ const qpid::framing::AMQHeaderBody* p = frames.getHeaders();
+ return p->get<T>();
+ }
+
template <class T> const T* getMethod() const {
return frames.as<T>();
}
+ template <class T> T* getMethod() {
+ return frames.as<T>();
+ }
+
template <class T> bool isA() const {
return frames.isA<T>();
}
- uint32_t getRequiredCredit() const;
+ uint32_t getRequiredCredit();
void encode(framing::Buffer& buffer) const;
void encodeContent(framing::Buffer& buffer) const;
@@ -110,26 +130,44 @@ public:
uint32_t encodedHeaderSize() const;
uint32_t encodedContentSize() const;
- void decodeHeader(framing::Buffer& buffer);
- void decodeContent(framing::Buffer& buffer);
+ QPID_BROKER_EXTERN void decodeHeader(framing::Buffer& buffer);
+ QPID_BROKER_EXTERN void decodeContent(framing::Buffer& buffer);
- /**
- * Releases the in-memory content data held by this
- * message. Must pass in a store from which the data can
- * be reloaded.
- */
- void releaseContent(MessageStore* store);
+ void QPID_BROKER_EXTERN tryReleaseContent();
+ void releaseContent();
+ void releaseContent(MessageStore* s);//deprecated, use 'setStore(store); releaseContent();' instead
void destroy();
- void sendContent(Queue& queue, framing::FrameHandler& out, uint16_t maxFrameSize) const;
+ bool getContentFrame(const Queue& queue, framing::AMQFrame& frame, uint16_t maxContentSize, uint64_t offset) const;
+ QPID_BROKER_EXTERN void sendContent(const Queue& queue, framing::FrameHandler& out, uint16_t maxFrameSize) const;
void sendHeader(framing::FrameHandler& out, uint16_t maxFrameSize) const;
- bool isContentLoaded() const;
+ QPID_BROKER_EXTERN bool isContentLoaded() const;
bool isExcluded(const std::vector<std::string>& excludes) const;
void addTraceId(const std::string& id);
+
+ void forcePersistent();
+ bool isForcedPersistent();
+
+ boost::intrusive_ptr<Message>& getReplacementMessage(const Queue* qfor) const;
+ void setReplacementMessage(boost::intrusive_ptr<Message> msg, const Queue* qfor);
+
+ /** Call cb when enqueue is complete, may call immediately. Holds cb by reference. */
+ void setEnqueueCompleteCallback(MessageCallback& cb);
+ void resetEnqueueCompleteCallback();
+
+ /** Call cb when dequeue is complete, may call immediately. Holds cb by reference. */
+ void setDequeueCompleteCallback(MessageCallback& cb);
+ void resetDequeueCompleteCallback();
private:
+ typedef std::map<const Queue*,boost::intrusive_ptr<Message> > Replacement;
+
+ MessageAdapter& getAdapter() const;
+ void allEnqueuesComplete();
+ void allDequeuesComplete();
+
mutable sys::Mutex lock;
framing::FrameSet frames;
mutable boost::shared_ptr<Exchange> exchange;
@@ -137,12 +175,22 @@ public:
bool redelivered;
bool loaded;
bool staged;
+ bool forcePersistentPolicy; // used to force message as durable, via a broker policy
ConnectionToken* publisher;
mutable MessageAdapter* adapter;
+ qpid::sys::AbsTime expiration;
+ boost::intrusive_ptr<ExpiryPolicy> expiryPolicy;
static TransferAdapter TRANSFER;
- MessageAdapter& getAdapter() const;
+ mutable Replacement replacement;
+ mutable boost::intrusive_ptr<Message> empty;
+
+ sys::Mutex callbackLock;
+ MessageCallback* enqueueCallback;
+ MessageCallback* dequeueCallback;
+
+ uint32_t requiredCredit;
};
}}
diff --git a/cpp/src/qpid/broker/MessageAdapter.cpp b/cpp/src/qpid/broker/MessageAdapter.cpp
index 12f01494de..c0c1c4445a 100644
--- a/cpp/src/qpid/broker/MessageAdapter.cpp
+++ b/cpp/src/qpid/broker/MessageAdapter.cpp
@@ -19,7 +19,7 @@
*
*/
-#include "MessageAdapter.h"
+#include "qpid/broker/MessageAdapter.h"
#include "qpid/framing/DeliveryProperties.h"
#include "qpid/framing/MessageProperties.h"
diff --git a/cpp/src/qpid/broker/MessageBuilder.cpp b/cpp/src/qpid/broker/MessageBuilder.cpp
index eda71ed3da..b1a2b77b05 100644
--- a/cpp/src/qpid/broker/MessageBuilder.cpp
+++ b/cpp/src/qpid/broker/MessageBuilder.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -18,10 +18,11 @@
* under the License.
*
*/
-#include "MessageBuilder.h"
+#include "qpid/broker/MessageBuilder.h"
-#include "Message.h"
-#include "MessageStore.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/MessageStore.h"
+#include "qpid/broker/NullMessageStore.h"
#include "qpid/framing/AMQFrame.h"
#include "qpid/framing/reply_exceptions.h"
@@ -29,11 +30,13 @@ using boost::intrusive_ptr;
using namespace qpid::broker;
using namespace qpid::framing;
-namespace
+namespace
{
std::string type_str(uint8_t type);
+ const std::string QPID_MANAGEMENT("qpid.management");
}
-MessageBuilder::MessageBuilder(MessageStore* const _store, uint64_t _stagingThreshold) :
+
+MessageBuilder::MessageBuilder(MessageStore* const _store, uint64_t _stagingThreshold) :
state(DORMANT), store(_store), stagingThreshold(_stagingThreshold), staging(false) {}
void MessageBuilder::handle(AMQFrame& frame)
@@ -48,14 +51,13 @@ void MessageBuilder::handle(AMQFrame& frame)
if (type == CONTENT_BODY) {
//TODO: rethink how to handle non-existent headers(?)...
//didn't get a header: add in a dummy
- AMQFrame header;
- header.setBody(AMQHeaderBody());
+ AMQFrame header((AMQHeaderBody()));
header.setBof(false);
header.setEof(false);
- message->getFrames().append(header);
+ message->getFrames().append(header);
} else if (type != HEADER_BODY) {
throw CommandInvalidException(
- QPID_MSG("Invalid frame sequence for message, expected header or content got "
+ QPID_MSG("Invalid frame sequence for message, expected header or content got "
<< type_str(type) << ")"));
}
state = CONTENT;
@@ -72,8 +74,13 @@ void MessageBuilder::handle(AMQFrame& frame)
} else {
message->getFrames().append(frame);
//have we reached the staging limit? if so stage message and release content
- if (state == CONTENT && stagingThreshold && message->getFrames().getContentSize() >= stagingThreshold) {
- message->releaseContent(store);
+ if (state == CONTENT
+ && stagingThreshold
+ && message->getFrames().getContentSize() >= stagingThreshold
+ && !NullMessageStore::isNullStore(store)
+ && message->getExchangeName() != QPID_MANAGEMENT /* don't stage mgnt messages */)
+ {
+ message->releaseContent();
staging = true;
}
}
@@ -89,6 +96,7 @@ void MessageBuilder::end()
void MessageBuilder::start(const SequenceNumber& id)
{
message = intrusive_ptr<Message>(new Message(id));
+ message->setStore(store);
state = METHOD;
staging = false;
}
@@ -101,7 +109,7 @@ const std::string CONTENT_BODY_S = "CONTENT";
const std::string HEARTBEAT_BODY_S = "HEARTBEAT";
const std::string UNKNOWN = "unknown";
-std::string type_str(uint8_t type)
+std::string type_str(uint8_t type)
{
switch(type) {
case METHOD_BODY: return METHOD_BODY_S;
@@ -117,7 +125,7 @@ std::string type_str(uint8_t type)
void MessageBuilder::checkType(uint8_t expected, uint8_t actual)
{
if (expected != actual) {
- throw CommandInvalidException(QPID_MSG("Invalid frame sequence for message (expected "
+ throw CommandInvalidException(QPID_MSG("Invalid frame sequence for message (expected "
<< type_str(expected) << " got " << type_str(actual) << ")"));
}
}
diff --git a/cpp/src/qpid/broker/MessageBuilder.h b/cpp/src/qpid/broker/MessageBuilder.h
index 395de024ab..e63c108097 100644
--- a/cpp/src/qpid/broker/MessageBuilder.h
+++ b/cpp/src/qpid/broker/MessageBuilder.h
@@ -21,6 +21,7 @@
#ifndef _MessageBuilder_
#define _MessageBuilder_
+#include "qpid/broker/BrokerImportExport.h"
#include "qpid/framing/FrameHandler.h"
#include "qpid/framing/SequenceNumber.h"
#include "qpid/RefCounted.h"
@@ -34,10 +35,11 @@ namespace qpid {
class MessageBuilder : public framing::FrameHandler{
public:
- MessageBuilder(MessageStore* const store, uint64_t stagingThreshold);
- void handle(framing::AMQFrame& frame);
+ QPID_BROKER_EXTERN MessageBuilder(MessageStore* const store,
+ uint64_t stagingThreshold);
+ QPID_BROKER_EXTERN void handle(framing::AMQFrame& frame);
boost::intrusive_ptr<Message> getMessage() { return message; }
- void start(const framing::SequenceNumber& id);
+ QPID_BROKER_EXTERN void start(const framing::SequenceNumber& id);
void end();
private:
enum State {DORMANT, METHOD, HEADER, CONTENT};
diff --git a/cpp/src/qpid/broker/MessageDelivery.cpp b/cpp/src/qpid/broker/MessageDelivery.cpp
deleted file mode 100644
index a757d191e7..0000000000
--- a/cpp/src/qpid/broker/MessageDelivery.cpp
+++ /dev/null
@@ -1,89 +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 "MessageDelivery.h"
-
-#include "DeliveryToken.h"
-#include "Message.h"
-#include "Queue.h"
-#include "qpid/framing/FrameHandler.h"
-#include "qpid/framing/MessageTransferBody.h"
-
-
-using namespace boost;
-using namespace qpid::broker;
-using namespace qpid::framing;
-
-namespace qpid{
-namespace broker{
-
-struct BaseToken : DeliveryToken
-{
- virtual ~BaseToken() {}
- virtual AMQFrame sendMethod(intrusive_ptr<Message> msg, DeliveryId id) = 0;
-};
-
-struct MessageDeliveryToken : BaseToken
-{
- const std::string destination;
- const uint8_t confirmMode;
- const uint8_t acquireMode;
- const bool isPreview;
-
- MessageDeliveryToken(const std::string& d, uint8_t c, uint8_t a, bool p) :
- destination(d), confirmMode(c), acquireMode(a), isPreview(p) {}
-
- AMQFrame sendMethod(intrusive_ptr<Message> msg, DeliveryId /*id*/)
- {
- //may need to set the redelivered flag:
- if (msg->getRedelivered()){
- msg->getProperties<DeliveryProperties>()->setRedelivered(true);
- }
- return AMQFrame(in_place<MessageTransferBody>(
- ProtocolVersion(), destination, confirmMode, acquireMode));
- }
-};
-
-}
-}
-
-DeliveryToken::shared_ptr MessageDelivery::getMessageDeliveryToken(const std::string& destination,
- uint8_t confirmMode, uint8_t acquireMode)
-{
- return DeliveryToken::shared_ptr(new MessageDeliveryToken(destination, confirmMode, acquireMode, false));
-}
-
-void MessageDelivery::deliver(QueuedMessage& msg,
- framing::FrameHandler& handler,
- DeliveryId id,
- DeliveryToken::shared_ptr token,
- uint16_t framesize)
-{
- //currently a message published from one class and delivered to
- //another may well have the wrong headers; however we will only
- //have one content class for 0-10 proper
-
- boost::shared_ptr<BaseToken> t = dynamic_pointer_cast<BaseToken>(token);
- AMQFrame method = t->sendMethod(msg.payload, id);
- method.setEof(false);
- handler.handle(method);
- msg.payload->sendHeader(handler, framesize);
- msg.payload->sendContent(*(msg.queue), handler, framesize);
-}
diff --git a/cpp/src/qpid/broker/MessageDelivery.h b/cpp/src/qpid/broker/MessageDelivery.h
deleted file mode 100644
index cfde9ee307..0000000000
--- a/cpp/src/qpid/broker/MessageDelivery.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef _broker_MessageDelivery_h
-#define _broker_MessageDelivery_h
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include <boost/shared_ptr.hpp>
-#include "DeliveryId.h"
-#include "Consumer.h"
-#include "qpid/framing/FrameHandler.h"
-
-namespace qpid {
-namespace broker {
-
-class DeliveryToken;
-class Message;
-class Queue;
-
-/**
- * TODO: clean this up; we don't need it anymore in its current form
- *
- * Encapsulates the different options for message delivery currently supported.
- */
-class MessageDelivery {
-public:
- static boost::shared_ptr<DeliveryToken> getMessageDeliveryToken(const std::string& destination,
- uint8_t confirmMode,
- uint8_t acquireMode);
-
- static void deliver(QueuedMessage& msg, framing::FrameHandler& out,
- DeliveryId deliveryTag, boost::shared_ptr<DeliveryToken> token, uint16_t framesize);
-};
-
-}
-}
-
-
-#endif /*!_broker_MessageDelivery_h*/
diff --git a/cpp/src/qpid/broker/MessageStore.h b/cpp/src/qpid/broker/MessageStore.h
index 4c4c21dfba..143e860ec7 100644
--- a/cpp/src/qpid/broker/MessageStore.h
+++ b/cpp/src/qpid/broker/MessageStore.h
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -21,12 +21,12 @@
#ifndef _MessageStore_
#define _MessageStore_
-#include "PersistableExchange.h"
-#include "PersistableMessage.h"
-#include "PersistableQueue.h"
-#include "PersistableConfig.h"
-#include "RecoveryManager.h"
-#include "TransactionalStore.h"
+#include "qpid/broker/PersistableExchange.h"
+#include "qpid/broker/PersistableMessage.h"
+#include "qpid/broker/PersistableQueue.h"
+#include "qpid/broker/PersistableConfig.h"
+#include "qpid/broker/RecoveryManager.h"
+#include "qpid/broker/TransactionalStore.h"
#include "qpid/framing/FieldTable.h"
#include <qpid/Options.h>
@@ -46,12 +46,16 @@ class MessageStore : public TransactionalStore, public Recoverable {
public:
/**
- * init the store, call before any other call. If not called, store
- * is free to pick any defaults
- *
- * @param options Options object provided by concrete store plug in.
+ * If called after initialization but before recovery, will discard the database
+ * and reinitialize using an empty store dir. If the parameter pushDownStoreFiles
+ * is true, the content of the store dir will be moved to a backup dir inside the
+ * store dir. This is used when cluster nodes recover and must get thier content
+ * from a cluster sync rather than directly fromt the store.
+ *
+ * @param pushDownStoreFiles If true, will move content of the store dir into a
+ * subdir, leaving the store dir otherwise empty.
*/
- virtual bool init(const Options* options) = 0;
+ virtual void truncateInit(const bool pushDownStoreFiles = false) = 0;
/**
* Record the existence of a durable queue
@@ -62,7 +66,7 @@ class MessageStore : public TransactionalStore, public Recoverable {
* Destroy a durable queue
*/
virtual void destroy(PersistableQueue& queue) = 0;
-
+
/**
* Record the existence of a durable exchange
*/
@@ -72,17 +76,17 @@ class MessageStore : public TransactionalStore, public Recoverable {
* Destroy a durable exchange
*/
virtual void destroy(const PersistableExchange& exchange) = 0;
-
+
/**
* Record a binding
*/
- virtual void bind(const PersistableExchange& exchange, const PersistableQueue& queue,
+ virtual void bind(const PersistableExchange& exchange, const PersistableQueue& queue,
const std::string& key, const framing::FieldTable& args) = 0;
/**
* Forget a binding
*/
- virtual void unbind(const PersistableExchange& exchange, const PersistableQueue& queue,
+ virtual void unbind(const PersistableExchange& exchange, const PersistableQueue& queue,
const std::string& key, const framing::FieldTable& args) = 0;
/**
@@ -102,10 +106,10 @@ class MessageStore : public TransactionalStore, public Recoverable {
* point). If the message has not yet been stored it will
* store the headers as well as any content passed in. A
* persistence id will be set on the message which can be
- * used to load the content or to append to it.
+ * used to load the content or to append to it.
*/
virtual void stage(const boost::intrusive_ptr<PersistableMessage>& msg) = 0;
-
+
/**
* Destroys a previously staged message. This only needs
* to be called if the message is never enqueued. (Once
@@ -119,7 +123,7 @@ class MessageStore : public TransactionalStore, public Recoverable {
*/
virtual void appendContent(const boost::intrusive_ptr<const PersistableMessage>& msg,
const std::string& data) = 0;
-
+
/**
* Loads (a section) of content data for the specified
* message (previously stored through a call to stage or
@@ -128,18 +132,18 @@ class MessageStore : public TransactionalStore, public Recoverable {
* content should be loaded, not the headers or related
* meta-data).
*/
- virtual void loadContent(const qpid::broker::PersistableQueue& queue,
+ virtual void loadContent(const qpid::broker::PersistableQueue& queue,
const boost::intrusive_ptr<const PersistableMessage>& msg,
std::string& data, uint64_t offset, uint32_t length) = 0;
-
+
/**
* Enqueues a message, storing the message if it has not
* been previously stored and recording that the given
- * message is on the given queue.
+ * message is on the given queue.
*
* Note: that this is async so the return of the function does
* not mean the opperation is complete.
- *
+ *
* @param msg the message to enqueue
* @param queue the name of the queue onto which it is to be enqueued
* @param xid (a pointer to) an identifier of the
@@ -149,7 +153,7 @@ class MessageStore : public TransactionalStore, public Recoverable {
virtual void enqueue(TransactionContext* ctxt,
const boost::intrusive_ptr<PersistableMessage>& msg,
const PersistableQueue& queue) = 0;
-
+
/**
* Dequeues a message, recording that the given message is
* no longer on the given queue and deleting the message
@@ -157,7 +161,7 @@ class MessageStore : public TransactionalStore, public Recoverable {
*
* Note: that this is async so the return of the function does
* not mean the opperation is complete.
- *
+ *
* @param msg the message to dequeue
* @param queue the name of the queue from which it is to be dequeued
* @param xid (a pointer to) an identifier of the
@@ -173,22 +177,22 @@ class MessageStore : public TransactionalStore, public Recoverable {
*
* Note: that this is async so the return of the function does
* not mean the opperation is complete.
- *
+ *
* @param queue the name of the queue from which it is to be dequeued
*/
virtual void flush(const qpid::broker::PersistableQueue& queue)=0;
/**
* Returns the number of outstanding AIO's for a given queue
- *
- * If 0, than all the enqueue / dequeues have been stored
+ *
+ * If 0, than all the enqueue / dequeues have been stored
* to disk
*
* @param queue the name of the queue to check for outstanding AIO
*/
virtual uint32_t outstandingQueueAIO(const PersistableQueue& queue) = 0;
-
+
virtual ~MessageStore(){}
};
diff --git a/cpp/src/qpid/broker/MessageStoreModule.cpp b/cpp/src/qpid/broker/MessageStoreModule.cpp
index c9528b9d98..5f7cceebd3 100644
--- a/cpp/src/qpid/broker/MessageStoreModule.cpp
+++ b/cpp/src/qpid/broker/MessageStoreModule.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -19,25 +19,33 @@
*
*/
-#include "MessageStoreModule.h"
+#include "qpid/broker/MessageStoreModule.h"
+#include "qpid/broker/NullMessageStore.h"
#include <iostream>
// This transfer protects against the unloading of the store lib prior to the handling of the exception
#define TRANSFER_EXCEPTION(fn) try { fn; } catch (std::exception& e) { throw Exception(e.what()); }
using boost::intrusive_ptr;
-using namespace qpid::broker;
using qpid::framing::FieldTable;
-MessageStoreModule::MessageStoreModule(MessageStore* _store) : store(_store) {}
+namespace qpid {
+namespace broker {
+
+MessageStoreModule::MessageStoreModule(boost::shared_ptr<MessageStore>& _store)
+ : store(_store) {}
MessageStoreModule::~MessageStoreModule()
{
- delete store;
}
bool MessageStoreModule::init(const Options*) { return true; }
+void MessageStoreModule::truncateInit(const bool pushDownStoreFiles)
+{
+ TRANSFER_EXCEPTION(store->truncateInit(pushDownStoreFiles));
+}
+
void MessageStoreModule::create(PersistableQueue& queue, const FieldTable& args)
{
TRANSFER_EXCEPTION(store->create(queue, args));
@@ -58,13 +66,13 @@ void MessageStoreModule::destroy(const PersistableExchange& exchange)
TRANSFER_EXCEPTION(store->destroy(exchange));
}
-void MessageStoreModule::bind(const PersistableExchange& e, const PersistableQueue& q,
+void MessageStoreModule::bind(const PersistableExchange& e, const PersistableQueue& q,
const std::string& k, const framing::FieldTable& a)
{
TRANSFER_EXCEPTION(store->bind(e, q, k, a));
}
-void MessageStoreModule::unbind(const PersistableExchange& e, const PersistableQueue& q,
+void MessageStoreModule::unbind(const PersistableExchange& e, const PersistableQueue& q,
const std::string& k, const framing::FieldTable& a)
{
TRANSFER_EXCEPTION(store->unbind(e, q, k, a));
@@ -102,7 +110,7 @@ void MessageStoreModule::appendContent(const intrusive_ptr<const PersistableMess
}
void MessageStoreModule::loadContent(
- const qpid::broker::PersistableQueue& queue,
+ const qpid::broker::PersistableQueue& queue,
const intrusive_ptr<const PersistableMessage>& msg,
string& data, uint64_t offset, uint32_t length)
{
@@ -162,3 +170,10 @@ void MessageStoreModule::collectPreparedXids(std::set<std::string>& xids)
{
TRANSFER_EXCEPTION(store->collectPreparedXids(xids));
}
+
+bool MessageStoreModule::isNull() const
+{
+ return NullMessageStore::isNullStore(store.get());
+}
+
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/MessageStoreModule.h b/cpp/src/qpid/broker/MessageStoreModule.h
index a16ef4de21..56b5a3c1ae 100644
--- a/cpp/src/qpid/broker/MessageStoreModule.h
+++ b/cpp/src/qpid/broker/MessageStoreModule.h
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -21,11 +21,12 @@
#ifndef _MessageStoreModule_
#define _MessageStoreModule_
-#include "MessageStore.h"
-#include "Queue.h"
-#include "RecoveryManager.h"
+#include "qpid/broker/MessageStore.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/RecoveryManager.h"
#include <boost/intrusive_ptr.hpp>
+#include <boost/shared_ptr.hpp>
namespace qpid {
namespace broker {
@@ -35,11 +36,12 @@ namespace broker {
*/
class MessageStoreModule : public MessageStore
{
- MessageStore* store;
+ boost::shared_ptr<MessageStore> store;
public:
- MessageStoreModule(MessageStore* store);
+ MessageStoreModule(boost::shared_ptr<MessageStore>& store);
bool init(const Options* options);
+ void truncateInit(const bool pushDownStoreFiles = false);
std::auto_ptr<TransactionContext> begin();
std::auto_ptr<TPCTransactionContext> begin(const std::string& xid);
void prepare(TPCTransactionContext& txn);
@@ -51,9 +53,9 @@ class MessageStoreModule : public MessageStore
void destroy(PersistableQueue& queue);
void create(const PersistableExchange& exchange, const framing::FieldTable& args);
void destroy(const PersistableExchange& exchange);
- void bind(const PersistableExchange& exchange, const PersistableQueue& queue,
+ void bind(const PersistableExchange& exchange, const PersistableQueue& queue,
const std::string& key, const framing::FieldTable& args);
- void unbind(const PersistableExchange& exchange, const PersistableQueue& queue,
+ void unbind(const PersistableExchange& exchange, const PersistableQueue& queue,
const std::string& key, const framing::FieldTable& args);
void create(const PersistableConfig& config);
void destroy(const PersistableConfig& config);
@@ -61,7 +63,7 @@ class MessageStoreModule : public MessageStore
void stage(const boost::intrusive_ptr<PersistableMessage>& msg);
void destroy(PersistableMessage& msg);
void appendContent(const boost::intrusive_ptr<const PersistableMessage>& msg, const std::string& data);
- void loadContent(const qpid::broker::PersistableQueue& queue,
+ void loadContent(const qpid::broker::PersistableQueue& queue,
const boost::intrusive_ptr<const PersistableMessage>& msg, std::string& data,
uint64_t offset, uint32_t length);
@@ -73,7 +75,8 @@ class MessageStoreModule : public MessageStore
const PersistableQueue& queue);
uint32_t outstandingQueueAIO(const PersistableQueue& queue);
void flush(const qpid::broker::PersistableQueue& queue);
-
+ bool isNull() const;
+
~MessageStoreModule();
};
diff --git a/cpp/src/qpid/broker/NameGenerator.cpp b/cpp/src/qpid/broker/NameGenerator.cpp
index 8484f921e9..e7f193d546 100644
--- a/cpp/src/qpid/broker/NameGenerator.cpp
+++ b/cpp/src/qpid/broker/NameGenerator.cpp
@@ -18,7 +18,7 @@
* under the License.
*
*/
-#include "NameGenerator.h"
+#include "qpid/broker/NameGenerator.h"
#include <sstream>
using namespace qpid::broker;
diff --git a/cpp/src/qpid/broker/NullMessageStore.cpp b/cpp/src/qpid/broker/NullMessageStore.cpp
index e1c7fe240d..6339b655f8 100644
--- a/cpp/src/qpid/broker/NullMessageStore.cpp
+++ b/cpp/src/qpid/broker/NullMessageStore.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -19,9 +19,11 @@
*
*/
-#include "NullMessageStore.h"
-#include "RecoveryManager.h"
+#include "qpid/broker/NullMessageStore.h"
+#include "qpid/broker/MessageStoreModule.h"
+#include "qpid/broker/RecoveryManager.h"
#include "qpid/log/Statement.h"
+#include "qpid/framing/reply_exceptions.h"
#include <iostream>
@@ -32,47 +34,41 @@ namespace broker{
const std::string nullxid = "";
-class DummyCtxt : public TPCTransactionContext
+class SimpleDummyCtxt : public TransactionContext {};
+
+class DummyCtxt : public TPCTransactionContext
{
const std::string xid;
public:
DummyCtxt(const std::string& _xid) : xid(_xid) {}
- static std::string getXid(TransactionContext& ctxt)
+ static std::string getXid(TransactionContext& ctxt)
{
DummyCtxt* c(dynamic_cast<DummyCtxt*>(&ctxt));
return c ? c->xid : nullxid;
}
};
-}
+NullMessageStore::NullMessageStore() : nextPersistenceId(1) {
+ QPID_LOG(info, "No message store configured, persistence is disabled.");
}
-using namespace qpid::broker;
-
-NullMessageStore::NullMessageStore(bool _warn) : warn(_warn), nextPersistenceId(1) {}
-
bool NullMessageStore::init(const Options* /*options*/) {return true;}
+void NullMessageStore::truncateInit(const bool /*pushDownStoreFiles*/) {}
+
void NullMessageStore::create(PersistableQueue& queue, const framing::FieldTable& /*args*/)
{
- QPID_LOG(info, "Queue '" << queue.getName()
- << "' will not be durable. Persistence not enabled.");
queue.setPersistenceId(nextPersistenceId++);
}
-void NullMessageStore::destroy(PersistableQueue&)
-{
-}
+void NullMessageStore::destroy(PersistableQueue&) {}
void NullMessageStore::create(const PersistableExchange& exchange, const framing::FieldTable& /*args*/)
{
- QPID_LOG(info, "Exchange'" << exchange.getName()
- << "' will not be durable. Persistence not enabled.");
exchange.setPersistenceId(nextPersistenceId++);
}
-void NullMessageStore::destroy(const PersistableExchange& )
-{}
+void NullMessageStore::destroy(const PersistableExchange& ) {}
void NullMessageStore::bind(const PersistableExchange&, const PersistableQueue&, const std::string&, const framing::FieldTable&){}
@@ -80,47 +76,31 @@ void NullMessageStore::unbind(const PersistableExchange&, const PersistableQueue
void NullMessageStore::create(const PersistableConfig& config)
{
- QPID_LOG(info, "Persistence not enabled, configuration not stored.");
config.setPersistenceId(nextPersistenceId++);
}
-void NullMessageStore::destroy(const PersistableConfig&)
-{
- QPID_LOG(info, "Persistence not enabled, configuration not stored.");
-}
+void NullMessageStore::destroy(const PersistableConfig&) {}
-void NullMessageStore::recover(RecoveryManager&)
-{
- QPID_LOG(info, "Persistence not enabled, no recovery attempted.");
-}
+void NullMessageStore::recover(RecoveryManager&) {}
-void NullMessageStore::stage(const intrusive_ptr<PersistableMessage>&)
-{
- QPID_LOG(info, "Can't stage message. Persistence not enabled.");
-}
+void NullMessageStore::stage(const intrusive_ptr<PersistableMessage>&) {}
-void NullMessageStore::destroy(PersistableMessage&)
-{
-}
+void NullMessageStore::destroy(PersistableMessage&) {}
-void NullMessageStore::appendContent(const intrusive_ptr<const PersistableMessage>&, const string&)
-{
- QPID_LOG(info, "Can't append content. Persistence not enabled.");
-}
+void NullMessageStore::appendContent(const intrusive_ptr<const PersistableMessage>&, const string&) {}
void NullMessageStore::loadContent(const qpid::broker::PersistableQueue&,
const intrusive_ptr<const PersistableMessage>&,
string&, uint64_t, uint32_t)
{
- QPID_LOG(info, "Can't load content. Persistence not enabled.");
+ throw qpid::framing::InternalErrorException("Can't load content; persistence not enabled");
}
void NullMessageStore::enqueue(TransactionContext*,
const intrusive_ptr<PersistableMessage>& msg,
- const PersistableQueue& queue)
+ const PersistableQueue&)
{
- msg->enqueueComplete();
- QPID_LOG(info, "Message is not durably recorded on '" << queue.getName() << "'. Persistence not enabled.");
+ msg->enqueueComplete();
}
void NullMessageStore::dequeue(TransactionContext*,
@@ -130,18 +110,15 @@ void NullMessageStore::dequeue(TransactionContext*,
msg->dequeueComplete();
}
-void NullMessageStore::flush(const qpid::broker::PersistableQueue&)
-{
-}
+void NullMessageStore::flush(const qpid::broker::PersistableQueue&) {}
-uint32_t NullMessageStore::outstandingQueueAIO(const PersistableQueue& )
-{
+uint32_t NullMessageStore::outstandingQueueAIO(const PersistableQueue& ) {
return 0;
}
std::auto_ptr<TransactionContext> NullMessageStore::begin()
{
- return std::auto_ptr<TransactionContext>();
+ return std::auto_ptr<TransactionContext>(new SimpleDummyCtxt());
}
std::auto_ptr<TPCTransactionContext> NullMessageStore::begin(const std::string& xid)
@@ -168,3 +145,21 @@ void NullMessageStore::collectPreparedXids(std::set<string>& out)
{
out.insert(prepared.begin(), prepared.end());
}
+
+bool NullMessageStore::isNull() const
+{
+ return true;
+}
+
+bool NullMessageStore::isNullStore(const MessageStore* store)
+{
+ const MessageStoreModule* wrapper = dynamic_cast<const MessageStoreModule*>(store);
+ if (wrapper) {
+ return wrapper->isNull();
+ } else {
+ const NullMessageStore* test = dynamic_cast<const NullMessageStore*>(store);
+ return test && test->isNull();
+ }
+}
+
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/NullMessageStore.h b/cpp/src/qpid/broker/NullMessageStore.h
index 4b8d02d555..e148ec4d51 100644
--- a/cpp/src/qpid/broker/NullMessageStore.h
+++ b/cpp/src/qpid/broker/NullMessageStore.h
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -22,8 +22,9 @@
#define _NullMessageStore_
#include <set>
-#include "MessageStore.h"
-#include "Queue.h"
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/MessageStore.h"
+#include "qpid/broker/Queue.h"
#include <boost/intrusive_ptr.hpp>
@@ -36,47 +37,58 @@ namespace broker {
class NullMessageStore : public MessageStore
{
std::set<std::string> prepared;
- const bool warn;
uint64_t nextPersistenceId;
public:
- NullMessageStore(bool warn = false);
+ QPID_BROKER_EXTERN NullMessageStore();
- virtual bool init(const Options* options);
- virtual std::auto_ptr<TransactionContext> begin();
- virtual std::auto_ptr<TPCTransactionContext> begin(const std::string& xid);
- virtual void prepare(TPCTransactionContext& txn);
- virtual void commit(TransactionContext& txn);
- virtual void abort(TransactionContext& txn);
- virtual void collectPreparedXids(std::set<std::string>& xids);
+ QPID_BROKER_EXTERN virtual bool init(const Options* options);
+ QPID_BROKER_EXTERN virtual void truncateInit(const bool pushDownStoreFiles = false);
+ QPID_BROKER_EXTERN virtual std::auto_ptr<TransactionContext> begin();
+ QPID_BROKER_EXTERN virtual std::auto_ptr<TPCTransactionContext> begin(const std::string& xid);
+ QPID_BROKER_EXTERN virtual void prepare(TPCTransactionContext& txn);
+ QPID_BROKER_EXTERN virtual void commit(TransactionContext& txn);
+ QPID_BROKER_EXTERN virtual void abort(TransactionContext& txn);
+ QPID_BROKER_EXTERN virtual void collectPreparedXids(std::set<std::string>& xids);
- virtual void create(PersistableQueue& queue, const framing::FieldTable& args);
- virtual void destroy(PersistableQueue& queue);
- virtual void create(const PersistableExchange& exchange, const framing::FieldTable& args);
- virtual void destroy(const PersistableExchange& exchange);
+ QPID_BROKER_EXTERN virtual void create(PersistableQueue& queue,
+ const framing::FieldTable& args);
+ QPID_BROKER_EXTERN virtual void destroy(PersistableQueue& queue);
+ QPID_BROKER_EXTERN virtual void create(const PersistableExchange& exchange,
+ const framing::FieldTable& args);
+ QPID_BROKER_EXTERN virtual void destroy(const PersistableExchange& exchange);
- virtual void bind(const PersistableExchange& exchange, const PersistableQueue& queue,
- const std::string& key, const framing::FieldTable& args);
- virtual void unbind(const PersistableExchange& exchange, const PersistableQueue& queue,
- const std::string& key, const framing::FieldTable& args);
- virtual void create(const PersistableConfig& config);
- virtual void destroy(const PersistableConfig& config);
- virtual void recover(RecoveryManager& queues);
- virtual void stage(const boost::intrusive_ptr<PersistableMessage>& msg);
- virtual void destroy(PersistableMessage& msg);
- virtual void appendContent(const boost::intrusive_ptr<const PersistableMessage>& msg,
- const std::string& data);
- virtual void loadContent(const qpid::broker::PersistableQueue& queue,
- const boost::intrusive_ptr<const PersistableMessage>& msg, std::string& data,
- uint64_t offset, uint32_t length);
- virtual void enqueue(TransactionContext* ctxt,
- const boost::intrusive_ptr<PersistableMessage>& msg,
- const PersistableQueue& queue);
- virtual void dequeue(TransactionContext* ctxt,
- const boost::intrusive_ptr<PersistableMessage>& msg,
- const PersistableQueue& queue);
- virtual uint32_t outstandingQueueAIO(const PersistableQueue& queue);
- virtual void flush(const qpid::broker::PersistableQueue& queue);
+ QPID_BROKER_EXTERN virtual void bind(const PersistableExchange& exchange,
+ const PersistableQueue& queue,
+ const std::string& key,
+ const framing::FieldTable& args);
+ QPID_BROKER_EXTERN virtual void unbind(const PersistableExchange& exchange,
+ const PersistableQueue& queue,
+ const std::string& key,
+ const framing::FieldTable& args);
+ QPID_BROKER_EXTERN virtual void create(const PersistableConfig& config);
+ QPID_BROKER_EXTERN virtual void destroy(const PersistableConfig& config);
+ QPID_BROKER_EXTERN virtual void recover(RecoveryManager& queues);
+ QPID_BROKER_EXTERN virtual void stage(const boost::intrusive_ptr<PersistableMessage>& msg);
+ QPID_BROKER_EXTERN virtual void destroy(PersistableMessage& msg);
+ QPID_BROKER_EXTERN virtual void appendContent(const boost::intrusive_ptr<const PersistableMessage>& msg,
+ const std::string& data);
+ QPID_BROKER_EXTERN virtual void loadContent(const qpid::broker::PersistableQueue& queue,
+ const boost::intrusive_ptr<const PersistableMessage>& msg,
+ std::string& data,
+ uint64_t offset,
+ uint32_t length);
+ QPID_BROKER_EXTERN virtual void enqueue(TransactionContext* ctxt,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue);
+ QPID_BROKER_EXTERN virtual void dequeue(TransactionContext* ctxt,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue);
+ QPID_BROKER_EXTERN virtual uint32_t outstandingQueueAIO(const PersistableQueue& queue);
+ QPID_BROKER_EXTERN virtual void flush(const qpid::broker::PersistableQueue& queue);
~NullMessageStore(){}
+
+ QPID_BROKER_EXTERN virtual bool isNull() const;
+ static bool isNullStore(const MessageStore*);
};
}
diff --git a/cpp/src/qpid/broker/PersistableConfig.h b/cpp/src/qpid/broker/PersistableConfig.h
index 914e91ea80..8ddb84d129 100644
--- a/cpp/src/qpid/broker/PersistableConfig.h
+++ b/cpp/src/qpid/broker/PersistableConfig.h
@@ -23,7 +23,7 @@
*/
#include <string>
-#include "Persistable.h"
+#include "qpid/broker/Persistable.h"
namespace qpid {
namespace broker {
diff --git a/cpp/src/qpid/broker/PersistableExchange.h b/cpp/src/qpid/broker/PersistableExchange.h
index 683b740ddc..e1a0853247 100644
--- a/cpp/src/qpid/broker/PersistableExchange.h
+++ b/cpp/src/qpid/broker/PersistableExchange.h
@@ -23,7 +23,7 @@
*/
#include <string>
-#include "Persistable.h"
+#include "qpid/broker/Persistable.h"
namespace qpid {
namespace broker {
diff --git a/cpp/src/qpid/broker/PersistableMessage.cpp b/cpp/src/qpid/broker/PersistableMessage.cpp
index 3bf390faf3..303a0501f4 100644
--- a/cpp/src/qpid/broker/PersistableMessage.cpp
+++ b/cpp/src/qpid/broker/PersistableMessage.cpp
@@ -20,12 +20,25 @@
*/
-#include "PersistableMessage.h"
-#include "MessageStore.h"
+#include "qpid/broker/PersistableMessage.h"
+#include "qpid/broker/MessageStore.h"
#include <iostream>
using namespace qpid::broker;
+namespace qpid {
+namespace broker {
+
+class MessageStore;
+
+PersistableMessage::~PersistableMessage() {}
+
+PersistableMessage::PersistableMessage() :
+ asyncEnqueueCounter(0),
+ asyncDequeueCounter(0),
+ store(0)
+{}
+
void PersistableMessage::flush()
{
syncList copy;
@@ -45,4 +58,126 @@ void PersistableMessage::flush()
}
}
+void PersistableMessage::setContentReleased()
+{
+ contentReleaseState.released = true;
+}
+
+bool PersistableMessage::isContentReleased() const
+{
+ return contentReleaseState.released;
+}
+
+bool PersistableMessage::isEnqueueComplete() {
+ sys::ScopedLock<sys::Mutex> l(asyncEnqueueLock);
+ return asyncEnqueueCounter == 0;
+}
+
+void PersistableMessage::enqueueComplete() {
+ bool notify = false;
+ {
+ sys::ScopedLock<sys::Mutex> l(asyncEnqueueLock);
+ if (asyncEnqueueCounter > 0) {
+ if (--asyncEnqueueCounter == 0) {
+ notify = true;
+ }
+ }
+ }
+ if (notify) {
+ allEnqueuesComplete();
+ sys::ScopedLock<sys::Mutex> l(storeLock);
+ if (store) {
+ for (syncList::iterator i = synclist.begin(); i != synclist.end(); ++i) {
+ PersistableQueue::shared_ptr q(i->lock());
+ if (q) q->notifyDurableIOComplete();
+ }
+ }
+ }
+}
+
+bool PersistableMessage::isStoredOnQueue(PersistableQueue::shared_ptr queue){
+ if (store && (queue->getPersistenceId()!=0)) {
+ for (syncList::iterator i = synclist.begin(); i != synclist.end(); ++i) {
+ PersistableQueue::shared_ptr q(i->lock());
+ if (q && q->getPersistenceId() == queue->getPersistenceId()) return true;
+ }
+ }
+ return false;
+}
+
+
+void PersistableMessage::addToSyncList(PersistableQueue::shared_ptr queue, MessageStore* _store) {
+ if (_store){
+ sys::ScopedLock<sys::Mutex> l(storeLock);
+ store = _store;
+ boost::weak_ptr<PersistableQueue> q(queue);
+ synclist.push_back(q);
+ }
+}
+
+void PersistableMessage::enqueueAsync(PersistableQueue::shared_ptr queue, MessageStore* _store) {
+ addToSyncList(queue, _store);
+ enqueueAsync();
+}
+
+void PersistableMessage::enqueueAsync() {
+ sys::ScopedLock<sys::Mutex> l(asyncEnqueueLock);
+ asyncEnqueueCounter++;
+}
+
+bool PersistableMessage::isDequeueComplete() {
+ sys::ScopedLock<sys::Mutex> l(asyncDequeueLock);
+ return asyncDequeueCounter == 0;
+}
+void PersistableMessage::dequeueComplete() {
+ bool notify = false;
+ {
+ sys::ScopedLock<sys::Mutex> l(asyncDequeueLock);
+ if (asyncDequeueCounter > 0) {
+ if (--asyncDequeueCounter == 0) {
+ notify = true;
+ }
+ }
+ }
+ if (notify) allDequeuesComplete();
+}
+
+void PersistableMessage::dequeueAsync(PersistableQueue::shared_ptr queue, MessageStore* _store) {
+ if (_store){
+ sys::ScopedLock<sys::Mutex> l(storeLock);
+ store = _store;
+ boost::weak_ptr<PersistableQueue> q(queue);
+ synclist.push_back(q);
+ }
+ dequeueAsync();
+}
+
+void PersistableMessage::dequeueAsync() {
+ sys::ScopedLock<sys::Mutex> l(asyncDequeueLock);
+ asyncDequeueCounter++;
+}
+
+PersistableMessage::ContentReleaseState::ContentReleaseState() : blocked(false), requested(false), released(false) {}
+
+void PersistableMessage::setStore(MessageStore* s)
+{
+ store = s;
+}
+
+void PersistableMessage::requestContentRelease()
+{
+ contentReleaseState.requested = true;
+}
+void PersistableMessage::blockContentRelease()
+{
+ contentReleaseState.blocked = true;
+}
+bool PersistableMessage::checkContentReleasable()
+{
+ return contentReleaseState.requested && !contentReleaseState.blocked;
+}
+
+}}
+
+
diff --git a/cpp/src/qpid/broker/PersistableMessage.h b/cpp/src/qpid/broker/PersistableMessage.h
index 7ed54c0ff0..7d49491dfd 100644
--- a/cpp/src/qpid/broker/PersistableMessage.h
+++ b/cpp/src/qpid/broker/PersistableMessage.h
@@ -26,10 +26,11 @@
#include <list>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
-#include "Persistable.h"
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/Persistable.h"
#include "qpid/framing/amqp_types.h"
-#include "qpid/sys/Monitor.h"
-#include "PersistableQueue.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/broker/PersistableQueue.h"
namespace qpid {
namespace broker {
@@ -41,10 +42,11 @@ class MessageStore;
*/
class PersistableMessage : public Persistable
{
- sys::Monitor asyncEnqueueLock;
- sys::Monitor asyncDequeueLock;
+ typedef std::list< boost::weak_ptr<PersistableQueue> > syncList;
+ sys::Mutex asyncEnqueueLock;
+ sys::Mutex asyncDequeueLock;
sys::Mutex storeLock;
-
+
/**
* Tracks the number of outstanding asynchronous enqueue
* operations. When the message is enqueued asynchronously the
@@ -62,15 +64,33 @@ class PersistableMessage : public Persistable
* dequeues.
*/
int asyncDequeueCounter;
-protected:
- typedef std::list< boost::weak_ptr<PersistableQueue> > syncList;
+
+ void enqueueAsync();
+ void dequeueAsync();
+
syncList synclist;
+ struct ContentReleaseState
+ {
+ bool blocked;
+ bool requested;
+ bool released;
+
+ ContentReleaseState();
+ };
+ ContentReleaseState contentReleaseState;
+
+ protected:
+ /** Called when all enqueues are complete for this message. */
+ virtual void allEnqueuesComplete() = 0;
+ /** Called when all dequeues are complete for this message. */
+ virtual void allDequeuesComplete() = 0;
+
+ void setContentReleased();
+
MessageStore* store;
- bool contentReleased;
-
- inline void setContentReleased() {contentReleased = true; }
-public:
+
+ public:
typedef boost::shared_ptr<PersistableMessage> shared_ptr;
/**
@@ -78,105 +98,39 @@ public:
*/
virtual uint32_t encodedHeaderSize() const = 0;
- virtual ~PersistableMessage() {};
+ virtual ~PersistableMessage();
- PersistableMessage():
- asyncEnqueueCounter(0),
- asyncDequeueCounter(0),
- store(0),
- contentReleased(false)
- {}
+ PersistableMessage();
void flush();
- inline bool isContentReleased()const {return contentReleased; }
-
- inline void waitForEnqueueComplete() {
- sys::ScopedLock<sys::Monitor> l(asyncEnqueueLock);
- while (asyncEnqueueCounter > 0) {
- asyncEnqueueLock.wait();
- }
- }
-
- inline bool isEnqueueComplete() {
- sys::ScopedLock<sys::Monitor> l(asyncEnqueueLock);
- return asyncEnqueueCounter == 0;
- }
-
- inline void enqueueComplete() {
- bool notify = false;
- {
- sys::ScopedLock<sys::Monitor> l(asyncEnqueueLock);
- if (asyncEnqueueCounter > 0) {
- if (--asyncEnqueueCounter == 0) {
- asyncEnqueueLock.notify();
- notify = true;
- }
- }
- }
- if (notify) {
- sys::ScopedLock<sys::Mutex> l(storeLock);
- if (store) {
- for (syncList::iterator i = synclist.begin(); i != synclist.end(); ++i) {
- PersistableQueue::shared_ptr q(i->lock());
- if (q) q->notifyDurableIOComplete();
- }
- }
- }
- }
-
- inline void enqueueAsync(PersistableQueue::shared_ptr queue, MessageStore* _store) {
- if (_store){
- sys::ScopedLock<sys::Mutex> l(storeLock);
- store = _store;
- boost::weak_ptr<PersistableQueue> q(queue);
- synclist.push_back(q);
- }
- enqueueAsync();
- }
-
- inline void enqueueAsync() {
- sys::ScopedLock<sys::Monitor> l(asyncEnqueueLock);
- asyncEnqueueCounter++;
- }
-
- inline bool isDequeueComplete() {
- sys::ScopedLock<sys::Monitor> l(asyncDequeueLock);
- return asyncDequeueCounter == 0;
- }
+ QPID_BROKER_EXTERN bool isContentReleased() const;
+
+ QPID_BROKER_EXTERN void setStore(MessageStore*);
+ void requestContentRelease();
+ void blockContentRelease();
+ bool checkContentReleasable();
+
+ virtual QPID_BROKER_EXTERN bool isPersistent() const = 0;
+
+ QPID_BROKER_EXTERN bool isEnqueueComplete();
+
+ QPID_BROKER_EXTERN void enqueueComplete();
+
+ QPID_BROKER_EXTERN void enqueueAsync(PersistableQueue::shared_ptr queue,
+ MessageStore* _store);
+
+
+ QPID_BROKER_EXTERN bool isDequeueComplete();
- inline void dequeueComplete() {
-
- sys::ScopedLock<sys::Monitor> l(asyncDequeueLock);
- if (asyncDequeueCounter > 0) {
- if (--asyncDequeueCounter == 0) {
- asyncDequeueLock.notify();
- }
- }
- }
-
- inline void waitForDequeueComplete() {
- sys::ScopedLock<sys::Monitor> l(asyncDequeueLock);
- while (asyncDequeueCounter > 0) {
- asyncDequeueLock.wait();
- }
- }
-
- inline void dequeueAsync(PersistableQueue::shared_ptr queue, MessageStore* _store) {
- if (_store){
- sys::ScopedLock<sys::Mutex> l(storeLock);
- store = _store;
- boost::weak_ptr<PersistableQueue> q(queue);
- synclist.push_back(q);
- }
- dequeueAsync();
- }
-
- inline void dequeueAsync() {
- sys::ScopedLock<sys::Monitor> l(asyncDequeueLock);
- asyncDequeueCounter++;
- }
+ QPID_BROKER_EXTERN void dequeueComplete();
+ QPID_BROKER_EXTERN void dequeueAsync(PersistableQueue::shared_ptr queue,
+ MessageStore* _store);
+
+ bool isStoredOnQueue(PersistableQueue::shared_ptr queue);
+
+ void addToSyncList(PersistableQueue::shared_ptr queue, MessageStore* _store);
};
diff --git a/cpp/src/qpid/broker/PersistableQueue.h b/cpp/src/qpid/broker/PersistableQueue.h
index 9236814ae3..8d85d36fef 100644
--- a/cpp/src/qpid/broker/PersistableQueue.h
+++ b/cpp/src/qpid/broker/PersistableQueue.h
@@ -23,7 +23,7 @@
*/
#include <string>
-#include "Persistable.h"
+#include "qpid/broker/Persistable.h"
#include "qpid/management/Manageable.h"
#include <boost/shared_ptr.hpp>
diff --git a/cpp/src/qpid/broker/Prefetch.h b/cpp/src/qpid/broker/Prefetch.h
deleted file mode 100644
index 8eb27a3e21..0000000000
--- a/cpp/src/qpid/broker/Prefetch.h
+++ /dev/null
@@ -1,42 +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.
- *
- */
-#ifndef _Prefetch_
-#define _Prefetch_
-
-#include "qpid/framing/amqp_types.h"
-
-namespace qpid {
- namespace broker {
- /**
- * Count and total size of asynchronously delivered
- * (i.e. pushed) messages that have acks outstanding.
- */
- struct Prefetch{
- uint32_t size;
- uint16_t count;
-
- void reset() { size = 0; count = 0; }
- };
- }
-}
-
-
-#endif
diff --git a/cpp/src/qpid/broker/Queue.cpp b/cpp/src/qpid/broker/Queue.cpp
index 40dfb80da2..f4231f2397 100644
--- a/cpp/src/qpid/broker/Queue.cpp
+++ b/cpp/src/qpid/broker/Queue.cpp
@@ -19,19 +19,23 @@
*
*/
-#include "Broker.h"
-#include "Queue.h"
-#include "Exchange.h"
-#include "DeliverableMessage.h"
-#include "MessageStore.h"
-#include "QueueRegistry.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/QueueEvents.h"
+#include "qpid/broker/Exchange.h"
+#include "qpid/broker/DeliverableMessage.h"
+#include "qpid/broker/MessageStore.h"
+#include "qpid/broker/NullMessageStore.h"
+#include "qpid/broker/QueueRegistry.h"
#include "qpid/StringUtils.h"
#include "qpid/log/Statement.h"
+#include "qpid/management/ManagementAgent.h"
#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/FieldTable.h"
#include "qpid/sys/Monitor.h"
#include "qpid/sys/Time.h"
-#include "qpid/management/ArgsQueuePurge.h"
+#include "qmf/org/apache/qpid/broker/ArgsQueuePurge.h"
#include <iostream>
#include <algorithm>
@@ -49,11 +53,34 @@ using qpid::management::Manageable;
using qpid::management::Args;
using std::for_each;
using std::mem_fun;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+
+namespace
+{
+const std::string qpidMaxSize("qpid.max_size");
+const std::string qpidMaxCount("qpid.max_count");
+const std::string qpidNoLocal("no-local");
+const std::string qpidTraceIdentity("qpid.trace.id");
+const std::string qpidTraceExclude("qpid.trace.exclude");
+const std::string qpidLastValueQueue("qpid.last_value_queue");
+const std::string qpidLastValueQueueNoBrowse("qpid.last_value_queue_no_browse");
+const std::string qpidPersistLastNode("qpid.persist_last_node");
+const std::string qpidVQMatchProperty("qpid.LVQ_key");
+const std::string qpidQueueEventGeneration("qpid.queue_event_generation");
+//following feature is not ready for general use as it doesn't handle
+//the case where a message is enqueued on more than one queue well enough:
+const std::string qpidInsertSequenceNumbers("qpid.insert_sequence_numbers");
+
+const int ENQUEUE_ONLY=1;
+const int ENQUEUE_AND_DEQUEUE=2;
+}
Queue::Queue(const string& _name, bool _autodelete,
MessageStore* const _store,
const OwnershipToken* const _owner,
- Manageable* parent) :
+ Manageable* parent,
+ Broker* b) :
name(_name),
autodelete(_autodelete),
@@ -62,22 +89,31 @@ Queue::Queue(const string& _name, bool _autodelete,
consumerCount(0),
exclusive(0),
noLocal(false),
+ lastValueQueue(false),
+ lastValueQueueNoBrowse(false),
+ persistLastNode(false),
+ inLastNodeFailure(false),
persistenceId(0),
policyExceeded(false),
- mgmtObject(0)
+ mgmtObject(0),
+ eventMode(0),
+ eventMgr(0),
+ insertSeqNo(0),
+ broker(b)
{
- if (parent != 0)
+ if (parent != 0 && broker != 0)
{
- ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ ManagementAgent* agent = broker->getManagementAgent();
if (agent != 0)
{
- mgmtObject = new management::Queue (agent, this, parent, _name, _store != 0, _autodelete, _owner != 0);
+ mgmtObject = new _qmf::Queue(agent, this, parent, _name, _store != 0, _autodelete, _owner != 0);
// Add the object to the management agent only if this queue is not durable.
// If it's durable, we will add it later when the queue is assigned a persistenceId.
- if (store == 0)
- agent->addObject (mgmtObject);
+ if (store == 0) {
+ agent->addObject (mgmtObject, agent->allocateId(this));
+ }
}
}
}
@@ -90,8 +126,12 @@ Queue::~Queue()
void Queue::notifyDurableIOComplete()
{
- Mutex::ScopedLock locker(messageLock);
- notify();
+ QueueListeners::NotificationSet copy;
+ {
+ Mutex::ScopedLock locker(messageLock);
+ listeners.populate(copy);
+ }
+ copy.notify();
}
bool isLocalTo(const OwnershipToken* token, boost::intrusive_ptr<Message>& msg)
@@ -129,35 +169,31 @@ void Queue::deliver(boost::intrusive_ptr<Message>& msg){
} else {
// if no store then mark as enqueued
if (!enqueue(0, msg)){
- if (mgmtObject != 0) {
- mgmtObject->inc_msgTotalEnqueues ();
- mgmtObject->inc_byteTotalEnqueues (msg->contentSize ());
- }
push(msg);
msg->enqueueComplete();
}else {
- if (mgmtObject != 0) {
- mgmtObject->inc_msgTotalEnqueues ();
- mgmtObject->inc_byteTotalEnqueues (msg->contentSize ());
- mgmtObject->inc_msgPersistEnqueues ();
- mgmtObject->inc_bytePersistEnqueues (msg->contentSize ());
- }
push(msg);
}
+ mgntEnqStats(msg);
QPID_LOG(debug, "Message " << msg << " enqueued on " << name << "[" << this << "]");
}
}
+void Queue::recoverPrepared(boost::intrusive_ptr<Message>& msg)
+{
+ if (policy.get()) policy->recoverEnqueued(msg);
+}
void Queue::recover(boost::intrusive_ptr<Message>& msg){
- push(msg);
- msg->enqueueComplete(); // mark the message as enqueued
- if (mgmtObject != 0) {
- mgmtObject->inc_msgTotalEnqueues ();
- mgmtObject->inc_byteTotalEnqueues (msg->contentSize ());
- mgmtObject->inc_msgPersistEnqueues ();
- mgmtObject->inc_bytePersistEnqueues (msg->contentSize ());
+ if (policy.get()) policy->recoverEnqueued(msg);
+
+ push(msg, true);
+ if (store){
+ // setup synclist for recovered messages, so they don't get re-stored on lastNodeFailure
+ msg->addToSyncList(shared_from_this(), store);
}
+ msg->enqueueComplete(); // mark the message as enqueued
+ mgntEnqStats(msg);
if (store && !msg->isContentLoaded()) {
//content has not been loaded, need to ensure that lazy loading mode is set:
@@ -168,121 +204,188 @@ void Queue::recover(boost::intrusive_ptr<Message>& msg){
void Queue::process(boost::intrusive_ptr<Message>& msg){
push(msg);
- if (mgmtObject != 0) {
- mgmtObject->inc_msgTotalEnqueues ();
- mgmtObject->inc_byteTotalEnqueues (msg->contentSize ());
+ mgntEnqStats(msg);
+ if (mgmtObject != 0){
mgmtObject->inc_msgTxnEnqueues ();
mgmtObject->inc_byteTxnEnqueues (msg->contentSize ());
- if (msg->isPersistent ()) {
- mgmtObject->inc_msgPersistEnqueues ();
- mgmtObject->inc_bytePersistEnqueues (msg->contentSize ());
- }
}
}
void Queue::requeue(const QueuedMessage& msg){
+ QueueListeners::NotificationSet copy;
+ {
+ Mutex::ScopedLock locker(messageLock);
+ if (!isEnqueued(msg)) return;
+ msg.payload->enqueueComplete(); // mark the message as enqueued
+ messages.insert(lower_bound(messages.begin(), messages.end(), msg), msg);
+ listeners.populate(copy);
+
+ // for persistLastNode - don't force a message twice to disk, but force it if no force before
+ if(inLastNodeFailure && persistLastNode && !msg.payload->isStoredOnQueue(shared_from_this())) {
+ msg.payload->forcePersistent();
+ if (msg.payload->isForcedPersistent() ){
+ enqueue(0, msg.payload);
+ }
+ }
+ }
+ copy.notify();
+}
+
+void Queue::clearLVQIndex(const QueuedMessage& msg){
+ const framing::FieldTable* ft = msg.payload ? msg.payload->getApplicationHeaders() : 0;
+ if (lastValueQueue && ft){
+ string key = ft->getAsString(qpidVQMatchProperty);
+ lvq.erase(key);
+ }
+}
+
+bool Queue::acquireMessageAt(const SequenceNumber& position, QueuedMessage& message)
+{
Mutex::ScopedLock locker(messageLock);
- msg.payload->enqueueComplete(); // mark the message as enqueued
- messages.push_front(msg);
- notify();
+ QPID_LOG(debug, "Attempting to acquire message at " << position);
+
+ Messages::iterator i = findAt(position);
+ if (i != messages.end() ) {
+ message = *i;
+ if (lastValueQueue) {
+ clearLVQIndex(*i);
+ }
+ QPID_LOG(debug,
+ "Acquired message at " << i->position << " from " << name);
+ messages.erase(i);
+ return true;
+ }
+ QPID_LOG(debug, "Could not acquire message at " << position << " from " << name << "; no message at that position");
+ return false;
}
bool Queue::acquire(const QueuedMessage& msg) {
Mutex::ScopedLock locker(messageLock);
QPID_LOG(debug, "attempting to acquire " << msg.position);
- for (Messages::iterator i = messages.begin(); i != messages.end(); i++) {
- if (i->position == msg.position) {
- messages.erase(i);
- QPID_LOG(debug, "Match found, acquire succeeded: " << i->position << " == " << msg.position);
- return true;
- } else {
- QPID_LOG(debug, "No match: " << i->position << " != " << msg.position);
- }
+ Messages::iterator i = findAt(msg.position);
+ if ((i != messages.end() && !lastValueQueue) // note that in some cases payload not be set
+ || (lastValueQueue && (i->position == msg.position) &&
+ msg.payload.get() == checkLvqReplace(*i).payload.get()) ) {
+
+ clearLVQIndex(msg);
+ QPID_LOG(debug,
+ "Match found, acquire succeeded: " <<
+ i->position << " == " << msg.position);
+ messages.erase(i);
+ return true;
+ } else {
+ QPID_LOG(debug, "No match: " << i->position << " != " << msg.position);
}
+
QPID_LOG(debug, "Acquire failed for " << msg.position);
return false;
}
-bool Queue::getNextMessage(QueuedMessage& m, Consumer& c)
+void Queue::notifyListener()
{
- if (c.preAcquires()) {
- return consumeNextMessage(m, c);
+ QueueListeners::NotificationSet set;
+ {
+ Mutex::ScopedLock locker(messageLock);
+ if (messages.size()) {
+ listeners.populate(set);
+ }
+ }
+ set.notify();
+}
+
+bool Queue::getNextMessage(QueuedMessage& m, Consumer::shared_ptr c)
+{
+ if (c->preAcquires()) {
+ switch (consumeNextMessage(m, c)) {
+ case CONSUMED:
+ return true;
+ case CANT_CONSUME:
+ notifyListener();//let someone else try
+ case NO_MESSAGES:
+ default:
+ return false;
+ }
} else {
return browseNextMessage(m, c);
}
}
-bool Queue::checkForMessages(Consumer& c)
+bool Queue::checkForMessages(Consumer::shared_ptr c)
{
Mutex::ScopedLock locker(messageLock);
if (messages.empty()) {
//no message available, register consumer for notification
//when this changes
- addListener(c);
+ listeners.addListener(c);
return false;
} else {
- QueuedMessage msg = messages.front();
+ QueuedMessage msg = getFront();
if (store && !msg.payload->isEnqueueComplete()) {
//though a message is on the queue, it has not yet been
//enqueued and so is not available for consumption yet,
//register consumer for notification when this changes
- addListener(c);
+ listeners.addListener(c);
return false;
} else {
//check that consumer has sufficient credit for the
//message (if it does not, no need to register it for
//notification as the consumer itself will handle the
//credit allocation required to change this condition).
- return c.accept(msg.payload);
+ return c->accept(msg.payload);
}
}
}
-bool Queue::consumeNextMessage(QueuedMessage& m, Consumer& c)
+Queue::ConsumeCode Queue::consumeNextMessage(QueuedMessage& m, Consumer::shared_ptr c)
{
while (true) {
Mutex::ScopedLock locker(messageLock);
if (messages.empty()) {
QPID_LOG(debug, "No messages to dispatch on queue '" << name << "'");
- addListener(c);
- return false;
+ listeners.addListener(c);
+ return NO_MESSAGES;
} else {
- QueuedMessage msg = messages.front();
- if (store && !msg.payload->isEnqueueComplete()) {
- QPID_LOG(debug, "Messages not ready to dispatch on queue '" << name << "'");
- addListener(c);
- return false;
+ QueuedMessage msg = getFront();
+ if (msg.payload->hasExpired()) {
+ QPID_LOG(debug, "Message expired from queue '" << name << "'");
+ popAndDequeue();
+ continue;
}
-
- if (c.filter(msg.payload)) {
- if (c.accept(msg.payload)) {
+
+ if (c->filter(msg.payload)) {
+ if (c->accept(msg.payload)) {
m = msg;
- messages.pop_front();
- return true;
+ popMsg(msg);
+ return CONSUMED;
} else {
//message(s) are available but consumer hasn't got enough credit
QPID_LOG(debug, "Consumer can't currently accept message from '" << name << "'");
- return false;
+ return CANT_CONSUME;
}
} else {
//consumer will never want this message
QPID_LOG(debug, "Consumer doesn't want message from '" << name << "'");
- return false;
+ return CANT_CONSUME;
}
}
}
}
-bool Queue::browseNextMessage(QueuedMessage& m, Consumer& c)
+bool Queue::browseNextMessage(QueuedMessage& m, Consumer::shared_ptr c)
{
QueuedMessage msg(this);
while (seek(msg, c)) {
- if (c.filter(msg.payload)) {
- if (c.accept(msg.payload)) {
+ if (c->filter(msg.payload) && !msg.payload->hasExpired()) {
+ if (c->accept(msg.payload)) {
//consumer wants the message
- c.position = msg.position;
+ c->position = msg.position;
m = msg;
+ if (!lastValueQueueNoBrowse) clearLVQIndex(msg);
+ if (lastValueQueue) {
+ boost::intrusive_ptr<Message> replacement = msg.payload->getReplacementMessage(this);
+ if (replacement.get()) m.payload = replacement;
+ }
return true;
} else {
//browser hasn't got enough credit for the message
@@ -291,70 +394,89 @@ bool Queue::browseNextMessage(QueuedMessage& m, Consumer& c)
}
} else {
//consumer will never want this message, continue seeking
- c.position = msg.position;
+ c->position = msg.position;
QPID_LOG(debug, "Browser skipping message from '" << name << "'");
}
}
return false;
}
-/**
- * notify listeners that there may be messages to process
- */
-void Queue::notify()
-{
- if (listeners.empty()) return;
-
- Listeners copy(listeners);
- listeners.clear();
- for_each(copy.begin(), copy.end(), mem_fun(&Consumer::notify));
-}
-
-void Queue::removeListener(Consumer& c)
-{
- Mutex::ScopedLock locker(messageLock);
- Listeners::iterator i = std::find(listeners.begin(), listeners.end(), &c);
- if (i != listeners.end()) listeners.erase(i);
-}
-
-void Queue::addListener(Consumer& c)
+void Queue::removeListener(Consumer::shared_ptr c)
{
- Listeners::iterator i = std::find(listeners.begin(), listeners.end(), &c);
- if (i == listeners.end()) listeners.push_back(&c);
+ QueueListeners::NotificationSet set;
+ {
+ Mutex::ScopedLock locker(messageLock);
+ listeners.removeListener(c);
+ if (messages.size()) {
+ listeners.populate(set);
+ }
+ }
+ set.notify();
}
-bool Queue::dispatch(Consumer& c)
+bool Queue::dispatch(Consumer::shared_ptr c)
{
QueuedMessage msg(this);
if (getNextMessage(msg, c)) {
- c.deliver(msg);
+ c->deliver(msg);
return true;
} else {
return false;
}
}
-bool Queue::seek(QueuedMessage& msg, Consumer& c) {
+// Find the next message
+bool Queue::seek(QueuedMessage& msg, Consumer::shared_ptr c) {
Mutex::ScopedLock locker(messageLock);
- if (!messages.empty() && messages.back().position > c.position) {
- if (c.position < messages.front().position) {
- msg = messages.front();
+ if (!messages.empty() && messages.back().position > c->position) {
+ if (c->position < getFront().position) {
+ msg = getFront();
return true;
} else {
- //TODO: can improve performance of this search, for now just searching linearly from end
- Messages::reverse_iterator pos;
- for (Messages::reverse_iterator i = messages.rbegin(); i != messages.rend() && i->position > c.position; i++) {
- pos = i;
+ Messages::iterator pos = findAt(c->position);
+ if (pos != messages.end() && pos+1 != messages.end()) {
+ msg = *(pos+1);
+ return true;
}
- msg = *pos;
- return true;
}
}
- addListener(c);
+ listeners.addListener(c);
return false;
}
-void Queue::consume(Consumer& c, bool requestExclusive){
+Queue::Messages::iterator Queue::findAt(SequenceNumber pos) {
+
+ if(!messages.empty()){
+ QueuedMessage compM;
+ compM.position = pos;
+ unsigned long diff = pos.getValue() - messages.front().position.getValue();
+ long maxEnd = diff < messages.size()? diff : messages.size();
+
+ Messages::iterator i = lower_bound(messages.begin(),messages.begin()+maxEnd,compM);
+ if (i!= messages.end() && i->position == pos)
+ return i;
+ }
+ return messages.end(); // no match found.
+}
+
+
+QueuedMessage Queue::find(SequenceNumber pos) const {
+
+ Mutex::ScopedLock locker(messageLock);
+ if(!messages.empty()){
+ QueuedMessage compM;
+ compM.position = pos;
+ unsigned long diff = pos.getValue() - messages.front().position.getValue();
+ long maxEnd = diff < messages.size()? diff : messages.size();
+
+ Messages::const_iterator i = lower_bound(messages.begin(),messages.begin()+maxEnd,compM);
+ if (i != messages.end())
+ return *i;
+ }
+ return QueuedMessage();
+}
+
+void Queue::consume(Consumer::shared_ptr c, bool requestExclusive){
Mutex::ScopedLock locker(consumerLock);
if(exclusive) {
throw ResourceLockedException(
@@ -364,7 +486,7 @@ void Queue::consume(Consumer& c, bool requestExclusive){
throw ResourceLockedException(
QPID_MSG("Queue " << getName() << " already has consumers. Exclusive access denied."));
} else {
- exclusive = c.getSession();
+ exclusive = c->getSession();
}
}
consumerCount++;
@@ -372,7 +494,7 @@ void Queue::consume(Consumer& c, bool requestExclusive){
mgmtObject->inc_consumerCount ();
}
-void Queue::cancel(Consumer& c){
+void Queue::cancel(Consumer::shared_ptr c){
removeListener(c);
Mutex::ScopedLock locker(consumerLock);
consumerCount--;
@@ -386,12 +508,35 @@ QueuedMessage Queue::get(){
QueuedMessage msg(this);
if(!messages.empty()){
- msg = messages.front();
- messages.pop_front();
+ msg = getFront();
+ popMsg(msg);
}
return msg;
}
+void Queue::purgeExpired()
+{
+ //As expired messages are discarded during dequeue also, only
+ //bother explicitly expiring if the rate of dequeues since last
+ //attempt is less than one per second.
+ if (dequeueTracker.sampleRatePerSecond() < 1) {
+ Messages expired;
+ {
+ Mutex::ScopedLock locker(messageLock);
+ for (Messages::iterator i = messages.begin(); i != messages.end();) {
+ if (lastValueQueue) checkLvqReplace(*i);
+ if (i->payload->hasExpired()) {
+ expired.push_back(*i);
+ i = messages.erase(i);
+ } else {
+ ++i;
+ }
+ }
+ }
+ for_each(expired.begin(), expired.end(), bind(&Queue::dequeue, this, (TransactionContext*) 0, _1));
+ }
+}
+
/**
* purge - for purging all or some messages on a queue
* depending on the purge_request
@@ -406,106 +551,252 @@ uint32_t Queue::purge(const uint32_t purge_request){
uint32_t count = 0;
// Either purge them all or just the some (purge_count) while the queue isn't empty.
- while((!purge_request || purge_count--) && !messages.empty())
- {
+ while((!purge_request || purge_count--) && !messages.empty()) {
popAndDequeue();
- count++;
+ count++;
}
return count;
}
-void Queue::push(boost::intrusive_ptr<Message>& msg){
- Mutex::ScopedLock locker(messageLock);
- messages.push_back(QueuedMessage(this, msg, ++sequence));
- if (policy.get()) {
- policy->enqueued(msg->contentSize());
- if (policy->limitExceeded()) {
- if (!policyExceeded) {
- policyExceeded = true;
- QPID_LOG(info, "Queue size exceeded policy for " << name);
- }
- if (store) {
- QPID_LOG(debug, "Message " << msg << " on " << name << " released from memory");
- msg->releaseContent(store);
- } else {
- QPID_LOG(error, "Message " << msg << " on " << name
- << " exceeds the policy for the queue but can't be released from memory as the queue is not durable");
- throw ResourceLimitExceededException(QPID_MSG("Policy exceeded for " << name << " " << *policy));
- }
- } else {
- if (policyExceeded) {
- policyExceeded = false;
- QPID_LOG(info, "Queue size within policy for " << name);
- }
+uint32_t Queue::move(const Queue::shared_ptr destq, uint32_t qty) {
+ Mutex::ScopedLock locker(messageLock);
+ uint32_t move_count = qty; // only comes into play if qty >0
+ uint32_t count = 0; // count how many were moved for returning
+
+ while((!qty || move_count--) && !messages.empty()) {
+ QueuedMessage qmsg = getFront();
+ boost::intrusive_ptr<Message> msg = qmsg.payload;
+ destq->deliver(msg); // deliver message to the destination queue
+ popMsg(qmsg);
+ dequeue(0, qmsg);
+ count++;
+ }
+ return count;
+}
+
+void Queue::popMsg(QueuedMessage& qmsg)
+{
+ const framing::FieldTable* ft = qmsg.payload->getApplicationHeaders();
+ if (lastValueQueue && ft){
+ string key = ft->getAsString(qpidVQMatchProperty);
+ lvq.erase(key);
+ }
+ messages.pop_front();
+ ++dequeueTracker;
+}
+
+void Queue::push(boost::intrusive_ptr<Message>& msg, bool isRecovery){
+ QueueListeners::NotificationSet copy;
+ {
+ Mutex::ScopedLock locker(messageLock);
+ QueuedMessage qm(this, msg, ++sequence);
+ if (insertSeqNo) msg->getOrInsertHeaders().setInt64(seqNoKey, sequence);
+
+ LVQ::iterator i;
+ const framing::FieldTable* ft = msg->getApplicationHeaders();
+ if (lastValueQueue && ft){
+ string key = ft->getAsString(qpidVQMatchProperty);
+
+ i = lvq.find(key);
+ if (i == lvq.end() || (broker && broker->isClusterUpdatee())) {
+ messages.push_back(qm);
+ listeners.populate(copy);
+ lvq[key] = msg;
+ }else {
+ boost::intrusive_ptr<Message> old = i->second->getReplacementMessage(this);
+ if (!old) old = i->second;
+ i->second->setReplacementMessage(msg,this);
+ if (isRecovery) {
+ //can't issue new requests for the store until
+ //recovery is complete
+ pendingDequeues.push_back(QueuedMessage(qm.queue, old, qm.position));
+ } else {
+ Mutex::ScopedUnlock u(messageLock);
+ dequeue(0, QueuedMessage(qm.queue, old, qm.position));
+ }
+ }
+ }else {
+ messages.push_back(qm);
+ listeners.populate(copy);
+ }
+ if (eventMode) {
+ if (eventMgr) eventMgr->enqueued(qm);
+ else QPID_LOG(warning, "Enqueue manager not set, events not generated for " << getName());
+ }
+ if (policy.get()) {
+ policy->enqueued(qm);
}
}
- notify();
+ copy.notify();
+}
+
+QueuedMessage Queue::getFront()
+{
+ QueuedMessage msg = messages.front();
+ if (lastValueQueue) {
+ boost::intrusive_ptr<Message> replacement = msg.payload->getReplacementMessage(this);
+ if (replacement.get()) msg.payload = replacement;
+ }
+ return msg;
+}
+
+QueuedMessage& Queue::checkLvqReplace(QueuedMessage& msg)
+{
+ boost::intrusive_ptr<Message> replacement = msg.payload->getReplacementMessage(this);
+ if (replacement.get()) {
+ const framing::FieldTable* ft = replacement->getApplicationHeaders();
+ if (ft) {
+ string key = ft->getAsString(qpidVQMatchProperty);
+ if (lvq.find(key) != lvq.end()){
+ lvq[key] = replacement;
+ }
+ }
+ msg.payload = replacement;
+ }
+ return msg;
}
/** function only provided for unit tests, or code not in critical message path */
-uint32_t Queue::getMessageCount() const{
+uint32_t Queue::getEnqueueCompleteMessageCount() const
+{
Mutex::ScopedLock locker(messageLock);
-
- uint32_t count =0;
+ uint32_t count = 0;
for ( Messages::const_iterator i = messages.begin(); i != messages.end(); ++i ) {
+ //NOTE: don't need to use checkLvqReplace() here as it
+ //is only relevant for LVQ which does not support persistence
+ //so the enqueueComplete check has no effect
if ( i->payload->isEnqueueComplete() ) count ++;
}
return count;
}
-uint32_t Queue::getConsumerCount() const{
+uint32_t Queue::getMessageCount() const
+{
+ Mutex::ScopedLock locker(messageLock);
+ return messages.size();
+}
+
+uint32_t Queue::getConsumerCount() const
+{
Mutex::ScopedLock locker(consumerLock);
return consumerCount;
}
-bool Queue::canAutoDelete() const{
+bool Queue::canAutoDelete() const
+{
Mutex::ScopedLock locker(consumerLock);
return autodelete && !consumerCount;
}
+void Queue::clearLastNodeFailure()
+{
+ inLastNodeFailure = false;
+}
+
+void Queue::setLastNodeFailure()
+{
+ if (persistLastNode){
+ Mutex::ScopedLock locker(messageLock);
+ try {
+ for ( Messages::iterator i = messages.begin(); i != messages.end(); ++i ) {
+ if (lastValueQueue) checkLvqReplace(*i);
+ // don't force a message twice to disk.
+ if(!i->payload->isStoredOnQueue(shared_from_this())) {
+ i->payload->forcePersistent();
+ if (i->payload->isForcedPersistent() ){
+ enqueue(0, i->payload);
+ }
+ }
+ }
+ } catch (const std::exception& e) {
+ // Could not go into last node standing (for example journal not large enough)
+ QPID_LOG(error, "Unable to fail to last node standing for queue: " << name << " : " << e.what());
+ }
+ inLastNodeFailure = true;
+ }
+}
+
// return true if store exists,
-bool Queue::enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg)
+bool Queue::enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg, bool suppressPolicyCheck)
{
+ if (policy.get() && !suppressPolicyCheck) {
+ Messages dequeues;
+ {
+ Mutex::ScopedLock locker(messageLock);
+ policy->tryEnqueue(msg);
+ policy->getPendingDequeues(dequeues);
+ }
+ //depending on policy, may have some dequeues that need to performed without holding the lock
+ for_each(dequeues.begin(), dequeues.end(), boost::bind(&Queue::dequeue, this, (TransactionContext*) 0, _1));
+ }
+
+ if (inLastNodeFailure && persistLastNode){
+ msg->forcePersistent();
+ }
+
if (traceId.size()) {
msg->addTraceId(traceId);
}
- if (msg->isPersistent() && store) {
+ if ((msg->isPersistent() || msg->checkContentReleasable()) && store) {
msg->enqueueAsync(shared_from_this(), store); //increment to async counter -- for message sent to more than one queue
boost::intrusive_ptr<PersistableMessage> pmsg = boost::static_pointer_cast<PersistableMessage>(msg);
store->enqueue(ctxt, pmsg, *this);
return true;
}
- //msg->enqueueAsync(); // increments intrusive ptr cnt
+ if (!store) {
+ //Messages enqueued on a transient queue should be prevented
+ //from having their content released as it may not be
+ //recoverable by these queue for delivery
+ msg->blockContentRelease();
+ }
return false;
}
+void Queue::enqueueAborted(boost::intrusive_ptr<Message> msg)
+{
+ Mutex::ScopedLock locker(messageLock);
+ if (policy.get()) policy->enqueueAborted(msg);
+}
+
// return true if store exists,
-bool Queue::dequeue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg)
+bool Queue::dequeue(TransactionContext* ctxt, const QueuedMessage& msg)
{
{
Mutex::ScopedLock locker(messageLock);
- dequeued(msg);
+ if (!isEnqueued(msg)) return false;
+ if (!ctxt) {
+ dequeued(msg);
+ }
}
- if (msg->isPersistent() && store) {
- msg->dequeueAsync(shared_from_this(), store); //increment to async counter -- for message sent to more than one queue
- boost::intrusive_ptr<PersistableMessage> pmsg = boost::static_pointer_cast<PersistableMessage>(msg);
+ if ((msg.payload->isPersistent() || msg.payload->checkContentReleasable()) && store) {
+ msg.payload->dequeueAsync(shared_from_this(), store); //increment to async counter -- for message sent to more than one queue
+ boost::intrusive_ptr<PersistableMessage> pmsg = boost::static_pointer_cast<PersistableMessage>(msg.payload);
store->dequeue(ctxt, pmsg, *this);
return true;
}
- //msg->dequeueAsync(); // decrements intrusive ptr cnt
return false;
}
+void Queue::dequeueCommitted(const QueuedMessage& msg)
+{
+ Mutex::ScopedLock locker(messageLock);
+ dequeued(msg);
+ if (mgmtObject != 0) {
+ mgmtObject->inc_msgTxnDequeues();
+ mgmtObject->inc_byteTxnDequeues(msg.payload->contentSize());
+ }
+}
+
/**
* Removes a message from the in-memory delivery queue as well
* dequeing it from the logical (and persistent if applicable) queue
*/
void Queue::popAndDequeue()
{
- boost::intrusive_ptr<Message> msg = messages.front().payload;
- messages.pop_front();
+ QueuedMessage msg = getFront();
+ popMsg(msg);
dequeue(0, msg);
}
@@ -513,29 +804,16 @@ void Queue::popAndDequeue()
* Updates policy and management when a message has been dequeued,
* expects messageLock to be held
*/
-void Queue::dequeued(boost::intrusive_ptr<Message>& msg)
+void Queue::dequeued(const QueuedMessage& msg)
{
- if (policy.get()) policy->dequeued(msg->contentSize());
- if (mgmtObject != 0){
- mgmtObject->inc_msgTotalDequeues ();
- mgmtObject->inc_byteTotalDequeues (msg->contentSize());
- if (msg->isPersistent ()){
- mgmtObject->inc_msgPersistDequeues ();
- mgmtObject->inc_bytePersistDequeues (msg->contentSize());
- }
+ if (policy.get()) policy->dequeued(msg);
+ mgntDeqStats(msg.payload);
+ if (eventMode == ENQUEUE_AND_DEQUEUE && eventMgr) {
+ eventMgr->dequeued(msg);
}
}
-namespace
-{
- const std::string qpidMaxSize("qpid.max_size");
- const std::string qpidMaxCount("qpid.max_count");
- const std::string qpidNoLocal("no-local");
- const std::string qpidTraceIdentity("qpid.trace.id");
- const std::string qpidTraceExclude("qpid.trace.exclude");
-}
-
void Queue::create(const FieldTable& _settings)
{
settings = _settings;
@@ -545,26 +823,56 @@ void Queue::create(const FieldTable& _settings)
configure(_settings);
}
-void Queue::configure(const FieldTable& _settings)
+void Queue::configure(const FieldTable& _settings, bool recovering)
{
- std::auto_ptr<QueuePolicy> _policy(new QueuePolicy(_settings));
- if (_policy->getMaxCount() || _policy->getMaxSize()) {
- setPolicy(_policy);
+
+ eventMode = _settings.getAsInt(qpidQueueEventGeneration);
+
+ if (QueuePolicy::getType(_settings) == QueuePolicy::FLOW_TO_DISK &&
+ (!store || NullMessageStore::isNullStore(store) || (eventMode && eventMgr && !eventMgr->isSync()) )) {
+ if ( NullMessageStore::isNullStore(store)) {
+ QPID_LOG(warning, "Flow to disk not valid for non-persisted queue:" << getName());
+ } else if (eventMgr && !eventMgr->isSync() ) {
+ QPID_LOG(warning, "Flow to disk not valid with async Queue Events:" << getName());
+ }
+ FieldTable copy(_settings);
+ copy.erase(QueuePolicy::typeKey);
+ setPolicy(QueuePolicy::createQueuePolicy(getName(), copy));
+ } else {
+ setPolicy(QueuePolicy::createQueuePolicy(getName(), _settings));
}
//set this regardless of owner to allow use of no-local with exclusive consumers also
noLocal = _settings.get(qpidNoLocal);
- QPID_LOG(debug, "Configured queue with no-local=" << noLocal);
+ QPID_LOG(debug, "Configured queue " << getName() << " with no-local=" << noLocal);
+
+ lastValueQueue= _settings.get(qpidLastValueQueue);
+ if (lastValueQueue) QPID_LOG(debug, "Configured queue as Last Value Queue for: " << getName());
- traceId = _settings.getString(qpidTraceIdentity);
- std::string excludeList = _settings.getString(qpidTraceExclude);
+ lastValueQueueNoBrowse = _settings.get(qpidLastValueQueueNoBrowse);
+ if (lastValueQueueNoBrowse){
+ QPID_LOG(debug, "Configured queue as Last Value Queue No Browse for: " << getName());
+ lastValueQueue = lastValueQueueNoBrowse;
+ }
+
+ persistLastNode= _settings.get(qpidPersistLastNode);
+ if (persistLastNode) QPID_LOG(debug, "Configured queue to Persist data if cluster fails to one node for: " << getName());
+
+ traceId = _settings.getAsString(qpidTraceIdentity);
+ std::string excludeList = _settings.getAsString(qpidTraceExclude);
if (excludeList.size()) {
split(traceExclude, excludeList, ", ");
}
QPID_LOG(debug, "Configured queue " << getName() << " with qpid.trace.id='" << traceId
<< "' and qpid.trace.exclude='"<< excludeList << "' i.e. " << traceExclude.size() << " elements");
+ FieldTable::ValuePtr p =_settings.get(qpidInsertSequenceNumbers);
+ if (p && p->convertsTo<std::string>()) insertSequenceNumbers(p->get<std::string>());
+
if (mgmtObject != 0)
mgmtObject->set_arguments (_settings);
+
+ if ( isDurable() && ! getPersistenceId() && ! recovering )
+ store->create(*this, _settings);
}
void Queue::destroy()
@@ -572,7 +880,7 @@ void Queue::destroy()
if (alternateExchange.get()) {
Mutex::ScopedLock locker(messageLock);
while(!messages.empty()){
- DeliverableMessage msg(messages.front().payload);
+ DeliverableMessage msg(getFront().payload);
alternateExchange->route(msg, msg.getMessage().getRoutingKey(),
msg.getMessage().getApplicationHeaders());
popAndDequeue();
@@ -617,8 +925,8 @@ void Queue::setPersistenceId(uint64_t _persistenceId) const
{
if (mgmtObject != 0 && persistenceId == 0)
{
- ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
- agent->addObject (mgmtObject, _persistenceId, 3);
+ ManagementAgent* agent = broker->getManagementAgent();
+ agent->addObject (mgmtObject, 0x3000000000000000LL + _persistenceId);
if (externalQueueStore) {
ManagementObject* childObj = externalQueueStore->GetManagementObject();
@@ -629,24 +937,40 @@ void Queue::setPersistenceId(uint64_t _persistenceId) const
persistenceId = _persistenceId;
}
-void Queue::encode(framing::Buffer& buffer) const
+void Queue::encode(Buffer& buffer) const
{
buffer.putShortString(name);
buffer.put(settings);
+ if (policy.get()) {
+ buffer.put(*policy);
+ }
+ buffer.putShortString(alternateExchange.get() ? alternateExchange->getName() : std::string(""));
}
uint32_t Queue::encodedSize() const
{
- return name.size() + 1/*short string size octet*/ + settings.size();
+ return name.size() + 1/*short string size octet*/
+ + (alternateExchange.get() ? alternateExchange->getName().size() : 0) + 1 /* short string */
+ + settings.encodedSize()
+ + (policy.get() ? (*policy).encodedSize() : 0);
}
-Queue::shared_ptr Queue::decode(QueueRegistry& queues, framing::Buffer& buffer)
+Queue::shared_ptr Queue::decode ( QueueRegistry& queues, Buffer& buffer, bool recovering )
{
string name;
buffer.getShortString(name);
std::pair<Queue::shared_ptr, bool> result = queues.declare(name, true);
buffer.get(result.first->settings);
- result.first->configure(result.first->settings);
+ result.first->configure(result.first->settings, recovering );
+ if (result.first->policy.get() && buffer.available() >= result.first->policy->encodedSize()) {
+ buffer.get ( *(result.first->policy) );
+ }
+ if (buffer.available()) {
+ string altExch;
+ buffer.getShortString(altExch);
+ result.first->alternateExchangeName.assign(altExch);
+ }
+
return result.first;
}
@@ -654,6 +978,12 @@ Queue::shared_ptr Queue::decode(QueueRegistry& queues, framing::Buffer& buffer)
void Queue::setAlternateExchange(boost::shared_ptr<Exchange> exchange)
{
alternateExchange = exchange;
+ if (mgmtObject) {
+ if (exchange.get() != 0)
+ mgmtObject->set_altExchange(exchange->GetManagementObject()->getObjectId());
+ else
+ mgmtObject->clr_altExchange();
+ }
}
boost::shared_ptr<Exchange> Queue::getAlternateExchange()
@@ -721,8 +1051,7 @@ ManagementObject* Queue::GetManagementObject (void) const
return (ManagementObject*) mgmtObject;
}
-Manageable::status_t Queue::ManagementMethod (uint32_t methodId,
- Args& args)
+Manageable::status_t Queue::ManagementMethod (uint32_t methodId, Args& args, string&)
{
Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD;
@@ -730,8 +1059,8 @@ Manageable::status_t Queue::ManagementMethod (uint32_t methodId,
switch (methodId)
{
- case management::Queue::METHOD_PURGE :
- management::ArgsQueuePurge iargs = dynamic_cast<const management::ArgsQueuePurge&>(args);
+ case _qmf::Queue::METHOD_PURGE :
+ _qmf::ArgsQueuePurge& iargs = (_qmf::ArgsQueuePurge&) args;
purge (iargs.i_request);
status = Manageable::STATUS_OK;
break;
@@ -739,3 +1068,63 @@ Manageable::status_t Queue::ManagementMethod (uint32_t methodId,
return status;
}
+
+void Queue::setPosition(SequenceNumber n) {
+ Mutex::ScopedLock locker(messageLock);
+ sequence = n;
+}
+
+SequenceNumber Queue::getPosition() {
+ return sequence;
+}
+
+int Queue::getEventMode() { return eventMode; }
+
+void Queue::setQueueEventManager(QueueEvents& mgr)
+{
+ eventMgr = &mgr;
+}
+
+void Queue::recoveryComplete(ExchangeRegistry& exchanges)
+{
+ // set the alternate exchange
+ if (!alternateExchangeName.empty()) {
+ try {
+ Exchange::shared_ptr ae = exchanges.get(alternateExchangeName);
+ setAlternateExchange(ae);
+ } catch (const NotFoundException&) {
+ QPID_LOG(warning, "Could not set alternate exchange \"" << alternateExchangeName << "\" on queue \"" << name << "\": exchange does not exist.");
+ }
+ }
+ //process any pending dequeues
+ for_each(pendingDequeues.begin(), pendingDequeues.end(), boost::bind(&Queue::dequeue, this, (TransactionContext*) 0, _1));
+ pendingDequeues.clear();
+}
+
+void Queue::insertSequenceNumbers(const std::string& key)
+{
+ seqNoKey = key;
+ insertSeqNo = !seqNoKey.empty();
+ QPID_LOG(debug, "Inserting sequence numbers as " << key);
+}
+
+void Queue::enqueued(const QueuedMessage& m)
+{
+ if (m.payload) {
+ if (policy.get()) {
+ policy->recoverEnqueued(m.payload);
+ policy->enqueued(m);
+ }
+ mgntEnqStats(m.payload);
+ enqueue ( 0, m.payload, true );
+ } else {
+ QPID_LOG(warning, "Queue informed of enqueued message that has no payload");
+ }
+}
+
+bool Queue::isEnqueued(const QueuedMessage& msg)
+{
+ return !policy.get() || policy->isEnqueued(msg);
+}
+
+QueueListeners& Queue::getListeners() { return listeners; }
diff --git a/cpp/src/qpid/broker/Queue.h b/cpp/src/qpid/broker/Queue.h
index 8b8ba8278f..5b177f1cf2 100644
--- a/cpp/src/qpid/broker/Queue.h
+++ b/cpp/src/qpid/broker/Queue.h
@@ -21,31 +21,38 @@
* under the License.
*
*/
-#include "OwnershipToken.h"
-#include "Consumer.h"
-#include "Message.h"
-#include "PersistableQueue.h"
-#include "QueuePolicy.h"
-#include "QueueBindings.h"
+
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/OwnershipToken.h"
+#include "qpid/broker/Consumer.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/PersistableQueue.h"
+#include "qpid/broker/QueuePolicy.h"
+#include "qpid/broker/QueueBindings.h"
+#include "qpid/broker/QueueListeners.h"
+#include "qpid/broker/RateTracker.h"
#include "qpid/framing/FieldTable.h"
#include "qpid/sys/Monitor.h"
#include "qpid/management/Manageable.h"
-#include "qpid/management/Queue.h"
+#include "qmf/org/apache/qpid/broker/Queue.h"
#include "qpid/framing/amqp_types.h"
-#include <vector>
-#include <memory>
-#include <deque>
-
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/intrusive_ptr.hpp>
+#include <list>
+#include <vector>
+#include <memory>
+#include <deque>
+#include <algorithm>
+
namespace qpid {
namespace broker {
class Broker;
class MessageStore;
+ class QueueEvents;
class QueueRegistry;
class TransactionContext;
class Exchange;
@@ -60,8 +67,10 @@ namespace qpid {
*/
class Queue : public boost::enable_shared_from_this<Queue>,
public PersistableQueue, public management::Manageable {
- typedef qpid::InlineVector<Consumer*, 5> Listeners;
+
typedef std::deque<QueuedMessage> Messages;
+ typedef std::map<string,boost::intrusive_ptr<Message> > LVQ;
+ enum ConsumeCode {NO_MESSAGES=0, CANT_CONSUME=1, CONSUMED=2};
const string name;
const bool autodelete;
@@ -70,10 +79,16 @@ namespace qpid {
uint32_t consumerCount;
OwnershipToken* exclusive;
bool noLocal;
+ bool lastValueQueue;
+ bool lastValueQueueNoBrowse;
+ bool persistLastNode;
+ bool inLastNodeFailure;
std::string traceId;
std::vector<std::string> traceExclude;
- Listeners listeners;
+ QueueListeners listeners;
Messages messages;
+ Messages pendingDequeues;//used to avoid dequeuing during recovery
+ LVQ lvq;
mutable qpid::sys::Mutex consumerLock;
mutable qpid::sys::Mutex messageLock;
mutable qpid::sys::Mutex ownershipLock;
@@ -82,25 +97,59 @@ namespace qpid {
std::auto_ptr<QueuePolicy> policy;
bool policyExceeded;
QueueBindings bindings;
+ std::string alternateExchangeName;
boost::shared_ptr<Exchange> alternateExchange;
framing::SequenceNumber sequence;
- management::Queue* mgmtObject;
-
- void push(boost::intrusive_ptr<Message>& msg);
+ qmf::org::apache::qpid::broker::Queue* mgmtObject;
+ RateTracker dequeueTracker;
+ int eventMode;
+ QueueEvents* eventMgr;
+ bool insertSeqNo;
+ std::string seqNoKey;
+ Broker* broker;
+
+ void push(boost::intrusive_ptr<Message>& msg, bool isRecovery=false);
void setPolicy(std::auto_ptr<QueuePolicy> policy);
- bool seek(QueuedMessage& msg, Consumer& position);
- bool getNextMessage(QueuedMessage& msg, Consumer& c);
- bool consumeNextMessage(QueuedMessage& msg, Consumer& c);
- bool browseNextMessage(QueuedMessage& msg, Consumer& c);
+ bool seek(QueuedMessage& msg, Consumer::shared_ptr position);
+ bool getNextMessage(QueuedMessage& msg, Consumer::shared_ptr c);
+ ConsumeCode consumeNextMessage(QueuedMessage& msg, Consumer::shared_ptr c);
+ bool browseNextMessage(QueuedMessage& msg, Consumer::shared_ptr c);
+ void notifyListener();
- void notify();
- void removeListener(Consumer&);
- void addListener(Consumer&);
+ void removeListener(Consumer::shared_ptr);
bool isExcluded(boost::intrusive_ptr<Message>& msg);
- void dequeued(boost::intrusive_ptr<Message>& msg);
+ void dequeued(const QueuedMessage& msg);
void popAndDequeue();
+ QueuedMessage getFront();
+ QueuedMessage& checkLvqReplace(QueuedMessage& msg);
+ void clearLVQIndex(const QueuedMessage& msg);
+
+ inline void mgntEnqStats(const boost::intrusive_ptr<Message>& msg)
+ {
+ if (mgmtObject != 0) {
+ mgmtObject->inc_msgTotalEnqueues ();
+ mgmtObject->inc_byteTotalEnqueues (msg->contentSize ());
+ if (msg->isPersistent ()) {
+ mgmtObject->inc_msgPersistEnqueues ();
+ mgmtObject->inc_bytePersistEnqueues (msg->contentSize ());
+ }
+ }
+ }
+ inline void mgntDeqStats(const boost::intrusive_ptr<Message>& msg)
+ {
+ if (mgmtObject != 0){
+ mgmtObject->inc_msgTotalDequeues ();
+ mgmtObject->inc_byteTotalDequeues (msg->contentSize());
+ if (msg->isPersistent ()){
+ mgmtObject->inc_msgPersistDequeues ();
+ mgmtObject->inc_bytePersistDequeues (msg->contentSize());
+ }
+ }
+ }
+
+ Messages::iterator findAt(framing::SequenceNumber pos);
public:
@@ -109,58 +158,73 @@ namespace qpid {
typedef std::vector<shared_ptr> vector;
- Queue(const string& name, bool autodelete = false,
- MessageStore* const store = 0,
- const OwnershipToken* const owner = 0,
- management::Manageable* parent = 0);
- ~Queue();
+ QPID_BROKER_EXTERN Queue(const string& name,
+ bool autodelete = false,
+ MessageStore* const store = 0,
+ const OwnershipToken* const owner = 0,
+ management::Manageable* parent = 0,
+ Broker* broker = 0);
+ QPID_BROKER_EXTERN ~Queue();
- bool dispatch(Consumer&);
+ QPID_BROKER_EXTERN bool dispatch(Consumer::shared_ptr);
/**
* Check whether there would be a message available for
* dispatch to this consumer. If not, the consumer will be
* notified of events that may have changed this
* situation.
*/
- bool checkForMessages(Consumer&);
+ bool checkForMessages(Consumer::shared_ptr);
void create(const qpid::framing::FieldTable& settings);
- void configure(const qpid::framing::FieldTable& settings);
+
+ // "recovering" means we are doing a MessageStore recovery.
+ QPID_BROKER_EXTERN void configure(const qpid::framing::FieldTable& settings,
+ bool recovering = false);
void destroy();
- void bound(const string& exchange, const string& key, const qpid::framing::FieldTable& args);
- void unbind(ExchangeRegistry& exchanges, Queue::shared_ptr shared_ref);
+ QPID_BROKER_EXTERN void bound(const string& exchange,
+ const string& key,
+ const qpid::framing::FieldTable& args);
+ QPID_BROKER_EXTERN void unbind(ExchangeRegistry& exchanges,
+ Queue::shared_ptr shared_ref);
- bool acquire(const QueuedMessage& msg);
+ QPID_BROKER_EXTERN bool acquire(const QueuedMessage& msg);
+ QPID_BROKER_EXTERN bool acquireMessageAt(const qpid::framing::SequenceNumber& position, QueuedMessage& message);
/**
* Delivers a message to the queue. Will record it as
* enqueued if persistent then process it.
*/
- void deliver(boost::intrusive_ptr<Message>& msg);
+ QPID_BROKER_EXTERN void deliver(boost::intrusive_ptr<Message>& msg);
/**
* Dispatches the messages immediately to a consumer if
* one is available or stores it for later if not.
*/
- void process(boost::intrusive_ptr<Message>& msg);
+ QPID_BROKER_EXTERN void process(boost::intrusive_ptr<Message>& msg);
/**
* Returns a message to the in-memory queue (due to lack
* of acknowledegement from a receiver). If a consumer is
* available it will be dispatched immediately, else it
* will be returned to the front of the queue.
*/
- void requeue(const QueuedMessage& msg);
+ QPID_BROKER_EXTERN void requeue(const QueuedMessage& msg);
/**
* Used during recovery to add stored messages back to the queue
*/
- void recover(boost::intrusive_ptr<Message>& msg);
+ QPID_BROKER_EXTERN void recover(boost::intrusive_ptr<Message>& msg);
- void consume(Consumer& c, bool exclusive = false);
- void cancel(Consumer& c);
+ QPID_BROKER_EXTERN void consume(Consumer::shared_ptr c,
+ bool exclusive = false);
+ QPID_BROKER_EXTERN void cancel(Consumer::shared_ptr c);
uint32_t purge(const uint32_t purge_request = 0); //defaults to all messages
+ QPID_BROKER_EXTERN void purgeExpired();
- uint32_t getMessageCount() const;
- uint32_t getConsumerCount() const;
+ //move qty # of messages to destination Queue destq
+ uint32_t move(const Queue::shared_ptr destq, uint32_t qty);
+
+ QPID_BROKER_EXTERN uint32_t getMessageCount() const;
+ QPID_BROKER_EXTERN uint32_t getEnqueueCompleteMessageCount() const;
+ QPID_BROKER_EXTERN uint32_t getConsumerCount() const;
inline const string& getName() const { return name; }
bool isExclusiveOwner(const OwnershipToken* const o) const;
void releaseExclusiveOwnership();
@@ -171,17 +235,50 @@ namespace qpid {
inline const framing::FieldTable& getSettings() const { return settings; }
inline bool isAutoDelete() const { return autodelete; }
bool canAutoDelete() const;
+ const QueueBindings& getBindings() const { return bindings; }
+
+ /**
+ * used to take messages from in memory and flush down to disk.
+ */
+ QPID_BROKER_EXTERN void setLastNodeFailure();
+ QPID_BROKER_EXTERN void clearLastNodeFailure();
- bool enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg);
+ bool enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg, bool suppressPolicyCheck = false);
+ void enqueueAborted(boost::intrusive_ptr<Message> msg);
/**
* dequeue from store (only done once messages is acknowledged)
*/
- bool dequeue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg);
+ QPID_BROKER_EXTERN bool dequeue(TransactionContext* ctxt, const QueuedMessage &msg);
+ /**
+ * Inform the queue that a previous transactional dequeue
+ * committed.
+ */
+ void dequeueCommitted(const QueuedMessage& msg);
+
+ /**
+ * Inform queue of messages that were enqueued, have since
+ * been acquired but not yet accepted or released (and
+ * thus are still logically on the queue) - used in
+ * clustered broker.
+ */
+ void enqueued(const QueuedMessage& msg);
/**
+ * Test whether the specified message (identified by its
+ * sequence/position), is still enqueued (note this
+ * doesn't mean it is available for delivery as it may
+ * have been delievered to a subscriber who has not yet
+ * accepted it).
+ */
+ bool isEnqueued(const QueuedMessage& msg);
+
+ /**
* Gets the next available message
*/
- QueuedMessage get();
+ QPID_BROKER_EXTERN QueuedMessage get();
+
+ /** Get the message at position pos */
+ QPID_BROKER_EXTERN QueuedMessage find(framing::SequenceNumber pos) const;
const QueuePolicy* getPolicy();
@@ -195,7 +292,8 @@ namespace qpid {
void encode(framing::Buffer& buffer) const;
uint32_t encodedSize() const;
- static Queue::shared_ptr decode(QueueRegistry& queues, framing::Buffer& buffer);
+ // "recovering" means we are doing a MessageStore recovery.
+ static Queue::shared_ptr decode(QueueRegistry& queues, framing::Buffer& buffer, bool recovering = false );
static void tryAutoDelete(Broker& broker, Queue::shared_ptr);
virtual void setExternalQueueStore(ExternalQueueStore* inst);
@@ -203,7 +301,51 @@ namespace qpid {
// Manageable entry points
management::ManagementObject* GetManagementObject (void) const;
management::Manageable::status_t
- ManagementMethod (uint32_t methodId, management::Args& args);
+ ManagementMethod (uint32_t methodId, management::Args& args, std::string& text);
+
+ /** Apply f to each Message on the queue. */
+ template <class F> void eachMessage(F f) {
+ sys::Mutex::ScopedLock l(messageLock);
+ if (lastValueQueue) {
+ for (Messages::iterator i = messages.begin(); i != messages.end(); ++i) {
+ f(checkLvqReplace(*i));
+ }
+ } else {
+ std::for_each(messages.begin(), messages.end(), f);
+ }
+ }
+
+ /** Apply f to each QueueBinding on the queue */
+ template <class F> void eachBinding(F f) {
+ bindings.eachBinding(f);
+ }
+
+ void popMsg(QueuedMessage& qmsg);
+
+ /** Set the position sequence number for the next message on the queue.
+ * Must be >= the current sequence number.
+ * Used by cluster to replicate queues.
+ */
+ QPID_BROKER_EXTERN void setPosition(framing::SequenceNumber pos);
+ /** return current position sequence number for the next message on the queue.
+ */
+ QPID_BROKER_EXTERN framing::SequenceNumber getPosition();
+ int getEventMode();
+ void setQueueEventManager(QueueEvents&);
+ QPID_BROKER_EXTERN void insertSequenceNumbers(const std::string& key);
+ /**
+ * Notify queue that recovery has completed.
+ */
+ void recoveryComplete(ExchangeRegistry& exchanges);
+
+ // For cluster update
+ QueueListeners& getListeners();
+
+ /**
+ * Reserve space in policy for an enqueued message that
+ * has been recovered in the prepared state (dtx only)
+ */
+ void recoverPrepared(boost::intrusive_ptr<Message>& msg);
};
}
}
diff --git a/cpp/src/qpid/broker/QueueBindings.cpp b/cpp/src/qpid/broker/QueueBindings.cpp
index 95e529f47e..3f43a8ef68 100644
--- a/cpp/src/qpid/broker/QueueBindings.cpp
+++ b/cpp/src/qpid/broker/QueueBindings.cpp
@@ -18,8 +18,8 @@
* under the License.
*
*/
-#include "QueueBindings.h"
-#include "ExchangeRegistry.h"
+#include "qpid/broker/QueueBindings.h"
+#include "qpid/broker/ExchangeRegistry.h"
#include "qpid/framing/reply_exceptions.h"
using qpid::framing::FieldTable;
@@ -29,7 +29,7 @@ using namespace qpid::broker;
void QueueBindings::add(const string& exchange, const string& key, const FieldTable& args)
{
- bindings.push_back(new Binding(exchange, key, args));
+ bindings.push_back(QueueBinding(exchange, key, args));
}
void QueueBindings::unbind(ExchangeRegistry& exchanges, Queue::shared_ptr queue)
@@ -37,11 +37,10 @@ void QueueBindings::unbind(ExchangeRegistry& exchanges, Queue::shared_ptr queue)
for (Bindings::iterator i = bindings.begin(); i != bindings.end(); i++) {
try {
exchanges.get(i->exchange)->unbind(queue, i->key, &(i->args));
- } catch (const NotFoundException&) {
- }
+ } catch (const NotFoundException&) {}
}
}
-QueueBindings::Binding::Binding(const string& _exchange, const string& _key, const FieldTable& _args)
+QueueBinding::QueueBinding(const string& _exchange, const string& _key, const FieldTable& _args)
: exchange(_exchange), key(_key), args(_args)
{}
diff --git a/cpp/src/qpid/broker/QueueBindings.h b/cpp/src/qpid/broker/QueueBindings.h
index b9b0f7c15c..1b90ba5540 100644
--- a/cpp/src/qpid/broker/QueueBindings.h
+++ b/cpp/src/qpid/broker/QueueBindings.h
@@ -24,32 +24,38 @@
#include "qpid/framing/FieldTable.h"
#include <boost/ptr_container/ptr_list.hpp>
#include <boost/shared_ptr.hpp>
+#include <algorithm>
namespace qpid {
namespace broker {
class ExchangeRegistry;
class Queue;
+
+struct QueueBinding{
+ std::string exchange;
+ std::string key;
+ qpid::framing::FieldTable args;
+ QueueBinding(const std::string& exchange, const std::string& key, const qpid::framing::FieldTable& args);
+};
+
class QueueBindings
{
- struct Binding{
- const std::string exchange;
- const std::string key;
- const qpid::framing::FieldTable args;
- Binding(const std::string& exchange, const std::string& key, const qpid::framing::FieldTable& args);
- };
-
- typedef boost::ptr_list<Binding> Bindings;
- Bindings bindings;
+ public:
-public:
+ /** Apply f to each QueueBinding. */
+ template <class F> void eachBinding(F f) const { std::for_each(bindings.begin(), bindings.end(), f); }
+
void add(const std::string& exchange, const std::string& key, const qpid::framing::FieldTable& args);
void unbind(ExchangeRegistry& exchanges, boost::shared_ptr<Queue> queue);
+
+ private:
+ typedef std::vector<QueueBinding> Bindings;
+ Bindings bindings;
};
-}
-}
+}} // namespace qpid::broker
#endif
diff --git a/cpp/src/qpid/broker/QueueCleaner.cpp b/cpp/src/qpid/broker/QueueCleaner.cpp
new file mode 100644
index 0000000000..c80fe89035
--- /dev/null
+++ b/cpp/src/qpid/broker/QueueCleaner.cpp
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/broker/QueueCleaner.h"
+
+#include "qpid/broker/Broker.h"
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace broker {
+
+QueueCleaner::QueueCleaner(QueueRegistry& q, sys::Timer& t) : queues(q), timer(t) {}
+
+QueueCleaner::~QueueCleaner()
+{
+ if (task) task->cancel();
+}
+
+void QueueCleaner::start(qpid::sys::Duration p)
+{
+ task = new Task(*this, p);
+ timer.add(task);
+}
+
+QueueCleaner::Task::Task(QueueCleaner& p, qpid::sys::Duration d) : sys::TimerTask(d), parent(p) {}
+
+void QueueCleaner::Task::fire()
+{
+ parent.fired();
+}
+
+void QueueCleaner::fired()
+{
+ queues.eachQueue(boost::bind(&Queue::purgeExpired, _1));
+ task->setupNextFire();
+ timer.add(task);
+}
+
+
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/QueueCleaner.h b/cpp/src/qpid/broker/QueueCleaner.h
new file mode 100644
index 0000000000..11c2d180ac
--- /dev/null
+++ b/cpp/src/qpid/broker/QueueCleaner.h
@@ -0,0 +1,59 @@
+#ifndef QPID_BROKER_QUEUECLEANER_H
+#define QPID_BROKER_QUEUECLEANER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/sys/Timer.h"
+
+namespace qpid {
+namespace broker {
+
+class QueueRegistry;
+/**
+ * TimerTask to purge expired messages from queues
+ */
+class QueueCleaner
+{
+ public:
+ QPID_BROKER_EXTERN QueueCleaner(QueueRegistry& queues, sys::Timer& timer);
+ QPID_BROKER_EXTERN ~QueueCleaner();
+ QPID_BROKER_EXTERN void start(qpid::sys::Duration period);
+ private:
+ class Task : public sys::TimerTask
+ {
+ public:
+ Task(QueueCleaner& parent, qpid::sys::Duration duration);
+ void fire();
+ private:
+ QueueCleaner& parent;
+ };
+
+ boost::intrusive_ptr<sys::TimerTask> task;
+ QueueRegistry& queues;
+ sys::Timer& timer;
+
+ void fired();
+};
+}} // namespace qpid::broker
+
+#endif /*!QPID_BROKER_QUEUECLEANER_H*/
diff --git a/cpp/src/qpid/broker/QueueEvents.cpp b/cpp/src/qpid/broker/QueueEvents.cpp
new file mode 100644
index 0000000000..bba054b0b8
--- /dev/null
+++ b/cpp/src/qpid/broker/QueueEvents.cpp
@@ -0,0 +1,122 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/broker/QueueEvents.h"
+#include "qpid/Exception.h"
+#include "qpid/log/Statement.h"
+
+namespace qpid {
+namespace broker {
+
+QueueEvents::QueueEvents(const boost::shared_ptr<sys::Poller>& poller, bool isSync) :
+ eventQueue(boost::bind(&QueueEvents::handle, this, _1), poller), enabled(true), sync(isSync)
+{
+ if (!sync) eventQueue.start();
+}
+
+QueueEvents::~QueueEvents()
+{
+ if (!sync) eventQueue.stop();
+}
+
+void QueueEvents::enqueued(const QueuedMessage& m)
+{
+ if (enabled) {
+ Event enq(ENQUEUE, m);
+ if (sync) {
+ for (Listeners::iterator j = listeners.begin(); j != listeners.end(); j++)
+ j->second(enq);
+ } else {
+ eventQueue.push(enq);
+ }
+ }
+}
+
+void QueueEvents::dequeued(const QueuedMessage& m)
+{
+ if (enabled) {
+ Event deq(DEQUEUE, m);
+ if (sync) {
+ for (Listeners::iterator j = listeners.begin(); j != listeners.end(); j++)
+ j->second(deq);
+ } else {
+ eventQueue.push(Event(DEQUEUE, m));
+ }
+ }
+}
+
+void QueueEvents::registerListener(const std::string& id, const EventListener& listener)
+{
+ qpid::sys::Mutex::ScopedLock l(lock);
+ if (listeners.find(id) == listeners.end()) {
+ listeners[id] = listener;
+ } else {
+ throw Exception(QPID_MSG("Event listener already registered for '" << id << "'"));
+ }
+}
+
+void QueueEvents::unregisterListener(const std::string& id)
+{
+ qpid::sys::Mutex::ScopedLock l(lock);
+ if (listeners.find(id) == listeners.end()) {
+ throw Exception(QPID_MSG("No event listener registered for '" << id << "'"));
+ } else {
+ listeners.erase(id);
+ }
+}
+
+QueueEvents::EventQueue::Batch::const_iterator
+QueueEvents::handle(const EventQueue::Batch& events) {
+ qpid::sys::Mutex::ScopedLock l(lock);
+ for (EventQueue::Batch::const_iterator i = events.begin(); i != events.end(); ++i) {
+ for (Listeners::iterator j = listeners.begin(); j != listeners.end(); j++) {
+ j->second(*i);
+ }
+ }
+ return events.end();
+}
+
+void QueueEvents::shutdown()
+{
+ if (!sync && !eventQueue.empty() && !listeners.empty()) eventQueue.shutdown();
+}
+
+void QueueEvents::enable()
+{
+ enabled = true;
+ QPID_LOG(debug, "Queue events enabled");
+}
+
+void QueueEvents::disable()
+{
+ enabled = false;
+ QPID_LOG(debug, "Queue events disabled");
+}
+
+bool QueueEvents::isSync()
+{
+ return sync;
+}
+
+
+QueueEvents::Event::Event(EventType t, const QueuedMessage& m) : type(t), msg(m) {}
+
+
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/QueueEvents.h b/cpp/src/qpid/broker/QueueEvents.h
new file mode 100644
index 0000000000..c42752133e
--- /dev/null
+++ b/cpp/src/qpid/broker/QueueEvents.h
@@ -0,0 +1,84 @@
+#ifndef QPID_BROKER_QUEUEEVENTS_H
+#define QPID_BROKER_QUEUEEVENTS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/QueuedMessage.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/PollableQueue.h"
+#include <map>
+#include <string>
+#include <boost/function.hpp>
+
+namespace qpid {
+namespace broker {
+
+/**
+ * Event manager for queue events. Allows queues to indicate when
+ * events have occured; allows listeners to register for notification
+ * of this. The notification happens asynchronously, in a separate
+ * thread.
+ */
+class QueueEvents
+{
+ public:
+ enum EventType {ENQUEUE, DEQUEUE};
+
+ struct Event
+ {
+ EventType type;
+ QueuedMessage msg;
+
+ QPID_BROKER_EXTERN Event(EventType, const QueuedMessage&);
+ };
+
+ typedef boost::function<void (Event)> EventListener;
+
+ QPID_BROKER_EXTERN QueueEvents(const boost::shared_ptr<sys::Poller>& poller, bool isSync = false);
+ QPID_BROKER_EXTERN ~QueueEvents();
+ QPID_BROKER_EXTERN void enqueued(const QueuedMessage&);
+ QPID_BROKER_EXTERN void dequeued(const QueuedMessage&);
+ QPID_BROKER_EXTERN void registerListener(const std::string& id,
+ const EventListener&);
+ QPID_BROKER_EXTERN void unregisterListener(const std::string& id);
+ void enable();
+ void disable();
+ //process all outstanding events
+ QPID_BROKER_EXTERN void shutdown();
+ QPID_BROKER_EXTERN bool isSync();
+ private:
+ typedef qpid::sys::PollableQueue<Event> EventQueue;
+ typedef std::map<std::string, EventListener> Listeners;
+
+ EventQueue eventQueue;
+ Listeners listeners;
+ volatile bool enabled;
+ qpid::sys::Mutex lock;//protect listeners from concurrent access
+ bool sync;
+
+ EventQueue::Batch::const_iterator handle(const EventQueue::Batch& e);
+
+};
+}} // namespace qpid::broker
+
+#endif /*!QPID_BROKER_QUEUEEVENTS_H*/
diff --git a/cpp/src/qpid/broker/QueueListeners.cpp b/cpp/src/qpid/broker/QueueListeners.cpp
new file mode 100644
index 0000000000..951de2184a
--- /dev/null
+++ b/cpp/src/qpid/broker/QueueListeners.cpp
@@ -0,0 +1,81 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/broker/QueueListeners.h"
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace broker {
+
+void QueueListeners::addListener(Consumer::shared_ptr c)
+{
+ if (c->preAcquires()) {
+ add(consumers, c);
+ } else {
+ add(browsers, c);
+ }
+}
+
+void QueueListeners::removeListener(Consumer::shared_ptr c)
+{
+ if (c->preAcquires()) {
+ remove(consumers, c);
+ } else {
+ remove(browsers, c);
+ }
+}
+
+void QueueListeners::populate(NotificationSet& set)
+{
+ if (consumers.size()) {
+ set.consumer = consumers.front();
+ consumers.erase(consumers.begin());
+ } else {
+ // Don't swap the vectors, hang on to the memory allocated.
+ set.browsers = browsers;
+ browsers.clear();
+ }
+}
+
+void QueueListeners::add(Listeners& listeners, Consumer::shared_ptr c)
+{
+ Listeners::iterator i = std::find(listeners.begin(), listeners.end(), c);
+ if (i == listeners.end()) listeners.push_back(c);
+}
+
+void QueueListeners::remove(Listeners& listeners, Consumer::shared_ptr c)
+{
+ Listeners::iterator i = std::find(listeners.begin(), listeners.end(), c);
+ if (i != listeners.end()) listeners.erase(i);
+}
+
+void QueueListeners::NotificationSet::notify()
+{
+ if (consumer) consumer->notify();
+ else std::for_each(browsers.begin(), browsers.end(), boost::mem_fn(&Consumer::notify));
+}
+
+bool QueueListeners::contains(Consumer::shared_ptr c) const {
+ return
+ std::find(browsers.begin(), browsers.end(), c) != browsers.end() ||
+ std::find(consumers.begin(), consumers.end(), c) != consumers.end();
+}
+
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/QueueListeners.h b/cpp/src/qpid/broker/QueueListeners.h
new file mode 100644
index 0000000000..51ef58eb06
--- /dev/null
+++ b/cpp/src/qpid/broker/QueueListeners.h
@@ -0,0 +1,75 @@
+#ifndef QPID_BROKER_QUEUELISTENERS_H
+#define QPID_BROKER_QUEUELISTENERS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/broker/Consumer.h"
+#include <vector>
+
+namespace qpid {
+namespace broker {
+
+/**
+ * Track and notify components that wish to be notified of messages
+ * that become available on a queue.
+ *
+ * None of the methods defined here are protected by locking. However
+ * the populate method allows a 'snapshot' to be taken of the
+ * listeners to be notified. NotificationSet::notify() may then be
+ * called outside of any lock that protects the QueueListeners
+ * instance from concurrent access.
+ */
+class QueueListeners
+{
+ public:
+ typedef std::vector<Consumer::shared_ptr> Listeners;
+
+ class NotificationSet
+ {
+ public:
+ void notify();
+ private:
+ Listeners browsers;
+ Consumer::shared_ptr consumer;
+ friend class QueueListeners;
+ };
+
+ void addListener(Consumer::shared_ptr);
+ void removeListener(Consumer::shared_ptr);
+ void populate(NotificationSet&);
+ bool contains(Consumer::shared_ptr c) const;
+
+ template <class F> void eachListener(F f) {
+ std::for_each(browsers.begin(), browsers.end(), f);
+ std::for_each(consumers.begin(), consumers.end(), f);
+ }
+
+ private:
+ Listeners consumers;
+ Listeners browsers;
+
+ void add(Listeners&, Consumer::shared_ptr);
+ void remove(Listeners&, Consumer::shared_ptr);
+
+};
+}} // namespace qpid::broker
+
+#endif /*!QPID_BROKER_QUEUELISTENERS_H*/
diff --git a/cpp/src/qpid/broker/QueuePolicy.cpp b/cpp/src/qpid/broker/QueuePolicy.cpp
index 08838aac79..a8aa674c53 100644
--- a/cpp/src/qpid/broker/QueuePolicy.cpp
+++ b/cpp/src/qpid/broker/QueuePolicy.cpp
@@ -18,40 +18,99 @@
* under the License.
*
*/
-#include "QueuePolicy.h"
+#include "qpid/broker/QueuePolicy.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/Exception.h"
#include "qpid/framing/FieldValue.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/log/Statement.h"
using namespace qpid::broker;
using namespace qpid::framing;
-QueuePolicy::QueuePolicy(uint32_t _maxCount, uint64_t _maxSize) :
- maxCount(_maxCount), maxSize(_maxSize), count(0), size(0) {}
-
-QueuePolicy::QueuePolicy(const FieldTable& settings) :
- maxCount(getInt(settings, maxCountKey, 0)),
- maxSize(getInt(settings, maxSizeKey, defaultMaxSize)), count(0), size(0) {}
+QueuePolicy::QueuePolicy(const std::string& _name, uint32_t _maxCount, uint64_t _maxSize, const std::string& _type) :
+ maxCount(_maxCount), maxSize(_maxSize), type(_type), count(0), size(0), policyExceeded(false), name(_name) {}
void QueuePolicy::enqueued(uint64_t _size)
{
- if (maxCount) count++;
+ if (maxCount) ++count;
if (maxSize) size += _size;
}
void QueuePolicy::dequeued(uint64_t _size)
{
- if (maxCount) count--;
- if (maxSize) size -= _size;
+ if (maxCount) {
+ if (count > 0) {
+ --count;
+ } else {
+ throw Exception(QPID_MSG("Attempted count underflow on dequeue(" << _size << "): " << *this));
+ }
+ }
+ if (maxSize) {
+ if (_size > size) {
+ throw Exception(QPID_MSG("Attempted size underflow on dequeue(" << _size << "): " << *this));
+ } else {
+ size -= _size;
+ }
+ }
+}
+
+bool QueuePolicy::checkLimit(boost::intrusive_ptr<Message> m)
+{
+ bool sizeExceeded = maxSize && (size + m->contentSize()) > maxSize;
+ bool countExceeded = maxCount && (count + 1) > maxCount;
+ bool exceeded = sizeExceeded || countExceeded;
+ if (exceeded) {
+ if (!policyExceeded) {
+ policyExceeded = true;
+ if (sizeExceeded) QPID_LOG(info, "Queue cumulative message size exceeded policy for " << name);
+ if (countExceeded) QPID_LOG(info, "Queue message count exceeded policy for " << name);
+ }
+ } else {
+ if (policyExceeded) {
+ policyExceeded = false;
+ QPID_LOG(info, "Queue cumulative message size and message count within policy for " << name);
+ }
+ }
+ return !exceeded;
+}
+
+void QueuePolicy::tryEnqueue(boost::intrusive_ptr<Message> m)
+{
+ if (checkLimit(m)) {
+ enqueued(m->contentSize());
+ } else {
+ throw ResourceLimitExceededException(QPID_MSG("Policy exceeded on " << name << ", policy: " << *this));
+ }
+}
+
+void QueuePolicy::recoverEnqueued(boost::intrusive_ptr<Message> m)
+{
+ enqueued(m->contentSize());
}
-bool QueuePolicy::limitExceeded()
+void QueuePolicy::enqueueAborted(boost::intrusive_ptr<Message> m)
{
- return (maxSize && size > maxSize) || (maxCount && count > maxCount);
+ dequeued(m->contentSize());
+}
+
+void QueuePolicy::enqueued(const QueuedMessage&) {}
+
+void QueuePolicy::dequeued(const QueuedMessage& m)
+{
+ dequeued(m.payload->contentSize());
+}
+
+bool QueuePolicy::isEnqueued(const QueuedMessage&)
+{
+ return true;
}
void QueuePolicy::update(FieldTable& settings)
{
if (maxCount) settings.setInt(maxCountKey, maxCount);
- if (maxSize) settings.setInt(maxSizeKey, maxSize);
+ if (maxSize) settings.setInt(maxSizeKey, maxSize);
+ settings.setString(typeKey, type);
}
@@ -62,27 +121,195 @@ int QueuePolicy::getInt(const FieldTable& settings, const std::string& key, int
else return defaultValue;
}
+std::string QueuePolicy::getType(const FieldTable& settings)
+{
+ FieldTable::ValuePtr v = settings.get(typeKey);
+ if (v && v->convertsTo<std::string>()) {
+ std::string t = v->get<std::string>();
+ std::transform(t.begin(), t.end(), t.begin(), tolower);
+ if (t == REJECT || t == FLOW_TO_DISK || t == RING || t == RING_STRICT) return t;
+ }
+ return REJECT;
+}
+
void QueuePolicy::setDefaultMaxSize(uint64_t s)
{
defaultMaxSize = s;
}
+void QueuePolicy::getPendingDequeues(Messages&) {}
+
+
+
+
+void QueuePolicy::encode(Buffer& buffer) const
+{
+ buffer.putLong(maxCount);
+ buffer.putLongLong(maxSize);
+ buffer.putLong(count);
+ buffer.putLongLong(size);
+}
+
+void QueuePolicy::decode ( Buffer& buffer )
+{
+ maxCount = buffer.getLong();
+ maxSize = buffer.getLongLong();
+ count = buffer.getLong();
+ size = buffer.getLongLong();
+}
+
+
+uint32_t QueuePolicy::encodedSize() const {
+ return sizeof(uint32_t) + // maxCount
+ sizeof(uint64_t) + // maxSize
+ sizeof(uint32_t) + // count
+ sizeof(uint64_t); // size
+}
+
+
+
const std::string QueuePolicy::maxCountKey("qpid.max_count");
const std::string QueuePolicy::maxSizeKey("qpid.max_size");
+const std::string QueuePolicy::typeKey("qpid.policy_type");
+const std::string QueuePolicy::REJECT("reject");
+const std::string QueuePolicy::FLOW_TO_DISK("flow_to_disk");
+const std::string QueuePolicy::RING("ring");
+const std::string QueuePolicy::RING_STRICT("ring_strict");
uint64_t QueuePolicy::defaultMaxSize(0);
+FlowToDiskPolicy::FlowToDiskPolicy(const std::string& _name, uint32_t _maxCount, uint64_t _maxSize) :
+ QueuePolicy(_name, _maxCount, _maxSize, FLOW_TO_DISK) {}
+
+bool FlowToDiskPolicy::checkLimit(boost::intrusive_ptr<Message> m)
+{
+ if (!QueuePolicy::checkLimit(m)) m->requestContentRelease();
+ return true;
+}
+
+RingQueuePolicy::RingQueuePolicy(const std::string& _name,
+ uint32_t _maxCount, uint64_t _maxSize, const std::string& _type) :
+ QueuePolicy(_name, _maxCount, _maxSize, _type), strict(_type == RING_STRICT) {}
+
+bool before(const QueuedMessage& a, const QueuedMessage& b)
+{
+ return a.position < b.position;
+}
+
+void RingQueuePolicy::enqueued(const QueuedMessage& m)
+{
+ //need to insert in correct location based on position
+ queue.insert(lower_bound(queue.begin(), queue.end(), m, before), m);
+}
+
+void RingQueuePolicy::dequeued(const QueuedMessage& m)
+{
+ //find and remove m from queue
+ if (find(m, pendingDequeues, true) || find(m, queue, true)) {
+ //now update count and size
+ QueuePolicy::dequeued(m);
+ }
+}
+
+bool RingQueuePolicy::isEnqueued(const QueuedMessage& m)
+{
+ //for non-strict ring policy, a message can be replaced (and
+ //therefore dequeued) before it is accepted or released by
+ //subscriber; need to detect this
+ return find(m, pendingDequeues, false) || find(m, queue, false);
+}
+
+bool RingQueuePolicy::checkLimit(boost::intrusive_ptr<Message> m)
+{
+ if (QueuePolicy::checkLimit(m)) return true;//if haven't hit limit, ok to accept
+
+ QueuedMessage oldest;
+ if (queue.empty()) {
+ QPID_LOG(debug, "Message too large for ring queue " << name
+ << " [" << *this << "] "
+ << ": message size = " << m->contentSize() << " bytes");
+ return false;
+ }
+ oldest = queue.front();
+ if (oldest.queue->acquire(oldest) || !strict) {
+ queue.pop_front();
+ pendingDequeues.push_back(oldest);
+ QPID_LOG(debug, "Ring policy triggered in " << name
+ << ": removed message " << oldest.position << " to make way for new message");
+ return true;
+ } else {
+ QPID_LOG(debug, "Ring policy could not be triggered in " << name
+ << ": oldest message (seq-no=" << oldest.position << ") has been delivered but not yet acknowledged or requeued");
+ //in strict mode, if oldest message has been delivered (hence
+ //cannot be acquired) but not yet acked, it should not be
+ //removed and the attempted enqueue should fail
+ return false;
+ }
+}
+
+void RingQueuePolicy::getPendingDequeues(Messages& result)
+{
+ result = pendingDequeues;
+}
+
+bool RingQueuePolicy::find(const QueuedMessage& m, Messages& q, bool remove)
+{
+ for (Messages::iterator i = q.begin(); i != q.end(); i++) {
+ if (i->payload == m.payload) {
+ if (remove) q.erase(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(uint32_t maxCount, uint64_t maxSize, const std::string& type)
+{
+ return createQueuePolicy("<unspecified>", maxCount, maxSize, type);
+}
+
+std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(const qpid::framing::FieldTable& settings)
+{
+ return createQueuePolicy("<unspecified>", settings);
+}
+
+std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(const std::string& name, const qpid::framing::FieldTable& settings)
+{
+ uint32_t maxCount = getInt(settings, maxCountKey, 0);
+ uint32_t maxSize = getInt(settings, maxSizeKey, defaultMaxSize);
+ if (maxCount || maxSize) {
+ return createQueuePolicy(name, maxCount, maxSize, getType(settings));
+ } else {
+ return std::auto_ptr<QueuePolicy>();
+ }
+}
+
+std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(const std::string& name,
+ uint32_t maxCount, uint64_t maxSize, const std::string& type)
+{
+ if (type == RING || type == RING_STRICT) {
+ return std::auto_ptr<QueuePolicy>(new RingQueuePolicy(name, maxCount, maxSize, type));
+ } else if (type == FLOW_TO_DISK) {
+ return std::auto_ptr<QueuePolicy>(new FlowToDiskPolicy(name, maxCount, maxSize));
+ } else {
+ return std::auto_ptr<QueuePolicy>(new QueuePolicy(name, maxCount, maxSize, type));
+ }
+
+}
+
namespace qpid {
namespace broker {
std::ostream& operator<<(std::ostream& out, const QueuePolicy& p)
{
if (p.maxSize) out << "size: max=" << p.maxSize << ", current=" << p.size;
- else out << "size unlimited, current=" << p.size;
+ else out << "size: unlimited";
out << "; ";
if (p.maxCount) out << "count: max=" << p.maxCount << ", current=" << p.count;
- else out << "count unlimited, current=" << p.count;
+ else out << "count: unlimited";
+ out << "; type=" << p.type;
return out;
}
}
}
+
diff --git a/cpp/src/qpid/broker/QueuePolicy.h b/cpp/src/qpid/broker/QueuePolicy.h
index 4511a63b64..b2937e94c7 100644
--- a/cpp/src/qpid/broker/QueuePolicy.h
+++ b/cpp/src/qpid/broker/QueuePolicy.h
@@ -21,40 +21,100 @@
#ifndef _QueuePolicy_
#define _QueuePolicy_
+#include <deque>
#include <iostream>
+#include <memory>
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/QueuedMessage.h"
#include "qpid/framing/FieldTable.h"
+#include "qpid/sys/AtomicValue.h"
+#include "qpid/sys/Mutex.h"
namespace qpid {
- namespace broker {
- class QueuePolicy
- {
- static const std::string maxCountKey;
- static const std::string maxSizeKey;
-
- static uint64_t defaultMaxSize;
+namespace broker {
+
+class QueuePolicy
+{
+ static uint64_t defaultMaxSize;
- const uint32_t maxCount;
- const uint64_t maxSize;
- uint32_t count;
- uint64_t size;
+ uint32_t maxCount;
+ uint64_t maxSize;
+ const std::string type;
+ uint32_t count;
+ uint64_t size;
+ bool policyExceeded;
- static int getInt(const qpid::framing::FieldTable& settings, const std::string& key, int defaultValue);
-
- public:
- QueuePolicy(uint32_t maxCount, uint64_t maxSize);
- QueuePolicy(const qpid::framing::FieldTable& settings);
- void enqueued(uint64_t size);
- void dequeued(uint64_t size);
- void update(qpid::framing::FieldTable& settings);
- bool limitExceeded();
- uint32_t getMaxCount() const { return maxCount; }
- uint64_t getMaxSize() const { return maxSize; }
-
- static void setDefaultMaxSize(uint64_t);
- friend std::ostream& operator<<(std::ostream&, const QueuePolicy&);
- };
- }
-}
+ static int getInt(const qpid::framing::FieldTable& settings, const std::string& key, int defaultValue);
+
+ public:
+ typedef std::deque<QueuedMessage> Messages;
+ static QPID_BROKER_EXTERN const std::string maxCountKey;
+ static QPID_BROKER_EXTERN const std::string maxSizeKey;
+ static QPID_BROKER_EXTERN const std::string typeKey;
+ static QPID_BROKER_EXTERN const std::string REJECT;
+ static QPID_BROKER_EXTERN const std::string FLOW_TO_DISK;
+ static QPID_BROKER_EXTERN const std::string RING;
+ static QPID_BROKER_EXTERN const std::string RING_STRICT;
+
+ virtual ~QueuePolicy() {}
+ QPID_BROKER_EXTERN void tryEnqueue(boost::intrusive_ptr<Message> msg);
+ QPID_BROKER_EXTERN void recoverEnqueued(boost::intrusive_ptr<Message> msg);
+ QPID_BROKER_EXTERN void enqueueAborted(boost::intrusive_ptr<Message> msg);
+ virtual void enqueued(const QueuedMessage&);
+ virtual void dequeued(const QueuedMessage&);
+ virtual bool isEnqueued(const QueuedMessage&);
+ QPID_BROKER_EXTERN void update(qpid::framing::FieldTable& settings);
+ uint32_t getMaxCount() const { return maxCount; }
+ uint64_t getMaxSize() const { return maxSize; }
+ void encode(framing::Buffer& buffer) const;
+ void decode ( framing::Buffer& buffer );
+ uint32_t encodedSize() const;
+ virtual void getPendingDequeues(Messages& result);
+
+ static QPID_BROKER_EXTERN std::auto_ptr<QueuePolicy> createQueuePolicy(const std::string& name, const qpid::framing::FieldTable& settings);
+ static QPID_BROKER_EXTERN std::auto_ptr<QueuePolicy> createQueuePolicy(const std::string& name, uint32_t maxCount, uint64_t maxSize, const std::string& type = REJECT);
+ static QPID_BROKER_EXTERN std::auto_ptr<QueuePolicy> createQueuePolicy(const qpid::framing::FieldTable& settings);
+ static QPID_BROKER_EXTERN std::auto_ptr<QueuePolicy> createQueuePolicy(uint32_t maxCount, uint64_t maxSize, const std::string& type = REJECT);
+ static std::string getType(const qpid::framing::FieldTable& settings);
+ static void setDefaultMaxSize(uint64_t);
+ friend QPID_BROKER_EXTERN std::ostream& operator<<(std::ostream&,
+ const QueuePolicy&);
+ protected:
+ const std::string name;
+
+ QueuePolicy(const std::string& name, uint32_t maxCount, uint64_t maxSize, const std::string& type = REJECT);
+
+ virtual bool checkLimit(boost::intrusive_ptr<Message> msg);
+ void enqueued(uint64_t size);
+ void dequeued(uint64_t size);
+};
+
+
+class FlowToDiskPolicy : public QueuePolicy
+{
+ public:
+ FlowToDiskPolicy(const std::string& name, uint32_t maxCount, uint64_t maxSize);
+ bool checkLimit(boost::intrusive_ptr<Message> msg);
+};
+
+class RingQueuePolicy : public QueuePolicy
+{
+ public:
+ RingQueuePolicy(const std::string& name, uint32_t maxCount, uint64_t maxSize, const std::string& type = RING);
+ void enqueued(const QueuedMessage&);
+ void dequeued(const QueuedMessage&);
+ bool isEnqueued(const QueuedMessage&);
+ bool checkLimit(boost::intrusive_ptr<Message> msg);
+ void getPendingDequeues(Messages& result);
+ private:
+ Messages pendingDequeues;
+ Messages queue;
+ const bool strict;
+
+ bool find(const QueuedMessage&, Messages&, bool remove);
+};
+
+}}
#endif
diff --git a/cpp/src/qpid/broker/QueueRegistry.cpp b/cpp/src/qpid/broker/QueueRegistry.cpp
index 61bdb0ffde..4b1fa62709 100644
--- a/cpp/src/qpid/broker/QueueRegistry.cpp
+++ b/cpp/src/qpid/broker/QueueRegistry.cpp
@@ -18,7 +18,8 @@
* under the License.
*
*/
-#include "QueueRegistry.h"
+#include "qpid/broker/QueueRegistry.h"
+#include "qpid/broker/QueueEvents.h"
#include "qpid/log/Statement.h"
#include <sstream>
#include <assert.h>
@@ -26,8 +27,8 @@
using namespace qpid::broker;
using namespace qpid::sys;
-QueueRegistry::QueueRegistry() :
- counter(1), store(0), parent(0) {}
+QueueRegistry::QueueRegistry(Broker* b) :
+ counter(1), store(0), events(0), parent(0), lastNode(false), broker(b) {}
QueueRegistry::~QueueRegistry(){}
@@ -41,8 +42,10 @@ QueueRegistry::declare(const string& declareName, bool durable,
QueueMap::iterator i = queues.find(name);
if (i == queues.end()) {
- Queue::shared_ptr queue(new Queue(name, autoDelete, durable ? store : 0, owner, parent));
+ Queue::shared_ptr queue(new Queue(name, autoDelete, durable ? store : 0, owner, parent, broker));
queues[name] = queue;
+ if (lastNode) queue->setLastNodeFailure();
+ if (events) queue->setQueueEventManager(*events);
return std::pair<Queue::shared_ptr, bool>(queue, true);
} else {
@@ -84,10 +87,27 @@ string QueueRegistry::generateName(){
void QueueRegistry::setStore (MessageStore* _store)
{
- assert (store == 0 && _store != 0);
store = _store;
}
MessageStore* QueueRegistry::getStore() const {
return store;
}
+
+void QueueRegistry::updateQueueClusterState(bool _lastNode)
+{
+ RWlock::ScopedRlock locker(lock);
+ for (QueueMap::iterator i = queues.begin(); i != queues.end(); i++) {
+ if (_lastNode){
+ i->second->setLastNodeFailure();
+ } else {
+ i->second->clearLastNodeFailure();
+ }
+ }
+ lastNode = _lastNode;
+}
+
+void QueueRegistry::setQueueEvents(QueueEvents* e)
+{
+ events = e;
+}
diff --git a/cpp/src/qpid/broker/QueueRegistry.h b/cpp/src/qpid/broker/QueueRegistry.h
index f7be1c551a..72a91dff24 100644
--- a/cpp/src/qpid/broker/QueueRegistry.h
+++ b/cpp/src/qpid/broker/QueueRegistry.h
@@ -21,14 +21,19 @@
#ifndef _QueueRegistry_
#define _QueueRegistry_
-#include <map>
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/Queue.h"
#include "qpid/sys/Mutex.h"
-#include "Queue.h"
#include "qpid/management/Manageable.h"
+#include <boost/bind.hpp>
+#include <algorithm>
+#include <map>
namespace qpid {
namespace broker {
+class QueueEvents;
+
/**
* A registry of queues indexed by queue name.
*
@@ -36,10 +41,10 @@ namespace broker {
* are deleted when and only when they are no longer in use.
*
*/
-class QueueRegistry{
+class QueueRegistry {
public:
- QueueRegistry();
- ~QueueRegistry();
+ QPID_BROKER_EXTERN QueueRegistry(Broker* b = 0);
+ QPID_BROKER_EXTERN ~QueueRegistry();
/**
* Declare a queue.
@@ -47,8 +52,11 @@ class QueueRegistry{
* @return The queue and a boolean flag which is true if the queue
* was created by this declare call false if it already existed.
*/
- std::pair<Queue::shared_ptr, bool> declare(const string& name, bool durable = false, bool autodelete = false,
- const OwnershipToken* owner = 0);
+ QPID_BROKER_EXTERN std::pair<Queue::shared_ptr, bool> declare
+ (const string& name,
+ bool durable = false,
+ bool autodelete = false,
+ const OwnershipToken* owner = 0);
/**
* Destroy the named queue.
@@ -62,7 +70,7 @@ class QueueRegistry{
* subsequent calls to find or declare with the same name.
*
*/
- void destroy (const string& name);
+ QPID_BROKER_EXTERN void destroy(const string& name);
template <class Test> bool destroyIf(const string& name, Test test)
{
qpid::sys::RWlock::ScopedWlock locker(lock);
@@ -77,13 +85,15 @@ class QueueRegistry{
/**
* Find the named queue. Return 0 if not found.
*/
- Queue::shared_ptr find(const string& name);
+ QPID_BROKER_EXTERN Queue::shared_ptr find(const string& name);
/**
* Generate unique queue name.
*/
string generateName();
+ void setQueueEvents(QueueEvents*);
+
/**
* Set the store to use. May only be called once.
*/
@@ -98,22 +108,37 @@ class QueueRegistry{
* Register the manageable parent for declared queues
*/
void setParent (management::Manageable* _parent) { parent = _parent; }
+
+ /** Call f for each queue in the registry. */
+ template <class F> void eachQueue(F f) const {
+ qpid::sys::RWlock::ScopedRlock l(lock);
+ for (QueueMap::const_iterator i = queues.begin(); i != queues.end(); ++i)
+ f(i->second);
+ }
+
+ /**
+ * Change queue mode when cluster size drops to 1 node, expands again
+ * in practice allows flow queue to disk when last name to be exectuted
+ */
+ void updateQueueClusterState(bool lastNode);
private:
typedef std::map<string, Queue::shared_ptr> QueueMap;
QueueMap queues;
- qpid::sys::RWlock lock;
+ mutable qpid::sys::RWlock lock;
int counter;
MessageStore* store;
+ QueueEvents* events;
management::Manageable* parent;
+ bool lastNode; //used to set mode on queue declare
+ Broker* broker;
//destroy impl that assumes lock is already held:
void destroyLH (const string& name);
};
-}
-}
+}} // namespace qpid::broker
#endif
diff --git a/cpp/src/qpid/broker/QueuedMessage.h b/cpp/src/qpid/broker/QueuedMessage.h
new file mode 100644
index 0000000000..35e48b11f3
--- /dev/null
+++ b/cpp/src/qpid/broker/QueuedMessage.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _QueuedMessage_
+#define _QueuedMessage_
+
+#include "qpid/broker/Message.h"
+
+namespace qpid {
+namespace broker {
+
+class Queue;
+
+struct QueuedMessage
+{
+ boost::intrusive_ptr<Message> payload;
+ framing::SequenceNumber position;
+ Queue* queue;
+
+ QueuedMessage() : queue(0) {}
+ QueuedMessage(Queue* q, boost::intrusive_ptr<Message> msg, framing::SequenceNumber sn) :
+ payload(msg), position(sn), queue(q) {}
+ QueuedMessage(Queue* q) : queue(q) {}
+
+};
+ inline bool operator<(const QueuedMessage& a, const QueuedMessage& b) { return a.position < b.position; }
+
+}}
+
+
+#endif
diff --git a/cpp/src/qpid/broker/RateFlowcontrol.h b/cpp/src/qpid/broker/RateFlowcontrol.h
new file mode 100644
index 0000000000..99f9d2c0c4
--- /dev/null
+++ b/cpp/src/qpid/broker/RateFlowcontrol.h
@@ -0,0 +1,105 @@
+#ifndef broker_RateFlowcontrol_h
+#define broker_RateFlowcontrol_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Time.h"
+#include "qpid/sys/IntegerTypes.h"
+
+#include <algorithm>
+
+namespace qpid {
+namespace broker {
+
+// Class to keep track of issuing flow control to make sure that the peer doesn't exceed
+// a given message rate
+//
+// Create the object with the target rate
+// Then call sendCredit() whenever credit is issued to the peer
+// Call receivedMessage() whenever a message is received, it returns the credit to issue.
+//
+// sentCredit() be sensibly called with a 0 parameter to indicate
+// that we sent credit but treat it as if the value was 0 (we may do this at the start of the connection
+// to allow our peer to send messages)
+//
+// receivedMessage() can be called with 0 to indicate that we've not received a message, but
+// tell me what credit I can send.
+class RateFlowcontrol {
+ uint32_t rate; // messages per second
+ uint32_t maxCredit; // max credit issued to client (issued at start)
+ uint32_t requestedCredit;
+ qpid::sys::AbsTime creditSent;
+
+public:
+ RateFlowcontrol(uint32_t r) :
+ rate(r),
+ maxCredit(0),
+ requestedCredit(0),
+ creditSent(qpid::sys::FAR_FUTURE)
+ {}
+
+ uint32_t getRate() const {
+ return rate;
+ }
+ void sentCredit(const qpid::sys::AbsTime& t, uint32_t credit);
+ uint32_t receivedMessage(const qpid::sys::AbsTime& t, uint32_t msgs);
+ uint32_t availableCredit(const qpid::sys::AbsTime& t);
+ bool flowStopped() const;
+};
+
+inline void RateFlowcontrol::sentCredit(const qpid::sys::AbsTime& t, uint32_t credit) {
+ // If the client isn't currently requesting credit (ie it's not sent us anything yet) then
+ // this credit goes to the max credit held by the client (it can't go to reduce credit
+ // less than 0)
+ int32_t nextRequestedCredit = requestedCredit - credit;
+ if ( nextRequestedCredit<0 ) {
+ requestedCredit = 0;
+ maxCredit -= nextRequestedCredit;
+ } else {
+ requestedCredit = nextRequestedCredit;
+ }
+ creditSent = t;
+}
+
+inline uint32_t RateFlowcontrol::availableCredit(const qpid::sys::AbsTime& t) {
+ qpid::sys::Duration d(creditSent, t);
+ // Could be -ve before first sentCredit
+ int64_t toSend = std::min(rate * d / qpid::sys::TIME_SEC, static_cast<int64_t>(requestedCredit));
+ return toSend > 0 ? toSend : 0;
+}
+
+inline uint32_t RateFlowcontrol::receivedMessage(const qpid::sys::AbsTime& t, uint32_t msgs) {
+ requestedCredit +=msgs;
+ // Don't send credit for every message, only send if more than 0.5s since last credit or
+ // we've got less than .25 of the max left (heuristic)
+ return requestedCredit*4 >= maxCredit*3 || qpid::sys::Duration(creditSent, t) >= 500*qpid::sys::TIME_MSEC
+ ? availableCredit(t)
+ : 0;
+}
+
+inline bool RateFlowcontrol::flowStopped() const {
+ return requestedCredit >= maxCredit;
+}
+
+}}
+
+#endif // broker_RateFlowcontrol_h
diff --git a/cpp/src/qpid/broker/RateTracker.cpp b/cpp/src/qpid/broker/RateTracker.cpp
new file mode 100644
index 0000000000..048349b658
--- /dev/null
+++ b/cpp/src/qpid/broker/RateTracker.cpp
@@ -0,0 +1,51 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/broker/RateTracker.h"
+
+using qpid::sys::AbsTime;
+using qpid::sys::Duration;
+using qpid::sys::TIME_SEC;
+
+namespace qpid {
+namespace broker {
+
+RateTracker::RateTracker() : currentCount(0), lastCount(0), lastTime(AbsTime::now()) {}
+
+RateTracker& RateTracker::operator++()
+{
+ ++currentCount;
+ return *this;
+}
+
+double RateTracker::sampleRatePerSecond()
+{
+ int32_t increment = currentCount - lastCount;
+ AbsTime now = AbsTime::now();
+ Duration interval(lastTime, now);
+ lastCount = currentCount;
+ lastTime = now;
+ //if sampling at higher frequency than supported, will just return the number of increments
+ if (interval < TIME_SEC) return increment;
+ else if (increment == 0) return 0;
+ else return increment / (interval / TIME_SEC);
+}
+
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/RateTracker.h b/cpp/src/qpid/broker/RateTracker.h
new file mode 100644
index 0000000000..0c20b37312
--- /dev/null
+++ b/cpp/src/qpid/broker/RateTracker.h
@@ -0,0 +1,57 @@
+#ifndef QPID_BROKER_RATETRACKER_H
+#define QPID_BROKER_RATETRACKER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Time.h"
+
+namespace qpid {
+namespace broker {
+
+/**
+ * Simple rate tracker: represents some value that can be incremented,
+ * then can periodcially sample the rate of increments.
+ */
+class RateTracker
+{
+ public:
+ RateTracker();
+ /**
+ * Increments the count being tracked. Can be called concurrently
+ * with other calls to this operator as well as with calls to
+ * sampleRatePerSecond().
+ */
+ RateTracker& operator++();
+ /**
+ * Returns the rate of increments per second since last
+ * called. Calls to this method should be serialised, but can be
+ * called concurrently with the increment operator
+ */
+ double sampleRatePerSecond();
+ private:
+ volatile int32_t currentCount;
+ int32_t lastCount;
+ qpid::sys::AbsTime lastTime;
+};
+}} // namespace qpid::broker
+
+#endif /*!QPID_BROKER_RATETRACKER_H*/
diff --git a/cpp/src/qpid/broker/RecoverableExchange.h b/cpp/src/qpid/broker/RecoverableExchange.h
index 76d0d2ecdf..ca6cc1541e 100644
--- a/cpp/src/qpid/broker/RecoverableExchange.h
+++ b/cpp/src/qpid/broker/RecoverableExchange.h
@@ -40,7 +40,9 @@ public:
/**
* Recover binding. Nb: queue must have been recovered earlier.
*/
- virtual void bind(std::string& queue, std::string& routingKey, qpid::framing::FieldTable& args) = 0;
+ virtual void bind(const std::string& queue,
+ const std::string& routingKey,
+ qpid::framing::FieldTable& args) = 0;
virtual ~RecoverableExchange() {};
};
diff --git a/cpp/src/qpid/broker/RecoverableMessage.h b/cpp/src/qpid/broker/RecoverableMessage.h
index f755fdf727..c98857ceb0 100644
--- a/cpp/src/qpid/broker/RecoverableMessage.h
+++ b/cpp/src/qpid/broker/RecoverableMessage.h
@@ -37,6 +37,7 @@ class RecoverableMessage
public:
typedef boost::shared_ptr<RecoverableMessage> shared_ptr;
virtual void setPersistenceId(uint64_t id) = 0;
+ virtual void setRedelivered() = 0;
/**
* Used by store to determine whether to load content on recovery
* or let message load its own content as and when it requires it.
diff --git a/cpp/src/qpid/broker/RecoverableQueue.h b/cpp/src/qpid/broker/RecoverableQueue.h
index b32bae7f07..49f05f97a1 100644
--- a/cpp/src/qpid/broker/RecoverableQueue.h
+++ b/cpp/src/qpid/broker/RecoverableQueue.h
@@ -22,7 +22,7 @@
*
*/
-#include "RecoverableMessage.h"
+#include "qpid/broker/RecoverableMessage.h"
#include <boost/shared_ptr.hpp>
namespace qpid {
diff --git a/cpp/src/qpid/broker/RecoverableTransaction.h b/cpp/src/qpid/broker/RecoverableTransaction.h
index 7fe34b6756..1b7d94bd1a 100644
--- a/cpp/src/qpid/broker/RecoverableTransaction.h
+++ b/cpp/src/qpid/broker/RecoverableTransaction.h
@@ -24,8 +24,8 @@
#include <boost/shared_ptr.hpp>
-#include "RecoverableMessage.h"
-#include "RecoverableQueue.h"
+#include "qpid/broker/RecoverableMessage.h"
+#include "qpid/broker/RecoverableQueue.h"
namespace qpid {
namespace broker {
diff --git a/cpp/src/qpid/broker/RecoveredDequeue.cpp b/cpp/src/qpid/broker/RecoveredDequeue.cpp
index e2d70964fb..658fd5a89e 100644
--- a/cpp/src/qpid/broker/RecoveredDequeue.cpp
+++ b/cpp/src/qpid/broker/RecoveredDequeue.cpp
@@ -18,22 +18,29 @@
* under the License.
*
*/
-#include "RecoveredDequeue.h"
+#include "qpid/broker/RecoveredDequeue.h"
using boost::intrusive_ptr;
using namespace qpid::broker;
-RecoveredDequeue::RecoveredDequeue(Queue::shared_ptr _queue, intrusive_ptr<Message> _msg) : queue(_queue), msg(_msg) {}
+RecoveredDequeue::RecoveredDequeue(Queue::shared_ptr _queue, intrusive_ptr<Message> _msg) : queue(_queue), msg(_msg)
+{
+ queue->recoverPrepared(msg);
+}
-bool RecoveredDequeue::prepare(TransactionContext*) throw(){
+bool RecoveredDequeue::prepare(TransactionContext*) throw()
+{
//should never be called; transaction has already prepared if an enqueue is recovered
return false;
}
-void RecoveredDequeue::commit() throw(){
+void RecoveredDequeue::commit() throw()
+{
+ queue->enqueueAborted(msg);
}
-void RecoveredDequeue::rollback() throw(){
+void RecoveredDequeue::rollback() throw()
+{
msg->enqueueComplete();
queue->process(msg);
}
diff --git a/cpp/src/qpid/broker/RecoveredDequeue.h b/cpp/src/qpid/broker/RecoveredDequeue.h
index 276e1f4c5c..67b37db5f9 100644
--- a/cpp/src/qpid/broker/RecoveredDequeue.h
+++ b/cpp/src/qpid/broker/RecoveredDequeue.h
@@ -21,11 +21,11 @@
#ifndef _RecoveredDequeue_
#define _RecoveredDequeue_
-#include "Deliverable.h"
-#include "Message.h"
-#include "MessageStore.h"
-#include "Queue.h"
-#include "TxOp.h"
+#include "qpid/broker/Deliverable.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/MessageStore.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/TxOp.h"
#include <boost/intrusive_ptr.hpp>
@@ -45,6 +45,10 @@ namespace qpid {
virtual void commit() throw();
virtual void rollback() throw();
virtual ~RecoveredDequeue(){}
+ virtual void accept(TxOpConstVisitor& visitor) const { visitor(*this); }
+
+ Queue::shared_ptr getQueue() const { return queue; }
+ boost::intrusive_ptr<Message> getMessage() const { return msg; }
};
}
}
diff --git a/cpp/src/qpid/broker/RecoveredEnqueue.cpp b/cpp/src/qpid/broker/RecoveredEnqueue.cpp
index 1984a5d4a8..48faa0942c 100644
--- a/cpp/src/qpid/broker/RecoveredEnqueue.cpp
+++ b/cpp/src/qpid/broker/RecoveredEnqueue.cpp
@@ -18,12 +18,15 @@
* under the License.
*
*/
-#include "RecoveredEnqueue.h"
+#include "qpid/broker/RecoveredEnqueue.h"
using boost::intrusive_ptr;
using namespace qpid::broker;
-RecoveredEnqueue::RecoveredEnqueue(Queue::shared_ptr _queue, intrusive_ptr<Message> _msg) : queue(_queue), msg(_msg) {}
+RecoveredEnqueue::RecoveredEnqueue(Queue::shared_ptr _queue, intrusive_ptr<Message> _msg) : queue(_queue), msg(_msg)
+{
+ queue->recoverPrepared(msg);
+}
bool RecoveredEnqueue::prepare(TransactionContext*) throw(){
//should never be called; transaction has already prepared if an enqueue is recovered
@@ -36,5 +39,6 @@ void RecoveredEnqueue::commit() throw(){
}
void RecoveredEnqueue::rollback() throw(){
+ queue->enqueueAborted(msg);
}
diff --git a/cpp/src/qpid/broker/RecoveredEnqueue.h b/cpp/src/qpid/broker/RecoveredEnqueue.h
index 6525179769..09f928f098 100644
--- a/cpp/src/qpid/broker/RecoveredEnqueue.h
+++ b/cpp/src/qpid/broker/RecoveredEnqueue.h
@@ -21,11 +21,11 @@
#ifndef _RecoveredEnqueue_
#define _RecoveredEnqueue_
-#include "Deliverable.h"
-#include "Message.h"
-#include "MessageStore.h"
-#include "Queue.h"
-#include "TxOp.h"
+#include "qpid/broker/Deliverable.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/MessageStore.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/TxOp.h"
#include <boost/intrusive_ptr.hpp>
@@ -45,6 +45,11 @@ namespace qpid {
virtual void commit() throw();
virtual void rollback() throw();
virtual ~RecoveredEnqueue(){}
+ virtual void accept(TxOpConstVisitor& visitor) const { visitor(*this); }
+
+ Queue::shared_ptr getQueue() const { return queue; }
+ boost::intrusive_ptr<Message> getMessage() const { return msg; }
+
};
}
}
diff --git a/cpp/src/qpid/broker/RecoveryManager.h b/cpp/src/qpid/broker/RecoveryManager.h
index 7dcbe3a2b0..2929e92250 100644
--- a/cpp/src/qpid/broker/RecoveryManager.h
+++ b/cpp/src/qpid/broker/RecoveryManager.h
@@ -21,12 +21,12 @@
#ifndef _RecoveryManager_
#define _RecoveryManager_
-#include "RecoverableExchange.h"
-#include "RecoverableQueue.h"
-#include "RecoverableMessage.h"
-#include "RecoverableTransaction.h"
-#include "RecoverableConfig.h"
-#include "TransactionalStore.h"
+#include "qpid/broker/RecoverableExchange.h"
+#include "qpid/broker/RecoverableQueue.h"
+#include "qpid/broker/RecoverableMessage.h"
+#include "qpid/broker/RecoverableTransaction.h"
+#include "qpid/broker/RecoverableConfig.h"
+#include "qpid/broker/TransactionalStore.h"
#include "qpid/framing/Buffer.h"
namespace qpid {
diff --git a/cpp/src/qpid/broker/RecoveryManagerImpl.cpp b/cpp/src/qpid/broker/RecoveryManagerImpl.cpp
index b058978ccf..12ac2d2bfd 100644
--- a/cpp/src/qpid/broker/RecoveryManagerImpl.cpp
+++ b/cpp/src/qpid/broker/RecoveryManagerImpl.cpp
@@ -18,21 +18,22 @@
* under the License.
*
*/
-#include "RecoveryManagerImpl.h"
-
-#include "Message.h"
-#include "Queue.h"
-#include "Link.h"
-#include "Bridge.h"
-#include "RecoveredEnqueue.h"
-#include "RecoveredDequeue.h"
+#include "qpid/broker/RecoveryManagerImpl.h"
+
+#include "qpid/broker/Message.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/Link.h"
+#include "qpid/broker/Bridge.h"
+#include "qpid/broker/RecoveredEnqueue.h"
+#include "qpid/broker/RecoveredDequeue.h"
#include "qpid/framing/reply_exceptions.h"
-using namespace qpid;
-using namespace qpid::broker;
using boost::dynamic_pointer_cast;
using boost::intrusive_ptr;
+namespace qpid {
+namespace broker {
+
RecoveryManagerImpl::RecoveryManagerImpl(QueueRegistry& _queues, ExchangeRegistry& _exchanges, LinkRegistry& _links,
DtxManager& _dtxMgr, uint64_t _stagingThreshold)
: queues(_queues), exchanges(_exchanges), links(_links), dtxMgr(_dtxMgr), stagingThreshold(_stagingThreshold) {}
@@ -44,10 +45,10 @@ class RecoverableMessageImpl : public RecoverableMessage
intrusive_ptr<Message> msg;
const uint64_t stagingThreshold;
public:
- RecoverableMessageImpl(const intrusive_ptr<Message>& _msg, uint64_t _stagingThreshold)
- : msg(_msg), stagingThreshold(_stagingThreshold) {}
+ RecoverableMessageImpl(const intrusive_ptr<Message>& _msg, uint64_t _stagingThreshold);
~RecoverableMessageImpl() {};
void setPersistenceId(uint64_t id);
+ void setRedelivered();
bool loadContent(uint64_t available);
void decodeContent(framing::Buffer& buffer);
void recover(Queue::shared_ptr queue);
@@ -59,7 +60,7 @@ class RecoverableQueueImpl : public RecoverableQueue
{
Queue::shared_ptr queue;
public:
- RecoverableQueueImpl(Queue::shared_ptr& _queue) : queue(_queue) {}
+ RecoverableQueueImpl(const boost::shared_ptr<Queue>& _queue) : queue(_queue) {}
~RecoverableQueueImpl() {};
void setPersistenceId(uint64_t id);
uint64_t getPersistenceId() const;
@@ -78,7 +79,7 @@ class RecoverableExchangeImpl : public RecoverableExchange
public:
RecoverableExchangeImpl(Exchange::shared_ptr _exchange, QueueRegistry& _queues) : exchange(_exchange), queues(_queues) {}
void setPersistenceId(uint64_t id);
- void bind(std::string& queue, std::string& routingKey, qpid::framing::FieldTable& args);
+ void bind(const std::string& queue, const std::string& routingKey, qpid::framing::FieldTable& args);
};
class RecoverableConfigImpl : public RecoverableConfig
@@ -102,18 +103,24 @@ public:
RecoverableExchange::shared_ptr RecoveryManagerImpl::recoverExchange(framing::Buffer& buffer)
{
- return RecoverableExchange::shared_ptr(new RecoverableExchangeImpl(Exchange::decode(exchanges, buffer), queues));
+ Exchange::shared_ptr e = Exchange::decode(exchanges, buffer);
+ if (e) {
+ return RecoverableExchange::shared_ptr(new RecoverableExchangeImpl(e, queues));
+ } else {
+ return RecoverableExchange::shared_ptr();
+ }
}
RecoverableQueue::shared_ptr RecoveryManagerImpl::recoverQueue(framing::Buffer& buffer)
{
- Queue::shared_ptr queue = Queue::decode(queues, buffer);
+ Queue::shared_ptr queue = Queue::decode(queues, buffer, true);
try {
Exchange::shared_ptr exchange = exchanges.getDefault();
if (exchange) {
exchange->bind(queue, queue->getName(), 0);
+ queue->bound(exchange->getName(), queue->getName(), framing::FieldTable());
}
- } catch (const framing::NotFoundException& e) {
+ } catch (const framing::NotFoundException& /*e*/) {
//assume no default exchange has been declared
}
return RecoverableQueue::shared_ptr(new RecoverableQueueImpl(queue));
@@ -149,7 +156,16 @@ RecoverableConfig::shared_ptr RecoveryManagerImpl::recoverConfig(framing::Buffer
void RecoveryManagerImpl::recoveryComplete()
{
- //TODO (finalise binding setup etc)
+ //notify all queues and exchanges
+ queues.eachQueue(boost::bind(&Queue::recoveryComplete, _1, boost::ref(exchanges)));
+ exchanges.eachExchange(boost::bind(&Exchange::recoveryComplete, _1, boost::ref(exchanges)));
+}
+
+RecoverableMessageImpl:: RecoverableMessageImpl(const intrusive_ptr<Message>& _msg, uint64_t _stagingThreshold) : msg(_msg), stagingThreshold(_stagingThreshold)
+{
+ if (!msg->isPersistent()) {
+ msg->forcePersistent(); // set so that message will get dequeued from store.
+ }
}
bool RecoverableMessageImpl::loadContent(uint64_t available)
@@ -172,6 +188,11 @@ void RecoverableMessageImpl::setPersistenceId(uint64_t id)
msg->setPersistenceId(id);
}
+void RecoverableMessageImpl::setRedelivered()
+{
+ msg->redeliver();
+}
+
void RecoverableQueueImpl::recover(RecoverableMessage::shared_ptr msg)
{
dynamic_pointer_cast<RecoverableMessageImpl>(msg)->recover(queue);
@@ -181,7 +202,7 @@ void RecoverableQueueImpl::setPersistenceId(uint64_t id)
{
queue->setPersistenceId(id);
}
-
+
uint64_t RecoverableQueueImpl::getPersistenceId() const
{
return queue->getPersistenceId();
@@ -215,10 +236,13 @@ void RecoverableConfigImpl::setPersistenceId(uint64_t id)
bridge->setPersistenceId(id);
}
-void RecoverableExchangeImpl::bind(string& queueName, string& key, framing::FieldTable& args)
+void RecoverableExchangeImpl::bind(const string& queueName,
+ const string& key,
+ framing::FieldTable& args)
{
Queue::shared_ptr queue = queues.find(queueName);
exchange->bind(queue, key, &args);
+ queue->bound(exchange->getName(), key, args);
}
void RecoverableMessageImpl::dequeue(DtxBuffer::shared_ptr buffer, Queue::shared_ptr queue)
@@ -251,3 +275,5 @@ void RecoverableTransactionImpl::enqueue(RecoverableQueue::shared_ptr queue, Rec
{
dynamic_pointer_cast<RecoverableQueueImpl>(queue)->enqueue(buffer, message);
}
+
+}}
diff --git a/cpp/src/qpid/broker/RecoveryManagerImpl.h b/cpp/src/qpid/broker/RecoveryManagerImpl.h
index cd34d464f5..6fbbfc4a6c 100644
--- a/cpp/src/qpid/broker/RecoveryManagerImpl.h
+++ b/cpp/src/qpid/broker/RecoveryManagerImpl.h
@@ -22,11 +22,11 @@
#define _RecoveryManagerImpl_
#include <list>
-#include "DtxManager.h"
-#include "ExchangeRegistry.h"
-#include "QueueRegistry.h"
-#include "LinkRegistry.h"
-#include "RecoveryManager.h"
+#include "qpid/broker/DtxManager.h"
+#include "qpid/broker/ExchangeRegistry.h"
+#include "qpid/broker/QueueRegistry.h"
+#include "qpid/broker/LinkRegistry.h"
+#include "qpid/broker/RecoveryManager.h"
namespace qpid {
namespace broker {
diff --git a/cpp/src/qpid/broker/RetryList.cpp b/cpp/src/qpid/broker/RetryList.cpp
new file mode 100644
index 0000000000..8f600c086d
--- /dev/null
+++ b/cpp/src/qpid/broker/RetryList.cpp
@@ -0,0 +1,60 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/broker/RetryList.h"
+
+namespace qpid {
+namespace broker {
+
+RetryList::RetryList() : urlIndex(0), addressIndex(0) {}
+
+void RetryList::reset(const std::vector<Url>& u)
+{
+ urls = u;
+ urlIndex = addressIndex = 0;//reset indices
+}
+
+bool RetryList::next(TcpAddress& address)
+{
+ while (urlIndex < urls.size()) {
+ while (addressIndex < urls[urlIndex].size()) {
+ const TcpAddress* tcp = urls[urlIndex][addressIndex++].get<TcpAddress>();
+ if (tcp) {
+ address = *tcp;
+ return true;
+ }
+ }
+ urlIndex++;
+ addressIndex = 0;
+ }
+
+ urlIndex = addressIndex = 0;//reset indices
+ return false;
+}
+
+std::ostream& operator<<(std::ostream& os, const RetryList& l)
+{
+ for (size_t i = 0; i < l.urls.size(); i++) {
+ os << l.urls[i] << " ";
+ }
+ return os;
+}
+
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/RetryList.h b/cpp/src/qpid/broker/RetryList.h
new file mode 100644
index 0000000000..f87adf2c8d
--- /dev/null
+++ b/cpp/src/qpid/broker/RetryList.h
@@ -0,0 +1,54 @@
+#ifndef QPID_BROKER_RETRYLIST_H
+#define QPID_BROKER_RETRYLIST_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/Address.h"
+#include "qpid/Url.h"
+
+namespace qpid {
+namespace broker {
+
+/**
+ * Simple utility for managing a list of urls to try on reconnecting a
+ * link. Currently only supports TCP urls.
+ */
+class RetryList
+{
+ public:
+ QPID_BROKER_EXTERN RetryList();
+ QPID_BROKER_EXTERN void reset(const std::vector<Url>& urls);
+ QPID_BROKER_EXTERN bool next(TcpAddress& address);
+ private:
+ std::vector<Url> urls;
+ size_t urlIndex;
+ size_t addressIndex;
+
+ friend std::ostream& operator<<(std::ostream& os, const RetryList& l);
+};
+
+std::ostream& operator<<(std::ostream& os, const RetryList& l);
+
+}} // namespace qpid::broker
+
+#endif /*!QPID_BROKER_RETRYLIST_H*/
diff --git a/cpp/src/qpid/broker/SaslAuthenticator.cpp b/cpp/src/qpid/broker/SaslAuthenticator.cpp
index 136cf6f785..0e509c8d93 100644
--- a/cpp/src/qpid/broker/SaslAuthenticator.cpp
+++ b/cpp/src/qpid/broker/SaslAuthenticator.cpp
@@ -19,17 +19,25 @@
*
*/
-#include "config.h"
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
-#include "Connection.h"
+#include "qpid/broker/Connection.h"
#include "qpid/log/Statement.h"
#include "qpid/framing/reply_exceptions.h"
+#include <boost/format.hpp>
#if HAVE_SASL
#include <sasl/sasl.h>
+#include "qpid/sys/cyrus/CyrusSecurityLayer.h"
+using qpid::sys::cyrus::CyrusSecurityLayer;
#endif
using namespace qpid::framing;
+using qpid::sys::SecurityLayer;
+using boost::format;
+using boost::str;
namespace qpid {
namespace broker {
@@ -39,12 +47,15 @@ class NullAuthenticator : public SaslAuthenticator
{
Connection& connection;
framing::AMQP_ClientProxy::Connection client;
+ std::string realm;
+ const bool encrypt;
public:
- NullAuthenticator(Connection& connection);
+ NullAuthenticator(Connection& connection, bool encrypt);
~NullAuthenticator();
void getMechanisms(framing::Array& mechanisms);
void start(const std::string& mechanism, const std::string& response);
void step(const std::string&) {}
+ std::auto_ptr<SecurityLayer> getSecurityLayer(uint16_t maxFrameSize);
};
#if HAVE_SASL
@@ -54,62 +65,132 @@ class CyrusAuthenticator : public SaslAuthenticator
sasl_conn_t *sasl_conn;
Connection& connection;
framing::AMQP_ClientProxy::Connection client;
+ const bool encrypt;
void processAuthenticationStep(int code, const char *challenge, unsigned int challenge_len);
public:
- CyrusAuthenticator(Connection& connection);
+ CyrusAuthenticator(Connection& connection, bool encrypt);
~CyrusAuthenticator();
void init();
void getMechanisms(framing::Array& mechanisms);
void start(const std::string& mechanism, const std::string& response);
void step(const std::string& response);
+ void getUid(std::string& uid);
+ void getError(std::string& error);
+ std::auto_ptr<SecurityLayer> getSecurityLayer(uint16_t maxFrameSize);
};
+bool SaslAuthenticator::available(void)
+{
+ return true;
+}
+
+// Initialize the SASL mechanism; throw if it fails.
+void SaslAuthenticator::init(const std::string& saslName)
+{
+ int code = sasl_server_init(NULL, saslName.c_str());
+ if (code != SASL_OK) {
+ // TODO: Figure out who owns the char* returned by
+ // sasl_errstring, though it probably does not matter much
+ throw Exception(sasl_errstring(code, NULL, NULL));
+ }
+}
+
+void SaslAuthenticator::fini(void)
+{
+ sasl_done();
+}
+
#else
typedef NullAuthenticator CyrusAuthenticator;
+bool SaslAuthenticator::available(void)
+{
+ return false;
+}
+
+void SaslAuthenticator::init(const std::string& /*saslName*/)
+{
+ throw Exception("Requested authentication but SASL unavailable");
+}
+
+void SaslAuthenticator::fini(void)
+{
+ return;
+}
+
#endif
std::auto_ptr<SaslAuthenticator> SaslAuthenticator::createAuthenticator(Connection& c)
{
+ static bool needWarning = true;
if (c.getBroker().getOptions().auth) {
- return std::auto_ptr<SaslAuthenticator>(new CyrusAuthenticator(c));
+ return std::auto_ptr<SaslAuthenticator>(new CyrusAuthenticator(c, c.getBroker().getOptions().requireEncrypted));
} else {
- return std::auto_ptr<SaslAuthenticator>(new NullAuthenticator(c));
+ QPID_LOG(debug, "SASL: No Authentication Performed");
+ needWarning = false;
+ return std::auto_ptr<SaslAuthenticator>(new NullAuthenticator(c, c.getBroker().getOptions().requireEncrypted));
}
}
-NullAuthenticator::NullAuthenticator(Connection& c) : connection(c), client(c.getOutput()) {}
+NullAuthenticator::NullAuthenticator(Connection& c, bool e) : connection(c), client(c.getOutput()),
+ realm(c.getBroker().getOptions().realm), encrypt(e) {}
NullAuthenticator::~NullAuthenticator() {}
void NullAuthenticator::getMechanisms(Array& mechanisms)
{
mechanisms.add(boost::shared_ptr<FieldValue>(new Str16Value("ANONYMOUS")));
+ mechanisms.add(boost::shared_ptr<FieldValue>(new Str16Value("PLAIN")));//useful for testing
}
void NullAuthenticator::start(const string& mechanism, const string& response)
{
- QPID_LOG(warning, "SASL: No Authentication Performed");
+ if (encrypt) {
+ QPID_LOG(error, "Rejected un-encrypted connection.");
+ throw ConnectionForcedException("Connection must be encrypted.");
+ }
if (mechanism == "PLAIN") { // Old behavior
- if (response.size() > 0 && response[0] == (char) 0) {
- string temp = response.substr(1);
- string::size_type i = temp.find((char)0);
- string uid = temp.substr(0, i);
- string pwd = temp.substr(i + 1);
- connection.setUserId(uid);
+ if (response.size() > 0) {
+ string uid;
+ string::size_type i = response.find((char)0);
+ if (i == 0 && response.size() > 1) {
+ //no authorization id; use authentication id
+ i = response.find((char)0, 1);
+ if (i != string::npos) uid = response.substr(1, i-1);
+ } else if (i != string::npos) {
+ //authorization id is first null delimited field
+ uid = response.substr(0, i);
+ }//else not a valid SASL PLAIN response, throw error?
+ if (!uid.empty()) {
+ //append realm if it has not already been added
+ i = uid.find(realm);
+ if (i == string::npos || realm.size() + i < uid.size()) {
+ uid = str(format("%1%@%2%") % uid % realm);
+ }
+ connection.setUserId(uid);
+ }
}
} else {
connection.setUserId("anonymous");
}
- client.tune(framing::CHANNEL_MAX, connection.getFrameMax(), 0, 0);
+ client.tune(framing::CHANNEL_MAX, connection.getFrameMax(), 0, connection.getHeartbeatMax());
+}
+
+
+std::auto_ptr<SecurityLayer> NullAuthenticator::getSecurityLayer(uint16_t)
+{
+ std::auto_ptr<SecurityLayer> securityLayer;
+ return securityLayer;
}
#if HAVE_SASL
-CyrusAuthenticator::CyrusAuthenticator(Connection& c) : sasl_conn(0), connection(c), client(c.getOutput())
+
+CyrusAuthenticator::CyrusAuthenticator(Connection& c, bool _encrypt) :
+ sasl_conn(0), connection(c), client(c.getOutput()), encrypt(_encrypt)
{
init();
}
@@ -145,6 +226,39 @@ void CyrusAuthenticator::init()
// server error, when one is available
throw ConnectionForcedException("Unable to perform authentication");
}
+
+ sasl_security_properties_t secprops;
+
+ //TODO: should the actual SSF values be configurable here?
+ secprops.min_ssf = encrypt ? 10: 0;
+ secprops.max_ssf = 256;
+
+ // If the transport provides encryption, notify the SASL library of
+ // the key length and set the ssf range to prevent double encryption.
+ sasl_ssf_t external_ssf = (sasl_ssf_t) connection.getSSF();
+ if (external_ssf) {
+ int result = sasl_setprop(sasl_conn, SASL_SSF_EXTERNAL, &external_ssf);
+ if (result != SASL_OK) {
+ throw framing::InternalErrorException(QPID_MSG("SASL error: unable to set external SSF: " << result));
+ }
+
+ secprops.max_ssf = secprops.min_ssf = 0;
+ }
+
+ QPID_LOG(debug, "min_ssf: " << secprops.min_ssf <<
+ ", max_ssf: " << secprops.max_ssf <<
+ ", external_ssf: " << external_ssf );
+
+ secprops.maxbufsize = 65535;
+ secprops.property_names = 0;
+ secprops.property_values = 0;
+ secprops.security_flags = 0; /* or SASL_SEC_NOANONYMOUS etc as appropriate */
+
+ int result = sasl_setprop(sasl_conn, SASL_SEC_PROPS, &secprops);
+ if (result != SASL_OK) {
+ throw framing::InternalErrorException(QPID_MSG("SASL error: " << result));
+ }
+
}
CyrusAuthenticator::~CyrusAuthenticator()
@@ -155,6 +269,23 @@ CyrusAuthenticator::~CyrusAuthenticator()
}
}
+void CyrusAuthenticator::getError(string& error)
+{
+ error = string(sasl_errdetail(sasl_conn));
+}
+
+void CyrusAuthenticator::getUid(string& uid)
+{
+ int code;
+ const void* ptr;
+
+ code = sasl_getprop(sasl_conn, SASL_USERNAME, &ptr);
+ if (SASL_OK != code)
+ return;
+
+ uid = string(const_cast<char*>(static_cast<const char*>(ptr)));
+}
+
void CyrusAuthenticator::getMechanisms(Array& mechanisms)
{
const char *separator = " ";
@@ -239,7 +370,7 @@ void CyrusAuthenticator::processAuthenticationStep(int code, const char *challen
connection.setUserId(const_cast<char*>(static_cast<const char*>(uid)));
- client.tune(framing::CHANNEL_MAX, connection.getFrameMax(), 0, 0);
+ client.tune(framing::CHANNEL_MAX, connection.getFrameMax(), 0, connection.getHeartbeatMax());
} else if (SASL_CONTINUE == code) {
string challenge_str(challenge, challenge_len);
@@ -264,6 +395,24 @@ void CyrusAuthenticator::processAuthenticationStep(int code, const char *challen
}
}
}
+
+std::auto_ptr<SecurityLayer> CyrusAuthenticator::getSecurityLayer(uint16_t maxFrameSize)
+{
+
+ const void* value(0);
+ int result = sasl_getprop(sasl_conn, SASL_SSF, &value);
+ if (result != SASL_OK) {
+ throw framing::InternalErrorException(QPID_MSG("SASL error: " << sasl_errdetail(sasl_conn)));
+ }
+ uint ssf = *(reinterpret_cast<const unsigned*>(value));
+ std::auto_ptr<SecurityLayer> securityLayer;
+ if (ssf) {
+ QPID_LOG(info, "Installing security layer, SSF: "<< ssf);
+ securityLayer = std::auto_ptr<SecurityLayer>(new CyrusSecurityLayer(sasl_conn, maxFrameSize));
+ }
+ return securityLayer;
+}
+
#endif
}}
diff --git a/cpp/src/qpid/broker/SaslAuthenticator.h b/cpp/src/qpid/broker/SaslAuthenticator.h
index c2d4ecf7c0..8ddaeb19a4 100644
--- a/cpp/src/qpid/broker/SaslAuthenticator.h
+++ b/cpp/src/qpid/broker/SaslAuthenticator.h
@@ -24,6 +24,7 @@
#include "qpid/framing/amqp_types.h"
#include "qpid/framing/AMQP_ClientProxy.h"
#include "qpid/Exception.h"
+#include "qpid/sys/SecurityLayer.h"
#include <memory>
namespace qpid {
@@ -38,6 +39,15 @@ public:
virtual void getMechanisms(framing::Array& mechanisms) = 0;
virtual void start(const std::string& mechanism, const std::string& response) = 0;
virtual void step(const std::string& response) = 0;
+ virtual void getUid(std::string&) {}
+ virtual void getError(std::string&) {}
+ virtual std::auto_ptr<qpid::sys::SecurityLayer> getSecurityLayer(uint16_t maxFrameSize) = 0;
+
+ static bool available(void);
+
+ // Initialize the SASL mechanism; throw if it fails.
+ static void init(const std::string& saslName);
+ static void fini(void);
static std::auto_ptr<SaslAuthenticator> createAuthenticator(Connection& connection);
};
diff --git a/cpp/src/qpid/broker/SecureConnection.cpp b/cpp/src/qpid/broker/SecureConnection.cpp
new file mode 100644
index 0000000000..74aec239ca
--- /dev/null
+++ b/cpp/src/qpid/broker/SecureConnection.cpp
@@ -0,0 +1,87 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/broker/SecureConnection.h"
+#include "qpid/sys/SecurityLayer.h"
+#include "qpid/framing/reply_exceptions.h"
+
+namespace qpid {
+namespace broker {
+
+using qpid::sys::SecurityLayer;
+
+SecureConnection::SecureConnection() : secured(false) {}
+
+size_t SecureConnection::decode(const char* buffer, size_t size)
+{
+ if (!secured && securityLayer.get()) {
+ //security layer comes into effect on first read after its
+ //activated
+ secured = true;
+ }
+ if (secured) {
+ return securityLayer->decode(buffer, size);
+ } else {
+ return codec->decode(buffer, size);
+ }
+}
+
+size_t SecureConnection::encode(const char* buffer, size_t size)
+{
+ if (secured) {
+ return securityLayer->encode(buffer, size);
+ } else {
+ return codec->encode(buffer, size);
+ }
+}
+
+bool SecureConnection::canEncode()
+{
+ if (secured) return securityLayer->canEncode();
+ else return codec->canEncode();
+}
+
+void SecureConnection::closed()
+{
+ codec->closed();
+}
+
+bool SecureConnection::isClosed() const
+{
+ return codec->isClosed();
+}
+
+framing::ProtocolVersion SecureConnection::getVersion() const
+{
+ return codec->getVersion();
+}
+
+void SecureConnection:: setCodec(std::auto_ptr<ConnectionCodec> c)
+{
+ codec = c;
+}
+
+void SecureConnection::activateSecurityLayer(std::auto_ptr<SecurityLayer> sl)
+{
+ securityLayer = sl;
+ securityLayer->init(codec.get());
+}
+
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/SecureConnection.h b/cpp/src/qpid/broker/SecureConnection.h
new file mode 100644
index 0000000000..4a0cc50e34
--- /dev/null
+++ b/cpp/src/qpid/broker/SecureConnection.h
@@ -0,0 +1,60 @@
+#ifndef QPID_BROKER_SECURECONNECTION_H
+#define QPID_BROKER_SECURECONNECTION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/ConnectionCodec.h"
+#include <memory>
+
+namespace qpid {
+
+namespace sys {
+class SecurityLayer;
+}
+
+namespace broker {
+
+/**
+ * A ConnectionCodec 'wrapper' that allows a connection to be
+ * 'secured' e.g. encrypted based on settings negotiatiated at the
+ * time of establishment.
+ */
+class SecureConnection : public qpid::sys::ConnectionCodec
+{
+ public:
+ SecureConnection();
+ size_t decode(const char* buffer, size_t size);
+ size_t encode(const char* buffer, size_t size);
+ bool canEncode();
+ void closed();
+ bool isClosed() const;
+ framing::ProtocolVersion getVersion() const;
+ void setCodec(std::auto_ptr<ConnectionCodec>);
+ void activateSecurityLayer(std::auto_ptr<qpid::sys::SecurityLayer>);
+ private:
+ std::auto_ptr<ConnectionCodec> codec;
+ std::auto_ptr<qpid::sys::SecurityLayer> securityLayer;
+ bool secured;
+};
+}} // namespace qpid::broker
+
+#endif /*!QPID_BROKER_SECURECONNECTION_H*/
diff --git a/cpp/src/qpid/broker/SecureConnectionFactory.cpp b/cpp/src/qpid/broker/SecureConnectionFactory.cpp
new file mode 100644
index 0000000000..5a31dbceeb
--- /dev/null
+++ b/cpp/src/qpid/broker/SecureConnectionFactory.cpp
@@ -0,0 +1,73 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/broker/SecureConnectionFactory.h"
+#include "qpid/framing/ProtocolVersion.h"
+#include "qpid/amqp_0_10/Connection.h"
+#include "qpid/broker/Connection.h"
+#include "qpid/broker/SecureConnection.h"
+#include "qpid/log/Statement.h"
+
+namespace qpid {
+namespace broker {
+
+using framing::ProtocolVersion;
+typedef std::auto_ptr<amqp_0_10::Connection> CodecPtr;
+typedef std::auto_ptr<SecureConnection> SecureConnectionPtr;
+typedef std::auto_ptr<Connection> ConnectionPtr;
+typedef std::auto_ptr<sys::ConnectionInputHandler> InputPtr;
+
+SecureConnectionFactory::SecureConnectionFactory(Broker& b) : broker(b) {}
+
+sys::ConnectionCodec*
+SecureConnectionFactory::create(ProtocolVersion v, sys::OutputControl& out, const std::string& id,
+ unsigned int conn_ssf ) {
+ if (broker.getConnectionCounter().allowConnection())
+ {
+ QPID_LOG(error, "Client max connection count limit exceeded: " << broker.getOptions().maxConnections << " connection refused");
+ return 0;
+ }
+ if (v == ProtocolVersion(0, 10)) {
+ SecureConnectionPtr sc(new SecureConnection());
+ CodecPtr c(new amqp_0_10::Connection(out, id, false));
+ ConnectionPtr i(new broker::Connection(c.get(), broker, id, conn_ssf, false));
+ i->setSecureConnection(sc.get());
+ c->setInputHandler(InputPtr(i.release()));
+ sc->setCodec(std::auto_ptr<sys::ConnectionCodec>(c));
+ return sc.release();
+ }
+ return 0;
+}
+
+sys::ConnectionCodec*
+SecureConnectionFactory::create(sys::OutputControl& out, const std::string& id,
+ unsigned int conn_ssf) {
+ // used to create connections from one broker to another
+ SecureConnectionPtr sc(new SecureConnection());
+ CodecPtr c(new amqp_0_10::Connection(out, id, true));
+ ConnectionPtr i(new broker::Connection(c.get(), broker, id, conn_ssf, true ));
+ i->setSecureConnection(sc.get());
+ c->setInputHandler(InputPtr(i.release()));
+ sc->setCodec(std::auto_ptr<sys::ConnectionCodec>(c));
+ return sc.release();
+}
+
+
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/SecureConnectionFactory.h b/cpp/src/qpid/broker/SecureConnectionFactory.h
new file mode 100644
index 0000000000..b1af6d4a0f
--- /dev/null
+++ b/cpp/src/qpid/broker/SecureConnectionFactory.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _SecureConnectionFactory_
+#define _SecureConnectionFactory_
+
+#include "qpid/sys/ConnectionCodec.h"
+
+namespace qpid {
+namespace broker {
+class Broker;
+
+class SecureConnectionFactory : public sys::ConnectionCodec::Factory
+{
+ public:
+ SecureConnectionFactory(Broker& b);
+
+ sys::ConnectionCodec*
+ create(framing::ProtocolVersion, sys::OutputControl&, const std::string& id,
+ unsigned int conn_ssf);
+
+ sys::ConnectionCodec*
+ create(sys::OutputControl&, const std::string& id,
+ unsigned int conn_ssf);
+
+ private:
+ Broker& broker;
+};
+
+}}
+
+
+#endif
diff --git a/cpp/src/qpid/broker/SemanticState.cpp b/cpp/src/qpid/broker/SemanticState.cpp
index 4d5c4e7537..e9b6aad967 100644
--- a/cpp/src/qpid/broker/SemanticState.cpp
+++ b/cpp/src/qpid/broker/SemanticState.cpp
@@ -19,21 +19,23 @@
*
*/
-#include "SessionState.h"
-#include "Connection.h"
-#include "DeliverableMessage.h"
-#include "DtxAck.h"
-#include "DtxTimeout.h"
-#include "Message.h"
-#include "Queue.h"
-#include "SessionContext.h"
-#include "TxAccept.h"
-#include "TxPublish.h"
+#include "qpid/broker/SessionState.h"
+#include "qpid/broker/Connection.h"
+#include "qpid/broker/DeliverableMessage.h"
+#include "qpid/broker/DtxAck.h"
+#include "qpid/broker/DtxTimeout.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/SessionContext.h"
+#include "qpid/broker/TxAccept.h"
+#include "qpid/broker/TxPublish.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/SequenceSet.h"
+#include "qpid/framing/IsInSequenceSet.h"
#include "qpid/log/Statement.h"
#include "qpid/ptr_map.h"
-#include "AclModule.h"
+#include "qpid/broker/AclModule.h"
#include <boost/bind.hpp>
#include <boost/format.hpp>
@@ -49,30 +51,35 @@
namespace qpid {
namespace broker {
-using std::mem_fun_ref;
+using namespace std;
using boost::intrusive_ptr;
+using boost::bind;
using namespace qpid::broker;
using namespace qpid::framing;
using namespace qpid::sys;
using qpid::ptr_map_ptr;
+using qpid::management::ManagementAgent;
+using qpid::management::ManagementObject;
+using qpid::management::Manageable;
+using qpid::management::Args;
+namespace _qmf = qmf::org::apache::qpid::broker;
SemanticState::SemanticState(DeliveryAdapter& da, SessionContext& ss)
: session(ss),
deliveryAdapter(da),
- prefetchSize(0),
- prefetchCount(0),
tagGenerator("sgen"),
dtxSelected(false),
- outputTasks(ss)
+ authMsg(getSession().getBroker().getOptions().auth && !getSession().getConnection().isFederationLink()),
+ userID(getSession().getConnection().getUserId()),
+ defaultRealm(getSession().getBroker().getOptions().realm)
{
- outstanding.reset();
acl = getSession().getBroker().getAcl();
}
SemanticState::~SemanticState() {
//cancel all consumers
for (ConsumerImplMap::iterator i = consumers.begin(); i != consumers.end(); i++) {
- cancel(*ptr_map_ptr(i));
+ cancel(i->second);
}
if (dtxBuffer.get()) {
@@ -85,23 +92,20 @@ bool SemanticState::exists(const string& consumerTag){
return consumers.find(consumerTag) != consumers.end();
}
-void SemanticState::consume(DeliveryToken::shared_ptr token, string& tagInOut,
- Queue::shared_ptr queue, bool nolocal, bool ackRequired, bool acquire,
- bool exclusive, const FieldTable*)
+void SemanticState::consume(const string& tag,
+ Queue::shared_ptr queue, bool ackRequired, bool acquire,
+ bool exclusive, const string& resumeId, uint64_t resumeTtl, const FieldTable& arguments)
{
- if(tagInOut.empty())
- tagInOut = tagGenerator.generate();
- std::auto_ptr<ConsumerImpl> c(new ConsumerImpl(this, token, tagInOut, queue, ackRequired, nolocal, acquire));
- queue->consume(*c, exclusive);//may throw exception
- outputTasks.addOutputTask(c.get());
- consumers.insert(tagInOut, c.release());
+ ConsumerImpl::shared_ptr c(new ConsumerImpl(this, tag, queue, ackRequired, acquire, exclusive, resumeId, resumeTtl, arguments));
+ queue->consume(c, exclusive);//may throw exception
+ consumers[tag] = c;
}
void SemanticState::cancel(const string& tag){
ConsumerImplMap::iterator i = consumers.find(tag);
if (i != consumers.end()) {
- cancel(*ptr_map_ptr(i));
- consumers.erase(i);
+ cancel(i->second);
+ consumers.erase(i);
//should cancel all unacked messages for this consumer so that
//they are not redelivered on recovery
for_each(unacked.begin(), unacked.end(), boost::bind(&DeliveryRecord::cancel, _1, tag));
@@ -149,7 +153,7 @@ void SemanticState::startDtx(const std::string& xid, DtxManager& mgr, bool join)
throw CommandInvalidException(QPID_MSG("Session has not been selected for use with dtx"));
}
dtxBuffer = DtxBuffer::shared_ptr(new DtxBuffer(xid));
- txBuffer = static_pointer_cast<TxBuffer>(dtxBuffer);
+ txBuffer = boost::static_pointer_cast<TxBuffer>(dtxBuffer);
if (join) {
mgr.join(xid, dtxBuffer);
} else {
@@ -217,7 +221,7 @@ void SemanticState::resumeDtx(const std::string& xid)
checkDtxTimeout();
dtxBuffer->setSuspended(false);
- txBuffer = static_pointer_cast<TxBuffer>(dtxBuffer);
+ txBuffer = boost::static_pointer_cast<TxBuffer>(dtxBuffer);
}
void SemanticState::checkDtxTimeout()
@@ -231,36 +235,70 @@ void SemanticState::checkDtxTimeout()
void SemanticState::record(const DeliveryRecord& delivery)
{
unacked.push_back(delivery);
- delivery.addTo(outstanding);
}
-bool SemanticState::checkPrefetch(intrusive_ptr<Message>& msg)
-{
- bool countOk = !prefetchCount || prefetchCount > unacked.size();
- bool sizeOk = !prefetchSize || prefetchSize > msg->contentSize() + outstanding.size || unacked.empty();
- return countOk && sizeOk;
-}
+const std::string QPID_SYNC_FREQUENCY("qpid.sync_frequency");
SemanticState::ConsumerImpl::ConsumerImpl(SemanticState* _parent,
- DeliveryToken::shared_ptr _token,
- const string& _name,
- Queue::shared_ptr _queue,
- bool ack,
- bool _nolocal,
- bool _acquire
- ) :
+ const string& _name,
+ Queue::shared_ptr _queue,
+ bool ack,
+ bool _acquire,
+ bool _exclusive,
+ const string& _resumeId,
+ uint64_t _resumeTtl,
+ const framing::FieldTable& _arguments
+
+
+) :
Consumer(_acquire),
parent(_parent),
- token(_token),
name(_name),
queue(_queue),
ackExpected(ack),
- nolocal(_nolocal),
acquire(_acquire),
blocked(true),
- windowing(true),
+ windowing(true),
+ exclusive(_exclusive),
+ resumeId(_resumeId),
+ resumeTtl(_resumeTtl),
+ arguments(_arguments),
msgCredit(0),
- byteCredit(0){}
+ byteCredit(0),
+ notifyEnabled(true),
+ syncFrequency(_arguments.getAsInt(QPID_SYNC_FREQUENCY)),
+ deliveryCount(0),
+ mgmtObject(0)
+{
+ if (parent != 0 && queue.get() != 0 && queue->GetManagementObject() !=0)
+ {
+ ManagementAgent* agent = parent->session.getBroker().getManagementAgent();
+ qpid::management::Manageable* ms = dynamic_cast<qpid::management::Manageable*> (&(parent->session));
+
+ if (agent != 0)
+ {
+ mgmtObject = new _qmf::Subscription(agent, this, ms , queue->GetManagementObject()->getObjectId() ,name,
+ !acquire, ackExpected, exclusive ,arguments);
+ agent->addObject (mgmtObject, agent->allocateId(this));
+ mgmtObject->set_creditMode("WINDOW");
+ }
+ }
+}
+
+ManagementObject* SemanticState::ConsumerImpl::GetManagementObject (void) const
+{
+ return (ManagementObject*) mgmtObject;
+}
+
+Manageable::status_t SemanticState::ConsumerImpl::ManagementMethod (uint32_t methodId, Args&, string&)
+{
+ Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD;
+
+ QPID_LOG (debug, "Queue::ManagementMethod [id=" << methodId << "]");
+
+ return status;
+}
+
OwnershipToken* SemanticState::ConsumerImpl::getSession()
{
@@ -270,29 +308,49 @@ OwnershipToken* SemanticState::ConsumerImpl::getSession()
bool SemanticState::ConsumerImpl::deliver(QueuedMessage& msg)
{
allocateCredit(msg.payload);
- DeliveryId deliveryTag =
- parent->deliveryAdapter.deliver(msg, token);
+ DeliveryRecord record(msg, queue, name, acquire, !ackExpected, windowing);
+ bool sync = syncFrequency && ++deliveryCount >= syncFrequency;
+ if (sync) deliveryCount = 0;//reset
+ parent->deliver(record, sync);
+ if (!ackExpected && acquire) record.setEnded();//allows message to be released now its been delivered
if (windowing || ackExpected || !acquire) {
- parent->record(DeliveryRecord(msg, queue, name, token, deliveryTag, acquire, !ackExpected));
+ parent->record(record);
}
if (acquire && !ackExpected) {
- queue->dequeue(0, msg.payload);
+ queue->dequeue(0, msg);
}
+ if (mgmtObject) { mgmtObject->inc_delivered(); }
return true;
}
-bool SemanticState::ConsumerImpl::filter(intrusive_ptr<Message> msg)
+bool SemanticState::ConsumerImpl::filter(intrusive_ptr<Message>)
{
- return !(nolocal &&
- &parent->getSession().getConnection() == msg->getPublisher());
+ return true;
}
bool SemanticState::ConsumerImpl::accept(intrusive_ptr<Message> msg)
{
- blocked = !(filter(msg) && checkCredit(msg) && (!ackExpected || parent->checkPrefetch(msg)));
+ // FIXME aconway 2009-06-08: if we have byte & message credit but
+ // checkCredit fails because the message is to big, we should
+ // remain on queue's listener list for possible smaller messages
+ // in future.
+ //
+ blocked = !(filter(msg) && checkCredit(msg));
return !blocked;
}
+namespace {
+struct ConsumerName {
+ const SemanticState::ConsumerImpl& consumer;
+ ConsumerName(const SemanticState::ConsumerImpl& ci) : consumer(ci) {}
+};
+
+ostream& operator<<(ostream& o, const ConsumerName& pc) {
+ return o << pc.consumer.getName() << " on "
+ << pc.consumer.getParent().getSession().getSessionId();
+}
+}
+
void SemanticState::ConsumerImpl::allocateCredit(intrusive_ptr<Message>& msg)
{
uint32_t originalMsgCredit = msgCredit;
@@ -303,7 +361,7 @@ void SemanticState::ConsumerImpl::allocateCredit(intrusive_ptr<Message>& msg)
if (byteCredit != 0xFFFFFFFF) {
byteCredit -= msg->getRequiredCredit();
}
- QPID_LOG(debug, "Credit allocated for '" << name << "' on " << parent
+ QPID_LOG(debug, "Credit allocated for " << ConsumerName(*this)
<< ", was " << " bytes: " << originalByteCredit << " msgs: " << originalMsgCredit
<< " now bytes: " << byteCredit << " msgs: " << msgCredit);
@@ -311,23 +369,27 @@ void SemanticState::ConsumerImpl::allocateCredit(intrusive_ptr<Message>& msg)
bool SemanticState::ConsumerImpl::checkCredit(intrusive_ptr<Message>& msg)
{
- if (msgCredit == 0 || (byteCredit != 0xFFFFFFFF && byteCredit < msg->getRequiredCredit())) {
- QPID_LOG(debug, "Not enough credit for '" << name << "' on " << parent
- << ", bytes: " << byteCredit << " msgs: " << msgCredit);
- return false;
- } else {
- QPID_LOG(debug, "Credit available for '" << name << "' on " << parent
- << " bytes: " << byteCredit << " msgs: " << msgCredit);
- return true;
- }
+ bool enoughCredit = msgCredit > 0 &&
+ (byteCredit == 0xFFFFFFFF || byteCredit >= msg->getRequiredCredit());
+ QPID_LOG(debug, (enoughCredit ? "Sufficient credit for " : "Insufficient credit for ")
+ << ConsumerName(*this)
+ << ", have bytes: " << byteCredit << " msgs: " << msgCredit
+ << ", need " << msg->getRequiredCredit() << " bytes");
+ return enoughCredit;
}
-SemanticState::ConsumerImpl::~ConsumerImpl() {}
+SemanticState::ConsumerImpl::~ConsumerImpl()
+{
+ if (mgmtObject != 0)
+ mgmtObject->resourceDestroy ();
+}
-void SemanticState::cancel(ConsumerImpl& c)
+void SemanticState::cancel(ConsumerImpl::shared_ptr c)
{
- outputTasks.removeOutputTask(&c);
- Queue::shared_ptr queue = c.getQueue();
+ c->disableNotify();
+ if (session.isAttached())
+ session.getConnection().outputTasks.removeOutputTask(c.get());
+ Queue::shared_ptr queue = c->getQueue();
if(queue) {
queue->cancel(c);
if (queue->canAutoDelete() && !queue->hasExclusiveOwner()) {
@@ -345,30 +407,48 @@ void SemanticState::handle(intrusive_ptr<Message> msg) {
} else {
DeliverableMessage deliverable(msg);
route(msg, deliverable);
+ if (msg->checkContentReleasable()) {
+ msg->releaseContent();
+ }
}
}
+namespace
+{
+const std::string nullstring;
+}
+
void SemanticState::route(intrusive_ptr<Message> msg, Deliverable& strategy) {
+ msg->setTimestamp(getSession().getBroker().getExpiryPolicy());
+
std::string exchangeName = msg->getExchangeName();
- //TODO: the following should be hidden behind message (using MessageAdapter or similar)
- if (msg->isA<MessageTransferBody>()) {
- msg->getProperties<DeliveryProperties>()->setExchange(exchangeName);
- }
- if (!cacheExchange || cacheExchange->getName() != exchangeName){
+ if (!cacheExchange || cacheExchange->getName() != exchangeName)
cacheExchange = session.getBroker().getExchanges().get(exchangeName);
+ cacheExchange->setProperties(msg);
+
+ /* verify the userid if specified: */
+ std::string id =
+ msg->hasProperties<MessageProperties>() ? msg->getProperties<MessageProperties>()->getUserId() : nullstring;
+
+ if (authMsg && !id.empty() && id != userID && id.append("@").append(defaultRealm) != userID)
+ {
+ QPID_LOG(debug, "authorised user id : " << userID << " but user id in message declared as " << id);
+ throw UnauthorizedAccessException(QPID_MSG("authorised user id : " << userID << " but user id in message declared as " << id));
}
- if (acl && acl->doTransferAcl())
- {
- if (!acl->authorise(getSession().getConnection().getUserId(),acl::PUBLISH,acl::EXCHANGE,exchangeName, msg->getRoutingKey() ))
- throw NotAllowedException("ACL denied exhange publish request");
+ if (acl && acl->doTransferAcl())
+ {
+ if (!acl->authorise(getSession().getConnection().getUserId(),acl::ACT_PUBLISH,acl::OBJ_EXCHANGE,exchangeName, msg->getRoutingKey() ))
+ throw NotAllowedException(QPID_MSG(userID << " cannot publish to " <<
+ exchangeName << " with routing-key " << msg->getRoutingKey()));
}
cacheExchange->route(strategy, msg->getRoutingKey(), msg->getApplicationHeaders());
if (!strategy.delivered) {
- //TODO:if reject-unroutable, then reject
- //else route to alternate exchange
+ //TODO:if discard-unroutable, just drop it
+ //TODO:else if accept-mode is explicit, reject it
+ //else route it to alternate exchange
if (cacheExchange->getAlternate()) {
cacheExchange->getAlternate()->route(strategy, msg->getRoutingKey(), msg->getApplicationHeaders());
}
@@ -380,30 +460,27 @@ void SemanticState::route(intrusive_ptr<Message> msg, Deliverable& strategy) {
}
void SemanticState::requestDispatch()
-{
- for (ConsumerImplMap::iterator i = consumers.begin(); i != consumers.end(); i++) {
- requestDispatch(*ptr_map_ptr(i));
- }
+{
+ for (ConsumerImplMap::iterator i = consumers.begin(); i != consumers.end(); i++)
+ i->second->requestDispatch();
}
-void SemanticState::requestDispatch(ConsumerImpl& c)
-{
- if(c.isBlocked())
- outputTasks.activateOutput();
- // TODO aconway 2008-07-16: we could directly call
- // c.doOutput();
- // since we are in the connections thread but for consistency
- // activateOutput() will set it up to be called in the next write idle.
- // Current cluster code depends on this, review cluster code to change.
+void SemanticState::ConsumerImpl::requestDispatch()
+{
+ if (blocked) {
+ parent->session.getConnection().outputTasks.addOutputTask(this);
+ parent->session.getConnection().outputTasks.activateOutput();
+ blocked = false;
+ }
}
-void SemanticState::complete(DeliveryRecord& delivery)
+bool SemanticState::complete(DeliveryRecord& delivery)
{
- delivery.subtractFrom(outstanding);
ConsumerImplMap::iterator i = consumers.find(delivery.getTag());
if (i != consumers.end()) {
- ptr_map_ptr(i)->complete(delivery);
+ i->second->complete(delivery);
}
+ return delivery.isRedundant();
}
void SemanticState::ConsumerImpl::complete(DeliveryRecord& delivery)
@@ -420,10 +497,9 @@ void SemanticState::ConsumerImpl::complete(DeliveryRecord& delivery)
void SemanticState::recover(bool requeue)
{
if(requeue){
- outstanding.reset();
//take copy and clear unacked as requeue may result in redelivery to this session
//which will in turn result in additions to unacked
- std::list<DeliveryRecord> copy = unacked;
+ DeliveryRecords copy = unacked;
unacked.clear();
for_each(copy.rbegin(), copy.rend(), mem_fun_ref(&DeliveryRecord::requeue));
}else{
@@ -431,27 +507,13 @@ void SemanticState::recover(bool requeue)
//unconfirmed messages re redelivered and therefore have their
//id adjusted, confirmed messages are not and so the ordering
//w.r.t id is lost
- unacked.sort();
- }
-}
-
-bool SemanticState::get(DeliveryToken::shared_ptr token, Queue::shared_ptr queue, bool ackExpected)
-{
- QueuedMessage msg = queue->get();
- if(msg.payload){
- DeliveryId myDeliveryTag = deliveryAdapter.deliver(msg, token);
- if(ackExpected){
- unacked.push_back(DeliveryRecord(msg, queue, myDeliveryTag));
- }
- return true;
- }else{
- return false;
+ sort(unacked.begin(), unacked.end());
}
}
-DeliveryId SemanticState::redeliver(QueuedMessage& msg, DeliveryToken::shared_ptr token)
+void SemanticState::deliver(DeliveryRecord& msg, bool sync)
{
- return deliveryAdapter.deliver(msg, token);
+ return deliveryAdapter.deliver(msg, sync);
}
SemanticState::ConsumerImpl& SemanticState::find(const std::string& destination)
@@ -460,7 +522,7 @@ SemanticState::ConsumerImpl& SemanticState::find(const std::string& destination)
if (i == consumers.end()) {
throw NotFoundException(QPID_MSG("Unknown destination " << destination));
} else {
- return *ptr_map_ptr(i);
+ return *(i->second);
}
}
@@ -478,7 +540,7 @@ void SemanticState::addByteCredit(const std::string& destination, uint32_t value
{
ConsumerImpl& c = find(destination);
c.addByteCredit(value);
- requestDispatch(c);
+ c.requestDispatch();
}
@@ -486,7 +548,7 @@ void SemanticState::addMessageCredit(const std::string& destination, uint32_t va
{
ConsumerImpl& c = find(destination);
c.addMessageCredit(value);
- requestDispatch(c);
+ c.requestDispatch();
}
void SemanticState::flush(const std::string& destination)
@@ -503,30 +565,48 @@ void SemanticState::stop(const std::string& destination)
void SemanticState::ConsumerImpl::setWindowMode()
{
windowing = true;
+ if (mgmtObject){
+ mgmtObject->set_creditMode("WINDOW");
+ }
}
void SemanticState::ConsumerImpl::setCreditMode()
{
windowing = false;
+ if (mgmtObject){
+ mgmtObject->set_creditMode("CREDIT");
+ }
}
void SemanticState::ConsumerImpl::addByteCredit(uint32_t value)
{
if (byteCredit != 0xFFFFFFFF) {
- byteCredit += value;
+ if (value == 0xFFFFFFFF) byteCredit = value;
+ else byteCredit += value;
}
}
void SemanticState::ConsumerImpl::addMessageCredit(uint32_t value)
{
if (msgCredit != 0xFFFFFFFF) {
- msgCredit += value;
+ if (value == 0xFFFFFFFF) msgCredit = value;
+ else msgCredit += value;
+ }
+}
+
+bool SemanticState::ConsumerImpl::haveCredit()
+{
+ if (msgCredit && byteCredit) {
+ return true;
+ } else {
+ blocked = true;
+ return false;
}
}
void SemanticState::ConsumerImpl::flush()
{
- while(queue->dispatch(*this))
+ while(haveCredit() && queue->dispatch(shared_from_this()))
;
stop();
}
@@ -550,20 +630,8 @@ Queue::shared_ptr SemanticState::getQueue(const string& name) const {
}
AckRange SemanticState::findRange(DeliveryId first, DeliveryId last)
-{
- ack_iterator start = find_if(unacked.begin(), unacked.end(), boost::bind(&DeliveryRecord::matchOrAfter, _1, first));
- ack_iterator end = start;
-
- if (start != unacked.end()) {
- if (first == last) {
- //just acked single element (move end past it)
- ++end;
- } else {
- //need to find end (position it just after the last record in range)
- end = find_if(start, unacked.end(), boost::bind(&DeliveryRecord::after, _1, last));
- }
- }
- return AckRange(start, end);
+{
+ return DeliveryRecord::findRange(unacked, first, last);
}
void SemanticState::acquire(DeliveryId first, DeliveryId last, DeliveryIds& acquired)
@@ -591,29 +659,62 @@ void SemanticState::reject(DeliveryId first, DeliveryId last)
}
bool SemanticState::ConsumerImpl::hasOutput() {
- return queue->checkForMessages(*this);
+ return queue->checkForMessages(shared_from_this());
}
bool SemanticState::ConsumerImpl::doOutput()
{
- //TODO: think through properly
- return queue->dispatch(*this);
+ return haveCredit() && queue->dispatch(shared_from_this());
}
-void SemanticState::ConsumerImpl::notify()
+void SemanticState::ConsumerImpl::enableNotify()
{
- //TODO: think through properly
- parent->outputTasks.activateOutput();
+ Mutex::ScopedLock l(lock);
+ notifyEnabled = true;
}
+void SemanticState::ConsumerImpl::disableNotify()
+{
+ Mutex::ScopedLock l(lock);
+ notifyEnabled = false;
+}
-void SemanticState::accepted(DeliveryId first, DeliveryId last)
+bool SemanticState::ConsumerImpl::isNotifyEnabled() const {
+ Mutex::ScopedLock l(lock);
+ return notifyEnabled;
+}
+
+void SemanticState::ConsumerImpl::notify()
{
- AckRange range = findRange(first, last);
+ Mutex::ScopedLock l(lock);
+ if (notifyEnabled) {
+ parent->session.getConnection().outputTasks.addOutputTask(this);
+ parent->session.getConnection().outputTasks.activateOutput();
+ }
+}
+
+
+// Test that a DeliveryRecord's ID is in a sequence set and some other
+// predicate on DeliveryRecord holds.
+template <class Predicate> struct IsInSequenceSetAnd {
+ IsInSequenceSet isInSet;
+ Predicate predicate;
+ IsInSequenceSetAnd(const SequenceSet& s, Predicate p) : isInSet(s), predicate(p) {}
+ bool operator()(DeliveryRecord& dr) {
+ return isInSet(dr.getId()) && predicate(dr);
+ }
+};
+
+template<class Predicate> IsInSequenceSetAnd<Predicate>
+isInSequenceSetAnd(const SequenceSet& s, Predicate p) {
+ return IsInSequenceSetAnd<Predicate>(s,p);
+}
+
+void SemanticState::accepted(const SequenceSet& commands) {
if (txBuffer.get()) {
//in transactional mode, don't dequeue or remove, just
//maintain set of acknowledged messages:
- accumulatedAck.add(first, last);
+ accumulatedAck.add(commands);
if (dtxBuffer.get()) {
//if enlisted in a dtx, copy the relevant slice from
@@ -623,25 +724,48 @@ void SemanticState::accepted(DeliveryId first, DeliveryId last)
dtxBuffer->enlist(txAck);
//mark the relevant messages as 'ended' in unacked
- for_each(range.start, range.end, mem_fun_ref(&DeliveryRecord::setEnded));
-
//if the messages are already completed, they can be
//removed from the record
- unacked.remove_if(mem_fun_ref(&DeliveryRecord::isRedundant));
-
+ DeliveryRecords::iterator removed =
+ remove_if(unacked.begin(), unacked.end(),
+ isInSequenceSetAnd(commands,
+ bind(&DeliveryRecord::setEnded, _1)));
+ unacked.erase(removed, unacked.end());
}
} else {
- for_each(range.start, range.end, boost::bind(&DeliveryRecord::accept, _1, (TransactionContext*) 0));
- unacked.remove_if(mem_fun_ref(&DeliveryRecord::isRedundant));
+ DeliveryRecords::iterator removed =
+ remove_if(unacked.begin(), unacked.end(),
+ isInSequenceSetAnd(commands,
+ bind(&DeliveryRecord::accept, _1,
+ (TransactionContext*) 0)));
+ unacked.erase(removed, unacked.end());
}
}
-void SemanticState::completed(DeliveryId first, DeliveryId last)
-{
- AckRange range = findRange(first, last);
- for_each(range.start, range.end, boost::bind(&SemanticState::complete, this, _1));
- unacked.remove_if(mem_fun_ref(&DeliveryRecord::isRedundant));
+void SemanticState::completed(const SequenceSet& commands) {
+ DeliveryRecords::iterator removed =
+ remove_if(unacked.begin(), unacked.end(),
+ isInSequenceSetAnd(commands,
+ bind(&SemanticState::complete, this, _1)));
+ unacked.erase(removed, unacked.end());
requestDispatch();
}
+void SemanticState::attached()
+{
+ for (ConsumerImplMap::iterator i = consumers.begin(); i != consumers.end(); i++) {
+ i->second->enableNotify();
+ session.getConnection().outputTasks.addOutputTask(i->second.get());
+ }
+ session.getConnection().outputTasks.activateOutput();
+}
+
+void SemanticState::detached()
+{
+ for (ConsumerImplMap::iterator i = consumers.begin(); i != consumers.end(); i++) {
+ i->second->disableNotify();
+ session.getConnection().outputTasks.removeOutputTask(i->second.get());
+ }
+}
+
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/SemanticState.h b/cpp/src/qpid/broker/SemanticState.h
index e03d5ec89b..e5e3f909f1 100644
--- a/cpp/src/qpid/broker/SemanticState.h
+++ b/cpp/src/qpid/broker/SemanticState.h
@@ -22,29 +22,30 @@
*
*/
-#include "Consumer.h"
-#include "Deliverable.h"
-#include "DeliveryAdapter.h"
-#include "DeliveryRecord.h"
-#include "DeliveryToken.h"
-#include "DtxBuffer.h"
-#include "DtxManager.h"
-#include "NameGenerator.h"
-#include "Prefetch.h"
-#include "TxBuffer.h"
+#include "qpid/broker/Consumer.h"
+#include "qpid/broker/Deliverable.h"
+#include "qpid/broker/DeliveryAdapter.h"
+#include "qpid/broker/DeliveryRecord.h"
+#include "qpid/broker/DtxBuffer.h"
+#include "qpid/broker/DtxManager.h"
+#include "qpid/broker/NameGenerator.h"
+#include "qpid/broker/TxBuffer.h"
#include "qpid/framing/FrameHandler.h"
#include "qpid/framing/SequenceSet.h"
#include "qpid/framing/Uuid.h"
#include "qpid/sys/AggregateOutput.h"
-#include "qpid/shared_ptr.h"
-#include "AclModule.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/AtomicValue.h"
+#include "qpid/broker/AclModule.h"
+#include "qmf/org/apache/qpid/broker/Subscription.h"
#include <list>
#include <map>
#include <vector>
#include <boost/intrusive_ptr.hpp>
+#include <boost/cast.hpp>
namespace qpid {
namespace broker {
@@ -55,36 +56,54 @@ class SessionContext;
* SemanticState holds the L3 and L4 state of an open session, whether
* attached to a channel or suspended.
*/
-class SemanticState : public sys::OutputTask,
- private boost::noncopyable
-{
- class ConsumerImpl : public Consumer, public sys::OutputTask
+class SemanticState : private boost::noncopyable {
+ public:
+ class ConsumerImpl : public Consumer, public sys::OutputTask,
+ public boost::enable_shared_from_this<ConsumerImpl>,
+ public management::Manageable
{
+ mutable qpid::sys::Mutex lock;
SemanticState* const parent;
- const DeliveryToken::shared_ptr token;
const string name;
const Queue::shared_ptr queue;
const bool ackExpected;
- const bool nolocal;
const bool acquire;
bool blocked;
bool windowing;
+ bool exclusive;
+ string resumeId;
+ uint64_t resumeTtl;
+ framing::FieldTable arguments;
uint32_t msgCredit;
uint32_t byteCredit;
+ bool notifyEnabled;
+ const int syncFrequency;
+ int deliveryCount;
+ qmf::org::apache::qpid::broker::Subscription* mgmtObject;
bool checkCredit(boost::intrusive_ptr<Message>& msg);
void allocateCredit(boost::intrusive_ptr<Message>& msg);
+ bool haveCredit();
public:
- ConsumerImpl(SemanticState* parent, DeliveryToken::shared_ptr token,
+ typedef boost::shared_ptr<ConsumerImpl> shared_ptr;
+
+ ConsumerImpl(SemanticState* parent,
const string& name, Queue::shared_ptr queue,
- bool ack, bool nolocal, bool acquire);
+ bool ack, bool acquire, bool exclusive,
+ const std::string& resumeId, uint64_t resumeTtl, const framing::FieldTable& arguments);
~ConsumerImpl();
OwnershipToken* getSession();
bool deliver(QueuedMessage& msg);
bool filter(boost::intrusive_ptr<Message> msg);
bool accept(boost::intrusive_ptr<Message> msg);
+
+ void disableNotify();
+ void enableNotify();
void notify();
+ bool isNotifyEnabled() const;
+
+ void requestDispatch();
void setWindowMode();
void setCreditMode();
@@ -93,50 +112,68 @@ class SemanticState : public sys::OutputTask,
void flush();
void stop();
void complete(DeliveryRecord&);
- Queue::shared_ptr getQueue() { return queue; }
- bool isBlocked() const { return blocked; }
+ Queue::shared_ptr getQueue() const { return queue; }
+ bool isBlocked() const { return blocked; }
+ bool setBlocked(bool set) { std::swap(set, blocked); return set; }
bool hasOutput();
bool doOutput();
+
+ std::string getName() const { return name; }
+
+ bool isAckExpected() const { return ackExpected; }
+ bool isAcquire() const { return acquire; }
+ bool isWindowing() const { return windowing; }
+ bool isExclusive() const { return exclusive; }
+ uint32_t getMsgCredit() const { return msgCredit; }
+ uint32_t getByteCredit() const { return byteCredit; }
+ std::string getResumeId() const { return resumeId; };
+ uint64_t getResumeTtl() const { return resumeTtl; }
+ const framing::FieldTable& getArguments() const { return arguments; }
+
+ SemanticState& getParent() { return *parent; }
+ const SemanticState& getParent() const { return *parent; }
+ // Manageable entry points
+ management::ManagementObject* GetManagementObject (void) const;
+ management::Manageable::status_t ManagementMethod (uint32_t methodId, management::Args& args, std::string& text);
};
- typedef boost::ptr_map<std::string,ConsumerImpl> ConsumerImplMap;
+ private:
+ typedef std::map<std::string, ConsumerImpl::shared_ptr> ConsumerImplMap;
typedef std::map<std::string, DtxBuffer::shared_ptr> DtxBufferMap;
SessionContext& session;
DeliveryAdapter& deliveryAdapter;
- Queue::shared_ptr defaultQueue;
ConsumerImplMap consumers;
- uint32_t prefetchSize;
- uint16_t prefetchCount;
- Prefetch outstanding;
NameGenerator tagGenerator;
- std::list<DeliveryRecord> unacked;
+ DeliveryRecords unacked;
TxBuffer::shared_ptr txBuffer;
DtxBuffer::shared_ptr dtxBuffer;
bool dtxSelected;
DtxBufferMap suspendedXids;
framing::SequenceSet accumulatedAck;
boost::shared_ptr<Exchange> cacheExchange;
- sys::AggregateOutput outputTasks;
AclModule* acl;
-
+ const bool authMsg;
+ const string userID;
+ const string defaultRealm;
+
void route(boost::intrusive_ptr<Message> msg, Deliverable& strategy);
- void record(const DeliveryRecord& delivery);
- bool checkPrefetch(boost::intrusive_ptr<Message>& msg);
void checkDtxTimeout();
- ConsumerImpl& find(const std::string& destination);
- void complete(DeliveryRecord&);
+
+ bool complete(DeliveryRecord&);
AckRange findRange(DeliveryId first, DeliveryId last);
void requestDispatch();
- void requestDispatch(ConsumerImpl&);
- void cancel(ConsumerImpl&);
+ void cancel(ConsumerImpl::shared_ptr);
public:
SemanticState(DeliveryAdapter&, SessionContext&);
~SemanticState();
SessionContext& getSession() { return session; }
+ const SessionContext& getSession() const { return session; }
+
+ ConsumerImpl& find(const std::string& destination);
/**
* Get named queue, never returns 0.
@@ -146,16 +183,13 @@ class SemanticState : public sys::OutputTask,
*/
Queue::shared_ptr getQueue(const std::string& name) const;
- uint32_t setPrefetchSize(uint32_t size){ return prefetchSize = size; }
- uint16_t setPrefetchCount(uint16_t n){ return prefetchCount = n; }
-
bool exists(const string& consumerTag);
- /**
- *@param tagInOut - if empty it is updated with the generated token.
- */
- void consume(DeliveryToken::shared_ptr token, string& tagInOut, Queue::shared_ptr queue,
- bool nolocal, bool ackRequired, bool acquire, bool exclusive, const framing::FieldTable* = 0);
+ void consume(const string& destination,
+ Queue::shared_ptr queue,
+ bool ackRequired, bool acquire, bool exclusive,
+ const string& resumeId=string(), uint64_t resumeTtl=0,
+ const framing::FieldTable& = framing::FieldTable());
void cancel(const string& tag);
@@ -166,7 +200,6 @@ class SemanticState : public sys::OutputTask,
void flush(const std::string& destination);
void stop(const std::string& destination);
- bool get(DeliveryToken::shared_ptr token, Queue::shared_ptr queue, bool ackExpected);
void startTx();
void commit(MessageStore* const store);
void rollback();
@@ -176,17 +209,29 @@ class SemanticState : public sys::OutputTask,
void suspendDtx(const std::string& xid);
void resumeDtx(const std::string& xid);
void recover(bool requeue);
- DeliveryId redeliver(QueuedMessage& msg, DeliveryToken::shared_ptr token);
+ void deliver(DeliveryRecord& message, bool sync);
void acquire(DeliveryId first, DeliveryId last, DeliveryIds& acquired);
void release(DeliveryId first, DeliveryId last, bool setRedelivered);
void reject(DeliveryId first, DeliveryId last);
void handle(boost::intrusive_ptr<Message> msg);
- bool hasOutput() { return outputTasks.hasOutput(); }
- bool doOutput() { return outputTasks.doOutput(); }
- //final 0-10 spec (completed and accepted are distinct):
- void completed(DeliveryId deliveryTag, DeliveryId endTag);
- void accepted(DeliveryId deliveryTag, DeliveryId endTag);
+ void completed(const framing::SequenceSet& commands);
+ void accepted(const framing::SequenceSet& commands);
+
+ void attached();
+ void detached();
+
+ // Used by cluster to re-create sessions
+ template <class F> void eachConsumer(F f) {
+ for(ConsumerImplMap::iterator i = consumers.begin(); i != consumers.end(); ++i)
+ f(i->second);
+ }
+ DeliveryRecords& getUnacked() { return unacked; }
+ framing::SequenceSet getAccumulatedAck() const { return accumulatedAck; }
+ TxBuffer::shared_ptr getTxBuffer() const { return txBuffer; }
+ void setTxBuffer(const TxBuffer::shared_ptr& txb) { txBuffer = txb; }
+ void setAccumulatedAck(const framing::SequenceSet& s) { accumulatedAck = s; }
+ void record(const DeliveryRecord& delivery);
};
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/SessionAdapter.cpp b/cpp/src/qpid/broker/SessionAdapter.cpp
index 03022b00bb..a7743d95ab 100644
--- a/cpp/src/qpid/broker/SessionAdapter.cpp
+++ b/cpp/src/qpid/broker/SessionAdapter.cpp
@@ -15,17 +15,23 @@
* limitations under the License.
*
*/
-#include "SessionAdapter.h"
-#include "Connection.h"
-#include "DeliveryToken.h"
-#include "MessageDelivery.h"
-#include "Queue.h"
+#include "qpid/broker/SessionAdapter.h"
+#include "qpid/broker/Connection.h"
+#include "qpid/broker/Queue.h"
#include "qpid/Exception.h"
#include "qpid/framing/reply_exceptions.h"
-#include "qpid/framing/constants.h"
+#include "qpid/framing/enum.h"
#include "qpid/log/Statement.h"
-#include "qpid/amqp_0_10/exceptions.h"
#include "qpid/framing/SequenceSet.h"
+#include "qpid/management/ManagementAgent.h"
+#include "qmf/org/apache/qpid/broker/EventExchangeDeclare.h"
+#include "qmf/org/apache/qpid/broker/EventExchangeDelete.h"
+#include "qmf/org/apache/qpid/broker/EventQueueDeclare.h"
+#include "qmf/org/apache/qpid/broker/EventQueueDelete.h"
+#include "qmf/org/apache/qpid/broker/EventBind.h"
+#include "qmf/org/apache/qpid/broker/EventUnbind.h"
+#include "qmf/org/apache/qpid/broker/EventSubscribe.h"
+#include "qmf/org/apache/qpid/broker/EventUnsubscribe.h"
#include <boost/format.hpp>
#include <boost/cast.hpp>
#include <boost/bind.hpp>
@@ -35,6 +41,9 @@ namespace broker {
using namespace qpid;
using namespace qpid::framing;
+using namespace qpid::framing::dtx;
+using namespace qpid::management;
+namespace _qmf = qmf::org::apache::qpid::broker;
typedef std::vector<Queue::shared_ptr> QueueVector;
@@ -48,23 +57,24 @@ SessionAdapter::SessionAdapter(SemanticState& s) :
dtxImpl(s)
{}
+static const std::string _TRUE("true");
+static const std::string _FALSE("false");
void SessionAdapter::ExchangeHandlerImpl::declare(const string& exchange, const string& type,
const string& alternateExchange,
bool passive, bool durable, bool /*autoDelete*/, const FieldTable& args){
- AclModule* acl = getBroker().getAcl();
- if (acl)
- {
- std::map<std::string, std::string> params;
- params.insert(make_pair("TYPE", type));
- params.insert(make_pair("ALT", alternateExchange));
- params.insert(make_pair("PAS", std::string(passive ? "Y" : "N") ));
- params.insert(make_pair("DURA", std::string(durable ? "Y" : "N")));
- if (!acl->authorise(getConnection().getUserId(),acl::CREATE,acl::EXCHANGE,exchange,&params) )
- throw NotAllowedException("ACL denied exhange declare request");
- }
-
+ AclModule* acl = getBroker().getAcl();
+ if (acl) {
+ std::map<acl::Property, std::string> params;
+ params.insert(make_pair(acl::PROP_TYPE, type));
+ params.insert(make_pair(acl::PROP_ALTERNATE, alternateExchange));
+ params.insert(make_pair(acl::PROP_PASSIVE, std::string(passive ? _TRUE : _FALSE) ));
+ params.insert(make_pair(acl::PROP_DURABLE, std::string(durable ? _TRUE : _FALSE)));
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_CREATE,acl::OBJ_EXCHANGE,exchange,&params) )
+ throw NotAllowedException(QPID_MSG("ACL denied exchange declare request from " << getConnection().getUserId()));
+ }
+
//TODO: implement autoDelete
Exchange::shared_ptr alternate;
if (!alternateExchange.empty()) {
@@ -75,21 +85,31 @@ void SessionAdapter::ExchangeHandlerImpl::declare(const string& exchange, const
checkType(actual, type);
checkAlternate(actual, alternate);
}else{
+ if(exchange.find("amq.") == 0 || exchange.find("qpid.") == 0) {
+ throw framing::NotAllowedException(QPID_MSG("Exchange names beginning with \"amq.\" or \"qpid.\" are reserved. (exchange=\"" << exchange << "\")"));
+ }
try{
std::pair<Exchange::shared_ptr, bool> response = getBroker().getExchanges().declare(exchange, type, durable, args);
if (response.second) {
- if (durable) {
- getBroker().getStore().create(*response.first, args);
- }
if (alternate) {
response.first->setAlternate(alternate);
alternate->incAlternateUsers();
}
+ if (durable) {
+ getBroker().getStore().create(*response.first, args);
+ }
} else {
checkType(response.first, type);
checkAlternate(response.first, alternate);
}
- }catch(UnknownExchangeTypeException& e){
+
+ ManagementAgent* agent = getBroker().getManagementAgent();
+ if (agent)
+ agent->raiseEvent(_qmf::EventExchangeDeclare(getConnection().getUrl(), getConnection().getUserId(), exchange, type,
+ alternateExchange, durable, false, args,
+ response.second ? "created" : "existing"));
+
+ }catch(UnknownExchangeTypeException& /*e*/){
throw CommandInvalidException(QPID_MSG("Exchange type not implemented: " << type));
}
}
@@ -104,57 +124,62 @@ void SessionAdapter::ExchangeHandlerImpl::checkType(Exchange::shared_ptr exchang
void SessionAdapter::ExchangeHandlerImpl::checkAlternate(Exchange::shared_ptr exchange, Exchange::shared_ptr alternate)
{
- if (alternate && alternate != exchange->getAlternate())
- throw NotAllowedException(
- QPID_MSG("Exchange declared with alternate-exchange "
- << exchange->getAlternate()->getName() << ", requested "
- << alternate->getName()));
+ if (alternate && ((exchange->getAlternate() && alternate != exchange->getAlternate())
+ || !exchange->getAlternate()))
+ throw NotAllowedException(QPID_MSG("Exchange declared with alternate-exchange "
+ << (exchange->getAlternate() ? exchange->getAlternate()->getName() : "<nonexistent>")
+ << ", requested "
+ << alternate->getName()));
}
-void SessionAdapter::ExchangeHandlerImpl::delete_(const string& name, bool /*ifUnused*/){
-
- AclModule* acl = getBroker().getAcl();
- if (acl)
- {
- if (!acl->authorise(getConnection().getUserId(),acl::DELETE,acl::EXCHANGE,name,NULL) )
- throw NotAllowedException("ACL denied exhange delete request");
+void SessionAdapter::ExchangeHandlerImpl::delete_(const string& name, bool /*ifUnused*/)
+{
+ AclModule* acl = getBroker().getAcl();
+ if (acl) {
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_DELETE,acl::OBJ_EXCHANGE,name,NULL) )
+ throw NotAllowedException(QPID_MSG("ACL denied exchange delete request from " << getConnection().getUserId()));
}
-
//TODO: implement unused
Exchange::shared_ptr exchange(getBroker().getExchanges().get(name));
if (exchange->inUseAsAlternate()) throw NotAllowedException(QPID_MSG("Exchange in use as alternate-exchange."));
if (exchange->isDurable()) getBroker().getStore().destroy(*exchange);
if (exchange->getAlternate()) exchange->getAlternate()->decAlternateUsers();
getBroker().getExchanges().destroy(name);
-}
+
+ ManagementAgent* agent = getBroker().getManagementAgent();
+ if (agent)
+ agent->raiseEvent(_qmf::EventExchangeDelete(getConnection().getUrl(), getConnection().getUserId(), name));
+}
ExchangeQueryResult SessionAdapter::ExchangeHandlerImpl::query(const string& name)
{
-
- AclModule* acl = getBroker().getAcl();
- if (acl)
- {
- if (!acl->authorise(getConnection().getUserId(),acl::ACCESS,acl::EXCHANGE,name,NULL) )
- throw NotAllowedException("ACL denied exhange query request");
+ AclModule* acl = getBroker().getAcl();
+ if (acl) {
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_ACCESS,acl::OBJ_EXCHANGE,name,NULL) )
+ throw NotAllowedException(QPID_MSG("ACL denied exchange query request from " << getConnection().getUserId()));
}
try {
Exchange::shared_ptr exchange(getBroker().getExchanges().get(name));
return ExchangeQueryResult(exchange->getType(), exchange->isDurable(), false, exchange->getArgs());
- } catch (const NotFoundException& e) {
+ } catch (const NotFoundException& /*e*/) {
return ExchangeQueryResult("", false, true, FieldTable());
}
}
+
void SessionAdapter::ExchangeHandlerImpl::bind(const string& queueName,
const string& exchangeName, const string& routingKey,
- const FieldTable& arguments){
+ const FieldTable& arguments)
+{
+ AclModule* acl = getBroker().getAcl();
+ if (acl) {
+ std::map<acl::Property, std::string> params;
+ params.insert(make_pair(acl::PROP_QUEUENAME, queueName));
+ params.insert(make_pair(acl::PROP_ROUTINGKEY, routingKey));
- AclModule* acl = getBroker().getAcl();
- if (acl)
- {
- if (!acl->authorise(getConnection().getUserId(),acl::BIND,acl::EXCHANGE,exchangeName,routingKey) )
- throw NotAllowedException("ACL denied exhange bind request");
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_BIND,acl::OBJ_EXCHANGE,exchangeName,&params))
+ throw NotAllowedException(QPID_MSG("ACL denied exchange bind request from " << getConnection().getUserId()));
}
Queue::shared_ptr queue = getQueue(queueName);
@@ -166,30 +191,29 @@ void SessionAdapter::ExchangeHandlerImpl::bind(const string& queueName,
if (exchange->isDurable() && queue->isDurable()) {
getBroker().getStore().bind(*exchange, *queue, routingKey, arguments);
}
+
+ ManagementAgent* agent = getBroker().getManagementAgent();
+ if (agent)
+ agent->raiseEvent(_qmf::EventBind(getConnection().getUrl(), getConnection().getUserId(), exchangeName, queueName, exchangeRoutingKey, arguments));
}
}else{
- throw NotFoundException(
- "Bind failed. No such exchange: " + exchangeName);
+ throw NotFoundException("Bind failed. No such exchange: " + exchangeName);
}
}
-void
-SessionAdapter::ExchangeHandlerImpl::unbind(const string& queueName,
- const string& exchangeName,
- const string& routingKey)
+void SessionAdapter::ExchangeHandlerImpl::unbind(const string& queueName,
+ const string& exchangeName,
+ const string& routingKey)
{
-
- AclModule* acl = getBroker().getAcl();
- if (acl)
- {
- std::map<std::string, std::string> params;
- params.insert(make_pair("QN", queueName));
- params.insert(make_pair("RKEY", routingKey));
- if (!acl->authorise(getConnection().getUserId(),acl::UNBIND,acl::EXCHANGE,exchangeName,&params) )
- throw NotAllowedException("ACL denied exchange unbind request");
+ AclModule* acl = getBroker().getAcl();
+ if (acl) {
+ std::map<acl::Property, std::string> params;
+ params.insert(make_pair(acl::PROP_QUEUENAME, queueName));
+ params.insert(make_pair(acl::PROP_ROUTINGKEY, routingKey));
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_UNBIND,acl::OBJ_EXCHANGE,exchangeName,&params) )
+ throw NotAllowedException(QPID_MSG("ACL denied exchange unbind request from " << getConnection().getUserId()));
}
-
Queue::shared_ptr queue = getQueue(queueName);
if (!queue.get()) throw NotFoundException("Unbind failed. No such exchange: " + exchangeName);
@@ -197,10 +221,14 @@ SessionAdapter::ExchangeHandlerImpl::unbind(const string& queueName,
if (!exchange.get()) throw NotFoundException("Unbind failed. No such exchange: " + exchangeName);
//TODO: revise unbind to rely solely on binding key (not args)
- if (exchange->unbind(queue, routingKey, 0) && exchange->isDurable() && queue->isDurable()) {
- getBroker().getStore().unbind(*exchange, *queue, routingKey, FieldTable());
- }
+ if (exchange->unbind(queue, routingKey, 0)) {
+ if (exchange->isDurable() && queue->isDurable())
+ getBroker().getStore().unbind(*exchange, *queue, routingKey, FieldTable());
+ ManagementAgent* agent = getBroker().getManagementAgent();
+ if (agent)
+ agent->raiseEvent(_qmf::EventUnbind(getConnection().getUrl(), getConnection().getUserId(), exchangeName, queueName, routingKey));
+ }
}
ExchangeBoundResult SessionAdapter::ExchangeHandlerImpl::bound(const std::string& exchangeName,
@@ -208,16 +236,15 @@ ExchangeBoundResult SessionAdapter::ExchangeHandlerImpl::bound(const std::string
const std::string& key,
const framing::FieldTable& args)
{
- AclModule* acl = getBroker().getAcl();
- if (acl)
- {
- std::map<std::string, std::string> params;
- params.insert(make_pair("QUEUE", queueName));
- params.insert(make_pair("RKEY", queueName));
- if (!acl->authorise(getConnection().getUserId(),acl::CREATE,acl::EXCHANGE,exchangeName,&params) )
- throw NotAllowedException("ACL denied exhange bound request");
+ AclModule* acl = getBroker().getAcl();
+ if (acl) {
+ std::map<acl::Property, std::string> params;
+ params.insert(make_pair(acl::PROP_QUEUENAME, queueName));
+ params.insert(make_pair(acl::PROP_ROUTINGKEY, key));
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_ACCESS,acl::OBJ_EXCHANGE,exchangeName,&params) )
+ throw NotAllowedException(QPID_MSG("ACL denied exchange bound request from " << getConnection().getUserId()));
}
-
+
Exchange::shared_ptr exchange;
try {
exchange = getBroker().getExchanges().get(exchangeName);
@@ -229,7 +256,7 @@ ExchangeBoundResult SessionAdapter::ExchangeHandlerImpl::bound(const std::string
}
if (!exchange) {
- return ExchangeBoundResult(true, false, false, false, false);
+ return ExchangeBoundResult(true, (!queueName.empty() && !queue), false, false, false);
} else if (!queueName.empty() && !queue) {
return ExchangeBoundResult(false, true, false, false, false);
} else if (exchange->isBound(queue, key.empty() ? 0 : &key, args.count() > 0 ? &args : &args)) {
@@ -268,7 +295,6 @@ void SessionAdapter::QueueHandlerImpl::destroyExclusiveQueues()
exclusiveQueues.erase(exclusiveQueues.begin());
}
}
-
bool SessionAdapter::QueueHandlerImpl::isLocal(const ConnectionToken* t) const
{
@@ -278,13 +304,12 @@ bool SessionAdapter::QueueHandlerImpl::isLocal(const ConnectionToken* t) const
QueueQueryResult SessionAdapter::QueueHandlerImpl::query(const string& name)
{
- AclModule* acl = getBroker().getAcl();
- if (acl)
- {
- if (!acl->authorise(getConnection().getUserId(),acl::ACCESS,acl::QUEUE,name,NULL) )
- throw NotAllowedException("ACL denied queue query request");
+ AclModule* acl = getBroker().getAcl();
+ if (acl) {
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_ACCESS,acl::OBJ_QUEUE,name,NULL) )
+ throw NotAllowedException(QPID_MSG("ACL denied queue query request from " << getConnection().getUserId()));
}
-
+
Queue::shared_ptr queue = session.getBroker().getQueues().find(name);
if (queue) {
@@ -304,20 +329,23 @@ QueueQueryResult SessionAdapter::QueueHandlerImpl::query(const string& name)
}
void SessionAdapter::QueueHandlerImpl::declare(const string& name, const string& alternateExchange,
- bool passive, bool durable, bool exclusive,
- bool autoDelete, const qpid::framing::FieldTable& arguments){
-
- AclModule* acl = getBroker().getAcl();
- if (acl)
- {
- std::map<std::string, std::string> params;
- params.insert(make_pair("ALT", alternateExchange));
- params.insert(make_pair("PAS", std::string(passive ? "Y" : "N") ));
- params.insert(make_pair("DURA", std::string(durable ? "Y" : "N")));
- params.insert(make_pair("EXCLUS", std::string(exclusive ? "Y" : "N")));
- params.insert(make_pair("AUTOD", std::string(autoDelete ? "Y" : "N")));
- if (!acl->authorise(getConnection().getUserId(),acl::CREATE,acl::QUEUE,name,&params) )
- throw NotAllowedException("ACL denied queue create request");
+ bool passive, bool durable, bool exclusive,
+ bool autoDelete, const qpid::framing::FieldTable& arguments)
+{
+ AclModule* acl = getBroker().getAcl();
+ if (acl) {
+ std::map<acl::Property, std::string> params;
+ params.insert(make_pair(acl::PROP_ALTERNATE, alternateExchange));
+ params.insert(make_pair(acl::PROP_PASSIVE, std::string(passive ? _TRUE : _FALSE) ));
+ params.insert(make_pair(acl::PROP_DURABLE, std::string(durable ? _TRUE : _FALSE)));
+ params.insert(make_pair(acl::PROP_EXCLUSIVE, std::string(exclusive ? _TRUE : _FALSE)));
+ params.insert(make_pair(acl::PROP_AUTODELETE, std::string(autoDelete ? _TRUE : _FALSE)));
+ params.insert(make_pair(acl::PROP_POLICYTYPE, arguments.getAsString("qpid.policy_type")));
+ params.insert(make_pair(acl::PROP_MAXQUEUECOUNT, boost::lexical_cast<string>(arguments.getAsInt("qpid.max_count"))));
+ params.insert(make_pair(acl::PROP_MAXQUEUESIZE, boost::lexical_cast<string>(arguments.getAsInt64("qpid.max_size"))));
+
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_CREATE,acl::OBJ_QUEUE,name,&params) )
+ throw NotAllowedException(QPID_MSG("ACL denied queue create request from " << getConnection().getUserId()));
}
Exchange::shared_ptr alternate;
@@ -326,17 +354,16 @@ void SessionAdapter::QueueHandlerImpl::declare(const string& name, const string&
}
Queue::shared_ptr queue;
if (passive && !name.empty()) {
- queue = getQueue(name);
+ queue = getQueue(name);
//TODO: check alternate-exchange is as expected
} else {
- std::pair<Queue::shared_ptr, bool> queue_created =
- getBroker().getQueues().declare(
- name, durable,
- autoDelete,
- exclusive ? this : 0);
- queue = queue_created.first;
- assert(queue);
- if (queue_created.second) { // This is a new queue
+ std::pair<Queue::shared_ptr, bool> queue_created =
+ getBroker().getQueues().declare(name, durable,
+ autoDelete,
+ exclusive ? &session : 0);
+ queue = queue_created.first;
+ assert(queue);
+ if (queue_created.second) { // This is a new queue
if (alternate) {
queue->setAlternateExchange(alternate);
alternate->incAlternateUsers();
@@ -345,48 +372,56 @@ void SessionAdapter::QueueHandlerImpl::declare(const string& name, const string&
//apply settings & create persistent record if required
queue_created.first->create(arguments);
- //add default binding:
- getBroker().getExchanges().getDefault()->bind(queue, name, 0);
+ //add default binding:
+ getBroker().getExchanges().getDefault()->bind(queue, name, 0);
queue->bound(getBroker().getExchanges().getDefault()->getName(), name, arguments);
//handle automatic cleanup:
- if (exclusive) {
- exclusiveQueues.push_back(queue);
- }
- } else {
- if (exclusive && queue->setExclusiveOwner(this)) {
- exclusiveQueues.push_back(queue);
+ if (exclusive) {
+ exclusiveQueues.push_back(queue);
+ }
+ } else {
+ if (exclusive && queue->setExclusiveOwner(&session)) {
+ exclusiveQueues.push_back(queue);
}
}
+
+ ManagementAgent* agent = getBroker().getManagementAgent();
+ if (agent)
+ agent->raiseEvent(_qmf::EventQueueDeclare(getConnection().getUrl(), getConnection().getUserId(),
+ name, durable, exclusive, autoDelete, arguments,
+ queue_created.second ? "created" : "existing"));
}
- if (exclusive && !queue->isExclusiveOwner(this))
- throw ResourceLockedException(
- QPID_MSG("Cannot grant exclusive access to queue "
- << queue->getName()));
+
+ if (exclusive && !queue->isExclusiveOwner(&session))
+ throw ResourceLockedException(QPID_MSG("Cannot grant exclusive access to queue "
+ << queue->getName()));
}
void SessionAdapter::QueueHandlerImpl::purge(const string& queue){
- AclModule* acl = getBroker().getAcl();
- if (acl)
- {
- if (!acl->authorise(getConnection().getUserId(),acl::PURGE,acl::QUEUE,queue,NULL) )
- throw NotAllowedException("ACL denied queue purge request");
+ AclModule* acl = getBroker().getAcl();
+ if (acl)
+ {
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_PURGE,acl::OBJ_QUEUE,queue,NULL) )
+ throw NotAllowedException(QPID_MSG("ACL denied queue purge request from " << getConnection().getUserId()));
}
getQueue(queue)->purge();
}
void SessionAdapter::QueueHandlerImpl::delete_(const string& queue, bool ifUnused, bool ifEmpty){
- AclModule* acl = getBroker().getAcl();
- if (acl)
- {
- if (!acl->authorise(getConnection().getUserId(),acl::DELETE,acl::QUEUE,queue,NULL) )
- throw NotAllowedException("ACL denied queue delete request");
+ AclModule* acl = getBroker().getAcl();
+ if (acl)
+ {
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_DELETE,acl::OBJ_QUEUE,queue,NULL) )
+ throw NotAllowedException(QPID_MSG("ACL denied queue delete request from " << getConnection().getUserId()));
}
- ChannelException error(0, "");
Queue::shared_ptr q = getQueue(queue);
+ if (q->hasExclusiveOwner() && !q->isExclusiveOwner(&session))
+ throw ResourceLockedException(QPID_MSG("Cannot delete queue "
+ << queue << "; it is exclusive to another session"));
if(ifEmpty && q->getMessageCount() > 0){
throw PreconditionFailedException("Queue not empty.");
}else if(ifUnused && q->getConsumerCount() > 0){
@@ -400,16 +435,18 @@ void SessionAdapter::QueueHandlerImpl::delete_(const string& queue, bool ifUnuse
q->destroy();
getBroker().getQueues().destroy(queue);
q->unbind(getBroker().getExchanges(), q);
+
+ ManagementAgent* agent = getBroker().getManagementAgent();
+ if (agent)
+ agent->raiseEvent(_qmf::EventQueueDelete(getConnection().getUrl(), getConnection().getUserId(), queue));
}
}
-
SessionAdapter::MessageHandlerImpl::MessageHandlerImpl(SemanticState& s) :
HandlerHelper(s),
releaseRedeliveredOp(boost::bind(&SemanticState::release, &state, _1, _2, true)),
releaseOp(boost::bind(&SemanticState::release, &state, _1, _2, false)),
- rejectOp(boost::bind(&SemanticState::reject, &state, _1, _2)),
- acceptOp(boost::bind(&SemanticState::accepted, &state, _1, _2))
+ rejectOp(boost::bind(&SemanticState::reject, &state, _1, _2))
{}
//
@@ -431,37 +468,47 @@ void SessionAdapter::MessageHandlerImpl::release(const SequenceSet& transfers, b
void
SessionAdapter::MessageHandlerImpl::subscribe(const string& queueName,
- const string& destination,
- uint8_t acceptMode,
- uint8_t acquireMode,
- bool exclusive,
- const string& /*resumeId*/,//TODO implement resume behaviour
- uint64_t /*resumeTtl*/,
- const FieldTable& arguments)
+ const string& destination,
+ uint8_t acceptMode,
+ uint8_t acquireMode,
+ bool exclusive,
+ const string& resumeId,
+ uint64_t resumeTtl,
+ const FieldTable& arguments)
{
- AclModule* acl = getBroker().getAcl();
- if (acl)
- {
- // add flags as needed
- if (!acl->authorise(getConnection().getUserId(),acl::CONSUME,acl::QUEUE,queueName,NULL) )
- throw NotAllowedException("ACL denied Queue subscribe request");
+ AclModule* acl = getBroker().getAcl();
+ if (acl)
+ {
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_CONSUME,acl::OBJ_QUEUE,queueName,NULL) )
+ throw NotAllowedException(QPID_MSG("ACL denied Queue subscribe request from " << getConnection().getUserId()));
}
Queue::shared_ptr queue = getQueue(queueName);
if(!destination.empty() && state.exists(destination))
throw NotAllowedException(QPID_MSG("Consumer tags must be unique"));
+ if (queue->hasExclusiveOwner() && !queue->isExclusiveOwner(&session))
+ throw ResourceLockedException(QPID_MSG("Cannot subscribe to exclusive queue "
+ << queue->getName()));
+
+ state.consume(destination, queue,
+ acceptMode == 0, acquireMode == 0, exclusive,
+ resumeId, resumeTtl, arguments);
- string tag = destination;
- state.consume(MessageDelivery::getMessageDeliveryToken(destination, acceptMode, acquireMode),
- tag, queue, false, //TODO get rid of no-local
- acceptMode == 0, acquireMode == 0, exclusive, &arguments);
+ ManagementAgent* agent = getBroker().getManagementAgent();
+ if (agent)
+ agent->raiseEvent(_qmf::EventSubscribe(getConnection().getUrl(), getConnection().getUserId(),
+ queueName, destination, exclusive, arguments));
}
void
SessionAdapter::MessageHandlerImpl::cancel(const string& destination )
{
state.cancel(destination);
+
+ ManagementAgent* agent = getBroker().getManagementAgent();
+ if (agent)
+ agent->raiseEvent(_qmf::EventUnsubscribe(getConnection().getUrl(), getConnection().getUserId(), destination));
}
void
@@ -510,8 +557,7 @@ void SessionAdapter::MessageHandlerImpl::stop(const std::string& destination)
void SessionAdapter::MessageHandlerImpl::accept(const framing::SequenceSet& commands)
{
-
- commands.for_each(acceptOp);
+ state.accepted(commands);
}
framing::MessageAcquireResult SessionAdapter::MessageHandlerImpl::acquire(const framing::SequenceSet& transfers)
@@ -595,7 +641,7 @@ XaResult SessionAdapter::DtxHandlerImpl::end(const Xid& xid,
if (suspend) {
throw CommandInvalidException(QPID_MSG("End and suspend cannot both be set."));
} else {
- return XaResult(XA_RBROLLBACK);
+ return XaResult(XA_STATUS_XA_RBROLLBACK);
}
} else {
if (suspend) {
@@ -603,10 +649,10 @@ XaResult SessionAdapter::DtxHandlerImpl::end(const Xid& xid,
} else {
state.endDtx(convert(xid), false);
}
- return XaResult(XA_OK);
+ return XaResult(XA_STATUS_XA_OK);
}
- } catch (const DtxTimeoutException& e) {
- return XaResult(XA_RBTIMEOUT);
+ } catch (const DtxTimeoutException& /*e*/) {
+ return XaResult(XA_STATUS_XA_RBTIMEOUT);
}
}
@@ -623,9 +669,9 @@ XaResult SessionAdapter::DtxHandlerImpl::start(const Xid& xid,
} else {
state.startDtx(convert(xid), getBroker().getDtxManager(), join);
}
- return XaResult(XA_OK);
- } catch (const DtxTimeoutException& e) {
- return XaResult(XA_RBTIMEOUT);
+ return XaResult(XA_STATUS_XA_OK);
+ } catch (const DtxTimeoutException& /*e*/) {
+ return XaResult(XA_STATUS_XA_RBTIMEOUT);
}
}
@@ -633,9 +679,9 @@ XaResult SessionAdapter::DtxHandlerImpl::prepare(const Xid& xid)
{
try {
bool ok = getBroker().getDtxManager().prepare(convert(xid));
- return XaResult(ok ? XA_OK : XA_RBROLLBACK);
- } catch (const DtxTimeoutException& e) {
- return XaResult(XA_RBTIMEOUT);
+ return XaResult(ok ? XA_STATUS_XA_OK : XA_STATUS_XA_RBROLLBACK);
+ } catch (const DtxTimeoutException& /*e*/) {
+ return XaResult(XA_STATUS_XA_RBTIMEOUT);
}
}
@@ -644,9 +690,9 @@ XaResult SessionAdapter::DtxHandlerImpl::commit(const Xid& xid,
{
try {
bool ok = getBroker().getDtxManager().commit(convert(xid), onePhase);
- return XaResult(ok ? XA_OK : XA_RBROLLBACK);
- } catch (const DtxTimeoutException& e) {
- return XaResult(XA_RBTIMEOUT);
+ return XaResult(ok ? XA_STATUS_XA_OK : XA_STATUS_XA_RBROLLBACK);
+ } catch (const DtxTimeoutException& /*e*/) {
+ return XaResult(XA_STATUS_XA_RBTIMEOUT);
}
}
@@ -655,9 +701,9 @@ XaResult SessionAdapter::DtxHandlerImpl::rollback(const Xid& xid)
{
try {
getBroker().getDtxManager().rollback(convert(xid));
- return XaResult(XA_OK);
- } catch (const DtxTimeoutException& e) {
- return XaResult(XA_RBTIMEOUT);
+ return XaResult(XA_STATUS_XA_OK);
+ } catch (const DtxTimeoutException& /*e*/) {
+ return XaResult(XA_STATUS_XA_RBTIMEOUT);
}
}
@@ -699,11 +745,11 @@ void SessionAdapter::DtxHandlerImpl::setTimeout(const Xid& xid,
Queue::shared_ptr SessionAdapter::HandlerHelper::getQueue(const string& name) const {
Queue::shared_ptr queue;
if (name.empty()) {
- throw amqp_0_10::IllegalArgumentException(QPID_MSG("No queue name specified."));
+ throw framing::IllegalArgumentException(QPID_MSG("No queue name specified."));
} else {
queue = session.getBroker().getQueues().find(name);
if (!queue)
- throw amqp_0_10::NotFoundException(QPID_MSG("Queue not found: "<<name));
+ throw framing::NotFoundException(QPID_MSG("Queue not found: "<<name));
}
return queue;
}
diff --git a/cpp/src/qpid/broker/SessionAdapter.h b/cpp/src/qpid/broker/SessionAdapter.h
index 4eaaf13f8d..b69f258037 100644
--- a/cpp/src/qpid/broker/SessionAdapter.h
+++ b/cpp/src/qpid/broker/SessionAdapter.h
@@ -19,15 +19,16 @@
*
*/
-#include "HandlerImpl.h"
+#include "qpid/broker/HandlerImpl.h"
-#include "ConnectionToken.h"
-#include "OwnershipToken.h"
+#include "qpid/broker/ConnectionToken.h"
+#include "qpid/broker/OwnershipToken.h"
#include "qpid/Exception.h"
#include "qpid/framing/AMQP_ServerOperations.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/framing/StructHelper.h"
+#include <algorithm>
#include <vector>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
@@ -68,6 +69,12 @@ class Queue;
FileHandler* getFileHandler() { throw framing::NotImplementedException("Class not implemented"); }
StreamHandler* getStreamHandler() { throw framing::NotImplementedException("Class not implemented"); }
+ template <class F> void eachExclusiveQueue(F f)
+ {
+ queueImpl.eachExclusiveQueue(f);
+ }
+
+
private:
//common base for utility methods etc that are specific to this adapter
struct HandlerHelper : public HandlerImpl
@@ -102,14 +109,14 @@ class Queue;
const std::string& routingKey,
const framing::FieldTable& arguments);
private:
- void checkType(shared_ptr<Exchange> exchange, const std::string& type);
+ void checkType(boost::shared_ptr<Exchange> exchange, const std::string& type);
- void checkAlternate(shared_ptr<Exchange> exchange,
- shared_ptr<Exchange> alternate);
+ void checkAlternate(boost::shared_ptr<Exchange> exchange,
+ boost::shared_ptr<Exchange> alternate);
};
class QueueHandlerImpl : public QueueHandler,
- public HandlerHelper, public OwnershipToken
+ public HandlerHelper
{
Broker& broker;
std::vector< boost::shared_ptr<Queue> > exclusiveQueues;
@@ -130,6 +137,10 @@ class Queue;
bool isLocal(const ConnectionToken* t) const;
void destroyExclusiveQueues();
+ template <class F> void eachExclusiveQueue(F f)
+ {
+ std::for_each(exclusiveQueues.begin(), exclusiveQueues.end(), f);
+ }
};
class MessageHandlerImpl :
diff --git a/cpp/src/qpid/broker/SessionContext.h b/cpp/src/qpid/broker/SessionContext.h
index 7a277964ab..afbbb2cc22 100644
--- a/cpp/src/qpid/broker/SessionContext.h
+++ b/cpp/src/qpid/broker/SessionContext.h
@@ -26,9 +26,9 @@
#include "qpid/framing/AMQP_ClientProxy.h"
#include "qpid/framing/amqp_types.h"
#include "qpid/sys/OutputControl.h"
-#include "ConnectionState.h"
-#include "OwnershipToken.h"
-
+#include "qpid/broker/ConnectionState.h"
+#include "qpid/broker/OwnershipToken.h"
+#include "qpid/SessionId.h"
#include <boost/noncopyable.hpp>
@@ -40,9 +40,12 @@ class SessionContext : public OwnershipToken, public sys::OutputControl
public:
virtual ~SessionContext(){}
virtual bool isLocal(const ConnectionToken* t) const = 0;
+ virtual bool isAttached() const = 0;
virtual ConnectionState& getConnection() = 0;
virtual framing::AMQP_ClientProxy& getProxy() = 0;
virtual Broker& getBroker() = 0;
+ virtual uint16_t getChannel() const = 0;
+ virtual const SessionId& getSessionId() const = 0;
};
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/SessionHandler.cpp b/cpp/src/qpid/broker/SessionHandler.cpp
index c752f6315b..7106f85807 100644
--- a/cpp/src/qpid/broker/SessionHandler.cpp
+++ b/cpp/src/qpid/broker/SessionHandler.cpp
@@ -18,9 +18,9 @@
*
*/
-#include "SessionHandler.h"
-#include "SessionState.h"
-#include "Connection.h"
+#include "qpid/broker/SessionHandler.h"
+#include "qpid/broker/SessionState.h"
+#include "qpid/broker/Connection.h"
#include "qpid/log/Statement.h"
#include <boost/bind.hpp>
@@ -34,7 +34,8 @@ using namespace qpid::sys;
SessionHandler::SessionHandler(Connection& c, ChannelId ch)
: amqp_0_10::SessionHandler(&c.getOutput(), ch),
connection(c),
- proxy(out)
+ proxy(out),
+ clusterOrderProxy(c.getClusterOrderOutput() ? new SetChannelProxy(ch, c.getClusterOrderOutput()) : 0)
{}
SessionHandler::~SessionHandler() {}
@@ -44,12 +45,18 @@ ClassId classId(AMQMethodBody* m) { return m ? m->amqpMethodId() : 0; }
MethodId methodId(AMQMethodBody* m) { return m ? m->amqpClassId() : 0; }
} // namespace
-void SessionHandler::channelException(uint16_t, const std::string&) {
- handleDetach();
+void SessionHandler::connectionException(framing::connection::CloseCode code, const std::string& msg) {
+ // NOTE: must tell the error listener _before_ calling connection.close()
+ if (connection.getErrorListener()) connection.getErrorListener()->connectionError(msg);
+ connection.close(code, msg);
}
-void SessionHandler::connectionException(uint16_t code, const std::string& msg) {
- connection.close(code, msg, 0, 0);
+void SessionHandler::channelException(framing::session::DetachCode, const std::string& msg) {
+ if (connection.getErrorListener()) connection.getErrorListener()->sessionError(getChannel(), msg);
+}
+
+void SessionHandler::executionException(framing::execution::ErrorCode, const std::string& msg) {
+ if (connection.getErrorListener()) connection.getErrorListener()->sessionError(getChannel(), msg);
}
ConnectionState& SessionHandler::getConnection() { return connection; }
@@ -71,6 +78,12 @@ void SessionHandler::setState(const std::string& name, bool force) {
session = connection.broker.getSessionManager().attach(*this, id, force);
}
+void SessionHandler::detaching()
+{
+ assert(session.get());
+ session->disableOutput();
+}
+
FrameHandler* SessionHandler::getInHandler() { return session.get() ? &session->in : 0; }
qpid::SessionState* SessionHandler::getState() { return session.get(); }
@@ -78,18 +91,31 @@ void SessionHandler::readyToSend() {
if (session.get()) session->readyToSend();
}
-// TODO aconway 2008-05-12: hacky - handle attached for bridge clients.
-// We need to integrate the client code so we can run a real client
-// in the bridge.
-//
-void SessionHandler::attached(const std::string& name) {
- if (session.get())
- checkName(name);
- else {
+/**
+ * Used by inter-broker bridges to set up session id and attach
+ */
+void SessionHandler::attachAs(const std::string& name)
+{
+ SessionId id(connection.getUserId(), name);
+ SessionState::Configuration config = connection.broker.getSessionManager().getSessionConfig();
+ session.reset(new SessionState(connection.getBroker(), *this, id, config));
+ sendAttach(false);
+}
+
+/**
+ * TODO: this is a little ugly, fix it; its currently still relied on
+ * for 'push' bridges
+ */
+void SessionHandler::attached(const std::string& name)
+{
+ if (session.get()) {
+ amqp_0_10::SessionHandler::attached(name);
+ } else {
SessionId id(connection.getUserId(), name);
SessionState::Configuration config = connection.broker.getSessionManager().getSessionConfig();
session.reset(new SessionState(connection.getBroker(), *this, id, config));
-}
+ markReadyToSend();
+ }
}
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/SessionHandler.h b/cpp/src/qpid/broker/SessionHandler.h
index 1aa3137fdf..ca6d6bb193 100644
--- a/cpp/src/qpid/broker/SessionHandler.h
+++ b/cpp/src/qpid/broker/SessionHandler.h
@@ -54,23 +54,42 @@ class SessionHandler : public amqp_0_10::SessionHandler {
framing::AMQP_ClientProxy& getProxy() { return proxy; }
const framing::AMQP_ClientProxy& getProxy() const { return proxy; }
+ /**
+ * If commands are sent based on the local time (e.g. in timers), they don't have
+ * a well-defined ordering across cluster nodes.
+ * This proxy is for sending such commands. In a clustered broker it will take steps
+ * to synchronize command order across the cluster. In a stand-alone broker
+ * it is just a synonym for getProxy()
+ */
+ framing::AMQP_ClientProxy& getClusterOrderProxy() {
+ return clusterOrderProxy.get() ? *clusterOrderProxy : proxy;
+ }
+
virtual void handleDetach();
-
- // Overrides
- void attached(const std::string& name);
+ void attached(const std::string& name);//used by 'pushing' inter-broker bridges
+ void attachAs(const std::string& name);//used by 'pulling' inter-broker bridges
protected:
virtual void setState(const std::string& sessionName, bool force);
virtual qpid::SessionState* getState();
virtual framing::FrameHandler* getInHandler();
- virtual void channelException(uint16_t code, const std::string& msg);
- virtual void connectionException(uint16_t code, const std::string& msg);
+ virtual void connectionException(framing::connection::CloseCode code, const std::string& msg);
+ virtual void channelException(framing::session::DetachCode, const std::string& msg);
+ virtual void executionException(framing::execution::ErrorCode, const std::string& msg);
+ virtual void detaching();
virtual void readyToSend();
private:
+ struct SetChannelProxy : public framing::AMQP_ClientProxy { // Proxy that sets the channel.
+ framing::ChannelHandler setChannel;
+ SetChannelProxy(uint16_t ch, framing::FrameHandler* out)
+ : framing::AMQP_ClientProxy(setChannel), setChannel(ch, out) {}
+ };
+
Connection& connection;
framing::AMQP_ClientProxy proxy;
std::auto_ptr<SessionState> session;
+ std::auto_ptr<SetChannelProxy> clusterOrderProxy;
};
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/SessionManager.cpp b/cpp/src/qpid/broker/SessionManager.cpp
index e7190fdae6..996a02f4c6 100644
--- a/cpp/src/qpid/broker/SessionManager.cpp
+++ b/cpp/src/qpid/broker/SessionManager.cpp
@@ -19,8 +19,8 @@
*
*/
-#include "SessionManager.h"
-#include "SessionState.h"
+#include "qpid/broker/SessionManager.h"
+#include "qpid/broker/SessionState.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/log/Statement.h"
#include "qpid/log/Helpers.h"
@@ -86,9 +86,14 @@ void SessionManager::forget(const SessionId& id) {
void SessionManager::eraseExpired() {
// Called with lock held.
if (!detached.empty()) {
- Detached::iterator keep = std::lower_bound(
- detached.begin(), detached.end(), now(),
- boost::bind(std::less<AbsTime>(), boost::bind(&SessionState::expiry, _1), _2));
+ // This used to use a more elegant invocation of std::lower_bound
+ // but violated the strict weak ordering rule which Visual Studio
+ // enforced. See QPID-1424 for more info should you be tempted to
+ // replace the loop with something more elegant.
+ AbsTime now = AbsTime::now();
+ Detached::iterator keep = detached.begin();
+ while ((keep != detached.end()) && ((*keep).expiry < now))
+ keep++;
if (detached.begin() != keep) {
QPID_LOG(debug, "Expiring sessions: " << log::formatList(detached.begin(), keep));
detached.erase(detached.begin(), keep);
diff --git a/cpp/src/qpid/broker/SessionState.cpp b/cpp/src/qpid/broker/SessionState.cpp
index aa6f6b7520..4c5aaf7fc4 100644
--- a/cpp/src/qpid/broker/SessionState.cpp
+++ b/cpp/src/qpid/broker/SessionState.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -18,18 +18,22 @@
* under the License.
*
*/
-#include "SessionState.h"
-#include "Broker.h"
-#include "ConnectionState.h"
-#include "MessageDelivery.h"
-#include "SessionManager.h"
-#include "SessionHandler.h"
+#include "qpid/broker/SessionState.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/broker/ConnectionState.h"
+#include "qpid/broker/DeliveryRecord.h"
+#include "qpid/broker/SessionManager.h"
+#include "qpid/broker/SessionHandler.h"
+#include "qpid/broker/RateFlowcontrol.h"
+#include "qpid/sys/Timer.h"
#include "qpid/framing/AMQContentBody.h"
#include "qpid/framing/AMQHeaderBody.h"
#include "qpid/framing/AMQMethodBody.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/framing/ServerInvoker.h"
#include "qpid/log/Statement.h"
+#include "qpid/management/ManagementAgent.h"
+#include "qpid/framing/AMQP_ClientProxy.h"
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
@@ -44,36 +48,51 @@ using qpid::management::ManagementAgent;
using qpid::management::ManagementObject;
using qpid::management::Manageable;
using qpid::management::Args;
+using qpid::sys::AbsTime;
+//using qpid::sys::Timer;
+namespace _qmf = qmf::org::apache::qpid::broker;
SessionState::SessionState(
- Broker& b, SessionHandler& h, const SessionId& id, const SessionState::Configuration& config)
+ Broker& b, SessionHandler& h, const SessionId& id, const SessionState::Configuration& config)
: qpid::SessionState(id, config),
broker(b), handler(&h),
- ignoring(false),
semanticState(*this, *this),
adapter(semanticState),
msgBuilder(&broker.getStore(), broker.getStagingThreshold()),
enqueuedOp(boost::bind(&SessionState::enqueued, this, _1)),
- mgmtObject(0)
+ mgmtObject(0),
+ rateFlowcontrol(0)
{
+ uint32_t maxRate = broker.getOptions().maxSessionRate;
+ if (maxRate) {
+ if (handler->getConnection().getClientThrottling()) {
+ rateFlowcontrol.reset(new RateFlowcontrol(maxRate));
+ } else {
+ QPID_LOG(warning, getId() << ": Unable to flow control client - client doesn't support");
+ }
+ }
Manageable* parent = broker.GetVhostObject ();
if (parent != 0) {
- ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ ManagementAgent* agent = getBroker().getManagementAgent();
if (agent != 0) {
- mgmtObject = new management::Session (agent, this, parent, getId().getName());
+ mgmtObject = new _qmf::Session
+ (agent, this, parent, getId().getName());
mgmtObject->set_attached (0);
mgmtObject->set_detachedLifespan (0);
- agent->addObject (mgmtObject);
+ mgmtObject->clr_expireTime();
+ if (rateFlowcontrol) mgmtObject->set_maxClientRate(maxRate);
+ agent->addObject (mgmtObject, agent->allocateId(this));
}
}
attach(h);
}
SessionState::~SessionState() {
- // Remove ID from active session list.
- broker.getSessionManager().forget(getId());
if (mgmtObject != 0)
mgmtObject->resourceDestroy ();
+
+ if (flowControlTimer)
+ flowControlTimer->cancel();
}
AMQP_ClientProxy& SessionState::getProxy() {
@@ -81,6 +100,11 @@ AMQP_ClientProxy& SessionState::getProxy() {
return handler->getProxy();
}
+uint16_t SessionState::getChannel() const {
+ assert(isAttached());
+ return handler->getChannel();
+}
+
ConnectionState& SessionState::getConnection() {
assert(isAttached());
return handler->getConnection();
@@ -92,18 +116,19 @@ bool SessionState::isLocal(const ConnectionToken* t) const
}
void SessionState::detach() {
- // activateOutput can be called in a different thread, lock to protect attached status
- Mutex::ScopedLock l(lock);
QPID_LOG(debug, getId() << ": detached on broker.");
- getConnection().outputTasks.removeOutputTask(&semanticState);
+ disableOutput();
handler = 0;
if (mgmtObject != 0)
mgmtObject->set_attached (0);
}
+void SessionState::disableOutput()
+{
+ semanticState.detached(); //prevents further activateOutput calls until reattached
+}
+
void SessionState::attach(SessionHandler& h) {
- // activateOutput can be called in a different thread, lock to protect attached status
- Mutex::ScopedLock l(lock);
QPID_LOG(debug, getId() << ": attached on broker.");
handler = &h;
if (mgmtObject != 0)
@@ -114,34 +139,42 @@ void SessionState::attach(SessionHandler& h) {
}
}
+void SessionState::abort() {
+ if (isAttached())
+ getConnection().outputTasks.abort();
+}
+
void SessionState::activateOutput() {
- // activateOutput can be called in a different thread, lock to protect attached status
- Mutex::ScopedLock l(lock);
- if (isAttached())
+ if (isAttached())
getConnection().outputTasks.activateOutput();
}
+void SessionState::giveReadCredit(int32_t credit) {
+ if (isAttached())
+ getConnection().outputTasks.giveReadCredit(credit);
+}
+
ManagementObject* SessionState::GetManagementObject (void) const
{
return (ManagementObject*) mgmtObject;
}
Manageable::status_t SessionState::ManagementMethod (uint32_t methodId,
- Args& /*args*/)
+ Args& /*args*/,
+ string& /*text*/)
{
Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD;
switch (methodId)
{
- case management::Session::METHOD_DETACH :
- if (handler != 0)
- {
+ case _qmf::Session::METHOD_DETACH :
+ if (handler != 0) {
handler->sendDetach();
}
status = Manageable::STATUS_OK;
break;
- case management::Session::METHOD_CLOSE :
+ case _qmf::Session::METHOD_CLOSE :
/*
if (handler != 0)
{
@@ -151,8 +184,8 @@ Manageable::status_t SessionState::ManagementMethod (uint32_t methodId,
break;
*/
- case management::Session::METHOD_SOLICITACK :
- case management::Session::METHOD_RESETLIFESPAN :
+ case _qmf::Session::METHOD_SOLICITACK :
+ case _qmf::Session::METHOD_RESETLIFESPAN :
status = Manageable::STATUS_NOT_IMPLEMENTED;
break;
}
@@ -162,18 +195,42 @@ Manageable::status_t SessionState::ManagementMethod (uint32_t methodId,
void SessionState::handleCommand(framing::AMQMethodBody* method, const SequenceNumber& id) {
Invoker::Result invocation = invoke(adapter, *method);
- receiverCompleted(id);
+ receiverCompleted(id);
if (!invocation.wasHandled()) {
throw NotImplementedException(QPID_MSG("Not implemented: " << *method));
} else if (invocation.hasResult()) {
getProxy().getExecution().result(id, invocation.getResult());
}
- if (method->isSync()) {
+ if (method->isSync()) {
incomplete.process(enqueuedOp, true);
- sendCompletion();
+ sendAcceptAndCompletion();
}
}
+struct ScheduledCreditTask : public sys::TimerTask {
+ sys::Timer& timer;
+ SessionState& sessionState;
+ ScheduledCreditTask(const qpid::sys::Duration& d, sys::Timer& t,
+ SessionState& s) :
+ TimerTask(d),
+ timer(t),
+ sessionState(s)
+ {}
+
+ void fire() {
+ // This is the best we can currently do to avoid a destruction/fire race
+ sessionState.getConnection().requestIOProcessing(boost::bind(&ScheduledCreditTask::sendCredit, this));
+ }
+
+ void sendCredit() {
+ if ( !sessionState.processSendCredit(0) ) {
+ QPID_LOG(warning, sessionState.getId() << ": Reschedule sending credit");
+ setupNextFire();
+ timer.add(this);
+ }
+ }
+};
+
void SessionState::handleContent(AMQFrame& frame, const SequenceNumber& id)
{
if (frame.getBof() && frame.getBos()) //start of frameset
@@ -183,14 +240,13 @@ void SessionState::handleContent(AMQFrame& frame, const SequenceNumber& id)
if (frame.getEof() && frame.getEos()) {//end of frameset
if (frame.getBof()) {
//i.e this is a just a command frame, add a dummy header
- AMQFrame header;
- header.setBody(AMQHeaderBody());
+ AMQFrame header((AMQHeaderBody()));
header.setBof(false);
header.setEof(false);
- msg->getFrames().append(header);
+ msg->getFrames().append(header);
}
msg->setPublisher(&getConnection());
- semanticState.handle(msg);
+ semanticState.handle(msg);
msgBuilder.end();
if (msg->isEnqueueComplete()) {
@@ -199,51 +255,80 @@ void SessionState::handleContent(AMQFrame& frame, const SequenceNumber& id)
incomplete.add(msg);
}
- //hold up execution until async enqueue is complete
- if (msg->getFrames().getMethod()->isSync()) {
+ //hold up execution until async enqueue is complete
+ if (msg->getFrames().getMethod()->isSync()) {
incomplete.process(enqueuedOp, true);
- sendCompletion();
+ sendAcceptAndCompletion();
} else {
incomplete.process(enqueuedOp, false);
}
}
+
+ // Handle producer session flow control
+ if (rateFlowcontrol && frame.getBof() && frame.getBos()) {
+ if ( !processSendCredit(1) ) {
+ QPID_LOG(debug, getId() << ": Schedule sending credit");
+ sys::Timer& timer = getBroker().getTimer();
+ // Use heuristic for scheduled credit of time for 50 messages, but not longer than 500ms
+ sys::Duration d = std::min(sys::TIME_SEC * 50 / rateFlowcontrol->getRate(), 500 * sys::TIME_MSEC);
+ flowControlTimer = new ScheduledCreditTask(d, timer, *this);
+ timer.add(flowControlTimer);
+ }
+ }
+}
+
+bool SessionState::processSendCredit(uint32_t msgs)
+{
+ qpid::sys::ScopedLock<Mutex> l(rateLock);
+ // Check for violating flow control
+ if ( msgs > 0 && rateFlowcontrol->flowStopped() ) {
+ QPID_LOG(warning, getId() << ": producer throttling violation");
+ // TODO: Probably do message.stop("") first time then disconnect
+ // See comment on getClusterOrderProxy() in .h file
+ getClusterOrderProxy().getMessage().stop("");
+ return true;
+ }
+ AbsTime now = AbsTime::now();
+ uint32_t sendCredit = rateFlowcontrol->receivedMessage(now, msgs);
+ if (mgmtObject) mgmtObject->dec_clientCredit(msgs);
+ if ( sendCredit>0 ) {
+ QPID_LOG(debug, getId() << ": send producer credit " << sendCredit);
+ getClusterOrderProxy().getMessage().flow("", 0, sendCredit);
+ rateFlowcontrol->sentCredit(now, sendCredit);
+ if (mgmtObject) mgmtObject->inc_clientCredit(sendCredit);
+ return true;
+ } else {
+ return !rateFlowcontrol->flowStopped() ;
+ }
+}
+
+void SessionState::sendAcceptAndCompletion()
+{
+ if (!accepted.empty()) {
+ getProxy().getMessage().accept(accepted);
+ accepted.clear();
+ }
+ sendCompletion();
}
void SessionState::enqueued(boost::intrusive_ptr<Message> msg)
{
receiverCompleted(msg->getCommandId());
- if (msg->requiresAccept())
- getProxy().getMessage().accept(SequenceSet(msg->getCommandId()));
+ if (msg->requiresAccept())
+ accepted.add(msg->getCommandId());
}
void SessionState::handleIn(AMQFrame& frame) {
SequenceNumber commandId = receiverGetCurrent();
- try {
- //TODO: make command handling more uniform, regardless of whether
- //commands carry content.
- AMQMethodBody* m = frame.getMethod();
- if (m == 0 || m->isContentBearing()) {
- handleContent(frame, commandId);
- } else if (frame.getBof() && frame.getEof()) {
- handleCommand(frame.getMethod(), commandId);
- } else {
- throw InternalErrorException("Cannot handle multi-frame command segments yet");
- }
- } catch(const SessionException& e) {
- //TODO: better implementation of new exception handling mechanism
-
- //0-10 final changes the types of exceptions, 'model layer'
- //exceptions will all be session exceptions regardless of
- //current channel/connection classification
-
- AMQMethodBody* m = frame.getMethod();
- if (m) {
- getProxy().getExecution().exception(e.code, commandId, m->amqpClassId(), m->amqpMethodId(), 0, e.what(), FieldTable());
- } else {
- getProxy().getExecution().exception(e.code, commandId, 0, 0, 0, e.what(), FieldTable());
- }
- ignoring = true;
- handler->sendDetach();
+ //TODO: make command handling more uniform, regardless of whether
+ //commands carry content.
+ AMQMethodBody* m = frame.getMethod();
+ if (m == 0 || m->isContentBearing()) {
+ handleContent(frame, commandId);
+ } else if (frame.getBof() && frame.getEof()) {
+ handleCommand(frame.getMethod(), commandId);
+ } else {
+ throw InternalErrorException("Cannot handle multi-frame command segments yet");
}
}
@@ -252,32 +337,50 @@ void SessionState::handleOut(AMQFrame& frame) {
handler->out(frame);
}
-DeliveryId SessionState::deliver(QueuedMessage& msg, DeliveryToken::shared_ptr token)
+void SessionState::deliver(DeliveryRecord& msg, bool sync)
{
uint32_t maxFrameSize = getConnection().getFrameMax();
assert(senderGetCommandPoint().offset == 0);
SequenceNumber commandId = senderGetCommandPoint().command;
- MessageDelivery::deliver(msg, getProxy().getHandler(), commandId, token, maxFrameSize);
+ msg.deliver(getProxy().getHandler(), commandId, maxFrameSize);
assert(senderGetCommandPoint() == SessionPoint(commandId+1, 0)); // Delivery has moved sendPoint.
- return commandId;
+ if (sync) {
+ AMQP_ClientProxy::Execution& p(getProxy().getExecution());
+ Proxy::ScopedSync s(p);
+ p.sync();
+ }
}
-void SessionState::sendCompletion() { handler->sendCompletion(); }
+void SessionState::sendCompletion() {
+ handler->sendCompletion();
+}
void SessionState::senderCompleted(const SequenceSet& commands) {
qpid::SessionState::senderCompleted(commands);
- for (SequenceSet::RangeIterator i = commands.rangesBegin(); i != commands.rangesEnd(); i++)
- semanticState.completed(i->first(), i->last());
+ semanticState.completed(commands);
}
void SessionState::readyToSend() {
QPID_LOG(debug, getId() << ": ready to send, activating output.");
assert(handler);
- sys::AggregateOutput& tasks = handler->getConnection().outputTasks;
- tasks.addOutputTask(&semanticState);
- tasks.activateOutput();
+ semanticState.attached();
+ if (rateFlowcontrol) {
+ qpid::sys::ScopedLock<Mutex> l(rateLock);
+ // Issue initial credit - use a heuristic here issue min of 300 messages or 1 secs worth
+ uint32_t credit = std::min(rateFlowcontrol->getRate(), 300U);
+ QPID_LOG(debug, getId() << ": Issuing producer message credit " << credit);
+ // See comment on getClusterOrderProxy() in .h file
+ getClusterOrderProxy().getMessage().setFlowMode("", 0);
+ getClusterOrderProxy().getMessage().flow("", 0, credit);
+ rateFlowcontrol->sentCredit(AbsTime::now(), credit);
+ if (mgmtObject) mgmtObject->inc_clientCredit(credit);
+ }
}
Broker& SessionState::getBroker() { return broker; }
+framing::AMQP_ClientProxy& SessionState::getClusterOrderProxy() {
+ return handler->getClusterOrderProxy();
+}
+
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/SessionState.h b/cpp/src/qpid/broker/SessionState.h
index 96f2e8f512..eade93ddaa 100644
--- a/cpp/src/qpid/broker/SessionState.h
+++ b/cpp/src/qpid/broker/SessionState.h
@@ -25,16 +25,15 @@
#include "qpid/SessionState.h"
#include "qpid/framing/FrameHandler.h"
#include "qpid/framing/SequenceSet.h"
-#include "qpid/sys/Mutex.h"
#include "qpid/sys/Time.h"
#include "qpid/management/Manageable.h"
-#include "qpid/management/Session.h"
-#include "SessionAdapter.h"
-#include "DeliveryAdapter.h"
-#include "IncompleteMessageList.h"
-#include "MessageBuilder.h"
-#include "SessionContext.h"
-#include "SemanticState.h"
+#include "qmf/org/apache/qpid/broker/Session.h"
+#include "qpid/broker/SessionAdapter.h"
+#include "qpid/broker/DeliveryAdapter.h"
+#include "qpid/broker/IncompleteMessageList.h"
+#include "qpid/broker/MessageBuilder.h"
+#include "qpid/broker/SessionContext.h"
+#include "qpid/broker/SemanticState.h"
#include <boost/noncopyable.hpp>
#include <boost/scoped_ptr.hpp>
@@ -49,6 +48,10 @@ namespace framing {
class AMQP_ClientProxy;
}
+namespace sys {
+class TimerTask;
+}
+
namespace broker {
class Broker;
@@ -56,12 +59,13 @@ class ConnectionState;
class Message;
class SessionHandler;
class SessionManager;
+class RateFlowcontrol;
/**
* Broker-side session state includes session's handler chains, which
* may themselves have state.
*/
-class SessionState : public qpid::SessionState,
+class SessionState : public qpid::SessionState,
public SessionContext,
public DeliveryAdapter,
public management::Manageable,
@@ -74,10 +78,14 @@ class SessionState : public qpid::SessionState,
void detach();
void attach(SessionHandler& handler);
+ void disableOutput();
/** @pre isAttached() */
framing::AMQP_ClientProxy& getProxy();
-
+
+ /** @pre isAttached() */
+ uint16_t getChannel() const;
+
/** @pre isAttached() */
ConnectionState& getConnection();
bool isLocal(const ConnectionToken* t) const;
@@ -85,22 +93,33 @@ class SessionState : public qpid::SessionState,
Broker& getBroker();
/** OutputControl **/
+ void abort();
void activateOutput();
+ void giveReadCredit(int32_t);
void senderCompleted(const framing::SequenceSet& ranges);
-
+
void sendCompletion();
//delivery adapter methods:
- DeliveryId deliver(QueuedMessage& msg, DeliveryToken::shared_ptr token);
+ void deliver(DeliveryRecord&, bool sync);
// Manageable entry points
management::ManagementObject* GetManagementObject (void) const;
management::Manageable::status_t
- ManagementMethod (uint32_t methodId, management::Args& args);
+ ManagementMethod (uint32_t methodId, management::Args& args, std::string&);
void readyToSend();
+ // Used by cluster to create replica sessions.
+ SemanticState& getSemanticState() { return semanticState; }
+ boost::intrusive_ptr<Message> getMessageInProgress() { return msgBuilder.getMessage(); }
+ SessionAdapter& getSessionAdapter() { return adapter; }
+
+ bool processSendCredit(uint32_t msgs);
+
+ const SessionId& getSessionId() const { return getId(); }
+
private:
void handleCommand(framing::AMQMethodBody* method, const framing::SequenceNumber& id);
@@ -114,20 +133,34 @@ class SessionState : public qpid::SessionState,
void handleInLast(framing::AMQFrame& frame);
void handleOutLast(framing::AMQFrame& frame);
+ void sendAcceptAndCompletion();
+
+ /**
+ * If commands are sent based on the local time (e.g. in timers), they don't have
+ * a well-defined ordering across cluster nodes.
+ * This proxy is for sending such commands. In a clustered broker it will take steps
+ * to synchronize command order across the cluster. In a stand-alone broker
+ * it is just a synonym for getProxy()
+ */
+ framing::AMQP_ClientProxy& getClusterOrderProxy();
+
Broker& broker;
- SessionHandler* handler;
+ SessionHandler* handler;
sys::AbsTime expiry; // Used by SessionManager.
- sys::Mutex lock;
- bool ignoring;
- std::string name;
SemanticState semanticState;
SessionAdapter adapter;
MessageBuilder msgBuilder;
IncompleteMessageList incomplete;
IncompleteMessageList::CompletionListener enqueuedOp;
- management::Session* mgmtObject;
+ qmf::org::apache::qpid::broker::Session* mgmtObject;
+ qpid::framing::SequenceSet accepted;
+
+ // State used for producer flow control (rate limited)
+ qpid::sys::Mutex rateLock;
+ boost::scoped_ptr<RateFlowcontrol> rateFlowcontrol;
+ boost::intrusive_ptr<sys::TimerTask> flowControlTimer;
- friend class SessionManager;
+ friend class SessionManager;
};
diff --git a/cpp/src/qpid/broker/SignalHandler.cpp b/cpp/src/qpid/broker/SignalHandler.cpp
index fee54cfdfc..b565cfd419 100644
--- a/cpp/src/qpid/broker/SignalHandler.cpp
+++ b/cpp/src/qpid/broker/SignalHandler.cpp
@@ -18,8 +18,8 @@
* under the License.
*
*/
-#include "SignalHandler.h"
-#include "Broker.h"
+#include "qpid/broker/SignalHandler.h"
+#include "qpid/broker/Broker.h"
#include <signal.h>
namespace qpid {
@@ -36,11 +36,10 @@ void SignalHandler::setBroker(const boost::intrusive_ptr<Broker>& b) {
signal(SIGHUP,SIG_IGN); // TODO aconway 2007-07-18: reload config.
signal(SIGCHLD,SIG_IGN);
- signal(SIGTSTP,SIG_IGN);
- signal(SIGTTOU,SIG_IGN);
- signal(SIGTTIN,SIG_IGN);
}
+void SignalHandler::shutdown() { shutdownHandler(0); }
+
void SignalHandler::shutdownHandler(int) {
if (broker.get()) {
broker->shutdown();
diff --git a/cpp/src/qpid/broker/SignalHandler.h b/cpp/src/qpid/broker/SignalHandler.h
index d2cdfae07c..bbe831b61d 100644
--- a/cpp/src/qpid/broker/SignalHandler.h
+++ b/cpp/src/qpid/broker/SignalHandler.h
@@ -38,6 +38,9 @@ class SignalHandler
/** Set the broker to be shutdown on signals */
static void setBroker(const boost::intrusive_ptr<Broker>& broker);
+ /** Initiate shut-down of broker */
+ static void shutdown();
+
private:
static void shutdownHandler(int);
static boost::intrusive_ptr<Broker> broker;
diff --git a/cpp/src/qpid/broker/System.cpp b/cpp/src/qpid/broker/System.cpp
index 6c58339432..455ad11cf2 100644
--- a/cpp/src/qpid/broker/System.cpp
+++ b/cpp/src/qpid/broker/System.cpp
@@ -17,20 +17,22 @@
// under the License.
//
-#include "System.h"
-#include "qpid/agent/ManagementAgent.h"
+#include "qpid/broker/System.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/management/ManagementAgent.h"
#include "qpid/framing/Uuid.h"
-#include <sys/utsname.h>
+#include "qpid/sys/SystemInfo.h"
#include <iostream>
#include <fstream>
using qpid::management::ManagementAgent;
using namespace qpid::broker;
using namespace std;
+namespace _qmf = qmf::org::apache::qpid::broker;
-System::System (string _dataDir) : mgmtObject(0)
+System::System (string _dataDir, Broker* broker) : mgmtObject(0)
{
- ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ ManagementAgent* agent = broker ? broker->getManagementAgent() : 0;
if (agent != 0)
{
@@ -62,18 +64,20 @@ System::System (string _dataDir) : mgmtObject(0)
}
}
- mgmtObject = new management::System (agent, this, systemId);
- struct utsname _uname;
- if (uname (&_uname) == 0)
- {
- mgmtObject->set_osName (std::string (_uname.sysname));
- mgmtObject->set_nodeName (std::string (_uname.nodename));
- mgmtObject->set_release (std::string (_uname.release));
- mgmtObject->set_version (std::string (_uname.version));
- mgmtObject->set_machine (std::string (_uname.machine));
- }
+ mgmtObject = new _qmf::System (agent, this, systemId);
+ std::string sysname, nodename, release, version, machine;
+ qpid::sys::SystemInfo::getSystemId (sysname,
+ nodename,
+ release,
+ version,
+ machine);
+ mgmtObject->set_osName (sysname);
+ mgmtObject->set_nodeName (nodename);
+ mgmtObject->set_release (release);
+ mgmtObject->set_version (version);
+ mgmtObject->set_machine (machine);
- agent->addObject (mgmtObject, 1, 1);
+ agent->addObject (mgmtObject, 0x1000000000000001LL);
}
}
diff --git a/cpp/src/qpid/broker/System.h b/cpp/src/qpid/broker/System.h
index ef7c6ba73b..0fc2c2bd88 100644
--- a/cpp/src/qpid/broker/System.h
+++ b/cpp/src/qpid/broker/System.h
@@ -21,24 +21,26 @@
//
#include "qpid/management/Manageable.h"
-#include "qpid/management/System.h"
+#include "qmf/org/apache/qpid/broker/System.h"
#include <boost/shared_ptr.hpp>
#include <string>
namespace qpid {
namespace broker {
+class Broker;
+
class System : public management::Manageable
{
private:
- management::System* mgmtObject;
+ qmf::org::apache::qpid::broker::System* mgmtObject;
public:
typedef boost::shared_ptr<System> shared_ptr;
- System (std::string _dataDir);
+ System (std::string _dataDir, Broker* broker = 0);
management::ManagementObject* GetManagementObject (void) const
{ return mgmtObject; }
diff --git a/cpp/src/qpid/broker/Timer.cpp b/cpp/src/qpid/broker/Timer.cpp
deleted file mode 100644
index 0b0d3ba63d..0000000000
--- a/cpp/src/qpid/broker/Timer.cpp
+++ /dev/null
@@ -1,104 +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 "Timer.h"
-#include <iostream>
-
-using boost::intrusive_ptr;
-using qpid::sys::AbsTime;
-using qpid::sys::Duration;
-using qpid::sys::Monitor;
-using qpid::sys::Thread;
-using namespace qpid::broker;
-
-TimerTask::TimerTask(Duration timeout) :
- duration(timeout), time(AbsTime::now(), timeout), cancelled(false) {}
-
-TimerTask::TimerTask(AbsTime _time) :
- duration(0), time(_time), cancelled(false) {}
-
-TimerTask::~TimerTask(){}
-
-void TimerTask::reset() { time = AbsTime(AbsTime::now(), duration); }
-
-Timer::Timer() : active(false)
-{
- start();
-}
-
-Timer::~Timer()
-{
- stop();
-}
-
-void Timer::run()
-{
- Monitor::ScopedLock l(monitor);
- while(active){
- if (tasks.empty()) {
- monitor.wait();
- } else {
- intrusive_ptr<TimerTask> t = tasks.top();
- if (t->cancelled) {
- tasks.pop();
- } else if(t->time < AbsTime::now()) {
- tasks.pop();
- Monitor::ScopedUnlock u(monitor);
- t->fire();
- } else {
- monitor.wait(t->time);
- }
- }
- }
-}
-
-void Timer::add(intrusive_ptr<TimerTask> task)
-{
- Monitor::ScopedLock l(monitor);
- tasks.push(task);
- monitor.notify();
-}
-
-void Timer::start()
-{
- Monitor::ScopedLock l(monitor);
- if (!active) {
- active = true;
- runner = Thread(this);
- }
-}
-
-void Timer::stop()
-{
- {
- Monitor::ScopedLock l(monitor);
- if (!active) return;
- active = false;
- monitor.notifyAll();
- }
- runner.join();
-}
-
-bool Later::operator()(const intrusive_ptr<TimerTask>& a,
- const intrusive_ptr<TimerTask>& b) const
-{
- return a.get() && b.get() && a->time > b->time;
-}
-
diff --git a/cpp/src/qpid/broker/Timer.h b/cpp/src/qpid/broker/Timer.h
deleted file mode 100644
index f702f0f32d..0000000000
--- a/cpp/src/qpid/broker/Timer.h
+++ /dev/null
@@ -1,79 +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.
- *
- */
-#ifndef _Timer_
-#define _Timer_
-
-#include "qpid/sys/Monitor.h"
-#include "qpid/sys/Thread.h"
-#include "qpid/sys/Runnable.h"
-#include "qpid/RefCounted.h"
-
-#include <memory>
-#include <queue>
-
-#include <boost/intrusive_ptr.hpp>
-
-namespace qpid {
-namespace broker {
-
-struct TimerTask : public RefCounted {
- const qpid::sys::Duration duration;
- qpid::sys::AbsTime time;
- volatile bool cancelled;
-
- TimerTask(qpid::sys::Duration timeout);
- TimerTask(qpid::sys::AbsTime time);
- virtual ~TimerTask();
- void reset();
- virtual void fire() = 0;
-};
-
-struct Later {
- bool operator()(const boost::intrusive_ptr<TimerTask>& a,
- const boost::intrusive_ptr<TimerTask>& b) const;
-};
-
-class Timer : private qpid::sys::Runnable {
- protected:
- qpid::sys::Monitor monitor;
- std::priority_queue<boost::intrusive_ptr<TimerTask>,
- std::vector<boost::intrusive_ptr<TimerTask> >,
- Later> tasks;
- qpid::sys::Thread runner;
- bool active;
-
- virtual void run();
-
- public:
- Timer();
- virtual ~Timer();
-
- void add(boost::intrusive_ptr<TimerTask> task);
- void start();
- void stop();
-
-};
-
-
-}}
-
-
-#endif
diff --git a/cpp/src/qpid/broker/TopicExchange.cpp b/cpp/src/qpid/broker/TopicExchange.cpp
index 48d6e88503..dd57549b5d 100644
--- a/cpp/src/qpid/broker/TopicExchange.cpp
+++ b/cpp/src/qpid/broker/TopicExchange.cpp
@@ -18,138 +18,249 @@
* under the License.
*
*/
-#include "TopicExchange.h"
+#include "qpid/broker/TopicExchange.h"
#include <algorithm>
-using namespace qpid::broker;
+
+namespace qpid {
+namespace broker {
+
using namespace qpid::framing;
using namespace qpid::sys;
+using namespace std;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
// TODO aconway 2006-09-20: More efficient matching algorithm.
// Areas for improvement:
// - excessive string copying: should be 0 copy, match from original buffer.
// - match/lookup: use descision tree or other more efficient structure.
-Tokens& Tokens::operator=(const std::string& s) {
- clear();
- if (s.empty()) return *this;
- std::string::const_iterator i = s.begin();
- while (true) {
- // Invariant: i is at the beginning of the next untokenized word.
- std::string::const_iterator j = std::find(i, s.end(), '.');
- push_back(std::string(i, j));
- if (j == s.end()) return *this;
- i = j + 1;
- }
- return *this;
-}
+namespace
+{
+const std::string qpidFedOp("qpid.fed.op");
+const std::string qpidFedTags("qpid.fed.tags");
+const std::string qpidFedOrigin("qpid.fed.origin");
-TopicPattern& TopicPattern::operator=(const Tokens& tokens) {
- Tokens::operator=(tokens);
- normalize();
- return *this;
+const std::string fedOpBind("B");
+const std::string fedOpUnbind("U");
+const std::string fedOpReorigin("R");
+const std::string fedOpHello("H");
}
+
namespace {
-const std::string hashmark("#");
-const std::string star("*");
-}
+// Iterate over a string of '.'-separated tokens.
+struct TokenIterator {
+ typedef pair<const char*,const char*> Token;
+
+ TokenIterator(const char* b, const char* e) : token(make_pair(b, find(b,e,'.'))), end(e) {}
+
+ bool finished() const { return !token.first; }
+
+ void next() {
+ if (token.second == end)
+ token.first = token.second = 0;
+ else {
+ token.first=token.second+1;
+ token.second=(find(token.first, end, '.'));
+ }
+ }
+
+ bool match1(char c) const {
+ return token.second==token.first+1 && *token.first == c;
+ }
+
+ bool match(const Token& token2) {
+ ptrdiff_t l=len();
+ return l == token2.second-token2.first &&
+ strncmp(token.first, token2.first, l) == 0;
+ }
+
+ ptrdiff_t len() const { return token.second - token.first; }
-void TopicPattern::normalize() {
- std::string word;
- Tokens::iterator i = begin();
- while (i != end()) {
- if (*i == hashmark) {
- ++i;
- while (i != end()) {
- // Invariant: *(i-1)==#, [begin()..i-1] is normalized.
- if (*i == star) { // Move * before #.
- std::swap(*i, *(i-1));
- ++i;
- } else if (*i == hashmark) {
- erase(i); // Remove extra #
- } else {
- break;
+ Token token;
+ const char* end;
+};
+
+class Normalizer : public TokenIterator {
+ public:
+ Normalizer(string& p)
+ : TokenIterator(&p[0], &p[0]+p.size()), pattern(p)
+ { normalize(); }
+
+ private:
+ // Apply 2 transformations: #.* -> *.# and #.# -> #
+ void normalize() {
+ while (!finished()) {
+ if (match1('#')) {
+ const char* hash1=token.first;
+ next();
+ if (!finished()) {
+ if (match1('#')) { // Erase #.# -> #
+ pattern.erase(hash1-pattern.data(), 2);
+ token.first -= 2;
+ token.second -= 2;
+ end -= 2;
+ }
+ else if (match1('*')) { // Swap #.* -> *.#
+ swap(*const_cast<char*>(hash1),
+ *const_cast<char*>(token.first));
+ }
}
}
- } else {
- i ++;
+ else
+ next();
}
}
-}
+ string& pattern;
+};
-namespace {
-// TODO aconway 2006-09-20: Ineficient to convert every routingKey to a string.
-// Need StringRef class that operates on a string in place witout copy.
-// Should be applied everywhere strings are extracted from frames.
-//
-bool do_match(Tokens::const_iterator pattern_begin, Tokens::const_iterator pattern_end, Tokens::const_iterator target_begin, Tokens::const_iterator target_end)
-{
- // Invariant: [pattern_begin..p) matches [target_begin..t)
- Tokens::const_iterator p = pattern_begin;
- Tokens::const_iterator t = target_begin;
- while (p != pattern_end && t != target_end)
- {
- if (*p == star || *p == *t) {
- ++p, ++t;
- } else if (*p == hashmark) {
- ++p;
- if (do_match(p, pattern_end, t, target_end)) return true;
- while (t != target_end) {
- ++t;
- if (do_match(p, pattern_end, t, target_end)) return true;
+class Matcher {
+ public:
+ Matcher(const string& p, const string& k)
+ : matched(), pattern(&p[0], &p[0]+p.size()), key(&k[0], &k[0]+k.size())
+ { matched = match(); }
+
+ operator bool() const { return matched; }
+
+ private:
+ Matcher(const char* bp, const char* ep, const char* bk, const char* ek)
+ : matched(), pattern(bp,ep), key(bk,ek) { matched = match(); }
+
+ bool match() {
+ // Invariant: pattern and key match up to but excluding
+ // pattern.token and key.token
+ while (!pattern.finished() && !key.finished()) {
+ if (pattern.match1('*') && !key.finished()) {
+ pattern.next();
+ key.next();
}
- return false;
- } else {
- return false;
+ else if (pattern.match1('#')) {
+ pattern.next();
+ if (pattern.finished()) return true; // Trailing # matches anything.
+ while (!key.finished()) {
+ if (Matcher(pattern.token.first, pattern.end,
+ key.token.first, key.end))
+ return true;
+ key.next();
+ }
+ return false;
+ }
+ else if (pattern.len() == key.len() &&
+ equal(pattern.token.first,pattern.token.second,key.token.first)) {
+ pattern.next();
+ key.next();
+ }
+ else
+ return false;
}
+ if (!pattern.finished() && pattern.match1('#'))
+ pattern.next(); // Trailing # matches empty.
+ return pattern.finished() && key.finished();
}
- while (p != pattern_end && *p == hashmark) ++p; // Ignore trailing #
- return t == target_end && p == pattern_end;
+
+ bool matched;
+ TokenIterator pattern, key;
+};
}
+
+// Convert sequences of * and # to a sequence of * followed by a single #
+string TopicExchange::normalize(const string& pattern) {
+ string normal(pattern);
+ Normalizer n(normal);
+ return normal;
}
-bool TopicPattern::match(const Tokens& target) const
+bool TopicExchange::match(const string& pattern, const string& key)
{
- return do_match(begin(), end(), target.begin(), target.end());
+ return Matcher(pattern, key);
}
-TopicExchange::TopicExchange(const string& _name, Manageable* _parent) : Exchange(_name, _parent)
+TopicExchange::TopicExchange(const string& _name, Manageable* _parent, Broker* b) : Exchange(_name, _parent, b)
{
if (mgmtExchange != 0)
mgmtExchange->set_type (typeName);
}
TopicExchange::TopicExchange(const std::string& _name, bool _durable,
- const FieldTable& _args, Manageable* _parent) :
- Exchange(_name, _durable, _args, _parent)
+ const FieldTable& _args, Manageable* _parent, Broker* b) :
+ Exchange(_name, _durable, _args, _parent, b)
{
if (mgmtExchange != 0)
mgmtExchange->set_type (typeName);
}
-bool TopicExchange::bind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* /*args*/){
- RWlock::ScopedWlock l(lock);
- TopicPattern routingPattern(routingKey);
- if (isBound(queue, routingPattern)) {
- return false;
- } else {
- Binding::shared_ptr binding (new Binding (routingKey, queue, this));
- bindings[routingPattern].push_back(binding);
- if (mgmtExchange != 0) {
- mgmtExchange->inc_bindingCount();
- ((management::Queue*) queue->GetManagementObject())->inc_bindingCount();
+bool TopicExchange::bind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* args)
+{
+ string fedOp(args ? args->getAsString(qpidFedOp) : fedOpBind);
+ string fedTags(args ? args->getAsString(qpidFedTags) : "");
+ string fedOrigin(args ? args->getAsString(qpidFedOrigin) : "");
+ bool propagate = false;
+ bool reallyUnbind;
+ string routingPattern = normalize(routingKey);
+
+ if (args == 0 || fedOp.empty() || fedOp == fedOpBind) {
+ RWlock::ScopedWlock l(lock);
+ if (isBound(queue, routingPattern)) {
+ return false;
+ } else {
+ Binding::shared_ptr binding (new Binding (routingPattern, queue, this, FieldTable(), fedOrigin));
+ BoundKey& bk = bindings[routingPattern];
+ bk.bindingVector.push_back(binding);
+ propagate = bk.fedBinding.addOrigin(fedOrigin);
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_bindingCount();
+ }
+ }
+ } else if (fedOp == fedOpUnbind) {
+ {
+ RWlock::ScopedWlock l(lock);
+ BoundKey& bk = bindings[routingPattern];
+ propagate = bk.fedBinding.delOrigin(fedOrigin);
+ reallyUnbind = bk.fedBinding.count() == 0;
+ }
+ if (reallyUnbind)
+ unbind(queue, routingPattern, 0);
+ } else if (fedOp == fedOpReorigin) {
+ /** gather up all the keys that need rebinding in a local vector
+ * while holding the lock. Then propagate once the lock is
+ * released
+ */
+ std::vector<std::string> keys2prop;
+ {
+ RWlock::ScopedRlock l(lock);
+ for (BindingMap::iterator iter = bindings.begin();
+ iter != bindings.end(); iter++) {
+ const BoundKey& bk = iter->second;
+
+ if (bk.fedBinding.hasLocal()) {
+ keys2prop.push_back(iter->first);
+ }
+ }
+ } /* lock dropped */
+ for (std::vector<std::string>::const_iterator key = keys2prop.begin();
+ key != keys2prop.end(); key++) {
+ propagateFedOp( *key, string(), fedOpBind, string());
}
- return true;
}
+
+ routeIVE();
+ if (propagate)
+ propagateFedOp(routingKey, fedTags, fedOp, fedOrigin);
+ return true;
}
-bool TopicExchange::unbind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* /*args*/){
+bool TopicExchange::unbind(Queue::shared_ptr queue, const string& constRoutingKey, const FieldTable* /*args*/){
RWlock::ScopedWlock l(lock);
- BindingMap::iterator bi = bindings.find(TopicPattern(routingKey));
- Binding::vector& qv(bi->second);
+ string routingKey = normalize(constRoutingKey);
+
+ BindingMap::iterator bi = bindings.find(routingKey);
if (bi == bindings.end()) return false;
+ BoundKey& bk = bi->second;
+ Binding::vector& qv(bk.bindingVector);
+ bool propagate = false;
Binding::vector::iterator q;
for (q = qv.begin(); q != qv.end(); q++)
@@ -157,19 +268,22 @@ bool TopicExchange::unbind(Queue::shared_ptr queue, const string& routingKey, co
break;
if(q == qv.end()) return false;
qv.erase(q);
+ propagate = bk.fedBinding.delOrigin();
if(qv.empty()) bindings.erase(bi);
if (mgmtExchange != 0) {
mgmtExchange->dec_bindingCount();
- ((management::Queue*) queue->GetManagementObject())->dec_bindingCount();
}
+
+ if (propagate)
+ propagateFedOp(routingKey, string(), fedOpUnbind, string());
return true;
}
-bool TopicExchange::isBound(Queue::shared_ptr queue, TopicPattern& pattern)
+bool TopicExchange::isBound(Queue::shared_ptr queue, const string& pattern)
{
BindingMap::iterator bi = bindings.find(pattern);
if (bi == bindings.end()) return false;
- Binding::vector& qv(bi->second);
+ Binding::vector& qv(bi->second.bindingVector);
Binding::vector::iterator q;
for (q = qv.begin(); q != qv.end(); q++)
if ((*q)->queue == queue)
@@ -177,55 +291,41 @@ bool TopicExchange::isBound(Queue::shared_ptr queue, TopicPattern& pattern)
return q != qv.end();
}
-void TopicExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* /*args*/){
- RWlock::ScopedRlock l(lock);
- uint32_t count(0);
- Tokens tokens(routingKey);
-
- for (BindingMap::iterator i = bindings.begin(); i != bindings.end(); ++i) {
- if (i->first.match(tokens)) {
- Binding::vector& qv(i->second);
- for(Binding::vector::iterator j = qv.begin(); j != qv.end(); j++, count++){
- msg.deliverTo((*j)->queue);
- if ((*j)->mgmtBinding != 0)
- (*j)->mgmtBinding->inc_msgMatched ();
- }
- }
- }
-
- if (mgmtExchange != 0)
+void TopicExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* /*args*/)
+{
+ Binding::vector mb;
+ BindingList b(new std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> >);
+ PreRoute pr(msg, this);
{
- mgmtExchange->inc_msgReceives ();
- mgmtExchange->inc_byteReceives (msg.contentSize ());
- if (count == 0)
- {
- mgmtExchange->inc_msgDrops ();
- mgmtExchange->inc_byteDrops (msg.contentSize ());
- }
- else
- {
- mgmtExchange->inc_msgRoutes (count);
- mgmtExchange->inc_byteRoutes (count * msg.contentSize ());
+ RWlock::ScopedRlock l(lock);
+ for (BindingMap::iterator i = bindings.begin(); i != bindings.end(); ++i) {
+ if (match(i->first, routingKey)) {
+ Binding::vector& qv(i->second.bindingVector);
+ for(Binding::vector::iterator j = qv.begin(); j != qv.end(); j++){
+ b->push_back(*j);
+ }
+ }
}
}
+ doRoute(msg, b);
}
bool TopicExchange::isBound(Queue::shared_ptr queue, const string* const routingKey, const FieldTable* const)
{
+ RWlock::ScopedRlock l(lock);
if (routingKey && queue) {
- TopicPattern key(*routingKey);
+ string key(normalize(*routingKey));
return isBound(queue, key);
} else if (!routingKey && !queue) {
return bindings.size() > 0;
} else if (routingKey) {
for (BindingMap::iterator i = bindings.begin(); i != bindings.end(); ++i) {
- if (i->first.match(*routingKey)) {
+ if (match(i->first, *routingKey))
return true;
}
- }
} else {
for (BindingMap::iterator i = bindings.begin(); i != bindings.end(); ++i) {
- Binding::vector& qv(i->second);
+ Binding::vector& qv(i->second.bindingVector);
Binding::vector::iterator q;
for (q = qv.begin(); q != qv.end(); q++)
if ((*q)->queue == queue)
@@ -233,10 +333,11 @@ bool TopicExchange::isBound(Queue::shared_ptr queue, const string* const routing
}
}
return false;
+ return queue && routingKey;
}
TopicExchange::~TopicExchange() {}
const std::string TopicExchange::typeName("topic");
-
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/TopicExchange.h b/cpp/src/qpid/broker/TopicExchange.h
index 2e107142b7..3bbf143889 100644
--- a/cpp/src/qpid/broker/TopicExchange.h
+++ b/cpp/src/qpid/broker/TopicExchange.h
@@ -23,77 +23,57 @@
#include <map>
#include <vector>
-#include "Exchange.h"
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/Exchange.h"
#include "qpid/framing/FieldTable.h"
#include "qpid/sys/Monitor.h"
-#include "Queue.h"
+#include "qpid/broker/Queue.h"
namespace qpid {
namespace broker {
-/** A vector of string tokens */
-class Tokens : public std::vector<std::string> {
- public:
- Tokens() {};
- // Default copy, assign, dtor are sufficient.
-
- /** Tokenize s, provides automatic conversion of string to Tokens */
- Tokens(const std::string& s) { operator=(s); }
- /** Tokenizing assignment operator s */
- Tokens & operator=(const std::string& s);
-
- private:
- size_t hash;
-};
-
-
-/**
- * Tokens that have been normalized as a pattern and can be matched
- * with topic Tokens. Normalized meands all sequences of mixed * and
- * # are reduced to a series of * followed by at most one #.
- */
-class TopicPattern : public Tokens
-{
- public:
- TopicPattern() {}
- // Default copy, assign, dtor are sufficient.
- TopicPattern(const Tokens& tokens) { operator=(tokens); }
- TopicPattern(const std::string& str) { operator=(str); }
- TopicPattern& operator=(const Tokens&);
- TopicPattern& operator=(const std::string& str) { return operator=(Tokens(str)); }
-
- /** Match a topic */
- bool match(const std::string& topic) { return match(Tokens(topic)); }
- bool match(const Tokens& topic) const;
-
- private:
- void normalize();
-};
-
-class TopicExchange : public virtual Exchange{
- typedef std::map<TopicPattern, Binding::vector> BindingMap;
+class TopicExchange : public virtual Exchange {
+ struct BoundKey {
+ Binding::vector bindingVector;
+ FedBinding fedBinding;
+ };
+ typedef std::map<std::string, BoundKey> BindingMap;
BindingMap bindings;
qpid::sys::RWlock lock;
- bool isBound(Queue::shared_ptr queue, TopicPattern& pattern);
+ bool isBound(Queue::shared_ptr queue, const string& pattern);
+
public:
static const std::string typeName;
- TopicExchange(const string& name, management::Manageable* parent = 0);
- TopicExchange(const string& _name, bool _durable,
- const qpid::framing::FieldTable& _args, management::Manageable* parent = 0);
+ static QPID_BROKER_EXTERN bool match(const std::string& pattern, const std::string& topic);
+ static QPID_BROKER_EXTERN std::string normalize(const std::string& pattern);
+
+ QPID_BROKER_EXTERN TopicExchange(const string& name,
+ management::Manageable* parent = 0, Broker* broker = 0);
+ QPID_BROKER_EXTERN TopicExchange(const string& _name,
+ bool _durable,
+ const qpid::framing::FieldTable& _args,
+ management::Manageable* parent = 0, Broker* broker = 0);
virtual std::string getType() const { return typeName; }
- virtual bool bind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args);
+ QPID_BROKER_EXTERN virtual bool bind(Queue::shared_ptr queue,
+ const string& routingKey,
+ const qpid::framing::FieldTable* args);
virtual bool unbind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args);
- virtual void route(Deliverable& msg, const string& routingKey, const qpid::framing::FieldTable* args);
+ QPID_BROKER_EXTERN virtual void route(Deliverable& msg,
+ const string& routingKey,
+ const qpid::framing::FieldTable* args);
- virtual bool isBound(Queue::shared_ptr queue, const string* const routingKey, const qpid::framing::FieldTable* const args);
+ QPID_BROKER_EXTERN virtual bool isBound(Queue::shared_ptr queue,
+ const string* const routingKey,
+ const qpid::framing::FieldTable* const args);
- virtual ~TopicExchange();
+ QPID_BROKER_EXTERN virtual ~TopicExchange();
+ virtual bool supportsDynamicBinding() { return true; }
};
diff --git a/cpp/src/qpid/broker/TxAccept.cpp b/cpp/src/qpid/broker/TxAccept.cpp
index 82acf61cd1..928ac12c10 100644
--- a/cpp/src/qpid/broker/TxAccept.cpp
+++ b/cpp/src/qpid/broker/TxAccept.cpp
@@ -18,7 +18,7 @@
* under the License.
*
*/
-#include "TxAccept.h"
+#include "qpid/broker/TxAccept.h"
#include "qpid/log/Statement.h"
using std::bind1st;
@@ -26,19 +26,56 @@ using std::bind2nd;
using std::mem_fun_ref;
using namespace qpid::broker;
using qpid::framing::SequenceSet;
+using qpid::framing::SequenceNumber;
-TxAccept::TxAccept(SequenceSet& _acked, std::list<DeliveryRecord>& _unacked) :
- acked(_acked), unacked(_unacked) {}
+TxAccept::RangeOp::RangeOp(const AckRange& r) : range(r) {}
+
+void TxAccept::RangeOp::prepare(TransactionContext* ctxt)
+{
+ for_each(range.start, range.end, bind(&DeliveryRecord::dequeue, _1, ctxt));
+}
+
+void TxAccept::RangeOp::commit()
+{
+ for_each(range.start, range.end, bind(&DeliveryRecord::committed, _1));
+ for_each(range.start, range.end, bind(&DeliveryRecord::setEnded, _1));
+}
+
+TxAccept::RangeOps::RangeOps(DeliveryRecords& u) : unacked(u) {}
+
+void TxAccept::RangeOps::operator()(SequenceNumber start, SequenceNumber end)
+{
+ ranges.push_back(RangeOp(DeliveryRecord::findRange(unacked, start, end)));
+}
+
+void TxAccept::RangeOps::prepare(TransactionContext* ctxt)
+{
+ std::for_each(ranges.begin(), ranges.end(), bind(&RangeOp::prepare, _1, ctxt));
+}
+
+void TxAccept::RangeOps::commit()
+{
+ std::for_each(ranges.begin(), ranges.end(), bind(&RangeOp::commit, _1));
+ //now remove if isRedundant():
+ if (!ranges.empty()) {
+ DeliveryRecords::iterator begin = ranges.front().range.start;
+ DeliveryRecords::iterator end = ranges.back().range.end;
+ DeliveryRecords::iterator removed = remove_if(begin, end, mem_fun_ref(&DeliveryRecord::isRedundant));
+ unacked.erase(removed, end);
+ }
+}
+
+TxAccept::TxAccept(const SequenceSet& _acked, DeliveryRecords& _unacked) :
+ acked(_acked), unacked(_unacked), ops(unacked)
+{
+ //populate the ops
+ acked.for_each(ops);
+}
bool TxAccept::prepare(TransactionContext* ctxt) throw()
{
try{
- //dequeue messages from their respective queues:
- for (ack_iterator i = unacked.begin(); i != unacked.end(); i++) {
- if (i->coveredBy(&acked)) {
- i->dequeue(ctxt);
- }
- }
+ ops.prepare(ctxt);
return true;
}catch(const std::exception& e){
QPID_LOG(error, "Failed to prepare: " << e.what());
@@ -51,11 +88,13 @@ bool TxAccept::prepare(TransactionContext* ctxt) throw()
void TxAccept::commit() throw()
{
- for (ack_iterator i = unacked.begin(); i != unacked.end(); i++) {
- if (i->coveredBy(&acked)) i->setEnded();
+ try {
+ ops.commit();
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Failed to commit: " << e.what());
+ } catch(...) {
+ QPID_LOG(error, "Failed to commit (unknown error)");
}
-
- unacked.remove_if(mem_fun_ref(&DeliveryRecord::isRedundant));
}
void TxAccept::rollback() throw() {}
diff --git a/cpp/src/qpid/broker/TxAccept.h b/cpp/src/qpid/broker/TxAccept.h
index 9548c50c2a..314a150176 100644
--- a/cpp/src/qpid/broker/TxAccept.h
+++ b/cpp/src/qpid/broker/TxAccept.h
@@ -25,8 +25,8 @@
#include <functional>
#include <list>
#include "qpid/framing/SequenceSet.h"
-#include "DeliveryRecord.h"
-#include "TxOp.h"
+#include "qpid/broker/DeliveryRecord.h"
+#include "qpid/broker/TxOp.h"
namespace qpid {
namespace broker {
@@ -34,9 +34,31 @@ namespace qpid {
* Defines the transactional behaviour for accepts received by
* a transactional channel.
*/
- class TxAccept : public TxOp{
- framing::SequenceSet& acked;
- std::list<DeliveryRecord>& unacked;
+ class TxAccept : public TxOp {
+ struct RangeOp
+ {
+ AckRange range;
+
+ RangeOp(const AckRange& r);
+ void prepare(TransactionContext* ctxt);
+ void commit();
+ };
+
+ struct RangeOps
+ {
+ std::vector<RangeOp> ranges;
+ DeliveryRecords& unacked;
+
+ RangeOps(DeliveryRecords& u);
+
+ void operator()(framing::SequenceNumber start, framing::SequenceNumber end);
+ void prepare(TransactionContext* ctxt);
+ void commit();
+ };
+
+ framing::SequenceSet acked;
+ DeliveryRecords& unacked;
+ RangeOps ops;
public:
/**
@@ -44,11 +66,15 @@ namespace qpid {
* acks received
* @param unacked the record of delivered messages
*/
- TxAccept(framing::SequenceSet& acked, std::list<DeliveryRecord>& unacked);
+ TxAccept(const framing::SequenceSet& acked, DeliveryRecords& unacked);
virtual bool prepare(TransactionContext* ctxt) throw();
virtual void commit() throw();
virtual void rollback() throw();
virtual ~TxAccept(){}
+ virtual void accept(TxOpConstVisitor& visitor) const { visitor(*this); }
+
+ // Used by cluster replication.
+ const framing::SequenceSet& getAcked() const { return acked; }
};
}
}
diff --git a/cpp/src/qpid/broker/TxBuffer.cpp b/cpp/src/qpid/broker/TxBuffer.cpp
index 8fe2c17bf0..b509778e89 100644
--- a/cpp/src/qpid/broker/TxBuffer.cpp
+++ b/cpp/src/qpid/broker/TxBuffer.cpp
@@ -18,10 +18,11 @@
* under the License.
*
*/
-#include "TxBuffer.h"
+#include "qpid/broker/TxBuffer.h"
#include "qpid/log/Statement.h"
#include <boost/mem_fn.hpp>
+#include <boost/bind.hpp>
using boost::mem_fn;
using namespace qpid::broker;
@@ -73,3 +74,7 @@ bool TxBuffer::commitLocal(TransactionalStore* const store)
}
return false;
}
+
+void TxBuffer::accept(TxOpConstVisitor& v) const {
+ std::for_each(ops.begin(), ops.end(), boost::bind(&TxOp::accept, _1, boost::ref(v)));
+}
diff --git a/cpp/src/qpid/broker/TxBuffer.h b/cpp/src/qpid/broker/TxBuffer.h
index 361c47e92c..d49c8ba16a 100644
--- a/cpp/src/qpid/broker/TxBuffer.h
+++ b/cpp/src/qpid/broker/TxBuffer.h
@@ -24,8 +24,9 @@
#include <algorithm>
#include <functional>
#include <vector>
-#include "TransactionalStore.h"
-#include "TxOp.h"
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/TransactionalStore.h"
+#include "qpid/broker/TxOp.h"
/**
* Represents a single transaction. As such, an instance of this class
@@ -68,7 +69,7 @@ namespace qpid {
/**
* Adds an operation to the transaction.
*/
- void enlist(TxOp::shared_ptr op);
+ QPID_BROKER_EXTERN void enlist(TxOp::shared_ptr op);
/**
* Requests that all ops are prepared. This should
@@ -81,7 +82,7 @@ namespace qpid {
* @returns true if all the operations prepared
* successfully, false if not.
*/
- bool prepare(TransactionContext* const ctxt);
+ QPID_BROKER_EXTERN bool prepare(TransactionContext* const ctxt);
/**
* Signals that the ops all prepared successfully and can
@@ -91,7 +92,7 @@ namespace qpid {
* Should only be called after a call to prepare() returns
* true.
*/
- void commit();
+ QPID_BROKER_EXTERN void commit();
/**
* Signals that all ops can be rolled back.
@@ -100,13 +101,16 @@ namespace qpid {
* returns true (2pc) or instead of a prepare call
* ('server-local')
*/
- void rollback();
+ QPID_BROKER_EXTERN void rollback();
/**
* Helper method for managing the process of server local
* commit
*/
- bool commitLocal(TransactionalStore* const store);
+ QPID_BROKER_EXTERN bool commitLocal(TransactionalStore* const store);
+
+ // Used by cluster to replicate transaction status.
+ void accept(TxOpConstVisitor& v) const;
};
}
}
diff --git a/cpp/src/qpid/broker/TxOp.h b/cpp/src/qpid/broker/TxOp.h
index e687c437cc..a8fa1c2621 100644
--- a/cpp/src/qpid/broker/TxOp.h
+++ b/cpp/src/qpid/broker/TxOp.h
@@ -21,11 +21,13 @@
#ifndef _TxOp_
#define _TxOp_
-#include "TransactionalStore.h"
+#include "qpid/broker/TxOpVisitor.h"
+#include "qpid/broker/TransactionalStore.h"
#include <boost/shared_ptr.hpp>
namespace qpid {
namespace broker {
+
class TxOp{
public:
typedef boost::shared_ptr<TxOp> shared_ptr;
@@ -34,9 +36,11 @@ namespace qpid {
virtual void commit() throw() = 0;
virtual void rollback() throw() = 0;
virtual ~TxOp(){}
+
+ virtual void accept(TxOpConstVisitor&) const = 0;
};
- }
-}
+
+}} // namespace qpid::broker
#endif
diff --git a/cpp/src/qpid/broker/TxOpVisitor.h b/cpp/src/qpid/broker/TxOpVisitor.h
new file mode 100644
index 0000000000..ceb894896e
--- /dev/null
+++ b/cpp/src/qpid/broker/TxOpVisitor.h
@@ -0,0 +1,97 @@
+#ifndef QPID_BROKER_TXOPVISITOR_H
+#define QPID_BROKER_TXOPVISITOR_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+namespace qpid {
+namespace broker {
+
+class DtxAck;
+class RecoveredDequeue;
+class RecoveredEnqueue;
+class TxAccept;
+class TxPublish;
+
+/**
+ * Visitor for TxOp familly of classes.
+ */
+struct TxOpConstVisitor
+{
+ virtual ~TxOpConstVisitor() {}
+ virtual void operator()(const DtxAck&) = 0;
+ virtual void operator()(const RecoveredDequeue&) = 0;
+ virtual void operator()(const RecoveredEnqueue&) = 0;
+ virtual void operator()(const TxAccept&) = 0;
+ virtual void operator()(const TxPublish&) = 0;
+};
+
+}} // namespace qpid::broker
+
+#endif /*!QPID_BROKER_TXOPVISITOR_H*/
+#ifndef QPID_BROKER_TXOPVISITOR_H
+#define QPID_BROKER_TXOPVISITOR_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+namespace qpid {
+namespace broker {
+
+class DtxAck;
+class RecoveredDequeue;
+class RecoveredEnqueue;
+class TxAccept;
+class TxPublish;
+
+/**
+ * Visitor for TxOp familly of classes.
+ */
+struct TxOpConstVisitor
+{
+ virtual ~TxOpConstVisitor() {}
+ virtual void operator()(const DtxAck&) = 0;
+ virtual void operator()(const RecoveredDequeue&) = 0;
+ virtual void operator()(const RecoveredEnqueue&) = 0;
+ virtual void operator()(const TxAccept&) = 0;
+ virtual void operator()(const TxPublish&) = 0;
+};
+
+}} // namespace qpid::broker
+
+#endif /*!QPID_BROKER_TXOPVISITOR_H*/
diff --git a/cpp/src/qpid/broker/TxPublish.cpp b/cpp/src/qpid/broker/TxPublish.cpp
index dcee00e803..4b083033ea 100644
--- a/cpp/src/qpid/broker/TxPublish.cpp
+++ b/cpp/src/qpid/broker/TxPublish.cpp
@@ -19,16 +19,21 @@
*
*/
#include "qpid/log/Statement.h"
-#include "TxPublish.h"
+#include "qpid/broker/TxPublish.h"
using boost::intrusive_ptr;
using namespace qpid::broker;
TxPublish::TxPublish(intrusive_ptr<Message> _msg) : msg(_msg) {}
-bool TxPublish::prepare(TransactionContext* ctxt) throw(){
+bool TxPublish::prepare(TransactionContext* ctxt) throw()
+{
try{
- for_each(queues.begin(), queues.end(), Prepare(ctxt, msg));
+ while (!queues.empty()) {
+ prepare(ctxt, queues.front());
+ prepared.push_back(queues.front());
+ queues.pop_front();
+ }
return true;
}catch(const std::exception& e){
QPID_LOG(error, "Failed to prepare: " << e.what());
@@ -38,14 +43,33 @@ bool TxPublish::prepare(TransactionContext* ctxt) throw(){
return false;
}
-void TxPublish::commit() throw(){
- for_each(queues.begin(), queues.end(), Commit(msg));
+void TxPublish::commit() throw()
+{
+ try {
+ for_each(prepared.begin(), prepared.end(), Commit(msg));
+ if (msg->checkContentReleasable()) {
+ msg->releaseContent();
+ }
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Failed to commit: " << e.what());
+ } catch(...) {
+ QPID_LOG(error, "Failed to commit (unknown error)");
+ }
}
-void TxPublish::rollback() throw(){
+void TxPublish::rollback() throw()
+{
+ try {
+ for_each(prepared.begin(), prepared.end(), Rollback(msg));
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Failed to complete rollback: " << e.what());
+ } catch(...) {
+ QPID_LOG(error, "Failed to complete rollback (unknown error)");
+ }
+
}
-void TxPublish::deliverTo(Queue::shared_ptr& queue){
+void TxPublish::deliverTo(const boost::shared_ptr<Queue>& queue){
if (!queue->isLocal(msg)) {
queues.push_back(queue);
delivered = true;
@@ -54,26 +78,30 @@ void TxPublish::deliverTo(Queue::shared_ptr& queue){
}
}
-TxPublish::Prepare::Prepare(TransactionContext* _ctxt, intrusive_ptr<Message>& _msg)
- : ctxt(_ctxt), msg(_msg){}
-
-void TxPublish::Prepare::operator()(Queue::shared_ptr& queue){
+void TxPublish::prepare(TransactionContext* ctxt, const boost::shared_ptr<Queue> queue)
+{
if (!queue->enqueue(ctxt, msg)){
/**
- * if not store then mark message for ack and deleivery once
- * commit happens, as async IO will never set it when no store
- * exists
- */
+ * if not store then mark message for ack and deleivery once
+ * commit happens, as async IO will never set it when no store
+ * exists
+ */
msg->enqueueComplete();
}
}
TxPublish::Commit::Commit(intrusive_ptr<Message>& _msg) : msg(_msg){}
-void TxPublish::Commit::operator()(Queue::shared_ptr& queue){
+void TxPublish::Commit::operator()(const boost::shared_ptr<Queue>& queue){
queue->process(msg);
}
+TxPublish::Rollback::Rollback(intrusive_ptr<Message>& _msg) : msg(_msg){}
+
+void TxPublish::Rollback::operator()(const boost::shared_ptr<Queue>& queue){
+ queue->enqueueAborted(msg);
+}
+
uint64_t TxPublish::contentSize ()
{
return msg->contentSize ();
diff --git a/cpp/src/qpid/broker/TxPublish.h b/cpp/src/qpid/broker/TxPublish.h
index d2590debfb..b6ab9767ab 100644
--- a/cpp/src/qpid/broker/TxPublish.h
+++ b/cpp/src/qpid/broker/TxPublish.h
@@ -21,11 +21,12 @@
#ifndef _TxPublish_
#define _TxPublish_
-#include "Queue.h"
-#include "Deliverable.h"
-#include "Message.h"
-#include "MessageStore.h"
-#include "TxOp.h"
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/Deliverable.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/MessageStore.h"
+#include "qpid/broker/TxOp.h"
#include <algorithm>
#include <functional>
@@ -46,37 +47,43 @@ namespace qpid {
* dispatch or to be added to the in-memory queue.
*/
class TxPublish : public TxOp, public Deliverable{
- class Prepare{
- TransactionContext* ctxt;
- boost::intrusive_ptr<Message>& msg;
- public:
- Prepare(TransactionContext* ctxt, boost::intrusive_ptr<Message>& msg);
- void operator()(Queue::shared_ptr& queue);
- };
class Commit{
boost::intrusive_ptr<Message>& msg;
public:
Commit(boost::intrusive_ptr<Message>& msg);
- void operator()(Queue::shared_ptr& queue);
+ void operator()(const boost::shared_ptr<Queue>& queue);
+ };
+ class Rollback{
+ boost::intrusive_ptr<Message>& msg;
+ public:
+ Rollback(boost::intrusive_ptr<Message>& msg);
+ void operator()(const boost::shared_ptr<Queue>& queue);
};
boost::intrusive_ptr<Message> msg;
std::list<Queue::shared_ptr> queues;
+ std::list<Queue::shared_ptr> prepared;
+
+ void prepare(TransactionContext* ctxt, boost::shared_ptr<Queue>);
public:
- TxPublish(boost::intrusive_ptr<Message> msg);
- virtual bool prepare(TransactionContext* ctxt) throw();
- virtual void commit() throw();
- virtual void rollback() throw();
+ QPID_BROKER_EXTERN TxPublish(boost::intrusive_ptr<Message> msg);
+ QPID_BROKER_EXTERN virtual bool prepare(TransactionContext* ctxt) throw();
+ QPID_BROKER_EXTERN virtual void commit() throw();
+ QPID_BROKER_EXTERN virtual void rollback() throw();
virtual Message& getMessage() { return *msg; };
- virtual void deliverTo(Queue::shared_ptr& queue);
+ QPID_BROKER_EXTERN virtual void deliverTo(const boost::shared_ptr<Queue>& queue);
virtual ~TxPublish(){}
+ virtual void accept(TxOpConstVisitor& visitor) const { visitor(*this); }
+
+ QPID_BROKER_EXTERN uint64_t contentSize();
- uint64_t contentSize();
+ boost::intrusive_ptr<Message> getMessage() const { return msg; }
+ const std::list<Queue::shared_ptr> getQueues() const { return queues; }
};
}
}
diff --git a/cpp/src/qpid/broker/Vhost.cpp b/cpp/src/qpid/broker/Vhost.cpp
index 23203ec13e..df37cba255 100644
--- a/cpp/src/qpid/broker/Vhost.cpp
+++ b/cpp/src/qpid/broker/Vhost.cpp
@@ -17,23 +17,33 @@
// under the License.
//
-#include "Vhost.h"
-#include "qpid/agent/ManagementAgent.h"
+#include "qpid/broker/Vhost.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/management/ManagementAgent.h"
using namespace qpid::broker;
using qpid::management::ManagementAgent;
+namespace _qmf = qmf::org::apache::qpid::broker;
-Vhost::Vhost (management::Manageable* parentBroker) : mgmtObject(0)
+namespace qpid { namespace management {
+class Manageable;
+}}
+
+Vhost::Vhost (qpid::management::Manageable* parentBroker, Broker* broker) : mgmtObject(0)
{
- if (parentBroker != 0)
+ if (parentBroker != 0 && broker != 0)
{
- ManagementAgent* agent = ManagementAgent::Singleton::getInstance();
+ ManagementAgent* agent = broker->getManagementAgent();
if (agent != 0)
{
- mgmtObject = new management::Vhost (agent, this, parentBroker, "/");
- agent->addObject (mgmtObject, 3, 1);
+ mgmtObject = new _qmf::Vhost(agent, this, parentBroker, "/");
+ agent->addObject (mgmtObject, 0x1000000000000003LL);
}
}
}
+void Vhost::setFederationTag(const std::string& tag)
+{
+ mgmtObject->set_federationTag(tag);
+}
diff --git a/cpp/src/qpid/broker/Vhost.h b/cpp/src/qpid/broker/Vhost.h
index e56cc61272..9554d641c2 100644
--- a/cpp/src/qpid/broker/Vhost.h
+++ b/cpp/src/qpid/broker/Vhost.h
@@ -21,29 +21,28 @@
//
#include "qpid/management/Manageable.h"
-#include "qpid/management/Vhost.h"
+#include "qmf/org/apache/qpid/broker/Vhost.h"
#include <boost/shared_ptr.hpp>
namespace qpid {
namespace broker {
+class Broker;
class Vhost : public management::Manageable
{
private:
- management::Vhost* mgmtObject;
+ qmf::org::apache::qpid::broker::Vhost* mgmtObject;
public:
typedef boost::shared_ptr<Vhost> shared_ptr;
- Vhost (management::Manageable* parentBroker);
+ Vhost (management::Manageable* parentBroker, Broker* broker = 0);
management::ManagementObject* GetManagementObject (void) const
{ return mgmtObject; }
-
- management::Manageable::status_t ManagementMethod (uint32_t, management::Args&)
- { return management::Manageable::STATUS_OK; }
+ void setFederationTag(const std::string& tag);
};
}}
diff --git a/cpp/src/qpid/broker/XmlExchange.cpp b/cpp/src/qpid/broker/XmlExchange.cpp
deleted file mode 100644
index cb0f9a9606..0000000000
--- a/cpp/src/qpid/broker/XmlExchange.cpp
+++ /dev/null
@@ -1,277 +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 "config.h"
-#include "XmlExchange.h"
-
-#include "DeliverableMessage.h"
-
-#include "qpid/log/Statement.h"
-#include "qpid/framing/FieldTable.h"
-#include "qpid/framing/FieldValue.h"
-#include "qpid/framing/reply_exceptions.h"
-
-#include <xercesc/framework/MemBufInputSource.hpp>
-
-#include <xqilla/context/ItemFactory.hpp>
-#include <xqilla/xqilla-simple.hpp>
-
-#include <iostream>
-#include <sstream>
-
-using namespace qpid::framing;
-using namespace qpid::sys;
-using qpid::management::Manageable;
-
-namespace qpid {
-namespace broker {
-
-XmlExchange::XmlExchange(const string& _name, Manageable* _parent) : Exchange(_name, _parent)
-{
- if (mgmtExchange != 0)
- mgmtExchange->set_type (typeName);
-}
-
-XmlExchange::XmlExchange(const std::string& _name, bool _durable,
- const FieldTable& _args, Manageable* _parent) :
- Exchange(_name, _durable, _args, _parent)
-{
- if (mgmtExchange != 0)
- mgmtExchange->set_type (typeName);
-}
-
-/*
- * Use the name of the query as the binding key.
- *
- * The first time a given name is used in a binding, the query body
- * must be provided.After that, no query body should be present.
- *
- * To modify an installed query, the user must first unbind the
- * existing query, then replace it by binding again with the same
- * name.
- *
- */
-
- // #### TODO: The Binding should take the query text
- // #### only. Consider encapsulating the entire block, including
- // #### the if condition.
-
-
-bool XmlExchange::bind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* bindingArguments)
-{
- string queryText = bindingArguments->getString("xquery");
-
- try {
- RWlock::ScopedWlock l(lock);
- XmlBinding::vector& bindings(bindingsMap[routingKey]);
- XmlBinding::vector::iterator i;
-
- for (i = bindings.begin(); i != bindings.end(); i++)
- if ((*i)->queue == queue)
- break;
-
- if (i == bindings.end()) {
-
- Query query(xqilla.parse(X(queryText.c_str())));
- XmlBinding::shared_ptr binding(new XmlBinding (routingKey, queue, this, query));
- XmlBinding::vector bindings(1, binding);
- bindingsMap[routingKey] = bindings;
- QPID_LOG(trace, "Bound successfully with query: " << queryText );
-
- if (mgmtExchange != 0) {
- mgmtExchange->inc_bindingCount();
- ((management::Queue*) queue->GetManagementObject())->inc_bindingCount();
- }
- return true;
- } else{
- return false;
- }
- }
- catch (XQException& e) {
- throw InternalErrorException(QPID_MSG("Could not parse xquery:"+ queryText));
- }
- catch (...) {
- throw InternalErrorException(QPID_MSG("Unexpected error - Could not parse xquery:"+ queryText));
- }
-}
-
-bool XmlExchange::unbind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* /*args*/)
-{
- RWlock::ScopedWlock l(lock);
- XmlBinding::vector& bindings(bindingsMap[routingKey]);
- XmlBinding::vector::iterator i;
-
- for (i = bindings.begin(); i != bindings.end(); i++)
- if ((*i)->queue == queue)
- break;
-
- if (i < bindings.end()) {
- bindings.erase(i);
- if (bindings.empty()) {
- bindingsMap.erase(routingKey);
- }
- if (mgmtExchange != 0) {
- mgmtExchange->dec_bindingCount();
- ((management::Queue*) queue->GetManagementObject())->dec_bindingCount();
- }
- return true;
- } else {
- return false;
- }
-}
-
-bool XmlExchange::matches(Query& query, Deliverable& msg, const qpid::framing::FieldTable* args)
-{
- // ### TODO: Need istream for frameset
- // Hack alert - the following code does not work for really large messages
-
- string msgContent;
-
- try {
- msg.getMessage().getFrames().getContent(msgContent);
-
- QPID_LOG(trace, "matches: query is [" << UTF8(query->getQueryText()) << "]");
- QPID_LOG(trace, "matches: message content is [" << msgContent << "]");
-
- boost::scoped_ptr<DynamicContext> context(query->createDynamicContext());
- if (!context.get()) {
- throw InternalErrorException(QPID_MSG("Query context looks munged ..."));
- }
-
- XERCES_CPP_NAMESPACE::MemBufInputSource xml((XMLByte*) msgContent.c_str(), msgContent.length(), "input" );
- Sequence seq(context->parseDocument(xml));
-
- if (args) {
- FieldTable::ValueMap::const_iterator v = args->begin();
- for(; v != args->end(); ++v) {
- // ### TODO: Do types properly
- if (v->second->convertsTo<std::string>()) {
- QPID_LOG(trace, "XmlExchange, external variable: " << v->first << " = " << v->second->getData().getString().c_str());
- Item::Ptr value = context->getItemFactory()->createString(X(v->second->getData().getString().c_str()), context.get());
- context->setExternalVariable(X(v->first.c_str()), value);
- }
- }
- }
-
- if(!seq.isEmpty() && seq.first()->isNode()) {
- context->setContextItem(seq.first());
- context->setContextPosition(1);
- context->setContextSize(1);
- }
- Result result = query->execute(context.get());
- return result->getEffectiveBooleanValue(context.get(), 0);
- }
- catch (XQException& e) {
- QPID_LOG(warning, "Could not parse XML content (or message headers):" << msgContent);
- return 0;
- }
- catch (...) {
- QPID_LOG(warning, "Unexpected error routing message: " << msgContent);
- return 0;
- }
- return 0;
-}
-
-void XmlExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* args)
-{
- try {
- RWlock::ScopedRlock l(lock);
- XmlBinding::vector& bindings(bindingsMap[routingKey]);
- XmlBinding::vector::iterator i;
- int count(0);
-
- for (i = bindings.begin(); i != bindings.end(); i++) {
-
- if ((*i)->xquery && matches((*i)->xquery, msg, args)) { // Overly defensive? There should always be a query ...
- msg.deliverTo((*i)->queue);
- count++;
- QPID_LOG(trace, "Delivered to queue" );
-
- if ((*i)->mgmtBinding != 0)
- (*i)->mgmtBinding->inc_msgMatched ();
- }
-
- if(!count){
- QPID_LOG(warning, "XMLExchange " << getName() << ": could not route message with query " << routingKey);
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgDrops ();
- mgmtExchange->inc_byteDrops (msg.contentSize ());
- }
- }
- else {
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgRoutes (count);
- mgmtExchange->inc_byteRoutes (count * msg.contentSize ());
- }
- }
-
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgReceives ();
- mgmtExchange->inc_byteReceives (msg.contentSize ());
- }
- }
- }
- catch (...) {
- QPID_LOG(warning, "XMLExchange " << getName() << ": exception routing message with query " << routingKey);
- }
-
-
-}
-
-
-bool XmlExchange::isBound(Queue::shared_ptr queue, const string* const routingKey, const FieldTable* const)
-{
- XmlBinding::vector::iterator j;
-
- if (routingKey) {
- XmlBindingsMap::iterator i = bindingsMap.find(*routingKey);
-
- if (i == bindingsMap.end())
- return false;
- if (!queue)
- return true;
- for (j = i->second.begin(); j != i->second.end(); j++)
- if ((*j)->queue == queue)
- return true;
- } else if (!queue) {
- //if no queue or routing key is specified, just report whether any bindings exist
- return bindingsMap.size() > 0;
- } else {
- for (XmlBindingsMap::iterator i = bindingsMap.begin(); i != bindingsMap.end(); i++)
- for (j = i->second.begin(); j != i->second.end(); j++)
- if ((*j)->queue == queue)
- return true;
- return false;
- }
-
- return false;
-}
-
-
-XmlExchange::~XmlExchange()
-{
- bindingsMap.clear();
-}
-
-const std::string XmlExchange::typeName("xml");
-
-}
-}
diff --git a/cpp/src/qpid/broker/XmlExchange.h b/cpp/src/qpid/broker/XmlExchange.h
deleted file mode 100644
index 883bfceaca..0000000000
--- a/cpp/src/qpid/broker/XmlExchange.h
+++ /dev/null
@@ -1,87 +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.
- *
- */
-#ifndef _XmlExchange_
-#define _XmlExchange_
-
-#include "Exchange.h"
-#include "qpid/framing/FieldTable.h"
-#include "qpid/sys/Monitor.h"
-#include "Queue.h"
-
-#include <xqilla/xqilla-simple.hpp>
-
-#include <boost/scoped_ptr.hpp>
-
-#include <map>
-#include <vector>
-
-namespace qpid {
-namespace broker {
-
-class XmlExchange : public virtual Exchange {
-
- typedef boost::shared_ptr<XQQuery> Query;
-
- struct XmlBinding : public Exchange::Binding {
- typedef boost::shared_ptr<XmlBinding> shared_ptr;
- typedef std::vector<XmlBinding::shared_ptr> vector;
-
- boost::shared_ptr<XQQuery> xquery;
-
- XmlBinding(const std::string& key, const Queue::shared_ptr queue, Exchange* parent, Query query):
- Binding(key, queue, parent), xquery(query) {}
- };
-
-
- typedef std::map<string, XmlBinding::vector > XmlBindingsMap;
-
- XmlBindingsMap bindingsMap;
- XQilla xqilla;
- qpid::sys::RWlock lock;
-
- bool matches(Query& query, Deliverable& msg, const qpid::framing::FieldTable* args);
-
- public:
- static const std::string typeName;
-
- XmlExchange(const std::string& name, management::Manageable* parent = 0);
- XmlExchange(const string& _name, bool _durable,
- const qpid::framing::FieldTable& _args, management::Manageable* parent = 0);
-
- virtual std::string getType() const { return typeName; }
-
- virtual bool bind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
-
- virtual bool unbind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
-
- virtual void route(Deliverable& msg, const std::string& routingKey, const qpid::framing::FieldTable* args);
-
- virtual bool isBound(Queue::shared_ptr queue, const string* const routingKey, const qpid::framing::FieldTable* const args);
-
- virtual ~XmlExchange();
-};
-
-
-}
-}
-
-
-#endif
diff --git a/cpp/src/qpid/broker/posix/BrokerDefaults.cpp b/cpp/src/qpid/broker/posix/BrokerDefaults.cpp
new file mode 100644
index 0000000000..9e463fa32d
--- /dev/null
+++ b/cpp/src/qpid/broker/posix/BrokerDefaults.cpp
@@ -0,0 +1,40 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/broker/Broker.h"
+#include <stdlib.h>
+
+namespace qpid {
+namespace broker {
+
+const std::string Broker::Options::DEFAULT_DATA_DIR_LOCATION("/tmp");
+const std::string Broker::Options::DEFAULT_DATA_DIR_NAME("/.qpidd");
+
+std::string
+Broker::Options::getHome() {
+ std::string home;
+ char *home_c = ::getenv("HOME");
+ if (home_c != 0)
+ home += home_c;
+ return home;
+}
+
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/windows/BrokerDefaults.cpp b/cpp/src/qpid/broker/windows/BrokerDefaults.cpp
new file mode 100644
index 0000000000..b6862f0418
--- /dev/null
+++ b/cpp/src/qpid/broker/windows/BrokerDefaults.cpp
@@ -0,0 +1,41 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/broker/Broker.h"
+#include <stdlib.h>
+
+namespace qpid {
+namespace broker {
+
+const std::string Broker::Options::DEFAULT_DATA_DIR_LOCATION("\\TEMP");
+const std::string Broker::Options::DEFAULT_DATA_DIR_NAME("\\QPIDD.DATA");
+
+std::string
+Broker::Options::getHome() {
+ std::string home;
+ char home_c[MAX_PATH+1];
+ size_t unused;
+ if (0 == getenv_s (&unused, home_c, sizeof(home_c), "HOME"))
+ home += home_c;
+ return home;
+}
+
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/windows/SaslAuthenticator.cpp b/cpp/src/qpid/broker/windows/SaslAuthenticator.cpp
new file mode 100644
index 0000000000..212d7c4db4
--- /dev/null
+++ b/cpp/src/qpid/broker/windows/SaslAuthenticator.cpp
@@ -0,0 +1,190 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+// This source is only used on Windows; SSPI is the Windows mechanism for
+// accessing authentication mechanisms, analogous to Cyrus SASL.
+
+#include "qpid/broker/Connection.h"
+#include "qpid/log/Statement.h"
+#include "qpid/framing/reply_exceptions.h"
+
+#include <windows.h>
+
+using namespace qpid::framing;
+using qpid::sys::SecurityLayer;
+
+namespace qpid {
+namespace broker {
+
+class NullAuthenticator : public SaslAuthenticator
+{
+ Connection& connection;
+ framing::AMQP_ClientProxy::Connection client;
+public:
+ NullAuthenticator(Connection& connection);
+ ~NullAuthenticator();
+ void getMechanisms(framing::Array& mechanisms);
+ void start(const std::string& mechanism, const std::string& response);
+ void step(const std::string&) {}
+ std::auto_ptr<SecurityLayer> getSecurityLayer(uint16_t maxFrameSize);
+};
+
+class SspiAuthenticator : public SaslAuthenticator
+{
+ HANDLE userToken;
+ Connection& connection;
+ framing::AMQP_ClientProxy::Connection client;
+
+public:
+ SspiAuthenticator(Connection& connection);
+ ~SspiAuthenticator();
+ void getMechanisms(framing::Array& mechanisms);
+ void start(const std::string& mechanism, const std::string& response);
+ void step(const std::string& response);
+ std::auto_ptr<SecurityLayer> getSecurityLayer(uint16_t maxFrameSize);
+};
+
+bool SaslAuthenticator::available(void)
+{
+ return true;
+}
+
+// Initialize the SASL mechanism; throw if it fails.
+void SaslAuthenticator::init(const std::string& /*saslName*/)
+{
+ return;
+}
+
+void SaslAuthenticator::fini(void)
+{
+ return;
+}
+
+std::auto_ptr<SaslAuthenticator> SaslAuthenticator::createAuthenticator(Connection& c)
+{
+ if (c.getBroker().getOptions().auth) {
+ return std::auto_ptr<SaslAuthenticator>(new SspiAuthenticator(c));
+ } else {
+ return std::auto_ptr<SaslAuthenticator>(new NullAuthenticator(c));
+ }
+}
+
+NullAuthenticator::NullAuthenticator(Connection& c) : connection(c), client(c.getOutput()) {}
+NullAuthenticator::~NullAuthenticator() {}
+
+void NullAuthenticator::getMechanisms(Array& mechanisms)
+{
+ mechanisms.add(boost::shared_ptr<FieldValue>(new Str16Value("ANONYMOUS")));
+}
+
+void NullAuthenticator::start(const string& mechanism, const string& response)
+{
+ QPID_LOG(warning, "SASL: No Authentication Performed");
+ if (mechanism == "PLAIN") { // Old behavior
+ if (response.size() > 0 && response[0] == (char) 0) {
+ string temp = response.substr(1);
+ string::size_type i = temp.find((char)0);
+ string uid = temp.substr(0, i);
+ string pwd = temp.substr(i + 1);
+ connection.setUserId(uid);
+ }
+ } else {
+ connection.setUserId("anonymous");
+ }
+ client.tune(framing::CHANNEL_MAX, connection.getFrameMax(), 0, 0);
+}
+
+std::auto_ptr<SecurityLayer> NullAuthenticator::getSecurityLayer(uint16_t)
+{
+ std::auto_ptr<SecurityLayer> securityLayer;
+ return securityLayer;
+}
+
+
+SspiAuthenticator::SspiAuthenticator(Connection& c) : userToken(INVALID_HANDLE_VALUE), connection(c), client(c.getOutput())
+{
+}
+
+SspiAuthenticator::~SspiAuthenticator()
+{
+ if (INVALID_HANDLE_VALUE != userToken) {
+ CloseHandle(userToken);
+ userToken = INVALID_HANDLE_VALUE;
+ }
+}
+
+void SspiAuthenticator::getMechanisms(Array& mechanisms)
+{
+ mechanisms.add(boost::shared_ptr<FieldValue>(new Str16Value(string("ANONYMOUS"))));
+ mechanisms.add(boost::shared_ptr<FieldValue>(new Str16Value(string("PLAIN"))));
+ QPID_LOG(info, "SASL: Mechanism list: ANONYMOUS PLAIN");
+}
+
+void SspiAuthenticator::start(const string& mechanism, const string& response)
+{
+ QPID_LOG(info, "SASL: Starting authentication with mechanism: " << mechanism);
+ if (mechanism == "ANONYMOUS") {
+ connection.setUserId("anonymous");
+ client.tune(framing::CHANNEL_MAX, connection.getFrameMax(), 0, 0);
+ return;
+ }
+ if (mechanism != "PLAIN")
+ throw ConnectionForcedException("Unsupported mechanism");
+
+ // PLAIN's response is composed of 3 strings separated by 0 bytes:
+ // authorization id, authentication id (user), clear-text password.
+ if (response.size() == 0)
+ throw ConnectionForcedException("Authentication failed");
+
+ string::size_type i = response.find((char)0);
+ string auth = response.substr(0, i);
+ string::size_type j = response.find((char)0, i+1);
+ string uid = response.substr(i+1, j-1);
+ string pwd = response.substr(j+1);
+ int error = 0;
+ if (!LogonUser(uid.c_str(), ".", pwd.c_str(),
+ LOGON32_LOGON_NETWORK,
+ LOGON32_PROVIDER_DEFAULT,
+ &userToken))
+ error = GetLastError();
+ pwd.replace(0, string::npos, 1, (char)0);
+ if (error != 0) {
+ QPID_LOG(info,
+ "SASL: Auth failed [" << error << "]: " << qpid::sys::strError(error));
+ throw ConnectionForcedException("Authentication failed");
+ }
+
+ connection.setUserId(uid);
+ client.tune(framing::CHANNEL_MAX, connection.getFrameMax(), 0, 0);
+}
+
+void SspiAuthenticator::step(const string& response)
+{
+ QPID_LOG(info, "SASL: Need another step!!!");
+}
+
+std::auto_ptr<SecurityLayer> SspiAuthenticator::getSecurityLayer(uint16_t)
+{
+ std::auto_ptr<SecurityLayer> securityLayer;
+ return securityLayer;
+}
+
+}}
diff --git a/cpp/src/qpid/client/AckMode.h b/cpp/src/qpid/client/AckMode.h
deleted file mode 100644
index b411c322d8..0000000000
--- a/cpp/src/qpid/client/AckMode.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef _client_AckMode_h
-#define _client_AckMode_h
-
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-namespace qpid {
-namespace client {
-
-/**
- * DEPRECATED
- *
- * The available acknowledgement modes for Channel (now also deprecated).
- */
-enum AckMode {
- /** No acknowledgement will be sent, broker can
- discard messages as soon as they are delivered
- to a consumer using this mode. **/
- NO_ACK = 0,
- /** Each message will be automatically
- acknowledged as soon as it is delivered to the
- application. **/
- AUTO_ACK = 1,
- /** Acknowledgements will be sent automatically,
- but not for each message. **/
- LAZY_ACK = 2,
- /** The application is responsible for explicitly
- acknowledging messages. **/
- CLIENT_ACK = 3
-};
-
-}} // namespace qpid::client
-
-#endif
diff --git a/cpp/src/qpid/client/AckPolicy.cpp b/cpp/src/qpid/client/AckPolicy.cpp
deleted file mode 100644
index 7956ebad0f..0000000000
--- a/cpp/src/qpid/client/AckPolicy.cpp
+++ /dev/null
@@ -1,50 +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 "AckPolicy.h"
-
-namespace qpid {
-namespace client {
-
-AckPolicy::AckPolicy(size_t n) : interval(n), count(n) {}
-
-void AckPolicy::ack(const Message& msg, AsyncSession session)
-{
- accepted.add(msg.getId());
- if (interval && --count==0) {
- session.markCompleted(msg.getId(), false, true);
- session.messageAccept(accepted);
- accepted.clear();
- count = interval;
- } else {
- session.markCompleted(msg.getId(), false, false);
- }
-}
-
-void AckPolicy::ackOutstanding(AsyncSession session)
-{
- if (!accepted.empty()) {
- session.messageAccept(accepted);
- accepted.clear();
- session.sendCompletion();
- }
-}
-
-}} // namespace qpid::client
diff --git a/cpp/src/qpid/client/AckPolicy.h b/cpp/src/qpid/client/AckPolicy.h
deleted file mode 100644
index b34f1d15d1..0000000000
--- a/cpp/src/qpid/client/AckPolicy.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef QPID_CLIENT_ACKPOLICY_H
-#define QPID_CLIENT_ACKPOLICY_H
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/framing/SequenceSet.h"
-#include "qpid/client/AsyncSession.h"
-#include "qpid/client/Message.h"
-
-namespace qpid {
-namespace client {
-
-/**
- * Policy for automatic acknowledgement of messages.
- *
- *
- * \ingroup clientapi
- */
-class AckPolicy
-{
- framing::SequenceSet accepted;
- size_t interval;
- size_t count;
-
- public:
- /**
- * Sends accepts and marks completion of received transfers.
- *
- *@param n: acknowledge every n messages.
- *n==0 means no automatic acknowledgement.
- */
- AckPolicy(size_t n=1);
- void ack(const Message& msg, AsyncSession session);
- void ackOutstanding(AsyncSession session);};
-
-}} // namespace qpid::client
-
-
-
-#endif /*!QPID_CLIENT_ACKPOLICY_H*/
diff --git a/cpp/src/qpid/client/AsyncSession.h b/cpp/src/qpid/client/AsyncSession.h
deleted file mode 100644
index 150aabe191..0000000000
--- a/cpp/src/qpid/client/AsyncSession.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef QPID_CLIENT_ASYNCSESSION_H
-#define QPID_CLIENT_ASYNCSESSION_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/client/AsyncSession_0_10.h"
-
-namespace qpid {
-namespace client {
-
-/**
- * AsyncSession is an alias for Session_0_10
- *
- * \ingroup clientapi
- */
-typedef AsyncSession_0_10 AsyncSession;
-
-}} // namespace qpid::client
-
-#endif /*!QPID_CLIENT_ASYNCSESSION_H*/
diff --git a/cpp/src/qpid/client/Bounds.cpp b/cpp/src/qpid/client/Bounds.cpp
index aac18022bc..abb983a62e 100644
--- a/cpp/src/qpid/client/Bounds.cpp
+++ b/cpp/src/qpid/client/Bounds.cpp
@@ -1,4 +1,24 @@
-#include "Bounds.h"
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/Bounds.h"
#include "qpid/log/Statement.h"
#include "qpid/sys/Waitable.h"
@@ -28,8 +48,7 @@ void Bounds::reduce(size_t size) {
if (current == 0) return;
current -= std::min(size, current);
if (current < max && lock.hasWaiters()) {
- assert(lock.hasWaiters() == 1);
- lock.notify();
+ lock.notifyAll();
}
}
diff --git a/cpp/src/qpid/client/Completion.cpp b/cpp/src/qpid/client/Completion.cpp
new file mode 100644
index 0000000000..a97c8c3534
--- /dev/null
+++ b/cpp/src/qpid/client/Completion.cpp
@@ -0,0 +1,40 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/client/Completion.h"
+#include "qpid/client/CompletionImpl.h"
+#include "qpid/client/PrivateImplRef.h"
+
+namespace qpid {
+namespace client {
+
+typedef PrivateImplRef<Completion> PI;
+Completion::Completion(CompletionImpl* p) { PI::ctor(*this, p); }
+Completion::Completion(const Completion& c) : Handle<CompletionImpl>() { PI::copy(*this, c); }
+Completion::~Completion() { PI::dtor(*this); }
+Completion& Completion::operator=(const Completion& c) { return PI::assign(*this, c); }
+
+
+void Completion::wait() { impl->wait(); }
+bool Completion::isComplete() { return impl->isComplete(); }
+std::string Completion::getResult() { return impl->getResult(); }
+
+}} // namespace qpid::client
diff --git a/cpp/src/qpid/client/Completion.h b/cpp/src/qpid/client/Completion.h
deleted file mode 100644
index c4979d7934..0000000000
--- a/cpp/src/qpid/client/Completion.h
+++ /dev/null
@@ -1,71 +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.
- *
- */
-
-#ifndef _Completion_
-#define _Completion_
-
-#include <boost/shared_ptr.hpp>
-#include "Future.h"
-#include "SessionImpl.h"
-
-namespace qpid {
-namespace client {
-
-/**
- * Asynchronous commands that do not return a result will return a
- * Completion. You can use the completion to wait for that specific
- * command to complete.
- *
- *@see TypedResult
- *
- *\ingroup clientapi
- */
-class Completion
-{
-protected:
- Future future;
- shared_ptr<SessionImpl> session;
-
-public:
- ///@internal
- Completion() {}
-
- ///@internal
- Completion(Future f, shared_ptr<SessionImpl> s) : future(f), session(s) {}
-
- /** Wait for the asynchronous command that returned this
- *Completion to complete.
- *
- *@exception If the command returns an error, get() throws an exception.
- */
- void wait()
- {
- future.wait(*session);
- }
-
- bool isComplete() {
- return future.isComplete(*session);
- }
-};
-
-}}
-
-#endif
diff --git a/cpp/src/qpid/client/CompletionImpl.h b/cpp/src/qpid/client/CompletionImpl.h
new file mode 100644
index 0000000000..f180708316
--- /dev/null
+++ b/cpp/src/qpid/client/CompletionImpl.h
@@ -0,0 +1,51 @@
+#ifndef QPID_CLIENT_COMPLETIONIMPL_H
+#define QPID_CLIENT_COMPLETIONIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/RefCounted.h"
+#include "qpid/client/Future.h"
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace client {
+
+///@internal
+class CompletionImpl : public RefCounted
+{
+public:
+ CompletionImpl() {}
+ CompletionImpl(Future f, boost::shared_ptr<SessionImpl> s) : future(f), session(s) {}
+
+ bool isComplete() { return future.isComplete(*session); }
+ void wait() { future.wait(*session); }
+ std::string getResult() { return future.getResult(*session); }
+
+protected:
+ Future future;
+ boost::shared_ptr<SessionImpl> session;
+};
+
+}} // namespace qpid::client
+
+
+#endif /*!QPID_CLIENT_COMPLETIONIMPL_H*/
diff --git a/cpp/src/qpid/client/Connection.cpp b/cpp/src/qpid/client/Connection.cpp
index 6572794516..32a01b2c40 100644
--- a/cpp/src/qpid/client/Connection.cpp
+++ b/cpp/src/qpid/client/Connection.cpp
@@ -18,15 +18,16 @@
* under the License.
*
*/
-#include "Connection.h"
-#include "ConnectionSettings.h"
-#include "Message.h"
-#include "SessionImpl.h"
-#include "SessionBase_0_10Access.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/ConnectionImpl.h"
+#include "qpid/client/ConnectionSettings.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/SessionImpl.h"
+#include "qpid/client/SessionBase_0_10Access.h"
+#include "qpid/Url.h"
#include "qpid/log/Logger.h"
#include "qpid/log/Options.h"
#include "qpid/log/Statement.h"
-#include "qpid/shared_ptr.h"
#include "qpid/framing/AMQP_HighestVersion.h"
#include <algorithm>
@@ -35,6 +36,7 @@
#include <functional>
#include <boost/format.hpp>
#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
using namespace qpid::framing;
using namespace qpid::sys;
@@ -43,9 +45,45 @@ using namespace qpid::sys;
namespace qpid {
namespace client {
-Connection::Connection() : channelIdCounter(0), version(framing::highestProtocolVersion) {}
+Connection::Connection() : version(framing::highestProtocolVersion) {}
-Connection::~Connection(){ }
+Connection::~Connection() {}
+
+void Connection::open(
+ const Url& url,
+ const std::string& uid, const std::string& pwd,
+ const std::string& vhost,
+ uint16_t maxFrameSize)
+{
+ ConnectionSettings settings;
+ settings.username = uid;
+ settings.password = pwd;
+ settings.virtualhost = vhost;
+ settings.maxFrameSize = maxFrameSize;
+ open(url, settings);
+}
+
+void Connection::open(const Url& url, const ConnectionSettings& settings) {
+ if (url.empty())
+ throw Exception(QPID_MSG("Attempt to open URL with no addresses."));
+ Url::const_iterator i = url.begin();
+ do {
+ const TcpAddress* tcp = i->get<TcpAddress>();
+ i++;
+ if (tcp) {
+ try {
+ ConnectionSettings cs(settings);
+ cs.host = tcp->host;
+ cs.port = tcp->port;
+ open(cs);
+ break;
+ }
+ catch (const Exception& /*e*/) {
+ if (i == url.end()) throw;
+ }
+ }
+ } while (i != url.end());
+}
void Connection::open(
const std::string& host, int port,
@@ -67,39 +105,55 @@ bool Connection::isOpen() const {
return impl && impl->isOpen();
}
+void
+Connection::registerFailureCallback ( boost::function<void ()> fn ) {
+ failureCallback = fn;
+ if ( impl )
+ impl->registerFailureCallback ( fn );
+}
+
+
+
void Connection::open(const ConnectionSettings& settings)
{
if (isOpen())
throw Exception(QPID_MSG("Connection::open() was already called"));
- impl = shared_ptr<ConnectionImpl>(new ConnectionImpl(version, settings));
- impl->open(settings.host, settings.port);
- max_frame_size = impl->getNegotiatedSettings().maxFrameSize;
+ impl = boost::shared_ptr<ConnectionImpl>(new ConnectionImpl(version, settings));
+ impl->open();
+ if ( failureCallback )
+ impl->registerFailureCallback ( failureCallback );
+}
+
+const ConnectionSettings& Connection::getNegotiatedSettings()
+{
+ if (!isOpen())
+ throw Exception(QPID_MSG("Connection is not open."));
+ return impl->getNegotiatedSettings();
}
-Session Connection::newSession(const std::string& name) {
+Session Connection::newSession(const std::string& name, uint32_t timeout) {
if (!isOpen())
throw Exception(QPID_MSG("Connection has not yet been opened"));
- shared_ptr<SessionImpl> simpl(
- new SessionImpl(name, impl, ++channelIdCounter, max_frame_size));
- impl->addSession(simpl);
- simpl->open(0);
Session s;
- SessionBase_0_10Access(s).set(simpl);
+ SessionBase_0_10Access(s).set(impl->newSession(name, timeout));
return s;
}
void Connection::resume(Session& session) {
if (!isOpen())
throw Exception(QPID_MSG("Connection is not open."));
-
- session.impl->setChannel(++channelIdCounter);
impl->addSession(session.impl);
session.impl->resume(impl);
}
void Connection::close() {
- impl->close();
+ if ( impl )
+ impl->close();
+}
+
+std::vector<Url> Connection::getInitialBrokers() {
+ return impl ? impl->getInitialBrokers() : std::vector<Url>();
}
}} // namespace qpid::client
diff --git a/cpp/src/qpid/client/Connection.h b/cpp/src/qpid/client/Connection.h
deleted file mode 100644
index ee543e20d2..0000000000
--- a/cpp/src/qpid/client/Connection.h
+++ /dev/null
@@ -1,149 +0,0 @@
-#ifndef _client_Connection_
-#define _client_Connection_
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include <map>
-#include <string>
-#include "qpid/client/Session.h"
-
-namespace qpid {
-namespace client {
-
-class ConnectionSettings;
-
-/**
- * Represents a connection to an AMQP broker. All communication is
- * initiated by establishing a connection, then creating one or more
- * Session objecst using the connection. @see newSession()
- *
- * \ingroup clientapi
- */
-class Connection
-{
- framing::ChannelId channelIdCounter;
- framing::ProtocolVersion version;
- uint16_t max_frame_size;
-
- protected:
- boost::shared_ptr<ConnectionImpl> impl;
-
- public:
- /**
- * Creates a connection object, but does not open the connection.
- * @see open()
- */
- Connection();
- ~Connection();
-
- /**
- * Opens a connection to a broker.
- *
- * @param host the host on which the broker is running.
- *
- * @param port the port on the which the broker is listening.
- *
- * @param uid the userid to connect with.
- *
- * @param pwd the password to connect with (currently SASL
- * PLAIN is the only authentication method supported so this
- * is sent in clear text).
- *
- * @param virtualhost the AMQP virtual host to use (virtual
- * hosts, where implemented(!), provide namespace partitioning
- * within a single broker).
- */
- void open(const std::string& host, int port = 5672,
- const std::string& uid = "guest",
- const std::string& pwd = "guest",
- const std::string& virtualhost = "/", uint16_t maxFrameSize=65535);
-
- /**
- * Opens a connection to a broker.
- *
- * @param the settings to use (host, port etc) @see ConnectionSettings
- */
- void open(const ConnectionSettings& settings);
-
- /**
- * Close the connection.
- *
- * Any further use of this connection (without reopening it) will
- * not succeed.
- */
- void close();
-
- /**
- * Create a new session on this connection. Sessions allow
- * multiple streams of work to be multiplexed over the same
- * connection. The returned Session provides functions to send
- * commands to the broker.
- *
- * Session functions are synchronous. In other words, a Session
- * function will send a command to the broker and does not return
- * until it receives the broker's response confirming the command
- * was executed.
- *
- * AsyncSession provides asynchronous versions of the same
- * functions. These functions send a command to the broker but do
- * not wait for a response.
- *
- * You can convert a Session s into an AsyncSession as follows:
- * @code
- * #include <qpid/client/AsyncSession.h>
- * AsyncSession as = async(s);
- * @endcode
- *
- * You can execute a single command asynchronously will a Session s
- * like ths:
- * @code
- * async(s).messageTransfer(...);
- * @endcode
- *
- * Using an AsyncSession is faster for sending large numbers of
- * commands, since each command is sent as soon as possible
- * without waiting for the previous command to be confirmed.
- *
- * However with AsyncSession you cannot assume that a command has
- * completed until you explicitly synchronize. The simplest way to
- * do this is to call Session::sync() or AsyncSession::sync().
- * Both of these functions wait for the broker to confirm all
- * commands issued so far on the session.
- *
- *@param name: A name to identify the session. @see qpid::SessionId
- * If the name is empty (the default) then a unique name will be
- * chosen using a Universally-unique identifier (UUID) algorithm.
- */
- Session newSession(const std::string& name=std::string());
-
- /**
- * Resume a suspended session. A session may be resumed
- * on a different connection to the one that created it.
- */
- void resume(Session& session);
-
- bool isOpen() const;
-};
-
-}} // namespace qpid::client
-
-
-#endif
diff --git a/cpp/src/qpid/client/ConnectionAccess.h b/cpp/src/qpid/client/ConnectionAccess.h
new file mode 100644
index 0000000000..b662fd5d8b
--- /dev/null
+++ b/cpp/src/qpid/client/ConnectionAccess.h
@@ -0,0 +1,41 @@
+#ifndef QPID_CLIENT_CONNECTIONACCESS_H
+#define QPID_CLIENT_CONNECTIONACCESS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/Connection.h"
+
+/**@file @internal Internal use only */
+
+namespace qpid {
+namespace client {
+
+
+
+struct ConnectionAccess {
+ static void setVersion(Connection& c, const framing::ProtocolVersion& v) { c.version = v; }
+ static boost::shared_ptr<ConnectionImpl> getImpl(Connection& c) { return c.impl; }
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_CONNECTIONACCESS_H*/
diff --git a/cpp/src/qpid/client/ConnectionHandler.cpp b/cpp/src/qpid/client/ConnectionHandler.cpp
index 22ebec76bf..8f1cc7b03f 100644
--- a/cpp/src/qpid/client/ConnectionHandler.cpp
+++ b/cpp/src/qpid/client/ConnectionHandler.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -19,17 +19,28 @@
*
*/
-#include "ConnectionHandler.h"
+#include "qpid/client/ConnectionHandler.h"
-#include "qpid/log/Statement.h"
+#include "qpid/client/SaslFactory.h"
#include "qpid/framing/amqp_framing.h"
#include "qpid/framing/all_method_bodies.h"
#include "qpid/framing/ClientInvoker.h"
#include "qpid/framing/reply_exceptions.h"
+#include "qpid/log/Helpers.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/SystemInfo.h"
using namespace qpid::client;
using namespace qpid::framing;
-using namespace boost;
+using namespace qpid::framing::connection;
+using qpid::sys::SecurityLayer;
+using qpid::sys::Duration;
+using qpid::sys::TimerTask;
+using qpid::sys::Timer;
+using qpid::sys::AbsTime;
+using qpid::sys::TIME_SEC;
+using qpid::sys::ScopedLock;
+using qpid::sys::Mutex;
namespace {
const std::string OK("OK");
@@ -40,24 +51,54 @@ const std::string INVALID_STATE_START("start received in invalid state");
const std::string INVALID_STATE_TUNE("tune received in invalid state");
const std::string INVALID_STATE_OPEN_OK("open-ok received in invalid state");
const std::string INVALID_STATE_CLOSE_OK("close-ok received in invalid state");
+
+const std::string SESSION_FLOW_CONTROL("qpid.session_flow");
+const std::string CLIENT_PROCESS_NAME("qpid.client_process");
+const std::string CLIENT_PID("qpid.client_pid");
+const std::string CLIENT_PPID("qpid.client_ppid");
+const int SESSION_FLOW_CONTROL_VER = 1;
}
-ConnectionHandler::ConnectionHandler(const ConnectionSettings& s, framing::ProtocolVersion& v)
- : StateManager(NOT_STARTED), ConnectionSettings(s), outHandler(*this), proxy(outHandler), errorCode(200), version(v)
-{
+CloseCode ConnectionHandler::convert(uint16_t replyCode)
+{
+ switch (replyCode) {
+ case 200: return CLOSE_CODE_NORMAL;
+ case 320: return CLOSE_CODE_CONNECTION_FORCED;
+ case 402: return CLOSE_CODE_INVALID_PATH;
+ case 501: default:
+ return CLOSE_CODE_FRAMING_ERROR;
+ }
+}
+
+ConnectionHandler::ConnectionHandler(const ConnectionSettings& s, ProtocolVersion& v)
+ : StateManager(NOT_STARTED), ConnectionSettings(s), outHandler(*this), proxy(outHandler),
+ errorCode(CLOSE_CODE_NORMAL), version(v)
+{
insist = true;
ESTABLISHED.insert(FAILED);
ESTABLISHED.insert(CLOSED);
ESTABLISHED.insert(OPEN);
-}
+
+ FINISHED.insert(FAILED);
+ FINISHED.insert(CLOSED);
+
+ properties.setInt(SESSION_FLOW_CONTROL, SESSION_FLOW_CONTROL_VER);
+ properties.setString(CLIENT_PROCESS_NAME, sys::SystemInfo::getProcessName());
+ properties.setInt(CLIENT_PID, sys::SystemInfo::getProcessId());
+ properties.setInt(CLIENT_PPID, sys::SystemInfo::getParentProcessId());
+}
void ConnectionHandler::incoming(AMQFrame& frame)
{
if (getState() == CLOSED) {
- throw Exception("Received frame on closed connection");
+ throw Exception("Received frame on closed connection");
}
+ if (rcvTimeoutTask) {
+ // Received frame on connection so delay timeout
+ rcvTimeoutTask->restart();
+ }
AMQBody* body = frame.getBody();
try {
@@ -67,26 +108,27 @@ void ConnectionHandler::incoming(AMQFrame& frame)
in(frame);
break;
case CLOSING:
- QPID_LOG(warning, "Ignoring frame while closing connection: " << frame);
+ QPID_LOG(warning, "Ignoring frame while closing connection: " << frame);
break;
default:
throw Exception("Cannot receive frames on non-zero channel until connection is established.");
}
}
}catch(std::exception& e){
- QPID_LOG(warning, "Closing connection due to " << e.what());
+ QPID_LOG(warning, "Closing connection due to " << e.what());
setState(CLOSING);
- proxy.close(501, e.what());
- if (onError) onError(501, e.what());
+ errorCode = CLOSE_CODE_FRAMING_ERROR;
+ errorText = e.what();
+ proxy.close(501, e.what());
}
}
void ConnectionHandler::outgoing(AMQFrame& frame)
{
- if (getState() == OPEN)
+ if (getState() == OPEN)
out(frame);
else
- throw Exception(errorText.empty() ? "Connection is not open." : errorText);
+ throw TransportFailure(errorText.empty() ? "Connection is not open." : errorText);
}
void ConnectionHandler::waitForOpen()
@@ -105,14 +147,29 @@ void ConnectionHandler::close()
fail("Connection closed before it was established");
break;
case OPEN:
- setState(CLOSING);
- proxy.close(200, OK);
- waitFor(CLOSED);
+ if (setState(CLOSING, OPEN)) {
+ proxy.close(200, OK);
+ waitFor(FINISHED);//FINISHED = CLOSED or FAILED
+ }
+ //else, state was changed from open after we checked, can only
+ //change to failed or closed, so nothing to do
break;
- // Nothing to do for CLOSING, CLOSED, FAILED or NOT_STARTED
+
+ // Nothing to do if already CLOSING, CLOSED, FAILED or if NOT_STARTED
}
}
+void ConnectionHandler::heartbeat()
+{
+ // Do nothing - the purpose of heartbeats is just to make sure that there is some
+ // traffic on the connection within the heart beat interval, we check for the
+ // traffic and don't need to do anything in response to heartbeats
+
+ // Although the above is still true we're now using a received heartbeat as a trigger
+ // to send out our own heartbeat
+ proxy.heartbeat();
+}
+
void ConnectionHandler::checkState(STATES s, const std::string& msg)
{
if (getState() != s) {
@@ -122,45 +179,92 @@ void ConnectionHandler::checkState(STATES s, const std::string& msg)
void ConnectionHandler::fail(const std::string& message)
{
- errorCode = 502;
+ errorCode = CLOSE_CODE_FRAMING_ERROR;
errorText = message;
QPID_LOG(warning, message);
setState(FAILED);
}
-void ConnectionHandler::start(const FieldTable& /*serverProps*/, const Array& /*mechanisms*/, const Array& /*locales*/)
+namespace {
+std::string SPACE(" ");
+}
+
+void ConnectionHandler::start(const FieldTable& /*serverProps*/, const Array& mechanisms, const Array& /*locales*/)
{
checkState(NOT_STARTED, INVALID_STATE_START);
setState(NEGOTIATING);
- //TODO: verify that desired mechanism and locale are supported
- string response = ((char)0) + username + ((char)0) + password;
- proxy.startOk(properties, mechanism, response, locale);
+ sasl = SaslFactory::getInstance().create(*this);
+
+ std::string mechlist;
+ bool chosenMechanismSupported = mechanism.empty();
+ for (Array::const_iterator i = mechanisms.begin(); i != mechanisms.end(); ++i) {
+ if (!mechanism.empty() && mechanism == (*i)->get<std::string>()) {
+ chosenMechanismSupported = true;
+ mechlist = (*i)->get<std::string>() + SPACE + mechlist;
+ } else {
+ if (i != mechanisms.begin()) mechlist += SPACE;
+ mechlist += (*i)->get<std::string>();
+ }
+ }
+
+ if (!chosenMechanismSupported) {
+ fail("Selected mechanism not supported: " + mechanism);
+ }
+
+ if (sasl.get()) {
+ string response = sasl->start(mechanism.empty() ? mechlist : mechanism,
+ getSSF ? getSSF() : 0);
+ proxy.startOk(properties, sasl->getMechanism(), response, locale);
+ } else {
+ //TODO: verify that desired mechanism and locale are supported
+ string response = ((char)0) + username + ((char)0) + password;
+ proxy.startOk(properties, mechanism, response, locale);
+ }
}
-void ConnectionHandler::secure(const std::string& /*challenge*/)
+void ConnectionHandler::secure(const std::string& challenge)
{
- throw NotImplementedException("Challenge-response cycle not yet implemented in client");
+ if (sasl.get()) {
+ string response = sasl->step(challenge);
+ proxy.secureOk(response);
+ } else {
+ throw NotImplementedException("Challenge-response cycle not yet implemented in client");
+ }
}
-void ConnectionHandler::tune(uint16_t maxChannelsProposed, uint16_t maxFrameSizeProposed,
- uint16_t /*heartbeatMin*/, uint16_t /*heartbeatMax*/)
+void ConnectionHandler::tune(uint16_t maxChannelsProposed, uint16_t maxFrameSizeProposed,
+ uint16_t heartbeatMin, uint16_t heartbeatMax)
{
checkState(NEGOTIATING, INVALID_STATE_TUNE);
maxChannels = std::min(maxChannels, maxChannelsProposed);
maxFrameSize = std::min(maxFrameSize, maxFrameSizeProposed);
- //TODO: implement heartbeats and check desired value is in valid range
+ // Clip the requested heartbeat to the maximum/minimum offered
+ uint16_t heartbeat = ConnectionSettings::heartbeat;
+ heartbeat = heartbeat < heartbeatMin ? heartbeatMin :
+ heartbeat > heartbeatMax ? heartbeatMax :
+ heartbeat;
+ ConnectionSettings::heartbeat = heartbeat;
proxy.tuneOk(maxChannels, maxFrameSize, heartbeat);
setState(OPENING);
proxy.open(virtualhost, capabilities, insist);
}
-void ConnectionHandler::openOk(const framing::Array& /*knownHosts*/)
+void ConnectionHandler::openOk ( const Array& knownBrokers )
{
checkState(OPENING, INVALID_STATE_OPEN_OK);
- //TODO: store knownHosts for reconnection etc
+ knownBrokersUrls.clear();
+ framing::Array::ValueVector::const_iterator i;
+ for ( i = knownBrokers.begin(); i != knownBrokers.end(); ++i )
+ knownBrokersUrls.push_back(Url((*i)->get<std::string>()));
+ if (sasl.get()) {
+ securityLayer = sasl->getSecurityLayer(maxFrameSize);
+ operUserId = sasl->getUserId();
+ }
setState(OPEN);
+ QPID_LOG(debug, "Known-brokers for connection: " << log::formatList(knownBrokersUrls));
}
+
void ConnectionHandler::redirect(const std::string& /*host*/, const Array& /*knownHosts*/)
{
throw NotImplementedException("Redirection received from broker; not yet implemented in client");
@@ -169,7 +273,7 @@ void ConnectionHandler::redirect(const std::string& /*host*/, const Array& /*kno
void ConnectionHandler::close(uint16_t replyCode, const std::string& replyText)
{
proxy.closeOk();
- errorCode = replyCode;
+ errorCode = convert(replyCode);
errorText = replyText;
setState(CLOSED);
QPID_LOG(warning, "Broker closed connection: " << replyCode << ", " << replyText);
@@ -181,7 +285,9 @@ void ConnectionHandler::close(uint16_t replyCode, const std::string& replyText)
void ConnectionHandler::closeOk()
{
checkState(CLOSING, INVALID_STATE_CLOSE_OK);
- if (onClose) {
+ if (onError && errorCode != CLOSE_CODE_NORMAL) {
+ onError(errorCode, errorText);
+ } else if (onClose) {
onClose();
}
setState(CLOSED);
@@ -195,5 +301,17 @@ bool ConnectionHandler::isOpen() const
bool ConnectionHandler::isClosed() const
{
int s = getState();
- return s == CLOSING || s == CLOSED || s == FAILED;
+ return s == CLOSED || s == FAILED;
+}
+
+bool ConnectionHandler::isClosing() const { return getState() == CLOSING; }
+
+std::auto_ptr<qpid::sys::SecurityLayer> ConnectionHandler::getSecurityLayer()
+{
+ return securityLayer;
+}
+
+void ConnectionHandler::setRcvTimeoutTask(boost::intrusive_ptr<qpid::sys::TimerTask> t)
+{
+ rcvTimeoutTask = t;
}
diff --git a/cpp/src/qpid/client/ConnectionHandler.h b/cpp/src/qpid/client/ConnectionHandler.h
index f8bd5e5d49..ed1e385dcf 100644
--- a/cpp/src/qpid/client/ConnectionHandler.h
+++ b/cpp/src/qpid/client/ConnectionHandler.h
@@ -21,17 +21,23 @@
#ifndef _ConnectionHandler_
#define _ConnectionHandler_
-#include "ChainableFrameHandler.h"
-#include "ConnectionSettings.h"
-#include "StateManager.h"
+#include "qpid/client/ChainableFrameHandler.h"
+#include "qpid/client/ConnectionSettings.h"
+#include "qpid/client/Sasl.h"
+#include "qpid/client/StateManager.h"
#include "qpid/framing/AMQMethodBody.h"
#include "qpid/framing/AMQP_HighestVersion.h"
#include "qpid/framing/AMQP_ClientOperations.h"
#include "qpid/framing/AMQP_ServerProxy.h"
#include "qpid/framing/Array.h"
+#include "qpid/framing/enum.h"
#include "qpid/framing/FieldTable.h"
#include "qpid/framing/FrameHandler.h"
#include "qpid/framing/InputHandler.h"
+#include "qpid/sys/SecurityLayer.h"
+#include "qpid/sys/Timer.h"
+#include "qpid/Url.h"
+#include <memory>
namespace qpid {
namespace client {
@@ -44,7 +50,7 @@ class ConnectionHandler : private StateManager,
{
typedef framing::AMQP_ClientOperations::ConnectionHandler ConnectionOperations;
enum STATES {NOT_STARTED, NEGOTIATING, OPENING, OPEN, CLOSING, CLOSED, FAILED};
- std::set<int> ESTABLISHED;
+ std::set<int> ESTABLISHED, FINISHED;
class Adapter : public framing::FrameHandler
{
@@ -56,12 +62,16 @@ class ConnectionHandler : private StateManager,
Adapter outHandler;
framing::AMQP_ServerProxy::Connection proxy;
- uint16_t errorCode;
+ framing::connection::CloseCode errorCode;
std::string errorText;
bool insist;
framing::ProtocolVersion version;
framing::Array capabilities;
framing::FieldTable properties;
+ std::auto_ptr<Sasl> sasl;
+ std::auto_ptr<qpid::sys::SecurityLayer> securityLayer;
+ boost::intrusive_ptr<qpid::sys::TimerTask> rcvTimeoutTask;
+ std::string operUserId;
void checkState(STATES s, const std::string& msg);
@@ -79,11 +89,13 @@ class ConnectionHandler : private StateManager,
const framing::Array& knownHosts);
void close(uint16_t replyCode, const std::string& replyText);
void closeOk();
+ void heartbeat();
public:
using InputHandler::handle;
typedef boost::function<void()> CloseListener;
- typedef boost::function<void(uint16_t, const std::string&)> ErrorListener;
+ typedef boost::function<void(uint16_t, const std::string&)> ErrorListener;
+ typedef boost::function<unsigned int()> GetConnSSF;
ConnectionHandler(const ConnectionSettings&, framing::ProtocolVersion&);
@@ -99,9 +111,19 @@ public:
// Note that open and closed aren't related by open = !closed
bool isOpen() const;
bool isClosed() const;
+ bool isClosing() const;
+
+ std::auto_ptr<qpid::sys::SecurityLayer> getSecurityLayer();
+ void setRcvTimeoutTask(boost::intrusive_ptr<qpid::sys::TimerTask>);
CloseListener onClose;
ErrorListener onError;
+
+ std::vector<Url> knownBrokersUrls;
+
+ static framing::connection::CloseCode convert(uint16_t replyCode);
+ const std::string& getUserId() const { return operUserId; }
+ GetConnSSF getSSF; /** query the connection for its security strength factor */
};
}}
diff --git a/cpp/src/qpid/client/ConnectionImpl.cpp b/cpp/src/qpid/client/ConnectionImpl.cpp
index 5e8596cacb..cede7f7310 100644
--- a/cpp/src/qpid/client/ConnectionImpl.cpp
+++ b/cpp/src/qpid/client/ConnectionImpl.cpp
@@ -18,55 +18,97 @@
* under the License.
*
*/
-#include "ConnectionImpl.h"
-#include "Connector.h"
-#include "ConnectionSettings.h"
-#include "SessionImpl.h"
+#include "qpid/client/ConnectionImpl.h"
+#include "qpid/client/Connector.h"
+#include "qpid/client/ConnectionSettings.h"
+#include "qpid/client/SessionImpl.h"
#include "qpid/log/Statement.h"
-#include "qpid/framing/constants.h"
+#include "qpid/Url.h"
+#include "qpid/framing/enum.h"
#include "qpid/framing/reply_exceptions.h"
#include <boost/bind.hpp>
#include <boost/format.hpp>
-using namespace qpid::client;
+#include <limits>
+
+namespace qpid {
+namespace client {
+
using namespace qpid::framing;
+using namespace qpid::framing::connection;
using namespace qpid::sys;
-
using namespace qpid::framing::connection;//for connection error codes
+// Get timer singleton
+Timer& theTimer() {
+ static Mutex timerInitLock;
+ ScopedLock<Mutex> l(timerInitLock);
+
+ static qpid::sys::Timer t;
+ return t;
+}
+
+class HeartbeatTask : public TimerTask {
+ TimeoutHandler& timeout;
+
+ void fire() {
+ // If we ever get here then we have timed out
+ QPID_LOG(debug, "Traffic timeout");
+ timeout.idleIn();
+ }
+
+public:
+ HeartbeatTask(Duration p, TimeoutHandler& t) :
+ TimerTask(p),
+ timeout(t)
+ {}
+};
+
ConnectionImpl::ConnectionImpl(framing::ProtocolVersion v, const ConnectionSettings& settings)
: Bounds(settings.maxFrameSize * settings.bounds),
handler(settings, v),
- connector(new Connector(v, settings, this)),
- version(v)
+ version(v),
+ nextChannel(1)
{
- QPID_LOG(debug, "ConnectionImpl created for " << version);
+ QPID_LOG(debug, "ConnectionImpl created for " << version.toString());
handler.in = boost::bind(&ConnectionImpl::incoming, this, _1);
handler.out = boost::bind(&Connector::send, boost::ref(connector), _1);
handler.onClose = boost::bind(&ConnectionImpl::closed, this,
- NORMAL, std::string());
- connector->setInputHandler(&handler);
- connector->setShutdownHandler(this);
-
+ CLOSE_CODE_NORMAL, std::string());
//only set error handler once open
handler.onError = boost::bind(&ConnectionImpl::closed, this, _1, _2);
+ handler.getSSF = boost::bind(&Connector::getSSF, boost::ref(connector));
}
+const uint16_t ConnectionImpl::NEXT_CHANNEL = std::numeric_limits<uint16_t>::max();
+
ConnectionImpl::~ConnectionImpl() {
// Important to close the connector first, to ensure the
// connector thread does not call on us while the destructor
// is running.
- connector->close();
+ if (connector) connector->close();
}
-void ConnectionImpl::addSession(const boost::shared_ptr<SessionImpl>& session)
+void ConnectionImpl::addSession(const boost::shared_ptr<SessionImpl>& session, uint16_t channel)
{
Mutex::ScopedLock l(lock);
- boost::weak_ptr<SessionImpl>& s = sessions[session->getChannel()];
- if (s.lock()) throw SessionBusyException();
- s = session;
+ for (uint16_t i = 0; i < NEXT_CHANNEL; i++) { //will at most search through channels once
+ uint16_t c = channel == NEXT_CHANNEL ? nextChannel++ : channel;
+ boost::weak_ptr<SessionImpl>& s = sessions[c];
+ boost::shared_ptr<SessionImpl> ss = s.lock();
+ if (!ss) {
+ //channel is free, we can assign it to this session
+ session->setChannel(c);
+ s = session;
+ return;
+ } else if (channel != NEXT_CHANNEL) {
+ //channel is taken and was requested explicitly so don't look for another
+ throw SessionBusyException(QPID_MSG("Channel " << ss->getChannel() << " attached to " << ss->getId()));
+ } //else channel is busy, but we can keep looking for a free one
+ }
+
}
void ConnectionImpl::handle(framing::AMQFrame& frame)
@@ -81,9 +123,11 @@ void ConnectionImpl::incoming(framing::AMQFrame& frame)
Mutex::ScopedLock l(lock);
s = sessions[frame.getChannel()].lock();
}
- if (!s)
- throw NotAttachedException(QPID_MSG("Invalid channel: " << frame.getChannel()));
- s->in(frame);
+ if (!s) {
+ QPID_LOG(info, "Dropping frame received on invalid channel: " << frame);
+ } else {
+ s->in(frame);
+ }
}
bool ConnectionImpl::isOpen() const
@@ -92,57 +136,121 @@ bool ConnectionImpl::isOpen() const
}
-void ConnectionImpl::open(const std::string& host, int port)
+void ConnectionImpl::open()
{
- QPID_LOG(info, "Connecting to " << host << ":" << port);
+ const std::string& protocol = handler.protocol;
+ const std::string& host = handler.host;
+ int port = handler.port;
+ QPID_LOG(info, "Connecting to " << protocol << ":" << host << ":" << port);
+
+ connector.reset(Connector::create(protocol, version, handler, this));
+ connector->setInputHandler(&handler);
+ connector->setShutdownHandler(this);
connector->connect(host, port);
connector->init();
- handler.waitForOpen();
+
+ // Enable heartbeat if requested
+ uint16_t heartbeat = static_cast<ConnectionSettings&>(handler).heartbeat;
+ if (heartbeat) {
+ // Set connection timeout to be 2x heart beat interval and setup timer
+ heartbeatTask = new HeartbeatTask(heartbeat * 2 * TIME_SEC, *this);
+ handler.setRcvTimeoutTask(heartbeatTask);
+ theTimer().add(heartbeatTask);
+ }
+
+ try {
+ handler.waitForOpen();
+ } catch (...) {
+ // Make sure the connector thread is joined.
+ connector->close();
+ throw;
+ }
+
+ // If the SASL layer has provided an "operational" userId for the connection,
+ // put it in the negotiated settings.
+ const std::string& userId(handler.getUserId());
+ if (!userId.empty())
+ handler.username = userId;
+
+ //enable security layer if one has been negotiated:
+ std::auto_ptr<SecurityLayer> securityLayer = handler.getSecurityLayer();
+ if (securityLayer.get()) {
+ QPID_LOG(debug, "Activating security layer");
+ connector->activateSecurityLayer(securityLayer);
+ } else {
+ QPID_LOG(debug, "No security layer in place");
+ }
}
void ConnectionImpl::idleIn()
{
- close();
+ connector->abort();
}
void ConnectionImpl::idleOut()
{
- AMQFrame frame(in_place<AMQHeartbeatBody>());
+ AMQFrame frame((AMQHeartbeatBody()));
connector->send(frame);
}
void ConnectionImpl::close()
{
- if (!handler.isOpen()) return;
- handler.close();
- closed(NORMAL, "Closed by client");
+ if (heartbeatTask)
+ heartbeatTask->cancel();
+ // close() must be idempotent and no-throw as it will often be called in destructors.
+ if (handler.isOpen()) {
+ try {
+ handler.close();
+ closed(CLOSE_CODE_NORMAL, "Closed by client");
+ } catch (...) {}
+ }
+ assert(!handler.isOpen());
}
template <class F> void ConnectionImpl::closeInternal(const F& f) {
- connector->close();
- for (SessionMap::iterator i = sessions.begin(); i != sessions.end(); ++i) {
+ if (heartbeatTask) {
+ heartbeatTask->cancel();
+ }
+ {
+ Mutex::ScopedUnlock u(lock);
+ connector->close();
+ }
+ //notifying sessions of failure can result in those session being
+ //deleted which in turn results in a call to erase(); this can
+ //even happen on this thread, when 's' goes out of scope
+ //below. Using a copy prevents the map being modified as we
+ //iterate through.
+ SessionMap copy;
+ sessions.swap(copy);
+ for (SessionMap::iterator i = copy.begin(); i != copy.end(); ++i) {
boost::shared_ptr<SessionImpl> s = i->second.lock();
if (s) f(s);
}
- sessions.clear();
}
void ConnectionImpl::closed(uint16_t code, const std::string& text) {
Mutex::ScopedLock l(lock);
- setException(new ConnectionException(code, text));
+ setException(new ConnectionException(ConnectionHandler::convert(code), text));
closeInternal(boost::bind(&SessionImpl::connectionClosed, _1, code, text));
}
-static const std::string CONN_CLOSED("Connection closed by broker");
+static const std::string CONN_CLOSED("Connection closed");
void ConnectionImpl::shutdown() {
- Mutex::ScopedLock l(lock);
- // FIXME aconway 2008-06-06: exception use, connection-forced is incorrect here.
- setException(new ConnectionException(CONNECTION_FORCED, CONN_CLOSED));
+ if ( failureCallback )
+ failureCallback();
+
if (handler.isClosed()) return;
- handler.fail(CONN_CLOSED);
- closeInternal(boost::bind(&SessionImpl::connectionBroke, _1, CONNECTION_FORCED, CONN_CLOSED));
+
+ // FIXME aconway 2008-06-06: exception use, amqp0-10 does not seem to have
+ // an appropriate close-code. connection-forced is not right.
+ bool isClosing = handler.isClosing();
+ handler.fail(CONN_CLOSED);//ensure connection is marked as failed before notifying sessions
+ Mutex::ScopedLock l(lock);
+ if (!isClosing)
+ closeInternal(boost::bind(&SessionImpl::connectionBroke, _1, CONN_CLOSED));
+ setException(new TransportFailure(CONN_CLOSED));
}
void ConnectionImpl::erase(uint16_t ch) {
@@ -154,4 +262,16 @@ const ConnectionSettings& ConnectionImpl::getNegotiatedSettings()
{
return handler;
}
-
+
+std::vector<qpid::Url> ConnectionImpl::getInitialBrokers() {
+ return handler.knownBrokersUrls;
+}
+
+boost::shared_ptr<SessionImpl> ConnectionImpl::newSession(const std::string& name, uint32_t timeout, uint16_t channel) {
+ boost::shared_ptr<SessionImpl> simpl(new SessionImpl(name, shared_from_this()));
+ addSession(simpl, channel);
+ simpl->open(timeout);
+ return simpl;
+}
+
+}} // namespace qpid::client
diff --git a/cpp/src/qpid/client/ConnectionImpl.h b/cpp/src/qpid/client/ConnectionImpl.h
index cd0788d68b..2b32e1ccf0 100644
--- a/cpp/src/qpid/client/ConnectionImpl.h
+++ b/cpp/src/qpid/client/ConnectionImpl.h
@@ -22,8 +22,9 @@
#ifndef _ConnectionImpl_
#define _ConnectionImpl_
-#include "Bounds.h"
-#include "ConnectionHandler.h"
+#include "qpid/client/Bounds.h"
+#include "qpid/client/ConnectionHandler.h"
+
#include "qpid/framing/FrameHandler.h"
#include "qpid/sys/Mutex.h"
#include "qpid/sys/ShutdownHandler.h"
@@ -39,7 +40,7 @@ namespace qpid {
namespace client {
class Connector;
-class ConnectionSettings;
+struct ConnectionSettings;
class SessionImpl;
class ConnectionImpl : public Bounds,
@@ -51,12 +52,17 @@ class ConnectionImpl : public Bounds,
{
typedef std::map<uint16_t, boost::weak_ptr<SessionImpl> > SessionMap;
+ static const uint16_t NEXT_CHANNEL;
+
SessionMap sessions;
ConnectionHandler handler;
boost::scoped_ptr<Connector> connector;
framing::ProtocolVersion version;
+ uint16_t nextChannel;
sys::Mutex lock;
+ boost::intrusive_ptr<qpid::sys::TimerTask> heartbeatTask;
+
template <class F> void closeInternal(const F&);
void incoming(framing::AMQFrame& frame);
@@ -65,20 +71,27 @@ class ConnectionImpl : public Bounds,
void idleIn();
void shutdown();
+ boost::function<void ()> failureCallback;
+
public:
ConnectionImpl(framing::ProtocolVersion version, const ConnectionSettings& settings);
~ConnectionImpl();
- void open(const std::string& host, int port);
+ void open();
bool isOpen() const;
- void addSession(const boost::shared_ptr<SessionImpl>&);
+ boost::shared_ptr<SessionImpl> newSession(const std::string& name, uint32_t timeout, uint16_t channel=NEXT_CHANNEL);
+ void addSession(const boost::shared_ptr<SessionImpl>&, uint16_t channel=NEXT_CHANNEL);
void close();
void handle(framing::AMQFrame& frame);
void erase(uint16_t channel);
-
const ConnectionSettings& getNegotiatedSettings();
+
+ std::vector<Url> getInitialBrokers();
+ void registerFailureCallback ( boost::function<void ()> fn ) { failureCallback = fn; }
+
+ framing::ProtocolVersion getVersion() { return version; }
};
}}
diff --git a/cpp/src/qpid/client/ConnectionSettings.cpp b/cpp/src/qpid/client/ConnectionSettings.cpp
index 6bc220cd41..3ae4ee010a 100644
--- a/cpp/src/qpid/client/ConnectionSettings.cpp
+++ b/cpp/src/qpid/client/ConnectionSettings.cpp
@@ -18,27 +18,28 @@
* under the License.
*
*/
-#include "ConnectionSettings.h"
+#include "qpid/client/ConnectionSettings.h"
#include "qpid/log/Logger.h"
#include "qpid/sys/Socket.h"
-#include <sys/socket.h>
+#include "qpid/Version.h"
namespace qpid {
namespace client {
ConnectionSettings::ConnectionSettings() :
+ protocol("tcp"),
host("localhost"),
port(TcpAddress::DEFAULT_PORT),
- username("guest"),
- password("guest"),
- mechanism("PLAIN"),
locale("en_US"),
heartbeat(0),
maxChannels(32767),
maxFrameSize(65535),
bounds(2),
- tcpNoDelay(false)
+ tcpNoDelay(false),
+ service(qpid::saslName),
+ minSsf(0),
+ maxSsf(256)
{}
ConnectionSettings::~ConnectionSettings() {}
@@ -46,7 +47,7 @@ ConnectionSettings::~ConnectionSettings() {}
void ConnectionSettings::configureSocket(qpid::sys::Socket& socket) const
{
if (tcpNoDelay) {
- socket.setTcpNoDelay(tcpNoDelay);
+ socket.setTcpNoDelay();
QPID_LOG(info, "Set TCP_NODELAY");
}
}
diff --git a/cpp/src/qpid/client/ConnectionSettings.h b/cpp/src/qpid/client/ConnectionSettings.h
deleted file mode 100644
index 5e93b3103e..0000000000
--- a/cpp/src/qpid/client/ConnectionSettings.h
+++ /dev/null
@@ -1,114 +0,0 @@
-#ifndef QPID_CLIENT_CONNECTIONSETTINGS_H
-#define QPID_CLIENT_CONNECTIONSETTINGS_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/Options.h"
-#include "qpid/log/Options.h"
-#include "qpid/Url.h"
-
-#include <iostream>
-#include <exception>
-
-namespace qpid {
-
-namespace sys {
-class Socket;
-}
-
-namespace client {
-
-/**
- * Settings for a Connection.
- */
-struct ConnectionSettings {
-
- ConnectionSettings();
- virtual ~ConnectionSettings();
-
- /**
- * Allows socket to be configured; default only sets tcp-nodelay
- * based on the flag set. Can be overridden.
- */
- virtual void configureSocket(qpid::sys::Socket&) const;
-
- /**
- * The host (or ip address) to connect to (defaults to 'localhost').
- */
- std::string host;
- /**
- * The port to connect to (defaults to 5672).
- */
- uint16_t port;
- /**
- * Allows an AMQP 'virtual host' to be specified for the
- * connection.
- */
- std::string virtualhost;
-
- /**
- * The username to use when authenticating the connection.
- */
- std::string username;
- /**
- * The password to use when authenticating the connection.
- */
- std::string password;
- /**
- * The SASL mechanism to use when authenticating the connection;
- * the options are currently PLAIN or ANONYMOUS.
- */
- std::string mechanism;
- /**
- * Allows a locale to be specified for the connection.
- */
- std::string locale;
- /**
- * Allows a heartbeat frequency to be specified (this feature is
- * not yet implemented).
- */
- uint16_t heartbeat;
- /**
- * The maximum number of channels that the client will request for
- * use on this connection.
- */
- uint16_t maxChannels;
- /**
- * The maximum frame size that the client will request for this
- * connection.
- */
- uint16_t maxFrameSize;
- /**
- * Allows the size of outgoing frames to be limited. The value
- * should be a mutliple of the maximum buffer size in use (which
- * is in turn set through the maxFrameSize setting above).
- */
- uint bounds;
- /**
- * If true, TCP_NODELAY will be set for the connection.
- */
- bool tcpNoDelay;
-};
-
-}} // namespace qpid::client
-
-#endif /*!QPID_CLIENT_CONNECTIONSETTINGS_H*/
diff --git a/cpp/src/qpid/client/Connector.cpp b/cpp/src/qpid/client/Connector.cpp
index f4f414bc63..2c4feffdcf 100644
--- a/cpp/src/qpid/client/Connector.cpp
+++ b/cpp/src/qpid/client/Connector.cpp
@@ -18,20 +18,23 @@
* under the License.
*
*/
-#include "Connector.h"
-#include "Bounds.h"
-#include "ConnectionImpl.h"
-#include "ConnectionSettings.h"
+#include "qpid/client/Connector.h"
+
+#include "qpid/client/ConnectionImpl.h"
+#include "qpid/client/ConnectionSettings.h"
#include "qpid/log/Statement.h"
+#include "qpid/sys/Codec.h"
#include "qpid/sys/Time.h"
#include "qpid/framing/AMQFrame.h"
#include "qpid/sys/AsynchIO.h"
#include "qpid/sys/Dispatcher.h"
#include "qpid/sys/Poller.h"
+#include "qpid/sys/SecurityLayer.h"
#include "qpid/Msg.h"
#include <iostream>
+#include <map>
#include <boost/bind.hpp>
#include <boost/format.hpp>
@@ -43,227 +46,37 @@ using namespace qpid::framing;
using boost::format;
using boost::str;
-Connector::Connector(ProtocolVersion ver,
- const ConnectionSettings& settings,
- ConnectionImpl* cimpl)
- : maxFrameSize(settings.maxFrameSize),
- version(ver),
- initiated(false),
- closed(true),
- joined(true),
- timeout(0),
- idleIn(0), idleOut(0),
- timeoutHandler(0),
- shutdownHandler(0),
- writer(maxFrameSize, cimpl),
- aio(0),
- impl(cimpl)
-{
- QPID_LOG(debug, "Connector created for " << version);
- settings.configureSocket(socket);
-}
-
-Connector::~Connector() {
- close();
-}
-
-void Connector::connect(const std::string& host, int port){
- Mutex::ScopedLock l(closedLock);
- assert(closed);
- socket.connect(host, port);
- identifier = str(format("[%1% %2%]") % socket.getLocalPort() % socket.getPeerAddress());
- closed = false;
- poller = Poller::shared_ptr(new Poller);
- aio = new AsynchIO(socket,
- boost::bind(&Connector::readbuff, this, _1, _2),
- boost::bind(&Connector::eof, this, _1),
- boost::bind(&Connector::eof, this, _1),
- 0, // closed
- 0, // nobuffs
- boost::bind(&Connector::writebuff, this, _1));
- writer.init(identifier, aio);
-}
-
-void Connector::init(){
- Mutex::ScopedLock l(closedLock);
- assert(joined);
- ProtocolInitiation init(version);
- writeDataBlock(init);
- joined = false;
- receiver = Thread(this);
-}
-
-bool Connector::closeInternal() {
- Mutex::ScopedLock l(closedLock);
- bool ret = !closed;
- if (!closed) {
- closed = true;
- poller->shutdown();
- }
- if (!joined && receiver.id() != Thread::current().id()) {
- joined = true;
- Mutex::ScopedUnlock u(closedLock);
- receiver.join();
- }
- return ret;
-}
-
-void Connector::close() {
- closeInternal();
-}
-
-void Connector::setInputHandler(InputHandler* handler){
- input = handler;
-}
-
-void Connector::setShutdownHandler(ShutdownHandler* handler){
- shutdownHandler = handler;
-}
-
-OutputHandler* Connector::getOutputHandler(){
- return this;
-}
+// Stuff for the registry of protocol connectors (maybe should be moved to its own file)
+namespace {
+ typedef std::map<std::string, Connector::Factory*> ProtocolRegistry;
-void Connector::send(AMQFrame& frame) {
- writer.handle(frame);
-}
+ ProtocolRegistry& theProtocolRegistry() {
+ static ProtocolRegistry protocolRegistry;
-void Connector::handleClosed() {
- if (closeInternal() && shutdownHandler)
- shutdownHandler->shutdown();
+ return protocolRegistry;
+ }
}
-struct Connector::Buff : public AsynchIO::BufferBase {
- Buff(size_t size) : AsynchIO::BufferBase(new char[size], size) {}
- ~Buff() { delete [] bytes;}
-};
-
-Connector::Writer::Writer(uint16_t s, Bounds* b) : maxFrameSize(s), aio(0), buffer(0), lastEof(0), bounds(b)
+Connector* Connector::create(const std::string& proto, framing::ProtocolVersion v, const ConnectionSettings& s, ConnectionImpl* c)
{
-}
-
-Connector::Writer::~Writer() { delete buffer; }
-
-void Connector::Writer::init(std::string id, sys::AsynchIO* a) {
- Mutex::ScopedLock l(lock);
- identifier = id;
- aio = a;
- newBuffer(l);
-}
-void Connector::Writer::handle(framing::AMQFrame& frame) {
- Mutex::ScopedLock l(lock);
- frames.push_back(frame);
- if (frame.getEof()) {//or if we already have a buffers worth
- lastEof = frames.size();
- aio->notifyPendingWrite();
- }
- QPID_LOG(trace, "SENT " << identifier << ": " << frame);
-}
-
-void Connector::Writer::writeOne(const Mutex::ScopedLock& l) {
- assert(buffer);
- framesEncoded = 0;
-
- buffer->dataStart = 0;
- buffer->dataCount = encode.getPosition();
- aio->queueWrite(buffer);
- newBuffer(l);
-}
-
-void Connector::Writer::newBuffer(const Mutex::ScopedLock&) {
- buffer = aio->getQueuedBuffer();
- if (!buffer) buffer = new Buff(maxFrameSize);
- encode = framing::Buffer(buffer->bytes, buffer->byteCount);
- framesEncoded = 0;
-}
-
-// Called in IO thread.
-void Connector::Writer::write(sys::AsynchIO&) {
- Mutex::ScopedLock l(lock);
- assert(buffer);
- size_t bytesWritten(0);
- for (size_t i = 0; i < lastEof; ++i) {
- AMQFrame& frame = frames[i];
- uint32_t size = frame.size();
- if (size > encode.available()) writeOne(l);
- assert(size <= encode.available());
- frame.encode(encode);
- ++framesEncoded;
- bytesWritten += size;
+ ProtocolRegistry::const_iterator i = theProtocolRegistry().find(proto);
+ if (i==theProtocolRegistry().end()) {
+ throw Exception(QPID_MSG("Unknown protocol: " << proto));
}
- frames.erase(frames.begin(), frames.begin()+lastEof);
- lastEof = 0;
- if (bounds) bounds->reduce(bytesWritten);
- if (encode.getPosition() > 0) writeOne(l);
+ return (i->second)(v, s, c);
}
-void Connector::readbuff(AsynchIO& aio, AsynchIO::BufferBase* buff) {
- framing::Buffer in(buff->bytes+buff->dataStart, buff->dataCount);
-
- if (!initiated) {
- framing::ProtocolInitiation protocolInit;
- if (protocolInit.decode(in)) {
- //TODO: check the version is correct
- QPID_LOG(debug, "RECV " << identifier << " INIT(" << protocolInit << ")");
- }
- initiated = true;
- }
- AMQFrame frame;
- while(frame.decode(in)){
- QPID_LOG(trace, "RECV " << identifier << ": " << frame);
- input->received(frame);
- }
- // TODO: unreading needs to go away, and when we can cope
- // with multiple sub-buffers in the general buffer scheme, it will
- if (in.available() != 0) {
- // Adjust buffer for used bytes and then "unread them"
- buff->dataStart += buff->dataCount-in.available();
- buff->dataCount = in.available();
- aio.unread(buff);
- } else {
- // Give whole buffer back to aio subsystem
- aio.queueReadBuffer(buff);
+void Connector::registerFactory(const std::string& proto, Factory* connectorFactory)
+{
+ ProtocolRegistry::const_iterator i = theProtocolRegistry().find(proto);
+ if (i!=theProtocolRegistry().end()) {
+ QPID_LOG(error, "Tried to register protocol: " << proto << " more than once");
}
+ theProtocolRegistry()[proto] = connectorFactory;
}
-void Connector::writebuff(AsynchIO& aio_) {
- writer.write(aio_);
-}
-
-void Connector::writeDataBlock(const AMQDataBlock& data) {
- AsynchIO::BufferBase* buff = new Buff(maxFrameSize);
- framing::Buffer out(buff->bytes, buff->byteCount);
- data.encode(out);
- buff->dataCount = data.size();
- aio->queueWrite(buff);
-}
-
-void Connector::eof(AsynchIO&) {
- handleClosed();
-}
-
-// TODO: astitcher 20070908 This version of the code can never time out, so the idle processing
-// will never be called
-void Connector::run(){
- // Keep the connection impl in memory until run() completes.
- boost::shared_ptr<ConnectionImpl> protect = impl->shared_from_this();
- assert(protect);
- try {
- Dispatcher d(poller);
-
- for (int i = 0; i < 32; i++) {
- aio->queueReadBuffer(new Buff(maxFrameSize));
- }
-
- aio->start(poller);
- d.run();
- aio->queueForDeletion();
- socket.close();
- } catch (const std::exception& e) {
- QPID_LOG(error, e.what());
- handleClosed();
- }
+void Connector::activateSecurityLayer(std::auto_ptr<qpid::sys::SecurityLayer>)
+{
}
-
}} // namespace qpid::client
diff --git a/cpp/src/qpid/client/Connector.h b/cpp/src/qpid/client/Connector.h
index cde12f7b5b..3a49ae9012 100644
--- a/cpp/src/qpid/client/Connector.h
+++ b/cpp/src/qpid/client/Connector.h
@@ -42,107 +42,40 @@
namespace qpid {
namespace sys {
-class Poller;
-class AsynchIO;
-class AsynchIOBufferBase;
+class SecurityLayer;
}
-
+
namespace client {
-class Bounds;
-class ConnectionSettings;
+struct ConnectionSettings;
class ConnectionImpl;
///@internal
-class Connector : public framing::OutputHandler,
- private sys::Runnable
-{
- struct Buff;
-
- /** Batch up frames for writing to aio. */
- class Writer : public framing::FrameHandler {
- typedef sys::AsynchIOBufferBase BufferBase;
- typedef std::vector<framing::AMQFrame> Frames;
-
- const uint16_t maxFrameSize;
- sys::Mutex lock;
- sys::AsynchIO* aio;
- BufferBase* buffer;
- Frames frames;
- size_t lastEof; // Position after last EOF in frames
- framing::Buffer encode;
- size_t framesEncoded;
- std::string identifier;
- Bounds* bounds;
-
- void writeOne(const sys::Mutex::ScopedLock&);
- void newBuffer(const sys::Mutex::ScopedLock&);
-
- public:
-
- Writer(uint16_t maxFrameSize, Bounds*);
- ~Writer();
- void init(std::string id, sys::AsynchIO*);
- void handle(framing::AMQFrame&);
- void write(sys::AsynchIO&);
- };
-
- const uint16_t maxFrameSize;
- framing::ProtocolVersion version;
- bool initiated;
-
- sys::Mutex closedLock;
- bool closed;
- bool joined;
-
- sys::AbsTime lastIn;
- sys::AbsTime lastOut;
- sys::Duration timeout;
- sys::Duration idleIn;
- sys::Duration idleOut;
-
- sys::TimeoutHandler* timeoutHandler;
- sys::ShutdownHandler* shutdownHandler;
- framing::InputHandler* input;
- framing::InitiationHandler* initialiser;
- framing::OutputHandler* output;
-
- Writer writer;
-
- sys::Thread receiver;
-
- sys::Socket socket;
-
- sys::AsynchIO* aio;
- boost::shared_ptr<sys::Poller> poller;
-
- void run();
- void handleClosed();
- bool closeInternal();
-
- void readbuff(qpid::sys::AsynchIO&, qpid::sys::AsynchIOBufferBase*);
- void writebuff(qpid::sys::AsynchIO&);
- void writeDataBlock(const framing::AMQDataBlock& data);
- void eof(qpid::sys::AsynchIO&);
-
- std::string identifier;
-
- ConnectionImpl* impl;
-
+class Connector : public framing::OutputHandler
+{
public:
- Connector(framing::ProtocolVersion pVersion,
- const ConnectionSettings&,
- ConnectionImpl*);
- virtual ~Connector();
- virtual void connect(const std::string& host, int port);
- virtual void init();
- virtual void close();
- virtual void setInputHandler(framing::InputHandler* handler);
- virtual void setShutdownHandler(sys::ShutdownHandler* handler);
- virtual sys::ShutdownHandler* getShutdownHandler() { return shutdownHandler; }
- virtual framing::OutputHandler* getOutputHandler();
- virtual void send(framing::AMQFrame& frame);
- const std::string& getIdentifier() const { return identifier; }
+ // Protocol connector factory related stuff (it might be better to separate this code from the TCP Connector in the future)
+ typedef Connector* Factory(framing::ProtocolVersion, const ConnectionSettings&, ConnectionImpl*);
+ static Connector* create(const std::string& proto, framing::ProtocolVersion, const ConnectionSettings&, ConnectionImpl*);
+ static void registerFactory(const std::string& proto, Factory* connectorFactory);
+
+ virtual ~Connector() {};
+ virtual void connect(const std::string& host, int port) = 0;
+ virtual void init() {};
+ virtual void close() = 0;
+ virtual void send(framing::AMQFrame& frame) = 0;
+ virtual void abort() = 0;
+
+ virtual void setInputHandler(framing::InputHandler* handler) = 0;
+ virtual void setShutdownHandler(sys::ShutdownHandler* handler) = 0;
+ virtual sys::ShutdownHandler* getShutdownHandler() const = 0;
+ virtual framing::OutputHandler* getOutputHandler() = 0;
+ virtual const std::string& getIdentifier() const = 0;
+
+ virtual void activateSecurityLayer(std::auto_ptr<qpid::sys::SecurityLayer>);
+
+ virtual unsigned int getSSF() = 0;
+
};
}}
diff --git a/cpp/src/qpid/client/Demux.cpp b/cpp/src/qpid/client/Demux.cpp
index b774214ae4..abc23c75df 100644
--- a/cpp/src/qpid/client/Demux.cpp
+++ b/cpp/src/qpid/client/Demux.cpp
@@ -19,7 +19,7 @@
*
*/
-#include "Demux.h"
+#include "qpid/client/Demux.h"
#include "qpid/Exception.h"
#include "qpid/framing/MessageTransferBody.h"
diff --git a/cpp/src/qpid/client/Demux.h b/cpp/src/qpid/client/Demux.h
index 7304e799bb..31dc3f9c06 100644
--- a/cpp/src/qpid/client/Demux.h
+++ b/cpp/src/qpid/client/Demux.h
@@ -25,6 +25,7 @@
#include "qpid/framing/FrameSet.h"
#include "qpid/sys/Mutex.h"
#include "qpid/sys/BlockingQueue.h"
+#include "qpid/client/ClientImportExport.h"
#ifndef _Demux_
#define _Demux_
@@ -49,17 +50,17 @@ public:
typedef sys::BlockingQueue<framing::FrameSet::shared_ptr> Queue;
typedef boost::shared_ptr<Queue> QueuePtr;
- Demux();
- ~Demux();
+ QPID_CLIENT_EXTERN Demux();
+ QPID_CLIENT_EXTERN ~Demux();
- void handle(framing::FrameSet::shared_ptr);
- void close(const sys::ExceptionHolder& ex);
- void open();
-
- QueuePtr add(const std::string& name, Condition);
- void remove(const std::string& name);
- QueuePtr get(const std::string& name);
- QueuePtr getDefault();
+ QPID_CLIENT_EXTERN void handle(framing::FrameSet::shared_ptr);
+ QPID_CLIENT_EXTERN void close(const sys::ExceptionHolder& ex);
+ QPID_CLIENT_EXTERN void open();
+
+ QPID_CLIENT_EXTERN QueuePtr add(const std::string& name, Condition);
+ QPID_CLIENT_EXTERN void remove(const std::string& name);
+ QPID_CLIENT_EXTERN QueuePtr get(const std::string& name);
+ QPID_CLIENT_EXTERN QueuePtr getDefault();
private:
struct Record
diff --git a/cpp/src/qpid/client/Dispatcher.cpp b/cpp/src/qpid/client/Dispatcher.cpp
index 5028d68405..a715c623bf 100644
--- a/cpp/src/qpid/client/Dispatcher.cpp
+++ b/cpp/src/qpid/client/Dispatcher.cpp
@@ -18,15 +18,25 @@
* under the License.
*
*/
-#include "Dispatcher.h"
+#include "qpid/client/Dispatcher.h"
+#include "qpid/client/SubscriptionImpl.h"
+#include "qpid/client/SessionImpl.h"
#include "qpid/framing/FrameSet.h"
#include "qpid/framing/MessageTransferBody.h"
#include "qpid/log/Statement.h"
#include "qpid/sys/BlockingQueue.h"
-#include "Message.h"
-
-#include <boost/state_saver.hpp>
+#include "qpid/client/Message.h"
+#include "qpid/client/MessageImpl.h"
+
+#include <boost/version.hpp>
+#if (BOOST_VERSION >= 104000)
+# include <boost/serialization/state_saver.hpp>
+ using boost::serialization::state_saver;
+#else
+# include <boost/state_saver.hpp>
+ using boost::state_saver;
+#endif /* BOOST_VERSION */
using qpid::framing::FrameSet;
using qpid::framing::MessageTransferBody;
@@ -37,44 +47,40 @@ using qpid::sys::Thread;
namespace qpid {
namespace client {
-Subscriber::Subscriber(const Session& s, MessageListener* l, AckPolicy a)
- : session(s), listener(l), autoAck(a) {}
-
-void Subscriber::received(Message& msg)
-{
- if (listener) {
- listener->received(msg);
- autoAck.ack(msg, session);
- }
-}
-
Dispatcher::Dispatcher(const Session& s, const std::string& q)
- : session(s), running(false), autoStop(true)
+ : session(s),
+ running(false),
+ autoStop(true),
+ failoverHandler(0)
{
- queue = q.empty() ?
- session.getExecution().getDemux().getDefault() :
- session.getExecution().getDemux().get(q);
-}
+ Demux& demux = SessionBase_0_10Access(session).get()->getDemux();
+ queue = q.empty() ? demux.getDefault() : demux.get(q);
+}
void Dispatcher::start()
{
worker = Thread(this);
}
+void Dispatcher::wait()
+{
+ worker.join();
+}
+
void Dispatcher::run()
{
Mutex::ScopedLock l(lock);
if (running)
throw Exception("Dispatcher is already running.");
- boost::state_saver<bool> reset(running); // Reset to false on exit.
+ state_saver<bool> reset(running); // Reset to false on exit.
running = true;
try {
while (!queue->isClosed()) {
Mutex::ScopedUnlock u(lock);
FrameSet::shared_ptr content = queue->pop();
if (content->isA<MessageTransferBody>()) {
- Message msg(*content);
- Subscriber::shared_ptr listener = find(msg.getDestination());
+ Message msg(new MessageImpl(*content));
+ boost::intrusive_ptr<SubscriptionImpl> listener = find(msg.getDestination());
if (!listener) {
QPID_LOG(error, "No listener found for destination " << msg.getDestination());
} else {
@@ -91,9 +97,21 @@ void Dispatcher::run()
}
session.sync(); // Make sure all our acks are received before returning.
}
- catch (const ClosedException&) {} //ignore it and return
+ catch (const ClosedException&) {
+ QPID_LOG(debug, QPID_MSG(session.getId() << ": closed by peer"));
+ }
+ catch (const TransportFailure&) {
+ QPID_LOG(info, QPID_MSG(session.getId() << ": transport failure"));
+ throw;
+ }
catch (const std::exception& e) {
- QPID_LOG(error, "Exception in client dispatch thread: " << e.what());
+ if ( failoverHandler ) {
+ QPID_LOG(debug, QPID_MSG(session.getId() << " failover: " << e.what()));
+ failoverHandler();
+ } else {
+ QPID_LOG(error, session.getId() << " error: " << e.what());
+ throw;
+ }
}
}
@@ -109,7 +127,7 @@ void Dispatcher::setAutoStop(bool b)
autoStop = b;
}
-Subscriber::shared_ptr Dispatcher::find(const std::string& name)
+boost::intrusive_ptr<SubscriptionImpl> Dispatcher::find(const std::string& name)
{
ScopedLock<Mutex> l(lock);
Listeners::iterator i = listeners.find(name);
@@ -119,27 +137,14 @@ Subscriber::shared_ptr Dispatcher::find(const std::string& name)
return i->second;
}
-void Dispatcher::listen(
- MessageListener* listener, AckPolicy autoAck
-)
-{
+void Dispatcher::listen(const boost::intrusive_ptr<SubscriptionImpl>& subscription) {
ScopedLock<Mutex> l(lock);
- defaultListener = Subscriber::shared_ptr(
- new Subscriber(session, listener, autoAck));
+ listeners[subscription->getName()] = subscription;
}
-void Dispatcher::listen(const std::string& destination, MessageListener* listener, AckPolicy autoAck)
-{
- ScopedLock<Mutex> l(lock);
- listeners[destination] = Subscriber::shared_ptr(
- new Subscriber(session, listener, autoAck));
-}
-
-void Dispatcher::cancel(const std::string& destination)
-{
+void Dispatcher::cancel(const std::string& destination) {
ScopedLock<Mutex> l(lock);
- listeners.erase(destination);
- if (autoStop && listeners.empty())
+ if (listeners.erase(destination) && running && autoStop && listeners.empty())
queue->close();
}
diff --git a/cpp/src/qpid/client/Dispatcher.h b/cpp/src/qpid/client/Dispatcher.h
index 7d42bf8793..74fdb90103 100644
--- a/cpp/src/qpid/client/Dispatcher.h
+++ b/cpp/src/qpid/client/Dispatcher.h
@@ -26,28 +26,18 @@
#include <string>
#include <boost/shared_ptr.hpp>
#include "qpid/client/Session.h"
+#include "qpid/client/SessionBase_0_10Access.h"
#include "qpid/sys/Mutex.h"
#include "qpid/sys/Runnable.h"
#include "qpid/sys/Thread.h"
-#include "MessageListener.h"
-#include "AckPolicy.h"
+#include "qpid/client/ClientImportExport.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/client/SubscriptionImpl.h"
namespace qpid {
namespace client {
-///@internal
-class Subscriber : public MessageListener
-{
- AsyncSession session;
- MessageListener* const listener;
- AckPolicy autoAck;
-
-public:
- typedef boost::shared_ptr<Subscriber> shared_ptr;
- Subscriber(const Session& session, MessageListener* listener, AckPolicy);
- void received(Message& msg);
-
-};
+class SubscriptionImpl;
///@internal
typedef framing::Handler<framing::FrameSet> FrameSetHandler;
@@ -55,7 +45,7 @@ typedef framing::Handler<framing::FrameSet> FrameSetHandler;
///@internal
class Dispatcher : public sys::Runnable
{
- typedef std::map<std::string, Subscriber::shared_ptr> Listeners;
+ typedef std::map<std::string, boost::intrusive_ptr<SubscriptionImpl> >Listeners;
sys::Mutex lock;
sys::Thread worker;
Session session;
@@ -63,22 +53,32 @@ class Dispatcher : public sys::Runnable
bool running;
bool autoStop;
Listeners listeners;
- Subscriber::shared_ptr defaultListener;
+ boost::intrusive_ptr<SubscriptionImpl> defaultListener;
std::auto_ptr<FrameSetHandler> handler;
- Subscriber::shared_ptr find(const std::string& name);
+ boost::intrusive_ptr<SubscriptionImpl> find(const std::string& name);
bool isStopped();
+ boost::function<void ()> failoverHandler;
+
public:
Dispatcher(const Session& session, const std::string& queue = "");
+ ~Dispatcher() {}
void start();
- void run();
+ void wait();
+ // As this class is marked 'internal', no extern should be made here;
+ // however, some test programs rely on it.
+ QPID_CLIENT_EXTERN void run();
void stop();
void setAutoStop(bool b);
- void listen(MessageListener* listener, AckPolicy autoAck=AckPolicy());
- void listen(const std::string& destination, MessageListener* listener, AckPolicy autoAck=AckPolicy());
+ void registerFailoverHandler ( boost::function<void ()> fh )
+ {
+ failoverHandler = fh;
+ }
+
+ void listen(const boost::intrusive_ptr<SubscriptionImpl>& subscription);
void cancel(const std::string& destination);
};
diff --git a/cpp/src/qpid/client/Execution.h b/cpp/src/qpid/client/Execution.h
index 10674afde0..ad622af9c1 100644
--- a/cpp/src/qpid/client/Execution.h
+++ b/cpp/src/qpid/client/Execution.h
@@ -22,7 +22,7 @@
#define _Execution_
#include "qpid/framing/SequenceNumber.h"
-#include "Demux.h"
+#include "qpid/client/Demux.h"
namespace qpid {
namespace client {
diff --git a/cpp/src/qpid/client/FailoverListener.cpp b/cpp/src/qpid/client/FailoverListener.cpp
new file mode 100644
index 0000000000..3396f5598c
--- /dev/null
+++ b/cpp/src/qpid/client/FailoverListener.cpp
@@ -0,0 +1,89 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/FailoverListener.h"
+#include "qpid/client/Session.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/log/Statement.h"
+#include "qpid/log/Helpers.h"
+
+namespace qpid {
+namespace client {
+
+const std::string FailoverListener::AMQ_FAILOVER("amq.failover");
+
+FailoverListener::FailoverListener(Connection c) :
+ connection(c),
+ session(c.newSession(AMQ_FAILOVER+"."+framing::Uuid(true).str())),
+ subscriptions(session)
+{
+ knownBrokers = c.getInitialBrokers();
+ if (session.exchangeQuery(arg::name=AMQ_FAILOVER).getNotFound()) {
+ session.close();
+ return;
+ }
+ std::string qname=session.getId().getName();
+ session.queueDeclare(arg::queue=qname, arg::exclusive=true, arg::autoDelete=true);
+ session.exchangeBind(arg::queue=qname, arg::exchange=AMQ_FAILOVER);
+ subscriptions.subscribe(*this, qname, SubscriptionSettings(FlowControl::unlimited(),
+ ACCEPT_MODE_NONE));
+ thread = sys::Thread(*this);
+}
+
+void FailoverListener::run() {
+ try {
+ subscriptions.run();
+ } catch(...) {}
+}
+
+FailoverListener::~FailoverListener() {
+ try {
+ subscriptions.stop();
+ thread.join();
+ if (connection.isOpen()) {
+ session.sync();
+ session.close();
+ }
+ } catch (...) {}
+}
+
+void FailoverListener::received(Message& msg) {
+ sys::Mutex::ScopedLock l(lock);
+ knownBrokers = getKnownBrokers(msg);
+}
+
+std::vector<Url> FailoverListener::getKnownBrokers() const {
+ sys::Mutex::ScopedLock l(lock);
+ return knownBrokers;
+}
+
+std::vector<Url> FailoverListener::getKnownBrokers(const Message& msg) {
+ std::vector<Url> knownBrokers;
+ framing::Array urlArray;
+ msg.getHeaders().getArray("amq.failover", urlArray);
+ for (framing::Array::ValueVector::const_iterator i = urlArray.begin();
+ i != urlArray.end();
+ ++i )
+ knownBrokers.push_back(Url((*i)->get<std::string>()));
+ return knownBrokers;
+}
+
+
+}} // namespace qpid::client
diff --git a/cpp/src/qpid/client/FailoverManager.cpp b/cpp/src/qpid/client/FailoverManager.cpp
new file mode 100644
index 0000000000..81f71eb7df
--- /dev/null
+++ b/cpp/src/qpid/client/FailoverManager.cpp
@@ -0,0 +1,131 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/client/FailoverManager.h"
+#include "qpid/Exception.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/Time.h"
+
+
+namespace qpid {
+namespace client {
+
+using qpid::sys::Monitor;
+using qpid::sys::AbsTime;
+using qpid::sys::Duration;
+
+FailoverManager::FailoverManager(const ConnectionSettings& s,
+ ReconnectionStrategy* rs) : settings(s), strategy(rs), state(IDLE) {}
+
+void FailoverManager::execute(Command& c)
+{
+ bool retry = false;
+ bool completed = false;
+ AbsTime failed;
+ while (!completed) {
+ try {
+ AsyncSession session = connect().newSession();
+ if (retry) {
+ Duration failoverTime(failed, AbsTime::now());
+ QPID_LOG(info, "Failed over for " << &c << " in " << (failoverTime/qpid::sys::TIME_MSEC) << " milliseconds");
+ }
+ c.execute(session, retry);
+ session.sync();//TODO: shouldn't be required
+ session.close();
+ completed = true;
+ } catch(const TransportFailure&) {
+ retry = true;
+ failed = AbsTime::now();
+ }
+ }
+}
+
+void FailoverManager::close()
+{
+ Monitor::ScopedLock l(lock);
+ connection.close();
+}
+
+Connection& FailoverManager::connect(std::vector<Url> brokers)
+{
+ Monitor::ScopedLock l(lock);
+ if (state == CANT_CONNECT) {
+ state = IDLE;//retry
+ }
+ while (!connection.isOpen()) {
+ if (state == CONNECTING) {
+ lock.wait();
+ } else if (state == CANT_CONNECT) {
+ throw CannotConnectException("Cannot establish a connection");
+ } else {
+ state = CONNECTING;
+ Connection c;
+ if (brokers.empty() && failoverListener.get())
+ brokers = failoverListener->getKnownBrokers();
+ attempt(c, settings, brokers);
+ if (c.isOpen()) state = IDLE;
+ else state = CANT_CONNECT;
+ connection = c;
+ lock.notifyAll();
+ }
+ }
+ return connection;
+}
+
+Connection& FailoverManager::getConnection()
+{
+ Monitor::ScopedLock l(lock);
+ return connection;
+}
+
+void FailoverManager::attempt(Connection& c, ConnectionSettings s, std::vector<Url> urls)
+{
+ Monitor::ScopedUnlock u(lock);
+ if (strategy) strategy->editUrlList(urls);
+ if (urls.empty()) {
+ attempt(c, s);
+ } else {
+ for (std::vector<Url>::const_iterator i = urls.begin(); i != urls.end() && !c.isOpen(); ++i) {
+ for (Url::const_iterator j = i->begin(); j != i->end() && !c.isOpen(); ++j) {
+ const TcpAddress* tcp = j->get<TcpAddress>();
+ if (tcp) {
+ s.host = tcp->host;
+ s.port = tcp->port;
+ attempt(c, s);
+ }
+ }
+ }
+ }
+}
+
+void FailoverManager::attempt(Connection& c, ConnectionSettings s)
+{
+ try {
+ QPID_LOG(info, "Attempting to connect to " << s.host << " on " << s.port << "...");
+ c.open(s);
+ failoverListener.reset(new FailoverListener(c));
+ QPID_LOG(info, "Connected to " << s.host << " on " << s.port);
+ } catch (const Exception& e) {
+ QPID_LOG(info, "Could not connect to " << s.host << " on " << s.port << ": " << e.what());
+ }
+}
+
+
+}} // namespace qpid::client
diff --git a/cpp/src/qpid/client/FlowControl.h b/cpp/src/qpid/client/FlowControl.h
deleted file mode 100644
index a4ed9879f4..0000000000
--- a/cpp/src/qpid/client/FlowControl.h
+++ /dev/null
@@ -1,73 +0,0 @@
-#ifndef QPID_CLIENT_FLOWCONTROL_H
-#define QPID_CLIENT_FLOWCONTROL_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-namespace qpid {
-namespace client {
-
-/**
- * Flow control works by associating a finite amount of "credit"
- * associated with a subscription.
- *
- * Credit includes a message count and a byte count. Each message
- * received decreases the message count by one, and the byte count by
- * the size of the message. Either count can have the special value
- * UNLIMITED which is never decreased.
- *
- * A subscription's credit is exhausted when the message count is 0 or
- * the byte count is too small for the next available message. The
- * subscription will not receive any further messages until is credit
- * is renewed.
- *
- * In "window mode" credit is automatically renewed when a message is
- * acknowledged (@see AckPolicy) In non-window mode credit is not
- * automatically renewed, it must be explicitly re-set (@see
- * SubscriptionManager)
- */
-struct FlowControl {
- static const uint32_t UNLIMITED=0xFFFFFFFF;
- FlowControl(uint32_t messages_=0, uint32_t bytes_=0, bool window_=false)
- : messages(messages_), bytes(bytes_), window(window_) {}
-
- static FlowControl messageCredit(uint32_t messages_) { return FlowControl(messages_,UNLIMITED,false); }
- static FlowControl messageWindow(uint32_t messages_) { return FlowControl(messages_,UNLIMITED,true); }
- static FlowControl byteCredit(uint32_t bytes_) { return FlowControl(UNLIMITED,bytes_,false); }
- static FlowControl byteWindow(uint32_t bytes_) { return FlowControl(UNLIMITED,bytes_,true); }
- static FlowControl unlimited() { return FlowControl(UNLIMITED, UNLIMITED, false); }
- static FlowControl zero() { return FlowControl(0, 0, false); }
-
- /** Message credit: subscription can accept up to this many messages. */
- uint32_t messages;
- /** Byte credit: subscription can accept up to this many bytes of message content. */
- uint32_t bytes;
- /** Window mode. If true credit is automatically renewed as messages are acknowledged. */
- bool window;
-
- bool operator==(const FlowControl& x) {
- return messages == x.messages && bytes == x.bytes && window == x.window;
- };
-};
-
-}} // namespace qpid::client
-
-#endif /*!QPID_CLIENT_FLOWCONTROL_H*/
diff --git a/cpp/src/qpid/client/Future.cpp b/cpp/src/qpid/client/Future.cpp
index 6a0c78ae4b..740cd3df59 100644
--- a/cpp/src/qpid/client/Future.cpp
+++ b/cpp/src/qpid/client/Future.cpp
@@ -19,7 +19,8 @@
*
*/
-#include "Future.h"
+#include "qpid/client/Future.h"
+#include "qpid/client/SessionImpl.h"
namespace qpid {
namespace client {
diff --git a/cpp/src/qpid/client/Future.h b/cpp/src/qpid/client/Future.h
deleted file mode 100644
index 67f39cdf3f..0000000000
--- a/cpp/src/qpid/client/Future.h
+++ /dev/null
@@ -1,64 +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.
- *
- */
-
-#ifndef _Future_
-#define _Future_
-
-#include <boost/bind.hpp>
-#include <boost/shared_ptr.hpp>
-#include "qpid/Exception.h"
-#include "qpid/framing/SequenceNumber.h"
-#include "qpid/framing/StructHelper.h"
-#include "FutureCompletion.h"
-#include "FutureResult.h"
-#include "SessionImpl.h"
-
-namespace qpid {
-namespace client {
-
-/**@internal */
-class Future : private framing::StructHelper
-{
- framing::SequenceNumber command;
- boost::shared_ptr<FutureResult> result;
- bool complete;
-
-public:
- Future() : complete(false) {}
- Future(const framing::SequenceNumber& id) : command(id), complete(false) {}
-
- template <class T> void decodeResult(T& value, SessionImpl& session)
- {
- if (result) {
- decode(value, result->getResult(session));
- } else {
- throw Exception("Result not expected");
- }
- }
-
- void wait(SessionImpl& session);
- bool isComplete(SessionImpl& session);
- void setFutureResult(boost::shared_ptr<FutureResult> r);
-};
-
-}}
-
-#endif
diff --git a/cpp/src/qpid/client/FutureCompletion.cpp b/cpp/src/qpid/client/FutureCompletion.cpp
index 130c65d6aa..ccfb073855 100644
--- a/cpp/src/qpid/client/FutureCompletion.cpp
+++ b/cpp/src/qpid/client/FutureCompletion.cpp
@@ -19,7 +19,7 @@
*
*/
-#include "FutureCompletion.h"
+#include "qpid/client/FutureCompletion.h"
using namespace qpid::client;
using namespace qpid::sys;
diff --git a/cpp/src/qpid/client/FutureCompletion.h b/cpp/src/qpid/client/FutureCompletion.h
deleted file mode 100644
index 4248ddeab8..0000000000
--- a/cpp/src/qpid/client/FutureCompletion.h
+++ /dev/null
@@ -1,49 +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.
- *
- */
-
-#ifndef _FutureCompletion_
-#define _FutureCompletion_
-
-#include "qpid/framing/amqp_framing.h"
-#include "qpid/sys/Monitor.h"
-
-namespace qpid {
-namespace client {
-
-///@internal
-class FutureCompletion
-{
-protected:
- mutable sys::Monitor lock;
- bool complete;
-
-public:
- FutureCompletion();
- virtual ~FutureCompletion(){}
- bool isComplete() const;
- void waitForCompletion() const;
- void completed();
-};
-
-}}
-
-
-#endif
diff --git a/cpp/src/qpid/client/FutureResult.cpp b/cpp/src/qpid/client/FutureResult.cpp
index 007f278051..0237eb1464 100644
--- a/cpp/src/qpid/client/FutureResult.cpp
+++ b/cpp/src/qpid/client/FutureResult.cpp
@@ -19,9 +19,9 @@
*
*/
-#include "FutureResult.h"
+#include "qpid/client/FutureResult.h"
-#include "SessionImpl.h"
+#include "qpid/client/SessionImpl.h"
using namespace qpid::client;
using namespace qpid::framing;
diff --git a/cpp/src/qpid/client/FutureResult.h b/cpp/src/qpid/client/FutureResult.h
deleted file mode 100644
index e97d80476d..0000000000
--- a/cpp/src/qpid/client/FutureResult.h
+++ /dev/null
@@ -1,47 +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.
- *
- */
-
-#ifndef _FutureResult_
-#define _FutureResult_
-
-#include <string>
-#include "qpid/framing/amqp_framing.h"
-#include "FutureCompletion.h"
-
-namespace qpid {
-namespace client {
-
-class SessionImpl;
-
-///@internal
-class FutureResult : public FutureCompletion
-{
- std::string result;
-public:
- const std::string& getResult(SessionImpl& session) const;
- void received(const std::string& result);
-};
-
-}}
-
-
-
-#endif
diff --git a/cpp/src/qpid/client/LoadPlugins.cpp b/cpp/src/qpid/client/LoadPlugins.cpp
new file mode 100644
index 0000000000..82cdedc7fe
--- /dev/null
+++ b/cpp/src/qpid/client/LoadPlugins.cpp
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include "qpid/Modules.h"
+#include "qpid/sys/Shlib.h"
+#include <string>
+#include <vector>
+using std::vector;
+using std::string;
+
+namespace {
+
+struct LoadtimeInitialise {
+ LoadtimeInitialise() {
+ qpid::ModuleOptions moduleOptions(QPIDC_MODULE_DIR);
+ string defaultPath (moduleOptions.loadDir);
+ moduleOptions.parse (0, 0, QPIDC_CONF_FILE, true);
+
+ for (vector<string>::iterator iter = moduleOptions.load.begin();
+ iter != moduleOptions.load.end();
+ iter++)
+ qpid::tryShlib (iter->data(), false);
+
+ if (!moduleOptions.noLoad) {
+ bool isDefault = defaultPath == moduleOptions.loadDir;
+ qpid::loadModuleDir (moduleOptions.loadDir, isDefault);
+ }
+ }
+} init;
+
+} // namespace
diff --git a/cpp/src/qpid/client/LocalQueue.cpp b/cpp/src/qpid/client/LocalQueue.cpp
index 99ab6f0133..0019adabaf 100644
--- a/cpp/src/qpid/client/LocalQueue.cpp
+++ b/cpp/src/qpid/client/LocalQueue.cpp
@@ -18,59 +18,35 @@
* under the License.
*
*/
-#include "LocalQueue.h"
+#include "qpid/client/LocalQueue.h"
+#include "qpid/client/LocalQueueImpl.h"
+#include "qpid/client/MessageImpl.h"
#include "qpid/Exception.h"
#include "qpid/framing/FrameSet.h"
+#include "qpid/framing/MessageTransferBody.h"
#include "qpid/framing/reply_exceptions.h"
+#include "qpid/client/PrivateImplRef.h"
+#include "qpid/client/SubscriptionImpl.h"
namespace qpid {
namespace client {
using namespace framing;
-LocalQueue::LocalQueue(AckPolicy a) : autoAck(a) {}
-LocalQueue::~LocalQueue() {}
+typedef PrivateImplRef<LocalQueue> PI;
-Message LocalQueue::pop() { return get(); }
+LocalQueue::LocalQueue() { PI::ctor(*this, new LocalQueueImpl()); }
+LocalQueue::LocalQueue(const LocalQueue& x) : Handle<LocalQueueImpl>() { PI::copy(*this, x); }
+LocalQueue::~LocalQueue() { PI::dtor(*this); }
+LocalQueue& LocalQueue::operator=(const LocalQueue& x) { return PI::assign(*this, x); }
-Message LocalQueue::get() {
- Message result;
- bool ok = get(result, sys::TIME_INFINITE);
- assert(ok); (void) ok;
- return result;
-}
+Message LocalQueue::pop(sys::Duration timeout) { return impl->pop(timeout); }
-bool LocalQueue::get(Message& result, sys::Duration timeout) {
- if (!queue)
- throw ClosedException();
- FrameSet::shared_ptr content;
- bool ok = queue->pop(content, timeout);
- if (!ok) return false;
- if (content->isA<MessageTransferBody>()) {
- result = Message(*content);
- autoAck.ack(result, session);
- return true;
- }
- else
- throw CommandInvalidException(
- QPID_MSG("Unexpected method: " << content->getMethod()));
-}
+Message LocalQueue::get(sys::Duration timeout) { return impl->get(timeout); }
-void LocalQueue::setAckPolicy(AckPolicy a) { autoAck=a; }
-AckPolicy& LocalQueue::getAckPolicy() { return autoAck; }
+bool LocalQueue::get(Message& result, sys::Duration timeout) { return impl->get(result, timeout); }
-bool LocalQueue::empty() const
-{
- if (!queue)
- throw ClosedException();
- return queue->empty();
-}
-
-size_t LocalQueue::size() const
-{
- if (!queue)
- throw ClosedException();
- return queue->size();
-}
+bool LocalQueue::empty() const { return impl->empty(); }
+size_t LocalQueue::size() const { return impl->size(); }
}} // namespace qpid::client
diff --git a/cpp/src/qpid/client/LocalQueue.h b/cpp/src/qpid/client/LocalQueue.h
deleted file mode 100644
index f81065ef3c..0000000000
--- a/cpp/src/qpid/client/LocalQueue.h
+++ /dev/null
@@ -1,93 +0,0 @@
-#ifndef QPID_CLIENT_LOCALQUEUE_H
-#define QPID_CLIENT_LOCALQUEUE_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/client/Message.h"
-#include "qpid/client/Demux.h"
-#include "qpid/client/AckPolicy.h"
-#include "qpid/sys/Time.h"
-
-namespace qpid {
-namespace client {
-
-/**
- * A local queue to collect messages retrieved from a remote broker
- * queue. Create a queue and subscribe it using the SubscriptionManager.
- * Messages from the remote queue on the broker will be stored in the
- * local queue until you retrieve them.
- *
- * \ingroup clientapi
- */
-class LocalQueue
-{
- public:
- /** Create a local queue. Subscribe the local queue to a remote broker
- * queue with a SubscriptionManager.
- *
- * LocalQueue is an alternative to implementing a MessageListener.
- *
- *@param ackPolicy Policy for acknowledging messages. @see AckPolicy.
- */
- LocalQueue(AckPolicy ackPolicy=AckPolicy());
-
- ~LocalQueue();
-
- /** Wait up to timeout for the next message from the local queue.
- *@param result Set to the message from the queue.
- *@param timeout wait up this timeout for a message to appear.
- *@return true if result was set, false if queue was empty after timeout.
- */
- bool get(Message& result, sys::Duration timeout=0);
-
- /** Get the next message off the local queue, or wait for a
- * message from the broker queue.
- *@exception ClosedException if subscription has been closed.
- */
- Message get();
-
- /** Synonym for get(). */
- Message pop();
-
- /** Return true if local queue is empty. */
- bool empty() const;
-
- /** Number of messages on the local queue */
- size_t size() const;
-
- /** Set the message acknowledgement policy. @see AckPolicy. */
- void setAckPolicy(AckPolicy);
-
- /** Get the message acknowledgement policy. @see AckPolicy. */
- AckPolicy& getAckPolicy();
-
- private:
- Session session;
- Demux::QueuePtr queue;
- AckPolicy autoAck;
-
- friend class SubscriptionManager;
-};
-
-}} // namespace qpid::client
-
-#endif /*!QPID_CLIENT_LOCALQUEUE_H*/
diff --git a/cpp/src/qpid/client/LocalQueueImpl.cpp b/cpp/src/qpid/client/LocalQueueImpl.cpp
new file mode 100644
index 0000000000..8b191728f4
--- /dev/null
+++ b/cpp/src/qpid/client/LocalQueueImpl.cpp
@@ -0,0 +1,78 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/LocalQueueImpl.h"
+#include "qpid/client/MessageImpl.h"
+#include "qpid/Exception.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/client/PrivateImplRef.h"
+#include "qpid/client/SubscriptionImpl.h"
+#include "qpid/client/CompletionImpl.h"
+
+namespace qpid {
+namespace client {
+
+using namespace framing;
+
+Message LocalQueueImpl::pop(sys::Duration timeout) { return get(timeout); }
+
+Message LocalQueueImpl::get(sys::Duration timeout) {
+ Message result;
+ bool ok = get(result, timeout);
+ if (!ok) throw Exception("Timed out waiting for a message");
+ return result;
+}
+
+bool LocalQueueImpl::get(Message& result, sys::Duration timeout) {
+ if (!queue)
+ throw ClosedException();
+ FrameSet::shared_ptr content;
+ bool ok = queue->pop(content, timeout);
+ if (!ok) return false;
+ if (content->isA<MessageTransferBody>()) {
+
+ *MessageImpl::get(result) = MessageImpl(*content);
+ boost::intrusive_ptr<SubscriptionImpl> si = PrivateImplRef<Subscription>::get(subscription);
+ assert(si);
+ if (si) si->received(result);
+ return true;
+ }
+ else
+ throw CommandInvalidException(
+ QPID_MSG("Unexpected method: " << content->getMethod()));
+}
+
+bool LocalQueueImpl::empty() const
+{
+ if (!queue)
+ throw ClosedException();
+ return queue->empty();
+}
+
+size_t LocalQueueImpl::size() const
+{
+ if (!queue)
+ throw ClosedException();
+ return queue->size();
+}
+
+}} // namespace qpid::client
diff --git a/cpp/src/qpid/client/LocalQueueImpl.h b/cpp/src/qpid/client/LocalQueueImpl.h
new file mode 100644
index 0000000000..75b62cf203
--- /dev/null
+++ b/cpp/src/qpid/client/LocalQueueImpl.h
@@ -0,0 +1,108 @@
+#ifndef QPID_CLIENT_LOCALQUEUEIMPL_H
+#define QPID_CLIENT_LOCALQUEUEIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/ClientImportExport.h"
+#include "qpid/client/Handle.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/Subscription.h"
+#include "qpid/client/Demux.h"
+#include "qpid/sys/Time.h"
+#include "qpid/RefCounted.h"
+
+namespace qpid {
+namespace client {
+
+/**
+ * A local queue to collect messages retrieved from a remote broker
+ * queue. Create a queue and subscribe it using the SubscriptionManager.
+ * Messages from the remote queue on the broker will be stored in the
+ * local queue until you retrieve them.
+ *
+ * \ingroup clientapi
+ *
+ * \details Using a Local Queue
+ *
+ * <pre>
+ * LocalQueue local_queue;
+ * subscriptions.subscribe(local_queue, string("message_queue"));
+ * for (int i=0; i&lt;10; i++) {
+ * Message message = local_queue.get();
+ * std::cout &lt;&lt; message.getData() &lt;&lt; std::endl;
+ * }
+ * </pre>
+ *
+ * <h2>Getting Messages</h2>
+ *
+ * <ul><li>
+ * <p>get()</p>
+ * <pre>Message message = local_queue.get();</pre>
+ * <pre>// Specifying timeouts (TIME_SEC, TIME_MSEC, TIME_USEC, TIME_NSEC)
+ *#include <qpid/sys/Time.h>
+ *Message message;
+ *local_queue.get(message, 5*sys::TIME_SEC);</pre></li></ul>
+ *
+ * <h2>Checking size</h2>
+ * <ul><li>
+ * <p>empty()</p>
+ * <pre>if (local_queue.empty()) { ... }</pre></li>
+ * <li><p>size()</p>
+ * <pre>std::cout &lt;&lt; local_queue.size();</pre></li>
+ * </ul>
+ */
+
+class LocalQueueImpl : public RefCounted {
+ public:
+ /** Wait up to timeout for the next message from the local queue.
+ *@param result Set to the message from the queue.
+ *@param timeout wait up this timeout for a message to appear.
+ *@return true if result was set, false if queue was empty after timeout.
+ */
+ bool get(Message& result, sys::Duration timeout=0);
+
+ /** Get the next message off the local queue, or wait up to the timeout
+ * for message from the broker queue.
+ *@param timeout wait up this timeout for a message to appear.
+ *@return message from the queue.
+ *@throw ClosedException if subscription is closed or timeout exceeded.
+ */
+ Message get(sys::Duration timeout=sys::TIME_INFINITE);
+
+ /** Synonym for get() */
+ Message pop(sys::Duration timeout=sys::TIME_INFINITE);
+
+ /** Return true if local queue is empty. */
+ bool empty() const;
+
+ /** Number of messages on the local queue */
+ size_t size() const;
+
+ private:
+ Demux::QueuePtr queue;
+ Subscription subscription;
+ friend class SubscriptionManagerImpl;
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_LOCALQUEUEIMPL_H*/
diff --git a/cpp/src/qpid/client/Message.cpp b/cpp/src/qpid/client/Message.cpp
index d5464594ee..00f911c57e 100644
--- a/cpp/src/qpid/client/Message.cpp
+++ b/cpp/src/qpid/client/Message.cpp
@@ -19,55 +19,44 @@
*
*/
-#include "Message.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/MessageImpl.h"
namespace qpid {
namespace client {
-Message::Message(const std::string& data_,
- const std::string& routingKey,
- const std::string& exchange) : TransferContent(data_, routingKey, exchange) {}
+Message::Message(MessageImpl* mi) : impl(mi) {}
-std::string Message::getDestination() const
-{
- return method.getDestination();
-}
+Message::Message(const std::string& data, const std::string& routingKey)
+ : impl(new MessageImpl(data, routingKey)) {}
-bool Message::isRedelivered() const
-{
- return hasDeliveryProperties() && getDeliveryProperties().getRedelivered();
-}
+Message::Message(const Message& m) : impl(new MessageImpl(*m.impl)) {}
-void Message::setRedelivered(bool redelivered)
-{
- getDeliveryProperties().setRedelivered(redelivered);
-}
+Message::~Message() { delete impl; }
-framing::FieldTable& Message::getHeaders()
-{
- return getMessageProperties().getApplicationHeaders();
-}
+Message& Message::operator=(const Message& m) { *impl = *m.impl; return *this; }
-const framing::FieldTable& Message::getHeaders() const
-{
- return getMessageProperties().getApplicationHeaders();
-}
+void Message::swap(Message& m) { std::swap(impl, m.impl); }
-const framing::MessageTransferBody& Message::getMethod() const
-{
- return method;
-}
+std::string Message::getDestination() const { return impl->getDestination(); }
+bool Message::isRedelivered() const { return impl->isRedelivered(); }
+void Message::setRedelivered(bool redelivered) { impl->setRedelivered(redelivered); }
+framing::FieldTable& Message::getHeaders() { return impl->getHeaders(); }
+const framing::FieldTable& Message::getHeaders() const { return impl->getHeaders(); }
+const framing::SequenceNumber& Message::getId() const { return impl->getId(); }
-const framing::SequenceNumber& Message::getId() const
-{
- return id;
-}
+void Message::setData(const std::string& s) { impl->setData(s); }
+const std::string& Message::getData() const { return impl->getData(); }
+std::string& Message::getData() { return impl->getData(); }
-/**@internal for incoming messages */
-Message::Message(const framing::FrameSet& frameset) :
- method(*frameset.as<framing::MessageTransferBody>()), id(frameset.getId())
-{
- populate(frameset);
-}
+void Message::appendData(const std::string& s) { impl->appendData(s); }
+
+bool Message::hasMessageProperties() const { return impl->hasMessageProperties(); }
+framing::MessageProperties& Message::getMessageProperties() { return impl->getMessageProperties(); }
+const framing::MessageProperties& Message::getMessageProperties() const { return impl->getMessageProperties(); }
+
+bool Message::hasDeliveryProperties() const { return impl->hasDeliveryProperties(); }
+framing::DeliveryProperties& Message::getDeliveryProperties() { return impl->getDeliveryProperties(); }
+const framing::DeliveryProperties& Message::getDeliveryProperties() const { return impl->getDeliveryProperties(); }
}}
diff --git a/cpp/src/qpid/client/Message.h b/cpp/src/qpid/client/Message.h
deleted file mode 100644
index 4e6ed49bb4..0000000000
--- a/cpp/src/qpid/client/Message.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef _client_Message_h
-#define _client_Message_h
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include <string>
-#include "qpid/client/Session.h"
-#include "qpid/framing/MessageTransferBody.h"
-#include "qpid/framing/TransferContent.h"
-
-namespace qpid {
-namespace client {
-
-/**
- * A message sent to or received from the broker.
- *
- * \ingroup clientapi
- */
-class Message : public framing::TransferContent
-{
-public:
- /** Create a Message.
- *@param data Data for the message body.
- *@param routingKey Passed to the exchange that routes the message.
- *@param exchange Name of the exchange that should route the message.
- */
- Message(const std::string& data=std::string(),
- const std::string& routingKey=std::string(),
- const std::string& exchange=std::string());
-
- /** The destination of messages sent to the broker is the exchange
- * name. The destination of messages received from the broker is
- * the delivery tag identifyig the local subscription (often this
- * is the name of the subscribed queue.)
- */
- std::string getDestination() const;
-
- /** Check the redelivered flag. */
- bool isRedelivered() const;
- /** Set the redelivered flag. */
- void setRedelivered(bool redelivered);
-
- /** Get a modifyable reference to the message headers. */
- framing::FieldTable& getHeaders();
-
- /** Get a non-modifyable reference to the message headers. */
- const framing::FieldTable& getHeaders() const;
-
- ///@internal
- const framing::MessageTransferBody& getMethod() const;
- ///@internal
- const framing::SequenceNumber& getId() const;
-
- /**@internal for incoming messages */
- Message(const framing::FrameSet& frameset);
-
-private:
- //method and id are only set for received messages:
- framing::MessageTransferBody method;
- framing::SequenceNumber id;
-};
-
-}}
-
-#endif /*!_client_Message_h*/
diff --git a/cpp/src/qpid/client/MessageImpl.cpp b/cpp/src/qpid/client/MessageImpl.cpp
new file mode 100644
index 0000000000..865c462b15
--- /dev/null
+++ b/cpp/src/qpid/client/MessageImpl.cpp
@@ -0,0 +1,71 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/client/MessageImpl.h"
+
+namespace qpid {
+namespace client {
+
+MessageImpl::MessageImpl(const std::string& data, const std::string& routingKey) : TransferContent(data, routingKey) {}
+
+std::string MessageImpl::getDestination() const
+{
+ return method.getDestination();
+}
+
+bool MessageImpl::isRedelivered() const
+{
+ return hasDeliveryProperties() && getDeliveryProperties().getRedelivered();
+}
+
+void MessageImpl::setRedelivered(bool redelivered)
+{
+ getDeliveryProperties().setRedelivered(redelivered);
+}
+
+framing::FieldTable& MessageImpl::getHeaders()
+{
+ return getMessageProperties().getApplicationHeaders();
+}
+
+const framing::FieldTable& MessageImpl::getHeaders() const
+{
+ return getMessageProperties().getApplicationHeaders();
+}
+
+const framing::MessageTransferBody& MessageImpl::getMethod() const
+{
+ return method;
+}
+
+const framing::SequenceNumber& MessageImpl::getId() const
+{
+ return id;
+}
+
+/**@internal for incoming messages */
+MessageImpl::MessageImpl(const framing::FrameSet& frameset) :
+ method(*frameset.as<framing::MessageTransferBody>()), id(frameset.getId())
+{
+ populate(frameset);
+}
+
+}}
diff --git a/cpp/src/qpid/client/MessageImpl.h b/cpp/src/qpid/client/MessageImpl.h
new file mode 100644
index 0000000000..a64ddd20d8
--- /dev/null
+++ b/cpp/src/qpid/client/MessageImpl.h
@@ -0,0 +1,80 @@
+#ifndef QPID_CLIENT_MESSAGEIMPL_H
+#define QPID_CLIENT_MESSAGEIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/Message.h"
+#include "qpid/client/Session.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/TransferContent.h"
+#include <string>
+
+namespace qpid {
+namespace client {
+
+class MessageImpl : public framing::TransferContent
+{
+public:
+ /** Create a Message.
+ *@param data Data for the message body.
+ *@param routingKey Passed to the exchange that routes the message.
+ */
+ MessageImpl(const std::string& data=std::string(),
+ const std::string& routingKey=std::string());
+
+ /** The destination of messages sent to the broker is the exchange
+ * name. The destination of messages received from the broker is
+ * the delivery tag identifyig the local subscription (often this
+ * is the name of the subscribed queue.)
+ */
+ std::string getDestination() const;
+
+ /** Check the redelivered flag. */
+ bool isRedelivered() const;
+ /** Set the redelivered flag. */
+ void setRedelivered(bool redelivered);
+
+ /** Get a modifyable reference to the message headers. */
+ framing::FieldTable& getHeaders();
+
+ /** Get a non-modifyable reference to the message headers. */
+ const framing::FieldTable& getHeaders() const;
+
+ ///@internal
+ const framing::MessageTransferBody& getMethod() const;
+ ///@internal
+ const framing::SequenceNumber& getId() const;
+
+ /**@internal for incoming messages */
+ MessageImpl(const framing::FrameSet& frameset);
+
+ static MessageImpl* get(Message& m) { return m.impl; }
+ static const MessageImpl* get(const Message& m) { return m.impl; }
+
+private:
+ //method and id are only set for received messages:
+ framing::MessageTransferBody method;
+ framing::SequenceNumber id;
+};
+
+}}
+
+#endif /*!QPID_CLIENT_MESSAGEIMPL_H*/
diff --git a/cpp/src/qpid/client/MessageListener.cpp b/cpp/src/qpid/client/MessageListener.cpp
index 68ebedeb0d..0f2a71287c 100644
--- a/cpp/src/qpid/client/MessageListener.cpp
+++ b/cpp/src/qpid/client/MessageListener.cpp
@@ -19,6 +19,6 @@
*
*/
-#include "MessageListener.h"
+#include "qpid/client/MessageListener.h"
qpid::client::MessageListener::~MessageListener() {}
diff --git a/cpp/src/qpid/client/MessageListener.h b/cpp/src/qpid/client/MessageListener.h
deleted file mode 100644
index 76e1d17445..0000000000
--- a/cpp/src/qpid/client/MessageListener.h
+++ /dev/null
@@ -1,53 +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 <string>
-
-#ifndef _MessageListener_
-#define _MessageListener_
-
-#include "Message.h"
-
-namespace qpid {
-namespace client {
-
- /**
- * Implement a subclass of MessageListener and subscribe it using
- * the SubscriptionManager to receive messages.
- *
- * Another way to receive messages is by using a LocalQueue.
- *
- * \ingroup clientapi
- */
- class MessageListener{
- public:
- virtual ~MessageListener();
-
- /** Called for each message arriving from the broker. Override
- * in your own subclass to process messages.
- */
- virtual void received(Message& msg) = 0;
- };
-
-}
-}
-
-
-#endif
diff --git a/cpp/src/qpid/client/MessageQueue.h b/cpp/src/qpid/client/MessageQueue.h
deleted file mode 100644
index ab6d351ba7..0000000000
--- a/cpp/src/qpid/client/MessageQueue.h
+++ /dev/null
@@ -1,50 +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.
- *
- */
-
-#ifndef _MessageQueue_
-#define _MessageQueue_
-#include <iostream>
-#include "qpid/sys/BlockingQueue.h"
-#include "MessageListener.h"
-
-namespace qpid {
-namespace client {
-
-/**
- * A MessageListener implementation that queues up
- * messages.
- *
- * \ingroup clientapi
- */
-class MessageQueue : public sys::BlockingQueue<Message>, public MessageListener
-{
- public:
- void received(Message& msg)
- {
- push(msg);
- }
-};
-
-}
-}
-
-
-#endif
diff --git a/cpp/src/qpid/client/MessageReplayTracker.cpp b/cpp/src/qpid/client/MessageReplayTracker.cpp
new file mode 100644
index 0000000000..079fb1167a
--- /dev/null
+++ b/cpp/src/qpid/client/MessageReplayTracker.cpp
@@ -0,0 +1,78 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/MessageReplayTracker.h"
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace client {
+
+MessageReplayTracker::MessageReplayTracker(uint f) : flushInterval(f), count(0) {}
+
+void MessageReplayTracker::send(const Message& message, const std::string& destination)
+{
+ buffer.push_back(ReplayRecord(message, destination));
+ buffer.back().send(*this);
+ if (flushInterval && ++count >= flushInterval) {
+ checkCompletion();
+ if (!buffer.empty()) session.flush();
+ }
+}
+void MessageReplayTracker::init(AsyncSession s)
+{
+ session = s;
+}
+
+void MessageReplayTracker::replay(AsyncSession s)
+{
+ session = s;
+ std::for_each(buffer.begin(), buffer.end(), boost::bind(&ReplayRecord::send, _1, boost::ref(*this)));
+ session.flush();
+ count = 0;
+}
+
+void MessageReplayTracker::setFlushInterval(uint f)
+{
+ flushInterval = f;
+}
+
+uint MessageReplayTracker::getFlushInterval()
+{
+ return flushInterval;
+}
+
+void MessageReplayTracker::checkCompletion()
+{
+ buffer.remove_if(boost::bind(&ReplayRecord::isComplete, _1));
+}
+
+MessageReplayTracker::ReplayRecord::ReplayRecord(const Message& m, const std::string& d) : message(m), destination(d) {}
+
+void MessageReplayTracker::ReplayRecord::send(MessageReplayTracker& tracker)
+{
+ status = tracker.session.messageTransfer(arg::destination=destination, arg::content=message);
+}
+
+bool MessageReplayTracker::ReplayRecord::isComplete()
+{
+ return status.isComplete();
+}
+
+}} // namespace qpid::client
diff --git a/cpp/src/qpid/client/PrivateImplRef.h b/cpp/src/qpid/client/PrivateImplRef.h
new file mode 100644
index 0000000000..503a383c31
--- /dev/null
+++ b/cpp/src/qpid/client/PrivateImplRef.h
@@ -0,0 +1,94 @@
+#ifndef QPID_CLIENT_PRIVATEIMPL_H
+#define QPID_CLIENT_PRIVATEIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/ClientImportExport.h"
+#include <boost/intrusive_ptr.hpp>
+#include "qpid/RefCounted.h"
+
+namespace qpid {
+namespace client {
+
+// FIXME aconway 2009-04-24: details!
+/** @file
+ *
+ * Helper class to implement a class with a private, reference counted
+ * implementation and reference semantics.
+ *
+ * Such classes are used in the public API to hide implementation, they
+ * should. Example of use:
+ *
+ * === Foo.h
+ *
+ * template <class T> PrivateImplRef;
+ * class FooImpl;
+ *
+ * Foo : public Handle<FooImpl> {
+ * public:
+ * Foo(FooImpl* = 0);
+ * Foo(const Foo&);
+ * ~Foo();
+ * Foo& operator=(const Foo&);
+ *
+ * int fooDo(); // and other Foo functions...
+ *
+ * private:
+ * typedef FooImpl Impl;
+ * Impl* impl;
+ * friend class PrivateImplRef<Foo>;
+ *
+ * === Foo.cpp
+ *
+ * typedef PrivateImplRef<Foo> PI;
+ * Foo::Foo(FooImpl* p) { PI::ctor(*this, p); }
+ * Foo::Foo(const Foo& c) : Handle<FooImpl>() { PI::copy(*this, c); }
+ * Foo::~Foo() { PI::dtor(*this); }
+ * Foo& Foo::operator=(const Foo& c) { return PI::assign(*this, c); }
+ *
+ * int foo::fooDo() { return impl->fooDo(); }
+ *
+ */
+template <class T> class PrivateImplRef {
+ public:
+ typedef typename T::Impl Impl;
+ typedef boost::intrusive_ptr<Impl> intrusive_ptr;
+
+ static intrusive_ptr get(const T& t) { return intrusive_ptr(t.impl); }
+
+ static void set(T& t, const intrusive_ptr& p) {
+ if (t.impl == p) return;
+ if (t.impl) boost::intrusive_ptr_release(t.impl);
+ t.impl = p.get();
+ if (t.impl) boost::intrusive_ptr_add_ref(t.impl);
+ }
+
+ // Helper functions to implement the ctor, dtor, copy, assign
+ static void ctor(T& t, Impl* p) { t.impl = p; if (p) boost::intrusive_ptr_add_ref(p); }
+ static void copy(T& t, const T& x) { if (&t == &x) return; t.impl = 0; assign(t, x); }
+ static void dtor(T& t) { if(t.impl) boost::intrusive_ptr_release(t.impl); }
+ static T& assign(T& t, const T& x) { set(t, get(x)); return t;}
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_PRIVATEIMPL_H*/
diff --git a/cpp/src/qpid/client/QueueOptions.cpp b/cpp/src/qpid/client/QueueOptions.cpp
new file mode 100644
index 0000000000..f4c1483859
--- /dev/null
+++ b/cpp/src/qpid/client/QueueOptions.cpp
@@ -0,0 +1,123 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/client/QueueOptions.h"
+
+namespace qpid {
+namespace client {
+
+enum QueueEventGeneration {ENQUEUE_ONLY=1, ENQUEUE_AND_DEQUEUE=2};
+
+
+QueueOptions::QueueOptions()
+{}
+
+const std::string QueueOptions::strMaxCountKey("qpid.max_count");
+const std::string QueueOptions::strMaxSizeKey("qpid.max_size");
+const std::string QueueOptions::strTypeKey("qpid.policy_type");
+const std::string QueueOptions::strREJECT("reject");
+const std::string QueueOptions::strFLOW_TO_DISK("flow_to_disk");
+const std::string QueueOptions::strRING("ring");
+const std::string QueueOptions::strRING_STRICT("ring_strict");
+const std::string QueueOptions::strLastValueQueue("qpid.last_value_queue");
+const std::string QueueOptions::strPersistLastNode("qpid.persist_last_node");
+const std::string QueueOptions::strLVQMatchProperty("qpid.LVQ_key");
+const std::string QueueOptions::strLastValueQueueNoBrowse("qpid.last_value_queue_no_browse");
+const std::string QueueOptions::strQueueEventMode("qpid.queue_event_generation");
+
+
+QueueOptions::~QueueOptions()
+{}
+
+void QueueOptions::setSizePolicy(QueueSizePolicy sp, uint64_t maxSize, uint32_t maxCount)
+{
+ if (maxCount) setInt(strMaxCountKey, maxCount);
+ if (maxSize) setInt(strMaxSizeKey, maxSize);
+ if (maxSize || maxCount){
+ switch (sp)
+ {
+ case REJECT:
+ setString(strTypeKey, strREJECT);
+ break;
+ case FLOW_TO_DISK:
+ setString(strTypeKey, strFLOW_TO_DISK);
+ break;
+ case RING:
+ setString(strTypeKey, strRING);
+ break;
+ case RING_STRICT:
+ setString(strTypeKey, strRING_STRICT);
+ break;
+ case NONE:
+ clearSizePolicy();
+ break;
+ }
+ }
+}
+
+
+void QueueOptions::setPersistLastNode()
+{
+ setInt(strPersistLastNode, 1);
+}
+
+void QueueOptions::setOrdering(QueueOrderingPolicy op)
+{
+ if (op == LVQ){
+ setInt(strLastValueQueue, 1);
+ }else if (op == LVQ_NO_BROWSE){
+ setInt(strLastValueQueueNoBrowse, 1);
+ }else {
+ clearOrdering();
+ }
+}
+
+void QueueOptions::getLVQKey(std::string& key)
+{
+ key.assign(strLVQMatchProperty);
+}
+
+void QueueOptions::clearSizePolicy()
+{
+ erase(strMaxCountKey);
+ erase(strMaxSizeKey);
+ erase(strTypeKey);
+}
+
+void QueueOptions::clearPersistLastNode()
+{
+ erase(strPersistLastNode);
+}
+
+void QueueOptions::clearOrdering()
+{
+ erase(strLastValueQueue);
+}
+
+void QueueOptions::enableQueueEvents(bool enqueueOnly)
+{
+ setInt(strQueueEventMode, enqueueOnly ? ENQUEUE_ONLY : ENQUEUE_AND_DEQUEUE);
+}
+
+}
+}
+
+
diff --git a/cpp/src/qpid/client/RdmaConnector.cpp b/cpp/src/qpid/client/RdmaConnector.cpp
new file mode 100644
index 0000000000..77169db3a6
--- /dev/null
+++ b/cpp/src/qpid/client/RdmaConnector.cpp
@@ -0,0 +1,387 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/client/Connector.h"
+
+#include "qpid/client/Bounds.h"
+#include "qpid/client/ConnectionImpl.h"
+#include "qpid/client/ConnectionSettings.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/Time.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/sys/rdma/RdmaIO.h"
+#include "qpid/sys/Dispatcher.h"
+#include "qpid/sys/Poller.h"
+#include "qpid/sys/SecurityLayer.h"
+#include "qpid/Msg.h"
+
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/format.hpp>
+#include <boost/lexical_cast.hpp>
+
+// This stuff needs to abstracted out of here to a platform specific file
+#include <netdb.h>
+
+namespace qpid {
+namespace client {
+
+using namespace qpid::sys;
+using namespace qpid::framing;
+using boost::format;
+using boost::str;
+
+ class RdmaConnector : public Connector, public sys::Codec, private sys::Runnable
+{
+ struct Buff;
+
+ typedef Rdma::Buffer BufferBase;
+ typedef std::deque<framing::AMQFrame> Frames;
+
+ const uint16_t maxFrameSize;
+ sys::Mutex lock;
+ Frames frames;
+ size_t lastEof; // Position after last EOF in frames
+ uint64_t currentSize;
+ Bounds* bounds;
+
+
+ framing::ProtocolVersion version;
+ bool initiated;
+
+ sys::Mutex pollingLock;
+ bool polling;
+ bool joined;
+
+ sys::ShutdownHandler* shutdownHandler;
+ framing::InputHandler* input;
+ framing::InitiationHandler* initialiser;
+ framing::OutputHandler* output;
+
+ sys::Thread receiver;
+
+ Rdma::AsynchIO* aio;
+ sys::Poller::shared_ptr poller;
+ std::auto_ptr<qpid::sys::SecurityLayer> securityLayer;
+
+ ~RdmaConnector();
+
+ void run();
+ void handleClosed();
+ bool closeInternal();
+
+ // Callbacks
+ void connected(sys::Poller::shared_ptr, Rdma::Connection::intrusive_ptr&, const Rdma::ConnectionParams&);
+ void connectionError(sys::Poller::shared_ptr, Rdma::Connection::intrusive_ptr&, Rdma::ErrorType);
+ void disconnected(sys::Poller::shared_ptr, Rdma::Connection::intrusive_ptr&);
+ void rejected(sys::Poller::shared_ptr, Rdma::Connection::intrusive_ptr&, const Rdma::ConnectionParams&);
+
+ void readbuff(Rdma::AsynchIO&, Rdma::Buffer*);
+ void writebuff(Rdma::AsynchIO&);
+ void writeDataBlock(const framing::AMQDataBlock& data);
+ void eof(Rdma::AsynchIO&);
+
+ std::string identifier;
+
+ ConnectionImpl* impl;
+
+ void connect(const std::string& host, int port);
+ void close();
+ void send(framing::AMQFrame& frame);
+ void abort() {} // TODO: need to fix this for heartbeat timeouts to work
+
+ void setInputHandler(framing::InputHandler* handler);
+ void setShutdownHandler(sys::ShutdownHandler* handler);
+ sys::ShutdownHandler* getShutdownHandler() const;
+ framing::OutputHandler* getOutputHandler();
+ const std::string& getIdentifier() const;
+ void activateSecurityLayer(std::auto_ptr<qpid::sys::SecurityLayer>);
+
+ size_t decode(const char* buffer, size_t size);
+ size_t encode(const char* buffer, size_t size);
+ bool canEncode();
+
+public:
+ RdmaConnector(framing::ProtocolVersion pVersion,
+ const ConnectionSettings&,
+ ConnectionImpl*);
+ unsigned int getSSF() { return 0; }
+};
+
+// Static constructor which registers connector here
+namespace {
+ Connector* create(framing::ProtocolVersion v, const ConnectionSettings& s, ConnectionImpl* c) {
+ return new RdmaConnector(v, s, c);
+ }
+
+ struct StaticInit {
+ StaticInit() {
+ Connector::registerFactory("rdma", &create);
+ Connector::registerFactory("ib", &create);
+ };
+ } init;
+}
+
+
+RdmaConnector::RdmaConnector(ProtocolVersion ver,
+ const ConnectionSettings& settings,
+ ConnectionImpl* cimpl)
+ : maxFrameSize(settings.maxFrameSize),
+ lastEof(0),
+ currentSize(0),
+ bounds(cimpl),
+ version(ver),
+ initiated(false),
+ polling(false),
+ joined(true),
+ shutdownHandler(0),
+ aio(0),
+ impl(cimpl)
+{
+ QPID_LOG(debug, "RdmaConnector created for " << version);
+}
+
+RdmaConnector::~RdmaConnector() {
+ close();
+}
+
+void RdmaConnector::connect(const std::string& host, int port){
+ Mutex::ScopedLock l(pollingLock);
+ assert(!polling);
+ assert(joined);
+ poller = Poller::shared_ptr(new Poller);
+
+ SocketAddress sa(host, boost::lexical_cast<std::string>(port));
+ Rdma::Connector* c = new Rdma::Connector(
+ sa,
+ Rdma::ConnectionParams(maxFrameSize, Rdma::DEFAULT_WR_ENTRIES),
+ boost::bind(&RdmaConnector::connected, this, poller, _1, _2),
+ boost::bind(&RdmaConnector::connectionError, this, poller, _1, _2),
+ boost::bind(&RdmaConnector::disconnected, this, poller, _1),
+ boost::bind(&RdmaConnector::rejected, this, poller, _1, _2));
+ c->start(poller);
+
+ polling = true;
+ joined = false;
+ receiver = Thread(this);
+}
+
+// The following only gets run when connected
+void RdmaConnector::connected(Poller::shared_ptr poller, Rdma::Connection::intrusive_ptr& ci, const Rdma::ConnectionParams& cp) {
+ Rdma::QueuePair::intrusive_ptr q = ci->getQueuePair();
+
+ aio = new Rdma::AsynchIO(ci->getQueuePair(),
+ cp.maxRecvBufferSize, cp.initialXmitCredit , Rdma::DEFAULT_WR_ENTRIES,
+ boost::bind(&RdmaConnector::readbuff, this, _1, _2),
+ boost::bind(&RdmaConnector::writebuff, this, _1),
+ 0, // write buffers full
+ boost::bind(&RdmaConnector::eof, this, _1)); // data error - just close connection
+ aio->start(poller);
+
+ identifier = str(format("[%1% %2%]") % ci->getLocalName() % ci->getPeerName());
+ ProtocolInitiation init(version);
+ writeDataBlock(init);
+}
+
+void RdmaConnector::connectionError(sys::Poller::shared_ptr, Rdma::Connection::intrusive_ptr&, Rdma::ErrorType) {
+ QPID_LOG(trace, "Connection Error " << identifier);
+ eof(*aio);
+}
+
+void RdmaConnector::disconnected(sys::Poller::shared_ptr, Rdma::Connection::intrusive_ptr&) {
+ eof(*aio);
+}
+
+void RdmaConnector::rejected(sys::Poller::shared_ptr, Rdma::Connection::intrusive_ptr&, const Rdma::ConnectionParams& cp) {
+ QPID_LOG(trace, "Connection Rejected " << identifier << ": " << cp.maxRecvBufferSize);
+ eof(*aio);
+}
+
+bool RdmaConnector::closeInternal() {
+ bool ret;
+ {
+ Mutex::ScopedLock l(pollingLock);
+ ret = polling;
+ if (polling) {
+ polling = false;
+ poller->shutdown();
+ }
+ if (joined || receiver.id() == Thread::current().id()) {
+ return ret;
+ }
+ joined = true;
+ }
+
+ receiver.join();
+ return ret;
+}
+
+void RdmaConnector::close() {
+ closeInternal();
+}
+
+void RdmaConnector::setInputHandler(InputHandler* handler){
+ input = handler;
+}
+
+void RdmaConnector::setShutdownHandler(ShutdownHandler* handler){
+ shutdownHandler = handler;
+}
+
+OutputHandler* RdmaConnector::getOutputHandler(){
+ return this;
+}
+
+sys::ShutdownHandler* RdmaConnector::getShutdownHandler() const {
+ return shutdownHandler;
+}
+
+const std::string& RdmaConnector::getIdentifier() const {
+ return identifier;
+}
+
+void RdmaConnector::send(AMQFrame& frame) {
+ bool notifyWrite = false;
+ {
+ Mutex::ScopedLock l(lock);
+ frames.push_back(frame);
+ //only ask to write if this is the end of a frameset or if we
+ //already have a buffers worth of data
+ currentSize += frame.encodedSize();
+ if (frame.getEof()) {
+ lastEof = frames.size();
+ notifyWrite = true;
+ } else {
+ notifyWrite = (currentSize >= maxFrameSize);
+ }
+ }
+ if (notifyWrite) aio->notifyPendingWrite();
+}
+
+void RdmaConnector::handleClosed() {
+ if (closeInternal() && shutdownHandler)
+ shutdownHandler->shutdown();
+}
+
+// Called in IO thread. (write idle routine)
+// This is NOT only called in response to previously calling notifyPendingWrite
+void RdmaConnector::writebuff(Rdma::AsynchIO&) {
+ Codec* codec = securityLayer.get() ? (Codec*) securityLayer.get() : (Codec*) this;
+ if (codec->canEncode()) {
+ std::auto_ptr<BufferBase> buffer = std::auto_ptr<BufferBase>(aio->getBuffer());
+ size_t encoded = codec->encode(buffer->bytes, buffer->byteCount);
+
+ buffer->dataStart = 0;
+ buffer->dataCount = encoded;
+ aio->queueWrite(buffer.release());
+ }
+}
+
+bool RdmaConnector::canEncode()
+{
+ Mutex::ScopedLock l(lock);
+ //have at least one full frameset or a whole buffers worth of data
+ return aio->writable() && aio->bufferAvailable() && (lastEof || currentSize >= maxFrameSize);
+}
+
+size_t RdmaConnector::encode(const char* buffer, size_t size)
+{
+ framing::Buffer out(const_cast<char*>(buffer), size);
+ size_t bytesWritten(0);
+ {
+ Mutex::ScopedLock l(lock);
+ while (!frames.empty() && out.available() >= frames.front().encodedSize() ) {
+ frames.front().encode(out);
+ QPID_LOG(trace, "SENT " << identifier << ": " << frames.front());
+ frames.pop_front();
+ if (lastEof) --lastEof;
+ }
+ bytesWritten = size - out.available();
+ currentSize -= bytesWritten;
+ }
+ if (bounds) bounds->reduce(bytesWritten);
+ return bytesWritten;
+}
+
+void RdmaConnector::readbuff(Rdma::AsynchIO&, Rdma::Buffer* buff) {
+ Codec* codec = securityLayer.get() ? (Codec*) securityLayer.get() : (Codec*) this;
+ codec->decode(buff->bytes+buff->dataStart, buff->dataCount);
+}
+
+size_t RdmaConnector::decode(const char* buffer, size_t size)
+{
+ framing::Buffer in(const_cast<char*>(buffer), size);
+ if (!initiated) {
+ framing::ProtocolInitiation protocolInit;
+ if (protocolInit.decode(in)) {
+ //TODO: check the version is correct
+ QPID_LOG(debug, "RECV " << identifier << " INIT(" << protocolInit << ")");
+ }
+ initiated = true;
+ }
+ AMQFrame frame;
+ while(frame.decode(in)){
+ QPID_LOG(trace, "RECV " << identifier << ": " << frame);
+ input->received(frame);
+ }
+ return size - in.available();
+}
+
+void RdmaConnector::writeDataBlock(const AMQDataBlock& data) {
+ Rdma::Buffer* buff = aio->getBuffer();
+ framing::Buffer out(buff->bytes, buff->byteCount);
+ data.encode(out);
+ buff->dataCount = data.encodedSize();
+ aio->queueWrite(buff);
+}
+
+void RdmaConnector::eof(Rdma::AsynchIO&) {
+ handleClosed();
+}
+
+void RdmaConnector::run(){
+ // Keep the connection impl in memory until run() completes.
+ //GRS: currently the ConnectionImpls destructor is where the Io thread is joined
+ //boost::shared_ptr<ConnectionImpl> protect = impl->shared_from_this();
+ //assert(protect);
+ try {
+ Dispatcher d(poller);
+
+ //aio->start(poller);
+ d.run();
+ //aio->queueForDeletion();
+ } catch (const std::exception& e) {
+ {
+ // We're no longer polling
+ Mutex::ScopedLock l(pollingLock);
+ polling = false;
+ }
+ QPID_LOG(error, e.what());
+ handleClosed();
+ }
+}
+
+void RdmaConnector::activateSecurityLayer(std::auto_ptr<qpid::sys::SecurityLayer> sl)
+{
+ securityLayer = sl;
+ securityLayer->init(this);
+}
+
+}} // namespace qpid::client
diff --git a/cpp/src/qpid/client/Results.cpp b/cpp/src/qpid/client/Results.cpp
index c605af2878..0de3e8bd04 100644
--- a/cpp/src/qpid/client/Results.cpp
+++ b/cpp/src/qpid/client/Results.cpp
@@ -19,18 +19,21 @@
*
*/
-#include "Results.h"
-#include "FutureResult.h"
+#include "qpid/client/Results.h"
+#include "qpid/client/FutureResult.h"
#include "qpid/framing/SequenceSet.h"
using namespace qpid::framing;
-using namespace boost;
namespace qpid {
namespace client {
Results::Results() {}
+Results::~Results() {
+ try { close(); } catch (const std::exception& /*e*/) { assert(0); }
+}
+
void Results::close()
{
for (Listeners::iterator i = listeners.begin(); i != listeners.end(); i++) {
diff --git a/cpp/src/qpid/client/Results.h b/cpp/src/qpid/client/Results.h
index 667f35089c..4c49f6b05b 100644
--- a/cpp/src/qpid/client/Results.h
+++ b/cpp/src/qpid/client/Results.h
@@ -38,6 +38,7 @@ public:
typedef boost::shared_ptr<FutureResult> FutureResultPtr;
Results();
+ ~Results();
void completed(const framing::SequenceSet& set);
void received(const framing::SequenceNumber& id, const std::string& result);
FutureResultPtr listenForResult(const framing::SequenceNumber& point);
diff --git a/cpp/src/qpid/client/Sasl.h b/cpp/src/qpid/client/Sasl.h
new file mode 100644
index 0000000000..63da37fcb1
--- /dev/null
+++ b/cpp/src/qpid/client/Sasl.h
@@ -0,0 +1,70 @@
+#ifndef QPID_CLIENT_SASL_H
+#define QPID_CLIENT_SASL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <memory>
+#include <string>
+#include "qpid/sys/IntegerTypes.h"
+
+namespace qpid {
+
+namespace sys {
+class SecurityLayer;
+}
+
+namespace client {
+
+struct ConnectionSettings;
+
+/**
+ * Interface to SASL support. This class is implemented by platform-specific
+ * SASL providers.
+ */
+class Sasl
+{
+ public:
+ /**
+ * Start SASL negotiation with the broker.
+ *
+ * @param mechanisms Comma-separated list of the SASL mechanism the
+ * client supports.
+ * @param ssf Security Strength Factor (SSF). SSF is used to negotiate
+ * a SASL security layer on top of the connection should both
+ * parties require and support it. The value indicates the
+ * required level of security for communication. Possible
+ * values are:
+ * @li 0 No security
+ * @li 1 Integrity checking only
+ * @li >1 Integrity and confidentiality with the number
+ * giving the encryption key length.
+ */
+ virtual std::string start(const std::string& mechanisms, unsigned int ssf) = 0;
+ virtual std::string step(const std::string& challenge) = 0;
+ virtual std::string getMechanism() = 0;
+ virtual std::string getUserId() = 0;
+ virtual std::auto_ptr<qpid::sys::SecurityLayer> getSecurityLayer(uint16_t maxFrameSize) = 0;
+ virtual ~Sasl() {}
+};
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_SASL_H*/
diff --git a/cpp/src/qpid/client/SaslFactory.cpp b/cpp/src/qpid/client/SaslFactory.cpp
new file mode 100644
index 0000000000..5012b75c94
--- /dev/null
+++ b/cpp/src/qpid/client/SaslFactory.cpp
@@ -0,0 +1,379 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/client/SaslFactory.h"
+#include "qpid/client/ConnectionSettings.h"
+#include <map>
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef HAVE_SASL
+
+namespace qpid {
+namespace client {
+
+//Null implementation
+
+SaslFactory::SaslFactory() {}
+
+SaslFactory::~SaslFactory() {}
+
+SaslFactory& SaslFactory::getInstance()
+{
+ qpid::sys::Mutex::ScopedLock l(lock);
+ if (!instance.get()) {
+ instance = std::auto_ptr<SaslFactory>(new SaslFactory());
+ }
+ return *instance;
+}
+
+std::auto_ptr<Sasl> SaslFactory::create(const ConnectionSettings&)
+{
+ return std::auto_ptr<Sasl>();
+}
+
+qpid::sys::Mutex SaslFactory::lock;
+std::auto_ptr<SaslFactory> SaslFactory::instance;
+
+}} // namespace qpid::client
+
+#else
+
+#include "qpid/Exception.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/sys/SecurityLayer.h"
+#include "qpid/sys/cyrus/CyrusSecurityLayer.h"
+#include "qpid/log/Statement.h"
+#include <sasl/sasl.h>
+#include <strings.h>
+
+namespace qpid {
+namespace client {
+
+using qpid::sys::SecurityLayer;
+using qpid::sys::cyrus::CyrusSecurityLayer;
+using qpid::framing::InternalErrorException;
+
+const size_t MAX_LOGIN_LENGTH = 50;
+
+class CyrusSasl : public Sasl
+{
+ public:
+ CyrusSasl(const ConnectionSettings&);
+ ~CyrusSasl();
+ std::string start(const std::string& mechanisms, unsigned int ssf);
+ std::string step(const std::string& challenge);
+ std::string getMechanism();
+ std::string getUserId();
+ std::auto_ptr<SecurityLayer> getSecurityLayer(uint16_t maxFrameSize);
+ private:
+ sasl_conn_t* conn;
+ sasl_callback_t callbacks[5];//realm, user, authname, password, end-of-list
+ ConnectionSettings settings;
+ std::string input;
+ std::string mechanism;
+ char login[MAX_LOGIN_LENGTH];
+
+ void interact(sasl_interact_t* client_interact);
+};
+
+//sasl callback functions
+int getUserFromSettings(void *context, int id, const char **result, unsigned *len);
+int getPasswordFromSettings(sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret);
+typedef int CallbackProc();
+
+qpid::sys::Mutex SaslFactory::lock;
+std::auto_ptr<SaslFactory> SaslFactory::instance;
+
+SaslFactory::SaslFactory()
+{
+ sasl_callback_t* callbacks = 0;
+ int result = sasl_client_init(callbacks);
+ if (result != SASL_OK) {
+ throw InternalErrorException(QPID_MSG("Sasl error: " << sasl_errstring(result, 0, 0)));
+ }
+}
+
+SaslFactory::~SaslFactory()
+{
+ sasl_done();
+}
+
+SaslFactory& SaslFactory::getInstance()
+{
+ qpid::sys::Mutex::ScopedLock l(lock);
+ if (!instance.get()) {
+ instance = std::auto_ptr<SaslFactory>(new SaslFactory());
+ }
+ return *instance;
+}
+
+std::auto_ptr<Sasl> SaslFactory::create(const ConnectionSettings& settings)
+{
+ std::auto_ptr<Sasl> sasl(new CyrusSasl(settings));
+ return sasl;
+}
+
+CyrusSasl::CyrusSasl(const ConnectionSettings& s) : conn(0), settings(s)
+{
+ size_t i = 0;
+
+ callbacks[i].id = SASL_CB_GETREALM;
+ callbacks[i].proc = 0;
+ callbacks[i++].context = 0;
+
+ if (!settings.username.empty()) {
+ callbacks[i].id = SASL_CB_USER;
+ callbacks[i].proc = (CallbackProc*) &getUserFromSettings;
+ callbacks[i++].context = &settings;
+
+ callbacks[i].id = SASL_CB_AUTHNAME;
+ callbacks[i].proc = (CallbackProc*) &getUserFromSettings;
+ callbacks[i++].context = &settings;
+ }
+
+ callbacks[i].id = SASL_CB_PASS;
+ if (settings.password.empty()) {
+ callbacks[i].proc = 0;
+ callbacks[i++].context = 0;
+ } else {
+ callbacks[i].proc = (CallbackProc*) &getPasswordFromSettings;
+ callbacks[i++].context = &settings;
+ }
+
+ callbacks[i].id = SASL_CB_LIST_END;
+ callbacks[i].proc = 0;
+ callbacks[i++].context = 0;
+}
+
+CyrusSasl::~CyrusSasl()
+{
+ if (conn) {
+ sasl_dispose(&conn);
+ }
+}
+
+namespace {
+ const std::string SSL("ssl");
+}
+
+std::string CyrusSasl::start(const std::string& mechanisms, unsigned int ssf)
+{
+ QPID_LOG(debug, "CyrusSasl::start(" << mechanisms << ")");
+ int result = sasl_client_new(settings.service.c_str(),
+ settings.host.c_str(),
+ 0, 0, /* Local and remote IP address strings */
+ callbacks,
+ 0, /* security flags */
+ &conn);
+
+ if (result != SASL_OK) throw InternalErrorException(QPID_MSG("Sasl error: " << sasl_errdetail(conn)));
+
+ sasl_security_properties_t secprops;
+
+ if (ssf) {
+ sasl_ssf_t external_ssf = (sasl_ssf_t) ssf;
+ if (external_ssf) {
+ int result = sasl_setprop(conn, SASL_SSF_EXTERNAL, &external_ssf);
+ if (result != SASL_OK) {
+ throw framing::InternalErrorException(QPID_MSG("SASL error: unable to set external SSF: " << result));
+ }
+ QPID_LOG(debug, "external SSF detected and set to " << ssf);
+ }
+ }
+
+ secprops.min_ssf = settings.minSsf;
+ secprops.max_ssf = settings.maxSsf;
+ secprops.maxbufsize = 65535;
+
+ QPID_LOG(debug, "min_ssf: " << secprops.min_ssf << ", max_ssf: " << secprops.max_ssf);
+
+ secprops.property_names = 0;
+ secprops.property_values = 0;
+ secprops.security_flags = 0;//TODO: provide means for application to configure these
+
+ result = sasl_setprop(conn, SASL_SEC_PROPS, &secprops);
+ if (result != SASL_OK) {
+ throw framing::InternalErrorException(QPID_MSG("SASL error: " << sasl_errdetail(conn)));
+ }
+
+
+ sasl_interact_t* client_interact = 0;
+ const char *out = 0;
+ unsigned outlen = 0;
+ const char *chosenMechanism = 0;
+
+ do {
+ result = sasl_client_start(conn,
+ mechanisms.c_str(),
+ &client_interact,
+ &out,
+ &outlen,
+ &chosenMechanism);
+
+ if (result == SASL_INTERACT) {
+ interact(client_interact);
+ }
+ } while (result == SASL_INTERACT);
+
+ if (result != SASL_CONTINUE && result != SASL_OK) {
+ throw InternalErrorException(QPID_MSG("Sasl error: " << sasl_errdetail(conn)));
+ }
+
+ mechanism = std::string(chosenMechanism);
+ QPID_LOG(debug, "CyrusSasl::start(" << mechanisms << "): selected "
+ << mechanism << " response: '" << std::string(out, outlen) << "'");
+ return std::string(out, outlen);
+}
+
+std::string CyrusSasl::step(const std::string& challenge)
+{
+ sasl_interact_t* client_interact = 0;
+ const char *out = 0;
+ unsigned outlen = 0;
+ int result = 0;
+ do {
+ result = sasl_client_step(conn, /* our context */
+ challenge.data(), /* the data from the server */
+ challenge.size(), /* it's length */
+ &client_interact, /* this should be
+ unallocated and NULL */
+ &out, /* filled in on success */
+ &outlen); /* filled in on success */
+
+ if (result == SASL_INTERACT) {
+ interact(client_interact);
+ }
+ } while (result == SASL_INTERACT);
+
+ std::string response;
+ if (result == SASL_CONTINUE || result == SASL_OK) response = std::string(out, outlen);
+ else if (result != SASL_OK) {
+ throw InternalErrorException(QPID_MSG("Sasl error: " << sasl_errdetail(conn)));
+ }
+ QPID_LOG(debug, "CyrusSasl::step(" << challenge << "): " << response);
+ return response;
+}
+
+std::string CyrusSasl::getMechanism()
+{
+ return mechanism;
+}
+
+std::string CyrusSasl::getUserId()
+{
+ int propResult;
+ const void* operName;
+
+ propResult = sasl_getprop(conn, SASL_USERNAME, &operName);
+ if (propResult == SASL_OK)
+ return std::string((const char*) operName);
+
+ return std::string();
+}
+
+void CyrusSasl::interact(sasl_interact_t* client_interact)
+{
+
+ if (client_interact->id == SASL_CB_PASS) {
+ char* password = getpass(client_interact->prompt);
+ input = std::string(password);
+ client_interact->result = input.data();
+ client_interact->len = input.size();
+ } else {
+ std::cout << client_interact->prompt;
+ if (client_interact->defresult) std::cout << " (" << client_interact->defresult << ")";
+ std::cout << ": ";
+ if (std::cin >> input) {
+ client_interact->result = input.data();
+ client_interact->len = input.size();
+ }
+ }
+
+}
+
+std::auto_ptr<SecurityLayer> CyrusSasl::getSecurityLayer(uint16_t maxFrameSize)
+{
+ const void* value(0);
+ int result = sasl_getprop(conn, SASL_SSF, &value);
+ if (result != SASL_OK) {
+ throw framing::InternalErrorException(QPID_MSG("SASL error: " << sasl_errdetail(conn)));
+ }
+ uint ssf = *(reinterpret_cast<const unsigned*>(value));
+ std::auto_ptr<SecurityLayer> securityLayer;
+ if (ssf) {
+ QPID_LOG(info, "Installing security layer, SSF: "<< ssf);
+ securityLayer = std::auto_ptr<SecurityLayer>(new CyrusSecurityLayer(conn, maxFrameSize));
+ }
+ return securityLayer;
+}
+
+int getUserFromSettings(void* context, int /*id*/, const char** result, unsigned* /*len*/)
+{
+ if (context) {
+ *result = ((ConnectionSettings*) context)->username.c_str();
+ QPID_LOG(debug, "getUserFromSettings(): " << (*result));
+ return SASL_OK;
+ } else {
+ return SASL_FAIL;
+ }
+}
+
+namespace {
+// Global map of secrest allocated for SASL connections via callback
+// to getPasswordFromSettings. Ensures secrets are freed.
+class SecretsMap {
+ typedef std::map<sasl_conn_t*, void*> Map;
+ Map map;
+ public:
+ void keep(sasl_conn_t* conn, void* secret) {
+ Map::iterator i = map.find(conn);
+ if (i != map.end()) free(i->second);
+ map[conn] = secret;
+ }
+
+ ~SecretsMap() {
+ for (Map::iterator i = map.begin(); i != map.end(); ++i)
+ free(i->second);
+ }
+};
+SecretsMap getPasswordFromSettingsSecrets;
+}
+
+int getPasswordFromSettings(sasl_conn_t* conn, void* context, int /*id*/, sasl_secret_t** psecret)
+{
+ if (context) {
+ size_t length = ((ConnectionSettings*) context)->password.size();
+ sasl_secret_t* secret = (sasl_secret_t*) malloc(sizeof(sasl_secret_t) + length);
+ getPasswordFromSettingsSecrets.keep(conn, secret);
+ secret->len = length;
+ memcpy(secret->data, ((ConnectionSettings*) context)->password.data(), length);
+ *psecret = secret;
+ return SASL_OK;
+ } else {
+ return SASL_FAIL;
+ }
+}
+
+}} // namespace qpid::client
+
+#endif
diff --git a/cpp/src/qpid/client/SaslFactory.h b/cpp/src/qpid/client/SaslFactory.h
new file mode 100644
index 0000000000..d012af06f7
--- /dev/null
+++ b/cpp/src/qpid/client/SaslFactory.h
@@ -0,0 +1,48 @@
+#ifndef QPID_CLIENT_SASLFACTORY_H
+#define QPID_CLIENT_SASLFACTORY_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/Sasl.h"
+#include "qpid/sys/Mutex.h"
+#include <memory>
+
+namespace qpid {
+namespace client {
+
+/**
+ * Factory for instances of the Sasl interface through which Sasl
+ * support is provided to a ConnectionHandler.
+ */
+class SaslFactory
+{
+ public:
+ std::auto_ptr<Sasl> create(const ConnectionSettings&);
+ static SaslFactory& getInstance();
+ ~SaslFactory();
+ private:
+ SaslFactory();
+ static qpid::sys::Mutex lock;
+ static std::auto_ptr<SaslFactory> instance;
+};
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_SASLFACTORY_H*/
diff --git a/cpp/src/qpid/client/Session.h b/cpp/src/qpid/client/Session.h
deleted file mode 100644
index bdabd26c82..0000000000
--- a/cpp/src/qpid/client/Session.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef QPID_CLIENT_SESSION_H
-#define QPID_CLIENT_SESSION_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/client/Session_0_10.h"
-
-namespace qpid {
-namespace client {
-
-/**
- * Session is an alias for Session_0_10
- *
- * \ingroup clientapi
- */
-typedef Session_0_10 Session;
-
-
-}} // namespace qpid::client
-
-#endif /*!QPID_CLIENT_SESSION_H*/
diff --git a/cpp/src/qpid/client/SessionBase_0_10.cpp b/cpp/src/qpid/client/SessionBase_0_10.cpp
index 974acbfcf6..1a345d534e 100644
--- a/cpp/src/qpid/client/SessionBase_0_10.cpp
+++ b/cpp/src/qpid/client/SessionBase_0_10.cpp
@@ -18,21 +18,23 @@
* under the License.
*
*/
-#include "SessionBase_0_10.h"
+#include "qpid/client/SessionBase_0_10.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/SessionImpl.h"
+#include "qpid/client/Future.h"
#include "qpid/framing/all_method_bodies.h"
namespace qpid {
namespace client {
+
using namespace framing;
SessionBase_0_10::SessionBase_0_10() {}
SessionBase_0_10::~SessionBase_0_10() {}
-void SessionBase_0_10::close() { impl->close(); }
-
-Execution& SessionBase_0_10::getExecution()
-{
- return *impl;
+void SessionBase_0_10::close()
+{
+ if (impl) impl->close();
}
void SessionBase_0_10::flush()
@@ -47,6 +49,11 @@ void SessionBase_0_10::sync()
impl->send(b).wait(*impl);
}
+void SessionBase_0_10::markCompleted(const framing::SequenceSet& ids, bool notifyPeer)
+{
+ impl->markCompleted(ids, notifyPeer);
+}
+
void SessionBase_0_10::markCompleted(const framing::SequenceNumber& id, bool cumulative, bool notifyPeer)
{
impl->markCompleted(id, cumulative, notifyPeer);
@@ -57,8 +64,14 @@ void SessionBase_0_10::sendCompletion()
impl->sendCompletion();
}
+uint16_t SessionBase_0_10::getChannel() const { return impl->getChannel(); }
+
+void SessionBase_0_10::suspend() { impl->suspend(); }
+void SessionBase_0_10::resume(Connection c) { impl->resume(c.impl); }
+uint32_t SessionBase_0_10::timeout(uint32_t seconds) { return impl->setTimeout(seconds); }
+
SessionId SessionBase_0_10::getId() const { return impl->getId(); }
-framing::FrameSet::shared_ptr SessionBase_0_10::get() { return impl->get(); }
+bool SessionBase_0_10::isValid() const { return impl; }
}} // namespace qpid::client
diff --git a/cpp/src/qpid/client/SessionBase_0_10.h b/cpp/src/qpid/client/SessionBase_0_10.h
deleted file mode 100644
index 8634164dd1..0000000000
--- a/cpp/src/qpid/client/SessionBase_0_10.h
+++ /dev/null
@@ -1,106 +0,0 @@
-#ifndef QPID_CLIENT_SESSIONBASE_H
-#define QPID_CLIENT_SESSIONBASE_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/SessionId.h"
-#include "qpid/framing/amqp_structs.h"
-#include "qpid/framing/ProtocolVersion.h"
-#include "qpid/framing/MethodContent.h"
-#include "qpid/framing/TransferContent.h"
-#include "qpid/client/Completion.h"
-#include "qpid/client/ConnectionImpl.h"
-#include "qpid/client/Execution.h"
-#include "qpid/client/SessionImpl.h"
-#include "qpid/client/TypedResult.h"
-#include "qpid/shared_ptr.h"
-#include <string>
-
-namespace qpid {
-namespace client {
-
-using std::string;
-using framing::Content;
-using framing::FieldTable;
-using framing::MethodContent;
-using framing::SequenceNumber;
-using framing::SequenceSet;
-using framing::SequenceNumberSet;
-using qpid::SessionId;
-using framing::Xid;
-
-/** Unit of message credit: messages or bytes */
-enum CreditUnit { MESSAGE_CREDIT=0, BYTE_CREDIT=1, UNLIMITED_CREDIT=0xFFFFFFFF };
-
-/**
- * Base class for handles to an AMQP session.
- *
- * Subclasses provide the AMQP commands for a given
- * version of the protocol.
- */
-class SessionBase_0_10 {
- public:
-
- typedef framing::TransferContent DefaultContent;
-
- ///@internal
- SessionBase_0_10();
- ~SessionBase_0_10();
-
- /** Get the next message frame-set from the session. */
- framing::FrameSet::shared_ptr get();
-
- /** Get the session ID */
- SessionId getId() const;
-
- /** Close the session.
- * A session is automatically closed when all handles to it are destroyed.
- */
- void close();
-
- /**
- * Synchronize the session: sync() waits until all commands issued
- * on this session so far have been completed by the broker.
- *
- * Note sync() is always synchronous, even on an AsyncSession object
- * because that's almost always what you want. You can call
- * AsyncSession::executionSync() directly in the unusual event
- * that you want to do an asynchronous sync.
- */
- void sync();
-
- /** Set the timeout for this session. */
- uint32_t timeout(uint32_t seconds);
-
- Execution& getExecution();
- void flush();
- void markCompleted(const framing::SequenceNumber& id, bool cumulative, bool notifyPeer);
- void sendCompletion();
-
- protected:
- boost::shared_ptr<SessionImpl> impl;
- friend class SessionBase_0_10Access;
-};
-
-}} // namespace qpid::client
-
-#endif /*!QPID_CLIENT_SESSIONBASE_H*/
diff --git a/cpp/src/qpid/client/SessionBase_0_10Access.h b/cpp/src/qpid/client/SessionBase_0_10Access.h
index e2189a53dd..4d08a7ceaf 100644
--- a/cpp/src/qpid/client/SessionBase_0_10Access.h
+++ b/cpp/src/qpid/client/SessionBase_0_10Access.h
@@ -33,7 +33,7 @@ class SessionBase_0_10Access {
public:
SessionBase_0_10Access(SessionBase_0_10& sb_) : sb(sb_) {}
void set(const boost::shared_ptr<SessionImpl>& si) { sb.impl = si; }
- boost::shared_ptr<SessionImpl> get() { return sb.impl; }
+ boost::shared_ptr<SessionImpl> get() const { return sb.impl; }
private:
SessionBase_0_10& sb;
};
diff --git a/cpp/src/qpid/client/SessionImpl.cpp b/cpp/src/qpid/client/SessionImpl.cpp
index 2075ed04f3..0f767c9f2e 100644
--- a/cpp/src/qpid/client/SessionImpl.cpp
+++ b/cpp/src/qpid/client/SessionImpl.cpp
@@ -19,21 +19,25 @@
*
*/
-#include "SessionImpl.h"
+#include "qpid/client/SessionImpl.h"
-#include "ConnectionImpl.h"
-#include "Future.h"
+#include "qpid/client/ConnectionImpl.h"
+#include "qpid/client/Future.h"
#include "qpid/framing/all_method_bodies.h"
#include "qpid/framing/ClientInvoker.h"
-#include "qpid/framing/constants.h"
+#include "qpid/framing/enum.h"
#include "qpid/framing/FrameSet.h"
+#include "qpid/framing/AMQFrame.h"
#include "qpid/framing/MethodContent.h"
#include "qpid/framing/SequenceSet.h"
#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/DeliveryProperties.h"
#include "qpid/log/Statement.h"
+#include "qpid/sys/IntegerTypes.h"
#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
namespace { const std::string EMPTY; }
@@ -41,29 +45,26 @@ namespace qpid {
namespace client {
using namespace qpid::framing;
-using namespace qpid::framing::session;//for detach codes
+using namespace qpid::framing::session; //for detach codes
typedef sys::Monitor::ScopedLock Lock;
typedef sys::Monitor::ScopedUnlock UnLock;
typedef sys::ScopedLock<sys::Semaphore> Acquire;
-SessionImpl::SessionImpl(const std::string& name,
- shared_ptr<ConnectionImpl> conn,
- uint16_t ch, uint64_t _maxFrameSize)
- : error(OK),
- code(NORMAL),
- text(EMPTY),
- state(INACTIVE),
+SessionImpl::SessionImpl(const std::string& name, boost::shared_ptr<ConnectionImpl> conn)
+ : state(INACTIVE),
detachedLifetime(0),
- maxFrameSize(_maxFrameSize),
+ maxFrameSize(conn->getNegotiatedSettings().maxFrameSize),
id(conn->getNegotiatedSettings().username, name.empty() ? Uuid(true).str() : name),
connection(conn),
ioHandler(*this),
- channel(ch),
proxy(ioHandler),
nextIn(0),
- nextOut(0)
+ nextOut(0),
+ sendMsgCredit(0),
+ doClearDeliveryPropertiesExchange(true),
+ autoDetach(true)
{
channel.next = connection.get();
}
@@ -71,12 +72,18 @@ SessionImpl::SessionImpl(const std::string& name,
SessionImpl::~SessionImpl() {
{
Lock l(state);
- if (state != DETACHED) {
- QPID_LOG(error, "Session was not closed cleanly");
+ if (state != DETACHED && state != DETACHING) {
+ QPID_LOG(warning, "Session was not closed cleanly: " << id);
+ try {
+ // Inform broker but don't wait for detached as that deadlocks.
+ // The detached will be ignored as the channel will be invalid.
+ if (autoDetach) detach();
+ } catch (...) {} // ignore errors.
setState(DETACHED);
handleClosed();
state.waitWaiters();
}
+ delete sendMsgCredit;
}
connection->erase(channel);
}
@@ -102,7 +109,7 @@ void SessionImpl::open(uint32_t timeout) // user thread
waitFor(ATTACHED);
//TODO: timeout will not be set locally until get response to
//confirm, should we wait for that?
- proxy.requestTimeout(timeout);
+ setTimeout(timeout);
proxy.commandPoint(nextOut, 0);
} else {
throw Exception("Open already called for this session");
@@ -112,16 +119,18 @@ void SessionImpl::open(uint32_t timeout) // user thread
void SessionImpl::close() //user thread
{
Lock l(state);
- if (detachedLifetime) {
- proxy.requestTimeout(0);
- //should we wait for the timeout response?
- detachedLifetime = 0;
+ // close() must be idempotent and no-throw as it will often be called in destructors.
+ if (state != DETACHED && state != DETACHING) {
+ try {
+ if (detachedLifetime) setTimeout(0);
+ detach();
+ waitFor(DETACHED);
+ } catch (...) {}
+ setState(DETACHED);
}
- detach();
- waitFor(DETACHED);
}
-void SessionImpl::resume(shared_ptr<ConnectionImpl>) // user thread
+void SessionImpl::resume(boost::shared_ptr<ConnectionImpl>) // user thread
{
throw NotImplementedException("Resume not yet implemented by client!");
}
@@ -135,8 +144,8 @@ void SessionImpl::suspend() //user thread
void SessionImpl::detach() //call with lock held
{
if (state == ATTACHED) {
- proxy.detach(id.getName());
setState(DETACHING);
+ proxy.detach(id.getName());
}
}
@@ -201,6 +210,16 @@ bool SessionImpl::isCompleteUpTo(const SequenceNumber& id)
return f.result;
}
+framing::SequenceNumber SessionImpl::getCompleteUpTo()
+{
+ SequenceNumber firstIncomplete;
+ {
+ Lock l(state);
+ firstIncomplete = incompleteIn.front();
+ }
+ return --firstIncomplete;
+}
+
struct MarkCompleted
{
const SequenceNumber& id;
@@ -219,6 +238,16 @@ struct MarkCompleted
};
+void SessionImpl::markCompleted(const SequenceSet& ids, bool notifyPeer)
+{
+ Lock l(state);
+ incompleteIn.remove(ids);
+ completedIn.add(ids);
+ if (notifyPeer) {
+ sendCompletion();
+ }
+}
+
void SessionImpl::markCompleted(const SequenceNumber& id, bool cumulative, bool notifyPeer)
{
Lock l(state);
@@ -239,17 +268,22 @@ void SessionImpl::markCompleted(const SequenceNumber& id, bool cumulative, bool
}
}
+void SessionImpl::setException(const sys::ExceptionHolder& ex) {
+ Lock l(state);
+ setExceptionLH(ex);
+}
+
+void SessionImpl::setExceptionLH(const sys::ExceptionHolder& ex) { // Call with lock held.
+ exceptionHolder = ex;
+ setState(DETACHED);
+}
+
/**
* Called by ConnectionImpl to notify active sessions when connection
* is explictly closed
*/
-void SessionImpl::connectionClosed(uint16_t _code, const std::string& _text)
-{
- Lock l(state);
- error = CONNECTION_CLOSE;
- code = _code;
- text = _text;
- setState(DETACHED);
+void SessionImpl::connectionClosed(uint16_t code, const std::string& text) {
+ setException(createConnectionException(code, text));
handleClosed();
}
@@ -257,9 +291,9 @@ void SessionImpl::connectionClosed(uint16_t _code, const std::string& _text)
* Called by ConnectionImpl to notify active sessions when connection
* is disconnected
*/
-void SessionImpl::connectionBroke(uint16_t _code, const std::string& _text)
-{
- connectionClosed(_code, _text);
+void SessionImpl::connectionBroke(const std::string& _text) {
+ setException(sys::ExceptionHolder(new TransportFailure(_text)));
+ handleClosed();
}
Future SessionImpl::send(const AMQBody& command)
@@ -272,8 +306,76 @@ Future SessionImpl::send(const AMQBody& command, const MethodContent& content)
return sendCommand(command, &content);
}
+namespace {
+// Functor for FrameSet::map to send header + content frames but, not method frames.
+struct SendContentFn {
+ FrameHandler& handler;
+ void operator()(const AMQFrame& f) {
+ if (!f.getMethod())
+ handler(const_cast<AMQFrame&>(f));
+ }
+ SendContentFn(FrameHandler& h) : handler(h) {}
+};
+
+// Adaptor to make FrameSet look like MethodContent; used in cluster update client
+struct MethodContentAdaptor : MethodContent
+{
+ AMQHeaderBody header;
+ const std::string content;
+
+ MethodContentAdaptor(const FrameSet& f) : header(*f.getHeaders()), content(f.getContent()) {}
+
+ AMQHeaderBody getHeader() const
+ {
+ return header;
+ }
+ const std::string& getData() const
+ {
+ return content;
+ }
+};
+
+}
+
+Future SessionImpl::send(const AMQBody& command, const FrameSet& content, bool reframe) {
+ Acquire a(sendLock);
+ SequenceNumber id = nextOut++;
+ {
+ Lock l(state);
+ checkOpen();
+ incompleteOut.add(id);
+ }
+ Future f(id);
+ if (command.getMethod()->resultExpected()) {
+ Lock l(state);
+ //result listener must be set before the command is sent
+ f.setFutureResult(results.listenForResult(id));
+ }
+ AMQFrame frame(command);
+ frame.setEof(false);
+ handleOut(frame);
+
+ if (reframe) {
+ MethodContentAdaptor c(content);
+ sendContent(c);
+ } else {
+ SendContentFn send(out);
+ content.map(send);
+ }
+ return f;
+}
+
+void SessionImpl::sendRawFrame(AMQFrame& frame) {
+ Acquire a(sendLock);
+ handleOut(frame);
+}
+
Future SessionImpl::sendCommand(const AMQBody& command, const MethodContent* content)
{
+ // Only message transfers have content
+ if (content && sendMsgCredit) {
+ sendMsgCredit->acquire();
+ }
Acquire a(sendLock);
SequenceNumber id = nextOut++;
{
@@ -297,9 +399,21 @@ Future SessionImpl::sendCommand(const AMQBody& command, const MethodContent* con
}
return f;
}
+
void SessionImpl::sendContent(const MethodContent& content)
{
AMQFrame header(content.getHeader());
+
+ // doClearDeliveryPropertiesExchange is set by cluster update client so
+ // it can send messages with delivery-properties.exchange set.
+ //
+ if (doClearDeliveryPropertiesExchange) {
+ // Normal client is not allowed to set the delivery-properties.exchange
+ // so clear it here.
+ AMQHeaderBody* headerp = static_cast<AMQHeaderBody*>(header.getBody());
+ if (headerp && headerp->get<DeliveryProperties>())
+ headerp->get<DeliveryProperties>(true)->clearExchangeFlag();
+ }
header.setFirstSegment(false);
uint64_t data_length = content.getData().length();
if(data_length > 0){
@@ -309,7 +423,7 @@ void SessionImpl::sendContent(const MethodContent& content)
const uint32_t frag_size = maxFrameSize - AMQFrame::frameOverhead();
if(data_length < frag_size){
- AMQFrame frame(in_place<AMQContentBody>(content.getData()));
+ AMQFrame frame((AMQContentBody(content.getData())));
frame.setFirstSegment(false);
handleOut(frame);
}else{
@@ -318,7 +432,7 @@ void SessionImpl::sendContent(const MethodContent& content)
while (remaining > 0) {
uint32_t length = remaining > frag_size ? frag_size : remaining;
string frag(content.getData().substr(offset, length));
- AMQFrame frame(in_place<AMQContentBody>(frag));
+ AMQFrame frame((AMQContentBody(frag)));
frame.setFirstSegment(false);
frame.setLastSegment(true);
if (offset > 0) {
@@ -359,37 +473,45 @@ bool isContentFrame(AMQFrame& frame)
void SessionImpl::handleIn(AMQFrame& frame) // network thread
{
try {
- if (!invoke(static_cast<SessionHandler&>(*this), *frame.getBody())) {
- if (invoke(static_cast<ExecutionHandler&>(*this), *frame.getBody())) {
- //make sure the command id sequence and completion
- //tracking takes account of execution commands
- Lock l(state);
- completedIn.add(nextIn++);
- } else {
- //if not handled by this class, its for the application:
- deliver(frame);
- }
+ if (invoke(static_cast<SessionHandler&>(*this), *frame.getBody())) {
+ ;
+ } else if (invoke(static_cast<ExecutionHandler&>(*this), *frame.getBody())) {
+ //make sure the command id sequence and completion
+ //tracking takes account of execution commands
+ Lock l(state);
+ completedIn.add(nextIn++);
+ } else if (invoke(static_cast<MessageHandler&>(*this), *frame.getBody())) {
+ ;
+ } else {
+ //if not handled by this class, its for the application:
+ deliver(frame);
}
- } catch (const SessionException& e) {
- //TODO: proper 0-10 exception handling
- QPID_LOG(error, "Session exception:" << e.what());
- Lock l(state);
- error = EXCEPTION;
- code = e.code;
- text = e.what();
+ }
+ catch (const SessionException& e) {
+ setException(createSessionException(e.code, e.getMessage()));
+ }
+ catch (const ChannelException& e) {
+ setException(createChannelException(e.code, e.getMessage()));
}
}
void SessionImpl::handleOut(AMQFrame& frame) // user thread
{
- connection->expand(frame.size(), true);
- channel.handle(frame);
+ sendFrame(frame, true);
}
void SessionImpl::proxyOut(AMQFrame& frame) // network thread
{
- connection->expand(frame.size(), false);
+ //Note: this case is treated slightly differently that command
+ //frames sent by application; session controls should not be
+ //blocked by bounds checking on the outgoing frame queue.
+ sendFrame(frame, false);
+}
+
+void SessionImpl::sendFrame(AMQFrame& frame, bool canBlock)
+{
channel.handle(frame);
+ connection->expand(frame.encodedSize(), canBlock);
}
void SessionImpl::deliver(AMQFrame& frame) // network thread
@@ -435,24 +557,22 @@ void SessionImpl::detach(const std::string& _name)
if (id.getName() != _name) throw InternalErrorException("Incorrect session name");
setState(DETACHED);
QPID_LOG(info, "Session detached by peer: " << id);
+ proxy.detached(_name, DETACH_CODE_NORMAL);
}
-void SessionImpl::detached(const std::string& _name, uint8_t _code)
-{
+void SessionImpl::detached(const std::string& _name, uint8_t _code) {
Lock l(state);
if (id.getName() != _name) throw InternalErrorException("Incorrect session name");
setState(DETACHED);
if (_code) {
//TODO: make sure this works with execution.exception - don't
//want to overwrite the code from that
- QPID_LOG(error, "Session detached by peer: " << id << " " << code);
- error = SESSION_DETACH;
- code = _code;
- text = "Session detached by peer";
+ setExceptionLH(createChannelException(_code, "Session detached by peer"));
+ QPID_LOG(error, exceptionHolder.what());
}
if (detachedLifetime == 0) {
handleClosed();
- }
+}
}
void SessionImpl::requestTimeout(uint32_t t)
@@ -478,7 +598,7 @@ void SessionImpl::commandPoint(const framing::SequenceNumber& id, uint64_t offse
void SessionImpl::expected(const framing::SequenceSet& commands, const framing::Array& fragments)
{
- if (!commands.empty() || fragments.size()) {
+ if (!commands.empty() || fragments.encodedSize()) {
throw NotImplementedException("Session resumption not yet supported");
}
}
@@ -492,7 +612,7 @@ void SessionImpl::completed(const framing::SequenceSet& commands, bool timelyRep
{
Lock l(state);
incompleteOut.remove(commands);
- state.notify();//notify any waiters of completion
+ state.notifyAll();//notify any waiters of completion
completedOut.add(commands);
//notify any waiting results of completion
results.completed(commands);
@@ -561,20 +681,78 @@ void SessionImpl::exception(uint16_t errorCode,
const std::string& description,
const framing::FieldTable& /*errorInfo*/)
{
- QPID_LOG(warning, "Exception received from peer: " << errorCode << ":" << description
+ Lock l(state);
+ setExceptionLH(createSessionException(errorCode, description));
+ QPID_LOG(warning, "Exception received from broker: " << exceptionHolder.what()
<< " [caused by " << commandId << " " << classCode << ":" << commandCode << "]");
+ if (detachedLifetime)
+ setTimeout(0);
+}
+
+// Message methods:
+void SessionImpl::accept(const qpid::framing::SequenceSet&)
+{
+}
+
+void SessionImpl::reject(const qpid::framing::SequenceSet&, uint16_t, const std::string&)
+{
+}
+
+void SessionImpl::release(const qpid::framing::SequenceSet&, bool)
+{
+}
+
+MessageResumeResult SessionImpl::resume(const std::string&, const std::string&)
+{
+ throw NotImplementedException("resuming transfers not yet supported");
+}
+
+namespace {
+ const std::string QPID_SESSION_DEST = "";
+ const uint8_t FLOW_MODE_CREDIT = 0;
+ const uint8_t CREDIT_MODE_MSG = 0;
+}
+
+void SessionImpl::setFlowMode(const std::string& dest, uint8_t flowMode)
+{
+ if ( dest != QPID_SESSION_DEST ) {
+ QPID_LOG(warning, "Ignoring flow control for unknown destination: " << dest);
+ return;
+ }
+
+ if ( flowMode != FLOW_MODE_CREDIT ) {
+ throw NotImplementedException("window flow control mode not supported by producer");
+ }
Lock l(state);
- error = EXCEPTION;
- code = errorCode;
- text = description;
- if (detachedLifetime) {
- proxy.requestTimeout(0);
- //should we wait for the timeout response?
- detachedLifetime = 0;
+ sendMsgCredit = new sys::Semaphore(0);
+}
+
+void SessionImpl::flow(const std::string& dest, uint8_t mode, uint32_t credit)
+{
+ if ( dest != QPID_SESSION_DEST ) {
+ QPID_LOG(warning, "Ignoring flow control for unknown destination: " << dest);
+ return;
+ }
+
+ if ( mode != CREDIT_MODE_MSG ) {
+ return;
+ }
+ if (sendMsgCredit) {
+ sendMsgCredit->release(credit);
}
}
+void SessionImpl::stop(const std::string& dest)
+{
+ if ( dest != QPID_SESSION_DEST ) {
+ QPID_LOG(warning, "Ignoring flow control for unknown destination: " << dest);
+ return;
+ }
+ if (sendMsgCredit) {
+ sendMsgCredit->forceLock();
+ }
+}
//private utility methods:
@@ -586,25 +764,21 @@ inline void SessionImpl::setState(State s) //call with lock held
inline void SessionImpl::waitFor(State s) //call with lock held
{
// We can be DETACHED at any time
- state.waitFor(States(s, DETACHED));
+ if (s == DETACHED) state.waitFor(DETACHED);
+ else state.waitFor(States(s, DETACHED));
check();
}
void SessionImpl::check() const //call with lock held.
{
- switch (error) {
- case OK: break;
- case CONNECTION_CLOSE: throw ConnectionException(code, text);
- case SESSION_DETACH: throw ChannelException(code, text);
- case EXCEPTION: throwExecutionException(code, text);
- }
+ exceptionHolder.raise();
}
void SessionImpl::checkOpen() const //call with lock held.
{
check();
if (state != ATTACHED) {
- throw NotAttachedException("Session isn't attached");
+ throw NotAttachedException(QPID_MSG("Session " << getId() << " isn't attached"));
}
}
@@ -616,10 +790,28 @@ void SessionImpl::assertOpen() const
void SessionImpl::handleClosed()
{
- // FIXME aconway 2008-06-12: needs to be set to the correct exception type.
- //
- demux.close(sys::ExceptionHolder(text.empty() ? new ClosedException() : new Exception(text)));
+ demux.close(exceptionHolder.empty() ?
+ sys::ExceptionHolder(new ClosedException()) : exceptionHolder);
results.close();
}
+uint32_t SessionImpl::setTimeout(uint32_t seconds) {
+ proxy.requestTimeout(seconds);
+ // FIXME aconway 2008-10-07: wait for timeout response from broker
+ // and use value retured by broker.
+ detachedLifetime = seconds;
+ return detachedLifetime;
+}
+
+uint32_t SessionImpl::getTimeout() const {
+ return detachedLifetime;
+}
+
+boost::shared_ptr<ConnectionImpl> SessionImpl::getConnection()
+{
+ return connection;
+}
+
+void SessionImpl::disableAutoDetach() { autoDetach = false; }
+
}}
diff --git a/cpp/src/qpid/client/SessionImpl.h b/cpp/src/qpid/client/SessionImpl.h
index 55031a94ae..2f35032c4e 100644
--- a/cpp/src/qpid/client/SessionImpl.h
+++ b/cpp/src/qpid/client/SessionImpl.h
@@ -22,12 +22,13 @@
#ifndef _SessionImpl_
#define _SessionImpl_
-#include "Demux.h"
-#include "Execution.h"
-#include "Results.h"
+#include "qpid/client/Demux.h"
+#include "qpid/client/Execution.h"
+#include "qpid/client/Results.h"
+#include "qpid/client/ClientImportExport.h"
#include "qpid/SessionId.h"
-#include "qpid/shared_ptr.h"
+#include "qpid/SessionState.h"
#include "qpid/framing/FrameHandler.h"
#include "qpid/framing/ChannelHandler.h"
#include "qpid/framing/SequenceNumber.h"
@@ -35,7 +36,10 @@
#include "qpid/framing/AMQP_ServerProxy.h"
#include "qpid/sys/Semaphore.h"
#include "qpid/sys/StateMonitor.h"
+#include "qpid/sys/ExceptionHolder.h"
+#include <boost/weak_ptr.hpp>
+#include <boost/shared_ptr.hpp>
#include <boost/optional.hpp>
namespace qpid {
@@ -52,15 +56,17 @@ namespace client {
class Future;
class ConnectionImpl;
+class SessionHandler;
///@internal
class SessionImpl : public framing::FrameHandler::InOutHandler,
public Execution,
private framing::AMQP_ClientOperations::SessionHandler,
- private framing::AMQP_ClientOperations::ExecutionHandler
+ private framing::AMQP_ClientOperations::ExecutionHandler,
+ private framing::AMQP_ClientOperations::MessageHandler
{
public:
- SessionImpl(const std::string& name, shared_ptr<ConnectionImpl>, uint16_t channel, uint64_t maxFrameSize);
+ SessionImpl(const std::string& name, boost::shared_ptr<ConnectionImpl>);
~SessionImpl();
@@ -74,33 +80,57 @@ public:
void open(uint32_t detachedLifetime);
void close();
- void resume(shared_ptr<ConnectionImpl>);
+ void resume(boost::shared_ptr<ConnectionImpl>);
void suspend();
void assertOpen() const;
Future send(const framing::AMQBody& command);
Future send(const framing::AMQBody& command, const framing::MethodContent& content);
+ /**
+ * This method takes the content as a FrameSet; if reframe=false,
+ * the caller is resposnible for ensuring that the header and
+ * content frames in that set are correct for this connection
+ * (right flags, right fragmentation etc). If reframe=true, then
+ * the header and content from the frameset will be copied and
+ * reframed correctly for the connection.
+ */
+ QPID_CLIENT_EXTERN Future send(const framing::AMQBody& command, const framing::FrameSet& content, bool reframe=false);
+ void sendRawFrame(framing::AMQFrame& frame);
Demux& getDemux();
void markCompleted(const framing::SequenceNumber& id, bool cumulative, bool notifyPeer);
+ void markCompleted(const framing::SequenceSet& ids, bool notifyPeer);
bool isComplete(const framing::SequenceNumber& id);
bool isCompleteUpTo(const framing::SequenceNumber& id);
+ framing::SequenceNumber getCompleteUpTo();
void waitForCompletion(const framing::SequenceNumber& id);
void sendCompletion();
void sendFlush();
+ void setException(const sys::ExceptionHolder&);
+
//NOTE: these are called by the network thread when the connection is closed or dies
void connectionClosed(uint16_t code, const std::string& text);
- void connectionBroke(uint16_t code, const std::string& text);
+ void connectionBroke(const std::string& text);
+
+ /** Set timeout in seconds, returns actual timeout allowed by broker */
+ uint32_t setTimeout(uint32_t requestedSeconds);
+
+ /** Get timeout in seconds. */
+ uint32_t getTimeout() const;
+
+ /**
+ * get the Connection associated with this connection
+ */
+ boost::shared_ptr<ConnectionImpl> getConnection();
+
+ void setDoClearDeliveryPropertiesExchange(bool b=true) { doClearDeliveryPropertiesExchange = b; }
+
+ /** Suppress sending detach in destructor. Used by cluster to build session state */
+ void disableAutoDetach();
private:
- enum ErrorType {
- OK,
- CONNECTION_CLOSE,
- SESSION_DETACH,
- EXCEPTION
- };
enum State {
INACTIVE,
ATTACHING,
@@ -110,12 +140,14 @@ private:
};
typedef framing::AMQP_ClientOperations::SessionHandler SessionHandler;
typedef framing::AMQP_ClientOperations::ExecutionHandler ExecutionHandler;
+ typedef framing::AMQP_ClientOperations::MessageHandler MessageHandler;
typedef sys::StateMonitor<State, DETACHED> StateMonitor;
typedef StateMonitor::Set States;
inline void setState(State s);
inline void waitFor(State);
+ void setExceptionLH(const sys::ExceptionHolder&); // LH = lock held when called.
void detach();
void check() const;
@@ -124,13 +156,19 @@ private:
void handleIn(framing::AMQFrame& frame);
void handleOut(framing::AMQFrame& frame);
+ /**
+ * Sends session controls. This case is treated slightly
+ * differently than command frames sent by the application via
+ * handleOut(); session controlsare not subject to bounds checking
+ * on the outgoing frame queue.
+ */
void proxyOut(framing::AMQFrame& frame);
+ void sendFrame(framing::AMQFrame& frame, bool canBlock);
void deliver(framing::AMQFrame& frame);
Future sendCommand(const framing::AMQBody&, const framing::MethodContent* = 0);
void sendContent(const framing::MethodContent&);
void waitForCompletionImpl(const framing::SequenceNumber& id);
- void requestTimeout(uint32_t timeout);
void sendCompletionImpl();
@@ -139,7 +177,8 @@ private:
void attach(const std::string& name, bool force);
void attached(const std::string& name);
void detach(const std::string& name);
- void detached(const std::string& name, uint8_t detachCode);
+ void detached(const std::string& name, uint8_t detachCode);
+ void requestTimeout(uint32_t timeout);
void timeout(uint32_t timeout);
void commandPoint(const framing::SequenceNumber& commandId, uint64_t commandOffset);
void expected(const framing::SequenceSet& commands, const framing::Array& fragments);
@@ -160,17 +199,28 @@ private:
uint8_t fieldIndex,
const std::string& description,
const framing::FieldTable& errorInfo);
-
- ErrorType error;
- int code; // Error code
- std::string text; // Error text
+
+ // Note: Following methods are called by network thread in
+ // response to message commands from the broker
+ // EXCEPT Message.Transfer
+ void accept(const qpid::framing::SequenceSet&);
+ void reject(const qpid::framing::SequenceSet&, uint16_t, const std::string&);
+ void release(const qpid::framing::SequenceSet&, bool);
+ qpid::framing::MessageResumeResult resume(const std::string&, const std::string&);
+ void setFlowMode(const std::string&, uint8_t);
+ void flow(const std::string&, uint8_t, uint32_t);
+ void stop(const std::string&);
+
+
+ sys::ExceptionHolder exceptionHolder;
mutable StateMonitor state;
mutable sys::Semaphore sendLock;
uint32_t detachedLifetime;
const uint64_t maxFrameSize;
const SessionId id;
- shared_ptr<ConnectionImpl> connection;
+ boost::shared_ptr<ConnectionImpl> connection;
+
framing::FrameHandler::MemFunRef<SessionImpl, &SessionImpl::proxyOut> ioHandler;
framing::ChannelHandler channel;
framing::AMQP_ServerProxy::Session proxy;
@@ -186,6 +236,16 @@ private:
framing::SequenceNumber nextIn;
framing::SequenceNumber nextOut;
+ SessionState sessionState;
+
+ // Only keep track of message credit
+ sys::Semaphore* sendMsgCredit;
+
+ bool doClearDeliveryPropertiesExchange;
+
+ bool autoDetach;
+
+ friend class client::SessionHandler;
};
}} // namespace qpid::client
diff --git a/cpp/src/qpid/client/SslConnector.cpp b/cpp/src/qpid/client/SslConnector.cpp
new file mode 100644
index 0000000000..5cdaaa4615
--- /dev/null
+++ b/cpp/src/qpid/client/SslConnector.cpp
@@ -0,0 +1,400 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/client/Connector.h"
+
+#include "config.h"
+#include "qpid/client/Bounds.h"
+#include "qpid/client/ConnectionImpl.h"
+#include "qpid/client/ConnectionSettings.h"
+#include "qpid/Options.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/Time.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/sys/ssl/util.h"
+#include "qpid/sys/ssl/SslIo.h"
+#include "qpid/sys/ssl/SslSocket.h"
+#include "qpid/sys/Dispatcher.h"
+#include "qpid/sys/Poller.h"
+#include "qpid/Msg.h"
+
+#include <iostream>
+#include <map>
+#include <boost/bind.hpp>
+#include <boost/format.hpp>
+
+namespace qpid {
+namespace client {
+
+using namespace qpid::sys;
+using namespace qpid::sys::ssl;
+using namespace qpid::framing;
+using boost::format;
+using boost::str;
+
+
+class SslConnector : public Connector, private sys::Runnable
+{
+ struct Buff;
+
+ /** Batch up frames for writing to aio. */
+ class Writer : public framing::FrameHandler {
+ typedef sys::ssl::SslIOBufferBase BufferBase;
+ typedef std::vector<framing::AMQFrame> Frames;
+
+ const uint16_t maxFrameSize;
+ sys::Mutex lock;
+ sys::ssl::SslIO* aio;
+ BufferBase* buffer;
+ Frames frames;
+ size_t lastEof; // Position after last EOF in frames
+ framing::Buffer encode;
+ size_t framesEncoded;
+ std::string identifier;
+ Bounds* bounds;
+
+ void writeOne();
+ void newBuffer();
+
+ public:
+
+ Writer(uint16_t maxFrameSize, Bounds*);
+ ~Writer();
+ void init(std::string id, sys::ssl::SslIO*);
+ void handle(framing::AMQFrame&);
+ void write(sys::ssl::SslIO&);
+ };
+
+ const uint16_t maxFrameSize;
+ framing::ProtocolVersion version;
+ bool initiated;
+
+ sys::Mutex closedLock;
+ bool closed;
+ bool joined;
+
+ sys::ShutdownHandler* shutdownHandler;
+ framing::InputHandler* input;
+ framing::InitiationHandler* initialiser;
+ framing::OutputHandler* output;
+
+ Writer writer;
+
+ sys::Thread receiver;
+
+ sys::ssl::SslSocket socket;
+
+ sys::ssl::SslIO* aio;
+ boost::shared_ptr<sys::Poller> poller;
+
+ ~SslConnector();
+
+ void run();
+ void handleClosed();
+ bool closeInternal();
+
+ void readbuff(qpid::sys::ssl::SslIO&, qpid::sys::ssl::SslIOBufferBase*);
+ void writebuff(qpid::sys::ssl::SslIO&);
+ void writeDataBlock(const framing::AMQDataBlock& data);
+ void eof(qpid::sys::ssl::SslIO&);
+
+ std::string identifier;
+
+ ConnectionImpl* impl;
+
+ void connect(const std::string& host, int port);
+ void init();
+ void close();
+ void send(framing::AMQFrame& frame);
+ void abort() {} // TODO: Need to fix for heartbeat timeouts to work
+
+ void setInputHandler(framing::InputHandler* handler);
+ void setShutdownHandler(sys::ShutdownHandler* handler);
+ sys::ShutdownHandler* getShutdownHandler() const;
+ framing::OutputHandler* getOutputHandler();
+ const std::string& getIdentifier() const;
+
+public:
+ SslConnector(framing::ProtocolVersion pVersion,
+ const ConnectionSettings&,
+ ConnectionImpl*);
+ unsigned int getSSF() { return socket.getKeyLen(); }
+};
+
+// Static constructor which registers connector here
+namespace {
+ Connector* create(framing::ProtocolVersion v, const ConnectionSettings& s, ConnectionImpl* c) {
+ return new SslConnector(v, s, c);
+ }
+
+ struct StaticInit {
+ StaticInit() {
+ try {
+ SslOptions options;
+ options.parse (0, 0, QPIDC_CONF_FILE, true);
+ if (options.certDbPath.empty()) {
+ QPID_LOG(info, "SSL connector not enabled, you must set QPID_SSL_CERT_DB to enable it.");
+ } else {
+ initNSS(options);
+ Connector::registerFactory("ssl", &create);
+ }
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Failed to initialise SSL connector: " << e.what());
+ }
+ };
+
+ ~StaticInit() { shutdownNSS(); }
+ } init;
+}
+
+SslConnector::SslConnector(ProtocolVersion ver,
+ const ConnectionSettings& settings,
+ ConnectionImpl* cimpl)
+ : maxFrameSize(settings.maxFrameSize),
+ version(ver),
+ initiated(false),
+ closed(true),
+ joined(true),
+ shutdownHandler(0),
+ writer(maxFrameSize, cimpl),
+ aio(0),
+ impl(cimpl)
+{
+ QPID_LOG(debug, "SslConnector created for " << version.toString());
+ //TODO: how do we want to handle socket configuration with ssl?
+ //settings.configureSocket(socket);
+}
+
+SslConnector::~SslConnector() {
+ close();
+}
+
+void SslConnector::connect(const std::string& host, int port){
+ Mutex::ScopedLock l(closedLock);
+ assert(closed);
+ try {
+ socket.connect(host, port);
+ } catch (const std::exception& e) {
+ socket.close();
+ throw;
+ }
+
+ identifier = str(format("[%1% %2%]") % socket.getLocalPort() % socket.getPeerAddress());
+ closed = false;
+ poller = Poller::shared_ptr(new Poller);
+ aio = new SslIO(socket,
+ boost::bind(&SslConnector::readbuff, this, _1, _2),
+ boost::bind(&SslConnector::eof, this, _1),
+ boost::bind(&SslConnector::eof, this, _1),
+ 0, // closed
+ 0, // nobuffs
+ boost::bind(&SslConnector::writebuff, this, _1));
+ writer.init(identifier, aio);
+}
+
+void SslConnector::init(){
+ Mutex::ScopedLock l(closedLock);
+ assert(joined);
+ ProtocolInitiation init(version);
+ writeDataBlock(init);
+ joined = false;
+ receiver = Thread(this);
+}
+
+bool SslConnector::closeInternal() {
+ Mutex::ScopedLock l(closedLock);
+ bool ret = !closed;
+ if (!closed) {
+ closed = true;
+ aio->queueForDeletion();
+ poller->shutdown();
+ }
+ if (!joined && receiver.id() != Thread::current().id()) {
+ joined = true;
+ Mutex::ScopedUnlock u(closedLock);
+ receiver.join();
+ }
+ return ret;
+}
+
+void SslConnector::close() {
+ closeInternal();
+}
+
+void SslConnector::setInputHandler(InputHandler* handler){
+ input = handler;
+}
+
+void SslConnector::setShutdownHandler(ShutdownHandler* handler){
+ shutdownHandler = handler;
+}
+
+OutputHandler* SslConnector::getOutputHandler() {
+ return this;
+}
+
+sys::ShutdownHandler* SslConnector::getShutdownHandler() const {
+ return shutdownHandler;
+}
+
+const std::string& SslConnector::getIdentifier() const {
+ return identifier;
+}
+
+void SslConnector::send(AMQFrame& frame) {
+ writer.handle(frame);
+}
+
+void SslConnector::handleClosed() {
+ if (closeInternal() && shutdownHandler)
+ shutdownHandler->shutdown();
+}
+
+struct SslConnector::Buff : public SslIO::BufferBase {
+ Buff(size_t size) : SslIO::BufferBase(new char[size], size) {}
+ ~Buff() { delete [] bytes;}
+};
+
+SslConnector::Writer::Writer(uint16_t s, Bounds* b) : maxFrameSize(s), aio(0), buffer(0), lastEof(0), bounds(b)
+{
+}
+
+SslConnector::Writer::~Writer() { delete buffer; }
+
+void SslConnector::Writer::init(std::string id, sys::ssl::SslIO* a) {
+ Mutex::ScopedLock l(lock);
+ identifier = id;
+ aio = a;
+ newBuffer();
+}
+void SslConnector::Writer::handle(framing::AMQFrame& frame) {
+ Mutex::ScopedLock l(lock);
+ frames.push_back(frame);
+ if (frame.getEof() || (bounds && bounds->getCurrentSize() >= maxFrameSize)) {
+ lastEof = frames.size();
+ aio->notifyPendingWrite();
+ }
+ QPID_LOG(trace, "SENT " << identifier << ": " << frame);
+}
+
+void SslConnector::Writer::writeOne() {
+ assert(buffer);
+ framesEncoded = 0;
+
+ buffer->dataStart = 0;
+ buffer->dataCount = encode.getPosition();
+ aio->queueWrite(buffer);
+ newBuffer();
+}
+
+void SslConnector::Writer::newBuffer() {
+ buffer = aio->getQueuedBuffer();
+ if (!buffer) buffer = new Buff(maxFrameSize);
+ encode = framing::Buffer(buffer->bytes, buffer->byteCount);
+ framesEncoded = 0;
+}
+
+// Called in IO thread.
+void SslConnector::Writer::write(sys::ssl::SslIO&) {
+ Mutex::ScopedLock l(lock);
+ assert(buffer);
+ size_t bytesWritten(0);
+ for (size_t i = 0; i < lastEof; ++i) {
+ AMQFrame& frame = frames[i];
+ uint32_t size = frame.encodedSize();
+ if (size > encode.available()) writeOne();
+ assert(size <= encode.available());
+ frame.encode(encode);
+ ++framesEncoded;
+ bytesWritten += size;
+ }
+ frames.erase(frames.begin(), frames.begin()+lastEof);
+ lastEof = 0;
+ if (bounds) bounds->reduce(bytesWritten);
+ if (encode.getPosition() > 0) writeOne();
+}
+
+void SslConnector::readbuff(SslIO& aio, SslIO::BufferBase* buff) {
+ framing::Buffer in(buff->bytes+buff->dataStart, buff->dataCount);
+
+ if (!initiated) {
+ framing::ProtocolInitiation protocolInit;
+ if (protocolInit.decode(in)) {
+ //TODO: check the version is correct
+ QPID_LOG(debug, "RECV " << identifier << " INIT(" << protocolInit << ")");
+ }
+ initiated = true;
+ }
+ AMQFrame frame;
+ while(frame.decode(in)){
+ QPID_LOG(trace, "RECV " << identifier << ": " << frame);
+ input->received(frame);
+ }
+ // TODO: unreading needs to go away, and when we can cope
+ // with multiple sub-buffers in the general buffer scheme, it will
+ if (in.available() != 0) {
+ // Adjust buffer for used bytes and then "unread them"
+ buff->dataStart += buff->dataCount-in.available();
+ buff->dataCount = in.available();
+ aio.unread(buff);
+ } else {
+ // Give whole buffer back to aio subsystem
+ aio.queueReadBuffer(buff);
+ }
+}
+
+void SslConnector::writebuff(SslIO& aio_) {
+ writer.write(aio_);
+}
+
+void SslConnector::writeDataBlock(const AMQDataBlock& data) {
+ SslIO::BufferBase* buff = new Buff(maxFrameSize);
+ framing::Buffer out(buff->bytes, buff->byteCount);
+ data.encode(out);
+ buff->dataCount = data.encodedSize();
+ aio->queueWrite(buff);
+}
+
+void SslConnector::eof(SslIO&) {
+ handleClosed();
+}
+
+void SslConnector::run(){
+ // Keep the connection impl in memory until run() completes.
+ boost::shared_ptr<ConnectionImpl> protect = impl->shared_from_this();
+ assert(protect);
+ try {
+ Dispatcher d(poller);
+
+ for (int i = 0; i < 32; i++) {
+ aio->queueReadBuffer(new Buff(maxFrameSize));
+ }
+
+ aio->start(poller);
+ d.run();
+ socket.close();
+ } catch (const std::exception& e) {
+ QPID_LOG(error, e.what());
+ handleClosed();
+ }
+}
+
+
+}} // namespace qpid::client
diff --git a/cpp/src/qpid/client/StateManager.cpp b/cpp/src/qpid/client/StateManager.cpp
index 0cb3c6b9d4..5462e0fed4 100644
--- a/cpp/src/qpid/client/StateManager.cpp
+++ b/cpp/src/qpid/client/StateManager.cpp
@@ -19,7 +19,7 @@
*
*/
-#include "StateManager.h"
+#include "qpid/client/StateManager.h"
#include "qpid/framing/amqp_framing.h"
using namespace qpid::client;
@@ -60,6 +60,18 @@ void StateManager::setState(int s)
stateLock.notifyAll();
}
+bool StateManager::setState(int s, int expected)
+{
+ Monitor::ScopedLock l(stateLock);
+ if (state == expected) {
+ state = s;
+ stateLock.notifyAll();
+ return true;
+ } else {
+ return false;
+ }
+}
+
int StateManager::getState() const
{
Monitor::ScopedLock l(stateLock);
diff --git a/cpp/src/qpid/client/StateManager.h b/cpp/src/qpid/client/StateManager.h
index b01664a0c1..3c8412dfa7 100644
--- a/cpp/src/qpid/client/StateManager.h
+++ b/cpp/src/qpid/client/StateManager.h
@@ -36,6 +36,7 @@ class StateManager
public:
StateManager(int initial);
void setState(int state);
+ bool setState(int state, int expected);
int getState() const ;
void waitForStateChange(int current);
void waitFor(std::set<int> states);
diff --git a/cpp/src/qpid/client/Subscription.cpp b/cpp/src/qpid/client/Subscription.cpp
new file mode 100644
index 0000000000..988f372604
--- /dev/null
+++ b/cpp/src/qpid/client/Subscription.cpp
@@ -0,0 +1,55 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/Subscription.h"
+#include "qpid/client/SubscriptionImpl.h"
+#include "qpid/client/CompletionImpl.h"
+#include "qpid/client/PrivateImplRef.h"
+#include "qpid/framing/enum.h"
+
+namespace qpid {
+namespace client {
+
+typedef PrivateImplRef<Subscription> PI;
+Subscription::Subscription(SubscriptionImpl* p) { PI::ctor(*this, p); }
+Subscription::~Subscription() { PI::dtor(*this); }
+Subscription::Subscription(const Subscription& c) : Handle<SubscriptionImpl>() { PI::copy(*this, c); }
+Subscription& Subscription::operator=(const Subscription& c) { return PI::assign(*this, c); }
+
+
+std::string Subscription::getName() const { return impl->getName(); }
+std::string Subscription::getQueue() const { return impl->getQueue(); }
+const SubscriptionSettings& Subscription::getSettings() const { return impl->getSettings(); }
+void Subscription::setFlowControl(const FlowControl& f) { impl->setFlowControl(f); }
+void Subscription::setAutoAck(unsigned int n) { impl->setAutoAck(n); }
+SequenceSet Subscription::getUnacquired() const { return impl->getUnacquired(); }
+SequenceSet Subscription::getUnaccepted() const { return impl->getUnaccepted(); }
+void Subscription::acquire(const SequenceSet& messageIds) { impl->acquire(messageIds); }
+void Subscription::accept(const SequenceSet& messageIds) { impl->accept(messageIds); }
+void Subscription::release(const SequenceSet& messageIds) { impl->release(messageIds); }
+Session Subscription::getSession() const { return impl->getSession(); }
+SubscriptionManager Subscription::getSubscriptionManager() { return impl->getSubscriptionManager(); }
+void Subscription::cancel() { impl->cancel(); }
+void Subscription::grantMessageCredit(uint32_t value) { impl->grantCredit(framing::message::CREDIT_UNIT_MESSAGE, value); }
+void Subscription::grantByteCredit(uint32_t value) { impl->grantCredit(framing::message::CREDIT_UNIT_BYTE, value); }
+}} // namespace qpid::client
+
+
diff --git a/cpp/src/qpid/client/SubscriptionImpl.cpp b/cpp/src/qpid/client/SubscriptionImpl.cpp
new file mode 100644
index 0000000000..a8a0b47d94
--- /dev/null
+++ b/cpp/src/qpid/client/SubscriptionImpl.cpp
@@ -0,0 +1,169 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/client/AsyncSession.h"
+#include "qpid/client/SubscriptionImpl.h"
+#include "qpid/client/SessionImpl.h"
+#include "qpid/client/SubscriptionManagerImpl.h"
+#include "qpid/client/MessageImpl.h"
+#include "qpid/client/CompletionImpl.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/SubscriptionSettings.h"
+#include "qpid/client/SessionBase_0_10Access.h"
+#include "qpid/client/PrivateImplRef.h"
+
+namespace qpid {
+namespace client {
+
+using sys::Mutex;
+using framing::MessageAcquireResult;
+
+SubscriptionImpl::SubscriptionImpl(SubscriptionManager m, const std::string& q, const SubscriptionSettings& s, const std::string& n, MessageListener* l)
+ : manager(*PrivateImplRef<SubscriptionManager>::get(m)), name(n), queue(q), settings(s), listener(l)
+{}
+
+void SubscriptionImpl::subscribe()
+{
+ async(manager.getSession()).messageSubscribe(
+ arg::queue=queue,
+ arg::destination=name,
+ arg::acceptMode=settings.acceptMode,
+ arg::acquireMode=settings.acquireMode,
+ arg::exclusive=settings.exclusive);
+ setFlowControl(settings.flowControl);
+}
+
+std::string SubscriptionImpl::getName() const { return name; }
+
+std::string SubscriptionImpl::getQueue() const { return queue; }
+
+const SubscriptionSettings& SubscriptionImpl::getSettings() const {
+ Mutex::ScopedLock l(lock);
+ return settings;
+}
+
+void SubscriptionImpl::setFlowControl(const FlowControl& f) {
+ Mutex::ScopedLock l(lock);
+ AsyncSession s=manager.getSession();
+ if (&settings.flowControl != &f) settings.flowControl = f;
+ s.messageSetFlowMode(name, f.window);
+ s.messageFlow(name, CREDIT_UNIT_MESSAGE, f.messages);
+ s.messageFlow(name, CREDIT_UNIT_BYTE, f.bytes);
+ s.sync();
+}
+
+void SubscriptionImpl::grantCredit(framing::message::CreditUnit unit, uint32_t value) {
+ async(manager.getSession()).messageFlow(name, unit, value);
+}
+
+void SubscriptionImpl::setAutoAck(size_t n) {
+ Mutex::ScopedLock l(lock);
+ settings.autoAck = n;
+}
+
+SequenceSet SubscriptionImpl::getUnacquired() const { Mutex::ScopedLock l(lock); return unacquired; }
+SequenceSet SubscriptionImpl::getUnaccepted() const { Mutex::ScopedLock l(lock); return unaccepted; }
+
+void SubscriptionImpl::acquire(const SequenceSet& messageIds) {
+ Mutex::ScopedLock l(lock);
+ MessageAcquireResult result = manager.getSession().messageAcquire(messageIds);
+ unacquired.remove(result.getTransfers());
+ if (settings.acceptMode == ACCEPT_MODE_EXPLICIT)
+ unaccepted.add(result.getTransfers());
+}
+
+void SubscriptionImpl::accept(const SequenceSet& messageIds) {
+ Mutex::ScopedLock l(lock);
+ manager.getSession().messageAccept(messageIds);
+ unaccepted.remove(messageIds);
+ switch (settings.completionMode) {
+ case COMPLETE_ON_ACCEPT:
+ manager.getSession().markCompleted(messageIds, true);
+ break;
+ case COMPLETE_ON_DELIVERY:
+ manager.getSession().sendCompletion();
+ break;
+ default://do nothing
+ break;
+ }
+}
+
+void SubscriptionImpl::release(const SequenceSet& messageIds) {
+ Mutex::ScopedLock l(lock);
+ manager.getSession().messageRelease(messageIds);
+ if (settings.acceptMode == ACCEPT_MODE_EXPLICIT)
+ unaccepted.remove(messageIds);
+}
+
+Session SubscriptionImpl::getSession() const { return manager.getSession(); }
+
+SubscriptionManager SubscriptionImpl::getSubscriptionManager() { return SubscriptionManager(&manager); }
+
+void SubscriptionImpl::cancel() { manager.cancel(name); }
+
+void SubscriptionImpl::received(Message& m) {
+ Mutex::ScopedLock l(lock);
+ MessageImpl& mi = *MessageImpl::get(m);
+ if (mi.getMethod().getAcquireMode() == ACQUIRE_MODE_NOT_ACQUIRED)
+ unacquired.add(m.getId());
+ else if (mi.getMethod().getAcceptMode() == ACCEPT_MODE_EXPLICIT)
+ unaccepted.add(m.getId());
+
+ if (listener) {
+ Mutex::ScopedUnlock u(lock);
+ listener->received(m);
+ }
+
+ if (settings.completionMode == COMPLETE_ON_DELIVERY) {
+ manager.getSession().markCompleted(m.getId(), false, false);
+ }
+ if (settings.autoAck) {
+ if (unaccepted.size() >= settings.autoAck) {
+ async(manager.getSession()).messageAccept(unaccepted);
+ switch (settings.completionMode) {
+ case COMPLETE_ON_ACCEPT:
+ manager.getSession().markCompleted(unaccepted, true);
+ break;
+ case COMPLETE_ON_DELIVERY:
+ manager.getSession().sendCompletion();
+ break;
+ default://do nothing
+ break;
+ }
+ unaccepted.clear();
+ }
+ }
+}
+
+Demux::QueuePtr SubscriptionImpl::divert()
+{
+ Session session(manager.getSession());
+ Demux& demux = SessionBase_0_10Access(session).get()->getDemux();
+ demuxRule = std::auto_ptr<ScopedDivert>(new ScopedDivert(name, demux));
+ return demuxRule->getQueue();
+}
+
+void SubscriptionImpl::cancelDiversion() {
+ demuxRule.reset();
+}
+
+}} // namespace qpid::client
+
diff --git a/cpp/src/qpid/client/SubscriptionImpl.h b/cpp/src/qpid/client/SubscriptionImpl.h
new file mode 100644
index 0000000000..da77213423
--- /dev/null
+++ b/cpp/src/qpid/client/SubscriptionImpl.h
@@ -0,0 +1,125 @@
+#ifndef QPID_CLIENT_SUBSCRIPTIONIMPL_H
+#define QPID_CLIENT_SUBSCRIPTIONIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/SubscriptionSettings.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/client/Demux.h"
+#include "qpid/framing/enum.h"
+#include "qpid/framing/SequenceSet.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/RefCounted.h"
+#include "qpid/client/ClientImportExport.h"
+#include <memory>
+
+namespace qpid {
+namespace client {
+
+class SubscriptionManager;
+class SubscriptionManagerImpl;
+
+class SubscriptionImpl : public RefCounted, public MessageListener {
+ public:
+ QPID_CLIENT_EXTERN SubscriptionImpl(SubscriptionManager, const std::string& queue,
+ const SubscriptionSettings&, const std::string& name, MessageListener* =0);
+
+ /** The name of the subsctription, used as the "destination" for messages from the broker.
+ * Usually the same as the queue name but can be set differently.
+ */
+ QPID_CLIENT_EXTERN std::string getName() const;
+
+ /** Name of the queue this subscription subscribes to */
+ QPID_CLIENT_EXTERN std::string getQueue() const;
+
+ /** Get the flow control and acknowledgement settings for this subscription */
+ QPID_CLIENT_EXTERN const SubscriptionSettings& getSettings() const;
+
+ /** Set the flow control parameters */
+ QPID_CLIENT_EXTERN void setFlowControl(const FlowControl&);
+
+ /** Automatically acknowledge (acquire and accept) batches of n messages.
+ * You can disable auto-acknowledgement by setting n=0, and use acquire() and accept()
+ * to manually acquire and accept messages.
+ */
+ QPID_CLIENT_EXTERN void setAutoAck(size_t n);
+
+ /** Get the set of ID's for messages received by this subscription but not yet acquired.
+ * This will always be empty if acquireMode=ACQUIRE_MODE_PRE_ACQUIRED
+ */
+ QPID_CLIENT_EXTERN SequenceSet getUnacquired() const;
+
+ /** Get the set of ID's for messages acquired by this subscription but not yet accepted. */
+ QPID_CLIENT_EXTERN SequenceSet getUnaccepted() const;
+
+ /** Acquire messageIds and remove them from the un-acquired set for the session. */
+ QPID_CLIENT_EXTERN void acquire(const SequenceSet& messageIds);
+
+ /** Accept messageIds and remove them from the un-accepted set for the session. */
+ QPID_CLIENT_EXTERN void accept(const SequenceSet& messageIds);
+
+ /** Release messageIds and remove them from the un-accepted set for the session. */
+ QPID_CLIENT_EXTERN void release(const SequenceSet& messageIds);
+
+ /** Get the session associated with this subscription */
+ QPID_CLIENT_EXTERN Session getSession() const;
+
+ /** Get the subscription manager associated with this subscription */
+ QPID_CLIENT_EXTERN SubscriptionManager getSubscriptionManager();
+
+ /** Send subscription request and issue appropriate flow control commands. */
+ QPID_CLIENT_EXTERN void subscribe();
+
+ /** Cancel the subscription. */
+ QPID_CLIENT_EXTERN void cancel();
+
+ /** Grant specified credit for this subscription **/
+ QPID_CLIENT_EXTERN void grantCredit(framing::message::CreditUnit unit, uint32_t value);
+
+ QPID_CLIENT_EXTERN void received(Message&);
+
+ /**
+ * Set up demux diversion for messages sent to this subscription
+ */
+ Demux::QueuePtr divert();
+ /**
+ * Cancel any demux diversion that may have been setup for this
+ * subscription
+ */
+ QPID_CLIENT_EXTERN void cancelDiversion();
+
+ private:
+
+ mutable sys::Mutex lock;
+ SubscriptionManagerImpl& manager;
+ std::string name, queue;
+ SubscriptionSettings settings;
+ framing::SequenceSet unacquired, unaccepted;
+ MessageListener* listener;
+ std::auto_ptr<ScopedDivert> demuxRule;
+};
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_SUBSCRIPTIONIMPL_H*/
diff --git a/cpp/src/qpid/client/SubscriptionManager.cpp b/cpp/src/qpid/client/SubscriptionManager.cpp
index b4c48f7365..7eac3c541b 100644
--- a/cpp/src/qpid/client/SubscriptionManager.cpp
+++ b/cpp/src/qpid/client/SubscriptionManager.cpp
@@ -18,129 +18,85 @@
* under the License.
*
*/
-#ifndef _Subscription_
-#define _Subscription_
-#include "SubscriptionManager.h"
-#include <qpid/client/Dispatcher.h>
-#include <qpid/client/Session.h>
-#include <qpid/client/MessageListener.h>
-#include <qpid/framing/Uuid.h>
-#include <set>
-#include <sstream>
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/SubscriptionManagerImpl.h"
+#include "qpid/client/PrivateImplRef.h"
namespace qpid {
namespace client {
-SubscriptionManager::SubscriptionManager(const Session& s)
- : dispatcher(s), session(s),
- flowControl(UNLIMITED, UNLIMITED, false),
- acceptMode(0), acquireMode(0),
- autoStop(true)
-{}
-
-void SubscriptionManager::subscribeInternal(
- const std::string& q, const std::string& dest, const FlowControl& fc)
-{
- session.messageSubscribe(
- arg::queue=q, arg::destination=dest,
- arg::acceptMode=acceptMode, arg::acquireMode=acquireMode);
- if (fc.messages || fc.bytes) // No need to set if all 0.
- setFlowControl(dest, fc);
-}
+typedef PrivateImplRef<SubscriptionManager> PI;
-void SubscriptionManager::subscribe(
- MessageListener& listener, const std::string& q, const std::string& d)
-{
- subscribe(listener, q, getFlowControl(), d);
-}
+SubscriptionManager::SubscriptionManager(const Session& s) { PI::ctor(*this, new SubscriptionManagerImpl(s)); }
+SubscriptionManager::SubscriptionManager(SubscriptionManagerImpl* i) { PI::ctor(*this, i); }
+SubscriptionManager::SubscriptionManager(const SubscriptionManager& x) : Runnable(), Handle<SubscriptionManagerImpl>() { PI::copy(*this, x); }
+SubscriptionManager::~SubscriptionManager() { PI::dtor(*this); }
+SubscriptionManager& SubscriptionManager::operator=(const SubscriptionManager& x) { return PI::assign(*this, x); }
-void SubscriptionManager::subscribe(
- MessageListener& listener, const std::string& q, const FlowControl& fc, const std::string& d)
-{
- std::string dest=d.empty() ? q:d;
- dispatcher.listen(dest, &listener, autoAck);
- return subscribeInternal(q, dest, fc);
-}
+Subscription SubscriptionManager::subscribe(
+ MessageListener& listener, const std::string& q, const SubscriptionSettings& ss, const std::string& n)
+{ return impl->subscribe(listener, q, ss, n); }
-void SubscriptionManager::subscribe(
- LocalQueue& lq, const std::string& q, const std::string& d)
-{
- subscribe(lq, q, getFlowControl(), d);
-}
+Subscription SubscriptionManager::subscribe(
+ LocalQueue& lq, const std::string& q, const SubscriptionSettings& ss, const std::string& n)
+{ return impl->subscribe(lq, q, ss, n); }
-void SubscriptionManager::subscribe(
- LocalQueue& lq, const std::string& q, const FlowControl& fc, const std::string& d)
-{
- std::string dest=d.empty() ? q:d;
- lq.session=session;
- lq.queue=session.getExecution().getDemux().add(dest, ByTransferDest(dest));
- return subscribeInternal(q, dest, fc);
-}
-void SubscriptionManager::setFlowControl(
- const std::string& dest, uint32_t messages, uint32_t bytes, bool window)
-{
- session.messageSetFlowMode(dest, window);
- session.messageFlow(dest, 0, messages);
- session.messageFlow(dest, 1, bytes);
- session.sync();
-}
+Subscription SubscriptionManager::subscribe(
+ MessageListener& listener, const std::string& q, const std::string& n)
+{ return impl->subscribe(listener, q, n); }
-void SubscriptionManager::setFlowControl(const std::string& dest, const FlowControl& fc) {
- setFlowControl(dest, fc.messages, fc.bytes, fc.window);
-}
-void SubscriptionManager::setFlowControl(const FlowControl& fc) { flowControl=fc; }
+Subscription SubscriptionManager::subscribe(
+ LocalQueue& lq, const std::string& q, const std::string& n)
+{ return impl->subscribe(lq, q, n); }
-void SubscriptionManager::setFlowControl(
- uint32_t messages_, uint32_t bytes_, bool window_)
-{
- setFlowControl(FlowControl(messages_, bytes_, window_));
-}
+void SubscriptionManager::cancel(const std::string& dest) { return impl->cancel(dest); }
-const FlowControl& SubscriptionManager::getFlowControl() const { return flowControl; }
+void SubscriptionManager::setAutoStop(bool set) { impl->setAutoStop(set); }
-void SubscriptionManager::setAcceptMode(bool c) { acceptMode=c; }
+void SubscriptionManager::run() { impl->run(); }
-void SubscriptionManager::setAcquireMode(bool a) { acquireMode=a; }
+void SubscriptionManager::start() { impl->start(); }
-void SubscriptionManager::setAckPolicy(const AckPolicy& a) { autoAck=a; }
+void SubscriptionManager::wait() { impl->wait(); }
-AckPolicy& SubscriptionManager::getAckPolicy() { return autoAck; }
+void SubscriptionManager::stop() { impl->stop(); }
-void SubscriptionManager::cancel(const std::string dest)
-{
- sync(session).messageCancel(dest);
- dispatcher.cancel(dest);
+bool SubscriptionManager::get(Message& result, const std::string& queue, sys::Duration timeout) {
+ return impl->get(result, queue, timeout);
}
-void SubscriptionManager::setAutoStop(bool set) { autoStop=set; }
+Message SubscriptionManager::get(const std::string& queue, sys::Duration timeout) {
+ return impl->get(queue, timeout);
+}
+
+Session SubscriptionManager::getSession() const { return impl->getSession(); }
-void SubscriptionManager::run()
-{
- dispatcher.setAutoStop(autoStop);
- dispatcher.run();
+Subscription SubscriptionManager::getSubscription(const std::string& name) const {
+ return impl->getSubscription(name);
+}
+void SubscriptionManager::registerFailoverHandler (boost::function<void ()> fh) {
+ impl->registerFailoverHandler(fh);
}
-void SubscriptionManager::stop()
-{
- dispatcher.stop();
+void SubscriptionManager::setFlowControl(const std::string& name, const FlowControl& flow) {
+ impl->setFlowControl(name, flow);
}
-bool SubscriptionManager::get(Message& result, const std::string& queue, sys::Duration timeout) {
- LocalQueue lq;
- std::string unique = framing::Uuid(true).str();
- subscribe(lq, queue, FlowControl::messageCredit(1), unique);
- AutoCancel ac(*this, unique);
- //first wait for message to be delivered if a timeout has been specified
- if (timeout && lq.get(result, timeout)) return true;
- //make sure message is not on queue before final check
- sync(session).messageFlush(unique);
- return lq.get(result, 0);
+void SubscriptionManager::setFlowControl(const std::string& name, uint32_t messages, uint32_t bytes, bool window) {
+ impl->setFlowControl(name, FlowControl(messages, bytes, window));
}
+void SubscriptionManager::setFlowControl(uint32_t messages, uint32_t bytes, bool window) {
+ impl->setFlowControl(messages, bytes, window);
+}
+
+void SubscriptionManager::setAcceptMode(AcceptMode mode) { impl->setAcceptMode(mode); }
+void SubscriptionManager::setAcquireMode(AcquireMode mode) { impl->setAcquireMode(mode); }
+
}} // namespace qpid::client
-#endif
+
diff --git a/cpp/src/qpid/client/SubscriptionManager.h b/cpp/src/qpid/client/SubscriptionManager.h
deleted file mode 100644
index 3dad15fd29..0000000000
--- a/cpp/src/qpid/client/SubscriptionManager.h
+++ /dev/null
@@ -1,210 +0,0 @@
-#ifndef QPID_CLIENT_SUBSCRIPTIONMANAGER_H
-#define QPID_CLIENT_SUBSCRIPTIONMANAGER_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/sys/Mutex.h"
-#include <qpid/client/Dispatcher.h>
-#include <qpid/client/Completion.h>
-#include <qpid/client/Session.h>
-#include <qpid/client/MessageListener.h>
-#include <qpid/client/LocalQueue.h>
-#include <qpid/client/FlowControl.h>
-#include <qpid/sys/Runnable.h>
-#include <set>
-#include <sstream>
-
-namespace qpid {
-namespace client {
-
-/**
- * A class to help create and manage subscriptions.
- *
- * Set up your subscriptions, then call run() to have messages
- * delivered.
- *
- * \ingroup clientapi
- */
-class SubscriptionManager : public sys::Runnable
-{
- typedef sys::Mutex::ScopedLock Lock;
- typedef sys::Mutex::ScopedUnlock Unlock;
-
- void subscribeInternal(const std::string& q, const std::string& dest, const FlowControl&);
-
- qpid::client::Dispatcher dispatcher;
- qpid::client::AsyncSession session;
- FlowControl flowControl;
- AckPolicy autoAck;
- bool acceptMode;
- bool acquireMode;
- bool autoStop;
-
- public:
- /** Create a new SubscriptionManager associated with a session */
- SubscriptionManager(const Session& session);
-
- /**
- * Subscribe a MessagesListener to receive messages from queue.
- *
- * Provide your own subclass of MessagesListener to process
- * incoming messages. It will be called for each message received.
- *
- *@param listener Listener object to receive messages.
- *@param queue Name of the queue to subscribe to.
- *@param flow initial FlowControl for the subscription.
- *@param tag Unique destination tag for the listener.
- * If not specified, the queue name is used.
- */
- void subscribe(MessageListener& listener,
- const std::string& queue,
- const FlowControl& flow,
- const std::string& tag=std::string());
-
- /**
- * Subscribe a LocalQueue to receive messages from queue.
- *
- * Incoming messages are stored in the queue for you to retrieve.
- *
- *@param queue Name of the queue to subscribe to.
- *@param flow initial FlowControl for the subscription.
- *@param tag Unique destination tag for the listener.
- * If not specified, the queue name is used.
- */
- void subscribe(LocalQueue& localQueue,
- const std::string& queue,
- const FlowControl& flow,
- const std::string& tag=std::string());
-
- /**
- * Subscribe a MessagesListener to receive messages from queue.
- *
- * Provide your own subclass of MessagesListener to process
- * incoming messages. It will be called for each message received.
- *
- *@param listener Listener object to receive messages.
- *@param queue Name of the queue to subscribe to.
- *@param tag Unique destination tag for the listener.
- * If not specified, the queue name is used.
- */
- void subscribe(MessageListener& listener,
- const std::string& queue,
- const std::string& tag=std::string());
-
- /**
- * Subscribe a LocalQueue to receive messages from queue.
- *
- * Incoming messages are stored in the queue for you to retrieve.
- *
- *@param queue Name of the queue to subscribe to.
- *@param tag Unique destination tag for the listener.
- * If not specified, the queue name is used.
- */
- void subscribe(LocalQueue& localQueue,
- const std::string& queue,
- const std::string& tag=std::string());
-
-
- /** Get a single message from a queue.
- *@param result is set to the message from the queue.
- *@
- *@param timeout wait up this timeout for a message to appear.
- *@return true if result was set, false if no message available after timeout.
- */
- bool get(Message& result, const std::string& queue, sys::Duration timeout=0);
-
- /** Cancel a subscription. */
- void cancel(const std::string tag);
-
- /** Deliver messages until stop() is called. */
- void run();
-
- /** If set true, run() will stop when all subscriptions
- * are cancelled. If false, run will only stop when stop()
- * is called. True by default.
- */
- void setAutoStop(bool set=true);
-
- /** Cause run() to return */
- void stop();
-
- static const uint32_t UNLIMITED=0xFFFFFFFF;
-
- /** Set the flow control for destination. */
- void setFlowControl(const std::string& destintion, const FlowControl& flow);
-
- /** Set the default initial flow control for subscriptions that do not specify it. */
- void setFlowControl(const FlowControl& flow);
-
- /** Get the default flow control for new subscriptions that do not specify it. */
- const FlowControl& getFlowControl() const;
-
- /** Set the flow control for destination tag.
- *@param tag: name of the destination.
- *@param messages: message credit.
- *@param bytes: byte credit.
- *@param window: if true use window-based flow control.
- */
- void setFlowControl(const std::string& tag, uint32_t messages, uint32_t bytes, bool window=true);
-
- /** Set the initial flow control settings to be applied to each new subscribtion.
- *@param messages: message credit.
- *@param bytes: byte credit.
- *@param window: if true use window-based flow control.
- */
- void setFlowControl(uint32_t messages, uint32_t bytes, bool window=true);
-
- /** Set the accept-mode for new subscriptions. Defaults to true.
- *@param required: if true messages must be confirmed by calling
- *Message::acknowledge() or automatically, see setAckPolicy()
- */
- void setAcceptMode(bool required);
-
- /** Set the acquire-mode for new subscriptions. Defaults to false.
- *@param acquire: if false messages pre-acquired, if true
- * messages are dequed on acknowledgement or on transfer
- * depending on acceptMode.
- */
- void setAcquireMode(bool acquire);
-
- /** Set the acknowledgement policy for new subscriptions.
- * Default is to acknowledge every message automatically.
- */
- void setAckPolicy(const AckPolicy& autoAck);
- /**
- *
- */
- AckPolicy& getAckPolicy();
-};
-
-/** AutoCancel cancels a subscription in its destructor */
-class AutoCancel {
- public:
- AutoCancel(SubscriptionManager& sm_, const std::string& tag_) : sm(sm_), tag(tag_) {}
- ~AutoCancel() { sm.cancel(tag); }
- private:
- SubscriptionManager& sm;
- std::string tag;
-};
-
-}} // namespace qpid::client
-
-#endif /*!QPID_CLIENT_SUBSCRIPTIONMANAGER_H*/
diff --git a/cpp/src/qpid/client/SubscriptionManagerImpl.cpp b/cpp/src/qpid/client/SubscriptionManagerImpl.cpp
new file mode 100644
index 0000000000..a558d90be8
--- /dev/null
+++ b/cpp/src/qpid/client/SubscriptionManagerImpl.cpp
@@ -0,0 +1,162 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/SubscriptionManagerImpl.h"
+#include "qpid/client/SubscriptionImpl.h"
+#include "qpid/client/LocalQueueImpl.h"
+#include "qpid/client/PrivateImplRef.h"
+#include <qpid/client/Dispatcher.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/MessageListener.h>
+#include <qpid/framing/Uuid.h>
+#include <set>
+#include <sstream>
+
+
+namespace qpid {
+namespace client {
+
+SubscriptionManagerImpl::SubscriptionManagerImpl(const Session& s)
+ : dispatcher(s), session(s), autoStop(true)
+{}
+
+Subscription SubscriptionManagerImpl::subscribe(
+ MessageListener& listener, const std::string& q, const SubscriptionSettings& ss, const std::string& n)
+{
+ sys::Mutex::ScopedLock l(lock);
+ std::string name=n.empty() ? q:n;
+ boost::intrusive_ptr<SubscriptionImpl> si = new SubscriptionImpl(SubscriptionManager(this), q, ss, name, &listener);
+ dispatcher.listen(si);
+ //issue subscription request after listener is registered with dispatcher
+ si->subscribe();
+ return subscriptions[name] = Subscription(si.get());
+}
+
+Subscription SubscriptionManagerImpl::subscribe(
+ LocalQueue& lq, const std::string& q, const SubscriptionSettings& ss, const std::string& n)
+{
+ sys::Mutex::ScopedLock l(lock);
+ std::string name=n.empty() ? q:n;
+ boost::intrusive_ptr<SubscriptionImpl> si = new SubscriptionImpl(SubscriptionManager(this), q, ss, name, 0);
+ boost::intrusive_ptr<LocalQueueImpl> lqi = PrivateImplRef<LocalQueue>::get(lq);
+ lqi->queue=si->divert();
+ si->subscribe();
+ lqi->subscription = Subscription(si.get());
+ return subscriptions[name] = lqi->subscription;
+}
+
+Subscription SubscriptionManagerImpl::subscribe(
+ MessageListener& listener, const std::string& q, const std::string& n)
+{
+ return subscribe(listener, q, defaultSettings, n);
+}
+
+Subscription SubscriptionManagerImpl::subscribe(
+ LocalQueue& lq, const std::string& q, const std::string& n)
+{
+ return subscribe(lq, q, defaultSettings, n);
+}
+
+void SubscriptionManagerImpl::cancel(const std::string& dest)
+{
+ sys::Mutex::ScopedLock l(lock);
+ std::map<std::string, Subscription>::iterator i = subscriptions.find(dest);
+ if (i != subscriptions.end()) {
+ sync(session).messageCancel(dest);
+ dispatcher.cancel(dest);
+ Subscription s = i->second;
+ if (s.isValid())
+ PrivateImplRef<Subscription>::get(s)->cancelDiversion();
+ subscriptions.erase(i);
+ }
+}
+
+void SubscriptionManagerImpl::setAutoStop(bool set) { autoStop=set; }
+
+void SubscriptionManagerImpl::run()
+{
+ dispatcher.setAutoStop(autoStop);
+ dispatcher.run();
+}
+
+void SubscriptionManagerImpl::start()
+{
+ dispatcher.setAutoStop(autoStop);
+ dispatcher.start();
+}
+
+void SubscriptionManagerImpl::wait()
+{
+ dispatcher.wait();
+}
+
+void SubscriptionManagerImpl::stop()
+{
+ dispatcher.stop();
+}
+
+bool SubscriptionManagerImpl::get(Message& result, const std::string& queue, sys::Duration timeout) {
+ LocalQueue lq;
+ std::string unique = framing::Uuid(true).str();
+ subscribe(lq, queue, SubscriptionSettings(FlowControl::messageCredit(1)), unique);
+ SubscriptionManager sm(this);
+ AutoCancel ac(sm, unique);
+ //first wait for message to be delivered if a timeout has been specified
+ if (timeout && lq.get(result, timeout))
+ return true;
+ //make sure message is not on queue before final check
+ sync(session).messageFlush(unique);
+ return lq.get(result, 0);
+}
+
+Message SubscriptionManagerImpl::get(const std::string& queue, sys::Duration timeout) {
+ Message result;
+ if (!get(result, queue, timeout))
+ throw Exception("Timed out waiting for a message");
+ return result;
+}
+
+Session SubscriptionManagerImpl::getSession() const { return session; }
+
+Subscription SubscriptionManagerImpl::getSubscription(const std::string& name) const {
+ sys::Mutex::ScopedLock l(lock);
+ std::map<std::string, Subscription>::const_iterator i = subscriptions.find(name);
+ if (i == subscriptions.end())
+ throw Exception(QPID_MSG("Subscription not found: " << name));
+ return i->second;
+}
+
+void SubscriptionManagerImpl::registerFailoverHandler (boost::function<void ()> fh) {
+ dispatcher.registerFailoverHandler(fh);
+}
+
+void SubscriptionManagerImpl::setFlowControl(const std::string& name, const FlowControl& flow) {
+ getSubscription(name).setFlowControl(flow);
+}
+
+void SubscriptionManagerImpl::setFlowControl(const std::string& name, uint32_t messages, uint32_t bytes, bool window) {
+ setFlowControl(name, FlowControl(messages, bytes, window));
+}
+
+}} // namespace qpid::client
+
+
diff --git a/cpp/src/qpid/client/SubscriptionManagerImpl.h b/cpp/src/qpid/client/SubscriptionManagerImpl.h
new file mode 100644
index 0000000000..6376a05c45
--- /dev/null
+++ b/cpp/src/qpid/client/SubscriptionManagerImpl.h
@@ -0,0 +1,278 @@
+#ifndef QPID_CLIENT_SUBSCRIPTIONMANAGERIMPL_H
+#define QPID_CLIENT_SUBSCRIPTIONMANAGERIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/sys/Mutex.h"
+#include <qpid/client/Dispatcher.h>
+#include <qpid/client/Completion.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/AsyncSession.h>
+#include <qpid/client/MessageListener.h>
+#include <qpid/client/LocalQueue.h>
+#include <qpid/client/Subscription.h>
+#include <qpid/sys/Runnable.h>
+#include <qpid/RefCounted.h>
+#include <set>
+#include <sstream>
+
+namespace qpid {
+namespace client {
+
+/**
+ * A class to help create and manage subscriptions.
+ *
+ * Set up your subscriptions, then call run() to have messages
+ * delivered.
+ *
+ * \ingroup clientapi
+ *
+ * \details
+ *
+ * <h2>Subscribing and canceling subscriptions</h2>
+ *
+ * <ul>
+ * <li>
+ * <p>subscribe()</p>
+ * <pre> SubscriptionManager subscriptions(session);
+ * Listener listener(subscriptions);
+ * subscriptions.subscribe(listener, myQueue);</pre>
+ * <pre> SubscriptionManager subscriptions(session);
+ * LocalQueue local_queue;
+ * subscriptions.subscribe(local_queue, string("message_queue"));</pre></li>
+ * <li>
+ * <p>cancel()</p>
+ * <pre>subscriptions.cancel();</pre></li>
+ * </ul>
+ *
+ * <h2>Waiting for messages (and returning)</h2>
+ *
+ * <ul>
+ * <li>
+ * <p>run()</p>
+ * <pre> // Give up control to receive messages
+ * subscriptions.run();</pre></li>
+ * <li>
+ * <p>stop()</p>
+ * <pre>.// Use this code in a listener to return from run()
+ * subscriptions.stop();</pre></li>
+ * <li>
+ * <p>setAutoStop()</p>
+ * <pre>.// Return from subscriptions.run() when last subscription is cancelled
+ *.subscriptions.setAutoStop(true);
+ *.subscriptons.run();
+ * </pre></li>
+ * <li>
+ * <p>Ending a subscription in a listener</p>
+ * <pre>
+ * void Listener::received(Message&amp; message) {
+ *
+ * if (message.getData() == "That's all, folks!") {
+ * subscriptions.cancel(message.getDestination());
+ * }
+ * }
+ * </pre>
+ * </li>
+ * </ul>
+ *
+ */
+class SubscriptionManagerImpl : public sys::Runnable, public RefCounted
+{
+ public:
+ /** Create a new SubscriptionManagerImpl associated with a session */
+ SubscriptionManagerImpl(const Session& session);
+
+ /**
+ * Subscribe a MessagesListener to receive messages from queue.
+ *
+ * Provide your own subclass of MessagesListener to process
+ * incoming messages. It will be called for each message received.
+ *
+ *@param listener Listener object to receive messages.
+ *@param queue Name of the queue to subscribe to.
+ *@param settings settings for the subscription.
+ *@param name unique destination name for the subscription, defaults to queue name.
+ */
+ Subscription subscribe(MessageListener& listener,
+ const std::string& queue,
+ const SubscriptionSettings& settings,
+ const std::string& name=std::string());
+
+ /**
+ * Subscribe a LocalQueue to receive messages from queue.
+ *
+ * Incoming messages are stored in the queue for you to retrieve.
+ *
+ *@param queue Name of the queue to subscribe to.
+ *@param flow initial FlowControl for the subscription.
+ *@param name unique destination name for the subscription, defaults to queue name.
+ * If not specified, the queue name is used.
+ */
+ Subscription subscribe(LocalQueue& localQueue,
+ const std::string& queue,
+ const SubscriptionSettings& settings,
+ const std::string& name=std::string());
+
+ /**
+ * Subscribe a MessagesListener to receive messages from queue.
+ *
+ * Provide your own subclass of MessagesListener to process
+ * incoming messages. It will be called for each message received.
+ *
+ *@param listener Listener object to receive messages.
+ *@param queue Name of the queue to subscribe to.
+ *@param name unique destination name for the subscription, defaults to queue name.
+ * If not specified, the queue name is used.
+ */
+ Subscription subscribe(MessageListener& listener,
+ const std::string& queue,
+ const std::string& name=std::string());
+
+ /**
+ * Subscribe a LocalQueue to receive messages from queue.
+ *
+ * Incoming messages are stored in the queue for you to retrieve.
+ *
+ *@param queue Name of the queue to subscribe to.
+ *@param name unique destination name for the subscription, defaults to queue name.
+ * If not specified, the queue name is used.
+ */
+ Subscription subscribe(LocalQueue& localQueue,
+ const std::string& queue,
+ const std::string& name=std::string());
+
+
+ /** Get a single message from a queue.
+ *@param result is set to the message from the queue.
+ *@param timeout wait up this timeout for a message to appear.
+ *@return true if result was set, false if no message available after timeout.
+ */
+ bool get(Message& result, const std::string& queue, sys::Duration timeout=0);
+
+ /** Get a single message from a queue.
+ *@param timeout wait up this timeout for a message to appear.
+ *@return message from the queue.
+ *@throw Exception if the timeout is exceeded.
+ */
+ Message get(const std::string& queue, sys::Duration timeout=sys::TIME_INFINITE);
+
+ /** Get a subscription by name.
+ *@throw Exception if not found.
+ */
+ Subscription getSubscription(const std::string& name) const;
+
+ /** Cancel a subscription. See also: Subscription.cancel() */
+ void cancel(const std::string& name);
+
+ /** Deliver messages in the current thread until stop() is called.
+ * Only one thread may be running in a SubscriptionManager at a time.
+ * @see run
+ */
+ void run();
+
+ /** Start a new thread to deliver messages.
+ * Only one thread may be running in a SubscriptionManager at a time.
+ * @see start
+ */
+ void start();
+
+ /**
+ * Wait for the thread started by a call to start() to complete.
+ */
+ void wait();
+
+ /** If set true, run() will stop when all subscriptions
+ * are cancelled. If false, run will only stop when stop()
+ * is called. True by default.
+ */
+ void setAutoStop(bool set=true);
+
+ /** Stop delivery. Causes run() to return, or the thread started with start() to exit. */
+ void stop();
+
+ static const uint32_t UNLIMITED=0xFFFFFFFF;
+
+ /** Set the flow control for a subscription. */
+ void setFlowControl(const std::string& name, const FlowControl& flow);
+
+ /** Set the flow control for a subscription.
+ *@param name: name of the subscription.
+ *@param messages: message credit.
+ *@param bytes: byte credit.
+ *@param window: if true use window-based flow control.
+ */
+ void setFlowControl(const std::string& name, uint32_t messages, uint32_t bytes, bool window=true);
+
+ /** Set the default settings for subscribe() calls that don't
+ * include a SubscriptionSettings parameter.
+ */
+ void setDefaultSettings(const SubscriptionSettings& s) { defaultSettings = s; }
+
+ /** Get the default settings for subscribe() calls that don't
+ * include a SubscriptionSettings parameter.
+ */
+ const SubscriptionSettings& getDefaultSettings() const { return defaultSettings; }
+
+ /** Get the default settings for subscribe() calls that don't
+ * include a SubscriptionSettings parameter.
+ */
+ SubscriptionSettings& getDefaultSettings() { return defaultSettings; }
+
+ /**
+ * Set the default flow control settings for subscribe() calls
+ * that don't include a SubscriptionSettings parameter.
+ *
+ *@param messages: message credit.
+ *@param bytes: byte credit.
+ *@param window: if true use window-based flow control.
+ */
+ void setFlowControl(uint32_t messages, uint32_t bytes, bool window=true) {
+ defaultSettings.flowControl = FlowControl(messages, bytes, window);
+ }
+
+ /**
+ *Set the default accept-mode for subscribe() calls that don't
+ *include a SubscriptionSettings parameter.
+ */
+ void setAcceptMode(AcceptMode mode) { defaultSettings.acceptMode = mode; }
+
+ /**
+ * Set the default acquire-mode subscribe()s that don't specify SubscriptionSettings.
+ */
+ void setAcquireMode(AcquireMode mode) { defaultSettings.acquireMode = mode; }
+
+ void registerFailoverHandler ( boost::function<void ()> fh );
+
+ Session getSession() const;
+
+ private:
+ mutable sys::Mutex lock;
+ qpid::client::Dispatcher dispatcher;
+ qpid::client::AsyncSession session;
+ bool autoStop;
+ SubscriptionSettings defaultSettings;
+ std::map<std::string, Subscription> subscriptions;
+};
+
+
+}} // namespace qpid::client
+
+#endif /*!QPID_CLIENT_SUBSCRIPTIONMANAGERIMPL_H*/
diff --git a/cpp/src/qpid/client/TCPConnector.cpp b/cpp/src/qpid/client/TCPConnector.cpp
new file mode 100644
index 0000000000..1a6e51d54d
--- /dev/null
+++ b/cpp/src/qpid/client/TCPConnector.cpp
@@ -0,0 +1,327 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/TCPConnector.h"
+
+#include "qpid/client/ConnectionImpl.h"
+#include "qpid/client/ConnectionSettings.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/Codec.h"
+#include "qpid/sys/Time.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/sys/AsynchIO.h"
+#include "qpid/sys/Dispatcher.h"
+#include "qpid/sys/Poller.h"
+#include "qpid/sys/SecurityLayer.h"
+#include "qpid/Msg.h"
+
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/format.hpp>
+
+namespace qpid {
+namespace client {
+
+using namespace qpid::sys;
+using namespace qpid::framing;
+using boost::format;
+using boost::str;
+
+// Static constructor which registers connector here
+namespace {
+ Connector* create(framing::ProtocolVersion v, const ConnectionSettings& s, ConnectionImpl* c) {
+ return new TCPConnector(v, s, c);
+ }
+
+ struct StaticInit {
+ StaticInit() {
+ Connector::registerFactory("tcp", &create);
+ };
+ } init;
+}
+
+struct TCPConnector::Buff : public AsynchIO::BufferBase {
+ Buff(size_t size) : AsynchIO::BufferBase(new char[size], size) {}
+ ~Buff() { delete [] bytes;}
+};
+
+TCPConnector::TCPConnector(ProtocolVersion ver,
+ const ConnectionSettings& settings,
+ ConnectionImpl* cimpl)
+ : maxFrameSize(settings.maxFrameSize),
+ lastEof(0),
+ currentSize(0),
+ bounds(cimpl),
+ version(ver),
+ initiated(false),
+ closed(true),
+ joined(true),
+ shutdownHandler(0),
+ aio(0),
+ impl(cimpl->shared_from_this())
+{
+ QPID_LOG(debug, "TCPConnector created for " << version.toString());
+ settings.configureSocket(socket);
+}
+
+TCPConnector::~TCPConnector() {
+ close();
+}
+
+void TCPConnector::connect(const std::string& host, int port) {
+ Mutex::ScopedLock l(lock);
+ assert(closed);
+ assert(joined);
+ poller = Poller::shared_ptr(new Poller);
+ AsynchConnector::create(socket,
+ poller,
+ host, port,
+ boost::bind(&TCPConnector::connected, this, _1),
+ boost::bind(&TCPConnector::connectFailed, this, _3));
+ closed = false;
+ joined = false;
+ receiver = Thread(this);
+}
+
+void TCPConnector::connected(const Socket&) {
+ aio = AsynchIO::create(socket,
+ boost::bind(&TCPConnector::readbuff, this, _1, _2),
+ boost::bind(&TCPConnector::eof, this, _1),
+ boost::bind(&TCPConnector::eof, this, _1),
+ 0, // closed
+ 0, // nobuffs
+ boost::bind(&TCPConnector::writebuff, this, _1));
+ for (int i = 0; i < 32; i++) {
+ aio->queueReadBuffer(new Buff(maxFrameSize));
+ }
+ aio->start(poller);
+
+ identifier = str(format("[%1% %2%]") % socket.getLocalPort() % socket.getPeerAddress());
+ ProtocolInitiation init(version);
+ writeDataBlock(init);
+}
+
+void TCPConnector::connectFailed(const std::string& msg) {
+ QPID_LOG(warning, "Connecting failed: " << msg);
+ closed = true;
+ poller->shutdown();
+ closeInternal();
+ if (shutdownHandler)
+ shutdownHandler->shutdown();
+}
+
+bool TCPConnector::closeInternal() {
+ bool ret;
+ {
+ Mutex::ScopedLock l(lock);
+ ret = !closed;
+ if (!closed) {
+ closed = true;
+ aio->queueForDeletion();
+ poller->shutdown();
+ }
+ if (joined || receiver.id() == Thread::current().id()) {
+ return ret;
+ }
+ joined = true;
+ }
+ receiver.join();
+ return ret;
+}
+
+void TCPConnector::close() {
+ closeInternal();
+}
+
+void TCPConnector::abort() {
+ // Can't abort a closed connection
+ if (!closed) {
+ if (aio) {
+ // Established connection
+ aio->requestCallback(boost::bind(&TCPConnector::eof, this, _1));
+ } else {
+ // We're still connecting
+ connectFailed("Connection timedout");
+ }
+ }
+}
+
+void TCPConnector::setInputHandler(InputHandler* handler){
+ input = handler;
+}
+
+void TCPConnector::setShutdownHandler(ShutdownHandler* handler){
+ shutdownHandler = handler;
+}
+
+OutputHandler* TCPConnector::getOutputHandler() {
+ return this;
+}
+
+sys::ShutdownHandler* TCPConnector::getShutdownHandler() const {
+ return shutdownHandler;
+}
+
+const std::string& TCPConnector::getIdentifier() const {
+ return identifier;
+}
+
+void TCPConnector::send(AMQFrame& frame) {
+ Mutex::ScopedLock l(lock);
+ frames.push_back(frame);
+ //only ask to write if this is the end of a frameset or if we
+ //already have a buffers worth of data
+ currentSize += frame.encodedSize();
+ bool notifyWrite = false;
+ if (frame.getEof()) {
+ lastEof = frames.size();
+ notifyWrite = true;
+ } else {
+ notifyWrite = (currentSize >= maxFrameSize);
+ }
+ if (notifyWrite && !closed) aio->notifyPendingWrite();
+}
+
+void TCPConnector::handleClosed() {
+ if (closeInternal() && shutdownHandler)
+ shutdownHandler->shutdown();
+}
+
+void TCPConnector::writebuff(AsynchIO& /*aio*/)
+{
+ Codec* codec = securityLayer.get() ? (Codec*) securityLayer.get() : (Codec*) this;
+ if (codec->canEncode()) {
+ std::auto_ptr<AsynchIO::BufferBase> buffer = std::auto_ptr<AsynchIO::BufferBase>(aio->getQueuedBuffer());
+ if (!buffer.get()) buffer = std::auto_ptr<AsynchIO::BufferBase>(new Buff(maxFrameSize));
+
+ size_t encoded = codec->encode(buffer->bytes, buffer->byteCount);
+
+ buffer->dataStart = 0;
+ buffer->dataCount = encoded;
+ aio->queueWrite(buffer.release());
+ }
+}
+
+// Called in IO thread.
+bool TCPConnector::canEncode()
+{
+ Mutex::ScopedLock l(lock);
+ //have at least one full frameset or a whole buffers worth of data
+ return lastEof || currentSize >= maxFrameSize;
+}
+
+// Called in IO thread.
+size_t TCPConnector::encode(const char* buffer, size_t size)
+{
+ framing::Buffer out(const_cast<char*>(buffer), size);
+ size_t bytesWritten(0);
+ {
+ Mutex::ScopedLock l(lock);
+ while (!frames.empty() && out.available() >= frames.front().encodedSize() ) {
+ frames.front().encode(out);
+ QPID_LOG(trace, "SENT " << identifier << ": " << frames.front());
+ frames.pop_front();
+ if (lastEof) --lastEof;
+ }
+ bytesWritten = size - out.available();
+ currentSize -= bytesWritten;
+ }
+ if (bounds) bounds->reduce(bytesWritten);
+ return bytesWritten;
+}
+
+bool TCPConnector::readbuff(AsynchIO& aio, AsynchIO::BufferBase* buff)
+{
+ Codec* codec = securityLayer.get() ? (Codec*) securityLayer.get() : (Codec*) this;
+ int32_t decoded = codec->decode(buff->bytes+buff->dataStart, buff->dataCount);
+ // TODO: unreading needs to go away, and when we can cope
+ // with multiple sub-buffers in the general buffer scheme, it will
+ if (decoded < buff->dataCount) {
+ // Adjust buffer for used bytes and then "unread them"
+ buff->dataStart += decoded;
+ buff->dataCount -= decoded;
+ aio.unread(buff);
+ } else {
+ // Give whole buffer back to aio subsystem
+ aio.queueReadBuffer(buff);
+ }
+ return true;
+}
+
+size_t TCPConnector::decode(const char* buffer, size_t size)
+{
+ framing::Buffer in(const_cast<char*>(buffer), size);
+ if (!initiated) {
+ framing::ProtocolInitiation protocolInit;
+ if (protocolInit.decode(in)) {
+ QPID_LOG(debug, "RECV " << identifier << " INIT(" << protocolInit << ")");
+ if(!(protocolInit==version)){
+ throw Exception(QPID_MSG("Unsupported version: " << protocolInit
+ << " supported version " << version));
+ }
+ }
+ initiated = true;
+ }
+ AMQFrame frame;
+ while(frame.decode(in)){
+ QPID_LOG(trace, "RECV " << identifier << ": " << frame);
+ input->received(frame);
+ }
+ return size - in.available();
+}
+
+void TCPConnector::writeDataBlock(const AMQDataBlock& data) {
+ AsynchIO::BufferBase* buff = new Buff(maxFrameSize);
+ framing::Buffer out(buff->bytes, buff->byteCount);
+ data.encode(out);
+ buff->dataCount = data.encodedSize();
+ aio->queueWrite(buff);
+}
+
+void TCPConnector::eof(AsynchIO&) {
+ handleClosed();
+}
+
+void TCPConnector::run() {
+ // Keep the connection impl in memory until run() completes.
+ boost::shared_ptr<ConnectionImpl> protect = impl.lock();
+ assert(protect);
+ try {
+ Dispatcher d(poller);
+
+ d.run();
+ } catch (const std::exception& e) {
+ QPID_LOG(error, QPID_MSG("FAIL " << identifier << ": " << e.what()));
+ handleClosed();
+ }
+ try {
+ socket.close();
+ } catch (const std::exception&) {}
+}
+
+void TCPConnector::activateSecurityLayer(std::auto_ptr<qpid::sys::SecurityLayer> sl)
+{
+ securityLayer = sl;
+ securityLayer->init(this);
+}
+
+
+}} // namespace qpid::client
diff --git a/cpp/src/qpid/client/TCPConnector.h b/cpp/src/qpid/client/TCPConnector.h
new file mode 100644
index 0000000000..6dc07d1f5d
--- /dev/null
+++ b/cpp/src/qpid/client/TCPConnector.h
@@ -0,0 +1,117 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef _TCPConnector_
+#define _TCPConnector_
+
+#include "Connector.h"
+#include "qpid/client/Bounds.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/sys/AsynchIO.h"
+#include "qpid/sys/Codec.h"
+#include "qpid/sys/IntegerTypes.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/SecurityLayer.h"
+#include "qpid/sys/Socket.h"
+#include "qpid/sys/Thread.h"
+
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include <deque>
+#include <string>
+
+namespace qpid {
+namespace client {
+
+class TCPConnector : public Connector, public sys::Codec, private sys::Runnable
+{
+ typedef std::deque<framing::AMQFrame> Frames;
+ struct Buff;
+
+ const uint16_t maxFrameSize;
+
+ sys::Mutex lock;
+ Frames frames; // Outgoing frame queue
+ size_t lastEof; // Position after last EOF in frames
+ uint64_t currentSize;
+ Bounds* bounds;
+
+ framing::ProtocolVersion version;
+ bool initiated;
+ bool closed;
+ bool joined;
+
+ sys::ShutdownHandler* shutdownHandler;
+ framing::InputHandler* input;
+ framing::InitiationHandler* initialiser;
+ framing::OutputHandler* output;
+
+ sys::Thread receiver;
+
+ sys::Socket socket;
+
+ sys::AsynchIO* aio;
+ std::string identifier;
+ boost::shared_ptr<sys::Poller> poller;
+ std::auto_ptr<qpid::sys::SecurityLayer> securityLayer;
+
+ ~TCPConnector();
+
+ void run();
+ void handleClosed();
+ bool closeInternal();
+
+ virtual void connected(const qpid::sys::Socket&);
+ void connectFailed(const std::string& msg);
+ bool readbuff(qpid::sys::AsynchIO&, qpid::sys::AsynchIOBufferBase*);
+ void writebuff(qpid::sys::AsynchIO&);
+ void writeDataBlock(const framing::AMQDataBlock& data);
+ void eof(qpid::sys::AsynchIO&);
+
+ boost::weak_ptr<ConnectionImpl> impl;
+
+ void connect(const std::string& host, int port);
+ void close();
+ void send(framing::AMQFrame& frame);
+ void abort();
+
+ void setInputHandler(framing::InputHandler* handler);
+ void setShutdownHandler(sys::ShutdownHandler* handler);
+ sys::ShutdownHandler* getShutdownHandler() const;
+ framing::OutputHandler* getOutputHandler();
+ const std::string& getIdentifier() const;
+ void activateSecurityLayer(std::auto_ptr<qpid::sys::SecurityLayer>);
+
+ size_t decode(const char* buffer, size_t size);
+ size_t encode(const char* buffer, size_t size);
+ bool canEncode();
+
+public:
+ TCPConnector(framing::ProtocolVersion pVersion,
+ const ConnectionSettings&,
+ ConnectionImpl*);
+ unsigned int getSSF() { return 0; }
+};
+
+}} // namespace qpid::client
+
+#endif /* _TCPConnector_ */
diff --git a/cpp/src/qpid/client/TypedResult.h b/cpp/src/qpid/client/TypedResult.h
deleted file mode 100644
index 5306997d74..0000000000
--- a/cpp/src/qpid/client/TypedResult.h
+++ /dev/null
@@ -1,65 +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.
- *
- */
-
-#ifndef _TypedResult_
-#define _TypedResult_
-
-#include "Completion.h"
-
-namespace qpid {
-namespace client {
-
-/**
- * Returned by asynchronous commands that return a result.
- * You can use get() to wait for completion and get the result value.
- * \ingroup clientapi
- */
-template <class T> class TypedResult : public Completion
-{
- T result;
- bool decoded;
-
-public:
- ///@internal
- TypedResult(Future f, shared_ptr<SessionImpl> s) : Completion(f, s), decoded(false) {}
-
- /**
- * Wait for the asynchronous command that returned this TypedResult to complete
- * and return its result.
- *
- *@return The result returned by the command.
- *@exception If the command returns an error, get() throws an exception.
- *
- */
- T& get()
- {
- if (!decoded) {
- future.decodeResult(result, *session);
- decoded = true;
- }
-
- return result;
- }
-};
-
-}}
-
-#endif
diff --git a/cpp/src/qpid/client/amqp0_10/AcceptTracker.cpp b/cpp/src/qpid/client/amqp0_10/AcceptTracker.cpp
new file mode 100644
index 0000000000..80be5c56f3
--- /dev/null
+++ b/cpp/src/qpid/client/amqp0_10/AcceptTracker.cpp
@@ -0,0 +1,111 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "AcceptTracker.h"
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+void AcceptTracker::State::accept()
+{
+ unconfirmed.add(unaccepted);
+ unaccepted.clear();
+}
+
+void AcceptTracker::State::release()
+{
+ unaccepted.clear();
+}
+
+uint32_t AcceptTracker::State::acceptsPending()
+{
+ return unconfirmed.size();
+}
+
+void AcceptTracker::State::completed(qpid::framing::SequenceSet& set)
+{
+ unconfirmed.remove(set);
+}
+
+void AcceptTracker::delivered(const std::string& destination, const qpid::framing::SequenceNumber& id)
+{
+ aggregateState.unaccepted.add(id);
+ destinationState[destination].unaccepted.add(id);
+}
+
+void AcceptTracker::accept(qpid::client::AsyncSession& session)
+{
+ for (StateMap::iterator i = destinationState.begin(); i != destinationState.end(); ++i) {
+ i->second.accept();
+ }
+ Record record;
+ record.status = session.messageAccept(aggregateState.unaccepted);
+ record.accepted = aggregateState.unaccepted;
+ pending.push_back(record);
+ aggregateState.accept();
+}
+
+void AcceptTracker::release(qpid::client::AsyncSession& session)
+{
+ session.messageRelease(aggregateState.unaccepted);
+ for (StateMap::iterator i = destinationState.begin(); i != destinationState.end(); ++i) {
+ i->second.release();
+ }
+ aggregateState.release();
+}
+
+uint32_t AcceptTracker::acceptsPending()
+{
+ checkPending();
+ return aggregateState.acceptsPending();
+}
+
+uint32_t AcceptTracker::acceptsPending(const std::string& destination)
+{
+ checkPending();
+ return destinationState[destination].acceptsPending();
+}
+
+void AcceptTracker::reset()
+{
+ destinationState.clear();
+ aggregateState.unaccepted.clear();
+ aggregateState.unconfirmed.clear();
+ pending.clear();
+}
+
+void AcceptTracker::checkPending()
+{
+ while (!pending.empty() && pending.front().status.isComplete()) {
+ completed(pending.front().accepted);
+ pending.pop_front();
+ }
+}
+
+void AcceptTracker::completed(qpid::framing::SequenceSet& set)
+{
+ for (StateMap::iterator i = destinationState.begin(); i != destinationState.end(); ++i) {
+ i->second.completed(set);
+ }
+ aggregateState.completed(set);
+}
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/cpp/src/qpid/client/amqp0_10/AcceptTracker.h b/cpp/src/qpid/client/amqp0_10/AcceptTracker.h
new file mode 100644
index 0000000000..fb58a3a8c8
--- /dev/null
+++ b/cpp/src/qpid/client/amqp0_10/AcceptTracker.h
@@ -0,0 +1,85 @@
+#ifndef QPID_CLIENT_AMQP0_10_ACCEPTTRACKER_H
+#define QPID_CLIENT_AMQP0_10_ACCEPTTRACKER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/Completion.h"
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/framing/SequenceSet.h"
+#include <deque>
+#include <map>
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+/**
+ * Tracks the set of messages requiring acceptance, and those for
+ * which an accept has been issued but is yet to be confirmed
+ * complete.
+ */
+class AcceptTracker
+{
+ public:
+ void delivered(const std::string& destination, const qpid::framing::SequenceNumber& id);
+ void accept(qpid::client::AsyncSession&);
+ void release(qpid::client::AsyncSession&);
+ uint32_t acceptsPending();
+ uint32_t acceptsPending(const std::string& destination);
+ void reset();
+ private:
+ struct State
+ {
+ /**
+ * ids of messages that have been delivered but not yet
+ * accepted
+ */
+ qpid::framing::SequenceSet unaccepted;
+ /**
+ * ids of messages for which an accpet has been issued but not
+ * yet confirmed as completed
+ */
+ qpid::framing::SequenceSet unconfirmed;
+
+ void accept();
+ void release();
+ uint32_t acceptsPending();
+ void completed(qpid::framing::SequenceSet&);
+ };
+ typedef std::map<std::string, State> StateMap;
+ struct Record
+ {
+ qpid::client::Completion status;
+ qpid::framing::SequenceSet accepted;
+ };
+ typedef std::deque<Record> Records;
+
+ State aggregateState;
+ StateMap destinationState;
+ Records pending;
+
+ void checkPending();
+ void completed(qpid::framing::SequenceSet&);
+};
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_ACCEPTTRACKER_H*/
diff --git a/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp b/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp
new file mode 100644
index 0000000000..b70e67d12f
--- /dev/null
+++ b/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp
@@ -0,0 +1,819 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/client/amqp0_10/AddressResolution.h"
+#include "qpid/client/amqp0_10/Codecs.h"
+#include "qpid/client/amqp0_10/CodecsInternal.h"
+#include "qpid/client/amqp0_10/MessageSource.h"
+#include "qpid/client/amqp0_10/MessageSink.h"
+#include "qpid/client/amqp0_10/OutgoingMessage.h"
+#include "qpid/messaging/Address.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/Variant.h"
+#include "qpid/Exception.h"
+#include "qpid/log/Statement.h"
+#include "qpid/framing/enum.h"
+#include "qpid/framing/ExchangeBoundResult.h"
+#include "qpid/framing/ExchangeQueryResult.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/QueueQueryResult.h"
+#include "qpid/framing/ReplyTo.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/Uuid.h"
+#include <boost/assign.hpp>
+#include <boost/format.hpp>
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+using qpid::Exception;
+using qpid::messaging::Address;
+using qpid::messaging::InvalidAddress;
+using qpid::messaging::Variant;
+using qpid::framing::ExchangeBoundResult;
+using qpid::framing::ExchangeQueryResult;
+using qpid::framing::FieldTable;
+using qpid::framing::QueueQueryResult;
+using qpid::framing::ReplyTo;
+using qpid::framing::Uuid;
+using namespace qpid::framing::message;
+using namespace boost::assign;
+
+
+namespace{
+const Variant EMPTY_VARIANT;
+const FieldTable EMPTY_FIELD_TABLE;
+const std::string EMPTY_STRING;
+
+//option names
+const std::string BROWSE("browse");
+const std::string EXCLUSIVE("exclusive");
+const std::string NO_LOCAL("no-local");
+const std::string FILTER("filter");
+const std::string RELIABILITY("reliability");
+const std::string NAME("subscription-name");
+const std::string NODE_PROPERTIES("node-properties");
+const std::string X_PROPERTIES("x-properties");
+
+//policy types
+const std::string CREATE("create");
+const std::string ASSERT("assert");
+const std::string DELETE("delete");
+//policy values
+const std::string ALWAYS("always");
+const std::string NEVER("never");
+const std::string RECEIVER("receiver");
+const std::string SENDER("sender");
+
+const std::string QUEUE_ADDRESS("queue");
+const std::string TOPIC_ADDRESS("topic");
+
+const std::string UNRELIABLE("unreliable");
+const std::string AT_MOST_ONCE("at-most-once");
+const std::string AT_LEAST_ONCE("at-least-once");
+const std::string EXACTLY_ONCE("exactly-once");
+const std::string DURABLE_SUBSCRIPTION("durable");
+const std::string DURABLE("durable");
+
+const std::string TOPIC_EXCHANGE("topic");
+const std::string FANOUT_EXCHANGE("fanout");
+const std::string DIRECT_EXCHANGE("direct");
+const std::string HEADERS_EXCHANGE("headers");
+const std::string XML_EXCHANGE("xml");
+const std::string WILDCARD_ANY("*");
+}
+
+//some amqp 0-10 specific options
+namespace xamqp{
+const std::string AUTO_DELETE("auto-delete");
+const std::string EXCHANGE_TYPE("type");
+const std::string EXCLUSIVE("exclusive");
+const std::string ALTERNATE_EXCHANGE("alternate-exchange");
+const std::string QUEUE_ARGUMENTS("x-queue-arguments");
+const std::string SUBSCRIBE_ARGUMENTS("x-subscribe-arguments");
+}
+
+class Node
+{
+ protected:
+ enum CheckMode {FOR_RECEIVER, FOR_SENDER};
+
+ Node(const Address& address);
+
+ const std::string name;
+ Variant createPolicy;
+ Variant assertPolicy;
+ Variant deletePolicy;
+
+ static bool enabled(const Variant& policy, CheckMode mode);
+ static bool createEnabled(const Address& address, CheckMode mode);
+ static void convert(const Variant& option, FieldTable& arguments);
+ static std::vector<std::string> RECEIVER_MODES;
+ static std::vector<std::string> SENDER_MODES;
+};
+
+class Queue : protected Node
+{
+ public:
+ Queue(const Address& address);
+ protected:
+ void checkCreate(qpid::client::AsyncSession&, CheckMode);
+ void checkAssert(qpid::client::AsyncSession&, CheckMode);
+ void checkDelete(qpid::client::AsyncSession&, CheckMode);
+ private:
+ bool durable;
+ bool autoDelete;
+ bool exclusive;
+ std::string alternateExchange;
+ FieldTable arguments;
+
+ void configure(const Address&);
+};
+
+class Exchange : protected Node
+{
+ public:
+ Exchange(const Address& address);
+ protected:
+ void checkCreate(qpid::client::AsyncSession&, CheckMode);
+ void checkAssert(qpid::client::AsyncSession&, CheckMode);
+ void checkDelete(qpid::client::AsyncSession&, CheckMode);
+ const std::string& getDesiredExchangeType() { return type; }
+
+ private:
+ std::string type;
+ bool typeSpecified;
+ bool durable;
+ bool autoDelete;
+ std::string alternateExchange;
+ FieldTable arguments;
+
+ void configure(const Address&);
+};
+
+class QueueSource : public Queue, public MessageSource
+{
+ public:
+ QueueSource(const Address& address);
+ void subscribe(qpid::client::AsyncSession& session, const std::string& destination);
+ void cancel(qpid::client::AsyncSession& session, const std::string& destination);
+ private:
+ const AcceptMode acceptMode;
+ const AcquireMode acquireMode;
+ bool exclusive;
+ FieldTable options;
+};
+
+class Subscription : public Exchange, public MessageSource
+{
+ public:
+ Subscription(const Address&, const std::string& exchangeType="");
+ void subscribe(qpid::client::AsyncSession& session, const std::string& destination);
+ void cancel(qpid::client::AsyncSession& session, const std::string& destination);
+ private:
+ struct Binding
+ {
+ Binding(const std::string& exchange, const std::string& key, const FieldTable& options = EMPTY_FIELD_TABLE);
+
+ std::string exchange;
+ std::string key;
+ FieldTable options;
+ };
+
+ typedef std::vector<Binding> Bindings;
+
+ const std::string queue;
+ const bool reliable;
+ const bool durable;
+ FieldTable queueOptions;
+ FieldTable subscriptionOptions;
+ Bindings bindings;
+
+ void bindSpecial(const std::string& exchangeType);
+ void bind(const std::string& subject);
+ void bind(const std::string& subject, const Variant& filter);
+ void bind(const std::string& subject, const Variant::Map& filter);
+ void bind(const std::string& subject, const Variant::List& filter);
+ void add(const std::string& exchange, const std::string& key, const FieldTable& options = EMPTY_FIELD_TABLE);
+ static std::string getSubscriptionName(const std::string& base, const Variant& name);
+};
+
+class ExchangeSink : public Exchange, public MessageSink
+{
+ public:
+ ExchangeSink(const Address& name);
+ void declare(qpid::client::AsyncSession& session, const std::string& name);
+ void send(qpid::client::AsyncSession& session, const std::string& name, OutgoingMessage& message);
+ void cancel(qpid::client::AsyncSession& session, const std::string& name);
+ private:
+};
+
+class QueueSink : public Queue, public MessageSink
+{
+ public:
+ QueueSink(const Address& name);
+ void declare(qpid::client::AsyncSession& session, const std::string& name);
+ void send(qpid::client::AsyncSession& session, const std::string& name, OutgoingMessage& message);
+ void cancel(qpid::client::AsyncSession& session, const std::string& name);
+ private:
+};
+
+
+bool isQueue(qpid::client::Session session, const qpid::messaging::Address& address);
+bool isTopic(qpid::client::Session session, const qpid::messaging::Address& address);
+
+bool in(const Variant& value, const std::vector<std::string>& choices)
+{
+ if (!value.isVoid()) {
+ for (std::vector<std::string>::const_iterator i = choices.begin(); i != choices.end(); ++i) {
+ if (value.asString() == *i) return true;
+ }
+ }
+ return false;
+}
+
+bool getReceiverPolicy(const Address& address, const std::string& key)
+{
+ return in(address.getOption(key), list_of<std::string>(ALWAYS)(RECEIVER));
+}
+
+bool getSenderPolicy(const Address& address, const std::string& key)
+{
+ return in(address.getOption(key), list_of<std::string>(ALWAYS)(SENDER));
+}
+
+bool is_unreliable(const Address& address)
+{
+ return in(address.getOption(RELIABILITY), list_of<std::string>(UNRELIABLE)(AT_MOST_ONCE));
+}
+
+bool is_reliable(const Address& address)
+{
+ return in(address.getOption(RELIABILITY), list_of<std::string>(AT_LEAST_ONCE)(EXACTLY_ONCE));
+}
+
+std::string checkAddressType(qpid::client::Session session, const Address& address)
+{
+ std::string type = address.getType();
+ if (type.empty()) {
+ ExchangeBoundResult result = session.exchangeBound(arg::exchange=address.getName(), arg::queue=address.getName());
+ if (result.getQueueNotFound() && result.getExchangeNotFound()) {
+ //neither a queue nor an exchange exists with that name; treat it as a queue
+ type = QUEUE_ADDRESS;
+ } else if (result.getExchangeNotFound()) {
+ //name refers to a queue
+ type = QUEUE_ADDRESS;
+ } else if (result.getQueueNotFound()) {
+ //name refers to an exchange
+ type = TOPIC_ADDRESS;
+ } else {
+ //both a queue and exchange exist for that name
+ throw InvalidAddress("Ambiguous address, please specify queue or topic as node type");
+ }
+ }
+ return type;
+}
+
+std::auto_ptr<MessageSource> AddressResolution::resolveSource(qpid::client::Session session,
+ const Address& address)
+{
+ std::string type = checkAddressType(session, address);
+ if (type == TOPIC_ADDRESS) {
+ std::auto_ptr<MessageSource> source(new Subscription(address));
+ QPID_LOG(debug, "treating source address as topic: " << address);
+ return source;
+ } else if (type == QUEUE_ADDRESS) {
+ std::auto_ptr<MessageSource> source(new QueueSource(address));
+ QPID_LOG(debug, "treating source address as queue: " << address);
+ return source;
+ } else {
+ throw InvalidAddress("Unrecognised type: " + type);
+ }
+}
+
+
+std::auto_ptr<MessageSink> AddressResolution::resolveSink(qpid::client::Session session,
+ const qpid::messaging::Address& address)
+{
+ std::string type = checkAddressType(session, address);
+ if (type == TOPIC_ADDRESS) {
+ std::auto_ptr<MessageSink> sink(new ExchangeSink(address));
+ QPID_LOG(debug, "treating target address as topic: " << address);
+ return sink;
+ } else if (type == QUEUE_ADDRESS) {
+ std::auto_ptr<MessageSink> sink(new QueueSink(address));
+ QPID_LOG(debug, "treating target address as queue: " << address);
+ return sink;
+ } else {
+ throw InvalidAddress("Unrecognised type: " + type);
+ }
+}
+
+const Variant& getNestedOption(const Variant::Map& options, const std::vector<std::string>& keys, size_t index = 0)
+{
+ Variant::Map::const_iterator i = options.find(keys[index]);
+ if (i == options.end()) {
+ return EMPTY_VARIANT;
+ } else if (index+1 < keys.size()) {
+ return getNestedOption(i->second.asMap(), keys, index+1);
+ } else {
+ return i->second;
+ }
+}
+
+QueueSource::QueueSource(const Address& address) :
+ Queue(address),
+ acceptMode(is_unreliable(address) ? ACCEPT_MODE_NONE : ACCEPT_MODE_EXPLICIT),
+ acquireMode(address.getOption(BROWSE).asBool() ? ACQUIRE_MODE_NOT_ACQUIRED : ACQUIRE_MODE_PRE_ACQUIRED),
+ exclusive(false)
+{
+ //extract subscription arguments from address options
+ const Variant& x = address.getOption(X_PROPERTIES);
+ if (!x.isVoid()) {
+ const Variant::Map& xProps = x.asMap();
+ Variant::Map passthrough;
+ for (Variant::Map::const_iterator i = xProps.begin(); i != xProps.end(); ++i) {
+ if (i->first == xamqp::EXCLUSIVE) exclusive = i->second;
+ else passthrough[i->first] = i->second;
+ }
+ translate(passthrough, options);
+ }
+}
+
+void QueueSource::subscribe(qpid::client::AsyncSession& session, const std::string& destination)
+{
+ checkCreate(session, FOR_RECEIVER);
+ checkAssert(session, FOR_RECEIVER);
+ session.messageSubscribe(arg::queue=name,
+ arg::destination=destination,
+ arg::acceptMode=acceptMode,
+ arg::acquireMode=acquireMode,
+ arg::exclusive=exclusive,
+ arg::arguments=options);
+}
+
+void QueueSource::cancel(qpid::client::AsyncSession& session, const std::string& destination)
+{
+ session.messageCancel(destination);
+ checkDelete(session, FOR_RECEIVER);
+}
+
+std::string Subscription::getSubscriptionName(const std::string& base, const Variant& name)
+{
+ if (name.isVoid()) {
+ return (boost::format("%1%_%2%") % base % Uuid(true).str()).str();
+ } else {
+ return (boost::format("%1%_%2%") % base % name.asString()).str();
+ }
+}
+
+Subscription::Subscription(const Address& address, const std::string& exchangeType)
+ : Exchange(address),
+ queue(getSubscriptionName(name, address.getOption(NAME))),
+ reliable(is_reliable(address)),
+ durable(address.getOption(DURABLE_SUBSCRIPTION).asBool())
+{
+ if (address.getOption(NO_LOCAL).asBool()) queueOptions.setInt(NO_LOCAL, 1);
+ const Variant& x = address.getOption(X_PROPERTIES);
+ if (!x.isVoid()) {
+ const Variant::Map& xProps = x.asMap();
+ Variant::Map passthrough;
+ for (Variant::Map::const_iterator i = xProps.begin(); i != xProps.end(); ++i) {
+ if (i->first == xamqp::QUEUE_ARGUMENTS) convert(i->second.asMap(), queueOptions);
+ else passthrough[i->first] = i->second;
+ }
+ translate(passthrough, subscriptionOptions);
+ }
+
+ const Variant& filter = address.getOption(FILTER);
+ if (!filter.isVoid()) {
+ bind(address.getSubject(), filter);
+ } else if (address.hasSubject()) {
+ //Note: This will not work for headers- or xml- exchange;
+ //fanout exchange will do no filtering.
+ //TODO: for headers- or xml- exchange can construct a match
+ //for the subject in the application-headers
+ bind(address.getSubject());
+ } else {
+ //Neither a subject nor a filter has been defined, treat this
+ //as wanting to match all messages (Note: direct exchange is
+ //currently unable to support this case).
+ if (!exchangeType.empty()) bindSpecial(exchangeType);
+ else if (!getDesiredExchangeType().empty()) bindSpecial(getDesiredExchangeType());
+ }
+}
+
+void Subscription::add(const std::string& exchange, const std::string& key, const FieldTable& options)
+{
+ bindings.push_back(Binding(exchange, key, options));
+}
+
+void Subscription::subscribe(qpid::client::AsyncSession& session, const std::string& destination)
+{
+ //create exchange if required and specified by policy:
+ checkCreate(session, FOR_RECEIVER);
+ checkAssert(session, FOR_RECEIVER);
+
+ //create subscription queue:
+ session.queueDeclare(arg::queue=queue, arg::exclusive=true,
+ arg::autoDelete=!reliable, arg::durable=durable, arg::arguments=queueOptions);
+ //bind subscription queue to exchange:
+ for (Bindings::const_iterator i = bindings.begin(); i != bindings.end(); ++i) {
+ session.exchangeBind(arg::queue=queue, arg::exchange=i->exchange, arg::bindingKey=i->key, arg::arguments=i->options);
+ }
+ //subscribe to subscription queue:
+ AcceptMode accept = reliable ? ACCEPT_MODE_EXPLICIT : ACCEPT_MODE_NONE;
+ session.messageSubscribe(arg::queue=queue, arg::destination=destination,
+ arg::exclusive=true, arg::acceptMode=accept, arg::arguments=subscriptionOptions);
+}
+
+void Subscription::cancel(qpid::client::AsyncSession& session, const std::string& destination)
+{
+ session.messageCancel(destination);
+ session.queueDelete(arg::queue=queue);
+ checkDelete(session, FOR_RECEIVER);
+}
+
+Subscription::Binding::Binding(const std::string& e, const std::string& k, const FieldTable& o):
+ exchange(e), key(k), options(o) {}
+
+ExchangeSink::ExchangeSink(const Address& address) : Exchange(address) {}
+
+void ExchangeSink::declare(qpid::client::AsyncSession& session, const std::string&)
+{
+ checkCreate(session, FOR_SENDER);
+ checkAssert(session, FOR_SENDER);
+}
+
+void ExchangeSink::send(qpid::client::AsyncSession& session, const std::string&, OutgoingMessage& m)
+{
+ m.message.getDeliveryProperties().setRoutingKey(m.getSubject());
+ m.status = session.messageTransfer(arg::destination=name, arg::content=m.message);
+}
+
+void ExchangeSink::cancel(qpid::client::AsyncSession& session, const std::string&)
+{
+ checkDelete(session, FOR_SENDER);
+}
+
+QueueSink::QueueSink(const Address& address) : Queue(address) {}
+
+void QueueSink::declare(qpid::client::AsyncSession& session, const std::string&)
+{
+ checkCreate(session, FOR_SENDER);
+ checkAssert(session, FOR_SENDER);
+}
+void QueueSink::send(qpid::client::AsyncSession& session, const std::string&, OutgoingMessage& m)
+{
+ m.message.getDeliveryProperties().setRoutingKey(name);
+ m.status = session.messageTransfer(arg::content=m.message);
+}
+
+void QueueSink::cancel(qpid::client::AsyncSession& session, const std::string&)
+{
+ checkDelete(session, FOR_SENDER);
+}
+
+Address AddressResolution::convert(const qpid::framing::ReplyTo& rt)
+{
+ Address address;
+ if (rt.getExchange().empty()) {//if default exchange, treat as queue
+ address.setName(rt.getRoutingKey());
+ address.setType(QUEUE_ADDRESS);
+ } else {
+ address.setName(rt.getExchange());
+ address.setSubject(rt.getRoutingKey());
+ address.setType(TOPIC_ADDRESS);
+ }
+ return address;
+}
+
+qpid::framing::ReplyTo AddressResolution::convert(const Address& address)
+{
+ if (address.getType() == QUEUE_ADDRESS || address.getType().empty()) {
+ return ReplyTo(EMPTY_STRING, address.getName());
+ } else if (address.getType() == TOPIC_ADDRESS) {
+ return ReplyTo(address.getName(), address.getSubject());
+ } else {
+ QPID_LOG(notice, "Unrecognised type for reply-to: " << address.getType());
+ return ReplyTo(EMPTY_STRING, address.getName());//treat as queue
+ }
+}
+
+bool isQueue(qpid::client::Session session, const qpid::messaging::Address& address)
+{
+ return address.getType() == QUEUE_ADDRESS ||
+ (address.getType().empty() && session.queueQuery(address.getName()).getQueue() == address.getName());
+}
+
+bool isTopic(qpid::client::Session session, const qpid::messaging::Address& address)
+{
+ if (address.getType().empty()) {
+ return !session.exchangeQuery(address.getName()).getNotFound();
+ } else if (address.getType() == TOPIC_ADDRESS) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void Subscription::bind(const std::string& subject)
+{
+ add(name, subject);
+}
+
+void Subscription::bind(const std::string& subject, const Variant& filter)
+{
+ switch (filter.getType()) {
+ case qpid::messaging::VAR_MAP:
+ bind(subject, filter.asMap());
+ break;
+ case qpid::messaging::VAR_LIST:
+ bind(subject, filter.asList());
+ break;
+ default:
+ //TODO: if both subject _and_ filter are specified, combine in
+ //some way; for now we just ignore the subject in that case.
+ add(name, filter.asString());
+ break;
+ }
+}
+
+void Subscription::bind(const std::string& subject, const Variant::Map& filter)
+{
+ qpid::framing::FieldTable arguments;
+ translate(filter, arguments);
+ add(name, subject.empty() ? queue : subject, arguments);
+}
+
+void Subscription::bind(const std::string& subject, const Variant::List& filter)
+{
+ for (Variant::List::const_iterator i = filter.begin(); i != filter.end(); ++i) {
+ bind(subject, *i);
+ }
+}
+
+void Subscription::bindSpecial(const std::string& exchangeType)
+{
+ if (exchangeType == TOPIC_EXCHANGE) {
+ add(name, WILDCARD_ANY);
+ } else if (exchangeType == FANOUT_EXCHANGE) {
+ add(name, queue);
+ } else if (exchangeType == HEADERS_EXCHANGE) {
+ //TODO: add special binding for headers exchange to match all messages
+ } else if (exchangeType == XML_EXCHANGE) {
+ //TODO: add special binding for xml exchange to match all messages
+ } else { //E.g. direct
+ throw qpid::Exception(QPID_MSG("Cannot create binding to match all messages for exchange of type " << exchangeType));
+ }
+}
+
+Node::Node(const Address& address) : name(address.getName()),
+ createPolicy(address.getOption(CREATE)),
+ assertPolicy(address.getOption(ASSERT)),
+ deletePolicy(address.getOption(DELETE)) {}
+
+Queue::Queue(const Address& a) : Node(a),
+ durable(false),
+ autoDelete(false),
+ exclusive(false)
+{
+ configure(a);
+}
+
+void Queue::checkCreate(qpid::client::AsyncSession& session, CheckMode mode)
+{
+ if (enabled(createPolicy, mode)) {
+ QPID_LOG(debug, "Auto-creating queue '" << name << "'");
+ try {
+ sync(session).queueDeclare(arg::queue=name,
+ arg::durable=durable,
+ arg::autoDelete=autoDelete,
+ arg::exclusive=exclusive,
+ arg::alternateExchange=alternateExchange,
+ arg::arguments=arguments);
+ } catch (const qpid::Exception& e) {
+ throw InvalidAddress((boost::format("Could not create queue %1%; %2%") % name % e.what()).str());
+ }
+ } else {
+ try {
+ sync(session).queueDeclare(arg::queue=name, arg::passive=true);
+ } catch (const qpid::framing::NotFoundException& /*e*/) {
+ throw InvalidAddress((boost::format("Queue %1% does not exist") % name).str());
+ } catch (const std::exception& e) {
+ throw InvalidAddress(e.what());
+ }
+ }
+}
+
+void Queue::checkDelete(qpid::client::AsyncSession& session, CheckMode mode)
+{
+ //Note: queue-delete will cause a session exception if the queue
+ //does not exist, the query here prevents obvious cases of this
+ //but there is a race whenever two deletions are made concurrently
+ //so careful use of the delete policy is recommended at present
+ if (enabled(deletePolicy, mode) && sync(session).queueQuery(name).getQueue() == name) {
+ QPID_LOG(debug, "Auto-deleting queue '" << name << "'");
+ sync(session).queueDelete(arg::queue=name);
+ }
+}
+
+void Queue::checkAssert(qpid::client::AsyncSession& session, CheckMode mode)
+{
+ if (enabled(assertPolicy, mode)) {
+ QueueQueryResult result = sync(session).queueQuery(name);
+ if (result.getQueue() != name) {
+ throw InvalidAddress((boost::format("Queue not found: %1%") % name).str());
+ } else {
+ if (durable && !result.getDurable()) {
+ throw InvalidAddress((boost::format("Queue not durable: %1%") % name).str());
+ }
+ if (autoDelete && !result.getAutoDelete()) {
+ throw InvalidAddress((boost::format("Queue not set to auto-delete: %1%") % name).str());
+ }
+ if (exclusive && !result.getExclusive()) {
+ throw InvalidAddress((boost::format("Queue not exclusive: %1%") % name).str());
+ }
+ if (!alternateExchange.empty() && result.getAlternateExchange() != alternateExchange) {
+ throw InvalidAddress((boost::format("Alternate exchange does not match for %1%, expected %2%, got %3%")
+ % name % alternateExchange % result.getAlternateExchange()).str());
+ }
+ for (FieldTable::ValueMap::const_iterator i = arguments.begin(); i != arguments.end(); ++i) {
+ FieldTable::ValuePtr v = result.getArguments().get(i->first);
+ if (!v) {
+ throw InvalidAddress((boost::format("Option %1% not set for %2%") % i->first % name).str());
+ } else if (*i->second != *v) {
+ throw InvalidAddress((boost::format("Option %1% does not match for %2%, expected %3%, got %4%")
+ % i->first % name % *(i->second) % *v).str());
+ }
+ }
+ }
+ }
+}
+
+void Queue::configure(const Address& address)
+{
+ const Variant& v = address.getOption(NODE_PROPERTIES);
+ if (!v.isVoid()) {
+ Variant::Map nodeProps = v.asMap();
+ durable = nodeProps[DURABLE];
+ Variant::Map::const_iterator x = nodeProps.find(X_PROPERTIES);
+ if (x != nodeProps.end()) {
+ const Variant::Map& xProps = x->second.asMap();
+ Variant::Map passthrough;
+ for (Variant::Map::const_iterator i = xProps.begin(); i != xProps.end(); ++i) {
+ if (i->first == xamqp::AUTO_DELETE) autoDelete = i->second;
+ else if (i->first == xamqp::EXCLUSIVE) exclusive = i->second;
+ else if (i->first == xamqp::ALTERNATE_EXCHANGE) alternateExchange = i->second.asString();
+ else passthrough[i->first] = i->second;
+ }
+ translate(passthrough, arguments);
+ }
+ }
+}
+
+Exchange::Exchange(const Address& a) : Node(a),
+ type(TOPIC_EXCHANGE),
+ typeSpecified(false),
+ durable(false),
+ autoDelete(false)
+{
+ configure(a);
+}
+
+void Exchange::checkCreate(qpid::client::AsyncSession& session, CheckMode mode)
+{
+ if (enabled(createPolicy, mode)) {
+ try {
+ sync(session).exchangeDeclare(arg::exchange=name,
+ arg::type=type,
+ arg::durable=durable,
+ arg::autoDelete=autoDelete,
+ arg::alternateExchange=alternateExchange,
+ arg::arguments=arguments);
+ } catch (const qpid::Exception& e) {
+ throw InvalidAddress((boost::format("Could not create exchange %1%; %2%") % name % e.what()).str());
+ }
+ } else {
+ try {
+ sync(session).exchangeDeclare(arg::exchange=name, arg::passive=true);
+ } catch (const qpid::framing::NotFoundException& /*e*/) {
+ throw InvalidAddress((boost::format("Exchange %1% does not exist") % name).str());
+ } catch (const std::exception& e) {
+ throw InvalidAddress(e.what());
+ }
+ }
+}
+
+void Exchange::checkDelete(qpid::client::AsyncSession& session, CheckMode mode)
+{
+ //Note: exchange-delete will cause a session exception if the
+ //exchange does not exist, the query here prevents obvious cases
+ //of this but there is a race whenever two deletions are made
+ //concurrently so careful use of the delete policy is recommended
+ //at present
+ if (enabled(deletePolicy, mode) && !sync(session).exchangeQuery(name).getNotFound()) {
+ sync(session).exchangeDelete(arg::exchange=name);
+ }
+}
+
+void Exchange::checkAssert(qpid::client::AsyncSession& session, CheckMode mode)
+{
+ if (enabled(assertPolicy, mode)) {
+ ExchangeQueryResult result = sync(session).exchangeQuery(name);
+ if (result.getNotFound()) {
+ throw InvalidAddress((boost::format("Exchange not found: %1%") % name).str());
+ } else {
+ if (typeSpecified && result.getType() != type) {
+ throw InvalidAddress((boost::format("Exchange %1% is of incorrect type, expected %2% but got %3%")
+ % name % type % result.getType()).str());
+ }
+ if (durable && !result.getDurable()) {
+ throw InvalidAddress((boost::format("Exchange not durable: %1%") % name).str());
+ }
+ //Note: Can't check auto-delete or alternate-exchange via
+ //exchange-query-result as these are not returned
+ //TODO: could use a passive declare to check alternate-exchange
+ for (FieldTable::ValueMap::const_iterator i = arguments.begin(); i != arguments.end(); ++i) {
+ FieldTable::ValuePtr v = result.getArguments().get(i->first);
+ if (!v) {
+ throw InvalidAddress((boost::format("Option %1% not set for %2%") % i->first % name).str());
+ } else if (i->second != v) {
+ throw InvalidAddress((boost::format("Option %1% does not match for %2%, expected %3%, got %4%")
+ % i->first % name % *(i->second) % *v).str());
+ }
+ }
+ }
+ }
+}
+
+void Exchange::configure(const Address& address)
+{
+ const Variant& v = address.getOption(NODE_PROPERTIES);
+ if (!v.isVoid()) {
+ Variant::Map nodeProps = v.asMap();
+ durable = nodeProps[DURABLE];
+ Variant::Map::const_iterator x = nodeProps.find(X_PROPERTIES);
+ if (x != nodeProps.end()) {
+ const Variant::Map& xProps = x->second.asMap();
+ Variant::Map passthrough;
+ for (Variant::Map::const_iterator i = xProps.begin(); i != xProps.end(); ++i) {
+ if (i->first == xamqp::AUTO_DELETE) autoDelete = i->second;
+ else if (i->first == xamqp::EXCHANGE_TYPE) { type = i->second.asString(); typeSpecified = true; }
+ else if (i->first == xamqp::ALTERNATE_EXCHANGE) alternateExchange = i->second.asString();
+ else passthrough[i->first] = i->second;
+ }
+ translate(passthrough, arguments);
+ }
+ }
+}
+
+
+bool Node::enabled(const Variant& policy, CheckMode mode)
+{
+ bool result = false;
+ switch (mode) {
+ case FOR_RECEIVER:
+ result = in(policy, RECEIVER_MODES);
+ break;
+ case FOR_SENDER:
+ result = in(policy, SENDER_MODES);
+ break;
+ }
+ return result;
+}
+
+bool Node::createEnabled(const Address& address, CheckMode mode)
+{
+ const Variant& policy = address.getOption(CREATE);
+ return enabled(policy, mode);
+}
+
+void Node::convert(const Variant& options, FieldTable& arguments)
+{
+ if (!options.isVoid()) {
+ translate(options.asMap(), arguments);
+ }
+}
+std::vector<std::string> Node::RECEIVER_MODES = list_of<std::string>(ALWAYS) (RECEIVER);
+std::vector<std::string> Node::SENDER_MODES = list_of<std::string>(ALWAYS) (SENDER);
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/cpp/src/qpid/client/amqp0_10/AddressResolution.h b/cpp/src/qpid/client/amqp0_10/AddressResolution.h
new file mode 100644
index 0000000000..01c8c51595
--- /dev/null
+++ b/cpp/src/qpid/client/amqp0_10/AddressResolution.h
@@ -0,0 +1,64 @@
+#ifndef QPID_CLIENT_AMQP0_10_ADDRESSRESOLUTION_H
+#define QPID_CLIENT_AMQP0_10_ADDRESSRESOLUTION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/Variant.h"
+#include "qpid/client/Session.h"
+
+namespace qpid {
+
+namespace framing{
+class ReplyTo;
+}
+
+namespace messaging {
+class Address;
+}
+
+namespace client {
+namespace amqp0_10 {
+
+class MessageSource;
+class MessageSink;
+
+/**
+ * Maps from a generic Address and optional Filter to an AMQP 0-10
+ * MessageSource which will then be used by a ReceiverImpl instance
+ * created for the address.
+ */
+class AddressResolution
+{
+ public:
+ std::auto_ptr<MessageSource> resolveSource(qpid::client::Session session,
+ const qpid::messaging::Address& address);
+
+ std::auto_ptr<MessageSink> resolveSink(qpid::client::Session session,
+ const qpid::messaging::Address& address);
+
+ static qpid::messaging::Address convert(const qpid::framing::ReplyTo&);
+ static qpid::framing::ReplyTo convert(const qpid::messaging::Address&);
+
+ private:
+};
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_ADDRESSRESOLUTION_H*/
diff --git a/cpp/src/qpid/client/amqp0_10/Codecs.cpp b/cpp/src/qpid/client/amqp0_10/Codecs.cpp
new file mode 100644
index 0000000000..ff72dfbf4e
--- /dev/null
+++ b/cpp/src/qpid/client/amqp0_10/Codecs.cpp
@@ -0,0 +1,299 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/client/amqp0_10/Codecs.h"
+#include "qpid/messaging/Variant.h"
+#include "qpid/framing/Array.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/FieldValue.h"
+#include "qpid/framing/List.h"
+#include <algorithm>
+#include <functional>
+
+using namespace qpid::framing;
+using namespace qpid::messaging;
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+namespace {
+const std::string iso885915("iso-8859-15");
+const std::string utf8("utf8");
+const std::string utf16("utf16");
+const std::string amqp0_10_binary("amqp0-10:binary");
+const std::string amqp0_10_bit("amqp0-10:bit");
+const std::string amqp0_10_datetime("amqp0-10:datetime");
+const std::string amqp0_10_struct("amqp0-10:struct");
+}
+
+template <class T, class U, class F> void convert(const T& from, U& to, F f)
+{
+ std::transform(from.begin(), from.end(), std::inserter(to, to.begin()), f);
+}
+
+Variant::Map::value_type toVariantMapEntry(const FieldTable::value_type& in);
+FieldTable::value_type toFieldTableEntry(const Variant::Map::value_type& in);
+Variant toVariant(boost::shared_ptr<FieldValue> in);
+boost::shared_ptr<FieldValue> toFieldValue(const Variant& in);
+
+template <class T, class U, class F> void translate(boost::shared_ptr<FieldValue> in, U& u, F f)
+{
+ T t;
+ getEncodedValue<T>(in, t);
+ convert(t, u, f);
+}
+
+template <class T, class U, class F> T* toFieldValueCollection(const U& u, F f)
+{
+ typename T::ValueType t;
+ convert(u, t, f);
+ return new T(t);
+}
+
+FieldTableValue* toFieldTableValue(const Variant::Map& map)
+{
+ FieldTable ft;
+ convert(map, ft, &toFieldTableEntry);
+ return new FieldTableValue(ft);
+}
+
+ListValue* toListValue(const Variant::List& list)
+{
+ List l;
+ convert(list, l, &toFieldValue);
+ return new ListValue(l);
+}
+
+void setEncodingFor(Variant& out, uint8_t code)
+{
+ switch(code){
+ case 0x80:
+ case 0x90:
+ case 0xa0:
+ out.setEncoding(amqp0_10_binary);
+ break;
+ case 0x84:
+ case 0x94:
+ out.setEncoding(iso885915);
+ break;
+ case 0x85:
+ case 0x95:
+ out.setEncoding(utf8);
+ break;
+ case 0x86:
+ case 0x96:
+ out.setEncoding(utf16);
+ break;
+ case 0xab:
+ out.setEncoding(amqp0_10_struct);
+ break;
+ default:
+ //do nothing
+ break;
+ }
+}
+
+Variant toVariant(boost::shared_ptr<FieldValue> in)
+{
+ Variant out;
+ //based on AMQP 0-10 typecode, pick most appropriate variant type
+ switch (in->getType()) {
+ //Fixed Width types:
+ case 0x01: out.setEncoding(amqp0_10_binary);
+ case 0x02: out = in->getIntegerValue<int8_t, 1>(); break;
+ case 0x03: out = in->getIntegerValue<uint8_t, 1>(); break;
+ case 0x04: break; //TODO: iso-8859-15 char
+ case 0x08: out = in->getIntegerValue<bool, 1>(); break;
+ case 0x010: out.setEncoding(amqp0_10_binary);
+ case 0x011: out = in->getIntegerValue<int16_t, 2>(); break;
+ case 0x012: out = in->getIntegerValue<uint16_t, 2>(); break;
+ case 0x020: out.setEncoding(amqp0_10_binary);
+ case 0x021: out = in->getIntegerValue<int32_t, 4>(); break;
+ case 0x022: out = in->getIntegerValue<uint32_t, 4>(); break;
+ case 0x023: out = in->get<float>(); break;
+ case 0x027: break; //TODO: utf-32 char
+ case 0x030: out.setEncoding(amqp0_10_binary);
+ case 0x031: out = in->getIntegerValue<int64_t, 8>(); break;
+ case 0x038: out.setEncoding(amqp0_10_datetime); //treat datetime as uint64_t, but set encoding
+ case 0x032: out = in->getIntegerValue<uint64_t, 8>(); break;
+ case 0x033:out = in->get<double>(); break;
+
+ //TODO: figure out whether and how to map values with codes 0x40-0xd8
+
+ case 0xf0: break;//void, which is the default value for Variant
+ case 0xf1: out.setEncoding(amqp0_10_bit); break;//treat 'bit' as void, which is the default value for Variant
+
+ //Variable Width types:
+ //strings:
+ case 0x80:
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x90:
+ case 0x94:
+ case 0x95:
+ case 0x96:
+ case 0xa0:
+ case 0xab:
+ setEncodingFor(out, in->getType());
+ out = in->get<std::string>();
+ break;
+
+ case 0xa8:
+ out = Variant::Map();
+ translate<FieldTable>(in, out.asMap(), &toVariantMapEntry);
+ break;
+
+ case 0xa9:
+ out = Variant::List();
+ translate<List>(in, out.asList(), &toVariant);
+ break;
+ case 0xaa: //convert amqp0-10 array into variant list
+ out = Variant::List();
+ translate<Array>(in, out.asList(), &toVariant);
+ break;
+
+ default:
+ //error?
+ break;
+ }
+ return out;
+}
+
+boost::shared_ptr<FieldValue> toFieldValue(const Variant& in)
+{
+ boost::shared_ptr<FieldValue> out;
+ switch (in.getType()) {
+ case VAR_VOID: out = boost::shared_ptr<FieldValue>(new VoidValue()); break;
+ case VAR_BOOL: out = boost::shared_ptr<FieldValue>(new BoolValue(in.asBool())); break;
+ case VAR_UINT8: out = boost::shared_ptr<FieldValue>(new Unsigned8Value(in.asUint8())); break;
+ case VAR_UINT16: out = boost::shared_ptr<FieldValue>(new Unsigned16Value(in.asUint16())); break;
+ case VAR_UINT32: out = boost::shared_ptr<FieldValue>(new Unsigned32Value(in.asUint32())); break;
+ case VAR_UINT64: out = boost::shared_ptr<FieldValue>(new Unsigned64Value(in.asUint64())); break;
+ case VAR_INT8: out = boost::shared_ptr<FieldValue>(new Integer8Value(in.asInt8())); break;
+ case VAR_INT16: out = boost::shared_ptr<FieldValue>(new Integer16Value(in.asInt16())); break;
+ case VAR_INT32: out = boost::shared_ptr<FieldValue>(new Integer32Value(in.asInt32())); break;
+ case VAR_INT64: out = boost::shared_ptr<FieldValue>(new Integer64Value(in.asInt64())); break;
+ case VAR_FLOAT: out = boost::shared_ptr<FieldValue>(new FloatValue(in.asFloat())); break;
+ case VAR_DOUBLE: out = boost::shared_ptr<FieldValue>(new DoubleValue(in.asDouble())); break;
+ //TODO: check encoding (and length?) when deciding what AMQP type to treat string as
+ case VAR_STRING: out = boost::shared_ptr<FieldValue>(new Str16Value(in.asString())); break;
+ case VAR_MAP:
+ //out = boost::shared_ptr<FieldValue>(toFieldValueCollection<FieldTableValue>(in.asMap(), &toFieldTableEntry));
+ out = boost::shared_ptr<FieldValue>(toFieldTableValue(in.asMap()));
+ break;
+ case VAR_LIST:
+ //out = boost::shared_ptr<FieldValue>(toFieldValueCollection<ListValue>(in.asList(), &toFieldValue));
+ out = boost::shared_ptr<FieldValue>(toListValue(in.asList()));
+ break;
+ }
+ return out;
+}
+
+Variant::Map::value_type toVariantMapEntry(const FieldTable::value_type& in)
+{
+ return Variant::Map::value_type(in.first, toVariant(in.second));
+}
+
+FieldTable::value_type toFieldTableEntry(const Variant::Map::value_type& in)
+{
+ return FieldTable::value_type(in.first, toFieldValue(in.second));
+}
+
+struct EncodeBuffer
+{
+ char* data;
+ Buffer buffer;
+
+ EncodeBuffer(size_t size) : data(new char[size]), buffer(data, size) {}
+ ~EncodeBuffer() { delete[] data; }
+
+ template <class T> void encode(T& t) { t.encode(buffer); }
+
+ void getData(std::string& s) {
+ s.assign(data, buffer.getSize());
+ }
+};
+
+struct DecodeBuffer
+{
+ Buffer buffer;
+
+ DecodeBuffer(const std::string& s) : buffer(const_cast<char*>(s.data()), s.size()) {}
+
+ template <class T> void decode(T& t) { t.decode(buffer); }
+
+};
+
+template <class T, class U, class F> void _encode(const U& value, std::string& data, F f)
+{
+ T t;
+ convert(value, t, f);
+ EncodeBuffer buffer(t.encodedSize());
+ buffer.encode(t);
+ buffer.getData(data);
+}
+
+template <class T, class U, class F> void _decode(const std::string& data, U& value, F f)
+{
+ T t;
+ DecodeBuffer buffer(data);
+ buffer.decode(t);
+ convert(t, value, f);
+}
+
+void MapCodec::encode(const Variant& value, std::string& data)
+{
+ _encode<FieldTable>(value.asMap(), data, &toFieldTableEntry);
+}
+
+void MapCodec::decode(const std::string& data, Variant& value)
+{
+ value = Variant::Map();
+ _decode<FieldTable>(data, value.asMap(), &toVariantMapEntry);
+}
+
+void ListCodec::encode(const Variant& value, std::string& data)
+{
+ _encode<List>(value.asList(), data, &toFieldValue);
+}
+
+void ListCodec::decode(const std::string& data, Variant& value)
+{
+ value = Variant::List();
+ _decode<List>(data, value.asList(), &toVariant);
+}
+
+void translate(const Variant::Map& from, FieldTable& to)
+{
+ convert(from, to, &toFieldTableEntry);
+}
+
+void translate(const FieldTable& from, Variant::Map& to)
+{
+ convert(from, to, &toVariantMapEntry);
+}
+
+const std::string ListCodec::contentType("amqp/list");
+const std::string MapCodec::contentType("amqp/map");
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/cpp/src/qpid/client/amqp0_10/CodecsInternal.h b/cpp/src/qpid/client/amqp0_10/CodecsInternal.h
new file mode 100644
index 0000000000..b5a561a9c3
--- /dev/null
+++ b/cpp/src/qpid/client/amqp0_10/CodecsInternal.h
@@ -0,0 +1,41 @@
+#ifndef QPID_CLIENT_AMQP0_10_CODECSINTERNAL_H
+#define QPID_CLIENT_AMQP0_10_CODECSINTERNAL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/Variant.h"
+#include "qpid/framing/FieldTable.h"
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+/**
+ * Declarations of a couple of conversion functions implemented in
+ * Codecs.cpp but not exposed through API
+ */
+
+void translate(const qpid::messaging::Variant::Map& from, qpid::framing::FieldTable& to);
+void translate(const qpid::framing::FieldTable& from, qpid::messaging::Variant::Map& to);
+
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_CODECSINTERNAL_H*/
diff --git a/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp b/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp
new file mode 100644
index 0000000000..cd5c0214e3
--- /dev/null
+++ b/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp
@@ -0,0 +1,208 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "ConnectionImpl.h"
+#include "SessionImpl.h"
+#include "qpid/messaging/Session.h"
+#include "qpid/client/PrivateImplRef.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/log/Statement.h"
+#include <boost/intrusive_ptr.hpp>
+#include <vector>
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+using qpid::messaging::Variant;
+using qpid::framing::Uuid;
+using namespace qpid::sys;
+
+template <class T> void setIfFound(const Variant::Map& map, const std::string& key, T& value)
+{
+ Variant::Map::const_iterator i = map.find(key);
+ if (i != map.end()) {
+ value = (T) i->second;
+ }
+}
+
+void convert(const Variant::Map& from, ConnectionSettings& to)
+{
+ setIfFound(from, "username", to.username);
+ setIfFound(from, "password", to.password);
+ setIfFound(from, "sasl-mechanism", to.mechanism);
+ setIfFound(from, "sasl-service", to.service);
+ setIfFound(from, "sasl-min-ssf", to.minSsf);
+ setIfFound(from, "sasl-max-ssf", to.maxSsf);
+
+ setIfFound(from, "heartbeat", to.heartbeat);
+ setIfFound(from, "tcp-nodelay", to.tcpNoDelay);
+
+ setIfFound(from, "locale", to.locale);
+ setIfFound(from, "max-channels", to.maxChannels);
+ setIfFound(from, "max-frame-size", to.maxFrameSize);
+ setIfFound(from, "bounds", to.bounds);
+}
+
+ConnectionImpl::ConnectionImpl(const std::string& u, const Variant::Map& options) :
+ url(u), reconnectionEnabled(true), timeout(-1),
+ minRetryInterval(1), maxRetryInterval(30)
+{
+ QPID_LOG(debug, "Opening connection to " << url << " with " << options);
+ convert(options, settings);
+ setIfFound(options, "reconnection-enabled", reconnectionEnabled);
+ setIfFound(options, "reconnection-timeout", timeout);
+ setIfFound(options, "min-retry-interval", minRetryInterval);
+ setIfFound(options, "max-retry-interval", maxRetryInterval);
+ connection.open(url, settings);
+}
+
+void ConnectionImpl::close()
+{
+ std::vector<std::string> names;
+ {
+ qpid::sys::Mutex::ScopedLock l(lock);
+ for (Sessions::const_iterator i = sessions.begin(); i != sessions.end(); ++i) names.push_back(i->first);
+ }
+ for (std::vector<std::string>::const_iterator i = names.begin(); i != names.end(); ++i) {
+ getSession(*i).close();
+ }
+
+ qpid::sys::Mutex::ScopedLock l(lock);
+ connection.close();
+}
+
+boost::intrusive_ptr<SessionImpl> getImplPtr(qpid::messaging::Session& session)
+{
+ return boost::dynamic_pointer_cast<SessionImpl>(
+ qpid::client::PrivateImplRef<qpid::messaging::Session>::get(session)
+ );
+}
+
+void ConnectionImpl::closed(SessionImpl& s)
+{
+ qpid::sys::Mutex::ScopedLock l(lock);
+ for (Sessions::iterator i = sessions.begin(); i != sessions.end(); ++i) {
+ if (getImplPtr(i->second).get() == &s) {
+ sessions.erase(i);
+ break;
+ }
+ }
+}
+
+qpid::messaging::Session ConnectionImpl::getSession(const std::string& name) const
+{
+ qpid::sys::Mutex::ScopedLock l(lock);
+ Sessions::const_iterator i = sessions.find(name);
+ if (i == sessions.end()) {
+ throw qpid::messaging::KeyError("No such session: " + name);
+ } else {
+ return i->second;
+ }
+}
+
+qpid::messaging::Session ConnectionImpl::newSession(bool transactional, const std::string& n)
+{
+ std::string name = n.empty() ? Uuid(true).str() : n;
+ qpid::messaging::Session impl(new SessionImpl(*this, transactional));
+ {
+ qpid::sys::Mutex::ScopedLock l(lock);
+ sessions[name] = impl;
+ }
+ try {
+ getImplPtr(impl)->setSession(connection.newSession(name));
+ } catch (const TransportFailure&) {
+ reconnect();
+ }
+ return impl;
+}
+
+void ConnectionImpl::reconnect()
+{
+ AbsTime start = now();
+ ScopedLock<Semaphore> l(semaphore);
+ if (!connection.isOpen()) connect(start);
+}
+
+bool expired(const AbsTime& start, int timeout)
+{
+ if (timeout == 0) return true;
+ if (timeout < 0) return false;
+ Duration used(start, now());
+ Duration allowed = timeout * TIME_SEC;
+ return allowed > used;
+}
+
+void ConnectionImpl::connect(const AbsTime& started)
+{
+ for (int i = minRetryInterval; !tryConnect(); i = std::min(i * 2, maxRetryInterval)) {
+ if (expired(started, timeout)) throw TransportFailure();
+ else qpid::sys::sleep(i);
+ }
+}
+
+bool ConnectionImpl::tryConnect()
+{
+ if (tryConnect(url) ||
+ (failoverListener.get() && tryConnect(failoverListener->getKnownBrokers())))
+ {
+ return resetSessions();
+ } else {
+ return false;
+ }
+}
+
+bool ConnectionImpl::tryConnect(const Url& u)
+{
+ try {
+ QPID_LOG(info, "Trying to connect to " << url << "...");
+ connection.open(u, settings);
+ failoverListener.reset(new FailoverListener(connection));
+ return true;
+ } catch (const Exception& e) {
+ //TODO: need to fix timeout on open so that it throws TransportFailure
+ QPID_LOG(info, "Failed to connect to " << u << ": " << e.what());
+ }
+ return false;
+}
+
+bool ConnectionImpl::tryConnect(const std::vector<Url>& urls)
+{
+ for (std::vector<Url>::const_iterator i = urls.begin(); i != urls.end(); ++i) {
+ if (tryConnect(*i)) return true;
+ }
+ return false;
+}
+
+bool ConnectionImpl::resetSessions()
+{
+ try {
+ qpid::sys::Mutex::ScopedLock l(lock);
+ for (Sessions::iterator i = sessions.begin(); i != sessions.end(); ++i) {
+ getImplPtr(i->second)->setSession(connection.newSession(i->first));
+ }
+ return true;
+ } catch (const TransportFailure&) {
+ QPID_LOG(debug, "Connection failed while re-inialising sessions");
+ return false;
+ }
+}
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h b/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h
new file mode 100644
index 0000000000..979cc6c82a
--- /dev/null
+++ b/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h
@@ -0,0 +1,72 @@
+#ifndef QPID_CLIENT_AMQP0_10_CONNECTIONIMPL_H
+#define QPID_CLIENT_AMQP0_10_CONNECTIONIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/ConnectionImpl.h"
+#include "qpid/messaging/Variant.h"
+#include "qpid/Url.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/FailoverListener.h"
+#include "qpid/client/ConnectionSettings.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Semaphore.h"
+#include <map>
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+class SessionImpl;
+
+class ConnectionImpl : public qpid::messaging::ConnectionImpl
+{
+ public:
+ ConnectionImpl(const std::string& url, const qpid::messaging::Variant::Map& options);
+ void close();
+ qpid::messaging::Session newSession(bool transactional, const std::string& name);
+ qpid::messaging::Session getSession(const std::string& name) const;
+ void closed(SessionImpl&);
+ void reconnect();
+ private:
+ typedef std::map<std::string, qpid::messaging::Session> Sessions;
+
+ mutable qpid::sys::Mutex lock;//used to protect data structures
+ qpid::sys::Semaphore semaphore;//used to coordinate reconnection
+ Sessions sessions;
+ qpid::client::Connection connection;
+ std::auto_ptr<FailoverListener> failoverListener;
+ qpid::Url url;
+ qpid::client::ConnectionSettings settings;
+ bool reconnectionEnabled;
+ int timeout;
+ int minRetryInterval;
+ int maxRetryInterval;
+
+ void connect(const qpid::sys::AbsTime& started);
+ bool tryConnect();
+ bool tryConnect(const std::vector<Url>& urls);
+ bool tryConnect(const Url&);
+ bool resetSessions();
+};
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_CONNECTIONIMPL_H*/
diff --git a/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp b/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp
new file mode 100644
index 0000000000..e66dc5915c
--- /dev/null
+++ b/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp
@@ -0,0 +1,303 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/client/amqp0_10/IncomingMessages.h"
+#include "qpid/client/amqp0_10/AddressResolution.h"
+#include "qpid/client/amqp0_10/Codecs.h"
+#include "qpid/client/amqp0_10/CodecsInternal.h"
+#include "qpid/client/SessionImpl.h"
+#include "qpid/client/SessionBase_0_10Access.h"
+#include "qpid/log/Statement.h"
+#include "qpid/messaging/Address.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/MessageImpl.h"
+#include "qpid/messaging/Variant.h"
+#include "qpid/framing/DeliveryProperties.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/framing/MessageProperties.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/enum.h"
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+using namespace qpid::framing;
+using namespace qpid::framing::message;
+using qpid::sys::AbsTime;
+using qpid::sys::Duration;
+using qpid::messaging::MessageImplAccess;
+using qpid::messaging::Variant;
+
+namespace {
+const std::string EMPTY_STRING;
+
+
+struct GetNone : IncomingMessages::Handler
+{
+ bool accept(IncomingMessages::MessageTransfer&) { return false; }
+};
+
+struct GetAny : IncomingMessages::Handler
+{
+ bool accept(IncomingMessages::MessageTransfer& transfer)
+ {
+ transfer.retrieve(0);
+ return true;
+ }
+};
+
+struct MatchAndTrack
+{
+ const std::string destination;
+ SequenceSet ids;
+
+ MatchAndTrack(const std::string& d) : destination(d) {}
+
+ bool operator()(boost::shared_ptr<qpid::framing::FrameSet> command)
+ {
+ if (command->as<MessageTransferBody>()->getDestination() == destination) {
+ ids.add(command->getId());
+ return true;
+ } else {
+ return false;
+ }
+ }
+};
+
+struct Match
+{
+ const std::string destination;
+ uint32_t matched;
+
+ Match(const std::string& d) : destination(d), matched(0) {}
+
+ bool operator()(boost::shared_ptr<qpid::framing::FrameSet> command)
+ {
+ if (command->as<MessageTransferBody>()->getDestination() == destination) {
+ ++matched;
+ return true;
+ } else {
+ return false;
+ }
+ }
+};
+}
+
+void IncomingMessages::setSession(qpid::client::AsyncSession s)
+{
+ session = s;
+ incoming = SessionBase_0_10Access(session).get()->getDemux().getDefault();
+ acceptTracker.reset();
+}
+
+bool IncomingMessages::get(Handler& handler, Duration timeout)
+{
+ //search through received list for any transfer of interest:
+ for (FrameSetQueue::iterator i = received.begin(); i != received.end(); i++)
+ {
+ MessageTransfer transfer(*i, *this);
+ if (handler.accept(transfer)) {
+ received.erase(i);
+ return true;
+ }
+ }
+ //none found, check incoming:
+ return process(&handler, timeout);
+}
+
+bool IncomingMessages::getNextDestination(std::string& destination, Duration timeout)
+{
+ //if there is not already a received message, we must wait for one
+ if (received.empty() && !wait(timeout)) return false;
+ //else we have a message in received; return the corresponding destination
+ destination = received.front()->as<MessageTransferBody>()->getDestination();
+ return true;
+}
+
+void IncomingMessages::accept()
+{
+ acceptTracker.accept(session);
+}
+
+void IncomingMessages::releaseAll()
+{
+ //first process any received messages...
+ while (!received.empty()) {
+ retrieve(received.front(), 0);
+ received.pop_front();
+ }
+ //then pump out any available messages from incoming queue...
+ GetAny handler;
+ while (process(&handler, 0)) ;
+ //now release all messages
+ acceptTracker.release(session);
+}
+
+void IncomingMessages::releasePending(const std::string& destination)
+{
+ //first pump all available messages from incoming to received...
+ while (process(0, 0)) ;
+
+ //now remove all messages for this destination from received list, recording their ids...
+ MatchAndTrack match(destination);
+ for (FrameSetQueue::iterator i = received.begin(); i != received.end(); i = match(*i) ? received.erase(i) : ++i) ;
+ //now release those messages
+ session.messageRelease(match.ids);
+}
+
+/**
+ * Get a frameset that is accepted by the specified handler from
+ * session queue, waiting for up to the specified duration and
+ * returning true if this could be achieved, false otherwise. Messages
+ * that are not accepted by the handler are pushed onto received queue
+ * for later retrieval.
+ */
+bool IncomingMessages::process(Handler* handler, qpid::sys::Duration duration)
+{
+ AbsTime deadline(AbsTime::now(), duration);
+ FrameSet::shared_ptr content;
+ for (Duration timeout = duration; incoming->pop(content, timeout); timeout = Duration(AbsTime::now(), deadline)) {
+ if (content->isA<MessageTransferBody>()) {
+ MessageTransfer transfer(content, *this);
+ if (handler && handler->accept(transfer)) {
+ QPID_LOG(debug, "Delivered " << *content->getMethod());
+ return true;
+ } else {
+ //received message for another destination, keep for later
+ QPID_LOG(debug, "Pushed " << *content->getMethod() << " to received queue");
+ received.push_back(content);
+ }
+ } else {
+ //TODO: handle other types of commands (e.g. message-accept, message-flow etc)
+ }
+ }
+ return false;
+}
+
+bool IncomingMessages::wait(qpid::sys::Duration duration)
+{
+ AbsTime deadline(AbsTime::now(), duration);
+ FrameSet::shared_ptr content;
+ for (Duration timeout = duration; incoming->pop(content, timeout); timeout = Duration(AbsTime::now(), deadline)) {
+ if (content->isA<MessageTransferBody>()) {
+ QPID_LOG(debug, "Pushed " << *content->getMethod() << " to received queue");
+ received.push_back(content);
+ return true;
+ } else {
+ //TODO: handle other types of commands (e.g. message-accept, message-flow etc)
+ }
+ }
+ return false;
+}
+
+uint32_t IncomingMessages::pendingAccept()
+{
+ return acceptTracker.acceptsPending();
+}
+uint32_t IncomingMessages::pendingAccept(const std::string& destination)
+{
+ return acceptTracker.acceptsPending(destination);
+}
+
+uint32_t IncomingMessages::available()
+{
+ //first pump all available messages from incoming to received...
+ while (process(0, 0)) {}
+ //return the count of received messages
+ return received.size();
+}
+
+uint32_t IncomingMessages::available(const std::string& destination)
+{
+ //first pump all available messages from incoming to received...
+ while (process(0, 0)) {}
+
+ //count all messages for this destination from received list
+ return std::for_each(received.begin(), received.end(), Match(destination)).matched;
+}
+
+void populate(qpid::messaging::Message& message, FrameSet& command);
+
+/**
+ * Called when message is retrieved; records retrieval for subsequent
+ * acceptance, marks the command as completed and converts command to
+ * message if message is required
+ */
+void IncomingMessages::retrieve(FrameSetPtr command, qpid::messaging::Message* message)
+{
+ if (message) {
+ populate(*message, *command);
+ }
+ const MessageTransferBody* transfer = command->as<MessageTransferBody>();
+ if (transfer->getAcquireMode() == ACQUIRE_MODE_PRE_ACQUIRED && transfer->getAcceptMode() == ACCEPT_MODE_EXPLICIT) {
+ acceptTracker.delivered(transfer->getDestination(), command->getId());
+ }
+ session.markCompleted(command->getId(), false, false);
+}
+
+IncomingMessages::MessageTransfer::MessageTransfer(FrameSetPtr c, IncomingMessages& p) : content(c), parent(p) {}
+
+const std::string& IncomingMessages::MessageTransfer::getDestination()
+{
+ return content->as<MessageTransferBody>()->getDestination();
+}
+void IncomingMessages::MessageTransfer::retrieve(qpid::messaging::Message* message)
+{
+ parent.retrieve(content, message);
+}
+
+void populateHeaders(qpid::messaging::Message& message,
+ const DeliveryProperties* deliveryProperties,
+ const MessageProperties* messageProperties)
+{
+ if (deliveryProperties) {
+ message.setSubject(deliveryProperties->getRoutingKey());
+ //TODO: convert other delivery properties
+ }
+ if (messageProperties) {
+ message.setContentType(messageProperties->getContentType());
+ if (messageProperties->hasReplyTo()) {
+ message.setReplyTo(AddressResolution::convert(messageProperties->getReplyTo()));
+ }
+ message.getHeaders().clear();
+ translate(messageProperties->getApplicationHeaders(), message.getHeaders());
+ //TODO: convert other message properties
+ }
+}
+
+void populateHeaders(qpid::messaging::Message& message, const AMQHeaderBody* headers)
+{
+ populateHeaders(message, headers->get<DeliveryProperties>(), headers->get<MessageProperties>());
+}
+
+void populate(qpid::messaging::Message& message, FrameSet& command)
+{
+ //need to be able to link the message back to the transfer it was delivered by
+ //e.g. for rejecting.
+ MessageImplAccess::get(message).setInternalId(command.getId());
+
+ command.getContent(message.getContent());
+
+ populateHeaders(message, command.getHeaders());
+}
+
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/cpp/src/qpid/client/amqp0_10/IncomingMessages.h b/cpp/src/qpid/client/amqp0_10/IncomingMessages.h
new file mode 100644
index 0000000000..2bc6dd49c4
--- /dev/null
+++ b/cpp/src/qpid/client/amqp0_10/IncomingMessages.h
@@ -0,0 +1,98 @@
+#ifndef QPID_CLIENT_AMQP0_10_INCOMINGMESSAGES_H
+#define QPID_CLIENT_AMQP0_10_INCOMINGMESSAGES_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include <boost/shared_ptr.hpp>
+#include "qpid/client/AsyncSession.h"
+#include "qpid/framing/SequenceSet.h"
+#include "qpid/sys/BlockingQueue.h"
+#include "qpid/sys/Time.h"
+#include "qpid/client/amqp0_10/AcceptTracker.h"
+
+namespace qpid {
+
+namespace framing{
+class FrameSet;
+}
+
+namespace messaging {
+class Message;
+}
+
+namespace client {
+namespace amqp0_10 {
+
+/**
+ *
+ */
+class IncomingMessages
+{
+ public:
+ typedef boost::shared_ptr<qpid::framing::FrameSet> FrameSetPtr;
+ class MessageTransfer
+ {
+ public:
+ const std::string& getDestination();
+ void retrieve(qpid::messaging::Message* message);
+ private:
+ FrameSetPtr content;
+ IncomingMessages& parent;
+
+ MessageTransfer(FrameSetPtr, IncomingMessages&);
+ friend class IncomingMessages;
+ };
+
+ struct Handler
+ {
+ virtual ~Handler() {}
+ virtual bool accept(MessageTransfer& transfer) = 0;
+ };
+
+ void setSession(qpid::client::AsyncSession session);
+ bool get(Handler& handler, qpid::sys::Duration timeout);
+ bool getNextDestination(std::string& destination, qpid::sys::Duration timeout);
+ void accept();
+ void releaseAll();
+ void releasePending(const std::string& destination);
+
+ uint32_t pendingAccept();
+ uint32_t pendingAccept(const std::string& destination);
+
+ uint32_t available();
+ uint32_t available(const std::string& destination);
+ private:
+ typedef std::deque<FrameSetPtr> FrameSetQueue;
+
+ qpid::client::AsyncSession session;
+ boost::shared_ptr< sys::BlockingQueue<FrameSetPtr> > incoming;
+ FrameSetQueue received;
+ AcceptTracker acceptTracker;
+
+ bool process(Handler*, qpid::sys::Duration);
+ bool wait(qpid::sys::Duration);
+ void retrieve(FrameSetPtr, qpid::messaging::Message*);
+
+};
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_INCOMINGMESSAGES_H*/
diff --git a/cpp/src/qpid/client/amqp0_10/MessageSink.h b/cpp/src/qpid/client/amqp0_10/MessageSink.h
new file mode 100644
index 0000000000..8d87a3c7bb
--- /dev/null
+++ b/cpp/src/qpid/client/amqp0_10/MessageSink.h
@@ -0,0 +1,52 @@
+#ifndef QPID_CLIENT_AMQP0_10_MESSAGESINK_H
+#define QPID_CLIENT_AMQP0_10_MESSAGESINK_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include "qpid/client/AsyncSession.h"
+
+namespace qpid {
+
+namespace messaging {
+class Message;
+}
+
+namespace client {
+namespace amqp0_10 {
+
+struct OutgoingMessage;
+
+/**
+ *
+ */
+class MessageSink
+{
+ public:
+ virtual ~MessageSink() {}
+ virtual void declare(qpid::client::AsyncSession& session, const std::string& name) = 0;
+ virtual void send(qpid::client::AsyncSession& session, const std::string& name, OutgoingMessage& message) = 0;
+ virtual void cancel(qpid::client::AsyncSession& session, const std::string& name) = 0;
+ private:
+};
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_MESSAGESINK_H*/
diff --git a/cpp/src/qpid/client/amqp0_10/MessageSource.h b/cpp/src/qpid/client/amqp0_10/MessageSource.h
new file mode 100644
index 0000000000..74f2732f59
--- /dev/null
+++ b/cpp/src/qpid/client/amqp0_10/MessageSource.h
@@ -0,0 +1,47 @@
+#ifndef QPID_CLIENT_AMQP0_10_MESSAGESOURCE_H
+#define QPID_CLIENT_AMQP0_10_MESSAGESOURCE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include "qpid/client/AsyncSession.h"
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+/**
+ * Abstraction behind which the AMQP 0-10 commands required to
+ * establish (and tear down) an incoming stream of messages from a
+ * given address are hidden.
+ */
+class MessageSource
+{
+ public:
+ virtual ~MessageSource() {}
+ virtual void subscribe(qpid::client::AsyncSession& session, const std::string& destination) = 0;
+ virtual void cancel(qpid::client::AsyncSession& session, const std::string& destination) = 0;
+
+ private:
+};
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_MESSAGESOURCE_H*/
diff --git a/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp b/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp
new file mode 100644
index 0000000000..abd4f4c28c
--- /dev/null
+++ b/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp
@@ -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 "qpid/client/amqp0_10/OutgoingMessage.h"
+#include "qpid/client/amqp0_10/AddressResolution.h"
+#include "qpid/client/amqp0_10/Codecs.h"
+#include "qpid/client/amqp0_10/CodecsInternal.h"
+#include "qpid/messaging/Address.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/MessageImpl.h"
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+using qpid::messaging::Address;
+using qpid::messaging::MessageImplAccess;
+
+void OutgoingMessage::convert(const qpid::messaging::Message& from)
+{
+ //TODO: need to avoid copying as much as possible
+ message.setData(from.getContent());
+ message.getMessageProperties().setContentType(from.getContentType());
+ const Address& address = from.getReplyTo();
+ if (address) {
+ message.getMessageProperties().setReplyTo(AddressResolution::convert(address));
+ }
+ translate(from.getHeaders(), message.getMessageProperties().getApplicationHeaders());
+ //TODO: set other message properties
+ message.getDeliveryProperties().setRoutingKey(from.getSubject());
+ //TODO: set other delivery properties
+}
+
+namespace {
+const std::string SUBJECT("subject");
+}
+
+void OutgoingMessage::setSubject(const std::string& subject)
+{
+ if (!subject.empty()) {
+ message.getMessageProperties().getApplicationHeaders().setString(SUBJECT, subject);
+ }
+}
+
+std::string OutgoingMessage::getSubject() const
+{
+ return message.getMessageProperties().getApplicationHeaders().getAsString(SUBJECT);
+}
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/cpp/src/qpid/client/amqp0_10/OutgoingMessage.h b/cpp/src/qpid/client/amqp0_10/OutgoingMessage.h
new file mode 100644
index 0000000000..0cdd2a2336
--- /dev/null
+++ b/cpp/src/qpid/client/amqp0_10/OutgoingMessage.h
@@ -0,0 +1,48 @@
+#ifndef QPID_CLIENT_AMQP0_10_OUTGOINGMESSAGE_H
+#define QPID_CLIENT_AMQP0_10_OUTGOINGMESSAGE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/Completion.h"
+#include "qpid/client/Message.h"
+
+namespace qpid {
+namespace messaging {
+class Message;
+}
+namespace client {
+namespace amqp0_10 {
+
+struct OutgoingMessage
+{
+ qpid::client::Message message;
+ qpid::client::Completion status;
+
+ void convert(const qpid::messaging::Message&);
+ void setSubject(const std::string& subject);
+ std::string getSubject() const;
+};
+
+
+
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_OUTGOINGMESSAGE_H*/
diff --git a/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp b/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp
new file mode 100644
index 0000000000..bc5c53fde6
--- /dev/null
+++ b/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp
@@ -0,0 +1,194 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "ReceiverImpl.h"
+#include "AddressResolution.h"
+#include "MessageSource.h"
+#include "SessionImpl.h"
+#include "qpid/messaging/Receiver.h"
+#include "qpid/messaging/Session.h"
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+using qpid::messaging::Receiver;
+
+void ReceiverImpl::received(qpid::messaging::Message&)
+{
+ //TODO: should this be configurable
+ if (capacity && --window <= capacity/2) {
+ session.sendCompletion();
+ window = capacity;
+ }
+}
+
+qpid::messaging::Message ReceiverImpl::get(qpid::sys::Duration timeout)
+{
+ qpid::messaging::Message result;
+ if (!get(result, timeout)) throw Receiver::NoMessageAvailable();
+ return result;
+}
+
+qpid::messaging::Message ReceiverImpl::fetch(qpid::sys::Duration timeout)
+{
+ qpid::messaging::Message result;
+ if (!fetch(result, timeout)) throw Receiver::NoMessageAvailable();
+ return result;
+}
+
+bool ReceiverImpl::get(qpid::messaging::Message& message, qpid::sys::Duration timeout)
+{
+ Get f(*this, message, timeout);
+ while (!parent.execute(f)) {}
+ return f.result;
+}
+
+bool ReceiverImpl::fetch(qpid::messaging::Message& message, qpid::sys::Duration timeout)
+{
+ Fetch f(*this, message, timeout);
+ while (!parent.execute(f)) {}
+ return f.result;
+}
+
+void ReceiverImpl::cancel()
+{
+ execute<Cancel>();
+}
+
+void ReceiverImpl::start()
+{
+ if (state == STOPPED) {
+ state = STARTED;
+ startFlow();
+ }
+}
+
+void ReceiverImpl::stop()
+{
+ state = STOPPED;
+ session.messageStop(destination);
+}
+
+void ReceiverImpl::setCapacity(uint32_t c)
+{
+ execute1<SetCapacity>(c);
+}
+
+void ReceiverImpl::startFlow()
+{
+ if (capacity > 0) {
+ session.messageSetFlowMode(destination, FLOW_MODE_WINDOW);
+ session.messageFlow(destination, CREDIT_UNIT_MESSAGE, capacity);
+ session.messageFlow(destination, CREDIT_UNIT_BYTE, byteCredit);
+ window = capacity;
+ }
+}
+
+void ReceiverImpl::init(qpid::client::AsyncSession s, AddressResolution& resolver)
+{
+
+ session = s;
+ if (state == UNRESOLVED) {
+ source = resolver.resolveSource(session, address);
+ state = STARTED;
+ }
+ if (state == CANCELLED) {
+ source->cancel(session, destination);
+ parent.receiverCancelled(destination);
+ } else {
+ source->subscribe(session, destination);
+ start();
+ }
+}
+
+
+const std::string& ReceiverImpl::getName() const { return destination; }
+
+uint32_t ReceiverImpl::getCapacity()
+{
+ return capacity;
+}
+
+uint32_t ReceiverImpl::available()
+{
+ return parent.available(destination);
+}
+
+uint32_t ReceiverImpl::pendingAck()
+{
+ return parent.pendingAck(destination);
+}
+
+ReceiverImpl::ReceiverImpl(SessionImpl& p, const std::string& name,
+ const qpid::messaging::Address& a) :
+
+ parent(p), destination(name), address(a), byteCredit(0xFFFFFFFF),
+ state(UNRESOLVED), capacity(0), window(0) {}
+
+bool ReceiverImpl::getImpl(qpid::messaging::Message& message, qpid::sys::Duration timeout)
+{
+ return parent.get(*this, message, timeout);
+}
+
+bool ReceiverImpl::fetchImpl(qpid::messaging::Message& message, qpid::sys::Duration timeout)
+{
+ if (state == CANCELLED) return false;//TODO: or should this be an error?
+
+ if (capacity == 0 || state != STARTED) {
+ session.messageSetFlowMode(destination, FLOW_MODE_CREDIT);
+ session.messageFlow(destination, CREDIT_UNIT_MESSAGE, 1);
+ session.messageFlow(destination, CREDIT_UNIT_BYTE, 0xFFFFFFFF);
+ }
+
+ if (getImpl(message, timeout)) {
+ return true;
+ } else {
+ sync(session).messageFlush(destination);
+ startFlow();//reallocate credit
+ return getImpl(message, 0);
+ }
+}
+
+void ReceiverImpl::cancelImpl()
+{
+ if (state != CANCELLED) {
+ state = CANCELLED;
+ source->cancel(session, destination);
+ parent.receiverCancelled(destination);
+ }
+}
+
+void ReceiverImpl::setCapacityImpl(uint32_t c)
+{
+ if (c != capacity) {
+ capacity = c;
+ if (state == STARTED) {
+ session.messageStop(destination);
+ startFlow();
+ }
+ }
+}
+qpid::messaging::Session ReceiverImpl::getSession() const
+{
+ return qpid::messaging::Session(&parent);
+}
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h b/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h
new file mode 100644
index 0000000000..d40aac4058
--- /dev/null
+++ b/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h
@@ -0,0 +1,148 @@
+#ifndef QPID_CLIENT_AMQP0_10_RECEIVERIMPL_H
+#define QPID_CLIENT_AMQP0_10_RECEIVERIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/Address.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/ReceiverImpl.h"
+#include "qpid/messaging/Variant.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/amqp0_10/SessionImpl.h"
+#include "qpid/sys/Time.h"
+#include <memory>
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+class AddressResolution;
+class MessageSource;
+
+/**
+ * A receiver implementation based on an AMQP 0-10 subscription.
+ */
+class ReceiverImpl : public qpid::messaging::ReceiverImpl
+{
+ public:
+
+ enum State {UNRESOLVED, STOPPED, STARTED, CANCELLED};
+
+ ReceiverImpl(SessionImpl& parent, const std::string& name,
+ const qpid::messaging::Address& address);
+
+ void init(qpid::client::AsyncSession session, AddressResolution& resolver);
+ bool get(qpid::messaging::Message& message, qpid::sys::Duration timeout);
+ qpid::messaging::Message get(qpid::sys::Duration timeout);
+ bool fetch(qpid::messaging::Message& message, qpid::sys::Duration timeout);
+ qpid::messaging::Message fetch(qpid::sys::Duration timeout);
+ void cancel();
+ void start();
+ void stop();
+ const std::string& getName() const;
+ void setCapacity(uint32_t);
+ uint32_t getCapacity();
+ uint32_t available();
+ uint32_t pendingAck();
+ void received(qpid::messaging::Message& message);
+ qpid::messaging::Session getSession() const;
+ private:
+ SessionImpl& parent;
+ const std::string destination;
+ const qpid::messaging::Address address;
+ const uint32_t byteCredit;
+ State state;
+
+ std::auto_ptr<MessageSource> source;
+ uint32_t capacity;
+ qpid::client::AsyncSession session;
+ qpid::messaging::MessageListener* listener;
+ uint32_t window;
+
+ void startFlow();
+ //implementation of public facing methods
+ bool fetchImpl(qpid::messaging::Message& message, qpid::sys::Duration timeout);
+ bool getImpl(qpid::messaging::Message& message, qpid::sys::Duration timeout);
+ void cancelImpl();
+ void setCapacityImpl(uint32_t);
+
+ //functors for public facing methods (allows locking and retry
+ //logic to be centralised)
+ struct Command
+ {
+ ReceiverImpl& impl;
+
+ Command(ReceiverImpl& i) : impl(i) {}
+ };
+
+ struct Get : Command
+ {
+ qpid::messaging::Message& message;
+ qpid::sys::Duration timeout;
+ bool result;
+
+ Get(ReceiverImpl& i, qpid::messaging::Message& m, qpid::sys::Duration t) :
+ Command(i), message(m), timeout(t), result(false) {}
+ void operator()() { result = impl.getImpl(message, timeout); }
+ };
+
+ struct Fetch : Command
+ {
+ qpid::messaging::Message& message;
+ qpid::sys::Duration timeout;
+ bool result;
+
+ Fetch(ReceiverImpl& i, qpid::messaging::Message& m, qpid::sys::Duration t) :
+ Command(i), message(m), timeout(t), result(false) {}
+ void operator()() { result = impl.fetchImpl(message, timeout); }
+ };
+
+ struct Cancel : Command
+ {
+ Cancel(ReceiverImpl& i) : Command(i) {}
+ void operator()() { impl.cancelImpl(); }
+ };
+
+ struct SetCapacity : Command
+ {
+ uint32_t capacity;
+
+ SetCapacity(ReceiverImpl& i, uint32_t c) : Command(i), capacity(c) {}
+ void operator()() { impl.setCapacityImpl(capacity); }
+ };
+
+ //helper templates for some common patterns
+ template <class F> void execute()
+ {
+ F f(*this);
+ parent.execute(f);
+ }
+
+ template <class F, class P> void execute1(P p)
+ {
+ F f(*this, p);
+ parent.execute(f);
+ }
+};
+
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_RECEIVERIMPL_H*/
diff --git a/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp b/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp
new file mode 100644
index 0000000000..4d6b9869e6
--- /dev/null
+++ b/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp
@@ -0,0 +1,144 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "SenderImpl.h"
+#include "MessageSink.h"
+#include "SessionImpl.h"
+#include "AddressResolution.h"
+#include "OutgoingMessage.h"
+#include "qpid/messaging/Session.h"
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+SenderImpl::SenderImpl(SessionImpl& _parent, const std::string& _name,
+ const qpid::messaging::Address& _address) :
+ parent(_parent), name(_name), address(_address), state(UNRESOLVED),
+ capacity(50), window(0), flushed(false) {}
+
+void SenderImpl::send(const qpid::messaging::Message& message)
+{
+ Send f(*this, &message);
+ while (f.repeat) parent.execute(f);
+}
+
+void SenderImpl::cancel()
+{
+ execute<Cancel>();
+}
+
+void SenderImpl::setCapacity(uint32_t c)
+{
+ bool flush = c < capacity;
+ capacity = c;
+ execute1<CheckPendingSends>(flush);
+}
+uint32_t SenderImpl::getCapacity() { return capacity; }
+uint32_t SenderImpl::pending()
+{
+ CheckPendingSends f(*this, false);
+ parent.execute(f);
+ return f.pending;
+}
+
+void SenderImpl::init(qpid::client::AsyncSession s, AddressResolution& resolver)
+{
+ session = s;
+ if (state == UNRESOLVED) {
+ sink = resolver.resolveSink(session, address);
+ state = ACTIVE;
+ }
+ if (state == CANCELLED) {
+ sink->cancel(session, name);
+ parent.senderCancelled(name);
+ } else {
+ sink->declare(session, name);
+ replay();
+ }
+}
+
+void SenderImpl::waitForCapacity()
+{
+ //TODO: add option to throw exception rather than blocking?
+ if (capacity <= (flushed ? checkPendingSends(false) : outgoing.size())) {
+ //Initial implementation is very basic. As outgoing is
+ //currently only reduced on receiving completions and we are
+ //blocking anyway we may as well sync(). If successful that
+ //should clear all outstanding sends.
+ session.sync();
+ checkPendingSends(false);
+ }
+ //flush periodically and check for conmpleted sends
+ if (++window > (capacity / 4)) {//TODO: make this configurable?
+ checkPendingSends(true);
+ window = 0;
+ }
+}
+
+void SenderImpl::sendImpl(const qpid::messaging::Message& m)
+{
+ //TODO: make recording for replay optional (would still want to track completion however)
+ std::auto_ptr<OutgoingMessage> msg(new OutgoingMessage());
+ msg->convert(m);
+ msg->setSubject(m.getSubject().empty() ? address.getSubject() : m.getSubject());
+ outgoing.push_back(msg.release());
+ sink->send(session, name, outgoing.back());
+}
+
+void SenderImpl::replay()
+{
+ for (OutgoingMessages::iterator i = outgoing.begin(); i != outgoing.end(); ++i) {
+ sink->send(session, name, *i);
+ }
+}
+
+uint32_t SenderImpl::checkPendingSends(bool flush)
+{
+ if (flush) {
+ session.flush();
+ flushed = true;
+ } else {
+ flushed = false;
+ }
+ while (!outgoing.empty() && outgoing.front().status.isComplete()) {
+ outgoing.pop_front();
+ }
+ return outgoing.size();
+}
+
+void SenderImpl::cancelImpl()
+{
+ state = CANCELLED;
+ sink->cancel(session, name);
+ parent.senderCancelled(name);
+}
+
+const std::string& SenderImpl::getName() const
+{
+ return name;
+}
+
+qpid::messaging::Session SenderImpl::getSession() const
+{
+ return qpid::messaging::Session(&parent);
+}
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/cpp/src/qpid/client/amqp0_10/SenderImpl.h b/cpp/src/qpid/client/amqp0_10/SenderImpl.h
new file mode 100644
index 0000000000..80d9843d9e
--- /dev/null
+++ b/cpp/src/qpid/client/amqp0_10/SenderImpl.h
@@ -0,0 +1,140 @@
+#ifndef QPID_CLIENT_AMQP0_10_SENDERIMPL_H
+#define QPID_CLIENT_AMQP0_10_SENDERIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/Address.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/SenderImpl.h"
+#include "qpid/messaging/Variant.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/amqp0_10/SessionImpl.h"
+#include <memory>
+#include <boost/ptr_container/ptr_deque.hpp>
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+class AddressResolution;
+class MessageSink;
+struct OutgoingMessage;
+
+/**
+ *
+ */
+class SenderImpl : public qpid::messaging::SenderImpl
+{
+ public:
+ enum State {UNRESOLVED, ACTIVE, CANCELLED};
+
+ SenderImpl(SessionImpl& parent, const std::string& name,
+ const qpid::messaging::Address& address);
+ void send(const qpid::messaging::Message&);
+ void cancel();
+ void setCapacity(uint32_t);
+ uint32_t getCapacity();
+ uint32_t pending();
+ void init(qpid::client::AsyncSession, AddressResolution&);
+ const std::string& getName() const;
+ qpid::messaging::Session getSession() const;
+
+ private:
+ SessionImpl& parent;
+ const std::string name;
+ const qpid::messaging::Address address;
+ State state;
+ std::auto_ptr<MessageSink> sink;
+
+ qpid::client::AsyncSession session;
+ std::string destination;
+ std::string routingKey;
+
+ typedef boost::ptr_deque<OutgoingMessage> OutgoingMessages;
+ OutgoingMessages outgoing;
+ uint32_t capacity;
+ uint32_t window;
+ bool flushed;
+
+ uint32_t checkPendingSends(bool flush);
+ void replay();
+ void waitForCapacity();
+
+ //logic for application visible methods:
+ void sendImpl(const qpid::messaging::Message&);
+ void cancelImpl();
+
+
+ //functors for application visible methods (allowing locking and
+ //retry to be centralised):
+ struct Command
+ {
+ SenderImpl& impl;
+
+ Command(SenderImpl& i) : impl(i) {}
+ };
+
+ struct Send : Command
+ {
+ const qpid::messaging::Message* message;
+ bool repeat;
+
+ Send(SenderImpl& i, const qpid::messaging::Message* m) : Command(i), message(m), repeat(true) {}
+ void operator()()
+ {
+ impl.waitForCapacity();
+ //from this point message will be recorded if there is any
+ //failure (and replayed) so need not repeat the call
+ repeat = false;
+ impl.sendImpl(*message);
+ }
+ };
+
+ struct Cancel : Command
+ {
+ Cancel(SenderImpl& i) : Command(i) {}
+ void operator()() { impl.cancelImpl(); }
+ };
+
+ struct CheckPendingSends : Command
+ {
+ bool flush;
+ uint32_t pending;
+ CheckPendingSends(SenderImpl& i, bool f) : Command(i), flush(f), pending(0) {}
+ void operator()() { pending = impl.checkPendingSends(flush); }
+ };
+
+ //helper templates for some common patterns
+ template <class F> void execute()
+ {
+ F f(*this);
+ parent.execute(f);
+ }
+
+ template <class F, class P> bool execute1(P p)
+ {
+ F f(*this, p);
+ return parent.execute(f);
+ }
+};
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_SENDERIMPL_H*/
diff --git a/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp b/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp
new file mode 100644
index 0000000000..c7dff05dd7
--- /dev/null
+++ b/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp
@@ -0,0 +1,433 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/client/amqp0_10/SessionImpl.h"
+#include "qpid/client/amqp0_10/ConnectionImpl.h"
+#include "qpid/client/amqp0_10/ReceiverImpl.h"
+#include "qpid/client/amqp0_10/SenderImpl.h"
+#include "qpid/client/amqp0_10/MessageSource.h"
+#include "qpid/client/amqp0_10/MessageSink.h"
+#include "qpid/client/PrivateImplRef.h"
+#include "qpid/Exception.h"
+#include "qpid/log/Statement.h"
+#include "qpid/messaging/Address.h"
+#include "qpid/messaging/Connection.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/MessageImpl.h"
+#include "qpid/messaging/Sender.h"
+#include "qpid/messaging/Receiver.h"
+#include "qpid/messaging/Session.h"
+#include "qpid/framing/reply_exceptions.h"
+#include <boost/format.hpp>
+#include <boost/function.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+using qpid::messaging::KeyError;
+using qpid::messaging::MessageImplAccess;
+using qpid::messaging::Sender;
+using qpid::messaging::Receiver;
+using qpid::messaging::VariantMap;
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+SessionImpl::SessionImpl(ConnectionImpl& c, bool t) : connection(c), transactional(t) {}
+
+
+void SessionImpl::sync()
+{
+ retry<Sync>();
+}
+
+void SessionImpl::flush()
+{
+ retry<Flush>();
+}
+
+void SessionImpl::commit()
+{
+ if (!execute<Commit>()) {
+ throw Exception();//TODO: what type?
+ }
+}
+
+void SessionImpl::rollback()
+{
+ //If the session fails during this operation, the transaction will
+ //be rolled back anyway.
+ execute<Rollback>();
+}
+
+void SessionImpl::acknowledge()
+{
+ //Should probably throw an exception on failure here, or indicate
+ //it through a return type at least. Failure means that the
+ //message may be redelivered; i.e. the application cannot delete
+ //any state necessary for preventing reprocessing of the message
+ execute<Acknowledge>();
+}
+
+void SessionImpl::reject(qpid::messaging::Message& m)
+{
+ //Possibly want to somehow indicate failure here as well. Less
+ //clear need as compared to acknowledge however.
+ execute1<Reject>(m);
+}
+
+void SessionImpl::close()
+{
+ //cancel all the senders and receivers (get copy of names and then
+ //make the calls to avoid modifying maps while iterating over
+ //them):
+ std::vector<std::string> s;
+ std::vector<std::string> r;
+ {
+ qpid::sys::Mutex::ScopedLock l(lock);
+ for (Senders::const_iterator i = senders.begin(); i != senders.end(); ++i) s.push_back(i->first);
+ for (Receivers::const_iterator i = receivers.begin(); i != receivers.end(); ++i) r.push_back(i->first);
+ }
+ for (std::vector<std::string>::const_iterator i = s.begin(); i != s.end(); ++i) getSender(*i).cancel();
+ for (std::vector<std::string>::const_iterator i = r.begin(); i != r.end(); ++i) getReceiver(*i).cancel();
+
+
+ connection.closed(*this);
+ session.close();
+}
+
+template <class T, class S> boost::intrusive_ptr<S> getImplPtr(T& t)
+{
+ return boost::dynamic_pointer_cast<S>(qpid::client::PrivateImplRef<T>::get(t));
+}
+
+template <class T> void getFreeKey(std::string& key, T& map)
+{
+ std::string name = key;
+ int count = 1;
+ for (typename T::const_iterator i = map.find(name); i != map.end(); i = map.find(name)) {
+ name = (boost::format("%1%_%2%") % key % ++count).str();
+ }
+ key = name;
+}
+
+
+void SessionImpl::setSession(qpid::client::Session s)
+{
+ qpid::sys::Mutex::ScopedLock l(lock);
+ session = s;
+ incoming.setSession(session);
+ if (transactional) session.txSelect();
+ for (Receivers::iterator i = receivers.begin(); i != receivers.end(); ++i) {
+ getImplPtr<Receiver, ReceiverImpl>(i->second)->init(session, resolver);
+ }
+ for (Senders::iterator i = senders.begin(); i != senders.end(); ++i) {
+ getImplPtr<Sender, SenderImpl>(i->second)->init(session, resolver);
+ }
+}
+
+struct SessionImpl::CreateReceiver : Command
+{
+ qpid::messaging::Receiver result;
+ const qpid::messaging::Address& address;
+
+ CreateReceiver(SessionImpl& i, const qpid::messaging::Address& a) :
+ Command(i), address(a) {}
+ void operator()() { result = impl.createReceiverImpl(address); }
+};
+
+Receiver SessionImpl::createReceiver(const qpid::messaging::Address& address)
+{
+ return get1<CreateReceiver, Receiver>(address);
+}
+
+Receiver SessionImpl::createReceiverImpl(const qpid::messaging::Address& address)
+{
+ std::string name = address.getName();
+ getFreeKey(name, receivers);
+ Receiver receiver(new ReceiverImpl(*this, name, address));
+ getImplPtr<Receiver, ReceiverImpl>(receiver)->init(session, resolver);
+ receivers[name] = receiver;
+ return receiver;
+}
+
+struct SessionImpl::CreateSender : Command
+{
+ qpid::messaging::Sender result;
+ const qpid::messaging::Address& address;
+
+ CreateSender(SessionImpl& i, const qpid::messaging::Address& a) :
+ Command(i), address(a) {}
+ void operator()() { result = impl.createSenderImpl(address); }
+};
+
+Sender SessionImpl::createSender(const qpid::messaging::Address& address)
+{
+ return get1<CreateSender, Sender>(address);
+}
+
+Sender SessionImpl::createSenderImpl(const qpid::messaging::Address& address)
+{
+ std::string name = address.getName();
+ getFreeKey(name, senders);
+ Sender sender(new SenderImpl(*this, name, address));
+ getImplPtr<Sender, SenderImpl>(sender)->init(session, resolver);
+ senders[name] = sender;
+ return sender;
+}
+
+Sender SessionImpl::getSender(const std::string& name) const
+{
+ qpid::sys::Mutex::ScopedLock l(lock);
+ Senders::const_iterator i = senders.find(name);
+ if (i == senders.end()) {
+ throw KeyError(name);
+ } else {
+ return i->second;
+ }
+}
+
+Receiver SessionImpl::getReceiver(const std::string& name) const
+{
+ qpid::sys::Mutex::ScopedLock l(lock);
+ Receivers::const_iterator i = receivers.find(name);
+ if (i == receivers.end()) {
+ throw KeyError(name);
+ } else {
+ return i->second;
+ }
+}
+
+SessionImpl& SessionImpl::convert(qpid::messaging::Session& s)
+{
+ boost::intrusive_ptr<SessionImpl> impl = getImplPtr<qpid::messaging::Session, SessionImpl>(s);
+ if (!impl) {
+ throw qpid::Exception(QPID_MSG("Configuration error; require qpid::client::amqp0_10::SessionImpl"));
+ }
+ return *impl;
+}
+
+namespace {
+
+struct IncomingMessageHandler : IncomingMessages::Handler
+{
+ typedef boost::function1<bool, IncomingMessages::MessageTransfer&> Callback;
+ Callback callback;
+
+ IncomingMessageHandler(Callback c) : callback(c) {}
+
+ bool accept(IncomingMessages::MessageTransfer& transfer)
+ {
+ return callback(transfer);
+ }
+};
+
+}
+
+
+bool SessionImpl::getNextReceiver(Receiver* receiver, IncomingMessages::MessageTransfer& transfer)
+{
+ Receivers::const_iterator i = receivers.find(transfer.getDestination());
+ if (i == receivers.end()) {
+ QPID_LOG(error, "Received message for unknown destination " << transfer.getDestination());
+ return false;
+ } else {
+ *receiver = i->second;
+ return true;
+ }
+}
+
+bool SessionImpl::accept(ReceiverImpl* receiver,
+ qpid::messaging::Message* message,
+ IncomingMessages::MessageTransfer& transfer)
+{
+ if (receiver->getName() == transfer.getDestination()) {
+ transfer.retrieve(message);
+ receiver->received(*message);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool SessionImpl::getIncoming(IncomingMessages::Handler& handler, qpid::sys::Duration timeout)
+{
+ return incoming.get(handler, timeout);
+}
+
+bool SessionImpl::get(ReceiverImpl& receiver, qpid::messaging::Message& message, qpid::sys::Duration timeout)
+{
+ IncomingMessageHandler handler(boost::bind(&SessionImpl::accept, this, &receiver, &message, _1));
+ return getIncoming(handler, timeout);
+}
+
+bool SessionImpl::nextReceiver(qpid::messaging::Receiver& receiver, qpid::sys::Duration timeout)
+{
+ qpid::sys::Mutex::ScopedLock l(lock);
+ while (true) {
+ try {
+ std::string destination;
+ if (incoming.getNextDestination(destination, timeout)) {
+ Receivers::const_iterator i = receivers.find(destination);
+ if (i == receivers.end()) {
+ throw qpid::Exception(QPID_MSG("Received message for unknown destination " << destination));
+ } else {
+ receiver = i->second;
+ }
+ return true;
+ } else {
+ return false;
+ }
+ } catch (TransportFailure&) {
+ reconnect();
+ }
+ }
+}
+
+qpid::messaging::Receiver SessionImpl::nextReceiver(qpid::sys::Duration timeout)
+{
+ qpid::messaging::Receiver receiver;
+ if (!nextReceiver(receiver, timeout)) throw Receiver::NoMessageAvailable();
+ if (!receiver) throw qpid::Exception("Bad receiver returned!");
+ return receiver;
+}
+
+uint32_t SessionImpl::available()
+{
+ return get1<Available, uint32_t>((const std::string*) 0);
+}
+uint32_t SessionImpl::available(const std::string& destination)
+{
+ return get1<Available, uint32_t>(&destination);
+}
+
+struct SessionImpl::Available : Command
+{
+ const std::string* destination;
+ uint32_t result;
+
+ Available(SessionImpl& i, const std::string* d) : Command(i), destination(d), result(0) {}
+ void operator()() { result = impl.availableImpl(destination); }
+};
+
+uint32_t SessionImpl::availableImpl(const std::string* destination)
+{
+ if (destination) {
+ return incoming.available(*destination);
+ } else {
+ return incoming.available();
+ }
+}
+
+uint32_t SessionImpl::pendingAck()
+{
+ return get1<PendingAck, uint32_t>((const std::string*) 0);
+}
+
+uint32_t SessionImpl::pendingAck(const std::string& destination)
+{
+ return get1<PendingAck, uint32_t>(&destination);
+}
+
+struct SessionImpl::PendingAck : Command
+{
+ const std::string* destination;
+ uint32_t result;
+
+ PendingAck(SessionImpl& i, const std::string* d) : Command(i), destination(d), result(0) {}
+ void operator()() { result = impl.pendingAckImpl(destination); }
+};
+
+uint32_t SessionImpl::pendingAckImpl(const std::string* destination)
+{
+ if (destination) {
+ return incoming.pendingAccept(*destination);
+ } else {
+ return incoming.pendingAccept();
+ }
+}
+
+void SessionImpl::syncImpl()
+{
+ session.sync();
+}
+
+void SessionImpl::flushImpl()
+{
+ session.flush();
+}
+
+
+void SessionImpl::commitImpl()
+{
+ incoming.accept();
+ session.txCommit();
+}
+
+void SessionImpl::rollbackImpl()
+{
+ for (Receivers::iterator i = receivers.begin(); i != receivers.end(); ++i) {
+ getImplPtr<Receiver, ReceiverImpl>(i->second)->stop();
+ }
+ //ensure that stop has been processed and all previously sent
+ //messages are available for release:
+ session.sync();
+ incoming.releaseAll();
+ session.txRollback();
+
+ for (Receivers::iterator i = receivers.begin(); i != receivers.end(); ++i) {
+ getImplPtr<Receiver, ReceiverImpl>(i->second)->start();
+ }
+}
+
+void SessionImpl::acknowledgeImpl()
+{
+ incoming.accept();
+}
+
+void SessionImpl::rejectImpl(qpid::messaging::Message& m)
+{
+ SequenceSet set;
+ set.add(MessageImplAccess::get(m).getInternalId());
+ session.messageReject(set);
+}
+
+void SessionImpl::receiverCancelled(const std::string& name)
+{
+ receivers.erase(name);
+ session.sync();
+ incoming.releasePending(name);
+}
+
+void SessionImpl::senderCancelled(const std::string& name)
+{
+ senders.erase(name);
+}
+
+void SessionImpl::reconnect()
+{
+ connection.reconnect();
+}
+
+qpid::messaging::Connection SessionImpl::getConnection() const
+{
+ return qpid::messaging::Connection(&connection);
+}
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/cpp/src/qpid/client/amqp0_10/SessionImpl.h b/cpp/src/qpid/client/amqp0_10/SessionImpl.h
new file mode 100644
index 0000000000..96c7ca93a3
--- /dev/null
+++ b/cpp/src/qpid/client/amqp0_10/SessionImpl.h
@@ -0,0 +1,212 @@
+#ifndef QPID_CLIENT_AMQP0_10_SESSIONIMPL_H
+#define QPID_CLIENT_AMQP0_10_SESSIONIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/SessionImpl.h"
+#include "qpid/messaging/Variant.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/amqp0_10/AddressResolution.h"
+#include "qpid/client/amqp0_10/IncomingMessages.h"
+#include "qpid/sys/Mutex.h"
+
+namespace qpid {
+
+namespace messaging {
+class Address;
+class Connection;
+class Message;
+class Receiver;
+class Sender;
+class Session;
+}
+
+namespace client {
+namespace amqp0_10 {
+
+class ConnectionImpl;
+class ReceiverImpl;
+class SenderImpl;
+
+/**
+ * Implementation of the protocol independent Session interface using
+ * AMQP 0-10.
+ */
+class SessionImpl : public qpid::messaging::SessionImpl
+{
+ public:
+ SessionImpl(ConnectionImpl&, bool transactional);
+ void commit();
+ void rollback();
+ void acknowledge();
+ void reject(qpid::messaging::Message&);
+ void close();
+ void sync();
+ void flush();
+ qpid::messaging::Sender createSender(const qpid::messaging::Address& address);
+ qpid::messaging::Receiver createReceiver(const qpid::messaging::Address& address);
+
+ qpid::messaging::Sender getSender(const std::string& name) const;
+ qpid::messaging::Receiver getReceiver(const std::string& name) const;
+
+ bool nextReceiver(qpid::messaging::Receiver& receiver, qpid::sys::Duration timeout);
+ qpid::messaging::Receiver nextReceiver(qpid::sys::Duration timeout);
+
+ qpid::messaging::Connection getConnection() const;
+
+ bool get(ReceiverImpl& receiver, qpid::messaging::Message& message, qpid::sys::Duration timeout);
+
+ void receiverCancelled(const std::string& name);
+ void senderCancelled(const std::string& name);
+
+ uint32_t available();
+ uint32_t available(const std::string& destination);
+
+ uint32_t pendingAck();
+ uint32_t pendingAck(const std::string& destination);
+
+ void setSession(qpid::client::Session);
+
+ template <class T> bool execute(T& f)
+ {
+ try {
+ qpid::sys::Mutex::ScopedLock l(lock);
+ f();
+ return true;
+ } catch (TransportFailure&) {
+ reconnect();
+ return false;
+ }
+ }
+
+ static SessionImpl& convert(qpid::messaging::Session&);
+
+ private:
+ typedef std::map<std::string, qpid::messaging::Receiver> Receivers;
+ typedef std::map<std::string, qpid::messaging::Sender> Senders;
+
+ mutable qpid::sys::Mutex lock;
+ ConnectionImpl& connection;
+ qpid::client::Session session;
+ AddressResolution resolver;
+ IncomingMessages incoming;
+ Receivers receivers;
+ Senders senders;
+ const bool transactional;
+
+ bool accept(ReceiverImpl*, qpid::messaging::Message*, IncomingMessages::MessageTransfer&);
+ bool getIncoming(IncomingMessages::Handler& handler, qpid::sys::Duration timeout);
+ bool getNextReceiver(qpid::messaging::Receiver* receiver, IncomingMessages::MessageTransfer& transfer);
+ void reconnect();
+
+ void commitImpl();
+ void rollbackImpl();
+ void acknowledgeImpl();
+ void rejectImpl(qpid::messaging::Message&);
+ void closeImpl();
+ void syncImpl();
+ void flushImpl();
+ qpid::messaging::Sender createSenderImpl(const qpid::messaging::Address& address);
+ qpid::messaging::Receiver createReceiverImpl(const qpid::messaging::Address& address);
+ uint32_t availableImpl(const std::string* destination);
+ uint32_t pendingAckImpl(const std::string* destination);
+
+ //functors for public facing methods (allows locking and retry
+ //logic to be centralised)
+ struct Command
+ {
+ SessionImpl& impl;
+
+ Command(SessionImpl& i) : impl(i) {}
+ };
+
+ struct Commit : Command
+ {
+ Commit(SessionImpl& i) : Command(i) {}
+ void operator()() { impl.commitImpl(); }
+ };
+
+ struct Rollback : Command
+ {
+ Rollback(SessionImpl& i) : Command(i) {}
+ void operator()() { impl.rollbackImpl(); }
+ };
+
+ struct Acknowledge : Command
+ {
+ Acknowledge(SessionImpl& i) : Command(i) {}
+ void operator()() { impl.acknowledgeImpl(); }
+ };
+
+ struct Sync : Command
+ {
+ Sync(SessionImpl& i) : Command(i) {}
+ void operator()() { impl.syncImpl(); }
+ };
+
+ struct Flush : Command
+ {
+ Flush(SessionImpl& i) : Command(i) {}
+ void operator()() { impl.flushImpl(); }
+ };
+
+ struct Reject : Command
+ {
+ qpid::messaging::Message& message;
+
+ Reject(SessionImpl& i, qpid::messaging::Message& m) : Command(i), message(m) {}
+ void operator()() { impl.rejectImpl(message); }
+ };
+
+ struct CreateSender;
+ struct CreateReceiver;
+ struct PendingAck;
+ struct Available;
+
+ //helper templates for some common patterns
+ template <class F> bool execute()
+ {
+ F f(*this);
+ return execute(f);
+ }
+
+ template <class F> void retry()
+ {
+ while (!execute<F>()) {}
+ }
+
+ template <class F, class P> bool execute1(P p)
+ {
+ F f(*this, p);
+ return execute(f);
+ }
+
+ template <class F, class R, class P> R get1(P p)
+ {
+ F f(*this, p);
+ while (!execute(f)) {}
+ return f.result;
+ }
+};
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_SESSIONIMPL_H*/
diff --git a/cpp/src/qpid/client/windows/SaslFactory.cpp b/cpp/src/qpid/client/windows/SaslFactory.cpp
new file mode 100644
index 0000000000..87df187ab2
--- /dev/null
+++ b/cpp/src/qpid/client/windows/SaslFactory.cpp
@@ -0,0 +1,146 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/SaslFactory.h"
+#include "qpid/client/ConnectionSettings.h"
+
+#include "qpid/Exception.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/sys/SecurityLayer.h"
+#include "qpid/log/Statement.h"
+
+#include "boost/tokenizer.hpp"
+
+namespace qpid {
+namespace client {
+
+using qpid::sys::SecurityLayer;
+using qpid::framing::InternalErrorException;
+
+class WindowsSasl : public Sasl
+{
+ public:
+ WindowsSasl(const ConnectionSettings&);
+ ~WindowsSasl();
+ std::string start(const std::string& mechanisms, unsigned int ssf);
+ std::string step(const std::string& challenge);
+ std::string getMechanism();
+ std::string getUserId();
+ std::auto_ptr<SecurityLayer> getSecurityLayer(uint16_t maxFrameSize);
+ private:
+ ConnectionSettings settings;
+ std::string mechanism;
+};
+
+qpid::sys::Mutex SaslFactory::lock;
+std::auto_ptr<SaslFactory> SaslFactory::instance;
+
+SaslFactory::SaslFactory()
+{
+}
+
+SaslFactory::~SaslFactory()
+{
+}
+
+SaslFactory& SaslFactory::getInstance()
+{
+ qpid::sys::Mutex::ScopedLock l(lock);
+ if (!instance.get()) {
+ instance = std::auto_ptr<SaslFactory>(new SaslFactory());
+ }
+ return *instance;
+}
+
+std::auto_ptr<Sasl> SaslFactory::create(const ConnectionSettings& settings)
+{
+ std::auto_ptr<Sasl> sasl(new WindowsSasl(settings));
+ return sasl;
+}
+
+namespace {
+ const std::string ANONYMOUS = "ANONYMOUS";
+ const std::string PLAIN = "PLAIN";
+}
+
+WindowsSasl::WindowsSasl(const ConnectionSettings& s)
+ : settings(s)
+{
+}
+
+WindowsSasl::~WindowsSasl()
+{
+}
+
+std::string WindowsSasl::start(const std::string& mechanisms,
+ unsigned int /*ssf*/)
+{
+ QPID_LOG(debug, "WindowsSasl::start(" << mechanisms << ")");
+
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep(" ");
+ bool havePlain = false;
+ bool haveAnon = false;
+ tokenizer mechs(mechanisms, sep);
+ for (tokenizer::iterator mech = mechs.begin();
+ mech != mechs.end();
+ ++mech) {
+ if (*mech == ANONYMOUS)
+ haveAnon = true;
+ else if (*mech == PLAIN)
+ havePlain = true;
+ }
+ if (!haveAnon && !havePlain)
+ throw InternalErrorException(QPID_MSG("Sasl error: no common mechanism"));
+
+ std::string resp = "";
+ if (havePlain) {
+ mechanism = PLAIN;
+ resp = ((char)0) + settings.username + ((char)0) + settings.password;
+ }
+ else {
+ mechanism = ANONYMOUS;
+ }
+ return resp;
+}
+
+std::string WindowsSasl::step(const std::string& challenge)
+{
+ // Shouldn't get this for PLAIN...
+ throw InternalErrorException(QPID_MSG("Sasl step error"));
+}
+
+std::string WindowsSasl::getMechanism()
+{
+ return mechanism;
+}
+
+std::string WindowsSasl::getUserId()
+{
+ return std::string(); // TODO - when GSSAPI is supported, return userId for connection.
+}
+
+std::auto_ptr<SecurityLayer> WindowsSasl::getSecurityLayer(uint16_t maxFrameSize)
+{
+ return std::auto_ptr<SecurityLayer>(0);
+}
+
+}} // namespace qpid::client
diff --git a/cpp/src/qpid/cluster/ClassifierHandler.cpp b/cpp/src/qpid/cluster/ClassifierHandler.cpp
deleted file mode 100644
index b78f795d20..0000000000
--- a/cpp/src/qpid/cluster/ClassifierHandler.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "ClassifierHandler.h"
-
-#include "qpid/framing/FrameDefaultVisitor.h"
-#include "qpid/framing/AMQFrame.h"
-
-namespace qpid {
-namespace cluster {
-
-using namespace framing;
-
-struct ClassifierHandler::Visitor : public FrameDefaultVisitor {
- Visitor(AMQFrame& f, ClassifierHandler& c)
- : chosen(0), frame(f), classifier(c) { f.getBody()->accept(*this); }
-
- void visit(const ExchangeDeclareBody&) { chosen=&classifier.wiring; }
- void visit(const ExchangeDeleteBody&) { chosen=&classifier.wiring; }
- void visit(const ExchangeBindBody&) { chosen=&classifier.wiring; }
- void visit(const ExchangeUnbindBody&) { chosen=&classifier.wiring; }
- void visit(const QueueDeclareBody&) { chosen=&classifier.wiring; }
- void visit(const QueueDeleteBody&) { chosen=&classifier.wiring; }
- void defaultVisit(const AMQBody&) { chosen=&classifier.other; }
-
- using framing::FrameDefaultVisitor::visit;
- using framing::FrameDefaultVisitor::defaultVisit;
-
- FrameHandler* chosen;
- AMQFrame& frame;
- ClassifierHandler& classifier;
-};
-
-void ClassifierHandler::handle(AMQFrame& f) { Visitor(f, *this).chosen->handle(f); }
-
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/ClassifierHandler.h b/cpp/src/qpid/cluster/ClassifierHandler.h
deleted file mode 100644
index 696e457c04..0000000000
--- a/cpp/src/qpid/cluster/ClassifierHandler.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef QPID_CLUSTER_CLASSIFIERHANDLER_H
-#define QPID_CLUSTER_CLASSIFIERHANDLER_H
-
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "qpid/framing/FrameHandler.h"
-
-namespace qpid {
-namespace cluster {
-
-/**
- * Classify frames and forward to the appropriate handler.
- */
-class ClassifierHandler : public framing::FrameHandler
-{
- public:
- ClassifierHandler(framing::FrameHandler& wiring_,
- framing::FrameHandler& other_)
- : wiring(wiring_), other(other_) {}
-
- void handle(framing::AMQFrame&);
-
- private:
- struct Visitor;
- friend struct Visitor;
- framing::FrameHandler& wiring;
- framing::FrameHandler& other;
-};
-
-}} // namespace qpid::cluster
-
-
-
-#endif /*!QPID_CLUSTER_CLASSIFIERHANDLER_H*/
diff --git a/cpp/src/qpid/cluster/Cluster.cpp b/cpp/src/qpid/cluster/Cluster.cpp
index 05ab9148b5..d049001eb0 100644
--- a/cpp/src/qpid/cluster/Cluster.cpp
+++ b/cpp/src/qpid/cluster/Cluster.cpp
@@ -16,305 +16,964 @@
*
*/
-#include "Cluster.h"
-#include "ConnectionInterceptor.h"
-
+/** CLUSTER IMPLEMENTATION OVERVIEW
+ *
+ * The cluster works on the principle that if all members of the
+ * cluster receive identical input, they will all produce identical
+ * results. cluster::Connections intercept data received from clients
+ * and multicast it via CPG. The data is processed (passed to the
+ * broker::Connection) only when it is received from CPG in cluster
+ * order. Each cluster member has Connection objects for directly
+ * connected clients and "shadow" Connection objects for connections
+ * to other members.
+ *
+ * This assumes that all broker actions occur deterministically in
+ * response to data arriving on client connections. There are two
+ * situations where this assumption fails:
+ * - sending data in response to polling local connections for writabiliy.
+ * - taking actions based on a timer or timestamp comparison.
+ *
+ * IMPORTANT NOTE: any time code is added to the broker that uses timers,
+ * the cluster may need to be updated to take account of this.
+ *
+ *
+ * USE OF TIMESTAMPS IN THE BROKER
+ *
+ * The following are the current areas where broker uses timers or timestamps:
+ *
+ * - Producer flow control: broker::SemanticState uses connection::getClusterOrderOutput.
+ * a FrameHandler that sends frames to the client via the cluster. Used by broker::SessionState
+ *
+ * - QueueCleaner, Message TTL: uses ExpiryPolicy, which is implemented by cluster::ExpiryPolicy.
+ *
+ * - Connection heartbeat: sends connection controls, not part of session command counting so OK to ignore.
+ *
+ * - LinkRegistry: only cluster elder is ever active for links.
+ *
+ * - management::ManagementBroker: uses MessageHandler supplied by cluster
+ * to send messages to the broker via the cluster.
+ *
+ * - Dtx: not yet supported with cluster.
+ *
+ * cluster::ExpiryPolicy implements the strategy for message expiry.
+ *
+ * CLUSTER PROTOCOL OVERVIEW
+ *
+ * Messages sent to/from CPG are called Events.
+ *
+ * An Event carries a ConnectionId, which includes a MemberId and a
+ * connection number.
+ *
+ * Events are either
+ * - Connection events: non-0 connection number and are associated with a connection.
+ * - Cluster Events: 0 connection number, are not associated with a connection.
+ *
+ * Events are further categorized as:
+ * - Control: carries method frame(s) that affect cluster behavior.
+ * - Data: carries raw data received from a client connection.
+ *
+ * The cluster defines extensions to the AMQP command set in ../../../xml/cluster.xml
+ * which defines two classes:
+ * - cluster: cluster control information.
+ * - cluster.connection: control information for a specific connection.
+ *
+ * The following combinations are legal:
+ * - Data frames carrying connection data.
+ * - Cluster control events carrying cluster commands.
+ * - Connection control events carrying cluster.connection commands.
+ * - Connection control events carrying non-cluster frames: frames sent to the client.
+ * e.g. flow-control frames generated on a timer.
+ *
+ * CLUSTER INITIALIZATION OVERVIEW
+ *
+ * When a new member joins the CPG group, all members (including the
+ * new one) multicast their "initial status." The new member is in
+ * INIT mode until it gets a complete set of initial status messages
+ * from all cluster members.
+ *
+ * The newcomer uses initial status to determine
+ * - The cluster UUID
+ * - Am I speaking the correct version of the cluster protocol?
+ * - Do I need to get an update from an existing active member?
+ * - Can I recover from my own store?
+ *
+ * Initialization happens in the Cluster constructor (plugin
+ * early-init phase) because it needs to be done before the store
+ * initializes. In INIT mode sending & receiving from the cluster are
+ * done single-threaded, bypassing the normal PollableQueues because
+ * the Poller is not active at this point to service them.
+ */
+#include "qpid/Exception.h"
+#include "qpid/cluster/Cluster.h"
+#include "qpid/cluster/ClusterSettings.h"
+#include "qpid/cluster/Connection.h"
+#include "qpid/cluster/UpdateClient.h"
+#include "qpid/cluster/RetractClient.h"
+#include "qpid/cluster/FailoverExchange.h"
+#include "qpid/cluster/UpdateExchange.h"
+
+#include "qpid/assert.h"
+#include "qmf/org/apache/qpid/cluster/ArgsClusterStopClusterNode.h"
+#include "qmf/org/apache/qpid/cluster/Package.h"
#include "qpid/broker/Broker.h"
-#include "qpid/broker/SessionState.h"
#include "qpid/broker/Connection.h"
+#include "qpid/broker/NullMessageStore.h"
+#include "qpid/broker/QueueRegistry.h"
+#include "qpid/broker/SessionState.h"
+#include "qpid/broker/SignalHandler.h"
#include "qpid/framing/AMQFrame.h"
-#include "qpid/framing/ClusterNotifyBody.h"
-#include "qpid/framing/ClusterConnectionCloseBody.h"
+#include "qpid/framing/AMQP_AllOperations.h"
+#include "qpid/framing/AllInvoker.h"
+#include "qpid/framing/ClusterConfigChangeBody.h"
+#include "qpid/framing/ClusterConnectionDeliverCloseBody.h"
+#include "qpid/framing/ClusterConnectionAbortBody.h"
+#include "qpid/framing/ClusterRetractOfferBody.h"
+#include "qpid/framing/ClusterConnectionDeliverDoOutputBody.h"
+#include "qpid/framing/ClusterReadyBody.h"
+#include "qpid/framing/ClusterShutdownBody.h"
+#include "qpid/framing/ClusterUpdateOfferBody.h"
+#include "qpid/framing/ClusterUpdateRequestBody.h"
+#include "qpid/framing/ClusterConnectionAnnounceBody.h"
+#include "qpid/framing/ClusterErrorCheckBody.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/log/Helpers.h"
#include "qpid/log/Statement.h"
+#include "qpid/management/IdAllocator.h"
+#include "qpid/management/ManagementAgent.h"
#include "qpid/memory.h"
-#include "qpid/shared_ptr.h"
+#include "qpid/sys/Thread.h"
+#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/cast.hpp>
+#include <boost/current_function.hpp>
#include <algorithm>
#include <iterator>
#include <map>
+#include <ostream>
namespace qpid {
namespace cluster {
+using namespace qpid;
using namespace qpid::framing;
using namespace qpid::sys;
+using namespace qpid::cluster;
+using namespace framing::cluster;
using namespace std;
-using broker::Connection;
+using management::ManagementAgent;
+using management::ManagementObject;
+using management::Manageable;
+using management::Args;
+namespace _qmf = ::qmf::org::apache::qpid::cluster;
+
+/**
+ * NOTE: must increment this number whenever any incompatible changes in
+ * cluster protocol/behavior are made. It allows early detection and
+ * sensible reporting of an attempt to mix different versions in a
+ * cluster.
+ *
+ * Currently use SVN revision to avoid clashes with versions from
+ * different branches.
+ */
+const uint32_t Cluster::CLUSTER_VERSION = 884125;
-ostream& operator <<(ostream& out, const Cluster& cluster) {
- return out << cluster.name.str() << "-" << cluster.self;
-}
+struct ClusterDispatcher : public framing::AMQP_AllOperations::ClusterHandler {
+ qpid::cluster::Cluster& cluster;
+ MemberId member;
+ Cluster::Lock& l;
+ ClusterDispatcher(Cluster& c, const MemberId& id, Cluster::Lock& l_) : cluster(c), member(id), l(l_) {}
-ostream& operator<<(ostream& out, const Cluster::MemberMap::value_type& m) {
- return out << m.first << "=" << m.second.url;
-}
+ void updateRequest(const std::string& url) { cluster.updateRequest(member, url, l); }
-ostream& operator <<(ostream& out, const Cluster::MemberMap& members) {
- ostream_iterator<Cluster::MemberMap::value_type> o(out, " ");
- copy(members.begin(), members.end(), o);
- return out;
-}
+ void initialStatus(uint32_t version, bool active, const Uuid& clusterId,
+ uint8_t storeState, const Uuid& shutdownId)
+ {
+ cluster.initialStatus(member, version, active, clusterId,
+ framing::cluster::StoreState(storeState), shutdownId, l);
+ }
+ void ready(const std::string& url) { cluster.ready(member, url, l); }
+ void configChange(const std::string& current) { cluster.configChange(member, current, l); }
+ void updateOffer(uint64_t updatee) {
+ cluster.updateOffer(member, updatee, l);
+ }
+ void retractOffer(uint64_t updatee) { cluster.retractOffer(member, updatee, l); }
+ void messageExpired(uint64_t id) { cluster.messageExpired(member, id, l); }
+ void errorCheck(uint8_t type, const framing::SequenceNumber& frameSeq) {
+ cluster.errorCheck(member, type, frameSeq, l);
+ }
+
+ void shutdown(const Uuid& id) { cluster.shutdown(member, id, l); }
+
+ bool invoke(AMQBody& body) { return framing::invoke(*this, body).wasHandled(); }
+};
-Cluster::Cluster(const std::string& name_, const Url& url_, broker::Broker& b) :
- broker(&b),
+Cluster::Cluster(const ClusterSettings& set, broker::Broker& b) :
+ settings(set),
+ broker(b),
+ mgmtObject(0),
poller(b.getPoller()),
cpg(*this),
- name(name_),
- url(url_),
+ name(settings.name),
+ myUrl(settings.url.empty() ? Url() : Url(settings.url)),
self(cpg.self()),
- cpgDispatchHandle(cpg,
- boost::bind(&Cluster::dispatch, this, _1), // read
- 0, // write
- boost::bind(&Cluster::disconnect, this, _1) // disconnect
- ),
- deliverQueue(boost::bind(&Cluster::deliverQueueCb, this, _1, _2)),
- mcastQueue(boost::bind(&Cluster::mcastQueueCb, this, _1, _2))
+ clusterId(true),
+ expiryPolicy(new ExpiryPolicy(mcast, self, broker.getTimer())),
+ mcast(cpg, poller, boost::bind(&Cluster::leave, this)),
+ dispatcher(cpg, poller, boost::bind(&Cluster::leave, this)),
+ deliverEventQueue(boost::bind(&Cluster::deliveredEvent, this, _1),
+ boost::bind(&Cluster::leave, this),
+ "Error decoding events",
+ poller),
+ deliverFrameQueue(boost::bind(&Cluster::deliveredFrame, this, _1),
+ boost::bind(&Cluster::leave, this),
+ "Error delivering frames",
+ poller),
+ quorum(boost::bind(&Cluster::leave, this)),
+ decoder(boost::bind(&Cluster::deliverFrame, this, _1)),
+ discarding(true),
+ state(INIT),
+ initMap(self, settings.size),
+ store(broker.getDataDir().getPath()),
+ lastSize(0),
+ lastBroker(false),
+ updateRetracted(false),
+ error(*this)
{
- broker->addFinalizer(boost::bind(&Cluster::leave, this));
- QPID_LOG(trace, "Joining cluster: " << name_);
- cpg.join(name);
- notify();
+ mAgent = broker.getManagementAgent();
+ if (mAgent != 0){
+ _qmf::Package packageInit(mAgent);
+ mgmtObject = new _qmf::Cluster (mAgent, this, &broker,name,myUrl.str());
+ mAgent->addObject (mgmtObject);
+ mgmtObject->set_status("JOINING");
+ }
- // FIXME aconway 2008-08-11: can we remove this loop?
- // Dispatch till we show up in the cluster map.
- while (empty())
- cpg.dispatchOne();
+ // Failover exchange provides membership updates to clients.
+ failoverExchange.reset(new FailoverExchange(this));
+ broker.getExchanges().registerExchange(failoverExchange);
+
+ // Update exchange is used during updates to replicate messages
+ // without modifying delivery-properties.exchange.
+ broker.getExchanges().registerExchange(
+ boost::shared_ptr<broker::Exchange>(new UpdateExchange(this)));
+ // Load my store status before we go into initialization
+ if (! broker::NullMessageStore::isNullStore(&broker.getStore())) {
+ store.load();
+ if (store.getClusterId())
+ clusterId = store.getClusterId(); // Use stored ID if there is one.
+ QPID_LOG(notice, "Cluster store state: " << store)
+ }
- // Start dispatching from the poller.
- cpgDispatchHandle.startWatch(poller);
- deliverQueue.start(poller);
- mcastQueue.start(poller);
+ cpg.join(name);
+ // Pump the CPG dispatch manually till we get initialized.
+ while (state == INIT)
+ cpg.dispatchOne();
}
Cluster::~Cluster() {
- for (ShadowConnectionMap::iterator i = shadowConnectionMap.begin();
- i != shadowConnectionMap.end();
- ++i)
- {
- i->second->dirtyClose();
+ if (updateThread.id()) updateThread.join(); // Join the previous updatethread.
+}
+
+void Cluster::initialize() {
+ if (settings.quorum) quorum.start(poller);
+ if (myUrl.empty())
+ myUrl = Url::getIpAddressesUrl(broker.getPort(broker::Broker::TCP_TRANSPORT));
+ // Cluster constructor will leave us in either READY or JOINER state.
+ switch (state) {
+ case READY:
+ mcast.mcastControl(ClusterReadyBody(ProtocolVersion(), myUrl.str()), self);
+ break;
+ case JOINER:
+ mcast.mcastControl(ClusterUpdateRequestBody(ProtocolVersion(), myUrl.str()), self);
+ break;
+ default:
+ assert(0);
}
- std::for_each(localConnectionSet.begin(), localConnectionSet.end(), boost::bind(&ConnectionInterceptor::dirtyClose, _1));
+ QPID_LOG(notice, *this << (state == READY ? " joined" : " joining") << " cluster " << name);
+ broker.getKnownBrokers = boost::bind(&Cluster::getUrls, this);
+ broker.setExpiryPolicy(expiryPolicy);
+ dispatcher.start();
+ deliverEventQueue.start();
+ deliverFrameQueue.start();
+
+ // Add finalizer last for exception safety.
+ broker.addFinalizer(boost::bind(&Cluster::brokerShutdown, this));
}
-// local connection initializes plugins
-void Cluster::initialize(broker::Connection& c) {
- bool isLocal = &c.getOutput() != &shadowOut;
- if (isLocal)
- localConnectionSet.insert(new ConnectionInterceptor(c, *this));
+// Called in connection thread to insert a client connection.
+void Cluster::addLocalConnection(const boost::intrusive_ptr<Connection>& c) {
+ QPID_LOG(info, *this << " new local connection " << c->getId());
+ localConnections.insert(c);
+ assert(c->getId().getMember() == self);
+ // Announce the connection to the cluster.
+ if (c->isLocalClient())
+ mcast.mcastControl(ClusterConnectionAnnounceBody(ProtocolVersion(),
+ c->getBrokerConnection().getSSF() ),
+ c->getId());
}
-void Cluster::leave() {
- Mutex::ScopedLock l(lock);
- if (!broker) return; // Already left.
- // At this point the poller has already been shut down so
- // no dispatches can occur thru the cpgDispatchHandle.
- //
- // FIXME aconway 2008-08-11: assert this is the cae.
-
- QPID_LOG(debug, "Leaving cluster " << *this);
- cpg.leave(name);
- // broker= is set to 0 when the final config-change is delivered.
- while(broker) {
- Mutex::ScopedUnlock u(lock);
- cpg.dispatchAll();
- }
- cpg.shutdown();
+// Called in connection thread to insert an updated shadow connection.
+void Cluster::addShadowConnection(const boost::intrusive_ptr<Connection>& c) {
+ QPID_LOG(info, *this << " new shadow connection " << c->getId());
+ // Safe to use connections here because we're pre-catchup, stalled
+ // and discarding, so deliveredFrame is not processing any
+ // connection events.
+ assert(discarding);
+ pair<ConnectionMap::iterator, bool> ib
+ = connections.insert(ConnectionMap::value_type(c->getId(), c));
+ assert(ib.second);
+}
+
+void Cluster::erase(const ConnectionId& id) {
+ Lock l(lock);
+ erase(id,l);
}
-template <class T> void decodePtr(Buffer& buf, T*& ptr) {
- uint64_t value = buf.getLongLong();
- ptr = reinterpret_cast<T*>(value);
+// Called by Connection::deliverClose() in deliverFrameQueue thread.
+void Cluster::erase(const ConnectionId& id, Lock&) {
+ QPID_LOG(info, *this << " connection closed " << id);
+ connections.erase(id);
+ decoder.erase(id);
}
-template <class T> void encodePtr(Buffer& buf, T* ptr) {
- uint64_t value = reinterpret_cast<uint64_t>(ptr);
- buf.putLongLong(value);
+std::vector<string> Cluster::getIds() const {
+ Lock l(lock);
+ return getIds(l);
}
-void Cluster::send(const AMQFrame& frame, ConnectionInterceptor* connection) {
- QPID_LOG(trace, "MCAST [" << connection << "] " << frame);
- mcastQueue.push(Message(frame, self, connection));
+std::vector<string> Cluster::getIds(Lock&) const {
+ return map.memberIds();
}
-void Cluster::mcastQueueCb(const MessageQueue::iterator& begin,
- const MessageQueue::iterator& end)
+std::vector<Url> Cluster::getUrls() const {
+ Lock l(lock);
+ return getUrls(l);
+}
+
+std::vector<Url> Cluster::getUrls(Lock&) const {
+ return map.memberUrls();
+}
+
+void Cluster::leave() {
+ Lock l(lock);
+ leave(l);
+}
+
+#define LEAVE_TRY(STMT) try { STMT; } \
+ catch (const std::exception& e) { \
+ QPID_LOG(warning, *this << " error leaving cluster: " << e.what()); \
+ } do {} while(0)
+
+void Cluster::leave(Lock&) {
+ if (state != LEFT) {
+ state = LEFT;
+ QPID_LOG(notice, *this << " leaving cluster " << name);
+ // Finalize connections now now to avoid problems later in destructor.
+ LEAVE_TRY(localConnections.clear());
+ LEAVE_TRY(connections.clear());
+ LEAVE_TRY(broker::SignalHandler::shutdown());
+ }
+}
+
+// Deliver CPG message.
+void Cluster::deliver(
+ cpg_handle_t /*handle*/,
+ const cpg_name* /*group*/,
+ uint32_t nodeid,
+ uint32_t pid,
+ void* msg,
+ int msg_len)
{
- // Static is OK because there is only one cluster allowed per
- // process and only one thread in mcastQueueCb at a time.
- static char buffer[64*1024]; // FIXME aconway 2008-07-04: buffer management.
- MessageQueue::iterator i = begin;
- while (i != end) {
- Buffer buf(buffer, sizeof(buffer));
- while (i != end && buf.available() > i->frame.size() + sizeof(uint64_t)) {
- i->frame.encode(buf);
- encodePtr(buf, i->connection);
- ++i;
+ MemberId from(nodeid, pid);
+ framing::Buffer buf(static_cast<char*>(msg), msg_len);
+ Event e(Event::decodeCopy(from, buf));
+ deliverEvent(e);
+}
+
+void Cluster::deliverEvent(const Event& e) {
+ // During initialization, execute events directly in the same thread.
+ // Once initialized, push to pollable queue to be processed in another thread.
+ if (state == INIT)
+ deliveredEvent(e);
+ else
+ deliverEventQueue.push(e);
+}
+
+void Cluster::deliverFrame(const EventFrame& e) {
+ // During initialization, execute events directly in the same thread.
+ // Once initialized, push to pollable queue to be processed in another thread.
+ if (state == INIT)
+ deliveredFrame(e);
+ else
+ deliverFrameQueue.push(e);
+}
+
+const ClusterUpdateOfferBody* castUpdateOffer(const framing::AMQBody* body) {
+ return (body && body->getMethod() &&
+ body->getMethod()->isA<ClusterUpdateOfferBody>()) ?
+ static_cast<const ClusterUpdateOfferBody*>(body) : 0;
+}
+
+const ClusterConnectionAnnounceBody* castAnnounce( const framing::AMQBody *body) {
+ return (body && body->getMethod() &&
+ body->getMethod()->isA<ClusterConnectionAnnounceBody>()) ?
+ static_cast<const ClusterConnectionAnnounceBody*>(body) : 0;
+}
+
+// Handler for deliverEventQueue.
+// This thread decodes frames from events.
+void Cluster::deliveredEvent(const Event& e) {
+ if (e.isCluster()) {
+ EventFrame ef(e, e.getFrame());
+ // Stop the deliverEventQueue on update offers.
+ // This preserves the connection decoder fragments for an update.
+ const ClusterUpdateOfferBody* offer = castUpdateOffer(ef.frame.getBody());
+ if (offer) {
+ QPID_LOG(info, *this << " stall for update offer from " << e.getMemberId()
+ << " to " << MemberId(offer->getUpdatee()));
+ deliverEventQueue.stop();
+ }
+ deliverFrame(ef);
+ }
+ else if(!discarding) {
+ if (e.isControl())
+ deliverFrame(EventFrame(e, e.getFrame()));
+ else {
+ try { decoder.decode(e, e.getData()); }
+ catch (const Exception& ex) {
+ // Close a connection that is sending us invalid data.
+ QPID_LOG(error, *this << " aborting connection "
+ << e.getConnectionId() << ": " << ex.what());
+ framing::AMQFrame abort((ClusterConnectionAbortBody()));
+ deliverFrame(EventFrame(EventHeader(CONTROL, e.getConnectionId()), abort));
+ }
}
- iovec iov = { buffer, buf.getPosition() };
- cpg.mcast(name, &iov, 1);
}
}
-void Cluster::notify() {
- send(AMQFrame(in_place<ClusterNotifyBody>(ProtocolVersion(), url.str())), 0);
+void Cluster::flagError(
+ Connection& connection, ErrorCheck::ErrorType type, const std::string& msg)
+{
+ Mutex::ScopedLock l(lock);
+ if (connection.isCatchUp()) {
+ QPID_LOG(critical, *this << " error on update connection " << connection
+ << ": " << msg);
+ leave(l);
+ }
+ error.error(connection, type, map.getFrameSeq(), map.getMembers(), msg);
}
-size_t Cluster::size() const {
+// Handler for deliverFrameQueue.
+// This thread executes the main logic.
+void Cluster::deliveredFrame(const EventFrame& efConst) {
Mutex::ScopedLock l(lock);
- return members.size();
+ if (state == LEFT) return;
+ EventFrame e(efConst);
+ const ClusterUpdateOfferBody* offer = castUpdateOffer(e.frame.getBody());
+ if (offer && error.isUnresolved()) {
+ // We can't honour an update offer that is delivered while an
+ // error is in progress so replace it with a retractOffer and re-start
+ // the event queue.
+ e.frame = AMQFrame(
+ ClusterRetractOfferBody(ProtocolVersion(), offer->getUpdatee()));
+ deliverEventQueue.start();
+ }
+ // Process each frame through the error checker.
+ if (error.isUnresolved()) {
+ error.delivered(e);
+ while (error.canProcess()) // There is a frame ready to process.
+ processFrame(error.getNext(), l);
+ }
+ else
+ processFrame(e, l);
}
-Cluster::MemberList Cluster::getMembers() const {
- Mutex::ScopedLock l(lock);
- MemberList result(members.size());
- std::transform(members.begin(), members.end(), result.begin(),
- boost::bind(&MemberMap::value_type::second, _1));
- return result;
+
+void Cluster::processFrame(const EventFrame& e, Lock& l) {
+ if (e.isCluster()) {
+ QPID_LOG(trace, *this << " DLVR: " << e);
+ ClusterDispatcher dispatch(*this, e.connectionId.getMember(), l);
+ if (!framing::invoke(dispatch, *e.frame.getBody()).wasHandled())
+ throw Exception(QPID_MSG("Invalid cluster control"));
+ }
+ else if (state >= CATCHUP) {
+ map.incrementFrameSeq();
+ ConnectionPtr connection = getConnection(e, l);
+ if (connection) {
+ QPID_LOG(trace, *this << " DLVR " << map.getFrameSeq() << ": " << e);
+ connection->deliveredFrame(e);
+ }
+ else
+ QPID_LOG(trace, *this << " DROP (no connection): " << e);
+ }
+ else // Drop connection frames while state < CATCHUP
+ QPID_LOG(trace, *this << " DROP (joining): " << e);
}
-// ################ HERE - leaking shadow connections.
-// FIXME aconway 2008-08-11: revisit memory management for shadow
-// connections, what if the Connection is closed other than via
-// disconnect? Dangling pointer in shadow map. Use ptr_map for shadow
-// map, add deleted state to ConnectionInterceptor? Interceptors need
-// to know about map? Check how Connections can be deleted.
+// Called in deliverFrameQueue thread
+ConnectionPtr Cluster::getConnection(const EventFrame& e, Lock&) {
+ ConnectionId id = e.connectionId;
+ ConnectionMap::iterator i = connections.find(id);
+ if (i != connections.end()) return i->second;
+ ConnectionPtr cp;
+ // If the frame is an announcement for a new connection, add it.
+ if (e.frame.getBody() && e.frame.getMethod() &&
+ e.frame.getMethod()->isA<ClusterConnectionAnnounceBody>())
+ {
+ if (id.getMember() == self) { // Announces one of my own
+ cp = localConnections.getErase(id);
+ assert(cp);
+ }
+ else { // New remote connection, create a shadow.
+ std::ostringstream mgmtId;
+ unsigned int ssf;
+ const ClusterConnectionAnnounceBody *announce = castAnnounce(e.frame.getBody());
+
+ mgmtId << id;
+ ssf = (announce && announce->hasSsf()) ? announce->getSsf() : 0;
+ QPID_LOG(debug, *this << "new connection's ssf =" << ssf );
+ cp = new Connection(*this, shadowOut, mgmtId.str(), id, ssf );
+ }
+ connections.insert(ConnectionMap::value_type(id, cp));
+ }
+ return cp;
+}
-ConnectionInterceptor* Cluster::getShadowConnection(const Cpg::Id& member, void* remotePtr) {
- ShadowConnectionId id(member, remotePtr);
- ShadowConnectionMap::iterator i = shadowConnectionMap.find(id);
- if (i == shadowConnectionMap.end()) { // A new shadow connection.
- std::ostringstream os;
- os << name << ":" << member << ":" << remotePtr;
- assert(broker);
- broker::Connection* c = new broker::Connection(&shadowOut, *broker, os.str());
- ShadowConnectionMap::value_type value(id, new ConnectionInterceptor(*c, *this, id));
- i = shadowConnectionMap.insert(value).first;
+Cluster::ConnectionVector Cluster::getConnections(Lock&) {
+ ConnectionVector result(connections.size());
+ std::transform(connections.begin(), connections.end(), result.begin(),
+ boost::bind(&ConnectionMap::value_type::second, _1));
+ return result;
+}
+
+struct AddrList {
+ const cpg_address* addrs;
+ int count;
+ const char *prefix, *suffix;
+ AddrList(const cpg_address* a, int n, const char* p="", const char* s="")
+ : addrs(a), count(n), prefix(p), suffix(s) {}
+};
+
+ostream& operator<<(ostream& o, const AddrList& a) {
+ if (!a.count) return o;
+ o << a.prefix;
+ for (const cpg_address* p = a.addrs; p < a.addrs+a.count; ++p) {
+ const char* reasonString;
+ switch (p->reason) {
+ case CPG_REASON_JOIN: reasonString = "(joined) "; break;
+ case CPG_REASON_LEAVE: reasonString = "(left) "; break;
+ case CPG_REASON_NODEDOWN: reasonString = "(node-down) "; break;
+ case CPG_REASON_NODEUP: reasonString = "(node-up) "; break;
+ case CPG_REASON_PROCDOWN: reasonString = "(process-down) "; break;
+ default: reasonString = " ";
+ }
+ qpid::cluster::MemberId member(*p);
+ o << member << reasonString;
}
- return i->second;
+ return o << a.suffix;
}
-void Cluster::deliver(
+void Cluster::configChange (
cpg_handle_t /*handle*/,
- cpg_name* /*group*/,
- uint32_t nodeid,
- uint32_t pid,
- void* msg,
- int msg_len)
+ const cpg_name */*group*/,
+ const cpg_address *current, int nCurrent,
+ const cpg_address *left, int nLeft,
+ const cpg_address *joined, int nJoined)
{
- Id from(nodeid, pid);
- try {
- Buffer buf(static_cast<char*>(msg), msg_len);
- while (buf.available() > 0) {
- AMQFrame frame;
- if (!frame.decode(buf)) // Not enough data.
- throw Exception("Received incomplete cluster event.");
- void* connection;
- decodePtr(buf, connection);
- deliverQueue.push(Message(frame, from, connection));
+ Mutex::ScopedLock l(lock);
+ QPID_LOG(notice, *this << " membership change: "
+ << AddrList(current, nCurrent) << "("
+ << AddrList(joined, nJoined, "joined: ")
+ << AddrList(left, nLeft, "left: ")
+ << ")");
+ std::string addresses;
+ for (const cpg_address* p = current; p < current+nCurrent; ++p)
+ addresses.append(MemberId(*p).str());
+ deliverEvent(Event::control(ClusterConfigChangeBody(ProtocolVersion(), addresses), self));
+}
+
+void Cluster::setReady(Lock&) {
+ state = READY;
+ if (mgmtObject!=0) mgmtObject->set_status("ACTIVE");
+ mcast.setReady();
+ broker.getQueueEvents().enable();
+}
+
+void Cluster::initMapCompleted(Lock& l) {
+ // Called on completion of the initial status map.
+ QPID_LOG(debug, *this << " initial status map complete. ");
+ if (state == INIT) {
+ // We have status for all members so we can make join descisions.
+ initMap.checkConsistent();
+ elders = initMap.getElders();
+ QPID_LOG(debug, *this << " elders: " << elders);
+ if (!elders.empty()) { // I'm not the elder, I don't handle links & replication.
+ broker.getLinks().setPassive(true);
+ broker.getQueueEvents().disable();
+ QPID_LOG(info, *this << " not active for links.");
+ }
+ else {
+ QPID_LOG(info, this << " active for links.");
+ }
+ setClusterId(initMap.getClusterId(), l);
+ if (store.hasStore()) store.dirty(clusterId);
+
+ if (initMap.isUpdateNeeded()) { // Joining established cluster.
+ broker.setRecovery(false); // Ditch my current store.
+ broker.setClusterUpdatee(true);
+ state = JOINER;
+ }
+ else { // I can go ready.
+ discarding = false;
+ setReady(l);
+ memberUpdate(l);
}
+ QPID_LOG(debug, *this << "Initialization complete");
+ }
+}
+
+void Cluster::configChange(const MemberId&, const std::string& configStr, Lock& l) {
+ if (state == LEFT) return;
+
+ MemberSet config = decodeMemberSet(configStr);
+ elders = intersection(elders, config);
+ if (elders.empty() && INIT < state && state < CATCHUP) {
+ QPID_LOG(critical, "Cannot update, all potential updaters left the cluster.");
+ leave(l);
+ return;
}
+ bool memberChange = map.configChange(config);
+
+ // Update initital status for new members joining.
+ initMap.configChange(config);
+ if (initMap.isResendNeeded()) {
+ mcast.mcastControl(
+ ClusterInitialStatusBody(
+ ProtocolVersion(), CLUSTER_VERSION, state > INIT, clusterId,
+ store.getState(), store.getShutdownId()
+ ),
+ self);
+ }
+ if (initMap.transitionToComplete()) initMapCompleted(l);
+
+ if (state >= CATCHUP && memberChange) {
+ memberUpdate(l);
+ if (elders.empty()) {
+ // We are the oldest, reactive links if necessary
+ QPID_LOG(info, this << " becoming active for links.");
+ broker.getLinks().setPassive(false);
+ }
+ }
+}
+
+void Cluster::makeOffer(const MemberId& id, Lock& ) {
+ if (state == READY && map.isJoiner(id)) {
+ state = OFFER;
+ QPID_LOG(info, *this << " send update-offer to " << id);
+ mcast.mcastControl(ClusterUpdateOfferBody(ProtocolVersion(), id), self);
+ }
+}
+
+// Called from Broker::~Broker when broker is shut down. At this
+// point we know the poller has stopped so no poller callbacks will be
+// invoked. We must ensure that CPG has also shut down so no CPG
+// callbacks will be invoked.
+//
+void Cluster::brokerShutdown() {
+ try { cpg.shutdown(); }
catch (const std::exception& e) {
- // FIXME aconway 2008-01-30: exception handling.
- QPID_LOG(critical, "Error in cluster deliver: " << e.what());
- assert(0);
- throw;
+ QPID_LOG(error, *this << " shutting down CPG: " << e.what());
}
+ delete this;
+}
+
+void Cluster::updateRequest(const MemberId& id, const std::string& url, Lock& l) {
+ map.updateRequest(id, url);
+ makeOffer(id, l);
}
-void Cluster::deliverQueueCb(const MessageQueue::iterator& begin,
- const MessageQueue::iterator& end)
+void Cluster::initialStatus(const MemberId& member, uint32_t version, bool active,
+ const framing::Uuid& id,
+ framing::cluster::StoreState store,
+ const framing::Uuid& shutdownId,
+ Lock& l)
{
- for (MessageQueue::iterator i = begin; i != end; ++i) {
- AMQFrame& frame(i->frame);
- Id from(i->from);
- ConnectionInterceptor* connection = reinterpret_cast<ConnectionInterceptor*>(i->connection);
- try {
- QPID_LOG(trace, "DLVR [" << from << " " << connection << "] " << frame);
-
- if (!broker) {
- QPID_LOG(warning, "Unexpected DLVR, already left the cluster.");
- return;
- }
- if (connection && from != self) // Look up shadow for remote connections
- connection = getShadowConnection(from, connection);
+ if (version != CLUSTER_VERSION) {
+ QPID_LOG(critical, *this << " incompatible cluster versions " <<
+ version << " != " << CLUSTER_VERSION);
+ leave(l);
+ return;
+ }
+ initMap.received(
+ member,
+ ClusterInitialStatusBody(ProtocolVersion(), version, active, id, store, shutdownId)
+ );
+ if (initMap.transitionToComplete()) initMapCompleted(l);
+}
- if (frame.getMethod() && frame.getMethod()->amqpClassId() == CLUSTER_CLASS_ID)
- handleMethod(from, connection, *frame.getMethod());
- else
- connection->deliver(frame);
+void Cluster::ready(const MemberId& id, const std::string& url, Lock& l) {
+ if (map.ready(id, Url(url)))
+ memberUpdate(l);
+ if (state == CATCHUP && id == self) {
+ setReady(l);
+ QPID_LOG(notice, *this << " caught up.");
+ }
+}
+
+void Cluster::updateOffer(const MemberId& updater, uint64_t updateeInt, Lock& l) {
+ // NOTE: deliverEventQueue has been stopped at the update offer by
+ // deliveredEvent in case an update is required.
+ if (state == LEFT) return;
+ MemberId updatee(updateeInt);
+ boost::optional<Url> url = map.updateOffer(updater, updatee);
+ if (updater == self) {
+ assert(state == OFFER);
+ if (url) // My offer was first.
+ updateStart(updatee, *url, l);
+ else { // Another offer was first.
+ QPID_LOG(info, *this << " cancelled offer to " << updatee << " unstall");
+ setReady(l);
+ makeOffer(map.firstJoiner(), l); // Maybe make another offer.
+ deliverEventQueue.start(); // Go back to normal processing
}
- catch (const std::exception& e) {
- // FIXME aconway 2008-01-30: exception handling.
- QPID_LOG(critical, "Error in cluster deliverQueueCb: " << e.what());
- assert(0);
- throw;
+ }
+ else if (updatee == self && url) {
+ assert(state == JOINER);
+ state = UPDATEE;
+ QPID_LOG(notice, *this << " receiving update from " << updater);
+ checkUpdateIn(l);
+ }
+ else {
+ QPID_LOG(debug,*this << " unstall, ignore update " << updater
+ << " to " << updatee);
+ deliverEventQueue.start(); // Not involved in update.
+ }
+}
+
+static client::ConnectionSettings connectionSettings(const ClusterSettings& settings) {
+ client::ConnectionSettings cs;
+ cs.username = settings.username;
+ cs.password = settings.password;
+ cs.mechanism = settings.mechanism;
+ return cs;
+}
+
+void Cluster::retractOffer(const MemberId& updater, uint64_t updateeInt, Lock& l) {
+ // An offer was received while handling an error, and converted to a retract.
+ // Behavior is very similar to updateOffer.
+ if (state == LEFT) return;
+ MemberId updatee(updateeInt);
+ boost::optional<Url> url = map.updateOffer(updater, updatee);
+ if (updater == self) {
+ assert(state == OFFER);
+ if (url) { // My offer was first.
+ if (updateThread.id())
+ updateThread.join(); // Join the previous updateThread to avoid leaks.
+ updateThread = Thread(new RetractClient(*url, connectionSettings(settings)));
}
+ setReady(l);
+ makeOffer(map.firstJoiner(), l); // Maybe make another offer.
+ // Don't unstall the event queue, that was already done in deliveredFrame
}
+ QPID_LOG(debug,*this << " retracted offer " << updater << " to " << updatee);
+}
+
+void Cluster::updateStart(const MemberId& updatee, const Url& url, Lock& l) {
+ // NOTE: deliverEventQueue is already stopped at the stall point by deliveredEvent.
+ if (state == LEFT) return;
+ assert(state == OFFER);
+ state = UPDATER;
+ QPID_LOG(notice, *this << " sending update to " << updatee << " at " << url);
+ if (updateThread.id())
+ updateThread.join(); // Join the previous updateThread to avoid leaks.
+ updateThread = Thread(
+ new UpdateClient(self, updatee, url, broker, map, *expiryPolicy,
+ getConnections(l), decoder,
+ boost::bind(&Cluster::updateOutDone, this),
+ boost::bind(&Cluster::updateOutError, this, _1),
+ connectionSettings(settings)));
}
-// Handle cluster methods
-// FIXME aconway 2008-07-11: Generate/template a better dispatch mechanism.
-void Cluster::handleMethod(Id from, ConnectionInterceptor* connection, AMQMethodBody& method) {
- assert(method.amqpClassId() == CLUSTER_CLASS_ID);
- switch (method.amqpMethodId()) {
- case CLUSTER_NOTIFY_METHOD_ID: {
- ClusterNotifyBody& notify=static_cast<ClusterNotifyBody&>(method);
- Mutex::ScopedLock l(lock);
- members[from].url=notify.getUrl();
- lock.notifyAll();
- break;
- }
- case CLUSTER_CONNECTION_CLOSE_METHOD_ID: {
- if (!connection->isLocal())
- shadowConnectionMap.erase(connection->getShadowId());
- else
- localConnectionSet.erase(connection);
- connection->deliverClosed();
- break;
- }
- case CLUSTER_CONNECTION_DO_OUTPUT_METHOD_ID: {
- connection->deliverDoOutput();
- break;
- }
+// Called in update thread.
+void Cluster::updateInDone(const ClusterMap& m) {
+ Lock l(lock);
+ updatedMap = m;
+ checkUpdateIn(l);
+}
+
+void Cluster::updateInRetracted() {
+ Lock l(lock);
+ updateRetracted = true;
+ map.clearStatus();
+ checkUpdateIn(l);
+}
+
+void Cluster::checkUpdateIn(Lock& l) {
+ if (state != UPDATEE) return; // Wait till we reach the stall point.
+ if (updatedMap) { // We're up to date
+ map = *updatedMap;
+ memberUpdate(l);
+ mcast.mcastControl(ClusterReadyBody(ProtocolVersion(), myUrl.str()), self);
+ state = CATCHUP;
+ broker.setClusterUpdatee(false);
+ discarding = false; // ok to set, we're stalled for update.
+ QPID_LOG(notice, *this << " update complete, starting catch-up.");
+ deliverEventQueue.start();
+ }
+ else if (updateRetracted) { // Update was retracted, request another update
+ updateRetracted = false;
+ state = JOINER;
+ QPID_LOG(notice, *this << " update retracted, sending new update request.");
+ mcast.mcastControl(ClusterUpdateRequestBody(ProtocolVersion(), myUrl.str()), self);
+ deliverEventQueue.start();
+ }
+}
+
+void Cluster::updateOutDone() {
+ Monitor::ScopedLock l(lock);
+ updateOutDone(l);
+}
+
+void Cluster::updateOutDone(Lock& l) {
+ QPID_LOG(notice, *this << " update sent");
+ assert(state == UPDATER);
+ state = READY;
+ deliverEventQueue.start(); // Start processing events again.
+ makeOffer(map.firstJoiner(), l); // Try another offer
+}
+
+void Cluster::updateOutError(const std::exception& e) {
+ Monitor::ScopedLock l(lock);
+ QPID_LOG(error, *this << " error sending update: " << e.what());
+ updateOutDone(l);
+}
+
+void Cluster ::shutdown(const MemberId& , const Uuid& id, Lock& l) {
+ QPID_LOG(notice, *this << " cluster shut down by administrator.");
+ if (store.hasStore()) store.clean(Uuid(id));
+ leave(l);
+}
+
+ManagementObject* Cluster::GetManagementObject() const { return mgmtObject; }
+
+Manageable::status_t Cluster::ManagementMethod (uint32_t methodId, Args& args, string&) {
+ Lock l(lock);
+ QPID_LOG(debug, *this << " managementMethod [id=" << methodId << "]");
+ switch (methodId) {
+ case _qmf::Cluster::METHOD_STOPCLUSTERNODE :
+ {
+ _qmf::ArgsClusterStopClusterNode& iargs = (_qmf::ArgsClusterStopClusterNode&) args;
+ stringstream stream;
+ stream << self;
+ if (iargs.i_brokerId == stream.str())
+ stopClusterNode(l);
+ }
+ break;
+ case _qmf::Cluster::METHOD_STOPFULLCLUSTER :
+ stopFullCluster(l);
+ break;
default:
- assert(0);
+ return Manageable::STATUS_UNKNOWN_METHOD;
}
+ return Manageable::STATUS_OK;
}
-void Cluster::configChange(
- cpg_handle_t /*handle*/,
- cpg_name */*group*/,
- cpg_address *current, int nCurrent,
- cpg_address *left, int nLeft,
- cpg_address */*joined*/, int nJoined)
-{
- Mutex::ScopedLock l(lock);
- for (int i = 0; i < nLeft; ++i)
- members.erase(left[i]);
- for(int j = 0; j < nCurrent; ++j)
- members[current[j]].id = current[j];
- QPID_LOG(debug, "Cluster members: " << nCurrent << " ("<< nLeft << " left, " << nJoined << " joined):"
- << members);
- assert(members.size() == size_t(nCurrent));
- if (members.find(self) == members.end())
- broker = 0; // We have left the group, this is the final config change.
- lock.notifyAll(); // Threads waiting for membership changes.
+void Cluster::stopClusterNode(Lock& l) {
+ QPID_LOG(notice, *this << " cluster member stopped by administrator.");
+ leave(l);
}
-void Cluster::dispatch(sys::DispatchHandle& h) {
- cpg.dispatchAll();
- h.rewatch();
+void Cluster::stopFullCluster(Lock& ) {
+ QPID_LOG(notice, *this << " shutting down cluster " << name);
+ mcast.mcastControl(ClusterShutdownBody(ProtocolVersion(), Uuid(true)), self);
}
-void Cluster::disconnect(sys::DispatchHandle& h) {
- h.stopWatch();
- // FIXME aconway 2008-08-11: error handling if we are disconnected.
- // Kill the broker?
- assert(0);
+void Cluster::memberUpdate(Lock& l) {
+ QPID_LOG(info, *this << " member update: " << map);
+ std::vector<Url> urls = getUrls(l);
+ std::vector<string> ids = getIds(l);
+ size_t size = urls.size();
+ failoverExchange->setUrls(urls);
+
+ if (size == 1 && lastSize > 1 && state >= CATCHUP) {
+ QPID_LOG(notice, *this << " last broker standing, update queue policies");
+ lastBroker = true;
+ broker.getQueues().updateQueueClusterState(true);
+ }
+ else if (size > 1 && lastBroker) {
+ QPID_LOG(notice, *this << " last broker standing joined by " << size-1 << " replicas, updating queue policies" << size);
+ lastBroker = false;
+ broker.getQueues().updateQueueClusterState(false);
+ }
+ lastSize = size;
+
+ if (mgmtObject) {
+ mgmtObject->set_clusterSize(size);
+ string urlstr;
+ for(std::vector<Url>::iterator iter = urls.begin(); iter != urls.end(); iter++ ) {
+ if (iter != urls.begin()) urlstr += ";";
+ urlstr += iter->str();
+ }
+ string idstr;
+ for(std::vector<string>::iterator iter = ids.begin(); iter != ids.end(); iter++ ) {
+ if (iter != ids.begin()) idstr += ";";
+ idstr += (*iter);
+ }
+ mgmtObject->set_members(urlstr);
+ mgmtObject->set_memberIDs(idstr);
+ }
+
+ // Close connections belonging to members that have left the cluster.
+ ConnectionMap::iterator i = connections.begin();
+ while (i != connections.end()) {
+ ConnectionMap::iterator j = i++;
+ MemberId m = j->second->getId().getMember();
+ if (m != self && !map.isMember(m)) {
+ j->second->getBrokerConnection().closed();
+ erase(j->second->getId(), l);
+ }
+ }
}
-}} // namespace qpid::cluster
+std::ostream& operator<<(std::ostream& o, const Cluster& cluster) {
+ static const char* STATE[] = {
+ "INIT", "JOINER", "UPDATEE", "CATCHUP", "READY", "OFFER", "UPDATER", "LEFT"
+ };
+ assert(sizeof(STATE)/sizeof(*STATE) == Cluster::LEFT+1);
+ o << "cluster(" << cluster.self << " " << STATE[cluster.state];
+ if (cluster.error.isUnresolved()) o << "/error";
+ return o << ")";;
+}
+MemberId Cluster::getId() const {
+ return self; // Immutable, no need to lock.
+}
+broker::Broker& Cluster::getBroker() const {
+ return broker; // Immutable, no need to lock.
+}
+
+void Cluster::setClusterId(const Uuid& uuid, Lock&) {
+ clusterId = uuid;
+ if (mgmtObject) {
+ stringstream stream;
+ stream << self;
+ mgmtObject->set_clusterID(clusterId.str());
+ mgmtObject->set_memberID(stream.str());
+ }
+ QPID_LOG(debug, *this << " cluster-uuid = " << clusterId);
+}
+
+void Cluster::messageExpired(const MemberId&, uint64_t id, Lock&) {
+ expiryPolicy->deliverExpire(id);
+}
+
+void Cluster::errorCheck(const MemberId& from, uint8_t type, framing::SequenceNumber frameSeq, Lock&) {
+ // If we see an errorCheck here (rather than in the ErrorCheck
+ // class) then we have processed succesfully past the point of the
+ // error.
+ if (state >= CATCHUP) // Don't respond pre catchup, we don't know what happened
+ error.respondNone(from, type, frameSeq);
+}
+
+}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/Cluster.h b/cpp/src/qpid/cluster/Cluster.h
index 2b40193dd3..7872588307 100644
--- a/cpp/src/qpid/cluster/Cluster.h
+++ b/cpp/src/qpid/cluster/Cluster.h
@@ -19,151 +19,261 @@
*
*/
-#include "qpid/cluster/Cpg.h"
-#include "qpid/cluster/ShadowConnectionOutputHandler.h"
-#include "qpid/cluster/PollableQueue.h"
-
+#include "ClusterMap.h"
+#include "ClusterSettings.h"
+#include "Cpg.h"
+#include "Decoder.h"
+#include "ErrorCheck.h"
+#include "Event.h"
+#include "EventFrame.h"
+#include "ExpiryPolicy.h"
+#include "FailoverExchange.h"
+#include "InitialStatusMap.h"
+#include "LockedConnectionMap.h"
+#include "Multicaster.h"
+#include "NoOpConnectionOutputHandler.h"
+#include "PollableQueue.h"
+#include "PollerDispatch.h"
+#include "Quorum.h"
+#include "StoreStatus.h"
+#include "UpdateReceiver.h"
+
+#include "qmf/org/apache/qpid/cluster/Cluster.h"
+#include "qpid/Url.h"
#include "qpid/broker/Broker.h"
-#include "qpid/broker/Connection.h"
-#include "qpid/sys/Dispatcher.h"
+#include "qpid/management/Manageable.h"
#include "qpid/sys/Monitor.h"
-#include "qpid/sys/Runnable.h"
-#include "qpid/sys/Thread.h"
-#include "qpid/log/Logger.h"
-#include "qpid/Url.h"
-#include "qpid/RefCounted.h"
-#include <boost/optional.hpp>
-#include <boost/function.hpp>
+#include <boost/bind.hpp>
#include <boost/intrusive_ptr.hpp>
+#include <boost/optional.hpp>
+#include <algorithm>
#include <map>
#include <vector>
namespace qpid {
+
+namespace framing {
+class AMQBody;
+class Uuid;
+}
+
namespace cluster {
-class ConnectionInterceptor;
+class Connection;
+class EventFrame;
/**
- * Connection to the cluster.
- * Keeps cluster membership data.
+ * Connection to the cluster
*/
-class Cluster : private Cpg::Handler, public RefCounted
-{
+class Cluster : private Cpg::Handler, public management::Manageable {
public:
- typedef boost::tuple<Cpg::Id, void*> ShadowConnectionId;
+ typedef boost::intrusive_ptr<Connection> ConnectionPtr;
+ typedef std::vector<ConnectionPtr> ConnectionVector;
- /** Details of a cluster member */
- struct Member {
- Cpg::Id id;
- Url url;
- };
-
- typedef std::vector<Member> MemberList;
-
- /**
- * Join a cluster.
- * @param name of the cluster.
- * @param url of this broker, sent to the cluster.
- */
- Cluster(const std::string& name, const Url& url, broker::Broker&);
+ // Public functions are thread safe unless otherwise mentioned in a comment.
+ // Construct the cluster in plugin earlyInitialize.
+ Cluster(const ClusterSettings&, broker::Broker&);
virtual ~Cluster();
- /** Initialize interceptors for a new connection */
- void initialize(broker::Connection&);
-
- /** Get the current cluster membership. */
- MemberList getMembers() const;
-
- /** Number of members in the cluster. */
- size_t size() const;
+ // Called by plugin initialize: cluster start-up requires transport plugins .
+ // Thread safety: only called by plugin initialize.
+ void initialize();
- bool empty() const { return size() == 0; }
+ // Connection map.
+ void addLocalConnection(const ConnectionPtr&);
+ void addShadowConnection(const ConnectionPtr&);
+ void erase(const ConnectionId&);
- /** Send frame to the cluster */
- void send(const framing::AMQFrame&, ConnectionInterceptor*);
+ // URLs of current cluster members.
+ std::vector<std::string> getIds() const;
+ std::vector<Url> getUrls() const;
+ boost::shared_ptr<FailoverExchange> getFailoverExchange() const { return failoverExchange; }
- /** Leave the cluster */
+ // Leave the cluster - called when fatal errors occur.
void leave();
-
- // Cluster frame handing functions
- void notify(const std::string& url);
- void connectionClose();
+
+ // Update completed - called in update thread
+ void updateInDone(const ClusterMap&);
+ void updateInRetracted();
+
+ MemberId getId() const;
+ broker::Broker& getBroker() const;
+ Multicaster& getMulticast() { return mcast; }
+
+ const ClusterSettings& getSettings() const { return settings; }
+
+ void deliverFrame(const EventFrame&);
+
+ // Called in deliverFrame thread to indicate an error from the broker.
+ void flagError(Connection&, ErrorCheck::ErrorType, const std::string& msg);
+
+ // Called only during update by Connection::shadowReady
+ Decoder& getDecoder() { return decoder; }
+
+ ExpiryPolicy& getExpiryPolicy() { return *expiryPolicy; }
+
+ UpdateReceiver& getUpdateReceiver() { return updateReceiver; }
private:
- typedef Cpg::Id Id;
- typedef std::map<Id, Member> MemberMap;
- typedef std::map<ShadowConnectionId, ConnectionInterceptor*> ShadowConnectionMap;
- typedef std::set<ConnectionInterceptor*> LocalConnectionSet;
-
- /** Message sent over the cluster. */
- struct Message {
- framing::AMQFrame frame; Id from; void* connection;
- Message(const framing::AMQFrame& f, const Id i, void* c)
- : frame(f), from(i), connection(c) {}
- };
- typedef PollableQueue<Message> MessageQueue;
-
- boost::function<void()> shutdownNext;
-
- void notify(); ///< Notify cluster of my details.
+ typedef sys::Monitor::ScopedLock Lock;
- /** CPG deliver callback. */
- void deliver(
+ typedef PollableQueue<Event> PollableEventQueue;
+ typedef PollableQueue<EventFrame> PollableFrameQueue;
+ typedef std::map<ConnectionId, ConnectionPtr> ConnectionMap;
+
+ /** Version number of the cluster protocol, to avoid mixed versions. */
+ static const uint32_t CLUSTER_VERSION;
+
+ // NB: A dummy Lock& parameter marks functions that must only be
+ // called with Cluster::lock locked.
+
+ void leave(Lock&);
+ std::vector<std::string> getIds(Lock&) const;
+ std::vector<Url> getUrls(Lock&) const;
+
+ // == Called in main thread from Broker destructor.
+ void brokerShutdown();
+
+ // == Called in deliverEventQueue thread
+ void deliveredEvent(const Event&);
+
+ // == Called in deliverFrameQueue thread
+ void deliveredFrame(const EventFrame&);
+ void processFrame(const EventFrame&, Lock&);
+
+ // Cluster controls implement XML methods from cluster.xml.
+ void updateRequest(const MemberId&, const std::string&, Lock&);
+ void updateOffer(const MemberId& updater, uint64_t updatee, Lock&);
+ void retractOffer(const MemberId& updater, uint64_t updatee, Lock&);
+ void initialStatus(const MemberId&,
+ uint32_t version,
+ bool active,
+ const framing::Uuid& clusterId,
+ framing::cluster::StoreState,
+ const framing::Uuid& shutdownId,
+ Lock&);
+ void ready(const MemberId&, const std::string&, Lock&);
+ void configChange(const MemberId&, const std::string& current, Lock& l);
+ void messageExpired(const MemberId&, uint64_t, Lock& l);
+ void errorCheck(const MemberId&, uint8_t type, SequenceNumber frameSeq, Lock&);
+
+ void shutdown(const MemberId&, const framing::Uuid& shutdownId, Lock&);
+
+ // Helper functions
+ ConnectionPtr getConnection(const EventFrame&, Lock&);
+ ConnectionVector getConnections(Lock&);
+ void updateStart(const MemberId& updatee, const Url& url, Lock&);
+ void makeOffer(const MemberId&, Lock&);
+ void setReady(Lock&);
+ void memberUpdate(Lock&);
+ void setClusterId(const framing::Uuid&, Lock&);
+ void erase(const ConnectionId&, Lock&);
+
+ void initMapCompleted(Lock&);
+
+
+
+ // == Called in CPG dispatch thread
+ void deliver( // CPG deliver callback.
cpg_handle_t /*handle*/,
- struct cpg_name *group,
+ const struct cpg_name *group,
uint32_t /*nodeid*/,
uint32_t /*pid*/,
void* /*msg*/,
int /*msg_len*/);
- /** CPG config change callback */
- void configChange(
+ void deliverEvent(const Event&);
+
+ void configChange( // CPG config change callback.
cpg_handle_t /*handle*/,
- struct cpg_name */*group*/,
- struct cpg_address */*members*/, int /*nMembers*/,
- struct cpg_address */*left*/, int /*nLeft*/,
- struct cpg_address */*joined*/, int /*nJoined*/
+ const struct cpg_name */*group*/,
+ const struct cpg_address */*members*/, int /*nMembers*/,
+ const struct cpg_address */*left*/, int /*nLeft*/,
+ const struct cpg_address */*joined*/, int /*nJoined*/
);
- /** Callback to handle delivered frames from the deliverQueue. */
- void deliverQueueCb(const MessageQueue::iterator& begin,
- const MessageQueue::iterator& end);
-
- /** Callback to multi-cast frames from mcastQueue */
- void mcastQueueCb(const MessageQueue::iterator& begin,
- const MessageQueue::iterator& end);
+ // == Called in management threads.
+ virtual qpid::management::ManagementObject* GetManagementObject() const;
+ virtual management::Manageable::status_t ManagementMethod (uint32_t methodId, management::Args& args, std::string& text);
+ void stopClusterNode(Lock&);
+ void stopFullCluster(Lock&);
- /** Callback to dispatch CPG events. */
- void dispatch(sys::DispatchHandle&);
- /** Callback if CPG fd is disconnected. */
- void disconnect(sys::DispatchHandle&);
+ // == Called in connection IO threads .
+ void checkUpdateIn(Lock&);
- void handleMethod(Id from, ConnectionInterceptor* connection, framing::AMQMethodBody& method);
+ // == Called in UpdateClient thread.
+ void updateOutDone();
+ void updateOutError(const std::exception&);
+ void updateOutDone(Lock&);
- ConnectionInterceptor* getShadowConnection(const Cpg::Id&, void*);
-
- mutable sys::Monitor lock; // Protect access to members.
- broker::Broker* broker;
+ // Immutable members set on construction, never changed.
+ const ClusterSettings settings;
+ broker::Broker& broker;
+ qmf::org::apache::qpid::cluster::Cluster* mgmtObject; // mgnt owns lifecycle
boost::shared_ptr<sys::Poller> poller;
Cpg cpg;
- Cpg::Name name;
- Url url;
- MemberMap members;
- Id self;
- ShadowConnectionMap shadowConnectionMap;
- LocalConnectionSet localConnectionSet;
- ShadowConnectionOutputHandler shadowOut;
- sys::DispatchHandle cpgDispatchHandle;
- MessageQueue deliverQueue;
- MessageQueue mcastQueue;
-
- friend std::ostream& operator <<(std::ostream&, const Cluster&);
- friend std::ostream& operator <<(std::ostream&, const MemberMap::value_type&);
- friend std::ostream& operator <<(std::ostream&, const MemberMap&);
+ const std::string name;
+ Url myUrl;
+ const MemberId self;
+ framing::Uuid clusterId;
+ NoOpConnectionOutputHandler shadowOut;
+ qpid::management::ManagementAgent* mAgent;
+ boost::intrusive_ptr<ExpiryPolicy> expiryPolicy;
+
+ // Thread safe members
+ Multicaster mcast;
+ PollerDispatch dispatcher;
+ PollableEventQueue deliverEventQueue;
+ PollableFrameQueue deliverFrameQueue;
+ boost::shared_ptr<FailoverExchange> failoverExchange;
+ Quorum quorum;
+ LockedConnectionMap localConnections;
+
+ // Used only in deliverEventQueue thread or when stalled for update.
+ Decoder decoder;
+ bool discarding;
+
+
+ // Remaining members are protected by lock.
+
+ // TODO aconway 2009-03-06: Most of these members are also only used in
+ // deliverFrameQueue thread or during stall. Review and separate members
+ // that require a lock, drop lock when not needed.
+
+ mutable sys::Monitor lock;
+
+
+ // Local cluster state, cluster map
+ enum {
+ INIT, ///< Establishing inital cluster stattus.
+ JOINER, ///< Sent update request, waiting for update offer.
+ UPDATEE, ///< Stalled receive queue at update offer, waiting for update to complete.
+ CATCHUP, ///< Update complete, unstalled but has not yet seen own "ready" event.
+ READY, ///< Fully operational
+ OFFER, ///< Sent an offer, waiting for accept/reject.
+ UPDATER, ///< Offer accepted, sending a state update.
+ LEFT ///< Final state, left the cluster.
+ } state;
+
+ ConnectionMap connections;
+ InitialStatusMap initMap;
+ StoreStatus store;
+ ClusterMap map;
+ MemberSet elders;
+ size_t lastSize;
+ bool lastBroker;
+ sys::Thread updateThread;
+ boost::optional<ClusterMap> updatedMap;
+ bool updateRetracted;
+ ErrorCheck error;
+ UpdateReceiver updateReceiver;
+
+ friend std::ostream& operator<<(std::ostream&, const Cluster&);
+ friend class ClusterDispatcher;
};
}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/ClusterMap.cpp b/cpp/src/qpid/cluster/ClusterMap.cpp
new file mode 100644
index 0000000000..8cac470ef3
--- /dev/null
+++ b/cpp/src/qpid/cluster/ClusterMap.cpp
@@ -0,0 +1,175 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/cluster/ClusterMap.h"
+#include "qpid/Url.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/log/Statement.h"
+#include <boost/bind.hpp>
+#include <algorithm>
+#include <functional>
+#include <iterator>
+#include <ostream>
+
+using namespace std;
+using namespace boost;
+
+namespace qpid {
+using namespace framing;
+
+namespace cluster {
+
+namespace {
+
+void addFieldTableValue(FieldTable::ValueMap::value_type vt, ClusterMap::Map& map, ClusterMap::Set& set) {
+ MemberId id(vt.first);
+ set.insert(id);
+ string url = vt.second->get<string>();
+ if (!url.empty())
+ map.insert(ClusterMap::Map::value_type(id, Url(url)));
+}
+
+void insertFieldTableFromMapValue(FieldTable& ft, const ClusterMap::Map::value_type& vt) {
+ ft.setString(vt.first.str(), vt.second.str());
+}
+
+void assignFieldTable(FieldTable& ft, const ClusterMap::Map& map) {
+ ft.clear();
+ for_each(map.begin(), map.end(), bind(&insertFieldTableFromMapValue, ref(ft), _1));
+}
+
+}
+
+ClusterMap::ClusterMap() : frameSeq(0) {}
+
+ClusterMap::ClusterMap(const Map& map) : frameSeq(0) {
+ transform(map.begin(), map.end(), inserter(alive, alive.begin()), bind(&Map::value_type::first, _1));
+ members = map;
+}
+
+ClusterMap::ClusterMap(const FieldTable& joinersFt, const FieldTable& membersFt, framing::SequenceNumber frameSeq_)
+ : frameSeq(frameSeq_)
+{
+ for_each(joinersFt.begin(), joinersFt.end(), bind(&addFieldTableValue, _1, ref(joiners), ref(alive)));
+ for_each(membersFt.begin(), membersFt.end(), bind(&addFieldTableValue, _1, ref(members), ref(alive)));
+}
+
+void ClusterMap::toMethodBody(framing::ClusterConnectionMembershipBody& b) const {
+ b.getJoiners().clear();
+ for_each(joiners.begin(), joiners.end(), bind(&insertFieldTableFromMapValue, ref(b.getJoiners()), _1));
+ for(Set::const_iterator i = alive.begin(); i != alive.end(); ++i) {
+ if (!isMember(*i) && !isJoiner(*i))
+ b.getJoiners().setString(i->str(), string());
+ }
+ b.getMembers().clear();
+ for_each(members.begin(), members.end(), bind(&insertFieldTableFromMapValue, ref(b.getMembers()), _1));
+ b.setFrameSeq(frameSeq);
+}
+
+Url ClusterMap::getUrl(const Map& map, const MemberId& id) {
+ Map::const_iterator i = map.find(id);
+ return i == map.end() ? Url() : i->second;
+}
+
+MemberId ClusterMap::firstJoiner() const {
+ return joiners.empty() ? MemberId() : joiners.begin()->first;
+}
+
+vector<string> ClusterMap::memberIds() const {
+ vector<string> ids;
+ for (Map::const_iterator iter = members.begin();
+ iter != members.end(); iter++) {
+ stringstream stream;
+ stream << iter->first;
+ ids.push_back(stream.str());
+ }
+ return ids;
+}
+
+vector<Url> ClusterMap::memberUrls() const {
+ vector<Url> urls(members.size());
+ transform(members.begin(), members.end(), urls.begin(),
+ bind(&Map::value_type::second, _1));
+ return urls;
+}
+
+ClusterMap::Set ClusterMap::getAlive() const { return alive; }
+
+ClusterMap::Set ClusterMap::getMembers() const {
+ Set s;
+ transform(members.begin(), members.end(), inserter(s, s.begin()),
+ bind(&Map::value_type::first, _1));
+ return s;
+}
+
+ostream& operator<<(ostream& o, const ClusterMap::Map& m) {
+ ostream_iterator<MemberId> oi(o);
+ transform(m.begin(), m.end(), oi, bind(&ClusterMap::Map::value_type::first, _1));
+ return o;
+}
+
+ostream& operator<<(ostream& o, const ClusterMap& m) {
+ for (ClusterMap::Set::const_iterator i = m.alive.begin(); i != m.alive.end(); ++i) {
+ o << *i;
+ if (m.isMember(*i)) o << "(member)";
+ else if (m.isJoiner(*i)) o << "(joiner)";
+ else o << "(unknown)";
+ o << " ";
+ }
+ return o;
+}
+
+bool ClusterMap::updateRequest(const MemberId& id, const string& url) {
+ if (isAlive(id)) {
+ joiners[id] = Url(url);
+ return true;
+ }
+ return false;
+}
+
+bool ClusterMap::ready(const MemberId& id, const Url& url) {
+ return isAlive(id) && members.insert(Map::value_type(id,url)).second;
+}
+
+bool ClusterMap::configChange(const Set& update) {
+ bool memberChange = false;
+ Set removed;
+ set_difference(alive.begin(), alive.end(),
+ update.begin(), update.end(),
+ inserter(removed, removed.begin()));
+ alive = update;
+ for (Set::const_iterator i = removed.begin(); i != removed.end(); ++i) {
+ memberChange = memberChange || members.erase(*i);
+ joiners.erase(*i);
+ }
+ return memberChange;
+}
+
+optional<Url> ClusterMap::updateOffer(const MemberId& from, const MemberId& to) {
+ Map::iterator i = joiners.find(to);
+ if (isAlive(from) && i != joiners.end()) {
+ Url url= i->second;
+ joiners.erase(i); // No longer a potential updatee.
+ return url;
+ }
+ return optional<Url>();
+}
+
+}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/ClusterMap.h b/cpp/src/qpid/cluster/ClusterMap.h
new file mode 100644
index 0000000000..98572813a8
--- /dev/null
+++ b/cpp/src/qpid/cluster/ClusterMap.h
@@ -0,0 +1,105 @@
+#ifndef QPID_CLUSTER_CLUSTERMAP_H
+#define QPID_CLUSTER_CLUSTERMAP_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "MemberSet.h"
+#include "qpid/Url.h"
+#include "qpid/framing/ClusterConnectionMembershipBody.h"
+#include "qpid/framing/SequenceNumber.h"
+
+#include <boost/function.hpp>
+#include <boost/optional.hpp>
+
+#include <vector>
+#include <deque>
+#include <map>
+#include <iosfwd>
+
+namespace qpid {
+namespace cluster {
+
+/**
+ * Map of established cluster members and joiners waiting for an update,
+ * along with other cluster state that must be updated.
+ */
+class ClusterMap {
+ public:
+ typedef std::map<MemberId, Url> Map;
+ typedef std::set<MemberId> Set;
+
+ ClusterMap();
+ ClusterMap(const Map& map);
+ ClusterMap(const framing::FieldTable& joiners, const framing::FieldTable& members, framing::SequenceNumber frameSeq);
+
+ /** Update from config change.
+ *@return true if member set changed.
+ */
+ bool configChange(const Set& members);
+
+ bool isJoiner(const MemberId& id) const { return joiners.find(id) != joiners.end(); }
+ bool isMember(const MemberId& id) const { return members.find(id) != members.end(); }
+ bool isAlive(const MemberId& id) const { return alive.find(id) != alive.end(); }
+
+ Url getJoinerUrl(const MemberId& id) { return getUrl(joiners, id); }
+ Url getMemberUrl(const MemberId& id) { return getUrl(members, id); }
+
+ /** First joiner in the cluster in ID order, target for offers */
+ MemberId firstJoiner() const;
+
+ /** Convert map contents to a cluster control body. */
+ void toMethodBody(framing::ClusterConnectionMembershipBody&) const;
+
+ size_t aliveCount() const { return alive.size(); }
+ size_t memberCount() const { return members.size(); }
+ std::vector<std::string> memberIds() const;
+ std::vector<Url> memberUrls() const;
+ Set getAlive() const;
+ Set getMembers() const;
+
+ bool updateRequest(const MemberId& id, const std::string& url);
+ /** Return non-empty Url if accepted */
+ boost::optional<Url> updateOffer(const MemberId& from, const MemberId& to);
+
+ /**@return true If this is a new member */
+ bool ready(const MemberId& id, const Url&);
+
+ framing::SequenceNumber getFrameSeq() { return frameSeq; }
+ framing::SequenceNumber incrementFrameSeq() { return ++frameSeq; }
+
+ /** Clear out all knowledge of joiners & members, just keep alive set */
+ void clearStatus() { joiners.clear(); members.clear(); }
+
+ private:
+ Url getUrl(const Map& map, const MemberId& id);
+
+ Map joiners, members;
+ Set alive;
+ framing::SequenceNumber frameSeq;
+
+ friend std::ostream& operator<<(std::ostream&, const Map&);
+ friend std::ostream& operator<<(std::ostream&, const ClusterMap&);
+};
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_CLUSTERMAP_H*/
diff --git a/cpp/src/qpid/cluster/ClusterPlugin.cpp b/cpp/src/qpid/cluster/ClusterPlugin.cpp
index 1d07660455..e4aee6730b 100644
--- a/cpp/src/qpid/cluster/ClusterPlugin.cpp
+++ b/cpp/src/qpid/cluster/ClusterPlugin.cpp
@@ -16,89 +16,157 @@
*
*/
-#include "ConnectionInterceptor.h"
+#include "config.h"
+#include "qpid/cluster/Connection.h"
+#include "qpid/cluster/ConnectionCodec.h"
+#include "qpid/cluster/ClusterSettings.h"
-#include "qpid/broker/Broker.h"
#include "qpid/cluster/Cluster.h"
+#include "qpid/cluster/ConnectionCodec.h"
+#include "qpid/cluster/UpdateClient.h"
+
+#include "qpid/broker/Broker.h"
#include "qpid/Plugin.h"
#include "qpid/Options.h"
-#include "qpid/shared_ptr.h"
-
+#include "qpid/sys/AtomicValue.h"
+#include "qpid/log/Statement.h"
+
+#include "qpid/management/ManagementAgent.h"
+#include "qpid/management/IdAllocator.h"
+#include "qpid/broker/Exchange.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/SessionState.h"
+#include "qpid/client/ConnectionSettings.h"
+
+#include <boost/shared_ptr.hpp>
#include <boost/utility/in_place_factory.hpp>
+#include <boost/scoped_ptr.hpp>
namespace qpid {
namespace cluster {
using namespace std;
+using broker::Broker;
+using management::IdAllocator;
+using management::ManagementAgent;
-struct ClusterValues {
- string name;
- string url;
-
- Url getUrl(uint16_t port) const {
- if (url.empty()) return Url::getIpAddressesUrl(port);
- return Url(url);
- }
-};
-/** Note separating options from values to work around boost version differences.
+/** Note separating options from settings to work around boost version differences.
* Old boost takes a reference to options objects, but new boost makes a copy.
* New boost allows a shared_ptr but that's not compatible with old boost.
*/
struct ClusterOptions : public Options {
- ClusterValues& values;
+ ClusterSettings& settings;
- ClusterOptions(ClusterValues& v) : Options("Cluster Options"), values(v) {
+ ClusterOptions(ClusterSettings& v) : Options("Cluster Options"), settings(v) {
addOptions()
- ("cluster-name", optValue(values.name, "NAME"), "Name of cluster to join")
- ("cluster-url", optValue(values.url,"URL"),
+ ("cluster-name", optValue(settings.name, "NAME"), "Name of cluster to join")
+ ("cluster-url", optValue(settings.url,"URL"),
"URL of this broker, advertized to the cluster.\n"
"Defaults to a URL listing all the local IP addresses\n")
+ ("cluster-username", optValue(settings.username, "USER"), "Username for connections between brokers")
+ ("cluster-password", optValue(settings.password, "PASS"), "Password for connections between brokers")
+ ("cluster-mechanism", optValue(settings.mechanism, "MECH"), "Authentication mechanism for connections between brokers")
+#if HAVE_LIBCMAN_H
+ ("cluster-cman", optValue(settings.quorum), "Integrate with Cluster Manager (CMAN) cluster.")
+#endif
+ ("cluster-size", optValue(settings.size, "N"), "Wait for N cluster members before allowing clients to connect.")
+ ("cluster-read-max", optValue(settings.readMax,"N"), "Experimental: flow-control limit reads per connection. 0=no limit.")
;
}
};
+struct UpdateClientIdAllocator : management::IdAllocator
+{
+ qpid::sys::AtomicValue<uint64_t> sequence;
+
+ UpdateClientIdAllocator() : sequence(0x4000000000000000LL) {}
+
+ uint64_t getIdFor(management::Manageable* m)
+ {
+ if (isUpdateQueue(m) || isUpdateExchange(m) || isUpdateSession(m) || isUpdateBinding(m)) {
+ return ++sequence;
+ } else {
+ return 0;
+ }
+ }
+
+ bool isUpdateQueue(management::Manageable* manageable)
+ {
+ qpid::broker::Queue* queue = dynamic_cast<qpid::broker::Queue*>(manageable);
+ return queue && queue->getName() == UpdateClient::UPDATE;
+ }
+
+ bool isUpdateExchange(management::Manageable* manageable)
+ {
+ qpid::broker::Exchange* exchange = dynamic_cast<qpid::broker::Exchange*>(manageable);
+ return exchange && exchange->getName() == UpdateClient::UPDATE;
+ }
+
+ bool isUpdateSession(management::Manageable* manageable)
+ {
+ broker::SessionState* session = dynamic_cast<broker::SessionState*>(manageable);
+ return session && session->getId().getName() == UpdateClient::UPDATE;
+ }
+
+ bool isUpdateBinding(management::Manageable* manageable)
+ {
+ broker::Exchange::Binding* binding = dynamic_cast<broker::Exchange::Binding*>(manageable);
+ return binding && binding->queue->getName() == UpdateClient::UPDATE;
+ }
+};
+
struct ClusterPlugin : public Plugin {
- ClusterValues values;
+ ClusterSettings settings;
ClusterOptions options;
- boost::intrusive_ptr<Cluster> cluster;
+ Cluster* cluster;
+ boost::scoped_ptr<ConnectionCodec::Factory> factory;
- ClusterPlugin() : options(values) {}
+ ClusterPlugin() : options(settings), cluster(0) {}
+ // Cluster needs to be initialized after the store
+ int initOrder() const { return Plugin::DEFAULT_INIT_ORDER+500; }
+
Options* getOptions() { return &options; }
- void init(broker::Broker& b) {
- if (values.name.empty()) return; // Only if --cluster-name option was specified.
- if (cluster) throw Exception("Cluster plugin cannot be initialized twice in one process.");
- cluster = new Cluster(values.name, values.getUrl(b.getPort()), b);
- b.addFinalizer(boost::bind(&ClusterPlugin::shutdown, this));
+ void earlyInitialize(Plugin::Target& target) {
+ if (settings.name.empty()) return; // Only if --cluster-name option was specified.
+ Broker* broker = dynamic_cast<Broker*>(&target);
+ if (!broker) return;
+ cluster = new Cluster(settings, *broker);
+ broker->setConnectionFactory(
+ boost::shared_ptr<sys::ConnectionCodec::Factory>(
+ new ConnectionCodec::Factory(broker->getConnectionFactory(), *cluster)));
+ ManagementAgent* mgmt = broker->getManagementAgent();
+ if (mgmt) {
+ std::auto_ptr<IdAllocator> allocator(new UpdateClientIdAllocator());
+ mgmt->setAllocator(allocator);
+ }
}
- template <class T> void init(T& t) {
- if (cluster) cluster->initialize(t);
+ void disallow(ManagementAgent* agent, const string& className, const string& methodName) {
+ string message = "Management method " + className + ":" + methodName + " is not allowed on a clustered broker.";
+ agent->disallow(className, methodName, message);
}
-
- template <class T> bool init(Plugin::Target& target) {
- T* t = dynamic_cast<T*>(&target);
- if (t) init(*t);
- return t;
+ void disallowManagementMethods(ManagementAgent* agent) {
+ if (!agent) return;
+ disallow(agent, "queue", "purge");
+ disallow(agent, "session", "detach");
+ disallow(agent, "session", "close");
+ disallow(agent, "connection", "close");
}
- void earlyInitialize(Plugin::Target&) {}
-
void initialize(Plugin::Target& target) {
- if (init<broker::Broker>(target)) return;
- if (!cluster) return; // Remaining plugins only valid if cluster initialized.
- if (init<broker::Connection>(target)) return;
+ Broker* broker = dynamic_cast<Broker*>(&target);
+ if (broker && cluster) {
+ disallowManagementMethods(broker->getManagementAgent());
+ cluster->initialize();
+ }
}
-
- void shutdown() { cluster = 0; }
};
static ClusterPlugin instance; // Static initialization.
-// For test purposes.
-boost::intrusive_ptr<Cluster> getGlobalCluster() { return instance.cluster; }
-
}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/ClusterSettings.h b/cpp/src/qpid/cluster/ClusterSettings.h
new file mode 100644
index 0000000000..d37c7792bf
--- /dev/null
+++ b/cpp/src/qpid/cluster/ClusterSettings.h
@@ -0,0 +1,50 @@
+#ifndef QPID_CLUSTER_CLUSTERSETTINGS_H
+#define QPID_CLUSTER_CLUSTERSETTINGS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/Url.h>
+#include <string>
+
+namespace qpid {
+namespace cluster {
+
+struct ClusterSettings {
+ std::string name;
+ std::string url;
+ bool quorum;
+ size_t readMax;
+ std::string username, password, mechanism;
+ size_t size;
+
+ ClusterSettings() : quorum(false), readMax(10), mechanism("ANONYMOUS"), size(1)
+ {}
+
+ Url getUrl(uint16_t port) const {
+ if (url.empty()) return Url::getIpAddressesUrl(port);
+ return Url(url);
+ }
+};
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_CLUSTERSETTINGS_H*/
diff --git a/cpp/src/qpid/cluster/Connection.cpp b/cpp/src/qpid/cluster/Connection.cpp
new file mode 100644
index 0000000000..d223244f15
--- /dev/null
+++ b/cpp/src/qpid/cluster/Connection.cpp
@@ -0,0 +1,479 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Connection.h"
+#include "UpdateClient.h"
+#include "Cluster.h"
+#include "UpdateReceiver.h"
+
+#include "qpid/broker/SessionState.h"
+#include "qpid/broker/SemanticState.h"
+#include "qpid/broker/TxBuffer.h"
+#include "qpid/broker/TxPublish.h"
+#include "qpid/broker/TxAccept.h"
+#include "qpid/broker/RecoveredEnqueue.h"
+#include "qpid/broker/RecoveredDequeue.h"
+#include "qpid/broker/Exchange.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/framing/enum.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/AllInvoker.h"
+#include "qpid/framing/DeliveryProperties.h"
+#include "qpid/framing/ClusterConnectionDeliverCloseBody.h"
+#include "qpid/framing/ConnectionCloseBody.h"
+#include "qpid/framing/ConnectionCloseOkBody.h"
+#include "qpid/log/Statement.h"
+
+#include <boost/current_function.hpp>
+
+// TODO aconway 2008-11-03:
+//
+// Refactor code for receiving an update into a separate UpdateConnection
+// class.
+//
+
+
+namespace qpid {
+namespace cluster {
+
+using namespace framing;
+using namespace framing::cluster;
+
+qpid::sys::AtomicValue<uint64_t> Connection::catchUpId(0x5000000000000000LL);
+
+Connection::NullFrameHandler Connection::nullFrameHandler;
+
+struct NullFrameHandler : public framing::FrameHandler {
+ void handle(framing::AMQFrame&) {}
+};
+
+
+namespace {
+sys::AtomicValue<uint64_t> idCounter;
+const std::string shadowPrefix("[shadow]");
+}
+
+
+// Shadow connection
+ Connection::Connection(Cluster& c, sys::ConnectionOutputHandler& out, const std::string& logId,
+ const ConnectionId& id, unsigned int ssf)
+ : cluster(c), self(id), catchUp(false), output(*this, out),
+ connection(&output, cluster.getBroker(), shadowPrefix+logId, ssf), expectProtocolHeader(false),
+ mcastFrameHandler(cluster.getMulticast(), self),
+ consumerNumbering(c.getUpdateReceiver().consumerNumbering)
+{ init(); }
+
+// Local connection
+Connection::Connection(Cluster& c, sys::ConnectionOutputHandler& out,
+ const std::string& logId, MemberId member,
+ bool isCatchUp, bool isLink, unsigned int ssf
+) : cluster(c), self(member, ++idCounter), catchUp(isCatchUp), output(*this, out),
+ connection(&output, cluster.getBroker(),
+ isCatchUp ? shadowPrefix+logId : logId,
+ ssf,
+ isLink,
+ isCatchUp ? ++catchUpId : 0),
+ expectProtocolHeader(isLink), mcastFrameHandler(cluster.getMulticast(), self),
+ consumerNumbering(c.getUpdateReceiver().consumerNumbering)
+{ init(); }
+
+void Connection::init() {
+ QPID_LOG(debug, cluster << " new connection: " << *this);
+ if (isLocalClient()) {
+ connection.setClusterOrderOutput(mcastFrameHandler); // Actively send cluster-order frames from local node
+ cluster.addLocalConnection(this);
+ giveReadCredit(cluster.getSettings().readMax);
+ }
+ else { // Shadow or catch-up connection
+ connection.setClusterOrderOutput(nullFrameHandler); // Passive, discard cluster-order frames
+ connection.setClientThrottling(false); // Disable client throttling, done by active node.
+ connection.setShadow(); // Mark the broker connection as a shadow.
+ }
+ if (!isCatchUp())
+ connection.setErrorListener(this);
+}
+
+void Connection::giveReadCredit(int credit) {
+ if (cluster.getSettings().readMax && credit)
+ output.giveReadCredit(credit);
+}
+
+Connection::~Connection() {
+ connection.setErrorListener(0);
+ QPID_LOG(debug, cluster << " deleted connection: " << *this);
+}
+
+bool Connection::doOutput() {
+ return output.doOutput();
+}
+
+// Received from a directly connected client.
+void Connection::received(framing::AMQFrame& f) {
+ QPID_LOG(trace, cluster << " RECV " << *this << ": " << f);
+ if (isLocal()) { // Local catch-up connection.
+ currentChannel = f.getChannel();
+ if (!framing::invoke(*this, *f.getBody()).wasHandled())
+ connection.received(f);
+ }
+ else { // Shadow or updated catch-up connection.
+ if (f.getMethod() && f.getMethod()->isA<ConnectionCloseBody>()) {
+ if (isShadow())
+ cluster.addShadowConnection(this);
+ AMQFrame ok((ConnectionCloseOkBody()));
+ connection.getOutput().send(ok);
+ output.closeOutput();
+ catchUp = false;
+ }
+ else
+ QPID_LOG(warning, cluster << " ignoring unexpected frame " << *this << ": " << f);
+ }
+}
+
+bool Connection::checkUnsupported(const AMQBody& body) {
+ std::string message;
+ if (body.getMethod()) {
+ switch (body.getMethod()->amqpClassId()) {
+ case DTX_CLASS_ID: message = "DTX transactions are not currently supported by cluster."; break;
+ }
+ }
+ if (!message.empty())
+ connection.close(connection::CLOSE_CODE_FRAMING_ERROR, message);
+ return !message.empty();
+}
+
+struct GiveReadCreditOnExit {
+ Connection& connection;
+ int credit;
+ GiveReadCreditOnExit(Connection& connection_, int credit_) :
+ connection(connection_), credit(credit_) {}
+ ~GiveReadCreditOnExit() { connection.giveReadCredit(credit); }
+};
+
+// Called in delivery thread, in cluster order.
+void Connection::deliveredFrame(const EventFrame& f) {
+ GiveReadCreditOnExit gc(*this, f.readCredit);
+ assert(!catchUp);
+ currentChannel = f.frame.getChannel();
+ if (f.frame.getBody() // frame can be emtpy with just readCredit
+ && !framing::invoke(*this, *f.frame.getBody()).wasHandled() // Connection contol.
+ && !checkUnsupported(*f.frame.getBody())) // Unsupported operation.
+ {
+ if (f.type == DATA) // incoming data frames to broker::Connection
+ connection.received(const_cast<AMQFrame&>(f.frame));
+ else { // frame control, send frame via SessionState
+ broker::SessionState* ss = connection.getChannel(currentChannel).getSession();
+ if (ss) ss->out(const_cast<AMQFrame&>(f.frame));
+ }
+ }
+}
+
+// A local connection is closed by the network layer.
+void Connection::closed() {
+ try {
+ if (catchUp) {
+ QPID_LOG(critical, cluster << " catch-up connection closed prematurely " << *this);
+ cluster.leave();
+ }
+ else if (isUpdated()) {
+ QPID_LOG(debug, cluster << " closed update connection " << *this);
+ connection.closed();
+ }
+ else if (isLocal()) {
+ QPID_LOG(debug, cluster << " local close of replicated connection " << *this);
+ // This was a local replicated connection. Multicast a deliver
+ // closed and process any outstanding frames from the cluster
+ // until self-delivery of deliver-close.
+ output.closeOutput();
+ cluster.getMulticast().mcastControl(ClusterConnectionDeliverCloseBody(), self);
+ }
+ }
+ catch (const std::exception& e) {
+ QPID_LOG(error, cluster << " error closing connection " << *this << ": " << e.what());
+ }
+}
+
+// Self-delivery of close message, close the connection.
+void Connection::deliverClose () {
+ assert(!catchUp);
+ connection.closed();
+ cluster.erase(self);
+}
+
+// The connection has been killed for misbehaving
+void Connection::abort() {
+ connection.abort();
+ cluster.erase(self);
+}
+
+// Member of a shadow connection left the cluster.
+void Connection::left() {
+ assert(isShadow());
+ connection.closed();
+}
+
+// ConnectoinCodec::decode receives read buffers from directly-connected clients.
+size_t Connection::decode(const char* buffer, size_t size) {
+ if (catchUp) { // Handle catch-up locally.
+ Buffer buf(const_cast<char*>(buffer), size);
+ while (localDecoder.decode(buf))
+ received(localDecoder.getFrame());
+ }
+ else { // Multicast local connections.
+ assert(isLocal());
+ const char* remainingData = buffer;
+ size_t remainingSize = size;
+ if (expectProtocolHeader) {
+ //If this is an outgoing link, we will receive a protocol
+ //header which needs to be decoded first
+ framing::ProtocolInitiation pi;
+ Buffer buf(const_cast<char*>(buffer), size);
+ if (pi.decode(buf)) {
+ //TODO: check the version is correct
+ QPID_LOG(debug, "Outgoing clustered link connection received INIT(" << pi << ")");
+ expectProtocolHeader = false;
+ remainingData = buffer + pi.encodedSize();
+ remainingSize = size - pi.encodedSize();
+ } else {
+ QPID_LOG(debug, "Not enough data for protocol header on outgoing clustered link");
+ giveReadCredit(1); // We're not going to mcast so give read credit now.
+ return 0;
+ }
+ }
+ cluster.getMulticast().mcastBuffer(remainingData, remainingSize, self);
+ }
+ return size;
+}
+
+broker::SessionState& Connection::sessionState() {
+ return *connection.getChannel(currentChannel).getSession();
+}
+
+broker::SemanticState& Connection::semanticState() {
+ return sessionState().getSemanticState();
+}
+
+void Connection::consumerState(const string& name, bool blocked, bool notifyEnabled, const SequenceNumber& position)
+{
+ broker::SemanticState::ConsumerImpl& c = semanticState().find(name);
+ c.position = position;
+ c.setBlocked(blocked);
+ if (notifyEnabled) c.enableNotify(); else c.disableNotify();
+ consumerNumbering.add(c.shared_from_this());
+}
+
+
+void Connection::sessionState(
+ const SequenceNumber& replayStart,
+ const SequenceNumber& sendCommandPoint,
+ const SequenceSet& sentIncomplete,
+ const SequenceNumber& expected,
+ const SequenceNumber& received,
+ const SequenceSet& unknownCompleted,
+ const SequenceSet& receivedIncomplete)
+{
+
+ sessionState().setState(
+ replayStart,
+ sendCommandPoint,
+ sentIncomplete,
+ expected,
+ received,
+ unknownCompleted,
+ receivedIncomplete);
+ QPID_LOG(debug, cluster << " received session state update for " << sessionState().getId());
+ // The output tasks will be added later in the update process.
+ connection.getOutputTasks().removeAll();
+}
+
+void Connection::outputTask(uint16_t channel, const std::string& name) {
+ broker::SessionState* session = connection.getChannel(channel).getSession();
+ if (!session)
+ throw Exception(QPID_MSG(cluster << " channel not attached " << *this
+ << "[" << channel << "] "));
+ OutputTask* task = &session->getSemanticState().find(name);
+ connection.getOutputTasks().addOutputTask(task);
+}
+
+void Connection::shadowReady(uint64_t memberId, uint64_t connectionId, const string& username, const string& fragment, uint32_t sendMax) {
+ ConnectionId shadowId = ConnectionId(memberId, connectionId);
+ QPID_LOG(debug, cluster << " catch-up connection " << *this << " becomes shadow " << shadowId);
+ self = shadowId;
+ connection.setUserId(username);
+ // OK to use decoder here because cluster is stalled for update.
+ cluster.getDecoder().get(self).setFragment(fragment.data(), fragment.size());
+ connection.setErrorListener(this);
+ output.setSendMax(sendMax);
+}
+
+void Connection::membership(const FieldTable& joiners, const FieldTable& members, const framing::SequenceNumber& frameSeq) {
+ QPID_LOG(debug, cluster << " incoming update complete on connection " << *this);
+ cluster.updateInDone(ClusterMap(joiners, members, frameSeq));
+ consumerNumbering.clear();
+ self.second = 0; // Mark this as completed update connection.
+}
+
+void Connection::retractOffer() {
+ QPID_LOG(debug, cluster << " incoming update retracted on connection " << *this);
+ cluster.updateInRetracted();
+ self.second = 0; // Mark this as completed update connection.
+}
+
+bool Connection::isLocal() const {
+ return self.first == cluster.getId() && self.second;
+}
+
+bool Connection::isShadow() const {
+ return self.first != cluster.getId();
+}
+
+bool Connection::isUpdated() const {
+ return self.first == cluster.getId() && self.second == 0;
+}
+
+
+boost::shared_ptr<broker::Queue> Connection::findQueue(const std::string& qname) {
+ boost::shared_ptr<broker::Queue> queue = cluster.getBroker().getQueues().find(qname);
+ if (!queue) throw Exception(QPID_MSG(cluster << " can't find queue " << qname));
+ return queue;
+}
+
+broker::QueuedMessage Connection::getUpdateMessage() {
+ boost::shared_ptr<broker::Queue> updateq = findQueue(UpdateClient::UPDATE);
+ assert(!updateq->isDurable());
+ broker::QueuedMessage m = updateq->get();
+ if (!m.payload) throw Exception(QPID_MSG(cluster << " empty update queue"));
+ return m;
+}
+
+void Connection::deliveryRecord(const string& qname,
+ const SequenceNumber& position,
+ const string& tag,
+ const SequenceNumber& id,
+ bool acquired,
+ bool accepted,
+ bool cancelled,
+ bool completed,
+ bool ended,
+ bool windowing,
+ bool enqueued,
+ uint32_t credit)
+{
+ broker::QueuedMessage m;
+ broker::Queue::shared_ptr queue = findQueue(qname);
+ if (!ended) { // Has a message
+ if (acquired) { // Message is on the update queue
+ m = getUpdateMessage();
+ m.queue = queue.get();
+ m.position = position;
+ if (enqueued) queue->enqueued(m); //inform queue of the message
+ } else { // Message at original position in original queue
+ m = queue->find(position);
+ }
+ if (!m.payload)
+ throw Exception(QPID_MSG("deliveryRecord no update message"));
+ }
+
+ broker::DeliveryRecord dr(m, queue, tag, acquired, accepted, windowing, credit);
+ dr.setId(id);
+ if (cancelled) dr.cancel(dr.getTag());
+ if (completed) dr.complete();
+ if (ended) dr.setEnded(); // Exsitance of message
+ semanticState().record(dr); // Part of the session's unacked list.
+}
+
+void Connection::queuePosition(const string& qname, const SequenceNumber& position) {
+ findQueue(qname)->setPosition(position);
+}
+
+void Connection::expiryId(uint64_t id) {
+ cluster.getExpiryPolicy().setId(id);
+}
+
+std::ostream& operator<<(std::ostream& o, const Connection& c) {
+ const char* type="unknown";
+ if (c.isLocal()) type = "local";
+ else if (c.isShadow()) type = "shadow";
+ else if (c.isUpdated()) type = "updated";
+ return o << c.getId() << "(" << type << (c.isCatchUp() ? ",catchup" : "") << ")";
+}
+
+void Connection::txStart() {
+ txBuffer.reset(new broker::TxBuffer());
+}
+void Connection::txAccept(const framing::SequenceSet& acked) {
+ txBuffer->enlist(boost::shared_ptr<broker::TxAccept>(
+ new broker::TxAccept(acked, semanticState().getUnacked())));
+}
+
+void Connection::txDequeue(const std::string& queue) {
+ txBuffer->enlist(boost::shared_ptr<broker::RecoveredDequeue>(
+ new broker::RecoveredDequeue(findQueue(queue), getUpdateMessage().payload)));
+}
+
+void Connection::txEnqueue(const std::string& queue) {
+ txBuffer->enlist(boost::shared_ptr<broker::RecoveredEnqueue>(
+ new broker::RecoveredEnqueue(findQueue(queue), getUpdateMessage().payload)));
+}
+
+void Connection::txPublish(const framing::Array& queues, bool delivered) {
+ boost::shared_ptr<broker::TxPublish> txPub(new broker::TxPublish(getUpdateMessage().payload));
+ for (framing::Array::const_iterator i = queues.begin(); i != queues.end(); ++i)
+ txPub->deliverTo(findQueue((*i)->get<std::string>()));
+ txPub->delivered = delivered;
+ txBuffer->enlist(txPub);
+}
+
+void Connection::txEnd() {
+ semanticState().setTxBuffer(txBuffer);
+}
+
+void Connection::accumulatedAck(const qpid::framing::SequenceSet& s) {
+ semanticState().setAccumulatedAck(s);
+}
+
+void Connection::exchange(const std::string& encoded) {
+ Buffer buf(const_cast<char*>(encoded.data()), encoded.size());
+ broker::Exchange::shared_ptr ex = broker::Exchange::decode(cluster.getBroker().getExchanges(), buf);
+ QPID_LOG(debug, cluster << " updated exchange " << ex->getName());
+}
+
+void Connection::queue(const std::string& encoded) {
+ Buffer buf(const_cast<char*>(encoded.data()), encoded.size());
+ broker::Queue::shared_ptr q = broker::Queue::decode(cluster.getBroker().getQueues(), buf);
+ QPID_LOG(debug, cluster << " updated queue " << q->getName());
+}
+
+void Connection::sessionError(uint16_t , const std::string& msg) {
+ cluster.flagError(*this, ERROR_TYPE_SESSION, msg);
+
+}
+
+void Connection::connectionError(const std::string& msg) {
+ cluster.flagError(*this, ERROR_TYPE_CONNECTION, msg);
+}
+
+void Connection::addQueueListener(const std::string& q, uint32_t listener) {
+ if (listener >= consumerNumbering.size())
+ throw Exception(QPID_MSG("Invalid listener ID: " << listener));
+ findQueue(q)->getListeners().addListener(consumerNumbering[listener]);
+}
+
+}} // Namespace qpid::cluster
+
diff --git a/cpp/src/qpid/cluster/Connection.h b/cpp/src/qpid/cluster/Connection.h
new file mode 100644
index 0000000000..7f94338348
--- /dev/null
+++ b/cpp/src/qpid/cluster/Connection.h
@@ -0,0 +1,210 @@
+#ifndef QPID_CLUSTER_CONNECTION_H
+#define QPID_CLUSTER_CONNECTION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "types.h"
+#include "OutputInterceptor.h"
+#include "EventFrame.h"
+#include "McastFrameHandler.h"
+#include "UpdateReceiver.h"
+
+#include "qpid/broker/Connection.h"
+#include "qpid/broker/SemanticState.h"
+#include "qpid/amqp_0_10/Connection.h"
+#include "qpid/sys/AtomicValue.h"
+#include "qpid/sys/ConnectionInputHandler.h"
+#include "qpid/sys/ConnectionOutputHandler.h"
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/framing/FrameDecoder.h"
+
+#include <iosfwd>
+
+namespace qpid {
+
+namespace framing { class AMQFrame; }
+
+namespace broker {
+class SemanticState;
+class QueuedMessage;
+class TxBuffer;
+class TxAccept;
+}
+
+namespace cluster {
+class Cluster;
+class Event;
+
+/** Intercept broker::Connection calls for shadow and local cluster connections. */
+class Connection :
+ public RefCounted,
+ public sys::ConnectionInputHandler,
+ public framing::AMQP_AllOperations::ClusterConnectionHandler,
+ private broker::Connection::ErrorListener
+
+{
+ public:
+
+ /** Local connection. */
+ Connection(Cluster&, sys::ConnectionOutputHandler& out, const std::string& logId, MemberId, bool catchUp, bool isLink,
+ unsigned int ssf);
+ /** Shadow connection. */
+ Connection(Cluster&, sys::ConnectionOutputHandler& out, const std::string& logId, const ConnectionId& id,
+ unsigned int ssf);
+ ~Connection();
+
+ ConnectionId getId() const { return self; }
+ broker::Connection& getBrokerConnection() { return connection; }
+
+ /** Local connections may be clients or catch-up connections */
+ bool isLocal() const;
+
+ bool isLocalClient() const { return isLocal() && !isCatchUp(); }
+
+ /** True for connections that are shadowing remote broker connections */
+ bool isShadow() const;
+
+ /** True if the connection is in "catch-up" mode: building initial broker state. */
+ bool isCatchUp() const { return catchUp; }
+
+ /** True if the connection is a completed shared update connection */
+ bool isUpdated() const;
+
+ Cluster& getCluster() { return cluster; }
+
+ // ConnectionInputHandler methods
+ void received(framing::AMQFrame&);
+ void closed();
+ bool doOutput();
+ bool hasOutput() { return connection.hasOutput(); }
+ void idleOut() { connection.idleOut(); }
+ void idleIn() { connection.idleIn(); }
+
+ /** Called if the connectors member has left the cluster */
+ void left();
+
+ // ConnectionCodec methods - called by IO layer with a read buffer.
+ size_t decode(const char* buffer, size_t size);
+
+ // Called for data delivered from the cluster.
+ void deliveredFrame(const EventFrame&);
+
+ void consumerState(const std::string& name, bool blocked, bool notifyEnabled, const qpid::framing::SequenceNumber& position);
+
+ // ==== Used in catch-up mode to build initial state.
+ //
+ // State update methods.
+ void sessionState(const framing::SequenceNumber& replayStart,
+ const framing::SequenceNumber& sendCommandPoint,
+ const framing::SequenceSet& sentIncomplete,
+ const framing::SequenceNumber& expected,
+ const framing::SequenceNumber& received,
+ const framing::SequenceSet& unknownCompleted,
+ const SequenceSet& receivedIncomplete);
+
+ void outputTask(uint16_t channel, const std::string& name);
+
+ void shadowReady(uint64_t memberId, uint64_t connectionId, const std::string& username, const std::string& fragment, uint32_t sendMax);
+
+ void membership(const framing::FieldTable&, const framing::FieldTable&, const framing::SequenceNumber& frameSeq);
+
+ void retractOffer();
+
+ void deliveryRecord(const std::string& queue,
+ const framing::SequenceNumber& position,
+ const std::string& tag,
+ const framing::SequenceNumber& id,
+ bool acquired,
+ bool accepted,
+ bool cancelled,
+ bool completed,
+ bool ended,
+ bool windowing,
+ bool enqueued,
+ uint32_t credit);
+
+ void queuePosition(const std::string&, const framing::SequenceNumber&);
+ void expiryId(uint64_t);
+
+ void txStart();
+ void txAccept(const framing::SequenceSet&);
+ void txDequeue(const std::string&);
+ void txEnqueue(const std::string&);
+ void txPublish(const framing::Array&, bool);
+ void txEnd();
+ void accumulatedAck(const framing::SequenceSet&);
+
+ // Encoded queue/exchange replication.
+ void queue(const std::string& encoded);
+ void exchange(const std::string& encoded);
+
+ void giveReadCredit(int credit);
+ void announce(uint32_t) {} // handled by Cluster.
+ void abort();
+ void deliverClose();
+
+ OutputInterceptor& getOutput() { return output; }
+
+ void addQueueListener(const std::string& queue, uint32_t listener);
+
+ private:
+ struct NullFrameHandler : public framing::FrameHandler {
+ void handle(framing::AMQFrame&) {}
+ };
+
+
+ static NullFrameHandler nullFrameHandler;
+
+ // Error listener functions
+ void connectionError(const std::string&);
+ void sessionError(uint16_t channel, const std::string&);
+
+ void init();
+ bool checkUnsupported(const framing::AMQBody& body);
+ void deliverDoOutput(uint32_t limit) { output.deliverDoOutput(limit); }
+
+ boost::shared_ptr<broker::Queue> findQueue(const std::string& qname);
+ broker::SessionState& sessionState();
+ broker::SemanticState& semanticState();
+ broker::QueuedMessage getUpdateMessage();
+
+ Cluster& cluster;
+ ConnectionId self;
+ bool catchUp;
+ OutputInterceptor output;
+ framing::FrameDecoder localDecoder;
+ broker::Connection connection;
+ framing::SequenceNumber deliverSeq;
+ framing::ChannelId currentChannel;
+ boost::shared_ptr<broker::TxBuffer> txBuffer;
+ bool expectProtocolHeader;
+ McastFrameHandler mcastFrameHandler;
+ UpdateReceiver::ConsumerNumbering& consumerNumbering;
+
+ static qpid::sys::AtomicValue<uint64_t> catchUpId;
+
+ friend std::ostream& operator<<(std::ostream&, const Connection&);
+};
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_CONNECTION_H*/
diff --git a/cpp/src/qpid/cluster/ConnectionCodec.cpp b/cpp/src/qpid/cluster/ConnectionCodec.cpp
new file mode 100644
index 0000000000..8f6f1d9ad5
--- /dev/null
+++ b/cpp/src/qpid/cluster/ConnectionCodec.cpp
@@ -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.
+ *
+ */
+#include "qpid/cluster/ConnectionCodec.h"
+#include "qpid/cluster/Connection.h"
+#include "qpid/cluster/Cluster.h"
+#include "qpid/cluster/ProxyInputHandler.h"
+#include "qpid/broker/Connection.h"
+#include "qpid/framing/ConnectionCloseBody.h"
+#include "qpid/framing/ConnectionCloseOkBody.h"
+#include "qpid/log/Statement.h"
+#include "qpid/memory.h"
+#include <stdexcept>
+#include <boost/utility/in_place_factory.hpp>
+
+namespace qpid {
+namespace cluster {
+
+using namespace framing;
+
+sys::ConnectionCodec*
+ConnectionCodec::Factory::create(ProtocolVersion v, sys::OutputControl& out, const std::string& id,
+ unsigned int ssf) {
+ if (v == ProtocolVersion(0, 10))
+ return new ConnectionCodec(v, out, id, cluster, false, false, ssf);
+ else if (v == ProtocolVersion(0x80 + 0, 0x80 + 10)) // Catch-up connection
+ return new ConnectionCodec(v, out, id, cluster, true, false, ssf);
+ return 0;
+}
+
+// Used for outgoing Link connections
+sys::ConnectionCodec*
+ConnectionCodec::Factory::create(sys::OutputControl& out, const std::string& logId,
+ unsigned int ssf) {
+ return new ConnectionCodec(ProtocolVersion(0,10), out, logId, cluster, false, true, ssf);
+}
+
+ConnectionCodec::ConnectionCodec(
+ const ProtocolVersion& v, sys::OutputControl& out,
+ const std::string& logId, Cluster& cluster, bool catchUp, bool isLink, unsigned int ssf
+) : codec(out, logId, isLink),
+ interceptor(new Connection(cluster, codec, logId, cluster.getId(), catchUp, isLink, ssf))
+{
+ std::auto_ptr<sys::ConnectionInputHandler> ih(new ProxyInputHandler(interceptor));
+ codec.setInputHandler(ih);
+ codec.setVersion(v);
+}
+
+ConnectionCodec::~ConnectionCodec() {}
+
+size_t ConnectionCodec::decode(const char* buffer, size_t size) {
+ return interceptor->decode(buffer, size);
+}
+
+bool ConnectionCodec::isClosed() const { return codec.isClosed(); }
+
+size_t ConnectionCodec::encode(const char* buffer, size_t size) { return codec.encode(buffer, size); }
+
+bool ConnectionCodec::canEncode() { return codec.canEncode(); }
+
+void ConnectionCodec::closed() { codec.closed(); }
+
+ProtocolVersion ConnectionCodec::getVersion() const { return codec.getVersion(); }
+
+}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/ConnectionCodec.h b/cpp/src/qpid/cluster/ConnectionCodec.h
new file mode 100644
index 0000000000..74cb3c507d
--- /dev/null
+++ b/cpp/src/qpid/cluster/ConnectionCodec.h
@@ -0,0 +1,82 @@
+#ifndef QPID_CLUSTER_CONNCTIONCODEC_H
+#define QPID_CLUSTER_CONNCTIONCODEC_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/amqp_0_10/Connection.h"
+#include "qpid/cluster/Connection.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+
+namespace broker {
+class Connection;
+}
+
+namespace cluster {
+class Cluster;
+
+/**
+ * Encapsulates the standard amqp_0_10::ConnectionCodec and sets up
+ * a cluster::Connection for the connection.
+ *
+ * The ConnectionCodec is deleted by the network layer when the
+ * connection closes. The cluster::Connection needs to be kept
+ * around until all cluster business on the connection is complete.
+ *
+ */
+class ConnectionCodec : public sys::ConnectionCodec {
+ public:
+ struct Factory : public sys::ConnectionCodec::Factory {
+ boost::shared_ptr<sys::ConnectionCodec::Factory> next;
+ Cluster& cluster;
+ Factory(boost::shared_ptr<sys::ConnectionCodec::Factory> f, Cluster& c)
+ : next(f), cluster(c) {}
+ sys::ConnectionCodec* create(framing::ProtocolVersion, sys::OutputControl&, const std::string& id,
+ unsigned int conn_ssf);
+ sys::ConnectionCodec* create(sys::OutputControl&, const std::string& id,
+ unsigned int conn_ssf);
+ };
+
+ ConnectionCodec(const framing::ProtocolVersion&, sys::OutputControl& out,
+ const std::string& logId, Cluster& c, bool catchUp, bool isLink,
+ unsigned int ssf);
+ ~ConnectionCodec();
+
+ // ConnectionCodec functions.
+ size_t decode(const char* buffer, size_t size);
+ size_t encode(const char* buffer, size_t size);
+ bool canEncode();
+ void closed();
+ bool isClosed() const;
+ framing::ProtocolVersion getVersion() const;
+
+
+ private:
+ amqp_0_10::Connection codec;
+ boost::intrusive_ptr<cluster::Connection> interceptor;
+};
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_CONNCTIONCODEC_H*/
diff --git a/cpp/src/qpid/cluster/ConnectionInterceptor.cpp b/cpp/src/qpid/cluster/ConnectionInterceptor.cpp
deleted file mode 100644
index c13651eccb..0000000000
--- a/cpp/src/qpid/cluster/ConnectionInterceptor.cpp
+++ /dev/null
@@ -1,108 +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 "ConnectionInterceptor.h"
-#include "qpid/framing/ClusterConnectionCloseBody.h"
-#include "qpid/framing/ClusterConnectionDoOutputBody.h"
-#include "qpid/framing/AMQFrame.h"
-
-namespace qpid {
-namespace cluster {
-
-using namespace framing;
-
-template <class T, class U, class V> void shift(T& a, U& b, const V& c) { a = b; b = c; }
-
-ConnectionInterceptor::ConnectionInterceptor(
- broker::Connection& conn, Cluster& clust, Cluster::ShadowConnectionId shadowId_)
- : connection(&conn), cluster(clust), isClosed(false), shadowId(shadowId_)
-{
- connection->addFinalizer(boost::bind(operator delete, this));
- // Attach my functions to Connection extension points.
- shift(receivedNext, connection->receivedFn, boost::bind(&ConnectionInterceptor::received, this, _1));
- shift(closedNext, connection->closedFn, boost::bind(&ConnectionInterceptor::closed, this));
- shift(doOutputNext, connection->doOutputFn, boost::bind(&ConnectionInterceptor::doOutput, this));
-}
-
-ConnectionInterceptor::~ConnectionInterceptor() {
- assert(connection == 0);
-}
-
-void ConnectionInterceptor::received(framing::AMQFrame& f) {
- if (isClosed) return;
- cluster.send(f, this);
-}
-
-void ConnectionInterceptor::deliver(framing::AMQFrame& f) {
- receivedNext(f);
-}
-
-void ConnectionInterceptor::closed() {
- if (isClosed) return;
- try {
- // Called when the local network connection is closed. We still
- // need to process any outstanding cluster frames for this
- // connection to ensure our sessions are up-to-date. We defer
- // closing the Connection object till deliverClosed(), but replace
- // its output handler with a null handler since the network output
- // handler will be deleted.
- //
- connection->setOutputHandler(&discardHandler);
- cluster.send(AMQFrame(in_place<ClusterConnectionCloseBody>()), this);
- isClosed = true;
- }
- catch (const std::exception& e) {
- QPID_LOG(error, QPID_MSG("While closing connection: " << e.what()));
- }
-}
-
-void ConnectionInterceptor::deliverClosed() {
- closedNext();
- // Drop reference so connection will be deleted, which in turn
- // will delete this via finalizer added in ctor.
- connection = 0;
-}
-
-void ConnectionInterceptor::dirtyClose() {
- // Not closed via cluster self-delivery but closed locally.
- // Used for dirty cluster shutdown where active connections
- // must be cleaned up.
- connection = 0;
-}
-
-bool ConnectionInterceptor::doOutput() {
- // FIXME aconway 2008-08-15: this is not correct.
- // Run in write threads so order of execution of doOutput is not determinate.
- // Will only work reliably for in single-consumer tests.
-
- if (connection->hasOutput()) {
- cluster.send(AMQFrame(in_place<ClusterConnectionDoOutputBody>()), this);
- return doOutputNext();
- }
- return false;
-}
-
-void ConnectionInterceptor::deliverDoOutput() {
- // FIXME aconway 2008-08-15: see comment in doOutput.
- if (isShadow())
- doOutputNext();
-}
-
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/ConnectionInterceptor.h b/cpp/src/qpid/cluster/ConnectionInterceptor.h
deleted file mode 100644
index 370572bd9d..0000000000
--- a/cpp/src/qpid/cluster/ConnectionInterceptor.h
+++ /dev/null
@@ -1,82 +0,0 @@
-#ifndef QPID_CLUSTER_CONNECTIONPLUGIN_H
-#define QPID_CLUSTER_CONNECTIONPLUGIN_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "Cluster.h"
-#include "qpid/broker/Connection.h"
-#include "qpid/sys/ConnectionOutputHandler.h"
-
-namespace qpid {
-namespace framing { class AMQFrame; }
-namespace cluster {
-
-/**
- * Plug-in associated with broker::Connections, both local and shadow.
- */
-class ConnectionInterceptor {
- public:
- ConnectionInterceptor(broker::Connection&, Cluster&,
- Cluster::ShadowConnectionId shadowId=Cluster::ShadowConnectionId(0,0));
- ~ConnectionInterceptor();
-
- Cluster::ShadowConnectionId getShadowId() const { return shadowId; }
-
- bool isLocal() const { return shadowId == Cluster::ShadowConnectionId(0,0); }
-
- // self-delivery of intercepted extension points.
- void deliver(framing::AMQFrame& f);
- void deliverClosed();
- void deliverDoOutput();
-
- void dirtyClose();
-
- private:
- struct NullConnectionHandler : public qpid::sys::ConnectionOutputHandler {
- void close() {}
- void send(framing::AMQFrame&) {}
- void doOutput() {}
- void activateOutput() {}
- };
-
- bool isShadow() { return shadowId != Cluster::ShadowConnectionId(0,0); }
-
- // Functions to intercept to Connection extension points.
- void received(framing::AMQFrame&);
- void closed();
- bool doOutput();
-
- boost::function<void (framing::AMQFrame&)> receivedNext;
- boost::function<void ()> closedNext;
- boost::function<bool ()> doOutputNext;
-
- boost::intrusive_ptr<broker::Connection> connection;
- Cluster& cluster;
- NullConnectionHandler discardHandler;
- bool isClosed;
- Cluster::ShadowConnectionId shadowId;
-};
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_CONNECTIONPLUGIN_H*/
-
diff --git a/cpp/src/qpid/cluster/Cpg.cpp b/cpp/src/qpid/cluster/Cpg.cpp
index 2ffd3509bf..3ae0c970c7 100644
--- a/cpp/src/qpid/cluster/Cpg.cpp
+++ b/cpp/src/qpid/cluster/Cpg.cpp
@@ -16,33 +16,85 @@
*
*/
-#include "Cpg.h"
+#include "qpid/cluster/Cpg.h"
#include "qpid/sys/Mutex.h"
-// Note cpg is currently unix-specific. Refactor if availble on other platforms.
+#include "qpid/sys/Time.h"
#include "qpid/sys/posix/PrivatePosix.h"
#include "qpid/log/Statement.h"
#include <vector>
#include <limits>
#include <iterator>
+#include <sstream>
#include <unistd.h>
+// This is a macro instead of a function because we don't want to
+// evaluate the MSG argument unless there is an error.
+#define CPG_CHECK(RESULT, MSG) \
+ if ((RESULT) != CPG_OK) throw Exception(errorStr((RESULT), (MSG)))
+
namespace qpid {
namespace cluster {
using namespace std;
+
+
Cpg* Cpg::cpgFromHandle(cpg_handle_t handle) {
void* cpg=0;
- check(cpg_context_get(handle, &cpg), "Cannot get CPG instance.");
+ CPG_CHECK(cpg_context_get(handle, &cpg), "Cannot get CPG instance.");
if (!cpg) throw Exception("Cannot get CPG instance.");
return reinterpret_cast<Cpg*>(cpg);
}
+// Applies the same retry-logic to all cpg calls that need it.
+void Cpg::callCpg ( CpgOp & c ) {
+ cpg_error_t result;
+ unsigned int snooze = 10;
+ for ( unsigned int nth_try = 0; nth_try < cpgRetries; ++ nth_try ) {
+ if ( CPG_OK == (result = c.op(handle, & group))) {
+ QPID_LOG(info, c.opName << " successful.");
+ break;
+ }
+ else if ( result == CPG_ERR_TRY_AGAIN ) {
+ QPID_LOG(info, "Retrying " << c.opName );
+ sys::usleep ( snooze );
+ snooze *= 10;
+ snooze = (snooze <= maxCpgRetrySleep) ? snooze : maxCpgRetrySleep;
+ }
+ else break; // Don't retry unless CPG tells us to.
+ }
+
+ if ( result != CPG_OK )
+ CPG_CHECK(result, c.msg(group));
+}
+
// Global callback functions.
void Cpg::globalDeliver (
cpg_handle_t handle,
+ const struct cpg_name *group,
+ uint32_t nodeid,
+ uint32_t pid,
+ void* msg,
+ size_t msg_len)
+{
+ cpgFromHandle(handle)->handler.deliver(handle, group, nodeid, pid, msg, msg_len);
+}
+
+void Cpg::globalConfigChange(
+ cpg_handle_t handle,
+ const struct cpg_name *group,
+ const struct cpg_address *members, size_t nMembers,
+ const struct cpg_address *left, size_t nLeft,
+ const struct cpg_address *joined, size_t nJoined
+)
+{
+ cpgFromHandle(handle)->handler.configChange(handle, group, members, nMembers, left, nLeft, joined, nJoined);
+}
+
+void Cpg::globalDeliver (
+ cpg_handle_t handle,
struct cpg_name *group,
uint32_t nodeid,
uint32_t pid,
@@ -65,103 +117,119 @@ void Cpg::globalConfigChange(
int Cpg::getFd() {
int fd;
- check(cpg_fd_get(handle, &fd), "Cannot get CPG file descriptor");
+ CPG_CHECK(cpg_fd_get(handle, &fd), "Cannot get CPG file descriptor");
return fd;
}
Cpg::Cpg(Handler& h) : IOHandle(new sys::IOHandlePrivate), handler(h), isShutdown(false) {
- cpg_callbacks_t callbacks = { &globalDeliver, &globalConfigChange };
- check(cpg_initialize(&handle, &callbacks), "Cannot initialize CPG");
- check(cpg_context_set(handle, this), "Cannot set CPG context");
+ cpg_callbacks_t callbacks;
+ ::memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.cpg_deliver_fn = &globalDeliver;
+ callbacks.cpg_confchg_fn = &globalConfigChange;
+
+ QPID_LOG(notice, "Initializing CPG");
+ cpg_error_t err = cpg_initialize(&handle, &callbacks);
+ int retries = 6; // FIXME aconway 2009-08-06: make this configurable.
+ while (err == CPG_ERR_TRY_AGAIN && --retries) {
+ QPID_LOG(notice, "Re-trying CPG initialization.");
+ sys::sleep(5);
+ err = cpg_initialize(&handle, &callbacks);
+ }
+ CPG_CHECK(err, "Failed to initialize CPG.");
+ CPG_CHECK(cpg_context_set(handle, this), "Cannot set CPG context");
// Note: CPG is currently unix-specific. If CPG is ported to
// windows then this needs to be refactored into
// qpid::sys::<platform>
IOHandle::impl->fd = getFd();
- QPID_LOG(debug, "Initialized CPG handle 0x" << std::hex << handle);
}
Cpg::~Cpg() {
try {
shutdown();
} catch (const std::exception& e) {
- QPID_LOG(error, "Exception in Cpg destructor: " << e.what());
+ QPID_LOG(error, "Error during CPG shutdown: " << e.what());
}
}
-void Cpg::join(const Name& group) {
- check(cpg_join(handle, const_cast<Name*>(&group)),cantJoinMsg(group));
+void Cpg::join(const std::string& name) {
+ group = name;
+ callCpg ( cpgJoinOp );
}
-void Cpg::leave(const Name& group) {
- check(cpg_leave(handle,const_cast<Name*>(&group)),cantLeaveMsg(group));
+void Cpg::leave() {
+ callCpg ( cpgLeaveOp );
}
-bool Cpg::isFlowControlEnabled() {
+
+
+
+bool Cpg::mcast(const iovec* iov, int iovLen) {
+ // Check for flow control
cpg_flow_control_state_t flowState;
- check(cpg_flow_control_state_get(handle, &flowState), "Cannot get CPG flow control status.");
- return flowState == CPG_FLOW_CONTROL_ENABLED;
-}
-
-// TODO aconway 2008-08-07: better handling of flow control.
-// Wait for flow control to be disabled.
-// FIXME aconway 2008-08-08: does flow control check involve a round-trip? If so maybe remove...
-void Cpg::waitForFlowControl() {
- int delayNs=1000; // one millisecond
- int tries=8; // double the delay on each try.
- while (isFlowControlEnabled() && tries > 0) {
- QPID_LOG(warning, "CPG flow control enabled, retry in " << delayNs << "ns");
- ::usleep(delayNs);
- --tries;
- delayNs *= 2;
- };
- if (tries == 0) {
- // FIXME aconway 2008-08-07: this is a fatal leave-the-cluster condition.
- throw Cpg::Exception("CPG flow control enabled, failed to send.");
- }
-}
+ CPG_CHECK(cpg_flow_control_state_get(handle, &flowState), "Cannot get CPG flow control status.");
+ if (flowState == CPG_FLOW_CONTROL_ENABLED)
+ return false;
-void Cpg::mcast(const Name& group, const iovec* iov, int iovLen) {
- waitForFlowControl();
cpg_error_t result;
do {
result = cpg_mcast_joined(handle, CPG_TYPE_AGREED, const_cast<iovec*>(iov), iovLen);
- if (result != CPG_ERR_TRY_AGAIN) check(result, cantMcastMsg(group));
+ if (result != CPG_ERR_TRY_AGAIN) CPG_CHECK(result, cantMcastMsg(group));
} while(result == CPG_ERR_TRY_AGAIN);
+ return true;
}
void Cpg::shutdown() {
if (!isShutdown) {
QPID_LOG(debug,"Shutting down CPG");
isShutdown=true;
- check(cpg_finalize(handle), "Error in shutdown of CPG");
+
+ callCpg ( cpgFinalizeOp );
}
}
+void Cpg::dispatchOne() {
+ CPG_CHECK(cpg_dispatch(handle,CPG_DISPATCH_ONE), "Error in CPG dispatch");
+}
+
+void Cpg::dispatchAll() {
+ CPG_CHECK(cpg_dispatch(handle,CPG_DISPATCH_ALL), "Error in CPG dispatch");
+}
+
+void Cpg::dispatchBlocking() {
+ CPG_CHECK(cpg_dispatch(handle,CPG_DISPATCH_BLOCKING), "Error in CPG dispatch");
+}
+
string Cpg::errorStr(cpg_error_t err, const std::string& msg) {
+ std::ostringstream os;
+ os << msg << ": ";
switch (err) {
- case CPG_OK: return msg+": ok";
- case CPG_ERR_LIBRARY: return msg+": library";
- case CPG_ERR_TIMEOUT: return msg+": timeout";
- case CPG_ERR_TRY_AGAIN: return msg+": timeout. The aisexec daemon may not be running";
- case CPG_ERR_INVALID_PARAM: return msg+": invalid param";
- case CPG_ERR_NO_MEMORY: return msg+": no memory";
- case CPG_ERR_BAD_HANDLE: return msg+": bad handle";
- case CPG_ERR_ACCESS: return msg+": access denied. You may need to set your group ID to 'ais'";
- case CPG_ERR_NOT_EXIST: return msg+": not exist";
- case CPG_ERR_EXIST: return msg+": exist";
- case CPG_ERR_NOT_SUPPORTED: return msg+": not supported";
- case CPG_ERR_SECURITY: return msg+": security";
- case CPG_ERR_TOO_MANY_GROUPS: return msg+": too many groups";
- default:
- assert(0);
- return ": unknown";
+ case CPG_OK: os << "ok"; break;
+ case CPG_ERR_LIBRARY: os << "library"; break;
+ case CPG_ERR_TIMEOUT: os << "timeout"; break;
+ case CPG_ERR_TRY_AGAIN: os << "try again"; break;
+ case CPG_ERR_INVALID_PARAM: os << "invalid param"; break;
+ case CPG_ERR_NO_MEMORY: os << "no memory"; break;
+ case CPG_ERR_BAD_HANDLE: os << "bad handle"; break;
+ case CPG_ERR_ACCESS: os << "access denied. You may need to set your group ID to 'ais'"; break;
+ case CPG_ERR_NOT_EXIST: os << "not exist"; break;
+ case CPG_ERR_EXIST: os << "exist"; break;
+ case CPG_ERR_NOT_SUPPORTED: os << "not supported"; break;
+ case CPG_ERR_SECURITY: os << "security"; break;
+ case CPG_ERR_TOO_MANY_GROUPS: os << "too many groups"; break;
+ default: os << ": unknown cpg error " << err;
};
+ os << " (" << err << ")";
+ return os.str();
}
std::string Cpg::cantJoinMsg(const Name& group) {
return "Cannot join CPG group "+group.str();
}
+std::string Cpg::cantFinalizeMsg(const Name& group) {
+ return "Cannot finalize CPG group "+group.str();
+}
+
std::string Cpg::cantLeaveMsg(const Name& group) {
return "Cannot leave CPG group "+group.str();
}
@@ -170,27 +238,44 @@ std::string Cpg::cantMcastMsg(const Name& group) {
return "Cannot mcast to CPG group "+group.str();
}
-Cpg::Id Cpg::self() const {
+MemberId Cpg::self() const {
unsigned int nodeid;
- check(cpg_local_get(handle, &nodeid), "Cannot get local CPG identity");
- return Id(nodeid, getpid());
+ CPG_CHECK(cpg_local_get(handle, &nodeid), "Cannot get local CPG identity");
+ return MemberId(nodeid, getpid());
}
-ostream& operator<<(ostream& o, std::pair<cpg_address*,int> a) {
- ostream_iterator<Cpg::Id> i(o, " ");
- std::copy(a.first, a.first+a.second, i);
- return o;
+namespace { int byte(uint32_t value, int i) { return (value >> (i*8)) & 0xff; } }
+
+ostream& operator<<(ostream& out, const MemberId& id) {
+ if (id.first) {
+ out << byte(id.first, 0) << "."
+ << byte(id.first, 1) << "."
+ << byte(id.first, 2) << "."
+ << byte(id.first, 3)
+ << ":";
+ }
+ return out << id.second;
}
-ostream& operator <<(ostream& out, const Cpg::Id& id) {
- return out << id.getNodeId() << "-" << id.getPid();
+ostream& operator<<(ostream& o, const ConnectionId& c) {
+ return o << c.first << "-" << c.second;
}
-ostream& operator <<(ostream& out, const cpg_name& name) {
- return out << string(name.value, name.length);
+std::string MemberId::str() const {
+ char s[8];
+ uint32_t x;
+ x = htonl(first);
+ ::memcpy(s, &x, 4);
+ x = htonl(second);
+ ::memcpy(s+4, &x, 4);
+ return std::string(s,8);
}
+MemberId::MemberId(const std::string& s) {
+ uint32_t x;
+ memcpy(&x, &s[0], 4);
+ first = ntohl(x);
+ memcpy(&x, &s[4], 4);
+ second = ntohl(x);
+}
}} // namespace qpid::cluster
-
-
-
diff --git a/cpp/src/qpid/cluster/Cpg.h b/cpp/src/qpid/cluster/Cpg.h
index 96fd692a77..6b81c602bd 100644
--- a/cpp/src/qpid/cluster/Cpg.h
+++ b/cpp/src/qpid/cluster/Cpg.h
@@ -20,25 +20,18 @@
*/
#include "qpid/Exception.h"
+#include "qpid/cluster/types.h"
#include "qpid/sys/IOHandle.h"
-#include "qpid/cluster/Dispatchable.h"
+#include "qpid/sys/Mutex.h"
-#include <boost/tuple/tuple.hpp>
-#include <boost/tuple/tuple_comparison.hpp>
#include <boost/scoped_ptr.hpp>
#include <cassert>
-
#include <string.h>
-extern "C" {
-#include <openais/cpg.h>
-}
-
namespace qpid {
namespace cluster {
-
/**
* Lightweight C++ interface to cpg.h operations.
*
@@ -46,6 +39,7 @@ namespace cluster {
* On error all functions throw Cpg::Exception.
*
*/
+
class Cpg : public sys::IOHandle {
public:
struct Exception : public ::qpid::Exception {
@@ -53,6 +47,7 @@ class Cpg : public sys::IOHandle {
};
struct Name : public cpg_name {
+ Name() { length = 0; }
Name(const char* s) { copy(s, strlen(s)); }
Name(const char* s, size_t n) { copy(s,n); }
Name(const std::string& s) { copy(s.data(), s.size()); }
@@ -65,14 +60,6 @@ class Cpg : public sys::IOHandle {
std::string str() const { return std::string(value, length); }
};
- // boost::tuple gives us == and < for free.
- struct Id : public boost::tuple<uint32_t, uint32_t> {
- Id(uint32_t n=0, uint32_t p=0) : boost::tuple<uint32_t, uint32_t>(n, p) {}
- Id(const cpg_address& addr) : boost::tuple<uint32_t, uint32_t>(addr.nodeid, addr.pid) {}
- uint32_t getNodeId() const { return boost::get<0>(*this); }
- uint32_t getPid() const { return boost::get<1>(*this); }
- };
-
static std::string str(const cpg_name& n) {
return std::string(n.value, n.length);
}
@@ -81,7 +68,7 @@ class Cpg : public sys::IOHandle {
virtual ~Handler() {};
virtual void deliver(
cpg_handle_t /*handle*/,
- struct cpg_name *group,
+ const struct cpg_name *group,
uint32_t /*nodeid*/,
uint32_t /*pid*/,
void* /*msg*/,
@@ -89,10 +76,10 @@ class Cpg : public sys::IOHandle {
virtual void configChange(
cpg_handle_t /*handle*/,
- struct cpg_name */*group*/,
- struct cpg_address */*members*/, int /*nMembers*/,
- struct cpg_address */*left*/, int /*nLeft*/,
- struct cpg_address */*joined*/, int /*nJoined*/
+ const struct cpg_name */*group*/,
+ const struct cpg_address */*members*/, int /*nMembers*/,
+ const struct cpg_address */*left*/, int /*nLeft*/,
+ const struct cpg_address */*joined*/, int /*nJoined*/
) = 0;
};
@@ -107,41 +94,115 @@ class Cpg : public sys::IOHandle {
/** Disconnect from CPG */
void shutdown();
- /** Dispatch CPG events.
- *@param type one of
- * - CPG_DISPATCH_ONE - dispatch exactly one event.
- * - CPG_DISPATCH_ALL - dispatch all available events, don't wait.
- * - CPG_DISPATCH_BLOCKING - blocking dispatch loop.
- */
- void dispatch(cpg_dispatch_t type) {
- check(cpg_dispatch(handle,type), "Error in CPG dispatch");
- }
+ void dispatchOne();
+ void dispatchAll();
+ void dispatchBlocking();
- void dispatchOne() { dispatch(CPG_DISPATCH_ONE); }
- void dispatchAll() { dispatch(CPG_DISPATCH_ALL); }
- void dispatchBlocking() { dispatch(CPG_DISPATCH_BLOCKING); }
+ void join(const std::string& group);
+ void leave();
- void join(const Name& group);
- void leave(const Name& group);
- void mcast(const Name& group, const iovec* iov, int iovLen);
+ /** Multicast to the group. NB: must not be called concurrently.
+ *
+ *@return true if the message was multi-cast, false if
+ * it was not sent due to flow control.
+ */
+ bool mcast(const iovec* iov, int iovLen);
cpg_handle_t getHandle() const { return handle; }
- Id self() const;
+ MemberId self() const;
int getFd();
private:
+
+ // Maximum number of retries for cog functions that can tell
+ // us to "try again later".
+ static const unsigned int cpgRetries = 5;
+
+ // Don't let sleep-time between cpg retries to go above 0.1 second.
+ static const unsigned int maxCpgRetrySleep = 100000;
+
+
+ // Base class for the Cpg operations that need retry capability.
+ struct CpgOp {
+ std::string opName;
+
+ CpgOp ( std::string opName )
+ : opName(opName) { }
+
+ virtual cpg_error_t op ( cpg_handle_t handle, struct cpg_name * ) = 0;
+ virtual std::string msg(const Name&) = 0;
+ virtual ~CpgOp ( ) { }
+ };
+
+
+ struct CpgJoinOp : public CpgOp {
+ CpgJoinOp ( )
+ : CpgOp ( std::string("cpg_join") ) { }
+
+ cpg_error_t op(cpg_handle_t handle, struct cpg_name * group) {
+ return cpg_join ( handle, group );
+ }
+
+ std::string msg(const Name& name) { return cantJoinMsg(name); }
+ };
+
+ struct CpgLeaveOp : public CpgOp {
+ CpgLeaveOp ( )
+ : CpgOp ( std::string("cpg_leave") ) { }
+
+ cpg_error_t op(cpg_handle_t handle, struct cpg_name * group) {
+ return cpg_leave ( handle, group );
+ }
+
+ std::string msg(const Name& name) { return cantLeaveMsg(name); }
+ };
+
+ struct CpgFinalizeOp : public CpgOp {
+ CpgFinalizeOp ( )
+ : CpgOp ( std::string("cpg_finalize") ) { }
+
+ cpg_error_t op(cpg_handle_t handle, struct cpg_name *) {
+ return cpg_finalize ( handle );
+ }
+
+ std::string msg(const Name& name) { return cantFinalizeMsg(name); }
+ };
+
+ // This fn standardizes retry policy across all Cpg ops that need it.
+ void callCpg ( CpgOp & );
+
+ CpgJoinOp cpgJoinOp;
+ CpgLeaveOp cpgLeaveOp;
+ CpgFinalizeOp cpgFinalizeOp;
+
static std::string errorStr(cpg_error_t err, const std::string& msg);
static std::string cantJoinMsg(const Name&);
- static std::string cantLeaveMsg(const Name&); std::string cantMcastMsg(const Name&);
-
- static void check(cpg_error_t result, const std::string& msg) {
- if (result != CPG_OK) throw Exception(errorStr(result, msg));
- }
+ static std::string cantLeaveMsg(const Name&);
+ static std::string cantMcastMsg(const Name&);
+ static std::string cantFinalizeMsg(const Name&);
static Cpg* cpgFromHandle(cpg_handle_t);
+ // New versions for corosync 1.0 and higher
+ static void globalDeliver(
+ cpg_handle_t handle,
+ const struct cpg_name *group,
+ uint32_t nodeid,
+ uint32_t pid,
+ void* msg,
+ size_t msg_len);
+
+ static void globalConfigChange(
+ cpg_handle_t handle,
+ const struct cpg_name *group,
+ const struct cpg_address *members, size_t nMembers,
+ const struct cpg_address *left, size_t nLeft,
+ const struct cpg_address *joined, size_t nJoined
+ );
+
+ // Old versions for openais
static void globalDeliver(
cpg_handle_t handle,
struct cpg_name *group,
@@ -158,18 +219,13 @@ class Cpg : public sys::IOHandle {
struct cpg_address *joined, int nJoined
);
- bool isFlowControlEnabled();
- void waitForFlowControl();
-
cpg_handle_t handle;
Handler& handler;
bool isShutdown;
+ Name group;
+ sys::Mutex dispatchLock;
};
-std::ostream& operator <<(std::ostream& out, const cpg_name& name);
-std::ostream& operator <<(std::ostream& out, const Cpg::Id& id);
-std::ostream& operator <<(std::ostream& out, const std::pair<cpg_address*,int> addresses);
-
inline bool operator==(const cpg_name& a, const cpg_name& b) {
return a.length==b.length && strncmp(a.value, b.value, a.length) == 0;
}
@@ -177,5 +233,4 @@ inline bool operator!=(const cpg_name& a, const cpg_name& b) { return !(a == b);
}} // namespace qpid::cluster
-
#endif /*!CPG_H*/
diff --git a/cpp/src/qpid/cluster/Decoder.cpp b/cpp/src/qpid/cluster/Decoder.cpp
new file mode 100644
index 0000000000..23ba372d78
--- /dev/null
+++ b/cpp/src/qpid/cluster/Decoder.cpp
@@ -0,0 +1,65 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/cluster/Decoder.h"
+#include "qpid/cluster/EventFrame.h"
+#include "qpid/framing/ClusterConnectionDeliverCloseBody.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/AMQFrame.h"
+
+
+namespace qpid {
+namespace cluster {
+
+void Decoder::decode(const EventHeader& eh, const char* data) {
+ sys::Mutex::ScopedLock l(lock);
+ assert(eh.getType() == DATA); // Only handle connection data events.
+ const char* cp = static_cast<const char*>(data);
+ framing::Buffer buf(const_cast<char*>(cp), eh.getSize());
+ framing::FrameDecoder& decoder = map[eh.getConnectionId()];
+ if (decoder.decode(buf)) { // Decoded a frame
+ framing::AMQFrame frame(decoder.getFrame());
+ while (decoder.decode(buf)) {
+ callback(EventFrame(eh, frame));
+ frame = decoder.getFrame();
+ }
+ // Set read-credit on the last frame ending in this event.
+ // Credit will be given when this frame is processed.
+ callback(EventFrame(eh, frame, 1));
+ }
+ else {
+ // We must give 1 unit read credit per event.
+ // This event does not complete any frames so
+ // send an empty frame with the read credit.
+ callback(EventFrame(eh, framing::AMQFrame(), 1));
+ }
+}
+
+void Decoder::erase(const ConnectionId& c) {
+ sys::Mutex::ScopedLock l(lock);
+ map.erase(c);
+}
+
+framing::FrameDecoder& Decoder::get(const ConnectionId& c) {
+ sys::Mutex::ScopedLock l(lock);
+ return map[c];
+}
+
+}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/Decoder.h b/cpp/src/qpid/cluster/Decoder.h
new file mode 100644
index 0000000000..2e2af2868f
--- /dev/null
+++ b/cpp/src/qpid/cluster/Decoder.h
@@ -0,0 +1,59 @@
+#ifndef QPID_CLUSTER_DECODER_H
+#define QPID_CLUSTER_DECODER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/cluster/types.h"
+#include "qpid/framing/FrameDecoder.h"
+#include "qpid/sys/Mutex.h"
+#include <boost/function.hpp>
+#include <map>
+
+namespace qpid {
+namespace cluster {
+
+class EventFrame;
+class EventHeader;
+
+/**
+ * A map of decoders for connections.
+ */
+class Decoder
+{
+ public:
+ typedef boost::function<void(const EventFrame&)> FrameHandler;
+
+ Decoder(FrameHandler fh) : callback(fh) {}
+ void decode(const EventHeader& eh, const char* data);
+ void erase(const ConnectionId&);
+ framing::FrameDecoder& get(const ConnectionId& c);
+
+ private:
+ typedef std::map<ConnectionId, framing::FrameDecoder> Map;
+ sys::Mutex lock;
+ Map map;
+ void process(const EventFrame&);
+ FrameHandler callback;
+};
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_DECODER_H*/
diff --git a/cpp/src/qpid/cluster/ErrorCheck.cpp b/cpp/src/qpid/cluster/ErrorCheck.cpp
new file mode 100644
index 0000000000..d66db8551d
--- /dev/null
+++ b/cpp/src/qpid/cluster/ErrorCheck.cpp
@@ -0,0 +1,155 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/cluster/ErrorCheck.h"
+#include "qpid/cluster/EventFrame.h"
+#include "qpid/cluster/ClusterMap.h"
+#include "qpid/cluster/Cluster.h"
+#include "qpid/framing/ClusterErrorCheckBody.h"
+#include "qpid/framing/ClusterConfigChangeBody.h"
+#include "qpid/log/Statement.h"
+
+#include <algorithm>
+
+namespace qpid {
+namespace cluster {
+
+using namespace std;
+using namespace framing;
+using namespace framing::cluster;
+
+ErrorCheck::ErrorCheck(Cluster& c)
+ : cluster(c), mcast(c.getMulticast()), frameSeq(0), type(ERROR_TYPE_NONE), connection(0)
+{}
+
+void ErrorCheck::error(
+ Connection& c, ErrorType t, framing::SequenceNumber seq, const MemberSet& ms,
+ const std::string& msg)
+{
+ // Detected a local error, inform cluster and set error state.
+ assert(t != ERROR_TYPE_NONE); // Must be an error.
+ assert(type == ERROR_TYPE_NONE); // Can't be called when already in an error state.
+ type = t;
+ unresolved = ms;
+ frameSeq = seq;
+ connection = &c;
+ message = msg;
+ QPID_LOG(debug, cluster<< (type == ERROR_TYPE_SESSION ? " channel" : " connection")
+ << " error " << frameSeq << " on " << c
+ << " must be resolved with: " << unresolved
+ << ": " << message);
+ mcast.mcastControl(
+ ClusterErrorCheckBody(ProtocolVersion(), type, frameSeq), cluster.getId());
+ // If there are already frames queued up by a previous error, review
+ // them with respect to this new error.
+ for (FrameQueue::iterator i = frames.begin(); i != frames.end(); i = review(i))
+ ;
+}
+
+void ErrorCheck::delivered(const EventFrame& e) {
+ frames.push_back(e);
+ review(frames.end()-1);
+}
+
+// Review a frame in the queue with respect to the current error.
+ErrorCheck::FrameQueue::iterator ErrorCheck::review(const FrameQueue::iterator& i) {
+ FrameQueue::iterator next = i+1;
+ if(!isUnresolved() || !i->frame.getBody() || !i->frame.getMethod())
+ return next; // Only interested in control frames while unresolved.
+ const AMQMethodBody* method = i->frame.getMethod();
+ if (method->isA<const ClusterErrorCheckBody>()) {
+ const ClusterErrorCheckBody* errorCheck =
+ static_cast<const ClusterErrorCheckBody*>(method);
+
+ if (errorCheck->getFrameSeq() == frameSeq) { // Addresses current error
+ next = frames.erase(i); // Drop matching error check controls
+ if (errorCheck->getType() < type) { // my error is worse than his
+ QPID_LOG(critical, cluster
+ << " local error " << frameSeq << " did not occur on member "
+ << i->getMemberId()
+ << ": " << message);
+ throw Exception(
+ QPID_MSG("local error did not occur on all cluster members " << ": " << message));
+ }
+ else { // his error is worse/same as mine.
+ QPID_LOG(debug, cluster << " error " << frameSeq
+ << " resolved with " << i->getMemberId());
+ unresolved.erase(i->getMemberId());
+ checkResolved();
+ }
+ }
+ else if (errorCheck->getFrameSeq() < frameSeq && errorCheck->getType() != NONE
+ && i->connectionId.getMember() != cluster.getId())
+ {
+ // This error occured before the current error so we
+ // have processed past it.
+ next = frames.erase(i); // Drop the error check control
+ respondNone(i->connectionId.getMember(), errorCheck->getType(),
+ errorCheck->getFrameSeq());
+ }
+ // if errorCheck->getFrameSeq() > frameSeq then leave it in the queue.
+ }
+ else if (method->isA<const ClusterConfigChangeBody>()) {
+ const ClusterConfigChangeBody* configChange =
+ static_cast<const ClusterConfigChangeBody*>(method);
+ if (configChange) {
+ MemberSet members(decodeMemberSet(configChange->getCurrent()));
+ QPID_LOG(debug, cluster << " apply config change to error "
+ << frameSeq << ": " << members);
+ MemberSet intersect;
+ set_intersection(members.begin(), members.end(),
+ unresolved.begin(), unresolved.end(),
+ inserter(intersect, intersect.begin()));
+ unresolved.swap(intersect);
+ checkResolved();
+ }
+ }
+ return next;
+}
+
+void ErrorCheck::checkResolved() {
+ if (unresolved.empty()) { // No more potentially conflicted members, we're clear.
+ type = ERROR_TYPE_NONE;
+ QPID_LOG(debug, cluster << " error " << frameSeq << " resolved.");
+ }
+ else
+ QPID_LOG(debug, cluster << " error " << frameSeq
+ << " must be resolved with " << unresolved);
+}
+
+EventFrame ErrorCheck::getNext() {
+ assert(canProcess());
+ EventFrame e(frames.front());
+ frames.pop_front();
+ return e;
+}
+
+void ErrorCheck::respondNone(const MemberId& from, uint8_t type, framing::SequenceNumber frameSeq) {
+ // Don't respond to non-errors or to my own errors.
+ if (type == ERROR_TYPE_NONE || from == cluster.getId())
+ return;
+ QPID_LOG(debug, cluster << " error " << frameSeq << " did not occur locally.");
+ mcast.mcastControl(
+ ClusterErrorCheckBody(ProtocolVersion(), ERROR_TYPE_NONE, frameSeq),
+ cluster.getId()
+ );
+}
+
+}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/ErrorCheck.h b/cpp/src/qpid/cluster/ErrorCheck.h
new file mode 100644
index 0000000000..de8cedafb3
--- /dev/null
+++ b/cpp/src/qpid/cluster/ErrorCheck.h
@@ -0,0 +1,90 @@
+#ifndef QPID_CLUSTER_ERRORCHECK_H
+#define QPID_CLUSTER_ERRORCHECK_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/cluster/MemberSet.h"
+#include "qpid/cluster/Multicaster.h"
+#include "qpid/framing/enum.h"
+#include "qpid/framing/SequenceNumber.h"
+#include <boost/function.hpp>
+#include <deque>
+#include <set>
+
+namespace qpid {
+namespace cluster {
+
+class EventFrame;
+class Cluster;
+class Multicaster;
+class Connection;
+
+/**
+ * Error checking logic.
+ *
+ * When an error occurs queue up frames until we can determine if all
+ * nodes experienced the error. If not, we shut down.
+ */
+class ErrorCheck
+{
+ public:
+ typedef framing::cluster::ErrorType ErrorType;
+ typedef framing::SequenceNumber SequenceNumber;
+
+ ErrorCheck(Cluster&);
+
+ /** A local error has occured */
+ void error(Connection&, ErrorType, SequenceNumber frameSeq, const MemberSet&,
+ const std::string& msg);
+
+ /** Called when a frame is delivered */
+ void delivered(const EventFrame&);
+
+ /**@pre canProcess **/
+ EventFrame getNext();
+
+ bool canProcess() const { return type == NONE && !frames.empty(); }
+
+ bool isUnresolved() const { return type != NONE; }
+
+ /** Respond to an error check saying we had no error. */
+ void respondNone(const MemberId&, uint8_t type, SequenceNumber frameSeq);
+
+ private:
+ static const ErrorType NONE = framing::cluster::ERROR_TYPE_NONE;
+ typedef std::deque<EventFrame> FrameQueue;
+ FrameQueue::iterator review(const FrameQueue::iterator&);
+ void checkResolved();
+
+ Cluster& cluster;
+ Multicaster& mcast;
+ FrameQueue frames;
+ MemberSet unresolved;
+ SequenceNumber frameSeq;
+ ErrorType type;
+ Connection* connection;
+ std::string message;
+};
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_ERRORCHECK_H*/
diff --git a/cpp/src/qpid/cluster/Event.cpp b/cpp/src/qpid/cluster/Event.cpp
new file mode 100644
index 0000000000..52564990f6
--- /dev/null
+++ b/cpp/src/qpid/cluster/Event.cpp
@@ -0,0 +1,136 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/cluster/types.h"
+#include "qpid/cluster/Event.h"
+#include "qpid/cluster/Cpg.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/assert.h"
+#include <ostream>
+#include <iterator>
+#include <algorithm>
+
+namespace qpid {
+namespace cluster {
+
+using framing::Buffer;
+using framing::AMQFrame;
+
+const size_t EventHeader::HEADER_SIZE =
+ sizeof(uint8_t) + // type
+ sizeof(uint64_t) + // connection pointer only, CPG provides member ID.
+ sizeof(uint32_t) // payload size
+ ;
+
+EventHeader::EventHeader(EventType t, const ConnectionId& c, size_t s)
+ : type(t), connectionId(c), size(s) {}
+
+
+Event::Event() {}
+
+Event::Event(EventType t, const ConnectionId& c, size_t s)
+ : EventHeader(t,c,s), store(RefCountedBuffer::create(s+HEADER_SIZE))
+{}
+
+void EventHeader::decode(const MemberId& m, framing::Buffer& buf) {
+ if (buf.available() <= HEADER_SIZE)
+ throw Exception("Not enough for multicast header");
+ type = (EventType)buf.getOctet();
+ if(type != DATA && type != CONTROL)
+ throw Exception("Invalid multicast event type");
+ connectionId = ConnectionId(m, buf.getLongLong());
+ size = buf.getLong();
+}
+
+Event Event::decodeCopy(const MemberId& m, framing::Buffer& buf) {
+ Event e;
+ e.decode(m, buf); // Header
+ if (buf.available() < e.size)
+ throw Exception("Not enough data for multicast event");
+ e.store = RefCountedBuffer::create(e.size + HEADER_SIZE);
+ memcpy(e.getData(), buf.getPointer() + buf.getPosition(), e.size);
+ return e;
+}
+
+Event Event::control(const framing::AMQFrame& f, const ConnectionId& cid) {
+ Event e(CONTROL, cid, f.encodedSize());
+ Buffer buf(e);
+ f.encode(buf);
+ return e;
+}
+
+Event Event::control(const framing::AMQBody& body, const ConnectionId& cid) {
+ return control(framing::AMQFrame(body), cid);
+}
+
+iovec Event::toIovec() const {
+ encodeHeader();
+ iovec iov = { const_cast<char*>(getStore()), getStoreSize() };
+ return iov;
+}
+
+void EventHeader::encode(Buffer& b) const {
+ b.putOctet(type);
+ b.putLongLong(connectionId.getNumber());
+ b.putLong(size);
+}
+
+// Encode my header in my buffer.
+void Event::encodeHeader () const {
+ Buffer b(const_cast<char*>(getStore()), HEADER_SIZE);
+ encode(b);
+ assert(b.getPosition() == HEADER_SIZE);
+}
+
+Event::operator Buffer() const {
+ return Buffer(const_cast<char*>(getData()), getSize());
+}
+
+const AMQFrame& Event::getFrame() const {
+ assert(type == CONTROL);
+ if (!frame.getBody()) {
+ Buffer buf(*this);
+ QPID_ASSERT(frame.decode(buf));
+ }
+ return frame;
+}
+
+static const char* EVENT_TYPE_NAMES[] = { "data", "control" };
+
+std::ostream& operator<< (std::ostream& o, EventType t) {
+ return o << EVENT_TYPE_NAMES[t];
+}
+
+std::ostream& operator<< (std::ostream& o, const EventHeader& e) {
+ return o << "Event[" << e.getConnectionId() << " " << e.getType()
+ << " " << e.getSize() << " bytes]";
+}
+
+std::ostream& operator<< (std::ostream& o, const Event& e) {
+ o << "Event[" << e.getConnectionId() << " ";
+ if (e.getType() == CONTROL)
+ o << e.getFrame();
+ else
+ o << " data " << e.getSize() << " bytes";
+ return o << "]";
+}
+
+}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/Event.h b/cpp/src/qpid/cluster/Event.h
new file mode 100644
index 0000000000..07f74d3ba5
--- /dev/null
+++ b/cpp/src/qpid/cluster/Event.h
@@ -0,0 +1,116 @@
+#ifndef QPID_CLUSTER_EVENT_H
+#define QPID_CLUSTER_EVENT_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/cluster/types.h"
+#include "qpid/RefCountedBuffer.h"
+#include "qpid/framing/AMQFrame.h"
+#include <sys/uio.h> // For iovec
+#include <iosfwd>
+
+#include "qpid/cluster/types.h"
+
+namespace qpid {
+
+namespace framing {
+class AMQBody;
+class AMQFrame;
+class Buffer;
+}
+
+namespace cluster {
+
+/** Header data for a multicast event */
+class EventHeader {
+ public:
+ EventHeader(EventType t=DATA, const ConnectionId& c=ConnectionId(), size_t size=0);
+ void decode(const MemberId& m, framing::Buffer&);
+ void encode(framing::Buffer&) const;
+
+ EventType getType() const { return type; }
+ ConnectionId getConnectionId() const { return connectionId; }
+ MemberId getMemberId() const { return connectionId.getMember(); }
+
+ /** Size of payload data, excluding header. */
+ size_t getSize() const { return size; }
+ /** Size of header + payload. */
+ size_t getStoreSize() const { return size + HEADER_SIZE; }
+
+ bool isCluster() const { return connectionId.getNumber() == 0; }
+ bool isConnection() const { return connectionId.getNumber() != 0; }
+ bool isControl() const { return type == CONTROL; }
+
+ protected:
+ static const size_t HEADER_SIZE;
+
+ EventType type;
+ ConnectionId connectionId;
+ size_t size;
+};
+
+/**
+ * Events are sent to/received from the cluster.
+ * Refcounted so they can be stored on queues.
+ */
+class Event : public EventHeader {
+ public:
+ Event();
+ /** Create an event with a buffer that can hold size bytes plus an event header. */
+ Event(EventType t, const ConnectionId& c, size_t);
+
+ /** Create an event copied from delivered data. */
+ static Event decodeCopy(const MemberId& m, framing::Buffer&);
+
+ /** Create a control event. */
+ static Event control(const framing::AMQBody&, const ConnectionId&);
+
+ /** Create a control event. */
+ static Event control(const framing::AMQFrame&, const ConnectionId&);
+
+ // Data excluding header.
+ char* getData() { return store + HEADER_SIZE; }
+ const char* getData() const { return store + HEADER_SIZE; }
+
+ // Store including header
+ char* getStore() { return store; }
+ const char* getStore() const { return store; }
+
+ const framing::AMQFrame& getFrame() const;
+
+ operator framing::Buffer() const;
+
+ iovec toIovec() const;
+
+ private:
+ void encodeHeader() const;
+
+ RefCountedBuffer::pointer store;
+ mutable framing::AMQFrame frame;
+};
+
+std::ostream& operator << (std::ostream&, const Event&);
+std::ostream& operator << (std::ostream&, const EventHeader&);
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_EVENT_H*/
diff --git a/cpp/src/qpid/cluster/EventFrame.cpp b/cpp/src/qpid/cluster/EventFrame.cpp
new file mode 100644
index 0000000000..5fbe1fe57c
--- /dev/null
+++ b/cpp/src/qpid/cluster/EventFrame.cpp
@@ -0,0 +1,41 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/cluster/EventFrame.h"
+#include "qpid/cluster/Connection.h"
+
+namespace qpid {
+namespace cluster {
+
+EventFrame::EventFrame() {}
+
+EventFrame::EventFrame(const EventHeader& e, const framing::AMQFrame& f, int rc)
+ : connectionId(e.getConnectionId()), frame(f), readCredit(rc), type(e.getType())
+{}
+
+std::ostream& operator<<(std::ostream& o, const EventFrame& e) {
+ if (e.frame.getBody()) o << e.frame;
+ else o << "null-frame";
+ o << " " << e.type << " " << e.connectionId;
+ if (e.readCredit) o << " read-credit=" << e.readCredit;
+ return o;
+}
+
+}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/EventFrame.h b/cpp/src/qpid/cluster/EventFrame.h
new file mode 100644
index 0000000000..61447c5525
--- /dev/null
+++ b/cpp/src/qpid/cluster/EventFrame.h
@@ -0,0 +1,60 @@
+#ifndef QPID_CLUSTER_EVENTFRAME_H
+#define QPID_CLUSTER_EVENTFRAME_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/cluster/types.h"
+#include "qpid/cluster/Event.h"
+#include "qpid/framing/AMQFrame.h"
+#include <boost/intrusive_ptr.hpp>
+#include <iosfwd>
+
+namespace qpid {
+namespace cluster {
+
+/**
+ * A frame decoded from an Event.
+ */
+struct EventFrame
+{
+ public:
+ EventFrame();
+
+ EventFrame(const EventHeader& e, const framing::AMQFrame& f, int rc=0);
+
+ bool isCluster() const { return connectionId.getNumber() == 0; }
+ bool isConnection() const { return connectionId.getNumber() != 0; }
+ bool isLastInEvent() const { return readCredit; }
+ MemberId getMemberId() const { return connectionId.getMember(); }
+
+
+ ConnectionId connectionId;
+ framing::AMQFrame frame;
+ int readCredit; ///< last frame in an event, give credit when processed.
+ EventType type;
+};
+
+std::ostream& operator<<(std::ostream& o, const EventFrame& e);
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_EVENTFRAME_H*/
diff --git a/cpp/src/qpid/cluster/ExpiryPolicy.cpp b/cpp/src/qpid/cluster/ExpiryPolicy.cpp
new file mode 100644
index 0000000000..190eeb7293
--- /dev/null
+++ b/cpp/src/qpid/cluster/ExpiryPolicy.cpp
@@ -0,0 +1,85 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/broker/Message.h"
+#include "qpid/cluster/ExpiryPolicy.h"
+#include "qpid/cluster/Multicaster.h"
+#include "qpid/framing/ClusterMessageExpiredBody.h"
+#include "qpid/sys/Time.h"
+#include "qpid/sys/Timer.h"
+#include "qpid/log/Statement.h"
+
+namespace qpid {
+namespace cluster {
+
+ExpiryPolicy::ExpiryPolicy(Multicaster& m, const MemberId& id, sys::Timer& t)
+ : expiryId(0), expiredPolicy(new Expired), mcast(m), memberId(id), timer(t) {}
+
+struct ExpiryTask : public sys::TimerTask {
+ ExpiryTask(const boost::intrusive_ptr<ExpiryPolicy>& policy, uint64_t id, sys::AbsTime when)
+ : TimerTask(when), expiryPolicy(policy), expiryId(id) {}
+ void fire() { expiryPolicy->sendExpire(expiryId); }
+ boost::intrusive_ptr<ExpiryPolicy> expiryPolicy;
+ const uint64_t expiryId;
+};
+
+void ExpiryPolicy::willExpire(broker::Message& m) {
+ uint64_t id = expiryId++;
+ assert(unexpiredById.find(id) == unexpiredById.end());
+ assert(unexpiredByMessage.find(&m) == unexpiredByMessage.end());
+ unexpiredById[id] = &m;
+ unexpiredByMessage[&m] = id;
+ timer.add(new ExpiryTask(this, id, m.getExpiration()));
+}
+
+void ExpiryPolicy::forget(broker::Message& m) {
+ MessageIdMap::iterator i = unexpiredByMessage.find(&m);
+ assert(i != unexpiredByMessage.end());
+ unexpiredById.erase(i->second);
+ unexpiredByMessage.erase(i);
+}
+
+bool ExpiryPolicy::hasExpired(broker::Message& m) {
+ return unexpiredByMessage.find(&m) == unexpiredByMessage.end();
+}
+
+void ExpiryPolicy::sendExpire(uint64_t id) {
+ mcast.mcastControl(framing::ClusterMessageExpiredBody(framing::ProtocolVersion(), id), memberId);
+}
+
+void ExpiryPolicy::deliverExpire(uint64_t id) {
+ IdMessageMap::iterator i = unexpiredById.find(id);
+ if (i != unexpiredById.end()) {
+ i->second->setExpiryPolicy(expiredPolicy); // hasExpired() == true;
+ unexpiredByMessage.erase(i->second);
+ unexpiredById.erase(i);
+ }
+}
+
+boost::optional<uint64_t> ExpiryPolicy::getId(broker::Message& m) {
+ MessageIdMap::iterator i = unexpiredByMessage.find(&m);
+ return i == unexpiredByMessage.end() ? boost::optional<uint64_t>() : i->second;
+}
+
+bool ExpiryPolicy::Expired::hasExpired(broker::Message&) { return true; }
+void ExpiryPolicy::Expired::willExpire(broker::Message&) { }
+
+}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/ExpiryPolicy.h b/cpp/src/qpid/cluster/ExpiryPolicy.h
new file mode 100644
index 0000000000..bdbe3a61dc
--- /dev/null
+++ b/cpp/src/qpid/cluster/ExpiryPolicy.h
@@ -0,0 +1,89 @@
+#ifndef QPID_CLUSTER_EXPIRYPOLICY_H
+#define QPID_CLUSTER_EXPIRYPOLICY_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/cluster/types.h"
+#include "qpid/broker/ExpiryPolicy.h"
+#include "qpid/sys/Mutex.h"
+#include <boost/function.hpp>
+#include <boost/intrusive_ptr.hpp>
+#include <boost/optional.hpp>
+#include <map>
+
+namespace qpid {
+
+namespace broker {
+class Message;
+}
+
+namespace sys {
+class Timer;
+}
+
+namespace cluster {
+class Multicaster;
+
+/**
+ * Cluster expiry policy
+ */
+class ExpiryPolicy : public broker::ExpiryPolicy
+{
+ public:
+ ExpiryPolicy(Multicaster&, const MemberId&, sys::Timer&);
+
+ void willExpire(broker::Message&);
+ bool hasExpired(broker::Message&);
+ void forget(broker::Message&);
+
+ // Send expiration notice to cluster.
+ void sendExpire(uint64_t);
+
+ // Cluster delivers expiry notice.
+ void deliverExpire(uint64_t);
+
+ void setId(uint64_t id) { expiryId = id; }
+ uint64_t getId() const { return expiryId; }
+
+ boost::optional<uint64_t> getId(broker::Message&);
+
+ private:
+ typedef std::map<broker::Message*, uint64_t> MessageIdMap;
+ typedef std::map<uint64_t, broker::Message*> IdMessageMap;
+
+ struct Expired : public broker::ExpiryPolicy {
+ bool hasExpired(broker::Message&);
+ void willExpire(broker::Message&);
+ };
+
+ MessageIdMap unexpiredByMessage;
+ IdMessageMap unexpiredById;
+ uint64_t expiryId;
+ boost::intrusive_ptr<Expired> expiredPolicy;
+ Multicaster& mcast;
+ MemberId memberId;
+ sys::Timer& timer;
+};
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_EXPIRYPOLICY_H*/
diff --git a/cpp/src/qpid/cluster/FailoverExchange.cpp b/cpp/src/qpid/cluster/FailoverExchange.cpp
new file mode 100644
index 0000000000..e01c41494b
--- /dev/null
+++ b/cpp/src/qpid/cluster/FailoverExchange.cpp
@@ -0,0 +1,99 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/cluster/FailoverExchange.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/DeliverableMessage.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/framing/MessageProperties.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/AMQHeaderBody.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/log/Statement.h"
+#include "qpid/framing/Array.h"
+#include <boost/bind.hpp>
+#include <algorithm>
+
+namespace qpid {
+namespace cluster {
+using namespace std;
+
+using namespace broker;
+using namespace framing;
+
+const string FailoverExchange::TYPE_NAME("amq.failover");
+
+FailoverExchange::FailoverExchange(management::Manageable* parent) : Exchange(TYPE_NAME, parent) {
+ if (mgmtExchange != 0)
+ mgmtExchange->set_type(TYPE_NAME);
+}
+
+
+void FailoverExchange::setUrls(const vector<Url>& u) {
+ Lock l(lock);
+ urls=u;
+ if (urls.empty()) return;
+ std::for_each(queues.begin(), queues.end(),
+ boost::bind(&FailoverExchange::sendUpdate, this, _1));
+}
+
+string FailoverExchange::getType() const { return TYPE_NAME; }
+
+bool FailoverExchange::bind(Queue::shared_ptr queue, const string&, const framing::FieldTable*) {
+ Lock l(lock);
+ sendUpdate(queue);
+ return queues.insert(queue).second;
+}
+
+bool FailoverExchange::unbind(Queue::shared_ptr queue, const string&, const framing::FieldTable*) {
+ Lock l(lock);
+ return queues.erase(queue);
+}
+
+bool FailoverExchange::isBound(Queue::shared_ptr queue, const string* const, const framing::FieldTable*) {
+ Lock l(lock);
+ return queues.find(queue) != queues.end();
+}
+
+void FailoverExchange::route(Deliverable&, const string& , const framing::FieldTable* ) {
+ QPID_LOG(warning, "Message received by exchange " << TYPE_NAME << " ignoring");
+}
+
+void FailoverExchange::sendUpdate(const Queue::shared_ptr& queue) {
+ // Called with lock held.
+ if (urls.empty()) return;
+ framing::Array array(0x95);
+ for (Urls::const_iterator i = urls.begin(); i != urls.end(); ++i)
+ array.add(boost::shared_ptr<Str16Value>(new Str16Value(i->str())));
+ const ProtocolVersion v;
+ boost::intrusive_ptr<Message> msg(new Message);
+ AMQFrame command(MessageTransferBody(v, TYPE_NAME, 1, 0));
+ command.setLastSegment(false);
+ msg->getFrames().append(command);
+ AMQHeaderBody header;
+ header.get<MessageProperties>(true)->setContentLength(0);
+ header.get<MessageProperties>(true)->getApplicationHeaders().setArray(TYPE_NAME, array);
+ AMQFrame headerFrame(header);
+ headerFrame.setFirstSegment(false);
+ msg->getFrames().append(headerFrame);
+ DeliverableMessage(msg).deliverTo(queue);
+}
+
+}} // namespace cluster
diff --git a/cpp/src/qpid/cluster/FailoverExchange.h b/cpp/src/qpid/cluster/FailoverExchange.h
new file mode 100644
index 0000000000..738cd2a602
--- /dev/null
+++ b/cpp/src/qpid/cluster/FailoverExchange.h
@@ -0,0 +1,68 @@
+#ifndef QPID_CLUSTER_FAILOVEREXCHANGE_H
+#define QPID_CLUSTER_FAILOVEREXCHANGE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/broker/Exchange.h"
+#include "qpid/broker/DeliverableMessage.h"
+#include "qpid/Url.h"
+
+#include <vector>
+#include <set>
+
+namespace qpid {
+namespace cluster {
+
+/**
+ * Failover exchange provides failover host list, as specified in AMQP 0-10.
+ */
+class FailoverExchange : public broker::Exchange
+{
+ public:
+ static const std::string TYPE_NAME;
+
+ FailoverExchange(management::Manageable* parent);
+
+ void setUrls(const std::vector<Url>&);
+
+ // Exchange overrides
+ std::string getType() const;
+ bool bind(broker::Queue::shared_ptr queue, const std::string& routingKey, const framing::FieldTable* args);
+ bool unbind(broker::Queue::shared_ptr queue, const std::string& routingKey, const framing::FieldTable* args);
+ bool isBound(broker::Queue::shared_ptr queue, const std::string* const routingKey, const framing::FieldTable* const args);
+ void route(broker::Deliverable& msg, const std::string& routingKey, const framing::FieldTable* args);
+
+ private:
+ void sendUpdate(const broker::Queue::shared_ptr&);
+
+ typedef sys::Mutex::ScopedLock Lock;
+ typedef std::vector<Url> Urls;
+ typedef std::set<broker::Queue::shared_ptr> Queues;
+
+ sys::Mutex lock;
+ Urls urls;
+ Queues queues;
+
+};
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_FAILOVEREXCHANGE_H*/
diff --git a/cpp/src/qpid/cluster/InitialStatusMap.cpp b/cpp/src/qpid/cluster/InitialStatusMap.cpp
new file mode 100644
index 0000000000..59338f89d4
--- /dev/null
+++ b/cpp/src/qpid/cluster/InitialStatusMap.cpp
@@ -0,0 +1,197 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "InitialStatusMap.h"
+#include "StoreStatus.h"
+#include <algorithm>
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace cluster {
+
+using namespace std;
+using namespace boost;
+using namespace framing::cluster;
+using namespace framing;
+
+InitialStatusMap::InitialStatusMap(const MemberId& self_, size_t size_)
+ : self(self_), completed(), resendNeeded(), size(size_)
+{}
+
+void InitialStatusMap::configChange(const MemberSet& members) {
+ resendNeeded = false;
+ bool wasComplete = isComplete();
+ if (firstConfig.empty()) firstConfig = members;
+ MemberSet::const_iterator i = members.begin();
+ Map::iterator j = map.begin();
+ while (i != members.end() || j != map.end()) {
+ if (i == members.end()) { // j not in members, member left
+ Map::iterator k = j++;
+ map.erase(k);
+ }
+ else if (j == map.end()) { // i not in map, member joined
+ resendNeeded = true;
+ map[*i] = optional<Status>();
+ ++i;
+ }
+ else if (*i < j->first) { // i not in map, member joined
+ resendNeeded = true;
+ map[*i] = optional<Status>();
+ ++i;
+ }
+ else if (*i > j->first) { // j not in members, member left
+ Map::iterator k = j++;
+ map.erase(k);
+ }
+ else {
+ i++; j++;
+ }
+ }
+ if (resendNeeded) { // Clear all status
+ for (Map::iterator i = map.begin(); i != map.end(); ++i)
+ i->second = optional<Status>();
+ }
+ completed = isComplete() && !wasComplete; // Set completed on the transition.
+}
+
+void InitialStatusMap::received(const MemberId& m, const Status& s){
+ bool wasComplete = isComplete();
+ map[m] = s;
+ completed = isComplete() && !wasComplete; // Set completed on the transition.
+}
+
+bool InitialStatusMap::notInitialized(const Map::value_type& v) {
+ return !v.second;
+}
+
+bool InitialStatusMap::isComplete() {
+ return !map.empty() && find_if(map.begin(), map.end(), &notInitialized) == map.end()
+ && (map.size() >= size);
+}
+
+bool InitialStatusMap::transitionToComplete() {
+ return completed;
+}
+
+bool InitialStatusMap::isResendNeeded() {
+ bool ret = resendNeeded;
+ resendNeeded = false;
+ return ret;
+}
+
+bool InitialStatusMap::isActive(const Map::value_type& v) {
+ return v.second && v.second->getActive();
+}
+
+bool InitialStatusMap::hasStore(const Map::value_type& v) {
+ return v.second &&
+ (v.second->getStoreState() == STORE_STATE_CLEAN_STORE ||
+ v.second->getStoreState() == STORE_STATE_DIRTY_STORE);
+}
+
+bool InitialStatusMap::isUpdateNeeded() {
+ assert(isComplete());
+ // We need an update if there are any active members.
+ if (find_if(map.begin(), map.end(), &isActive) != map.end()) return true;
+
+ // Otherwise it depends on store status, get my own status:
+ Map::iterator me = map.find(self);
+ assert(me != map.end());
+ assert(me->second);
+ switch (me->second->getStoreState()) {
+ case STORE_STATE_NO_STORE:
+ case STORE_STATE_EMPTY_STORE:
+ // If anybody has a store then we need an update.
+ return find_if(map.begin(), map.end(), &hasStore) != map.end();
+ case STORE_STATE_DIRTY_STORE: return true;
+ case STORE_STATE_CLEAN_STORE: return false; // Use our own store
+ }
+ return false;
+}
+
+MemberSet InitialStatusMap::getElders() {
+ assert(isComplete());
+ MemberSet elders;
+ // Elders are from first config change, active or higher node-id.
+ for (MemberSet::iterator i = firstConfig.begin(); i != firstConfig.end(); ++i) {
+ if (map.find(*i) != map.end() && (map[*i]->getActive() || *i > self))
+ elders.insert(*i);
+ }
+ return elders;
+}
+
+// Get cluster ID from an active member or the youngest newcomer.
+framing::Uuid InitialStatusMap::getClusterId() {
+ assert(isComplete());
+ assert(!map.empty());
+ Map::iterator i = find_if(map.begin(), map.end(), &isActive);
+ if (i != map.end())
+ return i->second->getClusterId(); // An active member
+ else
+ return map.begin()->second->getClusterId(); // Youngest newcomer in node-id order
+}
+
+void checkId(Uuid& expect, const Uuid& actual, const string& msg) {
+ if (!expect) expect = actual;
+ assert(expect);
+ if (expect != actual)
+ throw Exception(msg);
+}
+
+void InitialStatusMap::checkConsistent() {
+ assert(isComplete());
+ int clean = 0;
+ int dirty = 0;
+ int empty = 0;
+ int none = 0;
+ int active = 0;
+ Uuid clusterId;
+ Uuid shutdownId;
+
+ for (Map::iterator i = map.begin(); i != map.end(); ++i) {
+ if (i->second->getActive()) ++active;
+ switch (i->second->getStoreState()) {
+ case STORE_STATE_NO_STORE: ++none; break;
+ case STORE_STATE_EMPTY_STORE: ++empty; break;
+ case STORE_STATE_DIRTY_STORE:
+ ++dirty;
+ checkId(clusterId, i->second->getClusterId(),
+ "Cluster-ID mismatch. Stores belong to different clusters.");
+ break;
+ case STORE_STATE_CLEAN_STORE:
+ ++clean;
+ checkId(clusterId, i->second->getClusterId(),
+ "Cluster-ID mismatch. Stores belong to different clusters.");
+ checkId(shutdownId, i->second->getShutdownId(),
+ "Shutdown-ID mismatch. Stores were not shut down together");
+ break;
+ }
+ }
+ // Can't mix transient and persistent members.
+ if (none && (clean+dirty+empty))
+ throw Exception("Mixing transient and persistent brokers in a cluster");
+ // If there are no active members and there are dirty stores there
+ // must be at least one clean store.
+ if (!active && dirty && !clean)
+ throw Exception("Cannot recover, no clean store");
+}
+
+
+}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/InitialStatusMap.h b/cpp/src/qpid/cluster/InitialStatusMap.h
new file mode 100644
index 0000000000..40fd9ee49d
--- /dev/null
+++ b/cpp/src/qpid/cluster/InitialStatusMap.h
@@ -0,0 +1,75 @@
+#ifndef QPID_CLUSTER_INITIALSTATUSMAP_H
+#define QPID_CLUSTER_INITIALSTATUSMAP_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "MemberSet.h"
+#include <qpid/framing/ClusterInitialStatusBody.h>
+#include <boost/optional.hpp>
+
+namespace qpid {
+namespace cluster {
+
+/**
+ * Track status of cluster members during initialization.
+ */
+class InitialStatusMap
+{
+ public:
+ typedef framing::ClusterInitialStatusBody Status;
+
+ InitialStatusMap(const MemberId& self, size_t size);
+ /** Process a config change. @return true if we need to re-send our status */
+ void configChange(const MemberSet& newConfig);
+ /** @return true if we need to re-send status */
+ bool isResendNeeded();
+
+ /** Process received status */
+ void received(const MemberId&, const Status& is);
+
+ /**@return true if the map is complete. */
+ bool isComplete();
+ /**@return true if the map was completed by the last config change or received. */
+ bool transitionToComplete();
+ /**@pre isComplete(). @return this node's elders */
+ MemberSet getElders();
+ /**@pre isComplete(). @return True if we need an update. */
+ bool isUpdateNeeded();
+ /**@pre isComplete(). @return Cluster-wide cluster ID. */
+ framing::Uuid getClusterId();
+ /**@pre isComplete(). @throw Exception if there are any inconsistencies. */
+ void checkConsistent();
+
+ private:
+ typedef std::map<MemberId, boost::optional<Status> > Map;
+ static bool notInitialized(const Map::value_type&);
+ static bool isActive(const Map::value_type&);
+ static bool hasStore(const Map::value_type&);
+ Map map;
+ MemberSet firstConfig;
+ MemberId self;
+ bool completed, resendNeeded;
+ size_t size;
+};
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_INITIALSTATUSMAP_H*/
diff --git a/cpp/src/qpid/cluster/LockedConnectionMap.h b/cpp/src/qpid/cluster/LockedConnectionMap.h
new file mode 100644
index 0000000000..ac744d4f94
--- /dev/null
+++ b/cpp/src/qpid/cluster/LockedConnectionMap.h
@@ -0,0 +1,65 @@
+#ifndef QPID_CLUSTER_LOCKEDCONNECTIONMAP_H
+#define QPID_CLUSTER_LOCKEDCONNECTIONMAP_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/cluster/types.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/cluster/Connection.h"
+
+namespace qpid {
+namespace cluster {
+
+/**
+ * Thread safe map of connections.
+ */
+class LockedConnectionMap
+{
+ public:
+ void insert(const ConnectionPtr& c) {
+ sys::Mutex::ScopedLock l(lock);
+ assert(map.find(c->getId()) == map.end());
+ map[c->getId()] = c;
+ }
+
+ ConnectionPtr getErase(const ConnectionId& c) {
+ sys::Mutex::ScopedLock l(lock);
+ Map::iterator i = map.find(c);
+ if (i != map.end()) {
+ ConnectionPtr cp = i->second;
+ map.erase(i);
+ return cp;
+ }
+ else
+ return 0;
+ }
+
+ void clear() { sys::Mutex::ScopedLock l(lock); map.clear(); }
+
+ private:
+ typedef std::map<ConnectionId, ConnectionPtr> Map;
+ mutable sys::Mutex lock;
+ Map map;
+};
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_LOCKEDCONNECTIONMAP_H*/
diff --git a/cpp/src/qpid/cluster/McastFrameHandler.h b/cpp/src/qpid/cluster/McastFrameHandler.h
new file mode 100644
index 0000000000..17e4c2e9f0
--- /dev/null
+++ b/cpp/src/qpid/cluster/McastFrameHandler.h
@@ -0,0 +1,46 @@
+#ifndef QPID_CLUSTER_MCASTFRAMEHANDLER_H
+#define QPID_CLUSTER_MCASTFRAMEHANDLER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/cluster/types.h"
+#include "qpid/cluster/Multicaster.h"
+#include "qpid/framing/FrameHandler.h"
+
+namespace qpid {
+namespace cluster {
+
+/**
+ * A frame handler that multicasts frames as CONTROL events.
+ */
+class McastFrameHandler : public framing::FrameHandler
+{
+ public:
+ McastFrameHandler(Multicaster& m, const ConnectionId& cid) : mcast(m), connection(cid) {}
+ void handle(framing::AMQFrame& frame) { mcast.mcastControl(frame, connection); }
+ private:
+ Multicaster& mcast;
+ ConnectionId connection;
+};
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_MCASTFRAMEHANDLER_H*/
diff --git a/cpp/src/qpid/cluster/MemberSet.cpp b/cpp/src/qpid/cluster/MemberSet.cpp
new file mode 100644
index 0000000000..5dc148609f
--- /dev/null
+++ b/cpp/src/qpid/cluster/MemberSet.cpp
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "MemberSet.h"
+#include <ostream>
+#include <algorithm>
+
+namespace qpid {
+namespace cluster {
+
+MemberSet decodeMemberSet(const std::string& s) {
+ MemberSet set;
+ for (std::string::const_iterator i = s.begin(); i < s.end(); i += 8) {
+ assert(size_t(i-s.begin())+8 <= s.size());
+ set.insert(MemberId(std::string(i, i+8)));
+ }
+ return set;
+}
+
+MemberSet intersection(const MemberSet& a, const MemberSet& b)
+{
+ MemberSet intersection;
+ std::set_intersection(a.begin(), a.end(),
+ b.begin(), b.end(),
+ std::inserter(intersection, intersection.begin()));
+ return intersection;
+
+}
+
+std::ostream& operator<<(std::ostream& o, const MemberSet& ms) {
+ copy(ms.begin(), ms.end(), std::ostream_iterator<MemberId>(o, " "));
+ return o;
+}
+
+}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/MemberSet.h b/cpp/src/qpid/cluster/MemberSet.h
new file mode 100644
index 0000000000..df3df7c319
--- /dev/null
+++ b/cpp/src/qpid/cluster/MemberSet.h
@@ -0,0 +1,43 @@
+#ifndef QPID_CLUSTER_MEMBERSET_H
+#define QPID_CLUSTER_MEMBERSET_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "types.h"
+#include <set>
+#include <iosfwd>
+
+namespace qpid {
+namespace cluster {
+
+typedef std::set<MemberId> MemberSet;
+
+MemberSet decodeMemberSet(const std::string&);
+
+MemberSet intersection(const MemberSet& a, const MemberSet& b);
+
+std::ostream& operator<<(std::ostream& o, const MemberSet& ms);
+
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_MEMBERSET_H*/
diff --git a/cpp/src/qpid/cluster/Multicaster.cpp b/cpp/src/qpid/cluster/Multicaster.cpp
new file mode 100644
index 0000000000..229d7edb1e
--- /dev/null
+++ b/cpp/src/qpid/cluster/Multicaster.cpp
@@ -0,0 +1,103 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/cluster/Multicaster.h"
+#include "qpid/cluster/Cpg.h"
+#include "qpid/log/Statement.h"
+#include "qpid/framing/AMQBody.h"
+#include "qpid/framing/AMQFrame.h"
+
+namespace qpid {
+namespace cluster {
+
+Multicaster::Multicaster(Cpg& cpg_,
+ const boost::shared_ptr<sys::Poller>& poller,
+ boost::function<void()> onError_) :
+ onError(onError_), cpg(cpg_),
+ queue(boost::bind(&Multicaster::sendMcast, this, _1), poller),
+ ready(false)
+{
+ queue.start();
+}
+
+void Multicaster::mcastControl(const framing::AMQBody& body, const ConnectionId& id) {
+ mcast(Event::control(body, id));
+}
+
+void Multicaster::mcastControl(const framing::AMQFrame& frame, const ConnectionId& id) {
+ mcast(Event::control(frame, id));
+}
+
+void Multicaster::mcastBuffer(const char* data, size_t size, const ConnectionId& id) {
+ Event e(DATA, id, size);
+ memcpy(e.getData(), data, size);
+ mcast(e);
+}
+
+void Multicaster::mcast(const Event& e) {
+ {
+ sys::Mutex::ScopedLock l(lock);
+ if (!ready) {
+ if (e.isConnection()) holdingQueue.push_back(e);
+ else {
+ iovec iov = e.toIovec();
+ // FIXME aconway 2009-11-23: configurable retry --cluster-retry
+ if (!cpg.mcast(&iov, 1))
+ throw Exception("CPG flow control error during initialization");
+ QPID_LOG(trace, "MCAST (direct) " << e);
+ }
+ return;
+ }
+ }
+ QPID_LOG(trace, "MCAST " << e);
+ queue.push(e);
+}
+
+
+Multicaster::PollableEventQueue::Batch::const_iterator Multicaster::sendMcast(const PollableEventQueue::Batch& values) {
+ try {
+ PollableEventQueue::Batch::const_iterator i = values.begin();
+ while( i != values.end()) {
+ iovec iov = i->toIovec();
+ if (!cpg.mcast(&iov, 1)) {
+ // cpg didn't send because of CPG flow control.
+ break;
+ }
+ ++i;
+ }
+ return i;
+ }
+ catch (const std::exception& e) {
+ QPID_LOG(critical, "Multicast error: " << e.what());
+ queue.stop();
+ onError();
+ return values.end();
+ }
+}
+
+void Multicaster::setReady() {
+ sys::Mutex::ScopedLock l(lock);
+ ready = true;
+ std::for_each(holdingQueue.begin(), holdingQueue.end(), boost::bind(&Multicaster::mcast, this, _1));
+ holdingQueue.clear();
+}
+
+}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/Multicaster.h b/cpp/src/qpid/cluster/Multicaster.h
new file mode 100644
index 0000000000..2db84a9ce0
--- /dev/null
+++ b/cpp/src/qpid/cluster/Multicaster.h
@@ -0,0 +1,87 @@
+#ifndef QPID_CLUSTER_MULTICASTER_H
+#define QPID_CLUSTER_MULTICASTER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/cluster/types.h"
+#include "qpid/cluster/Event.h"
+#include "qpid/sys/PollableQueue.h"
+#include "qpid/sys/Mutex.h"
+#include <boost/shared_ptr.hpp>
+#include <deque>
+
+namespace qpid {
+
+namespace sys {
+class Poller;
+}
+
+namespace cluster {
+
+class Cpg;
+
+/**
+ * Multicast to the cluster. Shared, thread safe object.
+ *
+ * Runs in two modes;
+ *
+ * initializing: Hold connection mcast events. Multicast cluster
+ * events directly in the calling thread. This mode is used before
+ * joining the cluster where the poller may not yet be active and we
+ * want to hold any connection traffic till we join.
+ *
+ * ready: normal operation. Queues all mcasts on a pollable queue,
+ * multicasts connection and cluster events.
+ */
+class Multicaster
+{
+ public:
+ /** Starts in initializing mode. */
+ Multicaster(Cpg& cpg_,
+ const boost::shared_ptr<sys::Poller>&,
+ boost::function<void()> onError
+ );
+ void mcastControl(const framing::AMQBody& controlBody, const ConnectionId&);
+ void mcastControl(const framing::AMQFrame& controlFrame, const ConnectionId&);
+ void mcastBuffer(const char*, size_t, const ConnectionId&);
+ void mcast(const Event& e);
+
+ /** Switch to ready mode. */
+ void setReady();
+
+ private:
+ typedef sys::PollableQueue<Event> PollableEventQueue;
+ typedef std::deque<Event> PlainEventQueue;
+
+ PollableEventQueue::Batch::const_iterator sendMcast(const PollableEventQueue::Batch& );
+
+ sys::Mutex lock;
+ boost::function<void()> onError;
+ Cpg& cpg;
+ PollableEventQueue queue;
+ bool ready;
+ PlainEventQueue holdingQueue;
+ std::vector<struct ::iovec> ioVector;
+};
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_MULTICASTER_H*/
diff --git a/cpp/src/qpid/cluster/NoOpConnectionOutputHandler.h b/cpp/src/qpid/cluster/NoOpConnectionOutputHandler.h
new file mode 100644
index 0000000000..566a82476e
--- /dev/null
+++ b/cpp/src/qpid/cluster/NoOpConnectionOutputHandler.h
@@ -0,0 +1,47 @@
+#ifndef QPID_CLUSTER_NOOPCONNECTIONOUTPUTHANDLER_H
+#define QPID_CLUSTER_NOOPCONNECTIONOUTPUTHANDLER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <qpid/sys/ConnectionOutputHandler.h>
+
+namespace qpid {
+
+namespace framing { class AMQFrame; }
+
+namespace cluster {
+
+/**
+ * Output handler shadow connections, simply discards frames.
+ */
+class NoOpConnectionOutputHandler : public sys::ConnectionOutputHandler
+{
+ public:
+ virtual void send(framing::AMQFrame&) {}
+ virtual void close() {}
+ virtual void abort() {}
+ virtual void activateOutput() {}
+ virtual void giveReadCredit(int32_t) {}
+};
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_NOOPCONNECTIONOUTPUTHANDLER_H*/
diff --git a/cpp/src/qpid/cluster/Numbering.h b/cpp/src/qpid/cluster/Numbering.h
new file mode 100644
index 0000000000..2d2d931384
--- /dev/null
+++ b/cpp/src/qpid/cluster/Numbering.h
@@ -0,0 +1,70 @@
+#ifndef QPID_CLUSTER_NUMBERING_H
+#define QPID_CLUSTER_NUMBERING_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <map>
+#include <vector>
+
+namespace qpid {
+namespace cluster {
+
+/**
+ * A set of numbered T, with two way mapping number->T T->number
+ * Used to construct numberings of objects by code sending and receiving updates.
+ */
+template <class T> class Numbering
+{
+ public:
+ size_t size() const { return byNumber.size(); }
+
+ size_t add(const T& t) {
+ size_t n = (*this)[t]; // Already in the set?
+ if (n == size()) {
+ byObject[t] = n;
+ byNumber.push_back(t);
+ }
+ return n;
+ }
+
+ void clear() { byObject.clear(); byNumber.clear(); }
+
+ /**@return object at index n or T() if n > size() */
+ T operator[](size_t n) const { return(n < size()) ? byNumber[n] : T(); }
+
+ /**@return index of t or size() if t is not in the map */
+ size_t operator[](const T& t) const {
+ typename Map::const_iterator i = byObject.find(t);
+ return (i != byObject.end()) ? i->second : size();
+ }
+
+ bool contains(const T& t) const { return (*this)[t] == size(); }
+
+ private:
+ typedef std::map<T, size_t> Map;
+ Map byObject;
+ std::vector<T> byNumber;
+};
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_NUMBERING_H*/
diff --git a/cpp/src/qpid/cluster/OutputInterceptor.cpp b/cpp/src/qpid/cluster/OutputInterceptor.cpp
new file mode 100644
index 0000000000..cb75fe5561
--- /dev/null
+++ b/cpp/src/qpid/cluster/OutputInterceptor.cpp
@@ -0,0 +1,116 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/cluster/OutputInterceptor.h"
+#include "qpid/cluster/Connection.h"
+#include "qpid/cluster/Cluster.h"
+#include "qpid/framing/ClusterConnectionDeliverDoOutputBody.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/log/Statement.h"
+#include <boost/current_function.hpp>
+
+
+namespace qpid {
+namespace cluster {
+
+using namespace framing;
+using namespace std;
+
+NoOpConnectionOutputHandler OutputInterceptor::discardHandler;
+
+OutputInterceptor::OutputInterceptor(Connection& p, sys::ConnectionOutputHandler& h)
+ : parent(p), closing(false), next(&h), sendMax(1), sent(0), sentDoOutput(false)
+{}
+
+void OutputInterceptor::send(framing::AMQFrame& f) {
+ sys::Mutex::ScopedLock l(lock);
+ next->send(f);
+}
+
+void OutputInterceptor::activateOutput() {
+ if (parent.isCatchUp()) {
+ sys::Mutex::ScopedLock l(lock);
+ next->activateOutput();
+ }
+ else
+ sendDoOutput(sendMax);
+}
+
+void OutputInterceptor::abort() {
+ sys::Mutex::ScopedLock l(lock);
+ if (parent.isLocal()) {
+ next->abort();
+ }
+}
+
+void OutputInterceptor::giveReadCredit(int32_t credit) {
+ sys::Mutex::ScopedLock l(lock);
+ next->giveReadCredit(credit);
+}
+
+// Called in write thread when the IO layer has no more data to write.
+// We do nothing in the write thread, we run doOutput only on delivery
+// of doOutput requests.
+bool OutputInterceptor::doOutput() { return false; }
+
+// Send output up to limit, calculate new limit.
+void OutputInterceptor::deliverDoOutput(uint32_t limit) {
+ sentDoOutput = false;
+ sendMax = limit;
+ size_t newLimit = limit;
+ if (parent.isLocal()) {
+ size_t buffered = getBuffered();
+ if (buffered == 0 && sent == sendMax) // Could have sent more, increase the limit.
+ newLimit = sendMax*2;
+ else if (buffered > 0 && sent > 1) // Data left unsent, reduce the limit.
+ newLimit = sent-1;
+ }
+ sent = 0;
+ while (sent < limit && parent.getBrokerConnection().doOutput())
+ ++sent;
+ if (sent == limit) sendDoOutput(newLimit);
+}
+
+void OutputInterceptor::sendDoOutput(size_t newLimit) {
+ if (parent.isLocal() && !sentDoOutput && !closing) {
+ sentDoOutput = true;
+ parent.getCluster().getMulticast().mcastControl(
+ ClusterConnectionDeliverDoOutputBody(ProtocolVersion(), newLimit),
+ parent.getId());
+ }
+}
+
+void OutputInterceptor::closeOutput() {
+ sys::Mutex::ScopedLock l(lock);
+ closing = true;
+ next = &discardHandler;
+}
+
+void OutputInterceptor::close() {
+ sys::Mutex::ScopedLock l(lock);
+ next->close();
+}
+
+size_t OutputInterceptor::getBuffered() const {
+ sys::Mutex::ScopedLock l(lock);
+ return next->getBuffered();
+}
+
+}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/OutputInterceptor.h b/cpp/src/qpid/cluster/OutputInterceptor.h
new file mode 100644
index 0000000000..65bd82a4fc
--- /dev/null
+++ b/cpp/src/qpid/cluster/OutputInterceptor.h
@@ -0,0 +1,79 @@
+#ifndef QPID_CLUSTER_OUTPUTINTERCEPTOR_H
+#define QPID_CLUSTER_OUTPUTINTERCEPTOR_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/cluster/NoOpConnectionOutputHandler.h"
+#include "qpid/sys/ConnectionOutputHandler.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/broker/ConnectionFactory.h"
+#include <boost/function.hpp>
+
+namespace qpid {
+namespace framing { class AMQFrame; }
+namespace cluster {
+
+class Connection;
+
+/**
+ * Interceptor for connection OutputHandler, manages outgoing message replication.
+ */
+class OutputInterceptor : public sys::ConnectionOutputHandler {
+ public:
+ OutputInterceptor(cluster::Connection& p, sys::ConnectionOutputHandler& h);
+
+ // sys::ConnectionOutputHandler functions
+ void send(framing::AMQFrame& f);
+ void abort();
+ void activateOutput();
+ void giveReadCredit(int32_t);
+ void close();
+ size_t getBuffered() const;
+
+ // Delivery point for doOutput requests.
+ void deliverDoOutput(uint32_t limit);
+ // Intercept doOutput requests on Connection.
+ bool doOutput();
+
+ void closeOutput();
+
+ uint32_t getSendMax() const { return sendMax; }
+ void setSendMax(uint32_t sendMax_) { sendMax=sendMax_; }
+
+ cluster::Connection& parent;
+
+ private:
+ typedef sys::Mutex::ScopedLock Locker;
+
+ void sendDoOutput(size_t newLimit);
+
+ mutable sys::Mutex lock;
+ bool closing;
+ sys::ConnectionOutputHandler* next;
+ static NoOpConnectionOutputHandler discardHandler;
+ uint32_t sendMax, sent;
+ bool sentDoOutput;
+};
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_OUTPUTINTERCEPTOR_H*/
diff --git a/cpp/src/qpid/cluster/PollableCondition.cpp b/cpp/src/qpid/cluster/PollableCondition.cpp
deleted file mode 100644
index eecf95ff8d..0000000000
--- a/cpp/src/qpid/cluster/PollableCondition.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-#ifndef QPID_SYS_LINUX_POLLABLECONDITION_CPP
-#define QPID_SYS_LINUX_POLLABLECONDITION_CPP
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-// FIXME aconway 2008-08-11: this could be of more general interest,
-// move to common lib.
-//
-
-#include "qpid/sys/posix/PrivatePosix.h"
-#include "qpid/cluster/PollableCondition.h"
-#include "qpid/Exception.h"
-
-#include <unistd.h>
-#include <fcntl.h>
-
-namespace qpid {
-namespace cluster {
-
-PollableCondition::PollableCondition() : IOHandle(new sys::IOHandlePrivate) {
- int fds[2];
- if (::pipe(fds) == -1)
- throw ErrnoException(QPID_MSG("Can't create PollableCondition"));
- impl->fd = fds[0];
- writeFd = fds[1];
- if (::fcntl(impl->fd, F_SETFL, O_NONBLOCK) == -1)
- throw ErrnoException(QPID_MSG("Can't create PollableCondition"));
- if (::fcntl(writeFd, F_SETFL, O_NONBLOCK) == -1)
- throw ErrnoException(QPID_MSG("Can't create PollableCondition"));
-}
-
-bool PollableCondition::clear() {
- char buf[256];
- ssize_t n;
- bool wasSet = false;
- while ((n = ::read(impl->fd, buf, sizeof(buf))) > 0)
- wasSet = true;
- if (n == -1 && errno != EAGAIN) throw ErrnoException(QPID_MSG("Error clearing PollableCondition"));
- return wasSet;
-}
-
-void PollableCondition::set() {
- static const char dummy=0;
- ssize_t n = ::write(writeFd, &dummy, 1);
- if (n == -1 && errno != EAGAIN) throw ErrnoException("Error setting PollableCondition");
-}
-
-
-#if 0
-// FIXME aconway 2008-08-12: More efficient Linux implementation using
-// eventfd system call. Do a configure.ac test to enable this when
-// eventfd is available.
-
-#include <sys/eventfd.h>
-
-namespace qpid {
-namespace cluster {
-
-PollableCondition::PollableCondition() : IOHandle(new sys::IOHandlePrivate) {
- impl->fd = ::eventfd(0, 0);
- if (impl->fd < 0) throw ErrnoException("conditionfd() failed");
-}
-
-bool PollableCondition::clear() {
- char buf[8];
- ssize_t n = ::read(impl->fd, buf, 8);
- if (n != 8) throw ErrnoException("read failed on conditionfd");
- return *reinterpret_cast<uint64_t*>(buf);
-}
-
-void PollableCondition::set() {
- static const uint64_t value=1;
- ssize_t n = ::write(impl->fd, reinterpret_cast<const void*>(&value), 8);
- if (n != 8) throw ErrnoException("write failed on conditionfd");
-}
-
-#endif
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_SYS_LINUX_POLLABLECONDITION_CPP*/
diff --git a/cpp/src/qpid/cluster/PollableCondition.h b/cpp/src/qpid/cluster/PollableCondition.h
deleted file mode 100644
index 6bfca6cabe..0000000000
--- a/cpp/src/qpid/cluster/PollableCondition.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef QPID_SYS_POLLABLECONDITION_H
-#define QPID_SYS_POLLABLECONDITION_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/sys/IOHandle.h"
-
-// FIXME aconway 2008-08-11: this could be of more general interest,
-// move to sys namespace in common lib.
-//
-
-namespace qpid {
-namespace cluster {
-
-/**
- * A pollable condition to integrate in-process conditions with IO
- * conditions in a polling loop.
- *
- * Setting the condition makes it readable for a poller.
- *
- * Writable/disconnected conditions are undefined and should not be
- * polled for.
- */
-class PollableCondition : public sys::IOHandle {
- public:
- PollableCondition();
-
- /** Set the condition, triggers readable in a poller. */
- void set();
-
- /** Get the current state of the condition, then clear it.
- *@return The state of the condition before it was cleared.
- */
- bool clear();
-
- private:
- int writeFd;
-};
-}} // namespace qpid::cluster
-
-#endif /*!QPID_SYS_POLLABLECONDITION_H*/
diff --git a/cpp/src/qpid/cluster/PollableQueue.h b/cpp/src/qpid/cluster/PollableQueue.h
index 0bba2ba790..65f615d8b6 100644
--- a/cpp/src/qpid/cluster/PollableQueue.h
+++ b/cpp/src/qpid/cluster/PollableQueue.h
@@ -22,78 +22,53 @@
*
*/
-#include "qpid/cluster/PollableCondition.h"
-#include "qpid/sys/Dispatcher.h"
-#include "qpid/sys/Mutex.h"
-#include <boost/function.hpp>
-#include <boost/bind.hpp>
-#include <deque>
+#include "qpid/sys/PollableQueue.h"
+#include <qpid/log/Statement.h>
namespace qpid {
-
-namespace sys { class Poller; }
-
namespace cluster {
-// FIXME aconway 2008-08-11: this could be of more general interest,
-// move to common lib.
-
/**
- * A queue that can be polled by sys::Poller. Any thread can push to
- * the queue, on wakeup the poller thread processes all items on the
- * queue by passing them to a callback in a batch.
+ * More convenient version of PollableQueue that handles iterating
+ * over the batch and error handling.
*/
-template <class T>
-class PollableQueue {
- typedef std::deque<T> Queue;
-
+template <class T> class PollableQueue : public sys::PollableQueue<T> {
public:
- typedef typename Queue::iterator iterator;
-
- /** Callback to process a range of items. */
- typedef boost::function<void (const iterator&, const iterator&)> Callback;
-
- /** When the queue is selected by the poller, values are passed to callback cb. */
- explicit PollableQueue(const Callback& cb);
-
- /** Push a value onto the queue. Thread safe */
- void push(const T& t) { ScopedLock l(lock); queue.push_back(t); condition.set(); }
+ typedef boost::function<void (const T&)> Callback;
+ typedef boost::function<void()> ErrorCallback;
+
+ PollableQueue(Callback f, ErrorCallback err, const std::string& msg,
+ const boost::shared_ptr<sys::Poller>& poller)
+ : sys::PollableQueue<T>(boost::bind(&PollableQueue<T>::handleBatch, this, _1),
+ poller),
+ callback(f), error(err), message(msg)
+ {}
+
+ typename sys::PollableQueue<T>::Batch::const_iterator
+ handleBatch(const typename sys::PollableQueue<T>::Batch& values) {
+ try {
+ typename sys::PollableQueue<T>::Batch::const_iterator i = values.begin();
+ while (i != values.end() && !this->isStopped()) {
+ callback(*i);
+ ++i;
+ }
+ return i;
+ }
+ catch (const std::exception& e) {
+ QPID_LOG(error, message << ": " << e.what());
+ this->stop();
+ error();
+ return values.end();
+ }
+ }
- /** Start polling. */
- void start(const boost::shared_ptr<sys::Poller>& poller) { handle.startWatch(poller); }
-
- /** Stop polling. */
- void stop() { handle.stopWatch(); }
-
private:
- typedef sys::Mutex::ScopedLock ScopedLock;
- typedef sys::Mutex::ScopedUnlock ScopedUnlock;
-
- void dispatch(sys::DispatchHandle&);
-
- sys::Mutex lock;
Callback callback;
- PollableCondition condition;
- sys::DispatchHandle handle;
- Queue queue;
- Queue batch;
+ ErrorCallback error;
+ std::string message;
};
-template <class T> PollableQueue<T>::PollableQueue(const Callback& cb) // FIXME aconway 2008-08-12:
- : callback(cb),
- handle(condition, boost::bind(&PollableQueue<T>::dispatch, this, _1), 0, 0)
-{}
-
-template <class T> void PollableQueue<T>::dispatch(sys::DispatchHandle& h) {
- ScopedLock l(lock); // Lock for concurrent push()
- batch.clear();
- batch.swap(queue);
- condition.clear();
- ScopedUnlock u(lock);
- callback(batch.begin(), batch.end()); // Process the batch outside the lock.
- h.rewatch();
-}
-
+
}} // namespace qpid::cluster
#endif /*!QPID_CLUSTER_POLLABLEQUEUE_H*/
diff --git a/cpp/src/qpid/cluster/PollerDispatch.cpp b/cpp/src/qpid/cluster/PollerDispatch.cpp
new file mode 100644
index 0000000000..a839ef863b
--- /dev/null
+++ b/cpp/src/qpid/cluster/PollerDispatch.cpp
@@ -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 "qpid/cluster/PollerDispatch.h"
+
+#include "qpid/log/Statement.h"
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace cluster {
+
+PollerDispatch::PollerDispatch(Cpg& c, boost::shared_ptr<sys::Poller> p,
+ boost::function<void()> e)
+ : cpg(c), poller(p), onError(e),
+ dispatchHandle(cpg,
+ boost::bind(&PollerDispatch::dispatch, this, _1), // read
+ 0, // write
+ boost::bind(&PollerDispatch::disconnect, this, _1) // disconnect
+ ),
+ started(false)
+{}
+
+PollerDispatch::~PollerDispatch() {
+ if (started)
+ dispatchHandle.stopWatch();
+}
+
+void PollerDispatch::start() {
+ dispatchHandle.startWatch(poller);
+ started = true;
+}
+
+// Entry point: called by IO to dispatch CPG events.
+void PollerDispatch::dispatch(sys::DispatchHandle& h) {
+ try {
+ cpg.dispatchAll();
+ h.rewatch();
+ } catch (const std::exception& e) {
+ QPID_LOG(critical, "Error in cluster dispatch: " << e.what());
+ onError();
+ }
+}
+
+// Entry point: called if disconnected from CPG.
+void PollerDispatch::disconnect(sys::DispatchHandle& ) {
+ QPID_LOG(critical, "Disconnected from cluster");
+ onError();
+}
+
+}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/PollerDispatch.h b/cpp/src/qpid/cluster/PollerDispatch.h
new file mode 100644
index 0000000000..63801e0de9
--- /dev/null
+++ b/cpp/src/qpid/cluster/PollerDispatch.h
@@ -0,0 +1,60 @@
+#ifndef QPID_CLUSTER_POLLERDISPATCH_H
+#define QPID_CLUSTER_POLLERDISPATCH_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/cluster/Cpg.h"
+#include "qpid/sys/Poller.h"
+#include "qpid/sys/DispatchHandle.h"
+#include <boost/function.hpp>
+
+namespace qpid {
+namespace cluster {
+
+/**
+ * Dispatch CPG events via the poller.
+ */
+class PollerDispatch {
+ public:
+ PollerDispatch(Cpg&, boost::shared_ptr<sys::Poller> poller,
+ boost::function<void()> onError) ;
+
+ ~PollerDispatch();
+
+ void start();
+
+ private:
+ // Poller callbacks
+ void dispatch(sys::DispatchHandle&); // Dispatch CPG events.
+ void disconnect(sys::DispatchHandle&); // CPG was disconnected
+
+ Cpg& cpg;
+ boost::shared_ptr<sys::Poller> poller;
+ boost::function<void()> onError;
+ sys::DispatchHandleRef dispatchHandle;
+ bool started;
+
+
+};
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_POLLERDISPATCH_H*/
diff --git a/cpp/src/qpid/cluster/ProxyInputHandler.h b/cpp/src/qpid/cluster/ProxyInputHandler.h
new file mode 100644
index 0000000000..228f8d092d
--- /dev/null
+++ b/cpp/src/qpid/cluster/ProxyInputHandler.h
@@ -0,0 +1,57 @@
+#ifndef QPID_CLUSTER_PROXYINPUTHANDLER_H
+#define QPID_CLUSTER_PROXYINPUTHANDLER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/ConnectionInputHandler.h"
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+
+namespace framing { class AMQFrame; }
+
+namespace cluster {
+
+/**
+ * Proxies ConnectionInputHandler functions and ensures target.closed()
+ * is called, on deletion if not before.
+ */
+class ProxyInputHandler : public sys::ConnectionInputHandler
+{
+ public:
+ ProxyInputHandler(boost::intrusive_ptr<cluster::Connection> t) : target(t) {}
+ ~ProxyInputHandler() { closed(); }
+
+ void received(framing::AMQFrame& f) { target->received(f); }
+ void closed() { if (target) target->closed(); target = 0; }
+ void idleOut() { target->idleOut(); }
+ void idleIn() { target->idleIn(); }
+ bool doOutput() { return target->doOutput(); }
+ bool hasOutput() { return target->hasOutput(); }
+
+ private:
+ boost::intrusive_ptr<cluster::Connection> target;
+};
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_PROXYINPUTHANDLER_H*/
diff --git a/cpp/src/qpid/cluster/Quorum.h b/cpp/src/qpid/cluster/Quorum.h
new file mode 100644
index 0000000000..bbfa473f94
--- /dev/null
+++ b/cpp/src/qpid/cluster/Quorum.h
@@ -0,0 +1,32 @@
+#ifndef QPID_CLUSTER_QUORUM_H
+#define QPID_CLUSTER_QUORUM_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "config.h"
+
+#if HAVE_LIBCMAN_H
+#include "qpid/cluster/Quorum_cman.h"
+#else
+#include "qpid/cluster/Quorum_null.h"
+#endif
+
+#endif /*!QPID_CLUSTER_QUORUM_H*/
diff --git a/cpp/src/qpid/cluster/Quorum_cman.cpp b/cpp/src/qpid/cluster/Quorum_cman.cpp
new file mode 100644
index 0000000000..507d9649b9
--- /dev/null
+++ b/cpp/src/qpid/cluster/Quorum_cman.cpp
@@ -0,0 +1,103 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/cluster/Quorum_cman.h"
+#include "qpid/cluster/Cluster.h"
+#include "qpid/log/Statement.h"
+#include "qpid/Options.h"
+#include "qpid/sys/Time.h"
+#include "qpid/sys/posix/PrivatePosix.h"
+
+namespace qpid {
+namespace cluster {
+
+namespace {
+
+boost::function<void()> errorFn;
+
+void cmanCallbackFn(cman_handle_t handle, void */*privdata*/, int reason, int /*arg*/) {
+ if (reason == CMAN_REASON_STATECHANGE && !cman_is_quorate(handle)) {
+ QPID_LOG(critical, "Lost contact with cluster quorum.");
+ if (errorFn) errorFn();
+ cman_stop_notification(handle);
+ }
+}
+}
+
+Quorum::Quorum(boost::function<void()> err) : enable(false), cman(0), cmanFd(0) {
+ errorFn = err;
+}
+
+Quorum::~Quorum() {
+ dispatchHandle.reset();
+ if (cman) cman_finish(cman);
+}
+
+void Quorum::start(boost::shared_ptr<sys::Poller> p) {
+ poller = p;
+ enable = true;
+ QPID_LOG(debug, "Connecting to quorum service.");
+ cman = cman_init(0);
+ if (cman == 0) throw ErrnoException("Can't connect to cman service");
+ if (!cman_is_quorate(cman)) {
+ QPID_LOG(notice, "Waiting for cluster quorum.");
+ while(!cman_is_quorate(cman)) sys::sleep(5);
+ }
+ int err = cman_start_notification(cman, cmanCallbackFn);
+ if (err != 0) throw ErrnoException("Can't register for cman notifications");
+ watch(getFd());
+}
+
+void Quorum::watch(int fd) {
+ cmanFd = fd;
+ dispatchHandle.reset(
+ new sys::DispatchHandleRef(
+ sys::PosixIOHandle(cmanFd),
+ boost::bind(&Quorum::dispatch, this, _1), // read
+ 0, // write
+ boost::bind(&Quorum::disconnect, this, _1) // disconnect
+ ));
+ dispatchHandle->startWatch(poller);
+}
+
+int Quorum::getFd() {
+ int fd = cman_get_fd(cman);
+ if (fd == 0) throw ErrnoException("Can't get cman file descriptor");
+ return fd;
+}
+
+void Quorum::dispatch(sys::DispatchHandle&) {
+ try {
+ cman_dispatch(cman, CMAN_DISPATCH_ALL);
+ int fd = getFd();
+ if (fd != cmanFd) watch(fd);
+ } catch (const std::exception& e) {
+ QPID_LOG(critical, "Error in quorum dispatch: " << e.what());
+ errorFn();
+ }
+}
+
+void Quorum::disconnect(sys::DispatchHandle&) {
+ QPID_LOG(critical, "Disconnected from quorum service");
+ errorFn();
+}
+
+}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/Quorum_cman.h b/cpp/src/qpid/cluster/Quorum_cman.h
new file mode 100644
index 0000000000..130f1baf64
--- /dev/null
+++ b/cpp/src/qpid/cluster/Quorum_cman.h
@@ -0,0 +1,64 @@
+#ifndef QPID_CLUSTER_QUORUM_CMAN_H
+#define QPID_CLUSTER_QUORUM_CMAN_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/sys/DispatchHandle.h>
+#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
+#include <memory>
+
+extern "C" {
+#include <libcman.h>
+}
+
+namespace qpid {
+namespace sys {
+class Poller;
+}
+
+namespace cluster {
+class Cluster;
+
+class Quorum {
+ public:
+ Quorum(boost::function<void ()> onError);
+ ~Quorum();
+ void start(boost::shared_ptr<sys::Poller>);
+
+ private:
+ void dispatch(sys::DispatchHandle&);
+ void disconnect(sys::DispatchHandle&);
+ int getFd();
+ void watch(int fd);
+
+ bool enable;
+ cman_handle_t cman;
+ int cmanFd;
+ std::auto_ptr<sys::DispatchHandleRef> dispatchHandle;
+ boost::shared_ptr<sys::Poller> poller;
+};
+
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_QUORUM_CMAN_H*/
diff --git a/cpp/src/qpid/cluster/Quorum_null.h b/cpp/src/qpid/cluster/Quorum_null.h
new file mode 100644
index 0000000000..dc27f0a43b
--- /dev/null
+++ b/cpp/src/qpid/cluster/Quorum_null.h
@@ -0,0 +1,42 @@
+#ifndef QPID_CLUSTER_QUORUM_NULL_H
+#define QPID_CLUSTER_QUORUM_NULL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+
+namespace qpid {
+namespace cluster {
+class Cluster;
+
+/** Null implementation of quorum. */
+
+class Quorum {
+ public:
+ Quorum(boost::function<void ()>) {}
+ void start(boost::shared_ptr<sys::Poller>) {}
+};
+
+#endif /*!QPID_CLUSTER_QUORUM_NULL_H*/
+
+}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/RetractClient.cpp b/cpp/src/qpid/cluster/RetractClient.cpp
new file mode 100644
index 0000000000..7d9f52fc39
--- /dev/null
+++ b/cpp/src/qpid/cluster/RetractClient.cpp
@@ -0,0 +1,61 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/cluster/RetractClient.h"
+#include "qpid/cluster/UpdateClient.h"
+#include "qpid/framing/ClusterConnectionRetractOfferBody.h"
+#include "qpid/client/ConnectionAccess.h"
+#include "qpid/client/ConnectionImpl.h"
+#include "qpid/log/Statement.h"
+
+namespace qpid {
+namespace cluster {
+
+using namespace framing;
+
+namespace {
+
+struct AutoClose {
+ client::Connection& connection;
+ AutoClose(client::Connection& c) : connection(c) {}
+ ~AutoClose() { connection.close(); }
+};
+}
+
+RetractClient::RetractClient(const Url& u, const client::ConnectionSettings& cs)
+ : url(u), connectionSettings(cs)
+{}
+
+RetractClient::~RetractClient() { delete this; }
+
+
+void RetractClient::run() {
+ try {
+ client::Connection c = UpdateClient::catchUpConnection();
+ c.open(url, connectionSettings);
+ AutoClose ac(c);
+ AMQFrame retract((ClusterConnectionRetractOfferBody()));
+ client::ConnectionAccess::getImpl(c)->handle(retract);
+ } catch (const std::exception& e) {
+ QPID_LOG(error, " while retracting retract to " << url << ": " << e.what());
+ }
+}
+
+}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/RetractClient.h b/cpp/src/qpid/cluster/RetractClient.h
new file mode 100644
index 0000000000..fb896197cc
--- /dev/null
+++ b/cpp/src/qpid/cluster/RetractClient.h
@@ -0,0 +1,49 @@
+#ifndef QPID_CLUSTER_RETRACTCLIENT_H
+#define QPID_CLUSTER_RETRACTCLIENT_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/client/ConnectionSettings.h"
+#include "qpid/sys/Runnable.h"
+
+
+namespace qpid {
+namespace cluster {
+
+/**
+ * A client that retracts an offer to a remote broker using AMQP. @see UpdateClient
+ */
+class RetractClient : public sys::Runnable {
+ public:
+
+ RetractClient(const Url&, const client::ConnectionSettings&);
+ ~RetractClient();
+ void run(); // Will delete this when finished.
+
+ private:
+ Url url;
+ client::ConnectionSettings connectionSettings;
+};
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_RETRACTCLIENT_H*/
diff --git a/cpp/src/qpid/cluster/ShadowConnectionOutputHandler.h b/cpp/src/qpid/cluster/ShadowConnectionOutputHandler.h
deleted file mode 100644
index 6d429535e6..0000000000
--- a/cpp/src/qpid/cluster/ShadowConnectionOutputHandler.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef QPID_CLUSTER_SHADOWCONNECTIONOUTPUTHANDLER_H
-#define QPID_CLUSTER_SHADOWCONNECTIONOUTPUTHANDLER_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include <qpid/sys/ConnectionOutputHandler.h>
-
-namespace qpid {
-
-namespace framing { class AMQFrame; }
-
-namespace cluster {
-
-/**
- * Output handler for frames sent to shadow connections.
- * Simply discards frames.
- */
-class ShadowConnectionOutputHandler : public sys::ConnectionOutputHandler
-{
- public:
- virtual void send(framing::AMQFrame&) {}
- virtual void close() {}
- virtual void activateOutput() {}
-};
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_SHADOWCONNECTIONOUTPUTHANDLER_H*/
diff --git a/cpp/src/qpid/cluster/StoreStatus.cpp b/cpp/src/qpid/cluster/StoreStatus.cpp
new file mode 100644
index 0000000000..6e412c23f7
--- /dev/null
+++ b/cpp/src/qpid/cluster/StoreStatus.cpp
@@ -0,0 +1,110 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "StoreStatus.h"
+#include "qpid/Exception.h"
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <fstream>
+
+namespace qpid {
+namespace cluster {
+
+using framing::Uuid;
+using namespace framing::cluster;
+namespace fs=boost::filesystem;
+using std::ostream;
+
+StoreStatus::StoreStatus(const std::string& d)
+ : state(STORE_STATE_NO_STORE), dataDir(d)
+{}
+
+namespace {
+
+const char* SUBDIR="cluster";
+const char* CLUSTER_ID_FILE="cluster.uuid";
+const char* SHUTDOWN_ID_FILE="shutdown.uuid";
+
+Uuid loadUuid(const fs::path& path) {
+ Uuid ret;
+ if (exists(path)) {
+ fs::ifstream i(path);
+ i >> ret;
+ }
+ return ret;
+}
+
+void saveUuid(const fs::path& path, const Uuid& uuid) {
+ fs::ofstream o(path);
+ o << uuid;
+}
+
+} // namespace
+
+
+void StoreStatus::load() {
+ fs::path dir = fs::path(dataDir, fs::native)/SUBDIR;
+ create_directory(dir);
+ clusterId = loadUuid(dir/CLUSTER_ID_FILE);
+ shutdownId = loadUuid(dir/SHUTDOWN_ID_FILE);
+
+ if (clusterId && shutdownId) state = STORE_STATE_CLEAN_STORE;
+ else if (clusterId) state = STORE_STATE_DIRTY_STORE;
+ else state = STORE_STATE_EMPTY_STORE;
+}
+
+void StoreStatus::save() {
+ fs::path dir = fs::path(dataDir, fs::native)/SUBDIR;
+ create_directory(dir);
+ saveUuid(dir/CLUSTER_ID_FILE, clusterId);
+ saveUuid(dir/SHUTDOWN_ID_FILE, shutdownId);
+}
+
+void StoreStatus::dirty(const Uuid& clusterId_) {
+ clusterId = clusterId_;
+ shutdownId = Uuid();
+ state = STORE_STATE_DIRTY_STORE;
+ save();
+}
+
+void StoreStatus::clean(const Uuid& shutdownId_) {
+ state = STORE_STATE_CLEAN_STORE;
+ shutdownId = shutdownId_;
+ save();
+}
+
+ostream& operator<<(ostream& o, const StoreStatus& s) {
+ switch (s.getState()) {
+ case STORE_STATE_NO_STORE: o << "no store"; break;
+ case STORE_STATE_EMPTY_STORE: o << "empty store"; break;
+ case STORE_STATE_DIRTY_STORE:
+ o << "dirty store, cluster-id=" << s.getClusterId();
+ break;
+ case STORE_STATE_CLEAN_STORE:
+ o << "clean store, cluster-id=" << s.getClusterId()
+ << " shutdown-id=" << s.getShutdownId();
+ break;
+ }
+ return o;
+}
+
+}} // namespace qpid::cluster
+
diff --git a/cpp/src/qpid/cluster/StoreStatus.h b/cpp/src/qpid/cluster/StoreStatus.h
new file mode 100644
index 0000000000..522020ed69
--- /dev/null
+++ b/cpp/src/qpid/cluster/StoreStatus.h
@@ -0,0 +1,64 @@
+#ifndef QPID_CLUSTER_STORESTATE_H
+#define QPID_CLUSTER_STORESTATE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/framing/Uuid.h"
+#include "qpid/framing/enum.h"
+#include <iosfwd>
+
+namespace qpid {
+namespace cluster {
+
+/**
+ * State of the store for cluster purposes.
+ */
+class StoreStatus
+{
+ public:
+ typedef framing::Uuid Uuid;
+ typedef framing::cluster::StoreState StoreState;
+
+ StoreStatus(const std::string& dir);
+
+ framing::cluster::StoreState getState() const { return state; }
+ const Uuid& getClusterId() const { return clusterId; }
+ const Uuid& getShutdownId() const { return shutdownId; }
+
+ void dirty(const Uuid& start); // Start using the store.
+ void clean(const Uuid& stop); // Stop using the store.
+
+ void load();
+ void save();
+
+ bool hasStore() { return state != framing::cluster::STORE_STATE_NO_STORE; }
+
+ private:
+ framing::cluster::StoreState state;
+ Uuid clusterId, shutdownId;
+ std::string dataDir;
+};
+
+std::ostream& operator<<(std::ostream&, const StoreStatus&);
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_STORESTATE_H*/
diff --git a/cpp/src/qpid/cluster/UpdateClient.cpp b/cpp/src/qpid/cluster/UpdateClient.cpp
new file mode 100644
index 0000000000..b20cc907a2
--- /dev/null
+++ b/cpp/src/qpid/cluster/UpdateClient.cpp
@@ -0,0 +1,484 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/cluster/UpdateClient.h"
+#include "qpid/cluster/Cluster.h"
+#include "qpid/cluster/ClusterMap.h"
+#include "qpid/cluster/Connection.h"
+#include "qpid/cluster/Decoder.h"
+#include "qpid/cluster/ExpiryPolicy.h"
+#include "qpid/client/SessionBase_0_10Access.h"
+#include "qpid/client/ConnectionAccess.h"
+#include "qpid/client/SessionImpl.h"
+#include "qpid/client/ConnectionImpl.h"
+#include "qpid/client/Future.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/QueueRegistry.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/Exchange.h"
+#include "qpid/broker/ExchangeRegistry.h"
+#include "qpid/broker/SessionHandler.h"
+#include "qpid/broker/SessionState.h"
+#include "qpid/broker/TxOpVisitor.h"
+#include "qpid/broker/DtxAck.h"
+#include "qpid/broker/TxAccept.h"
+#include "qpid/broker/TxPublish.h"
+#include "qpid/broker/RecoveredDequeue.h"
+#include "qpid/broker/RecoveredEnqueue.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/ClusterConnectionMembershipBody.h"
+#include "qpid/framing/ClusterConnectionShadowReadyBody.h"
+#include "qpid/framing/ClusterConnectionSessionStateBody.h"
+#include "qpid/framing/ClusterConnectionConsumerStateBody.h"
+#include "qpid/framing/enum.h"
+#include "qpid/framing/ProtocolVersion.h"
+#include "qpid/framing/TypeCode.h"
+#include "qpid/log/Statement.h"
+#include "qpid/Url.h"
+#include <boost/bind.hpp>
+#include <boost/cast.hpp>
+#include <algorithm>
+
+namespace qpid {
+namespace cluster {
+
+using broker::Broker;
+using broker::Exchange;
+using broker::Queue;
+using broker::QueueBinding;
+using broker::Message;
+using broker::SemanticState;
+
+using namespace framing;
+namespace arg=client::arg;
+using client::SessionBase_0_10Access;
+
+struct ClusterConnectionProxy : public AMQP_AllProxy::ClusterConnection {
+ ClusterConnectionProxy(client::Connection c) :
+ AMQP_AllProxy::ClusterConnection(*client::ConnectionAccess::getImpl(c)) {}
+ ClusterConnectionProxy(client::AsyncSession s) :
+ AMQP_AllProxy::ClusterConnection(SessionBase_0_10Access(s).get()->out) {}
+};
+
+// Create a connection with special version that marks it as a catch-up connection.
+client::Connection UpdateClient::catchUpConnection() {
+ client::Connection c;
+ client::ConnectionAccess::setVersion(c, ProtocolVersion(0x80 , 0x80 + 10));
+ return c;
+}
+
+// Send a control body directly to the session.
+void send(client::AsyncSession& s, const AMQBody& body) {
+ client::SessionBase_0_10Access sb(s);
+ sb.get()->send(body);
+}
+
+// TODO aconway 2008-09-24: optimization: update connections/sessions in parallel.
+
+UpdateClient::UpdateClient(const MemberId& updater, const MemberId& updatee, const Url& url,
+ broker::Broker& broker, const ClusterMap& m, ExpiryPolicy& expiry_,
+ const Cluster::ConnectionVector& cons, Decoder& decoder_,
+ const boost::function<void()>& ok,
+ const boost::function<void(const std::exception&)>& fail,
+ const client::ConnectionSettings& cs
+)
+ : updaterId(updater), updateeId(updatee), updateeUrl(url), updaterBroker(broker), map(m),
+ expiry(expiry_), connections(cons), decoder(decoder_),
+ connection(catchUpConnection()), shadowConnection(catchUpConnection()),
+ done(ok), failed(fail), connectionSettings(cs)
+{}
+
+UpdateClient::~UpdateClient() {}
+
+// Reserved exchange/queue name for catch-up, avoid clashes with user queues/exchanges.
+const std::string UpdateClient::UPDATE("qpid.cluster-update");
+
+void UpdateClient::run() {
+ try {
+ connection.open(updateeUrl, connectionSettings);
+ session = connection.newSession(UPDATE);
+ update();
+ done();
+ } catch (const std::exception& e) {
+ failed(e);
+ }
+ delete this;
+}
+
+void UpdateClient::update() {
+ QPID_LOG(debug, updaterId << " updating state to " << updateeId
+ << " at " << updateeUrl);
+ Broker& b = updaterBroker;
+ b.getExchanges().eachExchange(boost::bind(&UpdateClient::updateExchange, this, _1));
+ b.getQueues().eachQueue(boost::bind(&UpdateClient::updateNonExclusiveQueue, this, _1));
+
+ // Update queue is used to transfer acquired messages that are no
+ // longer on their original queue.
+ session.queueDeclare(arg::queue=UPDATE, arg::autoDelete=true);
+ session.sync();
+ std::for_each(connections.begin(), connections.end(), boost::bind(&UpdateClient::updateConnection, this, _1));
+ session.queueDelete(arg::queue=UPDATE);
+ session.close();
+
+ // Update queue listeners: must come after sessions so consumerNumbering is populated.
+ b.getQueues().eachQueue(boost::bind(&UpdateClient::updateQueueListeners, this, _1));
+
+ ClusterConnectionProxy(session).expiryId(expiry.getId());
+ ClusterConnectionMembershipBody membership;
+ map.toMethodBody(membership);
+ AMQFrame frame(membership);
+ client::ConnectionAccess::getImpl(connection)->handle(frame);
+
+ connection.close();
+ QPID_LOG(debug, updaterId << " update completed to " << updateeId
+ << " at " << updateeUrl << ": " << membership);
+}
+
+namespace {
+template <class T> std::string encode(const T& t) {
+ std::string encoded;
+ encoded.resize(t.encodedSize());
+ framing::Buffer buf(const_cast<char*>(encoded.data()), encoded.size());
+ t.encode(buf);
+ return encoded;
+}
+} // namespace
+
+void UpdateClient::updateExchange(const boost::shared_ptr<Exchange>& ex) {
+ QPID_LOG(debug, updaterId << " updating exchange " << ex->getName());
+ ClusterConnectionProxy(session).exchange(encode(*ex));
+}
+
+/** Bind a queue to the update exchange and update messges to it
+ * setting the message possition as needed.
+ */
+class MessageUpdater {
+ std::string queue;
+ bool haveLastPos;
+ framing::SequenceNumber lastPos;
+ client::AsyncSession session;
+ ExpiryPolicy& expiry;
+
+ public:
+
+ MessageUpdater(const string& q, const client::AsyncSession s, ExpiryPolicy& expiry_) : queue(q), haveLastPos(false), session(s), expiry(expiry_) {
+ session.exchangeBind(queue, UpdateClient::UPDATE);
+ }
+
+ ~MessageUpdater() {
+ try {
+ session.exchangeUnbind(queue, UpdateClient::UPDATE);
+ }
+ catch (const std::exception& e) {
+ // Don't throw in a destructor.
+ QPID_LOG(error, "Unbinding update queue " << queue << ": " << e.what());
+ }
+ }
+
+
+ void updateQueuedMessage(const broker::QueuedMessage& message) {
+ // Send the queue position if necessary.
+ if (!haveLastPos || message.position - lastPos != 1) {
+ ClusterConnectionProxy(session).queuePosition(queue, message.position.getValue()-1);
+ haveLastPos = true;
+ }
+ lastPos = message.position;
+
+ // Send the expiry ID if necessary.
+ if (message.payload->getProperties<DeliveryProperties>()->getTtl()) {
+ boost::optional<uint64_t> expiryId = expiry.getId(*message.payload);
+ if (!expiryId) return; // Message already expired, don't replicate.
+ ClusterConnectionProxy(session).expiryId(*expiryId);
+ }
+
+ // We can't send a broker::Message via the normal client API,
+ // and it would be expensive to copy it into a client::Message
+ // so we go a bit under the client API covers here.
+ //
+ SessionBase_0_10Access sb(session);
+ // Disable client code that clears the delivery-properties.exchange
+ sb.get()->setDoClearDeliveryPropertiesExchange(false);
+ framing::MessageTransferBody transfer(
+ *message.payload->getFrames().as<framing::MessageTransferBody>());
+ transfer.setDestination(UpdateClient::UPDATE);
+
+ sb.get()->send(transfer, message.payload->getFrames(),
+ !message.payload->isContentReleased());
+ if (message.payload->isContentReleased()){
+ uint16_t maxFrameSize = sb.get()->getConnection()->getNegotiatedSettings().maxFrameSize;
+ uint16_t maxContentSize = maxFrameSize - AMQFrame::frameOverhead();
+ bool morecontent = true;
+ for (uint64_t offset = 0; morecontent; offset += maxContentSize)
+ {
+ AMQFrame frame((AMQContentBody()));
+ morecontent = message.payload->getContentFrame(*(message.queue), frame, maxContentSize, offset);
+ sb.get()->sendRawFrame(frame);
+ }
+ }
+ }
+
+ void updateMessage(const boost::intrusive_ptr<broker::Message>& message) {
+ updateQueuedMessage(broker::QueuedMessage(0, message, haveLastPos? lastPos.getValue()+1 : 1));
+ }
+};
+
+void UpdateClient::updateQueue(client::AsyncSession& s, const boost::shared_ptr<Queue>& q) {
+ broker::Exchange::shared_ptr alternateExchange = q->getAlternateExchange();
+ s.queueDeclare(
+ arg::queue = q->getName(),
+ arg::durable = q->isDurable(),
+ arg::autoDelete = q->isAutoDelete(),
+ arg::alternateExchange = alternateExchange ? alternateExchange->getName() : "",
+ arg::arguments = q->getSettings(),
+ arg::exclusive = q->hasExclusiveOwner()
+ );
+ MessageUpdater updater(q->getName(), s, expiry);
+ q->eachMessage(boost::bind(&MessageUpdater::updateQueuedMessage, &updater, _1));
+ q->eachBinding(boost::bind(&UpdateClient::updateBinding, this, s, q->getName(), _1));
+ ClusterConnectionProxy(s).queuePosition(q->getName(), q->getPosition());
+}
+
+void UpdateClient::updateExclusiveQueue(const boost::shared_ptr<broker::Queue>& q) {
+ QPID_LOG(debug, updaterId << " updating exclusive queue " << q->getName() << " on " << shadowSession.getId());
+ updateQueue(shadowSession, q);
+}
+
+void UpdateClient::updateNonExclusiveQueue(const boost::shared_ptr<broker::Queue>& q) {
+ if (!q->hasExclusiveOwner()) {
+ QPID_LOG(debug, updaterId << " updating queue " << q->getName());
+ updateQueue(session, q);
+ }//else queue will be updated as part of session state of owning session
+}
+
+void UpdateClient::updateBinding(client::AsyncSession& s, const std::string& queue, const QueueBinding& binding) {
+ s.exchangeBind(queue, binding.exchange, binding.key, binding.args);
+}
+
+void UpdateClient::updateOutputTask(const sys::OutputTask* task) {
+ const SemanticState::ConsumerImpl* cci =
+ boost::polymorphic_downcast<const SemanticState::ConsumerImpl*> (task);
+ SemanticState::ConsumerImpl* ci = const_cast<SemanticState::ConsumerImpl*>(cci);
+ uint16_t channel = ci->getParent().getSession().getChannel();
+ ClusterConnectionProxy(shadowConnection).outputTask(channel, ci->getName());
+ QPID_LOG(debug, updaterId << " updating output task " << ci->getName()
+ << " channel=" << channel);
+}
+
+void UpdateClient::updateConnection(const boost::intrusive_ptr<Connection>& updateConnection) {
+ QPID_LOG(debug, updaterId << " updating connection " << *updateConnection);
+ shadowConnection = catchUpConnection();
+
+ broker::Connection& bc = updateConnection->getBrokerConnection();
+ connectionSettings.maxFrameSize = bc.getFrameMax();
+ shadowConnection.open(updateeUrl, connectionSettings);
+ bc.eachSessionHandler(boost::bind(&UpdateClient::updateSession, this, _1));
+ // Safe to use decoder here because we are stalled for update.
+ std::pair<const char*, size_t> fragment = decoder.get(updateConnection->getId()).getFragment();
+ bc.getOutputTasks().eachOutput(
+ boost::bind(&UpdateClient::updateOutputTask, this, _1));
+ ClusterConnectionProxy(shadowConnection).shadowReady(
+ updateConnection->getId().getMember(),
+ updateConnection->getId().getNumber(),
+ bc.getUserId(),
+ string(fragment.first, fragment.second),
+ updateConnection->getOutput().getSendMax()
+ );
+ shadowConnection.close();
+ QPID_LOG(debug, updaterId << " updated connection " << *updateConnection);
+}
+
+void UpdateClient::updateSession(broker::SessionHandler& sh) {
+ broker::SessionState* ss = sh.getSession();
+ if (!ss) return; // no session.
+
+ QPID_LOG(debug, updaterId << " updating session " << &sh.getConnection()
+ << "[" << sh.getChannel() << "] = " << ss->getId());
+
+ // Create a client session to update session state.
+ boost::shared_ptr<client::ConnectionImpl> cimpl = client::ConnectionAccess::getImpl(shadowConnection);
+ boost::shared_ptr<client::SessionImpl> simpl = cimpl->newSession(ss->getId().getName(), ss->getTimeout(), sh.getChannel());
+ simpl->disableAutoDetach();
+ client::SessionBase_0_10Access(shadowSession).set(simpl);
+ AMQP_AllProxy::ClusterConnection proxy(simpl->out);
+
+ // Re-create session state on remote connection.
+
+ QPID_LOG(debug, updaterId << " updating exclusive queues.");
+ ss->getSessionAdapter().eachExclusiveQueue(boost::bind(&UpdateClient::updateExclusiveQueue, this, _1));
+
+ QPID_LOG(debug, updaterId << " updating consumers.");
+ ss->getSemanticState().eachConsumer(
+ boost::bind(&UpdateClient::updateConsumer, this, _1));
+
+ QPID_LOG(debug, updaterId << " updating unacknowledged messages.");
+ broker::DeliveryRecords& drs = ss->getSemanticState().getUnacked();
+ std::for_each(drs.begin(), drs.end(), boost::bind(&UpdateClient::updateUnacked, this, _1));
+
+ updateTxState(ss->getSemanticState()); // Tx transaction state.
+
+ // Adjust command counter for message in progress, will be sent after state update.
+ boost::intrusive_ptr<Message> inProgress = ss->getMessageInProgress();
+ SequenceNumber received = ss->receiverGetReceived().command;
+ if (inProgress)
+ --received;
+
+ // Reset command-sequence state.
+ proxy.sessionState(
+ ss->senderGetReplayPoint().command,
+ ss->senderGetCommandPoint().command,
+ ss->senderGetIncomplete(),
+ std::max(received, ss->receiverGetExpected().command),
+ received,
+ ss->receiverGetUnknownComplete(),
+ ss->receiverGetIncomplete()
+ );
+
+ // Send frames for partial message in progress.
+ if (inProgress) {
+ inProgress->getFrames().map(simpl->out);
+ }
+ QPID_LOG(debug, updaterId << " updated session " << sh.getSession()->getId());
+}
+
+void UpdateClient::updateConsumer(
+ const broker::SemanticState::ConsumerImpl::shared_ptr& ci)
+{
+ QPID_LOG(debug, updaterId << " updating consumer " << ci->getName() << " on "
+ << shadowSession.getId());
+
+ using namespace message;
+ shadowSession.messageSubscribe(
+ arg::queue = ci->getQueue()->getName(),
+ arg::destination = ci->getName(),
+ arg::acceptMode = ci->isAckExpected() ? ACCEPT_MODE_EXPLICIT : ACCEPT_MODE_NONE,
+ arg::acquireMode = ci->isAcquire() ? ACQUIRE_MODE_PRE_ACQUIRED : ACQUIRE_MODE_NOT_ACQUIRED,
+ arg::exclusive = ci->isExclusive(),
+ arg::resumeId = ci->getResumeId(),
+ arg::resumeTtl = ci->getResumeTtl(),
+ arg::arguments = ci->getArguments()
+ );
+ shadowSession.messageSetFlowMode(ci->getName(), ci->isWindowing() ? FLOW_MODE_WINDOW : FLOW_MODE_CREDIT);
+ shadowSession.messageFlow(ci->getName(), CREDIT_UNIT_MESSAGE, ci->getMsgCredit());
+ shadowSession.messageFlow(ci->getName(), CREDIT_UNIT_BYTE, ci->getByteCredit());
+ ClusterConnectionProxy(shadowSession).consumerState(
+ ci->getName(),
+ ci->isBlocked(),
+ ci->isNotifyEnabled(),
+ ci->position
+ );
+ consumerNumbering.add(ci);
+
+ QPID_LOG(debug, updaterId << " updated consumer " << ci->getName()
+ << " on " << shadowSession.getId());
+}
+
+void UpdateClient::updateUnacked(const broker::DeliveryRecord& dr) {
+ if (!dr.isEnded() && dr.isAcquired() && dr.getMessage().payload) {
+ // If the message is acquired then it is no longer on the
+ // updatees queue, put it on the update queue for updatee to pick up.
+ //
+ MessageUpdater(UPDATE, shadowSession, expiry).updateQueuedMessage(dr.getMessage());
+ }
+ ClusterConnectionProxy(shadowSession).deliveryRecord(
+ dr.getQueue()->getName(),
+ dr.getMessage().position,
+ dr.getTag(),
+ dr.getId(),
+ dr.isAcquired(),
+ dr.isAccepted(),
+ dr.isCancelled(),
+ dr.isComplete(),
+ dr.isEnded(),
+ dr.isWindowing(),
+ dr.getQueue()->isEnqueued(dr.getMessage()),
+ dr.getCredit()
+ );
+}
+
+class TxOpUpdater : public broker::TxOpConstVisitor, public MessageUpdater {
+ public:
+ TxOpUpdater(UpdateClient& dc, client::AsyncSession s, ExpiryPolicy& expiry)
+ : MessageUpdater(UpdateClient::UPDATE, s, expiry), parent(dc), session(s), proxy(s) {}
+
+ void operator()(const broker::DtxAck& ) {
+ throw InternalErrorException("DTX transactions not currently supported by cluster.");
+ }
+
+ void operator()(const broker::RecoveredDequeue& rdeq) {
+ updateMessage(rdeq.getMessage());
+ proxy.txEnqueue(rdeq.getQueue()->getName());
+ }
+
+ void operator()(const broker::RecoveredEnqueue& renq) {
+ updateMessage(renq.getMessage());
+ proxy.txEnqueue(renq.getQueue()->getName());
+ }
+
+ void operator()(const broker::TxAccept& txAccept) {
+ proxy.txAccept(txAccept.getAcked());
+ }
+
+ void operator()(const broker::TxPublish& txPub) {
+ updateMessage(txPub.getMessage());
+ typedef std::list<Queue::shared_ptr> QueueList;
+ const QueueList& qlist = txPub.getQueues();
+ Array qarray(TYPE_CODE_STR8);
+ for (QueueList::const_iterator i = qlist.begin(); i != qlist.end(); ++i)
+ qarray.push_back(Array::ValuePtr(new Str8Value((*i)->getName())));
+ proxy.txPublish(qarray, txPub.delivered);
+ }
+
+ private:
+ UpdateClient& parent;
+ client::AsyncSession session;
+ ClusterConnectionProxy proxy;
+};
+
+void UpdateClient::updateTxState(broker::SemanticState& s) {
+ QPID_LOG(debug, updaterId << " updating TX transaction state.");
+ ClusterConnectionProxy proxy(shadowSession);
+ proxy.accumulatedAck(s.getAccumulatedAck());
+ broker::TxBuffer::shared_ptr txBuffer = s.getTxBuffer();
+ if (txBuffer) {
+ proxy.txStart();
+ TxOpUpdater updater(*this, shadowSession, expiry);
+ txBuffer->accept(updater);
+ proxy.txEnd();
+ }
+}
+
+void UpdateClient::updateQueueListeners(const boost::shared_ptr<broker::Queue>& queue) {
+ queue->getListeners().eachListener(
+ boost::bind(&UpdateClient::updateQueueListener, this, queue->getName(), _1));
+}
+
+void UpdateClient::updateQueueListener(std::string& q,
+ const boost::shared_ptr<broker::Consumer>& c)
+{
+ const boost::shared_ptr<SemanticState::ConsumerImpl> ci =
+ boost::dynamic_pointer_cast<SemanticState::ConsumerImpl>(c);
+ size_t n = consumerNumbering[ci];
+ if (n >= consumerNumbering.size())
+ throw Exception(QPID_MSG("Unexpected listener on queue " << q));
+ ClusterConnectionProxy(session).addQueueListener(q, n);
+}
+
+}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/UpdateClient.h b/cpp/src/qpid/cluster/UpdateClient.h
new file mode 100644
index 0000000000..29ef5f9df2
--- /dev/null
+++ b/cpp/src/qpid/cluster/UpdateClient.h
@@ -0,0 +1,119 @@
+#ifndef QPID_CLUSTER_UPDATECLIENT_H
+#define QPID_CLUSTER_UPDATECLIENT_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/cluster/ClusterMap.h"
+#include "qpid/cluster/Numbering.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/ConnectionSettings.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/broker/SemanticState.h"
+#include "qpid/sys/Runnable.h"
+#include <boost/shared_ptr.hpp>
+
+
+namespace qpid {
+
+class Url;
+
+namespace broker {
+
+class Broker;
+class Queue;
+class Exchange;
+class QueueBindings;
+class QueueBinding;
+class QueuedMessage;
+class SessionHandler;
+class DeliveryRecord;
+class SessionState;
+class SemanticState;
+class Decoder;
+
+} // namespace broker
+
+namespace cluster {
+
+class Cluster;
+class Connection;
+class ClusterMap;
+class Decoder;
+class ExpiryPolicy;
+
+/**
+ * A client that updates the contents of a local broker to a remote one using AMQP.
+ */
+class UpdateClient : public sys::Runnable {
+ public:
+ static const std::string UPDATE; // Name for special update queue and exchange.
+ static client::Connection catchUpConnection();
+
+ UpdateClient(const MemberId& updater, const MemberId& updatee, const Url&,
+ broker::Broker& donor, const ClusterMap& map, ExpiryPolicy& expiry,
+ const std::vector<boost::intrusive_ptr<Connection> >&, Decoder&,
+ const boost::function<void()>& done,
+ const boost::function<void(const std::exception&)>& fail,
+ const client::ConnectionSettings&
+ );
+
+ ~UpdateClient();
+ void update();
+ void run(); // Will delete this when finished.
+
+ void updateUnacked(const broker::DeliveryRecord&);
+
+ private:
+ void updateQueue(client::AsyncSession&, const boost::shared_ptr<broker::Queue>&);
+ void updateNonExclusiveQueue(const boost::shared_ptr<broker::Queue>&);
+ void updateExclusiveQueue(const boost::shared_ptr<broker::Queue>&);
+ void updateExchange(const boost::shared_ptr<broker::Exchange>&);
+ void updateMessage(const broker::QueuedMessage&);
+ void updateMessageTo(const broker::QueuedMessage&, const std::string& queue, client::Session s);
+ void updateBinding(client::AsyncSession&, const std::string& queue, const broker::QueueBinding& binding);
+ void updateConnection(const boost::intrusive_ptr<Connection>& connection);
+ void updateSession(broker::SessionHandler& s);
+ void updateTxState(broker::SemanticState& s);
+ void updateOutputTask(const sys::OutputTask* task);
+ void updateConsumer(const broker::SemanticState::ConsumerImpl::shared_ptr&);
+ void updateQueueListeners(const boost::shared_ptr<broker::Queue>&);
+ void updateQueueListener(std::string& q, const boost::shared_ptr<broker::Consumer>& c);
+
+ Numbering<broker::SemanticState::ConsumerImpl::shared_ptr> consumerNumbering;
+ MemberId updaterId;
+ MemberId updateeId;
+ Url updateeUrl;
+ broker::Broker& updaterBroker;
+ ClusterMap map;
+ ExpiryPolicy& expiry;
+ std::vector<boost::intrusive_ptr<Connection> > connections;
+ Decoder& decoder;
+ client::Connection connection, shadowConnection;
+ client::AsyncSession session, shadowSession;
+ boost::function<void()> done;
+ boost::function<void(const std::exception& e)> failed;
+ client::ConnectionSettings connectionSettings;
+};
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_UPDATECLIENT_H*/
diff --git a/cpp/src/qpid/cluster/UpdateExchange.cpp b/cpp/src/qpid/cluster/UpdateExchange.cpp
new file mode 100644
index 0000000000..11937f296f
--- /dev/null
+++ b/cpp/src/qpid/cluster/UpdateExchange.cpp
@@ -0,0 +1,47 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/broker/Message.h"
+#include "UpdateExchange.h"
+
+namespace qpid {
+namespace cluster {
+
+using framing::MessageTransferBody;
+using framing::DeliveryProperties;
+
+UpdateExchange::UpdateExchange(management::Manageable* parent)
+ : broker::Exchange(UpdateClient::UPDATE, parent),
+ broker::FanOutExchange(UpdateClient::UPDATE, parent) {}
+
+
+void UpdateExchange::setProperties(const boost::intrusive_ptr<broker::Message>& msg) {
+ MessageTransferBody* transfer = msg->getMethod<MessageTransferBody>();
+ assert(transfer);
+ const DeliveryProperties* props = msg->getProperties<DeliveryProperties>();
+ assert(props);
+ if (props->hasExchange())
+ transfer->setDestination(props->getExchange());
+ else
+ transfer->clearDestinationFlag();
+}
+
+}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/UpdateExchange.h b/cpp/src/qpid/cluster/UpdateExchange.h
new file mode 100644
index 0000000000..9d7d9ee5fc
--- /dev/null
+++ b/cpp/src/qpid/cluster/UpdateExchange.h
@@ -0,0 +1,45 @@
+#ifndef QPID_CLUSTER_UPDATEEXCHANGE_H
+#define QPID_CLUSTER_UPDATEEXCHANGE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/cluster/UpdateClient.h"
+#include "qpid/broker/FanOutExchange.h"
+
+
+namespace qpid {
+namespace cluster {
+
+/**
+ * A keyless exchange (like fanout exchange) that does not modify
+ * delivery-properties.exchange but copies it to the MessageTransfer.
+ */
+class UpdateExchange : public broker::FanOutExchange
+{
+ public:
+ UpdateExchange(management::Manageable* parent);
+ void setProperties(const boost::intrusive_ptr<broker::Message>&);
+};
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_UPDATEEXCHANGE_H*/
diff --git a/cpp/src/qpid/cluster/UpdateReceiver.h b/cpp/src/qpid/cluster/UpdateReceiver.h
new file mode 100644
index 0000000000..cc1ce0da8d
--- /dev/null
+++ b/cpp/src/qpid/cluster/UpdateReceiver.h
@@ -0,0 +1,42 @@
+#ifndef QPID_CLUSTER_UPDATESTATE_H
+#define QPID_CLUSTER_UPDATESTATE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Numbering.h"
+#include "qpid/broker/SemanticState.h"
+
+namespace qpid {
+namespace cluster {
+
+/**
+ * Cluster-wide state used when receiving an update.
+ */
+class UpdateReceiver {
+ public:
+ /** Numbering used to identify Queue listeners as consumers */
+ typedef Numbering<boost::shared_ptr<broker::SemanticState::ConsumerImpl> > ConsumerNumbering;
+ ConsumerNumbering consumerNumbering;
+};
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_UPDATESTATE_H*/
diff --git a/cpp/src/qpid/cluster/WatchDogPlugin.cpp b/cpp/src/qpid/cluster/WatchDogPlugin.cpp
new file mode 100644
index 0000000000..fc2b830dac
--- /dev/null
+++ b/cpp/src/qpid/cluster/WatchDogPlugin.cpp
@@ -0,0 +1,136 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**@file
+
+ The watchdog plug-in will kill the qpidd broker process if it
+ becomes stuck for longer than a configured interval.
+
+ If the watchdog plugin is loaded and the --watchdog-interval=N
+ option is set then the broker starts a watchdog process and signals
+ it every N/2 seconds.
+
+ The watchdog process runs a very simple program that starts a timer
+ for N seconds, and resets the timer to N seconds whenever it is
+ signalled by the broker. If the timer ever reaches 0 the watchdog
+ kills the broker process (with kill -9) and exits.
+
+ This is useful in a cluster setting because in some insttances
+ (e.g. while resolving an error) it's possible for a stuck process
+ to hang other cluster members that are waiting for it to send a
+ message. Using the watchdog, the stuck process is terminated and
+ removed fromt the cluster allowing other members to continue and
+ clients of the stuck process to fail over to other members.
+
+*/
+#include "qpid/Plugin.h"
+#include "qpid/Options.h"
+#include "qpid/log/Statement.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/sys/Timer.h"
+#include "qpid/sys/Fork.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+namespace qpid {
+namespace cluster {
+
+using broker::Broker;
+
+struct Settings {
+ Settings() : interval(0) {}
+ int interval;
+};
+
+struct WatchDogOptions : public qpid::Options {
+ Settings& settings;
+
+ WatchDogOptions(Settings& s) : settings(s) {
+ addOptions()
+ ("watchdog-interval", optValue(settings.interval, "N"),
+ "broker is automatically killed if it is hung for more than \
+ N seconds. 0 disables watchdog.");
+ }
+};
+
+struct WatchDogTask : public sys::TimerTask {
+ int pid;
+ sys::Timer& timer;
+ int interval;
+
+ WatchDogTask(int pid_, sys::Timer& t, int _interval)
+ : TimerTask(_interval*sys::TIME_SEC/2), pid(pid_), timer(t), interval(_interval) {}
+
+ void fire() {
+ timer.add (new WatchDogTask(pid, timer, interval));
+ QPID_LOG(debug, "Sending keepalive signal to watchdog");
+ ::kill(pid, SIGUSR1);
+ }
+};
+
+struct WatchDogPlugin : public qpid::Plugin, public qpid::sys::Fork {
+ Settings settings;
+ WatchDogOptions options;
+ Broker* broker;
+ int watchdogPid;
+
+ WatchDogPlugin() : options(settings), broker(0), watchdogPid(0) {}
+
+ ~WatchDogPlugin() {
+ if (watchdogPid) ::kill(watchdogPid, SIGTERM);
+ ::waitpid(watchdogPid, 0, 0);
+ }
+
+ Options* getOptions() { return &options; }
+
+ void earlyInitialize(qpid::Plugin::Target& target) {
+ broker = dynamic_cast<Broker*>(&target);
+ if (broker && settings.interval) {
+ QPID_LOG(notice, "Starting watchdog process with interval of " <<
+ settings.interval << " seconds");
+ fork();
+ }
+ }
+
+ void initialize(Target&) {}
+
+ protected:
+
+ void child() { // Child of fork
+ const char* watchdog = ::getenv("QPID_WATCHDOG_EXEC"); // For use in tests
+ if (!watchdog) watchdog=QPID_EXEC_DIR "/qpidd_watchdog";
+ std::string interval = boost::lexical_cast<std::string>(settings.interval);
+ ::execl(watchdog, watchdog, interval.c_str(), NULL);
+ QPID_LOG(critical, "Failed to exec watchdog program " << watchdog );
+ ::kill(::getppid(), SIGKILL);
+ exit(1);
+ }
+
+ void parent(int pid) { // Parent of fork
+ watchdogPid = pid;
+ broker->getTimer().add(
+ new WatchDogTask(watchdogPid, broker->getTimer(), settings.interval));
+ // TODO aconway 2009-08-10: to be extra safe, we could monitor
+ // the watchdog child and re-start it if it exits.
+ }
+};
+
+static WatchDogPlugin instance; // Static initialization.
+
+}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/management-schema.xml b/cpp/src/qpid/cluster/management-schema.xml
new file mode 100644
index 0000000000..a6292e9113
--- /dev/null
+++ b/cpp/src/qpid/cluster/management-schema.xml
@@ -0,0 +1,61 @@
+<schema package="org.apache.qpid.cluster">
+
+ <!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ -->
+
+ <!-- Type information:
+
+Numeric types with "_wm" suffix are watermarked numbers. These are compound
+values containing a current value, and a low and high water mark for the reporting
+interval. The low and high water marks are set to the current value at the
+beginning of each interval and track the minimum and maximum values of the statistic
+over the interval respectively.
+
+Access rights for configuration elements:
+
+RO => Read Only
+RC => Read/Create, can be set at create time only, read-only thereafter
+RW => Read/Write
+
+If access rights are omitted for a property, they are assumed to be RO.
+
+ -->
+
+ <class name="Cluster">
+ <property name="brokerRef" type="objId" references="Broker" access="RC" index="y" parentRef="y"/>
+ <property name="clusterName" type="sstr" access="RC" desc="Name of cluster this server is a member of"/>
+ <property name="clusterID" type="sstr" access="RO" desc="Globally unique ID (UUID) for this cluster instance"/>
+ <property name="memberID" type="sstr" access="RO" desc="ID of this member of the cluster"/>
+ <property name="publishedURL" type="sstr" access="RC" desc="URL this node advertizes itself as"/>
+ <property name="clusterSize" type="uint16" access="RO" desc="Number of brokers currently in the cluster"/>
+ <property name="status" type="sstr" access="RO" desc="Cluster node status (STALLED,ACTIVE,JOINING)"/>
+ <property name="members" type="lstr" access="RO" desc="List of member URLs delimited by ';'"/>
+ <property name="memberIDs" type="lstr" access="RO" desc="List of member IDs delimited by ';'"/>
+
+ <method name="stopClusterNode">
+ <arg name="brokerId" type="sstr" dir="I"/>
+ </method>
+ <method name="stopFullCluster"/>
+
+ </class>
+
+
+
+</schema>
+
diff --git a/cpp/src/qpid/cluster/qpidd_watchdog.cpp b/cpp/src/qpid/cluster/qpidd_watchdog.cpp
new file mode 100644
index 0000000000..51c5ed4b3f
--- /dev/null
+++ b/cpp/src/qpid/cluster/qpidd_watchdog.cpp
@@ -0,0 +1,63 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/** @file helper executable for WatchDogPlugin.cpp */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+
+long timeout;
+
+void killParent(int) {
+ ::kill(getppid(), SIGKILL);
+ ::fprintf(stderr, "Watchdog killed unresponsive broker, pid=%d\n", ::getppid());
+ ::exit(1);
+}
+
+void resetTimer(int) {
+ struct ::itimerval itval = { { 0, 0 }, { timeout, 0 } };
+ if (::setitimer(ITIMER_REAL, &itval, 0) !=0) {
+ ::perror("Watchdog failed to set timer");
+ killParent(0);
+ ::exit(1);
+ }
+}
+
+/** Simple watchdog program: kill parent process if timeout
+ * expires without a SIGUSR1.
+ * Will be killed with SIGHUP when parent shuts down.
+ * Args: timeout in seconds.
+ */
+int main(int argc, char** argv) {
+ if(argc != 2 || (timeout = atoi(argv[1])) == 0) {
+ ::fprintf(stderr, "Usage: %s <timeout_seconds>\n", argv[0]);
+ ::exit(1);
+ }
+ ::signal(SIGUSR1, resetTimer);
+ ::signal(SIGALRM, killParent);
+ resetTimer(0);
+ while (true) { sleep(INT_MAX); }
+}
diff --git a/cpp/src/qpid/cluster/types.h b/cpp/src/qpid/cluster/types.h
new file mode 100644
index 0000000000..c25370b6b6
--- /dev/null
+++ b/cpp/src/qpid/cluster/types.h
@@ -0,0 +1,83 @@
+#ifndef QPID_CLUSTER_TYPES_H
+#define QPID_CLUSTER_TYPES_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "config.h"
+#include "qpid/Url.h"
+#include "qpid/sys/IntegerTypes.h"
+#include <boost/intrusive_ptr.hpp>
+#include <utility>
+#include <iosfwd>
+#include <string>
+
+extern "C" {
+#if defined (HAVE_OPENAIS_CPG_H)
+# include <openais/cpg.h>
+#elif defined (HAVE_COROSYNC_CPG_H)
+# include <corosync/cpg.h>
+#else
+# error "No cpg.h header file available"
+#endif
+}
+
+namespace qpid {
+namespace cluster {
+
+class Connection;
+typedef boost::intrusive_ptr<Connection> ConnectionPtr;
+
+/** Types of cluster event. */
+enum EventType { DATA, CONTROL };
+
+/** first=node-id, second=pid */
+struct MemberId : std::pair<uint32_t, uint32_t> {
+ MemberId(uint64_t n=0) : std::pair<uint32_t,uint32_t>( n >> 32, n & 0xffffffff) {}
+ MemberId(uint32_t node, uint32_t pid) : std::pair<uint32_t,uint32_t>(node, pid) {}
+ MemberId(const cpg_address& caddr) : std::pair<uint32_t,uint32_t>(caddr.nodeid, caddr.pid) {}
+ MemberId(const std::string&); // Decode from string.
+ uint32_t getNode() const { return first; }
+ uint32_t getPid() const { return second; }
+ operator uint64_t() const { return (uint64_t(first)<<32ull) + second; }
+
+ // AsMethodBody as string, network byte order.
+ std::string str() const;
+};
+
+inline bool operator==(const cpg_address& caddr, const MemberId& id) { return id == MemberId(caddr); }
+
+std::ostream& operator<<(std::ostream&, const MemberId&);
+
+struct ConnectionId : public std::pair<MemberId, uint64_t> {
+ ConnectionId(const MemberId& m=MemberId(), uint64_t c=0) : std::pair<MemberId, uint64_t> (m,c) {}
+ ConnectionId(uint64_t m, uint64_t c) : std::pair<MemberId, uint64_t>(MemberId(m), c) {}
+ MemberId getMember() const { return first; }
+ uint64_t getNumber() const { return second; }
+};
+
+std::ostream& operator<<(std::ostream&, const ConnectionId&);
+
+std::ostream& operator<<(std::ostream&, EventType);
+
+}} // namespace qpid::cluster
+
+#endif /*!QPID_CLUSTER_TYPES_H*/
diff --git a/cpp/src/qpid/console/Agent.cpp b/cpp/src/qpid/console/Agent.cpp
new file mode 100644
index 0000000000..fa76a13583
--- /dev/null
+++ b/cpp/src/qpid/console/Agent.cpp
@@ -0,0 +1,30 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/console/Agent.h"
+
+std::ostream& qpid::console::operator<<(std::ostream& o, const Agent& agent)
+{
+ o << "Agent at bank " << agent.getBrokerBank() << "." << agent.getAgentBank() <<
+ " (" << agent.getLabel() << ")";
+ return o;
+}
+
diff --git a/cpp/src/qpid/console/Broker.cpp b/cpp/src/qpid/console/Broker.cpp
new file mode 100644
index 0000000000..d2ff8f819e
--- /dev/null
+++ b/cpp/src/qpid/console/Broker.cpp
@@ -0,0 +1,328 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/console/Broker.h"
+#include "qpid/console/Object.h"
+#include "qpid/console/Value.h"
+#include "qpid/console/SessionManager.h"
+#include "qpid/console/ConsoleListener.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/SystemInfo.h"
+
+using namespace qpid::client;
+using namespace qpid::console;
+using namespace qpid::framing;
+using namespace qpid::sys;
+using namespace std;
+
+Broker::Broker(SessionManager& sm, ConnectionSettings& settings) :
+ sessionManager(sm), connected(false), connectionSettings(settings),
+ reqsOutstanding(1), syncInFlight(false), topicBound(false), methodObject(0),
+ connThreadBody(*this), connThread(connThreadBody)
+{
+ string osName;
+ string nodeName;
+ string release;
+ string version;
+ string machine;
+
+ sys::SystemInfo::getSystemId(osName, nodeName, release, version, machine);
+ uint32_t pid = sys::SystemInfo::getParentProcessId();
+
+ stringstream text;
+
+ text << "qmfc-cpp-" << nodeName << "-" << pid;
+ amqpSessionId = string(text.str());
+
+ QPID_LOG(debug, "Broker::Broker: constructed, amqpSessionId=" << amqpSessionId);
+}
+
+Broker::~Broker()
+{
+ connThreadBody.shutdown();
+ connThread.join();
+}
+
+string Broker::getUrl() const
+{
+ stringstream url;
+ url << connectionSettings.host << ":" << connectionSettings.port;
+ return url.str();
+}
+
+void Broker::encodeHeader(Buffer& buf, uint8_t opcode, uint32_t seq) const
+{
+ buf.putOctet('A');
+ buf.putOctet('M');
+ buf.putOctet('2');
+ buf.putOctet(opcode);
+ buf.putLong (seq);
+}
+
+bool Broker::checkHeader(Buffer& buf, uint8_t *opcode, uint32_t *seq) const
+{
+ if (buf.getSize() < 8)
+ return false;
+
+ uint8_t h1 = buf.getOctet();
+ uint8_t h2 = buf.getOctet();
+ uint8_t h3 = buf.getOctet();
+
+ *opcode = buf.getOctet();
+ *seq = buf.getLong();
+
+ return h1 == 'A' && h2 == 'M' && h3 == '2';
+}
+
+void Broker::received(qpid::client::Message& msg)
+{
+#define QMF_HEADER_SIZE 8
+ string data = msg.getData();
+ Buffer inBuffer(const_cast<char*>(data.c_str()), data.size());
+ uint8_t opcode;
+ uint32_t sequence;
+
+ while (inBuffer.available() >= QMF_HEADER_SIZE) {
+ if (checkHeader(inBuffer, &opcode, &sequence)) {
+ QPID_LOG(trace, "Broker::received: opcode=" << opcode << " seq=" << sequence);
+
+ if (opcode == 'b') sessionManager.handleBrokerResp(this, inBuffer, sequence);
+ else if (opcode == 'p') sessionManager.handlePackageInd(this, inBuffer, sequence);
+ else if (opcode == 'z') sessionManager.handleCommandComplete(this, inBuffer, sequence);
+ else if (opcode == 'q') sessionManager.handleClassInd(this, inBuffer, sequence);
+ else if (opcode == 'm') sessionManager.handleMethodResp(this, inBuffer, sequence);
+ else if (opcode == 'h') sessionManager.handleHeartbeatInd(this, inBuffer, sequence);
+ else if (opcode == 'e') sessionManager.handleEventInd(this, inBuffer, sequence);
+ else if (opcode == 's') sessionManager.handleSchemaResp(this, inBuffer, sequence);
+ else if (opcode == 'c') sessionManager.handleContentInd(this, inBuffer, sequence, true, false);
+ else if (opcode == 'i') sessionManager.handleContentInd(this, inBuffer, sequence, false, true);
+ else if (opcode == 'g') sessionManager.handleContentInd(this, inBuffer, sequence, true, true);
+ } else
+ return;
+ }
+}
+
+void Broker::resetAgents()
+{
+ for (AgentMap::iterator iter = agents.begin(); iter != agents.end(); iter++) {
+ if (sessionManager.listener != 0)
+ sessionManager.listener->delAgent(*(iter->second));
+ delete iter->second;
+ }
+
+ agents.clear();
+ agents[0x0000000100000000LL] = new Agent(this, 0, "BrokerAgent");
+}
+
+void Broker::updateAgent(const Object& object)
+{
+ uint32_t brokerBank = object.attrUint("brokerBank");
+ uint32_t agentBank = object.attrUint("agentBank");
+ uint64_t agentKey = ((uint64_t) brokerBank << 32) | (uint64_t) agentBank;
+ AgentMap::iterator iter = agents.find(agentKey);
+
+ if (object.isDeleted()) {
+ if (iter != agents.end()) {
+ if (sessionManager.listener != 0)
+ sessionManager.listener->delAgent(*(iter->second));
+ delete iter->second;
+ agents.erase(iter);
+ }
+ } else {
+ if (iter == agents.end()) {
+ Agent* agent = new Agent(this, agentBank, object.attrString("label"));
+ agents[agentKey] = agent;
+ if (sessionManager.listener != 0)
+ sessionManager.listener->newAgent(*agent);
+ }
+ }
+}
+
+void Broker::ConnectionThread::run()
+{
+ static const int delayMin(1);
+ static const int delayMax(128);
+ static const int delayFactor(2);
+ int delay(delayMin);
+ string dest("qmfc");
+
+ sessionId.generate();
+ queueName << "qmfc-" << sessionId;
+
+ while (true) {
+ try {
+ broker.topicBound = false;
+ broker.reqsOutstanding = 1;
+ connection.open(broker.connectionSettings);
+ session = connection.newSession(queueName.str());
+ subscriptions = new client::SubscriptionManager(session);
+
+ session.queueDeclare(arg::queue=queueName.str(), arg::autoDelete=true,
+ arg::exclusive=true);
+ session.exchangeBind(arg::exchange="amq.direct", arg::queue=queueName.str(),
+ arg::bindingKey=queueName.str());
+
+ subscriptions->setAcceptMode(ACCEPT_MODE_NONE);
+ subscriptions->setAcquireMode(ACQUIRE_MODE_PRE_ACQUIRED);
+ subscriptions->subscribe(broker, queueName.str(), dest);
+ subscriptions->setFlowControl(dest, FlowControl::unlimited());
+ {
+ Mutex::ScopedLock _lock(connLock);
+ if (shuttingDown)
+ return;
+ operational = true;
+ broker.resetAgents();
+ broker.connected = true;
+ broker.sessionManager.handleBrokerConnect(&broker);
+ broker.sessionManager.startProtocol(&broker);
+ try {
+ Mutex::ScopedUnlock _unlock(connLock);
+ subscriptions->run();
+ } catch (std::exception) {}
+
+ operational = false;
+ broker.connected = false;
+ broker.sessionManager.handleBrokerDisconnect(&broker);
+ }
+ delay = delayMin;
+ connection.close();
+ delete subscriptions;
+ subscriptions = 0;
+ } catch (std::exception &e) {
+ QPID_LOG(debug, " outer exception: " << e.what());
+ if (delay < delayMax)
+ delay *= delayFactor;
+ }
+
+ {
+ Mutex::ScopedLock _lock(connLock);
+ if (shuttingDown)
+ return;
+ {
+ Mutex::ScopedUnlock _unlock(connLock);
+ ::sleep(delay);
+ }
+ if (shuttingDown)
+ return;
+ }
+ }
+}
+
+Broker::ConnectionThread::~ConnectionThread()
+{
+ if (subscriptions != 0) {
+ delete subscriptions;
+ }
+}
+
+void Broker::ConnectionThread::sendBuffer(Buffer& buf, uint32_t length,
+ const string& exchange, const string& routingKey)
+{
+ {
+ Mutex::ScopedLock _lock(connLock);
+ if (!operational)
+ return;
+ }
+
+ client::Message msg;
+ string data;
+
+ buf.getRawData(data, length);
+ msg.getDeliveryProperties().setRoutingKey(routingKey);
+ msg.getMessageProperties().setReplyTo(ReplyTo("amq.direct", queueName.str()));
+ msg.setData(data);
+ try {
+ session.messageTransfer(arg::content=msg, arg::destination=exchange);
+ } catch(std::exception&) {}
+}
+
+void Broker::ConnectionThread::bindExchange(const std::string& exchange, const std::string& key)
+{
+ {
+ Mutex::ScopedLock _lock(connLock);
+ if (!operational)
+ return;
+ }
+
+ QPID_LOG(debug, "Broker::ConnectionThread::bindExchange: exchange=" << exchange << " key=" << key);
+ session.exchangeBind(arg::exchange=exchange, arg::queue=queueName.str(),
+ arg::bindingKey=key);
+}
+
+void Broker::ConnectionThread::shutdown()
+{
+ {
+ Mutex::ScopedLock _lock(connLock);
+ shuttingDown = true;
+ }
+ if (subscriptions)
+ subscriptions->stop();
+}
+
+void Broker::waitForStable()
+{
+ Mutex::ScopedLock l(lock);
+ if (reqsOutstanding == 0)
+ return;
+ syncInFlight = true;
+ while (reqsOutstanding != 0) {
+ bool result = cond.wait(lock, AbsTime(now(), TIME_SEC * sessionManager.settings.getTimeout));
+ if (!result)
+ throw(Exception("Timed out waiting for broker to synchronize"));
+ }
+}
+
+void Broker::incOutstanding()
+{
+ Mutex::ScopedLock l(lock);
+ reqsOutstanding++;
+}
+
+void Broker::decOutstanding()
+{
+ Mutex::ScopedLock l(lock);
+ reqsOutstanding--;
+ if (reqsOutstanding == 0) {
+ if (!topicBound) {
+ topicBound = true;
+ for (vector<string>::const_iterator iter = sessionManager.bindingKeyList.begin();
+ iter != sessionManager.bindingKeyList.end(); iter++)
+ connThreadBody.bindExchange("qpid.management", *iter);
+ }
+ if (syncInFlight) {
+ syncInFlight = false;
+ cond.notify();
+ }
+ }
+}
+
+void Broker::appendAgents(Agent::Vector& agentlist) const
+{
+ for (AgentMap::const_iterator iter = agents.begin(); iter != agents.end(); iter++) {
+ agentlist.push_back(iter->second);
+ }
+}
+
+ostream& qpid::console::operator<<(ostream& o, const Broker& k)
+{
+ o << "Broker: " << k.connectionSettings.host << ":" << k.connectionSettings.port;
+ return o;
+}
diff --git a/cpp/src/qpid/console/ClassKey.cpp b/cpp/src/qpid/console/ClassKey.cpp
new file mode 100644
index 0000000000..7a16113bae
--- /dev/null
+++ b/cpp/src/qpid/console/ClassKey.cpp
@@ -0,0 +1,105 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/console/ClassKey.h"
+#include <string.h>
+#include <cstdio>
+
+using namespace std;
+using namespace qpid::console;
+
+ClassKey::ClassKey(const string& _package, const string& _name, const uint8_t* _hash) :
+ package(_package), name(_name)
+{
+ ::memcpy(hash, _hash, HASH_SIZE);
+}
+
+string ClassKey::getHashString() const
+{
+ char cstr[36];
+ ::sprintf(cstr, "%02x%02x%02x%02x-%02x%02x%02x%02x-%02x%02x%02x%02x-%02x%02x%02x%02x",
+ hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7],
+ hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15]);
+ return string(cstr);
+}
+
+string ClassKey::str() const
+{
+ string result(package + ":" + name + "(" + getHashString() + ")");
+ return result;
+}
+
+bool ClassKey::operator==(const ClassKey& other) const
+{
+ return ::memcmp(hash, other.hash, HASH_SIZE) == 0 &&
+ name == other.name &&
+ package == other.package;
+}
+
+bool ClassKey::operator!=(const ClassKey& other) const
+{
+ return !(*this == other);
+}
+
+bool ClassKey::operator<(const ClassKey& other) const
+{
+ int cmp = ::memcmp(hash, other.hash, HASH_SIZE);
+ if (cmp != 0)
+ return cmp < 0;
+ cmp = name.compare(other.name);
+ if (cmp != 0)
+ return cmp < 0;
+ return package < other.package;
+}
+
+bool ClassKey::operator>(const ClassKey& other) const
+{
+ int cmp = ::memcmp(hash, other.hash, HASH_SIZE);
+ if (cmp != 0)
+ return cmp > 0;
+ cmp = name.compare(other.name);
+ if (cmp != 0)
+ return cmp > 0;
+ return package > other.package;
+}
+
+bool ClassKey::operator<=(const ClassKey& other) const
+{
+ return !(*this > other);
+}
+
+bool ClassKey::operator>=(const ClassKey& other) const
+{
+ return !(*this < other);
+}
+
+void ClassKey::encode(qpid::framing::Buffer& buffer) const
+{
+ buffer.putShortString(package);
+ buffer.putShortString(name);
+ buffer.putBin128(const_cast<uint8_t*>(hash));
+}
+
+ostream& qpid::console::operator<<(ostream& o, const ClassKey& k)
+{
+ o << k.str();
+ return o;
+}
diff --git a/cpp/src/qpid/console/Event.cpp b/cpp/src/qpid/console/Event.cpp
new file mode 100644
index 0000000000..3e14804b35
--- /dev/null
+++ b/cpp/src/qpid/console/Event.cpp
@@ -0,0 +1,205 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/console/Broker.h"
+#include "qpid/console/ClassKey.h"
+#include "qpid/console/Schema.h"
+#include "qpid/console/Event.h"
+#include "qpid/console/Value.h"
+#include "qpid/sys/Time.h"
+#include "qpid/framing/Buffer.h"
+
+using namespace qpid::console;
+using namespace std;
+using qpid::framing::Uuid;
+using qpid::framing::FieldTable;
+
+Event::Event(Broker* _broker, SchemaClass* _schema, qpid::framing::Buffer& buffer) :
+ broker(_broker), schema(_schema)
+{
+ timestamp = buffer.getLongLong();
+ severity = (Severity) buffer.getOctet();
+ for (vector<SchemaArgument*>::const_iterator aIter = schema->arguments.begin();
+ aIter != schema->arguments.end(); aIter++) {
+ SchemaArgument* argument = *aIter;
+ attributes[argument->name] = argument->decodeValue(buffer);
+ }
+}
+
+const ClassKey& Event::getClassKey() const
+{
+ return schema->getClassKey();
+}
+
+string Event::getSeverityString() const
+{
+ switch (severity) {
+ case SEV_EMERGENCY : return string("EMER");
+ case SEV_ALERT : return string("ALERT");
+ case SEV_CRITICAL : return string("CRIT");
+ case SEV_ERROR : return string("ERROR");
+ case SEV_WARNING : return string("WARN");
+ case SEV_NOTICE : return string("NOTIC");
+ case SEV_INFO : return string("INFO");
+ case SEV_DEBUG : return string("DEBUG");
+ }
+ return string("<UNKNOWN>");
+}
+
+ObjectId Event::attrRef(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return ObjectId();
+ Value::Ptr val = iter->second;
+ if (!val->isObjectId())
+ return ObjectId();
+ return val->asObjectId();
+}
+
+uint32_t Event::attrUint(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0;
+ Value::Ptr val = iter->second;
+ if (!val->isUint())
+ return 0;
+ return val->asUint();
+}
+
+int32_t Event::attrInt(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0;
+ Value::Ptr val = iter->second;
+ if (!val->isInt())
+ return 0;
+ return val->asInt();
+}
+
+uint64_t Event::attrUint64(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0;
+ Value::Ptr val = iter->second;
+ if (!val->isUint64())
+ return 0;
+ return val->asUint64();
+}
+
+int64_t Event::attrInt64(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0;
+ Value::Ptr val = iter->second;
+ if (!val->isInt64())
+ return 0;
+ return val->asInt64();
+}
+
+string Event::attrString(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return string();
+ Value::Ptr val = iter->second;
+ if (!val->isString())
+ return string();
+ return val->asString();
+}
+
+bool Event::attrBool(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return false;
+ Value::Ptr val = iter->second;
+ if (!val->isBool())
+ return false;
+ return val->asBool();
+}
+
+float Event::attrFloat(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0.0;
+ Value::Ptr val = iter->second;
+ if (!val->isFloat())
+ return 0.0;
+ return val->asFloat();
+}
+
+double Event::attrDouble(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0.0;
+ Value::Ptr val = iter->second;
+ if (!val->isDouble())
+ return 0.0;
+ return val->asDouble();
+}
+
+Uuid Event::attrUuid(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return Uuid();
+ Value::Ptr val = iter->second;
+ if (!val->isUuid())
+ return Uuid();
+ return val->asUuid();
+}
+
+FieldTable Event::attrMap(const string& key) const
+{
+ Object::AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return FieldTable();
+ Value::Ptr val = iter->second;
+ if (!val->isMap())
+ return FieldTable();
+ return val->asMap();
+}
+
+
+std::ostream& qpid::console::operator<<(std::ostream& o, const Event& event)
+{
+ const ClassKey& key = event.getClassKey();
+ sys::AbsTime aTime(sys::AbsTime(), sys::Duration(event.getTimestamp()));
+ o << aTime << " " << event.getSeverityString() << " " <<
+ key.getPackageName() << ":" << key.getClassName() <<
+ " broker=" << event.getBroker()->getUrl();
+
+ const Object::AttributeMap& attributes = event.getAttributes();
+ for (Object::AttributeMap::const_iterator iter = attributes.begin();
+ iter != attributes.end(); iter++) {
+ o << " " << iter->first << "=" << iter->second->str();
+ }
+ return o;
+}
+
+
diff --git a/cpp/src/qpid/console/Object.cpp b/cpp/src/qpid/console/Object.cpp
new file mode 100644
index 0000000000..6570e293ab
--- /dev/null
+++ b/cpp/src/qpid/console/Object.cpp
@@ -0,0 +1,384 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/console/SessionManager.h"
+#include "qpid/console/Broker.h"
+#include "qpid/console/Object.h"
+#include "qpid/console/Schema.h"
+#include "qpid/console/ClassKey.h"
+#include "qpid/console/Value.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/sys/Mutex.h"
+
+using namespace qpid::console;
+using namespace qpid::sys;
+using namespace qpid;
+using namespace std;
+using qpid::framing::Uuid;
+using qpid::framing::FieldTable;
+
+void Object::AttributeMap::addRef(const string& key, const ObjectId& val)
+{
+ (*this)[key] = Value::Ptr(new RefValue(val));
+}
+
+void Object::AttributeMap::addUint(const string& key, uint32_t val)
+{
+ (*this)[key] = Value::Ptr(new UintValue(val));
+}
+
+void Object::AttributeMap::addInt(const string& key, int32_t val)
+{
+ (*this)[key] = Value::Ptr(new IntValue(val));
+}
+
+void Object::AttributeMap::addUint64(const string& key, uint64_t val)
+{
+ (*this)[key] = Value::Ptr(new Uint64Value(val));
+}
+
+void Object::AttributeMap::addInt64(const string& key, int64_t val)
+{
+ (*this)[key] = Value::Ptr(new Int64Value(val));
+}
+
+void Object::AttributeMap::addString(const string& key, const string& val)
+{
+ (*this)[key] = Value::Ptr(new StringValue(val));
+}
+
+void Object::AttributeMap::addBool(const string& key, bool val)
+{
+ (*this)[key] = Value::Ptr(new BoolValue(val));
+}
+
+void Object::AttributeMap::addFloat(const string& key, float val)
+{
+ (*this)[key] = Value::Ptr(new FloatValue(val));
+}
+
+void Object::AttributeMap::addDouble(const string& key, double val)
+{
+ (*this)[key] = Value::Ptr(new DoubleValue(val));
+}
+
+void Object::AttributeMap::addUuid(const string& key, const Uuid& val)
+{
+ (*this)[key] = Value::Ptr(new UuidValue(val));
+}
+
+void Object::AttributeMap::addMap(const string& key, const FieldTable& val)
+{
+ (*this)[key] = Value::Ptr(new MapValue(val));
+}
+
+Object::Object(Broker* b, SchemaClass* s, framing::Buffer& buffer, bool prop, bool stat) :
+ broker(b), schema(s), pendingMethod(0)
+{
+ currentTime = buffer.getLongLong();
+ createTime = buffer.getLongLong();
+ deleteTime = buffer.getLongLong();
+ objectId.decode(buffer);
+
+ if (prop) {
+ set<string> excludes;
+ parsePresenceMasks(buffer, excludes);
+ for (vector<SchemaProperty*>::const_iterator pIter = schema->properties.begin();
+ pIter != schema->properties.end(); pIter++) {
+ SchemaProperty* property = *pIter;
+ if (excludes.count(property->name) != 0) {
+ attributes[property->name] = Value::Ptr(new NullValue());
+ } else {
+ attributes[property->name] = property->decodeValue(buffer);
+ }
+ }
+ }
+
+ if (stat) {
+ for (vector<SchemaStatistic*>::const_iterator sIter = schema->statistics.begin();
+ sIter != schema->statistics.end(); sIter++) {
+ SchemaStatistic* statistic = *sIter;
+ attributes[statistic->name] = statistic->decodeValue(buffer);
+ }
+ }
+}
+
+Object::~Object() {}
+
+const ClassKey& Object::getClassKey() const
+{
+ return schema->getClassKey();
+}
+
+string Object::getIndex() const
+{
+ string result;
+
+ for (vector<SchemaProperty*>::const_iterator pIter = schema->properties.begin();
+ pIter != schema->properties.end(); pIter++) {
+ SchemaProperty* property = *pIter;
+ if (property->isIndex) {
+ AttributeMap::const_iterator vIter = attributes.find(property->name);
+ if (vIter != attributes.end()) {
+ if (!result.empty())
+ result += ":";
+ result += vIter->second->str();
+ }
+ }
+ }
+ return result;
+}
+
+void Object::mergeUpdate(const Object& /*updated*/)
+{
+ // TODO
+}
+
+void Object::invokeMethod(const string name, const AttributeMap& args, MethodResponse& result)
+{
+ for (vector<SchemaMethod*>::const_iterator iter = schema->methods.begin();
+ iter != schema->methods.end(); iter++) {
+ if ((*iter)->name == name) {
+ SchemaMethod* method = *iter;
+ char rawbuffer[65536];
+ framing::Buffer buffer(rawbuffer, 65536);
+ uint32_t sequence = broker->sessionManager.sequenceManager.reserve("method");
+ pendingMethod = method;
+ broker->methodObject = this;
+ broker->encodeHeader(buffer, 'M', sequence);
+ objectId.encode(buffer);
+ schema->key.encode(buffer);
+ buffer.putShortString(name);
+
+ for (vector<SchemaArgument*>::const_iterator aIter = method->arguments.begin();
+ aIter != method->arguments.end(); aIter++) {
+ SchemaArgument* arg = *aIter;
+ if (arg->dirInput) {
+ AttributeMap::const_iterator attr = args.find(arg->name);
+ if (attr != args.end()) {
+ ValueFactory::encodeValue(arg->typeCode, attr->second, buffer);
+ } else {
+ // TODO Use the default value instead of throwing
+ throw Exception("Missing arguments in method call");
+ }
+ }
+ }
+
+ uint32_t length = buffer.getPosition();
+ buffer.reset();
+ stringstream routingKey;
+ routingKey << "agent." << objectId.getBrokerBank() << "." << objectId.getAgentBank();
+ broker->connThreadBody.sendBuffer(buffer, length, "qpid.management", routingKey.str());
+
+ {
+ Mutex::ScopedLock l(broker->lock);
+ bool ok = true;
+ while (pendingMethod != 0 && ok) {
+ ok = broker->cond.wait(broker->lock, AbsTime(now(), broker->sessionManager.settings.methodTimeout * TIME_SEC));
+ }
+
+ if (!ok) {
+ result.code = 0x1001;
+ result.text.assign("Method call timed out");
+ result.arguments.clear();
+ } else {
+ result = methodResponse;
+ }
+ }
+ }
+ }
+}
+
+void Object::handleMethodResp(framing::Buffer& buffer, uint32_t sequence)
+{
+ broker->sessionManager.sequenceManager.release(sequence);
+ methodResponse.code = buffer.getLong();
+ buffer.getMediumString(methodResponse.text);
+ methodResponse.arguments.clear();
+
+ for (vector<SchemaArgument*>::const_iterator aIter = pendingMethod->arguments.begin();
+ aIter != pendingMethod->arguments.end(); aIter++) {
+ SchemaArgument* arg = *aIter;
+ if (arg->dirOutput) {
+ methodResponse.arguments[arg->name] = arg->decodeValue(buffer);
+ }
+ }
+
+ {
+ Mutex::ScopedLock l(broker->lock);
+ pendingMethod = 0;
+ broker->cond.notify();
+ }
+}
+
+ObjectId Object::attrRef(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return ObjectId();
+ Value::Ptr val = iter->second;
+ if (!val->isObjectId())
+ return ObjectId();
+ return val->asObjectId();
+}
+
+uint32_t Object::attrUint(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0;
+ Value::Ptr val = iter->second;
+ if (!val->isUint())
+ return 0;
+ return val->asUint();
+}
+
+int32_t Object::attrInt(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0;
+ Value::Ptr val = iter->second;
+ if (!val->isInt())
+ return 0;
+ return val->asInt();
+}
+
+uint64_t Object::attrUint64(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0;
+ Value::Ptr val = iter->second;
+ if (!val->isUint64())
+ return 0;
+ return val->asUint64();
+}
+
+int64_t Object::attrInt64(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0;
+ Value::Ptr val = iter->second;
+ if (!val->isInt64())
+ return 0;
+ return val->asInt64();
+}
+
+string Object::attrString(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return string();
+ Value::Ptr val = iter->second;
+ if (!val->isString())
+ return string();
+ return val->asString();
+}
+
+bool Object::attrBool(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return false;
+ Value::Ptr val = iter->second;
+ if (!val->isBool())
+ return false;
+ return val->asBool();
+}
+
+float Object::attrFloat(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0.0;
+ Value::Ptr val = iter->second;
+ if (!val->isFloat())
+ return 0.0;
+ return val->asFloat();
+}
+
+double Object::attrDouble(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return 0.0;
+ Value::Ptr val = iter->second;
+ if (!val->isDouble())
+ return 0.0;
+ return val->asDouble();
+}
+
+Uuid Object::attrUuid(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return Uuid();
+ Value::Ptr val = iter->second;
+ if (!val->isUuid())
+ return Uuid();
+ return val->asUuid();
+}
+
+FieldTable Object::attrMap(const string& key) const
+{
+ AttributeMap::const_iterator iter = attributes.find(key);
+ if (iter == attributes.end())
+ return FieldTable();
+ Value::Ptr val = iter->second;
+ if (!val->isMap())
+ return FieldTable();
+ return val->asMap();
+}
+
+void Object::parsePresenceMasks(framing::Buffer& buffer, set<string>& excludeList)
+{
+ excludeList.clear();
+ uint8_t bit = 0;
+ uint8_t mask = 0;
+
+ for (vector<SchemaProperty*>::const_iterator pIter = schema->properties.begin();
+ pIter != schema->properties.end(); pIter++) {
+ SchemaProperty* property = *pIter;
+ if (property->isOptional) {
+ if (bit == 0) {
+ mask = buffer.getOctet();
+ bit = 1;
+ }
+ if ((mask & bit) == 0)
+ excludeList.insert(property->name);
+ if (bit == 0x80)
+ bit = 0;
+ else
+ bit = bit << 1;
+ }
+ }
+}
+
+ostream& qpid::console::operator<<(ostream& o, const Object& object)
+{
+ const ClassKey& key = object.getClassKey();
+ o << key.getPackageName() << ":" << key.getClassName() << "[" << object.getObjectId() << "] " <<
+ object.getIndex();
+ return o;
+}
+
diff --git a/cpp/src/qpid/console/ObjectId.cpp b/cpp/src/qpid/console/ObjectId.cpp
new file mode 100644
index 0000000000..fbaad20d57
--- /dev/null
+++ b/cpp/src/qpid/console/ObjectId.cpp
@@ -0,0 +1,91 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/console/ObjectId.h"
+#include "qpid/framing/Buffer.h"
+
+using namespace qpid::console;
+using namespace qpid;
+using namespace std;
+
+ObjectId::ObjectId(framing::Buffer& buffer)
+{
+ decode(buffer);
+}
+
+void ObjectId::decode(framing::Buffer& buffer)
+{
+ first = buffer.getLongLong();
+ second = buffer.getLongLong();
+}
+
+void ObjectId::encode(framing::Buffer& buffer)
+{
+ buffer.putLongLong(first);
+ buffer.putLongLong(second);
+}
+
+bool ObjectId::operator==(const ObjectId& other) const
+{
+ return second == other.second && first == other.first;
+}
+
+bool ObjectId::operator!=(const ObjectId& other) const
+{
+ return !(*this == other);
+}
+
+bool ObjectId::operator<(const ObjectId& other) const
+{
+ if (first < other.first)
+ return true;
+ if (first > other.first)
+ return false;
+ return second < other.second;
+}
+
+bool ObjectId::operator>(const ObjectId& other) const
+{
+ if (first > other.first)
+ return true;
+ if (first < other.first)
+ return false;
+ return second > other.second;
+}
+
+bool ObjectId::operator<=(const ObjectId& other) const
+{
+ return !(*this > other);
+}
+
+bool ObjectId::operator>=(const ObjectId& other) const
+{
+ return !(*this < other);
+}
+
+ostream& qpid::console::operator<<(ostream& o, const ObjectId& id)
+{
+ o << (int) id.getFlags() << "-" << id.getSequence() << "-" << id.getBrokerBank() << "-" <<
+ id.getAgentBank() << "-" << id.getObject();
+ return o;
+}
+
+
diff --git a/cpp/src/qpid/console/Package.cpp b/cpp/src/qpid/console/Package.cpp
new file mode 100644
index 0000000000..e5d6fa29fd
--- /dev/null
+++ b/cpp/src/qpid/console/Package.cpp
@@ -0,0 +1,41 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/console/Package.h"
+
+using namespace qpid::console;
+
+SchemaClass* Package::getClass(const std::string& className, uint8_t* hash)
+{
+ NameHash key(className, hash);
+ ClassMap::iterator iter = classes.find(key);
+ if (iter != classes.end())
+ return iter->second;
+ return 0;
+}
+
+void Package::addClass(const std::string& className, uint8_t* hash, SchemaClass* schemaClass)
+{
+ NameHash key(className, hash);
+ ClassMap::iterator iter = classes.find(key);
+ if (iter == classes.end())
+ classes[key] = schemaClass;
+}
diff --git a/cpp/src/qpid/console/Schema.cpp b/cpp/src/qpid/console/Schema.cpp
new file mode 100644
index 0000000000..a3dbd91201
--- /dev/null
+++ b/cpp/src/qpid/console/Schema.cpp
@@ -0,0 +1,165 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/console/Schema.h"
+#include "qpid/console/Value.h"
+#include "qpid/framing/FieldTable.h"
+
+using namespace qpid::console;
+using namespace qpid;
+using std::string;
+using std::vector;
+
+SchemaArgument::SchemaArgument(framing::Buffer& buffer, bool forMethod)
+{
+ framing::FieldTable map;
+ map.decode(buffer);
+
+ name = map.getAsString("name");
+ typeCode = map.getAsInt("type");
+ unit = map.getAsString("unit");
+ min = map.getAsInt("min");
+ max = map.getAsInt("max");
+ maxLen = map.getAsInt("maxlen");
+ desc = map.getAsString("desc");
+
+ dirInput = false;
+ dirOutput = false;
+ if (forMethod) {
+ string dir(map.getAsString("dir"));
+ if (dir.find('I') != dir.npos || dir.find('i') != dir.npos)
+ dirInput = true;
+ if (dir.find('O') != dir.npos || dir.find('o') != dir.npos)
+ dirOutput = true;
+ }
+}
+
+Value::Ptr SchemaArgument::decodeValue(framing::Buffer& buffer)
+{
+ return ValueFactory::newValue(typeCode, buffer);
+}
+
+SchemaProperty::SchemaProperty(framing::Buffer& buffer)
+{
+ framing::FieldTable map;
+ map.decode(buffer);
+
+ name = map.getAsString("name");
+ typeCode = map.getAsInt("type");
+ accessCode = map.getAsInt("access");
+ isIndex = map.getAsInt("index") != 0;
+ isOptional = map.getAsInt("optional") != 0;
+ unit = map.getAsString("unit");
+ min = map.getAsInt("min");
+ max = map.getAsInt("max");
+ maxLen = map.getAsInt("maxlen");
+ desc = map.getAsString("desc");
+}
+
+Value::Ptr SchemaProperty::decodeValue(framing::Buffer& buffer)
+{
+ return ValueFactory::newValue(typeCode, buffer);
+}
+
+SchemaStatistic::SchemaStatistic(framing::Buffer& buffer)
+{
+ framing::FieldTable map;
+ map.decode(buffer);
+
+ name = map.getAsString("name");
+ typeCode = map.getAsInt("type");
+ unit = map.getAsString("unit");
+ desc = map.getAsString("desc");
+}
+
+Value::Ptr SchemaStatistic::decodeValue(framing::Buffer& buffer)
+{
+ return ValueFactory::newValue(typeCode, buffer);
+}
+
+SchemaMethod::SchemaMethod(framing::Buffer& buffer)
+{
+ framing::FieldTable map;
+ map.decode(buffer);
+
+ name = map.getAsString("name");
+ desc = map.getAsString("desc");
+ int argCount = map.getAsInt("argCount");
+
+ for (int i = 0; i < argCount; i++)
+ arguments.push_back(new SchemaArgument(buffer, true));
+}
+
+SchemaMethod::~SchemaMethod()
+{
+ for (vector<SchemaArgument*>::iterator iter = arguments.begin();
+ iter != arguments.end(); iter++)
+ delete *iter;
+}
+
+SchemaClass::SchemaClass(const uint8_t _kind, const ClassKey& _key, framing::Buffer& buffer) :
+ kind(_kind), key(_key)
+{
+ if (kind == KIND_TABLE) {
+ uint8_t hasSupertype = 0; //buffer.getOctet();
+ uint16_t propCount = buffer.getShort();
+ uint16_t statCount = buffer.getShort();
+ uint16_t methodCount = buffer.getShort();
+
+ if (hasSupertype) {
+ string unused;
+ buffer.getShortString(unused);
+ buffer.getShortString(unused);
+ buffer.getLongLong();
+ buffer.getLongLong();
+ }
+
+ for (uint16_t idx = 0; idx < propCount; idx++)
+ properties.push_back(new SchemaProperty(buffer));
+ for (uint16_t idx = 0; idx < statCount; idx++)
+ statistics.push_back(new SchemaStatistic(buffer));
+ for (uint16_t idx = 0; idx < methodCount; idx++)
+ methods.push_back(new SchemaMethod(buffer));
+
+ } else if (kind == KIND_EVENT) {
+ uint16_t argCount = buffer.getShort();
+
+ for (uint16_t idx = 0; idx < argCount; idx++)
+ arguments.push_back(new SchemaArgument(buffer));
+ }
+}
+
+SchemaClass::~SchemaClass()
+{
+ for (vector<SchemaProperty*>::iterator iter = properties.begin();
+ iter != properties.end(); iter++)
+ delete *iter;
+ for (vector<SchemaStatistic*>::iterator iter = statistics.begin();
+ iter != statistics.end(); iter++)
+ delete *iter;
+ for (vector<SchemaMethod*>::iterator iter = methods.begin();
+ iter != methods.end(); iter++)
+ delete *iter;
+ for (vector<SchemaArgument*>::iterator iter = arguments.begin();
+ iter != arguments.end(); iter++)
+ delete *iter;
+}
+
diff --git a/cpp/src/qpid/console/SequenceManager.cpp b/cpp/src/qpid/console/SequenceManager.cpp
new file mode 100644
index 0000000000..86ea829749
--- /dev/null
+++ b/cpp/src/qpid/console/SequenceManager.cpp
@@ -0,0 +1,48 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/console/SequenceManager.h"
+
+using namespace qpid::console;
+using namespace qpid::sys;
+using std::string;
+using std::cout;
+using std::endl;
+
+uint32_t SequenceManager::reserve(const std::string& context)
+{
+ Mutex::ScopedLock l(lock);
+ uint32_t result = sequence++;
+ pending[result] = context;
+ return result;
+}
+
+std::string SequenceManager::release(uint32_t seq)
+{
+ Mutex::ScopedLock l(lock);
+ std::map<uint32_t, string>::iterator iter = pending.find(seq);
+ if (iter == pending.end())
+ return string();
+ string result(iter->second);
+ pending.erase(iter);
+ return result;
+}
+
diff --git a/cpp/src/qpid/console/SessionManager.cpp b/cpp/src/qpid/console/SessionManager.cpp
new file mode 100644
index 0000000000..0285c5f34a
--- /dev/null
+++ b/cpp/src/qpid/console/SessionManager.cpp
@@ -0,0 +1,481 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/console/SessionManager.h"
+#include "qpid/console/Schema.h"
+#include "qpid/console/Agent.h"
+#include "qpid/console/ConsoleListener.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/Time.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/framing/FieldTable.h"
+
+using namespace qpid::console;
+using namespace qpid::sys;
+using namespace qpid;
+using namespace std;
+using qpid::framing::Buffer;
+using qpid::framing::FieldTable;
+
+SessionManager::SessionManager(ConsoleListener* _listener, Settings _settings) :
+ listener(_listener), settings(_settings)
+{
+ bindingKeys();
+}
+
+SessionManager::~SessionManager()
+{
+ for (vector<Broker*>::iterator iter = brokers.begin();
+ iter != brokers.end(); iter++)
+ delete *iter;
+}
+
+Broker* SessionManager::addBroker(client::ConnectionSettings& settings)
+{
+ Broker* broker(new Broker(*this, settings));
+ {
+ Mutex::ScopedLock l(brokerListLock);
+ brokers.push_back(broker);
+ }
+ return broker;
+}
+
+void SessionManager::delBroker(Broker* broker)
+{
+ Mutex::ScopedLock l(brokerListLock);
+ for (vector<Broker*>::iterator iter = brokers.begin();
+ iter != brokers.end(); iter++)
+ if (*iter == broker) {
+ brokers.erase(iter);
+ delete broker;
+ return;
+ }
+}
+
+void SessionManager::getPackages(NameVector& packageNames)
+{
+ allBrokersStable();
+ packageNames.clear();
+ {
+ Mutex::ScopedLock l(lock);
+ for (map<string, Package*>::iterator iter = packages.begin();
+ iter != packages.end(); iter++)
+ packageNames.push_back(iter->first);
+ }
+}
+
+void SessionManager::getClasses(KeyVector& classKeys, const std::string& packageName)
+{
+ allBrokersStable();
+ classKeys.clear();
+ map<string, Package*>::iterator iter = packages.find(packageName);
+ if (iter == packages.end())
+ return;
+
+ Package& package = *(iter->second);
+ for (Package::ClassMap::const_iterator piter = package.classes.begin();
+ piter != package.classes.end(); piter++) {
+ ClassKey key(piter->second->getClassKey());
+ classKeys.push_back(key);
+ }
+}
+
+SchemaClass& SessionManager::getSchema(const ClassKey& classKey)
+{
+ allBrokersStable();
+ map<string, Package*>::iterator iter = packages.find(classKey.getPackageName());
+ if (iter == packages.end())
+ throw Exception("Unknown package");
+
+ Package& package = *(iter->second);
+ Package::NameHash key(classKey.getClassName(), classKey.getHash());
+ Package::ClassMap::iterator cIter = package.classes.find(key);
+ if (cIter == package.classes.end())
+ throw Exception("Unknown class");
+
+ return *(cIter->second);
+}
+
+void SessionManager::bindPackage(const std::string& packageName)
+{
+ stringstream key;
+ key << "console.obj.*.*." << packageName << ".#";
+ bindingKeyList.push_back(key.str());
+ for (vector<Broker*>::iterator iter = brokers.begin(); iter != brokers.end(); iter++)
+ (*iter)->addBinding(key.str());
+}
+
+void SessionManager::bindClass(const ClassKey& classKey)
+{
+ bindClass(classKey.getPackageName(), classKey.getClassName());
+}
+
+void SessionManager::bindClass(const std::string& packageName, const std::string& className)
+{
+ stringstream key;
+ key << "console.obj.*.*." << packageName << "." << className << ".#";
+ bindingKeyList.push_back(key.str());
+ for (vector<Broker*>::iterator iter = brokers.begin();
+ iter != brokers.end(); iter++)
+ (*iter)->addBinding(key.str());
+}
+
+void SessionManager::getAgents(Agent::Vector& agents, Broker* broker)
+{
+ agents.clear();
+ if (broker != 0) {
+ broker->appendAgents(agents);
+ } else {
+ for (vector<Broker*>::iterator iter = brokers.begin(); iter != brokers.end(); iter++) {
+ (*iter)->appendAgents(agents);
+ }
+ }
+}
+
+void SessionManager::getObjects(Object::Vector& objects, const std::string& className,
+ Broker* _broker, Agent* _agent)
+{
+ Agent::Vector agentList;
+
+ if (_agent != 0) {
+ agentList.push_back(_agent);
+ _agent->getBroker()->waitForStable();
+ } else {
+ if (_broker != 0) {
+ _broker->appendAgents(agentList);
+ _broker->waitForStable();
+ } else {
+ allBrokersStable();
+ Mutex::ScopedLock _lock(brokerListLock);
+ for (vector<Broker*>::iterator iter = brokers.begin(); iter != brokers.end(); iter++) {
+ (*iter)->appendAgents(agentList);
+ }
+ }
+ }
+
+ FieldTable ft;
+ uint32_t sequence;
+ ft.setString("_class", className);
+
+ getResult.clear();
+ syncSequenceList.clear();
+ error = string();
+
+ if (agentList.empty()) {
+ objects = getResult;
+ return;
+ }
+
+ for (Agent::Vector::iterator iter = agentList.begin(); iter != agentList.end(); iter++) {
+ Agent* agent = *iter;
+ char rawbuffer[512];
+ Buffer buffer(rawbuffer, 512);
+ stringstream routingKey;
+ routingKey << "agent." << agent->getBrokerBank() << "." << agent->getAgentBank();
+ {
+ Mutex::ScopedLock _lock(lock);
+ sequence = sequenceManager.reserve("multiget");
+ syncSequenceList.insert(sequence);
+ }
+ agent->getBroker()->encodeHeader(buffer, 'G', sequence);
+ ft.encode(buffer);
+ uint32_t length = buffer.getPosition();
+ buffer.reset();
+ agent->getBroker()->connThreadBody.sendBuffer(buffer, length, "qpid.management", routingKey.str());
+ }
+
+ {
+ Mutex::ScopedLock _lock(lock);
+ sys::AbsTime startTime = sys::now();
+ while (!syncSequenceList.empty() && error.empty()) {
+ cv.wait(lock, AbsTime(now(), settings.getTimeout * TIME_SEC));
+ sys::AbsTime currTime = sys::now();
+ if (sys::Duration(startTime, currTime) > settings.getTimeout * TIME_SEC)
+ break;
+ }
+ }
+
+ objects = getResult;
+}
+
+void SessionManager::bindingKeys()
+{
+ bindingKeyList.push_back("schema.#");
+ if (settings.rcvObjects && settings.rcvEvents && settings.rcvHeartbeats && !settings.userBindings) {
+ bindingKeyList.push_back("console.#");
+ } else {
+ if (settings.rcvObjects && !settings.userBindings)
+ bindingKeyList.push_back("console.obj.#");
+ else
+ bindingKeyList.push_back("console.obj.*.*.org.apache.qpid.broker.agent");
+ if (settings.rcvEvents)
+ bindingKeyList.push_back("console.event.#");
+ if (settings.rcvHeartbeats)
+ bindingKeyList.push_back("console.heartbeat");
+ }
+}
+
+void SessionManager::allBrokersStable()
+{
+ Mutex::ScopedLock l(brokerListLock);
+ for (vector<Broker*>::iterator iter = brokers.begin();
+ iter != brokers.end(); iter++)
+ if ((*iter)->isConnected())
+ (*iter)->waitForStable();
+}
+
+void SessionManager::startProtocol(Broker* broker)
+{
+ char rawbuffer[512];
+ Buffer buffer(rawbuffer, 512);
+
+ broker->encodeHeader(buffer, 'B');
+ uint32_t length = 512 - buffer.available();
+ buffer.reset();
+ broker->connThreadBody.sendBuffer(buffer, length);
+}
+
+
+void SessionManager::handleBrokerResp(Broker* broker, Buffer& inBuffer, uint32_t)
+{
+ framing::Uuid brokerId;
+
+ brokerId.decode(inBuffer);
+ broker->setBrokerId(brokerId);
+
+ char rawbuffer[512];
+ Buffer buffer(rawbuffer, 512);
+
+ uint32_t sequence = sequenceManager.reserve("startup");
+ broker->encodeHeader(buffer, 'P', sequence);
+ uint32_t length = 512 - buffer.available();
+ buffer.reset();
+ broker->connThreadBody.sendBuffer(buffer, length);
+
+ if (listener != 0) {
+ listener->brokerInfo(*broker);
+ }
+}
+
+void SessionManager::handlePackageInd(Broker* broker, Buffer& inBuffer, uint32_t)
+{
+ string packageName;
+ inBuffer.getShortString(packageName);
+
+ {
+ Mutex::ScopedLock l(lock);
+ map<string, Package*>::iterator iter = packages.find(packageName);
+ if (iter == packages.end()) {
+ packages[packageName] = new Package(packageName);
+ if (listener != 0)
+ listener->newPackage(packageName);
+ }
+ }
+
+ broker->incOutstanding();
+ char rawbuffer[512];
+ Buffer buffer(rawbuffer, 512);
+
+ uint32_t sequence = sequenceManager.reserve("startup");
+ broker->encodeHeader(buffer, 'Q', sequence);
+ buffer.putShortString(packageName);
+ uint32_t length = 512 - buffer.available();
+ buffer.reset();
+ broker->connThreadBody.sendBuffer(buffer, length);
+}
+
+void SessionManager::handleCommandComplete(Broker* broker, Buffer& inBuffer, uint32_t sequence)
+{
+ Mutex::ScopedLock l(lock);
+ uint32_t resultCode = inBuffer.getLong();
+ string resultText;
+ inBuffer.getShortString(resultText);
+ string context = sequenceManager.release(sequence);
+ if (resultCode != 0)
+ QPID_LOG(debug, "Received error in completion: " << resultCode << " " << resultText);
+ if (context == "startup") {
+ broker->decOutstanding();
+ } else if (context == "multiget") {
+ if (syncSequenceList.count(sequence) == 1) {
+ syncSequenceList.erase(sequence);
+ if (syncSequenceList.empty()) {
+ cv.notify();
+ }
+ }
+ }
+ // TODO: Other context cases
+}
+
+void SessionManager::handleClassInd(Broker* broker, Buffer& inBuffer, uint32_t)
+{
+ uint8_t kind;
+ string packageName;
+ string className;
+ uint8_t hash[16];
+
+ kind = inBuffer.getOctet();
+ inBuffer.getShortString(packageName);
+ inBuffer.getShortString(className);
+ inBuffer.getBin128(hash);
+
+ {
+ Mutex::ScopedLock l(lock);
+ map<string, Package*>::iterator pIter = packages.find(packageName);
+ if (pIter == packages.end() || pIter->second->getClass(className, hash))
+ return;
+ }
+
+ broker->incOutstanding();
+ char rawbuffer[512];
+ Buffer buffer(rawbuffer, 512);
+
+ uint32_t sequence = sequenceManager.reserve("startup");
+ broker->encodeHeader(buffer, 'S', sequence);
+ buffer.putShortString(packageName);
+ buffer.putShortString(className);
+ buffer.putBin128(hash);
+ uint32_t length = 512 - buffer.available();
+ buffer.reset();
+ broker->connThreadBody.sendBuffer(buffer, length);
+}
+
+void SessionManager::handleMethodResp(Broker* broker, Buffer& buffer, uint32_t sequence)
+{
+ if (broker->methodObject) {
+ broker->methodObject->handleMethodResp(buffer, sequence);
+ }
+}
+
+void SessionManager::handleHeartbeatInd(Broker* /*broker*/, Buffer& /*inBuffer*/, uint32_t /*sequence*/)
+{
+}
+
+void SessionManager::handleEventInd(Broker* broker, Buffer& buffer, uint32_t /*sequence*/)
+{
+ string packageName;
+ string className;
+ uint8_t hash[16];
+ SchemaClass* schemaClass;
+
+ buffer.getShortString(packageName);
+ buffer.getShortString(className);
+ buffer.getBin128(hash);
+
+ {
+ Mutex::ScopedLock l(lock);
+ map<string, Package*>::iterator pIter = packages.find(packageName);
+ if (pIter == packages.end())
+ return;
+ schemaClass = pIter->second->getClass(className, hash);
+ if (schemaClass == 0)
+ return;
+ }
+
+ Event event(broker, schemaClass, buffer);
+
+ if (listener)
+ listener->event(event);
+}
+
+void SessionManager::handleSchemaResp(Broker* broker, Buffer& inBuffer, uint32_t sequence)
+{
+ uint8_t kind;
+ string packageName;
+ string className;
+ uint8_t hash[16];
+
+ kind = inBuffer.getOctet();
+ inBuffer.getShortString(packageName);
+ inBuffer.getShortString(className);
+ inBuffer.getBin128(hash);
+
+ {
+ Mutex::ScopedLock l(lock);
+ map<string, Package*>::iterator pIter = packages.find(packageName);
+ if (pIter != packages.end() && !pIter->second->getClass(className, hash)) {
+ ClassKey key(packageName, className, hash);
+ SchemaClass* schemaClass(new SchemaClass(kind, key, inBuffer));
+ pIter->second->addClass(className, hash, schemaClass);
+ if (listener != 0) {
+ listener->newClass(schemaClass->getClassKey());
+ }
+ }
+ }
+
+ sequenceManager.release(sequence);
+ broker->decOutstanding();
+}
+
+void SessionManager::handleContentInd(Broker* broker, Buffer& buffer, uint32_t sequence, bool prop, bool stat)
+{
+ string packageName;
+ string className;
+ uint8_t hash[16];
+ SchemaClass* schemaClass;
+
+ buffer.getShortString(packageName);
+ buffer.getShortString(className);
+ buffer.getBin128(hash);
+
+ {
+ Mutex::ScopedLock l(lock);
+ map<string, Package*>::iterator pIter = packages.find(packageName);
+ if (pIter == packages.end())
+ return;
+ schemaClass = pIter->second->getClass(className, hash);
+ if (schemaClass == 0)
+ return;
+ }
+
+ Object object(broker, schemaClass, buffer, prop, stat);
+
+ if (prop && className == "agent" && packageName == "org.apache.qpid.broker")
+ broker->updateAgent(object);
+
+ {
+ Mutex::ScopedLock l(lock);
+ if (syncSequenceList.count(sequence) == 1) {
+ if (!object.isDeleted())
+ getResult.push_back(object);
+ return;
+ }
+ }
+
+ if (listener) {
+ if (prop)
+ listener->objectProps(*broker, object);
+ if (stat)
+ listener->objectStats(*broker, object);
+ }
+}
+
+void SessionManager::handleBrokerConnect(Broker* broker)
+{
+ if (listener != 0)
+ listener->brokerConnected(*broker);
+}
+
+void SessionManager::handleBrokerDisconnect(Broker* broker)
+{
+ if (listener != 0)
+ listener->brokerDisconnected(*broker);
+}
+
diff --git a/cpp/src/qpid/console/Value.cpp b/cpp/src/qpid/console/Value.cpp
new file mode 100644
index 0000000000..c30660f1dc
--- /dev/null
+++ b/cpp/src/qpid/console/Value.cpp
@@ -0,0 +1,169 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/console/Value.h"
+#include "qpid/framing/Buffer.h"
+
+using namespace qpid;
+using namespace qpid::console;
+using namespace std;
+
+string NullValue::str() const
+{
+ return "<Null>";
+}
+
+RefValue::RefValue(framing::Buffer& buffer)
+{
+ uint64_t first = buffer.getLongLong();
+ uint64_t second = buffer.getLongLong();
+ value.setValue(first, second);
+}
+
+string RefValue::str() const
+{
+ stringstream s;
+ s << value;
+ return s.str();
+}
+
+string UintValue::str() const
+{
+ stringstream s;
+ s << value;
+ return s.str();
+}
+
+string IntValue::str() const
+{
+ stringstream s;
+ s << value;
+ return s.str();
+}
+
+string Uint64Value::str() const
+{
+ stringstream s;
+ s << value;
+ return s.str();
+}
+
+string Int64Value::str() const
+{
+ stringstream s;
+ s << value;
+ return s.str();
+}
+
+StringValue::StringValue(framing::Buffer& buffer, int tc)
+{
+ if (tc == 6)
+ buffer.getShortString(value);
+ else
+ buffer.getMediumString(value);
+}
+
+string BoolValue::str() const
+{
+ return value ? "T" : "F";
+}
+
+string FloatValue::str() const
+{
+ stringstream s;
+ s << value;
+ return s.str();
+}
+
+string DoubleValue::str() const
+{
+ stringstream s;
+ s << value;
+ return s.str();
+}
+
+UuidValue::UuidValue(framing::Buffer& buffer)
+{
+ value.decode(buffer);
+}
+
+string MapValue::str() const
+{
+ stringstream s;
+ s << value;
+ return s.str();
+}
+
+MapValue::MapValue(framing::Buffer& buffer)
+{
+ value.decode(buffer);
+}
+
+
+Value::Ptr ValueFactory::newValue(int typeCode, framing::Buffer& buffer)
+{
+ switch (typeCode) {
+ case 1: return Value::Ptr(new UintValue(buffer.getOctet())); // U8
+ case 2: return Value::Ptr(new UintValue(buffer.getShort())); // U16
+ case 3: return Value::Ptr(new UintValue(buffer.getLong())); // U32
+ case 4: return Value::Ptr(new Uint64Value(buffer.getLongLong())); // U64
+ case 6: return Value::Ptr(new StringValue(buffer, 6)); // SSTR
+ case 7: return Value::Ptr(new StringValue(buffer, 7)); // LSTR
+ case 8: return Value::Ptr(new Int64Value(buffer.getLongLong())); // ABSTIME
+ case 9: return Value::Ptr(new Uint64Value(buffer.getLongLong())); // DELTATIME
+ case 10: return Value::Ptr(new RefValue(buffer)); // REF
+ case 11: return Value::Ptr(new BoolValue(buffer.getOctet())); // BOOL
+ case 12: return Value::Ptr(new FloatValue(buffer.getFloat())); // FLOAT
+ case 13: return Value::Ptr(new DoubleValue(buffer.getDouble())); // DOUBLE
+ case 14: return Value::Ptr(new UuidValue(buffer)); // UUID
+ case 15: return Value::Ptr(new MapValue(buffer)); // MAP
+ case 16: return Value::Ptr(new IntValue(buffer.getOctet())); // S8
+ case 17: return Value::Ptr(new IntValue(buffer.getShort())); // S16
+ case 18: return Value::Ptr(new IntValue(buffer.getLong())); // S32
+ case 19: return Value::Ptr(new Int64Value(buffer.getLongLong())); // S64
+ }
+
+ return Value::Ptr();
+}
+
+void ValueFactory::encodeValue(int typeCode, Value::Ptr value, framing::Buffer& buffer)
+{
+ switch (typeCode) {
+ case 1: buffer.putOctet(value->asUint()); return; // U8
+ case 2: buffer.putShort(value->asUint()); return; // U16
+ case 3: buffer.putLong(value->asUint()); return; // U32
+ case 4: buffer.putLongLong(value->asUint64()); return; // U64
+ case 6: buffer.putShortString(value->asString()); return; // SSTR
+ case 7: buffer.putMediumString(value->asString()); return; // LSTR
+ case 8: buffer.putLongLong(value->asInt64()); return; // ABSTIME
+ case 9: buffer.putLongLong(value->asUint64()); return; // DELTATIME
+ case 10: value->asObjectId().encode(buffer); return; // REF
+ case 11: buffer.putOctet(value->asBool() ? 1 : 0); return; // BOOL
+ case 12: buffer.putFloat(value->asFloat()); return; // FLOAT
+ case 13: buffer.putDouble(value->asDouble()); return; // DOUBLE
+ case 14: value->asUuid().encode(buffer); return; // UUID
+ case 15: value->asMap().encode(buffer); return; // MAP
+ case 16: buffer.putOctet(value->asInt()); return; // S8
+ case 17: buffer.putShort(value->asInt()); return; // S16
+ case 18: buffer.putLong(value->asInt()); return; // S32
+ case 19: buffer.putLongLong(value->asInt64()); return; // S64
+ }
+}
diff --git a/cpp/src/qpid/doxygen_mainpage.h b/cpp/src/qpid/doxygen_mainpage.h
deleted file mode 100644
index 1502ef536e..0000000000
--- a/cpp/src/qpid/doxygen_mainpage.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// This header file is just for doxygen documentation purposes.
-
-/** \mainpage Qpid C++ Developer Kit.
- *
- * The <a href=http://incubator.apache.org/qpid>Qpid project</a> provides implementations of the <a href="http://amqp.org/">AMQP messaging specification</a> in several programming language.
- *
- * Qpidc provides APIs and libraries to implement AMQP clients in
- * C++. Qpidc clients can interact with any compliant AMQP message
- * broker. The Qpid project also provides an AMQP broker daemon called
- * qpidd that you can use with your qpidc clients.
- *
- * See the \ref clientapi "client API reference" to get started.
- *
- */
-
-
-/**
- * \defgroup clientapi Application API for an AMQP client.
- *
- * A typical client takes the following steps:
- * - Connect to the broker using qpid::client::Connection::open()
- * - Create a qpid::client::Session object.
- *
- * Once a session is created the client can work with the broker:
- * - Create and bind queues using the qpid::client::Session commands.
- * - Send messages using qpid::client::Session::messageTransfer.
- * - Subscribe to queues using qpid::client::SubscriptionManager
- */
diff --git a/cpp/src/qpid/framing/AMQBody.h b/cpp/src/qpid/framing/AMQBody.h
index f3bf65470c..60ac2d3b7e 100644
--- a/cpp/src/qpid/framing/AMQBody.h
+++ b/cpp/src/qpid/framing/AMQBody.h
@@ -22,8 +22,11 @@
*
*/
#include "qpid/framing/amqp_types.h"
-
+#include "qpid/RefCounted.h"
+#include "qpid/framing/BodyFactory.h"
+#include <boost/intrusive_ptr.hpp>
#include <ostream>
+#include "qpid/CommonImportExport.h"
namespace qpid {
namespace framing {
@@ -43,16 +46,20 @@ struct AMQBodyConstVisitor {
virtual void visit(const AMQMethodBody&) = 0;
};
-class AMQBody
-{
+class AMQBody : public RefCounted {
public:
- virtual ~AMQBody();
+ AMQBody() {}
+ QPID_COMMON_EXTERN virtual ~AMQBody();
+
+ // Make AMQBody copyable even though RefCounted.
+ AMQBody(const AMQBody&) : RefCounted() {}
+ AMQBody& operator=(const AMQBody&) { return *this; }
virtual uint8_t type() const = 0;
virtual void encode(Buffer& buffer) const = 0;
virtual void decode(Buffer& buffer, uint32_t=0) = 0;
- virtual uint32_t size() const = 0;
+ virtual uint32_t encodedSize() const = 0;
virtual void print(std::ostream& out) const = 0;
virtual void accept(AMQBodyConstVisitor&) const = 0;
@@ -62,9 +69,10 @@ class AMQBody
/** Match if same type and same class/method ID for methods */
static bool match(const AMQBody& , const AMQBody& );
+ virtual boost::intrusive_ptr<AMQBody> clone() const = 0;
};
-std::ostream& operator<<(std::ostream& out, const AMQBody& body) ;
+QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& out, const AMQBody& body) ;
enum BodyTypes {
METHOD_BODY = 1,
diff --git a/cpp/src/qpid/framing/AMQCommandControlBody.h b/cpp/src/qpid/framing/AMQCommandControlBody.h
index 388fb48299..d12b70a168 100644
--- a/cpp/src/qpid/framing/AMQCommandControlBody.h
+++ b/cpp/src/qpid/framing/AMQCommandControlBody.h
@@ -43,7 +43,7 @@ template <class T> class AMQCommandControlBody : public AMQBody, public T
virtual void decode(Buffer& buffer, uint32_t=0) {
Codec::decode(buffer.getIterator(), static_cast<T&>(*this));
}
- virtual uint32_t size() const {
+ virtual uint32_t encodedSize() const {
Codec::size(buffer.getIterator(), static_cast<const T&>(*this));
}
diff --git a/cpp/src/qpid/framing/AMQContentBody.cpp b/cpp/src/qpid/framing/AMQContentBody.cpp
index 59f3619ef2..72f7d9978e 100644
--- a/cpp/src/qpid/framing/AMQContentBody.cpp
+++ b/cpp/src/qpid/framing/AMQContentBody.cpp
@@ -18,7 +18,7 @@
* under the License.
*
*/
-#include "AMQContentBody.h"
+#include "qpid/framing/AMQContentBody.h"
#include <iostream>
qpid::framing::AMQContentBody::AMQContentBody(){
@@ -27,7 +27,7 @@ qpid::framing::AMQContentBody::AMQContentBody(){
qpid::framing::AMQContentBody::AMQContentBody(const string& _data) : data(_data){
}
-uint32_t qpid::framing::AMQContentBody::size() const{
+uint32_t qpid::framing::AMQContentBody::encodedSize() const{
return data.size();
}
void qpid::framing::AMQContentBody::encode(Buffer& buffer) const{
@@ -39,6 +39,8 @@ void qpid::framing::AMQContentBody::decode(Buffer& buffer, uint32_t _size){
void qpid::framing::AMQContentBody::print(std::ostream& out) const
{
- out << "content (" << size() << " bytes)";
- out << " " << data.substr(0,16) << "...";
+ out << "content (" << encodedSize() << " bytes)";
+ const size_t max = 32;
+ out << " " << data.substr(0, max);
+ if (data.size() > max) out << "...";
}
diff --git a/cpp/src/qpid/framing/AMQContentBody.h b/cpp/src/qpid/framing/AMQContentBody.h
index 5d530a1b9a..69813b221c 100644
--- a/cpp/src/qpid/framing/AMQContentBody.h
+++ b/cpp/src/qpid/framing/AMQContentBody.h
@@ -18,9 +18,10 @@
* under the License.
*
*/
-#include "amqp_types.h"
-#include "AMQBody.h"
-#include "Buffer.h"
+#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/AMQBody.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/CommonImportExport.h"
#ifndef _AMQContentBody_
#define _AMQContentBody_
@@ -33,17 +34,18 @@ class AMQContentBody : public AMQBody
string data;
public:
- AMQContentBody();
- AMQContentBody(const string& data);
+ QPID_COMMON_EXTERN AMQContentBody();
+ QPID_COMMON_EXTERN AMQContentBody(const string& data);
inline virtual ~AMQContentBody(){}
- inline uint8_t type() const { return CONTENT_BODY; };
- inline const string& getData() const { return data; }
- inline string& getData() { return data; }
- uint32_t size() const;
- void encode(Buffer& buffer) const;
- void decode(Buffer& buffer, uint32_t size);
- void print(std::ostream& out) const;
- void accept(AMQBodyConstVisitor& v) const { v.visit(*this); }
+ QPID_COMMON_EXTERN inline uint8_t type() const { return CONTENT_BODY; };
+ QPID_COMMON_EXTERN inline const string& getData() const { return data; }
+ QPID_COMMON_EXTERN inline string& getData() { return data; }
+ QPID_COMMON_EXTERN uint32_t encodedSize() const;
+ QPID_COMMON_EXTERN void encode(Buffer& buffer) const;
+ QPID_COMMON_EXTERN void decode(Buffer& buffer, uint32_t size);
+ QPID_COMMON_EXTERN void print(std::ostream& out) const;
+ QPID_COMMON_EXTERN void accept(AMQBodyConstVisitor& v) const { v.visit(*this); }
+ QPID_COMMON_EXTERN boost::intrusive_ptr<AMQBody> clone() const { return BodyFactory::copy(*this); }
};
}
diff --git a/cpp/src/qpid/framing/AMQDataBlock.h b/cpp/src/qpid/framing/AMQDataBlock.h
index 9b6fdfd966..7f0d0dc2b5 100644
--- a/cpp/src/qpid/framing/AMQDataBlock.h
+++ b/cpp/src/qpid/framing/AMQDataBlock.h
@@ -18,7 +18,7 @@
* under the License.
*
*/
-#include "Buffer.h"
+#include "qpid/framing/Buffer.h"
#ifndef _AMQDataBlock_
#define _AMQDataBlock_
@@ -32,7 +32,7 @@ public:
virtual ~AMQDataBlock() {}
virtual void encode(Buffer& buffer) const = 0;
virtual bool decode(Buffer& buffer) = 0;
- virtual uint32_t size() const = 0;
+ virtual uint32_t encodedSize() const = 0;
};
}
diff --git a/cpp/src/qpid/framing/AMQFrame.cpp b/cpp/src/qpid/framing/AMQFrame.cpp
index c1fc647b52..5c5920d786 100644
--- a/cpp/src/qpid/framing/AMQFrame.cpp
+++ b/cpp/src/qpid/framing/AMQFrame.cpp
@@ -18,33 +18,66 @@
* under the License.
*
*/
-#include "AMQFrame.h"
+#include "qpid/framing/AMQFrame.h"
-#include "qpid/framing/variant.h"
#include "qpid/framing/AMQMethodBody.h"
#include "qpid/framing/reply_exceptions.h"
-
+#include "qpid/framing/BodyFactory.h"
+#include "qpid/framing/MethodBodyFactory.h"
#include <boost/format.hpp>
-
#include <iostream>
namespace qpid {
namespace framing {
+void AMQFrame::init() {
+ bof = eof = bos = eos = true;
+ subchannel=0;
+ channel=0;
+ encodedSizeCache = 0;
+}
+
+AMQFrame::AMQFrame(const boost::intrusive_ptr<AMQBody>& b) : body(b) { init(); }
+
+AMQFrame::AMQFrame(const AMQBody& b) : body(b.clone()) { init(); }
+
AMQFrame::~AMQFrame() {}
-void AMQFrame::setBody(const AMQBody& b) { body = new BodyHolder(b); }
+AMQBody* AMQFrame::getBody() {
+ // Non-const AMQBody* may be used to modify the body.
+ encodedSizeCache = 0;
+ return body.get();
+}
+
+const AMQBody* AMQFrame::getBody() const {
+ return body.get();
+}
-void AMQFrame::setMethod(ClassId c, MethodId m) { body = new BodyHolder(c,m); }
+void AMQFrame::setMethod(ClassId c, MethodId m) {
+ encodedSizeCache = 0;
+ body = MethodBodyFactory::create(c,m);
+}
-uint32_t AMQFrame::size() const {
- return frameOverhead() + body->size();
+uint32_t AMQFrame::encodedSize() const {
+ if (!encodedSizeCache) {
+ encodedSizeCache = frameOverhead() + body->encodedSize();
+ if (body->getMethod())
+ encodedSizeCache += sizeof(ClassId)+sizeof(MethodId);
+ }
+ return encodedSizeCache;
}
uint32_t AMQFrame::frameOverhead() {
return 12 /*frame header*/;
}
+uint16_t AMQFrame::DECODE_SIZE_MIN=4;
+
+uint16_t AMQFrame::decodeSize(char* data) {
+ Buffer buf(data+2, DECODE_SIZE_MIN);
+ return buf.getShort();
+}
+
void AMQFrame::encode(Buffer& buffer) const
{
//set track first (controls on track 0, everything else on 1):
@@ -53,20 +86,27 @@ void AMQFrame::encode(Buffer& buffer) const
uint8_t flags = (bof ? 0x08 : 0) | (eof ? 0x04 : 0) | (bos ? 0x02 : 0) | (eos ? 0x01 : 0);
buffer.putOctet(flags);
buffer.putOctet(getBody()->type());
- buffer.putShort(size());
+ buffer.putShort(encodedSize());
buffer.putOctet(0);
buffer.putOctet(0x0f & track);
buffer.putShort(channel);
buffer.putLong(0);
+ const AMQMethodBody* method=getMethod();
+ if (method) {
+ buffer.putOctet(method->amqpClassId());
+ buffer.putOctet(method->amqpMethodId());
+ }
body->encode(buffer);
}
bool AMQFrame::decode(Buffer& buffer)
-{
+{
if(buffer.available() < frameOverhead())
return false;
buffer.record();
+ encodedSizeCache = 0;
+ uint32_t start = buffer.getPosition();
uint8_t flags = buffer.getOctet();
uint8_t framing_version = (flags & 0xc0) >> 6;
if (framing_version != 0)
@@ -98,8 +138,24 @@ bool AMQFrame::decode(Buffer& buffer)
buffer.restore();
return false;
}
- body = new BodyHolder();
- body->decode(type,buffer, body_size);
+
+ switch(type)
+ {
+ case 0://CONTROL
+ case METHOD_BODY: {
+ ClassId c = buffer.getOctet();
+ MethodId m = buffer.getOctet();
+ body = MethodBodyFactory::create(c, m);
+ break;
+ }
+ case HEADER_BODY: body = BodyFactory::create<AMQHeaderBody>(); break;
+ case CONTENT_BODY: body = BodyFactory::create<AMQContentBody>(); break;
+ case HEARTBEAT_BODY: body = BodyFactory::create<AMQHeartbeatBody>(); break;
+ default:
+ throw IllegalArgumentException(QPID_MSG("Invalid frame type " << type));
+ }
+ body->decode(buffer, body_size);
+ encodedSizeCache = buffer.getPosition() - start;
return true;
}
diff --git a/cpp/src/qpid/framing/AMQFrame.h b/cpp/src/qpid/framing/AMQFrame.h
index 5a8e55f9d2..29e368b671 100644
--- a/cpp/src/qpid/framing/AMQFrame.h
+++ b/cpp/src/qpid/framing/AMQFrame.h
@@ -21,50 +21,33 @@
* under the License.
*
*/
-#include "AMQDataBlock.h"
-#include "AMQHeaderBody.h"
-#include "AMQContentBody.h"
-#include "AMQHeartbeatBody.h"
-#include "ProtocolVersion.h"
-#include "BodyHolder.h"
-
+#include "qpid/framing/AMQDataBlock.h"
+#include "qpid/framing/AMQHeaderBody.h"
+#include "qpid/framing/AMQContentBody.h"
+#include "qpid/framing/AMQHeartbeatBody.h"
+#include "qpid/framing/ProtocolVersion.h"
#include <boost/intrusive_ptr.hpp>
#include <boost/cast.hpp>
+#include "qpid/CommonImportExport.h"
namespace qpid {
namespace framing {
-class BodyHolder;
-
class AMQFrame : public AMQDataBlock
{
public:
- AMQFrame(boost::intrusive_ptr<BodyHolder> b=0) : body(b) { init(); }
- AMQFrame(const AMQBody& b) { setBody(b); init(); }
- ~AMQFrame();
-
- template <class InPlace>
- AMQFrame(const InPlace& ip, typename EnableInPlace<InPlace>::type* =0) {
- init(); setBody(ip);
- }
+ QPID_COMMON_EXTERN AMQFrame(const boost::intrusive_ptr<AMQBody>& b=0);
+ QPID_COMMON_EXTERN AMQFrame(const AMQBody& b);
+ QPID_COMMON_EXTERN ~AMQFrame();
ChannelId getChannel() const { return channel; }
void setChannel(ChannelId c) { channel = c; }
- boost::intrusive_ptr<BodyHolder> getHolder() { return body; }
-
- AMQBody* getBody() { return body ? body->get() : 0; }
- const AMQBody* getBody() const { return body ? body->get() : 0; }
+ QPID_COMMON_EXTERN AMQBody* getBody();
+ QPID_COMMON_EXTERN const AMQBody* getBody() const;
- AMQMethodBody* getMethod() { return getBody()->getMethod(); }
- const AMQMethodBody* getMethod() const { return getBody()->getMethod(); }
-
- void setBody(const AMQBody& b);
-
- template <class InPlace>
- typename EnableInPlace<InPlace>::type setBody(const InPlace& ip) {
- body = new BodyHolder(ip);
- }
+ AMQMethodBody* getMethod() { return getBody() ? getBody()->getMethod() : 0; }
+ const AMQMethodBody* getMethod() const { return getBody() ? getBody()->getMethod() : 0; }
void setMethod(ClassId c, MethodId m);
@@ -76,9 +59,9 @@ class AMQFrame : public AMQDataBlock
return boost::polymorphic_downcast<const T*>(getBody());
}
- void encode(Buffer& buffer) const;
- bool decode(Buffer& buffer);
- uint32_t size() const;
+ QPID_COMMON_EXTERN void encode(Buffer& buffer) const;
+ QPID_COMMON_EXTERN bool decode(Buffer& buffer);
+ QPID_COMMON_EXTERN uint32_t encodedSize() const;
// 0-10 terminology: first/last frame (in segment) first/last segment (in assembly)
@@ -104,20 +87,25 @@ class AMQFrame : public AMQDataBlock
bool getEos() const { return eos; }
void setEos(bool isEos) { eos = isEos; }
- static uint32_t frameOverhead();
+ static uint16_t DECODE_SIZE_MIN;
+ QPID_COMMON_EXTERN static uint32_t frameOverhead();
+ /** Must point to at least DECODE_SIZE_MIN bytes of data */
+ static uint16_t decodeSize(char* data);
+
private:
- void init() { bof = eof = bos = eos = true; subchannel=0; channel=0; }
+ void init();
- boost::intrusive_ptr<BodyHolder> body;
+ boost::intrusive_ptr<AMQBody> body;
uint16_t channel : 16;
uint8_t subchannel : 8;
bool bof : 1;
bool eof : 1;
bool bos : 1;
bool eos : 1;
+ mutable uint32_t encodedSizeCache;
};
-std::ostream& operator<<(std::ostream&, const AMQFrame&);
+QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, const AMQFrame&);
}} // namespace qpid::framing
diff --git a/cpp/src/qpid/framing/AMQHeaderBody.cpp b/cpp/src/qpid/framing/AMQHeaderBody.cpp
index 724c288705..14218f1b45 100644
--- a/cpp/src/qpid/framing/AMQHeaderBody.cpp
+++ b/cpp/src/qpid/framing/AMQHeaderBody.cpp
@@ -18,12 +18,12 @@
* under the License.
*
*/
-#include "AMQHeaderBody.h"
+#include "qpid/framing/AMQHeaderBody.h"
#include "qpid/Exception.h"
#include "qpid/log/Statement.h"
-uint32_t qpid::framing::AMQHeaderBody::size() const {
- return properties.size();
+uint32_t qpid::framing::AMQHeaderBody::encodedSize() const {
+ return properties.encodedSize();
}
void qpid::framing::AMQHeaderBody::encode(Buffer& buffer) const {
@@ -52,7 +52,7 @@ uint64_t qpid::framing::AMQHeaderBody::getContentLength() const
void qpid::framing::AMQHeaderBody::print(std::ostream& out) const
{
- out << "header (" << size() << " bytes)";
+ out << "header (" << encodedSize() << " bytes)";
out << "; properties={";
properties.print(out);
out << "}";
diff --git a/cpp/src/qpid/framing/AMQHeaderBody.h b/cpp/src/qpid/framing/AMQHeaderBody.h
index c69a768291..8d96e35720 100644
--- a/cpp/src/qpid/framing/AMQHeaderBody.h
+++ b/cpp/src/qpid/framing/AMQHeaderBody.h
@@ -21,11 +21,12 @@
* under the License.
*
*/
-#include "amqp_types.h"
-#include "AMQBody.h"
-#include "Buffer.h"
+#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/AMQBody.h"
+#include "qpid/framing/Buffer.h"
#include "qpid/framing/DeliveryProperties.h"
#include "qpid/framing/MessageProperties.h"
+#include "qpid/CommonImportExport.h"
#include <iostream>
#include <boost/optional.hpp>
@@ -34,16 +35,14 @@
namespace qpid {
namespace framing {
-enum DeliveryMode { TRANSIENT = 1, PERSISTENT = 2};
-
class AMQHeaderBody : public AMQBody
{
template <class T> struct OptProps { boost::optional<T> props; };
template <class Base, class T>
struct PropSet : public Base, public OptProps<T> {
- uint32_t size() const {
+ uint32_t encodedSize() const {
const boost::optional<T>& p=this->OptProps<T>::props;
- return (p ? p->size() : 0) + Base::size();
+ return (p ? p->encodedSize() : 0) + Base::encodedSize();
}
void encode(Buffer& buffer) const {
const boost::optional<T>& p=this->OptProps<T>::props;
@@ -68,7 +67,7 @@ class AMQHeaderBody : public AMQBody
};
struct Empty {
- uint32_t size() const { return 0; }
+ uint32_t encodedSize() const { return 0; }
void encode(Buffer&) const {};
bool decode(Buffer&, uint32_t, uint16_t) const { return false; };
void print(std::ostream&) const {}
@@ -83,12 +82,12 @@ public:
inline uint8_t type() const { return HEADER_BODY; }
- uint32_t size() const;
- void encode(Buffer& buffer) const;
- void decode(Buffer& buffer, uint32_t size);
- uint64_t getContentLength() const;
- void print(std::ostream& out) const;
- void accept(AMQBodyConstVisitor&) const;
+ QPID_COMMON_EXTERN uint32_t encodedSize() const;
+ QPID_COMMON_EXTERN void encode(Buffer& buffer) const;
+ QPID_COMMON_EXTERN void decode(Buffer& buffer, uint32_t size);
+ QPID_COMMON_EXTERN uint64_t getContentLength() const;
+ QPID_COMMON_EXTERN void print(std::ostream& out) const;
+ QPID_COMMON_EXTERN void accept(AMQBodyConstVisitor&) const;
template <class T> T* get(bool create) {
boost::optional<T>& p=properties.OptProps<T>::props;
@@ -99,6 +98,8 @@ public:
template <class T> const T* get() const {
return properties.OptProps<T>::props.get_ptr();
}
+
+ boost::intrusive_ptr<AMQBody> clone() const { return BodyFactory::copy(*this); }
};
}}
diff --git a/cpp/src/qpid/framing/AMQHeartbeatBody.cpp b/cpp/src/qpid/framing/AMQHeartbeatBody.cpp
index 140ce2e794..477616221c 100644
--- a/cpp/src/qpid/framing/AMQHeartbeatBody.cpp
+++ b/cpp/src/qpid/framing/AMQHeartbeatBody.cpp
@@ -19,7 +19,7 @@
*
*/
-#include "AMQHeartbeatBody.h"
+#include "qpid/framing/AMQHeartbeatBody.h"
#include <iostream>
qpid::framing::AMQHeartbeatBody::~AMQHeartbeatBody() {}
diff --git a/cpp/src/qpid/framing/AMQHeartbeatBody.h b/cpp/src/qpid/framing/AMQHeartbeatBody.h
index a2701c3398..9b1fe8a4c1 100644
--- a/cpp/src/qpid/framing/AMQHeartbeatBody.h
+++ b/cpp/src/qpid/framing/AMQHeartbeatBody.h
@@ -18,9 +18,10 @@
* under the License.
*
*/
-#include "amqp_types.h"
-#include "AMQBody.h"
-#include "Buffer.h"
+#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/AMQBody.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/CommonImportExport.h"
#ifndef _AMQHeartbeatBody_
#define _AMQHeartbeatBody_
@@ -31,13 +32,14 @@ namespace framing {
class AMQHeartbeatBody : public AMQBody
{
public:
- virtual ~AMQHeartbeatBody();
- inline uint32_t size() const { return 0; }
+ QPID_COMMON_EXTERN virtual ~AMQHeartbeatBody();
+ inline uint32_t encodedSize() const { return 0; }
inline uint8_t type() const { return HEARTBEAT_BODY; }
inline void encode(Buffer& ) const {}
inline void decode(Buffer& , uint32_t /*size*/) {}
- virtual void print(std::ostream& out) const;
+ QPID_COMMON_EXTERN virtual void print(std::ostream& out) const;
void accept(AMQBodyConstVisitor& v) const { v.visit(*this); }
+ boost::intrusive_ptr<AMQBody> clone() const { return BodyFactory::copy(*this); }
};
}
diff --git a/cpp/src/qpid/framing/AMQMethodBody.cpp b/cpp/src/qpid/framing/AMQMethodBody.cpp
index 924d906d43..594af4c6dc 100644
--- a/cpp/src/qpid/framing/AMQMethodBody.cpp
+++ b/cpp/src/qpid/framing/AMQMethodBody.cpp
@@ -18,7 +18,7 @@
* under the License.
*
*/
-#include "AMQMethodBody.h"
+#include "qpid/framing/AMQMethodBody.h"
namespace qpid {
namespace framing {
diff --git a/cpp/src/qpid/framing/AMQMethodBody.h b/cpp/src/qpid/framing/AMQMethodBody.h
index da28ee3aa9..c634180712 100644
--- a/cpp/src/qpid/framing/AMQMethodBody.h
+++ b/cpp/src/qpid/framing/AMQMethodBody.h
@@ -21,13 +21,13 @@
* under the License.
*
*/
-#include "amqp_types.h"
-#include "AMQBody.h"
+#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/AMQBody.h"
#include "qpid/framing/ProtocolVersion.h"
-#include "qpid/shared_ptr.h"
+#include "qpid/CommonImportExport.h"
+#include <boost/shared_ptr.hpp>
#include <ostream>
-
#include <assert.h>
namespace qpid {
@@ -40,7 +40,7 @@ class MethodBodyConstVisitor;
class AMQMethodBody : public AMQBody {
public:
AMQMethodBody() {}
- virtual ~AMQMethodBody();
+ QPID_COMMON_EXTERN virtual ~AMQMethodBody();
virtual void accept(MethodBodyConstVisitor&) const = 0;
@@ -54,7 +54,7 @@ class AMQMethodBody : public AMQBody {
return amqpClassId()==T::CLASS_ID && amqpMethodId()==T::METHOD_ID;
}
- virtual uint32_t size() const = 0;
+ virtual uint32_t encodedSize() const = 0;
virtual uint8_t type() const { return METHOD_BODY; }
virtual bool isSync() const { return false; /*only ModelMethods can have the sync flag set*/ }
diff --git a/cpp/src/qpid/framing/AccumulatedAck.cpp b/cpp/src/qpid/framing/AccumulatedAck.cpp
index 2d3ecf3f6a..2e6433a82f 100644
--- a/cpp/src/qpid/framing/AccumulatedAck.cpp
+++ b/cpp/src/qpid/framing/AccumulatedAck.cpp
@@ -18,7 +18,7 @@
* under the License.
*
*/
-#include "AccumulatedAck.h"
+#include "qpid/framing/AccumulatedAck.h"
#include <assert.h>
#include <iostream>
diff --git a/cpp/src/qpid/framing/AccumulatedAck.h b/cpp/src/qpid/framing/AccumulatedAck.h
index ea78b797e0..8e241b4ba1 100644
--- a/cpp/src/qpid/framing/AccumulatedAck.h
+++ b/cpp/src/qpid/framing/AccumulatedAck.h
@@ -25,8 +25,9 @@
#include <functional>
#include <list>
#include <ostream>
-#include "SequenceNumber.h"
-#include "SequenceNumberSet.h"
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/framing/SequenceNumberSet.h"
+#include "qpid/CommonImportExport.h"
namespace qpid {
namespace framing {
@@ -58,17 +59,17 @@ namespace qpid {
*/
std::list<Range> ranges;
- explicit AccumulatedAck(SequenceNumber r = SequenceNumber());
- void update(SequenceNumber firstTag, SequenceNumber lastTag);
- void consolidate();
- void clear();
- bool covers(SequenceNumber tag) const;
+ QPID_COMMON_EXTERN explicit AccumulatedAck(SequenceNumber r = SequenceNumber());
+ QPID_COMMON_EXTERN void update(SequenceNumber firstTag, SequenceNumber lastTag);
+ QPID_COMMON_EXTERN void consolidate();
+ QPID_COMMON_EXTERN void clear();
+ QPID_COMMON_EXTERN bool covers(SequenceNumber tag) const;
void collectRanges(SequenceNumberSet& set) const;
- void update(const SequenceNumber cumulative, const SequenceNumberSet& range);
+ QPID_COMMON_EXTERN void update(const SequenceNumber cumulative, const SequenceNumberSet& range);
void operator()(SequenceNumber first, SequenceNumber last) { update(first, last); }
};
- std::ostream& operator<<(std::ostream&, const Range&);
- std::ostream& operator<<(std::ostream&, const AccumulatedAck&);
+ QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, const Range&);
+ QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, const AccumulatedAck&);
}
}
diff --git a/cpp/src/qpid/framing/Array.cpp b/cpp/src/qpid/framing/Array.cpp
index f0b6331ff3..d95e0d167d 100644
--- a/cpp/src/qpid/framing/Array.cpp
+++ b/cpp/src/qpid/framing/Array.cpp
@@ -18,9 +18,9 @@
* under the License.
*
*/
-#include "Array.h"
-#include "Buffer.h"
-#include "FieldValue.h"
+#include "qpid/framing/Array.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/FieldValue.h"
#include "qpid/Exception.h"
#include "qpid/framing/reply_exceptions.h"
#include <assert.h>
@@ -28,25 +28,26 @@
namespace qpid {
namespace framing {
-Array::Array() : typeOctet(0xF0/*void*/) {}
+Array::Array() : type(TYPE_CODE_VOID) {}
-Array::Array(uint8_t type) : typeOctet(type) {}
+Array::Array(TypeCode t) : type(t) {}
+
+Array::Array(uint8_t t) : type(typeCode(t)) {}
Array::Array(const std::vector<std::string>& in)
{
- typeOctet = 0xA4;
+ type = TYPE_CODE_STR16;
for (std::vector<std::string>::const_iterator i = in.begin(); i != in.end(); ++i) {
- ValuePtr value(new StringValue(*i));
+ ValuePtr value(new Str16Value(*i));
values.push_back(value);
}
}
-
-uint32_t Array::size() const {
+uint32_t Array::encodedSize() const {
//note: size is only included when used as a 'top level' type
uint32_t len(4/*size*/ + 1/*type*/ + 4/*count*/);
for(ValueVector::const_iterator i = values.begin(); i != values.end(); ++i) {
- len += (*i)->getData().size();
+ len += (*i)->getData().encodedSize();
}
return len;
}
@@ -55,18 +56,18 @@ int Array::count() const {
return values.size();
}
-std::ostream& operator<<(std::ostream& out, const Array& t) {
- out << "{";
- for(Array::ValueVector::const_iterator i = t.values.begin(); i != t.values.end(); ++i) {
- if (i != t.values.begin()) out << ", ";
- out << *(i->get());
+std::ostream& operator<<(std::ostream& out, const Array& a) {
+ out << typeName(a.getType()) << "{";
+ for(Array::ValueVector::const_iterator i = a.values.begin(); i != a.values.end(); ++i) {
+ if (i != a.values.begin()) out << ", ";
+ (*i)->print(out);
}
return out << "}";
}
void Array::encode(Buffer& buffer) const{
- buffer.putLong(size() - 4);//size added only when array is a top-level type
- buffer.putOctet(typeOctet);
+ buffer.putLong(encodedSize() - 4);//size added only when array is a top-level type
+ buffer.putOctet(type);
buffer.putLong(count());
for (ValueVector::const_iterator i = values.begin(); i!=values.end(); ++i) {
(*i)->getData().encode(buffer);
@@ -74,6 +75,7 @@ void Array::encode(Buffer& buffer) const{
}
void Array::decode(Buffer& buffer){
+ values.clear();
uint32_t size = buffer.getLong();//size added only when array is a top-level type
uint32_t available = buffer.available();
if (available < size) {
@@ -81,21 +83,21 @@ void Array::decode(Buffer& buffer){
<< size << " bytes but only " << available << " available"));
}
if (size) {
- typeOctet = buffer.getOctet();
+ type = TypeCode(buffer.getOctet());
uint32_t count = buffer.getLong();
FieldValue dummy;
- dummy.setType(typeOctet);
+ dummy.setType(type);
available = buffer.available();
- if (available < count * dummy.getData().size()) {
+ if (available < count * dummy.getData().encodedSize()) {
throw IllegalArgumentException(QPID_MSG("Not enough data for array, expected "
- << count << " items of " << dummy.getData().size()
+ << count << " items of " << dummy.getData().encodedSize()
<< " bytes each but only " << available << " bytes available"));
}
for (uint32_t i = 0; i < count; i++) {
ValuePtr value(new FieldValue);
- value->setType(typeOctet);
+ value->setType(type);
value->getData().decode(buffer);
values.push_back(ValuePtr(value));
}
@@ -104,7 +106,7 @@ void Array::decode(Buffer& buffer){
bool Array::operator==(const Array& x) const {
- if (typeOctet != x.typeOctet) return false;
+ if (type != x.type) return false;
if (values.size() != x.values.size()) return false;
for (ValueVector::const_iterator i = values.begin(), j = x.values.begin(); i != values.end(); ++i, ++j) {
@@ -114,12 +116,13 @@ bool Array::operator==(const Array& x) const {
return true;
}
-void Array::add(ValuePtr value)
-{
- if (typeOctet != value->getType()) {
- throw IllegalArgumentException(QPID_MSG("Wrong type of value, expected " << typeOctet));
+void Array::insert(iterator i, ValuePtr value) {
+ if (type != value->getType()) {
+ // FIXME aconway 2008-10-31: put meaningful strings in this message.
+ throw Exception(QPID_MSG("Wrong type of value in Array, expected " << type
+ << " but found " << TypeCode(value->getType())));
}
- values.push_back(value);
+ values.insert(i, value);
}
diff --git a/cpp/src/qpid/framing/Array.h b/cpp/src/qpid/framing/Array.h
deleted file mode 100644
index 2cbd4c0b29..0000000000
--- a/cpp/src/qpid/framing/Array.h
+++ /dev/null
@@ -1,78 +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 <iostream>
-#include <vector>
-#include <boost/shared_ptr.hpp>
-#include <map>
-#include "amqp_types.h"
-#include "FieldValue.h"
-
-#ifndef _Array_
-#define _Array_
-
-namespace qpid {
-namespace framing {
-
-class Buffer;
-
-class Array
-{
- public:
- typedef boost::shared_ptr<FieldValue> ValuePtr;
- typedef std::vector<ValuePtr> ValueVector;
-
- uint32_t size() const;
- void encode(Buffer& buffer) const;
- void decode(Buffer& buffer);
-
- int count() const;
- bool operator==(const Array& other) const;
-
- Array();
- Array(uint8_t type);
- //creates a longstr array
- Array(const std::vector<std::string>& in);
-
- void add(ValuePtr value);
-
- template <class T>
- void collect(std::vector<T>& out) const
- {
- for (ValueVector::const_iterator i = values.begin(); i != values.end(); ++i) {
- out.push_back((*i)->get<T>());
- }
- }
-
- private:
- uint8_t typeOctet;
- ValueVector values;
-
- ValueVector::const_iterator begin() const { return values.begin(); }
- ValueVector::const_iterator end() const { return values.end(); }
-
- friend std::ostream& operator<<(std::ostream& out, const Array& body);
-};
-
-}
-}
-
-
-#endif
diff --git a/cpp/src/qpid/framing/Blob.cpp b/cpp/src/qpid/framing/Blob.cpp
index 388d4b64ef..0c8316f3d2 100644
--- a/cpp/src/qpid/framing/Blob.cpp
+++ b/cpp/src/qpid/framing/Blob.cpp
@@ -18,7 +18,7 @@
*
*/
-#include "Blob.h"
+#include "qpid/framing/Blob.h"
namespace qpid {
diff --git a/cpp/src/qpid/framing/Blob.h b/cpp/src/qpid/framing/Blob.h
index 5c84384ad7..e69de29bb2 100644
--- a/cpp/src/qpid/framing/Blob.h
+++ b/cpp/src/qpid/framing/Blob.h
@@ -1,197 +0,0 @@
-#ifndef QPID_FRAMING_BLOB_H
-#define QPID_FRAMING_BLOB_H
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <boost/static_assert.hpp>
-#include <boost/aligned_storage.hpp>
-#include <boost/checked_delete.hpp>
-#include <boost/utility/typed_in_place_factory.hpp>
-#include <boost/type_traits/is_base_and_derived.hpp>
-#include <boost/utility/enable_if.hpp>
-#include <boost/version.hpp>
-
-#include <new>
-
-#include <assert.h>
-
-
-namespace qpid {
-namespace framing {
-
-using boost::in_place;
-using boost::typed_in_place_factory_base;
-
-/** 0-arg typed_in_place_factory, missing in pre-1.35 boost. */
-#if (BOOST_VERSION < 103500)
-template <class T>
-struct typed_in_place_factory0 : public typed_in_place_factory_base {
- typedef T value_type ;
- void apply ( void* address ) const { new (address) T(); }
-};
-
-/** 0-arg in_place<T>() function, missing from boost. */
-template<class T>
-typed_in_place_factory0<T> in_place() { return typed_in_place_factory0<T>(); }
-#endif
-
-template <class T, class R=void>
-struct EnableInPlace
- : public boost::enable_if<boost::is_base_and_derived<
- typed_in_place_factory_base, T>,
- R>
-{};
-
-template <class T, class R=void>
-struct DisableInPlace
- : public boost::disable_if<boost::is_base_and_derived<
- typed_in_place_factory_base, T>,
- R>
-{};
-
-template <class T> struct BlobHelper {
- static void destroy(void* ptr) { static_cast<T*>(ptr)->~T(); }
- static void copy(void* dest, const void* src) {
- new (dest) T(*static_cast<const T*>(src));
- }
-};
-
-template <> struct BlobHelper<void> {
- static void destroy(void*);
- static void copy(void* to, const void* from);
-};
-
-/**
- * A Blob is a chunk of memory which can contain a single object at
- * a time-arbitrary type, provided sizeof(T)<=blob.size(). Using Blobs
- * ensures proper construction and destruction of its contents,
- * and proper copying between Blobs, but nothing else.
- *
- * In particular you must ensure that the Blob is big enough for its
- * contents and must know the type of object in the Blob to cast get().
- *
- * If BaseType is specified then only an object that can be
- * static_cast to BaseType may be stored in the Blob.
- */
-template <size_t Size, class BaseType=void>
-class Blob
-{
- boost::aligned_storage<Size> store;
- BaseType* basePtr;
-
- void (*destroy)(void*);
- void (*copy)(void*, const void*);
-
- template <class T>void setType() {
- BOOST_STATIC_ASSERT(sizeof(T) <= Size);
- destroy=&BlobHelper<T>::destroy;
- copy=&BlobHelper<T>::copy;
- // Base pointer may be offeset from store.address()
- basePtr = reinterpret_cast<T*>(store.address());
- }
-
- void initialize() {
- destroy=&BlobHelper<void>::destroy;
- copy=&BlobHelper<void>::copy;
- basePtr=0;
- }
-
- template<class Factory>
- typename EnableInPlace<Factory>::type apply(const Factory& factory)
- {
- typedef typename Factory::value_type T;
- assert(empty());
- factory.apply(store.address());
- setType<T>();
- }
-
- void assign(const Blob& b) {
- assert(empty());
- if (b.empty()) return;
- b.copy(this->store.address(), b.store.address());
- copy = b.copy;
- destroy = b.destroy;
- basePtr = reinterpret_cast<BaseType*>(
- ((char*)this)+ ((const char*)(b.basePtr) - (const char*)(&b)));
- }
-
- public:
- /** Construct an empty Blob. */
- Blob() { initialize(); }
-
- /** Copy a Blob. */
- Blob(const Blob& b) { initialize(); assign(b); }
-
- /** Construct from in_place constructor. */
- template<class InPlace>
- Blob(const InPlace & expr, typename EnableInPlace<InPlace>::type* =0) {
- initialize(); apply(expr);
- }
-
- /** Construct by copying an object constructor. */
- template<class T>
- Blob(const T & t, typename DisableInPlace<T>::type* =0) {
- initialize(); apply(in_place<T>(t));
- }
-
- ~Blob() { clear(); }
-
- /** Assign from another Blob. */
- Blob& operator=(const Blob& b) {
- clear();
- assign(b);
- return *this;
- }
-
- /** Assign from an in_place constructor expression. */
- template<class InPlace>
- typename EnableInPlace<InPlace,Blob&>::type operator=(const InPlace& expr) {
- clear(); apply(expr); return *this;
- }
-
- /** Assign from an object of type T. */
- template <class T>
- typename DisableInPlace<T, Blob&>::type operator=(const T& x) {
- clear(); apply(in_place<T>(x)); return *this;
- }
-
- /** Get pointer to Blob contents, returns 0 if empty. */
- BaseType* get() { return basePtr; }
-
- /** Get pointer to Blob contents, returns 0 if empty. */
- const BaseType* get() const { return basePtr; }
-
- /** Destroy the object in the Blob making it empty. */
- void clear() {
- void (*oldDestroy)(void*) = destroy;
- initialize();
- oldDestroy(store.address());
- }
-
- bool empty() const { return destroy==BlobHelper<void>::destroy; }
-
- static size_t size() { return Size; }
-};
-
-}} // namespace qpid::framing
-
-
-#endif /*!QPID_FRAMING_BLOB_H*/
diff --git a/cpp/src/qpid/framing/BodyFactory.h b/cpp/src/qpid/framing/BodyFactory.h
new file mode 100644
index 0000000000..6a8d9b1988
--- /dev/null
+++ b/cpp/src/qpid/framing/BodyFactory.h
@@ -0,0 +1,47 @@
+#ifndef QPID_FRAMING_BODYFACTORY_H
+#define QPID_FRAMING_BODYFACTORY_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+namespace framing {
+
+/**
+ * Indirect creation of body types to allow centralized changes to
+ * memory management strategy.
+ */
+class BodyFactory {
+ public:
+ template <class BodyType> static boost::intrusive_ptr<BodyType> create() {
+ return new BodyType;
+ }
+
+ template <class BodyType> static boost::intrusive_ptr<BodyType> copy(const BodyType& body) {
+ return new BodyType(body);
+ }
+};
+
+}} // namespace qpid::framing
+
+#endif /*!QPID_FRAMING_BODYFACTORY_H*/
diff --git a/cpp/src/qpid/framing/BodyHandler.cpp b/cpp/src/qpid/framing/BodyHandler.cpp
index ffbcf33a95..e2128596ed 100644
--- a/cpp/src/qpid/framing/BodyHandler.cpp
+++ b/cpp/src/qpid/framing/BodyHandler.cpp
@@ -18,11 +18,11 @@
* under the License.
*
*/
-#include "BodyHandler.h"
-#include "AMQMethodBody.h"
-#include "AMQHeaderBody.h"
-#include "AMQContentBody.h"
-#include "AMQHeartbeatBody.h"
+#include "qpid/framing/BodyHandler.h"
+#include "qpid/framing/AMQMethodBody.h"
+#include "qpid/framing/AMQHeaderBody.h"
+#include "qpid/framing/AMQContentBody.h"
+#include "qpid/framing/AMQHeartbeatBody.h"
#include <boost/cast.hpp>
#include "qpid/framing/reply_exceptions.h"
diff --git a/cpp/src/qpid/framing/BodyHolder.cpp b/cpp/src/qpid/framing/BodyHolder.cpp
index 1b2f74de2c..e69de29bb2 100644
--- a/cpp/src/qpid/framing/BodyHolder.cpp
+++ b/cpp/src/qpid/framing/BodyHolder.cpp
@@ -1,76 +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 "BodyHolder.h"
-#include "AMQMethodBody.h"
-#include "AMQHeaderBody.h"
-#include "AMQContentBody.h"
-#include "AMQHeartbeatBody.h"
-#include "Buffer.h"
-#include "qpid/framing/reply_exceptions.h"
-
-namespace qpid {
-namespace framing {
-
-
-// BodyHolder::operator=(const AMQBody&) is defined
-// in generated file BodyHolder_gen.cpp
-
-
-void BodyHolder::encode(Buffer& b) const {
- const AMQMethodBody* method=getMethod();
- if (method) {
- b.putOctet(method->amqpClassId());
- b.putOctet(method->amqpMethodId());
- method->encode(b);
- }
- else
- get()->encode(b);
-}
-
-void BodyHolder::decode(uint8_t type, Buffer& buffer, uint32_t size) {
- switch(type)
- {
- case 0://CONTROL
- case METHOD_BODY: {
- ClassId c = buffer.getOctet();
- MethodId m = buffer.getOctet();
- setMethod(c, m);
- break;
- }
- case HEADER_BODY: *this=in_place<AMQHeaderBody>(); break;
- case CONTENT_BODY: *this=in_place<AMQContentBody>(); break;
- case HEARTBEAT_BODY: *this=in_place<AMQHeartbeatBody>(); break;
- default:
- throw IllegalArgumentException(QPID_MSG("Invalid frame type " << type));
- }
- get()->decode(buffer, size);
-}
-
-uint32_t BodyHolder::size() const {
- const AMQMethodBody* method=getMethod();
- if (method)
- return sizeof(ClassId)+sizeof(MethodId)+method->size();
- else
- return get()->size();
-}
-
-}} // namespace qpid::framing
-
diff --git a/cpp/src/qpid/framing/BodyHolder.h b/cpp/src/qpid/framing/BodyHolder.h
index f843961a32..e69de29bb2 100644
--- a/cpp/src/qpid/framing/BodyHolder.h
+++ b/cpp/src/qpid/framing/BodyHolder.h
@@ -1,88 +0,0 @@
-#ifndef QPID_FRAMING_BODYHOLDER_H
-#define QPID_FRAMING_BODYHOLDER_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/framing/AMQBody.h"
-#include "qpid/framing/Blob.h"
-#include "qpid/framing/MaxMethodBodySize.h" // Generated file.
-#include "qpid/framing/amqp_types.h"
-#include "qpid/RefCounted.h"
-
-
-namespace qpid {
-namespace framing {
-
-class AMQMethodBody;
-class AMQBody;
-class Buffer;
-
-/**
- * Holder for arbitrary frame body.
- */
-class BodyHolder : public RefCounted
-{
- public:
- // default copy, assign dtor ok.
- BodyHolder() {}
- BodyHolder(const AMQBody& b) { setBody(b); }
- BodyHolder(ClassId c, MethodId m) { setMethod(c,m); }
-
- /** Construct from an in_place constructor expression. */
- template <class InPlace>
- BodyHolder(const InPlace& ip, typename EnableInPlace<InPlace>::type* =0)
- : blob(ip) {}
-
- void setBody(const AMQBody& b);
-
- /** Assign from an in_place constructor expression. */
- template <class InPlace>
- typename EnableInPlace<InPlace,BodyHolder&>::type
- operator=(const InPlace& ip) { blob=ip; return *this; }
-
- /** Assign by copying. */
- template <class T>
- typename DisableInPlace<T,BodyHolder&>::type operator=(const T& x)
- { blob=in_place<T>(x); return *this; }
-
- /** Set to method with ClassId c, MethodId m. */
- void setMethod(ClassId c, MethodId m);
-
- void encode(Buffer&) const;
- void decode(uint8_t frameType, Buffer&, uint32_t=0);
- uint32_t size() const;
-
- /** Return body pointer or 0 if empty. */
- AMQBody* get() { return blob.get(); }
- const AMQBody* get() const { return blob.get(); }
-
- /** Return method pointer or 0 if not a method. */
- AMQMethodBody* getMethod() { return get()->getMethod(); }
- const AMQMethodBody* getMethod() const { return get()->getMethod(); }
-
- private:
- Blob<MAX_METHOD_BODY_SIZE, AMQBody> blob;
-};
-
-}} // namespace qpid::framing
-
-#endif /*!QPID_FRAMING_BODYHOLDER_H*/
diff --git a/cpp/src/qpid/framing/Buffer.cpp b/cpp/src/qpid/framing/Buffer.cpp
index 9c089fd0f8..051e7a2362 100644
--- a/cpp/src/qpid/framing/Buffer.cpp
+++ b/cpp/src/qpid/framing/Buffer.cpp
@@ -18,8 +18,8 @@
* under the License.
*
*/
-#include "Buffer.h"
-#include "FieldTable.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/FieldTable.h"
#include <string.h>
#include <boost/format.hpp>
namespace qpid {
@@ -51,12 +51,14 @@ void Buffer::reset(){
void Buffer::putOctet(uint8_t i){
data[position++] = i;
+ assert(position <= size);
}
void Buffer::putShort(uint16_t i){
uint16_t b = i;
data[position++] = (uint8_t) (0xFF & (b >> 8));
data[position++] = (uint8_t) (0xFF & b);
+ assert(position <= size);
}
void Buffer::putLong(uint32_t i){
@@ -65,6 +67,7 @@ void Buffer::putLong(uint32_t i){
data[position++] = (uint8_t) (0xFF & (b >> 16));
data[position++] = (uint8_t) (0xFF & (b >> 8));
data[position++] = (uint8_t) (0xFF & b);
+ assert(position <= size);
}
void Buffer::putLongLong(uint64_t i){
@@ -76,6 +79,7 @@ void Buffer::putLongLong(uint64_t i){
void Buffer::putInt8(int8_t i){
data[position++] = (uint8_t) i;
+ assert(position <= size);
}
void Buffer::putInt16(int16_t i){
@@ -110,19 +114,22 @@ void Buffer::putDouble(double f){
putLongLong (val.i);
}
-void Buffer::putBin128(uint8_t* b){
+void Buffer::putBin128(const uint8_t* b){
memcpy (data + position, b, 16);
position += 16;
}
uint8_t Buffer::getOctet(){
- return (uint8_t) data[position++];
+ uint8_t octet = static_cast<uint8_t>(data[position++]);
+ assert(position <= size);
+ return octet;
}
uint16_t Buffer::getShort(){
uint16_t hi = (unsigned char) data[position++];
hi = hi << 8;
hi |= (unsigned char) data[position++];
+ assert(position <= size);
return hi;
}
@@ -131,6 +138,7 @@ uint32_t Buffer::getLong(){
uint32_t b = (unsigned char) data[position++];
uint32_t c = (unsigned char) data[position++];
uint32_t d = (unsigned char) data[position++];
+ assert(position <= size);
a = a << 24;
a |= b << 16;
a |= c << 8;
@@ -146,7 +154,9 @@ uint64_t Buffer::getLongLong(){
}
int8_t Buffer::getInt8(){
- return (int8_t) data[position++];
+ int8_t i = static_cast<int8_t>(data[position++]);
+ assert(position <= size);
+ return i;
}
int16_t Buffer::getInt16(){
@@ -220,14 +230,16 @@ void Buffer::putUInt<8>(uint64_t i) {
}
void Buffer::putShortString(const string& s){
- uint8_t len = s.length();
+ size_t slen = s.length();
+ uint8_t len = slen < 0x100 ? (uint8_t) slen : 0xFF;
putOctet(len);
s.copy(data + position, len);
position += len;
}
void Buffer::putMediumString(const string& s){
- uint16_t len = s.length();
+ size_t slen = s.length();
+ uint16_t len = slen < 0x10000 ? (uint16_t) slen : 0xFFFF;
putShort(len);
s.copy(data + position, len);
position += len;
diff --git a/cpp/src/qpid/framing/Buffer.h b/cpp/src/qpid/framing/Buffer.h
deleted file mode 100644
index a27b15cac0..0000000000
--- a/cpp/src/qpid/framing/Buffer.h
+++ /dev/null
@@ -1,132 +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 "amqp_types.h"
-#include "qpid/Exception.h"
-#include <boost/iterator/iterator_facade.hpp>
-
-#ifndef _Buffer_
-#define _Buffer_
-
-namespace qpid {
-namespace framing {
-
-struct OutOfBounds : qpid::Exception {};
-
-class Content;
-class FieldTable;
-
-class Buffer
-{
- uint32_t size;
- char* data;
- uint32_t position;
- uint32_t r_position;
-
- void checkAvailable(uint32_t count) { if (position + count > size) throw OutOfBounds(); }
-
- public:
-
- /** Buffer input/output iterator.
- * Supports using an amqp_0_10::Codec with a framing::Buffer.
- */
- class Iterator : public boost::iterator_facade<
- Iterator, char, boost::random_access_traversal_tag>
- {
- public:
- Iterator(Buffer& b) : buffer(&b) {}
-
- private:
- friend class boost::iterator_core_access;
- char& dereference() const { return buffer->data[buffer->position]; }
- void increment() { ++buffer->position; }
- bool equal(const Iterator& x) const { return buffer == x.buffer; }
-
- Buffer* buffer;
- };
-
- friend class Iterator;
-
- Buffer(char* data=0, uint32_t size=0);
-
- void record();
- void restore(bool reRecord = false);
- void reset();
-
- uint32_t available() { return size - position; }
- uint32_t getSize() { return size; }
- uint32_t getPosition() { return position; }
- Iterator getIterator() { return Iterator(*this); }
-
- void putOctet(uint8_t i);
- void putShort(uint16_t i);
- void putLong(uint32_t i);
- void putLongLong(uint64_t i);
- void putInt8(int8_t i);
- void putInt16(int16_t i);
- void putInt32(int32_t i);
- void putInt64(int64_t i);
- void putFloat(float f);
- void putDouble(double f);
- void putBin128(uint8_t* b);
-
- uint8_t getOctet();
- uint16_t getShort();
- uint32_t getLong();
- uint64_t getLongLong();
- int8_t getInt8();
- int16_t getInt16();
- int32_t getInt32();
- int64_t getInt64();
- float getFloat();
- double getDouble();
-
- template <int n>
- uint64_t getUInt();
-
- template <int n>
- void putUInt(uint64_t);
-
- void putShortString(const string& s);
- void putMediumString(const string& s);
- void putLongString(const string& s);
- void getShortString(string& s);
- void getMediumString(string& s);
- void getLongString(string& s);
- void getBin128(uint8_t* b);
-
- void putRawData(const string& s);
- void getRawData(string& s, uint32_t size);
-
- void putRawData(const uint8_t* data, size_t size);
- void getRawData(uint8_t* data, size_t size);
-
- template <class T> void put(const T& data) { data.encode(*this); }
- template <class T> void get(T& data) { data.decode(*this); }
-
- void dump(std::ostream&) const;
-};
-
-std::ostream& operator<<(std::ostream&, const Buffer&);
-
-}} // namespace qpid::framing
-
-
-#endif
diff --git a/cpp/src/qpid/framing/ChannelHandler.h b/cpp/src/qpid/framing/ChannelHandler.h
index 69aaeac492..ddab204578 100644
--- a/cpp/src/qpid/framing/ChannelHandler.h
+++ b/cpp/src/qpid/framing/ChannelHandler.h
@@ -21,8 +21,8 @@
* under the License.
*
*/
-#include "FrameHandler.h"
-#include "AMQFrame.h"
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/framing/AMQFrame.h"
namespace qpid {
namespace framing {
diff --git a/cpp/src/qpid/framing/Endian.cpp b/cpp/src/qpid/framing/Endian.cpp
new file mode 100644
index 0000000000..5acc3c459f
--- /dev/null
+++ b/cpp/src/qpid/framing/Endian.cpp
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/framing/Endian.h"
+
+namespace qpid {
+namespace framing {
+
+Endian::Endian() : littleEndian(!testBigEndian()) {}
+
+bool Endian::testBigEndian()
+{
+ uint16_t a = 1;
+ uint16_t b;
+ uint8_t* p = (uint8_t*) &b;
+ p[0] = 0xFF & (a >> 8);
+ p[1] = 0xFF & (a);
+ return a == b;
+}
+
+uint8_t* Endian::convertIfRequired(uint8_t* const octets, int width)
+{
+ if (instance.littleEndian) {
+ for (int i = 0; i < (width/2); i++) {
+ uint8_t temp = octets[i];
+ octets[i] = octets[width - (1 + i)];
+ octets[width - (1 + i)] = temp;
+ }
+ }
+ return octets;
+}
+
+const Endian Endian::instance;
+
+}} // namespace qpid::framing
diff --git a/cpp/src/qpid/framing/Endian.h b/cpp/src/qpid/framing/Endian.h
new file mode 100644
index 0000000000..077d5a3e9b
--- /dev/null
+++ b/cpp/src/qpid/framing/Endian.h
@@ -0,0 +1,46 @@
+#ifndef QPID_FRAMING_ENDIAN_H
+#define QPID_FRAMING_ENDIAN_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/IntegerTypes.h"
+
+namespace qpid {
+namespace framing {
+
+/**
+ * Conversion utility for little-endian platforms that need to convert
+ * to and from network ordered octet sequences
+ */
+class Endian
+{
+ public:
+ static uint8_t* convertIfRequired(uint8_t* const octets, int width);
+ private:
+ const bool littleEndian;
+ Endian();
+ static const Endian instance;
+ static bool testBigEndian();
+};
+}} // namespace qpid::framing
+
+#endif /*!QPID_FRAMING_ENDIAN_H*/
diff --git a/cpp/src/qpid/framing/FieldTable.cpp b/cpp/src/qpid/framing/FieldTable.cpp
index bd20c10c37..e2e91e450a 100644
--- a/cpp/src/qpid/framing/FieldTable.cpp
+++ b/cpp/src/qpid/framing/FieldTable.cpp
@@ -18,9 +18,11 @@
* under the License.
*
*/
-#include "FieldTable.h"
-#include "Buffer.h"
-#include "FieldValue.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/Array.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/Endian.h"
+#include "qpid/framing/FieldValue.h"
#include "qpid/Exception.h"
#include "qpid/framing/reply_exceptions.h"
#include <assert.h>
@@ -28,13 +30,25 @@
namespace qpid {
namespace framing {
+FieldTable::FieldTable(const FieldTable& ft)
+{
+ *this = ft;
+}
+
+FieldTable& FieldTable::operator=(const FieldTable& ft)
+{
+ clear();
+ values = ft.values;
+ return *this;
+}
+
FieldTable::~FieldTable() {}
-uint32_t FieldTable::size() const {
+uint32_t FieldTable::encodedSize() const {
uint32_t len(4/*size field*/ + 4/*count field*/);
for(ValueMap::const_iterator i = values.begin(); i != values.end(); ++i) {
// shortstr_len_byte + key size + value size
- len += 1 + (i->first).size() + (i->second)->size();
+ len += 1 + (i->first).size() + (i->second)->encodedSize();
}
return len;
}
@@ -69,17 +83,38 @@ void FieldTable::setString(const std::string& name, const std::string& value){
values[name] = ValuePtr(new Str16Value(value));
}
-void FieldTable::setInt(const std::string& name, int value){
+void FieldTable::setInt(const std::string& name, const int value){
values[name] = ValuePtr(new IntegerValue(value));
}
-void FieldTable::setTimestamp(const std::string& name, uint64_t value){
+void FieldTable::setInt64(const std::string& name, const int64_t value){
+ values[name] = ValuePtr(new Integer64Value(value));
+}
+
+void FieldTable::setTimestamp(const std::string& name, const uint64_t value){
values[name] = ValuePtr(new TimeValue(value));
}
-void FieldTable::setTable(const std::string& name, const FieldTable& value){
+void FieldTable::setUInt64(const std::string& name, const uint64_t value){
+ values[name] = ValuePtr(new Unsigned64Value(value));
+}
+
+void FieldTable::setTable(const std::string& name, const FieldTable& value)
+{
values[name] = ValuePtr(new FieldTableValue(value));
}
+void FieldTable::setArray(const std::string& name, const Array& value)
+{
+ values[name] = ValuePtr(new ArrayValue(value));
+}
+
+void FieldTable::setFloat(const std::string& name, const float value){
+ values[name] = ValuePtr(new FloatValue(value));
+}
+
+void FieldTable::setDouble(const std::string& name, double value){
+ values[name] = ValuePtr(new DoubleValue(value));
+}
FieldTable::ValuePtr FieldTable::get(const std::string& name) const
{
@@ -105,24 +140,54 @@ T getValue(const FieldTable::ValuePtr value)
return value->get<T>();
}
-std::string FieldTable::getString(const std::string& name) const {
+std::string FieldTable::getAsString(const std::string& name) const {
return getValue<std::string>(get(name));
}
-int FieldTable::getInt(const std::string& name) const {
+int FieldTable::getAsInt(const std::string& name) const {
return getValue<int>(get(name));
}
+uint64_t FieldTable::getAsUInt64(const std::string& name) const {
+ return static_cast<uint64_t>( getValue<int64_t>(get(name)));
+}
+
+int64_t FieldTable::getAsInt64(const std::string& name) const {
+ return getValue<int64_t>(get(name));
+}
+
+bool FieldTable::getTable(const std::string& name, FieldTable& value) const {
+ return getEncodedValue<FieldTable>(get(name), value);
+}
+
+bool FieldTable::getArray(const std::string& name, Array& value) const {
+ return getEncodedValue<Array>(get(name), value);
+}
+
+template <class T, int width, uint8_t typecode>
+bool getRawFixedWidthValue(FieldTable::ValuePtr vptr, T& value)
+{
+ if (vptr && vptr->getType() == typecode) {
+ value = vptr->get<T>();
+ return true;
+ }
+ return false;
+}
+
+bool FieldTable::getFloat(const std::string& name, float& value) const {
+ return getRawFixedWidthValue<float, 4, 0x23>(get(name), value);
+}
+
+bool FieldTable::getDouble(const std::string& name, double& value) const {
+ return getRawFixedWidthValue<double, 8, 0x33>(get(name), value);
+}
+
//uint64_t FieldTable::getTimestamp(const std::string& name) const {
// return getValue<uint64_t>(name);
//}
-//
-//void FieldTable::getTable(const std::string& name, FieldTable& value) const {
-// value = getValue<FieldTable>(name);
-//}
-void FieldTable::encode(Buffer& buffer) const{
- buffer.putLong(size() - 4);
+void FieldTable::encode(Buffer& buffer) const {
+ buffer.putLong(encodedSize() - 4);
buffer.putLong(values.size());
for (ValueMap::const_iterator i = values.begin(); i!=values.end(); ++i) {
buffer.putShortString(i->first);
@@ -131,11 +196,12 @@ void FieldTable::encode(Buffer& buffer) const{
}
void FieldTable::decode(Buffer& buffer){
+ clear();
uint32_t len = buffer.getLong();
if (len) {
uint32_t available = buffer.available();
if (available < len)
- throw IllegalArgumentException(QPID_MSG("Not enough data for field table."));
+ throw IllegalArgumentException(QPID_MSG("Not enough data for field table."));
uint32_t count = buffer.getLong();
uint32_t leftover = available - len;
while(buffer.available() > leftover && count--){
@@ -149,7 +215,6 @@ void FieldTable::decode(Buffer& buffer){
}
}
-
bool FieldTable::operator==(const FieldTable& x) const {
if (values.size() != x.values.size()) return false;
for (ValueMap::const_iterator i = values.begin(); i != values.end(); ++i) {
@@ -160,10 +225,22 @@ bool FieldTable::operator==(const FieldTable& x) const {
return true;
}
-//void FieldTable::erase(const std::string& name)
-//{
-// values.erase(values.find(name));
-//}
+void FieldTable::erase(const std::string& name)
+{
+ if (values.find(name) != values.end())
+ values.erase(name);
+}
+
+std::pair<FieldTable::ValueMap::iterator, bool> FieldTable::insert(const ValueMap::value_type& value)
+{
+ return values.insert(value);
+}
+
+FieldTable::ValueMap::iterator FieldTable::insert(ValueMap::iterator position, const ValueMap::value_type& value)
+{
+ return values.insert(position, value);
+}
+
}
}
diff --git a/cpp/src/qpid/framing/FieldTable.h b/cpp/src/qpid/framing/FieldTable.h
deleted file mode 100644
index 3c65d31aee..0000000000
--- a/cpp/src/qpid/framing/FieldTable.h
+++ /dev/null
@@ -1,101 +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 <iostream>
-#include <vector>
-#include <boost/shared_ptr.hpp>
-#include <map>
-#include "amqp_types.h"
-
-#ifndef _FieldTable_
-#define _FieldTable_
-
-namespace qpid {
- /**
- * The framing namespace contains classes that are used to create,
- * send and receive the basic packets from which AMQP is built.
- */
-namespace framing {
-
-class FieldValue;
-class Buffer;
-
-/**
- * A set of name-value pairs. (See the AMQP spec for more details on
- * AMQP field tables).
- *
- * \ingroup clientapi
- */
-class FieldTable
-{
- public:
- typedef boost::shared_ptr<FieldValue> ValuePtr;
- typedef std::map<std::string, ValuePtr> ValueMap;
- typedef ValueMap::iterator iterator;
-
- ~FieldTable();
- uint32_t size() const;
- void encode(Buffer& buffer) const;
- void decode(Buffer& buffer);
-
- int count() const;
- void set(const std::string& name, const ValuePtr& value);
- ValuePtr get(const std::string& name) const;
-
- void setString(const std::string& name, const std::string& value);
- void setInt(const std::string& name, int value);
- void setTimestamp(const std::string& name, uint64_t value);
- void setTable(const std::string& name, const FieldTable& value);
- //void setDecimal(string& name, xxx& value);
-
- std::string getString(const std::string& name) const;
- int getInt(const std::string& name) const;
-// uint64_t getTimestamp(const std::string& name) const;
-// void getTable(const std::string& name, FieldTable& value) const;
-// //void getDecimal(string& name, xxx& value);
-// //void erase(const std::string& name);
-
-
- bool operator==(const FieldTable& other) const;
-
- // Map-like interface.
- // TODO: may need to duplicate into versions that return mutable iterator
- ValueMap::const_iterator begin() const { return values.begin(); }
- ValueMap::const_iterator end() const { return values.end(); }
- ValueMap::const_iterator find(const std::string& s) const { return values.find(s); }
-
- // ### Hack Alert
-
- ValueMap::iterator getValues() { return values.begin(); }
-
- private:
- ValueMap values;
-
- friend std::ostream& operator<<(std::ostream& out, const FieldTable& body);
-};
-
-//class FieldNotFoundException{};
-//class UnknownFieldName : public FieldNotFoundException{};
-//class IncorrectFieldType : public FieldNotFoundException{};
-}
-}
-
-
-#endif
diff --git a/cpp/src/qpid/framing/FieldValue.cpp b/cpp/src/qpid/framing/FieldValue.cpp
index 681f20a793..5bac931b83 100644
--- a/cpp/src/qpid/framing/FieldValue.cpp
+++ b/cpp/src/qpid/framing/FieldValue.cpp
@@ -18,8 +18,11 @@
* under the License.
*
*/
-#include "FieldValue.h"
-#include "Buffer.h"
+#include "qpid/framing/FieldValue.h"
+#include "qpid/framing/Array.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/Endian.h"
+#include "qpid/framing/List.h"
#include "qpid/framing/reply_exceptions.h"
namespace qpid {
@@ -33,53 +36,60 @@ uint8_t FieldValue::getType()
void FieldValue::setType(uint8_t type)
{
typeOctet = type;
-
- uint8_t lenType = typeOctet >> 4;
- switch(lenType){
- case 0:
- data.reset(new FixedWidthValue<1>());
- break;
- case 1:
- data.reset(new FixedWidthValue<2>());
- break;
- case 2:
- data.reset(new FixedWidthValue<4>());
- break;
- case 3:
- data.reset(new FixedWidthValue<8>());
- break;
- case 4:
- data.reset(new FixedWidthValue<16>());
- break;
- case 5:
- data.reset(new FixedWidthValue<32>());
- break;
- case 6:
- data.reset(new FixedWidthValue<64>());
- break;
- case 7:
- data.reset(new FixedWidthValue<128>());
- break;
- case 8:
- data.reset(new VariableWidthValue<1>());
- break;
- case 9:
- data.reset(new VariableWidthValue<2>());
- break;
- case 0xA:
- data.reset(new VariableWidthValue<4>());
- break;
- case 0xC:
- data.reset(new FixedWidthValue<5>());
- break;
- case 0xD:
- data.reset(new FixedWidthValue<9>());
- break;
- case 0xF:
- data.reset(new FixedWidthValue<0>());
- break;
- default:
- throw IllegalArgumentException(QPID_MSG("Unknown field table value type: " << (int)typeOctet));
+ if (typeOctet == 0xA8) {
+ data.reset(new EncodedValue<FieldTable>());
+ } else if (typeOctet == 0xA9) {
+ data.reset(new EncodedValue<List>());
+ } else if (typeOctet == 0xAA) {
+ data.reset(new EncodedValue<Array>());
+ } else {
+ uint8_t lenType = typeOctet >> 4;
+ switch(lenType){
+ case 0:
+ data.reset(new FixedWidthValue<1>());
+ break;
+ case 1:
+ data.reset(new FixedWidthValue<2>());
+ break;
+ case 2:
+ data.reset(new FixedWidthValue<4>());
+ break;
+ case 3:
+ data.reset(new FixedWidthValue<8>());
+ break;
+ case 4:
+ data.reset(new FixedWidthValue<16>());
+ break;
+ case 5:
+ data.reset(new FixedWidthValue<32>());
+ break;
+ case 6:
+ data.reset(new FixedWidthValue<64>());
+ break;
+ case 7:
+ data.reset(new FixedWidthValue<128>());
+ break;
+ case 8:
+ data.reset(new VariableWidthValue<1>());
+ break;
+ case 9:
+ data.reset(new VariableWidthValue<2>());
+ break;
+ case 0xA:
+ data.reset(new VariableWidthValue<4>());
+ break;
+ case 0xC:
+ data.reset(new FixedWidthValue<5>());
+ break;
+ case 0xD:
+ data.reset(new FixedWidthValue<9>());
+ break;
+ case 0xF:
+ data.reset(new FixedWidthValue<0>());
+ break;
+ default:
+ throw IllegalArgumentException(QPID_MSG("Unknown field table value type: " << (int)typeOctet));
+ }
}
}
@@ -102,10 +112,10 @@ bool FieldValue::operator==(const FieldValue& v) const
*data == *v.data;
}
-StringValue::StringValue(const std::string& v) :
+Str8Value::Str8Value(const std::string& v) :
FieldValue(
- 0xA4,
- new VariableWidthValue<4>(
+ TYPE_CODE_STR8,
+ new VariableWidthValue<1>(
reinterpret_cast<const uint8_t*>(v.data()),
reinterpret_cast<const uint8_t*>(v.data()+v.size())))
{
@@ -129,16 +139,77 @@ Struct32Value::Struct32Value(const std::string& v) :
IntegerValue::IntegerValue(int v) :
FieldValue(0x21, new FixedWidthValue<4>(v))
+{}
+
+FloatValue::FloatValue(float v) :
+ FieldValue(0x23, new FixedWidthValue<4>(Endian::convertIfRequired(reinterpret_cast<uint8_t*>(&v), 4)))
+{}
+
+DoubleValue::DoubleValue(double v) :
+ FieldValue(0x33, new FixedWidthValue<8>(Endian::convertIfRequired(reinterpret_cast<uint8_t*>(&v), 8)))
+{}
+
+Integer64Value::Integer64Value(int64_t v) :
+ FieldValue(0x31, new FixedWidthValue<8>(v))
+{}
+
+Unsigned64Value::Unsigned64Value(uint64_t v) :
+ FieldValue(0x32, new FixedWidthValue<8>(v))
+{}
+
+
+TimeValue::TimeValue(uint64_t v) :
+ FieldValue(0x38, new FixedWidthValue<8>(v))
{
}
-TimeValue::TimeValue(uint64_t v) :
- FieldValue(0x32, new FixedWidthValue<8>(v))
+FieldTableValue::FieldTableValue(const FieldTable& f) : FieldValue(0xa8, new EncodedValue<FieldTable>(f))
+{
+}
+
+ListValue::ListValue(const List& l) : FieldValue(0xa9, new EncodedValue<List>(l))
+{
+}
+
+ArrayValue::ArrayValue(const Array& a) : FieldValue(0xaa, new EncodedValue<Array>(a))
{
}
-FieldTableValue::FieldTableValue(const FieldTable&) : FieldValue()
+VoidValue::VoidValue() : FieldValue(0xf0, new FixedWidthValue<0>()) {}
+
+BoolValue::BoolValue(bool b) :
+ FieldValue(0x08, new FixedWidthValue<1>(b))
+{}
+
+Unsigned8Value::Unsigned8Value(uint8_t v) :
+ FieldValue(0x02, new FixedWidthValue<1>(v))
+{}
+Unsigned16Value::Unsigned16Value(uint16_t v) :
+ FieldValue(0x12, new FixedWidthValue<2>(v))
+{}
+Unsigned32Value::Unsigned32Value(uint32_t v) :
+ FieldValue(0x22, new FixedWidthValue<4>(v))
+{}
+
+Integer8Value::Integer8Value(int8_t v) :
+ FieldValue(0x01, new FixedWidthValue<1>(v))
+{}
+Integer16Value::Integer16Value(int16_t v) :
+ FieldValue(0x11, new FixedWidthValue<2>(v))
+{}
+
+void FieldValue::print(std::ostream& out) const {
+ data->print(out);
+ out << TypeCode(typeOctet) << '(';
+ if (data->convertsToString()) out << data->getString();
+ else if (data->convertsToInt()) out << data->getInt();
+ else data->print(out);
+ out << ')';
+}
+
+uint8_t* FieldValue::convertIfRequired(uint8_t* const octets, int width)
{
+ return Endian::convertIfRequired(octets, width);
}
}}
diff --git a/cpp/src/qpid/framing/FieldValue.h b/cpp/src/qpid/framing/FieldValue.h
deleted file mode 100644
index a4c20bf415..0000000000
--- a/cpp/src/qpid/framing/FieldValue.h
+++ /dev/null
@@ -1,241 +0,0 @@
-#ifndef _framing_FieldValue_h
-#define _framing_FieldValue_h
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/Exception.h"
-#include "Buffer.h"
-#include "amqp_types.h"
-
-#include "assert.h"
-
-#include <iostream>
-#include <memory>
-#include <vector>
-
-namespace qpid {
-namespace framing {
-
-/**
- * Exception that is the base exception for all field table errors.
- *
- * \ingroup clientapi
- */
-class FieldValueException : public qpid::Exception {};
-
-/**
- * Exception thrown when we can't perform requested conversion
- *
- * \ingroup clientapi
- */
-struct InvalidConversionException : public FieldValueException {
- InvalidConversionException() {}
-};
-
-/**
- * Value that can appear in an AMQP field table
- *
- * \ingroup clientapi
- */
-class FieldValue {
- public:
- /*
- * Abstract type for content of different types
- */
- class Data {
- public:
- virtual ~Data() {};
- virtual uint32_t size() const = 0;
- virtual void encode(Buffer& buffer) = 0;
- virtual void decode(Buffer& buffer) = 0;
- virtual bool operator==(const Data&) const = 0;
-
- virtual bool convertsToInt() const { return false; }
- virtual bool convertsToString() const { return false; }
- virtual int64_t getInt() const { throw InvalidConversionException();}
- virtual std::string getString() const { throw InvalidConversionException(); }
-
- virtual void print(std::ostream& out) const = 0;
- };
-
- FieldValue(): data(0) {};
- // Default assignment operator is fine
- void setType(uint8_t type);
- uint8_t getType();
- Data& getData() { return *data; }
- uint32_t size() const { return 1 + data->size(); };
- bool empty() const { return data.get() == 0; }
- void encode(Buffer& buffer);
- void decode(Buffer& buffer);
- bool operator==(const FieldValue&) const;
- bool operator!=(const FieldValue& v) const { return !(*this == v); }
- void print(std::ostream& out) const { out << "(0x" << std::hex << int(typeOctet) << ")"; data->print(out); }
-
- template <typename T> bool convertsTo() const { return false; }
- template <typename T> T get() const { throw InvalidConversionException(); }
-
- protected:
- FieldValue(uint8_t t, Data* d): typeOctet(t), data(d) {}
-
- private:
- uint8_t typeOctet;
- std::auto_ptr<Data> data;
-};
-
-template <>
-inline bool FieldValue::convertsTo<int>() const { return data->convertsToInt(); }
-
-template <>
-inline bool FieldValue::convertsTo<std::string>() const { return data->convertsToString(); }
-
-template <>
-inline int FieldValue::get<int>() const { return data->getInt(); }
-
-template <>
-inline std::string FieldValue::get<std::string>() const { return data->getString(); }
-
-inline std::ostream& operator<<(std::ostream& out, const FieldValue& v) {
- v.print(out);
- return out;
-}
-
-template <int width>
-class FixedWidthValue : public FieldValue::Data {
- uint8_t octets[width];
-
- public:
- FixedWidthValue() {}
- FixedWidthValue(const uint8_t (&data)[width]) : octets(data) {}
- FixedWidthValue(uint64_t v)
- {
- for (int i = width; i > 0; --i) {
- octets[i-1] = (uint8_t) (0xFF & v); v >>= 8;
- }
- octets[0] = (uint8_t) (0xFF & v);
- }
-
- uint32_t size() const { return width; }
- void encode(Buffer& buffer) { buffer.putRawData(octets, width); }
- void decode(Buffer& buffer) { buffer.getRawData(octets, width); }
- bool operator==(const Data& d) const {
- const FixedWidthValue<width>* rhs = dynamic_cast< const FixedWidthValue<width>* >(&d);
- if (rhs == 0) return false;
- else return std::equal(&octets[0], &octets[width], &rhs->octets[0]);
- }
-
- bool convertsToInt() const { return true; }
- int64_t getInt() const
- {
- int64_t v = 0;
- for (int i = 0; i < width-1; ++i) {
- v |= octets[i]; v <<= 8;
- }
- v |= octets[width-1];
- return v;
- }
-
- void print(std::ostream& o) const { o << "F" << width << ":"; };
-};
-
-template <>
-class FixedWidthValue<0> : public FieldValue::Data {
- public:
- // Implicit default constructor is fine
- uint32_t size() const { return 0; }
- void encode(Buffer&) {};
- void decode(Buffer&) {};
- bool operator==(const Data& d) const {
- const FixedWidthValue<0>* rhs = dynamic_cast< const FixedWidthValue<0>* >(&d);
- return rhs != 0;
- }
- void print(std::ostream& o) const { o << "F0"; };
-};
-
-template <int lenwidth>
-class VariableWidthValue : public FieldValue::Data {
- std::vector<uint8_t> octets;
-
- public:
- VariableWidthValue() {}
- VariableWidthValue(const std::vector<uint8_t>& data) : octets(data) {}
- VariableWidthValue(const uint8_t* start, const uint8_t* end) : octets(start, end) {}
- uint32_t size() const { return lenwidth + octets.size(); }
- void encode(Buffer& buffer) {
- buffer.putUInt<lenwidth>(octets.size());
- buffer.putRawData(&octets[0], octets.size());
- };
- void decode(Buffer& buffer) {
- uint32_t len = buffer.getUInt<lenwidth>();
- octets.resize(len);
- buffer.getRawData(&octets[0], len);
- }
- bool operator==(const Data& d) const {
- const VariableWidthValue<lenwidth>* rhs = dynamic_cast< const VariableWidthValue<lenwidth>* >(&d);
- if (rhs == 0) return false;
- else return octets==rhs->octets;
- }
-
- bool convertsToString() const { return true; }
- std::string getString() const { return std::string(octets.begin(), octets.end()); }
-
- void print(std::ostream& o) const { o << "V" << lenwidth << ":" << octets.size() << ":"; };
-};
-
-/*
- * Basic string value encodes as iso-8859-15 with 32 bit length
- */
-class StringValue : public FieldValue {
- public:
- StringValue(const std::string& v);
-};
-
-class Str16Value : public FieldValue {
- public:
- Str16Value(const std::string& v);
-};
-
-class Struct32Value : public FieldValue {
- public:
- Struct32Value(const std::string& v);
-};
-
-
-/*
- * Basic integer value encodes as signed 32 bit
- */
-class IntegerValue : public FieldValue {
- public:
- IntegerValue(int v);
-};
-
-class TimeValue : public FieldValue {
- public:
- TimeValue(uint64_t v);
-};
-
-class FieldTableValue : public FieldValue {
- public:
- FieldTableValue(const FieldTable&);
-};
-
-}} // qpid::framing
-
-#endif
diff --git a/cpp/src/qpid/framing/FrameDecoder.cpp b/cpp/src/qpid/framing/FrameDecoder.cpp
new file mode 100644
index 0000000000..90cbbd84a1
--- /dev/null
+++ b/cpp/src/qpid/framing/FrameDecoder.cpp
@@ -0,0 +1,81 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/framing/FrameDecoder.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/log/Statement.h"
+#include "qpid/framing/reply_exceptions.h"
+#include <algorithm>
+#include <string.h>
+
+namespace qpid {
+namespace framing {
+
+namespace {
+/** Append up to n bytes from start of buf to end of bytes. */
+void append(std::vector<char>& bytes, Buffer& buffer, size_t n) {
+ size_t oldSize = bytes.size();
+ if ((n = std::min(n, size_t(buffer.available()))) == 0)
+ return;
+ bytes.resize(oldSize+n);
+ char* p = &bytes[oldSize];
+ buffer.getRawData(reinterpret_cast<uint8_t*>(p), n);
+}
+}
+
+bool FrameDecoder::decode(Buffer& buffer) {
+ if (buffer.available() == 0) return false;
+ if (fragment.empty()) {
+ if (frame.decode(buffer)) // Decode from buffer
+ return true;
+ else // Store fragment
+ append(fragment, buffer, buffer.available());
+ }
+ else { // Already have a fragment
+ // Get enough data to decode the frame size.
+ if (fragment.size() < AMQFrame::DECODE_SIZE_MIN) {
+ append(fragment, buffer, AMQFrame::DECODE_SIZE_MIN - fragment.size());
+ }
+ if (fragment.size() >= AMQFrame::DECODE_SIZE_MIN) {
+ uint16_t size = AMQFrame::decodeSize(&fragment[0]);
+ if (size <= fragment.size())
+ throw FramingErrorException(QPID_MSG("Frame size " << size << " is too small."));
+ append(fragment, buffer, size-fragment.size());
+ Buffer b(&fragment[0], fragment.size());
+ if (frame.decode(b)) {
+ assert(b.available() == 0);
+ fragment.clear();
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void FrameDecoder::setFragment(const char* data, size_t size) {
+ fragment.resize(size);
+ ::memcpy(&fragment[0], data, size);
+}
+
+std::pair<const char*, size_t> FrameDecoder::getFragment() const {
+ return std::pair<const char*, size_t>(&fragment[0], fragment.size());
+}
+
+}} // namespace qpid::framing
diff --git a/cpp/src/qpid/framing/FrameDecoder.h b/cpp/src/qpid/framing/FrameDecoder.h
new file mode 100644
index 0000000000..26bed6c447
--- /dev/null
+++ b/cpp/src/qpid/framing/FrameDecoder.h
@@ -0,0 +1,52 @@
+#ifndef QPID_FRAMING_FRAMEDECODER_H
+#define QPID_FRAMING_FRAMEDECODER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/CommonImportExport.h"
+
+namespace qpid {
+namespace framing {
+
+/**
+ * Decode a frame from buffer. If buffer does not contain a complete
+ * frame, caches the fragment for the next call to decode.
+ */
+class FrameDecoder
+{
+ public:
+ QPID_COMMON_EXTERN bool decode(Buffer& buffer);
+ const AMQFrame& getFrame() const { return frame; }
+ AMQFrame& getFrame() { return frame; }
+
+ void setFragment(const char*, size_t);
+ std::pair<const char*, size_t> getFragment() const;
+
+ private:
+ std::vector<char> fragment;
+ AMQFrame frame;
+
+};
+}} // namespace qpid::framing
+
+#endif /*!QPID_FRAMING_FRAMEDECODER_H*/
diff --git a/cpp/src/qpid/framing/FrameHandler.h b/cpp/src/qpid/framing/FrameHandler.h
index 457968c35e..fa1fb535ef 100644
--- a/cpp/src/qpid/framing/FrameHandler.h
+++ b/cpp/src/qpid/framing/FrameHandler.h
@@ -20,7 +20,7 @@
* under the License.
*
*/
-#include "Handler.h"
+#include "qpid/framing/Handler.h"
namespace qpid {
namespace framing {
diff --git a/cpp/src/qpid/framing/FrameSet.cpp b/cpp/src/qpid/framing/FrameSet.cpp
index 5326ab7c14..c03dd39458 100644
--- a/cpp/src/qpid/framing/FrameSet.cpp
+++ b/cpp/src/qpid/framing/FrameSet.cpp
@@ -19,7 +19,7 @@
*
*/
-#include "FrameSet.h"
+#include "qpid/framing/FrameSet.h"
#include "qpid/framing/all_method_bodies.h"
#include "qpid/framing/frame_functors.h"
#include "qpid/framing/MessageProperties.h"
@@ -33,7 +33,7 @@ FrameSet::FrameSet(const SequenceNumber& _id) : id(_id),contentSize(0),recalcula
void FrameSet::append(const AMQFrame& part)
{
parts.push_back(part);
- recalculateSize = true;
+ recalculateSize = true;
}
bool FrameSet::isComplete() const
@@ -52,6 +52,11 @@ const AMQMethodBody* FrameSet::getMethod() const
return parts.empty() ? 0 : parts[0].getMethod();
}
+AMQMethodBody* FrameSet::getMethod()
+{
+ return parts.empty() ? 0 : parts[0].getMethod();
+}
+
const AMQHeaderBody* FrameSet::getHeaders() const
{
return parts.size() < 2 ? 0 : parts[1].castBody<AMQHeaderBody>();
diff --git a/cpp/src/qpid/framing/FrameSet.h b/cpp/src/qpid/framing/FrameSet.h
index 82987910a7..398a709353 100644
--- a/cpp/src/qpid/framing/FrameSet.h
+++ b/cpp/src/qpid/framing/FrameSet.h
@@ -23,6 +23,7 @@
#include "qpid/framing/amqp_framing.h"
#include "qpid/framing/AMQFrame.h"
#include "qpid/framing/SequenceNumber.h"
+#include "qpid/CommonImportExport.h"
#ifndef _FrameSet_
#define _FrameSet_
@@ -44,19 +45,21 @@ class FrameSet
public:
typedef boost::shared_ptr<FrameSet> shared_ptr;
- FrameSet(const SequenceNumber& id);
- void append(const AMQFrame& part);
- bool isComplete() const;
+ QPID_COMMON_EXTERN FrameSet(const SequenceNumber& id);
+ QPID_COMMON_EXTERN void append(const AMQFrame& part);
+ QPID_COMMON_EXTERN bool isComplete() const;
- uint64_t getContentSize() const;
- void getContent(std::string&) const;
- std::string getContent() const;
+ QPID_COMMON_EXTERN uint64_t getContentSize() const;
+
+ QPID_COMMON_EXTERN void getContent(std::string&) const;
+ QPID_COMMON_EXTERN std::string getContent() const;
bool isContentBearing() const;
- const AMQMethodBody* getMethod() const;
- const AMQHeaderBody* getHeaders() const;
- AMQHeaderBody* getHeaders();
+ QPID_COMMON_EXTERN const AMQMethodBody* getMethod() const;
+ QPID_COMMON_EXTERN AMQMethodBody* getMethod();
+ QPID_COMMON_EXTERN const AMQHeaderBody* getHeaders() const;
+ QPID_COMMON_EXTERN AMQHeaderBody* getHeaders();
template <class T> bool isA() const {
const AMQMethodBody* method = getMethod();
@@ -68,11 +71,19 @@ public:
return (method && method->isA<T>()) ? dynamic_cast<const T*>(method) : 0;
}
+ template <class T> T* as() {
+ AMQMethodBody* method = getMethod();
+ return (method && method->isA<T>()) ? dynamic_cast<T*>(method) : 0;
+ }
+
template <class T> const T* getHeaderProperties() const {
const AMQHeaderBody* header = getHeaders();
return header ? header->get<T>() : 0;
}
+ Frames::const_iterator begin() const { return parts.begin(); }
+ Frames::const_iterator end() const { return parts.end(); }
+
const SequenceNumber& getId() const { return id; }
template <class P> void remove(P predicate) {
diff --git a/cpp/src/qpid/framing/Handler.h b/cpp/src/qpid/framing/Handler.h
index e07a803e17..fa8db36f49 100644
--- a/cpp/src/qpid/framing/Handler.h
+++ b/cpp/src/qpid/framing/Handler.h
@@ -21,7 +21,7 @@
* under the License.
*
*/
-#include "qpid/shared_ptr.h"
+#include <boost/shared_ptr.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <assert.h>
diff --git a/cpp/src/qpid/framing/HeaderProperties.h b/cpp/src/qpid/framing/HeaderProperties.h
index d66c1d00d6..8b1828daec 100644
--- a/cpp/src/qpid/framing/HeaderProperties.h
+++ b/cpp/src/qpid/framing/HeaderProperties.h
@@ -18,8 +18,8 @@
* under the License.
*
*/
-#include "amqp_types.h"
-#include "Buffer.h"
+#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/Buffer.h"
#ifndef _HeaderProperties_
#define _HeaderProperties_
@@ -33,7 +33,7 @@ namespace framing {
public:
inline virtual ~HeaderProperties(){}
virtual uint8_t classId() const = 0;
- virtual uint32_t size() const = 0;
+ virtual uint32_t encodedSize() const = 0;
virtual void encode(Buffer& buffer) const = 0;
virtual void decode(Buffer& buffer, uint32_t size) = 0;
};
diff --git a/cpp/src/qpid/framing/InitiationHandler.cpp b/cpp/src/qpid/framing/InitiationHandler.cpp
index eceeaf4abc..7ded505a47 100644
--- a/cpp/src/qpid/framing/InitiationHandler.cpp
+++ b/cpp/src/qpid/framing/InitiationHandler.cpp
@@ -19,6 +19,6 @@
*
*/
-#include "InitiationHandler.h"
+#include "qpid/framing/InitiationHandler.h"
qpid::framing::InitiationHandler::~InitiationHandler() {}
diff --git a/cpp/src/qpid/framing/InitiationHandler.h b/cpp/src/qpid/framing/InitiationHandler.h
index 16a6b502e8..5dfcc6b468 100644
--- a/cpp/src/qpid/framing/InitiationHandler.h
+++ b/cpp/src/qpid/framing/InitiationHandler.h
@@ -23,7 +23,7 @@
#ifndef _InitiationHandler_
#define _InitiationHandler_
-#include "ProtocolInitiation.h"
+#include "qpid/framing/ProtocolInitiation.h"
namespace qpid {
namespace framing {
diff --git a/cpp/src/qpid/framing/InputHandler.h b/cpp/src/qpid/framing/InputHandler.h
index 3a6d786a24..3efb23632a 100644
--- a/cpp/src/qpid/framing/InputHandler.h
+++ b/cpp/src/qpid/framing/InputHandler.h
@@ -21,7 +21,7 @@
*
*/
-#include "FrameHandler.h"
+#include "qpid/framing/FrameHandler.h"
#include <boost/noncopyable.hpp>
namespace qpid {
diff --git a/cpp/src/qpid/framing/IsInSequenceSet.h b/cpp/src/qpid/framing/IsInSequenceSet.h
new file mode 100644
index 0000000000..fe10c1b9fa
--- /dev/null
+++ b/cpp/src/qpid/framing/IsInSequenceSet.h
@@ -0,0 +1,51 @@
+#ifndef QPID_FRAMING_ISINSEQUENCESET_H
+#define QPID_FRAMING_ISINSEQUENCESET_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/framing/SequenceSet.h"
+
+namespace qpid {
+namespace framing {
+/**
+ * Functor to test whether values are in a sequence set. This is a
+ * stateful functor that requires the values to be supplied in order
+ * and takes advantage of that ordering to avoid multiple scans.
+ */
+class IsInSequenceSet
+{
+ public:
+ IsInSequenceSet(const SequenceSet& s) : set(s), i(set.rangesBegin()) {}
+
+ bool operator()(const SequenceNumber& n) {
+ while (i != set.rangesEnd() && i->end() <= n) ++i;
+ return i != set.rangesEnd() && i->begin() <= n;
+ }
+
+ private:
+ const SequenceSet& set;
+ SequenceSet::RangeIterator i;
+};
+
+}} // namespace qpid::framing
+
+#endif /*!QPID_FRAMING_ISINSEQUENCESET_H*/
diff --git a/cpp/src/qpid/framing/List.cpp b/cpp/src/qpid/framing/List.cpp
new file mode 100644
index 0000000000..bde7dabbac
--- /dev/null
+++ b/cpp/src/qpid/framing/List.cpp
@@ -0,0 +1,83 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/framing/List.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/FieldValue.h"
+#include "qpid/Exception.h"
+#include "qpid/framing/reply_exceptions.h"
+
+namespace qpid {
+namespace framing {
+
+uint32_t List::encodedSize() const
+{
+ uint32_t len(4/*size*/ + 4/*count*/);
+ for(Values::const_iterator i = values.begin(); i != values.end(); ++i) {
+ len += (*i)->encodedSize();
+ }
+ return len;
+}
+
+void List::encode(Buffer& buffer) const
+{
+ buffer.putLong(encodedSize() - 4);
+ buffer.putLong(size());
+ for (Values::const_iterator i = values.begin(); i!=values.end(); ++i) {
+ (*i)->encode(buffer);
+ }
+}
+
+void List::decode(Buffer& buffer)
+{
+ values.clear();
+ uint32_t size = buffer.getLong();
+ uint32_t available = buffer.available();
+ if (available < size) {
+ throw IllegalArgumentException(QPID_MSG("Not enough data for list, expected "
+ << size << " bytes but only " << available << " available"));
+ }
+ if (size) {
+ uint32_t count = buffer.getLong();
+ for (uint32_t i = 0; i < count; i++) {
+ ValuePtr value(new FieldValue);
+ value->decode(buffer);
+ values.push_back(value);
+ }
+ }
+}
+
+
+bool List::operator==(const List& other) const {
+ return values.size() == other.values.size() &&
+ std::equal(values.begin(), values.end(), other.values.begin());
+}
+
+std::ostream& operator<<(std::ostream& out, const List& l)
+{
+ out << "{";
+ for(List::Values::const_iterator i = l.values.begin(); i != l.values.end(); ++i) {
+ if (i != l.values.begin()) out << ", ";
+ (*i)->print(out);
+ }
+ return out << "}";
+}
+
+}} // namespace qpid::framing
diff --git a/cpp/src/qpid/framing/MethodBodyFactory.h b/cpp/src/qpid/framing/MethodBodyFactory.h
new file mode 100644
index 0000000000..607ec9d959
--- /dev/null
+++ b/cpp/src/qpid/framing/MethodBodyFactory.h
@@ -0,0 +1,44 @@
+#ifndef QPID_FRAMING_METHODBODYFACTORY_H
+#define QPID_FRAMING_METHODBODYFACTORY_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/framing/amqp_types.h"
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+namespace framing {
+
+class AMQMethodBody;
+
+/**
+ * Functions to create instances of AMQMethodBody sub-classes.
+ * Note: MethodBodyFactory.cpp file is generated by rubygen.
+ */
+class MethodBodyFactory
+{
+ public:
+ static boost::intrusive_ptr<AMQMethodBody> create(ClassId c, MethodId m);
+};
+
+}} // namespace qpid::framing
+
+#endif /*!QPID_FRAMING_METHODBODYFACTORY_H*/
diff --git a/cpp/src/qpid/framing/MethodContent.h b/cpp/src/qpid/framing/MethodContent.h
index 737c0d6b7b..b290a0c140 100644
--- a/cpp/src/qpid/framing/MethodContent.h
+++ b/cpp/src/qpid/framing/MethodContent.h
@@ -22,7 +22,7 @@
#define _MethodContent_
#include <string>
-#include "AMQHeaderBody.h"
+#include "qpid/framing/AMQHeaderBody.h"
namespace qpid {
namespace framing {
diff --git a/cpp/src/qpid/framing/ModelMethod.h b/cpp/src/qpid/framing/ModelMethod.h
index 8e4361e761..d99bd06cfa 100644
--- a/cpp/src/qpid/framing/ModelMethod.h
+++ b/cpp/src/qpid/framing/ModelMethod.h
@@ -21,7 +21,7 @@
* under the License.
*
*/
-#include "AMQMethodBody.h"
+#include "qpid/framing/AMQMethodBody.h"
#include "qpid/framing/Header.h"
namespace qpid {
@@ -35,7 +35,7 @@ public:
virtual ~ModelMethod() {}
virtual void encodeHeader(Buffer& buffer) const { header.encode(buffer); }
virtual void decodeHeader(Buffer& buffer, uint32_t size=0) { header.decode(buffer, size); }
- virtual uint32_t headerSize() const { return header.size(); }
+ virtual uint32_t headerSize() const { return header.encodedSize(); }
virtual bool isSync() const { return header.getSync(); }
virtual void setSync(bool on) const { header.setSync(on); }
Header& getHeader() { return header; }
diff --git a/cpp/src/qpid/framing/OutputHandler.h b/cpp/src/qpid/framing/OutputHandler.h
index 6f4b27fb72..88c95589da 100644
--- a/cpp/src/qpid/framing/OutputHandler.h
+++ b/cpp/src/qpid/framing/OutputHandler.h
@@ -22,7 +22,7 @@
*
*/
#include <boost/noncopyable.hpp>
-#include "FrameHandler.h"
+#include "qpid/framing/FrameHandler.h"
namespace qpid {
namespace framing {
diff --git a/cpp/src/qpid/framing/ProtocolInitiation.cpp b/cpp/src/qpid/framing/ProtocolInitiation.cpp
index 50617de017..e617015d64 100644
--- a/cpp/src/qpid/framing/ProtocolInitiation.cpp
+++ b/cpp/src/qpid/framing/ProtocolInitiation.cpp
@@ -18,7 +18,7 @@
* under the License.
*
*/
-#include "ProtocolInitiation.h"
+#include "qpid/framing/ProtocolInitiation.h"
namespace qpid {
namespace framing {
diff --git a/cpp/src/qpid/framing/ProtocolInitiation.h b/cpp/src/qpid/framing/ProtocolInitiation.h
index 43e32da4cf..c519bc2442 100644
--- a/cpp/src/qpid/framing/ProtocolInitiation.h
+++ b/cpp/src/qpid/framing/ProtocolInitiation.h
@@ -18,10 +18,11 @@
* under the License.
*
*/
-#include "amqp_types.h"
-#include "Buffer.h"
-#include "AMQDataBlock.h"
-#include "ProtocolVersion.h"
+#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/AMQDataBlock.h"
+#include "qpid/framing/ProtocolVersion.h"
+#include "qpid/CommonImportExport.h"
#ifndef _ProtocolInitiation_
#define _ProtocolInitiation_
@@ -35,20 +36,20 @@ private:
ProtocolVersion version;
public:
- ProtocolInitiation();
- ProtocolInitiation(uint8_t major, uint8_t minor);
- ProtocolInitiation(ProtocolVersion p);
- virtual ~ProtocolInitiation();
- virtual void encode(Buffer& buffer) const;
- virtual bool decode(Buffer& buffer);
- inline virtual uint32_t size() const { return 8; }
+ QPID_COMMON_EXTERN ProtocolInitiation();
+ QPID_COMMON_EXTERN ProtocolInitiation(uint8_t major, uint8_t minor);
+ QPID_COMMON_EXTERN ProtocolInitiation(ProtocolVersion p);
+ QPID_COMMON_EXTERN virtual ~ProtocolInitiation();
+ QPID_COMMON_EXTERN virtual void encode(Buffer& buffer) const;
+ QPID_COMMON_EXTERN virtual bool decode(Buffer& buffer);
+ inline virtual uint32_t encodedSize() const { return 8; }
inline uint8_t getMajor() const { return version.getMajor(); }
inline uint8_t getMinor() const { return version.getMinor(); }
inline ProtocolVersion getVersion() const { return version; }
bool operator==(ProtocolVersion v) const { return v == getVersion(); }
};
-std::ostream& operator<<(std::ostream& o, const framing::ProtocolInitiation& pi);
+QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& o, const framing::ProtocolInitiation& pi);
}
diff --git a/cpp/src/qpid/framing/ProtocolVersion.cpp b/cpp/src/qpid/framing/ProtocolVersion.cpp
index 7a96bfa925..c63cddb4cc 100644
--- a/cpp/src/qpid/framing/ProtocolVersion.cpp
+++ b/cpp/src/qpid/framing/ProtocolVersion.cpp
@@ -18,7 +18,7 @@
* under the License.
*
*/
-#include "ProtocolVersion.h"
+#include "qpid/framing/ProtocolVersion.h"
#include <sstream>
using namespace qpid::framing;
diff --git a/cpp/src/qpid/framing/ProtocolVersion.h b/cpp/src/qpid/framing/ProtocolVersion.h
deleted file mode 100644
index 9a7ebec491..0000000000
--- a/cpp/src/qpid/framing/ProtocolVersion.h
+++ /dev/null
@@ -1,57 +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.
- *
- */
-#ifndef _ProtocolVersion_
-#define _ProtocolVersion_
-
-#include "amqp_types.h"
-
-namespace qpid
-{
-namespace framing
-{
-
-class ProtocolVersion
-{
-private:
- uint8_t major_;
- uint8_t minor_;
-
-public:
- explicit ProtocolVersion(uint8_t _major=0, uint8_t _minor=0)
- : major_(_major), minor_(_minor) {}
-
- uint8_t getMajor() const { return major_; }
- void setMajor(uint8_t major) { major_ = major; }
- uint8_t getMinor() const { return minor_; }
- void setMinor(uint8_t minor) { minor_ = minor; }
- const std::string toString() const;
-
- ProtocolVersion& operator=(ProtocolVersion p);
-
- bool operator==(ProtocolVersion p) const;
- bool operator!=(ProtocolVersion p) const { return ! (*this == p); }
-};
-
-} // namespace framing
-} // namespace qpid
-
-
-#endif // ifndef _ProtocolVersion_
diff --git a/cpp/src/qpid/framing/Proxy.cpp b/cpp/src/qpid/framing/Proxy.cpp
index 6b37fb368d..452fb13b01 100644
--- a/cpp/src/qpid/framing/Proxy.cpp
+++ b/cpp/src/qpid/framing/Proxy.cpp
@@ -16,17 +16,23 @@
*
*/
-#include "Proxy.h"
-#include "AMQFrame.h"
+#include "qpid/framing/Proxy.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/AMQMethodBody.h"
+#include "qpid/log/Statement.h"
namespace qpid {
namespace framing {
-Proxy::Proxy(FrameHandler& h) : out(&h) {}
+Proxy::Proxy(FrameHandler& h) : out(&h), sync(false) {}
Proxy::~Proxy() {}
void Proxy::send(const AMQBody& b) {
+ if (sync) {
+ const AMQMethodBody* m = dynamic_cast<const AMQMethodBody*>(&b);
+ if (m) m->setSync(sync);
+ }
AMQFrame f(b);
out->handle(f);
}
@@ -39,4 +45,7 @@ FrameHandler& Proxy::getHandler() { return *out; }
void Proxy::setHandler(FrameHandler& f) { out=&f; }
+Proxy::ScopedSync::ScopedSync(Proxy& p) : proxy(p) { proxy.sync = true; }
+Proxy::ScopedSync::~ScopedSync() { proxy.sync = false; }
+
}} // namespace qpid::framing
diff --git a/cpp/src/qpid/framing/Proxy.h b/cpp/src/qpid/framing/Proxy.h
index 3dc082097a..0884e9cbd2 100644
--- a/cpp/src/qpid/framing/Proxy.h
+++ b/cpp/src/qpid/framing/Proxy.h
@@ -19,8 +19,10 @@
*
*/
-#include "FrameHandler.h"
-#include "ProtocolVersion.h"
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/framing/ProtocolVersion.h"
+
+#include "qpid/CommonImportExport.h"
namespace qpid {
namespace framing {
@@ -33,18 +35,26 @@ class AMQBody;
class Proxy
{
public:
- Proxy(FrameHandler& h);
- virtual ~Proxy();
+ class ScopedSync
+ {
+ Proxy& proxy;
+ public:
+ QPID_COMMON_EXTERN ScopedSync(Proxy& p);
+ QPID_COMMON_EXTERN ~ScopedSync();
+ };
- void send(const AMQBody&);
+ QPID_COMMON_EXTERN Proxy(FrameHandler& h);
+ QPID_COMMON_EXTERN virtual ~Proxy();
- ProtocolVersion getVersion() const;
+ QPID_COMMON_EXTERN void send(const AMQBody&);
- FrameHandler& getHandler();
- void setHandler(FrameHandler&);
+ QPID_COMMON_EXTERN ProtocolVersion getVersion() const;
+ QPID_COMMON_EXTERN FrameHandler& getHandler();
+ QPID_COMMON_EXTERN void setHandler(FrameHandler&);
private:
FrameHandler* out;
+ bool sync;
};
}} // namespace qpid::framing
diff --git a/cpp/src/qpid/framing/SendContent.cpp b/cpp/src/qpid/framing/SendContent.cpp
index a62e4eeb72..a26c19037b 100644
--- a/cpp/src/qpid/framing/SendContent.cpp
+++ b/cpp/src/qpid/framing/SendContent.cpp
@@ -19,7 +19,7 @@
*
*/
-#include "SendContent.h"
+#include "qpid/framing/SendContent.h"
qpid::framing::SendContent::SendContent(FrameHandler& h, uint16_t mfs, uint efc) : handler(h),
maxFrameSize(mfs),
@@ -34,13 +34,13 @@ void qpid::framing::SendContent::operator()(const AMQFrame& f)
real frame size, hence substract -1 from frameOverhead()*/
uint16_t maxContentSize = maxFrameSize - (AMQFrame::frameOverhead() - 1);
const AMQContentBody* body(f.castBody<AMQContentBody>());
- if (body->size() > maxContentSize) {
+ if (body->encodedSize() > maxContentSize) {
uint32_t offset = 0;
- for (int chunk = body->size() / maxContentSize; chunk > 0; chunk--) {
- sendFragment(*body, offset, maxContentSize, first && offset == 0, last && offset + maxContentSize == body->size());
+ for (int chunk = body->encodedSize() / maxContentSize; chunk > 0; chunk--) {
+ sendFragment(*body, offset, maxContentSize, first && offset == 0, last && offset + maxContentSize == body->encodedSize());
offset += maxContentSize;
}
- uint32_t remainder = body->size() % maxContentSize;
+ uint32_t remainder = body->encodedSize() % maxContentSize;
if (remainder) {
sendFragment(*body, offset, remainder, first && offset == 0, last);
}
@@ -53,8 +53,7 @@ void qpid::framing::SendContent::operator()(const AMQFrame& f)
void qpid::framing::SendContent::sendFragment(const AMQContentBody& body, uint32_t offset, uint16_t size, bool first, bool last) const
{
- AMQFrame fragment(in_place<AMQContentBody>(
- body.getData().substr(offset, size)));
+ AMQFrame fragment((AMQContentBody(body.getData().substr(offset, size))));
setFlags(fragment, first, last);
handler.handle(fragment);
}
diff --git a/cpp/src/qpid/framing/SendContent.h b/cpp/src/qpid/framing/SendContent.h
index dcd5202b3e..745c948c9e 100644
--- a/cpp/src/qpid/framing/SendContent.h
+++ b/cpp/src/qpid/framing/SendContent.h
@@ -22,6 +22,7 @@
#include "qpid/framing/amqp_framing.h"
#include "qpid/framing/AMQFrame.h"
#include "qpid/framing/FrameHandler.h"
+#include "qpid/CommonImportExport.h"
#ifndef _SendContent_
#define _SendContent_
@@ -44,8 +45,8 @@ class SendContent
void sendFragment(const AMQContentBody& body, uint32_t offset, uint16_t size, bool first, bool last) const;
void setFlags(AMQFrame& f, bool first, bool last) const;
public:
- SendContent(FrameHandler& _handler, uint16_t _maxFrameSize, uint frameCount);
- void operator()(const AMQFrame& f);
+ QPID_COMMON_EXTERN SendContent(FrameHandler& _handler, uint16_t _maxFrameSize, uint frameCount);
+ QPID_COMMON_EXTERN void operator()(const AMQFrame& f);
};
}
diff --git a/cpp/src/qpid/framing/SequenceNumber.cpp b/cpp/src/qpid/framing/SequenceNumber.cpp
index 7caaf5440b..41cb236629 100644
--- a/cpp/src/qpid/framing/SequenceNumber.cpp
+++ b/cpp/src/qpid/framing/SequenceNumber.cpp
@@ -19,67 +19,13 @@
*
*/
-#include "SequenceNumber.h"
-#include "Buffer.h"
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/framing/Buffer.h"
#include <ostream>
using qpid::framing::SequenceNumber;
using qpid::framing::Buffer;
-SequenceNumber::SequenceNumber() : value(0) {}
-
-SequenceNumber::SequenceNumber(uint32_t v) : value((int32_t) v) {}
-
-bool SequenceNumber::operator==(const SequenceNumber& other) const
-{
- return value == other.value;
-}
-
-bool SequenceNumber::operator!=(const SequenceNumber& other) const
-{
- return !(value == other.value);
-}
-
-
-SequenceNumber& SequenceNumber::operator++()
-{
- value = value + 1;
- return *this;
-}
-
-const SequenceNumber SequenceNumber::operator++(int)
-{
- SequenceNumber old(value);
- value = value + 1;
- return old;
-}
-
-SequenceNumber& SequenceNumber::operator--()
-{
- value = value - 1;
- return *this;
-}
-
-bool SequenceNumber::operator<(const SequenceNumber& other) const
-{
- return (value - other.value) < 0;
-}
-
-bool SequenceNumber::operator>(const SequenceNumber& other) const
-{
- return other < *this;
-}
-
-bool SequenceNumber::operator<=(const SequenceNumber& other) const
-{
- return *this == other || *this < other;
-}
-
-bool SequenceNumber::operator>=(const SequenceNumber& other) const
-{
- return *this == other || *this > other;
-}
-
void SequenceNumber::encode(Buffer& buffer) const
{
buffer.putLong(value);
@@ -90,19 +36,13 @@ void SequenceNumber::decode(Buffer& buffer)
value = buffer.getLong();
}
-uint32_t SequenceNumber::size() const {
+uint32_t SequenceNumber::encodedSize() const {
return 4;
}
namespace qpid {
namespace framing {
-int32_t operator-(const SequenceNumber& a, const SequenceNumber& b)
-{
- int32_t result = a.value - b.value;
- return result;
-}
-
std::ostream& operator<<(std::ostream& o, const SequenceNumber& n) {
return o << n.getValue();
}
diff --git a/cpp/src/qpid/framing/SequenceNumber.h b/cpp/src/qpid/framing/SequenceNumber.h
deleted file mode 100644
index aacd77501b..0000000000
--- a/cpp/src/qpid/framing/SequenceNumber.h
+++ /dev/null
@@ -1,75 +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.
- *
- */
-#ifndef _framing_SequenceNumber_h
-#define _framing_SequenceNumber_h
-
-#include "amqp_types.h"
-#include <iosfwd>
-
-namespace qpid {
-namespace framing {
-
-class Buffer;
-
-/**
- * 4-byte sequence number that 'wraps around'.
- */
-class SequenceNumber
-{
- int32_t value;
-
- public:
- SequenceNumber();
- SequenceNumber(uint32_t v);
-
- SequenceNumber& operator++();//prefix ++
- const SequenceNumber operator++(int);//postfix ++
- SequenceNumber& operator--();//prefix ++
- bool operator==(const SequenceNumber& other) const;
- bool operator!=(const SequenceNumber& other) const;
- bool operator<(const SequenceNumber& other) const;
- bool operator>(const SequenceNumber& other) const;
- bool operator<=(const SequenceNumber& other) const;
- bool operator>=(const SequenceNumber& other) const;
- uint32_t getValue() const { return (uint32_t) value; }
- operator uint32_t() const { return (uint32_t) value; }
-
- friend int32_t operator-(const SequenceNumber& a, const SequenceNumber& b);
-
- void encode(Buffer& buffer) const;
- void decode(Buffer& buffer);
- uint32_t size() const;
-
- template <class S> void serialize(S& s) { s(value); }
-};
-
-struct Window
-{
- SequenceNumber hwm;
- SequenceNumber lwm;
-};
-
-std::ostream& operator<<(std::ostream& o, const SequenceNumber& n);
-
-}} // namespace qpid::framing
-
-
-#endif
diff --git a/cpp/src/qpid/framing/SequenceNumberSet.cpp b/cpp/src/qpid/framing/SequenceNumberSet.cpp
index afab9033e5..e9d78f3c17 100644
--- a/cpp/src/qpid/framing/SequenceNumberSet.cpp
+++ b/cpp/src/qpid/framing/SequenceNumberSet.cpp
@@ -19,7 +19,7 @@
*
*/
-#include "SequenceNumberSet.h"
+#include "qpid/framing/SequenceNumberSet.h"
using namespace qpid::framing;
@@ -33,6 +33,7 @@ void SequenceNumberSet::encode(Buffer& buffer) const
void SequenceNumberSet::decode(Buffer& buffer)
{
+ clear();
uint16_t count = (buffer.getShort() / 4);
for (uint16_t i = 0; i < count; i++) {
push_back(SequenceNumber(buffer.getLong()));
diff --git a/cpp/src/qpid/framing/SequenceNumberSet.h b/cpp/src/qpid/framing/SequenceNumberSet.h
index 666307f9d9..c8356c8163 100644
--- a/cpp/src/qpid/framing/SequenceNumberSet.h
+++ b/cpp/src/qpid/framing/SequenceNumberSet.h
@@ -22,11 +22,12 @@
#define _framing_SequenceNumberSet_h
#include <ostream>
-#include "amqp_types.h"
-#include "Buffer.h"
-#include "SequenceNumber.h"
+#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/SequenceNumber.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/InlineVector.h"
+#include "qpid/CommonImportExport.h"
namespace qpid {
namespace framing {
@@ -41,8 +42,8 @@ public:
void encode(Buffer& buffer) const;
void decode(Buffer& buffer);
uint32_t encodedSize() const;
- SequenceNumberSet condense() const;
- void addRange(const SequenceNumber& start, const SequenceNumber& end);
+ QPID_COMMON_EXTERN SequenceNumberSet condense() const;
+ QPID_COMMON_EXTERN void addRange(const SequenceNumber& start, const SequenceNumber& end);
template <class T>
void processRanges(T& t) const
@@ -58,7 +59,7 @@ public:
}
}
- friend std::ostream& operator<<(std::ostream&, const SequenceNumberSet&);
+ friend QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, const SequenceNumberSet&);
};
diff --git a/cpp/src/qpid/framing/SequenceSet.cpp b/cpp/src/qpid/framing/SequenceSet.cpp
index 9610b9180c..dcfb4689b6 100644
--- a/cpp/src/qpid/framing/SequenceSet.cpp
+++ b/cpp/src/qpid/framing/SequenceSet.cpp
@@ -19,8 +19,8 @@
*
*/
-#include "SequenceSet.h"
-#include "Buffer.h"
+#include "qpid/framing/SequenceSet.h"
+#include "qpid/framing/Buffer.h"
#include "qpid/framing/reply_exceptions.h"
using namespace qpid::framing;
@@ -46,6 +46,7 @@ void SequenceSet::encode(Buffer& buffer) const
void SequenceSet::decode(Buffer& buffer)
{
+ clear();
uint16_t size = buffer.getShort();
uint16_t count = size / RANGE_SIZE;//number of ranges
if (size % RANGE_SIZE)
@@ -56,7 +57,7 @@ void SequenceSet::decode(Buffer& buffer)
}
}
-uint32_t SequenceSet::size() const {
+uint32_t SequenceSet::encodedSize() const {
return 2 /*size field*/ + (rangesSize() * RANGE_SIZE);
}
diff --git a/cpp/src/qpid/framing/SequenceSet.h b/cpp/src/qpid/framing/SequenceSet.h
deleted file mode 100644
index 99e7cb4b21..0000000000
--- a/cpp/src/qpid/framing/SequenceSet.h
+++ /dev/null
@@ -1,68 +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.
- *
- */
-#ifndef _framing_SequenceSet_h
-#define _framing_SequenceSet_h
-
-#include "SequenceNumber.h"
-#include "qpid/RangeSet.h"
-
-namespace qpid {
-namespace framing {
-class Buffer;
-
-class SequenceSet : public RangeSet<SequenceNumber> {
- public:
- SequenceSet() {}
- explicit SequenceSet(const RangeSet<SequenceNumber>& r)
- : RangeSet<SequenceNumber>(r) {}
- explicit SequenceSet(const SequenceNumber& s) { add(s); }
- SequenceSet(const SequenceNumber& start, const SequenceNumber finish) { add(start,finish); }
-
-
- void encode(Buffer& buffer) const;
- void decode(Buffer& buffer);
- uint32_t size() const;
-
- bool contains(const SequenceNumber& s) const;
- void add(const SequenceNumber& s);
- void add(const SequenceNumber& start, const SequenceNumber& finish); // Closed range
- void add(const SequenceSet& set);
- void remove(const SequenceNumber& s);
- void remove(const SequenceNumber& start, const SequenceNumber& finish); // Closed range
- void remove(const SequenceSet& set);
-
- template <class T> void for_each(T& t) const {
- for (RangeIterator i = rangesBegin(); i != rangesEnd(); i++)
- t(i->first(), i->last());
- }
-
- template <class T> void for_each(const T& t) const {
- for (RangeIterator i = rangesBegin(); i != rangesEnd(); i++)
- t(i->first(), i->last());
- }
-
- friend std::ostream& operator<<(std::ostream&, const SequenceSet&);
-};
-
-}} // namespace qpid::framing
-
-
-#endif
diff --git a/cpp/src/qpid/framing/StructHelper.h b/cpp/src/qpid/framing/StructHelper.h
deleted file mode 100644
index e3dce4f5ec..0000000000
--- a/cpp/src/qpid/framing/StructHelper.h
+++ /dev/null
@@ -1,56 +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.
- *
- */
-#ifndef _StructHelper_
-#define _StructHelper_
-
-#include "qpid/Exception.h"
-#include "Buffer.h"
-
-#include <stdlib.h> // For alloca
-
-namespace qpid {
-namespace framing {
-
-class StructHelper
-{
-public:
-
- template <class T> void encode(const T t, std::string& data) {
- uint32_t size = t.bodySize() + 2/*type*/;
- data.resize(size);
- Buffer wbuffer(const_cast<char*>(data.data()), size);
- wbuffer.putShort(T::TYPE);
- t.encodeStructBody(wbuffer);
- }
-
- template <class T> void decode(T& t, const std::string& data) {
- Buffer rbuffer(const_cast<char*>(data.data()), data.length());
- uint16_t type = rbuffer.getShort();
- if (type == T::TYPE) {
- t.decodeStructBody(rbuffer);
- } else {
- throw Exception("Type code does not match");
- }
- }
-};
-
-}}
-#endif
diff --git a/cpp/src/qpid/framing/TransferContent.cpp b/cpp/src/qpid/framing/TransferContent.cpp
index 42af2027eb..837d7d346a 100644
--- a/cpp/src/qpid/framing/TransferContent.cpp
+++ b/cpp/src/qpid/framing/TransferContent.cpp
@@ -19,20 +19,17 @@
*
*/
-#include "TransferContent.h"
+#include "qpid/framing/TransferContent.h"
namespace qpid {
namespace framing {
-TransferContent::TransferContent(const std::string& data,
- const std::string& routingKey,
- const std::string& exchange)
-{
+TransferContent::TransferContent(const std::string& data, const std::string& key) {
setData(data);
- if (routingKey.size()) getDeliveryProperties().setRoutingKey(routingKey);
- if (exchange.size()) getDeliveryProperties().setExchange(exchange);
+ if (!key.empty()) getDeliveryProperties().setRoutingKey(key);
}
+
AMQHeaderBody TransferContent::getHeader() const
{
return header;
diff --git a/cpp/src/qpid/framing/TransferContent.h b/cpp/src/qpid/framing/TransferContent.h
index 7630421bd4..5fe1a513a9 100644
--- a/cpp/src/qpid/framing/TransferContent.h
+++ b/cpp/src/qpid/framing/TransferContent.h
@@ -21,11 +21,12 @@
#ifndef _TransferContent_
#define _TransferContent_
-#include "FrameSet.h"
-#include "MethodContent.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/framing/MethodContent.h"
#include "qpid/Exception.h"
#include "qpid/framing/MessageProperties.h"
#include "qpid/framing/DeliveryProperties.h"
+#include "qpid/CommonImportExport.h"
namespace qpid {
namespace framing {
@@ -36,29 +37,27 @@ class TransferContent : public MethodContent
AMQHeaderBody header;
std::string data;
public:
- TransferContent(const std::string& data = std::string(),
- const std::string& routingKey = std::string(),
- const std::string& exchange = std::string());
+ QPID_COMMON_EXTERN TransferContent(const std::string& data = std::string(), const std::string& key=std::string());
///@internal
- AMQHeaderBody getHeader() const;
+ QPID_COMMON_EXTERN AMQHeaderBody getHeader() const;
- void setData(const std::string&);
- const std::string& getData() const;
- std::string& getData();
+ QPID_COMMON_EXTERN void setData(const std::string&);
+ QPID_COMMON_EXTERN const std::string& getData() const;
+ QPID_COMMON_EXTERN std::string& getData();
- void appendData(const std::string&);
+ QPID_COMMON_EXTERN void appendData(const std::string&);
- bool hasMessageProperties() const;
- MessageProperties& getMessageProperties();
- const MessageProperties& getMessageProperties() const;
+ QPID_COMMON_EXTERN bool hasMessageProperties() const;
+ QPID_COMMON_EXTERN MessageProperties& getMessageProperties();
+ QPID_COMMON_EXTERN const MessageProperties& getMessageProperties() const;
- bool hasDeliveryProperties() const;
- DeliveryProperties& getDeliveryProperties();
- const DeliveryProperties& getDeliveryProperties() const;
+ QPID_COMMON_EXTERN bool hasDeliveryProperties() const;
+ QPID_COMMON_EXTERN DeliveryProperties& getDeliveryProperties();
+ QPID_COMMON_EXTERN const DeliveryProperties& getDeliveryProperties() const;
///@internal
- void populate(const FrameSet& frameset);
+ QPID_COMMON_EXTERN void populate(const FrameSet& frameset);
};
}}
diff --git a/cpp/src/qpid/framing/Uuid.cpp b/cpp/src/qpid/framing/Uuid.cpp
index e8d8d517dd..432c7ab94e 100644
--- a/cpp/src/qpid/framing/Uuid.cpp
+++ b/cpp/src/qpid/framing/Uuid.cpp
@@ -16,7 +16,9 @@
*
*/
-#include "Uuid.h"
+#include "qpid/framing/Uuid.h"
+
+#include "qpid/sys/uuid.h"
#include "qpid/Exception.h"
#include "qpid/framing/Buffer.h"
#include "qpid/framing/reply_exceptions.h"
@@ -28,6 +30,37 @@ using namespace std;
static const size_t UNPARSED_SIZE=36;
+Uuid::Uuid(bool unique) {
+ if (unique) {
+ generate();
+ } else {
+ clear();
+ }
+}
+
+Uuid::Uuid(const uint8_t* data) {
+ assign(data);
+}
+
+void Uuid::assign(const uint8_t* data) {
+ // This const cast is for Solaris which has a
+ // uuid_copy that takes a non const 2nd argument
+ uuid_copy(c_array(), const_cast<uint8_t*>(data));
+}
+
+void Uuid::generate() {
+ uuid_generate(c_array());
+}
+
+void Uuid::clear() {
+ uuid_clear(c_array());
+}
+
+// Force int 0/!0 to false/true; avoids compile warnings.
+bool Uuid::isNull() const {
+ return !!uuid_is_null(data());
+}
+
void Uuid::encode(Buffer& buf) const {
buf.putRawData(data(), size());
}
@@ -52,7 +85,7 @@ istream& operator>>(istream& in, Uuid& uuid) {
return in;
}
-std::string Uuid::str() {
+std::string Uuid::str() const {
std::ostringstream os;
os << *this;
return os.str();
diff --git a/cpp/src/qpid/framing/Uuid.h b/cpp/src/qpid/framing/Uuid.h
deleted file mode 100644
index e3e309a56c..0000000000
--- a/cpp/src/qpid/framing/Uuid.h
+++ /dev/null
@@ -1,88 +0,0 @@
-#ifndef QPID_FRAMING_UUID_H
-#define QPID_FRAMING_UUID_H
-
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include <boost/array.hpp>
-
-#include <ostream>
-#include <istream>
-
-#include <uuid/uuid.h>
-
-namespace qpid {
-namespace framing {
-
-class Buffer;
-
-/**
- * A UUID is represented as a boost::array of 16 bytes.
- *
- * Full value semantics, operators ==, < etc. are provided by
- * boost::array so Uuid can be the key type in a map etc.
- */
-struct Uuid : public boost::array<uint8_t, 16> {
- /** If unique is true, generate a unique ID else a null ID. */
- Uuid(bool unique=false) { if (unique) generate(); else clear(); }
-
- /** Copy from 16 bytes of data. */
- Uuid(uint8_t* data) { assign(data); }
-
- /** Copy from 16 bytes of data. */
- void assign(uint8_t* data) {
- uuid_copy(c_array(), data);
- }
-
- /** Set to a new unique identifier. */
- void generate() { uuid_generate(c_array()); }
-
- /** Set to all zeros. */
- void clear() { uuid_clear(c_array()); }
-
- /** Test for null (all zeros). */
- bool isNull() {
- return uuid_is_null(data());
- }
-
- // Default op= and copy ctor are fine.
- // boost::array gives us ==, < etc.
-
- void encode(framing::Buffer& buf) const;
-
- void decode(framing::Buffer& buf);
-
- /** String value in format 1b4e28ba-2fa1-11d2-883f-b9a761bde3fb. */
- std::string str();
-
- template <class S> void serialize(S& s) {
- s.raw(begin(), size());
- }
-};
-
-/** Print in format 1b4e28ba-2fa1-11d2-883f-b9a761bde3fb. */
-std::ostream& operator<<(std::ostream&, Uuid);
-
-/** Read from format 1b4e28ba-2fa1-11d2-883f-b9a761bde3fb. */
-std::istream& operator>>(std::istream&, Uuid&);
-
-}} // namespace qpid::framing
-
-
-
-#endif /*!QPID_FRAMING_UUID_H*/
diff --git a/cpp/src/qpid/framing/amqp_framing.h b/cpp/src/qpid/framing/amqp_framing.h
index 4e4747c3f4..3a8b39afb5 100644
--- a/cpp/src/qpid/framing/amqp_framing.h
+++ b/cpp/src/qpid/framing/amqp_framing.h
@@ -18,15 +18,15 @@
* under the License.
*
*/
-#include "amqp_types.h"
-#include "AMQFrame.h"
-#include "AMQBody.h"
-#include "BodyHandler.h"
-#include "AMQMethodBody.h"
-#include "AMQHeaderBody.h"
-#include "AMQContentBody.h"
-#include "AMQHeartbeatBody.h"
-#include "InputHandler.h"
-#include "OutputHandler.h"
-#include "ProtocolInitiation.h"
-#include "ProtocolVersion.h"
+#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/AMQBody.h"
+#include "qpid/framing/BodyHandler.h"
+#include "qpid/framing/AMQMethodBody.h"
+#include "qpid/framing/AMQHeaderBody.h"
+#include "qpid/framing/AMQContentBody.h"
+#include "qpid/framing/AMQHeartbeatBody.h"
+#include "qpid/framing/InputHandler.h"
+#include "qpid/framing/OutputHandler.h"
+#include "qpid/framing/ProtocolInitiation.h"
+#include "qpid/framing/ProtocolVersion.h"
diff --git a/cpp/src/qpid/framing/amqp_types.h b/cpp/src/qpid/framing/amqp_types.h
deleted file mode 100644
index 8b10aa3069..0000000000
--- a/cpp/src/qpid/framing/amqp_types.h
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef AMQP_TYPES_H
-#define AMQP_TYPES_H
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-/** \file
- * Definitions and forward declarations of all types used
- * in AMQP messages.
- */
-
-#include <string>
-#ifdef _WINDOWS
-#include "windows.h"
-typedef unsigned char uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned int uint32_t;
-typedef unsigned __int64 uint64_t;
-#endif
-#ifndef _WINDOWS
-#include <stdint.h>
-#endif
-
-namespace qpid {
-namespace framing {
-
-using std::string;
-typedef uint8_t FrameType;
-typedef uint16_t ChannelId;
-typedef uint32_t BatchOffset;
-typedef uint8_t ClassId;
-typedef uint8_t MethodId;
-typedef uint16_t ReplyCode;
-
-// Types represented by classes.
-class Content;
-class FieldTable;
-class SequenceNumberSet;
-class Uuid;
-
-// Useful constants
-
-/** Maximum channel ID used by broker. Reserve high bit for internal use.*/
-const ChannelId CHANNEL_MAX=(ChannelId(~1))>>1;
-const ChannelId CHANNEL_HIGH_BIT= ChannelId(~CHANNEL_MAX);
-
-// Forward declare class types
-class FramingContent;
-class FieldTable;
-class SequenceNumberSet;
-class SequenceSet;
-class Uuid;
-
-}} // namespace qpid::framing
-#endif
diff --git a/cpp/src/qpid/framing/amqp_types_full.h b/cpp/src/qpid/framing/amqp_types_full.h
deleted file mode 100644
index d0aaf28cb4..0000000000
--- a/cpp/src/qpid/framing/amqp_types_full.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef _framing_amqp_types_decl_h
-#define _framing_amqp_types_decl_h
-
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-/** \file
- * Definitions and full declarations of all types used
- * in AMQP messages.
- *
- * It's better to include amqp_types.h in another header instead of this file
- * unless the header actually needs the full declarations. Including
- * full declarations when forward declarations would increase compile
- * times.
- */
-
-#include "amqp_types.h"
-#include "Array.h"
-#include "FieldTable.h"
-#include "SequenceSet.h"
-#include "Uuid.h"
-
-#endif /*!_framing_amqp_types_decl_h*/
diff --git a/cpp/src/qpid/framing/frame_functors.h b/cpp/src/qpid/framing/frame_functors.h
index 8ae3d15b4f..d2064d6a57 100644
--- a/cpp/src/qpid/framing/frame_functors.h
+++ b/cpp/src/qpid/framing/frame_functors.h
@@ -36,7 +36,7 @@ class SumFrameSize
uint64_t size;
public:
SumFrameSize() : size(0) {}
- void operator()(const AMQFrame& f) { size += f.size(); }
+ void operator()(const AMQFrame& f) { size += f.encodedSize(); }
uint64_t getSize() { return size; }
};
@@ -45,7 +45,7 @@ class SumBodySize
uint64_t size;
public:
SumBodySize() : size(0) {}
- void operator()(const AMQFrame& f) { size += f.getBody()->size(); }
+ void operator()(const AMQFrame& f) { size += f.getBody()->encodedSize(); }
uint64_t getSize() { return size; }
};
diff --git a/cpp/src/qpid/log/Logger.cpp b/cpp/src/qpid/log/Logger.cpp
index 54df54bb94..939e2502cc 100644
--- a/cpp/src/qpid/log/Logger.cpp
+++ b/cpp/src/qpid/log/Logger.cpp
@@ -16,20 +16,19 @@
*
*/
-#include "Logger.h"
-#include "Options.h"
+#include "qpid/log/Logger.h"
+#include "qpid/log/Options.h"
+#include "qpid/log/SinkOptions.h"
#include "qpid/memory.h"
#include "qpid/sys/Thread.h"
+#include "qpid/sys/Time.h"
#include <boost/pool/detail/singleton.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
-#include <boost/scoped_ptr.hpp>
#include <algorithm>
#include <sstream>
-#include <fstream>
#include <iomanip>
#include <stdexcept>
-#include <syslog.h>
#include <time.h>
@@ -44,45 +43,6 @@ inline void Logger::enable_unlocked(Statement* s) {
s->enabled=selector.isEnabled(s->level, s->function);
}
-struct OstreamOutput : public Logger::Output {
- OstreamOutput(std::ostream& o) : out(&o) {}
-
- OstreamOutput(const string& file)
- : out(new ofstream(file.c_str(), ios_base::out | ios_base::app)),
- mine(out)
- {
- if (!out->good())
- throw std::runtime_error("Can't open log file: "+file);
- }
-
- void log(const Statement&, const std::string& m) {
- *out << m << flush;
- }
-
- ostream* out;
- boost::scoped_ptr<ostream> mine;
-};
-
-struct SyslogOutput : public Logger::Output {
- SyslogOutput(const Options& opts)
- : name(opts.syslogName), facility(opts.syslogFacility.value)
- {
- ::openlog(name.c_str(), LOG_PID, facility);
- }
-
- ~SyslogOutput() {
- ::closelog();
- }
-
- void log(const Statement& s, const std::string& m)
- {
- syslog(LevelTraits::priority(s.level), "%s", m.c_str());
- }
-
- std::string name;
- int facility;
-};
-
Logger& Logger::instance() {
return boost::details::pool::singleton_default<Logger>::instance();
}
@@ -114,25 +74,7 @@ void Logger::log(const Statement& s, const std::string& msg) {
if (!prefix.empty())
os << prefix << ": ";
if (flags&TIME)
- {
- const char * month_abbrevs[] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" };
- time_t rawtime;
- struct tm * timeinfo;
-
- time ( & rawtime );
- timeinfo = localtime ( &rawtime );
- char time_string[100];
- sprintf ( time_string,
- "%d-%s-%02d %02d:%02d:%02d",
- 1900 + timeinfo->tm_year,
- month_abbrevs[timeinfo->tm_mon],
- timeinfo->tm_mday,
- timeinfo->tm_hour,
- timeinfo->tm_min,
- timeinfo->tm_sec
- );
- os << time_string << " ";
- }
+ qpid::sys::outputFormattedNow(os);
if (flags&LEVEL)
os << LevelTraits::name(s.level) << " ";
if (flags&THREAD)
@@ -159,25 +101,6 @@ void Logger::output(std::auto_ptr<Output> out) {
outputs.push_back(out.release());
}
-void Logger::output(std::ostream& out) {
- output(make_auto_ptr<Output>(new OstreamOutput(out)));
-}
-
-void Logger::syslog(const Options& opts) {
- output(make_auto_ptr<Output>(new SyslogOutput(opts)));
-}
-
-void Logger::output(const std::string& name, const Options& opts) {
- if (name=="stderr")
- output(clog);
- else if (name=="stdout")
- output(cout);
- else if (name=="syslog")
- syslog(opts);
- else
- output(make_auto_ptr<Output>(new OstreamOutput(name)));
-}
-
void Logger::clear() {
select(Selector()); // locked
format(0); // locked
@@ -212,16 +135,15 @@ void Logger::add(Statement& s) {
}
void Logger::configure(const Options& opts) {
+ options = opts;
clear();
Options o(opts);
if (o.trace)
o.selectors.push_back("trace+");
format(o);
select(Selector(o));
- void (Logger::* outputFn)(const std::string&, const Options&) = &Logger::output;
- for_each(o.outputs.begin(), o.outputs.end(),
- boost::bind(outputFn, this, _1, boost::cref(o)));
setPrefix(opts.prefix);
+ options.sinkOptions->setup(this);
}
void Logger::setPrefix(const std::string& p) { prefix = p; }
diff --git a/cpp/src/qpid/log/Logger.h b/cpp/src/qpid/log/Logger.h
deleted file mode 100644
index fa38678bba..0000000000
--- a/cpp/src/qpid/log/Logger.h
+++ /dev/null
@@ -1,117 +0,0 @@
-#ifndef LOGGER_H
-#define LOGGER_H
-
-/*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "Selector.h"
-#include "qpid/sys/Mutex.h"
-#include <boost/ptr_container/ptr_vector.hpp>
-#include <boost/noncopyable.hpp>
-#include <set>
-
-namespace qpid {
-namespace log {
-
-class Options;
-
-/**
- * Central logging agent.
- *
- * Thread safe, singleton.
- */
-class Logger : private boost::noncopyable {
- public:
- /** Flags indicating what to include in the log output */
- enum FormatFlag { FILE=1, LINE=2, FUNCTION=4, LEVEL=8, TIME=16, THREAD=32};
-
- /** Interface for log output destination.
- *
- * Implementations must be thread safe.
- */
- class Output {
- public:
- Output();
- virtual ~Output();
- /** Receives the statemnt of origin and formatted message to log. */
- virtual void log(const Statement&, const std::string&) =0;
- };
-
- static Logger& instance();
-
- Logger();
- ~Logger();
-
- /** Select the messages to be logged. */
- void select(const Selector& s);
-
- /** Set the formatting flags, bitwise OR of FormatFlag values. */
- void format(int formatFlags);
-
- /** Set format flags from options object.
- *@returns computed flags.
- */
- int format(const Options&);
-
- /** Configure logger from Options */
- void configure(const Options& o);
-
- /** Add a statement. */
- void add(Statement& s);
-
- /** Log a message. */
- void log(const Statement&, const std::string&);
-
- /** Add an ostream to outputs.
- *
- * The ostream must not be destroyed while the Logger might
- * still be using it. This is the case for std streams cout,
- * cerr, clog.
- */
- void output(std::ostream&);
-
- /** Add syslog to outputs. */
- void syslog(const Options&);
-
- /** Add an output.
- *@param name a file name or one of the special tokens:
- *stdout, stderr, syslog.
- */
- void output(const std::string& name, const Options&);
-
- /** Add an output destination for messages */
- void output(std::auto_ptr<Output> out);
-
- /** Set a prefix for all messages */
- void setPrefix(const std::string& prefix);
-
- /** Reset the logger to it's original state. */
- void clear();
-
-
- private:
- typedef boost::ptr_vector<Output> Outputs;
- typedef std::set<Statement*> Statements;
-
- sys::Mutex lock;
- inline void enable_unlocked(Statement* s);
-
- Statements statements;
- Outputs outputs;
- Selector selector;
- int flags;
- std::string prefix;
-};
-
-}} // namespace qpid::log
-
-
-#endif /*!LOGGER_H*/
diff --git a/cpp/src/qpid/log/Options.cpp b/cpp/src/qpid/log/Options.cpp
index e28f82648e..24ef413cbc 100644
--- a/cpp/src/qpid/log/Options.cpp
+++ b/cpp/src/qpid/log/Options.cpp
@@ -16,116 +16,39 @@
*
*/
-#include "Options.h"
-#include "Statement.h"
+#include "qpid/log/Options.h"
+#include "qpid/log/SinkOptions.h"
+#include "qpid/log/Statement.h"
#include "qpid/Options.h"
#include <map>
#include <string>
#include <algorithm>
-#include <syslog.h>
namespace qpid {
namespace log {
using namespace std;
-namespace {
-
-class SyslogFacilities {
- public:
- typedef map<string, int> ByName;
- typedef map<int, string> ByValue;
-
- SyslogFacilities() {
- struct NameValue { const char* name; int value; };
- NameValue nameValue[] = {
- { "AUTH", LOG_AUTH },
- { "AUTHPRIV", LOG_AUTHPRIV },
- { "CRON", LOG_CRON },
- { "DAEMON", LOG_DAEMON },
- { "FTP", LOG_FTP },
- { "KERN", LOG_KERN },
- { "LOCAL0", LOG_LOCAL0 },
- { "LOCAL1", LOG_LOCAL1 },
- { "LOCAL2", LOG_LOCAL2 },
- { "LOCAL3", LOG_LOCAL3 },
- { "LOCAL4", LOG_LOCAL4 },
- { "LOCAL5", LOG_LOCAL5 },
- { "LOCAL6", LOG_LOCAL6 },
- { "LOCAL7", LOG_LOCAL7 },
- { "LPR", LOG_LPR },
- { "MAIL", LOG_MAIL },
- { "NEWS", LOG_NEWS },
- { "SYSLOG", LOG_SYSLOG },
- { "USER", LOG_USER },
- { "UUCP", LOG_UUCP }
- };
- for (size_t i = 0; i < sizeof(nameValue)/sizeof(nameValue[0]); ++i) {
- byName.insert(ByName::value_type(nameValue[i].name, nameValue[i].value));
- // Recognise with and without LOG_ prefix e.g.: AUTH and LOG_AUTH
- byName.insert(ByName::value_type(string("LOG_")+nameValue[i].name, nameValue[i].value));
- byValue.insert(ByValue::value_type(nameValue[i].value, string("LOG_")+nameValue[i].name));
- }
- };
-
- int value(const string& name) const {
- string key(name);
- transform(key.begin(), key.end(), key.begin(), ::toupper);
- ByName::const_iterator i = byName.find(key);
- if (i == byName.end())
- throw Exception("Not a valid syslog facility: " + name);
- return i->second;
- }
-
- string name(int value) const {
- ByValue::const_iterator i = byValue.find(value);
- if (i == byValue.end())
- throw Exception("Not a valid syslog value: " + value);
- return i->second;
- }
-
- private:
- ByName byName;
- ByValue byValue;
-};
-
-}
-
-ostream& operator<<(ostream& o, const SyslogFacility& f) {
- return o << SyslogFacilities().name(f.value);
-}
-
-istream& operator>>(istream& i, SyslogFacility& f) {
- std::string name;
- i >> name;
- f.value = SyslogFacilities().value(name);
- return i;
-}
-
-namespace {
-std::string basename(const std::string path) {
- size_t i = path.find_last_of('/');
- return path.substr((i == std::string::npos) ? 0 : i+1);
-}
-}
-
-Options::Options(const std::string& argv0, const std::string& name) :
- qpid::Options(name),
- time(true), level(true), thread(false), source(false), function(false), trace(false),
- syslogName(basename(argv0)), syslogFacility(LOG_DAEMON)
+Options::Options(const std::string& argv0_, const std::string& name_) :
+ qpid::Options(name_),
+ argv0(argv0_),
+ name(name_),
+ time(true),
+ level(true),
+ thread(false),
+ source(false),
+ function(false),
+ trace(false),
+ sinkOptions (SinkOptions::create(argv0_))
{
- outputs.push_back("stderr");
- selectors.push_back("error+");
+ selectors.push_back("notice+");
ostringstream levels;
levels << LevelTraits::name(Level(0));
for (int i = 1; i < LevelTraits::COUNT; ++i)
levels << " " << LevelTraits::name(Level(i));
-
+
addOptions()
- ("log-output", optValue(outputs, "FILE"), "Send log output to FILE. "
- "FILE can be a file name or one of the special values:\n"
- "stderr, stdout, syslog")
("trace,t", optValue(trace), "Enables all logging" )
("log-enable", optValue(selectors, "RULE"),
("Enables logging for selected levels and components. "
@@ -143,9 +66,42 @@ Options::Options(const std::string& argv0, const std::string& name) :
("log-thread", optValue(thread,"yes|no"), "Include thread ID in log messages")
("log-function", optValue(function,"yes|no"), "Include function signature in log messages")
("log-prefix", optValue(prefix,"STRING"), "Prefix to append to all log messages")
- ("syslog-name", optValue(syslogName, "NAME"), "Name to use in syslog messages")
- ("syslog-facility", optValue(syslogFacility,"LOG_XXX"), "Facility to use in syslog messages")
;
-}
+ add(*sinkOptions);
+}
+
+Options::Options(const Options &o) :
+ qpid::Options(o.name),
+ argv0(o.argv0),
+ name(o.name),
+ selectors(o.selectors),
+ time(o.time),
+ level(o.level),
+ thread(o.thread),
+ source(o.source),
+ function(o.function),
+ trace(o.trace),
+ prefix(o.prefix),
+ sinkOptions (SinkOptions::create(o.argv0))
+{
+ *sinkOptions = *o.sinkOptions;
+}
+
+Options& Options::operator=(const Options& x) {
+ if (this != &x) {
+ argv0 = x.argv0;
+ name = x.name;
+ selectors = x.selectors;
+ time = x.time;
+ level= x.level;
+ thread = x.thread;
+ source = x.source;
+ function = x.function;
+ trace = x.trace;
+ prefix = x.prefix;
+ *sinkOptions = *x.sinkOptions;
+ }
+ return *this;
+}
}} // namespace qpid::log
diff --git a/cpp/src/qpid/log/Options.h b/cpp/src/qpid/log/Options.h
deleted file mode 100644
index 13fca38f9d..0000000000
--- a/cpp/src/qpid/log/Options.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef OPTIONS_H
-#define OPTIONS_H
-
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-#include "qpid/Options.h"
-#include <iosfwd>
-
-namespace qpid {
-namespace log {
-
-/** Provides << and >> operators to convert syslog facility values to/from strings. */
-struct SyslogFacility {
- int value;
- SyslogFacility(int i=0) : value(i) {}
-};
-
-std::ostream& operator<<(std::ostream&, const SyslogFacility&);
-std::istream& operator>>(std::istream&, SyslogFacility&);
-
-/** Logging options for config parser. */
-struct Options : public qpid::Options {
- /** Pass argv[0] for use in syslog output */
- Options(const std::string& argv0,
- const std::string& name="Logging options");
-
- std::vector<std::string> selectors;
- std::vector<std::string> outputs;
- bool time, level, thread, source, function;
- bool trace;
- std::string syslogName;
- SyslogFacility syslogFacility;
- std::string prefix;
-};
-
-
-}} // namespace qpid::log
-
-
-
-#endif /*!OPTIONS_H*/
diff --git a/cpp/src/qpid/log/OstreamOutput.cpp b/cpp/src/qpid/log/OstreamOutput.cpp
new file mode 100644
index 0000000000..9b6ec1f8aa
--- /dev/null
+++ b/cpp/src/qpid/log/OstreamOutput.cpp
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/log/OstreamOutput.h"
+#include <stdexcept>
+
+using namespace std;
+
+namespace qpid {
+namespace log {
+
+OstreamOutput::OstreamOutput(std::ostream& o) : out(&o) {}
+
+OstreamOutput::OstreamOutput(const std::string& file)
+ : out(new ofstream(file.c_str(), ios_base::out | ios_base::app)),
+ mine(out)
+{
+ if (!out->good())
+ throw std::runtime_error("Can't open log file: "+file);
+}
+
+void OstreamOutput::log(const Statement&, const std::string& m) {
+ *out << m << flush;
+}
+
+}} // namespace qpid::log
diff --git a/cpp/src/qpid/log/OstreamOutput.h b/cpp/src/qpid/log/OstreamOutput.h
new file mode 100644
index 0000000000..12fd4ce425
--- /dev/null
+++ b/cpp/src/qpid/log/OstreamOutput.h
@@ -0,0 +1,41 @@
+#ifndef QPID_LOG_OSTREAMOUTPUT_H
+#define QPID_LOG_OSTREAMOUTPUT_H
+
+/*
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/log/Logger.h"
+#include <boost/scoped_ptr.hpp>
+#include <fstream>
+#include <ostream>
+
+namespace qpid {
+namespace log {
+
+/**
+ * OstreamOutput is a reusable logging sink that directs logging to a C++
+ * ostream.
+ */
+class OstreamOutput : public qpid::log::Logger::Output {
+public:
+ QPID_COMMON_EXTERN OstreamOutput(std::ostream& o);
+ QPID_COMMON_EXTERN OstreamOutput(const std::string& file);
+
+ virtual void log(const Statement&, const std::string& m);
+
+private:
+ std::ostream* out;
+ boost::scoped_ptr<std::ostream> mine;
+};
+
+}} // namespace qpid::log
+
+#endif /*!QPID_LOG_OSTREAMOUTPUT_H*/
diff --git a/cpp/src/qpid/log/Selector.cpp b/cpp/src/qpid/log/Selector.cpp
index 994421d0ff..a4bc580470 100644
--- a/cpp/src/qpid/log/Selector.cpp
+++ b/cpp/src/qpid/log/Selector.cpp
@@ -16,10 +16,11 @@
*
*/
-#include "Selector.h"
-#include "Options.h"
+#include "qpid/log/Selector.h"
+#include "qpid/log/Options.h"
#include <boost/bind.hpp>
#include <algorithm>
+#include <string.h>
namespace qpid {
namespace log {
@@ -52,12 +53,13 @@ Selector::Selector(const Options& opt){
boost::bind(&Selector::enable, this, _1));
}
-bool Selector::isEnabled(Level level, const std::string& function) {
+bool Selector::isEnabled(Level level, const char* function) {
+ const char* functionEnd = function+::strlen(function);
for (std::vector<std::string>::iterator i=substrings[level].begin();
i != substrings[level].end();
++i)
{
- if (function.find(*i) != std::string::npos)
+ if (std::search(function, functionEnd, i->begin(), i->end()) != functionEnd)
return true;
}
return false;
diff --git a/cpp/src/qpid/log/Selector.h b/cpp/src/qpid/log/Selector.h
deleted file mode 100644
index 7c98bc6f8f..0000000000
--- a/cpp/src/qpid/log/Selector.h
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef SELECTOR_H
-#define SELECTOR_H
-
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "Statement.h"
-#include <vector>
-
-namespace qpid {
-namespace log {
-class Options;
-
-/**
- * A selector identifies the set of log messages to enable.
- *
- * Thread object unsafe, pass-by-value type.
- */
-class Selector {
- public:
- /** Empty selector selects nothing */
- Selector() {}
-
- /** Set selector from Options */
- Selector(const Options&);
-
- /** Equavlient to: Selector s; s.enable(l, s) */
- Selector(Level l, const std::string& s=std::string()) {
- enable(l,s);
- }
-
- Selector(const std::string& enableStr) { enable(enableStr); }
- /**
- * Enable messages with level in levels where the file
- * name contains substring. Empty string matches all.
- */
- void enable(Level level, const std::string& substring=std::string()) {
- substrings[level].push_back(substring);
- }
-
- /** Enable based on a 'level[+]:file' string */
- void enable(const std::string& enableStr);
-
- /** True if level is enabld for file. */
- bool isEnabled(Level level, const std::string& function);
-
- private:
- std::vector<std::string> substrings[LevelTraits::COUNT];
-};
-
-
-}} // namespace qpid::log
-
-
-#endif /*!SELECTOR_H*/
diff --git a/cpp/src/qpid/log/Statement.cpp b/cpp/src/qpid/log/Statement.cpp
index c2b286f1e7..6a32b50096 100644
--- a/cpp/src/qpid/log/Statement.cpp
+++ b/cpp/src/qpid/log/Statement.cpp
@@ -16,12 +16,11 @@
*
*/
-#include "Statement.h"
-#include "Logger.h"
+#include "qpid/log/Statement.h"
+#include "qpid/log/Logger.h"
#include <boost/bind.hpp>
#include <stdexcept>
#include <algorithm>
-#include <syslog.h>
#include <ctype.h>
namespace qpid {
@@ -67,11 +66,6 @@ const char* names[LevelTraits::COUNT] = {
"trace", "debug", "info", "notice", "warning", "error", "critical"
};
-int priorities[LevelTraits::COUNT] = {
- LOG_DEBUG, LOG_DEBUG, LOG_INFO, LOG_NOTICE,
- LOG_WARNING, LOG_ERR, LOG_CRIT
-};
-
} // namespace
Level LevelTraits::level(const char* name) {
@@ -86,8 +80,4 @@ const char* LevelTraits::name(Level l) {
return names[l];
}
-int LevelTraits::priority(Level l) {
- return priorities[l];
-}
-
}} // namespace qpid::log
diff --git a/cpp/src/qpid/log/Statement.h b/cpp/src/qpid/log/Statement.h
deleted file mode 100644
index f765df1cf4..0000000000
--- a/cpp/src/qpid/log/Statement.h
+++ /dev/null
@@ -1,128 +0,0 @@
-#ifndef STATEMENT_H
-#define STATEMENT_H
-
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "qpid/Msg.h"
-
-#include <boost/current_function.hpp>
-
-namespace qpid {
-namespace log {
-
-/** Debugging severity levels
- * - trace: High-volume debugging messages.
- * - debug: Debugging messages.
- * - info: Informational messages.
- * - notice: Normal but significant condition.
- * - warning: Warn of a possible problem.
- * - error: A definite error has occured.
- * - critical: System in danger of severe failure.
- */
-enum Level { trace, debug, info, notice, warning, error, critical };
-struct LevelTraits {
- static const int COUNT=critical+1;
-
- /** Get level from string name.
- *@exception if name invalid.
- */
- static Level level(const char* name);
-
- /** Get level from string name.
- *@exception if name invalid.
- */
- static Level level(const std::string& name) {
- return level(name.c_str());
- }
-
- /** String name of level */
- static const char* name(Level);
-
- /** Syslog priority of level */
- static int priority(Level);
-};
-
-/** POD struct representing a logging statement in source code. */
-struct Statement {
- bool enabled;
- const char* file;
- int line;
- const char* function;
- Level level;
-
- void log(const std::string& message);
-
- struct Initializer {
- Initializer(Statement& s);
- Statement& statement;
- };
-};
-
-///@internal static initializer for a Statement.
-#define QPID_LOG_STATEMENT_INIT(level) \
- { 0, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, (::qpid::log::level) }
-
-/**
- * Like QPID_LOG but computes an additional boolean test expression
- * to determine if the message should be logged. Evaluation of both
- * the test and message expressions occurs only if the requested log level
- * is enabled.
- *@param LEVEL severity Level for message, should be one of:
- * debug, info, notice, warning, error, critical. NB no qpid::log:: prefix.
- *@param TEST message is logged only if expression TEST evaluates to true.
- *@param MESSAGE any object with an @eostream operator<<, or a sequence
- * like of ostreamable objects separated by @e<<.
- */
-#define QPID_LOG_IF(LEVEL, TEST, MESSAGE) \
- do { \
- using ::qpid::log::Statement; \
- static Statement stmt_= QPID_LOG_STATEMENT_INIT(LEVEL); \
- static Statement::Initializer init_(stmt_); \
- if (stmt_.enabled && (TEST)) \
- stmt_.log(::qpid::Msg() << MESSAGE); \
- } while(0)
-
-/**
- * Macro for log statements. Example of use:
- * @code
- * QPID_LOG(debug, "There are " << foocount << " foos in the bar.");
- * QPID_LOG(error, boost::format("Dohickey %s exploded") % dohicky.name());
- * @endcode
- *
- * All code with logging statements should be built with
- * -DQPID_COMPONENT=<component name>
- * where component name is the name of the component this file belongs to.
- *
- * You can subscribe to log messages by level, by component, by filename
- * or a combination @see Configuration.
-
- *@param LEVEL severity Level for message, should be one of:
- * debug, info, notice, warning, error, critical. NB no qpid::log:: prefix.
- *@param MESSAGE any object with an @eostream operator<<, or a sequence
- * like of ostreamable objects separated by @e<<.
- */
-#define QPID_LOG(LEVEL, MESSAGE) QPID_LOG_IF(LEVEL, true, MESSAGE);
-
-}} // namespace qpid::log
-
-
-
-
-#endif /*!STATEMENT_H*/
-
diff --git a/cpp/src/qpid/log/posix/SinkOptions.cpp b/cpp/src/qpid/log/posix/SinkOptions.cpp
new file mode 100644
index 0000000000..292e9147f6
--- /dev/null
+++ b/cpp/src/qpid/log/posix/SinkOptions.cpp
@@ -0,0 +1,215 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/log/posix/SinkOptions.h"
+#include "qpid/log/SinkOptions.h"
+#include "qpid/log/Logger.h"
+#include "qpid/log/OstreamOutput.h"
+#include "qpid/memory.h"
+#include "qpid/Exception.h"
+#include <iostream>
+#include <map>
+#include <string>
+#include <syslog.h>
+
+using std::string;
+using qpid::Exception;
+
+namespace {
+
+// SyslogFacilities maps from syslog values to the text equivalents.
+class SyslogFacilities {
+public:
+ typedef std::map<string, int> ByName;
+ typedef std::map<int, string> ByValue;
+
+ SyslogFacilities() {
+ struct NameValue { const char* name; int value; };
+ NameValue nameValue[] = {
+ { "AUTH", LOG_AUTH },
+#ifdef HAVE_LOG_AUTHPRIV
+ { "AUTHPRIV", LOG_AUTHPRIV },
+#endif
+ { "CRON", LOG_CRON },
+ { "DAEMON", LOG_DAEMON },
+#ifdef HAVE_LOG_FTP
+ { "FTP", LOG_FTP },
+#endif
+ { "KERN", LOG_KERN },
+ { "LOCAL0", LOG_LOCAL0 },
+ { "LOCAL1", LOG_LOCAL1 },
+ { "LOCAL2", LOG_LOCAL2 },
+ { "LOCAL3", LOG_LOCAL3 },
+ { "LOCAL4", LOG_LOCAL4 },
+ { "LOCAL5", LOG_LOCAL5 },
+ { "LOCAL6", LOG_LOCAL6 },
+ { "LOCAL7", LOG_LOCAL7 },
+ { "LPR", LOG_LPR },
+ { "MAIL", LOG_MAIL },
+ { "NEWS", LOG_NEWS },
+ { "SYSLOG", LOG_SYSLOG },
+ { "USER", LOG_USER },
+ { "UUCP", LOG_UUCP }
+ };
+ for (size_t i = 0; i < sizeof(nameValue)/sizeof(nameValue[0]); ++i) {
+ byName.insert(ByName::value_type(nameValue[i].name, nameValue[i].value));
+ // Recognise with and without LOG_ prefix e.g.: AUTH and LOG_AUTH
+ byName.insert(ByName::value_type(string("LOG_")+nameValue[i].name, nameValue[i].value));
+ byValue.insert(ByValue::value_type(nameValue[i].value, string("LOG_")+nameValue[i].name));
+ }
+ }
+
+ int value(const string& name) const {
+ string key(name);
+ std::transform(key.begin(), key.end(), key.begin(), ::toupper);
+ ByName::const_iterator i = byName.find(key);
+ if (i == byName.end())
+ throw Exception("Not a valid syslog facility: " + name);
+ return i->second;
+ }
+
+ string name(int value) const {
+ ByValue::const_iterator i = byValue.find(value);
+ if (i == byValue.end())
+ throw Exception("Not a valid syslog value: " + value);
+ return i->second;
+ }
+
+ private:
+ ByName byName;
+ ByValue byValue;
+};
+
+// 'priorities' maps qpid log levels to syslog priorities. They are in
+// order of qpid log levels and must map to:
+// "trace", "debug", "info", "notice", "warning", "error", "critical"
+static int priorities[qpid::log::LevelTraits::COUNT] = {
+ LOG_DEBUG, LOG_DEBUG, LOG_INFO, LOG_NOTICE,
+ LOG_WARNING, LOG_ERR, LOG_CRIT
+};
+
+std::string basename(const std::string path) {
+ size_t i = path.find_last_of('/');
+ return path.substr((i == std::string::npos) ? 0 : i+1);
+}
+
+} // namespace
+
+namespace qpid {
+namespace log {
+namespace posix {
+
+std::ostream& operator<<(std::ostream& o, const SyslogFacility& f) {
+ return o << SyslogFacilities().name(f.value);
+}
+
+std::istream& operator>>(std::istream& i, SyslogFacility& f) {
+ std::string name;
+ i >> name;
+ f.value = SyslogFacilities().value(name);
+ return i;
+}
+
+class SyslogOutput : public qpid::log::Logger::Output {
+public:
+ SyslogOutput(const std::string& logName, const SyslogFacility& logFacility)
+ : name(logName), facility(logFacility.value)
+ {
+ ::openlog(name.c_str(), LOG_PID, facility);
+ }
+
+ virtual ~SyslogOutput() {
+ ::closelog();
+ }
+
+ virtual void log(const Statement& s, const std::string& m)
+ {
+ syslog(priorities[s.level], "%s", m.c_str());
+ }
+
+private:
+ std::string name;
+ int facility;
+};
+
+SinkOptions::SinkOptions(const std::string& argv0)
+ : qpid::log::SinkOptions(),
+ logToStderr(true),
+ logToStdout(false),
+ logToSyslog(false),
+ syslogName(basename(argv0)),
+ syslogFacility(LOG_DAEMON) {
+
+ addOptions()
+ ("log-to-stderr", optValue(logToStderr, "yes|no"), "Send logging output to stderr")
+ ("log-to-stdout", optValue(logToStdout, "yes|no"), "Send logging output to stdout")
+ ("log-to-file", optValue(logFile, "FILE"), "Send log output to FILE.")
+ ("log-to-syslog", optValue(logToSyslog, "yes|no"), "Send logging output to syslog;\n\tcustomize using --syslog-name and --syslog-facility")
+ ("syslog-name", optValue(syslogName, "NAME"), "Name to use in syslog messages")
+ ("syslog-facility", optValue(syslogFacility,"LOG_XXX"), "Facility to use in syslog messages")
+ ;
+
+}
+
+qpid::log::SinkOptions& SinkOptions::operator=(const qpid::log::SinkOptions& rhs) {
+ const SinkOptions *prhs = dynamic_cast<const SinkOptions*>(&rhs);
+ if (this != prhs) {
+ logToStderr = prhs->logToStderr;
+ logToStdout = prhs->logToStdout;
+ logToSyslog = prhs->logToSyslog;
+ logFile = prhs->logFile;
+ syslogName = prhs->syslogName;
+ syslogFacility.value = prhs->syslogFacility.value;
+ }
+ return *this;
+}
+
+void SinkOptions::detached(void) {
+ if (logToStderr && !logToStdout && !logToSyslog) {
+ logToStderr = false;
+ logToSyslog = true;
+ }
+}
+
+// The Logger acting on these options calls setup() to request any
+// Sinks be set up and fed back to the logger.
+void SinkOptions::setup(qpid::log::Logger *logger) {
+ if (logToStderr)
+ logger->output(make_auto_ptr<qpid::log::Logger::Output>
+ (new qpid::log::OstreamOutput(std::clog)));
+ if (logToStdout)
+ logger->output(make_auto_ptr<qpid::log::Logger::Output>
+ (new qpid::log::OstreamOutput(std::cout)));
+
+ if (logFile.length() > 0)
+ logger->output(make_auto_ptr<qpid::log::Logger::Output>
+ (new qpid::log::OstreamOutput(logFile)));
+
+ if (logToSyslog)
+ logger->output(make_auto_ptr<qpid::log::Logger::Output>
+ (new SyslogOutput(syslogName, syslogFacility)));
+
+}
+
+} // namespace qpid::log::posix
+
+SinkOptions* SinkOptions::create(const std::string& argv0) {
+ return new qpid::log::posix::SinkOptions (argv0);
+}
+
+}} // namespace qpid::log
diff --git a/cpp/src/qpid/log/posix/SinkOptions.h b/cpp/src/qpid/log/posix/SinkOptions.h
new file mode 100644
index 0000000000..d929c29025
--- /dev/null
+++ b/cpp/src/qpid/log/posix/SinkOptions.h
@@ -0,0 +1,64 @@
+#ifndef QPID_LOG_POSIX_SINKOPTIONS_H
+#define QPID_LOG_POSIX_SINKOPTIONS_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/log/SinkOptions.h"
+#include <string>
+
+namespace qpid {
+namespace log {
+namespace posix {
+
+/**
+ * Provides a type that can be passed to << and >> operators to convert
+ * syslog facility values to/from strings.
+ */
+struct SyslogFacility {
+ int value;
+ SyslogFacility(int i=0) : value(i) {}
+};
+
+struct SinkOptions : public qpid::log::SinkOptions {
+ SinkOptions(const std::string& argv0);
+ virtual ~SinkOptions() {}
+
+ virtual qpid::log::SinkOptions& operator=(const qpid::log::SinkOptions& rhs);
+
+ // This allows the caller to indicate that there's no normal outputs
+ // available. For example, when running as a daemon. In these cases, the
+ // platform's "syslog"-type output should replace the default stderr
+ // unless some other sink has been selected.
+ virtual void detached(void);
+
+ // The Logger acting on these options calls setup() to request any
+ // Sinks be set up and fed back to the logger.
+ virtual void setup(qpid::log::Logger *logger);
+
+ bool logToStderr;
+ bool logToStdout;
+ bool logToSyslog;
+ std::string logFile;
+ std::string syslogName;
+ SyslogFacility syslogFacility;
+};
+
+}}} // namespace qpid::log::posix
+
+#endif /*!QPID_LOG_POSIX_SINKOPTIONS_H*/
diff --git a/cpp/src/qpid/log/windows/SinkOptions.cpp b/cpp/src/qpid/log/windows/SinkOptions.cpp
new file mode 100644
index 0000000000..28f4b267e0
--- /dev/null
+++ b/cpp/src/qpid/log/windows/SinkOptions.cpp
@@ -0,0 +1,148 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/log/windows/SinkOptions.h"
+#include "qpid/log/SinkOptions.h"
+#include "qpid/log/Logger.h"
+#include "qpid/log/OstreamOutput.h"
+#include "qpid/memory.h"
+#include "qpid/Exception.h"
+#include <iostream>
+#include <map>
+#include <string>
+
+#include <windows.h>
+
+using qpid::Exception;
+
+namespace qpid {
+namespace log {
+namespace windows {
+
+namespace {
+
+// 'eventTypes' maps qpid log levels to Windows event types. They are in
+// order of qpid log levels and must map to:
+// "trace", "debug", "info", "notice", "warning", "error", "critical"
+static int eventTypes[qpid::log::LevelTraits::COUNT] = {
+ EVENTLOG_INFORMATION_TYPE, /* trace */
+ EVENTLOG_INFORMATION_TYPE, /* debug */
+ EVENTLOG_INFORMATION_TYPE, /* info */
+ EVENTLOG_INFORMATION_TYPE, /* notice */
+ EVENTLOG_WARNING_TYPE, /* warning */
+ EVENTLOG_ERROR_TYPE, /* error */
+ EVENTLOG_ERROR_TYPE /* critical */
+};
+
+} // namespace
+
+class EventLogOutput : public qpid::log::Logger::Output {
+public:
+ EventLogOutput(const std::string& sourceName) : logHandle(0)
+ {
+ logHandle = OpenEventLog(0, "Application");
+ }
+
+ virtual ~EventLogOutput() {
+ if (logHandle)
+ CloseEventLog(logHandle);
+ }
+
+ virtual void log(const Statement& s, const std::string& m)
+ {
+ if (logHandle) {
+ const char *msg = m.c_str();
+ ReportEvent(logHandle,
+ eventTypes[s.level],
+ 0, /* category unused */
+ 0, /* event id */
+ 0, /* user security id */
+ 1, /* number of strings */
+ 0, /* no event-specific data */
+ &msg,
+ 0);
+ }
+ }
+
+private:
+ HANDLE logHandle;
+};
+
+SinkOptions::SinkOptions(const std::string& argv0)
+ : qpid::log::SinkOptions(),
+ logToStderr(true),
+ logToStdout(false),
+ logToEventLog(false),
+ eventSource("Application")
+{
+ addOptions()
+ ("log-to-stderr", optValue(logToStderr, "yes|no"), "Send logging output to stderr")
+ ("log-to-stdout", optValue(logToStdout, "yes|no"), "Send logging output to stdout")
+ ("log-to-file", optValue(logFile, "FILE"), "Send log output to FILE.")
+ ("log-to-eventlog", optValue(logToEventLog, "yes|no"), "Send logging output to event log;\n\tcustomize using --syslog-name and --syslog-facility")
+ ("eventlog-source-name", optValue(eventSource, "Application"), "Event source to log to")
+ ;
+
+}
+
+qpid::log::SinkOptions& SinkOptions::operator=(const qpid::log::SinkOptions& rhs) {
+ const SinkOptions *prhs = dynamic_cast<const SinkOptions*>(&rhs);
+ if (this != prhs) {
+ logToStderr = prhs->logToStderr;
+ logToStdout = prhs->logToStdout;
+ logToEventLog = prhs->logToEventLog;
+ eventSource = prhs->eventSource;
+ logFile = prhs->logFile;
+ }
+ return *this;
+}
+
+void SinkOptions::detached(void) {
+ if (logToStderr && !logToStdout && !logToEventLog) {
+ logToStderr = false;
+ logToEventLog = true;
+ }
+}
+
+// The Logger acting on these options calls setup() to request any
+// Sinks be set up and fed back to the logger.
+void SinkOptions::setup(qpid::log::Logger *logger) {
+ if (logToStderr)
+ logger->output(make_auto_ptr<qpid::log::Logger::Output>
+ (new qpid::log::OstreamOutput(std::clog)));
+ if (logToStdout)
+ logger->output(make_auto_ptr<qpid::log::Logger::Output>
+ (new qpid::log::OstreamOutput(std::cout)));
+
+ if (logFile.length() > 0)
+ logger->output(make_auto_ptr<qpid::log::Logger::Output>
+ (new qpid::log::OstreamOutput(logFile)));
+
+ if (logToEventLog)
+ logger->output(make_auto_ptr<qpid::log::Logger::Output>
+ (new EventLogOutput(eventSource)));
+
+}
+
+} // namespace windows
+
+SinkOptions* SinkOptions::create(const std::string& argv0) {
+ return new qpid::log::windows::SinkOptions (argv0);
+}
+
+}} // namespace qpid::log
diff --git a/cpp/src/qpid/log/windows/SinkOptions.h b/cpp/src/qpid/log/windows/SinkOptions.h
new file mode 100644
index 0000000000..605822fd46
--- /dev/null
+++ b/cpp/src/qpid/log/windows/SinkOptions.h
@@ -0,0 +1,54 @@
+#ifndef QPID_LOG_WINDOWS_SINKOPTIONS_H
+#define QPID_LOG_WINDOWS_SINKOPTIONS_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/log/SinkOptions.h"
+#include <string>
+
+namespace qpid {
+namespace log {
+namespace windows {
+
+struct SinkOptions : public qpid::log::SinkOptions {
+ QPID_COMMON_EXTERN SinkOptions(const std::string& argv0);
+ virtual ~SinkOptions() {}
+
+ QPID_COMMON_EXTERN virtual qpid::log::SinkOptions& operator=(const qpid::log::SinkOptions& rhs);
+
+ // This allows the caller to indicate that there's no normal outputs
+ // available. For example, when running as a service. In these cases, the
+ // platform's "syslog"-type output should replace the default stderr
+ // unless some other sink has been selected.
+ QPID_COMMON_EXTERN virtual void detached(void);
+
+ // The Logger acting on these options calls setup() to request any
+ // Sinks be set up and fed back to the logger.
+ QPID_COMMON_EXTERN virtual void setup(qpid::log::Logger *logger);
+
+ bool logToStderr;
+ bool logToStdout;
+ bool logToEventLog;
+ std::string eventSource;
+ std::string logFile;
+};
+
+}}} // namespace qpid::log::windows
+
+#endif /*!QPID_LOG_WINDOWS_SINKOPTIONS_H*/
diff --git a/cpp/src/qpid/management/Args.h b/cpp/src/qpid/management/Args.h
deleted file mode 100644
index da1fb033b9..0000000000
--- a/cpp/src/qpid/management/Args.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef _Args_
-#define _Args_
-
-//
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-//
-
-
-namespace qpid {
-namespace management {
-
-class Args
-{
- public:
-
- virtual ~Args (void) = 0;
-
-};
-
-inline Args::~Args (void) {}
-
-class ArgsNone : public Args
-{
-};
-
-}}
-
-
-#endif /*!_Args_*/
diff --git a/cpp/src/qpid/management/IdAllocator.h b/cpp/src/qpid/management/IdAllocator.h
new file mode 100644
index 0000000000..6f49d6d13f
--- /dev/null
+++ b/cpp/src/qpid/management/IdAllocator.h
@@ -0,0 +1,42 @@
+#ifndef QPID_MANAGEMENT_IDALLOCATOR_H
+#define QPID_MANAGEMENT_IDALLOCATOR_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/management/Manageable.h"
+
+namespace qpid {
+namespace management {
+
+/**
+ * Interface through which plugins etc can control the mgmt object id
+ * allocation for special cases
+ */
+struct IdAllocator
+{
+ virtual uint64_t getIdFor(Manageable* object) = 0;
+ virtual ~IdAllocator() {}
+};
+
+}} // namespace qpid::management
+
+#endif /*!QPID_MANAGEMENT_IDALLOCATOR_H*/
diff --git a/cpp/src/qpid/management/Manageable.cpp b/cpp/src/qpid/management/Manageable.cpp
index 0f3fbab55c..a3593e73e3 100644
--- a/cpp/src/qpid/management/Manageable.cpp
+++ b/cpp/src/qpid/management/Manageable.cpp
@@ -17,26 +17,31 @@
// under the License.
//
-#include "Manageable.h"
+#include "qpid/management/Manageable.h"
using namespace qpid::management;
+using std::string;
-std::string Manageable::StatusText (status_t status)
+string Manageable::StatusText (status_t status, string text)
{
+ if ((status & STATUS_USER) == STATUS_USER)
+ return text;
+
switch (status)
{
case STATUS_OK : return "OK";
case STATUS_UNKNOWN_OBJECT : return "UnknownObject";
case STATUS_UNKNOWN_METHOD : return "UnknownMethod";
case STATUS_NOT_IMPLEMENTED : return "NotImplemented";
- case STATUS_INVALID_PARAMETER : return "InvalidParameter";
+ case STATUS_PARAMETER_INVALID : return "InvalidParameter";
case STATUS_FEATURE_NOT_IMPLEMENTED : return "FeatureNotImplemented";
+ case STATUS_FORBIDDEN : return "Forbidden";
}
return "??";
}
-Manageable::status_t Manageable::ManagementMethod (uint32_t, Args&)
+Manageable::status_t Manageable::ManagementMethod (uint32_t, Args&, std::string&)
{
return STATUS_UNKNOWN_METHOD;
}
diff --git a/cpp/src/qpid/management/Manageable.h b/cpp/src/qpid/management/Manageable.h
deleted file mode 100644
index e2b8980465..0000000000
--- a/cpp/src/qpid/management/Manageable.h
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef _Manageable_
-#define _Manageable_
-
-//
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-//
-
-#include "ManagementObject.h"
-#include "Args.h"
-#include <string>
-
-namespace qpid {
-namespace management {
-
-class Manageable
-{
- public:
-
- virtual ~Manageable (void) = 0;
-
- // status_t is a type used to pass completion status from the method handler.
- //
- typedef uint32_t status_t;
- static std::string StatusText (status_t status);
-
- static const status_t STATUS_OK = 0;
- static const status_t STATUS_UNKNOWN_OBJECT = 1;
- static const status_t STATUS_UNKNOWN_METHOD = 2;
- static const status_t STATUS_NOT_IMPLEMENTED = 3;
- static const status_t STATUS_INVALID_PARAMETER = 4;
- static const status_t STATUS_FEATURE_NOT_IMPLEMENTED = 5;
-
- // Every "Manageable" object must hold a reference to exactly one
- // management object. This object is always of a class derived from
- // the pure-virtual "ManagementObject".
- //
- // This accessor function returns a pointer to the management object.
- //
- virtual ManagementObject* GetManagementObject (void) const = 0;
-
- // Every "Manageable" object must implement ManagementMethod. This
- // function is called when a remote management client invokes a method
- // on this object. The input and output arguments are specific to the
- // method being called and must be down-cast to the appropriate sub class
- // before use.
- virtual status_t ManagementMethod (uint32_t methodId, Args& args);
-};
-
-inline Manageable::~Manageable (void) {}
-
-}}
-
-#endif /*!_Manageable_*/
diff --git a/cpp/src/qpid/management/ManagementAgent.cpp b/cpp/src/qpid/management/ManagementAgent.cpp
new file mode 100644
index 0000000000..b5ed4ed405
--- /dev/null
+++ b/cpp/src/qpid/management/ManagementAgent.cpp
@@ -0,0 +1,1295 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/management/ManagementAgent.h"
+#include "qpid/management/ManagementObject.h"
+#include "qpid/management/IdAllocator.h"
+#include "qpid/broker/DeliverableMessage.h"
+#include "qpid/log/Statement.h"
+#include <qpid/broker/Message.h>
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/sys/Time.h"
+#include "qpid/broker/ConnectionState.h"
+#include "qpid/broker/AclModule.h"
+#include <list>
+#include <iostream>
+#include <fstream>
+
+using boost::intrusive_ptr;
+using qpid::framing::Uuid;
+using namespace qpid::framing;
+using namespace qpid::management;
+using namespace qpid::broker;
+using namespace qpid::sys;
+using namespace std;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+ManagementAgent::RemoteAgent::~RemoteAgent ()
+{
+ QPID_LOG(trace, "Remote Agent removed bank=[" << brokerBank << "." << agentBank << "]");
+ if (mgmtObject != 0) {
+ mgmtObject->resourceDestroy();
+ agent.deleteObjectNowLH(mgmtObject->getObjectId());
+ }
+}
+
+ManagementAgent::ManagementAgent () :
+ threadPoolSize(1), interval(10), broker(0), startTime(uint64_t(Duration(now())))
+{
+ nextObjectId = 1;
+ brokerBank = 1;
+ bootSequence = 1;
+ nextRemoteBank = 10;
+ nextRequestSequence = 1;
+ clientWasAdded = false;
+}
+
+ManagementAgent::~ManagementAgent ()
+{
+ {
+ Mutex::ScopedLock lock (userLock);
+
+ // Reset the shared pointers to exchanges. If this is not done now, the exchanges
+ // will stick around until dExchange and mExchange are implicitely destroyed (long
+ // after this destructor completes). Those exchanges hold references to management
+ // objects that will be invalid.
+ dExchange.reset();
+ mExchange.reset();
+
+ moveNewObjectsLH();
+ for (ManagementObjectMap::iterator iter = managementObjects.begin ();
+ iter != managementObjects.end ();
+ iter++) {
+ ManagementObject* object = iter->second;
+ delete object;
+ }
+ managementObjects.clear();
+ }
+}
+
+void ManagementAgent::configure(const string& _dataDir, uint16_t _interval,
+ qpid::broker::Broker* _broker, int _threads)
+{
+ dataDir = _dataDir;
+ interval = _interval;
+ broker = _broker;
+ timer = &_broker->getTimer();
+ threadPoolSize = _threads;
+ ManagementObject::maxThreads = threadPoolSize;
+ timer->add (new Periodic(*this, interval));
+
+ // Get from file or generate and save to file.
+ if (dataDir.empty())
+ {
+ uuid.generate();
+ QPID_LOG (info, "ManagementAgent has no data directory, generated new broker ID: "
+ << uuid);
+ }
+ else
+ {
+ string filename(dataDir + "/.mbrokerdata");
+ ifstream inFile(filename.c_str ());
+
+ if (inFile.good())
+ {
+ inFile >> uuid;
+ inFile >> bootSequence;
+ inFile >> nextRemoteBank;
+ inFile.close();
+ QPID_LOG (debug, "ManagementAgent restored broker ID: " << uuid);
+
+ // if sequence goes beyond a 12-bit field, skip zero and wrap to 1.
+ bootSequence++;
+ if (bootSequence & 0xF000)
+ bootSequence = 1;
+ writeData();
+ }
+ else
+ {
+ uuid.generate();
+ QPID_LOG (info, "ManagementAgent generated broker ID: " << uuid);
+ writeData();
+ }
+
+ QPID_LOG (debug, "ManagementAgent boot sequence: " << bootSequence);
+ }
+}
+
+void ManagementAgent::writeData ()
+{
+ string filename (dataDir + "/.mbrokerdata");
+ ofstream outFile (filename.c_str ());
+
+ if (outFile.good())
+ {
+ outFile << uuid << " " << bootSequence << " " << nextRemoteBank << endl;
+ outFile.close();
+ }
+}
+
+void ManagementAgent::setExchange (qpid::broker::Exchange::shared_ptr _mexchange,
+ qpid::broker::Exchange::shared_ptr _dexchange)
+{
+ mExchange = _mexchange;
+ dExchange = _dexchange;
+}
+
+void ManagementAgent::registerClass (const string& packageName,
+ const string& className,
+ uint8_t* md5Sum,
+ ManagementObject::writeSchemaCall_t schemaCall)
+{
+ Mutex::ScopedLock lock(userLock);
+ PackageMap::iterator pIter = findOrAddPackageLH(packageName);
+ addClassLH(ManagementItem::CLASS_KIND_TABLE, pIter, className, md5Sum, schemaCall);
+}
+
+void ManagementAgent::registerEvent (const string& packageName,
+ const string& eventName,
+ uint8_t* md5Sum,
+ ManagementObject::writeSchemaCall_t schemaCall)
+{
+ Mutex::ScopedLock lock(userLock);
+ PackageMap::iterator pIter = findOrAddPackageLH(packageName);
+ addClassLH(ManagementItem::CLASS_KIND_EVENT, pIter, eventName, md5Sum, schemaCall);
+}
+
+ObjectId ManagementAgent::addObject(ManagementObject* object,
+ uint64_t persistId,
+ bool publishNow)
+{
+ Mutex::ScopedLock lock (addLock);
+ uint16_t sequence;
+ uint64_t objectNum;
+
+ if (persistId == 0) {
+ sequence = bootSequence;
+ objectNum = nextObjectId++;
+ } else {
+ sequence = 0;
+ objectNum = persistId;
+ }
+
+ ObjectId objId(0 /*flags*/ , sequence, brokerBank, 0, objectNum);
+
+ object->setObjectId(objId);
+ newManagementObjects[objId] = object;
+
+ if (publishNow) {
+#define IMM_BUFSIZE 65536
+ char rawBuf[IMM_BUFSIZE];
+ Buffer msgBuffer(rawBuf, IMM_BUFSIZE);
+
+ encodeHeader(msgBuffer, 'c');
+ object->writeProperties(msgBuffer);
+ uint32_t contentSize = msgBuffer.getPosition();
+ stringstream key;
+ key << "console.obj.1.0." << object->getPackageName() << "." << object->getClassName();
+ msgBuffer.reset();
+ sendBuffer(msgBuffer, contentSize, mExchange, key.str());
+ QPID_LOG(trace, "SEND Immediate ContentInd to=" << key.str());
+ }
+
+ return objId;
+}
+
+void ManagementAgent::raiseEvent(const ManagementEvent& event, severity_t severity)
+{
+ Mutex::ScopedLock lock (userLock);
+ Buffer outBuffer(eventBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+ uint8_t sev = (severity == SEV_DEFAULT) ? event.getSeverity() : (uint8_t) severity;
+
+ encodeHeader(outBuffer, 'e');
+ outBuffer.putShortString(event.getPackageName());
+ outBuffer.putShortString(event.getEventName());
+ outBuffer.putBin128(event.getMd5Sum());
+ outBuffer.putLongLong(uint64_t(Duration(now())));
+ outBuffer.putOctet(sev);
+ event.encode(outBuffer);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ sendBuffer(outBuffer, outLen, mExchange,
+ "console.event.1.0." + event.getPackageName() + "." + event.getEventName());
+}
+
+ManagementAgent::Periodic::Periodic (ManagementAgent& _agent, uint32_t _seconds)
+ : TimerTask (qpid::sys::Duration ((_seconds ? _seconds : 1) * qpid::sys::TIME_SEC)), agent(_agent) {}
+
+ManagementAgent::Periodic::~Periodic () {}
+
+void ManagementAgent::Periodic::fire ()
+{
+ agent.timer->add (new Periodic (agent, agent.interval));
+ agent.periodicProcessing ();
+}
+
+void ManagementAgent::clientAdded (const std::string& routingKey)
+{
+ if (routingKey.find("console") != 0)
+ return;
+
+ clientWasAdded = true;
+ for (RemoteAgentMap::iterator aIter = remoteAgents.begin();
+ aIter != remoteAgents.end();
+ aIter++) {
+ char localBuffer[16];
+ Buffer outBuffer(localBuffer, 16);
+ uint32_t outLen;
+
+ encodeHeader(outBuffer, 'x');
+ outLen = outBuffer.getPosition();
+ outBuffer.reset();
+ sendBuffer(outBuffer, outLen, dExchange, aIter->second->routingKey);
+ QPID_LOG(trace, "SEND ConsoleAddedIndication to=" << aIter->second->routingKey);
+ }
+}
+
+void ManagementAgent::encodeHeader (Buffer& buf, uint8_t opcode, uint32_t seq)
+{
+ buf.putOctet ('A');
+ buf.putOctet ('M');
+ buf.putOctet ('2');
+ buf.putOctet (opcode);
+ buf.putLong (seq);
+}
+
+bool ManagementAgent::checkHeader (Buffer& buf, uint8_t *opcode, uint32_t *seq)
+{
+ uint8_t h1 = buf.getOctet();
+ uint8_t h2 = buf.getOctet();
+ uint8_t h3 = buf.getOctet();
+
+ *opcode = buf.getOctet();
+ *seq = buf.getLong();
+
+ return h1 == 'A' && h2 == 'M' && h3 == '2';
+}
+
+void ManagementAgent::sendBuffer(Buffer& buf,
+ uint32_t length,
+ qpid::broker::Exchange::shared_ptr exchange,
+ string routingKey)
+{
+ if (exchange.get() == 0)
+ return;
+
+ intrusive_ptr<Message> msg(new Message());
+ AMQFrame method((MessageTransferBody(ProtocolVersion(), exchange->getName (), 0, 0)));
+ AMQFrame header((AMQHeaderBody()));
+ AMQFrame content((AMQContentBody()));
+
+ content.castBody<AMQContentBody>()->decode(buf, length);
+
+ method.setEof(false);
+ header.setBof(false);
+ header.setEof(false);
+ content.setBof(false);
+
+ msg->getFrames().append(method);
+ msg->getFrames().append(header);
+
+ MessageProperties* props =
+ msg->getFrames().getHeaders()->get<MessageProperties>(true);
+ props->setContentLength(length);
+ msg->getFrames().append(content);
+
+ DeliverableMessage deliverable (msg);
+ try {
+ exchange->route(deliverable, routingKey, 0);
+ } catch(exception&) {}
+}
+
+void ManagementAgent::moveNewObjectsLH()
+{
+ Mutex::ScopedLock lock (addLock);
+ for (ManagementObjectMap::iterator iter = newManagementObjects.begin ();
+ iter != newManagementObjects.end ();
+ iter++)
+ managementObjects[iter->first] = iter->second;
+ newManagementObjects.clear();
+}
+
+void ManagementAgent::periodicProcessing (void)
+{
+#define BUFSIZE 65536
+#define HEADROOM 4096
+ Mutex::ScopedLock lock (userLock);
+ char msgChars[BUFSIZE];
+ uint32_t contentSize;
+ string routingKey;
+ list<pair<ObjectId, ManagementObject*> > deleteList;
+
+ uint64_t uptime = uint64_t(Duration(now())) - startTime;
+ static_cast<_qmf::Broker*>(broker->GetManagementObject())->set_uptime(uptime);
+
+ moveNewObjectsLH();
+
+ //
+ // Clear the been-here flag on all objects in the map.
+ //
+ for (ManagementObjectMap::iterator iter = managementObjects.begin();
+ iter != managementObjects.end();
+ iter++) {
+ ManagementObject* object = iter->second;
+ object->setFlags(0);
+ if (clientWasAdded) {
+ object->setForcePublish(true);
+ }
+ }
+
+ clientWasAdded = false;
+
+ //
+ // Process the entire object map.
+ //
+ for (ManagementObjectMap::iterator baseIter = managementObjects.begin();
+ baseIter != managementObjects.end();
+ baseIter++) {
+ ManagementObject* baseObject = baseIter->second;
+ uint32_t pcount = 0;
+ uint32_t scount = 0;
+
+ //
+ // Skip until we find a base object requiring a sent message.
+ //
+ if (baseObject->getFlags() == 1 ||
+ (!baseObject->getConfigChanged() &&
+ !baseObject->getInstChanged() &&
+ !baseObject->getForcePublish() &&
+ !baseObject->isDeleted()))
+ continue;
+
+ Buffer msgBuffer(msgChars, BUFSIZE);
+ for (ManagementObjectMap::iterator iter = baseIter;
+ iter != managementObjects.end();
+ iter++) {
+ ManagementObject* object = iter->second;
+ if (baseObject->isSameClass(*object) && object->getFlags() == 0) {
+ object->setFlags(1);
+ if (object->getConfigChanged() || object->getInstChanged())
+ object->setUpdateTime();
+
+ if (object->getConfigChanged() || object->getForcePublish() || object->isDeleted()) {
+ encodeHeader(msgBuffer, 'c');
+ object->writeProperties(msgBuffer);
+ pcount++;
+ }
+
+ if (object->hasInst() && (object->getInstChanged() || object->getForcePublish())) {
+ encodeHeader(msgBuffer, 'i');
+ object->writeStatistics(msgBuffer);
+ scount++;
+ }
+
+ if (object->isDeleted())
+ deleteList.push_back(pair<ObjectId, ManagementObject*>(iter->first, object));
+ object->setForcePublish(false);
+
+ if (msgBuffer.available() < HEADROOM)
+ break;
+ }
+ }
+
+ contentSize = BUFSIZE - msgBuffer.available();
+ if (contentSize > 0) {
+ msgBuffer.reset();
+ stringstream key;
+ key << "console.obj.1.0." << baseObject->getPackageName() << "." << baseObject->getClassName();
+ sendBuffer(msgBuffer, contentSize, mExchange, key.str());
+ QPID_LOG(trace, "SEND Multicast ContentInd to=" << key.str() << " props=" << pcount << " stats=" << scount);
+ }
+ }
+
+ // Delete flagged objects
+ for (list<pair<ObjectId, ManagementObject*> >::reverse_iterator iter = deleteList.rbegin();
+ iter != deleteList.rend();
+ iter++) {
+ delete iter->second;
+ managementObjects.erase(iter->first);
+ }
+
+ if (!deleteList.empty()) {
+ deleteList.clear();
+ deleteOrphanedAgentsLH();
+ }
+
+ {
+ Buffer msgBuffer(msgChars, BUFSIZE);
+ encodeHeader(msgBuffer, 'h');
+ msgBuffer.putLongLong(uint64_t(Duration(now())));
+
+ contentSize = BUFSIZE - msgBuffer.available ();
+ msgBuffer.reset ();
+ routingKey = "console.heartbeat.1.0";
+ sendBuffer (msgBuffer, contentSize, mExchange, routingKey);
+ QPID_LOG(trace, "SEND HeartbeatInd to=" << routingKey);
+ }
+}
+
+void ManagementAgent::deleteObjectNowLH(const ObjectId& oid)
+{
+ ManagementObjectMap::iterator iter = managementObjects.find(oid);
+ if (iter == managementObjects.end())
+ return;
+ ManagementObject* object = iter->second;
+ if (!object->isDeleted())
+ return;
+
+#define DNOW_BUFSIZE 2048
+ char msgChars[DNOW_BUFSIZE];
+ uint32_t contentSize;
+ Buffer msgBuffer(msgChars, DNOW_BUFSIZE);
+
+ encodeHeader(msgBuffer, 'c');
+ object->writeProperties(msgBuffer);
+ contentSize = msgBuffer.getPosition();
+ msgBuffer.reset();
+ stringstream key;
+ key << "console.obj.1.0." << object->getPackageName() << "." << object->getClassName();
+ sendBuffer(msgBuffer, contentSize, mExchange, key.str());
+ QPID_LOG(trace, "SEND Immediate(delete) ContentInd to=" << key.str());
+
+ managementObjects.erase(oid);
+}
+
+void ManagementAgent::sendCommandComplete (string replyToKey, uint32_t sequence,
+ uint32_t code, string text)
+{
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader (outBuffer, 'z', sequence);
+ outBuffer.putLong (code);
+ outBuffer.putShortString (text);
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ sendBuffer (outBuffer, outLen, dExchange, replyToKey);
+ QPID_LOG(trace, "SEND CommandCompleteInd code=" << code << " text=" << text << " to=" <<
+ replyToKey << " seq=" << sequence);
+}
+
+bool ManagementAgent::dispatchCommand (Deliverable& deliverable,
+ const string& routingKey,
+ const FieldTable* /*args*/)
+{
+ Mutex::ScopedLock lock (userLock);
+ Message& msg = ((DeliverableMessage&) deliverable).getMessage ();
+
+ // Parse the routing key. This management broker should act as though it
+ // is bound to the exchange to match the following keys:
+ //
+ // agent.1.0.#
+ // broker
+ // schema.#
+
+ if (routingKey == "broker") {
+ dispatchAgentCommandLH(msg);
+ return false;
+ }
+
+ else if (routingKey.compare(0, 9, "agent.1.0") == 0) {
+ dispatchAgentCommandLH(msg);
+ return false;
+ }
+
+ else if (routingKey.compare(0, 8, "agent.1.") == 0) {
+ return authorizeAgentMessageLH(msg);
+ }
+
+ else if (routingKey.compare(0, 7, "schema.") == 0) {
+ dispatchAgentCommandLH(msg);
+ return true;
+ }
+
+ return true;
+}
+
+void ManagementAgent::handleMethodRequestLH (Buffer& inBuffer, string replyToKey,
+ uint32_t sequence, const ConnectionToken* connToken)
+{
+ string methodName;
+ string packageName;
+ string className;
+ uint8_t hash[16];
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+ AclModule* acl = broker->getAcl();
+
+ ObjectId objId(inBuffer);
+ inBuffer.getShortString(packageName);
+ inBuffer.getShortString(className);
+ inBuffer.getBin128(hash);
+ inBuffer.getShortString(methodName);
+
+ QPID_LOG(trace, "RECV MethodRequest class=" << packageName << ":" << className << "(" << Uuid(hash) << ") method=" <<
+ methodName << " replyTo=" << replyToKey);
+
+ encodeHeader(outBuffer, 'm', sequence);
+
+ DisallowedMethods::const_iterator i = disallowed.find(std::make_pair(className, methodName));
+ if (i != disallowed.end()) {
+ outBuffer.putLong(Manageable::STATUS_FORBIDDEN);
+ outBuffer.putMediumString(i->second);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ sendBuffer(outBuffer, outLen, dExchange, replyToKey);
+ QPID_LOG(trace, "SEND MethodResponse status=FORBIDDEN text=" << i->second << " seq=" << sequence)
+ return;
+ }
+
+ if (acl != 0) {
+ string userId = ((const qpid::broker::ConnectionState*) connToken)->getUserId();
+ map<acl::Property, string> params;
+ params[acl::PROP_SCHEMAPACKAGE] = packageName;
+ params[acl::PROP_SCHEMACLASS] = className;
+
+ if (!acl->authorise(userId, acl::ACT_ACCESS, acl::OBJ_METHOD, methodName, &params)) {
+ outBuffer.putLong(Manageable::STATUS_FORBIDDEN);
+ outBuffer.putMediumString(Manageable::StatusText(Manageable::STATUS_FORBIDDEN));
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ sendBuffer(outBuffer, outLen, dExchange, replyToKey);
+ QPID_LOG(trace, "SEND MethodResponse status=FORBIDDEN" << " seq=" << sequence)
+ return;
+ }
+ }
+
+ ManagementObjectMap::iterator iter = managementObjects.find(objId);
+ if (iter == managementObjects.end() || iter->second->isDeleted()) {
+ outBuffer.putLong (Manageable::STATUS_UNKNOWN_OBJECT);
+ outBuffer.putMediumString(Manageable::StatusText (Manageable::STATUS_UNKNOWN_OBJECT));
+ } else {
+ if ((iter->second->getPackageName() != packageName) ||
+ (iter->second->getClassName() != className)) {
+ outBuffer.putLong (Manageable::STATUS_PARAMETER_INVALID);
+ outBuffer.putMediumString(Manageable::StatusText (Manageable::STATUS_PARAMETER_INVALID));
+ }
+ else
+ try {
+ outBuffer.record();
+ Mutex::ScopedUnlock u(userLock);
+ iter->second->doMethod(methodName, inBuffer, outBuffer);
+ } catch(exception& e) {
+ outBuffer.restore();
+ outBuffer.putLong(Manageable::STATUS_EXCEPTION);
+ outBuffer.putMediumString(e.what());
+ }
+ }
+
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ sendBuffer(outBuffer, outLen, dExchange, replyToKey);
+ QPID_LOG(trace, "SEND MethodResponse to=" << replyToKey << " seq=" << sequence);
+}
+
+void ManagementAgent::handleBrokerRequestLH (Buffer&, string replyToKey, uint32_t sequence)
+{
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ QPID_LOG(trace, "RECV BrokerRequest replyTo=" << replyToKey);
+
+ encodeHeader (outBuffer, 'b', sequence);
+ uuid.encode (outBuffer);
+
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ sendBuffer (outBuffer, outLen, dExchange, replyToKey);
+ QPID_LOG(trace, "SEND BrokerResponse to=" << replyToKey);
+}
+
+void ManagementAgent::handlePackageQueryLH (Buffer&, string replyToKey, uint32_t sequence)
+{
+ QPID_LOG(trace, "RECV PackageQuery replyTo=" << replyToKey);
+
+ for (PackageMap::iterator pIter = packages.begin ();
+ pIter != packages.end ();
+ pIter++)
+ {
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader (outBuffer, 'p', sequence);
+ encodePackageIndication (outBuffer, pIter);
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ sendBuffer (outBuffer, outLen, dExchange, replyToKey);
+ QPID_LOG(trace, "SEND PackageInd package=" << (*pIter).first << " to=" << replyToKey << " seq=" << sequence);
+ }
+
+ sendCommandComplete (replyToKey, sequence);
+}
+
+void ManagementAgent::handlePackageIndLH (Buffer& inBuffer, string replyToKey, uint32_t sequence)
+{
+ string packageName;
+
+ inBuffer.getShortString(packageName);
+
+ QPID_LOG(trace, "RECV PackageInd package=" << packageName << " replyTo=" << replyToKey << " seq=" << sequence);
+
+ findOrAddPackageLH(packageName);
+}
+
+void ManagementAgent::handleClassQueryLH(Buffer& inBuffer, string replyToKey, uint32_t sequence)
+{
+ string packageName;
+
+ inBuffer.getShortString(packageName);
+
+ QPID_LOG(trace, "RECV ClassQuery package=" << packageName << " replyTo=" << replyToKey << " seq=" << sequence);
+
+ PackageMap::iterator pIter = packages.find(packageName);
+ if (pIter != packages.end())
+ {
+ ClassMap cMap = pIter->second;
+ for (ClassMap::iterator cIter = cMap.begin();
+ cIter != cMap.end();
+ cIter++)
+ {
+ if (cIter->second.hasSchema())
+ {
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader(outBuffer, 'q', sequence);
+ encodeClassIndication(outBuffer, pIter, cIter);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ sendBuffer(outBuffer, outLen, dExchange, replyToKey);
+ QPID_LOG(trace, "SEND ClassInd class=" << (*pIter).first << ":" << (*cIter).first.name <<
+ "(" << Uuid((*cIter).first.hash) << ") to=" << replyToKey << " seq=" << sequence);
+ }
+ }
+ }
+ sendCommandComplete(replyToKey, sequence);
+}
+
+void ManagementAgent::handleClassIndLH (Buffer& inBuffer, string replyToKey, uint32_t)
+{
+ string packageName;
+ SchemaClassKey key;
+
+ uint8_t kind = inBuffer.getOctet();
+ inBuffer.getShortString(packageName);
+ inBuffer.getShortString(key.name);
+ inBuffer.getBin128(key.hash);
+
+ QPID_LOG(trace, "RECV ClassInd class=" << packageName << ":" << key.name << "(" << Uuid(key.hash) <<
+ "), replyTo=" << replyToKey);
+
+ PackageMap::iterator pIter = findOrAddPackageLH(packageName);
+ ClassMap::iterator cIter = pIter->second.find(key);
+ if (cIter == pIter->second.end() || !cIter->second.hasSchema()) {
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+ uint32_t sequence = nextRequestSequence++;
+
+ encodeHeader (outBuffer, 'S', sequence);
+ outBuffer.putShortString(packageName);
+ outBuffer.putShortString(key.name);
+ outBuffer.putBin128(key.hash);
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ sendBuffer (outBuffer, outLen, dExchange, replyToKey);
+ QPID_LOG(trace, "SEND SchemaRequest class=" << packageName << ":" << key.name << "(" << Uuid(key.hash) <<
+ "), to=" << replyToKey << " seq=" << sequence);
+
+ if (cIter != pIter->second.end())
+ pIter->second.erase(key);
+
+ pIter->second.insert(pair<SchemaClassKey, SchemaClass>(key, SchemaClass(kind, sequence)));
+ }
+}
+
+void ManagementAgent::SchemaClass::appendSchema(Buffer& buf)
+{
+ // If the management package is attached locally (embedded in the broker or
+ // linked in via plug-in), call the schema handler directly. If the package
+ // is from a remote management agent, send the stored schema information.
+
+ if (writeSchemaCall != 0)
+ writeSchemaCall(buf);
+ else
+ buf.putRawData(buffer, bufferLen);
+}
+
+void ManagementAgent::handleSchemaRequestLH(Buffer& inBuffer, string replyToKey, uint32_t sequence)
+{
+ string packageName;
+ SchemaClassKey key;
+
+ inBuffer.getShortString (packageName);
+ inBuffer.getShortString (key.name);
+ inBuffer.getBin128 (key.hash);
+
+ QPID_LOG(trace, "RECV SchemaRequest class=" << packageName << ":" << key.name << "(" << Uuid(key.hash) <<
+ "), replyTo=" << replyToKey << " seq=" << sequence);
+
+ PackageMap::iterator pIter = packages.find(packageName);
+ if (pIter != packages.end()) {
+ ClassMap& cMap = pIter->second;
+ ClassMap::iterator cIter = cMap.find(key);
+ if (cIter != cMap.end()) {
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+ SchemaClass& classInfo = cIter->second;
+
+ if (classInfo.hasSchema()) {
+ encodeHeader(outBuffer, 's', sequence);
+ classInfo.appendSchema(outBuffer);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ sendBuffer(outBuffer, outLen, dExchange, replyToKey);
+ QPID_LOG(trace, "SEND SchemaResponse to=" << replyToKey << " seq=" << sequence);
+ }
+ else
+ sendCommandComplete(replyToKey, sequence, 1, "Schema not available");
+ }
+ else
+ sendCommandComplete(replyToKey, sequence, 1, "Class key not found");
+ }
+ else
+ sendCommandComplete(replyToKey, sequence, 1, "Package not found");
+}
+
+void ManagementAgent::handleSchemaResponseLH(Buffer& inBuffer, string /*replyToKey*/, uint32_t sequence)
+{
+ string packageName;
+ SchemaClassKey key;
+
+ inBuffer.record();
+ inBuffer.getOctet();
+ inBuffer.getShortString(packageName);
+ inBuffer.getShortString(key.name);
+ inBuffer.getBin128(key.hash);
+ inBuffer.restore();
+
+ QPID_LOG(trace, "RECV SchemaResponse class=" << packageName << ":" << key.name << "(" << Uuid(key.hash) << ")" << " seq=" << sequence);
+
+ PackageMap::iterator pIter = packages.find(packageName);
+ if (pIter != packages.end()) {
+ ClassMap& cMap = pIter->second;
+ ClassMap::iterator cIter = cMap.find(key);
+ if (cIter != cMap.end() && cIter->second.pendingSequence == sequence) {
+ size_t length = validateSchema(inBuffer, cIter->second.kind);
+ if (length == 0) {
+ QPID_LOG(warning, "Management Agent received invalid schema response: " << packageName << "." << key.name);
+ cMap.erase(key);
+ } else {
+ cIter->second.buffer = (uint8_t*) malloc(length);
+ cIter->second.bufferLen = length;
+ inBuffer.getRawData(cIter->second.buffer, cIter->second.bufferLen);
+
+ // Publish a class-indication message
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader(outBuffer, 'q');
+ encodeClassIndication(outBuffer, pIter, cIter);
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ sendBuffer(outBuffer, outLen, mExchange, "schema.class");
+ QPID_LOG(trace, "SEND ClassInd class=" << packageName << ":" << key.name << "(" << Uuid(key.hash) << ")" <<
+ " to=schema.class");
+ }
+ }
+ }
+}
+
+bool ManagementAgent::bankInUse (uint32_t bank)
+{
+ for (RemoteAgentMap::iterator aIter = remoteAgents.begin();
+ aIter != remoteAgents.end();
+ aIter++)
+ if (aIter->second->agentBank == bank)
+ return true;
+ return false;
+}
+
+uint32_t ManagementAgent::allocateNewBank ()
+{
+ while (bankInUse (nextRemoteBank))
+ nextRemoteBank++;
+
+ uint32_t allocated = nextRemoteBank++;
+ writeData ();
+ return allocated;
+}
+
+uint32_t ManagementAgent::assignBankLH (uint32_t requestedBank)
+{
+ if (requestedBank == 0 || bankInUse (requestedBank))
+ return allocateNewBank ();
+ return requestedBank;
+}
+
+void ManagementAgent::deleteOrphanedAgentsLH()
+{
+ vector<ObjectId> deleteList;
+
+ for (RemoteAgentMap::iterator aIter = remoteAgents.begin(); aIter != remoteAgents.end(); aIter++) {
+ ObjectId connectionRef = aIter->first;
+ bool found = false;
+
+ for (ManagementObjectMap::iterator iter = managementObjects.begin();
+ iter != managementObjects.end();
+ iter++) {
+ if (iter->first == connectionRef && !iter->second->isDeleted()) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ deleteList.push_back(connectionRef);
+ delete aIter->second;
+ }
+ }
+
+ for (vector<ObjectId>::iterator dIter = deleteList.begin(); dIter != deleteList.end(); dIter++)
+ remoteAgents.erase(*dIter);
+
+ deleteList.clear();
+}
+
+void ManagementAgent::handleAttachRequestLH (Buffer& inBuffer, string replyToKey, uint32_t sequence, const ConnectionToken* connToken)
+{
+ string label;
+ uint32_t requestedBrokerBank, requestedAgentBank;
+ uint32_t assignedBank;
+ ObjectId connectionRef = ((const ConnectionState*) connToken)->GetManagementObject()->getObjectId();
+ Uuid systemId;
+
+ moveNewObjectsLH();
+ deleteOrphanedAgentsLH();
+ RemoteAgentMap::iterator aIter = remoteAgents.find(connectionRef);
+ if (aIter != remoteAgents.end()) {
+ // There already exists an agent on this session. Reject the request.
+ sendCommandComplete(replyToKey, sequence, 1, "Connection already has remote agent");
+ return;
+ }
+
+ inBuffer.getShortString(label);
+ systemId.decode(inBuffer);
+ requestedBrokerBank = inBuffer.getLong();
+ requestedAgentBank = inBuffer.getLong();
+
+ QPID_LOG(trace, "RECV (Agent)AttachRequest label=" << label << " reqBrokerBank=" << requestedBrokerBank <<
+ " reqAgentBank=" << requestedAgentBank << " replyTo=" << replyToKey << " seq=" << sequence);
+
+ assignedBank = assignBankLH(requestedAgentBank);
+
+ RemoteAgent* agent = new RemoteAgent(*this);
+ agent->brokerBank = brokerBank;
+ agent->agentBank = assignedBank;
+ agent->routingKey = replyToKey;
+ agent->connectionRef = connectionRef;
+ agent->mgmtObject = new _qmf::Agent (this, agent);
+ agent->mgmtObject->set_connectionRef(agent->connectionRef);
+ agent->mgmtObject->set_label (label);
+ agent->mgmtObject->set_registeredTo (broker->GetManagementObject()->getObjectId());
+ agent->mgmtObject->set_systemId (systemId);
+ agent->mgmtObject->set_brokerBank (brokerBank);
+ agent->mgmtObject->set_agentBank (assignedBank);
+ addObject (agent->mgmtObject, 0, true);
+
+ remoteAgents[connectionRef] = agent;
+
+ QPID_LOG(trace, "Remote Agent registered bank=[" << brokerBank << "." << assignedBank << "] replyTo=" << replyToKey);
+
+ // Send an Attach Response
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader (outBuffer, 'a', sequence);
+ outBuffer.putLong (brokerBank);
+ outBuffer.putLong (assignedBank);
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ sendBuffer (outBuffer, outLen, dExchange, replyToKey);
+ QPID_LOG(trace, "SEND AttachResponse brokerBank=" << brokerBank << " agentBank=" << assignedBank <<
+ " to=" << replyToKey << " seq=" << sequence);
+}
+
+void ManagementAgent::handleGetQueryLH (Buffer& inBuffer, string replyToKey, uint32_t sequence)
+{
+ FieldTable ft;
+ FieldTable::ValuePtr value;
+
+ moveNewObjectsLH();
+
+ ft.decode(inBuffer);
+
+ QPID_LOG(trace, "RECV GetQuery query=" << ft << " seq=" << sequence);
+
+ value = ft.get("_class");
+ if (value.get() == 0 || !value->convertsTo<string>()) {
+ value = ft.get("_objectid");
+ if (value.get() == 0 || !value->convertsTo<string>())
+ return;
+
+ ObjectId selector(value->get<string>());
+ ManagementObjectMap::iterator iter = managementObjects.find(selector);
+ if (iter != managementObjects.end()) {
+ ManagementObject* object = iter->second;
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ if (object->getConfigChanged() || object->getInstChanged())
+ object->setUpdateTime();
+
+ if (!object->isDeleted()) {
+ encodeHeader(outBuffer, 'g', sequence);
+ object->writeProperties(outBuffer);
+ object->writeStatistics(outBuffer, true);
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ sendBuffer(outBuffer, outLen, dExchange, replyToKey);
+ QPID_LOG(trace, "SEND GetResponse to=" << replyToKey << " seq=" << sequence);
+ }
+ }
+ sendCommandComplete(replyToKey, sequence);
+ return;
+ }
+
+ string className (value->get<string>());
+
+ for (ManagementObjectMap::iterator iter = managementObjects.begin();
+ iter != managementObjects.end();
+ iter++) {
+ ManagementObject* object = iter->second;
+ if (object->getClassName () == className) {
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ if (object->getConfigChanged() || object->getInstChanged())
+ object->setUpdateTime();
+
+ if (!object->isDeleted()) {
+ encodeHeader(outBuffer, 'g', sequence);
+ object->writeProperties(outBuffer);
+ object->writeStatistics(outBuffer, true);
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ sendBuffer(outBuffer, outLen, dExchange, replyToKey);
+ QPID_LOG(trace, "SEND GetResponse to=" << replyToKey << " seq=" << sequence);
+ }
+ }
+ }
+
+ sendCommandComplete(replyToKey, sequence);
+}
+
+bool ManagementAgent::authorizeAgentMessageLH(Message& msg)
+{
+ Buffer inBuffer (inputBuffer, MA_BUFFER_SIZE);
+ uint8_t opcode;
+ uint32_t sequence;
+ string replyToKey;
+
+ if (msg.encodedSize() > MA_BUFFER_SIZE)
+ return false;
+
+ msg.encodeContent(inBuffer);
+ inBuffer.reset();
+
+ if (!checkHeader(inBuffer, &opcode, &sequence))
+ return false;
+
+ if (opcode == 'M') {
+ // TODO: check method call against ACL list.
+ AclModule* acl = broker->getAcl();
+ if (acl == 0)
+ return true;
+
+ string userId = ((const qpid::broker::ConnectionState*) msg.getPublisher())->getUserId();
+ string packageName;
+ string className;
+ uint8_t hash[16];
+ string methodName;
+
+ map<acl::Property, string> params;
+ ObjectId objId(inBuffer);
+ inBuffer.getShortString(packageName);
+ inBuffer.getShortString(className);
+ inBuffer.getBin128(hash);
+ inBuffer.getShortString(methodName);
+
+ params[acl::PROP_SCHEMAPACKAGE] = packageName;
+ params[acl::PROP_SCHEMACLASS] = className;
+
+ if (acl->authorise(userId, acl::ACT_ACCESS, acl::OBJ_METHOD, methodName, &params))
+ return true;
+
+ const framing::MessageProperties* p =
+ msg.getFrames().getHeaders()->get<framing::MessageProperties>();
+ if (p && p->hasReplyTo()) {
+ const framing::ReplyTo& rt = p->getReplyTo();
+ replyToKey = rt.getRoutingKey();
+
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader(outBuffer, 'm', sequence);
+ outBuffer.putLong(Manageable::STATUS_FORBIDDEN);
+ outBuffer.putMediumString(Manageable::StatusText(Manageable::STATUS_FORBIDDEN));
+ outLen = MA_BUFFER_SIZE - outBuffer.available();
+ outBuffer.reset();
+ sendBuffer(outBuffer, outLen, dExchange, replyToKey);
+ QPID_LOG(trace, "SEND MethodResponse status=FORBIDDEN" << " seq=" << sequence)
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+void ManagementAgent::dispatchAgentCommandLH(Message& msg)
+{
+ Buffer inBuffer(inputBuffer, MA_BUFFER_SIZE);
+ uint8_t opcode;
+ uint32_t sequence;
+ string replyToKey;
+
+ const framing::MessageProperties* p =
+ msg.getFrames().getHeaders()->get<framing::MessageProperties>();
+ if (p && p->hasReplyTo()) {
+ const framing::ReplyTo& rt = p->getReplyTo();
+ replyToKey = rt.getRoutingKey();
+ }
+ else
+ return;
+
+ if (msg.encodedSize() > MA_BUFFER_SIZE) {
+ QPID_LOG(debug, "ManagementAgent::dispatchAgentCommandLH: Message too large: " <<
+ msg.encodedSize());
+ return;
+ }
+
+ msg.encodeContent(inBuffer);
+ uint32_t bufferLen = inBuffer.getPosition();
+ inBuffer.reset();
+
+ while (inBuffer.getPosition() < bufferLen) {
+ if (!checkHeader(inBuffer, &opcode, &sequence))
+ return;
+
+ if (opcode == 'B') handleBrokerRequestLH (inBuffer, replyToKey, sequence);
+ else if (opcode == 'P') handlePackageQueryLH (inBuffer, replyToKey, sequence);
+ else if (opcode == 'p') handlePackageIndLH (inBuffer, replyToKey, sequence);
+ else if (opcode == 'Q') handleClassQueryLH (inBuffer, replyToKey, sequence);
+ else if (opcode == 'q') handleClassIndLH (inBuffer, replyToKey, sequence);
+ else if (opcode == 'S') handleSchemaRequestLH (inBuffer, replyToKey, sequence);
+ else if (opcode == 's') handleSchemaResponseLH (inBuffer, replyToKey, sequence);
+ else if (opcode == 'A') handleAttachRequestLH (inBuffer, replyToKey, sequence, msg.getPublisher());
+ else if (opcode == 'G') handleGetQueryLH (inBuffer, replyToKey, sequence);
+ else if (opcode == 'M') handleMethodRequestLH (inBuffer, replyToKey, sequence, msg.getPublisher());
+ }
+}
+
+ManagementAgent::PackageMap::iterator ManagementAgent::findOrAddPackageLH(string name)
+{
+ PackageMap::iterator pIter = packages.find (name);
+ if (pIter != packages.end ())
+ return pIter;
+
+ // No such package found, create a new map entry.
+ pair<PackageMap::iterator, bool> result =
+ packages.insert(pair<string, ClassMap>(name, ClassMap()));
+ QPID_LOG (debug, "ManagementAgent added package " << name);
+
+ // Publish a package-indication message
+ Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
+ uint32_t outLen;
+
+ encodeHeader (outBuffer, 'p');
+ encodePackageIndication (outBuffer, result.first);
+ outLen = MA_BUFFER_SIZE - outBuffer.available ();
+ outBuffer.reset ();
+ sendBuffer (outBuffer, outLen, mExchange, "schema.package");
+ QPID_LOG(trace, "SEND PackageInd package=" << name << " to=schema.package")
+
+ return result.first;
+}
+
+void ManagementAgent::addClassLH(uint8_t kind,
+ PackageMap::iterator pIter,
+ const string& className,
+ uint8_t* md5Sum,
+ ManagementObject::writeSchemaCall_t schemaCall)
+{
+ SchemaClassKey key;
+ ClassMap& cMap = pIter->second;
+
+ key.name = className;
+ memcpy(&key.hash, md5Sum, 16);
+
+ ClassMap::iterator cIter = cMap.find(key);
+ if (cIter != cMap.end())
+ return;
+
+ // No such class found, create a new class with local information.
+ QPID_LOG (debug, "ManagementAgent added class " << pIter->first << ":" <<
+ key.name);
+
+ cMap.insert(pair<SchemaClassKey, SchemaClass>(key, SchemaClass(kind, schemaCall)));
+ cIter = cMap.find(key);
+}
+
+void ManagementAgent::encodePackageIndication(Buffer& buf,
+ PackageMap::iterator pIter)
+{
+ buf.putShortString((*pIter).first);
+}
+
+void ManagementAgent::encodeClassIndication(Buffer& buf,
+ PackageMap::iterator pIter,
+ ClassMap::iterator cIter)
+{
+ SchemaClassKey key = (*cIter).first;
+
+ buf.putOctet((*cIter).second.kind);
+ buf.putShortString((*pIter).first);
+ buf.putShortString(key.name);
+ buf.putBin128(key.hash);
+}
+
+size_t ManagementAgent::validateSchema(Buffer& inBuffer, uint8_t kind)
+{
+ if (kind == ManagementItem::CLASS_KIND_TABLE)
+ return validateTableSchema(inBuffer);
+ else if (kind == ManagementItem::CLASS_KIND_EVENT)
+ return validateEventSchema(inBuffer);
+ return 0;
+}
+
+size_t ManagementAgent::validateTableSchema(Buffer& inBuffer)
+{
+ uint32_t start = inBuffer.getPosition();
+ uint32_t end;
+ string text;
+ uint8_t hash[16];
+
+ try {
+ inBuffer.record();
+ uint8_t kind = inBuffer.getOctet();
+ if (kind != ManagementItem::CLASS_KIND_TABLE)
+ return 0;
+
+ inBuffer.getShortString(text);
+ inBuffer.getShortString(text);
+ inBuffer.getBin128(hash);
+
+ uint8_t superType = 0; //inBuffer.getOctet();
+
+ uint16_t propCount = inBuffer.getShort();
+ uint16_t statCount = inBuffer.getShort();
+ uint16_t methCount = inBuffer.getShort();
+
+ if (superType == 1) {
+ inBuffer.getShortString(text);
+ inBuffer.getShortString(text);
+ inBuffer.getBin128(hash);
+ }
+
+ for (uint16_t idx = 0; idx < propCount + statCount; idx++) {
+ FieldTable ft;
+ ft.decode(inBuffer);
+ }
+
+ for (uint16_t idx = 0; idx < methCount; idx++) {
+ FieldTable ft;
+ ft.decode(inBuffer);
+ if (!ft.isSet("argCount"))
+ return 0;
+ int argCount = ft.getAsInt("argCount");
+ for (int mIdx = 0; mIdx < argCount; mIdx++) {
+ FieldTable aft;
+ aft.decode(inBuffer);
+ }
+ }
+ } catch (exception& /*e*/) {
+ return 0;
+ }
+
+ end = inBuffer.getPosition();
+ inBuffer.restore(); // restore original position
+ return end - start;
+}
+
+size_t ManagementAgent::validateEventSchema(Buffer& inBuffer)
+{
+ uint32_t start = inBuffer.getPosition();
+ uint32_t end;
+ string text;
+ uint8_t hash[16];
+
+ try {
+ inBuffer.record();
+ uint8_t kind = inBuffer.getOctet();
+ if (kind != ManagementItem::CLASS_KIND_EVENT)
+ return 0;
+
+ inBuffer.getShortString(text);
+ inBuffer.getShortString(text);
+ inBuffer.getBin128(hash);
+
+ uint8_t superType = inBuffer.getOctet();
+
+ uint16_t argCount = inBuffer.getShort();
+
+ if (superType == 1) {
+ inBuffer.getShortString(text);
+ inBuffer.getShortString(text);
+ inBuffer.getBin128(hash);
+ }
+ for (uint16_t idx = 0; idx < argCount; idx++) {
+ FieldTable ft;
+ ft.decode(inBuffer);
+ }
+ } catch (exception& /*e*/) {
+ return 0;
+ }
+
+ end = inBuffer.getPosition();
+ inBuffer.restore(); // restore original position
+ return end - start;
+}
+
+void ManagementAgent::setAllocator(std::auto_ptr<IdAllocator> a)
+{
+ Mutex::ScopedLock lock (addLock);
+ allocator = a;
+}
+
+uint64_t ManagementAgent::allocateId(Manageable* object)
+{
+ Mutex::ScopedLock lock (addLock);
+ if (allocator.get()) return allocator->getIdFor(object);
+ return 0;
+}
+
+void ManagementAgent::disallow(const std::string& className, const std::string& methodName, const std::string& message) {
+ disallowed[std::make_pair(className, methodName)] = message;
+}
diff --git a/cpp/src/qpid/management/ManagementAgent.h b/cpp/src/qpid/management/ManagementAgent.h
new file mode 100644
index 0000000000..c64c073d8c
--- /dev/null
+++ b/cpp/src/qpid/management/ManagementAgent.h
@@ -0,0 +1,264 @@
+#ifndef _ManagementAgent_
+#define _ManagementAgent_
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/broker/BrokerImportExport.h"
+#include "qpid/Options.h"
+#include "qpid/broker/Exchange.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Timer.h"
+#include "qpid/broker/ConnectionToken.h"
+#include "qpid/management/ManagementObject.h"
+#include "qpid/management/ManagementEvent.h"
+#include "qpid/management/Manageable.h"
+#include "qmf/org/apache/qpid/broker/Agent.h"
+#include <qpid/framing/AMQFrame.h>
+#include <memory>
+#include <string>
+#include <map>
+
+namespace qpid {
+namespace management {
+
+struct IdAllocator;
+
+class ManagementAgent
+{
+private:
+
+ int threadPoolSize;
+
+public:
+ typedef enum {
+ SEV_EMERG = 0,
+ SEV_ALERT = 1,
+ SEV_CRIT = 2,
+ SEV_ERROR = 3,
+ SEV_WARN = 4,
+ SEV_NOTE = 5,
+ SEV_INFO = 6,
+ SEV_DEBUG = 7,
+ SEV_DEFAULT = 8
+ } severity_t;
+
+
+ ManagementAgent ();
+ virtual ~ManagementAgent ();
+
+ void configure (const std::string& dataDir, uint16_t interval,
+ qpid::broker::Broker* broker, int threadPoolSize);
+ void setInterval (uint16_t _interval) { interval = _interval; }
+ void setExchange (qpid::broker::Exchange::shared_ptr mgmtExchange,
+ qpid::broker::Exchange::shared_ptr directExchange);
+ int getMaxThreads () { return threadPoolSize; }
+ QPID_BROKER_EXTERN void registerClass (const std::string& packageName,
+ const std::string& className,
+ uint8_t* md5Sum,
+ ManagementObject::writeSchemaCall_t schemaCall);
+ QPID_BROKER_EXTERN void registerEvent (const std::string& packageName,
+ const std::string& eventName,
+ uint8_t* md5Sum,
+ ManagementObject::writeSchemaCall_t schemaCall);
+ QPID_BROKER_EXTERN ObjectId addObject (ManagementObject* object,
+ uint64_t persistId = 0,
+ bool publishNow = false);
+ QPID_BROKER_EXTERN void raiseEvent(const ManagementEvent& event,
+ severity_t severity = SEV_DEFAULT);
+ QPID_BROKER_EXTERN void clientAdded (const std::string& routingKey);
+
+ bool dispatchCommand (qpid::broker::Deliverable& msg,
+ const std::string& routingKey,
+ const framing::FieldTable* args);
+
+ const framing::Uuid& getUuid() const { return uuid; }
+
+ void setAllocator(std::auto_ptr<IdAllocator> allocator);
+ uint64_t allocateId(Manageable* object);
+
+ /** Disallow a method. Attempts to call it will receive an exception with message. */
+ void disallow(const std::string& className, const std::string& methodName, const std::string& message);
+
+private:
+ struct Periodic : public qpid::sys::TimerTask
+ {
+ ManagementAgent& agent;
+
+ Periodic (ManagementAgent& agent, uint32_t seconds);
+ virtual ~Periodic ();
+ void fire ();
+ };
+
+ // Storage for tracking remote management agents, attached via the client
+ // management agent API.
+ //
+ struct RemoteAgent : public Manageable
+ {
+ ManagementAgent& agent;
+ uint32_t brokerBank;
+ uint32_t agentBank;
+ std::string routingKey;
+ ObjectId connectionRef;
+ qmf::org::apache::qpid::broker::Agent* mgmtObject;
+ RemoteAgent(ManagementAgent& _agent) : agent(_agent) {}
+ ManagementObject* GetManagementObject (void) const { return mgmtObject; }
+ virtual ~RemoteAgent ();
+ };
+
+ // TODO: Eventually replace string with entire reply-to structure. reply-to
+ // currently assumes that the exchange is "amq.direct" even though it could
+ // in theory be specified differently.
+ typedef std::map<ObjectId, RemoteAgent*> RemoteAgentMap;
+ typedef std::vector<std::string> ReplyToVector;
+
+ // Storage for known schema classes:
+ //
+ // SchemaClassKey -- Key elements for map lookups
+ // SchemaClassKeyComp -- Comparison class for SchemaClassKey
+ // SchemaClass -- Non-key elements for classes
+ //
+ struct SchemaClassKey
+ {
+ std::string name;
+ uint8_t hash[16];
+ };
+
+ struct SchemaClassKeyComp
+ {
+ bool operator() (const SchemaClassKey& lhs, const SchemaClassKey& rhs) const
+ {
+ if (lhs.name != rhs.name)
+ return lhs.name < rhs.name;
+ else
+ for (int i = 0; i < 16; i++)
+ if (lhs.hash[i] != rhs.hash[i])
+ return lhs.hash[i] < rhs.hash[i];
+ return false;
+ }
+ };
+
+ struct SchemaClass
+ {
+ uint8_t kind;
+ ManagementObject::writeSchemaCall_t writeSchemaCall;
+ uint32_t pendingSequence;
+ size_t bufferLen;
+ uint8_t* buffer;
+
+ SchemaClass(uint8_t _kind, uint32_t seq) :
+ kind(_kind), writeSchemaCall(0), pendingSequence(seq), bufferLen(0), buffer(0) {}
+ SchemaClass(uint8_t _kind, ManagementObject::writeSchemaCall_t call) :
+ kind(_kind), writeSchemaCall(call), pendingSequence(0), bufferLen(0), buffer(0) {}
+ bool hasSchema () { return (writeSchemaCall != 0) || (buffer != 0); }
+ void appendSchema (framing::Buffer& buf);
+ };
+
+ typedef std::map<SchemaClassKey, SchemaClass, SchemaClassKeyComp> ClassMap;
+ typedef std::map<std::string, ClassMap> PackageMap;
+
+ RemoteAgentMap remoteAgents;
+ PackageMap packages;
+ ManagementObjectMap managementObjects;
+ ManagementObjectMap newManagementObjects;
+
+ static ManagementAgent* agent;
+ static bool enabled;
+
+ framing::Uuid uuid;
+ sys::Mutex addLock;
+ sys::Mutex userLock;
+ qpid::broker::Exchange::shared_ptr mExchange;
+ qpid::broker::Exchange::shared_ptr dExchange;
+ std::string dataDir;
+ uint16_t interval;
+ qpid::broker::Broker* broker;
+ qpid::sys::Timer* timer;
+ uint16_t bootSequence;
+ uint32_t nextObjectId;
+ uint32_t brokerBank;
+ uint32_t nextRemoteBank;
+ uint32_t nextRequestSequence;
+ bool clientWasAdded;
+ const uint64_t startTime;
+
+ std::auto_ptr<IdAllocator> allocator;
+
+ typedef std::pair<std::string,std::string> MethodName;
+ typedef std::map<MethodName, std::string> DisallowedMethods;
+ DisallowedMethods disallowed;
+
+
+# define MA_BUFFER_SIZE 65536
+ char inputBuffer[MA_BUFFER_SIZE];
+ char outputBuffer[MA_BUFFER_SIZE];
+ char eventBuffer[MA_BUFFER_SIZE];
+
+ void writeData ();
+ void periodicProcessing (void);
+ void deleteObjectNowLH(const ObjectId& oid);
+ void encodeHeader (framing::Buffer& buf, uint8_t opcode, uint32_t seq = 0);
+ bool checkHeader (framing::Buffer& buf, uint8_t *opcode, uint32_t *seq);
+ void sendBuffer (framing::Buffer& buf,
+ uint32_t length,
+ qpid::broker::Exchange::shared_ptr exchange,
+ std::string routingKey);
+ void moveNewObjectsLH();
+
+ bool authorizeAgentMessageLH(qpid::broker::Message& msg);
+ void dispatchAgentCommandLH(qpid::broker::Message& msg);
+
+ PackageMap::iterator findOrAddPackageLH(std::string name);
+ void addClassLH(uint8_t kind,
+ PackageMap::iterator pIter,
+ const std::string& className,
+ uint8_t* md5Sum,
+ ManagementObject::writeSchemaCall_t schemaCall);
+ void encodePackageIndication (framing::Buffer& buf,
+ PackageMap::iterator pIter);
+ void encodeClassIndication (framing::Buffer& buf,
+ PackageMap::iterator pIter,
+ ClassMap::iterator cIter);
+ bool bankInUse (uint32_t bank);
+ uint32_t allocateNewBank ();
+ uint32_t assignBankLH (uint32_t requestedPrefix);
+ void deleteOrphanedAgentsLH();
+ void sendCommandComplete (std::string replyToKey, uint32_t sequence,
+ uint32_t code = 0, std::string text = std::string("OK"));
+ void handleBrokerRequestLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handlePackageQueryLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handlePackageIndLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handleClassQueryLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handleClassIndLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handleSchemaRequestLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handleSchemaResponseLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handleAttachRequestLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence, const qpid::broker::ConnectionToken* connToken);
+ void handleGetQueryLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
+ void handleMethodRequestLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence, const qpid::broker::ConnectionToken* connToken);
+
+ size_t validateSchema(framing::Buffer&, uint8_t kind);
+ size_t validateTableSchema(framing::Buffer&);
+ size_t validateEventSchema(framing::Buffer&);
+};
+
+}}
+
+#endif /*!_ManagementAgent_*/
diff --git a/cpp/src/qpid/management/ManagementBroker.cpp b/cpp/src/qpid/management/ManagementBroker.cpp
deleted file mode 100644
index 1bdd8ab836..0000000000
--- a/cpp/src/qpid/management/ManagementBroker.cpp
+++ /dev/null
@@ -1,933 +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 "ManagementBroker.h"
-#include "qpid/broker/DeliverableMessage.h"
-#include "qpid/log/Statement.h"
-#include <qpid/broker/Message.h>
-#include <qpid/broker/MessageDelivery.h>
-#include "qpid/framing/MessageTransferBody.h"
-#include "qpid/sys/Time.h"
-#include "qpid/broker/ConnectionState.h"
-#include <list>
-#include <iostream>
-#include <fstream>
-
-using boost::intrusive_ptr;
-using qpid::framing::Uuid;
-using namespace qpid::framing;
-using namespace qpid::management;
-using namespace qpid::broker;
-using namespace qpid::sys;
-using namespace std;
-
-Mutex ManagementAgent::Singleton::lock;
-bool ManagementAgent::Singleton::disabled = false;
-ManagementAgent* ManagementAgent::Singleton::agent = 0;
-int ManagementAgent::Singleton::refCount = 0;
-
-ManagementAgent::Singleton::Singleton(bool disableManagement)
-{
- Mutex::ScopedLock _lock(lock);
- if (disableManagement && !disabled) {
- disabled = true;
- assert(refCount == 0); // can't disable after agent has been allocated
- }
- if (refCount == 0 && !disabled)
- agent = new ManagementBroker();
- refCount++;
-}
-
-ManagementAgent::Singleton::~Singleton()
-{
- Mutex::ScopedLock _lock(lock);
- refCount--;
- if (refCount == 0 && !disabled) {
- delete agent;
- agent = 0;
- }
-}
-
-ManagementAgent* ManagementAgent::Singleton::getInstance()
-{
- return agent;
-}
-
-ManagementBroker::RemoteAgent::~RemoteAgent ()
-{
- if (mgmtObject != 0)
- mgmtObject->resourceDestroy();
-}
-
-ManagementBroker::ManagementBroker () :
- threadPoolSize(1), interval(10), broker(0)
-{
- localBank = 5;
- nextObjectId = 1;
- bootSequence = 1;
- nextRemoteBank = 10;
- nextRequestSequence = 1;
- clientWasAdded = false;
-}
-
-ManagementBroker::~ManagementBroker ()
-{
- timer.stop();
- {
- Mutex::ScopedLock lock (userLock);
-
- // Reset the shared pointers to exchanges. If this is not done now, the exchanges
- // will stick around until dExchange and mExchange are implicitely destroyed (long
- // after this destructor completes). Those exchanges hold references to management
- // objects that will be invalid.
- dExchange.reset();
- mExchange.reset();
-
- moveNewObjectsLH();
- for (ManagementObjectMap::iterator iter = managementObjects.begin ();
- iter != managementObjects.end ();
- iter++) {
- ManagementObject* object = iter->second;
- delete object;
- }
- managementObjects.clear();
- }
-}
-
-void ManagementBroker::configure(string _dataDir, uint16_t _interval, Manageable* _broker, int _threads)
-{
- dataDir = _dataDir;
- interval = _interval;
- broker = _broker;
- threadPoolSize = _threads;
- timer.add (intrusive_ptr<TimerTask> (new Periodic(*this, interval)));
-
- // Get from file or generate and save to file.
- if (dataDir.empty())
- {
- uuid.generate();
- QPID_LOG (info, "ManagementBroker has no data directory, generated new broker ID: "
- << uuid);
- }
- else
- {
- string filename(dataDir + "/.mbrokerdata");
- ifstream inFile(filename.c_str ());
-
- if (inFile.good())
- {
- inFile >> uuid;
- inFile >> bootSequence;
- inFile >> nextRemoteBank;
- inFile.close();
- QPID_LOG (debug, "ManagementBroker restored broker ID: " << uuid);
-
- bootSequence++;
- writeData();
- }
- else
- {
- uuid.generate();
- QPID_LOG (info, "ManagementBroker generated broker ID: " << uuid);
- writeData();
- }
-
- QPID_LOG (debug, "ManagementBroker boot sequence: " << bootSequence);
- }
-}
-
-void ManagementBroker::writeData ()
-{
- string filename (dataDir + "/.mbrokerdata");
- ofstream outFile (filename.c_str ());
-
- if (outFile.good())
- {
- outFile << uuid << " " << bootSequence << " " << nextRemoteBank << endl;
- outFile.close();
- }
-}
-
-void ManagementBroker::setExchange (broker::Exchange::shared_ptr _mexchange,
- broker::Exchange::shared_ptr _dexchange)
-{
- mExchange = _mexchange;
- dExchange = _dexchange;
-}
-
-void ManagementBroker::RegisterClass (string packageName,
- string className,
- uint8_t* md5Sum,
- ManagementObject::writeSchemaCall_t schemaCall)
-{
- Mutex::ScopedLock lock(userLock);
- PackageMap::iterator pIter = FindOrAddPackageLH(packageName);
- AddClass(pIter, className, md5Sum, schemaCall);
-}
-
-uint64_t ManagementBroker::addObject (ManagementObject* object,
- uint32_t persistId,
- uint32_t persistBank)
-{
- Mutex::ScopedLock lock (addLock);
- uint64_t objectId;
-
- if (persistId == 0)
- {
- objectId = ((uint64_t) bootSequence) << 48 |
- ((uint64_t) localBank) << 24 | nextObjectId++;
- if ((nextObjectId & 0xFF000000) != 0)
- {
- nextObjectId = 1;
- localBank++;
- }
- }
- else
- objectId = ((uint64_t) persistBank) << 24 | persistId;
-
- object->setObjectId (objectId);
- newManagementObjects[objectId] = object;
- return objectId;
-}
-
-ManagementBroker::Periodic::Periodic (ManagementBroker& _broker, uint32_t _seconds)
- : TimerTask (qpid::sys::Duration ((_seconds ? _seconds : 1) * qpid::sys::TIME_SEC)), broker(_broker) {}
-
-ManagementBroker::Periodic::~Periodic () {}
-
-void ManagementBroker::Periodic::fire ()
-{
- broker.timer.add (intrusive_ptr<TimerTask> (new Periodic (broker, broker.interval)));
- broker.PeriodicProcessing ();
-}
-
-void ManagementBroker::clientAdded (void)
-{
- Mutex::ScopedLock lock (userLock);
-
- clientWasAdded = true;
- for (RemoteAgentMap::iterator aIter = remoteAgents.begin();
- aIter != remoteAgents.end();
- aIter++) {
- Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
- uint32_t outLen;
-
- EncodeHeader (outBuffer, 'x');
- outLen = MA_BUFFER_SIZE - outBuffer.available ();
- outBuffer.reset ();
- SendBuffer (outBuffer, outLen, dExchange, aIter->second->routingKey);
- }
-}
-
-void ManagementBroker::EncodeHeader (Buffer& buf, uint8_t opcode, uint32_t seq)
-{
- buf.putOctet ('A');
- buf.putOctet ('M');
- buf.putOctet ('1');
- buf.putOctet (opcode);
- buf.putLong (seq);
-}
-
-bool ManagementBroker::CheckHeader (Buffer& buf, uint8_t *opcode, uint32_t *seq)
-{
- uint8_t h1 = buf.getOctet ();
- uint8_t h2 = buf.getOctet ();
- uint8_t h3 = buf.getOctet ();
-
- *opcode = buf.getOctet ();
- *seq = buf.getLong ();
-
- return h1 == 'A' && h2 == 'M' && h3 == '1';
-}
-
-void ManagementBroker::SendBuffer (Buffer& buf,
- uint32_t length,
- broker::Exchange::shared_ptr exchange,
- string routingKey)
-{
- if (exchange.get() == 0)
- return;
-
- intrusive_ptr<Message> msg (new Message ());
- AMQFrame method (in_place<MessageTransferBody>(
- ProtocolVersion(), exchange->getName (), 0, 0));
- AMQFrame header (in_place<AMQHeaderBody>());
- AMQFrame content(in_place<AMQContentBody>());
-
- content.castBody<AMQContentBody>()->decode(buf, length);
-
- method.setEof (false);
- header.setBof (false);
- header.setEof (false);
- content.setBof (false);
-
- msg->getFrames().append(method);
- msg->getFrames().append(header);
-
- MessageProperties* props =
- msg->getFrames().getHeaders()->get<MessageProperties>(true);
- props->setContentLength(length);
- msg->getFrames().append(content);
-
- DeliverableMessage deliverable (msg);
- exchange->route (deliverable, routingKey, 0);
-}
-
-void ManagementBroker::moveNewObjectsLH()
-{
- Mutex::ScopedLock lock (addLock);
- for (ManagementObjectMap::iterator iter = newManagementObjects.begin ();
- iter != newManagementObjects.end ();
- iter++)
- managementObjects[iter->first] = iter->second;
- newManagementObjects.clear();
-}
-
-void ManagementBroker::PeriodicProcessing (void)
-{
-#define BUFSIZE 65536
- Mutex::ScopedLock lock (userLock);
- char msgChars[BUFSIZE];
- uint32_t contentSize;
- string routingKey;
- std::list<uint64_t> deleteList;
-
- {
- Buffer msgBuffer(msgChars, BUFSIZE);
- EncodeHeader(msgBuffer, 'h');
- msgBuffer.putLongLong(uint64_t(Duration(now())));
-
- contentSize = BUFSIZE - msgBuffer.available ();
- msgBuffer.reset ();
- routingKey = "mgmt." + uuid.str() + ".heartbeat";
- SendBuffer (msgBuffer, contentSize, mExchange, routingKey);
- }
-
- moveNewObjectsLH();
-
- if (clientWasAdded)
- {
- clientWasAdded = false;
- for (ManagementObjectMap::iterator iter = managementObjects.begin ();
- iter != managementObjects.end ();
- iter++)
- {
- ManagementObject* object = iter->second;
- object->setAllChanged ();
- }
- }
-
- if (managementObjects.empty ())
- return;
-
- for (ManagementObjectMap::iterator iter = managementObjects.begin ();
- iter != managementObjects.end ();
- iter++)
- {
- ManagementObject* object = iter->second;
-
- if (object->getConfigChanged () || object->isDeleted ())
- {
- Buffer msgBuffer (msgChars, BUFSIZE);
- EncodeHeader (msgBuffer, 'c');
- object->writeProperties(msgBuffer);
-
- contentSize = BUFSIZE - msgBuffer.available ();
- msgBuffer.reset ();
- routingKey = "mgmt." + uuid.str() + ".prop." + object->getClassName ();
- SendBuffer (msgBuffer, contentSize, mExchange, routingKey);
- }
-
- if (object->getInstChanged ())
- {
- Buffer msgBuffer (msgChars, BUFSIZE);
- EncodeHeader (msgBuffer, 'i');
- object->writeStatistics(msgBuffer);
-
- contentSize = BUFSIZE - msgBuffer.available ();
- msgBuffer.reset ();
- routingKey = "mgmt." + uuid.str () + ".stat." + object->getClassName ();
- SendBuffer (msgBuffer, contentSize, mExchange, routingKey);
- }
-
- if (object->isDeleted ())
- deleteList.push_back (iter->first);
- }
-
- // Delete flagged objects
- for (std::list<uint64_t>::reverse_iterator iter = deleteList.rbegin ();
- iter != deleteList.rend ();
- iter++)
- managementObjects.erase (*iter);
-
- if (!deleteList.empty()) {
- deleteList.clear();
- deleteOrphanedAgentsLH();
- }
-}
-
-void ManagementBroker::sendCommandComplete (string replyToKey, uint32_t sequence,
- uint32_t code, string text)
-{
- Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
- uint32_t outLen;
-
- EncodeHeader (outBuffer, 'z', sequence);
- outBuffer.putLong (code);
- outBuffer.putShortString (text);
- outLen = MA_BUFFER_SIZE - outBuffer.available ();
- outBuffer.reset ();
- SendBuffer (outBuffer, outLen, dExchange, replyToKey);
-}
-
-bool ManagementBroker::dispatchCommand (Deliverable& deliverable,
- const string& routingKey,
- const FieldTable* /*args*/)
-{
- Mutex::ScopedLock lock (userLock);
- Message& msg = ((DeliverableMessage&) deliverable).getMessage ();
-
- // Parse the routing key. This management broker should act as though it
- // is bound to the exchange to match the following keys:
- //
- // agent.<X>.#
- // broker.#
- //
- // where <X> is any non-negative decimal integer less than the lowest remote
- // object-id bank.
-
- if (routingKey == "broker") {
- dispatchAgentCommandLH (msg);
- return false;
- }
-
- else if (routingKey.compare(0, 6, "agent.") == 0) {
- std::string::size_type delim = routingKey.find('.', 6);
- if (delim == string::npos)
- delim = routingKey.length();
- string bank = routingKey.substr(6, delim - 6);
- if ((uint32_t) atoi(bank.c_str()) <= localBank) {
- dispatchAgentCommandLH (msg);
- return false;
- }
- }
-
- return true;
-}
-
-void ManagementBroker::handleMethodRequestLH (Buffer& inBuffer, string replyToKey, uint32_t sequence)
-{
- string methodName;
- Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
- uint32_t outLen;
-
- uint64_t objId = inBuffer.getLongLong();
- inBuffer.getShortString(methodName);
-
- EncodeHeader(outBuffer, 'm', sequence);
-
- ManagementObjectMap::iterator iter = managementObjects.find(objId);
- if (iter == managementObjects.end() || iter->second->isDeleted()) {
- outBuffer.putLong (Manageable::STATUS_UNKNOWN_OBJECT);
- outBuffer.putShortString (Manageable::StatusText (Manageable::STATUS_UNKNOWN_OBJECT));
- } else {
- iter->second->doMethod(methodName, inBuffer, outBuffer);
- }
-
- outLen = MA_BUFFER_SIZE - outBuffer.available();
- outBuffer.reset();
- SendBuffer(outBuffer, outLen, dExchange, replyToKey);
-}
-
-void ManagementBroker::handleBrokerRequestLH (Buffer&, string replyToKey, uint32_t sequence)
-{
- Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
- uint32_t outLen;
-
- EncodeHeader (outBuffer, 'b', sequence);
- uuid.encode (outBuffer);
-
- outLen = MA_BUFFER_SIZE - outBuffer.available ();
- outBuffer.reset ();
- SendBuffer (outBuffer, outLen, dExchange, replyToKey);
-}
-
-void ManagementBroker::handlePackageQueryLH (Buffer&, string replyToKey, uint32_t sequence)
-{
- for (PackageMap::iterator pIter = packages.begin ();
- pIter != packages.end ();
- pIter++)
- {
- Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
- uint32_t outLen;
-
- EncodeHeader (outBuffer, 'p', sequence);
- EncodePackageIndication (outBuffer, pIter);
- outLen = MA_BUFFER_SIZE - outBuffer.available ();
- outBuffer.reset ();
- SendBuffer (outBuffer, outLen, dExchange, replyToKey);
- }
-
- sendCommandComplete (replyToKey, sequence);
-}
-
-void ManagementBroker::handlePackageIndLH (Buffer& inBuffer, string /*replyToKey*/, uint32_t /*sequence*/)
-{
- std::string packageName;
-
- inBuffer.getShortString(packageName);
- FindOrAddPackageLH(packageName);
-}
-
-void ManagementBroker::handleClassQueryLH (Buffer& inBuffer, string replyToKey, uint32_t sequence)
-{
- std::string packageName;
-
- inBuffer.getShortString (packageName);
- PackageMap::iterator pIter = packages.find (packageName);
- if (pIter != packages.end ())
- {
- ClassMap cMap = pIter->second;
- for (ClassMap::iterator cIter = cMap.begin ();
- cIter != cMap.end ();
- cIter++)
- {
- if (cIter->second->hasSchema ())
- {
- Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
- uint32_t outLen;
-
- EncodeHeader (outBuffer, 'q', sequence);
- EncodeClassIndication (outBuffer, pIter, cIter);
- outLen = MA_BUFFER_SIZE - outBuffer.available ();
- outBuffer.reset ();
- SendBuffer (outBuffer, outLen, dExchange, replyToKey);
- }
- }
- }
-
- sendCommandComplete (replyToKey, sequence);
-}
-
-void ManagementBroker::handleClassIndLH (Buffer& inBuffer, string replyToKey, uint32_t)
-{
- std::string packageName;
- SchemaClassKey key;
-
- inBuffer.getShortString(packageName);
- inBuffer.getShortString(key.name);
- inBuffer.getBin128(key.hash);
-
- PackageMap::iterator pIter = FindOrAddPackageLH(packageName);
- ClassMap::iterator cIter = pIter->second.find(key);
- if (cIter == pIter->second.end()) {
- Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
- uint32_t outLen;
- uint32_t sequence = nextRequestSequence++;
-
- EncodeHeader (outBuffer, 'S', sequence);
- outBuffer.putShortString(packageName);
- outBuffer.putShortString(key.name);
- outBuffer.putBin128(key.hash);
- outLen = MA_BUFFER_SIZE - outBuffer.available ();
- outBuffer.reset ();
- SendBuffer (outBuffer, outLen, dExchange, replyToKey);
-
- SchemaClass* newSchema = new SchemaClass;
- newSchema->pendingSequence = sequence;
- pIter->second[key] = newSchema;
- }
-}
-
-void ManagementBroker::SchemaClass::appendSchema(Buffer& buf)
-{
- // If the management package is attached locally (embedded in the broker or
- // linked in via plug-in), call the schema handler directly. If the package
- // is from a remote management agent, send the stored schema information.
-
- if (writeSchemaCall != 0)
- writeSchemaCall(buf);
- else
- buf.putRawData(buffer, bufferLen);
-}
-
-void ManagementBroker::handleSchemaRequestLH (Buffer& inBuffer, string replyToKey, uint32_t sequence)
-{
- string packageName;
- SchemaClassKey key;
-
- inBuffer.getShortString (packageName);
- inBuffer.getShortString (key.name);
- inBuffer.getBin128 (key.hash);
-
- PackageMap::iterator pIter = packages.find (packageName);
- if (pIter != packages.end()) {
- ClassMap cMap = pIter->second;
- ClassMap::iterator cIter = cMap.find (key);
- if (cIter != cMap.end()) {
- Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
- uint32_t outLen;
- SchemaClass* classInfo = cIter->second;
-
- if (classInfo->hasSchema()) {
- EncodeHeader(outBuffer, 's', sequence);
- classInfo->appendSchema (outBuffer);
- outLen = MA_BUFFER_SIZE - outBuffer.available ();
- outBuffer.reset();
- SendBuffer (outBuffer, outLen, dExchange, replyToKey);
- }
- else
- sendCommandComplete (replyToKey, sequence, 1, "Schema not available");
- }
- else
- sendCommandComplete (replyToKey, sequence, 1, "Class key not found");
- }
- else
- sendCommandComplete (replyToKey, sequence, 1, "Package not found");
-}
-
-void ManagementBroker::handleSchemaResponseLH (Buffer& inBuffer, string /*replyToKey*/, uint32_t sequence)
-{
- string packageName;
- SchemaClassKey key;
-
- inBuffer.record();
- inBuffer.getShortString (packageName);
- inBuffer.getShortString (key.name);
- inBuffer.getBin128 (key.hash);
- inBuffer.restore();
-
- PackageMap::iterator pIter = packages.find(packageName);
- if (pIter != packages.end()) {
- ClassMap cMap = pIter->second;
- ClassMap::iterator cIter = cMap.find(key);
- if (cIter != cMap.end() && cIter->second->pendingSequence == sequence) {
- size_t length = ValidateSchema(inBuffer);
- if (length == 0)
- cMap.erase(key);
- else {
- cIter->second->buffer = (uint8_t*) malloc(length);
- cIter->second->bufferLen = length;
- inBuffer.getRawData(cIter->second->buffer, cIter->second->bufferLen);
-
- // Publish a class-indication message
- Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
- uint32_t outLen;
-
- EncodeHeader (outBuffer, 'q');
- EncodeClassIndication (outBuffer, pIter, cIter);
- outLen = MA_BUFFER_SIZE - outBuffer.available ();
- outBuffer.reset ();
- SendBuffer (outBuffer, outLen, mExchange, "mgmt." + uuid.str() + ".schema");
- }
- }
- }
-}
-
-bool ManagementBroker::bankInUse (uint32_t bank)
-{
- for (RemoteAgentMap::iterator aIter = remoteAgents.begin();
- aIter != remoteAgents.end();
- aIter++)
- if (aIter->second->objIdBank == bank)
- return true;
- return false;
-}
-
-uint32_t ManagementBroker::allocateNewBank ()
-{
- while (bankInUse (nextRemoteBank))
- nextRemoteBank++;
-
- uint32_t allocated = nextRemoteBank++;
- writeData ();
- return allocated;
-}
-
-uint32_t ManagementBroker::assignBankLH (uint32_t requestedBank)
-{
- if (requestedBank == 0 || bankInUse (requestedBank))
- return allocateNewBank ();
- return requestedBank;
-}
-
-void ManagementBroker::deleteOrphanedAgentsLH()
-{
- vector<uint64_t> deleteList;
-
- for (RemoteAgentMap::iterator aIter = remoteAgents.begin(); aIter != remoteAgents.end(); aIter++) {
- uint64_t connectionRef = aIter->first;
- bool found = false;
-
- for (ManagementObjectMap::iterator iter = managementObjects.begin ();
- iter != managementObjects.end ();
- iter++) {
- if (iter->first == connectionRef && !iter->second->isDeleted()) {
- found = true;
- break;
- }
- }
-
- if (!found) {
- deleteList.push_back(connectionRef);
- delete aIter->second;
- }
- }
-
- for (vector<uint64_t>::iterator dIter = deleteList.begin(); dIter != deleteList.end(); dIter++) {
-
- remoteAgents.erase(*dIter);
- }
-
- deleteList.clear();
-}
-
-void ManagementBroker::handleAttachRequestLH (Buffer& inBuffer, string replyToKey, uint32_t sequence, const ConnectionToken* connToken)
-{
- string label;
- uint32_t requestedBank;
- uint32_t assignedBank;
- uint64_t connectionRef = ((const ConnectionState*) connToken)->GetManagementObject()->getObjectId();
- Uuid systemId;
-
- moveNewObjectsLH();
- deleteOrphanedAgentsLH();
- RemoteAgentMap::iterator aIter = remoteAgents.find(connectionRef);
- if (aIter != remoteAgents.end()) {
- // There already exists an agent on this session. Reject the request.
- sendCommandComplete (replyToKey, sequence, 1, "Connection already has remote agent");
- return;
- }
-
- inBuffer.getShortString (label);
- systemId.decode (inBuffer);
- requestedBank = inBuffer.getLong ();
- assignedBank = assignBankLH (requestedBank);
-
- RemoteAgent* agent = new RemoteAgent;
- agent->objIdBank = assignedBank;
- agent->routingKey = replyToKey;
- agent->connectionRef = connectionRef;
- agent->mgmtObject = new management::Agent (this, agent);
- agent->mgmtObject->set_connectionRef(agent->connectionRef);
- agent->mgmtObject->set_label (label);
- agent->mgmtObject->set_registeredTo (broker->GetManagementObject()->getObjectId());
- agent->mgmtObject->set_systemId (systemId);
- agent->mgmtObject->set_objectIdBank (assignedBank);
- addObject (agent->mgmtObject);
-
- remoteAgents[connectionRef] = agent;
-
- // Send an Attach Response
- Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
- uint32_t outLen;
-
- EncodeHeader (outBuffer, 'a', sequence);
- outBuffer.putLong (assignedBank);
- outLen = MA_BUFFER_SIZE - outBuffer.available ();
- outBuffer.reset ();
- SendBuffer (outBuffer, outLen, dExchange, replyToKey);
-}
-
-void ManagementBroker::handleGetQueryLH (Buffer& inBuffer, string replyToKey, uint32_t sequence)
-{
- FieldTable ft;
- FieldTable::ValuePtr value;
-
- moveNewObjectsLH();
-
- ft.decode(inBuffer);
- value = ft.get("_class");
- if (value.get() == 0 || !value->convertsTo<string>())
- {
- // TODO: Send completion with an error code
- return;
- }
-
- string className (value->get<string>());
-
- for (ManagementObjectMap::iterator iter = managementObjects.begin ();
- iter != managementObjects.end ();
- iter++)
- {
- ManagementObject* object = iter->second;
- if (object->getClassName () == className)
- {
- Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
- uint32_t outLen;
-
- EncodeHeader (outBuffer, 'g', sequence);
- object->writeProperties(outBuffer);
- object->writeStatistics(outBuffer, true);
- outLen = MA_BUFFER_SIZE - outBuffer.available ();
- outBuffer.reset ();
- SendBuffer (outBuffer, outLen, dExchange, replyToKey);
- }
- }
-
- sendCommandComplete (replyToKey, sequence);
-}
-
-void ManagementBroker::dispatchAgentCommandLH (Message& msg)
-{
- Buffer inBuffer (inputBuffer, MA_BUFFER_SIZE);
- uint8_t opcode;
- uint32_t sequence;
- string replyToKey;
-
- const framing::MessageProperties* p =
- msg.getFrames().getHeaders()->get<framing::MessageProperties>();
- if (p && p->hasReplyTo()) {
- const framing::ReplyTo& rt = p->getReplyTo();
- replyToKey = rt.getRoutingKey();
- }
- else
- return;
-
- if (msg.encodedSize() > MA_BUFFER_SIZE) {
- QPID_LOG(debug, "ManagementBroker::dispatchAgentCommandLH: Message too large: " <<
- msg.encodedSize());
- return;
- }
-
- msg.encodeContent(inBuffer);
- inBuffer.reset();
-
- if (!CheckHeader(inBuffer, &opcode, &sequence))
- return;
-
- if (opcode == 'B') handleBrokerRequestLH (inBuffer, replyToKey, sequence);
- else if (opcode == 'P') handlePackageQueryLH (inBuffer, replyToKey, sequence);
- else if (opcode == 'p') handlePackageIndLH (inBuffer, replyToKey, sequence);
- else if (opcode == 'Q') handleClassQueryLH (inBuffer, replyToKey, sequence);
- else if (opcode == 'q') handleClassIndLH (inBuffer, replyToKey, sequence);
- else if (opcode == 'S') handleSchemaRequestLH (inBuffer, replyToKey, sequence);
- else if (opcode == 's') handleSchemaResponseLH (inBuffer, replyToKey, sequence);
- else if (opcode == 'A') handleAttachRequestLH (inBuffer, replyToKey, sequence, msg.getPublisher());
- else if (opcode == 'G') handleGetQueryLH (inBuffer, replyToKey, sequence);
- else if (opcode == 'M') handleMethodRequestLH (inBuffer, replyToKey, sequence);
-}
-
-ManagementBroker::PackageMap::iterator ManagementBroker::FindOrAddPackageLH(std::string name)
-{
- PackageMap::iterator pIter = packages.find (name);
- if (pIter != packages.end ())
- return pIter;
-
- // No such package found, create a new map entry.
- pair<PackageMap::iterator, bool> result =
- packages.insert (pair<string, ClassMap> (name, ClassMap ()));
- QPID_LOG (debug, "ManagementBroker added package " << name);
-
- // Publish a package-indication message
- Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE);
- uint32_t outLen;
-
- EncodeHeader (outBuffer, 'p');
- EncodePackageIndication (outBuffer, result.first);
- outLen = MA_BUFFER_SIZE - outBuffer.available ();
- outBuffer.reset ();
- SendBuffer (outBuffer, outLen, mExchange, "mgmt." + uuid.str() + ".schema.package");
-
- return result.first;
-}
-
-void ManagementBroker::AddClass(PackageMap::iterator pIter,
- string className,
- uint8_t* md5Sum,
- ManagementObject::writeSchemaCall_t schemaCall)
-{
- SchemaClassKey key;
- ClassMap& cMap = pIter->second;
-
- key.name = className;
- memcpy (&key.hash, md5Sum, 16);
-
- ClassMap::iterator cIter = cMap.find (key);
- if (cIter != cMap.end ())
- return;
-
- // No such class found, create a new class with local information.
- QPID_LOG (debug, "ManagementBroker added class " << pIter->first << "." <<
- key.name);
- SchemaClass* classInfo = new SchemaClass;
-
- classInfo->writeSchemaCall = schemaCall;
- cMap[key] = classInfo;
- cIter = cMap.find (key);
-}
-
-void ManagementBroker::EncodePackageIndication (Buffer& buf,
- PackageMap::iterator pIter)
-{
- buf.putShortString ((*pIter).first);
-}
-
-void ManagementBroker::EncodeClassIndication (Buffer& buf,
- PackageMap::iterator pIter,
- ClassMap::iterator cIter)
-{
- SchemaClassKey key = (*cIter).first;
-
- buf.putShortString ((*pIter).first);
- buf.putShortString (key.name);
- buf.putBin128 (key.hash);
-}
-
-size_t ManagementBroker::ValidateSchema(Buffer& inBuffer)
-{
- uint32_t start = inBuffer.getPosition();
- uint32_t end;
- string text;
- uint8_t hash[16];
-
- inBuffer.record();
- inBuffer.getShortString(text);
- inBuffer.getShortString(text);
- inBuffer.getBin128(hash);
-
- uint16_t propCount = inBuffer.getShort();
- uint16_t statCount = inBuffer.getShort();
- uint16_t methCount = inBuffer.getShort();
- uint16_t evntCount = inBuffer.getShort();
-
- for (uint16_t idx = 0; idx < propCount + statCount; idx++) {
- FieldTable ft;
- ft.decode(inBuffer);
- }
-
- for (uint16_t idx = 0; idx < methCount; idx++) {
- FieldTable ft;
- ft.decode(inBuffer);
- int argCount = ft.getInt("argCount");
- for (int mIdx = 0; mIdx < argCount; mIdx++) {
- FieldTable aft;
- aft.decode(inBuffer);
- }
- }
-
- if (evntCount != 0)
- return 0;
-
- end = inBuffer.getPosition();
- inBuffer.restore(); // restore original position
- return end - start;
-}
diff --git a/cpp/src/qpid/management/ManagementBroker.h b/cpp/src/qpid/management/ManagementBroker.h
deleted file mode 100644
index 151926f526..0000000000
--- a/cpp/src/qpid/management/ManagementBroker.h
+++ /dev/null
@@ -1,216 +0,0 @@
-#ifndef _ManagementBroker_
-#define _ManagementBroker_
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES 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/Options.h"
-#include "qpid/broker/Exchange.h"
-#include "qpid/broker/Timer.h"
-#include "qpid/framing/Uuid.h"
-#include "qpid/sys/Mutex.h"
-#include "qpid/broker/ConnectionToken.h"
-#include "qpid/agent/ManagementAgent.h"
-#include "ManagementObject.h"
-#include "Manageable.h"
-#include "qpid/management/Agent.h"
-#include <qpid/framing/AMQFrame.h>
-
-namespace qpid {
-namespace management {
-
-class ManagementBroker : public ManagementAgent
-{
- private:
-
- int threadPoolSize;
-
- public:
-
- ManagementBroker ();
- virtual ~ManagementBroker ();
-
- void configure (std::string dataDir, uint16_t interval, Manageable* broker, int threadPoolSize);
- void setInterval (uint16_t _interval) { interval = _interval; }
- void setExchange (broker::Exchange::shared_ptr mgmtExchange,
- broker::Exchange::shared_ptr directExchange);
- int getMaxThreads () { return threadPoolSize; }
- void RegisterClass (std::string packageName,
- std::string className,
- uint8_t* md5Sum,
- ManagementObject::writeSchemaCall_t schemaCall);
- uint64_t addObject (ManagementObject* object,
- uint32_t persistId = 0,
- uint32_t persistBank = 4);
- void clientAdded (void);
- bool dispatchCommand (broker::Deliverable& msg,
- const std::string& routingKey,
- const framing::FieldTable* args);
-
- // Stubs for remote management agent calls
- void init (std::string, uint16_t, uint16_t, bool) { assert(0); }
- uint32_t pollCallbacks (uint32_t) { assert(0); return 0; }
- int getSignalFd () { assert(0); return -1; }
-
- private:
- friend class ManagementAgent;
-
- struct Periodic : public broker::TimerTask
- {
- ManagementBroker& broker;
-
- Periodic (ManagementBroker& broker, uint32_t seconds);
- virtual ~Periodic ();
- void fire ();
- };
-
- // Storage for tracking remote management agents, attached via the client
- // management agent API.
- //
- struct RemoteAgent : public Manageable
- {
- uint32_t objIdBank;
- std::string routingKey;
- uint64_t connectionRef;
- Agent* mgmtObject;
- ManagementObject* GetManagementObject (void) const { return mgmtObject; }
- virtual ~RemoteAgent ();
- };
-
- // TODO: Eventually replace string with entire reply-to structure. reply-to
- // currently assumes that the exchange is "amq.direct" even though it could
- // in theory be specified differently.
- typedef std::map<uint64_t, RemoteAgent*> RemoteAgentMap;
- typedef std::vector<std::string> ReplyToVector;
-
- // Storage for known schema classes:
- //
- // SchemaClassKey -- Key elements for map lookups
- // SchemaClassKeyComp -- Comparison class for SchemaClassKey
- // SchemaClass -- Non-key elements for classes
- //
- struct SchemaClassKey
- {
- std::string name;
- uint8_t hash[16];
- };
-
- struct SchemaClassKeyComp
- {
- bool operator() (const SchemaClassKey& lhs, const SchemaClassKey& rhs) const
- {
- if (lhs.name != rhs.name)
- return lhs.name < rhs.name;
- else
- for (int i = 0; i < 16; i++)
- if (lhs.hash[i] != rhs.hash[i])
- return lhs.hash[i] < rhs.hash[i];
- return false;
- }
- };
-
- struct SchemaClass
- {
- ManagementObject::writeSchemaCall_t writeSchemaCall;
- uint32_t pendingSequence;
- size_t bufferLen;
- uint8_t* buffer;
-
- SchemaClass () : writeSchemaCall(0), pendingSequence(0), bufferLen(0), buffer(0) {}
- bool hasSchema () { return (writeSchemaCall != 0) || (buffer != 0); }
- void appendSchema (framing::Buffer& buf);
- };
-
- typedef std::map<SchemaClassKey, SchemaClass*, SchemaClassKeyComp> ClassMap;
- typedef std::map<std::string, ClassMap> PackageMap;
-
- RemoteAgentMap remoteAgents;
- PackageMap packages;
- ManagementObjectMap managementObjects;
- ManagementObjectMap newManagementObjects;
-
- static ManagementAgent* agent;
- static bool enabled;
-
- framing::Uuid uuid;
- sys::Mutex addLock;
- sys::Mutex userLock;
- broker::Timer timer;
- broker::Exchange::shared_ptr mExchange;
- broker::Exchange::shared_ptr dExchange;
- std::string dataDir;
- uint16_t interval;
- Manageable* broker;
- uint16_t bootSequence;
- uint32_t localBank;
- uint32_t nextObjectId;
- uint32_t nextRemoteBank;
- uint32_t nextRequestSequence;
- bool clientWasAdded;
-
-# define MA_BUFFER_SIZE 65536
- char inputBuffer[MA_BUFFER_SIZE];
- char outputBuffer[MA_BUFFER_SIZE];
-
- void writeData ();
- void PeriodicProcessing (void);
- void EncodeHeader (framing::Buffer& buf, uint8_t opcode, uint32_t seq = 0);
- bool CheckHeader (framing::Buffer& buf, uint8_t *opcode, uint32_t *seq);
- void SendBuffer (framing::Buffer& buf,
- uint32_t length,
- broker::Exchange::shared_ptr exchange,
- std::string routingKey);
- void moveNewObjectsLH();
-
- void dispatchAgentCommandLH (broker::Message& msg);
-
- PackageMap::iterator FindOrAddPackageLH(std::string name);
- void AddClass(PackageMap::iterator pIter,
- std::string className,
- uint8_t* md5Sum,
- ManagementObject::writeSchemaCall_t schemaCall);
- void EncodePackageIndication (framing::Buffer& buf,
- PackageMap::iterator pIter);
- void EncodeClassIndication (framing::Buffer& buf,
- PackageMap::iterator pIter,
- ClassMap::iterator cIter);
- bool bankInUse (uint32_t bank);
- uint32_t allocateNewBank ();
- uint32_t assignBankLH (uint32_t requestedPrefix);
- void deleteOrphanedAgentsLH();
- void sendCommandComplete (std::string replyToKey, uint32_t sequence,
- uint32_t code = 0, std::string text = std::string("OK"));
- void handleBrokerRequestLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
- void handlePackageQueryLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
- void handlePackageIndLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
- void handleClassQueryLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
- void handleClassIndLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
- void handleSchemaRequestLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
- void handleSchemaResponseLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
- void handleAttachRequestLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence, const broker::ConnectionToken* connToken);
- void handleGetQueryLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
- void handleMethodRequestLH (framing::Buffer& inBuffer, std::string replyToKey, uint32_t sequence);
-
- size_t ValidateSchema(framing::Buffer&);
-};
-
-}}
-
-#endif /*!_ManagementBroker_*/
diff --git a/cpp/src/qpid/management/ManagementExchange.cpp b/cpp/src/qpid/management/ManagementExchange.cpp
index 4ccf8e68c9..b90bcd87d8 100644
--- a/cpp/src/qpid/management/ManagementExchange.cpp
+++ b/cpp/src/qpid/management/ManagementExchange.cpp
@@ -19,7 +19,7 @@
*
*/
-#include "ManagementExchange.h"
+#include "qpid/management/ManagementExchange.h"
#include "qpid/log/Statement.h"
using namespace qpid::management;
@@ -27,14 +27,14 @@ using namespace qpid::broker;
using namespace qpid::framing;
using namespace qpid::sys;
-ManagementExchange::ManagementExchange (const string& _name, Manageable* _parent) :
- Exchange (_name, _parent), TopicExchange(_name, _parent) {}
+ManagementExchange::ManagementExchange (const string& _name, Manageable* _parent, Broker* b) :
+ Exchange (_name, _parent, b), TopicExchange(_name, _parent, b) {}
ManagementExchange::ManagementExchange (const std::string& _name,
bool _durable,
const FieldTable& _args,
- Manageable* _parent) :
- Exchange (_name, _durable, _args, _parent),
- TopicExchange(_name, _durable, _args, _parent) {}
+ Manageable* _parent, Broker* b) :
+ Exchange (_name, _durable, _args, _parent, b),
+ TopicExchange(_name, _durable, _args, _parent, b) {}
void ManagementExchange::route (Deliverable& msg,
const string& routingKey,
@@ -56,11 +56,11 @@ bool ManagementExchange::bind (Queue::shared_ptr queue,
const string& routingKey,
const qpid::framing::FieldTable* args)
{
- managementAgent->clientAdded ();
- return TopicExchange::bind (queue, routingKey, args);
+ managementAgent->clientAdded(routingKey);
+ return TopicExchange::bind(queue, routingKey, args);
}
-void ManagementExchange::setManagmentAgent (ManagementBroker* agent)
+void ManagementExchange::setManagmentAgent (ManagementAgent* agent)
{
managementAgent = agent;
}
diff --git a/cpp/src/qpid/management/ManagementExchange.h b/cpp/src/qpid/management/ManagementExchange.h
index d54db1a74e..3fa4039af7 100644
--- a/cpp/src/qpid/management/ManagementExchange.h
+++ b/cpp/src/qpid/management/ManagementExchange.h
@@ -22,7 +22,7 @@
#define _ManagementExchange_
#include "qpid/broker/TopicExchange.h"
-#include "ManagementBroker.h"
+#include "qpid/management/ManagementAgent.h"
namespace qpid {
namespace broker {
@@ -30,15 +30,15 @@ namespace broker {
class ManagementExchange : public virtual TopicExchange
{
private:
- management::ManagementBroker* managementAgent;
+ management::ManagementAgent* managementAgent;
public:
static const std::string typeName;
- ManagementExchange (const string& name, Manageable* _parent = 0);
+ ManagementExchange (const string& name, Manageable* _parent = 0, Broker* broker = 0);
ManagementExchange (const string& _name, bool _durable,
const qpid::framing::FieldTable& _args,
- Manageable* _parent = 0);
+ Manageable* _parent = 0, Broker* broker = 0);
virtual std::string getType() const { return typeName; }
@@ -50,7 +50,7 @@ class ManagementExchange : public virtual TopicExchange
const string& routingKey,
const qpid::framing::FieldTable* args);
- void setManagmentAgent (management::ManagementBroker* agent);
+ void setManagmentAgent (management::ManagementAgent* agent);
virtual ~ManagementExchange();
};
diff --git a/cpp/src/qpid/management/ManagementObject.cpp b/cpp/src/qpid/management/ManagementObject.cpp
index 74d9571d10..bcb6159663 100644
--- a/cpp/src/qpid/management/ManagementObject.cpp
+++ b/cpp/src/qpid/management/ManagementObject.cpp
@@ -19,38 +19,165 @@
*
*/
-#include "Manageable.h"
-#include "ManagementObject.h"
-#include "qpid/agent/ManagementAgent.h"
+#include "qpid/management/Manageable.h"
+#include "qpid/management/ManagementObject.h"
#include "qpid/framing/FieldTable.h"
+#include "qpid/sys/Thread.h"
-using namespace qpid::framing;
+#include <stdlib.h>
+
+using namespace qpid;
using namespace qpid::management;
-using namespace qpid::sys;
+void AgentAttachment::setBanks(uint32_t broker, uint32_t bank)
+{
+ first =
+ ((uint64_t) (broker & 0x000fffff)) << 28 |
+ ((uint64_t) (bank & 0x0fffffff));
+}
+
+ObjectId::ObjectId(uint8_t flags, uint16_t seq, uint32_t broker, uint32_t bank, uint64_t object)
+ : agent(0)
+{
+ first =
+ ((uint64_t) (flags & 0x0f)) << 60 |
+ ((uint64_t) (seq & 0x0fff)) << 48 |
+ ((uint64_t) (broker & 0x000fffff)) << 28 |
+ ((uint64_t) (bank & 0x0fffffff));
+ second = object;
+}
+
+ObjectId::ObjectId(AgentAttachment* _agent, uint8_t flags, uint16_t seq, uint64_t object)
+ : agent(_agent)
+{
+ first =
+ ((uint64_t) (flags & 0x0f)) << 60 |
+ ((uint64_t) (seq & 0x0fff)) << 48;
+ second = object;
+}
+
+ObjectId::ObjectId(std::istream& in) : agent(0)
+{
+ std::string text;
+ in >> text;
+ fromString(text);
+}
+
+ObjectId::ObjectId(const std::string& text) : agent(0)
+{
+ fromString(text);
+}
+
+void ObjectId::fromString(const std::string& text)
+{
+#define FIELDS 5
+#if defined (_WIN32) && !defined (atoll)
+# define atoll(X) _atoi64(X)
+#endif
+
+ std::string copy(text.c_str());
+ char* cText;
+ char* field[FIELDS];
+ bool atFieldStart = true;
+ int idx = 0;
+
+ cText = const_cast<char*>(copy.c_str());
+ for (char* cursor = cText; *cursor; cursor++) {
+ if (atFieldStart) {
+ if (idx >= FIELDS)
+ throw Exception("Invalid ObjectId format");
+ field[idx++] = cursor;
+ atFieldStart = false;
+ } else {
+ if (*cursor == '-') {
+ *cursor = '\0';
+ atFieldStart = true;
+ }
+ }
+ }
+
+ if (idx != FIELDS)
+ throw Exception("Invalid ObjectId format");
+
+ first = (atoll(field[0]) << 60) +
+ (atoll(field[1]) << 48) +
+ (atoll(field[2]) << 28) +
+ atoll(field[3]);
+ second = atoll(field[4]);
+}
+
+
+bool ObjectId::operator==(const ObjectId &other) const
+{
+ uint64_t otherFirst = agent == 0 ? other.first : other.first & 0xffff000000000000LL;
+
+ return first == otherFirst && second == other.second;
+}
+
+bool ObjectId::operator<(const ObjectId &other) const
+{
+ uint64_t otherFirst = agent == 0 ? other.first : other.first & 0xffff000000000000LL;
+
+ return (first < otherFirst) || ((first == otherFirst) && (second < other.second));
+}
+
+void ObjectId::encode(framing::Buffer& buffer)
+{
+ if (agent == 0)
+ buffer.putLongLong(first);
+ else
+ buffer.putLongLong(first | agent->first);
+ buffer.putLongLong(second);
+}
+
+void ObjectId::decode(framing::Buffer& buffer)
+{
+ first = buffer.getLongLong();
+ second = buffer.getLongLong();
+}
+
+namespace qpid {
+namespace management {
+
+std::ostream& operator<<(std::ostream& out, const ObjectId& i)
+{
+ uint64_t virtFirst = i.first;
+ if (i.agent)
+ virtFirst |= i.agent->getFirst();
+
+ out << ((virtFirst & 0xF000000000000000LL) >> 60) <<
+ "-" << ((virtFirst & 0x0FFF000000000000LL) >> 48) <<
+ "-" << ((virtFirst & 0x0000FFFFF0000000LL) >> 28) <<
+ "-" << (virtFirst & 0x000000000FFFFFFFLL) <<
+ "-" << i.second;
+ return out;
+}
+
+}}
+
+int ManagementObject::maxThreads = 1;
int ManagementObject::nextThreadIndex = 0;
-void ManagementObject::writeTimestamps (Buffer& buf)
+void ManagementObject::writeTimestamps (framing::Buffer& buf)
{
buf.putShortString (getPackageName ());
buf.putShortString (getClassName ());
buf.putBin128 (getMd5Sum ());
- buf.putLongLong (uint64_t (Duration (now ())));
+ buf.putLongLong (updateTime);
buf.putLongLong (createTime);
buf.putLongLong (destroyTime);
- buf.putLongLong (objectId);
+ objectId.encode(buf);
}
-void ManagementObject::setReference(uint64_t) {}
+void ManagementObject::setReference(ObjectId) {}
int ManagementObject::getThreadIndex() {
- static __thread int thisIndex = -1;
+ static QPID_TSS int thisIndex = -1;
if (thisIndex == -1) {
sys::Mutex::ScopedLock mutex(accessLock);
thisIndex = nextThreadIndex;
- if (nextThreadIndex < agent->getMaxThreads() - 1)
+ if (nextThreadIndex < maxThreads - 1)
nextThreadIndex++;
}
return thisIndex;
}
-
diff --git a/cpp/src/qpid/management/ManagementObject.h b/cpp/src/qpid/management/ManagementObject.h
deleted file mode 100644
index 78d065aac2..0000000000
--- a/cpp/src/qpid/management/ManagementObject.h
+++ /dev/null
@@ -1,132 +0,0 @@
-#ifndef _ManagementObject_
-#define _ManagementObject_
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES 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/sys/Time.h"
-#include "qpid/sys/Mutex.h"
-#include <qpid/framing/Buffer.h>
-#include <map>
-
-namespace qpid {
-namespace management {
-
-class Manageable;
-class ManagementAgent;
-
-class ManagementObject
-{
- protected:
-
- uint64_t createTime;
- uint64_t destroyTime;
- uint64_t objectId;
- bool configChanged;
- bool instChanged;
- bool deleted;
- Manageable* coreObject;
- sys::Mutex accessLock;
- ManagementAgent* agent;
- int maxThreads;
-
- static const uint8_t TYPE_U8 = 1;
- static const uint8_t TYPE_U16 = 2;
- static const uint8_t TYPE_U32 = 3;
- static const uint8_t TYPE_U64 = 4;
- static const uint8_t TYPE_SSTR = 6;
- static const uint8_t TYPE_LSTR = 7;
- static const uint8_t TYPE_ABSTIME = 8;
- static const uint8_t TYPE_DELTATIME = 9;
- static const uint8_t TYPE_REF = 10;
- static const uint8_t TYPE_BOOL = 11;
- static const uint8_t TYPE_FLOAT = 12;
- static const uint8_t TYPE_DOUBLE = 13;
- static const uint8_t TYPE_UUID = 14;
- static const uint8_t TYPE_FTABLE = 15;
- static const uint8_t TYPE_S8 = 16;
- static const uint8_t TYPE_S16 = 17;
- static const uint8_t TYPE_S32 = 18;
- static const uint8_t TYPE_S64 = 19;
-
- static const uint8_t ACCESS_RC = 1;
- static const uint8_t ACCESS_RW = 2;
- static const uint8_t ACCESS_RO = 3;
-
- static const uint8_t DIR_I = 1;
- static const uint8_t DIR_O = 2;
- static const uint8_t DIR_IO = 3;
-
- static const uint8_t FLAG_CONFIG = 0x01;
- static const uint8_t FLAG_INDEX = 0x02;
- static const uint8_t FLAG_END = 0x80;
-
- static int nextThreadIndex;
-
- int getThreadIndex();
- void writeTimestamps (qpid::framing::Buffer& buf);
-
- public:
- typedef void (*writeSchemaCall_t) (qpid::framing::Buffer&);
-
- ManagementObject (ManagementAgent* _agent, Manageable* _core) :
- destroyTime(0), objectId (0), configChanged(true),
- instChanged(true), deleted(false), coreObject(_core), agent(_agent)
- { createTime = uint64_t (qpid::sys::Duration (qpid::sys::now ())); }
- virtual ~ManagementObject () {}
-
- virtual writeSchemaCall_t getWriteSchemaCall (void) = 0;
- virtual void writeProperties(qpid::framing::Buffer& buf) = 0;
- virtual void writeStatistics(qpid::framing::Buffer& buf,
- bool skipHeaders = false) = 0;
- virtual void doMethod (std::string methodName,
- qpid::framing::Buffer& inBuf,
- qpid::framing::Buffer& outBuf) = 0;
- virtual void setReference (uint64_t objectId);
-
- virtual std::string& getClassName (void) = 0;
- virtual std::string& getPackageName (void) = 0;
- virtual uint8_t* getMd5Sum (void) = 0;
-
- void setObjectId (uint64_t oid) { objectId = oid; }
- uint64_t getObjectId (void) { return objectId; }
- inline bool getConfigChanged (void) { return configChanged; }
- virtual bool getInstChanged (void) { return instChanged; }
- inline void setAllChanged (void) {
- configChanged = true;
- instChanged = true;
- }
-
- inline void resourceDestroy (void) {
- destroyTime = uint64_t (qpid::sys::Duration (qpid::sys::now ()));
- deleted = true;
- }
- inline bool isDeleted (void) { return deleted; }
- inline sys::Mutex& getLock() { return accessLock; }
-};
-
-typedef std::map<uint64_t,ManagementObject*> ManagementObjectMap;
-
-}}
-
-
-
-#endif /*!_ManagementObject_*/
diff --git a/cpp/src/qpid/messaging/Address.cpp b/cpp/src/qpid/messaging/Address.cpp
new file mode 100644
index 0000000000..ff72f62705
--- /dev/null
+++ b/cpp/src/qpid/messaging/Address.cpp
@@ -0,0 +1,362 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Address.h"
+#include "qpid/framing/Uuid.h"
+#include <sstream>
+#include <boost/format.hpp>
+
+namespace qpid {
+namespace messaging {
+
+namespace {
+const std::string SUBJECT_DIVIDER = "/";
+const std::string OPTIONS_DIVIDER = ";";
+const std::string SPACE = " ";
+const std::string TYPE = "type";
+}
+class AddressImpl
+{
+ public:
+ std::string name;
+ std::string subject;
+ Variant::Map options;
+
+ AddressImpl() {}
+ AddressImpl(const std::string& n, const std::string& s, const Variant::Map& o) :
+ name(n), subject(s), options(o) {}
+};
+
+class AddressParser
+{
+ public:
+ AddressParser(const std::string&);
+ bool parse(Address& address);
+ private:
+ const std::string& input;
+ std::string::size_type current;
+ static const std::string RESERVED;
+
+ bool readChar(char c);
+ bool readQuotedString(std::string& s);
+ bool readQuotedValue(Variant& value);
+ bool readString(std::string& value, char delimiter);
+ bool readWord(std::string& word, const std::string& delims = RESERVED);
+ bool readSimpleValue(Variant& word);
+ bool readKey(std::string& key);
+ bool readValue(Variant& value);
+ bool readKeyValuePair(Variant::Map& map);
+ bool readMap(Variant& value);
+ bool readList(Variant& value);
+ bool readName(std::string& name);
+ bool readSubject(std::string& subject);
+ bool error(const std::string& message);
+ bool eos();
+ bool iswhitespace();
+ bool in(const std::string& delims);
+ bool isreserved();
+};
+
+Address::Address() : impl(new AddressImpl()) {}
+Address::Address(const std::string& address) : impl(new AddressImpl())
+{
+ AddressParser parser(address);
+ parser.parse(*this);
+}
+Address::Address(const std::string& name, const std::string& subject, const Variant::Map& options,
+ const std::string& type)
+ : impl(new AddressImpl(name, subject, options)) { setType(type); }
+Address::Address(const Address& a) :
+ impl(new AddressImpl(a.impl->name, a.impl->subject, a.impl->options)) {}
+Address::~Address() { delete impl; }
+
+Address& Address::operator=(const Address& a) { *impl = *a.impl; return *this; }
+
+
+std::string Address::toStr() const
+{
+ std::stringstream out;
+ out << impl->name;
+ if (!impl->subject.empty()) out << SUBJECT_DIVIDER << impl->subject;
+ if (!impl->options.empty()) out << OPTIONS_DIVIDER << impl->options;
+ return out.str();
+}
+Address::operator bool() const { return !impl->name.empty(); }
+bool Address::operator !() const { return impl->name.empty(); }
+
+const std::string& Address::getName() const { return impl->name; }
+void Address::setName(const std::string& name) { impl->name = name; }
+const std::string& Address::getSubject() const { return impl->subject; }
+bool Address::hasSubject() const { return !(impl->subject.empty()); }
+void Address::setSubject(const std::string& subject) { impl->subject = subject; }
+const Variant::Map& Address::getOptions() const { return impl->options; }
+Variant::Map& Address::getOptions() { return impl->options; }
+void Address::setOptions(const Variant::Map& options) { impl->options = options; }
+
+
+namespace{
+const Variant EMPTY_VARIANT;
+const std::string EMPTY_STRING;
+const std::string NODE_PROPERTIES="node-properties";
+}
+
+const Variant& find(const Variant::Map& map, const std::string& key)
+{
+ Variant::Map::const_iterator i = map.find(key);
+ if (i == map.end()) return EMPTY_VARIANT;
+ else return i->second;
+}
+
+std::string Address::getType() const
+{
+ const Variant& props = getOption(NODE_PROPERTIES);
+ if (props.getType() == VAR_MAP) {
+ const Variant& type = find(props.asMap(), TYPE);
+ if (!type.isVoid()) return type.asString();
+ }
+ return EMPTY_STRING;
+}
+
+void Address::setType(const std::string& type)
+{
+ Variant& props = impl->options[NODE_PROPERTIES];
+ if (props.isVoid()) props = Variant::Map();
+ props.asMap()[TYPE] = type;
+}
+
+const Variant& Address::getOption(const std::string& key) const
+{
+ return find(impl->options, key);
+}
+
+std::ostream& operator<<(std::ostream& out, const Address& address)
+{
+ out << address.toStr();
+ return out;
+}
+
+InvalidAddress::InvalidAddress(const std::string& msg) : Exception(msg) {}
+
+MalformedAddress::MalformedAddress(const std::string& msg) : Exception(msg) {}
+
+AddressParser::AddressParser(const std::string& s) : input(s), current(0) {}
+
+bool AddressParser::error(const std::string& message)
+{
+ throw MalformedAddress((boost::format("%1%, character %2% of %3%") % message % current % input).str());
+}
+
+bool AddressParser::parse(Address& address)
+{
+ std::string name;
+ if (readName(name)) {
+ if (name.find('#') == 0) name = qpid::framing::Uuid(true).str() + name;
+ address.setName(name);
+ if (readChar('/')) {
+ std::string subject;
+ if (readSubject(subject)) {
+ address.setSubject(subject);
+ } else {
+ return error("Expected subject after /");
+ }
+ }
+ if (readChar(';')) {
+ Variant options = Variant::Map();
+ if (readMap(options)) {
+ address.setOptions(options.asMap());
+ }
+ }
+ //skip trailing whitespace
+ while (!eos() && iswhitespace()) ++current;
+ return eos() || error("Unexpected chars in address: " + input.substr(current));
+ } else {
+ return input.empty() || error("Expected name");
+ }
+}
+
+bool AddressParser::readList(Variant& value)
+{
+ if (readChar('[')) {
+ value = Variant::List();
+ Variant item;
+ while (readValue(item)) {
+ value.asList().push_back(item);
+ if (!readChar(',')) break;
+ }
+ return readChar(']') || error("Unmatched '['!");
+ } else {
+ return false;
+ }
+}
+
+bool AddressParser::readMap(Variant& value)
+{
+ if (readChar('{')) {
+ value = Variant::Map();
+ while (readKeyValuePair(value.asMap()) && readChar(',')) {}
+ return readChar('}') || error("Unmatched '{'!");
+ } else {
+ return false;
+ }
+}
+
+bool AddressParser::readKeyValuePair(Variant::Map& map)
+{
+ std::string key;
+ Variant value;
+ if (readKey(key)) {
+ if (readChar(':') && readValue(value)) {
+ map[key] = value;
+ return true;
+ } else {
+ return error("Bad key-value pair, expected ':'");
+ }
+ } else {
+ return false;
+ }
+}
+
+bool AddressParser::readKey(std::string& key)
+{
+ return readWord(key);
+}
+
+bool AddressParser::readValue(Variant& value)
+{
+ return readSimpleValue(value) || readQuotedValue(value) ||
+ readMap(value) || readList(value) || error("Expected value");
+}
+
+bool AddressParser::readString(std::string& value, char delimiter)
+{
+ if (readChar(delimiter)) {
+ std::string::size_type start = current++;
+ while (!eos()) {
+ if (input.at(current) == delimiter) {
+ if (current > start) {
+ value = input.substr(start, current - start);
+ } else {
+ value = "";
+ }
+ ++current;
+ return true;
+ } else {
+ ++current;
+ }
+ }
+ return error("Unmatched delimiter");
+ } else {
+ return false;
+ }
+}
+
+bool AddressParser::readName(std::string& name)
+{
+ return readQuotedString(name) || readWord(name, "/;");
+}
+
+bool AddressParser::readSubject(std::string& subject)
+{
+ return readQuotedString(subject) || readWord(subject, ";");
+}
+
+bool AddressParser::readQuotedString(std::string& s)
+{
+ return readString(s, '"') || readString(s, '\'');
+}
+
+bool AddressParser::readQuotedValue(Variant& value)
+{
+ std::string s;
+ if (readQuotedString(s)) {
+ value = s;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AddressParser::readSimpleValue(Variant& value)
+{
+ std::string s;
+ if (readWord(s)) {
+ value = s;
+ try { value = value.asInt64(); return true; } catch (const InvalidConversion&) {}
+ try { value = value.asDouble(); return true; } catch (const InvalidConversion&) {}
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AddressParser::readWord(std::string& value, const std::string& delims)
+{
+ //skip leading whitespace
+ while (!eos() && iswhitespace()) ++current;
+
+ //read any number of non-whitespace, non-reserved chars into value
+ std::string::size_type start = current;
+ while (!eos() && !iswhitespace() && !in(delims)) ++current;
+
+ if (current > start) {
+ value = input.substr(start, current - start);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AddressParser::readChar(char c)
+{
+ while (!eos()) {
+ if (iswhitespace()) {
+ ++current;
+ } else if (input.at(current) == c) {
+ ++current;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return false;
+}
+
+bool AddressParser::iswhitespace()
+{
+ return ::isspace(input.at(current));
+}
+
+bool AddressParser::isreserved()
+{
+ return in(RESERVED);
+}
+
+bool AddressParser::in(const std::string& chars)
+{
+ return chars.find(input.at(current)) != std::string::npos;
+}
+
+bool AddressParser::eos()
+{
+ return current >= input.size();
+}
+
+const std::string AddressParser::RESERVED = "\'\"{}[],:/";
+}} // namespace qpid::messaging
diff --git a/cpp/src/qpid/messaging/Connection.cpp b/cpp/src/qpid/messaging/Connection.cpp
new file mode 100644
index 0000000000..64ca962317
--- /dev/null
+++ b/cpp/src/qpid/messaging/Connection.cpp
@@ -0,0 +1,96 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/Connection.h"
+#include "qpid/messaging/ConnectionImpl.h"
+#include "qpid/messaging/Session.h"
+#include "qpid/messaging/SessionImpl.h"
+#include "qpid/client/PrivateImplRef.h"
+#include "qpid/client/amqp0_10/ConnectionImpl.h"
+#include "qpid/log/Statement.h"
+
+namespace qpid {
+namespace client {
+
+typedef PrivateImplRef<qpid::messaging::Connection> PI;
+
+}
+
+namespace messaging {
+
+using qpid::client::PI;
+
+Connection Connection::open(const std::string& url, const Variant::Map& options)
+{
+ //only support amqp 0-10 at present
+ Connection connection(new qpid::client::amqp0_10::ConnectionImpl(url, options));
+ return connection;
+}
+
+Connection::Connection(ConnectionImpl* impl) { PI::ctor(*this, impl); }
+Connection::Connection(const Connection& c) : qpid::client::Handle<ConnectionImpl>() { PI::copy(*this, c); }
+Connection& Connection::operator=(const Connection& c) { return PI::assign(*this, c); }
+Connection::~Connection() { PI::dtor(*this); }
+
+void Connection::close() { impl->close(); }
+Session Connection::newSession(const char* name) { return impl->newSession(false, name); }
+Session Connection::newSession(const std::string& name) { return impl->newSession(false, name); }
+Session Connection::newSession(bool transactional, const std::string& name)
+{
+ return impl->newSession(transactional, name);
+}
+Session Connection::getSession(const std::string& name) const { return impl->getSession(name); }
+
+InvalidOptionString::InvalidOptionString(const std::string& msg) : Exception(msg) {}
+
+void parseKeyValuePair(const std::string& in, Variant::Map& out)
+{
+ std::string::size_type i = in.find('=');
+ if (i == std::string::npos || i == in.size() || in.find('=', i+1) != std::string::npos) {
+ throw InvalidOptionString(QPID_MSG("Cannot parse name-value pair from " << in));
+ } else {
+ out[in.substr(0, i)] = in.substr(i+1);
+ }
+}
+
+void parseOptionString(const std::string& in, Variant::Map& out)
+{
+ std::string::size_type start = 0;
+ std::string::size_type i = in.find('&');
+ while (i != std::string::npos) {
+ parseKeyValuePair(in.substr(start, i-start), out);
+ if (i < in.size()) {
+ start = i+1;
+ i = in.find('&', start);
+ } else {
+ i = std::string::npos;
+ }
+ }
+ parseKeyValuePair(in.substr(start), out);
+}
+
+Variant::Map parseOptionString(const std::string& in)
+{
+ Variant::Map map;
+ parseOptionString(in, map);
+ return map;
+}
+
+}} // namespace qpid::messaging
diff --git a/cpp/src/qpid/messaging/ConnectionImpl.h b/cpp/src/qpid/messaging/ConnectionImpl.h
new file mode 100644
index 0000000000..4eff68ff9d
--- /dev/null
+++ b/cpp/src/qpid/messaging/ConnectionImpl.h
@@ -0,0 +1,46 @@
+#ifndef QPID_MESSAGING_CONNECTIONIMPL_H
+#define QPID_MESSAGING_CONNECTIONIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include "qpid/RefCounted.h"
+
+namespace qpid {
+namespace client {
+}
+
+namespace messaging {
+
+class Session;
+
+class ConnectionImpl : public virtual qpid::RefCounted
+{
+ public:
+ virtual ~ConnectionImpl() {}
+ virtual void close() = 0;
+ virtual Session newSession(bool transactional, const std::string& name) = 0;
+ virtual Session getSession(const std::string& name) const = 0;
+ private:
+};
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_CONNECTIONIMPL_H*/
diff --git a/cpp/src/qpid/messaging/ListContent.cpp b/cpp/src/qpid/messaging/ListContent.cpp
new file mode 100644
index 0000000000..0c3ca5fc62
--- /dev/null
+++ b/cpp/src/qpid/messaging/ListContent.cpp
@@ -0,0 +1,98 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/ListContent.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/client/amqp0_10/Codecs.h"
+
+namespace qpid {
+namespace messaging {
+
+class ListContentImpl : public Variant
+{
+ Message* msg;
+ public:
+ ListContentImpl(Message& m) : Variant(Variant::List()), msg(&m)
+ {
+ if (msg->getContent().size()) {
+ qpid::client::amqp0_10::ListCodec codec;
+ codec.decode(msg->getContent(), *this);
+ }
+ }
+
+ void encode()
+ {
+ qpid::client::amqp0_10::ListCodec codec;
+ codec.encode(*this, msg->getContent());
+ }
+};
+
+ListContent::ListContent(Message& m) : impl(new ListContentImpl(m)) {}
+ListContent::~ListContent() { delete impl; }
+ListContent& ListContent::operator=(const ListContent& l) { *impl = *l.impl; return *this; }
+
+ListContent::const_iterator ListContent::begin() const { return impl->asList().begin(); }
+ListContent::const_iterator ListContent::end() const { return impl->asList().end(); }
+ListContent::const_reverse_iterator ListContent::rbegin() const { return impl->asList().rbegin(); }
+ListContent::const_reverse_iterator ListContent::rend() const { return impl->asList().rend(); }
+
+ListContent::iterator ListContent::begin() { return impl->asList().begin(); }
+ListContent::iterator ListContent::end() { return impl->asList().end(); }
+ListContent::reverse_iterator ListContent::rbegin() { return impl->asList().rbegin(); }
+ListContent::reverse_iterator ListContent::rend() { return impl->asList().rend(); }
+
+bool ListContent::empty() const { return impl->asList().empty(); }
+size_t ListContent::size() const { return impl->asList().size(); }
+
+const Variant& ListContent::front() const { return impl->asList().front(); }
+Variant& ListContent::front() { return impl->asList().front(); }
+const Variant& ListContent::back() const { return impl->asList().back(); }
+Variant& ListContent::back() { return impl->asList().back(); }
+
+void ListContent::push_front(const Variant& v) { impl->asList().push_front(v); }
+void ListContent::push_back(const Variant& v) { impl->asList().push_back(v); }
+
+void ListContent::pop_front() { impl->asList().pop_front(); }
+void ListContent::pop_back() { impl->asList().pop_back(); }
+
+ListContent::iterator ListContent::insert(iterator position, const Variant& v)
+{
+ return impl->asList().insert(position, v);
+}
+void ListContent::insert(iterator position, size_t n, const Variant& v)
+{
+ impl->asList().insert(position, n, v);
+}
+ListContent::iterator ListContent::erase(iterator position) { return impl->asList().erase(position); }
+ListContent::iterator ListContent::erase(iterator first, iterator last) { return impl->asList().erase(first, last); }
+void ListContent::clear() { impl->asList().clear(); }
+
+void ListContent::encode() { impl->encode(); }
+
+const Variant::List& ListContent::asList() const { return impl->asList(); }
+Variant::List& ListContent::asList() { return impl->asList(); }
+
+std::ostream& operator<<(std::ostream& out, const ListContent& m)
+{
+ out << m.asList();
+ return out;
+}
+
+}} // namespace qpid::messaging
diff --git a/cpp/src/qpid/messaging/ListView.cpp b/cpp/src/qpid/messaging/ListView.cpp
new file mode 100644
index 0000000000..b717d157fa
--- /dev/null
+++ b/cpp/src/qpid/messaging/ListView.cpp
@@ -0,0 +1,63 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/ListView.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/client/amqp0_10/Codecs.h"
+
+namespace qpid {
+namespace messaging {
+
+class ListViewImpl : public Variant
+{
+ public:
+ ListViewImpl(const Message& msg) : Variant(Variant::List())
+ {
+ if (msg.getContent().size()) {
+ qpid::client::amqp0_10::ListCodec codec;
+ codec.decode(msg.getContent(), *this);
+ }
+ }
+};
+
+ListView::ListView(const Message& m) :impl(new ListViewImpl(m)) {}
+ListView::~ListView() { delete impl; }
+ListView& ListView::operator=(const ListView& l) { *impl = *l.impl; return *this; }
+
+ListView::const_iterator ListView::begin() const { return impl->asList().begin(); }
+ListView::const_iterator ListView::end() const { return impl->asList().end(); }
+ListView::const_reverse_iterator ListView::rbegin() const { return impl->asList().rbegin(); }
+ListView::const_reverse_iterator ListView::rend() const { return impl->asList().rend(); }
+
+bool ListView::empty() const { return impl->asList().empty(); }
+size_t ListView::size() const { return impl->asList().size(); }
+
+const Variant& ListView::front() const { return impl->asList().front(); }
+const Variant& ListView::back() const { return impl->asList().back(); }
+
+const Variant::List& ListView::asList() const { return impl->asList(); }
+
+std::ostream& operator<<(std::ostream& out, const ListView& m)
+{
+ out << m.asList();
+ return out;
+}
+
+}} // namespace qpid::messaging
diff --git a/cpp/src/qpid/messaging/MapContent.cpp b/cpp/src/qpid/messaging/MapContent.cpp
new file mode 100644
index 0000000000..6dba22be99
--- /dev/null
+++ b/cpp/src/qpid/messaging/MapContent.cpp
@@ -0,0 +1,88 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/MapContent.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/client/amqp0_10/Codecs.h"
+
+namespace qpid {
+namespace messaging {
+
+class MapContentImpl : public Variant
+{
+ Message* msg;
+ public:
+ MapContentImpl(Message& m) : Variant(Variant::Map()), msg(&m)
+ {
+ if (msg->getContent().size()) {
+ qpid::client::amqp0_10::MapCodec codec;
+ codec.decode(msg->getContent(), *this);
+ }
+ }
+
+ void encode()
+ {
+ qpid::client::amqp0_10::MapCodec codec;
+ codec.encode(*this, msg->getContent());
+ msg->setContentType(qpid::client::amqp0_10::MapCodec::contentType);
+ }
+};
+
+MapContent::MapContent(Message& m) : impl(new MapContentImpl(m)) {}
+MapContent::~MapContent() { delete impl; }
+MapContent& MapContent::operator=(const MapContent& m) { *impl = *m.impl; return *this; }
+
+MapContent::const_iterator MapContent::begin() const { return impl->asMap().begin(); }
+MapContent::const_iterator MapContent::end() const { return impl->asMap().end(); }
+MapContent::const_reverse_iterator MapContent::rbegin() const { return impl->asMap().rbegin(); }
+MapContent::const_reverse_iterator MapContent::rend() const { return impl->asMap().rend(); }
+MapContent::iterator MapContent::begin() { return impl->asMap().begin(); }
+MapContent::iterator MapContent::end() { return impl->asMap().end(); }
+MapContent::reverse_iterator MapContent::rbegin() { return impl->asMap().rbegin(); }
+MapContent::reverse_iterator MapContent::rend() { return impl->asMap().rend(); }
+
+bool MapContent::empty() const { return impl->asMap().empty(); }
+size_t MapContent::size() const { return impl->asMap().size(); }
+
+MapContent::const_iterator MapContent::find(const key_type& key) const { return impl->asMap().find(key); }
+MapContent::iterator MapContent::find(const key_type& key) { return impl->asMap().find(key); }
+const Variant& MapContent::operator[](const key_type& key) const { return impl->asMap()[key]; }
+Variant& MapContent::operator[](const key_type& key) { return impl->asMap()[key]; }
+
+std::pair<MapContent::iterator,bool> MapContent::insert(const value_type& item) { return impl->asMap().insert(item); }
+MapContent::iterator MapContent::insert(iterator position, const value_type& item) { return impl->asMap().insert(position, item); }
+void MapContent::erase(iterator position) { impl->asMap().erase(position); }
+void MapContent::erase(iterator first, iterator last) { impl->asMap().erase(first, last); }
+size_t MapContent::erase(const key_type& key) { return impl->asMap().erase(key); }
+void MapContent::clear() { impl->asMap().clear(); }
+
+void MapContent::encode() { impl->encode(); }
+
+const std::map<MapContent::key_type, Variant>& MapContent::asMap() const { return impl->asMap(); }
+std::map<MapContent::key_type, Variant>& MapContent::asMap() { return impl->asMap(); }
+
+
+std::ostream& operator<<(std::ostream& out, const MapContent& m)
+{
+ out << m.asMap();
+ return out;
+}
+
+}} // namespace qpid::messaging
diff --git a/cpp/src/qpid/messaging/MapView.cpp b/cpp/src/qpid/messaging/MapView.cpp
new file mode 100644
index 0000000000..ffa6e91a16
--- /dev/null
+++ b/cpp/src/qpid/messaging/MapView.cpp
@@ -0,0 +1,63 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/MapView.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/client/amqp0_10/Codecs.h"
+
+namespace qpid {
+namespace messaging {
+
+class MapViewImpl : public Variant
+{
+ public:
+ MapViewImpl(const Message& msg) : Variant(Variant::Map())
+ {
+ if (msg.getContent().size()) {
+ qpid::client::amqp0_10::MapCodec codec;
+ codec.decode(msg.getContent(), *this);
+ }
+ }
+};
+
+MapView::MapView(const Message& m) : impl(new MapViewImpl(m)) {}
+MapView::~MapView() { delete impl; }
+MapView& MapView::operator=(const MapView& m) { *impl = *m.impl; return *this; }
+
+MapView::const_iterator MapView::begin() const { return impl->asMap().begin(); }
+MapView::const_iterator MapView::end() const { return impl->asMap().end(); }
+MapView::const_reverse_iterator MapView::rbegin() const { return impl->asMap().rbegin(); }
+MapView::const_reverse_iterator MapView::rend() const { return impl->asMap().rend(); }
+
+bool MapView::empty() const { return impl->asMap().empty(); }
+size_t MapView::size() const { return impl->asMap().size(); }
+
+MapView::const_iterator MapView::find(const key_type& key) const { return impl->asMap().find(key); }
+const Variant& MapView::operator[](const key_type& key) const { return impl->asMap()[key]; }
+
+const std::map<MapView::key_type, Variant>& MapView::asMap() const { return impl->asMap(); }
+
+std::ostream& operator<<(std::ostream& out, const MapView& m)
+{
+ out << m.asMap();
+ return out;
+}
+
+}} // namespace qpid::messaging
diff --git a/cpp/src/qpid/messaging/Message.cpp b/cpp/src/qpid/messaging/Message.cpp
new file mode 100644
index 0000000000..deb40b6aa3
--- /dev/null
+++ b/cpp/src/qpid/messaging/Message.cpp
@@ -0,0 +1,58 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/MessageImpl.h"
+
+namespace qpid {
+namespace messaging {
+
+Message::Message(const std::string& bytes) : impl(new MessageImpl(bytes)) {}
+Message::Message(const char* bytes, size_t count) : impl(new MessageImpl(bytes, count)) {}
+
+Message::Message(const Message& m) : impl(new MessageImpl(*m.impl)) {}
+Message::~Message() { delete impl; }
+
+Message& Message::operator=(const Message& m) { *impl = *m.impl; return *this; }
+
+void Message::setReplyTo(const Address& d) { impl->setReplyTo(d); }
+const Address& Message::getReplyTo() const { return impl->getReplyTo(); }
+
+void Message::setSubject(const std::string& s) { impl->setSubject(s); }
+const std::string& Message::getSubject() const { return impl->getSubject(); }
+
+void Message::setContentType(const std::string& s) { impl->setContentType(s); }
+const std::string& Message::getContentType() const { return impl->getContentType(); }
+
+const VariantMap& Message::getHeaders() const { return impl->getHeaders(); }
+VariantMap& Message::getHeaders() { return impl->getHeaders(); }
+
+void Message::setContent(const std::string& c) { impl->setBytes(c); }
+void Message::setContent(const char* chars, size_t count) { impl->setBytes(chars, count); }
+const std::string& Message::getContent() const { return impl->getBytes(); }
+std::string& Message::getContent() { return impl->getBytes(); }
+
+void Message::getContent(std::pair<const char*, size_t>& content) const
+{
+ content.first = impl->getBytes().data();
+ content.second = impl->getBytes().size();
+}
+
+}} // namespace qpid::messaging
diff --git a/cpp/src/qpid/messaging/MessageImpl.cpp b/cpp/src/qpid/messaging/MessageImpl.cpp
new file mode 100644
index 0000000000..e17fccd64f
--- /dev/null
+++ b/cpp/src/qpid/messaging/MessageImpl.cpp
@@ -0,0 +1,64 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "MessageImpl.h"
+#include "qpid/messaging/Message.h"
+
+namespace qpid {
+namespace messaging {
+
+namespace {
+const std::string EMPTY_STRING = "";
+}
+
+MessageImpl::MessageImpl(const std::string& c) : bytes(c), internalId(0) {}
+MessageImpl::MessageImpl(const char* chars, size_t count) : bytes(chars, count), internalId(0) {}
+
+void MessageImpl::setReplyTo(const Address& d) { replyTo = d; }
+const Address& MessageImpl::getReplyTo() const { return replyTo; }
+
+void MessageImpl::setSubject(const std::string& s) { subject = s; }
+const std::string& MessageImpl::getSubject() const { return subject; }
+
+void MessageImpl::setContentType(const std::string& s) { contentType = s; }
+const std::string& MessageImpl::getContentType() const { return contentType; }
+
+const VariantMap& MessageImpl::getHeaders() const { return headers; }
+VariantMap& MessageImpl::getHeaders() { return headers; }
+
+//should these methods be on MessageContent?
+void MessageImpl::setBytes(const std::string& c) { bytes = c; }
+void MessageImpl::setBytes(const char* chars, size_t count) { bytes.assign(chars, count); }
+const std::string& MessageImpl::getBytes() const { return bytes; }
+std::string& MessageImpl::getBytes() { return bytes; }
+
+void MessageImpl::setInternalId(qpid::framing::SequenceNumber i) { internalId = i; }
+qpid::framing::SequenceNumber MessageImpl::getInternalId() { return internalId; }
+
+MessageImpl& MessageImplAccess::get(Message& msg)
+{
+ return *msg.impl;
+}
+const MessageImpl& MessageImplAccess::get(const Message& msg)
+{
+ return *msg.impl;
+}
+
+}} // namespace qpid::messaging
diff --git a/cpp/src/qpid/messaging/MessageImpl.h b/cpp/src/qpid/messaging/MessageImpl.h
new file mode 100644
index 0000000000..4939cdc5cc
--- /dev/null
+++ b/cpp/src/qpid/messaging/MessageImpl.h
@@ -0,0 +1,82 @@
+#ifndef QPID_MESSAGING_MESSAGEIMPL_H
+#define QPID_MESSAGING_MESSAGEIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/Address.h"
+#include "qpid/messaging/Variant.h"
+#include "qpid/framing/SequenceNumber.h"
+
+namespace qpid {
+namespace messaging {
+
+struct MessageImpl
+{
+ Address replyTo;
+ std::string subject;
+ std::string contentType;
+ Variant::Map headers;
+
+ std::string bytes;
+
+ qpid::framing::SequenceNumber internalId;
+
+ MessageImpl(const std::string& c);
+ MessageImpl(const char* chars, size_t count);
+
+ void setReplyTo(const Address& d);
+ const Address& getReplyTo() const;
+
+ void setSubject(const std::string& s);
+ const std::string& getSubject() const;
+
+ void setContentType(const std::string& s);
+ const std::string& getContentType() const;
+
+ const Variant::Map& getHeaders() const;
+ Variant::Map& getHeaders();
+
+ void setBytes(const std::string& bytes);
+ void setBytes(const char* chars, size_t count);
+ const std::string& getBytes() const;
+ std::string& getBytes();
+
+ void setInternalId(qpid::framing::SequenceNumber id);
+ qpid::framing::SequenceNumber getInternalId();
+
+};
+
+class Message;
+
+/**
+ * Provides access to the internal MessageImpl for a message which is
+ * useful when accessing any message state not exposed directly
+ * through the public API.
+ */
+struct MessageImplAccess
+{
+ static MessageImpl& get(Message&);
+ static const MessageImpl& get(const Message&);
+};
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_MESSAGEIMPL_H*/
diff --git a/cpp/src/qpid/messaging/Receiver.cpp b/cpp/src/qpid/messaging/Receiver.cpp
new file mode 100644
index 0000000000..bf9c056db8
--- /dev/null
+++ b/cpp/src/qpid/messaging/Receiver.cpp
@@ -0,0 +1,53 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/Receiver.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/ReceiverImpl.h"
+#include "qpid/messaging/Session.h"
+#include "qpid/client/PrivateImplRef.h"
+
+namespace qpid {
+namespace client {
+
+typedef PrivateImplRef<qpid::messaging::Receiver> PI;
+
+}
+
+namespace messaging {
+
+using qpid::client::PI;
+
+Receiver::Receiver(ReceiverImpl* impl) { PI::ctor(*this, impl); }
+Receiver::Receiver(const Receiver& s) : qpid::client::Handle<ReceiverImpl>() { PI::copy(*this, s); }
+Receiver::~Receiver() { PI::dtor(*this); }
+Receiver& Receiver::operator=(const Receiver& s) { return PI::assign(*this, s); }
+bool Receiver::get(Message& message, qpid::sys::Duration timeout) { return impl->get(message, timeout); }
+Message Receiver::get(qpid::sys::Duration timeout) { return impl->get(timeout); }
+bool Receiver::fetch(Message& message, qpid::sys::Duration timeout) { return impl->fetch(message, timeout); }
+Message Receiver::fetch(qpid::sys::Duration timeout) { return impl->fetch(timeout); }
+void Receiver::setCapacity(uint32_t c) { impl->setCapacity(c); }
+uint32_t Receiver::getCapacity() { return impl->getCapacity(); }
+uint32_t Receiver::available() { return impl->available(); }
+uint32_t Receiver::pendingAck() { return impl->pendingAck(); }
+void Receiver::cancel() { impl->cancel(); }
+const std::string& Receiver::getName() const { return impl->getName(); }
+Session Receiver::getSession() const { return impl->getSession(); }
+}} // namespace qpid::messaging
diff --git a/cpp/src/qpid/messaging/ReceiverImpl.h b/cpp/src/qpid/messaging/ReceiverImpl.h
new file mode 100644
index 0000000000..447a505518
--- /dev/null
+++ b/cpp/src/qpid/messaging/ReceiverImpl.h
@@ -0,0 +1,55 @@
+#ifndef QPID_MESSAGING_RECEIVERIMPL_H
+#define QPID_MESSAGING_RECEIVERIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/RefCounted.h"
+#include "qpid/sys/Time.h"
+
+namespace qpid {
+namespace client {
+}
+
+namespace messaging {
+
+class Message;
+class MessageListener;
+class Session;
+
+class ReceiverImpl : public virtual qpid::RefCounted
+{
+ public:
+ virtual ~ReceiverImpl() {}
+ virtual bool get(Message& message, qpid::sys::Duration timeout) = 0;
+ virtual Message get(qpid::sys::Duration timeout) = 0;
+ virtual bool fetch(Message& message, qpid::sys::Duration timeout) = 0;
+ virtual Message fetch(qpid::sys::Duration timeout) = 0;
+ virtual void setCapacity(uint32_t) = 0;
+ virtual uint32_t getCapacity() = 0;
+ virtual uint32_t available() = 0;
+ virtual uint32_t pendingAck() = 0;
+ virtual void cancel() = 0;
+ virtual const std::string& getName() const = 0;
+ virtual Session getSession() const = 0;
+};
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_RECEIVERIMPL_H*/
diff --git a/cpp/src/qpid/messaging/Sender.cpp b/cpp/src/qpid/messaging/Sender.cpp
new file mode 100644
index 0000000000..f2303f4126
--- /dev/null
+++ b/cpp/src/qpid/messaging/Sender.cpp
@@ -0,0 +1,50 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Sender.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/SenderImpl.h"
+#include "qpid/messaging/Session.h"
+#include "qpid/client/PrivateImplRef.h"
+
+namespace qpid {
+namespace client {
+
+typedef PrivateImplRef<qpid::messaging::Sender> PI;
+
+}
+
+namespace messaging {
+
+using qpid::client::PI;
+
+Sender::Sender(SenderImpl* impl) { PI::ctor(*this, impl); }
+Sender::Sender(const Sender& s) : qpid::client::Handle<SenderImpl>() { PI::copy(*this, s); }
+Sender::~Sender() { PI::dtor(*this); }
+Sender& Sender::operator=(const Sender& s) { return PI::assign(*this, s); }
+void Sender::send(const Message& message) { impl->send(message); }
+void Sender::cancel() { impl->cancel(); }
+void Sender::setCapacity(uint32_t c) { impl->setCapacity(c); }
+uint32_t Sender::getCapacity() { return impl->getCapacity(); }
+uint32_t Sender::pending() { return impl->pending(); }
+const std::string& Sender::getName() const { return impl->getName(); }
+Session Sender::getSession() const { return impl->getSession(); }
+
+}} // namespace qpid::messaging
diff --git a/cpp/src/qpid/messaging/SenderImpl.h b/cpp/src/qpid/messaging/SenderImpl.h
new file mode 100644
index 0000000000..5f30417f6a
--- /dev/null
+++ b/cpp/src/qpid/messaging/SenderImpl.h
@@ -0,0 +1,50 @@
+#ifndef QPID_MESSAGING_SENDERIMPL_H
+#define QPID_MESSAGING_SENDERIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/RefCounted.h"
+
+namespace qpid {
+namespace client {
+}
+
+namespace messaging {
+
+class Message;
+class Session;
+
+class SenderImpl : public virtual qpid::RefCounted
+{
+ public:
+ virtual ~SenderImpl() {}
+ virtual void send(const Message& message) = 0;
+ virtual void cancel() = 0;
+ virtual void setCapacity(uint32_t) = 0;
+ virtual uint32_t getCapacity() = 0;
+ virtual uint32_t pending() = 0;
+ virtual const std::string& getName() const = 0;
+ virtual Session getSession() const = 0;
+ private:
+};
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_SENDERIMPL_H*/
diff --git a/cpp/src/qpid/messaging/Session.cpp b/cpp/src/qpid/messaging/Session.cpp
new file mode 100644
index 0000000000..99896caad4
--- /dev/null
+++ b/cpp/src/qpid/messaging/Session.cpp
@@ -0,0 +1,109 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/Session.h"
+#include "qpid/messaging/Address.h"
+#include "qpid/messaging/Connection.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/Sender.h"
+#include "qpid/messaging/Receiver.h"
+#include "qpid/messaging/SessionImpl.h"
+#include "qpid/client/PrivateImplRef.h"
+
+namespace qpid {
+namespace client {
+
+typedef PrivateImplRef<qpid::messaging::Session> PI;
+
+}
+
+namespace messaging {
+
+using qpid::client::PI;
+
+Session::Session(SessionImpl* impl) { PI::ctor(*this, impl); }
+Session::Session(const Session& s) : qpid::client::Handle<SessionImpl>() { PI::copy(*this, s); }
+Session::~Session() { PI::dtor(*this); }
+Session& Session::operator=(const Session& s) { return PI::assign(*this, s); }
+void Session::commit() { impl->commit(); }
+void Session::rollback() { impl->rollback(); }
+void Session::acknowledge() { impl->acknowledge(); }
+void Session::reject(Message& m) { impl->reject(m); }
+void Session::close() { impl->close(); }
+
+Sender Session::createSender(const Address& address)
+{
+ return impl->createSender(address);
+}
+Receiver Session::createReceiver(const Address& address)
+{
+ return impl->createReceiver(address);
+}
+
+Sender Session::createSender(const std::string& address)
+{
+ return impl->createSender(Address(address));
+}
+Receiver Session::createReceiver(const std::string& address)
+{
+ return impl->createReceiver(Address(address));
+}
+
+void Session::sync()
+{
+ impl->sync();
+}
+
+void Session::flush()
+{
+ impl->flush();
+}
+
+bool Session::nextReceiver(Receiver& receiver, qpid::sys::Duration timeout)
+{
+ return impl->nextReceiver(receiver, timeout);
+}
+
+
+Receiver Session::nextReceiver(qpid::sys::Duration timeout)
+{
+ return impl->nextReceiver(timeout);
+}
+
+uint32_t Session::available() { return impl->available(); }
+uint32_t Session::pendingAck() { return impl->pendingAck(); }
+
+Sender Session::getSender(const std::string& name) const
+{
+ return impl->getSender(name);
+}
+Receiver Session::getReceiver(const std::string& name) const
+{
+ return impl->getReceiver(name);
+}
+
+Connection Session::getConnection() const
+{
+ return impl->getConnection();
+}
+
+KeyError::KeyError(const std::string& msg) : Exception(msg) {}
+
+}} // namespace qpid::messaging
diff --git a/cpp/src/qpid/messaging/SessionImpl.h b/cpp/src/qpid/messaging/SessionImpl.h
new file mode 100644
index 0000000000..164a6f6bc9
--- /dev/null
+++ b/cpp/src/qpid/messaging/SessionImpl.h
@@ -0,0 +1,64 @@
+#ifndef QPID_MESSAGING_SESSIONIMPL_H
+#define QPID_MESSAGING_SESSIONIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/RefCounted.h"
+#include <string>
+#include "qpid/sys/Time.h"
+
+namespace qpid {
+namespace client {
+}
+
+namespace messaging {
+
+class Address;
+class Connection;
+class Message;
+class Sender;
+class Receiver;
+
+class SessionImpl : public virtual qpid::RefCounted
+{
+ public:
+ virtual ~SessionImpl() {}
+ virtual void commit() = 0;
+ virtual void rollback() = 0;
+ virtual void acknowledge() = 0;
+ virtual void reject(Message&) = 0;
+ virtual void close() = 0;
+ virtual void sync() = 0;
+ virtual void flush() = 0;
+ virtual Sender createSender(const Address& address) = 0;
+ virtual Receiver createReceiver(const Address& address) = 0;
+ virtual bool nextReceiver(Receiver& receiver, qpid::sys::Duration timeout) = 0;
+ virtual Receiver nextReceiver(qpid::sys::Duration timeout) = 0;
+ virtual uint32_t available() = 0;
+ virtual uint32_t pendingAck() = 0;
+ virtual Sender getSender(const std::string& name) const = 0;
+ virtual Receiver getReceiver(const std::string& name) const = 0;
+ virtual Connection getConnection() const = 0;
+ private:
+};
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_SESSIONIMPL_H*/
diff --git a/cpp/src/qpid/messaging/Variant.cpp b/cpp/src/qpid/messaging/Variant.cpp
new file mode 100644
index 0000000000..9c2f92f47a
--- /dev/null
+++ b/cpp/src/qpid/messaging/Variant.cpp
@@ -0,0 +1,659 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Variant.h"
+#include <boost/format.hpp>
+#include <boost/lexical_cast.hpp>
+#include <algorithm>
+#include <sstream>
+
+namespace qpid {
+namespace messaging {
+
+InvalidConversion::InvalidConversion(const std::string& msg) : Exception(msg) {}
+
+
+namespace {
+std::string EMPTY;
+}
+
+class VariantImpl
+{
+ public:
+ VariantImpl();
+ VariantImpl(bool);
+ VariantImpl(uint8_t);
+ VariantImpl(uint16_t);
+ VariantImpl(uint32_t);
+ VariantImpl(uint64_t);
+ VariantImpl(int8_t);
+ VariantImpl(int16_t);
+ VariantImpl(int32_t);
+ VariantImpl(int64_t);
+ VariantImpl(float);
+ VariantImpl(double);
+ VariantImpl(const std::string&);
+ VariantImpl(const Variant::Map&);
+ VariantImpl(const Variant::List&);
+ ~VariantImpl();
+
+ VariantType getType() const;
+
+ bool asBool() const;
+ uint8_t asUint8() const;
+ uint16_t asUint16() const;
+ uint32_t asUint32() const;
+ uint64_t asUint64() const;
+ int8_t asInt8() const;
+ int16_t asInt16() const;
+ int32_t asInt32() const;
+ int64_t asInt64() const;
+ float asFloat() const;
+ double asDouble() const;
+ std::string asString() const;
+
+ const Variant::Map& asMap() const;
+ Variant::Map& asMap();
+ const Variant::List& asList() const;
+ Variant::List& asList();
+
+ const std::string& getString() const;
+ std::string& getString();
+
+ void setEncoding(const std::string&);
+ const std::string& getEncoding() const;
+
+ bool isEqualTo(VariantImpl&) const;
+ bool isEquivalentTo(VariantImpl&) const;
+
+ static VariantImpl* create(const Variant&);
+ private:
+ const VariantType type;
+ union {
+ bool b;
+ uint8_t ui8;
+ uint16_t ui16;
+ uint32_t ui32;
+ uint64_t ui64;
+ int8_t i8;
+ int16_t i16;
+ int32_t i32;
+ int64_t i64;
+ float f;
+ double d;
+ void* v;//variable width data
+ } value;
+ std::string encoding;//optional encoding for variable length data
+
+ std::string getTypeName(VariantType type) const;
+ template<class T> T convertFromString() const
+ {
+ std::string* s = reinterpret_cast<std::string*>(value.v);
+ try {
+ return boost::lexical_cast<T>(*s);
+ } catch(const boost::bad_lexical_cast&) {
+ throw InvalidConversion(QPID_MSG("Cannot convert " << *s));
+ }
+ }
+};
+
+
+VariantImpl::VariantImpl() : type(VAR_VOID) { value.i64 = 0; }
+VariantImpl::VariantImpl(bool b) : type(VAR_BOOL) { value.b = b; }
+VariantImpl::VariantImpl(uint8_t i) : type(VAR_UINT8) { value.ui8 = i; }
+VariantImpl::VariantImpl(uint16_t i) : type(VAR_UINT16) { value.ui16 = i; }
+VariantImpl::VariantImpl(uint32_t i) : type(VAR_UINT32) { value.ui32 = i; }
+VariantImpl::VariantImpl(uint64_t i) : type(VAR_UINT64) { value.ui64 = i; }
+VariantImpl::VariantImpl(int8_t i) : type(VAR_INT8) { value.i8 = i; }
+VariantImpl::VariantImpl(int16_t i) : type(VAR_INT16) { value.i16 = i; }
+VariantImpl::VariantImpl(int32_t i) : type(VAR_INT32) { value.i32 = i; }
+VariantImpl::VariantImpl(int64_t i) : type(VAR_INT64) { value.i64 = i; }
+VariantImpl::VariantImpl(float f) : type(VAR_FLOAT) { value.f = f; }
+VariantImpl::VariantImpl(double d) : type(VAR_DOUBLE) { value.d = d; }
+VariantImpl::VariantImpl(const std::string& s) : type(VAR_STRING) { value.v = new std::string(s); }
+VariantImpl::VariantImpl(const Variant::Map& m) : type(VAR_MAP) { value.v = new Variant::Map(m); }
+VariantImpl::VariantImpl(const Variant::List& l) : type(VAR_LIST) { value.v = new Variant::List(l); }
+
+VariantImpl::~VariantImpl() {
+ switch (type) {
+ case VAR_STRING:
+ delete reinterpret_cast<std::string*>(value.v);
+ break;
+ case VAR_MAP:
+ delete reinterpret_cast<Variant::Map*>(value.v);
+ break;
+ case VAR_LIST:
+ delete reinterpret_cast<Variant::List*>(value.v);
+ break;
+ default:
+ break;
+ }
+}
+
+VariantType VariantImpl::getType() const { return type; }
+
+namespace {
+
+bool same_char(char a, char b)
+{
+ return toupper(a) == toupper(b);
+}
+
+bool caseInsensitiveMatch(const std::string& a, const std::string& b)
+{
+ return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin(), &same_char);
+}
+
+const std::string TRUE("True");
+const std::string FALSE("False");
+
+bool toBool(const std::string& s)
+{
+ if (caseInsensitiveMatch(s, TRUE)) return true;
+ if (caseInsensitiveMatch(s, FALSE)) return false;
+ try { return boost::lexical_cast<int>(s); } catch(const boost::bad_lexical_cast&) {}
+ throw InvalidConversion(QPID_MSG("Cannot convert " << s << " to bool"));
+}
+
+template <class T> std::string toString(const T& t)
+{
+ std::stringstream out;
+ out << t;
+ return out.str();
+}
+
+template <class T> bool equal(const T& a, const T& b)
+{
+ return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
+}
+
+}
+
+bool VariantImpl::asBool() const
+{
+ switch(type) {
+ case VAR_VOID: return false;
+ case VAR_BOOL: return value.b;
+ case VAR_UINT8: return value.ui8;
+ case VAR_UINT16: return value.ui16;
+ case VAR_UINT32: return value.ui32;
+ case VAR_UINT64: return value.ui64;
+ case VAR_INT8: return value.i8;
+ case VAR_INT16: return value.i16;
+ case VAR_INT32: return value.i32;
+ case VAR_INT64: return value.i64;
+ case VAR_STRING: return toBool(*reinterpret_cast<std::string*>(value.v));
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_BOOL)));
+ }
+}
+uint8_t VariantImpl::asUint8() const
+{
+ switch(type) {
+ case VAR_UINT8: return value.ui8;
+ case VAR_STRING: return convertFromString<uint8_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_UINT8)));
+ }
+}
+uint16_t VariantImpl::asUint16() const
+{
+ switch(type) {
+ case VAR_UINT8: return value.ui8;
+ case VAR_UINT16: return value.ui16;
+ case VAR_STRING: return convertFromString<uint16_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_UINT16)));
+ }
+}
+uint32_t VariantImpl::asUint32() const
+{
+ switch(type) {
+ case VAR_UINT8: return value.ui8;
+ case VAR_UINT16: return value.ui16;
+ case VAR_UINT32: return value.ui32;
+ case VAR_STRING: return convertFromString<uint32_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_UINT32)));
+ }
+}
+uint64_t VariantImpl::asUint64() const
+{
+ switch(type) {
+ case VAR_UINT8: return value.ui8;
+ case VAR_UINT16: return value.ui16;
+ case VAR_UINT32: return value.ui32;
+ case VAR_UINT64: return value.ui64;
+ case VAR_STRING: return convertFromString<uint64_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_UINT64)));
+ }
+}
+int8_t VariantImpl::asInt8() const
+{
+ switch(type) {
+ case VAR_INT8: return value.i8;
+ case VAR_STRING: return convertFromString<int8_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_INT8)));
+ }
+}
+int16_t VariantImpl::asInt16() const
+{
+ switch(type) {
+ case VAR_INT8: return value.i8;
+ case VAR_INT16: return value.i16;
+ case VAR_STRING: return convertFromString<int16_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_INT16)));
+ }
+}
+int32_t VariantImpl::asInt32() const
+{
+ switch(type) {
+ case VAR_INT8: return value.i8;
+ case VAR_INT16: return value.i16;
+ case VAR_INT32: return value.i32;
+ case VAR_STRING: return convertFromString<int32_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_INT32)));
+ }
+}
+int64_t VariantImpl::asInt64() const
+{
+ switch(type) {
+ case VAR_INT8: return value.i8;
+ case VAR_INT16: return value.i16;
+ case VAR_INT32: return value.i32;
+ case VAR_INT64: return value.i64;
+ case VAR_STRING: return convertFromString<int64_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_INT64)));
+ }
+}
+float VariantImpl::asFloat() const
+{
+ switch(type) {
+ case VAR_FLOAT: return value.f;
+ case VAR_STRING: return convertFromString<float>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_FLOAT)));
+ }
+}
+double VariantImpl::asDouble() const
+{
+ switch(type) {
+ case VAR_FLOAT: return value.f;
+ case VAR_DOUBLE: return value.d;
+ case VAR_STRING: return convertFromString<double>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_DOUBLE)));
+ }
+}
+std::string VariantImpl::asString() const
+{
+ switch(type) {
+ case VAR_VOID: return EMPTY;
+ case VAR_BOOL: return value.b ? TRUE : FALSE;
+ case VAR_UINT8: return boost::lexical_cast<std::string>((int) value.ui8);
+ case VAR_UINT16: return boost::lexical_cast<std::string>(value.ui16);
+ case VAR_UINT32: return boost::lexical_cast<std::string>(value.ui32);
+ case VAR_UINT64: return boost::lexical_cast<std::string>(value.ui64);
+ case VAR_INT8: return boost::lexical_cast<std::string>((int) value.i8);
+ case VAR_INT16: return boost::lexical_cast<std::string>(value.i16);
+ case VAR_INT32: return boost::lexical_cast<std::string>(value.i32);
+ case VAR_INT64: return boost::lexical_cast<std::string>(value.i64);
+ case VAR_DOUBLE: return boost::lexical_cast<std::string>(value.d);
+ case VAR_FLOAT: return boost::lexical_cast<std::string>(value.f);
+ case VAR_STRING: return *reinterpret_cast<std::string*>(value.v);
+ case VAR_LIST: return toString(asList());
+ case VAR_MAP: return toString(asMap());
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_STRING)));
+ }
+}
+
+bool VariantImpl::isEqualTo(VariantImpl& other) const
+{
+ if (type == other.type) {
+ switch(type) {
+ case VAR_VOID: return true;
+ case VAR_BOOL: return value.b == other.value.b;
+ case VAR_UINT8: return value.ui8 == other.value.ui8;
+ case VAR_UINT16: return value.ui16 == other.value.ui16;
+ case VAR_UINT32: return value.ui32 == other.value.ui32;
+ case VAR_UINT64: return value.ui64 == other.value.ui64;
+ case VAR_INT8: return value.i8 == other.value.i8;
+ case VAR_INT16: return value.i16 == other.value.i16;
+ case VAR_INT32: return value.i32 == other.value.i32;
+ case VAR_INT64: return value.i64 == other.value.i64;
+ case VAR_DOUBLE: return value.d == other.value.d;
+ case VAR_FLOAT: return value.f == other.value.f;
+ case VAR_STRING: return *reinterpret_cast<std::string*>(value.v)
+ == *reinterpret_cast<std::string*>(other.value.v);
+ case VAR_LIST: return equal(asList(), other.asList());
+ case VAR_MAP: return equal(asMap(), other.asMap());
+ }
+ }
+ return false;
+}
+
+const Variant::Map& VariantImpl::asMap() const
+{
+ switch(type) {
+ case VAR_MAP: return *reinterpret_cast<Variant::Map*>(value.v);
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_MAP)));
+ }
+}
+
+Variant::Map& VariantImpl::asMap()
+{
+ switch(type) {
+ case VAR_MAP: return *reinterpret_cast<Variant::Map*>(value.v);
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_MAP)));
+ }
+}
+
+const Variant::List& VariantImpl::asList() const
+{
+ switch(type) {
+ case VAR_LIST: return *reinterpret_cast<Variant::List*>(value.v);
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_LIST)));
+ }
+}
+
+Variant::List& VariantImpl::asList()
+{
+ switch(type) {
+ case VAR_LIST: return *reinterpret_cast<Variant::List*>(value.v);
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_LIST)));
+ }
+}
+
+std::string& VariantImpl::getString()
+{
+ switch(type) {
+ case VAR_STRING: return *reinterpret_cast<std::string*>(value.v);
+ default: throw InvalidConversion(QPID_MSG("Variant is not a string; use asString() if conversion is required."));
+ }
+}
+
+const std::string& VariantImpl::getString() const
+{
+ switch(type) {
+ case VAR_STRING: return *reinterpret_cast<std::string*>(value.v);
+ default: throw InvalidConversion(QPID_MSG("Variant is not a string; use asString() if conversion is required."));
+ }
+}
+
+void VariantImpl::setEncoding(const std::string& s) { encoding = s; }
+const std::string& VariantImpl::getEncoding() const { return encoding; }
+
+std::string VariantImpl::getTypeName(VariantType type) const
+{
+ switch (type) {
+ case VAR_VOID: return "void";
+ case VAR_BOOL: return "bool";
+ case VAR_UINT8: return "uint8";
+ case VAR_UINT16: return "uint16";
+ case VAR_UINT32: return "uint32";
+ case VAR_UINT64: return "uint64";
+ case VAR_INT8: return "int8";
+ case VAR_INT16: return "int16";
+ case VAR_INT32: return "int32";
+ case VAR_INT64: return "int64";
+ case VAR_FLOAT: return "float";
+ case VAR_DOUBLE: return "double";
+ case VAR_STRING: return "string";
+ case VAR_MAP: return "map";
+ case VAR_LIST: return "list";
+ }
+ return "<unknown>";//should never happen
+}
+
+VariantImpl* VariantImpl::create(const Variant& v)
+{
+ switch (v.getType()) {
+ case VAR_BOOL: return new VariantImpl(v.asBool());
+ case VAR_UINT8: return new VariantImpl(v.asUint8());
+ case VAR_UINT16: return new VariantImpl(v.asUint16());
+ case VAR_UINT32: return new VariantImpl(v.asUint32());
+ case VAR_UINT64: return new VariantImpl(v.asUint64());
+ case VAR_INT8: return new VariantImpl(v.asInt8());
+ case VAR_INT16: return new VariantImpl(v.asInt16());
+ case VAR_INT32: return new VariantImpl(v.asInt32());
+ case VAR_INT64: return new VariantImpl(v.asInt64());
+ case VAR_FLOAT: return new VariantImpl(v.asFloat());
+ case VAR_DOUBLE: return new VariantImpl(v.asDouble());
+ case VAR_STRING: return new VariantImpl(v.asString());
+ case VAR_MAP: return new VariantImpl(v.asMap());
+ case VAR_LIST: return new VariantImpl(v.asList());
+ default: return new VariantImpl();
+ }
+}
+
+Variant::Variant() : impl(new VariantImpl()) {}
+Variant::Variant(bool b) : impl(new VariantImpl(b)) {}
+Variant::Variant(uint8_t i) : impl(new VariantImpl(i)) {}
+Variant::Variant(uint16_t i) : impl(new VariantImpl(i)) {}
+Variant::Variant(uint32_t i) : impl(new VariantImpl(i)) {}
+Variant::Variant(uint64_t i) : impl(new VariantImpl(i)) {}
+Variant::Variant(int8_t i) : impl(new VariantImpl(i)) {}
+Variant::Variant(int16_t i) : impl(new VariantImpl(i)) {}
+Variant::Variant(int32_t i) : impl(new VariantImpl(i)) {}
+Variant::Variant(int64_t i) : impl(new VariantImpl(i)) {}
+Variant::Variant(float f) : impl(new VariantImpl(f)) {}
+Variant::Variant(double d) : impl(new VariantImpl(d)) {}
+Variant::Variant(const std::string& s) : impl(new VariantImpl(s)) {}
+Variant::Variant(const char* s) : impl(new VariantImpl(std::string(s))) {}
+Variant::Variant(const Map& m) : impl(new VariantImpl(m)) {}
+Variant::Variant(const List& l) : impl(new VariantImpl(l)) {}
+Variant::Variant(const Variant& v) : impl(VariantImpl::create(v)) {}
+
+Variant::~Variant() { if (impl) delete impl; }
+
+void Variant::reset()
+{
+ if (impl) delete impl;
+ impl = new VariantImpl();
+}
+
+
+Variant& Variant::operator=(bool b)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(b);
+ return *this;
+}
+
+Variant& Variant::operator=(uint8_t i)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(i);
+ return *this;
+}
+Variant& Variant::operator=(uint16_t i)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(i);
+ return *this;
+}
+Variant& Variant::operator=(uint32_t i)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(i);
+ return *this;
+}
+Variant& Variant::operator=(uint64_t i)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(i);
+ return *this;
+}
+
+Variant& Variant::operator=(int8_t i)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(i);
+ return *this;
+}
+Variant& Variant::operator=(int16_t i)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(i);
+ return *this;
+}
+Variant& Variant::operator=(int32_t i)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(i);
+ return *this;
+}
+Variant& Variant::operator=(int64_t i)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(i);
+ return *this;
+}
+
+Variant& Variant::operator=(float f)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(f);
+ return *this;
+}
+Variant& Variant::operator=(double d)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(d);
+ return *this;
+}
+
+Variant& Variant::operator=(const std::string& s)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(s);
+ return *this;
+}
+
+Variant& Variant::operator=(const char* s)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(std::string(s));
+ return *this;
+}
+
+Variant& Variant::operator=(const Map& m)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(m);
+ return *this;
+}
+
+Variant& Variant::operator=(const List& l)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(l);
+ return *this;
+}
+
+Variant& Variant::operator=(const Variant& v)
+{
+ if (impl) delete impl;
+ impl = VariantImpl::create(v);
+ return *this;
+}
+
+VariantType Variant::getType() const { return impl->getType(); }
+bool Variant::isVoid() const { return impl->getType() == VAR_VOID; }
+bool Variant::asBool() const { return impl->asBool(); }
+uint8_t Variant::asUint8() const { return impl->asUint8(); }
+uint16_t Variant::asUint16() const { return impl->asUint16(); }
+uint32_t Variant::asUint32() const { return impl->asUint32(); }
+uint64_t Variant::asUint64() const { return impl->asUint64(); }
+int8_t Variant::asInt8() const { return impl->asInt8(); }
+int16_t Variant::asInt16() const { return impl->asInt16(); }
+int32_t Variant::asInt32() const { return impl->asInt32(); }
+int64_t Variant::asInt64() const { return impl->asInt64(); }
+float Variant::asFloat() const { return impl->asFloat(); }
+double Variant::asDouble() const { return impl->asDouble(); }
+std::string Variant::asString() const { return impl->asString(); }
+const Variant::Map& Variant::asMap() const { return impl->asMap(); }
+Variant::Map& Variant::asMap() { return impl->asMap(); }
+const Variant::List& Variant::asList() const { return impl->asList(); }
+Variant::List& Variant::asList() { return impl->asList(); }
+const std::string& Variant::getString() const { return impl->getString(); }
+std::string& Variant::getString() { return impl->getString(); }
+void Variant::setEncoding(const std::string& s) { impl->setEncoding(s); }
+const std::string& Variant::getEncoding() const { return impl->getEncoding(); }
+
+Variant::operator bool() const { return asBool(); }
+Variant::operator uint8_t() const { return asUint8(); }
+Variant::operator uint16_t() const { return asUint16(); }
+Variant::operator uint32_t() const { return asUint32(); }
+Variant::operator uint64_t() const { return asUint64(); }
+Variant::operator int8_t() const { return asInt8(); }
+Variant::operator int16_t() const { return asInt16(); }
+Variant::operator int32_t() const { return asInt32(); }
+Variant::operator int64_t() const { return asInt64(); }
+Variant::operator float() const { return asFloat(); }
+Variant::operator double() const { return asDouble(); }
+Variant::operator const char*() const { return asString().c_str(); }
+
+std::ostream& operator<<(std::ostream& out, const Variant::Map& map)
+{
+ out << "{";
+ for (Variant::Map::const_iterator i = map.begin(); i != map.end(); ++i) {
+ if (i != map.begin()) out << ", ";
+ out << i->first << ":" << i->second;
+ }
+ out << "}";
+ return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const Variant::List& list)
+{
+ out << "[";
+ for (Variant::List::const_iterator i = list.begin(); i != list.end(); ++i) {
+ if (i != list.begin()) out << ", ";
+ out << *i;
+ }
+ out << "]";
+ return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const Variant& value)
+{
+ switch (value.getType()) {
+ case VAR_MAP:
+ out << value.asMap();
+ break;
+ case VAR_LIST:
+ out << value.asList();
+ break;
+ case VAR_VOID:
+ out << "<void>";
+ break;
+ default:
+ out << value.asString();
+ break;
+ }
+ return out;
+}
+
+bool operator==(const Variant& a, const Variant& b)
+{
+ return a.isEqualTo(b);
+}
+
+bool Variant::isEqualTo(const Variant& other) const
+{
+ return impl->isEqualTo(*other.impl);
+}
+
+}} // namespace qpid::messaging
diff --git a/cpp/src/qpid/replication/ReplicatingEventListener.cpp b/cpp/src/qpid/replication/ReplicatingEventListener.cpp
new file mode 100644
index 0000000000..b7d52372f4
--- /dev/null
+++ b/cpp/src/qpid/replication/ReplicatingEventListener.cpp
@@ -0,0 +1,201 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/replication/ReplicatingEventListener.h"
+#include "qpid/replication/constants.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/broker/DeliverableMessage.h"
+#include "qpid/broker/QueueEvents.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/FrameHandler.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/log/Statement.h"
+
+namespace qpid {
+namespace replication {
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::replication::constants;
+
+void ReplicatingEventListener::handle(QueueEvents::Event event)
+{
+ switch (event.type) {
+ case QueueEvents::ENQUEUE:
+ deliverEnqueueMessage(event.msg);
+ QPID_LOG(debug, "Queuing 'enqueue' event on " << event.msg.queue->getName() << " for replication");
+ break;
+ case QueueEvents::DEQUEUE:
+ deliverDequeueMessage(event.msg);
+ QPID_LOG(debug, "Queuing 'dequeue' event from " << event.msg.queue->getName() << " for replication, (from position "
+ << event.msg.position << ")");
+ break;
+ }
+}
+
+namespace {
+const std::string EMPTY;
+}
+
+void ReplicatingEventListener::deliverDequeueMessage(const QueuedMessage& dequeued)
+{
+ FieldTable headers;
+ headers.setString(REPLICATION_TARGET_QUEUE, dequeued.queue->getName());
+ headers.setInt(REPLICATION_EVENT_TYPE, DEQUEUE);
+ headers.setInt(DEQUEUED_MESSAGE_POSITION, dequeued.position);
+ boost::intrusive_ptr<Message> msg(createMessage(headers));
+ DeliveryProperties* props = msg->getFrames().getHeaders()->get<DeliveryProperties>(true);
+ props->setRoutingKey(dequeued.queue->getName());
+ route(msg);
+}
+
+void ReplicatingEventListener::deliverEnqueueMessage(const QueuedMessage& enqueued)
+{
+ boost::intrusive_ptr<Message> msg(cloneMessage(*(enqueued.queue), enqueued.payload));
+ FieldTable& headers = msg->getProperties<MessageProperties>()->getApplicationHeaders();
+ headers.setString(REPLICATION_TARGET_QUEUE, enqueued.queue->getName());
+ headers.setInt(REPLICATION_EVENT_TYPE, ENQUEUE);
+ headers.setInt(QUEUE_MESSAGE_POSITION,enqueued.position);
+ route(msg);
+}
+
+void ReplicatingEventListener::route(boost::intrusive_ptr<qpid::broker::Message> msg)
+{
+ try {
+ if (exchange) {
+ DeliverableMessage deliverable(msg);
+ exchange->route(deliverable, msg->getRoutingKey(), msg->getApplicationHeaders());
+ } else if (queue) {
+ queue->deliver(msg);
+ } else {
+ QPID_LOG(error, "Cannot route replication event, neither replication queue nor exchange configured");
+ }
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Error enqueing replication event: " << e.what());
+ }
+}
+
+
+boost::intrusive_ptr<Message> ReplicatingEventListener::createMessage(const FieldTable& headers)
+{
+ boost::intrusive_ptr<Message> msg(new Message());
+ AMQFrame method((MessageTransferBody(ProtocolVersion(), EMPTY, 0, 0)));
+ AMQFrame header((AMQHeaderBody()));
+ header.setBof(false);
+ header.setEof(true);
+ header.setBos(true);
+ header.setEos(true);
+ msg->getFrames().append(method);
+ msg->getFrames().append(header);
+ MessageProperties* props = msg->getFrames().getHeaders()->get<MessageProperties>(true);
+ props->setApplicationHeaders(headers);
+ return msg;
+}
+
+struct AppendingHandler : FrameHandler
+{
+ boost::intrusive_ptr<Message> msg;
+
+ AppendingHandler(boost::intrusive_ptr<Message> m) : msg(m) {}
+
+ void handle(AMQFrame& f)
+ {
+ msg->getFrames().append(f);
+ }
+};
+
+boost::intrusive_ptr<Message> ReplicatingEventListener::cloneMessage(Queue& queue, boost::intrusive_ptr<Message> original)
+{
+ boost::intrusive_ptr<Message> copy(new Message());
+ AMQFrame method((MessageTransferBody(ProtocolVersion(), EMPTY, 0, 0)));
+ AppendingHandler handler(copy);
+ handler.handle(method);
+
+ //To avoid modifying original headers, create new frame with
+ //cloned body:
+ AMQFrame header(*original->getFrames().getHeaders());
+ header.setBof(false);
+ header.setEof(!original->getFrames().getContentSize());//if there is any content then the header is not the end of the frameset
+ header.setBos(true);
+ header.setEos(true);
+ handler.handle(header);
+
+ original->sendContent(queue, handler, std::numeric_limits<int16_t>::max());
+ return copy;
+}
+
+Options* ReplicatingEventListener::getOptions()
+{
+ return &options;
+}
+
+void ReplicatingEventListener::initialize(Plugin::Target& target)
+{
+ Broker* broker = dynamic_cast<broker::Broker*>(&target);
+ if (broker) {
+ broker->addFinalizer(boost::bind(&ReplicatingEventListener::shutdown, this));
+ if (!options.exchange.empty()) {
+ if (!options.queue.empty()) {
+ QPID_LOG(warning, "Replication queue option ignored as replication exchange has been specified");
+ }
+ try {
+ exchange = broker->getExchanges().declare(options.exchange, options.exchangeType).first;
+ } catch (const UnknownExchangeTypeException&) {
+ QPID_LOG(error, "Replication disabled due to invalid type: " << options.exchangeType);
+ }
+ } else if (!options.queue.empty()) {
+ if (options.createQueue) {
+ queue = broker->getQueues().declare(options.queue).first;
+ } else {
+ queue = broker->getQueues().find(options.queue);
+ }
+ if (queue) {
+ queue->insertSequenceNumbers(REPLICATION_EVENT_SEQNO);
+ } else {
+ QPID_LOG(error, "Replication queue named '" << options.queue << "' does not exist; replication plugin disabled.");
+ }
+ }
+ if (queue || exchange) {
+ QueueEvents::EventListener callback = boost::bind(&ReplicatingEventListener::handle, this, _1);
+ broker->getQueueEvents().registerListener(options.name, callback);
+ QPID_LOG(info, "Registered replicating queue event listener");
+ }
+ }
+}
+
+void ReplicatingEventListener::earlyInitialize(Target&) {}
+void ReplicatingEventListener::shutdown() { queue.reset(); exchange.reset(); }
+
+ReplicatingEventListener::PluginOptions::PluginOptions() : Options("Queue Replication Options"),
+ exchangeType("direct"),
+ name("replicator"),
+ createQueue(false)
+{
+ addOptions()
+ ("replication-exchange-name", optValue(exchange, "EXCHANGE"), "Exchange to which events for other queues are routed")
+ ("replication-exchange-type", optValue(exchangeType, "direct|topic etc"), "Type of exchange to use")
+ ("replication-queue", optValue(queue, "QUEUE"), "Queue on which events for other queues are recorded")
+ ("replication-listener-name", optValue(name, "NAME"), "name by which to register the replicating event listener")
+ ("create-replication-queue", optValue(createQueue), "if set, the replication will be created if it does not exist");
+}
+
+static ReplicatingEventListener plugin;
+
+}} // namespace qpid::replication
diff --git a/cpp/src/qpid/replication/ReplicatingEventListener.h b/cpp/src/qpid/replication/ReplicatingEventListener.h
new file mode 100644
index 0000000000..74418d00e6
--- /dev/null
+++ b/cpp/src/qpid/replication/ReplicatingEventListener.h
@@ -0,0 +1,78 @@
+#ifndef QPID_REPLICATION_REPLICATINGEVENTLISTENER_H
+#define QPID_REPLICATION_REPLICATINGEVENTLISTENER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Plugin.h"
+#include "qpid/Options.h"
+#include "qpid/broker/Exchange.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/QueueEvents.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/SequenceNumber.h"
+
+namespace qpid {
+namespace replication {
+
+/**
+ * An event listener plugin that records queue events as messages on a
+ * replication queue, from where they can be consumed (e.g. by an
+ * inter-broker link to the corresponding QueueReplicationExchange
+ * plugin.
+ */
+class ReplicatingEventListener : public Plugin
+{
+ public:
+ Options* getOptions();
+ void earlyInitialize(Plugin::Target& target);
+ void initialize(Plugin::Target& target);
+ void handle(qpid::broker::QueueEvents::Event);
+ private:
+ struct PluginOptions : public Options
+ {
+ std::string queue;
+ std::string exchange;
+ std::string exchangeType;
+ std::string name;
+ bool createQueue;
+
+ PluginOptions();
+ };
+
+ PluginOptions options;
+ qpid::broker::Queue::shared_ptr queue;
+ qpid::broker::Exchange::shared_ptr exchange;
+
+ void deliverDequeueMessage(const qpid::broker::QueuedMessage& enqueued);
+ void deliverEnqueueMessage(const qpid::broker::QueuedMessage& enqueued);
+ void route(boost::intrusive_ptr<qpid::broker::Message>);
+ void shutdown();
+
+ boost::intrusive_ptr<qpid::broker::Message> createMessage(const qpid::framing::FieldTable& headers);
+ boost::intrusive_ptr<qpid::broker::Message> cloneMessage(qpid::broker::Queue& queue,
+ boost::intrusive_ptr<qpid::broker::Message> original);
+};
+
+}} // namespace qpid::replication
+
+#endif /*!QPID_REPLICATION_REPLICATINGEVENTLISTENER_H*/
diff --git a/cpp/src/qpid/replication/ReplicationExchange.cpp b/cpp/src/qpid/replication/ReplicationExchange.cpp
new file mode 100644
index 0000000000..b5911bb71e
--- /dev/null
+++ b/cpp/src/qpid/replication/ReplicationExchange.cpp
@@ -0,0 +1,232 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/replication/ReplicationExchange.h"
+#include "qpid/replication/constants.h"
+#include "qpid/Plugin.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/broker/ExchangeRegistry.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/log/Statement.h"
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace replication {
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::replication::constants;
+
+const std::string SEQUENCE_VALUE("qpid.replication-event.sequence");
+ReplicationExchange::ReplicationExchange(const std::string& name, bool durable,
+ const FieldTable& _args,
+ QueueRegistry& qr,
+ Manageable* parent, Broker* broker)
+ : Exchange(name, durable, _args, parent, broker), queues(qr), sequence(args.getAsInt64(SEQUENCE_VALUE)), init(false)
+{
+ args.setInt64(SEQUENCE_VALUE, sequence);
+ if (mgmtExchange != 0)
+ mgmtExchange->set_type(typeName);
+}
+
+std::string ReplicationExchange::getType() const { return typeName; }
+
+void ReplicationExchange::route(Deliverable& msg, const std::string& /*routingKey*/, const FieldTable* args)
+{
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_msgReceives();
+ mgmtExchange->inc_byteReceives(msg.contentSize());
+ }
+ if (args) {
+ int eventType = args->getAsInt(REPLICATION_EVENT_TYPE);
+ if (eventType) {
+ if (isDuplicate(args)) return;
+ switch (eventType) {
+ case ENQUEUE:
+ handleEnqueueEvent(args, msg);
+ return;
+ case DEQUEUE:
+ handleDequeueEvent(args, msg);
+ return;
+ default:
+ throw IllegalArgumentException(QPID_MSG("Illegal value for " << REPLICATION_EVENT_TYPE << ": " << eventType));
+ }
+ }
+ } else {
+ QPID_LOG(warning, "Dropping unexpected message with no headers");
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_msgDrops();
+ mgmtExchange->inc_byteDrops(msg.contentSize());
+ }
+ }
+}
+
+void ReplicationExchange::handleEnqueueEvent(const FieldTable* args, Deliverable& msg)
+{
+ std::string queueName = args->getAsString(REPLICATION_TARGET_QUEUE);
+ Queue::shared_ptr queue = queues.find(queueName);
+ if (queue) {
+
+ SequenceNumber seqno1(args->getAsInt(QUEUE_MESSAGE_POSITION));
+
+ // note that queue will ++ before enqueue.
+ if (queue->getPosition() > --seqno1) // test queue.pos < seqnumber
+ {
+ QPID_LOG(error, "Cannot enqueue replicated message. Destination Queue " << queueName << " ahead of source queue");
+ mgmtExchange->inc_msgDrops();
+ mgmtExchange->inc_byteDrops(msg.contentSize());
+ } else {
+ queue->setPosition(seqno1);
+
+ FieldTable& headers = msg.getMessage().getProperties<MessageProperties>()->getApplicationHeaders();
+ headers.erase(REPLICATION_TARGET_QUEUE);
+ headers.erase(REPLICATION_EVENT_SEQNO);
+ headers.erase(REPLICATION_EVENT_TYPE);
+ headers.erase(QUEUE_MESSAGE_POSITION);
+ msg.deliverTo(queue);
+ QPID_LOG(debug, "Enqueued replicated message onto " << queueName);
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_msgRoutes();
+ mgmtExchange->inc_byteRoutes( msg.contentSize());
+ }
+ }
+ } else {
+ QPID_LOG(error, "Cannot enqueue replicated message. Queue " << queueName << " does not exist");
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_msgDrops();
+ mgmtExchange->inc_byteDrops(msg.contentSize());
+ }
+ }
+}
+
+void ReplicationExchange::handleDequeueEvent(const FieldTable* args, Deliverable& msg)
+{
+ std::string queueName = args->getAsString(REPLICATION_TARGET_QUEUE);
+ Queue::shared_ptr queue = queues.find(queueName);
+ if (queue) {
+ SequenceNumber position(args->getAsInt(DEQUEUED_MESSAGE_POSITION));
+ QueuedMessage dequeued;
+ if (queue->acquireMessageAt(position, dequeued)) {
+ queue->dequeue(0, dequeued);
+ QPID_LOG(debug, "Processed replicated 'dequeue' event from " << queueName << " at position " << position);
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_msgRoutes();
+ mgmtExchange->inc_byteRoutes(msg.contentSize());
+ }
+ } else {
+ QPID_LOG(warning, "Could not acquire message " << position << " from " << queueName);
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_msgDrops();
+ mgmtExchange->inc_byteDrops(msg.contentSize());
+ }
+ }
+ } else {
+ QPID_LOG(error, "Cannot process replicated 'dequeue' event. Queue " << queueName << " does not exist");
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_msgDrops();
+ mgmtExchange->inc_byteDrops(msg.contentSize());
+ }
+ }
+}
+
+bool ReplicationExchange::isDuplicate(const FieldTable* args)
+{
+ if (!args->get(REPLICATION_EVENT_SEQNO)) return false;
+ SequenceNumber seqno(args->getAsInt(REPLICATION_EVENT_SEQNO));
+ if (!init) {
+ init = true;
+ sequence = seqno;
+ return false;
+ } else if (seqno > sequence) {
+ if (seqno - sequence > 1) {
+ QPID_LOG(error, "Gap in replication event sequence between: " << sequence << " and " << seqno);
+ }
+ sequence = seqno;
+ return false;
+ } else {
+ QPID_LOG(info, "Duplicate detected: seqno=" << seqno << " (last seqno=" << sequence << ")");
+ return true;
+ }
+}
+
+bool ReplicationExchange::bind(Queue::shared_ptr /*queue*/, const std::string& /*routingKey*/, const FieldTable* /*args*/)
+{
+ throw NotImplementedException("Replication exchange does not support bind operation");
+}
+
+bool ReplicationExchange::unbind(Queue::shared_ptr /*queue*/, const std::string& /*routingKey*/, const FieldTable* /*args*/)
+{
+ throw NotImplementedException("Replication exchange does not support unbind operation");
+}
+
+bool ReplicationExchange::isBound(Queue::shared_ptr /*queue*/, const string* const /*routingKey*/, const FieldTable* const /*args*/)
+{
+ return false;
+}
+
+const std::string ReplicationExchange::typeName("replication");
+
+
+void ReplicationExchange::encode(Buffer& buffer) const
+{
+ args.setInt64(std::string(SEQUENCE_VALUE), sequence);
+ Exchange::encode(buffer);
+}
+
+
+struct ReplicationExchangePlugin : Plugin
+{
+ Broker* broker;
+
+ ReplicationExchangePlugin();
+ void earlyInitialize(Plugin::Target& target);
+ void initialize(Plugin::Target& target);
+ Exchange::shared_ptr create(const std::string& name, bool durable,
+ const framing::FieldTable& args,
+ management::Manageable* parent,
+ qpid::broker::Broker* broker);
+};
+
+ReplicationExchangePlugin::ReplicationExchangePlugin() : broker(0) {}
+
+Exchange::shared_ptr ReplicationExchangePlugin::create(const std::string& name, bool durable,
+ const framing::FieldTable& args,
+ management::Manageable* parent, qpid::broker::Broker* broker)
+{
+ Exchange::shared_ptr e(new ReplicationExchange(name, durable, args, broker->getQueues(), parent, broker));
+ return e;
+}
+
+
+void ReplicationExchangePlugin::earlyInitialize(Plugin::Target& target)
+{
+ broker = dynamic_cast<broker::Broker*>(&target);
+ if (broker) {
+ ExchangeRegistry::FactoryFunction f = boost::bind(&ReplicationExchangePlugin::create, this, _1, _2, _3, _4, _5);
+ broker->getExchanges().registerType(ReplicationExchange::typeName, f);
+ QPID_LOG(info, "Registered replication exchange");
+ }
+}
+
+void ReplicationExchangePlugin::initialize(Target&) {}
+
+static ReplicationExchangePlugin exchangePlugin;
+
+}} // namespace qpid::replication
diff --git a/cpp/src/qpid/replication/ReplicationExchange.h b/cpp/src/qpid/replication/ReplicationExchange.h
new file mode 100644
index 0000000000..f0252448f9
--- /dev/null
+++ b/cpp/src/qpid/replication/ReplicationExchange.h
@@ -0,0 +1,67 @@
+#ifndef QPID_REPLICATION_REPLICATIONEXCHANGE_H
+#define QPID_REPLICATION_REPLICATIONEXCHANGE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/broker/Exchange.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/SequenceNumber.h"
+
+namespace qpid {
+namespace replication {
+
+/**
+ * A custom exchange plugin that processes incoming messages
+ * representing enqueue or dequeue events for particular queues and
+ * carries out the corresponding action to replicate that on the local
+ * broker.
+ */
+class ReplicationExchange : public qpid::broker::Exchange
+{
+ public:
+ static const std::string typeName;
+
+ ReplicationExchange(const std::string& name, bool durable,
+ const qpid::framing::FieldTable& args,
+ qpid::broker::QueueRegistry& queues,
+ qpid::management::Manageable* parent = 0,
+ qpid::broker::Broker* broker = 0);
+
+ std::string getType() const;
+
+ void route(qpid::broker::Deliverable& msg, const std::string& routingKey, const qpid::framing::FieldTable* args);
+
+ bool bind(qpid::broker::Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
+ bool unbind(qpid::broker::Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
+ bool isBound(qpid::broker::Queue::shared_ptr queue, const std::string* const routingKey, const qpid::framing::FieldTable* const args);
+ private:
+ qpid::broker::QueueRegistry& queues;
+ qpid::framing::SequenceNumber sequence;
+ bool init;
+
+ bool isDuplicate(const qpid::framing::FieldTable* args);
+ void handleEnqueueEvent(const qpid::framing::FieldTable* args, qpid::broker::Deliverable& msg);
+ void handleDequeueEvent(const qpid::framing::FieldTable* args, qpid::broker::Deliverable& msg);
+ void encode(framing::Buffer& buffer) const;
+};
+}} // namespace qpid::replication
+
+#endif /*!QPID_REPLICATION_REPLICATIONEXCHANGE_H*/
diff --git a/cpp/src/qpid/replication/constants.h b/cpp/src/qpid/replication/constants.h
new file mode 100644
index 0000000000..c5ba7d3d6a
--- /dev/null
+++ b/cpp/src/qpid/replication/constants.h
@@ -0,0 +1,34 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+namespace qpid {
+namespace replication {
+namespace constants {
+
+const std::string REPLICATION_EVENT_TYPE("qpid.replication.type");
+const std::string REPLICATION_EVENT_SEQNO("qpid.replication.seqno");
+const std::string REPLICATION_TARGET_QUEUE("qpid.replication.target_queue");
+const std::string DEQUEUED_MESSAGE_POSITION("qpid.replication.message");
+const std::string QUEUE_MESSAGE_POSITION("qpid.replication.queue.position");
+
+const int ENQUEUE(1);
+const int DEQUEUE(2);
+
+}}}
diff --git a/cpp/src/qpid/shared_ptr.h b/cpp/src/qpid/shared_ptr.h
deleted file mode 100644
index 0c933ea6a6..0000000000
--- a/cpp/src/qpid/shared_ptr.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef _common_shared_ptr_h
-#define _common_shared_ptr_h
-
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include <boost/shared_ptr.hpp>
-#include <boost/cast.hpp>
-
-namespace qpid {
-
-// Import shared_ptr definitions into qpid namespace and define some
-// useful shared_ptr templates for convenience.
-
-using boost::shared_ptr;
-using boost::dynamic_pointer_cast;
-using boost::static_pointer_cast;
-using boost::const_pointer_cast;
-using boost::shared_polymorphic_downcast;
-
-template <class T> shared_ptr<T> make_shared_ptr(T* ptr) {
- return shared_ptr<T>(ptr);
-}
-
-template <class T, class D>
-shared_ptr<T> make_shared_ptr(T* ptr, D deleter) {
- return shared_ptr<T>(ptr, deleter);
-}
-
-inline void nullDeleter(void const *) {}
-
-} // namespace qpid
-
-
-
-#endif /*!_common_shared_ptr_h*/
diff --git a/cpp/src/qpid/store/CMakeLists.txt b/cpp/src/qpid/store/CMakeLists.txt
new file mode 100644
index 0000000000..0d25923175
--- /dev/null
+++ b/cpp/src/qpid/store/CMakeLists.txt
@@ -0,0 +1,80 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+project(qpidc_store)
+
+#set (CMAKE_VERBOSE_MAKEFILE ON) # for debugging
+
+include_directories( ${Boost_INCLUDE_DIR} )
+
+include_directories( ${CMAKE_CURRENT_SOURCE_DIR} )
+include_directories( ${CMAKE_HOME_DIRECTORY}/include )
+
+link_directories( ${Boost_LIBRARY_DIRS} )
+
+set (store_SOURCES
+ MessageStorePlugin.cpp
+ )
+add_library (store MODULE ${store_SOURCES})
+target_link_libraries (store qpidbroker ${Boost_PROGRAM_OPTIONS_LIBRARY})
+if (CMAKE_COMPILER_IS_GNUCXX)
+ set_target_properties (store PROPERTIES
+ PREFIX ""
+ LINK_FLAGS -Wl,--no-undefined)
+endif (CMAKE_COMPILER_IS_GNUCXX)
+
+if (CMAKE_SYSTEM_NAME STREQUAL Windows)
+ if (MSVC)
+ add_definitions(
+ /D "NOMINMAX"
+ /D "WIN32_LEAN_AND_MEAN"
+ )
+ endif (MSVC)
+endif (CMAKE_SYSTEM_NAME STREQUAL Windows)
+
+set_target_properties (store PROPERTIES VERSION ${qpidc_version})
+install (TARGETS store # RUNTIME
+ DESTINATION ${QPIDD_MODULE_DIR}
+ COMPONENT ${QPID_COMPONENT_BROKER})
+
+# Build the MS SQL Storage Provider plugin
+set (mssql_default ON)
+if (NOT CMAKE_SYSTEM_NAME STREQUAL Windows)
+ set(mssql_default OFF)
+endif (NOT CMAKE_SYSTEM_NAME STREQUAL Windows)
+option(BUILD_MSSQL "Build MS SQL Store provider plugin" ${mssql_default})
+if (BUILD_MSSQL)
+ add_library (mssql_store MODULE
+ ms-sql/MsSqlProvider.cpp
+ ms-sql/AmqpTransaction.cpp
+ ms-sql/BindingRecordset.cpp
+ ms-sql/BlobAdapter.cpp
+ ms-sql/BlobEncoder.cpp
+ ms-sql/BlobRecordset.cpp
+ ms-sql/DatabaseConnection.cpp
+ ms-sql/MessageMapRecordset.cpp
+ ms-sql/MessageRecordset.cpp
+ ms-sql/Recordset.cpp
+ ms-sql/State.cpp
+ ms-sql/VariantHelper.cpp)
+ target_link_libraries (mssql_store qpidbroker qpidcommon ${Boost_PROGRAM_OPTIONS_LIBRARY})
+ install (TARGETS mssql_store # RUNTIME
+ DESTINATION ${QPIDD_MODULE_DIR}
+ COMPONENT ${QPID_COMPONENT_BROKER})
+endif (BUILD_MSSQL)
diff --git a/cpp/src/qpid/store/MessageStorePlugin.cpp b/cpp/src/qpid/store/MessageStorePlugin.cpp
new file mode 100644
index 0000000000..05b6ef4465
--- /dev/null
+++ b/cpp/src/qpid/store/MessageStorePlugin.cpp
@@ -0,0 +1,447 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "MessageStorePlugin.h"
+#include "StorageProvider.h"
+#include "StoreException.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/Plugin.h"
+#include "qpid/Options.h"
+#include "qpid/DataDir.h"
+#include "qpid/log/Statement.h"
+
+/*
+ * The MessageStore pointer given to the Broker points to static storage.
+ * Thus, it cannot be deleted, especially by the broker. To prevent deletion,
+ * this no-op deleter is used with the boost::shared_ptr. When the last
+ * shared_ptr is destroyed, the deleter is called rather than delete().
+ */
+namespace {
+ class NoopDeleter {
+ public:
+ NoopDeleter() {}
+ void operator()(qpid::broker::MessageStore * /*p*/) {}
+ };
+}
+
+namespace qpid {
+namespace store {
+
+static MessageStorePlugin static_instance_registers_plugin;
+
+
+MessageStorePlugin::StoreOptions::StoreOptions(const std::string& name) :
+ qpid::Options(name)
+{
+ addOptions()
+ ("storage-provider", qpid::optValue(providerName, "PROVIDER"),
+ "Name of the storage provider to use.")
+ ;
+}
+
+
+void
+MessageStorePlugin::earlyInitialize (qpid::Plugin::Target& target)
+{
+ qpid::broker::Broker* broker =
+ dynamic_cast<qpid::broker::Broker*>(&target);
+ if (0 == broker)
+ return; // Only listen to Broker targets
+
+ // See if there are any storage provider plugins ready. If not, we can't
+ // do a message store.
+ qpid::Plugin::earlyInitAll(*this);
+
+ if (providers.empty()) {
+ QPID_LOG(warning,
+ "Message store plugin: No storage providers available.");
+ provider = providers.end();
+ return;
+ }
+ if (!options.providerName.empty()) {
+ // If specific one was chosen, locate it in loaded set of providers.
+ provider = providers.find(options.providerName);
+ if (provider == providers.end())
+ throw Exception("Message store plugin: storage provider '" +
+ options.providerName +
+ "' does not exist.");
+ }
+ else {
+ // No specific provider chosen; if there's only one, use it. Else
+ // report the need to pick one.
+ if (providers.size() > 1) {
+ provider = providers.end();
+ throw Exception("Message store plugin: multiple provider plugins "
+ "loaded; must either load only one or select one "
+ "using --storage-provider");
+ }
+ provider = providers.begin();
+ }
+
+ provider->second->activate(*this);
+ NoopDeleter d;
+ boost::shared_ptr<qpid::broker::MessageStore> sp(this, d);
+ broker->setStore(sp);
+ target.addFinalizer(boost::bind(&MessageStorePlugin::finalizeMe, this));
+}
+
+void
+MessageStorePlugin::initialize(qpid::Plugin::Target& target)
+{
+ qpid::broker::Broker* broker =
+ dynamic_cast<qpid::broker::Broker*>(&target);
+ if (0 == broker)
+ return; // Only listen to Broker targets
+
+ // Pass along the initialize step to the provider that's activated.
+ if (provider != providers.end()) {
+ provider->second->initialize(*this);
+ }
+ // qpid::Plugin::initializeAll(*this);
+}
+
+void
+MessageStorePlugin::finalizeMe()
+{
+ finalize(); // Call finalizers on any Provider plugins
+}
+
+void
+MessageStorePlugin::providerAvailable(const std::string name,
+ StorageProvider *be)
+{
+ ProviderMap::value_type newSp(name, be);
+ std::pair<ProviderMap::iterator, bool> inserted = providers.insert(newSp);
+ if (inserted.second == false)
+ QPID_LOG(warning, "Storage provider " << name << " duplicate; ignored.");
+}
+
+void
+MessageStorePlugin::truncateInit(const bool /*saveStoreContent*/)
+{
+ QPID_LOG(info, "Store: truncateInit");
+}
+
+
+/**
+ * Record the existence of a durable queue
+ */
+void
+MessageStorePlugin::create(broker::PersistableQueue& queue,
+ const framing::FieldTable& args)
+{
+ if (queue.getName().size() == 0)
+ {
+ QPID_LOG(error,
+ "Cannot create store for empty (null) queue name - "
+ "ignoring and attempting to continue.");
+ return;
+ }
+ if (queue.getPersistenceId()) {
+ THROW_STORE_EXCEPTION("Queue already created: " + queue.getName());
+ }
+ provider->second->create(queue, args);
+}
+
+/**
+ * Destroy a durable queue
+ */
+void
+MessageStorePlugin::destroy(broker::PersistableQueue& queue)
+{
+ provider->second->destroy(queue);
+}
+
+/**
+ * Record the existence of a durable exchange
+ */
+void
+MessageStorePlugin::create(const broker::PersistableExchange& exchange,
+ const framing::FieldTable& args)
+{
+ if (exchange.getPersistenceId()) {
+ THROW_STORE_EXCEPTION("Exchange already created: " + exchange.getName());
+ }
+ provider->second->create(exchange, args);
+}
+
+/**
+ * Destroy a durable exchange
+ */
+void
+MessageStorePlugin::destroy(const broker::PersistableExchange& exchange)
+{
+ provider->second->destroy(exchange);
+}
+
+/**
+ * Record a binding
+ */
+void
+MessageStorePlugin::bind(const broker::PersistableExchange& exchange,
+ const broker::PersistableQueue& queue,
+ const std::string& key,
+ const framing::FieldTable& args)
+{
+ provider->second->bind(exchange, queue, key, args);
+}
+
+/**
+ * Forget a binding
+ */
+void
+MessageStorePlugin::unbind(const broker::PersistableExchange& exchange,
+ const broker::PersistableQueue& queue,
+ const std::string& key,
+ const framing::FieldTable& args)
+{
+ provider->second->unbind(exchange, queue, key, args);
+}
+
+/**
+ * Record generic durable configuration
+ */
+void
+MessageStorePlugin::create(const broker::PersistableConfig& config)
+{
+ if (config.getPersistenceId()) {
+ THROW_STORE_EXCEPTION("Config item already created: " +
+ config.getName());
+ }
+ provider->second->create(config);
+}
+
+/**
+ * Destroy generic durable configuration
+ */
+void
+MessageStorePlugin::destroy(const broker::PersistableConfig& config)
+{
+ provider->second->destroy(config);
+}
+
+/**
+ * Stores a message before it has been enqueued
+ * (enqueueing automatically stores the message so this is
+ * only required if storage is required prior to that
+ * point).
+ */
+void
+MessageStorePlugin::stage(const boost::intrusive_ptr<broker::PersistableMessage>& msg)
+{
+ if (msg->getPersistenceId() == 0 && !msg->isContentReleased()) {
+ provider->second->stage(msg);
+ }
+}
+
+/**
+ * Destroys a previously staged message. This only needs
+ * to be called if the message is never enqueued. (Once
+ * enqueued, deletion will be automatic when the message
+ * is dequeued from all queues it was enqueued onto).
+ */
+void
+MessageStorePlugin::destroy(broker::PersistableMessage& msg)
+{
+ if (msg.getPersistenceId())
+ provider->second->destroy(msg);
+}
+
+/**
+ * Appends content to a previously staged message
+ */
+void
+MessageStorePlugin::appendContent
+ (const boost::intrusive_ptr<const broker::PersistableMessage>& msg,
+ const std::string& data)
+{
+ if (msg->getPersistenceId())
+ provider->second->appendContent(msg, data);
+ else
+ THROW_STORE_EXCEPTION("Cannot append content. Message not known to store!");
+}
+
+/**
+ * Loads (a section) of content data for the specified
+ * message (previously stored through a call to stage or
+ * enqueue) into data. The offset refers to the content
+ * only (i.e. an offset of 0 implies that the start of the
+ * content should be loaded, not the headers or related
+ * meta-data).
+ */
+void
+MessageStorePlugin::loadContent(const broker::PersistableQueue& queue,
+ const boost::intrusive_ptr<const broker::PersistableMessage>& msg,
+ std::string& data,
+ uint64_t offset,
+ uint32_t length)
+{
+ if (msg->getPersistenceId())
+ provider->second->loadContent(queue, msg, data, offset, length);
+ else
+ THROW_STORE_EXCEPTION("Cannot load content. Message not known to store!");
+}
+
+/**
+ * Enqueues a message, storing the message if it has not
+ * been previously stored and recording that the given
+ * message is on the given queue.
+ *
+ * Note: The operation is asynchronous so the return of this function does
+ * not mean the operation is complete.
+ */
+void
+MessageStorePlugin::enqueue(broker::TransactionContext* ctxt,
+ const boost::intrusive_ptr<broker::PersistableMessage>& msg,
+ const broker::PersistableQueue& queue)
+{
+ if (queue.getPersistenceId() == 0) {
+ THROW_STORE_EXCEPTION("Queue not created: " + queue.getName());
+ }
+ provider->second->enqueue(ctxt, msg, queue);
+}
+
+/**
+ * Dequeues a message, recording that the given message is
+ * no longer on the given queue and deleting the message
+ * if it is no longer on any other queue.
+ *
+ * Note: The operation is asynchronous so the return of this function does
+ * not mean the operation is complete.
+ */
+void
+MessageStorePlugin::dequeue(broker::TransactionContext* ctxt,
+ const boost::intrusive_ptr<broker::PersistableMessage>& msg,
+ const broker::PersistableQueue& queue)
+{
+ provider->second->dequeue(ctxt, msg, queue);
+}
+
+/**
+ * Flushes all async messages to disk for the specified queue
+ *
+ * Note: The operation is asynchronous so the return of this function does
+ * not mean the operation is complete.
+ */
+void
+MessageStorePlugin::flush(const broker::PersistableQueue& queue)
+{
+ provider->second->flush(queue);
+}
+
+/**
+ * Returns the number of outstanding AIO's for a given queue
+ *
+ * If 0, than all the enqueue / dequeues have been stored
+ * to disk.
+ */
+uint32_t
+MessageStorePlugin::outstandingQueueAIO(const broker::PersistableQueue& queue)
+{
+ return provider->second->outstandingQueueAIO(queue);
+}
+
+std::auto_ptr<broker::TransactionContext>
+MessageStorePlugin::begin()
+{
+ return provider->second->begin();
+}
+
+std::auto_ptr<broker::TPCTransactionContext>
+MessageStorePlugin::begin(const std::string& xid)
+{
+ return provider->second->begin(xid);
+}
+
+void
+MessageStorePlugin::prepare(broker::TPCTransactionContext& ctxt)
+{
+ provider->second->prepare(ctxt);
+}
+
+void
+MessageStorePlugin::commit(broker::TransactionContext& ctxt)
+{
+ provider->second->commit(ctxt);
+}
+
+void
+MessageStorePlugin::abort(broker::TransactionContext& ctxt)
+{
+ provider->second->abort(ctxt);
+}
+
+void
+MessageStorePlugin::collectPreparedXids(std::set<std::string>& xids)
+{
+ provider->second->collectPreparedXids(xids);
+}
+
+/**
+ * Request recovery of queue and message state; inherited from Recoverable
+ */
+void
+MessageStorePlugin::recover(broker::RecoveryManager& recoverer)
+{
+ ExchangeMap exchanges;
+ QueueMap queues;
+ MessageMap messages;
+ MessageQueueMap messageQueueMap;
+
+ provider->second->recoverConfigs(recoverer);
+ provider->second->recoverExchanges(recoverer, exchanges);
+ provider->second->recoverQueues(recoverer, queues);
+ provider->second->recoverBindings(recoverer, exchanges, queues);
+ provider->second->recoverMessages(recoverer, messages, messageQueueMap);
+ // Enqueue msgs where needed.
+ for (MessageQueueMap::const_iterator i = messageQueueMap.begin();
+ i != messageQueueMap.end();
+ ++i) {
+ // Locate the message corresponding to the current message Id
+ MessageMap::const_iterator iMsg = messages.find(i->first);
+ if (iMsg == messages.end()) {
+ std::ostringstream oss;
+ oss << "No matching message trying to re-enqueue message "
+ << i->first;
+ THROW_STORE_EXCEPTION(oss.str());
+ }
+ broker::RecoverableMessage::shared_ptr msg = iMsg->second;
+ // Now for each queue referenced in the queue map, locate it
+ // and re-enqueue the message.
+ for (std::vector<uint64_t>::const_iterator j = i->second.begin();
+ j != i->second.end();
+ ++j) {
+ // Locate the queue corresponding to the current queue Id
+ QueueMap::const_iterator iQ = queues.find(*j);
+ if (iQ == queues.end()) {
+ std::ostringstream oss;
+ oss << "No matching queue trying to re-enqueue message "
+ << " on queue Id " << *j;
+ THROW_STORE_EXCEPTION(oss.str());
+ }
+ iQ->second->recover(msg);
+ }
+ }
+
+ // recoverTransactions() and apply correctly while re-enqueuing
+}
+
+}} // namespace qpid::store
diff --git a/cpp/src/qpid/store/MessageStorePlugin.h b/cpp/src/qpid/store/MessageStorePlugin.h
new file mode 100644
index 0000000000..529a59401e
--- /dev/null
+++ b/cpp/src/qpid/store/MessageStorePlugin.h
@@ -0,0 +1,284 @@
+#ifndef QPID_STORE_MESSAGESTOREPLUGIN_H
+#define QPID_STORE_MESSAGESTOREPLUGIN_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Plugin.h"
+#include "qpid/Options.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/broker/MessageStore.h"
+#include "qpid/broker/PersistableExchange.h"
+#include "qpid/broker/PersistableMessage.h"
+#include "qpid/broker/PersistableQueue.h"
+#include "qpid/management/Manageable.h"
+
+#include <string>
+
+using namespace qpid;
+
+namespace qpid {
+namespace store {
+
+class StorageProvider;
+
+/**
+ * @class MessageStorePlugin
+ *
+ * MessageStorePlugin is the front end of the persistent message store
+ * plugin. It is responsible for coordinating recovery, initialization,
+ * transactions (both local and distributed), flow-to-disk loading and
+ * unloading and persisting broker state (queues, bindings etc.).
+ * Actual storage operations are carried out by a message store storage
+ * provider that implements the qpid::store::StorageProvider interface.
+ */
+class MessageStorePlugin :
+ public qpid::Plugin,
+ public qpid::broker::MessageStore, // Frontend classes
+ public qpid::Plugin::Target // Provider target
+ // @TODO Need a mgmt story for this. Maybe allow r/o access to provider store info? public qpid::management::Manageable
+{
+ public:
+ MessageStorePlugin() {}
+
+ /**
+ * @name Methods inherited from qpid::Plugin
+ */
+ //@{
+ virtual Options* getOptions() { return &options; }
+ virtual void earlyInitialize (Plugin::Target& target);
+ virtual void initialize(Plugin::Target& target);
+ //@}
+
+ /// Finalizer; calls Target::finalize() to run finalizers on
+ /// StorageProviders.
+ void finalizeMe();
+
+ /**
+ * Called by StorageProvider instances during the earlyInitialize sequence.
+ * Each StorageProvider must supply a unique name by which it is known and a
+ * pointer to itself.
+ */
+ virtual void providerAvailable(const std::string name, StorageProvider *be);
+
+ /**
+ * @name Methods inherited from qpid::broker::MessageStore
+ */
+ //@{
+ /**
+ * If called before recovery, will discard the database and reinitialize
+ * using an empty store. This is used when cluster nodes recover and
+ * must get their content from a cluster sync rather than directly from
+ * the store.
+ *
+ * @param saveStoreContent If true, the store's contents should be
+ * saved to a backup location before
+ * reinitializing the store content.
+ */
+ virtual void truncateInit(const bool saveStoreContent = false);
+
+ /**
+ * Record the existence of a durable queue
+ */
+ virtual void create(broker::PersistableQueue& queue,
+ const framing::FieldTable& args);
+ /**
+ * Destroy a durable queue
+ */
+ virtual void destroy(broker::PersistableQueue& queue);
+
+ /**
+ * Record the existence of a durable exchange
+ */
+ virtual void create(const broker::PersistableExchange& exchange,
+ const framing::FieldTable& args);
+ /**
+ * Destroy a durable exchange
+ */
+ virtual void destroy(const broker::PersistableExchange& exchange);
+
+ /**
+ * Record a binding
+ */
+ virtual void bind(const broker::PersistableExchange& exchange,
+ const broker::PersistableQueue& queue,
+ const std::string& key,
+ const framing::FieldTable& args);
+
+ /**
+ * Forget a binding
+ */
+ virtual void unbind(const broker::PersistableExchange& exchange,
+ const broker::PersistableQueue& queue,
+ const std::string& key,
+ const framing::FieldTable& args);
+
+ /**
+ * Record generic durable configuration
+ */
+ virtual void create(const broker::PersistableConfig& config);
+
+ /**
+ * Destroy generic durable configuration
+ */
+ virtual void destroy(const broker::PersistableConfig& config);
+
+ /**
+ * Stores a message before it has been enqueued
+ * (enqueueing automatically stores the message so this is
+ * only required if storage is required prior to that
+ * point). If the message has not yet been stored it will
+ * store the headers as well as any content passed in. A
+ * persistence id will be set on the message which can be
+ * used to load the content or to append to it.
+ */
+ virtual void stage(const boost::intrusive_ptr<broker::PersistableMessage>& msg);
+
+ /**
+ * Destroys a previously staged message. This only needs
+ * to be called if the message is never enqueued. (Once
+ * enqueued, deletion will be automatic when the message
+ * is dequeued from all queues it was enqueued onto).
+ */
+ virtual void destroy(broker::PersistableMessage& msg);
+
+ /**
+ * Appends content to a previously staged message
+ */
+ virtual void appendContent(const boost::intrusive_ptr<const broker::PersistableMessage>& msg,
+ const std::string& data);
+
+ /**
+ * Loads (a section) of content data for the specified
+ * message (previously stored through a call to stage or
+ * enqueue) into data. The offset refers to the content
+ * only (i.e. an offset of 0 implies that the start of the
+ * content should be loaded, not the headers or related
+ * meta-data).
+ */
+ virtual void loadContent(const broker::PersistableQueue& queue,
+ const boost::intrusive_ptr<const broker::PersistableMessage>& msg,
+ std::string& data,
+ uint64_t offset,
+ uint32_t length);
+
+ /**
+ * Enqueues a message, storing the message if it has not
+ * been previously stored and recording that the given
+ * message is on the given queue.
+ *
+ * Note: The operation is asynchronous so the return of this function does
+ * not mean the operation is complete.
+ *
+ * @param msg the message to enqueue
+ * @param queue the name of the queue onto which it is to be enqueued
+ * @param xid (a pointer to) an identifier of the
+ * distributed transaction in which the operation takes
+ * place or null for 'local' transactions
+ */
+ virtual void enqueue(broker::TransactionContext* ctxt,
+ const boost::intrusive_ptr<broker::PersistableMessage>& msg,
+ const broker::PersistableQueue& queue);
+
+ /**
+ * Dequeues a message, recording that the given message is
+ * no longer on the given queue and deleting the message
+ * if it is no longer on any other queue.
+ *
+ *
+ * Note: The operation is asynchronous so the return of this function does
+ * not mean the operation is complete.
+ *
+ * @param msg the message to dequeue
+ * @param queue the name of the queue from which it is to be dequeued
+ * @param xid (a pointer to) an identifier of the
+ * distributed transaction in which the operation takes
+ * place or null for 'local' transactions
+ */
+ virtual void dequeue(broker::TransactionContext* ctxt,
+ const boost::intrusive_ptr<broker::PersistableMessage>& msg,
+ const broker::PersistableQueue& queue);
+
+ /**
+ * Flushes all async messages to disk for the specified queue
+ *
+ *
+ * Note: The operation is asynchronous so the return of this function does
+ * not mean the operation is complete.
+ *
+ * @param queue the name of the queue from which it is to be dequeued
+ */
+ virtual void flush(const broker::PersistableQueue& queue);
+
+ /**
+ * Returns the number of outstanding AIO's for a given queue
+ *
+ * If 0, than all the enqueue / dequeues have been stored
+ * to disk
+ *
+ * @param queue the name of the queue to check for outstanding AIO
+ */
+ virtual uint32_t outstandingQueueAIO(const broker::PersistableQueue& queue);
+ //@}
+
+ /**
+ * @name Methods inherited from qpid::broker::TransactionalStore
+ */
+ //@{
+ std::auto_ptr<broker::TransactionContext> begin();
+
+ std::auto_ptr<broker::TPCTransactionContext> begin(const std::string& xid);
+
+ void prepare(broker::TPCTransactionContext& ctxt);
+
+ void commit(broker::TransactionContext& ctxt);
+
+ void abort(broker::TransactionContext& ctxt);
+
+ void collectPreparedXids(std::set<std::string>& xids);
+ //@}
+
+ /**
+ * Request recovery of queue and message state; inherited from Recoverable
+ */
+ virtual void recover(broker::RecoveryManager& recoverer);
+
+ // inline management::Manageable::status_t ManagementMethod (uint32_t, management::Args&, std::string&)
+ // { return management::Manageable::STATUS_OK; }
+
+ protected:
+
+ struct StoreOptions : public qpid::Options {
+ StoreOptions(const std::string& name="Store Options");
+ std::string providerName;
+ };
+ StoreOptions options;
+
+ typedef std::map<const std::string, StorageProvider*> ProviderMap;
+ ProviderMap providers;
+ ProviderMap::const_iterator provider;
+
+}; // class MessageStoreImpl
+
+} // namespace msgstore
+} // namespace mrg
+
+#endif /* QPID_SERIALIZER_H */
diff --git a/cpp/src/qpid/store/StorageProvider.h b/cpp/src/qpid/store/StorageProvider.h
new file mode 100644
index 0000000000..1f257e7416
--- /dev/null
+++ b/cpp/src/qpid/store/StorageProvider.h
@@ -0,0 +1,324 @@
+#ifndef QPID_STORE_STORAGEPROVIDER_H
+#define QPID_STORE_STORAGEPROVIDER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <map>
+#include <stdexcept>
+#include <vector>
+#include "qpid/Exception.h"
+#include "qpid/Plugin.h"
+#include "qpid/Options.h"
+#include "qpid/broker/MessageStore.h"
+
+using qpid::broker::PersistableConfig;
+using qpid::broker::PersistableExchange;
+using qpid::broker::PersistableMessage;
+using qpid::broker::PersistableQueue;
+
+namespace qpid {
+namespace store {
+
+typedef std::map<uint64_t, qpid::broker::RecoverableExchange::shared_ptr>
+ ExchangeMap;
+typedef std::map<uint64_t, qpid::broker::RecoverableQueue::shared_ptr>
+ QueueMap;
+typedef std::map<uint64_t, qpid::broker::RecoverableMessage::shared_ptr>
+ MessageMap;
+// Msg Id -> vector of queue Ids where message is queued
+typedef std::map<uint64_t, std::vector<uint64_t> > MessageQueueMap;
+
+class MessageStorePlugin;
+
+/**
+ * @class StorageProvider
+ *
+ * StorageProvider defines the interface for the storage provider plugin to the
+ * Qpid broker persistence store plugin.
+ *
+ * @TODO Should StorageProvider also inherit from MessageStore? If so, then
+ * maybe remove Recoverable from MessageStore's inheritance and move it
+ * to MessageStorePlugin? In any event, somehow the discardInit() feature
+ * needs to get added here.
+ */
+class StorageProvider : public qpid::Plugin, public qpid::broker::MessageStore
+{
+public:
+
+ class Exception : public qpid::Exception
+ {
+ public:
+ virtual ~Exception() throw() {}
+ virtual const char *what() const throw() = 0;
+ };
+
+ /**
+ * @name Methods inherited from qpid::Plugin
+ */
+ //@{
+ /**
+ * Return a pointer to the provider's options. The options will be
+ * updated during option parsing by the host program; therefore, the
+ * referenced Options object must remain valid past this function's return.
+ *
+ * @return An options group or 0 for no options. Default returns 0.
+ * Plugin retains ownership of return value.
+ */
+ virtual qpid::Options* getOptions() = 0;
+
+ /**
+ * Initialize Plugin functionality on a Target, called before
+ * initializing the target.
+ *
+ * StorageProviders should respond only to Targets of class
+ * qpid::store::MessageStorePlugin and ignore all others.
+ *
+ * When called, the provider should invoke the method
+ * qpid::store::MessageStorePlugin::providerAvailable() to alert the
+ * message store of StorageProvider's availability.
+ *
+ * Called before the target itself is initialized.
+ */
+ virtual void earlyInitialize (Plugin::Target& target) = 0;
+
+ /**
+ * Initialize StorageProvider functionality. Called after initializing
+ * the target.
+ *
+ * StorageProviders should respond only to Targets of class
+ * qpid::store::MessageStorePlugin and ignore all others.
+ *
+ * Called after the target is fully initialized.
+ */
+ virtual void initialize(Plugin::Target& target) = 0;
+ //@}
+
+ /**
+ * Receive notification that this provider is the one that will actively
+ * handle storage for the target. If the provider is to be used, this
+ * method will be called after earlyInitialize() and before any
+ * recovery operations (recovery, in turn, precedes call to initialize()).
+ * Thus, it is wise to not actually do any database ops from within
+ * earlyInitialize() - they can wait until activate() is called because
+ * at that point it is certain the database will be needed.
+ */
+ virtual void activate(MessageStorePlugin &store) = 0;
+
+ /**
+ * @name Methods inherited from qpid::broker::MessageStore
+ */
+ //@{
+ /**
+ * If called after init() but before recovery, will discard the database
+ * and reinitialize using an empty store dir. If @a pushDownStoreFiles
+ * is true, the content of the store dir will be moved to a backup dir
+ * inside the store dir. This is used when cluster nodes recover and must
+ * get thier content from a cluster sync rather than directly fromt the
+ * store.
+ *
+ * @param pushDownStoreFiles If true, will move content of the store dir
+ * into a subdir, leaving the store dir
+ * otherwise empty.
+ */
+ virtual void truncateInit(const bool pushDownStoreFiles = false) = 0;
+
+ /**
+ * Record the existence of a durable queue
+ */
+ virtual void create(PersistableQueue& queue,
+ const qpid::framing::FieldTable& args) = 0;
+ /**
+ * Destroy a durable queue
+ */
+ virtual void destroy(PersistableQueue& queue) = 0;
+
+ /**
+ * Record the existence of a durable exchange
+ */
+ virtual void create(const PersistableExchange& exchange,
+ const qpid::framing::FieldTable& args) = 0;
+ /**
+ * Destroy a durable exchange
+ */
+ virtual void destroy(const PersistableExchange& exchange) = 0;
+
+ /**
+ * Record a binding
+ */
+ virtual void bind(const PersistableExchange& exchange,
+ const PersistableQueue& queue,
+ const std::string& key,
+ const qpid::framing::FieldTable& args) = 0;
+
+ /**
+ * Forget a binding
+ */
+ virtual void unbind(const PersistableExchange& exchange,
+ const PersistableQueue& queue,
+ const std::string& key,
+ const qpid::framing::FieldTable& args) = 0;
+
+ /**
+ * Record generic durable configuration
+ */
+ virtual void create(const PersistableConfig& config) = 0;
+
+ /**
+ * Destroy generic durable configuration
+ */
+ virtual void destroy(const PersistableConfig& config) = 0;
+
+ /**
+ * Stores a messages before it has been enqueued
+ * (enqueueing automatically stores the message so this is
+ * only required if storage is required prior to that
+ * point). If the message has not yet been stored it will
+ * store the headers as well as any content passed in. A
+ * persistence id will be set on the message which can be
+ * used to load the content or to append to it.
+ */
+ virtual void stage(const boost::intrusive_ptr<PersistableMessage>& msg) = 0;
+
+ /**
+ * Destroys a previously staged message. This only needs
+ * to be called if the message is never enqueued. (Once
+ * enqueued, deletion will be automatic when the message
+ * is dequeued from all queues it was enqueued onto).
+ */
+ virtual void destroy(PersistableMessage& msg) = 0;
+
+ /**
+ * Appends content to a previously staged message
+ */
+ virtual void appendContent(const boost::intrusive_ptr<const PersistableMessage>& msg,
+ const std::string& data) = 0;
+
+ /**
+ * Loads (a section) of content data for the specified
+ * message (previously stored through a call to stage or
+ * enqueue) into data. The offset refers to the content
+ * only (i.e. an offset of 0 implies that the start of the
+ * content should be loaded, not the headers or related
+ * meta-data).
+ */
+ virtual void loadContent(const PersistableQueue& queue,
+ const boost::intrusive_ptr<const PersistableMessage>& msg,
+ std::string& data,
+ uint64_t offset,
+ uint32_t length) = 0;
+
+ /**
+ * Enqueues a message, storing the message if it has not
+ * been previously stored and recording that the given
+ * message is on the given queue.
+ *
+ * Note: that this is async so the return of the function does
+ * not mean the opperation is complete.
+ *
+ * @param msg the message to enqueue
+ * @param queue the name of the queue onto which it is to be enqueued
+ * @param xid (a pointer to) an identifier of the
+ * distributed transaction in which the operation takes
+ * place or null for 'local' transactions
+ */
+ virtual void enqueue(qpid::broker::TransactionContext* ctxt,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue) = 0;
+
+ /**
+ * Dequeues a message, recording that the given message is
+ * no longer on the given queue and deleting the message
+ * if it is no longer on any other queue.
+ *
+ * Note: that this is async so the return of the function does
+ * not mean the opperation is complete.
+ *
+ * @param msg the message to dequeue
+ * @param queue the name of the queue from which it is to be dequeued
+ * @param xid (a pointer to) an identifier of the
+ * distributed transaction in which the operation takes
+ * place or null for 'local' transactions
+ */
+ virtual void dequeue(qpid::broker::TransactionContext* ctxt,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue) = 0;
+
+ /**
+ * Flushes all async messages to disk for the specified queue
+ *
+ * Note: that this is async so the return of the function does
+ * not mean the opperation is complete.
+ *
+ * @param queue the name of the queue from which it is to be dequeued
+ */
+ virtual void flush(const qpid::broker::PersistableQueue& queue) = 0;
+
+ /**
+ * Returns the number of outstanding AIO's for a given queue
+ *
+ * If 0, than all the enqueue / dequeues have been stored
+ * to disk
+ *
+ * @param queue the name of the queue to check for outstanding AIO
+ */
+ virtual uint32_t outstandingQueueAIO(const PersistableQueue& queue) = 0;
+ //@}
+
+ /**
+ * @TODO This should probably not be here - it's only here because
+ * MessageStore inherits from Recoverable... maybe move that derivation.
+ *
+ * As it is now, we don't use this. Separate recover methods are
+ * declared below for individual types, which also set up maps of
+ * messages, queues, transactions for the main store plugin to handle
+ * properly.
+ *
+ * Request recovery of queue and message state.
+ */
+ virtual void recover(qpid::broker::RecoveryManager& /*recoverer*/) {}
+
+ /**
+ * @name Methods that do the recovery of the various objects that
+ * were saved.
+ */
+ //@{
+
+ /**
+ * Recover bindings.
+ */
+ virtual void recoverConfigs(qpid::broker::RecoveryManager& recoverer) = 0;
+ virtual void recoverExchanges(qpid::broker::RecoveryManager& recoverer,
+ ExchangeMap& exchangeMap) = 0;
+ virtual void recoverQueues(qpid::broker::RecoveryManager& recoverer,
+ QueueMap& queueMap) = 0;
+ virtual void recoverBindings(qpid::broker::RecoveryManager& recoverer,
+ const ExchangeMap& exchangeMap,
+ const QueueMap& queueMap) = 0;
+ virtual void recoverMessages(qpid::broker::RecoveryManager& recoverer,
+ MessageMap& messageMap,
+ MessageQueueMap& messageQueueMap) = 0;
+ //@}
+};
+
+}} // namespace qpid::store
+
+#endif /* QPID_STORE_STORAGEPROVIDER_H */
diff --git a/cpp/src/qpid/store/StoreException.h b/cpp/src/qpid/store/StoreException.h
new file mode 100644
index 0000000000..1dc7f670ec
--- /dev/null
+++ b/cpp/src/qpid/store/StoreException.h
@@ -0,0 +1,49 @@
+#ifndef QPID_STORE_STOREEXCEPTION_H
+#define QPID_STORE_STOREEXCEPTION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <exception>
+#include <boost/format.hpp>
+#include "StorageProvider.h"
+
+namespace qpid {
+namespace store {
+
+class StoreException : public std::exception
+{
+ std::string text;
+public:
+ StoreException(const std::string& _text) : text(_text) {}
+ StoreException(const std::string& _text,
+ const StorageProvider::Exception& cause)
+ : text(_text + ": " + cause.what()) {}
+ virtual ~StoreException() throw() {}
+ virtual const char* what() const throw() { return text.c_str(); }
+};
+
+#define THROW_STORE_EXCEPTION(MESSAGE) throw qpid::store::StoreException(boost::str(boost::format("%s (%s:%d)") % (MESSAGE) % __FILE__ % __LINE__))
+#define THROW_STORE_EXCEPTION_2(MESSAGE, EXCEPTION) throw qpid::store::StoreException(boost::str(boost::format("%s (%s:%d)") % (MESSAGE) % __FILE__ % __LINE__), EXCEPTION)
+
+}} // namespace qpid::store
+
+#endif /* QPID_STORE_STOREEXCEPTION_H */
diff --git a/cpp/src/qpid/store/ms-sql/AmqpTransaction.cpp b/cpp/src/qpid/store/ms-sql/AmqpTransaction.cpp
new file mode 100644
index 0000000000..0ecfacfb4b
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/AmqpTransaction.cpp
@@ -0,0 +1,89 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "AmqpTransaction.h"
+#include "DatabaseConnection.h"
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+AmqpTransaction::AmqpTransaction(std::auto_ptr<DatabaseConnection>& _db)
+ : db(_db), transDepth(0)
+{
+}
+
+AmqpTransaction::~AmqpTransaction()
+{
+ if (transDepth > 0)
+ this->abort();
+}
+
+void
+AmqpTransaction::begin()
+{
+ _bstr_t beginCmd("BEGIN TRANSACTION");
+ _ConnectionPtr c = *db;
+ c->Execute(beginCmd, NULL, adExecuteNoRecords);
+ ++transDepth;
+}
+
+void
+AmqpTransaction::commit()
+{
+ if (transDepth > 0) {
+ _bstr_t commitCmd("COMMIT TRANSACTION");
+ _ConnectionPtr c = *db;
+ c->Execute(commitCmd, NULL, adExecuteNoRecords);
+ --transDepth;
+ }
+}
+
+void
+AmqpTransaction::abort()
+{
+ if (transDepth > 0) {
+ _bstr_t rollbackCmd("ROLLBACK TRANSACTION");
+ _ConnectionPtr c = *db;
+ c->Execute(rollbackCmd, NULL, adExecuteNoRecords);
+ transDepth = 0;
+ }
+}
+
+AmqpTPCTransaction::AmqpTPCTransaction(std::auto_ptr<DatabaseConnection>& _db,
+ const std::string& _xid)
+ : AmqpTransaction(_db), xid(_xid)
+{
+}
+
+AmqpTPCTransaction::~AmqpTPCTransaction()
+{
+}
+
+void
+AmqpTPCTransaction::prepare()
+{
+ // Intermediate transactions should have already assured integrity of
+ // the content in the database; just waiting to pull the trigger on the
+ // outermost transaction.
+}
+
+}}} // namespace qpid::store::ms_sql
diff --git a/cpp/src/qpid/store/ms-sql/AmqpTransaction.h b/cpp/src/qpid/store/ms-sql/AmqpTransaction.h
new file mode 100644
index 0000000000..9b87d0ae15
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/AmqpTransaction.h
@@ -0,0 +1,84 @@
+#ifndef QPID_STORE_MSSQL_AMQPTRANSACTION_H
+#define QPID_STORE_MSSQL_AMQPTRANSACTION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/broker/TransactionalStore.h>
+#include <string>
+#include <memory>
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+class DatabaseConnection;
+
+/**
+ * @class AmqpTransaction
+ *
+ * Class representing an AMQP transaction. This is used around a set of
+ * enqueue and dequeue operations that occur when the broker is acting
+ * on a transaction commit/abort from the client.
+ */
+class AmqpTransaction : public qpid::broker::TransactionContext {
+
+ std::auto_ptr<DatabaseConnection> db;
+
+ // Since ADO w/ SQLOLEDB can't do nested transaction via its BeginTrans(),
+ // et al, nested transactions are carried out with direct SQL commands.
+ // To ensure the state of this is known, keep track of how deeply the
+ // transactions are nested.
+ unsigned int transDepth;
+
+public:
+ AmqpTransaction(std::auto_ptr<DatabaseConnection>& _db);
+ virtual ~AmqpTransaction();
+
+ DatabaseConnection *dbConn() { return db.get(); }
+
+ void begin();
+ void commit();
+ void abort();
+};
+
+/**
+ * @class AmqpTPCTransaction
+ *
+ * Class representing a Two-Phase-Commit (TPC) AMQP transaction. This is
+ * used around a set of enqueue and dequeue operations that occur when the
+ * broker is acting on a transaction prepare/commit/abort from the client.
+ */
+class AmqpTPCTransaction : public AmqpTransaction,
+ public qpid::broker::TPCTransactionContext {
+ std::string xid;
+
+public:
+ AmqpTPCTransaction(std::auto_ptr<DatabaseConnection>& _db,
+ const std::string& _xid);
+ virtual ~AmqpTPCTransaction();
+
+ void prepare();
+};
+
+}}} // namespace qpid::store::ms_sql
+
+#endif /* QPID_STORE_MSSQL_AMQPTRANSACTION_H */
diff --git a/cpp/src/qpid/store/ms-sql/BindingRecordset.cpp b/cpp/src/qpid/store/ms-sql/BindingRecordset.cpp
new file mode 100644
index 0000000000..1dc4370312
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/BindingRecordset.cpp
@@ -0,0 +1,165 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Exception.h>
+#include <qpid/log/Statement.h>
+
+#include "BindingRecordset.h"
+#include "BlobAdapter.h"
+#include "BlobEncoder.h"
+#include "VariantHelper.h"
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+void
+BindingRecordset::removeFilter(const std::string& filter)
+{
+ rs->PutFilter (VariantHelper<std::string>(filter));
+ long recs = rs->GetRecordCount();
+ if (recs == 0)
+ return; // Nothing to do
+ while (recs > 0) {
+ // Deleting adAffectAll doesn't work as documented; go one by one.
+ rs->Delete(adAffectCurrent);
+ if (--recs > 0)
+ rs->MoveNext();
+ }
+ rs->Update();
+}
+
+void
+BindingRecordset::add(uint64_t exchangeId,
+ uint64_t queueId,
+ const std::string& routingKey,
+ const qpid::framing::FieldTable& args)
+{
+ VariantHelper<std::string> routingKeyStr(routingKey);
+ BlobEncoder blob (args); // Marshall field table to a blob
+ rs->AddNew();
+ rs->Fields->GetItem("exchangeId")->Value = exchangeId;
+ rs->Fields->GetItem("queueId")->Value = queueId;
+ rs->Fields->GetItem("routingKey")->Value = routingKeyStr;
+ rs->Fields->GetItem("fieldTableBlob")->AppendChunk(blob);
+ rs->Update();
+}
+
+void
+BindingRecordset::remove(uint64_t exchangeId,
+ uint64_t queueId,
+ const std::string& routingKey,
+ const qpid::framing::FieldTable& /*args*/)
+{
+ // Look up the affected binding.
+ std::ostringstream filter;
+ filter << "exchangeId = " << exchangeId
+ << " AND queueId = " << queueId
+ << " AND routingKey = '" << routingKey << "'" << std::ends;
+ removeFilter(filter.str());
+}
+
+void
+BindingRecordset::removeForExchange(uint64_t exchangeId)
+{
+ // Look up the affected bindings by the exchange ID
+ std::ostringstream filter;
+ filter << "exchangeId = " << exchangeId << std::ends;
+ removeFilter(filter.str());
+}
+
+void
+BindingRecordset::removeForQueue(uint64_t queueId)
+{
+ // Look up the affected bindings by the queue ID
+ std::ostringstream filter;
+ filter << "queueId = " << queueId << std::ends;
+ removeFilter(filter.str());
+}
+
+void
+BindingRecordset::recover(broker::RecoveryManager& recoverer,
+ const store::ExchangeMap& exchMap,
+ const store::QueueMap& queueMap)
+{
+ if (rs->BOF && rs->EndOfFile)
+ return; // Nothing to do
+ rs->MoveFirst();
+ Binding b;
+ IADORecordBinding *piAdoRecordBinding;
+ rs->QueryInterface(__uuidof(IADORecordBinding),
+ (LPVOID *)&piAdoRecordBinding);
+ piAdoRecordBinding->BindToRecordset(&b);
+ while (!rs->EndOfFile) {
+ long blobSize = rs->Fields->Item["fieldTableBlob"]->ActualSize;
+ BlobAdapter blob(blobSize);
+ blob = rs->Fields->Item["fieldTableBlob"]->GetChunk(blobSize);
+ store::ExchangeMap::const_iterator exch = exchMap.find(b.exchangeId);
+ if (exch == exchMap.end()) {
+ std::ostringstream msg;
+ msg << "Error recovering bindings; exchange ID " << b.exchangeId
+ << " not found in exchange map";
+ throw qpid::Exception(msg.str());
+ }
+ broker::RecoverableExchange::shared_ptr exchPtr = exch->second;
+ store::QueueMap::const_iterator q = queueMap.find(b.queueId);
+ if (q == queueMap.end()) {
+ std::ostringstream msg;
+ msg << "Error recovering bindings; queue ID " << b.queueId
+ << " not found in queue map";
+ throw qpid::Exception(msg.str());
+ }
+ broker::RecoverableQueue::shared_ptr qPtr = q->second;
+ // The recovery manager wants the queue name, so get it from the
+ // RecoverableQueue.
+ std::string key(b.routingKey);
+ exchPtr->bind(qPtr->getName(), key, blob);
+ rs->MoveNext();
+ }
+
+ piAdoRecordBinding->Release();
+}
+
+void
+BindingRecordset::dump()
+{
+ Recordset::dump();
+ if (rs->EndOfFile && rs->BOF) // No records
+ return;
+ rs->MoveFirst();
+
+ Binding b;
+ IADORecordBinding *piAdoRecordBinding;
+ rs->QueryInterface(__uuidof(IADORecordBinding),
+ (LPVOID *)&piAdoRecordBinding);
+ piAdoRecordBinding->BindToRecordset(&b);
+
+ while (VARIANT_FALSE == rs->EndOfFile) {
+ QPID_LOG(notice, "exch Id " << b.exchangeId
+ << ", q Id " << b.queueId
+ << ", k: " << b.routingKey);
+ rs->MoveNext();
+ }
+
+ piAdoRecordBinding->Release();
+}
+
+}}} // namespace qpid::store::ms_sql
diff --git a/cpp/src/qpid/store/ms-sql/BindingRecordset.h b/cpp/src/qpid/store/ms-sql/BindingRecordset.h
new file mode 100644
index 0000000000..3cb732de75
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/BindingRecordset.h
@@ -0,0 +1,88 @@
+#ifndef QPID_STORE_MSSQL_BINDINGRECORDSET_H
+#define QPID_STORE_MSSQL_BINDINGRECORDSET_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <icrsint.h>
+#include "Recordset.h"
+#include <qpid/store/StorageProvider.h>
+#include <qpid/broker/RecoveryManager.h>
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+/**
+ * @class BindingRecordset
+ *
+ * Class for the binding records.
+ */
+class BindingRecordset : public Recordset {
+
+ class Binding : public CADORecordBinding {
+ BEGIN_ADO_BINDING(Binding)
+ ADO_FIXED_LENGTH_ENTRY2(1, adBigInt, exchangeId, FALSE)
+ ADO_FIXED_LENGTH_ENTRY2(2, adBigInt, queueId, FALSE)
+ ADO_VARIABLE_LENGTH_ENTRY4(3, adVarChar, routingKey,
+ sizeof(routingKey), FALSE)
+ END_ADO_BINDING()
+
+ public:
+ uint64_t exchangeId;
+ uint64_t queueId;
+ char routingKey[256];
+ };
+
+ // Remove all records matching the specified filter/query.
+ void removeFilter(const std::string& filter);
+
+public:
+ // Add a new binding
+ void add(uint64_t exchangeId,
+ uint64_t queueId,
+ const std::string& routingKey,
+ const qpid::framing::FieldTable& args);
+
+ // Remove a specific binding
+ void remove(uint64_t exchangeId,
+ uint64_t queueId,
+ const std::string& routingKey,
+ const qpid::framing::FieldTable& args);
+
+ // Remove all bindings for the specified exchange
+ void removeForExchange(uint64_t exchangeId);
+
+ // Remove all bindings for the specified queue
+ void removeForQueue(uint64_t queueId);
+
+ // Recover bindings set using exchMap to get from Id to RecoverableExchange.
+ void recover(qpid::broker::RecoveryManager& recoverer,
+ const qpid::store::ExchangeMap& exchMap,
+ const qpid::store::QueueMap& queueMap);
+
+ // Dump table contents; useful for debugging.
+ void dump();
+};
+
+}}} // namespace qpid::store::ms_sql
+
+#endif /* QPID_STORE_MSSQL_BINDINGRECORDSET_H */
diff --git a/cpp/src/qpid/store/ms-sql/BlobAdapter.cpp b/cpp/src/qpid/store/ms-sql/BlobAdapter.cpp
new file mode 100644
index 0000000000..1889f34e41
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/BlobAdapter.cpp
@@ -0,0 +1,64 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "BlobAdapter.h"
+#include <qpid/Exception.h>
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+void
+BlobAdapter::extractBuff()
+{
+ // To give a valid Buffer back, lock the safearray, obtaining a pointer to
+ // the actual data. Record the pointer in the Buffer so the destructor
+ // knows to unlock the safearray.
+ if (buff.getPointer() == 0) {
+ char *blob;
+ SafeArrayAccessData(this->parray, (void **)&blob);
+ qpid::framing::Buffer lockedBuff(blob, buff.getSize());
+ buff = lockedBuff;
+ }
+}
+
+
+BlobAdapter::~BlobAdapter()
+{
+ // If buff's pointer is set, the safearray is locked, so unlock it
+ if (buff.getPointer() != 0)
+ SafeArrayUnaccessData(this->parray);
+}
+
+BlobAdapter::operator qpid::framing::Buffer& ()
+{
+ extractBuff();
+ return buff;
+}
+
+BlobAdapter::operator qpid::framing::FieldTable& ()
+{
+ extractBuff();
+ fields.decode(buff);
+ return fields;
+}
+
+}}} // namespace qpid::store::ms_sql
diff --git a/cpp/src/qpid/store/ms-sql/BlobAdapter.h b/cpp/src/qpid/store/ms-sql/BlobAdapter.h
new file mode 100644
index 0000000000..1c666392bc
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/BlobAdapter.h
@@ -0,0 +1,62 @@
+#ifndef QPID_STORE_MSSQL_BLOBADAPTER_H
+#define QPID_STORE_MSSQL_BLOBADAPTER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <comutil.h>
+#include <qpid/framing/Buffer.h>
+#include <qpid/framing/FieldTable.h>
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+/**
+ * @class BlobAdapter
+ *
+ * Adapter for accessing a blob (varbinary SQL field) as a qpid::framing::Buffer
+ * in an exception-safe way.
+ */
+class BlobAdapter : public _variant_t {
+private:
+ // This Buffer's pointer indicates whether or not a safearray has
+ // been locked; if it's 0, no locking was done.
+ qpid::framing::Buffer buff;
+ qpid::framing::FieldTable fields;
+
+ void extractBuff();
+
+public:
+ // Initialize with the known length of the data that will come.
+ // Assigning a _variant_t to this object will set up the array to be
+ // accessed with the operator Buffer&()
+ BlobAdapter(long blobSize) : _variant_t(), buff(0, blobSize) {}
+ ~BlobAdapter();
+ BlobAdapter& operator=(_variant_t& var_t_Src)
+ { _variant_t::operator=(var_t_Src); return *this; }
+ operator qpid::framing::Buffer& ();
+ operator qpid::framing::FieldTable& ();
+};
+
+}}} // namespace qpid::store::ms_sql
+
+#endif /* QPID_STORE_MSSQL_BLOBADAPTER_H */
diff --git a/cpp/src/qpid/store/ms-sql/BlobEncoder.cpp b/cpp/src/qpid/store/ms-sql/BlobEncoder.cpp
new file mode 100644
index 0000000000..75d3dc2d86
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/BlobEncoder.cpp
@@ -0,0 +1,133 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "BlobEncoder.h"
+#include <qpid/Exception.h>
+#include <qpid/broker/Persistable.h>
+#include <qpid/broker/PersistableMessage.h>
+#include <boost/intrusive_ptr.hpp>
+#include <memory.h>
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+template <class ITEM> void
+BlobEncoder::encode(const ITEM &item)
+{
+ SAFEARRAYBOUND bound[1] = {0, 0};
+ bound[0].cElements = item.encodedSize();
+ blob = SafeArrayCreate(VT_UI1, 1, bound);
+ if (S_OK != SafeArrayLock(blob)) {
+ SafeArrayDestroy(blob);
+ blob = 0;
+ throw qpid::Exception("Error locking blob area for persistable item");
+ }
+ try {
+ qpid::framing::Buffer buff((char *)blob->pvData, bound[0].cElements);
+ item.encode(buff);
+ }
+ catch(...) {
+ SafeArrayUnlock(blob);
+ SafeArrayDestroy(blob);
+ blob = 0;
+ throw;
+ }
+ this->vt = VT_ARRAY | VT_UI1;
+ this->parray = blob;
+ SafeArrayUnlock(blob);
+}
+
+template <> void
+BlobEncoder::encode(const boost::intrusive_ptr<qpid::broker::PersistableMessage> &item)
+{
+ // NOTE! If this code changes, verify the recovery code in MessageRecordset
+ SAFEARRAYBOUND bound[1] = {0, 0};
+ bound[0].cElements = item->encodedSize() + sizeof(uint32_t);
+ blob = SafeArrayCreate(VT_UI1, 1, bound);
+ if (S_OK != SafeArrayLock(blob)) {
+ SafeArrayDestroy(blob);
+ blob = 0;
+ throw qpid::Exception("Error locking blob area for message");
+ }
+ try {
+ uint32_t headerSize = item->encodedHeaderSize();
+ qpid::framing::Buffer buff((char *)blob->pvData, bound[0].cElements);
+ buff.putLong(headerSize);
+ item->encode(buff);
+ }
+ catch(...) {
+ SafeArrayUnlock(blob);
+ SafeArrayDestroy(blob);
+ blob = 0;
+ throw;
+ }
+ this->vt = VT_ARRAY | VT_UI1;
+ this->parray = blob;
+ SafeArrayUnlock(blob);
+}
+
+template <> void
+BlobEncoder::encode(const std::string &item)
+{
+ SAFEARRAYBOUND bound[1] = {0, 0};
+ bound[0].cElements = item.size();
+ blob = SafeArrayCreate(VT_UI1, 1, bound);
+ if (S_OK != SafeArrayLock(blob)) {
+ SafeArrayDestroy(blob);
+ blob = 0;
+ throw qpid::Exception("Error locking blob area for string");
+ }
+ memcpy_s(blob->pvData, item.size(), item.data(), item.size());
+ this->vt = VT_ARRAY | VT_UI1;
+ this->parray = blob;
+ SafeArrayUnlock(blob);
+}
+
+BlobEncoder::BlobEncoder(const qpid::broker::Persistable &item) : blob(0)
+{
+ encode(item);
+}
+
+BlobEncoder::BlobEncoder(const boost::intrusive_ptr<qpid::broker::PersistableMessage> &msg) : blob(0)
+{
+ encode(msg);
+}
+
+BlobEncoder::BlobEncoder(const qpid::framing::FieldTable &fields) : blob(0)
+{
+ encode(fields);
+}
+
+BlobEncoder::BlobEncoder(const std::string &data) : blob(0)
+{
+ encode(data);
+}
+
+BlobEncoder::~BlobEncoder()
+{
+ if (blob)
+ SafeArrayDestroy(blob);
+ blob = 0;
+ this->parray = 0;
+}
+
+}}} // namespace qpid::store::ms_sql
diff --git a/cpp/src/qpid/store/ms-sql/BlobEncoder.h b/cpp/src/qpid/store/ms-sql/BlobEncoder.h
new file mode 100644
index 0000000000..d2b56223c1
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/BlobEncoder.h
@@ -0,0 +1,61 @@
+#ifndef QPID_STORE_MSSQL_BLOBENCODER_H
+#define QPID_STORE_MSSQL_BLOBENCODER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <comutil.h>
+#include <string>
+#include <boost/intrusive_ptr.hpp>
+#include <qpid/broker/Persistable.h>
+#include <qpid/broker/PersistableMessage.h>
+#include <qpid/framing/Buffer.h>
+#include <qpid/framing/FieldTable.h>
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+/**
+ * @class BlobEncoder
+ *
+ * Encodes a blob (varbinary) field from a qpid::broker::Persistable or a
+ * qpid::framing::FieldTable (both of which can be encoded to
+ * qpid::framing::Buffer) so it can be passed to ADO methods for writing
+ * to the database.
+ */
+class BlobEncoder : public _variant_t {
+private:
+ SAFEARRAY *blob;
+
+ template <class ITEM> void encode(const ITEM &item);
+
+public:
+ BlobEncoder(const qpid::broker::Persistable &item);
+ BlobEncoder(const boost::intrusive_ptr<qpid::broker::PersistableMessage> &msg);
+ BlobEncoder(const qpid::framing::FieldTable &fields);
+ BlobEncoder(const std::string& data);
+ ~BlobEncoder();
+};
+
+}}} // namespace qpid::store::ms_sql
+
+#endif /* QPID_STORE_MSSQL_BLOBENCODER_H */
diff --git a/cpp/src/qpid/store/ms-sql/BlobRecordset.cpp b/cpp/src/qpid/store/ms-sql/BlobRecordset.cpp
new file mode 100644
index 0000000000..ef1757dbad
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/BlobRecordset.cpp
@@ -0,0 +1,86 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/Exception.h>
+#include <qpid/log/Statement.h>
+
+#include "BlobRecordset.h"
+#include "BlobEncoder.h"
+#include "VariantHelper.h"
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+void
+BlobRecordset::add(const qpid::broker::Persistable& item)
+{
+ BlobEncoder blob (item); // Marshall item info to a blob
+ rs->AddNew();
+ rs->Fields->GetItem("fieldTableBlob")->AppendChunk(blob);
+ rs->Update();
+ uint64_t id = rs->Fields->Item["persistenceId"]->Value;
+ item.setPersistenceId(id);
+}
+
+void
+BlobRecordset::remove(uint64_t id)
+{
+ // Look up the item by its persistenceId
+ std::ostringstream filter;
+ filter << "persistenceId = " << id << std::ends;
+ rs->PutFilter (VariantHelper<std::string>(filter.str()));
+ if (!rs->EndOfFile) {
+ // Delete the record
+ rs->Delete(adAffectCurrent);
+ rs->Update();
+ }
+}
+
+void
+BlobRecordset::remove(const qpid::broker::Persistable& item)
+{
+ remove(item.getPersistenceId());
+}
+
+void
+BlobRecordset::dump()
+{
+ Recordset::dump();
+#if 1
+ if (rs->EndOfFile && rs->BOF) // No records
+ return;
+
+ rs->MoveFirst();
+ while (!rs->EndOfFile) {
+ uint64_t id = rs->Fields->Item["persistenceId"]->Value;
+ QPID_LOG(notice, " -> " << id);
+ rs->MoveNext();
+ }
+#else
+ for (Iterator iter = begin(); iter != end(); ++iter) {
+ uint64_t id = *iter.first;
+ QPID_LOG(notice, " -> " << id);
+ }
+#endif
+}
+
+}}} // namespace qpid::store::ms_sql
diff --git a/cpp/src/qpid/store/ms-sql/BlobRecordset.h b/cpp/src/qpid/store/ms-sql/BlobRecordset.h
new file mode 100644
index 0000000000..4d1c338746
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/BlobRecordset.h
@@ -0,0 +1,54 @@
+#ifndef QPID_STORE_MSSQL_BLOBRECORDSET_H
+#define QPID_STORE_MSSQL_BLOBRECORDSET_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Recordset.h"
+#include <qpid/broker/Persistable.h>
+#include <string>
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+/**
+ * @class BlobRecordset
+ *
+ * Class for the "blob" records that record an id, varbinary(max) pair.
+ */
+class BlobRecordset : public Recordset {
+protected:
+
+public:
+ void add(const qpid::broker::Persistable& item);
+
+ // Remove a record given its Id.
+ void remove(uint64_t id);
+ void remove(const qpid::broker::Persistable& item);
+
+ // Dump table contents; useful for debugging.
+ void dump();
+};
+
+}}} // namespace qpid::store::ms_sql
+
+#endif /* QPID_STORE_MSSQL_BLOBRECORDSET_H */
diff --git a/cpp/src/qpid/store/ms-sql/DatabaseConnection.cpp b/cpp/src/qpid/store/ms-sql/DatabaseConnection.cpp
new file mode 100644
index 0000000000..34edec8acd
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/DatabaseConnection.cpp
@@ -0,0 +1,70 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "DatabaseConnection.h"
+#include "Exception.h"
+#include <comdef.h>
+namespace {
+inline void TESTHR(HRESULT x) {if FAILED(x) _com_issue_error(x);};
+}
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+DatabaseConnection::DatabaseConnection() : conn(0)
+{
+}
+
+DatabaseConnection::~DatabaseConnection()
+{
+ close();
+}
+
+void
+DatabaseConnection::open(const std::string& connectString,
+ const std::string& dbName)
+{
+ if (conn && conn->State == adStateOpen)
+ return;
+ std::string adoConnect = "Provider=SQLOLEDB;" + connectString;
+ try {
+ TESTHR(conn.CreateInstance(__uuidof(Connection)));
+ conn->ConnectionString = adoConnect.c_str();
+ conn->Open("", "", "", adConnectUnspecified);
+ if (dbName.length() > 0)
+ conn->DefaultDatabase = dbName.c_str();
+ }
+ catch(_com_error &e) {
+ close();
+ throw ADOException("MSSQL can't open " + dbName + " at " + adoConnect, e);
+ }
+}
+
+void
+DatabaseConnection::close()
+{
+ if (conn && conn->State == adStateOpen)
+ conn->Close();
+ conn = 0;
+}
+
+}}} // namespace qpid::store::ms_sql
diff --git a/cpp/src/qpid/store/ms-sql/DatabaseConnection.h b/cpp/src/qpid/store/ms-sql/DatabaseConnection.h
new file mode 100644
index 0000000000..2b8bbffa90
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/DatabaseConnection.h
@@ -0,0 +1,62 @@
+#ifndef QPID_STORE_MSSQL_DATABASECONNECTION_H
+#define QPID_STORE_MSSQL_DATABASECONNECTION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+// Bring in ADO 2.8 (yes, I know it says "15", but that's it...)
+#import "C:\Program Files\Common Files\System\ado\msado15.dll" \
+ no_namespace rename("EOF", "EndOfFile")
+
+#include <string>
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+/**
+ * @class DatabaseConnection
+ *
+ * Represents a connection to the SQL database. This class wraps the
+ * needed _ConnectionPtr for ADO as well as the needed COM initialization
+ * and cleanup that each thread requires. It is expected that this class
+ * will be maintained in thread-specific storage so it has no locks.
+ */
+class DatabaseConnection {
+protected:
+ _ConnectionPtr conn;
+
+public:
+ DatabaseConnection();
+ ~DatabaseConnection();
+ void open(const std::string& connectString,
+ const std::string& dbName = "");
+ void close();
+ operator _ConnectionPtr () { return conn; }
+
+ void beginTransaction() { conn->BeginTrans(); }
+ void commitTransaction() {conn->CommitTrans(); }
+ void rollbackTransaction() { conn->RollbackTrans(); }
+};
+
+}}} // namespace qpid::store::ms_sql
+
+#endif /* QPID_STORE_MSSQL_DATABASECONNECTION_H */
diff --git a/cpp/src/qpid/store/ms-sql/Exception.h b/cpp/src/qpid/store/ms-sql/Exception.h
new file mode 100644
index 0000000000..0da4b24210
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/Exception.h
@@ -0,0 +1,62 @@
+#ifndef QPID_STORE_MSSQL_EXCEPTION_H
+#define QPID_STORE_MSSQL_EXCEPTION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <string>
+#include <comdef.h>
+#include <qpid/store/StorageProvider.h>
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+class Exception : public qpid::store::StorageProvider::Exception
+{
+protected:
+ std::string text;
+public:
+ Exception(const std::string& _text) : text(_text) {}
+ virtual ~Exception() {}
+ virtual const char* what() const throw() { return text.c_str(); }
+};
+
+class ADOException : public Exception
+{
+public:
+ ADOException(const std::string& _text, _com_error &e)
+ : Exception(_text) {
+ text += ": ";
+ text += e.ErrorMessage();
+ IErrorInfo *i = e.ErrorInfo();
+ if (i != 0) {
+ text += ": ";
+ _bstr_t wmsg = e.Description();
+ text += (const char *)wmsg;
+ i->Release();
+ }
+ }
+};
+
+}}} // namespace qpid::store::ms_sql
+
+#endif /* QPID_STORE_MSSQL_EXCEPTION_H */
diff --git a/cpp/src/qpid/store/ms-sql/MSSqlProvider.cpp b/cpp/src/qpid/store/ms-sql/MSSqlProvider.cpp
new file mode 100644
index 0000000000..a26df59df7
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/MSSqlProvider.cpp
@@ -0,0 +1,1061 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <stdlib.h>
+#include <string>
+#include <windows.h>
+#include <qpid/broker/RecoverableQueue.h>
+#include <qpid/log/Statement.h>
+#include <qpid/store/MessageStorePlugin.h>
+#include <qpid/store/StorageProvider.h>
+#include "AmqpTransaction.h"
+#include "BlobAdapter.h"
+#include "BlobRecordset.h"
+#include "BindingRecordset.h"
+#include "MessageMapRecordset.h"
+#include "MessageRecordset.h"
+#include "DatabaseConnection.h"
+#include "Exception.h"
+#include "State.h"
+#include "VariantHelper.h"
+
+// Bring in ADO 2.8 (yes, I know it says "15", but that's it...)
+#import "C:\Program Files\Common Files\System\ado\msado15.dll" \
+ no_namespace rename("EOF", "EndOfFile")
+#include <comdef.h>
+namespace {
+inline void TESTHR(HRESULT x) {if FAILED(x) _com_issue_error(x);};
+
+// Table names
+const std::string TblBinding("tblBinding");
+const std::string TblConfig("tblConfig");
+const std::string TblExchange("tblExchange");
+const std::string TblMessage("tblMessage");
+const std::string TblMessageMap("tblMessageMap");
+const std::string TblQueue("tblQueue");
+}
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+/**
+ * @class MSSqlProvider
+ *
+ * Implements a qpid::store::StorageProvider that uses Microsoft SQL Server as
+ * the backend data store for Qpid.
+ */
+class MSSqlProvider : public qpid::store::StorageProvider
+{
+protected:
+ void finalizeMe();
+
+ void dump();
+
+public:
+ MSSqlProvider();
+ ~MSSqlProvider();
+
+ virtual qpid::Options* getOptions() { return &options; }
+
+ virtual void earlyInitialize (Plugin::Target& target);
+ virtual void initialize(Plugin::Target& target);
+
+ /**
+ * Receive notification that this provider is the one that will actively
+ * handle provider storage for the target. If the provider is to be used,
+ * this method will be called after earlyInitialize() and before any
+ * recovery operations (recovery, in turn, precedes call to initialize()).
+ */
+ virtual void activate(MessageStorePlugin &store);
+
+ /**
+ * @name Methods inherited from qpid::broker::MessageStore
+ */
+ //@{
+ /**
+ * If called after init() but before recovery, will discard the database
+ * and reinitialize using an empty store dir. If @a pushDownStoreFiles
+ * is true, the content of the store dir will be moved to a backup dir
+ * inside the store dir. This is used when cluster nodes recover and must
+ * get thier content from a cluster sync rather than directly fromt the
+ * store.
+ *
+ * @param pushDownStoreFiles If true, will move content of the store dir
+ * into a subdir, leaving the store dir
+ * otherwise empty.
+ */
+ virtual void truncateInit(const bool pushDownStoreFiles = false);
+
+ /**
+ * Record the existence of a durable queue
+ */
+ virtual void create(PersistableQueue& queue,
+ const qpid::framing::FieldTable& args);
+ /**
+ * Destroy a durable queue
+ */
+ virtual void destroy(PersistableQueue& queue);
+
+ /**
+ * Record the existence of a durable exchange
+ */
+ virtual void create(const PersistableExchange& exchange,
+ const qpid::framing::FieldTable& args);
+ /**
+ * Destroy a durable exchange
+ */
+ virtual void destroy(const PersistableExchange& exchange);
+
+ /**
+ * Record a binding
+ */
+ virtual void bind(const PersistableExchange& exchange,
+ const PersistableQueue& queue,
+ const std::string& key,
+ const qpid::framing::FieldTable& args);
+
+ /**
+ * Forget a binding
+ */
+ virtual void unbind(const PersistableExchange& exchange,
+ const PersistableQueue& queue,
+ const std::string& key,
+ const qpid::framing::FieldTable& args);
+
+ /**
+ * Record generic durable configuration
+ */
+ virtual void create(const PersistableConfig& config);
+
+ /**
+ * Destroy generic durable configuration
+ */
+ virtual void destroy(const PersistableConfig& config);
+
+ /**
+ * Stores a messages before it has been enqueued
+ * (enqueueing automatically stores the message so this is
+ * only required if storage is required prior to that
+ * point). If the message has not yet been stored it will
+ * store the headers as well as any content passed in. A
+ * persistence id will be set on the message which can be
+ * used to load the content or to append to it.
+ */
+ virtual void stage(const boost::intrusive_ptr<PersistableMessage>& msg);
+
+ /**
+ * Destroys a previously staged message. This only needs
+ * to be called if the message is never enqueued. (Once
+ * enqueued, deletion will be automatic when the message
+ * is dequeued from all queues it was enqueued onto).
+ */
+ virtual void destroy(PersistableMessage& msg);
+
+ /**
+ * Appends content to a previously staged message
+ */
+ virtual void appendContent(const boost::intrusive_ptr<const PersistableMessage>& msg,
+ const std::string& data);
+
+ /**
+ * Loads (a section) of content data for the specified
+ * message (previously stored through a call to stage or
+ * enqueue) into data. The offset refers to the content
+ * only (i.e. an offset of 0 implies that the start of the
+ * content should be loaded, not the headers or related
+ * meta-data).
+ */
+ virtual void loadContent(const qpid::broker::PersistableQueue& queue,
+ const boost::intrusive_ptr<const PersistableMessage>& msg,
+ std::string& data,
+ uint64_t offset,
+ uint32_t length);
+
+ /**
+ * Enqueues a message, storing the message if it has not
+ * been previously stored and recording that the given
+ * message is on the given queue.
+ *
+ * Note: that this is async so the return of the function does
+ * not mean the opperation is complete.
+ *
+ * @param msg the message to enqueue
+ * @param queue the name of the queue onto which it is to be enqueued
+ * @param xid (a pointer to) an identifier of the
+ * distributed transaction in which the operation takes
+ * place or null for 'local' transactions
+ */
+ virtual void enqueue(qpid::broker::TransactionContext* ctxt,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue);
+
+ /**
+ * Dequeues a message, recording that the given message is
+ * no longer on the given queue and deleting the message
+ * if it is no longer on any other queue.
+ *
+ * Note: that this is async so the return of the function does
+ * not mean the opperation is complete.
+ *
+ * @param msg the message to dequeue
+ * @param queue the name of the queue from which it is to be dequeued
+ * @param xid (a pointer to) an identifier of the
+ * distributed transaction in which the operation takes
+ * place or null for 'local' transactions
+ */
+ virtual void dequeue(qpid::broker::TransactionContext* ctxt,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue);
+
+ /**
+ * Flushes all async messages to disk for the specified queue
+ *
+ * Note: this is a no-op for this provider.
+ *
+ * @param queue the name of the queue from which it is to be dequeued
+ */
+ virtual void flush(const PersistableQueue& queue) {};
+
+ /**
+ * Returns the number of outstanding AIO's for a given queue
+ *
+ * If 0, than all the enqueue / dequeues have been stored
+ * to disk
+ *
+ * @param queue the name of the queue to check for outstanding AIO
+ */
+ virtual uint32_t outstandingQueueAIO(const PersistableQueue& queue)
+ {return 0;}
+ //@}
+
+ /**
+ * @name Methods inherited from qpid::broker::TransactionalStore
+ */
+ //@{
+ virtual std::auto_ptr<qpid::broker::TransactionContext> begin();
+ virtual std::auto_ptr<qpid::broker::TPCTransactionContext> begin(const std::string& xid);
+ virtual void prepare(qpid::broker::TPCTransactionContext& txn);
+ virtual void commit(qpid::broker::TransactionContext& txn);
+ virtual void abort(qpid::broker::TransactionContext& txn);
+
+ // @TODO This maybe should not be in TransactionalStore
+ virtual void collectPreparedXids(std::set<std::string>& xids) {}
+ //@}
+
+ virtual void recoverConfigs(qpid::broker::RecoveryManager& recoverer);
+ virtual void recoverExchanges(qpid::broker::RecoveryManager& recoverer,
+ ExchangeMap& exchangeMap);
+ virtual void recoverQueues(qpid::broker::RecoveryManager& recoverer,
+ QueueMap& queueMap);
+ virtual void recoverBindings(qpid::broker::RecoveryManager& recoverer,
+ const ExchangeMap& exchangeMap,
+ const QueueMap& queueMap);
+ virtual void recoverMessages(qpid::broker::RecoveryManager& recoverer,
+ MessageMap& messageMap,
+ MessageQueueMap& messageQueueMap);
+
+private:
+ struct ProviderOptions : public qpid::Options
+ {
+ std::string connectString;
+ std::string catalogName;
+
+ ProviderOptions(const std::string &name)
+ : qpid::Options(name),
+ catalogName("QpidStore")
+ {
+ const enum { NAMELEN = MAX_COMPUTERNAME_LENGTH + 1 };
+ TCHAR myName[NAMELEN];
+ DWORD myNameLen = NAMELEN;
+ GetComputerName(myName, &myNameLen);
+ connectString = "Data Source=";
+ connectString += myName;
+ connectString += "\\SQLEXPRESS;Integrated Security=SSPI";
+ addOptions()
+ ("connect",
+ qpid::optValue(connectString, "STRING"),
+ "Connection string for the database to use. Will prepend "
+ "Provider=SQLOLEDB;")
+ ("catalog",
+ qpid::optValue(catalogName, "DB NAME"),
+ "Catalog (database) name")
+ ;
+ }
+ };
+ ProviderOptions options;
+
+ // Each thread has a separate connection to the database and also needs
+ // to manage its COM initialize/finalize individually. This is done by
+ // keeping a thread-specific State.
+ boost::thread_specific_ptr<State> dbState;
+
+ State *initState();
+ DatabaseConnection *initConnection(void);
+ void createDb(_ConnectionPtr conn, const std::string &name);
+};
+
+static MSSqlProvider static_instance_registers_plugin;
+
+void
+MSSqlProvider::finalizeMe()
+{
+ dbState.reset();
+}
+
+MSSqlProvider::MSSqlProvider()
+ : options("MS SQL Provider options")
+{
+}
+
+MSSqlProvider::~MSSqlProvider()
+{
+}
+
+void
+MSSqlProvider::earlyInitialize(Plugin::Target &target)
+{
+ MessageStorePlugin *store = dynamic_cast<MessageStorePlugin *>(&target);
+ if (store) {
+ // If the database init fails, report it and don't register; give
+ // the rest of the broker a chance to run.
+ //
+ // Don't try to initConnection() since that will fail if the
+ // database doesn't exist. Instead, try to open a connection without
+ // a database name, then search for the database. There's still a
+ // chance this provider won't be selected for the store too, so be
+ // be sure to close the database connection before return to avoid
+ // leaving a connection up that will not be used.
+ try {
+ initState(); // This initializes COM
+ std::auto_ptr<DatabaseConnection> db(new DatabaseConnection());
+ db->open(options.connectString, "");
+ _ConnectionPtr conn(*db);
+ _RecordsetPtr pCatalogs = NULL;
+ VariantHelper<std::string> catalogName(options.catalogName);
+ pCatalogs = conn->OpenSchema(adSchemaCatalogs, catalogName);
+ if (pCatalogs->EndOfFile) {
+ // Database doesn't exist; create it
+ QPID_LOG(notice,
+ "MSSQL: Creating database " + options.catalogName);
+ createDb(conn, options.catalogName);
+ }
+ else {
+ QPID_LOG(notice,
+ "MSSQL: Database located: " + options.catalogName);
+ }
+ if (pCatalogs) {
+ if (pCatalogs->State == adStateOpen)
+ pCatalogs->Close();
+ pCatalogs = 0;
+ }
+ db->close();
+ store->providerAvailable("MSSQL", this);
+ }
+ catch (qpid::Exception &e) {
+ QPID_LOG(error, e.what());
+ return;
+ }
+ store->addFinalizer(boost::bind(&MSSqlProvider::finalizeMe, this));
+ }
+}
+
+void
+MSSqlProvider::initialize(Plugin::Target& target)
+{
+}
+
+void
+MSSqlProvider::activate(MessageStorePlugin &store)
+{
+ QPID_LOG(info, "MS SQL Provider is up");
+}
+
+void
+MSSqlProvider::truncateInit(const bool pushDownStoreFiles)
+{
+}
+
+void
+MSSqlProvider::create(PersistableQueue& queue,
+ const qpid::framing::FieldTable& /*args needed for jrnl*/)
+{
+ DatabaseConnection *db = initConnection();
+ BlobRecordset rsQueues;
+ try {
+ db->beginTransaction();
+ rsQueues.open(db, TblQueue);
+ rsQueues.add(queue);
+ db->commitTransaction();
+ }
+ catch(_com_error &e) {
+ db->rollbackTransaction();
+ throw ADOException("Error creating queue " + queue.getName(), e);
+ }
+}
+
+/**
+ * Destroy a durable queue
+ */
+void
+MSSqlProvider::destroy(PersistableQueue& queue)
+{
+ // MessageDeleter class for use with for_each, below.
+ class MessageDeleter {
+ BlobRecordset& msgs;
+ public:
+ explicit MessageDeleter(BlobRecordset& _msgs) : msgs(_msgs) {}
+ void operator()(uint64_t msgId) { msgs.remove(msgId); }
+ };
+
+ DatabaseConnection *db = initConnection();
+ BlobRecordset rsQueues;
+ BindingRecordset rsBindings;
+ MessageRecordset rsMessages;
+ MessageMapRecordset rsMessageMaps;
+ try {
+ db->beginTransaction();
+ rsQueues.open(db, TblQueue);
+ rsBindings.open(db, TblBinding);
+ rsMessages.open(db, TblMessage);
+ rsMessageMaps.open(db, TblMessageMap);
+ // Remove bindings first; the queue IDs can't be ripped out from
+ // under the references in the bindings table. Then remove the
+ // message->queue entries for the queue, also because the queue can't
+ // be deleted while there are references to it. If there are messages
+ // orphaned by removing the queue references, those messages can
+ // also be deleted. Lastly, the queue record can be removed.
+ rsBindings.removeForQueue(queue.getPersistenceId());
+ std::vector<uint64_t> orphans;
+ rsMessageMaps.removeForQueue(queue.getPersistenceId(), orphans);
+ std::for_each(orphans.begin(), orphans.end(),
+ MessageDeleter(rsMessages));
+ rsQueues.remove(queue);
+ db->commitTransaction();
+ }
+ catch(_com_error &e) {
+ db->rollbackTransaction();
+ throw ADOException("Error deleting queue " + queue.getName(), e);
+ }
+}
+
+/**
+ * Record the existence of a durable exchange
+ */
+void
+MSSqlProvider::create(const PersistableExchange& exchange,
+ const qpid::framing::FieldTable& args)
+{
+ DatabaseConnection *db = initConnection();
+ BlobRecordset rsExchanges;
+ try {
+ db->beginTransaction();
+ rsExchanges.open(db, TblExchange);
+ rsExchanges.add(exchange);
+ db->commitTransaction();
+ }
+ catch(_com_error &e) {
+ db->rollbackTransaction();
+ throw ADOException("Error creating exchange " + exchange.getName(), e);
+ }
+}
+
+/**
+ * Destroy a durable exchange
+ */
+void
+MSSqlProvider::destroy(const PersistableExchange& exchange)
+{
+ DatabaseConnection *db = initConnection();
+ BlobRecordset rsExchanges;
+ BindingRecordset rsBindings;
+ try {
+ db->beginTransaction();
+ rsExchanges.open(db, TblExchange);
+ rsBindings.open(db, TblBinding);
+ // Remove bindings first; the exchange IDs can't be ripped out from
+ // under the references in the bindings table.
+ rsBindings.removeForExchange(exchange.getPersistenceId());
+ rsExchanges.remove(exchange);
+ db->commitTransaction();
+ }
+ catch(_com_error &e) {
+ db->rollbackTransaction();
+ throw ADOException("Error deleting exchange " + exchange.getName(), e);
+ }
+}
+
+/**
+ * Record a binding
+ */
+void
+MSSqlProvider::bind(const PersistableExchange& exchange,
+ const PersistableQueue& queue,
+ const std::string& key,
+ const qpid::framing::FieldTable& args)
+{
+ DatabaseConnection *db = initConnection();
+ BindingRecordset rsBindings;
+ try {
+ db->beginTransaction();
+ rsBindings.open(db, TblBinding);
+ rsBindings.add(exchange.getPersistenceId(),
+ queue.getPersistenceId(),
+ key,
+ args);
+ db->commitTransaction();
+ }
+ catch(_com_error &e) {
+ db->rollbackTransaction();
+ throw ADOException("Error binding exchange " + exchange.getName() +
+ " to queue " + queue.getName(), e);
+ }
+}
+
+/**
+ * Forget a binding
+ */
+void
+MSSqlProvider::unbind(const PersistableExchange& exchange,
+ const PersistableQueue& queue,
+ const std::string& key,
+ const qpid::framing::FieldTable& args)
+{
+ DatabaseConnection *db = initConnection();
+ BindingRecordset rsBindings;
+ try {
+ db->beginTransaction();
+ rsBindings.open(db, TblBinding);
+ rsBindings.remove(exchange.getPersistenceId(),
+ queue.getPersistenceId(),
+ key,
+ args);
+ db->commitTransaction();
+ }
+ catch(_com_error &e) {
+ db->rollbackTransaction();
+ throw ADOException("Error unbinding exchange " + exchange.getName() +
+ " from queue " + queue.getName(), e);
+ }
+}
+
+/**
+ * Record generic durable configuration
+ */
+void
+MSSqlProvider::create(const PersistableConfig& config)
+{
+ DatabaseConnection *db = initConnection();
+ BlobRecordset rsConfigs;
+ try {
+ db->beginTransaction();
+ rsConfigs.open(db, TblConfig);
+ rsConfigs.add(config);
+ db->commitTransaction();
+ }
+ catch(_com_error &e) {
+ db->rollbackTransaction();
+ throw ADOException("Error creating config " + config.getName(), e);
+ }
+}
+
+/**
+ * Destroy generic durable configuration
+ */
+void
+MSSqlProvider::destroy(const PersistableConfig& config)
+{
+ DatabaseConnection *db = initConnection();
+ BlobRecordset rsConfigs;
+ try {
+ db->beginTransaction();
+ rsConfigs.open(db, TblConfig);
+ rsConfigs.remove(config);
+ db->commitTransaction();
+ }
+ catch(_com_error &e) {
+ db->rollbackTransaction();
+ throw ADOException("Error deleting config " + config.getName(), e);
+ }
+}
+
+/**
+ * Stores a messages before it has been enqueued
+ * (enqueueing automatically stores the message so this is
+ * only required if storage is required prior to that
+ * point). If the message has not yet been stored it will
+ * store the headers as well as any content passed in. A
+ * persistence id will be set on the message which can be
+ * used to load the content or to append to it.
+ */
+void
+MSSqlProvider::stage(const boost::intrusive_ptr<PersistableMessage>& msg)
+{
+ DatabaseConnection *db = initConnection();
+ MessageRecordset rsMessages;
+ try {
+ db->beginTransaction();
+ rsMessages.open(db, TblMessage);
+ rsMessages.add(msg);
+ db->commitTransaction();
+ }
+ catch(_com_error &e) {
+ db->rollbackTransaction();
+ throw ADOException("Error staging message", e);
+ }
+}
+
+/**
+ * Destroys a previously staged message. This only needs
+ * to be called if the message is never enqueued. (Once
+ * enqueued, deletion will be automatic when the message
+ * is dequeued from all queues it was enqueued onto).
+ */
+void
+MSSqlProvider::destroy(PersistableMessage& msg)
+{
+ DatabaseConnection *db = initConnection();
+ BlobRecordset rsMessages;
+ try {
+ db->beginTransaction();
+ rsMessages.open(db, TblMessage);
+ rsMessages.remove(msg);
+ db->commitTransaction();
+ }
+ catch(_com_error &e) {
+ db->rollbackTransaction();
+ throw ADOException("Error deleting message", e);
+ }
+}
+
+/**
+ * Appends content to a previously staged message
+ */
+void
+MSSqlProvider::appendContent(const boost::intrusive_ptr<const PersistableMessage>& msg,
+ const std::string& data)
+{
+ DatabaseConnection *db = initConnection();
+ MessageRecordset rsMessages;
+ try {
+ db->beginTransaction();
+ rsMessages.open(db, TblMessage);
+ rsMessages.append(msg, data);
+ db->commitTransaction();
+ }
+ catch(_com_error &e) {
+ db->rollbackTransaction();
+ throw ADOException("Error appending to message", e);
+ }
+}
+
+/**
+ * Loads (a section) of content data for the specified
+ * message (previously stored through a call to stage or
+ * enqueue) into data. The offset refers to the content
+ * only (i.e. an offset of 0 implies that the start of the
+ * content should be loaded, not the headers or related
+ * meta-data).
+ */
+void
+MSSqlProvider::loadContent(const qpid::broker::PersistableQueue& /*queue*/,
+ const boost::intrusive_ptr<const PersistableMessage>& msg,
+ std::string& data,
+ uint64_t offset,
+ uint32_t length)
+{
+ // SQL store keeps all messages in one table, so we don't need the
+ // queue reference.
+ DatabaseConnection *db = initConnection();
+ MessageRecordset rsMessages;
+ try {
+ rsMessages.open(db, TblMessage);
+ rsMessages.loadContent(msg, data, offset, length);
+ }
+ catch(_com_error &e) {
+ throw ADOException("Error loading message content", e);
+ }
+}
+
+/**
+ * Enqueues a message, storing the message if it has not
+ * been previously stored and recording that the given
+ * message is on the given queue.
+ *
+ * @param ctxt The transaction context under which this enqueue happens.
+ * @param msg The message to enqueue
+ * @param queue the name of the queue onto which it is to be enqueued
+ */
+void
+MSSqlProvider::enqueue(qpid::broker::TransactionContext* ctxt,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue)
+{
+ // If this enqueue is in the context of a transaction, use the specified
+ // transaction to nest a new transaction for this operation. However, if
+ // this is not in the context of a transaction, then just use the thread's
+ // DatabaseConnection with a ADO transaction.
+ DatabaseConnection *db = 0;
+ AmqpTransaction *atxn = dynamic_cast<AmqpTransaction*> (ctxt);
+ if (atxn == 0) {
+ db = initConnection();
+ db->beginTransaction();
+ }
+ else {
+ (void)initState(); // Ensure this thread is initialized
+ db = atxn->dbConn();
+ try {
+ atxn->begin();
+ }
+ catch(_com_error &e) {
+ throw ADOException("Error queuing message", e);
+ }
+ }
+
+ MessageRecordset rsMessages;
+ MessageMapRecordset rsMap;
+ try {
+ if (msg->getPersistenceId() == 0) { // Message itself not yet saved
+ rsMessages.open(db, TblMessage);
+ rsMessages.add(msg);
+ }
+ rsMap.open(db, TblMessageMap);
+ rsMap.add(msg->getPersistenceId(), queue.getPersistenceId());
+ if (atxn)
+ atxn->commit();
+ else
+ db->commitTransaction();
+ }
+ catch(_com_error &e) {
+ if (atxn)
+ atxn->abort();
+ else
+ db->rollbackTransaction();
+ throw ADOException("Error queuing message", e);
+ }
+ msg->enqueueComplete();
+}
+
+/**
+ * Dequeues a message, recording that the given message is
+ * no longer on the given queue and deleting the message
+ * if it is no longer on any other queue.
+ *
+ * @param ctxt The transaction context under which this dequeue happens.
+ * @param msg The message to dequeue
+ * @param queue The queue from which it is to be dequeued
+ */
+void
+MSSqlProvider::dequeue(qpid::broker::TransactionContext* ctxt,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue)
+{
+ // If this dequeue is in the context of a transaction, use the specified
+ // transaction to nest a new transaction for this operation. However, if
+ // this is not in the context of a transaction, then just use the thread's
+ // DatabaseConnection with a ADO transaction.
+ DatabaseConnection *db = 0;
+ AmqpTransaction *atxn = dynamic_cast<AmqpTransaction*> (ctxt);
+ if (atxn == 0) {
+ db = initConnection();
+ db->beginTransaction();
+ }
+ else {
+ (void)initState(); // Ensure this thread is initialized
+ db = atxn->dbConn();
+ try {
+ atxn->begin();
+ }
+ catch(_com_error &e) {
+ throw ADOException("Error queuing message", e);
+ }
+ }
+
+ MessageMapRecordset rsMap;
+ MessageRecordset rsMessages;
+ try {
+ rsMap.open(db, TblMessageMap);
+ bool more = rsMap.remove(msg->getPersistenceId(),
+ queue.getPersistenceId());
+ if (!more) {
+ rsMessages.open(db, TblMessage);
+ rsMessages.remove(msg);
+ }
+ if (atxn)
+ atxn->commit();
+ else
+ db->commitTransaction();
+ }
+ catch(_com_error &e) {
+ if (atxn)
+ atxn->abort();
+ else
+ db->rollbackTransaction();
+ throw ADOException("Error dequeuing message", e);
+ }
+ msg->dequeueComplete();
+}
+
+std::auto_ptr<qpid::broker::TransactionContext>
+MSSqlProvider::begin()
+{
+ (void)initState(); // Ensure this thread is initialized
+
+ // Transactions are associated with the Connection, so this transaction
+ // context needs its own connection. At the time of writing, single-phase
+ // transactions are dealt with completely on one thread, so we really
+ // could just use the thread-specific DatabaseConnection for this.
+ // However, that would introduce an ugly, hidden coupling, so play
+ // it safe and handle this just like a TPC transaction, which actually
+ // can be prepared and committed/aborted from different threads,
+ // making it a bad idea to try using the thread-local DatabaseConnection.
+ std::auto_ptr<DatabaseConnection> db(new DatabaseConnection);
+ db->open(options.connectString, options.catalogName);
+ std::auto_ptr<AmqpTransaction> tx(new AmqpTransaction(db));
+ tx->begin();
+ std::auto_ptr<qpid::broker::TransactionContext> tc(tx);
+ return tc;
+}
+
+std::auto_ptr<qpid::broker::TPCTransactionContext>
+MSSqlProvider::begin(const std::string& xid)
+{
+ (void)initState(); // Ensure this thread is initialized
+ std::auto_ptr<DatabaseConnection> db(new DatabaseConnection);
+ db->open(options.connectString, options.catalogName);
+ std::auto_ptr<AmqpTPCTransaction> tx(new AmqpTPCTransaction(db, xid));
+ tx->begin();
+ std::auto_ptr<qpid::broker::TPCTransactionContext> tc(tx);
+ return tc;
+}
+
+void
+MSSqlProvider::prepare(qpid::broker::TPCTransactionContext& txn)
+{
+ // The inner transactions used for the components of the TPC are done;
+ // nothing else to do but wait for the commit.
+}
+
+void
+MSSqlProvider::commit(qpid::broker::TransactionContext& txn)
+{
+ (void)initState(); // Ensure this thread is initialized
+ AmqpTransaction *atxn = dynamic_cast<AmqpTransaction*> (&txn);
+ if (atxn == 0)
+ throw qpid::broker::InvalidTransactionContextException();
+ atxn->commit();
+}
+
+void
+MSSqlProvider::abort(qpid::broker::TransactionContext& txn)
+{
+ (void)initState(); // Ensure this thread is initialized
+ AmqpTransaction *atxn = dynamic_cast<AmqpTransaction*> (&txn);
+ if (atxn == 0)
+ throw qpid::broker::InvalidTransactionContextException();
+ atxn->abort();
+}
+
+// @TODO Much of this recovery code is way too similar... refactor to
+// a recover template method on BlobRecordset.
+
+void
+MSSqlProvider::recoverConfigs(qpid::broker::RecoveryManager& recoverer)
+{
+ DatabaseConnection *db = initConnection();
+ BlobRecordset rsConfigs;
+ rsConfigs.open(db, TblConfig);
+ _RecordsetPtr p = (_RecordsetPtr)rsConfigs;
+ if (p->BOF && p->EndOfFile)
+ return; // Nothing to do
+ p->MoveFirst();
+ while (!p->EndOfFile) {
+ uint64_t id = p->Fields->Item["persistenceId"]->Value;
+ long blobSize = p->Fields->Item["fieldTableBlob"]->ActualSize;
+ BlobAdapter blob(blobSize);
+ blob = p->Fields->Item["fieldTableBlob"]->GetChunk(blobSize);
+ // Recreate the Config instance and reset its ID.
+ broker::RecoverableConfig::shared_ptr config =
+ recoverer.recoverConfig(blob);
+ config->setPersistenceId(id);
+ p->MoveNext();
+ }
+}
+
+void
+MSSqlProvider::recoverExchanges(qpid::broker::RecoveryManager& recoverer,
+ ExchangeMap& exchangeMap)
+{
+ DatabaseConnection *db = initConnection();
+ BlobRecordset rsExchanges;
+ rsExchanges.open(db, TblExchange);
+ _RecordsetPtr p = (_RecordsetPtr)rsExchanges;
+ if (p->BOF && p->EndOfFile)
+ return; // Nothing to do
+ p->MoveFirst();
+ while (!p->EndOfFile) {
+ uint64_t id = p->Fields->Item["persistenceId"]->Value;
+ long blobSize = p->Fields->Item["fieldTableBlob"]->ActualSize;
+ BlobAdapter blob(blobSize);
+ blob = p->Fields->Item["fieldTableBlob"]->GetChunk(blobSize);
+ // Recreate the Exchange instance, reset its ID, and remember the
+ // ones restored for matching up when recovering bindings.
+ broker::RecoverableExchange::shared_ptr exchange =
+ recoverer.recoverExchange(blob);
+ exchange->setPersistenceId(id);
+ exchangeMap[id] = exchange;
+ p->MoveNext();
+ }
+}
+
+void
+MSSqlProvider::recoverQueues(qpid::broker::RecoveryManager& recoverer,
+ QueueMap& queueMap)
+{
+ DatabaseConnection *db = initConnection();
+ BlobRecordset rsQueues;
+ rsQueues.open(db, TblQueue);
+ _RecordsetPtr p = (_RecordsetPtr)rsQueues;
+ if (p->BOF && p->EndOfFile)
+ return; // Nothing to do
+ p->MoveFirst();
+ while (!p->EndOfFile) {
+ uint64_t id = p->Fields->Item["persistenceId"]->Value;
+ long blobSize = p->Fields->Item["fieldTableBlob"]->ActualSize;
+ BlobAdapter blob(blobSize);
+ blob = p->Fields->Item["fieldTableBlob"]->GetChunk(blobSize);
+ // Recreate the Queue instance and reset its ID.
+ broker::RecoverableQueue::shared_ptr queue =
+ recoverer.recoverQueue(blob);
+ queue->setPersistenceId(id);
+ queueMap[id] = queue;
+ p->MoveNext();
+ }
+}
+
+void
+MSSqlProvider::recoverBindings(qpid::broker::RecoveryManager& recoverer,
+ const ExchangeMap& exchangeMap,
+ const QueueMap& queueMap)
+{
+ DatabaseConnection *db = initConnection();
+ BindingRecordset rsBindings;
+ rsBindings.open(db, TblBinding);
+ rsBindings.recover(recoverer, exchangeMap, queueMap);
+}
+
+void
+MSSqlProvider::recoverMessages(qpid::broker::RecoveryManager& recoverer,
+ MessageMap& messageMap,
+ MessageQueueMap& messageQueueMap)
+{
+ DatabaseConnection *db = initConnection();
+ MessageRecordset rsMessages;
+ rsMessages.open(db, TblMessage);
+ rsMessages.recover(recoverer, messageMap);
+
+ MessageMapRecordset rsMessageMaps;
+ rsMessageMaps.open(db, TblMessageMap);
+ rsMessageMaps.recover(messageQueueMap);
+}
+
+////////////// Internal Methods
+
+State *
+MSSqlProvider::initState()
+{
+ State *state = dbState.get(); // See if thread has initialized
+ if (!state) {
+ state = new State;
+ dbState.reset(state);
+ }
+ return state;
+}
+
+DatabaseConnection *
+MSSqlProvider::initConnection(void)
+{
+ State *state = initState();
+ if (state->dbConn != 0)
+ return state->dbConn; // And the DatabaseConnection is set up too
+ std::auto_ptr<DatabaseConnection> db(new DatabaseConnection);
+ db->open(options.connectString, options.catalogName);
+ state->dbConn = db.release();
+ return state->dbConn;
+}
+
+void
+MSSqlProvider::createDb(_ConnectionPtr conn, const std::string &name)
+{
+ const std::string dbCmd = "CREATE DATABASE " + name;
+ const std::string useCmd = "USE " + name;
+ const std::string tableCmd = "CREATE TABLE ";
+ const std::string colSpecs =
+ " (persistenceId bigint PRIMARY KEY NOT NULL IDENTITY(1,1),"
+ " fieldTableBlob varbinary(MAX) NOT NULL)";
+ const std::string bindingSpecs =
+ " (exchangeId bigint REFERENCES tblExchange(persistenceId) NOT NULL,"
+ " queueId bigint REFERENCES tblQueue(persistenceId) NOT NULL,"
+ " routingKey varchar(255),"
+ " fieldTableBlob varbinary(MAX))";
+ const std::string messageMapSpecs =
+ " (messageId bigint REFERENCES tblMessage(persistenceId) NOT NULL,"
+ " queueId bigint REFERENCES tblQueue(persistenceId) NOT NULL)";
+ _variant_t unused;
+ _bstr_t dbStr = dbCmd.c_str();
+ try {
+ conn->Execute(dbStr, &unused, adExecuteNoRecords);
+ _bstr_t useStr = useCmd.c_str();
+ conn->Execute(useStr, &unused, adExecuteNoRecords);
+ std::string makeTable = tableCmd + TblQueue + colSpecs;
+ _bstr_t makeTableStr = makeTable.c_str();
+ conn->Execute(makeTableStr, &unused, adExecuteNoRecords);
+ makeTable = tableCmd + TblExchange + colSpecs;
+ makeTableStr = makeTable.c_str();
+ conn->Execute(makeTableStr, &unused, adExecuteNoRecords);
+ makeTable = tableCmd + TblConfig + colSpecs;
+ makeTableStr = makeTable.c_str();
+ conn->Execute(makeTableStr, &unused, adExecuteNoRecords);
+ makeTable = tableCmd + TblMessage + colSpecs;
+ makeTableStr = makeTable.c_str();
+ conn->Execute(makeTableStr, &unused, adExecuteNoRecords);
+ makeTable = tableCmd + TblBinding + bindingSpecs;
+ makeTableStr = makeTable.c_str();
+ conn->Execute(makeTableStr, &unused, adExecuteNoRecords);
+ makeTable = tableCmd + TblMessageMap + messageMapSpecs;
+ makeTableStr = makeTable.c_str();
+ conn->Execute(makeTableStr, &unused, adExecuteNoRecords);
+ }
+ catch(_com_error &e) {
+ throw ADOException("MSSQL can't create " + name, e);
+ }
+}
+
+void
+MSSqlProvider::dump()
+{
+ // dump all db records to qpid_log
+ QPID_LOG(notice, "DB Dump: (not dumping anything)");
+ // rsQueues.dump();
+}
+
+
+}}} // namespace qpid::store::ms_sql
diff --git a/cpp/src/qpid/store/ms-sql/MessageMapRecordset.cpp b/cpp/src/qpid/store/ms-sql/MessageMapRecordset.cpp
new file mode 100644
index 0000000000..68e174a2b0
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/MessageMapRecordset.cpp
@@ -0,0 +1,155 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Exception.h>
+#include <qpid/log/Statement.h>
+#include <qpid/store/StorageProvider.h>
+
+#include "MessageMapRecordset.h"
+#include "VariantHelper.h"
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+void
+MessageMapRecordset::add(uint64_t messageId, uint64_t queueId)
+{
+ rs->AddNew();
+ rs->Fields->GetItem("messageId")->Value = messageId;
+ rs->Fields->GetItem("queueId")->Value = queueId;
+ rs->Update();
+}
+
+bool
+MessageMapRecordset::remove(uint64_t messageId, uint64_t queueId)
+{
+ // Look up all mappings for the specified message. Then scan
+ // for the specified queue and keep track of whether or not the
+ // message exists on any queue we are not looking for a well.
+ std::ostringstream filter;
+ filter << "messageId = " << messageId << std::ends;
+ rs->PutFilter (VariantHelper<std::string>(filter.str()));
+ if (rs->RecordCount == 0)
+ return false;
+ MessageMap m;
+ IADORecordBinding *piAdoRecordBinding;
+ rs->QueryInterface(__uuidof(IADORecordBinding),
+ (LPVOID *)&piAdoRecordBinding);
+ piAdoRecordBinding->BindToRecordset(&m);
+ bool moreEntries = false, deleted = false;
+ rs->MoveFirst();
+ // If the desired mapping gets deleted, and we already know there are
+ // other mappings for the message, don't bother finishing the scan.
+ while (!rs->EndOfFile && !(deleted && moreEntries)) {
+ if (m.queueId == queueId) {
+ rs->Delete(adAffectCurrent);
+ rs->Update();
+ deleted = true;
+ }
+ else {
+ moreEntries = true;
+ }
+ rs->MoveNext();
+ }
+ piAdoRecordBinding->Release();
+ rs->Filter = "";
+ return moreEntries;
+}
+
+void
+MessageMapRecordset::removeForQueue(uint64_t queueId,
+ std::vector<uint64_t>& orphaned)
+{
+ // Read all the messages queued on queueId and add them to the orphaned
+ // list. Then remove each one and learn if there are references to it
+ // from other queues. The ones without references are left in the
+ // orphaned list, others are removed.
+ std::ostringstream filter;
+ filter << "queueId = " << queueId << std::ends;
+ rs->PutFilter (VariantHelper<std::string>(filter.str()));
+ MessageMap m;
+ IADORecordBinding *piAdoRecordBinding;
+ rs->QueryInterface(__uuidof(IADORecordBinding),
+ (LPVOID *)&piAdoRecordBinding);
+ piAdoRecordBinding->BindToRecordset(&m);
+ while (!rs->EndOfFile) {
+ orphaned.push_back(m.messageId);
+ rs->MoveNext();
+ }
+ piAdoRecordBinding->Release();
+ rs->Filter = ""; // Remove filter on queueId
+ rs->Requery(adOptionUnspecified); // Get the entire map again
+
+ // Now delete all the messages on this queue; any message that still has
+ // references from other queue(s) is removed from orphaned.
+ for (std::vector<uint64_t>::iterator i = orphaned.begin();
+ i != orphaned.end();
+ ) {
+ if (remove(*i, queueId))
+ i = orphaned.erase(i); // There are other refs to message *i
+ else
+ ++i;
+ }
+}
+
+void
+MessageMapRecordset::recover(MessageQueueMap& msgMap)
+{
+ if (rs->BOF && rs->EndOfFile)
+ return; // Nothing to do
+ rs->MoveFirst();
+ MessageMap b;
+ IADORecordBinding *piAdoRecordBinding;
+ rs->QueryInterface(__uuidof(IADORecordBinding),
+ (LPVOID *)&piAdoRecordBinding);
+ piAdoRecordBinding->BindToRecordset(&b);
+ while (!rs->EndOfFile) {
+ msgMap[b.messageId].push_back(b.queueId);
+ rs->MoveNext();
+ }
+
+ piAdoRecordBinding->Release();
+}
+
+void
+MessageMapRecordset::dump()
+{
+ Recordset::dump();
+ if (rs->EndOfFile && rs->BOF) // No records
+ return;
+ rs->MoveFirst();
+
+ MessageMap m;
+ IADORecordBinding *piAdoRecordBinding;
+ rs->QueryInterface(__uuidof(IADORecordBinding),
+ (LPVOID *)&piAdoRecordBinding);
+ piAdoRecordBinding->BindToRecordset(&m);
+
+ while (!rs->EndOfFile) {
+ QPID_LOG(notice, "msg " << m.messageId << " on queue " << m.queueId);
+ rs->MoveNext();
+ }
+
+ piAdoRecordBinding->Release();
+}
+
+}}} // namespace qpid::store::ms_sql
diff --git a/cpp/src/qpid/store/ms-sql/MessageMapRecordset.h b/cpp/src/qpid/store/ms-sql/MessageMapRecordset.h
new file mode 100644
index 0000000000..475137b18b
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/MessageMapRecordset.h
@@ -0,0 +1,77 @@
+#ifndef QPID_STORE_MSSQL_MESSAGEMAPRECORDSET_H
+#define QPID_STORE_MSSQL_MESSAGEMAPRECORDSET_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <icrsint.h>
+#include <vector>
+#include "Recordset.h"
+#include <qpid/broker/RecoveryManager.h>
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+/**
+ * @class MessageMapRecordset
+ *
+ * Class for the message map (message -> queue) records.
+ */
+class MessageMapRecordset : public Recordset {
+
+ class MessageMap : public CADORecordBinding {
+ BEGIN_ADO_BINDING(MessageMap)
+ ADO_FIXED_LENGTH_ENTRY2(1, adBigInt, messageId, FALSE)
+ ADO_FIXED_LENGTH_ENTRY2(2, adBigInt, queueId, FALSE)
+ END_ADO_BINDING()
+
+ public:
+ uint64_t messageId;
+ uint64_t queueId;
+ };
+
+public:
+ // Add a new mapping
+ void add(uint64_t messageId, uint64_t queueId);
+
+ // Remove a specific mapping. Returns true if the message is still
+ // enqueued on at least one other queue; false if the message no longer
+ // exists on any other queues.
+ bool remove(uint64_t messageId, uint64_t queueId);
+
+ // Remove mappings for all messages on a specified queue. If there are
+ // messages that were only on the specified queue and are, therefore,
+ // orphaned now, return them in the orphaned vector. The orphaned
+ // messages can be deleted permanently as they are not referenced on
+ // any other queues.
+ void removeForQueue(uint64_t queueId, std::vector<uint64_t>& orphaned);
+
+ // Recover the mappings of message ID -> vector<queue ID>.
+ void recover(MessageQueueMap& msgMap);
+
+ // Dump table contents; useful for debugging.
+ void dump();
+};
+
+}}} // namespace qpid::store::ms_sql
+
+#endif /* QPID_STORE_MSSQL_MESSAGEMAPRECORDSET_H */
diff --git a/cpp/src/qpid/store/ms-sql/MessageRecordset.cpp b/cpp/src/qpid/store/ms-sql/MessageRecordset.cpp
new file mode 100644
index 0000000000..b62a333df6
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/MessageRecordset.cpp
@@ -0,0 +1,184 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Exception.h>
+#include <qpid/log/Statement.h>
+
+#include "MessageRecordset.h"
+#include "BlobAdapter.h"
+#include "BlobEncoder.h"
+#include "VariantHelper.h"
+
+#include <boost/intrusive_ptr.hpp>
+
+class qpid::broker::PersistableMessage;
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+void
+MessageRecordset::add(const boost::intrusive_ptr<qpid::broker::PersistableMessage>& msg)
+{
+ BlobEncoder blob (msg); // Marshall headers and content to a blob
+ rs->AddNew();
+ rs->Fields->GetItem("fieldTableBlob")->AppendChunk(blob);
+ rs->Update();
+ uint64_t id = rs->Fields->Item["persistenceId"]->Value;
+ msg->setPersistenceId(id);
+}
+
+void
+MessageRecordset::append(const boost::intrusive_ptr<const qpid::broker::PersistableMessage>& msg,
+ const std::string& data)
+{
+ // Look up the message by its Id
+ std::ostringstream filter;
+ filter << "persistenceId = " << msg->getPersistenceId() << std::ends;
+ rs->PutFilter (VariantHelper<std::string>(filter.str()));
+ if (rs->RecordCount == 0) {
+ throw Exception("Can't append to message not stored in database");
+ }
+ BlobEncoder blob (data); // Marshall string data to a blob
+ rs->Fields->GetItem("fieldTableBlob")->AppendChunk(blob);
+ rs->Update();
+}
+
+void
+MessageRecordset::remove(const boost::intrusive_ptr<const qpid::broker::PersistableMessage>& msg)
+{
+ BlobRecordset::remove(msg->getPersistenceId());
+}
+
+void
+MessageRecordset::loadContent(const boost::intrusive_ptr<const qpid::broker::PersistableMessage>& msg,
+ std::string& data,
+ uint64_t offset,
+ uint32_t length)
+{
+ // Look up the message by its Id
+ std::ostringstream filter;
+ filter << "persistenceId = " << msg->getPersistenceId() << std::ends;
+ rs->PutFilter (VariantHelper<std::string>(filter.str()));
+ if (rs->RecordCount == 0) {
+ throw Exception("Can't load message not stored in database");
+ }
+
+ // NOTE! If this code needs to change, please verify the encoding
+ // code in BlobEncoder.
+ long blobSize = rs->Fields->Item["fieldTableBlob"]->ActualSize;
+ uint32_t headerSize;
+ const size_t headerFieldLength = sizeof(headerSize);
+ BlobAdapter blob(headerFieldLength);
+ blob =
+ rs->Fields->Item["fieldTableBlob"]->GetChunk((long)headerFieldLength);
+ headerSize = ((qpid::framing::Buffer&)blob).getLong();
+
+ // GetChunk always begins reading where the previous GetChunk left off,
+ // so we can't just tell it to ignore the header and read the data.
+ // So, read the header plus the offset, plus the desired data, then
+ // copy the desired data to the supplied string. If this ends up asking
+ // for more than is available in the field, reduce it to what's there.
+ long getSize = headerSize + offset + length;
+ if (getSize + (long)headerFieldLength > blobSize) {
+ size_t reduce = (getSize + headerFieldLength) - blobSize;
+ getSize -= reduce;
+ length -= reduce;
+ }
+ BlobAdapter header_plus(getSize);
+ header_plus = rs->Fields->Item["fieldTableBlob"]->GetChunk(getSize);
+ uint8_t *throw_away = new uint8_t[headerSize + offset];
+ ((qpid::framing::Buffer&)header_plus).getRawData(throw_away, headerSize + offset);
+ delete throw_away;
+ ((qpid::framing::Buffer&)header_plus).getRawData(data, length);
+}
+
+void
+MessageRecordset::recover(qpid::broker::RecoveryManager& recoverer,
+ std::map<uint64_t, broker::RecoverableMessage::shared_ptr>& messageMap)
+{
+ if (rs->BOF && rs->EndOfFile)
+ return; // Nothing to do
+ rs->MoveFirst();
+ Binding b;
+ IADORecordBinding *piAdoRecordBinding;
+ rs->QueryInterface(__uuidof(IADORecordBinding),
+ (LPVOID *)&piAdoRecordBinding);
+ piAdoRecordBinding->BindToRecordset(&b);
+ while (!rs->EndOfFile) {
+ // The blob was written as normal, but with the header length
+ // prepended in a uint32_t. Due to message staging threshold
+ // limits, the header may be all that's read in; get it first,
+ // recover that message header, then see if the rest is needed.
+ //
+ // NOTE! If this code needs to change, please verify the encoding
+ // code in BlobEncoder.
+ long blobSize = rs->Fields->Item["fieldTableBlob"]->ActualSize;
+ uint32_t headerSize;
+ const size_t headerFieldLength = sizeof(headerSize);
+ BlobAdapter blob(headerFieldLength);
+ blob =
+ rs->Fields->Item["fieldTableBlob"]->GetChunk((long)headerFieldLength);
+ headerSize = ((qpid::framing::Buffer&)blob).getLong();
+ BlobAdapter header(headerSize);
+ header = rs->Fields->Item["fieldTableBlob"]->GetChunk(headerSize);
+ broker::RecoverableMessage::shared_ptr msg;
+ msg = recoverer.recoverMessage(header);
+ msg->setPersistenceId(b.messageId);
+ messageMap[b.messageId] = msg;
+
+ // Now, do we need the rest of the content?
+ long contentLength = blobSize - headerFieldLength - headerSize;
+ if (msg->loadContent(contentLength)) {
+ BlobAdapter content(contentLength);
+ content =
+ rs->Fields->Item["fieldTableBlob"]->GetChunk(contentLength);
+ msg->decodeContent(content);
+ }
+ rs->MoveNext();
+ }
+
+ piAdoRecordBinding->Release();
+}
+
+void
+MessageRecordset::dump()
+{
+ Recordset::dump();
+ if (rs->EndOfFile && rs->BOF) // No records
+ return;
+ rs->MoveFirst();
+
+ Binding b;
+ IADORecordBinding *piAdoRecordBinding;
+ rs->QueryInterface(__uuidof(IADORecordBinding),
+ (LPVOID *)&piAdoRecordBinding);
+ piAdoRecordBinding->BindToRecordset(&b);
+
+ while (VARIANT_FALSE == rs->EndOfFile) {
+ QPID_LOG(notice, "Msg " << b.messageId);
+ rs->MoveNext();
+ }
+
+ piAdoRecordBinding->Release();
+}
+
+}}} // namespace qpid::store::ms_sql
diff --git a/cpp/src/qpid/store/ms-sql/MessageRecordset.h b/cpp/src/qpid/store/ms-sql/MessageRecordset.h
new file mode 100644
index 0000000000..698b2561fe
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/MessageRecordset.h
@@ -0,0 +1,85 @@
+#ifndef QPID_STORE_MSSQL_MESSAGERECORDSET_H
+#define QPID_STORE_MSSQL_MESSAGERECORDSET_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <icrsint.h>
+#include "BlobRecordset.h"
+#include <qpid/broker/PersistableMessage.h>
+#include <qpid/broker/RecoveryManager.h>
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+/**
+ * @class MessageRecordset
+ *
+ * Class for storing and recovering messages. Messages are primarily blobs
+ * and handled similarly. However, messages larger than the staging threshold
+ * are not contained completely in memory; they're left mostly in the store
+ * and the header is held in memory. So when the message "blob" is saved,
+ * an additional size-of-the-header field is prepended to the blob.
+ * On recovery, the size-of-the-header is used to get only what's needed
+ * until it's determined if the entire message is to be recovered to memory.
+ */
+class MessageRecordset : public BlobRecordset {
+ class Binding : public CADORecordBinding {
+ BEGIN_ADO_BINDING(Binding)
+ ADO_FIXED_LENGTH_ENTRY2(1, adBigInt, messageId, FALSE)
+ END_ADO_BINDING()
+
+ public:
+ uint64_t messageId;
+ };
+
+public:
+ // Store a message. Store the header size (4 bytes) then the regular
+ // blob comprising the message.
+ void add(const boost::intrusive_ptr<qpid::broker::PersistableMessage>& msg);
+
+ // Append additional content to an existing message.
+ void append(const boost::intrusive_ptr<const qpid::broker::PersistableMessage>& msg,
+ const std::string& data);
+
+ // Remove an existing message
+ void remove(const boost::intrusive_ptr<const qpid::broker::PersistableMessage>& msg);
+
+ // Load all or part of a stored message. This skips the header parts and
+ // loads content.
+ void loadContent(const boost::intrusive_ptr<const qpid::broker::PersistableMessage>& msg,
+ std::string& data,
+ uint64_t offset,
+ uint32_t length);
+
+ // Recover messages and save a map of those recovered.
+ void recover(qpid::broker::RecoveryManager& recoverer,
+ std::map<uint64_t, broker::RecoverableMessage::shared_ptr>& messageMap);
+
+ // Dump table contents; useful for debugging.
+ void dump();
+};
+
+}}} // namespace qpid::store::ms_sql
+
+#endif /* QPID_STORE_MSSQL_MESSAGERECORDSET_H */
diff --git a/cpp/src/qpid/store/ms-sql/Recordset.cpp b/cpp/src/qpid/store/ms-sql/Recordset.cpp
new file mode 100644
index 0000000000..e1a5158c87
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/Recordset.cpp
@@ -0,0 +1,121 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/Exception.h>
+#include <qpid/log/Statement.h>
+
+#include "Recordset.h"
+#include "BlobEncoder.h"
+#include "DatabaseConnection.h"
+#include "VariantHelper.h"
+
+namespace {
+inline void TESTHR(HRESULT x) {if FAILED(x) _com_issue_error(x);};
+}
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+#if 0
+Recordset::Iterator::Iterator(Recordset& _rs) : rs(_rs)
+{
+ rs->MoveFirst();
+ setCurrent();
+}
+
+std::pair<uint64_t, BlobAdapter>&
+Recordset::Iterator::dereference() const
+{
+ return const_cast<std::pair<uint64_t, BlobAdapter> >(current);
+}
+
+void
+Recordset::Iterator::increment()
+{
+ rs->MoveNext();
+ setCurrent();
+}
+
+bool
+Recordset::Iterator::equal(const Iterator& x) const
+{
+ return current.first == x.current.first;
+}
+
+void
+Recordset::Iterator::setCurrent()
+{
+ if (!rs->EndOfFile) {
+ uint64_t id = rs->Fields->Item["persistenceId"]->Value;
+ long blobSize = rs->Fields->Item["fieldTableBlob"]->ActualSize;
+ BlobAdapter blob(blobSize);
+ blob = rs->Fields->Item["fieldTableBlob"]->GetChunk(blobSize);
+ current = std::make_pair(id, blob);
+ }
+ else {
+ current.first = 0;
+ }
+}
+#endif
+
+void
+Recordset::open(DatabaseConnection* conn, const std::string& table)
+{
+ _ConnectionPtr p = *conn;
+ TESTHR(rs.CreateInstance(__uuidof(::Recordset)));
+ // Client-side cursors needed to get access to newly added
+ // identity column immediately. Recordsets need this to get the
+ // persistence ID for the broker objects.
+ rs->CursorLocation = adUseClient;
+ rs->Open(table.c_str(),
+ _variant_t((IDispatch *)p, true),
+ adOpenStatic,
+ adLockOptimistic,
+ adCmdTable);
+ tableName = table;
+}
+
+void
+Recordset::close()
+{
+ if (rs && rs->State == adStateOpen)
+ rs->Close();
+ rs = 0;
+}
+
+void
+Recordset::requery()
+{
+ // Restore the recordset to reflect all current records.
+ rs->Filter = "";
+ rs->Requery(-1);
+}
+
+void
+Recordset::dump()
+{
+ long count = rs->RecordCount;
+ QPID_LOG(notice, "DB Dump: " + tableName <<
+ ": " << count << " records");
+}
+
+}}} // namespace qpid::store::ms_sql
diff --git a/cpp/src/qpid/store/ms-sql/Recordset.h b/cpp/src/qpid/store/ms-sql/Recordset.h
new file mode 100644
index 0000000000..3631838aa8
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/Recordset.h
@@ -0,0 +1,101 @@
+#ifndef QPID_STORE_MSSQL_RECORDSET_H
+#define QPID_STORE_MSSQL_RECORDSET_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+// Bring in ADO 2.8 (yes, I know it says "15", but that's it...)
+#import "C:\Program Files\Common Files\System\ado\msado15.dll" \
+ no_namespace rename("EOF", "EndOfFile")
+#include <comdef.h>
+#include <comutil.h>
+#include <string>
+#if 0
+#include <utility>
+#endif
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+class DatabaseConnection;
+
+/**
+ * @class Recordset
+ *
+ * Represents an ADO Recordset, abstracting out the common operations needed
+ * on the common tables used that have 2 fields, persistence ID and blob.
+ */
+class Recordset {
+protected:
+ _RecordsetPtr rs;
+ DatabaseConnection* dbConn;
+ std::string tableName;
+
+public:
+
+#if 0
+ /**
+ * Iterator support for walking through the recordset.
+ * If I need to try this again, I'd look at Recordset cloning.
+ */
+ class Iterator : public boost::iterator_facade<
+ Iterator, std::pair<uint64_t, BlobAdapter>, boost::random_access_traversal_tag>
+ {
+ public:
+ Iterator() : rs(0) { }
+ Iterator(Recordset& _rs);
+
+ private:
+ friend class boost::iterator_core_access;
+
+ std::pair<uint64_t, BlobAdapter>& dereference() const;
+ void increment();
+ bool equal(const Iterator& x) const;
+
+ _RecordsetPtr rs;
+ std::pair<uint64_t, BlobAdapter> current;
+
+ void setCurrent();
+ };
+
+ friend class Iterator;
+#endif
+
+ Recordset() : rs(0) {}
+ virtual ~Recordset() { close(); }
+ void open(DatabaseConnection* conn, const std::string& table);
+ void close();
+ void requery();
+ operator _RecordsetPtr () { return rs; }
+#if 0
+ Iterator begin() { Iterator iter(*this); return iter; }
+ Iterator end() { Iterator iter; return iter; }
+#endif
+
+ // Dump table contents; useful for debugging.
+ void dump();
+};
+
+}}} // namespace qpid::store::ms_sql
+
+#endif /* QPID_STORE_MSSQL_RECORDSET_H */
diff --git a/cpp/src/qpid/store/ms-sql/State.cpp b/cpp/src/qpid/store/ms-sql/State.cpp
new file mode 100644
index 0000000000..720603dd11
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/State.cpp
@@ -0,0 +1,45 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "State.h"
+#include "DatabaseConnection.h"
+#include "Exception.h"
+#include <comdef.h>
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+State::State() : dbConn(0)
+{
+ HRESULT hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
+ if (hr != S_OK && hr != S_FALSE)
+ throw Exception("Error initializing COM");
+}
+
+State::~State()
+{
+ if (dbConn)
+ delete dbConn;
+ ::CoUninitialize();
+}
+
+}}} // namespace qpid::store::ms_sql
diff --git a/cpp/src/qpid/store/ms-sql/State.h b/cpp/src/qpid/store/ms-sql/State.h
new file mode 100644
index 0000000000..6350bc5bd2
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/State.h
@@ -0,0 +1,52 @@
+#ifndef QPID_STORE_MSSQL_STATE_H
+#define QPID_STORE_MSSQL_STATE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+class DatabaseConnection;
+
+/**
+ * @struct State
+ *
+ * Represents a thread's state for accessing ADO and the database.
+ * Creating an instance of State initializes COM for this thread, and
+ * destroying it uninitializes COM. There's also a DatabaseConnection
+ * for this thread's default access to the database. More DatabaseConnections
+ * can always be created, but State has one that can always be used by
+ * the thread whose state is represented.
+ *
+ * This class is intended to be one-per-thread, so it should be accessed
+ * via thread-specific storage.
+ */
+struct State {
+ State();
+ ~State();
+ DatabaseConnection *dbConn;
+};
+
+}}} // namespace qpid::store::ms_sql
+
+#endif /* QPID_STORE_MSSQL_STATE_H */
diff --git a/cpp/src/qpid/store/ms-sql/VariantHelper.cpp b/cpp/src/qpid/store/ms-sql/VariantHelper.cpp
new file mode 100644
index 0000000000..786724f031
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/VariantHelper.cpp
@@ -0,0 +1,59 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <string>
+#include "VariantHelper.h"
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+template <class Wrapped>
+VariantHelper<Wrapped>::VariantHelper()
+{
+ var.vt = VT_EMPTY;
+}
+
+template <class Wrapped>
+VariantHelper<Wrapped>::operator const _variant_t& () const
+{
+ return var;
+}
+
+// Specialization for using _variant_t to wrap a std::string
+VariantHelper<std::string>::VariantHelper(const std::string &init)
+{
+ var.SetString(init.c_str());
+}
+
+VariantHelper<std::string>&
+VariantHelper<std::string>::operator=(const std::string &rhs)
+{
+ var.SetString(rhs.c_str());
+ return *this;
+}
+
+VariantHelper<std::string>::operator const _variant_t& () const
+{
+ return var;
+}
+
+}}} // namespace qpid::store::ms_sql
diff --git a/cpp/src/qpid/store/ms-sql/VariantHelper.h b/cpp/src/qpid/store/ms-sql/VariantHelper.h
new file mode 100644
index 0000000000..723dbc3b76
--- /dev/null
+++ b/cpp/src/qpid/store/ms-sql/VariantHelper.h
@@ -0,0 +1,61 @@
+#ifndef QPID_STORE_MSSQL_VARIANTHELPER_H
+#define QPID_STORE_MSSQL_VARIANTHELPER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <comutil.h>
+
+namespace qpid {
+namespace store {
+namespace ms_sql {
+
+/**
+ * @class VariantHelper
+ *
+ * Class template to wrap the details of working with _variant_t objects.
+ */
+template <class Wrapped> class VariantHelper {
+private:
+ _variant_t var;
+
+public:
+ VariantHelper();
+ VariantHelper(const Wrapped &init);
+
+ VariantHelper& operator =(const Wrapped& rhs);
+ operator const _variant_t& () const;
+};
+
+// Specialization for using _variant_t to wrap a std::string
+template<> class VariantHelper<std::string> {
+private:
+ _variant_t var;
+
+public:
+ VariantHelper(const std::string &init);
+ VariantHelper& operator =(const std::string& rhs);
+ operator const _variant_t& () const;
+};
+
+}}} // namespace qpid::store::ms_sql
+
+#endif /* QPID_STORE_MSSQL_VARIANTHELPER_H */
diff --git a/cpp/src/qpid/sys/AggregateOutput.cpp b/cpp/src/qpid/sys/AggregateOutput.cpp
index 2fad28c381..709d3bc640 100644
--- a/cpp/src/qpid/sys/AggregateOutput.cpp
+++ b/cpp/src/qpid/sys/AggregateOutput.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -25,44 +25,67 @@
namespace qpid {
namespace sys {
-
-void AggregateOutput::activateOutput()
-{
- control.activateOutput();
-}
+
+AggregateOutput::AggregateOutput(OutputControl& c) : busy(false), control(c) {}
+
+void AggregateOutput::abort() { control.abort(); }
+
+void AggregateOutput::activateOutput() { control.activateOutput(); }
+
+void AggregateOutput::giveReadCredit(int32_t credit) { control.giveReadCredit(credit); }
bool AggregateOutput::hasOutput() {
- for (TaskList::const_iterator i = tasks.begin(); i != tasks.end(); ++i)
- if ((*i)->hasOutput()) return true;
- return false;
+ Mutex::ScopedLock l(lock);
+ return !tasks.empty();
}
-bool AggregateOutput::doOutput()
-{
- bool result = false;
- if (!tasks.empty()) {
- if (next >= tasks.size()) next = next % tasks.size();
-
- size_t start = next;
- //loop until a task generated some output
- while (!result) {
- result = tasks[next++]->doOutput();
- if (next >= tasks.size()) next = next % tasks.size();
- if (start == next) break;
+// Clear the busy flag and notify waiting threads in destructor.
+struct ScopedBusy {
+ bool& flag;
+ Monitor& monitor;
+ ScopedBusy(bool& f, Monitor& m) : flag(f), monitor(m) { f = true; }
+ ~ScopedBusy() { flag = false; monitor.notifyAll(); }
+};
+
+bool AggregateOutput::doOutput() {
+ Mutex::ScopedLock l(lock);
+ ScopedBusy sb(busy, lock);
+
+ while (!tasks.empty()) {
+ OutputTask* t=tasks.front();
+ tasks.pop_front();
+ bool didOutput;
+ {
+ // Allow concurrent call to addOutputTask.
+ // removeOutputTask will wait till !busy before removing a task.
+ Mutex::ScopedUnlock u(lock);
+ didOutput = t->doOutput();
+ }
+ if (didOutput) {
+ tasks.push_back(t);
+ return true;
}
}
- return result;
+ return false;
+}
+
+void AggregateOutput::addOutputTask(OutputTask* task) {
+ Mutex::ScopedLock l(lock);
+ tasks.push_back(task);
}
-void AggregateOutput::addOutputTask(OutputTask* t)
-{
- tasks.push_back(t);
+void AggregateOutput::removeOutputTask(OutputTask* task) {
+ Mutex::ScopedLock l(lock);
+ while (busy) lock.wait();
+ tasks.erase(std::remove(tasks.begin(), tasks.end(), task), tasks.end());
}
-
-void AggregateOutput::removeOutputTask(OutputTask* t)
+
+void AggregateOutput::removeAll()
{
- TaskList::iterator i = std::find(tasks.begin(), tasks.end(), t);
- if (i != tasks.end()) tasks.erase(i);
+ Mutex::ScopedLock l(lock);
+ while (busy) lock.wait();
+ tasks.clear();
}
+
}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/AggregateOutput.h b/cpp/src/qpid/sys/AggregateOutput.h
index 02a53ed50b..71ad713eb7 100644
--- a/cpp/src/qpid/sys/AggregateOutput.h
+++ b/cpp/src/qpid/sys/AggregateOutput.h
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -21,35 +21,58 @@
#ifndef _AggregateOutput_
#define _AggregateOutput_
-#include <vector>
-#include "Mutex.h"
-#include "OutputControl.h"
-#include "OutputTask.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/sys/OutputControl.h"
+#include "qpid/sys/OutputTask.h"
+#include "qpid/CommonImportExport.h"
+
+#include <algorithm>
+#include <deque>
namespace qpid {
namespace sys {
- class AggregateOutput : public OutputTask, public OutputControl
- {
- typedef std::vector<OutputTask*> TaskList;
-
- TaskList tasks;
- size_t next;
- OutputControl& control;
-
- public:
- AggregateOutput(OutputControl& c) : next(0), control(c) {};
- //this may be called on any thread
- void activateOutput();
- //all the following will be called on the same thread
- bool doOutput();
- bool hasOutput();
- void addOutputTask(OutputTask* t);
- void removeOutputTask(OutputTask* t);
- };
-
-}
-}
+/**
+ * Holds a collection of output tasks, doOutput picks the next one to execute.
+ *
+ * Tasks are automatically removed if their doOutput() or hasOutput() returns false.
+ *
+ * Thread safe. addOutputTask may be called in one connection thread while
+ * doOutput is called in another.
+ */
+
+class AggregateOutput : public OutputTask, public OutputControl
+{
+ typedef std::deque<OutputTask*> TaskList;
+
+ Monitor lock;
+ TaskList tasks;
+ bool busy;
+ OutputControl& control;
+
+ public:
+ QPID_COMMON_EXTERN AggregateOutput(OutputControl& c);
+
+ // These may be called concurrently with any function.
+ QPID_COMMON_EXTERN void abort();
+ QPID_COMMON_EXTERN void activateOutput();
+ QPID_COMMON_EXTERN void giveReadCredit(int32_t);
+ QPID_COMMON_EXTERN void addOutputTask(OutputTask* t);
+
+ // These functions must not be called concurrently with each other.
+ QPID_COMMON_EXTERN bool doOutput();
+ QPID_COMMON_EXTERN bool hasOutput();
+ QPID_COMMON_EXTERN void removeOutputTask(OutputTask* t);
+ QPID_COMMON_EXTERN void removeAll();
+
+ /** Apply f to each OutputTask* in the tasks list */
+ template <class F> void eachOutput(F f) {
+ Mutex::ScopedLock l(lock);
+ std::for_each(tasks.begin(), tasks.end(), f);
+ }
+};
+
+}} // namespace qpid::sys
#endif
diff --git a/cpp/src/qpid/sys/AsynchIO.h b/cpp/src/qpid/sys/AsynchIO.h
index ff7823e00d..2a41f0a7d1 100644
--- a/cpp/src/qpid/sys/AsynchIO.h
+++ b/cpp/src/qpid/sys/AsynchIO.h
@@ -21,15 +21,16 @@
*
*/
-#include "Dispatcher.h"
-
+#include "qpid/sys/IntegerTypes.h"
+#include "qpid/CommonImportExport.h"
#include <boost/function.hpp>
-#include <deque>
+#include <boost/shared_ptr.hpp>
namespace qpid {
namespace sys {
class Socket;
+class Poller;
/*
* Asynchronous acceptor: accepts connections then does a callback with the
@@ -39,44 +40,36 @@ class AsynchAcceptor {
public:
typedef boost::function1<void, const Socket&> Callback;
-private:
- Callback acceptedCallback;
- DispatchHandle handle;
- const Socket& socket;
-
-public:
- AsynchAcceptor(const Socket& s, Callback callback);
- void start(Poller::shared_ptr poller);
-
-private:
- void readable(DispatchHandle& handle);
+ QPID_COMMON_EXTERN static AsynchAcceptor* create(const Socket& s, Callback callback);
+ virtual ~AsynchAcceptor() {};
+ virtual void start(boost::shared_ptr<Poller> poller) = 0;
};
/*
* Asynchronous connector: starts the process of initiating a connection and
* invokes a callback when completed or failed.
*/
-class AsynchConnector : private DispatchHandle {
+class AsynchConnector {
public:
typedef boost::function1<void, const Socket&> ConnectedCallback;
- typedef boost::function2<void, int, std::string> FailedCallback;
-
-private:
- ConnectedCallback connCallback;
- FailedCallback failCallback;
- const Socket& socket;
-
-public:
- AsynchConnector(const Socket& socket,
- Poller::shared_ptr poller,
- std::string hostname,
- uint16_t port,
- ConnectedCallback connCb,
- FailedCallback failCb = 0);
-
-private:
- void connComplete(DispatchHandle& handle);
- void failure(int, std::string);
+ typedef boost::function3<void, const Socket&, int, const std::string&> FailedCallback;
+
+ // Call create() to allocate a new AsynchConnector object with the
+ // specified poller, addressing, and callbacks.
+ // This method is implemented in platform-specific code to
+ // create a correctly typed object. The platform code also manages
+ // deletes. To correctly manage heaps when needed, the allocate and
+ // delete should both be done from the same class/library.
+ QPID_COMMON_EXTERN static AsynchConnector* create(const Socket& s,
+ boost::shared_ptr<Poller> poller,
+ std::string hostname,
+ uint16_t port,
+ ConnectedCallback connCb,
+ FailedCallback failCb);
+
+protected:
+ AsynchConnector() {}
+ virtual ~AsynchConnector() {}
};
struct AsynchIOBufferBase {
@@ -99,16 +92,14 @@ struct AsynchIOBufferBase {
/*
* Asychronous reader/writer:
* Reader accepts buffers to read into; reads into the provided buffers
- * and then does a callback with the buffer and amount read. Optionally it can callback
- * when there is something to read but no buffer to read it into.
+ * and then does a callback with the buffer and amount read. Optionally it
+ * can callback when there is something to read but no buffer to read it into.
*
* Writer accepts a buffer and queues it for writing; can also be given
- * a callback for when writing is "idle" (ie fd is writable, but nothing to write)
- *
- * The class is implemented in terms of DispatchHandle to allow it to be deleted by deleting
- * the contained DispatchHandle
+ * a callback for when writing is "idle" (ie fd is writable, but nothing
+ * to write).
*/
-class AsynchIO : private DispatchHandle {
+class AsynchIO {
public:
typedef AsynchIOBufferBase BufferBase;
@@ -118,47 +109,40 @@ public:
typedef boost::function2<void, AsynchIO&, const Socket&> ClosedCallback;
typedef boost::function1<void, AsynchIO&> BuffersEmptyCallback;
typedef boost::function1<void, AsynchIO&> IdleCallback;
-
-private:
- ReadCallback readCallback;
- EofCallback eofCallback;
- DisconnectCallback disCallback;
- ClosedCallback closedCallback;
- BuffersEmptyCallback emptyCallback;
- IdleCallback idleCallback;
- const Socket& socket;
- std::deque<BufferBase*> bufferQueue;
- std::deque<BufferBase*> writeQueue;
- bool queuedClose;
- /**
- * This flag is used to detect and handle concurrency between
- * calls to notifyPendingWrite() (which can be made from any thread) and
- * the execution of the writeable() method (which is always on the
- * thread processing this handle.
- */
- volatile bool writePending;
-
+ typedef boost::function1<void, AsynchIO&> RequestCallback;
+
+ // Call create() to allocate a new AsynchIO object with the specified
+ // callbacks. This method is implemented in platform-specific code to
+ // create a correctly typed object. The platform code also manages
+ // deletes. To correctly manage heaps when needed, the allocate and
+ // delete should both be done from the same class/library.
+ QPID_COMMON_EXTERN static AsynchIO* create(const Socket& s,
+ ReadCallback rCb,
+ EofCallback eofCb,
+ DisconnectCallback disCb,
+ ClosedCallback cCb = 0,
+ BuffersEmptyCallback eCb = 0,
+ IdleCallback iCb = 0);
public:
- AsynchIO(const Socket& s,
- ReadCallback rCb, EofCallback eofCb, DisconnectCallback disCb,
- ClosedCallback cCb = 0, BuffersEmptyCallback eCb = 0, IdleCallback iCb = 0);
- void queueForDeletion();
-
- void start(Poller::shared_ptr poller);
- void queueReadBuffer(BufferBase* buff);
- void unread(BufferBase* buff);
- void queueWrite(BufferBase* buff);
- void notifyPendingWrite();
- void queueWriteClose();
- bool writeQueueEmpty() { return writeQueue.empty(); }
- BufferBase* getQueuedBuffer();
-
-private:
- ~AsynchIO();
- void readable(DispatchHandle& handle);
- void writeable(DispatchHandle& handle);
- void disconnected(DispatchHandle& handle);
- void close(DispatchHandle& handle);
+ virtual void queueForDeletion() = 0;
+
+ virtual void start(boost::shared_ptr<Poller> poller) = 0;
+ virtual void queueReadBuffer(BufferBase* buff) = 0;
+ virtual void unread(BufferBase* buff) = 0;
+ virtual void queueWrite(BufferBase* buff) = 0;
+ virtual void notifyPendingWrite() = 0;
+ virtual void queueWriteClose() = 0;
+ virtual bool writeQueueEmpty() = 0;
+ virtual void startReading() = 0;
+ virtual void stopReading() = 0;
+ virtual void requestCallback(RequestCallback) = 0;
+ virtual BufferBase* getQueuedBuffer() = 0;
+
+protected:
+ // Derived class manages lifetime; must be constructed using the
+ // static create() method. Deletes not allowed from outside.
+ AsynchIO() {}
+ virtual ~AsynchIO() {}
};
}}
diff --git a/cpp/src/qpid/sys/AsynchIOHandler.cpp b/cpp/src/qpid/sys/AsynchIOHandler.cpp
index 886dbc8f43..f658b7d50f 100644
--- a/cpp/src/qpid/sys/AsynchIOHandler.cpp
+++ b/cpp/src/qpid/sys/AsynchIOHandler.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -19,13 +19,15 @@
*
*/
-#include "AsynchIOHandler.h"
+#include "qpid/sys/AsynchIOHandler.h"
#include "qpid/sys/AsynchIO.h"
#include "qpid/sys/Socket.h"
#include "qpid/framing/AMQP_HighestVersion.h"
#include "qpid/framing/ProtocolInitiation.h"
#include "qpid/log/Statement.h"
+#include <boost/bind.hpp>
+
namespace qpid {
namespace sys {
@@ -44,7 +46,8 @@ AsynchIOHandler::AsynchIOHandler(std::string id, ConnectionCodec::Factory* f) :
factory(f),
codec(0),
readError(false),
- isClient(false)
+ isClient(false),
+ readCredit(InfiniteCredit)
{}
AsynchIOHandler::~AsynchIOHandler() {
@@ -70,19 +73,61 @@ void AsynchIOHandler::write(const framing::ProtocolInitiation& data)
buff = new Buff;
framing::Buffer out(buff->bytes, buff->byteCount);
data.encode(out);
- buff->dataCount = data.size();
+ buff->dataCount = data.encodedSize();
aio->queueWrite(buff);
}
+void AsynchIOHandler::abort() {
+ // Don't disconnect if we're already disconnecting
+ if (!readError) {
+ aio->requestCallback(boost::bind(&AsynchIOHandler::eof, this, _1));
+ }
+}
+
void AsynchIOHandler::activateOutput() {
aio->notifyPendingWrite();
}
// Input side
+void AsynchIOHandler::giveReadCredit(int32_t credit) {
+ // Check whether we started in the don't about credit state
+ if (readCredit.boolCompareAndSwap(InfiniteCredit, credit))
+ return;
+ // TODO In theory should be able to use an atomic operation before taking the lock
+ // but in practice there seems to be an unexplained race in that case
+ ScopedLock<Mutex> l(creditLock);
+ if (readCredit.fetchAndAdd(credit) != 0)
+ return;
+ assert(readCredit.get() >= 0);
+ if (readCredit.get() != 0)
+ aio->startReading();
+}
+
void AsynchIOHandler::readbuff(AsynchIO& , AsynchIO::BufferBase* buff) {
if (readError) {
return;
}
+
+ // Check here for read credit
+ if (readCredit.get() != InfiniteCredit) {
+ if (readCredit.get() == 0) {
+ // FIXME aconway 2009-10-01: Workaround to avoid "false wakeups".
+ // readbuff is sometimes called with no credit.
+ // This should be fixed somewhere else to avoid such calls.
+ aio->unread(buff);
+ return;
+ }
+ // TODO In theory should be able to use an atomic operation before taking the lock
+ // but in practice there seems to be an unexplained race in that case
+ ScopedLock<Mutex> l(creditLock);
+ if (--readCredit == 0) {
+ assert(readCredit.get() >= 0);
+ if (readCredit.get() == 0) {
+ aio->stopReading();
+ }
+ }
+ }
+
size_t decoded = 0;
if (codec) { // Already initiated
try {
@@ -99,13 +144,13 @@ void AsynchIOHandler::readbuff(AsynchIO& , AsynchIO::BufferBase* buff) {
decoded = in.getPosition();
QPID_LOG(debug, "RECV [" << identifier << "] INIT(" << protocolInit << ")");
try {
- codec = factory->create(protocolInit.getVersion(), *this, identifier);
+ codec = factory->create(protocolInit.getVersion(), *this, identifier, 0);
if (!codec) {
//TODO: may still want to revise this...
//send valid version header & close connection.
write(framing::ProtocolInitiation(framing::highestProtocolVersion));
readError = true;
- aio->queueWriteClose();
+ aio->queueWriteClose();
}
} catch (const std::exception& e) {
QPID_LOG(error, e.what());
@@ -130,11 +175,12 @@ void AsynchIOHandler::readbuff(AsynchIO& , AsynchIO::BufferBase* buff) {
void AsynchIOHandler::eof(AsynchIO&) {
QPID_LOG(debug, "DISCONNECTED [" << identifier << "]");
if (codec) codec->closed();
+ readError = true;
aio->queueWriteClose();
}
void AsynchIOHandler::closedSocket(AsynchIO&, const Socket& s) {
- // If we closed with data still to send log a warning
+ // If we closed with data still to send log a warning
if (!aio->writeQueueEmpty()) {
QPID_LOG(warning, "CLOSING [" << identifier << "] unsent data (probably due to client disconnect)");
}
@@ -154,21 +200,29 @@ void AsynchIOHandler::nobuffs(AsynchIO&) {
void AsynchIOHandler::idle(AsynchIO&){
if (isClient && codec == 0) {
- codec = factory->create(*this, identifier);
+ codec = factory->create(*this, identifier, 0);
write(framing::ProtocolInitiation(codec->getVersion()));
return;
}
if (codec == 0) return;
- if (codec->canEncode()) {
- // Try and get a queued buffer if not then construct new one
- AsynchIO::BufferBase* buff = aio->getQueuedBuffer();
- if (!buff) buff = new Buff;
- size_t encoded=codec->encode(buff->bytes, buff->byteCount);
- buff->dataCount = encoded;
- aio->queueWrite(buff);
- }
- if (codec->isClosed())
+ try {
+ if (codec->canEncode()) {
+ // Try and get a queued buffer if not then construct new one
+ AsynchIO::BufferBase* buff = aio->getQueuedBuffer();
+ if (!buff) buff = new Buff;
+ size_t encoded=codec->encode(buff->bytes, buff->byteCount);
+ buff->dataCount = encoded;
+ aio->queueWrite(buff);
+ }
+ if (codec->isClosed()) {
+ readError = true;
+ aio->queueWriteClose();
+ }
+ } catch (const std::exception& e) {
+ QPID_LOG(error, e.what());
+ readError = true;
aio->queueWriteClose();
+ }
}
}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/AsynchIOHandler.h b/cpp/src/qpid/sys/AsynchIOHandler.h
index 26e2cf4c5c..e1885bac79 100644
--- a/cpp/src/qpid/sys/AsynchIOHandler.h
+++ b/cpp/src/qpid/sys/AsynchIOHandler.h
@@ -9,9 +9,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -21,8 +21,11 @@
*
*/
-#include "OutputControl.h"
-#include "ConnectionCodec.h"
+#include "qpid/sys/OutputControl.h"
+#include "qpid/sys/ConnectionCodec.h"
+#include "qpid/sys/AtomicValue.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/CommonImportExport.h"
namespace qpid {
@@ -33,7 +36,7 @@ namespace framing {
namespace sys {
class AsynchIO;
-class AsynchIOBufferBase;
+struct AsynchIOBufferBase;
class Socket;
class AsynchIOHandler : public OutputControl {
@@ -43,29 +46,33 @@ class AsynchIOHandler : public OutputControl {
ConnectionCodec* codec;
bool readError;
bool isClient;
+ AtomicValue<int32_t> readCredit;
+ static const int32_t InfiniteCredit = -1;
+ Mutex creditLock;
void write(const framing::ProtocolInitiation&);
public:
- AsynchIOHandler(std::string id, ConnectionCodec::Factory* f);
- ~AsynchIOHandler();
- void init(AsynchIO* a, int numBuffs);
+ QPID_COMMON_EXTERN AsynchIOHandler(std::string id, ConnectionCodec::Factory* f);
+ QPID_COMMON_EXTERN ~AsynchIOHandler();
+ QPID_COMMON_EXTERN void init(AsynchIO* a, int numBuffs);
- void setClient() { isClient = true; }
+ QPID_COMMON_EXTERN void setClient() { isClient = true; }
// Output side
- void close();
- void activateOutput();
+ QPID_COMMON_EXTERN void abort();
+ QPID_COMMON_EXTERN void activateOutput();
+ QPID_COMMON_EXTERN void giveReadCredit(int32_t credit);
// Input side
- void readbuff(AsynchIO& aio, AsynchIOBufferBase* buff);
- void eof(AsynchIO& aio);
- void disconnect(AsynchIO& aio);
-
+ QPID_COMMON_EXTERN void readbuff(AsynchIO& aio, AsynchIOBufferBase* buff);
+ QPID_COMMON_EXTERN void eof(AsynchIO& aio);
+ QPID_COMMON_EXTERN void disconnect(AsynchIO& aio);
+
// Notifications
- void nobuffs(AsynchIO& aio);
- void idle(AsynchIO& aio);
- void closedSocket(AsynchIO& aio, const Socket& s);
+ QPID_COMMON_EXTERN void nobuffs(AsynchIO& aio);
+ QPID_COMMON_EXTERN void idle(AsynchIO& aio);
+ QPID_COMMON_EXTERN void closedSocket(AsynchIO& aio, const Socket& s);
};
}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/AtomicCount.h b/cpp/src/qpid/sys/AtomicCount.h
index d598b49427..94580c61f3 100644
--- a/cpp/src/qpid/sys/AtomicCount.h
+++ b/cpp/src/qpid/sys/AtomicCount.h
@@ -20,7 +20,7 @@
*/
#include <boost/detail/atomic_count.hpp>
-#include "ScopedIncrement.h"
+#include "qpid/sys/ScopedIncrement.h"
namespace qpid {
namespace sys {
diff --git a/cpp/src/qpid/sys/AtomicValue_gcc.h b/cpp/src/qpid/sys/AtomicValue_gcc.h
index da60edad65..d022b07c1d 100644
--- a/cpp/src/qpid/sys/AtomicValue_gcc.h
+++ b/cpp/src/qpid/sys/AtomicValue_gcc.h
@@ -57,7 +57,7 @@ class AtomicValue
/** If current value == testval then set to newval. Returns true if the swap was performed. */
bool boolCompareAndSwap(T testval, T newval) { return __sync_bool_compare_and_swap(&value, testval, newval); }
- T get() const { return const_cast<AtomicValue<T>*>(this)->fetchAndAdd(0); }
+ T get() const { return const_cast<AtomicValue<T>*>(this)->fetchAndAdd(static_cast<T>(0)); }
private:
T value;
diff --git a/cpp/src/qpid/sys/AtomicValue_mutex.h b/cpp/src/qpid/sys/AtomicValue_mutex.h
index 8871addbda..e4d433e7f5 100644
--- a/cpp/src/qpid/sys/AtomicValue_mutex.h
+++ b/cpp/src/qpid/sys/AtomicValue_mutex.h
@@ -53,6 +53,8 @@ class AtomicValue
inline T operator++(int) { return fetchAndAdd(1); }
inline T operator--(int) { return fetchAndSub(1); }
+ AtomicValue& operator=(T newval) { Lock l(lock); value = newval; return *this; }
+
/** If current value == testval then set to newval. Returns the old value. */
T valueCompareAndSwap(T testval, T newval) {
Lock l(lock);
diff --git a/cpp/src/qpid/sys/BlockingQueue.h b/cpp/src/qpid/sys/BlockingQueue.h
index c6c6291b97..210cb4ad82 100644
--- a/cpp/src/qpid/sys/BlockingQueue.h
+++ b/cpp/src/qpid/sys/BlockingQueue.h
@@ -22,7 +22,7 @@
*
*/
-#include "Waitable.h"
+#include "qpid/sys/Waitable.h"
#include <queue>
@@ -66,14 +66,17 @@ public:
return true;
}
- T pop() {
+ T pop(Duration timeout=TIME_INFINITE) {
T result;
- bool ok = pop(result);
- assert(ok); (void) ok; // Infinite wait.
+ bool ok = pop(result, timeout);
+ if (!ok)
+ throw Exception("Timed out waiting on a blocking queue");
return result;
}
- /** Push a value onto the queue */
+ /** Push a value onto the queue.
+ * Note it is not an error to push onto a closed queue.
+ */
void push(const T& t) {
Mutex::ScopedLock l(waitable);
queue.push(t);
diff --git a/cpp/src/qpid/sys/Codec.h b/cpp/src/qpid/sys/Codec.h
new file mode 100644
index 0000000000..ace721fbcc
--- /dev/null
+++ b/cpp/src/qpid/sys/Codec.h
@@ -0,0 +1,52 @@
+#ifndef QPID_SYS_CODEC_H
+#define QPID_SYS_CODEC_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <cstddef>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Generic codec interface
+ */
+class Codec
+{
+ public:
+ virtual ~Codec() {}
+
+ /** Decode from buffer, return number of bytes decoded.
+ * @return may be less than size if there was incomplete
+ * data at the end of the buffer.
+ */
+ virtual std::size_t decode(const char* buffer, std::size_t size) = 0;
+
+
+ /** Encode into buffer, return number of bytes encoded */
+ virtual std::size_t encode(const char* buffer, std::size_t size) = 0;
+
+ /** Return true if we have data to encode */
+ virtual bool canEncode() = 0;
+};
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_CODEC_H*/
diff --git a/cpp/src/qpid/sys/Condition.h b/cpp/src/qpid/sys/Condition.h
deleted file mode 100644
index 961c15e1ee..0000000000
--- a/cpp/src/qpid/sys/Condition.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef _sys_Condition_h
-#define _sys_Condition_h
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#ifdef USE_APR_PLATFORM
-#include "apr/Condition.h"
-#else
-#include "posix/Condition.h"
-#endif
-
-#endif /*!_sys_Condition_h*/
diff --git a/cpp/src/qpid/sys/ConnectionCodec.h b/cpp/src/qpid/sys/ConnectionCodec.h
index efc6839b60..7231b1daa6 100644
--- a/cpp/src/qpid/sys/ConnectionCodec.h
+++ b/cpp/src/qpid/sys/ConnectionCodec.h
@@ -21,54 +21,55 @@
* under the License.
*
*/
+#include "qpid/sys/Codec.h"
#include "qpid/framing/ProtocolVersion.h"
-#include "OutputControl.h"
-#include <memory>
-#include <map>
namespace qpid {
namespace sys {
+class InputHandlerFactory;
+class OutputControl;
+
/**
* Interface of coder/decoder for a connection of a specific protocol
* version.
*/
-class ConnectionCodec {
+class ConnectionCodec : public Codec {
public:
virtual ~ConnectionCodec() {}
- /** Decode from buffer, return number of bytes decoded.
- * @return may be less than size if there was incomplete
- * data at the end of the buffer.
- */
- virtual size_t decode(const char* buffer, size_t size) = 0;
-
-
- /** Encode into buffer, return number of bytes encoded */
- virtual size_t encode(const char* buffer, size_t size) = 0;
-
- /** Return true if we have data to encode */
- virtual bool canEncode() = 0;
-
/** Network connection was closed from other end. */
virtual void closed() = 0;
virtual bool isClosed() const = 0;
virtual framing::ProtocolVersion getVersion() const = 0;
-
+
struct Factory {
virtual ~Factory() {}
+ /** Security Strength Factor - indicates the level of security provided
+ * by the underlying transport. If zero, the transport provides no
+ * security (e.g. TCP). If non-zero, the transport provides some level
+ * of security (e.g. SSL). The values for SSF can be interpreted as:
+ *
+ * 0 = No protection.
+ * 1 = Integrity checking only.
+ * >1 = Supports authentication, integrity and confidentiality.
+ * The number represents the encryption key length.
+ */
+
/** Return 0 if version unknown */
virtual ConnectionCodec* create(
- framing::ProtocolVersion, OutputControl&, const std::string& id
+ framing::ProtocolVersion, OutputControl&, const std::string& id,
+ unsigned int conn_ssf
) = 0;
/** Return "preferred" codec for outbound connections. */
virtual ConnectionCodec* create(
- OutputControl&, const std::string& id
+ OutputControl&, const std::string& id,
+ unsigned int conn_ssf
) = 0;
};
};
diff --git a/cpp/src/qpid/sys/ConnectionInputHandler.h b/cpp/src/qpid/sys/ConnectionInputHandler.h
index a2c18d6d9a..9e85c66924 100644
--- a/cpp/src/qpid/sys/ConnectionInputHandler.h
+++ b/cpp/src/qpid/sys/ConnectionInputHandler.h
@@ -22,8 +22,8 @@
#define _ConnectionInputHandler_
#include "qpid/framing/InputHandler.h"
-#include "OutputTask.h"
-#include "TimeoutHandler.h"
+#include "qpid/sys/OutputTask.h"
+#include "qpid/sys/TimeoutHandler.h"
namespace qpid {
namespace sys {
@@ -33,6 +33,7 @@ namespace sys {
public TimeoutHandler, public OutputTask
{
public:
+
virtual void closed() = 0;
};
diff --git a/cpp/src/qpid/sys/ConnectionInputHandlerFactory.h b/cpp/src/qpid/sys/ConnectionInputHandlerFactory.h
index 2b309b5758..9bb7e13686 100644
--- a/cpp/src/qpid/sys/ConnectionInputHandlerFactory.h
+++ b/cpp/src/qpid/sys/ConnectionInputHandlerFactory.h
@@ -42,7 +42,8 @@ class ConnectionInputHandlerFactory : private boost::noncopyable
*@param id identify the connection for management purposes.
*/
virtual ConnectionInputHandler* create(ConnectionOutputHandler* out,
- const std::string& id) = 0;
+ const std::string& id,
+ bool isClient) = 0;
virtual ~ConnectionInputHandlerFactory(){}
};
diff --git a/cpp/src/qpid/sys/ConnectionOutputHandler.h b/cpp/src/qpid/sys/ConnectionOutputHandler.h
index 5a60ae4998..421dd7c269 100644
--- a/cpp/src/qpid/sys/ConnectionOutputHandler.h
+++ b/cpp/src/qpid/sys/ConnectionOutputHandler.h
@@ -22,7 +22,7 @@
#define _ConnectionOutputHandler_
#include "qpid/framing/OutputHandler.h"
-#include "OutputControl.h"
+#include "qpid/sys/OutputControl.h"
namespace qpid {
namespace sys {
@@ -34,6 +34,7 @@ class ConnectionOutputHandler : public virtual qpid::framing::OutputHandler, pub
{
public:
virtual void close() = 0;
+ virtual size_t getBuffered() const { return 0; }
};
}}
diff --git a/cpp/src/qpid/sys/ConnectionOutputHandlerPtr.h b/cpp/src/qpid/sys/ConnectionOutputHandlerPtr.h
new file mode 100644
index 0000000000..95a08d15ae
--- /dev/null
+++ b/cpp/src/qpid/sys/ConnectionOutputHandlerPtr.h
@@ -0,0 +1,56 @@
+#ifndef QPID_SYS_CONNECTIONOUTPUTHANDLERPTR_H
+#define QPID_SYS_CONNECTIONOUTPUTHANDLERPTR_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/ConnectionOutputHandler.h"
+
+namespace qpid {
+namespace sys {
+
+/**
+ * A ConnectionOutputHandler that delegates to another
+ * ConnectionOutputHandler. Allows the "real" ConnectionOutputHandler
+ * to be changed without updating all the pointers/references
+ * using the ConnectionOutputHandlerPtr
+ */
+class ConnectionOutputHandlerPtr : public ConnectionOutputHandler
+{
+ public:
+ ConnectionOutputHandlerPtr(ConnectionOutputHandler* p) : next(p) { assert(next); }
+ void set(ConnectionOutputHandler* p) { next = p; assert(next); }
+ ConnectionOutputHandler* get() { return next; }
+ const ConnectionOutputHandler* get() const { return next; }
+
+ void close() { next->close(); }
+ size_t getBuffered() const { return next->getBuffered(); }
+ void abort() { next->abort(); }
+ void activateOutput() { next->activateOutput(); }
+ void giveReadCredit(int32_t credit) { next->giveReadCredit(credit); }
+ void send(framing::AMQFrame& f) { next->send(f); }
+
+ private:
+ ConnectionOutputHandler* next;
+};
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_CONNECTIONOUTPUTHANDLERPTR_H*/
diff --git a/cpp/src/qpid/sys/CopyOnWriteArray.h b/cpp/src/qpid/sys/CopyOnWriteArray.h
new file mode 100644
index 0000000000..e4ae3a6094
--- /dev/null
+++ b/cpp/src/qpid/sys/CopyOnWriteArray.h
@@ -0,0 +1,138 @@
+#ifndef QPID_SYS_COPYONWRITEARRAY_H
+#define QPID_SYS_COPYONWRITEARRAY_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Mutex.h"
+#include <algorithm>
+#include <vector>
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * An array that copies on adding/removing element allowing lock-free
+ * iteration.
+ */
+template <class T>
+class CopyOnWriteArray
+{
+public:
+ typedef boost::shared_ptr<const std::vector<T> > ConstPtr;
+
+ CopyOnWriteArray() {}
+ CopyOnWriteArray(const CopyOnWriteArray& c) : array(c.array) {}
+
+ void add(T& t)
+ {
+ Mutex::ScopedLock l(lock);
+ ArrayPtr copy(array ? new std::vector<T>(*array) : new std::vector<T>());
+ copy->push_back(t);
+ array = copy;
+ }
+
+ bool remove(T& t)
+ {
+ Mutex::ScopedLock l(lock);
+ if (array && std::find(array->begin(), array->end(), t) != array->end()) {
+ ArrayPtr copy(new std::vector<T>(*array));
+ copy->erase(std::find(copy->begin(), copy->end(), t));
+ array = copy;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ bool clear()
+ {
+ Mutex::ScopedLock l(lock);
+ if (array && !array->empty()) {
+ ArrayPtr copy;
+ array = copy;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ template <class F>
+ bool add_unless(T& t, F f)
+ {
+ Mutex::ScopedLock l(lock);
+ if (array && std::find_if(array->begin(), array->end(), f) != array->end()) {
+ return false;
+ } else {
+ ArrayPtr copy(array ? new std::vector<T>(*array) : new std::vector<T>());
+ copy->push_back(t);
+ array = copy;
+ return true;
+ }
+ }
+
+ template <class F>
+ bool remove_if(F f)
+ {
+ Mutex::ScopedLock l(lock);
+ if (array && std::find_if(array->begin(), array->end(), f) != array->end()) {
+ ArrayPtr copy(new std::vector<T>(*array));
+ copy->erase(std::remove_if(copy->begin(), copy->end(), f), copy->end());
+ array = copy;
+ return true;
+ }
+ return false;
+ }
+
+ template <class F>
+ F for_each(F f)
+ {
+ ArrayPtr a;
+ {
+ Mutex::ScopedLock l(lock);
+ a = array;
+ }
+ if (!a) return f;
+ return std::for_each(a->begin(), a->end(), f);
+ }
+
+ ConstPtr snapshot()
+ {
+ ConstPtr a;
+ {
+ Mutex::ScopedLock l(lock);
+ a = array;
+ }
+ return a;
+ }
+
+private:
+ typedef boost::shared_ptr< std::vector<T> > ArrayPtr;
+ Mutex lock;
+ ArrayPtr array;
+};
+
+}}
+
+
+
+#endif /*!QPID_SYS_COPYONWRITEARRAY_H*/
diff --git a/cpp/src/qpid/sys/DeletionManager.h b/cpp/src/qpid/sys/DeletionManager.h
index 43154eb98e..c1fea19f30 100644
--- a/cpp/src/qpid/sys/DeletionManager.h
+++ b/cpp/src/qpid/sys/DeletionManager.h
@@ -54,6 +54,8 @@ struct deleter
template <typename H>
class DeletionManager
{
+ struct ThreadStatus;
+
public:
// Mark every thread as using the handle - it will be deleted
// below after every thread marks the handle as unused
@@ -65,6 +67,24 @@ public:
// handles get deleted here when no one else
// is using them either
static void markAllUnusedInThisThread() {
+ ThreadStatus* threadStatus = getThreadStatus();
+ ScopedLock<Mutex> l(threadStatus->lock);
+
+ // The actual deletions will happen here when all the shared_ptr
+ // ref counts hit 0 (that is when every thread marks the handle unused)
+ threadStatus->handles.clear();
+ }
+
+ static void destroyThreadState() {
+ ThreadStatus* threadStatus = getThreadStatus();
+ allThreadsStatuses.delThreadStatus(threadStatus);
+ delete threadStatus;
+ threadStatus = 0;
+ }
+
+private:
+
+ static ThreadStatus*& getThreadStatus() {
static __thread ThreadStatus* threadStatus = 0;
// Thread local vars can't be dynamically constructed so we need
@@ -75,14 +95,9 @@ public:
allThreadsStatuses.addThreadStatus(threadStatus);
}
- ScopedLock<Mutex> l(threadStatus->lock);
-
- // The actual deletions will happen here when all the shared_ptr
- // ref counts hit 0 (that is when every thread marks the handle unused)
- threadStatus->handles.clear();
+ return threadStatus;
}
-private:
typedef boost::shared_ptr<H> shared_ptr;
// In theory we know that we never need more handles than the number of
@@ -125,6 +140,15 @@ private:
statuses.push_back(t);
}
+ void delThreadStatus(ThreadStatus* t) {
+ ScopedLock<Mutex> l(lock);
+ typename std::vector<ThreadStatus*>::iterator it =
+ std::find(statuses.begin(),statuses.end(), t);
+ if (it != statuses.end()) {
+ statuses.erase(it);
+ }
+ }
+
void addHandle(shared_ptr h) {
ScopedLock<Mutex> l(lock);
std::for_each(statuses.begin(), statuses.end(), handleAdder(h));
diff --git a/cpp/src/qpid/sys/DispatchHandle.cpp b/cpp/src/qpid/sys/DispatchHandle.cpp
new file mode 100644
index 0000000000..605edabc64
--- /dev/null
+++ b/cpp/src/qpid/sys/DispatchHandle.cpp
@@ -0,0 +1,337 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/sys/DispatchHandle.h"
+
+#include <algorithm>
+
+#include <boost/cast.hpp>
+
+#include <assert.h>
+
+namespace qpid {
+namespace sys {
+
+DispatchHandle::DispatchHandle(const IOHandle& h, Callback rCb, Callback wCb, Callback dCb) :
+ PollerHandle(h),
+ readableCallback(rCb),
+ writableCallback(wCb),
+ disconnectedCallback(dCb),
+ state(IDLE)
+{
+}
+
+
+DispatchHandle::~DispatchHandle() {
+}
+
+void DispatchHandle::startWatch(Poller::shared_ptr poller0) {
+ bool r = readableCallback;
+ bool w = writableCallback;
+
+ ScopedLock<Mutex> lock(stateLock);
+ assert(state == IDLE);
+
+ poller = poller0;
+ poller->registerHandle(*this);
+ state = WAITING;
+ Poller::Direction dir = r ?
+ ( w ? Poller::INOUT : Poller::INPUT ) :
+ ( w ? Poller::OUTPUT : Poller::NONE );
+ poller->monitorHandle(*this, dir);
+}
+
+void DispatchHandle::rewatch() {
+ bool r = readableCallback;
+ bool w = writableCallback;
+ if (!r && !w) {
+ return;
+ }
+ Poller::Direction dir = r ?
+ ( w ? Poller::INOUT : Poller::INPUT ) :
+ ( w ? Poller::OUTPUT : Poller::NONE );
+
+ ScopedLock<Mutex> lock(stateLock);
+ switch(state) {
+ case IDLE:
+ case STOPPING:
+ case DELETING:
+ return;
+ default:
+ break;
+ }
+ assert(poller);
+ poller->monitorHandle(*this, dir);
+}
+
+void DispatchHandle::rewatchRead() {
+ if (!readableCallback) {
+ return;
+ }
+
+ ScopedLock<Mutex> lock(stateLock);
+ switch(state) {
+ case IDLE:
+ case STOPPING:
+ case DELETING:
+ return;
+ default:
+ break;
+ }
+ assert(poller);
+ poller->monitorHandle(*this, Poller::INPUT);
+}
+
+void DispatchHandle::rewatchWrite() {
+ if (!writableCallback) {
+ return;
+ }
+
+ ScopedLock<Mutex> lock(stateLock);
+ switch(state) {
+ case IDLE:
+ case STOPPING:
+ case DELETING:
+ return;
+ default:
+ break;
+ }
+ assert(poller);
+ poller->monitorHandle(*this, Poller::OUTPUT);
+}
+
+void DispatchHandle::unwatchRead() {
+ if (!readableCallback) {
+ return;
+ }
+
+ ScopedLock<Mutex> lock(stateLock);
+ switch(state) {
+ case IDLE:
+ case STOPPING:
+ case DELETING:
+ return;
+ default:
+ break;
+ }
+ assert(poller);
+ poller->unmonitorHandle(*this, Poller::INPUT);
+}
+
+void DispatchHandle::unwatchWrite() {
+ if (!writableCallback) {
+ return;
+ }
+
+ ScopedLock<Mutex> lock(stateLock);
+ switch(state) {
+ case IDLE:
+ case STOPPING:
+ case DELETING:
+ return;
+ default:
+ break;
+ }
+ assert(poller);
+ poller->unmonitorHandle(*this, Poller::OUTPUT);
+}
+
+void DispatchHandle::unwatch() {
+ ScopedLock<Mutex> lock(stateLock);
+ switch(state) {
+ case IDLE:
+ case STOPPING:
+ case DELETING:
+ return;
+ default:
+ break;
+ }
+ assert(poller);
+ poller->unmonitorHandle(*this, Poller::INOUT);
+}
+
+void DispatchHandle::stopWatch() {
+ ScopedLock<Mutex> lock(stateLock);
+ switch (state) {
+ case IDLE:
+ assert(state != IDLE);
+ return;
+ case STOPPING:
+ assert(state != STOPPING);
+ return;
+ case CALLING:
+ state = STOPPING;
+ break;
+ case WAITING:
+ state = IDLE;
+ break;
+ case DELETING:
+ return;
+ }
+ assert(poller);
+ poller->unregisterHandle(*this);
+ poller.reset();
+}
+
+// If we are in the IDLE/STOPPING state we can't do the callback as we've
+// not/no longer got the fd registered in any poller
+void DispatchHandle::call(Callback iCb) {
+ assert(iCb);
+ ScopedLock<Mutex> lock(stateLock);
+ switch (state) {
+ case IDLE:
+ case STOPPING:
+ case DELETING:
+ return;
+ default:
+ interruptedCallbacks.push(iCb);
+ assert(poller);
+ (void) poller->interrupt(*this);
+ }
+}
+
+// The slightly strange switch structure
+// is to ensure that the lock is released before
+// we do the delete
+void DispatchHandle::doDelete() {
+ {
+ ScopedLock<Mutex> lock(stateLock);
+ // Ensure that we're no longer watching anything
+ switch (state) {
+ case IDLE:
+ state = DELETING;
+ break;
+ case STOPPING:
+ state = DELETING;
+ return;
+ case WAITING:
+ state = DELETING;
+ assert(poller);
+ (void) poller->interrupt(*this);
+ poller->unregisterHandle(*this);
+ return;
+ case CALLING:
+ state = DELETING;
+ assert(poller);
+ poller->unregisterHandle(*this);
+ return;
+ case DELETING:
+ return;
+ }
+ }
+ // If we're IDLE we can do this right away
+ delete this;
+}
+
+void DispatchHandle::processEvent(Poller::EventType type) {
+
+ // Phase I
+ {
+ ScopedLock<Mutex> lock(stateLock);
+
+ switch(state) {
+ case IDLE:
+ // Can get here if a non connection thread stops watching
+ // whilst we were stuck in the above lock
+ return;
+ case WAITING:
+ state = CALLING;
+ break;
+ case CALLING:
+ assert(state!=CALLING);
+ return;
+ case STOPPING:
+ assert(state!=STOPPING);
+ return;
+ case DELETING:
+ // Need to make sure we clean up any pending callbacks in this case
+ std::swap(callbacks, interruptedCallbacks);
+ goto saybyebye;
+ }
+
+ std::swap(callbacks, interruptedCallbacks);
+ }
+
+ // Do callbacks - whilst we are doing the callbacks we are prevented from processing
+ // the same handle until we re-enable it. To avoid rentering the callbacks for a single
+ // handle re-enabling in the callbacks is actually deferred until they are complete.
+ switch (type) {
+ case Poller::READABLE:
+ readableCallback(*this);
+ break;
+ case Poller::WRITABLE:
+ writableCallback(*this);
+ break;
+ case Poller::READ_WRITABLE:
+ readableCallback(*this);
+ writableCallback(*this);
+ break;
+ case Poller::DISCONNECTED:
+ if (disconnectedCallback) {
+ disconnectedCallback(*this);
+ }
+ break;
+ case Poller::INTERRUPTED:
+ {
+ // We could only be interrupted if we also had a callback to do
+ assert(callbacks.size() > 0);
+ // We'll actually do the interrupt below
+ }
+ break;
+ default:
+ assert(false);
+ }
+
+ // If we have any callbacks do them now -
+ // (because we use a copy from before the previous callbacks we won't
+ // do anything yet that was just added)
+ while (callbacks.size() > 0) {
+ Callback cb = callbacks.front();
+ assert(cb);
+ cb(*this);
+ callbacks.pop();
+ }
+
+ {
+ ScopedLock<Mutex> lock(stateLock);
+ switch (state) {
+ case IDLE:
+ assert(state!=IDLE);
+ return;
+ case STOPPING:
+ state = IDLE;
+ return;
+ case WAITING:
+ assert(state!=WAITING);
+ return;
+ case CALLING:
+ state = WAITING;
+ return;
+ case DELETING:
+ break;
+ }
+ }
+
+saybyebye:
+ delete this;
+}
+
+}}
diff --git a/cpp/src/qpid/sys/DispatchHandle.h b/cpp/src/qpid/sys/DispatchHandle.h
new file mode 100644
index 0000000000..115a3c44f7
--- /dev/null
+++ b/cpp/src/qpid/sys/DispatchHandle.h
@@ -0,0 +1,150 @@
+#ifndef _sys_DispatchHandle_h
+#define _sys_DispatchHandle_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Poller.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/CommonImportExport.h"
+#include <boost/function.hpp>
+
+#include <queue>
+
+namespace qpid {
+namespace sys {
+
+class DispatchHandleRef;
+/**
+ * In order to have your own handle (file descriptor on Unix) watched by the poller
+ * you need to:
+ *
+ * - Subclass IOHandle, in the constructor supply an appropriate
+ * IOHandlerPrivate object for the platform.
+ *
+ * - Construct a DispatchHandle passing it your IOHandle and
+ * callback functions for read, write and disconnect events.
+ *
+ * - Ensure the DispatchHandle is not deleted until the poller is no longer using it.
+ * TODO: astitcher document DispatchHandleRef to simplify this.
+ *
+ * When an event occurs on the handle, the poller calls the relevant callback and
+ * stops watching that handle. Your callback can call rewatch() or related functions
+ * to re-enable polling.
+ */
+class DispatchHandle : public PollerHandle {
+ friend class DispatchHandleRef;
+public:
+ typedef boost::function1<void, DispatchHandle&> Callback;
+ typedef std::queue<Callback> CallbackQueue;
+
+private:
+ Callback readableCallback;
+ Callback writableCallback;
+ Callback disconnectedCallback;
+ CallbackQueue interruptedCallbacks;
+ CallbackQueue callbacks; // Double buffer
+ Poller::shared_ptr poller;
+ Mutex stateLock;
+ enum {
+ IDLE,
+ STOPPING,
+ WAITING,
+ CALLING,
+ DELETING
+ } state;
+
+public:
+ /**
+ * Provide a handle to poll and a set of callbacks. Note
+ * callbacks can be 0, meaning you are not interested in that
+ * event.
+ *
+ *@param h: the handle to watch. The IOHandle encapsulates a
+ * platfrom-specific handle to an IO object (e.g. a file descriptor
+ * on Unix.)
+ *@param rCb Callback called when the handle is readable.
+ *@param wCb Callback called when the handle is writable.
+ *@param dCb Callback called when the handle is disconnected.
+ */
+ QPID_COMMON_EXTERN DispatchHandle(const IOHandle& h, Callback rCb, Callback wCb, Callback dCb);
+ QPID_COMMON_EXTERN ~DispatchHandle();
+
+ /** Add this DispatchHandle to the poller to be watched. */
+ QPID_COMMON_EXTERN void startWatch(Poller::shared_ptr poller);
+
+ /** Resume watching for all non-0 callbacks. */
+ QPID_COMMON_EXTERN void rewatch();
+ /** Resume watching for read only. */
+ QPID_COMMON_EXTERN void rewatchRead();
+
+ /** Resume watching for write only. */
+ QPID_COMMON_EXTERN void rewatchWrite();
+
+ /** Stop watching temporarily. The DispatchHandle remains
+ associated with the poller and can be re-activated using
+ rewatch. */
+ QPID_COMMON_EXTERN void unwatch();
+ /** Stop watching for read */
+ QPID_COMMON_EXTERN void unwatchRead();
+ /** Stop watching for write */
+ QPID_COMMON_EXTERN void unwatchWrite();
+
+ /** Stop watching permanently. Disassociates from the poller. */
+ QPID_COMMON_EXTERN void stopWatch();
+
+ /** Interrupt watching this handle and make a serialised callback that respects the
+ * same exclusivity guarantees as the other callbacks
+ */
+ QPID_COMMON_EXTERN void call(Callback iCb);
+
+protected:
+ QPID_COMMON_EXTERN void doDelete();
+
+private:
+ QPID_COMMON_EXTERN void processEvent(Poller::EventType dir);
+};
+
+class DispatchHandleRef {
+ DispatchHandle* ref;
+
+public:
+ typedef boost::function1<void, DispatchHandle&> Callback;
+ DispatchHandleRef(const IOHandle& h, Callback rCb, Callback wCb, Callback dCb) :
+ ref(new DispatchHandle(h, rCb, wCb, dCb))
+ {}
+
+ ~DispatchHandleRef() { ref->doDelete(); }
+
+ void startWatch(Poller::shared_ptr poller) { ref->startWatch(poller); }
+ void rewatch() { ref->rewatch(); }
+ void rewatchRead() { ref->rewatchRead(); }
+ void rewatchWrite() { ref->rewatchWrite(); }
+ void unwatch() { ref->unwatch(); }
+ void unwatchRead() { ref->unwatchRead(); }
+ void unwatchWrite() { ref->unwatchWrite(); }
+ void stopWatch() { ref->stopWatch(); }
+ void call(Callback iCb) { ref->call(iCb); }
+};
+
+}}
+
+#endif // _sys_DispatchHandle_h
diff --git a/cpp/src/qpid/sys/Dispatcher.cpp b/cpp/src/qpid/sys/Dispatcher.cpp
index 02a62c8e66..5f52dcd990 100644
--- a/cpp/src/qpid/sys/Dispatcher.cpp
+++ b/cpp/src/qpid/sys/Dispatcher.cpp
@@ -19,9 +19,7 @@
*
*/
-#include "Dispatcher.h"
-
-#include <boost/cast.hpp>
+#include "qpid/sys/Dispatcher.h"
#include <assert.h>
@@ -36,404 +34,7 @@ Dispatcher::~Dispatcher() {
}
void Dispatcher::run() {
- do {
- Poller::Event event = poller->wait();
-
- // If can read/write then dispatch appropriate callbacks
- if (event.handle) {
- event.process();
- } else {
- // Handle shutdown
- switch (event.type) {
- case Poller::SHUTDOWN:
- goto dispatcher_shutdown;
- default:
- // This should be impossible
- assert(false);
- }
- }
- } while (true);
-
-dispatcher_shutdown:
- ;
-}
-
-DispatchHandle::~DispatchHandle() {
- stopWatch();
-}
-
-void DispatchHandle::startWatch(Poller::shared_ptr poller0) {
- bool r = readableCallback;
- bool w = writableCallback;
-
- ScopedLock<Mutex> lock(stateLock);
- assert(state == IDLE);
-
- // If no callbacks set then do nothing (that is what we were asked to do!)
- // TODO: Maybe this should be an assert instead
- if (!r && !w) {
- state = INACTIVE;
- return;
- }
-
- Poller::Direction d = r ?
- (w ? Poller::INOUT : Poller::IN) :
- Poller::OUT;
-
- poller = poller0;
- poller->addFd(*this, d);
-
- state = r ?
- (w ? ACTIVE_RW : ACTIVE_R) :
- ACTIVE_W;
-}
-
-void DispatchHandle::rewatch() {
- bool r = readableCallback;
- bool w = writableCallback;
-
- ScopedLock<Mutex> lock(stateLock);
- switch(state) {
- case IDLE:
- case DELAYED_IDLE:
- break;
- case DELAYED_R:
- case DELAYED_W:
- case DELAYED_INACTIVE:
- state = r ?
- (w ? DELAYED_RW : DELAYED_R) :
- DELAYED_W;
- break;
- case DELAYED_DELETE:
- break;
- case INACTIVE:
- case ACTIVE_R:
- case ACTIVE_W: {
- assert(poller);
- Poller::Direction d = r ?
- (w ? Poller::INOUT : Poller::IN) :
- Poller::OUT;
- poller->modFd(*this, d);
- state = r ?
- (w ? ACTIVE_RW : ACTIVE_R) :
- ACTIVE_W;
- break;
- }
- case DELAYED_RW:
- case ACTIVE_RW:
- // Don't need to do anything already waiting for readable/writable
- break;
- }
-}
-
-void DispatchHandle::rewatchRead() {
- if (!readableCallback) {
- return;
- }
-
- ScopedLock<Mutex> lock(stateLock);
- switch(state) {
- case IDLE:
- case DELAYED_IDLE:
- break;
- case DELAYED_R:
- case DELAYED_RW:
- case DELAYED_DELETE:
- break;
- case DELAYED_W:
- state = DELAYED_RW;
- break;
- case DELAYED_INACTIVE:
- state = DELAYED_R;
- break;
- case ACTIVE_R:
- case ACTIVE_RW:
- // Nothing to do: already waiting for readable
- break;
- case INACTIVE:
- assert(poller);
- poller->modFd(*this, Poller::IN);
- state = ACTIVE_R;
- break;
- case ACTIVE_W:
- assert(poller);
- poller->modFd(*this, Poller::INOUT);
- state = ACTIVE_RW;
- break;
- }
-}
-
-void DispatchHandle::rewatchWrite() {
- if (!writableCallback) {
- return;
- }
-
- ScopedLock<Mutex> lock(stateLock);
- switch(state) {
- case IDLE:
- case DELAYED_IDLE:
- break;
- case DELAYED_W:
- case DELAYED_RW:
- case DELAYED_DELETE:
- break;
- case DELAYED_R:
- state = DELAYED_RW;
- break;
- case DELAYED_INACTIVE:
- state = DELAYED_W;
- break;
- case INACTIVE:
- assert(poller);
- poller->modFd(*this, Poller::OUT);
- state = ACTIVE_W;
- break;
- case ACTIVE_R:
- assert(poller);
- poller->modFd(*this, Poller::INOUT);
- state = ACTIVE_RW;
- break;
- case ACTIVE_W:
- case ACTIVE_RW:
- // Nothing to do: already waiting for writable
- break;
- }
-}
-
-void DispatchHandle::unwatchRead() {
- if (!readableCallback) {
- return;
- }
-
- ScopedLock<Mutex> lock(stateLock);
- switch(state) {
- case IDLE:
- case DELAYED_IDLE:
- break;
- case DELAYED_R:
- state = DELAYED_INACTIVE;
- break;
- case DELAYED_RW:
- state = DELAYED_W;
- break;
- case DELAYED_W:
- case DELAYED_INACTIVE:
- case DELAYED_DELETE:
- break;
- case ACTIVE_R:
- assert(poller);
- poller->modFd(*this, Poller::NONE);
- state = INACTIVE;
- break;
- case ACTIVE_RW:
- assert(poller);
- poller->modFd(*this, Poller::OUT);
- state = ACTIVE_W;
- break;
- case ACTIVE_W:
- case INACTIVE:
- break;
- }
-}
-
-void DispatchHandle::unwatchWrite() {
- if (!writableCallback) {
- return;
- }
-
- ScopedLock<Mutex> lock(stateLock);
- switch(state) {
- case IDLE:
- case DELAYED_IDLE:
- break;
- case DELAYED_W:
- state = DELAYED_INACTIVE;
- break;
- case DELAYED_RW:
- state = DELAYED_R;
- break;
- case DELAYED_R:
- case DELAYED_INACTIVE:
- case DELAYED_DELETE:
- break;
- case ACTIVE_W:
- assert(poller);
- poller->modFd(*this, Poller::NONE);
- state = INACTIVE;
- break;
- case ACTIVE_RW:
- assert(poller);
- poller->modFd(*this, Poller::IN);
- state = ACTIVE_R;
- break;
- case ACTIVE_R:
- case INACTIVE:
- break;
- }
-}
-
-void DispatchHandle::unwatch() {
- ScopedLock<Mutex> lock(stateLock);
- switch (state) {
- case IDLE:
- case DELAYED_IDLE:
- break;
- case DELAYED_R:
- case DELAYED_W:
- case DELAYED_RW:
- case DELAYED_INACTIVE:
- state = DELAYED_INACTIVE;
- break;
- case DELAYED_DELETE:
- break;
- default:
- assert(poller);
- poller->modFd(*this, Poller::NONE);
- state = INACTIVE;
- break;
- }
-}
-
-void DispatchHandle::stopWatch() {
- ScopedLock<Mutex> lock(stateLock);
- switch (state) {
- case IDLE:
- case DELAYED_IDLE:
- case DELAYED_DELETE:
- return;
- case DELAYED_R:
- case DELAYED_W:
- case DELAYED_RW:
- case DELAYED_INACTIVE:
- state = DELAYED_IDLE;
- break;
- default:
- state = IDLE;
- break;
- }
- assert(poller);
- poller->delFd(*this);
- poller.reset();
-}
-
-// The slightly strange switch structure
-// is to ensure that the lock is released before
-// we do the delete
-void DispatchHandle::doDelete() {
- // Ensure that we're no longer watching anything
- stopWatch();
-
- // If we're in the middle of a callback defer the delete
- {
- ScopedLock<Mutex> lock(stateLock);
- switch (state) {
- case DELAYED_IDLE:
- case DELAYED_DELETE:
- state = DELAYED_DELETE;
- return;
- case IDLE:
- break;
- default:
- // Can only get out of stopWatch() in DELAYED_IDLE/DELAYED_DELETE/IDLE states
- assert(false);
- }
- }
- // If we're not then do it right away
- delete this;
-}
-
-void DispatchHandle::processEvent(Poller::EventType type) {
- // Note that we are now doing the callbacks
- {
- ScopedLock<Mutex> lock(stateLock);
-
- // Set up to wait for same events next time unless reset
- switch(state) {
- case ACTIVE_R:
- state = DELAYED_R;
- break;
- case ACTIVE_W:
- state = DELAYED_W;
- break;
- case ACTIVE_RW:
- state = DELAYED_RW;
- break;
- // Can only get here in a DELAYED_* state in the rare case
- // that we're already here for reading and we get activated for
- // writing and we can write (it might be possible the other way
- // round too). In this case we're already processing the handle
- // in a different thread in this function so return right away
- case DELAYED_R:
- case DELAYED_W:
- case DELAYED_RW:
- case DELAYED_INACTIVE:
- case DELAYED_IDLE:
- case DELAYED_DELETE:
- return;
- default:
- assert(false);
- }
- }
-
- // Do callbacks - whilst we are doing the callbacks we are prevented from processing
- // the same handle until we re-enable it. To avoid rentering the callbacks for a single
- // handle re-enabling in the callbacks is actually deferred until they are complete.
- switch (type) {
- case Poller::READABLE:
- readableCallback(*this);
- break;
- case Poller::WRITABLE:
- writableCallback(*this);
- break;
- case Poller::READ_WRITABLE:
- readableCallback(*this);
- writableCallback(*this);
- break;
- case Poller::DISCONNECTED:
- {
- ScopedLock<Mutex> lock(stateLock);
- state = DELAYED_INACTIVE;
- }
- if (disconnectedCallback) {
- disconnectedCallback(*this);
- }
- break;
- default:
- assert(false);
- }
-
- // If any of the callbacks re-enabled reading/writing then actually
- // do it now
- {
- ScopedLock<Mutex> lock(stateLock);
- switch (state) {
- case DELAYED_R:
- poller->modFd(*this, Poller::IN);
- state = ACTIVE_R;
- return;
- case DELAYED_W:
- poller->modFd(*this, Poller::OUT);
- state = ACTIVE_W;
- return;
- case DELAYED_RW:
- poller->modFd(*this, Poller::INOUT);
- state = ACTIVE_RW;
- return;
- case DELAYED_INACTIVE:
- state = INACTIVE;
- return;
- case DELAYED_IDLE:
- state = IDLE;
- return;
- default:
- // This should be impossible
- assert(false);
- return;
- case DELAYED_DELETE:
- break;
- }
- }
- delete this;
+ poller->run();
}
}}
diff --git a/cpp/src/qpid/sys/Dispatcher.h b/cpp/src/qpid/sys/Dispatcher.h
index 8e34354f9e..e8213d0579 100644
--- a/cpp/src/qpid/sys/Dispatcher.h
+++ b/cpp/src/qpid/sys/Dispatcher.h
@@ -22,139 +22,21 @@
*
*/
-#include "Poller.h"
-#include "Runnable.h"
-#include "Mutex.h"
-
-#include <memory>
-#include <queue>
-#include <boost/function.hpp>
-
-#include <assert.h>
-
+#include "qpid/sys/Poller.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/CommonImportExport.h"
namespace qpid {
namespace sys {
-class DispatchHandleRef;
-/**
- * In order to have your own handle (file descriptor on Unix) watched by the poller
- * you need to:
- *
- * - Subclass IOHandle, in the constructor supply an appropriate
- * IOHandlerPrivate object for the platform.
- *
- * - Construct a DispatchHandle passing it your IOHandle and
- * callback functions for read, write and disconnect events.
- *
- * - Ensure the DispatchHandle is not deleted until the poller is no longer using it.
- * TODO: astitcher document DispatchHandleRef to simplify this.
- *
- * When an event occurs on the handle, the poller calls the relevant callback and
- * stops watching that handle. Your callback can call rewatch() or related functions
- * to re-enable polling.
- */
-class DispatchHandle : public PollerHandle {
- friend class DispatchHandleRef;
-public:
- typedef boost::function1<void, DispatchHandle&> Callback;
-
-private:
- Callback readableCallback;
- Callback writableCallback;
- Callback disconnectedCallback;
- Poller::shared_ptr poller;
- Mutex stateLock;
- enum {
- IDLE, INACTIVE, ACTIVE_R, ACTIVE_W, ACTIVE_RW,
- DELAYED_IDLE, DELAYED_INACTIVE, DELAYED_R, DELAYED_W, DELAYED_RW,
- DELAYED_DELETE
- } state;
-
-public:
- /**
- * Provide a handle to poll and a set of callbacks. Note
- * callbacks can be 0, meaning you are not interested in that
- * event.
- *
- *@param h: the handle to watch. The IOHandle encapsulates a
- * platfrom-specific handle to an IO object (e.g. a file descriptor
- * on Unix.)
- *@param rCb Callback called when the handle is readable.
- *@param wCb Callback called when the handle is writable.
- *@param dCb Callback called when the handle is disconnected.
- */
- DispatchHandle(const IOHandle& h, Callback rCb, Callback wCb, Callback dCb) :
- PollerHandle(h),
- readableCallback(rCb),
- writableCallback(wCb),
- disconnectedCallback(dCb),
- state(IDLE)
- {}
-
- ~DispatchHandle();
-
- /** Add this DispatchHandle to the poller to be watched. */
- void startWatch(Poller::shared_ptr poller);
-
- /** Resume watchingn for all non-0 callbacks. */
- void rewatch();
- /** Resume watchingn for read only. */
- void rewatchRead();
-
- /** Resume watchingn for write only. */
- void rewatchWrite();
-
- /** Stop watching temporarily. The DispatchHandle remains
- associated with the poller and can be re-activated using
- rewatch. */
- void unwatch();
- /** Stop watching for read */
- void unwatchRead();
- /** Stop watching for write */
- void unwatchWrite();
-
- /** Stop watching permanently. Disassociates from the poller. */
- void stopWatch();
-
-protected:
- /** Override to get extra processing done when the DispatchHandle is deleted. */
- void doDelete();
-
-private:
- void processEvent(Poller::EventType dir);
-};
-
-class DispatchHandleRef {
- DispatchHandle* ref;
-
-public:
- typedef boost::function1<void, DispatchHandle&> Callback;
- DispatchHandleRef(const IOHandle& h, Callback rCb, Callback wCb, Callback dCb) :
- ref(new DispatchHandle(h, rCb, wCb, dCb))
- {}
-
- ~DispatchHandleRef() { ref->doDelete(); }
-
- void startWatch(Poller::shared_ptr poller) { ref->startWatch(poller); }
- void rewatch() { ref->rewatch(); }
- void rewatchRead() { ref->rewatchRead(); }
- void rewatchWrite() { ref->rewatchWrite(); }
- void unwatch() { ref->unwatch(); }
- void unwatchRead() { ref->unwatchRead(); }
- void unwatchWrite() { ref->unwatchWrite(); }
- void stopWatch() { ref->stopWatch(); }
-};
-
-
class Dispatcher : public Runnable {
const Poller::shared_ptr poller;
public:
- Dispatcher(Poller::shared_ptr poller);
- ~Dispatcher();
+ QPID_COMMON_EXTERN Dispatcher(Poller::shared_ptr poller);
+ QPID_COMMON_EXTERN ~Dispatcher();
- void run();
+ QPID_COMMON_EXTERN void run();
};
}}
diff --git a/cpp/src/qpid/sys/ExceptionHolder.h b/cpp/src/qpid/sys/ExceptionHolder.h
deleted file mode 100644
index cfb971411e..0000000000
--- a/cpp/src/qpid/sys/ExceptionHolder.h
+++ /dev/null
@@ -1,75 +0,0 @@
-#ifndef QPID_EXCEPTIONHOLDER_H
-#define QPID_EXCEPTIONHOLDER_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/memory.h"
-#include <boost/shared_ptr.hpp>
-
-
-namespace qpid {
-namespace sys {
-
-struct Raisable {
- virtual ~Raisable() {};
- virtual void raise() const=0;
- virtual std::string what() const=0;
-};
-
-/**
- * Holder for exceptions. Allows the thread that notices an error condition to
- * create an exception and store it to be thrown by another thread.
- */
-class ExceptionHolder : public Raisable {
- public:
- ExceptionHolder() {}
- // Use default copy & assign.
-
- /** Take ownership of ex */
- template <class Ex> ExceptionHolder(Ex* ex) { wrap(ex); }
- template <class Ex> ExceptionHolder(const boost::shared_ptr<Ex>& ex) { wrap(ex.release()); }
-
- template <class Ex> ExceptionHolder& operator=(Ex* ex) { wrap(ex); return *this; }
- template <class Ex> ExceptionHolder& operator=(boost::shared_ptr<Ex> ex) { wrap(ex.release()); return *this; }
-
- void raise() const { if (wrapper.get()) wrapper->raise() ; }
- std::string what() const { return wrapper->what(); }
- bool empty() const { return !wrapper.get(); }
- operator bool() const { return !empty(); }
- void reset() { wrapper.reset(); }
-
- private:
- template <class Ex> struct Wrapper : public Raisable {
- Wrapper(Ex* ptr) : exception(ptr) {}
- void raise() const { throw *exception; }
- std::string what() const { return exception->what(); }
- boost::shared_ptr<Ex> exception;
- };
- template <class Ex> void wrap(Ex* ex) { wrapper.reset(new Wrapper<Ex>(ex)); }
- boost::shared_ptr<Raisable> wrapper;
-};
-
-
-}} // namespace qpid::sys
-
-
-#endif /*!QPID_EXCEPTIONHOLDER_H*/
diff --git a/cpp/src/qpid/sys/FileSysDir.h b/cpp/src/qpid/sys/FileSysDir.h
new file mode 100755
index 0000000000..ffe7823f0a
--- /dev/null
+++ b/cpp/src/qpid/sys/FileSysDir.h
@@ -0,0 +1,62 @@
+#ifndef QPID_SYS_FILESYSDIR_H
+#define QPID_SYS_FILESYSDIR_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <string>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * @class FileSysDir
+ *
+ * Represents a filesystem directory accessible from the local host.
+ * This class simply checks existence of, and creates, a directory. It could
+ * be added to later to list contents, etc.
+ */
+class FileSysDir
+{
+ const std::string dirPath;
+
+ public:
+
+ FileSysDir (std::string path) : dirPath(path) {}
+ ~FileSysDir () {}
+
+ /**
+ * Check to see if the directory exists and is a directory. Throws an
+ * exception if there is an error checking existence or if the path
+ * exists but is not a directory.
+ *
+ * @retval true if the path exists and is a directory.
+ * @retval false if the path does not exist.
+ */
+ bool exists (void) const;
+
+ void mkdir(void);
+
+ std::string getPath () { return dirPath; }
+};
+
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_FILESYSDIR_H*/
diff --git a/cpp/src/qpid/sys/IOHandle.h b/cpp/src/qpid/sys/IOHandle.h
deleted file mode 100644
index d06512da58..0000000000
--- a/cpp/src/qpid/sys/IOHandle.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef _sys_IOHandle_h
-#define _sys_IOHandle_h
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-namespace qpid {
-namespace sys {
-
-/**
- * This is a class intended to abstract the Unix concept of file descriptor or the Windows concept of HANDLE
- */
-class PollerHandle;
-class IOHandlePrivate;
-class IOHandle {
- friend class PollerHandle;
-
-protected:
- IOHandlePrivate* const impl;
-
- IOHandle(IOHandlePrivate*);
- virtual ~IOHandle();
-};
-
-}}
-
-#endif // _sys_IOHandle_h
diff --git a/cpp/src/qpid/sys/LockFile.h b/cpp/src/qpid/sys/LockFile.h
index f06cd6a47d..14a76cbf3e 100644
--- a/cpp/src/qpid/sys/LockFile.h
+++ b/cpp/src/qpid/sys/LockFile.h
@@ -19,7 +19,44 @@
*
*/
-#include "posix/LockFile.h"
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+#include "qpid/CommonImportExport.h"
+#include "qpid/sys/IntegerTypes.h"
+
+namespace qpid {
+namespace sys {
+
+class LockFilePrivate;
+
+/**
+ * @class LockFile
+ *
+ * LockFile represents a locked file suitable for a coarse-grain system
+ * lock. For example, the broker uses this to ensure that only one broker
+ * runs. A common usage idiom is to store the current "owner" process ID
+ * in the lock file - if the lock file exists, but the stored process ID
+ * doesn't, the old owner has probably died without cleaning up the lock
+ * file.
+ */
+class LockFile : private boost::noncopyable
+{
+ std::string path;
+ bool created;
+ boost::shared_ptr<LockFilePrivate> impl;
+
+protected:
+ int read(void*, size_t) const;
+ int write(void*, size_t) const;
+
+public:
+ QPID_COMMON_EXTERN LockFile(const std::string& path_, bool create);
+ QPID_COMMON_EXTERN ~LockFile();
+};
+
+}} /* namespace qpid::sys */
#endif /*!_sys_LockFile_h*/
diff --git a/cpp/src/qpid/sys/LockPtr.h b/cpp/src/qpid/sys/LockPtr.h
new file mode 100644
index 0000000000..738a864317
--- /dev/null
+++ b/cpp/src/qpid/sys/LockPtr.h
@@ -0,0 +1,89 @@
+#ifndef QPID_SYS_LOCKPTR_H
+#define QPID_SYS_LOCKPTR_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Mutex.h"
+#include <boost/noncopyable.hpp>
+
+namespace qpid {
+namespace sys {
+
+class Mutex;
+
+/**
+ * LockPtr is a smart pointer to T. It is constructed from a volatile
+ * T* and a Lock (by default a Mutex). It const_casts away the
+ * volatile qualifier and locks the Lock for the duration of its
+ *
+ * Used in conjuntion with the "volatile" keyword to get the compiler
+ * to help enforce correct concurrent use of mutli-threaded objects.
+ * See ochttp://www.ddj.com/cpp/184403766 for a detailed discussion.
+ *
+ * To summarize the convention:
+ * - Declare thread-safe member functions as volatile.
+ * - Declare instances of the class that may be called concurrently as volatile.
+ * - Use LockPtr to cast away the volatile qualifier while taking a lock.
+ *
+ * This means that code calling on a concurrently-used object
+ * (declared volatile) can only call thread-safe (volatile) member
+ * functions. Code that needs to use thread-unsafe members must use a
+ * LockPtr, thereby acquiring the lock and making it safe to do so.
+ *
+ * A good type-safe pattern is the internally-locked object:
+ * - It has it's own private lock member.
+ * - All public functions are thread safe and declared volatile.
+ * - Any thread-unsafe, non-volatile functions are private.
+ * - Only member function implementations use LockPtr to access private functions.
+ *
+ * This encapsulates all the locking logic inside the class.
+ *
+ * One nice feature of this convention is the common case where you
+ * need a public, locked version of some function foo() and also a
+ * private unlocked version to avoid recursive locks. They can be declared as
+ * volatile and non-volatile overloads of the same function:
+ *
+ * // public
+ * void Thing::foo() volatile { LockPtr<Thing>(this, myLock)->foo(); }
+ * // private
+ * void Thing::foo() { ... do stuff ...}
+ */
+
+template <class T, class Lock> class LockPtr : public boost::noncopyable {
+ public:
+ LockPtr(volatile T* p, Lock& l) : ptr(const_cast<T*>(p)), lock(l) { lock.lock(); }
+ LockPtr(volatile T* p, volatile Lock& l) : ptr(const_cast<T*>(p)), lock(const_cast<Lock&>(l)) { lock.lock(); }
+ ~LockPtr() { lock.unlock(); }
+
+ T& operator*() { return *ptr; }
+ T* operator->() { return ptr; }
+
+ private:
+ T* ptr;
+ Lock& lock;
+};
+
+
+}} // namespace qpid::sys
+
+
+#endif /*!QPID_SYS_LOCKPTR_H*/
diff --git a/cpp/src/qpid/sys/Monitor.h b/cpp/src/qpid/sys/Monitor.h
deleted file mode 100644
index 1d9835675c..0000000000
--- a/cpp/src/qpid/sys/Monitor.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef _sys_Monitor_h
-#define _sys_Monitor_h
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <sys/errno.h>
-#include "Condition.h"
-
-namespace qpid {
-namespace sys {
-
-/**
- * A monitor is a condition variable and a mutex
- */
-class Monitor : public Mutex, public Condition {
- public:
- using Condition::wait;
- inline void wait();
- inline bool wait(const AbsTime& absoluteTime);
-};
-
-
-void Monitor::wait() {
- Condition::wait(*this);
-}
-
-bool Monitor::wait(const AbsTime& absoluteTime) {
- return Condition::wait(*this, absoluteTime);
-}
-
-}}
-#endif /*!_sys_Monitor_h*/
diff --git a/cpp/src/qpid/sys/Mutex.h b/cpp/src/qpid/sys/Mutex.h
deleted file mode 100644
index b4bd3a9b4a..0000000000
--- a/cpp/src/qpid/sys/Mutex.h
+++ /dev/null
@@ -1,89 +0,0 @@
-#ifndef _sys_Mutex_h
-#define _sys_Mutex_h
-
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-namespace qpid {
-namespace sys {
-
-/**
- * Scoped lock template: calls lock() in ctor, unlock() in dtor.
- * L can be any class with lock() and unlock() functions.
- */
-template <class L>
-class ScopedLock
-{
- public:
- ScopedLock(L& l) : mutex(l) { l.lock(); }
- ~ScopedLock() { mutex.unlock(); }
- private:
- L& mutex;
-};
-
-template <class L>
-class ScopedUnlock
-{
- public:
- ScopedUnlock(L& l) : mutex(l) { l.unlock(); }
- ~ScopedUnlock() { mutex.lock(); }
- private:
- L& mutex;
-};
-
-template <class L>
-class ScopedRlock
-{
- public:
- ScopedRlock(L& l) : mutex(l) { l.rlock(); }
- ~ScopedRlock() { mutex.unlock(); }
- private:
- L& mutex;
-};
-
-template <class L>
-class ScopedWlock
-{
- public:
- ScopedWlock(L& l) : mutex(l) { l.wlock(); }
- ~ScopedWlock() { mutex.unlock(); }
- private:
- L& mutex;
-};
-
-template <class L>
-class ConditionalScopedLock
-{
- public:
- ConditionalScopedLock(L& l) : mutex(l) { acquired = l.trylock(); }
- ~ConditionalScopedLock() { if (acquired) mutex.unlock(); }
- bool lockAcquired() { return acquired; }
- private:
- L& mutex;
- bool acquired;
-};
-
-}}
-
-#ifdef USE_APR_PLATFORM
-#include "apr/Mutex.h"
-#else
-#include "posix/Mutex.h"
-#endif
-
-#endif /*!_sys_Mutex_h*/
diff --git a/cpp/src/qpid/sys/OutputControl.h b/cpp/src/qpid/sys/OutputControl.h
index d922a0d85c..eae99beb0f 100644
--- a/cpp/src/qpid/sys/OutputControl.h
+++ b/cpp/src/qpid/sys/OutputControl.h
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -18,17 +18,22 @@
* under the License.
*
*/
+
+#include "qpid/sys/IntegerTypes.h"
+
#ifndef _OutputControl_
#define _OutputControl_
namespace qpid {
namespace sys {
- class OutputControl
+ class OutputControl
{
public:
virtual ~OutputControl() {}
+ virtual void abort() = 0;
virtual void activateOutput() = 0;
+ virtual void giveReadCredit(int32_t credit) = 0;
};
}
diff --git a/cpp/src/qpid/sys/PipeHandle.h b/cpp/src/qpid/sys/PipeHandle.h
new file mode 100755
index 0000000000..8aac76996b
--- /dev/null
+++ b/cpp/src/qpid/sys/PipeHandle.h
@@ -0,0 +1,51 @@
+#ifndef _sys_PipeHandle_h
+#define _sys_PipeHandle_h
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+#include "qpid/sys/IntegerTypes.h"
+#include "qpid/CommonImportExport.h"
+#include <string>
+
+// This class is a portability wrapper around pipe fds.
+// It currently exists primarily and solely for the purpose of
+// integration with single-threaded components that require QMF
+// integration through a signalling fd.
+
+namespace qpid {
+namespace sys {
+
+ class PipeHandle {
+ private:
+ int writeFd;
+ int readFd;
+ public:
+ QPID_COMMON_EXTERN PipeHandle(bool nonBlocking=true);
+ QPID_COMMON_EXTERN ~PipeHandle();
+ QPID_COMMON_EXTERN int read(void* buf, size_t bufSize);
+ QPID_COMMON_EXTERN int write(const void* buf, size_t bufSize);
+ QPID_COMMON_EXTERN int getReadHandle();
+ };
+
+}}
+
+#endif /*!_sys_PipeHandle_h*/
diff --git a/cpp/src/qpid/sys/PollableCondition.h b/cpp/src/qpid/sys/PollableCondition.h
new file mode 100644
index 0000000000..2eb6f2d947
--- /dev/null
+++ b/cpp/src/qpid/sys/PollableCondition.h
@@ -0,0 +1,64 @@
+#ifndef QPID_SYS_POLLABLECONDITION_H
+#define QPID_SYS_POLLABLECONDITION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Poller.h"
+#include "qpid/CommonImportExport.h"
+#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
+
+
+namespace qpid {
+namespace sys {
+
+class PollableConditionPrivate;
+
+class PollableCondition {
+public:
+ typedef boost::function1<void, PollableCondition&> Callback;
+
+ QPID_COMMON_EXTERN PollableCondition(const Callback& cb,
+ const boost::shared_ptr<sys::Poller>& poller);
+
+ QPID_COMMON_EXTERN ~PollableCondition();
+
+ /**
+ * Set the condition. Triggers callback to Callback from Poller.
+ */
+ QPID_COMMON_EXTERN void set();
+
+ /**
+ * Clear the condition. Stops callbacks from Poller.
+ */
+ QPID_COMMON_EXTERN void clear();
+
+ private:
+ PollableConditionPrivate *impl;
+
+ Callback callback;
+ boost::shared_ptr<sys::Poller> poller;
+};
+
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_POLLABLECONDITION_H*/
diff --git a/cpp/src/qpid/sys/PollableQueue.h b/cpp/src/qpid/sys/PollableQueue.h
new file mode 100644
index 0000000000..0786b21610
--- /dev/null
+++ b/cpp/src/qpid/sys/PollableQueue.h
@@ -0,0 +1,176 @@
+#ifndef QPID_SYS_POLLABLEQUEUE_H
+#define QPID_SYS_POLLABLEQUEUE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/PollableCondition.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/sys/Thread.h"
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+#include <algorithm>
+#include <vector>
+
+namespace qpid {
+namespace sys {
+
+class Poller;
+
+/**
+ * A queue whose item processing is dispatched by sys::Poller.
+ * Any thread can push to the queue; items pushed trigger an event the Poller
+ * recognizes. When a Poller I/O thread dispatches the event, a
+ * user-specified callback is invoked with all items on the queue.
+ */
+template <class T>
+class PollableQueue {
+ public:
+ typedef std::vector<T> Batch;
+ typedef T value_type;
+
+ /**
+ * Callback to process a batch of items from the queue.
+ *
+ * @param batch Queue of values to process. Any items remaining
+ * on return from Callback are put back on the queue.
+ * @return iterator pointing to the first un-processed item in batch.
+ * Items from this point up to batch.end() are put back on the queue.
+ */
+ typedef boost::function<typename Batch::const_iterator (const Batch& batch)> Callback;
+
+ /**
+ * Constructor; sets necessary parameters.
+ *
+ * @param cb Callback that will be called to process items on the
+ * queue. Will be called from a Poller I/O thread.
+ * @param poller Poller to use for dispatching queue events.
+ */
+ PollableQueue(const Callback& cb,
+ const boost::shared_ptr<sys::Poller>& poller);
+
+ ~PollableQueue();
+
+ /** Push a value onto the queue. Thread safe */
+ void push(const T& t);
+
+ /** Start polling. */
+ void start();
+
+ /** Stop polling and wait for the current callback, if any, to complete. */
+ void stop();
+
+ /** Are we currently stopped?*/
+ bool isStopped() const { ScopedLock l(lock); return stopped; }
+
+ size_t size() { ScopedLock l(lock); return queue.size(); }
+ bool empty() { ScopedLock l(lock); return queue.empty(); }
+
+ /**
+ * Allow any queued events to be processed; intended for calling
+ * after all dispatch threads exit the Poller loop in order to
+ * ensure clean shutdown with no events left on the queue.
+ */
+ void shutdown();
+
+ private:
+ typedef sys::Monitor::ScopedLock ScopedLock;
+ typedef sys::Monitor::ScopedUnlock ScopedUnlock;
+
+ void dispatch(PollableCondition& cond);
+ void process();
+
+ mutable sys::Monitor lock;
+ Callback callback;
+ PollableCondition condition;
+ Batch queue, batch;
+ Thread dispatcher;
+ bool stopped;
+};
+
+template <class T> PollableQueue<T>::PollableQueue(
+ const Callback& cb, const boost::shared_ptr<sys::Poller>& p)
+ : callback(cb),
+ condition(boost::bind(&PollableQueue<T>::dispatch, this, _1), p),
+ stopped(true)
+{
+}
+
+template <class T> void PollableQueue<T>::start() {
+ ScopedLock l(lock);
+ if (!stopped) return;
+ stopped = false;
+ if (!queue.empty()) condition.set();
+}
+
+template <class T> PollableQueue<T>::~PollableQueue() {
+}
+
+template <class T> void PollableQueue<T>::push(const T& t) {
+ ScopedLock l(lock);
+ if (queue.empty()) condition.set();
+ queue.push_back(t);
+}
+
+template <class T> void PollableQueue<T>::dispatch(PollableCondition& cond) {
+ ScopedLock l(lock);
+ assert(dispatcher.id() == 0);
+ dispatcher = Thread::current();
+ process();
+ dispatcher = Thread();
+ if (queue.empty()) cond.clear();
+ if (stopped) lock.notifyAll();
+}
+
+template <class T> void PollableQueue<T>::process() {
+ // Called with lock held
+ while (!stopped && !queue.empty()) {
+ assert(batch.empty());
+ batch.swap(queue);
+ typename Batch::const_iterator putBack;
+ {
+ ScopedUnlock u(lock); // Allow concurrent push to queue.
+ putBack = callback(batch);
+ }
+ // put back unprocessed items.
+ queue.insert(queue.begin(), putBack, typename Batch::const_iterator(batch.end()));
+ batch.clear();
+ }
+}
+
+template <class T> void PollableQueue<T>::shutdown() {
+ ScopedLock l(lock);
+ process();
+}
+
+template <class T> void PollableQueue<T>::stop() {
+ ScopedLock l(lock);
+ if (stopped) return;
+ condition.clear();
+ stopped = true;
+ // Avoid deadlock if stop is called from the dispatch thread
+ if (dispatcher.id() != Thread::current().id())
+ while (dispatcher.id()) lock.wait();
+}
+
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_POLLABLEQUEUE_H*/
diff --git a/cpp/src/qpid/sys/Poller.h b/cpp/src/qpid/sys/Poller.h
index e39528bdb5..413d4242b8 100644
--- a/cpp/src/qpid/sys/Poller.h
+++ b/cpp/src/qpid/sys/Poller.h
@@ -22,8 +22,9 @@
*
*/
-#include "Time.h"
-
+#include "qpid/sys/Time.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/CommonImportExport.h"
#include <boost/shared_ptr.hpp>
namespace qpid {
@@ -37,7 +38,7 @@ namespace sys {
*/
class PollerHandle;
class PollerPrivate;
-class Poller {
+class Poller : public Runnable {
PollerPrivate* const impl;
public:
@@ -45,8 +46,8 @@ public:
enum Direction {
NONE = 0,
- IN,
- OUT,
+ INPUT,
+ OUTPUT,
INOUT
};
@@ -57,7 +58,8 @@ public:
READ_WRITABLE,
DISCONNECTED,
SHUTDOWN,
- TIMEOUT
+ TIMEOUT,
+ INTERRUPTED
};
struct Event {
@@ -72,16 +74,31 @@ public:
void process();
};
- Poller();
- ~Poller();
+ QPID_COMMON_EXTERN Poller();
+ QPID_COMMON_EXTERN ~Poller();
/** Note: this function is async-signal safe */
- void shutdown();
+ QPID_COMMON_EXTERN void shutdown();
+
+ // Interrupt waiting for a specific poller handle
+ // returns true if we could interrupt the handle
+ // - in this case on return the handle is no longer being monitored,
+ // but we will receive an event from some invocation of poller::wait
+ // with the handle and the INTERRUPTED event type
+ // if it returns false then the handle is not being monitored by the poller
+ // - This can either be because it has just received an event which has been
+ // reported and has not been reenabled since.
+ // - Because it was removed from the monitoring set
+ // - Or because it is already being interrupted
+ QPID_COMMON_EXTERN bool interrupt(PollerHandle& handle);
+
+ // Poller run loop
+ QPID_COMMON_EXTERN void run();
- void addFd(PollerHandle& handle, Direction dir);
- void delFd(PollerHandle& handle);
- void modFd(PollerHandle& handle, Direction dir);
- void rearmFd(PollerHandle& handle);
- Event wait(Duration timeout = TIME_INFINITE);
+ QPID_COMMON_EXTERN void registerHandle(PollerHandle& handle);
+ QPID_COMMON_EXTERN void unregisterHandle(PollerHandle& handle);
+ QPID_COMMON_EXTERN void monitorHandle(PollerHandle& handle, Direction dir);
+ QPID_COMMON_EXTERN void unmonitorHandle(PollerHandle& handle, Direction dir);
+ QPID_COMMON_EXTERN Event wait(Duration timeout = TIME_INFINITE);
};
/**
@@ -91,14 +108,15 @@ class IOHandle;
class PollerHandlePrivate;
class PollerHandle {
friend class Poller;
+ friend class PollerPrivate;
friend struct Poller::Event;
PollerHandlePrivate* const impl;
- virtual void processEvent(Poller::EventType) {};
+ QPID_COMMON_EXTERN virtual void processEvent(Poller::EventType) {};
public:
- PollerHandle(const IOHandle& h);
- virtual ~PollerHandle();
+ QPID_COMMON_EXTERN PollerHandle(const IOHandle& h);
+ QPID_COMMON_EXTERN virtual ~PollerHandle();
};
inline void Poller::Event::process() {
diff --git a/cpp/src/qpid/sys/ProtocolFactory.h b/cpp/src/qpid/sys/ProtocolFactory.h
index 4aa14d2cf6..b233b2da1a 100644
--- a/cpp/src/qpid/sys/ProtocolFactory.h
+++ b/cpp/src/qpid/sys/ProtocolFactory.h
@@ -22,9 +22,9 @@
*
*/
-#include <stdint.h>
+#include "qpid/sys/IntegerTypes.h"
#include "qpid/SharedObject.h"
-#include "ConnectionCodec.h"
+#include "qpid/sys/ConnectionCodec.h"
#include <boost/function.hpp>
namespace qpid {
@@ -46,6 +46,7 @@ class ProtocolFactory : public qpid::SharedObject<ProtocolFactory>
const std::string& host, int16_t port,
ConnectionCodec::Factory* codec,
ConnectFailedCallback failed) = 0;
+ virtual bool supports(const std::string& /*capability*/) { return false; }
};
inline ProtocolFactory::~ProtocolFactory() {}
diff --git a/cpp/src/qpid/sys/RdmaIOPlugin.cpp b/cpp/src/qpid/sys/RdmaIOPlugin.cpp
new file mode 100644
index 0000000000..bd19247124
--- /dev/null
+++ b/cpp/src/qpid/sys/RdmaIOPlugin.cpp
@@ -0,0 +1,353 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/ProtocolFactory.h"
+
+#include "qpid/Plugin.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/framing/AMQP_HighestVersion.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/rdma/RdmaIO.h"
+#include "qpid/sys/OutputControl.h"
+
+#include <boost/bind.hpp>
+#include <boost/lexical_cast.hpp>
+#include <memory>
+
+#include <netdb.h>
+
+using std::auto_ptr;
+using std::string;
+using std::stringstream;
+
+namespace qpid {
+namespace sys {
+
+class RdmaIOHandler : public OutputControl {
+ Rdma::Connection::intrusive_ptr connection;
+ std::string identifier;
+ Rdma::AsynchIO* aio;
+ ConnectionCodec::Factory* factory;
+ ConnectionCodec* codec;
+ bool readError;
+
+ void write(const framing::ProtocolInitiation&);
+
+ public:
+ RdmaIOHandler(Rdma::Connection::intrusive_ptr& c, ConnectionCodec::Factory* f);
+ ~RdmaIOHandler();
+ void init(Rdma::AsynchIO* a);
+ void start(Poller::shared_ptr poller) {aio->start(poller);}
+
+ // Output side
+ void close();
+ void abort();
+ void activateOutput();
+ void giveReadCredit(int32_t credit);
+ void initProtocolOut();
+
+ // Input side
+ void readbuff(Rdma::AsynchIO& aio, Rdma::Buffer* buff);
+ void initProtocolIn(Rdma::Buffer* buff);
+
+ // Notifications
+ void full(Rdma::AsynchIO& aio);
+ void idle(Rdma::AsynchIO& aio);
+ void error(Rdma::AsynchIO& aio);
+};
+
+RdmaIOHandler::RdmaIOHandler(Rdma::Connection::intrusive_ptr& c, qpid::sys::ConnectionCodec::Factory* f) :
+ connection(c),
+ identifier(c->getPeerName()),
+ factory(f),
+ codec(0),
+ readError(false)
+{
+}
+
+void RdmaIOHandler::init(Rdma::AsynchIO* a) {
+ aio = a;
+}
+
+RdmaIOHandler::~RdmaIOHandler() {
+ if (codec)
+ codec->closed();
+ delete codec;
+
+ aio->deferDelete();
+}
+
+void RdmaIOHandler::write(const framing::ProtocolInitiation& data)
+{
+ QPID_LOG(debug, "Rdma: SENT [" << identifier << "] INIT(" << data << ")");
+ Rdma::Buffer* buff = aio->getBuffer();
+ framing::Buffer out(buff->bytes, buff->byteCount);
+ data.encode(out);
+ buff->dataCount = data.encodedSize();
+ aio->queueWrite(buff);
+}
+
+void RdmaIOHandler::close() {
+ aio->queueWriteClose();
+}
+
+// TODO: Dummy implementation, need to fill this in for heartbeat timeout to work
+void RdmaIOHandler::abort() {
+}
+
+void RdmaIOHandler::activateOutput() {
+ aio->notifyPendingWrite();
+}
+
+void RdmaIOHandler::idle(Rdma::AsynchIO&) {
+ // TODO: Shouldn't need this test as idle() should only ever be called when
+ // the connection is writable anyway
+ if ( !(aio->writable() && aio->bufferAvailable()) ) {
+ return;
+ }
+ if (codec == 0) return;
+ if (codec->canEncode()) {
+ Rdma::Buffer* buff = aio->getBuffer();
+ size_t encoded=codec->encode(buff->bytes, buff->byteCount);
+ buff->dataCount = encoded;
+ aio->queueWrite(buff);
+ }
+ if (codec->isClosed())
+ aio->queueWriteClose();
+}
+
+void RdmaIOHandler::initProtocolOut() {
+ // We mustn't have already started the conversation
+ // but we must be able to send
+ assert( codec == 0 );
+ assert( aio->writable() && aio->bufferAvailable() );
+ codec = factory->create(*this, identifier, 0);
+ write(framing::ProtocolInitiation(codec->getVersion()));
+}
+
+void RdmaIOHandler::error(Rdma::AsynchIO&) {
+ close();
+}
+
+void RdmaIOHandler::full(Rdma::AsynchIO&) {
+ QPID_LOG(debug, "Rdma: buffer full [" << identifier << "]");
+}
+
+// TODO: Dummy implementation of read throttling
+void RdmaIOHandler::giveReadCredit(int32_t) {
+}
+
+// The logic here is subtly different from TCP as RDMA is message oriented
+// so we define that an RDMA message is a frame - in this case there is no putting back
+// of any message remainder - there shouldn't be any. And what we read here can't be
+// smaller than a frame
+void RdmaIOHandler::readbuff(Rdma::AsynchIO&, Rdma::Buffer* buff) {
+ if (readError) {
+ return;
+ }
+ size_t decoded = 0;
+ try {
+ if (codec) {
+ decoded = codec->decode(buff->bytes+buff->dataStart, buff->dataCount);
+ }else{
+ // Need to start protocol processing
+ initProtocolIn(buff);
+ }
+ }catch(const std::exception& e){
+ QPID_LOG(error, e.what());
+ readError = true;
+ aio->queueWriteClose();
+ }
+}
+
+void RdmaIOHandler::initProtocolIn(Rdma::Buffer* buff) {
+ framing::Buffer in(buff->bytes+buff->dataStart, buff->dataCount);
+ framing::ProtocolInitiation protocolInit;
+ size_t decoded = 0;
+ if (protocolInit.decode(in)) {
+ decoded = in.getPosition();
+ QPID_LOG(debug, "Rdma: RECV [" << identifier << "] INIT(" << protocolInit << ")");
+
+ codec = factory->create(protocolInit.getVersion(), *this, identifier, 0);
+
+ // If we failed to create the codec then we don't understand the offered protocol version
+ if (!codec) {
+ // send valid version header & close connection.
+ write(framing::ProtocolInitiation(framing::highestProtocolVersion));
+ readError = true;
+ aio->queueWriteClose();
+ }
+ }
+}
+
+class RdmaIOProtocolFactory : public ProtocolFactory {
+ auto_ptr<Rdma::Listener> listener;
+ const uint16_t listeningPort;
+
+ public:
+ RdmaIOProtocolFactory(int16_t port, int backlog);
+ void accept(Poller::shared_ptr, ConnectionCodec::Factory*);
+ void connect(Poller::shared_ptr, const string& host, int16_t port, ConnectionCodec::Factory*, ConnectFailedCallback);
+
+ uint16_t getPort() const;
+ string getHost() const;
+
+ private:
+ bool request(Rdma::Connection::intrusive_ptr&, const Rdma::ConnectionParams&, ConnectionCodec::Factory*);
+ void established(Poller::shared_ptr, Rdma::Connection::intrusive_ptr&);
+ void connected(Poller::shared_ptr, Rdma::Connection::intrusive_ptr&, const Rdma::ConnectionParams&, ConnectionCodec::Factory*);
+ void connectionError(Rdma::Connection::intrusive_ptr&, Rdma::ErrorType);
+ void disconnected(Rdma::Connection::intrusive_ptr&);
+ void rejected(Rdma::Connection::intrusive_ptr&, const Rdma::ConnectionParams&, ConnectFailedCallback);
+};
+
+// Static instance to initialise plugin
+static class RdmaIOPlugin : public Plugin {
+ void earlyInitialize(Target&) {
+ }
+
+ void initialize(Target& target) {
+ // Check whether we actually have any rdma devices
+ if ( Rdma::deviceCount() == 0 ) {
+ QPID_LOG(info, "Rdma: Disabled: no rdma devices found");
+ return;
+ }
+
+ broker::Broker* broker = dynamic_cast<broker::Broker*>(&target);
+ // Only provide to a Broker
+ if (broker) {
+ const broker::Broker::Options& opts = broker->getOptions();
+ ProtocolFactory::shared_ptr protocol(new RdmaIOProtocolFactory(opts.port, opts.connectionBacklog));
+ QPID_LOG(notice, "Rdma: Listening on RDMA port " << protocol->getPort());
+ broker->registerProtocolFactory("rdma", protocol);
+ }
+ }
+} rdmaPlugin;
+
+RdmaIOProtocolFactory::RdmaIOProtocolFactory(int16_t port, int /*backlog*/) :
+ listeningPort(port)
+{}
+
+void RdmaIOProtocolFactory::established(Poller::shared_ptr poller, Rdma::Connection::intrusive_ptr& ci) {
+ RdmaIOHandler* async = ci->getContext<RdmaIOHandler>();
+ async->start(poller);
+}
+
+bool RdmaIOProtocolFactory::request(Rdma::Connection::intrusive_ptr& ci, const Rdma::ConnectionParams& cp,
+ ConnectionCodec::Factory* f) {
+ try {
+ RdmaIOHandler* async = new RdmaIOHandler(ci, f);
+ Rdma::AsynchIO* aio =
+ new Rdma::AsynchIO(ci->getQueuePair(),
+ cp.maxRecvBufferSize, cp.initialXmitCredit, Rdma::DEFAULT_WR_ENTRIES,
+ boost::bind(&RdmaIOHandler::readbuff, async, _1, _2),
+ boost::bind(&RdmaIOHandler::idle, async, _1),
+ 0, // boost::bind(&RdmaIOHandler::full, async, _1),
+ boost::bind(&RdmaIOHandler::error, async, _1));
+ async->init(aio);
+
+ // Record aio so we can get it back from a connection
+ ci->addContext(async);
+ return true;
+ } catch (const Rdma::Exception& e) {
+ QPID_LOG(error, "Rdma: Cannot accept new connection (Rdma exception): " << e.what());
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Rdma: Cannot accept new connection (unknown exception): " << e.what());
+ }
+
+ // If we get here we caught an exception so reject connection
+ return false;
+}
+
+void RdmaIOProtocolFactory::connectionError(Rdma::Connection::intrusive_ptr&, Rdma::ErrorType) {
+}
+
+void RdmaIOProtocolFactory::disconnected(Rdma::Connection::intrusive_ptr& ci) {
+ // If we've got a connection already tear it down, otherwise ignore
+ RdmaIOHandler* async = ci->getContext<RdmaIOHandler>();
+ if (async) {
+ async->close();
+ }
+ delete async;
+}
+
+uint16_t RdmaIOProtocolFactory::getPort() const {
+ return listeningPort; // Immutable no need for lock.
+}
+
+string RdmaIOProtocolFactory::getHost() const {
+ //return listener.getSockname();
+ return "";
+}
+
+void RdmaIOProtocolFactory::accept(Poller::shared_ptr poller, ConnectionCodec::Factory* fact) {
+ ::sockaddr_in sin;
+
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(listeningPort);
+ sin.sin_addr.s_addr = INADDR_ANY;
+
+ SocketAddress sa("",boost::lexical_cast<std::string>(listeningPort));
+ listener.reset(
+ new Rdma::Listener(sa,
+ Rdma::ConnectionParams(65536, Rdma::DEFAULT_WR_ENTRIES),
+ boost::bind(&RdmaIOProtocolFactory::established, this, poller, _1),
+ boost::bind(&RdmaIOProtocolFactory::connectionError, this, _1, _2),
+ boost::bind(&RdmaIOProtocolFactory::disconnected, this, _1),
+ boost::bind(&RdmaIOProtocolFactory::request, this, _1, _2, fact)));
+
+ listener->start(poller);
+}
+
+// Only used for outgoing connections (in federation)
+void RdmaIOProtocolFactory::rejected(Rdma::Connection::intrusive_ptr&, const Rdma::ConnectionParams&, ConnectFailedCallback failed) {
+ failed(-1, "Connection rejected");
+}
+
+// Do the same as connection request and established but mark a client too
+void RdmaIOProtocolFactory::connected(Poller::shared_ptr poller, Rdma::Connection::intrusive_ptr& ci, const Rdma::ConnectionParams& cp,
+ ConnectionCodec::Factory* f) {
+ (void) request(ci, cp, f);
+ established(poller, ci);
+ RdmaIOHandler* async = ci->getContext<RdmaIOHandler>();
+ async->initProtocolOut();
+}
+
+void RdmaIOProtocolFactory::connect(
+ Poller::shared_ptr poller,
+ const std::string& host, int16_t port,
+ ConnectionCodec::Factory* f,
+ ConnectFailedCallback failed)
+{
+ SocketAddress sa(host, boost::lexical_cast<std::string>(port));
+ Rdma::Connector* c =
+ new Rdma::Connector(
+ sa,
+ Rdma::ConnectionParams(8000, Rdma::DEFAULT_WR_ENTRIES),
+ boost::bind(&RdmaIOProtocolFactory::connected, this, poller, _1, _2, f),
+ boost::bind(&RdmaIOProtocolFactory::connectionError, this, _1, _2),
+ boost::bind(&RdmaIOProtocolFactory::disconnected, this, _1),
+ boost::bind(&RdmaIOProtocolFactory::rejected, this, _1, _2, failed));
+
+ c->start(poller);
+}
+
+}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/Runnable.cpp b/cpp/src/qpid/sys/Runnable.cpp
index 30122c682f..325d87c91b 100644
--- a/cpp/src/qpid/sys/Runnable.cpp
+++ b/cpp/src/qpid/sys/Runnable.cpp
@@ -16,7 +16,7 @@
*
*/
-#include "Runnable.h"
+#include "qpid/sys/Runnable.h"
#include <boost/bind.hpp>
namespace qpid {
diff --git a/cpp/src/qpid/sys/Runnable.h b/cpp/src/qpid/sys/Runnable.h
deleted file mode 100644
index fb3927c612..0000000000
--- a/cpp/src/qpid/sys/Runnable.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef _Runnable_
-#define _Runnable_
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <boost/function.hpp>
-
-namespace qpid {
-namespace sys {
-
-/**
- * Interface for objects that can be run, e.g. in a thread.
- */
-class Runnable
-{
- public:
- /** Type to represent a runnable as a Functor */
- typedef boost::function0<void> Functor;
-
- virtual ~Runnable();
-
- /** Derived classes override run(). */
- virtual void run() = 0;
-
- /** Create a functor object that will call this->run(). */
- Functor functor();
-};
-
-}}
-
-
-#endif
diff --git a/cpp/src/qpid/sys/SecurityLayer.h b/cpp/src/qpid/sys/SecurityLayer.h
new file mode 100644
index 0000000000..52bc40e352
--- /dev/null
+++ b/cpp/src/qpid/sys/SecurityLayer.h
@@ -0,0 +1,42 @@
+#ifndef QPID_SYS_SECURITYLAYER_H
+#define QPID_SYS_SECURITYLAYER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/sys/Codec.h"
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Defines interface to a SASL negotiated Security Layer (for
+ * encryption/integrity)
+ */
+class SecurityLayer : public Codec
+{
+ public:
+ virtual void init(Codec*) = 0;
+ virtual ~SecurityLayer() {}
+};
+
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_SECURITYLAYER_H*/
diff --git a/cpp/src/qpid/sys/Semaphore.h b/cpp/src/qpid/sys/Semaphore.h
index 3efb7ce2df..9d70f89aeb 100644
--- a/cpp/src/qpid/sys/Semaphore.h
+++ b/cpp/src/qpid/sys/Semaphore.h
@@ -19,7 +19,7 @@
*
*/
-#include "Monitor.h"
+#include "qpid/sys/Monitor.h"
namespace qpid {
namespace sys {
@@ -51,10 +51,22 @@ public:
count--;
}
+ void release(uint n)
+ {
+ Monitor::ScopedLock l(monitor);
+ if (count==0) monitor.notifyAll();
+ count+=n;
+ }
+
void release()
{
+ release(1);
+ }
+
+ void forceLock()
+ {
Monitor::ScopedLock l(monitor);
- if (!count++) monitor.notifyAll();
+ count = 0;
}
private:
diff --git a/cpp/src/qpid/sys/Shlib.cpp b/cpp/src/qpid/sys/Shlib.cpp
index 8fd3f42cc6..342d726876 100644
--- a/cpp/src/qpid/sys/Shlib.cpp
+++ b/cpp/src/qpid/sys/Shlib.cpp
@@ -18,7 +18,7 @@
*
*/
-#include "Shlib.h"
+#include "qpid/sys/Shlib.h"
#include "qpid/log/Statement.h"
diff --git a/cpp/src/qpid/sys/Shlib.h b/cpp/src/qpid/sys/Shlib.h
index e2752dc7d6..7f66cfec14 100644
--- a/cpp/src/qpid/sys/Shlib.h
+++ b/cpp/src/qpid/sys/Shlib.h
@@ -21,10 +21,10 @@
* under the License.
*
*/
-
+
+#include "qpid/CommonImportExport.h"
#include <boost/noncopyable.hpp>
#include <iostream>
-#include <dlfcn.h>
namespace qpid {
namespace sys {
@@ -41,10 +41,10 @@ class Shlib {
Shlib(const std::string& libname) { load(libname.c_str()); }
/** Unload shared library. */
- void unload();
+ QPID_COMMON_EXTERN void unload();
/** Look up symbol. */
- void* getSymbol(const char* symbol);
+ QPID_COMMON_EXTERN void* getSymbol(const char* symbol);
/** Look up symbol in shared library, cast it to the desired
* pointer type, void* by default.
@@ -58,7 +58,7 @@ class Shlib {
private:
void* handle;
- void load(const char* libname);
+ QPID_COMMON_EXTERN void load(const char* libname);
};
/** A shared library handle that unloads the shlib in it's dtor */
@@ -67,7 +67,7 @@ class AutoShlib : public Shlib {
/** Load shared library */
AutoShlib(const std::string& libname) : Shlib(libname) {}
/** Calls unload() */
- ~AutoShlib() throw();
+ QPID_COMMON_EXTERN ~AutoShlib() throw();
};
diff --git a/cpp/src/qpid/sys/Socket.h b/cpp/src/qpid/sys/Socket.h
index dd7ef9a96d..7b50c42a3c 100644
--- a/cpp/src/qpid/sys/Socket.h
+++ b/cpp/src/qpid/sys/Socket.h
@@ -22,47 +22,48 @@
*
*/
-#include "IOHandle.h"
-
+#include "qpid/sys/IOHandle.h"
+#include "qpid/sys/IntegerTypes.h"
+#include "qpid/CommonImportExport.h"
#include <string>
-struct sockaddr;
-
namespace qpid {
namespace sys {
class Duration;
+class SocketAddress;
class Socket : public IOHandle
{
public:
/** Create a socket wrapper for descriptor. */
- Socket();
+ QPID_COMMON_EXTERN Socket();
- /** Create an initialized TCP socket */
- void createTcp() const;
-
/** Set timeout for read and write */
void setTimeout(const Duration& interval) const;
-
+
/** Set socket non blocking */
void setNonblocking() const;
- void connect(const std::string& host, uint16_t port) const;
+ QPID_COMMON_EXTERN void setTcpNoDelay() const;
+
+ QPID_COMMON_EXTERN void connect(const std::string& host, uint16_t port) const;
+ QPID_COMMON_EXTERN void connect(const SocketAddress&) const;
- void close() const;
+ QPID_COMMON_EXTERN void close() const;
/** Bind to a port and start listening.
*@param port 0 means choose an available port.
*@param backlog maximum number of pending connections.
*@return The bound port.
*/
- int listen(uint16_t port = 0, int backlog = 10) const;
-
+ QPID_COMMON_EXTERN int listen(uint16_t port = 0, int backlog = 10) const;
+ QPID_COMMON_EXTERN int listen(const SocketAddress&, int backlog = 10) const;
+
/** Returns the "socket name" ie the address bound to
* the near end of the socket
*/
- std::string getSockname() const;
+ QPID_COMMON_EXTERN std::string getSockname() const;
/** Returns the "peer name" ie the address bound to
* the remote end of the socket
@@ -73,14 +74,14 @@ public:
* Returns an address (host and port) for the remote end of the
* socket
*/
- std::string getPeerAddress() const;
+ QPID_COMMON_EXTERN std::string getPeerAddress() const;
/**
* Returns an address (host and port) for the local end of the
* socket
*/
std::string getLocalAddress() const;
- uint16_t getLocalPort() const;
+ QPID_COMMON_EXTERN uint16_t getLocalPort() const;
uint16_t getRemotePort() const;
/**
@@ -92,17 +93,20 @@ public:
/** Accept a connection from a socket that is already listening
* and has an incoming connection
*/
- Socket* accept(struct sockaddr *addr, socklen_t *addrlen) const;
+ QPID_COMMON_EXTERN Socket* accept() const;
// TODO The following are raw operations, maybe they need better wrapping?
- int read(void *buf, size_t count) const;
- int write(const void *buf, size_t count) const;
-
- void setTcpNoDelay(bool nodelay) const;
+ QPID_COMMON_EXTERN int read(void *buf, size_t count) const;
+ QPID_COMMON_EXTERN int write(const void *buf, size_t count) const;
private:
+ /** Create socket */
+ void createSocket(const SocketAddress&) const;
+
Socket(IOHandlePrivate*);
mutable std::string connectname;
+ mutable bool nonblocking;
+ mutable bool nodelay;
};
}}
diff --git a/cpp/src/qpid/sys/SocketAddress.h b/cpp/src/qpid/sys/SocketAddress.h
new file mode 100644
index 0000000000..27b9642f2c
--- /dev/null
+++ b/cpp/src/qpid/sys/SocketAddress.h
@@ -0,0 +1,53 @@
+#ifndef _sys_SocketAddress_h
+#define _sys_SocketAddress_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/IntegerTypes.h"
+#include "qpid/CommonImportExport.h"
+#include <string>
+
+struct addrinfo;
+
+namespace qpid {
+namespace sys {
+
+class SocketAddress {
+ friend const ::addrinfo& getAddrInfo(const SocketAddress&);
+
+public:
+ /** Create a SocketAddress from hostname and port*/
+ QPID_COMMON_EXTERN SocketAddress(const std::string& host, const std::string& port);
+ QPID_COMMON_EXTERN SocketAddress(const SocketAddress&);
+ QPID_COMMON_EXTERN SocketAddress& operator=(const SocketAddress&);
+ QPID_COMMON_EXTERN ~SocketAddress();
+
+ std::string asString() const;
+
+private:
+ std::string host;
+ std::string port;
+ mutable ::addrinfo* addrInfo;
+};
+
+}}
+#endif /*!_sys_SocketAddress_h*/
diff --git a/cpp/src/qpid/sys/SslPlugin.cpp b/cpp/src/qpid/sys/SslPlugin.cpp
new file mode 100644
index 0000000000..c143f1f1d0
--- /dev/null
+++ b/cpp/src/qpid/sys/SslPlugin.cpp
@@ -0,0 +1,184 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/sys/ProtocolFactory.h"
+
+#include "qpid/Plugin.h"
+#include "qpid/sys/ssl/check.h"
+#include "qpid/sys/ssl/util.h"
+#include "qpid/sys/ssl/SslHandler.h"
+#include "qpid/sys/ssl/SslIo.h"
+#include "qpid/sys/ssl/SslSocket.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/log/Statement.h"
+
+#include <boost/bind.hpp>
+#include <memory>
+
+
+namespace qpid {
+namespace sys {
+
+struct SslServerOptions : ssl::SslOptions
+{
+ uint16_t port;
+ bool clientAuth;
+
+ SslServerOptions() : port(5671),
+ clientAuth(false)
+ {
+ addOptions()
+ ("ssl-port", optValue(port, "PORT"), "Port on which to listen for SSL connections")
+ ("ssl-require-client-authentication", optValue(clientAuth),
+ "Forces clients to authenticate in order to establish an SSL connection");
+ }
+};
+
+class SslProtocolFactory : public ProtocolFactory {
+ const bool tcpNoDelay;
+ qpid::sys::ssl::SslSocket listener;
+ const uint16_t listeningPort;
+ std::auto_ptr<qpid::sys::ssl::SslAcceptor> acceptor;
+
+ public:
+ SslProtocolFactory(const SslServerOptions&, int backlog, bool nodelay);
+ void accept(Poller::shared_ptr, ConnectionCodec::Factory*);
+ void connect(Poller::shared_ptr, const std::string& host, int16_t port,
+ ConnectionCodec::Factory*,
+ boost::function2<void, int, std::string> failed);
+
+ uint16_t getPort() const;
+ std::string getHost() const;
+ bool supports(const std::string& capability);
+
+ private:
+ void established(Poller::shared_ptr, const qpid::sys::ssl::SslSocket&, ConnectionCodec::Factory*,
+ bool isClient);
+};
+
+// Static instance to initialise plugin
+static struct SslPlugin : public Plugin {
+ SslServerOptions options;
+
+ Options* getOptions() { return &options; }
+
+ ~SslPlugin() { ssl::shutdownNSS(); }
+
+ void earlyInitialize(Target&) {
+ }
+
+ void initialize(Target& target) {
+ broker::Broker* broker = dynamic_cast<broker::Broker*>(&target);
+ // Only provide to a Broker
+ if (broker) {
+ if (options.certDbPath.empty()) {
+ QPID_LOG(info, "SSL plugin not enabled, you must set --ssl-cert-db to enable it.");
+ } else {
+ try {
+ ssl::initNSS(options, true);
+
+ const broker::Broker::Options& opts = broker->getOptions();
+ ProtocolFactory::shared_ptr protocol(new SslProtocolFactory(options,
+ opts.connectionBacklog, opts.tcpNoDelay));
+ QPID_LOG(notice, "Listening for SSL connections on TCP port " << protocol->getPort());
+ broker->registerProtocolFactory("ssl", protocol);
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Failed to initialise SSL plugin: " << e.what());
+ }
+ }
+ }
+ }
+} sslPlugin;
+
+SslProtocolFactory::SslProtocolFactory(const SslServerOptions& options, int backlog, bool nodelay) :
+ tcpNoDelay(nodelay), listeningPort(listener.listen(options.port, backlog, options.certName, options.clientAuth))
+{}
+
+void SslProtocolFactory::established(Poller::shared_ptr poller, const qpid::sys::ssl::SslSocket& s,
+ ConnectionCodec::Factory* f, bool isClient) {
+ qpid::sys::ssl::SslHandler* async = new qpid::sys::ssl::SslHandler(s.getPeerAddress(), f);
+
+ if (tcpNoDelay) {
+ s.setTcpNoDelay(tcpNoDelay);
+ QPID_LOG(info, "Set TCP_NODELAY on connection to " << s.getPeerAddress());
+ }
+
+ if (isClient)
+ async->setClient();
+ qpid::sys::ssl::SslIO* aio = new qpid::sys::ssl::SslIO(s,
+ boost::bind(&qpid::sys::ssl::SslHandler::readbuff, async, _1, _2),
+ boost::bind(&qpid::sys::ssl::SslHandler::eof, async, _1),
+ boost::bind(&qpid::sys::ssl::SslHandler::disconnect, async, _1),
+ boost::bind(&qpid::sys::ssl::SslHandler::closedSocket, async, _1, _2),
+ boost::bind(&qpid::sys::ssl::SslHandler::nobuffs, async, _1),
+ boost::bind(&qpid::sys::ssl::SslHandler::idle, async, _1));
+
+ async->init(aio, 4);
+ aio->start(poller);
+}
+
+uint16_t SslProtocolFactory::getPort() const {
+ return listeningPort; // Immutable no need for lock.
+}
+
+std::string SslProtocolFactory::getHost() const {
+ return listener.getSockname();
+}
+
+void SslProtocolFactory::accept(Poller::shared_ptr poller,
+ ConnectionCodec::Factory* fact) {
+ acceptor.reset(
+ new qpid::sys::ssl::SslAcceptor(listener,
+ boost::bind(&SslProtocolFactory::established, this, poller, _1, fact, false)));
+ acceptor->start(poller);
+}
+
+void SslProtocolFactory::connect(
+ Poller::shared_ptr poller,
+ const std::string& host, int16_t port,
+ ConnectionCodec::Factory* fact,
+ ConnectFailedCallback failed)
+{
+ // Note that the following logic does not cause a memory leak.
+ // The allocated Socket is freed either by the SslConnector
+ // upon connection failure or by the SslIoHandle upon connection
+ // shutdown. The allocated SslConnector frees itself when it
+ // is no longer needed.
+
+ qpid::sys::ssl::SslSocket* socket = new qpid::sys::ssl::SslSocket();
+ new qpid::sys::ssl::SslConnector (*socket, poller, host, port,
+ boost::bind(&SslProtocolFactory::established, this, poller, _1, fact, true),
+ failed);
+}
+
+namespace
+{
+const std::string SSL = "ssl";
+}
+
+bool SslProtocolFactory::supports(const std::string& capability)
+{
+ std::string s = capability;
+ transform(s.begin(), s.end(), s.begin(), tolower);
+ return s == SSL;
+}
+
+}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/StrError.h b/cpp/src/qpid/sys/StrError.h
deleted file mode 100644
index 3843f2abe1..0000000000
--- a/cpp/src/qpid/sys/StrError.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef _sys_StrError_h
-#define _sys_StrError_h
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <string>
-
-namespace qpid {
-namespace sys {
-
-/** Get the error message for a system number err, e.g. errno. */
-std::string strError(int err);
-
-}} // namespace qpid
-
-#endif // _sys_StrError_h
diff --git a/cpp/src/qpid/sys/SystemInfo.cpp b/cpp/src/qpid/sys/SystemInfo.cpp
deleted file mode 100644
index dcc7ad9985..0000000000
--- a/cpp/src/qpid/sys/SystemInfo.cpp
+++ /dev/null
@@ -1,35 +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 "SystemInfo.h"
-#include <unistd.h>
-
-namespace qpid {
-namespace sys {
-
-long SystemInfo::concurrency() {
-#ifdef _SC_NPROCESSORS_ONLN // Linux specific.
- return sysconf(_SC_NPROCESSORS_ONLN);
-#else
- return -1;
-#endif
-}
-
-}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/SystemInfo.h b/cpp/src/qpid/sys/SystemInfo.h
deleted file mode 100644
index 73c3ca3c17..0000000000
--- a/cpp/src/qpid/sys/SystemInfo.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef QPID_SYS_SYSTEMINFO_H
-#define QPID_SYS_SYSTEMINFO_H
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-namespace qpid {
-namespace sys {
-
-/**
- * Retrieve information about the system we are running on.
- * Results may be dependent on OS/hardware.
- */
-class SystemInfo
-{
- public:
- /** Estimate available concurrency, e.g. number of CPU cores.
- * -1 means estimate not available on this platform.
- */
- static long concurrency();
-};
-
-}} // namespace qpid::sys
-
-
-
-#endif /*!QPID_SYS_SYSTEMINFO_H*/
diff --git a/cpp/src/qpid/sys/TCPIOPlugin.cpp b/cpp/src/qpid/sys/TCPIOPlugin.cpp
index f38cf88e45..39ae12c189 100644
--- a/cpp/src/qpid/sys/TCPIOPlugin.cpp
+++ b/cpp/src/qpid/sys/TCPIOPlugin.cpp
@@ -19,12 +19,13 @@
*
*/
-#include "ProtocolFactory.h"
-#include "AsynchIOHandler.h"
-#include "AsynchIO.h"
+#include "qpid/sys/ProtocolFactory.h"
+#include "qpid/sys/AsynchIOHandler.h"
+#include "qpid/sys/AsynchIO.h"
#include "qpid/Plugin.h"
#include "qpid/sys/Socket.h"
+#include "qpid/sys/Poller.h"
#include "qpid/broker/Broker.h"
#include "qpid/log/Statement.h"
@@ -45,7 +46,7 @@ class AsynchIOProtocolFactory : public ProtocolFactory {
void accept(Poller::shared_ptr, ConnectionCodec::Factory*);
void connect(Poller::shared_ptr, const std::string& host, int16_t port,
ConnectionCodec::Factory*,
- boost::function2<void, int, std::string> failed);
+ ConnectFailedCallback);
uint16_t getPort() const;
std::string getHost() const;
@@ -53,6 +54,7 @@ class AsynchIOProtocolFactory : public ProtocolFactory {
private:
void established(Poller::shared_ptr, const Socket&, ConnectionCodec::Factory*,
bool isClient);
+ void connectFailed(const Socket&, int, const std::string&, ConnectFailedCallback);
};
// Static instance to initialise plugin
@@ -65,9 +67,10 @@ static class TCPIOPlugin : public Plugin {
// Only provide to a Broker
if (broker) {
const broker::Broker::Options& opts = broker->getOptions();
- ProtocolFactory::shared_ptr protocol(new AsynchIOProtocolFactory(opts.port, opts.connectionBacklog, opts.tcpNoDelay));
- QPID_LOG(info, "Listening on TCP port " << protocol->getPort());
- broker->registerProtocolFactory(protocol);
+ ProtocolFactory::shared_ptr protocol(new AsynchIOProtocolFactory(opts.port, opts.connectionBacklog,
+ opts.tcpNoDelay));
+ QPID_LOG(notice, "Listening on TCP port " << protocol->getPort());
+ broker->registerProtocolFactory("tcp", protocol);
}
}
} tcpPlugin;
@@ -81,19 +84,20 @@ void AsynchIOProtocolFactory::established(Poller::shared_ptr poller, const Socke
AsynchIOHandler* async = new AsynchIOHandler(s.getPeerAddress(), f);
if (tcpNoDelay) {
- s.setTcpNoDelay(tcpNoDelay);
+ s.setTcpNoDelay();
QPID_LOG(info, "Set TCP_NODELAY on connection to " << s.getPeerAddress());
}
if (isClient)
async->setClient();
- AsynchIO* aio = new AsynchIO(s,
- boost::bind(&AsynchIOHandler::readbuff, async, _1, _2),
- boost::bind(&AsynchIOHandler::eof, async, _1),
- boost::bind(&AsynchIOHandler::disconnect, async, _1),
- boost::bind(&AsynchIOHandler::closedSocket, async, _1, _2),
- boost::bind(&AsynchIOHandler::nobuffs, async, _1),
- boost::bind(&AsynchIOHandler::idle, async, _1));
+ AsynchIO* aio = AsynchIO::create
+ (s,
+ boost::bind(&AsynchIOHandler::readbuff, async, _1, _2),
+ boost::bind(&AsynchIOHandler::eof, async, _1),
+ boost::bind(&AsynchIOHandler::disconnect, async, _1),
+ boost::bind(&AsynchIOHandler::closedSocket, async, _1, _2),
+ boost::bind(&AsynchIOHandler::nobuffs, async, _1),
+ boost::bind(&AsynchIOHandler::idle, async, _1));
async->init(aio, 4);
aio->start(poller);
@@ -110,11 +114,20 @@ std::string AsynchIOProtocolFactory::getHost() const {
void AsynchIOProtocolFactory::accept(Poller::shared_ptr poller,
ConnectionCodec::Factory* fact) {
acceptor.reset(
- new AsynchAcceptor(listener,
+ AsynchAcceptor::create(listener,
boost::bind(&AsynchIOProtocolFactory::established, this, poller, _1, fact, false)));
acceptor->start(poller);
}
+void AsynchIOProtocolFactory::connectFailed(
+ const Socket& s, int ec, const std::string& emsg,
+ ConnectFailedCallback failedCb)
+{
+ failedCb(ec, emsg);
+ s.close();
+ delete &s;
+}
+
void AsynchIOProtocolFactory::connect(
Poller::shared_ptr poller,
const std::string& host, int16_t port,
@@ -128,9 +141,14 @@ void AsynchIOProtocolFactory::connect(
// is no longer needed.
Socket* socket = new Socket();
- new AsynchConnector (*socket, poller, host, port,
- boost::bind(&AsynchIOProtocolFactory::established, this, poller, _1, fact, true),
- failed);
+ AsynchConnector::create(*socket,
+ poller,
+ host,
+ port,
+ boost::bind(&AsynchIOProtocolFactory::established,
+ this, poller, _1, fact, true),
+ boost::bind(&AsynchIOProtocolFactory::connectFailed,
+ this, _1, _2, _3, failed));
}
}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/Thread.h b/cpp/src/qpid/sys/Thread.h
deleted file mode 100644
index 3188e45341..0000000000
--- a/cpp/src/qpid/sys/Thread.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef _sys_Thread_h
-#define _sys_Thread_h
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include <boost/shared_ptr.hpp>
-
-namespace qpid {
-namespace sys {
-
-class Runnable;
-class ThreadPrivate;
-
-class Thread
-{
- boost::shared_ptr<ThreadPrivate> impl;
-
- public:
- Thread();
- explicit Thread(qpid::sys::Runnable*);
- explicit Thread(qpid::sys::Runnable&);
-
- void join();
-
- unsigned long id();
-
- static Thread current();
-
- /** ID of current thread for logging.
- * Workaround for broken Thread::current() in APR
- */
- static unsigned long logId() { return current().id(); }
-};
-
-}}
-#endif /*!_sys_Thread_h*/
diff --git a/cpp/src/qpid/sys/Time.h b/cpp/src/qpid/sys/Time.h
deleted file mode 100644
index 6501cd0806..0000000000
--- a/cpp/src/qpid/sys/Time.h
+++ /dev/null
@@ -1,154 +0,0 @@
-#ifndef _sys_Time_h
-#define _sys_Time_h
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <stdint.h>
-#include <limits>
-#include <iosfwd>
-
-namespace qpid {
-namespace sys {
-
-class Duration;
-
-/** Class to represent an instant in time:
- * The time resolution is in nanosecs, and this is held with 64 bits
- * giving a total time span from about 25 million years ago to 25 million
- * years hence. As an aside the internal time can sensibly be negative
- * meaning before the epoch (probably 1/1/1970 although this class doesn't
- * care).
- *
- * The AbsTime class is a value class and so you don't need to add any accessors
- * to its internal state. If you think you want to replace its value,i
- * You need to construct a new AbsTime and assign it, viz:
- *
- * AbsTime when = AbsTime::now();
- * ...
- * when = AbsTime(when, 2*TIME_SEC); // Advance timer 2 secs
- *
- * If for some reason you need access to the internal nanosec value you need
- * to convert the AbsTime to a Duration and use its conversion to int64_t, viz:
- *
- * AbsTime now = AbsTime::now();
- *
- * int64_t ns = Duration(now);
- *
- * However note that the nanosecond value that is returned here is not defined to be
- * anything in particular and could vary from platform to platform.
- *
- * There are some sensible operations that are currently missing from AbsTime, but
- * nearly all that's needed can be done with a mixture of AbsTimes and Durations.
- *
- * For example, convenience operators to add a Duration and AbsTime returning an AbsTime
- * would fit here (although you can already perform the operation with one of the AbsTime
- * constructors). However trying to add 2 AbsTimes doesn't make sense.
- */
-class AbsTime {
- static int64_t max() { return std::numeric_limits<int64_t>::max(); }
- int64_t time_ns;
-
- friend class Duration;
-
-public:
- inline AbsTime() {}
- inline AbsTime(const AbsTime& time0, const Duration& duration);
- // Default assignment operation fine
- // Default copy constructor fine
-
- static AbsTime now();
- inline static AbsTime FarFuture();
- bool operator==(const AbsTime& t) const { return t.time_ns == time_ns; }
- template <class S> void serialize(S& s) { s(time_ns); }
-
- friend bool operator<(const AbsTime& a, const AbsTime& b);
- friend bool operator>(const AbsTime& a, const AbsTime& b);
- friend std::ostream& operator << (std::ostream&, const AbsTime&);
-};
-
-std::ostream& operator << (std::ostream&, const AbsTime&);
-
-/** Class to represent the duration between instants of time:
- * As AbsTime this class also uses nanosecs for its time
- * resolution. For the most part a duration can be dealt with like a
- * 64 bit integer, and indeed there is an implicit conversion which
- * makes this quite conveient.
- */
-class Duration {
- static int64_t max() { return std::numeric_limits<int64_t>::max(); }
- int64_t nanosecs;
-
- friend class AbsTime;
-
-public:
- inline Duration(int64_t time0);
- inline explicit Duration(const AbsTime& time0);
- inline explicit Duration(const AbsTime& start, const AbsTime& finish);
- inline operator int64_t() const;
-};
-
-std::ostream& operator << (std::ostream&, const Duration&);
-
-AbsTime::AbsTime(const AbsTime& t, const Duration& d) :
- time_ns(d == Duration::max() ? max() : t.time_ns+d.nanosecs)
-{}
-
-AbsTime AbsTime::FarFuture() { AbsTime ff; ff.time_ns = max(); return ff;}
-
-inline AbsTime now() { return AbsTime::now(); }
-
-inline bool operator<(const AbsTime& a, const AbsTime& b) { return a.time_ns < b.time_ns; }
-inline bool operator>(const AbsTime& a, const AbsTime& b) { return a.time_ns > b.time_ns; }
-
-Duration::Duration(int64_t time0) :
- nanosecs(time0)
-{}
-
-Duration::Duration(const AbsTime& time0) :
- nanosecs(time0.time_ns)
-{}
-
-Duration::Duration(const AbsTime& start, const AbsTime& finish) :
- nanosecs(finish.time_ns - start.time_ns)
-{}
-
-Duration::operator int64_t() const
-{ return nanosecs; }
-
-/** Nanoseconds per second. */
-const Duration TIME_SEC = 1000*1000*1000;
-/** Nanoseconds per millisecond */
-const Duration TIME_MSEC = 1000*1000;
-/** Nanoseconds per microseconds. */
-const Duration TIME_USEC = 1000;
-/** Nanoseconds per nanosecond. */
-const Duration TIME_NSEC = 1;
-
-/** Value to represent an infinite timeout */
-const Duration TIME_INFINITE = std::numeric_limits<int64_t>::max();
-
-/** Time greater than any other time */
-const AbsTime FAR_FUTURE = AbsTime::FarFuture();
-
-}}
-
-#endif /*!_sys_Time_h*/
diff --git a/cpp/src/qpid/sys/Timer.cpp b/cpp/src/qpid/sys/Timer.cpp
new file mode 100644
index 0000000000..c18fd93538
--- /dev/null
+++ b/cpp/src/qpid/sys/Timer.cpp
@@ -0,0 +1,179 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/sys/Timer.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/log/Statement.h"
+
+#include <numeric>
+
+using boost::intrusive_ptr;
+using std::max;
+
+namespace qpid {
+namespace sys {
+
+TimerTask::TimerTask(Duration timeout) :
+ sortTime(AbsTime::FarFuture()),
+ period(timeout),
+ nextFireTime(AbsTime::now(), timeout),
+ cancelled(false)
+{}
+
+TimerTask::TimerTask(AbsTime time) :
+ sortTime(AbsTime::FarFuture()),
+ period(0),
+ nextFireTime(time),
+ cancelled(false)
+{}
+
+TimerTask::~TimerTask() {}
+
+bool TimerTask::readyToFire() const {
+ return !(nextFireTime > AbsTime::now());
+}
+
+void TimerTask::fireTask() {
+ cancelled = true;
+ fire();
+}
+
+// This can only be used to setup the next fire time. After the Timer has already fired
+void TimerTask::setupNextFire() {
+ if (period && readyToFire()) {
+ nextFireTime = max(AbsTime::now(), AbsTime(nextFireTime, period));
+ cancelled = false;
+ } else {
+ QPID_LOG(error, "Couldn't setup next timer firing: " << Duration(nextFireTime, AbsTime::now()) << "[" << period << "]");
+ }
+}
+
+// Only allow tasks to be delayed
+void TimerTask::restart() { nextFireTime = max(nextFireTime, AbsTime(AbsTime::now(), period)); }
+
+void TimerTask::cancel() {
+ ScopedLock<Mutex> l(callbackLock);
+ cancelled = true;
+}
+
+Timer::Timer() :
+ active(false)
+{
+ start();
+}
+
+Timer::~Timer()
+{
+ stop();
+}
+
+// TODO AStitcher 21/08/09 The threshholds for emitting warnings are a little arbitrary
+void Timer::run()
+{
+ Monitor::ScopedLock l(monitor);
+ while (active) {
+ if (tasks.empty()) {
+ monitor.wait();
+ } else {
+ intrusive_ptr<TimerTask> t = tasks.top();
+ tasks.pop();
+ assert(!(t->nextFireTime < t->sortTime));
+
+ // warn on extreme lateness
+ AbsTime start(AbsTime::now());
+ Duration delay(t->sortTime, start);
+ {
+ ScopedLock<Mutex> l(t->callbackLock);
+ if (t->cancelled) {
+ if (delay > 500 * TIME_MSEC) {
+ QPID_LOG(debug, "cancelled Timer woken up " << delay / TIME_MSEC << "ms late");
+ }
+ continue;
+ } else if(Duration(t->nextFireTime, start) >= 0) {
+ Monitor::ScopedUnlock u(monitor);
+ t->fireTask();
+ // Warn on callback overrun
+ AbsTime end(AbsTime::now());
+ Duration overrun(tasks.top()->nextFireTime, end);
+ bool late = delay > 50 * TIME_MSEC;
+ bool overran = overrun > 2 * TIME_MSEC;
+ if (late)
+ if (overran) {
+ QPID_LOG(warning,
+ "Timer woken up " << delay / TIME_MSEC << "ms late, "
+ "overrunning by " << overrun / TIME_MSEC << "ms [taking "
+ << Duration(start, end) << "]");
+ } else {
+ QPID_LOG(warning, "Timer woken up " << delay / TIME_MSEC << "ms late");
+ } else if (overran) {
+ QPID_LOG(warning,
+ "Timer callback overran by " << overrun / TIME_MSEC << "ms [taking "
+ << Duration(start, end) << "]");
+ }
+ continue;
+ } else {
+ // If the timer was adjusted into the future it might no longer
+ // be the next event, so push and then get top to make sure
+ // You can only push events into the future
+ t->sortTime = t->nextFireTime;
+ tasks.push(t);
+ }
+ }
+ monitor.wait(tasks.top()->sortTime);
+ }
+ }
+}
+
+void Timer::add(intrusive_ptr<TimerTask> task)
+{
+ Monitor::ScopedLock l(monitor);
+ task->sortTime = task->nextFireTime;
+ tasks.push(task);
+ monitor.notify();
+}
+
+void Timer::start()
+{
+ Monitor::ScopedLock l(monitor);
+ if (!active) {
+ active = true;
+ runner = Thread(this);
+ }
+}
+
+void Timer::stop()
+{
+ {
+ Monitor::ScopedLock l(monitor);
+ if (!active) return;
+ active = false;
+ monitor.notifyAll();
+ }
+ runner.join();
+}
+
+bool operator<(const intrusive_ptr<TimerTask>& a,
+ const intrusive_ptr<TimerTask>& b)
+{
+ // Lower priority if time is later
+ return a.get() && b.get() && a->sortTime > b->sortTime;
+}
+
+}}
diff --git a/cpp/src/qpid/sys/Timer.h b/cpp/src/qpid/sys/Timer.h
new file mode 100644
index 0000000000..5748503841
--- /dev/null
+++ b/cpp/src/qpid/sys/Timer.h
@@ -0,0 +1,94 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef sys_Timer
+#define sys_Timer
+
+#include "qpid/sys/Monitor.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/RefCounted.h"
+#include "qpid/CommonImportExport.h"
+#include <memory>
+#include <queue>
+
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+namespace sys {
+
+class Timer;
+
+class TimerTask : public RefCounted {
+ friend class Timer;
+ friend bool operator<(const boost::intrusive_ptr<TimerTask>&,
+ const boost::intrusive_ptr<TimerTask>&);
+
+ AbsTime sortTime;
+ Duration period;
+ AbsTime nextFireTime;
+ Mutex callbackLock;
+ volatile bool cancelled;
+
+ bool readyToFire() const;
+ void fireTask();
+
+public:
+ QPID_COMMON_EXTERN TimerTask(Duration period);
+ QPID_COMMON_EXTERN TimerTask(AbsTime fireTime);
+ QPID_COMMON_EXTERN virtual ~TimerTask();
+
+ QPID_COMMON_EXTERN void setupNextFire();
+ QPID_COMMON_EXTERN void restart();
+ QPID_COMMON_EXTERN void cancel();
+
+protected:
+ // Must be overridden with callback
+ virtual void fire() = 0;
+};
+
+// For the priority_queue order
+bool operator<(const boost::intrusive_ptr<TimerTask>& a,
+ const boost::intrusive_ptr<TimerTask>& b);
+
+class Timer : private Runnable {
+ qpid::sys::Monitor monitor;
+ std::priority_queue<boost::intrusive_ptr<TimerTask> > tasks;
+ qpid::sys::Thread runner;
+ bool active;
+
+ // Runnable interface
+ void run();
+
+public:
+ QPID_COMMON_EXTERN Timer();
+ QPID_COMMON_EXTERN ~Timer();
+
+ QPID_COMMON_EXTERN void add(boost::intrusive_ptr<TimerTask> task);
+ QPID_COMMON_EXTERN void start();
+ QPID_COMMON_EXTERN void stop();
+};
+
+
+}}
+
+
+#endif
diff --git a/cpp/src/qpid/sys/alloca.h b/cpp/src/qpid/sys/alloca.h
new file mode 100644
index 0000000000..e989670e4f
--- /dev/null
+++ b/cpp/src/qpid/sys/alloca.h
@@ -0,0 +1,39 @@
+#ifndef QPID_SYS_ALLOCA_H
+#define QPID_SYS_ALLOCA_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#if (defined(_WINDOWS) || defined (WIN32)) && defined(_MSC_VER)
+#include <malloc.h>
+#ifdef alloc
+# undef alloc
+#endif
+#define alloc _alloc
+#ifdef alloca
+# undef alloca
+#endif
+#define alloca _alloca
+#endif
+#if !defined _WINDOWS && !defined WIN32
+#include <alloca.h>
+#endif
+
+#endif /*!QPID_SYS_ALLOCA_H*/
diff --git a/cpp/src/qpid/sys/apr/APRBase.cpp b/cpp/src/qpid/sys/apr/APRBase.cpp
index 724c489303..8bdba66bdc 100644
--- a/cpp/src/qpid/sys/apr/APRBase.cpp
+++ b/cpp/src/qpid/sys/apr/APRBase.cpp
@@ -20,7 +20,7 @@
*/
#include <iostream>
#include "qpid/log/Statement.h"
-#include "APRBase.h"
+#include "qpid/sys/apr/APRBase.h"
using namespace qpid::sys;
diff --git a/cpp/src/qpid/sys/apr/APRPool.cpp b/cpp/src/qpid/sys/apr/APRPool.cpp
index e8b71f6e8a..e221bfc2f1 100644
--- a/cpp/src/qpid/sys/apr/APRPool.cpp
+++ b/cpp/src/qpid/sys/apr/APRPool.cpp
@@ -19,8 +19,8 @@
*
*/
-#include "APRPool.h"
-#include "APRBase.h"
+#include "qpid/sys/apr/APRPool.h"
+#include "qpid/sys/apr/APRBase.h"
#include <boost/pool/detail/singleton.hpp>
using namespace qpid::sys;
diff --git a/cpp/src/qpid/sys/apr/Condition.h b/cpp/src/qpid/sys/apr/Condition.h
index 5e544219ab..66d465ca75 100644
--- a/cpp/src/qpid/sys/apr/Condition.h
+++ b/cpp/src/qpid/sys/apr/Condition.h
@@ -22,7 +22,7 @@
*
*/
-#include "APRPool.h"
+#include "qpid/sys/apr/APRPool.h"
#include "qpid/sys/Mutex.h"
#include "qpid/sys/Time.h"
diff --git a/cpp/src/qpid/sys/apr/Mutex.h b/cpp/src/qpid/sys/apr/Mutex.h
index 51089c98ff..cb75f5b339 100644
--- a/cpp/src/qpid/sys/apr/Mutex.h
+++ b/cpp/src/qpid/sys/apr/Mutex.h
@@ -19,8 +19,8 @@
*
*/
-#include "APRBase.h"
-#include "APRPool.h"
+#include "qpid/sys/apr/APRBase.h"
+#include "qpid/sys/apr/APRPool.h"
#include <boost/noncopyable.hpp>
#include <apr_thread_mutex.h>
diff --git a/cpp/src/qpid/sys/apr/Shlib.cpp b/cpp/src/qpid/sys/apr/Shlib.cpp
index b0ba706713..b7ee13a03b 100644
--- a/cpp/src/qpid/sys/apr/Shlib.cpp
+++ b/cpp/src/qpid/sys/apr/Shlib.cpp
@@ -19,8 +19,8 @@
*/
#include "qpid/sys/Shlib.h"
-#include "APRBase.h"
-#include "APRPool.h"
+#include "qpid/sys/apr/APRBase.h"
+#include "qpid/sys/apr/APRPool.h"
#include <apr_dso.h>
namespace qpid {
diff --git a/cpp/src/qpid/sys/apr/Socket.cpp b/cpp/src/qpid/sys/apr/Socket.cpp
index 577268844a..d9024d11c1 100644
--- a/cpp/src/qpid/sys/apr/Socket.cpp
+++ b/cpp/src/qpid/sys/apr/Socket.cpp
@@ -22,8 +22,8 @@
#include "qpid/sys/Socket.h"
-#include "APRBase.h"
-#include "APRPool.h"
+#include "qpid/sys/apr/APRBase.h"
+#include "qpid/sys/apr/APRPool.h"
#include <apr_network_io.h>
diff --git a/cpp/src/qpid/sys/apr/Thread.cpp b/cpp/src/qpid/sys/apr/Thread.cpp
index 3369ef7eb1..b52d0e6ace 100644
--- a/cpp/src/qpid/sys/apr/Thread.cpp
+++ b/cpp/src/qpid/sys/apr/Thread.cpp
@@ -19,7 +19,7 @@
*
*/
-#include "Thread.h"
+#include "qpid/sys/apr/Thread.h"
#include "qpid/sys/Runnable.h"
using namespace qpid::sys;
diff --git a/cpp/src/qpid/sys/apr/Thread.h b/cpp/src/qpid/sys/apr/Thread.h
index 8cbbc0456e..6cc63db5c9 100644
--- a/cpp/src/qpid/sys/apr/Thread.h
+++ b/cpp/src/qpid/sys/apr/Thread.h
@@ -22,8 +22,8 @@
*
*/
-#include "APRPool.h"
-#include "APRBase.h"
+#include "qpid/sys/apr/APRPool.h"
+#include "qpid/sys/apr/APRBase.h"
#include <apr_thread_proc.h>
#include <apr_portable.h>
diff --git a/cpp/src/qpid/sys/cyrus/CyrusSecurityLayer.cpp b/cpp/src/qpid/sys/cyrus/CyrusSecurityLayer.cpp
new file mode 100644
index 0000000000..454ce62495
--- /dev/null
+++ b/cpp/src/qpid/sys/cyrus/CyrusSecurityLayer.cpp
@@ -0,0 +1,127 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/sys/cyrus/CyrusSecurityLayer.h"
+#include <algorithm>
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/log/Statement.h"
+#include <string.h>
+
+namespace qpid {
+namespace sys {
+namespace cyrus {
+
+CyrusSecurityLayer::CyrusSecurityLayer(sasl_conn_t* c, uint16_t maxFrameSize) :
+ conn(c), decrypted(0), decryptedSize(0), encrypted(0), encryptedSize(0), codec(0), maxInputSize(0),
+ decodeBuffer(maxFrameSize), encodeBuffer(maxFrameSize), encoded(0)
+{
+ const void* value(0);
+ int result = sasl_getprop(conn, SASL_MAXOUTBUF, &value);
+ if (result != SASL_OK) {
+ throw framing::InternalErrorException(QPID_MSG("SASL encode error: " << sasl_errdetail(conn)));
+ }
+ maxInputSize = *(reinterpret_cast<const unsigned*>(value));
+}
+
+size_t CyrusSecurityLayer::decode(const char* input, size_t size)
+{
+ size_t inStart = 0;
+ do {
+ size_t inSize = std::min(size - inStart, maxInputSize);
+ int result = sasl_decode(conn, input + inStart, inSize, &decrypted, &decryptedSize);
+ if (result != SASL_OK) {
+ throw framing::InternalErrorException(QPID_MSG("SASL decode error: " << sasl_errdetail(conn)));
+ }
+ inStart += inSize;
+ size_t copied = 0;
+ do {
+ size_t count = std::min(decryptedSize - copied, decodeBuffer.size - decodeBuffer.position);
+ ::memcpy(decodeBuffer.data + decodeBuffer.position, decrypted + copied, count);
+ copied += count;
+ decodeBuffer.position += count;
+ size_t decodedSize = codec->decode(decodeBuffer.data, decodeBuffer.position);
+ if (decodedSize < decodeBuffer.position) {
+ ::memmove(decodeBuffer.data, decodeBuffer.data + decodedSize, decodeBuffer.position - decodedSize);
+ }
+ decodeBuffer.position -= decodedSize;
+ } while (copied < decryptedSize);
+ } while (inStart < size);
+ return size;
+}
+
+size_t CyrusSecurityLayer::encode(const char* buffer, size_t size)
+{
+ size_t processed = 0;//records how many bytes have been written to buffer
+ do {
+ if (!encrypted) {
+ if (!encoded) {
+ encodeBuffer.position = 0;
+ encoded = codec->encode(encodeBuffer.data, encodeBuffer.size);
+ if (!encoded) break;//nothing more to do
+ }
+
+ size_t encryptable = std::min(encoded, maxInputSize);
+ int result = sasl_encode(conn, encodeBuffer.data + encodeBuffer.position, encryptable, &encrypted, &encryptedSize);
+ if (result != SASL_OK) {
+ throw framing::InternalErrorException(QPID_MSG("SASL encode error: " << sasl_errdetail(conn)));
+ }
+ encodeBuffer.position += encryptable;
+ encoded -= encryptable;
+ }
+ size_t remaining = size - processed;
+ if (remaining < encryptedSize) {
+ //can't fit all encrypted data in the buffer we've
+ //been given, copy in what we can and hold on to the
+ //rest until the next call
+ ::memcpy(const_cast<char*>(buffer + processed), encrypted, remaining);
+ processed += remaining;
+ encrypted += remaining;
+ encryptedSize -= remaining;
+ } else {
+ ::memcpy(const_cast<char*>(buffer + processed), encrypted, encryptedSize);
+ processed += encryptedSize;
+ encrypted = 0;
+ encryptedSize = 0;
+ }
+ } while (processed < size);
+ return processed;
+}
+
+bool CyrusSecurityLayer::canEncode()
+{
+ return encrypted || codec->canEncode();
+}
+
+void CyrusSecurityLayer::init(qpid::sys::Codec* c)
+{
+ codec = c;
+}
+
+CyrusSecurityLayer::DataBuffer::DataBuffer(size_t s) : position(0), size(s)
+{
+ data = new char[size];
+}
+
+CyrusSecurityLayer::DataBuffer::~DataBuffer()
+{
+ delete[] data;
+}
+
+}}} // namespace qpid::sys::cyrus
diff --git a/cpp/src/qpid/sys/cyrus/CyrusSecurityLayer.h b/cpp/src/qpid/sys/cyrus/CyrusSecurityLayer.h
new file mode 100644
index 0000000000..1645cf1a58
--- /dev/null
+++ b/cpp/src/qpid/sys/cyrus/CyrusSecurityLayer.h
@@ -0,0 +1,68 @@
+#ifndef QPID_SYS_CYRUS_CYRUSSECURITYLAYER_H
+#define QPID_SYS_CYRUS_CYRUSSECURITYLAYER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/IntegerTypes.h"
+#include "qpid/sys/SecurityLayer.h"
+#include <sasl/sasl.h>
+
+namespace qpid {
+namespace sys {
+namespace cyrus {
+
+
+/**
+ * Implementation of SASL security layer using cyrus-sasl library
+ */
+class CyrusSecurityLayer : public qpid::sys::SecurityLayer
+{
+ public:
+ CyrusSecurityLayer(sasl_conn_t*, uint16_t maxFrameSize);
+ size_t decode(const char* buffer, size_t size);
+ size_t encode(const char* buffer, size_t size);
+ bool canEncode();
+ void init(qpid::sys::Codec*);
+ private:
+ struct DataBuffer
+ {
+ char* data;
+ size_t position;
+ const size_t size;
+ DataBuffer(size_t);
+ ~DataBuffer();
+ };
+
+ sasl_conn_t* conn;
+ const char* decrypted;
+ unsigned decryptedSize;
+ const char* encrypted;
+ unsigned encryptedSize;
+ qpid::sys::Codec* codec;
+ size_t maxInputSize;
+ DataBuffer decodeBuffer;
+ DataBuffer encodeBuffer;
+ size_t encoded;
+};
+}}} // namespace qpid::sys::cyrus
+
+#endif /*!QPID_SYS_CYRUS_CYRUSSECURITYLAYER_H*/
diff --git a/cpp/src/qpid/sys/epoll/EpollPoller.cpp b/cpp/src/qpid/sys/epoll/EpollPoller.cpp
index 5e20e312e0..d7f64f3b4c 100644
--- a/cpp/src/qpid/sys/epoll/EpollPoller.cpp
+++ b/cpp/src/qpid/sys/epoll/EpollPoller.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -25,18 +25,20 @@
#include "qpid/sys/DeletionManager.h"
#include "qpid/sys/posix/check.h"
#include "qpid/sys/posix/PrivatePosix.h"
+#include "qpid/log/Statement.h"
#include <sys/epoll.h>
#include <errno.h>
+#include <signal.h>
#include <assert.h>
-#include <vector>
+#include <queue>
#include <exception>
namespace qpid {
namespace sys {
-// Deletion manager to handle deferring deletion of PollerHandles to when they definitely aren't being used
+// Deletion manager to handle deferring deletion of PollerHandles to when they definitely aren't being used
DeletionManager<PollerHandlePrivate> PollerHandleDeletionManager;
// Instantiate (and define) class static for DeletionManager
@@ -45,6 +47,7 @@ DeletionManager<PollerHandlePrivate>::AllThreadsStatuses DeletionManager<PollerH
class PollerHandlePrivate {
friend class Poller;
+ friend class PollerPrivate;
friend class PollerHandle;
enum FDStat {
@@ -53,28 +56,36 @@ class PollerHandlePrivate {
INACTIVE,
HUNGUP,
MONITORED_HUNGUP,
+ INTERRUPTED,
+ INTERRUPTED_HUNGUP,
DELETED
};
- int fd;
::__uint32_t events;
+ const IOHandlePrivate* ioHandle;
PollerHandle* pollerHandle;
FDStat stat;
Mutex lock;
- PollerHandlePrivate(int f, PollerHandle* p) :
- fd(f),
+ PollerHandlePrivate(const IOHandlePrivate* h, PollerHandle* p) :
events(0),
+ ioHandle(h),
pollerHandle(p),
stat(ABSENT) {
}
+ int fd() const {
+ return toFd(ioHandle);
+ }
+
bool isActive() const {
return stat == MONITORED || stat == MONITORED_HUNGUP;
}
void setActive() {
- stat = (stat == HUNGUP) ? MONITORED_HUNGUP : MONITORED;
+ stat = (stat == HUNGUP || stat == INTERRUPTED_HUNGUP)
+ ? MONITORED_HUNGUP
+ : MONITORED;
}
bool isInactive() const {
@@ -94,14 +105,27 @@ class PollerHandlePrivate {
}
bool isHungup() const {
- return stat == MONITORED_HUNGUP || stat == HUNGUP;
+ return
+ stat == MONITORED_HUNGUP ||
+ stat == HUNGUP ||
+ stat == INTERRUPTED_HUNGUP;
}
void setHungup() {
assert(stat == MONITORED);
stat = HUNGUP;
}
-
+
+ bool isInterrupted() const {
+ return stat == INTERRUPTED || stat == INTERRUPTED_HUNGUP;
+ }
+
+ void setInterrupted() {
+ stat = (stat == MONITORED_HUNGUP || stat == HUNGUP)
+ ? INTERRUPTED_HUNGUP
+ : INTERRUPTED;
+ }
+
bool isDeleted() const {
return stat == DELETED;
}
@@ -112,13 +136,22 @@ class PollerHandlePrivate {
};
PollerHandle::PollerHandle(const IOHandle& h) :
- impl(new PollerHandlePrivate(toFd(h.impl), this))
+ impl(new PollerHandlePrivate(h.impl, this))
{}
PollerHandle::~PollerHandle() {
+ {
ScopedLock<Mutex> l(impl->lock);
- if (impl->isActive()) {
+ if (impl->isDeleted()) {
+ return;
+ }
+ impl->pollerHandle = 0;
+ if (impl->isInterrupted()) {
impl->setDeleted();
+ return;
+ }
+ assert(impl->isIdle());
+ impl->setDeleted();
}
PollerHandleDeletionManager.markForDeletion(impl);
}
@@ -134,7 +167,7 @@ class PollerPrivate {
struct ReadablePipe {
int fds[2];
-
+
/**
* This encapsulates an always readable pipe which we can add
* to the epoll set to force epoll_wait to return
@@ -144,31 +177,69 @@ class PollerPrivate {
// Just write the pipe's fds to the pipe
QPID_POSIX_CHECK(::write(fds[1], fds, 2));
}
-
+
~ReadablePipe() {
::close(fds[0]);
::close(fds[1]);
}
-
+
int getFD() {
return fds[0];
}
};
-
+
static ReadablePipe alwaysReadable;
-
+ static int alwaysReadableFd;
+
+ class InterruptHandle: public PollerHandle {
+ std::queue<PollerHandle*> handles;
+
+ void processEvent(Poller::EventType) {
+ PollerHandle* handle = handles.front();
+ handles.pop();
+ assert(handle);
+
+ // Synthesise event
+ Poller::Event event(handle, Poller::INTERRUPTED);
+
+ // Process synthesised event
+ event.process();
+ }
+
+ public:
+ InterruptHandle() :
+ PollerHandle(DummyIOHandle)
+ {}
+
+ void addHandle(PollerHandle& h) {
+ handles.push(&h);
+ }
+
+ PollerHandle* getHandle() {
+ PollerHandle* handle = handles.front();
+ handles.pop();
+ return handle;
+ }
+
+ bool queuedHandles() {
+ return handles.size() > 0;
+ }
+ };
+
const int epollFd;
bool isShutdown;
+ InterruptHandle interruptHandle;
+ ::sigset_t sigMask;
static ::__uint32_t directionToEpollEvent(Poller::Direction dir) {
switch (dir) {
- case Poller::IN: return ::EPOLLIN;
- case Poller::OUT: return ::EPOLLOUT;
- case Poller::INOUT: return ::EPOLLIN | ::EPOLLOUT;
+ case Poller::INPUT: return ::EPOLLIN;
+ case Poller::OUTPUT: return ::EPOLLOUT;
+ case Poller::INOUT: return ::EPOLLIN | ::EPOLLOUT;
default: return 0;
}
}
-
+
static Poller::EventType epollToDirection(::__uint32_t events) {
// POLLOUT & POLLHUP are mutually exclusive really, but at least socketpairs
// can give you both!
@@ -188,81 +259,161 @@ class PollerPrivate {
epollFd(::epoll_create(DefaultFds)),
isShutdown(false) {
QPID_POSIX_CHECK(epollFd);
+ ::sigemptyset(&sigMask);
+ // Add always readable fd into our set (but not listening to it yet)
+ ::epoll_event epe;
+ epe.events = 0;
+ epe.data.u64 = 1;
+ QPID_POSIX_CHECK(::epoll_ctl(epollFd, EPOLL_CTL_ADD, alwaysReadableFd, &epe));
}
~PollerPrivate() {
// It's probably okay to ignore any errors here as there can't be data loss
::close(epollFd);
+
+ // Need to put the interruptHandle in idle state to delete it
+ static_cast<PollerHandle&>(interruptHandle).impl->setIdle();
+ }
+
+ void resetMode(PollerHandlePrivate& handle);
+
+ void interrupt() {
+ ::epoll_event epe;
+ // Use EPOLLONESHOT so we only wake a single thread
+ epe.events = ::EPOLLIN | ::EPOLLONESHOT;
+ epe.data.u64 = 0; // Keep valgrind happy
+ epe.data.ptr = &static_cast<PollerHandle&>(interruptHandle);
+ QPID_POSIX_CHECK(::epoll_ctl(epollFd, EPOLL_CTL_MOD, alwaysReadableFd, &epe));
+ }
+
+ void interruptAll() {
+ ::epoll_event epe;
+ // Not EPOLLONESHOT, so we eventually get all threads
+ epe.events = ::EPOLLIN;
+ epe.data.u64 = 2; // Keep valgrind happy
+ QPID_POSIX_CHECK(::epoll_ctl(epollFd, EPOLL_CTL_MOD, alwaysReadableFd, &epe));
}
};
PollerPrivate::ReadablePipe PollerPrivate::alwaysReadable;
+int PollerPrivate::alwaysReadableFd = alwaysReadable.getFD();
-void Poller::addFd(PollerHandle& handle, Direction dir) {
+void Poller::registerHandle(PollerHandle& handle) {
PollerHandlePrivate& eh = *handle.impl;
ScopedLock<Mutex> l(eh.lock);
+ assert(eh.isIdle());
+
::epoll_event epe;
- int op;
-
- if (eh.isIdle()) {
- op = EPOLL_CTL_ADD;
- epe.events = PollerPrivate::directionToEpollEvent(dir) | ::EPOLLONESHOT;
- } else {
- assert(eh.isActive());
- op = EPOLL_CTL_MOD;
- epe.events = eh.events | PollerPrivate::directionToEpollEvent(dir);
- }
+ epe.events = ::EPOLLONESHOT;
+ epe.data.u64 = 0; // Keep valgrind happy
epe.data.ptr = &eh;
-
- QPID_POSIX_CHECK(::epoll_ctl(impl->epollFd, op, eh.fd, &epe));
-
- // Record monitoring state of this fd
- eh.events = epe.events;
+
+ QPID_POSIX_CHECK(::epoll_ctl(impl->epollFd, EPOLL_CTL_ADD, eh.fd(), &epe));
+
eh.setActive();
}
-void Poller::delFd(PollerHandle& handle) {
+void Poller::unregisterHandle(PollerHandle& handle) {
PollerHandlePrivate& eh = *handle.impl;
ScopedLock<Mutex> l(eh.lock);
assert(!eh.isIdle());
- int rc = ::epoll_ctl(impl->epollFd, EPOLL_CTL_DEL, eh.fd, 0);
+
+ int rc = ::epoll_ctl(impl->epollFd, EPOLL_CTL_DEL, eh.fd(), 0);
// Ignore EBADF since deleting a nonexistent fd has the overall required result!
// And allows the case where a sloppy program closes the fd and then does the delFd()
if (rc == -1 && errno != EBADF) {
- QPID_POSIX_CHECK(rc);
+ QPID_POSIX_CHECK(rc);
}
+
eh.setIdle();
}
-// modFd is equivalent to delFd followed by addFd
-void Poller::modFd(PollerHandle& handle, Direction dir) {
+void PollerPrivate::resetMode(PollerHandlePrivate& eh) {
+ PollerHandle* ph;
+ {
+ ScopedLock<Mutex> l(eh.lock);
+ assert(!eh.isActive());
+
+ if (eh.isIdle() || eh.isDeleted()) {
+ return;
+ }
+
+ if (eh.events==0) {
+ eh.setActive();
+ return;
+ }
+
+ if (!eh.isInterrupted()) {
+ ::epoll_event epe;
+ epe.events = eh.events | ::EPOLLONESHOT;
+ epe.data.u64 = 0; // Keep valgrind happy
+ epe.data.ptr = &eh;
+
+ QPID_POSIX_CHECK(::epoll_ctl(epollFd, EPOLL_CTL_MOD, eh.fd(), &epe));
+
+ eh.setActive();
+ return;
+ }
+ ph = eh.pollerHandle;
+ }
+
+ PollerHandlePrivate& ihp = *static_cast<PollerHandle&>(interruptHandle).impl;
+ ScopedLock<Mutex> l(ihp.lock);
+ interruptHandle.addHandle(*ph);
+ ihp.setActive();
+ interrupt();
+}
+
+void Poller::monitorHandle(PollerHandle& handle, Direction dir) {
PollerHandlePrivate& eh = *handle.impl;
ScopedLock<Mutex> l(eh.lock);
assert(!eh.isIdle());
-
+
+ ::__uint32_t oldEvents = eh.events;
+ eh.events |= PollerPrivate::directionToEpollEvent(dir);
+
+ // If no change nothing more to do - avoid unnecessary system call
+ if (oldEvents==eh.events) {
+ return;
+ }
+
+ // If we're not actually listening wait till we are to perform change
+ if (!eh.isActive()) {
+ return;
+ }
+
::epoll_event epe;
- epe.events = PollerPrivate::directionToEpollEvent(dir) | ::EPOLLONESHOT;
+ epe.events = eh.events | ::EPOLLONESHOT;
+ epe.data.u64 = 0; // Keep valgrind happy
epe.data.ptr = &eh;
-
- QPID_POSIX_CHECK(::epoll_ctl(impl->epollFd, EPOLL_CTL_MOD, eh.fd, &epe));
-
- // Record monitoring state of this fd
- eh.events = epe.events;
- eh.setActive();
+
+ QPID_POSIX_CHECK(::epoll_ctl(impl->epollFd, EPOLL_CTL_MOD, eh.fd(), &epe));
}
-void Poller::rearmFd(PollerHandle& handle) {
+void Poller::unmonitorHandle(PollerHandle& handle, Direction dir) {
PollerHandlePrivate& eh = *handle.impl;
ScopedLock<Mutex> l(eh.lock);
- assert(eh.isInactive());
+ assert(!eh.isIdle());
+
+ ::__uint32_t oldEvents = eh.events;
+ eh.events &= ~PollerPrivate::directionToEpollEvent(dir);
+
+ // If no change nothing more to do - avoid unnecessary system call
+ if (oldEvents==eh.events) {
+ return;
+ }
+
+ // If we're not actually listening wait till we are to perform change
+ if (!eh.isActive()) {
+ return;
+ }
::epoll_event epe;
- epe.events = eh.events;
+ epe.events = eh.events | ::EPOLLONESHOT;
+ epe.data.u64 = 0; // Keep valgrind happy
epe.data.ptr = &eh;
- QPID_POSIX_CHECK(::epoll_ctl(impl->epollFd, EPOLL_CTL_MOD, eh.fd, &epe));
-
- eh.setActive();
+ QPID_POSIX_CHECK(::epoll_ctl(impl->epollFd, EPOLL_CTL_MOD, eh.fd(), &epe));
}
void Poller::shutdown() {
@@ -273,63 +424,182 @@ void Poller::shutdown() {
if (impl->isShutdown)
return;
- // Don't use any locking here - isshutdown will be visible to all
+ // Don't use any locking here - isShutdown will be visible to all
// after the epoll_ctl() anyway (it's a memory barrier)
impl->isShutdown = true;
-
- // Add always readable fd to epoll (not EPOLLONESHOT)
- int fd = impl->alwaysReadable.getFD();
- ::epoll_event epe;
- epe.events = ::EPOLLIN;
- epe.data.ptr = 0;
- QPID_POSIX_CHECK(::epoll_ctl(impl->epollFd, EPOLL_CTL_ADD, fd, &epe));
+
+ impl->interruptAll();
+}
+
+bool Poller::interrupt(PollerHandle& handle) {
+ {
+ PollerHandlePrivate& eh = *handle.impl;
+ ScopedLock<Mutex> l(eh.lock);
+ if (eh.isIdle() || eh.isDeleted()) {
+ return false;
+ }
+
+ if (eh.isInterrupted()) {
+ return true;
+ }
+
+ // Stop monitoring handle for read or write
+ ::epoll_event epe;
+ epe.events = 0;
+ epe.data.u64 = 0; // Keep valgrind happy
+ epe.data.ptr = &eh;
+ QPID_POSIX_CHECK(::epoll_ctl(impl->epollFd, EPOLL_CTL_MOD, eh.fd(), &epe));
+
+ if (eh.isInactive()) {
+ eh.setInterrupted();
+ return true;
+ }
+ eh.setInterrupted();
+ }
+
+ PollerPrivate::InterruptHandle& ih = impl->interruptHandle;
+ PollerHandlePrivate& eh = *static_cast<PollerHandle&>(ih).impl;
+ ScopedLock<Mutex> l(eh.lock);
+ ih.addHandle(handle);
+
+ impl->interrupt();
+ eh.setActive();
+ return true;
+}
+
+void Poller::run() {
+ // Ensure that we exit thread responsibly under all circumstances
+ try {
+ // Make sure we can't be interrupted by signals at a bad time
+ ::sigset_t ss;
+ ::sigfillset(&ss);
+ ::pthread_sigmask(SIG_SETMASK, &ss, 0);
+
+ do {
+ Event event = wait();
+
+ // If can read/write then dispatch appropriate callbacks
+ if (event.handle) {
+ event.process();
+ } else {
+ // Handle shutdown
+ switch (event.type) {
+ case SHUTDOWN:
+ PollerHandleDeletionManager.destroyThreadState();
+ return;
+ default:
+ // This should be impossible
+ assert(false);
+ }
+ }
+ } while (true);
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "IO worker thread exiting with unhandled exception: " << e.what());
+ }
+ PollerHandleDeletionManager.destroyThreadState();
}
Poller::Event Poller::wait(Duration timeout) {
+ static __thread PollerHandlePrivate* lastReturnedHandle = 0;
epoll_event epe;
int timeoutMs = (timeout == TIME_INFINITE) ? -1 : timeout / TIME_MSEC;
+ AbsTime targetTimeout =
+ (timeout == TIME_INFINITE) ?
+ FAR_FUTURE :
+ AbsTime(now(), timeout);
+
+ if (lastReturnedHandle) {
+ impl->resetMode(*lastReturnedHandle);
+ lastReturnedHandle = 0;
+ }
- // Repeat until we weren't interupted
+ // Repeat until we weren't interrupted by signal
do {
PollerHandleDeletionManager.markAllUnusedInThisThread();
+ // Need to run on kernels without epoll_pwait()
+ // - fortunately in this case we don't really need the atomicity of epoll_pwait()
+#if 1
+ sigset_t os;
+ pthread_sigmask(SIG_SETMASK, &impl->sigMask, &os);
int rc = ::epoll_wait(impl->epollFd, &epe, 1, timeoutMs);
-
- if (impl->isShutdown) {
- PollerHandleDeletionManager.markAllUnusedInThisThread();
- return Event(0, SHUTDOWN);
- }
-
+ pthread_sigmask(SIG_SETMASK, &os, 0);
+#else
+ int rc = ::epoll_pwait(impl->epollFd, &epe, 1, timeoutMs, &impl->sigMask);
+#endif
+
if (rc ==-1 && errno != EINTR) {
QPID_POSIX_CHECK(rc);
} else if (rc > 0) {
assert(rc == 1);
- PollerHandlePrivate& eh = *static_cast<PollerHandlePrivate*>(epe.data.ptr);
-
+ void* dataPtr = epe.data.ptr;
+
+ // Check if this is an interrupt
+ PollerPrivate::InterruptHandle& interruptHandle = impl->interruptHandle;
+ if (dataPtr == &interruptHandle) {
+ PollerHandle* wrappedHandle = 0;
+ {
+ ScopedLock<Mutex> l(interruptHandle.impl->lock);
+ if (interruptHandle.impl->isActive()) {
+ wrappedHandle = interruptHandle.getHandle();
+ // If there is an interrupt queued behind this one we need to arm it
+ // We do it this way so that another thread can pick it up
+ if (interruptHandle.queuedHandles()) {
+ impl->interrupt();
+ interruptHandle.impl->setActive();
+ } else {
+ interruptHandle.impl->setInactive();
+ }
+ }
+ }
+ if (wrappedHandle) {
+ PollerHandlePrivate& eh = *wrappedHandle->impl;
+ {
+ ScopedLock<Mutex> l(eh.lock);
+ if (!eh.isDeleted()) {
+ if (!eh.isIdle()) {
+ eh.setInactive();
+ }
+ lastReturnedHandle = &eh;
+ assert(eh.pollerHandle == wrappedHandle);
+ return Event(wrappedHandle, INTERRUPTED);
+ }
+ }
+ PollerHandleDeletionManager.markForDeletion(&eh);
+ }
+ continue;
+ }
+
+ // Check for shutdown
+ if (impl->isShutdown) {
+ PollerHandleDeletionManager.markAllUnusedInThisThread();
+ return Event(0, SHUTDOWN);
+ }
+
+ PollerHandlePrivate& eh = *static_cast<PollerHandlePrivate*>(dataPtr);
ScopedLock<Mutex> l(eh.lock);
-
+
// the handle could have gone inactive since we left the epoll_wait
if (eh.isActive()) {
PollerHandle* handle = eh.pollerHandle;
+ assert(handle);
// If the connection has been hungup we could still be readable
// (just not writable), allow us to readable until we get here again
if (epe.events & ::EPOLLHUP) {
if (eh.isHungup()) {
+ eh.setInactive();
+ // Don't set up last Handle so that we don't reset this handle
+ // on re-entering Poller::wait. This means that we will never
+ // be set active again once we've returned disconnected, and so
+ // can never be returned again.
return Event(handle, DISCONNECTED);
}
eh.setHungup();
} else {
eh.setInactive();
}
+ lastReturnedHandle = &eh;
return Event(handle, PollerPrivate::epollToDirection(epe.events));
- } else if (eh.isDeleted()) {
- // The handle has been deleted whilst still active and so must be removed
- // from the poller
- int rc = ::epoll_ctl(impl->epollFd, EPOLL_CTL_DEL, eh.fd, 0);
- // Ignore EBADF since it's quite likely that we could race with closing the fd
- if (rc == -1 && errno != EBADF) {
- QPID_POSIX_CHECK(rc);
- }
}
}
// We only get here if one of the following:
@@ -340,10 +610,12 @@ Poller::Event Poller::wait(Duration timeout) {
// The only things we can do here are return a timeout or wait more.
// Obviously if we timed out we return timeout; if the wait was meant to
// be indefinite then we should never return with a time out so we go again.
- // If the wait wasn't indefinite, but we were interrupted then we have to return
- // with a timeout as we don't know how long we've waited so far and so we can't
- // continue the wait.
- if (rc == 0 || timeoutMs != -1) {
+ // If the wait wasn't indefinite, we check whether we are after the target wait
+ // time or not
+ if (timeoutMs == -1) {
+ continue;
+ }
+ if (rc == 0 && now() > targetTimeout) {
PollerHandleDeletionManager.markAllUnusedInThisThread();
return Event(0, TIMEOUT);
}
diff --git a/cpp/src/qpid/sys/posix/AsynchIO.cpp b/cpp/src/qpid/sys/posix/AsynchIO.cpp
index 7598eefe83..67b5cf0534 100644
--- a/cpp/src/qpid/sys/posix/AsynchIO.cpp
+++ b/cpp/src/qpid/sys/posix/AsynchIO.cpp
@@ -21,13 +21,16 @@
#include "qpid/sys/AsynchIO.h"
#include "qpid/sys/Socket.h"
+#include "qpid/sys/SocketAddress.h"
+#include "qpid/sys/Poller.h"
+#include "qpid/sys/DispatchHandle.h"
#include "qpid/sys/Time.h"
#include "qpid/log/Statement.h"
-#include "check.h"
+#include "qpid/sys/posix/check.h"
-// TODO The basic algorithm here is not really POSIX specific and with a bit more abstraction
-// could (should) be promoted to be platform portable
+// TODO The basic algorithm here is not really POSIX specific and with a
+// bit more abstraction could (should) be promoted to be platform portable
#include <unistd.h>
#include <sys/socket.h>
#include <signal.h>
@@ -35,18 +38,21 @@
#include <string.h>
#include <boost/bind.hpp>
+#include <boost/lexical_cast.hpp>
using namespace qpid::sys;
namespace {
-/*
- * Make *process* not generate SIGPIPE when writing to closed
- * pipe/socket (necessary as default action is to terminate process)
- */
-void ignoreSigpipe() {
- ::signal(SIGPIPE, SIG_IGN);
-}
+struct StaticInit {
+ StaticInit() {
+ /**
+ * Make *process* not generate SIGPIPE when writing to closed
+ * pipe/socket (necessary as default action is to terminate process)
+ */
+ ::signal(SIGPIPE, SIG_IGN);
+ };
+} init;
/*
* We keep per thread state to avoid locking overhead. The assumption is that
@@ -65,14 +71,37 @@ __thread int64_t threadMaxReadTimeNs = 2 * 1000000; // start at 2ms
/*
* Asynch Acceptor
*/
+namespace qpid {
+namespace sys {
+namespace posix {
+
+class AsynchAcceptor : public qpid::sys::AsynchAcceptor {
+public:
+ AsynchAcceptor(const Socket& s, AsynchAcceptor::Callback callback);
+ ~AsynchAcceptor();
+ void start(Poller::shared_ptr poller);
+
+private:
+ void readable(DispatchHandle& handle);
+
+private:
+ AsynchAcceptor::Callback acceptedCallback;
+ DispatchHandle handle;
+ const Socket& socket;
-AsynchAcceptor::AsynchAcceptor(const Socket& s, Callback callback) :
+};
+
+AsynchAcceptor::AsynchAcceptor(const Socket& s,
+ AsynchAcceptor::Callback callback) :
acceptedCallback(callback),
handle(s, boost::bind(&AsynchAcceptor::readable, this, _1), 0, 0),
socket(s) {
s.setNonblocking();
- ignoreSigpipe();
+}
+
+AsynchAcceptor::~AsynchAcceptor() {
+ handle.stopWatch();
}
void AsynchAcceptor::start(Poller::shared_ptr poller) {
@@ -89,7 +118,7 @@ void AsynchAcceptor::readable(DispatchHandle& h) {
// TODO: Currently we ignore the peers address, perhaps we should
// log it or use it for connection acceptance.
try {
- s = socket.accept(0, 0);
+ s = socket.accept();
if (s) {
acceptedCallback(*s);
} else {
@@ -97,6 +126,7 @@ void AsynchAcceptor::readable(DispatchHandle& h) {
}
} catch (const std::exception& e) {
QPID_LOG(error, "Could not accept socket: " << e.what());
+ break;
}
} while (true);
@@ -104,8 +134,32 @@ void AsynchAcceptor::readable(DispatchHandle& h) {
}
/*
- * Asynch Connector
+ * POSIX version of AsynchIO TCP socket connector.
+ *
+ * The class is implemented in terms of DispatchHandle to allow it to be
+ * deleted by deleting the contained DispatchHandle.
*/
+class AsynchConnector : public qpid::sys::AsynchConnector,
+ private DispatchHandle {
+
+private:
+ void connComplete(DispatchHandle& handle);
+ void failure(int, const std::string&);
+
+private:
+ ConnectedCallback connCallback;
+ FailedCallback failCallback;
+ std::string errMsg;
+ const Socket& socket;
+
+public:
+ AsynchConnector(const Socket& socket,
+ Poller::shared_ptr poller,
+ std::string hostname,
+ uint16_t port,
+ ConnectedCallback connCb,
+ FailedCallback failCb);
+};
AsynchConnector::AsynchConnector(const Socket& s,
Poller::shared_ptr poller,
@@ -122,12 +176,17 @@ AsynchConnector::AsynchConnector(const Socket& s,
socket(s)
{
socket.setNonblocking();
+ SocketAddress sa(hostname, boost::lexical_cast<std::string>(port));
try {
- socket.connect(hostname, port);
- startWatch(poller);
+ socket.connect(sa);
} catch(std::exception& e) {
- failure(-1, std::string(e.what()));
+ // Defer reporting failure
+ startWatch(poller);
+ errMsg = e.what();
+ DispatchHandle::call(boost::bind(&AsynchConnector::failure, this, -1, errMsg));
+ return;
}
+ startWatch(poller);
}
void AsynchConnector::connComplete(DispatchHandle& h)
@@ -139,25 +198,87 @@ void AsynchConnector::connComplete(DispatchHandle& h)
connCallback(socket);
DispatchHandle::doDelete();
} else {
- // TODO: This need to be fixed as strerror isn't thread safe
- failure(errCode, std::string(::strerror(errCode)));
+ failure(errCode, strError(errCode));
}
}
-void AsynchConnector::failure(int errCode, std::string message)
+void AsynchConnector::failure(int errCode, const std::string& message)
{
- if (failCallback)
- failCallback(errCode, message);
-
- socket.close();
- delete &socket;
+ failCallback(socket, errCode, message);
DispatchHandle::doDelete();
}
/*
- * Asynch reader/writer
+ * POSIX version of AsynchIO reader/writer
+ *
+ * The class is implemented in terms of DispatchHandle to allow it to be
+ * deleted by deleting the contained DispatchHandle.
*/
+class AsynchIO : public qpid::sys::AsynchIO, private DispatchHandle {
+
+public:
+ AsynchIO(const Socket& s,
+ ReadCallback rCb,
+ EofCallback eofCb,
+ DisconnectCallback disCb,
+ ClosedCallback cCb = 0,
+ BuffersEmptyCallback eCb = 0,
+ IdleCallback iCb = 0);
+
+ // Methods inherited from qpid::sys::AsynchIO
+
+ virtual void queueForDeletion();
+
+ virtual void start(Poller::shared_ptr poller);
+ virtual void queueReadBuffer(BufferBase* buff);
+ virtual void unread(BufferBase* buff);
+ virtual void queueWrite(BufferBase* buff);
+ virtual void notifyPendingWrite();
+ virtual void queueWriteClose();
+ virtual bool writeQueueEmpty();
+ virtual void startReading();
+ virtual void stopReading();
+ virtual void requestCallback(RequestCallback);
+ virtual BufferBase* getQueuedBuffer();
+
+private:
+ ~AsynchIO();
+
+ // Methods that are callback targets from Dispatcher.
+ void readable(DispatchHandle& handle);
+ void writeable(DispatchHandle& handle);
+ void disconnected(DispatchHandle& handle);
+ void requestedCall(RequestCallback);
+ void close(DispatchHandle& handle);
+
+private:
+ ReadCallback readCallback;
+ EofCallback eofCallback;
+ DisconnectCallback disCallback;
+ ClosedCallback closedCallback;
+ BuffersEmptyCallback emptyCallback;
+ IdleCallback idleCallback;
+ const Socket& socket;
+ std::deque<BufferBase*> bufferQueue;
+ std::deque<BufferBase*> writeQueue;
+ bool queuedClose;
+ /**
+ * This flag is used to detect and handle concurrency between
+ * calls to notifyPendingWrite() (which can be made from any thread) and
+ * the execution of the writeable() method (which is always on the
+ * thread processing this handle.
+ */
+ volatile bool writePending;
+ /**
+ * This records whether we've been reading is flow controlled:
+ * it's safe as a simple boolean as the only way to be stopped
+ * is in calls only allowed in the callback context, the only calls
+ * checking it are also in calls only allowed in callback context.
+ */
+ volatile bool readingStopped;
+};
+
AsynchIO::AsynchIO(const Socket& s,
ReadCallback rCb, EofCallback eofCb, DisconnectCallback disCb,
ClosedCallback cCb, BuffersEmptyCallback eCb, IdleCallback iCb) :
@@ -174,7 +295,8 @@ AsynchIO::AsynchIO(const Socket& s,
idleCallback(iCb),
socket(s),
queuedClose(false),
- writePending(false) {
+ writePending(false),
+ readingStopped(false) {
s.setNonblocking();
}
@@ -202,8 +324,11 @@ void AsynchIO::queueReadBuffer(BufferBase* buff) {
assert(buff);
buff->dataStart = 0;
buff->dataCount = 0;
+
+ bool queueWasEmpty = bufferQueue.empty();
bufferQueue.push_back(buff);
- DispatchHandle::rewatchRead();
+ if (queueWasEmpty && !readingStopped)
+ DispatchHandle::rewatchRead();
}
void AsynchIO::unread(BufferBase* buff) {
@@ -212,15 +337,18 @@ void AsynchIO::unread(BufferBase* buff) {
memmove(buff->bytes, buff->bytes+buff->dataStart, buff->dataCount);
buff->dataStart = 0;
}
+
+ bool queueWasEmpty = bufferQueue.empty();
bufferQueue.push_front(buff);
- DispatchHandle::rewatchRead();
+ if (queueWasEmpty && !readingStopped)
+ DispatchHandle::rewatchRead();
}
void AsynchIO::queueWrite(BufferBase* buff) {
assert(buff);
// If we've already closed the socket then throw the write away
if (queuedClose) {
- bufferQueue.push_front(buff);
+ queueReadBuffer(buff);
return;
} else {
writeQueue.push_front(buff);
@@ -229,6 +357,7 @@ void AsynchIO::queueWrite(BufferBase* buff) {
DispatchHandle::rewatchWrite();
}
+// This can happen outside the callback context
void AsynchIO::notifyPendingWrite() {
writePending = true;
DispatchHandle::rewatchWrite();
@@ -239,6 +368,33 @@ void AsynchIO::queueWriteClose() {
DispatchHandle::rewatchWrite();
}
+bool AsynchIO::writeQueueEmpty() {
+ return writeQueue.empty();
+}
+
+// This can happen outside the callback context
+void AsynchIO::startReading() {
+ readingStopped = false;
+ DispatchHandle::rewatchRead();
+}
+
+void AsynchIO::stopReading() {
+ readingStopped = true;
+ DispatchHandle::unwatchRead();
+}
+
+void AsynchIO::requestCallback(RequestCallback callback) {
+ // TODO creating a function object every time isn't all that
+ // efficient - if this becomes heavily used do something better (what?)
+ assert(callback);
+ DispatchHandle::call(boost::bind(&AsynchIO::requestedCall, this, callback));
+}
+
+void AsynchIO::requestedCall(RequestCallback callback) {
+ assert(callback);
+ callback(*this);
+}
+
/** Return a queued buffer if there are enough
* to spare
*/
@@ -277,6 +433,11 @@ void AsynchIO::readable(DispatchHandle& h) {
readTotal += rc;
readCallback(*this, buff);
+ if (readingStopped) {
+ // We have been flow controlled.
+ break;
+ }
+
if (rc != readCount) {
// If we didn't fill the read buffer then time to stop reading
break;
@@ -303,7 +464,7 @@ void AsynchIO::readable(DispatchHandle& h) {
break;
} else {
// Report error then just treat as a socket disconnect
- QPID_LOG(error, "Error reading socket: " << qpid::sys::strError(rc) << "(" << rc << ")" );
+ QPID_LOG(error, "Error reading socket: " << qpid::sys::strError(errno) << "(" << errno << ")" );
eofCallback(*this);
h.unwatchRead();
break;
@@ -427,3 +588,33 @@ void AsynchIO::close(DispatchHandle& h) {
}
}
+} // namespace posix
+
+AsynchAcceptor* AsynchAcceptor::create(const Socket& s,
+ Callback callback)
+{
+ return new posix::AsynchAcceptor(s, callback);
+}
+
+AsynchConnector* AsynchConnector::create(const Socket& s,
+ Poller::shared_ptr poller,
+ std::string hostname,
+ uint16_t port,
+ ConnectedCallback connCb,
+ FailedCallback failCb)
+{
+ return new posix::AsynchConnector(s, poller, hostname, port, connCb, failCb);
+}
+
+AsynchIO* AsynchIO::create(const Socket& s,
+ AsynchIO::ReadCallback rCb,
+ AsynchIO::EofCallback eofCb,
+ AsynchIO::DisconnectCallback disCb,
+ AsynchIO::ClosedCallback cCb,
+ AsynchIO::BuffersEmptyCallback eCb,
+ AsynchIO::IdleCallback iCb)
+{
+ return new posix::AsynchIO(s, rCb, eofCb, disCb, cCb, eCb, iCb);
+}
+
+}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/posix/Condition.h b/cpp/src/qpid/sys/posix/Condition.h
deleted file mode 100644
index 86d6500ee9..0000000000
--- a/cpp/src/qpid/sys/posix/Condition.h
+++ /dev/null
@@ -1,86 +0,0 @@
-#ifndef _sys_posix_Condition_h
-#define _sys_posix_Condition_h
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "PrivatePosix.h"
-
-#include "qpid/sys/Mutex.h"
-#include "qpid/sys/Time.h"
-
-#include <time.h>
-#include <sys/errno.h>
-#include <boost/noncopyable.hpp>
-
-namespace qpid {
-namespace sys {
-
-/**
- * A condition variable for thread synchronization.
- */
-class Condition
-{
- public:
- inline Condition();
- inline ~Condition();
- inline void wait(Mutex&);
- inline bool wait(Mutex&, const AbsTime& absoluteTime);
- inline void notify();
- inline void notifyAll();
-
- private:
- pthread_cond_t condition;
-};
-
-Condition::Condition() {
- QPID_POSIX_ASSERT_THROW_IF(pthread_cond_init(&condition, 0));
-}
-
-Condition::~Condition() {
- QPID_POSIX_ASSERT_THROW_IF(pthread_cond_destroy(&condition));
-}
-
-void Condition::wait(Mutex& mutex) {
- QPID_POSIX_ASSERT_THROW_IF(pthread_cond_wait(&condition, &mutex.mutex));
-}
-
-bool Condition::wait(Mutex& mutex, const AbsTime& absoluteTime){
- struct timespec ts;
- toTimespec(ts, Duration(absoluteTime));
- int status = pthread_cond_timedwait(&condition, &mutex.mutex, &ts);
- if (status != 0) {
- if (status == ETIMEDOUT) return false;
- throw QPID_POSIX_ERROR(status);
- }
- return true;
-}
-
-void Condition::notify(){
- QPID_POSIX_ASSERT_THROW_IF(pthread_cond_signal(&condition));
-}
-
-void Condition::notifyAll(){
- QPID_POSIX_ASSERT_THROW_IF(pthread_cond_broadcast(&condition));
-}
-
-}}
-#endif /*!_sys_posix_Condition_h*/
diff --git a/cpp/src/qpid/sys/posix/FileSysDir.cpp b/cpp/src/qpid/sys/posix/FileSysDir.cpp
new file mode 100755
index 0000000000..22dc487e74
--- /dev/null
+++ b/cpp/src/qpid/sys/posix/FileSysDir.cpp
@@ -0,0 +1,54 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/sys/FileSysDir.h"
+#include "qpid/sys/StrError.h"
+#include "qpid/Exception.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <cerrno>
+#include <unistd.h>
+
+namespace qpid {
+namespace sys {
+
+bool FileSysDir::exists (void) const
+{
+ const char *cpath = dirPath.c_str ();
+ struct stat s;
+ if (::stat(cpath, &s)) {
+ if (errno == ENOENT) {
+ return false;
+ }
+ throw qpid::Exception (strError(errno) +
+ ": Can't check directory: " + dirPath);
+ }
+ if (S_ISDIR(s.st_mode))
+ return true;
+ throw qpid::Exception(dirPath + " is not a directory");
+}
+
+void FileSysDir::mkdir(void)
+{
+ if (::mkdir(dirPath.c_str(), 0755))
+ throw Exception ("Can't create directory: " + dirPath);
+}
+
+}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/posix/Fork.cpp b/cpp/src/qpid/sys/posix/Fork.cpp
index ec3af620ef..a0d404a16e 100644
--- a/cpp/src/qpid/sys/posix/Fork.cpp
+++ b/cpp/src/qpid/sys/posix/Fork.cpp
@@ -22,7 +22,9 @@
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
+#include <string.h>
#include <sys/stat.h>
+#include <sys/select.h>
#include <sys/types.h>
#include <unistd.h>
diff --git a/cpp/src/qpid/sys/posix/IOHandle.cpp b/cpp/src/qpid/sys/posix/IOHandle.cpp
index 80b487eadc..9c049ee1de 100644
--- a/cpp/src/qpid/sys/posix/IOHandle.cpp
+++ b/cpp/src/qpid/sys/posix/IOHandle.cpp
@@ -21,7 +21,7 @@
#include "qpid/sys/IOHandle.h"
-#include "PrivatePosix.h"
+#include "qpid/sys/posix/PrivatePosix.h"
namespace qpid {
namespace sys {
@@ -31,6 +31,8 @@ int toFd(const IOHandlePrivate* h)
return h->fd;
}
+NullIOHandle DummyIOHandle;
+
IOHandle::IOHandle(IOHandlePrivate* h) :
impl(h)
{}
diff --git a/cpp/src/qpid/sys/posix/LockFile.cpp b/cpp/src/qpid/sys/posix/LockFile.cpp
new file mode 100755
index 0000000000..1862ff6ac9
--- /dev/null
+++ b/cpp/src/qpid/sys/posix/LockFile.cpp
@@ -0,0 +1,108 @@
+/*
+ *
+ * Copyright (c) 2008 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/sys/LockFile.h"
+#include "qpid/sys/posix/PidFile.h"
+
+#include <string>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "qpid/sys/posix/check.h"
+
+namespace qpid {
+namespace sys {
+
+class LockFilePrivate {
+ friend class LockFile;
+ friend class PidFile;
+
+ int fd;
+
+public:
+ LockFilePrivate(int f) : fd(f) {}
+};
+
+LockFile::LockFile(const std::string& path_, bool create)
+ : path(path_), created(create) {
+
+ errno = 0;
+ int flags=create ? O_WRONLY|O_CREAT|O_NOFOLLOW : O_RDWR;
+ int fd = ::open(path.c_str(), flags, 0644);
+ if (fd < 0) throw ErrnoException("Cannot open " + path, errno);
+ if (::lockf(fd, F_TLOCK, 0) < 0) {
+ ::close(fd);
+ throw ErrnoException("Cannot lock " + path, errno);
+ }
+ impl.reset(new LockFilePrivate(fd));
+}
+
+LockFile::~LockFile() {
+ if (impl) {
+ int f = impl->fd;
+ if (f >= 0) {
+ int unused_ret;
+ unused_ret = ::lockf(f, F_ULOCK, 0); // Suppress warnings about ignoring return value.
+ ::close(f);
+ impl->fd = -1;
+ }
+ }
+}
+
+int LockFile::read(void* bytes, size_t len) const {
+ if (!impl)
+ throw Exception("Lock file not open: " + path);
+
+ ssize_t rc = ::read(impl->fd, bytes, len);
+ if ((ssize_t)len > rc) {
+ throw Exception("Cannot read lock file: " + path);
+ }
+ return rc;
+}
+
+int LockFile::write(void* bytes, size_t len) const {
+ if (!impl)
+ throw Exception("Lock file not open: " + path);
+
+ ssize_t rc = ::write(impl->fd, bytes, len);
+ if ((ssize_t)len > rc) {
+ throw Exception("Cannot write lock file: " + path);
+ }
+ return rc;
+}
+
+PidFile::PidFile(const std::string& path_, bool create):
+ LockFile(path_, create)
+{}
+
+pid_t PidFile::readPid(void) const {
+ pid_t pid;
+ int desired_read = sizeof(pid_t);
+ read(&pid, desired_read);
+ return pid;
+}
+
+void PidFile::writePid(void) {
+ pid_t pid = getpid();
+ int desired_write = sizeof(pid_t);
+ write(&pid, desired_write);
+}
+
+}} /* namespace qpid::sys */
diff --git a/cpp/src/qpid/sys/posix/LockFile.h b/cpp/src/qpid/sys/posix/LockFile.h
deleted file mode 100644
index 027735e759..0000000000
--- a/cpp/src/qpid/sys/posix/LockFile.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef _sys_posix_LockFile_h
-#define _sys_posix_LockFile_h
-
-#include "check.h"
-
-#include <boost/noncopyable.hpp>
-#include <string>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-/*
- *
- * Copyright (c) 2008 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-namespace qpid {
-namespace sys {
-
-class LockFile : private boost::noncopyable {
-public:
- LockFile(const std::string& path_, bool create):
- path(path_), fd(-1), created(create) {
- errno = 0;
- int flags=create ? O_WRONLY|O_CREAT|O_NOFOLLOW : O_RDWR;
- fd = ::open(path.c_str(), flags, 0644);
- if (fd < 0) throw ErrnoException("Cannot open " + path, errno);
- if (::lockf(fd, F_TLOCK, 0) < 0) throw ErrnoException("Cannot lock " + path, errno);
- }
-
- ~LockFile() {
- if (fd >= 0) {
- (void) ::lockf(fd, F_ULOCK, 0); // Suppress warnings about ignoring return value.
- ::close(fd);
- }
- }
-
- std::string path;
- int fd;
- bool created;
-};
-
-}
-}
-#endif /*!_sys_posix_LockFile_h*/
diff --git a/cpp/src/qpid/sys/posix/Mutex.h b/cpp/src/qpid/sys/posix/Mutex.h
deleted file mode 100644
index cd5a8affd4..0000000000
--- a/cpp/src/qpid/sys/posix/Mutex.h
+++ /dev/null
@@ -1,158 +0,0 @@
-#ifndef _sys_posix_Mutex_h
-#define _sys_posix_Mutex_h
-
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "check.h"
-
-#include <pthread.h>
-#include <boost/noncopyable.hpp>
-
-namespace qpid {
-namespace sys {
-
-class Condition;
-
-/**
- * Mutex lock.
- */
-class Mutex : private boost::noncopyable {
- friend class Condition;
- static const pthread_mutexattr_t* getAttribute();
-
-public:
- typedef ::qpid::sys::ScopedLock<Mutex> ScopedLock;
- typedef ::qpid::sys::ScopedUnlock<Mutex> ScopedUnlock;
-
- inline Mutex();
- inline ~Mutex();
- inline void lock();
- inline void unlock();
- inline bool trylock();
-
-
-protected:
- pthread_mutex_t mutex;
-};
-
-/**
- * RW lock.
- */
-class RWlock : private boost::noncopyable {
- friend class Condition;
-
-public:
- typedef ::qpid::sys::ScopedRlock<RWlock> ScopedRlock;
- typedef ::qpid::sys::ScopedWlock<RWlock> ScopedWlock;
-
- inline RWlock();
- inline ~RWlock();
- inline void wlock(); // will write-lock
- inline void rlock(); // will read-lock
- inline void unlock();
- inline void trywlock(); // will write-try
- inline void tryrlock(); // will read-try
-
-protected:
- pthread_rwlock_t rwlock;
-};
-
-
-/**
- * PODMutex is a POD, can be static-initialized with
- * PODMutex m = QPID_PODMUTEX_INITIALIZER
- */
-struct PODMutex
-{
- typedef ::qpid::sys::ScopedLock<PODMutex> ScopedLock;
-
- inline void lock();
- inline void unlock();
- inline bool trylock();
-
- // Must be public to be a POD:
- pthread_mutex_t mutex;
-};
-
-#define QPID_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
-
-void PODMutex::lock() {
- QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_lock(&mutex));
-}
-
-void PODMutex::unlock() {
- QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_unlock(&mutex));
-}
-
-bool PODMutex::trylock() {
- return pthread_mutex_trylock(&mutex) == 0;
-}
-
-Mutex::Mutex() {
- QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_init(&mutex, getAttribute()));
-}
-
-Mutex::~Mutex(){
- QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_destroy(&mutex));
-}
-
-void Mutex::lock() {
- QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_lock(&mutex));
-}
-
-void Mutex::unlock() {
- QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_unlock(&mutex));
-}
-
-bool Mutex::trylock() {
- return pthread_mutex_trylock(&mutex) == 0;
-}
-
-
-RWlock::RWlock() {
- QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_init(&rwlock, NULL));
-}
-
-RWlock::~RWlock(){
- QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_destroy(&rwlock));
-}
-
-void RWlock::wlock() {
- QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_wrlock(&rwlock));
-}
-
-void RWlock::rlock() {
- QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_rdlock(&rwlock));
-}
-
-void RWlock::unlock() {
- QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_unlock(&rwlock));
-}
-
-void RWlock::trywlock() {
- QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_trywrlock(&rwlock));
-}
-
-void RWlock::tryrlock() {
- QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_tryrdlock(&rwlock));
-}
-
-
-}}
-#endif /*!_sys_posix_Mutex_h*/
diff --git a/cpp/src/qpid/sys/posix/PidFile.h b/cpp/src/qpid/sys/posix/PidFile.h
new file mode 100644
index 0000000000..fb19d407f4
--- /dev/null
+++ b/cpp/src/qpid/sys/posix/PidFile.h
@@ -0,0 +1,62 @@
+#ifndef _sys_PidFile_h
+#define _sys_PidFile_h
+
+/*
+ *
+ * Copyright (c) 2008 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/sys/LockFile.h"
+
+#include "qpid/CommonImportExport.h"
+#include "qpid/sys/IntegerTypes.h"
+
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+namespace qpid {
+namespace sys {
+
+class PidFile : public LockFile
+{
+public:
+ QPID_COMMON_EXTERN PidFile(const std::string& path_, bool create);
+
+ /**
+ * Read the process ID from the lock file. This method assumes that
+ * if there is a process ID in the file, it was written there by
+ * writePid(); thus, it's at the start of the file.
+ *
+ * Throws an exception if there is an error reading the file.
+ *
+ * @returns The stored process ID. No validity check is done on it.
+ */
+ QPID_COMMON_EXTERN pid_t readPid(void) const;
+
+ /**
+ * Write the current process's ID to the lock file. It's written at
+ * the start of the file and will overwrite any other content that
+ * may be in the file.
+ *
+ * Throws an exception if the write fails.
+ */
+ QPID_COMMON_EXTERN void writePid(void);
+};
+
+}} /* namespace qpid::sys */
+
+#endif /*!_sys_PidFile_h*/
diff --git a/cpp/src/qpid/sys/posix/PipeHandle.cpp b/cpp/src/qpid/sys/posix/PipeHandle.cpp
new file mode 100755
index 0000000000..4b19783338
--- /dev/null
+++ b/cpp/src/qpid/sys/posix/PipeHandle.cpp
@@ -0,0 +1,64 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+#include "qpid/sys/PipeHandle.h"
+#include "qpid/sys/posix/check.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+
+namespace qpid {
+namespace sys {
+
+PipeHandle::PipeHandle(bool nonBlocking) {
+
+ int pair[2];
+ pair[0] = pair[1] = -1;
+
+ if (socketpair(PF_UNIX, SOCK_STREAM, 0, pair) == -1)
+ throw qpid::Exception(QPID_MSG("Creation of pipe failed"));
+
+ writeFd = pair[0];
+ readFd = pair[1];
+
+ // Set the socket to non-blocking
+ if (nonBlocking) {
+ int flags = fcntl(readFd, F_GETFL);
+ fcntl(readFd, F_SETFL, flags | O_NONBLOCK);
+ }
+}
+
+PipeHandle::~PipeHandle() {
+ close(readFd);
+ close(writeFd);
+}
+
+int PipeHandle::read(void* buf, size_t bufSize) {
+ return ::read(readFd,buf,bufSize);
+}
+
+int PipeHandle::write(const void* buf, size_t bufSize) {
+ return ::write(writeFd,buf,bufSize);
+}
+
+int PipeHandle::getReadHandle() {
+ return readFd;
+}
+
+}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/posix/PollableCondition.cpp b/cpp/src/qpid/sys/posix/PollableCondition.cpp
new file mode 100644
index 0000000000..b22a615a54
--- /dev/null
+++ b/cpp/src/qpid/sys/posix/PollableCondition.cpp
@@ -0,0 +1,124 @@
+#ifndef QPID_SYS_LINUX_POLLABLECONDITION_CPP
+#define QPID_SYS_LINUX_POLLABLECONDITION_CPP
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/PollableCondition.h"
+#include "qpid/sys/DispatchHandle.h"
+#include "qpid/sys/IOHandle.h"
+#include "qpid/sys/posix/PrivatePosix.h"
+#include "qpid/Exception.h"
+
+#include <boost/bind.hpp>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+namespace qpid {
+namespace sys {
+
+class PollableConditionPrivate : public sys::IOHandle {
+ friend class PollableCondition;
+
+private:
+ PollableConditionPrivate(const sys::PollableCondition::Callback& cb,
+ sys::PollableCondition& parent,
+ const boost::shared_ptr<sys::Poller>& poller);
+ ~PollableConditionPrivate();
+
+ void dispatch(sys::DispatchHandle& h);
+ void set();
+ void clear();
+
+private:
+ PollableCondition::Callback cb;
+ PollableCondition& parent;
+ boost::shared_ptr<sys::Poller> poller;
+ int writeFd;
+ std::auto_ptr<DispatchHandleRef> handle;
+};
+
+PollableConditionPrivate::PollableConditionPrivate(
+ const sys::PollableCondition::Callback& cb,
+ sys::PollableCondition& parent,
+ const boost::shared_ptr<sys::Poller>& poller
+) : IOHandle(new sys::IOHandlePrivate), cb(cb), parent(parent)
+{
+ int fds[2];
+ if (::pipe(fds) == -1)
+ throw ErrnoException(QPID_MSG("Can't create PollableCondition"));
+ impl->fd = fds[0];
+ writeFd = fds[1];
+ if (::fcntl(impl->fd, F_SETFL, O_NONBLOCK) == -1)
+ throw ErrnoException(QPID_MSG("Can't create PollableCondition"));
+ if (::fcntl(writeFd, F_SETFL, O_NONBLOCK) == -1)
+ throw ErrnoException(QPID_MSG("Can't create PollableCondition"));
+ handle.reset (new DispatchHandleRef(
+ *this,
+ boost::bind(&sys::PollableConditionPrivate::dispatch, this, _1),
+ 0, 0));
+ handle->startWatch(poller);
+ handle->unwatch();
+
+ // Make the read FD readable
+ static const char dummy=0;
+ ssize_t n = ::write(writeFd, &dummy, 1);
+ if (n == -1 && errno != EAGAIN)
+ throw ErrnoException("Error setting PollableCondition");
+}
+
+PollableConditionPrivate::~PollableConditionPrivate() {
+ handle->stopWatch();
+ close(writeFd);
+}
+
+void PollableConditionPrivate::dispatch(sys::DispatchHandle&) {
+ cb(parent);
+}
+
+void PollableConditionPrivate::set() {
+ handle->rewatch();
+}
+
+void PollableConditionPrivate::clear() {
+ handle->unwatch();
+}
+
+
+PollableCondition::PollableCondition(const Callback& cb,
+ const boost::shared_ptr<sys::Poller>& poller
+) : impl(new PollableConditionPrivate(cb, *this, poller))
+{
+}
+
+PollableCondition::~PollableCondition()
+{
+ delete impl;
+}
+
+void PollableCondition::set() { impl->set(); }
+
+void PollableCondition::clear() { impl->clear(); }
+
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_LINUX_POLLABLECONDITION_CPP*/
diff --git a/cpp/src/qpid/sys/posix/PrivatePosix.h b/cpp/src/qpid/sys/posix/PrivatePosix.h
deleted file mode 100644
index 33c0cd81bc..0000000000
--- a/cpp/src/qpid/sys/posix/PrivatePosix.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef _sys_posix_PrivatePosix_h
-#define _sys_posix_PrivatePosix_h
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/sys/Time.h"
-
-struct timespec;
-struct timeval;
-
-namespace qpid {
-namespace sys {
-
-// Private Time related implementation details
-struct timespec& toTimespec(struct timespec& ts, const Duration& t);
-struct timeval& toTimeval(struct timeval& tv, const Duration& t);
-Duration toTime(const struct timespec& ts);
-
-// Private fd related implementation details
-class IOHandlePrivate {
-public:
- IOHandlePrivate(int f = -1) :
- fd(f)
- {}
-
- int fd;
-};
-
-int toFd(const IOHandlePrivate* h);
-
-}}
-
-#endif /*!_sys_posix_PrivatePosix_h*/
diff --git a/cpp/src/qpid/sys/posix/Shlib.cpp b/cpp/src/qpid/sys/posix/Shlib.cpp
index 1552aa06b5..299331103c 100644
--- a/cpp/src/qpid/sys/posix/Shlib.cpp
+++ b/cpp/src/qpid/sys/posix/Shlib.cpp
@@ -27,11 +27,11 @@ namespace qpid {
namespace sys {
void Shlib::load(const char* name) {
- dlerror();
+ ::dlerror();
handle = ::dlopen(name, RTLD_NOW);
const char* error = ::dlerror();
if (error) {
- throw Exception(QPID_MSG(error));
+ throw Exception(QPID_MSG(error << ": " << name));
}
}
@@ -52,7 +52,7 @@ void* Shlib::getSymbol(const char* name) {
void* sym = ::dlsym(handle, name);
const char* error = ::dlerror();
if (error)
- throw Exception(QPID_MSG(error));
+ throw Exception(QPID_MSG(error << ": " << name));
return sym;
}
diff --git a/cpp/src/qpid/sys/posix/Socket.cpp b/cpp/src/qpid/sys/posix/Socket.cpp
index 415d5293ef..7b906f33e8 100644
--- a/cpp/src/qpid/sys/posix/Socket.cpp
+++ b/cpp/src/qpid/sys/posix/Socket.cpp
@@ -21,8 +21,9 @@
#include "qpid/sys/Socket.h"
-#include "check.h"
-#include "PrivatePosix.h"
+#include "qpid/sys/SocketAddress.h"
+#include "qpid/sys/posix/check.h"
+#include "qpid/sys/posix/PrivatePosix.h"
#include <fcntl.h>
#include <sys/types.h>
@@ -36,6 +37,7 @@
#include <iostream>
#include <boost/format.hpp>
+#include <boost/lexical_cast.hpp>
namespace qpid {
namespace sys {
@@ -95,22 +97,33 @@ std::string getService(int fd, bool local)
}
Socket::Socket() :
- IOHandle(new IOHandlePrivate)
-{
- createTcp();
-}
+ IOHandle(new IOHandlePrivate),
+ nonblocking(false),
+ nodelay(false)
+{}
Socket::Socket(IOHandlePrivate* h) :
- IOHandle(h)
+ IOHandle(h),
+ nonblocking(false),
+ nodelay(false)
{}
-void Socket::createTcp() const
+void Socket::createSocket(const SocketAddress& sa) const
{
int& socket = impl->fd;
if (socket != -1) Socket::close();
- int s = ::socket (PF_INET, SOCK_STREAM, 0);
+ int s = ::socket(getAddrInfo(sa).ai_family, getAddrInfo(sa).ai_socktype, 0);
if (s < 0) throw QPID_POSIX_ERROR(errno);
socket = s;
+
+ try {
+ if (nonblocking) setNonblocking();
+ if (nodelay) setTcpNoDelay();
+ } catch (std::exception&) {
+ ::close(s);
+ socket = -1;
+ throw;
+ }
}
void Socket::setTimeout(const Duration& interval) const
@@ -123,40 +136,42 @@ void Socket::setTimeout(const Duration& interval) const
}
void Socket::setNonblocking() const {
- QPID_POSIX_CHECK(::fcntl(impl->fd, F_SETFL, O_NONBLOCK));
+ int& socket = impl->fd;
+ nonblocking = true;
+ if (socket != -1) {
+ QPID_POSIX_CHECK(::fcntl(socket, F_SETFL, O_NONBLOCK));
+ }
}
-namespace {
-const char* h_errstr(int e) {
- switch (e) {
- case HOST_NOT_FOUND: return "Host not found";
- case NO_ADDRESS: return "Name does not have an IP address";
- case TRY_AGAIN: return "A temporary error occurred on an authoritative name server.";
- case NO_RECOVERY: return "Non-recoverable name server error";
- default: return "Unknown error";
+void Socket::setTcpNoDelay() const
+{
+ int& socket = impl->fd;
+ nodelay = true;
+ if (socket != -1) {
+ int flag = 1;
+ int result = setsockopt(impl->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag));
+ QPID_POSIX_CHECK(result);
}
}
-}
void Socket::connect(const std::string& host, uint16_t port) const
{
- std::stringstream namestream;
- namestream << host << ":" << port;
- connectname = namestream.str();
+ SocketAddress sa(host, boost::lexical_cast<std::string>(port));
+ connect(sa);
+}
+
+void Socket::connect(const SocketAddress& addr) const
+{
+ connectname = addr.asString();
+
+ createSocket(addr);
const int& socket = impl->fd;
- struct sockaddr_in name;
- name.sin_family = AF_INET;
- name.sin_port = htons(port);
- // TODO: Be good to make this work for IPv6 as well as IPv4
- // Use more modern lookup functions
- struct hostent* hp = gethostbyname ( host.c_str() );
- if (hp == 0)
- throw Exception(QPID_MSG("Cannot resolve " << host << ": " << h_errstr(h_errno)));
- ::memcpy(&name.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length);
- if ((::connect(socket, (struct sockaddr*)(&name), sizeof(name)) < 0) &&
- (errno != EINPROGRESS))
- throw qpid::Exception(QPID_MSG(strError(errno) << ": " << host << ":" << port));
+ // TODO the correct thing to do here is loop on failure until you've used all the returned addresses
+ if ((::connect(socket, getAddrInfo(addr).ai_addr, getAddrInfo(addr).ai_addrlen) < 0) &&
+ (errno != EINPROGRESS)) {
+ throw Exception(QPID_MSG(strError(errno) << ": " << connectname));
+ }
}
void
@@ -170,18 +185,24 @@ Socket::close() const
int Socket::listen(uint16_t port, int backlog) const
{
+ SocketAddress sa("", boost::lexical_cast<std::string>(port));
+ return listen(sa, backlog);
+}
+
+int Socket::listen(const SocketAddress& sa, int backlog) const
+{
+ createSocket(sa);
+
const int& socket = impl->fd;
int yes=1;
QPID_POSIX_CHECK(setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)));
- struct sockaddr_in name;
- name.sin_family = AF_INET;
- name.sin_port = htons(port);
- name.sin_addr.s_addr = 0;
- if (::bind(socket, (struct sockaddr*)&name, sizeof(name)) < 0)
- throw Exception(QPID_MSG("Can't bind to port " << port << ": " << strError(errno)));
+
+ if (::bind(socket, getAddrInfo(sa).ai_addr, getAddrInfo(sa).ai_addrlen) < 0)
+ throw Exception(QPID_MSG("Can't bind to port " << sa.asString() << ": " << strError(errno)));
if (::listen(socket, backlog) < 0)
- throw Exception(QPID_MSG("Can't listen on port " << port << ": " << strError(errno)));
-
+ throw Exception(QPID_MSG("Can't listen on port " << sa.asString() << ": " << strError(errno)));
+
+ struct sockaddr_in name;
socklen_t namelen = sizeof(name);
if (::getsockname(socket, (struct sockaddr*)&name, &namelen) < 0)
throw QPID_POSIX_ERROR(errno);
@@ -189,9 +210,9 @@ int Socket::listen(uint16_t port, int backlog) const
return ntohs(name.sin_port);
}
-Socket* Socket::accept(struct sockaddr *addr, socklen_t *addrlen) const
+Socket* Socket::accept() const
{
- int afd = ::accept(impl->fd, addr, addrlen);
+ int afd = ::accept(impl->fd, 0, 0);
if ( afd >= 0)
return new Socket(new IOHandlePrivate(afd));
else if (errno == EAGAIN)
@@ -221,9 +242,10 @@ std::string Socket::getPeername() const
std::string Socket::getPeerAddress() const
{
- if (!connectname.empty())
- return std::string (connectname);
- return getName(impl->fd, false, true);
+ if (connectname.empty()) {
+ connectname = getName(impl->fd, false, true);
+ }
+ return connectname;
}
std::string Socket::getLocalAddress() const
@@ -238,7 +260,7 @@ uint16_t Socket::getLocalPort() const
uint16_t Socket::getRemotePort() const
{
- return atoi(getService(impl->fd, true).c_str());
+ return std::atoi(getService(impl->fd, true).c_str());
}
int Socket::getError() const
@@ -252,13 +274,4 @@ int Socket::getError() const
return result;
}
-void Socket::setTcpNoDelay(bool nodelay) const
-{
- if (nodelay) {
- int flag = 1;
- int result = setsockopt(impl->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag));
- QPID_POSIX_CHECK(result);
- }
-}
-
}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/posix/SocketAddress.cpp b/cpp/src/qpid/sys/posix/SocketAddress.cpp
new file mode 100644
index 0000000000..cb44f8e41f
--- /dev/null
+++ b/cpp/src/qpid/sys/posix/SocketAddress.cpp
@@ -0,0 +1,97 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/SocketAddress.h"
+
+#include "qpid/sys/posix/check.h"
+
+#include <sys/socket.h>
+#include <string.h>
+#include <netdb.h>
+
+namespace qpid {
+namespace sys {
+
+SocketAddress::SocketAddress(const std::string& host0, const std::string& port0) :
+ host(host0),
+ port(port0),
+ addrInfo(0)
+{
+}
+
+SocketAddress::SocketAddress(const SocketAddress& sa) :
+ host(sa.host),
+ port(sa.port),
+ addrInfo(0)
+{
+}
+
+SocketAddress& SocketAddress::operator=(const SocketAddress& sa)
+{
+ if (&sa != this) {
+ host = sa.host;
+ port = sa.port;
+
+ if (addrInfo) {
+ ::freeaddrinfo(addrInfo);
+ addrInfo = 0;
+ }
+ }
+ return *this;
+}
+
+SocketAddress::~SocketAddress()
+{
+ if (addrInfo) {
+ ::freeaddrinfo(addrInfo);
+ }
+}
+
+std::string SocketAddress::asString() const
+{
+ return host + ":" + port;
+}
+
+const ::addrinfo& getAddrInfo(const SocketAddress& sa)
+{
+ if (!sa.addrInfo) {
+ ::addrinfo hints;
+ ::memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET; // In order to allow AF_INET6 we'd have to change createTcp() as well
+ hints.ai_socktype = SOCK_STREAM;
+
+ const char* node = 0;
+ if (sa.host.empty()) {
+ hints.ai_flags |= AI_PASSIVE;
+ } else {
+ node = sa.host.c_str();
+ }
+ const char* service = sa.port.empty() ? "0" : sa.port.c_str();
+
+ int n = ::getaddrinfo(node, service, &hints, &sa.addrInfo);
+ if (n != 0)
+ throw Exception(QPID_MSG("Cannot resolve " << sa.host << ": " << ::gai_strerror(n)));
+ }
+
+ return *sa.addrInfo;
+}
+
+}}
diff --git a/cpp/src/qpid/sys/posix/SystemInfo.cpp b/cpp/src/qpid/sys/posix/SystemInfo.cpp
new file mode 100755
index 0000000000..55737fcfcc
--- /dev/null
+++ b/cpp/src/qpid/sys/posix/SystemInfo.cpp
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/sys/SystemInfo.h"
+
+#include "qpid/sys/posix/check.h"
+
+#include <sys/ioctl.h>
+#include <sys/utsname.h>
+#include <net/if.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <netdb.h>
+
+#ifndef HOST_NAME_MAX
+# define HOST_NAME_MAX 256
+#endif
+
+using namespace std;
+
+namespace qpid {
+namespace sys {
+
+long SystemInfo::concurrency() {
+#ifdef _SC_NPROCESSORS_ONLN // Linux specific.
+ return sysconf(_SC_NPROCESSORS_ONLN);
+#else
+ return -1;
+#endif
+}
+
+bool SystemInfo::getLocalHostname (TcpAddress &address) {
+ char name[HOST_NAME_MAX];
+ if (::gethostname(name, sizeof(name)) != 0)
+ return false;
+ address.host = name;
+ return true;
+}
+
+static const string LOCALHOST("127.0.0.1");
+
+void SystemInfo::getLocalIpAddresses (uint16_t port,
+ std::vector<Address> &addrList) {
+ int s = ::socket(PF_INET, SOCK_STREAM, 0);
+ for (int i=1;;i++) {
+ ::ifreq ifr;
+ ifr.ifr_ifindex = i;
+ if (::ioctl (s, SIOCGIFNAME, &ifr) < 0)
+ break;
+ /* now ifr.ifr_name is set */
+ if (::ioctl (s, SIOCGIFADDR, &ifr) < 0)
+ continue;
+ ::sockaddr *saddr = (::sockaddr *) &ifr.ifr_addr;
+ char dispName[NI_MAXHOST];
+ if (int rc=::getnameinfo(saddr, sizeof(ifr.ifr_addr), dispName, sizeof(dispName), 0, 0, NI_NUMERICHOST) != 0)
+ throw QPID_POSIX_ERROR(rc);
+ string addr(dispName);
+ if (addr != LOCALHOST)
+ addrList.push_back(TcpAddress(addr, port));
+ }
+ if (addrList.empty()) {
+ addrList.push_back(TcpAddress(LOCALHOST, port));
+ }
+ close (s);
+}
+
+void SystemInfo::getSystemId (std::string &osName,
+ std::string &nodeName,
+ std::string &release,
+ std::string &version,
+ std::string &machine)
+{
+ struct utsname _uname;
+ if (uname (&_uname) == 0)
+ {
+ osName = _uname.sysname;
+ nodeName = _uname.nodename;
+ release = _uname.release;
+ version = _uname.version;
+ machine = _uname.machine;
+ }
+}
+
+uint32_t SystemInfo::getProcessId()
+{
+ return (uint32_t) ::getpid();
+}
+
+uint32_t SystemInfo::getParentProcessId()
+{
+ return (uint32_t) ::getppid();
+}
+
+// Linux specific (Solaris has quite different stuff in /proc)
+string SystemInfo::getProcessName()
+{
+ string value;
+
+ ifstream input("/proc/self/status");
+ if (input.good()) {
+ while (!input.eof()) {
+ string key;
+ input >> key;
+ if (key == "Name:") {
+ input >> value;
+ break;
+ }
+ }
+ input.close();
+ }
+
+ return value;
+}
+
+}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/posix/Thread.cpp b/cpp/src/qpid/sys/posix/Thread.cpp
index bb5641bc53..a784e63195 100644
--- a/cpp/src/qpid/sys/posix/Thread.cpp
+++ b/cpp/src/qpid/sys/posix/Thread.cpp
@@ -22,7 +22,7 @@
#include "qpid/sys/Thread.h"
#include "qpid/sys/Runnable.h"
-#include "check.h"
+#include "qpid/sys/posix/check.h"
#include <pthread.h>
diff --git a/cpp/src/qpid/sys/posix/Time.cpp b/cpp/src/qpid/sys/posix/Time.cpp
index 8aa9fd9946..0734abd1df 100644
--- a/cpp/src/qpid/sys/posix/Time.cpp
+++ b/cpp/src/qpid/sys/posix/Time.cpp
@@ -19,25 +19,46 @@
*
*/
-#include "PrivatePosix.h"
+#include "qpid/sys/posix/PrivatePosix.h"
#include "qpid/sys/Time.h"
#include <ostream>
#include <time.h>
#include <stdio.h>
#include <sys/time.h>
+#include <unistd.h>
+
+namespace {
+int64_t max_abstime() { return std::numeric_limits<int64_t>::max(); }
+}
namespace qpid {
namespace sys {
+AbsTime::AbsTime(const AbsTime& t, const Duration& d) :
+ timepoint(d == Duration::max() ? max_abstime() : t.timepoint+d.nanosecs)
+{}
+
+AbsTime AbsTime::FarFuture() {
+ AbsTime ff; ff.timepoint = max_abstime(); return ff;
+}
+
AbsTime AbsTime::now() {
struct timespec ts;
::clock_gettime(CLOCK_REALTIME, &ts);
AbsTime time_now;
- time_now.time_ns = toTime(ts).nanosecs;
+ time_now.timepoint = toTime(ts).nanosecs;
return time_now;
}
+Duration::Duration(const AbsTime& time0) :
+ nanosecs(time0.timepoint)
+{}
+
+Duration::Duration(const AbsTime& start, const AbsTime& finish) :
+ nanosecs(finish.timepoint - start.timepoint)
+{}
+
struct timespec& toTimespec(struct timespec& ts, const Duration& t) {
ts.tv_sec = t / TIME_SEC;
ts.tv_nsec = t % TIME_SEC;
@@ -58,25 +79,35 @@ std::ostream& operator<<(std::ostream& o, const Duration& d) {
return o << int64_t(d) << "ns";
}
-std::ostream& operator<<(std::ostream& o, const AbsTime& t) {
- static const char * month_abbrevs[] = {
- "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"
- };
- struct tm * timeinfo;
- time_t rawtime(t.time_ns/TIME_SEC);
- timeinfo = localtime (&rawtime);
+namespace {
+inline std::ostream& outputFormattedTime(std::ostream& o, const ::time_t* time) {
+ ::tm timeinfo;
char time_string[100];
- sprintf ( time_string,
- "%d-%s-%02d %02d:%02d:%02d",
- 1900 + timeinfo->tm_year,
- month_abbrevs[timeinfo->tm_mon],
- timeinfo->tm_mday,
- timeinfo->tm_hour,
- timeinfo->tm_min,
- timeinfo->tm_sec
- );
+ ::strftime(time_string, 100,
+ "%Y-%m-%d %H:%M:%S",
+ localtime_r(time, &timeinfo));
return o << time_string;
}
+}
-}}
+std::ostream& operator<<(std::ostream& o, const AbsTime& t) {
+ ::time_t rawtime(t.timepoint/TIME_SEC);
+ return outputFormattedTime(o, &rawtime);
+}
+void outputFormattedNow(std::ostream& o) {
+ ::time_t rawtime;
+ ::time(&rawtime);
+ outputFormattedTime(o, &rawtime);
+ o << " ";
+}
+
+void sleep(int secs) {
+ ::sleep(secs);
+}
+
+void usleep(uint64_t usecs) {
+ ::usleep(usecs);
+}
+
+}}
diff --git a/cpp/src/qpid/sys/posix/check.h b/cpp/src/qpid/sys/posix/check.h
deleted file mode 100644
index f3031b7593..0000000000
--- a/cpp/src/qpid/sys/posix/check.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef _posix_check_h
-#define _posix_check_h
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/Exception.h"
-
-#include <cerrno>
-#include <assert.h>
-#include <stdio.h>
-
-#define QPID_POSIX_ERROR(ERRNO) qpid::Exception(QPID_MSG(qpid::sys::strError(ERRNO)))
-
-/** THROW QPID_POSIX_ERROR(errno) if RESULT is less than zero */
-#define QPID_POSIX_CHECK(RESULT) \
- if ((RESULT) < 0) throw QPID_POSIX_ERROR((errno))
-
-/** Throw a posix error if ERRNO is non-zero */
-#define QPID_POSIX_THROW_IF(ERRNO) \
- do { int e=(ERRNO); if (e) throw QPID_POSIX_ERROR(e); } while(0)
-
-/** Same as _THROW_IF in a release build, but abort a debug build */
-#ifdef NDEBUG
-#define QPID_POSIX_ASSERT_THROW_IF(ERRNO) QPID_POSIX_THROW_IF(ERRNO)
-#else
-#define QPID_POSIX_ASSERT_THROW_IF(ERRNO) \
- do { int e=(ERRNO); if (e) { errno=e; ::perror(0); assert(0); } } while(0)
-#endif
-
-#endif /*!_posix_check_h*/
diff --git a/cpp/src/qpid/sys/rdma/RdmaClient.cpp b/cpp/src/qpid/sys/rdma/RdmaClient.cpp
index afff96b72f..d39f7885a5 100644
--- a/cpp/src/qpid/sys/rdma/RdmaClient.cpp
+++ b/cpp/src/qpid/sys/rdma/RdmaClient.cpp
@@ -1,4 +1,24 @@
-#include "RdmaIO.h"
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/sys/rdma/RdmaIO.h"
#include "qpid/sys/Time.h"
#include <netdb.h>
@@ -20,18 +40,20 @@ using std::rand;
using qpid::sys::Poller;
using qpid::sys::Dispatcher;
+using qpid::sys::SocketAddress;
using qpid::sys::AbsTime;
using qpid::sys::Duration;
using qpid::sys::TIME_SEC;
using qpid::sys::TIME_INFINITE;
+namespace qpid {
+namespace tests {
+
// count of messages
int64_t smsgs = 0;
int64_t sbytes = 0;
int64_t rmsgs = 0;
int64_t rbytes = 0;
-int64_t cmsgs = 0;
-int writable = true;
int target = 1000000;
int msgsize = 200;
@@ -42,17 +64,15 @@ Duration fullTestDuration(TIME_INFINITE);
vector<char> testString;
void write(Rdma::AsynchIO& aio) {
- if ((cmsgs - rmsgs) < Rdma::DEFAULT_WR_ENTRIES/2) {
- while (writable) {
- if (smsgs >= target)
- return;
- Rdma::Buffer* b = aio.getBuffer();
- std::copy(testString.begin(), testString.end(), b->bytes);
- b->dataCount = msgsize;
- aio.queueWrite(b);
- ++smsgs;
- sbytes += b->byteCount;
- }
+ while (aio.writable()) {
+ if (smsgs >= target)
+ return;
+ Rdma::Buffer* b = aio.getBuffer();
+ std::copy(testString.begin(), testString.end(), b->bytes);
+ b->dataCount = msgsize;
+ aio.queueWrite(b);
+ ++smsgs;
+ sbytes += msgsize;
}
}
@@ -62,39 +82,46 @@ void dataError(Rdma::AsynchIO&) {
void data(Poller::shared_ptr p, Rdma::AsynchIO& aio, Rdma::Buffer* b) {
++rmsgs;
- rbytes += b->byteCount;
+ rbytes += b->dataCount;
// When all messages have been recvd stop
if (rmsgs < target) {
write(aio);
} else {
fullTestDuration = std::min(fullTestDuration, Duration(startTime, AbsTime::now()));
- if (cmsgs >= target)
+ if (aio.incompletedWrites() == 0)
p->shutdown();
}
}
-void full(Rdma::AsynchIO&) {
- writable = false;
+void full(Rdma::AsynchIO& a, Rdma::Buffer* b) {
+ // Warn as we shouldn't get here anymore
+ cerr << "!";
+
+ // Don't need to keep buffer just adjust the counts
+ --smsgs;
+ sbytes -= b->dataCount;
+
+ // Give buffer back
+ a.returnBuffer(b);
}
void idle(Poller::shared_ptr p, Rdma::AsynchIO& aio) {
- writable = true;
- ++cmsgs;
if (smsgs < target) {
write(aio);
} else {
sendingDuration = std::min(sendingDuration, Duration(startTime, AbsTime::now()));
- if (rmsgs >= target && cmsgs >= target)
+ if (rmsgs >= target && aio.incompletedWrites() == 0)
p->shutdown();
}
}
-void connected(Poller::shared_ptr poller, Rdma::Connection::intrusive_ptr& ci) {
+void connected(Poller::shared_ptr poller, Rdma::Connection::intrusive_ptr& ci, const Rdma::ConnectionParams& cp) {
cout << "Connected\n";
Rdma::QueuePair::intrusive_ptr q = ci->getQueuePair();
- Rdma::AsynchIO* aio = new Rdma::AsynchIO(ci->getQueuePair(), msgsize,
+ Rdma::AsynchIO* aio = new Rdma::AsynchIO(ci->getQueuePair(),
+ cp.maxRecvBufferSize, cp.initialXmitCredit , Rdma::DEFAULT_WR_ENTRIES,
boost::bind(&data, poller, _1, _2),
boost::bind(&idle, poller, _1),
&full,
@@ -111,31 +138,25 @@ void disconnected(boost::shared_ptr<Poller> p, Rdma::Connection::intrusive_ptr&)
p->shutdown();
}
-void connectionError(boost::shared_ptr<Poller> p, Rdma::Connection::intrusive_ptr&) {
+void connectionError(boost::shared_ptr<Poller> p, Rdma::Connection::intrusive_ptr&, const Rdma::ErrorType) {
cout << "Connection error\n";
p->shutdown();
}
-void rejected(boost::shared_ptr<Poller> p, Rdma::Connection::intrusive_ptr&) {
+void rejected(boost::shared_ptr<Poller> p, Rdma::Connection::intrusive_ptr&, const Rdma::ConnectionParams&) {
cout << "Connection rejected\n";
p->shutdown();
}
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char* argv[]) {
vector<string> args(&argv[0], &argv[argc]);
- ::addrinfo *res;
- ::addrinfo hints = {};
- hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_STREAM;
+ string host = args[1];
string port = (args.size() < 3) ? "20079" : args[2];
- int n = ::getaddrinfo(args[1].c_str(), port.c_str(), &hints, &res);
- if (n<0) {
- cerr << "Can't find information for: " << args[1] << "\n";
- return 1;
- } else {
- cout << "Connecting to: " << args[1] << ":" << port <<"\n";
- }
if (args.size() > 3)
msgsize = atoi(args[3].c_str());
@@ -144,19 +165,22 @@ int main(int argc, char* argv[]) {
// Make a random message of that size
testString.resize(msgsize);
for (int i = 0; i < msgsize; ++i) {
- testString[i] = 32 + rand() & 0x3f;
+ testString[i] = 32 + (rand() & 0x3f);
}
try {
boost::shared_ptr<Poller> p(new Poller());
Dispatcher d(p);
+ SocketAddress sa(host, port);
+ cout << "Connecting to: " << sa.asString() <<"\n";
Rdma::Connector c(
- *res->ai_addr,
- boost::bind(&connected, p, _1),
- boost::bind(&connectionError, p, _1),
+ sa,
+ Rdma::ConnectionParams(msgsize, Rdma::DEFAULT_WR_ENTRIES),
+ boost::bind(&connected, p, _1, _2),
+ boost::bind(&connectionError, p, _1, _2),
boost::bind(&disconnected, p, _1),
- boost::bind(&rejected, p, _1));
+ boost::bind(&rejected, p, _1, _2));
c.start(p);
d.run();
diff --git a/cpp/src/qpid/sys/rdma/RdmaIO.cpp b/cpp/src/qpid/sys/rdma/RdmaIO.cpp
index 755d6f17c4..8d06fccba1 100644
--- a/cpp/src/qpid/sys/rdma/RdmaIO.cpp
+++ b/cpp/src/qpid/sys/rdma/RdmaIO.cpp
@@ -1,12 +1,41 @@
-#include "RdmaIO.h"
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/sys/rdma/RdmaIO.h"
+
+#include "qpid/log/Statement.h"
+
#include <iostream>
#include <boost/bind.hpp>
+using qpid::sys::SocketAddress;
+using qpid::sys::DispatchHandle;
+using qpid::sys::Poller;
+
namespace Rdma {
AsynchIO::AsynchIO(
QueuePair::intrusive_ptr q,
- int s,
+ int size,
+ int xCredit,
+ int rCount,
ReadCallback rc,
IdleCallback ic,
FullCallback fc,
@@ -14,10 +43,15 @@ namespace Rdma {
) :
qp(q),
dataHandle(*qp, boost::bind(&AsynchIO::dataEvent, this, _1), 0, 0),
- bufferSize(s),
- recvBufferCount(DEFAULT_WR_ENTRIES),
- xmitBufferCount(DEFAULT_WR_ENTRIES),
+ bufferSize(size),
+ recvCredit(0),
+ xmitCredit(xCredit),
+ recvBufferCount(rCount),
+ xmitBufferCount(xCredit),
outstandingWrites(0),
+ closed(false),
+ deleting(false),
+ state(IDLE),
readCallback(rc),
idleCallback(ic),
fullCallback(fc),
@@ -29,80 +63,281 @@ namespace Rdma {
// Prepost some recv buffers before we go any further
for (int i = 0; i<recvBufferCount; ++i) {
+ // Allocate recv buffer
Buffer* b = qp->createBuffer(bufferSize);
buffers.push_front(b);
b->dataCount = b->byteCount;
qp->postRecv(b);
}
+
+ for (int i = 0; i<xmitBufferCount; ++i) {
+ // Allocate xmit buffer
+ Buffer* b = qp->createBuffer(bufferSize);
+ buffers.push_front(b);
+ bufferQueue.push_front(b);
+ b->dataCount = 0;
+ b->dataStart = 0;
+ }
}
AsynchIO::~AsynchIO() {
+ // Warn if we are deleting whilst there are still unreclaimed write buffers
+ if ( outstandingWrites>0 )
+ QPID_LOG(error, "RDMA: qp=" << qp << ": Deleting queue before all write buffers finished");
+
+ // Turn off callbacks (before doing the deletes)
+ dataHandle.stopWatch();
+
// The buffers ptr_deque automatically deletes all the buffers we've allocated
+ // TODO: It might turn out to be more efficient in high connection loads to reuse the
+ // buffers rather than having to reregister them all the time (this would be straightforward if all
+ // connections haver the same buffer size and harder otherwise)
}
void AsynchIO::start(Poller::shared_ptr poller) {
dataHandle.startWatch(poller);
}
- // TODO: Currently we don't prevent write buffer overrun we just advise
- // when to stop writing.
- void AsynchIO::queueWrite(Buffer* buff) {
- qp->postSend(buff);
- ++outstandingWrites;
- if (outstandingWrites >= xmitBufferCount) {
- fullCallback(*this);
+ // Mark for deletion/Delete this object when we have no outstanding writes
+ void AsynchIO::deferDelete() {
+ State oldState;
+ State newState;
+ bool doReturn;
+ //qpid::sys::ScopedLock<qpid::sys::Mutex> l(stateLock);
+ // It is safe to assign to deleting here as we either delete ourselves
+ // before leaving this function or deleting is set on exit
+ do {
+ newState = oldState = state.get();
+ doReturn = false;
+ if (outstandingWrites > 0 || oldState != IDLE) {
+ deleting = true;
+ doReturn = true;
+ } else{
+ newState = DELETED; // Stop any read callback before the dataHandle.stopWatch() in the destructor
+ }
+ } while (!state.boolCompareAndSwap(oldState, newState));
+ if (doReturn) {
+ return;
}
+ delete this;
}
- void AsynchIO::notifyPendingWrite() {
- // Just perform the idle callback (if possible)
- if (outstandingWrites < xmitBufferCount) {
- idleCallback(*this);
+ void AsynchIO::queueWrite(Buffer* buff) {
+ // Make sure we don't overrun our available buffers
+ // either at our end or the known available at the peers end
+ if (writable()) {
+ // TODO: We might want to batch up sending credit
+ if (recvCredit > 0) {
+ int creditSent = recvCredit & ~FlagsMask;
+ qp->postSend(creditSent, buff);
+ recvCredit -= creditSent;
+ } else {
+ qp->postSend(buff);
+ }
+ ++outstandingWrites;
+ --xmitCredit;
+ } else {
+ if (fullCallback) {
+ fullCallback(*this, buff);
+ } else {
+ QPID_LOG(error, "RDMA: qp=" << qp << ": Write queue full, but no callback, throwing buffer away");
+ returnBuffer(buff);
+ }
}
}
+ // Mark now closed (so we don't accept any more writes or make any idle callbacks)
void AsynchIO::queueWriteClose() {
+ // Don't think we actually need to lock here as transition is 1 way only to closed
+ closed = true;
}
- Buffer* AsynchIO::getBuffer() {
- qpid::sys::ScopedLock<qpid::sys::Mutex> l(bufferQueueLock);
- if (bufferQueue.empty()) {
- Buffer* b = qp->createBuffer(bufferSize);
- buffers.push_front(b);
- b->dataCount = 0;
- return b;
- } else {
- Buffer* b = bufferQueue.front();
- bufferQueue.pop_front();
- b->dataCount = 0;
- b->dataStart = 0;
- return b;
+ void AsynchIO::notifyPendingWrite() {
+ // As notifyPendingWrite can be called on an arbitrary thread it must check whether we are processing or not.
+ // If we are then we just return as we know that we will eventually do the idle callback anyway.
+ //
+ // qpid::sys::ScopedLock<qpid::sys::Mutex> l(stateLock);
+ // We can get here in any state (as the caller could be in any thread)
+ State oldState;
+ State newState;
+ bool doReturn;
+ do {
+ newState = oldState = state.get();
+ doReturn = false;
+ switch (oldState) {
+ case NOTIFY_WRITE:
+ case PENDING_NOTIFY:
+ // We only need to note a pending notify if we're already doing a notify as data processing
+ // is always followed by write notification processing
+ newState = PENDING_NOTIFY;
+ doReturn = true;
+ break;
+ case PENDING_DATA:
+ doReturn = true;
+ break;
+ case DATA:
+ // Only need to return here as data processing will do the idleCallback itself anyway
+ doReturn = true;
+ break;
+ case IDLE:
+ newState = NOTIFY_WRITE;
+ break;
+ case DELETED:
+ assert(oldState!=DELETED);
+ doReturn = true;
+ };
+ } while (!state.boolCompareAndSwap(oldState, newState));
+ if (doReturn) {
+ return;
+ }
+
+ doWriteCallback();
+
+ // Keep track of what we need to do so that we can release the lock
+ enum {COMPLETION, NOTIFY, RETURN, EXIT} action;
+ // If there was pending data whilst we were doing this, process it now
+ //
+ // Using NOTIFY_WRITE for both NOTIFY & COMPLETION is a bit strange, but we're making sure we get the
+ // correct result if we reenter notifyPendingWrite(), in which case we want to
+ // end up in PENDING_NOTIFY (entering dataEvent doesn't matter as it only checks
+ // not IDLE)
+ do {
+ //qpid::sys::ScopedLock<qpid::sys::Mutex> l(stateLock);
+ do {
+ newState = oldState = state.get();
+ action = RETURN; // Anything but COMPLETION
+ switch (oldState) {
+ case NOTIFY_WRITE:
+ newState = IDLE;
+ action = (action == COMPLETION) ? EXIT : RETURN;
+ break;
+ case PENDING_DATA:
+ newState = NOTIFY_WRITE;
+ action = COMPLETION;
+ break;
+ case PENDING_NOTIFY:
+ newState = NOTIFY_WRITE;
+ action = NOTIFY;
+ break;
+ default:
+ assert(oldState!=IDLE && oldState!=DATA && oldState!=DELETED);
+ action = RETURN;
+ }
+ } while (!state.boolCompareAndSwap(oldState, newState));
+
+ // Note we only get here if we were in the PENDING_DATA or PENDING_NOTIFY state
+ // so that we do need to process completions or notifications now
+ switch (action) {
+ case COMPLETION:
+ processCompletions();
+ // Fall through
+ case NOTIFY:
+ doWriteCallback();
+ break;
+ case RETURN:
+ return;
+ case EXIT:
+ // If we just processed completions we might need to delete ourselves
+ if (deleting && outstandingWrites == 0) {
+ delete this;
+ }
+ return;
+ }
+ } while (true);
+ }
+
+ void AsynchIO::dataEvent(qpid::sys::DispatchHandle&) {
+ // Keep track of writable notifications
+ // qpid::sys::ScopedLock<qpid::sys::Mutex> l(stateLock);
+ State oldState;
+ State newState;
+ bool doReturn;
+ do {
+ newState = oldState = state.get();
+ doReturn = false;
+ // We're already processing a notification
+ switch (oldState) {
+ case IDLE:
+ newState = DATA;
+ break;
+ default:
+ // Can't get here in DATA state as that would violate the serialisation rules
+ assert( oldState!=DATA );
+ newState = PENDING_DATA;
+ doReturn = true;
+ }
+ } while (!state.boolCompareAndSwap(oldState, newState));
+ if (doReturn) {
+ return;
}
+ processCompletions();
+
+ //qpid::sys::ScopedLock<qpid::sys::Mutex> l(stateLock);
+ do {
+ newState = oldState = state.get();
+ assert( oldState==DATA );
+ newState = NOTIFY_WRITE;
+ } while (!state.boolCompareAndSwap(oldState, newState));
+
+ do {
+ doWriteCallback();
+
+ // qpid::sys::ScopedLock<qpid::sys::Mutex> l(stateLock);
+ bool doBreak;
+ do {
+ newState = oldState = state.get();
+ doBreak = false;
+ if ( oldState==NOTIFY_WRITE ) {
+ newState = IDLE;
+ doBreak = true;
+ } else {
+ // Can't get DATA/PENDING_DATA here as dataEvent cannot be reentered
+ assert( oldState==PENDING_NOTIFY );
+ newState = NOTIFY_WRITE;
+ }
+ } while (!state.boolCompareAndSwap(oldState, newState));
+ if (doBreak) {
+ break;
+ }
+ } while (true);
+
+ // We might need to delete ourselves
+ if (deleting && outstandingWrites == 0) {
+ delete this;
+ }
}
- void AsynchIO::dataEvent(DispatchHandle&) {
+ void AsynchIO::processCompletions() {
QueuePair::intrusive_ptr q = qp->getNextChannelEvent();
+ // Re-enable notification for queue:
+ // This needs to happen before we could do anything that could generate more work completion
+ // events (ie the callbacks etc. in the following).
+ // This can't make us reenter this code as the handle attached to the completion queue will still be
+ // disabled by the poller until we leave this code
+ qp->notifyRecv();
+ qp->notifySend();
+
+ int recvEvents = 0;
+ int sendEvents = 0;
+
// If no event do nothing
if (!q)
return;
assert(q == qp);
- // Re-enable notification for queue
- qp->notifySend();
- qp->notifyRecv();
-
// Repeat until no more events
do {
QueuePairEvent e(qp->getNextEvent());
if (!e)
- return;
+ break;
::ibv_wc_status status = e.getEventStatus();
if (status != IBV_WC_SUCCESS) {
errorCallback(*this);
+ // TODO: Probably need to flush queues at this point
return;
}
@@ -111,46 +346,143 @@ namespace Rdma {
Buffer* b = e.getBuffer();
QueueDirection dir = e.getDirection();
if (dir == RECV) {
- readCallback(*this, b);
+ ++recvEvents;
+
+ // Get our xmitCredit if it was sent
+ bool dataPresent = true;
+ if (e.immPresent() ) {
+ xmitCredit += (e.getImm() & ~FlagsMask);
+ dataPresent = ((e.getImm() & IgnoreData) == 0);
+ }
+
+ // if there was no data sent then the message was only to update our credit
+ if ( dataPresent ) {
+ readCallback(*this, b);
+ }
+
// At this point the buffer has been consumed so put it back on the recv queue
+ b->dataStart = 0;
+ b->dataCount = 0;
qp->postRecv(b);
+
+ // Received another message
+ ++recvCredit;
+
+ // Send recvCredit if it is large enough (it will have got this large because we've not sent anything recently)
+ if (recvCredit > recvBufferCount/2) {
+ // TODO: This should use RDMA write with imm as there might not ever be a buffer to receive this message
+ // but this is a little unlikely, as to get in this state we have to have received messages without sending any
+ // for a while so its likely we've received an credit update from the far side.
+ if (writable()) {
+ Buffer* ob = getBuffer();
+ // Have to send something as adapters hate it when you try to transfer 0 bytes
+ *reinterpret_cast< uint32_t* >(ob->bytes) = htonl(recvCredit);
+ ob->dataCount = sizeof(uint32_t);
+
+ int creditSent = recvCredit & ~FlagsMask;
+ qp->postSend(creditSent | IgnoreData, ob);
+ recvCredit -= creditSent;
+ ++outstandingWrites;
+ --xmitCredit;
+ } else {
+ QPID_LOG(warning, "RDMA: qp=" << qp << ": Unable to send unsolicited credit");
+ }
+ }
} else {
+ ++sendEvents;
{
qpid::sys::ScopedLock<qpid::sys::Mutex> l(bufferQueueLock);
bufferQueue.push_front(b);
}
--outstandingWrites;
- // TODO: maybe don't call idle unless we're low on write buffers
- idleCallback(*this);
}
} while (true);
+
+ // Not sure if this is expected or not
+ if (recvEvents == 0 && sendEvents == 0) {
+ QPID_LOG(debug, "RDMA: qp=" << qp << ": Got channel event with no recv/send completions");
+ }
+ }
+
+ void AsynchIO::doWriteCallback() {
+ // TODO: maybe don't call idle unless we're low on write buffers
+ // Keep on calling the idle routine as long as we are writable and we got something to write last call
+ while (writable()) {
+ int xc = xmitCredit;
+ idleCallback(*this);
+ // Check whether we actually wrote anything
+ if (xmitCredit == xc) {
+ QPID_LOG(debug, "RDMA: qp=" << qp << ": Called for data, but got none: xmitCredit=" << xmitCredit);
+ return;
+ }
+ }
+ }
+
+ Buffer* AsynchIO::getBuffer() {
+ qpid::sys::ScopedLock<qpid::sys::Mutex> l(bufferQueueLock);
+ assert(!bufferQueue.empty());
+ Buffer* b = bufferQueue.front();
+ bufferQueue.pop_front();
+ b->dataCount = 0;
+ b->dataStart = 0;
+ return b;
+ }
+
+ void AsynchIO::returnBuffer(Buffer* b) {
+ qpid::sys::ScopedLock<qpid::sys::Mutex> l(bufferQueueLock);
+ bufferQueue.push_front(b);
+ b->dataCount = 0;
+ b->dataStart = 0;
+ }
+
+ ConnectionManager::ConnectionManager(
+ ErrorCallback errc,
+ DisconnectedCallback dc
+ ) :
+ ci(Connection::make()),
+ handle(*ci, boost::bind(&ConnectionManager::event, this, _1), 0, 0),
+ errorCallback(errc),
+ disconnectedCallback(dc)
+ {
+ ci->nonblocking();
+ }
+
+ ConnectionManager::~ConnectionManager()
+ {
+ handle.stopWatch();
+ }
+
+ void ConnectionManager::start(Poller::shared_ptr poller) {
+ startConnection(ci);
+ handle.startWatch(poller);
+ }
+
+ void ConnectionManager::event(DispatchHandle&) {
+ connectionEvent(ci);
}
Listener::Listener(
- const sockaddr& src,
- ConnectedCallback cc,
+ const SocketAddress& src,
+ const ConnectionParams& cp,
+ EstablishedCallback ec,
ErrorCallback errc,
DisconnectedCallback dc,
ConnectionRequestCallback crc
) :
+ ConnectionManager(errc, dc),
src_addr(src),
- ci(Connection::make()),
- handle(*ci, boost::bind(&Listener::connectionEvent, this, _1), 0, 0),
- connectedCallback(cc),
- errorCallback(errc),
- disconnectedCallback(dc),
- connectionRequestCallback(crc)
+ checkConnectionParams(cp),
+ connectionRequestCallback(crc),
+ establishedCallback(ec)
{
- ci->nonblocking();
}
- void Listener::start(Poller::shared_ptr poller) {
+ void Listener::startConnection(Connection::intrusive_ptr ci) {
ci->bind(src_addr);
ci->listen();
- handle.startWatch(poller);
}
- void Listener::connectionEvent(DispatchHandle&) {
+ void Listener::connectionEvent(Connection::intrusive_ptr ci) {
ConnectionEvent e(ci->getNextEvent());
// If (for whatever reason) there was no event do nothing
@@ -161,65 +493,75 @@ namespace Rdma {
// you get from CONNECT_REQUEST has the same context info
// as its parent listening rdma_cm_id
::rdma_cm_event_type eventType = e.getEventType();
+ ::rdma_conn_param conn_param = e.getConnectionParam();
Rdma::Connection::intrusive_ptr id = e.getConnection();
switch (eventType) {
case RDMA_CM_EVENT_CONNECT_REQUEST: {
- bool accept = true;
- // Extract connection parameters and private data from event
- ::rdma_conn_param conn_param = e.getConnectionParam();
+ // Make sure peer has sent params we can use
+ if (!conn_param.private_data || conn_param.private_data_len < sizeof(ConnectionParams)) {
+ id->reject();
+ break;
+ }
+ ConnectionParams cp = *static_cast<const ConnectionParams*>(conn_param.private_data);
+
+ // Reject if requested msg size is bigger than we allow
+ if (cp.maxRecvBufferSize > checkConnectionParams.maxRecvBufferSize) {
+ id->reject(&checkConnectionParams);
+ break;
+ }
+ bool accept = true;
if (connectionRequestCallback)
- //TODO: pass private data to callback (and accept new private data for accept somehow)
- accept = connectionRequestCallback(id);
+ accept = connectionRequestCallback(id, cp);
+
if (accept) {
// Accept connection
- id->accept(conn_param);
+ cp.initialXmitCredit = checkConnectionParams.initialXmitCredit;
+ id->accept(conn_param, &cp);
} else {
- //Reject connection
+ // Reject connection
id->reject();
}
-
break;
}
case RDMA_CM_EVENT_ESTABLISHED:
- connectedCallback(id);
+ establishedCallback(id);
break;
case RDMA_CM_EVENT_DISCONNECTED:
disconnectedCallback(id);
break;
case RDMA_CM_EVENT_CONNECT_ERROR:
- errorCallback(id);
+ errorCallback(id, CONNECT_ERROR);
break;
default:
- std::cerr << "Warning: unexpected response to listen - " << eventType << "\n";
+ // Unexpected response
+ errorCallback(id, UNKNOWN);
+ //std::cerr << "Warning: unexpected response to listen - " << eventType << "\n";
}
}
Connector::Connector(
- const sockaddr& dst,
+ const SocketAddress& dst,
+ const ConnectionParams& cp,
ConnectedCallback cc,
ErrorCallback errc,
DisconnectedCallback dc,
RejectedCallback rc
) :
+ ConnectionManager(errc, dc),
dst_addr(dst),
- ci(Connection::make()),
- handle(*ci, boost::bind(&Connector::connectionEvent, this, _1), 0, 0),
- connectedCallback(cc),
- errorCallback(errc),
- disconnectedCallback(dc),
- rejectedCallback(rc)
+ connectionParams(cp),
+ rejectedCallback(rc),
+ connectedCallback(cc)
{
- ci->nonblocking();
}
- void Connector::start(Poller::shared_ptr poller) {
+ void Connector::startConnection(Connection::intrusive_ptr ci) {
ci->resolve_addr(dst_addr);
- handle.startWatch(poller);
}
- void Connector::connectionEvent(DispatchHandle&) {
+ void Connector::connectionEvent(Connection::intrusive_ptr ci) {
ConnectionEvent e(ci->getNextEvent());
// If (for whatever reason) there was no event do nothing
@@ -227,6 +569,8 @@ namespace Rdma {
return;
::rdma_cm_event_type eventType = e.getEventType();
+ ::rdma_conn_param conn_param = e.getConnectionParam();
+ Rdma::Connection::intrusive_ptr id = e.getConnection();
switch (eventType) {
case RDMA_CM_EVENT_ADDR_RESOLVED:
// RESOLVE_ADDR
@@ -234,38 +578,46 @@ namespace Rdma {
break;
case RDMA_CM_EVENT_ADDR_ERROR:
// RESOLVE_ADDR
- errorCallback(ci);
+ errorCallback(ci, ADDR_ERROR);
break;
case RDMA_CM_EVENT_ROUTE_RESOLVED:
// RESOLVE_ROUTE:
- ci->connect();
+ ci->connect(&connectionParams);
break;
case RDMA_CM_EVENT_ROUTE_ERROR:
// RESOLVE_ROUTE:
- errorCallback(ci);
+ errorCallback(ci, ROUTE_ERROR);
break;
case RDMA_CM_EVENT_CONNECT_ERROR:
// CONNECTING
- errorCallback(ci);
+ errorCallback(ci, CONNECT_ERROR);
break;
case RDMA_CM_EVENT_UNREACHABLE:
// CONNECTING
- errorCallback(ci);
+ errorCallback(ci, UNREACHABLE);
break;
- case RDMA_CM_EVENT_REJECTED:
+ case RDMA_CM_EVENT_REJECTED: {
// CONNECTING
- rejectedCallback(ci);
+ // Extract private data from event
+ assert(conn_param.private_data && conn_param.private_data_len >= sizeof(ConnectionParams));
+ ConnectionParams cp = *static_cast<const ConnectionParams*>(conn_param.private_data);
+ rejectedCallback(ci, cp);
break;
- case RDMA_CM_EVENT_ESTABLISHED:
+ }
+ case RDMA_CM_EVENT_ESTABLISHED: {
// CONNECTING
- connectedCallback(ci);
+ // Extract private data from event
+ assert(conn_param.private_data && conn_param.private_data_len >= sizeof(ConnectionParams));
+ ConnectionParams cp = *static_cast<const ConnectionParams*>(conn_param.private_data);
+ connectedCallback(ci, cp);
break;
+ }
case RDMA_CM_EVENT_DISCONNECTED:
// ESTABLISHED
disconnectedCallback(ci);
break;
default:
- std::cerr << "Warning: unexpected event in connect: " << eventType << "\n";
+ QPID_LOG(warning, "RDMA: Unexpected event in connect: " << eventType);
}
}
}
diff --git a/cpp/src/qpid/sys/rdma/RdmaIO.h b/cpp/src/qpid/sys/rdma/RdmaIO.h
index 5c8d49607c..12a1b98d24 100644
--- a/cpp/src/qpid/sys/rdma/RdmaIO.h
+++ b/cpp/src/qpid/sys/rdma/RdmaIO.h
@@ -1,10 +1,33 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
#ifndef Rdma_Acceptor_h
#define Rdma_Acceptor_h
-#include "rdma_wrap.h"
+#include "qpid/sys/rdma/rdma_wrap.h"
+#include "qpid/sys/AtomicValue.h"
#include "qpid/sys/Dispatcher.h"
+#include "qpid/sys/DispatchHandle.h"
#include "qpid/sys/Mutex.h"
+#include "qpid/sys/SocketAddress.h"
#include <netinet/in.h>
@@ -12,32 +35,30 @@
#include <boost/ptr_container/ptr_deque.hpp>
#include <deque>
-using qpid::sys::DispatchHandle;
-using qpid::sys::Poller;
-
namespace Rdma {
class Connection;
- typedef boost::function1<void, Rdma::Connection::intrusive_ptr&> ConnectedCallback;
- typedef boost::function1<void, Rdma::Connection::intrusive_ptr&> ErrorCallback;
- typedef boost::function1<void, Rdma::Connection::intrusive_ptr&> DisconnectedCallback;
- typedef boost::function1<bool, Rdma::Connection::intrusive_ptr&> ConnectionRequestCallback;
- typedef boost::function1<void, Rdma::Connection::intrusive_ptr&> RejectedCallback;
-
class AsynchIO
{
typedef boost::function1<void, AsynchIO&> ErrorCallback;
typedef boost::function2<void, AsynchIO&, Buffer*> ReadCallback;
typedef boost::function1<void, AsynchIO&> IdleCallback;
- typedef boost::function1<void, AsynchIO&> FullCallback;
+ typedef boost::function2<void, AsynchIO&, Buffer*> FullCallback;
QueuePair::intrusive_ptr qp;
- DispatchHandle dataHandle;
+ qpid::sys::DispatchHandleRef dataHandle;
int bufferSize;
+ int recvCredit;
+ int xmitCredit;
int recvBufferCount;
int xmitBufferCount;
int outstandingWrites;
+ bool closed; // TODO: Perhaps (probably) this state can be merged with the following...
+ bool deleting; // TODO: Perhaps (probably) this state can be merged with the following...
+ enum State { IDLE, DATA, PENDING_DATA, NOTIFY_WRITE, PENDING_NOTIFY, DELETED };
+ qpid::sys::AtomicValue<State> state;
+ //qpid::sys::Mutex stateLock;
std::deque<Buffer*> bufferQueue;
qpid::sys::Mutex bufferQueueLock;
boost::ptr_deque<Buffer> buffers;
@@ -48,72 +69,154 @@ namespace Rdma {
ErrorCallback errorCallback;
public:
+ // TODO: Instead of specifying a buffer size specify the amount of memory the AsynchIO class can use
+ // for buffers both read and write (allocate half to each up front) and fail if we cannot allocate that much
+ // locked memory
AsynchIO(
QueuePair::intrusive_ptr q,
- int s,
+ int size,
+ int xCredit,
+ int rCount,
ReadCallback rc,
IdleCallback ic,
FullCallback fc,
ErrorCallback ec
);
- ~AsynchIO();
- void start(Poller::shared_ptr poller);
+ void start(qpid::sys::Poller::shared_ptr poller);
+ bool writable() const;
+ bool bufferAvailable() const;
void queueWrite(Buffer* buff);
void notifyPendingWrite();
void queueWriteClose();
+ void deferDelete();
+ int incompletedWrites() const;
Buffer* getBuffer();
+ void returnBuffer(Buffer*);
private:
- void dataEvent(DispatchHandle& handle);
+ // Don't let anyone else delete us to make sure there can't be outstanding callbacks
+ ~AsynchIO();
+
+ // Constants for the peer-peer command messages
+ // These are sent in the high bits if the imm data of an rdma message
+ // The low bits are used to send the credit
+ const static int FlagsMask = 0x10000000; // Mask for all flag bits - be sure to update this if you add more command bits
+ const static int IgnoreData = 0x10000000; // Message contains no application data
+
+ void dataEvent(qpid::sys::DispatchHandle& handle);
+ void processCompletions();
+ void doWriteCallback();
};
- class Listener
- {
- sockaddr src_addr;
+ inline bool AsynchIO::writable() const {
+ return (!closed && outstandingWrites < xmitBufferCount && xmitCredit > 0);
+ }
+
+ inline int AsynchIO::incompletedWrites() const {
+ return outstandingWrites;
+ }
+
+ inline bool AsynchIO::bufferAvailable() const {
+ return !bufferQueue.empty();
+ }
+ // These are the parameters necessary to start the conversation
+ // * Each peer HAS to allocate buffers of the size of the maximum receive from its peer
+ // * Each peer HAS to know the initial "credit" it has for transmitting to its peer
+ struct ConnectionParams {
+ int maxRecvBufferSize;
+ int initialXmitCredit ;
+
+ ConnectionParams(int s, int c) :
+ maxRecvBufferSize(s),
+ initialXmitCredit(c)
+ {}
+ };
+
+ enum ErrorType {
+ ADDR_ERROR,
+ ROUTE_ERROR,
+ CONNECT_ERROR,
+ UNREACHABLE,
+ UNKNOWN
+ };
+
+ typedef boost::function2<void, Rdma::Connection::intrusive_ptr&, ErrorType> ErrorCallback;
+ typedef boost::function1<void, Rdma::Connection::intrusive_ptr&> DisconnectedCallback;
+
+ class ConnectionManager {
Connection::intrusive_ptr ci;
- DispatchHandle handle;
- ConnectedCallback connectedCallback;
+ qpid::sys::DispatchHandle handle;
+
+ protected:
ErrorCallback errorCallback;
DisconnectedCallback disconnectedCallback;
+
+ public:
+ ConnectionManager(
+ ErrorCallback errc,
+ DisconnectedCallback dc
+ );
+
+ virtual ~ConnectionManager();
+
+ void start(qpid::sys::Poller::shared_ptr poller);
+
+ private:
+ void event(qpid::sys::DispatchHandle& handle);
+
+ virtual void startConnection(Connection::intrusive_ptr ci) = 0;
+ virtual void connectionEvent(Connection::intrusive_ptr ci) = 0;
+ };
+
+ typedef boost::function2<bool, Rdma::Connection::intrusive_ptr&, const ConnectionParams&> ConnectionRequestCallback;
+ typedef boost::function1<void, Rdma::Connection::intrusive_ptr&> EstablishedCallback;
+
+ class Listener : public ConnectionManager
+ {
+ qpid::sys::SocketAddress src_addr;
+ ConnectionParams checkConnectionParams;
ConnectionRequestCallback connectionRequestCallback;
+ EstablishedCallback establishedCallback;
public:
Listener(
- const sockaddr& src,
- ConnectedCallback cc,
+ const qpid::sys::SocketAddress& src,
+ const ConnectionParams& cp,
+ EstablishedCallback ec,
ErrorCallback errc,
DisconnectedCallback dc,
ConnectionRequestCallback crc = 0
);
- void start(Poller::shared_ptr poller);
private:
- void connectionEvent(DispatchHandle& handle);
+ void startConnection(Connection::intrusive_ptr ci);
+ void connectionEvent(Connection::intrusive_ptr ci);
};
- class Connector
+ typedef boost::function2<void, Rdma::Connection::intrusive_ptr&, const ConnectionParams&> RejectedCallback;
+ typedef boost::function2<void, Rdma::Connection::intrusive_ptr&, const ConnectionParams&> ConnectedCallback;
+
+ class Connector : public ConnectionManager
{
- sockaddr dst_addr;
- Connection::intrusive_ptr ci;
- DispatchHandle handle;
- ConnectedCallback connectedCallback;
- ErrorCallback errorCallback;
- DisconnectedCallback disconnectedCallback;
+ qpid::sys::SocketAddress dst_addr;
+ ConnectionParams connectionParams;
RejectedCallback rejectedCallback;
+ ConnectedCallback connectedCallback;
public:
Connector(
- const sockaddr& dst,
+ const qpid::sys::SocketAddress& dst,
+ const ConnectionParams& cp,
ConnectedCallback cc,
ErrorCallback errc,
DisconnectedCallback dc,
RejectedCallback rc = 0
);
- void start(Poller::shared_ptr poller);
private:
- void connectionEvent(DispatchHandle& handle);
+ void startConnection(Connection::intrusive_ptr ci);
+ void connectionEvent(Connection::intrusive_ptr ci);
};
}
diff --git a/cpp/src/qpid/sys/rdma/RdmaServer.cpp b/cpp/src/qpid/sys/rdma/RdmaServer.cpp
index f7f739d6c2..4c11ba23eb 100644
--- a/cpp/src/qpid/sys/rdma/RdmaServer.cpp
+++ b/cpp/src/qpid/sys/rdma/RdmaServer.cpp
@@ -1,4 +1,24 @@
-#include "RdmaIO.h"
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/sys/rdma/RdmaIO.h"
#include <arpa/inet.h>
@@ -15,19 +35,21 @@ using std::string;
using std::cout;
using std::cerr;
+using qpid::sys::SocketAddress;
using qpid::sys::Poller;
using qpid::sys::Dispatcher;
// All the accepted connections
+namespace qpid {
+namespace tests {
+
struct ConRec {
Rdma::Connection::intrusive_ptr connection;
Rdma::AsynchIO* data;
- bool writable;
queue<Rdma::Buffer*> queuedWrites;
ConRec(Rdma::Connection::intrusive_ptr c) :
- connection(c),
- writable(true)
+ connection(c)
{}
};
@@ -35,50 +57,53 @@ void dataError(Rdma::AsynchIO&) {
cout << "Data error:\n";
}
+void idle(ConRec* cr, Rdma::AsynchIO& a) {
+ // Need to make sure full is not called as it would reorder messages
+ while (!cr->queuedWrites.empty() && a.writable()) {
+ Rdma::Buffer* buf = cr->queuedWrites.front();
+ cr->queuedWrites.pop();
+ a.queueWrite(buf);
+ }
+}
+
void data(ConRec* cr, Rdma::AsynchIO& a, Rdma::Buffer* b) {
// Echo data back
Rdma::Buffer* buf = a.getBuffer();
std::copy(b->bytes+b->dataStart, b->bytes+b->dataStart+b->dataCount, buf->bytes);
buf->dataCount = b->dataCount;
- if (cr->queuedWrites.empty() && cr->writable) {
+ if (cr->queuedWrites.empty()) {
+ // If can't write then full will be called and push buffer on back of queue
a.queueWrite(buf);
} else {
cr->queuedWrites.push(buf);
+ // Try to empty queue
+ idle(cr, a);
}
}
-void full(ConRec* cr, Rdma::AsynchIO&) {
- cr->writable = false;
-}
-
-void idle(ConRec* cr, Rdma::AsynchIO& a) {
- cr->writable = true;
- while (!cr->queuedWrites.empty() && cr->writable) {
- Rdma::Buffer* buf = cr->queuedWrites.front();
- cr->queuedWrites.pop();
- a.queueWrite(buf);
- }
+void full(ConRec* cr, Rdma::AsynchIO&, Rdma::Buffer* buf) {
+ cr->queuedWrites.push(buf);
}
void disconnected(Rdma::Connection::intrusive_ptr& ci) {
ConRec* cr = ci->getContext<ConRec>();
cr->connection->disconnect();
- delete cr->data;
+ cr->data->queueWriteClose();
delete cr;
cout << "Disconnected: " << cr << "\n";
}
-void connectionError(Rdma::Connection::intrusive_ptr& ci) {
+void connectionError(Rdma::Connection::intrusive_ptr& ci, Rdma::ErrorType) {
ConRec* cr = ci->getContext<ConRec>();
cr->connection->disconnect();
if (cr) {
- delete cr->data;
+ cr->data->queueWriteClose();
delete cr;
}
cout << "Connection error: " << cr << "\n";
}
-bool connectionRequest(Rdma::Connection::intrusive_ptr& ci) {
+bool connectionRequest(Rdma::Connection::intrusive_ptr& ci, const Rdma::ConnectionParams& cp) {
cout << "Incoming connection: ";
// For fun reject alternate connection attempts
@@ -89,10 +114,11 @@ bool connectionRequest(Rdma::Connection::intrusive_ptr& ci) {
if (x) {
ConRec* cr = new ConRec(ci);
Rdma::AsynchIO* aio =
- new Rdma::AsynchIO(ci->getQueuePair(), 8000,
+ new Rdma::AsynchIO(ci->getQueuePair(),
+ cp.maxRecvBufferSize, cp.initialXmitCredit, Rdma::DEFAULT_WR_ENTRIES,
boost::bind(data, cr, _1, _2),
boost::bind(idle, cr, _1),
- boost::bind(full, cr, _1),
+ boost::bind(full, cr, _1, _2),
dataError);
ci->addContext(cr);
cr->data = aio;
@@ -112,23 +138,23 @@ void connected(Poller::shared_ptr poller, Rdma::Connection::intrusive_ptr& ci) {
cr->data->start(poller);
}
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char* argv[]) {
vector<string> args(&argv[0], &argv[argc]);
- ::sockaddr_in sin;
-
- int port = (args.size() < 2) ? 20079 : atoi(args[1].c_str());
+ std::string port = (args.size() < 2) ? "20079" : args[1];
cout << "Listening on port: " << port << "\n";
- sin.sin_family = AF_INET;
- sin.sin_port = htons(port);
- sin.sin_addr.s_addr = INADDR_ANY;
-
try {
boost::shared_ptr<Poller> p(new Poller());
Dispatcher d(p);
- Rdma::Listener a((const sockaddr&)(sin),
+ SocketAddress sa("", port);
+ Rdma::Listener a(sa,
+ Rdma::ConnectionParams(16384, Rdma::DEFAULT_WR_ENTRIES),
boost::bind(connected, p, _1),
connectionError,
disconnected,
diff --git a/cpp/src/qpid/sys/rdma/rdma_exception.h b/cpp/src/qpid/sys/rdma/rdma_exception.h
index 2773f25917..7867aef2e4 100644
--- a/cpp/src/qpid/sys/rdma/rdma_exception.h
+++ b/cpp/src/qpid/sys/rdma/rdma_exception.h
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
#ifndef RDMA_EXCEPTION_H
#define RDMA_EXCEPTION_H
diff --git a/cpp/src/qpid/sys/rdma/rdma_factories.cpp b/cpp/src/qpid/sys/rdma/rdma_factories.cpp
index 53dc4f8935..a5e9ebd23c 100644
--- a/cpp/src/qpid/sys/rdma/rdma_factories.cpp
+++ b/cpp/src/qpid/sys/rdma/rdma_factories.cpp
@@ -1,4 +1,24 @@
-#include "rdma_factories.h"
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/sys/rdma/rdma_factories.h"
namespace Rdma {
void acker(::rdma_cm_event* e) throw () {
@@ -36,4 +56,9 @@ namespace Rdma {
(void) ::ibv_destroy_cq(cq);
}
+ void destroyQp(::ibv_qp* qp) throw () {
+ if (qp)
+ (void) ::ibv_destroy_qp(qp);
+ }
+
}
diff --git a/cpp/src/qpid/sys/rdma/rdma_factories.h b/cpp/src/qpid/sys/rdma/rdma_factories.h
index 26a93bb494..783181cf1b 100644
--- a/cpp/src/qpid/sys/rdma/rdma_factories.h
+++ b/cpp/src/qpid/sys/rdma/rdma_factories.h
@@ -1,7 +1,27 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
#ifndef RDMA_FACTORIES_H
#define RDMA_FACTORIES_H
-#include "rdma_exception.h"
+#include "qpid/sys/rdma/rdma_exception.h"
#include <rdma/rdma_cma.h>
@@ -15,10 +35,11 @@ namespace Rdma {
void deallocPd(::ibv_pd* p) throw ();
void destroyCChannel(::ibv_comp_channel* c) throw ();
void destroyCq(::ibv_cq* cq) throw ();
+ void destroyQp(::ibv_qp* qp) throw ();
inline boost::shared_ptr< ::rdma_event_channel > mkEChannel() {
- return
- boost::shared_ptr< ::rdma_event_channel >(::rdma_create_event_channel(), destroyEChannel);
+ ::rdma_event_channel* c = CHECK_NULL(::rdma_create_event_channel());
+ return boost::shared_ptr< ::rdma_event_channel >(c, destroyEChannel);
}
inline boost::shared_ptr< ::rdma_cm_id >
diff --git a/cpp/src/qpid/sys/rdma/rdma_wrap.cpp b/cpp/src/qpid/sys/rdma/rdma_wrap.cpp
new file mode 100644
index 0000000000..53e31ca766
--- /dev/null
+++ b/cpp/src/qpid/sys/rdma/rdma_wrap.cpp
@@ -0,0 +1,185 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/rdma/rdma_wrap.h"
+
+namespace Rdma {
+ const ::rdma_conn_param DEFAULT_CONNECT_PARAM = {
+ 0, // .private_data
+ 0, // .private_data_len
+ 4, // .responder_resources
+ 4, // .initiator_depth
+ 0, // .flow_control
+ 5, // .retry_count
+ 7 // .rnr_retry_count
+ };
+
+ // This is moderately inefficient so don't use in a critical path
+ int deviceCount() {
+ int count;
+ ::ibv_free_device_list(::ibv_get_device_list(&count));
+ return count;
+ }
+
+ ::rdma_conn_param ConnectionEvent::getConnectionParam() const {
+ // It's badly documented, but it seems from the librdma source code that all the following
+ // event types have a valid param.conn
+ switch (event->event) {
+ case RDMA_CM_EVENT_CONNECT_REQUEST:
+ case RDMA_CM_EVENT_ESTABLISHED:
+ case RDMA_CM_EVENT_REJECTED:
+ case RDMA_CM_EVENT_DISCONNECTED:
+ case RDMA_CM_EVENT_CONNECT_ERROR:
+ return event->param.conn;
+ default:
+ ::rdma_conn_param p = {};
+ return p;
+ }
+ }
+
+ QueuePair::QueuePair(boost::shared_ptr< ::rdma_cm_id > i) :
+ qpid::sys::IOHandle(new qpid::sys::IOHandlePrivate),
+ pd(allocPd(i->verbs)),
+ cchannel(mkCChannel(i->verbs)),
+ scq(mkCq(i->verbs, DEFAULT_CQ_ENTRIES, 0, cchannel.get())),
+ rcq(mkCq(i->verbs, DEFAULT_CQ_ENTRIES, 0, cchannel.get())),
+ outstandingSendEvents(0),
+ outstandingRecvEvents(0)
+ {
+ impl->fd = cchannel->fd;
+
+ // Set cq context to this QueuePair object so we can find
+ // ourselves again
+ scq->cq_context = this;
+ rcq->cq_context = this;
+
+ ::ibv_qp_init_attr qp_attr = {};
+
+ // TODO: make a default struct for this
+ qp_attr.cap.max_send_wr = DEFAULT_WR_ENTRIES;
+ qp_attr.cap.max_send_sge = 4;
+ qp_attr.cap.max_recv_wr = DEFAULT_WR_ENTRIES;
+ qp_attr.cap.max_recv_sge = 4;
+
+ qp_attr.send_cq = scq.get();
+ qp_attr.recv_cq = rcq.get();
+ qp_attr.qp_type = IBV_QPT_RC;
+
+ CHECK(::rdma_create_qp(i.get(), pd.get(), &qp_attr));
+ qp = boost::shared_ptr< ::ibv_qp >(i->qp, destroyQp);
+
+ // Set the qp context to this so we can find ourselves again
+ qp->qp_context = this;
+ }
+
+ QueuePair::~QueuePair() {
+ if (outstandingSendEvents > 0)
+ ::ibv_ack_cq_events(scq.get(), outstandingSendEvents);
+ if (outstandingRecvEvents > 0)
+ ::ibv_ack_cq_events(rcq.get(), outstandingRecvEvents);
+
+ // Reset back pointer in case someone else has the qp
+ qp->qp_context = 0;
+ }
+
+ void QueuePair::postRecv(Buffer* buf) {
+ ::ibv_recv_wr rwr = {};
+ ::ibv_sge sge;
+
+ sge.addr = (uintptr_t) buf->bytes+buf->dataStart;
+ sge.length = buf->dataCount;
+ sge.lkey = buf->mr->lkey;
+
+ rwr.wr_id = reinterpret_cast<uint64_t>(buf);
+ rwr.sg_list = &sge;
+ rwr.num_sge = 1;
+
+ ::ibv_recv_wr* badrwr = 0;
+ CHECK_IBV(::ibv_post_recv(qp.get(), &rwr, &badrwr));
+ if (badrwr)
+ throw std::logic_error("ibv_post_recv(): Bad rwr");
+ }
+
+ void QueuePair::postSend(Buffer* buf) {
+ ::ibv_send_wr swr = {};
+ ::ibv_sge sge;
+
+ sge.addr = (uintptr_t) buf->bytes+buf->dataStart;
+ sge.length = buf->dataCount;
+ sge.lkey = buf->mr->lkey;
+
+ swr.wr_id = reinterpret_cast<uint64_t>(buf);
+ swr.opcode = IBV_WR_SEND;
+ swr.send_flags = IBV_SEND_SIGNALED;
+ swr.sg_list = &sge;
+ swr.num_sge = 1;
+
+ ::ibv_send_wr* badswr = 0;
+ CHECK_IBV(::ibv_post_send(qp.get(), &swr, &badswr));
+ if (badswr)
+ throw std::logic_error("ibv_post_send(): Bad swr");
+ }
+
+ void QueuePair::postSend(uint32_t imm, Buffer* buf) {
+ ::ibv_send_wr swr = {};
+ ::ibv_sge sge;
+
+ sge.addr = (uintptr_t) buf->bytes+buf->dataStart;
+ sge.length = buf->dataCount;
+ sge.lkey = buf->mr->lkey;
+ swr.send_flags = IBV_SEND_SIGNALED;
+
+ swr.wr_id = reinterpret_cast<uint64_t>(buf);
+ swr.imm_data = htonl(imm);
+ swr.opcode = IBV_WR_SEND_WITH_IMM;
+ swr.sg_list = &sge;
+ swr.num_sge = 1;
+
+ ::ibv_send_wr* badswr = 0;
+ CHECK_IBV(::ibv_post_send(qp.get(), &swr, &badswr));
+ if (badswr)
+ throw std::logic_error("ibv_post_send(): Bad swr");
+ }
+}
+
+std::ostream& operator<<(std::ostream& o, ::rdma_cm_event_type t) {
+# define CHECK_TYPE(t) case t: o << #t; break;
+ switch(t) {
+ CHECK_TYPE(RDMA_CM_EVENT_ADDR_RESOLVED)
+ CHECK_TYPE(RDMA_CM_EVENT_ADDR_ERROR)
+ CHECK_TYPE(RDMA_CM_EVENT_ROUTE_RESOLVED)
+ CHECK_TYPE(RDMA_CM_EVENT_ROUTE_ERROR)
+ CHECK_TYPE(RDMA_CM_EVENT_CONNECT_REQUEST)
+ CHECK_TYPE(RDMA_CM_EVENT_CONNECT_RESPONSE)
+ CHECK_TYPE(RDMA_CM_EVENT_CONNECT_ERROR)
+ CHECK_TYPE(RDMA_CM_EVENT_UNREACHABLE)
+ CHECK_TYPE(RDMA_CM_EVENT_REJECTED)
+ CHECK_TYPE(RDMA_CM_EVENT_ESTABLISHED)
+ CHECK_TYPE(RDMA_CM_EVENT_DISCONNECTED)
+ CHECK_TYPE(RDMA_CM_EVENT_DEVICE_REMOVAL)
+ CHECK_TYPE(RDMA_CM_EVENT_MULTICAST_JOIN)
+ CHECK_TYPE(RDMA_CM_EVENT_MULTICAST_ERROR)
+ default:
+ o << "UNKNOWN_EVENT";
+ }
+# undef CHECK_TYPE
+ return o;
+}
diff --git a/cpp/src/qpid/sys/rdma/rdma_wrap.h b/cpp/src/qpid/sys/rdma/rdma_wrap.h
index 421c8fc41b..e11497dc02 100644
--- a/cpp/src/qpid/sys/rdma/rdma_wrap.h
+++ b/cpp/src/qpid/sys/rdma/rdma_wrap.h
@@ -1,7 +1,27 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
#ifndef RDMA_WRAP_H
#define RDMA_WRAP_H
-#include "rdma_factories.h"
+#include "qpid/sys/rdma/rdma_factories.h"
#include <rdma/rdma_cma.h>
@@ -11,6 +31,8 @@
#include <fcntl.h>
+#include <netdb.h>
+
#include <vector>
#include <algorithm>
#include <iostream>
@@ -23,15 +45,9 @@ namespace Rdma {
const int DEFAULT_BACKLOG = 100;
const int DEFAULT_CQ_ENTRIES = 256;
const int DEFAULT_WR_ENTRIES = 64;
- const ::rdma_conn_param DEFAULT_CONNECT_PARAM = {
- 0, // .private_data
- 0, // .private_data_len
- 4, // .responder_resources
- 4, // .initiator_depth
- 0, // .flow_control
- 5, // .retry_count
- 7 // .rnr_retry_count
- };
+ extern const ::rdma_conn_param DEFAULT_CONNECT_PARAM;
+
+ int deviceCount();
struct Buffer {
friend class QueuePair;
@@ -95,6 +111,14 @@ namespace Rdma {
return dir != NONE;
}
+ bool immPresent() const {
+ return wc.wc_flags & IBV_WC_WITH_IMM;
+ }
+
+ uint32_t getImm() const {
+ return ntohl(wc.imm_data);
+ }
+
QueueDirection getDirection() const {
return dir;
}
@@ -117,15 +141,12 @@ namespace Rdma {
// Wrapper for a queue pair - this has the functionality for
// putting buffers on the receive queue and for sending buffers
// to the other end of the connection.
- //
- // Currently QueuePairs are contained inside Connections and have no
- // separate lifetime
class QueuePair : public qpid::sys::IOHandle, public qpid::RefCounted {
boost::shared_ptr< ::ibv_pd > pd;
boost::shared_ptr< ::ibv_comp_channel > cchannel;
boost::shared_ptr< ::ibv_cq > scq;
boost::shared_ptr< ::ibv_cq > rcq;
- boost::shared_ptr< ::rdma_cm_id > id;
+ boost::shared_ptr< ::ibv_qp > qp;
int outstandingSendEvents;
int outstandingRecvEvents;
@@ -187,6 +208,7 @@ namespace Rdma {
void postRecv(Buffer* buf);
void postSend(Buffer* buf);
+ void postSend(uint32_t imm, Buffer* buf);
void notifyRecv();
void notifySend();
};
@@ -213,14 +235,7 @@ namespace Rdma {
return event->event;
}
- ::rdma_conn_param getConnectionParam() const {
- if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST) {
- return event->param.conn;
- } else {
- ::rdma_conn_param p = {};
- return p;
- }
- }
+ ::rdma_conn_param getConnectionParam() const;
boost::intrusive_ptr<Connection> getConnection () const {
return id;
@@ -271,6 +286,11 @@ namespace Rdma {
impl->fd = channel->fd;
}
+ ~Connection() {
+ // Reset the id context in case someone else has it
+ id->context = 0;
+ }
+
// Default destructor fine
void ensureQueuePair() {
@@ -330,9 +350,9 @@ namespace Rdma {
return ConnectionEvent(e);
}
- void bind(sockaddr& src_addr) const {
+ void bind(qpid::sys::SocketAddress& src_addr) const {
assert(id.get());
- CHECK(::rdma_bind_addr(id.get(), &src_addr));
+ CHECK(::rdma_bind_addr(id.get(), getAddrInfo(src_addr).ai_addr));
}
void listen(int backlog = DEFAULT_BACKLOG) const {
@@ -341,12 +361,11 @@ namespace Rdma {
}
void resolve_addr(
- sockaddr& dst_addr,
- sockaddr* src_addr = 0,
+ qpid::sys::SocketAddress& dst_addr,
int timeout_ms = DEFAULT_TIMEOUT) const
{
assert(id.get());
- CHECK(::rdma_resolve_addr(id.get(), src_addr, &dst_addr, timeout_ms));
+ CHECK(::rdma_resolve_addr(id.get(), 0, getAddrInfo(dst_addr).ai_addr, timeout_ms));
}
void resolve_route(int timeout_ms = DEFAULT_TIMEOUT) const {
@@ -425,52 +444,38 @@ namespace Rdma {
return qp;
}
+
+ std::string getLocalName() const {
+ ::sockaddr* addr = ::rdma_get_local_addr(id.get());
+ char hostName[NI_MAXHOST];
+ char portName[NI_MAXSERV];
+ CHECK_IBV(::getnameinfo(
+ addr, sizeof(::sockaddr_storage),
+ hostName, sizeof(hostName),
+ portName, sizeof(portName),
+ NI_NUMERICHOST | NI_NUMERICSERV));
+ std::string r(hostName);
+ r += ":";
+ r += portName;
+ return r;
+ }
+
+ std::string getPeerName() const {
+ ::sockaddr* addr = ::rdma_get_peer_addr(id.get());
+ char hostName[NI_MAXHOST];
+ char portName[NI_MAXSERV];
+ CHECK_IBV(::getnameinfo(
+ addr, sizeof(::sockaddr_storage),
+ hostName, sizeof(hostName),
+ portName, sizeof(portName),
+ NI_NUMERICHOST | NI_NUMERICSERV));
+ std::string r(hostName);
+ r += ":";
+ r += portName;
+ return r;
+ }
};
- inline QueuePair::QueuePair(boost::shared_ptr< ::rdma_cm_id > i) :
- qpid::sys::IOHandle(new qpid::sys::IOHandlePrivate),
- pd(allocPd(i->verbs)),
- cchannel(mkCChannel(i->verbs)),
- scq(mkCq(i->verbs, DEFAULT_CQ_ENTRIES, 0, cchannel.get())),
- rcq(mkCq(i->verbs, DEFAULT_CQ_ENTRIES, 0, cchannel.get())),
- id(i),
- outstandingSendEvents(0),
- outstandingRecvEvents(0)
- {
- impl->fd = cchannel->fd;
-
- // Set cq context to this QueuePair object so we can find
- // ourselves again
- scq->cq_context = this;
- rcq->cq_context = this;
-
- ::ibv_qp_init_attr qp_attr = {};
-
- // TODO: make a default struct for this
- qp_attr.cap.max_send_wr = DEFAULT_WR_ENTRIES;
- qp_attr.cap.max_send_sge = 4;
- qp_attr.cap.max_recv_wr = DEFAULT_WR_ENTRIES;
- qp_attr.cap.max_recv_sge = 4;
-
- qp_attr.send_cq = scq.get();
- qp_attr.recv_cq = rcq.get();
- qp_attr.qp_type = IBV_QPT_RC;
-
- CHECK(::rdma_create_qp(id.get(), pd.get(), &qp_attr));
-
- // Set the qp context to this so we can find ourselves again
- id->qp->qp_context = this;
- }
-
- inline QueuePair::~QueuePair() {
- if (outstandingSendEvents > 0)
- ::ibv_ack_cq_events(scq.get(), outstandingSendEvents);
- if (outstandingRecvEvents > 0)
- ::ibv_ack_cq_events(rcq.get(), outstandingRecvEvents);
-
- ::rdma_destroy_qp(id.get());
- }
-
inline void QueuePair::notifyRecv() {
CHECK_IBV(ibv_req_notify_cq(rcq.get(), 0));
}
@@ -479,44 +484,6 @@ namespace Rdma {
CHECK_IBV(ibv_req_notify_cq(scq.get(), 0));
}
- inline void QueuePair::postRecv(Buffer* buf) {
- ::ibv_recv_wr rwr = {};
- ::ibv_sge sge;
-
- sge.addr = (uintptr_t) buf->bytes+buf->dataStart;
- sge.length = buf->dataCount;
- sge.lkey = buf->mr->lkey;
-
- rwr.wr_id = reinterpret_cast<uint64_t>(buf);
- rwr.sg_list = &sge;
- rwr.num_sge = 1;
-
- ::ibv_recv_wr* badrwr = 0;
- CHECK_IBV(::ibv_post_recv(id->qp, &rwr, &badrwr));
- if (badrwr)
- throw std::logic_error("ibv_post_recv(): Bad rwr");
- }
-
- inline void QueuePair::postSend(Buffer* buf) {
- ::ibv_send_wr swr = {};
- ::ibv_sge sge;
-
- sge.addr = (uintptr_t) buf->bytes+buf->dataStart;
- sge.length = buf->dataCount;
- sge.lkey = buf->mr->lkey;
-
- swr.wr_id = reinterpret_cast<uint64_t>(buf);
- swr.opcode = IBV_WR_SEND;
- swr.send_flags = IBV_SEND_SIGNALED;
- swr.sg_list = &sge;
- swr.num_sge = 1;
-
- ::ibv_send_wr* badswr = 0;
- CHECK_IBV(::ibv_post_send(id->qp, &swr, &badswr));
- if (badswr)
- throw std::logic_error("ibv_post_send(): Bad swr");
- }
-
inline ConnectionEvent::ConnectionEvent(::rdma_cm_event* e) :
id((e->event != RDMA_CM_EVENT_CONNECT_REQUEST) ?
Connection::find(e->id) : new Connection(e->id)),
@@ -525,26 +492,6 @@ namespace Rdma {
{}
}
-inline std::ostream& operator<<(std::ostream& o, ::rdma_cm_event_type t) {
-# define CHECK_TYPE(t) case t: o << #t; break;
- switch(t) {
- CHECK_TYPE(RDMA_CM_EVENT_ADDR_RESOLVED)
- CHECK_TYPE(RDMA_CM_EVENT_ADDR_ERROR)
- CHECK_TYPE(RDMA_CM_EVENT_ROUTE_RESOLVED)
- CHECK_TYPE(RDMA_CM_EVENT_ROUTE_ERROR)
- CHECK_TYPE(RDMA_CM_EVENT_CONNECT_REQUEST)
- CHECK_TYPE(RDMA_CM_EVENT_CONNECT_RESPONSE)
- CHECK_TYPE(RDMA_CM_EVENT_CONNECT_ERROR)
- CHECK_TYPE(RDMA_CM_EVENT_UNREACHABLE)
- CHECK_TYPE(RDMA_CM_EVENT_REJECTED)
- CHECK_TYPE(RDMA_CM_EVENT_ESTABLISHED)
- CHECK_TYPE(RDMA_CM_EVENT_DISCONNECTED)
- CHECK_TYPE(RDMA_CM_EVENT_DEVICE_REMOVAL)
- CHECK_TYPE(RDMA_CM_EVENT_MULTICAST_JOIN)
- CHECK_TYPE(RDMA_CM_EVENT_MULTICAST_ERROR)
- }
-# undef CHECK_TYPE
- return o;
-}
+std::ostream& operator<<(std::ostream& o, ::rdma_cm_event_type t);
#endif // RDMA_WRAP_H
diff --git a/cpp/src/qpid/sys/solaris/ECFPoller.cpp b/cpp/src/qpid/sys/solaris/ECFPoller.cpp
index fefa21dae1..f12012cbb0 100644
--- a/cpp/src/qpid/sys/solaris/ECFPoller.cpp
+++ b/cpp/src/qpid/sys/solaris/ECFPoller.cpp
@@ -30,9 +30,11 @@
#include <port.h>
#include <poll.h>
#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
#include <assert.h>
-#include <vector>
+#include <queue>
#include <exception>
@@ -43,11 +45,11 @@ namespace qpid {
namespace sys {
// Deletion manager to handle deferring deletion of PollerHandles to when they definitely aren't being used
-DeletionManager<PollerHandle> PollerHandleDeletionManager;
+DeletionManager<PollerHandlePrivate> PollerHandleDeletionManager;
// Instantiate (and define) class static for DeletionManager
template <>
-DeletionManager<PollerHandle>::AllThreadsStatuses DeletionManager<PollerHandle>::allThreadsStatuses(0);
+DeletionManager<PollerHandlePrivate>::AllThreadsStatuses DeletionManager<PollerHandlePrivate>::allThreadsStatuses(0);
class PollerHandlePrivate {
friend class Poller;
@@ -58,7 +60,8 @@ class PollerHandlePrivate {
MONITORED,
INACTIVE,
HUNGUP,
- MONITORED_HUNGUP
+ MONITORED_HUNGUP,
+ DELETED
};
int fd;
@@ -104,6 +107,14 @@ class PollerHandlePrivate {
assert(stat == MONITORED);
stat = HUNGUP;
}
+
+ bool isDeleted() const {
+ return stat == DELETED;
+ }
+
+ void setDeleted() {
+ stat = DELETED;
+ }
};
PollerHandle::PollerHandle(const IOHandle& h) :
@@ -111,11 +122,16 @@ PollerHandle::PollerHandle(const IOHandle& h) :
{}
PollerHandle::~PollerHandle() {
- delete impl;
-}
-
-void PollerHandle::deferDelete() {
- PollerHandleDeletionManager.markForDeletion(this);
+ {
+ ScopedLock<Mutex> l(impl->lock);
+ if (impl->isDeleted()) {
+ return;
+ }
+ if (impl->isActive()) {
+ impl->setDeleted();
+ }
+ }
+ PollerHandleDeletionManager.markForDeletion(impl);
}
/**
@@ -125,35 +141,82 @@ void PollerHandle::deferDelete() {
class PollerPrivate {
friend class Poller;
- const int portId;
+ class InterruptHandle: public PollerHandle {
+ std::queue<PollerHandle*> handles;
+
+ void processEvent(Poller::EventType) {
+ PollerHandle* handle = handles.front();
+ handles.pop();
+ assert(handle);
+
+ //Synthesise event
+ Poller::Event event(handle, Poller::INTERRUPTED);
+
+ //Process synthesised event
+ event.process();
+ }
+ public:
+ InterruptHandle() : PollerHandle(DummyIOHandle) {}
+
+ void addHandle(PollerHandle& h) {
+ handles.push(&h);
+ }
+
+ PollerHandle *getHandle() {
+ PollerHandle* handle = handles.front();
+ handles.pop();
+ return handle;
+ }
+
+ bool queuedHandles() {
+ return handles.size() > 0;
+ }
+ };
+
+ const int portId;
+ bool isShutdown;
+ InterruptHandle interruptHandle;
+
static uint32_t directionToPollEvent(Poller::Direction dir) {
switch (dir) {
- case Poller::IN: return POLLIN;
- case Poller::OUT: return POLLOUT;
- case Poller::INOUT: return POLLIN | POLLOUT;
- default: return 0;
+ case Poller::INPUT: return POLLIN;
+ case Poller::OUTPUT: return POLLOUT;
+ case Poller::INOUT: return POLLIN | POLLOUT;
+ default: return 0;
}
}
static Poller::EventType pollToDirection(uint32_t events) {
uint32_t e = events & (POLLIN | POLLOUT);
switch (e) {
- case POLLIN: return Poller::READABLE;
- case POLLOUT: return Poller::WRITABLE;
- case POLLIN | POLLOUT: return Poller::READ_WRITABLE;
- default:
- return (events & (POLLHUP | POLLERR)) ?
- Poller::DISCONNECTED : Poller::INVALID;
+ case POLLIN: return Poller::READABLE;
+ case POLLOUT: return Poller::WRITABLE;
+ case POLLIN | POLLOUT: return Poller::READ_WRITABLE;
+ default:
+ return (events & (POLLHUP | POLLERR)) ?
+ Poller::DISCONNECTED : Poller::INVALID;
}
}
-
+
PollerPrivate() :
- portId(::port_create()) {
+ portId(::port_create()),
+ isShutdown(false) {
+ QPID_POSIX_CHECK(portId);
+ QPID_LOG(trace, "port_create returned port Id: " << portId);
}
~PollerPrivate() {
}
+
+ void interrupt() {
+ //Send an Alarm to the port
+ //We need to send a nonzero event mask, using POLLHUP,
+ //nevertheless the wait method will only look for a PORT_ALERT_SET
+ QPID_LOG(trace, "Sending a port_alert to " << portId);
+ QPID_POSIX_CHECK(::port_alert(portId, PORT_ALERT_SET, POLLHUP,
+ &static_cast<PollerHandle&>(interruptHandle)));
+ }
};
void Poller::addFd(PollerHandle& handle, Direction dir) {
@@ -177,7 +240,6 @@ void Poller::addFd(PollerHandle& handle, Direction dir) {
QPID_LOG(trace, "Poller::addFd(handle=" << &handle
<< "[" << typeid(&handle).name()
<< "], fd=" << eh.fd << ")");
- //assert(dynamic_cast<DispatchHandle*>(&handle));
}
void Poller::delFd(PollerHandle& handle) {
@@ -223,17 +285,56 @@ void Poller::rearmFd(PollerHandle& handle) {
}
void Poller::shutdown() {
- //Send an Alarm to the port
- //We need to send a nonzero event mask, using POLLHUP, but
- //The wait method will only look for a PORT_ALERT_SET
- QPID_POSIX_CHECK(::port_alert(impl->portId, PORT_ALERT_SET, POLLHUP, NULL));
- QPID_LOG(trace, "Poller::shutdown");
+ //Allow sloppy code to shut us down more than once
+ if (impl->isShutdown)
+ return;
+
+ impl->isShutdown = true;
+ impl->interrupt();
+}
+
+bool Poller::interrupt(PollerHandle& handle) {
+ PollerPrivate::InterruptHandle& ih = impl->interruptHandle;
+ PollerHandlePrivate& eh = *static_cast<PollerHandle&>(ih).impl;
+ ScopedLock<Mutex> l(eh.lock);
+ ih.addHandle(handle);
+ impl->interrupt();
+ eh.setActive();
+ return true;
+}
+
+void Poller::run() {
+ // Make sure we can't be interrupted by signals at a bad time
+ ::sigset_t ss;
+ ::sigfillset(&ss);
+ ::pthread_sigmask(SIG_SETMASK, &ss, 0);
+
+ do {
+ Event event = wait();
+
+ // If can read/write then dispatch appropriate callbacks
+ if (event.handle) {
+ event.process();
+ } else {
+ // Handle shutdown
+ switch (event.type) {
+ case SHUTDOWN:
+ return;
+ default:
+ // This should be impossible
+ assert(false);
+ }
+ }
+ } while (true);
}
Poller::Event Poller::wait(Duration timeout) {
timespec_t tout;
timespec_t* ptout = NULL;
port_event_t pe;
+
+ AbsTime targetTimeout = (timeout == TIME_INFINITE) ? FAR_FUTURE :
+ AbsTime(now(), timeout);
if (timeout != TIME_INFINITE) {
tout.tv_sec = 0;
@@ -243,12 +344,21 @@ Poller::Event Poller::wait(Duration timeout) {
do {
PollerHandleDeletionManager.markAllUnusedInThisThread();
- QPID_LOG(trace, "About to enter port_get. Thread "
- << pthread_self()
+ QPID_LOG(trace, "About to enter port_get on " << impl->portId
+ << ". Thread " << pthread_self()
<< ", timeout=" << timeout);
-
+
+
int rc = ::port_get(impl->portId, &pe, ptout);
+ QPID_LOG(trace, "port_get on " << impl->portId
+ << " returned " << rc);
+
+ if (impl->isShutdown) {
+ PollerHandleDeletionManager.markAllUnusedInThisThread();
+ return Event(0, SHUTDOWN);
+ }
+
if (rc < 0) {
switch (errno) {
case EINTR:
@@ -259,33 +369,61 @@ Poller::Event Poller::wait(Duration timeout) {
QPID_POSIX_CHECK(rc);
}
} else {
- //We use alert mode to notify the shutdown of the Poller
- if (pe.portev_source == PORT_SOURCE_ALERT) {
- return Event(0, SHUTDOWN);
- }
- if (pe.portev_source == PORT_SOURCE_FD) {
- PollerHandle *handle = static_cast<PollerHandle*>(pe.portev_user);
- PollerHandlePrivate& eh = *handle->impl;
- ScopedLock<Mutex> l(eh.lock);
- QPID_LOG(trace, "About to send handle: " << handle);
+ PollerHandle* handle = static_cast<PollerHandle*>(pe.portev_user);
+ PollerHandlePrivate& eh = *handle->impl;
+ ScopedLock<Mutex> l(eh.lock);
+
+ if (eh.isActive()) {
+ QPID_LOG(trace, "Handle is active");
+ //We use alert mode to notify interrupts
+ if (pe.portev_source == PORT_SOURCE_ALERT &&
+ handle == &impl->interruptHandle) {
+ QPID_LOG(trace, "Interrupt notified");
+
+ PollerHandle* wrappedHandle = impl->interruptHandle.getHandle();
+
+ if (impl->interruptHandle.queuedHandles()) {
+ impl->interrupt();
+ eh.setActive();
+ } else {
+ eh.setInactive();
+ }
+ return Event(wrappedHandle, INTERRUPTED);
+ }
- if (eh.isActive()) {
- if (pe.portev_events & POLLHUP) {
- if (eh.isHungup()) {
- return Event(handle, DISCONNECTED);
+ if (pe.portev_source == PORT_SOURCE_FD) {
+ QPID_LOG(trace, "About to send handle: " << handle);
+ if (pe.portev_events & POLLHUP) {
+ if (eh.isHungup()) {
+ return Event(handle, DISCONNECTED);
+ }
+ eh.setHungup();
+ } else {
+ eh.setInactive();
}
- eh.setHungup();
- } else {
- eh.setInactive();
- }
- QPID_LOG(trace, "Sending event (thread: "
- << pthread_self() << ") for handle " << handle
- << ", direction= "
- << PollerPrivate::pollToDirection(pe.portev_events));
- return Event(handle, PollerPrivate::pollToDirection(pe.portev_events));
+ QPID_LOG(trace, "Sending event (thread: "
+ << pthread_self() << ") for handle " << handle
+ << ", direction= "
+ << PollerPrivate::pollToDirection(pe.portev_events));
+ return Event(handle, PollerPrivate::pollToDirection(pe.portev_events));
+ }
+ } else if (eh.isDeleted()) {
+ //Remove the handle from the poller
+ int rc = ::port_dissociate(impl->portId, PORT_SOURCE_FD,
+ (uintptr_t) eh.fd);
+ if (rc == -1 && errno != EBADFD) {
+ QPID_POSIX_CHECK(rc);
}
}
}
+
+ if (timeout == TIME_INFINITE) {
+ continue;
+ }
+ if (rc == 0 && now() > targetTimeout) {
+ PollerHandleDeletionManager.markAllUnusedInThisThread();
+ return Event(0, TIMEOUT);
+ }
} while (true);
}
diff --git a/cpp/src/qpid/sys/solaris/SystemInfo.cpp b/cpp/src/qpid/sys/solaris/SystemInfo.cpp
new file mode 100755
index 0000000000..0075a89021
--- /dev/null
+++ b/cpp/src/qpid/sys/solaris/SystemInfo.cpp
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/sys/SystemInfo.h"
+
+#define BSD_COMP
+#include <sys/ioctl.h>
+#include <netdb.h>
+#undef BDS_COMP
+
+
+#include <unistd.h>
+#include <net/if.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <errno.h>
+#include <limits.h>
+#include <procfs.h>
+#include <fcntl.h>
+#include <sys/types.h>
+
+using namespace std;
+
+namespace qpid {
+namespace sys {
+
+long SystemInfo::concurrency() {
+ return sysconf(_SC_NPROCESSORS_ONLN);
+}
+
+bool SystemInfo::getLocalHostname(TcpAddress &address) {
+ char name[MAXHOSTNAMELEN];
+ if (::gethostname(name, sizeof(name)) != 0)
+ return false;
+ address.host = name;
+ return true;
+}
+
+static const string LOCALHOST("127.0.0.1");
+
+void SystemInfo::getLocalIpAddresses(uint16_t port,
+ std::vector<Address> &addrList) {
+ int s = socket(PF_INET, SOCK_STREAM, 0);
+ for (int i=1;;i++) {
+ struct lifreq ifr;
+ ifr.lifr_index = i;
+ if (::ioctl(s, SIOCGIFADDR, &ifr) < 0) {
+ break;
+ }
+ struct sockaddr_in *sin = (struct sockaddr_in *) &ifr.lifr_addr;
+ std::string addr(inet_ntoa(sin->sin_addr));
+ if (addr != LOCALHOST)
+ addrList.push_back(TcpAddress(addr, port));
+ }
+ if (addrList.empty()) {
+ addrList.push_back(TcpAddress(LOCALHOST, port));
+ }
+ close (s);
+}
+
+void SystemInfo::getSystemId(std::string &osName,
+ std::string &nodeName,
+ std::string &release,
+ std::string &version,
+ std::string &machine) {
+ struct utsname _uname;
+ if (uname (&_uname) == 0) {
+ osName = _uname.sysname;
+ nodeName = _uname.nodename;
+ release = _uname.release;
+ version = _uname.version;
+ machine = _uname.machine;
+ }
+}
+
+uint32_t SystemInfo::getProcessId()
+{
+ return (uint32_t) ::getpid();
+}
+
+uint32_t SystemInfo::getParentProcessId()
+{
+ return (uint32_t) ::getppid();
+}
+
+string SystemInfo::getProcessName()
+{
+ psinfo processInfo;
+ char procfile[PATH_MAX];
+ int fd;
+ string value;
+
+ snprintf(procfile, PATH_MAX, "/proc/%d/psinfo", getProcessId());
+ if ((fd = open(procfile, O_RDONLY)) >= 0) {
+ if (read(fd, (void *) &processInfo, sizeof(processInfo)) == sizeof(processInfo)) {
+ value = processInfo.pr_fname;
+ }
+ }
+ return value;
+}
+
+}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/ssl/SslHandler.cpp b/cpp/src/qpid/sys/ssl/SslHandler.cpp
new file mode 100644
index 0000000000..3469f88c0f
--- /dev/null
+++ b/cpp/src/qpid/sys/ssl/SslHandler.cpp
@@ -0,0 +1,187 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/sys/ssl/SslHandler.h"
+
+#include "qpid/sys/ssl/SslIo.h"
+#include "qpid/sys/ssl/SslSocket.h"
+#include "qpid/framing/AMQP_HighestVersion.h"
+#include "qpid/framing/ProtocolInitiation.h"
+#include "qpid/log/Statement.h"
+
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace sys {
+namespace ssl {
+
+
+// Buffer definition
+struct Buff : public SslIO::BufferBase {
+ Buff() :
+ SslIO::BufferBase(new char[65536], 65536)
+ {}
+ ~Buff()
+ { delete [] bytes;}
+};
+
+SslHandler::SslHandler(std::string id, ConnectionCodec::Factory* f) :
+ identifier(id),
+ aio(0),
+ factory(f),
+ codec(0),
+ readError(false),
+ isClient(false)
+{}
+
+SslHandler::~SslHandler() {
+ if (codec)
+ codec->closed();
+ delete codec;
+}
+
+void SslHandler::init(SslIO* a, int numBuffs) {
+ aio = a;
+
+ // Give connection some buffers to use
+ for (int i = 0; i < numBuffs; i++) {
+ aio->queueReadBuffer(new Buff);
+ }
+}
+
+void SslHandler::write(const framing::ProtocolInitiation& data)
+{
+ QPID_LOG(debug, "SENT [" << identifier << "] INIT(" << data << ")");
+ SslIO::BufferBase* buff = aio->getQueuedBuffer();
+ if (!buff)
+ buff = new Buff;
+ framing::Buffer out(buff->bytes, buff->byteCount);
+ data.encode(out);
+ buff->dataCount = data.encodedSize();
+ aio->queueWrite(buff);
+}
+
+void SslHandler::abort() {
+ // TODO: can't implement currently as underlying functionality not implemented
+ // aio->requestCallback(boost::bind(&SslHandler::eof, this, _1));
+}
+void SslHandler::activateOutput() {
+ aio->notifyPendingWrite();
+}
+
+void SslHandler::giveReadCredit(int32_t) {
+ // FIXME aconway 2008-12-05: not yet implemented.
+}
+
+// Input side
+void SslHandler::readbuff(SslIO& , SslIO::BufferBase* buff) {
+ if (readError) {
+ return;
+ }
+ size_t decoded = 0;
+ if (codec) { // Already initiated
+ try {
+ decoded = codec->decode(buff->bytes+buff->dataStart, buff->dataCount);
+ }catch(const std::exception& e){
+ QPID_LOG(error, e.what());
+ readError = true;
+ aio->queueWriteClose();
+ }
+ }else{
+ framing::Buffer in(buff->bytes+buff->dataStart, buff->dataCount);
+ framing::ProtocolInitiation protocolInit;
+ if (protocolInit.decode(in)) {
+ decoded = in.getPosition();
+ QPID_LOG(debug, "RECV [" << identifier << "] INIT(" << protocolInit << ")");
+ try {
+ codec = factory->create(protocolInit.getVersion(), *this, identifier, aio->getKeyLen());
+ if (!codec) {
+ //TODO: may still want to revise this...
+ //send valid version header & close connection.
+ write(framing::ProtocolInitiation(framing::highestProtocolVersion));
+ readError = true;
+ aio->queueWriteClose();
+ }
+ } catch (const std::exception& e) {
+ QPID_LOG(error, e.what());
+ readError = true;
+ aio->queueWriteClose();
+ }
+ }
+ }
+ // TODO: unreading needs to go away, and when we can cope
+ // with multiple sub-buffers in the general buffer scheme, it will
+ if (decoded != size_t(buff->dataCount)) {
+ // Adjust buffer for used bytes and then "unread them"
+ buff->dataStart += decoded;
+ buff->dataCount -= decoded;
+ aio->unread(buff);
+ } else {
+ // Give whole buffer back to aio subsystem
+ aio->queueReadBuffer(buff);
+ }
+}
+
+void SslHandler::eof(SslIO&) {
+ QPID_LOG(debug, "DISCONNECTED [" << identifier << "]");
+ if (codec) codec->closed();
+ aio->queueWriteClose();
+}
+
+void SslHandler::closedSocket(SslIO&, const SslSocket& s) {
+ // If we closed with data still to send log a warning
+ if (!aio->writeQueueEmpty()) {
+ QPID_LOG(warning, "CLOSING [" << identifier << "] unsent data (probably due to client disconnect)");
+ }
+ delete &s;
+ aio->queueForDeletion();
+ delete this;
+}
+
+void SslHandler::disconnect(SslIO& a) {
+ // treat the same as eof
+ eof(a);
+}
+
+// Notifications
+void SslHandler::nobuffs(SslIO&) {
+}
+
+void SslHandler::idle(SslIO&){
+ if (isClient && codec == 0) {
+ codec = factory->create(*this, identifier, aio->getKeyLen());
+ write(framing::ProtocolInitiation(codec->getVersion()));
+ return;
+ }
+ if (codec == 0) return;
+ if (codec->canEncode()) {
+ // Try and get a queued buffer if not then construct new one
+ SslIO::BufferBase* buff = aio->getQueuedBuffer();
+ if (!buff) buff = new Buff;
+ size_t encoded=codec->encode(buff->bytes, buff->byteCount);
+ buff->dataCount = encoded;
+ aio->queueWrite(buff);
+ }
+ if (codec->isClosed())
+ aio->queueWriteClose();
+}
+
+
+}}} // namespace qpid::sys::ssl
diff --git a/cpp/src/qpid/sys/ssl/SslHandler.h b/cpp/src/qpid/sys/ssl/SslHandler.h
new file mode 100644
index 0000000000..8f6b8e732a
--- /dev/null
+++ b/cpp/src/qpid/sys/ssl/SslHandler.h
@@ -0,0 +1,76 @@
+#ifndef QPID_SYS_SSL_SSLHANDLER_H
+#define QPID_SYS_SSL_SSLHANDLER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/ConnectionCodec.h"
+#include "qpid/sys/OutputControl.h"
+
+namespace qpid {
+
+namespace framing {
+ class ProtocolInitiation;
+}
+
+namespace sys {
+namespace ssl {
+
+class SslIO;
+class SslIOBufferBase;
+class SslSocket;
+
+class SslHandler : public OutputControl {
+ std::string identifier;
+ SslIO* aio;
+ ConnectionCodec::Factory* factory;
+ ConnectionCodec* codec;
+ bool readError;
+ bool isClient;
+
+ void write(const framing::ProtocolInitiation&);
+
+ public:
+ SslHandler(std::string id, ConnectionCodec::Factory* f);
+ ~SslHandler();
+ void init(SslIO* a, int numBuffs);
+
+ void setClient() { isClient = true; }
+
+ // Output side
+ void abort();
+ void activateOutput();
+ void giveReadCredit(int32_t);
+
+ // Input side
+ void readbuff(SslIO& aio, SslIOBufferBase* buff);
+ void eof(SslIO& aio);
+ void disconnect(SslIO& aio);
+
+ // Notifications
+ void nobuffs(SslIO& aio);
+ void idle(SslIO& aio);
+ void closedSocket(SslIO& aio, const SslSocket& s);
+};
+
+}}} // namespace qpid::sys::ssl
+
+#endif /*!QPID_SYS_SSL_SSLHANDLER_H*/
diff --git a/cpp/src/qpid/sys/ssl/SslIo.cpp b/cpp/src/qpid/sys/ssl/SslIo.cpp
new file mode 100644
index 0000000000..c149d6ea74
--- /dev/null
+++ b/cpp/src/qpid/sys/ssl/SslIo.cpp
@@ -0,0 +1,439 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/sys/ssl/SslIo.h"
+#include "qpid/sys/ssl/SslSocket.h"
+
+#include "qpid/sys/Time.h"
+#include "qpid/sys/posix/check.h"
+#include "qpid/log/Statement.h"
+
+// TODO The basic algorithm here is not really POSIX specific and with a bit more abstraction
+// could (should) be promoted to be platform portable
+#include <unistd.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+
+#include <boost/bind.hpp>
+
+using namespace qpid::sys;
+using namespace qpid::sys::ssl;
+
+namespace {
+
+/*
+ * Make *process* not generate SIGPIPE when writing to closed
+ * pipe/socket (necessary as default action is to terminate process)
+ */
+void ignoreSigpipe() {
+ ::signal(SIGPIPE, SIG_IGN);
+}
+
+/*
+ * We keep per thread state to avoid locking overhead. The assumption is that
+ * on average all the connections are serviced by all the threads so the state
+ * recorded in each thread is about the same. If this turns out not to be the
+ * case we could rebalance the info occasionally.
+ */
+__thread int threadReadTotal = 0;
+__thread int threadMaxRead = 0;
+__thread int threadReadCount = 0;
+__thread int threadWriteTotal = 0;
+__thread int threadWriteCount = 0;
+__thread int64_t threadMaxReadTimeNs = 2 * 1000000; // start at 2ms
+}
+
+/*
+ * Asynch Acceptor
+ */
+
+SslAcceptor::SslAcceptor(const SslSocket& s, Callback callback) :
+ acceptedCallback(callback),
+ handle(s, boost::bind(&SslAcceptor::readable, this, _1), 0, 0),
+ socket(s) {
+
+ s.setNonblocking();
+ ignoreSigpipe();
+}
+
+SslAcceptor::~SslAcceptor()
+{
+ handle.stopWatch();
+}
+
+void SslAcceptor::start(Poller::shared_ptr poller) {
+ handle.startWatch(poller);
+}
+
+/*
+ * We keep on accepting as long as there is something to accept
+ */
+void SslAcceptor::readable(DispatchHandle& h) {
+ SslSocket* s;
+ do {
+ errno = 0;
+ // TODO: Currently we ignore the peers address, perhaps we should
+ // log it or use it for connection acceptance.
+ try {
+ s = socket.accept();
+ if (s) {
+ acceptedCallback(*s);
+ } else {
+ break;
+ }
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Could not accept socket: " << e.what());
+ }
+ } while (true);
+
+ h.rewatch();
+}
+
+/*
+ * Asynch Connector
+ */
+
+SslConnector::SslConnector(const SslSocket& s,
+ Poller::shared_ptr poller,
+ std::string hostname,
+ uint16_t port,
+ ConnectedCallback connCb,
+ FailedCallback failCb) :
+ DispatchHandle(s,
+ 0,
+ boost::bind(&SslConnector::connComplete, this, _1),
+ boost::bind(&SslConnector::connComplete, this, _1)),
+ connCallback(connCb),
+ failCallback(failCb),
+ socket(s)
+{
+ //TODO: would be better for connect to be performed on a
+ //non-blocking socket, but that doesn't work at present so connect
+ //blocks until complete
+ try {
+ socket.connect(hostname, port);
+ socket.setNonblocking();
+ startWatch(poller);
+ } catch(std::exception& e) {
+ failure(-1, std::string(e.what()));
+ }
+}
+
+void SslConnector::connComplete(DispatchHandle& h)
+{
+ int errCode = socket.getError();
+
+ h.stopWatch();
+ if (errCode == 0) {
+ connCallback(socket);
+ DispatchHandle::doDelete();
+ } else {
+ // TODO: This need to be fixed as strerror isn't thread safe
+ failure(errCode, std::string(::strerror(errCode)));
+ }
+}
+
+void SslConnector::failure(int errCode, std::string message)
+{
+ if (failCallback)
+ failCallback(errCode, message);
+
+ socket.close();
+ delete &socket;
+
+ DispatchHandle::doDelete();
+}
+
+/*
+ * Asynch reader/writer
+ */
+SslIO::SslIO(const SslSocket& s,
+ ReadCallback rCb, EofCallback eofCb, DisconnectCallback disCb,
+ ClosedCallback cCb, BuffersEmptyCallback eCb, IdleCallback iCb) :
+
+ DispatchHandle(s,
+ boost::bind(&SslIO::readable, this, _1),
+ boost::bind(&SslIO::writeable, this, _1),
+ boost::bind(&SslIO::disconnected, this, _1)),
+ readCallback(rCb),
+ eofCallback(eofCb),
+ disCallback(disCb),
+ closedCallback(cCb),
+ emptyCallback(eCb),
+ idleCallback(iCb),
+ socket(s),
+ queuedClose(false),
+ writePending(false) {
+
+ s.setNonblocking();
+}
+
+struct deleter
+{
+ template <typename T>
+ void operator()(T *ptr){ delete ptr;}
+};
+
+SslIO::~SslIO() {
+ std::for_each( bufferQueue.begin(), bufferQueue.end(), deleter());
+ std::for_each( writeQueue.begin(), writeQueue.end(), deleter());
+}
+
+void SslIO::queueForDeletion() {
+ DispatchHandle::doDelete();
+}
+
+void SslIO::start(Poller::shared_ptr poller) {
+ DispatchHandle::startWatch(poller);
+}
+
+void SslIO::queueReadBuffer(BufferBase* buff) {
+ assert(buff);
+ buff->dataStart = 0;
+ buff->dataCount = 0;
+ bufferQueue.push_back(buff);
+ DispatchHandle::rewatchRead();
+}
+
+void SslIO::unread(BufferBase* buff) {
+ assert(buff);
+ if (buff->dataStart != 0) {
+ memmove(buff->bytes, buff->bytes+buff->dataStart, buff->dataCount);
+ buff->dataStart = 0;
+ }
+ bufferQueue.push_front(buff);
+ DispatchHandle::rewatchRead();
+}
+
+void SslIO::queueWrite(BufferBase* buff) {
+ assert(buff);
+ // If we've already closed the socket then throw the write away
+ if (queuedClose) {
+ bufferQueue.push_front(buff);
+ return;
+ } else {
+ writeQueue.push_front(buff);
+ }
+ writePending = false;
+ DispatchHandle::rewatchWrite();
+}
+
+void SslIO::notifyPendingWrite() {
+ writePending = true;
+ DispatchHandle::rewatchWrite();
+}
+
+void SslIO::queueWriteClose() {
+ queuedClose = true;
+ DispatchHandle::rewatchWrite();
+}
+
+/** Return a queued buffer if there are enough
+ * to spare
+ */
+SslIO::BufferBase* SslIO::getQueuedBuffer() {
+ // Always keep at least one buffer (it might have data that was "unread" in it)
+ if (bufferQueue.size()<=1)
+ return 0;
+ BufferBase* buff = bufferQueue.back();
+ assert(buff);
+ buff->dataStart = 0;
+ buff->dataCount = 0;
+ bufferQueue.pop_back();
+ return buff;
+}
+
+/*
+ * We keep on reading as long as we have something to read and a buffer to put
+ * it in
+ */
+void SslIO::readable(DispatchHandle& h) {
+ int readTotal = 0;
+ AbsTime readStartTime = AbsTime::now();
+ do {
+ // (Try to) get a buffer
+ if (!bufferQueue.empty()) {
+ // Read into buffer
+ BufferBase* buff = bufferQueue.front();
+ assert(buff);
+ bufferQueue.pop_front();
+ errno = 0;
+ int readCount = buff->byteCount-buff->dataCount;
+ int rc = socket.read(buff->bytes + buff->dataCount, readCount);
+ if (rc > 0) {
+ buff->dataCount += rc;
+ threadReadTotal += rc;
+ readTotal += rc;
+
+ readCallback(*this, buff);
+ if (rc != readCount) {
+ // If we didn't fill the read buffer then time to stop reading
+ break;
+ }
+
+ // Stop reading if we've overrun our timeslot
+ if (Duration(readStartTime, AbsTime::now()) > threadMaxReadTimeNs) {
+ break;
+ }
+
+ } else {
+ // Put buffer back (at front so it doesn't interfere with unread buffers)
+ bufferQueue.push_front(buff);
+ assert(buff);
+
+ // Eof or other side has gone away
+ if (rc == 0 || errno == ECONNRESET) {
+ eofCallback(*this);
+ h.unwatchRead();
+ break;
+ } else if (errno == EAGAIN) {
+ // We have just put a buffer back so we know
+ // we can carry on watching for reads
+ break;
+ } else {
+ // Report error then just treat as a socket disconnect
+ QPID_LOG(error, "Error reading socket: " << qpid::sys::strError(rc) << "(" << rc << ")" );
+ eofCallback(*this);
+ h.unwatchRead();
+ break;
+ }
+ }
+ } else {
+ // Something to read but no buffer
+ if (emptyCallback) {
+ emptyCallback(*this);
+ }
+ // If we still have no buffers we can't do anything more
+ if (bufferQueue.empty()) {
+ h.unwatchRead();
+ break;
+ }
+
+ }
+ } while (true);
+
+ ++threadReadCount;
+ threadMaxRead = std::max(threadMaxRead, readTotal);
+ return;
+}
+
+/*
+ * We carry on writing whilst we have data to write and we can write
+ */
+void SslIO::writeable(DispatchHandle& h) {
+ int writeTotal = 0;
+ do {
+ // See if we've got something to write
+ if (!writeQueue.empty()) {
+ // Write buffer
+ BufferBase* buff = writeQueue.back();
+ writeQueue.pop_back();
+ errno = 0;
+ assert(buff->dataStart+buff->dataCount <= buff->byteCount);
+ int rc = socket.write(buff->bytes+buff->dataStart, buff->dataCount);
+ if (rc >= 0) {
+ threadWriteTotal += rc;
+ writeTotal += rc;
+
+ // If we didn't write full buffer put rest back
+ if (rc != buff->dataCount) {
+ buff->dataStart += rc;
+ buff->dataCount -= rc;
+ writeQueue.push_back(buff);
+ break;
+ }
+
+ // Recycle the buffer
+ queueReadBuffer(buff);
+
+ // If we've already written more than the max for reading then stop
+ // (this is to stop writes dominating reads)
+ if (writeTotal > threadMaxRead)
+ break;
+ } else {
+ // Put buffer back
+ writeQueue.push_back(buff);
+ if (errno == ECONNRESET || errno == EPIPE) {
+ // Just stop watching for write here - we'll get a
+ // disconnect callback soon enough
+ h.unwatchWrite();
+ break;
+ } else if (errno == EAGAIN) {
+ // We have just put a buffer back so we know
+ // we can carry on watching for writes
+ break;
+ } else {
+ QPID_POSIX_CHECK(rc);
+ }
+ }
+ } else {
+ // If we're waiting to close the socket then can do it now as there is nothing to write
+ if (queuedClose) {
+ close(h);
+ break;
+ }
+ // Fd is writable, but nothing to write
+ if (idleCallback) {
+ writePending = false;
+ idleCallback(*this);
+ }
+ // If we still have no buffers to write we can't do anything more
+ if (writeQueue.empty() && !writePending && !queuedClose) {
+ h.unwatchWrite();
+ // The following handles the case where writePending is
+ // set to true after the test above; in this case its
+ // possible that the unwatchWrite overwrites the
+ // desired rewatchWrite so we correct that here
+ if (writePending)
+ h.rewatchWrite();
+ break;
+ }
+ }
+ } while (true);
+
+ ++threadWriteCount;
+ return;
+}
+
+void SslIO::disconnected(DispatchHandle& h) {
+ // If we've already queued close do it instead of disconnected callback
+ if (queuedClose) {
+ close(h);
+ } else if (disCallback) {
+ disCallback(*this);
+ h.unwatch();
+ }
+}
+
+/*
+ * Close the socket and callback to say we've done it
+ */
+void SslIO::close(DispatchHandle& h) {
+ h.stopWatch();
+ socket.close();
+ if (closedCallback) {
+ closedCallback(*this, socket);
+ }
+}
+
+int SslIO::getKeyLen() {return socket.getKeyLen();}
diff --git a/cpp/src/qpid/sys/ssl/SslIo.h b/cpp/src/qpid/sys/ssl/SslIo.h
new file mode 100644
index 0000000000..3162abac40
--- /dev/null
+++ b/cpp/src/qpid/sys/ssl/SslIo.h
@@ -0,0 +1,171 @@
+#ifndef _sys_ssl_SslIO
+#define _sys_ssl_SslIO
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/sys/DispatchHandle.h"
+
+#include <boost/function.hpp>
+#include <deque>
+
+namespace qpid {
+namespace sys {
+namespace ssl {
+
+class SslSocket;
+
+/*
+ * Asynchronous ssl acceptor: accepts connections then does a callback
+ * with the accepted fd
+ */
+class SslAcceptor {
+public:
+ typedef boost::function1<void, const SslSocket&> Callback;
+
+private:
+ Callback acceptedCallback;
+ qpid::sys::DispatchHandle handle;
+ const SslSocket& socket;
+
+public:
+ SslAcceptor(const SslSocket& s, Callback callback);
+ ~SslAcceptor();
+ void start(qpid::sys::Poller::shared_ptr poller);
+
+private:
+ void readable(qpid::sys::DispatchHandle& handle);
+};
+
+/*
+ * Asynchronous ssl connector: starts the process of initiating a
+ * connection and invokes a callback when completed or failed.
+ */
+class SslConnector : private qpid::sys::DispatchHandle {
+public:
+ typedef boost::function1<void, const SslSocket&> ConnectedCallback;
+ typedef boost::function2<void, int, std::string> FailedCallback;
+
+private:
+ ConnectedCallback connCallback;
+ FailedCallback failCallback;
+ const SslSocket& socket;
+
+public:
+ SslConnector(const SslSocket& socket,
+ Poller::shared_ptr poller,
+ std::string hostname,
+ uint16_t port,
+ ConnectedCallback connCb,
+ FailedCallback failCb = 0);
+
+private:
+ void connComplete(DispatchHandle& handle);
+ void failure(int, std::string);
+};
+
+struct SslIOBufferBase {
+ char* const bytes;
+ const int32_t byteCount;
+ int32_t dataStart;
+ int32_t dataCount;
+
+ SslIOBufferBase(char* const b, const int32_t s) :
+ bytes(b),
+ byteCount(s),
+ dataStart(0),
+ dataCount(0)
+ {}
+
+ virtual ~SslIOBufferBase()
+ {}
+};
+
+/*
+ * Asychronous reader/writer:
+ * Reader accepts buffers to read into; reads into the provided buffers
+ * and then does a callback with the buffer and amount read. Optionally it can callback
+ * when there is something to read but no buffer to read it into.
+ *
+ * Writer accepts a buffer and queues it for writing; can also be given
+ * a callback for when writing is "idle" (ie fd is writable, but nothing to write)
+ *
+ * The class is implemented in terms of DispatchHandle to allow it to be deleted by deleting
+ * the contained DispatchHandle
+ */
+class SslIO : private qpid::sys::DispatchHandle {
+public:
+ typedef SslIOBufferBase BufferBase;
+
+ typedef boost::function2<void, SslIO&, BufferBase*> ReadCallback;
+ typedef boost::function1<void, SslIO&> EofCallback;
+ typedef boost::function1<void, SslIO&> DisconnectCallback;
+ typedef boost::function2<void, SslIO&, const SslSocket&> ClosedCallback;
+ typedef boost::function1<void, SslIO&> BuffersEmptyCallback;
+ typedef boost::function1<void, SslIO&> IdleCallback;
+
+
+private:
+ ReadCallback readCallback;
+ EofCallback eofCallback;
+ DisconnectCallback disCallback;
+ ClosedCallback closedCallback;
+ BuffersEmptyCallback emptyCallback;
+ IdleCallback idleCallback;
+ const SslSocket& socket;
+ std::deque<BufferBase*> bufferQueue;
+ std::deque<BufferBase*> writeQueue;
+ bool queuedClose;
+ /**
+ * This flag is used to detect and handle concurrency between
+ * calls to notifyPendingWrite() (which can be made from any thread) and
+ * the execution of the writeable() method (which is always on the
+ * thread processing this handle.
+ */
+ volatile bool writePending;
+
+public:
+ SslIO(const SslSocket& s,
+ ReadCallback rCb, EofCallback eofCb, DisconnectCallback disCb,
+ ClosedCallback cCb = 0, BuffersEmptyCallback eCb = 0, IdleCallback iCb = 0);
+ void queueForDeletion();
+
+ void start(qpid::sys::Poller::shared_ptr poller);
+ void queueReadBuffer(BufferBase* buff);
+ void unread(BufferBase* buff);
+ void queueWrite(BufferBase* buff);
+ void notifyPendingWrite();
+ void queueWriteClose();
+ bool writeQueueEmpty() { return writeQueue.empty(); }
+ BufferBase* getQueuedBuffer();
+
+ int getKeyLen();
+
+private:
+ ~SslIO();
+ void readable(qpid::sys::DispatchHandle& handle);
+ void writeable(qpid::sys::DispatchHandle& handle);
+ void disconnected(qpid::sys::DispatchHandle& handle);
+ void close(qpid::sys::DispatchHandle& handle);
+};
+
+}}}
+
+#endif // _sys_ssl_SslIO
diff --git a/cpp/src/qpid/sys/ssl/SslSocket.cpp b/cpp/src/qpid/sys/ssl/SslSocket.cpp
new file mode 100644
index 0000000000..aa8cf127d7
--- /dev/null
+++ b/cpp/src/qpid/sys/ssl/SslSocket.cpp
@@ -0,0 +1,297 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/sys/ssl/SslSocket.h"
+#include "qpid/sys/ssl/check.h"
+#include "qpid/sys/ssl/util.h"
+#include "qpid/Exception.h"
+#include "qpid/sys/posix/check.h"
+#include "qpid/sys/posix/PrivatePosix.h"
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <cstdlib>
+#include <string.h>
+#include <iostream>
+
+#include <private/pprio.h>
+#include <nss.h>
+#include <pk11pub.h>
+#include <ssl.h>
+#include <key.h>
+
+#include <boost/format.hpp>
+
+namespace qpid {
+namespace sys {
+namespace ssl {
+
+namespace {
+std::string getName(int fd, bool local, bool includeService = false)
+{
+ ::sockaddr_storage name; // big enough for any socket address
+ ::socklen_t namelen = sizeof(name);
+
+ int result = -1;
+ if (local) {
+ result = ::getsockname(fd, (::sockaddr*)&name, &namelen);
+ } else {
+ result = ::getpeername(fd, (::sockaddr*)&name, &namelen);
+ }
+
+ QPID_POSIX_CHECK(result);
+
+ char servName[NI_MAXSERV];
+ char dispName[NI_MAXHOST];
+ if (includeService) {
+ if (int rc=::getnameinfo((::sockaddr*)&name, namelen, dispName, sizeof(dispName),
+ servName, sizeof(servName),
+ NI_NUMERICHOST | NI_NUMERICSERV) != 0)
+ throw QPID_POSIX_ERROR(rc);
+ return std::string(dispName) + ":" + std::string(servName);
+
+ } else {
+ if (int rc=::getnameinfo((::sockaddr*)&name, namelen, dispName, sizeof(dispName), 0, 0, NI_NUMERICHOST) != 0)
+ throw QPID_POSIX_ERROR(rc);
+ return dispName;
+ }
+}
+
+std::string getService(int fd, bool local)
+{
+ ::sockaddr_storage name; // big enough for any socket address
+ ::socklen_t namelen = sizeof(name);
+
+ int result = -1;
+ if (local) {
+ result = ::getsockname(fd, (::sockaddr*)&name, &namelen);
+ } else {
+ result = ::getpeername(fd, (::sockaddr*)&name, &namelen);
+ }
+
+ QPID_POSIX_CHECK(result);
+
+ char servName[NI_MAXSERV];
+ if (int rc=::getnameinfo((::sockaddr*)&name, namelen, 0, 0,
+ servName, sizeof(servName),
+ NI_NUMERICHOST | NI_NUMERICSERV) != 0)
+ throw QPID_POSIX_ERROR(rc);
+ return servName;
+}
+
+}
+
+SslSocket::SslSocket() : IOHandle(new IOHandlePrivate()), socket(0), prototype(0)
+{
+ impl->fd = ::socket (PF_INET, SOCK_STREAM, 0);
+ if (impl->fd < 0) throw QPID_POSIX_ERROR(errno);
+ socket = SSL_ImportFD(0, PR_ImportTCPSocket(impl->fd));
+}
+
+/**
+ * This form of the constructor is used with the server-side sockets
+ * returned from accept. Because we use posix accept rather than
+ * PR_Accept, we have to reset the handshake.
+ */
+SslSocket::SslSocket(IOHandlePrivate* ioph, PRFileDesc* model) : IOHandle(ioph), socket(0), prototype(0)
+{
+ socket = SSL_ImportFD(model, PR_ImportTCPSocket(impl->fd));
+ NSS_CHECK(SSL_ResetHandshake(socket, true));
+}
+
+void SslSocket::setNonblocking() const
+{
+ PRSocketOptionData option;
+ option.option = PR_SockOpt_Nonblocking;
+ option.value.non_blocking = true;
+ PR_SetSocketOption(socket, &option);
+}
+
+void SslSocket::connect(const std::string& host, uint16_t port) const
+{
+ std::stringstream namestream;
+ namestream << host << ":" << port;
+ connectname = namestream.str();
+
+ void* arg = SslOptions::global.certName.empty() ? 0 : const_cast<char*>(SslOptions::global.certName.c_str());
+ NSS_CHECK(SSL_GetClientAuthDataHook(socket, NSS_GetClientAuthData, arg));
+ NSS_CHECK(SSL_SetURL(socket, host.data()));
+
+ char hostBuffer[PR_NETDB_BUF_SIZE];
+ PRHostEnt hostEntry;
+ PR_CHECK(PR_GetHostByName(host.data(), hostBuffer, PR_NETDB_BUF_SIZE, &hostEntry));
+ PRNetAddr address;
+ int value = PR_EnumerateHostEnt(0, &hostEntry, port, &address);
+ if (value < 0) {
+ throw Exception(QPID_MSG("Error getting address for host: " << ErrorString()));
+ } else if (value == 0) {
+ throw Exception(QPID_MSG("Could not resolve address for host."));
+ }
+ PR_CHECK(PR_Connect(socket, &address, PR_INTERVAL_NO_TIMEOUT));
+}
+
+void SslSocket::close() const
+{
+ if (impl->fd > 0) {
+ PR_Close(socket);
+ impl->fd = -1;
+ }
+}
+
+int SslSocket::listen(uint16_t port, int backlog, const std::string& certName, bool clientAuth) const
+{
+ //configure prototype socket:
+ prototype = SSL_ImportFD(0, PR_NewTCPSocket());
+ if (clientAuth) {
+ NSS_CHECK(SSL_OptionSet(prototype, SSL_REQUEST_CERTIFICATE, PR_TRUE));
+ NSS_CHECK(SSL_OptionSet(prototype, SSL_REQUIRE_CERTIFICATE, PR_TRUE));
+ }
+
+ //get certificate and key (is this the correct way?)
+ CERTCertificate *cert = PK11_FindCertFromNickname(const_cast<char*>(certName.c_str()), 0);
+ if (!cert) throw Exception(QPID_MSG("Failed to load certificate '" << certName << "'"));
+ SECKEYPrivateKey *key = PK11_FindKeyByAnyCert(cert, 0);
+ if (!key) throw Exception(QPID_MSG("Failed to retrieve private key from certificate"));
+ NSS_CHECK(SSL_ConfigSecureServer(prototype, cert, key, NSS_FindCertKEAType(cert)));
+ SECKEY_DestroyPrivateKey(key);
+ CERT_DestroyCertificate(cert);
+
+ //bind and listen
+ const int& socket = impl->fd;
+ int yes=1;
+ QPID_POSIX_CHECK(setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)));
+ struct sockaddr_in name;
+ name.sin_family = AF_INET;
+ name.sin_port = htons(port);
+ name.sin_addr.s_addr = 0;
+ if (::bind(socket, (struct sockaddr*)&name, sizeof(name)) < 0)
+ throw Exception(QPID_MSG("Can't bind to port " << port << ": " << strError(errno)));
+ if (::listen(socket, backlog) < 0)
+ throw Exception(QPID_MSG("Can't listen on port " << port << ": " << strError(errno)));
+
+ socklen_t namelen = sizeof(name);
+ if (::getsockname(socket, (struct sockaddr*)&name, &namelen) < 0)
+ throw QPID_POSIX_ERROR(errno);
+
+ return ntohs(name.sin_port);
+}
+
+SslSocket* SslSocket::accept() const
+{
+ int afd = ::accept(impl->fd, 0, 0);
+ if ( afd >= 0) {
+ return new SslSocket(new IOHandlePrivate(afd), prototype);
+ } else if (errno == EAGAIN) {
+ return 0;
+ } else {
+ throw QPID_POSIX_ERROR(errno);
+ }
+}
+
+int SslSocket::read(void *buf, size_t count) const
+{
+ return PR_Read(socket, buf, count);
+}
+
+int SslSocket::write(const void *buf, size_t count) const
+{
+ return PR_Write(socket, buf, count);
+}
+
+std::string SslSocket::getSockname() const
+{
+ return getName(impl->fd, true);
+}
+
+std::string SslSocket::getPeername() const
+{
+ return getName(impl->fd, false);
+}
+
+std::string SslSocket::getPeerAddress() const
+{
+ if (!connectname.empty())
+ return connectname;
+ return getName(impl->fd, false, true);
+}
+
+std::string SslSocket::getLocalAddress() const
+{
+ return getName(impl->fd, true, true);
+}
+
+uint16_t SslSocket::getLocalPort() const
+{
+ return std::atoi(getService(impl->fd, true).c_str());
+}
+
+uint16_t SslSocket::getRemotePort() const
+{
+ return atoi(getService(impl->fd, true).c_str());
+}
+
+int SslSocket::getError() const
+{
+ int result;
+ socklen_t rSize = sizeof (result);
+
+ if (::getsockopt(impl->fd, SOL_SOCKET, SO_ERROR, &result, &rSize) < 0)
+ throw QPID_POSIX_ERROR(errno);
+
+ return result;
+}
+
+void SslSocket::setTcpNoDelay(bool nodelay) const
+{
+ if (nodelay) {
+ PRSocketOptionData option;
+ option.option = PR_SockOpt_NoDelay;
+ option.value.no_delay = true;
+ PR_SetSocketOption(socket, &option);
+ }
+}
+
+
+/** get the bit length of the current cipher's key */
+int SslSocket::getKeyLen() const
+{
+ int enabled = 0;
+ int keySize = 0;
+ SECStatus rc;
+
+ rc = SSL_SecurityStatus( socket,
+ &enabled,
+ NULL,
+ NULL,
+ &keySize,
+ NULL, NULL );
+ if (rc == SECSuccess && enabled) {
+ return keySize;
+ }
+ return 0;
+}
+
+}}} // namespace qpid::sys::ssl
diff --git a/cpp/src/qpid/sys/ssl/SslSocket.h b/cpp/src/qpid/sys/ssl/SslSocket.h
new file mode 100644
index 0000000000..f1f05e7a98
--- /dev/null
+++ b/cpp/src/qpid/sys/ssl/SslSocket.h
@@ -0,0 +1,119 @@
+#ifndef _sys_ssl_Socket_h
+#define _sys_ssl_Socket_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/IOHandle.h"
+#include <nspr.h>
+
+#include <string>
+
+struct sockaddr;
+
+namespace qpid {
+namespace sys {
+
+class Duration;
+
+namespace ssl {
+
+class SslSocket : public qpid::sys::IOHandle
+{
+public:
+ /** Create a socket wrapper for descriptor. */
+ SslSocket();
+
+ /** Set socket non blocking */
+ void setNonblocking() const;
+
+ /** Set tcp-nodelay */
+ void setTcpNoDelay(bool nodelay) const;
+
+ void connect(const std::string& host, uint16_t port) const;
+
+ void close() const;
+
+ /** Bind to a port and start listening.
+ *@param port 0 means choose an available port.
+ *@param backlog maximum number of pending connections.
+ *@param certName name of certificate to use to identify the server
+ *@return The bound port.
+ */
+ int listen(uint16_t port = 0, int backlog = 10, const std::string& certName = "localhost.localdomain", bool clientAuth = false) const;
+
+ /**
+ * Accept a connection from a socket that is already listening
+ * and has an incoming connection
+ */
+ SslSocket* accept() const;
+
+ // TODO The following are raw operations, maybe they need better wrapping?
+ int read(void *buf, size_t count) const;
+ int write(const void *buf, size_t count) const;
+
+ /** Returns the "socket name" ie the address bound to
+ * the near end of the socket
+ */
+ std::string getSockname() const;
+
+ /** Returns the "peer name" ie the address bound to
+ * the remote end of the socket
+ */
+ std::string getPeername() const;
+
+ /**
+ * Returns an address (host and port) for the remote end of the
+ * socket
+ */
+ std::string getPeerAddress() const;
+ /**
+ * Returns an address (host and port) for the local end of the
+ * socket
+ */
+ std::string getLocalAddress() const;
+
+ uint16_t getLocalPort() const;
+ uint16_t getRemotePort() const;
+
+ /**
+ * Returns the error code stored in the socket. This may be used
+ * to determine the result of a non-blocking connect.
+ */
+ int getError() const;
+
+ int getKeyLen() const;
+
+private:
+ mutable std::string connectname;
+ mutable PRFileDesc* socket;
+ /**
+ * 'model' socket, with configuration to use when importing
+ * accepted sockets for use as ssl sockets. Set on listen(), used
+ * in accept to pass through to newly created socket instances.
+ */
+ mutable PRFileDesc* prototype;
+
+ SslSocket(IOHandlePrivate* ioph, PRFileDesc* model);
+};
+
+}}}
+#endif /*!_sys_ssl_Socket_h*/
diff --git a/cpp/src/qpid/sys/ssl/check.cpp b/cpp/src/qpid/sys/ssl/check.cpp
new file mode 100644
index 0000000000..c5e6005e03
--- /dev/null
+++ b/cpp/src/qpid/sys/ssl/check.cpp
@@ -0,0 +1,72 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/sys/ssl/check.h"
+#include <secerr.h>
+#include <sslerr.h>
+#include <boost/format.hpp>
+
+using boost::format;
+using boost::str;
+
+namespace qpid {
+namespace sys {
+namespace ssl {
+
+const std::string SSL_ERROR_BAD_CERT_DOMAIN_STR =
+ "Unable to communicate securely with peer: requested domain name does not match the server's certificate.";
+const std::string SSL_ERROR_BAD_CERT_ALERT_STR = "SSL peer cannot verify your certificate.";
+const std::string SEC_ERROR_BAD_DATABASE_STR = "Security library: bad database.";
+const std::string SSL_ERROR_NO_CERTIFICATE_STR = "Unable to find the certificate or key necessary for authentication.";
+const std::string SSL_ERROR_UNKNOWN = "Unknown NSS error code.";
+
+ErrorString::ErrorString() : code(PR_GetError()), buffer(new char[PR_GetErrorTextLength()]), used(PR_GetErrorText(buffer)) {}
+
+ErrorString::~ErrorString()
+{
+ delete[] buffer;
+}
+
+std::string ErrorString::getString() const
+{
+ std::string msg = std::string(buffer, used);
+ if (!used) {
+ //seems most of the NSPR/NSS errors don't have text set for
+ //them, add a few specific ones in here. (TODO: more complete
+ //list?):
+ switch (code) {
+ case SSL_ERROR_BAD_CERT_DOMAIN: msg = SSL_ERROR_BAD_CERT_DOMAIN_STR; break;
+ case SSL_ERROR_BAD_CERT_ALERT: msg = SSL_ERROR_BAD_CERT_ALERT_STR; break;
+ case SEC_ERROR_BAD_DATABASE: msg = SEC_ERROR_BAD_DATABASE_STR; break;
+ case SSL_ERROR_NO_CERTIFICATE: msg = SSL_ERROR_NO_CERTIFICATE_STR; break;
+ default: msg = SSL_ERROR_UNKNOWN; break;
+ }
+ }
+ return str(format("%1% [%2%]") % msg % code);
+}
+
+std::ostream& operator<<(std::ostream& out, const ErrorString& err)
+{
+ out << err.getString();
+ return out;
+}
+
+
+}}} // namespace qpid::sys::ssl
diff --git a/cpp/src/qpid/sys/ssl/check.h b/cpp/src/qpid/sys/ssl/check.h
new file mode 100644
index 0000000000..984c338a18
--- /dev/null
+++ b/cpp/src/qpid/sys/ssl/check.h
@@ -0,0 +1,53 @@
+#ifndef QPID_SYS_SSL_CHECK_H
+#define QPID_SYS_SSL_CHECK_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <iostream>
+#include <string>
+#include <nspr.h>
+#include <nss.h>
+
+namespace qpid {
+namespace sys {
+namespace ssl {
+
+class ErrorString
+{
+ public:
+ ErrorString();
+ ~ErrorString();
+ std::string getString() const;
+ private:
+ const int code;
+ char* const buffer;
+ const size_t used;
+};
+
+std::ostream& operator<<(std::ostream& out, const ErrorString& err);
+
+}}} // namespace qpid::sys::ssl
+
+
+#define NSS_CHECK(value) if (value != SECSuccess) { throw Exception(QPID_MSG("Failed: " << qpid::sys::ssl::ErrorString())); }
+#define PR_CHECK(value) if (value != PR_SUCCESS) { throw Exception(QPID_MSG("Failed: " << qpid::sys::ssl::ErrorString())); }
+
+#endif /*!QPID_SYS_SSL_CHECK_H*/
diff --git a/cpp/src/qpid/sys/ssl/util.cpp b/cpp/src/qpid/sys/ssl/util.cpp
new file mode 100644
index 0000000000..53326e2f55
--- /dev/null
+++ b/cpp/src/qpid/sys/ssl/util.cpp
@@ -0,0 +1,118 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/sys/ssl/util.h"
+#include "qpid/sys/ssl/check.h"
+#include "qpid/Exception.h"
+#include "qpid/sys/SystemInfo.h"
+
+#include <unistd.h>
+#include <nspr.h>
+#include <nss.h>
+#include <pk11pub.h>
+#include <ssl.h>
+
+#include <iostream>
+#include <fstream>
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+
+namespace qpid {
+namespace sys {
+namespace ssl {
+
+std::string defaultCertName()
+{
+ TcpAddress address;
+ if (SystemInfo::getLocalHostname(address)) {
+ return address.host;
+ } else {
+ return "localhost";
+ }
+}
+
+SslOptions::SslOptions() : qpid::Options("SSL Settings"),
+ certName(defaultCertName()),
+ exportPolicy(false)
+{
+ addOptions()
+ ("ssl-use-export-policy", optValue(exportPolicy), "Use NSS export policy")
+ ("ssl-cert-password-file", optValue(certPasswordFile, "PATH"), "File containing password to use for accessing certificate database")
+ ("ssl-cert-db", optValue(certDbPath, "PATH"), "Path to directory containing certificate database")
+ ("ssl-cert-name", optValue(certName, "NAME"), "Name of the certificate to use");
+}
+
+SslOptions& SslOptions::operator=(const SslOptions& o)
+{
+ certDbPath = o.certDbPath;
+ certName = o.certName;
+ certPasswordFile = o.certPasswordFile;
+ exportPolicy = o.exportPolicy;
+ return *this;
+}
+
+char* promptForPassword(PK11SlotInfo*, PRBool retry, void*)
+{
+ if (retry) return 0;
+ //TODO: something else?
+ return PL_strdup(getpass("Please enter the password for accessing the certificate database:"));
+}
+
+SslOptions SslOptions::global;
+
+char* readPasswordFromFile(PK11SlotInfo*, PRBool retry, void*)
+{
+ const std::string& passwordFile = SslOptions::global.certPasswordFile;
+ if (retry || passwordFile.empty() || !boost::filesystem::exists(passwordFile)) {
+ return 0;
+ } else {
+ std::ifstream file(passwordFile.c_str());
+ std::string password;
+ file >> password;
+ return PL_strdup(password.c_str());
+ }
+}
+
+void initNSS(const SslOptions& options, bool server)
+{
+ SslOptions::global = options;
+ if (options.certPasswordFile.empty()) {
+ PK11_SetPasswordFunc(promptForPassword);
+ } else {
+ PK11_SetPasswordFunc(readPasswordFromFile);
+ }
+ NSS_CHECK(NSS_Init(options.certDbPath.c_str()));
+ if (options.exportPolicy) {
+ NSS_CHECK(NSS_SetExportPolicy());
+ } else {
+ NSS_CHECK(NSS_SetDomesticPolicy());
+ }
+ if (server) {
+ //use defaults for all args, TODO: may want to make this configurable
+ SSL_ConfigServerSessionIDCache(0, 0, 0, 0);
+ }
+}
+
+void shutdownNSS()
+{
+ NSS_Shutdown();
+}
+
+}}} // namespace qpid::sys::ssl
diff --git a/cpp/src/qpid/sys/ssl/util.h b/cpp/src/qpid/sys/ssl/util.h
new file mode 100644
index 0000000000..f34adab7be
--- /dev/null
+++ b/cpp/src/qpid/sys/ssl/util.h
@@ -0,0 +1,50 @@
+#ifndef QPID_SYS_SSL_UTIL_H
+#define QPID_SYS_SSL_UTIL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/Options.h"
+#include <string>
+
+namespace qpid {
+namespace sys {
+namespace ssl {
+
+struct SslOptions : qpid::Options
+{
+ static SslOptions global;
+
+ std::string certDbPath;
+ std::string certName;
+ std::string certPasswordFile;
+ bool exportPolicy;
+
+ SslOptions();
+ SslOptions& operator=(const SslOptions&);
+};
+
+void initNSS(const SslOptions& options, bool server = false);
+void shutdownNSS();
+
+}}} // namespace qpid::sys::ssl
+
+#endif /*!QPID_SYS_SSL_UTIL_H*/
diff --git a/cpp/src/qpid/sys/uuid.h b/cpp/src/qpid/sys/uuid.h
new file mode 100644
index 0000000000..804ab34463
--- /dev/null
+++ b/cpp/src/qpid/sys/uuid.h
@@ -0,0 +1,28 @@
+#ifndef _sys_uuid_h
+#define _sys_uuid_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifdef _WIN32
+# include "qpid/sys/windows/uuid.h"
+#else
+# include <uuid/uuid.h>
+#endif /* _WIN32 */
+
+#endif /* _sys_uuid_h */
diff --git a/cpp/src/qpid/sys/windows/AsynchIO.cpp b/cpp/src/qpid/sys/windows/AsynchIO.cpp
new file mode 100644
index 0000000000..e4174ee445
--- /dev/null
+++ b/cpp/src/qpid/sys/windows/AsynchIO.cpp
@@ -0,0 +1,751 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/sys/windows/AsynchIoResult.h"
+#include "qpid/sys/windows/IoHandlePrivate.h"
+#include "qpid/sys/AsynchIO.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Socket.h"
+#include "qpid/sys/Poller.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/sys/Time.h"
+#include "qpid/log/Statement.h"
+
+#include "qpid/sys/windows/check.h"
+
+#include <boost/thread/once.hpp>
+
+#include <queue>
+#include <winsock2.h>
+#include <mswsock.h>
+#include <windows.h>
+
+#include <boost/bind.hpp>
+
+namespace {
+
+ typedef qpid::sys::ScopedLock<qpid::sys::Mutex> QLock;
+
+/*
+ * The function pointers for AcceptEx and ConnectEx need to be looked up
+ * at run time. Make sure this is done only once.
+ */
+boost::once_flag lookUpAcceptExOnce = BOOST_ONCE_INIT;
+LPFN_ACCEPTEX fnAcceptEx = 0;
+typedef void (*lookUpFunc)(const qpid::sys::Socket &);
+
+void lookUpAcceptEx() {
+ SOCKET h = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ GUID guidAcceptEx = WSAID_ACCEPTEX;
+ DWORD dwBytes = 0;
+ WSAIoctl(h,
+ SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &guidAcceptEx,
+ sizeof(guidAcceptEx),
+ &fnAcceptEx,
+ sizeof(fnAcceptEx),
+ &dwBytes,
+ NULL,
+ NULL);
+ closesocket(h);
+ if (fnAcceptEx == 0)
+ throw qpid::Exception(QPID_MSG("Failed to look up AcceptEx"));
+}
+
+}
+
+namespace qpid {
+namespace sys {
+namespace windows {
+
+/*
+ * Asynch Acceptor
+ *
+ */
+class AsynchAcceptor : public qpid::sys::AsynchAcceptor {
+
+ friend class AsynchAcceptResult;
+
+public:
+ AsynchAcceptor(const Socket& s, AsynchAcceptor::Callback callback);
+ ~AsynchAcceptor();
+ void start(Poller::shared_ptr poller);
+
+private:
+ void restart(void);
+
+ AsynchAcceptor::Callback acceptedCallback;
+ const Socket& socket;
+};
+
+AsynchAcceptor::AsynchAcceptor(const Socket& s, Callback callback)
+ : acceptedCallback(callback),
+ socket(s) {
+
+ s.setNonblocking();
+#if (BOOST_VERSION >= 103500) /* boost 1.35 or later reversed the args */
+ boost::call_once(lookUpAcceptExOnce, lookUpAcceptEx);
+#else
+ boost::call_once(lookUpAcceptEx, lookUpAcceptExOnce);
+#endif
+}
+
+AsynchAcceptor::~AsynchAcceptor()
+{
+ socket.close();
+}
+
+void AsynchAcceptor::start(Poller::shared_ptr poller) {
+ poller->monitorHandle(PollerHandle(socket), Poller::INPUT);
+ restart ();
+}
+
+void AsynchAcceptor::restart(void) {
+ DWORD bytesReceived = 0; // Not used, needed for AcceptEx API
+ AsynchAcceptResult *result = new AsynchAcceptResult(acceptedCallback,
+ this,
+ toSocketHandle(socket));
+ BOOL status;
+ status = ::fnAcceptEx(toSocketHandle(socket),
+ toSocketHandle(*result->newSocket),
+ result->addressBuffer,
+ 0,
+ AsynchAcceptResult::SOCKADDRMAXLEN,
+ AsynchAcceptResult::SOCKADDRMAXLEN,
+ &bytesReceived,
+ result->overlapped());
+ QPID_WINDOWS_CHECK_ASYNC_START(status);
+}
+
+
+AsynchAcceptResult::AsynchAcceptResult(AsynchAcceptor::Callback cb,
+ AsynchAcceptor *acceptor,
+ SOCKET listener)
+ : callback(cb), acceptor(acceptor), listener(listener) {
+ newSocket.reset (new Socket());
+}
+
+void AsynchAcceptResult::success(size_t /*bytesTransferred*/) {
+ ::setsockopt (toSocketHandle(*newSocket),
+ SOL_SOCKET,
+ SO_UPDATE_ACCEPT_CONTEXT,
+ (char*)&listener,
+ sizeof (listener));
+ callback(*(newSocket.release()));
+ acceptor->restart ();
+ delete this;
+}
+
+void AsynchAcceptResult::failure(int status) {
+ //if (status != WSA_OPERATION_ABORTED)
+ // Can there be anything else? ;
+ delete this;
+}
+
+/*
+ * AsynchConnector does synchronous connects for now... to do asynch the
+ * IocpPoller will need some extension to register an event handle as a
+ * CONNECT-type "direction", the connect completion/result will need an
+ * event handle to associate with the connecting handle. But there's no
+ * time for that right now...
+ */
+class AsynchConnector : public qpid::sys::AsynchConnector {
+private:
+ ConnectedCallback connCallback;
+ FailedCallback failCallback;
+ const Socket& socket;
+
+public:
+ AsynchConnector(const Socket& socket,
+ Poller::shared_ptr poller,
+ std::string hostname,
+ uint16_t port,
+ ConnectedCallback connCb,
+ FailedCallback failCb = 0);
+};
+
+AsynchConnector::AsynchConnector(const Socket& sock,
+ Poller::shared_ptr poller,
+ std::string hostname,
+ uint16_t port,
+ ConnectedCallback connCb,
+ FailedCallback failCb)
+ : connCallback(connCb), failCallback(failCb), socket(sock) {
+ try {
+ socket.connect(hostname, port);
+ socket.setNonblocking();
+ connCallback(socket);
+ } catch(std::exception& e) {
+ if (failCallback)
+ failCallback(socket, -1, std::string(e.what()));
+ socket.close();
+ delete &socket;
+ }
+}
+
+} // namespace windows
+
+AsynchAcceptor* AsynchAcceptor::create(const Socket& s,
+ Callback callback)
+{
+ return new windows::AsynchAcceptor(s, callback);
+}
+
+AsynchConnector* qpid::sys::AsynchConnector::create(const Socket& s,
+ Poller::shared_ptr poller,
+ std::string hostname,
+ uint16_t port,
+ ConnectedCallback connCb,
+ FailedCallback failCb)
+{
+ return new windows::AsynchConnector(s,
+ poller,
+ hostname,
+ port,
+ connCb,
+ failCb);
+}
+
+
+/*
+ * Asynch reader/writer
+ */
+
+namespace windows {
+
+class AsynchIO : public qpid::sys::AsynchIO {
+public:
+ AsynchIO(const Socket& s,
+ ReadCallback rCb,
+ EofCallback eofCb,
+ DisconnectCallback disCb,
+ ClosedCallback cCb = 0,
+ BuffersEmptyCallback eCb = 0,
+ IdleCallback iCb = 0);
+ ~AsynchIO();
+
+ // Methods inherited from qpid::sys::AsynchIO
+
+ /**
+ * Notify the object is should delete itself as soon as possible.
+ */
+ virtual void queueForDeletion();
+
+ /// Take any actions needed to prepare for working with the poller.
+ virtual void start(Poller::shared_ptr poller);
+ virtual void queueReadBuffer(BufferBase* buff);
+ virtual void unread(BufferBase* buff);
+ virtual void queueWrite(BufferBase* buff);
+ virtual void notifyPendingWrite();
+ virtual void queueWriteClose();
+ virtual bool writeQueueEmpty();
+ virtual void startReading();
+ virtual void stopReading();
+ virtual void requestCallback(RequestCallback);
+
+ /**
+ * getQueuedBuffer returns a buffer from the buffer queue, if one is
+ * available.
+ *
+ * @retval Pointer to BufferBase buffer; 0 if none is available.
+ */
+ virtual BufferBase* getQueuedBuffer();
+
+private:
+ ReadCallback readCallback;
+ EofCallback eofCallback;
+ DisconnectCallback disCallback;
+ ClosedCallback closedCallback;
+ BuffersEmptyCallback emptyCallback;
+ IdleCallback idleCallback;
+ const Socket& socket;
+ Poller::shared_ptr poller;
+
+ std::deque<BufferBase*> bufferQueue;
+ std::deque<BufferBase*> writeQueue;
+ /* The MSVC-supplied deque is not thread-safe; keep locks to serialize
+ * access to the buffer queue and write queue.
+ */
+ Mutex bufferQueueLock;
+
+ // Number of outstanding I/O operations.
+ volatile LONG opsInProgress;
+ // Is there a write in progress?
+ volatile bool writeInProgress;
+ // Deletion requested, but there are callbacks in progress.
+ volatile bool queuedDelete;
+ // Socket close requested, but there are operations in progress.
+ volatile bool queuedClose;
+
+private:
+ // Dispatch events that have completed.
+ void notifyEof(void);
+ void notifyDisconnect(void);
+ void notifyClosed(void);
+ void notifyBuffersEmpty(void);
+ void notifyIdle(void);
+
+ /**
+ * Initiate a write of the specified buffer. There's no callback for
+ * write completion to the AsynchIO object.
+ */
+ void startWrite(AsynchIO::BufferBase* buff);
+
+ void close(void);
+
+ /**
+ * readComplete is called when a read request is complete.
+ *
+ * @param result Results of the operation.
+ */
+ void readComplete(AsynchReadResult *result);
+
+ /**
+ * writeComplete is called when a write request is complete.
+ *
+ * @param result Results of the operation.
+ */
+ void writeComplete(AsynchWriteResult *result);
+
+ /**
+ * Queue of completions to run. This queue enforces the requirement
+ * from upper layers that only one thread at a time is allowed to act
+ * on any given connection. Once a thread is busy processing a completion
+ * on this object, other threads that dispatch completions queue the
+ * completions here for the in-progress thread to handle when done.
+ * Thus, any threads can dispatch a completion from the IocpPoller, but
+ * this class ensures that actual processing at the connection level is
+ * only on one thread at a time.
+ */
+ std::queue<AsynchIoResult *> completionQueue;
+ volatile bool working;
+ Mutex completionLock;
+
+ /**
+ * Called when there's a completion to process.
+ */
+ void completion(AsynchIoResult *result);
+};
+
+// This is used to encapsulate pure callbacks into a handle
+class CallbackHandle : public IOHandle {
+public:
+ CallbackHandle(AsynchIoResult::Completer completeCb,
+ AsynchIO::RequestCallback reqCb = 0) :
+ IOHandle(new IOHandlePrivate (INVALID_SOCKET, completeCb, reqCb))
+ {}
+};
+
+AsynchIO::AsynchIO(const Socket& s,
+ ReadCallback rCb,
+ EofCallback eofCb,
+ DisconnectCallback disCb,
+ ClosedCallback cCb,
+ BuffersEmptyCallback eCb,
+ IdleCallback iCb) :
+
+ readCallback(rCb),
+ eofCallback(eofCb),
+ disCallback(disCb),
+ closedCallback(cCb),
+ emptyCallback(eCb),
+ idleCallback(iCb),
+ socket(s),
+ opsInProgress(0),
+ writeInProgress(false),
+ queuedDelete(false),
+ queuedClose(false),
+ working(false) {
+}
+
+struct deleter
+{
+ template <typename T>
+ void operator()(T *ptr){ delete ptr;}
+};
+
+AsynchIO::~AsynchIO() {
+ std::for_each( bufferQueue.begin(), bufferQueue.end(), deleter());
+ std::for_each( writeQueue.begin(), writeQueue.end(), deleter());
+}
+
+void AsynchIO::queueForDeletion() {
+ queuedDelete = true;
+ if (opsInProgress > 0) {
+ QPID_LOG(info, "Delete AsynchIO queued; ops in progress");
+ // AsynchIOHandler calls this then deletes itself; don't do any more
+ // callbacks.
+ readCallback = 0;
+ eofCallback = 0;
+ disCallback = 0;
+ closedCallback = 0;
+ emptyCallback = 0;
+ idleCallback = 0;
+ }
+ else {
+ delete this;
+ }
+}
+
+void AsynchIO::start(Poller::shared_ptr poller0) {
+ poller = poller0;
+ poller->monitorHandle(PollerHandle(socket), Poller::INPUT);
+ if (writeQueue.size() > 0) // Already have data queued for write
+ notifyPendingWrite();
+ startReading();
+}
+
+void AsynchIO::queueReadBuffer(AsynchIO::BufferBase* buff) {
+ assert(buff);
+ buff->dataStart = 0;
+ buff->dataCount = 0;
+ QLock l(bufferQueueLock);
+ bufferQueue.push_back(buff);
+}
+
+void AsynchIO::unread(AsynchIO::BufferBase* buff) {
+ assert(buff);
+ if (buff->dataStart != 0) {
+ memmove(buff->bytes, buff->bytes+buff->dataStart, buff->dataCount);
+ buff->dataStart = 0;
+ }
+ QLock l(bufferQueueLock);
+ bufferQueue.push_front(buff);
+}
+
+void AsynchIO::queueWrite(AsynchIO::BufferBase* buff) {
+ assert(buff);
+ QLock l(bufferQueueLock);
+ writeQueue.push_back(buff);
+ if (!writeInProgress)
+ notifyPendingWrite();
+}
+
+void AsynchIO::notifyPendingWrite() {
+ // This method is generally called from a processing thread; transfer
+ // work on this to an I/O thread. Much of the upper layer code assumes
+ // that all I/O-related things happen in an I/O thread.
+ if (poller == 0) // Not really going yet...
+ return;
+
+ InterlockedIncrement(&opsInProgress);
+ PollerHandle ph(CallbackHandle(boost::bind(&AsynchIO::completion, this, _1)));
+ poller->monitorHandle(ph, Poller::OUTPUT);
+}
+
+void AsynchIO::queueWriteClose() {
+ queuedClose = true;
+ if (!writeInProgress)
+ notifyPendingWrite();
+}
+
+bool AsynchIO::writeQueueEmpty() {
+ QLock l(bufferQueueLock);
+ return writeQueue.size() == 0;
+}
+
+/*
+ * Initiate a read operation. AsynchIO::readComplete() will be
+ * called when the read is complete and data is available.
+ */
+void AsynchIO::startReading() {
+ if (queuedDelete)
+ return;
+
+ // (Try to) get a buffer; look on the front since there may be an
+ // "unread" one there with data remaining from last time.
+ AsynchIO::BufferBase *buff = 0;
+ {
+ QLock l(bufferQueueLock);
+
+ if (!bufferQueue.empty()) {
+ buff = bufferQueue.front();
+ assert(buff);
+ bufferQueue.pop_front();
+ }
+ }
+ if (buff != 0) {
+ int readCount = buff->byteCount - buff->dataCount;
+ AsynchReadResult *result =
+ new AsynchReadResult(boost::bind(&AsynchIO::completion, this, _1),
+ buff,
+ readCount);
+ DWORD bytesReceived = 0, flags = 0;
+ InterlockedIncrement(&opsInProgress);
+ int status = WSARecv(toSocketHandle(socket),
+ const_cast<LPWSABUF>(result->getWSABUF()), 1,
+ &bytesReceived,
+ &flags,
+ result->overlapped(),
+ 0);
+ if (status != 0) {
+ int error = WSAGetLastError();
+ if (error != WSA_IO_PENDING) {
+ result->failure(error);
+ result = 0; // result is invalid here
+ return;
+ }
+ }
+ // On status 0 or WSA_IO_PENDING, completion will handle the rest.
+ }
+ else {
+ notifyBuffersEmpty();
+ }
+ return;
+}
+
+// stopReading was added to prevent a race condition with read-credit on Linux.
+// It may or may not be required on windows.
+//
+// AsynchIOHandler::readbuff() calls stopReading() inside the same
+// critical section that protects startReading() in
+// AsynchIOHandler::giveReadCredit().
+//
+void AsynchIO::stopReading() {}
+
+// Queue the specified callback for invocation from an I/O thread.
+void AsynchIO::requestCallback(RequestCallback callback) {
+ // This method is generally called from a processing thread; transfer
+ // work on this to an I/O thread. Much of the upper layer code assumes
+ // that all I/O-related things happen in an I/O thread.
+ if (poller == 0) // Not really going yet...
+ return;
+
+ InterlockedIncrement(&opsInProgress);
+ PollerHandle ph(CallbackHandle(
+ boost::bind(&AsynchIO::completion, this, _1),
+ callback));
+ poller->monitorHandle(ph, Poller::INPUT);
+}
+
+/**
+ * Return a queued buffer if there are enough to spare.
+ */
+AsynchIO::BufferBase* AsynchIO::getQueuedBuffer() {
+ QLock l(bufferQueueLock);
+ // Always keep at least one buffer (it might have data that was
+ // "unread" in it).
+ if (bufferQueue.size() <= 1)
+ return 0;
+ BufferBase* buff = bufferQueue.back();
+ assert(buff);
+ bufferQueue.pop_back();
+ return buff;
+}
+
+void AsynchIO::notifyEof(void) {
+ if (eofCallback)
+ eofCallback(*this);
+}
+
+void AsynchIO::notifyDisconnect(void) {
+ if (disCallback)
+ disCallback(*this);
+}
+
+void AsynchIO::notifyClosed(void) {
+ if (closedCallback)
+ closedCallback(*this, socket);
+}
+
+void AsynchIO::notifyBuffersEmpty(void) {
+ if (emptyCallback)
+ emptyCallback(*this);
+}
+
+void AsynchIO::notifyIdle(void) {
+ if (idleCallback)
+ idleCallback(*this);
+}
+
+/*
+ * Asynch reader/writer using overlapped I/O
+ */
+
+void AsynchIO::startWrite(AsynchIO::BufferBase* buff) {
+ writeInProgress = true;
+ InterlockedIncrement(&opsInProgress);
+ int writeCount = buff->byteCount-buff->dataCount;
+ AsynchWriteResult *result =
+ new AsynchWriteResult(boost::bind(&AsynchIO::completion, this, _1),
+ buff,
+ buff->dataCount);
+ DWORD bytesSent = 0;
+ int status = WSASend(toSocketHandle(socket),
+ const_cast<LPWSABUF>(result->getWSABUF()), 1,
+ &bytesSent,
+ 0,
+ result->overlapped(),
+ 0);
+ if (status != 0) {
+ int error = WSAGetLastError();
+ if (error != WSA_IO_PENDING) {
+ result->failure(error); // Also decrements in-progress count
+ result = 0; // result is invalid here
+ return;
+ }
+ }
+ // On status 0 or WSA_IO_PENDING, completion will handle the rest.
+ return;
+}
+
+/*
+ * Close the socket and callback to say we've done it
+ */
+void AsynchIO::close(void) {
+ socket.close();
+ notifyClosed();
+}
+
+void AsynchIO::readComplete(AsynchReadResult *result) {
+ int status = result->getStatus();
+ size_t bytes = result->getTransferred();
+ if (status == 0 && bytes > 0) {
+ bool restartRead = true; // May not if receiver doesn't want more
+ if (readCallback)
+ readCallback(*this, result->getBuff());
+ if (restartRead)
+ startReading();
+ }
+ else {
+ // No data read, so put the buffer back. It may be partially filled,
+ // so "unread" it back to the front of the queue.
+ unread(result->getBuff());
+ if (status == 0)
+ notifyEof();
+ else
+ notifyDisconnect();
+ }
+}
+
+/*
+ * NOTE - this completion is called for completed writes and also when
+ * a write is desired. The difference is in the buff - if a write is desired
+ * the buff is 0.
+ */
+void AsynchIO::writeComplete(AsynchWriteResult *result) {
+ int status = result->getStatus();
+ size_t bytes = result->getTransferred();
+ AsynchIO::BufferBase *buff = result->getBuff();
+ if (buff != 0) {
+ writeInProgress = false;
+ if (status == 0 && bytes > 0) {
+ if (bytes < result->getRequested()) // Still more to go; resubmit
+ startWrite(buff);
+ else
+ queueReadBuffer(buff); // All done; back to the pool
+ }
+ else {
+ // An error... if it's a connection close, ignore it - it will be
+ // noticed and handled on a read completion any moment now.
+ // What to do with real error??? Save the Buffer?
+ }
+ }
+
+ // If there are no writes outstanding, check for more writes to initiate
+ // (either queued or via idle). The opsInProgress count is handled in
+ // completion()
+ if (!writeInProgress) {
+ bool writing = false;
+ {
+ QLock l(bufferQueueLock);
+ if (writeQueue.size() > 0) {
+ buff = writeQueue.front();
+ assert(buff);
+ writeQueue.pop_front();
+ startWrite(buff);
+ writing = true;
+ }
+ }
+ if (!writing && !queuedClose) {
+ notifyIdle();
+ }
+ }
+ return;
+}
+
+void AsynchIO::completion(AsynchIoResult *result) {
+ {
+ ScopedLock<Mutex> l(completionLock);
+ if (working) {
+ completionQueue.push(result);
+ return;
+ }
+
+ // First thread in with something to do; note we're working then keep
+ // handling completions.
+ working = true;
+ while (result != 0) {
+ // New scope to unlock temporarily.
+ {
+ ScopedUnlock<Mutex> ul(completionLock);
+ AsynchReadResult *r = dynamic_cast<AsynchReadResult*>(result);
+ if (r != 0)
+ readComplete(r);
+ else {
+ AsynchWriteResult *w =
+ dynamic_cast<AsynchWriteResult*>(result);
+ if (w != 0)
+ writeComplete(w);
+ else {
+ AsynchCallbackRequest *req =
+ dynamic_cast<AsynchCallbackRequest*>(result);
+ req->reqCallback(*this);
+ }
+ }
+ delete result;
+ result = 0;
+ InterlockedDecrement(&opsInProgress);
+ }
+ // Lock is held again.
+ if (completionQueue.empty())
+ continue;
+ result = completionQueue.front();
+ completionQueue.pop();
+ }
+ working = false;
+ }
+ // Lock released; ok to close if ops are done and close requested.
+ // Layer above will call back to queueForDeletion() if it hasn't
+ // already been done. If it already has, go ahead and delete.
+ if (opsInProgress == 0) {
+ if (queuedClose)
+ // close() may cause a delete; don't trust 'this' on return
+ close();
+ else if (queuedDelete)
+ delete this;
+ }
+}
+
+} // namespace windows
+
+AsynchIO* qpid::sys::AsynchIO::create(const Socket& s,
+ AsynchIO::ReadCallback rCb,
+ AsynchIO::EofCallback eofCb,
+ AsynchIO::DisconnectCallback disCb,
+ AsynchIO::ClosedCallback cCb,
+ AsynchIO::BuffersEmptyCallback eCb,
+ AsynchIO::IdleCallback iCb)
+{
+ return new qpid::sys::windows::AsynchIO(s, rCb, eofCb, disCb, cCb, eCb, iCb);
+}
+
+}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/windows/AsynchIoResult.h b/cpp/src/qpid/sys/windows/AsynchIoResult.h
new file mode 100755
index 0000000000..66c89efc11
--- /dev/null
+++ b/cpp/src/qpid/sys/windows/AsynchIoResult.h
@@ -0,0 +1,204 @@
+#ifndef _windows_asynchIoResult_h
+#define _windows_asynchIoResult_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/AsynchIO.h"
+#include "qpid/sys/Socket.h"
+#include <memory.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+namespace qpid {
+namespace sys {
+namespace windows {
+
+/*
+ * AsynchIoResult defines the class that receives the result of an
+ * asynchronous I/O operation, either send/recv or accept/connect.
+ *
+ * Operation factories should set one of these up before beginning the
+ * operation. Poller knows how to dispatch completion to this class.
+ * This class must be subclassed for needed operations; this class provides
+ * an interface only and cannot be instantiated.
+ *
+ * This class is tied to Windows; it inherits from OVERLAPPED so that the
+ * IocpPoller can cast OVERLAPPED pointers back to AsynchIoResult and call
+ * the completion handler.
+ */
+class AsynchResult : private OVERLAPPED {
+public:
+ LPOVERLAPPED overlapped(void) { return this; }
+ static AsynchResult* from_overlapped(LPOVERLAPPED ol) {
+ return static_cast<AsynchResult*>(ol);
+ }
+ virtual void success (size_t bytesTransferred) {
+ bytes = bytesTransferred;
+ status = 0;
+ complete();
+ }
+ virtual void failure (int error) {
+ bytes = 0;
+ status = error;
+ complete();
+ }
+ size_t getTransferred(void) const { return bytes; }
+ int getStatus(void) const { return status; }
+
+protected:
+ AsynchResult() : bytes(0), status(0)
+ { memset(overlapped(), 0, sizeof(OVERLAPPED)); }
+ ~AsynchResult() {}
+ virtual void complete(void) = 0;
+
+ size_t bytes;
+ int status;
+};
+
+class AsynchAcceptor;
+
+class AsynchAcceptResult : public AsynchResult {
+
+ friend class AsynchAcceptor;
+
+public:
+ AsynchAcceptResult(qpid::sys::AsynchAcceptor::Callback cb,
+ AsynchAcceptor *acceptor,
+ SOCKET listener);
+ virtual void success (size_t bytesTransferred);
+ virtual void failure (int error);
+
+private:
+ virtual void complete(void) {} // No-op for this class.
+
+ std::auto_ptr<qpid::sys::Socket> newSocket;
+ qpid::sys::AsynchAcceptor::Callback callback;
+ AsynchAcceptor *acceptor;
+ SOCKET listener;
+
+ // AcceptEx needs a place to write the local and remote addresses
+ // when accepting the connection. Place those here; get enough for
+ // IPv6 addresses, even if the socket is IPv4.
+ enum { SOCKADDRMAXLEN = sizeof sockaddr_in6 + 16,
+ SOCKADDRBUFLEN = 2 * SOCKADDRMAXLEN };
+ char addressBuffer[SOCKADDRBUFLEN];
+};
+
+class AsynchIoResult : public AsynchResult {
+public:
+ typedef boost::function1<void, AsynchIoResult *> Completer;
+
+ virtual ~AsynchIoResult() {}
+ qpid::sys::AsynchIO::BufferBase *getBuff(void) const { return iobuff; }
+ size_t getRequested(void) const { return requested; }
+ const WSABUF *getWSABUF(void) const { return &wsabuf; }
+
+protected:
+ void setBuff (qpid::sys::AsynchIO::BufferBase *buffer) { iobuff = buffer; }
+
+protected:
+ AsynchIoResult(Completer cb,
+ qpid::sys::AsynchIO::BufferBase *buff, size_t length)
+ : completionCallback(cb), iobuff(buff), requested(length) {}
+
+ virtual void complete(void) = 0;
+ WSABUF wsabuf;
+ Completer completionCallback;
+
+private:
+ qpid::sys::AsynchIO::BufferBase *iobuff;
+ size_t requested; // Number of bytes in original I/O request
+};
+
+class AsynchReadResult : public AsynchIoResult {
+
+ // complete() updates buffer then does completion callback.
+ virtual void complete(void) {
+ getBuff()->dataCount += bytes;
+ completionCallback(this);
+ }
+
+public:
+ AsynchReadResult(AsynchIoResult::Completer cb,
+ qpid::sys::AsynchIO::BufferBase *buff,
+ size_t length)
+ : AsynchIoResult(cb, buff, length) {
+ wsabuf.buf = buff->bytes + buff->dataCount;
+ wsabuf.len = length;
+ }
+};
+
+class AsynchWriteResult : public AsynchIoResult {
+
+ // complete() updates buffer then does completion callback.
+ virtual void complete(void) {
+ qpid::sys::AsynchIO::BufferBase *b = getBuff();
+ b->dataStart += bytes;
+ b->dataCount -= bytes;
+ completionCallback(this);
+ }
+
+public:
+ AsynchWriteResult(AsynchIoResult::Completer cb,
+ qpid::sys::AsynchIO::BufferBase *buff,
+ size_t length)
+ : AsynchIoResult(cb, buff, length) {
+ wsabuf.buf = buff ? buff->bytes : 0;
+ wsabuf.len = length;
+ }
+};
+
+class AsynchWriteWanted : public AsynchWriteResult {
+
+ // complete() just does completion callback; no buffers used.
+ virtual void complete(void) {
+ completionCallback(this);
+ }
+
+public:
+ AsynchWriteWanted(AsynchIoResult::Completer cb)
+ : AsynchWriteResult(cb, 0, 0) {
+ wsabuf.buf = 0;
+ wsabuf.len = 0;
+ }
+};
+
+class AsynchCallbackRequest : public AsynchIoResult {
+ // complete() needs to simply call the completionCallback; no buffers.
+ virtual void complete(void) {
+ completionCallback(this);
+ }
+
+public:
+ AsynchCallbackRequest(AsynchIoResult::Completer cb,
+ qpid::sys::AsynchIO::RequestCallback reqCb)
+ : AsynchIoResult(cb, 0, 0), reqCallback(reqCb) {
+ wsabuf.buf = 0;
+ wsabuf.len = 0;
+ }
+
+ qpid::sys::AsynchIO::RequestCallback reqCallback;
+};
+
+}}} // qpid::sys::windows
+
+#endif /*!_windows_asynchIoResult_h*/
diff --git a/cpp/src/qpid/sys/windows/FileSysDir.cpp b/cpp/src/qpid/sys/windows/FileSysDir.cpp
new file mode 100644
index 0000000000..88f1637d48
--- /dev/null
+++ b/cpp/src/qpid/sys/windows/FileSysDir.cpp
@@ -0,0 +1,53 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/sys/FileSysDir.h"
+#include "qpid/sys/StrError.h"
+#include "qpid/Exception.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <direct.h>
+#include <errno.h>
+
+namespace qpid {
+namespace sys {
+
+bool FileSysDir::exists (void) const
+{
+ const char *cpath = dirPath.c_str ();
+ struct _stat s;
+ if (::_stat(cpath, &s)) {
+ if (errno == ENOENT) {
+ return false;
+ }
+ throw qpid::Exception (strError(errno) +
+ ": Can't check directory: " + dirPath);
+ }
+ if (s.st_mode & _S_IFDIR)
+ return true;
+ throw qpid::Exception(dirPath + " is not a directory");
+}
+
+void FileSysDir::mkdir(void)
+{
+ if (::_mkdir(dirPath.c_str()) == -1)
+ throw Exception ("Can't create directory: " + dirPath);
+}
+
+}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/windows/IOHandle.cpp b/cpp/src/qpid/sys/windows/IOHandle.cpp
new file mode 100755
index 0000000000..250737cb99
--- /dev/null
+++ b/cpp/src/qpid/sys/windows/IOHandle.cpp
@@ -0,0 +1,42 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/IOHandle.h"
+#include "qpid/sys/windows/IoHandlePrivate.h"
+#include <windows.h>
+
+namespace qpid {
+namespace sys {
+
+SOCKET toFd(const IOHandlePrivate* h)
+{
+ return h->fd;
+}
+
+IOHandle::IOHandle(IOHandlePrivate* h) :
+ impl(h)
+{}
+
+IOHandle::~IOHandle() {
+ delete impl;
+}
+
+}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/windows/IoHandlePrivate.h b/cpp/src/qpid/sys/windows/IoHandlePrivate.h
new file mode 100755
index 0000000000..5943db5cc7
--- /dev/null
+++ b/cpp/src/qpid/sys/windows/IoHandlePrivate.h
@@ -0,0 +1,61 @@
+#ifndef _sys_windows_IoHandlePrivate_h
+#define _sys_windows_IoHandlePrivate_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/AsynchIO.h"
+#include "qpid/sys/windows/AsynchIoResult.h"
+#include "qpid/CommonImportExport.h"
+
+#include <winsock2.h>
+
+namespace qpid {
+namespace sys {
+
+// Private fd related implementation details
+// There should be either a valid socket handle or a completer callback.
+// Handle is used to associate with poller's iocp; completer is used to
+// inject a completion that will very quickly trigger a callback to the
+// completer from an I/O thread. If the callback mechanism is used, there
+// can be a RequestCallback set - this carries the callback object through
+// from AsynchIO::requestCallback() through to the I/O completion processing.
+class IOHandlePrivate {
+ friend QPID_COMMON_EXTERN SOCKET toSocketHandle(const Socket& s);
+ static IOHandlePrivate* getImpl(const IOHandle& h);
+
+public:
+ IOHandlePrivate(SOCKET f = INVALID_SOCKET,
+ windows::AsynchIoResult::Completer cb = 0,
+ AsynchIO::RequestCallback reqCallback = 0) :
+ fd(f), event(cb), cbRequest(reqCallback)
+ {}
+
+ SOCKET fd;
+ windows::AsynchIoResult::Completer event;
+ AsynchIO::RequestCallback cbRequest;
+};
+
+QPID_COMMON_EXTERN SOCKET toSocketHandle(const Socket& s);
+
+}}
+
+#endif /* _sys_windows_IoHandlePrivate_h */
diff --git a/cpp/src/qpid/sys/windows/IocpPoller.cpp b/cpp/src/qpid/sys/windows/IocpPoller.cpp
new file mode 100755
index 0000000000..4fcc9155f1
--- /dev/null
+++ b/cpp/src/qpid/sys/windows/IocpPoller.cpp
@@ -0,0 +1,214 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/sys/Poller.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Dispatcher.h"
+
+#include "qpid/sys/windows/AsynchIoResult.h"
+#include "qpid/sys/windows/IoHandlePrivate.h"
+#include "qpid/sys/windows/check.h"
+
+#include <winsock2.h>
+#include <windows.h>
+
+#include <assert.h>
+#include <vector>
+#include <exception>
+
+namespace qpid {
+namespace sys {
+
+class PollerHandlePrivate {
+ friend class Poller;
+ friend class PollerHandle;
+
+ SOCKET fd;
+ windows::AsynchIoResult::Completer cb;
+ AsynchIO::RequestCallback cbRequest;
+
+ PollerHandlePrivate(SOCKET f,
+ windows::AsynchIoResult::Completer cb0 = 0,
+ AsynchIO::RequestCallback rcb = 0)
+ : fd(f), cb(cb0), cbRequest(rcb)
+ {
+ }
+
+};
+
+PollerHandle::PollerHandle(const IOHandle& h) :
+ impl(new PollerHandlePrivate(toSocketHandle(static_cast<const Socket&>(h)), h.impl->event, h.impl->cbRequest))
+{}
+
+PollerHandle::~PollerHandle() {
+ delete impl;
+}
+
+/**
+ * Concrete implementation of Poller to use the Windows I/O Completion
+ * port (IOCP) facility.
+ */
+class PollerPrivate {
+ friend class Poller;
+
+ const HANDLE iocp;
+
+ // The number of threads running the event loop.
+ volatile LONG threadsRunning;
+
+ // Shutdown request is handled by setting isShutdown and injecting a
+ // well-formed completion event into the iocp.
+ bool isShutdown;
+
+ PollerPrivate() :
+ iocp(::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0)),
+ threadsRunning(0),
+ isShutdown(false) {
+ QPID_WINDOWS_CHECK_NULL(iocp);
+ }
+
+ ~PollerPrivate() {
+ // It's probably okay to ignore any errors here as there can't be
+ // data loss
+ ::CloseHandle(iocp);
+ }
+};
+
+void Poller::shutdown() {
+ // Allow sloppy code to shut us down more than once.
+ if (impl->isShutdown)
+ return;
+ ULONG_PTR key = 1; // Tell wait() it's a shutdown, not I/O
+ PostQueuedCompletionStatus(impl->iocp, 0, key, 0);
+}
+
+bool Poller::interrupt(PollerHandle&) {
+ return false; // There's no concept of a registered handle.
+}
+
+void Poller::run() {
+ do {
+ Poller::Event event = this->wait();
+
+ // Handle shutdown
+ switch (event.type) {
+ case Poller::SHUTDOWN:
+ return;
+ break;
+ case Poller::INVALID: // On any type of success or fail completion
+ break;
+ default:
+ // This should be impossible
+ assert(false);
+ }
+ } while (true);
+}
+
+void Poller::monitorHandle(PollerHandle& handle, Direction dir) {
+ HANDLE h = (HANDLE)(handle.impl->fd);
+ if (h != INVALID_HANDLE_VALUE) {
+ HANDLE iocpHandle = ::CreateIoCompletionPort (h, impl->iocp, 0, 0);
+ QPID_WINDOWS_CHECK_NULL(iocpHandle);
+ }
+ else {
+ // INPUT is used to request a callback; OUTPUT to request a write
+ assert(dir == Poller::INPUT || dir == Poller::OUTPUT);
+
+ if (dir == Poller::OUTPUT) {
+ windows::AsynchWriteWanted *result =
+ new windows::AsynchWriteWanted(handle.impl->cb);
+ PostQueuedCompletionStatus(impl->iocp, 0, 0, result->overlapped());
+ }
+ else {
+ windows::AsynchCallbackRequest *result =
+ new windows::AsynchCallbackRequest(handle.impl->cb,
+ handle.impl->cbRequest);
+ PostQueuedCompletionStatus(impl->iocp, 0, 0, result->overlapped());
+ }
+ }
+}
+
+// All no-ops...
+void Poller::unmonitorHandle(PollerHandle& handle, Direction dir) {}
+void Poller::registerHandle(PollerHandle& handle) {}
+void Poller::unregisterHandle(PollerHandle& handle) {}
+
+Poller::Event Poller::wait(Duration timeout) {
+ DWORD timeoutMs = 0;
+ DWORD numTransferred = 0;
+ ULONG_PTR completionKey = 0;
+ OVERLAPPED *overlapped = 0;
+ windows::AsynchResult *result = 0;
+
+ // Wait for either an I/O operation to finish (thus signaling the
+ // IOCP handle) or a shutdown request to be made (thus signaling the
+ // shutdown event).
+ if (timeout == TIME_INFINITE)
+ timeoutMs = INFINITE;
+ else
+ timeoutMs = static_cast<DWORD>(timeout / TIME_MSEC);
+
+ InterlockedIncrement(&impl->threadsRunning);
+ bool goodOp = ::GetQueuedCompletionStatus (impl->iocp,
+ &numTransferred,
+ &completionKey,
+ &overlapped,
+ timeoutMs);
+ LONG remainingThreads = InterlockedDecrement(&impl->threadsRunning);
+ if (goodOp) {
+ // Dequeued a successful completion. If it's a posted packet from
+ // shutdown() the overlapped ptr is 0 and key is 1. Else downcast
+ // the OVERLAPPED pointer to an AsynchIoResult and call the
+ // completion handler.
+ if (overlapped == 0 && completionKey == 1) {
+ // If there are other threads still running this wait, re-post
+ // the completion.
+ if (remainingThreads > 0)
+ PostQueuedCompletionStatus(impl->iocp, 0, completionKey, 0);
+ return Event(0, SHUTDOWN);
+ }
+
+ result = windows::AsynchResult::from_overlapped(overlapped);
+ result->success (static_cast<size_t>(numTransferred));
+ }
+ else {
+ if (overlapped != 0) {
+ // Dequeued a completion for a failed operation. Downcast back
+ // to the result object and inform it that the operation failed.
+ DWORD status = ::GetLastError();
+ result = windows::AsynchResult::from_overlapped(overlapped);
+ result->failure (static_cast<int>(status));
+ }
+ }
+ return Event(0, INVALID); // TODO - this may need to be changed.
+
+}
+
+// Concrete constructors
+Poller::Poller() :
+ impl(new PollerPrivate())
+{}
+
+Poller::~Poller() {
+ delete impl;
+}
+
+}}
diff --git a/cpp/src/qpid/sys/windows/LockFile.cpp b/cpp/src/qpid/sys/windows/LockFile.cpp
new file mode 100755
index 0000000000..048c2d5b18
--- /dev/null
+++ b/cpp/src/qpid/sys/windows/LockFile.cpp
@@ -0,0 +1,64 @@
+/*
+ *
+ * Copyright (c) 2008 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/sys/LockFile.h"
+#include "qpid/sys/windows/check.h"
+
+#include <windows.h>
+
+namespace qpid {
+namespace sys {
+
+class LockFilePrivate {
+ friend class LockFile;
+
+ HANDLE fd;
+
+public:
+ LockFilePrivate(HANDLE f) : fd(f) {}
+};
+
+LockFile::LockFile(const std::string& path_, bool create)
+ : path(path_), created(create) {
+
+ HANDLE h = ::CreateFile(path.c_str(),
+ create ? (GENERIC_READ|GENERIC_WRITE) : GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ 0, /* Default security */
+ create ? OPEN_ALWAYS : OPEN_EXISTING,
+ FILE_FLAG_DELETE_ON_CLOSE, /* Delete file when closed */
+ NULL);
+ if (h == INVALID_HANDLE_VALUE)
+ throw qpid::Exception(path + ": " + qpid::sys::strError(GetLastError()));
+
+ // Lock up to 4Gb
+ if (!::LockFile(h, 0, 0, 0xffffffff, 0))
+ throw qpid::Exception(path + ": " + qpid::sys::strError(GetLastError()));
+ impl.reset(new LockFilePrivate(h));
+}
+
+LockFile::~LockFile() {
+ if (impl) {
+ if (impl->fd != INVALID_HANDLE_VALUE) {
+ ::UnlockFile(impl->fd, 0, 0, 0xffffffff, 0);
+ ::CloseHandle(impl->fd);
+ }
+ }
+}
+
+}} /* namespace qpid::sys */
diff --git a/cpp/src/qpid/sys/windows/PipeHandle.cpp b/cpp/src/qpid/sys/windows/PipeHandle.cpp
new file mode 100755
index 0000000000..062458ae5f
--- /dev/null
+++ b/cpp/src/qpid/sys/windows/PipeHandle.cpp
@@ -0,0 +1,101 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES 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/sys/PipeHandle.h"
+#include "qpid/sys/windows/check.h"
+#include <winsock2.h>
+
+namespace qpid {
+namespace sys {
+
+PipeHandle::PipeHandle(bool nonBlocking) {
+
+ SOCKET listener, pair[2];
+ struct sockaddr_in addr;
+ int err;
+ int addrlen = sizeof(addr);
+ pair[0] = pair[1] = INVALID_SOCKET;
+ if ((listener = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
+ throw QPID_WINDOWS_ERROR(WSAGetLastError());
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ addr.sin_port = 0;
+
+ err = bind(listener, (const struct sockaddr*) &addr, sizeof(addr));
+ if (err == SOCKET_ERROR) {
+ err = WSAGetLastError();
+ closesocket(listener);
+ throw QPID_WINDOWS_ERROR(err);
+ }
+
+ err = getsockname(listener, (struct sockaddr*) &addr, &addrlen);
+ if (err == SOCKET_ERROR) {
+ err = WSAGetLastError();
+ closesocket(listener);
+ throw QPID_WINDOWS_ERROR(err);
+ }
+
+ try {
+ if (listen(listener, 1) == SOCKET_ERROR)
+ throw QPID_WINDOWS_ERROR(WSAGetLastError());
+ if ((pair[0] = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
+ throw QPID_WINDOWS_ERROR(WSAGetLastError());
+ if (connect(pair[0], (const struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
+ throw QPID_WINDOWS_ERROR(WSAGetLastError());
+ if ((pair[1] = accept(listener, NULL, NULL)) == INVALID_SOCKET)
+ throw QPID_WINDOWS_ERROR(WSAGetLastError());
+
+ closesocket(listener);
+ writeFd = pair[0];
+ readFd = pair[1];
+ }
+ catch (...) {
+ closesocket(listener);
+ if (pair[0] != INVALID_SOCKET)
+ closesocket(pair[0]);
+ throw;
+ }
+
+ // Set the socket to non-blocking
+ if (nonBlocking) {
+ unsigned long nonblock = 1;
+ ioctlsocket(readFd, FIONBIO, &nonblock);
+ }
+}
+
+PipeHandle::~PipeHandle() {
+ closesocket(readFd);
+ closesocket(writeFd);
+}
+
+int PipeHandle::read(void* buf, size_t bufSize) {
+ return ::recv(readFd, (char *)buf, bufSize, 0);
+}
+
+int PipeHandle::write(const void* buf, size_t bufSize) {
+ return ::send(writeFd, (const char *)buf, bufSize, 0);
+}
+
+int PipeHandle::getReadHandle() {
+ return readFd;
+}
+
+}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/windows/PollableCondition.cpp b/cpp/src/qpid/sys/windows/PollableCondition.cpp
new file mode 100644
index 0000000000..5ccc136bd1
--- /dev/null
+++ b/cpp/src/qpid/sys/windows/PollableCondition.cpp
@@ -0,0 +1,116 @@
+#ifndef QPID_SYS_WINDOWS_POLLABLECONDITION_CPP
+#define QPID_SYS_WINDOWS_POLLABLECONDITION_CPP
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/PollableCondition.h"
+#include "qpid/sys/IOHandle.h"
+#include "qpid/sys/windows/AsynchIoResult.h"
+#include "qpid/sys/windows/IoHandlePrivate.h"
+
+#include <boost/bind.hpp>
+#include <windows.h>
+
+namespace qpid {
+namespace sys {
+
+// PollableConditionPrivate will reuse the IocpPoller's ability to queue
+// a completion to the IOCP and have it dispatched to the completer callback
+// noted in the IOHandlePrivate when the request is queued. The
+// AsynchCallbackRequest object is not really used - we already have the
+// desired callback for the user of PollableCondition.
+class PollableConditionPrivate : private IOHandle {
+ friend class PollableCondition;
+
+private:
+ PollableConditionPrivate(const sys::PollableCondition::Callback& cb,
+ sys::PollableCondition& parent,
+ const boost::shared_ptr<sys::Poller>& poller);
+ ~PollableConditionPrivate();
+
+ void poke();
+ void dispatch(windows::AsynchIoResult *result);
+
+private:
+ PollableCondition::Callback cb;
+ PollableCondition& parent;
+ boost::shared_ptr<sys::Poller> poller;
+ LONG isSet;
+ LONG armed;
+};
+
+PollableConditionPrivate::PollableConditionPrivate(const sys::PollableCondition::Callback& cb,
+ sys::PollableCondition& parent,
+ const boost::shared_ptr<sys::Poller>& poller)
+ : IOHandle(new sys::IOHandlePrivate(INVALID_SOCKET,
+ boost::bind(&PollableConditionPrivate::dispatch, this, _1))),
+ cb(cb), parent(parent), poller(poller), isSet(0), armed(0)
+{
+}
+
+PollableConditionPrivate::~PollableConditionPrivate()
+{
+}
+
+void PollableConditionPrivate::poke()
+{
+ if (!armed)
+ return;
+
+ // monitorHandle will queue a completion for the IOCP; when it's handled, a
+ // poller thread will call back to dispatch() below.
+ PollerHandle ph(*this);
+ poller->monitorHandle(ph, Poller::INPUT);
+}
+
+void PollableConditionPrivate::dispatch(windows::AsynchIoResult *result)
+{
+ delete result; // Poller::monitorHandle() allocates this
+ cb(parent);
+}
+
+ /* PollableCondition */
+
+PollableCondition::PollableCondition(const Callback& cb,
+ const boost::shared_ptr<sys::Poller>& poller)
+ : impl(new PollableConditionPrivate(cb, *this, poller))
+{
+}
+
+PollableCondition::~PollableCondition()
+{
+ delete impl;
+}
+
+void PollableCondition::set() {
+ // Add one to the set count and poke it to provoke a callback
+ ::InterlockedIncrement(&impl->isSet);
+ impl->poke();
+}
+
+void PollableCondition::clear() {
+ ::InterlockedExchange(&impl->isSet, 0);
+}
+
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_WINDOWS_POLLABLECONDITION_CPP*/
diff --git a/cpp/src/qpid/sys/windows/Shlib.cpp b/cpp/src/qpid/sys/windows/Shlib.cpp
new file mode 100644
index 0000000000..38027de93f
--- /dev/null
+++ b/cpp/src/qpid/sys/windows/Shlib.cpp
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Shlib.h"
+#include "qpid/Exception.h"
+#include "qpid/sys/windows/check.h"
+#include <windows.h>
+
+namespace qpid {
+namespace sys {
+
+void Shlib::load(const char* name) {
+ HMODULE h = LoadLibrary(name);
+ if (h == NULL) {
+ throw QPID_WINDOWS_ERROR(GetLastError());
+ }
+ handle = static_cast<void*>(h);
+}
+
+void Shlib::unload() {
+ if (handle) {
+ if (FreeLibrary(static_cast<HMODULE>(handle)) == 0) {
+ throw QPID_WINDOWS_ERROR(GetLastError());
+ }
+ handle = 0;
+ }
+}
+
+void* Shlib::getSymbol(const char* name) {
+ void* sym = GetProcAddress(static_cast<HMODULE>(handle), name);
+ if (sym == NULL)
+ throw QPID_WINDOWS_ERROR(GetLastError());
+ return sym;
+}
+
+}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/windows/Socket.cpp b/cpp/src/qpid/sys/windows/Socket.cpp
new file mode 100755
index 0000000000..11fb8b4133
--- /dev/null
+++ b/cpp/src/qpid/sys/windows/Socket.cpp
@@ -0,0 +1,343 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/sys/Socket.h"
+#include "qpid/sys/SocketAddress.h"
+#include "qpid/sys/windows/IoHandlePrivate.h"
+#include "qpid/sys/windows/check.h"
+#include "qpid/sys/Time.h"
+
+#include <cstdlib>
+#include <string.h>
+
+#include <winsock2.h>
+
+#include <boost/format.hpp>
+#include <boost/lexical_cast.hpp>
+
+// Need to initialize WinSock. Ideally, this would be a singleton or embedded
+// in some one-time initialization function. I tried boost singleton and could
+// not get it to compile (and others located in google had the same problem).
+// So, this simple static with an interlocked increment will do for known
+// use cases at this time. Since this will only shut down winsock at process
+// termination, there may be some problems with client programs that also
+// expect to load and unload winsock, but we'll see...
+// If someone does get an easy-to-use singleton sometime, converting to it
+// may be preferable.
+
+namespace {
+
+static LONG volatile initialized = 0;
+
+class WinSockSetup {
+ // : public boost::details::pool::singleton_default<WinSockSetup> {
+
+public:
+ WinSockSetup() {
+ LONG timesEntered = InterlockedIncrement(&initialized);
+ if (timesEntered > 1)
+ return;
+ err = 0;
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
+ /* Request WinSock 2.2 */
+ wVersionRequested = MAKEWORD(2, 2);
+ err = WSAStartup(wVersionRequested, &wsaData);
+ }
+
+ ~WinSockSetup() {
+ WSACleanup();
+ }
+
+public:
+ int error(void) const { return err; }
+
+protected:
+ DWORD err;
+};
+
+static WinSockSetup setup;
+
+} /* namespace */
+
+namespace qpid {
+namespace sys {
+
+namespace {
+
+std::string getName(SOCKET fd, bool local, bool includeService = false)
+{
+ sockaddr_in name; // big enough for any socket address
+ socklen_t namelen = sizeof(name);
+ if (local) {
+ QPID_WINSOCK_CHECK(::getsockname(fd, (sockaddr*)&name, &namelen));
+ } else {
+ QPID_WINSOCK_CHECK(::getpeername(fd, (sockaddr*)&name, &namelen));
+ }
+
+ char servName[NI_MAXSERV];
+ char dispName[NI_MAXHOST];
+ if (includeService) {
+ if (int rc = ::getnameinfo((sockaddr*)&name, namelen,
+ dispName, sizeof(dispName),
+ servName, sizeof(servName),
+ NI_NUMERICHOST | NI_NUMERICSERV) != 0)
+ throw qpid::Exception(QPID_MSG(gai_strerror(rc)));
+ return std::string(dispName) + ":" + std::string(servName);
+ } else {
+ if (int rc = ::getnameinfo((sockaddr*)&name, namelen,
+ dispName, sizeof(dispName),
+ 0, 0,
+ NI_NUMERICHOST) != 0)
+ throw qpid::Exception(QPID_MSG(gai_strerror(rc)));
+ return dispName;
+ }
+}
+
+std::string getService(SOCKET fd, bool local)
+{
+ sockaddr_in name; // big enough for any socket address
+ socklen_t namelen = sizeof(name);
+
+ if (local) {
+ QPID_WINSOCK_CHECK(::getsockname(fd, (sockaddr*)&name, &namelen));
+ } else {
+ QPID_WINSOCK_CHECK(::getpeername(fd, (sockaddr*)&name, &namelen));
+ }
+
+ char servName[NI_MAXSERV];
+ if (int rc = ::getnameinfo((sockaddr*)&name, namelen,
+ 0, 0,
+ servName, sizeof(servName),
+ NI_NUMERICHOST | NI_NUMERICSERV) != 0)
+ throw qpid::Exception(QPID_MSG(gai_strerror(rc)));
+ return servName;
+}
+} // namespace
+
+Socket::Socket() :
+ IOHandle(new IOHandlePrivate),
+ nonblocking(false),
+ nodelay(false)
+{
+ SOCKET& socket = impl->fd;
+ if (socket != INVALID_SOCKET) Socket::close();
+ SOCKET s = ::socket (PF_INET, SOCK_STREAM, 0);
+ if (s == INVALID_SOCKET) throw QPID_WINDOWS_ERROR(WSAGetLastError());
+ socket = s;
+}
+
+Socket::Socket(IOHandlePrivate* h) :
+ IOHandle(h),
+ nonblocking(false),
+ nodelay(false)
+{}
+
+void
+Socket::createSocket(const SocketAddress& sa) const
+{
+ SOCKET& socket = impl->fd;
+ if (socket != INVALID_SOCKET) Socket::close();
+
+ SOCKET s = ::socket (getAddrInfo(sa).ai_family,
+ getAddrInfo(sa).ai_socktype,
+ 0);
+ if (s == INVALID_SOCKET) throw QPID_WINDOWS_ERROR(WSAGetLastError());
+ socket = s;
+
+ try {
+ if (nonblocking) setNonblocking();
+ if (nodelay) setTcpNoDelay();
+ } catch (std::exception&) {
+ closesocket(s);
+ socket = INVALID_SOCKET;
+ throw;
+ }
+}
+
+void Socket::setTimeout(const Duration& interval) const
+{
+ const SOCKET& socket = impl->fd;
+ int64_t nanosecs = interval;
+ nanosecs /= (1000 * 1000); // nsecs -> usec -> msec
+ int msec = 0;
+ if (nanosecs > std::numeric_limits<int>::max())
+ msec = std::numeric_limits<int>::max();
+ else
+ msec = static_cast<int>(nanosecs);
+ setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&msec, sizeof(msec));
+ setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&msec, sizeof(msec));
+}
+
+void Socket::setNonblocking() const {
+ u_long nonblock = 1;
+ QPID_WINSOCK_CHECK(ioctlsocket(impl->fd, FIONBIO, &nonblock));
+}
+
+void Socket::connect(const std::string& host, uint16_t port) const
+{
+ SocketAddress sa(host, boost::lexical_cast<std::string>(port));
+ connect(sa);
+}
+
+void
+Socket::connect(const SocketAddress& addr) const
+{
+ const SOCKET& socket = impl->fd;
+ const addrinfo *addrs = &(getAddrInfo(addr));
+ int error = 0;
+ WSASetLastError(0);
+ while (addrs != 0) {
+ if ((::connect(socket, addrs->ai_addr, addrs->ai_addrlen) == 0) ||
+ (WSAGetLastError() == WSAEWOULDBLOCK))
+ break;
+ // Error... save this error code and see if there are other address
+ // to try before throwing the exception.
+ error = WSAGetLastError();
+ addrs = addrs->ai_next;
+ }
+ if (error)
+ throw qpid::Exception(QPID_MSG(strError(error) << ": " << connectname));
+}
+
+void
+Socket::close() const
+{
+ SOCKET& socket = impl->fd;
+ if (socket == INVALID_SOCKET) return;
+ QPID_WINSOCK_CHECK(closesocket(socket));
+ socket = INVALID_SOCKET;
+}
+
+
+int Socket::write(const void *buf, size_t count) const
+{
+ const SOCKET& socket = impl->fd;
+ int sent = ::send(socket, (const char *)buf, count, 0);
+ if (sent == SOCKET_ERROR)
+ return -1;
+ return sent;
+}
+
+int Socket::read(void *buf, size_t count) const
+{
+ const SOCKET& socket = impl->fd;
+ int received = ::recv(socket, (char *)buf, count, 0);
+ if (received == SOCKET_ERROR)
+ return -1;
+ return received;
+}
+
+int Socket::listen(uint16_t port, int backlog) const
+{
+ const SOCKET& socket = impl->fd;
+ BOOL yes=1;
+ QPID_WINSOCK_CHECK(setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)));
+ struct sockaddr_in name;
+ memset(&name, 0, sizeof(name));
+ name.sin_family = AF_INET;
+ name.sin_port = htons(port);
+ name.sin_addr.s_addr = 0;
+ if (::bind(socket, (struct sockaddr*)&name, sizeof(name)) == SOCKET_ERROR)
+ throw Exception(QPID_MSG("Can't bind to port " << port << ": " << strError(WSAGetLastError())));
+ if (::listen(socket, backlog) == SOCKET_ERROR)
+ throw Exception(QPID_MSG("Can't listen on port " << port << ": " << strError(WSAGetLastError())));
+
+ socklen_t namelen = sizeof(name);
+ QPID_WINSOCK_CHECK(::getsockname(socket, (struct sockaddr*)&name, &namelen));
+ return ntohs(name.sin_port);
+}
+
+Socket* Socket::accept() const
+{
+ SOCKET afd = ::accept(impl->fd, 0, 0);
+ if (afd != INVALID_SOCKET)
+ return new Socket(new IOHandlePrivate(afd));
+ else if (WSAGetLastError() == EAGAIN)
+ return 0;
+ else throw QPID_WINDOWS_ERROR(WSAGetLastError());
+}
+
+std::string Socket::getSockname() const
+{
+ return getName(impl->fd, true);
+}
+
+std::string Socket::getPeername() const
+{
+ return getName(impl->fd, false);
+}
+
+std::string Socket::getPeerAddress() const
+{
+ if (!connectname.empty())
+ return std::string (connectname);
+ return getName(impl->fd, false, true);
+}
+
+std::string Socket::getLocalAddress() const
+{
+ return getName(impl->fd, true, true);
+}
+
+uint16_t Socket::getLocalPort() const
+{
+ return atoi(getService(impl->fd, true).c_str());
+}
+
+uint16_t Socket::getRemotePort() const
+{
+ return atoi(getService(impl->fd, true).c_str());
+}
+
+int Socket::getError() const
+{
+ int result;
+ socklen_t rSize = sizeof (result);
+
+ QPID_WINSOCK_CHECK(::getsockopt(impl->fd, SOL_SOCKET, SO_ERROR, (char *)&result, &rSize));
+ return result;
+}
+
+void Socket::setTcpNoDelay() const
+{
+ int flag = 1;
+ int result = setsockopt(impl->fd,
+ IPPROTO_TCP,
+ TCP_NODELAY,
+ (char *)&flag,
+ sizeof(flag));
+ QPID_WINSOCK_CHECK(result);
+ nodelay = true;
+}
+
+inline IOHandlePrivate* IOHandlePrivate::getImpl(const qpid::sys::IOHandle &h)
+{
+ return h.impl;
+}
+
+SOCKET toSocketHandle(const Socket& s)
+{
+ return IOHandlePrivate::getImpl(s)->fd;
+}
+
+}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/windows/SocketAddress.cpp b/cpp/src/qpid/sys/windows/SocketAddress.cpp
new file mode 100644
index 0000000000..a3e03c9be8
--- /dev/null
+++ b/cpp/src/qpid/sys/windows/SocketAddress.cpp
@@ -0,0 +1,70 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/sys/SocketAddress.h"
+
+#include "qpid/sys/windows/check.h"
+
+#include <ws2tcpip.h>
+#include <string.h>
+
+namespace qpid {
+namespace sys {
+
+SocketAddress::SocketAddress(const std::string& host0, const std::string& port0) :
+ host(host0),
+ port(port0),
+ addrInfo(0)
+{
+ ::addrinfo hints;
+ ::memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET; // In order to allow AF_INET6 we'd have to change createTcp() as well
+ hints.ai_socktype = SOCK_STREAM;
+
+ const char* node = 0;
+ if (host.empty()) {
+ hints.ai_flags |= AI_PASSIVE;
+ } else {
+ node = host.c_str();
+ }
+ const char* service = port.empty() ? "0" : port.c_str();
+
+ int n = ::getaddrinfo(node, service, &hints, &addrInfo);
+ if (n != 0)
+ throw Exception(QPID_MSG("Cannot resolve " << host << ": " << ::gai_strerror(n)));
+}
+
+SocketAddress::~SocketAddress()
+{
+ ::freeaddrinfo(addrInfo);
+}
+
+std::string SocketAddress::asString() const
+{
+ return host + ":" + port;
+}
+
+const ::addrinfo& getAddrInfo(const SocketAddress& sa)
+{
+ return *sa.addrInfo;
+}
+
+}}
diff --git a/cpp/src/qpid/sys/windows/StrError.cpp b/cpp/src/qpid/sys/windows/StrError.cpp
new file mode 100755
index 0000000000..9c1bfcd79c
--- /dev/null
+++ b/cpp/src/qpid/sys/windows/StrError.cpp
@@ -0,0 +1,47 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/StrError.h"
+#include <string>
+#include <string.h>
+#include <windows.h>
+
+namespace qpid {
+namespace sys {
+
+std::string strError(int err) {
+ const size_t bufsize = 512;
+ char buf[bufsize];
+ if (0 == FormatMessage (FORMAT_MESSAGE_MAX_WIDTH_MASK
+ | FORMAT_MESSAGE_FROM_SYSTEM,
+ 0,
+ err,
+ 0, // Default language
+ buf,
+ bufsize,
+ 0))
+ {
+ strerror_s (buf, bufsize, err);
+ }
+ return std::string(buf);
+}
+
+}}
diff --git a/cpp/src/qpid/sys/windows/SystemInfo.cpp b/cpp/src/qpid/sys/windows/SystemInfo.cpp
new file mode 100755
index 0000000000..ea53fc199c
--- /dev/null
+++ b/cpp/src/qpid/sys/windows/SystemInfo.cpp
@@ -0,0 +1,201 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/* GetNativeSystemInfo call requires _WIN32_WINNT 0x0501 or higher */
+#ifndef _WIN32_WINNT
+# define _WIN32_WINNT 0x0501
+#endif
+
+#include "qpid/sys/IntegerTypes.h"
+#include "qpid/sys/SystemInfo.h"
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+#include <tlhelp32.h>
+
+#ifndef HOST_NAME_MAX
+# define HOST_NAME_MAX 256
+#endif
+
+namespace qpid {
+namespace sys {
+
+long SystemInfo::concurrency() {
+ SYSTEM_INFO sys_info;
+ ::GetSystemInfo (&sys_info);
+ long activeProcessors = 0;
+ DWORD_PTR mask = sys_info.dwActiveProcessorMask;
+ while (mask != 0) {
+ if (mask & 1)
+ ++activeProcessors;
+ mask >>= 1;
+ }
+ return activeProcessors;
+}
+
+bool SystemInfo::getLocalHostname (TcpAddress &address) {
+ char name[HOST_NAME_MAX];
+ if (::gethostname(name, sizeof(name)) != 0) {
+ errno = WSAGetLastError();
+ return false;
+ }
+ address.host = name;
+ return true;
+}
+
+void SystemInfo::getLocalIpAddresses (uint16_t port,
+ std::vector<Address> &addrList) {
+ enum { MAX_URL_INTERFACES = 100 };
+ static const std::string LOCALHOST("127.0.0.1");
+
+ SOCKET s = socket (PF_INET, SOCK_STREAM, 0);
+ if (s != INVALID_SOCKET) {
+ INTERFACE_INFO interfaces[MAX_URL_INTERFACES];
+ DWORD filledBytes = 0;
+ WSAIoctl (s,
+ SIO_GET_INTERFACE_LIST,
+ 0,
+ 0,
+ interfaces,
+ sizeof (interfaces),
+ &filledBytes,
+ 0,
+ 0);
+ unsigned int interfaceCount = filledBytes / sizeof (INTERFACE_INFO);
+ for (unsigned int i = 0; i < interfaceCount; ++i) {
+ if (interfaces[i].iiFlags & IFF_UP) {
+ std::string addr(inet_ntoa(interfaces[i].iiAddress.AddressIn.sin_addr));
+ if (addr != LOCALHOST)
+ addrList.push_back(TcpAddress(addr, port));
+ }
+ }
+ closesocket (s);
+ }
+}
+
+void SystemInfo::getSystemId (std::string &osName,
+ std::string &nodeName,
+ std::string &release,
+ std::string &version,
+ std::string &machine)
+{
+ osName = "Microsoft Windows";
+
+ char node[MAX_COMPUTERNAME_LENGTH + 1];
+ DWORD nodelen = MAX_COMPUTERNAME_LENGTH + 1;
+ GetComputerName (node, &nodelen);
+ nodeName = node;
+
+ OSVERSIONINFOEX vinfo;
+ vinfo.dwOSVersionInfoSize = sizeof(vinfo);
+ GetVersionEx ((OSVERSIONINFO *)&vinfo);
+
+ SYSTEM_INFO sinfo;
+ GetNativeSystemInfo(&sinfo);
+
+ switch(vinfo.dwMajorVersion) {
+ case 5:
+ switch(vinfo.dwMinorVersion) {
+ case 0:
+ release ="2000";
+ break;
+ case 1:
+ release = "XP";
+ break;
+ case 2:
+ if (sinfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ||
+ sinfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
+ release = "XP-64";
+ else
+ release = "Server 2003";
+ break;
+ default:
+ release = "Windows";
+ }
+ break;
+ case 6:
+ if (vinfo.wProductType == VER_NT_SERVER)
+ release = "Server 2008";
+ else
+ release = "Vista";
+ break;
+ default:
+ release = "Microsoft Windows";
+ }
+ version = vinfo.szCSDVersion;
+
+ switch(sinfo.wProcessorArchitecture) {
+ case PROCESSOR_ARCHITECTURE_AMD64:
+ machine = "x86-64";
+ break;
+ case PROCESSOR_ARCHITECTURE_IA64:
+ machine = "IA64";
+ break;
+ case PROCESSOR_ARCHITECTURE_INTEL:
+ machine = "x86";
+ break;
+ default:
+ machine = "unknown";
+ break;
+ }
+}
+
+uint32_t SystemInfo::getProcessId()
+{
+ return static_cast<uint32_t>(::GetCurrentProcessId());
+}
+
+uint32_t SystemInfo::getParentProcessId()
+{
+ // Only want info for the current process, so ask for something specific.
+ // The module info won't be used here but it keeps the snapshot limited to
+ // the current process so a search through all processes is not needed.
+ HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0);
+ if (snap == INVALID_HANDLE_VALUE)
+ return 0;
+ PROCESSENTRY32 entry;
+ entry.dwSize = sizeof(entry);
+ if (!Process32First(snap, &entry))
+ entry.th32ParentProcessID = 0;
+ CloseHandle(snap);
+ return static_cast<uint32_t>(entry.th32ParentProcessID);
+}
+
+std::string SystemInfo::getProcessName()
+{
+ std::string name;
+
+ // Only want info for the current process, so ask for something specific.
+ // The module info won't be used here but it keeps the snapshot limited to
+ // the current process so a search through all processes is not needed.
+ HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0);
+ if (snap == INVALID_HANDLE_VALUE)
+ return name;
+ PROCESSENTRY32 entry;
+ entry.dwSize = sizeof(entry);
+ if (!Process32First(snap, &entry))
+ entry.szExeFile[0] = '\0';
+ CloseHandle(snap);
+ name = entry.szExeFile;
+ return name;
+}
+
+}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/windows/Thread.cpp b/cpp/src/qpid/sys/windows/Thread.cpp
new file mode 100755
index 0000000000..fed82e4d54
--- /dev/null
+++ b/cpp/src/qpid/sys/windows/Thread.cpp
@@ -0,0 +1,88 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/sys/Thread.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/windows/check.h"
+
+#include <process.h>
+#include <windows.h>
+
+namespace {
+unsigned __stdcall runRunnable(void* p)
+{
+ static_cast<qpid::sys::Runnable*>(p)->run();
+ _endthreadex(0);
+ return 0;
+}
+}
+
+namespace qpid {
+namespace sys {
+
+class ThreadPrivate {
+ friend class Thread;
+
+ HANDLE threadHandle;
+ unsigned threadId;
+
+ ThreadPrivate(Runnable* runnable) {
+ uintptr_t h = _beginthreadex(0,
+ 0,
+ runRunnable,
+ runnable,
+ 0,
+ &threadId);
+ QPID_WINDOWS_CHECK_CRT_NZ(h);
+ threadHandle = reinterpret_cast<HANDLE>(h);
+ }
+
+ ThreadPrivate()
+ : threadHandle(GetCurrentThread()), threadId(GetCurrentThreadId()) {}
+};
+
+Thread::Thread() {}
+
+Thread::Thread(Runnable* runnable) : impl(new ThreadPrivate(runnable)) {}
+
+Thread::Thread(Runnable& runnable) : impl(new ThreadPrivate(&runnable)) {}
+
+void Thread::join() {
+ if (impl) {
+ DWORD status = WaitForSingleObject (impl->threadHandle, INFINITE);
+ QPID_WINDOWS_CHECK_NOT(status, WAIT_FAILED);
+ CloseHandle (impl->threadHandle);
+ impl->threadHandle = 0;
+ }
+}
+
+unsigned long Thread::id() {
+ return impl ? impl->threadId : 0;
+}
+
+/* static */
+Thread Thread::current() {
+ Thread t;
+ t.impl.reset(new ThreadPrivate());
+ return t;
+}
+
+}} /* qpid::sys */
diff --git a/cpp/src/qpid/sys/windows/Time.cpp b/cpp/src/qpid/sys/windows/Time.cpp
new file mode 100644
index 0000000000..1d7b94e8d7
--- /dev/null
+++ b/cpp/src/qpid/sys/windows/Time.cpp
@@ -0,0 +1,103 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Time.h"
+#include <ostream>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/thread/thread_time.hpp>
+#include <windows.h>
+
+using namespace boost::posix_time;
+
+namespace qpid {
+namespace sys {
+
+AbsTime::AbsTime(const AbsTime& t, const Duration& d) {
+ if (d == Duration::max()) {
+ timepoint = ptime(max_date_time);
+ }
+ else {
+ time_duration td = microseconds(d.nanosecs / 1000);
+ timepoint = t.timepoint + td;
+ }
+}
+
+AbsTime AbsTime::FarFuture() {
+ AbsTime ff;
+ ptime maxd(max_date_time);
+ ff.timepoint = maxd;
+ return ff;
+}
+
+AbsTime AbsTime::now() {
+ AbsTime time_now;
+ time_now.timepoint = boost::get_system_time();
+ return time_now;
+}
+
+Duration::Duration(const AbsTime& time0) : nanosecs(0) {
+ time_period p(ptime(min_date_time), time0.timepoint);
+ nanosecs = p.length().total_nanoseconds();
+}
+
+Duration::Duration(const AbsTime& start, const AbsTime& finish) {
+ time_duration d = finish.timepoint - start.timepoint;
+ nanosecs = d.total_nanoseconds();
+}
+
+std::ostream& operator<<(std::ostream& o, const Duration& d) {
+ return o << int64_t(d) << "ns";
+}
+
+std::ostream& operator<<(std::ostream& o, const AbsTime& t) {
+ std::string time_string = to_simple_string(t.timepoint);
+ return o << time_string;
+}
+
+
+void toPtime(ptime& pt, const AbsTime& t) {
+ pt = t.getPrivate();
+}
+
+void sleep(int secs) {
+ ::Sleep(secs * 1000);
+}
+
+void usleep(uint64_t usecs) {
+ DWORD msecs = usecs / 1000;
+ if (msecs == 0)
+ msecs = 1;
+ ::Sleep(msecs);
+}
+
+void outputFormattedNow(std::ostream& o) {
+ ::time_t rawtime;
+ ::tm timeinfo;
+ char time_string[100];
+
+ ::time( &rawtime );
+ ::localtime_s(&timeinfo, &rawtime);
+ ::strftime(time_string, 100,
+ "%Y-%m-%d %H:%M:%S",
+ &timeinfo);
+ o << time_string << " ";
+}
+}}
diff --git a/cpp/src/qpid/sys/windows/uuid.cpp b/cpp/src/qpid/sys/windows/uuid.cpp
new file mode 100644
index 0000000000..6ff3a3cb8a
--- /dev/null
+++ b/cpp/src/qpid/sys/windows/uuid.cpp
@@ -0,0 +1,59 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <Rpc.h>
+#ifdef uuid_t /* Done in rpcdce.h */
+# undef uuid_t
+#endif
+
+#include "qpid/sys/windows/uuid.h"
+
+#include <string.h>
+
+void uuid_clear (uuid_t uu) {
+ UuidCreateNil (reinterpret_cast<UUID*>(uu));
+}
+
+void uuid_copy (uuid_t dst, const uuid_t src) {
+ memcpy (dst, src, qpid::sys::UuidSize);
+}
+
+void uuid_generate (uuid_t out) {
+ UuidCreate (reinterpret_cast<UUID*>(out));
+}
+
+int uuid_is_null (const uuid_t uu) {
+ RPC_STATUS unused;
+ return UuidIsNil ((UUID*)uu, &unused);
+}
+
+int uuid_parse (const char *in, uuid_t uu) {
+ return UuidFromString ((unsigned char*)in, (UUID*)uu) == RPC_S_OK ? 0 : -1;
+}
+
+void uuid_unparse (const uuid_t uu, char *out) {
+ unsigned char *formatted;
+ if (UuidToString((UUID*)uu, &formatted) == RPC_S_OK) {
+ strncpy_s (out, 36+1, (char*)formatted, _TRUNCATE);
+ RpcStringFree(&formatted);
+ }
+}
+
diff --git a/cpp/src/qpid/sys/windows/uuid.h b/cpp/src/qpid/sys/windows/uuid.h
new file mode 100644
index 0000000000..c79abe95c6
--- /dev/null
+++ b/cpp/src/qpid/sys/windows/uuid.h
@@ -0,0 +1,38 @@
+#ifndef _sys_windows_uuid_h
+#define _sys_windows_uuid_h
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/CommonImportExport.h"
+#include <qpid/sys/IntegerTypes.h>
+
+namespace qpid { namespace sys { const size_t UuidSize = 16; }}
+typedef uint8_t uuid_t[qpid::sys::UuidSize];
+
+QPID_COMMON_EXTERN void uuid_clear (uuid_t uu);
+QPID_COMMON_EXTERN void uuid_copy (uuid_t dst, const uuid_t src);
+QPID_COMMON_EXTERN void uuid_generate (uuid_t out);
+QPID_COMMON_EXTERN int uuid_is_null (const uuid_t uu); // Returns 1 if null, else 0
+QPID_COMMON_EXTERN int uuid_parse (const char *in, uuid_t uu); // Returns 0 on success, else -1
+QPID_COMMON_EXTERN void uuid_unparse (const uuid_t uu, char *out);
+
+#endif /*!_sys_windows_uuid_h*/
diff --git a/cpp/src/qpid/xml/XmlBinding.h b/cpp/src/qpid/xml/XmlBinding.h
new file mode 100644
index 0000000000..cc6b4dca5d
--- /dev/null
+++ b/cpp/src/qpid/xml/XmlBinding.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <qpid/framing/FieldTable>
+#include <string>
+
+#ifndef _XmlBinding_
+#define _XmlBinding_
+
+namespace qpid {
+namespace client {
+
+class XmlBinding : public framing::FieldTable {
+ public:
+ setQuery(string query) { setString("xquery", query); }
+};
+
+}
+}
+#endif
diff --git a/cpp/src/qpid/xml/XmlExchange.cpp b/cpp/src/qpid/xml/XmlExchange.cpp
new file mode 100644
index 0000000000..472ca28954
--- /dev/null
+++ b/cpp/src/qpid/xml/XmlExchange.cpp
@@ -0,0 +1,262 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "config.h"
+
+#include "qpid/xml/XmlExchange.h"
+
+#include "qpid/broker/DeliverableMessage.h"
+
+#include "qpid/log/Statement.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/FieldValue.h"
+#include "qpid/framing/reply_exceptions.h"
+
+#include "qpid/Plugin.h"
+
+#include <xercesc/framework/MemBufInputSource.hpp>
+
+#include <xqilla/ast/XQGlobalVariable.hpp>
+
+#include <xqilla/context/ItemFactory.hpp>
+#include <xqilla/xqilla-simple.hpp>
+
+#include <iostream>
+#include <sstream>
+
+using namespace qpid::framing;
+using namespace qpid::sys;
+using qpid::management::Manageable;
+namespace _qmf = qmf::org::apache::qpid::broker;
+
+namespace qpid {
+namespace broker {
+
+
+ XmlExchange::XmlExchange(const string& _name, Manageable* _parent, Broker* b) : Exchange(_name, _parent, b)
+{
+ if (mgmtExchange != 0)
+ mgmtExchange->set_type (typeName);
+}
+
+XmlExchange::XmlExchange(const std::string& _name, bool _durable,
+ const FieldTable& _args, Manageable* _parent, Broker* b) :
+ Exchange(_name, _durable, _args, _parent, b)
+{
+ if (mgmtExchange != 0)
+ mgmtExchange->set_type (typeName);
+}
+
+
+ // #### TODO: The Binding should take the query text
+ // #### only. Consider encapsulating the entire block, including
+ // #### the if condition.
+
+
+bool XmlExchange::bind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* bindingArguments)
+{
+ string queryText = bindingArguments->getAsString("xquery");
+
+ try {
+ RWlock::ScopedWlock l(lock);
+
+ XmlBinding::vector& bindings(bindingsMap[routingKey]);
+ XmlBinding::vector::ConstPtr p = bindings.snapshot();
+ if (!p || std::find_if(p->begin(), p->end(), MatchQueue(queue)) == p->end()) {
+ Query query(xqilla.parse(X(queryText.c_str())));
+ XmlBinding::shared_ptr binding(new XmlBinding (routingKey, queue, this, query));
+ bindings.add(binding);
+ QPID_LOG(trace, "Bound successfully with query: " << queryText );
+
+ binding->parse_message_content = false;
+
+ if (query->getQueryBody()->getStaticAnalysis().areContextFlagsUsed()) {
+ binding->parse_message_content = true;
+ }
+ else {
+ GlobalVariables &vars = const_cast<GlobalVariables&>(query->getVariables());
+ for(GlobalVariables::iterator it = vars.begin(); it != vars.end(); ++it) {
+ if ((*it)->getStaticAnalysis().areContextFlagsUsed()) {
+ binding->parse_message_content = true;
+ break;
+ }
+ }
+ }
+
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_bindingCount();
+ ((_qmf::Queue*) queue->GetManagementObject())->inc_bindingCount();
+ }
+ } else {
+ return false;
+ }
+ }
+ catch (XQException& e) {
+ throw InternalErrorException(QPID_MSG("Could not parse xquery:"+ queryText));
+ }
+ catch (...) {
+ throw InternalErrorException(QPID_MSG("Unexpected error - Could not parse xquery:"+ queryText));
+ }
+ routeIVE();
+ return true;
+}
+
+bool XmlExchange::unbind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* /*args*/)
+{
+ RWlock::ScopedWlock l(lock);
+ if (bindingsMap[routingKey].remove_if(MatchQueue(queue))) {
+ if (mgmtExchange != 0) {
+ mgmtExchange->dec_bindingCount();
+ ((_qmf::Queue*) queue->GetManagementObject())->dec_bindingCount();
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool XmlExchange::matches(Query& query, Deliverable& msg, const qpid::framing::FieldTable* args, bool parse_message_content)
+{
+ string msgContent;
+
+ try {
+ QPID_LOG(trace, "matches: query is [" << UTF8(query->getQueryText()) << "]");
+
+ boost::scoped_ptr<DynamicContext> context(query->createDynamicContext());
+ if (!context.get()) {
+ throw InternalErrorException(QPID_MSG("Query context looks munged ..."));
+ }
+
+ if (parse_message_content) {
+
+ msg.getMessage().getFrames().getContent(msgContent);
+
+ QPID_LOG(trace, "matches: message content is [" << msgContent << "]");
+
+ XERCES_CPP_NAMESPACE::MemBufInputSource xml((const XMLByte*) msgContent.c_str(),
+ msgContent.length(), "input" );
+
+ // This will parse the document using either Xerces or FastXDM, depending
+ // on your XQilla configuration. FastXDM can be as much as 10x faster.
+
+ Sequence seq(context->parseDocument(xml));
+
+ if(!seq.isEmpty() && seq.first()->isNode()) {
+ context->setContextItem(seq.first());
+ context->setContextPosition(1);
+ context->setContextSize(1);
+ }
+ }
+
+ if (args) {
+ FieldTable::ValueMap::const_iterator v = args->begin();
+ for(; v != args->end(); ++v) {
+ // ### TODO: Do types properly
+ if (v->second->convertsTo<std::string>()) {
+ QPID_LOG(trace, "XmlExchange, external variable: " << v->first << " = " << v->second->getData().getString().c_str());
+ Item::Ptr value = context->getItemFactory()->createString(X(v->second->getData().getString().c_str()), context.get());
+ context->setExternalVariable(X(v->first.c_str()), value);
+ }
+ }
+ }
+
+ Result result = query->execute(context.get());
+ return result->getEffectiveBooleanValue(context.get(), 0);
+ }
+ catch (XQException& e) {
+ QPID_LOG(warning, "Could not parse XML content (or message headers):" << msgContent);
+ }
+ catch (...) {
+ QPID_LOG(warning, "Unexpected error routing message: " << msgContent);
+ }
+ return 0;
+}
+
+// Future optimization: If any query in a binding for a given routing key requires
+// message content, parse the message once, and use that parsed form for all bindings.
+//
+// Future optimization: XQilla does not currently do document projection for data
+// accessed via the context item. If there is a single query for a given routing key,
+// and it accesses document data, this could be a big win.
+//
+// Document projection often is not a win if you have multiple queries on the same data.
+// But for very large messages, if all these queries are on the first part of the data,
+// it could still be a big win.
+
+void XmlExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* args)
+{
+ PreRoute pr(msg, this);
+ try {
+ XmlBinding::vector::ConstPtr p;
+ BindingList b(new std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> >);
+ {
+ RWlock::ScopedRlock l(lock);
+ p = bindingsMap[routingKey].snapshot();
+ if (!p.get()) return;
+ }
+
+ for (std::vector<XmlBinding::shared_ptr>::const_iterator i = p->begin(); i != p->end(); i++) {
+ if (matches((*i)->xquery, msg, args, (*i)->parse_message_content)) {
+ b->push_back(*i);
+ }
+ }
+ doRoute(msg, b);
+ } catch (...) {
+ QPID_LOG(warning, "XMLExchange " << getName() << ": exception routing message with query " << routingKey);
+ }
+}
+
+
+bool XmlExchange::isBound(Queue::shared_ptr queue, const string* const routingKey, const FieldTable* const)
+{
+ RWlock::ScopedRlock l(lock);
+ if (routingKey) {
+ XmlBindingsMap::iterator i = bindingsMap.find(*routingKey);
+
+ if (i == bindingsMap.end())
+ return false;
+ if (!queue)
+ return true;
+ XmlBinding::vector::ConstPtr p = i->second.snapshot();
+ return p && std::find_if(p->begin(), p->end(), MatchQueue(queue)) != p->end();
+ } else if (!queue) {
+ //if no queue or routing key is specified, just report whether any bindings exist
+ return bindingsMap.size() > 0;
+ } else {
+ for (XmlBindingsMap::iterator i = bindingsMap.begin(); i != bindingsMap.end(); i++) {
+ XmlBinding::vector::ConstPtr p = i->second.snapshot();
+ if (p && std::find_if(p->begin(), p->end(), MatchQueue(queue)) != p->end()) return true;
+ }
+ return false;
+ }
+
+}
+
+
+XmlExchange::~XmlExchange()
+{
+ bindingsMap.clear();
+}
+
+const std::string XmlExchange::typeName("xml");
+
+}
+}
diff --git a/cpp/src/qpid/xml/XmlExchange.h b/cpp/src/qpid/xml/XmlExchange.h
new file mode 100644
index 0000000000..38cb7699b6
--- /dev/null
+++ b/cpp/src/qpid/xml/XmlExchange.h
@@ -0,0 +1,90 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#ifndef _XmlExchange_
+#define _XmlExchange_
+
+#include "qpid/broker/Exchange.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/sys/CopyOnWriteArray.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/broker/Queue.h"
+
+#include <xqilla/xqilla-simple.hpp>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <map>
+#include <vector>
+
+namespace qpid {
+namespace broker {
+
+class Broker;
+class XmlExchange : public virtual Exchange {
+
+ typedef boost::shared_ptr<XQQuery> Query;
+
+ struct XmlBinding : public Exchange::Binding {
+ typedef boost::shared_ptr<XmlBinding> shared_ptr;
+ typedef qpid::sys::CopyOnWriteArray<XmlBinding::shared_ptr> vector;
+
+ boost::shared_ptr<XQQuery> xquery;
+ bool parse_message_content;
+
+ XmlBinding(const std::string& key, const Queue::shared_ptr queue, Exchange* parent, Query query):
+ Binding(key, queue, parent), xquery(query), parse_message_content(true) {}
+ };
+
+
+ typedef std::map<string, XmlBinding::vector > XmlBindingsMap;
+
+ XmlBindingsMap bindingsMap;
+ XQilla xqilla;
+ qpid::sys::RWlock lock;
+
+ bool matches(Query& query, Deliverable& msg, const qpid::framing::FieldTable* args, bool parse_message_content);
+
+ public:
+ static const std::string typeName;
+
+ XmlExchange(const std::string& name, management::Manageable* parent = 0, Broker* broker = 0);
+ XmlExchange(const string& _name, bool _durable,
+ const qpid::framing::FieldTable& _args, management::Manageable* parent = 0, Broker* broker = 0);
+
+ virtual std::string getType() const { return typeName; }
+
+ virtual bool bind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual bool unbind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual void route(Deliverable& msg, const std::string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual bool isBound(Queue::shared_ptr queue, const string* const routingKey, const qpid::framing::FieldTable* const args);
+
+ virtual ~XmlExchange();
+};
+
+
+}
+}
+
+
+#endif
diff --git a/cpp/src/qpid/xml/XmlExchangePlugin.cpp b/cpp/src/qpid/xml/XmlExchangePlugin.cpp
new file mode 100644
index 0000000000..742b878e86
--- /dev/null
+++ b/cpp/src/qpid/xml/XmlExchangePlugin.cpp
@@ -0,0 +1,69 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <sstream>
+#include "qpid/acl/Acl.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/Plugin.h"
+#include "qpid/log/Statement.h"
+
+#include <boost/shared_ptr.hpp>
+#include <boost/utility/in_place_factory.hpp>
+
+#include "qpid/xml/XmlExchange.h"
+
+namespace qpid {
+namespace broker { // ACL uses the acl namespace here - should I?
+
+using namespace std;
+class Broker;
+
+Exchange::shared_ptr create(const std::string& name, bool durable,
+ const framing::FieldTable& args,
+ management::Manageable* parent,
+ Broker* broker)
+{
+ Exchange::shared_ptr e(new XmlExchange(name, durable, args, parent, broker));
+ return e;
+}
+
+
+class XmlExchangePlugin : public Plugin
+{
+public:
+ void earlyInitialize(Plugin::Target& target);
+ void initialize(Plugin::Target& target);
+};
+
+
+void XmlExchangePlugin::earlyInitialize(Plugin::Target& target)
+{
+ Broker* broker = dynamic_cast<broker::Broker*>(&target);
+ if (broker) {
+ broker->getExchanges().registerType(XmlExchange::typeName, &create);
+ QPID_LOG(info, "Registered xml exchange");
+ }
+}
+
+void XmlExchangePlugin::initialize(Target&) {}
+
+
+static XmlExchangePlugin matchingPlugin;
+
+
+}} // namespace qpid::acl
diff --git a/cpp/src/qpidd.cpp b/cpp/src/qpidd.cpp
index e79875f964..a7c1dbe8a6 100644
--- a/cpp/src/qpidd.cpp
+++ b/cpp/src/qpidd.cpp
@@ -18,192 +18,46 @@
* under the License.
*
*/
-#include "qpid/broker/Broker.h"
-#include "qpid/broker/SignalHandler.h"
-#include "qpid/sys/posix/check.h"
-#include "qpid/broker/Daemon.h"
-#include "qpid/log/Statement.h"
-#include "qpid/log/Options.h"
-#include "qpid/log/Logger.h"
+
+#include "./qpidd.h"
#include "qpid/Plugin.h"
-#include "qpid/sys/Shlib.h"
-#include "config.h"
-#include <boost/filesystem/operations.hpp>
-#include <boost/filesystem/path.hpp>
-#include <iostream>
-#include <fstream>
-#include <signal.h>
-#include <unistd.h>
-#include <sys/utsname.h>
+#include "qpid/Version.h"
+#include "qpid/log/Logger.h"
+#include "qpid/log/Statement.h"
-using namespace qpid;
-using namespace qpid::broker;
-using namespace qpid::sys;
-using namespace qpid::log;
+#include <iostream>
+#include <memory>
using namespace std;
-namespace fs=boost::filesystem;
-
-struct ModuleOptions : public qpid::Options {
- string loadDir;
- vector<string> load;
- bool noLoad;
- ModuleOptions() : qpid::Options("Module options"), loadDir("/usr/lib/qpidd"), noLoad(false)
- {
- struct utsname _uname;
- if (::uname(&_uname) == 0) {
- if (string(_uname.machine) == "x86_64")
- loadDir = "/usr/lib64/qpidd";
- }
-
- addOptions()
- ("module-dir", optValue(loadDir, "DIR"), "Load all .so modules in this directory")
- ("load-module", optValue(load, "FILE"), "Specifies additional module(s) to be loaded")
- ("no-module-dir", optValue(noLoad), "Don't load modules from module directory");
- }
-};
-
-
-struct DaemonOptions : public qpid::Options {
- bool daemon;
- bool quit;
- bool check;
- int wait;
- std::string piddir;
-
- DaemonOptions() : qpid::Options("Daemon options"), daemon(false), quit(false), check(false), wait(10)
- {
- char *home = ::getenv("HOME");
-
- if (home == 0)
- piddir += "/tmp";
- else
- piddir += home;
- piddir += "/.qpidd";
-
- addOptions()
- ("daemon,d", optValue(daemon), "Run as a daemon. --log-output defaults to syslog in this mode.")
- ("pid-dir", optValue(piddir, "DIR"), "Directory where port-specific PID file is stored")
- ("wait,w", optValue(wait, "SECONDS"), "Sets the maximum wait time to initialize the daemon. If the daemon fails to initialize, prints an error and returns 1")
- ("check,c", optValue(check), "Prints the daemon's process ID to stdout and returns 0 if the daemon is running, otherwise returns 1")
- ("quit,q", optValue(quit), "Tells the daemon to shut down");
- }
-};
-
-
-struct QpiddOptions : public qpid::Options {
- CommonOptions common;
- ModuleOptions module;
- Broker::Options broker;
- DaemonOptions daemon;
- qpid::log::Options log;
-
- QpiddOptions(const char* argv0) : qpid::Options("Options"), common("", "/etc/qpidd.conf"), log(argv0) {
- add(common);
- add(module);
- add(broker);
- add(daemon);
- add(log);
- Plugin::addOptions(*this);
- }
-
- void usage() const {
- cout << "Usage: qpidd [OPTIONS]" << endl << endl << *this << endl;
- };
-};
-
-// BootstrapOptions is a minimal subset of options used for a pre-parse
-// of the command line to discover which plugin modules need to be loaded.
-// The pre-parse is necessary because plugin modules may supply their own
-// set of options. CommonOptions is needed to properly support loading
-// from a configuration file.
-struct BootstrapOptions : public qpid::Options {
- CommonOptions common;
- ModuleOptions module;
- qpid::log::Options log;
-
- BootstrapOptions(const char* argv0) : qpid::Options("Options"), common("", "/etc/qpidd.conf"), log(argv0) {
- add(common);
- add(module);
- add(log);
- }
-};
auto_ptr<QpiddOptions> options;
-struct QpiddDaemon : public Daemon {
- QpiddDaemon(std::string pidDir) : Daemon(pidDir) {}
-
- /** Code for parent process */
- void parent() {
- uint16_t port = wait(options->daemon.wait);
- if (options->broker.port == 0)
- cout << port << endl;
- }
-
- /** Code for forked child process */
- void child() {
- boost::intrusive_ptr<Broker> brokerPtr(new Broker(options->broker));
- broker::SignalHandler::setBroker(brokerPtr);
- uint16_t port=brokerPtr->getPort();
- ready(port); // Notify parent.
- brokerPtr->run();
- }
-};
-
-void tryShlib(const char* libname, bool noThrow) {
- try {
- Shlib shlib(libname);
- QPID_LOG (info, "Loaded Module: " << libname);
- }
- catch (const exception& e) {
- if (!noThrow)
- throw;
- }
-}
-
-void loadModuleDir (string dirname, bool isDefault)
-{
- fs::path dirPath (dirname, fs::native);
-
- if (!fs::exists (dirPath))
- {
- if (isDefault)
- return;
- throw Exception ("Directory not found: " + dirname);
- }
-
- fs::directory_iterator endItr;
- for (fs::directory_iterator itr (dirPath); itr != endItr; ++itr)
- {
- if (!fs::is_directory(*itr) &&
- itr->string().find (".so") == itr->string().length() - 3)
- tryShlib (itr->string().data(), true);
- }
-}
-
-
int main(int argc, char* argv[])
{
try
{
- {
- BootstrapOptions bootOptions(argv[0]);
- string defaultPath (bootOptions.module.loadDir);
- // Parse only the common, load, and log options to see which modules need
- // to be loaded. Once the modules are loaded, the command line will
- // be re-parsed with all of the module-supplied options.
+ BootstrapOptions bootOptions(argv[0]);
+ string defaultPath (bootOptions.module.loadDir);
+ // Parse only the common, load, and log options to see which
+ // modules need to be loaded. Once the modules are loaded,
+ // the command line will be re-parsed with all of the
+ // module-supplied options.
+ try {
bootOptions.parse (argc, argv, bootOptions.common.config, true);
qpid::log::Logger::instance().configure(bootOptions.log);
+ } catch (const std::exception& e) {
+ // Couldn't configure logging so write the message direct to stderr.
+ cerr << "Unexpected error: " << e.what() << endl;
+ return 1;
+ }
- for (vector<string>::iterator iter = bootOptions.module.load.begin();
- iter != bootOptions.module.load.end();
- iter++)
- tryShlib (iter->data(), false);
+ for (vector<string>::iterator iter = bootOptions.module.load.begin();
+ iter != bootOptions.module.load.end();
+ iter++)
+ qpid::tryShlib (iter->data(), false);
- if (!bootOptions.module.noLoad) {
- bool isDefault = defaultPath == bootOptions.module.loadDir;
- loadModuleDir (bootOptions.module.loadDir, isDefault);
- }
+ if (!bootOptions.module.noLoad) {
+ bool isDefault = defaultPath == bootOptions.module.loadDir;
+ qpid::loadModuleDir (bootOptions.module.loadDir, isDefault);
}
// Parse options
@@ -211,49 +65,22 @@ int main(int argc, char* argv[])
options->parse(argc, argv, options->common.config);
// Options that just print information.
- if(options->common.help || options->common.version) {
+ if (options->common.help || options->common.version) {
if (options->common.version)
- cout << "qpidd (" << PACKAGE_NAME << ") version "
- << PACKAGE_VERSION << endl;
+ cout << "qpidd (" << qpid::product << ") version "
+ << qpid::version << endl;
else if (options->common.help)
options->usage();
return 0;
}
- // Options that affect a running daemon.
- if (options->daemon.check || options->daemon.quit) {
- pid_t pid = Daemon::getPid(options->daemon.piddir, options->broker.port);
- if (pid < 0)
- return 1;
- if (options->daemon.check)
- cout << pid << endl;
- if (options->daemon.quit && kill(pid, SIGINT) < 0)
- throw Exception("Failed to stop daemon: " + strError(errno));
- return 0;
- }
-
- // Starting the broker.
- if (options->daemon.daemon) {
- // For daemon mode replace default stderr with syslog.
- if (options->log.outputs.size() == 1 && options->log.outputs[0] == "stderr") {
- options->log.outputs[0] = "syslog";
- qpid::log::Logger::instance().configure(options->log);
- }
- // Fork the daemon
- QpiddDaemon d(options->daemon.piddir);
- d.fork(); // Broker is stared in QpiddDaemon::child()
- }
- else { // Non-daemon broker.
- boost::intrusive_ptr<Broker> brokerPtr(new Broker(options->broker));
- broker::SignalHandler::setBroker(brokerPtr);
- if (options->broker.port == 0)
- cout << uint16_t(brokerPtr->getPort()) << endl;
- brokerPtr->run();
- }
- return 0;
+ // Everything else is driven by the platform-specific broker
+ // logic.
+ QpiddBroker broker;
+ return broker.execute(options.get());
}
catch(const exception& e) {
- cerr << e.what() << endl;
+ QPID_LOG(critical, "Unexpected error: " << e.what());
}
return 1;
}
diff --git a/cpp/src/qpidd.h b/cpp/src/qpidd.h
new file mode 100644
index 0000000000..c702270e80
--- /dev/null
+++ b/cpp/src/qpidd.h
@@ -0,0 +1,70 @@
+#ifndef QPID_H
+#define QPID_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/Modules.h"
+#include "qpid/Options.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/log/Options.h"
+
+#include <memory>
+
+// BootstrapOptions is a minimal subset of options used for a pre-parse
+// of the command line to discover which plugin modules need to be loaded.
+// The pre-parse is necessary because plugin modules may supply their own
+// set of options. CommonOptions is needed to properly support loading
+// from a configuration file.
+struct BootstrapOptions : public qpid::Options {
+ qpid::CommonOptions common;
+ qpid::ModuleOptions module;
+ qpid::log::Options log;
+
+ BootstrapOptions(const char *argv0);
+};
+
+// Each platform derives an options struct from QpiddOptionsPrivate, adding
+// platform-specific option types. QpiddOptions needs to allocation one of
+// these derived structs from its constructor.
+struct QpiddOptions;
+struct QpiddOptionsPrivate {
+ QpiddOptions *options;
+ QpiddOptionsPrivate(QpiddOptions *parent) : options(parent) {}
+ virtual ~QpiddOptionsPrivate() {}
+protected:
+ QpiddOptionsPrivate() {}
+};
+
+struct QpiddOptions : public qpid::Options {
+ qpid::CommonOptions common;
+ qpid::ModuleOptions module;
+ qpid::broker::Broker::Options broker;
+ qpid::log::Options log;
+ std::auto_ptr<QpiddOptionsPrivate> platform;
+
+ QpiddOptions(const char *argv0);
+ void usage() const;
+};
+
+class QpiddBroker {
+public:
+ int execute (QpiddOptions *options);
+};
+
+#endif /*!QPID_H*/
diff --git a/cpp/src/rdma.cmake b/cpp/src/rdma.cmake
new file mode 100644
index 0000000000..e020cb84a9
--- /dev/null
+++ b/cpp/src/rdma.cmake
@@ -0,0 +1,118 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+# RDMA (Remote DMA) wrapper CMake fragment, to be included in CMakeLists.txt
+#
+
+# Optional RDMA support. Requires ibverbs and rdma_cm.
+
+include(CheckIncludeFiles)
+include(CheckLibraryExists)
+
+CHECK_LIBRARY_EXISTS (ibverbs ibv_create_qp "" HAVE_IBVERBS)
+CHECK_LIBRARY_EXISTS (rdmacm rdma_create_id "" HAVE_RDMACM)
+CHECK_INCLUDE_FILES (infiniband/verbs.h HAVE_IBVERBS_H)
+CHECK_INCLUDE_FILES (rdma/rdma_cma.h HAVE_RDMACM_H)
+
+set (rdma_default ${rdma_force})
+if (HAVE_IBVERBS AND HAVE_IBVERBS_H)
+ if (HAVE_RDMACM AND HAVE_RDMACM_H)
+ set (rdma_default ON)
+ endif (HAVE_RDMACM AND HAVE_RDMACM_H)
+endif (HAVE_IBVERBS AND HAVE_IBVERBS_H)
+
+option(BUILD_RDMA "Build with support for Remote DMA protocols" ${rdma_default})
+if (BUILD_RDMA)
+ if (NOT HAVE_IBVERBS)
+ message(FATAL_ERROR "libibverbs not found, required for RDMA support")
+ endif (NOT HAVE_IBVERBS)
+ if (NOT HAVE_RDMACM)
+ message(FATAL_ERROR "librdmacm not found, required for RDMA support")
+ endif (NOT HAVE_RDMACM)
+ if (NOT HAVE_IBVERBS_H)
+ message(FATAL_ERROR "ibverbs headers not found, required for RDMA support")
+ endif (NOT HAVE_IBVERBS_H)
+ if (NOT HAVE_RDMACM_H)
+ message(FATAL_ERROR "rdmacm headers not found, required for RDMA support")
+ endif (NOT HAVE_RDMACM_H)
+
+ set (rdma_SOURCES
+ qpid/sys/rdma/rdma_exception.h
+ qpid/sys/rdma/rdma_factories.cpp
+ qpid/sys/rdma/rdma_factories.h
+ qpid/sys/rdma/RdmaIO.cpp
+ qpid/sys/rdma/RdmaIO.h
+ qpid/sys/rdma/rdma_wrap.cpp
+ qpid/sys/rdma/rdma_wrap.h
+ )
+
+ add_library (rdmawrap SHARED ${rdma_SOURCES})
+ target_link_libraries (rdmawrap qpidcommon rdmacm ibverbs)
+ set_target_properties (rdmawrap PROPERTIES VERSION ${qpidc_version})
+ if (CMAKE_COMPILER_IS_GNUCXX)
+ set_target_properties(rdmawrap PROPERTIES
+ COMPILE_FLAGS -Wno-missing-field-initializers
+ LINK_FLAGS -Wl,--no-undefined)
+ endif (CMAKE_COMPILER_IS_GNUCXX)
+
+ install (TARGETS rdmawrap
+ DESTINATION ${QPID_INSTALL_LIBDIR}
+ COMPONENT ${QPID_COMPONENT_COMMON})
+
+ add_library (rdma MODULE qpid/sys/RdmaIOPlugin.cpp)
+ target_link_libraries (rdma qpidbroker rdmawrap)
+ set_target_properties (rdma PROPERTIES
+ PREFIX "")
+
+ if (CMAKE_COMPILER_IS_GNUCXX)
+ set_target_properties(rdma PROPERTIES
+ COMPILE_FLAGS -Wno-missing-field-initializers
+ LINK_FLAGS -Wl,--no-undefined)
+ endif (CMAKE_COMPILER_IS_GNUCXX)
+
+ install (TARGETS rdma
+ DESTINATION ${QPIDD_MODULE_DIR}
+ COMPONENT ${QPID_COMPONENT_BROKER})
+
+ add_library (rdmaconnector MODULE qpid/client/RdmaConnector.cpp)
+ target_link_libraries (rdmaconnector qpidclient rdmawrap)
+ set_target_properties (rdmaconnector PROPERTIES
+ PREFIX "")
+
+ if (CMAKE_COMPILER_IS_GNUCXX)
+ set_target_properties(rdmaconnector PROPERTIES
+ COMPILE_FLAGS -Wno-missing-field-initializers
+ LINK_FLAGS -Wl,--no-undefined)
+ endif (CMAKE_COMPILER_IS_GNUCXX)
+
+ install (TARGETS rdmaconnector
+ DESTINATION ${QPIDC_MODULE_DIR}
+ COMPONENT ${QPID_COMPONENT_CLIENT})
+
+ # RDMA test/sample programs
+ add_executable (RdmaServer qpid/sys/rdma/RdmaServer.cpp)
+ target_link_libraries (RdmaServer rdmawrap qpidcommon)
+ add_executable (RdmaClient qpid/sys/rdma/RdmaClient.cpp)
+ target_link_libraries (RdmaClient rdmawrap qpidcommon)
+ if (CMAKE_COMPILER_IS_GNUCXX)
+ set_target_properties(RdmaClient PROPERTIES
+ COMPILE_FLAGS -Wno-missing-field-initializers)
+ endif (CMAKE_COMPILER_IS_GNUCXX)
+
+endif (BUILD_RDMA)
diff --git a/cpp/src/replication.mk b/cpp/src/replication.mk
new file mode 100644
index 0000000000..4a51fb9c7d
--- /dev/null
+++ b/cpp/src/replication.mk
@@ -0,0 +1,52 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Make file for building two plugins for asynchronously replicating
+# queues.
+
+dmodule_LTLIBRARIES += replicating_listener.la replication_exchange.la
+
+# a queue event listener plugin that creates messages on a replication
+# queue corresponding to enqueue and dequeue events:
+replicating_listener_la_SOURCES = \
+ qpid/replication/constants.h \
+ qpid/replication/ReplicatingEventListener.cpp \
+ qpid/replication/ReplicatingEventListener.h
+
+replicating_listener_la_LIBADD = libqpidbroker.la
+if SUNOS
+ replicating_listener_la_LIBADD += libqpidcommon.la -lboost_program_options -luuid $(SUNCC_RUNTIME_LIBS)
+endif
+
+replicating_listener_la_LDFLAGS = $(PLUGINLDFLAGS)
+
+# a custom exchange plugin that allows an exchange to be created that
+# can process the messages from a replication queue (populated on the
+# source system by the replicating listener plugin above) and take the
+# corresponding action on the local queues
+replication_exchange_la_SOURCES = \
+ qpid/replication/constants.h \
+ qpid/replication/ReplicationExchange.cpp \
+ qpid/replication/ReplicationExchange.h
+
+replication_exchange_la_LIBADD = libqpidbroker.la
+
+if SUNOS
+ replication_exchange_la_LIBADD += libqpidcommon.la -lboost_program_options $(SUNCC_RUNTIME_LIBS) -luuid
+endif
+replication_exchange_la_LDFLAGS = $(PLUGINLDFLAGS)
diff --git a/cpp/src/ssl.cmake b/cpp/src/ssl.cmake
new file mode 100644
index 0000000000..13fafa587f
--- /dev/null
+++ b/cpp/src/ssl.cmake
@@ -0,0 +1,106 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+# SSL/TLS CMake fragment, to be included in CMakeLists.txt
+#
+
+# Optional SSL/TLS support. Requires Netscape Portable Runtime on Linux.
+
+include(FindPkgConfig)
+
+# According to some cmake docs this is not a reliable way to detect
+# pkg-configed libraries, but it's no worse than what we did under
+# autotools
+pkg_check_modules(NSS nss)
+
+set (ssl_default ${ssl_force})
+if (CMAKE_SYSTEM_NAME STREQUAL Windows)
+else (CMAKE_SYSTEM_NAME STREQUAL Windows)
+ if (NSS_FOUND)
+ set (ssl_default ON)
+ endif (NSS_FOUND)
+endif (CMAKE_SYSTEM_NAME STREQUAL Windows)
+
+option(BUILD_SSL "Build with support for SSL" ${ssl_default})
+if (BUILD_SSL)
+
+ if (NOT NSS_FOUND)
+ message(FATAL_ERROR "nss/nspr not found, required for ssl support")
+ endif (NOT NSS_FOUND)
+
+ foreach(f ${NSS_CFLAGS})
+ set (NSS_COMPILE_FLAGS "${NSS_COMPILE_FLAGS} ${f}")
+ endforeach(f)
+
+ foreach(f ${NSS_LDFLAGS})
+ set (NSS_LINK_FLAGS "${NSS_LINK_FLAGS} ${f}")
+ endforeach(f)
+
+ set (sslcommon_SOURCES
+ qpid/sys/ssl/check.h
+ qpid/sys/ssl/check.cpp
+ qpid/sys/ssl/util.h
+ qpid/sys/ssl/util.cpp
+ qpid/sys/ssl/SslSocket.h
+ qpid/sys/ssl/SslSocket.cpp
+ qpid/sys/ssl/SslIo.h
+ qpid/sys/ssl/SslIo.cpp
+ )
+
+ add_library (sslcommon SHARED ${sslcommon_SOURCES})
+ target_link_libraries (sslcommon qpidcommon)
+ set_target_properties (sslcommon PROPERTIES
+ VERSION ${qpidc_version}
+ COMPILE_FLAGS ${NSS_COMPILE_FLAGS}
+ LINK_FLAGS ${NSS_LINK_FLAGS})
+
+ set (ssl_SOURCES
+ qpid/sys/SslPlugin.cpp
+ qpid/sys/ssl/SslHandler.h
+ qpid/sys/ssl/SslHandler.cpp
+ )
+ add_library (ssl MODULE ${ssl_SOURCES})
+ target_link_libraries (ssl qpidbroker sslcommon ${Boost_PROGRAM_OPTIONS_LIBRARY})
+ set_target_properties (ssl PROPERTIES
+ PREFIX ""
+ COMPILE_FLAGS ${NSS_COMPILE_FLAGS})
+ if (CMAKE_COMPILER_IS_GNUCXX)
+ set_target_properties(ssl PROPERTIES
+ LINK_FLAGS -Wl,--no-undefined)
+ endif (CMAKE_COMPILER_IS_GNUCXX)
+
+ install (TARGETS ssl
+ DESTINATION ${QPIDD_MODULE_DIR}
+ COMPONENT ${QPID_COMPONENT_BROKER})
+
+ add_library (sslconnector MODULE qpid/client/SslConnector.cpp)
+ target_link_libraries (sslconnector qpidclient sslcommon)
+ set_target_properties (sslconnector PROPERTIES
+ PREFIX ""
+ COMPILE_FLAGS ${NSS_COMPILE_FLAGS})
+ if (CMAKE_COMPILER_IS_GNUCXX)
+ set_target_properties(sslconnector PROPERTIES
+ LINK_FLAGS -Wl,--no-undefined)
+ endif (CMAKE_COMPILER_IS_GNUCXX)
+
+ install (TARGETS sslconnector
+ DESTINATION ${QPIDC_MODULE_DIR}
+ COMPONENT ${QPID_COMPONENT_CLIENT})
+
+endif (BUILD_SSL)
diff --git a/cpp/src/ssl.mk b/cpp/src/ssl.mk
new file mode 100644
index 0000000000..f7fba7bd35
--- /dev/null
+++ b/cpp/src/ssl.mk
@@ -0,0 +1,64 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+# Makefile fragment, conditionally included in Makefile.am
+#
+libsslcommon_la_SOURCES = \
+ qpid/sys/ssl/check.h \
+ qpid/sys/ssl/check.cpp \
+ qpid/sys/ssl/util.h \
+ qpid/sys/ssl/util.cpp \
+ qpid/sys/ssl/SslSocket.h \
+ qpid/sys/ssl/SslSocket.cpp \
+ qpid/sys/ssl/SslIo.h \
+ qpid/sys/ssl/SslIo.cpp
+
+libsslcommon_la_LIBADD= -lnss3 -lssl3 -lnspr4 libqpidcommon.la
+
+libsslcommon_la_CXXFLAGS=$(AM_CXXFLAGS) $(SSL_CFLAGS)
+
+lib_LTLIBRARIES += libsslcommon.la
+
+ssl_la_SOURCES = \
+ qpid/sys/SslPlugin.cpp \
+ qpid/sys/ssl/SslHandler.h \
+ qpid/sys/ssl/SslHandler.cpp
+
+ssl_la_LIBADD= libqpidbroker.la libsslcommon.la
+
+ssl_la_CXXFLAGS=$(AM_CXXFLAGS) $(SSL_CFLAGS)
+
+ssl_la_LDFLAGS = $(PLUGINLDFLAGS)
+
+dmodule_LTLIBRARIES += ssl.la
+
+
+sslconnector_la_SOURCES = \
+ qpid/client/SslConnector.cpp
+
+sslconnector_la_LIBADD = \
+ libqpidclient.la \
+ libsslcommon.la
+
+sslconnector_la_CXXFLAGS = $(AM_CXXFLAGS) -DQPIDC_CONF_FILE=\"$(confdir)/qpidc.conf\" $(SSL_CFLAGS)
+
+sslconnector_la_LDFLAGS = $(PLUGINLDFLAGS)
+
+cmodule_LTLIBRARIES += \
+ sslconnector.la
diff --git a/cpp/src/tests/.valgrind.supp b/cpp/src/tests/.valgrind.supp
index dd8f7536a1..0e3e045437 100644
--- a/cpp/src/tests/.valgrind.supp
+++ b/cpp/src/tests/.valgrind.supp
@@ -1,4 +1,53 @@
{
+ Leak in TCPConnector: https://bugzilla.redhat.com/show_bug.cgi?id=520600
+ Memcheck:Leak
+ fun:_vgrZU_libcZdsoZa_calloc
+ fun:_dl_allocate_tls
+ fun:*
+ fun:*
+ fun:*
+ fun:_ZN4qpid6client12TCPConnector7connectERKSsi
+}
+
+{
+ Leak in TCPConnector: https://bugzilla.redhat.com/show_bug.cgi?id=520600
+ Memcheck:Leak
+ fun:_vgrZU_libcZdsoZa_calloc
+ fun:_dl_allocate_tls
+ fun:*
+ fun:*
+ fun:_ZN4qpid6client12TCPConnector7connectERKSsi
+}
+
+{
+ Reported on FC5 and RHEL5 when md5 sasl libs are installed
+ Memcheck:Leak
+ fun:*
+ fun:_dl_map_object_from_fd
+ fun:_dl_map_object
+ fun:openaux
+ fun:_dl_catch_error
+ fun:_dl_map_object_deps
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:*
+ fun:_sasl_get_plugin
+ fun:_sasl_load_plugins
+ fun:sasl_client_init
+}
+{
+ Benign leak in CPG - patched version.
+ Memcheck:Leak
+ fun:*
+ fun:openais_service_connect
+ fun:cpg_initialize
+}
+
+{
Benign error in libcpg.
Memcheck:Param
socketcall.sendmsg(msg.msg_iov[i])
@@ -24,13 +73,6 @@
}
{
- Bogus epoll_ctl error on i386
- Memcheck:Param
- epoll_ctl(event)
- fun:epoll_ctl
-}
-
-{
boost 103200 -- we think Boost is responsible for these leaks.
Memcheck:Leak
fun:_Znwm
@@ -193,9 +235,42 @@
}
{
- CPG related errors - seem benign but should invesgitate.
+ CPG error - seems benign.
Memcheck:Param
socketcall.sendmsg(msg.msg_iov[i])
- fun:sendmsg
- obj:/usr/lib/openais/libcpg.so.2.0.0
+ obj:*
+ obj:*/libcpg.so.2.0.0
+}
+
+{
+ Known leak in boost.thread 1.33.1. Wildcards for 64/32 bit diffs.
+ Memcheck:Leak
+ fun:*
+ obj:/usr/*/libboost_thread.so.1.33.1
+ fun:_ZN5boost6detail3tss3setEPv
+}
+
+{
+ Shows up on RHEL5: believed benign
+ Memcheck:Cond
+ fun:__strcpy_chk
+ fun:_sasl_load_plugins
+ fun:sasl_client_init
+}
+
+{
+ Seems like a use after delete issue in boost unit_test
+ Memcheck:Addr8
+ fun:_ZN5boost9unit_test14framework_implD1Ev
+ fun:exit
+ fun:(below main)
+}
+
+{
+ Seems like a use after delete issue in boost unit_test
+ Memcheck:Addr4
+ fun:_ZN5boost9unit_test14framework_implD1Ev
+ fun:exit
+ fun:(below main)
}
+
diff --git a/cpp/src/tests/AccumulatedAckTest.cpp b/cpp/src/tests/AccumulatedAckTest.cpp
index 028ce71907..c736a519d2 100644
--- a/cpp/src/tests/AccumulatedAckTest.cpp
+++ b/cpp/src/tests/AccumulatedAckTest.cpp
@@ -8,9 +8,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -28,6 +28,9 @@ using std::list;
using namespace qpid::framing;
+namespace qpid {
+namespace tests {
+
bool covers(const AccumulatedAck& ack, int i)
{
return ack.covers(SequenceNumber(i));
@@ -97,7 +100,7 @@ QPID_AUTO_TEST_CASE(testUpdateFromCompletionData)
ack.update(mark, ranges);
- for(int i = 0; i <= 15; i++) {
+ for(int i = 0; i <= 15; i++) {
BOOST_CHECK(covers(ack, i));
}
BOOST_CHECK(!covers(ack, 16));
@@ -221,7 +224,7 @@ QPID_AUTO_TEST_CASE(testConsolidation4)
ack.update(SequenceNumber(9), SequenceNumber(9));
ack.update(SequenceNumber(3), SequenceNumber(4));
- for(int i = 0; i <= 15; i++) {
+ for(int i = 0; i <= 15; i++) {
BOOST_CHECK(covers(ack, i));
}
BOOST_CHECK(!covers(ack, 16));
@@ -230,3 +233,5 @@ QPID_AUTO_TEST_CASE(testConsolidation4)
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/Address.cpp b/cpp/src/tests/Address.cpp
new file mode 100644
index 0000000000..f25a27d231
--- /dev/null
+++ b/cpp/src/tests/Address.cpp
@@ -0,0 +1,98 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <iostream>
+#include "qpid/messaging/Address.h"
+#include "qpid/messaging/Variant.h"
+
+#include "unit_test.h"
+
+using namespace qpid::messaging;
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(AddressSuite)
+
+QPID_AUTO_TEST_CASE(testParseNameOnly)
+{
+ Address address("my-topic");
+ BOOST_CHECK_EQUAL(std::string("my-topic"), address.getName());
+}
+
+QPID_AUTO_TEST_CASE(testParseSubject)
+{
+ Address address("my-topic/my-subject");
+ BOOST_CHECK_EQUAL(std::string("my-topic"), address.getName());
+ BOOST_CHECK_EQUAL(std::string("my-subject"), address.getSubject());
+}
+
+QPID_AUTO_TEST_CASE(testParseOptions)
+{
+ Address address("my-topic; {a:bc, x:101, y:'a string'}");
+ BOOST_CHECK_EQUAL(std::string("my-topic"), address.getName());
+ BOOST_CHECK_EQUAL(std::string("bc"), address.getOption("a").asString());
+ BOOST_CHECK_EQUAL((uint16_t) 101, address.getOption("x").asInt64());
+ BOOST_CHECK_EQUAL(std::string("a string"), address.getOption("y").asString());
+}
+
+QPID_AUTO_TEST_CASE(testParseSubjectAndOptions)
+{
+ Address address("my-topic/my-subject; {a:bc, x:101, y:'a string'}");
+ BOOST_CHECK_EQUAL(std::string("my-topic"), address.getName());
+ BOOST_CHECK_EQUAL(std::string("my-subject"), address.getSubject());
+ BOOST_CHECK_EQUAL(std::string("bc"), address.getOption("a").asString());
+ BOOST_CHECK_EQUAL((uint16_t) 101, address.getOption("x").asInt64());
+ BOOST_CHECK_EQUAL(std::string("a string"), address.getOption("y").asString());
+}
+
+QPID_AUTO_TEST_CASE(testParseNestedOptions)
+{
+ Address address("my-topic; {a:{p:202, q:'another string'}, x:101, y:'a string'}");
+ BOOST_CHECK_EQUAL(std::string("my-topic"), address.getName());
+ BOOST_CHECK_EQUAL((uint16_t) 202, address.getOptions()["a"].asMap()["p"].asInt64());
+ BOOST_CHECK_EQUAL(std::string("another string"), address.getOptions()["a"].asMap()["q"].asString());
+ BOOST_CHECK_EQUAL((uint16_t) 101, address.getOption("x").asInt64());
+ BOOST_CHECK_EQUAL(std::string("a string"), address.getOption("y").asString());
+}
+
+QPID_AUTO_TEST_CASE(testParseOptionsWithList)
+{
+ Address address("my-topic; {a:[202, 'another string'], x:101}");
+ BOOST_CHECK_EQUAL(std::string("my-topic"), address.getName());
+ Variant::List& list = address.getOptions()["a"].asList();
+ Variant::List::const_iterator i = list.begin();
+ BOOST_CHECK(i != list.end());
+ BOOST_CHECK_EQUAL((uint16_t) 202, i->asInt64());
+ BOOST_CHECK(++i != list.end());
+ BOOST_CHECK_EQUAL(std::string("another string"), i->asString());
+ BOOST_CHECK_EQUAL((uint16_t) 101, address.getOption("x").asInt64());
+}
+
+QPID_AUTO_TEST_CASE(testParseQuotedNameAndSubject)
+{
+ Address address("'my topic with / in it'/'my subject with ; in it'");
+ BOOST_CHECK_EQUAL(std::string("my topic with / in it"), address.getName());
+ BOOST_CHECK_EQUAL(std::string("my subject with ; in it"), address.getSubject());
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+}}
diff --git a/cpp/src/tests/Array.cpp b/cpp/src/tests/Array.cpp
index c779cbe901..7622b89d15 100644
--- a/cpp/src/tests/Array.cpp
+++ b/cpp/src/tests/Array.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -25,6 +25,9 @@
#include "unit_test.h"
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(ArrayTestSuite)
using namespace qpid::framing;
@@ -69,7 +72,7 @@ QPID_AUTO_TEST_CASE(testArrayAssignment)
Array a(data);
b = a;
BOOST_CHECK_EQUAL(a, b);
- }
+ }
std::vector<std::string> data2;
b.collect(data2);
//BOOST_CHECK_EQUAL(data, data2);
@@ -77,3 +80,5 @@ QPID_AUTO_TEST_CASE(testArrayAssignment)
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/AsyncCompletion.cpp b/cpp/src/tests/AsyncCompletion.cpp
new file mode 100644
index 0000000000..e32097106f
--- /dev/null
+++ b/cpp/src/tests/AsyncCompletion.cpp
@@ -0,0 +1,120 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#include "unit_test.h"
+#include "test_tools.h"
+#include "BrokerFixture.h"
+#include "qpid/broker/NullMessageStore.h"
+#include "qpid/sys/BlockingQueue.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/sys/Time.h"
+#include "qpid/framing/QueueQueryResult.h"
+#include "qpid/client/TypedResult.h"
+
+using namespace std;
+using namespace qpid;
+using namespace client;
+using namespace framing;
+
+namespace qpid { namespace broker {
+class TransactionContext;
+class PersistableQueue;
+}}
+
+using broker::PersistableMessage;
+using broker::NullMessageStore;
+using broker::TransactionContext;
+using broker::PersistableQueue;
+using sys::TIME_SEC;
+using boost::intrusive_ptr;
+
+/** @file Unit tests for async completion.
+ * Using a dummy store, verify that the broker indicates async completion of
+ * message enqueues at the correct time.
+ */
+
+namespace qpid {
+namespace tests {
+
+class AsyncCompletionMessageStore : public NullMessageStore {
+ public:
+ sys::BlockingQueue<boost::intrusive_ptr<PersistableMessage> > enqueued;
+
+ AsyncCompletionMessageStore() : NullMessageStore() {}
+ ~AsyncCompletionMessageStore(){}
+
+ void enqueue(TransactionContext*,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& )
+ {
+ enqueued.push(msg);
+ }
+};
+
+QPID_AUTO_TEST_SUITE(AsyncCompletionTestSuite)
+
+QPID_AUTO_TEST_CASE(testWaitTillComplete) {
+ SessionFixture fix;
+ AsyncCompletionMessageStore* store = new AsyncCompletionMessageStore;
+ boost::shared_ptr<qpid::broker::MessageStore> p;
+ p.reset(store);
+ fix.broker->setStore(p);
+ AsyncSession s = fix.session;
+
+ static const int count = 3;
+
+ s.queueDeclare("q", arg::durable=true);
+ Completion transfers[count];
+ for (int i = 0; i < count; ++i) {
+ Message msg(boost::lexical_cast<string>(i), "q");
+ msg.getDeliveryProperties().setDeliveryMode(PERSISTENT);
+ transfers[i] = s.messageTransfer(arg::content=msg);
+ }
+
+ // Get hold of the broker-side messages.
+ typedef vector<intrusive_ptr<PersistableMessage> > BrokerMessages;
+ BrokerMessages enqueued;
+ for (int j = 0; j < count; ++j)
+ enqueued.push_back(store->enqueued.pop(TIME_SEC));
+
+ // Send a sync, make sure it does not complete till all messages are complete.
+ // In reverse order for fun.
+ Completion sync = s.executionSync(arg::sync=true);
+ for (int k = count-1; k >= 0; --k) {
+ BOOST_CHECK(!transfers[k].isComplete()); // Should not be complete yet.
+ BOOST_CHECK(!sync.isComplete()); // Should not be complete yet.
+ enqueued[k]->enqueueComplete();
+ }
+ sync.wait(); // Should complete now, all messages are completed.
+}
+
+QPID_AUTO_TEST_CASE(testGetResult) {
+ SessionFixture fix;
+ AsyncSession s = fix.session;
+
+ s.queueDeclare("q", arg::durable=true);
+ TypedResult<QueueQueryResult> tr = s.queueQuery("q");
+ QueueQueryResult qq = tr.get();
+ BOOST_CHECK_EQUAL(qq.getQueue(), "q");
+ BOOST_CHECK_EQUAL(qq.getMessageCount(), 0U);
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/AtomicValue.cpp b/cpp/src/tests/AtomicValue.cpp
index 05083ad177..d855d993a7 100644
--- a/cpp/src/tests/AtomicValue.cpp
+++ b/cpp/src/tests/AtomicValue.cpp
@@ -21,6 +21,9 @@
#include "test_tools.h"
#include "qpid/sys/AtomicValue.h"
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(AtomicValueTestSuite)
QPID_AUTO_TEST_CASE(test) {
@@ -47,3 +50,5 @@ QPID_AUTO_TEST_CASE(test) {
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/BasicP2PTest.cpp b/cpp/src/tests/BasicP2PTest.cpp
deleted file mode 100644
index f4a4cce7f2..0000000000
--- a/cpp/src/tests/BasicP2PTest.cpp
+++ /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 "BasicP2PTest.h"
-
-using namespace qpid;
-using namespace qpid::client;
-
-class BasicP2PTest::Receiver : public Worker, public MessageListener
-{
- const std::string queue;
- std::string tag;
-public:
- Receiver(ConnectionOptions& options, const std::string& _queue, const int _messages)
- : Worker(options, _messages), queue(_queue){}
- void init()
- {
- Queue q(queue, true);
- channel.declareQueue(q);
- framing::FieldTable args;
- channel.bind(Exchange::STANDARD_DIRECT_EXCHANGE, q, queue, args);
- channel.consume(q, tag, this);
- channel.start();
- }
-
- void start()
- {
- }
-
- void received(Message&)
- {
- count++;
- }
-};
-
-void BasicP2PTest::assign(const std::string& role, framing::FieldTable& params, ConnectionOptions& options)
-{
- std::string queue = params.getString("P2P_QUEUE_AND_KEY_NAME");
- int messages = params.getInt("P2P_NUM_MESSAGES");
- if (role == "SENDER") {
- worker = std::auto_ptr<Worker>(new Sender(options, Exchange::STANDARD_DIRECT_EXCHANGE, queue, messages));
- } else if(role == "RECEIVER"){
- worker = std::auto_ptr<Worker>(new Receiver(options, queue, messages));
- } else {
- throw Exception("unrecognised role");
- }
- worker->init();
-}
diff --git a/cpp/src/tests/BasicP2PTest.h b/cpp/src/tests/BasicP2PTest.h
deleted file mode 100644
index b2611f0301..0000000000
--- a/cpp/src/tests/BasicP2PTest.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef _BasicP2PTest_
-#define _BasicP2PTest_
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <memory>
-#include <sstream>
-
-#include "qpid/Exception.h"
-#include "qpid/client/Channel.h"
-#include "qpid/client/Message.h"
-#include "qpid/client/Connection.h"
-#include "qpid/client/MessageListener.h"
-#include "SimpleTestCaseBase.h"
-
-
-namespace qpid {
-
-class BasicP2PTest : public SimpleTestCaseBase
-{
- class Receiver;
-public:
- void assign(const std::string& role, framing::FieldTable& params, ConnectionOptions& options);
-};
-
-}
-
-#endif
diff --git a/cpp/src/tests/BasicPubSubTest.cpp b/cpp/src/tests/BasicPubSubTest.cpp
deleted file mode 100644
index 1e9ff364f1..0000000000
--- a/cpp/src/tests/BasicPubSubTest.cpp
+++ /dev/null
@@ -1,121 +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 "BasicPubSubTest.h"
-
-using namespace qpid;
-
-class BasicPubSubTest::Receiver : public Worker, public MessageListener
-{
- const Exchange& exchange;
- const std::string queue;
- const std::string key;
- std::string tag;
-public:
- Receiver(ConnectionOptions& options, const Exchange& _exchange, const std::string& _queue, const std::string& _key, const int _messages)
- : Worker(options, _messages), exchange(_exchange), queue(_queue), key(_key){}
-
- void init()
- {
- Queue q(queue, true);
- channel.declareQueue(q);
- framing::FieldTable args;
- channel.bind(exchange, q, key, args);
- channel.consume(q, tag, this);
- channel.start();
- }
-
- void start(){
- }
-
- void received(Message&)
- {
- count++;
- }
-};
-
-class BasicPubSubTest::MultiReceiver : public Worker, public MessageListener
-{
- typedef boost::ptr_vector<Receiver> ReceiverList;
- ReceiverList receivers;
-
-public:
- MultiReceiver(ConnectionOptions& options, const Exchange& exchange, const std::string& key, const int _messages, int receiverCount)
- : Worker(options, _messages)
- {
- for (int i = 0; i != receiverCount; i++) {
- std::string queue = (boost::format("%1%_%2%") % options.clientid % i).str();
- receivers.push_back(new Receiver(options, exchange, queue, key, _messages));
- }
- }
-
- void init()
- {
- for (ReceiverList::size_type i = 0; i != receivers.size(); i++) {
- receivers[i].init();
- }
- }
-
- void start()
- {
- for (ReceiverList::size_type i = 0; i != receivers.size(); i++) {
- receivers[i].start();
- }
- }
-
- void received(Message& msg)
- {
- for (ReceiverList::size_type i = 0; i != receivers.size(); i++) {
- receivers[i].received(msg);
- }
- }
-
- virtual int getCount()
- {
- count = 0;
- for (ReceiverList::size_type i = 0; i != receivers.size(); i++) {
- count += receivers[i].getCount();
- }
- return count;
- }
- virtual void stop()
- {
- for (ReceiverList::size_type i = 0; i != receivers.size(); i++) {
- receivers[i].stop();
- }
- }
-};
-
-void BasicPubSubTest::assign(const std::string& role, framing::FieldTable& params, ConnectionOptions& options)
-{
- std::string key = params.getString("PUBSUB_KEY");
- int messages = params.getInt("PUBSUB_NUM_MESSAGES");
- int receivers = params.getInt("PUBSUB_NUM_RECEIVERS");
- if (role == "SENDER") {
- worker = std::auto_ptr<Worker>(new Sender(options, Exchange::STANDARD_TOPIC_EXCHANGE, key, messages));
- } else if(role == "RECEIVER"){
- worker = std::auto_ptr<Worker>(new MultiReceiver(options, Exchange::STANDARD_TOPIC_EXCHANGE, key, messages, receivers));
- } else {
- throw Exception("unrecognised role");
- }
- worker->init();
-}
-
diff --git a/cpp/src/tests/BasicPubSubTest.h b/cpp/src/tests/BasicPubSubTest.h
deleted file mode 100644
index 242d2847d7..0000000000
--- a/cpp/src/tests/BasicPubSubTest.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef _BasicPubSubTest_
-#define _BasicPubSubTest_
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <memory>
-#include <sstream>
-
-#include "qpid/Exception.h"
-#include "qpid/client/Channel.h"
-#include "qpid/client/Message.h"
-#include "qpid/client/Connection.h"
-#include "qpid/client/MessageListener.h"
-#include "SimpleTestCaseBase.h"
-#include <boost/ptr_container/ptr_vector.hpp>
-#include <boost/format.hpp>
-
-
-namespace qpid {
-
-using namespace qpid::client;
-
-class BasicPubSubTest : public SimpleTestCaseBase
-{
- class Receiver;
- class MultiReceiver;
-public:
- void assign(const std::string& role, framing::FieldTable& params, ConnectionOptions& options);
-};
-
-}
-
-#endif
diff --git a/cpp/src/tests/Blob.cpp b/cpp/src/tests/Blob.cpp
index c40e43b96e..e69de29bb2 100644
--- a/cpp/src/tests/Blob.cpp
+++ b/cpp/src/tests/Blob.cpp
@@ -1,128 +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/framing/Blob.h"
-
-#include "unit_test.h"
-
-QPID_AUTO_TEST_SUITE(BlobTestSuite)
-
-using namespace std;
-using namespace qpid::framing;
-
-struct Base {
- int id;
- int magic;
-
- Base(int n) : id(n), magic(42) {}
- Base(const Base& c) : id(c.id), magic(42) {}
- ~Base() { BOOST_CHECK_EQUAL(42, magic); } // Detect random data.
-};
-
-template <class T> struct Count : public Base {
- static int instances;
- bool destroyed;
-
- Count(int n) : Base(n), destroyed(false) { ++instances; }
- Count(const Count& c) : Base(c), destroyed(false) { ++instances; }
- ~Count() {
- BOOST_CHECK(!destroyed); // Detect double-destructor
- destroyed=true;
- BOOST_CHECK(--instances >= 0);
- }
-};
-
-template <class T> int Count<T>::instances = 0;
-
-struct Foo : public Count<Foo> { Foo(int n) : Count<Foo>(n) {}; };
-struct Bar : public Count<Bar> { Bar(int n) : Count<Bar>(n) {}; };
-
-typedef Blob<sizeof(Foo), Base> TestBlob ;
-
-QPID_AUTO_TEST_CASE(testBlobCtor) {
- {
- TestBlob empty;
- BOOST_CHECK(empty.empty());
- BOOST_CHECK(empty.get() == 0);
-
- TestBlob empty2(empty);
- BOOST_CHECK(empty2.empty());
-
- TestBlob foo(in_place<Foo>(1));
- BOOST_CHECK(!foo.empty());
- BOOST_CHECK_EQUAL(1, foo.get()->id);
- BOOST_CHECK_EQUAL(1, Foo::instances);
-
- TestBlob foo2(foo);
- BOOST_CHECK(!foo2.empty());
- BOOST_CHECK_EQUAL(1, foo2.get()->id);
- BOOST_CHECK_EQUAL(2, Foo::instances);
- }
-
- BOOST_CHECK_EQUAL(0, Foo::instances);
- BOOST_CHECK_EQUAL(0, Bar::instances);
-}
-
-
-QPID_AUTO_TEST_CASE(testAssign) {
- {
- TestBlob b;
- b = Foo(2);
- BOOST_CHECK_EQUAL(2, b.get()->id);
- BOOST_CHECK_EQUAL(1, Foo::instances);
-
- TestBlob b2(b);
- BOOST_CHECK_EQUAL(2, b.get()->id);
- BOOST_CHECK_EQUAL(2, Foo::instances);
-
- b2 = Bar(3);
- BOOST_CHECK_EQUAL(3, b2.get()->id);
- BOOST_CHECK_EQUAL(1, Foo::instances);
- BOOST_CHECK_EQUAL(1, Bar::instances);
-
- b2 = in_place<Foo>(4);
- BOOST_CHECK_EQUAL(4, b2.get()->id);
- BOOST_CHECK_EQUAL(2, Foo::instances);
- BOOST_CHECK_EQUAL(0, Bar::instances);
-
- b2.clear();
- BOOST_CHECK(b2.empty());
- BOOST_CHECK_EQUAL(1, Foo::instances);
- }
- BOOST_CHECK_EQUAL(0, Foo::instances);
- BOOST_CHECK_EQUAL(0, Bar::instances);
-}
-
-
-QPID_AUTO_TEST_CASE(testClear) {
- TestBlob b(in_place<Foo>(5));
- TestBlob c(b);
- BOOST_CHECK(!c.empty());
- BOOST_CHECK(!b.empty());
- BOOST_CHECK_EQUAL(2, Foo::instances);
-
- c.clear();
- BOOST_CHECK(c.empty());
- BOOST_CHECK_EQUAL(1, Foo::instances);
-
- b.clear();
- BOOST_CHECK(b.empty());
- BOOST_CHECK_EQUAL(0, Foo::instances);
-}
-
-QPID_AUTO_TEST_SUITE_END()
diff --git a/cpp/src/tests/BrokerFixture.h b/cpp/src/tests/BrokerFixture.h
index 09cca066ef..566fbda406 100644
--- a/cpp/src/tests/BrokerFixture.h
+++ b/cpp/src/tests/BrokerFixture.h
@@ -10,9 +10,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -23,14 +23,21 @@
*/
#include "SocketProxy.h"
-#include "qpid/sys/Thread.h"
+
#include "qpid/broker/Broker.h"
#include "qpid/client/Connection.h"
#include "qpid/client/ConnectionImpl.h"
#include "qpid/client/Session.h"
#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/LocalQueue.h"
+#include "qpid/log/Logger.h"
+#include "qpid/log/Options.h"
+#include "qpid/sys/Thread.h"
#include <boost/noncopyable.hpp>
+namespace qpid {
+namespace tests {
+
/**
* A fixture with an in-process broker.
*/
@@ -42,9 +49,16 @@ struct BrokerFixture : private boost::noncopyable {
qpid::sys::Thread brokerThread;
BrokerFixture(Broker::Options opts=Broker::Options()) {
+ // Keep the tests quiet unless logging env. vars have been set by user.
+ if (!::getenv("QPID_LOG_ENABLE") && !::getenv("QPID_TRACE")) {
+ qpid::log::Options logOpts;
+ logOpts.selectors.clear();
+ logOpts.selectors.push_back("error+");
+ qpid::log::Logger::instance().configure(logOpts);
+ }
opts.port=0;
// Management doesn't play well with multiple in-process brokers.
- opts.enableMgmt=false;
+ opts.enableMgmt=false;
opts.workerThreads=1;
opts.dataDir="";
opts.auth=false;
@@ -52,26 +66,35 @@ struct BrokerFixture : private boost::noncopyable {
// TODO aconway 2007-12-05: At one point BrokerFixture
// tests could hang in Connection ctor if the following
// line is removed. This may not be an issue anymore.
- broker->getPort();
+ broker->accept();
+ broker->getPort(qpid::broker::Broker::TCP_TRANSPORT);
brokerThread = qpid::sys::Thread(*broker);
};
- ~BrokerFixture() {
+ void shutdownBroker()
+ {
broker->shutdown();
+ broker = BrokerPtr();
+ }
+
+ ~BrokerFixture() {
+ if (broker) broker->shutdown();
brokerThread.join();
}
/** Open a connection to the broker. */
void open(qpid::client::Connection& c) {
- c.open("localhost", broker->getPort());
+ c.open("localhost", broker->getPort(qpid::broker::Broker::TCP_TRANSPORT));
}
- uint16_t getPort() { return broker->getPort(); }
+ uint16_t getPort() { return broker->getPort(qpid::broker::Broker::TCP_TRANSPORT); }
};
/** Connection that opens in its constructor */
struct LocalConnection : public qpid::client::Connection {
LocalConnection(uint16_t port) { open("localhost", port); }
+ LocalConnection(const qpid::client::ConnectionSettings& s) { open(s); }
+ ~LocalConnection() { close(); }
};
/** A local client connection via a socket proxy. */
@@ -80,6 +103,11 @@ struct ProxyConnection : public qpid::client::Connection {
ProxyConnection(int brokerPort) : proxy(brokerPort) {
open("localhost", proxy.getPort());
}
+ ProxyConnection(const qpid::client::ConnectionSettings& s) : proxy(s.port) {
+ qpid::client::ConnectionSettings proxySettings(s);
+ proxySettings.port = proxy.getPort();
+ open(proxySettings);
+ }
~ProxyConnection() { close(); }
};
@@ -92,9 +120,15 @@ struct ClientT {
SessionType session;
qpid::client::SubscriptionManager subs;
qpid::client::LocalQueue lq;
- ClientT(uint16_t port) : connection(port), session(connection.newSession()), subs(session) {}
+ std::string name;
+
+ ClientT(uint16_t port, const std::string& name_=std::string())
+ : connection(port), session(connection.newSession(name_)), subs(session), name(name_) {}
+ ClientT(const qpid::client::ConnectionSettings& settings, const std::string& name_=std::string())
+ : connection(settings), session(connection.newSession(name_)), subs(session), name(name_) {}
- ~ClientT() { connection.close(); }
+ ~ClientT() { close(); }
+ void close() { session.close(); connection.close(); }
};
typedef ClientT<> Client;
@@ -107,7 +141,7 @@ struct SessionFixtureT : BrokerFixture, ClientT<ConnectionType,SessionType> {
SessionFixtureT(Broker::Options opts=Broker::Options()) :
BrokerFixture(opts),
- ClientT<ConnectionType,SessionType>(broker->getPort())
+ ClientT<ConnectionType,SessionType>(broker->getPort(qpid::broker::Broker::TCP_TRANSPORT))
{}
};
@@ -115,5 +149,6 @@ struct SessionFixtureT : BrokerFixture, ClientT<ConnectionType,SessionType> {
typedef SessionFixtureT<LocalConnection> SessionFixture;
typedef SessionFixtureT<ProxyConnection> ProxySessionFixture;
+}} // namespace qpid::tests
#endif /*!TESTS_BROKERFIXTURE_H*/
diff --git a/cpp/src/tests/CMakeLists.txt b/cpp/src/tests/CMakeLists.txt
new file mode 100644
index 0000000000..469d777dce
--- /dev/null
+++ b/cpp/src/tests/CMakeLists.txt
@@ -0,0 +1,345 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Enable dashboard reporting.
+include (CTest)
+
+# Make sure that everything get built before the tests
+# Need to create a var with all the necessary top level targets
+
+add_definitions(-DBOOST_TEST_DYN_LINK)
+include_directories( ${CMAKE_CURRENT_SOURCE_DIR} )
+
+include (FindPythonInterp)
+
+# Create the environment scripts for tests
+set (abs_srcdir ${CMAKE_CURRENT_SOURCE_DIR})
+set (abs_builddir ${CMAKE_CURRENT_BINARY_DIR})
+set (abs_top_srcdir ${CMAKE_SOURCE_DIR})
+set (abs_top_builddir ${CMAKE_BINARY_DIR})
+set (builddir_lib_suffix "")
+configure_file (${CMAKE_CURRENT_SOURCE_DIR}/test_env.sh.in
+ ${CMAKE_CURRENT_BINARY_DIR}/test_env.sh)
+
+
+# If valgrind is selected in the configuration step, set up the path to it
+# for CTest.
+if (ENABLE_VALGRIND)
+ set (MEMORYCHECK_COMMAND ${VALGRIND})
+ set (MEMORYCHECK_COMMAND_OPTIONS "--gen-suppressions=all
+--leak-check=full
+--demangle=yes
+--suppressions=${CMAKE_CURRENT_SOURCE_DIR}/.valgrind.supp
+--num-callers=25
+--log-file=ctest_valgrind.vglog")
+endif (ENABLE_VALGRIND)
+
+# Using the Boost DLLs triggers warning 4275 on Visual Studio
+# (non dll-interface class used as base for dll-interface class).
+# This is ok, so suppress the warning.
+# Also, boost lengthy names trigger warning 4503, decorated name length exceeded
+# and using getenv() triggers insecure CRT warnings which we can silence in the
+# test environment.
+if (MSVC)
+ add_definitions( /wd4275 /wd4503 /D_CRT_SECURE_NO_WARNINGS)
+endif (MSVC)
+
+# Like this to work with cmake 2.4 on Unix
+set (qpid_test_boost_libs
+ ${Boost_REGEX_LIBRARY}
+ ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
+
+# Macro to make it easier to remember where the tests are built
+macro(remember_location testname)
+ set (${testname}_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/${testname}${CMAKE_EXECUTABLE_SUFFIX})
+endmacro(remember_location)
+
+# Windows uses some process-startup calls to ensure that errors, etc. don't
+# result in error boxes being thrown up. Since it's expected that most test
+# runs will be in scripts, the default is to force these outputs to stderr
+# instead of windows. If you want to remove this code, build without the
+# QPID_WINDOWS_DEFAULT_TEST_OUTPUTS ON.
+if (CMAKE_SYSTEM_NAME STREQUAL Windows)
+ option(QPID_WINDOWS_DEFAULT_TEST_OUTPUTS "Use default error-handling on Windows tests" OFF)
+ if (NOT QPID_WINDOWS_DEFAULT_TEST_OUTPUTS)
+ set(platform_test_additions windows/DisableWin32ErrorWindows.cpp)
+ endif (NOT QPID_WINDOWS_DEFAULT_TEST_OUTPUTS)
+endif (CMAKE_SYSTEM_NAME STREQUAL Windows)
+
+#
+# Unit test program
+#
+# Unit tests are built as a single program to reduce valgrind overhead
+# when running the tests. If you want to build a subset of the tests run
+# ccmake and set unit_tests_to_build to the set you want to build.
+
+set(unit_tests_to_build
+ exception_test
+ RefCounted
+ SessionState
+ logging
+ AsyncCompletion
+ Url
+ Uuid
+ Shlib
+ FieldValue
+ FieldTable
+ Array
+ QueueOptionsTest
+ InlineAllocator
+ InlineVector
+ ClientSessionTest
+ MessagingSessionTests
+ SequenceSet
+ StringUtils
+ IncompleteMessageList
+ RangeSet
+ AtomicValue
+ QueueTest
+ AccumulatedAckTest
+ DtxWorkRecordTest
+ DeliveryRecordTest
+ ExchangeTest
+ HeadersExchangeTest
+ MessageTest
+ QueueRegistryTest
+ QueuePolicyTest
+ FramingTest
+ HeaderTest
+ SequenceNumberTest
+ TimerTest
+ TopicExchangeTest
+ TxBufferTest
+ TxPublishTest
+ MessageBuilderTest
+ ManagementTest
+ MessageReplayTracker
+ ConsoleTest
+ QueueEvents
+ ProxyTest
+ RetryList
+ RateFlowcontrolTest
+ FrameDecoder
+ ReplicationTest
+ ClientMessageTest
+ PollableCondition
+ Variant
+ ClientMessage
+ ${xml_tests}
+ CACHE STRING "Which unit tests to build"
+ )
+
+mark_as_advanced(unit_tests_to_build)
+
+# Disabled till we move to amqp_0_10 codec.
+# amqp_0_10/serialize.cpp allSegmentTypes.h \
+# amqp_0_10/ProxyTemplate.cpp \
+# amqp_0_10/apply.cpp \
+# amqp_0_10/Map.cpp \
+# amqp_0_10/handlers.cpp
+
+add_executable (unit_test unit_test
+ ${unit_tests_to_build} ${platform_test_additions})
+# The generally recommended way to add macro settings is to use
+# COMPILE_DEFINITIONS, but it's a rough go to add more than one definition
+# with a value; in this case, assuming that -D works everywhere is easier.
+set_source_files_properties (ReplicationTest.cpp Shlib.cpp ${xml_tests}
+ PROPERTIES
+ COMPILE_FLAGS
+ "-DQPID_MODULE_SUFFIX=\\\"${CMAKE_SHARED_MODULE_SUFFIX}\\\" -DQPID_MODULE_PREFIX=\\\"${CMAKE_SHARED_MODULE_PREFIX}\\\"")
+target_link_libraries (unit_test
+ ${qpid_test_boost_libs}
+ qpidclient qpidbroker qmfconsole)
+remember_location(unit_test)
+
+add_library (shlibtest MODULE shlibtest.cpp)
+
+if (BUILD_CLUSTER)
+ include (cluster.cmake)
+endif (BUILD_CLUSTER)
+
+# FIXME aconway 2009-11-30: enable SSL
+#if SSL
+#include ssl.mk
+#endif
+
+#
+# Other test programs
+#
+add_executable (perftest perftest.cpp ${platform_test_additions})
+target_link_libraries (perftest qpidclient)
+#perftest_SOURCES=perftest.cpp test_tools.h TestOptions.h ConnectionOptions.h
+remember_location(perftest)
+
+add_executable (txtest txtest.cpp ${platform_test_additions})
+target_link_libraries (txtest qpidclient)
+#txtest_SOURCES=txtest.cpp TestOptions.h ConnectionOptions.h
+remember_location(txtest)
+
+add_executable (latencytest latencytest.cpp ${platform_test_additions})
+target_link_libraries (latencytest qpidclient)
+#latencytest_SOURCES=latencytest.cpp TestOptions.h ConnectionOptions.h
+remember_location(latencytest)
+
+add_executable (echotest echotest.cpp ${platform_test_additions})
+target_link_libraries (echotest qpidclient)
+#echotest_SOURCES=echotest.cpp TestOptions.h ConnectionOptions.h
+remember_location(echotest)
+
+add_executable (client_test client_test.cpp ${platform_test_additions})
+target_link_libraries (client_test qpidclient)
+#client_test_SOURCES=client_test.cpp TestOptions.h ConnectionOptions.h
+remember_location(client_test)
+
+add_executable (topic_listener topic_listener.cpp ${platform_test_additions})
+target_link_libraries (topic_listener qpidclient)
+#topic_listener_SOURCES=topic_listener.cpp TestOptions.h ConnectionOptions.h
+remember_location(topic_listener)
+
+add_executable (topic_publisher topic_publisher.cpp ${platform_test_additions})
+target_link_libraries (topic_publisher qpidclient)
+#topic_publisher_SOURCES=topic_publisher.cpp TestOptions.h ConnectionOptions.h
+remember_location(topic_publisher)
+
+add_executable (publish publish.cpp ${platform_test_additions})
+target_link_libraries (publish qpidclient)
+#publish_SOURCES=publish.cpp TestOptions.h ConnectionOptions.h
+remember_location(publish)
+
+add_executable (consume consume.cpp ${platform_test_additions})
+target_link_libraries (consume qpidclient)
+#consume_SOURCES=consume.cpp TestOptions.h ConnectionOptions.h
+remember_location(consume)
+
+add_executable (header_test header_test.cpp ${platform_test_additions})
+target_link_libraries (header_test qpidclient)
+#header_test_SOURCES=header_test.cpp TestOptions.h ConnectionOptions.h
+remember_location(header_test)
+
+add_executable (declare_queues declare_queues.cpp ${platform_test_additions})
+target_link_libraries (declare_queues qpidclient)
+remember_location(declare_queues)
+
+add_executable (replaying_sender replaying_sender.cpp ${platform_test_additions})
+target_link_libraries (replaying_sender qpidclient)
+remember_location(replaying_sender)
+
+add_executable (resuming_receiver resuming_receiver.cpp ${platform_test_additions})
+target_link_libraries (resuming_receiver qpidclient)
+remember_location(resuming_receiver)
+
+add_executable (txshift txshift.cpp ${platform_test_additions})
+target_link_libraries (txshift qpidclient)
+#txshift_SOURCES=txshift.cpp TestOptions.h ConnectionOptions.h
+remember_location(txshift)
+
+add_executable (txjob txjob.cpp ${platform_test_additions})
+target_link_libraries (txjob qpidclient)
+#txjob_SOURCES=txjob.cpp TestOptions.h ConnectionOptions.h
+remember_location(txjob)
+
+add_executable (receiver receiver.cpp ${platform_test_additions})
+target_link_libraries (receiver qpidclient)
+#receiver_SOURCES=receiver.cpp TestOptions.h ConnectionOptions.h
+remember_location(receiver)
+
+add_executable (sender sender.cpp ${platform_test_additions})
+target_link_libraries (sender qpidclient)
+#sender_SOURCES=sender.cpp TestOptions.h ConnectionOptions.h
+remember_location(sender)
+
+if (CMAKE_SYSTEM_NAME STREQUAL Windows)
+ set (ENV{OUTDIR} ${EXECUTABLE_OUTPUT_PATH})
+ set (test_script_suffix ".ps1")
+ set (shell "powershell")
+endif (CMAKE_SYSTEM_NAME STREQUAL Windows)
+
+set(test_wrap ${shell} ${CMAKE_CURRENT_SOURCE_DIR}/run_test${test_script_suffix})
+
+add_test (unit_test ${test_wrap} ${unit_test_LOCATION})
+add_test (start_broker ${shell} ${CMAKE_CURRENT_SOURCE_DIR}/start_broker${test_script_suffix})
+add_test (client_test ${test_wrap} ${client_test_LOCATION})
+add_test (quick_perftest ${test_wrap} ${perftest_LOCATION} --summary --count 100)
+add_test (quick_topictest ${test_wrap} ${CMAKE_CURRENT_SOURCE_DIR}/quick_topictest${test_script_suffix})
+add_test (quick_txtest ${test_wrap} ${txtest_LOCATION} --queues 4 --tx-count 10 --quiet)
+if (PYTHON_EXECUTABLE)
+ add_test (run_header_test ${shell} ${CMAKE_CURRENT_SOURCE_DIR}/run_header_test${test_script_suffix})
+ add_test (python_tests ${test_wrap} ${CMAKE_CURRENT_SOURCE_DIR}/python_tests${test_script_suffix})
+endif (PYTHON_EXECUTABLE)
+add_test (stop_broker ${shell} ${CMAKE_CURRENT_SOURCE_DIR}/stop_broker${test_script_suffix})
+if (PYTHON_EXECUTABLE)
+ add_test (federation_tests ${shell} ${CMAKE_CURRENT_SOURCE_DIR}/run_federation_tests${test_script_suffix})
+if (BUILD_ACL)
+ add_test (acl_tests ${shell} ${CMAKE_CURRENT_SOURCE_DIR}/run_acl_tests${test_script_suffix})
+endif (BUILD_ACL)
+endif (PYTHON_EXECUTABLE)
+
+add_library(test_store MODULE test_store.cpp)
+target_link_libraries (test_store qpidbroker qpidcommon)
+set_target_properties (test_store PROPERTIES PREFIX "")
+
+#EXTRA_DIST += \
+# run_test vg_check \
+# run-unit-tests start_broker python_tests stop_broker \
+# quick_topictest \
+# quick_perftest \
+# quick_txtest \
+# topictest \
+# run_header_test \
+# header_test.py \
+# ssl_test \
+# config.null \
+# ais_check \
+# run_federation_tests \
+# run_acl_tests \
+# .valgrind.supp \
+# MessageUtils.h \
+# TestMessageStore.h \
+# TxMocks.h \
+# start_cluster stop_cluster restart_cluster
+
+add_library (dlclose_noop MODULE dlclose_noop.c)
+#libdlclose_noop_la_LDFLAGS = -module -rpath $(abs_builddir)
+
+#CLEANFILES+=valgrind.out *.log *.vglog* dummy_test $(unit_wrappers)
+#
+## FIXME aconway 2008-05-23: Disabled interop_runner because it uses
+## the obsolete Channel class. Convert to Session and re-enable.
+##
+## check_PROGRAMS += interop_runner
+#
+## interop_runner_SOURCES = \
+## interop_runner.cpp \
+## SimpleTestCaseBase.cpp \
+## BasicP2PTest.cpp \
+## BasicPubSubTest.cpp \
+## SimpleTestCaseBase.h \
+## BasicP2PTest.h \
+## BasicPubSubTest.h \
+## TestCase.h \
+## TestOptions.h ConnectionOptions.h
+## interop_runner_LDADD = $(lib_client) $(lib_common) $(extra_libs)
+#
+#
+## Longer running stability tests, not run by default check: target.
+## Not run under valgrind, too slow
+#LONG_TESTS=fanout_perftest shared_perftest multiq_perftest topic_perftest run_failover_soak
+#EXTRA_DIST+=$(LONG_TESTS) run_perftest
+#check-long:
+# $(MAKE) check TESTS="start_broker $(LONG_TESTS) stop_broker" VALGRIND=
diff --git a/cpp/src/tests/ClientMessage.cpp b/cpp/src/tests/ClientMessage.cpp
new file mode 100644
index 0000000000..ab1cf9d102
--- /dev/null
+++ b/cpp/src/tests/ClientMessage.cpp
@@ -0,0 +1,46 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <iostream>
+#include "qpid/messaging/Message.h"
+
+#include "unit_test.h"
+
+using namespace qpid::messaging;
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(ClientMessageSuite)
+
+QPID_AUTO_TEST_CASE(testCopyConstructor)
+{
+ Message m("my-data");
+ m.setSubject("my-subject");
+ m.getHeaders()["a"] = "ABC";
+ Message c(m);
+ BOOST_CHECK_EQUAL(m.getContent(), c.getContent());
+ BOOST_CHECK_EQUAL(m.getSubject(), c.getSubject());
+ BOOST_CHECK_EQUAL(m.getHeaders()["a"], c.getHeaders()["a"]);
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/ClientMessageTest.cpp b/cpp/src/tests/ClientMessageTest.cpp
new file mode 100644
index 0000000000..f925f1c234
--- /dev/null
+++ b/cpp/src/tests/ClientMessageTest.cpp
@@ -0,0 +1,51 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+/**@file Unit tests for the client::Message class. */
+
+#include "unit_test.h"
+#include "qpid/client/Message.h"
+
+using namespace qpid::client;
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(ClientMessageTestSuite)
+
+QPID_AUTO_TEST_CASE(MessageCopyAssign) {
+ // Verify that message has normal copy semantics.
+ Message m("foo");
+ BOOST_CHECK_EQUAL("foo", m.getData());
+ Message c(m);
+ BOOST_CHECK_EQUAL("foo", c.getData());
+ Message a;
+ BOOST_CHECK_EQUAL("", a.getData());
+ a = m;
+ BOOST_CHECK_EQUAL("foo", a.getData());
+ a.setData("a");
+ BOOST_CHECK_EQUAL("a", a.getData());
+ c.setData("c");
+ BOOST_CHECK_EQUAL("c", c.getData());
+ BOOST_CHECK_EQUAL("foo", m.getData());
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/ClientSessionTest.cpp b/cpp/src/tests/ClientSessionTest.cpp
index 0b46d39047..6ca0aa6d44 100644
--- a/cpp/src/tests/ClientSessionTest.cpp
+++ b/cpp/src/tests/ClientSessionTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -19,21 +19,30 @@
*
*/
#include "unit_test.h"
+#include "test_tools.h"
#include "BrokerFixture.h"
-#include "qpid/client/AckPolicy.h"
-#include "qpid/client/Dispatcher.h"
+#include "qpid/client/QueueOptions.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/AsyncSession.h"
#include "qpid/sys/Monitor.h"
#include "qpid/sys/Thread.h"
#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Time.h"
#include "qpid/client/Session.h"
-#include "qpid/framing/TransferContent.h"
+#include "qpid/client/Message.h"
#include "qpid/framing/reply_exceptions.h"
#include <boost/optional.hpp>
#include <boost/lexical_cast.hpp>
+#include <boost/bind.hpp>
+#include <boost/ptr_container/ptr_vector.hpp>
#include <vector>
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(ClientSessionTest)
using namespace qpid::client;
@@ -42,6 +51,7 @@ using namespace qpid;
using qpid::sys::Monitor;
using qpid::sys::Thread;
using qpid::sys::TIME_SEC;
+using qpid::broker::Broker;
using std::string;
using std::cout;
using std::endl;
@@ -51,22 +61,22 @@ struct DummyListener : public sys::Runnable, public MessageListener {
std::vector<Message> messages;
string name;
uint expected;
- Dispatcher dispatcher;
+ SubscriptionManager submgr;
DummyListener(Session& session, const string& n, uint ex) :
- name(n), expected(ex), dispatcher(session) {}
+ name(n), expected(ex), submgr(session) {}
void run()
{
- dispatcher.listen(name, this);
- dispatcher.run();
+ submgr.subscribe(*this, name);
+ submgr.run();
}
void received(Message& msg)
{
messages.push_back(msg);
if (--expected == 0) {
- dispatcher.stop();
+ submgr.stop();
}
}
};
@@ -94,54 +104,33 @@ struct SimpleListener : public MessageListener
struct ClientSessionFixture : public ProxySessionFixture
{
- void declareSubscribe(const string& q="my-queue",
- const string& dest="my-dest")
- {
- session.queueDeclare(arg::queue=q);
- session.messageSubscribe(arg::queue=q, arg::destination=dest, arg::acquireMode=1);
- session.messageFlow(arg::destination=dest, arg::unit=0, arg::value=0xFFFFFFFF);//messages
- session.messageFlow(arg::destination=dest, arg::unit=1, arg::value=0xFFFFFFFF);//bytes
+ ClientSessionFixture(Broker::Options opts = Broker::Options()) : ProxySessionFixture(opts) {
+ session.queueDeclare(arg::queue="my-queue");
}
};
QPID_AUTO_TEST_CASE(testQueueQuery) {
ClientSessionFixture fix;
fix.session = fix.connection.newSession();
- fix.session.queueDeclare(arg::queue="my-queue", arg::alternateExchange="amq.fanout", arg::exclusive=true, arg::autoDelete=true);
- QueueQueryResult result = fix.session.queueQuery(string("my-queue"));
+ fix.session.queueDeclare(arg::queue="q", arg::alternateExchange="amq.fanout",
+ arg::exclusive=true, arg::autoDelete=true);
+ QueueQueryResult result = fix.session.queueQuery("q");
BOOST_CHECK_EQUAL(false, result.getDurable());
BOOST_CHECK_EQUAL(true, result.getExclusive());
- BOOST_CHECK_EQUAL(string("amq.fanout"),
- result.getAlternateExchange());
-}
-
-QPID_AUTO_TEST_CASE(testTransfer)
-{
- ClientSessionFixture fix;
- fix.session=fix.connection.newSession();
- fix.declareSubscribe();
- fix.session.messageTransfer(arg::acceptMode=1, arg::content=TransferContent("my-message", "my-queue"));
- //get & test the message:
- FrameSet::shared_ptr msg = fix.session.get();
- BOOST_CHECK(msg->isA<MessageTransferBody>());
- BOOST_CHECK_EQUAL(string("my-message"), msg->getContent());
- //confirm receipt:
- AckPolicy autoAck;
- autoAck.ack(Message(*msg), fix.session);
+ BOOST_CHECK_EQUAL("amq.fanout", result.getAlternateExchange());
}
QPID_AUTO_TEST_CASE(testDispatcher)
{
ClientSessionFixture fix;
fix.session =fix.connection.newSession();
- fix.declareSubscribe();
size_t count = 100;
- for (size_t i = 0; i < count; ++i)
- fix.session.messageTransfer(arg::content=TransferContent(boost::lexical_cast<string>(i), "my-queue"));
- DummyListener listener(fix.session, "my-dest", count);
+ for (size_t i = 0; i < count; ++i)
+ fix.session.messageTransfer(arg::content=Message(boost::lexical_cast<string>(i), "my-queue"));
+ DummyListener listener(fix.session, "my-queue", count);
listener.run();
- BOOST_CHECK_EQUAL(count, listener.messages.size());
- for (size_t i = 0; i < count; ++i)
+ BOOST_CHECK_EQUAL(count, listener.messages.size());
+ for (size_t i = 0; i < count; ++i)
BOOST_CHECK_EQUAL(boost::lexical_cast<string>(i), listener.messages[i].getData());
}
@@ -149,54 +138,49 @@ QPID_AUTO_TEST_CASE(testDispatcherThread)
{
ClientSessionFixture fix;
fix.session =fix.connection.newSession();
- fix.declareSubscribe();
size_t count = 10;
- DummyListener listener(fix.session, "my-dest", count);
+ DummyListener listener(fix.session, "my-queue", count);
sys::Thread t(listener);
for (size_t i = 0; i < count; ++i) {
- fix.session.messageTransfer(arg::content=TransferContent(boost::lexical_cast<string>(i), "my-queue"));
+ fix.session.messageTransfer(arg::content=Message(boost::lexical_cast<string>(i), "my-queue"));
}
t.join();
- BOOST_CHECK_EQUAL(count, listener.messages.size());
- for (size_t i = 0; i < count; ++i)
+ BOOST_CHECK_EQUAL(count, listener.messages.size());
+ for (size_t i = 0; i < count; ++i)
BOOST_CHECK_EQUAL(boost::lexical_cast<string>(i), listener.messages[i].getData());
}
-// FIXME aconway 2008-05-26: Re-enable with final resume implementation.
-//
-// QPID_AUTO_TEST_CASE_EXPECTED_FAILURES(testSuspend0Timeout, 1)
-// {
-// ClientSessionFixture fix;
-// fix.session.suspend(); // session has 0 timeout.
-// try {
-// fix.connection.resume(fix.session);
-// BOOST_FAIL("Expected InvalidArgumentException.");
-// } catch(const InternalErrorException&) {}
-// }
-
-// QPID_AUTO_TEST_CASE_EXPECTED_FAILURES(testUseSuspendedError, 1)
-// {
-// ClientSessionFixture fix;
-// fix.session =fix.session.timeout(60);
-// fix.session.suspend();
-// try {
-// fix.session.exchangeQuery(name="amq.fanout");
-// BOOST_FAIL("Expected session suspended exception");
-// } catch(const CommandInvalidException&) {}
-// }
-
-// QPID_AUTO_TEST_CASE_EXPECTED_FAILURES(testSuspendResume, 1)
-// {
-// ClientSessionFixture fix;
-// fix.session.timeout(60);
-// fix.declareSubscribe();
-// fix.session.suspend();
-// // Make sure we are still subscribed after resume.
-// fix.connection.resume(fix.session);
-// fix.session.messageTransfer(content=TransferContent("my-message", "my-queue"));
-// FrameSet::shared_ptr msg = fix.session.get();
-// BOOST_CHECK_EQUAL(string("my-message"), msg->getContent());
-// }
+// FIXME aconway 2009-06-17: test for unimplemented feature, enable when implemented.
+void testSuspend0Timeout() {
+ ClientSessionFixture fix;
+ fix.session.suspend(); // session has 0 timeout.
+ try {
+ fix.connection.resume(fix.session);
+ BOOST_FAIL("Expected InvalidArgumentException.");
+ } catch(const InternalErrorException&) {}
+}
+
+QPID_AUTO_TEST_CASE(testUseSuspendedError)
+{
+ ClientSessionFixture fix;
+ fix.session.timeout(60);
+ fix.session.suspend();
+ try {
+ fix.session.exchangeQuery(arg::exchange="amq.fanout");
+ BOOST_FAIL("Expected session suspended exception");
+ } catch(const NotAttachedException&) {}
+}
+
+// FIXME aconway 2009-06-17: test for unimplemented feature, enable when implemented.
+void testSuspendResume() {
+ ClientSessionFixture fix;
+ fix.session.timeout(60);
+ fix.session.suspend();
+ // Make sure we are still subscribed after resume.
+ fix.connection.resume(fix.session);
+ fix.session.messageTransfer(arg::content=Message("my-message", "my-queue"));
+ BOOST_CHECK_EQUAL("my-message", fix.subs.get("my-queue", TIME_SEC).getData());
+}
QPID_AUTO_TEST_CASE(testSendToSelf) {
@@ -233,8 +217,8 @@ QPID_AUTO_TEST_CASE(testLocalQueue) {
BOOST_CHECK_EQUAL("foo0", lq.pop().getData());
BOOST_CHECK_EQUAL("foo1", lq.pop().getData());
BOOST_CHECK(lq.empty()); // Credit exhausted.
- fix.subs.setFlowControl("lq", FlowControl::unlimited());
- BOOST_CHECK_EQUAL("foo2", lq.pop().getData());
+ fix.subs.getSubscription("lq").setFlowControl(FlowControl::unlimited());
+ BOOST_CHECK_EQUAL("foo2", lq.pop().getData());
}
struct DelayedTransfer : sys::Runnable
@@ -245,7 +229,7 @@ struct DelayedTransfer : sys::Runnable
void run()
{
- sleep(1);
+ qpid::sys::sleep(1);
fixture.session.messageTransfer(arg::content=Message("foo2", "getq"));
}
};
@@ -265,7 +249,7 @@ QPID_AUTO_TEST_CASE(testGet) {
Thread t(sender);
//test timed get where message shows up after a short delay
BOOST_CHECK(fix.subs.get(got, "getq", 5*TIME_SEC));
- BOOST_CHECK_EQUAL("foo2", got.getData());
+ BOOST_CHECK_EQUAL("foo2", got.getData());
t.join();
}
@@ -284,6 +268,345 @@ QPID_AUTO_TEST_CASE(testOpenFailure) {
BOOST_CHECK(!c.isOpen());
}
-QPID_AUTO_TEST_SUITE_END()
+QPID_AUTO_TEST_CASE(testPeriodicExpiration) {
+ Broker::Options opts;
+ opts.queueCleanInterval = 1;
+ ClientSessionFixture fix(opts);
+ fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true);
+
+ for (uint i = 0; i < 10; i++) {
+ Message m((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ if (i % 2) m.getDeliveryProperties().setTtl(500);
+ fix.session.messageTransfer(arg::content=m);
+ }
+
+ BOOST_CHECK_EQUAL(fix.session.queueQuery(string("my-queue")).getMessageCount(), 10u);
+ qpid::sys::sleep(2);
+ BOOST_CHECK_EQUAL(fix.session.queueQuery(string("my-queue")).getMessageCount(), 5u);
+}
+
+QPID_AUTO_TEST_CASE(testExpirationOnPop) {
+ ClientSessionFixture fix;
+ fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true);
+
+ for (uint i = 0; i < 10; i++) {
+ Message m((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ if (i % 2) m.getDeliveryProperties().setTtl(200);
+ fix.session.messageTransfer(arg::content=m);
+ }
+
+ qpid::sys::usleep(300* 1000);
+
+ for (uint i = 0; i < 10; i++) {
+ if (i % 2) continue;
+ Message m;
+ BOOST_CHECK(fix.subs.get(m, "my-queue", TIME_SEC));
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), m.getData());
+ }
+}
+
+QPID_AUTO_TEST_CASE(testRelease) {
+ ClientSessionFixture fix;
+
+ const uint count=10;
+ for (uint i = 0; i < count; i++) {
+ Message m((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ fix.session.messageTransfer(arg::content=m);
+ }
+
+ fix.subs.setAutoStop(false);
+ fix.subs.start();
+ SubscriptionSettings settings;
+ settings.autoAck = 0;
+
+ SimpleListener l1;
+ Subscription s1 = fix.subs.subscribe(l1, "my-queue", settings);
+ l1.waitFor(count);
+ s1.cancel();
+
+ for (uint i = 0; i < count; i++) {
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), l1.messages[i].getData());
+ }
+ s1.release(s1.getUnaccepted());
+
+ //check that released messages are redelivered
+ settings.autoAck = 1;
+ SimpleListener l2;
+ Subscription s2 = fix.subs.subscribe(l2, "my-queue", settings);
+ l2.waitFor(count);
+ for (uint i = 0; i < count; i++) {
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), l2.messages[i].getData());
+ }
+
+ fix.subs.stop();
+ fix.subs.wait();
+ fix.session.close();
+}
+
+QPID_AUTO_TEST_CASE(testCompleteOnAccept) {
+ ClientSessionFixture fix;
+ const uint count = 8;
+ const uint chunk = 4;
+ for (uint i = 0; i < count; i++) {
+ Message m((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ fix.session.messageTransfer(arg::content=m);
+ }
+
+ SubscriptionSettings settings;
+ settings.autoAck = 0;
+ settings.completionMode = COMPLETE_ON_ACCEPT;
+ settings.flowControl = FlowControl::messageWindow(chunk);
+
+ LocalQueue q;
+ Subscription s = fix.subs.subscribe(q, "my-queue", settings);
+ fix.session.messageFlush(arg::destination=s.getName());
+ SequenceSet accepted;
+ for (uint i = 0; i < chunk; i++) {
+ Message m;
+ BOOST_CHECK(q.get(m));
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), m.getData());
+ accepted.add(m.getId());
+ }
+ Message m;
+ BOOST_CHECK(!q.get(m));
+
+ s.accept(accepted);
+ fix.session.messageFlush(arg::destination=s.getName());
+ accepted.clear();
+
+ for (uint i = chunk; i < count; i++) {
+ Message m;
+ BOOST_CHECK(q.get(m));
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), m.getData());
+ accepted.add(m.getId());
+ }
+ fix.session.messageAccept(accepted);
+}
+
+namespace
+{
+struct Publisher : qpid::sys::Runnable
+{
+ AsyncSession session;
+ Message message;
+ uint count;
+ Thread thread;
+
+ Publisher(Connection& con, Message m, uint c) : session(con.newSession()), message(m), count(c) {}
+
+ void start()
+ {
+ thread = Thread(*this);
+ }
+
+ void join()
+ {
+ thread.join();
+ }
+
+ void run()
+ {
+ for (uint i = 0; i < count; i++) {
+ session.messageTransfer(arg::content=message);
+ }
+ session.sync();
+ session.close();
+ }
+};
+}
+
+QPID_AUTO_TEST_CASE(testConcurrentSenders)
+{
+ //Ensure concurrent publishing sessions on a connection don't
+ //cause assertions, deadlocks or other undesirables:
+ BrokerFixture fix;
+ Connection connection;
+ ConnectionSettings settings;
+ settings.maxFrameSize = 1024;
+ settings.port = fix.broker->getPort(qpid::broker::Broker::TCP_TRANSPORT);
+ connection.open(settings);
+ AsyncSession session = connection.newSession();
+ Message message(string(512, 'X'));
+
+ boost::ptr_vector<Publisher> publishers;
+ for (size_t i = 0; i < 5; i++) {
+ publishers.push_back(new Publisher(connection, message, 100));
+ }
+ std::for_each(publishers.begin(), publishers.end(), boost::bind(&Publisher::start, _1));
+ std::for_each(publishers.begin(), publishers.end(), boost::bind(&Publisher::join, _1));
+ connection.close();
+}
+
+
+QPID_AUTO_TEST_CASE(testExclusiveSubscribe)
+{
+ ClientSessionFixture fix;
+ fix.session.queueDeclare(arg::queue="myq", arg::exclusive=true, arg::autoDelete=true);
+ SubscriptionSettings settings;
+ settings.exclusive = true;
+ LocalQueue q;
+ fix.subs.subscribe(q, "myq", settings, "first");
+ //attempt to create new subscriber should fail
+ ScopedSuppressLogging sl;
+ BOOST_CHECK_THROW(fix.subs.subscribe(q, "myq", "second"), ResourceLockedException);
+ ;
+
+}
+
+QPID_AUTO_TEST_CASE(testExclusiveBinding) {
+ FieldTable options;
+ options.setString("qpid.exclusive-binding", "anything");
+ ClientSessionFixture fix;
+ fix.session.queueDeclare(arg::queue="queue-1", arg::exclusive=true, arg::autoDelete=true);
+ fix.session.queueDeclare(arg::queue="queue-2", arg::exclusive=true, arg::autoDelete=true);
+ fix.session.exchangeBind(arg::exchange="amq.direct", arg::queue="queue-1", arg::bindingKey="my-key", arg::arguments=options);
+ fix.session.messageTransfer(arg::destination="amq.direct", arg::content=Message("message1", "my-key"));
+ fix.session.exchangeBind(arg::exchange="amq.direct", arg::queue="queue-2", arg::bindingKey="my-key", arg::arguments=options);
+ fix.session.messageTransfer(arg::destination="amq.direct", arg::content=Message("message2", "my-key"));
+
+ Message got;
+ BOOST_CHECK(fix.subs.get(got, "queue-1"));
+ BOOST_CHECK_EQUAL("message1", got.getData());
+ BOOST_CHECK(!fix.subs.get(got, "queue-1"));
+
+ BOOST_CHECK(fix.subs.get(got, "queue-2"));
+ BOOST_CHECK_EQUAL("message2", got.getData());
+ BOOST_CHECK(!fix.subs.get(got, "queue-2"));
+}
+
+QPID_AUTO_TEST_CASE(testResubscribeWithLocalQueue) {
+ ClientSessionFixture fix;
+ fix.session.queueDeclare(arg::queue="some-queue", arg::exclusive=true, arg::autoDelete=true);
+ LocalQueue p, q;
+ fix.subs.subscribe(p, "some-queue");
+ fix.subs.cancel("some-queue");
+ fix.subs.subscribe(q, "some-queue");
+
+ fix.session.messageTransfer(arg::content=Message("some-data", "some-queue"));
+ fix.session.messageFlush(arg::destination="some-queue");
+
+ Message got;
+ BOOST_CHECK(!p.get(got));
+
+ BOOST_CHECK(q.get(got));
+ BOOST_CHECK_EQUAL("some-data", got.getData());
+ BOOST_CHECK(!q.get(got));
+}
+
+QPID_AUTO_TEST_CASE(testReliableDispatch) {
+ ClientSessionFixture fix;
+ std::string queue("a-queue");
+ fix.session.queueDeclare(arg::queue=queue, arg::autoDelete=true);
+
+ ConnectionSettings settings;
+ settings.port = fix.broker->getPort(qpid::broker::Broker::TCP_TRANSPORT);
+
+ Connection c1;
+ c1.open(settings);
+ Session s1 = c1.newSession();
+ SubscriptionManager subs1(s1);
+ LocalQueue q1;
+ subs1.subscribe(q1, queue, FlowControl());//first subscriber has no credit
+
+ Connection c2;
+ c2.open(settings);
+ Session s2 = c2.newSession();
+ SubscriptionManager subs2(s2);
+ LocalQueue q2;
+ subs2.subscribe(q2, queue);//second subscriber has credit
+ fix.session.messageTransfer(arg::content=Message("my-message", queue));
+
+ //check that the second consumer gets the message
+ Message got;
+ BOOST_CHECK(q2.get(got, 1*TIME_SEC));
+ BOOST_CHECK_EQUAL("my-message", got.getData());
+
+ c1.close();
+ c2.close();
+}
+
+QPID_AUTO_TEST_CASE(testSessionCloseOnInvalidSession) {
+ Session session;
+ session.close();
+}
+
+QPID_AUTO_TEST_CASE(testLVQVariedSize) {
+ ClientSessionFixture fix;
+ std::string queue("my-lvq");
+ QueueOptions args;
+ args.setOrdering(LVQ_NO_BROWSE);
+ fix.session.queueDeclare(arg::queue=queue, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args);
+
+ std::string key;
+ args.getLVQKey(key);
+
+ for (size_t i = 0; i < 10; i++) {
+ std::ostringstream data;
+ size_t size = 100 - ((i % 10) * 10);
+ data << std::string(size, 'x');
+
+ Message m(data.str(), queue);
+ m.getHeaders().setString(key, "abc");
+ fix.session.messageTransfer(arg::content=m);
+ }
+}
+
+QPID_AUTO_TEST_CASE(testSessionManagerSetFlowControl) {
+ ClientSessionFixture fix;
+ std::string name("dummy");
+ LocalQueue queue;
+ SubscriptionSettings settings;
+ settings.flowControl = FlowControl();
+ fix.session.queueDeclare(arg::queue=name, arg::exclusive=true, arg::autoDelete=true);
+ fix.subs.subscribe(queue, name, settings);
+ fix.session.messageTransfer(arg::content=Message("my-message", name));
+ fix.subs.setFlowControl(name, 1, FlowControl::UNLIMITED, false);
+ fix.session.messageFlush(name);
+ Message got;
+ BOOST_CHECK(queue.get(got, 0));
+ BOOST_CHECK_EQUAL("my-message", got.getData());
+}
+
+QPID_AUTO_TEST_CASE(testGetThenSubscribe) {
+ ClientSessionFixture fix;
+ std::string name("myqueue");
+ fix.session.queueDeclare(arg::queue=name, arg::exclusive=true, arg::autoDelete=true);
+ fix.session.messageTransfer(arg::content=Message("one", name));
+ fix.session.messageTransfer(arg::content=Message("two", name));
+ Message got;
+ BOOST_CHECK(fix.subs.get(got, name));
+ BOOST_CHECK_EQUAL("one", got.getData());
+
+ DummyListener listener(fix.session, name, 1);
+ listener.run();
+ BOOST_CHECK_EQUAL(1u, listener.messages.size());
+ if (!listener.messages.empty()) {
+ BOOST_CHECK_EQUAL("two", listener.messages[0].getData());
+ }
+}
+
+QPID_AUTO_TEST_CASE(testSessionIsValid) {
+ ClientSessionFixture fix;
+ BOOST_CHECK(fix.session.isValid());
+ Session session;
+ BOOST_CHECK(!session.isValid());
+}
+
+QPID_AUTO_TEST_CASE(testExpirationNotAltered) {
+ ClientSessionFixture fix;
+ fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true);
+
+ Message m("my-message", "my-queue");
+ m.getDeliveryProperties().setTtl(60000);
+ m.getDeliveryProperties().setExpiration(12345);
+ fix.session.messageTransfer(arg::content=m);
+ Message got;
+ BOOST_CHECK(fix.subs.get(got, "my-queue"));
+ BOOST_CHECK_EQUAL("my-message", got.getData());
+ BOOST_CHECK_EQUAL(12345u, got.getDeliveryProperties().getExpiration());
+}
+
+QPID_AUTO_TEST_SUITE_END()
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/ClusterFailover.cpp b/cpp/src/tests/ClusterFailover.cpp
new file mode 100644
index 0000000000..6b1ef99807
--- /dev/null
+++ b/cpp/src/tests/ClusterFailover.cpp
@@ -0,0 +1,68 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/**@file Tests for partial failure in a cluster.
+ * Partial failure means some nodes experience a failure while others do not.
+ * In this case the failed nodes must shut down.
+ */
+
+#include "test_tools.h"
+#include "unit_test.h"
+#include "ClusterFixture.h"
+#include "qpid/client/FailoverManager.h"
+#include <boost/assign.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(ClusterFailoverTestSuite)
+
+using namespace std;
+using namespace qpid;
+using namespace qpid::cluster;
+using namespace qpid::framing;
+using namespace qpid::client;
+using namespace qpid::client::arg;
+using namespace boost::assign;
+using broker::Broker;
+using boost::shared_ptr;
+
+// Timeout for tests that wait for messages
+const sys::Duration TIMEOUT=sys::TIME_SEC/4;
+
+
+// Test re-connecting with same session name after a failure.
+QPID_AUTO_TEST_CASE(testReconnectSameSessionName) {
+ ostringstream clusterLib;
+ clusterLib << getLibPath("CLUSTER_LIB");
+ ClusterFixture::Args args = list_of<string>("--auth")("no")("--no-module-dir")("--no-data-dir")("--load-module")(clusterLib.str());
+ ClusterFixture cluster(2, args, -1);
+ Client c0(cluster[0], "foo");
+ BOOST_CHECK_EQUAL(2u, knownBrokerPorts(c0.connection, 2).size()); // wait for both.
+ cluster.killWithSilencer(0, c0.connection, 9);
+ Client c1(cluster[1], "foo"); // Using same name, should be cleaned up.
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/ClusterFixture.cpp b/cpp/src/tests/ClusterFixture.cpp
new file mode 100644
index 0000000000..fd90ed170e
--- /dev/null
+++ b/cpp/src/tests/ClusterFixture.cpp
@@ -0,0 +1,160 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test_tools.h"
+#include "unit_test.h"
+#include "ForkedBroker.h"
+#include "BrokerFixture.h"
+
+#include "qpid/client/Connection.h"
+#include "qpid/client/ConnectionAccess.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/FailoverListener.h"
+#include "qpid/cluster/Cluster.h"
+#include "qpid/cluster/Cpg.h"
+#include "qpid/cluster/UpdateClient.h"
+#include "qpid/framing/AMQBody.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/enum.h"
+#include "qpid/log/Logger.h"
+
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/assign.hpp>
+
+#include <string>
+#include <iostream>
+#include <iterator>
+#include <vector>
+#include <set>
+#include <algorithm>
+#include <iterator>
+
+
+using namespace std;
+using namespace qpid;
+using namespace qpid::cluster;
+using namespace qpid::framing;
+using namespace qpid::client;
+using qpid::sys::TIME_SEC;
+using qpid::broker::Broker;
+using boost::shared_ptr;
+using qpid::cluster::Cluster;
+using boost::assign::list_of;
+
+
+#include "ClusterFixture.h"
+
+namespace qpid {
+namespace tests {
+
+ClusterFixture::ClusterFixture(size_t n, const Args& args_, int localIndex_)
+ : name(Uuid(true).str()), localIndex(localIndex_), userArgs(args_)
+{
+ add(n);
+}
+
+ClusterFixture::ClusterFixture(size_t n, boost::function<void (Args&, size_t)> updateArgs_, int localIndex_)
+ : name(Uuid(true).str()), localIndex(localIndex_), updateArgs(updateArgs_)
+{
+ add(n);
+}
+
+ClusterFixture::Args ClusterFixture::makeArgs(const std::string& prefix, size_t index) {
+ Args args = list_of<string>("qpidd ")
+ ("--cluster-name")(name)
+ ("--log-prefix")(prefix);
+ args.insert(args.end(), userArgs.begin(), userArgs.end());
+ if (updateArgs) updateArgs(args, index);
+ return args;
+}
+
+void ClusterFixture::add() {
+ if (size() != size_t(localIndex)) { // fork a broker process.
+ std::ostringstream os; os << "fork" << size();
+ std::string prefix = os.str();
+ forkedBrokers.push_back(shared_ptr<ForkedBroker>(new ForkedBroker(makeArgs(prefix, size()))));
+ push_back(forkedBrokers.back()->getPort());
+ }
+ else { // Run in this process
+ addLocal();
+ }
+}
+
+namespace {
+/** Parse broker & cluster options */
+Broker::Options parseOpts(size_t argc, const char* argv[]) {
+ Broker::Options opts;
+ Plugin::addOptions(opts); // Pick up cluster options.
+ opts.parse(argc, argv, "", true); // Allow-unknown for --load-module
+ return opts;
+}
+}
+
+void ClusterFixture::addLocal() {
+ assert(int(size()) == localIndex);
+ ostringstream os; os << "local" << localIndex;
+ string prefix = os.str();
+ Args args(makeArgs(prefix, localIndex));
+ vector<const char*> argv(args.size());
+ transform(args.begin(), args.end(), argv.begin(), boost::bind(&string::c_str, _1));
+ qpid::log::Logger::instance().setPrefix(prefix);
+ localBroker.reset(new BrokerFixture(parseOpts(argv.size(), &argv[0])));
+ push_back(localBroker->getPort());
+ forkedBrokers.push_back(shared_ptr<ForkedBroker>());
+}
+
+bool ClusterFixture::hasLocal() const { return localIndex >= 0 && size_t(localIndex) < size(); }
+
+/** Kill a forked broker with sig, or shutdown localBroker if n==0. */
+void ClusterFixture::kill(size_t n, int sig) {
+ if (n == size_t(localIndex))
+ localBroker->broker->shutdown();
+ else
+ forkedBrokers[n]->kill(sig);
+}
+
+/** Kill a broker and suppressing errors from closing connection c. */
+void ClusterFixture::killWithSilencer(size_t n, client::Connection& c, int sig) {
+ ScopedSuppressLogging sl;
+ kill(n,sig);
+ try { c.close(); } catch(...) {}
+}
+
+/**
+ * Get the known broker ports from a Connection.
+ *@param n if specified wait for the cluster size to be n, up to a timeout.
+ */
+std::set<int> knownBrokerPorts(qpid::client::Connection& c, int n) {
+ FailoverListener fl(c);
+ std::vector<qpid::Url> urls = fl.getKnownBrokers();
+ if (n >= 0 && unsigned(n) != urls.size()) {
+ // Retry up to 10 secs in .1 second intervals.
+ for (size_t retry=100; urls.size() != unsigned(n) && retry != 0; --retry) {
+ qpid::sys::usleep(1000*100); // 0.1 secs
+ urls = fl.getKnownBrokers();
+ }
+ }
+ std::set<int> s;
+ for (std::vector<qpid::Url>::const_iterator i = urls.begin(); i != urls.end(); ++i)
+ s.insert((*i)[0].get<qpid::TcpAddress>()->port);
+ return s;
+}
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/ClusterFixture.h b/cpp/src/tests/ClusterFixture.h
new file mode 100644
index 0000000000..1eee32b9a4
--- /dev/null
+++ b/cpp/src/tests/ClusterFixture.h
@@ -0,0 +1,115 @@
+#ifndef CLUSTER_FIXTURE_H
+#define CLUSTER_FIXTURE_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test_tools.h"
+#include "unit_test.h"
+#include "ForkedBroker.h"
+#include "BrokerFixture.h"
+
+#include "qpid/client/Connection.h"
+#include "qpid/client/ConnectionAccess.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/FailoverListener.h"
+#include "qpid/cluster/Cluster.h"
+#include "qpid/cluster/Cpg.h"
+#include "qpid/cluster/UpdateClient.h"
+#include "qpid/framing/AMQBody.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/enum.h"
+#include "qpid/log/Logger.h"
+
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <string>
+#include <iostream>
+#include <iterator>
+#include <vector>
+#include <set>
+#include <algorithm>
+#include <iterator>
+
+
+using namespace std;
+using namespace qpid;
+using namespace qpid::cluster;
+using namespace qpid::framing;
+using namespace qpid::client;
+using qpid::sys::TIME_SEC;
+using qpid::broker::Broker;
+using boost::shared_ptr;
+using qpid::cluster::Cluster;
+
+namespace qpid {
+namespace tests {
+
+/** Cluster fixture is a vector of ports for the replicas.
+ *
+ * At most one replica (by default replica 0) is in the current
+ * process, all others are forked as children.
+ */
+class ClusterFixture : public vector<uint16_t> {
+ public:
+ typedef std::vector<std::string> Args;
+
+ /** @param localIndex can be -1 meaning don't automatically start a local broker.
+ * A local broker can be started with addLocal().
+ */
+ ClusterFixture(size_t n, const Args& args, int localIndex=-1);
+
+ /**@param updateArgs function is passed the index of the cluster member and can update the arguments. */
+ ClusterFixture(size_t n, boost::function<void (Args&, size_t)> updateArgs, int localIndex=-1);
+
+ void add(size_t n) { for (size_t i=0; i < n; ++i) add(); }
+ void add(); // Add a broker.
+ void setup();
+
+ bool hasLocal() const;
+
+ /** Kill a forked broker with sig, or shutdown localBroker. */
+ void kill(size_t n, int sig=SIGINT);
+
+ /** Kill a broker and suppressing errors from closing connection c. */
+ void killWithSilencer(size_t n, client::Connection& c, int sig=SIGINT);
+
+ private:
+
+ void addLocal(); // Add a local broker.
+ Args makeArgs(const std::string& prefix, size_t index);
+ string name;
+ std::auto_ptr<BrokerFixture> localBroker;
+ int localIndex;
+ std::vector<shared_ptr<ForkedBroker> > forkedBrokers;
+ Args userArgs;
+ boost::function<void (Args&, size_t)> updateArgs;
+};
+
+/**
+ * Get the known broker ports from a Connection.
+ *@param n if specified wait for the cluster size to be n, up to a timeout.
+ */
+std::set<int> knownBrokerPorts(qpid::client::Connection& source, int n=-1);
+
+}} // namespace qpid::tests
+
+#endif /*!CLUSTER_FIXTURE_H*/
diff --git a/cpp/src/tests/ConnectionOptions.h b/cpp/src/tests/ConnectionOptions.h
index 1579ac0b57..6fd6c2c63f 100644
--- a/cpp/src/tests/ConnectionOptions.h
+++ b/cpp/src/tests/ConnectionOptions.h
@@ -10,9 +10,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -25,6 +25,8 @@
#include "qpid/client/ConnectionSettings.h"
#include "qpid/Options.h"
+namespace qpid {
+
/**
* Options parser for ConnectionOptions.
*/
@@ -35,19 +37,26 @@ struct ConnectionOptions : public qpid::Options,
{
using namespace qpid;
addOptions()
- ("broker,b", optValue(host, "HOST"), "Broker host to connect to")
+ ("broker,b", optValue(host, "HOST"), "Broker host to connect to")
("port,p", optValue(port, "PORT"), "Broker port to connect to")
+ ("protocol,P", optValue(protocol, "tcp|rdma"), "Protocol to use for broker connection")
("virtualhost,v", optValue(virtualhost, "VHOST"), "virtual host")
("username", optValue(username, "USER"), "user name for broker log in.")
("password", optValue(password, "PASSWORD"), "password for broker log in.")
("mechanism", optValue(mechanism, "MECH"), "SASL mechanism to use when authenticating.")
("locale", optValue(locale, "LOCALE"), "locale to use.")
("max-channels", optValue(maxChannels, "N"), "the maximum number of channels the client requires.")
+ ("heartbeat", optValue(heartbeat, "N"), "Desired heartbeat interval in seconds.")
("max-frame-size", optValue(maxFrameSize, "N"), "the maximum frame size to request.")
- ("bounds-multiplier", optValue(bounds, "N"),
+ ("bounds-multiplier", optValue(bounds, "N"),
"bound size of write queue (as a multiple of the max frame size).")
- ("tcp-nodelay", optValue(tcpNoDelay), "Turn on tcp-nodelay");
+ ("tcp-nodelay", optValue(tcpNoDelay), "Turn on tcp-nodelay")
+ ("service", optValue(service, "SERVICE-NAME"), "SASL service name.")
+ ("min-ssf", optValue(minSsf, "N"), "Minimum acceptable strength for SASL security layer")
+ ("max-ssf", optValue(maxSsf, "N"), "Maximum acceptable strength for SASL security layer");
}
};
+} // namespace qpid
+
#endif /*!QPID_CLIENT_CONNECTIONOPTIONS_H*/
diff --git a/cpp/src/tests/ConsoleTest.cpp b/cpp/src/tests/ConsoleTest.cpp
new file mode 100644
index 0000000000..107472ed9e
--- /dev/null
+++ b/cpp/src/tests/ConsoleTest.cpp
@@ -0,0 +1,46 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/console/Package.h"
+#include "qpid/console/ClassKey.h"
+#include "unit_test.h"
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(ConsoleTestSuite)
+
+using namespace qpid::framing;
+using namespace qpid::console;
+
+QPID_AUTO_TEST_CASE(testClassKey) {
+ uint8_t hash[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+ ClassKey k("com.redhat.test", "class", hash);
+
+ BOOST_CHECK_EQUAL(k.getPackageName(), "com.redhat.test");
+ BOOST_CHECK_EQUAL(k.getClassName(), "class");
+ BOOST_CHECK_EQUAL(k.getHashString(), "00010203-04050607-08090a0b-0c0d0e0f");
+ BOOST_CHECK_EQUAL(k.str(), "com.redhat.test:class(00010203-04050607-08090a0b-0c0d0e0f)");
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/DeliveryRecordTest.cpp b/cpp/src/tests/DeliveryRecordTest.cpp
index 43161b4065..17f9a0d148 100644
--- a/cpp/src/tests/DeliveryRecordTest.cpp
+++ b/cpp/src/tests/DeliveryRecordTest.cpp
@@ -8,9 +8,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -31,6 +31,9 @@ using namespace qpid::framing;
using boost::dynamic_pointer_cast;
using std::list;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(DeliveryRecordTestSuite)
QPID_AUTO_TEST_CASE(testSort)
@@ -45,16 +48,19 @@ QPID_AUTO_TEST_CASE(testSort)
list<DeliveryRecord> records;
for (list<SequenceNumber>::iterator i = ids.begin(); i != ids.end(); i++) {
- records.push_back(DeliveryRecord(QueuedMessage(0), Queue::shared_ptr(), "tag", DeliveryToken::shared_ptr(), *i, false, false));
+ DeliveryRecord r(QueuedMessage(0), Queue::shared_ptr(), "tag", false, false, false);
+ r.setId(*i);
+ records.push_back(r);
}
records.sort();
SequenceNumber expected(0);
for (list<DeliveryRecord>::iterator i = records.begin(); i != records.end(); i++) {
- BOOST_CHECK(i->matches(++expected));
+ BOOST_CHECK(i->getId() == ++expected);
}
}
QPID_AUTO_TEST_SUITE_END()
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/DispatcherTest.cpp b/cpp/src/tests/DispatcherTest.cpp
index 7631956acc..17b3b4e3e6 100644
--- a/cpp/src/tests/DispatcherTest.cpp
+++ b/cpp/src/tests/DispatcherTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -20,7 +20,10 @@
*/
#include "qpid/sys/Poller.h"
+#include "qpid/sys/IOHandle.h"
#include "qpid/sys/Dispatcher.h"
+#include "qpid/sys/DispatchHandle.h"
+#include "qpid/sys/posix/PrivatePosix.h"
#include "qpid/sys/Thread.h"
#include <sys/types.h>
@@ -28,6 +31,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
+#include <signal.h>
#include <iostream>
#include <boost/bind.hpp>
@@ -35,6 +39,9 @@
using namespace std;
using namespace qpid::sys;
+namespace qpid {
+namespace tests {
+
int writeALot(int fd, const string& s) {
int bytesWritten = 0;
do {
@@ -42,7 +49,7 @@ int writeALot(int fd, const string& s) {
int lastWrite = ::write(fd, s.c_str(), s.size());
if ( lastWrite >= 0) {
bytesWritten += lastWrite;
- }
+ }
} while (errno != EAGAIN);
return bytesWritten;
}
@@ -50,13 +57,13 @@ int writeALot(int fd, const string& s) {
int readALot(int fd) {
int bytesRead = 0;
char buf[10240];
-
+
do {
errno = 0;
int lastRead = ::read(fd, buf, sizeof(buf));
if ( lastRead >= 0) {
bytesRead += lastRead;
- }
+ }
} while (errno != EAGAIN);
return bytesRead;
}
@@ -74,55 +81,169 @@ void reader(DispatchHandle& h, int fd) {
h.rewatch();
}
-int main(int argc, char** argv)
+void rInterrupt(DispatchHandle&) {
+ cerr << "R";
+}
+
+void wInterrupt(DispatchHandle&) {
+ cerr << "W";
+}
+
+DispatchHandle::Callback rcb = rInterrupt;
+DispatchHandle::Callback wcb = wInterrupt;
+
+DispatchHandleRef *volatile rh = 0;
+DispatchHandleRef *volatile wh = 0;
+
+volatile bool stopWait = false;
+volatile bool phase1finished = false;
+
+timer_t timer;
+
+void stop_handler(int /*signo*/, siginfo_t* /*info*/, void* /*context*/) {
+ stopWait = true;
+}
+
+void timer_handler(int /*signo*/, siginfo_t* /*info*/, void* /*context*/) {
+ static int count = 0;
+ if (count++ < 10) {
+ rh->call(rcb);
+ wh->call(wcb);
+ } else {
+ phase1finished = true;
+ assert(::timer_delete(timer) == 0);
+ }
+}
+
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
+int main(int /*argc*/, char** /*argv*/)
{
// Create poller
Poller::shared_ptr poller(new Poller);
-
+
// Create dispatcher thread
Dispatcher d(poller);
Dispatcher d1(poller);
- //Dispatcher d2(poller);
- //Dispatcher d3(poller);
+ Dispatcher d2(poller);
+ Dispatcher d3(poller);
Thread dt(d);
Thread dt1(d1);
- //Thread dt2(d2);
- //Thread dt3(d3);
+ Thread dt2(d2);
+ Thread dt3(d3);
// Setup sender and receiver
int sv[2];
- int rc = ::socketpair(AF_LOCAL, SOCK_STREAM, 0, sv);
+ int rc = ::socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
assert(rc >= 0);
-
+
// Set non-blocking
rc = ::fcntl(sv[0], F_SETFL, O_NONBLOCK);
assert(rc >= 0);
rc = ::fcntl(sv[1], F_SETFL, O_NONBLOCK);
assert(rc >= 0);
-
+
// Make up a large string
string testString = "This is only a test ... 1,2,3,4,5,6,7,8,9,10;";
for (int i = 0; i < 8; i++)
testString += testString;
- DispatchHandle rh(sv[0], boost::bind(reader, _1, sv[0]), 0);
- DispatchHandle wh(sv[1], 0, boost::bind(writer, _1, sv[1], testString));
+ PosixIOHandle f0(sv[0]);
+ PosixIOHandle f1(sv[1]);
+
+ rh = new DispatchHandleRef(f0, boost::bind(reader, _1, sv[0]), 0, 0);
+ wh = new DispatchHandleRef(f1, 0, boost::bind(writer, _1, sv[1], testString), 0);
+
+ rh->startWatch(poller);
+ wh->startWatch(poller);
+
+ // Set up a regular itimer interupt
+
+ // Ignore signal in this thread
+ ::sigset_t sm;
+ ::sigemptyset(&sm);
+ ::sigaddset(&sm, SIGRTMIN);
+ ::pthread_sigmask(SIG_BLOCK, &sm, 0);
+
+ // Signal handling
+ struct ::sigaction sa;
+ sa.sa_sigaction = timer_handler;
+ sa.sa_flags = SA_RESTART | SA_SIGINFO;
+ ::sigemptyset(&sa.sa_mask);
+ rc = ::sigaction(SIGRTMIN, &sa,0);
+ assert(rc == 0);
+
+ ::sigevent se;
+ ::memset(&se, 0, sizeof(se)); // Clear to make valgrind happy (this *is* the neatest way to do this portably - sigh)
+ se.sigev_notify = SIGEV_SIGNAL;
+ se.sigev_signo = SIGRTMIN;
+ rc = ::timer_create(CLOCK_REALTIME, &se, &timer);
+ assert(rc == 0);
+
+ itimerspec ts = {
+ /*.it_value = */ {2, 0}, // s, ns
+ /*.it_interval = */ {2, 0}}; // s, ns
+
+ rc = ::timer_settime(timer, 0, &ts, 0);
+ assert(rc == 0);
+
+ // wait
+ while (!phase1finished) {
+ ::sleep(1);
+ }
+
+ // Now test deleting/creating DispatchHandles in tight loop, so that we are likely to still be using the
+ // attached PollerHandles after deleting the DispatchHandle
+ DispatchHandleRef* t = wh;
+ wh = 0;
+ delete t;
+ t = rh;
+ rh = 0;
+ delete t;
+
+ sa.sa_sigaction = stop_handler;
+ rc = ::sigaction(SIGRTMIN, &sa,0);
+ assert(rc == 0);
+
+ itimerspec nts = {
+ /*.it_value = */ {30, 0}, // s, ns
+ /*.it_interval = */ {30, 0}}; // s, ns
+
+ rc = ::timer_create(CLOCK_REALTIME, &se, &timer);
+ assert(rc == 0);
+ rc = ::timer_settime(timer, 0, &nts, 0);
+ assert(rc == 0);
+
+ DispatchHandleRef* rh1;
+ DispatchHandleRef* wh1;
+
+ struct timespec w = {0, 1000000};
+ while (!stopWait) {
+ rh1 = new DispatchHandleRef(f0, boost::bind(reader, _1, sv[0]), 0, 0);
+ wh1 = new DispatchHandleRef(f1, 0, boost::bind(writer, _1, sv[1], testString), 0);
+ rh1->startWatch(poller);
+ wh1->startWatch(poller);
+
+ ::nanosleep(&w, 0);
+
+ delete wh1;
+ delete rh1;
+ }
+
+ rc = ::timer_delete(timer);
+ assert(rc == 0);
- rh.watch(poller);
- wh.watch(poller);
-
- // wait 2 minutes then shutdown
- sleep(60);
-
poller->shutdown();
dt.join();
dt1.join();
- //dt2.join();
- //dt3.join();
+ dt2.join();
+ dt3.join();
- cout << "Wrote: " << writtenBytes << "\n";
+ cout << "\nWrote: " << writtenBytes << "\n";
cout << "Read: " << readBytes << "\n";
-
+
return 0;
}
diff --git a/cpp/src/tests/DtxWorkRecordTest.cpp b/cpp/src/tests/DtxWorkRecordTest.cpp
index c7c1b460ff..9d7666dca4 100644
--- a/cpp/src/tests/DtxWorkRecordTest.cpp
+++ b/cpp/src/tests/DtxWorkRecordTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -27,6 +27,9 @@
using namespace qpid::broker;
using boost::static_pointer_cast;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(DtxWorkRecordTestSuite)
QPID_AUTO_TEST_CASE(testOnePhaseCommit){
@@ -44,7 +47,7 @@ QPID_AUTO_TEST_CASE(testOnePhaseCommit){
DtxBuffer::shared_ptr bufferB(new DtxBuffer());
bufferB->enlist(static_pointer_cast<TxOp>(opB));
bufferB->markEnded();
-
+
DtxWorkRecord work("my-xid", &store);
work.add(bufferA);
work.add(bufferB);
@@ -77,7 +80,7 @@ QPID_AUTO_TEST_CASE(testFailOnOnePhaseCommit){
DtxBuffer::shared_ptr bufferC(new DtxBuffer());
bufferC->enlist(static_pointer_cast<TxOp>(opC));
bufferC->markEnded();
-
+
DtxWorkRecord work("my-xid", &store);
work.add(bufferA);
work.add(bufferB);
@@ -108,7 +111,7 @@ QPID_AUTO_TEST_CASE(testTwoPhaseCommit){
DtxBuffer::shared_ptr bufferB(new DtxBuffer());
bufferB->enlist(static_pointer_cast<TxOp>(opB));
bufferB->markEnded();
-
+
DtxWorkRecord work("my-xid", &store);
work.add(bufferA);
work.add(bufferB);
@@ -142,7 +145,7 @@ QPID_AUTO_TEST_CASE(testFailOnTwoPhaseCommit){
DtxBuffer::shared_ptr bufferC(new DtxBuffer());
bufferC->enlist(static_pointer_cast<TxOp>(opC));
bufferC->markEnded();
-
+
DtxWorkRecord work("my-xid", &store);
work.add(bufferA);
work.add(bufferB);
@@ -171,7 +174,7 @@ QPID_AUTO_TEST_CASE(testRollback){
DtxBuffer::shared_ptr bufferB(new DtxBuffer());
bufferB->enlist(static_pointer_cast<TxOp>(opB));
bufferB->markEnded();
-
+
DtxWorkRecord work("my-xid", &store);
work.add(bufferA);
work.add(bufferB);
@@ -187,3 +190,4 @@ QPID_AUTO_TEST_CASE(testRollback){
QPID_AUTO_TEST_SUITE_END()
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/ExchangeTest.cpp b/cpp/src/tests/ExchangeTest.cpp
index e496f0c478..88a1cd99c2 100644
--- a/cpp/src/tests/ExchangeTest.cpp
+++ b/cpp/src/tests/ExchangeTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -39,9 +39,12 @@ using namespace qpid::framing;
using namespace qpid::sys;
using namespace qpid;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(ExchangeTestSuite)
-QPID_AUTO_TEST_CASE(testMe)
+QPID_AUTO_TEST_CASE(testMe)
{
Queue::shared_ptr queue(new Queue("queue", true));
Queue::shared_ptr queue2(new Queue("queue2", true));
@@ -57,7 +60,7 @@ QPID_AUTO_TEST_CASE(testMe)
queue.reset();
queue2.reset();
- intrusive_ptr<Message> msgPtr(MessageUtils::createMessage("exchange", "key", "id"));
+ intrusive_ptr<Message> msgPtr(MessageUtils::createMessage("exchange", "key", false, "id"));
DeliverableMessage msg(msgPtr);
topic.route(msg, "abc", 0);
direct.route(msg, "abc", 0);
@@ -70,15 +73,15 @@ QPID_AUTO_TEST_CASE(testIsBound)
Queue::shared_ptr b(new Queue("b", true));
Queue::shared_ptr c(new Queue("c", true));
Queue::shared_ptr d(new Queue("d", true));
-
+
string k1("abc");
string k2("def");
string k3("xyz");
FanOutExchange fanout("fanout");
- fanout.bind(a, "", 0);
- fanout.bind(b, "", 0);
- fanout.bind(c, "", 0);
+ BOOST_CHECK(fanout.bind(a, "", 0));
+ BOOST_CHECK(fanout.bind(b, "", 0));
+ BOOST_CHECK(fanout.bind(c, "", 0));
BOOST_CHECK(fanout.isBound(a, 0, 0));
BOOST_CHECK(fanout.isBound(b, 0, 0));
@@ -86,10 +89,10 @@ QPID_AUTO_TEST_CASE(testIsBound)
BOOST_CHECK(!fanout.isBound(d, 0, 0));
DirectExchange direct("direct");
- direct.bind(a, k1, 0);
- direct.bind(a, k3, 0);
- direct.bind(b, k2, 0);
- direct.bind(c, k1, 0);
+ BOOST_CHECK(direct.bind(a, k1, 0));
+ BOOST_CHECK(direct.bind(a, k3, 0));
+ BOOST_CHECK(direct.bind(b, k2, 0));
+ BOOST_CHECK(direct.bind(c, k1, 0));
BOOST_CHECK(direct.isBound(a, 0, 0));
BOOST_CHECK(direct.isBound(a, &k1, 0));
@@ -104,10 +107,10 @@ QPID_AUTO_TEST_CASE(testIsBound)
BOOST_CHECK(!direct.isBound(d, &k3, 0));
TopicExchange topic("topic");
- topic.bind(a, k1, 0);
- topic.bind(a, k3, 0);
- topic.bind(b, k2, 0);
- topic.bind(c, k1, 0);
+ BOOST_CHECK(topic.bind(a, k1, 0));
+ BOOST_CHECK(topic.bind(a, k3, 0));
+ BOOST_CHECK(topic.bind(b, k2, 0));
+ BOOST_CHECK(topic.bind(c, k1, 0));
BOOST_CHECK(topic.isBound(a, 0, 0));
BOOST_CHECK(topic.isBound(a, &k1, 0));
@@ -139,7 +142,7 @@ QPID_AUTO_TEST_CASE(testIsBound)
headers.bind(a, "", &args3);
headers.bind(b, "", &args2);
headers.bind(c, "", &args1);
-
+
BOOST_CHECK(headers.isBound(a, 0, 0));
BOOST_CHECK(headers.isBound(a, 0, &args1));
BOOST_CHECK(headers.isBound(a, 0, &args3));
@@ -153,7 +156,7 @@ QPID_AUTO_TEST_CASE(testIsBound)
BOOST_CHECK(!headers.isBound(d, 0, &args3));
}
-QPID_AUTO_TEST_CASE(testDeleteGetAndRedeclare)
+QPID_AUTO_TEST_CASE(testDeleteGetAndRedeclare)
{
ExchangeRegistry exchanges;
exchanges.declare("my-exchange", "direct", false, FieldTable());
@@ -162,7 +165,125 @@ QPID_AUTO_TEST_CASE(testDeleteGetAndRedeclare)
exchanges.get("my-exchange");
} catch (const NotFoundException&) {}
std::pair<Exchange::shared_ptr, bool> response = exchanges.declare("my-exchange", "direct", false, FieldTable());
- BOOST_CHECK_EQUAL(string("direct"), response.first->getType());
+ BOOST_CHECK_EQUAL(string("direct"), response.first->getType());
+}
+
+intrusive_ptr<Message> cmessage(std::string exchange, std::string routingKey) {
+ intrusive_ptr<Message> msg(new Message());
+ AMQFrame method((MessageTransferBody(ProtocolVersion(), exchange, 0, 0)));
+ AMQFrame header((AMQHeaderBody()));
+ msg->getFrames().append(method);
+ msg->getFrames().append(header);
+ msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(routingKey);
+ return msg;
+}
+
+QPID_AUTO_TEST_CASE(testSequenceOptions)
+{
+ FieldTable args;
+ args.setInt("qpid.msg_sequence",1);
+ char* buff = new char[10000];
+ framing::Buffer buffer(buff,10000);
+ {
+ DirectExchange direct("direct1", false, args);
+
+ intrusive_ptr<Message> msg1 = cmessage("e", "A");
+ intrusive_ptr<Message> msg2 = cmessage("e", "B");
+ intrusive_ptr<Message> msg3 = cmessage("e", "C");
+
+ DeliverableMessage dmsg1(msg1);
+ DeliverableMessage dmsg2(msg2);
+ DeliverableMessage dmsg3(msg3);
+
+ direct.route(dmsg1, "abc", 0);
+ direct.route(dmsg2, "abc", 0);
+ direct.route(dmsg3, "abc", 0);
+
+ BOOST_CHECK_EQUAL(1, msg1->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+ BOOST_CHECK_EQUAL(2, msg2->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+ BOOST_CHECK_EQUAL(3, msg3->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+
+ FanOutExchange fanout("fanout1", false, args);
+ HeadersExchange header("headers1", false, args);
+ TopicExchange topic ("topic1", false, args);
+
+ // check other exchanges, that they preroute
+ intrusive_ptr<Message> msg4 = cmessage("e", "A");
+ intrusive_ptr<Message> msg5 = cmessage("e", "B");
+ intrusive_ptr<Message> msg6 = cmessage("e", "C");
+
+ DeliverableMessage dmsg4(msg4);
+ DeliverableMessage dmsg5(msg5);
+ DeliverableMessage dmsg6(msg6);
+
+ fanout.route(dmsg4, "abc", 0);
+ BOOST_CHECK_EQUAL(1, msg4->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+
+ FieldTable headers;
+ header.route(dmsg5, "abc", &headers);
+ BOOST_CHECK_EQUAL(1, msg5->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+
+ topic.route(dmsg6, "abc", 0);
+ BOOST_CHECK_EQUAL(1, msg6->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+ direct.encode(buffer);
+ }
+ {
+
+ ExchangeRegistry exchanges;
+ buffer.reset();
+ DirectExchange::shared_ptr exch_dec = Exchange::decode(exchanges, buffer);
+
+ intrusive_ptr<Message> msg1 = cmessage("e", "A");
+ DeliverableMessage dmsg1(msg1);
+ exch_dec->route(dmsg1, "abc", 0);
+
+ BOOST_CHECK_EQUAL(4, msg1->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+
+ }
+ delete [] buff;
+}
+
+QPID_AUTO_TEST_CASE(testIVEOption)
+{
+ FieldTable args;
+ args.setInt("qpid.ive",1);
+ DirectExchange direct("direct1", false, args);
+ FanOutExchange fanout("fanout1", false, args);
+ HeadersExchange header("headers1", false, args);
+ TopicExchange topic ("topic1", false, args);
+
+ intrusive_ptr<Message> msg1 = cmessage("direct1", "abc");
+ msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString("a", "abc");
+ DeliverableMessage dmsg1(msg1);
+
+ FieldTable args2;
+ args2.setString("x-match", "any");
+ args2.setString("a", "abc");
+
+ direct.route(dmsg1, "abc", 0);
+ fanout.route(dmsg1, "abc", 0);
+ header.route(dmsg1, "abc", &args2);
+ topic.route(dmsg1, "abc", 0);
+ Queue::shared_ptr queue(new Queue("queue", true));
+ Queue::shared_ptr queue1(new Queue("queue1", true));
+ Queue::shared_ptr queue2(new Queue("queue2", true));
+ Queue::shared_ptr queue3(new Queue("queue3", true));
+
+ BOOST_CHECK(HeadersExchange::match(args2, msg1->getProperties<MessageProperties>()->getApplicationHeaders()));
+
+ BOOST_CHECK(direct.bind(queue, "abc", 0));
+ BOOST_CHECK(fanout.bind(queue1, "abc", 0));
+ BOOST_CHECK(header.bind(queue2, "", &args2));
+ BOOST_CHECK(topic.bind(queue3, "abc", 0));
+
+ BOOST_CHECK_EQUAL(1u,queue->getMessageCount());
+ BOOST_CHECK_EQUAL(1u,queue1->getMessageCount());
+ BOOST_CHECK_EQUAL(1u,queue2->getMessageCount());
+ BOOST_CHECK_EQUAL(1u,queue3->getMessageCount());
+
}
+
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/FieldTable.cpp b/cpp/src/tests/FieldTable.cpp
index 315801b428..fe2a14ec03 100644
--- a/cpp/src/tests/FieldTable.cpp
+++ b/cpp/src/tests/FieldTable.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -19,21 +19,26 @@
*
*/
#include <iostream>
+#include "qpid/framing/Array.h"
#include "qpid/framing/FieldTable.h"
#include "qpid/framing/FieldValue.h"
-#include <alloca.h>
+#include "qpid/framing/List.h"
+#include "qpid/sys/alloca.h"
#include "unit_test.h"
using namespace qpid::framing;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(FieldTableTestSuite)
QPID_AUTO_TEST_CASE(testMe)
{
FieldTable ft;
ft.setString("A", "BCDE");
- BOOST_CHECK(string("BCDE") == ft.getString("A"));
+ BOOST_CHECK(string("BCDE") == ft.getAsString("A"));
char buff[100];
Buffer wbuffer(buff, 100);
@@ -42,7 +47,7 @@ QPID_AUTO_TEST_CASE(testMe)
Buffer rbuffer(buff, 100);
FieldTable ft2;
rbuffer.get(ft2);
- BOOST_CHECK(string("BCDE") == ft2.getString("A"));
+ BOOST_CHECK(string("BCDE") == ft2.getAsString("A"));
}
@@ -55,11 +60,11 @@ QPID_AUTO_TEST_CASE(testAssignment)
a.setInt("B", 1234);
b = a;
a.setString("A", "CCCC");
-
- BOOST_CHECK(string("CCCC") == a.getString("A"));
- BOOST_CHECK(string("BBBB") == b.getString("A"));
- BOOST_CHECK_EQUAL(1234, a.getInt("B"));
- BOOST_CHECK_EQUAL(1234, b.getInt("B"));
+
+ BOOST_CHECK(string("CCCC") == a.getAsString("A"));
+ BOOST_CHECK(string("BBBB") == b.getAsString("A"));
+ BOOST_CHECK_EQUAL(1234, a.getAsInt("B"));
+ BOOST_CHECK_EQUAL(1234, b.getAsInt("B"));
BOOST_CHECK(IntegerValue(1234) == *a.get("B"));
BOOST_CHECK(IntegerValue(1234) == *b.get("B"));
@@ -67,19 +72,142 @@ QPID_AUTO_TEST_CASE(testAssignment)
{
FieldTable c;
c = a;
-
- char* buff = static_cast<char*>(::alloca(c.size()));
- Buffer wbuffer(buff, c.size());
+
+ char* buff = static_cast<char*>(::alloca(c.encodedSize()));
+ Buffer wbuffer(buff, c.encodedSize());
wbuffer.put(c);
- Buffer rbuffer(buff, c.size());
+ Buffer rbuffer(buff, c.encodedSize());
rbuffer.get(d);
BOOST_CHECK_EQUAL(c, d);
- BOOST_CHECK(string("CCCC") == c.getString("A"));
+ BOOST_CHECK(string("CCCC") == c.getAsString("A"));
BOOST_CHECK(IntegerValue(1234) == *c.get("B"));
}
- BOOST_CHECK(string("CCCC") == d.getString("A"));
+ BOOST_CHECK(string("CCCC") == d.getAsString("A"));
BOOST_CHECK(IntegerValue(1234) == *d.get("B"));
}
+
+QPID_AUTO_TEST_CASE(testNestedValues)
+{
+ double d = 1.2345;
+ uint32_t u = 101;
+ char buff[1000];
+ {
+ FieldTable a;
+ FieldTable b;
+ std::vector<std::string> items;
+ items.push_back("one");
+ items.push_back("two");
+ Array c(items);
+ List list;
+ list.push_back(List::ValuePtr(new Str16Value("red")));
+ list.push_back(List::ValuePtr(new Unsigned32Value(u)));
+ list.push_back(List::ValuePtr(new Str8Value("yellow")));
+ list.push_back(List::ValuePtr(new DoubleValue(d)));
+
+ a.setString("id", "A");
+ b.setString("id", "B");
+ a.setTable("B", b);
+ a.setArray("C", c);
+ a.set("my-list", FieldTable::ValuePtr(new ListValue(list)));
+
+
+ Buffer wbuffer(buff, 100);
+ wbuffer.put(a);
+ }
+ {
+ Buffer rbuffer(buff, 100);
+ FieldTable a;
+ FieldTable b;
+ Array c;
+ rbuffer.get(a);
+ BOOST_CHECK(string("A") == a.getAsString("id"));
+ a.getTable("B", b);
+ BOOST_CHECK(string("B") == b.getAsString("id"));
+ a.getArray("C", c);
+ std::vector<std::string> items;
+ c.collect(items);
+ BOOST_CHECK((uint) 2 == items.size());
+ BOOST_CHECK(string("one") == items[0]);
+ BOOST_CHECK(string("two") == items[1]);
+
+ List list;
+ BOOST_CHECK(a.get("my-list")->get<List>(list));
+ List::const_iterator i = list.begin();
+ BOOST_CHECK(i != list.end());
+ BOOST_CHECK_EQUAL(std::string("red"), (*i)->get<std::string>());
+
+ i++;
+ BOOST_CHECK(i != list.end());
+ BOOST_CHECK_EQUAL(u, (uint32_t) (*i)->get<int>());
+
+ i++;
+ BOOST_CHECK(i != list.end());
+ BOOST_CHECK_EQUAL(std::string("yellow"), (*i)->get<std::string>());
+
+ i++;
+ BOOST_CHECK(i != list.end());
+ BOOST_CHECK_EQUAL(d, (*i)->get<double>());
+
+ i++;
+ BOOST_CHECK(i == list.end());
+ }
+}
+
+QPID_AUTO_TEST_CASE(testFloatAndDouble)
+{
+ char buff[100];
+ float f = 5.672f;
+ double d = 56.720001;
+ {
+ FieldTable a;
+ a.setString("string", "abc");
+ a.setInt("int", 5672);
+ a.setFloat("float", f);
+ a.setDouble("double", d);
+
+ Buffer wbuffer(buff, 100);
+ wbuffer.put(a);
+ }
+ {
+ Buffer rbuffer(buff, 100);
+ FieldTable a;
+ rbuffer.get(a);
+ BOOST_CHECK(string("abc") == a.getAsString("string"));
+ BOOST_CHECK(5672 == a.getAsInt("int"));
+ float f2;
+ BOOST_CHECK(!a.getFloat("string", f2));
+ BOOST_CHECK(!a.getFloat("int", f2));
+ BOOST_CHECK(a.getFloat("float", f2));
+ BOOST_CHECK(f2 == f);
+
+ double d2;
+ BOOST_CHECK(!a.getDouble("string", d2));
+ BOOST_CHECK(!a.getDouble("int", d2));
+ BOOST_CHECK(a.getDouble("double", d2));
+ BOOST_CHECK(d2 == d);
+ }
+}
+
+QPID_AUTO_TEST_CASE(test64GetAndSetConverts)
+{
+ FieldTable args;
+ args.setInt64("a",100);
+ args.setInt64("b",-(int64_t) ((int64_t) 1<<34));
+
+ args.setUInt64("c",1u);
+ args.setUInt64("d",(uint64_t) ((uint64_t) 1<<34));
+ BOOST_CHECK_EQUAL(1u, args.getAsUInt64("c"));
+ BOOST_CHECK_EQUAL(100u, args.getAsUInt64("a"));
+ BOOST_CHECK_EQUAL(1, args.getAsInt64("c"));
+ BOOST_CHECK_EQUAL(100, args.getAsInt64("a"));
+ BOOST_CHECK_EQUAL(-(int64_t) ((int64_t) 1<<34), args.getAsInt64("b"));
+ BOOST_CHECK_EQUAL((uint64_t) ((uint64_t) 1<<34), args.getAsUInt64("d"));
+ BOOST_CHECK_EQUAL((int64_t) ((int64_t) 1<<34), args.getAsInt64("d"));
+
+}
+
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/FieldValue.cpp b/cpp/src/tests/FieldValue.cpp
index eacf098034..0ebd0d7d44 100644
--- a/cpp/src/tests/FieldValue.cpp
+++ b/cpp/src/tests/FieldValue.cpp
@@ -6,9 +6,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -20,21 +20,24 @@
#include "unit_test.h"
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(FieldValueTestSuite)
using namespace qpid::framing;
-StringValue s("abc");
+Str16Value s("abc");
IntegerValue i(42);
//DecimalValue d(1234,2);
//FieldTableValue ft;
//EmptyValue e;
-QPID_AUTO_TEST_CASE(testStringValueEquals)
+QPID_AUTO_TEST_CASE(testStr16ValueEquals)
{
-
- BOOST_CHECK(StringValue("abc") == s);
- BOOST_CHECK(StringValue("foo") != s);
+
+ BOOST_CHECK(Str16Value("abc") == s);
+ BOOST_CHECK(Str16Value("foo") != s);
BOOST_CHECK(s != i);
BOOST_CHECK(s.convertsTo<std::string>() == true);
BOOST_CHECK(s.convertsTo<int>() == false);
@@ -73,7 +76,7 @@ QPID_AUTO_TEST_CASE(testFieldTableValueEquals)
BOOST_CHECK_EQUAL(std::string("FOO"),
ft.getValue().getString("foo"));
BOOST_CHECK_EQUAL(7, ft.getValue().getInt("magic"));
-
+
FieldTableValue f2;
BOOST_CHECK(ft != f2);
f2.getValue().setString("foo", "FOO");
@@ -88,3 +91,5 @@ QPID_AUTO_TEST_CASE(testFieldTableValueEquals)
#endif
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/ForkedBroker.cpp b/cpp/src/tests/ForkedBroker.cpp
new file mode 100644
index 0000000000..e1a96c8e90
--- /dev/null
+++ b/cpp/src/tests/ForkedBroker.cpp
@@ -0,0 +1,131 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "ForkedBroker.h"
+#include "qpid/log/Statement.h"
+#include <boost/bind.hpp>
+#include <algorithm>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <signal.h>
+
+using namespace std;
+using qpid::ErrnoException;
+
+namespace std {
+static ostream& operator<<(ostream& o, const qpid::tests::ForkedBroker::Args& a) {
+copy(a.begin(), a.end(), ostream_iterator<string>(o, " "));
+return o;
+}
+}
+
+namespace qpid {
+namespace tests {
+
+ForkedBroker::ForkedBroker(const Args& constArgs) {
+ Args args(constArgs);
+ Args::iterator i = find(args.begin(), args.end(), string("TMP_DATA_DIR"));
+ if (i != args.end()) {
+ args.erase(i);
+ char dd[] = "/tmp/ForkedBroker.XXXXXX";
+ if (!mkdtemp(dd))
+ throw qpid::ErrnoException("Can't create data dir");
+ dataDir = dd;
+ args.push_back("--data-dir");
+ args.push_back(dataDir);
+ }
+ init(args);
+}
+
+ForkedBroker::~ForkedBroker() {
+ try { kill(); }
+ catch (const std::exception& e) {
+ QPID_LOG(error, QPID_MSG("Killing forked broker: " << e.what()));
+ }
+ if (!dataDir.empty())
+ {
+ int unused_ret; // Suppress warnings about ignoring return value.
+ unused_ret = ::system(("rm -rf "+dataDir).c_str());
+ }
+}
+
+void ForkedBroker::kill(int sig) {
+ if (pid == 0) return;
+ int savePid = pid;
+ pid = 0; // Reset pid here in case of an exception.
+ using qpid::ErrnoException;
+ if (::kill(savePid, sig) < 0)
+ throw ErrnoException("kill failed");
+ int status;
+ if (::waitpid(savePid, &status, 0) < 0 && sig != 9)
+ throw ErrnoException("wait for forked process failed");
+ if (WEXITSTATUS(status) != 0 && sig != 9)
+ throw qpid::Exception(QPID_MSG("Forked broker exited with: " << WEXITSTATUS(status)));
+}
+
+bool isLogOption(const std::string& s) {
+ const char * log_enable = "--log-enable",
+ * trace = "--trace";
+ return( (! strncmp(s.c_str(), log_enable, strlen(log_enable))) ||
+ (! strncmp(s.c_str(), trace, strlen(trace)))
+ );
+}
+
+void ForkedBroker::init(const Args& userArgs) {
+ using qpid::ErrnoException;
+ port = 0;
+ int pipeFds[2];
+ if(::pipe(pipeFds) < 0) throw ErrnoException("Can't create pipe");
+ pid = ::fork();
+ if (pid < 0) throw ErrnoException("Fork failed");
+ if (pid) { // parent
+ ::close(pipeFds[1]);
+ FILE* f = ::fdopen(pipeFds[0], "r");
+ if (!f) throw ErrnoException("fopen failed");
+ if (::fscanf(f, "%d", &port) != 1) {
+ if (ferror(f)) throw ErrnoException("Error reading port number from child.");
+ else throw qpid::Exception("EOF reading port number from child.");
+ }
+ ::close(pipeFds[0]);
+ }
+ else { // child
+ ::close(pipeFds[0]);
+ int fd = ::dup2(pipeFds[1], 1); // pipe stdout to the parent.
+ if (fd < 0) throw ErrnoException("dup2 failed");
+ const char* prog = ::getenv("QPIDD_EXEC");
+ if (!prog) prog = "../qpidd"; // This only works from within svn checkout
+ Args args(userArgs);
+ args.push_back("--port=0");
+ // Keep quiet except for errors.
+ if (!::getenv("QPID_TRACE") && !::getenv("QPID_LOG_ENABLE")
+ && find_if(userArgs.begin(), userArgs.end(), isLogOption) == userArgs.end())
+ args.push_back("--log-enable=error+");
+ std::vector<const char*> argv(args.size());
+ std::transform(args.begin(), args.end(), argv.begin(), boost::bind(&std::string::c_str, _1));
+ argv.push_back(0);
+ QPID_LOG(debug, "ForkedBroker exec " << prog << ": " << args);
+ execv(prog, const_cast<char* const*>(&argv[0]));
+ QPID_LOG(critical, "execv failed to start broker: prog=\"" << prog << "\"; args=\"" << args << "\"; errno=" << errno << " (" << std::strerror(errno) << ")");
+ ::exit(1);
+ }
+}
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/ForkedBroker.h b/cpp/src/tests/ForkedBroker.h
index a7869ff602..ddbad185d8 100644
--- a/cpp/src/tests/ForkedBroker.h
+++ b/cpp/src/tests/ForkedBroker.h
@@ -1,4 +1,5 @@
#ifndef TESTS_FORKEDBROKER_H
+#define TESTS_FORKEDBROKER_H
/*
@@ -10,9 +11,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -30,9 +31,12 @@
#include <stdio.h>
#include <sys/wait.h>
+namespace qpid {
+namespace tests {
+
/**
* Class to fork a broker child process.
- *
+ *
* For most tests a BrokerFixture may be more convenient as it starts
* a broker in the same process which allows you to easily debug into
* the broker.
@@ -41,68 +45,34 @@
* those brokers can't coexist in the same process (e.g. for cluster
* tests where CPG doesn't allow multiple group members in a single
* process.)
- *
+ *
*/
class ForkedBroker {
public:
- ForkedBroker(std::vector<const char*> argv) { init(argv); }
-
- ForkedBroker(int argc, const char* const argv[]) {
- std::vector<const char*> args(argv, argv+argc);
- init(args);
- }
+ typedef std::vector<std::string> Args;
- ~ForkedBroker() {
- try { stop(); } catch(const std::exception& e) {
- QPID_LOG(error, QPID_MSG("Stopping forked broker: " << e.what()));
- }
- }
-
- void stop() {
- using qpid::ErrnoException;
- if (pid == 0) return;
- if (::kill(pid, SIGINT) < 0) throw ErrnoException("kill failed");
- int status;
- if (::waitpid(pid, &status, 0) < 0) throw ErrnoException("wait for forked process failed");
- if (WEXITSTATUS(status) != 0)
- throw qpid::Exception(QPID_MSG("forked broker exited with: " << WEXITSTATUS(status)));
- pid = 0;
- }
+ // argv args are passed to broker.
+ //
+ // Special value "TMP_DATA_DIR" is substituted with a temporary
+ // data directory for the broker.
+ //
+ ForkedBroker(const Args& argv);
+ ~ForkedBroker();
+ void kill(int sig=SIGINT);
+ int wait(); // Wait for exit, return exit status.
uint16_t getPort() { return port; }
+ pid_t getPID() { return pid; }
private:
- void init(const std::vector<const char*>& args) {
- using qpid::ErrnoException;
- pid = 0;
- port = 0;
- int pipeFds[2];
- if(::pipe(pipeFds) < 0) throw ErrnoException("Can't create pipe");
- pid = ::fork();
- if (pid < 0) throw ErrnoException("Fork failed");
- if (pid) { // parent
- ::close(pipeFds[1]);
- FILE* f = ::fdopen(pipeFds[0], "r");
- if (!f) throw ErrnoException("fopen failed");
- if (::fscanf(f, "%d", &port) != 1) throw ErrnoException("ill-formatted port");
- }
- else { // child
- ::close(pipeFds[0]);
- int fd = ::dup2(pipeFds[1], 1);
- if (fd < 0) throw ErrnoException("dup2 failed");
- const char* prog = "../qpidd";
- std::vector<const char*> args2(args);
- args2.push_back("--port=0");
- args2.push_back("--mgmt-enable=no"); // TODO aconway 2008-07-16: why does mgmt cause problems?
- args2.push_back(0);
- execv(prog, const_cast<char* const*>(&args2[0]));
- throw ErrnoException("execv failed");
- }
- }
+ void init(const Args& args);
pid_t pid;
int port;
+ std::string dataDir;
};
+}} // namespace qpid::tests
+
#endif /*!TESTS_FORKEDBROKER_H*/
diff --git a/cpp/src/tests/Frame.cpp b/cpp/src/tests/Frame.cpp
index 9ee3848b7b..1270eabba3 100644
--- a/cpp/src/tests/Frame.cpp
+++ b/cpp/src/tests/Frame.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -23,6 +23,9 @@
#include <boost/lexical_cast.hpp>
#include "unit_test.h"
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(FrameTestSuite)
using namespace std;
@@ -33,7 +36,7 @@ QPID_AUTO_TEST_CASE(testContentBody) {
Frame f(42, AMQContentBody("foobar"));
AMQBody* body=f.getBody();
BOOST_CHECK(dynamic_cast<AMQContentBody*>(body));
- Buffer b(f.size());
+ Buffer b(f.encodedSize();
f.encode(b);
b.flip();
Frame g;
@@ -50,7 +53,7 @@ QPID_AUTO_TEST_CASE(testMethodBody) {
42, QueueDeclareBody(ProtocolVersion(), 1, "q", "altex",
true, false, true, false, true, args));
BOOST_CHECK_EQUAL(f.getChannel(), 42);
- Buffer b(f.size());
+ Buffer b(f.encodedSize();
f.encode(b);
b.flip();
Frame g;
@@ -78,3 +81,5 @@ QPID_AUTO_TEST_CASE(testLoop) {
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/FrameDecoder.cpp b/cpp/src/tests/FrameDecoder.cpp
new file mode 100644
index 0000000000..9eeff2a41e
--- /dev/null
+++ b/cpp/src/tests/FrameDecoder.cpp
@@ -0,0 +1,78 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "unit_test.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/FrameDecoder.h"
+#include "qpid/framing/AMQContentBody.h"
+#include "qpid/framing/Buffer.h"
+#include <string>
+
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(FrameDecoderTest)
+
+using namespace std;
+using namespace qpid::framing;
+
+
+string makeData(int size) {
+ string data;
+ data.resize(size);
+ for (int i =0; i < size; ++i)
+ data[i] = 'a' + (i%26);
+ return data;
+}
+string encodeFrame(string data) {
+ AMQFrame f((AMQContentBody(data)));
+ string encoded;
+ encoded.resize(f.encodedSize());
+ Buffer b(&encoded[0], encoded.size());
+ f.encode(b);
+ return encoded;
+}
+
+string getData(const AMQFrame& frame) {
+ const AMQContentBody* content = dynamic_cast<const AMQContentBody*>(frame.getBody());
+ BOOST_CHECK(content);
+ return content->getData();
+}
+
+QPID_AUTO_TEST_CASE(testByteFragments) {
+ string data = makeData(42);
+ string encoded = encodeFrame(data);
+ FrameDecoder decoder;
+ for (size_t i = 0; i < encoded.size()-1; ++i) {
+ Buffer buf(&encoded[i], 1);
+ BOOST_CHECK(!decoder.decode(buf));
+ }
+ Buffer buf(&encoded[encoded.size()-1], 1);
+ BOOST_CHECK(decoder.decode(buf));
+ BOOST_CHECK_EQUAL(data, getData(decoder.getFrame()));
+}
+
+
+
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/FramingTest.cpp b/cpp/src/tests/FramingTest.cpp
index f82507c0a7..3d0fa0c0de 100644
--- a/cpp/src/tests/FramingTest.cpp
+++ b/cpp/src/tests/FramingTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -39,8 +39,11 @@ using namespace qpid;
using namespace qpid::framing;
using namespace std;
+namespace qpid {
+namespace tests {
+
template <class T>
-std::string tostring(const T& x)
+std::string tostring(const T& x)
{
std::ostringstream out;
out << x;
@@ -49,7 +52,7 @@ std::string tostring(const T& x)
QPID_AUTO_TEST_SUITE(FramingTestSuite)
-QPID_AUTO_TEST_CASE(testMessageTransferBody)
+QPID_AUTO_TEST_CASE(testMessageTransferBody)
{
char buffer[1024];
ProtocolVersion version(highestProtocolVersion);
@@ -62,8 +65,8 @@ QPID_AUTO_TEST_CASE(testMessageTransferBody)
out.decode(rbuff);
BOOST_CHECK_EQUAL(tostring(in), tostring(out));
}
-
-QPID_AUTO_TEST_CASE(testConnectionSecureBody)
+
+QPID_AUTO_TEST_CASE(testConnectionSecureBody)
{
char buffer[1024];
ProtocolVersion version(highestProtocolVersion);
@@ -88,10 +91,10 @@ QPID_AUTO_TEST_CASE(testConnectionRedirectBody)
Array hosts(0x95);
hosts.add(boost::shared_ptr<FieldValue>(new Str16Value(a)));
hosts.add(boost::shared_ptr<FieldValue>(new Str16Value(b)));
-
+
ConnectionRedirectBody in(version, a, hosts);
in.encode(wbuff);
-
+
Buffer rbuff(buffer, sizeof(buffer));
ConnectionRedirectBody out(version);
out.decode(rbuff);
@@ -111,7 +114,7 @@ QPID_AUTO_TEST_CASE(testQueueDeclareBody)
out.decode(rbuff);
BOOST_CHECK_EQUAL(tostring(in), tostring(out));
}
-
+
QPID_AUTO_TEST_CASE(testConnectionRedirectBodyFrame)
{
char buffer[1024];
@@ -122,8 +125,8 @@ QPID_AUTO_TEST_CASE(testConnectionRedirectBodyFrame)
Array hosts(0x95);
hosts.add(boost::shared_ptr<FieldValue>(new Str16Value(a)));
hosts.add(boost::shared_ptr<FieldValue>(new Str16Value(b)));
-
- AMQFrame in(in_place<ConnectionRedirectBody>(version, a, hosts));
+
+ AMQFrame in((ConnectionRedirectBody(version, a, hosts)));
in.setChannel(999);
in.encode(wbuff);
@@ -138,7 +141,7 @@ QPID_AUTO_TEST_CASE(testMessageCancelBodyFrame)
char buffer[1024];
ProtocolVersion version(highestProtocolVersion);
Buffer wbuff(buffer, sizeof(buffer));
- AMQFrame in(in_place<MessageCancelBody>(version, "tag"));
+ AMQFrame in((MessageCancelBody(version, "tag")));
in.setChannel(999);
in.encode(wbuff);
@@ -149,3 +152,5 @@ QPID_AUTO_TEST_CASE(testMessageCancelBodyFrame)
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/HeaderTest.cpp b/cpp/src/tests/HeaderTest.cpp
index c3b64419ed..4b16f3c793 100644
--- a/cpp/src/tests/HeaderTest.cpp
+++ b/cpp/src/tests/HeaderTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -26,9 +26,12 @@
using namespace qpid::framing;
using namespace std;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(HeaderTestSuite)
-QPID_AUTO_TEST_CASE(testGenericProperties)
+QPID_AUTO_TEST_CASE(testGenericProperties)
{
AMQHeaderBody body;
body.get<MessageProperties>(true)->getApplicationHeaders().setString(
@@ -39,7 +42,7 @@ QPID_AUTO_TEST_CASE(testGenericProperties)
Buffer rbuffer(buff, 100);
AMQHeaderBody body2;
- body2.decode(rbuffer, body.size());
+ body2.decode(rbuffer, body.encodedSize());
MessageProperties* props =
body2.get<MessageProperties>(true);
BOOST_CHECK_EQUAL(
@@ -47,10 +50,10 @@ QPID_AUTO_TEST_CASE(testGenericProperties)
props->getApplicationHeaders().get("A")->get<string>());
}
-QPID_AUTO_TEST_CASE(testMessageProperties)
+QPID_AUTO_TEST_CASE(testMessageProperties)
{
- AMQFrame out(in_place<AMQHeaderBody>());
- MessageProperties* props1 =
+ AMQFrame out((AMQHeaderBody()));
+ MessageProperties* props1 =
out.castBody<AMQHeaderBody>()->get<MessageProperties>(true);
props1->setContentLength(42);
@@ -82,10 +85,10 @@ QPID_AUTO_TEST_CASE(testMessageProperties)
}
-QPID_AUTO_TEST_CASE(testDeliveryProperies)
+QPID_AUTO_TEST_CASE(testDeliveryProperies)
{
- AMQFrame out(in_place<AMQHeaderBody>());
- DeliveryProperties* props1 =
+ AMQFrame out((AMQHeaderBody()));
+ DeliveryProperties* props1 =
out.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true);
props1->setDiscardUnroutable(true);
@@ -108,3 +111,4 @@ QPID_AUTO_TEST_CASE(testDeliveryProperies)
QPID_AUTO_TEST_SUITE_END()
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/HeadersExchangeTest.cpp b/cpp/src/tests/HeadersExchangeTest.cpp
index 46933f955a..40deb59c86 100644
--- a/cpp/src/tests/HeadersExchangeTest.cpp
+++ b/cpp/src/tests/HeadersExchangeTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -28,9 +28,12 @@
using namespace qpid::broker;
using namespace qpid::framing;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(HeadersExchangeTestSuite)
-
-QPID_AUTO_TEST_CASE(testMatchAll)
+
+QPID_AUTO_TEST_CASE(testMatchAll)
{
FieldTable b, m, n;
b.setString("x-match", "all");
@@ -43,7 +46,7 @@ QPID_AUTO_TEST_CASE(testMatchAll)
// Ignore extras.
m.setString("extra", "x");
BOOST_CHECK(HeadersExchange::match(b, m));
-
+
// Fail mismatch, wrong value.
m.setString("foo", "NotFoo");
BOOST_CHECK(!HeadersExchange::match(b, m));
@@ -54,7 +57,7 @@ QPID_AUTO_TEST_CASE(testMatchAll)
BOOST_CHECK(!HeadersExchange::match(b, n));
}
-QPID_AUTO_TEST_CASE(testMatchAny)
+QPID_AUTO_TEST_CASE(testMatchAny)
{
FieldTable b, m, n;
b.setString("x-match", "any");
@@ -67,7 +70,7 @@ QPID_AUTO_TEST_CASE(testMatchAny)
BOOST_CHECK(HeadersExchange::match(b, m));
}
-QPID_AUTO_TEST_CASE(testMatchEmptyValue)
+QPID_AUTO_TEST_CASE(testMatchEmptyValue)
{
FieldTable b, m;
b.setString("x-match", "all");
@@ -82,23 +85,23 @@ QPID_AUTO_TEST_CASE(testMatchEmptyArgs)
{
FieldTable b, m;
m.setString("foo", "FOO");
-
+
b.setString("x-match", "all");
BOOST_CHECK(HeadersExchange::match(b, m));
b.setString("x-match", "any");
BOOST_CHECK(!HeadersExchange::match(b, m));
}
-
-QPID_AUTO_TEST_CASE(testMatchNoXMatch)
+
+QPID_AUTO_TEST_CASE(testMatchNoXMatch)
{
FieldTable b, m;
b.setString("foo", "FOO");
m.setString("foo", "FOO");
BOOST_CHECK(!HeadersExchange::match(b, m));
}
-
-QPID_AUTO_TEST_CASE(testBindNoXMatch)
+
+QPID_AUTO_TEST_CASE(testBindNoXMatch)
{
HeadersExchange exchange("test");
Queue::shared_ptr queue;
@@ -112,4 +115,6 @@ QPID_AUTO_TEST_CASE(testBindNoXMatch)
}
}
-QPID_AUTO_TEST_SUITE_END()
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/IncompleteMessageList.cpp b/cpp/src/tests/IncompleteMessageList.cpp
index 925cdbf43e..303d83cd66 100644
--- a/cpp/src/tests/IncompleteMessageList.cpp
+++ b/cpp/src/tests/IncompleteMessageList.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -27,6 +27,9 @@
#include "unit_test.h"
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(IncompleteMessageListTestSuite)
using namespace qpid::broker;
@@ -41,7 +44,7 @@ struct Checker
Checker(uint start, uint end) {
for (uint i = start; i <= end; i++) {
ids.push_back(i);
- }
+ }
}
Checker& expect(const SequenceNumber& id) {
@@ -49,11 +52,11 @@ struct Checker
return *this;
}
- void operator()(boost::intrusive_ptr<Message> msg) {
+ void operator()(boost::intrusive_ptr<Message> msg) {
BOOST_CHECK(!ids.empty());
BOOST_CHECK_EQUAL(msg->getCommandId(), ids.front());
ids.pop_front();
- }
+ }
};
QPID_AUTO_TEST_CASE(testProcessSimple)
@@ -73,6 +76,7 @@ QPID_AUTO_TEST_CASE(testProcessSimple)
QPID_AUTO_TEST_CASE(testProcessWithIncomplete)
{
+ Queue::shared_ptr queue;
IncompleteMessageList list;
SequenceNumber counter(1);
boost::intrusive_ptr<Message> middle;
@@ -82,7 +86,7 @@ QPID_AUTO_TEST_CASE(testProcessWithIncomplete)
list.add(msg);
if (i == 2) {
//mark a message in the middle as incomplete
- msg->enqueueAsync();
+ msg->enqueueAsync(queue, 0);
middle = msg;
}
}
@@ -90,7 +94,7 @@ QPID_AUTO_TEST_CASE(testProcessWithIncomplete)
list.process(Checker(1, 2), false);
//mark message complete and re-process to get remaining messages sent to listener
middle->enqueueComplete();
- list.process(Checker(3, 5), false);
+ list.process(Checker(3, 5), false);
}
@@ -126,3 +130,5 @@ QPID_AUTO_TEST_CASE(testSyncProcessWithIncomplete)
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/InitialStatusMap.cpp b/cpp/src/tests/InitialStatusMap.cpp
new file mode 100644
index 0000000000..82450eac22
--- /dev/null
+++ b/cpp/src/tests/InitialStatusMap.cpp
@@ -0,0 +1,248 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#include "unit_test.h"
+#include "test_tools.h"
+#include "qpid/cluster/InitialStatusMap.h"
+#include "qpid/framing/Uuid.h"
+#include <boost/assign.hpp>
+
+using namespace std;
+using namespace qpid::cluster;
+using namespace qpid::framing;
+using namespace qpid::framing::cluster;
+using namespace boost::assign;
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(InitialStatusMapTestSuite)
+
+typedef InitialStatusMap::Status Status;
+
+Status activeStatus(const Uuid& id=Uuid()) {
+ return Status(ProtocolVersion(), 0, true, id, STORE_STATE_NO_STORE, Uuid());
+}
+
+Status newcomerStatus(const Uuid& id=Uuid()) {
+ return Status(ProtocolVersion(), 0, false, id, STORE_STATE_NO_STORE, Uuid());
+}
+
+Status storeStatus(bool active, StoreState state, Uuid start=Uuid(), Uuid stop=Uuid()) {
+ return Status(ProtocolVersion(), 0, active, start, state, stop);
+}
+
+QPID_AUTO_TEST_CASE(testFirstInCluster) {
+ // Single member is first in cluster.
+ InitialStatusMap map(MemberId(0), 1);
+ Uuid id(true);
+ BOOST_CHECK(!map.isComplete());
+ MemberSet members = list_of(MemberId(0));
+ map.configChange(members);
+ BOOST_CHECK(!map.isComplete());
+ map.received(MemberId(0), newcomerStatus(id));
+ BOOST_CHECK(map.isComplete());
+ BOOST_CHECK(map.transitionToComplete());
+ BOOST_CHECK(map.getElders().empty());
+ BOOST_CHECK(!map.isUpdateNeeded());
+ BOOST_CHECK_EQUAL(id, map.getClusterId());
+}
+
+QPID_AUTO_TEST_CASE(testJoinExistingCluster) {
+ // Single member 0 joins existing cluster 1,2
+ InitialStatusMap map(MemberId(0), 1);
+ Uuid id(true);
+ MemberSet members = list_of(MemberId(0))(MemberId(1))(MemberId(2));
+ map.configChange(members);
+ BOOST_CHECK(map.isResendNeeded());
+ BOOST_CHECK(!map.isComplete());
+ map.received(MemberId(0), newcomerStatus());
+ map.received(MemberId(1), activeStatus(id));
+ BOOST_CHECK(!map.isComplete());
+ map.received(MemberId(2), activeStatus(id));
+ BOOST_CHECK(map.isComplete());
+ BOOST_CHECK(map.transitionToComplete());
+ BOOST_CHECK_EQUAL(map.getElders(), list_of<MemberId>(1)(2));
+ BOOST_CHECK(map.isUpdateNeeded());
+ BOOST_CHECK_EQUAL(map.getClusterId(), id);
+
+ // Check that transitionToComplete is reset.
+ map.configChange(list_of<MemberId>(0)(1));
+ BOOST_CHECK(!map.transitionToComplete());
+}
+
+QPID_AUTO_TEST_CASE(testMultipleFirstInCluster) {
+ // Multiple members 0,1,2 join at same time.
+ InitialStatusMap map(MemberId(1), 1); // self is 1
+ Uuid id(true);
+ MemberSet members = list_of(MemberId(0))(MemberId(1))(MemberId(2));
+ map.configChange(members);
+ BOOST_CHECK(map.isResendNeeded());
+
+ // All new members
+ map.received(MemberId(0), newcomerStatus(id));
+ map.received(MemberId(1), newcomerStatus());
+ map.received(MemberId(2), newcomerStatus());
+ BOOST_CHECK(!map.isResendNeeded());
+ BOOST_CHECK(map.isComplete());
+ BOOST_CHECK(map.transitionToComplete());
+ BOOST_CHECK_EQUAL(map.getElders(), list_of(MemberId(2)));
+ BOOST_CHECK(!map.isUpdateNeeded());
+ BOOST_CHECK_EQUAL(map.getClusterId(), id);
+}
+
+QPID_AUTO_TEST_CASE(testMultipleJoinExisting) {
+ // Multiple members 1,2,3 join existing cluster containing 0.
+ InitialStatusMap map(MemberId(2), 1); // self is 2
+ Uuid id(true);
+ MemberSet members = list_of(MemberId(0))(MemberId(1))(MemberId(2))(MemberId(3));
+ map.configChange(members);
+ BOOST_CHECK(map.isResendNeeded());
+
+ map.received(MemberId(1), newcomerStatus());
+ map.received(MemberId(2), newcomerStatus());
+ map.received(MemberId(3), newcomerStatus());
+ map.received(MemberId(0), activeStatus(id));
+ BOOST_CHECK(!map.isResendNeeded());
+ BOOST_CHECK(map.isComplete());
+ BOOST_CHECK(map.transitionToComplete());
+ BOOST_CHECK_EQUAL(map.getElders(), list_of(MemberId(0))(MemberId(3)));
+ BOOST_CHECK(map.isUpdateNeeded());
+ BOOST_CHECK_EQUAL(map.getClusterId(), id);
+}
+
+QPID_AUTO_TEST_CASE(testMembersLeave) {
+ // Test that map completes if members leave rather than send status.
+ InitialStatusMap map(MemberId(0), 1);
+ Uuid id(true);
+ map.configChange(list_of(MemberId(0))(MemberId(1))(MemberId(2)));
+ map.received(MemberId(0), newcomerStatus());
+ map.received(MemberId(1), activeStatus(id));
+ BOOST_CHECK(!map.isComplete());
+ map.configChange(list_of(MemberId(0))(MemberId(1))); // 2 left
+ BOOST_CHECK(map.isComplete());
+ BOOST_CHECK(map.transitionToComplete());
+ BOOST_CHECK_EQUAL(map.getElders(), list_of(MemberId(1)));
+ BOOST_CHECK_EQUAL(map.getClusterId(), id);
+}
+
+QPID_AUTO_TEST_CASE(testInteveningConfig) {
+ // Multiple config changes arrives before we complete the map.
+ InitialStatusMap map(MemberId(0), 1);
+ Uuid id(true);
+
+ map.configChange(list_of<MemberId>(0)(1));
+ BOOST_CHECK(map.isResendNeeded());
+ map.received(MemberId(0), newcomerStatus());
+ BOOST_CHECK(!map.isComplete());
+ BOOST_CHECK(!map.isResendNeeded());
+ // New member 2 joins before we receive 1
+ map.configChange(list_of<MemberId>(0)(1)(2));
+ BOOST_CHECK(!map.isComplete());
+ BOOST_CHECK(map.isResendNeeded());
+ map.received(1, activeStatus(id));
+ map.received(2, newcomerStatus());
+ // We should not be complete as we haven't received 0 since new member joined
+ BOOST_CHECK(!map.isComplete());
+ BOOST_CHECK(!map.isResendNeeded());
+
+ map.received(0, newcomerStatus());
+ BOOST_CHECK(map.isComplete());
+ BOOST_CHECK(map.transitionToComplete());
+ BOOST_CHECK_EQUAL(map.getElders(), list_of<MemberId>(1));
+ BOOST_CHECK_EQUAL(map.getClusterId(), id);
+}
+
+QPID_AUTO_TEST_CASE(testInitialSize) {
+ InitialStatusMap map(MemberId(0), 3);
+ map.configChange(list_of<MemberId>(0)(1));
+ map.received(MemberId(0), newcomerStatus());
+ map.received(MemberId(1), newcomerStatus());
+ BOOST_CHECK(!map.isComplete());
+
+ map.configChange(list_of<MemberId>(0)(1)(2));
+ map.received(MemberId(0), newcomerStatus());
+ map.received(MemberId(1), newcomerStatus());
+ map.received(MemberId(2), newcomerStatus());
+ BOOST_CHECK(map.isComplete());
+}
+
+QPID_AUTO_TEST_CASE(testAllCleanNoUpdate) {
+ InitialStatusMap map(MemberId(0), 3);
+ map.configChange(list_of<MemberId>(0)(1)(2));
+ map.received(MemberId(0), storeStatus(false, STORE_STATE_CLEAN_STORE));
+ map.received(MemberId(1), storeStatus(false, STORE_STATE_CLEAN_STORE));
+ map.received(MemberId(2), storeStatus(false, STORE_STATE_CLEAN_STORE));
+ BOOST_CHECK(!map.isUpdateNeeded());
+}
+
+QPID_AUTO_TEST_CASE(testAllEmptyNoUpdate) {
+ InitialStatusMap map(MemberId(0), 3);
+ map.configChange(list_of<MemberId>(0)(1)(2));
+ map.received(MemberId(0), storeStatus(false, STORE_STATE_EMPTY_STORE));
+ map.received(MemberId(1), storeStatus(false, STORE_STATE_EMPTY_STORE));
+ map.received(MemberId(2), storeStatus(false, STORE_STATE_EMPTY_STORE));
+ BOOST_CHECK(map.isComplete());
+ BOOST_CHECK(!map.isUpdateNeeded());
+}
+
+QPID_AUTO_TEST_CASE(testAllNoStoreNoUpdate) {
+ InitialStatusMap map(MemberId(0), 3);
+ map.configChange(list_of<MemberId>(0)(1)(2));
+ map.received(MemberId(0), storeStatus(false, STORE_STATE_NO_STORE));
+ map.received(MemberId(1), storeStatus(false, STORE_STATE_NO_STORE));
+ map.received(MemberId(2), storeStatus(false, STORE_STATE_NO_STORE));
+ BOOST_CHECK(map.isComplete());
+ BOOST_CHECK(!map.isUpdateNeeded());
+}
+
+QPID_AUTO_TEST_CASE(testDirtyNeedUpdate) {
+ InitialStatusMap map(MemberId(0), 3);
+ map.configChange(list_of<MemberId>(0)(1)(2));
+ map.received(MemberId(0), storeStatus(false, STORE_STATE_DIRTY_STORE));
+ map.received(MemberId(1), storeStatus(false, STORE_STATE_CLEAN_STORE));
+ map.received(MemberId(2), storeStatus(false, STORE_STATE_CLEAN_STORE));
+ BOOST_CHECK(map.transitionToComplete());
+ BOOST_CHECK(map.isUpdateNeeded());
+}
+
+QPID_AUTO_TEST_CASE(testEmptyNeedUpdate) {
+ InitialStatusMap map(MemberId(0), 3);
+ map.configChange(list_of<MemberId>(0)(1)(2));
+ map.received(MemberId(0), storeStatus(false, STORE_STATE_EMPTY_STORE));
+ map.received(MemberId(1), storeStatus(false, STORE_STATE_CLEAN_STORE));
+ map.received(MemberId(2), storeStatus(false, STORE_STATE_CLEAN_STORE));
+ BOOST_CHECK(map.transitionToComplete());
+ BOOST_CHECK(map.isUpdateNeeded());
+}
+
+QPID_AUTO_TEST_CASE(testEmptyAlone) {
+ InitialStatusMap map(MemberId(0), 1);
+ map.configChange(list_of<MemberId>(0));
+ map.received(MemberId(0), storeStatus(false, STORE_STATE_EMPTY_STORE));
+ BOOST_CHECK(map.transitionToComplete());
+ BOOST_CHECK(!map.isUpdateNeeded());
+}
+
+// FIXME aconway 2009-11-20: consistency tests for mixed stores,
+// tests for manual intervention case.
+
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/InlineAllocator.cpp b/cpp/src/tests/InlineAllocator.cpp
index fe6eaefaf4..a4c4d64cea 100644
--- a/cpp/src/tests/InlineAllocator.cpp
+++ b/cpp/src/tests/InlineAllocator.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -22,6 +22,9 @@
#include "qpid/InlineAllocator.h"
#include "unit_test.h"
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(InlineAllocatorTestSuite)
using namespace qpid;
@@ -48,16 +51,18 @@ QPID_AUTO_TEST_CASE(testAllocateFull) {
char* p = alloc.allocate(1);
BOOST_CHECK(p == (char*)&alloc);
-
+
char* q = alloc.allocate(1);
BOOST_CHECK(q != (char*)&alloc);
alloc.deallocate(p,1);
p = alloc.allocate(1);
BOOST_CHECK(p == (char*)&alloc);
-
+
alloc.deallocate(p,1);
alloc.deallocate(q,1);
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/InlineVector.cpp b/cpp/src/tests/InlineVector.cpp
index bcd36e47b4..ba5165886d 100644
--- a/cpp/src/tests/InlineVector.cpp
+++ b/cpp/src/tests/InlineVector.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -22,6 +22,9 @@
#include "qpid/InlineVector.h"
#include "unit_test.h"
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(InlineVectorTestSuite)
using namespace qpid;
@@ -30,6 +33,10 @@ using namespace std;
typedef InlineVector<int, 3> Vec;
bool isInline(const Vec& v) {
+ // If nothing, give it the benefit of the doubt;
+ // can't take address of nothing.
+ if (v.size() <= 0)
+ return true;
return (const char*)&v <= (const char*)(&v[0]) &&
(const char*)(&v[0]) < (const char*)&v+sizeof(v);
}
@@ -113,7 +120,9 @@ QPID_AUTO_TEST_CASE(testAssign) {
QPID_AUTO_TEST_CASE(testResize) {
Vec v;
v.resize(5);
- BOOST_CHECK(!isInline(v));
+ BOOST_CHECK(!isInline(v));
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/Makefile.am b/cpp/src/tests/Makefile.am
index 31328ef59a..9a6e67ca2e 100644
--- a/cpp/src/tests/Makefile.am
+++ b/cpp/src/tests/Makefile.am
@@ -1,11 +1,34 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
AM_CXXFLAGS = $(WARNING_CFLAGS) -DBOOST_TEST_DYN_LINK
-INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../gen -I$(top_builddir)/src/gen
+INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src
+PUBLIC_INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include # Use public API only
abs_builddir=@abs_builddir@
+abs_srcdir=@abs_srcdir@
+
extra_libs =
lib_client = $(abs_builddir)/../libqpidclient.la
lib_common = $(abs_builddir)/../libqpidcommon.la
lib_broker = $(abs_builddir)/../libqpidbroker.la
+lib_console = $(abs_builddir)/../libqmfconsole.la
# lib_amqp_0_10 = $(abs_builddir)/../libqpidamqp_0_10.la
#
@@ -16,6 +39,19 @@ check_LTLIBRARIES=
TESTS=
EXTRA_DIST=
CLEANFILES=
+LONG_TESTS=
+
+#
+# Destination for intalled programs and tests defined here
+#
+qpidexecdir = $(libexecdir)/qpid
+qpidexec_PROGRAMS =
+qpidexec_SCRIPTS =
+qpidtestdir = $(qpidexecdir)/tests
+qpidtest_PROGRAMS =
+qpidtest_SCRIPTS =
+tmoduledir = $(libdir)/qpid/tests
+tmodule_LTLIBRARIES=
#
# Unit test program
@@ -28,18 +64,21 @@ CLEANFILES=
TESTS+=unit_test
check_PROGRAMS+=unit_test
unit_test_LDADD=-lboost_unit_test_framework -lboost_regex \
- $(lib_client) $(lib_broker) # $(lib_amqp_0_10)
+ $(lib_client) $(lib_broker) $(lib_console)
unit_test_SOURCES= unit_test.cpp unit_test.h \
+ MessagingSessionTests.cpp \
+ ClientSessionTest.cpp \
BrokerFixture.h SocketProxy.h \
exception_test.cpp \
RefCounted.cpp \
- SessionState.cpp Blob.cpp logging.cpp \
+ SessionState.cpp logging.cpp \
+ AsyncCompletion.cpp \
Url.cpp Uuid.cpp \
Shlib.cpp FieldValue.cpp FieldTable.cpp Array.cpp \
+ QueueOptionsTest.cpp \
InlineAllocator.cpp \
InlineVector.cpp \
- ClientSessionTest.cpp \
SequenceSet.cpp \
StringUtils.cpp \
IncompleteMessageList.cpp \
@@ -63,7 +102,22 @@ unit_test_SOURCES= unit_test.cpp unit_test.h \
TxPublishTest.cpp \
MessageBuilderTest.cpp \
ConnectionOptions.h \
- ForkedBroker.h
+ ForkedBroker.h \
+ ForkedBroker.cpp \
+ ManagementTest.cpp \
+ MessageReplayTracker.cpp \
+ ConsoleTest.cpp \
+ QueueEvents.cpp \
+ ProxyTest.cpp \
+ RetryList.cpp \
+ RateFlowcontrolTest.cpp \
+ FrameDecoder.cpp \
+ ReplicationTest.cpp \
+ ClientMessageTest.cpp \
+ PollableCondition.cpp \
+ Variant.cpp \
+ Address.cpp \
+ ClientMessage.cpp
if HAVE_XML
unit_test_SOURCES+= XmlClientSessionTest.cpp
@@ -77,94 +131,227 @@ endif
# amqp_0_10/Map.cpp \
# amqp_0_10/handlers.cpp
+TESTLIBFLAGS = -module -rpath $(abs_builddir)
check_LTLIBRARIES += libshlibtest.la
-libshlibtest_la_LDFLAGS = -module -rpath $(abs_builddir)
+libshlibtest_la_LDFLAGS = $(TESTLIBFLAGS)
libshlibtest_la_SOURCES = shlibtest.cpp
+tmodule_LTLIBRARIES += test_store.la
+test_store_la_SOURCES = test_store.cpp
+test_store_la_LIBADD = $(lib_broker)
+test_store_la_LDFLAGS = -module
+
include cluster.mk
+if SSL
+include ssl.mk
+endif
+
+# receiver, sender are installed and therefore built as part of make, not make check
+qpidtest_PROGRAMS += receiver
+receiver_SOURCES = \
+ receiver.cpp \
+ TestOptions.h \
+ ConnectionOptions.h
+receiver_LDADD = $(lib_client)
+
+qpidtest_PROGRAMS += sender
+sender_SOURCES = \
+ sender.cpp \
+ TestOptions.h \
+ ConnectionOptions.h
+sender_LDADD = $(lib_client)
#
# Other test programs
#
check_PROGRAMS+=perftest
perftest_SOURCES=perftest.cpp test_tools.h TestOptions.h ConnectionOptions.h
+perftest_INCLUDES=$(PUBLIC_INCLUDES)
perftest_LDADD=$(lib_client)
check_PROGRAMS+=txtest
+txtest_INCLUDES=$(PUBLIC_INCLUDES)
txtest_SOURCES=txtest.cpp TestOptions.h ConnectionOptions.h
txtest_LDADD=$(lib_client)
check_PROGRAMS+=latencytest
+latencytest_INCLUDES=$(PUBLIC_INCLUDES)
latencytest_SOURCES=latencytest.cpp TestOptions.h ConnectionOptions.h
latencytest_LDADD=$(lib_client)
+check_PROGRAMS+=echotest
+echotest_INCLUDES=$(PUBLIC_INCLUDES)
+echotest_SOURCES=echotest.cpp TestOptions.h ConnectionOptions.h
+echotest_LDADD=$(lib_client)
+
check_PROGRAMS+=client_test
+client_test_INCLUDES=$(PUBLIC_INCLUDES)
client_test_SOURCES=client_test.cpp TestOptions.h ConnectionOptions.h
client_test_LDADD=$(lib_client)
check_PROGRAMS+=topic_listener
+topic_listener_INCLUDES=$(PUBLIC_INCLUDES)
topic_listener_SOURCES=topic_listener.cpp TestOptions.h ConnectionOptions.h
topic_listener_LDADD=$(lib_client)
check_PROGRAMS+=topic_publisher
+topic_publisher_INCLUDES=$(PUBLIC_INCLUDES)
topic_publisher_SOURCES=topic_publisher.cpp TestOptions.h ConnectionOptions.h
topic_publisher_LDADD=$(lib_client)
check_PROGRAMS+=publish
+publish_INCLUDES=$(PUBLIC_INCLUDES)
publish_SOURCES=publish.cpp TestOptions.h ConnectionOptions.h
publish_LDADD=$(lib_client)
check_PROGRAMS+=consume
+consume_INCLUDES=$(PUBLIC_INCLUDES)
consume_SOURCES=consume.cpp TestOptions.h ConnectionOptions.h
consume_LDADD=$(lib_client)
-TESTS_ENVIRONMENT = VALGRIND=$(VALGRIND) srcdir=$(srcdir) QPID_DATA_DIR= $(srcdir)/run_test
+check_PROGRAMS+=header_test
+header_test_INCLUDES=$(PUBLIC_INCLUDES)
+header_test_SOURCES=header_test.cpp TestOptions.h ConnectionOptions.h
+header_test_LDADD=$(lib_client)
+
+check_PROGRAMS+=failover_soak
+failover_soak_INCLUDES=$(PUBLIC_INCLUDES)
+failover_soak_SOURCES=failover_soak.cpp ForkedBroker.h ForkedBroker.cpp
+failover_soak_LDADD=$(lib_client) $(lib_broker)
+
+check_PROGRAMS+=declare_queues
+declare_queues_INCLUDES=$(PUBLIC_INCLUDES)
+declare_queues_SOURCES=declare_queues.cpp
+declare_queues_LDADD=$(lib_client)
+
+check_PROGRAMS+=replaying_sender
+replaying_sender_INCLUDES=$(PUBLIC_INCLUDES)
+replaying_sender_SOURCES=replaying_sender.cpp
+replaying_sender_LDADD=$(lib_client)
+
+check_PROGRAMS+=resuming_receiver
+resuming_receiver_INCLUDES=$(PUBLIC_INCLUDES)
+resuming_receiver_SOURCES=resuming_receiver.cpp
+resuming_receiver_LDADD=$(lib_client)
+
+check_PROGRAMS+=txshift
+txshift_INCLUDES=$(PUBLIC_INCLUDES)
+txshift_SOURCES=txshift.cpp TestOptions.h ConnectionOptions.h
+txshift_LDADD=$(lib_client)
-system_tests = client_test quick_perftest quick_topictest
-TESTS += start_broker $(system_tests) python_tests stop_broker run_federation_tests
+check_PROGRAMS+=txjob
+txjob_INCLUDES=$(PUBLIC_INCLUDES)
+txjob_SOURCES=txjob.cpp TestOptions.h ConnectionOptions.h
+txjob_LDADD=$(lib_client)
+
+check_PROGRAMS+=PollerTest
+PollerTest_SOURCES=PollerTest.cpp
+PollerTest_LDADD=$(lib_common) $(SOCKLIBS)
+
+check_PROGRAMS+=DispatcherTest
+DispatcherTest_SOURCES=DispatcherTest.cpp
+DispatcherTest_LDADD=$(lib_common) $(SOCKLIBS)
+
+check_PROGRAMS+=qpid_ping
+qpid_ping_INCLUDES=$(PUBLIC_INCLUDES)
+qpid_ping_SOURCES=qpid_ping.cpp test_tools.h TestOptions.h ConnectionOptions.h
+qpid_ping_LDADD=$(lib_client)
+
+check_PROGRAMS+=datagen
+datagen_SOURCES=datagen.cpp
+datagen_LDADD=$(lib_common)
+
+check_PROGRAMS+=qrsh_server
+qrsh_server_SOURCES=qrsh_server.cpp
+qrsh_server_LDADD=$(lib_client)
+
+check_PROGRAMS+=qrsh_run
+qrsh_run_SOURCES=qrsh_run.cpp
+qrsh_run_LDADD=$(lib_client)
+
+check_PROGRAMS+=qrsh
+qrsh_SOURCES=qrsh.cpp
+qrsh_LDADD=$(lib_client)
+
+check_PROGRAMS+=qpid_stream
+qpid_stream_INCLUDES=$(PUBLIC_INCLUDES)
+qpid_stream_SOURCES=qpid_stream.cpp
+qpid_stream_LDADD=$(lib_client)
+
+TESTS_ENVIRONMENT = \
+ VALGRIND=$(VALGRIND) \
+ LIBTOOL="$(LIBTOOL)" \
+ QPID_DATA_DIR= \
+ BOOST_TEST_SHOW_PROGRESS=yes \
+ $(srcdir)/run_test
+
+system_tests = client_test quick_perftest quick_topictest run_header_test quick_txtest
+TESTS += start_broker $(system_tests) python_tests stop_broker run_federation_tests run_acl_tests run_cli_tests replication_test
EXTRA_DIST += \
run_test vg_check \
run-unit-tests start_broker python_tests stop_broker \
quick_topictest \
quick_perftest \
+ quick_txtest \
topictest \
+ run_header_test \
+ header_test.py \
+ ssl_test \
+ config.null \
+ ais_check \
run_federation_tests \
+ run_cli_tests \
+ run_acl_tests \
.valgrind.supp \
MessageUtils.h \
TestMessageStore.h \
- MockConnectionInputHandler.h \
TxMocks.h \
- start_cluster stop_cluster restart_cluster
+ replication_test \
+ run_perftest \
+ ring_queue_test \
+ run_ring_queue_test \
+ cluster.cmake
check_LTLIBRARIES += libdlclose_noop.la
libdlclose_noop_la_LDFLAGS = -module -rpath $(abs_builddir)
libdlclose_noop_la_SOURCES = dlclose_noop.c
-CLEANFILES+=valgrind.out *.log *.vglog* dummy_test $(unit_wrappers)
+CLEANFILES+=valgrind.out *.log *.vglog* dummy_test qpidd.port $(unit_wrappers)
-# FIXME aconway 2008-05-23: Disabled interop_runner because it uses
-# the obsolete Channel class. Convert to Session and re-enable.
-#
-# check_PROGRAMS += interop_runner
+# Longer running stability tests, not run by default check: target.
+# Not run under valgrind, too slow
-# interop_runner_SOURCES = \
-# interop_runner.cpp \
-# SimpleTestCaseBase.cpp \
-# BasicP2PTest.cpp \
-# BasicPubSubTest.cpp \
-# SimpleTestCaseBase.h \
-# BasicP2PTest.h \
-# BasicPubSubTest.h \
-# TestCase.h \
-# TestOptions.h ConnectionOptions.h
-# interop_runner_LDADD = $(lib_client) $(lib_common) $(extra_libs)
+LONG_TESTS+=start_broker fanout_perftest shared_perftest multiq_perftest topic_perftest run_ring_queue_test stop_broker \
+ run_failover_soak reliable_replication_test \
+ federated_cluster_test_with_node_failure
+EXTRA_DIST+= \
+ CMakeLists.txt \
+ fanout_perftest \
+ shared_perftest \
+ multiq_perftest \
+ topic_perftest \
+ run_failover_soak \
+ reliable_replication_test \
+ federated_cluster_test_with_node_failure \
+ windows/DisableWin32ErrorWindows.cpp
-# Longer running stability tests, not run by default check: target.
-# Not run under valgrind, too slow
-LONG_TESTS=fanout_perftest shared_perftest multiq_perftest topic_perftest
-EXTRA_DIST+=$(LONG_TESTS) run_perftest
check-long:
- $(MAKE) check TESTS="start_broker $(LONG_TESTS) stop_broker" VALGRIND=
+ $(MAKE) check TESTS="$(LONG_TESTS)" VALGRIND=
+
+check: python_prep
+
+PYTHON_SRC_DIR=$(abs_srcdir)/../../../python
+PYTHON_BLD_DIR=$(abs_builddir)/python
+AMQP_SPEC_DIR=$(abs_srcdir)/../../../specs
+
+# Generate python client as part of the all-am target so it gets built before tests.
+all-am: python_prep
+
+python_prep:
+ if test -d $(PYTHON_SRC_DIR) -a -d $(AMQP_SPEC_DIR); \
+ then $(MAKE) -C $(PYTHON_SRC_DIR) install PREFIX=$(PYTHON_BLD_DIR) PYTHON_LIB=$(PYTHON_BLD_DIR) EXEC_PREFIX=$(PYTHON_BLD_DIR)/commands AMQP_SPEC_DIR=$(AMQP_SPEC_DIR); \
+ else echo "WARNING: python client not built, missing one of $(PYTHON_SRC_DIR) $(AMQP_SPEC_DIR)"; fi
+
diff --git a/cpp/src/tests/ManagementTest.cpp b/cpp/src/tests/ManagementTest.cpp
new file mode 100644
index 0000000000..d05b4676ba
--- /dev/null
+++ b/cpp/src/tests/ManagementTest.cpp
@@ -0,0 +1,115 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/management/ManagementObject.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/console/ObjectId.h"
+#include "unit_test.h"
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(ManagementTestSuite)
+
+using namespace qpid::framing;
+using namespace qpid::management;
+
+QPID_AUTO_TEST_CASE(testObjectIdSerializeStream) {
+ std::string text("0-10-4-2500-80000000000");
+ std::stringstream input(text);
+
+ ObjectId oid(input);
+
+ std::stringstream output;
+ output << oid;
+
+ BOOST_CHECK_EQUAL(text, output.str());
+}
+
+QPID_AUTO_TEST_CASE(testObjectIdSerializeString) {
+ std::string text("0-10-4-2500-80000000000");
+
+ ObjectId oid(text);
+
+ std::stringstream output;
+ output << oid;
+
+ BOOST_CHECK_EQUAL(text, output.str());
+}
+
+QPID_AUTO_TEST_CASE(testObjectIdEncode) {
+ char buffer[100];
+ Buffer msgBuf(buffer, 100);
+ msgBuf.putLongLong(0x1002000030000004LL);
+ msgBuf.putLongLong(0x0000000000000005LL);
+ msgBuf.reset();
+
+ ObjectId oid(msgBuf);
+
+ std::stringstream out1;
+ out1 << oid;
+
+ BOOST_CHECK_EQUAL(out1.str(), "1-2-3-4-5");
+}
+
+QPID_AUTO_TEST_CASE(testObjectIdAttach) {
+ AgentAttachment agent;
+ ObjectId oid(&agent, 10, 20, 50);
+
+ std::stringstream out1;
+ out1 << oid;
+ BOOST_CHECK_EQUAL(out1.str(), "10-20-0-0-50");
+
+ agent.setBanks(30, 40);
+ std::stringstream out2;
+ out2 << oid;
+ BOOST_CHECK_EQUAL(out2.str(), "10-20-30-40-50");
+}
+
+QPID_AUTO_TEST_CASE(testConsoleObjectId) {
+ qpid::console::ObjectId oid1, oid2;
+
+ oid1.setValue(1, 2);
+ oid2.setValue(3, 4);
+
+ BOOST_CHECK(oid1 < oid2);
+ BOOST_CHECK(oid1 <= oid2);
+ BOOST_CHECK(oid2 > oid1);
+ BOOST_CHECK(oid2 >= oid1);
+ BOOST_CHECK(oid1 != oid2);
+ BOOST_CHECK(oid1 == oid1);
+
+ oid1.setValue(3, 6);
+ oid2.setValue(3, 4);
+
+ BOOST_CHECK(oid1 > oid2);
+ BOOST_CHECK(oid1 >= oid2);
+ BOOST_CHECK(oid2 < oid1);
+ BOOST_CHECK(oid2 <= oid1);
+ BOOST_CHECK(oid1 != oid2);
+
+ oid2.setValue(3, 6);
+ BOOST_CHECK(oid1 == oid2);
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/MessageBuilderTest.cpp b/cpp/src/tests/MessageBuilderTest.cpp
index 63c3a800de..c2fb8ad32e 100644
--- a/cpp/src/tests/MessageBuilderTest.cpp
+++ b/cpp/src/tests/MessageBuilderTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -27,20 +27,22 @@
#include "unit_test.h"
#include <list>
-using namespace boost;
using namespace qpid::broker;
using namespace qpid::framing;
using namespace qpid::sys;
+namespace qpid {
+namespace tests {
+
class MockMessageStore : public NullMessageStore
{
enum Op {STAGE=1, APPEND=2};
uint64_t id;
- intrusive_ptr<PersistableMessage> expectedMsg;
+ boost::intrusive_ptr<PersistableMessage> expectedMsg;
string expectedData;
std::list<Op> ops;
-
+
void checkExpectation(Op actual)
{
BOOST_CHECK_EQUAL(ops.front(), actual);
@@ -50,40 +52,47 @@ class MockMessageStore : public NullMessageStore
public:
MockMessageStore() : id(0), expectedMsg(0) {}
- void expectStage(PersistableMessage& msg)
- {
+ void expectStage(PersistableMessage& msg)
+ {
expectedMsg = &msg;
- ops.push_back(STAGE);
+ ops.push_back(STAGE);
}
- void expectAppendContent(PersistableMessage& msg, const string& data)
- {
+ void expectAppendContent(PersistableMessage& msg, const string& data)
+ {
expectedMsg = &msg;
expectedData = data;
- ops.push_back(APPEND);
+ ops.push_back(APPEND);
}
- void stage(const intrusive_ptr<PersistableMessage>& msg)
+ void stage(const boost::intrusive_ptr<PersistableMessage>& msg)
{
checkExpectation(STAGE);
BOOST_CHECK_EQUAL(expectedMsg, msg);
msg->setPersistenceId(++id);
}
- void appendContent(const intrusive_ptr<const PersistableMessage>& msg,
+ void appendContent(const boost::intrusive_ptr<const PersistableMessage>& msg,
const string& data)
{
checkExpectation(APPEND);
- BOOST_CHECK_EQUAL(static_pointer_cast<const PersistableMessage>(expectedMsg), msg);
- BOOST_CHECK_EQUAL(expectedData, data);
+ BOOST_CHECK_EQUAL(boost::static_pointer_cast<const PersistableMessage>(expectedMsg), msg);
+ BOOST_CHECK_EQUAL(expectedData, data);
}
bool expectationsMet()
{
return ops.empty();
}
+
+ //don't treat this store as a null impl
+ bool isNull() const
+ {
+ return false;
+ }
+
};
-
+
QPID_AUTO_TEST_SUITE(MessageBuilderTestSuite)
QPID_AUTO_TEST_CASE(testHeaderOnly)
@@ -94,11 +103,10 @@ QPID_AUTO_TEST_CASE(testHeaderOnly)
std::string exchange("builder-exchange");
std::string key("builder-exchange");
- AMQFrame method(in_place<MessageTransferBody>(
- ProtocolVersion(), exchange, 0, 0));
- AMQFrame header(in_place<AMQHeaderBody>());
+ AMQFrame method((MessageTransferBody(ProtocolVersion(), exchange, 0, 0)));
+ AMQFrame header((AMQHeaderBody()));
- header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(0);
+ header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(0);
header.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setRoutingKey(key);
builder.handle(method);
@@ -119,15 +127,15 @@ QPID_AUTO_TEST_CASE(test1ContentFrame)
std::string exchange("builder-exchange");
std::string key("builder-exchange");
- AMQFrame method(in_place<MessageTransferBody>(ProtocolVersion(), exchange, 0, 0));
- AMQFrame header(in_place<AMQHeaderBody>());
- AMQFrame content(in_place<AMQContentBody>(data));
+ AMQFrame method((MessageTransferBody(ProtocolVersion(), exchange, 0, 0)));
+ AMQFrame header((AMQHeaderBody()));
+ AMQFrame content((AMQContentBody(data)));
method.setEof(false);
header.setBof(false);
header.setEof(false);
content.setBof(false);
- header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data.size());
+ header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data.size());
header.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setRoutingKey(key);
builder.handle(method);
@@ -138,7 +146,7 @@ QPID_AUTO_TEST_CASE(test1ContentFrame)
BOOST_CHECK(builder.getMessage());
BOOST_CHECK(!builder.getMessage()->getFrames().isComplete());
- builder.handle(content);
+ builder.handle(content);
BOOST_CHECK(builder.getMessage());
BOOST_CHECK(builder.getMessage()->getFrames().isComplete());
}
@@ -153,11 +161,10 @@ QPID_AUTO_TEST_CASE(test2ContentFrames)
std::string exchange("builder-exchange");
std::string key("builder-exchange");
- AMQFrame method(in_place<MessageTransferBody>(
- ProtocolVersion(), exchange, 0, 0));
- AMQFrame header(in_place<AMQHeaderBody>());
- AMQFrame content1(in_place<AMQContentBody>(data1));
- AMQFrame content2(in_place<AMQContentBody>(data2));
+ AMQFrame method((MessageTransferBody(ProtocolVersion(), exchange, 0, 0)));
+ AMQFrame header((AMQHeaderBody()));
+ AMQFrame content1((AMQContentBody(data1)));
+ AMQFrame content2((AMQContentBody(data2)));
method.setEof(false);
header.setBof(false);
header.setEof(false);
@@ -165,7 +172,7 @@ QPID_AUTO_TEST_CASE(test2ContentFrames)
content1.setEof(false);
content2.setBof(false);
- header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data1.size() + data2.size());
+ header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data1.size() + data2.size());
header.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setRoutingKey(key);
builder.handle(method);
@@ -184,19 +191,18 @@ QPID_AUTO_TEST_CASE(testStaging)
MockMessageStore store;
MessageBuilder builder(&store, 5);
builder.start(SequenceNumber());
-
+
std::string data1("abcdefg");
std::string data2("hijklmn");
std::string exchange("builder-exchange");
std::string key("builder-exchange");
- AMQFrame method(in_place<MessageTransferBody>(
- ProtocolVersion(), exchange, 0, 0));
- AMQFrame header(in_place<AMQHeaderBody>());
- AMQFrame content1(in_place<AMQContentBody>(data1));
- AMQFrame content2(in_place<AMQContentBody>(data2));
+ AMQFrame method(MessageTransferBody(ProtocolVersion(), exchange, 0, 0));
+ AMQFrame header((AMQHeaderBody()));
+ AMQFrame content1((AMQContentBody(data1)));
+ AMQFrame content2((AMQContentBody(data2)));
- header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data1.size() + data2.size());
+ header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data1.size() + data2.size());
header.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setRoutingKey(key);
builder.handle(method);
@@ -214,4 +220,32 @@ QPID_AUTO_TEST_CASE(testStaging)
BOOST_CHECK(!builder.getMessage()->isContentLoaded());
}
+QPID_AUTO_TEST_CASE(testNoManagementStaging)
+{
+ // Make sure management messages don't stage
+ MockMessageStore store;
+ MessageBuilder builder(&store, 5);
+ builder.start(SequenceNumber());
+
+ std::string data1("abcdefg");
+ std::string exchange("qpid.management");
+ std::string key("builder-exchange");
+
+ AMQFrame method(MessageTransferBody(ProtocolVersion(), exchange, 0, 0));
+ AMQFrame header((AMQHeaderBody()));
+ AMQFrame content1((AMQContentBody(data1)));
+
+ header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data1.size());
+ header.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setRoutingKey(key);
+
+ builder.handle(method);
+ builder.handle(header);
+
+ builder.handle(content1);
+ BOOST_CHECK(store.expectationsMet());
+ BOOST_CHECK_EQUAL((uint64_t) 0, builder.getMessage()->getPersistenceId());
+}
+
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/MessageReplayTracker.cpp b/cpp/src/tests/MessageReplayTracker.cpp
new file mode 100644
index 0000000000..3d79ee53c2
--- /dev/null
+++ b/cpp/src/tests/MessageReplayTracker.cpp
@@ -0,0 +1,102 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "unit_test.h"
+#include "BrokerFixture.h"
+#include "qpid/client/MessageReplayTracker.h"
+#include "qpid/sys/Time.h"
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(MessageReplayTrackerTests)
+
+using namespace qpid::client;
+using namespace qpid::sys;
+using std::string;
+
+class ReplayBufferChecker
+{
+ public:
+
+ ReplayBufferChecker(uint from, uint to) : end(to), i(from) {}
+
+ void operator()(const Message& m)
+ {
+ if (i > end) BOOST_FAIL("Extra message found: " + m.getData());
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i++)).str(), m.getData());
+ }
+ private:
+ const uint end;
+ uint i;
+
+};
+
+QPID_AUTO_TEST_CASE(testReplay)
+{
+ ProxySessionFixture fix;
+ fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true);
+
+ MessageReplayTracker tracker(10);
+ tracker.init(fix.session);
+ for (uint i = 0; i < 5; i++) {
+ Message message((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ tracker.send(message);
+ }
+ ReplayBufferChecker checker(1, 10);
+ tracker.foreach(checker);
+
+ tracker.replay(fix.session);
+ for (uint j = 0; j < 2; j++) {//each message should have been sent twice
+ for (uint i = 0; i < 5; i++) {
+ Message m;
+ BOOST_CHECK(fix.subs.get(m, "my-queue", TIME_SEC));
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), m.getData());
+ }
+ }
+ Message m;
+ BOOST_CHECK(!fix.subs.get(m, "my-queue"));
+}
+
+QPID_AUTO_TEST_CASE(testCheckCompletion)
+{
+ ProxySessionFixture fix;
+ fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true);
+
+ MessageReplayTracker tracker(10);
+ tracker.init(fix.session);
+ for (uint i = 0; i < 5; i++) {
+ Message message((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ tracker.send(message);
+ }
+ fix.session.sync();//ensures all messages are complete
+ tracker.checkCompletion();
+ tracker.replay(fix.session);
+ Message received;
+ for (uint i = 0; i < 5; i++) {
+ BOOST_CHECK(fix.subs.get(received, "my-queue"));
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), received.getData());
+ }
+ BOOST_CHECK(!fix.subs.get(received, "my-queue"));
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/MessageTest.cpp b/cpp/src/tests/MessageTest.cpp
index b5c1648caf..7d67c92b37 100644
--- a/cpp/src/tests/MessageTest.cpp
+++ b/cpp/src/tests/MessageTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -24,16 +24,18 @@
#include "qpid/framing/MessageTransferBody.h"
#include "qpid/framing/FieldValue.h"
#include "qpid/framing/Uuid.h"
+#include "qpid/sys/alloca.h"
#include "unit_test.h"
#include <iostream>
-#include <alloca.h>
-using namespace boost;
using namespace qpid::broker;
using namespace qpid::framing;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(MessageTestSuite)
QPID_AUTO_TEST_CASE(testEncodeDecode)
@@ -44,13 +46,12 @@ QPID_AUTO_TEST_CASE(testEncodeDecode)
string data1("abcdefg");
string data2("hijklmn");
- intrusive_ptr<Message> msg(new Message());
+ boost::intrusive_ptr<Message> msg(new Message());
- AMQFrame method(in_place<MessageTransferBody>(
- ProtocolVersion(), exchange, 0, 0));
- AMQFrame header(in_place<AMQHeaderBody>());
- AMQFrame content1(in_place<AMQContentBody>(data1));
- AMQFrame content2(in_place<AMQContentBody>(data2));
+ AMQFrame method((MessageTransferBody(ProtocolVersion(), exchange, 0, 0)));
+ AMQFrame header((AMQHeaderBody()));
+ AMQFrame content1((AMQContentBody(data1)));
+ AMQFrame content2((AMQContentBody(data2)));
msg->getFrames().append(method);
msg->getFrames().append(header);
@@ -58,7 +59,7 @@ QPID_AUTO_TEST_CASE(testEncodeDecode)
msg->getFrames().append(content2);
MessageProperties* mProps = msg->getFrames().getHeaders()->get<MessageProperties>(true);
- mProps->setContentLength(data1.size() + data2.size());
+ mProps->setContentLength(data1.size() + data2.size());
mProps->setMessageId(messageId);
FieldTable applicationHeaders;
applicationHeaders.setString("abc", "xyz");
@@ -71,7 +72,7 @@ QPID_AUTO_TEST_CASE(testEncodeDecode)
char* buff = static_cast<char*>(::alloca(msg->encodedSize()));
Buffer wbuffer(buff, msg->encodedSize());
msg->encode(wbuffer);
-
+
Buffer rbuffer(buff, msg->encodedSize());
msg = new Message();
msg->decodeHeader(rbuffer);
@@ -81,10 +82,11 @@ QPID_AUTO_TEST_CASE(testEncodeDecode)
BOOST_CHECK_EQUAL((uint64_t) data1.size() + data2.size(), msg->contentSize());
BOOST_CHECK_EQUAL((uint64_t) data1.size() + data2.size(), msg->getProperties<MessageProperties>()->getContentLength());
BOOST_CHECK_EQUAL(messageId, msg->getProperties<MessageProperties>()->getMessageId());
- BOOST_CHECK_EQUAL(string("xyz"), msg->getProperties<MessageProperties>()->getApplicationHeaders().getString("abc"));
+ BOOST_CHECK_EQUAL(string("xyz"), msg->getProperties<MessageProperties>()->getApplicationHeaders().getAsString("abc"));
BOOST_CHECK_EQUAL((uint8_t) PERSISTENT, msg->getProperties<DeliveryProperties>()->getDeliveryMode());
BOOST_CHECK(msg->isPersistent());
}
QPID_AUTO_TEST_SUITE_END()
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/MessageUtils.h b/cpp/src/tests/MessageUtils.h
index 21ee834ba7..a1b140d484 100644
--- a/cpp/src/tests/MessageUtils.h
+++ b/cpp/src/tests/MessageUtils.h
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -20,7 +20,6 @@
*/
#include "qpid/broker/Message.h"
-#include "qpid/broker/MessageDelivery.h"
#include "qpid/framing/AMQFrame.h"
#include "qpid/framing/MessageTransferBody.h"
#include "qpid/framing/Uuid.h"
@@ -29,28 +28,36 @@ using namespace qpid;
using namespace broker;
using namespace framing;
+namespace qpid {
+namespace tests {
+
struct MessageUtils
{
- static boost::intrusive_ptr<Message> createMessage(const string& exchange="", const string& routingKey="",
- const Uuid& messageId=Uuid(true), uint64_t contentSize = 0)
+ static boost::intrusive_ptr<Message> createMessage(const string& exchange="", const string& routingKey="",
+ const bool durable = false, const Uuid& messageId=Uuid(true),
+ uint64_t contentSize = 0)
{
- boost::intrusive_ptr<Message> msg(new Message());
+ boost::intrusive_ptr<broker::Message> msg(new broker::Message());
- AMQFrame method(in_place<MessageTransferBody>(ProtocolVersion(), exchange, 0, 0));
- AMQFrame header(in_place<AMQHeaderBody>());
+ AMQFrame method(( MessageTransferBody(ProtocolVersion(), exchange, 0, 0)));
+ AMQFrame header((AMQHeaderBody()));
msg->getFrames().append(method);
msg->getFrames().append(header);
MessageProperties* props = msg->getFrames().getHeaders()->get<MessageProperties>(true);
- props->setContentLength(contentSize);
+ props->setContentLength(contentSize);
props->setMessageId(messageId);
msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(routingKey);
+ if (durable)
+ msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setDeliveryMode(2);
return msg;
}
static void addContent(boost::intrusive_ptr<Message> msg, const string& data)
{
- AMQFrame content(in_place<AMQContentBody>(data));
+ AMQFrame content((AMQContentBody(data)));
msg->getFrames().append(content);
}
};
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/MessagingSessionTests.cpp b/cpp/src/tests/MessagingSessionTests.cpp
new file mode 100644
index 0000000000..4125c51698
--- /dev/null
+++ b/cpp/src/tests/MessagingSessionTests.cpp
@@ -0,0 +1,778 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "unit_test.h"
+#include "test_tools.h"
+#include "BrokerFixture.h"
+#include "qpid/messaging/Address.h"
+#include "qpid/messaging/Connection.h"
+#include "qpid/messaging/ListContent.h"
+#include "qpid/messaging/ListView.h"
+#include "qpid/messaging/MapContent.h"
+#include "qpid/messaging/MapView.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/Receiver.h"
+#include "qpid/messaging/Sender.h"
+#include "qpid/messaging/Session.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Session.h"
+#include "qpid/framing/ExchangeQueryResult.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/sys/Time.h"
+#include <boost/assign.hpp>
+#include <boost/format.hpp>
+#include <string>
+#include <vector>
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(MessagingSessionTests)
+
+using namespace qpid::messaging;
+using namespace qpid;
+using qpid::broker::Broker;
+using qpid::framing::Uuid;
+
+struct BrokerAdmin
+{
+ qpid::client::Connection connection;
+ qpid::client::Session session;
+
+ BrokerAdmin(uint16_t port)
+ {
+ connection.open("localhost", port);
+ session = connection.newSession();
+ }
+
+ void createQueue(const std::string& name)
+ {
+ session.queueDeclare(qpid::client::arg::queue=name);
+ }
+
+ void deleteQueue(const std::string& name)
+ {
+ session.queueDelete(qpid::client::arg::queue=name);
+ }
+
+ void createExchange(const std::string& name, const std::string& type)
+ {
+ session.exchangeDeclare(qpid::client::arg::exchange=name, qpid::client::arg::type=type);
+ }
+
+ void deleteExchange(const std::string& name)
+ {
+ session.exchangeDelete(qpid::client::arg::exchange=name);
+ }
+
+ bool checkQueueExists(const std::string& name)
+ {
+ return session.queueQuery(name).getQueue() == name;
+ }
+
+ bool checkExchangeExists(const std::string& name, std::string& type)
+ {
+ qpid::framing::ExchangeQueryResult result = session.exchangeQuery(name);
+ type = result.getType();
+ return !result.getNotFound();
+ }
+
+ ~BrokerAdmin()
+ {
+ session.close();
+ connection.close();
+ }
+};
+
+struct MessagingFixture : public BrokerFixture
+{
+ Connection connection;
+ Session session;
+ BrokerAdmin admin;
+
+ MessagingFixture(Broker::Options opts = Broker::Options()) :
+ BrokerFixture(opts),
+ connection(Connection::open((boost::format("amqp:tcp:localhost:%1%") % (broker->getPort(Broker::TCP_TRANSPORT))).str())),
+ session(connection.newSession()),
+ admin(broker->getPort(Broker::TCP_TRANSPORT)) {}
+
+ void ping(const qpid::messaging::Address& address)
+ {
+ Receiver r = session.createReceiver(address);
+ Sender s = session.createSender(address);
+ Message out(Uuid(true).str());
+ s.send(out);
+ Message in;
+ BOOST_CHECK(r.fetch(in, 5*qpid::sys::TIME_SEC));
+ BOOST_CHECK_EQUAL(out.getContent(), in.getContent());
+ r.cancel();
+ s.cancel();
+ }
+
+ ~MessagingFixture()
+ {
+ session.close();
+ connection.close();
+ }
+};
+
+struct QueueFixture : MessagingFixture
+{
+ std::string queue;
+
+ QueueFixture(const std::string& name = "test-queue") : queue(name)
+ {
+ admin.createQueue(queue);
+ }
+
+ ~QueueFixture()
+ {
+ admin.deleteQueue(queue);
+ }
+
+};
+
+struct TopicFixture : MessagingFixture
+{
+ std::string topic;
+
+ TopicFixture(const std::string& name = "test-topic", const std::string& type="fanout") : topic(name)
+ {
+ admin.createExchange(topic, type);
+ }
+
+ ~TopicFixture()
+ {
+ admin.deleteExchange(topic);
+ }
+
+};
+
+struct MultiQueueFixture : MessagingFixture
+{
+ typedef std::vector<std::string>::const_iterator const_iterator;
+ std::vector<std::string> queues;
+
+ MultiQueueFixture(const std::vector<std::string>& names = boost::assign::list_of<std::string>("q1")("q2")("q3")) : queues(names)
+ {
+ for (const_iterator i = queues.begin(); i != queues.end(); ++i) {
+ admin.createQueue(*i);
+ }
+ }
+
+ ~MultiQueueFixture()
+ {
+ for (const_iterator i = queues.begin(); i != queues.end(); ++i) {
+ admin.deleteQueue(*i);
+ }
+ }
+
+};
+std::vector<std::string> fetch(Receiver& receiver, int count, qpid::sys::Duration timeout=qpid::sys::TIME_SEC*5)
+{
+ std::vector<std::string> data;
+ Message message;
+ for (int i = 0; i < count && receiver.fetch(message, timeout); i++) {
+ data.push_back(message.getContent());
+ }
+ return data;
+}
+
+
+void send(Sender& sender, uint count = 1, uint start = 1, const std::string& base = "Message")
+{
+ for (uint i = start; i < start + count; ++i) {
+ sender.send(Message((boost::format("%1%_%2%") % base % i).str()));
+ }
+}
+
+void receive(Receiver& receiver, uint count = 1, uint start = 1,
+ const std::string& base = "Message", qpid::sys::Duration timeout=qpid::sys::TIME_SEC*5)
+{
+ for (uint i = start; i < start + count; ++i) {
+ BOOST_CHECK_EQUAL(receiver.fetch(timeout).getContent(), (boost::format("%1%_%2%") % base % i).str());
+ }
+}
+
+QPID_AUTO_TEST_CASE(testSimpleSendReceive)
+{
+ QueueFixture fix;
+ Sender sender = fix.session.createSender(fix.queue);
+ Message out("test-message");
+ sender.send(out);
+ Receiver receiver = fix.session.createReceiver(fix.queue);
+ Message in = receiver.fetch(5 * qpid::sys::TIME_SEC);
+ fix.session.acknowledge();
+ BOOST_CHECK_EQUAL(in.getContent(), out.getContent());
+}
+
+QPID_AUTO_TEST_CASE(testSendReceiveHeaders)
+{
+ QueueFixture fix;
+ Sender sender = fix.session.createSender(fix.queue);
+ Message out("test-message");
+ for (uint i = 0; i < 10; ++i) {
+ out.getHeaders()["a"] = i;
+ sender.send(out);
+ }
+ Receiver receiver = fix.session.createReceiver(fix.queue);
+ Message in;
+ for (uint i = 0; i < 10; ++i) {
+ BOOST_CHECK(receiver.fetch(in, 5 * qpid::sys::TIME_SEC));
+ BOOST_CHECK_EQUAL(in.getContent(), out.getContent());
+ BOOST_CHECK_EQUAL(in.getHeaders()["a"].asUint32(), i);
+ fix.session.acknowledge();
+ }
+}
+
+QPID_AUTO_TEST_CASE(testSenderError)
+{
+ MessagingFixture fix;
+ ScopedSuppressLogging sl;
+ BOOST_CHECK_THROW(fix.session.createSender("NonExistentAddress"), qpid::messaging::InvalidAddress);
+ fix.session = fix.connection.newSession();
+ BOOST_CHECK_THROW(fix.session.createSender("NonExistentAddress; {create:receiver}"),
+ qpid::messaging::InvalidAddress);
+}
+
+QPID_AUTO_TEST_CASE(testReceiverError)
+{
+ MessagingFixture fix;
+ ScopedSuppressLogging sl;
+ BOOST_CHECK_THROW(fix.session.createReceiver("NonExistentAddress"), qpid::messaging::InvalidAddress);
+ fix.session = fix.connection.newSession();
+ BOOST_CHECK_THROW(fix.session.createReceiver("NonExistentAddress; {create:sender}"),
+ qpid::messaging::InvalidAddress);
+}
+
+QPID_AUTO_TEST_CASE(testSimpleTopic)
+{
+ TopicFixture fix;
+
+ Sender sender = fix.session.createSender(fix.topic);
+ Message msg("one");
+ sender.send(msg);
+ Receiver sub1 = fix.session.createReceiver(fix.topic);
+ sub1.setCapacity(10u);
+ msg.setContent("two");
+ sender.send(msg);
+ Receiver sub2 = fix.session.createReceiver(fix.topic);
+ sub2.setCapacity(10u);
+ msg.setContent("three");
+ sender.send(msg);
+ Receiver sub3 = fix.session.createReceiver(fix.topic);
+ sub3.setCapacity(10u);
+ msg.setContent("four");
+ sender.send(msg);
+ BOOST_CHECK_EQUAL(fetch(sub2, 2), boost::assign::list_of<std::string>("three")("four"));
+ sub2.cancel();
+
+ msg.setContent("five");
+ sender.send(msg);
+ BOOST_CHECK_EQUAL(fetch(sub1, 4), boost::assign::list_of<std::string>("two")("three")("four")("five"));
+ BOOST_CHECK_EQUAL(fetch(sub3, 2), boost::assign::list_of<std::string>("four")("five"));
+ Message in;
+ BOOST_CHECK(!sub2.fetch(in, 0));//TODO: or should this raise an error?
+
+
+ //TODO: check pending messages...
+}
+
+QPID_AUTO_TEST_CASE(testNextReceiver)
+{
+ MultiQueueFixture fix;
+
+ for (uint i = 0; i < fix.queues.size(); i++) {
+ Receiver r = fix.session.createReceiver(fix.queues[i]);
+ r.setCapacity(10u);
+ }
+
+ for (uint i = 0; i < fix.queues.size(); i++) {
+ Sender s = fix.session.createSender(fix.queues[i]);
+ Message msg((boost::format("Message_%1%") % (i+1)).str());
+ s.send(msg);
+ }
+
+ for (uint i = 0; i < fix.queues.size(); i++) {
+ Message msg;
+ BOOST_CHECK(fix.session.nextReceiver().fetch(msg, qpid::sys::TIME_SEC));
+ BOOST_CHECK_EQUAL(msg.getContent(), (boost::format("Message_%1%") % (i+1)).str());
+ }
+}
+
+QPID_AUTO_TEST_CASE(testMapMessage)
+{
+ QueueFixture fix;
+ Sender sender = fix.session.createSender(fix.queue);
+ Message out;
+ MapContent content(out);
+ content["abc"] = "def";
+ content["pi"] = 3.14f;
+ content.encode();
+ sender.send(out);
+ Receiver receiver = fix.session.createReceiver(fix.queue);
+ Message in = receiver.fetch(5 * qpid::sys::TIME_SEC);
+ MapView view(in);
+ BOOST_CHECK_EQUAL(view["abc"].asString(), "def");
+ BOOST_CHECK_EQUAL(view["pi"].asFloat(), 3.14f);
+ fix.session.acknowledge();
+}
+
+QPID_AUTO_TEST_CASE(testListMessage)
+{
+ QueueFixture fix;
+ Sender sender = fix.session.createSender(fix.queue);
+ Message out;
+ ListContent content(out);
+ content.push_back(Variant("abc"));
+ content.push_back(Variant(1234));
+ content.push_back(Variant("def"));
+ content.push_back(Variant(56.789));
+ content.encode();
+ sender.send(out);
+ Receiver receiver = fix.session.createReceiver(fix.queue);
+ Message in = receiver.fetch(5 * qpid::sys::TIME_SEC);
+ ListView view(in);
+ BOOST_CHECK_EQUAL(view.size(), content.size());
+ BOOST_CHECK_EQUAL(view.front().asString(), "abc");
+ BOOST_CHECK_EQUAL(view.back().asDouble(), 56.789);
+
+ ListView::const_iterator i = view.begin();
+ BOOST_CHECK(i != view.end());
+ BOOST_CHECK_EQUAL(i->asString(), "abc");
+ BOOST_CHECK(++i != view.end());
+ BOOST_CHECK_EQUAL(i->asInt64(), 1234);
+ BOOST_CHECK(++i != view.end());
+ BOOST_CHECK_EQUAL(i->asString(), "def");
+ BOOST_CHECK(++i != view.end());
+ BOOST_CHECK_EQUAL(i->asDouble(), 56.789);
+ BOOST_CHECK(++i == view.end());
+
+ fix.session.acknowledge();
+}
+
+QPID_AUTO_TEST_CASE(testReject)
+{
+ QueueFixture fix;
+ Sender sender = fix.session.createSender(fix.queue);
+ Message m1("reject-me");
+ sender.send(m1);
+ Message m2("accept-me");
+ sender.send(m2);
+ Receiver receiver = fix.session.createReceiver(fix.queue);
+ Message in = receiver.fetch(5 * qpid::sys::TIME_SEC);
+ BOOST_CHECK_EQUAL(in.getContent(), m1.getContent());
+ fix.session.reject(in);
+ in = receiver.fetch(5 * qpid::sys::TIME_SEC);
+ BOOST_CHECK_EQUAL(in.getContent(), m2.getContent());
+ fix.session.acknowledge();
+}
+
+QPID_AUTO_TEST_CASE(testAvailable)
+{
+ MultiQueueFixture fix;
+
+ Receiver r1 = fix.session.createReceiver(fix.queues[0]);
+ r1.setCapacity(100);
+
+ Receiver r2 = fix.session.createReceiver(fix.queues[1]);
+ r2.setCapacity(100);
+
+ Sender s1 = fix.session.createSender(fix.queues[0]);
+ Sender s2 = fix.session.createSender(fix.queues[1]);
+
+ for (uint i = 0; i < 10; ++i) {
+ s1.send(Message((boost::format("A_%1%") % (i+1)).str()));
+ }
+ for (uint i = 0; i < 5; ++i) {
+ s2.send(Message((boost::format("B_%1%") % (i+1)).str()));
+ }
+ qpid::sys::sleep(1);//is there any avoid an arbitrary sleep while waiting for messages to be dispatched?
+ for (uint i = 0; i < 5; ++i) {
+ BOOST_CHECK_EQUAL(fix.session.available(), 15u - 2*i);
+ BOOST_CHECK_EQUAL(r1.available(), 10u - i);
+ BOOST_CHECK_EQUAL(r1.fetch().getContent(), (boost::format("A_%1%") % (i+1)).str());
+ BOOST_CHECK_EQUAL(r2.available(), 5u - i);
+ BOOST_CHECK_EQUAL(r2.fetch().getContent(), (boost::format("B_%1%") % (i+1)).str());
+ fix.session.acknowledge();
+ }
+ for (uint i = 5; i < 10; ++i) {
+ BOOST_CHECK_EQUAL(fix.session.available(), 10u - i);
+ BOOST_CHECK_EQUAL(r1.available(), 10u - i);
+ BOOST_CHECK_EQUAL(r1.fetch().getContent(), (boost::format("A_%1%") % (i+1)).str());
+ }
+}
+
+QPID_AUTO_TEST_CASE(testPendingAck)
+{
+ QueueFixture fix;
+ Sender sender = fix.session.createSender(fix.queue);
+ for (uint i = 0; i < 10; ++i) {
+ sender.send(Message((boost::format("Message_%1%") % (i+1)).str()));
+ }
+ Receiver receiver = fix.session.createReceiver(fix.queue);
+ for (uint i = 0; i < 10; ++i) {
+ BOOST_CHECK_EQUAL(receiver.fetch().getContent(), (boost::format("Message_%1%") % (i+1)).str());
+ }
+ BOOST_CHECK_EQUAL(fix.session.pendingAck(), 0u);
+ fix.session.acknowledge();
+ BOOST_CHECK_EQUAL(fix.session.pendingAck(), 10u);
+ fix.session.sync();
+ BOOST_CHECK_EQUAL(fix.session.pendingAck(), 0u);
+}
+
+QPID_AUTO_TEST_CASE(testPendingSend)
+{
+ QueueFixture fix;
+ Sender sender = fix.session.createSender(fix.queue);
+ send(sender, 10);
+ //Note: this test relies on 'inside knowledge' of the sender
+ //implementation and the fact that the simple test case makes it
+ //possible to predict when completion information will be sent to
+ //the client. TODO: is there a better way of testing this?
+ BOOST_CHECK_EQUAL(sender.pending(), 10u);
+ fix.session.sync();
+ BOOST_CHECK_EQUAL(sender.pending(), 0u);
+
+ Receiver receiver = fix.session.createReceiver(fix.queue);
+ receive(receiver, 10);
+ fix.session.acknowledge();
+}
+
+QPID_AUTO_TEST_CASE(testBrowse)
+{
+ QueueFixture fix;
+ Sender sender = fix.session.createSender(fix.queue);
+ send(sender, 10);
+ Receiver browser1 = fix.session.createReceiver(fix.queue + "; {browse:true}");
+ receive(browser1, 10);
+ Receiver browser2 = fix.session.createReceiver(fix.queue + "; {browse:true}");
+ receive(browser2, 10);
+ Receiver consumer = fix.session.createReceiver(fix.queue);
+ receive(consumer, 10);
+ fix.session.acknowledge();
+}
+
+struct QueueCreatePolicyFixture : public MessagingFixture
+{
+ qpid::messaging::Address address;
+
+ QueueCreatePolicyFixture(const std::string& a) : address(a) {}
+
+ void test()
+ {
+ ping(address);
+ BOOST_CHECK(admin.checkQueueExists(address.getName()));
+ }
+
+ ~QueueCreatePolicyFixture()
+ {
+ admin.deleteQueue(address.getName());
+ }
+};
+
+QPID_AUTO_TEST_CASE(testCreatePolicyQueueAlways)
+{
+ QueueCreatePolicyFixture fix("#; {create:always, node-properties:{type:queue}}");
+ fix.test();
+}
+
+QPID_AUTO_TEST_CASE(testCreatePolicyQueueReceiver)
+{
+ QueueCreatePolicyFixture fix("#; {create:receiver, node-properties:{type:queue}}");
+ Receiver r = fix.session.createReceiver(fix.address);
+ fix.test();
+ r.cancel();
+}
+
+QPID_AUTO_TEST_CASE(testCreatePolicyQueueSender)
+{
+ QueueCreatePolicyFixture fix("#; {create:sender, node-properties:{type:queue}}");
+ Sender s = fix.session.createSender(fix.address);
+ fix.test();
+ s.cancel();
+}
+
+struct ExchangeCreatePolicyFixture : public MessagingFixture
+{
+ qpid::messaging::Address address;
+ const std::string exchangeType;
+
+ ExchangeCreatePolicyFixture(const std::string& a, const std::string& t) :
+ address(a), exchangeType(t) {}
+
+ void test()
+ {
+ ping(address);
+ std::string actualType;
+ BOOST_CHECK(admin.checkExchangeExists(address.getName(), actualType));
+ BOOST_CHECK_EQUAL(exchangeType, actualType);
+ }
+
+ ~ExchangeCreatePolicyFixture()
+ {
+ admin.deleteExchange(address.getName());
+ }
+};
+
+QPID_AUTO_TEST_CASE(testCreatePolicyTopic)
+{
+ ExchangeCreatePolicyFixture fix("#; {create:always, node-properties:{type:topic}}",
+ "topic");
+ fix.test();
+}
+
+QPID_AUTO_TEST_CASE(testCreatePolicyTopicReceiverFanout)
+{
+ ExchangeCreatePolicyFixture fix("#/my-subject; {create:receiver, node-properties:{type:topic, x-properties:{type:fanout}}}", "fanout");
+ Receiver r = fix.session.createReceiver(fix.address);
+ fix.test();
+ r.cancel();
+}
+
+QPID_AUTO_TEST_CASE(testCreatePolicyTopicSenderDirect)
+{
+ ExchangeCreatePolicyFixture fix("#/my-subject; {create:sender, node-properties:{type:topic, x-properties:{type:direct}}}", "direct");
+ Sender s = fix.session.createSender(fix.address);
+ fix.test();
+ s.cancel();
+}
+
+struct DeletePolicyFixture : public MessagingFixture
+{
+ enum Mode {RECEIVER, SENDER, ALWAYS, NEVER};
+
+ std::string getPolicy(Mode mode)
+ {
+ switch (mode) {
+ case SENDER:
+ return "{delete:sender}";
+ case RECEIVER:
+ return "{delete:receiver}";
+ case ALWAYS:
+ return "{delete:always}";
+ case NEVER:
+ return "{delete:never}";
+ }
+ return "";
+ }
+
+ void testAll()
+ {
+ test(RECEIVER);
+ test(SENDER);
+ test(ALWAYS);
+ test(NEVER);
+ }
+
+ virtual ~DeletePolicyFixture() {}
+ virtual void create(const qpid::messaging::Address&) = 0;
+ virtual void destroy(const qpid::messaging::Address&) = 0;
+ virtual bool exists(const qpid::messaging::Address&) = 0;
+
+ void test(Mode mode)
+ {
+ qpid::messaging::Address address("#; " + getPolicy(mode));
+ create(address);
+
+ Sender s = session.createSender(address);
+ Receiver r = session.createReceiver(address);
+ switch (mode) {
+ case RECEIVER:
+ s.cancel();
+ BOOST_CHECK(exists(address));
+ r.cancel();
+ BOOST_CHECK(!exists(address));
+ break;
+ case SENDER:
+ r.cancel();
+ BOOST_CHECK(exists(address));
+ s.cancel();
+ BOOST_CHECK(!exists(address));
+ break;
+ case ALWAYS:
+ s.cancel();
+ BOOST_CHECK(!exists(address));
+ break;
+ case NEVER:
+ r.cancel();
+ BOOST_CHECK(exists(address));
+ s.cancel();
+ BOOST_CHECK(exists(address));
+ destroy(address);
+ }
+ }
+};
+
+struct QueueDeletePolicyFixture : DeletePolicyFixture
+{
+ void create(const qpid::messaging::Address& address)
+ {
+ admin.createQueue(address.getName());
+ }
+ void destroy(const qpid::messaging::Address& address)
+ {
+ admin.deleteQueue(address.getName());
+ }
+ bool exists(const qpid::messaging::Address& address)
+ {
+ return admin.checkQueueExists(address.getName());
+ }
+};
+
+struct ExchangeDeletePolicyFixture : DeletePolicyFixture
+{
+ const std::string exchangeType;
+ ExchangeDeletePolicyFixture(const std::string type = "topic") : exchangeType(type) {}
+
+ void create(const qpid::messaging::Address& address)
+ {
+ admin.createExchange(address.getName(), exchangeType);
+ }
+ void destroy(const qpid::messaging::Address& address)
+ {
+ admin.deleteExchange(address.getName());
+ }
+ bool exists(const qpid::messaging::Address& address)
+ {
+ std::string actualType;
+ return admin.checkExchangeExists(address.getName(), actualType) && actualType == exchangeType;
+ }
+};
+
+QPID_AUTO_TEST_CASE(testDeletePolicyQueue)
+{
+ QueueDeletePolicyFixture fix;
+ fix.testAll();
+}
+
+QPID_AUTO_TEST_CASE(testDeletePolicyExchange)
+{
+ ExchangeDeletePolicyFixture fix;
+ fix.testAll();
+}
+
+QPID_AUTO_TEST_CASE(testAssertPolicyQueue)
+{
+ MessagingFixture fix;
+ std::string a1 = "q; {create:always, assert:always, node-properties:{type:queue, durable:false, x-properties:{qpid.max-count:100}}}";
+ Sender s1 = fix.session.createSender(a1);
+ s1.cancel();
+ Receiver r1 = fix.session.createReceiver(a1);
+ r1.cancel();
+
+ std::string a2 = "q; {assert:receiver, node-properties:{durable:true, x-properties:{qpid.max-count:100}}}";
+ Sender s2 = fix.session.createSender(a2);
+ s2.cancel();
+ BOOST_CHECK_THROW(fix.session.createReceiver(a2), qpid::messaging::InvalidAddress);
+
+ std::string a3 = "q; {assert:sender, node-properties:{x-properties:{qpid.max-count:99}}}";
+ BOOST_CHECK_THROW(fix.session.createSender(a3), qpid::messaging::InvalidAddress);
+ Receiver r3 = fix.session.createReceiver(a3);
+ r3.cancel();
+
+ fix.admin.deleteQueue("q");
+}
+
+QPID_AUTO_TEST_CASE(testGetSender)
+{
+ QueueFixture fix;
+ std::string name = fix.session.createSender(fix.queue).getName();
+ Sender sender = fix.session.getSender(name);
+ BOOST_CHECK_EQUAL(name, sender.getName());
+ Message out(Uuid(true).str());
+ sender.send(out);
+ Message in;
+ BOOST_CHECK(fix.session.createReceiver(fix.queue).fetch(in));
+ BOOST_CHECK_EQUAL(out.getContent(), in.getContent());
+ BOOST_CHECK_THROW(fix.session.getSender("UnknownSender"), qpid::messaging::KeyError);
+}
+
+QPID_AUTO_TEST_CASE(testGetReceiver)
+{
+ QueueFixture fix;
+ std::string name = fix.session.createReceiver(fix.queue).getName();
+ Receiver receiver = fix.session.getReceiver(name);
+ BOOST_CHECK_EQUAL(name, receiver.getName());
+ Message out(Uuid(true).str());
+ fix.session.createSender(fix.queue).send(out);
+ Message in;
+ BOOST_CHECK(receiver.fetch(in));
+ BOOST_CHECK_EQUAL(out.getContent(), in.getContent());
+ BOOST_CHECK_THROW(fix.session.getReceiver("UnknownReceiver"), qpid::messaging::KeyError);
+}
+
+QPID_AUTO_TEST_CASE(testGetSessionFromConnection)
+{
+ QueueFixture fix;
+ fix.connection.newSession("my-session");
+ Session session = fix.connection.getSession("my-session");
+ Message out(Uuid(true).str());
+ session.createSender(fix.queue).send(out);
+ Message in;
+ BOOST_CHECK(session.createReceiver(fix.queue).fetch(in));
+ BOOST_CHECK_EQUAL(out.getContent(), in.getContent());
+ BOOST_CHECK_THROW(fix.connection.getSession("UnknownSession"), qpid::messaging::KeyError);
+}
+
+QPID_AUTO_TEST_CASE(testGetConnectionFromSession)
+{
+ QueueFixture fix;
+ Message out(Uuid(true).str());
+ Sender sender = fix.session.createSender(fix.queue);
+ sender.send(out);
+ Message in;
+ sender.getSession().getConnection().newSession("incoming");
+ BOOST_CHECK(fix.connection.getSession("incoming").createReceiver(fix.queue).fetch(in));
+ BOOST_CHECK_EQUAL(out.getContent(), in.getContent());
+}
+
+QPID_AUTO_TEST_CASE(testTx)
+{
+ QueueFixture fix;
+ Session ssn1 = fix.connection.newSession(true);
+ Session ssn2 = fix.connection.newSession(true);
+ Sender sender1 = ssn1.createSender(fix.queue);
+ Sender sender2 = ssn2.createSender(fix.queue);
+ Receiver receiver1 = ssn1.createReceiver(fix.queue);
+ Receiver receiver2 = ssn2.createReceiver(fix.queue);
+ Message in;
+
+ send(sender1, 5, 1, "A");
+ send(sender2, 5, 1, "B");
+ ssn2.commit();
+ receive(receiver1, 5, 1, "B");//(only those from sender2 should be received)
+ BOOST_CHECK(!receiver1.fetch(in, 0));//check there are no more messages
+ ssn1.rollback();
+ receive(receiver2, 5, 1, "B");
+ BOOST_CHECK(!receiver2.fetch(in, 0));//check there are no more messages
+ ssn2.rollback();
+ receive(receiver1, 5, 1, "B");
+ BOOST_CHECK(!receiver1.fetch(in, 0));//check there are no more messages
+ ssn1.commit();
+ //check neither receiver gets any more messages:
+ BOOST_CHECK(!receiver1.fetch(in, 0));
+ BOOST_CHECK(!receiver2.fetch(in, 0));
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/MockConnectionInputHandler.h b/cpp/src/tests/MockConnectionInputHandler.h
deleted file mode 100644
index 89b6155355..0000000000
--- a/cpp/src/tests/MockConnectionInputHandler.h
+++ /dev/null
@@ -1,100 +0,0 @@
-#ifndef _tests_MockConnectionInputHandler_h
-#define _tests_MockConnectionInputHandler_h
-
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "qpid/sys/ConnectionInputHandler.h"
-#include "qpid/sys/ConnectionInputHandlerFactory.h"
-#include "qpid/sys/Monitor.h"
-
-struct MockConnectionInputHandler : public qpid::sys::ConnectionInputHandler {
-
- MockConnectionInputHandler() : state(START) {}
-
- ~MockConnectionInputHandler() {}
-
- void received(qpid::framing::AMQFrame* framep) {
- qpid::sys::Monitor::ScopedLock l(monitor);
- frame = *framep;
- setState(GOT_FRAME);
- }
-
- qpid::framing::AMQFrame waitForFrame() {
- waitFor(GOT_FRAME);
- return frame;
- }
-
- void waitForClosed() {
- waitFor(CLOSED);
- }
-
- void closed() {
- qpid::sys::Monitor::ScopedLock l(monitor);
- setState(CLOSED);
- }
-
- void idleOut() {}
- void idleIn() {}
-
- private:
- typedef enum { START, GOT_FRAME, CLOSED } State;
-
- void setState(State s) {
- state = s;
- monitor.notify();
- }
-
- void waitFor(State s) {
- qpid::sys::Monitor::ScopedLock l(monitor);
- qpid::sys::Time deadline = qpid::sys::now() + 10*qpid::sys::TIME_SEC;
- while (state != s)
- CPPUNIT_ASSERT(monitor.wait(deadline));
- }
-
- qpid::sys::Monitor monitor;
- State state;
- qpid::framing::AMQFrame frame;
-};
-
-
-struct MockConnectionInputHandlerFactory : public qpid::sys::ConnectionInputHandlerFactory {
- MockConnectionInputHandlerFactory() : handler(0) {}
-
- qpid::sys::ConnectionInputHandler* create(qpid::sys::ConnectionOutputHandler*) {
- qpid::sys::Monitor::ScopedLock lock(monitor);
- handler = new MockConnectionInputHandler();
- monitor.notifyAll();
- return handler;
- }
-
- void waitForHandler() {
- qpid::sys::Monitor::ScopedLock lock(monitor);
- qpid::sys::Time deadline =
- qpid::sys::now() + 500 * qpid::sys::TIME_SEC;
- while (handler == 0)
- CPPUNIT_ASSERT(monitor.wait(deadline));
- }
-
- MockConnectionInputHandler* handler;
- qpid::sys::Monitor monitor;
-};
-
-
-
-#endif /*!_tests_MockConnectionInputHandler_h*/
diff --git a/cpp/src/tests/PartialFailure.cpp b/cpp/src/tests/PartialFailure.cpp
new file mode 100644
index 0000000000..63ee28017a
--- /dev/null
+++ b/cpp/src/tests/PartialFailure.cpp
@@ -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.
+ *
+ */
+
+/**@file Tests for partial failure in a cluster.
+ * Partial failure means some nodes experience a failure while others do not.
+ * In this case the failed nodes must shut down.
+ */
+
+#include "test_tools.h"
+#include "unit_test.h"
+#include "ClusterFixture.h"
+#include <boost/assign.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(PartialFailureTestSuite)
+
+using namespace std;
+using namespace qpid;
+using namespace qpid::cluster;
+using namespace qpid::framing;
+using namespace qpid::client;
+using namespace qpid::client::arg;
+using namespace boost::assign;
+using broker::Broker;
+using boost::shared_ptr;
+
+// Timeout for tests that wait for messages
+const sys::Duration TIMEOUT=sys::TIME_SEC/4;
+
+static bool isLogOption(const std::string& s) { return boost::starts_with(s, "--log-enable"); }
+
+void updateArgs(ClusterFixture::Args& args, size_t index) {
+ ostringstream clusterLib, testStoreLib, storeName;
+ clusterLib << getLibPath("CLUSTER_LIB");
+ testStoreLib << getLibPath("TEST_STORE_LIB");
+ storeName << "s" << index;
+ args.push_back("--auth");
+ args.push_back("no");
+ args.push_back("--no-module-dir");
+ args.push_back("--load-module");
+ args.push_back(clusterLib.str());
+ args.push_back("--load-module");
+ args.push_back(testStoreLib.str());
+ args.push_back("--test-store-name");
+ args.push_back(storeName.str());
+ args.push_back("TMP_DATA_DIR");
+
+ // These tests generate errors deliberately, disable error logging unless a log env var is set.
+ if (!::getenv("QPID_TRACE") && !::getenv("QPID_LOG_ENABLE")) {
+ remove_if(args.begin(), args.end(), isLogOption);
+ args.push_back("--log-enable=critical+:DISABLED"); // hacky way to disable logs.
+ }
+}
+
+Message pMessage(string data, string q) {
+ Message msg(data, q);
+ msg.getDeliveryProperties().setDeliveryMode(PERSISTENT);
+ return msg;
+}
+
+void queueAndSub(Client& c) {
+ c.session.queueDeclare(c.name, durable=true);
+ c.subs.subscribe(c.lq, c.name);
+}
+
+// Handle near-simultaneous errors
+QPID_AUTO_TEST_CASE(testCoincidentErrors) {
+ ClusterFixture cluster(2, updateArgs, -1);
+ Client c0(cluster[0], "c0");
+ Client c1(cluster[1], "c1");
+
+ c0.session.queueDeclare("q", durable=true);
+ {
+ ScopedSuppressLogging allQuiet;
+ async(c0.session).messageTransfer(content=pMessage("TEST_STORE_DO: s0[exception]", "q"));
+ async(c1.session).messageTransfer(content=pMessage("TEST_STORE_DO: s1[exception]", "q"));
+
+ int alive=0;
+ try { Client c00(cluster[0], "c00"); ++alive; c00.close(); } catch (...) {}
+ try { Client c11(cluster[1], "c11"); ++alive; c11.close(); } catch (...) {}
+
+ BOOST_CHECK_EQUAL(alive, 1);
+
+ // Close inside ScopedSuppressLogging to avoid warnings
+ c0.close();
+ c1.close();
+ }
+}
+
+// Verify normal cluster-wide errors.
+QPID_AUTO_TEST_CASE(testNormalErrors) {
+ // FIXME aconway 2009-04-10: Would like to put a scope just around
+ // the statements expected to fail (in BOOST_CHECK_yTHROW) but that
+ // sproadically lets out messages, possibly because they're in
+ // Connection thread.
+
+ ClusterFixture cluster(3, updateArgs, -1);
+ Client c0(cluster[0], "c0");
+ Client c1(cluster[1], "c1");
+ Client c2(cluster[2], "c2");
+
+ {
+ ScopedSuppressLogging allQuiet;
+ queueAndSub(c0);
+ c0.session.messageTransfer(content=Message("x", "c0"));
+ BOOST_CHECK_EQUAL(c0.lq.get(TIMEOUT).getData(), "x");
+
+ // Session error.
+ BOOST_CHECK_THROW(c0.session.exchangeBind(), SessionException);
+ c1.session.messageTransfer(content=Message("stay", "c0")); // Will stay on queue, session c0 is dead.
+
+ // Connection error, kill c1 on all members.
+ queueAndSub(c1);
+ BOOST_CHECK_THROW(
+ c1.session.messageTransfer(
+ content=pMessage("TEST_STORE_DO: s0[exception] s1[exception] s2[exception] testNormalErrors", "c1")),
+ ConnectionException);
+ c2.session.messageTransfer(content=Message("stay", "c1")); // Will stay on queue, session/connection c1 is dead.
+
+ BOOST_CHECK_EQUAL(3u, knownBrokerPorts(c2.connection, 3).size());
+ BOOST_CHECK_EQUAL(c2.subs.get("c0", TIMEOUT).getData(), "stay");
+ BOOST_CHECK_EQUAL(c2.subs.get("c1", TIMEOUT).getData(), "stay");
+
+ // Close inside ScopedSuppressLogging to avoid warnings
+ c0.close();
+ c1.close();
+ c2.close();
+ }
+}
+
+
+// Test errors after a new member joins to verify frame-sequence-numbers are ok in update.
+QPID_AUTO_TEST_CASE(testErrorAfterJoin) {
+ ClusterFixture cluster(1, updateArgs, -1);
+ Client c0(cluster[0]);
+ {
+ ScopedSuppressLogging allQuiet;
+
+ c0.session.queueDeclare("q", durable=true);
+ c0.session.messageTransfer(content=pMessage("a", "q"));
+
+ // Kill the new guy
+ cluster.add();
+ Client c1(cluster[1]);
+ c0.session.messageTransfer(content=pMessage("TEST_STORE_DO: s1[exception] testErrorAfterJoin", "q"));
+ BOOST_CHECK_THROW(c1.session.messageTransfer(content=pMessage("xxx", "q")), TransportFailure);
+ BOOST_CHECK_EQUAL(1u, knownBrokerPorts(c0.connection, 1).size());
+
+ // Kill the old guy
+ cluster.add();
+ Client c2(cluster[2]);
+ c2.session.messageTransfer(content=pMessage("TEST_STORE_DO: s0[exception] testErrorAfterJoin2", "q"));
+ BOOST_CHECK_THROW(c0.session.messageTransfer(content=pMessage("xxx", "q")), TransportFailure);
+
+ BOOST_CHECK_EQUAL(1u, knownBrokerPorts(c2.connection, 1).size());
+
+ // Close inside ScopedSuppressLogging to avoid warnings
+ c0.close();
+ c1.close();
+ c2.close();
+ }
+}
+
+// Test that if one member fails and others do not, the failure leaves the cluster.
+QPID_AUTO_TEST_CASE(testSinglePartialFailure) {
+ ClusterFixture cluster(3, updateArgs, -1);
+ Client c0(cluster[0], "c0");
+ Client c1(cluster[1], "c1");
+ Client c2(cluster[2], "c2");
+
+ {
+ ScopedSuppressLogging allQuiet;
+
+ c0.session.queueDeclare("q", durable=true);
+ c0.session.messageTransfer(content=pMessage("a", "q"));
+ // Cause partial failure on c1
+ c0.session.messageTransfer(content=pMessage("TEST_STORE_DO: s1[exception] testSinglePartialFailure", "q"));
+ BOOST_CHECK_THROW(c1.session.queueQuery("q"), TransportFailure);
+
+ c0.session.messageTransfer(content=pMessage("b", "q"));
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q").getMessageCount(), 3u);
+ BOOST_CHECK_EQUAL(2u, knownBrokerPorts(c0.connection, 2).size());
+
+ // Cause partial failure on c2
+ c0.session.messageTransfer(content=pMessage("TEST_STORE_DO: s2[exception] testSinglePartialFailure2", "q"));
+ BOOST_CHECK_THROW(c2.session.queueQuery("q"), TransportFailure);
+
+ c0.session.messageTransfer(content=pMessage("c", "q"));
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q").getMessageCount(), 5u);
+ BOOST_CHECK_EQUAL(1u, knownBrokerPorts(c0.connection, 1).size());
+
+ // Close inside ScopedSuppressLogging to avoid warnings
+ c0.close();
+ c1.close();
+ c2.close();
+ }
+}
+
+// Test multiple partial falures: 2 fail 2 pass
+QPID_AUTO_TEST_CASE(testMultiPartialFailure) {
+ ClusterFixture cluster(4, updateArgs, -1);
+ Client c0(cluster[0], "c0");
+ Client c1(cluster[1], "c1");
+ Client c2(cluster[2], "c2");
+ Client c3(cluster[3], "c3");
+
+ {
+ ScopedSuppressLogging allQuiet;
+
+ c0.session.queueDeclare("q", durable=true);
+ c0.session.messageTransfer(content=pMessage("a", "q"));
+
+ // Cause partial failure on c1, c2
+ c0.session.messageTransfer(content=pMessage("TEST_STORE_DO: s1[exception] s2[exception] testMultiPartialFailure", "q"));
+ BOOST_CHECK_THROW(c1.session.queueQuery("q"), TransportFailure);
+ BOOST_CHECK_THROW(c2.session.queueQuery("q"), TransportFailure);
+
+ c0.session.messageTransfer(content=pMessage("b", "q"));
+ c3.session.messageTransfer(content=pMessage("c", "q"));
+ BOOST_CHECK_EQUAL(c3.session.queueQuery("q").getMessageCount(), 4u);
+ // FIXME aconway 2009-06-30: This check fails sporadically with 2 != 3.
+ // It should pass reliably.
+ // BOOST_CHECK_EQUAL(2u, knownBrokerPorts(c0.connection, 2).size());
+
+ // Close inside ScopedSuppressLogging to avoid warnings
+ c0.close();
+ c1.close();
+ c2.close();
+ c3.close();
+ }
+}
+
+/** FIXME aconway 2009-04-10:
+ * The current approach to shutting down a process in test_store
+ * sometimes leads to assertion failures and errors in the shut-down
+ * process. Need a cleaner solution
+ */
+#if 0
+QPID_AUTO_TEST_CASE(testPartialFailureMemberLeaves) {
+ ClusterFixture cluster(2, updateArgs, -1);
+ Client c0(cluster[0], "c0");
+ Client c1(cluster[1], "c1");
+
+ {
+ ScopedSuppressLogging allQuiet;
+
+ c0.session.queueDeclare("q", durable=true);
+ c0.session.messageTransfer(content=pMessage("a", "q"));
+
+ // Cause failure on member 0 and simultaneous crash on member 1.
+ BOOST_CHECK_THROW(
+ c0.session.messageTransfer(
+ content=pMessage("TEST_STORE_DO: s0[exception] s1[exit_process] testPartialFailureMemberLeaves", "q")),
+ ConnectionException);
+ cluster.wait(1);
+
+ Client c00(cluster[0], "c00"); // Old connection is dead.
+ BOOST_CHECK_EQUAL(c00.session.queueQuery("q").getMessageCount(), 1u);
+ BOOST_CHECK_EQUAL(1u, knownBrokerPorts(c00.connection, 1).size());
+
+ // Close inside ScopedSuppressLogging to avoid warnings
+ c0.close();
+ }
+}
+#endif
+
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/PollableCondition.cpp b/cpp/src/tests/PollableCondition.cpp
new file mode 100644
index 0000000000..f9b3c25c93
--- /dev/null
+++ b/cpp/src/tests/PollableCondition.cpp
@@ -0,0 +1,109 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "test_tools.h"
+#include "unit_test.h"
+#include "qpid/sys/Poller.h"
+#include "qpid/sys/PollableCondition.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/sys/Time.h"
+#include "qpid/sys/Thread.h"
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(PollableConditionTest)
+
+using namespace qpid::sys;
+
+const Duration SHORT = TIME_SEC/100;
+const Duration LONG = TIME_SEC/10;
+
+class Callback {
+ public:
+ enum Action { NONE, CLEAR };
+
+ Callback() : count(), action(NONE) {}
+
+ void call(PollableCondition& pc) {
+ Mutex::ScopedLock l(lock);
+ ++count;
+ switch(action) {
+ case NONE: break;
+ case CLEAR: pc.clear(); break;
+ }
+ action = NONE;
+ lock.notify();
+ }
+
+ bool isCalling() { Mutex::ScopedLock l(lock); return wait(LONG); }
+
+ bool isNotCalling() { Mutex::ScopedLock l(lock); return !wait(SHORT); }
+
+ bool nextCall(Action a=NONE) {
+ Mutex::ScopedLock l(lock);
+ action = a;
+ return wait(LONG);
+ }
+
+ private:
+ bool wait(Duration timeout) {
+ int n = count;
+ AbsTime deadline(now(), timeout);
+ while (n == count && lock.wait(deadline))
+ ;
+ return n != count;
+ }
+
+ Monitor lock;
+ int count;
+ Action action;
+};
+
+QPID_AUTO_TEST_CASE(testPollableCondition) {
+ boost::shared_ptr<Poller> poller(new Poller());
+ Callback callback;
+ PollableCondition pc(boost::bind(&Callback::call, &callback, _1), poller);
+
+ Thread runner = Thread(*poller);
+
+ BOOST_CHECK(callback.isNotCalling()); // condition is not set.
+
+ pc.set();
+ BOOST_CHECK(callback.isCalling()); // Set.
+ BOOST_CHECK(callback.isCalling()); // Still set.
+
+ callback.nextCall(Callback::CLEAR);
+ BOOST_CHECK(callback.isNotCalling()); // Cleared
+
+ pc.set();
+ BOOST_CHECK(callback.isCalling()); // Set.
+ callback.nextCall(Callback::CLEAR);
+ BOOST_CHECK(callback.isNotCalling()); // Cleared.
+
+ poller->shutdown();
+ runner.join();
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+}} //namespace qpid::tests
diff --git a/cpp/src/tests/PollerTest.cpp b/cpp/src/tests/PollerTest.cpp
index fcb1d0dadf..11337d6be3 100644
--- a/cpp/src/tests/PollerTest.cpp
+++ b/cpp/src/tests/PollerTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -23,7 +23,9 @@
* Use socketpair to test the poller
*/
+#include "qpid/sys/IOHandle.h"
#include "qpid/sys/Poller.h"
+#include "qpid/sys/posix/PrivatePosix.h"
#include <string>
#include <iostream>
@@ -48,7 +50,7 @@ int writeALot(int fd, const string& s) {
int lastWrite = ::write(fd, s.c_str(), s.size());
if ( lastWrite >= 0) {
bytesWritten += lastWrite;
- }
+ }
} while (errno != EAGAIN);
return bytesWritten;
}
@@ -56,32 +58,32 @@ int writeALot(int fd, const string& s) {
int readALot(int fd) {
int bytesRead = 0;
char buf[1024];
-
+
do {
errno = 0;
int lastRead = ::read(fd, buf, sizeof(buf));
if ( lastRead >= 0) {
bytesRead += lastRead;
- }
+ }
} while (errno != EAGAIN);
return bytesRead;
}
-int main(int argc, char** argv)
+int main(int /*argc*/, char** /*argv*/)
{
- try
+ try
{
int sv[2];
- int rc = ::socketpair(AF_LOCAL, SOCK_STREAM, 0, sv);
+ int rc = ::socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
assert(rc >= 0);
-
+
// Set non-blocking
rc = ::fcntl(sv[0], F_SETFL, O_NONBLOCK);
assert(rc >= 0);
rc = ::fcntl(sv[1], F_SETFL, O_NONBLOCK);
assert(rc >= 0);
-
+
// Make up a large string
string testString = "This is only a test ... 1,2,3,4,5,6,7,8,9,10;";
for (int i = 0; i < 6; i++)
@@ -95,66 +97,127 @@ int main(int argc, char** argv)
// Write as much as we can to socket 0
int bytesWritten = writeALot(sv[0], testString);
cout << "Wrote(0): " << bytesWritten << " bytes\n";
-
+
// Read as much as we can from socket 1
bytesRead = readALot(sv[1]);
assert(bytesRead == bytesWritten);
cout << "Read(1): " << bytesRead << " bytes\n";
auto_ptr<Poller> poller(new Poller);
-
- PollerHandle h0(sv[0]);
- PollerHandle h1(sv[1]);
-
- poller->addFd(h0, Poller::INOUT);
-
- // Wait for 500ms - h0 should be writable
+
+ PosixIOHandle f0(sv[0]);
+ PosixIOHandle f1(sv[1]);
+
+ PollerHandle h0(f0);
+ PollerHandle h1(f1);
+
+ poller->registerHandle(h0);
+ poller->monitorHandle(h0, Poller::INOUT);
+
+ // h0 should be writable
Poller::Event event = poller->wait();
assert(event.handle == &h0);
- assert(event.dir == Poller::OUT);
-
+ assert(event.type == Poller::WRITABLE);
+
// Write as much as we can to socket 0
bytesWritten = writeALot(sv[0], testString);
cout << "Wrote(0): " << bytesWritten << " bytes\n";
-
+
// Wait for 500ms - h0 no longer writable
- poller->rearmFd(h0);
event = poller->wait(500000000);
assert(event.handle == 0);
// Test we can read it all now
- poller->addFd(h1, Poller::INOUT);
+ poller->registerHandle(h1);
+ poller->monitorHandle(h1, Poller::INOUT);
event = poller->wait();
assert(event.handle == &h1);
- assert(event.dir == Poller::INOUT);
-
+ assert(event.type == Poller::READ_WRITABLE);
+
bytesRead = readALot(sv[1]);
assert(bytesRead == bytesWritten);
cout << "Read(1): " << bytesRead << " bytes\n";
-
- // At this point h1 should have been disabled from the poller
- // (as it was just returned) and h0 can write again
+
+ // Test poller interrupt
+ assert(poller->interrupt(h0) == true);
event = poller->wait();
assert(event.handle == &h0);
- assert(event.dir == Poller::OUT);
+ assert(event.type == Poller::INTERRUPTED);
+
+ // Test multiple interrupts
+ assert(poller->interrupt(h0) == true);
+ assert(poller->interrupt(h1) == true);
- // Now both the handles should be disabled
+ // Make sure we can interrupt them again
+ assert(poller->interrupt(h0) == true);
+ assert(poller->interrupt(h1) == true);
+
+ // Make sure that they both come out
+ event = poller->wait();
+ assert(event.type == Poller::INTERRUPTED);
+ assert(event.handle == &h0 || event.handle == &h1);
+ if (event.handle == &h0) {
+ event = poller->wait();
+ assert(event.type == Poller::INTERRUPTED);
+ assert(event.handle == &h1);
+ } else {
+ event = poller->wait();
+ assert(event.type == Poller::INTERRUPTED);
+ assert(event.handle == &h0);
+ }
+
+ poller->unmonitorHandle(h1, Poller::INOUT);
+
+ event = poller->wait();
+ assert(event.handle == &h0);
+ assert(event.type == Poller::WRITABLE);
+
+ // We didn't write anything so it should still be writable
+ event = poller->wait();
+ assert(event.handle == &h0);
+ assert(event.type == Poller::WRITABLE);
+
+ poller->unmonitorHandle(h0, Poller::INOUT);
+
+ event = poller->wait(500000000);
+ assert(event.handle == 0);
+
+ poller->unregisterHandle(h1);
+ assert(poller->interrupt(h1) == false);
+
+ // close the other end to force a disconnect
+ ::close(sv[1]);
+
+ // Now make sure that we are readable followed by disconnected
+ // and after that we never return again
+ poller->monitorHandle(h0, Poller::INOUT);
event = poller->wait(500000000);
+ assert(event.handle == &h0);
+ assert(event.type == Poller::READABLE);
+ event = poller->wait(500000000);
+ assert(event.handle == &h0);
+ assert(event.type == Poller::DISCONNECTED);
+ event = poller->wait(1500000000);
assert(event.handle == 0);
-
+
+ // Now we're disconnected monitoring should have no effect at all
+ poller->unmonitorHandle(h0, Poller::INOUT);
+ event = poller->wait(1500000000);
+ assert(event.handle == 0);
+
+ poller->unregisterHandle(h0);
+ assert(poller->interrupt(h0) == false);
+
// Test shutdown
poller->shutdown();
event = poller->wait();
assert(event.handle == 0);
- assert(event.dir == Poller::SHUTDOWN);
+ assert(event.type == Poller::SHUTDOWN);
event = poller->wait();
assert(event.handle == 0);
- assert(event.dir == Poller::SHUTDOWN);
+ assert(event.type == Poller::SHUTDOWN);
- poller->delFd(h1);
- poller->delFd(h0);
-
return 0;
} catch (exception& e) {
cout << "Caught exception " << e.what() << "\n";
diff --git a/cpp/src/tests/ProxyTest.cpp b/cpp/src/tests/ProxyTest.cpp
new file mode 100644
index 0000000000..a926b28395
--- /dev/null
+++ b/cpp/src/tests/ProxyTest.cpp
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <iostream>
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/AMQMethodBody.h"
+#include "qpid/framing/ExecutionSyncBody.h"
+#include "qpid/framing/Proxy.h"
+
+#include "unit_test.h"
+
+using namespace qpid::framing;
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(ProxyTestSuite)
+
+
+QPID_AUTO_TEST_CASE(testScopedSync)
+{
+ struct DummyHandler : FrameHandler
+ {
+ void handle(AMQFrame& f) {
+ AMQMethodBody* m = f.getMethod();
+ BOOST_CHECK(m);
+ BOOST_CHECK(m->isA<ExecutionSyncBody>());
+ BOOST_CHECK(m->isSync());
+ }
+ };
+ DummyHandler f;
+ Proxy p(f);
+ Proxy::ScopedSync s(p);
+ p.send(ExecutionSyncBody(p.getVersion()));
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/QueueEvents.cpp b/cpp/src/tests/QueueEvents.cpp
new file mode 100644
index 0000000000..bd18fa45fb
--- /dev/null
+++ b/cpp/src/tests/QueueEvents.cpp
@@ -0,0 +1,238 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "MessageUtils.h"
+#include "unit_test.h"
+#include "BrokerFixture.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/QueueEvents.h"
+#include "qpid/client/QueueOptions.h"
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/sys/Dispatcher.h"
+#include <boost/bind.hpp>
+#include <boost/format.hpp>
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(QueueEventsSuite)
+
+using namespace qpid::client;
+using namespace qpid::broker;
+using namespace qpid::sys;
+using qpid::framing::SequenceNumber;
+
+struct EventChecker
+{
+ typedef std::deque<QueueEvents::Event> Events;
+
+ Events events;
+ boost::shared_ptr<Poller> poller;
+
+ void handle(QueueEvents::Event e)
+ {
+ if (events.empty()) {
+ BOOST_FAIL("Unexpected event received");
+ } else {
+ BOOST_CHECK_EQUAL(events.front().type, e.type);
+ BOOST_CHECK_EQUAL(events.front().msg.queue, e.msg.queue);
+ BOOST_CHECK_EQUAL(events.front().msg.payload, e.msg.payload);
+ BOOST_CHECK_EQUAL(events.front().msg.position, e.msg.position);
+ events.pop_front();
+ }
+ if (events.empty() && poller) poller->shutdown();
+ }
+
+ void expect(QueueEvents::Event e)
+ {
+ events.push_back(e);
+ }
+};
+
+QPID_AUTO_TEST_CASE(testBasicEventProcessing)
+{
+ boost::shared_ptr<Poller> poller(new Poller());
+ sys::Dispatcher dispatcher(poller);
+ Thread dispatchThread(dispatcher);
+ QueueEvents events(poller);
+ EventChecker listener;
+ listener.poller = poller;
+ events.registerListener("dummy", boost::bind(&EventChecker::handle, &listener, _1));
+ //signal occurence of some events:
+ Queue queue("queue1");
+ SequenceNumber id;
+ QueuedMessage event1(&queue, MessageUtils::createMessage(), id);
+ QueuedMessage event2(&queue, MessageUtils::createMessage(), ++id);
+
+ //define events expected by listener:
+ listener.expect(QueueEvents::Event(QueueEvents::ENQUEUE, event1));
+ listener.expect(QueueEvents::Event(QueueEvents::ENQUEUE, event2));
+ listener.expect(QueueEvents::Event(QueueEvents::DEQUEUE, event1));
+
+ events.enqueued(event1);
+ events.enqueued(event2);
+ events.dequeued(event1);
+
+ dispatchThread.join();
+ events.shutdown();
+ events.unregisterListener("dummy");
+}
+
+
+struct EventRecorder
+{
+ struct EventRecord
+ {
+ QueueEvents::EventType type;
+ std::string queue;
+ std::string content;
+ SequenceNumber position;
+ };
+
+ typedef std::deque<EventRecord> Events;
+
+ Events events;
+
+ void handle(QueueEvents::Event event)
+ {
+ EventRecord record;
+ record.type = event.type;
+ record.queue = event.msg.queue->getName();
+ event.msg.payload->getFrames().getContent(record.content);
+ record.position = event.msg.position;
+ events.push_back(record);
+ }
+
+ void check(QueueEvents::EventType type, const std::string& queue, const std::string& content, const SequenceNumber& position)
+ {
+ if (events.empty()) {
+ BOOST_FAIL("Missed event");
+ } else {
+ BOOST_CHECK_EQUAL(events.front().type, type);
+ BOOST_CHECK_EQUAL(events.front().queue, queue);
+ BOOST_CHECK_EQUAL(events.front().content, content);
+ BOOST_CHECK_EQUAL(events.front().position, position);
+ events.pop_front();
+ }
+ }
+ void checkEnqueue(const std::string& queue, const std::string& data, const SequenceNumber& position)
+ {
+ check(QueueEvents::ENQUEUE, queue, data, position);
+ }
+
+ void checkDequeue(const std::string& queue, const std::string& data, const SequenceNumber& position)
+ {
+ check(QueueEvents::DEQUEUE, queue, data, position);
+ }
+};
+
+QPID_AUTO_TEST_CASE(testSystemLevelEventProcessing)
+{
+ ProxySessionFixture fixture;
+ //register dummy event listener to broker
+ EventRecorder listener;
+ fixture.broker->getQueueEvents().registerListener("recorder", boost::bind(&EventRecorder::handle, &listener, _1));
+
+ //declare queue with event options specified
+ QueueOptions options;
+ options.enableQueueEvents(false);
+ std::string q("queue-events-test");
+ fixture.session.queueDeclare(arg::queue=q, arg::arguments=options);
+ //send and consume some messages
+ LocalQueue incoming;
+ Subscription sub = fixture.subs.subscribe(incoming, q);
+ for (int i = 0; i < 5; i++) {
+ fixture.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
+ }
+ for (int i = 0; i < 3; i++) {
+ BOOST_CHECK_EQUAL(incoming.pop().getData(), (boost::format("%1%_%2%") % "Message" % (i+1)).str());
+ }
+ for (int i = 5; i < 10; i++) {
+ fixture.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
+ }
+ for (int i = 3; i < 10; i++) {
+ BOOST_CHECK_EQUAL(incoming.pop().getData(), (boost::format("%1%_%2%") % "Message" % (i+1)).str());
+ }
+ fixture.connection.close();
+ fixture.broker->getQueueEvents().shutdown();
+
+ //check listener was notified of all events, and in correct order
+ SequenceNumber enqueueId(1);
+ SequenceNumber dequeueId(1);
+ for (int i = 0; i < 5; i++) {
+ listener.checkEnqueue(q, (boost::format("%1%_%2%") % "Message" % (i+1)).str(), enqueueId++);
+ }
+ for (int i = 0; i < 3; i++) {
+ listener.checkDequeue(q, (boost::format("%1%_%2%") % "Message" % (i+1)).str(), dequeueId++);
+ }
+ for (int i = 5; i < 10; i++) {
+ listener.checkEnqueue(q, (boost::format("%1%_%2%") % "Message" % (i+1)).str(), enqueueId++);
+ }
+ for (int i = 3; i < 10; i++) {
+ listener.checkDequeue(q, (boost::format("%1%_%2%") % "Message" % (i+1)).str(), dequeueId++);
+ }
+}
+
+QPID_AUTO_TEST_CASE(testSystemLevelEventProcessing_enqueuesOnly)
+{
+ ProxySessionFixture fixture;
+ //register dummy event listener to broker
+ EventRecorder listener;
+ fixture.broker->getQueueEvents().registerListener("recorder", boost::bind(&EventRecorder::handle, &listener, _1));
+
+ //declare queue with event options specified
+ QueueOptions options;
+ options.enableQueueEvents(true);
+ std::string q("queue-events-test");
+ fixture.session.queueDeclare(arg::queue=q, arg::arguments=options);
+ //send and consume some messages
+ LocalQueue incoming;
+ Subscription sub = fixture.subs.subscribe(incoming, q);
+ for (int i = 0; i < 5; i++) {
+ fixture.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
+ }
+ for (int i = 0; i < 3; i++) {
+ BOOST_CHECK_EQUAL(incoming.pop().getData(), (boost::format("%1%_%2%") % "Message" % (i+1)).str());
+ }
+ for (int i = 5; i < 10; i++) {
+ fixture.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
+ }
+ for (int i = 3; i < 10; i++) {
+ BOOST_CHECK_EQUAL(incoming.pop().getData(), (boost::format("%1%_%2%") % "Message" % (i+1)).str());
+ }
+ fixture.connection.close();
+ fixture.broker->getQueueEvents().shutdown();
+
+ //check listener was notified of all events, and in correct order
+ SequenceNumber enqueueId(1);
+ SequenceNumber dequeueId(1);
+ for (int i = 0; i < 5; i++) {
+ listener.checkEnqueue(q, (boost::format("%1%_%2%") % "Message" % (i+1)).str(), enqueueId++);
+ }
+ for (int i = 5; i < 10; i++) {
+ listener.checkEnqueue(q, (boost::format("%1%_%2%") % "Message" % (i+1)).str(), enqueueId++);
+ }
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/QueueOptionsTest.cpp b/cpp/src/tests/QueueOptionsTest.cpp
new file mode 100644
index 0000000000..f2fbaba2c1
--- /dev/null
+++ b/cpp/src/tests/QueueOptionsTest.cpp
@@ -0,0 +1,102 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <iostream>
+#include "qpid/framing/Array.h"
+#include "qpid/client/QueueOptions.h"
+
+#include "unit_test.h"
+
+using namespace qpid::client;
+
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(QueueOptionsTestSuite)
+
+QPID_AUTO_TEST_CASE(testSizePolicy)
+{
+ QueueOptions ft;
+
+ ft.setSizePolicy(REJECT,1,2);
+
+ BOOST_CHECK(QueueOptions::strREJECT == ft.getAsString(QueueOptions::strTypeKey));
+ BOOST_CHECK(1 == ft.getAsInt(QueueOptions::strMaxSizeKey));
+ BOOST_CHECK(2 == ft.getAsInt(QueueOptions::strMaxCountKey));
+
+ ft.setSizePolicy(FLOW_TO_DISK,0,2);
+ BOOST_CHECK(QueueOptions::strFLOW_TO_DISK == ft.getAsString(QueueOptions::strTypeKey));
+ BOOST_CHECK(1 == ft.getAsInt(QueueOptions::strMaxSizeKey));
+ BOOST_CHECK(2 == ft.getAsInt(QueueOptions::strMaxCountKey));
+
+ ft.setSizePolicy(RING,1,0);
+ BOOST_CHECK(QueueOptions::strRING == ft.getAsString(QueueOptions::strTypeKey));
+
+ ft.setSizePolicy(RING_STRICT,1,0);
+ BOOST_CHECK(QueueOptions::strRING_STRICT == ft.getAsString(QueueOptions::strTypeKey));
+
+ ft.clearSizePolicy();
+ BOOST_CHECK(!ft.isSet(QueueOptions::strTypeKey));
+ BOOST_CHECK(!ft.isSet(QueueOptions::strMaxSizeKey));
+ BOOST_CHECK(!ft.isSet(QueueOptions::strMaxCountKey));
+}
+
+QPID_AUTO_TEST_CASE(testFlags)
+{
+ QueueOptions ft;
+
+ ft.setPersistLastNode();
+ ft.setOrdering(LVQ);
+
+ BOOST_CHECK(1 == ft.getAsInt(QueueOptions::strPersistLastNode));
+ BOOST_CHECK(1 == ft.getAsInt(QueueOptions::strLastValueQueue));
+
+ ft.clearPersistLastNode();
+ ft.setOrdering(FIFO);
+
+ BOOST_CHECK(!ft.isSet(QueueOptions::strPersistLastNode));
+ BOOST_CHECK(!ft.isSet(QueueOptions::strLastValueQueue));
+
+}
+
+QPID_AUTO_TEST_CASE(testSetOrdering)
+{
+ //ensure setOrdering(FIFO) works even if not preceded by a call to
+ //setOrdering(LVQ)
+ QueueOptions ft;
+ ft.setOrdering(FIFO);
+ BOOST_CHECK(!ft.isSet(QueueOptions::strLastValueQueue));
+
+}
+
+QPID_AUTO_TEST_CASE(testClearPersistLastNode)
+{
+ //ensure clear works even if not preceded by the setting on the
+ //option
+ QueueOptions ft;
+ ft.clearPersistLastNode();
+ BOOST_CHECK(!ft.isSet(QueueOptions::strPersistLastNode));
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/QueuePolicyTest.cpp b/cpp/src/tests/QueuePolicyTest.cpp
index db88682010..875976db85 100644
--- a/cpp/src/tests/QueuePolicyTest.cpp
+++ b/cpp/src/tests/QueuePolicyTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -18,64 +18,287 @@
* under the License.
*
*/
-#include "qpid/broker/QueuePolicy.h"
#include "unit_test.h"
+#include "test_tools.h"
+
+#include "qpid/broker/QueuePolicy.h"
+#include "qpid/client/QueueOptions.h"
+#include "qpid/sys/Time.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "MessageUtils.h"
+#include "BrokerFixture.h"
using namespace qpid::broker;
+using namespace qpid::client;
using namespace qpid::framing;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(QueuePolicyTestSuite)
+QueuedMessage createMessage(uint32_t size)
+{
+ QueuedMessage msg;
+ msg.payload = MessageUtils::createMessage();
+ MessageUtils::addContent(msg.payload, std::string (size, 'x'));
+ return msg;
+}
+
+
QPID_AUTO_TEST_CASE(testCount)
{
- QueuePolicy policy(5, 0);
- BOOST_CHECK(!policy.limitExceeded());
- for (int i = 0; i < 5; i++) policy.enqueued(10);
- BOOST_CHECK_EQUAL((uint64_t) 0, policy.getMaxSize());
- BOOST_CHECK_EQUAL((uint32_t) 5, policy.getMaxCount());
- BOOST_CHECK(!policy.limitExceeded());
- policy.enqueued(10);
- BOOST_CHECK(policy.limitExceeded());
- policy.dequeued(10);
- BOOST_CHECK(!policy.limitExceeded());
- policy.enqueued(10);
- BOOST_CHECK(policy.limitExceeded());
+ std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy("test", 5, 0));
+ BOOST_CHECK_EQUAL((uint64_t) 0, policy->getMaxSize());
+ BOOST_CHECK_EQUAL((uint32_t) 5, policy->getMaxCount());
+
+ QueuedMessage msg = createMessage(10);
+ for (size_t i = 0; i < 5; i++) {
+ policy->tryEnqueue(msg.payload);
+ }
+ try {
+ policy->tryEnqueue(msg.payload);
+ BOOST_FAIL("Policy did not fail on enqueuing sixth message");
+ } catch (const ResourceLimitExceededException&) {}
+
+ policy->dequeued(msg);
+ policy->tryEnqueue(msg.payload);
+
+ try {
+ policy->tryEnqueue(msg.payload);
+ BOOST_FAIL("Policy did not fail on enqueuing sixth message (after dequeue)");
+ } catch (const ResourceLimitExceededException&) {}
}
QPID_AUTO_TEST_CASE(testSize)
{
- QueuePolicy policy(0, 50);
- for (int i = 0; i < 5; i++) policy.enqueued(10);
- BOOST_CHECK(!policy.limitExceeded());
- policy.enqueued(10);
- BOOST_CHECK(policy.limitExceeded());
- policy.dequeued(10);
- BOOST_CHECK(!policy.limitExceeded());
- policy.enqueued(10);
- BOOST_CHECK(policy.limitExceeded());
+ std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy("test", 0, 50));
+ QueuedMessage msg = createMessage(10);
+
+ for (size_t i = 0; i < 5; i++) {
+ policy->tryEnqueue(msg.payload);
+ }
+ try {
+ policy->tryEnqueue(msg.payload);
+ BOOST_FAIL("Policy did not fail on aggregate size exceeding 50. " << *policy);
+ } catch (const ResourceLimitExceededException&) {}
+
+ policy->dequeued(msg);
+ policy->tryEnqueue(msg.payload);
+
+ try {
+ policy->tryEnqueue(msg.payload);
+ BOOST_FAIL("Policy did not fail on aggregate size exceeding 50 (after dequeue). " << *policy);
+ } catch (const ResourceLimitExceededException&) {}
}
QPID_AUTO_TEST_CASE(testBoth)
{
- QueuePolicy policy(5, 50);
- for (int i = 0; i < 5; i++) policy.enqueued(11);
- BOOST_CHECK(policy.limitExceeded());
- policy.dequeued(20);
- BOOST_CHECK(!policy.limitExceeded());//fails
- policy.enqueued(5);
- policy.enqueued(10);
- BOOST_CHECK(policy.limitExceeded());
+ std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy("test", 5, 50));
+ try {
+ QueuedMessage msg = createMessage(51);
+ policy->tryEnqueue(msg.payload);
+ BOOST_FAIL("Policy did not fail on single message exceeding 50. " << *policy);
+ } catch (const ResourceLimitExceededException&) {}
+
+ std::vector<QueuedMessage> messages;
+ messages.push_back(createMessage(15));
+ messages.push_back(createMessage(10));
+ messages.push_back(createMessage(11));
+ messages.push_back(createMessage(2));
+ messages.push_back(createMessage(7));
+ for (size_t i = 0; i < messages.size(); i++) {
+ policy->tryEnqueue(messages[i].payload);
+ }
+ //size = 45 at this point, count = 5
+ try {
+ QueuedMessage msg = createMessage(5);
+ policy->tryEnqueue(msg.payload);
+ BOOST_FAIL("Policy did not fail on count exceeding 6. " << *policy);
+ } catch (const ResourceLimitExceededException&) {}
+ try {
+ QueuedMessage msg = createMessage(10);
+ policy->tryEnqueue(msg.payload);
+ BOOST_FAIL("Policy did not fail on aggregate size exceeding 50. " << *policy);
+ } catch (const ResourceLimitExceededException&) {}
+
+
+ policy->dequeued(messages[0]);
+ try {
+ QueuedMessage msg = createMessage(20);
+ policy->tryEnqueue(msg.payload);
+ } catch (const ResourceLimitExceededException&) {
+ BOOST_FAIL("Policy failed incorrectly after dequeue. " << *policy);
+ }
}
QPID_AUTO_TEST_CASE(testSettings)
{
//test reading and writing the policy from/to field table
+ std::auto_ptr<QueuePolicy> a(QueuePolicy::createQueuePolicy("test", 101, 303));
FieldTable settings;
- QueuePolicy a(101, 303);
- a.update(settings);
- QueuePolicy b(settings);
- BOOST_CHECK_EQUAL(a.getMaxCount(), b.getMaxCount());
- BOOST_CHECK_EQUAL(a.getMaxSize(), b.getMaxSize());
+ a->update(settings);
+ std::auto_ptr<QueuePolicy> b(QueuePolicy::createQueuePolicy("test", settings));
+ BOOST_CHECK_EQUAL(a->getMaxCount(), b->getMaxCount());
+ BOOST_CHECK_EQUAL(a->getMaxSize(), b->getMaxSize());
+}
+
+QPID_AUTO_TEST_CASE(testRingPolicy)
+{
+ FieldTable args;
+ std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 5, 0, QueuePolicy::RING);
+ policy->update(args);
+
+ ProxySessionFixture f;
+ std::string q("my-ring-queue");
+ f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args);
+ for (int i = 0; i < 10; i++) {
+ f.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
+ }
+ client::Message msg;
+ for (int i = 5; i < 10; i++) {
+ BOOST_CHECK(f.subs.get(msg, q, qpid::sys::TIME_SEC));
+ BOOST_CHECK_EQUAL((boost::format("%1%_%2%") % "Message" % (i+1)).str(), msg.getData());
+ }
+ BOOST_CHECK(!f.subs.get(msg, q));
+
+ for (int i = 10; i < 20; i++) {
+ f.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
+ }
+ for (int i = 15; i < 20; i++) {
+ BOOST_CHECK(f.subs.get(msg, q, qpid::sys::TIME_SEC));
+ BOOST_CHECK_EQUAL((boost::format("%1%_%2%") % "Message" % (i+1)).str(), msg.getData());
+ }
+ BOOST_CHECK(!f.subs.get(msg, q));
+}
+
+QPID_AUTO_TEST_CASE(testStrictRingPolicy)
+{
+ FieldTable args;
+ std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 5, 0, QueuePolicy::RING_STRICT);
+ policy->update(args);
+
+ ProxySessionFixture f;
+ std::string q("my-ring-queue");
+ f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args);
+ LocalQueue incoming;
+ SubscriptionSettings settings(FlowControl::unlimited());
+ settings.autoAck = 0; // no auto ack.
+ Subscription sub = f.subs.subscribe(incoming, q, settings);
+ for (int i = 0; i < 5; i++) {
+ f.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
+ }
+ for (int i = 0; i < 5; i++) {
+ BOOST_CHECK_EQUAL(incoming.pop().getData(), (boost::format("%1%_%2%") % "Message" % (i+1)).str());
+ }
+ try {
+ ScopedSuppressLogging sl; // Suppress messages for expected errors.
+ f.session.messageTransfer(arg::content=client::Message("Message_6", q));
+ BOOST_FAIL("expecting ResourceLimitExceededException.");
+ } catch (const ResourceLimitExceededException&) {}
+}
+
+QPID_AUTO_TEST_CASE(testPolicyWithDtx)
+{
+ FieldTable args;
+ std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 5, 0, QueuePolicy::REJECT);
+ policy->update(args);
+
+ ProxySessionFixture f;
+ std::string q("my-policy-queue");
+ f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args);
+ LocalQueue incoming;
+ SubscriptionSettings settings(FlowControl::unlimited());
+ settings.autoAck = 0; // no auto ack.
+ Subscription sub = f.subs.subscribe(incoming, q, settings);
+ f.session.dtxSelect();
+ Xid tx1(1, "test-dtx-mgr", "tx1");
+ f.session.dtxStart(arg::xid=tx1);
+ for (int i = 0; i < 5; i++) {
+ f.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
+ }
+ f.session.dtxEnd(arg::xid=tx1);
+ f.session.dtxCommit(arg::xid=tx1, arg::onePhase=true);
+
+ Xid tx2(1, "test-dtx-mgr", "tx2");
+ f.session.dtxStart(arg::xid=tx2);
+ for (int i = 0; i < 5; i++) {
+ BOOST_CHECK_EQUAL(incoming.pop().getData(), (boost::format("%1%_%2%") % "Message" % (i+1)).str());
+ }
+ SequenceSet accepting=sub.getUnaccepted();
+ f.session.messageAccept(accepting);
+ f.session.dtxEnd(arg::xid=tx2);
+ f.session.dtxPrepare(arg::xid=tx2);
+ f.session.dtxRollback(arg::xid=tx2);
+ f.session.messageRelease(accepting);
+
+ Xid tx3(1, "test-dtx-mgr", "tx3");
+ f.session.dtxStart(arg::xid=tx3);
+ for (int i = 0; i < 5; i++) {
+ incoming.pop();
+ }
+ accepting=sub.getUnaccepted();
+ f.session.messageAccept(accepting);
+ f.session.dtxEnd(arg::xid=tx3);
+ f.session.dtxPrepare(arg::xid=tx3);
+
+ Session other = f.connection.newSession();
+ try {
+ ScopedSuppressLogging sl; // Suppress messages for expected errors.
+ other.messageTransfer(arg::content=client::Message("Message_6", q));
+ BOOST_FAIL("expecting ResourceLimitExceededException.");
+ } catch (const ResourceLimitExceededException&) {}
+
+ f.session.dtxCommit(arg::xid=tx3);
+ //now retry and this time should succeed
+ other = f.connection.newSession();
+ other.messageTransfer(arg::content=client::Message("Message_6", q));
+}
+
+QPID_AUTO_TEST_CASE(testFlowToDiskWithNoStore)
+{
+ //Ensure that with no store loaded, we don't flow to disk but
+ //fallback to rejecting messages
+ QueueOptions args;
+ args.setSizePolicy(FLOW_TO_DISK, 0, 5);
+
+ ProxySessionFixture f;
+ std::string q("my-queue");
+ f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args);
+ LocalQueue incoming;
+ SubscriptionSettings settings(FlowControl::unlimited());
+ settings.autoAck = 0; // no auto ack.
+ Subscription sub = f.subs.subscribe(incoming, q, settings);
+ for (int i = 0; i < 5; i++) {
+ f.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
+ }
+ for (int i = 0; i < 5; i++) {
+ BOOST_CHECK_EQUAL(incoming.pop().getData(), (boost::format("%1%_%2%") % "Message" % (i+1)).str());
+ }
+ try {
+ ScopedSuppressLogging sl; // Suppress messages for expected errors.
+ f.session.messageTransfer(arg::content=client::Message("Message_6", q));
+ BOOST_FAIL("expecting ResourceLimitExceededException.");
+ } catch (const ResourceLimitExceededException&) {}
+}
+
+QPID_AUTO_TEST_CASE(testPolicyFailureOnCommit)
+{
+ FieldTable args;
+ std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 5, 0, QueuePolicy::REJECT);
+ policy->update(args);
+
+ ProxySessionFixture f;
+ std::string q("q");
+ f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args);
+ f.session.txSelect();
+ for (int i = 0; i < 10; i++) {
+ f.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
+ }
+ ScopedSuppressLogging sl; // Suppress messages for expected errors.
+ BOOST_CHECK_THROW(f.session.txCommit(), InternalErrorException);
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/QueueRegistryTest.cpp b/cpp/src/tests/QueueRegistryTest.cpp
index 7ad4e0b89d..712cb568c3 100644
--- a/cpp/src/tests/QueueRegistryTest.cpp
+++ b/cpp/src/tests/QueueRegistryTest.cpp
@@ -6,9 +6,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -23,6 +23,9 @@
using namespace qpid::broker;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(QueueRegistryTest)
QPID_AUTO_TEST_CASE(testDeclare)
@@ -49,7 +52,7 @@ QPID_AUTO_TEST_CASE(testDeclare)
BOOST_CHECK_EQUAL(bar, q->getName());
}
-QPID_AUTO_TEST_CASE(testDeclareTmp)
+QPID_AUTO_TEST_CASE(testDeclareTmp)
{
QueueRegistry reg;
std::pair<Queue::shared_ptr, bool> qc;
@@ -58,8 +61,8 @@ QPID_AUTO_TEST_CASE(testDeclareTmp)
BOOST_CHECK(qc.second);
BOOST_CHECK_EQUAL(std::string("tmp_1"), qc.first->getName());
}
-
-QPID_AUTO_TEST_CASE(testFind)
+
+QPID_AUTO_TEST_CASE(testFind)
{
std::string foo("foo");
std::string bar("bar");
@@ -75,7 +78,7 @@ QPID_AUTO_TEST_CASE(testFind)
BOOST_CHECK_EQUAL(bar, q->getName());
}
-QPID_AUTO_TEST_CASE(testDestroy)
+QPID_AUTO_TEST_CASE(testDestroy)
{
std::string foo("foo");
QueueRegistry reg;
@@ -92,3 +95,5 @@ QPID_AUTO_TEST_CASE(testDestroy)
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/QueueTest.cpp b/cpp/src/tests/QueueTest.cpp
index 20b3d90eb6..6c2adf5c87 100644
--- a/cpp/src/tests/QueueTest.cpp
+++ b/cpp/src/tests/QueueTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -18,29 +18,44 @@
* under the License.
*
*/
+#include "MessageUtils.h"
#include "unit_test.h"
+#include "test_tools.h"
#include "qpid/Exception.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/broker/DeliverableMessage.h"
+#include "qpid/broker/FanOutExchange.h"
#include "qpid/broker/Queue.h"
#include "qpid/broker/Deliverable.h"
#include "qpid/broker/ExchangeRegistry.h"
#include "qpid/broker/QueueRegistry.h"
+#include "qpid/broker/NullMessageStore.h"
+#include "qpid/broker/ExpiryPolicy.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/client/QueueOptions.h"
+#include "qpid/framing/AMQFrame.h"
#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/reply_exceptions.h"
#include <iostream>
#include "boost/format.hpp"
using boost::intrusive_ptr;
using namespace qpid;
using namespace qpid::broker;
+using namespace qpid::client;
using namespace qpid::framing;
using namespace qpid::sys;
+namespace qpid {
+namespace tests {
+
class TestConsumer : public virtual Consumer{
public:
- typedef boost::shared_ptr<TestConsumer> shared_ptr;
+ typedef boost::shared_ptr<TestConsumer> shared_ptr;
intrusive_ptr<Message> last;
bool received;
- TestConsumer(): received(false) {};
+ TestConsumer(bool acquire = true):Consumer(acquire), received(false) {};
virtual bool deliver(QueuedMessage& msg){
last = msg.payload;
@@ -53,19 +68,20 @@ public:
class FailOnDeliver : public Deliverable
{
- Message msg;
+ boost::intrusive_ptr<Message> msg;
public:
- void deliverTo(Queue::shared_ptr& queue)
+ FailOnDeliver() : msg(MessageUtils::createMessage()) {}
+ void deliverTo(const boost::shared_ptr<Queue>& queue)
{
throw Exception(QPID_MSG("Invalid delivery to " << queue->getName()));
}
- Message& getMessage() { return msg; }
+ Message& getMessage() { return *(msg.get()); }
};
-intrusive_ptr<Message> message(std::string exchange, std::string routingKey) {
+intrusive_ptr<Message> create_message(std::string exchange, std::string routingKey) {
intrusive_ptr<Message> msg(new Message());
- AMQFrame method(in_place<MessageTransferBody>(ProtocolVersion(), exchange, 0, 0));
- AMQFrame header(in_place<AMQHeaderBody>());
+ AMQFrame method((MessageTransferBody(ProtocolVersion(), exchange, 0, 0)));
+ AMQFrame header((AMQHeaderBody()));
msg->getFrames().append(method);
msg->getFrames().append(header);
msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(routingKey);
@@ -77,68 +93,69 @@ QPID_AUTO_TEST_SUITE(QueueTestSuite)
QPID_AUTO_TEST_CASE(testAsyncMessage) {
Queue::shared_ptr queue(new Queue("my_test_queue", true));
intrusive_ptr<Message> received;
-
- TestConsumer c1;
+
+ TestConsumer::shared_ptr c1(new TestConsumer());
queue->consume(c1);
-
-
+
+
//Test basic delivery:
- intrusive_ptr<Message> msg1 = message("e", "A");
- msg1->enqueueAsync();//this is done on enqueue which is not called from process
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ msg1->enqueueAsync(queue, 0);//this is done on enqueue which is not called from process
queue->process(msg1);
sleep(2);
-
- BOOST_CHECK(!c1.received);
+
+ BOOST_CHECK(!c1->received);
msg1->enqueueComplete();
-
+
received = queue->get().payload;
- BOOST_CHECK_EQUAL(msg1.get(), received.get());
+ BOOST_CHECK_EQUAL(msg1.get(), received.get());
}
-
-
+
+
QPID_AUTO_TEST_CASE(testAsyncMessageCount){
Queue::shared_ptr queue(new Queue("my_test_queue", true));
- intrusive_ptr<Message> msg1 = message("e", "A");
- msg1->enqueueAsync();//this is done on enqueue which is not called from process
-
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ msg1->enqueueAsync(queue, 0);//this is done on enqueue which is not called from process
+
queue->process(msg1);
sleep(2);
uint32_t compval=0;
- BOOST_CHECK_EQUAL(compval, queue->getMessageCount());
+ BOOST_CHECK_EQUAL(compval, queue->getEnqueueCompleteMessageCount());
msg1->enqueueComplete();
compval=1;
- BOOST_CHECK_EQUAL(compval, queue->getMessageCount());
+ BOOST_CHECK_EQUAL(compval, queue->getEnqueueCompleteMessageCount());
+ BOOST_CHECK_EQUAL(compval, queue->getMessageCount());
}
QPID_AUTO_TEST_CASE(testConsumers){
Queue::shared_ptr queue(new Queue("my_queue", true));
-
+
//Test adding consumers:
- TestConsumer c1;
- TestConsumer c2;
+ TestConsumer::shared_ptr c1(new TestConsumer());
+ TestConsumer::shared_ptr c2(new TestConsumer());
queue->consume(c1);
queue->consume(c2);
-
+
BOOST_CHECK_EQUAL(uint32_t(2), queue->getConsumerCount());
-
+
//Test basic delivery:
- intrusive_ptr<Message> msg1 = message("e", "A");
- intrusive_ptr<Message> msg2 = message("e", "B");
- intrusive_ptr<Message> msg3 = message("e", "C");
-
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "B");
+ intrusive_ptr<Message> msg3 = create_message("e", "C");
+
queue->deliver(msg1);
BOOST_CHECK(queue->dispatch(c1));
- BOOST_CHECK_EQUAL(msg1.get(), c1.last.get());
-
+ BOOST_CHECK_EQUAL(msg1.get(), c1->last.get());
+
queue->deliver(msg2);
BOOST_CHECK(queue->dispatch(c2));
- BOOST_CHECK_EQUAL(msg2.get(), c2.last.get());
-
- c1.received = false;
+ BOOST_CHECK_EQUAL(msg2.get(), c2->last.get());
+
+ c1->received = false;
queue->deliver(msg3);
BOOST_CHECK(queue->dispatch(c1));
- BOOST_CHECK_EQUAL(msg3.get(), c1.last.get());
-
+ BOOST_CHECK_EQUAL(msg3.get(), c1->last.get());
+
//Test cancellation:
queue->cancel(c1);
BOOST_CHECK_EQUAL(uint32_t(1), queue->getConsumerCount());
@@ -152,15 +169,15 @@ QPID_AUTO_TEST_CASE(testRegistry){
registry.declare("queue1", true, true);
registry.declare("queue2", true, true);
registry.declare("queue3", true, true);
-
+
BOOST_CHECK(registry.find("queue1"));
BOOST_CHECK(registry.find("queue2"));
BOOST_CHECK(registry.find("queue3"));
-
+
registry.destroy("queue1");
registry.destroy("queue2");
registry.destroy("queue3");
-
+
BOOST_CHECK(!registry.find("queue1"));
BOOST_CHECK(!registry.find("queue2"));
BOOST_CHECK(!registry.find("queue3"));
@@ -168,17 +185,17 @@ QPID_AUTO_TEST_CASE(testRegistry){
QPID_AUTO_TEST_CASE(testDequeue){
Queue::shared_ptr queue(new Queue("my_queue", true));
- intrusive_ptr<Message> msg1 = message("e", "A");
- intrusive_ptr<Message> msg2 = message("e", "B");
- intrusive_ptr<Message> msg3 = message("e", "C");
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "B");
+ intrusive_ptr<Message> msg3 = create_message("e", "C");
intrusive_ptr<Message> received;
-
+
queue->deliver(msg1);
queue->deliver(msg2);
queue->deliver(msg3);
-
+
BOOST_CHECK_EQUAL(uint32_t(3), queue->getMessageCount());
-
+
received = queue->get().payload;
BOOST_CHECK_EQUAL(msg1.get(), received.get());
BOOST_CHECK_EQUAL(uint32_t(2), queue->getMessageCount());
@@ -187,23 +204,22 @@ QPID_AUTO_TEST_CASE(testDequeue){
BOOST_CHECK_EQUAL(msg2.get(), received.get());
BOOST_CHECK_EQUAL(uint32_t(1), queue->getMessageCount());
- TestConsumer consumer;
+ TestConsumer::shared_ptr consumer(new TestConsumer());
queue->consume(consumer);
queue->dispatch(consumer);
- if (!consumer.received)
+ if (!consumer->received)
sleep(2);
- BOOST_CHECK_EQUAL(msg3.get(), consumer.last.get());
+ BOOST_CHECK_EQUAL(msg3.get(), consumer->last.get());
BOOST_CHECK_EQUAL(uint32_t(0), queue->getMessageCount());
received = queue->get().payload;
BOOST_CHECK(!received);
BOOST_CHECK_EQUAL(uint32_t(0), queue->getMessageCount());
-
+
}
-QPID_AUTO_TEST_CASE(testBound)
-{
+QPID_AUTO_TEST_CASE(testBound){
//test the recording of bindings, and use of those to allow a queue to be unbound
string key("my-key");
FieldTable args;
@@ -231,11 +247,856 @@ QPID_AUTO_TEST_CASE(testBound)
queue->unbind(exchanges, queue);
//ensure the remaining exchanges don't still have the queue bound to them:
- FailOnDeliver deliverable;
+ FailOnDeliver deliverable;
exchange1->route(deliverable, key, &args);
exchange3->route(deliverable, key, &args);
}
-QPID_AUTO_TEST_SUITE_END()
+QPID_AUTO_TEST_CASE(testPersistLastNodeStanding){
+ client::QueueOptions args;
+ args.setPersistLastNode();
+
+ Queue::shared_ptr queue(new Queue("my-queue", true));
+ queue->configure(args);
+
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "B");
+ intrusive_ptr<Message> msg3 = create_message("e", "C");
+
+ //enqueue 2 messages
+ queue->deliver(msg1);
+ queue->deliver(msg2);
+
+ //change mode
+ queue->setLastNodeFailure();
+
+ //enqueue 1 message
+ queue->deliver(msg3);
+
+ //check all have persistent ids.
+ BOOST_CHECK(msg1->isPersistent());
+ BOOST_CHECK(msg2->isPersistent());
+ BOOST_CHECK(msg3->isPersistent());
+
+}
+
+
+QPID_AUTO_TEST_CASE(testSeek){
+
+ Queue::shared_ptr queue(new Queue("my-queue", true));
+
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "B");
+ intrusive_ptr<Message> msg3 = create_message("e", "C");
+
+ //enqueue 2 messages
+ queue->deliver(msg1);
+ queue->deliver(msg2);
+ queue->deliver(msg3);
+
+ TestConsumer::shared_ptr consumer(new TestConsumer(false));
+ SequenceNumber seq(2);
+ consumer->position = seq;
+
+ QueuedMessage qm;
+ queue->dispatch(consumer);
+
+ BOOST_CHECK_EQUAL(msg3.get(), consumer->last.get());
+ queue->dispatch(consumer);
+ queue->dispatch(consumer); // make sure over-run is safe
+
+}
+
+QPID_AUTO_TEST_CASE(testSearch){
+
+ Queue::shared_ptr queue(new Queue("my-queue", true));
+
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "B");
+ intrusive_ptr<Message> msg3 = create_message("e", "C");
+
+ //enqueue 2 messages
+ queue->deliver(msg1);
+ queue->deliver(msg2);
+ queue->deliver(msg3);
+
+ SequenceNumber seq(2);
+ QueuedMessage qm = queue->find(seq);
+
+ BOOST_CHECK_EQUAL(seq.getValue(), qm.position.getValue());
+
+ queue->acquire(qm);
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 2u);
+ SequenceNumber seq1(3);
+ QueuedMessage qm1 = queue->find(seq1);
+ BOOST_CHECK_EQUAL(seq1.getValue(), qm1.position.getValue());
+
+}
+const std::string nullxid = "";
+
+class SimpleDummyCtxt : public TransactionContext {};
+
+class DummyCtxt : public TPCTransactionContext
+{
+ const std::string xid;
+ public:
+ DummyCtxt(const std::string& _xid) : xid(_xid) {}
+ static std::string getXid(TransactionContext& ctxt)
+ {
+ DummyCtxt* c(dynamic_cast<DummyCtxt*>(&ctxt));
+ return c ? c->xid : nullxid;
+ }
+};
+
+class TestMessageStoreOC : public MessageStore
+{
+ std::set<std::string> prepared;
+ uint64_t nextPersistenceId;
+ public:
+
+ uint enqCnt;
+ uint deqCnt;
+ bool error;
+
+ TestMessageStoreOC() : MessageStore(),nextPersistenceId(1),enqCnt(0),deqCnt(0),error(false) {}
+ ~TestMessageStoreOC(){}
+
+ virtual void dequeue(TransactionContext*,
+ const boost::intrusive_ptr<PersistableMessage>& /*msg*/,
+ const PersistableQueue& /*queue*/)
+ {
+ if (error) throw Exception("Dequeue error test");
+ deqCnt++;
+ }
+
+ virtual void enqueue(TransactionContext*,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& /* queue */)
+ {
+ if (error) throw Exception("Enqueue error test");
+ enqCnt++;
+ msg->enqueueComplete();
+ }
+
+ void createError()
+ {
+ error=true;
+ }
+
+ bool init(const Options*) { return true; }
+ void truncateInit(const bool) {}
+ void create(PersistableQueue& queue, const framing::FieldTable&) { queue.setPersistenceId(nextPersistenceId++); }
+ void destroy(PersistableQueue&) {}
+ void create(const PersistableExchange& exchange, const framing::FieldTable&) { exchange.setPersistenceId(nextPersistenceId++); }
+ void destroy(const PersistableExchange&) {}
+ void bind(const PersistableExchange&, const PersistableQueue&, const std::string&, const framing::FieldTable&) {}
+ void unbind(const PersistableExchange&, const PersistableQueue&, const std::string&, const framing::FieldTable&) {}
+ void create(const PersistableConfig& config) { config.setPersistenceId(nextPersistenceId++); }
+ void destroy(const PersistableConfig&) {}
+ void stage(const boost::intrusive_ptr<PersistableMessage>&) {}
+ void destroy(PersistableMessage&) {}
+ void appendContent(const boost::intrusive_ptr<const PersistableMessage>&, const std::string&) {}
+ void loadContent(const qpid::broker::PersistableQueue&, const boost::intrusive_ptr<const PersistableMessage>&,
+ std::string&, uint64_t, uint32_t) { throw qpid::framing::InternalErrorException("Can't load content; persistence not enabled"); }
+ void flush(const qpid::broker::PersistableQueue&) {}
+ uint32_t outstandingQueueAIO(const PersistableQueue&) { return 0; }
+
+ std::auto_ptr<TransactionContext> begin() { return std::auto_ptr<TransactionContext>(new SimpleDummyCtxt()); }
+ std::auto_ptr<TPCTransactionContext> begin(const std::string& xid) { return std::auto_ptr<TPCTransactionContext>(new DummyCtxt(xid)); }
+ void prepare(TPCTransactionContext& ctxt) { prepared.insert(DummyCtxt::getXid(ctxt)); }
+ void commit(TransactionContext& ctxt) { prepared.erase(DummyCtxt::getXid(ctxt)); }
+ void abort(TransactionContext& ctxt) { prepared.erase(DummyCtxt::getXid(ctxt)); }
+ void collectPreparedXids(std::set<std::string>& out) { out.insert(prepared.begin(), prepared.end()); }
+
+ void recover(RecoveryManager&) {}
+};
+
+
+QPID_AUTO_TEST_CASE(testLVQOrdering){
+
+ client::QueueOptions args;
+ // set queue mode
+ args.setOrdering(client::LVQ);
+
+ Queue::shared_ptr queue(new Queue("my-queue", true ));
+ queue->configure(args);
+
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "B");
+ intrusive_ptr<Message> msg3 = create_message("e", "C");
+ intrusive_ptr<Message> msg4 = create_message("e", "D");
+ intrusive_ptr<Message> received;
+
+ //set deliever match for LVQ a,b,c,a
+
+ string key;
+ args.getLVQKey(key);
+ BOOST_CHECK_EQUAL(key, "qpid.LVQ_key");
+
+
+ msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+ msg2->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"b");
+ msg3->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"c");
+ msg4->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+
+ //enqueue 4 message
+ queue->deliver(msg1);
+ queue->deliver(msg2);
+ queue->deliver(msg3);
+ queue->deliver(msg4);
+
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg4.get(), received.get());
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg2.get(), received.get());
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg3.get(), received.get());
+
+ intrusive_ptr<Message> msg5 = create_message("e", "A");
+ intrusive_ptr<Message> msg6 = create_message("e", "B");
+ intrusive_ptr<Message> msg7 = create_message("e", "C");
+ msg5->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+ msg6->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"b");
+ msg7->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"c");
+ queue->deliver(msg5);
+ queue->deliver(msg6);
+ queue->deliver(msg7);
+
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg5.get(), received.get());
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg6.get(), received.get());
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg7.get(), received.get());
+
+}
+
+QPID_AUTO_TEST_CASE(testLVQEmptyKey){
+
+ client::QueueOptions args;
+ // set queue mode
+ args.setOrdering(client::LVQ);
+ Queue::shared_ptr queue(new Queue("my-queue", true ));
+ queue->configure(args);
+
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "B");
+
+ string key;
+ args.getLVQKey(key);
+ BOOST_CHECK_EQUAL(key, "qpid.LVQ_key");
+
+
+ msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+ queue->deliver(msg1);
+ queue->deliver(msg2);
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 2u);
+
+}
+
+QPID_AUTO_TEST_CASE(testLVQAcquire){
+
+ client::QueueOptions args;
+ // set queue mode
+ args.setOrdering(client::LVQ);
+
+ Queue::shared_ptr queue(new Queue("my-queue", true ));
+ queue->configure(args);
+
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "B");
+ intrusive_ptr<Message> msg3 = create_message("e", "C");
+ intrusive_ptr<Message> msg4 = create_message("e", "D");
+ intrusive_ptr<Message> msg5 = create_message("e", "F");
+ intrusive_ptr<Message> msg6 = create_message("e", "G");
+
+ //set deliever match for LVQ a,b,c,a
+
+ string key;
+ args.getLVQKey(key);
+ BOOST_CHECK_EQUAL(key, "qpid.LVQ_key");
+
+
+ msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+ msg2->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"b");
+ msg3->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"c");
+ msg4->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+ msg5->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"b");
+ msg6->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"c");
+
+ //enqueue 4 message
+ queue->deliver(msg1);
+ queue->deliver(msg2);
+ queue->deliver(msg3);
+ queue->deliver(msg4);
+
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
+
+ framing::SequenceNumber sequence(1);
+ QueuedMessage qmsg(queue.get(), msg1, sequence);
+ QueuedMessage qmsg2(queue.get(), msg2, ++sequence);
+
+ BOOST_CHECK(!queue->acquire(qmsg));
+ BOOST_CHECK(queue->acquire(qmsg2));
+
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 2u);
+
+ queue->deliver(msg5);
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
+
+ // set mode to no browse and check
+ args.setOrdering(client::LVQ_NO_BROWSE);
+ queue->configure(args);
+ TestConsumer::shared_ptr c1(new TestConsumer(false));
+
+ queue->dispatch(c1);
+ queue->dispatch(c1);
+ queue->dispatch(c1);
+
+ queue->deliver(msg6);
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
+
+ intrusive_ptr<Message> received;
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg4.get(), received.get());
+
+}
+
+QPID_AUTO_TEST_CASE(testLVQMultiQueue){
+
+ client::QueueOptions args;
+ // set queue mode
+ args.setOrdering(client::LVQ);
+
+ Queue::shared_ptr queue1(new Queue("my-queue", true ));
+ Queue::shared_ptr queue2(new Queue("my-queue", true ));
+ intrusive_ptr<Message> received;
+ queue1->configure(args);
+ queue2->configure(args);
+
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "A");
+
+ string key;
+ args.getLVQKey(key);
+ BOOST_CHECK_EQUAL(key, "qpid.LVQ_key");
+
+ msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+ msg2->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+
+ queue1->deliver(msg1);
+ queue2->deliver(msg1);
+ queue1->deliver(msg2);
+
+ received = queue1->get().payload;
+ BOOST_CHECK_EQUAL(msg2.get(), received.get());
+
+ received = queue2->get().payload;
+ BOOST_CHECK_EQUAL(msg1.get(), received.get());
+
+}
+
+QPID_AUTO_TEST_CASE(testLVQRecover){
+
+/* simulate this
+ 1. start 2 nodes
+ 2. create cluster durable lvq
+ 3. send a transient message to the queue
+ 4. kill one of the nodes (to trigger force persistent behaviour)...
+ 5. then restart it (to turn off force persistent behaviour)
+ 6. send another transient message with same lvq key as in 3
+ 7. kill the second node again (retrigger force persistent)
+ 8. stop and recover the first node
+*/
+ TestMessageStoreOC testStore;
+ client::QueueOptions args;
+ // set queue mode
+ args.setOrdering(client::LVQ);
+ args.setPersistLastNode();
+
+ Queue::shared_ptr queue1(new Queue("my-queue", true, &testStore));
+ intrusive_ptr<Message> received;
+ queue1->configure(args);
+
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "A");
+ // 2
+ string key;
+ args.getLVQKey(key);
+ BOOST_CHECK_EQUAL(key, "qpid.LVQ_key");
+
+ msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+ msg2->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+ // 3
+ queue1->deliver(msg1);
+ // 4
+ queue1->setLastNodeFailure();
+ BOOST_CHECK_EQUAL(testStore.enqCnt, 1u);
+ // 5
+ queue1->clearLastNodeFailure();
+ BOOST_CHECK_EQUAL(testStore.enqCnt, 1u);
+ // 6
+ queue1->deliver(msg2);
+ BOOST_CHECK_EQUAL(testStore.enqCnt, 1u);
+ queue1->setLastNodeFailure();
+ BOOST_CHECK_EQUAL(testStore.enqCnt, 2u);
+ BOOST_CHECK_EQUAL(testStore.deqCnt, 1u);
+}
+
+void addMessagesToQueue(uint count, Queue& queue, uint oddTtl = 200, uint evenTtl = 0)
+{
+ for (uint i = 0; i < count; i++) {
+ intrusive_ptr<Message> m = create_message("exchange", "key");
+ if (i % 2) {
+ if (oddTtl) m->getProperties<DeliveryProperties>()->setTtl(oddTtl);
+ } else {
+ if (evenTtl) m->getProperties<DeliveryProperties>()->setTtl(evenTtl);
+ }
+ m->setTimestamp(new broker::ExpiryPolicy);
+ queue.deliver(m);
+ }
+}
+
+QPID_AUTO_TEST_CASE(testPurgeExpired) {
+ Queue queue("my-queue");
+ addMessagesToQueue(10, queue);
+ BOOST_CHECK_EQUAL(queue.getMessageCount(), 10u);
+ ::usleep(300*1000);
+ queue.purgeExpired();
+ BOOST_CHECK_EQUAL(queue.getMessageCount(), 5u);
+}
+
+QPID_AUTO_TEST_CASE(testQueueCleaner) {
+ Timer timer;
+ QueueRegistry queues;
+ Queue::shared_ptr queue = queues.declare("my-queue").first;
+ addMessagesToQueue(10, *queue, 200, 400);
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 10u);
+
+ QueueCleaner cleaner(queues, timer);
+ cleaner.start(100 * qpid::sys::TIME_MSEC);
+ ::usleep(300*1000);
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 5u);
+ ::usleep(300*1000);
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 0u);
+}
+
+QPID_AUTO_TEST_CASE(testMultiQueueLastNode){
+
+ TestMessageStoreOC testStore;
+ client::QueueOptions args;
+ args.setPersistLastNode();
+
+ Queue::shared_ptr queue1(new Queue("queue1", true, &testStore ));
+ queue1->configure(args);
+ Queue::shared_ptr queue2(new Queue("queue2", true, &testStore ));
+ queue2->configure(args);
+
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+
+ queue1->deliver(msg1);
+ queue2->deliver(msg1);
+
+ //change mode
+ queue1->setLastNodeFailure();
+ BOOST_CHECK_EQUAL(testStore.enqCnt, 1u);
+ queue2->setLastNodeFailure();
+ BOOST_CHECK_EQUAL(testStore.enqCnt, 2u);
+
+ // check they don't get stored twice
+ queue1->setLastNodeFailure();
+ queue2->setLastNodeFailure();
+ BOOST_CHECK_EQUAL(testStore.enqCnt, 2u);
+
+ intrusive_ptr<Message> msg2 = create_message("e", "B");
+ queue1->deliver(msg2);
+ queue2->deliver(msg2);
+
+ queue1->clearLastNodeFailure();
+ queue2->clearLastNodeFailure();
+ // check only new messages get forced
+ queue1->setLastNodeFailure();
+ queue2->setLastNodeFailure();
+ BOOST_CHECK_EQUAL(testStore.enqCnt, 4u);
+
+ // check no failure messages are stored
+ queue1->clearLastNodeFailure();
+ queue2->clearLastNodeFailure();
+
+ intrusive_ptr<Message> msg3 = create_message("e", "B");
+ queue1->deliver(msg3);
+ queue2->deliver(msg3);
+ BOOST_CHECK_EQUAL(testStore.enqCnt, 4u);
+ queue1->setLastNodeFailure();
+ queue2->setLastNodeFailure();
+ BOOST_CHECK_EQUAL(testStore.enqCnt, 6u);
+
+ // check requeue 1
+ intrusive_ptr<Message> msg4 = create_message("e", "C");
+ intrusive_ptr<Message> msg5 = create_message("e", "D");
+
+ framing::SequenceNumber sequence(1);
+ QueuedMessage qmsg1(queue1.get(), msg4, sequence);
+ QueuedMessage qmsg2(queue2.get(), msg5, ++sequence);
+
+ queue1->requeue(qmsg1);
+ BOOST_CHECK_EQUAL(testStore.enqCnt, 7u);
+
+ // check requeue 2
+ queue2->clearLastNodeFailure();
+ queue2->requeue(qmsg2);
+ BOOST_CHECK_EQUAL(testStore.enqCnt, 7u);
+ queue2->setLastNodeFailure();
+ BOOST_CHECK_EQUAL(testStore.enqCnt, 8u);
+
+ queue2->clearLastNodeFailure();
+ queue2->setLastNodeFailure();
+ BOOST_CHECK_EQUAL(testStore.enqCnt, 8u);
+}
+
+QPID_AUTO_TEST_CASE(testLastNodeRecoverAndFail){
+/*
+simulate this:
+ 1. start two nodes
+ 2. create cluster durable queue and add some messages
+ 3. kill one node (trigger force-persistent behaviour)
+ 4. stop and recover remaining node
+ 5. add another node
+ 6. kill that new node again
+make sure that an attempt to re-enqueue a message does not happen which will
+result in the last man standing exiting with an error.
+
+we need to make sure that recover is safe, i.e. messages are
+not requeued to the store.
+*/
+ TestMessageStoreOC testStore;
+ client::QueueOptions args;
+ // set queue mode
+ args.setPersistLastNode();
+
+ Queue::shared_ptr queue1(new Queue("my-queue", true, &testStore));
+ intrusive_ptr<Message> received;
+ queue1->configure(args);
+
+ // check requeue 1
+ intrusive_ptr<Message> msg1 = create_message("e", "C");
+ intrusive_ptr<Message> msg2 = create_message("e", "D");
+
+ queue1->recover(msg1);
+
+ queue1->setLastNodeFailure();
+ BOOST_CHECK_EQUAL(testStore.enqCnt, 0u);
+
+ queue1->clearLastNodeFailure();
+ BOOST_CHECK_EQUAL(testStore.enqCnt, 0u);
+
+ queue1->deliver(msg2);
+ BOOST_CHECK_EQUAL(testStore.enqCnt, 0u);
+ queue1->setLastNodeFailure();
+ BOOST_CHECK_EQUAL(testStore.enqCnt, 1u);
+
+}
+
+QPID_AUTO_TEST_CASE(testLastNodeJournalError){
+/*
+simulate store exception going into last node standing
+
+*/
+ TestMessageStoreOC testStore;
+ client::QueueOptions args;
+ // set queue mode
+ args.setPersistLastNode();
+
+ Queue::shared_ptr queue1(new Queue("my-queue", true, &testStore));
+ intrusive_ptr<Message> received;
+ queue1->configure(args);
+
+ // check requeue 1
+ intrusive_ptr<Message> msg1 = create_message("e", "C");
+
+ queue1->deliver(msg1);
+ testStore.createError();
+
+ ScopedSuppressLogging sl; // Suppress messages for expected errors.
+ queue1->setLastNodeFailure();
+ BOOST_CHECK_EQUAL(testStore.enqCnt, 0u);
+
+}
+
+intrusive_ptr<Message> mkMsg(MessageStore& store, std::string content = "", bool durable = false)
+{
+ intrusive_ptr<Message> msg = MessageUtils::createMessage("", "", durable);
+ if (content.size()) MessageUtils::addContent(msg, content);
+ msg->setStore(&store);
+ return msg;
+}
+
+QPID_AUTO_TEST_CASE(testFlowToDiskBlocking){
+
+ TestMessageStoreOC testStore;
+ client::QueueOptions args0; // No size policy
+ client::QueueOptions args1;
+ args1.setSizePolicy(FLOW_TO_DISK, 0, 1);
+ client::QueueOptions args2;
+ args2.setSizePolicy(FLOW_TO_DISK, 0, 2);
+
+ // --- Fanout exchange bound to single transient queue -------------------------------------------------------------
+
+ FanOutExchange sbtFanout1("sbtFanout1", false, args0); // single binding to transient queue
+ Queue::shared_ptr tq1(new Queue("tq1", true)); // transient w/ limit
+ tq1->configure(args1);
+ sbtFanout1.bind(tq1, "", 0);
+
+ intrusive_ptr<Message> msg01 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
+ DeliverableMessage dmsg01(msg01);
+ sbtFanout1.route(dmsg01, "", 0); // Brings queue 1 to capacity limit
+ msg01->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg01->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(1u, tq1->getMessageCount());
+
+ intrusive_ptr<Message> msg02 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
+ DeliverableMessage dmsg02(msg02);
+ BOOST_CHECK_THROW(sbtFanout1.route(dmsg02, "", 0), ResourceLimitExceededException);
+ msg02->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg02->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(1u, tq1->getMessageCount());
+
+ intrusive_ptr<Message> msg03 = mkMsg(testStore, std::string(5, 'X'), true); // durable w/ content
+ DeliverableMessage dmsg03(msg03);
+ BOOST_CHECK_THROW(sbtFanout1.route(dmsg03, "", 0), ResourceLimitExceededException);
+ msg03->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg03->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(1u, tq1->getMessageCount());
+
+ intrusive_ptr<Message> msg04 = mkMsg(testStore); // transient no content
+ DeliverableMessage dmsg04(msg04);
+ BOOST_CHECK_THROW(sbtFanout1.route(dmsg04, "", 0), ResourceLimitExceededException);
+ msg04->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg04->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(1u, tq1->getMessageCount());
+
+ intrusive_ptr<Message> msg05 = mkMsg(testStore, "", true); // durable no content
+ DeliverableMessage dmsg05(msg05);
+ BOOST_CHECK_THROW(sbtFanout1.route(dmsg05, "", 0), ResourceLimitExceededException);
+ msg05->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg05->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(1u, tq1->getMessageCount());
+
+ // --- Fanout exchange bound to single durable queue ---------------------------------------------------------------
+
+ FanOutExchange sbdFanout2("sbdFanout2", false, args0); // single binding to durable queue
+ Queue::shared_ptr dq2(new Queue("dq2", true, &testStore)); // durable w/ limit
+ dq2->configure(args1);
+ sbdFanout2.bind(dq2, "", 0);
+
+ intrusive_ptr<Message> msg06 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
+ DeliverableMessage dmsg06(msg06);
+ sbdFanout2.route(dmsg06, "", 0); // Brings queue 2 to capacity limit
+ msg06->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg06->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(1u, dq2->getMessageCount());
+
+ intrusive_ptr<Message> msg07 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
+ DeliverableMessage dmsg07(msg07);
+ sbdFanout2.route(dmsg07, "", 0);
+ msg07->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg07->isContentReleased(), true);
+ BOOST_CHECK_EQUAL(2u, dq2->getMessageCount());
+
+ intrusive_ptr<Message> msg08 = mkMsg(testStore, std::string(5, 'X'), true); // durable w/ content
+ DeliverableMessage dmsg08(msg08);
+ sbdFanout2.route(dmsg08, "", 0);
+ msg08->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg08->isContentReleased(), true);
+ BOOST_CHECK_EQUAL(3u, dq2->getMessageCount());
+
+ intrusive_ptr<Message> msg09 = mkMsg(testStore); // transient no content
+ DeliverableMessage dmsg09(msg09);
+ sbdFanout2.route(dmsg09, "", 0);
+ msg09->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg09->isContentReleased(), true);
+ BOOST_CHECK_EQUAL(4u, dq2->getMessageCount());
+
+ intrusive_ptr<Message> msg10 = mkMsg(testStore, "", true); // durable no content
+ DeliverableMessage dmsg10(msg10);
+ sbdFanout2.route(dmsg10, "", 0);
+ msg10->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg10->isContentReleased(), true);
+ BOOST_CHECK_EQUAL(5u, dq2->getMessageCount());
+
+ // --- Fanout exchange bound to multiple durable queues ------------------------------------------------------------
+
+ FanOutExchange mbdFanout3("mbdFanout3", false, args0); // multiple bindings to durable queues
+ Queue::shared_ptr dq3(new Queue("dq3", true, &testStore)); // durable w/ limit 2
+ dq3->configure(args2);
+ mbdFanout3.bind(dq3, "", 0);
+ Queue::shared_ptr dq4(new Queue("dq4", true, &testStore)); // durable w/ limit 1
+ dq4->configure(args1);
+ mbdFanout3.bind(dq4, "", 0);
+ Queue::shared_ptr dq5(new Queue("dq5", true, &testStore)); // durable no limit
+ dq5->configure(args0);
+ mbdFanout3.bind(dq5, "", 0);
+
+ intrusive_ptr<Message> msg11 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
+ DeliverableMessage dmsg11(msg11);
+ mbdFanout3.route(dmsg11, "", 0); // Brings queues 3 and 4 to capacity limit
+ msg11->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg11->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(1u, dq3->getMessageCount());
+ BOOST_CHECK_EQUAL(1u, dq4->getMessageCount());
+ BOOST_CHECK_EQUAL(1u, dq5->getMessageCount());
+
+ intrusive_ptr<Message> msg12 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
+ DeliverableMessage dmsg12(msg12);
+ mbdFanout3.route(dmsg12, "", 0);
+ msg12->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg12->isContentReleased(), false); // XXXX - consequence of transient msg multi-queue ftd policy-handling limitations, fix in broker at some point!
+ BOOST_CHECK_EQUAL(2u, dq3->getMessageCount());
+ BOOST_CHECK_EQUAL(2u, dq4->getMessageCount());
+ BOOST_CHECK_EQUAL(2u, dq5->getMessageCount());
+
+ intrusive_ptr<Message> msg13 = mkMsg(testStore, std::string(5, 'X'), true); // durable w/ content
+ DeliverableMessage dmsg13(msg13);
+ mbdFanout3.route(dmsg13, "", 0);
+ msg13->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg13->isContentReleased(), true);
+ BOOST_CHECK_EQUAL(3u, dq3->getMessageCount());
+ BOOST_CHECK_EQUAL(3u, dq4->getMessageCount());
+ BOOST_CHECK_EQUAL(3u, dq5->getMessageCount());
+
+ intrusive_ptr<Message> msg14 = mkMsg(testStore); // transient no content
+ DeliverableMessage dmsg14(msg14);
+ mbdFanout3.route(dmsg14, "", 0);
+ msg14->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg14->isContentReleased(), false); // XXXX - consequence of transient msg multi-queue ftd policy-handling limitations, fix in broker at some point!
+ BOOST_CHECK_EQUAL(4u, dq3->getMessageCount());
+ BOOST_CHECK_EQUAL(4u, dq4->getMessageCount());
+ BOOST_CHECK_EQUAL(4u, dq5->getMessageCount());
+
+ intrusive_ptr<Message> msg15 = mkMsg(testStore, "", true); // durable no content
+ DeliverableMessage dmsg15(msg15);
+ mbdFanout3.route(dmsg15, "", 0);
+ msg15->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg15->isContentReleased(), true);
+ BOOST_CHECK_EQUAL(5u, dq3->getMessageCount());
+ BOOST_CHECK_EQUAL(5u, dq4->getMessageCount());
+ BOOST_CHECK_EQUAL(5u, dq5->getMessageCount());
+
+ // Bind a transient queue, this should block the release of any further messages.
+ // Note: this will result in a violation of the count policy of dq3 and dq4 - but this
+ // is expected until a better overall multi-queue design is implemented. Similarly
+ // for the other tests in this section.
+
+ Queue::shared_ptr tq6(new Queue("tq6", true)); // transient no limit
+ tq6->configure(args0);
+ mbdFanout3.bind(tq6, "", 0);
+
+ intrusive_ptr<Message> msg16 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
+ DeliverableMessage dmsg16(msg16);
+ mbdFanout3.route(dmsg16, "", 0);
+ msg16->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg16->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(6u, dq3->getMessageCount());
+ BOOST_CHECK_EQUAL(6u, dq4->getMessageCount());
+ BOOST_CHECK_EQUAL(6u, dq5->getMessageCount());
+
+ intrusive_ptr<Message> msg17 = mkMsg(testStore, std::string(5, 'X'), true); // durable w/ content
+ DeliverableMessage dmsg17(msg17);
+ mbdFanout3.route(dmsg17, "", 0);
+ msg17->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg17->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(7u, dq3->getMessageCount());
+ BOOST_CHECK_EQUAL(7u, dq4->getMessageCount());
+ BOOST_CHECK_EQUAL(7u, dq5->getMessageCount());
+
+ intrusive_ptr<Message> msg18 = mkMsg(testStore); // transient no content
+ DeliverableMessage dmsg18(msg18);
+ mbdFanout3.route(dmsg18, "", 0);
+ msg18->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg18->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(8u, dq3->getMessageCount());
+ BOOST_CHECK_EQUAL(8u, dq4->getMessageCount());
+ BOOST_CHECK_EQUAL(8u, dq5->getMessageCount());
+
+ intrusive_ptr<Message> msg19 = mkMsg(testStore, "", true); // durable no content
+ DeliverableMessage dmsg19(msg19);
+ mbdFanout3.route(dmsg19, "", 0);
+ msg19->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg19->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(9u, dq3->getMessageCount());
+ BOOST_CHECK_EQUAL(9u, dq4->getMessageCount());
+ BOOST_CHECK_EQUAL(9u, dq5->getMessageCount());
+
+
+ // --- Fanout exchange bound to multiple durable and transient queues ----------------------------------------------
+
+ FanOutExchange mbmFanout4("mbmFanout4", false, args0); // multiple bindings to durable/transient queues
+ Queue::shared_ptr dq7(new Queue("dq7", true, &testStore)); // durable no limit
+ dq7->configure(args0);
+ mbmFanout4.bind(dq7, "", 0);
+ Queue::shared_ptr dq8(new Queue("dq8", true, &testStore)); // durable w/ limit
+ dq8->configure(args1);
+ mbmFanout4.bind(dq8, "", 0);
+ Queue::shared_ptr tq9(new Queue("tq9", true)); // transient no limit
+ tq9->configure(args0);
+ mbmFanout4.bind(tq9, "", 0);
+
+ intrusive_ptr<Message> msg20 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
+ DeliverableMessage dmsg20(msg20);
+ mbmFanout4.route(dmsg20, "", 0); // Brings queue 7 to capacity limit
+ msg20->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg20->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(1u, dq7->getMessageCount());
+ BOOST_CHECK_EQUAL(1u, dq8->getMessageCount());
+ BOOST_CHECK_EQUAL(1u, tq9->getMessageCount());
+
+ intrusive_ptr<Message> msg21 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
+ DeliverableMessage dmsg21(msg21);
+ mbmFanout4.route(dmsg21, "", 0);
+ msg21->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg21->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(2u, dq7->getMessageCount()); // over limit
+ BOOST_CHECK_EQUAL(2u, dq8->getMessageCount());
+ BOOST_CHECK_EQUAL(2u, tq9->getMessageCount());
+
+ intrusive_ptr<Message> msg22 = mkMsg(testStore, std::string(5, 'X'), true); // durable w/ content
+ DeliverableMessage dmsg22(msg22);
+ mbmFanout4.route(dmsg22, "", 0);
+ msg22->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg22->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(3u, dq7->getMessageCount()); // over limit
+ BOOST_CHECK_EQUAL(3u, dq8->getMessageCount()); // over limit
+ BOOST_CHECK_EQUAL(3u, tq9->getMessageCount());
+
+ intrusive_ptr<Message> msg23 = mkMsg(testStore); // transient no content
+ DeliverableMessage dmsg23(msg23);
+ mbmFanout4.route(dmsg23, "", 0);
+ msg23->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg23->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(4u, dq7->getMessageCount()); // over limit
+ BOOST_CHECK_EQUAL(4u, dq8->getMessageCount()); // over limit
+ BOOST_CHECK_EQUAL(4u, tq9->getMessageCount());
+
+ intrusive_ptr<Message> msg24 = mkMsg(testStore, "", true); // durable no content
+ DeliverableMessage dmsg24(msg24);
+ mbmFanout4.route(dmsg24, "", 0);
+ msg24->tryReleaseContent();
+ BOOST_CHECK_EQUAL(msg24->isContentReleased(), false);
+ BOOST_CHECK_EQUAL(5u, dq7->getMessageCount()); // over limit
+ BOOST_CHECK_EQUAL(5u, dq8->getMessageCount()); // over limit
+ BOOST_CHECK_EQUAL(5u, tq9->getMessageCount());
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/RangeSet.cpp b/cpp/src/tests/RangeSet.cpp
index 9c602de78d..db3a964086 100644
--- a/cpp/src/tests/RangeSet.cpp
+++ b/cpp/src/tests/RangeSet.cpp
@@ -24,6 +24,9 @@
using namespace std;
using namespace qpid;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(RangeSetTestSuite)
typedef qpid::Range<int> TestRange;
@@ -44,8 +47,8 @@ QPID_AUTO_TEST_CASE(testRangeSetAddPoint) {
BOOST_CHECK_MESSAGE(r.contains(TestRange(3,4)), r);
BOOST_CHECK(!r.empty());
r += 5;
- BOOST_CHECK_MESSAGE(r.contains(5), r);
- BOOST_CHECK_MESSAGE(r.contains(TestRange(5,6)), r);
+ BOOST_CHECK_MESSAGE(r.contains(5), r);
+ BOOST_CHECK_MESSAGE(r.contains(TestRange(5,6)), r);
BOOST_CHECK_MESSAGE(!r.contains(TestRange(3,6)), r);
r += 4;
BOOST_CHECK_MESSAGE(r.contains(TestRange(3,6)), r);
@@ -139,3 +142,5 @@ QPID_AUTO_TEST_CASE(testRangeContaining) {
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/RateFlowcontrolTest.cpp b/cpp/src/tests/RateFlowcontrolTest.cpp
new file mode 100644
index 0000000000..80ad06af8c
--- /dev/null
+++ b/cpp/src/tests/RateFlowcontrolTest.cpp
@@ -0,0 +1,71 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "unit_test.h"
+
+#include "qpid/broker/RateFlowcontrol.h"
+#include "qpid/sys/Time.h"
+
+using namespace qpid::broker;
+using namespace qpid::sys;
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(RateFlowcontrolTestSuite)
+
+QPID_AUTO_TEST_CASE(RateFlowcontrolTest)
+{
+ // BOOST_CHECK(predicate);
+ // BOOST_CHECK_EQUAL(a, b);
+
+ RateFlowcontrol fc(100);
+ AbsTime n=AbsTime::now();
+
+ BOOST_CHECK_EQUAL( fc.receivedMessage(n, 0), 0U );
+
+ fc.sentCredit(n, 0);
+
+ BOOST_CHECK_EQUAL( fc.receivedMessage(n, 0), 0U );
+ fc.sentCredit(n, 50);
+
+ Duration d=250*TIME_MSEC;
+
+ n = AbsTime(n,d);
+ BOOST_CHECK_EQUAL( fc.receivedMessage(n, 25), 0U );
+ BOOST_CHECK_EQUAL( fc.availableCredit(n), 25U );
+
+ n = AbsTime(n,d);
+ BOOST_CHECK_EQUAL( fc.receivedMessage(n, 23), 48U );
+ BOOST_CHECK_EQUAL( fc.availableCredit(n), 48U );
+ fc.sentCredit(n, 48);
+ BOOST_CHECK_EQUAL( fc.receivedMessage(n, 50), 0U);
+ BOOST_CHECK(fc.flowStopped());
+
+ n = AbsTime(n,d);
+ BOOST_CHECK_EQUAL( fc.receivedMessage(n, 0), 25U);
+ n = AbsTime(n,d);
+ BOOST_CHECK_EQUAL( fc.receivedMessage(n, 0), 50U);
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/RefCounted.cpp b/cpp/src/tests/RefCounted.cpp
index 8c679a3d2e..e4c1da5696 100644
--- a/cpp/src/tests/RefCounted.cpp
+++ b/cpp/src/tests/RefCounted.cpp
@@ -27,6 +27,9 @@ using boost::intrusive_ptr;
using namespace std;
using namespace qpid;
+namespace qpid {
+namespace tests {
+
struct CountMe : public RefCounted {
static int instances;
CountMe() { ++instances; }
@@ -48,3 +51,5 @@ QPID_AUTO_TEST_CASE(testRefCounted) {
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/ReplicationTest.cpp b/cpp/src/tests/ReplicationTest.cpp
new file mode 100644
index 0000000000..3b289d1b4e
--- /dev/null
+++ b/cpp/src/tests/ReplicationTest.cpp
@@ -0,0 +1,141 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "unit_test.h"
+#include "test_tools.h"
+#include "BrokerFixture.h"
+
+#include "qpid/Plugin.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/client/QueueOptions.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/replication/constants.h"
+#include "qpid/sys/Shlib.h"
+
+#include <string>
+#include <sstream>
+#include <vector>
+
+#include <boost/assign.hpp>
+#include <boost/bind.hpp>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace qpid::replication::constants;
+using boost::assign::list_of;
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(ReplicationTestSuite)
+
+// FIXME aconway 2009-11-26: clean this up.
+// The CMake-based build passes in the module suffix; if it's not there, this
+// is a Linux/UNIX libtool-based build.
+#if defined (QPID_MODULE_SUFFIX)
+qpid::sys::Shlib plugin("replicating_listener" QPID_MODULE_SUFFIX);
+#else
+qpid::sys::Shlib plugin(getLibPath("REPLICATING_LISTENER_LIB"));
+#endif
+
+qpid::broker::Broker::Options getBrokerOpts(const std::vector<std::string>& args)
+{
+ std::vector<const char*> argv(args.size());
+ transform(args.begin(), args.end(), argv.begin(), boost::bind(&string::c_str, _1));
+
+ qpid::broker::Broker::Options opts;
+ qpid::Plugin::addOptions(opts);
+ opts.parse(argv.size(), &argv[0], "", true);
+ return opts;
+}
+
+QPID_AUTO_TEST_CASE(testReplicationExchange)
+{
+ qpid::broker::Broker::Options brokerOpts(getBrokerOpts(list_of<string>("qpidd")
+ ("--replication-exchange-name=qpid.replication")));
+ ProxySessionFixture f(brokerOpts);
+
+
+ std::string dataQ("queue-1");
+ std::string eventQ("event-queue-1");
+ std::string dataQ2("queue-2");
+ std::string eventQ2("event-queue-2");
+ FieldTable eventQopts;
+ eventQopts.setString("qpid.insert_sequence_numbers", REPLICATION_EVENT_SEQNO);
+
+ f.session.queueDeclare(arg::queue=eventQ, arg::exclusive=true, arg::autoDelete=true, arg::arguments=eventQopts);
+ f.session.exchangeBind(arg::exchange="qpid.replication", arg::queue=eventQ, arg::bindingKey=dataQ);
+
+ f.session.queueDeclare(arg::queue=eventQ2, arg::exclusive=true, arg::autoDelete=true, arg::arguments=eventQopts);
+ f.session.exchangeBind(arg::exchange="qpid.replication", arg::queue=eventQ2, arg::bindingKey=dataQ2);
+
+ QueueOptions args;
+ args.enableQueueEvents(false);
+ f.session.queueDeclare(arg::queue=dataQ, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args);
+ f.session.queueDeclare(arg::queue=dataQ2, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args);
+ for (int i = 0; i < 10; i++) {
+ f.session.messageTransfer(arg::content=Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), dataQ));
+ f.session.messageTransfer(arg::content=Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), dataQ2));
+ }
+ Message msg;
+ LocalQueue incoming;
+ Subscription sub = f.subs.subscribe(incoming, dataQ);
+ for (int i = 0; i < 10; i++) {
+ BOOST_CHECK(incoming.get(msg, qpid::sys::TIME_SEC));
+ BOOST_CHECK_EQUAL((boost::format("%1%_%2%") % "Message" % (i+1)).str(), msg.getData());
+ }
+ BOOST_CHECK(!f.subs.get(msg, dataQ));
+
+ sub.cancel();
+ sub = f.subs.subscribe(incoming, eventQ);
+ //check that we received enqueue events for first queue:
+ for (int i = 0; i < 10; i++) {
+ BOOST_CHECK(incoming.get(msg, qpid::sys::TIME_SEC));
+ BOOST_CHECK_EQUAL(msg.getHeaders().getAsString(REPLICATION_TARGET_QUEUE), dataQ);
+ BOOST_CHECK_EQUAL(msg.getHeaders().getAsInt(REPLICATION_EVENT_TYPE), ENQUEUE);
+ BOOST_CHECK_EQUAL(msg.getHeaders().getAsInt64(REPLICATION_EVENT_SEQNO), (i+1));
+ BOOST_CHECK_EQUAL((boost::format("%1%_%2%") % "Message" % (i+1)).str(), msg.getData());
+ }
+ //check that we received dequeue events for first queue:
+ for (int i = 0; i < 10; i++) {
+ BOOST_CHECK(incoming.get(msg, qpid::sys::TIME_SEC));
+ BOOST_CHECK_EQUAL(msg.getHeaders().getAsString(REPLICATION_TARGET_QUEUE), dataQ);
+ BOOST_CHECK_EQUAL(msg.getHeaders().getAsInt(REPLICATION_EVENT_TYPE), DEQUEUE);
+ BOOST_CHECK_EQUAL(msg.getHeaders().getAsInt(DEQUEUED_MESSAGE_POSITION), (i+1));
+ BOOST_CHECK_EQUAL(msg.getHeaders().getAsInt64(REPLICATION_EVENT_SEQNO), (i+11));
+ }
+
+ sub.cancel();
+ sub = f.subs.subscribe(incoming, eventQ2);
+ //check that we received enqueue events for second queue:
+ for (int i = 0; i < 10; i++) {
+ BOOST_CHECK(incoming.get(msg, qpid::sys::TIME_SEC));
+ BOOST_CHECK_EQUAL(msg.getHeaders().getAsString(REPLICATION_TARGET_QUEUE), dataQ2);
+ BOOST_CHECK_EQUAL(msg.getHeaders().getAsInt(REPLICATION_EVENT_TYPE), ENQUEUE);
+ BOOST_CHECK_EQUAL(msg.getHeaders().getAsInt64(REPLICATION_EVENT_SEQNO), (i+1));
+ BOOST_CHECK_EQUAL((boost::format("%1%_%2%") % "Message" % (i+1)).str(), msg.getData());
+ }
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/RetryList.cpp b/cpp/src/tests/RetryList.cpp
new file mode 100644
index 0000000000..d1d22348a3
--- /dev/null
+++ b/cpp/src/tests/RetryList.cpp
@@ -0,0 +1,111 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#include "unit_test.h"
+#include "test_tools.h"
+#include "qpid/broker/RetryList.h"
+
+using namespace qpid;
+using namespace qpid::broker;
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(RetryListTestSuite)
+
+struct RetryListFixture
+{
+ RetryList list;
+ std::vector<Url> urls;
+ std::vector<TcpAddress> expected;
+
+ void addUrl(const std::string& s)
+ {
+ urls.push_back(Url(s));
+ }
+
+ void addExpectation(const std::string& host, uint16_t port)
+ {
+ expected.push_back(TcpAddress(host, port));
+ }
+
+ void check()
+ {
+ list.reset(urls);
+ for (int t = 0; t < 2; t++) {
+ TcpAddress next;
+ for (std::vector<TcpAddress>::const_iterator i = expected.begin(); i != expected.end(); ++i) {
+ BOOST_CHECK(list.next(next));
+ BOOST_CHECK_EQUAL(i->host, next.host);
+ BOOST_CHECK_EQUAL(i->port, next.port);
+ }
+ BOOST_CHECK(!list.next(next));
+ }
+ }
+};
+
+QPID_AUTO_TEST_CASE(testWithSingleAddress)
+{
+ RetryListFixture test;
+ test.addUrl("amqp:host:5673");
+ test.addExpectation("host", 5673);
+ test.check();
+}
+
+QPID_AUTO_TEST_CASE(testWithSingleUrlOfMultipleAddresses)
+{
+ RetryListFixture test;
+ test.addUrl("amqp:host1,host2:2222,tcp:host3:5673,host4:1");
+
+ test.addExpectation("host1", 5672);
+ test.addExpectation("host2", 2222);
+ test.addExpectation("host3", 5673);
+ test.addExpectation("host4", 1);
+
+ test.check();
+}
+
+QPID_AUTO_TEST_CASE(testWithMultipleUrlsOfMultipleAddresses)
+{
+ RetryListFixture test;
+ test.addUrl("amqp:my-host");
+ test.addUrl("amqp:host1:6666,host2:2222,tcp:host3:5673,host4:1");
+ test.addUrl("amqp:host5,host6:2222,tcp:host7:5673");
+
+ test.addExpectation("my-host", 5672);
+ test.addExpectation("host1", 6666);
+ test.addExpectation("host2", 2222);
+ test.addExpectation("host3", 5673);
+ test.addExpectation("host4", 1);
+ test.addExpectation("host5", 5672);
+ test.addExpectation("host6", 2222);
+ test.addExpectation("host7", 5673);
+
+ test.check();
+}
+
+QPID_AUTO_TEST_CASE(testEmptyList)
+{
+ RetryListFixture test;
+ test.check();
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/SequenceNumberTest.cpp b/cpp/src/tests/SequenceNumberTest.cpp
index e4c6d066ef..f3c934e3ca 100644
--- a/cpp/src/tests/SequenceNumberTest.cpp
+++ b/cpp/src/tests/SequenceNumberTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -26,6 +26,8 @@
using namespace qpid::framing;
+namespace qpid {
+namespace tests {
void checkDifference(SequenceNumber& a, SequenceNumber& b, int gap)
{
@@ -54,7 +56,7 @@ void checkComparison(SequenceNumber& a, SequenceNumber& b, int gap)
BOOST_CHECK(++a < ++b);//test prefix
}
//keep incrementing until a also wraps around
- for (int i = 0; i < (gap + 2); i++) {
+ for (int i = 0; i < (gap + 2); i++) {
BOOST_CHECK(a++ < b++);//test postfix
}
//let a 'catch up'
@@ -91,7 +93,7 @@ QPID_AUTO_TEST_CASE(testIncrementPostfix)
BOOST_CHECK(b != c);
}
-QPID_AUTO_TEST_CASE(testIncrementPrefix)
+QPID_AUTO_TEST_CASE(testIncrementPrefix)
{
SequenceNumber a;
SequenceNumber b;
@@ -203,3 +205,5 @@ QPID_AUTO_TEST_CASE(testDifferenceWithWrapAround2)
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/SequenceSet.cpp b/cpp/src/tests/SequenceSet.cpp
index ba2f1391a1..aaeb68e3c5 100644
--- a/cpp/src/tests/SequenceSet.cpp
+++ b/cpp/src/tests/SequenceSet.cpp
@@ -20,6 +20,9 @@
#include "unit_test.h"
#include <list>
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(SequenceSetTestSuite)
using namespace qpid::framing;
@@ -72,7 +75,7 @@ QPID_AUTO_TEST_CASE(testAdd) {
BOOST_CHECK(!s.contains(i));
RangeExpectations().expect(2, 5).expect(8, 8).check(s);
-
+
SequenceSet t;
t.add(6, 10);
t.add(s);
@@ -90,7 +93,7 @@ QPID_AUTO_TEST_CASE(testAdd2) {
SequenceSet s;
s.add(7,6);
s.add(4,4);
- s.add(3,10);
+ s.add(3,10);
s.add(2);
RangeExpectations().expect(2, 10).check(s);
}
@@ -137,4 +140,4 @@ QPID_AUTO_TEST_CASE(testRemove) {
QPID_AUTO_TEST_SUITE_END()
-
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/SessionState.cpp b/cpp/src/tests/SessionState.cpp
index ba966da9b1..157cabfb63 100644
--- a/cpp/src/tests/SessionState.cpp
+++ b/cpp/src/tests/SessionState.cpp
@@ -28,6 +28,9 @@
#include <functional>
#include <numeric>
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(SessionStateTestSuite)
using namespace std;
@@ -45,8 +48,7 @@ T applyAccumulate(Iter begin, Iter end, T seed, const F& f) {
// Create a frame with a one-char string.
AMQFrame& frame(char s) {
- static AMQFrame frame;
- frame.setBody(AMQContentBody(string(&s, 1)));
+ static AMQFrame frame((AMQContentBody(string(&s, 1))));
return frame;
}
@@ -64,7 +66,7 @@ string str(const boost::iterator_range<vector<AMQFrame>::const_iterator>& frames
}
// Make a transfer command frame.
AMQFrame transferFrame(bool hasContent) {
- AMQFrame t(in_place<MessageTransferBody>());
+ AMQFrame t((MessageTransferBody()));
t.setFirstFrame(true);
t.setLastFrame(true);
t.setFirstSegment(true);
@@ -73,7 +75,7 @@ AMQFrame transferFrame(bool hasContent) {
}
// Make a content frame
AMQFrame contentFrame(string content, bool isLast=true) {
- AMQFrame f(in_place<AMQContentBody>(content));
+ AMQFrame f((AMQContentBody(content)));
f.setFirstFrame(true);
f.setLastFrame(true);
f.setFirstSegment(false);
@@ -85,7 +87,7 @@ AMQFrame contentFrameChar(char content, bool isLast=true) {
}
// Send frame & return size of frame.
-size_t send(qpid::SessionState& s, const AMQFrame& f) { s.senderRecord(f); return f.size(); }
+size_t send(qpid::SessionState& s, const AMQFrame& f) { s.senderRecord(f); return f.encodedSize(); }
// Send transfer command with no content.
size_t transfer0(qpid::SessionState& s) { return send(s, transferFrame(false)); }
// Send transfer frame with single content frame.
@@ -95,7 +97,7 @@ size_t transfer1(qpid::SessionState& s, string content) {
size_t transfer1Char(qpid::SessionState& s, char content) {
return transfer1(s, string(1,content));
}
-
+
// Send transfer frame with multiple single-byte content frames.
size_t transferN(qpid::SessionState& s, string content) {
size_t size=send(s, transferFrame(!content.empty()));
@@ -116,8 +118,8 @@ size_t transfers(qpid::SessionState& s, string content) {
bind(transfer1Char, ref(s), _1));
}
-size_t contentFrameSize(size_t n=1) { return AMQFrame(in_place<AMQContentBody>()).size() + n; }
-size_t transferFrameSize() { return AMQFrame(in_place<MessageTransferBody>()).size(); }
+size_t contentFrameSize(size_t n=1) { return AMQFrame(( AMQContentBody())).encodedSize() + n; }
+size_t transferFrameSize() { return AMQFrame((MessageTransferBody())).encodedSize(); }
// ==== qpid::SessionState test classes
@@ -134,8 +136,8 @@ QPID_AUTO_TEST_CASE(testSendGetReplyList) {
transferN(s, "xyz");
BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(0,0))),"CabcCdCeCfCxyz");
// Ignore controls.
- s.senderRecord(AMQFrame(in_place<SessionFlushBody>()));
- BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(2,0))),"CeCfCxyz");
+ s.senderRecord(AMQFrame(new SessionFlushBody()));
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(2,0))),"CeCfCxyz");
}
QPID_AUTO_TEST_CASE(testNeedFlush) {
@@ -186,7 +188,7 @@ QPID_AUTO_TEST_CASE(testPeerConfirmed) {
s.senderConfirmed(SessionPoint(5));
BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(5,0))), "CxCy");
BOOST_CHECK(s.senderNeedFlush());
-
+
s.senderConfirmed(SessionPoint(6));
BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(6,0))), "Cy");
BOOST_CHECK(!s.senderNeedFlush());
@@ -196,7 +198,7 @@ QPID_AUTO_TEST_CASE(testPeerCompleted) {
qpid::SessionState s;
s.setTimeout(1);
s.senderGetCommandPoint();
- // Completion implies confirmation
+ // Completion implies confirmation
transfers(s, "abc");
BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(0,0))), "CaCbCc");
SequenceSet set(SequenceSet() + 0 + 1);
@@ -206,7 +208,7 @@ QPID_AUTO_TEST_CASE(testPeerCompleted) {
transfers(s, "def");
// We dont do out-of-order confirmation, so this will only confirm up to 3:
set = SequenceSet(SequenceSet() + 2 + 3 + 5);
- s.senderCompleted(set);
+ s.senderCompleted(set);
BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(4,0))), "CeCf");
}
@@ -216,11 +218,11 @@ QPID_AUTO_TEST_CASE(testReceive) {
s.receiverSetCommandPoint(SessionPoint());
BOOST_CHECK_EQUAL(s.receiverGetExpected(), SessionPoint(0));
BOOST_CHECK_EQUAL(s.receiverGetReceived(), SessionPoint(0));
-
+
BOOST_CHECK(s.receiverRecord(transferFrame(false)));
BOOST_CHECK_EQUAL(s.receiverGetExpected(), SessionPoint(1));
BOOST_CHECK_EQUAL(s.receiverGetReceived(), SessionPoint(1));
-
+
BOOST_CHECK(s.receiverRecord(transferFrame(true)));
SessionPoint point = SessionPoint(1, transferFrameSize());
BOOST_CHECK_EQUAL(s.receiverGetExpected(), point);
@@ -298,3 +300,5 @@ QPID_AUTO_TEST_CASE(testNeedKnownCompleted) {
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/Shlib.cpp b/cpp/src/tests/Shlib.cpp
index 426a052c9f..692cfcdff9 100644
--- a/cpp/src/tests/Shlib.cpp
+++ b/cpp/src/tests/Shlib.cpp
@@ -24,13 +24,23 @@
#include "unit_test.h"
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(ShlibTestSuite)
using namespace qpid::sys;
typedef void (*CallMe)(int*);
+
QPID_AUTO_TEST_CASE(testShlib) {
+ // The CMake-based build passes in the module suffix; if it's not there,
+ // this is a Linux/UNIX libtool-based build.
+#if defined (QPID_MODULE_PREFIX) && defined (QPID_MODULE_SUFFIX)
+ Shlib sh("./" QPID_MODULE_PREFIX "shlibtest" QPID_MODULE_SUFFIX);
+#else
Shlib sh(".libs/libshlibtest.so");
+#endif
// Double cast to avoid ISO warning.
CallMe callMe=sh.getSymbol<CallMe>("callMe");
BOOST_REQUIRE(callMe != 0);
@@ -44,17 +54,23 @@ QPID_AUTO_TEST_CASE(testShlib) {
}
catch (const qpid::Exception&) {}
}
-
+
QPID_AUTO_TEST_CASE(testAutoShlib) {
int unloaded = 0;
{
+#if defined (QPID_MODULE_PREFIX) && defined (QPID_MODULE_SUFFIX)
+ AutoShlib sh("./" QPID_MODULE_PREFIX "shlibtest" QPID_MODULE_SUFFIX);
+#else
AutoShlib sh(".libs/libshlibtest.so");
+#endif
CallMe callMe=sh.getSymbol<CallMe>("callMe");
BOOST_REQUIRE(callMe != 0);
callMe(&unloaded);
}
BOOST_CHECK_EQUAL(42, unloaded);
}
-
+
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/SimpleTestCaseBase.cpp b/cpp/src/tests/SimpleTestCaseBase.cpp
deleted file mode 100644
index 2739734731..0000000000
--- a/cpp/src/tests/SimpleTestCaseBase.cpp
+++ /dev/null
@@ -1,87 +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 "SimpleTestCaseBase.h"
-
-using namespace qpid;
-
-void SimpleTestCaseBase::start()
-{
- if (worker.get()) {
- worker->start();
- }
-}
-
-void SimpleTestCaseBase::stop()
-{
- if (worker.get()) {
- worker->stop();
- }
-}
-
-void SimpleTestCaseBase::report(client::Message& report)
-{
- if (worker.get()) {
- report.getHeaders().setInt("MESSAGE_COUNT", worker->getCount());
- //add number of messages sent or received
- std::stringstream reportstr;
- reportstr << worker->getCount();
- report.setData(reportstr.str());
- }
-}
-
-SimpleTestCaseBase::Sender::Sender(ConnectionOptions& options,
- const Exchange& _exchange,
- const std::string& _key,
- const int _messages)
- : Worker(options, _messages), exchange(_exchange), key(_key) {}
-
-void SimpleTestCaseBase::Sender::init()
-{
- channel.start();
-}
-
-void SimpleTestCaseBase::Sender::start(){
- Message msg;
- while (count < messages) {
- channel.publish(msg, exchange, key);
- count++;
- }
- stop();
-}
-
-SimpleTestCaseBase::Worker::Worker(ConnectionOptions& options, const int _messages) :
- messages(_messages), count(0)
-{
- connection.open(options.host, options.port);
- connection.openChannel(channel);
-}
-
-void SimpleTestCaseBase::Worker::stop()
-{
- channel.close();
- connection.close();
-}
-
-int SimpleTestCaseBase::Worker::getCount()
-{
- return count;
-}
-
diff --git a/cpp/src/tests/SimpleTestCaseBase.h b/cpp/src/tests/SimpleTestCaseBase.h
deleted file mode 100644
index 0c1052d0c2..0000000000
--- a/cpp/src/tests/SimpleTestCaseBase.h
+++ /dev/null
@@ -1,89 +0,0 @@
-#ifndef _SimpleTestCaseBase_
-#define _SimpleTestCaseBase_
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <memory>
-#include <sstream>
-
-#include "qpid/Exception.h"
-#include "qpid/client/Channel.h"
-#include "qpid/client/Message.h"
-#include "qpid/client/Connection.h"
-#include "ConnectionOptions.h"
-#include "qpid/client/MessageListener.h"
-#include "TestCase.h"
-
-
-namespace qpid {
-
-using namespace qpid::client;
-
-class SimpleTestCaseBase : public TestCase
-{
-protected:
- class Worker
- {
- protected:
- client::Connection connection;
- client::Channel channel;
- const int messages;
- int count;
-
- public:
-
- Worker(ConnectionOptions& options, const int messages);
- virtual ~Worker(){}
-
- virtual void stop();
- virtual int getCount();
- virtual void init() = 0;
- virtual void start() = 0;
- };
-
- class Sender : public Worker
- {
- const Exchange& exchange;
- const std::string key;
- public:
- Sender(ConnectionOptions& options,
- const Exchange& exchange,
- const std::string& key,
- const int messages);
- void init();
- void start();
- };
-
- std::auto_ptr<Worker> worker;
-
-public:
- virtual void assign(const std::string& role, framing::FieldTable& params, ConnectionOptions& options) = 0;
-
- virtual ~SimpleTestCaseBase() {}
-
- void start();
- void stop();
- void report(client::Message& report);
-};
-
-}
-
-#endif
diff --git a/cpp/src/tests/SocketProxy.h b/cpp/src/tests/SocketProxy.h
index a1a1351c7d..4582dc36fd 100644
--- a/cpp/src/tests/SocketProxy.h
+++ b/cpp/src/tests/SocketProxy.h
@@ -21,45 +21,65 @@
*
*/
+#include "qpid/sys/IOHandle.h"
+#ifdef _WIN32
+# include "qpid/sys/windows/IoHandlePrivate.h"
+ typedef SOCKET FdType;
+#else
+# include "qpid/sys/posix/PrivatePosix.h"
+ typedef int FdType;
+#endif
#include "qpid/sys/Socket.h"
-#include "qpid/sys/Poller.h"
#include "qpid/sys/Runnable.h"
#include "qpid/sys/Thread.h"
#include "qpid/sys/Mutex.h"
-#include "qpid/client/Connection.h"
#include "qpid/log/Statement.h"
-#include <algorithm>
+namespace qpid {
+namespace tests {
/**
- * A simple socket proxy that forwards to another socket.
+ * A simple socket proxy that forwards to another socket.
* Used between client & local broker to simulate network failures.
*/
class SocketProxy : private qpid::sys::Runnable
{
+ // Need a Socket we can get the fd from
+ class LowSocket : public qpid::sys::Socket {
+ public:
+#ifdef _WIN32
+ FdType getFd() { return toSocketHandle(*this); }
+#else
+ FdType getFd() { return toFd(impl); }
+#endif
+ };
+
public:
/** Connect to connectPort on host, start a forwarding thread.
* Listen for connection on getPort().
*/
SocketProxy(int connectPort, const std::string host="localhost")
- : closed(false), port(listener.listen()), dropClient(), dropServer()
+ : closed(false), joined(true),
+ port(listener.listen()), dropClient(), dropServer()
{
client.connect(host, connectPort);
+ joined = false;
thread = qpid::sys::Thread(static_cast<qpid::sys::Runnable*>(this));
}
-
- ~SocketProxy() { close(); }
+
+ ~SocketProxy() { close(); if (!joined) thread.join(); }
/** Simulate a network disconnect. */
void close() {
{
qpid::sys::Mutex::ScopedLock l(lock);
- if (closed) return;
+ if (closed) { return; }
closed=true;
}
- poller.shutdown();
- if (thread.id() != qpid::sys::Thread::current().id())
- thread.join();
+ if (thread.id() != qpid::sys::Thread::current().id()) {
+ thread.join();
+ joined = true;
+ }
client.close();
}
@@ -75,7 +95,7 @@ class SocketProxy : private qpid::sys::Runnable
}
uint16_t getPort() const { return port; }
-
+
private:
static void throwErrno(const std::string& msg) {
throw qpid::Exception(msg+":"+qpid::sys::strError(errno));
@@ -85,59 +105,77 @@ class SocketProxy : private qpid::sys::Runnable
}
void run() {
- std::auto_ptr<qpid::sys::Socket> server;
+ std::auto_ptr<LowSocket> server;
try {
- qpid::sys::PollerHandle listenerHandle(listener);
- poller.addFd(listenerHandle, qpid::sys::Poller::IN);
- qpid::sys::Poller::Event event = poller.wait();
- throwIf(event.type == qpid::sys::Poller::SHUTDOWN, "SocketProxy: Closed by close()");
- throwIf(!(event.type == qpid::sys::Poller::READABLE && event.handle == &listenerHandle), "SocketProxy: Accept failed");
-
- poller.delFd(listenerHandle);
- server.reset(listener.accept(0, 0));
-
- // Pump data between client & server sockets
- qpid::sys::PollerHandle clientHandle(client);
- qpid::sys::PollerHandle serverHandle(*server);
- poller.addFd(clientHandle, qpid::sys::Poller::IN);
- poller.addFd(serverHandle, qpid::sys::Poller::IN);
+ fd_set socks;
+ FdType maxFd = listener.getFd();
+ struct timeval tmo;
+ for (;;) {
+ FD_ZERO(&socks);
+ FD_SET(maxFd, &socks);
+ tmo.tv_sec = 0;
+ tmo.tv_usec = 500 * 1000;
+ if (select(maxFd+1, &socks, 0, 0, &tmo) == 0) {
+ qpid::sys::Mutex::ScopedLock l(lock);
+ throwIf(closed, "SocketProxy: Closed by close()");
+ continue;
+ }
+ throwIf(!FD_ISSET(maxFd, &socks), "SocketProxy: Accept failed");
+ break; // Accept ready... go to next step
+ }
+ server.reset(reinterpret_cast<LowSocket *>(listener.accept()));
+ maxFd = server->getFd();
+ if (client.getFd() > maxFd)
+ maxFd = client.getFd();
char buffer[1024];
for (;;) {
- qpid::sys::Poller::Event event = poller.wait();
- throwIf(event.type == qpid::sys::Poller::SHUTDOWN, "SocketProxy: Closed by close()");
- throwIf(event.type == qpid::sys::Poller::DISCONNECTED, "SocketProxy: client/server disconnected");
- if (event.handle == &serverHandle) {
- ssize_t n = server->read(buffer, sizeof(buffer));
+ FD_ZERO(&socks);
+ tmo.tv_sec = 0;
+ tmo.tv_usec = 500 * 1000;
+ FD_SET(client.getFd(), &socks);
+ FD_SET(server->getFd(), &socks);
+ if (select(maxFd+1, &socks, 0, 0, &tmo) == 0) {
+ qpid::sys::Mutex::ScopedLock l(lock);
+ throwIf(closed, "SocketProxy: Closed by close()");
+ continue;
+ }
+ // Something is set; relay data as needed until something closes
+ if (FD_ISSET(server->getFd(), &socks)) {
+ int n = server->read(buffer, sizeof(buffer));
+ throwIf(n <= 0, "SocketProxy: server disconnected");
if (!dropServer) client.write(buffer, n);
- poller.rearmFd(serverHandle);
- } else if (event.handle == &clientHandle) {
- ssize_t n = client.read(buffer, sizeof(buffer));
- if (!dropClient) server->write(buffer, n);
- poller.rearmFd(clientHandle);
- } else {
- throwIf(true, "SocketProxy: No handle ready");
}
+ if (FD_ISSET(client.getFd(), &socks)) {
+ int n = client.read(buffer, sizeof(buffer));
+ throwIf(n <= 0, "SocketProxy: client disconnected");
+ if (!dropServer) server->write(buffer, n);
+ }
+ if (!FD_ISSET(client.getFd(), &socks) &&
+ !FD_ISSET(server->getFd(), &socks))
+ throwIf(true, "SocketProxy: No handle ready");
}
}
catch (const std::exception& e) {
QPID_LOG(debug, "SocketProxy::run exception: " << e.what());
}
try {
- if (server.get()) server->close();
- close();
- }
+ if (server.get()) server->close();
+ close();
+ }
catch (const std::exception& e) {
QPID_LOG(debug, "SocketProxy::run exception in client/server close()" << e.what());
}
}
mutable qpid::sys::Mutex lock;
- bool closed;
- qpid::sys::Poller poller;
- qpid::sys::Socket client, listener;
+ mutable bool closed;
+ bool joined;
+ LowSocket client, listener;
uint16_t port;
qpid::sys::Thread thread;
bool dropClient, dropServer;
};
+}} // namespace qpid::tests
+
#endif
diff --git a/cpp/src/tests/StoreStatus.cpp b/cpp/src/tests/StoreStatus.cpp
new file mode 100644
index 0000000000..153e4a33db
--- /dev/null
+++ b/cpp/src/tests/StoreStatus.cpp
@@ -0,0 +1,109 @@
+ /*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#include "unit_test.h"
+#include "test_tools.h"
+#include "qpid/cluster/StoreStatus.h"
+#include "qpid/framing/Uuid.h"
+#include <boost/assign.hpp>
+#include <boost/filesystem/operations.hpp>
+
+using namespace std;
+using namespace qpid::cluster;
+using namespace qpid::framing;
+using namespace qpid::framing::cluster;
+using namespace boost::assign;
+using namespace boost::filesystem;
+
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(StoreStatusTestSuite)
+
+const char* TEST_DIR = "StoreStatus.tmp";
+
+QPID_AUTO_TEST_CASE(testLoadEmpty) {
+ create_directory(TEST_DIR);
+ StoreStatus ss(TEST_DIR);
+ BOOST_CHECK_EQUAL(ss.getState(), STORE_STATE_NO_STORE);
+ BOOST_CHECK(!ss.getClusterId());
+ BOOST_CHECK(!ss.getShutdownId());
+ ss.load();
+ BOOST_CHECK_EQUAL(ss.getState(), STORE_STATE_EMPTY_STORE);
+ BOOST_CHECK(!ss.getShutdownId());
+ remove_all(TEST_DIR);
+}
+
+QPID_AUTO_TEST_CASE(testSaveLoadDirty) {
+ create_directory(TEST_DIR);
+ Uuid clusterId = Uuid(true);
+ StoreStatus ss(TEST_DIR);
+ ss.load();
+ ss.dirty(clusterId);
+ BOOST_CHECK_EQUAL(ss.getState(), STORE_STATE_DIRTY_STORE);
+
+ StoreStatus ss2(TEST_DIR);
+ ss2.load();
+ BOOST_CHECK_EQUAL(ss2.getState(), STORE_STATE_DIRTY_STORE);
+ BOOST_CHECK_EQUAL(ss2.getClusterId(), clusterId);
+ BOOST_CHECK(!ss2.getShutdownId());
+ remove_all(TEST_DIR);
+}
+
+QPID_AUTO_TEST_CASE(testSaveLoadClean) {
+ create_directory(TEST_DIR);
+ Uuid clusterId = Uuid(true);
+ Uuid shutdownId = Uuid(true);
+ StoreStatus ss(TEST_DIR);
+ ss.load();
+ ss.dirty(clusterId);
+ ss.clean(shutdownId);
+ BOOST_CHECK_EQUAL(ss.getState(), STORE_STATE_CLEAN_STORE);
+
+ StoreStatus ss2(TEST_DIR);
+ ss2.load();
+ BOOST_CHECK_EQUAL(ss2.getState(), STORE_STATE_CLEAN_STORE);
+ BOOST_CHECK_EQUAL(ss2.getClusterId(), clusterId);
+ BOOST_CHECK_EQUAL(ss2.getShutdownId(), shutdownId);
+ remove_all(TEST_DIR);
+}
+
+QPID_AUTO_TEST_CASE(testMarkDirty) {
+ // Save clean then mark to dirty.
+ create_directory(TEST_DIR);
+ Uuid clusterId = Uuid(true);
+ Uuid shutdownId = Uuid(true);
+ StoreStatus ss(TEST_DIR);
+ ss.load();
+ ss.dirty(clusterId);
+ ss.clean(shutdownId);
+ ss.dirty(clusterId);
+
+ StoreStatus ss2(TEST_DIR);
+ ss2.load();
+ BOOST_CHECK_EQUAL(ss2.getState(), STORE_STATE_DIRTY_STORE);
+ BOOST_CHECK_EQUAL(ss2.getClusterId(), clusterId);
+ BOOST_CHECK(!ss2.getShutdownId());
+ remove_all(TEST_DIR);
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/TestCase.h b/cpp/src/tests/TestCase.h
deleted file mode 100644
index ba3330c951..0000000000
--- a/cpp/src/tests/TestCase.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef _TestCase_
-#define _TestCase_
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "ConnectionOptions.h"
-#include "qpid/client/Message.h"
-
-
-namespace qpid {
-
-/**
- * Interface to be implemented by test cases for use with the test
- * runner.
- */
-class TestCase
-{
-public:
- /**
- * Directs the test case to act in a particular role. Some roles
- * may be 'activated' at this stage others may require an explicit
- * start request.
- */
- virtual void assign(const std::string& role, framing::FieldTable& params, client::ConnectionOptions& options) = 0;
- /**
- * Each test will be started on its own thread, which should block
- * until the test completes (this may or may not require an
- * explicit stop() request).
- */
- virtual void start() = 0;
- /**
- * Requests that the test be stopped if still running.
- */
- virtual void stop() = 0;
- /**
- * Allows the test to fill in details on the final report
- * message. Will be called only after start has returned.
- */
- virtual void report(client::Message& report) = 0;
-
- virtual ~TestCase() {}
-};
-
-}
-
-#endif
diff --git a/cpp/src/tests/TestMessageStore.h b/cpp/src/tests/TestMessageStore.h
index a6fe716e9c..20e0b755b2 100644
--- a/cpp/src/tests/TestMessageStore.h
+++ b/cpp/src/tests/TestMessageStore.h
@@ -10,9 +10,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -28,6 +28,9 @@ using namespace qpid;
using namespace qpid::broker;
using namespace qpid::framing;
+namespace qpid {
+namespace tests {
+
typedef std::pair<string, boost::intrusive_ptr<PersistableMessage> > msg_queue_pair;
class TestMessageStore : public NullMessageStore
@@ -35,7 +38,7 @@ class TestMessageStore : public NullMessageStore
public:
std::vector<boost::intrusive_ptr<PersistableMessage> > dequeued;
std::vector<msg_queue_pair> enqueued;
-
+
void dequeue(TransactionContext*,
const boost::intrusive_ptr<PersistableMessage>& msg,
const PersistableQueue& /*queue*/)
@@ -47,12 +50,14 @@ class TestMessageStore : public NullMessageStore
const boost::intrusive_ptr<PersistableMessage>& msg,
const PersistableQueue& queue)
{
- msg->enqueueComplete();
+ msg->enqueueComplete();
enqueued.push_back(msg_queue_pair(queue.getName(), msg));
}
- TestMessageStore() : NullMessageStore(false) {}
+ TestMessageStore() : NullMessageStore() {}
~TestMessageStore(){}
};
+}} // namespace qpid::tests
+
#endif
diff --git a/cpp/src/tests/TestOptions.h b/cpp/src/tests/TestOptions.h
index a400fe5ecb..f8da0f59cf 100644
--- a/cpp/src/tests/TestOptions.h
+++ b/cpp/src/tests/TestOptions.h
@@ -9,9 +9,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -67,7 +67,7 @@ struct TestOptions : public qpid::Options
connection.open(con);
}
-
+
bool help;
ConnectionOptions con;
qpid::log::Options log;
diff --git a/cpp/src/tests/TimerTest.cpp b/cpp/src/tests/TimerTest.cpp
index 50712ff79c..1552421ba0 100644
--- a/cpp/src/tests/TimerTest.cpp
+++ b/cpp/src/tests/TimerTest.cpp
@@ -8,9 +8,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -19,7 +19,7 @@
* under the License.
*
*/
-#include "qpid/broker/Timer.h"
+#include "qpid/sys/Timer.h"
#include "qpid/sys/Monitor.h"
#include "unit_test.h"
#include <math.h>
@@ -28,11 +28,13 @@
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
-using namespace qpid::broker;
using namespace qpid::sys;
using boost::intrusive_ptr;
using boost::dynamic_pointer_cast;
+namespace qpid {
+namespace tests {
+
class Counter
{
Mutex lock;
@@ -45,7 +47,7 @@ class Counter
return ++counter;
}
};
-
+
class TestTask : public TimerTask
{
const AbsTime start;
@@ -57,7 +59,7 @@ class TestTask : public TimerTask
Counter& counter;
public:
- TestTask(Duration timeout, Counter& _counter)
+ TestTask(Duration timeout, Counter& _counter)
: TimerTask(timeout), start(now()), expected(timeout), end(start), fired(false), counter(_counter) {}
void fire()
@@ -75,7 +77,11 @@ class TestTask : public TimerTask
BOOST_CHECK(fired);
BOOST_CHECK_EQUAL(expected_position, position);
Duration actual(start, end);
+#ifdef _WIN32
+ uint64_t difference = _abs64(expected - actual);
+#else
uint64_t difference = abs(expected - actual);
+#endif
std::string msg(boost::lexical_cast<std::string>(boost::format("tolerance = %1%, difference = %2%") % tolerance % difference));
BOOST_CHECK_MESSAGE(difference < tolerance, msg);
}
@@ -103,14 +109,14 @@ QPID_AUTO_TEST_CASE(testGeneral)
intrusive_ptr<TestTask> task2(new TestTask(Duration(1 * TIME_SEC), counter));
intrusive_ptr<TestTask> task3(new TestTask(Duration(4 * TIME_SEC), counter));
intrusive_ptr<TestTask> task4(new TestTask(Duration(2 * TIME_SEC), counter));
-
+
timer.add(task1);
timer.add(task2);
timer.add(task3);
timer.add(task4);
-
+
dynamic_pointer_cast<TestTask>(task3)->wait(Duration(6 * TIME_SEC));
-
+
dynamic_pointer_cast<TestTask>(task1)->check(3);
dynamic_pointer_cast<TestTask>(task2)->check(1);
dynamic_pointer_cast<TestTask>(task3)->check(4);
@@ -118,3 +124,5 @@ QPID_AUTO_TEST_CASE(testGeneral)
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/TopicExchangeTest.cpp b/cpp/src/tests/TopicExchangeTest.cpp
index af4263de34..c103620dbf 100644
--- a/cpp/src/tests/TopicExchangeTest.cpp
+++ b/cpp/src/tests/TopicExchangeTest.cpp
@@ -6,9 +6,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -21,147 +21,107 @@
#include "test_tools.h"
using namespace qpid::broker;
+using namespace std;
-Tokens makeTokens(const char** begin, const char** end)
-{
- Tokens t;
- t.insert(t.end(), begin, end);
- return t;
-}
-
-// Calculate size of an array.
-#define LEN(a) (sizeof(a)/sizeof(a[0]))
-
-// Convert array to token vector
-#define TOKENS(a) makeTokens(a, a + LEN(a))
-
-#define ASSERT_NORMALIZED(expect, pattern) \
- BOOST_CHECK_EQUAL(Tokens(expect), static_cast<Tokens>(TopicPattern(pattern)))
-
+namespace qpid {
+namespace tests {
QPID_AUTO_TEST_SUITE(TopicExchangeTestSuite)
-QPID_AUTO_TEST_CASE(testTokens)
-{
- Tokens tokens("hello.world");
- const char* expect[] = {"hello", "world"};
- BOOST_CHECK_EQUAL(TOKENS(expect), tokens);
-
- tokens = "a.b.c";
- const char* expect2[] = { "a", "b", "c" };
- BOOST_CHECK_EQUAL(TOKENS(expect2), tokens);
-
- tokens = "";
- BOOST_CHECK(tokens.empty());
-
- tokens = "x";
- const char* expect3[] = { "x" };
- BOOST_CHECK_EQUAL(TOKENS(expect3), tokens);
-
- tokens = (".x");
- const char* expect4[] = { "", "x" };
- BOOST_CHECK_EQUAL(TOKENS(expect4), tokens);
-
- tokens = ("x.");
- const char* expect5[] = { "x", "" };
- BOOST_CHECK_EQUAL(TOKENS(expect5), tokens);
-
- tokens = (".");
- const char* expect6[] = { "", "" };
- BOOST_CHECK_EQUAL(TOKENS(expect6), tokens);
-
- tokens = ("..");
- const char* expect7[] = { "", "", "" };
- BOOST_CHECK_EQUAL(TOKENS(expect7), tokens);
-}
+#define CHECK_NORMALIZED(expect, pattern) BOOST_CHECK_EQUAL(expect, TopicExchange::normalize(pattern));
-QPID_AUTO_TEST_CASE(testNormalize)
-{
- BOOST_CHECK(TopicPattern("").empty());
- ASSERT_NORMALIZED("a.b.c", "a.b.c");
- ASSERT_NORMALIZED("a.*.c", "a.*.c");
- ASSERT_NORMALIZED("#", "#");
- ASSERT_NORMALIZED("#", "#.#.#.#");
- ASSERT_NORMALIZED("*.*.*.#", "#.*.#.*.#.#.*");
- ASSERT_NORMALIZED("a.*.*.*.#", "a.*.#.*.#.*.#");
- ASSERT_NORMALIZED("a.*.*.*.#", "a.*.#.*.#.*");
-}
-
-QPID_AUTO_TEST_CASE(testPlain)
+QPID_AUTO_TEST_CASE(testNormalize)
{
- TopicPattern p("ab.cd.e");
- BOOST_CHECK(p.match("ab.cd.e"));
- BOOST_CHECK(!p.match("abx.cd.e"));
- BOOST_CHECK(!p.match("ab.cd"));
- BOOST_CHECK(!p.match("ab.cd..e."));
- BOOST_CHECK(!p.match("ab.cd.e."));
- BOOST_CHECK(!p.match(".ab.cd.e"));
-
- p = "";
- BOOST_CHECK(p.match(""));
-
- p = ".";
- BOOST_CHECK(p.match("."));
+ CHECK_NORMALIZED("", "");
+ CHECK_NORMALIZED("a.b.c", "a.b.c");
+ CHECK_NORMALIZED("a.*.c", "a.*.c");
+ CHECK_NORMALIZED("#", "#");
+ CHECK_NORMALIZED("#", "#.#.#.#");
+ CHECK_NORMALIZED("*.*.*.#", "#.*.#.*.#.#.*");
+ CHECK_NORMALIZED("a.*.*.*.#", "a.*.#.*.#.*.#");
+ CHECK_NORMALIZED("a.*.*.*.#", "a.*.#.*.#.*");
+ CHECK_NORMALIZED("*.*.*.#", "*.#.#.*.*.#");
}
-
-QPID_AUTO_TEST_CASE(testStar)
+QPID_AUTO_TEST_CASE(testPlain)
{
- TopicPattern p("a.*.b");
- BOOST_CHECK(p.match("a.xx.b"));
- BOOST_CHECK(!p.match("a.b"));
-
- p = "*.x";
- BOOST_CHECK(p.match("y.x"));
- BOOST_CHECK(p.match(".x"));
- BOOST_CHECK(!p.match("x"));
-
- p = "x.x.*";
- BOOST_CHECK(p.match("x.x.y"));
- BOOST_CHECK(p.match("x.x."));
- BOOST_CHECK(!p.match("x.x"));
- BOOST_CHECK(!p.match("q.x.y"));
+ string pattern("ab.cd.e");
+ BOOST_CHECK(TopicExchange::match(pattern, "ab.cd.e"));
+ BOOST_CHECK(!TopicExchange::match(pattern, "abx.cd.e"));
+ BOOST_CHECK(!TopicExchange::match(pattern, "ab.cd"));
+ BOOST_CHECK(!TopicExchange::match(pattern, "ab.cd..e."));
+ BOOST_CHECK(!TopicExchange::match(pattern, "ab.cd.e."));
+ BOOST_CHECK(!TopicExchange::match(pattern, ".ab.cd.e"));
+
+ pattern = "";
+ BOOST_CHECK(TopicExchange::match(pattern, ""));
+
+ pattern = ".";
+ BOOST_CHECK(TopicExchange::match(pattern, "."));
}
-QPID_AUTO_TEST_CASE(testHash)
+
+QPID_AUTO_TEST_CASE(testStar)
{
- TopicPattern p("a.#.b");
- BOOST_CHECK(p.match("a.b"));
- BOOST_CHECK(p.match("a.x.b"));
- BOOST_CHECK(p.match("a..x.y.zz.b"));
- BOOST_CHECK(!p.match("a.b."));
- BOOST_CHECK(!p.match("q.x.b"));
-
- p = "a.#";
- BOOST_CHECK(p.match("a"));
- BOOST_CHECK(p.match("a.b"));
- BOOST_CHECK(p.match("a.b.c"));
-
- p = "#.a";
- BOOST_CHECK(p.match("a"));
- BOOST_CHECK(p.match("x.y.a"));
+ string pattern("a.*.b");
+ BOOST_CHECK(TopicExchange::match(pattern, "a.xx.b"));
+ BOOST_CHECK(!TopicExchange::match(pattern, "a.b"));
+
+ pattern = "*.x";
+ BOOST_CHECK(TopicExchange::match(pattern, "y.x"));
+ BOOST_CHECK(TopicExchange::match(pattern, ".x"));
+ BOOST_CHECK(!TopicExchange::match(pattern, "x"));
+
+ pattern = "x.x.*";
+ BOOST_CHECK(TopicExchange::match(pattern, "x.x.y"));
+ BOOST_CHECK(TopicExchange::match(pattern, "x.x."));
+ BOOST_CHECK(!TopicExchange::match(pattern, "x.x"));
+ BOOST_CHECK(!TopicExchange::match(pattern, "q.x.y"));
}
-QPID_AUTO_TEST_CASE(testMixed)
+QPID_AUTO_TEST_CASE(testHash)
{
- TopicPattern p("*.x.#.y");
- BOOST_CHECK(p.match("a.x.y"));
- BOOST_CHECK(p.match("a.x.p.qq.y"));
- BOOST_CHECK(!p.match("a.a.x.y"));
- BOOST_CHECK(!p.match("aa.x.b.c"));
-
- p = "a.#.b.*";
- BOOST_CHECK(p.match("a.b.x"));
- BOOST_CHECK(p.match("a.x.x.x.b.x"));
+ string pattern("a.#.b");
+ BOOST_CHECK(TopicExchange::match(pattern, "a.b"));
+ BOOST_CHECK(TopicExchange::match(pattern, "a.x.b"));
+ BOOST_CHECK(TopicExchange::match(pattern, "a..x.y.zz.b"));
+ BOOST_CHECK(!TopicExchange::match(pattern, "a.b."));
+ BOOST_CHECK(!TopicExchange::match(pattern, "q.x.b"));
+
+ pattern = "a.#";
+ BOOST_CHECK(TopicExchange::match(pattern, "a"));
+ BOOST_CHECK(TopicExchange::match(pattern, "a.b"));
+ BOOST_CHECK(TopicExchange::match(pattern, "a.b.c"));
+
+ pattern = "#.a";
+ BOOST_CHECK(TopicExchange::match(pattern, "a"));
+ BOOST_CHECK(TopicExchange::match(pattern, "x.y.a"));
+
+ pattern = "a.#.b.#.c";
+ BOOST_CHECK(TopicExchange::match(pattern, "a.b.c"));
+ BOOST_CHECK(TopicExchange::match(pattern, "a.x.b.y.c"));
+ BOOST_CHECK(TopicExchange::match(pattern, "a.x.x.b.y.y.c"));
}
-QPID_AUTO_TEST_CASE(testCombo)
+QPID_AUTO_TEST_CASE(testMixed)
{
- TopicPattern p("*.#.#.*.*.#");
- BOOST_CHECK(p.match("x.y.z"));
- BOOST_CHECK(p.match("x.y.z.a.b.c"));
- BOOST_CHECK(!p.match("x.y"));
- BOOST_CHECK(!p.match("x"));
+ string pattern("*.x.#.y");
+ BOOST_CHECK(TopicExchange::match(pattern, "a.x.y"));
+ BOOST_CHECK(TopicExchange::match(pattern, "a.x.p.qq.y"));
+ BOOST_CHECK(!TopicExchange::match(pattern, "a.a.x.y"));
+ BOOST_CHECK(!TopicExchange::match(pattern, "aa.x.b.c"));
+
+ pattern = "a.#.b.*";
+ BOOST_CHECK(TopicExchange::match(pattern, "a.b.x"));
+ BOOST_CHECK(TopicExchange::match(pattern, "a.x.x.x.b.x"));
+
+ pattern = "*.*.*.#";
+ BOOST_CHECK(TopicExchange::match(pattern, "x.y.z"));
+ BOOST_CHECK(TopicExchange::match(pattern, "x.y.z.a.b.c"));
+ BOOST_CHECK(!TopicExchange::match(pattern, "x.y"));
+ BOOST_CHECK(!TopicExchange::match(pattern, "x"));
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/TxBufferTest.cpp b/cpp/src/tests/TxBufferTest.cpp
index 3d6a12cacc..4807026ab7 100644
--- a/cpp/src/tests/TxBufferTest.cpp
+++ b/cpp/src/tests/TxBufferTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -27,6 +27,9 @@
using namespace qpid::broker;
using boost::static_pointer_cast;
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(TxBufferTestSuite)
QPID_AUTO_TEST_CASE(testCommitLocal)
@@ -174,3 +177,5 @@ QPID_AUTO_TEST_CASE(testBufferIsClearedAfterCommit)
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/TxMocks.h b/cpp/src/tests/TxMocks.h
index 86864b987e..a34d864bae 100644
--- a/cpp/src/tests/TxMocks.h
+++ b/cpp/src/tests/TxMocks.h
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -32,6 +32,9 @@ using namespace qpid::broker;
using boost::static_pointer_cast;
using std::string;
+namespace qpid {
+namespace tests {
+
template <class T> void assertEqualVector(std::vector<T>& expected, std::vector<T>& actual){
unsigned int i = 0;
while(i < expected.size() && i < actual.size()){
@@ -62,15 +65,15 @@ class MockTxOp : public TxOp, public TxOpConstants{
string debugName;
public:
typedef boost::shared_ptr<MockTxOp> shared_ptr;
-
+
MockTxOp() : failOnPrepare(false) {}
MockTxOp(bool _failOnPrepare) : failOnPrepare(_failOnPrepare) {}
-
+
void setDebugName(string name){
debugName = name;
}
- void printExpected(){
+ void printExpected(){
std::cout << std::endl << "MockTxOp[" << debugName << "] expects: ";
for (std::vector<string>::iterator i = expected.begin(); i < expected.end(); i++) {
if(i != expected.begin()) std::cout << ", ";
@@ -79,7 +82,7 @@ public:
std::cout << std::endl;
}
- void printActual(){
+ void printActual(){
std::cout << std::endl << "MockTxOp[" << debugName << "] actual: ";
for (std::vector<string>::iterator i = actual.begin(); i < actual.end(); i++) {
if(i != actual.begin()) std::cout << ", ";
@@ -87,7 +90,7 @@ public:
}
std::cout << std::endl;
}
-
+
bool prepare(TransactionContext*) throw(){
actual.push_back(PREPARE);
return !failOnPrepare;
@@ -114,7 +117,10 @@ public:
void check(){
assertEqualVector(expected, actual);
}
- ~MockTxOp(){}
+
+ void accept(TxOpConstVisitor&) const {}
+
+ ~MockTxOp(){}
};
class MockTransactionalStore : public TransactionalStore{
@@ -125,10 +131,10 @@ class MockTransactionalStore : public TransactionalStore{
const string ABORT;
std::vector<string> expected;
std::vector<string> actual;
-
+
enum states {OPEN = 1, PREPARED = 2, COMMITTED = 3, ABORTED = 4};
int state;
-
+
class TestTransactionContext : public TPCTransactionContext{
MockTransactionalStore* store;
public:
@@ -142,29 +148,29 @@ class MockTransactionalStore : public TransactionalStore{
if(!store->isOpen() && !store->isPrepared()) throw "txn already completed";
store->state = COMMITTED;
}
-
+
void abort(){
if(!store->isOpen() && !store->isPrepared()) throw "txn already completed";
store->state = ABORTED;
}
~TestTransactionContext(){}
};
-
+
public:
MockTransactionalStore() :
BEGIN("BEGIN"), BEGIN2PC("BEGIN2PC"), PREPARE("PREPARE"), COMMIT("COMMIT"), ABORT("ABORT"), state(OPEN){}
void collectPreparedXids(std::set<std::string>&)
{
- throw "Operation not supported";
+ throw "Operation not supported";
}
-
- std::auto_ptr<TPCTransactionContext> begin(const std::string&){
+
+ std::auto_ptr<TPCTransactionContext> begin(const std::string&){
actual.push_back(BEGIN2PC);
std::auto_ptr<TPCTransactionContext> txn(new TestTransactionContext(this));
return txn;
}
- std::auto_ptr<TransactionContext> begin(){
+ std::auto_ptr<TransactionContext> begin(){
actual.push_back(BEGIN);
std::auto_ptr<TransactionContext> txn(new TestTransactionContext(this));
return txn;
@@ -180,7 +186,7 @@ public:
void abort(TransactionContext& ctxt){
actual.push_back(ABORT);
dynamic_cast<TestTransactionContext&>(ctxt).abort();
- }
+ }
MockTransactionalStore& expectBegin(){
expected.push_back(BEGIN);
return *this;
@@ -204,23 +210,25 @@ public:
void check(){
assertEqualVector(expected, actual);
}
-
+
bool isPrepared(){
return state == PREPARED;
}
-
+
bool isCommitted(){
return state == COMMITTED;
}
-
+
bool isAborted(){
return state == ABORTED;
}
-
+
bool isOpen() const{
return state == OPEN;
}
~MockTransactionalStore(){}
};
+}} // namespace qpid::tests
+
#endif
diff --git a/cpp/src/tests/TxPublishTest.cpp b/cpp/src/tests/TxPublishTest.cpp
index 9e9715c987..6b44d95baa 100644
--- a/cpp/src/tests/TxPublishTest.cpp
+++ b/cpp/src/tests/TxPublishTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -35,35 +35,38 @@ using boost::intrusive_ptr;
using namespace qpid::broker;
using namespace qpid::framing;
+namespace qpid {
+namespace tests {
+
struct TxPublishTest
{
-
+
TestMessageStore store;
Queue::shared_ptr queue1;
Queue::shared_ptr queue2;
intrusive_ptr<Message> msg;
TxPublish op;
-
+
TxPublishTest() :
- queue1(new Queue("queue1", false, &store, 0)),
- queue2(new Queue("queue2", false, &store, 0)),
- msg(MessageUtils::createMessage("exchange", "routing_key", "id")),
+ queue1(new Queue("queue1", false, &store, 0)),
+ queue2(new Queue("queue2", false, &store, 0)),
+ msg(MessageUtils::createMessage("exchange", "routing_key", false, "id")),
op(msg)
{
msg->getProperties<DeliveryProperties>()->setDeliveryMode(PERSISTENT);
op.deliverTo(queue1);
op.deliverTo(queue2);
- }
+ }
};
QPID_AUTO_TEST_SUITE(TxPublishTestSuite)
-
+
QPID_AUTO_TEST_CASE(testPrepare)
{
TxPublishTest t;
- intrusive_ptr<PersistableMessage> pmsg = static_pointer_cast<PersistableMessage>(t.msg);
+ intrusive_ptr<PersistableMessage> pmsg = boost::static_pointer_cast<PersistableMessage>(t.msg);
//ensure messages are enqueued in store
t.op.prepare(0);
BOOST_CHECK_EQUAL((size_t) 2, t.store.enqueued.size());
@@ -71,7 +74,7 @@ QPID_AUTO_TEST_CASE(testPrepare)
BOOST_CHECK_EQUAL(pmsg, t.store.enqueued[0].second);
BOOST_CHECK_EQUAL(string("queue2"), t.store.enqueued[1].first);
BOOST_CHECK_EQUAL(pmsg, t.store.enqueued[1].second);
- BOOST_CHECK_EQUAL( true, ( static_pointer_cast<PersistableMessage>(t.msg))->isEnqueueComplete());
+ BOOST_CHECK_EQUAL( true, ( boost::static_pointer_cast<PersistableMessage>(t.msg))->isEnqueueComplete());
}
QPID_AUTO_TEST_CASE(testCommit)
@@ -84,11 +87,13 @@ QPID_AUTO_TEST_CASE(testCommit)
BOOST_CHECK_EQUAL((uint32_t) 1, t.queue1->getMessageCount());
intrusive_ptr<Message> msg_dequeue = t.queue1->get().payload;
- BOOST_CHECK_EQUAL( true, (static_pointer_cast<PersistableMessage>(msg_dequeue))->isEnqueueComplete());
+ BOOST_CHECK_EQUAL( true, (boost::static_pointer_cast<PersistableMessage>(msg_dequeue))->isEnqueueComplete());
BOOST_CHECK_EQUAL(t.msg, msg_dequeue);
BOOST_CHECK_EQUAL((uint32_t) 1, t.queue2->getMessageCount());
- BOOST_CHECK_EQUAL(t.msg, t.queue2->get().payload);
+ BOOST_CHECK_EQUAL(t.msg, t.queue2->get().payload);
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/Url.cpp b/cpp/src/tests/Url.cpp
index d2892d92bf..343186eb1f 100644
--- a/cpp/src/tests/Url.cpp
+++ b/cpp/src/tests/Url.cpp
@@ -26,39 +26,47 @@ using namespace std;
using namespace qpid;
using namespace boost::assign;
-QPID_AUTO_TEST_SUITE(UrlTestSuite)
+namespace qpid {
+namespace tests {
-QPID_AUTO_TEST_CASE(testUrl_str) {
- Url url;
- url.push_back(TcpAddress("foo.com"));
- url.push_back(TcpAddress("bar.com", 6789));
- BOOST_CHECK_EQUAL("amqp:tcp:foo.com:5672,tcp:bar.com:6789", url.str());
- BOOST_CHECK(Url().str().empty());
-}
+QPID_AUTO_TEST_SUITE(UrlTestSuite)
+#define URL_CHECK_STR(STR) BOOST_CHECK_EQUAL(Url(STR).str(), STR)
+#define URL_CHECK_INVALID(STR) BOOST_CHECK_THROW(Url(STR), Url::Invalid)
-QPID_AUTO_TEST_CASE(testUrl_parse) {
- Url url;
- url.parse("amqp:foo.com,tcp:bar.com:1234");
- BOOST_CHECK_EQUAL(2u, url.size());
- BOOST_CHECK_EQUAL("foo.com", boost::get<TcpAddress>(url[0]).host);
- BOOST_CHECK_EQUAL("amqp:tcp:foo.com:5672,tcp:bar.com:1234", url.str());
+QPID_AUTO_TEST_CASE(TestParseTcp) {
+ URL_CHECK_STR("amqp:tcp:host:42");
+ URL_CHECK_STR("amqp:tcp:host-._~%ff%23:42"); // unreserved chars and pct encoded hex.
- url.parse("amqp:foo/ignorethis");
- BOOST_CHECK_EQUAL("amqp:tcp:foo:5672", url.str());
+ // Check defaults
+ BOOST_CHECK_EQUAL(Url("amqp:host:42").str(), "amqp:tcp:host:42");
+ BOOST_CHECK_EQUAL(Url("amqp:tcp:host").str(), "amqp:tcp:host:5672");
+ BOOST_CHECK_EQUAL(Url("amqp:tcp:").str(), "amqp:tcp:127.0.0.1:5672");
+ BOOST_CHECK_EQUAL(Url("amqp:").str(), "amqp:tcp:127.0.0.1:5672");
+ BOOST_CHECK_EQUAL(Url("amqp::42").str(), "amqp:tcp:127.0.0.1:42");
- url.parse("amqp:");
- BOOST_CHECK_EQUAL("amqp:tcp::5672", url.str());
+ URL_CHECK_INVALID("amqp::badHost!#$#");
+ URL_CHECK_INVALID("amqp::host:badPort");
+}
- try {
- url.parse("invalid url");
- BOOST_FAIL("Expected InvalidUrl exception");
- }
- catch (const Url::InvalidUrl&) {}
+QPID_AUTO_TEST_CASE(TestParseExample) {
+ URL_CHECK_STR("amqp:example:x");
+ URL_CHECK_INVALID("amqp:example:badExample");
+}
- url.parseNoThrow("invalid url");
- BOOST_CHECK(url.empty());
+QPID_AUTO_TEST_CASE(TestParseMultiAddress) {
+ URL_CHECK_STR("amqp:tcp:host:0,example:y,tcp:foo:0,example:1");
+ URL_CHECK_STR("amqp:example:z,tcp:foo:0");
+ URL_CHECK_INVALID("amqp:tcp:h:0,");
+ URL_CHECK_INVALID(",amqp:tcp:h");
}
+QPID_AUTO_TEST_CASE(TestInvalidAddress) {
+ URL_CHECK_INVALID("xxxx");
+ URL_CHECK_INVALID("");
+}
+
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/Uuid.cpp b/cpp/src/tests/Uuid.cpp
index ee86d75a26..a6ddb9b5a5 100644
--- a/cpp/src/tests/Uuid.cpp
+++ b/cpp/src/tests/Uuid.cpp
@@ -18,11 +18,14 @@
#include "qpid/framing/Uuid.h"
#include "qpid/framing/Buffer.h"
+#include "qpid/sys/alloca.h"
#include "unit_test.h"
#include <set>
-#include <alloca.h>
+
+namespace qpid {
+namespace tests {
QPID_AUTO_TEST_SUITE(UuidTestSuite)
@@ -77,3 +80,5 @@ QPID_AUTO_TEST_CASE(testUuidEncodeDecode) {
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/Variant.cpp b/cpp/src/tests/Variant.cpp
new file mode 100644
index 0000000000..21005779f0
--- /dev/null
+++ b/cpp/src/tests/Variant.cpp
@@ -0,0 +1,178 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <iostream>
+#include "qpid/messaging/Variant.h"
+
+#include "unit_test.h"
+
+using namespace qpid::messaging;
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(VariantSuite)
+
+QPID_AUTO_TEST_CASE(testConversions)
+{
+ Variant value;
+
+ //string to float/double
+ value = "1.5";
+ BOOST_CHECK_EQUAL((float) 1.5, value.asFloat());
+ BOOST_CHECK_EQUAL((double) 1.5, value.asDouble());
+
+ //float to string or double
+ value = 1.5f;
+ BOOST_CHECK_EQUAL((float) 1.5, value.asFloat());
+ BOOST_CHECK_EQUAL((double) 1.5, value.asDouble());
+ BOOST_CHECK_EQUAL(std::string("1.5"), value.asString());
+
+ //double to string (conversion to float not valid)
+ value = 1.5;
+ BOOST_CHECK_THROW(value.asFloat(), InvalidConversion);
+ BOOST_CHECK_EQUAL((double) 1.5, value.asDouble());
+ BOOST_CHECK_EQUAL(std::string("1.5"), value.asString());
+
+ //uint8 to larger unsigned ints and string
+ value = (uint8_t) 7;
+ BOOST_CHECK_EQUAL((uint8_t) 7, value.asUint8());
+ BOOST_CHECK_EQUAL((uint16_t) 7, value.asUint16());
+ BOOST_CHECK_EQUAL((uint32_t) 7, value.asUint32());
+ BOOST_CHECK_EQUAL((uint64_t) 7, value.asUint64());
+ BOOST_CHECK_EQUAL(std::string("7"), value.asString());
+ BOOST_CHECK_THROW(value.asInt8(), InvalidConversion);
+
+ value = (uint16_t) 8;
+ BOOST_CHECK_EQUAL(std::string("8"), value.asString());
+ value = (uint32_t) 9;
+ BOOST_CHECK_EQUAL(std::string("9"), value.asString());
+
+ //uint32 to larger unsigned ints and string
+ value = (uint32_t) 9999999;
+ BOOST_CHECK_EQUAL((uint32_t) 9999999, value.asUint32());
+ BOOST_CHECK_EQUAL((uint64_t) 9999999, value.asUint64());
+ BOOST_CHECK_EQUAL(std::string("9999999"), value.asString());
+ BOOST_CHECK_THROW(value.asUint8(), InvalidConversion);
+ BOOST_CHECK_THROW(value.asUint16(), InvalidConversion);
+ BOOST_CHECK_THROW(value.asInt32(), InvalidConversion);
+
+ value = "true";
+ BOOST_CHECK(value.asBool());
+ value = "false";
+ BOOST_CHECK(!value.asBool());
+ value = "1";
+ BOOST_CHECK(value.asBool());
+ value = "0";
+ BOOST_CHECK(!value.asBool());
+ value = "other";
+ BOOST_CHECK_THROW(value.asBool(), InvalidConversion);
+}
+
+QPID_AUTO_TEST_CASE(testAssignment)
+{
+ Variant value("abc");
+ Variant other = value;
+ BOOST_CHECK_EQUAL(VAR_STRING, value.getType());
+ BOOST_CHECK_EQUAL(other.getType(), value.getType());
+ BOOST_CHECK_EQUAL(other.asString(), value.asString());
+
+ const uint32_t i(1000);
+ value = i;
+ BOOST_CHECK_EQUAL(VAR_UINT32, value.getType());
+ BOOST_CHECK_EQUAL(VAR_STRING, other.getType());
+}
+
+QPID_AUTO_TEST_CASE(testList)
+{
+ const std::string s("abc");
+ const float f(9.876f);
+ const int16_t x(1000);
+
+ Variant value = Variant::List();
+ value.asList().push_back(Variant(s));
+ value.asList().push_back(Variant(f));
+ value.asList().push_back(Variant(x));
+ BOOST_CHECK_EQUAL(3u, value.asList().size());
+ Variant::List::const_iterator i = value.asList().begin();
+
+ BOOST_CHECK(i != value.asList().end());
+ BOOST_CHECK_EQUAL(VAR_STRING, i->getType());
+ BOOST_CHECK_EQUAL(s, i->asString());
+ i++;
+
+ BOOST_CHECK(i != value.asList().end());
+ BOOST_CHECK_EQUAL(VAR_FLOAT, i->getType());
+ BOOST_CHECK_EQUAL(f, i->asFloat());
+ i++;
+
+ BOOST_CHECK(i != value.asList().end());
+ BOOST_CHECK_EQUAL(VAR_INT16, i->getType());
+ BOOST_CHECK_EQUAL(x, i->asInt16());
+ i++;
+
+ BOOST_CHECK(i == value.asList().end());
+}
+
+QPID_AUTO_TEST_CASE(testMap)
+{
+ const std::string red("red");
+ const float pi(3.14f);
+ const int16_t x(1000);
+
+ Variant value = Variant::Map();
+ value.asMap()["colour"] = red;
+ value.asMap()["pi"] = pi;
+ value.asMap()["my-key"] = x;
+ BOOST_CHECK_EQUAL(3u, value.asMap().size());
+
+ BOOST_CHECK_EQUAL(VAR_STRING, value.asMap()["colour"].getType());
+ BOOST_CHECK_EQUAL(red, value.asMap()["colour"].asString());
+
+ BOOST_CHECK_EQUAL(VAR_FLOAT, value.asMap()["pi"].getType());
+ BOOST_CHECK_EQUAL(pi, value.asMap()["pi"].asFloat());
+
+ BOOST_CHECK_EQUAL(VAR_INT16, value.asMap()["my-key"].getType());
+ BOOST_CHECK_EQUAL(x, value.asMap()["my-key"].asInt16());
+
+ value.asMap()["my-key"] = "now it's a string";
+ BOOST_CHECK_EQUAL(VAR_STRING, value.asMap()["my-key"].getType());
+ BOOST_CHECK_EQUAL(std::string("now it's a string"), value.asMap()["my-key"].asString());
+}
+
+QPID_AUTO_TEST_CASE(testIsEqualTo)
+{
+ BOOST_CHECK_EQUAL(Variant("abc"), Variant("abc"));
+ BOOST_CHECK_EQUAL(Variant(1234), Variant(1234));
+
+ Variant a = Variant::Map();
+ a.asMap()["colour"] = "red";
+ a.asMap()["pi"] = 3.14f;
+ a.asMap()["my-key"] = 1234;
+ Variant b = Variant::Map();
+ b.asMap()["colour"] = "red";
+ b.asMap()["pi"] = 3.14f;
+ b.asMap()["my-key"] = 1234;
+ BOOST_CHECK_EQUAL(a, b);
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/XmlClientSessionTest.cpp b/cpp/src/tests/XmlClientSessionTest.cpp
index d0a1520c81..b59abbf2cc 100644
--- a/cpp/src/tests/XmlClientSessionTest.cpp
+++ b/cpp/src/tests/XmlClientSessionTest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -18,15 +18,18 @@
* under the License.
*
*/
+
#include "unit_test.h"
+#include "test_tools.h"
#include "BrokerFixture.h"
+#include "qpid/sys/Shlib.h"
#include "qpid/sys/Monitor.h"
#include "qpid/sys/Thread.h"
#include "qpid/sys/Runnable.h"
-#include "qpid/framing/TransferContent.h"
+#include "qpid/client/Message.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/client/Connection.h"
-#include "qpid/client/Dispatcher.h"
+#include "qpid/client/SubscriptionManager.h"
#include "qpid/client/LocalQueue.h"
#include "qpid/client/Session.h"
#include "qpid/client/SubscriptionManager.h"
@@ -36,6 +39,9 @@
#include <vector>
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(XmlClientSessionTest)
using namespace qpid::client;
@@ -43,35 +49,14 @@ using namespace qpid::client;
using namespace qpid::client::arg;
using namespace qpid::framing;
using namespace qpid;
+using qpid::sys::Shlib;
using qpid::sys::Monitor;
using std::string;
using std::cout;
using std::endl;
-struct DummyListener : public sys::Runnable, public MessageListener {
- std::vector<Message> messages;
- string name;
- uint expected;
- Dispatcher dispatcher;
-
- DummyListener(Session& session, const string& n, uint ex) :
- name(n), expected(ex), dispatcher(session) {}
-
- void run()
- {
- dispatcher.listen(name, this);
- dispatcher.run();
- }
-
- void received(Message& msg)
- {
- messages.push_back(msg);
- if (--expected == 0)
- dispatcher.stop();
- }
-};
-
+Shlib shlib(getLibPath("XML_LIB"));
class SubscribedLocalQueue : public LocalQueue {
private:
@@ -118,39 +103,124 @@ struct ClientSessionFixture : public ProxySessionFixture
// ########### START HERE ####################################
+
+
QPID_AUTO_TEST_CASE(testXmlBinding) {
- ClientSessionFixture f;
+ ClientSessionFixture f;
+
+ SubscriptionManager subscriptions(f.session);
+ SubscribedLocalQueue localQueue(subscriptions);
+
+ f.session.exchangeDeclare(qpid::client::arg::exchange="xml", qpid::client::arg::type="xml");
+ f.session.queueDeclare(qpid::client::arg::queue="odd_blue");
+ subscriptions.subscribe(localQueue, "odd_blue");
+
+ FieldTable binding;
+ binding.setString("xquery", "declare variable $color external;"
+ "(./message/id mod 2 = 1) and ($color = 'blue')");
+ f.session.exchangeBind(qpid::client::arg::exchange="xml", qpid::client::arg::queue="odd_blue", qpid::client::arg::bindingKey="query_name", qpid::client::arg::arguments=binding);
+
+ Message message;
+ message.getDeliveryProperties().setRoutingKey("query_name");
- SubscriptionManager subscriptions(f.session);
- SubscribedLocalQueue localQueue(subscriptions);
+ message.getHeaders().setString("color", "blue");
+ string m = "<message><id>1</id></message>";
+ message.setData(m);
- f.session.exchangeDeclare(qpid::client::arg::exchange="xml", qpid::client::arg::type="xml");
- f.session.queueDeclare(qpid::client::arg::queue="odd_blue");
- subscriptions.subscribe(localQueue, "odd_blue");
+ f.session.messageTransfer(qpid::client::arg::content=message, qpid::client::arg::destination="xml");
- FieldTable binding;
- binding.setString("xquery", "declare variable $color external;"
- "(./message/id mod 2 = 1) and ($color = 'blue')");
- f.session.exchangeBind(qpid::client::arg::exchange="xml", qpid::client::arg::queue="odd_blue", qpid::client::arg::bindingKey="query_name", qpid::client::arg::arguments=binding);
+ Message m2 = localQueue.get();
+ BOOST_CHECK_EQUAL(m, m2.getData());
+}
+
+/**
+ * Ensure that multiple queues can be bound using the same routing key
+ */
+QPID_AUTO_TEST_CASE(testXMLBindMultipleQueues) {
+ ClientSessionFixture f;
+
+
+ f.session.exchangeDeclare(arg::exchange="xml", arg::type="xml");
+ f.session.queueDeclare(arg::queue="blue", arg::exclusive=true, arg::autoDelete=true);
+ f.session.queueDeclare(arg::queue="red", arg::exclusive=true, arg::autoDelete=true);
+
+ FieldTable blue;
+ blue.setString("xquery", "./colour = 'blue'");
+ f.session.exchangeBind(arg::exchange="xml", arg::queue="blue", arg::bindingKey="by-colour", arg::arguments=blue);
+ FieldTable red;
+ red.setString("xquery", "./colour = 'red'");
+ f.session.exchangeBind(arg::exchange="xml", arg::queue="red", arg::bindingKey="by-colour", arg::arguments=red);
+
+ Message sent1("<colour>blue</colour>", "by-colour");
+ f.session.messageTransfer(arg::content=sent1, arg::destination="xml");
+
+ Message sent2("<colour>red</colour>", "by-colour");
+ f.session.messageTransfer(arg::content=sent2, arg::destination="xml");
+
+ Message received;
+ BOOST_CHECK(f.subs.get(received, "blue"));
+ BOOST_CHECK_EQUAL(sent1.getData(), received.getData());
+ BOOST_CHECK(f.subs.get(received, "red"));
+ BOOST_CHECK_EQUAL(sent2.getData(), received.getData());
+}
+
+//### Test: Bad XML does not kill the server - and does not even
+// raise an exception, the content is not required to be XML.
+
+QPID_AUTO_TEST_CASE(testXMLSendBadXML) {
+ ClientSessionFixture f;
- Message message;
- message.getDeliveryProperties().setRoutingKey("query_name");
+ f.session.exchangeDeclare(arg::exchange="xml", arg::type="xml");
+ f.session.queueDeclare(arg::queue="blue", arg::exclusive=true, arg::autoDelete=true)\
+ ;
+ f.session.queueDeclare(arg::queue="red", arg::exclusive=true, arg::autoDelete=true);
- message.getHeaders().setString("color", "blue");
- string m = "<message><id>1</id></message>";
- message.setData(m);
+ FieldTable blue;
+ blue.setString("xquery", "./colour = 'blue'");
+ f.session.exchangeBind(arg::exchange="xml", arg::queue="blue", arg::bindingKey="by-c\
+olour", arg::arguments=blue);
+ FieldTable red;
+ red.setString("xquery", "./colour = 'red'");
+ f.session.exchangeBind(arg::exchange="xml", arg::queue="red", arg::bindingKey="by-co\
+lour", arg::arguments=red);
- f.session.messageTransfer(qpid::client::arg::content=message, qpid::client::arg::destination="xml");
+ Message sent1("<>colour>blue</colour>", "by-colour");
+ f.session.messageTransfer(arg::content=sent1, arg::destination="xml");
- Message m2 = localQueue.get();
- BOOST_CHECK_EQUAL(m, m2.getData());
+ BOOST_CHECK_EQUAL(1, 1);
}
-//### Test: Bad XML does not kill the server
-//### Test: Bad XQuery does not kill the server
+//### Test: Bad XQuery does not kill the server, but does raise an exception
+
+QPID_AUTO_TEST_CASE(testXMLBadXQuery) {
+ ClientSessionFixture f;
+
+ f.session.exchangeDeclare(arg::exchange="xml", arg::type="xml");
+ f.session.queueDeclare(arg::queue="blue", arg::exclusive=true, arg::autoDelete=true)\
+ ;
+
+ try {
+ ScopedSuppressLogging sl; // Supress logging of error messages for expected error.
+ FieldTable blue;
+ blue.setString("xquery", "./colour $=! 'blue'");
+ f.session.exchangeBind(arg::exchange="xml", arg::queue="blue", arg::bindingKey="by-c\
+olour", arg::arguments=blue);
+ }
+ catch (const InternalErrorException& e) {
+ return;
+ }
+ BOOST_ERROR("A bad XQuery must raise an exception when used in an XML Binding.");
+
+}
+
+
+//### Test: Each session can provide its own definition for a query name
+
+
//### Test: Bindings persist, surviving broker restart
QPID_AUTO_TEST_SUITE_END()
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/acl.py b/cpp/src/tests/acl.py
new file mode 100755
index 0000000000..b27f2f1916
--- /dev/null
+++ b/cpp/src/tests/acl.py
@@ -0,0 +1,884 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import sys
+import qpid
+from qpid.util import connect
+from qpid.connection import Connection
+from qpid.datatypes import uuid4
+from qpid.testlib import TestBase010
+from qmf.console import Session
+from qpid.datatypes import Message
+
+class ACLFile:
+ def __init__(self):
+ self.f = open('data_dir/policy.acl','w');
+
+ def write(self,line):
+ self.f.write(line)
+
+ def close(self):
+ self.f.close()
+
+class ACLTests(TestBase010):
+
+ def get_session(self, user, passwd):
+ socket = connect(self.broker.host, self.broker.port)
+ connection = Connection (sock=socket, username=user, password=passwd)
+ connection.start()
+ return connection.session(str(uuid4()))
+
+ def reload_acl(self):
+ acl = self.qmf.getObjects(_class="acl")[0]
+ return acl.reloadACLFile()
+
+ def setUp(self):
+ aclf = ACLFile()
+ aclf.write('acl allow all all\n')
+ aclf.close()
+ TestBase010.setUp(self)
+ self.startQmf()
+ self.reload_acl()
+
+ #=====================================
+ # ACL general tests
+ #=====================================
+
+ def test_deny_mode(self):
+ """
+ Test the deny all mode
+ """
+ aclf = ACLFile()
+ aclf.write('acl allow anonymous all all\n')
+ aclf.write('acl allow bob@QPID create queue\n')
+ aclf.write('acl deny all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
+
+ session = self.get_session('bob','bob')
+ try:
+ session.queue_declare(queue="deny_queue")
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request");
+ self.fail("Error during queue create request");
+
+ try:
+ session.exchange_bind(exchange="amq.direct", queue="deny_queue", binding_key="routing_key")
+ self.fail("ACL should deny queue bind request");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+
+ def test_allow_mode(self):
+ """
+ Test the allow all mode
+ """
+ aclf = ACLFile()
+ aclf.write('acl deny bob@QPID bind exchange\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
+
+ session = self.get_session('bob','bob')
+ try:
+ session.queue_declare(queue="allow_queue")
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request");
+ self.fail("Error during queue create request");
+
+ try:
+ session.exchange_bind(exchange="amq.direct", queue="allow_queue", binding_key="routing_key")
+ self.fail("ACL should deny queue bind request");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+
+
+ def test_group_and_user_with_same_name(self):
+ """
+ Test a group and user with same name
+ Ex. group admin admin
+ """
+ aclf = ACLFile()
+ aclf.write('group bob@QPID bob@QPID\n')
+ aclf.write('acl deny bob@QPID bind exchange\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
+
+ session = self.get_session('bob','bob')
+ try:
+ session.queue_declare(queue="allow_queue")
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request");
+ self.fail("Error during queue create request");
+
+ try:
+ session.exchange_bind(exchange="amq.direct", queue="allow_queue", binding_key="routing_key")
+ self.fail("ACL should deny queue bind request");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+
+
+ #=====================================
+ # ACL file format tests
+ #=====================================
+
+ def test_empty_groups(self):
+ """
+ Test empty groups
+ """
+ aclf = ACLFile()
+ aclf.write('acl group\n')
+ aclf.write('acl group admins bob@QPID joe@QPID\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("Insufficient tokens for acl definition",0,len(result.text)) == -1):
+ self.fail("ACL Reader should reject the acl file due to empty group name")
+
+ def test_illegal_acl_formats(self):
+ """
+ Test illegal acl formats
+ """
+ aclf = ACLFile()
+ aclf.write('acl group admins bob@QPID joe@QPID\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("Unknown ACL permission",0,len(result.text)) == -1):
+ self.fail(result)
+
+ def test_illegal_extension_lines(self):
+ """
+ Test illegal extension lines
+ """
+
+ aclf = ACLFile()
+ aclf.write('group admins bob@QPID \ ')
+ aclf.write(' \ \n')
+ aclf.write('joe@QPID \n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("contains illegal characters",0,len(result.text)) == -1):
+ self.fail(result)
+
+ def test_user_without_realm(self):
+ """
+ Test a user defined without a realm
+ Ex. group admin rajith
+ """
+ aclf = ACLFile()
+ aclf.write('group admin bob\n')
+ aclf.write('acl deny admin bind exchange\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("Username 'bob' must contain a realm",0,len(result.text)) == -1):
+ self.fail(result)
+
+
+ #=====================================
+ # ACL queue tests
+ #=====================================
+
+ def test_queue_allow_mode(self):
+ """
+ Test cases for queue acl in allow mode
+ """
+ aclf = ACLFile()
+ aclf.write('acl deny bob@QPID create queue name=q1 durable=true passive=true\n')
+ aclf.write('acl deny bob@QPID create queue name=q2 exclusive=true policytype=ring\n')
+ aclf.write('acl deny bob@QPID access queue name=q3\n')
+ aclf.write('acl deny bob@QPID purge queue name=q3\n')
+ aclf.write('acl deny bob@QPID delete queue name=q4\n')
+ aclf.write('acl deny bob@QPID create queue name=q5 maxqueuesize=1000 maxqueuecount=100\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
+
+ session = self.get_session('bob','bob')
+
+ try:
+ session.queue_declare(queue="q1", durable=True, passive=True)
+ self.fail("ACL should deny queue create request with name=q1 durable=true passive=true");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ queue_options = {}
+ queue_options["qpid.policy_type"] = "ring"
+ session.queue_declare(queue="q2", exclusive=True, arguments=queue_options)
+ self.fail("ACL should deny queue create request with name=q2 exclusive=true qpid.policy_type=ring");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ queue_options = {}
+ queue_options["qpid.policy_type"] = "ring_strict"
+ session.queue_declare(queue="q2", exclusive=True, arguments=queue_options)
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request with name=q2 exclusive=true qpid.policy_type=ring_strict");
+
+ try:
+ queue_options = {}
+ queue_options["qpid.max_count"] = 200
+ queue_options["qpid.max_size"] = 500
+ session.queue_declare(queue="q5", exclusive=True, arguments=queue_options)
+ self.fail("ACL should deny queue create request with name=q2, qpid.max_size=500 and qpid.max_count=200");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ queue_options = {}
+ queue_options["qpid.max_count"] = 200
+ queue_options["qpid.max_size"] = 100
+ session.queue_declare(queue="q2", exclusive=True, arguments=queue_options)
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request with name=q2, qpid.max_size=100 and qpid.max_count=200 ");
+ try:
+ session.queue_declare(queue="q3", exclusive=True)
+ session.queue_declare(queue="q4", durable=True)
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request for q3 and q4 with any parameter");
+
+ try:
+ session.queue_query(queue="q3")
+ self.fail("ACL should deny queue query request for q3");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.queue_purge(queue="q3")
+ self.fail("ACL should deny queue purge request for q3");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.queue_purge(queue="q4")
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue purge request for q4");
+
+ try:
+ session.queue_delete(queue="q4")
+ self.fail("ACL should deny queue delete request for q4");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.queue_delete(queue="q3")
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue delete request for q3");
+
+
+ def test_queue_deny_mode(self):
+ """
+ Test cases for queue acl in deny mode
+ """
+ aclf = ACLFile()
+ aclf.write('acl allow bob@QPID create queue name=q1 durable=true passive=true\n')
+ aclf.write('acl allow bob@QPID create queue name=q2 exclusive=true policytype=ring\n')
+ aclf.write('acl allow bob@QPID access queue name=q3\n')
+ aclf.write('acl allow bob@QPID purge queue name=q3\n')
+ aclf.write('acl allow bob@QPID create queue name=q3\n')
+ aclf.write('acl allow bob@QPID create queue name=q4\n')
+ aclf.write('acl allow bob@QPID delete queue name=q4\n')
+ aclf.write('acl allow bob@QPID create queue name=q5 maxqueuesize=1000 maxqueuecount=100\n')
+ aclf.write('acl allow anonymous all all\n')
+ aclf.write('acl deny all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
+
+ session = self.get_session('bob','bob')
+
+ try:
+ session.queue_declare(queue="q1", durable=True, passive=True)
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request with name=q1 durable=true passive=true");
+
+ try:
+ session.queue_declare(queue="q1", durable=False, passive=False)
+ self.fail("ACL should deny queue create request with name=q1 durable=true passive=false");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.queue_declare(queue="q2", exclusive=False)
+ self.fail("ACL should deny queue create request with name=q2 exclusive=false");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ queue_options = {}
+ queue_options["qpid.max_count"] = 200
+ queue_options["qpid.max_size"] = 500
+ session.queue_declare(queue="q5", arguments=queue_options)
+ self.fail("ACL should deny queue create request with name=q2 maxqueuesize=500 maxqueuecount=200");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ queue_options = {}
+ queue_options["qpid.max_count"] = 100
+ queue_options["qpid.max_size"] = 500
+ session.queue_declare(queue="q5", arguments=queue_options)
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request with name=q2 maxqueuesize=500 maxqueuecount=200");
+
+ try:
+ queue_options = {}
+ queue_options["qpid.policy_type"] = "ring"
+ session.queue_declare(queue="q2", exclusive=True, arguments=queue_options)
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request for q2 with exclusive=true policytype=ring");
+
+ try:
+ session.queue_declare(queue="q3")
+ session.queue_declare(queue="q4")
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request for q3 and q4");
+
+ try:
+ session.queue_query(queue="q4")
+ self.fail("ACL should deny queue query request for q4");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.queue_purge(queue="q4")
+ self.fail("ACL should deny queue purge request for q4");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.queue_purge(queue="q3")
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue purge request for q3");
+
+ try:
+ session.queue_query(queue="q3")
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue query request for q3");
+
+ try:
+ session.queue_delete(queue="q3")
+ self.fail("ACL should deny queue delete request for q3");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.queue_delete(queue="q4")
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue delete request for q4");
+
+ #=====================================
+ # ACL exchange tests
+ #=====================================
+
+ def test_exchange_acl_allow_mode(self):
+ session = self.get_session('bob','bob')
+ session.queue_declare(queue="baz")
+
+ """
+ Test cases for exchange acl in allow mode
+ """
+ aclf = ACLFile()
+ aclf.write('acl deny bob@QPID create exchange name=testEx durable=true passive=true\n')
+ aclf.write('acl deny bob@QPID create exchange name=ex1 type=direct\n')
+ aclf.write('acl deny bob@QPID access exchange name=myEx queuename=q1 routingkey=rk1.*\n')
+ aclf.write('acl deny bob@QPID bind exchange name=myEx queuename=q1 routingkey=rk1\n')
+ aclf.write('acl deny bob@QPID unbind exchange name=myEx queuename=q1 routingkey=rk1\n')
+ aclf.write('acl deny bob@QPID delete exchange name=myEx\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
+
+ session = self.get_session('bob','bob')
+ session.queue_declare(queue='q1')
+ session.queue_declare(queue='q2')
+ session.exchange_declare(exchange='myEx', type='direct')
+
+ try:
+ session.exchange_declare(exchange='testEx', durable=True, passive=True)
+ self.fail("ACL should deny exchange create request with name=testEx durable=true passive=true");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_declare(exchange='testEx', type='direct', durable=True, passive=False)
+ except qpid.session.SessionException, e:
+ print e
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange create request for testEx with any parameter other than durable=true and passive=true");
+
+ try:
+ session.exchange_declare(exchange='ex1', type='direct')
+ self.fail("ACL should deny exchange create request with name=ex1 type=direct");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_declare(exchange='myXml', type='direct')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange create request for myXml with any parameter");
+
+ try:
+ session.exchange_query(name='myEx')
+ self.fail("ACL should deny exchange query request for myEx");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_bound(exchange='myEx', queue='q1', binding_key='rk1.*')
+ self.fail("ACL should deny exchange bound request for myEx with queuename=q1 and routing_key='rk1.*' ");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_query(name='amq.topic')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange query request for exchange='amq.topic'");
+
+ try:
+ session.exchange_bound(exchange='myEx', queue='q1', binding_key='rk2.*')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange bound request for myEx with queuename=q1 and binding_key='rk2.*'");
+
+ try:
+ session.exchange_bind(exchange='myEx', queue='q1', binding_key='rk1')
+ self.fail("ACL should deny exchange bind request with exchange='myEx' queuename='q1' bindingkey='rk1'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_bind(exchange='myEx', queue='q1', binding_key='x')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange bind request for exchange='myEx', queue='q1', binding_key='x'");
+
+ try:
+ session.exchange_bind(exchange='myEx', queue='q2', binding_key='rk1')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange bind request for exchange='myEx', queue='q2', binding_key='rk1'");
+
+ try:
+ session.exchange_unbind(exchange='myEx', queue='q1', binding_key='rk1')
+ self.fail("ACL should deny exchange unbind request with exchange='myEx' queuename='q1' bindingkey='rk1'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_unbind(exchange='myEx', queue='q1', binding_key='x')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange unbind request for exchange='myEx', queue='q1', binding_key='x'");
+
+ try:
+ session.exchange_unbind(exchange='myEx', queue='q2', binding_key='rk1')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange unbind request for exchange='myEx', queue='q2', binding_key='rk1'");
+
+ try:
+ session.exchange_delete(exchange='myEx')
+ self.fail("ACL should deny exchange delete request for myEx");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_delete(exchange='myXml')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange delete request for myXml");
+
+
+ def test_exchange_acl_deny_mode(self):
+ session = self.get_session('bob','bob')
+ session.queue_declare(queue='bar')
+
+ """
+ Test cases for exchange acl in deny mode
+ """
+ aclf = ACLFile()
+ aclf.write('acl allow bob@QPID create exchange name=myEx durable=true passive=false\n')
+ aclf.write('acl allow bob@QPID bind exchange name=amq.topic queuename=bar routingkey=foo.*\n')
+ aclf.write('acl allow bob@QPID unbind exchange name=amq.topic queuename=bar routingkey=foo.*\n')
+ aclf.write('acl allow bob@QPID access exchange name=myEx queuename=q1 routingkey=rk1.*\n')
+ aclf.write('acl allow bob@QPID delete exchange name=myEx\n')
+ aclf.write('acl allow anonymous all all\n')
+ aclf.write('acl deny all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
+
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_declare(exchange='myEx', type='direct', durable=True, passive=False)
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange create request for myEx with durable=true and passive=false");
+
+ try:
+ session.exchange_declare(exchange='myEx', type='direct', durable=False)
+ self.fail("ACL should deny exchange create request with name=myEx durable=false");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_bind(exchange='amq.topic', queue='bar', binding_key='foo.bar')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange bind request for exchange='amq.topic', queue='bar', binding_key='foor.bar'");
+
+ try:
+ session.exchange_bind(exchange='amq.topic', queue='baz', binding_key='foo.bar')
+ self.fail("ACL should deny exchange bind request for exchange='amq.topic', queue='baz', binding_key='foo.bar'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_bind(exchange='amq.topic', queue='bar', binding_key='fooz.bar')
+ self.fail("ACL should deny exchange bind request for exchange='amq.topic', queue='bar', binding_key='fooz.bar'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_unbind(exchange='amq.topic', queue='bar', binding_key='foo.bar')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange unbind request for exchange='amq.topic', queue='bar', binding_key='foor.bar'");
+ try:
+ session.exchange_unbind(exchange='amq.topic', queue='baz', binding_key='foo.bar')
+ self.fail("ACL should deny exchange unbind request for exchange='amq.topic', queue='baz', binding_key='foo.bar'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_unbind(exchange='amq.topic', queue='bar', binding_key='fooz.bar')
+ self.fail("ACL should deny exchange unbind request for exchange='amq.topic', queue='bar', binding_key='fooz.bar'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_query(name='amq.topic')
+ self.fail("ACL should deny exchange query request for amq.topic");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_bound(exchange='myEx', queue='q1', binding_key='rk2.*')
+ self.fail("ACL should deny exchange bound request for amq.topic with queuename=q1 and routing_key='rk2.*' ");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_query(name='myEx')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange query request for exchange='myEx'");
+
+ try:
+ session.exchange_bound(exchange='myEx', queue='q1', binding_key='rk1.*')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange bound request for myEx with queuename=q1 and binding_key='rk1.*'");
+
+ try:
+ session.exchange_delete(exchange='myXml')
+ self.fail("ACL should deny exchange delete request for myXml");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_delete(exchange='myEx')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange delete request for myEx");
+
+ #=====================================
+ # ACL consume tests
+ #=====================================
+
+ def test_consume_allow_mode(self):
+ """
+ Test cases for consume in allow mode
+ """
+ aclf = ACLFile()
+ aclf.write('acl deny bob@QPID consume queue name=q1\n')
+ aclf.write('acl deny bob@QPID consume queue name=q2\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
+
+ session = self.get_session('bob','bob')
+
+
+ try:
+ session.queue_declare(queue='q1')
+ session.queue_declare(queue='q2')
+ session.queue_declare(queue='q3')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow create queue request");
+
+ try:
+ session.message_subscribe(queue='q1', destination='myq1')
+ self.fail("ACL should deny subscription for queue='q1'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.message_subscribe(queue='q2', destination='myq1')
+ self.fail("ACL should deny subscription for queue='q2'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.message_subscribe(queue='q3', destination='myq1')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow subscription for q3");
+
+
+ def test_consume_deny_mode(self):
+ """
+ Test cases for consume in allow mode
+ """
+ aclf = ACLFile()
+ aclf.write('acl allow bob@QPID consume queue name=q1\n')
+ aclf.write('acl allow bob@QPID consume queue name=q2\n')
+ aclf.write('acl allow bob@QPID create queue\n')
+ aclf.write('acl allow anonymous all\n')
+ aclf.write('acl deny all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
+
+ session = self.get_session('bob','bob')
+
+
+ try:
+ session.queue_declare(queue='q1')
+ session.queue_declare(queue='q2')
+ session.queue_declare(queue='q3')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow create queue request");
+
+ try:
+ session.message_subscribe(queue='q1', destination='myq1')
+ session.message_subscribe(queue='q2', destination='myq2')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow subscription for q1 and q2");
+
+ try:
+ session.message_subscribe(queue='q3', destination='myq3')
+ self.fail("ACL should deny subscription for queue='q3'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+
+ #=====================================
+ # ACL publish tests
+ #=====================================
+
+ def test_publish_acl_allow_mode(self):
+ """
+ Test various publish acl
+ """
+ aclf = ACLFile()
+ aclf.write('acl deny bob@QPID publish exchange name=amq.direct routingkey=rk1\n')
+ aclf.write('acl deny bob@QPID publish exchange name=amq.topic\n')
+ aclf.write('acl deny bob@QPID publish exchange name=myEx routingkey=rk2\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
+
+ session = self.get_session('bob','bob')
+
+ props = session.delivery_properties(routing_key="rk1")
+
+ try:
+ session.message_transfer(destination="amq.direct", message=Message(props,"Test"))
+ self.fail("ACL should deny message transfer to name=amq.direct routingkey=rk1");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.message_transfer(destination="amq.topic", message=Message(props,"Test"))
+ self.fail("ACL should deny message transfer to name=amq.topic");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.exchange_declare(exchange='myEx', type='direct', durable=False)
+ session.message_transfer(destination="myEx", message=Message(props,"Test"))
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow message transfer to exchange myEx with routing key rk1");
+
+
+ props = session.delivery_properties(routing_key="rk2")
+ try:
+ session.message_transfer(destination="amq.direct", message=Message(props,"Test"))
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow message transfer to exchange amq.direct with routing key rk2");
+
+
+ def test_publish_acl_deny_mode(self):
+ """
+ Test various publish acl
+ """
+ aclf = ACLFile()
+ aclf.write('acl allow bob@QPID publish exchange name=amq.direct routingkey=rk1\n')
+ aclf.write('acl allow bob@QPID publish exchange name=amq.topic\n')
+ aclf.write('acl allow bob@QPID publish exchange name=myEx routingkey=rk2\n')
+ aclf.write('acl allow bob@QPID create exchange\n')
+ aclf.write('acl allow anonymous all all \n')
+ aclf.write('acl deny all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("format error",0,len(result.text)) != -1):
+ self.fail(result)
+
+ session = self.get_session('bob','bob')
+
+ props = session.delivery_properties(routing_key="rk2")
+
+ try:
+ session.message_transfer(destination="amq.direct", message=Message(props,"Test"))
+ self.fail("ACL should deny message transfer to name=amq.direct routingkey=rk2");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.message_transfer(destination="amq.topic", message=Message(props,"Test"))
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow message transfer to exchange amq.topic with any routing key");
+
+ try:
+ session.exchange_declare(exchange='myEx', type='direct', durable=False)
+ session.message_transfer(destination="myEx", message=Message(props,"Test"))
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow message transfer to exchange myEx with routing key=rk2");
+
+ props = session.delivery_properties(routing_key="rk1")
+
+ try:
+ session.message_transfer(destination="myEx", message=Message(props,"Test"))
+ self.fail("ACL should deny message transfer to name=myEx routingkey=rk1");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.message_transfer(destination="amq.direct", message=Message(props,"Test"))
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow message transfer to exchange amq.direct with routing key rk1");
diff --git a/cpp/src/tests/ais_check b/cpp/src/tests/ais_check
index d76841eb1d..92eaa9dd39 100755
--- a/cpp/src/tests/ais_check
+++ b/cpp/src/tests/ais_check
@@ -1,37 +1,34 @@
#!/bin/sh
-srcdir=`dirname $0`
-
-# Check AIS requirements tests if found.
-id -nG | grep '\<ais\>' >/dev/null || \
- NOGROUP="You are not a member of the ais group."
-ps -u root | grep aisexec >/dev/null || \
- NOAISEXEC="The aisexec daemon is not running as root"
-
-if test -n "$NOGROUP" -o -n "$NOAISEXEC"; then
- cat <<EOF
-
- =========== WARNING: NOT RUNNING AIS TESTS ==============
-
- Tests that depend on the openais library (used for clustering)
- will not be run because:
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
- $NOGROUP
- $NOAISEXEC
+srcdir=`dirname $0`
- ==========================================================
-
-EOF
+# Check AIS requirements and run tests if found.
+ps -u root | grep 'aisexec\|corosync' >/dev/null || {
+ echo WARNING: Skipping cluster tests, the aisexec or corosync daemon is not running.
exit 0; # A warning, not a failure.
-fi
+}
-# Execute command with the ais group set.
+# Execute command with the ais group set if user is a member.
with_ais_group() {
- id -nG | grep '\<ais\>' >/dev/null || { echo "You are not a member of the ais group."; exit 1; }
- echo $* | newgrp ais
+ if id -nG | grep '\<ais\>' >/dev/null; then sg ais -c "$*"
+ else "$@"
+ fi
}
-
-# Run the tests
-srcdir=`dirname $0`
-with_ais_group $srcdir/run_test ./cluster_test || ERROR=1
-exit $ERROR
-
diff --git a/cpp/src/tests/allSegmentTypes.h b/cpp/src/tests/allSegmentTypes.h
deleted file mode 100644
index e942250c89..0000000000
--- a/cpp/src/tests/allSegmentTypes.h
+++ /dev/null
@@ -1,128 +0,0 @@
-#ifndef TESTS_ALLSEGMENTTYPES_H
-#define TESTS_ALLSEGMENTTYPES_H
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-///
-/// This file was automatically generated from the AMQP specification.
-/// Do not edit.
-///
-
-
-#include "qpid/amqp_0_10/specification.h"
-#include "qpid/amqp_0_10/Header.h"
-#include "qpid/amqp_0_10/Body.h"
-
-using namespace qpid::amqp_0_10;
-
-template <class Op> size_t allSegmentTypes(Op& op) {
- op(Header());
- op(Body());
- op(ControlHolder(connection::Start()));
- op(ControlHolder(connection::StartOk()));
- op(ControlHolder(connection::Secure()));
- op(ControlHolder(connection::SecureOk()));
- op(ControlHolder(connection::Tune()));
- op(ControlHolder(connection::TuneOk()));
- op(ControlHolder(connection::Open()));
- op(ControlHolder(connection::OpenOk()));
- // op(ControlHolder(connection::Redirect())); // known-hosts array
- op(ControlHolder(connection::Heartbeat()));
- // op(ControlHolder(connection::Close())); // class/method dropped
- op(ControlHolder(connection::CloseOk()));
- op(ControlHolder(session::Attach()));
- op(ControlHolder(session::Attached()));
- op(ControlHolder(session::Detach()));
- op(ControlHolder(session::Detached()));
- op(ControlHolder(session::RequestTimeout()));
- op(ControlHolder(session::Timeout()));
- op(ControlHolder(session::CommandPoint()));
- // op(ControlHolder(session::Expected())); // fragments array encoding problem
- // op(ControlHolder(session::Confirmed())); // fragments array encoding problem
- op(ControlHolder(session::Completed()));
- op(ControlHolder(session::KnownCompleted()));
- op(ControlHolder(session::Flush()));
- op(ControlHolder(session::Gap()));
- // FIXME aconway 2008-04-15: command encoding, fix headers, fix sized structs.
- op(CommandHolder(execution::Sync()));
- op(CommandHolder(execution::Result()));
-
- // FIXME aconway 2008-04-16: investigate remaining failures.
- // op(CommandHolder(execution::Exception()));
- op(CommandHolder(message::Transfer()));
- op(CommandHolder(message::Accept()));
- // op(CommandHolder(message::Reject()));
- op(CommandHolder(message::Release()));
- op(CommandHolder(message::Acquire()));
- // op(CommandHolder(message::Resume()));
- op(CommandHolder(message::Subscribe()));
- op(CommandHolder(message::Cancel()));
- op(CommandHolder(message::SetFlowMode()));
- op(CommandHolder(message::Flow()));
- op(CommandHolder(message::Flush()));
- op(CommandHolder(message::Stop()));
- op(CommandHolder(tx::Select()));
- op(CommandHolder(tx::Commit()));
- op(CommandHolder(tx::Rollback()));
- op(CommandHolder(dtx::Select()));
- // op(CommandHolder(dtx::Start()));
- // op(CommandHolder(dtx::End()));
- // op(CommandHolder(dtx::Commit()));
- // op(CommandHolder(dtx::Forget()));
- // op(CommandHolder(dtx::GetTimeout()));
- // op(CommandHolder(dtx::Prepare()));
- // op(CommandHolder(dtx::Recover()));
- // op(CommandHolder(dtx::Rollback()));
- // op(CommandHolder(dtx::SetTimeout()));
- op(CommandHolder(exchange::Declare()));
- op(CommandHolder(exchange::Delete()));
- op(CommandHolder(exchange::Query()));
- op(CommandHolder(exchange::Bind()));
- op(CommandHolder(exchange::Unbind()));
- op(CommandHolder(exchange::Bound()));
- op(CommandHolder(queue::Declare()));
- op(CommandHolder(queue::Delete()));
- op(CommandHolder(queue::Purge()));
- op(CommandHolder(queue::Query()));
- // op(CommandHolder(file::Qos()));
- // op(CommandHolder(file::QosOk()));
-// op(CommandHolder(file::Consume()));
-// op(CommandHolder(file::ConsumeOk()));
-// op(CommandHolder(file::Cancel()));
-// op(CommandHolder(file::Open()));
-// op(CommandHolder(file::OpenOk()));
-// op(CommandHolder(file::Stage()));
-// op(CommandHolder(file::Publish()));
-// op(CommandHolder(file::Return()));
-// op(CommandHolder(file::Deliver()));
-// op(CommandHolder(file::Ack()));
-// op(CommandHolder(file::Reject()));
-// op(CommandHolder(stream::Qos()));
-// op(CommandHolder(stream::QosOk()));
-// op(CommandHolder(stream::Consume()));
-// op(CommandHolder(stream::ConsumeOk()));
-// op(CommandHolder(stream::Cancel()));
-// op(CommandHolder(stream::Publish()));
-// op(CommandHolder(stream::Return()));
-// op(CommandHolder(stream::Deliver()));
- return 0;
-}
-#endif /*!TESTS_ALLSEGMENTTYPES_H*/
diff --git a/cpp/src/tests/amqp_0_10/Map.cpp b/cpp/src/tests/amqp_0_10/Map.cpp
index efde967050..ffb235829e 100644
--- a/cpp/src/tests/amqp_0_10/Map.cpp
+++ b/cpp/src/tests/amqp_0_10/Map.cpp
@@ -18,7 +18,7 @@
* under the License.
*
*/
-#include "unit_test.h"
+#include "amqp_0_10/unit_test.h"
#include "qpid/amqp_0_10/Map.h"
#include "qpid/amqp_0_10/Array.h"
#include "qpid/amqp_0_10/Struct32.h"
diff --git a/cpp/src/tests/amqp_0_10/ProxyTemplate.cpp b/cpp/src/tests/amqp_0_10/ProxyTemplate.cpp
index 9d4fcb8935..f54ee0da22 100644
--- a/cpp/src/tests/amqp_0_10/ProxyTemplate.cpp
+++ b/cpp/src/tests/amqp_0_10/ProxyTemplate.cpp
@@ -19,7 +19,7 @@
*
*/
-#include "unit_test.h"
+#include "amqp_0_10/unit_test.h"
#include "qpid/amqp_0_10/ProxyTemplate.h"
#include <boost/any.hpp>
diff --git a/cpp/src/tests/amqp_0_10/apply.cpp b/cpp/src/tests/amqp_0_10/apply.cpp
index 5a67c28c79..0aa4421791 100644
--- a/cpp/src/tests/amqp_0_10/apply.cpp
+++ b/cpp/src/tests/amqp_0_10/apply.cpp
@@ -18,7 +18,7 @@
* under the License.
*
*/
-#include "unit_test.h"
+#include "amqp_0_10/unit_test.h"
#include "qpid/amqp_0_10/specification.h"
#include "qpid/amqp_0_10/ApplyControl.h"
diff --git a/cpp/src/tests/amqp_0_10/handlers.cpp b/cpp/src/tests/amqp_0_10/handlers.cpp
index 428643c802..91bb304a17 100644
--- a/cpp/src/tests/amqp_0_10/handlers.cpp
+++ b/cpp/src/tests/amqp_0_10/handlers.cpp
@@ -19,7 +19,7 @@
*
*/
-#include "unit_test.h"
+#include "amqp_0_10/unit_test.h"
#include "qpid/Exception.h"
#include "qpid/amqp_0_10/Unit.h"
#include "qpid/amqp_0_10/ControlHolder.h"
diff --git a/cpp/src/tests/amqp_0_10/serialize.cpp b/cpp/src/tests/amqp_0_10/serialize.cpp
index 0cfeb8d28d..975d6206ec 100644
--- a/cpp/src/tests/amqp_0_10/serialize.cpp
+++ b/cpp/src/tests/amqp_0_10/serialize.cpp
@@ -19,8 +19,8 @@
*
*/
-#include "unit_test.h"
-#include "allSegmentTypes.h"
+#include "amqp_0_10/unit_test.h"
+#include "amqp_0_10/allSegmentTypes.h"
#include "qpid/framing/AMQFrame.h"
#include "qpid/framing/Buffer.h"
@@ -34,7 +34,7 @@
#include "qpid/amqp_0_10/FrameHeader.h"
#include "qpid/amqp_0_10/Map.h"
#include "qpid/amqp_0_10/Unit.h"
-#include "tests/allSegmentTypes.h"
+#include "allSegmentTypes.h"
#include <boost/test/test_case_template.hpp>
#include <boost/type_traits/is_arithmetic.hpp>
diff --git a/cpp/src/tests/background.ps1 b/cpp/src/tests/background.ps1
new file mode 100644
index 0000000000..36e9e4e6e9
--- /dev/null
+++ b/cpp/src/tests/background.ps1
@@ -0,0 +1,55 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Run a PowerShell scriptblock in a background process.
+param(
+ [scriptblock] $script # scriptblock to run
+)
+
+# break out of the script on any errors
+trap { break }
+
+# In order to pass a scriptblock to another powershell instance, it must
+# be encoded to pass through the command line.
+$encodedScript = [convert]::ToBase64String(
+ [Text.Encoding]::Unicode.GetBytes([string] $script))
+
+#$p = new-object System.Diagnostics.Process
+$si = new-object System.Diagnostics.ProcessStartInfo
+$si.WorkingDirectory = $pwd
+$si.FileName = (get-command powershell.exe).Definition
+$si.Arguments = "-encodedCommand $encodedScript"
+
+###### debugging setup
+#$si.CreateNoWindow = $true
+# UseShellExecute false required for RedirectStandard(Error, Output)
+#$si.UseShellExecute = $false
+#$si.RedirectStandardError = $true
+#$si.RedirectStandardOutput = $true
+######
+$si.UseShellExecute = $true
+
+##### Debugging, instead of the plain Start() above.
+#$output = [io.File]::AppendText("start.out")
+#$error = [io.File]::AppendText("start.err")
+$p = [System.Diagnostics.Process]::Start($si)
+#$output.WriteLine($p.StandardOutput.ReadToEnd())
+#$error.WriteLine($p.StandardError.ReadToEnd())
+#$p.WaitForExit()
+#$output.Close()
diff --git a/cpp/src/tests/benchmark b/cpp/src/tests/benchmark
new file mode 100755
index 0000000000..c075837847
--- /dev/null
+++ b/cpp/src/tests/benchmark
@@ -0,0 +1,95 @@
+#!/bin/sh
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# A basic "benchmark" to generate performacne samples of throughput
+# and latency against a single cluster member while they are replicating.
+#
+# Must be run in the qpid src/tests build directory.
+#
+
+usage() {
+cat <<EOF
+Usage: $0 [options] -- client hosts --- broker hosts
+Read the script for options.
+EOF
+}
+# Defaults
+TESTDIR=${TESTDIR:-$PWD} # Absolute path to test exes on all hosts.
+SCRIPTDIR=${SCRIPTDIR:-`dirname $0`} # Path to local test scripts directory.
+SAMPLES=10 # Runs of each test.
+COUNT=${COUNT:-10000} # Count for pub/sub tests.
+SIZE=${SIZE:-600} # Size of messages
+ECHO=${ECHO:-1000} # Count for echo test.
+NSUBS=${NSUBS:-4}
+NPUBS=${NPUBS:-4}
+
+collect() { eval $COLLECT=\""\$$COLLECT $*"\"; }
+COLLECT=ARGS
+while test $# -gt 0; do
+ case $1 in
+ --testdir) TESTDIR=$2 ; shift 2 ;;
+ --samples) SAMPLES=$2 ; shift 2 ;;
+ --count) COUNT=$2 ; shift 2 ;;
+ --echos) ECHO=$2 ; shift 2 ;;
+ --size) SIZE=$2 ; shift 2 ;;
+ --nsubs) NSUBS=$2 ; shift 2 ;;
+ --npubs) NPUBS=$2 ; shift 2 ;;
+ --) COLLECT=CLIENTARG; shift ;;
+ ---) COLLECT=BROKERARG; shift;;
+ *) collect $1; shift ;;
+ esac
+done
+
+CLIENTS=${CLIENTARG:-$CLIENTS}
+BROKERS=${BROKERARG:-$BROKERS}
+test -z "$CLIENTS" && { echo "Must specify at least one client host."; exit 1; }
+test -z "$BROKERS" && { echo "Must specify at least one broker host."; exit 1; }
+
+export TESTDIR # For perfdist
+CLIENTS=($CLIENTS) # Convert to array
+BROKERS=($BROKERS)
+trap "rm -f $FILES" EXIT
+
+dosamples() {
+ FILE=`mktemp`
+ FILES="$FILES $FILE"
+ TABS=`echo "$HEADING" | sed s'/[^ ]//g'`
+ {
+ echo "\"$*\"$TABS"
+ echo "$HEADING"
+ for (( i=0; i<$SAMPLES; ++i)) ; do echo "`$*`" ; done
+ echo
+ } | tee $FILE
+}
+
+HEADING="pub sub total Mb"
+dosamples $SCRIPTDIR/perfdist --size $SIZE --count $COUNT --nsubs $NSUBS --npubs $NPUBS -s -- ${CLIENTS[*]} --- ${BROKERS[*]}
+HEADING="pub"
+dosamples ssh -A ${CLIENTS[0]} $TESTDIR/publish --routing-key perftest0 --size $SIZE --count $COUNT -s -b ${BROKERS[0]}
+HEADING="sub"
+dosamples ssh -A ${CLIENTS[0]} $TESTDIR/consume --queue perftest0 -s --count $COUNT -b ${BROKERS[0]}
+HEADING="min max avg"
+dosamples ssh -A ${CLIENTS[0]} $TESTDIR/echotest --count $ECHO -s -b ${BROKERS[0]}
+
+echo
+echo "Tab separated spreadsheet (also saved as benchmark.tab):"
+echo
+
+echo "benchmark -- ${CLIENTS[*]} --- ${BROKERS[*]} " | tee benchmark.tab
+paste $FILES | tee -a benchmark.tab
diff --git a/cpp/src/tests/cli_tests.py b/cpp/src/tests/cli_tests.py
new file mode 100755
index 0000000000..a65097d431
--- /dev/null
+++ b/cpp/src/tests/cli_tests.py
@@ -0,0 +1,190 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import sys
+import os
+from qpid.testlib import TestBase010
+from qpid.datatypes import Message
+from qpid.queue import Empty
+from time import sleep
+
+class CliTests(TestBase010):
+
+ def remote_host(self):
+ return self.defines.get("remote-host", "localhost")
+
+ def remote_port(self):
+ return int(self.defines["remote-port"])
+
+ def cli_dir(self):
+ return self.defines["cli-dir"]
+
+ def makeQueue(self, qname, arguments):
+ ret = os.system(self.command(" add queue " + qname + " " + arguments))
+ self.assertEqual(ret, 0)
+ queues = self.qmf.getObjects(_class="queue")
+ for queue in queues:
+ if queue.name == qname:
+ return queue
+ assert False
+
+ def test_queue_params(self):
+ self.startQmf()
+ queue1 = self.makeQueue("test_queue_params1", "--limit-policy none")
+ queue2 = self.makeQueue("test_queue_params2", "--limit-policy reject")
+ queue3 = self.makeQueue("test_queue_params3", "--limit-policy flow-to-disk")
+ queue4 = self.makeQueue("test_queue_params4", "--limit-policy ring")
+ queue5 = self.makeQueue("test_queue_params5", "--limit-policy ring-strict")
+
+ LIMIT = "qpid.policy_type"
+ assert LIMIT not in queue1.arguments
+ self.assertEqual(queue2.arguments[LIMIT], "reject")
+ self.assertEqual(queue3.arguments[LIMIT], "flow_to_disk")
+ self.assertEqual(queue4.arguments[LIMIT], "ring")
+ self.assertEqual(queue5.arguments[LIMIT], "ring_strict")
+
+ queue6 = self.makeQueue("test_queue_params6", "--order fifo")
+ queue7 = self.makeQueue("test_queue_params7", "--order lvq")
+ queue8 = self.makeQueue("test_queue_params8", "--order lvq-no-browse")
+
+ LVQ = "qpid.last_value_queue"
+ LVQNB = "qpid.last_value_queue_no_browse"
+
+ assert LVQ not in queue6.arguments
+ assert LVQ in queue7.arguments
+ assert LVQ not in queue8.arguments
+
+ assert LVQNB not in queue6.arguments
+ assert LVQNB not in queue7.arguments
+ assert LVQNB in queue8.arguments
+
+ def test_qpid_config(self):
+ self.startQmf();
+ qmf = self.qmf
+ qname = "test_qpid_config"
+
+ ret = os.system(self.command(" add queue " + qname))
+ self.assertEqual(ret, 0)
+ queues = qmf.getObjects(_class="queue")
+ found = False
+ for queue in queues:
+ if queue.name == qname:
+ self.assertEqual(queue.durable, False)
+ found = True
+ self.assertEqual(found, True)
+
+ ret = os.system(self.command(" del queue " + qname))
+ self.assertEqual(ret, 0)
+ queues = qmf.getObjects(_class="queue")
+ found = False
+ for queue in queues:
+ if queue.name == qname:
+ found = True
+ self.assertEqual(found, False)
+
+ def test_qpid_config_durable(self):
+ self.startQmf();
+ qmf = self.qmf
+ qname = "test_qpid_config"
+
+ ret = os.system(self.command(" add queue --durable " + qname))
+ self.assertEqual(ret, 0)
+ queues = qmf.getObjects(_class="queue")
+ found = False
+ for queue in queues:
+ if queue.name == qname:
+ self.assertEqual(queue.durable, True)
+ found = True
+ self.assertEqual(found, True)
+
+ ret = os.system(self.command(" del queue " + qname))
+ self.assertEqual(ret, 0)
+ queues = qmf.getObjects(_class="queue")
+ found = False
+ for queue in queues:
+ if queue.name == qname:
+ found = True
+ self.assertEqual(found, False)
+
+ def test_qpid_config_altex(self):
+ self.startQmf();
+ qmf = self.qmf
+ exName = "testalt"
+ qName = "testqalt"
+ altName = "amq.direct"
+
+ ret = os.system(self.command(" add exchange topic %s --alternate-exchange=%s" % (exName, altName)))
+ self.assertEqual(ret, 0)
+
+ exchanges = qmf.getObjects(_class="exchange")
+ found = False
+ for exchange in exchanges:
+ if exchange.name == altName:
+ self.assertEqual(exchange.altExchange, None)
+
+ if exchange.name == exName:
+ found = True
+ if not exchange.altExchange:
+ self.fail("Alternate exchange not set")
+ self.assertEqual(exchange._altExchange_.name, altName)
+ self.assertEqual(found, True)
+
+ ret = os.system(self.command(" add queue %s --alternate-exchange=%s" % (qName, altName)))
+ self.assertEqual(ret, 0)
+
+ queues = qmf.getObjects(_class="queue")
+ found = False
+ for queue in queues:
+ if queue.name == qName:
+ found = True
+ if not queue.altExchange:
+ self.fail("Alternate exchange not set")
+ self.assertEqual(queue._altExchange_.name, altName)
+ self.assertEqual(found, True)
+
+ def test_qpid_route(self):
+ self.startQmf();
+ qmf = self.qmf
+
+ command = self.cli_dir() + "/qpid-route dynamic add guest/guest@localhost:%d %s:%d amq.topic" %\
+ (self.broker.port, self.remote_host(), self.remote_port())
+ ret = os.system(command)
+ self.assertEqual(ret, 0)
+
+ links = qmf.getObjects(_class="link")
+ found = False
+ for link in links:
+ if link.port == self.remote_port():
+ found = True
+ self.assertEqual(found, True)
+
+ def getProperty(self, msg, name):
+ for h in msg.headers:
+ if hasattr(h, name): return getattr(h, name)
+ return None
+
+ def getAppHeader(self, msg, name):
+ headers = self.getProperty(msg, "application_headers")
+ if headers:
+ return headers[name]
+ return None
+
+ def command(self, arg = ""):
+ return self.cli_dir() + "/qpid-config -a localhost:%d" % self.broker.port + " " + arg
diff --git a/cpp/src/tests/client_test.cpp b/cpp/src/tests/client_test.cpp
index 204c2c4b71..2f5e8e5afe 100644
--- a/cpp/src/tests/client_test.cpp
+++ b/cpp/src/tests/client_test.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -32,21 +32,24 @@
#include "qpid/client/Connection.h"
#include "qpid/client/Message.h"
#include "qpid/client/Session.h"
-#include "qpid/framing/FrameSet.h"
-#include "qpid/framing/all_method_bodies.h"
+#include "qpid/client/SubscriptionManager.h"
+
using namespace qpid;
using namespace qpid::client;
using namespace qpid::framing;
using std::string;
+namespace qpid {
+namespace tests {
+
struct Args : public TestOptions {
uint msgSize;
bool verbose;
Args() : TestOptions("Simple test of Qpid c++ client; sends and receives a single message."), msgSize(26)
{
- addOptions()
+ addOptions()
("size", optValue(msgSize, "N"), "message size")
("verbose", optValue(verbose), "print out some status messages");
}
@@ -58,7 +61,7 @@ std::string generateData(uint size)
{
if (size < chars.length()) {
return chars.substr(0, size);
- }
+ }
std::string data;
for (uint i = 0; i < (size / chars.length()); i++) {
data += chars;
@@ -78,6 +81,10 @@ void print(const std::string& text, const Message& msg)
std::cout << std::endl;
}
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char** argv)
{
try {
@@ -92,7 +99,7 @@ int main(int argc, char** argv)
//Create and open a session on the connection through which
//most functionality is exposed:
Session session = connection.newSession();
- if (opts.verbose) std::cout << "Opened session." << std::endl;
+ if (opts.verbose) std::cout << "Opened session." << std::endl;
//'declare' the exchange and the queue, which will create them
@@ -113,35 +120,18 @@ int main(int argc, char** argv)
session.messageTransfer(arg::destination="MyExchange", arg::content=msgOut, arg::acceptMode=1);
if (opts.verbose) print("Published message: ", msgOut);
- //subscribe to the queue, add sufficient credit and then get
- //incoming 'frameset', check that its a message transfer and
- //then convert it to a message (see Dispatcher and
- //SubscriptionManager utilties for common reusable patterns at
- //a higher level)
- session.messageSubscribe(arg::queue="MyQueue", arg::destination="MyId");
- session.messageFlow(arg::destination="MyId", arg::unit=0, arg::value=1); //credit for one message
- session.messageFlow(arg::destination="MyId", arg::unit=1, arg::value=0xFFFFFFFF); //credit for infinite bytes
- if (opts.verbose) std::cout << "Subscribed to queue." << std::endl;
- FrameSet::shared_ptr incoming = session.get();
- if (incoming->isA<MessageTransferBody>()) {
- Message msgIn(*incoming);
- if (msgIn.getData() == msgOut.getData()) {
- if (opts.verbose) std::cout << "Received the exepected message." << std::endl;
- session.messageAccept(SequenceSet(msgIn.getId()));
- session.markCompleted(msgIn.getId(), true, true);
- } else {
- print("Received an unexepected message: ", msgIn);
- }
- } else {
- throw Exception("Unexpected command received");
- }
-
+ // Using the SubscriptionManager, get the message from the queue.
+ SubscriptionManager subs(session);
+ Message msgIn = subs.get("MyQueue");
+ if (msgIn.getData() == msgOut.getData())
+ if (opts.verbose) std::cout << "Received the exepected message." << std::endl;
+
//close the session & connection
session.close();
if (opts.verbose) std::cout << "Closed session." << std::endl;
- connection.close();
+ connection.close();
if (opts.verbose) std::cout << "Closed connection." << std::endl;
- return 0;
+ return 0;
} catch(const std::exception& e) {
std::cout << e.what() << std::endl;
}
diff --git a/cpp/src/tests/cluster.cmake b/cpp/src/tests/cluster.cmake
new file mode 100644
index 0000000000..9084bfb85b
--- /dev/null
+++ b/cpp/src/tests/cluster.cmake
@@ -0,0 +1,86 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#
+# Cluster tests cmake fragment, to be included in CMakeLists.txt
+#
+
+add_executable (failover_soak failover_soak.cpp ForkedBroker.cpp ${platform_test_additions})
+target_link_libraries (failover_soak qpidclient)
+remember_location(failover_soak)
+
+set (cluster_test_SOURCES
+ cluster_test
+ unit_test
+ ClusterFixture
+ ForkedBroker
+ PartialFailure
+ ClusterFailover
+ InitialStatusMap
+ StoreStatus
+ )
+add_executable (cluster_test ${cluster_test_SOURCES} ${platform_test_additions})
+target_link_libraries (cluster_test ${qpid_test_boost_libs} qpidclient qpidbroker cluster_shared)
+remember_location(cluster_test)
+
+add_test (cluster_test ${CMAKE_CURRENT_SOURCE_DIR}/run_cluster_test${test_script_suffix})
+add_test (cluster_tests ${CMAKE_CURRENT_SOURCE_DIR}/run_cluster_tests${test_script_suffix})
+add_test (cluster_read_credit ${CMAKE_CURRENT_SOURCE_DIR}/cluster_read_credit${test_script_suffix})
+add_test (cluster_test_watchdog ${CMAKE_CURRENT_SOURCE_DIR}/test_watchdog${test_script_suffix})
+add_test (federated_cluster_test ${CMAKE_CURRENT_SOURCE_DIR}/federated_cluster_test${test_script_suffix})
+add_test (clustered_replication_test ${CMAKE_CURRENT_SOURCE_DIR}/clustered_replication_test${test_script_suffix})
+
+# FIXME aconway 2009-12-01: translate to cmake
+# # Clean up after cluster_test and start_cluster
+# CLEANFILES += cluster_test.acl cluster.ports
+
+# EXTRA_DIST += \
+# ais_check \
+# run_cluster_test \
+# cluster_read_credit \
+# test_watchdog \
+# start_cluster \
+# stop_cluster \
+# restart_cluster \
+# cluster_python_tests \
+# cluster_python_tests_failing.txt \
+# federated_cluster_test \
+# clustered_replication_test \
+# run_cluster_tests \
+# run_long_cluster_tests \
+# testlib.py \
+# cluster_tests.py \
+# long_cluster_tests.py \
+# cluster_tests.fail
+
+# LONG_TESTS += \
+# run_long_cluster_tests \
+# start_cluster \
+# cluster_python_tests \
+# stop_cluster
+
+# qpidtest_PROGRAMS += cluster_test
+
+# cluster_test_SOURCES = \
+
+# cluster_test_LDADD=$(lib_client) $(lib_broker) ../cluster.la -lboost_unit_test_framework
+
+# qpidtest_SCRIPTS += run_cluster_tests cluster_tests.py run_long_cluster_tests long_cluster_tests.py testlib.py cluster_tests.fail
+
+# endif
diff --git a/cpp/src/tests/cluster.mk b/cpp/src/tests/cluster.mk
index 8b83e927ec..20053788e4 100644
--- a/cpp/src/tests/cluster.mk
+++ b/cpp/src/tests/cluster.mk
@@ -1,21 +1,86 @@
-if CPG
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+if HAVE_LIBCPG
+
#
# Cluster tests makefile fragment, to be included in Makefile.am
#
-lib_cluster = $(abs_builddir)/../libqpidcluster.la
-
# NOTE: Programs using the openais library must be run with gid=ais
# You should do "newgrp ais" before running the tests to run these.
#
# ais_check checks pre-requisites for cluster tests and runs them if ok.
-TESTS+=ais_check
-EXTRA_DIST+=ais_check start_cluster stop_cluster
+TESTS += \
+ run_cluster_test \
+ cluster_read_credit \
+ test_watchdog \
+ run_cluster_tests \
+ federated_cluster_test \
+ clustered_replication_test
+
+# Clean up after cluster_test and start_cluster
+CLEANFILES += cluster_test.acl cluster.ports
+
+EXTRA_DIST += \
+ ais_check \
+ run_cluster_test \
+ cluster_read_credit \
+ test_watchdog \
+ start_cluster \
+ stop_cluster \
+ restart_cluster \
+ cluster_python_tests \
+ cluster_python_tests_failing.txt \
+ federated_cluster_test \
+ clustered_replication_test \
+ run_cluster_tests \
+ run_long_cluster_tests \
+ testlib.py \
+ cluster_tests.py \
+ long_cluster_tests.py \
+ cluster_tests.fail
+
+LONG_TESTS += \
+ run_long_cluster_tests \
+ start_cluster \
+ cluster_python_tests \
+ stop_cluster
+
+qpidtest_PROGRAMS += cluster_test
+
+cluster_test_SOURCES = \
+ cluster_test.cpp \
+ unit_test.cpp \
+ ClusterFixture.cpp \
+ ClusterFixture.h \
+ ForkedBroker.h \
+ ForkedBroker.cpp \
+ PartialFailure.cpp \
+ ClusterFailover.cpp \
+ InitialStatusMap.cpp \
+ StoreStatus.cpp
+
+cluster_test_LDADD=$(lib_client) $(lib_broker) ../cluster.la -lboost_unit_test_framework
-check_PROGRAMS+=cluster_test
-cluster_test_SOURCES=unit_test.cpp cluster_test.cpp
-cluster_test_LDADD=$(lib_client) $(lib_cluster) -lboost_unit_test_framework
+qpidtest_SCRIPTS += run_cluster_tests cluster_tests.py run_long_cluster_tests long_cluster_tests.py testlib.py cluster_tests.fail
endif
diff --git a/cpp/src/tests/cluster_python_tests b/cpp/src/tests/cluster_python_tests
new file mode 100755
index 0000000000..1a3fa4aff8
--- /dev/null
+++ b/cpp/src/tests/cluster_python_tests
@@ -0,0 +1,5 @@
+#!/bin/sh
+#
+FAILING=`dirname $0`/cluster_python_tests_failing.txt
+source `dirname $0`/python_tests
+
diff --git a/cpp/src/tests/cluster_python_tests_failing.txt b/cpp/src/tests/cluster_python_tests_failing.txt
new file mode 100644
index 0000000000..53b609942d
--- /dev/null
+++ b/cpp/src/tests/cluster_python_tests_failing.txt
@@ -0,0 +1,31 @@
+tests_0-10.management.ManagementTest.test_purge_queue
+tests_0-10.management.ManagementTest.test_connection_close
+tests_0-10.dtx.DtxTests.test_bad_resume
+tests_0-10.dtx.DtxTests.test_commit_unknown
+tests_0-10.dtx.DtxTests.test_end
+tests_0-10.dtx.DtxTests.test_end_suspend_and_fail
+tests_0-10.dtx.DtxTests.test_end_unknown_xid
+tests_0-10.dtx.DtxTests.test_forget_xid_on_completion
+tests_0-10.dtx.DtxTests.test_get_timeout
+tests_0-10.dtx.DtxTests.test_get_timeout_unknown
+tests_0-10.dtx.DtxTests.test_implicit_end
+tests_0-10.dtx.DtxTests.test_invalid_commit_not_ended
+tests_0-10.dtx.DtxTests.test_invalid_commit_one_phase_false
+tests_0-10.dtx.DtxTests.test_invalid_commit_one_phase_true
+tests_0-10.dtx.DtxTests.test_invalid_prepare_not_ended
+tests_0-10.dtx.DtxTests.test_invalid_rollback_not_ended
+tests_0-10.dtx.DtxTests.test_prepare_unknown
+tests_0-10.dtx.DtxTests.test_recover
+tests_0-10.dtx.DtxTests.test_rollback_unknown
+tests_0-10.dtx.DtxTests.test_select_required
+tests_0-10.dtx.DtxTests.test_set_timeout
+tests_0-10.dtx.DtxTests.test_simple_commit
+tests_0-10.dtx.DtxTests.test_simple_prepare_commit
+tests_0-10.dtx.DtxTests.test_simple_prepare_rollback
+tests_0-10.dtx.DtxTests.test_simple_rollback
+tests_0-10.dtx.DtxTests.test_start_already_known
+tests_0-10.dtx.DtxTests.test_start_join
+tests_0-10.dtx.DtxTests.test_start_join_and_resume
+tests_0-10.dtx.DtxTests.test_suspend_resume
+tests_0-10.dtx.DtxTests.test_suspend_start_end_resume
+tests_0-10.message.MessageTests.test_ttl
diff --git a/cpp/src/tests/cluster_read_credit b/cpp/src/tests/cluster_read_credit
new file mode 100755
index 0000000000..370d4098c5
--- /dev/null
+++ b/cpp/src/tests/cluster_read_credit
@@ -0,0 +1,27 @@
+#!/bin/sh
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Regression test for http://issues.apache.org/jira/browse/QPID-2086
+
+srcdir=`dirname $0`
+. $srcdir/ais_check
+$srcdir/start_cluster 1 --cluster-read-max=2 || exit 1
+trap $srcdir/stop_cluster EXIT
+seq 1 10000 | ./sender --port `cat cluster.ports` --routing-key no-such-queue
diff --git a/cpp/src/tests/cluster_test.cpp b/cpp/src/tests/cluster_test.cpp
index 49c5264990..33f23aa5b3 100644
--- a/cpp/src/tests/cluster_test.cpp
+++ b/cpp/src/tests/cluster_test.cpp
@@ -20,98 +20,78 @@
#include "unit_test.h"
#include "ForkedBroker.h"
#include "BrokerFixture.h"
+#include "ClusterFixture.h"
-#include "qpid/cluster/Cpg.h"
-#include "qpid/cluster/Cluster.h"
-#include "qpid/framing/AMQBody.h"
#include "qpid/client/Connection.h"
+#include "qpid/client/ConnectionSettings.h"
+#include "qpid/client/ConnectionAccess.h"
#include "qpid/client/Session.h"
+#include "qpid/client/FailoverListener.h"
+#include "qpid/client/FailoverManager.h"
+#include "qpid/client/QueueOptions.h"
+#include "qpid/cluster/Cluster.h"
+#include "qpid/cluster/Cpg.h"
+#include "qpid/cluster/UpdateClient.h"
+#include "qpid/framing/AMQBody.h"
#include "qpid/framing/Uuid.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/enum.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/log/Logger.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/sys/Thread.h"
#include <boost/bind.hpp>
-#include <boost/ptr_container/ptr_vector.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/assign.hpp>
#include <string>
#include <iostream>
+#include <fstream>
#include <iterator>
#include <vector>
+#include <set>
#include <algorithm>
-
-namespace qpid {
-namespace cluster {
-boost::intrusive_ptr<Cluster> getGlobalCluster(); // Defined in qpid/cluster/ClusterPlugin.cpp
-}} // namespace qpid::cluster
-
-
-QPID_AUTO_TEST_SUITE(CpgTestSuite)
+#include <iterator>
using namespace std;
using namespace qpid;
using namespace qpid::cluster;
using namespace qpid::framing;
using namespace qpid::client;
-using qpid::broker::Broker;
-using boost::ptr_vector;
-using qpid::cluster::Cluster;
-using qpid::cluster::getGlobalCluster;
+using namespace boost::assign;
+using broker::Broker;
+using boost::shared_ptr;
-/** Cluster fixture is a vector of ports for the replicas.
- * Replica 0 is in the current process, all others are forked as children.
- */
-struct ClusterFixture : public vector<uint16_t> {
- string name;
- Broker::Options opts;
- std::auto_ptr<BrokerFixture> broker0;
- boost::ptr_vector<ForkedBroker> forkedBrokers;
-
- ClusterFixture(size_t n);
- void add(size_t n) { for (size_t i=0; i < n; ++i) add(); }
- void add();
- void setup();
-};
+namespace qpid {
+namespace tests {
-ClusterFixture::ClusterFixture(size_t n) : name(Uuid(true).str()) {
- add(n);
- // Wait for all n members to join the cluster
- int retry=20; // TODO aconway 2008-07-16: nasty sleeps, clean this up.
- while (retry && getGlobalCluster()->size() != n) {
- ::sleep(1);
- --retry;
- }
- BOOST_CHECK_EQUAL(n, getGlobalCluster()->size());
-}
+QPID_AUTO_TEST_SUITE(cluster_test)
-void ClusterFixture::add() {
- std::ostringstream os;
- os << "broker" << size();
- std::string prefix = os.str();
+bool durableFlag = std::getenv("STORE_LIB") != 0;
- const char* argv[] = {
- "qpidd " __FILE__ ,
- "--load-module=../.libs/libqpidcluster.so",
- "--cluster-name", name.c_str(),
- "--auth=no", "--no-data-dir",
- "--log-prefix", prefix.c_str(),
- };
- size_t argc = sizeof(argv)/sizeof(argv[0]);
+void prepareArgs(ClusterFixture::Args& args, const bool durableFlag = false) {
+ ostringstream clusterLib;
+ clusterLib << getLibPath("CLUSTER_LIB");
+ args += "--auth", "no", "--no-module-dir", "--load-module", clusterLib.str();
+ if (durableFlag)
+ args += "--load-module", getLibPath("STORE_LIB"), "TMP_DATA_DIR";
+ else
+ args += "--no-data-dir";
+}
- if (size()) { // Not the first broker, fork.
- forkedBrokers.push_back(new ForkedBroker(argc, argv));
- push_back(forkedBrokers.back().getPort());
- }
- else { // First broker, run in this process.
- Broker::Options opts;
- Plugin::addOptions(opts); // Pick up cluster options.
- opts.parse(argc, argv, "", true); // Allow-unknown for --load-module
- broker0.reset(new BrokerFixture(opts));
- push_back(broker0->getPort());
- }
+ClusterFixture::Args prepareArgs(const bool durableFlag = false) {
+ ClusterFixture::Args args;
+ prepareArgs(args, durableFlag);
+ return args;
}
-// For debugging: op << for CPG types.
+// Timeout for tests that wait for messages
+const sys::Duration TIMEOUT=sys::TIME_SEC/2;
+
ostream& operator<<(ostream& o, const cpg_name* n) {
- return o << qpid::cluster::Cpg::str(*n);
+ return o << Cpg::str(*n);
}
ostream& operator<<(ostream& o, const cpg_address& a) {
@@ -127,55 +107,557 @@ ostream& operator<<(ostream& o, const pair<T*, int>& array) {
return o;
}
-struct Callback : public Cpg::Handler {
- Callback(const string group_) : group(group_) {}
- string group;
- vector<string> delivered;
- vector<int> configChanges;
+template <class C> set<int> makeSet(const C& c) {
+ set<int> s;
+ copy(c.begin(), c.end(), inserter(s, s.begin()));
+ return s;
+}
- void deliver (
- cpg_handle_t /*handle*/,
- struct cpg_name *grp,
- uint32_t /*nodeid*/,
- uint32_t /*pid*/,
- void* msg,
- int msg_len)
- {
- BOOST_CHECK_EQUAL(group, Cpg::str(*grp));
- delivered.push_back(string((char*)msg,msg_len));
+class Sender {
+ public:
+ Sender(boost::shared_ptr<ConnectionImpl> ci, uint16_t ch) : connection(ci), channel(ch) {}
+ void send(const AMQBody& body, bool firstSeg, bool lastSeg, bool firstFrame, bool lastFrame) {
+ AMQFrame f(body);
+ f.setChannel(channel);
+ f.setFirstSegment(firstSeg);
+ f.setLastSegment(lastSeg);
+ f.setFirstFrame(firstFrame);
+ f.setLastFrame(lastFrame);
+ connection->handle(f);
}
- void configChange(
- cpg_handle_t /*handle*/,
- struct cpg_name *grp,
- struct cpg_address */*members*/, int nMembers,
- struct cpg_address */*left*/, int nLeft,
- struct cpg_address */*joined*/, int nJoined
- )
- {
- BOOST_CHECK_EQUAL(group, Cpg::str(*grp));
- configChanges.push_back(nMembers);
- BOOST_MESSAGE("configChange: "<<
- nLeft<<" left "<<
- nJoined<<" joined "<<
- nMembers<<" members.");
+ private:
+ boost::shared_ptr<ConnectionImpl> connection;
+ uint16_t channel;
+};
+
+int64_t getMsgSequence(const Message& m) {
+ return m.getMessageProperties().getApplicationHeaders().getAsInt64("qpid.msg_sequence");
+}
+
+Message ttlMessage(const string& data, const string& key, uint64_t ttl, bool durable = false) {
+ Message m(data, key);
+ m.getDeliveryProperties().setTtl(ttl);
+ if (durable) m.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
+ return m;
+}
+
+Message makeMessage(const string& data, const string& key, bool durable = false) {
+ Message m(data, key);
+ if (durable) m.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
+ return m;
+}
+
+vector<string> browse(Client& c, const string& q, int n) {
+ SubscriptionSettings browseSettings(
+ FlowControl::messageCredit(n),
+ ACCEPT_MODE_NONE,
+ ACQUIRE_MODE_NOT_ACQUIRED,
+ 0 // No auto-ack.
+ );
+ LocalQueue lq;
+ c.subs.subscribe(lq, q, browseSettings);
+ vector<string> result;
+ for (int i = 0; i < n; ++i) {
+ Message m;
+ if (!lq.get(m, TIMEOUT))
+ break;
+ result.push_back(m.getData());
}
+ c.subs.getSubscription(q).cancel();
+ return result;
+}
+
+ConnectionSettings aclSettings(int port, const std::string& id) {
+ ConnectionSettings settings;
+ settings.port = port;
+ settings.mechanism = "PLAIN";
+ settings.username = id;
+ settings.password = id;
+ return settings;
+}
+
+// An illegal frame body
+struct PoisonPill : public AMQBody {
+ virtual uint8_t type() const { return 0xFF; }
+ virtual void encode(Buffer& ) const {}
+ virtual void decode(Buffer& , uint32_t=0) {}
+ virtual uint32_t encodedSize() const { return 0; }
+
+ virtual void print(std::ostream&) const {};
+ virtual void accept(AMQBodyConstVisitor&) const {};
+
+ virtual AMQMethodBody* getMethod() { return 0; }
+ virtual const AMQMethodBody* getMethod() const { return 0; }
+
+ /** Match if same type and same class/method ID for methods */
+ static bool match(const AMQBody& , const AMQBody& ) { return false; }
+ virtual boost::intrusive_ptr<AMQBody> clone() const { return new PoisonPill; }
};
-QPID_AUTO_TEST_CASE(testForkedBroker) {
- // Verify the ForkedBroker works as expected.
- const char* argv[] = { "", "--auth=no", "--no-data-dir", "--log-prefix=testForkedBroker" };
- ForkedBroker broker(sizeof(argv)/sizeof(argv[0]), argv);
- Client c(broker.getPort());
- BOOST_CHECK_EQUAL("direct", c.session.exchangeQuery("amq.direct").getType());
+QPID_AUTO_TEST_CASE(testBadClientData) {
+ // Ensure that bad data on a client connection closes the
+ // connection but does not stop the broker.
+ ClusterFixture::Args args;
+ prepareArgs(args, false);
+ args += "--log-enable=critical"; // Supress expected errors
+ ClusterFixture cluster(2, args, -1);
+ Client c0(cluster[0]);
+ Client c1(cluster[1]);
+ boost::shared_ptr<client::ConnectionImpl> ci =
+ client::ConnectionAccess::getImpl(c0.connection);
+ AMQFrame poison(boost::intrusive_ptr<AMQBody>(new PoisonPill));
+ ci->handle(poison);
+ {
+ ScopedSuppressLogging sl;
+ BOOST_CHECK_THROW(c0.session.queueQuery("q0"), TransportFailure);
+ }
+ Client c00(cluster[0]);
+ BOOST_CHECK_EQUAL(c00.session.queueQuery("q00").getQueue(), "");
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q1").getQueue(), "");
+}
+
+QPID_AUTO_TEST_CASE(testAcl) {
+ ofstream policyFile("cluster_test.acl");
+ policyFile << "acl allow foo@QPID create queue name=foo" << endl
+ << "acl allow foo@QPID create queue name=foo2" << endl
+ << "acl deny foo@QPID create queue name=bar" << endl
+ << "acl allow all all" << endl;
+ policyFile.close();
+ char cwd[1024];
+ BOOST_CHECK(::getcwd(cwd, sizeof(cwd)));
+ ostringstream aclLib;
+ aclLib << getLibPath("ACL_LIB");
+ ClusterFixture::Args args;
+ prepareArgs(args, durableFlag);
+ args += "--log-enable=critical"; // Supress expected errors
+ args += "--acl-file", string(cwd) + "/cluster_test.acl",
+ "--cluster-mechanism", "PLAIN",
+ "--cluster-username", "cluster",
+ "--cluster-password", "cluster",
+ "--load-module", aclLib.str();
+ ClusterFixture cluster(2, args, -1);
+
+ Client c0(aclSettings(cluster[0], "c0"), "c0");
+ Client c1(aclSettings(cluster[1], "c1"), "c1");
+ Client foo(aclSettings(cluster[1], "foo"), "foo");
+
+ foo.session.queueDeclare("foo", arg::durable=durableFlag);
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("foo").getQueue(), "foo");
+
+ {
+ ScopedSuppressLogging sl;
+ BOOST_CHECK_THROW(foo.session.queueDeclare("bar", arg::durable=durableFlag), framing::NotAllowedException);
+ }
+ BOOST_CHECK(c0.session.queueQuery("bar").getQueue().empty());
+ BOOST_CHECK(c1.session.queueQuery("bar").getQueue().empty());
+
+ cluster.add();
+ Client c2(aclSettings(cluster[2], "c2"), "c2");
+ {
+ ScopedSuppressLogging sl;
+ BOOST_CHECK_THROW(foo.session.queueDeclare("bar", arg::durable=durableFlag), framing::NotAllowedException);
+ }
+ BOOST_CHECK(c2.session.queueQuery("bar").getQueue().empty());
+}
+
+QPID_AUTO_TEST_CASE(testMessageTimeToLive) {
+ ClusterFixture::Args args;
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(2, args, -1);
+ Client c0(cluster[0], "c0");
+ Client c1(cluster[1], "c1");
+ c0.session.queueDeclare("p", arg::durable=durableFlag);
+ c0.session.queueDeclare("q", arg::durable=durableFlag);
+ c0.session.messageTransfer(arg::content=ttlMessage("a", "q", 200, durableFlag));
+ c0.session.messageTransfer(arg::content=makeMessage("b", "q", durableFlag));
+ c0.session.messageTransfer(arg::content=ttlMessage("x", "p", 10000, durableFlag));
+ c0.session.messageTransfer(arg::content=makeMessage("y", "p", durableFlag));
+ cluster.add();
+ Client c2(cluster[1], "c2");
+
+ BOOST_CHECK_EQUAL(browse(c0, "p", 1), list_of<string>("x"));
+ BOOST_CHECK_EQUAL(browse(c1, "p", 1), list_of<string>("x"));
+ BOOST_CHECK_EQUAL(browse(c2, "p", 1), list_of<string>("x"));
+
+ sys::usleep(200*1000);
+ BOOST_CHECK_EQUAL(browse(c0, "q", 1), list_of<string>("b"));
+ BOOST_CHECK_EQUAL(browse(c1, "q", 1), list_of<string>("b"));
+ BOOST_CHECK_EQUAL(browse(c2, "q", 1), list_of<string>("b"));
+}
+
+QPID_AUTO_TEST_CASE(testSequenceOptions) {
+ // Make sure the exchange qpid.msg_sequence property is properly replicated.
+ ClusterFixture::Args args;
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(1, args, -1);
+ Client c0(cluster[0], "c0");
+ FieldTable ftargs;
+ ftargs.setInt("qpid.msg_sequence", 1);
+ c0.session.queueDeclare(arg::queue="q", arg::durable=durableFlag);
+ c0.session.exchangeDeclare(arg::exchange="ex", arg::type="direct", arg::arguments=ftargs);
+ c0.session.exchangeBind(arg::exchange="ex", arg::queue="q", arg::bindingKey="k");
+ c0.session.messageTransfer(arg::content=makeMessage("1", "k", durableFlag), arg::destination="ex");
+ c0.session.messageTransfer(arg::content=makeMessage("2", "k", durableFlag), arg::destination="ex");
+ BOOST_CHECK_EQUAL(1, getMsgSequence(c0.subs.get("q", TIMEOUT)));
+ BOOST_CHECK_EQUAL(2, getMsgSequence(c0.subs.get("q", TIMEOUT)));
+
+ cluster.add();
+ Client c1(cluster[1]);
+ c1.session.messageTransfer(arg::content=makeMessage("3", "k", durableFlag), arg::destination="ex");
+ BOOST_CHECK_EQUAL(3, getMsgSequence(c1.subs.get("q", TIMEOUT)));
+}
+
+QPID_AUTO_TEST_CASE(testTxTransaction) {
+ ClusterFixture::Args args;
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(1, args, -1);
+ Client c0(cluster[0], "c0");
+ c0.session.queueDeclare(arg::queue="q", arg::durable=durableFlag);
+ c0.session.messageTransfer(arg::content=makeMessage("A", "q", durableFlag));
+ c0.session.messageTransfer(arg::content=makeMessage("B", "q", durableFlag));
+
+ // Start a transaction that will commit.
+ Session commitSession = c0.connection.newSession("commit");
+ SubscriptionManager commitSubs(commitSession);
+ commitSession.txSelect();
+ commitSession.messageTransfer(arg::content=makeMessage("a", "q", durableFlag));
+ commitSession.messageTransfer(arg::content=makeMessage("b", "q", durableFlag));
+ BOOST_CHECK_EQUAL(commitSubs.get("q", TIMEOUT).getData(), "A");
+
+ // Start a transaction that will roll back.
+ Session rollbackSession = c0.connection.newSession("rollback");
+ SubscriptionManager rollbackSubs(rollbackSession);
+ rollbackSession.txSelect();
+ rollbackSession.messageTransfer(arg::content=makeMessage("1", "q", durableFlag));
+ Message rollbackMessage = rollbackSubs.get("q", TIMEOUT);
+ BOOST_CHECK_EQUAL(rollbackMessage.getData(), "B");
+
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q").getMessageCount(), 0u);
+ // Add new member mid transaction.
+ cluster.add();
+ Client c1(cluster[1], "c1");
+
+ // More transactional work
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q").getMessageCount(), 0u);
+ rollbackSession.messageTransfer(arg::content=makeMessage("2", "q", durableFlag));
+ commitSession.messageTransfer(arg::content=makeMessage("c", "q", durableFlag));
+ rollbackSession.messageTransfer(arg::content=makeMessage("3", "q", durableFlag));
+
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q").getMessageCount(), 0u);
+
+ // Commit/roll back.
+ commitSession.txCommit();
+ rollbackSession.txRollback();
+ rollbackSession.messageRelease(rollbackMessage.getId());
+
+ // Verify queue status: just the comitted messages and dequeues should remain.
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q").getMessageCount(), 4u);
+ BOOST_CHECK_EQUAL(c1.subs.get("q", TIMEOUT).getData(), "B");
+ BOOST_CHECK_EQUAL(c1.subs.get("q", TIMEOUT).getData(), "a");
+ BOOST_CHECK_EQUAL(c1.subs.get("q", TIMEOUT).getData(), "b");
+ BOOST_CHECK_EQUAL(c1.subs.get("q", TIMEOUT).getData(), "c");
+
+ commitSession.close();
+ rollbackSession.close();
+}
+
+QPID_AUTO_TEST_CASE(testUnacked) {
+ // Verify replication of unacknowledged messages.
+ ClusterFixture::Args args;
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(1, args, -1);
+ Client c0(cluster[0], "c0");
+
+ Message m;
+
+ // Create unacked message: acquired but not accepted.
+ SubscriptionSettings manualAccept(FlowControl::unlimited(), ACCEPT_MODE_EXPLICIT, ACQUIRE_MODE_PRE_ACQUIRED, 0);
+ c0.session.queueDeclare("q1", arg::durable=durableFlag);
+ c0.session.messageTransfer(arg::content=makeMessage("11","q1", durableFlag));
+ LocalQueue q1;
+ c0.subs.subscribe(q1, "q1", manualAccept);
+ BOOST_CHECK_EQUAL(q1.get(TIMEOUT).getData(), "11"); // Acquired but not accepted
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q1").getMessageCount(), 0u); // Gone from queue
+
+ // Create unacked message: not acquired, accepted or completeed.
+ SubscriptionSettings manualAcquire(FlowControl::unlimited(), ACCEPT_MODE_EXPLICIT, ACQUIRE_MODE_NOT_ACQUIRED, 0);
+ c0.session.queueDeclare("q2", arg::durable=durableFlag);
+ c0.session.messageTransfer(arg::content=makeMessage("21","q2", durableFlag));
+ c0.session.messageTransfer(arg::content=makeMessage("22","q2", durableFlag));
+ LocalQueue q2;
+ c0.subs.subscribe(q2, "q2", manualAcquire);
+ m = q2.get(TIMEOUT); // Not acquired or accepted, still on queue
+ BOOST_CHECK_EQUAL(m.getData(), "21");
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q2").getMessageCount(), 2u); // Not removed
+ c0.subs.getSubscription("q2").acquire(m); // Acquire manually
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q2").getMessageCount(), 1u); // Removed
+ BOOST_CHECK_EQUAL(q2.get(TIMEOUT).getData(), "22"); // Not acquired or accepted, still on queue
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q2").getMessageCount(), 1u); // 1 not acquired.
+
+ // Create empty credit record: acquire and accept but don't complete.
+ SubscriptionSettings manualComplete(FlowControl::messageWindow(1), ACCEPT_MODE_EXPLICIT, ACQUIRE_MODE_PRE_ACQUIRED, 1, MANUAL_COMPLETION);
+ c0.session.queueDeclare("q3", arg::durable=durableFlag);
+ c0.session.messageTransfer(arg::content=makeMessage("31", "q3", durableFlag));
+ c0.session.messageTransfer(arg::content=makeMessage("32", "q3", durableFlag));
+ LocalQueue q3;
+ c0.subs.subscribe(q3, "q3", manualComplete);
+ Message m31=q3.get(TIMEOUT);
+ BOOST_CHECK_EQUAL(m31.getData(), "31"); // Automatically acquired & accepted but not completed.
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q3").getMessageCount(), 1u);
+
+ // Add new member while there are unacked messages.
+ cluster.add();
+ Client c1(cluster[1], "c1");
+
+ // Check queue counts
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q1").getMessageCount(), 0u);
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q2").getMessageCount(), 1u);
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q3").getMessageCount(), 1u);
+
+ // Complete the empty credit message, should unblock the message behind it.
+ BOOST_CHECK_THROW(q3.get(0), Exception);
+ c0.session.markCompleted(SequenceSet(m31.getId()), true);
+ BOOST_CHECK_EQUAL(q3.get(TIMEOUT).getData(), "32");
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q3").getMessageCount(), 0u);
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q3").getMessageCount(), 0u);
+
+ // Close the original session - unacked messages should be requeued.
+ c0.session.close();
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q1").getMessageCount(), 1u);
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q2").getMessageCount(), 2u);
+
+ BOOST_CHECK_EQUAL(c1.subs.get("q1", TIMEOUT).getData(), "11");
+ BOOST_CHECK_EQUAL(c1.subs.get("q2", TIMEOUT).getData(), "21");
+ BOOST_CHECK_EQUAL(c1.subs.get("q2", TIMEOUT).getData(), "22");
+}
+
+// FIXME aconway 2009-06-17: test for unimplemented feature, enable when implemented.
+void testUpdateTxState() {
+ // Verify that we update transaction state correctly to new members.
+ ClusterFixture::Args args;
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(1, args, -1);
+ Client c0(cluster[0], "c0");
+
+ // Do work in a transaction.
+ c0.session.txSelect();
+ c0.session.queueDeclare("q", arg::durable=durableFlag);
+ c0.session.messageTransfer(arg::content=makeMessage("1","q", durableFlag));
+ c0.session.messageTransfer(arg::content=makeMessage("2","q", durableFlag));
+ Message m;
+ BOOST_CHECK(c0.subs.get(m, "q", TIMEOUT));
+ BOOST_CHECK_EQUAL(m.getData(), "1");
+
+ // New member, TX not comitted, c1 should see nothing.
+ cluster.add();
+ Client c1(cluster[1], "c1");
+ BOOST_CHECK_EQUAL(c1.session.queueQuery(arg::queue="q").getMessageCount(), 0u);
+
+ // After commit c1 shoudl see results of tx.
+ c0.session.txCommit();
+ BOOST_CHECK_EQUAL(c1.session.queueQuery(arg::queue="q").getMessageCount(), 1u);
+ BOOST_CHECK(c1.subs.get(m, "q", TIMEOUT));
+ BOOST_CHECK_EQUAL(m.getData(), "2");
+
+ // Another transaction with both members active.
+ c0.session.messageTransfer(arg::content=makeMessage("3","q", durableFlag));
+ BOOST_CHECK_EQUAL(c1.session.queueQuery(arg::queue="q").getMessageCount(), 0u);
+ c0.session.txCommit();
+ BOOST_CHECK_EQUAL(c1.session.queueQuery(arg::queue="q").getMessageCount(), 1u);
+ BOOST_CHECK(c1.subs.get(m, "q", TIMEOUT));
+ BOOST_CHECK_EQUAL(m.getData(), "3");
+}
+
+QPID_AUTO_TEST_CASE(testUpdateMessageBuilder) {
+ // Verify that we update a partially recieved message to a new member.
+ ClusterFixture::Args args;
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(1, args, -1);
+ Client c0(cluster[0], "c0");
+ c0.session.queueDeclare("q", arg::durable=durableFlag);
+ Sender sender(ConnectionAccess::getImpl(c0.connection), c0.session.getChannel());
+
+ // Send first 2 frames of message.
+ MessageTransferBody transfer(
+ ProtocolVersion(), string(), // default exchange.
+ framing::message::ACCEPT_MODE_NONE,
+ framing::message::ACQUIRE_MODE_PRE_ACQUIRED);
+ sender.send(transfer, true, false, true, true);
+ AMQHeaderBody header;
+ header.get<DeliveryProperties>(true)->setRoutingKey("q");
+ if (durableFlag)
+ header.get<DeliveryProperties>(true)->setDeliveryMode(DELIVERY_MODE_PERSISTENT);
+ else
+ header.get<DeliveryProperties>(true)->setDeliveryMode(DELIVERY_MODE_NON_PERSISTENT);
+ sender.send(header, false, false, true, true);
+
+ // No reliable way to ensure the partial message has arrived
+ // before we start the new broker, so we sleep.
+ sys::usleep(2500);
+ cluster.add();
+
+ // Send final 2 frames of message.
+ sender.send(AMQContentBody("ab"), false, true, true, false);
+ sender.send(AMQContentBody("cd"), false, true, false, true);
+
+ // Verify message is enqued correctly on second member.
+ Message m;
+ Client c1(cluster[1], "c1");
+ BOOST_CHECK(c1.subs.get(m, "q", TIMEOUT));
+ BOOST_CHECK_EQUAL(m.getData(), "abcd");
+ BOOST_CHECK_EQUAL(2u, knownBrokerPorts(c1.connection).size());
+}
+
+QPID_AUTO_TEST_CASE(testConnectionKnownHosts) {
+ ClusterFixture::Args args;
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(1, args, -1);
+ Client c0(cluster[0], "c0");
+ set<int> kb0 = knownBrokerPorts(c0.connection);
+ BOOST_CHECK_EQUAL(kb0.size(), 1u);
+ BOOST_CHECK_EQUAL(kb0, makeSet(cluster));
+
+ cluster.add();
+ Client c1(cluster[1], "c1");
+ set<int> kb1 = knownBrokerPorts(c1.connection);
+ kb0 = knownBrokerPorts(c0.connection, 2);
+ BOOST_CHECK_EQUAL(kb1.size(), 2u);
+ BOOST_CHECK_EQUAL(kb1, makeSet(cluster));
+ BOOST_CHECK_EQUAL(kb1,kb0);
+
+ cluster.add();
+ Client c2(cluster[2], "c2");
+ set<int> kb2 = knownBrokerPorts(c2.connection);
+ kb1 = knownBrokerPorts(c1.connection, 3);
+ kb0 = knownBrokerPorts(c0.connection, 3);
+ BOOST_CHECK_EQUAL(kb2.size(), 3u);
+ BOOST_CHECK_EQUAL(kb2, makeSet(cluster));
+ BOOST_CHECK_EQUAL(kb2,kb0);
+ BOOST_CHECK_EQUAL(kb2,kb1);
+
+ cluster.killWithSilencer(1,c1.connection,9);
+ kb0 = knownBrokerPorts(c0.connection, 2);
+ kb2 = knownBrokerPorts(c2.connection, 2);
+ BOOST_CHECK_EQUAL(kb0.size(), 2u);
+ BOOST_CHECK_EQUAL(kb0, kb2);
+}
+
+QPID_AUTO_TEST_CASE(testUpdateConsumers) {
+ ClusterFixture::Args args;
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(1, args, -1);
+
+ Client c0(cluster[0], "c0");
+ c0.session.queueDeclare("p", arg::durable=durableFlag);
+ c0.session.queueDeclare("q", arg::durable=durableFlag);
+ c0.subs.subscribe(c0.lq, "q", FlowControl::zero());
+ LocalQueue lp;
+ c0.subs.subscribe(lp, "p", FlowControl::messageCredit(1));
+ c0.session.sync();
+
+ // Start new members
+ cluster.add(); // Local
+ Client c1(cluster[1], "c1");
+ cluster.add();
+ Client c2(cluster[2], "c2");
+
+ // Transfer messages
+ c0.session.messageTransfer(arg::content=makeMessage("aaa", "q", durableFlag));
+
+ c0.session.messageTransfer(arg::content=makeMessage("bbb", "p", durableFlag));
+ c0.session.messageTransfer(arg::content=makeMessage("ccc", "p", durableFlag));
+
+ // Activate the subscription, ensure message removed on all queues.
+ c0.subs.setFlowControl("q", FlowControl::unlimited());
+ Message m;
+ BOOST_CHECK(c0.lq.get(m, TIMEOUT));
+ BOOST_CHECK_EQUAL(m.getData(), "aaa");
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q").getMessageCount(), 0u);
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q").getMessageCount(), 0u);
+ BOOST_CHECK_EQUAL(c2.session.queueQuery("q").getMessageCount(), 0u);
+
+ // Check second subscription's flow control: gets first message, not second.
+ BOOST_CHECK(lp.get(m, TIMEOUT));
+ BOOST_CHECK_EQUAL(m.getData(), "bbb");
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("p").getMessageCount(), 1u);
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("p").getMessageCount(), 1u);
+ BOOST_CHECK_EQUAL(c2.session.queueQuery("p").getMessageCount(), 1u);
+
+ BOOST_CHECK(c0.subs.get(m, "p", TIMEOUT));
+ BOOST_CHECK_EQUAL(m.getData(), "ccc");
+
+ // Kill the subscribing member, ensure further messages are not removed.
+ cluster.killWithSilencer(0,c0.connection,9);
+ BOOST_REQUIRE_EQUAL(knownBrokerPorts(c1.connection, 2).size(), 2u);
+ for (int i = 0; i < 10; ++i) {
+ c1.session.messageTransfer(arg::content=makeMessage("xxx", "q", durableFlag));
+ BOOST_REQUIRE(c1.subs.get(m, "q", TIMEOUT));
+ BOOST_REQUIRE_EQUAL(m.getData(), "xxx");
+ }
+}
+
+// Test that message data and delivery properties are updated properly.
+QPID_AUTO_TEST_CASE(testUpdateMessages) {
+ ClusterFixture::Args args;
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(1, args, -1);
+ Client c0(cluster[0], "c0");
+
+ // Create messages with different delivery properties
+ c0.session.queueDeclare("q", arg::durable=durableFlag);
+ c0.session.exchangeBind(arg::exchange="amq.fanout", arg::queue="q");
+ c0.session.messageTransfer(arg::content=makeMessage("foo","q", durableFlag));
+ c0.session.messageTransfer(arg::content=makeMessage("bar","q", durableFlag),
+ arg::destination="amq.fanout");
+
+ while (c0.session.queueQuery("q").getMessageCount() != 2)
+ sys::usleep(1000); // Wait for message to show up on broker 0.
+
+ // Add a new broker, it will catch up.
+ cluster.add();
+
+ // Do some work post-add
+ c0.session.queueDeclare("p", arg::durable=durableFlag);
+ c0.session.messageTransfer(arg::content=makeMessage("pfoo","p", durableFlag));
+
+ // Do some work post-join
+ BOOST_REQUIRE_EQUAL(knownBrokerPorts(c0.connection, 2).size(), 2u);
+ c0.session.messageTransfer(arg::content=makeMessage("pbar","p", durableFlag));
+
+ // Verify new brokers have state.
+ Message m;
+
+ Client c1(cluster[1], "c1");
+
+ BOOST_CHECK(c1.subs.get(m, "q", TIMEOUT));
+ BOOST_CHECK_EQUAL(m.getData(), "foo");
+ BOOST_CHECK(m.getDeliveryProperties().hasExchange());
+ BOOST_CHECK_EQUAL(m.getDeliveryProperties().getExchange(), "");
+ BOOST_CHECK(c1.subs.get(m, "q", TIMEOUT));
+ BOOST_CHECK_EQUAL(m.getData(), "bar");
+ BOOST_CHECK(m.getDeliveryProperties().hasExchange());
+ BOOST_CHECK_EQUAL(m.getDeliveryProperties().getExchange(), "amq.fanout");
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q").getMessageCount(), 0u);
+
+ // Add another broker, don't wait for join - should be stalled till ready.
+ cluster.add();
+ Client c2(cluster[2], "c2");
+ BOOST_CHECK(c2.subs.get(m, "p", TIMEOUT));
+ BOOST_CHECK_EQUAL(m.getData(), "pfoo");
+ BOOST_CHECK(c2.subs.get(m, "p", TIMEOUT));
+ BOOST_CHECK_EQUAL(m.getData(), "pbar");
+ BOOST_CHECK_EQUAL(c2.session.queueQuery("p").getMessageCount(), 0u);
}
QPID_AUTO_TEST_CASE(testWiringReplication) {
- ClusterFixture cluster(3);
+ ClusterFixture::Args args;
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(3, args, -1);
Client c0(cluster[0]);
BOOST_CHECK(c0.session.queueQuery("q").getQueue().empty());
- BOOST_CHECK(c0.session.exchangeQuery("ex").getType().empty());
- c0.session.queueDeclare("q");
+ BOOST_CHECK(c0.session.exchangeQuery("ex").getType().empty());
+ c0.session.queueDeclare("q", arg::durable=durableFlag);
c0.session.exchangeDeclare("ex", arg::type="direct");
c0.session.close();
c0.connection.close();
@@ -185,41 +667,45 @@ QPID_AUTO_TEST_CASE(testWiringReplication) {
Client c(cluster[i]);
BOOST_CHECK_EQUAL("q", c.session.queueQuery("q").getQueue());
BOOST_CHECK_EQUAL("direct", c.session.exchangeQuery("ex").getType());
- }
+ }
}
QPID_AUTO_TEST_CASE(testMessageEnqueue) {
// Enqueue on one broker, dequeue on another.
- ClusterFixture cluster(2);
+ ClusterFixture::Args args;
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(2, args, -1);
Client c0(cluster[0]);
- c0.session.queueDeclare("q");
- c0.session.messageTransfer(arg::content=TransferContent("foo", "q"));
- c0.session.messageTransfer(arg::content=TransferContent("bar", "q"));
+ c0.session.queueDeclare("q", arg::durable=durableFlag);
+ c0.session.messageTransfer(arg::content=makeMessage("foo", "q", durableFlag));
+ c0.session.messageTransfer(arg::content=makeMessage("bar", "q", durableFlag));
c0.session.close();
Client c1(cluster[1]);
Message msg;
- BOOST_CHECK(c1.subs.get(msg, "q", qpid::sys::TIME_SEC));
+ BOOST_CHECK(c1.subs.get(msg, "q", TIMEOUT));
BOOST_CHECK_EQUAL(string("foo"), msg.getData());
- BOOST_CHECK(c1.subs.get(msg, "q", qpid::sys::TIME_SEC));
+ BOOST_CHECK(c1.subs.get(msg, "q", TIMEOUT));
BOOST_CHECK_EQUAL(string("bar"), msg.getData());
}
QPID_AUTO_TEST_CASE(testMessageDequeue) {
// Enqueue on one broker, dequeue on two others.
- ClusterFixture cluster (3);
- Client c0(cluster[0]);
- c0.session.queueDeclare("q");
- c0.session.messageTransfer(arg::content=TransferContent("foo", "q"));
- c0.session.messageTransfer(arg::content=TransferContent("bar", "q"));
+ ClusterFixture::Args args;
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(3, args, -1);
+ Client c0(cluster[0], "c0");
+ c0.session.queueDeclare("q", arg::durable=durableFlag);
+ c0.session.messageTransfer(arg::content=makeMessage("foo", "q", durableFlag));
+ c0.session.messageTransfer(arg::content=makeMessage("bar", "q", durableFlag));
Message msg;
// Dequeue on 2 others, ensure correct order.
- Client c1(cluster[1]);
+ Client c1(cluster[1], "c1");
BOOST_CHECK(c1.subs.get(msg, "q"));
BOOST_CHECK_EQUAL("foo", msg.getData());
-
- Client c2(cluster[2]);
+
+ Client c2(cluster[2], "c2");
BOOST_CHECK(c1.subs.get(msg, "q"));
BOOST_CHECK_EQUAL("bar", msg.getData());
@@ -230,21 +716,26 @@ QPID_AUTO_TEST_CASE(testMessageDequeue) {
}
QPID_AUTO_TEST_CASE(testDequeueWaitingSubscription) {
- ClusterFixture cluster(3);
- // First start a subscription.
+ ClusterFixture::Args args;
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(3, args, -1);
Client c0(cluster[0]);
- c0.session.queueDeclare("q");
+ BOOST_REQUIRE_EQUAL(knownBrokerPorts(c0.connection, 3).size(), 3u); // Wait for brokers.
+
+ // First start a subscription.
+ c0.session.queueDeclare("q", arg::durable=durableFlag);
c0.subs.subscribe(c0.lq, "q", FlowControl::messageCredit(2));
+
// Now send messages
Client c1(cluster[1]);
- c1.session.messageTransfer(arg::content=TransferContent("foo", "q"));
- c1.session.messageTransfer(arg::content=TransferContent("bar", "q"));
+ c1.session.messageTransfer(arg::content=makeMessage("foo", "q", durableFlag));
+ c1.session.messageTransfer(arg::content=makeMessage("bar", "q", durableFlag));
// Check they arrived
Message m;
- BOOST_CHECK(c0.lq.get(m, sys::TIME_SEC));
+ BOOST_CHECK(c0.lq.get(m, TIMEOUT));
BOOST_CHECK_EQUAL("foo", m.getData());
- BOOST_CHECK(c0.lq.get(m, sys::TIME_SEC));
+ BOOST_CHECK(c0.lq.get(m, TIMEOUT));
BOOST_CHECK_EQUAL("bar", m.getData());
// Queue should be empty on all cluster members.
@@ -254,5 +745,447 @@ QPID_AUTO_TEST_CASE(testDequeueWaitingSubscription) {
BOOST_CHECK_EQUAL(0u, c2.session.queueQuery("q").getMessageCount());
}
+QPID_AUTO_TEST_CASE(queueDurabilityPropagationToNewbie)
+{
+ /*
+ Start with a single broker.
+ Set up two queues: one durable, and one not.
+ Add a new broker to the cluster.
+ Make sure it has one durable and one non-durable queue.
+ */
+ ClusterFixture::Args args;
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(1, args, -1);
+ Client c0(cluster[0]);
+ c0.session.queueDeclare("durable_queue", arg::durable=true);
+ c0.session.queueDeclare("non_durable_queue", arg::durable=false);
+ cluster.add();
+ Client c1(cluster[1]);
+ QueueQueryResult durable_query = c1.session.queueQuery ( "durable_queue" );
+ QueueQueryResult non_durable_query = c1.session.queueQuery ( "non_durable_queue" );
+ BOOST_CHECK_EQUAL(durable_query.getQueue(), std::string("durable_queue"));
+ BOOST_CHECK_EQUAL(non_durable_query.getQueue(), std::string("non_durable_queue"));
+
+ BOOST_CHECK_EQUAL ( durable_query.getDurable(), true );
+ BOOST_CHECK_EQUAL ( non_durable_query.getDurable(), false );
+}
+
+
+QPID_AUTO_TEST_CASE(testHeartbeatCancelledOnFailover)
+{
+
+ struct Sender : FailoverManager::Command
+ {
+ std::string queue;
+ std::string content;
+
+ Sender(const std::string& q, const std::string& c) : queue(q), content(c) {}
+
+ void execute(AsyncSession& session, bool)
+ {
+ session.messageTransfer(arg::content=makeMessage(content, queue, durableFlag));
+ }
+ };
+
+ struct Receiver : FailoverManager::Command, MessageListener, qpid::sys::Runnable
+ {
+ FailoverManager& mgr;
+ std::string queue;
+ std::string expectedContent;
+ qpid::client::Subscription subscription;
+ qpid::sys::Monitor lock;
+ bool ready, failed;
+
+ Receiver(FailoverManager& m, const std::string& q, const std::string& c) : mgr(m), queue(q), expectedContent(c), ready(false), failed(false) {}
+
+ void received(Message& message)
+ {
+ BOOST_CHECK_EQUAL(expectedContent, message.getData());
+ subscription.cancel();
+ }
+
+ void execute(AsyncSession& session, bool)
+ {
+ session.queueDeclare(arg::queue=queue, arg::durable=durableFlag);
+ SubscriptionManager subs(session);
+ subscription = subs.subscribe(*this, queue);
+ session.sync();
+ setReady();
+ subs.run();
+ //cleanup:
+ session.queueDelete(arg::queue=queue);
+ }
+
+ void run()
+ {
+ try {
+ mgr.execute(*this);
+ }
+ catch (const std::exception& e) {
+ BOOST_MESSAGE("Exception in mgr.execute: " << e.what());
+ failed = true;
+ }
+ }
+
+ void waitForReady()
+ {
+ qpid::sys::Monitor::ScopedLock l(lock);
+ while (!ready) {
+ lock.wait();
+ }
+ }
+
+ void setReady()
+ {
+ qpid::sys::Monitor::ScopedLock l(lock);
+ ready = true;
+ lock.notify();
+ }
+ };
+
+ ClusterFixture::Args args;
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(2, args, -1);
+ ConnectionSettings settings;
+ settings.port = cluster[1];
+ settings.heartbeat = 1;
+ FailoverManager fmgr(settings);
+ Sender sender("my-queue", "my-data");
+ Receiver receiver(fmgr, "my-queue", "my-data");
+ qpid::sys::Thread runner(receiver);
+ receiver.waitForReady();
+ {
+ ScopedSuppressLogging allQuiet; // suppress connection closed messages
+ cluster.kill(1);
+ //sleep for 2 secs to allow the heartbeat task to fire on the now dead connection:
+ ::usleep(2*1000*1000);
+ }
+ fmgr.execute(sender);
+ runner.join();
+ BOOST_CHECK(!receiver.failed);
+ fmgr.close();
+}
+
+QPID_AUTO_TEST_CASE(testPolicyUpdate) {
+ //tests that the policys internal state is accurate on newly
+ //joined nodes
+ ClusterFixture::Args args;
+ args += "--log-enable", "critical";
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(1, args, -1);
+ Client c1(cluster[0], "c1");
+ {
+ ScopedSuppressLogging allQuiet;
+ QueueOptions options;
+ options.setSizePolicy(REJECT, 0, 2);
+ c1.session.queueDeclare("q", arg::arguments=options, arg::durable=durableFlag);
+ c1.session.messageTransfer(arg::content=makeMessage("one", "q", durableFlag));
+ cluster.add();
+ Client c2(cluster[1], "c2");
+ c2.session.messageTransfer(arg::content=makeMessage("two", "q", durableFlag));
+
+ BOOST_CHECK_THROW(c2.session.messageTransfer(arg::content=makeMessage("three", "q", durableFlag)), framing::ResourceLimitExceededException);
+
+ Message received;
+ BOOST_CHECK(c1.subs.get(received, "q"));
+ BOOST_CHECK_EQUAL(received.getData(), std::string("one"));
+ BOOST_CHECK(c1.subs.get(received, "q"));
+ BOOST_CHECK_EQUAL(received.getData(), std::string("two"));
+ BOOST_CHECK(!c1.subs.get(received, "q"));
+ }
+}
+
+QPID_AUTO_TEST_CASE(testExclusiveQueueUpdate) {
+ //tests that exclusive queues are accurately replicated on newly
+ //joined nodes
+ ClusterFixture::Args args;
+ args += "--log-enable", "critical";
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(1, args, -1);
+ Client c1(cluster[0], "c1");
+ {
+ ScopedSuppressLogging allQuiet;
+ c1.session.queueDeclare("q", arg::exclusive=true, arg::autoDelete=true, arg::alternateExchange="amq.fanout");
+ cluster.add();
+ Client c2(cluster[1], "c2");
+ QueueQueryResult result = c2.session.queueQuery("q");
+ BOOST_CHECK_EQUAL(result.getQueue(), std::string("q"));
+ BOOST_CHECK(result.getExclusive());
+ BOOST_CHECK(result.getAutoDelete());
+ BOOST_CHECK(!result.getDurable());
+ BOOST_CHECK_EQUAL(result.getAlternateExchange(), std::string("amq.fanout"));
+ BOOST_CHECK_THROW(c2.session.queueDeclare(arg::queue="q", arg::exclusive=true, arg::passive=true), framing::ResourceLockedException);
+ c1.session.close();
+ c1.connection.close();
+ c2.session = c2.connection.newSession();
+ BOOST_CHECK_THROW(c2.session.queueDeclare(arg::queue="q", arg::passive=true), framing::NotFoundException);
+ }
+}
+
+/**
+ * Subscribes to specified queue and acquires up to the specified
+ * number of message but does not accept or release them. These
+ * message are therefore 'locked' by the clients session.
+ */
+Subscription lockMessages(Client& client, const std::string& queue, int count)
+{
+ LocalQueue q;
+ SubscriptionSettings settings(FlowControl::messageCredit(count));
+ settings.autoAck = 0;
+ Subscription sub = client.subs.subscribe(q, queue, settings);
+ client.session.messageFlush(sub.getName());
+ return sub;
+}
+
+/**
+ * check that the specified queue contains the expected set of
+ * messages (matched on content) for all nodes in the cluster
+ */
+void checkQueue(ClusterFixture& cluster, const std::string& queue, const std::vector<std::string>& messages)
+{
+ for (size_t i = 0; i < cluster.size(); i++) {
+ Client client(cluster[i], (boost::format("%1%_%2%") % "c" % (i+1)).str());
+ BOOST_CHECK_EQUAL(browse(client, queue, messages.size()), messages);
+ client.close();
+ }
+}
+
+void send(Client& client, const std::string& queue, int count, int start=1, const std::string& base="m",
+ const std::string& lvqKey="")
+{
+ for (int i = 0; i < count; i++) {
+ Message message = makeMessage((boost::format("%1%_%2%") % base % (i+start)).str(), queue, durableFlag);
+ if (!lvqKey.empty()) message.getHeaders().setString(QueueOptions::strLVQMatchProperty, lvqKey);
+ client.session.messageTransfer(arg::content=message);
+ }
+}
+
+QPID_AUTO_TEST_CASE(testRingQueueUpdate) {
+ //tests that ring queues are accurately replicated on newly
+ //joined nodes
+ ClusterFixture::Args args;
+ args += "--log-enable", "critical";
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(1, args, -1);
+ Client c1(cluster[0], "c1");
+ {
+ ScopedSuppressLogging allQuiet;
+ QueueOptions options;
+ options.setSizePolicy(RING, 0, 5);
+ c1.session.queueDeclare("q", arg::arguments=options, arg::durable=durableFlag);
+ send(c1, "q", 5);
+ lockMessages(c1, "q", 1);
+ //add new node
+ cluster.add();
+ BOOST_CHECK_EQUAL(2u, knownBrokerPorts(c1.connection, 2).size());//wait till joined
+ //send one more message
+ send(c1, "q", 1, 6);
+ //release locked message
+ c1.close();
+ //check state of queue on both nodes
+ checkQueue(cluster, "q", list_of<string>("m_2")("m_3")("m_4")("m_5")("m_6"));
+ }
+}
+
+QPID_AUTO_TEST_CASE(testRingQueueUpdate2) {
+ //tests that ring queues are accurately replicated on newly joined
+ //nodes; just like testRingQueueUpdate, but new node joins after
+ //the sixth message has been sent.
+ ClusterFixture::Args args;
+ args += "--log-enable", "critical";
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(1, args, -1);
+ Client c1(cluster[0], "c1");
+ {
+ ScopedSuppressLogging allQuiet;
+ QueueOptions options;
+ options.setSizePolicy(RING, 0, 5);
+ c1.session.queueDeclare("q", arg::arguments=options, arg::durable=durableFlag);
+ send(c1, "q", 5);
+ lockMessages(c1, "q", 1);
+ //send sixth message
+ send(c1, "q", 1, 6);
+ //add new node
+ cluster.add();
+ BOOST_CHECK_EQUAL(2u, knownBrokerPorts(c1.connection, 2).size());//wait till joined
+ //release locked message
+ c1.close();
+ //check state of queue on both nodes
+ checkQueue(cluster, "q", list_of<string>("m_2")("m_3")("m_4")("m_5")("m_6"));
+ }
+}
+
+QPID_AUTO_TEST_CASE(testLvqUpdate) {
+ //tests that lvqs are accurately replicated on newly joined nodes
+ ClusterFixture::Args args;
+ args += "--log-enable", "critical";
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(1, args, -1);
+ Client c1(cluster[0], "c1");
+ {
+ ScopedSuppressLogging allQuiet;
+ QueueOptions options;
+ options.setOrdering(LVQ);
+ c1.session.queueDeclare("q", arg::arguments=options, arg::durable=durableFlag);
+
+ send(c1, "q", 5, 1, "a", "a");
+ send(c1, "q", 2, 1, "b", "b");
+ send(c1, "q", 1, 1, "c", "c");
+ send(c1, "q", 1, 3, "b", "b");
+
+ //add new node
+ cluster.add();
+ BOOST_CHECK_EQUAL(2u, knownBrokerPorts(c1.connection, 2).size());//wait till joined
+
+ //check state of queue on both nodes
+ checkQueue(cluster, "q", list_of<string>("a_5")("b_3")("c_1"));
+ }
+}
+
+
+QPID_AUTO_TEST_CASE(testBrowsedLvqUpdate) {
+ //tests that lvqs are accurately replicated on newly joined nodes
+ //if the lvq state has been affected by browsers
+ ClusterFixture::Args args;
+ args += "--log-enable", "critical";
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(1, args, -1);
+ Client c1(cluster[0], "c1");
+ {
+ ScopedSuppressLogging allQuiet;
+ QueueOptions options;
+ options.setOrdering(LVQ);
+ c1.session.queueDeclare("q", arg::arguments=options, arg::durable=durableFlag);
+
+ send(c1, "q", 1, 1, "a", "a");
+ send(c1, "q", 2, 1, "b", "b");
+ send(c1, "q", 1, 1, "c", "c");
+ checkQueue(cluster, "q", list_of<string>("a_1")("b_2")("c_1"));
+ send(c1, "q", 4, 2, "a", "a");
+ send(c1, "q", 1, 3, "b", "b");
+
+ //add new node
+ cluster.add();
+ BOOST_CHECK_EQUAL(2u, knownBrokerPorts(c1.connection, 2).size());//wait till joined
+
+ //check state of queue on both nodes
+ checkQueue(cluster, "q", list_of<string>("a_1")("b_2")("c_1")("a_5")("b_3"));
+ }
+}
+
+QPID_AUTO_TEST_CASE(testRelease) {
+ //tests that releasing a messages that was unacked when one node
+ //joined works correctly
+ ClusterFixture::Args args;
+ args += "--log-enable", "critical";
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(1, args, -1);
+ Client c1(cluster[0], "c1");
+ {
+ ScopedSuppressLogging allQuiet;
+ c1.session.queueDeclare("q", arg::durable=durableFlag);
+ for (int i = 0; i < 5; i++) {
+ c1.session.messageTransfer(arg::content=makeMessage((boost::format("%1%_%2%") % "m" % (i+1)).str(), "q", durableFlag));
+ }
+ //receive but don't ack a message
+ LocalQueue lq;
+ SubscriptionSettings lqSettings(FlowControl::messageCredit(1));
+ lqSettings.autoAck = 0;
+ Subscription lqSub = c1.subs.subscribe(lq, "q", lqSettings);
+ c1.session.messageFlush("q");
+ Message received;
+ BOOST_CHECK(lq.get(received));
+ BOOST_CHECK_EQUAL(received.getData(), std::string("m_1"));
+
+ //add new node
+ cluster.add();
+
+ lqSub.release(lqSub.getUnaccepted());
+
+ //check state of queue on both nodes
+ vector<string> expected = list_of<string>("m_1")("m_2")("m_3")("m_4")("m_5");
+ Client c3(cluster[0], "c3");
+ BOOST_CHECK_EQUAL(browse(c3, "q", 5), expected);
+ Client c2(cluster[1], "c2");
+ BOOST_CHECK_EQUAL(browse(c2, "q", 5), expected);
+ }
+}
+
+
+// Browse for 1 message with byte credit, return true if a message was
+// received false if not.
+bool browseByteCredit(Client& c, const string& q, int n, Message& m) {
+ SubscriptionSettings browseSettings(
+ FlowControl(1, n, false), // 1 message, n bytes credit, no window
+ ACCEPT_MODE_NONE,
+ ACQUIRE_MODE_NOT_ACQUIRED,
+ 0 // No auto-ack.
+ );
+ LocalQueue lq;
+ Subscription s = c.subs.subscribe(lq, q, browseSettings);
+ c.session.messageFlush(arg::destination=q, arg::sync=true);
+ c.session.sync();
+ c.subs.getSubscription(q).cancel();
+ return lq.get(m, 0); // No timeout, flush should push message thru.
+}
+
+// Ensure cluster update preserves exact message size, use byte credt as test.
+QPID_AUTO_TEST_CASE(testExactByteCredit) {
+ ClusterFixture cluster(1, prepareArgs(), -1);
+ Client c0(cluster[0], "c0");
+ c0.session.queueDeclare("q");
+ c0.session.messageTransfer(arg::content=Message("MyMessage", "q"));
+ cluster.add();
+
+ int size=36; // Size of message on broker: headers+body
+ Client c1(cluster[1], "c1");
+ Message m;
+
+ // Ensure we get the message with exact credit.
+ BOOST_CHECK(browseByteCredit(c0, "q", size, m));
+ BOOST_CHECK(browseByteCredit(c1, "q", size, m));
+ // and not with one byte less.
+ BOOST_CHECK(!browseByteCredit(c0, "q", size-1, m));
+ BOOST_CHECK(!browseByteCredit(c1, "q", size-1, m));
+}
+
+// Test that consumer positions are updated correctly.
+// Regression test for https://bugzilla.redhat.com/show_bug.cgi?id=541927
+//
+QPID_AUTO_TEST_CASE(testUpdateConsumerPosition) {
+ ClusterFixture::Args args;
+ prepareArgs(args, durableFlag);
+ ClusterFixture cluster(1, args, -1);
+ Client c0(cluster[0], "c0");
+
+ c0.session.queueDeclare("q", arg::durable=durableFlag);
+ SubscriptionSettings settings;
+ settings.autoAck = 0;
+ // Set the acquire mode to 'not-acquired' the consumer moves along the queue
+ // but does not acquire (remove) messages.
+ settings.acquireMode = ACQUIRE_MODE_NOT_ACQUIRED;
+ Subscription s = c0.subs.subscribe(c0.lq, "q", settings);
+ c0.session.messageTransfer(arg::content=makeMessage("1", "q", durableFlag));
+ BOOST_CHECK_EQUAL("1", c0.lq.get(TIMEOUT).getData());
+
+ // Add another member, send/receive another message and acquire
+ // the messages. With the bug, this creates an inconsistency
+ // because the browse position was not updated to the new member.
+ cluster.add();
+ c0.session.messageTransfer(arg::content=makeMessage("2", "q", durableFlag));
+ BOOST_CHECK_EQUAL("2", c0.lq.get(TIMEOUT).getData());
+ s.acquire(s.getUnacquired());
+ s.accept(s.getUnaccepted());
+
+ // In the bug we now have 0 messages on cluster[0] and 1 message on cluster[1]
+ // Subscribing on cluster[1] provokes an error that shuts down cluster[0]
+ Client c1(cluster[1], "c1");
+ Subscription s1 = c1.subs.subscribe(c1.lq, "q"); // Default auto-ack=1
+ Message m;
+ BOOST_CHECK(!c1.lq.get(m, TIMEOUT/10));
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q").getMessageCount(), 0u);
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q").getMessageCount(), 0u);
+}
QPID_AUTO_TEST_SUITE_END()
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/cluster_test_scripts/README.txt b/cpp/src/tests/cluster_test_scripts/README.txt
new file mode 100644
index 0000000000..e861a2f397
--- /dev/null
+++ b/cpp/src/tests/cluster_test_scripts/README.txt
@@ -0,0 +1,20 @@
+Cluster test scripts.
+
+A set of scripts to start and stop cluster and test clients on
+multiple hosts using ssh.
+
+Pre-requisites: You must be
+ - set up for password-free ssh access to the test hosts.
+ - a member of the ais group on all the test hosts.
+
+Configuration:
+
+Copy defaults.sh to config.sh and edit the values as necessary.
+
+Test scripts:
+
+Test scripts use the functions in functions.sh to start & monitor
+cluster and clients.
+A test script can collect other scripts.
+
+
diff --git a/cpp/src/tests/cluster_test_scripts/cluster_check b/cpp/src/tests/cluster_test_scripts/cluster_check
new file mode 100755
index 0000000000..5cc872a921
--- /dev/null
+++ b/cpp/src/tests/cluster_test_scripts/cluster_check
@@ -0,0 +1,17 @@
+#!/bin/sh
+# Check that all members of a cluster are running
+
+source config.sh
+
+HOSTS=(`cat $CLUSTER_HOME/hosts`)
+PORTS=(`cat $CLUSTER_HOME/ports`)
+
+for ((i=0; i<${#HOSTS[*]}; ++i)); do
+ host=${HOSTS[$i]}
+ port=${PORTS[$i]}
+ ssh $host "$QPIDD -cp $port" > /dev/null || {
+ ret=1
+ echo "ERROR: broker not running $host:$port"
+ }
+done
+exit $ret
diff --git a/cpp/src/tests/cluster_test_scripts/cluster_start b/cpp/src/tests/cluster_test_scripts/cluster_start
new file mode 100755
index 0000000000..bde582ef2b
--- /dev/null
+++ b/cpp/src/tests/cluster_test_scripts/cluster_start
@@ -0,0 +1,36 @@
+#!/bin/sh
+# Start a cluster
+#
+# Arguments: NAME HOST [host...]
+# Start a cluster called NAME with N nodes running on the given HOSTs
+# repeat the host name to run multiple brokers on one host. Use dynamic
+# ports.
+#
+# Log files, data directories and hosts/ports files are all stored under
+# $HOME/cluster_test/$NAME
+#
+
+source config.sh
+
+CLUSTER_NAME=`date +"${USER}_%F_%T"`
+HOSTS=($BROKER_HOSTS)
+for ((i = 0; i < ${#HOSTS[*]}; ++i)) ; do
+ host=${HOSTS[$i]}
+ datadir=$CLUSTER_HOME/broker$i
+ log=$datadir/qpidd.log
+ ssh $host "rm -rf $datadir; mkdir -p $datadir" || {
+ echo "ERROR: can't make data dir $datadir"; exit 1
+ }
+ port=`ssh $host "echo $QPIDD -dp0 --cluster-name=$CLUSTER_NAME \
+ --data-dir=$datadir \
+ --log-to-file=$log --log-prefix=broker$i \
+ $QPIDD_OPTS | newgrp ais"` || {
+ error "ERROR: can't start broker $i on $host"; exit 1;
+ }
+ PORTS="$PORTS $port"
+done
+
+echo "$BROKER_HOSTS" > $CLUSTER_HOME/hosts
+echo "$PORTS" > $CLUSTER_HOME/ports
+
+`dirname $0`/cluster_check $NAME
diff --git a/cpp/src/tests/cluster_test_scripts/cluster_stop b/cpp/src/tests/cluster_test_scripts/cluster_stop
new file mode 100755
index 0000000000..d4543d2d4a
--- /dev/null
+++ b/cpp/src/tests/cluster_test_scripts/cluster_stop
@@ -0,0 +1,18 @@
+#!/bin/sh
+# Stop the cluster.
+
+source config.sh
+
+HOSTS=(`cat $CLUSTER_HOME/hosts`)
+PORTS=(`cat $CLUSTER_HOME/ports`)
+
+for ((i=0; i<${#HOSTS[*]}; ++i)); do
+ host=${HOSTS[$i]}
+ port=${PORTS[$i]}
+ ssh $host "$QPIDD -qp $port" > /dev/null || {
+ ret=1
+ echo "ERROR: stopping broker at $host:$port"
+ }
+done
+
+exit $ret
diff --git a/cpp/src/tests/cluster_test_scripts/config_example.sh b/cpp/src/tests/cluster_test_scripts/config_example.sh
new file mode 100755
index 0000000000..fd5b800df7
--- /dev/null
+++ b/cpp/src/tests/cluster_test_scripts/config_example.sh
@@ -0,0 +1,25 @@
+# Cluster configuration.
+
+# All output stored under $HOME/$CLUSTER_HOME.
+CLUSTER_HOME=$HOME/cluster_test
+
+# Hosts where brokers will be run. Repeat hostname to run multiple brokers on 1 host.
+BROKER_HOSTS="mrg22 mrg23 mrg24 mrg25 mrg26"
+
+# Hosts where clients will be run.
+CLIENT_HOSTS="$BROKER_HOSTS"
+
+# Paths to executables
+QPIDD=qpidd
+PERFTEST=perftest
+
+# Directory containing tests
+TESTDIR=/usr/bin
+
+# Options for qpidd, must be sufficient to load the cluster plugin.
+# Scripts will add --cluster-name, --daemon, --port and --log-to-file options here.
+QPIDD_OPTS=" \
+--auth=no \
+--log-enable=notice+ \
+--log-enable=debug+:cluster \
+"
diff --git a/cpp/src/tests/cluster_test_scripts/perftest b/cpp/src/tests/cluster_test_scripts/perftest
new file mode 100755
index 0000000000..72c8268835
--- /dev/null
+++ b/cpp/src/tests/cluster_test_scripts/perftest
@@ -0,0 +1,34 @@
+#!/bin/sh
+# Run a distributed perftest against a cluster.
+# Args: npubs nsubs [perftest-options]
+
+source config.sh
+
+NPUBS=${1:-4} ; shift
+NSUBS=${1:-4} ; shift
+OPTS="--npubs $NPUBS --nsubs $NSUBS $*"
+
+CLIENTS=($CLIENT_HOSTS)
+BROKERS=(`cat $CLUSTER_HOME/hosts`)
+PORTS=(`cat $CLUSTER_HOME/ports`)
+
+start() {
+ client=${CLIENTS[i % ${#CLIENTS[*]}]}
+ broker=${BROKERS[i % ${#BROKERS[*]}]}
+ port=${PORTS[i % ${#PORTS[*]}]}
+ ssh -n $client $PERFTEST $OPTS $* -b $broker -p $port &
+ PIDS="$PIDS $!"
+}
+
+ssh ${CLIENTS[0]} $PERFTEST $OPTS --setup -b ${BROKERS[0]} -p${PORTS[0]}
+for (( i=0 ; i < $NPUBS ; ++i)); do start --publish; done
+for (( ; i < $NPUBS+$NSUBS ; ++i)); do start --subscribe; done
+ssh ${CLIENTS[0]} $PERFTEST $OPTS --control -b ${BROKERS[0]} -p${PORTS[0]}
+
+for pid in $PIDS; do
+ wait $pid || echo "ERROR: client process $pid failed"
+done
+
+`dirname $0`/cluster_check
+
+
diff --git a/cpp/src/tests/cluster_tests.fail b/cpp/src/tests/cluster_tests.fail
new file mode 100644
index 0000000000..139597f9cb
--- /dev/null
+++ b/cpp/src/tests/cluster_tests.fail
@@ -0,0 +1,2 @@
+
+
diff --git a/cpp/src/tests/cluster_tests.py b/cpp/src/tests/cluster_tests.py
new file mode 100755
index 0000000000..178271e977
--- /dev/null
+++ b/cpp/src/tests/cluster_tests.py
@@ -0,0 +1,233 @@
+#!/usr/bin/env python
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import os, signal, sys, time, imp, re
+from qpid import datatypes, messaging
+from qpid.brokertest import *
+from qpid.harness import Skipped
+from qpid.messaging import Message
+from threading import Thread
+from logging import getLogger
+
+log = getLogger("qpid.cluster_tests")
+
+# Import scripts as modules
+qpid_cluster=import_script(checkenv("QPID_CLUSTER_EXEC"))
+
+class ShortTests(BrokerTest):
+ """Short cluster functionality tests."""
+
+ def test_message_replication(self):
+ """Test basic cluster message replication."""
+ # Start a cluster, send some messages to member 0.
+ cluster = self.cluster(2)
+ s0 = cluster[0].connect().session()
+ s0.sender("q; {create:always}").send(Message("x"))
+ s0.sender("q; {create:always}").send(Message("y"))
+ s0.connection.close()
+
+ # Verify messages available on member 1.
+ s1 = cluster[1].connect().session()
+ m = s1.receiver("q", capacity=1).fetch(timeout=1)
+ s1.acknowledge()
+ self.assertEqual("x", m.content)
+ s1.connection.close()
+
+ # Start member 2 and verify messages available.
+ s2 = cluster.start().connect().session()
+ m = s2.receiver("q", capacity=1).fetch(timeout=1)
+ s2.acknowledge()
+ self.assertEqual("y", m.content)
+ s2.connection.close()
+
+ def test_store_direct_update_match(self):
+ """Verify that brokers stores an identical message whether they receive it
+ direct from clients or during an update, no header or other differences"""
+ cluster = self.cluster(0, args=["--load-module", self.test_store_lib])
+ cluster.start(args=["--test-store-dump", "direct.dump"])
+ # Try messages with various headers
+ cluster[0].send_message("q", Message(durable=True, content="foobar",
+ subject="subject",
+ reply_to="reply_to",
+ properties={"n":10}))
+ # Try messages of different sizes
+ for size in range(0,10000,100):
+ cluster[0].send_message("q", Message(content="x"*size, durable=True))
+ # Try sending via named exchange
+ c = cluster[0].connect_old()
+ s = c.session(str(qpid.datatypes.uuid4()))
+ s.exchange_bind(exchange="amq.direct", binding_key="foo", queue="q")
+ props = s.delivery_properties(routing_key="foo", delivery_mode=2)
+ s.message_transfer(
+ destination="amq.direct",
+ message=qpid.datatypes.Message(props, "content"))
+
+ # Now update a new member and compare their dumps.
+ cluster.start(args=["--test-store-dump", "updatee.dump"])
+ assert file("direct.dump").read() == file("updatee.dump").read()
+ os.remove("direct.dump")
+ os.remove("updatee.dump")
+
+class LongTests(BrokerTest):
+ """Tests that can run for a long time if -DDURATION=<minutes> is set"""
+ def duration(self):
+ d = self.config.defines.get("DURATION")
+ if d: return float(d)*60
+ else: return 3 # Default is to be quick
+
+ def test_failover(self):
+ """Test fail-over during continuous send-receive with errors"""
+
+ # Original cluster will all be killed so expect exit with failure
+ cluster = self.cluster(3, expect=EXPECT_EXIT_FAIL)
+ for b in cluster: ErrorGenerator(b)
+
+ # Start sender and receiver threads
+ cluster[0].declare_queue("test-queue")
+ sender = NumberedSender(cluster[1], 1000) # Max queue depth
+ receiver = NumberedReceiver(cluster[2], sender)
+ receiver.start()
+ sender.start()
+
+ # Kill original brokers, start new ones for the duration.
+ endtime = time.time() + self.duration()
+ i = 0
+ while time.time() < endtime:
+ cluster[i].kill()
+ i += 1
+ b = cluster.start(expect=EXPECT_EXIT_FAIL)
+ ErrorGenerator(b)
+ time.sleep(1)
+ sender.stop()
+ receiver.stop(sender.sent)
+ for i in range(i, len(cluster)): cluster[i].kill()
+
+
+class StoreTests(BrokerTest):
+ """
+ Cluster tests that can only be run if there is a store available.
+ """
+ def args(self):
+ assert BrokerTest.store_lib
+ return ["--load-module", BrokerTest.store_lib]
+
+ def test_store_loaded(self):
+ """Ensure we are indeed loading a working store"""
+ broker = self.broker(self.args(), name="recoverme", expect=EXPECT_EXIT_FAIL)
+ m = Message("x", durable=True)
+ broker.send_message("q", m)
+ broker.kill()
+ broker = self.broker(self.args(), name="recoverme")
+ self.assertEqual("x", broker.get_message("q").content)
+
+ def test_kill_restart(self):
+ """Verify we can kill/resetart a broker with store in a cluster"""
+ cluster = self.cluster(1, self.args())
+ cluster.start("restartme", expect=EXPECT_EXIT_FAIL).kill()
+
+ # Send a message, retrieve from the restarted broker
+ cluster[0].send_message("q", "x")
+ m = cluster.start("restartme").get_message("q")
+ self.assertEqual("x", m.content)
+
+ def test_persistent_restart(self):
+ """Verify persistent cluster shutdown/restart scenarios"""
+ cluster = self.cluster(0, args=self.args() + ["--cluster-size=3"])
+ a = cluster.start("a", expect=EXPECT_EXIT_OK, wait=False)
+ b = cluster.start("b", expect=EXPECT_EXIT_OK, wait=False)
+ c = cluster.start("c", expect=EXPECT_EXIT_FAIL, wait=True)
+ a.send_message("q", Message("1", durable=True))
+ # Kill & restart one member.
+ c.kill()
+ self.assertEqual(a.get_message("q").content, "1")
+ a.send_message("q", Message("2", durable=True))
+ c = cluster.start("c", expect=EXPECT_EXIT_OK)
+ self.assertEqual(c.get_message("q").content, "2")
+ # Shut down the entire cluster cleanly and bring it back up
+ a.send_message("q", Message("3", durable=True))
+ qpid_cluster.main(["qpid-cluster", "-kf", a.host_port()])
+ a = cluster.start("a", wait=False)
+ b = cluster.start("b", wait=False)
+ c = cluster.start("c", wait=True)
+ self.assertEqual(a.get_message("q").content, "3")
+
+ def test_persistent_partial_failure(self):
+ # Kill 2 members, shut down the last cleanly then restart
+ # Ensure we use the clean database
+ cluster = self.cluster(0, args=self.args() + ["--cluster-size=3"])
+ a = cluster.start("a", expect=EXPECT_EXIT_FAIL, wait=False)
+ b = cluster.start("b", expect=EXPECT_EXIT_FAIL, wait=False)
+ c = cluster.start("c", expect=EXPECT_EXIT_OK, wait=True)
+ a.send_message("q", Message("4", durable=True))
+ a.kill()
+ b.kill()
+ self.assertEqual(c.get_message("q").content, "4")
+ c.send_message("q", Message("clean", durable=True))
+ qpid_cluster.main(["qpid-cluster", "-kf", c.host_port()])
+ a = cluster.start("a", wait=False)
+ b = cluster.start("b", wait=False)
+ c = cluster.start("c", wait=True)
+ self.assertEqual(a.get_message("q").content, "clean")
+
+ def test_wrong_cluster_id(self):
+ # Start a cluster1 broker, then try to restart in cluster2
+ cluster1 = self.cluster(0, args=self.args())
+ a = cluster1.start("a", expect=EXPECT_EXIT_OK)
+ a.terminate()
+ cluster2 = self.cluster(1, args=self.args())
+ try:
+ a = cluster2.start("a", expect=EXPECT_EXIT_FAIL)
+ self.fail("Expected exception")
+ except: pass
+
+ def test_wrong_shutdown_id(self):
+ # Start 2 members and shut down.
+ cluster = self.cluster(0, args=self.args()+["--cluster-size=2"])
+ a = cluster.start("a", expect=EXPECT_EXIT_OK, wait=False)
+ b = cluster.start("b", expect=EXPECT_EXIT_OK, wait=False)
+ self.assertEqual(0, qpid_cluster.main(["qpid_cluster", "-kf", a.host_port()]))
+ self.assertEqual(a.wait(), 0)
+ self.assertEqual(b.wait(), 0)
+
+ # Restart with a different member and shut down.
+ a = cluster.start("a", expect=EXPECT_EXIT_OK, wait=False)
+ c = cluster.start("c", expect=EXPECT_EXIT_OK, wait=False)
+ self.assertEqual(0, qpid_cluster.main(["qpid_cluster", "-kf", a.host_port()]))
+ self.assertEqual(a.wait(), 0)
+ self.assertEqual(c.wait(), 0)
+
+ # Mix members from both shutdown events, they should fail
+ a = cluster.start("a", expect=EXPECT_EXIT_FAIL, wait=False)
+ b = cluster.start("b", expect=EXPECT_EXIT_FAIL, wait=False)
+
+ def test_total_failure(self):
+ # Verify we abort with sutiable error message if no clean stores.
+ cluster = self.cluster(0, args=self.args()+["--cluster-size=2"])
+ a = cluster.start("a", expect=EXPECT_EXIT_FAIL, wait=False)
+ b = cluster.start("b", expect=EXPECT_EXIT_FAIL, wait=True)
+ a.kill()
+ b.kill()
+ a = cluster.start("a", expect=EXPECT_EXIT_FAIL, wait=False)
+ b = cluster.start("b", expect=EXPECT_EXIT_FAIL, wait=False)
+ assert a.wait() != 0
+ assert b.wait() != 0
+ msg = re.compile("critical.*no clean store")
+ assert msg.search(file(a.log).read())
+ assert msg.search(file(b.log).read())
diff --git a/cpp/src/tests/clustered_replication_test b/cpp/src/tests/clustered_replication_test
new file mode 100755
index 0000000000..174f93382d
--- /dev/null
+++ b/cpp/src/tests/clustered_replication_test
@@ -0,0 +1,110 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Test reliability of the replication feature in the face of link
+# failures:
+source ./test_env.sh
+
+trap stop_brokers INT EXIT
+
+fail() {
+ echo $1
+ exit 1
+}
+
+stop_brokers() {
+ if [[ $PRIMARY1 ]] ; then
+ $QPIDD_EXEC --no-module-dir -q --port $PRIMARY1
+ unset PRIMARY1
+ fi
+ if [[ $PRIMARY2 ]] ; then
+ $QPIDD_EXEC --no-module-dir -q --port $PRIMARY2
+ unset PRIMARY2
+ fi
+ if [[ $DR1 ]] ; then
+ $QPIDD_EXEC --no-module-dir -q --port $DR1
+ unset DR1
+ fi
+ if [[ $DR2 ]] ; then
+ $QPIDD_EXEC --no-module-dir -q --port $DR2
+ unset DR2
+ fi
+}
+
+if test -d $PYTHON_DIR; then
+ . $srcdir/ais_check
+
+ #todo: these cluster names need to be unique to prevent clashes
+ PRIMARY_CLUSTER=PRIMARY_$(hostname)_$$
+ DR_CLUSTER=DR_$(hostname)_$$
+
+ GENERAL_OPTS="--auth no --no-module-dir --no-data-dir --daemon --port 0 --log-to-stderr false"
+ PRIMARY_OPTS="--load-module $REPLICATING_LISTENER_LIB --create-replication-queue true --replication-queue REPLICATION_QUEUE --load-module $CLUSTER_LIB --cluster-name $PRIMARY_CLUSTER"
+ DR_OPTS="--load-module $REPLICATION_EXCHANGE_LIB --load-module $CLUSTER_LIB --cluster-name $DR_CLUSTER"
+
+ rm -f repl*.tmp #cleanup any files left from previous run
+
+ #start first node of primary cluster and set up test queue
+ echo Starting primary cluster
+ PRIMARY1=$(with_ais_group $QPIDD_EXEC $GENERAL_OPTS $PRIMARY_OPTS --log-to-file repl.primary.1.tmp) || fail "Could not start PRIMARY1"
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$PRIMARY1" add queue test-queue --generate-queue-events 2
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$PRIMARY1" add queue control-queue --generate-queue-events 1
+
+ #send 10 messages, consume 5 of them
+ for i in `seq 1 10`; do echo Message$i; done | ./sender --port $PRIMARY1
+ ./receiver --port $PRIMARY1 --messages 5 > /dev/null
+
+ #add new node to primary cluster, testing correct transfer of state:
+ echo Adding node to primary cluster
+ PRIMARY2=$(with_ais_group $QPIDD_EXEC $GENERAL_OPTS $PRIMARY_OPTS --log-to-file repl.primary.2.tmp) || fail "Could not start PRIMARY2 "
+
+ #start DR cluster, set up test queue there and establish replication bridge
+ echo Starting DR cluster
+ DR1=$(with_ais_group $QPIDD_EXEC $GENERAL_OPTS $DR_OPTS --log-to-file repl.dr.1.tmp) || fail "Could not start DR1"
+ DR2=$(with_ais_group $QPIDD_EXEC $GENERAL_OPTS $DR_OPTS --log-to-file repl.dr.2.tmp) || fail "Could not start DR2"
+
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$DR1" add queue test-queue
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$DR1" add queue control-queue
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$DR1" add exchange replication REPLICATION_EXCHANGE
+ $PYTHON_COMMANDS/qpid-route queue add localhost:$DR2 localhost:$PRIMARY2 REPLICATION_EXCHANGE REPLICATION_QUEUE
+
+ #send more messages to primary
+ for i in `seq 11 20`; do echo Message$i; done | ./sender --port $PRIMARY1 --send-eos 1
+
+ #wait for replication events to all be processed:
+ echo Waiting for replication to complete
+ echo Done | ./sender --port $PRIMARY1 --routing-key control-queue --send-eos 1
+ ./receiver --queue control-queue --port $DR1 > /dev/null
+
+ #verify contents of test queue on dr cluster:
+ echo Verifying...
+ ./receiver --port $DR2 > repl.out.tmp
+ for i in `seq 6 20`; do echo Message$i; done | diff repl.out.tmp - || FAIL=1
+
+ if [[ $FAIL ]]; then
+ echo Clustered replication test failed: expectations not met!
+ exit 1
+ else
+ echo Clustered replication test passed
+ rm -f repl*.tmp
+ fi
+
+fi
diff --git a/cpp/src/tests/config.null b/cpp/src/tests/config.null
new file mode 100644
index 0000000000..565c7da435
--- /dev/null
+++ b/cpp/src/tests/config.null
@@ -0,0 +1 @@
+# empty config
diff --git a/cpp/src/tests/consume.cpp b/cpp/src/tests/consume.cpp
index fecf6bb315..69110d151f 100644
--- a/cpp/src/tests/consume.cpp
+++ b/cpp/src/tests/consume.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -34,32 +34,44 @@
using namespace qpid;
using namespace qpid::client;
using namespace qpid::sys;
-using std::string;
+using namespace std;
+
+namespace qpid {
+namespace tests {
-typedef std::vector<std::string> StringSet;
+typedef vector<string> StringSet;
struct Args : public qpid::TestOptions {
uint count;
uint ack;
string queue;
+ bool declare;
+ bool summary;
+ bool print;
+ bool durable;
- Args() : count(0), ack(1)
+ Args() : count(1000), ack(0), queue("publish-consume"),
+ declare(false), summary(false), print(false)
{
addOptions()
("count", optValue(count, "N"), "number of messages to publish")
("ack-frequency", optValue(ack, "N"), "ack every N messages (0 means use no-ack mode)")
- ("queue", optValue(queue, "<queue name>"), "queue to consume from");
+ ("queue", optValue(queue, "<queue name>"), "queue to consume from")
+ ("declare", optValue(declare), "declare the queue")
+ ("durable", optValue(durable), "declare the queue durable, use with declare")
+ ("print-data", optValue(print), "Print the recieved data at info level")
+ ("s,summary", optValue(summary), "Print undecorated rate.");
}
};
Args opts;
-struct Client
+struct Client
{
Connection connection;
Session session;
- Client()
+ Client()
{
opts.open(connection);
session = connection.newSession();
@@ -67,33 +79,44 @@ struct Client
void consume()
{
-
+ if (opts.declare)
+ session.queueDeclare(arg::queue=opts.queue, arg::durable=opts.durable);
SubscriptionManager subs(session);
- LocalQueue lq(AckPolicy(opts.ack));
- subs.setAcceptMode(opts.ack > 0 ? 0 : 1);
- subs.setFlowControl(opts.count, SubscriptionManager::UNLIMITED,
- false);
- subs.subscribe(lq, opts.queue);
+ LocalQueue lq;
+ SubscriptionSettings settings;
+ settings.acceptMode = opts.ack > 0 ? ACCEPT_MODE_EXPLICIT : ACCEPT_MODE_NONE;
+ settings.flowControl = FlowControl(opts.count, SubscriptionManager::UNLIMITED,false);
+ Subscription sub = subs.subscribe(lq, opts.queue, settings);
Message msg;
+ AbsTime begin=now();
for (size_t i = 0; i < opts.count; ++i) {
msg=lq.pop();
- std::cout << "Received: " << msg.getMessageProperties().getCorrelationId() << std::endl;
+ QPID_LOG(info, "Received: " << msg.getMessageProperties().getCorrelationId());
+ if (opts.print) QPID_LOG(info, "Data: " << msg.getData());
}
if (opts.ack != 0)
- subs.getAckPolicy().ackOutstanding(session); // Cumulative ack for final batch.
+ sub.accept(sub.getUnaccepted()); // Cumulative ack for final batch.
+ AbsTime end=now();
+ double secs(double(Duration(begin,end))/TIME_SEC);
+ if (opts.summary) cout << opts.count/secs << endl;
+ else cout << "Time: " << secs << "s Rate: " << opts.count/secs << endl;
}
- ~Client()
+ ~Client()
{
try{
session.close();
connection.close();
- } catch(const std::exception& e) {
- std::cout << e.what() << std::endl;
+ } catch(const exception& e) {
+ cout << e.what() << endl;
}
}
};
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char** argv)
{
try {
@@ -101,8 +124,8 @@ int main(int argc, char** argv)
Client client;
client.consume();
return 0;
- } catch(const std::exception& e) {
- std::cout << e.what() << std::endl;
+ } catch(const exception& e) {
+ cout << e.what() << endl;
}
return 1;
}
diff --git a/cpp/src/tests/datagen.cpp b/cpp/src/tests/datagen.cpp
new file mode 100644
index 0000000000..acbc07d63c
--- /dev/null
+++ b/cpp/src/tests/datagen.cpp
@@ -0,0 +1,103 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <exception>
+#include <iostream>
+#include <stdlib.h>
+#include <time.h>
+#include "qpid/Options.h"
+
+namespace qpid {
+namespace tests {
+
+struct Args : public qpid::Options
+{
+ uint count;
+ uint minSize;
+ uint maxSize;
+ uint minChar;
+ uint maxChar;
+ bool help;
+
+ Args() : qpid::Options("Random data generator"),
+ count(1), minSize(8), maxSize(4096),
+ minChar(32), maxChar(126),//safely printable ascii chars
+ help(false)
+ {
+ addOptions()
+ ("count", qpid::optValue(count, "N"), "number of data strings to generate")
+ ("min-size", qpid::optValue(minSize, "N"), "minimum size of data string")
+ ("max-size", qpid::optValue(maxSize, "N"), "maximum size of data string")
+ ("min-char", qpid::optValue(minChar, "N"), "minimum char value used in data string")
+ ("max-char", qpid::optValue(maxChar, "N"), "maximum char value used in data string")
+ ("help", qpid::optValue(help), "print this usage statement");
+ }
+
+ bool parse(int argc, char** argv) {
+ try {
+ qpid::Options::parse(argc, argv);
+ if (maxSize < minSize) throw qpid::Options::Exception("max-size must be greater than min-size");
+ if (maxChar < minChar) throw qpid::Options::Exception("max-char must be greater than min-char");
+
+ if (help) {
+ std::cerr << *this << std::endl << std::endl;
+ } else {
+ return true;
+ }
+ } catch (const std::exception& e) {
+ std::cerr << *this << std::endl << std::endl << e.what() << std::endl;
+ }
+ return false;
+ }
+
+};
+
+uint random(uint min, uint max)
+{
+ return (rand() % (max-min+1)) + min;
+}
+
+std::string generateData(uint size, uint min, uint max)
+{
+ std::string data;
+ for (uint i = 0; i < size; i++) {
+ data += (char) random(min, max);
+ }
+ return data;
+}
+
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
+int main(int argc, char** argv)
+{
+ Args opts;
+ if (opts.parse(argc, argv)) {
+ srand(time(0));
+ for (uint i = 0; i < opts.count; i++) {
+ std::cout << generateData(random(opts.minSize, opts.maxSize), opts.minChar, opts.maxChar) << std::endl;
+ }
+ return 0;
+ } else {
+ return 1;
+ }
+}
diff --git a/cpp/src/tests/declare_queues.cpp b/cpp/src/tests/declare_queues.cpp
new file mode 100644
index 0000000000..bf85b9c04b
--- /dev/null
+++ b/cpp/src/tests/declare_queues.cpp
@@ -0,0 +1,101 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/client/FailoverManager.h>
+#include <qpid/client/Session.h>
+#include <qpid/sys/Time.h>
+#include <qpid/Exception.h>
+
+#include <cstdlib>
+#include <iostream>
+#include <sstream>
+
+using namespace qpid::client;
+
+using namespace std;
+
+int
+main(int argc, char ** argv)
+{
+ ConnectionSettings settings;
+ if ( argc != 6 )
+ {
+ cerr << "Usage: declare_queues host port durability queue_name_prefix n_queues\n";
+ return 1;
+ }
+
+ settings.host = argv[1];
+ settings.port = atoi(argv[2]);
+ int durability = atoi(argv[3]);
+ char const * queue_name_prefix = argv[4];
+ int n_queues = atoi(argv[5]);
+
+ FailoverManager connection(settings);
+
+ int max_fail = 13;
+ for ( int i = 0; i < n_queues; ++ i ) {
+ stringstream queue_name;
+ queue_name << queue_name_prefix << '_' << i;
+
+ bool queue_created = false;
+ int failure_count;
+
+ // Any non-transport failure is Bad.
+ try
+ {
+ while ( ! queue_created ) {
+ Session session = connection.connect().newSession();
+ // TransportFailures aren't too bad -- they might happen because
+ // we are doing a cluster failover test. But if we get too many,
+ // we will still bug out.
+ failure_count = 0;
+ try {
+ if ( durability )
+ session.queueDeclare(arg::queue=queue_name.str(), arg::durable=true);
+ else
+ session.queueDeclare(arg::queue=queue_name.str());
+ queue_created = true;
+ cout << "declare_queues: Created queue " << queue_name.str() << endl;
+ }
+ catch ( const qpid::TransportFailure& ) {
+ if ( ++ failure_count >= max_fail ) {
+ cerr << "declare_queues failed: too many transport errors.\n";
+ cerr << " host: " << settings.host
+ << " port: " << settings.port << endl;
+ return 1;
+ }
+ qpid::sys::sleep ( 1 );
+ }
+ }
+ }
+ catch ( const exception & error) {
+ cerr << "declare_queues failed:" << error.what() << endl;
+ cerr << " host: " << settings.host
+ << " port: " << settings.port << endl;
+ return 1;
+ }
+ }
+}
+
+
+
+
+
diff --git a/cpp/src/tests/dlclose_noop.c b/cpp/src/tests/dlclose_noop.c
index ba2fa75891..b78cf486d8 100644
--- a/cpp/src/tests/dlclose_noop.c
+++ b/cpp/src/tests/dlclose_noop.c
@@ -26,5 +26,5 @@
*/
#include <stdio.h>
-void* dlclose(void* handle) {}
+void* dlclose(void* handle) { return 0; }
diff --git a/cpp/src/tests/echotest.cpp b/cpp/src/tests/echotest.cpp
new file mode 100644
index 0000000000..ab26dcf3fd
--- /dev/null
+++ b/cpp/src/tests/echotest.cpp
@@ -0,0 +1,157 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/client/Connection.h>
+#include <qpid/client/SubscriptionManager.h>
+#include <qpid/client/AsyncSession.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/MessageListener.h>
+#include <qpid/sys/Time.h>
+
+#include <iostream>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace qpid::sys;
+using namespace std;
+
+namespace qpid {
+namespace tests {
+
+struct Args : public qpid::Options,
+ public qpid::client::ConnectionSettings
+{
+ bool help;
+ uint count;
+ uint size;
+ bool summary;
+
+ Args() : qpid::Options("Simple latency test optins"), help(false), count(20), size(0), summary()
+ {
+ using namespace qpid;
+ addOptions()
+ ("help", optValue(help), "Print this usage statement")
+ ("count", optValue(count, "N"), "Number of messages to send")
+ ("size", optValue(count, "N"), "Size of messages")
+ ("broker,b", optValue(host, "HOST"), "Broker host to connect to")
+ ("port,p", optValue(port, "PORT"), "Broker port to connect to")
+ ("username", optValue(username, "USER"), "user name for broker log in.")
+ ("password", optValue(password, "PASSWORD"), "password for broker log in.")
+ ("mechanism", optValue(mechanism, "MECH"), "SASL mechanism to use when authenticating.")
+ ("tcp-nodelay", optValue(tcpNoDelay), "Turn on tcp-nodelay")
+ ("s,summary", optValue(summary), "Print only average latency.");
+ }
+};
+
+uint64_t current_time()
+{
+ Duration t(now());
+ return t;
+}
+
+class Listener : public MessageListener
+{
+ private:
+ Session session;
+ SubscriptionManager subscriptions;
+ uint counter;
+ const uint limit;
+ std::string queue;
+ Message request;
+ double total, min, max;
+ bool summary;
+
+ public:
+ Listener(Session& session, uint limit, bool summary);
+ void start(uint size);
+ void received(Message& message);
+};
+
+Listener::Listener(Session& s, uint l, bool summary_) :
+ session(s), subscriptions(s), counter(0), limit(l),
+ queue(session.getId().getName()), total(),
+ min(std::numeric_limits<double>::max()), max(), summary(summary_)
+{}
+
+void Listener::start(uint size)
+{
+ session.queueDeclare(arg::queue=queue, arg::exclusive=true, arg::autoDelete=true);
+ request.getDeliveryProperties().setRoutingKey(queue);
+ subscriptions.subscribe(*this, queue, SubscriptionSettings(FlowControl::unlimited(), ACCEPT_MODE_NONE));
+
+ request.getDeliveryProperties().setTimestamp(current_time());
+ if (size) request.setData(std::string(size, 'X'));
+ async(session).messageTransfer(arg::content=request);
+ subscriptions.run();
+}
+
+void Listener::received(Message& response)
+{
+ //extract timestamp and compute latency:
+ uint64_t sentAt = response.getDeliveryProperties().getTimestamp();
+ uint64_t receivedAt = current_time();
+
+ double latency = ((double) (receivedAt - sentAt)) / TIME_MSEC;
+ if (!summary) cout << "Latency: " << latency << "ms" << endl;
+ min = std::min(latency, min);
+ max = std::max(latency, max);
+ total += latency;
+
+ if (++counter < limit) {
+ request.getDeliveryProperties().setTimestamp(current_time());
+ async(session).messageTransfer(arg::content=request);
+ } else {
+ subscriptions.cancel(queue);
+ if (summary) cout << min << "\t" << max << "\t" << total/limit << endl;
+ else cout << "min: " << min << " max: " << max << " average: " << total/limit << endl;
+ }
+}
+
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
+int main(int argc, char** argv)
+{
+ Args opts;
+ opts.parse(argc, argv);
+
+ if (opts.help) {
+ std::cout << opts << std::endl;
+ return 0;
+ }
+
+ Connection connection;
+ try {
+ connection.open(opts);
+ Session session = connection.newSession();
+ Listener listener(session, opts.count, opts.summary);
+ listener.start(opts.size);
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/cpp/src/tests/exception_test.cpp b/cpp/src/tests/exception_test.cpp
index 1cbe35fff4..4dac8ee965 100644
--- a/cpp/src/tests/exception_test.cpp
+++ b/cpp/src/tests/exception_test.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -20,12 +20,17 @@
*/
#include "unit_test.h"
+#include "test_tools.h"
#include "BrokerFixture.h"
#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/MessageListener.h"
#include "qpid/sys/Runnable.h"
#include "qpid/sys/Thread.h"
#include "qpid/framing/reply_exceptions.h"
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(exception_test)
// FIXME aconway 2008-06-12: need to update our exception handling to
@@ -38,6 +43,7 @@ using namespace sys;
using namespace client;
using namespace framing;
+using qpid::broker::Broker;
using boost::bind;
using boost::function;
@@ -46,12 +52,15 @@ struct Catcher : public Runnable {
function<void ()> f;
bool caught;
Thread thread;
-
+
Catcher(function<void ()> f_) : f(f_), caught(false), thread(this) {}
~Catcher() { join(); }
-
+
void run() {
- try { f(); }
+ try {
+ ScopedSuppressLogging sl; // Suppress messages for expected errors.
+ f();
+ }
catch(const Ex& e) {
caught=true;
BOOST_MESSAGE(string("Caught expected exception: ")+e.what()+"["+typeid(e).name()+"]");
@@ -73,12 +82,21 @@ struct Catcher : public Runnable {
}
};
+QPID_AUTO_TEST_CASE(TestSessionBusy) {
+ SessionFixture f;
+ try {
+ ScopedSuppressLogging sl; // Suppress messages for expected errors.
+ f.connection.newSession(f.session.getId().getName());
+ BOOST_FAIL("Expected SessionBusyException for " << f.session.getId().getName());
+ } catch (const SessionBusyException&) {} // FIXME aconway 2008-09-22: client is not throwing correct exception.
+}
+
QPID_AUTO_TEST_CASE(DisconnectedPop) {
ProxySessionFixture fix;
- ProxyConnection c(fix.broker->getPort());
+ ProxyConnection c(fix.broker->getPort(Broker::TCP_TRANSPORT));
fix.session.queueDeclare(arg::queue="q");
fix.subs.subscribe(fix.lq, "q");
- Catcher<Exception> pop(bind(&LocalQueue::pop, boost::ref(fix.lq)));
+ Catcher<TransportFailure> pop(bind(&LocalQueue::pop, &fix.lq, sys::TIME_SEC));
fix.connection.proxy.close();
BOOST_CHECK(pop.join());
}
@@ -88,18 +106,22 @@ QPID_AUTO_TEST_CASE(DisconnectedListen) {
struct NullListener : public MessageListener {
void received(Message&) { BOOST_FAIL("Unexpected message"); }
} l;
- ProxyConnection c(fix.broker->getPort());
+ ProxyConnection c(fix.broker->getPort(Broker::TCP_TRANSPORT));
fix.session.queueDeclare(arg::queue="q");
fix.subs.subscribe(l, "q");
- Thread t(fix.subs);
+
+ Catcher<TransportFailure> runner(bind(&SubscriptionManager::run, boost::ref(fix.subs)));
fix.connection.proxy.close();
- t.join();
- BOOST_CHECK_THROW(fix.session.close(), ConnectionException);
+ runner.join();
+ BOOST_CHECK_THROW(fix.session.queueDeclare(arg::queue="x"), TransportFailure);
}
QPID_AUTO_TEST_CASE(NoSuchQueueTest) {
ProxySessionFixture fix;
+ ScopedSuppressLogging sl; // Suppress messages for expected errors.
BOOST_CHECK_THROW(fix.subs.subscribe(fix.lq, "no such queue"), NotFoundException);
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/failover_soak.cpp b/cpp/src/tests/failover_soak.cpp
new file mode 100644
index 0000000000..ed5c9cbee5
--- /dev/null
+++ b/cpp/src/tests/failover_soak.cpp
@@ -0,0 +1,826 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <string.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <vector>
+
+#include <boost/assign.hpp>
+
+#include "qpid/framing/Uuid.h"
+
+#include <ForkedBroker.h>
+#include <qpid/client/Connection.h>
+
+
+
+
+
+using namespace std;
+using boost::assign::list_of;
+using namespace qpid::framing;
+using namespace qpid::client;
+
+
+namespace qpid {
+namespace tests {
+
+typedef vector<ForkedBroker *> brokerVector;
+
+typedef enum
+{
+ NO_STATUS,
+ RUNNING,
+ COMPLETED
+}
+childStatus;
+
+
+typedef enum
+{
+ NO_TYPE,
+ DECLARING_CLIENT,
+ SENDING_CLIENT,
+ RECEIVING_CLIENT
+}
+childType;
+
+
+ostream& operator<< ( ostream& os, const childType& ct ) {
+ switch ( ct ) {
+ case DECLARING_CLIENT: os << "Declaring Client"; break;
+ case SENDING_CLIENT: os << "Sending Client"; break;
+ case RECEIVING_CLIENT: os << "Receiving Client"; break;
+ default: os << "No Client"; break;
+ }
+
+ return os;
+}
+
+
+
+
+struct child
+{
+ child ( string & name, pid_t pid, childType type )
+ : name(name), pid(pid), retval(-999), status(RUNNING), type(type)
+ {
+ gettimeofday ( & startTime, 0 );
+ }
+
+
+ void
+ done ( int _retval )
+ {
+ retval = _retval;
+ status = COMPLETED;
+ gettimeofday ( & stopTime, 0 );
+ }
+
+
+ void
+ setType ( childType t )
+ {
+ type = t;
+ }
+
+
+ string name;
+ pid_t pid;
+ int retval;
+ childStatus status;
+ childType type;
+ struct timeval startTime,
+ stopTime;
+};
+
+
+
+
+struct children : public vector<child *>
+{
+
+ void
+ add ( string & name, pid_t pid, childType type )
+ {
+ push_back ( new child ( name, pid, type ) );
+ }
+
+
+ child *
+ get ( pid_t pid )
+ {
+ vector<child *>::iterator i;
+ for ( i = begin(); i != end(); ++ i )
+ if ( pid == (*i)->pid )
+ return *i;
+
+ return 0;
+ }
+
+
+ void
+ exited ( pid_t pid, int retval )
+ {
+ child * kid = get ( pid );
+ if(! kid)
+ {
+ if ( verbosity > 1 )
+ {
+ cerr << "children::exited warning: Can't find child with pid "
+ << pid
+ << endl;
+ }
+ return;
+ }
+
+ kid->done ( retval );
+ }
+
+
+ int
+ unfinished ( )
+ {
+ int count = 0;
+
+ vector<child *>::iterator i;
+ for ( i = begin(); i != end(); ++ i )
+ if ( COMPLETED != (*i)->status )
+ ++ count;
+
+ return count;
+ }
+
+
+ int
+ checkChildren ( )
+ {
+ vector<child *>::iterator i;
+ for ( i = begin(); i != end(); ++ i )
+ if ( (COMPLETED == (*i)->status) && (0 != (*i)->retval) )
+ {
+ cerr << "checkChildren: error on child of type "
+ << (*i)->type
+ << endl;
+ return (*i)->retval;
+ }
+
+ return 0;
+ }
+
+
+ void
+ killEverybody ( )
+ {
+ vector<child *>::iterator i;
+ for ( i = begin(); i != end(); ++ i )
+ kill ( (*i)->pid, 9 );
+ }
+
+
+
+ void
+ print ( )
+ {
+ cout << "--- status of all children --------------\n";
+ vector<child *>::iterator i;
+ for ( i = begin(); i != end(); ++ i )
+ cout << "child: " << (*i)->name
+ << " status: " << (*i)->status
+ << endl;
+ cout << "\n\n\n\n";
+ }
+
+ int verbosity;
+};
+
+
+children allMyChildren;
+
+
+void
+childExit ( int )
+{
+ int childReturnCode;
+ pid_t pid = waitpid ( 0, & childReturnCode, WNOHANG);
+
+ if ( pid > 0 )
+ allMyChildren.exited ( pid, childReturnCode );
+}
+
+
+
+int
+mrand ( int maxDesiredVal ) {
+ double zeroToOne = (double) rand() / (double) RAND_MAX;
+ return (int) (zeroToOne * (double) maxDesiredVal);
+}
+
+
+
+int
+mrand ( int minDesiredVal, int maxDesiredVal ) {
+ int interval = maxDesiredVal - minDesiredVal;
+ return minDesiredVal + mrand ( interval );
+}
+
+
+
+void
+makeClusterName ( string & s ) {
+ stringstream ss;
+ ss << "soakTestCluster_" << Uuid(true).str();
+ s = ss.str();
+}
+
+
+
+
+
+void
+printBrokers ( brokerVector & brokers )
+{
+ cout << "Broker List ------------ size: " << brokers.size() << "\n";
+ for ( brokerVector::iterator i = brokers.begin(); i != brokers.end(); ++ i) {
+ cout << "pid: "
+ << (*i)->getPID()
+ << " port: "
+ << (*i)->getPort()
+ << endl;
+ }
+ cout << "end Broker List ------------\n";
+}
+
+
+
+
+ForkedBroker * newbie = 0;
+int newbie_port = 0;
+
+
+
+bool
+wait_for_newbie ( )
+{
+ if ( ! newbie )
+ return true;
+
+ try
+ {
+ Connection connection;
+ connection.open ( "127.0.0.1", newbie_port );
+ connection.close();
+ newbie = 0; // He's no newbie anymore!
+ return true;
+ }
+ catch ( const std::exception& error )
+ {
+ std::cerr << "wait_for_newbie error: "
+ << error.what()
+ << endl;
+ return false;
+ }
+}
+
+bool endsWith(const char* str, const char* suffix) {
+ return (strlen(suffix) < strlen(str) && 0 == strcmp(str+strlen(str)-strlen(suffix), suffix));
+}
+
+
+void
+startNewBroker ( brokerVector & brokers,
+ char const * moduleOrDir,
+ string const clusterName,
+ int verbosity,
+ int durable )
+{
+ static int brokerId = 0;
+ stringstream path, prefix;
+ prefix << "soak-" << brokerId;
+ std::vector<std::string> argv = list_of<string>
+ ("qpidd")
+ ("--cluster-name")(clusterName)
+ ("--auth=no")
+ ("--mgmt-enable=no")
+ ("--log-prefix")(prefix.str())
+ ("--log-to-file")(prefix.str()+".log")
+ ("--log-enable=notice+")
+ ("TMP_DATA_DIR");
+
+ if (endsWith(moduleOrDir, "cluster.so")) {
+ // Module path specified, load only that module.
+ argv.push_back(string("--load-module=")+moduleOrDir);
+ argv.push_back("--no-module-dir");
+ if ( durable ) {
+ std::cerr << "failover_soak warning: durable arg hass no effect. Use \"dir\" option of \"moduleOrDir\".\n";
+ }
+ }
+ else {
+ // Module directory specified, load all modules in dir.
+ argv.push_back(string("--module-dir=")+moduleOrDir);
+ }
+
+ newbie = new ForkedBroker (argv);
+ newbie_port = newbie->getPort();
+ ForkedBroker * broker = newbie;
+
+ if ( verbosity > 0 )
+ std::cerr << "new broker created: pid == "
+ << broker->getPID()
+ << " log-prefix == "
+ << "soak-" << brokerId
+ << endl;
+ brokers.push_back ( broker );
+
+ ++ brokerId;
+}
+
+
+
+
+
+bool
+killFrontBroker ( brokerVector & brokers, int verbosity )
+{
+ cerr << "killFrontBroker: waiting for newbie sync...\n";
+ if ( ! wait_for_newbie() )
+ return false;
+ cerr << "killFrontBroker: newbie synced.\n";
+
+ if ( verbosity > 0 )
+ cout << "killFrontBroker pid: " << brokers[0]->getPID() << " on port " << brokers[0]->getPort() << endl;
+ try { brokers[0]->kill(9); }
+ catch ( const exception& error ) {
+ if ( verbosity > 0 )
+ {
+ cout << "error killing broker: "
+ << error.what()
+ << endl;
+ }
+
+ return false;
+ }
+ delete brokers[0];
+ brokers.erase ( brokers.begin() );
+ return true;
+}
+
+
+
+
+
+/*
+ * The optional delay is to avoid killing newbie brokers that have just
+ * been added and are still in the process of updating. This causes
+ * spurious, test-generated errors that scare everybody.
+ */
+void
+killAllBrokers ( brokerVector & brokers, int delay )
+{
+ if ( delay > 0 )
+ {
+ std::cerr << "Killing all brokers after delay of " << delay << endl;
+ sleep ( delay );
+ }
+
+ for ( uint i = 0; i < brokers.size(); ++ i )
+ try { brokers[i]->kill(9); }
+ catch ( const exception& error )
+ {
+ std::cerr << "killAllBrokers Warning: exception during kill on broker "
+ << i
+ << " "
+ << error.what()
+ << endl;
+ }
+}
+
+
+
+
+
+pid_t
+runDeclareQueuesClient ( brokerVector brokers,
+ char const * host,
+ char const * path,
+ int verbosity,
+ int durable,
+ char const * queue_prefix,
+ int n_queues
+ )
+{
+ string name("declareQueues");
+ int port = brokers[0]->getPort ( );
+
+ if ( verbosity > 1 )
+ cout << "startDeclareQueuesClient: host: "
+ << host
+ << " port: "
+ << port
+ << endl;
+ stringstream portSs;
+ portSs << port;
+
+ vector<const char*> argv;
+ argv.push_back ( "declareQueues" );
+ argv.push_back ( host );
+ argv.push_back ( portSs.str().c_str() );
+ if ( durable )
+ argv.push_back ( "1" );
+ else
+ argv.push_back ( "0" );
+
+ argv.push_back ( queue_prefix );
+
+ char n_queues_str[20];
+ sprintf ( n_queues_str, "%d", n_queues );
+ argv.push_back ( n_queues_str );
+
+ argv.push_back ( 0 );
+ pid_t pid = fork();
+
+ if ( ! pid ) {
+ execv ( path, const_cast<char * const *>(&argv[0]) );
+ perror ( "error executing declareQueues: " );
+ return 0;
+ }
+
+ allMyChildren.add ( name, pid, DECLARING_CLIENT );
+ return pid;
+}
+
+
+
+
+
+pid_t
+startReceivingClient ( brokerVector brokers,
+ char const * host,
+ char const * receiverPath,
+ char const * reportFrequency,
+ int verbosity,
+ char const * queue_name
+ )
+{
+ string name("receiver");
+ int port = brokers[0]->getPort ( );
+
+ if ( verbosity > 1 )
+ cout << "startReceivingClient: port " << port << endl;
+
+ // verbosity has to be > 1 to let clients talk.
+ int client_verbosity = (verbosity > 1 ) ? 1 : 0;
+
+ char portStr[100];
+ char verbosityStr[100];
+ sprintf(portStr, "%d", port);
+ sprintf(verbosityStr, "%d", client_verbosity);
+
+
+ vector<const char*> argv;
+ argv.push_back ( "resumingReceiver" );
+ argv.push_back ( host );
+ argv.push_back ( portStr );
+ argv.push_back ( reportFrequency );
+ argv.push_back ( verbosityStr );
+ argv.push_back ( queue_name );
+ argv.push_back ( 0 );
+
+ pid_t pid = fork();
+
+ if ( ! pid ) {
+ execv ( receiverPath, const_cast<char * const *>(&argv[0]) );
+ perror ( "error executing receiver: " );
+ return 0;
+ }
+
+ allMyChildren.add ( name, pid, RECEIVING_CLIENT );
+ return pid;
+}
+
+
+
+
+
+pid_t
+startSendingClient ( brokerVector brokers,
+ char const * host,
+ char const * senderPath,
+ char const * nMessages,
+ char const * reportFrequency,
+ int verbosity,
+ int durability,
+ char const * queue_name
+ )
+{
+ string name("sender");
+ int port = brokers[0]->getPort ( );
+
+ if ( verbosity > 1)
+ cout << "startSenderClient: port " << port << endl;
+ char portStr[100];
+ char verbosityStr[100];
+ //
+ // verbosity has to be > 1 to let clients talk.
+ int client_verbosity = (verbosity > 1 ) ? 1 : 0;
+
+ sprintf ( portStr, "%d", port);
+ sprintf ( verbosityStr, "%d", client_verbosity);
+
+ vector<const char*> argv;
+ argv.push_back ( "replayingSender" );
+ argv.push_back ( host );
+ argv.push_back ( portStr );
+ argv.push_back ( nMessages );
+ argv.push_back ( reportFrequency );
+ argv.push_back ( verbosityStr );
+ if ( durability )
+ argv.push_back ( "1" );
+ else
+ argv.push_back ( "0" );
+ argv.push_back ( queue_name );
+ argv.push_back ( 0 );
+
+ pid_t pid = fork();
+
+ if ( ! pid ) {
+ execv ( senderPath, const_cast<char * const *>(&argv[0]) );
+ perror ( "error executing sender: " );
+ return 0;
+ }
+
+ allMyChildren.add ( name, pid, SENDING_CLIENT );
+ return pid;
+}
+
+
+
+#define HUNKY_DORY 0
+#define BAD_ARGS 1
+#define CANT_FORK_DQ 2
+#define CANT_FORK_RECEIVER 3
+#define CANT_FORK_SENDER 4
+#define DQ_FAILED 5
+#define ERROR_ON_CHILD 6
+#define HANGING 7
+#define ERROR_KILLING_BROKER 8
+
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
+// If you want durability, use the "dir" option of "moduleOrDir" .
+int
+main ( int argc, char const ** argv )
+{
+ if ( argc != 11 ) {
+ cerr << "Usage: "
+ << argv[0]
+ << "moduleOrDir declareQueuesPath senderPath receiverPath nMessages reportFrequency verbosity durable n_queues n_brokers"
+ << endl;
+ cerr << "\tverbosity is an integer, durable is 0 or 1\n";
+ return BAD_ARGS;
+ }
+ signal ( SIGCHLD, childExit );
+
+ int i = 1;
+ char const * moduleOrDir = argv[i++];
+ char const * declareQueuesPath = argv[i++];
+ char const * senderPath = argv[i++];
+ char const * receiverPath = argv[i++];
+ char const * nMessages = argv[i++];
+ char const * reportFrequency = argv[i++];
+ int verbosity = atoi(argv[i++]);
+ int durable = atoi(argv[i++]);
+ int n_queues = atoi(argv[i++]);
+ int n_brokers = atoi(argv[i++]);
+
+ char const * host = "127.0.0.1";
+ int maxBrokers = 50;
+
+ allMyChildren.verbosity = verbosity;
+
+ string clusterName;
+
+ srand ( getpid() );
+
+ makeClusterName ( clusterName );
+
+ brokerVector brokers;
+
+ if ( verbosity > 1 )
+ cout << "Starting initial cluster...\n";
+
+ for ( int i = 0; i < n_brokers; ++ i ) {
+ startNewBroker ( brokers,
+ moduleOrDir,
+ clusterName,
+ verbosity,
+ durable );
+ }
+
+
+ if ( verbosity > 0 )
+ printBrokers ( brokers );
+
+ // Get prefix for each queue name.
+ stringstream queue_prefix;
+ queue_prefix << "failover_soak_" << getpid();
+
+
+ // Run the declareQueues child.
+ int childStatus;
+ pid_t dqClientPid =
+ runDeclareQueuesClient ( brokers,
+ host,
+ declareQueuesPath,
+ verbosity,
+ durable,
+ queue_prefix.str().c_str(),
+ n_queues
+ );
+ if ( -1 == dqClientPid ) {
+ cerr << "END_OF_TEST ERROR_START_DECLARE_1\n";
+ return CANT_FORK_DQ;
+ }
+
+ // Don't continue until declareQueues is finished.
+ pid_t retval = waitpid ( dqClientPid, & childStatus, 0);
+ if ( retval != dqClientPid) {
+ cerr << "END_OF_TEST ERROR_START_DECLARE_2\n";
+ return DQ_FAILED;
+ }
+ allMyChildren.exited ( dqClientPid, childStatus );
+
+
+ /*
+ Start one receiving and one sending client for each queue.
+ */
+ for ( int i = 0; i < n_queues; ++ i ) {
+
+ stringstream queue_name;
+ queue_name << queue_prefix.str() << '_' << i;
+
+ // Receiving client ---------------------------
+ pid_t receivingClientPid =
+ startReceivingClient ( brokers,
+ host,
+ receiverPath,
+ reportFrequency,
+ verbosity,
+ queue_name.str().c_str() );
+ if ( -1 == receivingClientPid ) {
+ cerr << "END_OF_TEST ERROR_START_RECEIVER\n";
+ return CANT_FORK_RECEIVER;
+ }
+
+
+ // Sending client ---------------------------
+ pid_t sendingClientPid =
+ startSendingClient ( brokers,
+ host,
+ senderPath,
+ nMessages,
+ reportFrequency,
+ verbosity,
+ durable,
+ queue_name.str().c_str() );
+ if ( -1 == sendingClientPid ) {
+ cerr << "END_OF_TEST ERROR_START_SENDER\n";
+ return CANT_FORK_SENDER;
+ }
+ }
+
+
+ int minSleep = 2,
+ maxSleep = 4;
+
+
+ for ( int totalBrokers = n_brokers;
+ totalBrokers < maxBrokers;
+ ++ totalBrokers
+ )
+ {
+ if ( verbosity > 0 )
+ cout << totalBrokers << " brokers have been added to the cluster.\n\n\n";
+
+ // Sleep for a while. -------------------------
+ int sleepyTime = mrand ( minSleep, maxSleep );
+ if ( verbosity > 0 )
+ cout << "Sleeping for " << sleepyTime << " seconds.\n";
+ sleep ( sleepyTime );
+
+ // Kill the oldest broker. --------------------------
+ if ( ! killFrontBroker ( brokers, verbosity ) )
+ {
+ allMyChildren.killEverybody();
+ killAllBrokers ( brokers, 5 );
+ std::cerr << "END_OF_TEST ERROR_BROKER\n";
+ return ERROR_KILLING_BROKER;
+ }
+
+ // Sleep for a while. -------------------------
+ sleepyTime = mrand ( minSleep, maxSleep );
+ if ( verbosity > 1 )
+ cerr << "Sleeping for " << sleepyTime << " seconds.\n";
+ sleep ( sleepyTime );
+
+ // Start a new broker. --------------------------
+ if ( verbosity > 0 )
+ cout << "Starting new broker.\n\n";
+
+ startNewBroker ( brokers,
+ moduleOrDir,
+ clusterName,
+ verbosity,
+ durable );
+
+ if ( verbosity > 1 )
+ printBrokers ( brokers );
+
+ // If all children have exited, quit.
+ int unfinished = allMyChildren.unfinished();
+ if ( ! unfinished ) {
+ killAllBrokers ( brokers, 5 );
+
+ if ( verbosity > 1 )
+ cout << "failoverSoak: all children have exited.\n";
+ int retval = allMyChildren.checkChildren();
+ if ( verbosity > 1 )
+ std::cerr << "failoverSoak: checkChildren: " << retval << endl;
+
+ if ( retval )
+ {
+ std::cerr << "END_OF_TEST ERROR_CLIENT\n";
+ return ERROR_ON_CHILD;
+ }
+ else
+ {
+ std::cerr << "END_OF_TEST SUCCESSFUL\n";
+ return HUNKY_DORY;
+ }
+ }
+
+ // Even if some are still running, if there's an error, quit.
+ if ( allMyChildren.checkChildren() )
+ {
+ if ( verbosity > 0 )
+ cout << "failoverSoak: error on child.\n";
+ allMyChildren.killEverybody();
+ killAllBrokers ( brokers, 5 );
+ std::cerr << "END_OF_TEST ERROR_CLIENT\n";
+ return ERROR_ON_CHILD;
+ }
+
+ if ( verbosity > 1 ) {
+ std::cerr << "------- next kill-broker loop --------\n";
+ allMyChildren.print();
+ }
+ }
+
+ retval = allMyChildren.checkChildren();
+ if ( verbosity > 1 )
+ std::cerr << "failoverSoak: checkChildren: " << retval << endl;
+
+ if ( verbosity > 1 )
+ cout << "failoverSoak: maxBrokers reached.\n";
+
+ allMyChildren.killEverybody();
+ killAllBrokers ( brokers, 5 );
+
+ std::cerr << "END_OF_TEST SUCCESSFUL\n";
+
+ return retval ? ERROR_ON_CHILD : HUNKY_DORY;
+}
+
+
+
diff --git a/cpp/src/tests/fanout_perftest b/cpp/src/tests/fanout_perftest
index a71a748232..d8a7661f49 100755
--- a/cpp/src/tests/fanout_perftest
+++ b/cpp/src/tests/fanout_perftest
@@ -1,2 +1,22 @@
#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
exec `dirname $0`/run_perftest 10000 --mode fanout --npubs 16 --nsubs 16 --size 64
diff --git a/cpp/src/tests/federated_cluster_test b/cpp/src/tests/federated_cluster_test
new file mode 100755
index 0000000000..70bec5e703
--- /dev/null
+++ b/cpp/src/tests/federated_cluster_test
@@ -0,0 +1,152 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Test reliability of the replication feature in the face of link
+# failures:
+srcdir=`dirname $0`
+source ./test_env.sh
+
+trap stop_brokers EXIT
+
+fail() {
+ echo $1
+ exit 1
+}
+
+stop_brokers() {
+ if [[ $BROKER_A ]] ; then
+ ../qpidd --no-module-dir -q --port $BROKER_A
+ unset BROKER_A
+ fi
+ if [[ $NODE_1 ]] ; then
+ ../qpidd --no-module-dir -q --port $NODE_1
+ unset NODE_1
+ fi
+ if [[ $NODE_2 ]] ; then
+ ../qpidd --no-module-dir -q --port $NODE_2
+ unset NODE_2
+ fi
+ if [ -f cluster.ports ]; then
+ rm cluster.ports
+ fi
+}
+
+start_brokers() {
+ #start single node...
+ BROKER_A=`../qpidd --daemon --port 0 --no-data-dir --no-module-dir --auth no --log-enable info+` || fail "BROKER_A failed to start"
+
+ #...and start cluster
+ $srcdir/start_cluster 2 || fail "Could not start cluster"
+ NODE_1=$(head -1 cluster.ports)
+ NODE_2=$(tail -1 cluster.ports)
+ test -n "$NODE_1" || fail "NODE_1 failed to start"
+ test -n "$NODE_2" || fail "NODE_2 failed to start"
+}
+
+setup() {
+ #create exchange on both cluster and single broker
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add exchange direct test-exchange
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$NODE_1" add exchange direct test-exchange
+
+ #create dynamic routes for test exchange
+ $PYTHON_COMMANDS/qpid-route dynamic add "localhost:$NODE_2" "localhost:$BROKER_A" test-exchange
+ $PYTHON_COMMANDS/qpid-route dynamic add "localhost:$BROKER_A" "localhost:$NODE_2" test-exchange
+
+ #create test queue on cluster and bind it to the test exchange
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$NODE_1" add queue test-queue
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$NODE_1" bind test-exchange test-queue to-cluster
+
+ #create test queue on single broker and bind it to the test exchange
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue test-queue
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" bind test-exchange test-queue from-cluster
+}
+
+run_test_pull_to_cluster_two_consumers() {
+ #start consumers on each of the two nodes of the cluster
+ ./receiver --port $NODE_1 --queue test-queue --credit-window 1 > fed1.out.tmp &
+ ./receiver --port $NODE_2 --queue test-queue --credit-window 1 > fed2.out.tmp &
+
+ #send stream of messages to test exchange on single broker
+ for i in `seq 1 1000`; do echo Message $i >> fed.in.tmp; done
+ ./sender --port $BROKER_A --exchange test-exchange --routing-key to-cluster --send-eos 2 < fed.in.tmp
+
+ #combine output of the two consumers, sort it and compare with the expected stream
+ wait
+ sort -g -k 2 fed1.out.tmp fed2.out.tmp > fed.out.tmp
+ diff fed.in.tmp fed.out.tmp || fail "federated link to cluster failed: expectations not met!"
+
+ rm -f fed*.tmp #cleanup
+}
+
+run_test_pull_to_cluster() {
+ #send stream of messages to test exchange on single broker
+ for i in `seq 1 1000`; do echo Message $i >> fed.in.tmp; done
+ ./sender --port $BROKER_A --exchange test-exchange --routing-key to-cluster --send-eos 1 < fed.in.tmp
+
+ #consume from remaining node of the cluster
+ ./receiver --port $NODE_2 --queue test-queue > fed.out.tmp
+
+ #verify all messages are received
+ diff fed.in.tmp fed.out.tmp || fail "federated link to cluster failed: expectations not met!"
+
+ rm -f fed*.tmp #cleanup
+}
+
+run_test_pull_from_cluster() {
+ #start consumer on single broker
+ ./receiver --port $BROKER_A --queue test-queue --credit-window 1 > fed.out.tmp &
+
+ #send stream of messages to test exchange on cluster
+ for i in `seq 1 1000`; do echo Message $i >> fed.in.tmp; done
+ ./sender --port $NODE_2 --exchange test-exchange --routing-key from-cluster --send-eos 1 < fed.in.tmp
+
+ #verify all messages are received
+ wait
+ diff fed.in.tmp fed.out.tmp || fail "federated link from cluster failed: expectations not met!"
+
+ rm -f fed*.tmp #cleanup
+}
+
+
+if test -d ${PYTHON_DIR}; then
+ . $srcdir/ais_check
+
+ rm -f fed*.tmp #cleanup any files left from previous run
+ start_brokers
+ echo "brokers started"
+ setup
+ echo "setup completed"
+ run_test_pull_to_cluster_two_consumers
+ echo "federated link to cluster verified"
+ run_test_pull_from_cluster
+ echo "federated link from cluster verified"
+ if [[ $TEST_NODE_FAILURE ]] ; then
+ #kill first cluster node and retest
+ kill -9 $(../qpidd --check --port $NODE_1) && unset NODE_1
+ echo "killed first cluster node; waiting for links to re-establish themselves..."
+ sleep 5
+ echo "retesting..."
+ run_test_pull_to_cluster
+ echo "federated link to cluster verified"
+ run_test_pull_from_cluster
+ echo "federated link from cluster verified"
+ fi
+fi
diff --git a/cpp/src/tests/federated_cluster_test_with_node_failure b/cpp/src/tests/federated_cluster_test_with_node_failure
new file mode 100755
index 0000000000..f144a676de
--- /dev/null
+++ b/cpp/src/tests/federated_cluster_test_with_node_failure
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+srcdir=`dirname $0`
+TEST_NODE_FAILURE=1 $srcdir/federated_cluster_test
diff --git a/cpp/src/tests/federated_topic_test b/cpp/src/tests/federated_topic_test
index dbb4a2a133..b1063c7e8c 100755
--- a/cpp/src/tests/federated_topic_test
+++ b/cpp/src/tests/federated_topic_test
@@ -1,4 +1,24 @@
#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# Run the topic test on a federated setup
# Clean up old log files
@@ -8,6 +28,7 @@ rm -f subscriber_*.log
SUBSCRIBERS=2
MESSAGES=1000
BATCHES=1
+VERBOSE=1
while getopts "s:m:b:" opt ; do
case $opt in
@@ -22,23 +43,27 @@ while getopts "s:m:b:" opt ; do
done
MY_DIR=$(dirname $(which $0))
-PYTHON_DIR=${MY_DIR}/../../../python
+source ./test_env.sh
trap stop_brokers EXIT
-start_brokers() {
+start_broker() {
${MY_DIR}/../qpidd --daemon --port 0 --no-module-dir --no-data-dir --auth no > qpidd.port
+}
+
+start_brokers() {
+ start_broker
PORT_A=`cat qpidd.port`
- ${MY_DIR}/../qpidd --daemon --port 0 --no-module-dir --no-data-dir --auth no > qpidd.port
+ start_broker
PORT_B=`cat qpidd.port`
- ${MY_DIR}/../qpidd --daemon --port 0 --no-module-dir --no-data-dir --auth no > qpidd.port
+ start_broker
PORT_C=`cat qpidd.port`
}
stop_brokers() {
- ${MY_DIR}/../qpidd -q --port $PORT_A
- ${MY_DIR}/../qpidd -q --port $PORT_B
- ${MY_DIR}/../qpidd -q --port $PORT_C
+ for p in $PORT_A $PORT_B $PORT_C; do
+ $QPIDD_EXEC --no-module-dir -q --port $p
+ done
}
subscribe() {
@@ -62,33 +87,43 @@ setup_routes() {
BROKER_A="localhost:$PORT_A"
BROKER_B="localhost:$PORT_B"
BROKER_C="localhost:$PORT_C"
- export PYTHONPATH=$PYTHON_DIR:$PYTHONPATH
- echo "Establishing routes for topic..."
- $PYTHON_DIR/commands/qpid-route add $BROKER_B $BROKER_A amq.topic topic_control B B
- $PYTHON_DIR/commands/qpid-route add $BROKER_C $BROKER_B amq.topic topic_control C C
- echo "linked A->B->C"
- $PYTHON_DIR/commands/qpid-route add $BROKER_B $BROKER_C amq.topic topic_control B B
- $PYTHON_DIR/commands/qpid-route add $BROKER_A $BROKER_B amq.topic topic_control A A
- echo "linked C->B->A"
-
- echo "Establishing routes for response queue..."
- $PYTHON_DIR/commands/qpid-route add $BROKER_B $BROKER_C amq.direct response B B
- $PYTHON_DIR/commands/qpid-route add $BROKER_A $BROKER_B amq.direct response A A
- echo "linked C->B->A"
+ if (($VERBOSE)); then
+ echo "Establishing routes for topic..."
+ fi
+ $PYTHON_COMMANDS/qpid-route route add $BROKER_B $BROKER_A amq.topic topic_control B B
+ $PYTHON_COMMANDS/qpid-route route add $BROKER_C $BROKER_B amq.topic topic_control C C
+ if (($VERBOSE)); then
+ echo "linked A->B->C"
+ fi
+ $PYTHON_COMMANDS/qpid-route route add $BROKER_B $BROKER_C amq.topic topic_control B B
+ $PYTHON_COMMANDS/qpid-route route add $BROKER_A $BROKER_B amq.topic topic_control A A
+ if (($VERBOSE)); then
+ echo "linked C->B->A"
+ echo "Establishing routes for response queue..."
+ fi
+
+ $PYTHON_COMMANDS/qpid-route route add $BROKER_B $BROKER_C amq.direct response B B
+ $PYTHON_COMMANDS/qpid-route route add $BROKER_A $BROKER_B amq.direct response A A
+ if (($VERBOSE)); then
+ echo "linked C->B->A"
+ for b in $BROKER_A $BROKER_B $BROKER_C; do
+ echo "Routes for $b"
+ $PYTHON_COMMANDS/qpid-route route list $b
+ done
+ fi
}
if test -d ${PYTHON_DIR} ; then
start_brokers
- echo "Running federated topic test against brokers on ports $PORT_A $PORT_B $PORT_C"
-
- setup_routes
+ if (($VERBOSE)); then
+ echo "Running federated topic test against brokers on ports $PORT_A $PORT_B $PORT_C"
+ fi
for ((i=$SUBSCRIBERS ; i--; )); do
subscribe $i &
done
- #sleep to give subscribers time to get initialised
- sleep 1
+ setup_routes
- publish 2>&1 || exit 1
+ publish || exit 1
fi
diff --git a/cpp/src/tests/federation.py b/cpp/src/tests/federation.py
index b92df89839..aa68e8198b 100755
--- a/cpp/src/tests/federation.py
+++ b/cpp/src/tests/federation.py
@@ -19,103 +19,65 @@
#
import sys
-from qpid.testlib import TestBase010, testrunner
-from qpid.management import managementChannel, managementClient
+from qpid.testlib import TestBase010
from qpid.datatypes import Message
from qpid.queue import Empty
from time import sleep
-def add_module(args=sys.argv[1:]):
- for a in args:
- if a.startswith("federation"):
- return False
- return True
-
-def scan_args(name, default=None, args=sys.argv[1:]):
- if (name in args):
- pos = args.index(name)
- return args[pos + 1]
- elif default:
- return default
- else:
- print "Please specify extra argument: %s" % name
- sys.exit(2)
-
-def extract_args(name, args):
- if (name in args):
- pos = args.index(name)
- del args[pos:pos+2]
- else:
- return None
-
-def remote_host():
- return scan_args("--remote-host", "localhost")
-
-def remote_port():
- return int(scan_args("--remote-port"))
+class FederationTests(TestBase010):
-class Helper:
- def __init__(self, parent):
- self.parent = parent
- self.session = parent.conn.session("Helper")
- self.mc = managementClient(self.session.spec)
- self.mch = self.mc.addChannel(self.session)
- self.mc.syncWaitForStable(self.mch)
+ def remote_host(self):
+ return self.defines.get("remote-host", "localhost")
- def shutdown (self):
- self.mc.removeChannel (self.mch)
+ def remote_port(self):
+ return int(self.defines["remote-port"])
- def get_objects(self, type):
- return self.mc.syncGetObjects(self.mch, type)
+ def verify_cleanup(self):
+ attempts = 0
+ total = len(self.qmf.getObjects(_class="bridge")) + len(self.qmf.getObjects(_class="link"))
+ while total > 0:
+ attempts += 1
+ if attempts >= 10:
+ self.fail("Bridges and links didn't clean up")
+ return
+ sleep(1)
+ total = len(self.qmf.getObjects(_class="bridge")) + len(self.qmf.getObjects(_class="link"))
- def get_object(self, type, position = 1, expected = None):
- objects = self.get_objects(type)
- if not expected: expected = position
- self.assertEqual(len(objects), expected)
- return objects[(position - 1)]
+ def test_bridge_create_and_close(self):
+ self.startQmf();
+ qmf = self.qmf
-
- def call_method(self, object, method, args=None):
- res = self.mc.syncCallMethod(self.mch, object.id, object.classKey, method, args)
- self.assertEqual(res.status, 0)
- self.assertEqual(res.statusText, "OK")
- return res
-
- def assertEqual(self, a, b):
- self.parent.assertEqual(a, b)
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(self.remote_host(), self.remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
-class FederationTests(TestBase010):
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "amq.direct", "amq.direct", "my-key", "", "", False, False, False, 0)
+ self.assertEqual(result.status, 0)
- def test_bridge_create_and_close(self):
- mgmt = Helper(self)
- broker = mgmt.get_object("broker")
-
- mgmt.call_method(broker, "connect", {"host":remote_host(), "port":remote_port()})
- link = mgmt.get_object("link")
-
- mgmt.call_method(link, "bridge", {"durable":0, "src":"amq.direct", "dest":"amq.direct", "key":"my-key"})
- bridge = mgmt.get_object("bridge")
-
- mgmt.call_method(bridge, "close")
- mgmt.call_method(link, "close")
+ bridge = qmf.getObjects(_class="bridge")[0]
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
- sleep(6)
- self.assertEqual(len(mgmt.get_objects("bridge")), 0)
- self.assertEqual(len(mgmt.get_objects("link")), 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
- mgmt.shutdown ()
+ self.verify_cleanup()
def test_pull_from_exchange(self):
session = self.session
- mgmt = Helper(self)
- broker = mgmt.get_object("broker")
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(self.remote_host(), self.remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
- mgmt.call_method(broker, "connect", {"host":remote_host(), "port":remote_port()})
- link = mgmt.get_object("link")
-
- mgmt.call_method(link, "bridge", {"durable":0, "src":"amq.direct", "dest":"amq.fanout", "key":"my-key"})
- bridge = mgmt.get_object("bridge")
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "amq.direct", "amq.fanout", "my-key", "", "", False, False, False, 0)
+ self.assertEqual(result.status, 0)
+
+ bridge = qmf.getObjects(_class="bridge")[0]
#setup queue to receive messages from local broker
session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
@@ -125,7 +87,7 @@ class FederationTests(TestBase010):
sleep(6)
#send messages to remote broker and confirm it is routed to local broker
- r_conn = self.connect(host=remote_host(), port=remote_port())
+ r_conn = self.connect(host=self.remote_host(), port=self.remote_port())
r_session = r_conn.session("test_pull_from_exchange")
for i in range(1, 11):
@@ -140,21 +102,64 @@ class FederationTests(TestBase010):
self.fail("Got unexpected message in queue: " + extra.body)
except Empty: None
- mgmt.call_method(bridge, "close")
- mgmt.call_method(link, "close")
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ self.verify_cleanup()
+
+ def test_push_to_exchange(self):
+ session = self.session
+
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(self.remote_host(), self.remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "amq.direct", "amq.fanout", "my-key", "", "", False, True, False, 0)
+ self.assertEqual(result.status, 0)
+
+ bridge = qmf.getObjects(_class="bridge")[0]
+
+ #setup queue to receive messages from remote broker
+ r_conn = self.connect(host=self.remote_host(), port=self.remote_port())
+ r_session = r_conn.session("test_push_to_exchange")
+ r_session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ r_session.exchange_bind(queue="fed1", exchange="amq.fanout")
+ self.subscribe(session=r_session, queue="fed1", destination="f1")
+ queue = r_session.incoming("f1")
sleep(6)
- self.assertEqual(len(mgmt.get_objects("bridge")), 0)
- self.assertEqual(len(mgmt.get_objects("link")), 0)
- mgmt.shutdown()
+ #send messages to local broker and confirm it is routed to remote broker
+ for i in range(1, 11):
+ dp = session.delivery_properties(routing_key="my-key")
+ session.message_transfer(destination="amq.direct", message=Message(dp, "Message %d" % i))
+
+ for i in range(1, 11):
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.body)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ self.verify_cleanup()
def test_pull_from_queue(self):
session = self.session
#setup queue on remote broker and add some messages
- r_conn = self.connect(host=remote_host(), port=remote_port())
+ r_conn = self.connect(host=self.remote_host(), port=self.remote_port())
r_session = r_conn.session("test_pull_from_queue")
- r_session.queue_declare(queue="my-bridge-queue", exclusive=True, auto_delete=True)
+ r_session.queue_declare(queue="my-bridge-queue", auto_delete=True)
for i in range(1, 6):
dp = r_session.delivery_properties(routing_key="my-bridge-queue")
r_session.message_transfer(message=Message(dp, "Message %d" % i))
@@ -165,16 +170,18 @@ class FederationTests(TestBase010):
self.subscribe(queue="fed1", destination="f1")
queue = session.incoming("f1")
- mgmt = Helper(self)
- broker = mgmt.get_object("broker")
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(self.remote_host(), self.remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
- mgmt.call_method(broker, "connect", {"host":remote_host(), "port":remote_port()})
- link = mgmt.get_object("link")
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "my-bridge-queue", "amq.fanout", "my-key", "", "", True, False, False, 1)
+ self.assertEqual(result.status, 0)
- mgmt.call_method(link, "bridge", {"durable":0, "src":"my-bridge-queue", "dest":"amq.fanout",
- "key":"", "tag":"", "excludes":"", "srcIsQueue":1})
- sleep(6)
- bridge = mgmt.get_object("bridge")
+ bridge = qmf.getObjects(_class="bridge")[0]
+ sleep(3)
#add some more messages (i.e. after bridge was created)
for i in range(6, 11):
@@ -192,37 +199,96 @@ class FederationTests(TestBase010):
self.fail("Got unexpected message in queue: " + extra.body)
except Empty: None
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
- mgmt.call_method(bridge, "close")
- mgmt.call_method(link, "close")
- sleep(6)
- self.assertEqual(len(mgmt.get_objects("bridge")), 0)
- self.assertEqual(len(mgmt.get_objects("link")), 0)
+ self.verify_cleanup()
- mgmt.shutdown ()
+ def test_tracing_automatic(self):
+ remoteUrl = "%s:%d" % (self.remote_host(), self.remote_port())
+ self.startQmf()
+ l_broker = self.qmf_broker
+ r_broker = self.qmf.addBroker(remoteUrl)
- def test_tracing(self):
+ l_brokerObj = self.qmf.getObjects(_class="broker", _broker=l_broker)[0]
+ r_brokerObj = self.qmf.getObjects(_class="broker", _broker=r_broker)[0]
+
+ l_res = l_brokerObj.connect(self.remote_host(), self.remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ r_res = r_brokerObj.connect(self.broker.host, self.broker.port, False, "PLAIN", "guest", "guest", "tcp")
+
+ self.assertEqual(l_res.status, 0)
+ self.assertEqual(r_res.status, 0)
+
+ l_link = self.qmf.getObjects(_class="link", _broker=l_broker)[0]
+ r_link = self.qmf.getObjects(_class="link", _broker=r_broker)[0]
+
+ l_res = l_link.bridge(False, "amq.direct", "amq.direct", "key", "", "", False, False, False, 0)
+ r_res = r_link.bridge(False, "amq.direct", "amq.direct", "key", "", "", False, False, False, 0)
+
+ self.assertEqual(l_res.status, 0)
+ self.assertEqual(r_res.status, 0)
+
+ count = 0
+ while l_link.state != "Operational" or r_link.state != "Operational":
+ count += 1
+ if count > 10:
+ self.fail("Fed links didn't become operational after 10 seconds")
+ sleep(1)
+ l_link = self.qmf.getObjects(_class="link", _broker=l_broker)[0]
+ r_link = self.qmf.getObjects(_class="link", _broker=r_broker)[0]
+ sleep(3)
+
+ #setup queue to receive messages from local broker
session = self.session
-
- mgmt = Helper(self)
- broker = mgmt.get_object("broker")
+ session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed1", exchange="amq.direct", binding_key="key")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = session.incoming("f1")
+
+ #setup queue on remote broker and add some messages
+ r_conn = self.connect(host=self.remote_host(), port=self.remote_port())
+ r_session = r_conn.session("test_trace")
+ for i in range(1, 11):
+ dp = r_session.delivery_properties(routing_key="key")
+ r_session.message_transfer(destination="amq.direct", message=Message(dp, "Message %d" % i))
- mgmt.call_method(broker, "connect", {"host":remote_host(), "port":remote_port()})
- link = mgmt.get_object("link")
+ for i in range(1, 11):
+ try:
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.body)
+ except Empty:
+ self.fail("Failed to find expected message containing 'Message %d'" % i)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ def test_tracing(self):
+ session = self.session
- mgmt.call_method(link, "bridge", {"durable":0, "src":"amq.direct", "dest":"amq.fanout", "key":"my-key",
- "tag":"my-bridge-id", "excludes":"exclude-me,also-exclude-me"})
- sleep(6)
- bridge = mgmt.get_object("bridge")
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(self.remote_host(), self.remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "amq.direct", "amq.fanout", "my-key", "my-bridge-id",
+ "exclude-me,also-exclude-me", False, False, False, 0)
+ self.assertEqual(result.status, 0)
+ bridge = qmf.getObjects(_class="bridge")[0]
#setup queue to receive messages from local broker
session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
session.exchange_bind(queue="fed1", exchange="amq.fanout")
self.subscribe(queue="fed1", destination="f1")
queue = session.incoming("f1")
+ sleep(6)
#send messages to remote broker and confirm it is routed to local broker
- r_conn = self.connect(host=remote_host(), port=remote_port())
+ r_conn = self.connect(host=self.remote_host(), port=self.remote_port())
r_session = r_conn.session("test_tracing")
trace = [None, "exclude-me", "a,exclude-me,b", "also-exclude-me,c", "dont-exclude-me"]
@@ -244,13 +310,280 @@ class FederationTests(TestBase010):
self.fail("Got unexpected message in queue: " + extra.body)
except Empty: None
- mgmt.call_method(bridge, "close")
- mgmt.call_method(link, "close")
- sleep(6)
- self.assertEqual(len(mgmt.get_objects("bridge")), 0)
- self.assertEqual(len(mgmt.get_objects("link")), 0)
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ self.verify_cleanup()
+
+ def test_dynamic_fanout(self):
+ session = self.session
+ r_conn = self.connect(host=self.remote_host(), port=self.remote_port())
+ r_session = r_conn.session("test_dynamic_fanout")
+
+ session.exchange_declare(exchange="fed.fanout", type="fanout")
+ r_session.exchange_declare(exchange="fed.fanout", type="fanout")
+
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(self.remote_host(), self.remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "fed.fanout", "fed.fanout", "", "", "", False, False, True, 0)
+ self.assertEqual(result.status, 0)
+ bridge = qmf.getObjects(_class="bridge")[0]
+ sleep(5)
+
+ session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed1", exchange="fed.fanout")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = session.incoming("f1")
+
+ for i in range(1, 11):
+ dp = r_session.delivery_properties()
+ r_session.message_transfer(destination="fed.fanout", message=Message(dp, "Message %d" % i))
+
+ for i in range(1, 11):
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.body)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ self.verify_cleanup()
+
+
+ def test_dynamic_direct(self):
+ session = self.session
+ r_conn = self.connect(host=self.remote_host(), port=self.remote_port())
+ r_session = r_conn.session("test_dynamic_direct")
+
+ session.exchange_declare(exchange="fed.direct", type="direct")
+ r_session.exchange_declare(exchange="fed.direct", type="direct")
+
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(self.remote_host(), self.remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "fed.direct", "fed.direct", "", "", "", False, False, True, 0)
+ self.assertEqual(result.status, 0)
+ bridge = qmf.getObjects(_class="bridge")[0]
+ sleep(5)
+
+ session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed1", exchange="fed.direct", binding_key="fd-key")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = session.incoming("f1")
+
+ for i in range(1, 11):
+ dp = r_session.delivery_properties(routing_key="fd-key")
+ r_session.message_transfer(destination="fed.direct", message=Message(dp, "Message %d" % i))
+
+ for i in range(1, 11):
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.body)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ self.verify_cleanup()
+
+ def test_dynamic_topic(self):
+ session = self.session
+ r_conn = self.connect(host=self.remote_host(), port=self.remote_port())
+ r_session = r_conn.session("test_dynamic_topic")
+
+ session.exchange_declare(exchange="fed.topic", type="topic")
+ r_session.exchange_declare(exchange="fed.topic", type="topic")
+
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(self.remote_host(), self.remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "fed.topic", "fed.topic", "", "", "", False, False, True, 0)
+ self.assertEqual(result.status, 0)
+ bridge = qmf.getObjects(_class="bridge")[0]
+ sleep(5)
+
+ session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed1", exchange="fed.topic", binding_key="ft-key.#")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = session.incoming("f1")
+
+ for i in range(1, 11):
+ dp = r_session.delivery_properties(routing_key="ft-key.one.two")
+ r_session.message_transfer(destination="fed.topic", message=Message(dp, "Message %d" % i))
+
+ for i in range(1, 11):
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.body)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ self.verify_cleanup()
+
+ def test_dynamic_topic_reorigin(self):
+ session = self.session
+ r_conn = self.connect(host=self.remote_host(), port=self.remote_port())
+ r_session = r_conn.session("test_dynamic_topic_reorigin")
+
+ session.exchange_declare(exchange="fed.topic_reorigin", type="topic")
+ r_session.exchange_declare(exchange="fed.topic_reorigin", type="topic")
+
+ session.exchange_declare(exchange="fed.topic_reorigin_2", type="topic")
+ r_session.exchange_declare(exchange="fed.topic_reorigin_2", type="topic")
+
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(self.remote_host(), self.remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ session.queue_declare(queue="fed2", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed2", exchange="fed.topic_reorigin_2", binding_key="ft-key.one.#")
+ self.subscribe(queue="fed2", destination="f2")
+ queue2 = session.incoming("f2")
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "fed.topic_reorigin", "fed.topic_reorigin", "", "", "", False, False, True, 0)
+ self.assertEqual(result.status, 0)
+ result = link.bridge(False, "fed.topic_reorigin_2", "fed.topic_reorigin_2", "", "", "", False, False, True, 0)
+ self.assertEqual(result.status, 0)
+
+ bridge = qmf.getObjects(_class="bridge")[0]
+ bridge2 = qmf.getObjects(_class="bridge")[1]
+ sleep(5)
+
+ session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed1", exchange="fed.topic_reorigin", binding_key="ft-key.#")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = session.incoming("f1")
+
+ for i in range(1, 11):
+ dp = r_session.delivery_properties(routing_key="ft-key.one.two")
+ r_session.message_transfer(destination="fed.topic_reorigin", message=Message(dp, "Message %d" % i))
+
+ for i in range(1, 11):
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.body)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = bridge2.close()
+ self.assertEqual(result.status, 0)
+
+ # extra check: verify we don't leak bridge objects - keep the link
+ # around and verify the bridge count has gone to zero
+
+ attempts = 0
+ bridgeCount = len(qmf.getObjects(_class="bridge"))
+ while bridgeCount > 0:
+ attempts += 1
+ if attempts >= 5:
+ self.fail("Bridges didn't clean up")
+ return
+ sleep(1)
+ bridgeCount = len(qmf.getObjects(_class="bridge"))
+
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ self.verify_cleanup()
+
+ def test_dynamic_direct_reorigin(self):
+ session = self.session
+ r_conn = self.connect(host=self.remote_host(), port=self.remote_port())
+ r_session = r_conn.session("test_dynamic_direct_reorigin")
+
+ session.exchange_declare(exchange="fed.direct_reorigin", type="direct")
+ r_session.exchange_declare(exchange="fed.direct_reorigin", type="direct")
+
+ session.exchange_declare(exchange="fed.direct_reorigin_2", type="direct")
+ r_session.exchange_declare(exchange="fed.direct_reorigin_2", type="direct")
+
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(self.remote_host(), self.remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
- mgmt.shutdown ()
+ session.queue_declare(queue="fed2", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed2", exchange="fed.direct_reorigin_2", binding_key="ft-key.two")
+ self.subscribe(queue="fed2", destination="f2")
+ queue2 = session.incoming("f2")
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "fed.direct_reorigin", "fed.direct_reorigin", "", "", "", False, False, True, 0)
+ self.assertEqual(result.status, 0)
+ result = link.bridge(False, "fed.direct_reorigin_2", "fed.direct_reorigin_2", "", "", "", False, False, True, 0)
+ self.assertEqual(result.status, 0)
+
+ bridge = qmf.getObjects(_class="bridge")[0]
+ bridge2 = qmf.getObjects(_class="bridge")[1]
+ sleep(5)
+
+ session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed1", exchange="fed.direct_reorigin", binding_key="ft-key.one")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = session.incoming("f1")
+
+ for i in range(1, 11):
+ dp = r_session.delivery_properties(routing_key="ft-key.one")
+ r_session.message_transfer(destination="fed.direct_reorigin", message=Message(dp, "Message %d" % i))
+
+ for i in range(1, 11):
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.body)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+
+ # Extra test: don't explicitly close() bridge2. When the link is closed,
+ # it should clean up bridge2 automagically. verify_cleanup() will detect
+ # if bridge2 isn't cleaned up and will fail the test.
+ #
+ #result = bridge2.close()
+ #self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ self.verify_cleanup()
def getProperty(self, msg, name):
for h in msg.headers:
@@ -261,16 +594,4 @@ class FederationTests(TestBase010):
headers = self.getProperty(msg, "application_headers")
if headers:
return headers[name]
- return None
-
-if __name__ == '__main__':
- args = sys.argv[1:]
- #need to remove the extra options from args as test runner doesn't recognise them
- extract_args("--remote-port", args)
- extract_args("--remote-host", args)
-
- if add_module():
- #add module(s) to run to testrunners args
- args.append("federation")
-
- if not testrunner.run(args): sys.exit(1)
+ return None
diff --git a/cpp/src/tests/find_prog.ps1 b/cpp/src/tests/find_prog.ps1
new file mode 100644
index 0000000000..5c482debbf
--- /dev/null
+++ b/cpp/src/tests/find_prog.ps1
@@ -0,0 +1,36 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Locate the subdirectory where the specified program resides; the program
+# must have a directory and a file name, even if the directory is .
+param(
+ [string] $prog # program to look for somewhere below cwd
+)
+
+$dir = Split-Path $prog
+$exe = Split-Path $prog -leaf
+$sub = ""
+$subs = "Debug","Release","MinSizeRel","RelWithDebInfo"
+foreach ($try in $subs) {
+ $prog = "$dir\$try\$exe"
+ if (Test-Path $prog) {
+ $sub = $try
+ break
+ }
+}
diff --git a/cpp/src/tests/header_test.cpp b/cpp/src/tests/header_test.cpp
new file mode 100644
index 0000000000..c36b4f3bc3
--- /dev/null
+++ b/cpp/src/tests/header_test.cpp
@@ -0,0 +1,59 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <iostream>
+
+#include "TestOptions.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/SubscriptionManager.h"
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace std;
+
+int main(int argc, char** argv)
+{
+ TestOptions opts;
+ try {
+ opts.parse(argc, argv);
+ Connection connection;
+ connection.open(opts.con);
+ Session session = connection.newSession();
+ std::string q("header_interop_test_queue");
+ session.queueDeclare(arg::queue=q);
+ double pi = 3.14159265;
+ float e = 2.71828f;
+ Message msg("", q);
+ msg.getMessageProperties().getApplicationHeaders().setDouble("pi", pi);
+ msg.getMessageProperties().getApplicationHeaders().setFloat("e", e);
+ session.messageTransfer(arg::content=msg);
+
+ session.close();
+ connection.close();
+
+ return 0;
+ } catch(const exception& e) {
+ cout << e.what() << endl;
+ }
+ return 1;
+}
diff --git a/cpp/src/tests/header_test.py b/cpp/src/tests/header_test.py
new file mode 100755
index 0000000000..d5a2c16c01
--- /dev/null
+++ b/cpp/src/tests/header_test.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import qpid
+import sys
+import os
+from qpid.util import connect
+from qpid.connection import Connection
+from qpid.datatypes import Message, RangedSet, uuid4
+from qpid.queue import Empty
+from math import fabs
+
+def getApplicationHeaders(msg):
+ for h in msg.headers:
+ if hasattr(h, 'application_headers'): return getattr(h, 'application_headers')
+ return None
+
+# Set parameters for login
+
+host="127.0.0.1"
+port=5672
+user="guest"
+password="guest"
+
+if len(sys.argv) > 1 :
+ host=sys.argv[1]
+if len(sys.argv) > 2 :
+ port=int(sys.argv[2])
+
+# Create a connection.
+socket = connect(host, port)
+connection = Connection (sock=socket)
+connection.start()
+session = connection.session(str(uuid4()))
+
+q = "header_interop_test_queue"
+session.queue_declare(queue=q)
+
+session.message_subscribe(queue=q, destination="received")
+queue = session.incoming("received")
+queue.start()
+
+msg = queue.get(timeout=10)
+pi = 3.14159265
+e = 2.71828
+
+headers = getApplicationHeaders(msg)
+pi_ = headers["pi"]
+e_ = headers["e"]
+session.close(timeout=10)
+
+failed = False
+
+if pi != pi_:
+ print "got incorrect value for pi: ", pi_, " expected:", pi
+ failed = True
+
+if fabs(e - e_) > 0.0001:
+ print "got incorrect value for e: ", e_, " expected:", e
+ failed = True
+
+if failed:
+ sys.exit(1)
+else:
+ print "Correct header values received."
+ sys.exit(0)
+
+
+
diff --git a/cpp/src/tests/interop_runner.cpp b/cpp/src/tests/interop_runner.cpp
deleted file mode 100644
index 8c6e0a6991..0000000000
--- a/cpp/src/tests/interop_runner.cpp
+++ /dev/null
@@ -1,251 +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/Options.h"
-#include "qpid/ptr_map.h"
-#include "qpid/Exception.h"
-#include "qpid/client/Channel.h"
-#include "qpid/client/Connection.h"
-#include "qpid/client/ConnectionOptions.h"
-#include "qpid/client/Exchange.h"
-#include "qpid/client/MessageListener.h"
-#include "qpid/client/Queue.h"
-#include "qpid/sys/Thread.h"
-#include "qpid/sys/Time.h"
-#include <iostream>
-#include <memory>
-#include "BasicP2PTest.h"
-#include "BasicPubSubTest.h"
-#include "TestCase.h"
-#include <boost/ptr_container/ptr_map.hpp>
-
-/**
- * Framework for interop tests.
- *
- * [see http://cwiki.apache.org/confluence/display/qpid/Interop+Testing+Specification for details].
- */
-
-using namespace qpid::client;
-using namespace qpid::sys;
-using qpid::TestCase;
-using qpid::framing::FieldTable;
-using qpid::framing::ReplyTo;
-using namespace std;
-
-class DummyRun : public TestCase
-{
-public:
- DummyRun() {}
- void assign(const string&, FieldTable&, ConnectionOptions&) {}
- void start() {}
- void stop() {}
- void report(qpid::client::Message&) {}
-};
-
-string parse_next_word(const string& input, const string& delims, string::size_type& position);
-
-/**
- */
-class Listener : public MessageListener, private Runnable{
- typedef boost::ptr_map<string, TestCase> TestMap;
-
- Channel& channel;
- ConnectionOptions& options;
- TestMap tests;
- const string name;
- const string topic;
- TestCase* test;
- auto_ptr<Thread> runner;
- ReplyTo reportTo;
- string reportCorrelator;
-
- void shutdown();
- bool invite(const string& name);
- void run();
-
- void sendResponse(Message& response, ReplyTo replyTo);
- void sendResponse(Message& response, Message& request);
- void sendSimpleResponse(const string& type, Message& request);
- void sendReport();
-public:
- Listener(Channel& channel, ConnectionOptions& options);
- void received(Message& msg);
- void bindAndConsume();
- void registerTest(string name, TestCase* test);
-};
-
-struct TestSettings : ConnectionOptions
-{
- bool help;
-
- TestSettings() : help(false)
- {
- addOptions()
- ("help", qpid::optValue(help), "print this usage statement");
- }
-};
-
-int main(int argc, char** argv) {
- try {
- TestSettings options;
- options.parse(argc, argv);
- if (options.help) {
- cout << options;
- } else {
- Connection connection;
- connection.open(options.host, options.port, "guest", "guest", options.virtualhost);
-
- Channel channel;
- connection.openChannel(channel);
-
- Listener listener(channel, options);
- listener.registerTest("TC1_DummyRun", new DummyRun());
- listener.registerTest("TC2_BasicP2P", new qpid::BasicP2PTest());
- listener.registerTest("TC3_BasicPubSub", new qpid::BasicPubSubTest());
-
- listener.bindAndConsume();
-
- channel.run();
- connection.close();
- }
- } catch(const exception& error) {
- cout << error.what() << endl << "Type " << argv[0] << " --help for help" << endl;
- }
-}
-
-Listener::Listener(Channel& _channel, ConnectionOptions& _options) : channel(_channel), options(_options), name(options.clientid), topic("iop.control." + name)
-{}
-
-void Listener::registerTest(string name, TestCase* test)
-{
- tests.insert(name, test);
-}
-
-void Listener::bindAndConsume()
-{
- Queue control(name, true);
- channel.declareQueue(control);
- qpid::framing::FieldTable bindArgs;
- //replace these separate binds with a wildcard once that is supported on java broker
- channel.bind(Exchange::STANDARD_TOPIC_EXCHANGE, control, "iop.control", bindArgs);
- channel.bind(Exchange::STANDARD_TOPIC_EXCHANGE, control, topic, bindArgs);
-
- string tag;
- channel.consume(control, tag, this);
-}
-
-void Listener::sendSimpleResponse(const string& type, Message& request)
-{
- Message response;
- response.getHeaders().setString("CONTROL_TYPE", type);
- response.getHeaders().setString("CLIENT_NAME", name);
- response.getHeaders().setString("CLIENT_PRIVATE_CONTROL_KEY", topic);
- response.getMessageProperties().setCorrelationId(request.getMessageProperties().getCorrelationId());
- sendResponse(response, request);
-}
-
-void Listener::sendResponse(Message& response, Message& request)
-{
- sendResponse(response, request.getMessageProperties().getReplyTo());
-}
-
-void Listener::sendResponse(Message& response, ReplyTo replyTo)
-{
- string exchange = replyTo.getExchange();
- string routingKey = replyTo.getRoutingKey();
- channel.publish(response, exchange, routingKey);
-}
-
-void Listener::received(Message& message)
-{
- string type(message.getHeaders().getString("CONTROL_TYPE"));
-
- if (type == "INVITE") {
- string name(message.getHeaders().getString("TEST_NAME"));
- if (name.empty() || invite(name)) {
- sendSimpleResponse("ENLIST", message);
- } else {
- cout << "Can't take part in '" << name << "'" << endl;
- }
- } else if (type == "ASSIGN_ROLE") {
- test->assign(message.getHeaders().getString("ROLE"), message.getHeaders(), options);
- sendSimpleResponse("ACCEPT_ROLE", message);
- } else if (type == "START") {
- reportTo = message.getMessageProperties().getReplyTo();
- reportCorrelator = message.getMessageProperties().getCorrelationId();
- runner = auto_ptr<Thread>(new Thread(this));
- } else if (type == "STATUS_REQUEST") {
- reportTo = message.getMessageProperties().getReplyTo();
- reportCorrelator = message.getMessageProperties().getCorrelationId();
- test->stop();
- sendReport();
- } else if (type == "TERMINATE") {
- if (test) test->stop();
- shutdown();
- } else {
- cerr <<"ERROR!: Received unknown control message: " << type << endl;
- shutdown();
- }
-}
-
-void Listener::shutdown()
-{
- channel.close();
-}
-
-bool Listener::invite(const string& name)
-{
- TestMap::iterator i = tests.find(name);
- test = (i != tests.end()) ? qpid::ptr_map_ptr(i) : 0;
- return test;
-}
-
-void Listener::run()
-{
- //NB: this method will be called in its own thread
- //start test and when start returns...
- test->start();
- sendReport();
-}
-
-void Listener::sendReport()
-{
- Message report;
- report.getHeaders().setString("CONTROL_TYPE", "REPORT");
- test->report(report);
- report.getMessageProperties().setCorrelationId(reportCorrelator);
- sendResponse(report, reportTo);
-}
-
-string parse_next_word(const string& input, const string& delims, string::size_type& position)
-{
- string::size_type start = input.find_first_not_of(delims, position);
- if (start == string::npos) {
- return "";
- } else {
- string::size_type end = input.find_first_of(delims, start);
- if (end == string::npos) {
- end = input.length();
- }
- position = end;
- return input.substr(start, end - start);
- }
-}
diff --git a/cpp/src/tests/latencytest.cpp b/cpp/src/tests/latencytest.cpp
index e1a6f156a5..a205ef6c7c 100644
--- a/cpp/src/tests/latencytest.cpp
+++ b/cpp/src/tests/latencytest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -21,53 +21,64 @@
#include <algorithm>
+#include <limits>
#include <iostream>
#include <memory>
#include <sstream>
#include <vector>
-#include <unistd.h>
#include "TestOptions.h"
+#include "qpid/sys/Thread.h"
#include "qpid/client/Connection.h"
#include "qpid/client/Message.h"
#include "qpid/client/AsyncSession.h"
#include "qpid/client/SubscriptionManager.h"
+#include "qpid/sys/Time.h"
using namespace qpid;
using namespace qpid::client;
using namespace qpid::sys;
using std::string;
+namespace qpid {
+namespace tests {
+
typedef std::vector<std::string> StringSet;
struct Args : public qpid::TestOptions {
uint size;
uint count;
uint rate;
+ bool sync;
uint reportFrequency;
uint timeLimit;
- uint queues;
+ uint concurrentConnections;
uint prefetch;
uint ack;
bool cumulative;
bool csv;
bool durable;
string base;
+ bool singleConnect;
- Args() : size(256), count(1000), rate(0), reportFrequency(100),
- timeLimit(0), queues(1),
+ Args() : size(256), count(1000), rate(0), reportFrequency(1000),
+ timeLimit(0), concurrentConnections(1),
prefetch(100), ack(0),
- durable(false), base("latency-test")
+ durable(false), base("latency-test"), singleConnect(false)
+
{
- addOptions()
+ addOptions()
("size", optValue(size, "N"), "message size")
- ("queues", optValue(queues, "N"), "number of queues")
+ ("concurrentTests", optValue(concurrentConnections, "N"), "number of concurrent test setups, will create another publisher,\
+ subcriber, queue, and connections")
+ ("single-connection", optValue(singleConnect, "yes|no"), "Use one connection for multiple sessions.")
("count", optValue(count, "N"), "number of messages to send")
("rate", optValue(rate, "N"), "target message rate (causes count to be ignored)")
- ("report-frequency", optValue(reportFrequency, "N"),
+ ("sync", optValue(sync), "send messages synchronously")
+ ("report-frequency", optValue(reportFrequency, "N"),
"number of milliseconds to wait between reports (ignored unless rate specified)")
- ("time-limit", optValue(timeLimit, "N"),
+ ("time-limit", optValue(timeLimit, "N"),
"test duration, in seconds")
("prefetch", optValue(prefetch, "N"), "prefetch count (0 implies no flow control, and no acking)")
("ack", optValue(ack, "N"), "Ack frequency in messages (defaults to half the prefetch value)")
@@ -82,6 +93,7 @@ const std::string chars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
Args opts;
double c_min, c_avg, c_max;
+Connection globalConnection;
uint64_t current_time()
{
@@ -89,7 +101,7 @@ uint64_t current_time()
return t;
}
-struct Stats
+struct Stats
{
Mutex lock;
uint count;
@@ -106,14 +118,15 @@ struct Stats
class Client : public Runnable
{
protected:
- Connection connection;
+ Connection* connection;
+ Connection localConnection;
AsyncSession session;
Thread thread;
string queue;
public:
Client(const string& q);
- virtual ~Client() {}
+ virtual ~Client();
void start();
void join();
@@ -122,7 +135,7 @@ public:
};
class Receiver : public Client, public MessageListener
-{
+{
SubscriptionManager mgr;
uint count;
Stats& stats;
@@ -143,6 +156,8 @@ class Sender : public Client
void sendByRate();
void sendByCount();
Receiver& receiver;
+ const string data;
+
public:
Sender(const string& queue, Receiver& receiver);
void test();
@@ -156,7 +171,7 @@ class Test
Receiver receiver;
Sender sender;
AbsTime begin;
-
+
public:
Test(const string& q) : queue(q), receiver(queue, stats), sender(queue, receiver), begin(now()) {}
void start();
@@ -167,8 +182,14 @@ public:
Client::Client(const string& q) : queue(q)
{
- opts.open(connection);
- session = connection.newSession();
+ if (opts.singleConnect){
+ connection = &globalConnection;
+ if (!globalConnection.isOpen()) opts.open(globalConnection);
+ }else{
+ connection = &localConnection;
+ opts.open(localConnection);
+ }
+ session = connection->newSession();
}
void Client::start()
@@ -185,8 +206,16 @@ void Client::run()
{
try{
test();
+ } catch(const std::exception& e) {
+ std::cout << "Error in receiver: " << e.what() << std::endl;
+ }
+}
+
+Client::~Client()
+{
+ try{
session.close();
- connection.close();
+ connection->close();
} catch(const std::exception& e) {
std::cout << "Error in receiver: " << e.what() << std::endl;
}
@@ -199,15 +228,17 @@ Receiver::Receiver(const string& q, Stats& s) : Client(q), mgr(session), count(0
if (msgCount) {
std::cout << "Warning: found " << msgCount << " msgs on " << queue << ". Purging..." << std::endl;
session.queuePurge(arg::queue=queue);
+ session.sync();
}
+ SubscriptionSettings settings;
if (opts.prefetch) {
- mgr.setAckPolicy(AckPolicy(opts.ack ? opts.ack : (opts.prefetch / 2)));
- mgr.setFlowControl(opts.prefetch, SubscriptionManager::UNLIMITED, true);
+ settings.autoAck = (opts.ack ? opts.ack : (opts.prefetch / 2));
+ settings.flowControl = FlowControl::messageWindow(opts.prefetch);
} else {
- mgr.setAcceptMode(1/*not-required*/);
- mgr.setFlowControl(SubscriptionManager::UNLIMITED, SubscriptionManager::UNLIMITED, false);
+ settings.acceptMode = ACCEPT_MODE_NONE;
+ settings.flowControl = FlowControl::unlimited();
}
- mgr.subscribe(*this, queue);
+ mgr.subscribe(*this, queue, settings);
}
void Receiver::test()
@@ -219,11 +250,9 @@ void Receiver::test()
void Receiver::received(Message& msg)
{
++count;
- uint64_t sentAt = msg.getDeliveryProperties().getTimestamp();
- //uint64_t sentAt = msg.getHeaders().getTimestamp("sent-at");// TODO: add support for uint64_t as a field table type
uint64_t receivedAt = current_time();
+ uint64_t sentAt = msg.getDeliveryProperties().getTimestamp();
- //std::cerr << "Latency: " << (receivedAt - sentAt) << std::endl;
stats.update(((double) (receivedAt - sentAt)) / TIME_MSEC);
if (!opts.rate && count >= opts.count) {
@@ -235,57 +264,70 @@ void Stats::update(double latency)
{
Mutex::ScopedLock l(lock);
count++;
- if (minLatency == 0 || minLatency > latency) minLatency = latency;
- if (maxLatency == 0 || maxLatency < latency) maxLatency = latency;
+ minLatency = std::min(minLatency, latency);
+ maxLatency = std::max(maxLatency, latency);
totalLatency += latency;
}
-Stats::Stats() : count(0), minLatency(0), maxLatency(0), totalLatency(0) {}
+Stats::Stats() : count(0), minLatency(std::numeric_limits<double>::max()), maxLatency(0), totalLatency(0) {}
void Stats::print()
{
static bool already_have_stats = false;
uint value;
- double aux_avg = (totalLatency / count);
if (opts.rate)
value = opts.rate;
else
value = opts.count;
Mutex::ScopedLock l(lock);
+ double aux_avg = (totalLatency / count);
if (!opts.cumulative) {
if (!opts.csv) {
- std::cout << "Latency(ms): min=" << minLatency << ", max=" <<
- maxLatency << ", avg=" << aux_avg;
+ if (count) {
+ std::cout << "Latency(ms): min=" << minLatency << ", max=" <<
+ maxLatency << ", avg=" << aux_avg;
+ } else {
+ std::cout << "Stalled: no samples for interval";
+ }
} else {
- std::cout << value << "," << minLatency << "," << maxLatency <<
+ if (count) {
+ std::cout << value << "," << minLatency << "," << maxLatency <<
"," << aux_avg;
+ } else {
+ std::cout << value << "," << minLatency << "," << maxLatency <<
+ ", Stalled";
+ }
}
} else {
- if (already_have_stats) {
- c_avg = (c_min + aux_avg) / 2;
- if (c_min > minLatency) c_min = minLatency;
- if (c_max < maxLatency) c_max = maxLatency;
+ if (count) {
+ if (already_have_stats) {
+ c_avg = (c_min + aux_avg) / 2;
+ if (c_min > minLatency) c_min = minLatency;
+ if (c_max < maxLatency) c_max = maxLatency;
+ } else {
+ c_avg = aux_avg;
+ c_min = minLatency;
+ c_max = maxLatency;
+ already_have_stats = true;
+ }
+ std::cout << value << "," << c_min << "," << c_max <<
+ "," << c_avg;
} else {
- c_avg = aux_avg;
- c_min = minLatency;
- c_max = maxLatency;
- already_have_stats = true;
+ std::cout << "Stalled: no samples for interval";
}
- std::cout << value << "," << c_min << "," << c_max <<
- "," << c_avg;
}
-
}
void Stats::reset()
{
Mutex::ScopedLock l(lock);
count = 0;
- totalLatency = maxLatency = minLatency = 0;
+ totalLatency = maxLatency = 0;
+ minLatency = std::numeric_limits<double>::max();
}
-Sender::Sender(const string& q, Receiver& receiver) : Client(q), receiver(receiver) {}
+Sender::Sender(const string& q, Receiver& receiver) : Client(q), receiver(receiver), data(generateData(opts.size)) {}
void Sender::test()
{
@@ -295,7 +337,7 @@ void Sender::test()
void Sender::sendByCount()
{
- Message msg(generateData(opts.size), queue);
+ Message msg(data, queue);
if (opts.durable) {
msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
}
@@ -303,45 +345,38 @@ void Sender::sendByCount()
for (uint i = 0; i < opts.count; i++) {
uint64_t sentAt(current_time());
msg.getDeliveryProperties().setTimestamp(sentAt);
- //msg.getHeaders().setTimestamp("sent-at", sentAt);//TODO add support for uint64_t to field tables
async(session).messageTransfer(arg::content=msg, arg::acceptMode=1);
+ if (opts.sync) session.sync();
}
session.sync();
}
void Sender::sendByRate()
{
- Message msg(generateData(opts.size), queue);
+ Message msg(data, queue);
if (opts.durable) {
msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
}
-
- //calculate interval (in micro secs) between messages to achieve desired rate
- uint64_t interval = (1000*1000)/opts.rate;
- uint64_t timeLimit(opts.timeLimit * TIME_SEC);
- uint64_t start(current_time());
-
+ uint64_t interval = TIME_SEC/opts.rate;
+ int64_t timeLimit = opts.timeLimit * TIME_SEC;
+ uint64_t sent = 0, missedRate = 0;
+ AbsTime start = now();
while (true) {
- uint64_t start_msg(current_time());
- msg.getDeliveryProperties().setTimestamp(start_msg);
- //msg.getHeaders().setTimestamp("sent-at", sentAt);//TODO add support for uint64_t to field tables
+ AbsTime sentAt=now();
+ msg.getDeliveryProperties().setTimestamp(Duration(sentAt));
async(session).messageTransfer(arg::content=msg, arg::acceptMode=1);
-
- uint64_t now = current_time();
-
- if (timeLimit != 0 && (now - start) > timeLimit) {
- session.sync();
- receiver.stop();
- break;
- }
-
- uint64_t timeTaken = (now - start_msg) / TIME_USEC;
- if (timeTaken < interval) {
- usleep(interval - timeTaken);
- } else if (timeTaken > interval &&
- !opts.csv && !opts.cumulative) { // Don't be so verbose in this case, we're piping the results to another program
- std::cout << "Could not achieve desired rate! (Took " << timeTaken
- << " microsecs to send message, aiming for " << interval << " microsecs)" << std::endl;
+ if (opts.sync) session.sync();
+ ++sent;
+ AbsTime waitTill(start, sent*interval);
+ Duration delay(sentAt, waitTill);
+ if (delay < 0)
+ ++missedRate;
+ else
+ sys::usleep(delay / TIME_USEC);
+ if (timeLimit != 0 && Duration(start, now()) > timeLimit) {
+ session.sync();
+ receiver.stop();
+ break;
}
}
}
@@ -350,7 +385,7 @@ string Sender::generateData(uint size)
{
if (size < chars.length()) {
return chars.substr(0, size);
- }
+ }
std::string data;
for (uint i = 0; i < (size / chars.length()); i++) {
data += chars;
@@ -360,43 +395,51 @@ string Sender::generateData(uint size)
}
-void Test::start()
-{
- receiver.start();
+void Test::start()
+{
+ receiver.start();
begin = AbsTime(now());
- sender.start();
+ sender.start();
}
-void Test::join()
-{
- sender.join();
- receiver.join();
+void Test::join()
+{
+ sender.join();
+ receiver.join();
AbsTime end = now();
Duration time(begin, end);
double msecs(time / TIME_MSEC);
if (!opts.csv) {
- std::cout << "Sent " << receiver.getCount() << " msgs through " << queue
+ std::cout << "Sent " << receiver.getCount() << " msgs through " << queue
<< " in " << msecs << "ms (" << (receiver.getCount() * 1000 / msecs) << " msgs/s) ";
}
stats.print();
std::cout << std::endl;
}
-void Test::report()
-{
+void Test::report()
+{
stats.print();
std::cout << std::endl;
stats.reset();
}
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char** argv)
{
try {
opts.parse(argc, argv);
if (opts.cumulative)
opts.csv = true;
- boost::ptr_vector<Test> tests(opts.queues);
- for (uint i = 0; i < opts.queues; i++) {
+
+ Connection localConnection;
+ AsyncSession session;
+
+ boost::ptr_vector<Test> tests(opts.concurrentConnections);
+ for (uint i = 0; i < opts.concurrentConnections; i++) {
std::ostringstream out;
out << opts.base << "-" << (i+1);
tests.push_back(new Test(out.str()));
@@ -406,7 +449,7 @@ int main(int argc, char** argv)
}
if (opts.rate && !opts.timeLimit) {
while (true) {
- usleep(opts.reportFrequency * 1000);
+ qpid::sys::usleep(opts.reportFrequency * 1000);
//print latency report:
for (boost::ptr_vector<Test>::iterator i = tests.begin(); i != tests.end(); i++) {
i->report();
diff --git a/cpp/src/tests/logging.cpp b/cpp/src/tests/logging.cpp
index 97bfed2436..5cb563c7d3 100644
--- a/cpp/src/tests/logging.cpp
+++ b/cpp/src/tests/logging.cpp
@@ -19,8 +19,14 @@
#include "test_tools.h"
#include "qpid/log/Logger.h"
#include "qpid/log/Options.h"
+#include "qpid/log/OstreamOutput.h"
#include "qpid/memory.h"
#include "qpid/Options.h"
+#if defined (_WIN32)
+# include "qpid/log/windows/SinkOptions.h"
+#else
+# include "qpid/log/posix/SinkOptions.h"
+#endif
#include <boost/test/floating_point_comparison.hpp>
#include <boost/format.hpp>
@@ -31,6 +37,9 @@
#include <time.h>
+namespace qpid {
+namespace tests {
+
QPID_AUTO_TEST_SUITE(loggingTestSuite)
using namespace std;
@@ -77,6 +86,7 @@ QPID_AUTO_TEST_CASE(testStatementEnabled) {
// Verify that the singleton enables and disables static
// log statements.
Logger& l = Logger::instance();
+ ScopedSuppressLogging ls(l);
l.select(Selector(debug));
static Statement s=QPID_LOG_STATEMENT_INIT(debug);
BOOST_CHECK(!s.enabled);
@@ -99,7 +109,7 @@ struct TestOutput : public Logger::Output {
TestOutput(Logger& l) {
l.output(std::auto_ptr<Logger::Output>(this));
}
-
+
void log(const Statement& s, const string& m) {
msg.push_back(m);
stmt.push_back(s);
@@ -133,7 +143,7 @@ QPID_AUTO_TEST_CASE(testLoggerOutput) {
QPID_AUTO_TEST_CASE(testMacro) {
Logger& l=Logger::instance();
- l.clear();
+ ScopedSuppressLogging ls(l);
l.select(Selector(info));
TestOutput* out=new TestOutput(l);
QPID_LOG(info, "foo");
@@ -152,6 +162,7 @@ QPID_AUTO_TEST_CASE(testMacro) {
QPID_AUTO_TEST_CASE(testLoggerFormat) {
Logger& l = Logger::instance();
+ ScopedSuppressLogging ls(l);
l.select(Selector(critical));
TestOutput* out=new TestOutput(l);
@@ -165,23 +176,19 @@ QPID_AUTO_TEST_CASE(testLoggerFormat) {
l.format(Logger::FUNCTION);
QPID_LOG(critical, "foo");
-
+ BOOST_CHECK_EQUAL(string(BOOST_CURRENT_FUNCTION) + ": foo\n", out->last());
+
l.format(Logger::LEVEL);
QPID_LOG(critical, "foo");
BOOST_CHECK_EQUAL("critical foo\n", out->last());
-
- l.format(~0); // Everything
- QPID_LOG(critical, "foo");
- string re=".* critical -?\\[[0-9a-f]*] "+string(__FILE__)+":\\d+:void .*testLoggerFormat.*\\(\\): foo\n";
- BOOST_CHECK_REGEX(re, out->last());
}
QPID_AUTO_TEST_CASE(testOstreamOutput) {
Logger& l=Logger::instance();
- l.clear();
+ ScopedSuppressLogging ls(l);
l.select(Selector(error));
ostringstream os;
- l.output(os);
+ l.output(qpid::make_auto_ptr<Logger::Output>(new OstreamOutput(os)));
QPID_LOG(error, "foo");
QPID_LOG(error, "bar");
QPID_LOG(error, "baz");
@@ -191,6 +198,7 @@ QPID_AUTO_TEST_CASE(testOstreamOutput) {
#if 0 // This test requires manual intervention. Normally disabled.
QPID_AUTO_TEST_CASE(testSyslogOutput) {
Logger& l=Logger::instance();
+ Logger::StateSaver ls(l);
l.clear();
l.select(Selector(info));
l.syslog("qpid_test");
@@ -223,12 +231,12 @@ clock_t timeLoop(int times, int (*fp)()) {
// Overhead test disabled because it consumes a ton of CPU and takes
// forever under valgrind. Not friendly for regular test runs.
-//
+//
#if 0
QPID_AUTO_TEST_CASE(testOverhead) {
// Ensure that the ratio of CPU time for an incrementing loop
// with and without disabled log statements is in acceptable limits.
- //
+ //
int times=100000000;
clock_t noLog=timeLoop(times, count);
clock_t withLog=timeLoop(times, loggedCount);
@@ -237,9 +245,9 @@ QPID_AUTO_TEST_CASE(testOverhead) {
// NB: in initial tests the ratio was consistently below 1.5,
// 2.5 is reasonable and should avoid spurios failures
// due to machine load.
- //
- BOOST_CHECK_SMALL(ratio, 2.5);
-}
+ //
+ BOOST_CHECK_SMALL(ratio, 2.5);
+}
#endif // 0
Statement statement(
@@ -258,19 +266,26 @@ QPID_AUTO_TEST_CASE(testOptionsParse) {
"--log-enable", "error+:foo",
"--log-enable", "debug:bar",
"--log-enable", "info",
- "--log-output", "x",
- "--log-output", "y",
+ "--log-to-stderr", "no",
+ "--log-to-file", "logout",
"--log-level", "yes",
"--log-source", "1",
"--log-thread", "true",
"--log-function", "YES"
};
qpid::log::Options opts("");
+#ifdef _WIN32
+ qpid::log::windows::SinkOptions sinks("test");
+#else
+ qpid::log::posix::SinkOptions sinks("test");
+#endif
opts.parse(ARGC(argv), const_cast<char**>(argv));
+ sinks = *opts.sinkOptions;
vector<string> expect=list_of("error+:foo")("debug:bar")("info");
BOOST_CHECK_EQUAL(expect, opts.selectors);
- expect=list_of("x")("y");
- BOOST_CHECK_EQUAL(expect, opts.outputs);
+ BOOST_CHECK(!sinks.logToStderr);
+ BOOST_CHECK(!sinks.logToStdout);
+ BOOST_CHECK(sinks.logFile == "logout");
BOOST_CHECK(opts.level);
BOOST_CHECK(opts.source);
BOOST_CHECK(opts.function);
@@ -278,10 +293,17 @@ QPID_AUTO_TEST_CASE(testOptionsParse) {
}
QPID_AUTO_TEST_CASE(testOptionsDefault) {
- Options opts("");
- vector<string> expect=list_of("stderr");
- BOOST_CHECK_EQUAL(expect, opts.outputs);
- expect=list_of("error+");
+ qpid::log::Options opts("");
+#ifdef _WIN32
+ qpid::log::windows::SinkOptions sinks("test");
+#else
+ qpid::log::posix::SinkOptions sinks("test");
+#endif
+ sinks = *opts.sinkOptions;
+ BOOST_CHECK(sinks.logToStderr);
+ BOOST_CHECK(!sinks.logToStdout);
+ BOOST_CHECK(sinks.logFile.length() == 0);
+ vector<string> expect=list_of("notice+");
BOOST_CHECK_EQUAL(expect, opts.selectors);
BOOST_CHECK(opts.time && opts.level);
BOOST_CHECK(!(opts.source || opts.function || opts.thread));
@@ -306,47 +328,16 @@ QPID_AUTO_TEST_CASE(testSelectorFromOptions) {
BOOST_CHECK(s.isEnabled(critical, "foo"));
}
-QPID_AUTO_TEST_CASE(testOptionsFormat) {
- Logger l;
- {
- Options opts("");
- BOOST_CHECK_EQUAL(Logger::TIME|Logger::LEVEL, l.format(opts));
- const char* argv[]={
- 0,
- "--log-time", "no",
- "--log-level", "no",
- "--log-source", "1",
- "--log-thread", "1"
- };
- opts.parse(ARGC(argv), const_cast<char**>(argv));
- BOOST_CHECK_EQUAL(
- Logger::FILE|Logger::LINE|Logger::THREAD, l.format(opts));
- }
- {
- Options opts(""); // Clear.
- const char* argv[]={
- 0,
- "--log-level", "no",
- "--log-thread", "true",
- "--log-function", "YES",
- "--log-time", "YES"
- };
- opts.parse(ARGC(argv), const_cast<char**>(argv));
- BOOST_CHECK_EQUAL(
- Logger::THREAD|Logger::FUNCTION|Logger::TIME,
- l.format(opts));
- }
-}
-
-QPID_AUTO_TEST_CASE(testLoggerConfigure) {
+QPID_AUTO_TEST_CASE(testLoggerStateure) {
Logger& l=Logger::instance();
- l.clear();
- Options opts("test");
+ ScopedSuppressLogging ls(l);
+ qpid::log::Options opts("test");
const char* argv[]={
0,
- "--log-time", "no",
+ "--log-time", "no",
"--log-source", "yes",
- "--log-output", "logging.tmp",
+ "--log-to-stderr", "no",
+ "--log-to-file", "logging.tmp",
"--log-enable", "critical"
};
opts.parse(ARGC(argv), const_cast<char**>(argv));
@@ -363,15 +354,23 @@ QPID_AUTO_TEST_CASE(testLoggerConfigure) {
QPID_AUTO_TEST_CASE(testQuoteNonPrintable) {
Logger& l=Logger::instance();
- l.clear();
- Options opts("test");
- opts.outputs.clear();
- opts.outputs.push_back("logging.tmp");
+ ScopedSuppressLogging ls(l);
+ qpid::log::Options opts("test");
opts.time=false;
+#ifdef _WIN32
+ qpid::log::windows::SinkOptions *sinks =
+ dynamic_cast<qpid::log::windows::SinkOptions *>(opts.sinkOptions.get());
+#else
+ qpid::log::posix::SinkOptions *sinks =
+ dynamic_cast<qpid::log::posix::SinkOptions *>(opts.sinkOptions.get());
+#endif
+ sinks->logToStderr = false;
+ sinks->logFile = "logging.tmp";
l.configure(opts);
+
char s[] = "null\0tab\tspace newline\nret\r\x80\x99\xff";
string str(s, sizeof(s));
- QPID_LOG(critical, str);
+ QPID_LOG(critical, str);
ifstream log("logging.tmp");
string line;
getline(log, line, '\0');
@@ -382,3 +381,5 @@ QPID_AUTO_TEST_CASE(testQuoteNonPrintable) {
}
QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/long_cluster_tests.py b/cpp/src/tests/long_cluster_tests.py
new file mode 100755
index 0000000000..f77837f0c4
--- /dev/null
+++ b/cpp/src/tests/long_cluster_tests.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import os, signal, sys, unittest
+from testlib import TestBaseCluster
+
+class LongClusterTests(TestBaseCluster):
+ """Long/Soak cluster tests with async store ability"""
+
+
+ def test_LongCluster_01_DummyTest(self):
+ """Dummy test - a placeholder for the first of the long/soak python cluster tests"""
+ pass
+
+# Start the test here
+
+if __name__ == '__main__':
+ if os.getenv("STORE_LIB") != None:
+ print "NOTE: Store enabled for the following tests:"
+ if not unittest.main(): sys.exit(1)
+
diff --git a/cpp/src/tests/multiq_perftest b/cpp/src/tests/multiq_perftest
index f6644e740c..10f9edd2a6 100755
--- a/cpp/src/tests/multiq_perftest
+++ b/cpp/src/tests/multiq_perftest
@@ -1,2 +1,22 @@
#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
exec `dirname $0`/run_perftest 10000 --mode shared --qt 16
diff --git a/cpp/src/tests/perfdist b/cpp/src/tests/perfdist
index 816d2d99f6..59548b23f7 100755
--- a/cpp/src/tests/perfdist
+++ b/cpp/src/tests/perfdist
@@ -1,4 +1,25 @@
#!/bin/bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+
#
# Distributed perftest.
# Runs perftest clients on multiple hosts using ssh.
@@ -7,23 +28,24 @@
set -e
usage() {
cat <<EOF
-usage: $0 <perftest-args> -- <client-hosts ...>
-
-Run perftest with clients running on the listed hosts. Clients are
-assigned to hosts publishers first, then subscribers the host list is
-used round-robin if there are more clients than hosts. perftest-args should
-include a --host <brokerhost> flag.
+usage: $0 <perftest-args> -- <client-hosts ...> [ --- <broker hosts...> ]
+Client & broker hosts can also be set in env vars CLIENTS and BROKERS.
-Do not pass preftest action flags: --setup, --control, --publish, --subscribe.
-The script will pass them to the appropriate client processes.
+Run perftest clients on the client hosts against brokers on the broker
+hosts Clients are assigned to client hosts round robin: publishers
+first, then subscribers. If there are multiple brokers (for cluster
+tests) clients connect to them round robin.
-Note all perftest args must come before --.
+Broker hosts can be listed with -b in perftest-args or after ---
+at the end of the arguments.
Error: $*
EOF
exit 1
}
+TESTDIR=${TESTDIR:-$PWD} # Absolute path to test exes on all hosts.
+
collect() { eval $COLLECT=\""\$$COLLECT $*"\"; }
NPUBS=1
NSUBS=1
@@ -33,18 +55,33 @@ while test $# -gt 0; do
--publish|--subscribe|--setup|--control) usage "Don't pass perftest action flags: $1" ;;
--npubs) collect $1 $2; NPUBS=$2; shift 2 ;;
--nsubs) collect $1 $2; NSUBS=$2; shift 2 ;;
- --) COLLECT=HOSTS; shift ;;
+ -s|--summary) collect $1; QUIET=yes; shift 1 ;;
+ -b|--broker) BROKERS="$BROKERS $2"; shift 2;;
+ --) COLLECT=CLIENTARG; shift ;;
+ ---) COLLECT=BROKERARG; shift;;
*) collect $1; shift ;;
esac
done
-if [ -z "$HOSTS" ]; then usage "No hosts listed after --"; fi
-PATH="`dirname $0`:$PATH"
-PERFTEST="`which perftest` $ARGS" || usage "Can't find perftest executable"
-HOSTS=($HOSTS)
-start() { ssh ${HOSTS[i % ${#HOSTS[*]}]} $PERFTEST $*& }
+CLIENTS=${CLIENTARG:-$CLIENTS}
+if [ -z "$CLIENTS" ]; then usage "No client hosts listed after --"; fi
+BROKERS=${BROKERARG:-$BROKERS}
+if [ -z "$BROKERS" ]; then usage "No brokers specified"; fi
+
+PERFTEST="$TESTDIR/perftest $ARGS"
+
+CLIENTS=($CLIENTS)
+BROKERS=($BROKERS)
+start() {
+ CLIENT=${CLIENTS[i % ${#CLIENTS[*]}]}
+ BROKER=${BROKERS[i % ${#BROKERS[*]}]}
+ ARGS="$* --broker $BROKER"
+ cmd="ssh -n $CLIENT $PERFTEST $ARGS"
+ test -z "$QUIET" && echo "Client $i: $cmd"
+ $cmd &
+}
-$PERFTEST --setup
+$PERFTEST --setup -b ${BROKERS[0]}
for (( i=0 ; i < $NPUBS ; ++i)); do start --publish; done
for (( ; i < $NPUBS+$NSUBS ; ++i)); do start --subscribe; done
-$PERFTEST --control
+$PERFTEST --control -b ${BROKERS[0]}
diff --git a/cpp/src/tests/perftest.cpp b/cpp/src/tests/perftest.cpp
index 9096854a6d..88d9fd15cb 100644
--- a/cpp/src/tests/perftest.cpp
+++ b/cpp/src/tests/perftest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -28,6 +28,7 @@
#include "qpid/client/Message.h"
#include "qpid/framing/FieldTable.h"
#include "qpid/sys/Time.h"
+#include "qpid/sys/Thread.h"
#include <boost/lexical_cast.hpp>
#include <boost/bind.hpp>
@@ -38,7 +39,6 @@
#include <sstream>
#include <numeric>
#include <algorithm>
-#include <unistd.h>
#include <math.h>
@@ -49,6 +49,9 @@ using namespace sys;
using boost::lexical_cast;
using boost::bind;
+namespace qpid {
+namespace tests {
+
enum Mode { SHARED, FANOUT, TOPIC };
const char* modeNames[] = { "shared", "fanout", "topic" };
@@ -75,6 +78,7 @@ struct Opts : public TestOptions {
// Queue policy
uint32_t queueMaxCount;
uint64_t queueMaxSize;
+ std::string baseName;
bool queueDurable;
// Publisher
@@ -92,22 +96,26 @@ struct Opts : public TestOptions {
// General
size_t qt;
+ bool singleConnect;
size_t iterations;
Mode mode;
bool summary;
uint32_t intervalSub;
uint32_t intervalPub;
size_t tx;
+ size_t txPub;
+ size_t txSub;
+ bool commitAsync;
static const std::string helpText;
-
+
Opts() :
TestOptions(helpText),
- setup(false), control(false), publish(false), subscribe(false),
+ setup(false), control(false), publish(false), subscribe(false), baseName("perftest"),
pubs(1), count(500000), size(1024), confirm(true), durable(false), uniqueData(false), syncPub(false),
subs(1), ack(0),
- qt(1), iterations(1), mode(SHARED), summary(false),
- intervalSub(0), intervalPub(0), tx(0)
+ qt(1),singleConnect(false), iterations(1), mode(SHARED), summary(false),
+ intervalSub(0), intervalPub(0), tx(0), txPub(0), txSub(0), commitAsync(false)
{
addOptions()
("setup", optValue(setup), "Create shared queues.")
@@ -131,19 +139,25 @@ struct Opts : public TestOptions {
("nsubs", optValue(subs, "N"), "Create N subscribers.")
("sub-ack", optValue(ack, "N"), "N>0: Subscriber acks batches of N.\n"
"N==0: Subscriber uses unconfirmed mode")
-
+
("qt", optValue(qt, "N"), "Create N queues or topics.")
+ ("single-connection", optValue(singleConnect, "yes|no"), "Use one connection for multiple sessions.")
+
("iterations", optValue(iterations, "N"), "Desired number of iterations of the test.")
("summary,s", optValue(summary), "Summary output: pubs/sec subs/sec transfers/sec Mbytes/sec")
("queue-max-count", optValue(queueMaxCount, "N"), "queue policy: count to trigger 'flow to disk'")
("queue-max-size", optValue(queueMaxSize, "N"), "queue policy: accumulated size to trigger 'flow to disk'")
+ ("base-name", optValue(baseName, "NAME"), "base name used for queues or topics")
("queue-durable", optValue(queueDurable, "N"), "Make queue durable (implied if durable set)")
("interval_sub", optValue(intervalSub, "ms"), ">=0 delay between msg consume")
("interval_pub", optValue(intervalPub, "ms"), ">=0 delay between msg publish")
- ("tx", optValue(tx, "N"), "if non-zero, the transaction batch size");
+ ("tx", optValue(tx, "N"), "if non-zero, the transaction batch size for publishing and consuming")
+ ("pub-tx", optValue(txPub, "N"), "if non-zero, the transaction batch size for publishing")
+ ("async-commit", optValue(commitAsync, "yes|no"), "Don't wait for completion of commit")
+ ("sub-tx", optValue(txSub, "N"), "if non-zero, the transaction batch size for consuming");
}
// Computed values
@@ -160,7 +174,7 @@ struct Opts : public TestOptions {
count += subs - (count % subs);
cout << "WARNING: Adjusted --count to " << count
<< " the nearest multiple of --nsubs" << endl;
- }
+ }
totalPubs = pubs*qt;
totalSubs = subs*qt;
subQuota = (pubs*count)/subs;
@@ -180,6 +194,18 @@ struct Opts : public TestOptions {
break;
}
transfers=(totalPubs*count) + (totalSubs*subQuota);
+ if (tx) {
+ if (txPub) {
+ cerr << "WARNING: Using overriden tx value for publishers: " << txPub << std::endl;
+ } else {
+ txPub = tx;
+ }
+ if (txSub) {
+ cerr << "WARNING: Using overriden tx value for subscribers: " << txSub << std::endl;
+ } else {
+ txSub = tx;
+ }
+ }
}
};
@@ -196,25 +222,46 @@ const std::string Opts::helpText=
"Note the <other options> must be identical for all processes.\n";
Opts opts;
+Connection globalConnection;
+
+std::string fqn(const std::string& name)
+{
+ ostringstream fqn;
+ fqn << opts.baseName << "_" << name;
+ return fqn.str();
+}
struct Client : public Runnable {
- Connection connection;
+ Connection* connection;
+ Connection localConnection;
AsyncSession session;
Thread thread;
Client() {
- opts.open(connection);
- session = connection.newSession();
+ if (opts.singleConnect){
+ connection = &globalConnection;
+ if (!globalConnection.isOpen()) opts.open(globalConnection);
+ }else{
+ connection = &localConnection;
+ opts.open(localConnection);
+ }
+ session = connection->newSession();
}
~Client() {
- session.close();
- connection.close();
+ try {
+ if (connection->isOpen()) {
+ session.close();
+ connection->close();
+ }
+ } catch (const std::exception& e) {
+ std::cerr << "Error in shutdown: " << e.what() << std::endl;
+ }
}
};
struct Setup : public Client {
-
+
void queueInit(string name, bool durable=false, const framing::FieldTable& settings=framing::FieldTable()) {
session.queueDeclare(arg::queue=name, arg::durable=durable, arg::arguments=settings);
session.queuePurge(arg::queue=name);
@@ -222,18 +269,19 @@ struct Setup : public Client {
}
void run() {
- queueInit("pub_start");
- queueInit("pub_done");
- queueInit("sub_ready");
- queueInit("sub_done");
+ queueInit(fqn("pub_start"));
+ queueInit(fqn("pub_done"));
+ queueInit(fqn("sub_ready"));
+ queueInit(fqn("sub_done"));
+ if (opts.iterations > 1) queueInit(fqn("sub_iteration"));
if (opts.mode==SHARED) {
framing::FieldTable settings;//queue policy settings
settings.setInt("qpid.max_count", opts.queueMaxCount);
settings.setInt("qpid.max_size", opts.queueMaxSize);
for (size_t i = 0; i < opts.qt; ++i) {
ostringstream qname;
- qname << "perftest" << i;
- queueInit(qname.str(), opts.durable || opts.queueDurable, settings);
+ qname << opts.baseName << i;
+ queueInit(qname.str(), opts.durable || opts.queueDurable, settings);
}
}
}
@@ -258,7 +306,7 @@ class Stats {
public:
Stats() : sum(0) {}
-
+
// Functor to collect rates.
void operator()(const string& data) {
try {
@@ -269,7 +317,7 @@ class Stats {
throw Exception("Bad report: "+data);
}
}
-
+
double mean() const {
return sum/values.size();
}
@@ -286,7 +334,7 @@ class Stats {
}
return sqrt(ssq/(values.size()-1));
}
-
+
ostream& print(ostream& out) {
ostream_iterator<double> o(out, "\n");
copy(values.begin(), values.end(), o);
@@ -296,11 +344,11 @@ class Stats {
return out << endl;
}
};
-
+
// Manage control queues, collect and print reports.
struct Controller : public Client {
-
+
SubscriptionManager subs;
Controller() : subs(session) {}
@@ -309,7 +357,7 @@ struct Controller : public Client {
void process(size_t n, string queue,
boost::function<void (const string&)> msgFn)
{
- if (!opts.summary)
+ if (!opts.summary)
cout << "Processing " << n << " messages from "
<< queue << " " << flush;
LocalQueue lq;
@@ -325,8 +373,8 @@ struct Controller : public Client {
void process(size_t n, LocalQueue lq, string queue,
boost::function<void (const string&)> msgFn)
{
- session.messageFlow(queue, 0, n);
- if (!opts.summary)
+ session.messageFlow(queue, 0, n);
+ if (!opts.summary)
cout << "Processing " << n << " messages from "
<< queue << " " << flush;
for (size_t i = 0; i < n; ++i) {
@@ -341,20 +389,20 @@ struct Controller : public Client {
cout << "Sending " << data << " " << n << " times to " << queue
<< endl;
Message msg(data, queue);
- for (size_t i = 0; i < n; ++i)
+ for (size_t i = 0; i < n; ++i)
session.messageTransfer(arg::content=msg, arg::acceptMode=1);
}
void run() { // Controller
try {
// Wait for subscribers to be ready.
- process(opts.totalSubs, "sub_ready", bind(expect, _1, "ready"));
+ process(opts.totalSubs, fqn("sub_ready"), bind(expect, _1, "ready"));
LocalQueue pubDone;
LocalQueue subDone;
subs.setFlowControl(0, SubscriptionManager::UNLIMITED, false);
- subs.subscribe(pubDone, "pub_done");
- subs.subscribe(subDone, "sub_done");
+ subs.subscribe(pubDone, fqn("pub_done"));
+ subs.subscribe(subDone, fqn("sub_done"));
double txrateTotal(0);
double mbytesTotal(0);
@@ -363,15 +411,18 @@ struct Controller : public Client {
for (size_t j = 0; j < opts.iterations; ++j) {
AbsTime start=now();
- send(opts.totalPubs, "pub_start", "start"); // Start publishers
+ send(opts.totalPubs, fqn("pub_start"), "start"); // Start publishers
+ if (j) {
+ send(opts.totalPubs, fqn("sub_iteration"), "next"); // Start subscribers on next iteration
+ }
Stats pubRates;
Stats subRates;
- process(opts.totalPubs, pubDone, "pub_done", boost::ref(pubRates));
- process(opts.totalSubs, subDone, "sub_done", boost::ref(subRates));
+ process(opts.totalPubs, pubDone, fqn("pub_done"), boost::ref(pubRates));
+ process(opts.totalSubs, subDone, fqn("sub_done"), boost::ref(subRates));
- AbsTime end=now();
+ AbsTime end=now();
double time=secs(start, end);
double txrate=opts.transfers/time;
@@ -411,7 +462,6 @@ struct Controller : public Client {
}
catch (const std::exception& e) {
cout << "Controller exception: " << e.what() << endl;
- exit(1);
}
}
};
@@ -422,12 +472,12 @@ struct PublishThread : public Client {
string routingKey;
PublishThread() {};
-
+
PublishThread(string key, string dest=string()) {
destination=dest;
routingKey=key;
}
-
+
void run() { // Publisher
try {
string data;
@@ -445,7 +495,7 @@ struct PublishThread : public Client {
}
} else {
size_t msgSize=max(opts.size, sizeof(size_t));
- data = string(msgSize, 'X');
+ data = string(msgSize, 'X');
}
Message msg(data, routingKey);
@@ -453,19 +503,21 @@ struct PublishThread : public Client {
msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
- if (opts.tx) sync(session).txSelect();
+ if (opts.txPub){
+ session.txSelect();
+ }
SubscriptionManager subs(session);
LocalQueue lq;
- subs.setFlowControl(1, SubscriptionManager::UNLIMITED, true);
- subs.subscribe(lq, "pub_start");
-
+ subs.setFlowControl(1, SubscriptionManager::UNLIMITED, true);
+ subs.subscribe(lq, fqn("pub_start"));
+
for (size_t j = 0; j < opts.iterations; ++j) {
expect(lq.pop().getData(), "start");
AbsTime start=now();
for (size_t i=0; i<opts.count; i++) {
// Stamp the iteration into the message data, avoid
// any heap allocation.
- const_cast<std::string&>(msg.getData()).replace(offset, sizeof(size_t),
+ const_cast<std::string&>(msg.getData()).replace(offset, sizeof(size_t),
reinterpret_cast<const char*>(&i), sizeof(size_t));
if (opts.syncPub) {
sync(session).messageTransfer(
@@ -478,23 +530,31 @@ struct PublishThread : public Client {
arg::content=msg,
arg::acceptMode=1);
}
- if (opts.tx && ((i+1) % opts.tx == 0)) sync(session).txCommit();
- if (opts.intervalPub) ::usleep(opts.intervalPub*1000);
+ if (opts.txPub && ((i+1) % opts.txPub == 0)){
+ if (opts.commitAsync){
+ session.txCommit();
+ } else {
+ sync(session).txCommit();
+ }
+ }
+ if (opts.intervalPub)
+ qpid::sys::usleep(opts.intervalPub*1000);
}
if (opts.confirm) session.sync();
AbsTime end=now();
double time=secs(start,end);
-
+
// Send result to controller.
- Message report(lexical_cast<string>(opts.count/time), "pub_done");
+ Message report(lexical_cast<string>(opts.count/time), fqn("pub_done"));
session.messageTransfer(arg::content=report, arg::acceptMode=1);
- if (opts.tx) sync(session).txCommit();
+ if (opts.txPub){
+ sync(session).txCommit();
+ }
}
session.close();
}
catch (const std::exception& e) {
cout << "PublishThread exception: " << e.what() << endl;
- exit(1);
}
}
};
@@ -504,7 +564,7 @@ struct SubscribeThread : public Client {
string queue;
SubscribeThread() {}
-
+
SubscribeThread(string q) { queue = q; }
SubscribeThread(string key, string ex) {
@@ -529,31 +589,48 @@ struct SubscribeThread : public Client {
}
void run() { // Subscribe
- try {
- if (opts.tx) sync(session).txSelect();
+ try {
+ if (opts.txSub) sync(session).txSelect();
SubscriptionManager subs(session);
- LocalQueue lq(AckPolicy(opts.tx ? opts.tx : opts.ack));
- subs.setAcceptMode(opts.tx || opts.ack ? 0 : 1);
- subs.setFlowControl(opts.subQuota, SubscriptionManager::UNLIMITED,
- false);
- subs.subscribe(lq, queue);
+ SubscriptionSettings settings;
+ settings.autoAck = opts.txSub ? opts.txSub : opts.ack;
+ settings.acceptMode = (opts.txSub || opts.ack ? ACCEPT_MODE_EXPLICIT : ACCEPT_MODE_NONE);
+ settings.flowControl = FlowControl::messageCredit(opts.subQuota);
+ LocalQueue lq;
+ Subscription subscription = subs.subscribe(lq, queue, settings);
// Notify controller we are ready.
- session.messageTransfer(arg::content=Message("ready", "sub_ready"), arg::acceptMode=1);
- if (opts.tx) sync(session).txCommit();
-
+ session.messageTransfer(arg::content=Message("ready", fqn("sub_ready")), arg::acceptMode=1);
+ if (opts.txSub) {
+ if (opts.commitAsync) session.txCommit();
+ else sync(session).txCommit();
+ }
+
+ LocalQueue iterationControl;
+ if (opts.iterations > 1) {
+ subs.subscribe(iterationControl, fqn("sub_iteration"), SubscriptionSettings(FlowControl::messageCredit(0)));
+ }
+
for (size_t j = 0; j < opts.iterations; ++j) {
if (j > 0) {
- //need to allocate some more credit
- session.messageFlow(queue, 0, opts.subQuota);
+ //need to wait here until all subs are done
+ session.messageFlow(fqn("sub_iteration"), 0, 1);
+ iterationControl.pop();
+
+ //need to allocate some more credit for subscription
+ session.messageFlow(queue, 0, opts.subQuota);
}
Message msg;
AbsTime start=now();
size_t expect=0;
for (size_t i = 0; i < opts.subQuota; ++i) {
msg=lq.pop();
- if (opts.tx && ((i+1) % opts.tx == 0)) sync(session).txCommit();
- if (opts.intervalSub) ::usleep(opts.intervalSub*1000);
- // TODO aconway 2007-11-23: check message order for.
+ if (opts.txSub && ((i+1) % opts.txSub == 0)) {
+ if (opts.commitAsync) session.txCommit();
+ else sync(session).txCommit();
+ }
+ if (opts.intervalSub)
+ qpid::sys::usleep(opts.intervalSub*1000);
+ // TODO aconway 2007-11-23: check message order for.
// multiple publishers. Need an array of counters,
// one per publisher and a publisher ID in the
// message. Careful not to introduce a lot of overhead
@@ -568,29 +645,37 @@ struct SubscribeThread : public Client {
expect = n+1;
}
}
- if (opts.tx || opts.ack)
- lq.getAckPolicy().ackOutstanding(session); // Cumulative ack for final batch.
- if (opts.tx)
- sync(session).txCommit();
+ if (opts.txSub || opts.ack)
+ subscription.accept(subscription.getUnaccepted());
+ if (opts.txSub) {
+ if (opts.commitAsync) session.txCommit();
+ else sync(session).txCommit();
+ }
AbsTime end=now();
// Report to publisher.
Message result(lexical_cast<string>(opts.subQuota/secs(start,end)),
- "sub_done");
+ fqn("sub_done"));
session.messageTransfer(arg::content=result, arg::acceptMode=1);
- if (opts.tx) sync(session).txCommit();
+ if (opts.txSub) sync(session).txCommit();
}
session.close();
}
catch (const std::exception& e) {
cout << "SubscribeThread exception: " << e.what() << endl;
- exit(1);
}
}
};
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char** argv) {
-
+ int exitCode = 0;
+ boost::ptr_vector<Client> subs(opts.subs);
+ boost::ptr_vector<Client> pubs(opts.pubs);
+
try {
opts.parse(argc, argv);
@@ -600,7 +685,7 @@ int main(int argc, char** argv) {
case TOPIC: exchange="amq.topic"; break;
case SHARED: break;
}
-
+
bool singleProcess=
(!opts.setup && !opts.control && !opts.publish && !opts.subscribe);
if (singleProcess)
@@ -608,13 +693,10 @@ int main(int argc, char** argv) {
if (opts.setup) Setup().run(); // Set up queues
- boost::ptr_vector<Client> subs(opts.subs);
- boost::ptr_vector<Client> pubs(opts.pubs);
-
// Start pubs/subs for each queue/topic.
for (size_t i = 0; i < opts.qt; ++i) {
ostringstream key;
- key << "perftest" << i; // Queue or topic name.
+ key << opts.baseName << i; // Queue or topic name.
if (opts.publish) {
size_t n = singleProcess ? opts.pubs : 1;
for (size_t j = 0; j < n; ++j) {
@@ -635,29 +717,25 @@ int main(int argc, char** argv) {
}
if (opts.control) Controller().run();
-
-
- // Wait for started threads.
- if (opts.publish) {
- for (boost::ptr_vector<Client>::iterator i=pubs.begin();
- i != pubs.end();
- ++i)
- i->thread.join();
- }
-
-
- if (opts.subscribe) {
- for (boost::ptr_vector<Client>::iterator i=subs.begin();
- i != subs.end();
- ++i)
- i->thread.join();
- }
- return 0;
}
catch (const std::exception& e) {
- cout << endl << e.what() << endl;
+ cout << endl << e.what() << endl;
+ exitCode = 1;
}
- return 1;
-}
-
+ // Wait for started threads.
+ if (opts.publish) {
+ for (boost::ptr_vector<Client>::iterator i=pubs.begin();
+ i != pubs.end();
+ ++i)
+ i->thread.join();
+ }
+
+ if (opts.subscribe) {
+ for (boost::ptr_vector<Client>::iterator i=subs.begin();
+ i != subs.end();
+ ++i)
+ i->thread.join();
+ }
+ return exitCode;
+}
diff --git a/cpp/src/tests/policy.acl b/cpp/src/tests/policy.acl
new file mode 100644
index 0000000000..ef46026555
--- /dev/null
+++ b/cpp/src/tests/policy.acl
@@ -0,0 +1 @@
+acl allow all all
diff --git a/cpp/src/tests/publish.cpp b/cpp/src/tests/publish.cpp
index b78f3fdf6d..3f456e7588 100644
--- a/cpp/src/tests/publish.cpp
+++ b/cpp/src/tests/publish.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -34,9 +34,12 @@
using namespace qpid;
using namespace qpid::client;
using namespace qpid::sys;
-using std::string;
+using namespace std;
-typedef std::vector<std::string> StringSet;
+namespace qpid {
+namespace tests {
+
+typedef vector<string> StringSet;
struct Args : public qpid::TestOptions {
uint size;
@@ -44,64 +47,80 @@ struct Args : public qpid::TestOptions {
bool durable;
string destination;
string routingKey;
+ bool summary;
+ bool id;
- Args() : size(256), count(1000), durable(true)
- {
+ Args() : size(256), count(1000), durable(true), routingKey("publish-consume"), summary(false), id(false) {
addOptions()
("size", optValue(size, "N"), "message size")
("count", optValue(count, "N"), "number of messages to publish")
("durable", optValue(durable, "yes|no"), "use durable messages")
("destination", optValue(destination, "<exchange name>"), "destination to publish to")
- ("routing-key", optValue(routingKey, "<key>"), "routing key to publish with");
+ ("routing-key", optValue(routingKey, "<key>"), "routing key to publish with")
+ ("summary,s", optValue(summary), "Output only the rate.")
+ ("id", optValue(id), "Add unique correlation ID");
}
};
Args opts;
-struct Client
+struct Client
{
Connection connection;
AsyncSession session;
- Client()
+ Client()
{
opts.open(connection);
session = connection.newSession();
}
- std::string id(uint i)
- {
- std::stringstream s;
- s << "msg" << i;
- return s.str();
+ // Cheap hex calculation, avoid expensive ostrstream and string
+ // creation to generate correlation ids in message loop.
+ char hex(char i) { return i<10 ? '0'+i : 'A'+i-10; }
+ void hex(char i, string& s) {
+ s[0]=hex(i>>24); s[1]=hex(i>>16); s[2]=hex(i>>8); s[3]=i;
}
void publish()
{
+ AbsTime begin=now();
Message msg(string(opts.size, 'X'), opts.routingKey);
+ string correlationId = "0000";
if (opts.durable)
msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
-
+
for (uint i = 0; i < opts.count; i++) {
- msg.getMessageProperties().setCorrelationId(id(i + 1));
+ if (opts.id) {
+ hex(i+1, correlationId);
+ msg.getMessageProperties().setCorrelationId(correlationId);
+ }
session.messageTransfer(arg::destination=opts.destination,
arg::content=msg,
arg::acceptMode=1);
}
session.sync();
+ AbsTime end=now();
+ double secs(double(Duration(begin,end))/TIME_SEC);
+ if (opts.summary) cout << opts.count/secs << endl;
+ else cout << "Time: " << secs << "s Rate: " << opts.count/secs << endl;
}
- ~Client()
+ ~Client()
{
try{
session.close();
connection.close();
- } catch(const std::exception& e) {
- std::cout << e.what() << std::endl;
+ } catch(const exception& e) {
+ cout << e.what() << endl;
}
}
};
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char** argv)
{
try {
@@ -109,8 +128,8 @@ int main(int argc, char** argv)
Client client;
client.publish();
return 0;
- } catch(const std::exception& e) {
- std::cout << e.what() << std::endl;
+ } catch(const exception& e) {
+ cout << e.what() << endl;
}
return 1;
}
diff --git a/cpp/src/tests/python_tests b/cpp/src/tests/python_tests
index 896692e41e..51c808a6c9 100755
--- a/cpp/src/tests/python_tests
+++ b/cpp/src/tests/python_tests
@@ -1,19 +1,29 @@
#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# Run the python tests.
+source ./test_env.sh
+test -d $PYTHON_DIR || { echo "Skipping python tests, no python dir."; exit 0; }
QPID_PORT=${QPID_PORT:-5672}
PYTHON_TESTS=${PYTHON_TESTS:-$*}
-MY_DIR=`dirname \`which $0\``
-QPID_PYTHON_DIR=${QPID_PYTHON_DIR:-${MY_DIR}/../../../python}
-
-run() {
- SPEC=$1
- FAILING=$2
- ./run-tests --skip-self-test -v -s $SPEC -I $FAILING -b localhost:$QPID_PORT $PYTHON_TESTS || { echo "FAIL python tests for $SPEC"; exit 1; }
-}
+FAILING=${FAILING:-/dev/null}
-if test -d ${QPID_PYTHON_DIR} ; then
- cd ${QPID_PYTHON_DIR}
- run 0-10-errata cpp_failing_0-10.txt
-else
- echo "WARNING: No python tests. $QPID_PYTHON_DIR not found."
-fi
+python $QPID_PYTHON_TEST -b localhost:$QPID_PORT -I $FAILING $PYTHON_TESTS || exit 1
diff --git a/cpp/src/tests/python_tests.ps1 b/cpp/src/tests/python_tests.ps1
new file mode 100644
index 0000000000..ab456a1557
--- /dev/null
+++ b/cpp/src/tests/python_tests.ps1
@@ -0,0 +1,42 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Run the python tests; intended to be run by run_test.ps1 which sets up
+# QPID_PORT
+$srcdir = Split-Path $myInvocation.InvocationName
+$PYTHON_DIR = "$srcdir\..\..\..\python"
+if (!(Test-Path $PYTHON_DIR -pathType Container)) {
+ "Skipping python tests as python libs not found"
+ exit 1
+}
+
+if (Test-Path env:FAILING) {
+ $fails = "-I $env:FAILING"
+}
+if (Test-Path env:PYTHON_TESTS) {
+ $tests = "$env:PYTHON_TESTS"
+}
+else {
+ $tests = "$args"
+}
+
+#cd $PYTHON_DIR
+$env:PYTHONPATH="$PYTHON_DIR;$env:PYTHONPATH"
+python $PYTHON_DIR/qpid-python-test -b localhost:$env:QPID_PORT $fails $tests
+exit $LASTEXITCODE
diff --git a/cpp/src/tests/qpid_ping.cpp b/cpp/src/tests/qpid_ping.cpp
new file mode 100644
index 0000000000..b046fdf54b
--- /dev/null
+++ b/cpp/src/tests/qpid_ping.cpp
@@ -0,0 +1,123 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+
+ */
+
+#include "TestOptions.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/sys/Time.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/framing/Uuid.h"
+#include <string>
+#include <iostream>
+
+using namespace std;
+using namespace qpid::sys;
+using namespace qpid::framing;
+using namespace qpid::client;
+using namespace qpid;
+
+namespace qpid {
+namespace tests {
+
+struct PingOptions : public qpid::TestOptions {
+ int timeout; // Timeout in seconds.
+ bool quiet; // No output
+ PingOptions() : timeout(1), quiet(false) {
+ addOptions()
+ ("timeout,t", optValue(timeout, "SECONDS"), "Max time to wait.")
+ ("quiet,q", optValue(quiet), "Don't print anything to stderr/stdout.");
+ }
+};
+
+PingOptions opts;
+
+class Ping : public Runnable {
+ Connection connection;
+ Thread thread;
+ Monitor lock;
+ enum { WAITING, SUCCESS, ERROR } status;
+
+ public:
+ Ping() : status(WAITING) {}
+
+ void run() {
+ try {
+ opts.open(connection);
+ if (!opts.quiet) cout << "Opened connection." << endl;
+ AsyncSession s = connection.newSession();
+ string qname(Uuid(true).str());
+ s.queueDeclare(arg::queue=qname,arg::autoDelete=true,arg::exclusive=true);
+ s.messageTransfer(arg::content=Message("hello", qname));
+ if (!opts.quiet) cout << "Sent message." << endl;
+ SubscriptionManager subs(s);
+ subs.get(qname);
+ if (!opts.quiet) cout << "Received message." << endl;
+ s.sync();
+ s.close();
+ connection.close();
+ Mutex::ScopedLock l(lock);
+ status = SUCCESS;
+ lock.notifyAll();
+ } catch (const exception& e) {
+ if (!opts.quiet)
+ cerr << "Unexpected exception: " << e.what() << endl;
+ Mutex::ScopedLock l(lock);
+ status = ERROR;
+ lock.notifyAll();
+ }
+ }
+
+ void start() { thread=Thread(this); }
+
+ bool wait() {
+ Mutex::ScopedLock l(lock);
+ AbsTime deadline(now(), opts.timeout*TIME_SEC);
+ while (status == WAITING && lock.wait(deadline))
+ ;
+ if (status == WAITING && !opts.quiet)
+ cerr << "Timed out after " << opts.timeout << " seconds." << endl;
+ if (status != WAITING) thread.join();
+ return status == SUCCESS;
+ }
+};
+
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
+int main(int argc, char** argv) {
+ try {
+ opts.parse(argc, argv);
+ Ping ping;
+ ping.start();
+ if (!ping.wait()) exit(1);
+ if (!opts.quiet) cout << "Success!" << endl;
+ return 0;
+ } catch (const exception& e) {
+ if (!opts.quiet)
+ cerr << "Unexpected exception: " << e.what() << endl;
+ return 1;
+ }
+}
diff --git a/cpp/src/tests/qpid_stream.cpp b/cpp/src/tests/qpid_stream.cpp
new file mode 100644
index 0000000000..8195bf390e
--- /dev/null
+++ b/cpp/src/tests/qpid_stream.cpp
@@ -0,0 +1,170 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/Connection.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/Receiver.h>
+#include <qpid/messaging/Sender.h>
+#include <qpid/messaging/Session.h>
+#include <qpid/sys/Runnable.h>
+#include <qpid/sys/Thread.h>
+#include <qpid/sys/Time.h>
+#include <qpid/Options.h>
+#include <iostream>
+#include <string>
+
+using namespace qpid::messaging;
+using namespace qpid::sys;
+
+namespace qpid {
+namespace tests {
+
+struct Args : public qpid::Options
+{
+ std::string url;
+ std::string address;
+ uint rate;
+ bool durable;
+
+ Args() : url("amqp:tcp:127.0.0.1:5672"), address("test-queue"), rate(1000), durable(false)
+ {
+ addOptions()
+ ("url", qpid::optValue(url, "URL"), "Url to connect to.")
+ ("address", qpid::optValue(address, "ADDRESS"), "Address to stream messages through.")
+ ("rate", qpid::optValue(rate, "msgs/sec"), "Rate at which to stream messages.")
+ ("durable", qpid::optValue(durable, "true|false"), "Mark messages as durable.");
+ }
+};
+
+Args opts;
+
+const std::string TIMESTAMP = "ts";
+
+uint64_t timestamp(const AbsTime& time)
+{
+ Duration t(time);
+ return t;
+}
+
+struct Client : Runnable
+{
+ virtual ~Client() {}
+ virtual void doWork(Session&) = 0;
+
+ void run()
+ {
+ try {
+ Connection connection = Connection::open(opts.url);
+ Session session = connection.newSession();
+ doWork(session);
+ session.close();
+ connection.close();
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ }
+
+ Thread thread;
+
+ void start() { thread = Thread(this); }
+ void join() { thread.join(); }
+};
+
+struct Publish : Client
+{
+ void doWork(Session& session)
+ {
+ Sender sender = session.createSender(opts.address);
+ Message msg;
+ uint64_t interval = TIME_SEC / opts.rate;
+ uint64_t sent = 0, missedRate = 0;
+ AbsTime start = now();
+ while (true) {
+ AbsTime sentAt = now();
+ msg.getHeaders()[TIMESTAMP] = timestamp(sentAt);
+ sender.send(msg);
+ ++sent;
+ AbsTime waitTill(start, sent*interval);
+ Duration delay(sentAt, waitTill);
+ if (delay < 0) {
+ ++missedRate;
+ } else {
+ qpid::sys::usleep(delay / TIME_USEC);
+ }
+ }
+ }
+};
+
+struct Consume : Client
+{
+ void doWork(Session& session)
+ {
+ Message msg;
+ uint64_t received = 0;
+ double minLatency = std::numeric_limits<double>::max();
+ double maxLatency = 0;
+ double totalLatency = 0;
+ Receiver receiver = session.createReceiver(opts.address);
+ while (receiver.fetch(msg)) {
+ session.acknowledge();//TODO: add batching option
+ ++received;
+ //calculate latency
+ uint64_t receivedAt = timestamp(now());
+ uint64_t sentAt = msg.getHeaders()[TIMESTAMP].asUint64();
+ double latency = ((double) (receivedAt - sentAt)) / TIME_MSEC;
+
+ //update avg, min & max
+ minLatency = std::min(minLatency, latency);
+ maxLatency = std::max(maxLatency, latency);
+ totalLatency += latency;
+
+ if (received % opts.rate == 0) {
+ std::cout << "count=" << received
+ << ", avg=" << (totalLatency/received)
+ << ", min=" << minLatency
+ << ", max=" << maxLatency << std::endl;
+ }
+ }
+ }
+};
+
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
+int main(int argc, char** argv)
+{
+ try {
+ opts.parse(argc, argv);
+ Publish publish;
+ Consume consume;
+ publish.start();
+ consume.start();
+ consume.join();
+ publish.join();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/cpp/src/tests/qrsh.cpp b/cpp/src/tests/qrsh.cpp
new file mode 100644
index 0000000000..0cb52b6b05
--- /dev/null
+++ b/cpp/src/tests/qrsh.cpp
@@ -0,0 +1,169 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/client/Connection.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/AsyncSession.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/MessageListener.h>
+#include <qpid/client/SubscriptionManager.h>
+
+#include <stdio.h>
+#include <cstdlib>
+#include <iostream>
+
+#include <sstream>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using namespace std;
+
+namespace qpid {
+namespace tests {
+
+class ResponseListener : public MessageListener
+{
+ public :
+
+ int exitCode;
+
+ ResponseListener ( SubscriptionManager & subscriptions )
+ : exitCode(-1),
+ subscriptions ( subscriptions )
+ {
+ }
+
+ virtual void
+ received ( Message & message )
+ {
+ char first_word[1000];
+ sscanf ( message.getData().c_str(), "%s", first_word );
+
+ if ( ! strcmp ( first_word, "wait_response" ) )
+ {
+ // If we receive a message here, parse out the exit code.
+ sscanf ( message.getData().c_str(), "%*s%d", & exitCode );
+ subscriptions.cancel(message.getDestination());
+ }
+ else
+ if ( ! strcmp ( first_word, "get_response" ) )
+ {
+ // The remainder of the message is the file we requested.
+ fprintf ( stdout,
+ "%s",
+ message.getData().c_str() + strlen("get_response" )
+ );
+ subscriptions.cancel(message.getDestination());
+ }
+ }
+
+
+ private :
+
+ SubscriptionManager & subscriptions;
+};
+
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
+/*
+ * argv[1] host
+ * argv[2] port
+ * argv[3] server name
+ * argv[4] command name
+ * argv[5..N] args to the command
+ */
+int
+main ( int argc, char ** argv )
+{
+ const char* host = argv[1];
+ int port = atoi(argv[2]);
+
+
+ Connection connection;
+
+ try
+ {
+ connection.open ( host, port );
+ Session session = connection.newSession ( );
+
+ // Make a queue and bind it to fanout.
+ string myQueue = session.getId().getName();
+
+ session.queueDeclare ( arg::queue=myQueue,
+ arg::exclusive=true,
+ arg::autoDelete=true
+ );
+
+ session.exchangeBind ( arg::exchange="amq.fanout",
+ arg::queue=myQueue,
+ arg::bindingKey="my-key"
+ );
+
+ // Get ready to listen for the wait-response.
+ // or maybe a get-response.
+ // ( Although this may not be one of those types
+ // of command, get ready anyway.
+ SubscriptionManager subscriptions ( session );
+ ResponseListener responseListener ( subscriptions );
+ subscriptions.subscribe ( responseListener, myQueue );
+
+ bool response_command = false;
+ if(! strcmp("exec_wait", argv[4] ))
+ response_command = true;
+ else
+ if(! strcmp("exited", argv[4] ))
+ response_command = true;
+ else
+ if(! strcmp("get", argv[4] ))
+ response_command = true;
+
+ // Send the payload message.
+ // Skip "qrsh host_name port"
+ Message message;
+ stringstream ss;
+ for ( int i = 3; i < argc; ++ i )
+ ss << argv[i] << ' ';
+
+ message.setData ( ss.str() );
+
+ session.messageTransfer(arg::content=message,
+ arg::destination="amq.fanout");
+
+ if ( response_command )
+ subscriptions.run();
+
+ session.close();
+ connection.close();
+ return responseListener.exitCode;
+ }
+ catch ( exception const & e)
+ {
+ cerr << e.what() << endl;
+ }
+
+ return 1;
+}
+
+
+
diff --git a/cpp/src/tests/qrsh_run.cpp b/cpp/src/tests/qrsh_run.cpp
new file mode 100644
index 0000000000..cfdd0cef80
--- /dev/null
+++ b/cpp/src/tests/qrsh_run.cpp
@@ -0,0 +1,321 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <iostream>
+#include <sstream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+
+using namespace std;
+
+
+
+int
+main ( int argc, char ** argv )
+{
+ int exit_code = -1;
+ int fd[2];
+ int my_pid = getpid();
+ int child_pid;
+
+ pipe(fd);
+
+ char const * root_dir = argv[1]; // This arg is prepended by qrsh_server.
+ char const * child_name = argv[2]; // This arg comes from qrsh.
+ char const * child_path = argv[3]; // This arg comes from qrsh.
+
+ // This is the problem..
+ fprintf ( stderr, "MDEBUG qrsh_run: root_dir: |%s|\n", root_dir );
+ fprintf ( stderr, "MDEBUG qrsh_run: child_name: |%s|\n", child_name );
+ fprintf ( stderr, "MDEBUG qrsh_run: child_path: |%s|\n", child_path );
+
+ /*
+ * A named child is one for whom we will create a directory and
+ * store information. There are some magic names that are not
+ * real symbolic names -- but are instead the names of actions.
+ */
+
+ bool named_child = true;
+
+ if ( ! strcmp ( child_name, "exec" ) )
+ named_child = false;
+ else
+ if ( ! strcmp ( child_name, "exec_wait" ) )
+ named_child = false;
+ else
+ if ( ! strcmp ( child_name, "exited" ) )
+ named_child = false;
+ else
+ named_child = true;
+
+ stringstream child_dir_name;
+
+ if ( named_child )
+ {
+ child_dir_name << root_dir
+ << '/'
+ << child_name;
+
+ /*
+ * Make the child directory before forking, or there is
+ * a race in which the child might be trying to make its
+ * stdout and stderr files while we are tring to make
+ * the directory.
+ */
+ if ( -1 == mkdir ( child_dir_name.str().c_str(), 0777 ) )
+ {
+ fprintf ( stderr,
+ "qrsh_run error: Can't mkdir |%s|\n",
+ child_dir_name.str().c_str()
+ );
+ exit ( 1 );
+ }
+
+ }
+ else
+ /*
+ * If this is an 'exited' command that means we are
+ * waiting for a pre-existing child.
+ */
+ if ( ! strcmp ( child_name, "exited" ) )
+ {
+ int wait_pid = atoi(child_path);
+
+ // Find the child's symbolic name.
+ stringstream pid_to_name_file_name;
+ pid_to_name_file_name << root_dir
+ << '/'
+ << wait_pid;
+ FILE * fp = fopen ( pid_to_name_file_name.str().c_str(), "r" );
+ if (! fp)
+ {
+ fprintf ( stderr,
+ "qrsh_run %d error: Can't open pid2name file |%s|.\n",
+ my_pid,
+ pid_to_name_file_name.str().c_str()
+ );
+ exit(1);
+ }
+ char symbolic_name[1000];
+ strcpy ( symbolic_name, "qrsh_no_name" );
+ fscanf ( fp, "%s", symbolic_name );
+ fclose ( fp );
+
+ // Make the name of the child's exit code file.
+ stringstream exit_code_file_name;
+ exit_code_file_name << root_dir
+ << '/'
+ << symbolic_name
+ << "/exit_code";
+
+ struct stat stat_buf;
+ int file_does_not_exist = stat ( exit_code_file_name.str().c_str(), & stat_buf );
+
+ /*
+ * If the result of stat is zero, the file exists, which means that
+ * the command has exited. The question we are being asked here is
+ * "has it exited yet?"
+ */
+ if ( ! file_does_not_exist )
+ return 1;
+ else
+ if ( errno == ENOENT )
+ return 0;
+ else
+ return 2 ;
+ }
+
+
+ // We are not waiting on a pre-wxiting child: we have a
+ // new child to create.
+
+ child_pid = fork();
+
+ if ( child_pid == 0 )
+ {
+ // This code is executed in the child process.
+
+ // If it's a *named* child, then redirect its stdout and stderr.
+ if ( named_child )
+ {
+ stringstream stdout_path,
+ stderr_path;
+
+ // Redirect the child's stdout. -----------------
+ stdout_path << root_dir
+ << '/'
+ << child_name
+ << '/'
+ << "stdout";
+
+ int redirected_stdout = open ( stdout_path.str().c_str(),
+ O_WRONLY|O_CREAT|O_TRUNC,
+ S_IRWXU|S_IRWXG|S_IRWXO
+ );
+ if ( redirected_stdout < 0 )
+ {
+ perror ( "qrsh_run: error opening redirected_stdout: " );
+ fprintf ( stderr, "stdout path: |%s|\n", stdout_path.str().c_str() );
+ exit ( 1 );
+ }
+ if ( -1 == dup2 ( redirected_stdout, 1 ) )
+ {
+ perror ( "qrsh_run: dup2 (stdout) error: " );
+ exit(1);
+ }
+
+ // Redirect the child's stderr. -----------------
+ stderr_path << root_dir
+ << '/'
+ << child_name
+ << '/'
+ << "stderr";
+
+ int redirected_stderr = open ( stderr_path.str().c_str(),
+ O_WRONLY|O_CREAT|O_TRUNC,
+ S_IRWXU|S_IRWXG|S_IRWXO
+ );
+ if ( redirected_stderr < 0 )
+ {
+ perror ( "qrsh_run: error opening redirected_stderr: " );
+ fprintf ( stderr, "stderr path: |%s|\n", stderr_path.str().c_str() );
+ exit ( 1 );
+ }
+ if(-1 == dup2 ( redirected_stderr, 2 ) )
+ {
+ perror ( "qrsh_run: dup2 (stderr) error: " );
+ exit(1);
+ }
+ }
+
+ fprintf ( stderr, "MDEBUG ------------- qrsh_run argv -------------\n" );
+ for ( int i = 0; i < argc; ++ i )
+ fprintf ( stderr, "MDEBUG argv[%d] : |%s|\n", i, argv[i] );
+
+ execv ( child_path, argv + 2 );
+ perror ( "qrsh_run: execv error: " );
+ fprintf ( stderr, "on path |%s|\n", child_path );
+ exit ( 1 );
+ }
+ else
+ {
+ // This code is executed in the parent process.
+
+ if ( named_child )
+ {
+ // Write the name-to-pid mapping.
+ stringstream pid_file_name;
+ pid_file_name << child_dir_name.str()
+ << "/pid";
+
+ FILE * fp;
+ if ( ! (fp = fopen ( pid_file_name.str().c_str(), "w") ) )
+ {
+ fprintf ( stderr,
+ "qrsh_run %d error: Can't open file |%s|\n",
+ my_pid,
+ pid_file_name.str().c_str()
+ );
+ exit(1);
+ }
+ fprintf ( fp, "%d\n", child_pid );
+ fclose ( fp );
+
+
+ // Write the pid-to-name mapping.
+ stringstream name_to_pid_file_name;
+ name_to_pid_file_name << root_dir
+ << '/'
+ << child_pid;
+ if(! (fp = fopen ( name_to_pid_file_name.str().c_str(), "w")))
+ {
+ fprintf ( stderr,
+ "qrsh_run %d error: Can't open file |%s|\n",
+ my_pid,
+ name_to_pid_file_name.str().c_str()
+ );
+ exit(1);
+ }
+ fprintf ( fp, "%s\n", child_name );
+ fclose(fp);
+ }
+
+ pid_t awaited_pid;
+ while ( 0 == (awaited_pid = waitpid ( child_pid, & exit_code, WNOHANG)) )
+ {
+ fprintf ( stderr,
+ "qrsh_run %d info: parent: waiting for child %d...\n",
+ my_pid,
+ child_pid
+ );
+ sleep(1);
+ }
+
+ if ( -1 == awaited_pid )
+ {
+ fprintf ( stderr, "qrsh_run error awaiting child!\n" );
+ exit ( 1 );
+ }
+
+ /*
+ * Write the exit code.
+ */
+ exit_code >>= 8;
+
+ if ( named_child )
+ {
+ if ( child_pid == awaited_pid )
+ {
+ stringstream exit_code_file_name;
+ exit_code_file_name << child_dir_name.str()
+ << "/exit_code";
+
+ FILE * fp;
+ if ( ! (fp = fopen ( exit_code_file_name.str().c_str(), "w") ) )
+ {
+ fprintf ( stderr,
+ "qrsh_run error: Can't open file |%s|\n",
+ exit_code_file_name.str().c_str()
+ );
+ exit(1);
+ }
+ fprintf ( fp, "%d\n", exit_code );
+ fclose ( fp );
+ }
+ }
+ }
+
+ fprintf ( stderr, "MDEBUG qrsh_run returning exit code %d\n", exit_code );
+ return exit_code;
+}
+
+
+
+
diff --git a/cpp/src/tests/qrsh_server.cpp b/cpp/src/tests/qrsh_server.cpp
new file mode 100644
index 0000000000..f1163ba479
--- /dev/null
+++ b/cpp/src/tests/qrsh_server.cpp
@@ -0,0 +1,1065 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <cstdlib>
+#include <iostream>
+#include <map>
+#include <dirent.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <qpid/client/Connection.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/AsyncSession.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/MessageListener.h>
+#include <qpid/client/SubscriptionManager.h>
+
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace std;
+
+
+namespace qpid {
+namespace tests {
+
+int
+mrand ( int max_desired_val )
+{
+ double zero_to_one = (double) rand() / (double) RAND_MAX;
+ return (int) (zero_to_one * (double) max_desired_val);
+}
+
+
+
+char *
+file2str ( char const * file_name )
+{
+ FILE * fp = fopen ( file_name, "r" );
+ if(! fp)
+ {
+ fprintf ( stderr, "file2str error: can't open file |%s|.\n", file_name );
+ return 0;
+ }
+
+ fseek ( fp, 0, SEEK_END );
+ size_t file_len = (size_t) ftell ( fp );
+ rewind ( fp );
+ char * content = (char *) malloc ( file_len + 1 );
+
+ if ( ! content )
+ {
+ fprintf ( stderr,
+ "file2str error: can't malloc %d bytes.\n",
+ (int)file_len
+ );
+ return 0;
+ }
+
+ size_t items_read = fread ( content, file_len, 1, fp );
+
+ if ( 1 != items_read )
+ {
+ fprintf ( stderr, "file2str error: read failed.\n" );
+ free ( content );
+ return 0;
+ }
+
+ fclose ( fp );
+ content[file_len] = 0;
+
+ return content;
+}
+
+
+
+
+
+class QrshServer : public MessageListener
+{
+ public:
+
+ QrshServer ( SubscriptionManager & subscriptions,
+ char const * name,
+ char const * qrsh_run_path,
+ char const * host,
+ int port
+ );
+
+ virtual void received ( Message & message);
+
+
+ private:
+
+ set<string> all_server_names;
+
+ stringstream data_dir;
+
+ SubscriptionManager & subscriptions;
+
+ // Is this message addressed to me?
+ bool myMessage ( Message const & message );
+
+ /* ----------------------------------------------
+ * Special Commands
+ * These are commands that the qrsh_server executes
+ * directly, rather than through a child process
+ * instance of qrsh_run.
+ */
+ void runCommand ( Message const & message );
+ void execute ( Message const & message );
+ void wait ( Message const & message );
+ void exited ( Message const & message );
+ void get ( Message const & message );
+ void rememberIntroduction ( Message const & message );
+ void getStraw ( Message const & message );
+ void addAlias ( Message const & message );
+
+ void start ( );
+ void sayHello ( );
+ void sayName ( );
+ // end Special Commands ------------------------
+
+
+ void saveCommand ( Message const & message );
+
+ void send ( string const & content );
+
+ void drawStraws ( );
+ void getNames ( );
+ void runSavedCommand ( );
+
+ char ** getArgs ( char const * s );
+ bool isProcessName ( char const * s );
+ int string_countWords ( char const * s );
+ char const * skipWord ( char const * s );
+
+
+ void string_replaceAll ( string & str,
+ string & target,
+ string & replacement
+ );
+
+
+ string name,
+ qrsh_run_path,
+ host;
+
+ vector<string *> aliases;
+
+ int port;
+
+ map < char *, int > abstract_name_map;
+
+ set < string > myFellowBrokers;
+
+ bool saidHello;
+
+ Message savedCommand;
+
+ vector < int > straws;
+ int myStraw;
+
+};
+
+
+
+QrshServer::QrshServer ( SubscriptionManager & subs,
+ char const * name,
+ char const * qrsh_run_path,
+ char const * host,
+ int port
+ )
+ : subscriptions ( subs ),
+ name ( name ),
+ qrsh_run_path ( qrsh_run_path ),
+ host ( host ),
+ port ( port ),
+ saidHello ( false ),
+ myStraw ( 0 )
+{
+ data_dir << "/tmp/qrsh_"
+ << getpid();
+
+ if(mkdir ( data_dir.str().c_str(), 0777 ) )
+ {
+ fprintf ( stderr,
+ "QrshServer::QrshServer error: can't mkdir |%s|\n",
+ data_dir.str().c_str()
+ );
+ exit ( 1 );
+ }
+}
+
+
+
+void
+QrshServer::saveCommand ( Message const & message )
+{
+ savedCommand = message;
+}
+
+
+
+void
+QrshServer::runSavedCommand ( )
+{
+ runCommand ( savedCommand );
+}
+
+
+
+void
+QrshServer::start ( )
+{
+ stringstream announcement_data;
+ announcement_data << "hello_my_name_is "
+ << name;
+
+ send ( announcement_data.str() );
+
+ saidHello = true;
+}
+
+
+
+
+void
+QrshServer::send ( string const & content )
+{
+ try
+ {
+ Message message;
+ message.setData ( content );
+
+ Connection connection;
+ connection.open ( host, port );
+ Session session = connection.newSession ( );
+ session.messageTransfer ( arg::content = message,
+ arg::destination = "amq.fanout"
+ );
+ session.close();
+ connection.close();
+ }
+ catch ( exception const & e )
+ {
+ fprintf ( stderr, "QrshServer::send error: |%s|\n", e.what() );
+ }
+}
+
+
+
+
+void
+QrshServer::sayHello ( )
+{
+ if ( saidHello )
+ return;
+
+ stringstream ss;
+
+ ss << "hello_my_name_is "
+ << name;
+
+ send ( ss.str() );
+ saidHello = true;
+}
+
+
+
+void
+QrshServer::sayName ( )
+{
+ fprintf ( stderr, "My name is: |%s|\n", name.c_str() );
+}
+
+
+
+
+void
+QrshServer::drawStraws ( )
+{
+ myStraw = mrand ( 1000000000 );
+ stringstream ss;
+ ss << "straw "
+ << name
+ << ' '
+ << myStraw;
+ send ( ss.str() );
+}
+
+
+
+void
+QrshServer::getStraw ( Message const & message )
+{
+ int straw;
+
+ char brokerName[1000];
+ sscanf ( message.getData().c_str(), "%*s%s", brokerName );
+
+ if ( ! strcmp ( brokerName, name.c_str() ) )
+ return;
+
+ sscanf ( message.getData().c_str(), "%*s%*s%d", & straw );
+ straws.push_back ( straw );
+
+ bool i_win = true;
+ int ties = 0;
+
+ if ( straws.size() >= myFellowBrokers.size() )
+ {
+ // All votes are in! Let's see if I win!
+ for ( unsigned int i = 0; i < straws.size(); ++ i )
+ {
+ if ( straws[i] == myStraw )
+ ++ ties;
+ else
+ if ( straws[i] > myStraw )
+ {
+ i_win = false;
+ break;
+ }
+ }
+
+ if ( i_win && (ties <= 0) )
+ {
+ myStraw = 0;
+ straws.clear();
+ runSavedCommand ( );
+ }
+ else
+ if ( i_win && (ties > 0) )
+ {
+ fprintf ( stderr, "MDEBUG oh no! drawStraws error: server %s tied with straw %d!\n", name.c_str(), straw );
+ }
+ }
+}
+
+
+
+
+/*
+ * "APB" command (all-points-bullitens (commands that are not addressed
+ * specifically to any server)) are handled directly, here.
+ * Because if I return simply "true", the normal command processing code
+ * will misinterpret the command.
+ */
+bool
+QrshServer::myMessage ( Message const & message )
+{
+ int const maxlen = 100;
+ char head[maxlen];
+ char first_word [ maxlen + 1 ];
+ strncpy ( head, message.getData().c_str(), maxlen );
+ sscanf ( head, "%s", first_word );
+
+ if ( ! strcmp ( name.c_str(), first_word ) )
+ {
+ return true;
+ }
+ else
+ {
+ // Is the given name one of my aliases?
+ char possibleAlias[1000];
+ if(1 == sscanf ( message.getData().c_str(), "%s", possibleAlias ))
+ {
+ for ( unsigned int i = 0; i < aliases.size(); ++ i )
+ {
+
+ if ( ! strcmp ( possibleAlias, aliases[i]->c_str() ))
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ if ( ! strcmp ( first_word, "hello_my_name_is" ) )
+ {
+ rememberIntroduction ( message );
+ sayHello ( );
+ return false;
+ }
+ else
+ if ( ! strcmp ( first_word, "straw" ) )
+ {
+ getStraw ( message );
+ return false;
+ }
+ else
+ if ( ! strcmp ( first_word, "all" ) )
+ {
+ return true;
+ }
+ else
+ if ( ! strcmp ( first_word, "any" ) )
+ {
+ straws.clear();
+ usleep ( 200000 );
+ saveCommand ( message );
+ drawStraws ( );
+ return false;
+ }
+ else
+ return false;
+}
+
+
+
+
+void
+QrshServer::rememberIntroduction ( Message const & message )
+{
+ char brokerName [ 1000 ];
+ sscanf ( message.getData().c_str(), "%*s%s", brokerName );
+
+ if ( strcmp ( brokerName, name.c_str() ) )
+ myFellowBrokers.insert ( string ( brokerName ) );
+}
+
+
+
+
+void
+QrshServer::addAlias ( Message const & message )
+{
+ char alias[1000];
+ sscanf ( message.getData().c_str(), "%*s%*s%s", alias );
+ aliases.push_back ( new string(alias) );
+}
+
+
+
+
+void
+QrshServer::getNames ( )
+{
+ abstract_name_map.clear();
+
+ DIR * dir = opendir ( data_dir.str().c_str() );
+
+ if ( ! dir )
+ {
+ fprintf ( stderr,
+ "QrshServer::getNames error: could not open dir |%s|.\n",
+ data_dir.str().c_str()
+ );
+ return;
+ }
+
+ struct dirent * file;
+ while ( (file = readdir ( dir ) ) )
+ {
+ if ( '.' != file->d_name[0] )
+ {
+ stringstream pid_file_name;
+ pid_file_name << data_dir.str()
+ << '/'
+ << file->d_name
+ << "/pid";
+
+ int pid = 0;
+ FILE * fp;
+ if ( (fp = fopen ( pid_file_name.str().c_str(), "r" ) ) )
+ {
+ fscanf ( fp, "%d", & pid );
+ fclose ( fp );
+ abstract_name_map.insert(pair<char*, int>(strdup(file->d_name), pid));
+ }
+ else
+ {
+ /*
+ * Fail silently. The non-existence of this file
+ * is not necessarily an error.
+ */
+ }
+ }
+ }
+ closedir ( dir );
+}
+
+
+
+void
+QrshServer::string_replaceAll ( string & str,
+ string & target,
+ string & replacement
+ )
+{
+ int target_size = target.size();
+ int found_pos = 0;
+
+ while ( 0 <= (found_pos = str.find ( target ) ) )
+ str.replace ( found_pos, target_size, replacement );
+}
+
+
+
+
+bool
+QrshServer::isProcessName ( char const * str )
+{
+ getNames();
+ map<char *, int>::iterator it;
+ for ( it = abstract_name_map.begin(); it != abstract_name_map.end(); ++ it )
+ {
+ if ( ! strcmp ( str, it->first ) )
+ return true;
+ }
+
+ return false;
+}
+
+
+
+
+
+int
+QrshServer::string_countWords ( char const * s1 )
+{
+ int count = 0;
+ char const * s2 = s1 + 1;
+
+ if ( ! isspace(* s1) )
+ {
+ ++ count;
+ }
+
+ for ( ; * s2; ++ s1, ++ s2 )
+ {
+ // count space-to-word transitions.
+ if ( isspace(*s1) && (! isspace(*s2)) )
+ ++ count;
+ }
+
+ return count;
+}
+
+
+
+
+void
+QrshServer::execute ( Message const & message )
+{
+ // First, gather all the symbolic names we know.
+ getNames();
+
+ // Now make a copy of the command, that I can alter.
+ string command ( message.getData() );
+
+
+ // Replace each occurrence of every abstract name with its pid.
+ char pid_str[100];
+ map<char *, int>::iterator it;
+ for ( it = abstract_name_map.begin(); it != abstract_name_map.end(); ++ it )
+ {
+ sprintf ( pid_str, "%d", it->second );
+ string target ( it->first ),
+ replacement ( pid_str );
+ string_replaceAll ( command, target, replacement );
+ }
+
+
+ char const * truncated_command = skipWord(skipWord(command.c_str()));
+
+ if ( truncated_command )
+ system ( truncated_command );
+}
+
+
+
+
+
+void
+QrshServer::get ( Message const & request_message )
+{
+ char * file_content;
+
+ /*
+ * Get the contents of the requested file.
+ */
+ char file_or_process_name[1000];
+ sscanf ( request_message.getData().c_str(), "%*s%*s%s", file_or_process_name );
+
+ if ( isProcessName ( file_or_process_name ) )
+ {
+ stringstream desired_file_name;
+ desired_file_name << data_dir.str()
+ << '/'
+ << file_or_process_name
+ << '/';
+ char requested_output_stream[1000];
+ if(1 != sscanf ( request_message.getData().c_str(),
+ "%*s%*s%*s%s",
+ requested_output_stream
+ )
+ )
+ {
+ fprintf ( stderr,
+ "QrshServer::get error: Can't read requested data file name from this message: |%s|\n",
+ request_message.getData().c_str()
+ );
+ return;
+ }
+ desired_file_name << requested_output_stream;
+ file_content = file2str ( desired_file_name.str().c_str() );
+ }
+ else
+ {
+ file_content = file2str ( file_or_process_name );
+ }
+
+ stringstream reply_data ;
+ reply_data << "get_response "
+ << file_content;
+ /*
+ * Send a response-message to the server who is waiting.
+ */
+ send ( reply_data.str() );
+}
+
+
+
+
+
+
+void
+QrshServer::exited ( Message const & message )
+{
+ int exit_code = -1;
+
+ // First, gather all the symbolic names we know.
+ getNames();
+
+ // Now make a copy of the command, that I can alter.
+ string edited_command ( message.getData() );
+
+ // Replace each occurrence of every abstract name with its pid.
+ char pid_str[100];
+ map<char *, int>::iterator it;
+ for ( it = abstract_name_map.begin(); it != abstract_name_map.end(); ++ it )
+ {
+ sprintf ( pid_str, "%d", it->second );
+ string target ( it->first ),
+ replacement ( pid_str );
+ string_replaceAll ( edited_command, target, replacement );
+ }
+
+ // Skip the service name. That is not used by the child.
+ char const * truncated_command = skipWord(edited_command.c_str());
+
+ if ( truncated_command )
+ {
+ stringstream ss;
+ ss << qrsh_run_path
+ << ' '
+ << data_dir.str()
+ << ' '
+ << truncated_command;
+
+ int child_pid;
+ if ( ! (child_pid = fork() ) )
+ {
+ // This is the child.
+
+ char ** argv = getArgs ( ss.str().c_str() );
+ execv ( qrsh_run_path.c_str(), argv );
+
+ perror ( "qrsh_server: execv error: " );
+ exit ( 1 );
+ }
+ else
+ {
+ // This is the parent.
+ pid_t awaited_pid;
+ while ( 0 == (awaited_pid = waitpid ( child_pid, & exit_code, WNOHANG)) )
+ {
+ fprintf ( stderr, "qrsh_server info: parent: waiting for child...\n" );
+ sleep(1);
+ }
+
+ if ( -1 == awaited_pid )
+ {
+ fprintf ( stderr, "qrsh_server error awaiting child!\n" );
+ exit ( 1 );
+ }
+
+ exit_code >>= 8;
+
+ stringstream data;
+ data << "wait_response "
+ << exit_code;
+
+ send ( data.str() );
+ }
+ }
+}
+
+
+
+
+void
+QrshServer::wait ( Message const & message )
+{
+ bool pre_existing = false;
+ if ( 3 == string_countWords ( message.getData().c_str() ) )
+ {
+ // The first word is the name of this service.
+ // The second word is "exec_wait".
+ // The third word is the symbolic name of the command to wait for.
+ // The fact that there are exactly three words means that this
+ // must be a command that has already been named and started --
+ // we just need to find its pid and wait on it.
+ pre_existing = true;
+ }
+
+
+ int exit_code = -1;
+
+ // First, gather all the symbolic names we know.
+ getNames();
+
+ // Now make a copy of the command, that I can alter.
+ string edited_command ( message.getData() );
+
+ // Replace each occurrence of every abstract name with its pid.
+ char pid_str[100];
+ map<char *, int>::iterator it;
+ for ( it = abstract_name_map.begin(); it != abstract_name_map.end(); ++ it )
+ {
+ sprintf ( pid_str, "%d", it->second );
+ string target ( it->first ),
+ replacement ( pid_str );
+ string_replaceAll ( edited_command, target, replacement );
+ }
+
+ // Skip the service name. That is not used by the child.
+ char const * truncated_command = skipWord(edited_command.c_str());
+
+ if ( truncated_command )
+ {
+ stringstream ss;
+ ss << qrsh_run_path
+ << ' '
+ << data_dir.str()
+ << ' '
+ << truncated_command;
+
+ int child_pid;
+ if ( ! (child_pid = fork() ) )
+ {
+ // This is the child.
+
+ char ** argv = getArgs ( ss.str().c_str() );
+ execv ( qrsh_run_path.c_str(), argv );
+
+ perror ( "qrsh_server: execv error: " );
+ exit ( 1 );
+ }
+ else
+ {
+ // This is the parent.
+ pid_t awaited_pid;
+ while ( 0 == (awaited_pid = waitpid ( child_pid, & exit_code, WNOHANG)) )
+ {
+ fprintf ( stderr, "qrsh_server info: parent: waiting for child...\n" );
+ sleep(1);
+ }
+
+ if ( -1 == awaited_pid )
+ {
+ fprintf ( stderr, "qrsh_server error awaiting child!\n" );
+ exit ( 1 );
+ }
+ }
+
+ exit_code >>= 8;
+
+ stringstream data;
+ data << "wait_response "
+ << exit_code;
+
+ send ( data.str() );
+ }
+}
+
+
+
+
+
+char const *
+QrshServer::skipWord ( char const * s )
+{
+ if(! (s && *s) )
+ return 0;
+
+ // skip past initial white space
+ while ( isspace(*s) )
+ {
+ ++ s;
+ if(! *s)
+ return 0;
+ }
+
+ // skip past first word
+ while ( ! isspace(*s) )
+ {
+ ++ s;
+ if(! *s)
+ return 0;
+ }
+
+ return s;
+}
+
+
+
+
+
+char **
+QrshServer::getArgs ( char const * str )
+{
+ char const * s = str;
+
+ char ** argv = 0;
+ vector<int> start_positions,
+ lengths;
+
+ int pos = 0;
+ int arg_len = 0;
+
+ int n_args = 0;
+ while ( 1 )
+ {
+ // advance over whitespace.
+ while ( isspace ( *s ) )
+ {
+ ++ s; ++ pos;
+ if(! *s)
+ {
+ goto done;
+ }
+ }
+
+ ++ n_args;
+ start_positions.push_back ( pos );
+ arg_len = 0;
+
+ // advance over non-whitespace.
+ while ( ! isspace ( *s ) )
+ {
+ ++ s; ++ pos; ++ arg_len;
+ if(! *s)
+ {
+ lengths.push_back ( arg_len );
+ arg_len = 0;
+ goto done;
+ }
+ }
+
+ lengths.push_back ( arg_len );
+ arg_len = 0;
+ }
+
+ done:
+
+ if ( arg_len > 0 )
+ lengths.push_back ( arg_len );
+
+ // Alloc the array.
+ argv = (char **) malloc ( sizeof(char *) * ( n_args + 1 ) );
+ argv[n_args] = 0; // mull-term the array.
+
+ for ( int i = 0; i < n_args; ++ i )
+ {
+ argv[i] = ( char *) malloc ( lengths[i] + 1 );
+ strncpy ( argv[i],
+ str + start_positions[i],
+ lengths[i]
+ );
+ argv[i][lengths[i]] = 0;
+ }
+
+ return argv;
+}
+
+
+
+void
+QrshServer::runCommand ( Message const & message )
+{
+ char const * s = message.getData().c_str();
+
+ /*
+ * Skip the first word, which is this server's name.
+ */
+ while ( isspace(*s) ) // go to start of first word.
+ ++ s;
+
+ while ( ! isspace(*s) ) // go to end of first word.
+ ++ s;
+
+ while ( isspace(*s) ) // go to start of second word.
+ ++ s;
+
+ char command_name[1000];
+ sscanf ( s, "%s", command_name );
+
+ if ( ! strcmp ( "get", command_name ) )
+ {
+ get ( message );
+ }
+ else
+ if ( ! strcmp ( "exited", command_name ) )
+ {
+ exited ( message );
+ }
+ else
+ if ( ! strcmp ( "exec_wait", command_name ) )
+ {
+ wait ( message );
+ }
+ else
+ if ( ! strcmp ( "exec", command_name ) )
+ {
+ execute ( message );
+ }
+ else
+ if ( ! strcmp ( "start", command_name ) )
+ {
+ start ( );
+ }
+ else
+ if ( ! strcmp ( "alias", command_name ) )
+ {
+ addAlias ( message );
+ }
+ else
+ if ( ! strcmp ( "sayName", command_name ) )
+ {
+ sayName ( );
+ }
+ else
+ {
+ /*
+ * If the command is not any of the "special" commands
+ * above, then it's a "normal" command.
+ * That means we run it with a child process instance of
+ * qrsh_run, which will save all its data in the qrsh dir.
+ */
+ stringstream ss;
+ ss << qrsh_run_path
+ << ' '
+ << data_dir.str()
+ << ' '
+ << s;
+
+ if ( ! fork() )
+ {
+ char ** argv = getArgs ( ss.str().c_str() );
+ execv ( qrsh_run_path.c_str(), argv );
+ perror ( "qrsh_server: execv error: " );
+ }
+ }
+}
+
+
+
+void
+QrshServer::received ( Message & message )
+{
+ if ( myMessage ( message ) )
+ runCommand ( message );
+}
+
+
+
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
+/*
+ * fixme mick Mon Aug 3 10:29:26 EDT 2009
+ * argv[1] server name
+ * argv[2] qrsh exe path
+ * argv[3] host
+ * argv[4] port
+ */
+int
+main ( int /*argc*/, char** argv )
+{
+ const char* host = argv[3];
+ int port = atoi(argv[4]);
+ Connection connection;
+ Message msg;
+
+ srand ( getpid() );
+
+ try
+ {
+ connection.open ( host, port );
+ Session session = connection.newSession();
+
+
+ // Declare queues.
+ string myQueue = session.getId().getName();
+ session.queueDeclare ( arg::queue=myQueue,
+ arg::exclusive=true,
+ arg::autoDelete=true);
+
+ session.exchangeBind ( arg::exchange="amq.fanout",
+ arg::queue=myQueue,
+ arg::bindingKey="my-key");
+
+ // Create a server and subscribe it to my queue.
+ SubscriptionManager subscriptions ( session );
+ QrshServer server ( subscriptions,
+ argv[1], // server name
+ argv[2], // qrsh exe path
+ host,
+ port
+ );
+ subscriptions.subscribe ( server, myQueue );
+
+ // Receive messages until the subscription is cancelled
+ // by QrshServer::received()
+ subscriptions.run();
+
+ connection.close();
+ }
+ catch(const exception& error)
+ {
+ cout << error.what() << endl;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+
diff --git a/cpp/src/tests/qrsh_utils/10_all b/cpp/src/tests/qrsh_utils/10_all
new file mode 100755
index 0000000000..7b486ea672
--- /dev/null
+++ b/cpp/src/tests/qrsh_utils/10_all
@@ -0,0 +1,30 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#! /bin/bash
+
+echo "Asking all servers to say their names... "
+qrsh 127.0.0.1 5813 \
+ all sayName
+
+
+
+
diff --git a/cpp/src/tests/qrsh_utils/1_remote_run b/cpp/src/tests/qrsh_utils/1_remote_run
new file mode 100755
index 0000000000..5b9b307bba
--- /dev/null
+++ b/cpp/src/tests/qrsh_utils/1_remote_run
@@ -0,0 +1,26 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#! /bin/bash
+
+
+./qrsh 127.0.0.1 5813 \
+ mrg23 command_1 /home/mick/redhat/qrsh/qrsh_run/my_command foo bar baz
diff --git a/cpp/src/tests/qrsh_utils/2_forever b/cpp/src/tests/qrsh_utils/2_forever
new file mode 100755
index 0000000000..5528b0e4d8
--- /dev/null
+++ b/cpp/src/tests/qrsh_utils/2_forever
@@ -0,0 +1,26 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#! /bin/bash
+
+
+./qrsh 127.0.0.1 5813 \
+ mrg23 command_2 /home/mick/redhat/qrsh/qrsh_run/forever foo bar baz
diff --git a/cpp/src/tests/qrsh_utils/3_kill_it b/cpp/src/tests/qrsh_utils/3_kill_it
new file mode 100755
index 0000000000..afc7a03c9d
--- /dev/null
+++ b/cpp/src/tests/qrsh_utils/3_kill_it
@@ -0,0 +1,27 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#! /bin/bash
+
+echo "Killing command 2... "
+./qrsh 127.0.0.1 5813 \
+ mrg23 exec kill -9 command_2
+
diff --git a/cpp/src/tests/qrsh_utils/4_wait_for_it b/cpp/src/tests/qrsh_utils/4_wait_for_it
new file mode 100755
index 0000000000..a4dc0da1ce
--- /dev/null
+++ b/cpp/src/tests/qrsh_utils/4_wait_for_it
@@ -0,0 +1,26 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#! /bin/bash
+
+./qrsh 127.0.0.1 5813 \
+ mrg23 exec_wait /home/mick/redhat/qrsh/qrsh_run/my_command foo bar baz
+echo "my_command returned an exit code of $?"
diff --git a/cpp/src/tests/qrsh_utils/5_exited b/cpp/src/tests/qrsh_utils/5_exited
new file mode 100755
index 0000000000..4fec1dcc79
--- /dev/null
+++ b/cpp/src/tests/qrsh_utils/5_exited
@@ -0,0 +1,64 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#! /bin/bash
+
+path=/home/mick/redhat/qrsh/qrsh_run
+
+echo "Running command_3 ..."
+./qrsh 127.0.0.1 5813 \
+ mrg23 command_3 $path/my_command foo bar baz
+
+echo "Now I do some other stuff..."
+sleep 1
+echo "And then some more stuff..."
+sleep 1
+echo "and so on..."
+sleep 1
+
+echo "Now I'm waiting for command_3 ..."
+./qrsh 127.0.0.1 5813 \
+ mrg23 exited command_3
+echo "has command_3 exited: $? ."
+sleep 5
+
+./qrsh 127.0.0.1 5813 \
+ mrg23 exited command_3
+echo "has command_3 exited: $? ."
+sleep 5
+
+./qrsh 127.0.0.1 5813 \
+ mrg23 exited command_3
+echo "has command_3 exited: $? ."
+sleep 5
+
+./qrsh 127.0.0.1 5813 \
+ mrg23 exited command_3
+echo "has command_3 exited: $? ."
+sleep 5
+
+./qrsh 127.0.0.1 5813 \
+ mrg23 exited command_3
+echo "has command_3 exited: $? ."
+sleep 5
+
+
+
diff --git a/cpp/src/tests/qrsh_utils/6_get b/cpp/src/tests/qrsh_utils/6_get
new file mode 100755
index 0000000000..4b35ca98e6
--- /dev/null
+++ b/cpp/src/tests/qrsh_utils/6_get
@@ -0,0 +1,29 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#! /bin/bash
+
+echo "getting /tmp/foo ..."
+./qrsh 127.0.0.1 5813 \
+ mrg23 get /tmp/foo
+
+
+
diff --git a/cpp/src/tests/qrsh_utils/7_get_output b/cpp/src/tests/qrsh_utils/7_get_output
new file mode 100755
index 0000000000..59911089ec
--- /dev/null
+++ b/cpp/src/tests/qrsh_utils/7_get_output
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#! /bin/bash
+
+echo "Run a command..."
+./qrsh 127.0.0.1 5813 \
+ mrg23 command_4 /home/mick/redhat/qrsh/qrsh_run/my_command foo bar baz
+
+echo "Wait for a while..."
+sleep 20
+
+echo "Get stderr output:"
+echo "------------- begin stderr ---------------"
+./qrsh 127.0.0.1 5813 \
+ mrg23 get command_4 stderr
+echo "------------- end stderr ---------------"
+echo " "
+echo " "
+echo " "
+echo "Get stdout output:"
+echo "------------- begin stdout ---------------"
+./qrsh 127.0.0.1 5813 \
+ mrg23 get command_4 stdout
+echo "------------- end stdout ---------------"
+
diff --git a/cpp/src/tests/qrsh_utils/8_any b/cpp/src/tests/qrsh_utils/8_any
new file mode 100755
index 0000000000..2a922ea0e0
--- /dev/null
+++ b/cpp/src/tests/qrsh_utils/8_any
@@ -0,0 +1,43 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#! /bin/bash
+
+echo "asking any server to say his name ..."
+./qrsh 127.0.0.1 5813 \
+ any sayName
+sleep 1
+echo "asking any server to say his name ..."
+./qrsh 127.0.0.1 5813 \
+ any sayName
+sleep 1
+echo "asking any server to say his name ..."
+./qrsh 127.0.0.1 5813 \
+ any sayName
+sleep 1
+echo "asking any server to say his name ..."
+./qrsh 127.0.0.1 5813 \
+ any sayName
+sleep 1
+
+
+
+
diff --git a/cpp/src/tests/qrsh_utils/9_alias b/cpp/src/tests/qrsh_utils/9_alias
new file mode 100755
index 0000000000..a4cfdfdf9a
--- /dev/null
+++ b/cpp/src/tests/qrsh_utils/9_alias
@@ -0,0 +1,38 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#! /bin/bash
+
+# Make a group of two of the servers, using "alias",
+# and send the group a command.
+
+qrsh 127.0.0.1 5813 \
+ mrg22 alias group_1
+qrsh 127.0.0.1 5813 \
+ mrg23 alias group_1
+
+echo "Asking group_1 to say their names... "
+qrsh 127.0.0.1 5813 \
+ group_1 sayName
+
+
+
+
diff --git a/cpp/src/tests/qrsh_utils/qrsh_example_command.cpp b/cpp/src/tests/qrsh_utils/qrsh_example_command.cpp
new file mode 100644
index 0000000000..386e2f73f0
--- /dev/null
+++ b/cpp/src/tests/qrsh_utils/qrsh_example_command.cpp
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+
+
+main ( int argc, char ** argv )
+{
+ fprintf ( stderr, "Hello, I am the Example Child!\n");
+ fprintf ( stderr, "my arguments %d are:\n", argc - 1 );
+ fprintf ( stdout, "And hello to stdout, too!\n");
+
+ int i;
+ for ( i = 1; i < argc; ++ i )
+ {
+ fprintf ( stderr, "arg %d: |%s|\n", i, argv[i] );
+ }
+
+ for ( i = 0; i < 15; ++ i )
+ {
+ fprintf ( stderr, "child sleeping...\n" );
+ sleep ( 1 );
+ }
+
+ fprintf ( stderr, "child exiting with code 13.\n" );
+
+ return 13;
+}
+
+
+
+
diff --git a/cpp/src/tests/qrsh_utils/qrsh_forever.cpp b/cpp/src/tests/qrsh_utils/qrsh_forever.cpp
new file mode 100644
index 0000000000..191a9bca11
--- /dev/null
+++ b/cpp/src/tests/qrsh_utils/qrsh_forever.cpp
@@ -0,0 +1,50 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+#include <stdio.h>
+#include <unistd.h>
+
+
+
+main ( int argc, char ** argv )
+{
+ fprintf ( stderr, "Hello, I am the Forever Example Child!\n");
+ fprintf ( stderr, "my %d arguments are:\n", argc - 1 );
+
+ int i;
+ for ( i = 1; i < argc; ++ i )
+ fprintf ( stderr, "arg %d: |%s|\n", i, argv[i] );
+
+ for ( i = 0; i >= 0; ++ i )
+ {
+ fprintf ( stderr, "child sleeping forever %d ...\n" , i);
+ sleep ( 1 );
+ }
+
+ fprintf ( stderr, "child exiting with code 12.\n" );
+
+ return 12;
+}
+
+
+
+
diff --git a/cpp/src/tests/qrsh_utils/qsh_doc.txt b/cpp/src/tests/qrsh_utils/qsh_doc.txt
new file mode 100644
index 0000000000..ad5990b38b
--- /dev/null
+++ b/cpp/src/tests/qrsh_utils/qsh_doc.txt
@@ -0,0 +1,309 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+##############################################
+ qrsh: a Qpid-based remote shell utility
+
+ Last updated: 3 Aug 09 Mick Goulish
+##############################################
+
+
+
+=============================
+Overview
+=============================
+
+ You're writing a multi-box test, and you want to write a
+ shell script in which you start processes on other boxes
+ and kill them (or send arbitrary signals to them).
+
+ But ssh doesn't let you signal them, and bash isn't the
+ greatest language in the world for creating data structures
+ (like you need to associate the PIDs with box names and
+ executable names.)
+
+ Qsh is a utility implemented on Qpid that you can use from
+ within your bash script, or any other scripting language.
+ With it, you can:
+
+ 1. run any executable on any box in your cluster.
+
+ 2. don't worry about PIDs and box-names. You associate
+ your own abstract names with the executable instances,
+ and then use those names in the rest of your script.
+ I.e. "broker_1" "sender_3" etc.
+
+ 3. Launch the executable and wait until it returns, and
+ get its exit code.
+
+ 4. Launch your executable and do other stuff, then come
+ back later and see if it has exited.
+
+ 5. Get whatever it sent to stdout or stderr.
+
+ 6. Get the contents of any other file.
+
+ 7. send a command to all your boxes at once
+
+ 8. send a command to a randomly selected box.
+
+ 9. define groups of boxes, and send a command simultaneously
+ to all boxes in a given group.
+
+
+
+
+=============================
+Using It
+=============================
+
+ 1. You need to run a Qpid broker.
+
+ 2. You start a Qpid client ( which is called a qrsh_server )
+ on all the boxes you care about. And you give them all
+ names like "mrg13", "mrg14" etc. The names can be anything
+ you want, but I've always used one qrsh_server per box,
+ and given it the box name. ( However, you can run two on
+ one box, they won't collide. )
+
+ 3. After you start all servers, send a "start" command to any
+ one of them:
+
+ 4. The qrsh_servers use the fanout exchange to talk to each
+ other.
+
+ 5. In your script, you run an executable called "qrsh". It knows
+ how to talk to the servers, do what you want, and retrieve
+ the data you want.
+
+
+ example start script: (this does 4 servers on the same box)
+ -------------------------------------------------------------
+
+ echo "Starting server mrg22 ..."
+ ./qrsh_server mrg22 ./qrsh_run 127.0.0.1 5813 &
+
+ echo "Starting server mrg23 ..."
+ ./qrsh_server mrg23 ./qrsh_run 127.0.0.1 5813 &
+
+ echo "Starting server mrg24 ..."
+ ./qrsh_server mrg24 ./qrsh_run 127.0.0.1 5813 &
+
+ echo "Starting server mrg25 ..."
+ ./qrsh_server mrg25 ./qrsh_run 127.0.0.1 5813 &
+
+ echo "Issuing start command..."
+ sleep 2
+ ./qrsh 127.0.0.1 5813 mrg22 start
+ sleep 1
+
+ echo "Ready."
+
+ # end of script.
+
+
+
+
+
+
+=============================
+Qrsh Syntax
+=============================
+
+ qrsh host port server_name command_name arg*
+
+
+ "host" and "port" specify the Qpid server to connect to.
+
+ "server_name" can be anything you want. I always use the name
+ of the box that the server is running on.
+
+ "command_name" is the name that you choose to assign to
+ the process you are running. Each process that you decide
+ to name must have a unique name within this script.
+
+ Or it could be a reserved command name, that Qsh
+ interprets in a special way.
+
+ Reserved command names are:
+
+ exec
+ exec_wait
+ exited
+ get
+
+ "exec" means "interpret the rest of the command line as a
+ command to be executed by the designated server.
+
+ "exec_wait" means same as "exec", but wait for the command
+ to terminate, and return its exit code.
+
+ "exited" -- you provide 1 arg, which is an abstract
+ process name. qrsh returns 1 if that process has exited,
+ else 0.
+
+ "get" -- you provide one arg which is a path. qrsh returns
+ (by printing to stdout) the contents of that file.
+
+ "arg*" is zero or more arguments. They are interpreted
+ differently depending on whether you are using one of
+ the above reserved command names, or making up your own
+ abstract name for a command.
+
+
+
+
+=============================
+Examples
+=============================
+
+ 1. Run a process on a remote box.
+
+ qrsh mrg23 command_1 /usr/sbin/whatever foo bar baz
+
+ Returns immediately.
+
+
+
+ 2. Kill a process that you started earlier:
+
+ qrsh mrg23 exec kill -9 command_1
+
+ After the word "exec" put any command line you want.
+ The server you're sending this to will replace all abstract
+ names in the command with process IDs. ( In this example,
+ just the word "command_1" will be replaced. ) Then it will
+ execute the command.
+
+
+
+ 3. Execute a command, and wait for it to finish
+
+ qrsh mrg23 exec_wait command_name args
+
+
+
+ 4. Check on whether a command you issude earlier has exited.
+
+ ./qrsh mrg23 exited command_3
+
+ Returns 1 if it has exited, else 0.
+
+
+
+ 5. Get the contents of a file from the remote system:
+
+ ./qrsh mrg23 get /tmp/foo
+
+ Prints the contents to stdout.
+
+
+
+ 6. Send a command to all servers at once:
+
+ # This example causes them all to print thir names to stderr.
+ ./qrsh all sayName
+
+
+ 7. Define a group of servers and send a command to that group.
+
+ #! /bin/bash
+
+ # Make a group of two of the servers, using "alias",
+ # and send the group a command.
+
+ qrsh 127.0.0.1 5813 \
+ mrg22 alias group_1
+
+ qrsh 127.0.0.1 5813 \
+ mrg23 alias group_1
+
+ echo "Asking group_1 to say their names... "
+ qrsh 127.0.0.1 5813 \
+ group_1 sayName
+
+ # end of script.
+
+
+
+
+ 8. Execute a command and get its stdout and stderr contents.
+
+ #! /bin/bash
+
+ echo "Run a command..."
+ ./qrsh 127.0.0.1 5813 \
+ mrg23 command_4 my_command foo bar baz
+
+ echo "Wait for a while..."
+ sleep 10
+
+ echo "Get stderr output:"
+ echo "------------- begin stderr ---------------"
+ ./qrsh 127.0.0.1 5813 \
+ mrg23 get command_4 stderr
+ echo "------------- end stderr ---------------"
+ echo " "
+
+ echo " "
+ echo "Get stdout output:"
+ echo "------------- begin stdout ---------------"
+ ./qrsh 127.0.0.1 5813 \
+ mrg23 get command_4 stdout
+ echo "------------- end stdout ---------------"
+
+ # end of script.
+
+
+
+
+ 9. Send a command to one of your servers, selected
+ at random.
+
+ #! /bin/bash
+
+ # I do it multiple times here, so I can see
+ # that it really is selecting randomly.
+
+ echo "asking any server to say his name ..."
+ ./qrsh 127.0.0.1 5813 \
+ any sayName
+ sleep 1
+
+ echo "asking any server to say his name ..."
+ ./qrsh 127.0.0.1 5813 \
+ any sayName
+ sleep 1
+
+ echo "asking any server to say his name ..."
+ ./qrsh 127.0.0.1 5813 \
+ any sayName
+ sleep 1
+
+ echo "asking any server to say his name ..."
+ ./qrsh 127.0.0.1 5813 \
+ any sayName
+
+ # end of script.
+
+
+
+
diff --git a/cpp/src/tests/quick_perftest b/cpp/src/tests/quick_perftest
index 676436fdc7..4f7cf3cb54 100755
--- a/cpp/src/tests/quick_perftest
+++ b/cpp/src/tests/quick_perftest
@@ -1,2 +1,22 @@
#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
exec `dirname $0`/run_test ./perftest --summary --count 100
diff --git a/cpp/src/tests/quick_topictest b/cpp/src/tests/quick_topictest
index b1e63b9350..0a6b29b33f 100755
--- a/cpp/src/tests/quick_topictest
+++ b/cpp/src/tests/quick_topictest
@@ -1,6 +1,27 @@
#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+
# Quick and quiet topic test for make check.
-test -z "$srcdir" && srcdir=.
+test -z "$srcdir" && srcdir=`dirname $0`
$srcdir/topictest -s2 -m2 -b1 > topictest.log 2>&1 || {
echo $0 FAILED:
cat topictest.log
diff --git a/cpp/src/tests/quick_topictest.ps1 b/cpp/src/tests/quick_topictest.ps1
new file mode 100644
index 0000000000..b2efbdd684
--- /dev/null
+++ b/cpp/src/tests/quick_topictest.ps1
@@ -0,0 +1,30 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Quick and quiet topic test for make check.
+[string]$me = $myInvocation.InvocationName
+$srcdir = Split-Path $me
+& "$srcdir\topictest.ps1" -subscribers 2 -messages 2 -batches 1 > topictest.log 2>&1
+if (!$?) {
+ "$me FAILED:"
+ cat topictest.log
+ exit $LastExitCode
+}
+Remove-Item topictest.log
+exit 0
diff --git a/cpp/src/tests/quick_txtest b/cpp/src/tests/quick_txtest
new file mode 100755
index 0000000000..938e3805d8
--- /dev/null
+++ b/cpp/src/tests/quick_txtest
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+exec `dirname $0`/run_test ./txtest --queues 4 --tx-count 10 --quiet
diff --git a/cpp/src/tests/receiver.cpp b/cpp/src/tests/receiver.cpp
new file mode 100644
index 0000000000..e01954e31a
--- /dev/null
+++ b/cpp/src/tests/receiver.cpp
@@ -0,0 +1,139 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/client/FailoverManager.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/SubscriptionManager.h>
+#include <qpid/client/SubscriptionSettings.h>
+#include "TestOptions.h"
+
+#include <iostream>
+#include <fstream>
+
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using namespace std;
+
+namespace qpid {
+namespace tests {
+
+struct Args : public qpid::TestOptions
+{
+ string queue;
+ uint messages;
+ bool ignoreDuplicates;
+ uint creditWindow;
+ uint ackFrequency;
+ bool browse;
+
+ Args() : queue("test-queue"), messages(0), ignoreDuplicates(false), creditWindow(0), ackFrequency(1), browse(false)
+ {
+ addOptions()
+ ("queue", qpid::optValue(queue, "QUEUE NAME"), "Queue from which to request messages")
+ ("messages", qpid::optValue(messages, "N"), "Number of messages to receive; 0 means receive indefinitely")
+ ("ignore-duplicates", qpid::optValue(ignoreDuplicates), "Detect and ignore duplicates (by checking 'sn' header)")
+ ("credit-window", qpid::optValue(creditWindow, "N"), "Credit window (0 implies infinite window)")
+ ("ack-frequency", qpid::optValue(ackFrequency, "N"), "Ack frequency (0 implies none of the messages will get accepted)")
+ ("browse", qpid::optValue(browse), "Browse rather than consuming");
+ }
+};
+
+const string EOS("eos");
+
+class Receiver : public MessageListener, public FailoverManager::Command
+{
+ public:
+ Receiver(const string& queue, uint messages, bool ignoreDuplicates, uint creditWindow, uint ackFrequency, bool browse);
+ void received(Message& message);
+ void execute(AsyncSession& session, bool isRetry);
+ private:
+ const string queue;
+ const uint count;
+ const bool skipDups;
+ SubscriptionSettings settings;
+ Subscription subscription;
+ uint processed;
+ uint lastSn;
+
+ bool isDuplicate(Message& message);
+};
+
+Receiver::Receiver(const string& q, uint messages, bool ignoreDuplicates, uint creditWindow, uint ackFrequency, bool browse) :
+ queue(q), count(messages), skipDups(ignoreDuplicates), processed(0), lastSn(0)
+{
+ if (browse) settings.acquireMode = ACQUIRE_MODE_NOT_ACQUIRED;
+ if (creditWindow) settings.flowControl = FlowControl::messageWindow(creditWindow);
+ settings.autoAck = ackFrequency;
+}
+
+void Receiver::received(Message& message)
+{
+ if (!(skipDups && isDuplicate(message))) {
+ bool eos = message.getData() == EOS;
+ if (!eos) std::cout << message.getData() << std::endl;
+ if (eos || ++processed == count) subscription.cancel();
+ }
+}
+
+bool Receiver::isDuplicate(Message& message)
+{
+ uint sn = message.getHeaders().getAsInt("sn");
+ if (lastSn < sn) {
+ lastSn = sn;
+ return false;
+ } else {
+ return true;
+ }
+}
+
+void Receiver::execute(AsyncSession& session, bool /*isRetry*/)
+{
+ SubscriptionManager subs(session);
+ subscription = subs.subscribe(*this, queue, settings);
+ subs.run();
+ if (settings.autoAck) {
+ subscription.accept(subscription.getUnaccepted());
+ }
+}
+
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
+int main(int argc, char ** argv)
+{
+ Args opts;
+ try {
+ opts.parse(argc, argv);
+ FailoverManager connection(opts.con);
+ Receiver receiver(opts.queue, opts.messages, opts.ignoreDuplicates, opts.creditWindow, opts.ackFrequency, opts.browse);
+ connection.execute(receiver);
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cerr << "Failure: " << error.what() << std::endl;
+ }
+ return 1;
+}
diff --git a/cpp/src/tests/reliable_replication_test b/cpp/src/tests/reliable_replication_test
new file mode 100755
index 0000000000..f57d11a263
--- /dev/null
+++ b/cpp/src/tests/reliable_replication_test
@@ -0,0 +1,93 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Test reliability of the replication feature in the face of link
+# failures:
+
+source ./test_env.sh
+
+trap stop_brokers EXIT
+
+stop_brokers() {
+ if [[ $BROKER_A ]] ; then
+ $QPIDD_EXEC --no-module-dir -q --port $BROKER_A
+ unset BROKER_A
+ fi
+ if [[ $BROKER_B ]] ; then
+ $QPIDD_EXEC --no-module-dir -q --port $BROKER_B
+ unset BROKER_B
+ fi
+}
+
+setup() {
+ rm -f replication-source.log replication-dest.log
+ $QPIDD_EXEC --daemon --port 0 --no-data-dir --no-module-dir --auth no --load-module $REPLICATING_LISTENER_LIB --replication-queue replication --create-replication-queue true --log-enable trace+ --log-to-file replication-source.log --log-to-stderr 0 > qpidd-repl.port
+ BROKER_A=`cat qpidd-repl.port`
+
+ $QPIDD_EXEC --daemon --port 0 --no-data-dir --no-module-dir --auth no --load-module $REPLICATION_EXCHANGE_LIB --log-enable info+ --log-to-file replication-dest.log --log-to-stderr 0 > qpidd-repl.port
+ BROKER_B=`cat qpidd-repl.port`
+
+ echo "Testing replication from port $BROKER_A to port $BROKER_B"
+
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add exchange replication replication
+ $PYTHON_COMMANDS/qpid-route --ack 500 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication
+
+ #create test queue (only replicate enqueues for this test):
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-a --generate-queue-events 1
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-a
+}
+
+send() {
+ ./sender --port $BROKER_A --routing-key queue-a --send-eos 1 < replicated.expected
+}
+
+receive() {
+ rm -f replicated.actual
+ ./receiver --port $BROKER_B --queue queue-a > replicated.actual
+}
+
+bounce_link() {
+ echo "Destroying link..."
+ $PYTHON_COMMANDS/qpid-route link del "localhost:$BROKER_B" "localhost:$BROKER_A"
+ echo "Link destroyed; recreating route..."
+ sleep 2
+ $PYTHON_COMMANDS/qpid-route --ack 500 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication
+ echo "Route re-established"
+}
+
+if test -d ${PYTHON_DIR} && test -e $REPLICATING_LISTENER_LIB && test -e $REPLICATION_EXCHANGE_LIB ; then
+ setup
+ for i in `seq 1 100000`; do echo Message $i; done > replicated.expected
+ send &
+ receive &
+ for i in `seq 1 5`; do sleep 10; bounce_link; done;
+ wait
+ #check that received list is identical to sent list
+ diff replicated.actual replicated.expected || FAIL=1
+ if [[ $FAIL ]]; then
+ echo reliable replication test failed: expectations not met!
+ exit 1
+ else
+ echo replication reliable in the face of link failures
+ rm -f replication.actual replication.expected replication-source.log replication-dest.log qpidd-repl.port
+ fi
+fi
+
diff --git a/cpp/src/tests/replaying_sender.cpp b/cpp/src/tests/replaying_sender.cpp
new file mode 100644
index 0000000000..62912ea0fc
--- /dev/null
+++ b/cpp/src/tests/replaying_sender.cpp
@@ -0,0 +1,163 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/client/FailoverManager.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/AsyncSession.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/MessageReplayTracker.h>
+#include <qpid/Exception.h>
+
+#include <iostream>
+#include <sstream>
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using namespace std;
+
+namespace qpid {
+namespace tests {
+
+class Sender : public FailoverManager::Command
+{
+ public:
+ Sender(const std::string& queue, uint count, uint reportFreq);
+ void execute(AsyncSession& session, bool isRetry);
+ uint getSent();
+
+ void setVerbosity ( int v ) { verbosity = v; }
+ void setPersistence ( int p ) { persistence = p; }
+
+ private:
+ MessageReplayTracker sender;
+ const uint count;
+ uint sent;
+ const uint reportFrequency;
+ Message message;
+ int verbosity;
+ int persistence;
+ string queueName;
+};
+
+Sender::Sender(const std::string& queue, uint count_, uint reportFreq )
+ : sender(10),
+ count(count_),
+ sent(0),
+ reportFrequency(reportFreq),
+ verbosity(0),
+ persistence(0),
+ queueName ( queue )
+{
+ message.getDeliveryProperties().setRoutingKey(queueName.c_str());
+}
+
+void Sender::execute(AsyncSession& session, bool isRetry)
+{
+ if (verbosity > 0)
+ std::cout << "replaying_sender " << (isRetry ? "first " : "re-") << "connect." << endl;
+ if (isRetry) sender.replay(session);
+ else sender.init(session);
+ while (sent < count) {
+ stringstream message_data;
+ message_data << ++sent;
+ message.setData(message_data.str());
+ message.getHeaders().setInt("sn", sent);
+ if ( persistence )
+ message.getDeliveryProperties().setDeliveryMode(PERSISTENT);
+
+ sender.send(message);
+ if (count > reportFrequency && !(sent % reportFrequency)) {
+ if ( verbosity > 0 )
+ std::cout << "Sender sent "
+ << sent
+ << " of "
+ << count
+ << " on queue "
+ << queueName
+ << std::endl;
+ }
+ }
+ message.setData("That's all, folks!");
+ sender.send(message);
+
+ if ( verbosity > 0 )
+ std::cout << "SENDER COMPLETED\n";
+}
+
+uint Sender::getSent()
+{
+ return sent;
+}
+
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
+int main(int argc, char ** argv)
+{
+ ConnectionSettings settings;
+
+ if ( argc != 8 )
+ {
+ std::cerr << "Usage: replaying_sender host port n_messages report_frequency verbosity persistence queue_name\n";
+ return 1;
+ }
+
+ settings.host = argv[1];
+ settings.port = atoi(argv[2]);
+ int n_messages = atoi(argv[3]);
+ int reportFrequency = atoi(argv[4]);
+ int verbosity = atoi(argv[5]);
+ int persistence = atoi(argv[6]);
+ char * queue_name = argv[7];
+
+ FailoverManager connection(settings);
+ Sender sender(queue_name, n_messages, reportFrequency );
+ sender.setVerbosity ( verbosity );
+ sender.setPersistence ( persistence );
+ try {
+ connection.execute ( sender );
+ if ( verbosity > 0 )
+ {
+ std::cout << "Sender finished. Sent "
+ << sender.getSent()
+ << " messages on queue "
+ << queue_name
+ << endl;
+ }
+ connection.close();
+ return 0;
+ }
+ catch(const std::exception& error)
+ {
+ cerr << "Sender (host: "
+ << settings.host
+ << " port: "
+ << settings.port
+ << " ) "
+ << " Failed: "
+ << error.what()
+ << std::endl;
+ }
+ return 1;
+}
diff --git a/cpp/src/tests/replication_test b/cpp/src/tests/replication_test
new file mode 100755
index 0000000000..691fd20b0c
--- /dev/null
+++ b/cpp/src/tests/replication_test
@@ -0,0 +1,182 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Run a test of the replication feature
+
+source ./test_env.sh
+
+trap stop_brokers INT TERM QUIT
+
+stop_brokers() {
+ if [ x$BROKER_A != x ]; then
+ $QPIDD_EXEC --no-module-dir -q --port $BROKER_A
+ unset BROKER_A
+ fi
+ if [ x$BROKER_B != x ]; then
+ $QPIDD_EXEC --no-module-dir -q --port $BROKER_B
+ unset BROKER_B
+ fi
+}
+
+if test -d ${PYTHON_DIR} && test -f "$REPLICATING_LISTENER_LIB" && test -f "$REPLICATION_EXCHANGE_LIB"; then
+ rm -f queue-*.repl replication-*.log #cleanup from any earlier runs
+
+ $QPIDD_EXEC --daemon --port 0 --no-data-dir --no-module-dir --auth no --load-module $REPLICATING_LISTENER_LIB --replication-queue replication --create-replication-queue true --log-enable info+ --log-to-file replication-source.log --log-to-stderr 0 > qpidd.port
+ BROKER_A=`cat qpidd.port`
+
+ $QPIDD_EXEC --daemon --port 0 --no-data-dir --no-module-dir --auth no --load-module $REPLICATION_EXCHANGE_LIB --log-enable info+ --log-to-file replication-dest.log --log-to-stderr 0 > qpidd.port
+ BROKER_B=`cat qpidd.port`
+ echo "Running replication test between localhost:$BROKER_A and localhost:$BROKER_B"
+
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add exchange replication replication
+ $PYTHON_COMMANDS/qpid-route --ack 5 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication
+
+ #create test queues
+
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-a --generate-queue-events 2
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-b --generate-queue-events 2
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-c --generate-queue-events 1
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-d --generate-queue-events 2
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-e --generate-queue-events 1
+
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-a
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-b
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-c
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-e
+ #queue-d deliberately not declared on DR; this error case should be handled
+
+ #publish and consume from test queues on broker A:
+ i=1
+ while [ $i -le 10 ]; do
+ echo Message $i for A >> queue-a-input.repl
+ i=`expr $i + 1`
+ done
+ i=1
+ while [ $i -le 20 ]; do
+ echo Message $i for B >> queue-b-input.repl
+ i=`expr $i + 1`
+ done
+ i=1
+ while [ $i -le 15 ]; do
+ echo Message $i for C >> queue-c-input.repl
+ i=`expr $i + 1`
+ done
+
+ ./sender --port $BROKER_A --routing-key queue-a --send-eos 1 < queue-a-input.repl
+ ./sender --port $BROKER_A --routing-key queue-b --send-eos 1 < queue-b-input.repl
+ ./sender --port $BROKER_A --routing-key queue-c --send-eos 1 < queue-c-input.repl
+ echo dummy | ./sender --port $BROKER_A --routing-key queue-d --send-eos 1
+
+ ./receiver --port $BROKER_A --queue queue-a --messages 5 > /dev/null
+ ./receiver --port $BROKER_A --queue queue-b --messages 10 > /dev/null
+ ./receiver --port $BROKER_A --queue queue-c --messages 10 > /dev/null
+ ./receiver --port $BROKER_A --queue queue-d > /dev/null
+
+
+ # What we are doing is putting a message on the end of repliaction queue & waiting for it on remote side
+ # making sure all the messages have been flushed from the replication queue.
+ echo dummy | ./sender --port $BROKER_A --routing-key queue-e --send-eos 1
+ ./receiver --port $BROKER_B --queue queue-e --messages 1 > /dev/null
+
+ #shutdown broker A then check that broker Bs versions of the queues are as expected
+ $QPIDD_EXEC --no-module-dir -q --port $BROKER_A
+ unset BROKER_A
+
+ #validate replicated queues:
+ ./receiver --port $BROKER_B --queue queue-a > queue-a-backup.repl
+ ./receiver --port $BROKER_B --queue queue-b > queue-b-backup.repl
+ ./receiver --port $BROKER_B --queue queue-c > queue-c-backup.repl
+
+
+ tail -5 queue-a-input.repl > queue-a-expected.repl
+ tail -10 queue-b-input.repl > queue-b-expected.repl
+ diff queue-a-backup.repl queue-a-expected.repl || FAIL=1
+ diff queue-b-backup.repl queue-b-expected.repl || FAIL=1
+ diff queue-c-backup.repl queue-c-input.repl || FAIL=1
+
+ grep 'queue-d does not exist' replication-dest.log > /dev/null || echo "WARNING: Expected error to be logged!"
+
+ stop_brokers
+
+ # now check offsets working (enqueue based on position being set, not queue abs position)
+
+ $QPIDD_EXEC --daemon --port 0 --no-data-dir --no-module-dir --auth no --load-module $REPLICATING_LISTENER_LIB --replication-queue replication --create-replication-queue true --log-enable info+ --log-to-file replication-source.log --log-to-stderr 0 > qpidd.port
+ BROKER_A=`cat qpidd.port`
+
+ $QPIDD_EXEC --daemon --port 0 --no-data-dir --no-module-dir --auth no --load-module $REPLICATION_EXCHANGE_LIB --log-enable info+ --log-to-file replication-dest.log --log-to-stderr 0 > qpidd.port
+ BROKER_B=`cat qpidd.port`
+
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add exchange replication replication
+ $PYTHON_COMMANDS/qpid-route --ack 5 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication
+
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-e --generate-queue-events 2
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-e
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-d --generate-queue-events 1
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-d
+
+ i=1
+ while [ $i -le 10 ]; do
+ echo Message $i for A >> queue-e-input.repl
+ i=`expr $i + 1`
+ done
+
+ ./sender --port $BROKER_A --routing-key queue-e --send-eos 1 < queue-e-input.repl
+ ./receiver --port $BROKER_A --queue queue-e --messages 10 > /dev/null
+
+ # What we are doing is putting a message on the end of repliaction queue & waiting for it on remote side
+ # making sure all the messages have been flushed from the replication queue.
+ echo dummy | ./sender --port $BROKER_A --routing-key queue-d --send-eos 1
+ ./receiver --port $BROKER_B --queue queue-d --messages 1 > /dev/null
+
+ # now check offsets working
+ $QPIDD_EXEC --no-module-dir -q --port $BROKER_B
+ unset BROKER_B
+ $QPIDD_EXEC --daemon --port 0 --no-data-dir --no-module-dir --auth no --load-module $REPLICATION_EXCHANGE_LIB --log-enable info+ --log-to-file replication-dest.log --log-to-stderr 0 > qpidd.port
+ BROKER_B=`cat qpidd.port`
+
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-e
+ $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add exchange replication replication
+ $PYTHON_COMMANDS/qpid-route --ack 5 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication
+ # now send another 15
+ i=11
+ while [ $i -le 15 ]; do
+ echo Message $i for A >> queue-e1-input.repl
+ i=`expr $i + 1`
+ done
+ ./sender --port $BROKER_A --routing-key queue-e --send-eos 1 < queue-e1-input.repl
+
+ ./receiver --port $BROKER_B --queue queue-e > queue-e-backup.repl
+ diff queue-e-backup.repl queue-e1-input.repl || FAIL=1
+
+ stop_brokers
+
+ if [ x$FAIL != x ]; then
+ echo replication test failed: expectations not met!
+ exit 1
+ else
+ echo queue state replicated as expected
+ rm -f queue-*.repl replication-*.log
+ fi
+
+else
+ echo "Skipping replication test, plugins not built or python utils not located"
+fi
+
diff --git a/cpp/src/tests/restart_cluster b/cpp/src/tests/restart_cluster
index e288805674..6a6abc8042 100755
--- a/cpp/src/tests/restart_cluster
+++ b/cpp/src/tests/restart_cluster
@@ -1,4 +1,24 @@
#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# Re-start a cluster on the local host.
srcdir=`dirname $0`
diff --git a/cpp/src/tests/resuming_receiver.cpp b/cpp/src/tests/resuming_receiver.cpp
new file mode 100644
index 0000000000..abd62f003e
--- /dev/null
+++ b/cpp/src/tests/resuming_receiver.cpp
@@ -0,0 +1,192 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/client/FailoverManager.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/SubscriptionManager.h>
+
+#include <iostream>
+#include <fstream>
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using namespace std;
+
+
+
+namespace qpid {
+namespace tests {
+
+class Listener : public MessageListener,
+ public FailoverManager::Command,
+ public FailoverManager::ReconnectionStrategy
+{
+ public:
+ Listener ( int report_frequency = 1000,
+ int verbosity = 0,
+ char const * queue_name = "message_queue" );
+ void received(Message& message);
+ void execute(AsyncSession& session, bool isRetry);
+ void check();
+ void editUrlList(vector<Url>& urls);
+ private:
+ Subscription subscription;
+ uint count;
+ vector<int> received_twice;
+ uint lastSn;
+ bool gaps;
+ uint reportFrequency;
+ int verbosity;
+ bool done;
+ string queueName;
+};
+
+
+Listener::Listener ( int freq, int verbosity, char const * name )
+ : count(0),
+ lastSn(0),
+ gaps(false),
+ reportFrequency(freq),
+ verbosity(verbosity),
+ done(false),
+ queueName ( name )
+{}
+
+
+void Listener::received(Message & message)
+{
+ if (message.getData() == "That's all, folks!")
+ {
+ done = true;
+ if(verbosity > 0 )
+ {
+ cout << "Shutting down listener for "
+ << message.getDestination() << endl;
+
+ cout << "Listener received "
+ << count
+ << " messages ("
+ << received_twice.size()
+ << " received_twice)"
+ << endl;
+
+ }
+ subscription.cancel();
+ if ( verbosity > 0 )
+ cout << "LISTENER COMPLETED\n";
+
+ if ( ! gaps ) {
+ cout << "no gaps were detected\n";
+ cout << received_twice.size() << " messages were received twice.\n";
+ }
+ else {
+ cout << "gaps detected\n";
+ for ( unsigned int i = 0; i < received_twice.size(); ++ i )
+ cout << "received_twice "
+ << received_twice[i]
+ << endl;
+ }
+ } else {
+ uint sn = message.getHeaders().getAsInt("sn");
+ if (lastSn < sn) {
+ if (sn - lastSn > 1) {
+ cerr << "Error: gap in sequence between " << lastSn << " and " << sn << endl;
+ gaps = true;
+ }
+ lastSn = sn;
+ ++count;
+ if ( ! ( count % reportFrequency ) ) {
+ if ( verbosity > 0 )
+ cout << "Listener has received "
+ << count
+ << " messages on queue "
+ << queueName
+ << endl;
+ }
+ } else {
+ received_twice.push_back ( sn );
+ }
+ }
+}
+
+void Listener::check()
+{
+ if (gaps) throw Exception("Detected gaps in sequence; messages appear to have been lost.");
+}
+
+void Listener::execute(AsyncSession& session, bool isRetry) {
+ if (verbosity > 0)
+ cout << "resuming_receiver " << (isRetry ? "first " : "re-") << "connect." << endl;
+ if (!done) {
+ SubscriptionManager subs(session);
+ subscription = subs.subscribe(*this, queueName);
+ subs.run();
+ }
+}
+
+void Listener::editUrlList(vector<Url>& urls)
+{
+ /**
+ * A more realistic algorithm would be to search through the list
+ * for prefered hosts and ensure they come first in the list.
+ */
+ if (urls.size() > 1) rotate(urls.begin(), urls.begin() + 1, urls.end());
+}
+
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
+int main(int argc, char ** argv)
+{
+ ConnectionSettings settings;
+
+ if ( argc != 6 )
+ {
+ cerr << "Usage: resuming_receiver host port report_frequency verbosity queue_name\n";
+ return 1;
+ }
+
+ settings.host = argv[1];
+ settings.port = atoi(argv[2]);
+ int reportFrequency = atoi(argv[3]);
+ int verbosity = atoi(argv[4]);
+ char * queue_name = argv[5];
+
+ Listener listener ( reportFrequency, verbosity, queue_name );
+ FailoverManager connection(settings, &listener);
+
+ try {
+ connection.execute(listener);
+ connection.close();
+ listener.check();
+ return 0;
+ } catch(const exception& error) {
+ cerr << "Receiver failed: " << error.what() << endl;
+ }
+ return 1;
+}
+
+
+
diff --git a/cpp/src/tests/ring_queue_test b/cpp/src/tests/ring_queue_test
new file mode 100755
index 0000000000..553746eb49
--- /dev/null
+++ b/cpp/src/tests/ring_queue_test
@@ -0,0 +1,174 @@
+#!/bin/bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Test script for validating the behaviour of a ring queue
+
+QUEUE_NAME=ring-queue
+LIMIT=100
+DURABLE=0
+MESSAGES=10000
+SENDERS=1
+RECEIVERS=1
+CONCURRENT=0
+BROKER_URL="-a ${QPID_BROKER:-localhost}:${QPID_PORT:-5672}"
+
+setup() {
+ if [[ $DURABLE -gt 0 ]]; then
+ EXTRA_ARGS=" --durable"
+ fi
+ qpid-config $BROKER_URL add queue $QUEUE_NAME --max-queue-count $LIMIT --limit-policy ring $EXTRA_ARGS
+}
+
+send() {
+ datagen --count $MESSAGES | tee sender_${QUEUE_NAME}_${1} | sender --durable $DURABLE --routing-key $QUEUE_NAME
+}
+
+receive() {
+ #TODO: allow a variety of receiver options to be passed in (ack-frequency, credit-window etc)
+ receiver --queue $QUEUE_NAME > receiver_${QUEUE_NAME}_${1}
+}
+
+cleanup() {
+ rm -f sender_${QUEUE_NAME}_* receiver_${QUEUE_NAME}_*
+ qpid-config $BROKER_URL del queue $QUEUE_NAME --force
+}
+
+log() {
+ echo $1
+}
+
+fail() {
+ echo $1
+ FAILED=1
+}
+
+validate() {
+ if [[ $RECEIVERS -eq 0 ]]; then
+ #queue should have $LIMIT messages on it, but need to send an eos also
+ sender --routing-key $QUEUE_NAME --send-eos 1 < /dev/null
+ received=$(receiver --queue $QUEUE_NAME --browse | wc -l)
+ if [[ received -eq $(( $LIMIT - 1)) ]]; then
+ log "queue contains $LIMIT messages as expected"
+ else
+ fail "queue does not contain the expected $LIMIT messages (received $received)"
+ fi
+ elif [[ $CONCURRENT -eq 0 ]]; then
+ #sum of length of all output files should be equal to $LIMIT - $RECEIVERS (1 eos message each)
+ received=$(cat receiver_${QUEUE_NAME}_* | wc -l)
+ expected=$(( $LIMIT - $RECEIVERS ))
+ if [[ $received -eq $expected ]]; then
+ log "received $LIMIT messages as expected"
+ else
+ fail "received $received messages, expected $expected"
+ fi
+ #if there were only a single sender and receiver (executed serially) we can check the
+ #actual received contents
+ if [[ $RECEIVERS -eq 1 ]] && [[ $SENDERS -eq 1 ]]; then
+ tail -n $(($LIMIT - 1)) sender_${QUEUE_NAME}_1 | diff - receiver_${QUEUE_NAME}_1 || FAILED=1
+ if [[ $FAILED -eq 1 ]]; then
+ fail "did not receive expected messages"
+ else
+ log "received messages matched expectations"
+ fi
+ fi
+ else
+ #multiple receivers, concurrent with senders; ring queue functionality cannot be validated in this case
+ if [[ $(cat receiver_${QUEUE_NAME}_* | wc -l) -le $(cat sender_${QUEUE_NAME}_* | wc -l) ]]; then
+ log "sent at least as many messages as were received"
+ else
+ #Note: if any receiver was browsing, this would be valid (would need to add 'sort | uniq')
+ # to pipeline above
+ fail "received more messages than were sent"
+ fi
+ fi
+
+ if [[ $FAILED ]]; then
+ echo $(basename $0): FAILED
+ exit 1
+ else
+ cleanup
+ fi
+}
+
+run_test() {
+ if [[ $CONCURRENT -eq 0 ]]; then
+ echo "Starting $SENDERS senders followed by $RECEIVERS receivers "
+ else
+ echo "Starting $SENDERS senders concurrently with $RECEIVERS receivers"
+ fi
+ for ((i=1; i <= $SENDERS; i++)); do
+ send $i &
+ sender_pids[$i]=$!
+ done
+ if [[ $CONCURRENT -eq 0 ]] && [[ $RECEIVERS -gt 0 ]]; then
+ wait
+ sender --routing-key $QUEUE_NAME --send-eos $RECEIVERS < /dev/null
+ fi
+ for ((i=1; i <= $RECEIVERS; i++)); do
+ receive $i &
+ done
+ if [[ $CONCURRENT -gt 0 ]]; then
+ for ((i=1; i <= $SENDERS; i++)); do
+ wait ${sender_pids[$i]}
+ done
+ sender --routing-key $QUEUE_NAME --send-eos $RECEIVERS < /dev/null
+ fi
+ wait
+}
+
+usage() {
+ cat <<EOF
+$(basename $0): Test script for validating the behaviour of a ring queue
+
+Options:
+ -q <queue> the name of the queue to use
+ -s <senders> the number of senders to start
+ -r <receivers> the number of receivers to start
+ -l <limit> the limit for the ring queue
+ -m <messages> the number of messages to send
+ -c if specified, receivers will run concurrently with senders
+ -d if specified the queue and messages will be durable
+EOF
+ exit 1
+}
+
+while getopts "s:r:m:u:dch" opt ; do
+ case $opt in
+ q) QUEUE_NAME=$OPTARG ;;
+ l) LIMIT=$OPTARG ;;
+ s) SENDERS=$OPTARG ;;
+ r) RECEIVERS=$OPTARG ;;
+ m) MESSAGES=$OPTARG ;;
+ d) DURABLE=1 ;;
+ c) CONCURRENT=1 ;;
+ h) usage;;
+ ?) usage;;
+ esac
+done
+
+if [[ $SENDERS -gt 0 ]]; then
+ setup
+ run_test
+ validate
+else
+ echo "Nothing can be done if there are no senders"
+fi
+
diff --git a/cpp/src/tests/run-unit-tests b/cpp/src/tests/run-unit-tests
index 464ce131f5..862a76c4f5 100755
--- a/cpp/src/tests/run-unit-tests
+++ b/cpp/src/tests/run-unit-tests
@@ -1,4 +1,24 @@
#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
#
# Library names (without path or .so) and CppUnit test paths can be
# specified on the command line or in env var UNIT_TESTS. For example:
diff --git a/cpp/src/tests/run_acl_tests b/cpp/src/tests/run_acl_tests
new file mode 100755
index 0000000000..7112f621a1
--- /dev/null
+++ b/cpp/src/tests/run_acl_tests
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Run the acl tests. $srcdir is set by the Makefile.
+source ./test_env.sh
+DATA_DIR=`pwd`/data_dir
+
+trap stop_brokers INT TERM QUIT
+
+start_brokers() {
+ ../qpidd --daemon --port 0 --no-module-dir --data-dir $DATA_DIR --load-module $ACL_LIB --acl-file policy.acl --auth no > qpidd.port
+ LOCAL_PORT=`cat qpidd.port`
+}
+
+stop_brokers() {
+ $QPIDD_EXEC --no-module-dir -q --port $LOCAL_PORT
+}
+
+test_loading_acl_from_absolute_path(){
+ POLICY_FILE=$srcdir/policy.acl
+ rm -f temp.log
+ PORT=`../qpidd --daemon --port 0 --no-module-dir --no-data-dir --auth no --load-module $ACL_LIB --acl-file $POLICY_FILE -t --log-to-file temp.log 2>/dev/null`
+ ACL_FILE=`grep "notice Read ACL file" temp.log | sed 's/^.*Read ACL file //'`
+ $QPIDD_EXEC --no-module-dir -q --port $PORT
+ if test "$ACL_FILE" != "\"$POLICY_FILE\""; then
+ echo "unable to load policy file from an absolute path";
+ return 1;
+ fi
+ rm temp.log
+}
+
+if test -d ${PYTHON_DIR} ; then
+ rm -rf $DATA_DIR
+ mkdir -p $DATA_DIR
+ cp $srcdir/policy.acl $DATA_DIR
+ start_brokers
+ echo "Running acl tests using brokers on ports $LOCAL_PORT"
+ PYTHONPATH=$PYTHON_DIR:$srcdir
+ export PYTHONPATH
+ $QPID_PYTHON_TEST -b localhost:$LOCAL_PORT -m acl || EXITCODE=1
+ stop_brokers || EXITCODE=1
+ test_loading_acl_from_absolute_path || EXITCODE=1
+ rm -rf $DATA_DIR
+ exit $EXITCODE
+fi
+
diff --git a/cpp/src/tests/run_cli_tests b/cpp/src/tests/run_cli_tests
new file mode 100755
index 0000000000..34ce3c4f1a
--- /dev/null
+++ b/cpp/src/tests/run_cli_tests
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Run the cli-utility tests.
+
+source ./test_env.sh
+CLI_DIR=$PYTHON_COMMANDS
+
+trap stop_brokers INT TERM QUIT
+
+start_brokers() {
+ ../qpidd --daemon --port 0 --no-data-dir --no-module-dir --auth no > qpidd.port
+ LOCAL_PORT=`cat qpidd.port`
+ ../qpidd --daemon --port 0 --no-data-dir --no-module-dir --auth no > qpidd.port
+ REMOTE_PORT=`cat qpidd.port`
+}
+
+stop_brokers() {
+ $QPIDD_EXEC --no-module-dir -q --port $LOCAL_PORT
+ $QPIDD_EXEC --no-module-dir -q --port $REMOTE_PORT
+}
+
+if test -d ${PYTHON_DIR} ; then
+ start_brokers
+ echo "Running CLI tests using brokers on ports $LOCAL_PORT $REMOTE_PORT"
+ $PYTHON_COMMANDS/qpid-python-test -m cli_tests -b localhost:$LOCAL_PORT -Dremote-port=$REMOTE_PORT -Dcli-dir=$CLI_DIR $@
+ RETCODE=$?
+ stop_brokers
+ if test x$RETCODE != x0; then
+ echo "FAIL CLI tests"; exit 1;
+ fi
+fi
+
diff --git a/cpp/src/tests/run_cluster_test b/cpp/src/tests/run_cluster_test
new file mode 100755
index 0000000000..c022eea1fe
--- /dev/null
+++ b/cpp/src/tests/run_cluster_test
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+
+# Run the tests
+srcdir=`dirname $0`
+. $srcdir/ais_check
+with_ais_group $srcdir/run_test ./cluster_test
diff --git a/cpp/src/tests/run_cluster_tests b/cpp/src/tests/run_cluster_tests
new file mode 100755
index 0000000000..6064f28751
--- /dev/null
+++ b/cpp/src/tests/run_cluster_tests
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+source ./test_env.sh
+source $srcdir/ais_check
+
+test -x $QPID_PYTHON_TEST || { echo Skipping test, $QPID_PYTHON_TEST not found; exit 0; }
+
+# Delete old cluster test data
+OUTDIR=brokertest.tmp
+rm -rf $OUTDIR
+mkdir -p $OUTDIR
+
+# Ignore tests requiring a store by default.
+CLUSTER_TESTS_IGNORE=${CLUSTER_TESTS_IGNORE:--i cluster_tests.StoreTests.* -I $srcdir/cluster_tests.fail}
+CLUSTER_TESTS=${CLUSTER_TESTS:-$*}
+
+with_ais_group $QPID_PYTHON_TEST -DOUTDIR=$OUTDIR -m cluster_tests $CLUSTER_TESTS_IGNORE $CLUSTER_TESTS || exit 1
+rm -rf $OUTDIR
+#exit 0
diff --git a/cpp/src/tests/run_failover_soak b/cpp/src/tests/run_failover_soak
new file mode 100755
index 0000000000..69551a51c2
--- /dev/null
+++ b/cpp/src/tests/run_failover_soak
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+source ./test_env.sh
+. $srcdir/ais_check
+
+host=127.0.0.1
+
+unset QPID_NO_MODULE_DIR # failover_soak uses --module-dir, dont want clash
+MODULES=${MODULES:-$moduledir}
+MESSAGES=${MESSAGES:-1000000}
+REPORT_FREQUENCY=${REPORT_FREQUENCY:-20000}
+VERBOSITY=${VERBOSITY:-10}
+DURABILITY=${DURABILITY:-0}
+N_QUEUES=${N_QUEUES:-1}
+N_BROKERS=${N_BROKERS:-3}
+
+rm -f soak-*.log
+exec ./failover_soak $MODULES ./declare_queues ./replaying_sender ./resuming_receiver $MESSAGES $REPORT_FREQUENCY $VERBOSITY $DURABILITY $N_QUEUES $N_BROKERS
+
diff --git a/cpp/src/tests/run_federation_tests b/cpp/src/tests/run_federation_tests
index 6142c1c37c..8d7954a533 100755
--- a/cpp/src/tests/run_federation_tests
+++ b/cpp/src/tests/run_federation_tests
@@ -1,7 +1,27 @@
#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# Run the federation tests.
-MY_DIR=`dirname \`which $0\``
-PYTHON_DIR=${MY_DIR}/../../../python
+
+source ./test_env.sh
trap stop_brokers INT TERM QUIT
@@ -13,20 +33,17 @@ start_brokers() {
}
stop_brokers() {
- ../qpidd -q --port $LOCAL_PORT
- ../qpidd -q --port $REMOTE_PORT
+ $QPIDD_EXEC --no-module-dir -q --port $LOCAL_PORT
+ $QPIDD_EXEC --no-module-dir -q --port $REMOTE_PORT
}
if test -d ${PYTHON_DIR} ; then
start_brokers
echo "Running federation tests using brokers on ports $LOCAL_PORT $REMOTE_PORT"
- PYTHONPATH=${PYTHON_DIR}
- export PYTHONPATH
- ${MY_DIR}/federation.py -v -s ${MY_DIR}/../../../specs/amqp.0-10-qpid-errata.xml -b localhost:$LOCAL_PORT --remote-port $REMOTE_PORT
+ $QPID_PYTHON_TEST -m federation -b localhost:$LOCAL_PORT -Dremote-port=$REMOTE_PORT $@
RETCODE=$?
stop_brokers
if test x$RETCODE != x0; then
echo "FAIL federation tests"; exit 1;
fi
fi
-
diff --git a/cpp/src/tests/run_federation_tests.ps1 b/cpp/src/tests/run_federation_tests.ps1
new file mode 100644
index 0000000000..dd0ea2fe5b
--- /dev/null
+++ b/cpp/src/tests/run_federation_tests.ps1
@@ -0,0 +1,80 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Run the federation tests.
+
+$srcdir = Split-Path $myInvocation.InvocationName
+$PYTHON_DIR = "$srcdir\..\..\..\python"
+if (!(Test-Path $PYTHON_DIR -pathType Container)) {
+ "Skipping federation tests as python libs not found"
+ exit 1
+}
+
+# Test runs from the tests directory but the broker executable is one level
+# up, and most likely in a subdirectory from there based on what build type.
+# Look around for it before trying to start it.
+$subs = "Debug","Release","MinSizeRel","RelWithDebInfo"
+foreach ($sub in $subs) {
+ $prog = "..\$sub\qpidd.exe"
+ if (Test-Path $prog) {
+ break
+ }
+}
+if (!(Test-Path $prog)) {
+ "Cannot locate qpidd.exe"
+ exit 1
+}
+$cmdline = "$prog --auth=no --no-module-dir --port=0 --log-to-file qpidd.log $args | foreach { set-content qpidd.port `$_ }"
+$cmdblock = $executioncontext.invokecommand.NewScriptBlock($cmdline)
+
+function start_brokers {
+ # Start 2 brokers, saving the port numbers in LOCAL_PORT, REMOTE_PORT.
+ . $srcdir\background.ps1 $cmdblock
+ while (!(Test-Path qpidd.port)) {
+ Start-Sleep 2
+ }
+ set-item -path env:LOCAL_PORT -value (get-content -path qpidd.port -totalcount 1)
+ Remove-Item qpidd.port
+ . $srcdir\background.ps1 $cmdblock
+ while (!(Test-Path qpidd.port)) {
+ Start-Sleep 2
+ }
+ set-item -path env:REMOTE_PORT -value (get-content -path qpidd.port -totalcount 1)
+}
+
+function stop_brokers {
+ Invoke-Expression "$prog -q --port $env:LOCAL_PORT" | Out-Default
+ Invoke-Expression "$prog -q --port $env:REMOTE_PORT" | Out-Default
+}
+
+trap {
+ &stop_brokers
+ break
+}
+
+&start_brokers
+"Running federation tests using brokers on ports $env:LOCAL_PORT $env:REMOTE_PORT"
+$env:PYTHONPATH=$PYTHON_DIR
+python $srcdir/federation.py -v -s $srcdir\..\..\..\specs\amqp.0-10-qpid-errata.xml -b localhost:$env:LOCAL_PORT --remote-port $env:REMOTE_PORT $args
+$RETCODE=$LASTEXITCODE
+&stop_brokers
+if ($RETCODE -ne 0) {
+ "FAIL federation tests"
+ exit 1
+}
diff --git a/cpp/src/tests/run_header_test b/cpp/src/tests/run_header_test
new file mode 100755
index 0000000000..07658343e7
--- /dev/null
+++ b/cpp/src/tests/run_header_test
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Simple test of encode/decode of a double in application headers
+# TODO: this should be expanded to cover a wider set of types and go
+# in both directions
+
+srcdir=`dirname $0`
+source ./test_env.sh
+
+test -f qpidd.port && QPID_PORT=`cat qpidd.port`
+
+if test -d ${PYTHON_DIR} ; then
+ ./header_test -p $QPID_PORT
+ $srcdir/header_test.py "localhost" $QPID_PORT
+else
+ echo "Skipping header test as python libs not found"
+fi
+
diff --git a/cpp/src/tests/run_header_test.ps1 b/cpp/src/tests/run_header_test.ps1
new file mode 100644
index 0000000000..7d3e43a30f
--- /dev/null
+++ b/cpp/src/tests/run_header_test.ps1
@@ -0,0 +1,47 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Simple test of encode/decode of a double in application headers
+# TODO: this should be expanded to cover a wider set of types and go
+# in both directions
+
+$srcdir = Split-Path $myInvocation.InvocationName
+$PYTHON_DIR = "$srcdir\..\..\..\python"
+if (!(Test-Path $PYTHON_DIR -pathType Container)) {
+ "Skipping header test as python libs not found"
+ exit 0
+}
+
+if (Test-Path qpidd.port) {
+ set-item -path env:QPID_PORT -value (get-content -path qpidd.port -totalcount 1)
+}
+
+# Test runs from the tests directory but the test executables are in a
+# subdirectory based on the build type. Look around for it before trying
+# to start it.
+. $srcdir\find_prog.ps1 .\header_test.exe
+if (!(Test-Path $prog)) {
+ "Cannot locate header_test.exe"
+ exit 1
+}
+
+Invoke-Expression "$prog -p $env:QPID_PORT" | Write-Output
+$env:PYTHONPATH="$PYTHON_DIR;$env:PYTHONPATH"
+Invoke-Expression "python $srcdir/header_test.py localhost $env:QPID_PORT" | Write-Output
+exit $LASTEXITCODE
diff --git a/cpp/src/tests/run_long_cluster_tests b/cpp/src/tests/run_long_cluster_tests
new file mode 100755
index 0000000000..cb9c6b219b
--- /dev/null
+++ b/cpp/src/tests/run_long_cluster_tests
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+srcdir=`dirname $0`
+$srcdir/run_cluster_tests long_cluster_tests
diff --git a/cpp/src/tests/run_perftest b/cpp/src/tests/run_perftest
index c1e66294c1..1a9b934641 100755
--- a/cpp/src/tests/run_perftest
+++ b/cpp/src/tests/run_perftest
@@ -1,4 +1,24 @@
#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# Args: count [perftest options...]
# Run a perftest with count multiplied.
#
diff --git a/cpp/src/tests/run_ring_queue_test b/cpp/src/tests/run_ring_queue_test
new file mode 100755
index 0000000000..7ca870841e
--- /dev/null
+++ b/cpp/src/tests/run_ring_queue_test
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#script to run a sequence of ring queue tests via make
+
+#setup path to find qpid-config and sender/receiver test progs
+source ./test_env.sh
+
+export PATH=$PWD:$srcdir:$PYTHON_COMMANDS:$PATH
+
+#set port to connect to via env var
+test -s qpidd.port && QPID_PORT=`cat qpidd.port`
+export QPID_PORT
+
+ring_queue_test -c -s 4 -r 4
+ring_queue_test -s 4 -r 0
+ring_queue_test -s 1 -r 1
+
+
diff --git a/cpp/src/tests/run_test b/cpp/src/tests/run_test
index 4d0da15d4c..4b227621bc 100755
--- a/cpp/src/tests/run_test
+++ b/cpp/src/tests/run_test
@@ -1,11 +1,30 @@
#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
#
# Set up environment and run a test executable or script.
#
# Output nothing if test passes, show the output if it fails and
# leave output in <test>.log for examination.
#
-# If qpidd.port exists run test with QPID_PORT=`cat qpidd.port`
+# If qpidd.port exists and is not empty run test with QPID_PORT=`cat qpidd.port`
#
# If $VALGRIND if is set run under valgrind. If there are valgrind
# erros show valgrind output, also leave it in <test>.valgrind for
@@ -13,13 +32,14 @@
#
srcdir=`dirname $0`
-. $srcdir/vg_check
+source ./test_env.sh
+source $srcdir/vg_check
# Export variables from makefile.
-export VALGRIND srcdir
+export srcdir
# Set QPID_PORT if qpidd.port exists.
-test -f qpidd.port && QPID_PORT=`cat qpidd.port`
+test -s qpidd.port && QPID_PORT=`cat qpidd.port`
export QPID_PORT
# Avoid silly libtool error messages if these are not defined
@@ -32,27 +52,30 @@ export LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
VG_LOG="`basename $1`.vglog"
rm -f $VG_LOG*
-VALGRIND_OPTS="
---gen-suppressions=all
+# Use VALGRIND_OPTS="--gen-suppressions=all" to generated suppressions
+VALGRIND_OPTS="$VALGRIND_OPTS
--leak-check=full
--demangle=yes
--suppressions=$srcdir/.valgrind.supp
--num-callers=25
--log-file=$VG_LOG --
"
-# FIXME aconway 2008-07-16: removed --trace-children=yes, problems with cluster tests forking
-# qpidd libtool script. Investigate & restore --trace-children if possible.
-
ERROR=0
if grep -l "^# Generated by .*libtool" "$1" >/dev/null 2>&1; then
# This is a libtool "executable". Valgrind it if VALGRIND specified.
test -n "$VALGRIND" && VALGRIND="$VALGRIND $VALGRIND_OPTS"
# Hide output unless there's an error.
- libtool --mode=execute $VALGRIND "$@" 2>&1 || ERROR=1
+ $LIBTOOL --mode=execute $VALGRIND "$@" 2>&1 || ERROR=1
test -n "$VALGRIND" && { vg_check $VG_LOG* || ERROR=1 ; }
-else
+elif file $1 | grep -q text; then
# This is a non-libtool shell script, just execute it.
exec "$@"
+else
+ # This is a real executable, valgrind it.
+ test -n "$VALGRIND" && VALGRIND="$VALGRIND $VALGRIND_OPTS"
+ # Hide output unless there's an error.
+ $VALGRIND "$@" 2>&1 || ERROR=1
+ test -n "$VALGRIND" && { vg_check $VG_LOG* || ERROR=1 ; }
fi
exit $ERROR
diff --git a/cpp/src/tests/run_test.ps1 b/cpp/src/tests/run_test.ps1
new file mode 100644
index 0000000000..4deb07bf71
--- /dev/null
+++ b/cpp/src/tests/run_test.ps1
@@ -0,0 +1,73 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+$srcdir = Split-Path $myInvocation.InvocationName
+
+# Set up environment and run a test executable or script.
+$env:QPID_DATA_DIR = ""
+$env:BOOST_TEST_SHOW_PROGRESS = "yes"
+
+# The test exe is probably not in the current binary dir - it's usually
+# placed in a subdirectory based on the configuration built in Visual Studio.
+# So check around to see where it is - when located, set the QPID_LIB_DIR
+# and PATH to look in the corresponding configuration off the src directory,
+# one level up.
+$prog = $args[0]
+$is_script = $prog -match ".ps1$"
+if (Test-Path $prog) {
+ $env:QPID_LIB_DIR = ".."
+ $env:PATH += ";.."
+}
+else {
+ . $srcdir\find_prog.ps1 $prog
+ $args[0] = $prog
+ $env:QPID_LIB_DIR = "..\$sub"
+ $env:PATH += "$dir\$sub;..\$sub"
+}
+
+# If qpidd.port exists and is not empty run test with QPID_PORT set.
+if (Test-Path qpidd.port) {
+ set-item -path env:QPID_PORT -value (get-content -path qpidd.port -totalcount 1)
+}
+
+$si = new-object System.Diagnostics.ProcessStartInfo
+$si.WorkingDirectory = $pwd
+$si.UseShellExecute = $false
+$si.CreateNoWindow = $true
+$si.RedirectStandardOutput = $true
+if ($is_script) {
+ $si.FileName = (get-command powershell.exe).Definition
+ $si.Arguments = $args
+}
+else {
+ $si.FileName = $args[0]
+ if ($args.length -gt 1) {
+ $si.Arguments = $args[1..($args.length-1)]
+ }
+}
+$p = [System.Diagnostics.Process]::Start($si)
+$line = ""
+while (($line = $p.StandardOutput.ReadLine()) -ne $null) {
+ $line
+}
+# ReadToEnd() works, but doesn't show any output until the program exits.
+#$p.StandardOutput.ReadToEnd()
+$p.WaitForExit()
+$status = $p.ExitCode
+exit $status
diff --git a/cpp/src/tests/sender.cpp b/cpp/src/tests/sender.cpp
new file mode 100644
index 0000000000..4e845c42b4
--- /dev/null
+++ b/cpp/src/tests/sender.cpp
@@ -0,0 +1,137 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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/client/FailoverManager.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/AsyncSession.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/MessageReplayTracker.h>
+#include <qpid/client/QueueOptions.h>
+#include <qpid/Exception.h>
+#include "TestOptions.h"
+
+#include <fstream>
+#include <iostream>
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using namespace std;
+
+namespace qpid {
+namespace tests {
+
+struct Args : public qpid::TestOptions
+{
+ string destination;
+ string key;
+ uint sendEos;
+ bool durable;
+ uint ttl;
+ string lvqMatchValue;
+ string lvqMatchFile;
+
+ Args() : key("test-queue"), sendEos(0), durable(false), ttl(0)
+ {
+ addOptions()
+ ("exchange", qpid::optValue(destination, "EXCHANGE"), "Exchange to send messages to")
+ ("routing-key", qpid::optValue(key, "KEY"), "Routing key to add to messages")
+ ("send-eos", qpid::optValue(sendEos, "N"), "Send N EOS messages to mark end of input")
+ ("durable", qpid::optValue(durable, "true|false"), "Mark messages as durable.")
+ ("ttl", qpid::optValue(ttl, "msecs"), "Time-to-live for messages, in milliseconds")
+ ("lvq-match-value", qpid::optValue(lvqMatchValue, "KEY"), "The value to set for the LVQ match key property")
+ ("lvq-match-file", qpid::optValue(lvqMatchFile, "FILE"), "A file containing values to set for the LVQ match key property");
+ }
+};
+
+const string EOS("eos");
+
+class Sender : public FailoverManager::Command
+{
+ public:
+ Sender(const std::string& destination, const std::string& key, uint sendEos, bool durable, uint ttl,
+ const std::string& lvqMatchValue, const std::string& lvqMatchFile);
+ void execute(AsyncSession& session, bool isRetry);
+ private:
+ const std::string destination;
+ MessageReplayTracker sender;
+ Message message;
+ const uint sendEos;
+ uint sent;
+ std::ifstream lvqMatchValues;
+};
+
+Sender::Sender(const std::string& dest, const std::string& key, uint eos, bool durable, uint ttl, const std::string& lvqMatchValue, const std::string& lvqMatchFile) :
+ destination(dest), sender(10), message("", key), sendEos(eos), sent(0) , lvqMatchValues(lvqMatchFile.c_str())
+{
+ if (durable){
+ message.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
+ }
+
+ if (ttl) {
+ message.getDeliveryProperties().setTtl(ttl);
+ }
+
+ if (!lvqMatchValue.empty()) {
+ message.getHeaders().setString(QueueOptions::strLVQMatchProperty, lvqMatchValue);
+ }
+}
+
+void Sender::execute(AsyncSession& session, bool isRetry)
+{
+ if (isRetry) sender.replay(session);
+ else sender.init(session);
+ string data;
+ while (getline(std::cin, data)) {
+ message.setData(data);
+ message.getHeaders().setInt("sn", ++sent);
+ string matchKey;
+ if (lvqMatchValues && getline(lvqMatchValues, matchKey)) {
+ message.getHeaders().setString(QueueOptions::strLVQMatchProperty, matchKey);
+ }
+ sender.send(message, destination);
+ }
+ for (uint i = sendEos; i > 0; --i) {
+ message.setData(EOS);
+ sender.send(message, destination);
+ }
+}
+
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
+int main(int argc, char ** argv)
+{
+ Args opts;
+ try {
+ opts.parse(argc, argv);
+ FailoverManager connection(opts.con);
+ Sender sender(opts.destination, opts.key, opts.sendEos, opts.durable, opts.ttl, opts.lvqMatchValue, opts.lvqMatchFile);
+ connection.execute(sender);
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << "Failed: " << error.what() << std::endl;
+ }
+ return 1;
+}
diff --git a/cpp/src/tests/shared_perftest b/cpp/src/tests/shared_perftest
index 212ba22df4..cc192d25bd 100755
--- a/cpp/src/tests/shared_perftest
+++ b/cpp/src/tests/shared_perftest
@@ -1,2 +1,22 @@
#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
exec `dirname $0`/run_perftest 100000 --mode shared --npubs 16 --nsubs 16
diff --git a/cpp/src/tests/shlibtest.cpp b/cpp/src/tests/shlibtest.cpp
index 80320ea7be..5655eb7e64 100644
--- a/cpp/src/tests/shlibtest.cpp
+++ b/cpp/src/tests/shlibtest.cpp
@@ -18,11 +18,17 @@
*
*/
+namespace qpid {
+namespace tests {
+
int* loaderData = 0;
-extern "C" void callMe(int *i) { loaderData=i; }
+extern "C"
+#ifdef WIN32
+__declspec(dllexport)
+#endif
+void callMe(int *i) { loaderData=i; }
struct OnUnload { ~OnUnload() { *loaderData=42; } };
OnUnload unloader; // For destructor.
-
-
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/ssl.mk b/cpp/src/tests/ssl.mk
new file mode 100644
index 0000000000..cb887c8fda
--- /dev/null
+++ b/cpp/src/tests/ssl.mk
@@ -0,0 +1,23 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+TESTS+=ssl_test
+EXTRA_DIST+=ssl_test
+clean-local:
+ rm -rf test_cert_db cert.password \ No newline at end of file
diff --git a/cpp/src/tests/ssl_test b/cpp/src/tests/ssl_test
new file mode 100755
index 0000000000..528833076e
--- /dev/null
+++ b/cpp/src/tests/ssl_test
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Run a simple test over SSL
+source ./test_env.sh
+
+CONFIG=$(dirname $0)/config.null
+CERT_DIR=`pwd`/test_cert_db
+CERT_PW_FILE=`pwd`/cert.password
+TEST_HOSTNAME=127.0.0.1
+COUNT=10
+
+trap cleanup EXIT
+
+error() { echo $*; exit 1; }
+
+create_certs() {
+ #create certificate and key databases with single, simple, self-signed certificate in it
+ mkdir ${CERT_DIR}
+ certutil -N -d ${CERT_DIR} -f ${CERT_PW_FILE}
+ certutil -S -d ${CERT_DIR} -n ${TEST_HOSTNAME} -s "CN=${TEST_HOSTNAME}" -t "CT,," -x -f ${CERT_PW_FILE} -z /usr/bin/certutil
+}
+
+delete_certs() {
+ if [[ -e ${CERT_DIR} ]] ; then
+ rm -rf ${CERT_DIR}
+ fi
+}
+
+start_broker() {
+ PORT=`../qpidd --daemon --transport ssl --port 0 --ssl-port 0 --no-data-dir --no-module-dir --auth no --config $CONFIG --load-module $SSL_LIB --ssl-cert-db $CERT_DIR --ssl-cert-password-file $CERT_PW_FILE --ssl-cert-name $TEST_HOSTNAME`
+}
+
+stop_broker() {
+ if [[ $PORT ]] ; then
+ $QPIDD_EXEC --no-module-dir -q --port $PORT
+ fi
+}
+
+cleanup() {
+ stop_broker
+ delete_certs
+}
+
+CERTUTIL=$(type -p certutil)
+if [[ !(-x $CERTUTIL) ]] ; then
+ echo "No certutil, skipping ssl test";
+ exit 0;
+fi
+
+if [[ !(-e ${CERT_PW_FILE}) ]] ; then
+ echo password > ${CERT_PW_FILE}
+fi
+delete_certs
+create_certs || error "Could not create test certificate"
+
+start_broker || error "Could not start broker"
+echo "Running SSL test on port $PORT"
+export QPID_NO_MODULE_DIR=1
+export QPID_LOAD_MODULE=$SSLCONNECTOR_LIB
+export QPID_SSL_CERT_DB=${CERT_DIR}
+export QPID_SSL_CERT_PASSWORD_FILE=${CERT_PW_FILE}
+./perftest --count ${COUNT} --port ${PORT} -P ssl -b $TEST_HOSTNAME --summary
+
diff --git a/cpp/src/tests/start_broker b/cpp/src/tests/start_broker
index aabe12ad43..093c44051a 100755
--- a/cpp/src/tests/start_broker
+++ b/cpp/src/tests/start_broker
@@ -1,4 +1,24 @@
#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# Start a test broker.
srcdir=`dirname $0`
-exec $srcdir/run_test ../qpidd --auth=no --no-module-dir --daemon --port=0 --log-output qpidd.log "$@" > qpidd.port
+exec $srcdir/run_test ../qpidd --auth=no --no-module-dir --daemon --port=0 --log-to-file qpidd.log "$@" > qpidd.port
diff --git a/cpp/src/tests/start_broker.ps1 b/cpp/src/tests/start_broker.ps1
new file mode 100644
index 0000000000..9263262b9f
--- /dev/null
+++ b/cpp/src/tests/start_broker.ps1
@@ -0,0 +1,60 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Get the directory where this script resides.
+function Get-ScriptPath
+ { Split-Path $myInvocation.ScriptName }
+
+# Start a test broker and capture it's port (from stdout) to qpidd.port
+# This script will exit immediately after spawning the broker process. To avoid
+# running more tests before the broker is initialized, wait for the qpidd.port
+# file to appear before exiting.
+if (Test-Path qpidd.port) {
+ Remove-Item qpidd.port
+}
+
+# Test runs from the tests directory but the broker executable is one level
+# up, and most likely in a subdirectory from there based on what build type.
+# Look around for it before trying to start it.
+$subs = "Debug","Release","MinSizeRel","RelWithDebInfo"
+foreach ($sub in $subs) {
+ $prog = "..\$sub\qpidd.exe"
+ if (Test-Path $prog) {
+ break
+ }
+}
+if (!(Test-Path $prog)) {
+ "Cannot locate qpidd.exe"
+ exit 1
+}
+$cmdline = "$prog --auth=no --no-module-dir --port=0 --log-to-file qpidd.log $args | foreach { set-content qpidd.port `$_ }"
+$cmdblock = $executioncontext.invokecommand.NewScriptBlock($cmdline)
+$srcdir = Get-ScriptPath
+. $srcdir\background.ps1 $cmdblock
+
+$wait_time = 0
+while (!(Test-Path qpidd.port) -and ($wait_time -lt 10)) {
+ Start-Sleep 2
+ $wait_time += 2
+}
+if (Test-Path qpidd.port) {
+ exit 0
+}
+"Time out waiting for broker to start"
+exit 1
diff --git a/cpp/src/tests/start_cluster b/cpp/src/tests/start_cluster
index 55f989a3e9..bc35a2eddc 100755
--- a/cpp/src/tests/start_cluster
+++ b/cpp/src/tests/start_cluster
@@ -1,26 +1,42 @@
#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# Start a cluster of brokers on local host, put the list of ports for cluster members in cluster.ports
#
# Execute command with the ais group set.
-with_ais_group() {
- id -nG | grep '\<ais\>' >/dev/null || { echo "You are not a member of the ais group." 1>&2; exit 1; }
- echo $* | newgrp ais
-}
-
-test -f cluster.ports && { echo "cluster.ports file already exists" ; exit 1; }
-rm -f cluster*.log
-SIZE=$1; shift
-CLUSTER=`pwd` # Cluster name=pwd, avoid clashes.
-OPTS="-d --load-module ../.libs/libqpidcluster.so --cluster-name=$CLUSTER --no-data-dir --auth=no $*"
-
-if test "$SIZE" = "one"; then # Special case of singleton cluster, use default port.
- ../qpidd -q
- with_ais_group ../qpidd $OPTS || exit 1
-else
- for (( i=0; i<SIZE; ++i )); do
- PORT=`with_ais_group ../qpidd -p0 --log-output=cluster$i.log $OPTS` || exit 1
- echo $PORT >> cluster.ports
- done
-fi
+source ./test_env.sh
+. `dirname $0`/ais_check
+
+rm -f cluster*.log cluster.ports qpidd.port
+
+SIZE=${1:-3}; shift
+CLUSTER=$HOSTNAME.$$
+OPTS="-d --no-module-dir --load-module $CLUSTER_LIB --cluster-name=$CLUSTER --auth=no --log-enable notice+ --log-enable debug+:cluster $@"
+
+for (( i=0; i<SIZE; ++i )); do
+ DDIR=`mktemp -d /tmp/start_cluster.XXXXXXXXXX`
+ PORT=`with_ais_group ../qpidd -p0 --log-to-file=cluster$i.log $OPTS --data-dir=$DDIR` || exit 1
+ echo $PORT >> cluster.ports
+done
+
+head -n 1 cluster.ports > qpidd.port # First member's port for tests.
diff --git a/cpp/src/tests/start_cluster_hosts b/cpp/src/tests/start_cluster_hosts
new file mode 100755
index 0000000000..778b4248da
--- /dev/null
+++ b/cpp/src/tests/start_cluster_hosts
@@ -0,0 +1,70 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#
+# Start a cluster of brokers on local host, put the list of host port addresses
+# in cluster.ports
+#
+# Arguments: [-k] [-p port] HOST [HOST...]
+# -p port to start broker on, can be 0. Actual ports recorded in cluster.addr.
+# -k kill any qpidd processes owned by this user before starting.
+#
+# Start a broker on each named host. Name a host twice to start multiple brokers.
+#
+# You must be able to ssh to each host and be in group ais.
+# $QPIDD must be executable on each host.
+# Logs go to syslog on each host, with a unique prefix per broker.
+#
+
+QPIDD=${QPIDD:-$PWD/../qpidd}
+LIBQPIDCLUSTER=${LIBQPIDCLUSTER:-$PWD/../.libs/cluster.so}
+NAME=$USER # User name is default cluster name.
+RESTART=NO
+
+while getopts "kp:n:q:r" ARG ; do
+ case $ARG in
+ k) KILL=yes ;;
+ p) PORT="$OPTARG" ;;
+ n) NAME=$OPTARG ;;
+ q) QPIDD=$OPTARG ;;
+ l) LIBQPIDCLUSTER=$OPTARG ;;
+ r) RESTART=yes ;;
+ *) echo "Error parsing options: $ARG"; exit 1 ;;
+ esac
+done
+shift `expr $OPTIND - 1`
+test -n "$PORT" && PORTOPT="-p $PORT"
+test "$KILL" = yes && KILL="$QPIDD --no-module-dir -q $PORTOPT ;"
+CLUSTER=${*:-$CLUSTER} # Use args or env
+test -z "$CLUSTER" && { echo Must specify at least one host; exit 1; }
+
+
+OPTS="-d $PORTOPT --load-module $LIBQPIDCLUSTER --cluster-name=$NAME --no-data-dir --auth=no --log-to-syslog --log-enable=info+"
+
+num=0
+for h in $CLUSTER; do
+ num=`expr $num + 1` # Give a unique log prefix to each node.
+ cmd="$KILL $QPIDD $OPTS --log-prefix $num.$h"
+ out=`echo "$cmd" | ssh $h newgrp ais` || { echo == $h error: $out ; exit 1; }
+ if [ "$PORT" = 0 ] ; then p=$out; else p=$PORT; fi
+ echo "$h $p"
+done
+
diff --git a/cpp/src/tests/stop_broker b/cpp/src/tests/stop_broker
index 6912795fca..248fd1fc5c 100755
--- a/cpp/src/tests/stop_broker
+++ b/cpp/src/tests/stop_broker
@@ -1,11 +1,31 @@
#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# Stop the broker, check for errors.
#
QPID_PORT=`cat qpidd.port`
export QPID_PORT
rm -f qpidd.port
-../qpidd --quit || ERROR=1
+../qpidd --no-module-dir --quit || ERROR=1
# Check qpidd.log.
egrep 'warning\|error\|critical' qpidd.log && {
diff --git a/cpp/src/tests/stop_broker.ps1 b/cpp/src/tests/stop_broker.ps1
new file mode 100644
index 0000000000..4fdeb26e2b
--- /dev/null
+++ b/cpp/src/tests/stop_broker.ps1
@@ -0,0 +1,56 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Stop the broker, check for errors.
+Get-Content -path qpidd.port -totalCount 1 | Set-Variable -name qpid_port
+Remove-Item qpidd.port
+
+# Test runs from the tests directory but the broker executable is one level
+# up, and most likely in a subdirectory from there based on what build type.
+# Look around for it before trying to start it.
+$subs = "Debug","Release","MinSizeRel","RelWithDebInfo"
+foreach ($sub in $subs) {
+ $prog = "..\$sub\qpidd.exe"
+ if (Test-Path $prog) {
+ break
+ }
+}
+if (!(Test-Path $prog)) {
+ "Cannot locate qpidd.exe"
+ exit 1
+}
+
+# Piping the output makes the script wait for qpidd to finish.
+Invoke-Expression "$prog --quit --port $qpid_port" | Write-Output
+$stopped = $?
+
+# Check qpidd.log.
+filter bad_stuff {
+ $_ -match "( warning | error | critical )"
+}
+
+$qpidd_errors = $false
+Get-Content -path qpidd.log | where { bad_stuff } | Out-Default | Set-Variable -name qpidd_errors -value $true
+if ($qpidd_errors -eq $true) {
+ "WARNING: Suspicious broker log entries in qpidd.log, above."
+}
+if ($stopped -eq $true) {
+ exit 0
+}
+exit 1
diff --git a/cpp/src/tests/stop_cluster b/cpp/src/tests/stop_cluster
index 9bd05092de..d598a2255a 100755
--- a/cpp/src/tests/stop_cluster
+++ b/cpp/src/tests/stop_cluster
@@ -1,11 +1,31 @@
#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# Stop brokers on ports listed in cluster.ports
PORTS=`cat cluster.ports`
for PORT in $PORTS ; do
- ../qpidd -qp $PORT || ERROR="$ERROR $PORT"
+ $QPIDD_EXEC --no-module-dir -qp $PORT || ERROR="$ERROR $PORT"
done
-rm -f cluster.ports
+rm -f cluster.ports qpidd.port
if [ -n "$ERROR" ]; then
echo "Errors stopping brokers on ports: $ERROR"
diff --git a/cpp/src/tests/test_env.sh.in b/cpp/src/tests/test_env.sh.in
new file mode 100644
index 0000000000..32c010b9be
--- /dev/null
+++ b/cpp/src/tests/test_env.sh.in
@@ -0,0 +1,68 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+absdir() { echo `cd $1 && pwd`; }
+
+# Environment variables substituted by configure/cmake.
+srcdir=@abs_srcdir@
+builddir=@abs_builddir@
+top_srcdir=@abs_top_srcdir@
+top_builddir=@abs_top_builddir@
+moduledir=$top_builddir/src@builddir_lib_suffix@
+testmoduledir=$builddir@builddir_lib_suffix@
+
+# Python paths and directories
+export PYTHON_DIR=$builddir/python
+export QPID_PYTHON_TEST=$PYTHON_DIR/commands/qpid-python-test
+if [ ! -d $PYTHON_DIR -a -d $top_srcdir/../python ]; then
+ export PYTHON_DIR=$top_srcdir/../python
+ export QPID_PYTHON_TEST=$PYTHON_DIR/qpid-python-test
+fi
+export PYTHON_COMMANDS=$PYTHON_DIR/commands
+export PYTHONPATH=$srcdir:$PYTHON_DIR:$PYTHON_COMMANDS:$PYTHONPATH
+export QPID_CONFIG_EXEC=$PYTHON_COMMANDS/qpid-config
+export QPID_ROUTE_EXEC=$PYTHON_COMMANDS/qpid-route
+export QPID_CLUSTER_EXEC=$PYTHON_COMMANDS/qpid-cluster
+
+# Executables
+export QPIDD_EXEC=$top_builddir/src/qpidd
+export QPID_WATCHDOG_EXEC=$top_builddir/src/qpidd_watchdog
+
+# Test executables
+export QPID_TEST_EXEC_DIR=$builddir
+export RECEIVER_EXEC=$QPID_TEST_EXEC_DIR/receiver
+export SENDER_EXEC=$QPID_TEST_EXEC_DIR/sender
+
+# Modules
+export TEST_STORE_LIB=$testmoduledir/test_store.so
+
+exportmodule() { test -f $moduledir/$2 && eval "export $1=$moduledir/$2"; }
+exportmodule ACL_LIB acl.so
+exportmodule CLUSTER_LIB cluster.so
+exportmodule REPLICATING_LISTENER_LIB replicating_listener.so
+exportmodule REPLICATION_EXCHANGE_LIB replication_exchange.so
+exportmodule SSLCONNECTOR_LIB sslconnector.so
+exportmodule SSL_LIB ssl.so
+exportmodule WATCHDOG_LIB watchdog.so
+exportmodule XML_LIB xml.so
+
+# Qpid options
+export QPID_NO_MODULE_DIR=1 # Don't accidentally load installed modules
+export QPID_DATA_DIR= # Default to no data dir, not ~/.qpidd
+
diff --git a/cpp/src/tests/test_store.cpp b/cpp/src/tests/test_store.cpp
new file mode 100644
index 0000000000..257e77b6b4
--- /dev/null
+++ b/cpp/src/tests/test_store.cpp
@@ -0,0 +1,178 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+/**@file
+ * Plug-in message store for tests.
+ *
+ * Add functionality as required, build up a comprehensive set of
+ * features to support persistent behavior tests.
+ *
+ * Current features special "action" messages can:
+ * - raise exception from enqueue.
+ * - force host process to exit.
+ * - do async completion after a delay.
+ */
+
+#include "qpid/broker/NullMessageStore.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/log/Statement.h"
+#include "qpid/Plugin.h"
+#include "qpid/Options.h"
+#include <boost/cast.hpp>
+#include <boost/lexical_cast.hpp>
+#include <memory>
+#include <fstream>
+
+using namespace qpid;
+using namespace broker;
+using namespace std;
+using namespace qpid::sys;
+
+namespace qpid {
+namespace tests {
+
+struct TestStoreOptions : public Options {
+
+ string name;
+ string dump;
+
+ TestStoreOptions() : Options("Test Store Options") {
+ addOptions()
+ ("test-store-name", optValue(name, "NAME"), "Name of test store instance.")
+ ("test-store-dump", optValue(dump, "FILE"), "File to dump enqueued messages.")
+ ;
+ }
+};
+
+struct Completer : public Runnable {
+ boost::intrusive_ptr<PersistableMessage> message;
+ int usecs;
+ Completer(boost::intrusive_ptr<PersistableMessage> m, int u) : message(m), usecs(u) {}
+ void run() {
+ qpid::sys::usleep(usecs);
+ message->enqueueComplete();
+ delete this;
+ }
+};
+
+class TestStore : public NullMessageStore {
+ public:
+ TestStore(const TestStoreOptions& opts, Broker& broker_)
+ : options(opts), name(opts.name), broker(broker_)
+ {
+ QPID_LOG(info, "TestStore name=" << name << " dump=" << options.dump);
+ if (!options.dump.empty())
+ dump.reset(new ofstream(options.dump.c_str()));
+ }
+
+ ~TestStore() {
+ for_each(threads.begin(), threads.end(), boost::bind(&Thread::join, _1));
+ }
+
+ virtual bool isNull() const { return false; }
+
+ void enqueue(TransactionContext* ,
+ const boost::intrusive_ptr<PersistableMessage>& pmsg,
+ const PersistableQueue& )
+ {
+ Message* msg = dynamic_cast<Message*>(pmsg.get());
+ assert(msg);
+
+ // Dump the message if there is a dump file.
+ if (dump.get()) {
+ msg->getFrames().getMethod()->print(*dump);
+ *dump << endl << " ";
+ msg->getFrames().getHeaders()->print(*dump);
+ *dump << endl << " ";
+ *dump << msg->getFrames().getContentSize() << endl;
+ }
+
+ // Check the message for special instructions.
+ string data = msg->getFrames().getContent();
+ size_t i = string::npos;
+ size_t j = string::npos;
+ if (strncmp(data.c_str(), TEST_STORE_DO.c_str(), strlen(TEST_STORE_DO.c_str())) == 0
+ && (i = data.find(name+"[")) != string::npos
+ && (j = data.find("]", i)) != string::npos)
+ {
+ size_t start = i+name.size()+1;
+ string action = data.substr(start, j-start);
+
+ if (action == EXCEPTION) {
+ throw Exception(QPID_MSG("TestStore " << name << " throwing exception for: " << data));
+ }
+ else if (action == EXIT_PROCESS) {
+ // FIXME aconway 2009-04-10: this is a dubious way to
+ // close the process at best, it can cause assertions or seg faults
+ // rather than clean exit.
+ QPID_LOG(critical, "TestStore " << name << " forcing process exit for: " << data);
+ exit(0);
+ }
+ else if (strncmp(action.c_str(), ASYNC.c_str(), strlen(ASYNC.c_str())) == 0) {
+ std::string delayStr(action.substr(ASYNC.size()));
+ int delay = boost::lexical_cast<int>(delayStr);
+ threads.push_back(Thread(*new Completer(msg, delay)));
+ }
+ else {
+ QPID_LOG(error, "TestStore " << name << " unknown action " << action);
+ msg->enqueueComplete();
+ }
+ }
+ else
+ msg->enqueueComplete();
+ }
+
+ private:
+ static const string TEST_STORE_DO, EXCEPTION, EXIT_PROCESS, ASYNC;
+ TestStoreOptions options;
+ string name;
+ Broker& broker;
+ vector<Thread> threads;
+ std::auto_ptr<ofstream> dump;
+};
+
+const string TestStore::TEST_STORE_DO = "TEST_STORE_DO: ";
+const string TestStore::EXCEPTION = "exception";
+const string TestStore::EXIT_PROCESS = "exit_process";
+const string TestStore::ASYNC="async ";
+
+struct TestStorePlugin : public Plugin {
+
+ TestStoreOptions options;
+
+ Options* getOptions() { return &options; }
+
+ void earlyInitialize (Plugin::Target& target)
+ {
+ Broker* broker = dynamic_cast<Broker*>(&target);
+ if (!broker) return;
+ boost::shared_ptr<MessageStore> p(new TestStore(options, *broker));
+ broker->setStore (p);
+ }
+
+ void initialize(qpid::Plugin::Target&) {}
+};
+
+static TestStorePlugin pluginInstance;
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/test_tools.h b/cpp/src/tests/test_tools.h
index 32127b0442..bb2509fd32 100644
--- a/cpp/src/tests/test_tools.h
+++ b/cpp/src/tests/test_tools.h
@@ -18,15 +18,18 @@
* limitations under the License.
*
*/
+#include "qpid/log/Logger.h"
#include <limits.h> // Include before boost/test headers.
-
#include <boost/test/test_tools.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/regex.hpp>
#include <boost/assign/list_of.hpp>
#include <vector>
+#include <set>
#include <ostream>
+#include <sstream>
+#include <exception>
// Print a sequence
template <class T> std::ostream& seqPrint(std::ostream& o, const T& seq) {
@@ -34,7 +37,7 @@ template <class T> std::ostream& seqPrint(std::ostream& o, const T& seq) {
return o;
}
-// Compare sequences
+// Compare sequences
template <class T, class U>
bool seqEqual(const T& a, const U& b) {
typename T::const_iterator i = a.begin();
@@ -43,14 +46,17 @@ bool seqEqual(const T& a, const U& b) {
return (i == a.end()) && (j == b.end());
}
-// ostream and == operators so we can compare vectors and boost::assign::list_of
-// with BOOST_CHECK_EQUALS
+// ostream and == operators so we can compare vectors and sets with
+// boost::assign::list_of with BOOST_CHECK_EQUALS
namespace std { // In namespace std so boost can find them.
template <class T>
ostream& operator<<(ostream& o, const vector<T>& v) { return seqPrint(o, v); }
template <class T>
+ostream& operator<<(ostream& o, const set<T>& v) { return seqPrint(o, v); }
+
+template <class T>
ostream& operator<<(ostream& o, const boost::assign_detail::generic_list<T>& l) { return seqPrint(o, l); }
template <class T>
@@ -58,8 +64,17 @@ bool operator == (const vector<T>& a, const boost::assign_detail::generic_list<T
template <class T>
bool operator == (const boost::assign_detail::generic_list<T>& b, const vector<T>& a) { return seqEqual(a, b); }
+
+template <class T>
+bool operator == (const set<T>& a, const boost::assign_detail::generic_list<T>& b) { return seqEqual(a, b); }
+
+template <class T>
+bool operator == (const boost::assign_detail::generic_list<T>& b, const set<T>& a) { return seqEqual(a, b); }
}
+namespace qpid {
+namespace tests {
+
/** NB: order of parameters is regex first, in line with
* CHECK(expected, actual) convention.
*/
@@ -78,5 +93,30 @@ inline bool regexPredicate(const std::string& re, const std::string& text) {
/** Check if types of two objects (as given by typeinfo::name()) match. */
#define BOOST_CHECK_TYPEID_EQUAL(a,b) BOOST_CHECK_EQUAL(typeid(a).name(),typeid(b).name())
+/**
+ * Supress all logging in a scope, restore to previous configuration in destructor.
+ */
+struct ScopedSuppressLogging {
+ typedef qpid::log::Logger Logger;
+ ScopedSuppressLogging(Logger& l=Logger::instance()) : logger(l), opts(l.getOptions()) { l.clear(); }
+ ~ScopedSuppressLogging() { logger.configure(opts); }
+ Logger& logger;
+ qpid::log::Options opts;
+};
+
+inline std::string getLibPath(const char* envName, const char* defaultPath = 0) {
+ const char* p = std::getenv(envName);
+ if (p != 0)
+ return p;
+ if (defaultPath == 0) {
+ std::ostringstream msg;
+ msg << "Environment variable " << envName << " not set.";
+ throw std::runtime_error(msg.str());
+ }
+ return defaultPath;
+}
+
+}} // namespace qpid::tests
+
#endif /*!TEST_TOOLS_H*/
diff --git a/cpp/src/tests/test_watchdog b/cpp/src/tests/test_watchdog
new file mode 100755
index 0000000000..5afdaa5e24
--- /dev/null
+++ b/cpp/src/tests/test_watchdog
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Tests for the watchdog plug-in
+
+source ./test_env.sh
+# Start a broker with watchdog, freeze it with kill -STOP, verify that it is killed.
+PORT=`$QPIDD_EXEC -dp0 --no-data-dir --auth=no --no-module-dir --load-module $WATCHDOG_LIB --log-to-file=qpidd_watchdog.log --watchdog-interval 1` || exit 1
+PID=`$QPIDD_EXEC --no-module-dir -cp $PORT` || exit 1
+kill -STOP $PID
+sleep 2
+
+if kill -0 $PID 2>/dev/null; then
+ echo "Hung process did not die."
+ kill $PID
+else
+ true
+fi
diff --git a/cpp/src/tests/test_wrap b/cpp/src/tests/test_wrap
new file mode 100755
index 0000000000..dd43c5a2e2
--- /dev/null
+++ b/cpp/src/tests/test_wrap
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Read the started broker port, set appropriate env vars
+# then run the program under test
+
+QPID_PORT=`cat qpidd.port`
+export QPID_PORT
+
+program=$1
+shift
+
+QPID_LOG_TO_FILE=`basename $program`.log
+export QPID_LOG_TO_FILE
+
+ERROR=0
+$program $* || ERROR=1
+
+# Check qpidd.log.
+egrep 'warning\|error\|critical' $QPID_LOG_TO_FILE && {
+ echo "WARNING: Suspicious broker log entries in $QPID_LOG_TO_FILE, above."
+}
+
+# Check valgrind log.
+#if test -n "$VALGRIND"; then
+# . `dirname $0`/vg_check $VG_LOG*
+# vg_check qpidd.vglog* || ERROR=1
+#fi
+
+exit $ERROR
diff --git a/cpp/src/tests/testlib.py b/cpp/src/tests/testlib.py
new file mode 100644
index 0000000000..fe57a84a81
--- /dev/null
+++ b/cpp/src/tests/testlib.py
@@ -0,0 +1,766 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#
+# Support library for qpid python tests.
+#
+
+import os, re, signal, subprocess, time, unittest
+
+class TestBase(unittest.TestCase):
+ """
+ Base class for qpid tests. Provides broker start/stop/kill methods
+ """
+
+ """
+ The following environment vars control if and how the test is run, and determine where many of the helper
+ executables/libs are to be found.
+ """
+ _storeLib = os.getenv("STORE_LIB")
+ _storeEnable = _storeLib != None # Must be True for durability to be enabled during the test
+ _qpiddExec = os.getenv("QPIDD_EXEC", "/usr/sbin/qpidd")
+ _tempStoreDir = os.path.abspath(os.getenv("TMP_DATA_DIR", "/tmp/qpid"))
+
+ """Global message counter ensures unique messages"""
+ _msgCnt = 0
+
+ # --- Helper functions for parameter handling ---
+
+ def _paramBool(self, key, val, keyOnly = False):
+ if val == None:
+ return ""
+ if keyOnly:
+ if val:
+ return " --%s" % key
+ else:
+ return ""
+ else:
+ if val:
+ return " --%s yes" % key
+ else:
+ return " --%s no" % key
+
+ # --- Helper functions for message creation ---
+
+ def _makeMessage(self, msgSize):
+ msg = "Message-%04d" % self._msgCnt
+ self._msgCnt = self._msgCnt + 1
+ msgLen = len(msg)
+ if msgSize > msgLen:
+ for i in range(msgLen, msgSize):
+ if i == msgLen:
+ msg += "-"
+ else:
+ msg += chr(ord('a') + (i % 26))
+ return msg
+
+ def _makeMessageList(self, numMsgs, msgSize):
+ if msgSize == None:
+ msgSize = 12
+ msgs = ""
+ for m in range(0, numMsgs):
+ msgs += "%s\n" % self._makeMessage(msgSize)
+ return msgs
+
+ # --- Starting and stopping a broker ---
+
+ def startBroker(self, qpiddArgs, logFile = None):
+ """Start a single broker daemon, returns tuple (pid, port)"""
+ if self._qpiddExec == None:
+ raise Exception("Environment variable QPIDD is not set")
+ cmd = "%s --daemon --port=0 %s" % (self._qpiddExec, qpiddArgs)
+ portStr = os.popen(cmd).read()
+ if len(portStr) == 0:
+ err = "Broker daemon startup failed."
+ if logFile != None:
+ err += " See log file %s" % logFile
+ raise Exception(err)
+ port = int(portStr)
+ pidStr = os.popen("%s -p %d -c" % (self._qpiddExec, port)).read()
+ try:
+ pid = int(pidStr)
+ except:
+ raise Exception("Unable to get pid: \"%s -p %d -c\" returned %s" % (self._qpiddExec, port, pidStr))
+ #print "started broker: pid=%d, port=%d args: %s" % (pid, port, qpiddArgs)
+ return (pid, port)
+
+ def killBroker(self, nodeTuple, ignoreFailures = False):
+ """Kill a broker using kill -9"""
+ try:
+ os.kill(nodeTuple[self.PID], signal.SIGKILL)
+ try:
+ os.waitpid(nodeTuple[self.PID], 0)
+ except:
+ pass
+ #print "killed broker: port=%d pid=%d" % (nodeTuple[self.PORT], nodeTuple[self.PID])
+ except:
+ if ignoreFailures:
+ print "WARNING: killBroker (port=%d pid=%d) failed - ignoring." % (nodeTuple[self.PORT], nodeTuple[self.PID])
+ else:
+ raise
+
+ def stopBroker(self, nodeTuple, ignoreFailures = False):
+ """Stop a broker using qpidd -q"""
+ try:
+ ret = os.spawnl(os.P_WAIT, self._qpiddExec, self._qpiddExec, "--port=%d" % nodeTuple[self.PORT], "--quit", "--no-module-dir")
+ if ret != 0:
+ raise Exception("stopBroker(): port=%d: qpidd -q returned %d" % (nodeTuple[self.PORT], ret))
+ try:
+ os.waitpid(nodeTuple[self.PID], 0)
+ except:
+ pass
+ #print "stopped broker: port=%d pid=%d" % (nodeTuple[self.PORT], nodeTuple[self.PID])
+ except:
+ if ignoreFailures:
+ print "WARNING: stopBroker (port=%d pid=%d) failed - ignoring." % (nodeTuple[self.PORT], nodeTuple[self.PID])
+ else:
+ raise
+
+
+
+class TestBaseCluster(TestBase):
+ """
+ Base class for cluster tests. Provides methods for starting and stopping clusters and cluster nodes.
+ """
+
+ """
+ The following environment vars control if and how the test is run, and determine where many of the helper
+ executables/libs are to be found.
+ """
+ _clusterLib = os.getenv("CLUSTER_LIB")
+ _clusterTestEnable = _clusterLib != None # Must be True for these cluster tests to run
+ _xmlLib = os.getenv("XML_LIB")
+ _xmlEnable = _xmlLib != None
+ _qpidConfigExec = os.getenv("QPID_CONFIG_EXEC", "/usr/bin/qpid-config")
+ _qpidRouteExec = os.getenv("QPID_ROUTE_EXEC", "/usr/bin/qpid-route")
+ _receiverExec = os.getenv("RECEIVER_EXEC", "/usr/libexec/qpid/test/receiver")
+ _senderExec = os.getenv("SENDER_EXEC", "/usr/libexec/qpid/test/sender")
+
+
+ """
+ _clusterDict is a dictionary of clusters:
+ key = cluster name (string)
+ val = dictionary of node numbers:
+ key = integer node number
+ val = tuple containing (pid, port)
+ For example, two clusters "TestCluster0" and "TestCluster1" containing several nodes would look as follows:
+ {"TestCluster0": {0: (pid0-0, port0-0), 1: (pid0-1, port0-1), ...}, "TestCluster1": {0: (pid1-0, port1-0), 1: (pid1-1, port1-1), ...}}
+ where pidm-n and portm-n are the int pid and port for TestCluster m node n respectively.
+ """
+ _clusterDict = {}
+
+ """Index for (pid, port) tuple"""
+ PID = 0
+ PORT = 1
+
+ def run(self, res):
+ """ Skip cluster testing if env var RUN_CLUSTER_TESTS is not defined."""
+ if not self._clusterTestEnable:
+ return
+ unittest.TestCase.run(self, res)
+
+ # --- Private helper / convenience functions ---
+
+ def _checkPids(self, clusterName = None):
+ for pid, port in self.getTupleList():
+ try:
+ os.kill(pid, 0)
+ except:
+ raise Exception("_checkPids(): Broker with pid %d expected but does not exist! (crashed?)" % pid)
+
+
+ # --- Starting cluster node(s) ---
+
+ def createClusterNode(self, nodeNumber, clusterName):
+ """Create a node and add it to the named cluster"""
+ if self._tempStoreDir == None:
+ raise Exception("Environment variable TMP_DATA_DIR is not set")
+ if self._clusterLib == None:
+ raise Exception("Environment variable LIBCLUSTER is not set")
+ name = "%s-%d" % (clusterName, nodeNumber)
+ dataDir = os.path.join(self._tempStoreDir, "cluster", name)
+ logFile = "%s.log" % dataDir
+ args = "--no-module-dir --load-module=%s --data-dir=%s --cluster-name=%s --auth=no --log-enable=notice+ --log-to-file=%s" % \
+ (self._clusterLib, dataDir, clusterName, logFile)
+ if self._storeEnable:
+ if self._storeLib == None:
+ raise Exception("Environment variable LIBSTORE is not set")
+ args += " --load-module %s" % self._storeLib
+ self._clusterDict[clusterName][nodeNumber] = self.startBroker(args, logFile)
+
+ def createCluster(self, clusterName, numberNodes = 0):
+ """Create a cluster containing an initial number of nodes"""
+ self._clusterDict[clusterName] = {}
+ for n in range(0, numberNodes):
+ self.createClusterNode(n, clusterName)
+
+ def waitForNodes(self, clusterName):
+ """Wait for all nodes to become active (ie finish cluster sync)"""
+ # TODO - connect to each known node in cluster
+ # Until this is done, wait a bit (hack)
+ time.sleep(1)
+
+ # --- Cluster and node status ---
+
+ def getTupleList(self, clusterName = None):
+ """Get list of (pid, port) tuples of all known cluster brokers"""
+ tList = []
+ for c, l in self._clusterDict.iteritems():
+ if clusterName == None or c == clusterName:
+ for t in l.itervalues():
+ tList.append(t)
+ return tList
+
+ def getNumBrokers(self):
+ """Get total number of brokers in all known clusters"""
+ return len(self.getTupleList())
+
+ def checkNumBrokers(self, expected = None, checkPids = True):
+ """Check that the total number of brokers in all known clusters is the expected value"""
+ if expected != None and self.getNumBrokers() != expected:
+ raise Exception("Unexpected number of brokers: expected %d, found %d" % (expected, self.getNumBrokers()))
+ if checkPids:
+ self._checkPids()
+
+ def getClusterTupleList(self, clusterName):
+ """Get list of (pid, port) tuples of all nodes in named cluster"""
+ if clusterName in self._clusterDict:
+ return self._clusterDict[clusterName].values()
+ return []
+
+ def getNumClusterBrokers(self, clusterName):
+ """Get total number of brokers in named cluster"""
+ return len(self.getClusterTupleList(clusterName))
+
+ def getNodeTuple(self, nodeNumber, clusterName):
+ """Get the (pid, port) tuple for the given cluster node"""
+ return self._clusterDict[clusterName][nodeNumber]
+
+ def checkNumClusterBrokers(self, clusterName, expected = None, checkPids = True, waitForNodes = True):
+ """Check that the total number of brokers in the named cluster is the expected value"""
+ if expected != None and self.getNumClusterBrokers(clusterName) != expected:
+ raise Exception("Unexpected number of brokers in cluster %s: expected %d, found %d" % \
+ (clusterName, expected, self.getNumClusterBrokers(clusterName)))
+ if checkPids:
+ self._checkPids(clusterName)
+ if waitForNodes:
+ self.waitForNodes(clusterName)
+
+ def clusterExists(self, clusterName):
+ """ Return True if clusterName exists, False otherwise"""
+ return clusterName in self._clusterDict.keys()
+
+ def clusterNodeExists(self, clusterName, nodeNumber):
+ """ Return True if nodeNumber in clusterName exists, False otherwise"""
+ if clusterName in self._clusterDict.keys():
+ return nodeNumber in self._clusterDict[nodeName]
+ return False
+
+ def createCheckCluster(self, clusterName, size):
+ """Create a cluster using the given name and size, then check the number of brokers"""
+ self.createCluster(clusterName, size)
+ self.checkNumClusterBrokers(clusterName, size)
+
+ # --- Kill cluster nodes using signal 9 ---
+
+ def killNode(self, nodeNumber, clusterName, updateDict = True, ignoreFailures = False):
+ """Kill the given node in the named cluster using kill -9"""
+ self.killBroker(self.getNodeTuple(nodeNumber, clusterName), ignoreFailures)
+ if updateDict:
+ del(self._clusterDict[clusterName][nodeNumber])
+
+ def killCluster(self, clusterName, updateDict = True, ignoreFailures = False):
+ """Kill all nodes in the named cluster"""
+ for n in self._clusterDict[clusterName].iterkeys():
+ self.killNode(n, clusterName, False, ignoreFailures)
+ if updateDict:
+ del(self._clusterDict[clusterName])
+
+ def killClusterCheck(self, clusterName):
+ """Kill the named cluster and check that the name is removed from the cluster dictionary"""
+ self.killCluster(clusterName)
+ if self.clusterExists(clusterName):
+ raise Exception("Unable to kill cluster %s; %d nodes still exist" % \
+ (clusterName, self.getNumClusterBrokers(clusterName)))
+
+ def killAllClusters(self, ignoreFailures = False):
+ """Kill all known clusters"""
+ for n in self._clusterDict.iterkeys():
+ self.killCluster(n, False, ignoreFailures)
+ self._clusterDict.clear()
+
+ def killAllClustersCheck(self, ignoreFailures = False):
+ """Kill all known clusters and check that the cluster dictionary is empty"""
+ self.killAllClusters(ignoreFailures)
+ self.checkNumBrokers(0)
+
+ # --- Stop cluster nodes using qpidd -q ---
+
+ def stopNode(self, nodeNumber, clusterName, updateDict = True, ignoreFailures = False):
+ """Stop the given node in the named cluster using qpidd -q"""
+ self.stopBroker(self.getNodeTuple(nodeNumber, clusterName), ignoreFailures)
+ if updateDict:
+ del(self._clusterDict[clusterName][nodeNumber])
+
+ def stopAllClusters(self, ignoreFailures = False):
+ """Stop all known clusters"""
+ for n in self._clusterDict.iterkeys():
+ self.stopCluster(n, False, ignoreFailures)
+ self._clusterDict.clear()
+
+
+ def stopCluster(self, clusterName, updateDict = True, ignoreFailures = False):
+ """Stop all nodes in the named cluster"""
+ for n in self._clusterDict[clusterName].iterkeys():
+ self.stopNode(n, clusterName, False, ignoreFailures)
+ if updateDict:
+ del(self._clusterDict[clusterName])
+
+ def stopCheckCluster(self, clusterName, ignoreFailures = False):
+ """Stop the named cluster and check that the name is removed from the cluster dictionary"""
+ self.stopCluster(clusterName, True, ignoreFailures)
+ if self.clusterExists(clusterName):
+ raise Exception("Unable to kill cluster %s; %d nodes still exist" % (clusterName, self.getNumClusterBrokers(clusterName)))
+
+ def stopAllCheck(self, ignoreFailures = False):
+ """Kill all known clusters and check that the cluster dictionary is empty"""
+ self.stopAllClusters()
+ self.checkNumBrokers(0)
+
+ # --- qpid-config functions ---
+
+ def _qpidConfig(self, nodeNumber, clusterName, action):
+ """Configure some aspect of a qpid broker using the qpid_config executable"""
+ port = self.getNodeTuple(nodeNumber, clusterName)[self.PORT]
+ #print "%s -a localhost:%d %s" % (self._qpidConfigExec, port, action)
+ ret = os.spawnl(os.P_WAIT, self._qpidConfigExec, self._qpidConfigExec, "-a", "localhost:%d" % port, *action.split())
+ if ret != 0:
+ raise Exception("_qpidConfig(): cluster=\"%s\" nodeNumber=%d port=%d action=\"%s\" returned %d" % \
+ (clusterName, nodeNumber, port, action, ret))
+
+ def addExchange(self, nodeNumber, clusterName, exchangeType, exchangeName, durable = False, sequence = False, \
+ ive = False):
+ """Add a named exchange."""
+ action = "add exchange %s %s" % (exchangeType, exchangeName)
+ action += self._paramBool("durable", durable, True)
+ action += self._paramBool("sequence", sequence, True)
+ action += self._paramBool("ive", ive, True)
+ self._qpidConfig(nodeNumber, clusterName, action)
+
+ def deleteExchange(self, nodeNumber, clusterName, exchangeName):
+ """Delete a named exchange"""
+ self._qpidConfig(nodeNumber, clusterName, "del exchange %s" % exchangeName)
+
+ def addQueue(self, nodeNumber, clusterName, queueName, configArgs = None):
+ """Add a queue using qpid-config."""
+ action = "add queue %s" % queueName
+ if self._storeEnable:
+ action += " --durable"
+ if configArgs != None:
+ action += " %s" % configArgs
+ self._qpidConfig(nodeNumber, clusterName, action)
+
+ def delQueue(self, nodeNumber, clusterName, queueName):
+ """Delete a named queue using qpid-config."""
+ self._qpidConfig(nodeNumber, clusterName, "del queue %s" % queueName)
+
+ def bind(self, nodeNumber, clusterName, exchangeName, queueName, key):
+ """Create an exchange-queue binding using qpid-config."""
+ self._qpidConfig(nodeNumber, clusterName, "bind %s %s %s" % (exchangeName, queueName, key))
+
+ def unbind(self, nodeNumber, clusterName, exchangeName, queueName, key):
+ """Remove an exchange-queue binding using qpid-config."""
+ self._qpidConfig(nodeNumber, clusterName, "unbind %s %s %s" % (exchangeName, queueName, key))
+
+ # --- qpid-route functions (federation) ---
+
+ def brokerDict(self, nodeNumber, clusterName, host = "localhost", user = None, password = None):
+ """Returns a dictionary containing the broker info to be passed to route functions"""
+ port = self.getNodeTuple(nodeNumber, clusterName)[self.PORT]
+ return {"cluster": clusterName, "node":nodeNumber, "port":port, "host":host, "user":user, "password":password}
+
+ def _brokerStr(self, brokerDict):
+ """Set up a broker string in the format [user/password@]host:port"""
+ str = ""
+ if brokerDict["user"] !=None and brokerDict["password"] != None:
+ str = "%s@%s" % (brokerDict["user"], brokerDict["password"])
+ str += "%s:%d" % (brokerDict["host"], brokerDict["port"])
+ return str
+
+ def _qpidRoute(self, action):
+ """Set up a route using qpid-route"""
+ #print "%s %s" % (self._qpidRouteExec, action)
+ ret = os.spawnl(os.P_WAIT, self._qpidRouteExec, self._qpidRouteExec, *action.split())
+ if ret != 0:
+ raise Exception("_qpidRoute(): action=\"%s\" returned %d" % (action, ret))
+
+ def routeDynamicAdd(self, destBrokerDict, srcBrokerDict, exchangeName):
+ self._qpidRoute("dynamic add %s %s %s" % (self._brokerStr(destBrokerDict), self._brokerStr(srcBrokerDict), exchangeName))
+
+ def routeDynamicDelete(self, destBrokerDict, srcBrokerDict, exchangeName):
+ self._qpidRoute("dynamic del %s %s %s" % (self._brokerStr(destBrokerDict), self._brokerStr(srcBrokerDict), exchangeName))
+
+ def routeAdd(self, destBrokerDict, srcBrokerDict, exchangeName, routingKey):
+ self._qpidRoute("route add %s %s %s %s" % (self._brokerStr(destBrokerDict), self._brokerStr(srcBrokerDict), exchangeName, routingKey))
+
+ def routeDelete(self, destBrokerDict, srcBrokerDict, exchangeName, routingKey):
+ self._qpidRoute("route del %s %s %s %s" % (self._brokerStr(destBrokerDict), self._brokerStr(srcBrokerDict), exchangeName, routingKey))
+
+ def routeQueueAdd(self, destBrokerDict, srcBrokerDict, exchangeName, queueName):
+ self._qpidRoute("queue add %s %s %s %s" % (self._brokerStr(destBrokerDict), self._brokerStr(srcBrokerDict), exchangeName, queueName))
+
+ def routeQueueDelete(self, destBrokerDict, srcBrokerDict, exchangeName, queueName):
+ self._qpidRoute("queue del %s %s %s %s" % (self._brokerStr(destBrokerDict), self._brokerStr(srcBrokerDict), exchangeName, queueName))
+
+ def routeLinkAdd(self, destBrokerDict, srcBrokerDict):
+ self._qpidRoute("link add %s %s" % (self._brokerStr(destBrokerDict), self._brokerStr(srcBrokerDict)))
+
+ def routeLinkDelete(self, destBrokerDict, srcBrokerDict):
+ self._qpidRoute("link del %s %s" % (self._brokerStr(destBrokerDict), self._brokerStr(srcBrokerDict)))
+
+ # --- Message send and receive functions ---
+
+ def _receiver(self, action):
+ if self._receiverExec == None:
+ raise Exception("Environment variable RECEIVER is not set")
+ cmd = "%s %s" % (self._receiverExec, action)
+ #print cmd
+ return subprocess.Popen(cmd.split(), stdout = subprocess.PIPE)
+
+ def _sender(self, action):
+ if self._senderExec == None:
+ raise Exception("Environment variable SENDER is not set")
+ cmd = "%s %s" % (self._senderExec, action)
+ #print cmd
+ return subprocess.Popen(cmd.split(), stdin = subprocess.PIPE)
+
+ def createReciever(self, nodeNumber, clusterName, queueName, numMsgs = None, receiverArgs = None):
+ port = self.getNodeTuple(nodeNumber, clusterName)[self.PORT]
+ action = "--port %d --queue %s" % (port, queueName)
+ if numMsgs != None:
+ action += " --messages %d" % numMsgs
+ if receiverArgs != None:
+ action += " %s" % receiverArgs
+ return self._receiver(action)
+
+ def createSender(self, nodeNumber, clusterName, exchangeName, routingKey, senderArgs = None):
+ port = self.getNodeTuple(nodeNumber, clusterName)[self.PORT]
+ action = "--port %d --exchange %s" % (port, exchangeName)
+ if routingKey != None and len(routingKey) > 0:
+ action += " --routing-key %s" % routingKey
+ if self._storeEnable:
+ action += " --durable yes"
+ if senderArgs != None:
+ action += " %s" % senderArgs
+ return self._sender(action)
+
+ def createBindDirectExchangeQueue(self, nodeNumber, clusterName, exchangeName, queueName):
+ self.addExchange(nodeNumber, clusterName, "direct", exchangeName)
+ self.addQueue(nodeNumber, clusterName, queueName)
+ self.bind(nodeNumber, clusterName, exchangeName, queueName, queueName)
+
+ def createBindTopicExchangeQueues(self, nodeNumber, clusterName, exchangeName, queueNameKeyList):
+ self.addExchange(nodeNumber, clusterName, "topic", exchangeName)
+ for queueName, key in queueNameKeyList.iteritems():
+ self.addQueue(nodeNumber, clusterName, queueName)
+ self.bind(nodeNumber, clusterName, exchangeName, queueName, key)
+
+ def createBindFanoutExchangeQueues(self, nodeNumber, clusterName, exchangeName, queueNameList):
+ self.addExchange(nodeNumber, clusterName, "fanout", exchangeName)
+ for queueName in queueNameList:
+ self.addQueue(nodeNumber, clusterName, queueName)
+ self.bind(nodeNumber, clusterName, exchangeName, queueName, "")
+
+ def sendMsgs(self, nodeNumber, clusterName, exchangeName, routingKey, numMsgs, msgSize = None, wait = True):
+ msgs = self._makeMessageList(numMsgs, msgSize)
+ sender = self.createSender(nodeNumber, clusterName, exchangeName, routingKey)
+ sender.stdin.write(msgs)
+ sender.stdin.close()
+ if wait:
+ sender.wait()
+ return msgs
+
+ def receiveMsgs(self, nodeNumber, clusterName, queueName, numMsgs, wait = True):
+ receiver = self.createReciever(nodeNumber, clusterName, queueName, numMsgs)
+ cnt = 0
+ msgs = ""
+ while cnt < numMsgs:
+ rx = receiver.stdout.readline()
+ if rx == "" and receiver.poll() != None: break
+ msgs += rx
+ cnt = cnt + 1
+ if wait:
+ receiver.wait()
+ return msgs
+
+
+ # --- Exchange-specific helper inner classes ---
+
+ class TestHelper:
+ """
+ This is a "virtual" superclass for test helpers, and is not useful on its own, but the
+ per-exchange subclasses are designed to keep track of the messages sent to and received
+ from queues which have bindings to that exchange type.
+ """
+
+ def __init__(self, testBaseCluster, clusterName, numNodes, exchangeName, queueNameList):
+
+ """Dictionary of queues and lists of messages sent to them."""
+ self._txMsgs = {}
+ """Dictionary of queues and lists of messages received from them."""
+ self._rxMsgs = {}
+ """List of node numbers currently in the cluster"""
+ self._nodes = []
+ """List of node numbers which have been killed and can therefore be recovered"""
+ self._deadNodes = []
+ """Last node to be used"""
+ self._lastNode = None
+
+ self._testBaseCluster = testBaseCluster
+ self._clusterName = clusterName
+ self._exchangeName = exchangeName
+ self._queueNameList = queueNameList
+ self._addQueues(queueNameList)
+ self._testBaseCluster.createCheckCluster(clusterName, numNodes)
+ self._nodes.extend(range(0, numNodes))
+
+ def _addQueues(self, queueNameList):
+ for qn in queueNameList:
+ if not qn in self._txMsgs:
+ self._txMsgs[qn] = []
+ if not qn in self._rxMsgs:
+ self._rxMsgs[qn] = []
+
+ def _bindQueue(self, queueName, bindingKey, nodeNumber = None):
+ """Bind a queue to an exchange using a binding key."""
+ if nodeNumber == None:
+ nodeNumber = self._nodes[0] # first available node
+ self._testBaseCluster.addQueue(nodeNumber, self._clusterName, queueName)
+ self._testBaseCluster.bind(nodeNumber, self._clusterName, self._exchangeName, queueName, bindingKey)
+
+ def _highestNodeNumber(self):
+ """Find the highest node number used so far between the current nodes and those stopped/killed."""
+ highestNode = self._nodes[-1]
+ if len(self._deadNodes) == 0:
+ return highestNode
+ highestDeadNode = self._deadNodes[-1]
+ if highestNode > highestDeadNode:
+ return highestNode
+ return highestDeadNode
+
+ def killCluster(self):
+ """Kill all nodes in the cluster"""
+ self._testBaseCluster.killCluster(self._clusterName)
+ self._testBaseCluster.checkNumClusterBrokers(self._clusterName, 0)
+ self._deadNodes.extend(self._nodes)
+ self._deadNodes.sort()
+ del self._nodes[:]
+
+ def restoreCluster(self, lastNode = None, restoreNodes = True):
+ """Restore a previously killed cluster"""
+ self._testBaseCluster.createCluster(self._clusterName)
+ if restoreNodes:
+ numNodes = len(self._deadNodes)
+ self.restoreNodes(lastNode)
+ self._testBaseCluster.checkNumClusterBrokers(self._clusterName, numNodes)
+
+ def addNodes(self, numberOfNodes = 1):
+ """Add a fixed number of nodes to the cluster."""
+ nodeStart = self._highestNodeNumber() + 1
+ for i in range(0, numberOfNodes):
+ nodeNumber = nodeStart + i
+ self._testBaseCluster.createClusterNode(nodeNumber, self._clusterName)
+ self._nodes.append(nodeNumber)
+ self._testBaseCluster.checkNumClusterBrokers(self._clusterName, len(self._nodes))
+ self._testBaseCluster.waitForNodes(self._clusterName)
+
+ def restoreNode(self, nodeNumber):
+ """Restore a cluster node that has been previously killed"""
+ if nodeNumber not in self._deadNodes:
+ raise Exception("restoreNode(): Node number %d not in dead node list %s" % (nodeNumber, self._deadNodes))
+ self._testBaseCluster.createClusterNode(nodeNumber, self._clusterName)
+ self._deadNodes.remove(nodeNumber)
+ self._nodes.append(nodeNumber)
+ self._nodes.sort()
+
+ def restoreNodes(self, lastNode = None):
+ """Restore all known cluster nodes that have been previously killed starting with a known last-used node"""
+ if len(self._nodes) == 0: # restore last-used node first
+ if lastNode == None:
+ lastNode = self._lastNode
+ self.restoreNode(lastNode)
+ while len(self._deadNodes) > 0:
+ self.restoreNode(self._deadNodes[0])
+ self._testBaseCluster.waitForNodes(self._clusterName)
+
+ def killNode(self, nodeNumber):
+ """Kill a cluster node (if it is in the _nodes list)."""
+ if nodeNumber not in self._nodes:
+ raise Exception("killNode(): Node number %d not in node list %s" % (nodeNumber, self._nodes))
+ self._testBaseCluster.killNode(nodeNumber, self._clusterName)
+ self._nodes.remove(nodeNumber)
+ self._deadNodes.append(nodeNumber)
+ self._deadNodes.sort()
+
+ def sendMsgs(self, routingKey, numMsgs, nodeNumber = None, msgSize = None, wait = True):
+ """Send a fixed number of messages using the given routing key."""
+ if nodeNumber == None:
+ nodeNumber = self._nodes[0] # Use first available node
+ msgs = self._testBaseCluster._makeMessageList(numMsgs, msgSize)
+ sender = self._testBaseCluster.createSender(nodeNumber, self._clusterName, self._exchangeName, routingKey)
+ sender.stdin.write(msgs)
+ sender.stdin.close()
+ if wait:
+ sender.wait()
+ self._lastNode = nodeNumber
+ return msgs.split()
+
+ # TODO - this i/f is messy: one mumMsgs can be given, but a list of queues
+ # so assuming numMsgs for each queue
+ # A mechanism is needed to specify a different numMsgs per queue
+ def receiveMsgs(self, numMsgs, nodeNumber = None, queueNameList = None, wait = True):
+ """Receive a fixed number of messages from a named queue. If numMsgs == None, get all remaining messages."""
+ if nodeNumber == None:
+ nodeNumber = self._nodes[0] # Use first available node
+ if queueNameList == None:
+ queueNameList = self._txMsgs.iterkeys()
+ for qn in queueNameList:
+ nm = numMsgs
+ if nm == None:
+ nm = len(self._txMsgs[qn]) - len(self._rxMsgs[qn]) # get all remaining messages
+ if nm > 0:
+ while nm > 0:
+ receiver = self._testBaseCluster.createReciever(nodeNumber, self._clusterName, qn, nm)
+ cnt = 0
+ while cnt < nm:
+ rx = receiver.stdout.readline().strip()
+ if rx == "":
+ if receiver.poll() != None: break
+ elif rx not in self._rxMsgs[qn]:
+ self._rxMsgs[qn].append(rx)
+ cnt = cnt + 1
+ nm = nm - cnt
+ if wait:
+ receiver.wait()
+ self._rxMsgs[qn].sort()
+ self._lastNode = nodeNumber
+
+ def receiveRemainingMsgs(self, nodeNumber = None, queueNameList = None, wait = True):
+ """Receive all remaining messages on named queue."""
+ self.receiveMsgs(None, nodeNumber, queueNameList, wait)
+
+ def checkMsgs(self):
+ """Return True if all expected messages have been received (ie the transmit and receive list are identical)."""
+ txMsgTot = 0
+ rxMsgTot = 0
+ for qn, txMsgList in self._txMsgs.iteritems():
+ rxMsgList = self._rxMsgs[qn]
+ txMsgTot = txMsgTot + len(txMsgList)
+ rxMsgTot = rxMsgTot + len(rxMsgList)
+ if len(txMsgList) != len(rxMsgList):
+ return False
+ for i, m in enumerate(txMsgList):
+ if m != rxMsgList[i]:
+ return False
+ if txMsgTot == 0 and rxMsgTot == 0:
+ print "WARNING: No messages were either sent or received"
+ return True
+
+ def finalizeTest(self):
+ """Recover all the remaining messages on all queues, then check that all expected messages were received."""
+ self.receiveRemainingMsgs()
+ self._testBaseCluster.stopAllCheck()
+ if not self.checkMsgs():
+ self.printMsgs()
+ self._testBaseCluster.fail("Send - receive message mismatch")
+
+ def printMsgs(self, txMsgs = True, rxMsgs = True):
+ """Print all messages transmitted and received."""
+ for qn, txMsgList in self._txMsgs.iteritems():
+ print "Queue: %s" % qn
+ if txMsgs:
+ print " txMsgList = %s" % txMsgList
+ if rxMsgs:
+ rxMsgList = self._rxMsgs[qn]
+ print " rxMsgList = %s" % rxMsgList
+
+
+ class DirectExchangeTestHelper(TestHelper):
+
+ def __init__(self, testBaseCluster, clusterName, numNodes, exchangeName, queueNameList):
+ TestBaseCluster.TestHelper.__init__(self, testBaseCluster, clusterName, numNodes, exchangeName, queueNameList)
+ self._testBaseCluster.addExchange(0, clusterName, "direct", exchangeName)
+ for qn in queueNameList:
+ self._bindQueue(qn, qn)
+
+ def addQueues(self, queueNameList):
+ self._addQueues(queueNameList)
+ for qn in queueNameList:
+ self._bindQueue(qn, qn)
+
+ def sendMsgs(self, numMsgs, nodeNumber = None, queueNameList = None, msgSize = None, wait = True):
+ if queueNameList == None:
+ queueNameList = self._txMsgs.iterkeys()
+ for qn in queueNameList:
+ self._txMsgs[qn].extend(TestBaseCluster.TestHelper.sendMsgs(self, qn, numMsgs, nodeNumber, msgSize, wait))
+
+
+ class TopicExchangeTestHelper(TestHelper):
+
+ def __init__(self, testBaseCluster, clusterName, numNodes, exchangeName, queueNameKeyList):
+ self._queueNameKeyList = queueNameKeyList
+ TestBaseCluster.TestHelper.__init__(self, testBaseCluster, clusterName, numNodes, exchangeName, queueNameKeyList.iterkeys())
+ self._testBaseCluster.addExchange(0, clusterName, "topic", exchangeName)
+ for qn, bk in queueNameKeyList.iteritems():
+ self._bindQueue(qn, bk)
+
+ def addQueues(self, queueNameKeyList):
+ self._addQueues(queueNameKeyList.iterkeys())
+ for qn, bk in queueNameKeyList.iteritems():
+ self._bindQueue(qn, bk)
+
+ def _prepareRegex(self, bk):
+ # This regex conversion is not very complete - there are other chars that should be escaped too
+ return "^%s$" % bk.replace(".", r"\.").replace("*", r"[^.]*").replace("#", ".*")
+
+ def sendMsgs(self, routingKey, numMsgs, nodeNumber = None, msgSize = None, wait = True):
+ msgList = TestBaseCluster.TestHelper.sendMsgs(self, routingKey, numMsgs, nodeNumber, msgSize, wait)
+ for qn, bk in self._queueNameKeyList.iteritems():
+ if re.match(self._prepareRegex(bk), routingKey):
+ self._txMsgs[qn].extend(msgList)
+
+
+ class FanoutExchangeTestHelper(TestHelper):
+
+ def __init__(self, testBaseCluster, clusterName, numNodes, exchangeName, queueNameList):
+ TestBaseCluster.TestHelper.__init__(self, testBaseCluster, clusterName, numNodes, exchangeName, queueNameList)
+ self._testBaseCluster.addExchange(0, clusterName, "fanout", exchangeName)
+ for qn in queueNameList:
+ self._bindQueue(qn, "")
+
+ def addQueues(self, queueNameList):
+ self._addQueues(queueNameList)
+ for qn in queueNameList:
+ self._bindQueue(qn, "")
+
+ def sendMsgs(self, numMsgs, nodeNumber = None, msgSize = None, wait = True):
+ msgList = TestBaseCluster.TestHelper.sendMsgs(self, "", numMsgs, nodeNumber, msgSize, wait)
+ for ml in self._txMsgs.itervalues():
+ ml.extend(msgList)
+
diff --git a/cpp/src/tests/topic_listener.cpp b/cpp/src/tests/topic_listener.cpp
index 636618b6dc..aa8c19df99 100644
--- a/cpp/src/tests/topic_listener.cpp
+++ b/cpp/src/tests/topic_listener.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -23,7 +23,7 @@
* This file provides one half of a test and example of a pub-sub
* style of interaction. See topic_publisher.cpp for the other half,
* in which the logic for publishing is defined.
- *
+ *
* This file contains the listener logic. A listener will subscribe to
* a logical 'topic'. It will count the number of messages it receives
* and the time elapsed between the first one and the last one. It
@@ -36,7 +36,9 @@
#include "qpid/client/Connection.h"
#include "qpid/client/MessageListener.h"
#include "qpid/client/Session.h"
+#include "qpid/client/AsyncSession.h"
#include "qpid/client/SubscriptionManager.h"
+#include "qpid/sys/SystemInfo.h"
#include "qpid/sys/Time.h"
#include "qpid/framing/FieldValue.h"
#include <iostream>
@@ -48,11 +50,14 @@ using namespace qpid::sys;
using namespace qpid::framing;
using namespace std;
+namespace qpid {
+namespace tests {
+
/**
* A message listener implementation in which the runtime logic is
* defined.
*/
-class Listener : public MessageListener{
+class Listener : public MessageListener{
Session session;
SubscriptionManager& mgr;
const string responseQueue;
@@ -60,12 +65,13 @@ class Listener : public MessageListener{
bool init;
int count;
AbsTime start;
-
+
void shutdown();
void report();
public:
Listener(const Session& session, SubscriptionManager& mgr, const string& reponseQueue, bool tx);
virtual void received(Message& msg);
+ Subscription subscription;
};
/**
@@ -88,6 +94,52 @@ struct Args : public qpid::TestOptions {
}
};
+Listener::Listener(const Session& s, SubscriptionManager& m, const string& _responseq, bool tx) :
+ session(s), mgr(m), responseQueue(_responseq), transactional(tx), init(false), count(0){}
+
+void Listener::received(Message& message){
+ if(!init){
+ start = now();
+ count = 0;
+ init = true;
+ cout << "Batch started." << endl;
+ }
+ string type = message.getHeaders().getAsString("TYPE");
+
+ if(string("TERMINATION_REQUEST") == type){
+ shutdown();
+ }else if(string("REPORT_REQUEST") == type){
+ subscription.accept(subscription.getUnaccepted()); // Accept everything upto this point
+ cout <<"Batch ended, sending report." << endl;
+ //send a report:
+ report();
+ init = false;
+ }else if (++count % 1000 == 0){
+ cout <<"Received " << count << " messages." << endl;
+ }
+}
+
+void Listener::shutdown(){
+ mgr.stop();
+}
+
+void Listener::report(){
+ AbsTime finish = now();
+ Duration time(start, finish);
+ stringstream reportstr;
+ reportstr << "Received " << count << " messages in "
+ << time/TIME_MSEC << " ms.";
+ Message msg(reportstr.str(), responseQueue);
+ msg.getHeaders().setString("TYPE", "REPORT");
+ session.messageTransfer(arg::destination="amq.direct", arg::content=msg, arg::acceptMode=1);
+ if(transactional){
+ sync(session).txCommit();
+ }
+}
+
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
/**
* The main routine creates a Listener instance and sets it up to
@@ -118,19 +170,20 @@ int main(int argc, char** argv){
//set up listener
SubscriptionManager mgr(session);
Listener listener(session, mgr, "response", args.transactional);
+ SubscriptionSettings settings;
if (args.prefetch) {
- mgr.setAckPolicy(AckPolicy(args.ack ? args.ack : (args.prefetch / 2)));
- mgr.setFlowControl(args.prefetch, SubscriptionManager::UNLIMITED, true);
+ settings.autoAck = (args.ack ? args.ack : (args.prefetch / 2));
+ settings.flowControl = FlowControl::messageCredit(args.prefetch);
} else {
- mgr.setAcceptMode(1/*-not-required*/);
- mgr.setFlowControl(SubscriptionManager::UNLIMITED, SubscriptionManager::UNLIMITED, false);
+ settings.acceptMode = ACCEPT_MODE_NONE;
+ settings.flowControl = FlowControl::unlimited();
}
- mgr.subscribe(listener, control);
+ listener.subscription = mgr.subscribe(listener, control, settings);
session.sync();
if( args.statusqueue.length() > 0 ) {
stringstream msg_str;
- msg_str << "topic_listener: " << (int)getpid();
+ msg_str << "topic_listener: " << qpid::sys::SystemInfo::getProcessId();
session.messageTransfer(arg::content=Message(msg_str.str(), args.statusqueue));
cout << "Ready status put on queue '" << args.statusqueue << "'" << endl;
}
@@ -138,7 +191,7 @@ int main(int argc, char** argv){
if (args.transactional) {
session.txSelect();
}
-
+
cout << "topic_listener: listening..." << endl;
mgr.run();
if (args.durable) {
@@ -154,47 +207,3 @@ int main(int argc, char** argv){
}
return 1;
}
-
-Listener::Listener(const Session& s, SubscriptionManager& m, const string& _responseq, bool tx) :
- session(s), mgr(m), responseQueue(_responseq), transactional(tx), init(false), count(0){}
-
-void Listener::received(Message& message){
- if(!init){
- start = now();
- count = 0;
- init = true;
- cout << "Batch started." << endl;
- }
- string type = message.getHeaders().getString("TYPE");
-
- if(string("TERMINATION_REQUEST") == type){
- shutdown();
- }else if(string("REPORT_REQUEST") == type){
- mgr.getAckPolicy().ackOutstanding(session);//acknowledge everything upto this point
- cout <<"Batch ended, sending report." << endl;
- //send a report:
- report();
- init = false;
- }else if (++count % 1000 == 0){
- cout <<"Received " << count << " messages." << endl;
- }
-}
-
-void Listener::shutdown(){
- mgr.stop();
-}
-
-void Listener::report(){
- AbsTime finish = now();
- Duration time(start, finish);
- stringstream reportstr;
- reportstr << "Received " << count << " messages in "
- << time/TIME_MSEC << " ms.";
- Message msg(reportstr.str(), responseQueue);
- msg.getHeaders().setString("TYPE", "REPORT");
- session.messageTransfer(arg::destination="amq.direct", arg::content=msg, arg::acceptMode=1);
- if(transactional){
- sync(session).txCommit();
- }
-}
-
diff --git a/cpp/src/tests/topic_perftest b/cpp/src/tests/topic_perftest
index 5d317610f3..cd440b2458 100755
--- a/cpp/src/tests/topic_perftest
+++ b/cpp/src/tests/topic_perftest
@@ -1,2 +1,22 @@
#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
exec `dirname $0`/run_perftest 10000 --mode topic --qt 16
diff --git a/cpp/src/tests/topic_publisher.cpp b/cpp/src/tests/topic_publisher.cpp
index f37ad2dc0e..3381132b1a 100644
--- a/cpp/src/tests/topic_publisher.cpp
+++ b/cpp/src/tests/topic_publisher.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -23,7 +23,7 @@
* This file provides one half of a test and example of a pub-sub
* style of interaction. See topic_listener.cpp for the other half, in
* which the logic for subscribers is defined.
- *
+ *
* This file contains the publisher logic. The publisher will send a
* number of messages to the exchange with the appropriate routing key
* for the logical 'topic'. Once it has done this it will then send a
@@ -40,7 +40,6 @@
#include "qpid/client/AsyncSession.h"
#include "qpid/client/SubscriptionManager.h"
#include "qpid/sys/Monitor.h"
-#include <unistd.h>
#include "qpid/sys/Time.h"
#include <cstdlib>
#include <iostream>
@@ -50,19 +49,22 @@ using namespace qpid::client;
using namespace qpid::sys;
using namespace std;
+namespace qpid {
+namespace tests {
+
/**
* The publishing logic is defined in this class. It implements
* message listener and can therfore be used to receive messages sent
* back by the subscribers.
*/
-class Publisher {
+class Publisher {
AsyncSession session;
SubscriptionManager mgr;
LocalQueue queue;
const string controlTopic;
const bool transactional;
const bool durable;
-
+
string generateData(int size);
public:
@@ -100,6 +102,64 @@ struct Args : public TestOptions {
}
};
+Publisher::Publisher(const AsyncSession& _session, const string& _controlTopic, bool tx, bool d) :
+ session(_session), mgr(session), controlTopic(_controlTopic), transactional(tx), durable(d)
+{
+ mgr.subscribe(queue, "response");
+}
+
+int64_t Publisher::publish(int msgs, int listeners, int size){
+ Message msg(generateData(size), controlTopic);
+ if (durable) {
+ msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
+ }
+ AbsTime start = now();
+
+ for(int i = 0; i < msgs; i++){
+ session.messageTransfer(arg::content=msg, arg::destination="amq.topic", arg::acceptMode=1);
+ }
+ //send report request
+ Message reportRequest("", controlTopic);
+ reportRequest.getHeaders().setString("TYPE", "REPORT_REQUEST");
+ session.messageTransfer(arg::content=reportRequest, arg::destination="amq.topic", arg::acceptMode=1);
+ if(transactional){
+ sync(session).txCommit();
+ }
+ //wait for a response from each listener (TODO, could log these)
+ for (int i = 0; i < listeners; i++) {
+ Message report = queue.pop();
+ }
+
+ if(transactional){
+ sync(session).txCommit();
+ }
+
+ AbsTime finish = now();
+ return Duration(start, finish);
+}
+
+string Publisher::generateData(int size){
+ string data;
+ for(int i = 0; i < size; i++){
+ data += ('A' + (i / 26));
+ }
+ return data;
+}
+
+void Publisher::terminate(){
+ //send termination request
+ Message terminationRequest("", controlTopic);
+ terminationRequest.getHeaders().setString("TYPE", "TERMINATION_REQUEST");
+ session.messageTransfer(arg::content=terminationRequest, arg::destination="amq.topic", arg::acceptMode=1);
+ if(transactional){
+ session.txCommit();
+ }
+}
+
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char** argv) {
try{
Args args;
@@ -121,11 +181,11 @@ int main(int argc, char** argv) {
Message m = statusQ.get();
if( m.getData().find("topic_listener: ", 0) == 0 ) {
cout << "Listener " << (i+1) << " of " << args.subscribers
- << " is ready (pid " << m.getData().substr(16, m.getData().length() - 16)
- << ")" << endl;
+ << " is ready (pid " << m.getData().substr(16, m.getData().length() - 16)
+ << ")" << endl;
} else {
throw Exception(QPID_MSG("Unexpected message received on status queue: " << m.getData()));
- }
+ }
}
}
@@ -142,7 +202,7 @@ int main(int argc, char** argv) {
int64_t min(0);
int64_t sum(0);
for(int i = 0; i < batchSize; i++){
- if(i > 0 && args.delay) sleep(args.delay);
+ if(i > 0 && args.delay) qpid::sys::sleep(args.delay);
int64_t msecs =
publisher.publish(args.messages,
args.subscribers,
@@ -151,12 +211,12 @@ int main(int argc, char** argv) {
if(!min || msecs < min) min = msecs;
sum += msecs;
cout << "Completed " << (i+1) << " of " << batchSize
- << " in " << msecs << "ms" << endl;
+ << " in " << msecs << "ms" << endl;
}
publisher.terminate();
int64_t avg = sum / batchSize;
if(batchSize > 1){
- cout << batchSize << " batches completed. avg=" << avg <<
+ cout << batchSize << " batches completed. avg=" << avg <<
", max=" << max << ", min=" << min << endl;
}
session.close();
@@ -168,57 +228,3 @@ int main(int argc, char** argv) {
}
return 1;
}
-
-Publisher::Publisher(const AsyncSession& _session, const string& _controlTopic, bool tx, bool d) :
- session(_session), mgr(session), controlTopic(_controlTopic), transactional(tx), durable(d)
-{
- mgr.subscribe(queue, "response");
-}
-
-int64_t Publisher::publish(int msgs, int listeners, int size){
- Message msg(generateData(size), controlTopic);
- if (durable) {
- msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
- }
- AbsTime start = now();
-
- for(int i = 0; i < msgs; i++){
- session.messageTransfer(arg::content=msg, arg::destination="amq.topic", arg::acceptMode=1);
- }
- //send report request
- Message reportRequest("", controlTopic);
- reportRequest.getHeaders().setString("TYPE", "REPORT_REQUEST");
- session.messageTransfer(arg::content=reportRequest, arg::destination="amq.topic", arg::acceptMode=1);
- if(transactional){
- sync(session).txCommit();
- }
- //wait for a response from each listener (TODO, could log these)
- for (int i = 0; i < listeners; i++) {
- Message report = queue.pop();
- }
-
- if(transactional){
- sync(session).txCommit();
- }
-
- AbsTime finish = now();
- return Duration(start, finish);
-}
-
-string Publisher::generateData(int size){
- string data;
- for(int i = 0; i < size; i++){
- data += ('A' + (i / 26));
- }
- return data;
-}
-
-void Publisher::terminate(){
- //send termination request
- Message terminationRequest("", controlTopic);
- terminationRequest.getHeaders().setString("TYPE", "TERMINATION_REQUEST");
- session.messageTransfer(arg::content=terminationRequest, arg::destination="amq.topic", arg::acceptMode=1);
- if(transactional){
- session.txCommit();
- }
-}
diff --git a/cpp/src/tests/topictest b/cpp/src/tests/topictest
index 6763d8552b..8fd680ee35 100755
--- a/cpp/src/tests/topictest
+++ b/cpp/src/tests/topictest
@@ -1,4 +1,24 @@
#!/bin/bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# Run the C++ topic test
# Clean up old log files
diff --git a/cpp/src/tests/topictest.ps1 b/cpp/src/tests/topictest.ps1
new file mode 100644
index 0000000000..0d22cea657
--- /dev/null
+++ b/cpp/src/tests/topictest.ps1
@@ -0,0 +1,70 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Run the C++ topic test
+$srcdir = Split-Path $myInvocation.InvocationName
+
+# Parameters with default values: s (subscribers) m (messages) b (batches)
+# h (host) t (false; use transactions)
+param (
+ [int]$subscribers = 10,
+ [int]$messages = 2000,
+ [int]$batches = 10,
+ [string]$broker,
+ [switch] $t # transactional
+)
+
+# Clean up old log files
+Get-Item subscriber_*.log | Remove-Item
+
+if ($t) {
+ $transactional = "--transactional --durable"
+}
+
+# Find which subdir the exes are in
+. $srcdir\find_prog.ps1 .\topic_listener.exe
+
+function subscribe {
+ param ([int]$num)
+ "Start subscriber $num"
+ $LOG = "subscriber_$num.log"
+ $cmdline = ".\$sub\topic_listener $transactional > $LOG 2>&1
+ if (`$LastExitCode -ne 0) { Remove-Item $LOG }"
+ $cmdblock = $executioncontext.invokecommand.NewScriptBlock($cmdline)
+ . $srcdir\background.ps1 $cmdblock
+}
+
+function publish {
+ Invoke-Expression ".\$sub\topic_publisher --messages $messages --batches $batches --subscribers $subscribers $host $transactional" 2>&1
+}
+
+if ($broker.length) {
+ $broker = "-h$broker"
+}
+
+$i = $subscribers
+while ($i -gt 0) {
+ subscribe $i
+ $i--
+}
+
+# FIXME aconway 2007-03-27: Hack around startup race. Fix topic test.
+Start-Sleep 2
+publish
+exit $LastExitCode
diff --git a/cpp/src/tests/txjob.cpp b/cpp/src/tests/txjob.cpp
new file mode 100644
index 0000000000..a7a905c1b7
--- /dev/null
+++ b/cpp/src/tests/txjob.cpp
@@ -0,0 +1,102 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/ptr_container/ptr_vector.hpp>
+
+#include "TestOptions.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/FailoverManager.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/sys/Thread.h"
+
+using namespace qpid::client;
+using namespace qpid::sys;
+
+namespace qpid {
+namespace tests {
+
+struct Args : public qpid::TestOptions
+{
+ string workQueue;
+ string source;
+ string dest;
+ uint messages;
+ uint jobs;
+ bool quit;
+ bool declareQueues;
+
+ Args() : workQueue("txshift-control"), source("txshift-1"), dest("txshift-2"), messages(0), jobs(0),
+ quit(false), declareQueues(false)
+ {
+ addOptions()
+ ("messages", qpid::optValue(messages, "N"), "Number of messages to shift")
+ ("jobs", qpid::optValue(jobs, "N"), "Number of shift jobs to request")
+ ("source", qpid::optValue(source, "QUEUE NAME"), "source queue from which messages will be shifted")
+ ("dest", qpid::optValue(dest, "QUEUE NAME"), "dest queue to which messages will be shifted")
+ ("work-queue", qpid::optValue(workQueue, "QUEUE NAME"), "work queue from which to take instructions")
+ ("add-quit", qpid::optValue(quit), "add a 'quit' instruction to the queue (after any other jobs)")
+ ("declare-queues", qpid::optValue(declareQueues), "issue a declare for all queues");
+ }
+};
+
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
+//TODO: might be nice to make this capable of failover as well at some
+//point; for now its just for the setup phase.
+int main(int argc, char** argv)
+{
+ Args opts;
+ try {
+ opts.parse(argc, argv);
+ Connection connection;
+ connection.open(opts.con);
+ Session session = connection.newSession();
+ if (opts.declareQueues) {
+ session.queueDeclare(arg::queue=opts.workQueue);
+ session.queueDeclare(arg::queue=opts.source);
+ session.queueDeclare(arg::queue=opts.dest);
+ }
+ for (uint i = 0; i < opts.jobs; ++i) {
+ Message job("transfer", opts.workQueue);
+ job.getHeaders().setString("src", opts.source);
+ job.getHeaders().setString("dest", opts.dest);
+ job.getHeaders().setInt("count", opts.messages);
+ async(session).messageTransfer(arg::content=job);
+ }
+
+ if (opts.quit) {
+ async(session).messageTransfer(arg::content=Message("quit", opts.workQueue));
+ }
+
+ session.sync();
+ session.close();
+
+ return 0;
+ } catch(const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ return 1;
+ }
+}
diff --git a/cpp/src/tests/txshift.cpp b/cpp/src/tests/txshift.cpp
new file mode 100644
index 0000000000..882d3716d8
--- /dev/null
+++ b/cpp/src/tests/txshift.cpp
@@ -0,0 +1,193 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/ptr_container/ptr_vector.hpp>
+
+#include "TestOptions.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/FailoverManager.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/Thread.h"
+
+using namespace qpid::client;
+using namespace qpid::sys;
+
+namespace qpid {
+namespace tests {
+
+struct Args : public qpid::TestOptions
+{
+ string workQueue;
+ size_t workers;
+
+ Args() : workQueue("txshift-control"), workers(1)
+ {
+ addOptions()
+ ("workers", qpid::optValue(workers, "N"), "Number of separate worker sessions to start")
+ ("work-queue", qpid::optValue(workQueue, "NAME"), "work queue from which to take instructions");
+ }
+};
+
+struct Transfer : MessageListener
+{
+ std::string control;
+ std::string source;
+ std::string destination;
+ uint expected;
+ uint transfered;
+ SubscriptionSettings controlSettings;
+ Subscription controlSubscription;
+ SubscriptionSettings sourceSettings;
+ Subscription sourceSubscription;
+
+ Transfer(const std::string control_) : control(control_), expected(0), transfered(0) {}
+
+ void subscribeToSource(SubscriptionManager manager)
+ {
+ sourceSettings.autoAck = 0;//will accept once at the end of the batch
+ sourceSettings.flowControl = FlowControl::messageCredit(expected);
+ sourceSubscription = manager.subscribe(*this, source, sourceSettings);
+ QPID_LOG(info, "Subscribed to source: " << source << " expecting: " << expected);
+ }
+
+ void subscribeToControl(SubscriptionManager manager)
+ {
+ controlSettings.flowControl = FlowControl::messageCredit(1);
+ controlSubscription = manager.subscribe(*this, control, controlSettings);
+ QPID_LOG(info, "Subscribed to job queue");
+ }
+
+ void received(Message& message)
+ {
+ QPID_LOG(debug, "received: " << message.getData() << " for " << message.getDestination());
+ if (message.getDestination() == source) {
+ receivedFromSource(message);
+ } else if (message.getDestination() == control) {
+ receivedFromControl(message);
+ } else {
+ QPID_LOG(error, "Unexpected message: " << message.getData() << " to " << message.getDestination());
+ }
+ }
+
+ void receivedFromSource(Message& message)
+ {
+ QPID_LOG(debug, "transfering " << (transfered+1) << " of " << expected);
+ message.getDeliveryProperties().setRoutingKey(destination);
+ async(sourceSubscription.getSession()).messageTransfer(arg::content=message);
+ if (++transfered == expected) {
+ QPID_LOG(info, "completed job: " << transfered << " messages shifted from " <<
+ source << " to " << destination);
+ sourceSubscription.accept(sourceSubscription.getUnaccepted());
+ sourceSubscription.getSession().txCommit();
+ sourceSubscription.cancel();
+ //grant credit to allow broker to send us another control message
+ controlSubscription.grantMessageCredit(1);
+ }
+ }
+
+ void receivedFromControl(Message& message)
+ {
+ if (message.getData() == "transfer") {
+ source = message.getHeaders().getAsString("src");
+ destination = message.getHeaders().getAsString("dest");
+ expected = message.getHeaders().getAsInt("count");
+ transfered = 0;
+ QPID_LOG(info, "received transfer request: " << expected << " messages to be shifted from " <<
+ source << " to " << destination);
+ subscribeToSource(controlSubscription.getSubscriptionManager());
+ } else if (message.getData() == "quit") {
+ QPID_LOG(info, "received quit request");
+ controlSubscription.cancel();
+ } else {
+ std::cerr << "Rejecting invalid message: " << message.getData() << std::endl;
+ controlSubscription.getSession().messageReject(SequenceSet(message.getId()));
+ }
+ }
+
+};
+
+struct Worker : FailoverManager::Command, Runnable
+{
+ FailoverManager& connection;
+ Transfer transfer;
+ Thread runner;
+
+ Worker(FailoverManager& c, const std::string& controlQueue) : connection(c), transfer(controlQueue) {}
+
+ void run()
+ {
+ connection.execute(*this);
+ }
+
+ void start()
+ {
+ runner = Thread(this);
+ }
+
+ void join()
+ {
+ runner.join();
+ }
+
+ void execute(AsyncSession& session, bool isRetry)
+ {
+ if (isRetry) QPID_LOG(info, "Retrying...");
+ session.txSelect();
+ SubscriptionManager subs(session);
+ transfer.subscribeToControl(subs);
+ subs.run();
+ session.txCommit();//commit accept of control messages
+ }
+};
+
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
+int main(int argc, char** argv)
+{
+ Args opts;
+ try {
+ opts.parse(argc, argv);
+ FailoverManager connection(opts.con);
+ connection.connect();
+ if (opts.workers == 1) {
+ Worker worker(connection, opts.workQueue);
+ worker.run();
+ } else {
+ boost::ptr_vector<Worker> workers;
+ for (size_t i = 0; i < opts.workers; i++) {
+ workers.push_back(new Worker(connection, opts.workQueue));
+ }
+ std::for_each(workers.begin(), workers.end(), boost::bind(&Worker::start, _1));
+ std::for_each(workers.begin(), workers.end(), boost::bind(&Worker::join, _1));
+ }
+
+ return 0;
+ } catch(const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ return 1;
+ }
+}
diff --git a/cpp/src/tests/txtest.cpp b/cpp/src/tests/txtest.cpp
index f0e70e83e9..d0ba2f1245 100644
--- a/cpp/src/tests/txtest.cpp
+++ b/cpp/src/tests/txtest.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -33,12 +33,17 @@
#include "qpid/client/SubscriptionManager.h"
#include "qpid/framing/Array.h"
#include "qpid/framing/Buffer.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/sys/Thread.h"
using namespace qpid;
using namespace qpid::client;
using namespace qpid::sys;
using std::string;
+namespace qpid {
+namespace tests {
+
typedef std::vector<std::string> StringSet;
struct Args : public qpid::TestOptions {
@@ -51,13 +56,14 @@ struct Args : public qpid::TestOptions {
uint txCount;
uint totalMsgCount;
bool dtx;
+ bool quiet;
- Args() : init(true), transfer(true), check(true),
- size(256), durable(true), queues(2),
+ Args() : init(true), transfer(true), check(true),
+ size(256), durable(true), queues(2),
base("tx-test"), msgsPerTx(1), txCount(1), totalMsgCount(10),
- dtx(false)
+ dtx(false), quiet(false)
{
- addOptions()
+ addOptions()
("init", optValue(init, "yes|no"), "Declare queues and populate one with the initial set of messages.")
("transfer", optValue(transfer, "yes|no"), "'Move' messages from one queue to another using transactions to ensure no message loss.")
@@ -69,7 +75,8 @@ struct Args : public qpid::TestOptions {
("messages-per-tx", optValue(msgsPerTx, "N"), "number of messages transferred per transaction")
("tx-count", optValue(txCount, "N"), "number of transactions per 'agent'")
("total-messages", optValue(totalMsgCount, "N"), "total number of messages in 'circulation'")
- ("dtx", optValue(dtx, "yes|no"), "use distributed transactions");
+ ("dtx", optValue(dtx, "yes|no"), "use distributed transactions")
+ ("quiet", optValue(quiet), "reduce output from test");
}
};
@@ -79,7 +86,7 @@ std::string generateData(uint size)
{
if (size < chars.length()) {
return chars.substr(0, size);
- }
+ }
std::string data;
for (uint i = 0; i < (size / chars.length()); i++) {
data += chars;
@@ -99,18 +106,18 @@ void generateSet(const std::string& base, uint count, StringSet& collection)
Args opts;
-struct Client
+struct Client
{
Connection connection;
AsyncSession session;
- Client()
+ Client()
{
opts.open(connection);
session = connection.newSession();
}
- ~Client()
+ ~Client()
{
try{
session.close();
@@ -126,38 +133,44 @@ struct Transfer : public Client, public Runnable
std::string src;
std::string dest;
Thread thread;
- unsigned long xid_cnt;
framing::Xid xid;
- Transfer(const std::string& to, const std::string& from) : src(to), dest(from), xid_cnt(0), xid(0x4c414e47, "", from) {}
+ Transfer(const std::string& to, const std::string& from) : src(to), dest(from), xid(0x4c414e47, "", from) {}
- void run()
+ void run()
{
try {
-
+
if (opts.dtx) session.dtxSelect();
else session.txSelect();
SubscriptionManager subs(session);
-
- LocalQueue lq(AckPolicy(0));//manual acking
- subs.setFlowControl(opts.msgsPerTx, SubscriptionManager::UNLIMITED, true);
- subs.subscribe(lq, src);
-
+
+ LocalQueue lq;
+ SubscriptionSettings settings(FlowControl::messageWindow(opts.msgsPerTx));
+ settings.autoAck = 0; // Disabled
+ Subscription sub = subs.subscribe(lq, src, settings);
+
for (uint t = 0; t < opts.txCount; t++) {
Message in;
Message out("", dest);
if (opts.dtx) {
- setNextXid(xid);
+ setNewXid(xid);
session.dtxStart(arg::xid=xid);
}
for (uint m = 0; m < opts.msgsPerTx; m++) {
in = lq.pop();
- out.setData(in.getData());
+ std::string& data = in.getData();
+ if (data.size() != opts.size) {
+ std::ostringstream oss;
+ oss << "Message size incorrect: size=" << in.getData().size() << "; expected " << opts.size;
+ throw std::runtime_error(oss.str());
+ }
+ out.setData(data);
out.getMessageProperties().setCorrelationId(in.getMessageProperties().getCorrelationId());
out.getDeliveryProperties().setDeliveryMode(in.getDeliveryProperties().getDeliveryMode());
session.messageTransfer(arg::content=out, arg::acceptMode=1);
}
- lq.getAckPolicy().ackOutstanding(session);
+ sub.accept(sub.getUnaccepted());
if (opts.dtx) {
session.dtxEnd(arg::xid=xid);
session.dtxPrepare(arg::xid=xid);
@@ -171,14 +184,13 @@ struct Transfer : public Client, public Runnable
}
}
- void setNextXid(framing::Xid& xid) {
- std::ostringstream oss;
- oss << std::setfill('0') << std::hex << "xid-" << std::setw(12) << (++xid_cnt);
- xid.setGlobalId(oss.str());
+ void setNewXid(framing::Xid& xid) {
+ framing::Uuid uuid(true);
+ xid.setGlobalId(uuid.str());
}
};
-struct Controller : public Client
+struct Controller : public Client
{
StringSet ids;
StringSet queues;
@@ -189,7 +201,7 @@ struct Controller : public Client
generateSet("msg", opts.totalMsgCount, ids);
}
- void init()
+ void init()
{
//declare queues
for (StringSet::iterator i = queues.begin(); i != queues.end(); i++) {
@@ -217,7 +229,7 @@ struct Controller : public Client
StringSet::iterator next = i + 1;
if (next == queues.end()) next = queues.begin();
- std::cout << "Transfering from " << *i << " to " << *next << std::endl;
+ if (!opts.quiet) std::cout << "Transfering from " << *i << " to " << *next << std::endl;
agents.push_back(new Transfer(*i, *next));
agents.back().thread = Thread(agents.back());
}
@@ -227,11 +239,9 @@ struct Controller : public Client
}
}
- void check()
+ int check()
{
SubscriptionManager subs(session);
- subs.setFlowControl(SubscriptionManager::UNLIMITED, SubscriptionManager::UNLIMITED, false);
- subs.setAcceptMode(1/*not-required*/);
// Recover DTX transactions (if any)
if (opts.dtx) {
@@ -241,13 +251,13 @@ struct Controller : public Client
xidArr.collect(inDoubtXids);
if (inDoubtXids.size()) {
- std::cout << "Recovering DTX in-doubt transaction(s):" << std::endl;
+ if (!opts.quiet) std::cout << "Recovering DTX in-doubt transaction(s):" << std::endl;
framing::StructHelper decoder;
framing::Xid xid;
// abort even, commit odd transactions
for (unsigned i = 0; i < inDoubtXids.size(); i++) {
decoder.decode(xid, inDoubtXids[i]);
- std::cout << (i%2 ? " * aborting " : " * committing ");
+ if (!opts.quiet) std::cout << (i%2 ? " * aborting " : " * committing ");
xid.print(std::cout);
std::cout << std::endl;
if (i%2) {
@@ -262,9 +272,10 @@ struct Controller : public Client
StringSet drained;
//drain each queue and verify the correct set of messages are available
for (StringSet::iterator i = queues.begin(); i != queues.end(); i++) {
- //subscribe, allocate credit and flush
- LocalQueue lq(AckPolicy(0));//manual acking
- subs.subscribe(lq, *i, *i);
+ //subscribe, allocate credit and flushn
+ LocalQueue lq;
+ SubscriptionSettings settings(FlowControl::unlimited(), ACCEPT_MODE_NONE);
+ subs.subscribe(lq, *i, settings);
session.messageFlush(arg::destination=*i);
session.sync();
@@ -275,7 +286,7 @@ struct Controller : public Client
drained.push_back(m.getMessageProperties().getCorrelationId());
++count;
}
- std::cout << "Drained " << count << " messages from " << *i << std::endl;
+ if (!opts.quiet) std::cout << "Drained " << count << " messages from " << *i << std::endl;
}
sort(ids.begin(), ids.end());
@@ -283,41 +294,47 @@ struct Controller : public Client
//check that drained == ids
StringSet missing;
- set_difference(ids.begin(), ids.end(), drained.begin(), drained.end(), back_inserter(missing));
+ set_difference(ids.begin(), ids.end(), drained.begin(), drained.end(), back_inserter(missing));
StringSet extra;
- set_difference(drained.begin(), drained.end(), ids.begin(), ids.end(), back_inserter(extra));
+ set_difference(drained.begin(), drained.end(), ids.begin(), ids.end(), back_inserter(extra));
if (missing.empty() && extra.empty()) {
- std::cout << "All expected messages were retrieved." << std::endl;
+ std::cout << "All expected messages were retrieved." << std::endl;
+ return 0;
} else {
if (!missing.empty()) {
std::cout << "The following ids were missing:" << std::endl;
for (StringSet::iterator i = missing.begin(); i != missing.end(); i++) {
- std::cout << " '" << *i << "'" << std::endl;
- }
+ std::cout << " '" << *i << "'" << std::endl;
+ }
}
if (!extra.empty()) {
std::cout << "The following extra ids were encountered:" << std::endl;
for (StringSet::iterator i = extra.begin(); i != extra.end(); i++) {
- std::cout << " '" << *i << "'" << std::endl;
- }
+ std::cout << " '" << *i << "'" << std::endl;
+ }
}
+ return 1;
}
}
};
+}} // namespace qpid::tests
+
+using namespace qpid::tests;
+
int main(int argc, char** argv)
{
try {
opts.parse(argc, argv);
Controller controller;
- if (opts.init) controller.init();
+ if (opts.init) controller.init();
if (opts.transfer) controller.transfer();
- if (opts.check) controller.check();
+ if (opts.check) return controller.check();
return 0;
} catch(const std::exception& e) {
std::cout << e.what() << std::endl;
}
- return 1;
+ return 2;
}
diff --git a/cpp/src/tests/unit_test.h b/cpp/src/tests/unit_test.h
index b986c74afa..ed9623bcc0 100644
--- a/cpp/src/tests/unit_test.h
+++ b/cpp/src/tests/unit_test.h
@@ -51,18 +51,6 @@
#endif // Workarounds for BOOST_AUTO_TEST_CASE|SUITE|SUITE_END
-// Workaround for BOOST_AUTO_TEST_SUITE_EXPECTED_FAILURES
-//
-#if (BOOST_VERSION < 103500)
-
-// Keep the test function for compilation but do not not register it.
-// TODO aconway 2008-04-23: better workaround for expected failures.
-# define QPID_AUTO_TEST_CASE_EXPECTED_FAILURES(test_name,n) \
- namespace { struct test_name { void test_method(); }; } \
- void test_name::test_method()
-
-#endif // Workaround for BOOST_AUTO_TEST_SUITE_EXPECTED_FAILURES
-
//
// Default definitions for latest version of boost.
//
@@ -75,10 +63,6 @@
# define QPID_AUTO_TEST_CASE(name) BOOST_AUTO_TEST_CASE(name)
#endif
-#ifndef QPID_AUTO_TEST_CASE_EXPECTED_FAILURES
-# define QPID_AUTO_TEST_CASE_EXPECTED_FAILURES(name,n) BOOST_AUTO_TEST_SUITE_EXPECTED_FAILURES(name,n)
-#endif
-
#ifndef QPID_AUTO_TEST_SUITE_END
# define QPID_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
#endif
diff --git a/cpp/src/tests/vg_check b/cpp/src/tests/vg_check
index e9a691abe6..c5a1e6d2d0 100644
--- a/cpp/src/tests/vg_check
+++ b/cpp/src/tests/vg_check
@@ -1,6 +1,7 @@
# Check for valgrind errors. Sourced by test scripts.
vg_failed() {
+ echo "Valgrind error log in $VG_LOG." 1>&2
cat $VG_LOG 1>&2
echo $1 1>&2
exit 1
@@ -12,10 +13,10 @@ vg_check()
test -f $VG_LOG || vg_failed Valgrind log file $VG_LOG missing.
# Ensure there is an ERROR SUMMARY line.
grep -E '^==[0-9]+== ERROR SUMMARY:' $VG_LOG > /dev/null || \
- vg_failed "No valgrind ERROR SUMMARY line in $$vg_failed."
+ vg_failed "No valgrind ERROR SUMMARY line in $VG_LOG."
# Ensure that the number of errors is 0.
grep -E '^==[0-9]+== ERROR SUMMARY: [^0]' $VG_LOG > /dev/null && \
- vg_failed "Valgrind reported errors in $vg_out; see above."
+ vg_failed "Valgrind reported errors in $VG_LOG; see above."
# Check for leaks.
grep -E '^==[0-9]+== +.* lost: [^0]' $VG_LOG && \
vg_failed "Found memory leaks (see log file, $VG_LOG); see above."
diff --git a/cpp/src/tests/windows/DisableWin32ErrorWindows.cpp b/cpp/src/tests/windows/DisableWin32ErrorWindows.cpp
new file mode 100644
index 0000000000..a0b665db73
--- /dev/null
+++ b/cpp/src/tests/windows/DisableWin32ErrorWindows.cpp
@@ -0,0 +1,72 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+// This file intends to prevent Windows from throwing up error boxes and
+// offering to debug when serious errors happen. The errors are displayed
+// on stderr instead. The purpose of this is to allow the tests to proceed
+// scripted and catch the text for logging. If this behavior is desired,
+// include this file with the executable being built. If the default
+// behaviors are desired, don't include this file in the build.
+
+#include <crtdbg.h>
+#include <windows.h>
+#include <iostream>
+
+namespace {
+
+// Instead of popping up a window for exceptions, just print something out
+LONG _stdcall UnhandledExceptionFilter (PEXCEPTION_POINTERS pExceptionInfo)
+{
+ DWORD dwExceptionCode = pExceptionInfo->ExceptionRecord->ExceptionCode;
+
+ if (dwExceptionCode == EXCEPTION_ACCESS_VIOLATION)
+ std::cerr << "\nERROR: ACCESS VIOLATION\n" << std::endl;
+ else
+ std::cerr << "\nERROR: UNHANDLED EXCEPTION\n" << std::endl;
+
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+struct redirect_errors_to_stderr {
+ redirect_errors_to_stderr ();
+};
+
+static redirect_errors_to_stderr block;
+
+redirect_errors_to_stderr::redirect_errors_to_stderr()
+{
+ _CrtSetReportMode (_CRT_WARN, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile (_CRT_WARN, _CRTDBG_FILE_STDERR);
+ _CrtSetReportMode (_CRT_ERROR, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile (_CRT_ERROR, _CRTDBG_FILE_STDERR);
+ _CrtSetReportMode (_CRT_ASSERT, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile (_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+
+ // Prevent the system from displaying the critical-error-handler
+ // and can't-open-file message boxes.
+ SetErrorMode(SEM_FAILCRITICALERRORS);
+ SetErrorMode(SEM_NOOPENFILEERRORBOX);
+
+ // And this will catch all unhandled exceptions.
+ SetUnhandledExceptionFilter (&UnhandledExceptionFilter);
+}
+
+} // namespace
diff --git a/cpp/src/windows/QpiddBroker.cpp b/cpp/src/windows/QpiddBroker.cpp
new file mode 100644
index 0000000000..15380dda0b
--- /dev/null
+++ b/cpp/src/windows/QpiddBroker.cpp
@@ -0,0 +1,310 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#else
+// These need to be made something sensible, like reading a value from
+// the registry. But for now, get things going with a local definition.
+namespace {
+const char *QPIDD_CONF_FILE = "qpid_broker.conf";
+const char *QPIDD_MODULE_DIR = ".";
+}
+#endif
+#include "qpidd.h"
+#include "qpid/Exception.h"
+#include "qpid/Options.h"
+#include "qpid/Plugin.h"
+#include "qpid/sys/IntegerTypes.h"
+#include "qpid/sys/windows/check.h"
+#include "qpid/broker/Broker.h"
+
+#include <iostream>
+#include <windows.h>
+
+using namespace qpid::broker;
+
+BootstrapOptions::BootstrapOptions(const char* argv0)
+ : qpid::Options("Options"),
+ common("", QPIDD_CONF_FILE),
+ module(QPIDD_MODULE_DIR),
+ log(argv0)
+{
+ add(common);
+ add(module);
+ add(log);
+}
+
+// Local functions to set and get the pid via a LockFile.
+namespace {
+
+const std::string TCP = "tcp";
+
+// ShutdownEvent maintains an event that can be used to ask the broker
+// to stop. Analogous to sending SIGTERM/SIGINT to the posix broker.
+// The signal() method signals the event.
+class ShutdownEvent {
+ public:
+ ShutdownEvent(int port);
+ ~ShutdownEvent();
+
+ void create();
+ void open();
+ void signal();
+
+ private:
+ std::string eventName;
+
+ protected:
+ HANDLE event;
+};
+
+class ShutdownHandler : public ShutdownEvent, public qpid::sys::Runnable {
+ public:
+ ShutdownHandler(int port, const boost::intrusive_ptr<Broker>& b)
+ : ShutdownEvent(port) { broker = b; }
+
+ private:
+ virtual void run(); // Inherited from Runnable
+ boost::intrusive_ptr<Broker> broker;
+};
+
+ShutdownEvent::ShutdownEvent(int port) : event(NULL) {
+ std::ostringstream name;
+ name << "qpidd_" << port << std::ends;
+ eventName = name.str();
+}
+
+void ShutdownEvent::create() {
+ // Auto-reset event in case multiple processes try to signal a
+ // broker that doesn't respond for some reason. Initially not signaled.
+ event = ::CreateEvent(NULL, false, false, eventName.c_str());
+ QPID_WINDOWS_CHECK_NULL(event);
+}
+
+void ShutdownEvent::open() {
+ // TODO: Might need to search Global\\ name if unadorned name fails
+ event = ::OpenEvent(EVENT_MODIFY_STATE, false, eventName.c_str());
+ QPID_WINDOWS_CHECK_NULL(event);
+}
+
+ShutdownEvent::~ShutdownEvent() {
+ ::CloseHandle(event);
+ event = NULL;
+}
+
+void ShutdownEvent::signal() {
+ QPID_WINDOWS_CHECK_NOT(::SetEvent(event), 0);
+}
+
+
+void ShutdownHandler::run() {
+ if (event == NULL)
+ return;
+ ::WaitForSingleObject(event, INFINITE);
+ if (broker.get()) {
+ broker->shutdown();
+ broker = 0; // Release the broker reference
+ }
+}
+
+// Console control handler to properly handle ctl-c.
+int ourPort;
+BOOL CtrlHandler(DWORD ctl)
+{
+ ShutdownEvent shutter(ourPort); // We have to have set up the port before interrupting
+ shutter.open();
+ shutter.signal();
+ return ((ctl == CTRL_C_EVENT || ctl == CTRL_CLOSE_EVENT) ? TRUE : FALSE);
+}
+
+template <typename T>
+class NamedSharedMemory {
+ std::string name;
+ HANDLE memory;
+ T* data;
+
+public:
+ NamedSharedMemory(const std::string&);
+ ~NamedSharedMemory();
+
+ T& create();
+ T& get();
+};
+
+template <typename T>
+NamedSharedMemory<T>::NamedSharedMemory(const std::string& n) :
+ name(n),
+ memory(NULL),
+ data(0)
+{};
+
+template <typename T>
+NamedSharedMemory<T>::~NamedSharedMemory() {
+ if (data)
+ ::UnmapViewOfFile(data);
+ if (memory != NULL)
+ ::CloseHandle(memory);
+};
+
+template <typename T>
+T& NamedSharedMemory<T>::create() {
+ assert(memory == NULL);
+
+ // Create named shared memory file
+ memory = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(T), name.c_str());
+ QPID_WINDOWS_CHECK_NULL(memory);
+
+ // Map file into memory
+ data = static_cast<T*>(::MapViewOfFile(memory, FILE_MAP_WRITE, 0, 0, 0));
+ QPID_WINDOWS_CHECK_NULL(data);
+
+ return *data;
+}
+
+template <typename T>
+T& NamedSharedMemory<T>::get() {
+ if (memory == NULL) {
+ // TODO: Might need to search Global\\ name if unadorned name fails
+ memory = ::OpenFileMapping(FILE_MAP_WRITE, FALSE, name.c_str());
+ QPID_WINDOWS_CHECK_NULL(memory);
+
+ data = static_cast<T*>(::MapViewOfFile(memory, FILE_MAP_WRITE, 0, 0, 0));
+ QPID_WINDOWS_CHECK_NULL(data);
+ }
+
+ return *data;
+}
+
+std::string brokerInfoName(uint16_t port)
+{
+ std::ostringstream path;
+ path << "qpidd_info_" << port;
+ return path.str();
+}
+
+struct BrokerInfo {
+ DWORD pid;
+};
+
+}
+
+struct ProcessControlOptions : public qpid::Options {
+ bool quit;
+ bool check;
+ //std::string transport; No transport options yet - TCP is it.
+
+ ProcessControlOptions()
+ : qpid::Options("Process control options"),
+ quit(false),
+ check(false) //, transport(TCP)
+ {
+ // Only have TCP for now, so don't need this...
+ // ("transport", optValue(transport, "TRANSPORT"), "The transport for which to return the port")
+ addOptions()
+ ("check,c", qpid::optValue(check), "Prints the broker's process ID to stdout and returns 0 if the broker is running, otherwise returns 1")
+ ("quit,q", qpid::optValue(quit), "Tells the broker to shut down");
+ }
+};
+
+struct QpiddWindowsOptions : public QpiddOptionsPrivate {
+ ProcessControlOptions control;
+ QpiddWindowsOptions(QpiddOptions *parent) : QpiddOptionsPrivate(parent) {
+ parent->add(control);
+ }
+};
+
+QpiddOptions::QpiddOptions(const char* argv0)
+ : qpid::Options("Options"),
+ common("", QPIDD_CONF_FILE),
+ module(QPIDD_MODULE_DIR),
+ log(argv0)
+{
+ add(common);
+ add(module);
+ add(broker);
+ add(log);
+
+ platform.reset(new QpiddWindowsOptions(this));
+ qpid::Plugin::addOptions(*this);
+}
+
+void QpiddOptions::usage() const {
+ std::cout << "Usage: qpidd [OPTIONS]" << std::endl << std::endl
+ << *this << std::endl;
+}
+
+int QpiddBroker::execute (QpiddOptions *options) {
+ // Options that affect a running daemon.
+ QpiddWindowsOptions *myOptions =
+ reinterpret_cast<QpiddWindowsOptions *>(options->platform.get());
+ if (myOptions == 0)
+ throw qpid::Exception("Internal error obtaining platform options");
+
+ if (myOptions->control.check || myOptions->control.quit) {
+ // Relies on port number being set via --port or QPID_PORT env variable.
+ NamedSharedMemory<BrokerInfo> info(brokerInfoName(options->broker.port));
+ int pid = info.get().pid;
+ if (pid < 0)
+ return 1;
+ if (myOptions->control.check)
+ std::cout << pid << std::endl;
+ if (myOptions->control.quit) {
+ ShutdownEvent shutter(options->broker.port);
+ shutter.open();
+ shutter.signal();
+ HANDLE brokerHandle = ::OpenProcess(SYNCHRONIZE, false, pid);
+ QPID_WINDOWS_CHECK_NULL(brokerHandle);
+ ::WaitForSingleObject(brokerHandle, INFINITE);
+ ::CloseHandle(brokerHandle);
+ }
+ return 0;
+ }
+
+ boost::intrusive_ptr<Broker> brokerPtr(new Broker(options->broker));
+
+ // Need the correct port number to use in the pid file name.
+ if (options->broker.port == 0)
+ options->broker.port = brokerPtr->getPort("");
+
+ BrokerInfo info;
+ info.pid = ::GetCurrentProcessId();
+
+ NamedSharedMemory<BrokerInfo> sharedInfo(brokerInfoName(options->broker.port));
+ sharedInfo.create() = info;
+
+ // Allow the broker to receive a shutdown request via a qpidd --quit
+ // command. Note that when the broker is run as a service this operation
+ // should not be allowed.
+ ourPort = options->broker.port;
+ ShutdownHandler waitShut(ourPort, brokerPtr);
+ waitShut.create();
+ qpid::sys::Thread waitThr(waitShut); // Wait for shutdown event
+ ::SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE);
+ brokerPtr->accept();
+ std::cout << options->broker.port << std::endl;
+ brokerPtr->run();
+ waitShut.signal(); // In case we shut down some other way
+ waitThr.join();
+
+ // CloseHandle(h);
+ return 0;
+}
diff --git a/cpp/src/xml.mk b/cpp/src/xml.mk
new file mode 100644
index 0000000000..957a18efde
--- /dev/null
+++ b/cpp/src/xml.mk
@@ -0,0 +1,28 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+dmodule_LTLIBRARIES += xml.la
+
+xml_la_SOURCES = \
+ qpid/xml/XmlExchange.cpp \
+ qpid/xml/XmlExchange.h \
+ qpid/xml/XmlExchangePlugin.cpp
+
+xml_la_LIBADD = -lxerces-c -lxqilla libqpidbroker.la
+
+xml_la_LDFLAGS = $(PLUGINLDFLAGS)
diff --git a/cpp/xml/cluster.xml b/cpp/xml/cluster.xml
index 6dfb4d14c3..e2c69d33fd 100644
--- a/cpp/xml/cluster.xml
+++ b/cpp/xml/cluster.xml
@@ -20,18 +20,209 @@
-
-->
+<!--
+- NOTE: if you make changes to this XML you must update CLUSTER_VERSION
+- in src/qpid/cluster/Cluster.cpp
+-->
+
<amqp major="0" minor="10" port="5672">
+ <!-- Controls sent between cluster nodes. -->
+
<class name = "cluster" code = "0x80" label="Qpid clustering extensions.">
<doc>Qpid extension class to allow clustered brokers to communicate.</doc>
- <control name = "notify" code="0x1">
- <field name="url" type="str16" />
+ <!-- New joiner requests an update to url. -->
+ <control name="update-request" code="0x1">
+ <field name="url" type="str16"/>
+ </control>
+
+ <!-- Sender offers an update to a new joiner. -->
+ <control name = "update-offer" code="0x2">
+ <field name="updatee" type="uint64"/>
+ </control>
+
+ <!-- Sender retracts an offer to a new joiner. -->
+ <control name = "retract-offer" code="0x3">
+ <field name="updatee" type="uint64"/>
+ </control>
+
+ <!-- Possible states for persistent store -->
+ <domain name="store-state" type="uint8">
+ <enum>
+ <choice name="no-store" value="0"/>
+ <choice name="empty-store" value="1"/>
+ <choice name="clean-store" value="2"/>
+ <choice name="dirty-store" value="3"/>
+ </enum>
+ </domain>
+
+ <!-- Status exchanged when new members join the cluster. -->
+ <control name="initial-status" code="0x5">
+ <field name="version" type="uint32"/>
+ <field name="active" type="bit"/>
+ <field name="cluster-id" type="uuid"/>>
+ <field name="store-state" type="store-state"/>
+ <field name="shutdown-id" type="uuid"/>
+ </control>
+
+ <!-- New member or updater is ready as an active member. -->
+ <control name="ready" code="0x10">
+ <field name="url" type="str16"/>
+ </control>
+
+ <control name="config-change" code="0x11" label="Raw cluster membership.">
+ <field name="current" type="vbin16"/> <!-- packed member-id array -->
+ </control>
+
+ <control name="message-expired" code="0x12">
+ <field name="id" type="uint64"/>
+ </control>
+
+ <domain name="error-type" type="uint8" label="Types of error">
+ <enum>
+ <choice name="none" value="0"/>
+ <choice name="session" value="1"/>
+ <choice name="connection" value="2"/>
+ </enum>
+ </domain>
+
+ <!-- Check for error consistency across the cluster -->
+ <control name="error-check" code="0x14">
+ <field name="type" type="error-type"/>
+ <field name="frame-seq" type="sequence-no"/>
+ </control>
+
+ <!-- Shut down the entire cluster -->
+ <control name="shutdown" code="0x20">
+ <field name="shutdown-id" type="uuid"/>
+ </control>
+
+ </class>
+
+ <!-- Controls associated with a specific connection. -->
+
+ <class name="cluster-connection" code="0x81" label="Qpid clustering extensions.">
+
+ <!-- Announce a new connection -->
+ <control name="announce" code="0x1">
+ <!-- Security Strength Factor (ssf): if the transport provides
+ encryption (e.g. ssl), ssf is the bit length of the key. Zero if no
+ encryption provided. -->
+ <field name="ssf" type="uint32"/>
+ </control>
+
+ <!-- Marks the cluster-wide point when a connection is considered closed. -->
+ <control name="deliver-close" code="0x2"/>
+
+ <!-- Permission to generate output up to the limit. -->
+ <control name="deliver-do-output" code="0x3">
+ <field name="limit" type="uint32"/>
</control>
- <control name="connection-close" code="0x2"/>
+ <!-- Abort a connection that is sending invalid data. -->
+ <control name="abort" code="0x4"/>
+
+ <!-- Update controls. Sent to a new broker in joining mode.
+ A connection is updateed as followed:
+ - open as a normal connection.
+ - attach sessions, create consumers, set flow with normal AMQP cokmmands.
+ - send /reset additional session state with controls below.
+ - send shadow-ready to mark end of shadow update.
+ - send membership when entire update is complete.
+ -->
+
+ <!-- Consumer state that cannot be set by standard AMQP controls. -->
+ <control name="consumer-state" code="0x10">
+ <field name="name" type="str8"/>
+ <field name="blocked" type="bit"/>
+ <field name="notifyEnabled" type="bit"/>
+ <field name="position" type="sequence-no"/>
+ </control>
+
+ <!-- Delivery-record for outgoing messages sent but not yet accepted. -->
+ <control name="delivery-record" code ="0x11">
+ <field name="queue" type="str8"/>
+ <field name="position" type="sequence-no"/>
+ <field name="tag" type="str8"/>
+ <field name="id" type="sequence-no"/>
+ <field name="acquired" type="bit"/> <!--If not set, message follows. -->
+ <field name="accepted" type="bit"/>
+ <field name="cancelled" type="bit"/>
+ <field name="completed" type="bit"/>
+ <field name="ended" type="bit"/>
+ <field name="windowing" type="bit"/>
+ <field name="enqueued" type="bit"/>
+ <field name="credit" type="uint32"/>
+ </control>
+
+ <!-- Tx transaction state. -->
+ <control name="tx-start" code="0x12"/>
+ <control name="tx-accept" code="0x13"> <field name="commands" type="sequence-set"/> </control>
+ <control name="tx-dequeue" code="0x14"> <field name="queue" type="str8"/> </control>
+ <control name="tx-enqueue" code="0x15"> <field name="queue" type="str8"/> </control>
+ <control name="tx-publish" code="0x16">
+ <field name="queues" type="array"/> <!--Array of str8 -->
+ <field name="delivered" type="bit"/>
+ </control>
+ <control name="tx-end" code="0x17"/>
+ <control name="accumulated-ack" code="0x18"> <field name="commands" type="sequence-set"/> </control>
+
+ <!-- Consumers in the connection's output task -->
+ <control name="output-task" code="0x19">
+ <field name="channel" type="uint16"/>
+ <field name="name" type="str8"/>
+ </control>
- <control name="connection-do-output" code="0x3"/>
+ <!-- Complete a session state update. -->
+ <control name="session-state" code="0x1F">
+ <!-- Target session deduced from channel number. -->
+ <field name="replay-start" type="sequence-no"/> <!-- Replay frames will start from this point.-->
+ <field name="command-point" type="sequence-no"/> <!-- Id of next command sent -->
+ <field name="sent-incomplete" type="sequence-set"/> <!-- Commands sent and incomplete. -->
+ <field name="expected" type="sequence-no"/> <!-- Next command expected. -->
+ <field name="received" type="sequence-no"/> <!-- Received up to here (>= expected) -->
+ <field name="unknown-completed" type="sequence-set"/> <!-- Completed but not known to peer. -->
+ <field name="received-incomplete" type="sequence-set"/> <!-- Received and incomplete -->
+ </control>
+
+ <!-- Complete a shadow connection update. -->
+ <control name="shadow-ready" code="0x20" label="End of shadow connection update.">
+ <field name="member-id" type="uint64"/>
+ <field name="connection-id" type="uint64"/>
+ <field name="user-name" type="str8"/>
+ <field name="fragment" type="str32"/>
+ <field name="send-max" type="uint32"/>
+ </control>
+
+ <!-- Complete a cluster state update. -->
+ <control name="membership" code="0x21" label="Cluster membership details.">
+ <field name="joiners" type="map"/> <!-- member-id -> URL -->
+ <field name="members" type="map"/> <!-- member-id -> state -->
+ <field name="frame-seq" type="sequence-no"/> <!-- frame sequence number -->
+ </control>
+
+ <!-- Updater cannot fulfill an update offer. -->
+ <control name = "retract-offer" code="0x22"/>
+
+ <!-- Set the position of a replicated queue. -->
+ <control name="queue-position" code="0x30">
+ <field name="queue" type="str8"/>
+ <field name="position" type="sequence-no"/>
+ </control>
+
+ <!-- Replicate encoded exchanges/queues. -->
+ <control name="exchange" code="0x31"><field name="encoded" type="str32"/></control>
+ <control name="queue" code="0x32"><field name="encoded" type="str32"/></control>
+
+ <!-- Set expiry-id for subsequent messages. -->
+ <control name="expiry-id" code="0x33"><field name="expiry-id" type="uint64"/></control>
+
+ <!-- Add a listener to a queue -->
+ <control name="add-queue-listener" code="0x34">
+ <field name="queue" type="str8"/>
+ <field name="consumer" type="uint32"/>
+ </control>
</class>
</amqp>
diff --git a/dotnet/DISCLAIMER b/dotnet/DISCLAIMER
deleted file mode 100644
index c9a0ddf8f9..0000000000
--- a/dotnet/DISCLAIMER
+++ /dev/null
@@ -1,5 +0,0 @@
-Apache Qpid is an effort undergoing incubation at the Apache Software Foundation (ASF), sponsored by the Apache Incubator PMC.
-
-Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects.
-
-While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF.
diff --git a/dotnet/NOTICE.txt b/dotnet/NOTICE.txt
index 910974b01c..0b22ed3ab2 100644
--- a/dotnet/NOTICE.txt
+++ b/dotnet/NOTICE.txt
@@ -23,4 +23,10 @@ This product also includes software developed by:
- The Mentalis Security Library, Copyright 2002-2006, , The Mentalis.org Team
under tterms based on the BSD license (http://www.mentalis.org/site/license.qpx).
- Available from http://www.mentalis.org/soft/projects/seclib/ \ No newline at end of file
+ Available from http://www.mentalis.org/soft/projects/seclib/
+
+This product includes software, Apache Log4Net
+(http://logging.apache.org/log4net)
+License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
+
+
diff --git a/dotnet/Qpid.Buffer.Tests/Properties/AssemblyInfo.cs b/dotnet/Qpid.Buffer.Tests/Properties/AssemblyInfo.cs
index fa7f41dbda..2f49033c2d 100644
--- a/dotnet/Qpid.Buffer.Tests/Properties/AssemblyInfo.cs
+++ b/dotnet/Qpid.Buffer.Tests/Properties/AssemblyInfo.cs
@@ -1,35 +1,56 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Apache.Qpid.Buffer.Tests")]
-[assembly: AssemblyDescription("Built from svn revision number: ")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Apache Software Foundation")]
-[assembly: AssemblyProduct("Apache.Qpid.Buffer.Tests")]
-[assembly: AssemblyCopyright("Apache Software Foundation")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("9d967d0b-9454-4f00-8f53-fa86fd62b696")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Revision and Build Numbers
-// by using the '*' as shown below:
-[assembly: AssemblyVersion("2.1.0.0")]
-[assembly: AssemblyFileVersion("1.0.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.
+ *
+ */
+
+ using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Apache.Qpid.Buffer.Tests")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("Apache.Qpid.Buffer.Tests")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("9d967d0b-9454-4f00-8f53-fa86fd62b696")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/Qpid.Buffer.Tests/Qpid.Buffer.Tests.csproj b/dotnet/Qpid.Buffer.Tests/Qpid.Buffer.Tests.csproj
index 379997ab11..72d3ccc82f 100644
--- a/dotnet/Qpid.Buffer.Tests/Qpid.Buffer.Tests.csproj
+++ b/dotnet/Qpid.Buffer.Tests/Qpid.Buffer.Tests.csproj
@@ -1,59 +1,83 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <PropertyGroup>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProductVersion>8.0.50727</ProductVersion>
- <SchemaVersion>2.0</SchemaVersion>
- <ProjectGuid>{74640962-99D0-4D06-B57A-9CD66517CF52}</ProjectGuid>
- <OutputType>Library</OutputType>
- <AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>Apache.Qpid.Buffer.Tests</RootNamespace>
- <AssemblyName>Apache.Qpid.Buffer.Tests</AssemblyName>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>..\bin\net-2.0\debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- <UseVSHostingProcess>true</UseVSHostingProcess>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>pdbonly</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>..\bin\net-2.0\release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <ItemGroup>
- <Reference Include="nunit.framework, Version=2.2.8.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\Qpid.Client.Tests\lib\nunit\nunit.framework.dll</HintPath>
- </Reference>
- <Reference Include="System" />
- <Reference Include="System.Data" />
- <Reference Include="System.Xml" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="SlicedByteBufferTests.cs" />
- <Compile Include="SimpleByteBufferTests.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- </ItemGroup>
- <ItemGroup>
- <ProjectReference Include="..\Qpid.Buffer\Qpid.Buffer.csproj">
- <Project>{44384DF2-B0A4-4580-BDBC-EE4BAA87D995}</Project>
- <Name>Qpid.Buffer</Name>
- </ProjectReference>
- </ItemGroup>
- <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
- <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
- Other similar extension points exist, see Microsoft.Common.targets.
- <Target Name="BeforeBuild">
- </Target>
- <Target Name="AfterBuild">
- </Target>
- -->
-</Project> \ No newline at end of file
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.50727</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{74640962-99D0-4D06-B57A-9CD66517CF52}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Apache.Qpid.Buffer.Tests</RootNamespace>
+ <AssemblyName>Apache.Qpid.Buffer.Tests</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\bin\net-2.0\debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <UseVSHostingProcess>true</UseVSHostingProcess>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\bin\net-2.0\release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="nunit.framework, Version=2.2.8.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\Qpid.Client.Tests\lib\nunit\nunit.framework.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="**\*.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Qpid.Buffer\Qpid.Buffer.csproj">
+ <Project>{44384DF2-B0A4-4580-BDBC-EE4BAA87D995}</Project>
+ <Name>Qpid.Buffer</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/dotnet/Qpid.Buffer.Tests/SimpleByteBufferTests.cs b/dotnet/Qpid.Buffer.Tests/SimpleByteBufferTests.cs
index 9af8801627..b028bdb1ee 100644
--- a/dotnet/Qpid.Buffer.Tests/SimpleByteBufferTests.cs
+++ b/dotnet/Qpid.Buffer.Tests/SimpleByteBufferTests.cs
@@ -1,333 +1,333 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using NUnit.Framework;
-using Apache.Qpid.Buffer;
-
-namespace Apache.Qpid.Buffer.Tests
-{
- /// <summary>
- /// Tests for the SimpleByteBuffer class
- /// </summary>
- [TestFixture]
- public class SimpleByteBufferTests
- {
- [Test]
- public void CanCreateNewBuffer()
- {
- const int size = 10;
- ByteBuffer buffer = ByteBuffer.Allocate(size);
- Assert.AreEqual(size, buffer.Capacity);
- Assert.AreEqual(0, buffer.Position);
- Assert.AreEqual(size, buffer.Remaining);
- Assert.AreEqual(true, buffer.HasRemaining);
- }
-
- [Test]
- public void CanWrapArray()
- {
- byte[] array = new byte[10];
- for ( int i=0; i < array.Length; i++ )
- {
- array[i] = (byte) i;
- }
- ByteBuffer buffer = ByteBuffer.Wrap(array);
- // the buffer should be the same size,
- // and positioned at the end
- Assert.AreEqual(array.Length, buffer.Capacity);
- Assert.AreEqual(array.Length, buffer.Position);
- Assert.AreEqual(array.Length, buffer.Limit);
- }
-
- #region Base Read/Write tests
- //
- // Base Read/Write tests
- //
- [Test]
- public void CanReadWriteBytes()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(10);
- buffer.Put((byte)0x01).Put((byte)0x02).Put((byte)0x03);
- buffer.Rewind();
- Assert.AreEqual(0x01, buffer.GetByte());
- Assert.AreEqual(0x02, buffer.GetByte());
- Assert.AreEqual(0x03, buffer.GetByte());
- }
-
- [Test]
- [ExpectedException(typeof(BufferUnderflowException))]
- public void ThrowOnReadByteWithNoSpace()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(1);
- buffer.Put((byte)0x01);
- buffer.GetByte();
- }
-
- [Test]
- [ExpectedException(typeof(BufferOverflowException))]
- public void ThrowOnWriteByteWithNoSpace()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(1);
- buffer.Put((byte)0x01).Put((byte)0x02);
- }
-
- #endregion Base Read/Write tests
-
- #region Other Buffer Operations
- //
- // Other Buffer Operations
- //
-
- [Test]
- public void CanFlipBuffer()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(10);
- buffer.Put((byte)0x01).Put((byte)0x02).Put((byte)0x03);
- buffer.Flip();
- Assert.AreEqual(10, buffer.Capacity);
- Assert.AreEqual(3, buffer.Limit);
- Assert.AreEqual(0, buffer.Position);
- Assert.AreEqual(3, buffer.Remaining);
- }
-
- [Test]
- public void CanCompactBuffer()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(10);
- buffer.Put((byte)0x01).Put((byte)0x02).Put((byte)0x03);
- buffer.Flip();
- buffer.Position = 1;
- buffer.Compact();
- Assert.AreEqual(10, buffer.Capacity);
- Assert.AreEqual(10, buffer.Limit);
- Assert.AreEqual(2, buffer.Position);
- Assert.AreEqual(8, buffer.Remaining);
- buffer.Rewind();
- Assert.AreEqual((byte)0x02, buffer.GetByte());
- Assert.AreEqual((byte)0x03, buffer.GetByte());
- }
-
- [Test]
- public void CanClearBuffer()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(10);
- buffer.Put((byte)0x01).Put((byte)0x02).Put((byte)0x03);
- buffer.Flip();
- buffer.Position = 2;
- buffer.Clear();
- Assert.AreEqual(10, buffer.Capacity);
- Assert.AreEqual(10, buffer.Limit);
- Assert.AreEqual(0, buffer.Position);
- Assert.AreEqual(10, buffer.Remaining);
- }
-
- [Test]
- public void CanExpandBuffer()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(10);
- buffer.Put((byte)0x01).Put((byte)0x02).Put((byte)0x03);
- buffer.Flip();
- buffer.Position = 2;
- int pos = buffer.Position;
- buffer.Expand(20);
-
- Assert.AreEqual(pos, buffer.Position);
- Assert.IsTrue(buffer.Remaining >= 20);
- buffer.Rewind();
- Assert.AreEqual(0x01, buffer.GetByte());
- }
-
- [Test]
- public void CanAutoExpand()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(2);
- buffer.IsAutoExpand = true;
- // should cause autoexpand
- buffer.Put((byte)0x01).Put((byte)0x02).Put((byte)0x03);
- Assert.IsTrue(buffer.Capacity > 2);
- }
-
- [Test]
- public void CanGetArray()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(10);
- buffer.Put((byte)0x01).Put((byte)0x02).Put((byte)0x03);
- buffer.Flip();
-
- byte[] array = buffer.Array;
- for ( int i=0; i < buffer.Limit; i++ )
- {
- Assert.AreEqual(buffer.GetByte(), array[i]);
- }
- }
-
- [Test]
- public void CanSkip()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(10);
- buffer.Skip(4);
- Assert.AreEqual(4, buffer.Position);
- }
-
- #endregion // Base Read/Write tests
-
- #region Typed Accessors
- //
- // Typed Accessors
- //
- [Test]
- public void CanReadWriteSByte()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(10);
- sbyte value = -12;
- buffer.Put(value);
- buffer.Flip();
- Assert.AreEqual(value, buffer.GetSByte());
- }
- [Test]
- public void CanReadWriteUInt16()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(10);
- ushort value = 41233;
- buffer.Put(value);
- buffer.Flip();
- Assert.AreEqual(value, buffer.GetUInt16());
- }
- [Test]
- public void CanReadWriteInt16()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(10);
- short value = -21233;
- buffer.Put(value);
- buffer.Flip();
- Assert.AreEqual(value, buffer.GetInt16());
- }
- [Test]
- public void CanReadWriteUInt32()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(10);
- uint value = 41233211;
- buffer.Put(value);
- buffer.Flip();
- Assert.AreEqual(value, buffer.GetUInt32());
- }
- [Test]
- public void CanReadWriteInt32()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(10);
- int value = -22221233;
- buffer.Put(value);
- buffer.Flip();
- Assert.AreEqual(value, buffer.GetInt32());
- }
- [Test]
- public void CanReadWriteUInt64()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(10);
- ulong value = 41233218871;
- buffer.Put(value);
- buffer.Flip();
- Assert.AreEqual(value, buffer.GetUInt64());
- }
- [Test]
- public void CanReadWriteInt64()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(10);
- long value = -9887335411;
- buffer.Put(value);
- buffer.Flip();
- Assert.AreEqual(value, buffer.GetInt64());
- }
- [Test]
- public void CanReadWriteFloat()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(10);
- float value = -1.2331f;
- buffer.Put(value);
- buffer.Flip();
- Assert.AreEqual(value, buffer.GetFloat());
- }
-
- [Test]
- public void CanReadWriteDouble()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(10);
- double value = -1.2331E12;
- buffer.Put(value);
- buffer.Flip();
- Assert.AreEqual(value, buffer.GetDouble());
- }
-
- [Test]
- public void CanReadWriteChar()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(10);
- char value = 'H';
- buffer.Put(value);
- buffer.Flip();
- Assert.AreEqual(value, buffer.GetChar());
- }
-
- [Test]
- public void CanReadWriteByteArray()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(10);
- buffer.Put(new byte[] { 0x01, 0x02, 0x03});
- buffer.Flip();
- byte[] data = new byte[3];
- buffer.GetBytes(data);
- Assert.AreEqual(0x01, data[0]);
- Assert.AreEqual(0x02, data[1]);
- Assert.AreEqual(0x03, data[2]);
- }
-
- [Test]
- public void CanReadWriteByteArrayWithOffset()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(10);
- buffer.Put(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 }, 1, 4);
- buffer.Flip();
- byte[] data = new byte[3];
- buffer.GetBytes(data, 2, 1);
- Assert.AreEqual(0x00, data[0]);
- Assert.AreEqual(0x00, data[1]);
- Assert.AreEqual(0x02, data[2]);
- }
-
- [Test]
- public void CanWriteByteBuffer()
- {
- ByteBuffer buffer1 = ByteBuffer.Allocate(10);
- buffer1.Put((byte)0x01).Put((byte)0x02).Put((byte)0x03);
- buffer1.Flip();
-
- ByteBuffer buffer2 = ByteBuffer.Allocate(10);
- buffer2.Put(buffer1);
- buffer2.Flip();
- Assert.AreEqual(buffer1.Limit, buffer2.Limit);
- Assert.AreEqual(0x01, buffer2.GetByte());
- }
- #endregion // Typed Accessors
-
- } // class SimpleByteBufferTests
-}
-
-
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using NUnit.Framework;
+using Apache.Qpid.Buffer;
+
+namespace Apache.Qpid.Buffer.Tests
+{
+ /// <summary>
+ /// Tests for the SimpleByteBuffer class
+ /// </summary>
+ [TestFixture]
+ public class SimpleByteBufferTests
+ {
+ [Test]
+ public void CanCreateNewBuffer()
+ {
+ const int size = 10;
+ ByteBuffer buffer = ByteBuffer.Allocate(size);
+ Assert.AreEqual(size, buffer.Capacity);
+ Assert.AreEqual(0, buffer.Position);
+ Assert.AreEqual(size, buffer.Remaining);
+ Assert.AreEqual(true, buffer.HasRemaining);
+ }
+
+ [Test]
+ public void CanWrapArray()
+ {
+ byte[] array = new byte[10];
+ for ( int i=0; i < array.Length; i++ )
+ {
+ array[i] = (byte) i;
+ }
+ ByteBuffer buffer = ByteBuffer.Wrap(array);
+ // the buffer should be the same size,
+ // and positioned at the end
+ Assert.AreEqual(array.Length, buffer.Capacity);
+ Assert.AreEqual(array.Length, buffer.Position);
+ Assert.AreEqual(array.Length, buffer.Limit);
+ }
+
+ #region Base Read/Write tests
+ //
+ // Base Read/Write tests
+ //
+ [Test]
+ public void CanReadWriteBytes()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(10);
+ buffer.Put((byte)0x01).Put((byte)0x02).Put((byte)0x03);
+ buffer.Rewind();
+ Assert.AreEqual(0x01, buffer.GetByte());
+ Assert.AreEqual(0x02, buffer.GetByte());
+ Assert.AreEqual(0x03, buffer.GetByte());
+ }
+
+ [Test]
+ [ExpectedException(typeof(BufferUnderflowException))]
+ public void ThrowOnReadByteWithNoSpace()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(1);
+ buffer.Put((byte)0x01);
+ buffer.GetByte();
+ }
+
+ [Test]
+ [ExpectedException(typeof(BufferOverflowException))]
+ public void ThrowOnWriteByteWithNoSpace()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(1);
+ buffer.Put((byte)0x01).Put((byte)0x02);
+ }
+
+ #endregion Base Read/Write tests
+
+ #region Other Buffer Operations
+ //
+ // Other Buffer Operations
+ //
+
+ [Test]
+ public void CanFlipBuffer()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(10);
+ buffer.Put((byte)0x01).Put((byte)0x02).Put((byte)0x03);
+ buffer.Flip();
+ Assert.AreEqual(10, buffer.Capacity);
+ Assert.AreEqual(3, buffer.Limit);
+ Assert.AreEqual(0, buffer.Position);
+ Assert.AreEqual(3, buffer.Remaining);
+ }
+
+ [Test]
+ public void CanCompactBuffer()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(10);
+ buffer.Put((byte)0x01).Put((byte)0x02).Put((byte)0x03);
+ buffer.Flip();
+ buffer.Position = 1;
+ buffer.Compact();
+ Assert.AreEqual(10, buffer.Capacity);
+ Assert.AreEqual(10, buffer.Limit);
+ Assert.AreEqual(2, buffer.Position);
+ Assert.AreEqual(8, buffer.Remaining);
+ buffer.Rewind();
+ Assert.AreEqual((byte)0x02, buffer.GetByte());
+ Assert.AreEqual((byte)0x03, buffer.GetByte());
+ }
+
+ [Test]
+ public void CanClearBuffer()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(10);
+ buffer.Put((byte)0x01).Put((byte)0x02).Put((byte)0x03);
+ buffer.Flip();
+ buffer.Position = 2;
+ buffer.Clear();
+ Assert.AreEqual(10, buffer.Capacity);
+ Assert.AreEqual(10, buffer.Limit);
+ Assert.AreEqual(0, buffer.Position);
+ Assert.AreEqual(10, buffer.Remaining);
+ }
+
+ [Test]
+ public void CanExpandBuffer()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(10);
+ buffer.Put((byte)0x01).Put((byte)0x02).Put((byte)0x03);
+ buffer.Flip();
+ buffer.Position = 2;
+ int pos = buffer.Position;
+ buffer.Expand(20);
+
+ Assert.AreEqual(pos, buffer.Position);
+ Assert.IsTrue(buffer.Remaining >= 20);
+ buffer.Rewind();
+ Assert.AreEqual(0x01, buffer.GetByte());
+ }
+
+ [Test]
+ public void CanAutoExpand()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(2);
+ buffer.IsAutoExpand = true;
+ // should cause autoexpand
+ buffer.Put((byte)0x01).Put((byte)0x02).Put((byte)0x03);
+ Assert.IsTrue(buffer.Capacity > 2);
+ }
+
+ [Test]
+ public void CanGetArray()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(10);
+ buffer.Put((byte)0x01).Put((byte)0x02).Put((byte)0x03);
+ buffer.Flip();
+
+ byte[] array = buffer.Array;
+ for ( int i=0; i < buffer.Limit; i++ )
+ {
+ Assert.AreEqual(buffer.GetByte(), array[i]);
+ }
+ }
+
+ [Test]
+ public void CanSkip()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(10);
+ buffer.Skip(4);
+ Assert.AreEqual(4, buffer.Position);
+ }
+
+ #endregion // Base Read/Write tests
+
+ #region Typed Accessors
+ //
+ // Typed Accessors
+ //
+ [Test]
+ public void CanReadWriteSByte()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(10);
+ sbyte value = -12;
+ buffer.Put(value);
+ buffer.Flip();
+ Assert.AreEqual(value, buffer.GetSByte());
+ }
+ [Test]
+ public void CanReadWriteUInt16()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(10);
+ ushort value = 41233;
+ buffer.Put(value);
+ buffer.Flip();
+ Assert.AreEqual(value, buffer.GetUInt16());
+ }
+ [Test]
+ public void CanReadWriteInt16()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(10);
+ short value = -21233;
+ buffer.Put(value);
+ buffer.Flip();
+ Assert.AreEqual(value, buffer.GetInt16());
+ }
+ [Test]
+ public void CanReadWriteUInt32()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(10);
+ uint value = 41233211;
+ buffer.Put(value);
+ buffer.Flip();
+ Assert.AreEqual(value, buffer.GetUInt32());
+ }
+ [Test]
+ public void CanReadWriteInt32()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(10);
+ int value = -22221233;
+ buffer.Put(value);
+ buffer.Flip();
+ Assert.AreEqual(value, buffer.GetInt32());
+ }
+ [Test]
+ public void CanReadWriteUInt64()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(10);
+ ulong value = 41233218871;
+ buffer.Put(value);
+ buffer.Flip();
+ Assert.AreEqual(value, buffer.GetUInt64());
+ }
+ [Test]
+ public void CanReadWriteInt64()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(10);
+ long value = -9887335411;
+ buffer.Put(value);
+ buffer.Flip();
+ Assert.AreEqual(value, buffer.GetInt64());
+ }
+ [Test]
+ public void CanReadWriteFloat()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(10);
+ float value = -1.2331f;
+ buffer.Put(value);
+ buffer.Flip();
+ Assert.AreEqual(value, buffer.GetFloat());
+ }
+
+ [Test]
+ public void CanReadWriteDouble()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(10);
+ double value = -1.2331E12;
+ buffer.Put(value);
+ buffer.Flip();
+ Assert.AreEqual(value, buffer.GetDouble());
+ }
+
+ [Test]
+ public void CanReadWriteChar()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(10);
+ char value = 'H';
+ buffer.Put(value);
+ buffer.Flip();
+ Assert.AreEqual(value, buffer.GetChar());
+ }
+
+ [Test]
+ public void CanReadWriteByteArray()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(10);
+ buffer.Put(new byte[] { 0x01, 0x02, 0x03});
+ buffer.Flip();
+ byte[] data = new byte[3];
+ buffer.GetBytes(data);
+ Assert.AreEqual(0x01, data[0]);
+ Assert.AreEqual(0x02, data[1]);
+ Assert.AreEqual(0x03, data[2]);
+ }
+
+ [Test]
+ public void CanReadWriteByteArrayWithOffset()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(10);
+ buffer.Put(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 }, 1, 4);
+ buffer.Flip();
+ byte[] data = new byte[3];
+ buffer.GetBytes(data, 2, 1);
+ Assert.AreEqual(0x00, data[0]);
+ Assert.AreEqual(0x00, data[1]);
+ Assert.AreEqual(0x02, data[2]);
+ }
+
+ [Test]
+ public void CanWriteByteBuffer()
+ {
+ ByteBuffer buffer1 = ByteBuffer.Allocate(10);
+ buffer1.Put((byte)0x01).Put((byte)0x02).Put((byte)0x03);
+ buffer1.Flip();
+
+ ByteBuffer buffer2 = ByteBuffer.Allocate(10);
+ buffer2.Put(buffer1);
+ buffer2.Flip();
+ Assert.AreEqual(buffer1.Limit, buffer2.Limit);
+ Assert.AreEqual(0x01, buffer2.GetByte());
+ }
+ #endregion // Typed Accessors
+
+ } // class SimpleByteBufferTests
+}
+
+
diff --git a/dotnet/Qpid.Buffer.Tests/SlicedByteBufferTests.cs b/dotnet/Qpid.Buffer.Tests/SlicedByteBufferTests.cs
index 071aa23830..7dec7c390f 100644
--- a/dotnet/Qpid.Buffer.Tests/SlicedByteBufferTests.cs
+++ b/dotnet/Qpid.Buffer.Tests/SlicedByteBufferTests.cs
@@ -1,133 +1,133 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using NUnit.Framework;
-using Apache.Qpid.Buffer;
-
-namespace Apache.Qpid.Buffer.Tests
-{
- /// <summary>
- /// Tests for the SlicedByteBuffer class
- /// </summary>
- [TestFixture]
- public class SlicedByteBufferTests
- {
- private ByteBuffer _baseBuffer;
-
- [SetUp]
- public void Setup()
- {
- const int size = 50;
- _baseBuffer = ByteBuffer.Allocate(size);
- for ( byte b = 0; b < 10; b++ )
- {
- _baseBuffer.Put(b);
- }
- _baseBuffer.Flip();
- }
-
- [Test]
- public void CanSliceBuffer()
- {
- _baseBuffer.Position = 5;
-
- ByteBuffer slice = _baseBuffer.Slice();
- Assert.AreEqual(5, slice.Capacity);
- Assert.AreEqual(0, slice.Position);
- Assert.AreEqual(5, slice.Remaining);
- Assert.AreEqual(5, slice.Limit);
- }
-
- [Test]
- public void CanReadWriteSlice()
- {
- _baseBuffer.Position = 5;
-
- ByteBuffer slice = _baseBuffer.Slice();
- slice.Put((byte) 0xFF).Put((byte) 0xF0).Put((byte) 0xA0);
- slice.Flip();
-
- Assert.AreEqual(3, slice.Limit);
- Assert.AreEqual(0xFF, slice.GetByte());
- Assert.AreEqual(0xF0, slice.GetByte());
- Assert.AreEqual(0xA0, slice.GetByte());
- }
-
- [Test]
- public void WriteModifiesBaseBufferOnCorrectPosition()
- {
- _baseBuffer.Position = 5;
-
- ByteBuffer slice = _baseBuffer.Slice();
- slice.Put((byte) 0xFF);
- slice.Flip();
- // reading the _baseBuffer at position 5 should yield 0xFF
- _baseBuffer.Position = 5;
- Assert.AreEqual(0xFF, _baseBuffer.GetByte());
-
- }
-
- [Test]
- public void CanReadWriteByteArray()
- {
- _baseBuffer.Position = 5;
-
- ByteBuffer slice = _baseBuffer.Slice();
- byte[] data = {0xFF, 0xF0, 0xF2, 0xEE, 0x23};
- slice.Put(data, 2, 2);
- slice.Flip();
-
- Assert.AreEqual(2, slice.Limit);
- Assert.AreEqual(0xF2, slice.GetByte());
- Assert.AreEqual(0xEE, slice.GetByte());
- }
-
- [Test]
- [ExpectedException(typeof(BufferOverflowException))]
- public void ThrowWhenWritePastLimit()
- {
- _baseBuffer.Position = 5;
-
- ByteBuffer slice = _baseBuffer.Slice();
- slice.Put(0x01).Put(0x02);
- }
-
-
- [Test]
- [ExpectedException(typeof(NotSupportedException))]
- public void ThrowOnCompact()
- {
- // we don't support compacting
- ByteBuffer slice = _baseBuffer.Slice();
- slice.Compact();
- }
-
- [Test]
- [ExpectedException(typeof(NotSupportedException))]
- public void ThrowOnResize()
- {
- // we don't support resizing
- ByteBuffer slice = _baseBuffer.Slice();
- slice.Expand(50);
- }
- } // class SlicedByteBufferTests
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using NUnit.Framework;
+using Apache.Qpid.Buffer;
+
+namespace Apache.Qpid.Buffer.Tests
+{
+ /// <summary>
+ /// Tests for the SlicedByteBuffer class
+ /// </summary>
+ [TestFixture]
+ public class SlicedByteBufferTests
+ {
+ private ByteBuffer _baseBuffer;
+
+ [SetUp]
+ public void Setup()
+ {
+ const int size = 50;
+ _baseBuffer = ByteBuffer.Allocate(size);
+ for ( byte b = 0; b < 10; b++ )
+ {
+ _baseBuffer.Put(b);
+ }
+ _baseBuffer.Flip();
+ }
+
+ [Test]
+ public void CanSliceBuffer()
+ {
+ _baseBuffer.Position = 5;
+
+ ByteBuffer slice = _baseBuffer.Slice();
+ Assert.AreEqual(5, slice.Capacity);
+ Assert.AreEqual(0, slice.Position);
+ Assert.AreEqual(5, slice.Remaining);
+ Assert.AreEqual(5, slice.Limit);
+ }
+
+ [Test]
+ public void CanReadWriteSlice()
+ {
+ _baseBuffer.Position = 5;
+
+ ByteBuffer slice = _baseBuffer.Slice();
+ slice.Put((byte) 0xFF).Put((byte) 0xF0).Put((byte) 0xA0);
+ slice.Flip();
+
+ Assert.AreEqual(3, slice.Limit);
+ Assert.AreEqual(0xFF, slice.GetByte());
+ Assert.AreEqual(0xF0, slice.GetByte());
+ Assert.AreEqual(0xA0, slice.GetByte());
+ }
+
+ [Test]
+ public void WriteModifiesBaseBufferOnCorrectPosition()
+ {
+ _baseBuffer.Position = 5;
+
+ ByteBuffer slice = _baseBuffer.Slice();
+ slice.Put((byte) 0xFF);
+ slice.Flip();
+ // reading the _baseBuffer at position 5 should yield 0xFF
+ _baseBuffer.Position = 5;
+ Assert.AreEqual(0xFF, _baseBuffer.GetByte());
+
+ }
+
+ [Test]
+ public void CanReadWriteByteArray()
+ {
+ _baseBuffer.Position = 5;
+
+ ByteBuffer slice = _baseBuffer.Slice();
+ byte[] data = {0xFF, 0xF0, 0xF2, 0xEE, 0x23};
+ slice.Put(data, 2, 2);
+ slice.Flip();
+
+ Assert.AreEqual(2, slice.Limit);
+ Assert.AreEqual(0xF2, slice.GetByte());
+ Assert.AreEqual(0xEE, slice.GetByte());
+ }
+
+ [Test]
+ [ExpectedException(typeof(BufferOverflowException))]
+ public void ThrowWhenWritePastLimit()
+ {
+ _baseBuffer.Position = 5;
+
+ ByteBuffer slice = _baseBuffer.Slice();
+ slice.Put(0x01).Put(0x02);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NotSupportedException))]
+ public void ThrowOnCompact()
+ {
+ // we don't support compacting
+ ByteBuffer slice = _baseBuffer.Slice();
+ slice.Compact();
+ }
+
+ [Test]
+ [ExpectedException(typeof(NotSupportedException))]
+ public void ThrowOnResize()
+ {
+ // we don't support resizing
+ ByteBuffer slice = _baseBuffer.Slice();
+ slice.Expand(50);
+ }
+ } // class SlicedByteBufferTests
+}
diff --git a/dotnet/Qpid.Buffer.Tests/default.build b/dotnet/Qpid.Buffer.Tests/default.build
index 688633fc11..77e95fb9d9 100644
--- a/dotnet/Qpid.Buffer.Tests/default.build
+++ b/dotnet/Qpid.Buffer.Tests/default.build
@@ -1,27 +1,48 @@
-<?xml version="1.0"?>
-<project name="Apache.Qpid.Buffer" default="test">
-
- <target name="build">
- <csc target="library"
- define="${build.defines}"
- warnaserror="true" debug="${build.debug}"
- output="${build.dir}/${project::get-name()}.Tests.dll">
-
- <sources>
- <include name="**/*.cs" />
- </sources>
- <references>
- <include name="${build.dir}/nunit.framework.dll" />
- <include name="${build.dir}/${project::get-name()}.dll" />
- </references>
-
- </csc>
- </target>
- <target name="test" depends="build">
- <nunit2>
- <formatter type="${nant.formatter}" usefile="false" />
- <test assemblyname="${build.dir}/${project::get-name()}.Tests.dll" />
- </nunit2>
- </target>
-</project>
-
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="Apache.Qpid.Buffer" default="test">
+
+ <target name="build">
+ <csc target="library"
+ define="${build.defines}"
+ warnaserror="true" debug="${build.debug}"
+ output="${build.dir}/${project::get-name()}.Tests.dll">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ <include name="${build.dir}/nunit.framework.dll" />
+ <include name="${build.dir}/${project::get-name()}.dll" />
+ </references>
+
+ </csc>
+ </target>
+ <target name="test" depends="build">
+ <nunit2>
+ <formatter type="${nant.formatter}" usefile="false" />
+ <test assemblyname="${build.dir}/${project::get-name()}.Tests.dll" />
+ </nunit2>
+ </target>
+</project>
+
diff --git a/dotnet/Qpid.Buffer/IByteBufferAllocator.cs b/dotnet/Qpid.Buffer/IByteBufferAllocator.cs
index 0f457df065..74944f7e69 100644
--- a/dotnet/Qpid.Buffer/IByteBufferAllocator.cs
+++ b/dotnet/Qpid.Buffer/IByteBufferAllocator.cs
@@ -1,50 +1,50 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-
-namespace Apache.Qpid.Buffer
-{
- /// <summary>
- /// Allocates <see cref="ByteBuffer"/>'s and manages them. Please
- /// implement this interface if you need more advanced memory management scheme
- /// </summary>
- public interface IByteBufferAllocator : IDisposable
- {
- /// <summary>
- /// Returns the buffer which is capable of the specified size.
- /// </summary>
- /// <param name="capacity">The capacity of the buffer</param>
- /// <returns>A new buffer</returns>
- ByteBuffer Allocate(int capacity);
-
- /// <summary>
- /// Wrap the specified byte array in a new buffer
- /// </summary>
- /// <param name="src">Source array</param>
- /// <returns>A new buffer</returns>
- ByteBuffer Wrap(byte[] src);
-
- } // interface IByteBufferAllocator
-}
-
-
-
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+
+namespace Apache.Qpid.Buffer
+{
+ /// <summary>
+ /// Allocates <see cref="ByteBuffer"/>'s and manages them. Please
+ /// implement this interface if you need more advanced memory management scheme
+ /// </summary>
+ public interface IByteBufferAllocator : IDisposable
+ {
+ /// <summary>
+ /// Returns the buffer which is capable of the specified size.
+ /// </summary>
+ /// <param name="capacity">The capacity of the buffer</param>
+ /// <returns>A new buffer</returns>
+ ByteBuffer Allocate(int capacity);
+
+ /// <summary>
+ /// Wrap the specified byte array in a new buffer
+ /// </summary>
+ /// <param name="src">Source array</param>
+ /// <returns>A new buffer</returns>
+ ByteBuffer Wrap(byte[] src);
+
+ } // interface IByteBufferAllocator
+}
+
+
+
diff --git a/dotnet/Qpid.Buffer/Properties/AssemblyInfo.cs b/dotnet/Qpid.Buffer/Properties/AssemblyInfo.cs
index f8fa3f97b9..b692af7ce5 100644
--- a/dotnet/Qpid.Buffer/Properties/AssemblyInfo.cs
+++ b/dotnet/Qpid.Buffer/Properties/AssemblyInfo.cs
@@ -49,5 +49,5 @@ using System.Runtime.InteropServices;
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
-[assembly: AssemblyVersion("2.1.0.0")]
+[assembly: AssemblyVersion("0.5.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/Qpid.Buffer/Qpid.Buffer.csproj b/dotnet/Qpid.Buffer/Qpid.Buffer.csproj
index f1b5a907a1..d13f399196 100644
--- a/dotnet/Qpid.Buffer/Qpid.Buffer.csproj
+++ b/dotnet/Qpid.Buffer/Qpid.Buffer.csproj
@@ -1,4 +1,25 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@@ -12,6 +33,11 @@
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>
</AssemblyOriginatorKeyFile>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -38,15 +64,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
- <Compile Include="BufferOverflowException.cs" />
- <Compile Include="BufferUnderflowException.cs" />
- <Compile Include="ByteBuffer.cs" />
- <Compile Include="ByteBufferHexDumper.cs" />
- <Compile Include="IByteBufferAllocator.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="SimpleByteBuffer.cs" />
- <Compile Include="SimpleByteBufferAllocator.cs" />
- <Compile Include="SlicedByteBuffer.cs" />
+ <Compile Include="**\*.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
@@ -56,4 +74,4 @@
<Target Name="AfterBuild">
</Target>
-->
-</Project> \ No newline at end of file
+</Project>
diff --git a/dotnet/Qpid.Buffer/SimpleByteBuffer.cs b/dotnet/Qpid.Buffer/SimpleByteBuffer.cs
index d3b7245cb1..956c59aa45 100644
--- a/dotnet/Qpid.Buffer/SimpleByteBuffer.cs
+++ b/dotnet/Qpid.Buffer/SimpleByteBuffer.cs
@@ -1,120 +1,120 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-
-namespace Apache.Qpid.Buffer
-{
- internal sealed class SimpleByteBuffer : ByteBuffer
- {
- private byte[] _buffer;
-
- public override int Capacity
- {
- get { return _buffer.Length; }
- }
-
- public override byte[] Array
- {
- get { return _buffer; }
- }
-
- /// <summary>
- /// Initialize a new instance with the desired size
- /// </summary>
- /// <param name="desiredSize">Initial Length of the array</param>
- internal SimpleByteBuffer(int desiredSize)
- {
- _buffer = new byte[desiredSize];
- Position = 0;
- Limit = Capacity;
- }
-
- /// <summary>
- /// Initialize a new instance with the data from
- /// an underlying array
- /// </summary>
- /// <param name="buffer">Initial data</param>
- /// <remarks>The original array is copied during construction and is not modified</remarks>
- internal SimpleByteBuffer(byte[] buffer)
- {
- _buffer = (byte[])buffer.Clone();
- // position at end
- Position = Limit = Capacity;
- }
-
- protected override void DoWrite(int position, byte value)
- {
- // available space is already handled by base class
- _buffer[position] = value;
- }
-
- protected override void DoWrite(int position, byte[] src, int offset, int length)
- {
- // available space is already handled by base class
- for ( int i = 0; i < length; i++ )
- {
- _buffer[position+i] = src[offset+i];
- }
- }
-
- protected override byte DoReadByte(int position)
- {
- return _buffer[position];
- }
-
- protected override void DoReadBytes(int position, byte[] dest, int offset, int length)
- {
- System.Array.Copy(_buffer, position, dest, offset, length);
- }
-
- protected override void DoCompact()
- {
- if ( Remaining > 0 )
- {
- if ( Position > 0 )
- {
- System.Array.Copy(_buffer, Position, _buffer, 0, Remaining);
- }
- Position = Remaining;
- } else
- {
- Position = 0;
- }
- Limit = Capacity;
- }
-
- protected override void DoResize(int newSize)
- {
- if ( newSize < Capacity )
- throw new NotSupportedException("Cannot resize a buffer to make it smaller");
-
- int newCapacity = 1;
- while ( newCapacity < newSize )
- {
- newCapacity <<= 1;
- }
-
- byte[] newBuffer = new byte[newCapacity];
- System.Array.Copy(_buffer, newBuffer, _buffer.Length);
- _buffer = newBuffer;
- }
- } // class SimpleByteBuffer
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+
+namespace Apache.Qpid.Buffer
+{
+ internal sealed class SimpleByteBuffer : ByteBuffer
+ {
+ private byte[] _buffer;
+
+ public override int Capacity
+ {
+ get { return _buffer.Length; }
+ }
+
+ public override byte[] Array
+ {
+ get { return _buffer; }
+ }
+
+ /// <summary>
+ /// Initialize a new instance with the desired size
+ /// </summary>
+ /// <param name="desiredSize">Initial Length of the array</param>
+ internal SimpleByteBuffer(int desiredSize)
+ {
+ _buffer = new byte[desiredSize];
+ Position = 0;
+ Limit = Capacity;
+ }
+
+ /// <summary>
+ /// Initialize a new instance with the data from
+ /// an underlying array
+ /// </summary>
+ /// <param name="buffer">Initial data</param>
+ /// <remarks>The original array is copied during construction and is not modified</remarks>
+ internal SimpleByteBuffer(byte[] buffer)
+ {
+ _buffer = (byte[])buffer.Clone();
+ // position at end
+ Position = Limit = Capacity;
+ }
+
+ protected override void DoWrite(int position, byte value)
+ {
+ // available space is already handled by base class
+ _buffer[position] = value;
+ }
+
+ protected override void DoWrite(int position, byte[] src, int offset, int length)
+ {
+ // available space is already handled by base class
+ for ( int i = 0; i < length; i++ )
+ {
+ _buffer[position+i] = src[offset+i];
+ }
+ }
+
+ protected override byte DoReadByte(int position)
+ {
+ return _buffer[position];
+ }
+
+ protected override void DoReadBytes(int position, byte[] dest, int offset, int length)
+ {
+ System.Array.Copy(_buffer, position, dest, offset, length);
+ }
+
+ protected override void DoCompact()
+ {
+ if ( Remaining > 0 )
+ {
+ if ( Position > 0 )
+ {
+ System.Array.Copy(_buffer, Position, _buffer, 0, Remaining);
+ }
+ Position = Remaining;
+ } else
+ {
+ Position = 0;
+ }
+ Limit = Capacity;
+ }
+
+ protected override void DoResize(int newSize)
+ {
+ if ( newSize < Capacity )
+ throw new NotSupportedException("Cannot resize a buffer to make it smaller");
+
+ int newCapacity = 1;
+ while ( newCapacity < newSize )
+ {
+ newCapacity <<= 1;
+ }
+
+ byte[] newBuffer = new byte[newCapacity];
+ System.Array.Copy(_buffer, newBuffer, _buffer.Length);
+ _buffer = newBuffer;
+ }
+ } // class SimpleByteBuffer
+}
diff --git a/dotnet/Qpid.Buffer/SlicedByteBuffer.cs b/dotnet/Qpid.Buffer/SlicedByteBuffer.cs
index c27b7949b6..890e2a3c7a 100644
--- a/dotnet/Qpid.Buffer/SlicedByteBuffer.cs
+++ b/dotnet/Qpid.Buffer/SlicedByteBuffer.cs
@@ -1,86 +1,86 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-
-namespace Apache.Qpid.Buffer
-{
- internal sealed class SlicedByteBuffer : ByteBuffer
- {
- private ByteBuffer _buffer;
- private int _capacity;
- private int _startPos;
-
- public override int Capacity
- {
- get { return _capacity; }
- }
-
- public override byte[] Array
- {
- get { return _buffer.Array; }
- }
-
- /// <summary>
- /// Initialize a new instance
- /// </summary>
- /// <param name="buffer">Underlying byte buffer</param>
- internal SlicedByteBuffer(ByteBuffer buffer)
- {
- _buffer = buffer;
- _startPos = buffer.Position;
- Position = 0;
- _capacity = buffer.Remaining;
- Limit = Capacity;
- // cannot autoexpand
- IsAutoExpand = false;
- }
-
- protected override void DoWrite(int position, byte value)
- {
- _buffer.Put(_startPos + position, value);
- }
-
- protected override void DoWrite(int position, byte[] src, int offset, int length)
- {
- _buffer.Put(_startPos + position, src, offset, length);
- }
-
- protected override byte DoReadByte(int position)
- {
- return _buffer.GetByte(_startPos + position);
- }
-
- protected override void DoReadBytes(int position, byte[] dest, int offset, int length)
- {
- _buffer.GetBytes(_startPos + position, dest, offset, length);
- }
-
- protected override void DoCompact()
- {
- throw new NotSupportedException();
- }
-
- protected override void DoResize(int newSize)
- {
- throw new NotSupportedException();
- }
- } // class SlicedByteBuffer
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+
+namespace Apache.Qpid.Buffer
+{
+ internal sealed class SlicedByteBuffer : ByteBuffer
+ {
+ private ByteBuffer _buffer;
+ private int _capacity;
+ private int _startPos;
+
+ public override int Capacity
+ {
+ get { return _capacity; }
+ }
+
+ public override byte[] Array
+ {
+ get { return _buffer.Array; }
+ }
+
+ /// <summary>
+ /// Initialize a new instance
+ /// </summary>
+ /// <param name="buffer">Underlying byte buffer</param>
+ internal SlicedByteBuffer(ByteBuffer buffer)
+ {
+ _buffer = buffer;
+ _startPos = buffer.Position;
+ Position = 0;
+ _capacity = buffer.Remaining;
+ Limit = Capacity;
+ // cannot autoexpand
+ IsAutoExpand = false;
+ }
+
+ protected override void DoWrite(int position, byte value)
+ {
+ _buffer.Put(_startPos + position, value);
+ }
+
+ protected override void DoWrite(int position, byte[] src, int offset, int length)
+ {
+ _buffer.Put(_startPos + position, src, offset, length);
+ }
+
+ protected override byte DoReadByte(int position)
+ {
+ return _buffer.GetByte(_startPos + position);
+ }
+
+ protected override void DoReadBytes(int position, byte[] dest, int offset, int length)
+ {
+ _buffer.GetBytes(_startPos + position, dest, offset, length);
+ }
+
+ protected override void DoCompact()
+ {
+ throw new NotSupportedException();
+ }
+
+ protected override void DoResize(int newSize)
+ {
+ throw new NotSupportedException();
+ }
+ } // class SlicedByteBuffer
+}
diff --git a/dotnet/Qpid.Buffer/default.build b/dotnet/Qpid.Buffer/default.build
index c2d36d15e6..efb5a8fc89 100644
--- a/dotnet/Qpid.Buffer/default.build
+++ b/dotnet/Qpid.Buffer/default.build
@@ -1,25 +1,46 @@
-<?xml version="1.0"?>
-<project name="Apache.Qpid.Buffer" default="build">
- <!--
- Properties that come from master build file
- - build.dir: root directory for build
- - build.debug: true if building debug release
- - build.defines: variables to define during build
- -->
-
- <target name="build">
- <csc target="library"
- define="${build.defines}"
- debug="${build.debug}"
- unsafe="true"
- output="${build.dir}/${project::get-name()}.dll">
-
- <sources>
- <include name="**/*.cs" />
- </sources>
- <references>
- </references>
- </csc>
- </target>
-</project>
-
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="Apache.Qpid.Buffer" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="library"
+ define="${build.defines}"
+ debug="${build.debug}"
+ unsafe="true"
+ output="${build.dir}/${project::get-name()}.dll">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ </references>
+ </csc>
+ </target>
+</project>
+
diff --git a/dotnet/Qpid.Client.Tests/App.config b/dotnet/Qpid.Client.Tests/App.config
index fd7c412a57..e71a468a3a 100644
--- a/dotnet/Qpid.Client.Tests/App.config
+++ b/dotnet/Qpid.Client.Tests/App.config
@@ -1,13 +1,34 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<configuration>
- <configSections>
- <sectionGroup name="qpid.client">
- <section name="authentication" type="Apache.Qpid.Client.Configuration.AuthenticationConfigurationSectionHandler, Apache.Qpid.Client"/>
- </sectionGroup>
- </configSections>
- <qpid.client>
- <authentication>
- <add key="TEST" value="Apache.Qpid.Client.Tests.Security.TestCallbackHandler, Apache.Qpid.Client.Tests"/>
- </authentication>
- </qpid.client>
-</configuration>
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<configuration>
+ <configSections>
+ <sectionGroup name="qpid.client">
+ <section name="authentication" type="Apache.Qpid.Client.Configuration.AuthenticationConfigurationSectionHandler, Apache.Qpid.Client"/>
+ </sectionGroup>
+ </configSections>
+ <qpid.client>
+ <authentication>
+ <add key="TEST" value="Apache.Qpid.Client.Tests.Security.TestCallbackHandler, Apache.Qpid.Client.Tests"/>
+ </authentication>
+ </qpid.client>
+</configuration>
diff --git a/dotnet/Qpid.Client.Tests/BrokerDetails/BrokerDetailsTest.cs b/dotnet/Qpid.Client.Tests/BrokerDetails/BrokerDetailsTest.cs
index 8e8d8ced3b..56269c0f9d 100644
--- a/dotnet/Qpid.Client.Tests/BrokerDetails/BrokerDetailsTest.cs
+++ b/dotnet/Qpid.Client.Tests/BrokerDetails/BrokerDetailsTest.cs
@@ -1,65 +1,65 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Net;
-using NUnit.Framework;
-using Apache.Qpid.Client.Qms;
-
-namespace Apache.Qpid.Client.Tests.BrokerDetails
-{
- [TestFixture]
- public class BrokerDetailsTest
- {
-
- [Test]
- public void ValidateBrokerInfoEqualsMethod()
- {
- AmqBrokerInfo broker = new AmqBrokerInfo("amqp", "localhost", 5672, true);
- AmqBrokerInfo broker1 = new AmqBrokerInfo("Amqp", "localhost", 5672, true);
-
- Assert.IsTrue(broker.Equals(broker1),"The two AmqBrokerInfo objects are not equals");
- Console.WriteLine(string.Format("The object broker: {0} and broker1: {1} are equals", broker, broker1));
- }
-
- [Test]
- public void ValidateBrokerInfoWithDifferentSSL()
- {
- AmqBrokerInfo broker = new AmqBrokerInfo("amqp", "localhost", 5672, true);
- AmqBrokerInfo broker1 = new AmqBrokerInfo("amqp", "localhost", 5672, false);
-
- Assert.IsFalse(broker.Equals(broker1), "The two AmqBrokerInfo objects are equals");
- Console.WriteLine(string.Format("The object broker: {0} and broker1: {1} are not equals", broker, broker1));
- }
-
- [Test]
- public void ValidateBrokerInfoFromToString()
- {
- String url = "tcp://localhost:5672?timeout='200',immediatedelivery='true'";
-
- AmqBrokerInfo broker = new AmqBrokerInfo(url);
- AmqBrokerInfo broker1 = new AmqBrokerInfo(broker.ToString());
-
- Assert.AreEqual(broker.GetOption("timeout"), broker1.GetOption("timeout"));
- Assert.AreEqual(broker.GetOption("immediatedelivery"), broker1.GetOption("immediatedelivery"));
- }
-
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Net;
+using NUnit.Framework;
+using Apache.Qpid.Client.Qms;
+
+namespace Apache.Qpid.Client.Tests.BrokerDetails
+{
+ [TestFixture]
+ public class BrokerDetailsTest
+ {
+
+ [Test]
+ public void ValidateBrokerInfoEqualsMethod()
+ {
+ AmqBrokerInfo broker = new AmqBrokerInfo("amqp", "localhost", 5672, true);
+ AmqBrokerInfo broker1 = new AmqBrokerInfo("Amqp", "localhost", 5672, true);
+
+ Assert.IsTrue(broker.Equals(broker1),"The two AmqBrokerInfo objects are not equals");
+ Console.WriteLine(string.Format("The object broker: {0} and broker1: {1} are equals", broker, broker1));
+ }
+
+ [Test]
+ public void ValidateBrokerInfoWithDifferentSSL()
+ {
+ AmqBrokerInfo broker = new AmqBrokerInfo("amqp", "localhost", 5672, true);
+ AmqBrokerInfo broker1 = new AmqBrokerInfo("amqp", "localhost", 5672, false);
+
+ Assert.IsFalse(broker.Equals(broker1), "The two AmqBrokerInfo objects are equals");
+ Console.WriteLine(string.Format("The object broker: {0} and broker1: {1} are not equals", broker, broker1));
+ }
+
+ [Test]
+ public void ValidateBrokerInfoFromToString()
+ {
+ String url = "tcp://localhost:5672?timeout='200',immediatedelivery='true'";
+
+ AmqBrokerInfo broker = new AmqBrokerInfo(url);
+ AmqBrokerInfo broker1 = new AmqBrokerInfo(broker.ToString());
+
+ Assert.AreEqual(broker.GetOption("timeout"), broker1.GetOption("timeout"));
+ Assert.AreEqual(broker.GetOption("immediatedelivery"), broker1.GetOption("immediatedelivery"));
+ }
+
+ }
+}
diff --git a/dotnet/Qpid.Client.Tests/Channel/ChannelMessageCreationTests.cs b/dotnet/Qpid.Client.Tests/Channel/ChannelMessageCreationTests.cs
index c27aa9a503..f4f217c2a0 100644
--- a/dotnet/Qpid.Client.Tests/Channel/ChannelMessageCreationTests.cs
+++ b/dotnet/Qpid.Client.Tests/Channel/ChannelMessageCreationTests.cs
@@ -1,79 +1,79 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-
-using log4net;
-using NUnit.Framework;
-using Apache.Qpid.Client;
-using Apache.Qpid.Client.Message;
-using Apache.Qpid.Messaging;
-
-namespace Apache.Qpid.Client.Tests.Channel
-{
- /// <summary>
- /// Test that channels can create messages correctly
- /// </summary>
- [TestFixture]
- public class ChannelMessageCreationTests
- {
- [Test]
- public void CanCreateTextMessage()
- {
- IChannel channel = AmqChannel.CreateDisconnectedChannel();
- ITextMessage msg = channel.CreateTextMessage();
- Assert.IsNotNull(msg);
- }
- [Test]
- public void CanCreateTextMessageWithContent()
- {
- IChannel channel = AmqChannel.CreateDisconnectedChannel();
- const string CONTENT = "1234567890";
- ITextMessage msg = channel.CreateTextMessage(CONTENT);
- Assert.IsNotNull(msg);
- Assert.AreEqual(CONTENT, msg.Text);
- }
- [Test]
- public void CanCreateBytesMessage()
- {
- IChannel channel = AmqChannel.CreateDisconnectedChannel();
- IBytesMessage msg = channel.CreateBytesMessage();
- Assert.IsNotNull(msg);
- }
- [Test]
- public void CanCreateMessage()
- {
- IChannel channel = AmqChannel.CreateDisconnectedChannel();
- IMessage msg = channel.CreateMessage();
- Assert.IsNotNull(msg);
- }
- [Test]
- public void CanCreateMessageFromMimeType()
- {
- IChannel channel = AmqChannel.CreateDisconnectedChannel();
- IMessage msg = channel.CreateMessage("text/xml");
- Assert.IsNotNull(msg);
- Assert.IsInstanceOfType(typeof(ITextMessage), msg);
- }
- }
-} // namespace Apache.Qpid.Client.Tests.Channel
-
-
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+
+using log4net;
+using NUnit.Framework;
+using Apache.Qpid.Client;
+using Apache.Qpid.Client.Message;
+using Apache.Qpid.Messaging;
+
+namespace Apache.Qpid.Client.Tests.Channel
+{
+ /// <summary>
+ /// Test that channels can create messages correctly
+ /// </summary>
+ [TestFixture]
+ public class ChannelMessageCreationTests
+ {
+ [Test]
+ public void CanCreateTextMessage()
+ {
+ IChannel channel = AmqChannel.CreateDisconnectedChannel();
+ ITextMessage msg = channel.CreateTextMessage();
+ Assert.IsNotNull(msg);
+ }
+ [Test]
+ public void CanCreateTextMessageWithContent()
+ {
+ IChannel channel = AmqChannel.CreateDisconnectedChannel();
+ const string CONTENT = "1234567890";
+ ITextMessage msg = channel.CreateTextMessage(CONTENT);
+ Assert.IsNotNull(msg);
+ Assert.AreEqual(CONTENT, msg.Text);
+ }
+ [Test]
+ public void CanCreateBytesMessage()
+ {
+ IChannel channel = AmqChannel.CreateDisconnectedChannel();
+ IBytesMessage msg = channel.CreateBytesMessage();
+ Assert.IsNotNull(msg);
+ }
+ [Test]
+ public void CanCreateMessage()
+ {
+ IChannel channel = AmqChannel.CreateDisconnectedChannel();
+ IMessage msg = channel.CreateMessage();
+ Assert.IsNotNull(msg);
+ }
+ [Test]
+ public void CanCreateMessageFromMimeType()
+ {
+ IChannel channel = AmqChannel.CreateDisconnectedChannel();
+ IMessage msg = channel.CreateMessage("text/xml");
+ Assert.IsNotNull(msg);
+ Assert.IsInstanceOfType(typeof(ITextMessage), msg);
+ }
+ }
+} // namespace Apache.Qpid.Client.Tests.Channel
+
+
diff --git a/dotnet/Qpid.Client.Tests/Messages/MessageFactoryRegistryTests.cs b/dotnet/Qpid.Client.Tests/Messages/MessageFactoryRegistryTests.cs
index 1211196541..4db3c91cb5 100644
--- a/dotnet/Qpid.Client.Tests/Messages/MessageFactoryRegistryTests.cs
+++ b/dotnet/Qpid.Client.Tests/Messages/MessageFactoryRegistryTests.cs
@@ -1,114 +1,114 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-
-using log4net;
-using NUnit.Framework;
-using Apache.Qpid.Messaging;
-using Apache.Qpid.Client.Message;
-
-namespace Apache.Qpid.Client.Tests.Messages
-{
- /// <summary>
- /// Ensure a factory creates messages correctly
- /// </summary>
- [TestFixture]
- public class MessageFactoryRegistryTests
- {
- const string TEXT_PLAIN = "text/plain";
- const string TEXT_XML = "text/xml";
- const string OCTET_STREAM = "application/octet-stream";
-
- /// <summary>
- /// Check default registry can create text/plain messages
- /// </summary>
- [Test]
- public void CanCreateTextPlain()
- {
- MessageFactoryRegistry registry =
- MessageFactoryRegistry.NewDefaultRegistry();
-
- IMessage message = registry.CreateMessage(TEXT_PLAIN);
- Assert.IsNotNull(message);
- Assert.AreEqual(TEXT_PLAIN, message.ContentType);
- Assert.IsInstanceOfType(typeof(QpidTextMessage), message);
- }
- /// <summary>
- /// Check default registry can create text/xml messages
- /// </summary>
- [Test]
- public void CanCreateTextXml()
- {
- MessageFactoryRegistry registry =
- MessageFactoryRegistry.NewDefaultRegistry();
-
- IMessage message = registry.CreateMessage(TEXT_XML);
- Assert.IsNotNull(message);
- Assert.AreEqual(TEXT_XML, message.ContentType);
- Assert.IsInstanceOfType(typeof(QpidTextMessage), message);
- }
- /// <summary>
- /// Check default registry can create application/octet-stream messages
- /// </summary>
- [Test]
- public void CanCreateBinary()
- {
- MessageFactoryRegistry registry =
- MessageFactoryRegistry.NewDefaultRegistry();
-
- IMessage message = registry.CreateMessage(OCTET_STREAM);
- Assert.IsNotNull(message);
- Assert.AreEqual(OCTET_STREAM, message.ContentType);
- Assert.IsInstanceOfType(typeof(QpidBytesMessage), message);
- }
- /// <summary>
- /// Check default registry can create messages for unknown types
- /// </summary>
- [Test]
- public void CanCreateUnknownType()
- {
- MessageFactoryRegistry registry =
- MessageFactoryRegistry.NewDefaultRegistry();
-
- const string OTHER = "application/unknown";
- IMessage message = registry.CreateMessage(OTHER);
- Assert.IsNotNull(message);
- Assert.AreEqual(OTHER, message.ContentType);
- Assert.IsInstanceOfType(typeof(QpidBytesMessage), message);
- }
- /// <summary>
- /// Check that text messages default to UTF-8 encoding
- /// </summary>
- [Test]
- public void TextMessagesDefaultToUTF8Encoding()
- {
- MessageFactoryRegistry registry =
- MessageFactoryRegistry.NewDefaultRegistry();
-
- IMessage message = registry.CreateMessage(TEXT_PLAIN);
- Assert.AreEqual("utf-8", message.ContentEncoding.ToLower());
- }
-
- }
-} // namespace Apache.Qpid.Client.Tests.Messages
-
-
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+
+using log4net;
+using NUnit.Framework;
+using Apache.Qpid.Messaging;
+using Apache.Qpid.Client.Message;
+
+namespace Apache.Qpid.Client.Tests.Messages
+{
+ /// <summary>
+ /// Ensure a factory creates messages correctly
+ /// </summary>
+ [TestFixture]
+ public class MessageFactoryRegistryTests
+ {
+ const string TEXT_PLAIN = "text/plain";
+ const string TEXT_XML = "text/xml";
+ const string OCTET_STREAM = "application/octet-stream";
+
+ /// <summary>
+ /// Check default registry can create text/plain messages
+ /// </summary>
+ [Test]
+ public void CanCreateTextPlain()
+ {
+ MessageFactoryRegistry registry =
+ MessageFactoryRegistry.NewDefaultRegistry();
+
+ IMessage message = registry.CreateMessage(TEXT_PLAIN);
+ Assert.IsNotNull(message);
+ Assert.AreEqual(TEXT_PLAIN, message.ContentType);
+ Assert.IsInstanceOfType(typeof(QpidTextMessage), message);
+ }
+ /// <summary>
+ /// Check default registry can create text/xml messages
+ /// </summary>
+ [Test]
+ public void CanCreateTextXml()
+ {
+ MessageFactoryRegistry registry =
+ MessageFactoryRegistry.NewDefaultRegistry();
+
+ IMessage message = registry.CreateMessage(TEXT_XML);
+ Assert.IsNotNull(message);
+ Assert.AreEqual(TEXT_XML, message.ContentType);
+ Assert.IsInstanceOfType(typeof(QpidTextMessage), message);
+ }
+ /// <summary>
+ /// Check default registry can create application/octet-stream messages
+ /// </summary>
+ [Test]
+ public void CanCreateBinary()
+ {
+ MessageFactoryRegistry registry =
+ MessageFactoryRegistry.NewDefaultRegistry();
+
+ IMessage message = registry.CreateMessage(OCTET_STREAM);
+ Assert.IsNotNull(message);
+ Assert.AreEqual(OCTET_STREAM, message.ContentType);
+ Assert.IsInstanceOfType(typeof(QpidBytesMessage), message);
+ }
+ /// <summary>
+ /// Check default registry can create messages for unknown types
+ /// </summary>
+ [Test]
+ public void CanCreateUnknownType()
+ {
+ MessageFactoryRegistry registry =
+ MessageFactoryRegistry.NewDefaultRegistry();
+
+ const string OTHER = "application/unknown";
+ IMessage message = registry.CreateMessage(OTHER);
+ Assert.IsNotNull(message);
+ Assert.AreEqual(OTHER, message.ContentType);
+ Assert.IsInstanceOfType(typeof(QpidBytesMessage), message);
+ }
+ /// <summary>
+ /// Check that text messages default to UTF-8 encoding
+ /// </summary>
+ [Test]
+ public void TextMessagesDefaultToUTF8Encoding()
+ {
+ MessageFactoryRegistry registry =
+ MessageFactoryRegistry.NewDefaultRegistry();
+
+ IMessage message = registry.CreateMessage(TEXT_PLAIN);
+ Assert.AreEqual("utf-8", message.ContentEncoding.ToLower());
+ }
+
+ }
+} // namespace Apache.Qpid.Client.Tests.Messages
+
+
diff --git a/dotnet/Qpid.Client.Tests/Properties/AssemblyInfo.cs b/dotnet/Qpid.Client.Tests/Properties/AssemblyInfo.cs
index 6359567f04..c710818053 100644
--- a/dotnet/Qpid.Client.Tests/Properties/AssemblyInfo.cs
+++ b/dotnet/Qpid.Client.Tests/Properties/AssemblyInfo.cs
@@ -50,4 +50,4 @@ using log4net.Config;
// Build Number
// Revision
//
-[assembly: AssemblyVersion("2.1.0.0")]
+[assembly: AssemblyVersion("0.5.0.0")]
diff --git a/dotnet/Qpid.Client.Tests/Qpid.Client.Tests.csproj b/dotnet/Qpid.Client.Tests/Qpid.Client.Tests.csproj
index ad54129523..73eabfa1f8 100644
--- a/dotnet/Qpid.Client.Tests/Qpid.Client.Tests.csproj
+++ b/dotnet/Qpid.Client.Tests/Qpid.Client.Tests.csproj
@@ -1,8 +1,29 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProductVersion>8.0.50727</ProductVersion>
+ <ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{BA1B0032-4CE6-40DD-A2DC-119F0FFA0A1D}</ProjectGuid>
<OutputType>Library</OutputType>
@@ -11,6 +32,26 @@
<AssemblyName>Apache.Qpid.Client.Tests</AssemblyName>
<StartupObject>
</StartupObject>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ <PublishUrl>http://localhost/Apache.Qpid.Client.Tests/</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Web</InstallFrom>
+ <UpdateEnabled>true</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <IsWebBootstrapper>true</IsWebBootstrapper>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -44,20 +85,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
- <Compile Include="BrokerDetails\BrokerDetailsTest.cs" />
- <Compile Include="Channel\ChannelMessageCreationTests.cs" />
- <Compile Include="Channel\ChannelQueueTest.cs" />
- <Compile Include="interop\InteropClientTestCase.cs" />
- <Compile Include="interop\TestCases\TestCase1DummyRun.cs" />
- <Compile Include="interop\TestCases\TestCase2BasicP2P.cs" />
- <Compile Include="interop\TestCases\TestCase3BasicPubSub.cs" />
- <Compile Include="interop\TestClient.cs" />
- <Compile Include="Messages\MessageFactoryRegistryTests.cs" />
- <Compile Include="interop\TopicListener.cs" />
- <Compile Include="interop\TopicPublisher.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="Security\CallbackHandlerRegistryTests.cs" />
- <Compile Include="url\ConnectionUrlTest.cs" />
+ <Compile Include="**\*.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Qpid.Buffer\Qpid.Buffer.csproj">
@@ -89,6 +117,36 @@
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework Client Profile</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 2.0 %28x86%29</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.0 %28x86%29</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <ItemGroup>
+ <Folder Include="interop\TestCases\" />
+ </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
@@ -97,4 +155,4 @@
<Target Name="AfterBuild">
</Target>
-->
-</Project> \ No newline at end of file
+</Project>
diff --git a/dotnet/Qpid.Client.Tests/Security/CallbackHandlerRegistryTests.cs b/dotnet/Qpid.Client.Tests/Security/CallbackHandlerRegistryTests.cs
index 1345511cbf..f1446a9aa6 100644
--- a/dotnet/Qpid.Client.Tests/Security/CallbackHandlerRegistryTests.cs
+++ b/dotnet/Qpid.Client.Tests/Security/CallbackHandlerRegistryTests.cs
@@ -1,66 +1,66 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using NUnit.Framework;
-using Apache.Qpid.Client.Security;
-
-
-namespace Apache.Qpid.Client.Tests.Security
-{
- [TestFixture]
- public class CallbackRegistryHandlerTests
- {
- [Test]
- public void ParsesConfiguration()
- {
- CallbackHandlerRegistry registry = CallbackHandlerRegistry.Instance;
- Assert.AreEqual(4, registry.Mechanisms.Length);
- Assert.Contains("TEST", registry.Mechanisms);
-
- Type handlerType = registry.GetCallbackHandler("TEST");
- Assert.IsNotNull(handlerType);
- Assert.AreEqual(typeof(TestCallbackHandler), handlerType);
- }
-
- [Test]
- public void MechanimsInOrder()
- {
- CallbackHandlerRegistry registry = CallbackHandlerRegistry.Instance;
- Assert.AreEqual(4, registry.Mechanisms.Length);
- Assert.AreEqual("TEST", registry.Mechanisms[0]);
- Assert.AreEqual("EXTERNAL", registry.Mechanisms[1]);
- Assert.AreEqual("CRAM-MD5", registry.Mechanisms[2]);
- Assert.AreEqual("PLAIN", registry.Mechanisms[3]);
- }
- } // class CallbackRegistryHandlerTests
-
- public class TestCallbackHandler : IAMQCallbackHandler
- {
- public void Initialize(Qpid.Client.Protocol.AMQProtocolSession session)
- {
- }
- public void Handle(Qpid.Sasl.ISaslCallback[] callbacks)
- {
- }
-
- } // class TestCallbackHandler
-
-} // namespace Apache.Qpid.Client.Tests.Connection
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using NUnit.Framework;
+using Apache.Qpid.Client.Security;
+
+
+namespace Apache.Qpid.Client.Tests.Security
+{
+ [TestFixture]
+ public class CallbackRegistryHandlerTests
+ {
+ [Test]
+ public void ParsesConfiguration()
+ {
+ CallbackHandlerRegistry registry = CallbackHandlerRegistry.Instance;
+ Assert.AreEqual(4, registry.Mechanisms.Length);
+ Assert.Contains("TEST", registry.Mechanisms);
+
+ Type handlerType = registry.GetCallbackHandler("TEST");
+ Assert.IsNotNull(handlerType);
+ Assert.AreEqual(typeof(TestCallbackHandler), handlerType);
+ }
+
+ [Test]
+ public void MechanimsInOrder()
+ {
+ CallbackHandlerRegistry registry = CallbackHandlerRegistry.Instance;
+ Assert.AreEqual(4, registry.Mechanisms.Length);
+ Assert.AreEqual("TEST", registry.Mechanisms[0]);
+ Assert.AreEqual("EXTERNAL", registry.Mechanisms[1]);
+ Assert.AreEqual("CRAM-MD5", registry.Mechanisms[2]);
+ Assert.AreEqual("PLAIN", registry.Mechanisms[3]);
+ }
+ } // class CallbackRegistryHandlerTests
+
+ public class TestCallbackHandler : IAMQCallbackHandler
+ {
+ public void Initialize(Qpid.Client.Protocol.AMQProtocolSession session)
+ {
+ }
+ public void Handle(Qpid.Sasl.ISaslCallback[] callbacks)
+ {
+ }
+
+ } // class TestCallbackHandler
+
+} // namespace Apache.Qpid.Client.Tests.Connection
diff --git a/dotnet/Qpid.Client.Tests/default.build b/dotnet/Qpid.Client.Tests/default.build
index 8dfc8a6f48..5116e651e1 100644
--- a/dotnet/Qpid.Client.Tests/default.build
+++ b/dotnet/Qpid.Client.Tests/default.build
@@ -1,4 +1,25 @@
<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
<project name="Apache.Qpid.Client" default="test">
<target name="build">
diff --git a/dotnet/Qpid.Client.Tests/interop/TopicListener.cs b/dotnet/Qpid.Client.Tests/interop/TopicListener.cs
index 13141d52b8..b355abb28d 100644
--- a/dotnet/Qpid.Client.Tests/interop/TopicListener.cs
+++ b/dotnet/Qpid.Client.Tests/interop/TopicListener.cs
@@ -1,211 +1,211 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using log4net;
-using Apache.Qpid.Messaging;
-using Apache.Qpid.Client.Qms;
-
-namespace Apache.Qpid.Client.Tests.interop
-{
- public class TopicListener
- {
- private static ILog log = LogManager.GetLogger(typeof(TopicListener));
-
- /// <summary> The default AMQ connection URL to use for tests. </summary>
- const string DEFAULT_URI = "amqp://guest:guest@default/test?brokerlist='tcp://localhost:5672'";
-
- /// <summary> Holds the routing key for the topic to receive test messages on. </summary>
- public static string CONTROL_ROUTING_KEY = "topic_control";
-
- /// <summary> Holds the routing key for the queue to send reports to. </summary>
- public static string RESPONSE_ROUTING_KEY = "response";
-
- /// <summary> Holds the connection to listen on. </summary>
- private IConnection connection;
-
- /// <summary> Holds the channel for all test messages.</summary>
- private IChannel channel;
-
- /// <summary> Holds the producer to send report messages on. </summary>
- private IMessagePublisher publisher;
-
- /// <summary> Holds a flag to indicate that a timer has begun on the first message. Reset when report is sent. </summary> */
- private bool init;
-
- /// <summary> Holds the count of messages received by this listener. </summary> */
- private int count;
-
- /// <summary> Creates a topic listener using the specified broker URL. </summary>
- ///
- /// <param name="connectionUri">The broker URL to listen on.</param>
- TopicListener(string connectionUri)
- {
- log.Debug("TopicListener(string connectionUri = " + connectionUri + "): called");
-
- // Create a connection to the broker.
- IConnectionInfo connectionInfo = QpidConnectionInfo.FromUrl(connectionUri);
- connection = new AMQConnection(connectionInfo);
-
- // Establish a session on the broker.
- channel = connection.CreateChannel(false, AcknowledgeMode.AutoAcknowledge, 1);
-
- // Set up a queue to listen for test messages on.
- string topicQueueName = channel.GenerateUniqueName();
- channel.DeclareQueue(topicQueueName, false, true, true);
-
- // Set this listener up to listen for incoming messages on the test topic queue.
- channel.Bind(topicQueueName, ExchangeNameDefaults.TOPIC, CONTROL_ROUTING_KEY);
- IMessageConsumer consumer = channel.CreateConsumerBuilder(topicQueueName)
- .Create();
- consumer.OnMessage += new MessageReceivedDelegate(OnMessage);
-
- // Set up this listener with a producer to send the reports on.
- publisher = channel.CreatePublisherBuilder()
- .WithExchangeName(ExchangeNameDefaults.DIRECT)
- .WithRoutingKey(RESPONSE_ROUTING_KEY)
- .Create();
-
- connection.Start();
- Console.WriteLine("Waiting for messages...");
- }
-
- public static void Main(String[] argv)
- {
- // Create an instance of this listener with the command line parameters.
- new TopicListener(DEFAULT_URI);
- }
-
- /// <summary>
- /// Handles all message received by this listener. Test messages are counted, report messages result in a report being sent and
- /// shutdown messages result in this listener being terminated.
- /// </summary>
- ///
- /// <param name="message">The received message.</param>
- public void OnMessage(IMessage message)
- {
- log.Debug("public void onMessage(Message message = " + message + "): called");
-
- // Take the start time of the first message if this is the first message.
- if (!init)
- {
- count = 0;
- init = true;
- }
-
- // Check if the message is a control message telling this listener to shut down.
- if (IsShutdown(message))
- {
- log.Debug("Got a shutdown message.");
- Shutdown();
- }
- // Check if the message is a report request message asking this listener to respond with the message count.
- else if (IsReport(message))
- {
- log.Debug("Got a report request message.");
-
- // Send the message count report.
- SendReport();
-
- // Reset the initialization flag so that the next message is considered to be the first.
- init = false;
- }
- // Otherwise it is an ordinary test message, so increment the message count.
- else
- {
- count++;
- }
- }
-
- /// <summary> Checks a message to see if it is a shutdown control message. </summary>
- ///
- /// <param name="m">The message to check.</param>
- ///
- /// <returns><tt>true</tt> if it is a shutdown control message, <tt>false</tt> otherwise.</returns>
- private bool IsShutdown(IMessage m)
- {
- bool result = CheckTextField(m, "TYPE", "TERMINATION_REQUEST");
-
- //log.Debug("isShutdown = " + result);
-
- return result;
- }
-
- /// <summary> Checks a message to see if it is a report request control message. </summary>
- ///
- /// <param name="m">The message to check.</param>
- ///
- /// <returns><tt>true</tt> if it is a report request control message, <tt>false</tt> otherwise.</returns>
- private bool IsReport(IMessage m)
- {
- bool result = CheckTextField(m, "TYPE", "REPORT_REQUEST");
-
- //log.Debug("isReport = " + result);
-
- return result;
- }
-
- /// <summary> Checks whether or not a text field on a message has the specified value. </summary>
- ///
- /// <param name="e">The message to check.</param>
- /// <param name="e">The name of the field to check.</param>
- /// <param name="e">The expected value of the field to compare with.</param>
- ///
- /// <returns> <tt>true</tt>If the specified field has the specified value, <tt>fals</tt> otherwise. </returns>
- private static bool CheckTextField(IMessage m, string fieldName, string value)
- {
- /*log.Debug("private static boolean checkTextField(Message m = " + m + ", String fieldName = " + fieldName
- + ", String value = " + value + "): called");*/
-
- string comp = m.Headers.GetString(fieldName);
-
- return (comp != null) && comp == value;
- }
-
- /// <summary> Stops the message consumer and closes the connection. </summary>
- private void Shutdown()
- {
- connection.Stop();
- channel.Dispose();
- connection.Dispose();
- }
-
- /// <summary> Sends the report message to the response location. </summary>
- private void SendReport()
- {
- string report = "Received " + count + ".";
-
- IMessage reportMessage = channel.CreateTextMessage(report);
-
- reportMessage.Headers.SetBoolean("BOOLEAN", false);
- //reportMessage.Headers.SetByte("BYTE", 5);
- reportMessage.Headers.SetDouble("DOUBLE", 3.141);
- reportMessage.Headers.SetFloat("FLOAT", 1.0f);
- reportMessage.Headers.SetInt("INT", 1);
- reportMessage.Headers.SetLong("LONG", 1);
- reportMessage.Headers.SetString("STRING", "hello");
- reportMessage.Headers.SetShort("SHORT", 2);
-
- publisher.Send(reportMessage);
-
- Console.WriteLine("Sent report: " + report);
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using log4net;
+using Apache.Qpid.Messaging;
+using Apache.Qpid.Client.Qms;
+
+namespace Apache.Qpid.Client.Tests.interop
+{
+ public class TopicListener
+ {
+ private static ILog log = LogManager.GetLogger(typeof(TopicListener));
+
+ /// <summary> The default AMQ connection URL to use for tests. </summary>
+ const string DEFAULT_URI = "amqp://guest:guest@default/test?brokerlist='tcp://localhost:5672'";
+
+ /// <summary> Holds the routing key for the topic to receive test messages on. </summary>
+ public static string CONTROL_ROUTING_KEY = "topic_control";
+
+ /// <summary> Holds the routing key for the queue to send reports to. </summary>
+ public static string RESPONSE_ROUTING_KEY = "response";
+
+ /// <summary> Holds the connection to listen on. </summary>
+ private IConnection connection;
+
+ /// <summary> Holds the channel for all test messages.</summary>
+ private IChannel channel;
+
+ /// <summary> Holds the producer to send report messages on. </summary>
+ private IMessagePublisher publisher;
+
+ /// <summary> Holds a flag to indicate that a timer has begun on the first message. Reset when report is sent. </summary> */
+ private bool init;
+
+ /// <summary> Holds the count of messages received by this listener. </summary> */
+ private int count;
+
+ /// <summary> Creates a topic listener using the specified broker URL. </summary>
+ ///
+ /// <param name="connectionUri">The broker URL to listen on.</param>
+ TopicListener(string connectionUri)
+ {
+ log.Debug("TopicListener(string connectionUri = " + connectionUri + "): called");
+
+ // Create a connection to the broker.
+ IConnectionInfo connectionInfo = QpidConnectionInfo.FromUrl(connectionUri);
+ connection = new AMQConnection(connectionInfo);
+
+ // Establish a session on the broker.
+ channel = connection.CreateChannel(false, AcknowledgeMode.AutoAcknowledge, 1);
+
+ // Set up a queue to listen for test messages on.
+ string topicQueueName = channel.GenerateUniqueName();
+ channel.DeclareQueue(topicQueueName, false, true, true);
+
+ // Set this listener up to listen for incoming messages on the test topic queue.
+ channel.Bind(topicQueueName, ExchangeNameDefaults.TOPIC, CONTROL_ROUTING_KEY);
+ IMessageConsumer consumer = channel.CreateConsumerBuilder(topicQueueName)
+ .Create();
+ consumer.OnMessage += new MessageReceivedDelegate(OnMessage);
+
+ // Set up this listener with a producer to send the reports on.
+ publisher = channel.CreatePublisherBuilder()
+ .WithExchangeName(ExchangeNameDefaults.DIRECT)
+ .WithRoutingKey(RESPONSE_ROUTING_KEY)
+ .Create();
+
+ connection.Start();
+ Console.WriteLine("Waiting for messages...");
+ }
+
+ public static void Main(String[] argv)
+ {
+ // Create an instance of this listener with the command line parameters.
+ new TopicListener(DEFAULT_URI);
+ }
+
+ /// <summary>
+ /// Handles all message received by this listener. Test messages are counted, report messages result in a report being sent and
+ /// shutdown messages result in this listener being terminated.
+ /// </summary>
+ ///
+ /// <param name="message">The received message.</param>
+ public void OnMessage(IMessage message)
+ {
+ log.Debug("public void onMessage(Message message = " + message + "): called");
+
+ // Take the start time of the first message if this is the first message.
+ if (!init)
+ {
+ count = 0;
+ init = true;
+ }
+
+ // Check if the message is a control message telling this listener to shut down.
+ if (IsShutdown(message))
+ {
+ log.Debug("Got a shutdown message.");
+ Shutdown();
+ }
+ // Check if the message is a report request message asking this listener to respond with the message count.
+ else if (IsReport(message))
+ {
+ log.Debug("Got a report request message.");
+
+ // Send the message count report.
+ SendReport();
+
+ // Reset the initialization flag so that the next message is considered to be the first.
+ init = false;
+ }
+ // Otherwise it is an ordinary test message, so increment the message count.
+ else
+ {
+ count++;
+ }
+ }
+
+ /// <summary> Checks a message to see if it is a shutdown control message. </summary>
+ ///
+ /// <param name="m">The message to check.</param>
+ ///
+ /// <returns><tt>true</tt> if it is a shutdown control message, <tt>false</tt> otherwise.</returns>
+ private bool IsShutdown(IMessage m)
+ {
+ bool result = CheckTextField(m, "TYPE", "TERMINATION_REQUEST");
+
+ //log.Debug("isShutdown = " + result);
+
+ return result;
+ }
+
+ /// <summary> Checks a message to see if it is a report request control message. </summary>
+ ///
+ /// <param name="m">The message to check.</param>
+ ///
+ /// <returns><tt>true</tt> if it is a report request control message, <tt>false</tt> otherwise.</returns>
+ private bool IsReport(IMessage m)
+ {
+ bool result = CheckTextField(m, "TYPE", "REPORT_REQUEST");
+
+ //log.Debug("isReport = " + result);
+
+ return result;
+ }
+
+ /// <summary> Checks whether or not a text field on a message has the specified value. </summary>
+ ///
+ /// <param name="e">The message to check.</param>
+ /// <param name="e">The name of the field to check.</param>
+ /// <param name="e">The expected value of the field to compare with.</param>
+ ///
+ /// <returns> <tt>true</tt>If the specified field has the specified value, <tt>fals</tt> otherwise. </returns>
+ private static bool CheckTextField(IMessage m, string fieldName, string value)
+ {
+ /*log.Debug("private static boolean checkTextField(Message m = " + m + ", String fieldName = " + fieldName
+ + ", String value = " + value + "): called");*/
+
+ string comp = m.Headers.GetString(fieldName);
+
+ return (comp != null) && comp == value;
+ }
+
+ /// <summary> Stops the message consumer and closes the connection. </summary>
+ private void Shutdown()
+ {
+ connection.Stop();
+ channel.Dispose();
+ connection.Dispose();
+ }
+
+ /// <summary> Sends the report message to the response location. </summary>
+ private void SendReport()
+ {
+ string report = "Received " + count + ".";
+
+ IMessage reportMessage = channel.CreateTextMessage(report);
+
+ reportMessage.Headers.SetBoolean("BOOLEAN", false);
+ //reportMessage.Headers.SetByte("BYTE", 5);
+ reportMessage.Headers.SetDouble("DOUBLE", 3.141);
+ reportMessage.Headers.SetFloat("FLOAT", 1.0f);
+ reportMessage.Headers.SetInt("INT", 1);
+ reportMessage.Headers.SetLong("LONG", 1);
+ reportMessage.Headers.SetString("STRING", "hello");
+ reportMessage.Headers.SetShort("SHORT", 2);
+
+ publisher.Send(reportMessage);
+
+ Console.WriteLine("Sent report: " + report);
+ }
+ }
+}
diff --git a/dotnet/Qpid.Client.Tests/interop/TopicPublisher.cs b/dotnet/Qpid.Client.Tests/interop/TopicPublisher.cs
index ef5d39f0bc..4fd0419e9c 100644
--- a/dotnet/Qpid.Client.Tests/interop/TopicPublisher.cs
+++ b/dotnet/Qpid.Client.Tests/interop/TopicPublisher.cs
@@ -1,188 +1,208 @@
-using System;
-using System.Threading;
-using log4net;
-using Apache.Qpid.Messaging;
-using Apache.Qpid.Client.Qms;
-
-namespace Apache.Qpid.Client.Tests.interop
-{
- public class TopicPublisher
- {
- private static ILog log = LogManager.GetLogger(typeof(TopicPublisher));
-
- /// <summary> The default AMQ connection URL to use for tests. </summary>
- const string DEFAULT_URI = "amqp://guest:guest@default/test?brokerlist='tcp://localhost:5672'";
-
- /// <summary> Holds the default test timeout for broker communications before tests give up. </summary>
- const int TIMEOUT = 10000;
-
- /// <summary> Holds the routing key for the topic to receive test messages on. </summary>
- const string CONTROL_ROUTING_KEY = "topic_control";
-
- /// <summary> Holds the routing key for the queue to send reports to. </summary>
- const string RESPONSE_ROUTING_KEY = "response";
-
- /// <summary> Holds the number of messages to send in each test run. </summary>
- private int numMessages;
-
- /// <summary> Holds the number of subscribers listening to the messsages. </summary>
- private int numSubscribers;
-
- /// <summary> A monitor used to wait for all reports to arrive back from consumers on. </summary>
- private AutoResetEvent allReportsReceivedEvt = new AutoResetEvent(false);
-
- /// <summary> Holds the connection to listen on. </summary>
- private IConnection connection;
-
- /// <summary> Holds the channel for all test messages.</summary>
- private IChannel channel;
-
- /// <summary> Holds the producer to send test messages on. </summary>
- private IMessagePublisher publisher;
-
- /// <summary>
- /// Creates a topic publisher that will send the specifed number of messages and expect the specifed number of report back from test
- /// subscribers.
- /// </summary>
- ///
- /// <param name="connectionUri">The broker URL.</param>
- /// <param name="numMessages">The number of messages to send in each test.</param>
- /// <param name="numSubscribers">The number of subscribes that are expected to reply with a report.</param>
- TopicPublisher(string connectionUri, int numMessages, int numSubscribers)
- {
- log.Debug("TopicPublisher(string connectionUri = " + connectionUri + ", int numMessages = "+ numMessages +
- ", int numSubscribers = " + numSubscribers + "): called");
-
- // Create a connection to the broker.
- IConnectionInfo connectionInfo = QpidConnectionInfo.FromUrl(connectionUri);
- connection = new AMQConnection(connectionInfo);
-
- // Establish a session on the broker.
- channel = connection.CreateChannel(false, AcknowledgeMode.AutoAcknowledge, 1);
-
- // Set up a queue to listen for reports on.
- string responseQueueName = channel.GenerateUniqueName();
- channel.DeclareQueue(responseQueueName, false, true, true);
-
- // Set this listener up to listen for reports on the response queue.
- channel.Bind(responseQueueName, ExchangeNameDefaults.DIRECT, RESPONSE_ROUTING_KEY);
- //channel.Bind(responseQueueName, "<<default>>", RESPONSE_ROUTING_KEY);
- IMessageConsumer consumer = channel.CreateConsumerBuilder(responseQueueName)
- .Create();
- consumer.OnMessage += new MessageReceivedDelegate(OnMessage);
-
- // Set up this listener with a producer to send the test messages and report requests on.
- publisher = channel.CreatePublisherBuilder()
- .WithExchangeName(ExchangeNameDefaults.TOPIC)
- .WithRoutingKey(CONTROL_ROUTING_KEY)
- .Create();
-
- // Keep the test parameters.
- this.numMessages = numMessages;
- this.numSubscribers = numSubscribers;
-
- connection.Start();
- Console.WriteLine("Sending messages and waiting for reports...");
- }
-
- /// <summary>
- /// Start a test subscriber. The broker URL must be specified as the first command line argument.
- /// </summary>
- ///
- /// <param name="argv">The command line arguments, broker URL first.</param>
- public static void Main(String[] argv)
- {
- // Create an instance of this publisher with the command line parameters.
- TopicPublisher publisher = new TopicPublisher(DEFAULT_URI, 1, 1);
-
- // Publish the test messages.
- publisher.DoTest();
- }
-
- /// <summary>
- /// Sends the test messages and waits for all subscribers to reply with a report.
- /// </summary>
- public void DoTest()
- {
- log.Debug("public void DoTest(): called");
-
- // Create a test message to send.
- IMessage testMessage = channel.CreateTextMessage("test");
-
- // Send the desired number of test messages.
- for (int i = 0; i < numMessages; i++)
- {
- publisher.Send(testMessage);
- }
-
- log.Debug("Sent " + numMessages + " test messages.");
-
- // Send the report request.
- IMessage reportRequestMessage = channel.CreateTextMessage("Report request message.");
- reportRequestMessage.Headers["TYPE"] = "REPORT_REQUEST";
-
- reportRequestMessage.Headers.SetBoolean("BOOLEAN", false);
- //reportRequestMessage.Headers.SetByte("BYTE", 5);
- reportRequestMessage.Headers.SetDouble("DOUBLE", 3.141);
- reportRequestMessage.Headers.SetFloat("FLOAT", 1.0f);
- reportRequestMessage.Headers.SetInt("INT", 1);
- reportRequestMessage.Headers.SetLong("LONG", 1);
- reportRequestMessage.Headers.SetString("STRING", "hello");
- reportRequestMessage.Headers.SetShort("SHORT", 2);
-
- publisher.Send(reportRequestMessage);
-
- log.Debug("Sent the report request message, waiting for all replies...");
-
- // Wait until all the reports come in.
- allReportsReceivedEvt.WaitOne(TIMEOUT, true);
-
- // Check if all reports were really received or if the timeout occurred.
- if (numSubscribers == 0)
- {
- log.Debug("Got all reports.");
- }
- else
- {
- log.Debug("Waiting for reports timed out, still waiting for " + numSubscribers + ".");
- }
-
- // Send the termination request.
- IMessage terminationRequestMessage = channel.CreateTextMessage("Termination request message.");
- terminationRequestMessage.Headers["TYPE"] = "TERMINATION_REQUEST";
- publisher.Send(terminationRequestMessage);
-
- log.Debug("Sent the termination request message.");
-
- // Close all message producers and consumers and the connection to the broker.
- Shutdown();
- }
-
- /// <summary>
- /// Handles all report messages from subscribers. This decrements the count of subscribers that are still to reply, until this becomes
- /// zero, at which time waiting threads are notified of this event.
- /// </summary>
- ///
- /// <param name="message">The received report message.</param>
- public void OnMessage(IMessage message)
- {
- log.Debug("public void OnMessage(IMessage message = " + message + "): called");
-
- // Decrement the count of expected messages and release the wait monitor when this becomes zero.
- if (--numSubscribers == 0)
- {
- log.Debug("Got reports from all subscribers.");
- allReportsReceivedEvt.Set();
- }
- }
-
- /// <summary> Stops the message consumers and closes the connection. </summary>
- private void Shutdown()
- {
- connection.Stop();
- publisher.Dispose();
- channel.Dispose();
- connection.Dispose();
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Threading;
+using log4net;
+using Apache.Qpid.Messaging;
+using Apache.Qpid.Client.Qms;
+
+namespace Apache.Qpid.Client.Tests.interop
+{
+ public class TopicPublisher
+ {
+ private static ILog log = LogManager.GetLogger(typeof(TopicPublisher));
+
+ /// <summary> The default AMQ connection URL to use for tests. </summary>
+ const string DEFAULT_URI = "amqp://guest:guest@default/test?brokerlist='tcp://localhost:5672'";
+
+ /// <summary> Holds the default test timeout for broker communications before tests give up. </summary>
+ const int TIMEOUT = 10000;
+
+ /// <summary> Holds the routing key for the topic to receive test messages on. </summary>
+ const string CONTROL_ROUTING_KEY = "topic_control";
+
+ /// <summary> Holds the routing key for the queue to send reports to. </summary>
+ const string RESPONSE_ROUTING_KEY = "response";
+
+ /// <summary> Holds the number of messages to send in each test run. </summary>
+ private int numMessages;
+
+ /// <summary> Holds the number of subscribers listening to the messsages. </summary>
+ private int numSubscribers;
+
+ /// <summary> A monitor used to wait for all reports to arrive back from consumers on. </summary>
+ private AutoResetEvent allReportsReceivedEvt = new AutoResetEvent(false);
+
+ /// <summary> Holds the connection to listen on. </summary>
+ private IConnection connection;
+
+ /// <summary> Holds the channel for all test messages.</summary>
+ private IChannel channel;
+
+ /// <summary> Holds the producer to send test messages on. </summary>
+ private IMessagePublisher publisher;
+
+ /// <summary>
+ /// Creates a topic publisher that will send the specifed number of messages and expect the specifed number of report back from test
+ /// subscribers.
+ /// </summary>
+ ///
+ /// <param name="connectionUri">The broker URL.</param>
+ /// <param name="numMessages">The number of messages to send in each test.</param>
+ /// <param name="numSubscribers">The number of subscribes that are expected to reply with a report.</param>
+ TopicPublisher(string connectionUri, int numMessages, int numSubscribers)
+ {
+ log.Debug("TopicPublisher(string connectionUri = " + connectionUri + ", int numMessages = "+ numMessages +
+ ", int numSubscribers = " + numSubscribers + "): called");
+
+ // Create a connection to the broker.
+ IConnectionInfo connectionInfo = QpidConnectionInfo.FromUrl(connectionUri);
+ connection = new AMQConnection(connectionInfo);
+
+ // Establish a session on the broker.
+ channel = connection.CreateChannel(false, AcknowledgeMode.AutoAcknowledge, 1);
+
+ // Set up a queue to listen for reports on.
+ string responseQueueName = channel.GenerateUniqueName();
+ channel.DeclareQueue(responseQueueName, false, true, true);
+
+ // Set this listener up to listen for reports on the response queue.
+ channel.Bind(responseQueueName, ExchangeNameDefaults.DIRECT, RESPONSE_ROUTING_KEY);
+ //channel.Bind(responseQueueName, "<<default>>", RESPONSE_ROUTING_KEY);
+ IMessageConsumer consumer = channel.CreateConsumerBuilder(responseQueueName)
+ .Create();
+ consumer.OnMessage += new MessageReceivedDelegate(OnMessage);
+
+ // Set up this listener with a producer to send the test messages and report requests on.
+ publisher = channel.CreatePublisherBuilder()
+ .WithExchangeName(ExchangeNameDefaults.TOPIC)
+ .WithRoutingKey(CONTROL_ROUTING_KEY)
+ .Create();
+
+ // Keep the test parameters.
+ this.numMessages = numMessages;
+ this.numSubscribers = numSubscribers;
+
+ connection.Start();
+ Console.WriteLine("Sending messages and waiting for reports...");
+ }
+
+ /// <summary>
+ /// Start a test subscriber. The broker URL must be specified as the first command line argument.
+ /// </summary>
+ ///
+ /// <param name="argv">The command line arguments, broker URL first.</param>
+ public static void Main(String[] argv)
+ {
+ // Create an instance of this publisher with the command line parameters.
+ TopicPublisher publisher = new TopicPublisher(DEFAULT_URI, 1, 1);
+
+ // Publish the test messages.
+ publisher.DoTest();
+ }
+
+ /// <summary>
+ /// Sends the test messages and waits for all subscribers to reply with a report.
+ /// </summary>
+ public void DoTest()
+ {
+ log.Debug("public void DoTest(): called");
+
+ // Create a test message to send.
+ IMessage testMessage = channel.CreateTextMessage("test");
+
+ // Send the desired number of test messages.
+ for (int i = 0; i < numMessages; i++)
+ {
+ publisher.Send(testMessage);
+ }
+
+ log.Debug("Sent " + numMessages + " test messages.");
+
+ // Send the report request.
+ IMessage reportRequestMessage = channel.CreateTextMessage("Report request message.");
+ reportRequestMessage.Headers["TYPE"] = "REPORT_REQUEST";
+
+ reportRequestMessage.Headers.SetBoolean("BOOLEAN", false);
+ //reportRequestMessage.Headers.SetByte("BYTE", 5);
+ reportRequestMessage.Headers.SetDouble("DOUBLE", 3.141);
+ reportRequestMessage.Headers.SetFloat("FLOAT", 1.0f);
+ reportRequestMessage.Headers.SetInt("INT", 1);
+ reportRequestMessage.Headers.SetLong("LONG", 1);
+ reportRequestMessage.Headers.SetString("STRING", "hello");
+ reportRequestMessage.Headers.SetShort("SHORT", 2);
+
+ publisher.Send(reportRequestMessage);
+
+ log.Debug("Sent the report request message, waiting for all replies...");
+
+ // Wait until all the reports come in.
+ allReportsReceivedEvt.WaitOne(TIMEOUT, true);
+
+ // Check if all reports were really received or if the timeout occurred.
+ if (numSubscribers == 0)
+ {
+ log.Debug("Got all reports.");
+ }
+ else
+ {
+ log.Debug("Waiting for reports timed out, still waiting for " + numSubscribers + ".");
+ }
+
+ // Send the termination request.
+ IMessage terminationRequestMessage = channel.CreateTextMessage("Termination request message.");
+ terminationRequestMessage.Headers["TYPE"] = "TERMINATION_REQUEST";
+ publisher.Send(terminationRequestMessage);
+
+ log.Debug("Sent the termination request message.");
+
+ // Close all message producers and consumers and the connection to the broker.
+ Shutdown();
+ }
+
+ /// <summary>
+ /// Handles all report messages from subscribers. This decrements the count of subscribers that are still to reply, until this becomes
+ /// zero, at which time waiting threads are notified of this event.
+ /// </summary>
+ ///
+ /// <param name="message">The received report message.</param>
+ public void OnMessage(IMessage message)
+ {
+ log.Debug("public void OnMessage(IMessage message = " + message + "): called");
+
+ // Decrement the count of expected messages and release the wait monitor when this becomes zero.
+ if (--numSubscribers == 0)
+ {
+ log.Debug("Got reports from all subscribers.");
+ allReportsReceivedEvt.Set();
+ }
+ }
+
+ /// <summary> Stops the message consumers and closes the connection. </summary>
+ private void Shutdown()
+ {
+ connection.Stop();
+ publisher.Dispose();
+ channel.Dispose();
+ connection.Dispose();
+ }
+ }
+}
diff --git a/dotnet/Qpid.Client.Tests/log4net.config b/dotnet/Qpid.Client.Tests/log4net.config
index 8753c9c431..0ad25c4185 100644
--- a/dotnet/Qpid.Client.Tests/log4net.config
+++ b/dotnet/Qpid.Client.Tests/log4net.config
@@ -1,3 +1,23 @@
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
<log4net>
<!-- ============================== -->
@@ -45,4 +65,4 @@
<appender-ref ref="UdpAppender"/>
</root>
-</log4net> \ No newline at end of file
+</log4net>
diff --git a/dotnet/Qpid.Client.Transport.Socket.Blocking/Properties/AssemblyInfo.cs b/dotnet/Qpid.Client.Transport.Socket.Blocking/Properties/AssemblyInfo.cs
index e50bacdfc7..19599b0833 100644
--- a/dotnet/Qpid.Client.Transport.Socket.Blocking/Properties/AssemblyInfo.cs
+++ b/dotnet/Qpid.Client.Transport.Socket.Blocking/Properties/AssemblyInfo.cs
@@ -49,5 +49,5 @@ using System.Runtime.InteropServices;
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
-[assembly: AssemblyVersion("2.1.0.0")]
+[assembly: AssemblyVersion("0.5.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/Qpid.Client.Transport.Socket.Blocking/Qpid.Client.Transport.Socket.Blocking.csproj b/dotnet/Qpid.Client.Transport.Socket.Blocking/Qpid.Client.Transport.Socket.Blocking.csproj
index a12b6695e2..6a0b1cd8e6 100644
--- a/dotnet/Qpid.Client.Transport.Socket.Blocking/Qpid.Client.Transport.Socket.Blocking.csproj
+++ b/dotnet/Qpid.Client.Transport.Socket.Blocking/Qpid.Client.Transport.Socket.Blocking.csproj
@@ -1,3 +1,24 @@
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
diff --git a/dotnet/Qpid.Client/Client/AMQAuthenticationException.cs b/dotnet/Qpid.Client/Client/AMQAuthenticationException.cs
index 6382eaaf39..7bb64e3fff 100644
--- a/dotnet/Qpid.Client/Client/AMQAuthenticationException.cs
+++ b/dotnet/Qpid.Client/Client/AMQAuthenticationException.cs
@@ -1,39 +1,39 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Runtime.Serialization;
-
-namespace Apache.Qpid.Client
-{
- [Serializable]
- public class AMQAuthenticationException : AMQException
- {
- public AMQAuthenticationException(int error, String message)
- : base(error, message)
- {
- }
-
- protected AMQAuthenticationException(SerializationInfo info, StreamingContext ctxt)
- : base(info, ctxt)
- {
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Runtime.Serialization;
+
+namespace Apache.Qpid.Client
+{
+ [Serializable]
+ public class AMQAuthenticationException : AMQException
+ {
+ public AMQAuthenticationException(int error, String message)
+ : base(error, message)
+ {
+ }
+
+ protected AMQAuthenticationException(SerializationInfo info, StreamingContext ctxt)
+ : base(info, ctxt)
+ {
+ }
+ }
+}
diff --git a/dotnet/Qpid.Client/Client/AMQNoConsumersException.cs b/dotnet/Qpid.Client/Client/AMQNoConsumersException.cs
index 0d93176734..5c9dd86c53 100644
--- a/dotnet/Qpid.Client/Client/AMQNoConsumersException.cs
+++ b/dotnet/Qpid.Client/Client/AMQNoConsumersException.cs
@@ -1,45 +1,45 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Runtime.Serialization;
-using Apache.Qpid.Common;
-using Apache.Qpid.Protocol;
-
-namespace Apache.Qpid.Client
-{
- [Serializable]
- public class AMQNoConsumersException : AMQUndeliveredException
- {
- public AMQNoConsumersException(string message)
- : this(message, null)
- {
- }
-
- public AMQNoConsumersException(string message, object bounced)
- : base(AMQConstant.NO_CONSUMERS.Code, message, bounced)
- {
- }
- protected AMQNoConsumersException(SerializationInfo info, StreamingContext ctxt)
- : base(info, ctxt)
- {
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Runtime.Serialization;
+using Apache.Qpid.Common;
+using Apache.Qpid.Protocol;
+
+namespace Apache.Qpid.Client
+{
+ [Serializable]
+ public class AMQNoConsumersException : AMQUndeliveredException
+ {
+ public AMQNoConsumersException(string message)
+ : this(message, null)
+ {
+ }
+
+ public AMQNoConsumersException(string message, object bounced)
+ : base(AMQConstant.NO_CONSUMERS.Code, message, bounced)
+ {
+ }
+ protected AMQNoConsumersException(SerializationInfo info, StreamingContext ctxt)
+ : base(info, ctxt)
+ {
+ }
+ }
+}
diff --git a/dotnet/Qpid.Client/Client/AMQNoRouteException.cs b/dotnet/Qpid.Client/Client/AMQNoRouteException.cs
index bde3cdd989..5868d78f32 100644
--- a/dotnet/Qpid.Client/Client/AMQNoRouteException.cs
+++ b/dotnet/Qpid.Client/Client/AMQNoRouteException.cs
@@ -1,46 +1,46 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Runtime.Serialization;
-using Apache.Qpid.Common;
-using Apache.Qpid.Protocol;
-
-namespace Apache.Qpid.Client
-{
- [Serializable]
- public class AMQNoRouteException : AMQUndeliveredException
- {
- public AMQNoRouteException(string message)
- : this(message, null)
- {
- }
-
- public AMQNoRouteException(string message, object bounced)
- : base(AMQConstant.NO_ROUTE.Code, message, bounced)
- {
- }
-
- protected AMQNoRouteException(SerializationInfo info, StreamingContext ctxt)
- : base(info, ctxt)
- {
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Runtime.Serialization;
+using Apache.Qpid.Common;
+using Apache.Qpid.Protocol;
+
+namespace Apache.Qpid.Client
+{
+ [Serializable]
+ public class AMQNoRouteException : AMQUndeliveredException
+ {
+ public AMQNoRouteException(string message)
+ : this(message, null)
+ {
+ }
+
+ public AMQNoRouteException(string message, object bounced)
+ : base(AMQConstant.NO_ROUTE.Code, message, bounced)
+ {
+ }
+
+ protected AMQNoRouteException(SerializationInfo info, StreamingContext ctxt)
+ : base(info, ctxt)
+ {
+ }
+ }
+}
diff --git a/dotnet/Qpid.Client/Client/Configuration/AuthenticationConfigurationSectionHandler.cs b/dotnet/Qpid.Client/Client/Configuration/AuthenticationConfigurationSectionHandler.cs
index ae9225a53a..8d289fa956 100644
--- a/dotnet/Qpid.Client/Client/Configuration/AuthenticationConfigurationSectionHandler.cs
+++ b/dotnet/Qpid.Client/Client/Configuration/AuthenticationConfigurationSectionHandler.cs
@@ -1,84 +1,84 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Collections.Specialized;
-using System.Configuration;
-using System.Text;
-
-using Apache.Qpid.Client.Security;
-using Apache.Qpid.Sasl.Mechanisms;
-
-namespace Apache.Qpid.Client.Configuration
-{
- public class AuthenticationConfigurationSectionHandler
- : IConfigurationSectionHandler
- {
-
- public object Create(object parent, object configContext, System.Xml.XmlNode section)
- {
- NameValueSectionHandler handler = new NameValueSectionHandler();
- OrderedHashTable schemes = new OrderedHashTable();
-
- NameValueCollection options = (NameValueCollection)
- handler.Create(parent, configContext, section);
-
- if ( options != null )
- {
- foreach ( string key in options.Keys )
- {
- Type type = Type.GetType(options[key]);
- if ( type == null )
- throw new ConfigurationException(string.Format("Type '{0}' not found", key));
- if ( !typeof(IAMQCallbackHandler).IsAssignableFrom(type) )
- throw new ConfigurationException(string.Format("Type '{0}' does not implement IAMQCallbackHandler", key));
-
- schemes.Add(key, type);
- }
- }
-
- return schemes;
- }
-
- } // class AuthenticationConfigurationSectionHandler
-
- public class OrderedHashTable : Hashtable
- {
- private ArrayList _keys = new ArrayList();
-
- public IList OrderedKeys
- {
- get { return _keys; }
- }
-
- public override void Add(object key, object value)
- {
- base.Add(key, value);
- _keys.Add(key);
- }
- public override void Remove(object key)
- {
- base.Remove(key);
- _keys.Remove(key);
- }
- }
-} // namespace Apache.Qpid.Client.Configuration
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Configuration;
+using System.Text;
+
+using Apache.Qpid.Client.Security;
+using Apache.Qpid.Sasl.Mechanisms;
+
+namespace Apache.Qpid.Client.Configuration
+{
+ public class AuthenticationConfigurationSectionHandler
+ : IConfigurationSectionHandler
+ {
+
+ public object Create(object parent, object configContext, System.Xml.XmlNode section)
+ {
+ NameValueSectionHandler handler = new NameValueSectionHandler();
+ OrderedHashTable schemes = new OrderedHashTable();
+
+ NameValueCollection options = (NameValueCollection)
+ handler.Create(parent, configContext, section);
+
+ if ( options != null )
+ {
+ foreach ( string key in options.Keys )
+ {
+ Type type = Type.GetType(options[key]);
+ if ( type == null )
+ throw new ConfigurationException(string.Format("Type '{0}' not found", key));
+ if ( !typeof(IAMQCallbackHandler).IsAssignableFrom(type) )
+ throw new ConfigurationException(string.Format("Type '{0}' does not implement IAMQCallbackHandler", key));
+
+ schemes.Add(key, type);
+ }
+ }
+
+ return schemes;
+ }
+
+ } // class AuthenticationConfigurationSectionHandler
+
+ public class OrderedHashTable : Hashtable
+ {
+ private ArrayList _keys = new ArrayList();
+
+ public IList OrderedKeys
+ {
+ get { return _keys; }
+ }
+
+ public override void Add(object key, object value)
+ {
+ base.Add(key, value);
+ _keys.Add(key);
+ }
+ public override void Remove(object key)
+ {
+ base.Remove(key);
+ _keys.Remove(key);
+ }
+ }
+} // namespace Apache.Qpid.Client.Configuration
diff --git a/dotnet/Qpid.Client/Client/Handler/QueueDeleteOkMethodHandler.cs b/dotnet/Qpid.Client/Client/Handler/QueueDeleteOkMethodHandler.cs
index 7290d758f8..70aa3e1078 100644
--- a/dotnet/Qpid.Client/Client/Handler/QueueDeleteOkMethodHandler.cs
+++ b/dotnet/Qpid.Client/Client/Handler/QueueDeleteOkMethodHandler.cs
@@ -1,44 +1,44 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using log4net;
-using Apache.Qpid.Client.Message;
-using Apache.Qpid.Client.Protocol;
-using Apache.Qpid.Client.State;
-using Apache.Qpid.Framing;
-
-namespace Apache.Qpid.Client.Handler
-{
- public class QueueDeleteOkMethodHandler : IStateAwareMethodListener
- {
-
- private static readonly ILog _logger = LogManager.GetLogger(typeof(QueueDeleteOkMethodHandler));
-
- public void MethodReceived(AMQStateManager stateManager, AMQMethodEvent evt)
- {
- QueueDeleteOkBody body = (QueueDeleteOkBody)evt.Method;
- if (body != null)
- {
- _logger.InfoFormat("Received Queue.Delete-Ok message, message count {0}", body.MessageCount);
- }
- }
-
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using log4net;
+using Apache.Qpid.Client.Message;
+using Apache.Qpid.Client.Protocol;
+using Apache.Qpid.Client.State;
+using Apache.Qpid.Framing;
+
+namespace Apache.Qpid.Client.Handler
+{
+ public class QueueDeleteOkMethodHandler : IStateAwareMethodListener
+ {
+
+ private static readonly ILog _logger = LogManager.GetLogger(typeof(QueueDeleteOkMethodHandler));
+
+ public void MethodReceived(AMQStateManager stateManager, AMQMethodEvent evt)
+ {
+ QueueDeleteOkBody body = (QueueDeleteOkBody)evt.Method;
+ if (body != null)
+ {
+ _logger.InfoFormat("Received Queue.Delete-Ok message, message count {0}", body.MessageCount);
+ }
+ }
+
+ }
+}
diff --git a/dotnet/Qpid.Client/Client/Handler/QueuePurgeOkMethodHandler.cs b/dotnet/Qpid.Client/Client/Handler/QueuePurgeOkMethodHandler.cs
index 8bde707b00..22db70575d 100644
--- a/dotnet/Qpid.Client/Client/Handler/QueuePurgeOkMethodHandler.cs
+++ b/dotnet/Qpid.Client/Client/Handler/QueuePurgeOkMethodHandler.cs
@@ -1,44 +1,44 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using log4net;
-using Apache.Qpid.Client.Message;
-using Apache.Qpid.Client.Protocol;
-using Apache.Qpid.Client.State;
-using Apache.Qpid.Framing;
-
-namespace Apache.Qpid.Client.Handler
-{
- public class QueuePurgeOkMethodHandler : IStateAwareMethodListener
- {
-
- private static readonly ILog _logger = LogManager.GetLogger(typeof(QueuePurgeOkMethodHandler));
-
- public void MethodReceived(AMQStateManager stateManager, AMQMethodEvent evt)
- {
- QueuePurgeOkBody body = (QueuePurgeOkBody)evt.Method;
- if (body != null)
- {
- _logger.InfoFormat("Received Queue.Purge-Ok message, message count {0}", body.MessageCount);
- }
- }
-
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using log4net;
+using Apache.Qpid.Client.Message;
+using Apache.Qpid.Client.Protocol;
+using Apache.Qpid.Client.State;
+using Apache.Qpid.Framing;
+
+namespace Apache.Qpid.Client.Handler
+{
+ public class QueuePurgeOkMethodHandler : IStateAwareMethodListener
+ {
+
+ private static readonly ILog _logger = LogManager.GetLogger(typeof(QueuePurgeOkMethodHandler));
+
+ public void MethodReceived(AMQStateManager stateManager, AMQMethodEvent evt)
+ {
+ QueuePurgeOkBody body = (QueuePurgeOkBody)evt.Method;
+ if (body != null)
+ {
+ _logger.InfoFormat("Received Queue.Purge-Ok message, message count {0}", body.MessageCount);
+ }
+ }
+
+ }
+}
diff --git a/dotnet/Qpid.Client/Client/Message/QpidHeaders.cs b/dotnet/Qpid.Client/Client/Message/QpidHeaders.cs
index d27c1df853..9ad1c26867 100644
--- a/dotnet/Qpid.Client/Client/Message/QpidHeaders.cs
+++ b/dotnet/Qpid.Client/Client/Message/QpidHeaders.cs
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
using System;
using System.Collections;
using System.Text;
diff --git a/dotnet/Qpid.Client/Client/Protocol/DefaultTimeouts.cs b/dotnet/Qpid.Client/Client/Protocol/DefaultTimeouts.cs
index 6841b46f54..2f23a1571d 100644
--- a/dotnet/Qpid.Client/Client/Protocol/DefaultTimeouts.cs
+++ b/dotnet/Qpid.Client/Client/Protocol/DefaultTimeouts.cs
@@ -1,47 +1,47 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Text;
-
-namespace Apache.Qpid.Client.Protocol
-{
- /// <summary>
- /// Default timeout values for the protocol
- /// </summary>
- sealed class DefaultTimeouts
- {
- /// <summary>
- /// Maximum number of milliseconds to wait for a state change
- /// in the protocol's state machine
- /// </summary>
- public const int MaxWaitForState = 30* 1000;
- /// <summary>
- /// Maximum number of milliseconds to wait for a reply
- /// frame when doing synchronous writer to the broker
- /// </summary>
- public const int MaxWaitForSyncWriter = 30 * 1000;
-
- private DefaultTimeouts()
- {
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Text;
+
+namespace Apache.Qpid.Client.Protocol
+{
+ /// <summary>
+ /// Default timeout values for the protocol
+ /// </summary>
+ sealed class DefaultTimeouts
+ {
+ /// <summary>
+ /// Maximum number of milliseconds to wait for a state change
+ /// in the protocol's state machine
+ /// </summary>
+ public const int MaxWaitForState = 30* 1000;
+ /// <summary>
+ /// Maximum number of milliseconds to wait for a reply
+ /// frame when doing synchronous writer to the broker
+ /// </summary>
+ public const int MaxWaitForSyncWriter = 30 * 1000;
+
+ private DefaultTimeouts()
+ {
+ }
+ }
+}
diff --git a/dotnet/Qpid.Client/Client/Security/CallbackHandlerRegistry.cs b/dotnet/Qpid.Client/Client/Security/CallbackHandlerRegistry.cs
index 85be927ff4..9ac0381850 100644
--- a/dotnet/Qpid.Client/Client/Security/CallbackHandlerRegistry.cs
+++ b/dotnet/Qpid.Client/Client/Security/CallbackHandlerRegistry.cs
@@ -1,127 +1,129 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Configuration;
-using System.Text;
-using Apache.Qpid.Sasl;
-using Apache.Qpid.Sasl.Mechanisms;
-
-using Apache.Qpid.Client.Configuration;
-
-namespace Apache.Qpid.Client.Security
-{
-
- /// <summary>
- /// Helper class to map SASL mechanisms to our
- /// internal ISaslCallbackHandler implementations.
- /// </summary>
- /// <remarks>
- /// The set of configured callback handlers and their order
- /// controls the selection of the SASL mechanism used for authentication.
- /// <para>
- /// You can either replace the default handler for CRAM-MD5 and PLAIN
- /// authentication (the two default options) using the application
- /// configuration file. Configuration is done by especifying the SASL
- /// mechanism name (e.g PLAIN) and the type implementing the callback handler
- /// used to provide any data required by the mechanism like username and password.
- /// </para>
- /// <para>
- /// Callback handler types should implement the IAMQCallbackHandler interface.
- /// </para>
- /// <para>
- /// New callbacks or authentication mechanisms can be configured like this:
- /// </para>
- /// <example><![CDATA[
- /// <configuration>
- /// <configSections>
- /// <sectionGroup name="qpid.client">
- /// <section name="authentication" type="Apache.Qpid.Client.Configuration.AuthenticationConfigurationSectionHandler, Apache.Qpid.Client"/>
- /// </sectionGroup>
- /// </configSections>
- /// <qpid.client>
- /// <authentication>
- /// <add key="TEST" value="Apache.Qpid.Client.Tests.Security.TestCallbackHandler, Apache.Qpid.Client.Tests"/>
- /// </authentication>
- /// </qpid.client>
- /// </configuration>
- /// ]]></example>
- /// </remarks>
- public sealed class CallbackHandlerRegistry
- {
- private static CallbackHandlerRegistry _instance =
- new CallbackHandlerRegistry();
- private OrderedHashTable _mechanism2HandlerMap;
- private string[] _mechanisms;
-
- public static CallbackHandlerRegistry Instance
- {
- get { return _instance; }
- }
-
- public string[] Mechanisms
- {
- get { return _mechanisms; }
- }
-
- private CallbackHandlerRegistry()
- {
- _mechanism2HandlerMap = (OrderedHashTable)
- ConfigurationSettings.GetConfig("qpid.client/authentication");
-
- // configure default options if not available
- if ( _mechanism2HandlerMap == null )
- _mechanism2HandlerMap = new OrderedHashTable();
-
- if ( !_mechanism2HandlerMap.Contains(ExternalSaslClient.Mechanism) )
- _mechanism2HandlerMap.Add(ExternalSaslClient.Mechanism, typeof(UsernamePasswordCallbackHandler));
- if ( !_mechanism2HandlerMap.Contains(CramMD5SaslClient.Mechanism) )
- _mechanism2HandlerMap.Add(CramMD5SaslClient.Mechanism, typeof(UsernamePasswordCallbackHandler));
- if ( !_mechanism2HandlerMap.Contains(PlainSaslClient.Mechanism) )
- _mechanism2HandlerMap.Add(PlainSaslClient.Mechanism, typeof(UsernamePasswordCallbackHandler));
-
- _mechanisms = new string[_mechanism2HandlerMap.Count];
- _mechanism2HandlerMap.OrderedKeys.CopyTo(_mechanisms, 0);
- }
-
- public bool IsSupportedMechanism(string mechanism)
- {
- return _mechanism2HandlerMap.Contains(mechanism);
- }
-
- public string ChooseMechanism(string mechanisms)
- {
- IList mechs = mechanisms.Split(' ');
- foreach ( string supportedMech in _mechanisms )
- {
- if ( mechs.Contains(supportedMech) )
- return supportedMech;
- }
- return null;
- }
-
- public Type GetCallbackHandler(string mechanism)
- {
- return (Type)_mechanism2HandlerMap[mechanism];
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Configuration;
+using System.Text;
+using Apache.Qpid.Sasl;
+using Apache.Qpid.Sasl.Mechanisms;
+
+using Apache.Qpid.Client.Configuration;
+
+namespace Apache.Qpid.Client.Security
+{
+
+ /// <summary>
+ /// Helper class to map SASL mechanisms to our
+ /// internal ISaslCallbackHandler implementations.
+ /// </summary>
+ /// <remarks>
+ /// The set of configured callback handlers and their order
+ /// controls the selection of the SASL mechanism used for authentication.
+ /// <para>
+ /// You can either replace the default handler for CRAM-MD5 and PLAIN
+ /// authentication (the two default options) using the application
+ /// configuration file. Configuration is done by especifying the SASL
+ /// mechanism name (e.g PLAIN) and the type implementing the callback handler
+ /// used to provide any data required by the mechanism like username and password.
+ /// </para>
+ /// <para>
+ /// Callback handler types should implement the IAMQCallbackHandler interface.
+ /// </para>
+ /// <para>
+ /// New callbacks or authentication mechanisms can be configured like this:
+ /// </para>
+ /// <example><![CDATA[
+ /// <configuration>
+ /// <configSections>
+ /// <sectionGroup name="qpid.client">
+ /// <section name="authentication" type="Apache.Qpid.Client.Configuration.AuthenticationConfigurationSectionHandler, Apache.Qpid.Client"/>
+ /// </sectionGroup>
+ /// </configSections>
+ /// <qpid.client>
+ /// <authentication>
+ /// <add key="TEST" value="Apache.Qpid.Client.Tests.Security.TestCallbackHandler, Apache.Qpid.Client.Tests"/>
+ /// </authentication>
+ /// </qpid.client>
+ /// </configuration>
+ /// ]]></example>
+ /// </remarks>
+ public sealed class CallbackHandlerRegistry
+ {
+ private static CallbackHandlerRegistry _instance =
+ new CallbackHandlerRegistry();
+ private OrderedHashTable _mechanism2HandlerMap;
+ private string[] _mechanisms;
+
+ public static CallbackHandlerRegistry Instance
+ {
+ get { return _instance; }
+ }
+
+ public string[] Mechanisms
+ {
+ get { return _mechanisms; }
+ }
+
+ private CallbackHandlerRegistry()
+ {
+ _mechanism2HandlerMap = (OrderedHashTable)
+ ConfigurationSettings.GetConfig("qpid.client/authentication");
+
+ // configure default options if not available
+ if ( _mechanism2HandlerMap == null )
+ _mechanism2HandlerMap = new OrderedHashTable();
+
+ if ( !_mechanism2HandlerMap.Contains(ExternalSaslClient.Mechanism) )
+ _mechanism2HandlerMap.Add(ExternalSaslClient.Mechanism, typeof(UsernamePasswordCallbackHandler));
+ if ( !_mechanism2HandlerMap.Contains(CramMD5SaslClient.Mechanism) )
+ _mechanism2HandlerMap.Add(CramMD5SaslClient.Mechanism, typeof(UsernamePasswordCallbackHandler));
+ if ( !_mechanism2HandlerMap.Contains(CramMD5HexSaslClient.Mechanism) )
+ _mechanism2HandlerMap.Add(CramMD5HexSaslClient.Mechanism, typeof(UsernamePasswordCallbackHandler));
+ if ( !_mechanism2HandlerMap.Contains(PlainSaslClient.Mechanism) )
+ _mechanism2HandlerMap.Add(PlainSaslClient.Mechanism, typeof(UsernamePasswordCallbackHandler));
+
+ _mechanisms = new string[_mechanism2HandlerMap.Count];
+ _mechanism2HandlerMap.OrderedKeys.CopyTo(_mechanisms, 0);
+ }
+
+ public bool IsSupportedMechanism(string mechanism)
+ {
+ return _mechanism2HandlerMap.Contains(mechanism);
+ }
+
+ public string ChooseMechanism(string mechanisms)
+ {
+ IList mechs = mechanisms.Split(' ');
+ foreach ( string supportedMech in _mechanisms )
+ {
+ if ( mechs.Contains(supportedMech) )
+ return supportedMech;
+ }
+ return null;
+ }
+
+ public Type GetCallbackHandler(string mechanism)
+ {
+ return (Type)_mechanism2HandlerMap[mechanism];
+ }
+ }
+}
diff --git a/dotnet/Qpid.Client/Client/Security/IAMQCallbackHandler.cs b/dotnet/Qpid.Client/Client/Security/IAMQCallbackHandler.cs
index 2560c1d96b..6ff45be04a 100644
--- a/dotnet/Qpid.Client/Client/Security/IAMQCallbackHandler.cs
+++ b/dotnet/Qpid.Client/Client/Security/IAMQCallbackHandler.cs
@@ -1,35 +1,35 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Text;
-using Apache.Qpid.Client.Protocol;
-using Apache.Qpid.Sasl;
-
-namespace Apache.Qpid.Client.Security
-{
- public interface IAMQCallbackHandler : ISaslCallbackHandler
- {
- void Initialize(AMQProtocolSession session);
- }
-
-}
-
-
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Text;
+using Apache.Qpid.Client.Protocol;
+using Apache.Qpid.Sasl;
+
+namespace Apache.Qpid.Client.Security
+{
+ public interface IAMQCallbackHandler : ISaslCallbackHandler
+ {
+ void Initialize(AMQProtocolSession session);
+ }
+
+}
+
+
diff --git a/dotnet/Qpid.Client/Client/Security/UsernamePasswordCallbackHandler.cs b/dotnet/Qpid.Client/Client/Security/UsernamePasswordCallbackHandler.cs
index 489d4d1665..743ade77c9 100644
--- a/dotnet/Qpid.Client/Client/Security/UsernamePasswordCallbackHandler.cs
+++ b/dotnet/Qpid.Client/Client/Security/UsernamePasswordCallbackHandler.cs
@@ -1,56 +1,56 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Text;
-using Apache.Qpid.Client.Protocol;
-using Apache.Qpid.Sasl;
-
-namespace Apache.Qpid.Client.Security
-{
- internal class UsernamePasswordCallbackHandler : IAMQCallbackHandler
- {
- private AMQProtocolSession _session;
-
- public void Initialize(AMQProtocolSession session)
- {
- if ( session == null )
- throw new ArgumentNullException("session");
-
- _session = session;
- }
-
- public void Handle(ISaslCallback[] callbacks)
- {
- foreach ( ISaslCallback cb in callbacks )
- {
- if ( cb is NameCallback )
- {
- ((NameCallback)cb).Text = _session.Username;
- } else if ( cb is PasswordCallback )
- {
- ((PasswordCallback)cb).Text = _session.Password;
- }
- }
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Text;
+using Apache.Qpid.Client.Protocol;
+using Apache.Qpid.Sasl;
+
+namespace Apache.Qpid.Client.Security
+{
+ internal class UsernamePasswordCallbackHandler : IAMQCallbackHandler
+ {
+ private AMQProtocolSession _session;
+
+ public void Initialize(AMQProtocolSession session)
+ {
+ if ( session == null )
+ throw new ArgumentNullException("session");
+
+ _session = session;
+ }
+
+ public void Handle(ISaslCallback[] callbacks)
+ {
+ foreach ( ISaslCallback cb in callbacks )
+ {
+ if ( cb is NameCallback )
+ {
+ ((NameCallback)cb).Text = _session.Username;
+ } else if ( cb is PasswordCallback )
+ {
+ ((PasswordCallback)cb).Text = _session.Password;
+ }
+ }
+ }
+ }
+}
diff --git a/dotnet/Qpid.Client/Client/SslOptions.cs b/dotnet/Qpid.Client/Client/SslOptions.cs
index d637101000..4630121828 100644
--- a/dotnet/Qpid.Client/Client/SslOptions.cs
+++ b/dotnet/Qpid.Client/Client/SslOptions.cs
@@ -1,81 +1,81 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Security.Cryptography.X509Certificates;
-
-namespace Apache.Qpid.Client
-{
- /// <summary>
- /// Configures SSL-related options to connect to an AMQP broker.
- /// </summary>
- /// <remarks>
- /// If the server certificate is not trusted by the client,
- /// connection will fail. However, you can set the
- /// <see cref="IgnoreValidationErrors"/> property to true
- /// to ignore any certificate verification errors for debugging purposes.
- /// </remarks>
- public class SslOptions
- {
- private X509Certificate _clientCertificate;
- private bool _ignoreValidationErrors;
-
- /// <summary>
- /// Certificate to present to the broker to authenticate
- /// this client connection
- /// </summary>
- public X509Certificate ClientCertificate
- {
- get { return _clientCertificate; }
- }
-
- /// <summary>
- /// If true, the validity of the broker certificate
- /// will not be verified on connection
- /// </summary>
- public bool IgnoreValidationErrors
- {
- get { return _ignoreValidationErrors; }
- }
-
- /// <summary>
- /// Initialize a new instance with default values
- /// (No client certificate, don't ignore validation errors)
- /// </summary>
- public SslOptions()
- {
- }
-
- /// <summary>
- /// Initialize a new instance
- /// </summary>
- /// <param name="clientCertificate">
- /// Certificate to use to authenticate the client to the broker
- /// </param>
- /// <param name="ignoreValidationErrors">
- /// If true, ignore any validation errors when validating the server certificate
- /// </param>
- public SslOptions(X509Certificate clientCertificate, bool ignoreValidationErrors)
- {
- _clientCertificate = clientCertificate;
- _ignoreValidationErrors = ignoreValidationErrors;
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Security.Cryptography.X509Certificates;
+
+namespace Apache.Qpid.Client
+{
+ /// <summary>
+ /// Configures SSL-related options to connect to an AMQP broker.
+ /// </summary>
+ /// <remarks>
+ /// If the server certificate is not trusted by the client,
+ /// connection will fail. However, you can set the
+ /// <see cref="IgnoreValidationErrors"/> property to true
+ /// to ignore any certificate verification errors for debugging purposes.
+ /// </remarks>
+ public class SslOptions
+ {
+ private X509Certificate _clientCertificate;
+ private bool _ignoreValidationErrors;
+
+ /// <summary>
+ /// Certificate to present to the broker to authenticate
+ /// this client connection
+ /// </summary>
+ public X509Certificate ClientCertificate
+ {
+ get { return _clientCertificate; }
+ }
+
+ /// <summary>
+ /// If true, the validity of the broker certificate
+ /// will not be verified on connection
+ /// </summary>
+ public bool IgnoreValidationErrors
+ {
+ get { return _ignoreValidationErrors; }
+ }
+
+ /// <summary>
+ /// Initialize a new instance with default values
+ /// (No client certificate, don't ignore validation errors)
+ /// </summary>
+ public SslOptions()
+ {
+ }
+
+ /// <summary>
+ /// Initialize a new instance
+ /// </summary>
+ /// <param name="clientCertificate">
+ /// Certificate to use to authenticate the client to the broker
+ /// </param>
+ /// <param name="ignoreValidationErrors">
+ /// If true, ignore any validation errors when validating the server certificate
+ /// </param>
+ public SslOptions(X509Certificate clientCertificate, bool ignoreValidationErrors)
+ {
+ _clientCertificate = clientCertificate;
+ _ignoreValidationErrors = ignoreValidationErrors;
+ }
+ }
+}
diff --git a/dotnet/Qpid.Client/Client/Transport/IStreamFilter.cs b/dotnet/Qpid.Client/Client/Transport/IStreamFilter.cs
index 7195b3ab04..e0e890fc5a 100644
--- a/dotnet/Qpid.Client/Client/Transport/IStreamFilter.cs
+++ b/dotnet/Qpid.Client/Client/Transport/IStreamFilter.cs
@@ -1,38 +1,38 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System.IO;
-
-namespace Apache.Qpid.Client.Transport
-{
- /// <summary>
- /// Defines a way to introduce an arbitrary filtering
- /// stream into the stream chain managed by <see cref="IoHandler"/>
- /// </summary>
- public interface IStreamFilter
- {
- /// <summary>
- /// Creates a new filtering stream on top of another
- /// </summary>
- /// <param name="lowerStream">Next stream on the stack</param>
- /// <returns>A new filtering stream</returns>
- Stream CreateFilterStream(Stream lowerStream);
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System.IO;
+
+namespace Apache.Qpid.Client.Transport
+{
+ /// <summary>
+ /// Defines a way to introduce an arbitrary filtering
+ /// stream into the stream chain managed by <see cref="IoHandler"/>
+ /// </summary>
+ public interface IStreamFilter
+ {
+ /// <summary>
+ /// Creates a new filtering stream on top of another
+ /// </summary>
+ /// <param name="lowerStream">Next stream on the stack</param>
+ /// <returns>A new filtering stream</returns>
+ Stream CreateFilterStream(Stream lowerStream);
+ }
+}
diff --git a/dotnet/Qpid.Client/Client/Transport/IoHandler.cs b/dotnet/Qpid.Client/Client/Transport/IoHandler.cs
index 9ac513069e..0475236d92 100644
--- a/dotnet/Qpid.Client/Client/Transport/IoHandler.cs
+++ b/dotnet/Qpid.Client/Client/Transport/IoHandler.cs
@@ -1,322 +1,322 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.IO;
-using System.Threading;
-using log4net;
-using Apache.Qpid.Buffer;
-using Apache.Qpid.Client.Protocol;
-
-namespace Apache.Qpid.Client.Transport
-{
- /// <summary>
- /// Responsible for reading and writing
- /// ByteBuffers from/to network streams, and handling
- /// the stream filters
- /// </summary>
- public class IoHandler : IByteChannel, IDisposable
- {
- private static readonly ILog _log = LogManager.GetLogger(typeof(IoHandler));
- private const int DEFAULT_BUFFER_SIZE = 32 * 1024;
-
- private Stream _topStream;
- private IProtocolListener _protocolListener;
- private int _readBufferSize;
-
- public int ReadBufferSize
- {
- get { return _readBufferSize; }
- set { _readBufferSize = value; }
- }
-
- /// <summary>
- /// Initialize a new instance
- /// </summary>
- /// <param name="stream">Underlying network stream</param>
- /// <param name="protocolListener">Protocol listener to report exceptions to</param>
- public IoHandler(Stream stream, IProtocolListener protocolListener)
- {
- if ( stream == null )
- throw new ArgumentNullException("stream");
- if ( protocolListener == null )
- throw new ArgumentNullException("protocolListener");
-
- // initially, the stream at the top of the filter
- // chain is the underlying network stream
- _topStream = stream;
- _protocolListener = protocolListener;
- _readBufferSize = DEFAULT_BUFFER_SIZE;
- }
-
- /// <summary>
- /// Adds a new filter on the top of the chain
- /// </summary>
- /// <param name="filter">Stream filter to put on top of the chain</param>
- /// <remarks>
- /// This should *only* be called during initialization. We don't
- /// support changing the filter change after the first read/write
- /// has been done and it's not thread-safe to boot!
- /// </remarks>
- public void AddFilter(IStreamFilter filter)
- {
- _topStream = filter.CreateFilterStream(_topStream);
- }
-
- #region IByteChannel Implementation
- //
- // IByteChannel Implementation
- //
-
- /// <summary>
- /// Read a <see cref="ByteBuffer"/> from the underlying
- /// network stream and any configured filters
- /// </summary>
- /// <returns>A ByteBuffer, if available</returns>
- public ByteBuffer Read()
- {
- byte[] bytes = AllocateBuffer();
-
- int numOctets = _topStream.Read(bytes, 0, bytes.Length);
-
- return WrapByteArray(bytes, numOctets);
- }
-
- /// <summary>
- /// Begin an asynchronous read operation
- /// </summary>
- /// <param name="callback">Callback method to call when read operation completes</param>
- /// <param name="state">State object</param>
- /// <returns>An <see cref="System.IAsyncResult"/> object</returns>
- public IAsyncResult BeginRead(AsyncCallback callback, object state)
- {
- byte[] bytes = AllocateBuffer();
- ReadData rd = new ReadData(callback, state, bytes);
-
- // only put a callback if the caller wants one.
- AsyncCallback myCallback = null;
- if ( callback != null )
- myCallback = new AsyncCallback(OnAsyncReadDone);
-
- IAsyncResult result = _topStream.BeginRead(
- bytes, 0, bytes.Length, myCallback,rd
- );
- return new WrappedAsyncResult(result, bytes);
- }
-
- /// <summary>
- /// End an asynchronous read operation
- /// </summary>
- /// <param name="result">The <see cref="System.IAsyncResult"/> object returned from <see cref="BeginRead"/></param>
- /// <returns>The <see cref="ByteBuffer"/> read</returns>
- public ByteBuffer EndRead(IAsyncResult result)
- {
- WrappedAsyncResult theResult = (WrappedAsyncResult)result;
- int bytesRead = _topStream.EndRead(theResult.InnerResult);
- return WrapByteArray(theResult.Buffer, bytesRead);
- }
-
- /// <summary>
- /// Write a <see cref="ByteBuffer"/> to the underlying network
- /// stream, going through any configured filters
- /// </summary>
- /// <param name="buffer"></param>
- public void Write(ByteBuffer buffer)
- {
- try
- {
- _topStream.Write(buffer.Array, buffer.Position, buffer.Limit); // FIXME
- }
- catch (Exception e)
- {
- _log.Warn("Write caused exception", e);
- _protocolListener.OnException(e);
- }
- }
-
- /// <summary>
- /// Begin an asynchronous write operation
- /// </summary>
- /// <param name="buffer">Buffer to write</param>
- /// <param name="callback">A callback to call when the operation completes</param>
- /// <param name="state">State object</param>
- /// <returns>An <see cref="System.IAsyncResult"/> object</returns>
- public IAsyncResult BeginWrite(ByteBuffer buffer, AsyncCallback callback, object state)
- {
- try
- {
- return _topStream.BeginWrite(
- buffer.Array, buffer.Position, buffer.Limit,
- callback, state
- );
- } catch ( Exception e )
- {
- _log.Error("BeginWrite caused exception", e);
- // not clear if an exception here should be propagated? we still
- // need to propagate it upwards anyway!
- _protocolListener.OnException(e);
- throw;
- }
- }
-
- /// <summary>
- /// End an asynchronous write operation
- /// </summary>
- /// <param name="result">The <see cref="System.IAsyncResult"/> object returned by <see cref="BeginWrite"/></param>
- public void EndWrite(IAsyncResult result)
- {
- try
- {
- _topStream.EndWrite(result);
- } catch ( Exception e )
- {
- _log.Error("EndWrite caused exception", e);
- // not clear if an exception here should be propagated?
- _protocolListener.OnException(e);
- //throw;
- }
- }
- #endregion // IByteChannel Implementation
-
- #region IDisposable Implementation
- //
- // IDisposable Implementation
- //
-
- public void Dispose()
- {
- if ( _topStream != null )
- {
- _topStream.Close();
- }
- }
-
- #endregion // IDisposable Implementation
-
- #region Private and Helper Classes/Methods
- //
- // Private and Helper Classes/Methods
- //
-
- private byte[] AllocateBuffer()
- {
- return new byte[ReadBufferSize];
- }
-
- private static ByteBuffer WrapByteArray(byte[] bytes, int size)
- {
- ByteBuffer byteBuffer = ByteBuffer.Wrap(bytes);
- byteBuffer.Limit = size;
- byteBuffer.Flip();
-
- return byteBuffer;
- }
-
-
- private static void OnAsyncReadDone(IAsyncResult result)
- {
- ReadData rd = (ReadData) result.AsyncState;
- IAsyncResult wrapped = new WrappedAsyncResult(result, rd.Buffer);
- rd.Callback(wrapped);
- }
-
- class ReadData
- {
- private object _state;
- private AsyncCallback _callback;
- private byte[] _buffer;
-
- public object State
- {
- get { return _state; }
- }
-
- public AsyncCallback Callback
- {
- get { return _callback; }
- }
-
- public byte[] Buffer
- {
- get { return _buffer; }
- }
-
- public ReadData(AsyncCallback callback, object state, byte[] buffer)
- {
- _callback = callback;
- _state = state;
- _buffer = buffer;
- }
- }
-
- class WrappedAsyncResult : IAsyncResult
- {
- private IAsyncResult _innerResult;
- private byte[] _buffer;
-
- #region IAsyncResult Properties
- //
- // IAsyncResult Properties
- //
- public bool IsCompleted
- {
- get { return _innerResult.IsCompleted; }
- }
-
- public WaitHandle AsyncWaitHandle
- {
- get { return _innerResult.AsyncWaitHandle; }
- }
-
- public object AsyncState
- {
- get { return _innerResult.AsyncState; }
- }
-
- public bool CompletedSynchronously
- {
- get { return _innerResult.CompletedSynchronously; }
- }
- #endregion // IAsyncResult Properties
-
- public IAsyncResult InnerResult
- {
- get { return _innerResult; }
- }
- public byte[] Buffer
- {
- get { return _buffer; }
- }
-
- public WrappedAsyncResult(IAsyncResult result, byte[] buffer)
- {
- if ( result == null )
- throw new ArgumentNullException("result");
- if ( buffer == null )
- throw new ArgumentNullException("buffer");
-
- _innerResult = result;
- _buffer = buffer;
- }
- }
-
- #endregion // Private and Helper Classes/Methods
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.IO;
+using System.Threading;
+using log4net;
+using Apache.Qpid.Buffer;
+using Apache.Qpid.Client.Protocol;
+
+namespace Apache.Qpid.Client.Transport
+{
+ /// <summary>
+ /// Responsible for reading and writing
+ /// ByteBuffers from/to network streams, and handling
+ /// the stream filters
+ /// </summary>
+ public class IoHandler : IByteChannel, IDisposable
+ {
+ private static readonly ILog _log = LogManager.GetLogger(typeof(IoHandler));
+ private const int DEFAULT_BUFFER_SIZE = 32 * 1024;
+
+ private Stream _topStream;
+ private IProtocolListener _protocolListener;
+ private int _readBufferSize;
+
+ public int ReadBufferSize
+ {
+ get { return _readBufferSize; }
+ set { _readBufferSize = value; }
+ }
+
+ /// <summary>
+ /// Initialize a new instance
+ /// </summary>
+ /// <param name="stream">Underlying network stream</param>
+ /// <param name="protocolListener">Protocol listener to report exceptions to</param>
+ public IoHandler(Stream stream, IProtocolListener protocolListener)
+ {
+ if ( stream == null )
+ throw new ArgumentNullException("stream");
+ if ( protocolListener == null )
+ throw new ArgumentNullException("protocolListener");
+
+ // initially, the stream at the top of the filter
+ // chain is the underlying network stream
+ _topStream = stream;
+ _protocolListener = protocolListener;
+ _readBufferSize = DEFAULT_BUFFER_SIZE;
+ }
+
+ /// <summary>
+ /// Adds a new filter on the top of the chain
+ /// </summary>
+ /// <param name="filter">Stream filter to put on top of the chain</param>
+ /// <remarks>
+ /// This should *only* be called during initialization. We don't
+ /// support changing the filter change after the first read/write
+ /// has been done and it's not thread-safe to boot!
+ /// </remarks>
+ public void AddFilter(IStreamFilter filter)
+ {
+ _topStream = filter.CreateFilterStream(_topStream);
+ }
+
+ #region IByteChannel Implementation
+ //
+ // IByteChannel Implementation
+ //
+
+ /// <summary>
+ /// Read a <see cref="ByteBuffer"/> from the underlying
+ /// network stream and any configured filters
+ /// </summary>
+ /// <returns>A ByteBuffer, if available</returns>
+ public ByteBuffer Read()
+ {
+ byte[] bytes = AllocateBuffer();
+
+ int numOctets = _topStream.Read(bytes, 0, bytes.Length);
+
+ return WrapByteArray(bytes, numOctets);
+ }
+
+ /// <summary>
+ /// Begin an asynchronous read operation
+ /// </summary>
+ /// <param name="callback">Callback method to call when read operation completes</param>
+ /// <param name="state">State object</param>
+ /// <returns>An <see cref="System.IAsyncResult"/> object</returns>
+ public IAsyncResult BeginRead(AsyncCallback callback, object state)
+ {
+ byte[] bytes = AllocateBuffer();
+ ReadData rd = new ReadData(callback, state, bytes);
+
+ // only put a callback if the caller wants one.
+ AsyncCallback myCallback = null;
+ if ( callback != null )
+ myCallback = new AsyncCallback(OnAsyncReadDone);
+
+ IAsyncResult result = _topStream.BeginRead(
+ bytes, 0, bytes.Length, myCallback,rd
+ );
+ return new WrappedAsyncResult(result, bytes);
+ }
+
+ /// <summary>
+ /// End an asynchronous read operation
+ /// </summary>
+ /// <param name="result">The <see cref="System.IAsyncResult"/> object returned from <see cref="BeginRead"/></param>
+ /// <returns>The <see cref="ByteBuffer"/> read</returns>
+ public ByteBuffer EndRead(IAsyncResult result)
+ {
+ WrappedAsyncResult theResult = (WrappedAsyncResult)result;
+ int bytesRead = _topStream.EndRead(theResult.InnerResult);
+ return WrapByteArray(theResult.Buffer, bytesRead);
+ }
+
+ /// <summary>
+ /// Write a <see cref="ByteBuffer"/> to the underlying network
+ /// stream, going through any configured filters
+ /// </summary>
+ /// <param name="buffer"></param>
+ public void Write(ByteBuffer buffer)
+ {
+ try
+ {
+ _topStream.Write(buffer.Array, buffer.Position, buffer.Limit); // FIXME
+ }
+ catch (Exception e)
+ {
+ _log.Warn("Write caused exception", e);
+ _protocolListener.OnException(e);
+ }
+ }
+
+ /// <summary>
+ /// Begin an asynchronous write operation
+ /// </summary>
+ /// <param name="buffer">Buffer to write</param>
+ /// <param name="callback">A callback to call when the operation completes</param>
+ /// <param name="state">State object</param>
+ /// <returns>An <see cref="System.IAsyncResult"/> object</returns>
+ public IAsyncResult BeginWrite(ByteBuffer buffer, AsyncCallback callback, object state)
+ {
+ try
+ {
+ return _topStream.BeginWrite(
+ buffer.Array, buffer.Position, buffer.Limit,
+ callback, state
+ );
+ } catch ( Exception e )
+ {
+ _log.Error("BeginWrite caused exception", e);
+ // not clear if an exception here should be propagated? we still
+ // need to propagate it upwards anyway!
+ _protocolListener.OnException(e);
+ throw;
+ }
+ }
+
+ /// <summary>
+ /// End an asynchronous write operation
+ /// </summary>
+ /// <param name="result">The <see cref="System.IAsyncResult"/> object returned by <see cref="BeginWrite"/></param>
+ public void EndWrite(IAsyncResult result)
+ {
+ try
+ {
+ _topStream.EndWrite(result);
+ } catch ( Exception e )
+ {
+ _log.Error("EndWrite caused exception", e);
+ // not clear if an exception here should be propagated?
+ _protocolListener.OnException(e);
+ //throw;
+ }
+ }
+ #endregion // IByteChannel Implementation
+
+ #region IDisposable Implementation
+ //
+ // IDisposable Implementation
+ //
+
+ public void Dispose()
+ {
+ if ( _topStream != null )
+ {
+ _topStream.Close();
+ }
+ }
+
+ #endregion // IDisposable Implementation
+
+ #region Private and Helper Classes/Methods
+ //
+ // Private and Helper Classes/Methods
+ //
+
+ private byte[] AllocateBuffer()
+ {
+ return new byte[ReadBufferSize];
+ }
+
+ private static ByteBuffer WrapByteArray(byte[] bytes, int size)
+ {
+ ByteBuffer byteBuffer = ByteBuffer.Wrap(bytes);
+ byteBuffer.Limit = size;
+ byteBuffer.Flip();
+
+ return byteBuffer;
+ }
+
+
+ private static void OnAsyncReadDone(IAsyncResult result)
+ {
+ ReadData rd = (ReadData) result.AsyncState;
+ IAsyncResult wrapped = new WrappedAsyncResult(result, rd.Buffer);
+ rd.Callback(wrapped);
+ }
+
+ class ReadData
+ {
+ private object _state;
+ private AsyncCallback _callback;
+ private byte[] _buffer;
+
+ public object State
+ {
+ get { return _state; }
+ }
+
+ public AsyncCallback Callback
+ {
+ get { return _callback; }
+ }
+
+ public byte[] Buffer
+ {
+ get { return _buffer; }
+ }
+
+ public ReadData(AsyncCallback callback, object state, byte[] buffer)
+ {
+ _callback = callback;
+ _state = state;
+ _buffer = buffer;
+ }
+ }
+
+ class WrappedAsyncResult : IAsyncResult
+ {
+ private IAsyncResult _innerResult;
+ private byte[] _buffer;
+
+ #region IAsyncResult Properties
+ //
+ // IAsyncResult Properties
+ //
+ public bool IsCompleted
+ {
+ get { return _innerResult.IsCompleted; }
+ }
+
+ public WaitHandle AsyncWaitHandle
+ {
+ get { return _innerResult.AsyncWaitHandle; }
+ }
+
+ public object AsyncState
+ {
+ get { return _innerResult.AsyncState; }
+ }
+
+ public bool CompletedSynchronously
+ {
+ get { return _innerResult.CompletedSynchronously; }
+ }
+ #endregion // IAsyncResult Properties
+
+ public IAsyncResult InnerResult
+ {
+ get { return _innerResult; }
+ }
+ public byte[] Buffer
+ {
+ get { return _buffer; }
+ }
+
+ public WrappedAsyncResult(IAsyncResult result, byte[] buffer)
+ {
+ if ( result == null )
+ throw new ArgumentNullException("result");
+ if ( buffer == null )
+ throw new ArgumentNullException("buffer");
+
+ _innerResult = result;
+ _buffer = buffer;
+ }
+ }
+
+ #endregion // Private and Helper Classes/Methods
+ }
+}
diff --git a/dotnet/Qpid.Client/Client/Transport/ProtocolDecoderOutput.cs b/dotnet/Qpid.Client/Client/Transport/ProtocolDecoderOutput.cs
index 3841c158e4..9fa313152f 100644
--- a/dotnet/Qpid.Client/Client/Transport/ProtocolDecoderOutput.cs
+++ b/dotnet/Qpid.Client/Client/Transport/ProtocolDecoderOutput.cs
@@ -1,60 +1,60 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Threading;
-using Apache.Qpid.Client.Protocol;
-using Apache.Qpid.Codec;
-using Apache.Qpid.Framing;
-using log4net;
-
-namespace Apache.Qpid.Client.Transport
-{
- /// <summary>
- /// <see cref="IProtocolDecoderOutput"/> implementation that forwards
- /// each <see cref="IDataBlock"/> as it is decoded to the
- /// protocol listener
- /// </summary>
- internal class ProtocolDecoderOutput : IProtocolDecoderOutput
- {
- private IProtocolListener _protocolListener;
- static readonly ILog _protocolTraceLog = LogManager.GetLogger("TRACE.Qpid.Client.ProtocolChannel");
-
- public ProtocolDecoderOutput(IProtocolListener protocolListener)
- {
- if ( protocolListener == null )
- throw new ArgumentNullException("protocolListener");
-
- _protocolListener = protocolListener;
- }
-
- public void Write(object message)
- {
- IDataBlock block = message as IDataBlock;
- if ( block != null )
- {
- _protocolTraceLog.Debug(String.Format("READ {0}", block));
- _protocolListener.OnMessage(block);
- }
- }
- }
-} // namespace Apache.Qpid.Client.Transport
-
-
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Threading;
+using Apache.Qpid.Client.Protocol;
+using Apache.Qpid.Codec;
+using Apache.Qpid.Framing;
+using log4net;
+
+namespace Apache.Qpid.Client.Transport
+{
+ /// <summary>
+ /// <see cref="IProtocolDecoderOutput"/> implementation that forwards
+ /// each <see cref="IDataBlock"/> as it is decoded to the
+ /// protocol listener
+ /// </summary>
+ internal class ProtocolDecoderOutput : IProtocolDecoderOutput
+ {
+ private IProtocolListener _protocolListener;
+ static readonly ILog _protocolTraceLog = LogManager.GetLogger("TRACE.Qpid.Client.ProtocolChannel");
+
+ public ProtocolDecoderOutput(IProtocolListener protocolListener)
+ {
+ if ( protocolListener == null )
+ throw new ArgumentNullException("protocolListener");
+
+ _protocolListener = protocolListener;
+ }
+
+ public void Write(object message)
+ {
+ IDataBlock block = message as IDataBlock;
+ if ( block != null )
+ {
+ _protocolTraceLog.Debug(String.Format("READ {0}", block));
+ _protocolListener.OnMessage(block);
+ }
+ }
+ }
+} // namespace Apache.Qpid.Client.Transport
+
+
diff --git a/dotnet/Qpid.Client/Client/Transport/Socket/Blocking/BlockingSocketTransport.cs b/dotnet/Qpid.Client/Client/Transport/Socket/Blocking/BlockingSocketTransport.cs
index 8a16f9a675..f336d8a80a 100644
--- a/dotnet/Qpid.Client/Client/Transport/Socket/Blocking/BlockingSocketTransport.cs
+++ b/dotnet/Qpid.Client/Client/Transport/Socket/Blocking/BlockingSocketTransport.cs
@@ -1,150 +1,150 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Collections;
-using System.IO;
-using System.Threading;
-using Apache.Qpid.Client.Qms;
-using Apache.Qpid.Client.Protocol;
-using Apache.Qpid.Codec;
-using Apache.Qpid.Framing;
-
-namespace Apache.Qpid.Client.Transport.Socket.Blocking
-{
- /// <summary>
- /// TCP Socket transport supporting both
- /// SSL and non-SSL connections.
- /// </summary>
- public class BlockingSocketTransport : ITransport
- {
- // Configuration variables.
- IProtocolListener _protocolListener;
-
- // Runtime variables.
- private ISocketConnector _connector;
- private IoHandler _ioHandler;
- private AmqpChannel _amqpChannel;
- private ManualResetEvent _stopEvent;
-
- public IProtocolWriter ProtocolWriter
- {
- get { return _amqpChannel; }
- }
- public string LocalEndpoint
- {
- get { return _connector.LocalEndpoint; }
- }
-
-
- /// <summary>
- /// Connect to the specified broker
- /// </summary>
- /// <param name="broker">The broker to connect to</param>
- /// <param name="connection">The AMQ connection</param>
- public void Connect(IBrokerInfo broker, AMQConnection connection)
- {
- _stopEvent = new ManualResetEvent(false);
- _protocolListener = connection.ProtocolListener;
-
- _ioHandler = MakeBrokerConnection(broker, connection);
- // todo: get default read size from config!
-
- IProtocolDecoderOutput decoderOutput =
- new ProtocolDecoderOutput(_protocolListener);
- _amqpChannel =
- new AmqpChannel(new ByteChannel(_ioHandler), decoderOutput);
-
- // post an initial async read
- _amqpChannel.BeginRead(new AsyncCallback(OnAsyncReadDone), this);
- }
-
- /// <summary>
- /// Close the broker connection
- /// </summary>
- public void Close()
- {
- StopReading();
- CloseBrokerConnection();
- }
-
- private void StopReading()
- {
- _stopEvent.Set();
- }
-
- private void CloseBrokerConnection()
- {
- if ( _ioHandler != null )
- {
- _ioHandler.Dispose();
- _ioHandler = null;
- }
- if ( _connector != null )
- {
- _connector.Dispose();
- _connector = null;
- }
- }
-
- private IoHandler MakeBrokerConnection(IBrokerInfo broker, AMQConnection connection)
- {
- if ( broker.UseSSL )
- {
- _connector = new SslSocketConnector();
- } else
- {
- _connector = new SocketConnector();
- }
-
- Stream stream = _connector.Connect(broker);
- return new IoHandler(stream, connection.ProtocolListener);
- }
-
- private void OnAsyncReadDone(IAsyncResult result)
- {
- try
- {
- _amqpChannel.EndRead(result);
-
- bool stopping = _stopEvent.WaitOne(0, false);
- if ( !stopping )
- _amqpChannel.BeginRead(new AsyncCallback(OnAsyncReadDone), null);
- } catch ( Exception e )
- {
- // ignore any errors during closing
- bool stopping = _stopEvent.WaitOne(0, false);
- if ( !stopping )
- _protocolListener.OnException(e);
- }
- }
-
- #region IProtocolDecoderOutput Members
-
- public void Write(object message)
- {
- _protocolListener.OnMessage((IDataBlock)message);
- }
-
- #endregion
- }
-}
-
-
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Collections;
+using System.IO;
+using System.Threading;
+using Apache.Qpid.Client.Qms;
+using Apache.Qpid.Client.Protocol;
+using Apache.Qpid.Codec;
+using Apache.Qpid.Framing;
+
+namespace Apache.Qpid.Client.Transport.Socket.Blocking
+{
+ /// <summary>
+ /// TCP Socket transport supporting both
+ /// SSL and non-SSL connections.
+ /// </summary>
+ public class BlockingSocketTransport : ITransport
+ {
+ // Configuration variables.
+ IProtocolListener _protocolListener;
+
+ // Runtime variables.
+ private ISocketConnector _connector;
+ private IoHandler _ioHandler;
+ private AmqpChannel _amqpChannel;
+ private ManualResetEvent _stopEvent;
+
+ public IProtocolWriter ProtocolWriter
+ {
+ get { return _amqpChannel; }
+ }
+ public string LocalEndpoint
+ {
+ get { return _connector.LocalEndpoint; }
+ }
+
+
+ /// <summary>
+ /// Connect to the specified broker
+ /// </summary>
+ /// <param name="broker">The broker to connect to</param>
+ /// <param name="connection">The AMQ connection</param>
+ public void Connect(IBrokerInfo broker, AMQConnection connection)
+ {
+ _stopEvent = new ManualResetEvent(false);
+ _protocolListener = connection.ProtocolListener;
+
+ _ioHandler = MakeBrokerConnection(broker, connection);
+ // todo: get default read size from config!
+
+ IProtocolDecoderOutput decoderOutput =
+ new ProtocolDecoderOutput(_protocolListener);
+ _amqpChannel =
+ new AmqpChannel(new ByteChannel(_ioHandler), decoderOutput);
+
+ // post an initial async read
+ _amqpChannel.BeginRead(new AsyncCallback(OnAsyncReadDone), this);
+ }
+
+ /// <summary>
+ /// Close the broker connection
+ /// </summary>
+ public void Close()
+ {
+ StopReading();
+ CloseBrokerConnection();
+ }
+
+ private void StopReading()
+ {
+ _stopEvent.Set();
+ }
+
+ private void CloseBrokerConnection()
+ {
+ if ( _ioHandler != null )
+ {
+ _ioHandler.Dispose();
+ _ioHandler = null;
+ }
+ if ( _connector != null )
+ {
+ _connector.Dispose();
+ _connector = null;
+ }
+ }
+
+ private IoHandler MakeBrokerConnection(IBrokerInfo broker, AMQConnection connection)
+ {
+ if ( broker.UseSSL )
+ {
+ _connector = new SslSocketConnector();
+ } else
+ {
+ _connector = new SocketConnector();
+ }
+
+ Stream stream = _connector.Connect(broker);
+ return new IoHandler(stream, connection.ProtocolListener);
+ }
+
+ private void OnAsyncReadDone(IAsyncResult result)
+ {
+ try
+ {
+ _amqpChannel.EndRead(result);
+
+ bool stopping = _stopEvent.WaitOne(0, false);
+ if ( !stopping )
+ _amqpChannel.BeginRead(new AsyncCallback(OnAsyncReadDone), null);
+ } catch ( Exception e )
+ {
+ // ignore any errors during closing
+ bool stopping = _stopEvent.WaitOne(0, false);
+ if ( !stopping )
+ _protocolListener.OnException(e);
+ }
+ }
+
+ #region IProtocolDecoderOutput Members
+
+ public void Write(object message)
+ {
+ _protocolListener.OnMessage((IDataBlock)message);
+ }
+
+ #endregion
+ }
+}
+
+
diff --git a/dotnet/Qpid.Client/Client/Transport/Socket/Blocking/ByteChannel.cs b/dotnet/Qpid.Client/Client/Transport/Socket/Blocking/ByteChannel.cs
index 73575c7086..4540f01f4e 100644
--- a/dotnet/Qpid.Client/Client/Transport/Socket/Blocking/ByteChannel.cs
+++ b/dotnet/Qpid.Client/Client/Transport/Socket/Blocking/ByteChannel.cs
@@ -1,92 +1,92 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using log4net;
-using Apache.Qpid.Buffer;
-
-namespace Apache.Qpid.Client.Transport.Socket.Blocking
-{
- class ByteChannel : IByteChannel
- {
- // Warning: don't use this log for regular logging.
- private static readonly ILog _ioTraceLog = LogManager.GetLogger("TRACE.Qpid.Client.ByteChannel");
-
- private IByteChannel _lowerChannel;
-
- public ByteChannel(IByteChannel lowerChannel)
- {
- _lowerChannel = lowerChannel;
- }
-
- public ByteBuffer Read()
- {
- ByteBuffer result = _lowerChannel.Read();
-
- // TODO: Move into decorator.
- if (_ioTraceLog.IsDebugEnabled)
- {
- _ioTraceLog.Debug(String.Format("READ {0}", result));
- }
-
- return result;
- }
-
- public IAsyncResult BeginRead(AsyncCallback callback, object state)
- {
- return _lowerChannel.BeginRead(callback, state);
- }
-
- public ByteBuffer EndRead(IAsyncResult result)
- {
- ByteBuffer buffer = _lowerChannel.EndRead(result);
- if ( _ioTraceLog.IsDebugEnabled )
- {
- _ioTraceLog.Debug(String.Format("READ {0}", buffer));
- }
- return buffer;
- }
-
- public void Write(ByteBuffer buffer)
- {
- // TODO: Move into decorator.
- if (_ioTraceLog.IsDebugEnabled)
- {
- _ioTraceLog.Debug(String.Format("WRITE {0}", buffer));
- }
-
- _lowerChannel.Write(buffer);
- }
-
- public IAsyncResult BeginWrite(ByteBuffer buffer, AsyncCallback callback, object state)
- {
- if ( _ioTraceLog.IsDebugEnabled )
- {
- _ioTraceLog.Debug(String.Format("WRITE {0}", buffer));
- }
- return _lowerChannel.BeginWrite(buffer, callback, state);
- }
-
- public void EndWrite(IAsyncResult result)
- {
- _lowerChannel.EndWrite(result);
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using log4net;
+using Apache.Qpid.Buffer;
+
+namespace Apache.Qpid.Client.Transport.Socket.Blocking
+{
+ class ByteChannel : IByteChannel
+ {
+ // Warning: don't use this log for regular logging.
+ private static readonly ILog _ioTraceLog = LogManager.GetLogger("TRACE.Qpid.Client.ByteChannel");
+
+ private IByteChannel _lowerChannel;
+
+ public ByteChannel(IByteChannel lowerChannel)
+ {
+ _lowerChannel = lowerChannel;
+ }
+
+ public ByteBuffer Read()
+ {
+ ByteBuffer result = _lowerChannel.Read();
+
+ // TODO: Move into decorator.
+ if (_ioTraceLog.IsDebugEnabled)
+ {
+ _ioTraceLog.Debug(String.Format("READ {0}", result));
+ }
+
+ return result;
+ }
+
+ public IAsyncResult BeginRead(AsyncCallback callback, object state)
+ {
+ return _lowerChannel.BeginRead(callback, state);
+ }
+
+ public ByteBuffer EndRead(IAsyncResult result)
+ {
+ ByteBuffer buffer = _lowerChannel.EndRead(result);
+ if ( _ioTraceLog.IsDebugEnabled )
+ {
+ _ioTraceLog.Debug(String.Format("READ {0}", buffer));
+ }
+ return buffer;
+ }
+
+ public void Write(ByteBuffer buffer)
+ {
+ // TODO: Move into decorator.
+ if (_ioTraceLog.IsDebugEnabled)
+ {
+ _ioTraceLog.Debug(String.Format("WRITE {0}", buffer));
+ }
+
+ _lowerChannel.Write(buffer);
+ }
+
+ public IAsyncResult BeginWrite(ByteBuffer buffer, AsyncCallback callback, object state)
+ {
+ if ( _ioTraceLog.IsDebugEnabled )
+ {
+ _ioTraceLog.Debug(String.Format("WRITE {0}", buffer));
+ }
+ return _lowerChannel.BeginWrite(buffer, callback, state);
+ }
+
+ public void EndWrite(IAsyncResult result)
+ {
+ _lowerChannel.EndWrite(result);
+ }
+ }
+}
diff --git a/dotnet/Qpid.Client/Client/Transport/Socket/Blocking/ISocketConnector.cs b/dotnet/Qpid.Client/Client/Transport/Socket/Blocking/ISocketConnector.cs
index 3d5d2898cf..137fa19c0d 100644
--- a/dotnet/Qpid.Client/Client/Transport/Socket/Blocking/ISocketConnector.cs
+++ b/dotnet/Qpid.Client/Client/Transport/Socket/Blocking/ISocketConnector.cs
@@ -1,34 +1,34 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.IO;
-using Apache.Qpid.Client.Qms;
-
-namespace Apache.Qpid.Client.Transport.Socket.Blocking
-{
- interface ISocketConnector : IDisposable
- {
- string LocalEndpoint { get; }
- Stream Connect(IBrokerInfo broker);
- }
-}
-
-
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.IO;
+using Apache.Qpid.Client.Qms;
+
+namespace Apache.Qpid.Client.Transport.Socket.Blocking
+{
+ interface ISocketConnector : IDisposable
+ {
+ string LocalEndpoint { get; }
+ Stream Connect(IBrokerInfo broker);
+ }
+}
+
+
diff --git a/dotnet/Qpid.Client/Client/Transport/Socket/Blocking/SocketConnector.cs b/dotnet/Qpid.Client/Client/Transport/Socket/Blocking/SocketConnector.cs
index 83f7287e9b..b6dd8c3be1 100644
--- a/dotnet/Qpid.Client/Client/Transport/Socket/Blocking/SocketConnector.cs
+++ b/dotnet/Qpid.Client/Client/Transport/Socket/Blocking/SocketConnector.cs
@@ -1,71 +1,71 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System.IO;
-using System.Net;
-using System.Net.Sockets;
-using Apache.Qpid.Client.Qms;
-
-namespace Apache.Qpid.Client.Transport.Socket.Blocking
-{
- /// <summary>
- /// Implements a TCP connection over regular sockets.
- /// </summary>
- class SocketConnector : ISocketConnector
- {
- private MyTcpClient _tcpClient;
-
- public string LocalEndpoint
- {
- get { return _tcpClient.LocalEndpoint.ToString(); }
- }
-
- public Stream Connect(IBrokerInfo broker)
- {
- _tcpClient = new MyTcpClient(broker.Host, broker.Port);
- return _tcpClient.GetStream();
- }
-
- public void Dispose()
- {
- if ( _tcpClient != null )
- {
- _tcpClient.Close();
- _tcpClient = null;
- }
- }
-
- class MyTcpClient : TcpClient
- {
- public MyTcpClient(string host, int port)
- : base(host, port)
- {
- }
-
- public EndPoint LocalEndpoint
- {
- get { return Client.LocalEndPoint; }
- }
- }
-
- }
-}
-
-
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using Apache.Qpid.Client.Qms;
+
+namespace Apache.Qpid.Client.Transport.Socket.Blocking
+{
+ /// <summary>
+ /// Implements a TCP connection over regular sockets.
+ /// </summary>
+ class SocketConnector : ISocketConnector
+ {
+ private MyTcpClient _tcpClient;
+
+ public string LocalEndpoint
+ {
+ get { return _tcpClient.LocalEndpoint.ToString(); }
+ }
+
+ public Stream Connect(IBrokerInfo broker)
+ {
+ _tcpClient = new MyTcpClient(broker.Host, broker.Port);
+ return _tcpClient.GetStream();
+ }
+
+ public void Dispose()
+ {
+ if ( _tcpClient != null )
+ {
+ _tcpClient.Close();
+ _tcpClient = null;
+ }
+ }
+
+ class MyTcpClient : TcpClient
+ {
+ public MyTcpClient(string host, int port)
+ : base(host, port)
+ {
+ }
+
+ public EndPoint LocalEndpoint
+ {
+ get { return Client.LocalEndPoint; }
+ }
+ }
+
+ }
+}
+
+
diff --git a/dotnet/Qpid.Client/Client/Transport/Socket/Blocking/SslSocketConnector.cs b/dotnet/Qpid.Client/Client/Transport/Socket/Blocking/SslSocketConnector.cs
index 708edde48c..8436e6fc4f 100644
--- a/dotnet/Qpid.Client/Client/Transport/Socket/Blocking/SslSocketConnector.cs
+++ b/dotnet/Qpid.Client/Client/Transport/Socket/Blocking/SslSocketConnector.cs
@@ -1,107 +1,107 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System.IO;
-using System.Net;
-using log4net;
-using Apache.Qpid.Client.Qms;
-using Org.Mentalis.Security.Ssl;
-using MCertificate = Org.Mentalis.Security.Certificates.Certificate;
-using MCertificateChain = Org.Mentalis.Security.Certificates.CertificateChain;
-
-namespace Apache.Qpid.Client.Transport.Socket.Blocking
-{
- /// <summary>
- /// Implements a TLS v1.0 connection using the Mentalis.org library
- /// </summary>
- /// <remarks>
- /// It would've been easier to implement this at the StreamFilter
- /// level, but unfortunately the Mentalis library doesn't support
- /// a passthrough SSL stream class and is tied directly
- /// to socket-like classes.
- /// </remarks>
- class SslSocketConnector : ISocketConnector
- {
- private static ILog _logger = LogManager.GetLogger(typeof(SslSocketConnector));
- private MyTcpClient _tcpClient;
-
- public string LocalEndpoint
- {
- get { return _tcpClient.LocalEndpoint.ToString(); }
- }
-
- public Stream Connect(IBrokerInfo broker)
- {
- MCertificate cert = GetClientCert(broker);
- SecurityOptions options = new SecurityOptions(
- SecureProtocol.Tls1, cert, ConnectionEnd.Client
- );
- if ( broker.SslOptions != null
- && broker.SslOptions.IgnoreValidationErrors )
- {
- _logger.Warn("Ignoring any certificate validation errors during SSL handshake...");
- options.VerificationType = CredentialVerification.None;
- }
-
- _tcpClient = new MyTcpClient(broker.Host, broker.Port, options);
- return _tcpClient.GetStream();
- }
-
- public void Dispose()
- {
- if ( _tcpClient != null )
- {
- _tcpClient.Close();
- _tcpClient = null;
- }
- }
-
- private static MCertificate GetClientCert(IBrokerInfo broker)
- {
- // if a client certificate is configured,
- // use that to enable mutual authentication
- MCertificate cert = null;
- if ( broker.SslOptions != null
- && broker.SslOptions.ClientCertificate != null )
- {
- cert = MCertificate.CreateFromX509Certificate(
- broker.SslOptions.ClientCertificate
- );
- _logger.DebugFormat("Using Client Certificate for SSL '{0}'", cert.ToString(true));
- }
- return cert;
- }
-
- class MyTcpClient : SecureTcpClient
- {
- public MyTcpClient(string host, int port, SecurityOptions options)
- : base(host, port, options)
- {
- }
-
- public EndPoint LocalEndpoint
- {
- get { return Client.LocalEndPoint; }
- }
-
- }
-
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System.IO;
+using System.Net;
+using log4net;
+using Apache.Qpid.Client.Qms;
+using Org.Mentalis.Security.Ssl;
+using MCertificate = Org.Mentalis.Security.Certificates.Certificate;
+using MCertificateChain = Org.Mentalis.Security.Certificates.CertificateChain;
+
+namespace Apache.Qpid.Client.Transport.Socket.Blocking
+{
+ /// <summary>
+ /// Implements a TLS v1.0 connection using the Mentalis.org library
+ /// </summary>
+ /// <remarks>
+ /// It would've been easier to implement this at the StreamFilter
+ /// level, but unfortunately the Mentalis library doesn't support
+ /// a passthrough SSL stream class and is tied directly
+ /// to socket-like classes.
+ /// </remarks>
+ class SslSocketConnector : ISocketConnector
+ {
+ private static ILog _logger = LogManager.GetLogger(typeof(SslSocketConnector));
+ private MyTcpClient _tcpClient;
+
+ public string LocalEndpoint
+ {
+ get { return _tcpClient.LocalEndpoint.ToString(); }
+ }
+
+ public Stream Connect(IBrokerInfo broker)
+ {
+ MCertificate cert = GetClientCert(broker);
+ SecurityOptions options = new SecurityOptions(
+ SecureProtocol.Tls1, cert, ConnectionEnd.Client
+ );
+ if ( broker.SslOptions != null
+ && broker.SslOptions.IgnoreValidationErrors )
+ {
+ _logger.Warn("Ignoring any certificate validation errors during SSL handshake...");
+ options.VerificationType = CredentialVerification.None;
+ }
+
+ _tcpClient = new MyTcpClient(broker.Host, broker.Port, options);
+ return _tcpClient.GetStream();
+ }
+
+ public void Dispose()
+ {
+ if ( _tcpClient != null )
+ {
+ _tcpClient.Close();
+ _tcpClient = null;
+ }
+ }
+
+ private static MCertificate GetClientCert(IBrokerInfo broker)
+ {
+ // if a client certificate is configured,
+ // use that to enable mutual authentication
+ MCertificate cert = null;
+ if ( broker.SslOptions != null
+ && broker.SslOptions.ClientCertificate != null )
+ {
+ cert = MCertificate.CreateFromX509Certificate(
+ broker.SslOptions.ClientCertificate
+ );
+ _logger.DebugFormat("Using Client Certificate for SSL '{0}'", cert.ToString(true));
+ }
+ return cert;
+ }
+
+ class MyTcpClient : SecureTcpClient
+ {
+ public MyTcpClient(string host, int port, SecurityOptions options)
+ : base(host, port, options)
+ {
+ }
+
+ public EndPoint LocalEndpoint
+ {
+ get { return Client.LocalEndPoint; }
+ }
+
+ }
+
+ }
+}
diff --git a/dotnet/Qpid.Client/Client/Util/FlowControlQueue.cs b/dotnet/Qpid.Client/Client/Util/FlowControlQueue.cs
index 87bb2a2859..a06de9eac8 100644
--- a/dotnet/Qpid.Client/Client/Util/FlowControlQueue.cs
+++ b/dotnet/Qpid.Client/Client/Util/FlowControlQueue.cs
@@ -1,98 +1,98 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Collections;
-using System.Text;
-using System.Threading;
-using Apache.Qpid.Collections;
-using Apache.Qpid.Common;
-
-namespace Apache.Qpid.Client.Util
-{
- internal delegate void ThresholdMethod(int currentCount);
-
- /// <summary>
- /// Basic bounded queue used to implement prefetching.
- /// Notice we do the callbacks here asynchronously to
- /// avoid adding more complexity to the channel impl.
- /// </summary>
- internal class FlowControlQueue
- {
- private BlockingQueue _queue = new LinkedBlockingQueue();
- private int _itemCount;
- private int _lowerBound;
- private int _upperBound;
- private ThresholdMethod _underThreshold;
- private ThresholdMethod _overThreshold;
-
- public FlowControlQueue(
- int lowerBound,
- int upperBound,
- ThresholdMethod underThreshold,
- ThresholdMethod overThreshold
- )
- {
- _lowerBound = lowerBound;
- _upperBound = upperBound;
- _underThreshold = underThreshold;
- _overThreshold = overThreshold;
- }
-
- public void Enqueue(object item)
- {
- _queue.EnqueueBlocking(item);
- int count = Interlocked.Increment(ref _itemCount);
- if ( _overThreshold != null )
- {
- if ( count == _upperBound )
- {
- _overThreshold.BeginInvoke(
- count, new AsyncCallback(OnAsyncCallEnd),
- _overThreshold
- );
- }
- }
- }
-
- public object Dequeue()
- {
- object item = _queue.DequeueBlocking();
- int count = Interlocked.Decrement(ref _itemCount);
- if ( _underThreshold != null )
- {
- if ( count == _lowerBound )
- {
- _underThreshold.BeginInvoke(
- count, new AsyncCallback(OnAsyncCallEnd),
- _underThreshold
- );
- }
- }
- return item;
- }
-
- private void OnAsyncCallEnd(IAsyncResult res)
- {
- ThresholdMethod method = (ThresholdMethod)res.AsyncState;
- method.EndInvoke(res);
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Collections;
+using System.Text;
+using System.Threading;
+using Apache.Qpid.Collections;
+using Apache.Qpid.Common;
+
+namespace Apache.Qpid.Client.Util
+{
+ internal delegate void ThresholdMethod(int currentCount);
+
+ /// <summary>
+ /// Basic bounded queue used to implement prefetching.
+ /// Notice we do the callbacks here asynchronously to
+ /// avoid adding more complexity to the channel impl.
+ /// </summary>
+ internal class FlowControlQueue
+ {
+ private BlockingQueue _queue = new LinkedBlockingQueue();
+ private int _itemCount;
+ private int _lowerBound;
+ private int _upperBound;
+ private ThresholdMethod _underThreshold;
+ private ThresholdMethod _overThreshold;
+
+ public FlowControlQueue(
+ int lowerBound,
+ int upperBound,
+ ThresholdMethod underThreshold,
+ ThresholdMethod overThreshold
+ )
+ {
+ _lowerBound = lowerBound;
+ _upperBound = upperBound;
+ _underThreshold = underThreshold;
+ _overThreshold = overThreshold;
+ }
+
+ public void Enqueue(object item)
+ {
+ _queue.EnqueueBlocking(item);
+ int count = Interlocked.Increment(ref _itemCount);
+ if ( _overThreshold != null )
+ {
+ if ( count == _upperBound )
+ {
+ _overThreshold.BeginInvoke(
+ count, new AsyncCallback(OnAsyncCallEnd),
+ _overThreshold
+ );
+ }
+ }
+ }
+
+ public object Dequeue()
+ {
+ object item = _queue.DequeueBlocking();
+ int count = Interlocked.Decrement(ref _itemCount);
+ if ( _underThreshold != null )
+ {
+ if ( count == _lowerBound )
+ {
+ _underThreshold.BeginInvoke(
+ count, new AsyncCallback(OnAsyncCallEnd),
+ _underThreshold
+ );
+ }
+ }
+ return item;
+ }
+
+ private void OnAsyncCallEnd(IAsyncResult res)
+ {
+ ThresholdMethod method = (ThresholdMethod)res.AsyncState;
+ method.EndInvoke(res);
+ }
+ }
+}
diff --git a/dotnet/Qpid.Client/Properties/AssemblyInfo.cs b/dotnet/Qpid.Client/Properties/AssemblyInfo.cs
index 4343c30bf5..670a4f90b2 100644
--- a/dotnet/Qpid.Client/Properties/AssemblyInfo.cs
+++ b/dotnet/Qpid.Client/Properties/AssemblyInfo.cs
@@ -49,4 +49,4 @@ using System.Runtime.InteropServices;
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
-[assembly: AssemblyVersion("2.1.0.0")]
+[assembly: AssemblyVersion("0.5.0.0")]
diff --git a/dotnet/Qpid.Client/Qpid.Client.csproj b/dotnet/Qpid.Client/Qpid.Client.csproj
index 6f4b87773b..303f885149 100644
--- a/dotnet/Qpid.Client/Qpid.Client.csproj
+++ b/dotnet/Qpid.Client/Qpid.Client.csproj
@@ -1,4 +1,25 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@@ -9,6 +30,11 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Apache.Qpid.Client</RootNamespace>
<AssemblyName>Apache.Qpid.Client</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -41,94 +67,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
- <Compile Include="Client\AmqBrokerInfo.cs" />
- <Compile Include="Client\AMQConnection.cs" />
- <Compile Include="Client\AMQConnectionException.cs" />
- <Compile Include="Client\AMQDestination.cs" />
- <Compile Include="Client\AmqChannel.cs" />
- <Compile Include="Client\AMQAuthenticationException.cs" />
- <Compile Include="Client\AMQNoConsumersException.cs" />
- <Compile Include="Client\AMQNoRouteException.cs" />
- <Compile Include="Client\Configuration\AuthenticationConfigurationSectionHandler.cs" />
- <Compile Include="Client\Handler\QueueDeleteOkMethodHandler.cs" />
- <Compile Include="Client\Handler\QueuePurgeOkMethodHandler.cs" />
- <Compile Include="Client\Protocol\DefaultTimeouts.cs" />
- <Compile Include="Client\SslOptions.cs" />
- <Compile Include="Client\Message\QpidHeaders.cs" />
- <Compile Include="Client\QpidConnectionInfo.cs" />
- <Compile Include="Client\BasicMessageConsumer.cs" />
- <Compile Include="Client\BasicMessageProducer.cs" />
- <Compile Include="Client\Closeable.cs" />
- <Compile Include="Client\ConnectionTuneParameters.cs" />
- <Compile Include="Client\Failover\FailoverException.cs" />
- <Compile Include="Client\Failover\FailoverHandler.cs" />
- <Compile Include="Client\Failover\FailoverState.cs" />
- <Compile Include="Client\Failover\FailoverSupport.cs" />
- <Compile Include="Client\Handler\BasicDeliverMethodHandler.cs" />
- <Compile Include="Client\Handler\BasicReturnMethodHandler.cs" />
- <Compile Include="Client\Handler\ChannelCloseMethodHandler.cs" />
- <Compile Include="Client\Handler\ConnectionCloseMethodHandler.cs" />
- <Compile Include="Client\Handler\ConnectionCloseOkHandler.cs" />
- <Compile Include="Client\Handler\ConnectionOpenOkMethodHandler.cs" />
- <Compile Include="Client\Handler\ConnectionRedirectMethodHandler.cs" />
- <Compile Include="Client\Handler\ConnectionSecureMethodHandler.cs" />
- <Compile Include="Client\Handler\ConnectionStartMethodHandler.cs" />
- <Compile Include="Client\Handler\ConnectionTuneMethodHandler.cs" />
- <Compile Include="Client\Message\AbstractQmsMessage.cs" />
- <Compile Include="Client\Message\AMQMessage.cs" />
- <Compile Include="Client\Message\AMQMessageFactory.cs" />
- <Compile Include="Client\Message\IMessageFactory.cs" />
- <Compile Include="Client\Message\MessageFactoryRegistry.cs" />
- <Compile Include="Client\Message\UnexpectedBodyReceivedException.cs" />
- <Compile Include="Client\Message\UnprocessedMessage.cs" />
- <Compile Include="Client\Message\QpidBytesMessage.cs" />
- <Compile Include="Client\Message\QpidBytesMessageFactory.cs" />
- <Compile Include="Client\Message\QpidTextMessage.cs" />
- <Compile Include="Client\Message\QpidTextMessageFactory.cs" />
- <Compile Include="Client\Protocol\AMQMethodEvent.cs" />
- <Compile Include="Client\Protocol\AMQProtocolListener.cs" />
- <Compile Include="Client\Protocol\AMQProtocolSession.cs" />
- <Compile Include="Client\Protocol\Listener\BlockingMethodFrameListener.cs" />
- <Compile Include="Client\Protocol\Listener\IAMQMethodListener.cs" />
- <Compile Include="Client\Protocol\IConnectionCloser.cs" />
- <Compile Include="Client\Protocol\ProtocolWriter.cs" />
- <Compile Include="Client\Protocol\IProtocolListener.cs" />
- <Compile Include="Client\Security\CallbackHandlerRegistry.cs" />
- <Compile Include="Client\Security\IAMQCallbackHandler.cs" />
- <Compile Include="Client\Security\UsernamePasswordCallbackHandler.cs" />
- <Compile Include="Client\State\AMQState.cs" />
- <Compile Include="Client\State\AMQStateChangedEvent.cs" />
- <Compile Include="Client\State\AMQStateManager.cs" />
- <Compile Include="Client\State\IAMQStateListener.cs" />
- <Compile Include="Client\State\IllegalStateTransitionException.cs" />
- <Compile Include="Client\State\IStateAwareMethodListener.cs" />
- <Compile Include="Client\State\IStateListener.cs" />
- <Compile Include="Client\Protocol\Listener\SpecificMethodFrameListener.cs" />
- <Compile Include="Client\State\StateWaiter.cs" />
- <Compile Include="Client\Transport\AmqpChannel.cs" />
- <Compile Include="Client\Transport\AMQProtocolProvider.cs" />
- <Compile Include="Client\Transport\IStreamFilter.cs" />
- <Compile Include="Client\Transport\IoHandler.cs" />
- <Compile Include="Client\Transport\IByteChannel.cs" />
- <Compile Include="Client\Transport\IProtocolChannel.cs" />
- <Compile Include="Client\Transport\IProtocolWriter.cs" />
- <Compile Include="Client\Transport\ITransport.cs" />
- <Compile Include="Client\Transport\ProtocolDecoderOutput.cs" />
- <Compile Include="Client\Transport\SingleProtocolEncoderOutput.cs" />
- <Compile Include="Client\Transport\Socket\Blocking\BlockingSocketTransport.cs" />
- <Compile Include="Client\Transport\Socket\Blocking\ByteChannel.cs" />
- <Compile Include="Client\Transport\Socket\Blocking\SslSocketConnector.cs" />
- <Compile Include="Client\Transport\Socket\Blocking\SocketConnector.cs" />
- <Compile Include="Client\Transport\Socket\Blocking\ISocketConnector.cs" />
- <Compile Include="Client\Util\FlowControlQueue.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="qms\BrokerInfo.cs" />
- <Compile Include="qms\ConnectionInfo.cs" />
- <Compile Include="qms\FailoverPolicy.cs" />
- <Compile Include="qms\failover\FailoverMethod.cs" />
- <Compile Include="qms\failover\FailoverRoundRobin.cs" />
- <Compile Include="qms\failover\FailoverSingleServer.cs" />
- <Compile Include="qms\UrlSyntaxException.cs" />
+ <Compile Include="**\*.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Qpid.Buffer\Qpid.Buffer.csproj">
@@ -160,4 +99,4 @@
<Target Name="AfterBuild">
</Target>
-->
-</Project> \ No newline at end of file
+</Project>
diff --git a/dotnet/Qpid.Client/default.build b/dotnet/Qpid.Client/default.build
index 14e457203e..9a0ec2ea6d 100644
--- a/dotnet/Qpid.Client/default.build
+++ b/dotnet/Qpid.Client/default.build
@@ -1,4 +1,25 @@
<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
<project name="Apache.Qpid.Client" default="build">
<!--
Properties that come from master build file
diff --git a/dotnet/Qpid.Codec/Properties/AssemblyInfo.cs b/dotnet/Qpid.Codec/Properties/AssemblyInfo.cs
index 4729dc6ab8..5261a62ec5 100644
--- a/dotnet/Qpid.Codec/Properties/AssemblyInfo.cs
+++ b/dotnet/Qpid.Codec/Properties/AssemblyInfo.cs
@@ -49,5 +49,5 @@ using System.Runtime.InteropServices;
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
-[assembly: AssemblyVersion("2.1.0.0")]
+[assembly: AssemblyVersion("0.5.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/Qpid.Codec/Qpid.Codec.csproj b/dotnet/Qpid.Codec/Qpid.Codec.csproj
index 33677382e0..a0217cffa3 100644
--- a/dotnet/Qpid.Codec/Qpid.Codec.csproj
+++ b/dotnet/Qpid.Codec/Qpid.Codec.csproj
@@ -1,4 +1,25 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@@ -9,6 +30,11 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Apache.Qpid.Codec</RootNamespace>
<AssemblyName>Apache.Qpid.Codec</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -37,24 +63,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
- <Compile Include="CumulativeProtocolDecoder.cs" />
- <Compile Include="Demux\DemuxingProtocolCodecFactory.cs" />
- <Compile Include="Demux\IMessageDecoder.cs" />
- <Compile Include="Demux\IMessageDecoderFactory.cs" />
- <Compile Include="Demux\IMessageEncoder.cs" />
- <Compile Include="Demux\IMessageEncoderFactory.cs" />
- <Compile Include="Demux\MessageDecoderResult.cs" />
- <Compile Include="IProtocolCodecFactory.cs" />
- <Compile Include="IProtocolDecoder.cs" />
- <Compile Include="IProtocolDecoderOutput.cs" />
- <Compile Include="IProtocolEncoder.cs" />
- <Compile Include="IProtocolEncoderOutput.cs" />
- <Compile Include="ProtocolCodecException.cs" />
- <Compile Include="ProtocolDecoderException.cs" />
- <Compile Include="ProtocolEncoderException.cs" />
- <Compile Include="Support\SimpleProtocolDecoderOutput.cs" />
- <Compile Include="Support\SimpleProtocolEncoderOutput.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="**\*.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Qpid.Buffer\Qpid.Buffer.csproj">
@@ -70,4 +79,4 @@
<Target Name="AfterBuild">
</Target>
-->
-</Project> \ No newline at end of file
+</Project>
diff --git a/dotnet/Qpid.Codec/default.build b/dotnet/Qpid.Codec/default.build
index db9e8d1166..dd59df7d6a 100644
--- a/dotnet/Qpid.Codec/default.build
+++ b/dotnet/Qpid.Codec/default.build
@@ -1,26 +1,47 @@
-<?xml version="1.0"?>
-<project name="Apache.Qpid.Codec" default="build">
- <!--
- Properties that come from master build file
- - build.dir: root directory for build
- - build.debug: true if building debug release
- - build.defines: variables to define during build
- -->
-
- <target name="build">
- <csc target="library"
- define="${build.defines}"
- debug="${build.debug}"
- output="${build.dir}/${project::get-name()}.dll">
-
- <sources>
- <include name="**/*.cs" />
- </sources>
- <references>
- <include name="${build.dir}/log4net.dll" />
- <include name="${build.dir}/Apache.Qpid.Buffer.dll" />
- </references>
- </csc>
- </target>
-</project>
-
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="Apache.Qpid.Codec" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="library"
+ define="${build.defines}"
+ debug="${build.debug}"
+ output="${build.dir}/${project::get-name()}.dll">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ <include name="${build.dir}/log4net.dll" />
+ <include name="${build.dir}/Apache.Qpid.Buffer.dll" />
+ </references>
+ </csc>
+ </target>
+</project>
+
diff --git a/dotnet/Qpid.Common.Tests/Properties/AssemblyInfo.cs b/dotnet/Qpid.Common.Tests/Properties/AssemblyInfo.cs
index 96a94b6498..2516a73035 100644
--- a/dotnet/Qpid.Common.Tests/Properties/AssemblyInfo.cs
+++ b/dotnet/Qpid.Common.Tests/Properties/AssemblyInfo.cs
@@ -1,3 +1,24 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
@@ -29,5 +50,5 @@ using System.Runtime.InteropServices;
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
-[assembly: AssemblyVersion("2.1.0.0")]
+[assembly: AssemblyVersion("0.5.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/Qpid.Common.Tests/Qpid.Common.Tests.csproj b/dotnet/Qpid.Common.Tests/Qpid.Common.Tests.csproj
index 766bd62c97..c99217cc51 100644
--- a/dotnet/Qpid.Common.Tests/Qpid.Common.Tests.csproj
+++ b/dotnet/Qpid.Common.Tests/Qpid.Common.Tests.csproj
@@ -1,4 +1,25 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@@ -9,6 +30,11 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Apache.Qpid.Tests</RootNamespace>
<AssemblyName>Apache.Qpid.Common.Tests</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -38,11 +64,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
- <Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="Qpid\Collections\TestConsumerProducerQueue.cs" />
- <Compile Include="Qpid\Collections\TestLinkedHashtable.cs" />
- <Compile Include="Qpid\Framing\TestEncodingUtils.cs" />
- <Compile Include="Qpid\Framing\TestAMQType.cs" />
+ <Compile Include="**\*.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Qpid.Buffer\Qpid.Buffer.csproj">
@@ -62,4 +84,4 @@
<Target Name="AfterBuild">
</Target>
-->
-</Project> \ No newline at end of file
+</Project>
diff --git a/dotnet/Qpid.Common.Tests/Qpid/Collections/TestConsumerProducerQueue.cs b/dotnet/Qpid.Common.Tests/Qpid/Collections/TestConsumerProducerQueue.cs
index 03ed999999..3e19508bac 100644
--- a/dotnet/Qpid.Common.Tests/Qpid/Collections/TestConsumerProducerQueue.cs
+++ b/dotnet/Qpid.Common.Tests/Qpid/Collections/TestConsumerProducerQueue.cs
@@ -1,85 +1,85 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Collections;
-using System.Text;
-using System.Threading;
-using NUnit.Framework;
-using Apache.Qpid.Collections;
-
-namespace Apache.Qpid.Collections.Tests
-{
- [TestFixture]
- public class TestConsumerProducerQueue
- {
- private ConsumerProducerQueue _queue;
-
- [SetUp]
- public void SetUp()
- {
- _queue = new ConsumerProducerQueue();
- }
-
- [Test]
- public void CanDequeueWithInifiniteWait()
- {
- Thread producer = new Thread(new ThreadStart(ProduceFive));
- producer.Start();
- for ( int i = 0; i < 5; i++ )
- {
- object item = _queue.Dequeue();
- Assert.IsNotNull(item);
- }
- }
-
- [Test]
- public void ReturnsNullOnDequeueTimeout()
- {
- // queue is empty
- Assert.IsNull(_queue.Dequeue(500));
- }
-
- [Test]
- public void DequeueTillEmpty()
- {
- _queue.Enqueue(1);
- _queue.Enqueue(2);
- _queue.Enqueue(3);
- Assert.AreEqual(1, _queue.Dequeue());
- Assert.AreEqual(2, _queue.Dequeue());
- Assert.AreEqual(3, _queue.Dequeue());
- // no messages in queue, will timeout
- Assert.IsNull(_queue.Dequeue(500));
- }
-
-
- private void ProduceFive()
- {
- Thread.Sleep(1000);
- _queue.Enqueue("test item 1");
- _queue.Enqueue("test item 2");
- _queue.Enqueue("test item 3");
- Thread.Sleep(0);
- _queue.Enqueue("test item 4");
- _queue.Enqueue("test item 5");
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Collections;
+using System.Text;
+using System.Threading;
+using NUnit.Framework;
+using Apache.Qpid.Collections;
+
+namespace Apache.Qpid.Collections.Tests
+{
+ [TestFixture]
+ public class TestConsumerProducerQueue
+ {
+ private ConsumerProducerQueue _queue;
+
+ [SetUp]
+ public void SetUp()
+ {
+ _queue = new ConsumerProducerQueue();
+ }
+
+ [Test]
+ public void CanDequeueWithInifiniteWait()
+ {
+ Thread producer = new Thread(new ThreadStart(ProduceFive));
+ producer.Start();
+ for ( int i = 0; i < 5; i++ )
+ {
+ object item = _queue.Dequeue();
+ Assert.IsNotNull(item);
+ }
+ }
+
+ [Test]
+ public void ReturnsNullOnDequeueTimeout()
+ {
+ // queue is empty
+ Assert.IsNull(_queue.Dequeue(500));
+ }
+
+ [Test]
+ public void DequeueTillEmpty()
+ {
+ _queue.Enqueue(1);
+ _queue.Enqueue(2);
+ _queue.Enqueue(3);
+ Assert.AreEqual(1, _queue.Dequeue());
+ Assert.AreEqual(2, _queue.Dequeue());
+ Assert.AreEqual(3, _queue.Dequeue());
+ // no messages in queue, will timeout
+ Assert.IsNull(_queue.Dequeue(500));
+ }
+
+
+ private void ProduceFive()
+ {
+ Thread.Sleep(1000);
+ _queue.Enqueue("test item 1");
+ _queue.Enqueue("test item 2");
+ _queue.Enqueue("test item 3");
+ Thread.Sleep(0);
+ _queue.Enqueue("test item 4");
+ _queue.Enqueue("test item 5");
+ }
+ }
+}
diff --git a/dotnet/Qpid.Common.Tests/Qpid/Framing/TestAMQType.cs b/dotnet/Qpid.Common.Tests/Qpid/Framing/TestAMQType.cs
index ab4cb4409c..23cb71c9f8 100644
--- a/dotnet/Qpid.Common.Tests/Qpid/Framing/TestAMQType.cs
+++ b/dotnet/Qpid.Common.Tests/Qpid/Framing/TestAMQType.cs
@@ -1,270 +1,270 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using NUnit.Framework;
-using Apache.Qpid.Buffer;
-using Apache.Qpid.Framing;
-
-namespace Apache.Qpid.Framing.Tests
-{
- [TestFixture]
- public class TestAMQType
- {
-
- #region LONG_STRING tests
- [Test]
- public void LONG_STRING_ReadWrite()
- {
- AMQType type = AMQType.LONG_STRING;
- ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
- const string VALUE = "simple string 1";
-
- type.WriteToBuffer(VALUE, buffer);
- buffer.Flip();
- buffer.Rewind();
- AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
- Assert.AreEqual(VALUE, value.Value);
- }
- #endregion // LONG_STRING tests
-
- #region UINT32 tests
- [Test]
- public void UINT32_CanGetEncodingSize()
- {
- AMQType type = AMQType.UINT32;
- Assert.AreEqual(4, type.GetEncodingSize(1234443));
- }
-
- [Test]
- public void UINT32_ToNativeValue()
- {
- AMQType type = AMQType.UINT32;
- Assert.AreEqual(1, type.ToNativeValue(1));
- Assert.AreEqual(1, type.ToNativeValue((short)1));
- Assert.AreEqual(1, type.ToNativeValue((byte)1));
- Assert.AreEqual(1, type.ToNativeValue("1"));
-
- try
- {
- Assert.AreEqual(1, type.ToNativeValue("adasdads"));
- Assert.Fail("Invalid format allowed");
- } catch ( FormatException )
- {
- }
- }
-
- [Test]
- public void UINT32_ReadWrite()
- {
- AMQType type = AMQType.UINT32;
- ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
- const uint VALUE = 0xFFEEDDCC;
-
- type.WriteToBuffer(VALUE, buffer);
- buffer.Flip();
- buffer.Rewind();
- AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
- Assert.AreEqual(VALUE, value.Value);
- }
- #endregion // UINT32 Tests
-
- #region VOID Tests
- [Test]
- public void VOID_CanGetEncodingSize()
- {
- AMQType type = AMQType.VOID;
- Assert.AreEqual(0, type.GetEncodingSize(null));
- }
-
- [Test]
- public void VOID_ToNativeValue()
- {
- AMQType type = AMQType.VOID;
- Assert.IsNull(type.ToNativeValue(null));
-
- try
- {
- type.ToNativeValue("asdasd");
- Assert.Fail("converted invalid value");
- } catch (FormatException)
- {
- }
- }
-
- [Test]
- public void VOID_ReadWrite()
- {
- AMQType type = AMQType.VOID;
- ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
-
- type.WriteToBuffer(null, buffer);
- buffer.Flip();
- buffer.Rewind();
- AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
- Assert.AreEqual(null, value.Value);
- }
-
- #endregion // VOID Tests
-
- #region BOOLEAN Tests
- [Test]
- public void BOOLEAN_CanGetEncodingSize()
- {
- AMQType type = AMQType.BOOLEAN;
- Assert.AreEqual(1, type.GetEncodingSize(true));
- }
-
- [Test]
- public void BOOLEAN_ToNativeValue()
- {
- AMQType type = AMQType.BOOLEAN;
- Assert.AreEqual(true, type.ToNativeValue(true));
- Assert.AreEqual(false, type.ToNativeValue("false"));
-
- try
- {
- type.ToNativeValue("asdasd");
- Assert.Fail("converted invalid value");
- } catch ( FormatException )
- {
- }
- }
-
- [Test]
- public void BOOLEAN_ReadWrite()
- {
- AMQType type = AMQType.BOOLEAN;
- ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
-
- type.WriteToBuffer(true, buffer);
- buffer.Flip();
- buffer.Rewind();
- AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
- Assert.AreEqual(true, value.Value);
- }
- #endregion // BOOLEAN Tests
-
- #region INT16 tests
- [Test]
- public void INT16_ReadWrite()
- {
- AMQType type = AMQType.INT16;
- ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
- const short VALUE = -32765;
-
- type.WriteToBuffer(VALUE, buffer);
- buffer.Flip();
- buffer.Rewind();
- AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
- Assert.AreEqual(VALUE, value.Value);
- }
- //public void UINT16_ReadWrite()
- //{
- // AMQType type = AMQType.UINT16;
- // ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
- // const ushort VALUE = 64321;
-
- // type.WriteToBuffer(VALUE, buffer);
- // buffer.Flip();
- // buffer.Rewind();
- // AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
- // Assert.AreEqual(VALUE, value.Value);
- //}
- #endregion // INT16 Tests
-
- #region INT32 tests
- [Test]
- public void INT32_ReadWrite()
- {
- AMQType type = AMQType.INT32;
- ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
- const int VALUE = -39273563;
-
- type.WriteToBuffer(VALUE, buffer);
- buffer.Flip();
- buffer.Rewind();
- AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
- Assert.AreEqual(VALUE, value.Value);
- }
- #endregion // INT32 Tests
-
- #region INT64 tests
- [Test]
- public void INT64_ReadWrite()
- {
- AMQType type = AMQType.INT64;
- ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
- const long VALUE = -(2^43+1233123);
-
- type.WriteToBuffer(VALUE, buffer);
- buffer.Flip();
- buffer.Rewind();
- AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
- Assert.AreEqual(VALUE, value.Value);
- }
- [Test]
- public void UINT64_ReadWrite()
- {
- AMQType type = AMQType.UINT64;
- ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
- const ulong VALUE = (2 ^ 61 + 1233123);
-
- type.WriteToBuffer(VALUE, buffer);
- buffer.Flip();
- buffer.Rewind();
- AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
- Assert.AreEqual(VALUE, value.Value);
- }
- #endregion // INT64 Tests
-
- #region FLOAT tests
- [Test]
- public void FLOAT_ReadWrite()
- {
- AMQType type = AMQType.FLOAT;
- ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
- const float VALUE = 1.2345000E-035f;
-
- type.WriteToBuffer(VALUE, buffer);
- buffer.Flip();
- buffer.Rewind();
- AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
- Assert.AreEqual(VALUE, value.Value);
- }
- #endregion // FLOAT Tests
-
- #region DOUBLE tests
- [Test]
- public void DOUBLE_ReadWrite()
- {
- AMQType type = AMQType.DOUBLE;
- ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
- const double VALUE = 1.2345000E-045;
-
- type.WriteToBuffer(VALUE, buffer);
- buffer.Flip();
- buffer.Rewind();
- AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
- Assert.AreEqual(VALUE, value.Value);
- }
- #endregion // FLOAT Tests
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using NUnit.Framework;
+using Apache.Qpid.Buffer;
+using Apache.Qpid.Framing;
+
+namespace Apache.Qpid.Framing.Tests
+{
+ [TestFixture]
+ public class TestAMQType
+ {
+
+ #region LONG_STRING tests
+ [Test]
+ public void LONG_STRING_ReadWrite()
+ {
+ AMQType type = AMQType.LONG_STRING;
+ ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
+ const string VALUE = "simple string 1";
+
+ type.WriteToBuffer(VALUE, buffer);
+ buffer.Flip();
+ buffer.Rewind();
+ AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ Assert.AreEqual(VALUE, value.Value);
+ }
+ #endregion // LONG_STRING tests
+
+ #region UINT32 tests
+ [Test]
+ public void UINT32_CanGetEncodingSize()
+ {
+ AMQType type = AMQType.UINT32;
+ Assert.AreEqual(4, type.GetEncodingSize(1234443));
+ }
+
+ [Test]
+ public void UINT32_ToNativeValue()
+ {
+ AMQType type = AMQType.UINT32;
+ Assert.AreEqual(1, type.ToNativeValue(1));
+ Assert.AreEqual(1, type.ToNativeValue((short)1));
+ Assert.AreEqual(1, type.ToNativeValue((byte)1));
+ Assert.AreEqual(1, type.ToNativeValue("1"));
+
+ try
+ {
+ Assert.AreEqual(1, type.ToNativeValue("adasdads"));
+ Assert.Fail("Invalid format allowed");
+ } catch ( FormatException )
+ {
+ }
+ }
+
+ [Test]
+ public void UINT32_ReadWrite()
+ {
+ AMQType type = AMQType.UINT32;
+ ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
+ const uint VALUE = 0xFFEEDDCC;
+
+ type.WriteToBuffer(VALUE, buffer);
+ buffer.Flip();
+ buffer.Rewind();
+ AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ Assert.AreEqual(VALUE, value.Value);
+ }
+ #endregion // UINT32 Tests
+
+ #region VOID Tests
+ [Test]
+ public void VOID_CanGetEncodingSize()
+ {
+ AMQType type = AMQType.VOID;
+ Assert.AreEqual(0, type.GetEncodingSize(null));
+ }
+
+ [Test]
+ public void VOID_ToNativeValue()
+ {
+ AMQType type = AMQType.VOID;
+ Assert.IsNull(type.ToNativeValue(null));
+
+ try
+ {
+ type.ToNativeValue("asdasd");
+ Assert.Fail("converted invalid value");
+ } catch (FormatException)
+ {
+ }
+ }
+
+ [Test]
+ public void VOID_ReadWrite()
+ {
+ AMQType type = AMQType.VOID;
+ ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
+
+ type.WriteToBuffer(null, buffer);
+ buffer.Flip();
+ buffer.Rewind();
+ AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ Assert.AreEqual(null, value.Value);
+ }
+
+ #endregion // VOID Tests
+
+ #region BOOLEAN Tests
+ [Test]
+ public void BOOLEAN_CanGetEncodingSize()
+ {
+ AMQType type = AMQType.BOOLEAN;
+ Assert.AreEqual(1, type.GetEncodingSize(true));
+ }
+
+ [Test]
+ public void BOOLEAN_ToNativeValue()
+ {
+ AMQType type = AMQType.BOOLEAN;
+ Assert.AreEqual(true, type.ToNativeValue(true));
+ Assert.AreEqual(false, type.ToNativeValue("false"));
+
+ try
+ {
+ type.ToNativeValue("asdasd");
+ Assert.Fail("converted invalid value");
+ } catch ( FormatException )
+ {
+ }
+ }
+
+ [Test]
+ public void BOOLEAN_ReadWrite()
+ {
+ AMQType type = AMQType.BOOLEAN;
+ ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
+
+ type.WriteToBuffer(true, buffer);
+ buffer.Flip();
+ buffer.Rewind();
+ AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ Assert.AreEqual(true, value.Value);
+ }
+ #endregion // BOOLEAN Tests
+
+ #region INT16 tests
+ [Test]
+ public void INT16_ReadWrite()
+ {
+ AMQType type = AMQType.INT16;
+ ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
+ const short VALUE = -32765;
+
+ type.WriteToBuffer(VALUE, buffer);
+ buffer.Flip();
+ buffer.Rewind();
+ AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ Assert.AreEqual(VALUE, value.Value);
+ }
+ //public void UINT16_ReadWrite()
+ //{
+ // AMQType type = AMQType.UINT16;
+ // ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
+ // const ushort VALUE = 64321;
+
+ // type.WriteToBuffer(VALUE, buffer);
+ // buffer.Flip();
+ // buffer.Rewind();
+ // AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ // Assert.AreEqual(VALUE, value.Value);
+ //}
+ #endregion // INT16 Tests
+
+ #region INT32 tests
+ [Test]
+ public void INT32_ReadWrite()
+ {
+ AMQType type = AMQType.INT32;
+ ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
+ const int VALUE = -39273563;
+
+ type.WriteToBuffer(VALUE, buffer);
+ buffer.Flip();
+ buffer.Rewind();
+ AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ Assert.AreEqual(VALUE, value.Value);
+ }
+ #endregion // INT32 Tests
+
+ #region INT64 tests
+ [Test]
+ public void INT64_ReadWrite()
+ {
+ AMQType type = AMQType.INT64;
+ ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
+ const long VALUE = -(2^43+1233123);
+
+ type.WriteToBuffer(VALUE, buffer);
+ buffer.Flip();
+ buffer.Rewind();
+ AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ Assert.AreEqual(VALUE, value.Value);
+ }
+ [Test]
+ public void UINT64_ReadWrite()
+ {
+ AMQType type = AMQType.UINT64;
+ ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
+ const ulong VALUE = (2 ^ 61 + 1233123);
+
+ type.WriteToBuffer(VALUE, buffer);
+ buffer.Flip();
+ buffer.Rewind();
+ AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ Assert.AreEqual(VALUE, value.Value);
+ }
+ #endregion // INT64 Tests
+
+ #region FLOAT tests
+ [Test]
+ public void FLOAT_ReadWrite()
+ {
+ AMQType type = AMQType.FLOAT;
+ ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
+ const float VALUE = 1.2345000E-035f;
+
+ type.WriteToBuffer(VALUE, buffer);
+ buffer.Flip();
+ buffer.Rewind();
+ AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ Assert.AreEqual(VALUE, value.Value);
+ }
+ #endregion // FLOAT Tests
+
+ #region DOUBLE tests
+ [Test]
+ public void DOUBLE_ReadWrite()
+ {
+ AMQType type = AMQType.DOUBLE;
+ ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
+ const double VALUE = 1.2345000E-045;
+
+ type.WriteToBuffer(VALUE, buffer);
+ buffer.Flip();
+ buffer.Rewind();
+ AMQTypedValue value = AMQTypedValue.ReadFromBuffer(buffer);
+ Assert.AreEqual(VALUE, value.Value);
+ }
+ #endregion // FLOAT Tests
+ }
+}
diff --git a/dotnet/Qpid.Common.Tests/Qpid/Framing/TestEncodingUtils.cs b/dotnet/Qpid.Common.Tests/Qpid/Framing/TestEncodingUtils.cs
index 720d7697d3..a8202dc70d 100644
--- a/dotnet/Qpid.Common.Tests/Qpid/Framing/TestEncodingUtils.cs
+++ b/dotnet/Qpid.Common.Tests/Qpid/Framing/TestEncodingUtils.cs
@@ -1,60 +1,60 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using NUnit.Framework;
-using Apache.Qpid.Buffer;
-using Apache.Qpid.Framing;
-
-namespace Apache.Qpid.Framing.Tests
-{
- [TestFixture]
- public class TestEncodingUtils
- {
- [Test]
- public void CanReadLongAsShortString()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
- EncodingUtils.WriteShortStringBytes(buffer, "98878122");
- buffer.Flip();
- long value = EncodingUtils.ReadLongAsShortString(buffer);
- Assert.AreEqual(98878122, value);
- }
- [Test]
- public void CanReadLongAsShortStringNegative()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
- EncodingUtils.WriteShortStringBytes(buffer, "-98878122");
- buffer.Flip();
- long value = EncodingUtils.ReadLongAsShortString(buffer);
- Assert.AreEqual(-98878122, value);
- }
- [Test]
- public void CanReadLongAsShortStringEmpty()
- {
- ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
- EncodingUtils.WriteShortStringBytes(buffer, "");
- buffer.Flip();
- long value = EncodingUtils.ReadLongAsShortString(buffer);
- Assert.AreEqual(0, value);
- }
-
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using NUnit.Framework;
+using Apache.Qpid.Buffer;
+using Apache.Qpid.Framing;
+
+namespace Apache.Qpid.Framing.Tests
+{
+ [TestFixture]
+ public class TestEncodingUtils
+ {
+ [Test]
+ public void CanReadLongAsShortString()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
+ EncodingUtils.WriteShortStringBytes(buffer, "98878122");
+ buffer.Flip();
+ long value = EncodingUtils.ReadLongAsShortString(buffer);
+ Assert.AreEqual(98878122, value);
+ }
+ [Test]
+ public void CanReadLongAsShortStringNegative()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
+ EncodingUtils.WriteShortStringBytes(buffer, "-98878122");
+ buffer.Flip();
+ long value = EncodingUtils.ReadLongAsShortString(buffer);
+ Assert.AreEqual(-98878122, value);
+ }
+ [Test]
+ public void CanReadLongAsShortStringEmpty()
+ {
+ ByteBuffer buffer = ByteBuffer.Allocate(0x1000);
+ EncodingUtils.WriteShortStringBytes(buffer, "");
+ buffer.Flip();
+ long value = EncodingUtils.ReadLongAsShortString(buffer);
+ Assert.AreEqual(0, value);
+ }
+
+ }
+}
diff --git a/dotnet/Qpid.Common.Tests/default.build b/dotnet/Qpid.Common.Tests/default.build
index 00658bdbe2..a97c0282c2 100644
--- a/dotnet/Qpid.Common.Tests/default.build
+++ b/dotnet/Qpid.Common.Tests/default.build
@@ -1,31 +1,52 @@
-<?xml version="1.0"?>
-<project name="Apache.Qpid.Common" default="test">
-
- <target name="build">
- <csc target="library"
- define="${build.defines}"
- warnaserror="true" debug="${build.debug}"
- output="${build.dir}/${project::get-name()}.Tests.dll">
-
- <sources>
- <include name="**/*.cs" />
- </sources>
- <references>
- <include name="${build.dir}/log4net.dll" />
- <include name="${build.dir}/nunit.framework.dll" />
- <include name="${build.dir}/${project::get-name()}.dll" />
- <include name="${build.dir}/Apache.Qpid.Codec.dll" />
- <include name="${build.dir}/Apache.Qpid.Messaging.dll" />
- <include name="${build.dir}/Apache.Qpid.Buffer.dll" />
- </references>
-
- </csc>
- </target>
- <target name="test" depends="build">
- <nunit2>
- <formatter type="${nant.formatter}" usefile="false" />
- <test assemblyname="${build.dir}/${project::get-name()}.Tests.dll" />
- </nunit2>
- </target>
-</project>
-
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="Apache.Qpid.Common" default="test">
+
+ <target name="build">
+ <csc target="library"
+ define="${build.defines}"
+ warnaserror="true" debug="${build.debug}"
+ output="${build.dir}/${project::get-name()}.Tests.dll">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ <include name="${build.dir}/log4net.dll" />
+ <include name="${build.dir}/nunit.framework.dll" />
+ <include name="${build.dir}/${project::get-name()}.dll" />
+ <include name="${build.dir}/Apache.Qpid.Codec.dll" />
+ <include name="${build.dir}/Apache.Qpid.Messaging.dll" />
+ <include name="${build.dir}/Apache.Qpid.Buffer.dll" />
+ </references>
+
+ </csc>
+ </target>
+ <target name="test" depends="build">
+ <nunit2>
+ <formatter type="${nant.formatter}" usefile="false" />
+ <test assemblyname="${build.dir}/${project::get-name()}.Tests.dll" />
+ </nunit2>
+ </target>
+</project>
+
diff --git a/dotnet/Qpid.Common/AMQInvalidArgumentException.cs b/dotnet/Qpid.Common/AMQInvalidArgumentException.cs
index 0fb4ddae99..831f7bab0e 100644
--- a/dotnet/Qpid.Common/AMQInvalidArgumentException.cs
+++ b/dotnet/Qpid.Common/AMQInvalidArgumentException.cs
@@ -1,46 +1,46 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Runtime.Serialization;
-
-using Apache.Qpid.Protocol;
-
-namespace Apache.Qpid
-{
- /// <summary>
- /// Thrown when an invalid argument was supplied to the broker
- /// </summary>
- [Serializable]
- public class AMQInvalidArgumentException : AMQException
- {
- public AMQInvalidArgumentException(string message)
- : base(AMQConstant.INVALID_ARGUMENT.Code, message, null)
- {
- }
-
- protected AMQInvalidArgumentException(SerializationInfo info, StreamingContext ctxt)
- : base(info, ctxt)
- {
- }
-
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Runtime.Serialization;
+
+using Apache.Qpid.Protocol;
+
+namespace Apache.Qpid
+{
+ /// <summary>
+ /// Thrown when an invalid argument was supplied to the broker
+ /// </summary>
+ [Serializable]
+ public class AMQInvalidArgumentException : AMQException
+ {
+ public AMQInvalidArgumentException(string message)
+ : base(AMQConstant.INVALID_ARGUMENT.Code, message, null)
+ {
+ }
+
+ protected AMQInvalidArgumentException(SerializationInfo info, StreamingContext ctxt)
+ : base(info, ctxt)
+ {
+ }
+
+ }
+}
diff --git a/dotnet/Qpid.Common/AMQInvalidRoutingKeyException.cs b/dotnet/Qpid.Common/AMQInvalidRoutingKeyException.cs
index 3f8dead94d..a3ce813d1b 100644
--- a/dotnet/Qpid.Common/AMQInvalidRoutingKeyException.cs
+++ b/dotnet/Qpid.Common/AMQInvalidRoutingKeyException.cs
@@ -1,46 +1,46 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Runtime.Serialization;
-
-using Apache.Qpid.Protocol;
-
-namespace Apache.Qpid
-{
- /// <summary>
- /// Thrown when an invalid routing key was sent to the broker
- /// </summary>
- [Serializable]
- public class AMQInvalidRoutingKeyException : AMQException
- {
- public AMQInvalidRoutingKeyException(string message)
- : base(AMQConstant.INVALID_ROUTING_KEY.Code, message, null)
- {
- }
-
- protected AMQInvalidRoutingKeyException(SerializationInfo info, StreamingContext ctxt)
- : base(info, ctxt)
- {
- }
-
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Runtime.Serialization;
+
+using Apache.Qpid.Protocol;
+
+namespace Apache.Qpid
+{
+ /// <summary>
+ /// Thrown when an invalid routing key was sent to the broker
+ /// </summary>
+ [Serializable]
+ public class AMQInvalidRoutingKeyException : AMQException
+ {
+ public AMQInvalidRoutingKeyException(string message)
+ : base(AMQConstant.INVALID_ROUTING_KEY.Code, message, null)
+ {
+ }
+
+ protected AMQInvalidRoutingKeyException(SerializationInfo info, StreamingContext ctxt)
+ : base(info, ctxt)
+ {
+ }
+
+ }
+}
diff --git a/dotnet/Qpid.Common/Collections/ConsumerProducerQueue.cs b/dotnet/Qpid.Common/Collections/ConsumerProducerQueue.cs
index ea4526faaf..131f316da6 100644
--- a/dotnet/Qpid.Common/Collections/ConsumerProducerQueue.cs
+++ b/dotnet/Qpid.Common/Collections/ConsumerProducerQueue.cs
@@ -1,113 +1,113 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Collections;
-using System.Threading;
-
-
-namespace Apache.Qpid.Collections
-{
- /// <summary>
- /// Simple FIFO queue to support multi-threaded consumer
- /// and producers. It supports timeouts in dequeue operations.
- /// </summary>
- public sealed class ConsumerProducerQueue
- {
- private Queue _queue = new Queue();
- private WaitSemaphore _semaphore = new WaitSemaphore();
-
- /// <summary>
- /// Put an item into the tail of the queue
- /// </summary>
- /// <param name="item"></param>
- public void Enqueue(object item)
- {
- lock ( _queue.SyncRoot )
- {
- _queue.Enqueue(item);
- _semaphore.Increment();
- }
- }
-
- /// <summary>
- /// Wait indefinitely for an item to be available
- /// on the queue.
- /// </summary>
- /// <returns>The object at the head of the queue</returns>
- public object Dequeue()
- {
- return Dequeue(Timeout.Infinite);
- }
-
- /// <summary>
- /// Wait up to the number of milliseconds specified
- /// for an item to be available on the queue
- /// </summary>
- /// <param name="timeout">Number of milliseconds to wait</param>
- /// <returns>The object at the head of the queue, or null
- /// if the timeout expires</returns>
- public object Dequeue(long timeout)
- {
- if ( _semaphore.Decrement(timeout) )
- {
- lock ( _queue.SyncRoot )
- {
- return _queue.Dequeue();
- }
- }
- return null;
- }
-
- #region Simple Semaphore
- //
- // Simple Semaphore
- //
-
- class WaitSemaphore
- {
- private int _count;
- private AutoResetEvent _event = new AutoResetEvent(false);
-
- public void Increment()
- {
- Interlocked.Increment(ref _count);
- _event.Set();
- }
-
- public bool Decrement(long timeout)
- {
- if ( timeout > int.MaxValue )
- throw new ArgumentOutOfRangeException("timeout", timeout, "Must be <= Int32.MaxValue");
-
- int millis = (int) (timeout & 0x7FFFFFFF);
- if ( Interlocked.Decrement(ref _count) > 0 )
- {
- // there are messages in queue, so no need to wait
- return true;
- } else
- {
- return _event.WaitOne(millis, false);
- }
- }
- }
- #endregion // Simple Semaphore
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Collections;
+using System.Threading;
+
+
+namespace Apache.Qpid.Collections
+{
+ /// <summary>
+ /// Simple FIFO queue to support multi-threaded consumer
+ /// and producers. It supports timeouts in dequeue operations.
+ /// </summary>
+ public sealed class ConsumerProducerQueue
+ {
+ private Queue _queue = new Queue();
+ private WaitSemaphore _semaphore = new WaitSemaphore();
+
+ /// <summary>
+ /// Put an item into the tail of the queue
+ /// </summary>
+ /// <param name="item"></param>
+ public void Enqueue(object item)
+ {
+ lock ( _queue.SyncRoot )
+ {
+ _queue.Enqueue(item);
+ _semaphore.Increment();
+ }
+ }
+
+ /// <summary>
+ /// Wait indefinitely for an item to be available
+ /// on the queue.
+ /// </summary>
+ /// <returns>The object at the head of the queue</returns>
+ public object Dequeue()
+ {
+ return Dequeue(Timeout.Infinite);
+ }
+
+ /// <summary>
+ /// Wait up to the number of milliseconds specified
+ /// for an item to be available on the queue
+ /// </summary>
+ /// <param name="timeout">Number of milliseconds to wait</param>
+ /// <returns>The object at the head of the queue, or null
+ /// if the timeout expires</returns>
+ public object Dequeue(long timeout)
+ {
+ if ( _semaphore.Decrement(timeout) )
+ {
+ lock ( _queue.SyncRoot )
+ {
+ return _queue.Dequeue();
+ }
+ }
+ return null;
+ }
+
+ #region Simple Semaphore
+ //
+ // Simple Semaphore
+ //
+
+ class WaitSemaphore
+ {
+ private int _count;
+ private AutoResetEvent _event = new AutoResetEvent(false);
+
+ public void Increment()
+ {
+ Interlocked.Increment(ref _count);
+ _event.Set();
+ }
+
+ public bool Decrement(long timeout)
+ {
+ if ( timeout > int.MaxValue )
+ throw new ArgumentOutOfRangeException("timeout", timeout, "Must be <= Int32.MaxValue");
+
+ int millis = (int) (timeout & 0x7FFFFFFF);
+ if ( Interlocked.Decrement(ref _count) > 0 )
+ {
+ // there are messages in queue, so no need to wait
+ return true;
+ } else
+ {
+ return _event.WaitOne(millis, false);
+ }
+ }
+ }
+ #endregion // Simple Semaphore
+ }
+}
diff --git a/dotnet/Qpid.Common/Framing/AMQType.cs b/dotnet/Qpid.Common/Framing/AMQType.cs
index 618ab31d32..95da72b907 100644
--- a/dotnet/Qpid.Common/Framing/AMQType.cs
+++ b/dotnet/Qpid.Common/Framing/AMQType.cs
@@ -1,700 +1,700 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Text;
-using Apache.Qpid.Buffer;
-
-namespace Apache.Qpid.Framing
-{
- /// <summary>
- /// Base class for the Field Table Type system.
- /// Ported over from the Java AMQType enumeration
- /// </summary>
- public abstract class AMQType
- {
- private byte _identifier;
-
- /// <summary>
- /// Type code identifier for this type
- /// </summary>
- public byte Identifier
- {
- get { return _identifier; }
- }
-
- protected AMQType(char identifier)
- {
- _identifier = (byte)identifier;
- }
-
- /// <summary>
- /// Create a new <see cref="AMQTypedValue"/> instance
- /// </summary>
- /// <param name="value">Value to initialize with</param>
- /// <returns>A new typed value instance</returns>
- public AMQTypedValue AsTypedValue(object value)
- {
- return new AMQTypedValue(this, ToNativeValue(value));
- }
-
- /// <summary>
- /// Write the specified value to the buffer using the encoding
- /// specified for this type
- /// </summary>
- /// <param name="value">Value to write</param>
- /// <param name="buffer">Buffer to write to</param>
- public void WriteToBuffer(object value, ByteBuffer buffer)
- {
- buffer.Put(Identifier);
- WriteValueImpl(value, buffer);
- }
-
- public override string ToString()
- {
- return ((Char) Identifier).ToString();
- }
-
- /// <summary>
- /// Get the encoding size for the specified value in this type format
- /// </summary>
- /// <param name="value">Value to find encoded size for</param>
- /// <returns>The encoded size</returns>
- public abstract uint GetEncodingSize(object value);
- /// <summary>
- /// Convert the specified value to this type
- /// </summary>
- /// <param name="value">Value to convert</param>
- /// <returns>The converted value</returns>
- public abstract object ToNativeValue(object value);
-
- /// <summary>
- /// Read a value from the specified buffer using the encoding for
- /// this type
- /// </summary>
- /// <param name="buffer">Buffer to read from</param>
- /// <returns>The value read</returns>
- public abstract object ReadValueFromBuffer(ByteBuffer buffer);
-
- protected abstract void WriteValueImpl(Object value, ByteBuffer buffer);
-
-
- #region Known Types
- //
- // Known Types
- //
-
- // long string is not defined in the proposed specification,
- // and the 'S' discriminator is left for unsigned short (16-bit) values
- public static readonly AMQType LONG_STRING = new AMQLongStringType();
- public static readonly AMQType UINT32 = new AMQUInt32Type();
- public static readonly AMQType DECIMAL = new AMQDecimalType();
- public static readonly AMQType TIMESTAMP = new AMQTimeStampType();
- public static readonly AMQType FIELD_TABLE = new AMQFieldTableType();
- public static readonly AMQType VOID = new AMQVoidType();
- public static readonly AMQType BINARY = new AMQBinaryType();
- public static readonly AMQType ASCII_STRING = new AMQAsciiStringType();
- public static readonly AMQType WIDE_STRING = new AMQWideStringType();
- public static readonly AMQType BOOLEAN = new AMQBooleanType();
- public static readonly AMQType ASCII_CHARACTER = new AMQAsciiCharType();
- public static readonly AMQType BYTE = new AMQByteType();
- public static readonly AMQType SBYTE = new AMQSByteType();
- public static readonly AMQType INT16 = new AMQInt16Type();
- public static readonly AMQType UINT16 = new AMQUInt16Type();
- public static readonly AMQType INT32 = new AMQInt32Type();
- public static readonly AMQType INT64 = new AMQInt64Type();
- public static readonly AMQType UINT64 = new AMQUInt64Type();
- public static readonly AMQType FLOAT = new AMQFloatType();
- public static readonly AMQType DOUBLE = new AMQDoubleType();
-
- #endregion // Known Types
-
- #region Type Implementation
- //
- // Type Implementation
- //
-
- sealed class AMQLongStringType : AMQType
- {
- public AMQLongStringType() : base('S')
- {
- }
-
- public override uint GetEncodingSize(object value)
- {
- return EncodingUtils.EncodedLongStringLength((string) value);
- }
-
- public override object ToNativeValue(object value)
- {
- if ( value == null )
- throw new ArgumentNullException("value");
- return value.ToString();
- }
-
- public override object ReadValueFromBuffer(ByteBuffer buffer)
- {
- return EncodingUtils.ReadLongString(buffer);
- }
-
- protected override void WriteValueImpl(object value, ByteBuffer buffer)
- {
- EncodingUtils.WriteLongStringBytes(buffer, (string) value);
- }
-
- }
-
- sealed class AMQUInt32Type : AMQType
- {
- public AMQUInt32Type() : base('i')
- {
- }
-
- public override uint GetEncodingSize(object value)
- {
- return EncodingUtils.UnsignedIntegerLength();
- }
-
- public override object ToNativeValue(object value)
- {
- return Convert.ToUInt32(value);
- }
-
- public override object ReadValueFromBuffer(ByteBuffer buffer)
- {
- return EncodingUtils.ReadUnsignedInteger(buffer);
- }
-
- protected override void WriteValueImpl(object value, ByteBuffer buffer)
- {
- EncodingUtils.WriteUnsignedInteger(buffer, (uint) value);
- }
-
- }
-
- sealed class AMQDecimalType : AMQType
- {
- public AMQDecimalType() : base('D')
- {
- }
-
- public override uint GetEncodingSize(object value)
- {
- throw new NotImplementedException();
- }
-
- public override object ToNativeValue(object value)
- {
- throw new NotImplementedException();
- }
-
- public override object ReadValueFromBuffer(ByteBuffer buffer)
- {
- throw new NotImplementedException();
- }
-
- protected override void WriteValueImpl(object value, ByteBuffer buffer)
- {
- throw new NotImplementedException();
- }
- }
-
- sealed class AMQTimeStampType : AMQType
- {
- public AMQTimeStampType() : base('T')
- {
- }
-
- public override uint GetEncodingSize(object value)
- {
- throw new NotImplementedException();
- }
-
- public override object ToNativeValue(object value)
- {
- throw new NotImplementedException();
- }
-
- public override object ReadValueFromBuffer(ByteBuffer buffer)
- {
- throw new NotImplementedException();
- }
-
- protected override void WriteValueImpl(object value, ByteBuffer buffer)
- {
- throw new NotImplementedException();
- }
- }
-
- sealed class AMQFieldTableType : AMQType
- {
- public AMQFieldTableType() : base('F')
- {
- }
-
- public override uint GetEncodingSize(object value)
- {
- throw new NotImplementedException();
- }
-
- public override object ToNativeValue(object value)
- {
- throw new NotImplementedException();
- }
-
- public override object ReadValueFromBuffer(ByteBuffer buffer)
- {
- throw new NotImplementedException();
- }
-
- protected override void WriteValueImpl(object value, ByteBuffer buffer)
- {
- throw new NotImplementedException();
- }
- }
-
- sealed class AMQVoidType : AMQType
- {
- public AMQVoidType() : base('V')
- {
- }
-
- public override uint GetEncodingSize(object value)
- {
- return 0;
- }
-
- public override object ToNativeValue(object value)
- {
- if ( value != null )
- throw new FormatException(string.Format("Cannot convert {0} to VOID type", value));
- return null;
- }
-
- public override object ReadValueFromBuffer(ByteBuffer buffer)
- {
- return null;
- }
-
- protected override void WriteValueImpl(object value, ByteBuffer buffer)
- {
- }
- }
-
- // Extended Types
-
- sealed class AMQBinaryType : AMQType
- {
- public AMQBinaryType() : base('x')
- {
- }
-
- public override uint GetEncodingSize(object value)
- {
- return EncodingUtils.EncodedLongstrLength((byte[]) value);
- }
-
- public override object ToNativeValue(object value)
- {
- if ( value is byte[] || value == null )
- {
- return value;
- }
- throw new ArgumentException("Value cannot be converted to byte[]");
- }
-
- public override object ReadValueFromBuffer(ByteBuffer buffer)
- {
- return EncodingUtils.ReadLongstr(buffer);
- }
-
- protected override void WriteValueImpl(object value, ByteBuffer buffer)
- {
- EncodingUtils.WriteLongstr(buffer, (byte[])value);
- }
- }
-
- sealed class AMQAsciiStringType : AMQType
- {
- public AMQAsciiStringType() : base('c')
- {
- }
-
- public override uint GetEncodingSize(object value)
- {
- return EncodingUtils.EncodedAsciiStringLength((string)value);
- }
-
- public override object ToNativeValue(object value)
- {
- if ( value == null )
- throw new ArgumentNullException("value");
- return value.ToString();
- }
-
- public override object ReadValueFromBuffer(ByteBuffer buffer)
- {
- return EncodingUtils.ReadAsciiString(buffer);
- }
-
- protected override void WriteValueImpl(object value, ByteBuffer buffer)
- {
- EncodingUtils.WriteAsciiString(buffer, (string)value);
- }
- }
-
- sealed class AMQWideStringType : AMQType
- {
- // todo: Change encoding to UTF16 (java code still uses default
- // ascii encoding for wide strings
- private static readonly Encoding ENCODING = Encoding.ASCII;
-
- public AMQWideStringType()
- : base('C')
- {
- }
-
- public override uint GetEncodingSize(object value)
- {
- return EncodingUtils.EncodedLongStringLength((string)value, ENCODING);
- }
-
- public override object ToNativeValue(object value)
- {
- if ( value == null )
- throw new ArgumentNullException("value");
- return value.ToString();
- }
-
- public override object ReadValueFromBuffer(ByteBuffer buffer)
- {
- return EncodingUtils.ReadLongString(buffer, ENCODING);
- }
-
- protected override void WriteValueImpl(object value, ByteBuffer buffer)
- {
- EncodingUtils.WriteLongStringBytes(buffer, (string)value, ENCODING);
- }
- }
-
- sealed class AMQBooleanType : AMQType
- {
- public AMQBooleanType() : base('t')
- {
- }
-
- public override uint GetEncodingSize(object value)
- {
- return EncodingUtils.EncodedBooleanLength();
- }
-
- public override object ToNativeValue(object value)
- {
- return Convert.ToBoolean(value);
- }
-
- public override object ReadValueFromBuffer(ByteBuffer buffer)
- {
- return EncodingUtils.ReadBoolean(buffer);
- }
-
- protected override void WriteValueImpl(object value, ByteBuffer buffer)
- {
- EncodingUtils.WriteBoolean(buffer, (bool)value);
- }
- }
-
- sealed class AMQAsciiCharType : AMQType
- {
- public AMQAsciiCharType() : base('k')
- {
- }
-
- public override uint GetEncodingSize(object value)
- {
- return EncodingUtils.EncodedCharLength();
- }
-
- public override object ToNativeValue(object value)
- {
- return Convert.ToChar(value);
- }
-
- public override object ReadValueFromBuffer(ByteBuffer buffer)
- {
- return EncodingUtils.ReadChar(buffer);
- }
-
- protected override void WriteValueImpl(object value, ByteBuffer buffer)
- {
- EncodingUtils.WriteChar(buffer, (char)value);
- }
- }
-
- sealed class AMQByteType : AMQType
- {
- public AMQByteType() : base('B')
- {
- }
-
- public override uint GetEncodingSize(object value)
- {
- return EncodingUtils.EncodedByteLength();
- }
-
- public override object ToNativeValue(object value)
- {
- return Convert.ToByte(value);
- }
-
- public override object ReadValueFromBuffer(ByteBuffer buffer)
- {
- return EncodingUtils.ReadByte(buffer);
- }
-
- protected override void WriteValueImpl(object value, ByteBuffer buffer)
- {
- EncodingUtils.WriteByte(buffer, (byte)value);
- }
- }
-
- sealed class AMQSByteType : AMQType
- {
- public AMQSByteType()
- : base('b')
- {
- }
-
- public override uint GetEncodingSize(object value)
- {
- return EncodingUtils.EncodedSByteLength();
- }
-
- public override object ToNativeValue(object value)
- {
- return Convert.ToSByte(value);
- }
-
- public override object ReadValueFromBuffer(ByteBuffer buffer)
- {
- return EncodingUtils.ReadSByte(buffer);
- }
-
- protected override void WriteValueImpl(object value, ByteBuffer buffer)
- {
- EncodingUtils.WriteSByte(buffer, (sbyte)value);
- }
- }
-
- sealed class AMQInt16Type : AMQType
- {
- public AMQInt16Type() : base('s')
- {
- }
-
- public override uint GetEncodingSize(object value)
- {
- return EncodingUtils.EncodedShortLength();
- }
-
- public override object ToNativeValue(object value)
- {
- return Convert.ToInt16(value);
- }
-
- public override object ReadValueFromBuffer(ByteBuffer buffer)
- {
- return EncodingUtils.ReadShort(buffer);
- }
-
- protected override void WriteValueImpl(object value, ByteBuffer buffer)
- {
- EncodingUtils.WriteShort(buffer, (short)value);
- }
- }
-
- sealed class AMQUInt16Type : AMQType
- {
- public AMQUInt16Type()
- : base('S')
- {
- }
-
- public override uint GetEncodingSize(object value)
- {
- return EncodingUtils.EncodedUnsignedShortLength();
- }
-
- public override object ToNativeValue(object value)
- {
- return Convert.ToUInt16(value);
- }
-
- public override object ReadValueFromBuffer(ByteBuffer buffer)
- {
- return EncodingUtils.ReadUnsignedShort(buffer);
- }
-
- protected override void WriteValueImpl(object value, ByteBuffer buffer)
- {
- EncodingUtils.WriteUnsignedShort(buffer, (ushort)value);
- }
- }
-
- sealed class AMQInt32Type : AMQType
- {
- public AMQInt32Type() : base('I')
- {
- }
-
- public override uint GetEncodingSize(object value)
- {
- return EncodingUtils.EncodedIntegerLength();
- }
-
- public override object ToNativeValue(object value)
- {
- return Convert.ToInt32(value);
- }
-
- public override object ReadValueFromBuffer(ByteBuffer buffer)
- {
- return EncodingUtils.ReadInteger(buffer);
- }
-
- protected override void WriteValueImpl(object value, ByteBuffer buffer)
- {
- EncodingUtils.WriteInteger(buffer, (int)value);
- }
- }
-
- sealed class AMQInt64Type : AMQType
- {
- public AMQInt64Type() : base('l')
- {
- }
-
- public override uint GetEncodingSize(object value)
- {
- return EncodingUtils.EncodedLongLength();
- }
-
- public override object ToNativeValue(object value)
- {
- return Convert.ToInt64(value);
- }
-
- public override object ReadValueFromBuffer(ByteBuffer buffer)
- {
- return EncodingUtils.ReadLong(buffer);
- }
-
- protected override void WriteValueImpl(object value, ByteBuffer buffer)
- {
- EncodingUtils.WriteLong(buffer, (long)value);
- }
- }
-
- sealed class AMQUInt64Type : AMQType
- {
- public AMQUInt64Type()
- : base('L')
- {
- }
-
- public override uint GetEncodingSize(object value)
- {
- return EncodingUtils.EncodedUnsignedLongLength();
- }
-
- public override object ToNativeValue(object value)
- {
- return Convert.ToUInt64(value);
- }
-
- public override object ReadValueFromBuffer(ByteBuffer buffer)
- {
- return EncodingUtils.ReadUnsignedLong(buffer);
- }
-
- protected override void WriteValueImpl(object value, ByteBuffer buffer)
- {
- EncodingUtils.WriteUnsignedLong(buffer, (ulong)value);
- }
- }
-
- sealed class AMQFloatType : AMQType
- {
- public AMQFloatType() : base('f')
- {
- }
-
- public override uint GetEncodingSize(object value)
- {
- return EncodingUtils.EncodedFloatLength();
- }
-
- public override object ToNativeValue(object value)
- {
- return Convert.ToSingle(value);
- }
-
- public override object ReadValueFromBuffer(ByteBuffer buffer)
- {
- return EncodingUtils.ReadFloat(buffer);
- }
-
- protected override void WriteValueImpl(object value, ByteBuffer buffer)
- {
- EncodingUtils.WriteFloat(buffer, (float)value);
- }
- }
-
- sealed class AMQDoubleType : AMQType
- {
- public AMQDoubleType() : base('d')
- {
- }
-
- public override uint GetEncodingSize(object value)
- {
- return EncodingUtils.EncodedDoubleLength();
- }
-
- public override object ToNativeValue(object value)
- {
- return Convert.ToDouble(value);
- }
-
- public override object ReadValueFromBuffer(ByteBuffer buffer)
- {
- return EncodingUtils.ReadDouble(buffer);
- }
-
- protected override void WriteValueImpl(object value, ByteBuffer buffer)
- {
- EncodingUtils.WriteDouble(buffer, (double)value);
- }
- }
-
- #endregion // Type Implementation
-
- } // class AMQType
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Text;
+using Apache.Qpid.Buffer;
+
+namespace Apache.Qpid.Framing
+{
+ /// <summary>
+ /// Base class for the Field Table Type system.
+ /// Ported over from the Java AMQType enumeration
+ /// </summary>
+ public abstract class AMQType
+ {
+ private byte _identifier;
+
+ /// <summary>
+ /// Type code identifier for this type
+ /// </summary>
+ public byte Identifier
+ {
+ get { return _identifier; }
+ }
+
+ protected AMQType(char identifier)
+ {
+ _identifier = (byte)identifier;
+ }
+
+ /// <summary>
+ /// Create a new <see cref="AMQTypedValue"/> instance
+ /// </summary>
+ /// <param name="value">Value to initialize with</param>
+ /// <returns>A new typed value instance</returns>
+ public AMQTypedValue AsTypedValue(object value)
+ {
+ return new AMQTypedValue(this, ToNativeValue(value));
+ }
+
+ /// <summary>
+ /// Write the specified value to the buffer using the encoding
+ /// specified for this type
+ /// </summary>
+ /// <param name="value">Value to write</param>
+ /// <param name="buffer">Buffer to write to</param>
+ public void WriteToBuffer(object value, ByteBuffer buffer)
+ {
+ buffer.Put(Identifier);
+ WriteValueImpl(value, buffer);
+ }
+
+ public override string ToString()
+ {
+ return ((Char) Identifier).ToString();
+ }
+
+ /// <summary>
+ /// Get the encoding size for the specified value in this type format
+ /// </summary>
+ /// <param name="value">Value to find encoded size for</param>
+ /// <returns>The encoded size</returns>
+ public abstract uint GetEncodingSize(object value);
+ /// <summary>
+ /// Convert the specified value to this type
+ /// </summary>
+ /// <param name="value">Value to convert</param>
+ /// <returns>The converted value</returns>
+ public abstract object ToNativeValue(object value);
+
+ /// <summary>
+ /// Read a value from the specified buffer using the encoding for
+ /// this type
+ /// </summary>
+ /// <param name="buffer">Buffer to read from</param>
+ /// <returns>The value read</returns>
+ public abstract object ReadValueFromBuffer(ByteBuffer buffer);
+
+ protected abstract void WriteValueImpl(Object value, ByteBuffer buffer);
+
+
+ #region Known Types
+ //
+ // Known Types
+ //
+
+ // long string is not defined in the proposed specification,
+ // and the 'S' discriminator is left for unsigned short (16-bit) values
+ public static readonly AMQType LONG_STRING = new AMQLongStringType();
+ public static readonly AMQType UINT32 = new AMQUInt32Type();
+ public static readonly AMQType DECIMAL = new AMQDecimalType();
+ public static readonly AMQType TIMESTAMP = new AMQTimeStampType();
+ public static readonly AMQType FIELD_TABLE = new AMQFieldTableType();
+ public static readonly AMQType VOID = new AMQVoidType();
+ public static readonly AMQType BINARY = new AMQBinaryType();
+ public static readonly AMQType ASCII_STRING = new AMQAsciiStringType();
+ public static readonly AMQType WIDE_STRING = new AMQWideStringType();
+ public static readonly AMQType BOOLEAN = new AMQBooleanType();
+ public static readonly AMQType ASCII_CHARACTER = new AMQAsciiCharType();
+ public static readonly AMQType BYTE = new AMQByteType();
+ public static readonly AMQType SBYTE = new AMQSByteType();
+ public static readonly AMQType INT16 = new AMQInt16Type();
+ public static readonly AMQType UINT16 = new AMQUInt16Type();
+ public static readonly AMQType INT32 = new AMQInt32Type();
+ public static readonly AMQType INT64 = new AMQInt64Type();
+ public static readonly AMQType UINT64 = new AMQUInt64Type();
+ public static readonly AMQType FLOAT = new AMQFloatType();
+ public static readonly AMQType DOUBLE = new AMQDoubleType();
+
+ #endregion // Known Types
+
+ #region Type Implementation
+ //
+ // Type Implementation
+ //
+
+ sealed class AMQLongStringType : AMQType
+ {
+ public AMQLongStringType() : base('S')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedLongStringLength((string) value);
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ if ( value == null )
+ throw new ArgumentNullException("value");
+ return value.ToString();
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadLongString(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteLongStringBytes(buffer, (string) value);
+ }
+
+ }
+
+ sealed class AMQUInt32Type : AMQType
+ {
+ public AMQUInt32Type() : base('i')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.UnsignedIntegerLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToUInt32(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadUnsignedInteger(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteUnsignedInteger(buffer, (uint) value);
+ }
+
+ }
+
+ sealed class AMQDecimalType : AMQType
+ {
+ public AMQDecimalType() : base('D')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ sealed class AMQTimeStampType : AMQType
+ {
+ public AMQTimeStampType() : base('T')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ sealed class AMQFieldTableType : AMQType
+ {
+ public AMQFieldTableType() : base('F')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ sealed class AMQVoidType : AMQType
+ {
+ public AMQVoidType() : base('V')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return 0;
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ if ( value != null )
+ throw new FormatException(string.Format("Cannot convert {0} to VOID type", value));
+ return null;
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return null;
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ }
+ }
+
+ // Extended Types
+
+ sealed class AMQBinaryType : AMQType
+ {
+ public AMQBinaryType() : base('x')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedLongstrLength((byte[]) value);
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ if ( value is byte[] || value == null )
+ {
+ return value;
+ }
+ throw new ArgumentException("Value cannot be converted to byte[]");
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadLongstr(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteLongstr(buffer, (byte[])value);
+ }
+ }
+
+ sealed class AMQAsciiStringType : AMQType
+ {
+ public AMQAsciiStringType() : base('c')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedAsciiStringLength((string)value);
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ if ( value == null )
+ throw new ArgumentNullException("value");
+ return value.ToString();
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadAsciiString(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteAsciiString(buffer, (string)value);
+ }
+ }
+
+ sealed class AMQWideStringType : AMQType
+ {
+ // todo: Change encoding to UTF16 (java code still uses default
+ // ascii encoding for wide strings
+ private static readonly Encoding ENCODING = Encoding.ASCII;
+
+ public AMQWideStringType()
+ : base('C')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedLongStringLength((string)value, ENCODING);
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ if ( value == null )
+ throw new ArgumentNullException("value");
+ return value.ToString();
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadLongString(buffer, ENCODING);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteLongStringBytes(buffer, (string)value, ENCODING);
+ }
+ }
+
+ sealed class AMQBooleanType : AMQType
+ {
+ public AMQBooleanType() : base('t')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedBooleanLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToBoolean(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadBoolean(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteBoolean(buffer, (bool)value);
+ }
+ }
+
+ sealed class AMQAsciiCharType : AMQType
+ {
+ public AMQAsciiCharType() : base('k')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedCharLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToChar(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadChar(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteChar(buffer, (char)value);
+ }
+ }
+
+ sealed class AMQByteType : AMQType
+ {
+ public AMQByteType() : base('B')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedByteLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToByte(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadByte(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteByte(buffer, (byte)value);
+ }
+ }
+
+ sealed class AMQSByteType : AMQType
+ {
+ public AMQSByteType()
+ : base('b')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedSByteLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToSByte(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadSByte(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteSByte(buffer, (sbyte)value);
+ }
+ }
+
+ sealed class AMQInt16Type : AMQType
+ {
+ public AMQInt16Type() : base('s')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedShortLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToInt16(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadShort(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteShort(buffer, (short)value);
+ }
+ }
+
+ sealed class AMQUInt16Type : AMQType
+ {
+ public AMQUInt16Type()
+ : base('S')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedUnsignedShortLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToUInt16(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadUnsignedShort(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteUnsignedShort(buffer, (ushort)value);
+ }
+ }
+
+ sealed class AMQInt32Type : AMQType
+ {
+ public AMQInt32Type() : base('I')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedIntegerLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToInt32(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadInteger(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteInteger(buffer, (int)value);
+ }
+ }
+
+ sealed class AMQInt64Type : AMQType
+ {
+ public AMQInt64Type() : base('l')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedLongLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToInt64(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadLong(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteLong(buffer, (long)value);
+ }
+ }
+
+ sealed class AMQUInt64Type : AMQType
+ {
+ public AMQUInt64Type()
+ : base('L')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedUnsignedLongLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToUInt64(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadUnsignedLong(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteUnsignedLong(buffer, (ulong)value);
+ }
+ }
+
+ sealed class AMQFloatType : AMQType
+ {
+ public AMQFloatType() : base('f')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedFloatLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToSingle(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadFloat(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteFloat(buffer, (float)value);
+ }
+ }
+
+ sealed class AMQDoubleType : AMQType
+ {
+ public AMQDoubleType() : base('d')
+ {
+ }
+
+ public override uint GetEncodingSize(object value)
+ {
+ return EncodingUtils.EncodedDoubleLength();
+ }
+
+ public override object ToNativeValue(object value)
+ {
+ return Convert.ToDouble(value);
+ }
+
+ public override object ReadValueFromBuffer(ByteBuffer buffer)
+ {
+ return EncodingUtils.ReadDouble(buffer);
+ }
+
+ protected override void WriteValueImpl(object value, ByteBuffer buffer)
+ {
+ EncodingUtils.WriteDouble(buffer, (double)value);
+ }
+ }
+
+ #endregion // Type Implementation
+
+ } // class AMQType
+}
diff --git a/dotnet/Qpid.Common/Framing/AMQTypeMap.cs b/dotnet/Qpid.Common/Framing/AMQTypeMap.cs
index ed38c203a9..8497c283f9 100644
--- a/dotnet/Qpid.Common/Framing/AMQTypeMap.cs
+++ b/dotnet/Qpid.Common/Framing/AMQTypeMap.cs
@@ -1,75 +1,75 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Collections;
-
-namespace Apache.Qpid.Framing
-{
- public sealed class AMQTypeMap
- {
- private static Hashtable _reverseTypeMap;
-
- private AMQTypeMap()
- {
- }
-
- static AMQTypeMap()
- {
- _reverseTypeMap = Hashtable.Synchronized(new Hashtable());
-
- Add(AMQType.LONG_STRING);
- Add(AMQType.BOOLEAN);
- Add(AMQType.BYTE);
- Add(AMQType.SBYTE);
- Add(AMQType.INT16);
- // not supported for now as type code conflicts
- // with LONG_STRING
- //Add(AMQType.UINT16);
- Add(AMQType.INT32);
- Add(AMQType.UINT32);
- Add(AMQType.INT64);
- Add(AMQType.UINT64);
- Add(AMQType.FLOAT);
- Add(AMQType.DOUBLE);
- Add(AMQType.DECIMAL);
- Add(AMQType.BINARY);
- Add(AMQType.ASCII_STRING);
- Add(AMQType.WIDE_STRING);
- Add(AMQType.ASCII_CHARACTER);
- Add(AMQType.TIMESTAMP);
- Add(AMQType.FIELD_TABLE);
- Add(AMQType.VOID);
- }
-
- public static AMQType GetType(byte identifier)
- {
- AMQType type = (AMQType)_reverseTypeMap[identifier];
- if ( type == null )
- throw new ArgumentOutOfRangeException(string.Format("No such type code: {0:x}", identifier));
- return type;
- }
-
- private static void Add(AMQType type)
- {
- _reverseTypeMap.Add(type.Identifier, type);
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Collections;
+
+namespace Apache.Qpid.Framing
+{
+ public sealed class AMQTypeMap
+ {
+ private static Hashtable _reverseTypeMap;
+
+ private AMQTypeMap()
+ {
+ }
+
+ static AMQTypeMap()
+ {
+ _reverseTypeMap = Hashtable.Synchronized(new Hashtable());
+
+ Add(AMQType.LONG_STRING);
+ Add(AMQType.BOOLEAN);
+ Add(AMQType.BYTE);
+ Add(AMQType.SBYTE);
+ Add(AMQType.INT16);
+ // not supported for now as type code conflicts
+ // with LONG_STRING
+ //Add(AMQType.UINT16);
+ Add(AMQType.INT32);
+ Add(AMQType.UINT32);
+ Add(AMQType.INT64);
+ Add(AMQType.UINT64);
+ Add(AMQType.FLOAT);
+ Add(AMQType.DOUBLE);
+ Add(AMQType.DECIMAL);
+ Add(AMQType.BINARY);
+ Add(AMQType.ASCII_STRING);
+ Add(AMQType.WIDE_STRING);
+ Add(AMQType.ASCII_CHARACTER);
+ Add(AMQType.TIMESTAMP);
+ Add(AMQType.FIELD_TABLE);
+ Add(AMQType.VOID);
+ }
+
+ public static AMQType GetType(byte identifier)
+ {
+ AMQType type = (AMQType)_reverseTypeMap[identifier];
+ if ( type == null )
+ throw new ArgumentOutOfRangeException(string.Format("No such type code: {0:x}", identifier));
+ return type;
+ }
+
+ private static void Add(AMQType type)
+ {
+ _reverseTypeMap.Add(type.Identifier, type);
+ }
+ }
+}
diff --git a/dotnet/Qpid.Common/Framing/AMQTypedValue.cs b/dotnet/Qpid.Common/Framing/AMQTypedValue.cs
index 8d21a60831..3d2e313fa6 100644
--- a/dotnet/Qpid.Common/Framing/AMQTypedValue.cs
+++ b/dotnet/Qpid.Common/Framing/AMQTypedValue.cs
@@ -1,76 +1,76 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using Apache.Qpid.Buffer;
-
-namespace Apache.Qpid.Framing
-{
- public class AMQTypedValue
- {
- private readonly AMQType _type;
- private readonly object _value;
-
- public AMQType Type
- {
- get { return _type; }
- }
-
- public object Value
- {
- get { return _value; }
- }
-
- public uint EncodingLength
- {
- get { return _type.GetEncodingSize(_value); }
- }
-
- public AMQTypedValue(AMQType type, object value)
- {
- if ( type == null )
- throw new ArgumentNullException("type");
- _type = type;
- _value = type.ToNativeValue(value);
- }
-
- public AMQTypedValue(AMQType type, ByteBuffer buffer)
- {
- _type = type;
- _value = type.ReadValueFromBuffer(buffer);
- }
-
- public void WriteToBuffer(ByteBuffer buffer)
- {
- _type.WriteToBuffer(_value, buffer);
- }
-
- public static AMQTypedValue ReadFromBuffer(ByteBuffer buffer)
- {
- AMQType type = AMQTypeMap.GetType(buffer.GetByte());
- return new AMQTypedValue(type, buffer);
- }
-
- public override string ToString()
- {
- return string.Format("{0}: {1}", Type, Value);
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using Apache.Qpid.Buffer;
+
+namespace Apache.Qpid.Framing
+{
+ public class AMQTypedValue
+ {
+ private readonly AMQType _type;
+ private readonly object _value;
+
+ public AMQType Type
+ {
+ get { return _type; }
+ }
+
+ public object Value
+ {
+ get { return _value; }
+ }
+
+ public uint EncodingLength
+ {
+ get { return _type.GetEncodingSize(_value); }
+ }
+
+ public AMQTypedValue(AMQType type, object value)
+ {
+ if ( type == null )
+ throw new ArgumentNullException("type");
+ _type = type;
+ _value = type.ToNativeValue(value);
+ }
+
+ public AMQTypedValue(AMQType type, ByteBuffer buffer)
+ {
+ _type = type;
+ _value = type.ReadValueFromBuffer(buffer);
+ }
+
+ public void WriteToBuffer(ByteBuffer buffer)
+ {
+ _type.WriteToBuffer(_value, buffer);
+ }
+
+ public static AMQTypedValue ReadFromBuffer(ByteBuffer buffer)
+ {
+ AMQType type = AMQTypeMap.GetType(buffer.GetByte());
+ return new AMQTypedValue(type, buffer);
+ }
+
+ public override string ToString()
+ {
+ return string.Format("{0}: {1}", Type, Value);
+ }
+ }
+}
diff --git a/dotnet/Qpid.Common/Properties/AssemblyInfo.cs b/dotnet/Qpid.Common/Properties/AssemblyInfo.cs
index 3d3f444f3e..3847429519 100644
--- a/dotnet/Qpid.Common/Properties/AssemblyInfo.cs
+++ b/dotnet/Qpid.Common/Properties/AssemblyInfo.cs
@@ -49,4 +49,4 @@ using System.Runtime.InteropServices;
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
-[assembly: AssemblyVersion("2.1.0.0")]
+[assembly: AssemblyVersion("0.5.0.0")]
diff --git a/dotnet/Qpid.Common/Protocol/AMQConstant.cs b/dotnet/Qpid.Common/Protocol/AMQConstant.cs
index fcf94c29f4..9400b1bd80 100644
--- a/dotnet/Qpid.Common/Protocol/AMQConstant.cs
+++ b/dotnet/Qpid.Common/Protocol/AMQConstant.cs
@@ -1,100 +1,100 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Collections;
-
-namespace Apache.Qpid.Protocol
-{
- public sealed class AMQConstant
- {
- private int _code;
- private string _name;
- private static Hashtable _codeMap = new Hashtable();
-
- public int Code
- {
- get { return _code; }
- }
-
- public string Name
- {
- get { return _name; }
- }
-
- private AMQConstant(int code, string name, bool map)
- {
- _code = code;
- _name = name;
-
- if ( map )
- {
- _codeMap.Add(code, this);
- }
- }
-
- public override string ToString()
- {
- return string.Format("{0}: {1}", Code, Name);
- }
-
- public static AMQConstant GetConstant(int code)
- {
- AMQConstant c = (AMQConstant)_codeMap[code];
- if ( c == null )
- {
- c = new AMQConstant(code, "unknown code", false);
- }
- return c;
- }
-
- #region Constants
- //
- // Constants
- //
- public static readonly AMQConstant FRAME_MIN_SIZE = new AMQConstant(4096, "frame min size", true);
- public static readonly AMQConstant FRAME_END = new AMQConstant(206, "frame end", true);
- public static readonly AMQConstant REPLY_SUCCESS = new AMQConstant(200, "reply success", true);
- public static readonly AMQConstant NOT_DELIVERED = new AMQConstant(310, "not delivered", true);
- public static readonly AMQConstant MESSAGE_TOO_LARGE = new AMQConstant(311, "message too large", true);
- public static readonly AMQConstant NO_ROUTE = new AMQConstant(312, "no route", true);
- public static readonly AMQConstant NO_CONSUMERS = new AMQConstant(313, "no consumers", true);
- public static readonly AMQConstant CONTEXT_IN_USE = new AMQConstant(320, "context in use", true);
- public static readonly AMQConstant INVALID_PATH = new AMQConstant(402, "invalid path", true);
- public static readonly AMQConstant ACCESS_REFUSED = new AMQConstant(403, "access refused", true);
- public static readonly AMQConstant NOT_FOUND = new AMQConstant(404, "not found", true);
- public static readonly AMQConstant ALREADY_EXISTS = new AMQConstant(405, "already exists", true);
- public static readonly AMQConstant IN_USE = new AMQConstant(406, "in use", true);
- public static readonly AMQConstant INVALID_ROUTING_KEY = new AMQConstant(407, "routing key invalid", true);
- public static readonly AMQConstant REQUEST_TIMEOUT = new AMQConstant(408, "request timeout", true);
- public static readonly AMQConstant INVALID_ARGUMENT = new AMQConstant(409, "argument invalid", true);
- public static readonly AMQConstant FRAME_ERROR = new AMQConstant(501, "frame error", true);
- public static readonly AMQConstant SYNTAX_ERROR = new AMQConstant(502, "syntax error", true);
- public static readonly AMQConstant COMMAND_INVALID = new AMQConstant(503, "command invalid", true);
- public static readonly AMQConstant CHANNEL_ERROR = new AMQConstant(504, "channel error", true);
- public static readonly AMQConstant RESOURCE_ERROR = new AMQConstant(506, "resource error", true);
- public static readonly AMQConstant NOT_ALLOWED = new AMQConstant(530, "not allowed", true);
- public static readonly AMQConstant NOT_IMPLEMENTED = new AMQConstant(540, "not implemented", true);
- public static readonly AMQConstant INTERNAL_ERROR = new AMQConstant(541, "internal error", true);
-
- #endregion // Constants
-
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Collections;
+
+namespace Apache.Qpid.Protocol
+{
+ public sealed class AMQConstant
+ {
+ private int _code;
+ private string _name;
+ private static Hashtable _codeMap = new Hashtable();
+
+ public int Code
+ {
+ get { return _code; }
+ }
+
+ public string Name
+ {
+ get { return _name; }
+ }
+
+ private AMQConstant(int code, string name, bool map)
+ {
+ _code = code;
+ _name = name;
+
+ if ( map )
+ {
+ _codeMap.Add(code, this);
+ }
+ }
+
+ public override string ToString()
+ {
+ return string.Format("{0}: {1}", Code, Name);
+ }
+
+ public static AMQConstant GetConstant(int code)
+ {
+ AMQConstant c = (AMQConstant)_codeMap[code];
+ if ( c == null )
+ {
+ c = new AMQConstant(code, "unknown code", false);
+ }
+ return c;
+ }
+
+ #region Constants
+ //
+ // Constants
+ //
+ public static readonly AMQConstant FRAME_MIN_SIZE = new AMQConstant(4096, "frame min size", true);
+ public static readonly AMQConstant FRAME_END = new AMQConstant(206, "frame end", true);
+ public static readonly AMQConstant REPLY_SUCCESS = new AMQConstant(200, "reply success", true);
+ public static readonly AMQConstant NOT_DELIVERED = new AMQConstant(310, "not delivered", true);
+ public static readonly AMQConstant MESSAGE_TOO_LARGE = new AMQConstant(311, "message too large", true);
+ public static readonly AMQConstant NO_ROUTE = new AMQConstant(312, "no route", true);
+ public static readonly AMQConstant NO_CONSUMERS = new AMQConstant(313, "no consumers", true);
+ public static readonly AMQConstant CONTEXT_IN_USE = new AMQConstant(320, "context in use", true);
+ public static readonly AMQConstant INVALID_PATH = new AMQConstant(402, "invalid path", true);
+ public static readonly AMQConstant ACCESS_REFUSED = new AMQConstant(403, "access refused", true);
+ public static readonly AMQConstant NOT_FOUND = new AMQConstant(404, "not found", true);
+ public static readonly AMQConstant ALREADY_EXISTS = new AMQConstant(405, "already exists", true);
+ public static readonly AMQConstant IN_USE = new AMQConstant(406, "in use", true);
+ public static readonly AMQConstant INVALID_ROUTING_KEY = new AMQConstant(407, "routing key invalid", true);
+ public static readonly AMQConstant REQUEST_TIMEOUT = new AMQConstant(408, "request timeout", true);
+ public static readonly AMQConstant INVALID_ARGUMENT = new AMQConstant(409, "argument invalid", true);
+ public static readonly AMQConstant FRAME_ERROR = new AMQConstant(501, "frame error", true);
+ public static readonly AMQConstant SYNTAX_ERROR = new AMQConstant(502, "syntax error", true);
+ public static readonly AMQConstant COMMAND_INVALID = new AMQConstant(503, "command invalid", true);
+ public static readonly AMQConstant CHANNEL_ERROR = new AMQConstant(504, "channel error", true);
+ public static readonly AMQConstant RESOURCE_ERROR = new AMQConstant(506, "resource error", true);
+ public static readonly AMQConstant NOT_ALLOWED = new AMQConstant(530, "not allowed", true);
+ public static readonly AMQConstant NOT_IMPLEMENTED = new AMQConstant(540, "not implemented", true);
+ public static readonly AMQConstant INTERNAL_ERROR = new AMQConstant(541, "internal error", true);
+
+ #endregion // Constants
+
+ }
+}
diff --git a/dotnet/Qpid.Common/Qpid.Common.csproj b/dotnet/Qpid.Common/Qpid.Common.csproj
index 0b6b1698e5..09f0a96ba9 100644
--- a/dotnet/Qpid.Common/Qpid.Common.csproj
+++ b/dotnet/Qpid.Common/Qpid.Common.csproj
@@ -1,4 +1,25 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@@ -12,6 +33,11 @@
<SignAssembly>false</SignAssembly>
<AssemblyOriginatorKeyFile>
</AssemblyOriginatorKeyFile>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -40,142 +66,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
- <Compile Include="AMQChannelClosedException.cs" />
- <Compile Include="AMQConnectionClosedException.cs" />
- <Compile Include="AMQDisconnectedException.cs" />
- <Compile Include="AMQException.cs" />
- <Compile Include="AMQInvalidArgumentException.cs" />
- <Compile Include="AMQInvalidRoutingKeyException.cs" />
- <Compile Include="AMQUndeliveredException.cs" />
- <Compile Include="AssemblySettings.cs" />
- <Compile Include="Collections\LinkedHashtable.cs" />
- <Compile Include="Collections\ConsumerProducerQueue.cs" />
- <Compile Include="Framing\AMQDataBlockDecoder.cs" />
- <Compile Include="Framing\AMQDataBlockEncoder.cs" />
- <Compile Include="Framing\AMQFrame.cs" />
- <Compile Include="Framing\AMQMethodBody.cs" />
- <Compile Include="Framing\AMQMethodBodyFactory.cs" />
- <Compile Include="Framing\AMQProtocolHeaderException.cs" />
- <Compile Include="Framing\AMQType.cs" />
- <Compile Include="Framing\BasicContentHeaderProperties.cs" />
- <Compile Include="Framing\CompositeAMQDataBlock.cs" />
- <Compile Include="Framing\ContentBody.cs" />
- <Compile Include="Framing\ContentBodyFactory.cs" />
- <Compile Include="Framing\ContentHeaderBody.cs" />
- <Compile Include="Framing\ContentHeaderBodyFactory.cs" />
- <Compile Include="Framing\ContentHeaderPropertiesFactory.cs" />
- <Compile Include="Framing\AMQTypedValue.cs" />
- <Compile Include="Framing\AMQTypeMap.cs" />
- <Compile Include="Framing\EncodingUtils.cs" />
- <Compile Include="Framing\FieldTable.cs" />
- <Compile Include="Framing\HeartbeatBody.cs" />
- <Compile Include="Framing\HeartbeatBodyFactory.cs" />
- <Compile Include="Framing\IBody.cs" />
- <Compile Include="Framing\IDataBlock.cs" />
- <Compile Include="Framing\AMQFrameDecodingException.cs" />
- <Compile Include="Framing\IEncodableAMQDataBlock.cs" />
- <Compile Include="Framing\IBodyFactory.cs" />
- <Compile Include="Framing\IContentHeaderProperties.cs" />
- <Compile Include="Framing\ProtocolInitiation.cs" />
- <Compile Include="generated\AccessRequestBody.cs" />
- <Compile Include="generated\AccessRequestOkBody.cs" />
- <Compile Include="generated\BasicAckBody.cs" />
- <Compile Include="generated\BasicCancelBody.cs" />
- <Compile Include="generated\BasicCancelOkBody.cs" />
- <Compile Include="generated\BasicConsumeBody.cs" />
- <Compile Include="generated\BasicConsumeOkBody.cs" />
- <Compile Include="generated\BasicDeliverBody.cs" />
- <Compile Include="generated\BasicGetBody.cs" />
- <Compile Include="generated\BasicGetEmptyBody.cs" />
- <Compile Include="generated\BasicGetOkBody.cs" />
- <Compile Include="generated\BasicPublishBody.cs" />
- <Compile Include="generated\BasicQosBody.cs" />
- <Compile Include="generated\BasicQosOkBody.cs" />
- <Compile Include="generated\BasicRecoverBody.cs" />
- <Compile Include="generated\BasicRecoverOkBody.cs" />
- <Compile Include="generated\BasicRejectBody.cs" />
- <Compile Include="generated\BasicReturnBody.cs" />
- <Compile Include="generated\ChannelAlertBody.cs" />
- <Compile Include="generated\ChannelCloseBody.cs" />
- <Compile Include="generated\ChannelCloseOkBody.cs" />
- <Compile Include="generated\ChannelFlowBody.cs" />
- <Compile Include="generated\ChannelFlowOkBody.cs" />
- <Compile Include="generated\ChannelOpenBody.cs" />
- <Compile Include="generated\ChannelOpenOkBody.cs" />
- <Compile Include="generated\ConnectionCloseBody.cs" />
- <Compile Include="generated\ConnectionCloseOkBody.cs" />
- <Compile Include="generated\ConnectionOpenBody.cs" />
- <Compile Include="generated\ConnectionOpenOkBody.cs" />
- <Compile Include="generated\ConnectionRedirectBody.cs" />
- <Compile Include="generated\ConnectionSecureBody.cs" />
- <Compile Include="generated\ConnectionSecureOkBody.cs" />
- <Compile Include="generated\ConnectionStartBody.cs" />
- <Compile Include="generated\ConnectionStartOkBody.cs" />
- <Compile Include="generated\ConnectionTuneBody.cs" />
- <Compile Include="generated\ConnectionTuneOkBody.cs" />
- <Compile Include="generated\DtxSelectBody.cs" />
- <Compile Include="generated\DtxSelectOkBody.cs" />
- <Compile Include="generated\DtxStartBody.cs" />
- <Compile Include="generated\DtxStartOkBody.cs" />
- <Compile Include="generated\ExchangeBoundBody.cs" />
- <Compile Include="generated\ExchangeBoundOkBody.cs" />
- <Compile Include="generated\ExchangeDeclareBody.cs" />
- <Compile Include="generated\ExchangeDeclareOkBody.cs" />
- <Compile Include="generated\ExchangeDeleteBody.cs" />
- <Compile Include="generated\ExchangeDeleteOkBody.cs" />
- <Compile Include="generated\FileAckBody.cs" />
- <Compile Include="generated\FileCancelBody.cs" />
- <Compile Include="generated\FileCancelOkBody.cs" />
- <Compile Include="generated\FileConsumeBody.cs" />
- <Compile Include="generated\FileConsumeOkBody.cs" />
- <Compile Include="generated\FileDeliverBody.cs" />
- <Compile Include="generated\FileOpenBody.cs" />
- <Compile Include="generated\FileOpenOkBody.cs" />
- <Compile Include="generated\FilePublishBody.cs" />
- <Compile Include="generated\FileQosBody.cs" />
- <Compile Include="generated\FileQosOkBody.cs" />
- <Compile Include="generated\FileRejectBody.cs" />
- <Compile Include="generated\FileReturnBody.cs" />
- <Compile Include="generated\FileStageBody.cs" />
- <Compile Include="generated\MainRegistry.cs" />
- <Compile Include="generated\MethodBodyDecoderRegistry.cs" />
- <Compile Include="generated\QueueBindBody.cs" />
- <Compile Include="generated\QueueBindOkBody.cs" />
- <Compile Include="generated\QueueDeclareBody.cs" />
- <Compile Include="generated\QueueDeclareOkBody.cs" />
- <Compile Include="generated\QueueDeleteBody.cs" />
- <Compile Include="generated\QueueDeleteOkBody.cs" />
- <Compile Include="generated\QueuePurgeBody.cs" />
- <Compile Include="generated\QueuePurgeOkBody.cs" />
- <Compile Include="generated\StreamCancelBody.cs" />
- <Compile Include="generated\StreamCancelOkBody.cs" />
- <Compile Include="generated\StreamConsumeBody.cs" />
- <Compile Include="generated\StreamConsumeOkBody.cs" />
- <Compile Include="generated\StreamDeliverBody.cs" />
- <Compile Include="generated\StreamPublishBody.cs" />
- <Compile Include="generated\StreamQosBody.cs" />
- <Compile Include="generated\StreamQosOkBody.cs" />
- <Compile Include="generated\StreamReturnBody.cs" />
- <Compile Include="generated\TestContentBody.cs" />
- <Compile Include="generated\TestContentOkBody.cs" />
- <Compile Include="generated\TestIntegerBody.cs" />
- <Compile Include="generated\TestIntegerOkBody.cs" />
- <Compile Include="generated\TestStringBody.cs" />
- <Compile Include="generated\TestStringOkBody.cs" />
- <Compile Include="generated\TestTableBody.cs" />
- <Compile Include="generated\TestTableOkBody.cs" />
- <Compile Include="generated\TunnelRequestBody.cs" />
- <Compile Include="generated\TxCommitBody.cs" />
- <Compile Include="generated\TxCommitOkBody.cs" />
- <Compile Include="generated\TxRollbackBody.cs" />
- <Compile Include="generated\TxRollbackOkBody.cs" />
- <Compile Include="generated\TxSelectBody.cs" />
- <Compile Include="generated\TxSelectOkBody.cs" />
- <Compile Include="Collections\BlockingQueue.cs" />
- <Compile Include="Collections\LinkedBlockingQueue.cs" />
- <Compile Include="Collections\SynchronousQueue.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="Protocol\AMQConstant.cs" />
+ <Compile Include="**\*.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Qpid.Buffer\Qpid.Buffer.csproj">
@@ -210,4 +101,4 @@
<Target Name="AfterBuild">
</Target>
-->
-</Project> \ No newline at end of file
+</Project>
diff --git a/dotnet/Qpid.Common/amqp.xml b/dotnet/Qpid.Common/amqp.xml
index 8ad0f17a2c..ddd4b5be4b 100644
--- a/dotnet/Qpid.Common/amqp.xml
+++ b/dotnet/Qpid.Common/amqp.xml
@@ -1,4 +1,25 @@
<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
<!--
Copyright Notice
diff --git a/dotnet/Qpid.Common/build.xml b/dotnet/Qpid.Common/build.xml
index b6a8fb63b9..96dd877722 100644
--- a/dotnet/Qpid.Common/build.xml
+++ b/dotnet/Qpid.Common/build.xml
@@ -1,4 +1,26 @@
<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+
+<!--
This sole purpose of this build script is to generate the framing layer for the .net client from the AMQ spec.
-->
<project name="AMQ Dot Net Framing Layer" default="generate">
diff --git a/dotnet/Qpid.Common/default.build b/dotnet/Qpid.Common/default.build
index 36055b9ca9..df07397d0b 100644
--- a/dotnet/Qpid.Common/default.build
+++ b/dotnet/Qpid.Common/default.build
@@ -1,4 +1,25 @@
<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
<project name="Apache.Qpid.Common" default="build">
<!--
Properties that come from master build file
diff --git a/dotnet/Qpid.Common/lib/log4net/log4net.xml b/dotnet/Qpid.Common/lib/log4net/log4net.xml
index b8fd000170..5beb669ab0 100644
--- a/dotnet/Qpid.Common/lib/log4net/log4net.xml
+++ b/dotnet/Qpid.Common/lib/log4net/log4net.xml
@@ -1,4 +1,25 @@
<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
<doc>
<assembly>
<name>log4net</name>
diff --git a/dotnet/Qpid.Common/stylesheets/csharp.xsl b/dotnet/Qpid.Common/stylesheets/csharp.xsl
index 674c971559..ed04a40403 100644
--- a/dotnet/Qpid.Common/stylesheets/csharp.xsl
+++ b/dotnet/Qpid.Common/stylesheets/csharp.xsl
@@ -1,4 +1,25 @@
<?xml version='1.0'?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amq="http://amq.org">
<!-- this class contains the templates for generating C# source code for a given framing model -->
diff --git a/dotnet/Qpid.Common/stylesheets/framing.xsl b/dotnet/Qpid.Common/stylesheets/framing.xsl
index e015d4c40b..119f439599 100644
--- a/dotnet/Qpid.Common/stylesheets/framing.xsl
+++ b/dotnet/Qpid.Common/stylesheets/framing.xsl
@@ -1,4 +1,25 @@
<?xml version='1.0'?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amq="http://amq.org">
<xsl:import href="prepare1.xsl"/>
diff --git a/dotnet/Qpid.Common/stylesheets/java.xsl b/dotnet/Qpid.Common/stylesheets/java.xsl
index f9904c9e94..7297c6ae62 100644
--- a/dotnet/Qpid.Common/stylesheets/java.xsl
+++ b/dotnet/Qpid.Common/stylesheets/java.xsl
@@ -1,4 +1,25 @@
<?xml version='1.0'?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amq="http://amq.org">
<!-- this class contains the templates for generating java source code for a given framing model -->
diff --git a/dotnet/Qpid.Common/stylesheets/prepare1.xsl b/dotnet/Qpid.Common/stylesheets/prepare1.xsl
index 9661fb47f6..e266b0a9cc 100644
--- a/dotnet/Qpid.Common/stylesheets/prepare1.xsl
+++ b/dotnet/Qpid.Common/stylesheets/prepare1.xsl
@@ -1,4 +1,25 @@
<?xml version='1.0'?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amq="http://amq.org">
<xsl:import href="utils.xsl"/>
diff --git a/dotnet/Qpid.Common/stylesheets/prepare2.xsl b/dotnet/Qpid.Common/stylesheets/prepare2.xsl
index d98365d1f3..0a64eb6f86 100644
--- a/dotnet/Qpid.Common/stylesheets/prepare2.xsl
+++ b/dotnet/Qpid.Common/stylesheets/prepare2.xsl
@@ -1,4 +1,25 @@
<?xml version='1.0'?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amq="http://amq.org">
<xsl:import href="utils.xsl"/>
diff --git a/dotnet/Qpid.Common/stylesheets/prepare3.xsl b/dotnet/Qpid.Common/stylesheets/prepare3.xsl
index 92a2648cd6..a921160dd0 100644
--- a/dotnet/Qpid.Common/stylesheets/prepare3.xsl
+++ b/dotnet/Qpid.Common/stylesheets/prepare3.xsl
@@ -1,4 +1,25 @@
<?xml version='1.0'?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amq="http://amq.org">
<xsl:import href="utils.xsl"/>
diff --git a/dotnet/Qpid.Common/stylesheets/registry.xsl b/dotnet/Qpid.Common/stylesheets/registry.xsl
index ae2a25a792..47a2a29069 100644
--- a/dotnet/Qpid.Common/stylesheets/registry.xsl
+++ b/dotnet/Qpid.Common/stylesheets/registry.xsl
@@ -1,4 +1,25 @@
<?xml version='1.0'?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amq="http://amq.org">
<xsl:import href="csharp.xsl"/>
diff --git a/dotnet/Qpid.Common/stylesheets/utils.xsl b/dotnet/Qpid.Common/stylesheets/utils.xsl
index 422b757b5c..d097bbc4eb 100644
--- a/dotnet/Qpid.Common/stylesheets/utils.xsl
+++ b/dotnet/Qpid.Common/stylesheets/utils.xsl
@@ -1,4 +1,25 @@
<?xml version='1.0'?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amq="http://amq.org">
<!-- This file contains functions that are used in the generation of the java classes for framing -->
diff --git a/dotnet/Qpid.Integration.Tests/Properties/AssemblyInfo.cs b/dotnet/Qpid.Integration.Tests/Properties/AssemblyInfo.cs
index a11c78b1d9..e19650559f 100644
--- a/dotnet/Qpid.Integration.Tests/Properties/AssemblyInfo.cs
+++ b/dotnet/Qpid.Integration.Tests/Properties/AssemblyInfo.cs
@@ -1,53 +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.
- *
- */
-using System.Reflection;
-using System.Runtime.InteropServices;
-using log4net.Config;
-[assembly: XmlConfigurator(ConfigFile="log4net.config")]
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Apache.Qpid.Integration.Tests")]
-[assembly: AssemblyDescription("Built from svn revision number: ")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Apache Software Foundation")]
-[assembly: AssemblyProduct("Apache.Qpid.Integration.Tests")]
-[assembly: AssemblyCopyright("Apache Software Foundation")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("7ebdea21-1352-4673-b66e-fdc0beff461f")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-[assembly: AssemblyVersion("2.1.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.
+ *
+ */
+using System.Reflection;
+using System.Runtime.InteropServices;
+using log4net.Config;
+[assembly: XmlConfigurator(ConfigFile="log4net.config")]
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Apache.Qpid.Integration.Tests")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("Apache.Qpid.Integration.Tests")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("7ebdea21-1352-4673-b66e-fdc0beff461f")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("0.5.0.0")]
diff --git a/dotnet/Qpid.Integration.Tests/Qpid.Integration.Tests.csproj b/dotnet/Qpid.Integration.Tests/Qpid.Integration.Tests.csproj
index 51d91f2bd3..e7d6e59cf5 100755
--- a/dotnet/Qpid.Integration.Tests/Qpid.Integration.Tests.csproj
+++ b/dotnet/Qpid.Integration.Tests/Qpid.Integration.Tests.csproj
@@ -1,65 +1,124 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <PropertyGroup>
- <ProjectGuid>{DE21CEBC-F38C-43EA-B576-38CA9738A00A}</ProjectGuid>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <OutputType>Library</OutputType>
- <RootNamespace>Qpid.Integration.Tests</RootNamespace>
- <AssemblyName>Qpid.Integration.Tests</AssemblyName>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
- <OutputPath>bin\Debug\</OutputPath>
- <DebugSymbols>True</DebugSymbols>
- <DebugType>Full</DebugType>
- <Optimize>False</Optimize>
- <CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
- <OutputPath>bin\Release\</OutputPath>
- <DebugSymbols>False</DebugSymbols>
- <DebugType>None</DebugType>
- <Optimize>True</Optimize>
- <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
- <DefineConstants>TRACE</DefineConstants>
- </PropertyGroup>
- <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
- <ItemGroup>
- <Reference Include="System" />
- <Reference Include="System.Xml" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="framework\Circuit.cs" />
- <Compile Include="framework\FrameworkBaseCase.cs" />
- <Compile Include="framework\Publisher.cs" />
- <Compile Include="framework\Receiver.cs" />
- <Compile Include="framework\TestClientDetails.cs" />
- <Compile Include="framework\TestModel.cs" />
- <Compile Include="interactive\SendReceiveTest.cs" />
- <Compile Include="interop\InteropClientTestCase.cs" />
- <Compile Include="interop\TestCases\TestCase1DummyRun.cs" />
- <Compile Include="interop\TestCases\TestCase3BasicPubSub.cs" />
- <Compile Include="testcases\BaseMessagingTestFixture.cs" />
- <Compile Include="testcases\ChannelQueueTest.cs" />
- <Compile Include="testcases\CommitRollbackTest.cs" />
- <Compile Include="testcases\ConnectionTest.cs" />
- <Compile Include="testcases\DurableSubscriptionTest.cs" />
- <Compile Include="testcases\HeadersExchangeTest.cs" />
- <Compile Include="testcases\MandatoryMessageTest.cs" />
- <Compile Include="testcases\ProducerMultiConsumerTest.cs" />
- <Compile Include="testcases\SslConnectionTest.cs" />
- <Compile Include="testcases\SustainedTest.cs" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="framework\Assertion.cs" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="interactive\FailoverTest.cs" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="interop\TestClient.cs" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="interop\TestCases\TestCase2BasicP2P.cs" />
- </ItemGroup>
-</Project> \ No newline at end of file
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <ProjectGuid>{DE21CEBC-F38C-43EA-B576-38CA9738A00A}</ProjectGuid>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <OutputType>Library</OutputType>
+ <RootNamespace>Qpid.Integration.Tests</RootNamespace>
+ <AssemblyName>Qpid.Integration.Tests</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ <PublishUrl>http://localhost/Qpid.Integration.Tests/</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Web</InstallFrom>
+ <UpdateEnabled>true</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <IsWebBootstrapper>true</IsWebBootstrapper>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+ <OutputPath>bin\Debug\</OutputPath>
+ <DebugSymbols>True</DebugSymbols>
+ <DebugType>Full</DebugType>
+ <Optimize>False</Optimize>
+ <CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
+ <OutputPath>bin\Release\</OutputPath>
+ <DebugSymbols>False</DebugSymbols>
+ <DebugType>None</DebugType>
+ <Optimize>True</Optimize>
+ <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
+ <DefineConstants>TRACE</DefineConstants>
+ </PropertyGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
+ <ItemGroup>
+ <Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\client-010\lib\log4net\log4net.dll</HintPath>
+ </Reference>
+ <Reference Include="nunit.framework, Version=2.2.8.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\client-010\lib\nunit\nunit.framework.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="**\*.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Qpid.Client\Qpid.Client.csproj">
+ <Project>{68987C05-3768-452C-A6FC-6BA1D372852F}</Project>
+ <Name>Qpid.Client</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Common\Qpid.Common.csproj">
+ <Project>{77064C42-24D2-4CEB-9EA2-0EF481A43205}</Project>
+ <Name>Qpid.Common</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Messaging\Qpid.Messaging.csproj">
+ <Project>{6688F826-C58E-4C1B-AA1F-22AFAB4B7D07}</Project>
+ <Name>Qpid.Messaging</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework Client Profile</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 2.0 %28x86%29</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.0 %28x86%29</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+</Project>
diff --git a/dotnet/Qpid.Integration.Tests/default.build b/dotnet/Qpid.Integration.Tests/default.build
index 36c28dc1d7..187aa15894 100644
--- a/dotnet/Qpid.Integration.Tests/default.build
+++ b/dotnet/Qpid.Integration.Tests/default.build
@@ -1,48 +1,69 @@
-<?xml version="1.0"?>
-<project name="Apache.Qpid.Integration.Tests" default="test">
-
- <!-- Creates a .dll for this module. -->
- <target name="build">
-
- <csc target="library"
- define="${build.defines}"
- warnaserror="false"
- debug="${build.debug}"
- output="${build.dir}/${project::get-name()}.dll">
-
- <sources>
- <include name="**/*.cs" />
- </sources>
-
- <references>
- <include name="${build.dir}/log4net.dll" />
- <include name="${build.dir}/nunit.framework.dll" />
- <include name="${build.dir}/Apache.Qpid.Common.dll" />
- <include name="${build.dir}/Apache.Qpid.Messaging.dll" />
- <include name="${build.dir}/Apache.Qpid.Client.dll" />
- <include name="${build.dir}/Apache.Qpid.Sasl.dll" />
- </references>
- </csc>
-
- <!--<copy tofile="${build.dir}/${project::get-name()}.dll.config" file="App.config" />-->
- <copy todir="${build.dir}" file="log4net.config"/>
-
- </target>
-
- <!-- Runs all of the tests in this module. -->
- <target name="test" depends="build">
- <nunit2 verbose="true">
- <formatter type="${nant.formatter}" usefile="true" outputdir="${build.dir}/testresults/" extension="txt"/>
- <formatter type="Plain" usefile="false"/>
- <test>
- <assemblies>
- <include name="${build.dir}/${project::get-name()}.dll"/>
- </assemblies>
- <categories>
- <include name="Integration"/>
- </categories>
- </test>
- </nunit2>
- </target>
-
-</project>
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="Apache.Qpid.Integration.Tests" default="test">
+
+ <!-- Creates a .dll for this module. -->
+ <target name="build">
+
+ <csc target="library"
+ define="${build.defines}"
+ warnaserror="false"
+ debug="${build.debug}"
+ output="${build.dir}/${project::get-name()}.dll">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+
+ <references>
+ <include name="${build.dir}/log4net.dll" />
+ <include name="${build.dir}/nunit.framework.dll" />
+ <include name="${build.dir}/Apache.Qpid.Common.dll" />
+ <include name="${build.dir}/Apache.Qpid.Messaging.dll" />
+ <include name="${build.dir}/Apache.Qpid.Client.dll" />
+ <include name="${build.dir}/Apache.Qpid.Sasl.dll" />
+ </references>
+ </csc>
+
+ <!--<copy tofile="${build.dir}/${project::get-name()}.dll.config" file="App.config" />-->
+ <copy todir="${build.dir}" file="log4net.config"/>
+
+ </target>
+
+ <!-- Runs all of the tests in this module. -->
+ <target name="test" depends="build">
+ <nunit2 verbose="true">
+ <formatter type="${nant.formatter}" usefile="true" outputdir="${build.dir}/testresults/" extension="txt"/>
+ <formatter type="Plain" usefile="false"/>
+ <test>
+ <assemblies>
+ <include name="${build.dir}/${project::get-name()}.dll"/>
+ </assemblies>
+ <categories>
+ <include name="Integration"/>
+ </categories>
+ </test>
+ </nunit2>
+ </target>
+
+</project>
diff --git a/dotnet/Qpid.Integration.Tests/framework/Assertion.cs b/dotnet/Qpid.Integration.Tests/framework/Assertion.cs
index fba8253251..de12de6522 100644
--- a/dotnet/Qpid.Integration.Tests/framework/Assertion.cs
+++ b/dotnet/Qpid.Integration.Tests/framework/Assertion.cs
@@ -1,39 +1,39 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-namespace Apache.Qpid.Integration.Tests.framework
-{
- /// <summary>
- /// Assertion models an assertion on a test <see cref="Circuit"/>.
- ///
- /// <p/><table id="crc"><caption>CRC Card</caption>
- /// <tr><th> Responsibilities
- /// <tr><td> Indicate whether or not the assertion passes when applied.
- /// </table>
- /// </summary>
- public interface Assertion
- {
- /// <summary>
- /// Applies the assertion.
- /// </summary>
- /// <return> <tt>true</tt> if the assertion passes, <tt>false</tt> if it fails. </return>
- bool apply();
- }
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+namespace Apache.Qpid.Integration.Tests.framework
+{
+ /// <summary>
+ /// Assertion models an assertion on a test <see cref="Circuit"/>.
+ ///
+ /// <p/><table id="crc"><caption>CRC Card</caption>
+ /// <tr><th> Responsibilities
+ /// <tr><td> Indicate whether or not the assertion passes when applied.
+ /// </table>
+ /// </summary>
+ public interface Assertion
+ {
+ /// <summary>
+ /// Applies the assertion.
+ /// </summary>
+ /// <return> <tt>true</tt> if the assertion passes, <tt>false</tt> if it fails. </return>
+ bool apply();
+ }
} \ No newline at end of file
diff --git a/dotnet/Qpid.Integration.Tests/framework/Circuit.cs b/dotnet/Qpid.Integration.Tests/framework/Circuit.cs
index d5f0ed15e2..aae9ca0496 100644
--- a/dotnet/Qpid.Integration.Tests/framework/Circuit.cs
+++ b/dotnet/Qpid.Integration.Tests/framework/Circuit.cs
@@ -1,102 +1,102 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System.Collections.Generic;//.IList;
-
-namespace Apache.Qpid.Integration.Tests.framework
-{
- /// <summary>
- /// A Circuit is the basic test unit against which test cases are to be written. A circuit consists of two 'ends', an
- /// instigating 'publisher' end and a more passive 'receivers' end.
- ///
- /// <p/>Once created, the life-cycle of a circuit may be controlled by <see cref="#start()"/>ing it, or <see cref="#close()"/>ing it.
- /// Once started, the circuit is ready to send messages over. Once closed the circuit can no longer be used.
- ///
- /// <p/>The state of the circuit may be taken with the <see cref="#check()"/> method, and asserted against by the
- /// <see cref="#applyAssertions(System.Collections.Generic.IList)"/> method.
- ///
- /// <p/>There is a default test procedure which may be performed against the circuit. The outline of this procedure is:
- ///
- /// <p/><pre>
- /// Start the circuit.
- /// Send test messages.
- /// Request a status report.
- /// Assert conditions on the publishing end of the circuit.
- /// Assert conditions on the receiving end of the circuit.
- /// Close the circuit.
- /// Pass with no failed assertions or fail with a list of failed assertions.
- /// </pre>
- ///
- /// <p/><table id="crc"><caption>CRC Card</caption>
- /// <tr><th> Responsibilities
- /// <tr><td> Supply the publishing and receiving ends of a test messaging circuit.
- /// <tr><td> Start the circuit running.
- /// <tr><td> Close the circuit down.
- /// <tr><td> Take a reading of the circuits state.
- /// <tr><td> Apply assertions against the circuits state.
- /// <tr><td> Send test messages over the circuit.
- /// <tr><td> Perform the default test procedue on the circuit.
- /// </table>
- /// </summary>
- public interface Circuit
- {
- /// <summary> Gets the interface on the publishing end of the circuit. </summary>
- ///
- /// <return> The publishing end of the circuit. </return>
- Publisher GetPublisher();
-
- /// <summary> Gets the interface on the receiving end of the circuit. </summary>
- ///
- /// <return> The receiving end of the circuit. </return>
- Receiver GetReceiver();
-
- /// <summary> Connects and starts the circuit. After this method is called the circuit is ready to send messages. </summary>
- void Start();
-
- /// <summary>
- /// Checks the test circuit. The effect of this is to gather the circuits state, for both ends of the circuit,
- /// into a report, against which assertions may be checked.
- /// </summary>
- void Check();
-
- /// <summary> Closes the circuit. All associated resources are closed. </summary>
- void Close();
-
- /// <summary>
- /// Applied a list of assertions against the test circuit. The <see cref="#check()"/> method should be called before doing
- /// this, to ensure that the circuit has gathered its state into a report to assert against.
- /// </summary>
- ///
- /// <param name="assertions"> The list of assertions to apply to the circuit. </param>
- ///
- /// <return> Any assertions that failed. </return>
- IList<Assertion> ApplyAssertions(IList<Assertion> assertions);
-
- /// <summary>
- /// Runs the default test procedure against the circuit, and checks that all of the specified assertions hold.
- /// </summary>
- ///
- /// <param name="numMessages"> The number of messages to send using the default test procedure. </param>
- /// <param name="assertions"> The list of assertions to apply. </param>
- ///
- /// <return> Any assertions that failed. </return>
- IList<Assertion> Test(int numMessages, IList<Assertion> assertions);
- }
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System.Collections.Generic;//.IList;
+
+namespace Apache.Qpid.Integration.Tests.framework
+{
+ /// <summary>
+ /// A Circuit is the basic test unit against which test cases are to be written. A circuit consists of two 'ends', an
+ /// instigating 'publisher' end and a more passive 'receivers' end.
+ ///
+ /// <p/>Once created, the life-cycle of a circuit may be controlled by <see cref="#start()"/>ing it, or <see cref="#close()"/>ing it.
+ /// Once started, the circuit is ready to send messages over. Once closed the circuit can no longer be used.
+ ///
+ /// <p/>The state of the circuit may be taken with the <see cref="#check()"/> method, and asserted against by the
+ /// <see cref="#applyAssertions(System.Collections.Generic.IList)"/> method.
+ ///
+ /// <p/>There is a default test procedure which may be performed against the circuit. The outline of this procedure is:
+ ///
+ /// <p/><pre>
+ /// Start the circuit.
+ /// Send test messages.
+ /// Request a status report.
+ /// Assert conditions on the publishing end of the circuit.
+ /// Assert conditions on the receiving end of the circuit.
+ /// Close the circuit.
+ /// Pass with no failed assertions or fail with a list of failed assertions.
+ /// </pre>
+ ///
+ /// <p/><table id="crc"><caption>CRC Card</caption>
+ /// <tr><th> Responsibilities
+ /// <tr><td> Supply the publishing and receiving ends of a test messaging circuit.
+ /// <tr><td> Start the circuit running.
+ /// <tr><td> Close the circuit down.
+ /// <tr><td> Take a reading of the circuits state.
+ /// <tr><td> Apply assertions against the circuits state.
+ /// <tr><td> Send test messages over the circuit.
+ /// <tr><td> Perform the default test procedue on the circuit.
+ /// </table>
+ /// </summary>
+ public interface Circuit
+ {
+ /// <summary> Gets the interface on the publishing end of the circuit. </summary>
+ ///
+ /// <return> The publishing end of the circuit. </return>
+ Publisher GetPublisher();
+
+ /// <summary> Gets the interface on the receiving end of the circuit. </summary>
+ ///
+ /// <return> The receiving end of the circuit. </return>
+ Receiver GetReceiver();
+
+ /// <summary> Connects and starts the circuit. After this method is called the circuit is ready to send messages. </summary>
+ void Start();
+
+ /// <summary>
+ /// Checks the test circuit. The effect of this is to gather the circuits state, for both ends of the circuit,
+ /// into a report, against which assertions may be checked.
+ /// </summary>
+ void Check();
+
+ /// <summary> Closes the circuit. All associated resources are closed. </summary>
+ void Close();
+
+ /// <summary>
+ /// Applied a list of assertions against the test circuit. The <see cref="#check()"/> method should be called before doing
+ /// this, to ensure that the circuit has gathered its state into a report to assert against.
+ /// </summary>
+ ///
+ /// <param name="assertions"> The list of assertions to apply to the circuit. </param>
+ ///
+ /// <return> Any assertions that failed. </return>
+ IList<Assertion> ApplyAssertions(IList<Assertion> assertions);
+
+ /// <summary>
+ /// Runs the default test procedure against the circuit, and checks that all of the specified assertions hold.
+ /// </summary>
+ ///
+ /// <param name="numMessages"> The number of messages to send using the default test procedure. </param>
+ /// <param name="assertions"> The list of assertions to apply. </param>
+ ///
+ /// <return> Any assertions that failed. </return>
+ IList<Assertion> Test(int numMessages, IList<Assertion> assertions);
+ }
} \ No newline at end of file
diff --git a/dotnet/Qpid.Integration.Tests/framework/FrameworkBaseCase.cs b/dotnet/Qpid.Integration.Tests/framework/FrameworkBaseCase.cs
index a7a663e531..77c1cae0ad 100644
--- a/dotnet/Qpid.Integration.Tests/framework/FrameworkBaseCase.cs
+++ b/dotnet/Qpid.Integration.Tests/framework/FrameworkBaseCase.cs
@@ -1,282 +1,282 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using log4net;
-using NUnit.Framework;
-//using org.apache.log4j.NDC;
-
-using Apache.Qpid.Integration.Tests.framework.sequencers;//.CircuitFactory;
-
-//using uk.co.thebadgerset.junit.extensions.AsymptoticTestCase;
-//using uk.co.thebadgerset.junit.extensions.SetupTaskAware;
-//using uk.co.thebadgerset.junit.extensions.SetupTaskHandler;
-//using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
-//using uk.co.thebadgerset.junit.extensions.util.TestContextProperties;
-
-//using java.util.ArrayList;
-using System.Collections.Generic;//.IList;
-
-namespace Apache.Qpid.Integration.Tests.framework
-{
- /// <summary>
- /// FrameworkBaseCase provides a starting point for writing test cases against the test framework. Its main purpose is
- /// to provide some convenience methods for testing.
- ///
- /// <p/><table id="crc"><caption>CRC Card</caption>
- /// <tr><th> Responsibilities <th> Collaborations
- /// <tr><td> Create and clean up in-vm brokers on every test case.
- /// <tr><td> Produce lists of assertions from assertion creation calls.
- /// <tr><td> Produce JUnit failures from assertion failures.
- /// <tr><td> Convert failed assertions to error messages.
- /// </table>
- /// </summary>
- public class FrameworkBaseCase //extends AsymptoticTestCase : FrameworkTestContext, SetupTaskAware, BrokerLifecycleAware
- {
- /// <summary> Used for debugging purposes. </summary>
- private static ILog log = LogManager.GetLogger(typeof(FrameworkBaseCase));
-
- /// <summary> Holds the test sequencer to create and run test circuits with. </summary>
- protected CircuitFactory circuitFactory;// = new LocalCircuitFactory();
-
- /// <summary> Used to read the tests configurable properties through. </summary>
- protected TestModel testProps;
-
- /// <summary> A default setup task processor to delegate setup tasks to. </summary>
- //protected SetupTaskHandler taskHandler = new SetupTaskHandler();
-
- /// <summary> Flag used to track whether the test is in-vm or not. </summary>
- //protected bool isUsingInVM;
-
- /// <summary> Holds the failure mechanism. </summary>
- //protected CauseFailure failureMechanism = new CauseFailureUserPrompt();
-
- /*
- /// <summary>
- /// Creates a new test case with the specified name.
- /// </summary>
- /// <param name="name"> The test case name. </param>
- public FrameworkBaseCase(string name) : base(name)
- {
- }
- */
-
- /// <summary>
- /// Returns the test case sequencer that provides test circuit, and test sequence implementations. The sequencer
- /// that this base case returns by default is suitable for running a test circuit with both circuit ends colocated
- /// on the same JVM.
- /// </summary>
- /// <return> The test case sequencer. </return>
- protected CircuitFactory GetCircuitFactory()
- {
- return circuitFactory;
- }
-
- /// <summary>
- /// Overrides the default test circuit factory. Test decorators can use this to supply distributed test sequencers or
- /// other test circuit factory specializations.
- /// </summary>
- /// <param name="circuitFactory"> The new test circuit factory. </param>
- public void SetCircuitFactory(CircuitFactory circuitFactory)
- {
- this.circuitFactory = circuitFactory;
- }
-
- /*
- /// <summary>
- /// Reports the current test case name.
- /// </summary>
- /// <return> The current test case name. </return>
- public TestCaseVector GetTestCaseVector()
- {
- return new TestCaseVector(this.getName(), 0);
- }
- */
-
- /// <summary>
- /// Reports the current test case parameters.
- /// </summary>
- /// <return> The current test case parameters. </return>
- public TestModel getTestParameters()
- {
- return testProps;
- }
-
- /// <summary>
- /// Creates a list of assertions.
- /// </summary>
- /// <param name="asserts"> The assertions to compile in a list. </param>
- ///
- /// <return> A list of assertions. </return>
- protected IList<Assertion> AssertionList(params Assertion[] asserts)
- {
- IList<Assertion> result = new List<Assertion>();
-
- foreach (Assertion assertion in asserts)
- {
- result.Add(assertion);
- }
-
- return result;
- }
-
- /// <summary>
- /// Generates a JUnit assertion exception (failure) if any assertions are passed into this method, also concatenating
- /// all of the error messages in the assertions together to form an error message to diagnose the test failure with.
- /// </summary>
- /// <param name="asserts"> The list of failed assertions. </param>
- protected static void AssertNoFailures(List<Assertion> asserts)
- {
- log.Debug("protected void assertNoFailures(List<Assertion> asserts = " + asserts + "): called");
-
- // Check if there are no assertion failures, and return without doing anything if so.
- if ((asserts == null) || (asserts.Count == 0))
- {
- return;
- }
-
- // Compile all of the assertion failure messages together.
- string errorMessage = AssertionsToString(asserts);
-
- // Fail with the error message from all of the assertions.
- Assert.Fail(errorMessage);
- }
-
- /// <summary>
- /// Converts a list of failed assertions into an error message.
- /// </summary>
- /// <param name="asserts"> The failed assertions. </param>
- ///
- /// <return> The error message. </return>
- protected static string AssertionsToString(List<Assertion> asserts)
- {
- string errorMessage = "";
-
- foreach (Assertion assertion in asserts)
- {
- errorMessage += assertion.ToString() + "\n";
- }
-
- return errorMessage;
- }
-
- /// <summary>
- /// Ensures that the in-vm broker is created and initialized.
- /// </summary>
- ///
- /// <exception cref="Exception"> Any exceptions allowed to fall through and fail the test. </exception>
- [SetUp]
- protected void SetUp()
- {
- //NDC.Push(Name);
-
- //testProps = TestContextProperties.getInstance(TestModel.defaults);
-
- // Process all optional setup tasks. This may include in-vm broker creation, if a decorator has added it.
- //taskHandler.runSetupTasks();
- }
-
- /// <summary> Ensures that the in-vm broker is cleaned up after each test run. </summary>
- [TearDown]
- protected void TearDown()
- {
- //NDC.Pop();
-
- // Process all optional tear down tasks. This may include in-vm broker clean up, if a decorator has added it.
- //taskHandler.runTearDownTasks();
- }
-
- /*
- /// <summary>
- /// Adds the specified task to the tests setup.
- /// </summary>
- /// <param name="task"> The task to add to the tests setup. </param>
- public void chainSetupTask(Runnable task)
- {
- taskHandler.chainSetupTask(task);
- }
- */
-
- /*
- /// <summary>
- /// Adds the specified task to the tests tear down.
- /// </summary>
- /// <param name="task"> The task to add to the tests tear down. </param>
- public void chainTearDownTask(Runnable task)
- {
- taskHandler.chainTearDownTask(task);
- }
- */
-
- /*
- /// <summary>
- /// Should provide a translation from the junit method name of a test to its test case name as known to the test
- /// clients that will run the test. The purpose of this is to convert the JUnit method name into the correct test
- /// case name to place into the test invite. For example the method "testP2P" might map onto the interop test case
- /// name "TC2_BasicP2P".
- /// </summary>
- /// <param name="methodName"> The name of the JUnit test method. </param>
- ///
- /// <return> The name of the corresponding interop test case. </return>
- public string getTestCaseNameForTestMethod(string methodName)
- {
- return methodName;
- }
-
- public void setInVmBrokers()
- {
- isUsingInVM = true;
- }
-
- /// <summary>
- /// Indicates whether or not a test case is using in-vm brokers.
- /// </summary>
- /// <return> <tt>true</tt> if the test is using in-vm brokers, <tt>false</tt> otherwise. </return>
- public bool usingInVmBroker()
- {
- return isUsingInVM;
- }
-
- /// <summary>
- /// Sets the currently live in-vm broker.
- /// </summary>
- /// <param name="i"> The currently live in-vm broker. </param>
- public void setLiveBroker(int i)
- { }
-
- /// <summary>
- /// Reports the currently live in-vm broker.
- /// </summary>
- /// <return> The currently live in-vm broker. </return>
- public int getLiveBroker()
- {
- return 0;
- }
-
- /// <summary>
- /// Accepts a failure mechanism.
- /// </summary>
- /// <param name="failureMechanism"> The failure mechanism. </param>
- public void setFailureMechanism(CauseFailure failureMechanism)
- {
- this.failureMechanism = failureMechanism;
- }
- */
- }
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using log4net;
+using NUnit.Framework;
+//using org.apache.log4j.NDC;
+
+using Apache.Qpid.Integration.Tests.framework.sequencers;//.CircuitFactory;
+
+//using uk.co.thebadgerset.junit.extensions.AsymptoticTestCase;
+//using uk.co.thebadgerset.junit.extensions.SetupTaskAware;
+//using uk.co.thebadgerset.junit.extensions.SetupTaskHandler;
+//using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
+//using uk.co.thebadgerset.junit.extensions.util.TestContextProperties;
+
+//using java.util.ArrayList;
+using System.Collections.Generic;//.IList;
+
+namespace Apache.Qpid.Integration.Tests.framework
+{
+ /// <summary>
+ /// FrameworkBaseCase provides a starting point for writing test cases against the test framework. Its main purpose is
+ /// to provide some convenience methods for testing.
+ ///
+ /// <p/><table id="crc"><caption>CRC Card</caption>
+ /// <tr><th> Responsibilities <th> Collaborations
+ /// <tr><td> Create and clean up in-vm brokers on every test case.
+ /// <tr><td> Produce lists of assertions from assertion creation calls.
+ /// <tr><td> Produce JUnit failures from assertion failures.
+ /// <tr><td> Convert failed assertions to error messages.
+ /// </table>
+ /// </summary>
+ public class FrameworkBaseCase //extends AsymptoticTestCase : FrameworkTestContext, SetupTaskAware, BrokerLifecycleAware
+ {
+ /// <summary> Used for debugging purposes. </summary>
+ private static ILog log = LogManager.GetLogger(typeof(FrameworkBaseCase));
+
+ /// <summary> Holds the test sequencer to create and run test circuits with. </summary>
+ protected CircuitFactory circuitFactory;// = new LocalCircuitFactory();
+
+ /// <summary> Used to read the tests configurable properties through. </summary>
+ protected TestModel testProps;
+
+ /// <summary> A default setup task processor to delegate setup tasks to. </summary>
+ //protected SetupTaskHandler taskHandler = new SetupTaskHandler();
+
+ /// <summary> Flag used to track whether the test is in-vm or not. </summary>
+ //protected bool isUsingInVM;
+
+ /// <summary> Holds the failure mechanism. </summary>
+ //protected CauseFailure failureMechanism = new CauseFailureUserPrompt();
+
+ /*
+ /// <summary>
+ /// Creates a new test case with the specified name.
+ /// </summary>
+ /// <param name="name"> The test case name. </param>
+ public FrameworkBaseCase(string name) : base(name)
+ {
+ }
+ */
+
+ /// <summary>
+ /// Returns the test case sequencer that provides test circuit, and test sequence implementations. The sequencer
+ /// that this base case returns by default is suitable for running a test circuit with both circuit ends colocated
+ /// on the same JVM.
+ /// </summary>
+ /// <return> The test case sequencer. </return>
+ protected CircuitFactory GetCircuitFactory()
+ {
+ return circuitFactory;
+ }
+
+ /// <summary>
+ /// Overrides the default test circuit factory. Test decorators can use this to supply distributed test sequencers or
+ /// other test circuit factory specializations.
+ /// </summary>
+ /// <param name="circuitFactory"> The new test circuit factory. </param>
+ public void SetCircuitFactory(CircuitFactory circuitFactory)
+ {
+ this.circuitFactory = circuitFactory;
+ }
+
+ /*
+ /// <summary>
+ /// Reports the current test case name.
+ /// </summary>
+ /// <return> The current test case name. </return>
+ public TestCaseVector GetTestCaseVector()
+ {
+ return new TestCaseVector(this.getName(), 0);
+ }
+ */
+
+ /// <summary>
+ /// Reports the current test case parameters.
+ /// </summary>
+ /// <return> The current test case parameters. </return>
+ public TestModel getTestParameters()
+ {
+ return testProps;
+ }
+
+ /// <summary>
+ /// Creates a list of assertions.
+ /// </summary>
+ /// <param name="asserts"> The assertions to compile in a list. </param>
+ ///
+ /// <return> A list of assertions. </return>
+ protected IList<Assertion> AssertionList(params Assertion[] asserts)
+ {
+ IList<Assertion> result = new List<Assertion>();
+
+ foreach (Assertion assertion in asserts)
+ {
+ result.Add(assertion);
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Generates a JUnit assertion exception (failure) if any assertions are passed into this method, also concatenating
+ /// all of the error messages in the assertions together to form an error message to diagnose the test failure with.
+ /// </summary>
+ /// <param name="asserts"> The list of failed assertions. </param>
+ protected static void AssertNoFailures(List<Assertion> asserts)
+ {
+ log.Debug("protected void assertNoFailures(List<Assertion> asserts = " + asserts + "): called");
+
+ // Check if there are no assertion failures, and return without doing anything if so.
+ if ((asserts == null) || (asserts.Count == 0))
+ {
+ return;
+ }
+
+ // Compile all of the assertion failure messages together.
+ string errorMessage = AssertionsToString(asserts);
+
+ // Fail with the error message from all of the assertions.
+ Assert.Fail(errorMessage);
+ }
+
+ /// <summary>
+ /// Converts a list of failed assertions into an error message.
+ /// </summary>
+ /// <param name="asserts"> The failed assertions. </param>
+ ///
+ /// <return> The error message. </return>
+ protected static string AssertionsToString(List<Assertion> asserts)
+ {
+ string errorMessage = "";
+
+ foreach (Assertion assertion in asserts)
+ {
+ errorMessage += assertion.ToString() + "\n";
+ }
+
+ return errorMessage;
+ }
+
+ /// <summary>
+ /// Ensures that the in-vm broker is created and initialized.
+ /// </summary>
+ ///
+ /// <exception cref="Exception"> Any exceptions allowed to fall through and fail the test. </exception>
+ [SetUp]
+ protected void SetUp()
+ {
+ //NDC.Push(Name);
+
+ //testProps = TestContextProperties.getInstance(TestModel.defaults);
+
+ // Process all optional setup tasks. This may include in-vm broker creation, if a decorator has added it.
+ //taskHandler.runSetupTasks();
+ }
+
+ /// <summary> Ensures that the in-vm broker is cleaned up after each test run. </summary>
+ [TearDown]
+ protected void TearDown()
+ {
+ //NDC.Pop();
+
+ // Process all optional tear down tasks. This may include in-vm broker clean up, if a decorator has added it.
+ //taskHandler.runTearDownTasks();
+ }
+
+ /*
+ /// <summary>
+ /// Adds the specified task to the tests setup.
+ /// </summary>
+ /// <param name="task"> The task to add to the tests setup. </param>
+ public void chainSetupTask(Runnable task)
+ {
+ taskHandler.chainSetupTask(task);
+ }
+ */
+
+ /*
+ /// <summary>
+ /// Adds the specified task to the tests tear down.
+ /// </summary>
+ /// <param name="task"> The task to add to the tests tear down. </param>
+ public void chainTearDownTask(Runnable task)
+ {
+ taskHandler.chainTearDownTask(task);
+ }
+ */
+
+ /*
+ /// <summary>
+ /// Should provide a translation from the junit method name of a test to its test case name as known to the test
+ /// clients that will run the test. The purpose of this is to convert the JUnit method name into the correct test
+ /// case name to place into the test invite. For example the method "testP2P" might map onto the interop test case
+ /// name "TC2_BasicP2P".
+ /// </summary>
+ /// <param name="methodName"> The name of the JUnit test method. </param>
+ ///
+ /// <return> The name of the corresponding interop test case. </return>
+ public string getTestCaseNameForTestMethod(string methodName)
+ {
+ return methodName;
+ }
+
+ public void setInVmBrokers()
+ {
+ isUsingInVM = true;
+ }
+
+ /// <summary>
+ /// Indicates whether or not a test case is using in-vm brokers.
+ /// </summary>
+ /// <return> <tt>true</tt> if the test is using in-vm brokers, <tt>false</tt> otherwise. </return>
+ public bool usingInVmBroker()
+ {
+ return isUsingInVM;
+ }
+
+ /// <summary>
+ /// Sets the currently live in-vm broker.
+ /// </summary>
+ /// <param name="i"> The currently live in-vm broker. </param>
+ public void setLiveBroker(int i)
+ { }
+
+ /// <summary>
+ /// Reports the currently live in-vm broker.
+ /// </summary>
+ /// <return> The currently live in-vm broker. </return>
+ public int getLiveBroker()
+ {
+ return 0;
+ }
+
+ /// <summary>
+ /// Accepts a failure mechanism.
+ /// </summary>
+ /// <param name="failureMechanism"> The failure mechanism. </param>
+ public void setFailureMechanism(CauseFailure failureMechanism)
+ {
+ this.failureMechanism = failureMechanism;
+ }
+ */
+ }
} \ No newline at end of file
diff --git a/dotnet/Qpid.Integration.Tests/framework/Publisher.cs b/dotnet/Qpid.Integration.Tests/framework/Publisher.cs
index 72bd079277..5fbdc7a907 100644
--- a/dotnet/Qpid.Integration.Tests/framework/Publisher.cs
+++ b/dotnet/Qpid.Integration.Tests/framework/Publisher.cs
@@ -1,65 +1,65 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-//using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
-using System;
-
-namespace Apache.Qpid.Integration.Tests.framework
-{
- /// <summary>
- /// A Publisher represents the status of the publishing side of a test circuit. Its main purpose is to provide assertions
- /// that can be applied to test the behaviour of the publishers.
- ///
- /// <p/><table id="crc"><caption>CRC Card</caption>
- /// <tr><th> Responsibilities
- /// <tr><td> Provide assertion that the publishers received no exceptions.
- /// </table>
- /// </summary>
- public interface Publisher
- {
- /// <summary>
- /// Provides an assertion that the publisher encountered no exceptions.
- /// </summary>
- ///
- /// <param name="testProps"> The test configuration properties. </param>
- ///
- /// <return> An assertion that the publisher encountered no exceptions. </return>
- Assertion NoExceptionsAssertion(TestModel testProps);
-
- /// <summary>
- /// Provides an assertion that the AMQP channel was forcibly closed by an error condition.
- /// </summary>
- ///
- /// <param name="testProps"> The test configuration properties. </param>
- ///
- /// <return> An assertion that the AMQP channel was forcibly closed by an error condition. </return>
- Assertion ChannelClosedAssertion(TestModel testProps);
-
- /// <summary>
- /// Provides an assertion that the publisher got a given exception during the test.
- /// </summary>
- ///
- /// <param name="testProps"> The test configuration properties. </param>
- /// <param name="exceptionClass"> The exception class to check for. </param>
- ///
- /// <return> An assertion that the publisher got a given exception during the test. </return>
- Assertion ExceptionAssertion(TestModel testProps, Type exceptionClass);
- }
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+//using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
+using System;
+
+namespace Apache.Qpid.Integration.Tests.framework
+{
+ /// <summary>
+ /// A Publisher represents the status of the publishing side of a test circuit. Its main purpose is to provide assertions
+ /// that can be applied to test the behaviour of the publishers.
+ ///
+ /// <p/><table id="crc"><caption>CRC Card</caption>
+ /// <tr><th> Responsibilities
+ /// <tr><td> Provide assertion that the publishers received no exceptions.
+ /// </table>
+ /// </summary>
+ public interface Publisher
+ {
+ /// <summary>
+ /// Provides an assertion that the publisher encountered no exceptions.
+ /// </summary>
+ ///
+ /// <param name="testProps"> The test configuration properties. </param>
+ ///
+ /// <return> An assertion that the publisher encountered no exceptions. </return>
+ Assertion NoExceptionsAssertion(TestModel testProps);
+
+ /// <summary>
+ /// Provides an assertion that the AMQP channel was forcibly closed by an error condition.
+ /// </summary>
+ ///
+ /// <param name="testProps"> The test configuration properties. </param>
+ ///
+ /// <return> An assertion that the AMQP channel was forcibly closed by an error condition. </return>
+ Assertion ChannelClosedAssertion(TestModel testProps);
+
+ /// <summary>
+ /// Provides an assertion that the publisher got a given exception during the test.
+ /// </summary>
+ ///
+ /// <param name="testProps"> The test configuration properties. </param>
+ /// <param name="exceptionClass"> The exception class to check for. </param>
+ ///
+ /// <return> An assertion that the publisher got a given exception during the test. </return>
+ Assertion ExceptionAssertion(TestModel testProps, Type exceptionClass);
+ }
} \ No newline at end of file
diff --git a/dotnet/Qpid.Integration.Tests/framework/Receiver.cs b/dotnet/Qpid.Integration.Tests/framework/Receiver.cs
index 80320c68b6..96820b5980 100644
--- a/dotnet/Qpid.Integration.Tests/framework/Receiver.cs
+++ b/dotnet/Qpid.Integration.Tests/framework/Receiver.cs
@@ -1,80 +1,80 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-//using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
-using System;
-
-namespace Apache.Qpid.Integration.Tests.framework
-{
- /// <summary>
- /// A Receiver is a <see cref="CircuitEnd"/> that represents the status of the receiving side of a test circuit. Its main
- /// purpose is to provide assertions that can be applied to check the behaviour of the receivers.
- ///
- /// <p/><table id="crc"><caption>CRC Card</caption>
- /// <tr><th> Responsibilities
- /// <tr><td> Provide assertion that the receivers received no exceptions.
- /// <tr><td> Provide assertion that the receivers received all test messages sent to it.
- /// </table>
- /// </summary>
- public interface Receiver
- {
- /// <summary>
- /// Provides an assertion that the receivers encountered no exceptions.
- /// </summary>
- ///
- /// <param name="testProps"> The test configuration properties. </param>
- ///
- /// <return> An assertion that the receivers encountered no exceptions. </return>
- Assertion NoExceptionsAssertion(TestModel testProps);
-
- /// <summary>
- /// Provides an assertion that the receivers got all messages that were sent to it.
- /// </summary>
- /// <param name="testProps"> The test configuration properties. </param>
- ///
- /// <return> An assertion that the receivers got all messages that were sent to it. </return>
- Assertion AllMessagesReceivedAssertion(TestModel testProps);
-
- /// <summary>
- /// Provides an assertion that the receivers got none of the messages that were sent to it.
- /// </summary>
- /// <param name="testProps"> The test configuration properties. </param>
- ///
- /// <return> An assertion that the receivers got none of the messages that were sent to it. </return>
- Assertion NoMessagesReceivedAssertion(TestModel testProps);
-
- /// <summary>
- /// Provides an assertion that the AMQP channel was forcibly closed by an error condition.
- /// </summary>
- /// <param name="testProps"> The test configuration properties. </param>
- ///
- /// <return> An assertion that the AMQP channel was forcibly closed by an error condition. </return>
- Assertion ChannelClosedAssertion(TestModel testProps);
-
- /// <summary>
- /// Provides an assertion that the receiver got a given exception during the test.
- /// </summary>
- /// <param name="testProps"> The test configuration properties. </param>
- /// <param name="exceptionClass"> The exception class to check for. </param>
- ///
- /// <return> An assertion that the receiver got a given exception during the test. </return>
- Assertion ExceptionAssertion(TestModel testProps, Type exceptionClass);
- }
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+//using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
+using System;
+
+namespace Apache.Qpid.Integration.Tests.framework
+{
+ /// <summary>
+ /// A Receiver is a <see cref="CircuitEnd"/> that represents the status of the receiving side of a test circuit. Its main
+ /// purpose is to provide assertions that can be applied to check the behaviour of the receivers.
+ ///
+ /// <p/><table id="crc"><caption>CRC Card</caption>
+ /// <tr><th> Responsibilities
+ /// <tr><td> Provide assertion that the receivers received no exceptions.
+ /// <tr><td> Provide assertion that the receivers received all test messages sent to it.
+ /// </table>
+ /// </summary>
+ public interface Receiver
+ {
+ /// <summary>
+ /// Provides an assertion that the receivers encountered no exceptions.
+ /// </summary>
+ ///
+ /// <param name="testProps"> The test configuration properties. </param>
+ ///
+ /// <return> An assertion that the receivers encountered no exceptions. </return>
+ Assertion NoExceptionsAssertion(TestModel testProps);
+
+ /// <summary>
+ /// Provides an assertion that the receivers got all messages that were sent to it.
+ /// </summary>
+ /// <param name="testProps"> The test configuration properties. </param>
+ ///
+ /// <return> An assertion that the receivers got all messages that were sent to it. </return>
+ Assertion AllMessagesReceivedAssertion(TestModel testProps);
+
+ /// <summary>
+ /// Provides an assertion that the receivers got none of the messages that were sent to it.
+ /// </summary>
+ /// <param name="testProps"> The test configuration properties. </param>
+ ///
+ /// <return> An assertion that the receivers got none of the messages that were sent to it. </return>
+ Assertion NoMessagesReceivedAssertion(TestModel testProps);
+
+ /// <summary>
+ /// Provides an assertion that the AMQP channel was forcibly closed by an error condition.
+ /// </summary>
+ /// <param name="testProps"> The test configuration properties. </param>
+ ///
+ /// <return> An assertion that the AMQP channel was forcibly closed by an error condition. </return>
+ Assertion ChannelClosedAssertion(TestModel testProps);
+
+ /// <summary>
+ /// Provides an assertion that the receiver got a given exception during the test.
+ /// </summary>
+ /// <param name="testProps"> The test configuration properties. </param>
+ /// <param name="exceptionClass"> The exception class to check for. </param>
+ ///
+ /// <return> An assertion that the receiver got a given exception during the test. </return>
+ Assertion ExceptionAssertion(TestModel testProps, Type exceptionClass);
+ }
} \ No newline at end of file
diff --git a/dotnet/Qpid.Integration.Tests/framework/TestClientDetails.cs b/dotnet/Qpid.Integration.Tests/framework/TestClientDetails.cs
index 401e183fd0..8be8de3d96 100644
--- a/dotnet/Qpid.Integration.Tests/framework/TestClientDetails.cs
+++ b/dotnet/Qpid.Integration.Tests/framework/TestClientDetails.cs
@@ -1,84 +1,84 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-
-namespace Apache.Qpid.Integration.Tests.framework
-{
- /// <summary>
- /// TestClientDetails is used to encapsulate information about an interop test client. It pairs together the unique
- /// name of the client, and the route on which it listens to its control messages.
- ///
- /// <p><table id="crc"><caption>CRC Card</caption>
- /// <tr><th> Responsibilities <th> Collaborations
- /// <tr><td> Record test clients control addresses together with their names.
- /// </table>
- /// </summary>
- public class TestClientDetails
- {
- /// <summary> The test clients name. </summary>
- public string clientName;
-
- /// <summary> The routing key of the test clients control topic. </summary>
- public string privateControlKey;
-
- /// <summary>
- /// Two TestClientDetails are considered to be equal, iff they have the same client name.
- /// </summary>
- /// <param name="o"> The object to compare to. </param>
- ///
- /// <return> <tt>If the object to compare to is a TestClientDetails equal to this one, <tt>false</tt> otherwise. </return>
- public override bool Equals(Object o)
- {
- if (this == o)
- {
- return true;
- }
-
- if (!(o is TestClientDetails))
- {
- return false;
- }
-
- TestClientDetails testClientDetails = (TestClientDetails) o;
-
- return !((clientName != null) ? (!clientName.Equals(testClientDetails.clientName))
- : (testClientDetails.clientName != null));
- }
-
- /// <summary>
- /// Computes a hash code compatible with the equals method; based on the client name alone.
- /// </summary>
- /// <return> A hash code for this. </return>
- public override int GetHashCode()
- {
- return ((clientName != null) ? clientName.GetHashCode() : 0);
- }
-
- /// <summary>
- /// Outputs the client name and address details. Mostly used for debugging purposes.
- /// </summary>
- /// <return> The client name and address. </return>
- public override string ToString()
- {
- return "TestClientDetails: [ clientName = " + clientName + ", privateControlKey = " + privateControlKey + " ]";
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+
+namespace Apache.Qpid.Integration.Tests.framework
+{
+ /// <summary>
+ /// TestClientDetails is used to encapsulate information about an interop test client. It pairs together the unique
+ /// name of the client, and the route on which it listens to its control messages.
+ ///
+ /// <p><table id="crc"><caption>CRC Card</caption>
+ /// <tr><th> Responsibilities <th> Collaborations
+ /// <tr><td> Record test clients control addresses together with their names.
+ /// </table>
+ /// </summary>
+ public class TestClientDetails
+ {
+ /// <summary> The test clients name. </summary>
+ public string clientName;
+
+ /// <summary> The routing key of the test clients control topic. </summary>
+ public string privateControlKey;
+
+ /// <summary>
+ /// Two TestClientDetails are considered to be equal, iff they have the same client name.
+ /// </summary>
+ /// <param name="o"> The object to compare to. </param>
+ ///
+ /// <return> <tt>If the object to compare to is a TestClientDetails equal to this one, <tt>false</tt> otherwise. </return>
+ public override bool Equals(Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+
+ if (!(o is TestClientDetails))
+ {
+ return false;
+ }
+
+ TestClientDetails testClientDetails = (TestClientDetails) o;
+
+ return !((clientName != null) ? (!clientName.Equals(testClientDetails.clientName))
+ : (testClientDetails.clientName != null));
+ }
+
+ /// <summary>
+ /// Computes a hash code compatible with the equals method; based on the client name alone.
+ /// </summary>
+ /// <return> A hash code for this. </return>
+ public override int GetHashCode()
+ {
+ return ((clientName != null) ? clientName.GetHashCode() : 0);
+ }
+
+ /// <summary>
+ /// Outputs the client name and address details. Mostly used for debugging purposes.
+ /// </summary>
+ /// <return> The client name and address. </return>
+ public override string ToString()
+ {
+ return "TestClientDetails: [ clientName = " + clientName + ", privateControlKey = " + privateControlKey + " ]";
+ }
+ }
+}
diff --git a/dotnet/Qpid.Integration.Tests/framework/TestModel.cs b/dotnet/Qpid.Integration.Tests/framework/TestModel.cs
index a4a1d7db9b..88bea1e5ad 100644
--- a/dotnet/Qpid.Integration.Tests/framework/TestModel.cs
+++ b/dotnet/Qpid.Integration.Tests/framework/TestModel.cs
@@ -1,657 +1,657 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-//using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
-
-//using javax.jms.Session;
-
-//using java.util.Properties;
-
-namespace Apache.Qpid.Integration.Tests.framework
-{
- public class TestModel //extends ParsedProperties
- {}
-
- /*
- /// <summary>
- /// MessagingTestConfigProperties defines a set of property names and default values for specifying a messaging topology,
- /// and test parameters for running a messaging test over that topology. A Properties object holding some of these
- /// properties, superimposed onto the defaults, is used to establish test topologies and control test behaviour.
- ///
- /// <p/>A complete list of the parameters, default values and comments on their usage is provided here:
- ///
- /// <p/><table><caption>Parameters</caption>
- /// <tr><th> Parameter <th> Default <th> Comments
- /// <tr><td> messageSize <td> 0 <td> Message size in bytes. Not including any headers.
- /// <tr><td> destinationName <td> ping <td> The root name to use to generate destination names to ping.
- /// <tr><td> persistent <td> false <td> Determines whether peristent delivery is used.
- /// <tr><td> transacted <td> false <td> Determines whether messages are sent/received in transactions.
- /// <tr><td> broker <td> tcp://localhost:5672 <td> Determines the broker to connect to.
- /// <tr><td> virtualHost <td> test <td> Determines the virtual host to send all ping over.
- /// <tr><td> rate <td> 0 <td> The maximum rate (in hertz) to send messages at. 0 means no limit.
- /// <tr><td> verbose <td> false <td> The verbose flag for debugging. Prints to console on every message.
- /// <tr><td> pubsub <td> false <td> Whether to ping topics or queues. Uses p2p by default.
- /// <tr><td> username <td> guest <td> The username to access the broker with.
- /// <tr><td> password <td> guest <td> The password to access the broker with.
- /// <tr><td> selector <td> null <td> Not used. Defines a message selector to filter pings with.
- /// <tr><td> destinationCount <td> 1 <td> The number of receivers listening to the pings.
- /// <tr><td> timeout <td> 30000 <td> In milliseconds. The timeout to stop waiting for replies.
- /// <tr><td> commitBatchSize <td> 1 <td> The number of messages per transaction in transactional mode.
- /// <tr><td> uniqueDests <td> true <td> Whether each receivers only listens to one ping destination or all.
- /// <tr><td> durableDests <td> false <td> Whether or not durable destinations are used.
- /// <tr><td> ackMode <td> AUTO_ACK <td> The message acknowledgement mode. Possible values are:
- /// 0 - SESSION_TRANSACTED
- /// 1 - AUTO_ACKNOWLEDGE
- /// 2 - CLIENT_ACKNOWLEDGE
- /// 3 - DUPS_OK_ACKNOWLEDGE
- /// 257 - NO_ACKNOWLEDGE
- /// 258 - PRE_ACKNOWLEDGE
- /// <tr><td> maxPending <td> 0 <td> The maximum size in bytes, of messages sent but not yet received.
- /// Limits the volume of messages currently buffered on the client
- /// or broker. Can help scale test clients by limiting amount of buffered
- /// data to avoid out of memory errors.
- /// </table>
- ///
- /// <p><table id="crc"><caption>CRC Card</caption>
- /// <tr><th> Responsibilities <th> Collaborations
- /// <tr><td> Provide the names and defaults of all test parameters.
- /// </table>
- /// </summary>
- ///
- /// <remarks> Put a type-safe wrapper around these properties, but continue to store the parameters as properties. This is
- /// simply to ensure that it is a simple matter to serialize/deserialize string/string pairs onto messages.</remarks>
- public class MessagingTestConfigProperties extends ParsedProperties
- {
- // ====================== Connection Properties ==================================
-
- /// <summary> Holds the name of the default connection configuration. </summary>
- public static final string CONNECTION_NAME = "broker";
-
- /// <summary> Holds the name of the property to get the initial context factory name from. </summary>
- public static final string INITIAL_CONTEXT_FACTORY_PROPNAME = "java.naming.factory.initial";
-
- /// <summary> Defines the class to use as the initial context factory by default. </summary>
- public static final string INITIAL_CONTEXT_FACTORY_DEFAULT = "org.apache.qpid.jndi.PropertiesFileInitialContextFactory";
-
- /// <summary> Holds the name of the property to get the test broker url from. </summary>
- public static final string BROKER_PROPNAME = "qpid.test.broker";
-
- /// <summary> Holds the default broker url for the test. </summary>
- public static final string BROKER_DEFAULT = "vm://:1";
-
- /// <summary> Holds the name of the property to get the test broker virtual path. </summary>
- public static final string VIRTUAL_HOST_PROPNAME = "virtualHost";
-
- /// <summary> Holds the default virtual path for the test. </summary>
- public static final string VIRTUAL_HOST_DEFAULT = "";
-
- /// <summary> Holds the name of the property to get the broker access username from. </summary>
- public static final string USERNAME_PROPNAME = "username";
-
- /// <summary> Holds the default broker log on username. </summary>
- public static final string USERNAME_DEFAULT = "guest";
-
- /// <summary> Holds the name of the property to get the broker access password from. </summary>
- public static final string PASSWORD_PROPNAME = "password";
-
- /// <summary> Holds the default broker log on password. </summary>
- public static final string PASSWORD_DEFAULT = "guest";
-
- // ====================== Messaging Topology Properties ==========================
-
- /// <summary> Holds the name of the property to get the bind publisher procuder flag from. </summary>
- public static final string PUBLISHER_PRODUCER_BIND_PROPNAME = "publisherProducerBind";
-
- /// <summary> Holds the default value of the publisher producer flag. </summary>
- public static final bool PUBLISHER_PRODUCER_BIND_DEFAULT = true;
-
- /// <summary> Holds the name of the property to get the bind publisher procuder flag from. </summary>
- public static final string PUBLISHER_CONSUMER_BIND_PROPNAME = "publisherConsumerBind";
-
- /// <summary> Holds the default value of the publisher consumer flag. </summary>
- public static final bool PUBLISHER_CONSUMER_BIND_DEFAULT = false;
-
- /// <summary> Holds the name of the property to get the bind receivers procuder flag from. </summary>
- public static final string RECEIVER_PRODUCER_BIND_PROPNAME = "receiverProducerBind";
-
- /// <summary> Holds the default value of the receivers producer flag. </summary>
- public static final bool RECEIVER_PRODUCER_BIND_DEFAULT = false;
-
- /// <summary> Holds the name of the property to get the bind receivers procuder flag from. </summary>
- public static final string RECEIVER_CONSUMER_BIND_PROPNAME = "receiverConsumerBind";
-
- /// <summary> Holds the default value of the receivers consumer flag. </summary>
- public static final bool RECEIVER_CONSUMER_BIND_DEFAULT = true;
-
- /// <summary> Holds the name of the property to get the publishers consumer active flag from. </summary>
- public static final string PUBLISHER_CONSUMER_ACTIVE_PROPNAME = "publisherConsumerActive";
-
- /// <summary> Holds the default value of the publishers consumer active flag. </summary>
- public static final bool PUBLISHER_CONSUMER_ACTIVE_DEFAULT = true;
-
- /// <summary> Holds the name of the property to get the receivers consumer active flag from. </summary>
- public static final string RECEIVER_CONSUMER_ACTIVE_PROPNAME = "receiverConsumerActive";
-
- /// <summary> Holds the default value of the receivers consumer active flag. </summary>
- public static final bool RECEIVER_CONSUMER_ACTIVE_DEFAULT = true;
-
- /// <summary> Holds the name of the property to get the destination name root from. </summary>
- public static final string SEND_DESTINATION_NAME_ROOT_PROPNAME = "sendDestinationRoot";
-
- /// <summary> Holds the root of the name of the default destination to send to. </summary>
- public static final string SEND_DESTINATION_NAME_ROOT_DEFAULT = "sendTo";
-
- /// <summary> Holds the name of the property to get the destination name root from. </summary>
- public static final string RECEIVE_DESTINATION_NAME_ROOT_PROPNAME = "receiveDestinationRoot";
-
- /// <summary> Holds the root of the name of the default destination to send to. </summary>
- public static final string RECEIVE_DESTINATION_NAME_ROOT_DEFAULT = "receiveFrom";
-
- /// <summary> Holds the name of the proeprty to get the destination count from. </summary>
- public static final string DESTINATION_COUNT_PROPNAME = "destinationCount";
-
- /// <summary> Defines the default number of destinations to ping. </summary>
- public static final int DESTINATION_COUNT_DEFAULT = 1;
-
- /// <summary> Holds the name of the property to get the p2p or pub/sub messaging mode from. </summary>
- public static final string PUBSUB_PROPNAME = "pubsub";
-
- /// <summary> Holds the pub/sub mode default, true means ping a topic, false means ping a queue. </summary>
- public static final bool PUBSUB_DEFAULT = false;
-
- // ====================== JMS Options and Flags =================================
-
- /// <summary> Holds the name of the property to get the test delivery mode from. </summary>
- public static final string PERSISTENT_MODE_PROPNAME = "persistent";
-
- /// <summary> Holds the message delivery mode to use for the test. </summary>
- public static final bool PERSISTENT_MODE_DEFAULT = false;
-
- /// <summary> Holds the name of the property to get the test transactional mode from. </summary>
- public static final string TRANSACTED_PUBLISHER_PROPNAME = "transactedPublisher";
-
- /// <summary> Holds the transactional mode to use for the test. </summary>
- public static final bool TRANSACTED_PUBLISHER_DEFAULT = false;
-
- /// <summary> Holds the name of the property to get the test transactional mode from. </summary>
- public static final string TRANSACTED_RECEIVER_PROPNAME = "transactedReceiver";
-
- /// <summary> Holds the transactional mode to use for the test. </summary>
- public static final bool TRANSACTED_RECEIVER_DEFAULT = false;
-
- /// <summary> Holds the name of the property to set the no local flag from. </summary>
- public static final string NO_LOCAL_PROPNAME = "noLocal";
-
- /// <summary> Defines the default value of the no local flag to use when consuming messages. </summary>
- public static final bool NO_LOCAL_DEFAULT = false;
-
- /// <summary> Holds the name of the property to get the message acknowledgement mode from. </summary>
- public static final string ACK_MODE_PROPNAME = "ackMode";
-
- /// <summary> Defines the default message acknowledgement mode. </summary>
- public static final int ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE;
-
- /// <summary> Holds the name of the property to get the durable subscriptions flag from, when doing pub/sub messaging. </summary>
- public static final string DURABLE_SUBSCRIPTION_PROPNAME = "durableSubscription";
-
- /// <summary> Defines the default value of the durable subscriptions flag. </summary>
- public static final bool DURABLE_SUBSCRIPTION_DEFAULT = false;
-
- // ====================== Qpid/AMQP Options and Flags ================================
-
- /// <summary> Holds the name of the property to set the exclusive flag from. </summary>
- public static final string EXCLUSIVE_PROPNAME = "exclusive";
-
- /// <summary> Defines the default value of the exclusive flag to use when consuming messages. </summary>
- public static final bool EXCLUSIVE_DEFAULT = false;
-
- /// <summary> Holds the name of the property to set the immediate flag from. </summary>
- public static final string IMMEDIATE_PROPNAME = "immediate";
-
- /// <summary> Defines the default value of the immediate flag to use when sending messages. </summary>
- public static final bool IMMEDIATE_DEFAULT = false;
-
- /// <summary> Holds the name of the property to set the mandatory flag from. </summary>
- public static final string MANDATORY_PROPNAME = "mandatory";
-
- /// <summary> Defines the default value of the mandatory flag to use when sending messages. </summary>
- public static final bool MANDATORY_DEFAULT = false;
-
- /// <summary> Holds the name of the property to get the durable destinations flag from. </summary>
- public static final string DURABLE_DESTS_PROPNAME = "durableDests";
-
- /// <summary> Default value for the durable destinations flag. </summary>
- public static final bool DURABLE_DESTS_DEFAULT = false;
-
- /// <summary> Holds the name of the property to set the prefetch size from. </summary>
- public static final string PREFETCH_PROPNAME = "prefetch";
-
- /// <summary> Defines the default prefetch size to use when consuming messages. </summary>
- public static final int PREFETCH_DEFAULT = 100;
-
- // ====================== Common Test Parameters ================================
-
- /// <summary> Holds the name of the property to get the test message size from. </summary>
- public static final string MESSAGE_SIZE_PROPNAME = "messageSize";
-
- /// <summary> Used to set up a default message size. </summary>
- public static final int MESSAGE_SIZE_DEAFULT = 0;
-
- /// <summary> Holds the name of the property to get the message rate from. </summary>
- public static final string RATE_PROPNAME = "rate";
-
- /// <summary> Defines the default rate (in pings per second) to send pings at. 0 means as fast as possible, no restriction. </summary>
- public static final int RATE_DEFAULT = 0;
-
- /// <summary> Holds the name of the proeprty to get the. </summary>
- public static final string SELECTOR_PROPNAME = "selector";
-
- /// <summary> Holds the default message selector. </summary>
- public static final string SELECTOR_DEFAULT = "";
-
- /// <summary> Holds the name of the property to get the waiting timeout for response messages. </summary>
- public static final string TIMEOUT_PROPNAME = "timeout";
-
- /// <summary> Default time to wait before assuming that a ping has timed out. </summary>
- public static final long TIMEOUT_DEFAULT = 30000;
-
- /// <summary> Holds the name of the property to get the commit batch size from. </summary>
- public static final string TX_BATCH_SIZE_PROPNAME = "commitBatchSize";
-
- /// <summary> Defines the default number of pings to send in each transaction when running transactionally. </summary>
- public static final int TX_BATCH_SIZE_DEFAULT = 1;
-
- /// <summary> Holds the name of the property to set the maximum amount of pending message data for a producer to hold. </summary>
- public static final string MAX_PENDING_PROPNAME = "maxPending";
-
- /// <summary> Defines the default maximum quantity of pending message data to allow producers to hold. </summary>
- public static final int MAX_PENDING_DEFAULT = 0;
-
- /// <summary> Holds the name of the property to get the publisher rollback flag from. </summary>
- public static final string ROLLBACK_PUBLISHER_PROPNAME = "rollbackPublisher";
-
- /// <summary> Holds the default publisher roll back setting. </summary>
- public static final bool ROLLBACK_PUBLISHER_DEFAULT = false;
-
- /// <summary> Holds the name of the property to get the publisher rollback flag from. </summary>
- public static final string ROLLBACK_RECEIVER_PROPNAME = "rollbackReceiver";
-
- /// <summary> Holds the default publisher roll back setting. </summary>
- public static final bool ROLLBACK_RECEIVER_DEFAULT = false;
-
- // ====================== Options that control the bahviour of the test framework. =========================
-
- /// <summary> Holds the name of the property to get the behavioural mode of not applicable assertions. </summary>
- public static final string NOT_APPLICABLE_ASSERTION_PROPNAME = "notApplicableAssertion";
-
- /// <summary> Holds the default behavioral mode of not applicable assertions, which is logging them as a warning. </summary>
- public static final string NOT_APPLICABLE_ASSERTION_DEFAULT = "warn";
-
- /// <summary> Holds the name of the property to get the verbose mode proeprty from. </summary>
- public static final string VERBOSE_PROPNAME = "verbose";
-
- /// <summary> Holds the default verbose mode. </summary>
- public static final bool VERBOSE_DEFAULT = false;
-
- /// <summary> Holds the default configuration properties. </summary>
- public static ParsedProperties defaults = new ParsedProperties();
-
- static
- {
- defaults.setPropertyIfNull(INITIAL_CONTEXT_FACTORY_PROPNAME, INITIAL_CONTEXT_FACTORY_DEFAULT);
- defaults.setPropertyIfNull(BROKER_PROPNAME, BROKER_DEFAULT);
- defaults.setPropertyIfNull(VIRTUAL_HOST_PROPNAME, VIRTUAL_HOST_DEFAULT);
- defaults.setPropertyIfNull(USERNAME_PROPNAME, USERNAME_DEFAULT);
- defaults.setPropertyIfNull(PASSWORD_PROPNAME, PASSWORD_DEFAULT);
-
- defaults.setPropertyIfNull(PUBLISHER_PRODUCER_BIND_PROPNAME, PUBLISHER_PRODUCER_BIND_DEFAULT);
- defaults.setPropertyIfNull(PUBLISHER_CONSUMER_BIND_PROPNAME, PUBLISHER_CONSUMER_BIND_DEFAULT);
- defaults.setPropertyIfNull(RECEIVER_PRODUCER_BIND_PROPNAME, RECEIVER_PRODUCER_BIND_DEFAULT);
- defaults.setPropertyIfNull(RECEIVER_CONSUMER_BIND_PROPNAME, RECEIVER_CONSUMER_BIND_DEFAULT);
- defaults.setPropertyIfNull(PUBLISHER_CONSUMER_ACTIVE_PROPNAME, PUBLISHER_CONSUMER_ACTIVE_DEFAULT);
- defaults.setPropertyIfNull(RECEIVER_CONSUMER_ACTIVE_PROPNAME, RECEIVER_CONSUMER_ACTIVE_DEFAULT);
- defaults.setPropertyIfNull(SEND_DESTINATION_NAME_ROOT_PROPNAME, SEND_DESTINATION_NAME_ROOT_DEFAULT);
- defaults.setPropertyIfNull(RECEIVE_DESTINATION_NAME_ROOT_PROPNAME, RECEIVE_DESTINATION_NAME_ROOT_DEFAULT);
- defaults.setPropertyIfNull(DESTINATION_COUNT_PROPNAME, DESTINATION_COUNT_DEFAULT);
- defaults.setPropertyIfNull(PUBSUB_PROPNAME, PUBSUB_DEFAULT);
-
- defaults.setPropertyIfNull(PERSISTENT_MODE_PROPNAME, PERSISTENT_MODE_DEFAULT);
- defaults.setPropertyIfNull(TRANSACTED_PUBLISHER_PROPNAME, TRANSACTED_PUBLISHER_DEFAULT);
- defaults.setPropertyIfNull(TRANSACTED_RECEIVER_PROPNAME, TRANSACTED_RECEIVER_DEFAULT);
- defaults.setPropertyIfNull(NO_LOCAL_PROPNAME, NO_LOCAL_DEFAULT);
- defaults.setPropertyIfNull(ACK_MODE_PROPNAME, ACK_MODE_DEFAULT);
- defaults.setPropertyIfNull(DURABLE_SUBSCRIPTION_PROPNAME, DURABLE_SUBSCRIPTION_DEFAULT);
-
- defaults.setPropertyIfNull(EXCLUSIVE_PROPNAME, EXCLUSIVE_DEFAULT);
- defaults.setPropertyIfNull(IMMEDIATE_PROPNAME, IMMEDIATE_DEFAULT);
- defaults.setPropertyIfNull(MANDATORY_PROPNAME, MANDATORY_DEFAULT);
- defaults.setPropertyIfNull(DURABLE_DESTS_PROPNAME, DURABLE_DESTS_DEFAULT);
- defaults.setPropertyIfNull(PREFETCH_PROPNAME, PREFETCH_DEFAULT);
-
- defaults.setPropertyIfNull(MESSAGE_SIZE_PROPNAME, MESSAGE_SIZE_DEAFULT);
- defaults.setPropertyIfNull(RATE_PROPNAME, RATE_DEFAULT);
- defaults.setPropertyIfNull(SELECTOR_PROPNAME, SELECTOR_DEFAULT);
- defaults.setPropertyIfNull(TIMEOUT_PROPNAME, TIMEOUT_DEFAULT);
- defaults.setPropertyIfNull(TX_BATCH_SIZE_PROPNAME, TX_BATCH_SIZE_DEFAULT);
- defaults.setPropertyIfNull(MAX_PENDING_PROPNAME, MAX_PENDING_DEFAULT);
- defaults.setPropertyIfNull(ROLLBACK_PUBLISHER_PROPNAME, ROLLBACK_PUBLISHER_DEFAULT);
- defaults.setPropertyIfNull(ROLLBACK_RECEIVER_PROPNAME, ROLLBACK_RECEIVER_DEFAULT);
-
- defaults.setPropertyIfNull(NOT_APPLICABLE_ASSERTION_PROPNAME, NOT_APPLICABLE_ASSERTION_DEFAULT);
- defaults.setPropertyIfNull(VERBOSE_PROPNAME, VERBOSE_DEFAULT);
- }
-
- /// <summary> Creates a test configuration based on the defaults. </summary>
- public MessagingTestConfigProperties()
- {
- super(defaults);
- }
-
- /// <summary>
- /// Creates a test configuration based on the supplied properties.
- /// </summary>
- /// <param name="properties"> The test configuration. </param>
- public MessagingTestConfigProperties(Properties properties)
- {
- super(properties);
- }
-
- /// <summary>
- /// The size of test messages to send.
- /// </summary>
- /// <return> The size of test messages to send. </return>
- public int getMessageSize()
- {
- return getPropertyAsInteger(MESSAGE_SIZE_PROPNAME);
- }
-
- /// <summary>
- /// Flag to indicate that the publishing producer should be set up to publish to a destination.
- /// </summary>
- /// <return> Flag to indicate that the publishing producer should be set up to publish to a destination. </return>
- public bool getPublisherProducerBind()
- {
- return getPropertyAsBoolean(PUBLISHER_PRODUCER_BIND_PROPNAME);
- }
-
- /// <summary>
- /// Flag to indicate that the publishing consumer should be set up to receive from a destination.
- /// </summary>
- /// <return> Flag to indicate that the publishing consumer should be set up to receive from a destination. </return>
- public bool getPublisherConsumerBind()
- {
- return getPropertyAsBoolean(PUBLISHER_CONSUMER_BIND_PROPNAME);
- }
-
- /// <summary>
- /// Flag to indicate that the receiving producer should be set up to publish to a destination.
- /// </summary>
- /// <return> Flag to indicate that the receiving producer should be set up to publish to a destination. </return>
- public bool getReceiverProducerBind()
- {
- return getPropertyAsBoolean(RECEIVER_PRODUCER_BIND_PROPNAME);
- }
-
- /// <summary>
- /// Flag to indicate that the receiving consumer should be set up to receive from a destination.
- /// </summary>
- /// <return> Flag to indicate that the receiving consumer should be set up to receive from a destination. </return>
- public bool getReceiverConsumerBind()
- {
- return getPropertyAsBoolean(RECEIVER_CONSUMER_BIND_PROPNAME);
- }
-
- /// <summary>
- /// Flag to indicate that the publishing consumer should be created and actively listening.
- /// </summary>
- /// <return> Flag to indicate that the publishing consumer should be created. </return>
- public bool getPublisherConsumerActive()
- {
- return getPropertyAsBoolean(PUBLISHER_CONSUMER_ACTIVE_PROPNAME);
- }
-
- /// <summary>
- /// Flag to indicate that the receiving consumers should be created and actively listening.
- /// </summary>
- /// <return> Flag to indicate that the receiving consumers should be created and actively listening. </return>
- public bool getReceiverConsumerActive()
- {
- return getPropertyAsBoolean(RECEIVER_CONSUMER_ACTIVE_PROPNAME);
- }
-
- /// <summary>
- /// A root to create all test destination names from.
- /// </summary>
- /// <return> A root to create all test destination names from. </return>
- public string getSendDestinationNameRoot()
- {
- return getProperty(SEND_DESTINATION_NAME_ROOT_PROPNAME);
- }
-
- /// <summary>
- /// A root to create all receiving destination names from.
- /// </summary>
- /// <return> A root to create all receiving destination names from. </return>
- public string getReceiveDestinationNameRoot()
- {
- return getProperty(RECEIVE_DESTINATION_NAME_ROOT_PROPNAME);
- }
-
- /// <summary>
- /// Flag to indicate that persistent messages should be used.
- /// </summary>
- /// <return> Flag to indicate that persistent messages should be used. </return>
- public bool getPersistentMode()
- {
- return getPropertyAsBoolean(PERSISTENT_MODE_PROPNAME);
- }
-
- /// <summary>
- /// Flag to indicate that transactional messages should be sent by the publisher.
- /// </summary>
- /// <return> Flag to indicate that transactional messages should be sent by the publisher. </return>
- public bool getPublisherTransacted()
- {
- return getPropertyAsBoolean(TRANSACTED_PUBLISHER_PROPNAME);
- }
-
- /// <summary>
- /// Flag to indicate that transactional receives should be used by the receiver.
- /// </summary>
- /// <return> Flag to indicate that transactional receives should be used by the receiver. </return>
- public bool getReceiverTransacted()
- {
- return getPropertyAsBoolean(TRANSACTED_PUBLISHER_PROPNAME);
- }
-
- /// <summary>
- /// The name of the virtual host to run all tests over.
- /// </summary>
- /// <return> The name of the virtual host to run all tests over. </return>
- public string getVirtualHost()
- {
- return getProperty(VIRTUAL_HOST_PROPNAME);
- }
-
- /// <summary>
- /// Limiting rate for each sender in messages per second, or zero for unlimited.
- /// </summary>
- /// <return> Limiting rate for each sender in messages per second, or zero for unlimited. </return>
- public string getRate()
- {
- return getProperty(RATE_PROPNAME);
- }
-
- /// <summary>
- /// Flag to indicate that test messages should be received publish/subscribe style by all receivers.
- /// </summary>
- /// <return> Flag to indicate that test messages should be received publish/subscribe style by all receivers. </return>
- public bool getPubsub()
- {
- return getPropertyAsBoolean(PUBSUB_PROPNAME);
- }
-
- /// <summary>
- /// The username credentials to run tests with.
- /// </summary>
- /// <return> The username credentials to run tests with. </return>
- public string getUsername()
- {
- return getProperty(USERNAME_PROPNAME);
- }
-
- /// <summary>
- /// The password credentials to run tests with.
- /// </summary>
- /// <return> The password credentials to run tests with. </return>
- public string getPassword()
- {
- return getProperty(PASSWORD_PROPNAME);
- }
-
- /// <summary>
- /// The timeout duration to fail tests on, should they receive no messages within it.
- /// </summary>
- /// <return> The timeout duration to fail tests on, should they receive no messages within it. </return>
- public long getTimeout()
- {
- return getPropertyAsLong(TIMEOUT_PROPNAME);
- }
-
- /// <summary>
- /// The number of messages to batch into each transaction in transational tests.
- /// </summary>
- /// <return> The number of messages to batch into each transaction in transational tests. </return>
- public int getTxBatchSize()
- {
- return getPropertyAsInteger(TX_BATCH_SIZE_PROPNAME);
- }
-
- /// <summary>
- /// Flag to indicate that tests should use durable destinations.
- /// </summary>
- /// <return> Flag to indicate that tests should use durable destinations. </return>
- public bool getDurableDests()
- {
- return getPropertyAsBoolean(DURABLE_DESTS_PROPNAME);
- }
-
- /// <summary>
- /// The ack mode for message receivers to use.
- /// </summary>
- /// <return> The ack mode for message receivers to use. </return>
- public int getAckMode()
- {
- return getPropertyAsInteger(ACK_MODE_PROPNAME);
- }
-
- /// <summary>
- /// Flag to indicate that tests should use durable subscriptions.
- /// </summary>
- /// <return> Flag to indicate that tests should use durable subscriptions. </return>
- public bool getDurableSubscription()
- {
- return getPropertyAsBoolean(DURABLE_SUBSCRIPTION_PROPNAME);
- }
-
- /// <summary>
- /// The maximum amount of in-flight data, in bytes, that tests should send at any time.
- /// </summary>
- /// <return> The maximum amount of in-flight data, in bytes, that tests should send at any time. </return>
- public int getMaxPending()
- {
- return getPropertyAsInteger(MAX_PENDING_PROPNAME);
- }
-
- /// <summary>
- /// The size of the prefetch queue to use.
- /// </summary>
- /// <return> The size of the prefetch queue to use. </return>
- public int getPrefetch()
- {
- return getPropertyAsInteger(PREFETCH_PROPNAME);
- }
-
- /// <summary>
- /// Flag to indicate that subscriptions should be no-local.
- /// </summary>
- /// <return> Flag to indicate that subscriptions should be no-local. </return>
- public bool getNoLocal()
- {
- return getPropertyAsBoolean(NO_LOCAL_PROPNAME);
- }
-
- /// <summary>
- /// Flag to indicate that subscriptions should be exclusive.
- /// </summary>
- /// <return> Flag to indicate that subscriptions should be exclusive. </return>
- public bool getExclusive()
- {
- return getPropertyAsBoolean(EXCLUSIVE_PROPNAME);
- }
-
- /// <summary>
- /// Flag to indicate that messages must be delivered immediately.
- /// </summary>
- /// <return> Flag to indicate that messages must be delivered immediately. </return>
- public bool getImmediate()
- {
- return getPropertyAsBoolean(IMMEDIATE_PROPNAME);
- }
-
- /// <summary>
- /// Flag to indicate that messages must be routable.
- /// </summary>
- /// <return> Flag to indicate that messages must be routable. </return>
- public bool getMandatory()
- {
- return getPropertyAsBoolean(MANDATORY_PROPNAME);
- }
-
- /// <summary>
- /// Gets the value of a flag to indicate that the publisher should rollback all messages sent.
- /// </summary>
- /// <return> A flag to indicate that the publisher should rollback all messages sent. </return>
- public bool getRollbackPublisher()
- {
- return getPropertyAsBoolean(ROLLBACK_PUBLISHER_PROPNAME);
- }
-
- /// <summary>
- /// Gets the value of a flag to indicate that the receiver should rollback all messages received, then receive them
- /// again.
- /// </summary>
- /// <return> A flag to indicate that the publisher should rollback all messages received. </return>
- public bool getRollbackReceiver()
- {
- return getPropertyAsBoolean(ROLLBACK_RECEIVER_PROPNAME);
- }
-
- /// <summary>
- /// Gets the behavioural mode of not applicable assertions. Should be one of 'quiet', 'warn' or 'fail'.
- /// </summary>
- /// <return> The behavioural mode of not applicable assertions. </return>
- public string getNotApplicableAssertionMode()
- {
- return getProperty(NOT_APPLICABLE_ASSERTION_PROPNAME);
- }
- }
- */
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+//using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
+
+//using javax.jms.Session;
+
+//using java.util.Properties;
+
+namespace Apache.Qpid.Integration.Tests.framework
+{
+ public class TestModel //extends ParsedProperties
+ {}
+
+ /*
+ /// <summary>
+ /// MessagingTestConfigProperties defines a set of property names and default values for specifying a messaging topology,
+ /// and test parameters for running a messaging test over that topology. A Properties object holding some of these
+ /// properties, superimposed onto the defaults, is used to establish test topologies and control test behaviour.
+ ///
+ /// <p/>A complete list of the parameters, default values and comments on their usage is provided here:
+ ///
+ /// <p/><table><caption>Parameters</caption>
+ /// <tr><th> Parameter <th> Default <th> Comments
+ /// <tr><td> messageSize <td> 0 <td> Message size in bytes. Not including any headers.
+ /// <tr><td> destinationName <td> ping <td> The root name to use to generate destination names to ping.
+ /// <tr><td> persistent <td> false <td> Determines whether peristent delivery is used.
+ /// <tr><td> transacted <td> false <td> Determines whether messages are sent/received in transactions.
+ /// <tr><td> broker <td> tcp://localhost:5672 <td> Determines the broker to connect to.
+ /// <tr><td> virtualHost <td> test <td> Determines the virtual host to send all ping over.
+ /// <tr><td> rate <td> 0 <td> The maximum rate (in hertz) to send messages at. 0 means no limit.
+ /// <tr><td> verbose <td> false <td> The verbose flag for debugging. Prints to console on every message.
+ /// <tr><td> pubsub <td> false <td> Whether to ping topics or queues. Uses p2p by default.
+ /// <tr><td> username <td> guest <td> The username to access the broker with.
+ /// <tr><td> password <td> guest <td> The password to access the broker with.
+ /// <tr><td> selector <td> null <td> Not used. Defines a message selector to filter pings with.
+ /// <tr><td> destinationCount <td> 1 <td> The number of receivers listening to the pings.
+ /// <tr><td> timeout <td> 30000 <td> In milliseconds. The timeout to stop waiting for replies.
+ /// <tr><td> commitBatchSize <td> 1 <td> The number of messages per transaction in transactional mode.
+ /// <tr><td> uniqueDests <td> true <td> Whether each receivers only listens to one ping destination or all.
+ /// <tr><td> durableDests <td> false <td> Whether or not durable destinations are used.
+ /// <tr><td> ackMode <td> AUTO_ACK <td> The message acknowledgement mode. Possible values are:
+ /// 0 - SESSION_TRANSACTED
+ /// 1 - AUTO_ACKNOWLEDGE
+ /// 2 - CLIENT_ACKNOWLEDGE
+ /// 3 - DUPS_OK_ACKNOWLEDGE
+ /// 257 - NO_ACKNOWLEDGE
+ /// 258 - PRE_ACKNOWLEDGE
+ /// <tr><td> maxPending <td> 0 <td> The maximum size in bytes, of messages sent but not yet received.
+ /// Limits the volume of messages currently buffered on the client
+ /// or broker. Can help scale test clients by limiting amount of buffered
+ /// data to avoid out of memory errors.
+ /// </table>
+ ///
+ /// <p><table id="crc"><caption>CRC Card</caption>
+ /// <tr><th> Responsibilities <th> Collaborations
+ /// <tr><td> Provide the names and defaults of all test parameters.
+ /// </table>
+ /// </summary>
+ ///
+ /// <remarks> Put a type-safe wrapper around these properties, but continue to store the parameters as properties. This is
+ /// simply to ensure that it is a simple matter to serialize/deserialize string/string pairs onto messages.</remarks>
+ public class MessagingTestConfigProperties extends ParsedProperties
+ {
+ // ====================== Connection Properties ==================================
+
+ /// <summary> Holds the name of the default connection configuration. </summary>
+ public static final string CONNECTION_NAME = "broker";
+
+ /// <summary> Holds the name of the property to get the initial context factory name from. </summary>
+ public static final string INITIAL_CONTEXT_FACTORY_PROPNAME = "java.naming.factory.initial";
+
+ /// <summary> Defines the class to use as the initial context factory by default. </summary>
+ public static final string INITIAL_CONTEXT_FACTORY_DEFAULT = "org.apache.qpid.jndi.PropertiesFileInitialContextFactory";
+
+ /// <summary> Holds the name of the property to get the test broker url from. </summary>
+ public static final string BROKER_PROPNAME = "qpid.test.broker";
+
+ /// <summary> Holds the default broker url for the test. </summary>
+ public static final string BROKER_DEFAULT = "vm://:1";
+
+ /// <summary> Holds the name of the property to get the test broker virtual path. </summary>
+ public static final string VIRTUAL_HOST_PROPNAME = "virtualHost";
+
+ /// <summary> Holds the default virtual path for the test. </summary>
+ public static final string VIRTUAL_HOST_DEFAULT = "";
+
+ /// <summary> Holds the name of the property to get the broker access username from. </summary>
+ public static final string USERNAME_PROPNAME = "username";
+
+ /// <summary> Holds the default broker log on username. </summary>
+ public static final string USERNAME_DEFAULT = "guest";
+
+ /// <summary> Holds the name of the property to get the broker access password from. </summary>
+ public static final string PASSWORD_PROPNAME = "password";
+
+ /// <summary> Holds the default broker log on password. </summary>
+ public static final string PASSWORD_DEFAULT = "guest";
+
+ // ====================== Messaging Topology Properties ==========================
+
+ /// <summary> Holds the name of the property to get the bind publisher procuder flag from. </summary>
+ public static final string PUBLISHER_PRODUCER_BIND_PROPNAME = "publisherProducerBind";
+
+ /// <summary> Holds the default value of the publisher producer flag. </summary>
+ public static final bool PUBLISHER_PRODUCER_BIND_DEFAULT = true;
+
+ /// <summary> Holds the name of the property to get the bind publisher procuder flag from. </summary>
+ public static final string PUBLISHER_CONSUMER_BIND_PROPNAME = "publisherConsumerBind";
+
+ /// <summary> Holds the default value of the publisher consumer flag. </summary>
+ public static final bool PUBLISHER_CONSUMER_BIND_DEFAULT = false;
+
+ /// <summary> Holds the name of the property to get the bind receivers procuder flag from. </summary>
+ public static final string RECEIVER_PRODUCER_BIND_PROPNAME = "receiverProducerBind";
+
+ /// <summary> Holds the default value of the receivers producer flag. </summary>
+ public static final bool RECEIVER_PRODUCER_BIND_DEFAULT = false;
+
+ /// <summary> Holds the name of the property to get the bind receivers procuder flag from. </summary>
+ public static final string RECEIVER_CONSUMER_BIND_PROPNAME = "receiverConsumerBind";
+
+ /// <summary> Holds the default value of the receivers consumer flag. </summary>
+ public static final bool RECEIVER_CONSUMER_BIND_DEFAULT = true;
+
+ /// <summary> Holds the name of the property to get the publishers consumer active flag from. </summary>
+ public static final string PUBLISHER_CONSUMER_ACTIVE_PROPNAME = "publisherConsumerActive";
+
+ /// <summary> Holds the default value of the publishers consumer active flag. </summary>
+ public static final bool PUBLISHER_CONSUMER_ACTIVE_DEFAULT = true;
+
+ /// <summary> Holds the name of the property to get the receivers consumer active flag from. </summary>
+ public static final string RECEIVER_CONSUMER_ACTIVE_PROPNAME = "receiverConsumerActive";
+
+ /// <summary> Holds the default value of the receivers consumer active flag. </summary>
+ public static final bool RECEIVER_CONSUMER_ACTIVE_DEFAULT = true;
+
+ /// <summary> Holds the name of the property to get the destination name root from. </summary>
+ public static final string SEND_DESTINATION_NAME_ROOT_PROPNAME = "sendDestinationRoot";
+
+ /// <summary> Holds the root of the name of the default destination to send to. </summary>
+ public static final string SEND_DESTINATION_NAME_ROOT_DEFAULT = "sendTo";
+
+ /// <summary> Holds the name of the property to get the destination name root from. </summary>
+ public static final string RECEIVE_DESTINATION_NAME_ROOT_PROPNAME = "receiveDestinationRoot";
+
+ /// <summary> Holds the root of the name of the default destination to send to. </summary>
+ public static final string RECEIVE_DESTINATION_NAME_ROOT_DEFAULT = "receiveFrom";
+
+ /// <summary> Holds the name of the proeprty to get the destination count from. </summary>
+ public static final string DESTINATION_COUNT_PROPNAME = "destinationCount";
+
+ /// <summary> Defines the default number of destinations to ping. </summary>
+ public static final int DESTINATION_COUNT_DEFAULT = 1;
+
+ /// <summary> Holds the name of the property to get the p2p or pub/sub messaging mode from. </summary>
+ public static final string PUBSUB_PROPNAME = "pubsub";
+
+ /// <summary> Holds the pub/sub mode default, true means ping a topic, false means ping a queue. </summary>
+ public static final bool PUBSUB_DEFAULT = false;
+
+ // ====================== JMS Options and Flags =================================
+
+ /// <summary> Holds the name of the property to get the test delivery mode from. </summary>
+ public static final string PERSISTENT_MODE_PROPNAME = "persistent";
+
+ /// <summary> Holds the message delivery mode to use for the test. </summary>
+ public static final bool PERSISTENT_MODE_DEFAULT = false;
+
+ /// <summary> Holds the name of the property to get the test transactional mode from. </summary>
+ public static final string TRANSACTED_PUBLISHER_PROPNAME = "transactedPublisher";
+
+ /// <summary> Holds the transactional mode to use for the test. </summary>
+ public static final bool TRANSACTED_PUBLISHER_DEFAULT = false;
+
+ /// <summary> Holds the name of the property to get the test transactional mode from. </summary>
+ public static final string TRANSACTED_RECEIVER_PROPNAME = "transactedReceiver";
+
+ /// <summary> Holds the transactional mode to use for the test. </summary>
+ public static final bool TRANSACTED_RECEIVER_DEFAULT = false;
+
+ /// <summary> Holds the name of the property to set the no local flag from. </summary>
+ public static final string NO_LOCAL_PROPNAME = "noLocal";
+
+ /// <summary> Defines the default value of the no local flag to use when consuming messages. </summary>
+ public static final bool NO_LOCAL_DEFAULT = false;
+
+ /// <summary> Holds the name of the property to get the message acknowledgement mode from. </summary>
+ public static final string ACK_MODE_PROPNAME = "ackMode";
+
+ /// <summary> Defines the default message acknowledgement mode. </summary>
+ public static final int ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE;
+
+ /// <summary> Holds the name of the property to get the durable subscriptions flag from, when doing pub/sub messaging. </summary>
+ public static final string DURABLE_SUBSCRIPTION_PROPNAME = "durableSubscription";
+
+ /// <summary> Defines the default value of the durable subscriptions flag. </summary>
+ public static final bool DURABLE_SUBSCRIPTION_DEFAULT = false;
+
+ // ====================== Qpid/AMQP Options and Flags ================================
+
+ /// <summary> Holds the name of the property to set the exclusive flag from. </summary>
+ public static final string EXCLUSIVE_PROPNAME = "exclusive";
+
+ /// <summary> Defines the default value of the exclusive flag to use when consuming messages. </summary>
+ public static final bool EXCLUSIVE_DEFAULT = false;
+
+ /// <summary> Holds the name of the property to set the immediate flag from. </summary>
+ public static final string IMMEDIATE_PROPNAME = "immediate";
+
+ /// <summary> Defines the default value of the immediate flag to use when sending messages. </summary>
+ public static final bool IMMEDIATE_DEFAULT = false;
+
+ /// <summary> Holds the name of the property to set the mandatory flag from. </summary>
+ public static final string MANDATORY_PROPNAME = "mandatory";
+
+ /// <summary> Defines the default value of the mandatory flag to use when sending messages. </summary>
+ public static final bool MANDATORY_DEFAULT = false;
+
+ /// <summary> Holds the name of the property to get the durable destinations flag from. </summary>
+ public static final string DURABLE_DESTS_PROPNAME = "durableDests";
+
+ /// <summary> Default value for the durable destinations flag. </summary>
+ public static final bool DURABLE_DESTS_DEFAULT = false;
+
+ /// <summary> Holds the name of the property to set the prefetch size from. </summary>
+ public static final string PREFETCH_PROPNAME = "prefetch";
+
+ /// <summary> Defines the default prefetch size to use when consuming messages. </summary>
+ public static final int PREFETCH_DEFAULT = 100;
+
+ // ====================== Common Test Parameters ================================
+
+ /// <summary> Holds the name of the property to get the test message size from. </summary>
+ public static final string MESSAGE_SIZE_PROPNAME = "messageSize";
+
+ /// <summary> Used to set up a default message size. </summary>
+ public static final int MESSAGE_SIZE_DEAFULT = 0;
+
+ /// <summary> Holds the name of the property to get the message rate from. </summary>
+ public static final string RATE_PROPNAME = "rate";
+
+ /// <summary> Defines the default rate (in pings per second) to send pings at. 0 means as fast as possible, no restriction. </summary>
+ public static final int RATE_DEFAULT = 0;
+
+ /// <summary> Holds the name of the proeprty to get the. </summary>
+ public static final string SELECTOR_PROPNAME = "selector";
+
+ /// <summary> Holds the default message selector. </summary>
+ public static final string SELECTOR_DEFAULT = "";
+
+ /// <summary> Holds the name of the property to get the waiting timeout for response messages. </summary>
+ public static final string TIMEOUT_PROPNAME = "timeout";
+
+ /// <summary> Default time to wait before assuming that a ping has timed out. </summary>
+ public static final long TIMEOUT_DEFAULT = 30000;
+
+ /// <summary> Holds the name of the property to get the commit batch size from. </summary>
+ public static final string TX_BATCH_SIZE_PROPNAME = "commitBatchSize";
+
+ /// <summary> Defines the default number of pings to send in each transaction when running transactionally. </summary>
+ public static final int TX_BATCH_SIZE_DEFAULT = 1;
+
+ /// <summary> Holds the name of the property to set the maximum amount of pending message data for a producer to hold. </summary>
+ public static final string MAX_PENDING_PROPNAME = "maxPending";
+
+ /// <summary> Defines the default maximum quantity of pending message data to allow producers to hold. </summary>
+ public static final int MAX_PENDING_DEFAULT = 0;
+
+ /// <summary> Holds the name of the property to get the publisher rollback flag from. </summary>
+ public static final string ROLLBACK_PUBLISHER_PROPNAME = "rollbackPublisher";
+
+ /// <summary> Holds the default publisher roll back setting. </summary>
+ public static final bool ROLLBACK_PUBLISHER_DEFAULT = false;
+
+ /// <summary> Holds the name of the property to get the publisher rollback flag from. </summary>
+ public static final string ROLLBACK_RECEIVER_PROPNAME = "rollbackReceiver";
+
+ /// <summary> Holds the default publisher roll back setting. </summary>
+ public static final bool ROLLBACK_RECEIVER_DEFAULT = false;
+
+ // ====================== Options that control the bahviour of the test framework. =========================
+
+ /// <summary> Holds the name of the property to get the behavioural mode of not applicable assertions. </summary>
+ public static final string NOT_APPLICABLE_ASSERTION_PROPNAME = "notApplicableAssertion";
+
+ /// <summary> Holds the default behavioral mode of not applicable assertions, which is logging them as a warning. </summary>
+ public static final string NOT_APPLICABLE_ASSERTION_DEFAULT = "warn";
+
+ /// <summary> Holds the name of the property to get the verbose mode proeprty from. </summary>
+ public static final string VERBOSE_PROPNAME = "verbose";
+
+ /// <summary> Holds the default verbose mode. </summary>
+ public static final bool VERBOSE_DEFAULT = false;
+
+ /// <summary> Holds the default configuration properties. </summary>
+ public static ParsedProperties defaults = new ParsedProperties();
+
+ static
+ {
+ defaults.setPropertyIfNull(INITIAL_CONTEXT_FACTORY_PROPNAME, INITIAL_CONTEXT_FACTORY_DEFAULT);
+ defaults.setPropertyIfNull(BROKER_PROPNAME, BROKER_DEFAULT);
+ defaults.setPropertyIfNull(VIRTUAL_HOST_PROPNAME, VIRTUAL_HOST_DEFAULT);
+ defaults.setPropertyIfNull(USERNAME_PROPNAME, USERNAME_DEFAULT);
+ defaults.setPropertyIfNull(PASSWORD_PROPNAME, PASSWORD_DEFAULT);
+
+ defaults.setPropertyIfNull(PUBLISHER_PRODUCER_BIND_PROPNAME, PUBLISHER_PRODUCER_BIND_DEFAULT);
+ defaults.setPropertyIfNull(PUBLISHER_CONSUMER_BIND_PROPNAME, PUBLISHER_CONSUMER_BIND_DEFAULT);
+ defaults.setPropertyIfNull(RECEIVER_PRODUCER_BIND_PROPNAME, RECEIVER_PRODUCER_BIND_DEFAULT);
+ defaults.setPropertyIfNull(RECEIVER_CONSUMER_BIND_PROPNAME, RECEIVER_CONSUMER_BIND_DEFAULT);
+ defaults.setPropertyIfNull(PUBLISHER_CONSUMER_ACTIVE_PROPNAME, PUBLISHER_CONSUMER_ACTIVE_DEFAULT);
+ defaults.setPropertyIfNull(RECEIVER_CONSUMER_ACTIVE_PROPNAME, RECEIVER_CONSUMER_ACTIVE_DEFAULT);
+ defaults.setPropertyIfNull(SEND_DESTINATION_NAME_ROOT_PROPNAME, SEND_DESTINATION_NAME_ROOT_DEFAULT);
+ defaults.setPropertyIfNull(RECEIVE_DESTINATION_NAME_ROOT_PROPNAME, RECEIVE_DESTINATION_NAME_ROOT_DEFAULT);
+ defaults.setPropertyIfNull(DESTINATION_COUNT_PROPNAME, DESTINATION_COUNT_DEFAULT);
+ defaults.setPropertyIfNull(PUBSUB_PROPNAME, PUBSUB_DEFAULT);
+
+ defaults.setPropertyIfNull(PERSISTENT_MODE_PROPNAME, PERSISTENT_MODE_DEFAULT);
+ defaults.setPropertyIfNull(TRANSACTED_PUBLISHER_PROPNAME, TRANSACTED_PUBLISHER_DEFAULT);
+ defaults.setPropertyIfNull(TRANSACTED_RECEIVER_PROPNAME, TRANSACTED_RECEIVER_DEFAULT);
+ defaults.setPropertyIfNull(NO_LOCAL_PROPNAME, NO_LOCAL_DEFAULT);
+ defaults.setPropertyIfNull(ACK_MODE_PROPNAME, ACK_MODE_DEFAULT);
+ defaults.setPropertyIfNull(DURABLE_SUBSCRIPTION_PROPNAME, DURABLE_SUBSCRIPTION_DEFAULT);
+
+ defaults.setPropertyIfNull(EXCLUSIVE_PROPNAME, EXCLUSIVE_DEFAULT);
+ defaults.setPropertyIfNull(IMMEDIATE_PROPNAME, IMMEDIATE_DEFAULT);
+ defaults.setPropertyIfNull(MANDATORY_PROPNAME, MANDATORY_DEFAULT);
+ defaults.setPropertyIfNull(DURABLE_DESTS_PROPNAME, DURABLE_DESTS_DEFAULT);
+ defaults.setPropertyIfNull(PREFETCH_PROPNAME, PREFETCH_DEFAULT);
+
+ defaults.setPropertyIfNull(MESSAGE_SIZE_PROPNAME, MESSAGE_SIZE_DEAFULT);
+ defaults.setPropertyIfNull(RATE_PROPNAME, RATE_DEFAULT);
+ defaults.setPropertyIfNull(SELECTOR_PROPNAME, SELECTOR_DEFAULT);
+ defaults.setPropertyIfNull(TIMEOUT_PROPNAME, TIMEOUT_DEFAULT);
+ defaults.setPropertyIfNull(TX_BATCH_SIZE_PROPNAME, TX_BATCH_SIZE_DEFAULT);
+ defaults.setPropertyIfNull(MAX_PENDING_PROPNAME, MAX_PENDING_DEFAULT);
+ defaults.setPropertyIfNull(ROLLBACK_PUBLISHER_PROPNAME, ROLLBACK_PUBLISHER_DEFAULT);
+ defaults.setPropertyIfNull(ROLLBACK_RECEIVER_PROPNAME, ROLLBACK_RECEIVER_DEFAULT);
+
+ defaults.setPropertyIfNull(NOT_APPLICABLE_ASSERTION_PROPNAME, NOT_APPLICABLE_ASSERTION_DEFAULT);
+ defaults.setPropertyIfNull(VERBOSE_PROPNAME, VERBOSE_DEFAULT);
+ }
+
+ /// <summary> Creates a test configuration based on the defaults. </summary>
+ public MessagingTestConfigProperties()
+ {
+ super(defaults);
+ }
+
+ /// <summary>
+ /// Creates a test configuration based on the supplied properties.
+ /// </summary>
+ /// <param name="properties"> The test configuration. </param>
+ public MessagingTestConfigProperties(Properties properties)
+ {
+ super(properties);
+ }
+
+ /// <summary>
+ /// The size of test messages to send.
+ /// </summary>
+ /// <return> The size of test messages to send. </return>
+ public int getMessageSize()
+ {
+ return getPropertyAsInteger(MESSAGE_SIZE_PROPNAME);
+ }
+
+ /// <summary>
+ /// Flag to indicate that the publishing producer should be set up to publish to a destination.
+ /// </summary>
+ /// <return> Flag to indicate that the publishing producer should be set up to publish to a destination. </return>
+ public bool getPublisherProducerBind()
+ {
+ return getPropertyAsBoolean(PUBLISHER_PRODUCER_BIND_PROPNAME);
+ }
+
+ /// <summary>
+ /// Flag to indicate that the publishing consumer should be set up to receive from a destination.
+ /// </summary>
+ /// <return> Flag to indicate that the publishing consumer should be set up to receive from a destination. </return>
+ public bool getPublisherConsumerBind()
+ {
+ return getPropertyAsBoolean(PUBLISHER_CONSUMER_BIND_PROPNAME);
+ }
+
+ /// <summary>
+ /// Flag to indicate that the receiving producer should be set up to publish to a destination.
+ /// </summary>
+ /// <return> Flag to indicate that the receiving producer should be set up to publish to a destination. </return>
+ public bool getReceiverProducerBind()
+ {
+ return getPropertyAsBoolean(RECEIVER_PRODUCER_BIND_PROPNAME);
+ }
+
+ /// <summary>
+ /// Flag to indicate that the receiving consumer should be set up to receive from a destination.
+ /// </summary>
+ /// <return> Flag to indicate that the receiving consumer should be set up to receive from a destination. </return>
+ public bool getReceiverConsumerBind()
+ {
+ return getPropertyAsBoolean(RECEIVER_CONSUMER_BIND_PROPNAME);
+ }
+
+ /// <summary>
+ /// Flag to indicate that the publishing consumer should be created and actively listening.
+ /// </summary>
+ /// <return> Flag to indicate that the publishing consumer should be created. </return>
+ public bool getPublisherConsumerActive()
+ {
+ return getPropertyAsBoolean(PUBLISHER_CONSUMER_ACTIVE_PROPNAME);
+ }
+
+ /// <summary>
+ /// Flag to indicate that the receiving consumers should be created and actively listening.
+ /// </summary>
+ /// <return> Flag to indicate that the receiving consumers should be created and actively listening. </return>
+ public bool getReceiverConsumerActive()
+ {
+ return getPropertyAsBoolean(RECEIVER_CONSUMER_ACTIVE_PROPNAME);
+ }
+
+ /// <summary>
+ /// A root to create all test destination names from.
+ /// </summary>
+ /// <return> A root to create all test destination names from. </return>
+ public string getSendDestinationNameRoot()
+ {
+ return getProperty(SEND_DESTINATION_NAME_ROOT_PROPNAME);
+ }
+
+ /// <summary>
+ /// A root to create all receiving destination names from.
+ /// </summary>
+ /// <return> A root to create all receiving destination names from. </return>
+ public string getReceiveDestinationNameRoot()
+ {
+ return getProperty(RECEIVE_DESTINATION_NAME_ROOT_PROPNAME);
+ }
+
+ /// <summary>
+ /// Flag to indicate that persistent messages should be used.
+ /// </summary>
+ /// <return> Flag to indicate that persistent messages should be used. </return>
+ public bool getPersistentMode()
+ {
+ return getPropertyAsBoolean(PERSISTENT_MODE_PROPNAME);
+ }
+
+ /// <summary>
+ /// Flag to indicate that transactional messages should be sent by the publisher.
+ /// </summary>
+ /// <return> Flag to indicate that transactional messages should be sent by the publisher. </return>
+ public bool getPublisherTransacted()
+ {
+ return getPropertyAsBoolean(TRANSACTED_PUBLISHER_PROPNAME);
+ }
+
+ /// <summary>
+ /// Flag to indicate that transactional receives should be used by the receiver.
+ /// </summary>
+ /// <return> Flag to indicate that transactional receives should be used by the receiver. </return>
+ public bool getReceiverTransacted()
+ {
+ return getPropertyAsBoolean(TRANSACTED_PUBLISHER_PROPNAME);
+ }
+
+ /// <summary>
+ /// The name of the virtual host to run all tests over.
+ /// </summary>
+ /// <return> The name of the virtual host to run all tests over. </return>
+ public string getVirtualHost()
+ {
+ return getProperty(VIRTUAL_HOST_PROPNAME);
+ }
+
+ /// <summary>
+ /// Limiting rate for each sender in messages per second, or zero for unlimited.
+ /// </summary>
+ /// <return> Limiting rate for each sender in messages per second, or zero for unlimited. </return>
+ public string getRate()
+ {
+ return getProperty(RATE_PROPNAME);
+ }
+
+ /// <summary>
+ /// Flag to indicate that test messages should be received publish/subscribe style by all receivers.
+ /// </summary>
+ /// <return> Flag to indicate that test messages should be received publish/subscribe style by all receivers. </return>
+ public bool getPubsub()
+ {
+ return getPropertyAsBoolean(PUBSUB_PROPNAME);
+ }
+
+ /// <summary>
+ /// The username credentials to run tests with.
+ /// </summary>
+ /// <return> The username credentials to run tests with. </return>
+ public string getUsername()
+ {
+ return getProperty(USERNAME_PROPNAME);
+ }
+
+ /// <summary>
+ /// The password credentials to run tests with.
+ /// </summary>
+ /// <return> The password credentials to run tests with. </return>
+ public string getPassword()
+ {
+ return getProperty(PASSWORD_PROPNAME);
+ }
+
+ /// <summary>
+ /// The timeout duration to fail tests on, should they receive no messages within it.
+ /// </summary>
+ /// <return> The timeout duration to fail tests on, should they receive no messages within it. </return>
+ public long getTimeout()
+ {
+ return getPropertyAsLong(TIMEOUT_PROPNAME);
+ }
+
+ /// <summary>
+ /// The number of messages to batch into each transaction in transational tests.
+ /// </summary>
+ /// <return> The number of messages to batch into each transaction in transational tests. </return>
+ public int getTxBatchSize()
+ {
+ return getPropertyAsInteger(TX_BATCH_SIZE_PROPNAME);
+ }
+
+ /// <summary>
+ /// Flag to indicate that tests should use durable destinations.
+ /// </summary>
+ /// <return> Flag to indicate that tests should use durable destinations. </return>
+ public bool getDurableDests()
+ {
+ return getPropertyAsBoolean(DURABLE_DESTS_PROPNAME);
+ }
+
+ /// <summary>
+ /// The ack mode for message receivers to use.
+ /// </summary>
+ /// <return> The ack mode for message receivers to use. </return>
+ public int getAckMode()
+ {
+ return getPropertyAsInteger(ACK_MODE_PROPNAME);
+ }
+
+ /// <summary>
+ /// Flag to indicate that tests should use durable subscriptions.
+ /// </summary>
+ /// <return> Flag to indicate that tests should use durable subscriptions. </return>
+ public bool getDurableSubscription()
+ {
+ return getPropertyAsBoolean(DURABLE_SUBSCRIPTION_PROPNAME);
+ }
+
+ /// <summary>
+ /// The maximum amount of in-flight data, in bytes, that tests should send at any time.
+ /// </summary>
+ /// <return> The maximum amount of in-flight data, in bytes, that tests should send at any time. </return>
+ public int getMaxPending()
+ {
+ return getPropertyAsInteger(MAX_PENDING_PROPNAME);
+ }
+
+ /// <summary>
+ /// The size of the prefetch queue to use.
+ /// </summary>
+ /// <return> The size of the prefetch queue to use. </return>
+ public int getPrefetch()
+ {
+ return getPropertyAsInteger(PREFETCH_PROPNAME);
+ }
+
+ /// <summary>
+ /// Flag to indicate that subscriptions should be no-local.
+ /// </summary>
+ /// <return> Flag to indicate that subscriptions should be no-local. </return>
+ public bool getNoLocal()
+ {
+ return getPropertyAsBoolean(NO_LOCAL_PROPNAME);
+ }
+
+ /// <summary>
+ /// Flag to indicate that subscriptions should be exclusive.
+ /// </summary>
+ /// <return> Flag to indicate that subscriptions should be exclusive. </return>
+ public bool getExclusive()
+ {
+ return getPropertyAsBoolean(EXCLUSIVE_PROPNAME);
+ }
+
+ /// <summary>
+ /// Flag to indicate that messages must be delivered immediately.
+ /// </summary>
+ /// <return> Flag to indicate that messages must be delivered immediately. </return>
+ public bool getImmediate()
+ {
+ return getPropertyAsBoolean(IMMEDIATE_PROPNAME);
+ }
+
+ /// <summary>
+ /// Flag to indicate that messages must be routable.
+ /// </summary>
+ /// <return> Flag to indicate that messages must be routable. </return>
+ public bool getMandatory()
+ {
+ return getPropertyAsBoolean(MANDATORY_PROPNAME);
+ }
+
+ /// <summary>
+ /// Gets the value of a flag to indicate that the publisher should rollback all messages sent.
+ /// </summary>
+ /// <return> A flag to indicate that the publisher should rollback all messages sent. </return>
+ public bool getRollbackPublisher()
+ {
+ return getPropertyAsBoolean(ROLLBACK_PUBLISHER_PROPNAME);
+ }
+
+ /// <summary>
+ /// Gets the value of a flag to indicate that the receiver should rollback all messages received, then receive them
+ /// again.
+ /// </summary>
+ /// <return> A flag to indicate that the publisher should rollback all messages received. </return>
+ public bool getRollbackReceiver()
+ {
+ return getPropertyAsBoolean(ROLLBACK_RECEIVER_PROPNAME);
+ }
+
+ /// <summary>
+ /// Gets the behavioural mode of not applicable assertions. Should be one of 'quiet', 'warn' or 'fail'.
+ /// </summary>
+ /// <return> The behavioural mode of not applicable assertions. </return>
+ public string getNotApplicableAssertionMode()
+ {
+ return getProperty(NOT_APPLICABLE_ASSERTION_PROPNAME);
+ }
+ }
+ */
} \ No newline at end of file
diff --git a/dotnet/Qpid.Integration.Tests/framework/sequencers/CircuitFactory.cs b/dotnet/Qpid.Integration.Tests/framework/sequencers/CircuitFactory.cs
index 463cf06dfb..4be08c3f38 100644
--- a/dotnet/Qpid.Integration.Tests/framework/sequencers/CircuitFactory.cs
+++ b/dotnet/Qpid.Integration.Tests/framework/sequencers/CircuitFactory.cs
@@ -1,85 +1,85 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using Apache.Qpid.Integration.Tests.framework;
-//using org.apache.qpid.util.ConversationFactory;
-
-//using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
-
-//using javax.jms.JMSException;
-//using javax.jms.Message;
-
-using System.Collections.Generic;//.IList;
-//using System.Collections.Generic.IDictionary;
-//using java.util.Properties;
-
-namespace Apache.Qpid.Integration.Tests.framework.sequencers
-{
- /// <summary>
- /// A CircuitFactory is responsibile for creating test circuits appropriate to the context that a test case is
- /// running in, and providing an implementation of a standard test procedure over a test circuit.
- ///
- /// <p/><table id="crc"><caption>CRC Card</caption>
- /// <tr><th> Responsibilities
- /// <tr><td> Provide a standard test procedure over a test circuit.
- /// <tr><td> Construct test circuits appropriate to a tests context.
- /// </table>
- /// </summary>
- public interface CircuitFactory
- {
- /// <summary>
- /// Creates a test circuit for the test, configered by the test parameters specified.
- /// </summary>
- /// <param name="testProperties"> The test parameters. </param>
- ///
- /// <return> A test circuit. </return>
- Circuit CreateCircuit(TestModel testProperties);
-
- /// <summary>
- /// Sets the sender test client to coordinate the test with.
- /// </summary>
- /// <param name="sender"> The contact details of the sending client in the test. </param>
- void SetSender(TestClientDetails sender);
-
- /// <summary>
- /// Sets the receiving test client to coordinate the test with.
- /// </summary>
- /// <param name="receiver"> The contact details of the sending client in the test. </param>
- void SetReceiver(TestClientDetails receiver);
-
- /// <summary>
- /// Supplies the sending test client.
- /// </summary>
- /// <return> The sending test client. </return>
- TestClientDetails GetSender();
-
- /// <summary>
- /// Supplies the receiving test client.
- /// </summary>
- /// <return> The receiving test client. </return>
- IList<TestClientDetails> GetReceivers();
-
- /// <summary>
- /// Accepts the conversation factory over which to hold the test coordinating conversation.
- /// </summary>
- /// <param name="conversationFactory"> The conversation factory to coordinate the test over. </param>
- //void setConversationFactory(ConversationFactory conversationFactory);
- }
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using Apache.Qpid.Integration.Tests.framework;
+//using org.apache.qpid.util.ConversationFactory;
+
+//using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
+
+//using javax.jms.JMSException;
+//using javax.jms.Message;
+
+using System.Collections.Generic;//.IList;
+//using System.Collections.Generic.IDictionary;
+//using java.util.Properties;
+
+namespace Apache.Qpid.Integration.Tests.framework.sequencers
+{
+ /// <summary>
+ /// A CircuitFactory is responsibile for creating test circuits appropriate to the context that a test case is
+ /// running in, and providing an implementation of a standard test procedure over a test circuit.
+ ///
+ /// <p/><table id="crc"><caption>CRC Card</caption>
+ /// <tr><th> Responsibilities
+ /// <tr><td> Provide a standard test procedure over a test circuit.
+ /// <tr><td> Construct test circuits appropriate to a tests context.
+ /// </table>
+ /// </summary>
+ public interface CircuitFactory
+ {
+ /// <summary>
+ /// Creates a test circuit for the test, configered by the test parameters specified.
+ /// </summary>
+ /// <param name="testProperties"> The test parameters. </param>
+ ///
+ /// <return> A test circuit. </return>
+ Circuit CreateCircuit(TestModel testProperties);
+
+ /// <summary>
+ /// Sets the sender test client to coordinate the test with.
+ /// </summary>
+ /// <param name="sender"> The contact details of the sending client in the test. </param>
+ void SetSender(TestClientDetails sender);
+
+ /// <summary>
+ /// Sets the receiving test client to coordinate the test with.
+ /// </summary>
+ /// <param name="receiver"> The contact details of the sending client in the test. </param>
+ void SetReceiver(TestClientDetails receiver);
+
+ /// <summary>
+ /// Supplies the sending test client.
+ /// </summary>
+ /// <return> The sending test client. </return>
+ TestClientDetails GetSender();
+
+ /// <summary>
+ /// Supplies the receiving test client.
+ /// </summary>
+ /// <return> The receiving test client. </return>
+ IList<TestClientDetails> GetReceivers();
+
+ /// <summary>
+ /// Accepts the conversation factory over which to hold the test coordinating conversation.
+ /// </summary>
+ /// <param name="conversationFactory"> The conversation factory to coordinate the test over. </param>
+ //void setConversationFactory(ConversationFactory conversationFactory);
+ }
} \ No newline at end of file
diff --git a/dotnet/Qpid.Integration.Tests/interactive/FailoverTest.cs b/dotnet/Qpid.Integration.Tests/interactive/FailoverTest.cs
index 547266a7a5..142ac40b27 100644
--- a/dotnet/Qpid.Integration.Tests/interactive/FailoverTest.cs
+++ b/dotnet/Qpid.Integration.Tests/interactive/FailoverTest.cs
@@ -73,12 +73,12 @@ namespace Apache.Qpid.Integration.Tests.interactive
/// <summary>Used to wait for test completion on. </summary>
private static object testComplete = new Object();
- /// <summary>Used to wait for failover completion on. </summary>
+ /// <summary>Used to wait for failover completion on. </summary>
private static object failoverComplete = new Object();
bool failedOver=false;
- /// <summary>Used to record the extra message count (1) if the message sent right after failover actually made it to the new broker.</summary>
+ /// <summary>Used to record the extra message count (1) if the message sent right after failover actually made it to the new broker.</summary>
int _extraMessage = 0;
/// <summary>
diff --git a/dotnet/Qpid.Integration.Tests/interactive/SendReceiveTest.cs b/dotnet/Qpid.Integration.Tests/interactive/SendReceiveTest.cs
index ebc9307c2e..68d7a2ae68 100644
--- a/dotnet/Qpid.Integration.Tests/interactive/SendReceiveTest.cs
+++ b/dotnet/Qpid.Integration.Tests/interactive/SendReceiveTest.cs
@@ -1,181 +1,181 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Threading;
-using log4net;
-using NUnit.Framework;
-using Apache.Qpid.Messaging;
-using Apache.Qpid.Client.Qms;
-using Apache.Qpid.Client;
-using Apache.Qpid.Integration.Tests.testcases;
-
-namespace Apache.Qpid.Integration.Tests.interactive
-{
- /// <summary>
- /// SendReceiveTest provides a quick interactive send-receive test, where the user is prompted to trigger each send or receive.
- ///
- /// <p><table id="crc"><caption>CRC Card</caption>
- /// <tr><th> Responsibilities <th> Collaborations
- /// <tr><td> Run an interactive send-receive loop prompting user to trigger each event.
- /// </table>
- /// </summary>
- [TestFixture, Category("Interactive")]
- public class SendReceiveTest : BaseMessagingTestFixture
- {
- /// <summary>Used for debugging purposes.</summary>
- private static ILog log = LogManager.GetLogger(typeof(SendReceiveTest));
-
- /// <summary>Defines the name of the test topic to use with the tests.</summary>
- public const string TEST_ROUTING_KEY = "quicktestkey";
-
- /// <summary>The number of consumers to test.</summary>
- private const int CONSUMER_COUNT = 5;
-
- /// <summary>The number of test messages to send.</summary>
- private const int MESSAGE_COUNT = 10;
-
- /// <summary>Monitor used to signal succesfull receipt of all test messages.</summary>
- AutoResetEvent _finishedEvent;
-
- /// <summary>Used to count test messages received so far.</summary>
- private int _messageReceivedCount;
-
- /// <summary>Used to hold the expected number of messages to receive.</summary>
- private int expectedMessageCount;
-
- /// <summary>Flag used to indicate that all messages really were received, and that the test did not just time out. </summary>
- private bool allReceived;
-
- /// <summary> Creates one producing end-point and many consuming end-points connected on a topic. </summary>
- [SetUp]
- public override void Init()
- {
- base.Init();
-
- // Reset all test counts and flags.
- _messageReceivedCount = 0;
- allReceived = false;
- _finishedEvent = new AutoResetEvent(false);
- }
-
- /// <summary> Cleans up all test end-points. </summary>
- [TearDown]
- public override void Shutdown()
- {
- try
- {
- // Close all end points for producer and consumers.
- // Producer is on 0, and consumers on 1 .. n, so loop is from 0 to n inclusive.
- for (int i = 0; i <= CONSUMER_COUNT; i++)
- {
- CloseEndPoint(i);
- }
- }
- finally
- {
- base.Shutdown();
- }
- }
-
- /// <summary> Check that all consumers on a topic each receive all message on it. </summary>
- [Test]
- public void AllConsumerReceiveAllMessagesOnTopic()
- {
- // Create end-points for all the consumers in the test.
- for (int i = 1; i <= CONSUMER_COUNT; i++)
- {
- SetUpEndPoint(i, false, true, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, false, ExchangeNameDefaults.TOPIC,
- true, false, null);
- testConsumer[i].OnMessage += new MessageReceivedDelegate(OnMessage);
- }
-
- // Create an end-point to publish to the test topic.
- SetUpEndPoint(0, true, false, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, false, ExchangeNameDefaults.TOPIC,
- true, false, null);
-
- expectedMessageCount = (MESSAGE_COUNT * CONSUMER_COUNT);
-
- PromptAndWait("Press to send...");
-
- for (int i = 0; i < MESSAGE_COUNT; i++)
- {
- testProducer[0].Send(testChannel[0].CreateTextMessage("A"));
- }
-
- _finishedEvent.WaitOne(new TimeSpan(0, 0, 0, 10), false);
-
- PromptAndWait("Press to complete test...");
-
- // Check that all messages really were received.
- Assert.IsTrue(allReceived, "All messages were not received, only got " + _messageReceivedCount + " but wanted " + expectedMessageCount);
- }
-
- /// <summary> Check that consumers on the same queue receive each message once accross all consumers. </summary>
- //[Test]
- public void AllConsumerReceiveAllMessagesOnDirect()
- {
- // Create end-points for all the consumers in the test.
- for (int i = 1; i <= CONSUMER_COUNT; i++)
- {
- SetUpEndPoint(i, false, true, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, false, ExchangeNameDefaults.DIRECT,
- true, false, null);
- testConsumer[i].OnMessage += new MessageReceivedDelegate(OnMessage);
- }
-
- // Create an end-point to publish to the test topic.
- SetUpEndPoint(0, true, false, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, false, ExchangeNameDefaults.DIRECT,
- true, false, null);
-
- expectedMessageCount = MESSAGE_COUNT;
-
- for (int i = 0; i < MESSAGE_COUNT; i++)
- {
- testProducer[0].Send(testChannel[0].CreateTextMessage("A"));
- }
-
- _finishedEvent.WaitOne(new TimeSpan(0, 0, 0, 10), false);
-
- // Check that all messages really were received.
- Assert.IsTrue(allReceived, "All messages were not received, only got: " + _messageReceivedCount + " but wanted " + expectedMessageCount);
- }
-
- /// <summary> Atomically increments the message count on every message, and signals once all messages in the test are received. </summary>
- public void OnMessage(IMessage m)
- {
- int newCount = Interlocked.Increment(ref _messageReceivedCount);
-
- if (newCount >= expectedMessageCount)
- {
- allReceived = true;
- _finishedEvent.Set();
- }
- }
-
- /// <summary>Prompts the user on stdout and waits for a reply on stdin, using the specified prompt message.</summary>
- ///
- /// <param name="message">The message to prompt the user with.</param>
- private void PromptAndWait(string message)
- {
- Console.WriteLine("\n" + message);
- Console.ReadLine();
- }
- }
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Threading;
+using log4net;
+using NUnit.Framework;
+using Apache.Qpid.Messaging;
+using Apache.Qpid.Client.Qms;
+using Apache.Qpid.Client;
+using Apache.Qpid.Integration.Tests.testcases;
+
+namespace Apache.Qpid.Integration.Tests.interactive
+{
+ /// <summary>
+ /// SendReceiveTest provides a quick interactive send-receive test, where the user is prompted to trigger each send or receive.
+ ///
+ /// <p><table id="crc"><caption>CRC Card</caption>
+ /// <tr><th> Responsibilities <th> Collaborations
+ /// <tr><td> Run an interactive send-receive loop prompting user to trigger each event.
+ /// </table>
+ /// </summary>
+ [TestFixture, Category("Interactive")]
+ public class SendReceiveTest : BaseMessagingTestFixture
+ {
+ /// <summary>Used for debugging purposes.</summary>
+ private static ILog log = LogManager.GetLogger(typeof(SendReceiveTest));
+
+ /// <summary>Defines the name of the test topic to use with the tests.</summary>
+ public const string TEST_ROUTING_KEY = "quicktestkey";
+
+ /// <summary>The number of consumers to test.</summary>
+ private const int CONSUMER_COUNT = 5;
+
+ /// <summary>The number of test messages to send.</summary>
+ private const int MESSAGE_COUNT = 10;
+
+ /// <summary>Monitor used to signal succesfull receipt of all test messages.</summary>
+ AutoResetEvent _finishedEvent;
+
+ /// <summary>Used to count test messages received so far.</summary>
+ private int _messageReceivedCount;
+
+ /// <summary>Used to hold the expected number of messages to receive.</summary>
+ private int expectedMessageCount;
+
+ /// <summary>Flag used to indicate that all messages really were received, and that the test did not just time out. </summary>
+ private bool allReceived;
+
+ /// <summary> Creates one producing end-point and many consuming end-points connected on a topic. </summary>
+ [SetUp]
+ public override void Init()
+ {
+ base.Init();
+
+ // Reset all test counts and flags.
+ _messageReceivedCount = 0;
+ allReceived = false;
+ _finishedEvent = new AutoResetEvent(false);
+ }
+
+ /// <summary> Cleans up all test end-points. </summary>
+ [TearDown]
+ public override void Shutdown()
+ {
+ try
+ {
+ // Close all end points for producer and consumers.
+ // Producer is on 0, and consumers on 1 .. n, so loop is from 0 to n inclusive.
+ for (int i = 0; i <= CONSUMER_COUNT; i++)
+ {
+ CloseEndPoint(i);
+ }
+ }
+ finally
+ {
+ base.Shutdown();
+ }
+ }
+
+ /// <summary> Check that all consumers on a topic each receive all message on it. </summary>
+ [Test]
+ public void AllConsumerReceiveAllMessagesOnTopic()
+ {
+ // Create end-points for all the consumers in the test.
+ for (int i = 1; i <= CONSUMER_COUNT; i++)
+ {
+ SetUpEndPoint(i, false, true, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, false, ExchangeNameDefaults.TOPIC,
+ true, false, null);
+ testConsumer[i].OnMessage += new MessageReceivedDelegate(OnMessage);
+ }
+
+ // Create an end-point to publish to the test topic.
+ SetUpEndPoint(0, true, false, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, false, ExchangeNameDefaults.TOPIC,
+ true, false, null);
+
+ expectedMessageCount = (MESSAGE_COUNT * CONSUMER_COUNT);
+
+ PromptAndWait("Press to send...");
+
+ for (int i = 0; i < MESSAGE_COUNT; i++)
+ {
+ testProducer[0].Send(testChannel[0].CreateTextMessage("A"));
+ }
+
+ _finishedEvent.WaitOne(new TimeSpan(0, 0, 0, 10), false);
+
+ PromptAndWait("Press to complete test...");
+
+ // Check that all messages really were received.
+ Assert.IsTrue(allReceived, "All messages were not received, only got " + _messageReceivedCount + " but wanted " + expectedMessageCount);
+ }
+
+ /// <summary> Check that consumers on the same queue receive each message once accross all consumers. </summary>
+ //[Test]
+ public void AllConsumerReceiveAllMessagesOnDirect()
+ {
+ // Create end-points for all the consumers in the test.
+ for (int i = 1; i <= CONSUMER_COUNT; i++)
+ {
+ SetUpEndPoint(i, false, true, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, false, ExchangeNameDefaults.DIRECT,
+ true, false, null);
+ testConsumer[i].OnMessage += new MessageReceivedDelegate(OnMessage);
+ }
+
+ // Create an end-point to publish to the test topic.
+ SetUpEndPoint(0, true, false, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, false, ExchangeNameDefaults.DIRECT,
+ true, false, null);
+
+ expectedMessageCount = MESSAGE_COUNT;
+
+ for (int i = 0; i < MESSAGE_COUNT; i++)
+ {
+ testProducer[0].Send(testChannel[0].CreateTextMessage("A"));
+ }
+
+ _finishedEvent.WaitOne(new TimeSpan(0, 0, 0, 10), false);
+
+ // Check that all messages really were received.
+ Assert.IsTrue(allReceived, "All messages were not received, only got: " + _messageReceivedCount + " but wanted " + expectedMessageCount);
+ }
+
+ /// <summary> Atomically increments the message count on every message, and signals once all messages in the test are received. </summary>
+ public void OnMessage(IMessage m)
+ {
+ int newCount = Interlocked.Increment(ref _messageReceivedCount);
+
+ if (newCount >= expectedMessageCount)
+ {
+ allReceived = true;
+ _finishedEvent.Set();
+ }
+ }
+
+ /// <summary>Prompts the user on stdout and waits for a reply on stdin, using the specified prompt message.</summary>
+ ///
+ /// <param name="message">The message to prompt the user with.</param>
+ private void PromptAndWait(string message)
+ {
+ Console.WriteLine("\n" + message);
+ Console.ReadLine();
+ }
+ }
} \ No newline at end of file
diff --git a/dotnet/Qpid.Integration.Tests/interop/InteropClientTestCase.cs b/dotnet/Qpid.Integration.Tests/interop/InteropClientTestCase.cs
index 7bc0fcf21a..09361b33e8 100644
--- a/dotnet/Qpid.Integration.Tests/interop/InteropClientTestCase.cs
+++ b/dotnet/Qpid.Integration.Tests/interop/InteropClientTestCase.cs
@@ -1,67 +1,87 @@
-using System;
-using System.Text;
-using Apache.Qpid.Messaging;
-
-namespace Apache.Qpid.Integration.Tests.interop
-{
- /// <summary> Defines the possible test case roles that an interop test case can take on. </summary>
- public enum Roles { SENDER, RECEIVER };
-
- /// <summary>
- /// InteropClientTestCase provides an interface that classes implementing test cases from the interop testing spec
- /// (http://cwiki.apache.org/confluence/display/qpid/Interop+Testing+Specification) should implement.
- ///
- /// <p><table id="crc"><caption>CRC Card</caption>
- /// <tr><th> Responsibilities
- /// <tr><td> Supply the name of the test case that this implements.
- /// <tr><td> Accept/Reject invites based on test parameters.
- /// <tr><td> Adapt to assigned roles.
- /// <tr><td> Perform test case actions.
- /// <tr><td> Generate test reports.
- /// </table>
- /// </summary>
- interface InteropClientTestCase
- {
- /// <summary>
- /// Should provide the name of the test case that this class implements. The exact names are defined in the
- /// interop testing spec.
- /// </summary>
- ///
- /// <returns> The name of the test case that this implements. </returns>
- string GetName();
-
- /// <summary>
- /// Determines whether the test invite that matched this test case is acceptable.
- /// </summary>
- ///
- /// <param name="inviteMessage"> The invitation to accept or reject. </param>
- ///
- /// <returns> <tt>true</tt> to accept the invitation, <tt>false</tt> to reject it. </returns>
- ///
- /// @throws JMSException Any JMSException resulting from reading the message are allowed to fall through.
- bool AcceptInvite(IMessage inviteMessage);
-
- /// <summary>
- /// Assigns the role to be played by this test case. The test parameters are fully specified in the
- /// assignment message. When this method return the test case will be ready to execute.
- /// </summary>
- ///
- /// <param name="role"> The role to be played; sender or receiver. </param>
- /// <param name="assignRoleMessage"> The role assingment message, contains the full test parameters. </param>
- void AssignRole(Roles role, IMessage assignRoleMessage);
-
- /// <summary>
- /// Performs the test case actions.
- /// </summary>
- void Start();
-
- /// <summary>
- /// Gets a report on the actions performed by the test case in its assigned role.
- /// </summary>
- ///
- /// <param name="session"> The session to create the report message in. </param>
- ///
- /// <returns> The report message. </returns>
- IMessage GetReport(IChannel channel);
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Text;
+using Apache.Qpid.Messaging;
+
+namespace Apache.Qpid.Integration.Tests.interop
+{
+ /// <summary> Defines the possible test case roles that an interop test case can take on. </summary>
+ public enum Roles { SENDER, RECEIVER };
+
+ /// <summary>
+ /// InteropClientTestCase provides an interface that classes implementing test cases from the interop testing spec
+ /// (http://cwiki.apache.org/confluence/display/qpid/Interop+Testing+Specification) should implement.
+ ///
+ /// <p><table id="crc"><caption>CRC Card</caption>
+ /// <tr><th> Responsibilities
+ /// <tr><td> Supply the name of the test case that this implements.
+ /// <tr><td> Accept/Reject invites based on test parameters.
+ /// <tr><td> Adapt to assigned roles.
+ /// <tr><td> Perform test case actions.
+ /// <tr><td> Generate test reports.
+ /// </table>
+ /// </summary>
+ interface InteropClientTestCase
+ {
+ /// <summary>
+ /// Should provide the name of the test case that this class implements. The exact names are defined in the
+ /// interop testing spec.
+ /// </summary>
+ ///
+ /// <returns> The name of the test case that this implements. </returns>
+ string GetName();
+
+ /// <summary>
+ /// Determines whether the test invite that matched this test case is acceptable.
+ /// </summary>
+ ///
+ /// <param name="inviteMessage"> The invitation to accept or reject. </param>
+ ///
+ /// <returns> <tt>true</tt> to accept the invitation, <tt>false</tt> to reject it. </returns>
+ ///
+ /// @throws JMSException Any JMSException resulting from reading the message are allowed to fall through.
+ bool AcceptInvite(IMessage inviteMessage);
+
+ /// <summary>
+ /// Assigns the role to be played by this test case. The test parameters are fully specified in the
+ /// assignment message. When this method return the test case will be ready to execute.
+ /// </summary>
+ ///
+ /// <param name="role"> The role to be played; sender or receiver. </param>
+ /// <param name="assignRoleMessage"> The role assingment message, contains the full test parameters. </param>
+ void AssignRole(Roles role, IMessage assignRoleMessage);
+
+ /// <summary>
+ /// Performs the test case actions.
+ /// </summary>
+ void Start();
+
+ /// <summary>
+ /// Gets a report on the actions performed by the test case in its assigned role.
+ /// </summary>
+ ///
+ /// <param name="session"> The session to create the report message in. </param>
+ ///
+ /// <returns> The report message. </returns>
+ IMessage GetReport(IChannel channel);
+ }
+}
diff --git a/dotnet/Qpid.Integration.Tests/interop/TestCases/TestCase1DummyRun.cs b/dotnet/Qpid.Integration.Tests/interop/TestCases/TestCase1DummyRun.cs
index c3c159ca6c..d908b7af0b 100644
--- a/dotnet/Qpid.Integration.Tests/interop/TestCases/TestCase1DummyRun.cs
+++ b/dotnet/Qpid.Integration.Tests/interop/TestCases/TestCase1DummyRun.cs
@@ -1,69 +1,89 @@
-using System;
-using System.Text;
-using log4net;
-using Apache.Qpid.Messaging;
-
-namespace Apache.Qpid.Integration.Tests.interop.TestCases
-{
- /// <summary>
- /// Implements tet case 1, dummy run. This test case sends no test messages, it exists to confirm that the test harness
- /// is interacting with the coordinator correctly.
- ///
- /// <p><table id="crc"><caption>CRC Card</caption>
- /// <tr><th> Responsibilities <th> Collaborations
- /// <tr><td> Supply the name of the test case that this implements.
- /// <tr><td> Accept/Reject invites based on test parameters.
- /// <tr><td> Adapt to assigned roles.
- /// <tr><td> Perform test case actions.
- /// <tr><td> Generate test reports.
- /// </table>
- /// </summary>
- public class TestCase1DummyRun : InteropClientTestCase
- {
- private static ILog log = LogManager.GetLogger(typeof(TestCase1DummyRun));
-
- public String GetName()
- {
- log.Debug("public String getName(): called");
-
- return "TC1_DummyRun";
- }
-
- public bool AcceptInvite(IMessage inviteMessage)
- {
- log.Debug("public boolean acceptInvite(Message inviteMessage): called");
-
- // Test parameters don't matter, accept all invites.
- return true;
- }
-
- public void AssignRole(Roles role, IMessage assignRoleMessage)
- {
- log.Debug("public void assignRole(Roles role, Message assignRoleMessage): called");
-
- // Do nothing, both roles are the same.
- }
-
- public void Start()
- {
- log.Debug("public void start(): called");
-
- // Do nothing.
- }
-
- public IMessage GetReport(IChannel channel)
- {
- log.Debug("public Message getReport(Session session): called");
-
- // Generate a dummy report, the coordinator expects a report but doesn't care what it is.
- return channel.CreateTextMessage("Dummy Run, Ok.");
- }
-
- public void OnMessage(IMessage message)
- {
- log.Debug("public void onMessage(Message message = " + message + "): called");
-
- // Ignore any messages.
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Text;
+using log4net;
+using Apache.Qpid.Messaging;
+
+namespace Apache.Qpid.Integration.Tests.interop.TestCases
+{
+ /// <summary>
+ /// Implements tet case 1, dummy run. This test case sends no test messages, it exists to confirm that the test harness
+ /// is interacting with the coordinator correctly.
+ ///
+ /// <p><table id="crc"><caption>CRC Card</caption>
+ /// <tr><th> Responsibilities <th> Collaborations
+ /// <tr><td> Supply the name of the test case that this implements.
+ /// <tr><td> Accept/Reject invites based on test parameters.
+ /// <tr><td> Adapt to assigned roles.
+ /// <tr><td> Perform test case actions.
+ /// <tr><td> Generate test reports.
+ /// </table>
+ /// </summary>
+ public class TestCase1DummyRun : InteropClientTestCase
+ {
+ private static ILog log = LogManager.GetLogger(typeof(TestCase1DummyRun));
+
+ public String GetName()
+ {
+ log.Debug("public String getName(): called");
+
+ return "TC1_DummyRun";
+ }
+
+ public bool AcceptInvite(IMessage inviteMessage)
+ {
+ log.Debug("public boolean acceptInvite(Message inviteMessage): called");
+
+ // Test parameters don't matter, accept all invites.
+ return true;
+ }
+
+ public void AssignRole(Roles role, IMessage assignRoleMessage)
+ {
+ log.Debug("public void assignRole(Roles role, Message assignRoleMessage): called");
+
+ // Do nothing, both roles are the same.
+ }
+
+ public void Start()
+ {
+ log.Debug("public void start(): called");
+
+ // Do nothing.
+ }
+
+ public IMessage GetReport(IChannel channel)
+ {
+ log.Debug("public Message getReport(Session session): called");
+
+ // Generate a dummy report, the coordinator expects a report but doesn't care what it is.
+ return channel.CreateTextMessage("Dummy Run, Ok.");
+ }
+
+ public void OnMessage(IMessage message)
+ {
+ log.Debug("public void onMessage(Message message = " + message + "): called");
+
+ // Ignore any messages.
+ }
+ }
+}
diff --git a/dotnet/Qpid.Integration.Tests/interop/TestCases/TestCase2BasicP2P.cs b/dotnet/Qpid.Integration.Tests/interop/TestCases/TestCase2BasicP2P.cs
index f4f0c7dbd3..8993da832e 100644
--- a/dotnet/Qpid.Integration.Tests/interop/TestCases/TestCase2BasicP2P.cs
+++ b/dotnet/Qpid.Integration.Tests/interop/TestCases/TestCase2BasicP2P.cs
@@ -1,185 +1,205 @@
-using System;
-using System.Text;
-using log4net;
-using Apache.Qpid.Messaging;
-
-namespace Apache.Qpid.Integration.Tests.interop.TestCases
-{
- /// <summary>
- /// Implements test case 2, basic P2P. Sends/receives a specified number of messages to a specified route on the
- /// default direct exchange. Produces reports on the actual number of messages sent/received.
- ///
- /// <p><table id="crc"><caption>CRC Card</caption>
- /// <tr><th> Responsibilities <th> Collaborations
- /// <tr><td> Supply the name of the test case that this implements.
- /// <tr><td> Accept/Reject invites based on test parameters.
- /// <tr><td> Adapt to assigned roles.
- /// <tr><td> Send required number of test messages.
- /// <tr><td> Generate test reports.
- /// </table>
- /// </summary>
- public class TestCase2BasicP2P : InteropClientTestCase
- {
- /// <summary> Used for debugging. </summary>
- private static ILog log = LogManager.GetLogger(typeof(TestCase2BasicP2P));
-
- /// <summary> Holds the count of test messages received. </summary>
- private int messageCount;
-
- /// <summary> The role to be played by the test. </summary>
- private Roles role;
-
- /// <summary> The number of test messages to send. </summary>
- private int numMessages;
-
- /// <summary> The routing key to send them to on the default direct exchange. </summary>
- private string sendDestination;
-
- /// <summary> The connection to send the test messages on. </summary>
- private IConnection connection;
-
- /// <summary> The session to send the test messages on. </summary>
- private IChannel channel;
-
- /// <summary> The producer to send the test messages with. </summary>
- private IMessagePublisher publisher;
-
- /// <summary>
- /// Should provide the name of the test case that this class implements. The exact names are defined in the
- /// interop testing spec.
- /// </summary>
- ///
- /// <returns> The name of the test case that this implements. </returns>
- public String GetName()
- {
- log.Debug("public String GetName(): called");
-
- return "TC2_BasicP2P";
- }
-
- /// <summary>
- /// Determines whether the test invite that matched this test case is acceptable.
- /// </summary>
- ///
- /// <param name="inviteMessage"> The invitation to accept or reject. </param>
- ///
- /// <returns> <tt>true</tt> to accept the invitation, <tt>false</tt> to reject it. </returns>
- public bool AcceptInvite(IMessage inviteMessage)
- {
- log.Debug("public boolean AcceptInvite(Message inviteMessage = " + inviteMessage + "): called");
-
- // All invites are acceptable.
- return true;
- }
-
- /// <summary>
- /// Assigns the role to be played by this test case. The test parameters are fully specified in the
- /// assignment message. When this method return the test case will be ready to execute.
- /// </summary>
- ///
- /// <param name="role"> The role to be played; sender or receiver. </param>
- /// <param name="assignRoleMessage"> The role assingment message, contains the full test parameters. </param>
- public void AssignRole(Roles role, IMessage assignRoleMessage)
- {
- log.Debug("public void AssignRole(Roles role = " + role + ", Message assignRoleMessage = " + assignRoleMessage
- + "): called");
-
- // Reset the message count for a new test.
- messageCount = 0;
-
- // Take note of the role to be played.
- this.role = role;
-
- // Create a new connection to pass the test messages on.
- connection =
- TestClient.CreateConnection(TestClient.brokerUrl, TestClient.virtualHost);
- channel = connection.CreateChannel(false, AcknowledgeMode.AutoAcknowledge);
-
- // Extract and retain the test parameters.
- numMessages = assignRoleMessage.Headers.GetInt("P2P_NUM_MESSAGES");
- string queueAndKeyName = assignRoleMessage.Headers.GetString("P2P_QUEUE_AND_KEY_NAME");
- channel.DeclareQueue(queueAndKeyName, false, true, true);
- channel.Bind(queueAndKeyName, ExchangeNameDefaults.DIRECT, queueAndKeyName);
- sendDestination = queueAndKeyName;
-
- log.Debug("numMessages = " + numMessages);
- log.Debug("sendDestination = " + sendDestination);
- log.Debug("role = " + role);
-
- switch (role)
- {
- // Check if the sender role is being assigned, and set up a message producer if so.
- case Roles.SENDER:
- publisher = channel.CreatePublisherBuilder()
- .WithExchangeName(ExchangeNameDefaults.DIRECT)
- .WithRoutingKey(sendDestination)
- .Create();
- break;
-
- // Otherwise the receiver role is being assigned, so set this up to listen for messages.
- case Roles.RECEIVER:
- IMessageConsumer consumer = channel.CreateConsumerBuilder(sendDestination).Create();
- consumer.OnMessage += new MessageReceivedDelegate(OnMessage);
-
- break;
- }
-
- connection.Start();
- }
-
- /// <summary> Performs the test case actions. </summary>
- public void Start()
- {
- log.Debug("public void start(): called");
-
- // Check that the sender role is being performed.
- if (role == Roles.SENDER)
- {
- IMessage testMessage = channel.CreateTextMessage("test");
-
- for (int i = 0; i < numMessages; i++)
- {
- publisher.Send(testMessage);
-
- // Increment the message count.
- messageCount++;
- }
- }
- }
-
- /// <summary>
- /// Gets a report on the actions performed by the test case in its assigned role.
- /// </summary>
- ///
- /// <param name="session"> The session to create the report message in. </param>
- ///
- /// <returns> The report message. </returns>
- public IMessage GetReport(IChannel channel)
- {
- log.Debug("public Message GetReport(IChannel channel): called");
-
- // Close the test connection.
- //connection.Stop();
-
- // Generate a report message containing the count of the number of messages passed.
- IMessage report = channel.CreateMessage();
- //report.Headers.SetString("CONTROL_TYPE", "REPORT");
- report.Headers.SetInt("MESSAGE_COUNT", messageCount);
-
- return report;
- }
-
- /// <summary>
- /// Counts incoming test messages.
- /// </summary>
- ///
- /// <param name="message"> The incoming test message. </param>
- public void OnMessage(IMessage message)
- {
- log.Debug("public void OnMessage(IMessage message = " + message + "): called");
-
- // Increment the message count.
- messageCount++;
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Text;
+using log4net;
+using Apache.Qpid.Messaging;
+
+namespace Apache.Qpid.Integration.Tests.interop.TestCases
+{
+ /// <summary>
+ /// Implements test case 2, basic P2P. Sends/receives a specified number of messages to a specified route on the
+ /// default direct exchange. Produces reports on the actual number of messages sent/received.
+ ///
+ /// <p><table id="crc"><caption>CRC Card</caption>
+ /// <tr><th> Responsibilities <th> Collaborations
+ /// <tr><td> Supply the name of the test case that this implements.
+ /// <tr><td> Accept/Reject invites based on test parameters.
+ /// <tr><td> Adapt to assigned roles.
+ /// <tr><td> Send required number of test messages.
+ /// <tr><td> Generate test reports.
+ /// </table>
+ /// </summary>
+ public class TestCase2BasicP2P : InteropClientTestCase
+ {
+ /// <summary> Used for debugging. </summary>
+ private static ILog log = LogManager.GetLogger(typeof(TestCase2BasicP2P));
+
+ /// <summary> Holds the count of test messages received. </summary>
+ private int messageCount;
+
+ /// <summary> The role to be played by the test. </summary>
+ private Roles role;
+
+ /// <summary> The number of test messages to send. </summary>
+ private int numMessages;
+
+ /// <summary> The routing key to send them to on the default direct exchange. </summary>
+ private string sendDestination;
+
+ /// <summary> The connection to send the test messages on. </summary>
+ private IConnection connection;
+
+ /// <summary> The session to send the test messages on. </summary>
+ private IChannel channel;
+
+ /// <summary> The producer to send the test messages with. </summary>
+ private IMessagePublisher publisher;
+
+ /// <summary>
+ /// Should provide the name of the test case that this class implements. The exact names are defined in the
+ /// interop testing spec.
+ /// </summary>
+ ///
+ /// <returns> The name of the test case that this implements. </returns>
+ public String GetName()
+ {
+ log.Debug("public String GetName(): called");
+
+ return "TC2_BasicP2P";
+ }
+
+ /// <summary>
+ /// Determines whether the test invite that matched this test case is acceptable.
+ /// </summary>
+ ///
+ /// <param name="inviteMessage"> The invitation to accept or reject. </param>
+ ///
+ /// <returns> <tt>true</tt> to accept the invitation, <tt>false</tt> to reject it. </returns>
+ public bool AcceptInvite(IMessage inviteMessage)
+ {
+ log.Debug("public boolean AcceptInvite(Message inviteMessage = " + inviteMessage + "): called");
+
+ // All invites are acceptable.
+ return true;
+ }
+
+ /// <summary>
+ /// Assigns the role to be played by this test case. The test parameters are fully specified in the
+ /// assignment message. When this method return the test case will be ready to execute.
+ /// </summary>
+ ///
+ /// <param name="role"> The role to be played; sender or receiver. </param>
+ /// <param name="assignRoleMessage"> The role assingment message, contains the full test parameters. </param>
+ public void AssignRole(Roles role, IMessage assignRoleMessage)
+ {
+ log.Debug("public void AssignRole(Roles role = " + role + ", Message assignRoleMessage = " + assignRoleMessage
+ + "): called");
+
+ // Reset the message count for a new test.
+ messageCount = 0;
+
+ // Take note of the role to be played.
+ this.role = role;
+
+ // Create a new connection to pass the test messages on.
+ connection =
+ TestClient.CreateConnection(TestClient.brokerUrl, TestClient.virtualHost);
+ channel = connection.CreateChannel(false, AcknowledgeMode.AutoAcknowledge);
+
+ // Extract and retain the test parameters.
+ numMessages = assignRoleMessage.Headers.GetInt("P2P_NUM_MESSAGES");
+ string queueAndKeyName = assignRoleMessage.Headers.GetString("P2P_QUEUE_AND_KEY_NAME");
+ channel.DeclareQueue(queueAndKeyName, false, true, true);
+ channel.Bind(queueAndKeyName, ExchangeNameDefaults.DIRECT, queueAndKeyName);
+ sendDestination = queueAndKeyName;
+
+ log.Debug("numMessages = " + numMessages);
+ log.Debug("sendDestination = " + sendDestination);
+ log.Debug("role = " + role);
+
+ switch (role)
+ {
+ // Check if the sender role is being assigned, and set up a message producer if so.
+ case Roles.SENDER:
+ publisher = channel.CreatePublisherBuilder()
+ .WithExchangeName(ExchangeNameDefaults.DIRECT)
+ .WithRoutingKey(sendDestination)
+ .Create();
+ break;
+
+ // Otherwise the receiver role is being assigned, so set this up to listen for messages.
+ case Roles.RECEIVER:
+ IMessageConsumer consumer = channel.CreateConsumerBuilder(sendDestination).Create();
+ consumer.OnMessage += new MessageReceivedDelegate(OnMessage);
+
+ break;
+ }
+
+ connection.Start();
+ }
+
+ /// <summary> Performs the test case actions. </summary>
+ public void Start()
+ {
+ log.Debug("public void start(): called");
+
+ // Check that the sender role is being performed.
+ if (role == Roles.SENDER)
+ {
+ IMessage testMessage = channel.CreateTextMessage("test");
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ publisher.Send(testMessage);
+
+ // Increment the message count.
+ messageCount++;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets a report on the actions performed by the test case in its assigned role.
+ /// </summary>
+ ///
+ /// <param name="session"> The session to create the report message in. </param>
+ ///
+ /// <returns> The report message. </returns>
+ public IMessage GetReport(IChannel channel)
+ {
+ log.Debug("public Message GetReport(IChannel channel): called");
+
+ // Close the test connection.
+ //connection.Stop();
+
+ // Generate a report message containing the count of the number of messages passed.
+ IMessage report = channel.CreateMessage();
+ //report.Headers.SetString("CONTROL_TYPE", "REPORT");
+ report.Headers.SetInt("MESSAGE_COUNT", messageCount);
+
+ return report;
+ }
+
+ /// <summary>
+ /// Counts incoming test messages.
+ /// </summary>
+ ///
+ /// <param name="message"> The incoming test message. </param>
+ public void OnMessage(IMessage message)
+ {
+ log.Debug("public void OnMessage(IMessage message = " + message + "): called");
+
+ // Increment the message count.
+ messageCount++;
+ }
+ }
+}
diff --git a/dotnet/Qpid.Integration.Tests/interop/TestCases/TestCase3BasicPubSub.cs b/dotnet/Qpid.Integration.Tests/interop/TestCases/TestCase3BasicPubSub.cs
index a9f073ce04..79c0322bcd 100644
--- a/dotnet/Qpid.Integration.Tests/interop/TestCases/TestCase3BasicPubSub.cs
+++ b/dotnet/Qpid.Integration.Tests/interop/TestCases/TestCase3BasicPubSub.cs
@@ -1,224 +1,244 @@
-using System;
-using System.Text;
-using log4net;
-using Apache.Qpid.Messaging;
-
-namespace Apache.Qpid.Integration.Tests.interop.TestCases
-{
- /// <summary>
- /// Implements test case 3, basic pub/sub. Sends/received a specified number of messages to a specified route on the
- /// default topic exchange, using the specified number of receiver connections. Produces reports on the actual number of
- /// messages sent/received.
- ///
- /// <p><table id="crc"><caption>CRC Card</caption>
- /// <tr><th> Responsibilities <th> Collaborations
- /// <tr><td> Supply the name of the test case that this implements.
- /// <tr><td> Accept/Reject invites based on test parameters.
- /// <tr><td> Adapt to assigned roles.
- /// <tr><td> Send required number of test messages using pub/sub.
- /// <tr><td> Generate test reports.
- /// </table>
- /// </summary>
- public class TestCase3BasicPubSub : InteropClientTestCase
- {
- /// <summary> Used for debugging. </summary>
- private static ILog log = LogManager.GetLogger(typeof(TestCase3BasicPubSub));
-
- /// <summary> Holds the count of test messages received. </summary>
- private int messageCount;
-
- /// <summary> The role to be played by the test. </summary>
- private Roles role;
-
- /// <summary> The number of test messages to send. </summary>
- private int numMessages;
-
- /// <summary> The number of receiver connection to use. </summary>
- private int numReceivers;
-
- /// <summary> The routing key to send them to on the default direct exchange. </summary>
- private string sendDestination;
-
- /// <summary> The connections to send/receive the test messages on. </summary>
- private IConnection[] connection;
-
- /// <summary> The sessions to send/receive the test messages on. </summary>
- private IChannel[] channel;
-
- /// <summary> The producer to send the test messages with. </summary>
- IMessagePublisher publisher;
-
- /// <summary>
- /// Should provide the name of the test case that this class implements. The exact names are defined in the
- /// interop testing spec.
- /// </summary>
- ///
- /// <returns> The name of the test case that this implements. </returns>
- public String GetName()
- {
- log.Debug("public String GetName(): called");
-
- return "TC3_BasicPubSub";
- }
-
- /// <summary>
- /// Determines whether the test invite that matched this test case is acceptable.
- /// </summary>
- ///
- /// <param name="inviteMessage"> The invitation to accept or reject. </param>
- ///
- /// <returns> <tt>true</tt> to accept the invitation, <tt>false</tt> to reject it. </returns>
- public bool AcceptInvite(IMessage inviteMessage)
- {
- log.Debug("public boolean AcceptInvite(IMessage inviteMessage = " + inviteMessage + "): called");
-
- // All invites are acceptable.
- return true;
- }
-
- /// <summary>
- /// Assigns the role to be played by this test case. The test parameters are fully specified in the
- /// assignment message. When this method return the test case will be ready to execute.
- /// </summary>
- ///
- /// <param name="role"> The role to be played; sender or receiver. </param>
- /// <param name="assignRoleMessage"> The role assingment message, contains the full test parameters. </param>
- public void AssignRole(Roles role, IMessage assignRoleMessage)
- {
- log.Debug("public void assignRole(Roles role = " + role + ", IMessage assignRoleMessage = " + assignRoleMessage
- + "): called");
-
- // Reset the message count for a new test.
- messageCount = 0;
-
- // Take note of the role to be played.
- this.role = role;
-
- // Extract and retain the test parameters.
- numMessages = assignRoleMessage.Headers.GetInt("PUBSUB_NUM_MESSAGES");
- numReceivers = assignRoleMessage.Headers.GetInt("PUBSUB_NUM_RECEIVERS");
- string sendKey = assignRoleMessage.Headers.GetString("PUBSUB_KEY");
- sendDestination = sendKey;
-
- log.Debug("numMessages = " + numMessages);
- log.Debug("numReceivers = " + numReceivers);
- log.Debug("sendKey = " + sendKey);
- log.Debug("role = " + role);
-
- switch (role)
- {
- // Check if the sender role is being assigned, and set up a single message producer if so.
- case Roles.SENDER:
- // Create a new connection to pass the test messages on.
- connection = new IConnection[1];
- channel = new IChannel[1];
-
- connection[0] =
- TestClient.CreateConnection(TestClient.brokerUrl, TestClient.virtualHost);
- channel[0] = connection[0].CreateChannel(false, AcknowledgeMode.AutoAcknowledge);
-
- // Extract and retain the test parameters.
- publisher = channel[0].CreatePublisherBuilder()
- .WithExchangeName(ExchangeNameDefaults.TOPIC)
- .WithRoutingKey(sendDestination)
- .WithMandatory(false)
- .WithImmediate(false)
- .Create();
- break;
-
- // Otherwise the receiver role is being assigned, so set this up to listen for messages on the required number
- // of receiver connections.
- case Roles.RECEIVER:
- // Create the required number of receiver connections.
- connection = new IConnection[numReceivers];
- channel = new IChannel[numReceivers];
-
- for (int i = 0; i < numReceivers; i++)
- {
- connection[i] =
- TestClient.CreateConnection(TestClient.brokerUrl, TestClient.virtualHost);
- channel[i] = connection[i].CreateChannel(false, AcknowledgeMode.AutoAcknowledge);
-
- IMessageConsumer consumer = channel[i].CreateConsumerBuilder(sendDestination).Create();
- consumer.OnMessage += new MessageReceivedDelegate(OnMessage);
- }
-
- break;
- }
-
- // Start all the connection dispatcher threads running.
- foreach (IConnection con in connection)
- {
- con.Start();
- }
- }
-
- /// <summary>
- /// Performs the test case actions.
- /// </summary>
- public void Start()
- {
- log.Debug("public void Start(): called");
-
- // Check that the sender role is being performed.
- if (role == Roles.SENDER)
- {
- IMessage testMessage = channel[0].CreateTextMessage("test");
-
- for (int i = 0; i < numMessages; i++)
- {
- publisher.Send(testMessage);
-
- // Increment the message count.
- messageCount++;
- }
- }
- }
-
- /// <summary>
- /// Gets a report on the actions performed by the test case in its assigned role.
- /// </summary>
- ///
- /// <param name="session"> The session to create the report message in. </param>
- ///
- /// <returns> The report message. </returns>
- public IMessage GetReport(IChannel channel)
- {
- log.Debug("public IMessage getReport(IChannel channel): called");
-
- // Close the test connections.
- /*foreach (IConnection con in connection)
- {
- try
- {
- con.Stop();
- }
- catch (AMQConnectionClosedException e)
- {
- // The connection has already died due to an error. Log this as a warning.
- log.Warn("Connection already closed.");
- }
- }*/
-
- // Generate a report message containing the count of the number of messages passed.
- IMessage report = channel.CreateMessage();
- //report.Headers.SetString("CONTROL_TYPE", "REPORT");
- report.Headers.SetInt("MESSAGE_COUNT", messageCount);
-
- return report;
- }
-
- /// <summary>
- /// Counts incoming test messages.
- /// </summary>
- ///
- /// <param name="message"> The incoming test message. </param>
- public void OnMessage(IMessage message)
- {
- log.Debug("public void onMessage(IMessage message = " + message + "): called");
-
- // Increment the message count.
- messageCount++;
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Text;
+using log4net;
+using Apache.Qpid.Messaging;
+
+namespace Apache.Qpid.Integration.Tests.interop.TestCases
+{
+ /// <summary>
+ /// Implements test case 3, basic pub/sub. Sends/received a specified number of messages to a specified route on the
+ /// default topic exchange, using the specified number of receiver connections. Produces reports on the actual number of
+ /// messages sent/received.
+ ///
+ /// <p><table id="crc"><caption>CRC Card</caption>
+ /// <tr><th> Responsibilities <th> Collaborations
+ /// <tr><td> Supply the name of the test case that this implements.
+ /// <tr><td> Accept/Reject invites based on test parameters.
+ /// <tr><td> Adapt to assigned roles.
+ /// <tr><td> Send required number of test messages using pub/sub.
+ /// <tr><td> Generate test reports.
+ /// </table>
+ /// </summary>
+ public class TestCase3BasicPubSub : InteropClientTestCase
+ {
+ /// <summary> Used for debugging. </summary>
+ private static ILog log = LogManager.GetLogger(typeof(TestCase3BasicPubSub));
+
+ /// <summary> Holds the count of test messages received. </summary>
+ private int messageCount;
+
+ /// <summary> The role to be played by the test. </summary>
+ private Roles role;
+
+ /// <summary> The number of test messages to send. </summary>
+ private int numMessages;
+
+ /// <summary> The number of receiver connection to use. </summary>
+ private int numReceivers;
+
+ /// <summary> The routing key to send them to on the default direct exchange. </summary>
+ private string sendDestination;
+
+ /// <summary> The connections to send/receive the test messages on. </summary>
+ private IConnection[] connection;
+
+ /// <summary> The sessions to send/receive the test messages on. </summary>
+ private IChannel[] channel;
+
+ /// <summary> The producer to send the test messages with. </summary>
+ IMessagePublisher publisher;
+
+ /// <summary>
+ /// Should provide the name of the test case that this class implements. The exact names are defined in the
+ /// interop testing spec.
+ /// </summary>
+ ///
+ /// <returns> The name of the test case that this implements. </returns>
+ public String GetName()
+ {
+ log.Debug("public String GetName(): called");
+
+ return "TC3_BasicPubSub";
+ }
+
+ /// <summary>
+ /// Determines whether the test invite that matched this test case is acceptable.
+ /// </summary>
+ ///
+ /// <param name="inviteMessage"> The invitation to accept or reject. </param>
+ ///
+ /// <returns> <tt>true</tt> to accept the invitation, <tt>false</tt> to reject it. </returns>
+ public bool AcceptInvite(IMessage inviteMessage)
+ {
+ log.Debug("public boolean AcceptInvite(IMessage inviteMessage = " + inviteMessage + "): called");
+
+ // All invites are acceptable.
+ return true;
+ }
+
+ /// <summary>
+ /// Assigns the role to be played by this test case. The test parameters are fully specified in the
+ /// assignment message. When this method return the test case will be ready to execute.
+ /// </summary>
+ ///
+ /// <param name="role"> The role to be played; sender or receiver. </param>
+ /// <param name="assignRoleMessage"> The role assingment message, contains the full test parameters. </param>
+ public void AssignRole(Roles role, IMessage assignRoleMessage)
+ {
+ log.Debug("public void assignRole(Roles role = " + role + ", IMessage assignRoleMessage = " + assignRoleMessage
+ + "): called");
+
+ // Reset the message count for a new test.
+ messageCount = 0;
+
+ // Take note of the role to be played.
+ this.role = role;
+
+ // Extract and retain the test parameters.
+ numMessages = assignRoleMessage.Headers.GetInt("PUBSUB_NUM_MESSAGES");
+ numReceivers = assignRoleMessage.Headers.GetInt("PUBSUB_NUM_RECEIVERS");
+ string sendKey = assignRoleMessage.Headers.GetString("PUBSUB_KEY");
+ sendDestination = sendKey;
+
+ log.Debug("numMessages = " + numMessages);
+ log.Debug("numReceivers = " + numReceivers);
+ log.Debug("sendKey = " + sendKey);
+ log.Debug("role = " + role);
+
+ switch (role)
+ {
+ // Check if the sender role is being assigned, and set up a single message producer if so.
+ case Roles.SENDER:
+ // Create a new connection to pass the test messages on.
+ connection = new IConnection[1];
+ channel = new IChannel[1];
+
+ connection[0] =
+ TestClient.CreateConnection(TestClient.brokerUrl, TestClient.virtualHost);
+ channel[0] = connection[0].CreateChannel(false, AcknowledgeMode.AutoAcknowledge);
+
+ // Extract and retain the test parameters.
+ publisher = channel[0].CreatePublisherBuilder()
+ .WithExchangeName(ExchangeNameDefaults.TOPIC)
+ .WithRoutingKey(sendDestination)
+ .WithMandatory(false)
+ .WithImmediate(false)
+ .Create();
+ break;
+
+ // Otherwise the receiver role is being assigned, so set this up to listen for messages on the required number
+ // of receiver connections.
+ case Roles.RECEIVER:
+ // Create the required number of receiver connections.
+ connection = new IConnection[numReceivers];
+ channel = new IChannel[numReceivers];
+
+ for (int i = 0; i < numReceivers; i++)
+ {
+ connection[i] =
+ TestClient.CreateConnection(TestClient.brokerUrl, TestClient.virtualHost);
+ channel[i] = connection[i].CreateChannel(false, AcknowledgeMode.AutoAcknowledge);
+
+ IMessageConsumer consumer = channel[i].CreateConsumerBuilder(sendDestination).Create();
+ consumer.OnMessage += new MessageReceivedDelegate(OnMessage);
+ }
+
+ break;
+ }
+
+ // Start all the connection dispatcher threads running.
+ foreach (IConnection con in connection)
+ {
+ con.Start();
+ }
+ }
+
+ /// <summary>
+ /// Performs the test case actions.
+ /// </summary>
+ public void Start()
+ {
+ log.Debug("public void Start(): called");
+
+ // Check that the sender role is being performed.
+ if (role == Roles.SENDER)
+ {
+ IMessage testMessage = channel[0].CreateTextMessage("test");
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ publisher.Send(testMessage);
+
+ // Increment the message count.
+ messageCount++;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets a report on the actions performed by the test case in its assigned role.
+ /// </summary>
+ ///
+ /// <param name="session"> The session to create the report message in. </param>
+ ///
+ /// <returns> The report message. </returns>
+ public IMessage GetReport(IChannel channel)
+ {
+ log.Debug("public IMessage getReport(IChannel channel): called");
+
+ // Close the test connections.
+ /*foreach (IConnection con in connection)
+ {
+ try
+ {
+ con.Stop();
+ }
+ catch (AMQConnectionClosedException e)
+ {
+ // The connection has already died due to an error. Log this as a warning.
+ log.Warn("Connection already closed.");
+ }
+ }*/
+
+ // Generate a report message containing the count of the number of messages passed.
+ IMessage report = channel.CreateMessage();
+ //report.Headers.SetString("CONTROL_TYPE", "REPORT");
+ report.Headers.SetInt("MESSAGE_COUNT", messageCount);
+
+ return report;
+ }
+
+ /// <summary>
+ /// Counts incoming test messages.
+ /// </summary>
+ ///
+ /// <param name="message"> The incoming test message. </param>
+ public void OnMessage(IMessage message)
+ {
+ log.Debug("public void onMessage(IMessage message = " + message + "): called");
+
+ // Increment the message count.
+ messageCount++;
+ }
+ }
+}
diff --git a/dotnet/Qpid.Integration.Tests/interop/TestClient.cs b/dotnet/Qpid.Integration.Tests/interop/TestClient.cs
index a0fdc1c59f..e2fac9e1a4 100644
--- a/dotnet/Qpid.Integration.Tests/interop/TestClient.cs
+++ b/dotnet/Qpid.Integration.Tests/interop/TestClient.cs
@@ -1,359 +1,379 @@
-using System;
-using System.Collections;
-using System.Text;
-using System.Threading;
-using Apache.Qpid.Messaging;
-using Apache.Qpid.Client.Qms;
-using Apache.Qpid.Client;
-using log4net;
-using Apache.Qpid.Integration.Tests.interop.TestCases;
-
-namespace Apache.Qpid.Integration.Tests.interop
-{
- /// <summary>
- /// Implements a test client as described in the interop testing spec
- /// (http://cwiki.apache.org/confluence/display/qpid/Interop+Testing+Specification). A test client is an agent that
- /// reacts to control message sequences send by the test coordinator.
- ///
- /// <p/><table><caption>Messages Handled by TestClient</caption>
- /// <tr><th> Message <th> Action
- /// <tr><td> Invite(compulsory) <td> Reply with Enlist.
- /// <tr><td> Invite(test case) <td> Reply with Enlist if test case available.
- /// <tr><td> AssignRole(test case) <td> Reply with Accept Role if matches an enlisted test. Keep test parameters.
- /// <tr><td> Start <td> Send test messages defined by test parameters. Send report on messages sent.
- /// <tr><td> Status Request <td> Send report on messages received.
- /// </table>
- ///
- /// <p><table id="crc"><caption>CRC Card</caption>
- /// <tr><th> Responsibilities <th> Collaborations
- /// <tr><td> Handle all incoming control messages. <td> {@link InteropClientTestCase}
- /// <tr><td> Configure and look up test cases by name. <td> {@link InteropClientTestCase}
- /// </table>
- /// </summary>
- public class TestClient
- {
- private static ILog log = LogManager.GetLogger(typeof(TestClient));
-
- /// <summary> Defines the default broker for the tests, localhost, default port. </summary>
- public static string DEFAULT_BROKER_URL = "amqp://guest:guest@clientid/?brokerlist='tcp://localhost:5672'";
-
- /// <summary> Defines the default virtual host to use for the tests, none. </summary>
- public static string DEFAULT_VIRTUAL_HOST = "";
-
- /// <summary> Defines the default identifying name of this test client. </summary>
- public static string DEFAULT_CLIENT_NAME = "dotnet";
-
- /// <summary> Holds the URL of the broker to run the tests on. </summary>
- public static string brokerUrl;
-
- /// <summary> Holds the virtual host to run the tests on. If <tt>null</tt>, then the default virtual host is used. </summary>
- public static string virtualHost;
-
- /// <summary> The clients identifying name to print in test results and to distinguish from other clients. </summary>
- private string clientName;
-
- /// <summary> Holds all the test cases. </summary>
- private IDictionary testCases = new Hashtable();
-
- InteropClientTestCase currentTestCase;
-
- private MessagePublisherBuilder publisherBuilder;
-
- private IChannel channel;
-
- /// <summary> Monitor to wait for termination events on. </summary>
- private static object terminationMonitor = new Object();
-
- /// <summary>
- /// Creates a new interop test client, listenting to the specified broker and virtual host, with the specified
- /// client identifying name.
- /// </summary>
- ///
- /// <param name="brokerUrl"> The url of the broker to connect to. </param>
- /// <param name="virtualHost"> The virtual host to conect to. </param>
- /// <param name="clientName"> The client name to use. </param>
- public TestClient(string brokerUrl, string virtualHost, string clientName)
- {
- log.Info("public TestClient(string brokerUrl = " + brokerUrl + ", string virtualHost = " + virtualHost
- + ", string clientName = " + clientName + "): called");
-
- // Retain the connection parameters.
- TestClient.brokerUrl = brokerUrl;
- TestClient.virtualHost = virtualHost;
- this.clientName = clientName;
- }
-
-
- /// <summary>
- /// The entry point for the interop test coordinator. This client accepts the following command line arguments:
- /// </summary>
- ///
- /// <p/><table>
- /// <tr><td> -b <td> The broker URL. <td> Optional.
- /// <tr><td> -h <td> The virtual host. <td> Optional.
- /// <tr><td> -n <td> The test client name. <td> Optional.
- /// <tr><td> name=value <td> Trailing argument define name/value pairs. Added to system properties. <td> Optional.
- /// </table>
- ///
- /// <param name="args"> The command line arguments. </param>
- public static void Main(string[] args)
- {
- // Extract the command line options (Not exactly Posix but it will do for now...).
- string brokerUrl = DEFAULT_BROKER_URL;
- string virtualHost = DEFAULT_VIRTUAL_HOST;
- string clientName = DEFAULT_CLIENT_NAME;
-
- foreach (string nextArg in args)
- {
- if (nextArg.StartsWith("-b"))
- {
- brokerUrl = nextArg.Substring(2);
- }
- else if (nextArg.StartsWith("-h"))
- {
- virtualHost = nextArg.Substring(2);
- }
- else if (nextArg.StartsWith("-n"))
- {
- clientName = nextArg.Substring(2);
- }
- }
-
- NDC.Push(clientName);
-
- // Create a test client and start it running.
- TestClient client = new TestClient(brokerUrl, virtualHost, clientName);
-
- try
- {
- client.Start();
- }
- catch (Exception e)
- {
- log.Error("The test client was unable to start.", e);
- System.Environment.Exit(1);
- }
-
- // Wait for a signal on the termination monitor before quitting.
- lock (terminationMonitor)
- {
- Monitor.Wait(terminationMonitor);
- }
-
- NDC.Pop();
- }
-
- /// <summary>
- /// Starts the interop test client running. This causes it to start listening for incoming test invites.
- /// </summary>
- private void Start()
- {
- log.Info("private void Start(): called");
-
- // Use a class path scanner to find all the interop test case implementations.
- ArrayList testCaseClasses = new ArrayList();
-
- // ClasspathScanner.getMatches(InteropClientTestCase.class, "^TestCase.*", true);
- // Hard code the test classes till the classpath scanner is fixed.
- testCaseClasses.Add(typeof(TestCase1DummyRun));
- testCaseClasses.Add(typeof(TestCase2BasicP2P));
- testCaseClasses.Add(typeof(TestCase3BasicPubSub));
-
- // Create all the test case implementations and index them by the test names.
- foreach (Type testClass in testCaseClasses)
- {
- InteropClientTestCase testCase = (InteropClientTestCase)Activator.CreateInstance(testClass);
- testCases.Add(testCase.GetName(), testCase);
-
- log.Info("Found test case: " + testClass);
- }
-
- // Open a connection to communicate with the coordinator on.
- log.Info("brokerUrl = " + brokerUrl);
- IConnection connection = CreateConnection(brokerUrl, virtualHost);
-
- channel = connection.CreateChannel(false, AcknowledgeMode.AutoAcknowledge);
-
- // Set this up to listen for control messages.
- string responseQueueName = channel.GenerateUniqueName();
- channel.DeclareQueue(responseQueueName, false, true, true);
-
- channel.Bind(responseQueueName, ExchangeNameDefaults.TOPIC, "iop.control." + clientName);
- channel.Bind(responseQueueName, ExchangeNameDefaults.TOPIC, "iop.control");
-
- IMessageConsumer consumer = channel.CreateConsumerBuilder(responseQueueName)
- .Create();
- consumer.OnMessage += new MessageReceivedDelegate(OnMessage);
-
- // Create a publisher to send replies with.
- publisherBuilder = channel.CreatePublisherBuilder()
- .WithExchangeName(ExchangeNameDefaults.DIRECT);
-
-
- // Start listening for incoming control messages.
- connection.Start();
- Console.WriteLine("Test client " + clientName + " ready to receive test control messages...");
- }
-
- /// <summary>
- /// Establishes an AMQ connection. This is a simple convenience method for code that does not anticipate handling connection failures.
- /// All exceptions that indicate that the connection has failed, are allowed to fall through.
- /// </summary>
- ///
- /// <param name="brokerUrl"> The broker url to connect to, <tt>null</tt> to use the default from the properties. </param>
- /// <param name="virtualHost"> The virtual host to connectio to, <tt>null</tt> to use the default. </param>
- ///
- /// <returns> A JMS conneciton. </returns>
- public static IConnection CreateConnection(string brokerUrl, string virtualHost)
- {
- log.Info("public static Connection createConnection(string brokerUrl = " + brokerUrl + ", string virtualHost = "
- + virtualHost + "): called");
-
- // Create a connection to the broker.
- IConnectionInfo connectionInfo = QpidConnectionInfo.FromUrl(brokerUrl);
- connectionInfo.VirtualHost = virtualHost;
- IConnection connection = new AMQConnection(connectionInfo);
-
- return connection;
- }
-
- /// <summary>
- /// Handles all incoming control messages.
- /// </summary>
- ///
- /// <param name="message"> The incoming message. </param>
- public void OnMessage(IMessage message)
- {
- log.Info("public void OnMessage(IMessage message = " + message + "): called");
-
- try
- {
- string controlType = message.Headers.GetString("CONTROL_TYPE");
- string testName = message.Headers.GetString("TEST_NAME");
-
- // Check if the message is a test invite.
- if ("INVITE" == controlType)
- {
- string testCaseName = message.Headers.GetString("TEST_NAME");
-
- // Flag used to indicate that an enlist should be sent. Only enlist to compulsory invites or invites
- // for which test cases exist.
- bool enlist = false;
-
- if (testCaseName != null)
- {
- log.Info("Got an invite to test: " + testCaseName);
-
- // Check if the requested test case is available.
- InteropClientTestCase testCase = (InteropClientTestCase)testCases[testCaseName];
-
- if (testCase != null)
- {
- // Make the requested test case the current test case.
- currentTestCase = testCase;
- enlist = true;
- }
- }
- else
- {
- log.Info("Got a compulsory invite.");
-
- enlist = true;
- }
-
- log.Info("enlist = " + enlist);
-
- if (enlist)
- {
- // Reply with the client name in an Enlist message.
- IMessage enlistMessage = channel.CreateMessage();
- enlistMessage.Headers.SetString("CONTROL_TYPE", "ENLIST");
- enlistMessage.Headers.SetString("CLIENT_NAME", clientName);
- enlistMessage.Headers.SetString("CLIENT_PRIVATE_CONTROL_KEY", "iop.control." + clientName);
- enlistMessage.CorrelationId = message.CorrelationId;
-
- Send(enlistMessage, message.ReplyToRoutingKey);
- }
- }
- else if ("ASSIGN_ROLE" == controlType)
- {
- // Assign the role to the current test case.
- string roleName = message.Headers.GetString("ROLE");
-
- log.Info("Got a role assignment to role: " + roleName);
-
- Roles role;
-
- if (roleName == "SENDER")
- {
- role = Roles.SENDER;
- }
- else
- {
- role = Roles.RECEIVER;
- }
-
- currentTestCase.AssignRole(role, message);
-
- // Reply by accepting the role in an Accept Role message.
- IMessage acceptRoleMessage = channel.CreateMessage();
- acceptRoleMessage.Headers.SetString("CONTROL_TYPE", "ACCEPT_ROLE");
- acceptRoleMessage.CorrelationId = message.CorrelationId;
-
- Send(acceptRoleMessage, message.ReplyToRoutingKey);
- }
- else if ("START" == controlType || "STATUS_REQUEST" == controlType)
- {
- if ("START" == controlType)
- {
- log.Info("Got a start notification.");
-
- // Start the current test case.
- currentTestCase.Start();
- }
- else
- {
- log.Info("Got a status request.");
- }
-
- // Generate the report from the test case and reply with it as a Report message.
- IMessage reportMessage = currentTestCase.GetReport(channel);
- reportMessage.Headers.SetString("CONTROL_TYPE", "REPORT");
- reportMessage.CorrelationId = message.CorrelationId;
-
- Send(reportMessage, message.ReplyToRoutingKey);
- }
- else if ("TERMINATE" == controlType)
- {
- Console.WriteLine("Received termination instruction from coordinator.");
-
- // Is a cleaner shutdown needed?
- System.Environment.Exit(1);
- }
- else
- {
- // Log a warning about this but otherwise ignore it.
- log.Warn("Got an unknown control message, controlType = " + controlType + ", message = " + message);
- }
- }
- catch (QpidException e)
- {
- // Log a warning about this, but otherwise ignore it.
- log.Warn("A QpidException occurred whilst handling a message.");
- log.Info("Got QpidException whilst handling message: " + message, e);
- }
- }
-
- /// <summary>
- /// Send the specified message using the specified routing key on the direct exchange.
- /// </summary>
- ///
- /// <param name="message"> The message to send.</param>
- /// <param name="routingKey"> The routing key to send the message with.</param>
- public void Send(IMessage message, string routingKey)
- {
- IMessagePublisher publisher = publisherBuilder.WithRoutingKey(routingKey).Create();
- publisher.Send(message);
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Collections;
+using System.Text;
+using System.Threading;
+using Apache.Qpid.Messaging;
+using Apache.Qpid.Client.Qms;
+using Apache.Qpid.Client;
+using log4net;
+using Apache.Qpid.Integration.Tests.interop.TestCases;
+
+namespace Apache.Qpid.Integration.Tests.interop
+{
+ /// <summary>
+ /// Implements a test client as described in the interop testing spec
+ /// (http://cwiki.apache.org/confluence/display/qpid/Interop+Testing+Specification). A test client is an agent that
+ /// reacts to control message sequences send by the test coordinator.
+ ///
+ /// <p/><table><caption>Messages Handled by TestClient</caption>
+ /// <tr><th> Message <th> Action
+ /// <tr><td> Invite(compulsory) <td> Reply with Enlist.
+ /// <tr><td> Invite(test case) <td> Reply with Enlist if test case available.
+ /// <tr><td> AssignRole(test case) <td> Reply with Accept Role if matches an enlisted test. Keep test parameters.
+ /// <tr><td> Start <td> Send test messages defined by test parameters. Send report on messages sent.
+ /// <tr><td> Status Request <td> Send report on messages received.
+ /// </table>
+ ///
+ /// <p><table id="crc"><caption>CRC Card</caption>
+ /// <tr><th> Responsibilities <th> Collaborations
+ /// <tr><td> Handle all incoming control messages. <td> {@link InteropClientTestCase}
+ /// <tr><td> Configure and look up test cases by name. <td> {@link InteropClientTestCase}
+ /// </table>
+ /// </summary>
+ public class TestClient
+ {
+ private static ILog log = LogManager.GetLogger(typeof(TestClient));
+
+ /// <summary> Defines the default broker for the tests, localhost, default port. </summary>
+ public static string DEFAULT_BROKER_URL = "amqp://guest:guest@clientid/?brokerlist='tcp://localhost:5672'";
+
+ /// <summary> Defines the default virtual host to use for the tests, none. </summary>
+ public static string DEFAULT_VIRTUAL_HOST = "";
+
+ /// <summary> Defines the default identifying name of this test client. </summary>
+ public static string DEFAULT_CLIENT_NAME = "dotnet";
+
+ /// <summary> Holds the URL of the broker to run the tests on. </summary>
+ public static string brokerUrl;
+
+ /// <summary> Holds the virtual host to run the tests on. If <tt>null</tt>, then the default virtual host is used. </summary>
+ public static string virtualHost;
+
+ /// <summary> The clients identifying name to print in test results and to distinguish from other clients. </summary>
+ private string clientName;
+
+ /// <summary> Holds all the test cases. </summary>
+ private IDictionary testCases = new Hashtable();
+
+ InteropClientTestCase currentTestCase;
+
+ private MessagePublisherBuilder publisherBuilder;
+
+ private IChannel channel;
+
+ /// <summary> Monitor to wait for termination events on. </summary>
+ private static object terminationMonitor = new Object();
+
+ /// <summary>
+ /// Creates a new interop test client, listenting to the specified broker and virtual host, with the specified
+ /// client identifying name.
+ /// </summary>
+ ///
+ /// <param name="brokerUrl"> The url of the broker to connect to. </param>
+ /// <param name="virtualHost"> The virtual host to conect to. </param>
+ /// <param name="clientName"> The client name to use. </param>
+ public TestClient(string brokerUrl, string virtualHost, string clientName)
+ {
+ log.Info("public TestClient(string brokerUrl = " + brokerUrl + ", string virtualHost = " + virtualHost
+ + ", string clientName = " + clientName + "): called");
+
+ // Retain the connection parameters.
+ TestClient.brokerUrl = brokerUrl;
+ TestClient.virtualHost = virtualHost;
+ this.clientName = clientName;
+ }
+
+
+ /// <summary>
+ /// The entry point for the interop test coordinator. This client accepts the following command line arguments:
+ /// </summary>
+ ///
+ /// <p/><table>
+ /// <tr><td> -b <td> The broker URL. <td> Optional.
+ /// <tr><td> -h <td> The virtual host. <td> Optional.
+ /// <tr><td> -n <td> The test client name. <td> Optional.
+ /// <tr><td> name=value <td> Trailing argument define name/value pairs. Added to system properties. <td> Optional.
+ /// </table>
+ ///
+ /// <param name="args"> The command line arguments. </param>
+ public static void Main(string[] args)
+ {
+ // Extract the command line options (Not exactly Posix but it will do for now...).
+ string brokerUrl = DEFAULT_BROKER_URL;
+ string virtualHost = DEFAULT_VIRTUAL_HOST;
+ string clientName = DEFAULT_CLIENT_NAME;
+
+ foreach (string nextArg in args)
+ {
+ if (nextArg.StartsWith("-b"))
+ {
+ brokerUrl = nextArg.Substring(2);
+ }
+ else if (nextArg.StartsWith("-h"))
+ {
+ virtualHost = nextArg.Substring(2);
+ }
+ else if (nextArg.StartsWith("-n"))
+ {
+ clientName = nextArg.Substring(2);
+ }
+ }
+
+ NDC.Push(clientName);
+
+ // Create a test client and start it running.
+ TestClient client = new TestClient(brokerUrl, virtualHost, clientName);
+
+ try
+ {
+ client.Start();
+ }
+ catch (Exception e)
+ {
+ log.Error("The test client was unable to start.", e);
+ System.Environment.Exit(1);
+ }
+
+ // Wait for a signal on the termination monitor before quitting.
+ lock (terminationMonitor)
+ {
+ Monitor.Wait(terminationMonitor);
+ }
+
+ NDC.Pop();
+ }
+
+ /// <summary>
+ /// Starts the interop test client running. This causes it to start listening for incoming test invites.
+ /// </summary>
+ private void Start()
+ {
+ log.Info("private void Start(): called");
+
+ // Use a class path scanner to find all the interop test case implementations.
+ ArrayList testCaseClasses = new ArrayList();
+
+ // ClasspathScanner.getMatches(InteropClientTestCase.class, "^TestCase.*", true);
+ // Hard code the test classes till the classpath scanner is fixed.
+ testCaseClasses.Add(typeof(TestCase1DummyRun));
+ testCaseClasses.Add(typeof(TestCase2BasicP2P));
+ testCaseClasses.Add(typeof(TestCase3BasicPubSub));
+
+ // Create all the test case implementations and index them by the test names.
+ foreach (Type testClass in testCaseClasses)
+ {
+ InteropClientTestCase testCase = (InteropClientTestCase)Activator.CreateInstance(testClass);
+ testCases.Add(testCase.GetName(), testCase);
+
+ log.Info("Found test case: " + testClass);
+ }
+
+ // Open a connection to communicate with the coordinator on.
+ log.Info("brokerUrl = " + brokerUrl);
+ IConnection connection = CreateConnection(brokerUrl, virtualHost);
+
+ channel = connection.CreateChannel(false, AcknowledgeMode.AutoAcknowledge);
+
+ // Set this up to listen for control messages.
+ string responseQueueName = channel.GenerateUniqueName();
+ channel.DeclareQueue(responseQueueName, false, true, true);
+
+ channel.Bind(responseQueueName, ExchangeNameDefaults.TOPIC, "iop.control." + clientName);
+ channel.Bind(responseQueueName, ExchangeNameDefaults.TOPIC, "iop.control");
+
+ IMessageConsumer consumer = channel.CreateConsumerBuilder(responseQueueName)
+ .Create();
+ consumer.OnMessage += new MessageReceivedDelegate(OnMessage);
+
+ // Create a publisher to send replies with.
+ publisherBuilder = channel.CreatePublisherBuilder()
+ .WithExchangeName(ExchangeNameDefaults.DIRECT);
+
+
+ // Start listening for incoming control messages.
+ connection.Start();
+ Console.WriteLine("Test client " + clientName + " ready to receive test control messages...");
+ }
+
+ /// <summary>
+ /// Establishes an AMQ connection. This is a simple convenience method for code that does not anticipate handling connection failures.
+ /// All exceptions that indicate that the connection has failed, are allowed to fall through.
+ /// </summary>
+ ///
+ /// <param name="brokerUrl"> The broker url to connect to, <tt>null</tt> to use the default from the properties. </param>
+ /// <param name="virtualHost"> The virtual host to connectio to, <tt>null</tt> to use the default. </param>
+ ///
+ /// <returns> A JMS conneciton. </returns>
+ public static IConnection CreateConnection(string brokerUrl, string virtualHost)
+ {
+ log.Info("public static Connection createConnection(string brokerUrl = " + brokerUrl + ", string virtualHost = "
+ + virtualHost + "): called");
+
+ // Create a connection to the broker.
+ IConnectionInfo connectionInfo = QpidConnectionInfo.FromUrl(brokerUrl);
+ connectionInfo.VirtualHost = virtualHost;
+ IConnection connection = new AMQConnection(connectionInfo);
+
+ return connection;
+ }
+
+ /// <summary>
+ /// Handles all incoming control messages.
+ /// </summary>
+ ///
+ /// <param name="message"> The incoming message. </param>
+ public void OnMessage(IMessage message)
+ {
+ log.Info("public void OnMessage(IMessage message = " + message + "): called");
+
+ try
+ {
+ string controlType = message.Headers.GetString("CONTROL_TYPE");
+ string testName = message.Headers.GetString("TEST_NAME");
+
+ // Check if the message is a test invite.
+ if ("INVITE" == controlType)
+ {
+ string testCaseName = message.Headers.GetString("TEST_NAME");
+
+ // Flag used to indicate that an enlist should be sent. Only enlist to compulsory invites or invites
+ // for which test cases exist.
+ bool enlist = false;
+
+ if (testCaseName != null)
+ {
+ log.Info("Got an invite to test: " + testCaseName);
+
+ // Check if the requested test case is available.
+ InteropClientTestCase testCase = (InteropClientTestCase)testCases[testCaseName];
+
+ if (testCase != null)
+ {
+ // Make the requested test case the current test case.
+ currentTestCase = testCase;
+ enlist = true;
+ }
+ }
+ else
+ {
+ log.Info("Got a compulsory invite.");
+
+ enlist = true;
+ }
+
+ log.Info("enlist = " + enlist);
+
+ if (enlist)
+ {
+ // Reply with the client name in an Enlist message.
+ IMessage enlistMessage = channel.CreateMessage();
+ enlistMessage.Headers.SetString("CONTROL_TYPE", "ENLIST");
+ enlistMessage.Headers.SetString("CLIENT_NAME", clientName);
+ enlistMessage.Headers.SetString("CLIENT_PRIVATE_CONTROL_KEY", "iop.control." + clientName);
+ enlistMessage.CorrelationId = message.CorrelationId;
+
+ Send(enlistMessage, message.ReplyToRoutingKey);
+ }
+ }
+ else if ("ASSIGN_ROLE" == controlType)
+ {
+ // Assign the role to the current test case.
+ string roleName = message.Headers.GetString("ROLE");
+
+ log.Info("Got a role assignment to role: " + roleName);
+
+ Roles role;
+
+ if (roleName == "SENDER")
+ {
+ role = Roles.SENDER;
+ }
+ else
+ {
+ role = Roles.RECEIVER;
+ }
+
+ currentTestCase.AssignRole(role, message);
+
+ // Reply by accepting the role in an Accept Role message.
+ IMessage acceptRoleMessage = channel.CreateMessage();
+ acceptRoleMessage.Headers.SetString("CONTROL_TYPE", "ACCEPT_ROLE");
+ acceptRoleMessage.CorrelationId = message.CorrelationId;
+
+ Send(acceptRoleMessage, message.ReplyToRoutingKey);
+ }
+ else if ("START" == controlType || "STATUS_REQUEST" == controlType)
+ {
+ if ("START" == controlType)
+ {
+ log.Info("Got a start notification.");
+
+ // Start the current test case.
+ currentTestCase.Start();
+ }
+ else
+ {
+ log.Info("Got a status request.");
+ }
+
+ // Generate the report from the test case and reply with it as a Report message.
+ IMessage reportMessage = currentTestCase.GetReport(channel);
+ reportMessage.Headers.SetString("CONTROL_TYPE", "REPORT");
+ reportMessage.CorrelationId = message.CorrelationId;
+
+ Send(reportMessage, message.ReplyToRoutingKey);
+ }
+ else if ("TERMINATE" == controlType)
+ {
+ Console.WriteLine("Received termination instruction from coordinator.");
+
+ // Is a cleaner shutdown needed?
+ System.Environment.Exit(1);
+ }
+ else
+ {
+ // Log a warning about this but otherwise ignore it.
+ log.Warn("Got an unknown control message, controlType = " + controlType + ", message = " + message);
+ }
+ }
+ catch (QpidException e)
+ {
+ // Log a warning about this, but otherwise ignore it.
+ log.Warn("A QpidException occurred whilst handling a message.");
+ log.Info("Got QpidException whilst handling message: " + message, e);
+ }
+ }
+
+ /// <summary>
+ /// Send the specified message using the specified routing key on the direct exchange.
+ /// </summary>
+ ///
+ /// <param name="message"> The message to send.</param>
+ /// <param name="routingKey"> The routing key to send the message with.</param>
+ public void Send(IMessage message, string routingKey)
+ {
+ IMessagePublisher publisher = publisherBuilder.WithRoutingKey(routingKey).Create();
+ publisher.Send(message);
+ }
+ }
+}
diff --git a/dotnet/Qpid.Integration.Tests/log4net.config b/dotnet/Qpid.Integration.Tests/log4net.config
index 974f51c80d..73bfc77a3e 100644
--- a/dotnet/Qpid.Integration.Tests/log4net.config
+++ b/dotnet/Qpid.Integration.Tests/log4net.config
@@ -1,48 +1,69 @@
-<log4net>
-
- <!-- ============================== -->
- <!-- Append messages to the console -->
- <!-- ============================== -->
-
- <appender name="console" type="log4net.Appender.ConsoleAppender" >
- <layout type="log4net.Layout.PatternLayout">
- <conversionPattern value="%m%n"/>
- </layout>
- <threshold value="info"/>
- </appender>
-
- <!-- ====================================== -->
- <!-- Append messages to the socket appender -->
- <!-- ====================================== -->
-
- <appender name="UdpAppender" type="log4net.Appender.UdpAppender">
- <remoteAddress value="127.0.0.1"/>
- <remotePort value="4445"/>
- <layout type="log4net.Layout.XmlLayoutSchemaLog4j">
- <locationInfo value="true"/>
- </layout>
- <threshold value="debug"/>
- </appender>
-
- <!-- ================ -->
- <!-- Limit categories -->
- <!-- ================ -->
-
- <logger name="Qpid">
- <level value="debug"/>
- </logger>
-
- <logger name="CONSOLE">
- <level value="info"/>
- <appender-ref ref="console"/>
- </logger>
-
- <!-- ======================= -->
- <!-- Setup the Root category -->
- <!-- ======================= -->
-
- <root>
- <appender-ref ref="UdpAppender"/>
- </root>
-
-</log4net> \ No newline at end of file
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<log4net>
+
+ <!-- ============================== -->
+ <!-- Append messages to the console -->
+ <!-- ============================== -->
+
+ <appender name="console" type="log4net.Appender.ConsoleAppender" >
+ <layout type="log4net.Layout.PatternLayout">
+ <conversionPattern value="%m%n"/>
+ </layout>
+ <threshold value="info"/>
+ </appender>
+
+ <!-- ====================================== -->
+ <!-- Append messages to the socket appender -->
+ <!-- ====================================== -->
+
+ <appender name="UdpAppender" type="log4net.Appender.UdpAppender">
+ <remoteAddress value="127.0.0.1"/>
+ <remotePort value="4445"/>
+ <layout type="log4net.Layout.XmlLayoutSchemaLog4j">
+ <locationInfo value="true"/>
+ </layout>
+ <threshold value="debug"/>
+ </appender>
+
+ <!-- ================ -->
+ <!-- Limit categories -->
+ <!-- ================ -->
+
+ <logger name="Qpid">
+ <level value="debug"/>
+ </logger>
+
+ <logger name="CONSOLE">
+ <level value="info"/>
+ <appender-ref ref="console"/>
+ </logger>
+
+ <!-- ======================= -->
+ <!-- Setup the Root category -->
+ <!-- ======================= -->
+
+ <root>
+ <appender-ref ref="UdpAppender"/>
+ </root>
+
+</log4net>
diff --git a/dotnet/Qpid.Integration.Tests/testcases/BaseMessagingTestFixture.cs b/dotnet/Qpid.Integration.Tests/testcases/BaseMessagingTestFixture.cs
index d4b61a2788..4c82dbe08c 100644
--- a/dotnet/Qpid.Integration.Tests/testcases/BaseMessagingTestFixture.cs
+++ b/dotnet/Qpid.Integration.Tests/testcases/BaseMessagingTestFixture.cs
@@ -1,261 +1,261 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Text;
-using log4net;
-using NUnit.Framework;
-using Apache.Qpid.Messaging;
-using Apache.Qpid.Client.Qms;
-using Apache.Qpid.Client;
-
-namespace Apache.Qpid.Integration.Tests.testcases
-{
- /// <summary>
- /// Provides a basis for writing Unit tests that communicate with an AMQ protocol broker. By default it creates a connection
- /// to a message broker running on localhost on the standard AMQ port, 5672, using guest:guest login credentials. It also
- /// creates a standard auto-ack channel on this connection.
- /// </summary>
- public class BaseMessagingTestFixture
- {
- private static ILog log = LogManager.GetLogger(typeof(BaseMessagingTestFixture));
-
- /// <summary> Used to build dummy data to fill test messages with. </summary>
- private const string MESSAGE_DATA_BYTES = "-- Test Message -- Test Message -- Test Message -- Test Message -- Test Message ";
-
- /// <summary> The default timeout in milliseconds to use on receives. </summary>
- private const long RECEIVE_WAIT = 2000;
-
- /// <summary> The default AMQ connection URL to use for tests. </summary>
- public const string connectionUri = "amqp://guest:guest@test/test?brokerlist='tcp://localhost:5672'";
-
- /// <summary> The default AMQ connection URL parsed as a connection info. </summary>
- protected IConnectionInfo connectionInfo;
-
- /// <summary> Holds an array of connections for building mutiple test end-points. </summary>
- protected IConnection[] testConnection = new IConnection[10];
-
- /// <summary> Holds an array of channels for building mutiple test end-points. </summary>
- protected IChannel[] testChannel = new IChannel[10];
-
- /// <summary> Holds an array of queues for building mutiple test end-points. </summary>
- protected String[] testQueue = new String[10];
-
- /// <summary> Holds an array of producers for building mutiple test end-points. </summary>
- protected IMessagePublisher[] testProducer = new IMessagePublisher[10];
-
- /// <summary> Holds an array of consumers for building mutiple test end-points. </summary>
- protected IMessageConsumer[] testConsumer = new IMessageConsumer[10];
-
- /// <summary> A counter used to supply unique ids. </summary>
- private static int uniqueId = 0;
-
- /// <summary> Used to hold unique ids per test. </summary>
- protected Guid testId;
-
- /// <summary> Creates the test connection and channel. </summary>
- [SetUp]
- public virtual void Init()
- {
- log.Debug("public virtual void Init(): called");
-
- // Set up a unique id for this test.
- testId = System.Guid.NewGuid();
- }
-
- /// <summary>
- /// Disposes of the test connection. This is called manually because the connection is a field so dispose will not be automatically
- /// called on it.
- /// </summary>
- [TearDown]
- public virtual void Shutdown()
- {
- log.Debug("public virtual void Shutdown(): called");
- }
-
- /// <summary> Sets up the nth test end-point. </summary>
- ///
- /// <param name="n">The index of the test end-point to set up.</param>
- /// <param name="producer"><tt>true</tt> to set up a producer on the end-point.</param>
- /// <param name="consumer"><tt>true</tt> to set up a consumer on the end-point.</param>
- /// <param name="routingKey">The routing key for the producer to send on.</param>
- /// <param name="ackMode">The ack mode for the end-points channel.</param>
- /// <param name="transacted"><tt>true</tt> to use transactions on the end-points channel.</param>
- /// <param name="exchangeName">The exchange to produce or consume on.</param>
- /// <param name="declareBind"><tt>true</tt> if the consumers queue should be declared and bound, <tt>false</tt> if it has already been.</param>
- /// <param name="durable"><tt>true</tt> to declare the consumers queue as durable.</param>
- /// <param name="subscriptionName">If durable is true, the fixed unique queue name to use.</param>
- public void SetUpEndPoint(int n, bool producer, bool consumer, string routingKey, AcknowledgeMode ackMode, bool transacted,
- string exchangeName, bool declareBind, bool durable, string subscriptionName)
- {
- // Allow client id to be fixed, or undefined.
- {
- // Use unique id for end point.
- connectionInfo = QpidConnectionInfo.FromUrl(connectionUri);
-
- connectionInfo.ClientName = "test" + n;
- }
-
- testConnection[n] = new AMQConnection(connectionInfo);
- testConnection[n].Start();
- testChannel[n] = testConnection[n].CreateChannel(transacted, ackMode);
-
- if (producer)
- {
- testProducer[n] = testChannel[n].CreatePublisherBuilder()
- .WithExchangeName(exchangeName)
- .WithRoutingKey(routingKey)
- .Create();
- }
-
- if (consumer)
- {
- string queueName;
-
- // Use the subscription name as the queue name if the subscription is durable, otherwise use a generated name.
- if (durable)
- {
- // The durable queue is declared without auto-delete, and passively, in case it has already been declared.
- queueName = subscriptionName;
-
- if (declareBind)
- {
- testChannel[n].DeclareQueue(queueName, durable, true, false);
- testChannel[n].Bind(queueName, exchangeName, routingKey);
- }
- }
- else
- {
- queueName = testChannel[n].GenerateUniqueName();
-
- if (declareBind)
- {
- if (durable)
- {
- testQueue[n] = queueName;
- }
- testChannel[n].DeclareQueue(queueName, durable, true, true);
- testChannel[n].Bind(queueName, exchangeName, routingKey);
- }
- }
-
- testConsumer[n] = testChannel[n].CreateConsumerBuilder(queueName).Create();
- }
- }
-
- /// <summary> Closes down the nth test end-point. </summary>
- public void CloseEndPoint(int n)
- {
- log.Debug("public void CloseEndPoint(int n): called");
-
- if (testProducer[n] != null)
- {
- testProducer[n].Close();
- testProducer[n].Dispose();
- testProducer[n] = null;
- }
-
- if (testConsumer[n] != null)
- {
- if (testQueue[n] != null)
- {
- testChannel[n].DeleteQueue(testQueue[n], false, false, true);
- }
- testConsumer[n].Close();
- testConsumer[n].Dispose();
- testConsumer[n] = null;
- }
-
- if (testConnection[n] != null)
- {
- testConnection[n].Stop();
- testConnection[n].Close();
- testConnection[n].Dispose();
- testConnection[n] = null;
- }
- }
-
- /// <summary>
- /// Consumes n messages, checking that the n+1th is not available within a timeout, and that the consumed messages
- /// are text messages with contents equal to the specified message body.
- /// </summary>
- ///
- /// <param name="n">The number of messages to consume.</param>
- /// <param name="body">The body text to match against all messages.</param>
- /// <param name="consumer">The message consumer to recieve the messages on.</param>
- public static void ConsumeNMessagesOnly(int n, string body, IMessageConsumer consumer)
- {
- ConsumeNMessages(n, body, consumer);
-
- // Check that one more than n cannot be received.
- IMessage msg = consumer.Receive(RECEIVE_WAIT);
- Assert.IsNull(msg, "Consumer got more messages than the number requested (" + n + ").");
- }
-
- /// <summary>
- /// Consumes n messages, checking that the n+1th is not available within a timeout, and that the consumed messages
- /// are text messages with contents equal to the specified message body.
- /// </summary>
- ///
- /// <param name="n">The number of messages to consume.</param>
- /// <param name="body">The body text to match against all messages.</param>
- /// <param name="consumer">The message consumer to recieve the messages on.</param>
- public static void ConsumeNMessages(int n, string body, IMessageConsumer consumer)
- {
- IMessage msg;
-
- // Try to receive n messages.
- for (int i = 0; i < n; i++)
- {
- msg = consumer.Receive(RECEIVE_WAIT);
- Assert.IsNotNull(msg, "Consumer did not receive message number: " + i);
- Assert.AreEqual(body, ((ITextMessage)msg).Text, "Incorrect Message recevied on consumer1.");
- }
- }
-
- /// <summary>Creates the requested number of bytes of dummy text. Usually used for filling test messages. </summary>
- ///
- /// <param name="size">The number of bytes of dummy text to generate.</param>
- ///
- /// <return>The requested number of bytes of dummy text.</return>
- public static String GetData(int size)
- {
- StringBuilder buf = new StringBuilder(size);
-
- if (size > 0)
- {
- int div = MESSAGE_DATA_BYTES.Length / size;
- int mod = MESSAGE_DATA_BYTES.Length % size;
-
- for (int i = 0; i < div; i++)
- {
- buf.Append(MESSAGE_DATA_BYTES);
- }
-
- if (mod != 0)
- {
- buf.Append(MESSAGE_DATA_BYTES, 0, mod);
- }
- }
-
- return buf.ToString();
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Text;
+using log4net;
+using NUnit.Framework;
+using Apache.Qpid.Messaging;
+using Apache.Qpid.Client.Qms;
+using Apache.Qpid.Client;
+
+namespace Apache.Qpid.Integration.Tests.testcases
+{
+ /// <summary>
+ /// Provides a basis for writing Unit tests that communicate with an AMQ protocol broker. By default it creates a connection
+ /// to a message broker running on localhost on the standard AMQ port, 5672, using guest:guest login credentials. It also
+ /// creates a standard auto-ack channel on this connection.
+ /// </summary>
+ public class BaseMessagingTestFixture
+ {
+ private static ILog log = LogManager.GetLogger(typeof(BaseMessagingTestFixture));
+
+ /// <summary> Used to build dummy data to fill test messages with. </summary>
+ private const string MESSAGE_DATA_BYTES = "-- Test Message -- Test Message -- Test Message -- Test Message -- Test Message ";
+
+ /// <summary> The default timeout in milliseconds to use on receives. </summary>
+ private const long RECEIVE_WAIT = 2000;
+
+ /// <summary> The default AMQ connection URL to use for tests. </summary>
+ public const string connectionUri = "amqp://guest:guest@test/test?brokerlist='tcp://localhost:5672'";
+
+ /// <summary> The default AMQ connection URL parsed as a connection info. </summary>
+ protected IConnectionInfo connectionInfo;
+
+ /// <summary> Holds an array of connections for building mutiple test end-points. </summary>
+ protected IConnection[] testConnection = new IConnection[10];
+
+ /// <summary> Holds an array of channels for building mutiple test end-points. </summary>
+ protected IChannel[] testChannel = new IChannel[10];
+
+ /// <summary> Holds an array of queues for building mutiple test end-points. </summary>
+ protected String[] testQueue = new String[10];
+
+ /// <summary> Holds an array of producers for building mutiple test end-points. </summary>
+ protected IMessagePublisher[] testProducer = new IMessagePublisher[10];
+
+ /// <summary> Holds an array of consumers for building mutiple test end-points. </summary>
+ protected IMessageConsumer[] testConsumer = new IMessageConsumer[10];
+
+ /// <summary> A counter used to supply unique ids. </summary>
+ private static int uniqueId = 0;
+
+ /// <summary> Used to hold unique ids per test. </summary>
+ protected Guid testId;
+
+ /// <summary> Creates the test connection and channel. </summary>
+ [SetUp]
+ public virtual void Init()
+ {
+ log.Debug("public virtual void Init(): called");
+
+ // Set up a unique id for this test.
+ testId = System.Guid.NewGuid();
+ }
+
+ /// <summary>
+ /// Disposes of the test connection. This is called manually because the connection is a field so dispose will not be automatically
+ /// called on it.
+ /// </summary>
+ [TearDown]
+ public virtual void Shutdown()
+ {
+ log.Debug("public virtual void Shutdown(): called");
+ }
+
+ /// <summary> Sets up the nth test end-point. </summary>
+ ///
+ /// <param name="n">The index of the test end-point to set up.</param>
+ /// <param name="producer"><tt>true</tt> to set up a producer on the end-point.</param>
+ /// <param name="consumer"><tt>true</tt> to set up a consumer on the end-point.</param>
+ /// <param name="routingKey">The routing key for the producer to send on.</param>
+ /// <param name="ackMode">The ack mode for the end-points channel.</param>
+ /// <param name="transacted"><tt>true</tt> to use transactions on the end-points channel.</param>
+ /// <param name="exchangeName">The exchange to produce or consume on.</param>
+ /// <param name="declareBind"><tt>true</tt> if the consumers queue should be declared and bound, <tt>false</tt> if it has already been.</param>
+ /// <param name="durable"><tt>true</tt> to declare the consumers queue as durable.</param>
+ /// <param name="subscriptionName">If durable is true, the fixed unique queue name to use.</param>
+ public void SetUpEndPoint(int n, bool producer, bool consumer, string routingKey, AcknowledgeMode ackMode, bool transacted,
+ string exchangeName, bool declareBind, bool durable, string subscriptionName)
+ {
+ // Allow client id to be fixed, or undefined.
+ {
+ // Use unique id for end point.
+ connectionInfo = QpidConnectionInfo.FromUrl(connectionUri);
+
+ connectionInfo.ClientName = "test" + n;
+ }
+
+ testConnection[n] = new AMQConnection(connectionInfo);
+ testConnection[n].Start();
+ testChannel[n] = testConnection[n].CreateChannel(transacted, ackMode);
+
+ if (producer)
+ {
+ testProducer[n] = testChannel[n].CreatePublisherBuilder()
+ .WithExchangeName(exchangeName)
+ .WithRoutingKey(routingKey)
+ .Create();
+ }
+
+ if (consumer)
+ {
+ string queueName;
+
+ // Use the subscription name as the queue name if the subscription is durable, otherwise use a generated name.
+ if (durable)
+ {
+ // The durable queue is declared without auto-delete, and passively, in case it has already been declared.
+ queueName = subscriptionName;
+
+ if (declareBind)
+ {
+ testChannel[n].DeclareQueue(queueName, durable, true, false);
+ testChannel[n].Bind(queueName, exchangeName, routingKey);
+ }
+ }
+ else
+ {
+ queueName = testChannel[n].GenerateUniqueName();
+
+ if (declareBind)
+ {
+ if (durable)
+ {
+ testQueue[n] = queueName;
+ }
+ testChannel[n].DeclareQueue(queueName, durable, true, true);
+ testChannel[n].Bind(queueName, exchangeName, routingKey);
+ }
+ }
+
+ testConsumer[n] = testChannel[n].CreateConsumerBuilder(queueName).Create();
+ }
+ }
+
+ /// <summary> Closes down the nth test end-point. </summary>
+ public void CloseEndPoint(int n)
+ {
+ log.Debug("public void CloseEndPoint(int n): called");
+
+ if (testProducer[n] != null)
+ {
+ testProducer[n].Close();
+ testProducer[n].Dispose();
+ testProducer[n] = null;
+ }
+
+ if (testConsumer[n] != null)
+ {
+ if (testQueue[n] != null)
+ {
+ testChannel[n].DeleteQueue(testQueue[n], false, false, true);
+ }
+ testConsumer[n].Close();
+ testConsumer[n].Dispose();
+ testConsumer[n] = null;
+ }
+
+ if (testConnection[n] != null)
+ {
+ testConnection[n].Stop();
+ testConnection[n].Close();
+ testConnection[n].Dispose();
+ testConnection[n] = null;
+ }
+ }
+
+ /// <summary>
+ /// Consumes n messages, checking that the n+1th is not available within a timeout, and that the consumed messages
+ /// are text messages with contents equal to the specified message body.
+ /// </summary>
+ ///
+ /// <param name="n">The number of messages to consume.</param>
+ /// <param name="body">The body text to match against all messages.</param>
+ /// <param name="consumer">The message consumer to recieve the messages on.</param>
+ public static void ConsumeNMessagesOnly(int n, string body, IMessageConsumer consumer)
+ {
+ ConsumeNMessages(n, body, consumer);
+
+ // Check that one more than n cannot be received.
+ IMessage msg = consumer.Receive(RECEIVE_WAIT);
+ Assert.IsNull(msg, "Consumer got more messages than the number requested (" + n + ").");
+ }
+
+ /// <summary>
+ /// Consumes n messages, checking that the n+1th is not available within a timeout, and that the consumed messages
+ /// are text messages with contents equal to the specified message body.
+ /// </summary>
+ ///
+ /// <param name="n">The number of messages to consume.</param>
+ /// <param name="body">The body text to match against all messages.</param>
+ /// <param name="consumer">The message consumer to recieve the messages on.</param>
+ public static void ConsumeNMessages(int n, string body, IMessageConsumer consumer)
+ {
+ IMessage msg;
+
+ // Try to receive n messages.
+ for (int i = 0; i < n; i++)
+ {
+ msg = consumer.Receive(RECEIVE_WAIT);
+ Assert.IsNotNull(msg, "Consumer did not receive message number: " + i);
+ Assert.AreEqual(body, ((ITextMessage)msg).Text, "Incorrect Message recevied on consumer1.");
+ }
+ }
+
+ /// <summary>Creates the requested number of bytes of dummy text. Usually used for filling test messages. </summary>
+ ///
+ /// <param name="size">The number of bytes of dummy text to generate.</param>
+ ///
+ /// <return>The requested number of bytes of dummy text.</return>
+ public static String GetData(int size)
+ {
+ StringBuilder buf = new StringBuilder(size);
+
+ if (size > 0)
+ {
+ int div = MESSAGE_DATA_BYTES.Length / size;
+ int mod = MESSAGE_DATA_BYTES.Length % size;
+
+ for (int i = 0; i < div; i++)
+ {
+ buf.Append(MESSAGE_DATA_BYTES);
+ }
+
+ if (mod != 0)
+ {
+ buf.Append(MESSAGE_DATA_BYTES, 0, mod);
+ }
+ }
+
+ return buf.ToString();
+ }
+ }
+}
diff --git a/dotnet/Qpid.Integration.Tests/testcases/ChannelQueueTest.cs b/dotnet/Qpid.Integration.Tests/testcases/ChannelQueueTest.cs
index e34864aefd..4692e7ecb1 100644
--- a/dotnet/Qpid.Integration.Tests/testcases/ChannelQueueTest.cs
+++ b/dotnet/Qpid.Integration.Tests/testcases/ChannelQueueTest.cs
@@ -1,237 +1,237 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Net;
-using System.Threading;
-using log4net;
-using Apache.Qpid.Client.Qms;
-using Apache.Qpid.Client;
-using Apache.Qpid.Messaging;
-using NUnit.Framework;
-
-namespace Apache.Qpid.Integration.Tests.testcases
-{
- /// <summary>
- /// Test the queue methods
- /// </summary>
- [TestFixture, Category("Integration")]
- public class ChannelQueueTest
- {
- private static ILog _logger = LogManager.GetLogger(typeof(ChannelQueueTest));
-
- /// <summary> The default AMQ connection URL to use for tests. </summary>
- const string DEFAULT_URI = "amqp://guest:guest@default/test?brokerlist='tcp://localhost:5672'";
- const string _routingKey = "ServiceQ1";
-
- private ExceptionListenerDelegate _exceptionDelegate;
- private AutoResetEvent _evt = new AutoResetEvent(false);
- private Exception _lastException = null;
-
- private IMessageConsumer _consumer;
- private IMessagePublisher _publisher;
- private IChannel _channel;
- private IConnection _connection;
-
- private string _queueName;
-
- [SetUp]
- public virtual void Init()
- {
- _logger.Info("public virtual void Init(): called");
-
- // Create a connection to the broker.
- IConnectionInfo connectionInfo = QpidConnectionInfo.FromUrl(DEFAULT_URI);
- _connection = new AMQConnection(connectionInfo);
- _logger.Info("Starting...");
-
- // Register this to listen for exceptions on the test connection.
- _exceptionDelegate = new ExceptionListenerDelegate(OnException);
- _connection.ExceptionListener += _exceptionDelegate;
-
- // Establish a session on the broker.
- _channel = _connection.CreateChannel(false, AcknowledgeMode.AutoAcknowledge, 1);
-
- // Create a durable, non-temporary, non-exclusive queue.
- _queueName = _channel.GenerateUniqueName();
- _channel.DeclareQueue(_queueName, true, false, false);
-
- _channel.Bind(_queueName, ExchangeNameDefaults.TOPIC, _routingKey);
-
- // Clear the most recent message and exception.
- _lastException = null;
- }
-
- [TearDown]
- public virtual void ShutDown()
- {
- _logger.Info("public virtual void Shutdown(): called");
-
- if (_connection != null)
- {
- _logger.Info("Disposing connection.");
- _connection.Dispose();
- _logger.Info("Connection disposed.");
- }
- }
-
- [Test]
- public void DeleteUsedQueue()
- {
- // Create the consumer
- _consumer = _channel.CreateConsumerBuilder(_queueName)
- .WithPrefetchLow(100)
- .Create();
- _logger.Info("Consumer was created...");
-
- // delete the queue
- _channel.DeleteQueue(_queueName, false, true, true);
- _logger.InfoFormat("Queue {0} was delete", _queueName);
-
- Assert.IsNull(_lastException);
- }
-
- [Test]
- public void DeleteUnusedQueue()
- {
- // delete the queue
- _channel.DeleteQueue(_queueName, true, true, true);
- _logger.InfoFormat("Queue {0} was delete", _queueName);
-
- Assert.IsNull(_lastException);
- }
-
- [Test]
- public void DeleteNonEmptyQueue()
- {
- // Create the publisher
- _publisher = _channel.CreatePublisherBuilder()
- .WithExchangeName(ExchangeNameDefaults.TOPIC)
- .WithRoutingKey(_routingKey)
- .Create();
- _logger.Info("Publisher created...");
- SendTestMessage("DeleteNonEmptyQueue Message 1");
-
- try
- {
- _channel.DeleteQueue(_queueName, true, false, true);
- }
- catch (AMQException)
- {
- Assert.Fail("The test fails");
- }
- }
-
- [Test]
- public void DeleteEmptyQueue()
- {
- // Create the publisher
- _publisher = _channel.CreatePublisherBuilder()
- .WithExchangeName(ExchangeNameDefaults.TOPIC)
- .WithRoutingKey(_routingKey)
- .Create();
- _logger.Info("Publisher created...");
-
- // delete an empty queue with ifEmpty = true
- _channel.DeleteQueue(_queueName, false, true, true);
-
- Assert.IsNull(_lastException);
- }
-
- [Test]
- public void DeleteQueueWithResponse()
- {
- // Create the publisher
- _publisher = _channel.CreatePublisherBuilder()
- .WithExchangeName(ExchangeNameDefaults.TOPIC)
- .WithRoutingKey(_routingKey)
- .Create();
- _logger.Info("Publisher created...");
-
- SendTestMessage("DeleteQueueWithResponse Message 1");
- SendTestMessage("DeleteQueueWithResponse Message 2");
-
- // delete the queue, the server must respond
- _channel.DeleteQueue(_queueName, false, false, false);
- }
-
- [Test]
- public void PurgeQueueWithResponse()
- {
- _publisher = _channel.CreatePublisherBuilder()
- .WithExchangeName(ExchangeNameDefaults.TOPIC)
- .WithRoutingKey(_routingKey)
- .Create();
- _logger.Info("Pubisher created");
-
- SendTestMessage("Message 1");
- SendTestMessage("Message 2");
-
- _channel.PurgeQueue(_queueName, false);
- }
-
- [Test]
- public void PurgeQueueWithOutResponse()
- {
- _publisher = _channel.CreatePublisherBuilder()
- .WithExchangeName(ExchangeNameDefaults.TOPIC)
- .WithRoutingKey(_routingKey)
- .Create();
- _logger.Info("Pubisher created");
-
- SendTestMessage("Message 1");
- SendTestMessage("Message 2");
-
- _channel.PurgeQueue(_queueName, true);
- }
-
-
- /// <summary>
- /// Callback method to handle any exceptions raised by the test connection.</summary> ///
- /// <param name="e">The connection exception.</param>
- public void OnException(Exception e)
- {
- // Preserve the most recent exception in case test cases need to examine it.
- _lastException = e;
-
- // Notify any waiting threads that an exception event has occurred.
- _evt.Set();
- }
-
- /// <summary>
- /// Sends the specified message to the test publisher, and confirms that it was received by the test consumer or not
- /// depending on whether or not the message should be received by the consumer.
- ///
- /// Any exceptions raised by the connection will cause an Assert failure exception to be raised.
- /// </summary>
- ///
- /// <param name="msgSend">The message to send.</param>
- private void SendTestMessage(string msg)
- {
- // create the IMessage object
- IMessage msgSend = _channel.CreateTextMessage(msg);
-
- // send the message
- _publisher.Send(msgSend);
- _logger.InfoFormat("The messages \"{0}\" was sent", msg);
- }
-
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Net;
+using System.Threading;
+using log4net;
+using Apache.Qpid.Client.Qms;
+using Apache.Qpid.Client;
+using Apache.Qpid.Messaging;
+using NUnit.Framework;
+
+namespace Apache.Qpid.Integration.Tests.testcases
+{
+ /// <summary>
+ /// Test the queue methods
+ /// </summary>
+ [TestFixture, Category("Integration")]
+ public class ChannelQueueTest
+ {
+ private static ILog _logger = LogManager.GetLogger(typeof(ChannelQueueTest));
+
+ /// <summary> The default AMQ connection URL to use for tests. </summary>
+ const string DEFAULT_URI = "amqp://guest:guest@default/test?brokerlist='tcp://localhost:5672'";
+ const string _routingKey = "ServiceQ1";
+
+ private ExceptionListenerDelegate _exceptionDelegate;
+ private AutoResetEvent _evt = new AutoResetEvent(false);
+ private Exception _lastException = null;
+
+ private IMessageConsumer _consumer;
+ private IMessagePublisher _publisher;
+ private IChannel _channel;
+ private IConnection _connection;
+
+ private string _queueName;
+
+ [SetUp]
+ public virtual void Init()
+ {
+ _logger.Info("public virtual void Init(): called");
+
+ // Create a connection to the broker.
+ IConnectionInfo connectionInfo = QpidConnectionInfo.FromUrl(DEFAULT_URI);
+ _connection = new AMQConnection(connectionInfo);
+ _logger.Info("Starting...");
+
+ // Register this to listen for exceptions on the test connection.
+ _exceptionDelegate = new ExceptionListenerDelegate(OnException);
+ _connection.ExceptionListener += _exceptionDelegate;
+
+ // Establish a session on the broker.
+ _channel = _connection.CreateChannel(false, AcknowledgeMode.AutoAcknowledge, 1);
+
+ // Create a durable, non-temporary, non-exclusive queue.
+ _queueName = _channel.GenerateUniqueName();
+ _channel.DeclareQueue(_queueName, true, false, false);
+
+ _channel.Bind(_queueName, ExchangeNameDefaults.TOPIC, _routingKey);
+
+ // Clear the most recent message and exception.
+ _lastException = null;
+ }
+
+ [TearDown]
+ public virtual void ShutDown()
+ {
+ _logger.Info("public virtual void Shutdown(): called");
+
+ if (_connection != null)
+ {
+ _logger.Info("Disposing connection.");
+ _connection.Dispose();
+ _logger.Info("Connection disposed.");
+ }
+ }
+
+ [Test]
+ public void DeleteUsedQueue()
+ {
+ // Create the consumer
+ _consumer = _channel.CreateConsumerBuilder(_queueName)
+ .WithPrefetchLow(100)
+ .Create();
+ _logger.Info("Consumer was created...");
+
+ // delete the queue
+ _channel.DeleteQueue(_queueName, false, true, true);
+ _logger.InfoFormat("Queue {0} was delete", _queueName);
+
+ Assert.IsNull(_lastException);
+ }
+
+ [Test]
+ public void DeleteUnusedQueue()
+ {
+ // delete the queue
+ _channel.DeleteQueue(_queueName, true, true, true);
+ _logger.InfoFormat("Queue {0} was delete", _queueName);
+
+ Assert.IsNull(_lastException);
+ }
+
+ [Test]
+ public void DeleteNonEmptyQueue()
+ {
+ // Create the publisher
+ _publisher = _channel.CreatePublisherBuilder()
+ .WithExchangeName(ExchangeNameDefaults.TOPIC)
+ .WithRoutingKey(_routingKey)
+ .Create();
+ _logger.Info("Publisher created...");
+ SendTestMessage("DeleteNonEmptyQueue Message 1");
+
+ try
+ {
+ _channel.DeleteQueue(_queueName, true, false, true);
+ }
+ catch (AMQException)
+ {
+ Assert.Fail("The test fails");
+ }
+ }
+
+ [Test]
+ public void DeleteEmptyQueue()
+ {
+ // Create the publisher
+ _publisher = _channel.CreatePublisherBuilder()
+ .WithExchangeName(ExchangeNameDefaults.TOPIC)
+ .WithRoutingKey(_routingKey)
+ .Create();
+ _logger.Info("Publisher created...");
+
+ // delete an empty queue with ifEmpty = true
+ _channel.DeleteQueue(_queueName, false, true, true);
+
+ Assert.IsNull(_lastException);
+ }
+
+ [Test]
+ public void DeleteQueueWithResponse()
+ {
+ // Create the publisher
+ _publisher = _channel.CreatePublisherBuilder()
+ .WithExchangeName(ExchangeNameDefaults.TOPIC)
+ .WithRoutingKey(_routingKey)
+ .Create();
+ _logger.Info("Publisher created...");
+
+ SendTestMessage("DeleteQueueWithResponse Message 1");
+ SendTestMessage("DeleteQueueWithResponse Message 2");
+
+ // delete the queue, the server must respond
+ _channel.DeleteQueue(_queueName, false, false, false);
+ }
+
+ [Test]
+ public void PurgeQueueWithResponse()
+ {
+ _publisher = _channel.CreatePublisherBuilder()
+ .WithExchangeName(ExchangeNameDefaults.TOPIC)
+ .WithRoutingKey(_routingKey)
+ .Create();
+ _logger.Info("Pubisher created");
+
+ SendTestMessage("Message 1");
+ SendTestMessage("Message 2");
+
+ _channel.PurgeQueue(_queueName, false);
+ }
+
+ [Test]
+ public void PurgeQueueWithOutResponse()
+ {
+ _publisher = _channel.CreatePublisherBuilder()
+ .WithExchangeName(ExchangeNameDefaults.TOPIC)
+ .WithRoutingKey(_routingKey)
+ .Create();
+ _logger.Info("Pubisher created");
+
+ SendTestMessage("Message 1");
+ SendTestMessage("Message 2");
+
+ _channel.PurgeQueue(_queueName, true);
+ }
+
+
+ /// <summary>
+ /// Callback method to handle any exceptions raised by the test connection.</summary> ///
+ /// <param name="e">The connection exception.</param>
+ public void OnException(Exception e)
+ {
+ // Preserve the most recent exception in case test cases need to examine it.
+ _lastException = e;
+
+ // Notify any waiting threads that an exception event has occurred.
+ _evt.Set();
+ }
+
+ /// <summary>
+ /// Sends the specified message to the test publisher, and confirms that it was received by the test consumer or not
+ /// depending on whether or not the message should be received by the consumer.
+ ///
+ /// Any exceptions raised by the connection will cause an Assert failure exception to be raised.
+ /// </summary>
+ ///
+ /// <param name="msgSend">The message to send.</param>
+ private void SendTestMessage(string msg)
+ {
+ // create the IMessage object
+ IMessage msgSend = _channel.CreateTextMessage(msg);
+
+ // send the message
+ _publisher.Send(msgSend);
+ _logger.InfoFormat("The messages \"{0}\" was sent", msg);
+ }
+
+ }
+}
diff --git a/dotnet/Qpid.Integration.Tests/testcases/CommitRollbackTest.cs b/dotnet/Qpid.Integration.Tests/testcases/CommitRollbackTest.cs
index 72074da809..dbb3f70aec 100644
--- a/dotnet/Qpid.Integration.Tests/testcases/CommitRollbackTest.cs
+++ b/dotnet/Qpid.Integration.Tests/testcases/CommitRollbackTest.cs
@@ -1,261 +1,261 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Threading;
-using log4net;
-using NUnit.Framework;
-using Apache.Qpid.Messaging;
-using Apache.Qpid.Client.Qms;
-using Apache.Qpid.Client;
-
-namespace Apache.Qpid.Integration.Tests.testcases
-{
- /// <summary>
- /// CommitRollbackTest
- ///
- /// <p><table id="crc"><caption>CRC Card</caption>
- /// <tr><th> Responsibilities <th> Collaborations
- /// <tr><td> Check that an uncommitted send cannot be received.
- /// <tr><td> Check that a committed send can be received.
- /// <tr><td> Check that a rolled back send cannot be received.
- /// <tr><td> Check that an uncommitted receive can be re-received.
- /// <tr><td> Check that a committed receive cannot be re-received.
- /// <tr><td> Check that a rolled back receive can be re-received.
- /// </table>
- /// </summary>
- [TestFixture, Category("Integration")]
- public class CommitRollbackTest : BaseMessagingTestFixture
- {
- /// <summary>Used for debugging purposes.</summary>
- private static ILog log = LogManager.GetLogger(typeof(CommitRollbackTest));
-
- /// <summary>Defines the name of the test topic to use with the tests.</summary>
- public const string TEST_ROUTING_KEY = "commitrollbacktestkey";
-
- /// <summary>Used to count test messages received so far.</summary>
- private int messageReceivedCount;
-
- /// <summary>Used to hold the expected number of messages to receive.</summary>
- private int expectedMessageCount;
-
- /// <summary>Monitor used to signal succesfull receipt of all test messages.</summary>
- AutoResetEvent finishedEvent;
-
- /// <summary>Flag used to indicate that all messages really were received, and that the test did not just time out. </summary>
- private bool allReceived;
-
- [SetUp]
- public override void Init()
- {
- base.Init();
-
- // Create one producer and one consumer, p2p, tx, consumer with queue bound to producers routing key.
- SetUpEndPoint(0, true, false, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, true, ExchangeNameDefaults.DIRECT,
- true, false, null);
- SetUpEndPoint(1, true, true, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, true, ExchangeNameDefaults.DIRECT,
- true, false, null);
-
- // Clear counts
- messageReceivedCount = 0;
- expectedMessageCount = 0;
- finishedEvent = new AutoResetEvent(false);
- allReceived = false;
- }
-
- [TearDown]
- public override void Shutdown()
- {
- try
- {
- // Clean up after the test.
- CloseEndPoint(0);
- CloseEndPoint(1);
- }
- finally
- {
- base.Shutdown();
- }
- }
-
- /// <summary> Check that an uncommitted send cannot be received. </summary>
- [Test]
- public void TestUncommittedSendNotReceived()
- {
- // Send messages.
- testProducer[0].Send(testChannel[0].CreateTextMessage("A"));
-
- // Try to receive messages.
- ConsumeNMessagesOnly(0, "A", testConsumer[1]);
- testChannel[1].Commit();
- }
-
- /// <summary> Check that a committed send can be received. </summary>
- [Test]
- public void TestCommittedSendReceived()
- {
- // Send messages.
- testProducer[0].Send(testChannel[0].CreateTextMessage("B"));
- testChannel[0].Commit();
-
- // Try to receive messages.
- ConsumeNMessagesOnly(1, "B", testConsumer[1]);
- testChannel[1].Commit();
- }
-
- /// <summary> Check that a rolled back send cannot be received. </summary>
- [Test]
- public void TestRolledBackSendNotReceived()
- {
- // Send messages.
- testProducer[0].Send(testChannel[0].CreateTextMessage("B"));
- testChannel[0].Rollback();
-
- // Try to receive messages.
- ConsumeNMessagesOnly(0, "B", testConsumer[1]);
- testChannel[1].Commit();
- }
-
- /// <summary> Check that an uncommitted receive can be re-received. </summary>
- [Test]
- public void TestUncommittedReceiveCanBeRereceived()
- {
- // Create a third end-point as an alternative delivery route for the message.
- SetUpEndPoint(2, false, true, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, true, ExchangeNameDefaults.DIRECT,
- true, false, null);
-
- // Send messages.
- testProducer[0].Send(testChannel[0].CreateTextMessage("C"));
- testChannel[0].Commit();
-
- // Try to receive messages.
- ConsumeNMessagesOnly(1, "C", testConsumer[1]);
-
- // Close end-point 1 without committing the message, then re-open to consume again.
- CloseEndPoint(1);
-
- // Check that the message was released from the rolled back end-point an can be received on the alternative one instead.
- ConsumeNMessagesOnly(1, "C", testConsumer[2]);
-
- CloseEndPoint(2);
- }
-
- /// <summary> Check that a committed receive cannot be re-received. </summary>
- [Test]
- public void TestCommittedReceiveNotRereceived()
- {
- // Send messages.
- testProducer[0].Send(testChannel[0].CreateTextMessage("D"));
- testChannel[0].Commit();
-
- // Try to receive messages.
- ConsumeNMessagesOnly(1, "D", testConsumer[1]);
- testChannel[1].Commit();
-
- // Try to receive messages.
- ConsumeNMessagesOnly(0, "D", testConsumer[1]);
- }
-
- /// <summary> Check that a rolled back receive can be re-received. </summary>
- [Test]
- public void TestRolledBackReceiveCanBeRereceived()
- {
- // Send messages.
- testProducer[0].Send(testChannel[0].CreateTextMessage("E"));
- testChannel[0].Commit();
-
- // Try to receive messages.
- ConsumeNMessagesOnly(1, "E", testConsumer[1]);
-
- testChannel[1].Rollback();
-
- // Try to receive messages.
- ConsumeNMessagesOnly(1, "E", testConsumer[1]);
-
- }
-
- [Test]
- public void TestReceiveAndSendRollback()
- {
- // Send messages
- testProducer[0].Send(testChannel[0].CreateTextMessage("F"));
- testChannel[0].Commit();
-
- // Try to receive messages.
- ConsumeNMessagesOnly(1, "F", testConsumer[1]);
- testProducer[1].Send(testChannel[1].CreateTextMessage("G"));
- testChannel[1].Rollback();
-
- // Try to receive messages.
- ConsumeNMessagesOnly(1, "F", testConsumer[1]);
-
- }
-
- [Test]
- public void TestReceivePrePublished()
- {
- // Send messages
- for (int i = 0; i < 10; ++i)
- {
- testProducer[0].Send(testChannel[0].CreateTextMessage("G"+i));
- testChannel[0].Commit();
- }
-
- for (int i = 0; i < 10; ++i)
- {
- ConsumeNMessages(1, "G"+i, testConsumer[1]);
- }
- testChannel[1].Commit();
- }
-
- [Test]
- public void TestReceivePrePublishedOnMessageHandler()
- {
- testConsumer[1].OnMessage += new MessageReceivedDelegate(OnMessage);
- // Send messages
- for (int i = 0; i < 10; ++i)
- {
- testProducer[0].Send(testChannel[0].CreateTextMessage("G"+i));
- testChannel[0].Commit();
- }
- expectedMessageCount = 10;
-
- finishedEvent.WaitOne(new TimeSpan(0, 0, 0, 30), false);
-
- // Check that all messages really were received.
- Assert.IsTrue(allReceived, "All messages were not received, only got: " + messageReceivedCount + " but wanted " + expectedMessageCount);
-
- testChannel[1].Commit();
- }
-
- /// <summary> Atomically increments the message count on every message, and signals once all messages in the test are received. </summary>
- public void OnMessage(IMessage m)
- {
- int newCount = Interlocked.Increment(ref messageReceivedCount);
-
- if (newCount >= expectedMessageCount)
- {
- allReceived = true;
- finishedEvent.Set();
- }
- }
-
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Threading;
+using log4net;
+using NUnit.Framework;
+using Apache.Qpid.Messaging;
+using Apache.Qpid.Client.Qms;
+using Apache.Qpid.Client;
+
+namespace Apache.Qpid.Integration.Tests.testcases
+{
+ /// <summary>
+ /// CommitRollbackTest
+ ///
+ /// <p><table id="crc"><caption>CRC Card</caption>
+ /// <tr><th> Responsibilities <th> Collaborations
+ /// <tr><td> Check that an uncommitted send cannot be received.
+ /// <tr><td> Check that a committed send can be received.
+ /// <tr><td> Check that a rolled back send cannot be received.
+ /// <tr><td> Check that an uncommitted receive can be re-received.
+ /// <tr><td> Check that a committed receive cannot be re-received.
+ /// <tr><td> Check that a rolled back receive can be re-received.
+ /// </table>
+ /// </summary>
+ [TestFixture, Category("Integration")]
+ public class CommitRollbackTest : BaseMessagingTestFixture
+ {
+ /// <summary>Used for debugging purposes.</summary>
+ private static ILog log = LogManager.GetLogger(typeof(CommitRollbackTest));
+
+ /// <summary>Defines the name of the test topic to use with the tests.</summary>
+ public const string TEST_ROUTING_KEY = "commitrollbacktestkey";
+
+ /// <summary>Used to count test messages received so far.</summary>
+ private int messageReceivedCount;
+
+ /// <summary>Used to hold the expected number of messages to receive.</summary>
+ private int expectedMessageCount;
+
+ /// <summary>Monitor used to signal succesfull receipt of all test messages.</summary>
+ AutoResetEvent finishedEvent;
+
+ /// <summary>Flag used to indicate that all messages really were received, and that the test did not just time out. </summary>
+ private bool allReceived;
+
+ [SetUp]
+ public override void Init()
+ {
+ base.Init();
+
+ // Create one producer and one consumer, p2p, tx, consumer with queue bound to producers routing key.
+ SetUpEndPoint(0, true, false, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, true, ExchangeNameDefaults.DIRECT,
+ true, false, null);
+ SetUpEndPoint(1, true, true, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, true, ExchangeNameDefaults.DIRECT,
+ true, false, null);
+
+ // Clear counts
+ messageReceivedCount = 0;
+ expectedMessageCount = 0;
+ finishedEvent = new AutoResetEvent(false);
+ allReceived = false;
+ }
+
+ [TearDown]
+ public override void Shutdown()
+ {
+ try
+ {
+ // Clean up after the test.
+ CloseEndPoint(0);
+ CloseEndPoint(1);
+ }
+ finally
+ {
+ base.Shutdown();
+ }
+ }
+
+ /// <summary> Check that an uncommitted send cannot be received. </summary>
+ [Test]
+ public void TestUncommittedSendNotReceived()
+ {
+ // Send messages.
+ testProducer[0].Send(testChannel[0].CreateTextMessage("A"));
+
+ // Try to receive messages.
+ ConsumeNMessagesOnly(0, "A", testConsumer[1]);
+ testChannel[1].Commit();
+ }
+
+ /// <summary> Check that a committed send can be received. </summary>
+ [Test]
+ public void TestCommittedSendReceived()
+ {
+ // Send messages.
+ testProducer[0].Send(testChannel[0].CreateTextMessage("B"));
+ testChannel[0].Commit();
+
+ // Try to receive messages.
+ ConsumeNMessagesOnly(1, "B", testConsumer[1]);
+ testChannel[1].Commit();
+ }
+
+ /// <summary> Check that a rolled back send cannot be received. </summary>
+ [Test]
+ public void TestRolledBackSendNotReceived()
+ {
+ // Send messages.
+ testProducer[0].Send(testChannel[0].CreateTextMessage("B"));
+ testChannel[0].Rollback();
+
+ // Try to receive messages.
+ ConsumeNMessagesOnly(0, "B", testConsumer[1]);
+ testChannel[1].Commit();
+ }
+
+ /// <summary> Check that an uncommitted receive can be re-received. </summary>
+ [Test]
+ public void TestUncommittedReceiveCanBeRereceived()
+ {
+ // Create a third end-point as an alternative delivery route for the message.
+ SetUpEndPoint(2, false, true, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, true, ExchangeNameDefaults.DIRECT,
+ true, false, null);
+
+ // Send messages.
+ testProducer[0].Send(testChannel[0].CreateTextMessage("C"));
+ testChannel[0].Commit();
+
+ // Try to receive messages.
+ ConsumeNMessagesOnly(1, "C", testConsumer[1]);
+
+ // Close end-point 1 without committing the message, then re-open to consume again.
+ CloseEndPoint(1);
+
+ // Check that the message was released from the rolled back end-point an can be received on the alternative one instead.
+ ConsumeNMessagesOnly(1, "C", testConsumer[2]);
+
+ CloseEndPoint(2);
+ }
+
+ /// <summary> Check that a committed receive cannot be re-received. </summary>
+ [Test]
+ public void TestCommittedReceiveNotRereceived()
+ {
+ // Send messages.
+ testProducer[0].Send(testChannel[0].CreateTextMessage("D"));
+ testChannel[0].Commit();
+
+ // Try to receive messages.
+ ConsumeNMessagesOnly(1, "D", testConsumer[1]);
+ testChannel[1].Commit();
+
+ // Try to receive messages.
+ ConsumeNMessagesOnly(0, "D", testConsumer[1]);
+ }
+
+ /// <summary> Check that a rolled back receive can be re-received. </summary>
+ [Test]
+ public void TestRolledBackReceiveCanBeRereceived()
+ {
+ // Send messages.
+ testProducer[0].Send(testChannel[0].CreateTextMessage("E"));
+ testChannel[0].Commit();
+
+ // Try to receive messages.
+ ConsumeNMessagesOnly(1, "E", testConsumer[1]);
+
+ testChannel[1].Rollback();
+
+ // Try to receive messages.
+ ConsumeNMessagesOnly(1, "E", testConsumer[1]);
+
+ }
+
+ [Test]
+ public void TestReceiveAndSendRollback()
+ {
+ // Send messages
+ testProducer[0].Send(testChannel[0].CreateTextMessage("F"));
+ testChannel[0].Commit();
+
+ // Try to receive messages.
+ ConsumeNMessagesOnly(1, "F", testConsumer[1]);
+ testProducer[1].Send(testChannel[1].CreateTextMessage("G"));
+ testChannel[1].Rollback();
+
+ // Try to receive messages.
+ ConsumeNMessagesOnly(1, "F", testConsumer[1]);
+
+ }
+
+ [Test]
+ public void TestReceivePrePublished()
+ {
+ // Send messages
+ for (int i = 0; i < 10; ++i)
+ {
+ testProducer[0].Send(testChannel[0].CreateTextMessage("G"+i));
+ testChannel[0].Commit();
+ }
+
+ for (int i = 0; i < 10; ++i)
+ {
+ ConsumeNMessages(1, "G"+i, testConsumer[1]);
+ }
+ testChannel[1].Commit();
+ }
+
+ [Test]
+ public void TestReceivePrePublishedOnMessageHandler()
+ {
+ testConsumer[1].OnMessage += new MessageReceivedDelegate(OnMessage);
+ // Send messages
+ for (int i = 0; i < 10; ++i)
+ {
+ testProducer[0].Send(testChannel[0].CreateTextMessage("G"+i));
+ testChannel[0].Commit();
+ }
+ expectedMessageCount = 10;
+
+ finishedEvent.WaitOne(new TimeSpan(0, 0, 0, 30), false);
+
+ // Check that all messages really were received.
+ Assert.IsTrue(allReceived, "All messages were not received, only got: " + messageReceivedCount + " but wanted " + expectedMessageCount);
+
+ testChannel[1].Commit();
+ }
+
+ /// <summary> Atomically increments the message count on every message, and signals once all messages in the test are received. </summary>
+ public void OnMessage(IMessage m)
+ {
+ int newCount = Interlocked.Increment(ref messageReceivedCount);
+
+ if (newCount >= expectedMessageCount)
+ {
+ allReceived = true;
+ finishedEvent.Set();
+ }
+ }
+
+ }
+}
diff --git a/dotnet/Qpid.Integration.Tests/testcases/ConnectionTest.cs b/dotnet/Qpid.Integration.Tests/testcases/ConnectionTest.cs
index 357f164346..d7b4a4ddd2 100644
--- a/dotnet/Qpid.Integration.Tests/testcases/ConnectionTest.cs
+++ b/dotnet/Qpid.Integration.Tests/testcases/ConnectionTest.cs
@@ -1,73 +1,73 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using NUnit.Framework;
-using Apache.Qpid.Client.Qms;
-using Apache.Qpid.Client;
-using Apache.Qpid.Messaging;
-
-namespace Apache.Qpid.Integration.Tests.testcases
-{
- [TestFixture, Category("Integration")]
- public class ConnectionTest
- {
- private AmqBrokerInfo _broker =
- new AmqBrokerInfo("amqp", "localhost", 5672, false);
-
- [Test]
- public void SimpleConnection()
- {
- IConnectionInfo connectionInfo = new QpidConnectionInfo();
- connectionInfo.VirtualHost = "test";
- connectionInfo.AddBrokerInfo(_broker);
- using (IConnection connection = new AMQConnection(connectionInfo))
- {
- Console.WriteLine("connection = " + connection);
- }
- }
-
- [Test]
- [ExpectedException(typeof(AMQAuthenticationException))]
- public void PasswordFailureConnection()
- {
- IConnectionInfo connectionInfo = new QpidConnectionInfo();
- connectionInfo.VirtualHost = "test";
- connectionInfo.Password = "rubbish";
- connectionInfo.AddBrokerInfo(_broker);
-
- using (IConnection connection = new AMQConnection(connectionInfo))
- {
- Console.WriteLine("connection = " + connection);
- // wrong
- Assert.Fail("Authentication succeeded but should've failed");
- }
- }
-
- [Test]
- [ExpectedException(typeof(AMQConnectionException))]
- public void ConnectionFailure()
- {
- string url = "amqp://guest:guest@clientid/testpath?brokerlist='tcp://localhost:5673?retries='0''";
- new AMQConnection(QpidConnectionInfo.FromUrl(url));
- Assert.Fail("Connection should not be established");
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using NUnit.Framework;
+using Apache.Qpid.Client.Qms;
+using Apache.Qpid.Client;
+using Apache.Qpid.Messaging;
+
+namespace Apache.Qpid.Integration.Tests.testcases
+{
+ [TestFixture, Category("Integration")]
+ public class ConnectionTest
+ {
+ private AmqBrokerInfo _broker =
+ new AmqBrokerInfo("amqp", "localhost", 5672, false);
+
+ [Test]
+ public void SimpleConnection()
+ {
+ IConnectionInfo connectionInfo = new QpidConnectionInfo();
+ connectionInfo.VirtualHost = "test";
+ connectionInfo.AddBrokerInfo(_broker);
+ using (IConnection connection = new AMQConnection(connectionInfo))
+ {
+ Console.WriteLine("connection = " + connection);
+ }
+ }
+
+ [Test]
+ [ExpectedException(typeof(AMQAuthenticationException))]
+ public void PasswordFailureConnection()
+ {
+ IConnectionInfo connectionInfo = new QpidConnectionInfo();
+ connectionInfo.VirtualHost = "test";
+ connectionInfo.Password = "rubbish";
+ connectionInfo.AddBrokerInfo(_broker);
+
+ using (IConnection connection = new AMQConnection(connectionInfo))
+ {
+ Console.WriteLine("connection = " + connection);
+ // wrong
+ Assert.Fail("Authentication succeeded but should've failed");
+ }
+ }
+
+ [Test]
+ [ExpectedException(typeof(AMQConnectionException))]
+ public void ConnectionFailure()
+ {
+ string url = "amqp://guest:guest@clientid/testpath?brokerlist='tcp://localhost:5673?retries='0''";
+ new AMQConnection(QpidConnectionInfo.FromUrl(url));
+ Assert.Fail("Connection should not be established");
+ }
+ }
+}
diff --git a/dotnet/Qpid.Integration.Tests/testcases/DurableSubscriptionTest.cs b/dotnet/Qpid.Integration.Tests/testcases/DurableSubscriptionTest.cs
index ac975100b1..b7973ae3f5 100644
--- a/dotnet/Qpid.Integration.Tests/testcases/DurableSubscriptionTest.cs
+++ b/dotnet/Qpid.Integration.Tests/testcases/DurableSubscriptionTest.cs
@@ -1,166 +1,166 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Threading;
-using log4net;
-using NUnit.Framework;
-using Apache.Qpid.Messaging;
-using Apache.Qpid.Client.Qms;
-
-namespace Apache.Qpid.Integration.Tests.testcases
-{
- /// <summary>
- /// DurableSubscriptionTest checks that durable subscriptions work, by sending messages that can be picked up by
- /// a subscription that is currently off-line, and checking that the subscriber gets all of its messages when it
- /// does come on-line.
- ///
- /// <p/><table id="crc"><caption>CRC Card</caption>
- /// <tr><th> Responsibilities <th> Collaborations
- /// <tr><td>
- /// </table>
- /// </summary>
- [TestFixture, Category("Integration")]
- public class DurableSubscriptionTest : BaseMessagingTestFixture
- {
- /// <summary>Used for debugging purposes.</summary>
- private static ILog log = LogManager.GetLogger(typeof(DurableSubscriptionTest));
-
- /// <summary>Defines the name of the test topic to use with the tests.</summary>
- public const string TEST_ROUTING_KEY = "durablesubtestkey";
-
- [SetUp]
- public override void Init()
- {
- base.Init();
- }
-
- [TearDown]
- public override void Shutdown()
- {
- base.Shutdown();
- }
-
- [Test]
- public void TestDurableSubscriptionNoAck()
- {
- TestDurableSubscription(AcknowledgeMode.NoAcknowledge);
- }
-
- [Test]
- public void TestDurableSubscriptionAutoAck()
- {
- TestDurableSubscription(AcknowledgeMode.AutoAcknowledge);
- }
-
- private void TestDurableSubscription(AcknowledgeMode ackMode)
- {
- // Create a topic with one producer and two consumers.
- SetUpEndPoint(0, true, false, TEST_ROUTING_KEY + testId, ackMode, false, ExchangeNameDefaults.TOPIC, true, false, null);
- SetUpEndPoint(1, false, true, TEST_ROUTING_KEY + testId, ackMode, false, ExchangeNameDefaults.TOPIC, true, false, null);
- SetUpEndPoint(2, false, true, TEST_ROUTING_KEY + testId, ackMode, false, ExchangeNameDefaults.TOPIC, true,
- true, "TestSubscription" + testId);
-
- Thread.Sleep(500);
-
- // Send messages and receive on both consumers.
- testProducer[0].Send(testChannel[0].CreateTextMessage("A"));
-
- ConsumeNMessagesOnly(1, "A", testConsumer[1]);
- ConsumeNMessagesOnly(1, "A", testConsumer[2]);
-
- // Detach one consumer.
- CloseEndPoint(2);
-
- // Send message and receive on one consumer.
- testProducer[0].Send(testChannel[0].CreateTextMessage("B"));
-
- ConsumeNMessagesOnly(1, "B", testConsumer[1]);
-
- // Re-attach consumer, check that it gets the messages that it missed.
- SetUpEndPoint(2, false, true, TEST_ROUTING_KEY + testId, ackMode, false, ExchangeNameDefaults.TOPIC, true,
- true, "TestSubscription" + testId);
-
- ConsumeNMessagesOnly(1, "B", testConsumer[2]);
-
- // Clean up any open consumers at the end of the test.
- CloseEndPoint(2);
- CloseEndPoint(1);
- CloseEndPoint(0);
- }
-
- /// <summary> Check that an uncommitted receive can be re-received, on re-consume from the same durable subscription. </summary>
- [Test]
- public void TestUncommittedReceiveCanBeRereceivedNewConnection()
- {
- SetUpEndPoint(0, true, false, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, true, ExchangeNameDefaults.TOPIC,
- true, false, null);
- SetUpEndPoint(1, false, true, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, true, ExchangeNameDefaults.TOPIC,
- true, true, "foo"+testId);
-
- // Send messages.
- testProducer[0].Send(testChannel[0].CreateTextMessage("C"));
- testChannel[0].Commit();
-
- // Try to receive messages, but don't commit them.
- ConsumeNMessagesOnly(1, "C", testConsumer[1]);
-
- // Close end-point 1 without committing the message, then re-open the subscription to consume again.
- CloseEndPoint(1);
- SetUpEndPoint(1, false, true, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, true, ExchangeNameDefaults.TOPIC,
- true, true, "foo"+testId);
-
- // Check that the message was released from the rolled back end-point an can be received on the alternative one instead.
- ConsumeNMessagesOnly(1, "C", testConsumer[1]);
- testChannel[1].Commit();
- CloseEndPoint(1);
- CloseEndPoint(0);
- }
-
- /// <summary> Check that a rolled back receive can be re-received, on re-consume from the same durable subscription. </summary>
- [Test]
- public void TestRolledBackReceiveCanBeRereceivedNewConnection()
- {
- SetUpEndPoint(0, true, false, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, true, ExchangeNameDefaults.TOPIC,
- true, false, null);
- SetUpEndPoint(1, false, true, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, true, ExchangeNameDefaults.TOPIC,
- true, true, "foo"+testId);
-
- // Send messages.
- testProducer[0].Send(testChannel[0].CreateTextMessage("D"));
- testChannel[0].Commit();
-
- // Try to receive messages, but roll them back.
- ConsumeNMessagesOnly(1, "D", testConsumer[1]);
- testChannel[1].Rollback();
-
- // Close end-point 1 without committing the message, then re-open the subscription to consume again.
- CloseEndPoint(1);
- SetUpEndPoint(1, false, true, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, true, ExchangeNameDefaults.TOPIC,
- true, true, "foo"+testId);
-
- // Check that the message was released from the rolled back end-point an can be received on the alternative one instead.
- ConsumeNMessagesOnly(1, "D", testConsumer[1]);
- testChannel[1].Commit();
- CloseEndPoint(1);
- CloseEndPoint(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.
+ *
+ */
+using System;
+using System.Threading;
+using log4net;
+using NUnit.Framework;
+using Apache.Qpid.Messaging;
+using Apache.Qpid.Client.Qms;
+
+namespace Apache.Qpid.Integration.Tests.testcases
+{
+ /// <summary>
+ /// DurableSubscriptionTest checks that durable subscriptions work, by sending messages that can be picked up by
+ /// a subscription that is currently off-line, and checking that the subscriber gets all of its messages when it
+ /// does come on-line.
+ ///
+ /// <p/><table id="crc"><caption>CRC Card</caption>
+ /// <tr><th> Responsibilities <th> Collaborations
+ /// <tr><td>
+ /// </table>
+ /// </summary>
+ [TestFixture, Category("Integration")]
+ public class DurableSubscriptionTest : BaseMessagingTestFixture
+ {
+ /// <summary>Used for debugging purposes.</summary>
+ private static ILog log = LogManager.GetLogger(typeof(DurableSubscriptionTest));
+
+ /// <summary>Defines the name of the test topic to use with the tests.</summary>
+ public const string TEST_ROUTING_KEY = "durablesubtestkey";
+
+ [SetUp]
+ public override void Init()
+ {
+ base.Init();
+ }
+
+ [TearDown]
+ public override void Shutdown()
+ {
+ base.Shutdown();
+ }
+
+ [Test]
+ public void TestDurableSubscriptionNoAck()
+ {
+ TestDurableSubscription(AcknowledgeMode.NoAcknowledge);
+ }
+
+ [Test]
+ public void TestDurableSubscriptionAutoAck()
+ {
+ TestDurableSubscription(AcknowledgeMode.AutoAcknowledge);
+ }
+
+ private void TestDurableSubscription(AcknowledgeMode ackMode)
+ {
+ // Create a topic with one producer and two consumers.
+ SetUpEndPoint(0, true, false, TEST_ROUTING_KEY + testId, ackMode, false, ExchangeNameDefaults.TOPIC, true, false, null);
+ SetUpEndPoint(1, false, true, TEST_ROUTING_KEY + testId, ackMode, false, ExchangeNameDefaults.TOPIC, true, false, null);
+ SetUpEndPoint(2, false, true, TEST_ROUTING_KEY + testId, ackMode, false, ExchangeNameDefaults.TOPIC, true,
+ true, "TestSubscription" + testId);
+
+ Thread.Sleep(500);
+
+ // Send messages and receive on both consumers.
+ testProducer[0].Send(testChannel[0].CreateTextMessage("A"));
+
+ ConsumeNMessagesOnly(1, "A", testConsumer[1]);
+ ConsumeNMessagesOnly(1, "A", testConsumer[2]);
+
+ // Detach one consumer.
+ CloseEndPoint(2);
+
+ // Send message and receive on one consumer.
+ testProducer[0].Send(testChannel[0].CreateTextMessage("B"));
+
+ ConsumeNMessagesOnly(1, "B", testConsumer[1]);
+
+ // Re-attach consumer, check that it gets the messages that it missed.
+ SetUpEndPoint(2, false, true, TEST_ROUTING_KEY + testId, ackMode, false, ExchangeNameDefaults.TOPIC, true,
+ true, "TestSubscription" + testId);
+
+ ConsumeNMessagesOnly(1, "B", testConsumer[2]);
+
+ // Clean up any open consumers at the end of the test.
+ CloseEndPoint(2);
+ CloseEndPoint(1);
+ CloseEndPoint(0);
+ }
+
+ /// <summary> Check that an uncommitted receive can be re-received, on re-consume from the same durable subscription. </summary>
+ [Test]
+ public void TestUncommittedReceiveCanBeRereceivedNewConnection()
+ {
+ SetUpEndPoint(0, true, false, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, true, ExchangeNameDefaults.TOPIC,
+ true, false, null);
+ SetUpEndPoint(1, false, true, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, true, ExchangeNameDefaults.TOPIC,
+ true, true, "foo"+testId);
+
+ // Send messages.
+ testProducer[0].Send(testChannel[0].CreateTextMessage("C"));
+ testChannel[0].Commit();
+
+ // Try to receive messages, but don't commit them.
+ ConsumeNMessagesOnly(1, "C", testConsumer[1]);
+
+ // Close end-point 1 without committing the message, then re-open the subscription to consume again.
+ CloseEndPoint(1);
+ SetUpEndPoint(1, false, true, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, true, ExchangeNameDefaults.TOPIC,
+ true, true, "foo"+testId);
+
+ // Check that the message was released from the rolled back end-point an can be received on the alternative one instead.
+ ConsumeNMessagesOnly(1, "C", testConsumer[1]);
+ testChannel[1].Commit();
+ CloseEndPoint(1);
+ CloseEndPoint(0);
+ }
+
+ /// <summary> Check that a rolled back receive can be re-received, on re-consume from the same durable subscription. </summary>
+ [Test]
+ public void TestRolledBackReceiveCanBeRereceivedNewConnection()
+ {
+ SetUpEndPoint(0, true, false, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, true, ExchangeNameDefaults.TOPIC,
+ true, false, null);
+ SetUpEndPoint(1, false, true, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, true, ExchangeNameDefaults.TOPIC,
+ true, true, "foo"+testId);
+
+ // Send messages.
+ testProducer[0].Send(testChannel[0].CreateTextMessage("D"));
+ testChannel[0].Commit();
+
+ // Try to receive messages, but roll them back.
+ ConsumeNMessagesOnly(1, "D", testConsumer[1]);
+ testChannel[1].Rollback();
+
+ // Close end-point 1 without committing the message, then re-open the subscription to consume again.
+ CloseEndPoint(1);
+ SetUpEndPoint(1, false, true, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, true, ExchangeNameDefaults.TOPIC,
+ true, true, "foo"+testId);
+
+ // Check that the message was released from the rolled back end-point an can be received on the alternative one instead.
+ ConsumeNMessagesOnly(1, "D", testConsumer[1]);
+ testChannel[1].Commit();
+ CloseEndPoint(1);
+ CloseEndPoint(0);
+ }
+ }
+}
diff --git a/dotnet/Qpid.Integration.Tests/testcases/HeadersExchangeTest.cs b/dotnet/Qpid.Integration.Tests/testcases/HeadersExchangeTest.cs
index 5e17cf1d2d..2094aa3b1b 100644
--- a/dotnet/Qpid.Integration.Tests/testcases/HeadersExchangeTest.cs
+++ b/dotnet/Qpid.Integration.Tests/testcases/HeadersExchangeTest.cs
@@ -1,282 +1,282 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Threading;
-using log4net;
-using NUnit.Framework;
-using Apache.Qpid.Framing;
-using Apache.Qpid.Messaging;
-using Apache.Qpid.Client.Qms;
-using Apache.Qpid.Client;
-
-namespace Apache.Qpid.Integration.Tests.testcases
-{
- /// <summary>
- /// Sets up a producer/consumer pair to send test messages through a header exchange. The header exchange matching pattern is tested to
- /// verify that it correctly matches or filters out messages based on their headers.
- ///
- /// Check that a message matching all fields of a headers exchange is passed by the exchange.
- /// Check that a message containing values for empty fields of a headers exchange is passed by the exchange.
- /// Check that a message matching only some fields of a headers exhcnage is not passed by the exchange.
- /// Check that a message with additional fields to the correct matching fields of a headers exchange is passed by the exchange.
- /// </summary>
- ///
- /// <todo>Remove the HeadersMatchingProducer class and rename this to HeaderExchangeTest. The producer and consumer are implemented
- /// in a single test class to make running this as part of an automated test suite possible.</todo>
- ///
- /// <todo>Consider not using a delegate to callback the OnMessage method. Easier to just call receive on the consumer but using the
- /// callback does demonstrate how to do so.</todo>
- [TestFixture, Category("Integration")]
- public class HeadersExchangeTest : BaseMessagingTestFixture
- {
- private static ILog _logger = LogManager.GetLogger(typeof(HeadersExchangeTest));
-
- /// <summary> Holds the default test timeout for broker communications before tests give up. </summary>
- private static readonly int TIMEOUT = 2000;
-
- /// <summary> Holds the name of the headers exchange to create to send test messages on. </summary>
- private string _exchangeName = "ServiceQ1";
-
- /// <summary> Used to preserve the most recent exception in case test cases need to examine it. </summary>
- private Exception _lastException = null;
-
- /// <summary> Used to preserve the most recent message from the test consumer. </summary>
- private IMessage _lastMessage = null;
-
- /// <summary> The test consumer to get messages from the broker with. </summary>
- private IMessageConsumer _consumer;
-
- private IMessagePublisher _publisher;
-
- private AutoResetEvent _evt = new AutoResetEvent(false);
-
- private MessageReceivedDelegate _msgRecDelegate;
- private ExceptionListenerDelegate _exceptionDelegate;
-
- /// <summary> Holds the test connection. </summary>
- protected IConnection _connection;
-
- /// <summary> Holds the test channel. </summary>
- protected IChannel _channel;
-
- [SetUp]
- public override void Init()
- {
- // Ensure that the base init method is called. It establishes a connection with the broker.
- base.Init();
-
- connectionInfo = QpidConnectionInfo.FromUrl(connectionUri);
- _connection = new AMQConnection(connectionInfo);
- _channel = _connection.CreateChannel(false, AcknowledgeMode.AutoAcknowledge, 500, 300);
-
- _logger.Info("Starting...");
- _logger.Info("Exchange name is '" + _exchangeName + "'...");
-
- // Register this to listen for exceptions on the test connection.
- _exceptionDelegate = new ExceptionListenerDelegate(OnException);
- _connection.ExceptionListener += _exceptionDelegate;
-
- // Declare a new headers exchange with the name of the test service.
- _channel.DeclareExchange(_exchangeName, ExchangeClassConstants.HEADERS);
-
- // Create a non-durable, temporary (aka auto-delete), exclusive queue.
- string queueName = _channel.GenerateUniqueName();
- _channel.DeclareQueue(queueName, false, true, true);
-
- // Bind the queue to the new headers exchange, setting up some header patterns for the exchange to match.
- _channel.Bind(queueName, _exchangeName, null, CreatePatternAsFieldTable());
-
- // Create a test consumer to consume messages from the test exchange.
- _consumer = _channel.CreateConsumerBuilder(queueName)
- .WithPrefetchLow(100)
- .WithPrefetchHigh(500)
- .WithNoLocal(false) // make sure we get our own messages
- .Create();
-
- // Register this to listen for messages on the consumer.
- _msgRecDelegate = new MessageReceivedDelegate(OnMessage);
- _consumer.OnMessage += _msgRecDelegate;
-
- // Clear the most recent message and exception.
- _lastException = null;
- _lastMessage = null;
-
- _publisher = _channel.CreatePublisherBuilder()
- .WithExchangeName(_exchangeName)
- .WithMandatory(true)
- .Create();
-
- _publisher.DeliveryMode = DeliveryMode.NonPersistent;
-
- // Start all channel
- _connection.Start();
- }
-
- /// <summary>
- /// Deregisters the on message delegate before closing the connection.
- /// </summary>
- [TearDown]
- public override void Shutdown()
- {
- _logger.Info("public void Shutdown(): called");
-
- //_consumer.OnMessage -= _msgRecDelegate;
- //_connection.ExceptionListener -= _exceptionDelegate;
-
- _connection.Stop();
- _connection.Close();
- _connection.Dispose();
-
- base.Shutdown();
- }
-
- /// <summary>
- /// Callback method that is passed any messages received on the test channel.
- /// </summary>
- ///
- /// <param name="message">The received message.</param>
- public void OnMessage(IMessage message)
- {
- _logger.Debug(string.Format("message.Type = {0}", message.GetType()));
- _logger.Debug("Got message '" + message + "'");
-
- // Preserve the most recent exception so that test cases can examine it.
- _lastMessage = message;
-
- // Notify any waiting threads that a message has been received.
- _evt.Set();
- }
-
- /// <summary>Callback method to handle any exceptions raised by the test connection.</summary>
- ///
- /// <param name="e">The connection exception.</param>
- public void OnException(Exception e)
- {
- // Preserve the most recent exception in case test cases need to examine it.
- _lastException = e;
-
- // Notify any waiting threads that an exception event has occurred.
- _evt.Set();
- }
-
- /// <summary>Check that a message matching all fields of a headers exchange is passed by the exchange.</summary>
- [Test]
- public void TestMatchAll()
- {
- IMessage msg = _channel.CreateTextMessage("matches match2=''");
- msg.Headers["match1"] = "foo";
- msg.Headers["match2"] = "";
-
- // Use the SendTestMessage helper method to verify that the message was sent and received.
- SendTestMessage(msg, true);
- }
-
- /// <summary>Check that a message containing values for empty fields of a headers exchange is passed by the exchange.</summary>
- [Test]
- public void TestMatchEmptyMatchesAnything()
- {
- // Send a test message that matches the headers exchange.
- IMessage msg = _channel.CreateTextMessage("matches match1='foo' and match2='bar'");
- msg.Headers["match1"] = "foo";
- msg.Headers["match2"] = "bar";
-
- // Use the SendTestMessage helper method to verify that the message was sent and received.
- SendTestMessage(msg, true);
- }
-
- /// <summary>Check that a message matching only some fields of a headers exchange is not passed by the exchange.</summary>
- [Test]
- public void TestMatchOneFails()
- {
- IMessage msg = _channel.CreateTextMessage("not match - only match1");
- msg.Headers["match1"] = "foo";
-
- // Use the SendTestMessage helper method to verify that the message was sent and not received.
- SendTestMessage(msg, false);
- }
-
- /// <summary>
- /// Check that a message with additional fields to the correct matching fields of a headers exchange is passed by
- /// the exchange.
- /// </summary>
- [Test]
- public void TestMatchExtraFields()
- {
- IMessage msg = _channel.CreateTextMessage("matches - extra headers");
- msg.Headers["match1"] = "foo";
- msg.Headers["match2"] = "bar";
- msg.Headers["match3"] = "not required";
-
- // Use the SendTestMessage helper method to verify that the message was sent and received.
- SendTestMessage(msg, true);
- }
-
- /// <summary>
- /// Sends the specified message to the test publisher, and confirms that it was received by the test consumer or not
- /// depending on whether or not the message should be received by the consumer.
- ///
- /// Any exceptions raised by the connection will cause an Assert failure exception to be raised.
- /// </summary>
- ///
- /// <param name="msgSend">The message to send.</param>
- /// <param name="shouldPass">A flag to indicate whether or not the message should be received by the consumer.</param>
- private void SendTestMessage(IMessage msgSend, bool shouldPass)
- {
- _publisher.Send(msgSend);
- _evt.WaitOne(TIMEOUT, true);
-
- // Check that an exception other than not routable was raised in which case re-raise it as a test error.
- if (_lastException != null && !(_lastException.InnerException is AMQUndeliveredException))
- {
- Assert.Fail("Exception {0} was raised by the broker connection.", _lastException);
- }
- // Check that a message was returned if the test is expecting the message to pass.
- else if (shouldPass)
- {
- Assert.IsNotNull(_lastMessage, "Did not get a matching message from the headers exchange.");
- }
- // Check that a not routable exception was raised if the test is expecting the message to fail.
- else if (_lastException != null && _lastException.InnerException is AMQUndeliveredException)
- {
- Assert.IsNull(_lastMessage, "Message could not be routed so consumer should not have received it.");
- }
- // The broker did not respond within the test timeout so fail the test.
- else
- {
- Assert.Fail("The test timed out without a response from the broker.");
- }
- }
-
- /// <summary> Returns a field table containing patterns to match the test header exchange against. </summary>
- ///
- /// <returns> A field table containing test patterns. </returns>
- private FieldTable CreatePatternAsFieldTable()
- {
- FieldTable matchTable = new FieldTable();
-
- matchTable["match1"] = "foo";
- matchTable["match2"] = "";
- matchTable["x-match"] = "all";
-
- return matchTable;
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Threading;
+using log4net;
+using NUnit.Framework;
+using Apache.Qpid.Framing;
+using Apache.Qpid.Messaging;
+using Apache.Qpid.Client.Qms;
+using Apache.Qpid.Client;
+
+namespace Apache.Qpid.Integration.Tests.testcases
+{
+ /// <summary>
+ /// Sets up a producer/consumer pair to send test messages through a header exchange. The header exchange matching pattern is tested to
+ /// verify that it correctly matches or filters out messages based on their headers.
+ ///
+ /// Check that a message matching all fields of a headers exchange is passed by the exchange.
+ /// Check that a message containing values for empty fields of a headers exchange is passed by the exchange.
+ /// Check that a message matching only some fields of a headers exhcnage is not passed by the exchange.
+ /// Check that a message with additional fields to the correct matching fields of a headers exchange is passed by the exchange.
+ /// </summary>
+ ///
+ /// <todo>Remove the HeadersMatchingProducer class and rename this to HeaderExchangeTest. The producer and consumer are implemented
+ /// in a single test class to make running this as part of an automated test suite possible.</todo>
+ ///
+ /// <todo>Consider not using a delegate to callback the OnMessage method. Easier to just call receive on the consumer but using the
+ /// callback does demonstrate how to do so.</todo>
+ [TestFixture, Category("Integration")]
+ public class HeadersExchangeTest : BaseMessagingTestFixture
+ {
+ private static ILog _logger = LogManager.GetLogger(typeof(HeadersExchangeTest));
+
+ /// <summary> Holds the default test timeout for broker communications before tests give up. </summary>
+ private static readonly int TIMEOUT = 2000;
+
+ /// <summary> Holds the name of the headers exchange to create to send test messages on. </summary>
+ private string _exchangeName = "ServiceQ1";
+
+ /// <summary> Used to preserve the most recent exception in case test cases need to examine it. </summary>
+ private Exception _lastException = null;
+
+ /// <summary> Used to preserve the most recent message from the test consumer. </summary>
+ private IMessage _lastMessage = null;
+
+ /// <summary> The test consumer to get messages from the broker with. </summary>
+ private IMessageConsumer _consumer;
+
+ private IMessagePublisher _publisher;
+
+ private AutoResetEvent _evt = new AutoResetEvent(false);
+
+ private MessageReceivedDelegate _msgRecDelegate;
+ private ExceptionListenerDelegate _exceptionDelegate;
+
+ /// <summary> Holds the test connection. </summary>
+ protected IConnection _connection;
+
+ /// <summary> Holds the test channel. </summary>
+ protected IChannel _channel;
+
+ [SetUp]
+ public override void Init()
+ {
+ // Ensure that the base init method is called. It establishes a connection with the broker.
+ base.Init();
+
+ connectionInfo = QpidConnectionInfo.FromUrl(connectionUri);
+ _connection = new AMQConnection(connectionInfo);
+ _channel = _connection.CreateChannel(false, AcknowledgeMode.AutoAcknowledge, 500, 300);
+
+ _logger.Info("Starting...");
+ _logger.Info("Exchange name is '" + _exchangeName + "'...");
+
+ // Register this to listen for exceptions on the test connection.
+ _exceptionDelegate = new ExceptionListenerDelegate(OnException);
+ _connection.ExceptionListener += _exceptionDelegate;
+
+ // Declare a new headers exchange with the name of the test service.
+ _channel.DeclareExchange(_exchangeName, ExchangeClassConstants.HEADERS);
+
+ // Create a non-durable, temporary (aka auto-delete), exclusive queue.
+ string queueName = _channel.GenerateUniqueName();
+ _channel.DeclareQueue(queueName, false, true, true);
+
+ // Bind the queue to the new headers exchange, setting up some header patterns for the exchange to match.
+ _channel.Bind(queueName, _exchangeName, null, CreatePatternAsFieldTable());
+
+ // Create a test consumer to consume messages from the test exchange.
+ _consumer = _channel.CreateConsumerBuilder(queueName)
+ .WithPrefetchLow(100)
+ .WithPrefetchHigh(500)
+ .WithNoLocal(false) // make sure we get our own messages
+ .Create();
+
+ // Register this to listen for messages on the consumer.
+ _msgRecDelegate = new MessageReceivedDelegate(OnMessage);
+ _consumer.OnMessage += _msgRecDelegate;
+
+ // Clear the most recent message and exception.
+ _lastException = null;
+ _lastMessage = null;
+
+ _publisher = _channel.CreatePublisherBuilder()
+ .WithExchangeName(_exchangeName)
+ .WithMandatory(true)
+ .Create();
+
+ _publisher.DeliveryMode = DeliveryMode.NonPersistent;
+
+ // Start all channel
+ _connection.Start();
+ }
+
+ /// <summary>
+ /// Deregisters the on message delegate before closing the connection.
+ /// </summary>
+ [TearDown]
+ public override void Shutdown()
+ {
+ _logger.Info("public void Shutdown(): called");
+
+ //_consumer.OnMessage -= _msgRecDelegate;
+ //_connection.ExceptionListener -= _exceptionDelegate;
+
+ _connection.Stop();
+ _connection.Close();
+ _connection.Dispose();
+
+ base.Shutdown();
+ }
+
+ /// <summary>
+ /// Callback method that is passed any messages received on the test channel.
+ /// </summary>
+ ///
+ /// <param name="message">The received message.</param>
+ public void OnMessage(IMessage message)
+ {
+ _logger.Debug(string.Format("message.Type = {0}", message.GetType()));
+ _logger.Debug("Got message '" + message + "'");
+
+ // Preserve the most recent exception so that test cases can examine it.
+ _lastMessage = message;
+
+ // Notify any waiting threads that a message has been received.
+ _evt.Set();
+ }
+
+ /// <summary>Callback method to handle any exceptions raised by the test connection.</summary>
+ ///
+ /// <param name="e">The connection exception.</param>
+ public void OnException(Exception e)
+ {
+ // Preserve the most recent exception in case test cases need to examine it.
+ _lastException = e;
+
+ // Notify any waiting threads that an exception event has occurred.
+ _evt.Set();
+ }
+
+ /// <summary>Check that a message matching all fields of a headers exchange is passed by the exchange.</summary>
+ [Test]
+ public void TestMatchAll()
+ {
+ IMessage msg = _channel.CreateTextMessage("matches match2=''");
+ msg.Headers["match1"] = "foo";
+ msg.Headers["match2"] = "";
+
+ // Use the SendTestMessage helper method to verify that the message was sent and received.
+ SendTestMessage(msg, true);
+ }
+
+ /// <summary>Check that a message containing values for empty fields of a headers exchange is passed by the exchange.</summary>
+ [Test]
+ public void TestMatchEmptyMatchesAnything()
+ {
+ // Send a test message that matches the headers exchange.
+ IMessage msg = _channel.CreateTextMessage("matches match1='foo' and match2='bar'");
+ msg.Headers["match1"] = "foo";
+ msg.Headers["match2"] = "bar";
+
+ // Use the SendTestMessage helper method to verify that the message was sent and received.
+ SendTestMessage(msg, true);
+ }
+
+ /// <summary>Check that a message matching only some fields of a headers exchange is not passed by the exchange.</summary>
+ [Test]
+ public void TestMatchOneFails()
+ {
+ IMessage msg = _channel.CreateTextMessage("not match - only match1");
+ msg.Headers["match1"] = "foo";
+
+ // Use the SendTestMessage helper method to verify that the message was sent and not received.
+ SendTestMessage(msg, false);
+ }
+
+ /// <summary>
+ /// Check that a message with additional fields to the correct matching fields of a headers exchange is passed by
+ /// the exchange.
+ /// </summary>
+ [Test]
+ public void TestMatchExtraFields()
+ {
+ IMessage msg = _channel.CreateTextMessage("matches - extra headers");
+ msg.Headers["match1"] = "foo";
+ msg.Headers["match2"] = "bar";
+ msg.Headers["match3"] = "not required";
+
+ // Use the SendTestMessage helper method to verify that the message was sent and received.
+ SendTestMessage(msg, true);
+ }
+
+ /// <summary>
+ /// Sends the specified message to the test publisher, and confirms that it was received by the test consumer or not
+ /// depending on whether or not the message should be received by the consumer.
+ ///
+ /// Any exceptions raised by the connection will cause an Assert failure exception to be raised.
+ /// </summary>
+ ///
+ /// <param name="msgSend">The message to send.</param>
+ /// <param name="shouldPass">A flag to indicate whether or not the message should be received by the consumer.</param>
+ private void SendTestMessage(IMessage msgSend, bool shouldPass)
+ {
+ _publisher.Send(msgSend);
+ _evt.WaitOne(TIMEOUT, true);
+
+ // Check that an exception other than not routable was raised in which case re-raise it as a test error.
+ if (_lastException != null && !(_lastException.InnerException is AMQUndeliveredException))
+ {
+ Assert.Fail("Exception {0} was raised by the broker connection.", _lastException);
+ }
+ // Check that a message was returned if the test is expecting the message to pass.
+ else if (shouldPass)
+ {
+ Assert.IsNotNull(_lastMessage, "Did not get a matching message from the headers exchange.");
+ }
+ // Check that a not routable exception was raised if the test is expecting the message to fail.
+ else if (_lastException != null && _lastException.InnerException is AMQUndeliveredException)
+ {
+ Assert.IsNull(_lastMessage, "Message could not be routed so consumer should not have received it.");
+ }
+ // The broker did not respond within the test timeout so fail the test.
+ else
+ {
+ Assert.Fail("The test timed out without a response from the broker.");
+ }
+ }
+
+ /// <summary> Returns a field table containing patterns to match the test header exchange against. </summary>
+ ///
+ /// <returns> A field table containing test patterns. </returns>
+ private FieldTable CreatePatternAsFieldTable()
+ {
+ FieldTable matchTable = new FieldTable();
+
+ matchTable["match1"] = "foo";
+ matchTable["match2"] = "";
+ matchTable["x-match"] = "all";
+
+ return matchTable;
+ }
+ }
+}
diff --git a/dotnet/Qpid.Integration.Tests/testcases/MandatoryMessageTest.cs b/dotnet/Qpid.Integration.Tests/testcases/MandatoryMessageTest.cs
index 6cfdad1f94..4abc56905f 100644
--- a/dotnet/Qpid.Integration.Tests/testcases/MandatoryMessageTest.cs
+++ b/dotnet/Qpid.Integration.Tests/testcases/MandatoryMessageTest.cs
@@ -1,149 +1,149 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Threading;
-using log4net;
-using NUnit.Framework;
-using Apache.Qpid.Messaging;
-using Apache.Qpid.Client.Qms;
-using Apache.Qpid.Client;
-
-namespace Apache.Qpid.Integration.Tests.testcases
-{
- /// <summary>
- /// MandatoryMessageTest checks that messages sent with the 'mandatory' flag, must either be routed to a valid
- /// queue or returned to the sender when no route is available.
- ///
- /// <p><table id="crc"><caption>CRC Card</caption>
- /// <tr><th> Responsibilities <th> Collaborations
- /// <tr><td> Check default exchange returns unroutable mandatory messages.
- /// <tr><td> Check direct exchange returns unroutable mandatory messages.
- /// <tr><td> Check headers exchange returns unroutable mandatory messages.
- /// <tr><td> Check topic exchange returns unroutable mandatory messages.
- /// </table>
- /// </summary>
- [TestFixture, Category("Integration")]
- public class MandatoryMessageTest : BaseMessagingTestFixture
- {
- /// <summary>Used for debugging purposes.</summary>
- private static ILog log = LogManager.GetLogger(typeof(MandatoryMessageTest));
-
- /// <summary>Defines the maximum time in milliseconds, to wait for redelivery to occurr.</summary>
- public const int TIMEOUT = 1000;
-
- /// <summary>Defines the name of the routing key to use with the tests.</summary>
- public const string TEST_ROUTING_KEY = "unboundkey";
-
- /// <summary>Condition used to coordinate receipt of redelivery exception to the sending thread.</summary>
- private ManualResetEvent errorEvent;
-
- /// <summary>Holds the last received error condition, for examination by the tests sending thread.</summary>
- private Exception lastErrorException;
-
- /// <summary> Holds the test connection. </summary>
- protected IConnection _connection;
-
- /// <summary> Holds the test channel. </summary>
- protected IChannel _channel;
-
- [SetUp]
- public override void Init()
- {
- base.Init();
-
- errorEvent = new ManualResetEvent(false);
- lastErrorException = null;
- }
-
- [TearDown]
- public override void Shutdown()
- {
- base.Shutdown();
- }
-
- /// <summary>
- /// Handles all exception conditions on the connection. The error event is notified and the exception recorded as the last seen.
- /// </summary>
- ///
- /// <param name="e">The asynchronous exception on the connection.</param>
- public void OnException(Exception e)
- {
- lastErrorException = e;
- errorEvent.Set();
- }
-
- [Test]
- public void SendUndeliverableMessageOnDirectExchange()
- {
- SendOne(ExchangeNameDefaults.DIRECT);
- }
-
- [Test]
- public void SendUndeliverableMessageOnTopicExchange()
- {
- SendOne(ExchangeNameDefaults.TOPIC);
- }
-
- [Test]
- public void SendUndeliverableMessageOnHeadersExchange()
- {
- SendOne(ExchangeNameDefaults.HEADERS);
- }
-
- /// <summary>
- /// Sends a single message to the specified exchange with the routing key 'unboundkey', marked as mandatory.
- /// A check is performed to assert that a redelivery error is returned from the broker for the message.
- /// </summary>
- ///
- /// <param name="exchangeName">The name of the exchange to send to.</param>
- private void SendOne(string exchangeName)
- {
- log.Debug("private void SendOne(string exchangeName = " + exchangeName + "): called");
-
- // Send a test message to a unbound key on the specified exchange.
- SetUpEndPoint(0, false, false, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, false, exchangeName,
- true, false, null);
- testProducer[0] = testChannel[0].CreatePublisherBuilder()
- .WithRoutingKey(TEST_ROUTING_KEY + testId)
- .WithMandatory(true)
- .WithExchangeName(exchangeName)
- .Create();
-
- // Set up the exception listener on the connection.
- testConnection[0].ExceptionListener = new ExceptionListenerDelegate(OnException);
-
- // Send message that should fail.
- testProducer[0].Send(testChannel[0].CreateTextMessage("Test Message"));
-
- // Wait for up to the timeout for a redelivery exception to be returned.
- errorEvent.WaitOne(TIMEOUT, true);
-
- // Asserts that a redelivery exception was returned, and is of the correct type.
- Type expectedException = typeof(AMQUndeliveredException);
- Exception ex = lastErrorException;
-
- Assert.IsNotNull(ex, "No exception was thrown by the test. Expected " + expectedException);
- Assert.IsInstanceOfType(expectedException, ex.InnerException);
-
- CloseEndPoint(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.
+ *
+ */
+using System;
+using System.Threading;
+using log4net;
+using NUnit.Framework;
+using Apache.Qpid.Messaging;
+using Apache.Qpid.Client.Qms;
+using Apache.Qpid.Client;
+
+namespace Apache.Qpid.Integration.Tests.testcases
+{
+ /// <summary>
+ /// MandatoryMessageTest checks that messages sent with the 'mandatory' flag, must either be routed to a valid
+ /// queue or returned to the sender when no route is available.
+ ///
+ /// <p><table id="crc"><caption>CRC Card</caption>
+ /// <tr><th> Responsibilities <th> Collaborations
+ /// <tr><td> Check default exchange returns unroutable mandatory messages.
+ /// <tr><td> Check direct exchange returns unroutable mandatory messages.
+ /// <tr><td> Check headers exchange returns unroutable mandatory messages.
+ /// <tr><td> Check topic exchange returns unroutable mandatory messages.
+ /// </table>
+ /// </summary>
+ [TestFixture, Category("Integration")]
+ public class MandatoryMessageTest : BaseMessagingTestFixture
+ {
+ /// <summary>Used for debugging purposes.</summary>
+ private static ILog log = LogManager.GetLogger(typeof(MandatoryMessageTest));
+
+ /// <summary>Defines the maximum time in milliseconds, to wait for redelivery to occurr.</summary>
+ public const int TIMEOUT = 1000;
+
+ /// <summary>Defines the name of the routing key to use with the tests.</summary>
+ public const string TEST_ROUTING_KEY = "unboundkey";
+
+ /// <summary>Condition used to coordinate receipt of redelivery exception to the sending thread.</summary>
+ private ManualResetEvent errorEvent;
+
+ /// <summary>Holds the last received error condition, for examination by the tests sending thread.</summary>
+ private Exception lastErrorException;
+
+ /// <summary> Holds the test connection. </summary>
+ protected IConnection _connection;
+
+ /// <summary> Holds the test channel. </summary>
+ protected IChannel _channel;
+
+ [SetUp]
+ public override void Init()
+ {
+ base.Init();
+
+ errorEvent = new ManualResetEvent(false);
+ lastErrorException = null;
+ }
+
+ [TearDown]
+ public override void Shutdown()
+ {
+ base.Shutdown();
+ }
+
+ /// <summary>
+ /// Handles all exception conditions on the connection. The error event is notified and the exception recorded as the last seen.
+ /// </summary>
+ ///
+ /// <param name="e">The asynchronous exception on the connection.</param>
+ public void OnException(Exception e)
+ {
+ lastErrorException = e;
+ errorEvent.Set();
+ }
+
+ [Test]
+ public void SendUndeliverableMessageOnDirectExchange()
+ {
+ SendOne(ExchangeNameDefaults.DIRECT);
+ }
+
+ [Test]
+ public void SendUndeliverableMessageOnTopicExchange()
+ {
+ SendOne(ExchangeNameDefaults.TOPIC);
+ }
+
+ [Test]
+ public void SendUndeliverableMessageOnHeadersExchange()
+ {
+ SendOne(ExchangeNameDefaults.HEADERS);
+ }
+
+ /// <summary>
+ /// Sends a single message to the specified exchange with the routing key 'unboundkey', marked as mandatory.
+ /// A check is performed to assert that a redelivery error is returned from the broker for the message.
+ /// </summary>
+ ///
+ /// <param name="exchangeName">The name of the exchange to send to.</param>
+ private void SendOne(string exchangeName)
+ {
+ log.Debug("private void SendOne(string exchangeName = " + exchangeName + "): called");
+
+ // Send a test message to a unbound key on the specified exchange.
+ SetUpEndPoint(0, false, false, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, false, exchangeName,
+ true, false, null);
+ testProducer[0] = testChannel[0].CreatePublisherBuilder()
+ .WithRoutingKey(TEST_ROUTING_KEY + testId)
+ .WithMandatory(true)
+ .WithExchangeName(exchangeName)
+ .Create();
+
+ // Set up the exception listener on the connection.
+ testConnection[0].ExceptionListener = new ExceptionListenerDelegate(OnException);
+
+ // Send message that should fail.
+ testProducer[0].Send(testChannel[0].CreateTextMessage("Test Message"));
+
+ // Wait for up to the timeout for a redelivery exception to be returned.
+ errorEvent.WaitOne(TIMEOUT, true);
+
+ // Asserts that a redelivery exception was returned, and is of the correct type.
+ Type expectedException = typeof(AMQUndeliveredException);
+ Exception ex = lastErrorException;
+
+ Assert.IsNotNull(ex, "No exception was thrown by the test. Expected " + expectedException);
+ Assert.IsInstanceOfType(expectedException, ex.InnerException);
+
+ CloseEndPoint(0);
+ }
+ }
+}
diff --git a/dotnet/Qpid.Integration.Tests/testcases/ProducerMultiConsumerTest.cs b/dotnet/Qpid.Integration.Tests/testcases/ProducerMultiConsumerTest.cs
index 876e7c7bf7..bae6c76818 100644
--- a/dotnet/Qpid.Integration.Tests/testcases/ProducerMultiConsumerTest.cs
+++ b/dotnet/Qpid.Integration.Tests/testcases/ProducerMultiConsumerTest.cs
@@ -1,167 +1,167 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.Text;
-using System.Threading;
-using log4net;
-using NUnit.Framework;
-using Apache.Qpid.Messaging;
-using Apache.Qpid.Client.Qms;
-using Apache.Qpid.Client;
-
-namespace Apache.Qpid.Integration.Tests.testcases
-{
- /// ProducerMultiConsumerTest provides some tests for one producer and multiple consumers.
- ///
- /// <p><table id="crc"><caption>CRC Card</caption>
- /// <tr><th> Responsibilities <th> Collaborations
- /// <tr><td> Check that all consumers on a topic each receive all message on it.
- /// <tr><td> Check that consumers on the same queue receive each message once accross all consumers.
- /// </table>
- /// </summary>
- [TestFixture, Category("Integration")]
- public class ProducerMultiConsumerTest : BaseMessagingTestFixture
- {
- private static readonly ILog _logger = LogManager.GetLogger(typeof(ProducerMultiConsumerTest));
-
- /// <summary>Base name for the routing key used for this test (made unique by adding in test id).</summary>
- private const string TEST_ROUTING_KEY = "ProducerMultiConsumerTest";
-
- /// <summary>The number of consumers to test.</summary>
- private const int CONSUMER_COUNT = 5;
-
- /// <summary>The number of test messages to send.</summary>
- private const int MESSAGE_COUNT = 10;
-
- /// <summary>Monitor used to signal succesfull receipt of all test messages.</summary>
- AutoResetEvent _finishedEvent;
-
- /// <summary>Used to count test messages received so far.</summary>
- private int _messageReceivedCount;
-
- /// <summary>Used to hold the expected number of messages to receive.</summary>
- private int expectedMessageCount;
-
- /// <summary>Flag used to indicate that all messages really were received, and that the test did not just time out. </summary>
- private bool allReceived;
-
- /// <summary> Creates one producing end-point and many consuming end-points connected on a topic. </summary>
- [SetUp]
- public override void Init()
- {
- base.Init();
-
- // Reset all test counts and flags.
- _messageReceivedCount = 0;
- allReceived = false;
- _finishedEvent = new AutoResetEvent(false);
- }
-
- /// <summary> Cleans up all test end-points. </summary>
- [TearDown]
- public override void Shutdown()
- {
- try
- {
- // Close all end points for producer and consumers.
- // Producer is on 0, and consumers on 1 .. n, so loop is from 0 to n inclusive.
- for (int i = 0; i <= CONSUMER_COUNT; i++)
- {
- CloseEndPoint(i);
- }
- }
- finally
- {
- base.Shutdown();
- }
- }
-
- /// <summary> Check that all consumers on a topic each receive all message on it. </summary>
- [Test]
- public void AllConsumerReceiveAllMessagesOnTopic()
- {
- // Create end-points for all the consumers in the test.
- for (int i = 1; i <= CONSUMER_COUNT; i++)
- {
- SetUpEndPoint(i, false, true, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, false, ExchangeNameDefaults.TOPIC,
- true, false, null);
- testConsumer[i].OnMessage += new MessageReceivedDelegate(OnMessage);
- }
-
- // Create an end-point to publish to the test topic.
- SetUpEndPoint(0, true, false, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, false, ExchangeNameDefaults.TOPIC,
- true, false, null);
-
- expectedMessageCount = (MESSAGE_COUNT * CONSUMER_COUNT);
-
- for (int i = 0; i < MESSAGE_COUNT; i++)
- {
- testProducer[0].Send(testChannel[0].CreateTextMessage("A"));
- }
-
- _finishedEvent.WaitOne(new TimeSpan(0, 0, 0, 30), false);
-
- // Check that all messages really were received.
- Assert.IsTrue(allReceived, "All messages were not received, only got " + _messageReceivedCount + " but wanted " + expectedMessageCount);
- }
-
- /// <summary> Check that consumers on the same queue receive each message once accross all consumers. </summary>
- [Test]
- public void AllConsumerReceiveAllMessagesOnDirect()
- {
- // Create end-points for all the consumers in the test.
- for (int i = 1; i <= CONSUMER_COUNT; i++)
- {
- SetUpEndPoint(i, false, true, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, false, ExchangeNameDefaults.DIRECT,
- true, false, null);
- testConsumer[i].OnMessage += new MessageReceivedDelegate(OnMessage);
- }
-
- // Create an end-point to publish to the test topic.
- SetUpEndPoint(0, true, false, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, false, ExchangeNameDefaults.DIRECT,
- true, false, null);
-
- expectedMessageCount = (MESSAGE_COUNT * CONSUMER_COUNT);
-
- for (int i = 0; i < MESSAGE_COUNT; i++)
- {
- testProducer[0].Send(testChannel[0].CreateTextMessage("A"));
- }
-
- _finishedEvent.WaitOne(new TimeSpan(0, 0, 0, 30), false);
-
- // Check that all messages really were received.
- Assert.IsTrue(allReceived, "All messages were not received, only got: " + _messageReceivedCount + " but wanted " + expectedMessageCount);
- }
-
- /// <summary> Atomically increments the message count on every message, and signals once all messages in the test are received. </summary>
- public void OnMessage(IMessage m)
- {
- int newCount = Interlocked.Increment(ref _messageReceivedCount);
-
- if (newCount >= expectedMessageCount)
- {
- allReceived = true;
- _finishedEvent.Set();
- }
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Text;
+using System.Threading;
+using log4net;
+using NUnit.Framework;
+using Apache.Qpid.Messaging;
+using Apache.Qpid.Client.Qms;
+using Apache.Qpid.Client;
+
+namespace Apache.Qpid.Integration.Tests.testcases
+{
+ /// ProducerMultiConsumerTest provides some tests for one producer and multiple consumers.
+ ///
+ /// <p><table id="crc"><caption>CRC Card</caption>
+ /// <tr><th> Responsibilities <th> Collaborations
+ /// <tr><td> Check that all consumers on a topic each receive all message on it.
+ /// <tr><td> Check that consumers on the same queue receive each message once accross all consumers.
+ /// </table>
+ /// </summary>
+ [TestFixture, Category("Integration")]
+ public class ProducerMultiConsumerTest : BaseMessagingTestFixture
+ {
+ private static readonly ILog _logger = LogManager.GetLogger(typeof(ProducerMultiConsumerTest));
+
+ /// <summary>Base name for the routing key used for this test (made unique by adding in test id).</summary>
+ private const string TEST_ROUTING_KEY = "ProducerMultiConsumerTest";
+
+ /// <summary>The number of consumers to test.</summary>
+ private const int CONSUMER_COUNT = 5;
+
+ /// <summary>The number of test messages to send.</summary>
+ private const int MESSAGE_COUNT = 10;
+
+ /// <summary>Monitor used to signal succesfull receipt of all test messages.</summary>
+ AutoResetEvent _finishedEvent;
+
+ /// <summary>Used to count test messages received so far.</summary>
+ private int _messageReceivedCount;
+
+ /// <summary>Used to hold the expected number of messages to receive.</summary>
+ private int expectedMessageCount;
+
+ /// <summary>Flag used to indicate that all messages really were received, and that the test did not just time out. </summary>
+ private bool allReceived;
+
+ /// <summary> Creates one producing end-point and many consuming end-points connected on a topic. </summary>
+ [SetUp]
+ public override void Init()
+ {
+ base.Init();
+
+ // Reset all test counts and flags.
+ _messageReceivedCount = 0;
+ allReceived = false;
+ _finishedEvent = new AutoResetEvent(false);
+ }
+
+ /// <summary> Cleans up all test end-points. </summary>
+ [TearDown]
+ public override void Shutdown()
+ {
+ try
+ {
+ // Close all end points for producer and consumers.
+ // Producer is on 0, and consumers on 1 .. n, so loop is from 0 to n inclusive.
+ for (int i = 0; i <= CONSUMER_COUNT; i++)
+ {
+ CloseEndPoint(i);
+ }
+ }
+ finally
+ {
+ base.Shutdown();
+ }
+ }
+
+ /// <summary> Check that all consumers on a topic each receive all message on it. </summary>
+ [Test]
+ public void AllConsumerReceiveAllMessagesOnTopic()
+ {
+ // Create end-points for all the consumers in the test.
+ for (int i = 1; i <= CONSUMER_COUNT; i++)
+ {
+ SetUpEndPoint(i, false, true, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, false, ExchangeNameDefaults.TOPIC,
+ true, false, null);
+ testConsumer[i].OnMessage += new MessageReceivedDelegate(OnMessage);
+ }
+
+ // Create an end-point to publish to the test topic.
+ SetUpEndPoint(0, true, false, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, false, ExchangeNameDefaults.TOPIC,
+ true, false, null);
+
+ expectedMessageCount = (MESSAGE_COUNT * CONSUMER_COUNT);
+
+ for (int i = 0; i < MESSAGE_COUNT; i++)
+ {
+ testProducer[0].Send(testChannel[0].CreateTextMessage("A"));
+ }
+
+ _finishedEvent.WaitOne(new TimeSpan(0, 0, 0, 30), false);
+
+ // Check that all messages really were received.
+ Assert.IsTrue(allReceived, "All messages were not received, only got " + _messageReceivedCount + " but wanted " + expectedMessageCount);
+ }
+
+ /// <summary> Check that consumers on the same queue receive each message once accross all consumers. </summary>
+ [Test]
+ public void AllConsumerReceiveAllMessagesOnDirect()
+ {
+ // Create end-points for all the consumers in the test.
+ for (int i = 1; i <= CONSUMER_COUNT; i++)
+ {
+ SetUpEndPoint(i, false, true, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, false, ExchangeNameDefaults.DIRECT,
+ true, false, null);
+ testConsumer[i].OnMessage += new MessageReceivedDelegate(OnMessage);
+ }
+
+ // Create an end-point to publish to the test topic.
+ SetUpEndPoint(0, true, false, TEST_ROUTING_KEY + testId, AcknowledgeMode.AutoAcknowledge, false, ExchangeNameDefaults.DIRECT,
+ true, false, null);
+
+ expectedMessageCount = (MESSAGE_COUNT * CONSUMER_COUNT);
+
+ for (int i = 0; i < MESSAGE_COUNT; i++)
+ {
+ testProducer[0].Send(testChannel[0].CreateTextMessage("A"));
+ }
+
+ _finishedEvent.WaitOne(new TimeSpan(0, 0, 0, 30), false);
+
+ // Check that all messages really were received.
+ Assert.IsTrue(allReceived, "All messages were not received, only got: " + _messageReceivedCount + " but wanted " + expectedMessageCount);
+ }
+
+ /// <summary> Atomically increments the message count on every message, and signals once all messages in the test are received. </summary>
+ public void OnMessage(IMessage m)
+ {
+ int newCount = Interlocked.Increment(ref _messageReceivedCount);
+
+ if (newCount >= expectedMessageCount)
+ {
+ allReceived = true;
+ _finishedEvent.Set();
+ }
+ }
+ }
+}
diff --git a/dotnet/Qpid.Integration.Tests/testcases/Qpid.Integration.Tests.csproj b/dotnet/Qpid.Integration.Tests/testcases/Qpid.Integration.Tests.csproj
index 8b27526da4..1df37f6c1b 100755
--- a/dotnet/Qpid.Integration.Tests/testcases/Qpid.Integration.Tests.csproj
+++ b/dotnet/Qpid.Integration.Tests/testcases/Qpid.Integration.Tests.csproj
@@ -1,42 +1,63 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <PropertyGroup>
- <ProjectGuid>{EFEB9E41-B66E-4674-85F7-18FAD056AD67}</ProjectGuid>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <OutputType>Exe</OutputType>
- <RootNamespace>Qpid.Integration.Tests</RootNamespace>
- <AssemblyName>Qpid.Integration.Tests</AssemblyName>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
- <OutputPath>bin\Debug\</OutputPath>
- <DebugSymbols>True</DebugSymbols>
- <DebugType>Full</DebugType>
- <Optimize>False</Optimize>
- <CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
- <OutputPath>bin\Release\</OutputPath>
- <DebugSymbols>False</DebugSymbols>
- <DebugType>None</DebugType>
- <Optimize>True</Optimize>
- <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
- <DefineConstants>TRACE</DefineConstants>
- </PropertyGroup>
- <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
- <ItemGroup>
- <Reference Include="System" />
- <Reference Include="System.Xml" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="BaseMessagingTestFixture.cs" />
- <Compile Include="ChannelQueueTest.cs" />
- <Compile Include="CommitRollbackTest.cs" />
- <Compile Include="ConnectionTest.cs" />
- <Compile Include="DurableSubscriptionTest.cs" />
- <Compile Include="HeadersExchangeTest.cs" />
- <Compile Include="MandatoryMessageTest.cs" />
- <Compile Include="ProducerMultiConsumerTest.cs" />
- <Compile Include="SslConnectionTest.cs" />
- </ItemGroup>
-</Project> \ No newline at end of file
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <ProjectGuid>{EFEB9E41-B66E-4674-85F7-18FAD056AD67}</ProjectGuid>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <OutputType>Exe</OutputType>
+ <RootNamespace>Qpid.Integration.Tests</RootNamespace>
+ <AssemblyName>Qpid.Integration.Tests</AssemblyName>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+ <OutputPath>bin\Debug\</OutputPath>
+ <DebugSymbols>True</DebugSymbols>
+ <DebugType>Full</DebugType>
+ <Optimize>False</Optimize>
+ <CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
+ <OutputPath>bin\Release\</OutputPath>
+ <DebugSymbols>False</DebugSymbols>
+ <DebugType>None</DebugType>
+ <Optimize>True</Optimize>
+ <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
+ <DefineConstants>TRACE</DefineConstants>
+ </PropertyGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="BaseMessagingTestFixture.cs" />
+ <Compile Include="ChannelQueueTest.cs" />
+ <Compile Include="CommitRollbackTest.cs" />
+ <Compile Include="ConnectionTest.cs" />
+ <Compile Include="DurableSubscriptionTest.cs" />
+ <Compile Include="HeadersExchangeTest.cs" />
+ <Compile Include="MandatoryMessageTest.cs" />
+ <Compile Include="ProducerMultiConsumerTest.cs" />
+ <Compile Include="SslConnectionTest.cs" />
+ </ItemGroup>
+</Project>
diff --git a/dotnet/Qpid.Integration.Tests/testcases/SslConnectionTest.cs b/dotnet/Qpid.Integration.Tests/testcases/SslConnectionTest.cs
index 1c104d1451..5f953e1470 100644
--- a/dotnet/Qpid.Integration.Tests/testcases/SslConnectionTest.cs
+++ b/dotnet/Qpid.Integration.Tests/testcases/SslConnectionTest.cs
@@ -1,64 +1,64 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.IO;
-using System.Reflection;
-using System.Security.Cryptography.X509Certificates;
-using NUnit.Framework;
-using Apache.Qpid.Client.Qms;
-using Apache.Qpid.Client;
-using Apache.Qpid.Messaging;
-
-namespace Apache.Qpid.Integration.Tests.testcases
-{
- /// <summary>
- /// Test SSL/TLS connections to the broker
- /// </summary>
- [TestFixture, Category("Integration")]
- public class SslConnectionTest
- {
- /// <summary>
- /// Make a test TLS connection to the broker
- /// without using client-certificates
- /// </summary>
- //[Test]
- public void DoSslConnection()
- {
- // because for tests we don't usually trust the server certificate
- // we need here to tell the client to ignore certificate validation errors
- SslOptions sslConfig = new SslOptions(null, true);
-
- MakeBrokerConnection(sslConfig);
- }
-
- private static void MakeBrokerConnection(SslOptions options)
- {
- IConnectionInfo connectionInfo = new QpidConnectionInfo();
- connectionInfo.VirtualHost = "test";
- connectionInfo.AddBrokerInfo(new AmqBrokerInfo("amqp", "localhost", 8672, options));
-
- using ( IConnection connection = new AMQConnection(connectionInfo) )
- {
- Console.WriteLine("connection = " + connection);
- }
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.IO;
+using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
+using NUnit.Framework;
+using Apache.Qpid.Client.Qms;
+using Apache.Qpid.Client;
+using Apache.Qpid.Messaging;
+
+namespace Apache.Qpid.Integration.Tests.testcases
+{
+ /// <summary>
+ /// Test SSL/TLS connections to the broker
+ /// </summary>
+ [TestFixture, Category("Integration")]
+ public class SslConnectionTest
+ {
+ /// <summary>
+ /// Make a test TLS connection to the broker
+ /// without using client-certificates
+ /// </summary>
+ //[Test]
+ public void DoSslConnection()
+ {
+ // because for tests we don't usually trust the server certificate
+ // we need here to tell the client to ignore certificate validation errors
+ SslOptions sslConfig = new SslOptions(null, true);
+
+ MakeBrokerConnection(sslConfig);
+ }
+
+ private static void MakeBrokerConnection(SslOptions options)
+ {
+ IConnectionInfo connectionInfo = new QpidConnectionInfo();
+ connectionInfo.VirtualHost = "test";
+ connectionInfo.AddBrokerInfo(new AmqBrokerInfo("amqp", "localhost", 8672, options));
+
+ using ( IConnection connection = new AMQConnection(connectionInfo) )
+ {
+ Console.WriteLine("connection = " + connection);
+ }
+ }
+ }
+}
diff --git a/dotnet/Qpid.Integration.Tests/testcases/SustainedTest.cs b/dotnet/Qpid.Integration.Tests/testcases/SustainedTest.cs
index aca3f396d6..4074055eba 100644
--- a/dotnet/Qpid.Integration.Tests/testcases/SustainedTest.cs
+++ b/dotnet/Qpid.Integration.Tests/testcases/SustainedTest.cs
@@ -1,109 +1,109 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-using System.IO;
-using System.Reflection;
-using System.Threading;
-using NUnit.Framework;
-using Apache.Qpid.Client.Qms;
-using Apache.Qpid.Client;
-using Apache.Qpid.Messaging;
-using log4net;
-
-namespace Apache.Qpid.Integration.Tests.testcases
-{
- /// <summary>
- /// Runs through the range of ack modes for each test case, sending and recieving a large number of messages
- /// </summary>
- [TestFixture, Category("Integration")]
- public class SustainedTest : BaseMessagingTestFixture
- {
- /// <summary>The number of test messages to send.</summary>
- private const int MESSAGE_COUNT = 50;//00;
-
- /// <summary>Base name for the routing key used for this test (made unique by adding in test id).</summary>
- private const string TEST_ROUTING_KEY = "MessageOrderTest";
-
- /// <summary>
- /// The logger
- /// </summary>
- private static ILog _logger = LogManager.GetLogger(typeof(SustainedTest));
-
- [Test]
- public void MessageOrderTestAutoAck()
- {
- MessageOrderTest(AcknowledgeMode.AutoAcknowledge);
- }
-
- [Test]
- public void MessageOrderTestNoAck()
- {
- MessageOrderTest(AcknowledgeMode.NoAcknowledge);
- }
-
- public void MessageOrderTest(AcknowledgeMode consumerMode)
- {
-
- // Consumer
- SetUpEndPoint(1, false, true, TEST_ROUTING_KEY, consumerMode, false, ExchangeNameDefaults.DIRECT,
- true, false, null);
-
-
- Console.WriteLine("Starting producer thread");
- Thread prodThread = new Thread(new ThreadStart(SendMessages));
- prodThread.Start();
-
- Thread.Sleep(2000);
- Console.WriteLine("Starting consuming");
- for (int i = 0; i < MESSAGE_COUNT; i++)
- {
- if ((i % 10) == 0)
- {
- Console.WriteLine("Consuming message "+i);
- }
- ConsumeNMessages(1, "Msg"+i, testConsumer[1]);
- }
- prodThread.Join();
- CloseEndPoint(0);
- CloseEndPoint(1);
- }
-
- private static void SendMessages()
- {
- AMQConnection conn = new AMQConnection(QpidConnectionInfo.FromUrl(BaseMessagingTestFixture.connectionUri));
- conn.Start();
- IChannel channel = conn.CreateChannel(false, AcknowledgeMode.AutoAcknowledge);
- IMessagePublisher producer = channel.CreatePublisherBuilder().
- WithExchangeName(ExchangeNameDefaults.DIRECT).
- WithRoutingKey(TEST_ROUTING_KEY).
- Create();
-
- for (int i = 0; i < MESSAGE_COUNT ; i++)
- {
- if ((i % 10) == 0)
- {
- Console.WriteLine("Sending message "+i);
- }
- producer.Send(channel.CreateTextMessage("Msg" + i));
- }
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.IO;
+using System.Reflection;
+using System.Threading;
+using NUnit.Framework;
+using Apache.Qpid.Client.Qms;
+using Apache.Qpid.Client;
+using Apache.Qpid.Messaging;
+using log4net;
+
+namespace Apache.Qpid.Integration.Tests.testcases
+{
+ /// <summary>
+ /// Runs through the range of ack modes for each test case, sending and recieving a large number of messages
+ /// </summary>
+ [TestFixture, Category("Integration")]
+ public class SustainedTest : BaseMessagingTestFixture
+ {
+ /// <summary>The number of test messages to send.</summary>
+ private const int MESSAGE_COUNT = 50;//00;
+
+ /// <summary>Base name for the routing key used for this test (made unique by adding in test id).</summary>
+ private const string TEST_ROUTING_KEY = "MessageOrderTest";
+
+ /// <summary>
+ /// The logger
+ /// </summary>
+ private static ILog _logger = LogManager.GetLogger(typeof(SustainedTest));
+
+ [Test]
+ public void MessageOrderTestAutoAck()
+ {
+ MessageOrderTest(AcknowledgeMode.AutoAcknowledge);
+ }
+
+ [Test]
+ public void MessageOrderTestNoAck()
+ {
+ MessageOrderTest(AcknowledgeMode.NoAcknowledge);
+ }
+
+ public void MessageOrderTest(AcknowledgeMode consumerMode)
+ {
+
+ // Consumer
+ SetUpEndPoint(1, false, true, TEST_ROUTING_KEY, consumerMode, false, ExchangeNameDefaults.DIRECT,
+ true, false, null);
+
+
+ Console.WriteLine("Starting producer thread");
+ Thread prodThread = new Thread(new ThreadStart(SendMessages));
+ prodThread.Start();
+
+ Thread.Sleep(2000);
+ Console.WriteLine("Starting consuming");
+ for (int i = 0; i < MESSAGE_COUNT; i++)
+ {
+ if ((i % 10) == 0)
+ {
+ Console.WriteLine("Consuming message "+i);
+ }
+ ConsumeNMessages(1, "Msg"+i, testConsumer[1]);
+ }
+ prodThread.Join();
+ CloseEndPoint(0);
+ CloseEndPoint(1);
+ }
+
+ private static void SendMessages()
+ {
+ AMQConnection conn = new AMQConnection(QpidConnectionInfo.FromUrl(BaseMessagingTestFixture.connectionUri));
+ conn.Start();
+ IChannel channel = conn.CreateChannel(false, AcknowledgeMode.AutoAcknowledge);
+ IMessagePublisher producer = channel.CreatePublisherBuilder().
+ WithExchangeName(ExchangeNameDefaults.DIRECT).
+ WithRoutingKey(TEST_ROUTING_KEY).
+ Create();
+
+ for (int i = 0; i < MESSAGE_COUNT ; i++)
+ {
+ if ((i % 10) == 0)
+ {
+ Console.WriteLine("Sending message "+i);
+ }
+ producer.Send(channel.CreateTextMessage("Msg" + i));
+ }
+ }
+ }
+}
diff --git a/dotnet/Qpid.Messaging/ICloseable.cs b/dotnet/Qpid.Messaging/ICloseable.cs
index 3c9d66047d..658a5ed5a4 100644
--- a/dotnet/Qpid.Messaging/ICloseable.cs
+++ b/dotnet/Qpid.Messaging/ICloseable.cs
@@ -1,38 +1,38 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-using System;
-
-namespace Apache.Qpid.Messaging
-{
- /// <summary>An ICloseable is a resource that can be explicitly closed. Generally speaking a closed resource can no longer be used, and the
- /// act of closing a resource is usually interpreted as a signal that the closed item can have its resource cleaned up and de-allocated.
- ///
- /// <p/><table id="crc"><caption>CRC Card</caption>
- /// <tr><th> Responsibilities <th> Collaborations
- /// <tr><td> Close (and clean-up) a resource.
- /// </table>
- /// </summary>
- public interface ICloseable
- {
- /// <summary> Close the resource. </summary>
- void Close();
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+
+namespace Apache.Qpid.Messaging
+{
+ /// <summary>An ICloseable is a resource that can be explicitly closed. Generally speaking a closed resource can no longer be used, and the
+ /// act of closing a resource is usually interpreted as a signal that the closed item can have its resource cleaned up and de-allocated.
+ ///
+ /// <p/><table id="crc"><caption>CRC Card</caption>
+ /// <tr><th> Responsibilities <th> Collaborations
+ /// <tr><td> Close (and clean-up) a resource.
+ /// </table>
+ /// </summary>
+ public interface ICloseable
+ {
+ /// <summary> Close the resource. </summary>
+ void Close();
+ }
+}
diff --git a/dotnet/Qpid.Messaging/Properties/AssemblyInfo.cs b/dotnet/Qpid.Messaging/Properties/AssemblyInfo.cs
index ab14b1faf0..d9dff07f3f 100644
--- a/dotnet/Qpid.Messaging/Properties/AssemblyInfo.cs
+++ b/dotnet/Qpid.Messaging/Properties/AssemblyInfo.cs
@@ -50,7 +50,7 @@ using System.Runtime.InteropServices;
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
-[assembly: AssemblyVersion("2.1.0.0")]
+[assembly: AssemblyVersion("0.5.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: CLSCompliant(true)]
diff --git a/dotnet/Qpid.Messaging/Qpid.Messaging.csproj b/dotnet/Qpid.Messaging/Qpid.Messaging.csproj
index 403911ee3f..37b80d1515 100644
--- a/dotnet/Qpid.Messaging/Qpid.Messaging.csproj
+++ b/dotnet/Qpid.Messaging/Qpid.Messaging.csproj
@@ -1,8 +1,29 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProductVersion>8.0.50727</ProductVersion>
+ <ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{6688F826-C58E-4C1B-AA1F-22AFAB4B7D07}</ProjectGuid>
<OutputType>Library</OutputType>
@@ -10,6 +31,26 @@
<RootNamespace>Apache.Qpid.Messaging</RootNamespace>
<AssemblyName>Apache.Qpid.Messaging</AssemblyName>
<SignAssembly>true</SignAssembly>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ <PublishUrl>http://localhost/Apache.Qpid.Messaging/</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Web</InstallFrom>
+ <UpdateEnabled>true</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <IsWebBootstrapper>true</IsWebBootstrapper>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -34,29 +75,34 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
- <Compile Include="AcknowledgeMode.cs" />
- <Compile Include="ChannelLimitReachedException.cs" />
- <Compile Include="DeliveryMode.cs" />
- <Compile Include="ExchangeClassConstants.cs" />
- <Compile Include="ExchangeNameDefaults.cs" />
- <Compile Include="IBytesMessage.cs" />
- <Compile Include="IConnection.cs" />
- <Compile Include="IConnectionFactory.cs" />
- <Compile Include="IConnectionListener.cs" />
- <Compile Include="IFieldTable.cs" />
- <Compile Include="IHeaders.cs" />
- <Compile Include="IMessage.cs" />
- <Compile Include="IMessageConsumer.cs" />
- <Compile Include="IMessagePublisher.cs" />
- <Compile Include="IChannel.cs" />
- <Compile Include="ITextMessage.cs" />
- <Compile Include="MessageConsumerBuilder.cs" />
- <Compile Include="MessageNotReadableException.cs" />
- <Compile Include="MessageNotWritableException.cs" />
- <Compile Include="MessagePublisherBuilder.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="QpidException.cs" />
- <Compile Include="ResourceAllocationException.cs" />
+ <Compile Include="**\*.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework Client Profile</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 2.0 %28x86%29</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.0 %28x86%29</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
@@ -66,4 +112,4 @@
<Target Name="AfterBuild">
</Target>
-->
-</Project> \ No newline at end of file
+</Project>
diff --git a/dotnet/Qpid.Messaging/default.build b/dotnet/Qpid.Messaging/default.build
index 789258bfad..e351def886 100644
--- a/dotnet/Qpid.Messaging/default.build
+++ b/dotnet/Qpid.Messaging/default.build
@@ -1,24 +1,45 @@
-<?xml version="1.0"?>
-<project name="Apache.Qpid.Messaging" default="build">
- <!--
- Properties that come from master build file
- - build.dir: root directory for build
- - build.debug: true if building debug release
- - build.defines: variables to define during build
- -->
-
- <target name="build">
- <csc target="library"
- define="${build.defines}"
- debug="${build.debug}"
- output="${build.dir}/${project::get-name()}.dll">
-
- <sources>
- <include name="**/*.cs" />
- </sources>
- <references>
- </references>
- </csc>
- </target>
-</project>
-
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="Apache.Qpid.Messaging" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="library"
+ define="${build.defines}"
+ debug="${build.debug}"
+ output="${build.dir}/${project::get-name()}.dll">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ </references>
+ </csc>
+ </target>
+</project>
+
diff --git a/dotnet/Qpid.NET.sln b/dotnet/Qpid.NET.sln
index 8bccc6ec26..07deccf237 100644
--- a/dotnet/Qpid.NET.sln
+++ b/dotnet/Qpid.NET.sln
@@ -1,7 +1,6 @@

-Microsoft Visual Studio Solution File, Format Version 9.00
-# Visual Studio 2005
-# SharpDevelop 2.2.1.2648
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qpid.Messaging", "Qpid.Messaging\Qpid.Messaging.csproj", "{6688F826-C58E-4C1B-AA1F-22AFAB4B7D07}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qpid.Common.Tests", "Qpid.Common.Tests\Qpid.Common.Tests.csproj", "{F83624B0-762B-4D82-900D-FF4C1B36E36E}"
@@ -26,7 +25,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TopicPublisher", "TopicPubl
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TopicListener", "TopicListener\TopicListener.csproj", "{9A112DF2-146F-4CF4-919B-9D3BE7D088E9}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "TestClient\TestClient.csproj", "{9A112DF2-146F-4CF4-919B-9D3BE7D088E9}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "TestClient\TestClient.csproj", "{6E0374D9-99BE-4D4F-B41D-B227E37E04C6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qpid.Integration.Tests", "Qpid.Integration.Tests\Qpid.Integration.Tests.csproj", "{DE21CEBC-F38C-43EA-B576-38CA9738A00A}"
EndProject
@@ -84,14 +83,12 @@ Global
{9A112DF2-146F-4CF4-919B-9D3BE7D088E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9A112DF2-146F-4CF4-919B-9D3BE7D088E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9A112DF2-146F-4CF4-919B-9D3BE7D088E9}.Release|Any CPU.Build.0 = Release|Any CPU
- {666C2D04-C9DC-4D43-B4DF-0989225EABC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {666C2D04-C9DC-4D43-B4DF-0989225EABC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {666C2D04-C9DC-4D43-B4DF-0989225EABC3}.Release|Any CPU.Build.0 = Release|Any CPU
- {666C2D04-C9DC-4D43-B4DF-0989225EABC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {DE21CEBC-F38C-43EA-B576-38CA9738A00A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6E0374D9-99BE-4D4F-B41D-B227E37E04C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6E0374D9-99BE-4D4F-B41D-B227E37E04C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DE21CEBC-F38C-43EA-B576-38CA9738A00A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {DE21CEBC-F38C-43EA-B576-38CA9738A00A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DE21CEBC-F38C-43EA-B576-38CA9738A00A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DE21CEBC-F38C-43EA-B576-38CA9738A00A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DE21CEBC-F38C-43EA-B576-38CA9738A00A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/dotnet/Qpid.Sasl.Tests/App.config b/dotnet/Qpid.Sasl.Tests/App.config
index 539f341e7c..021399939e 100644
--- a/dotnet/Qpid.Sasl.Tests/App.config
+++ b/dotnet/Qpid.Sasl.Tests/App.config
@@ -1,12 +1,33 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<configuration>
- <configSections>
- <section name="qpid.sasl" type="Apache.Qpid.Sasl.Configuration.SaslConfigurationSectionHandler, Apache.Qpid.Sasl"/>
- </configSections>
-
- <qpid.sasl>
- <clientFactories>
- <add type="Apache.Qpid.Sasl.Tests.TestClientFactory, Apache.Qpid.Sasl.Tests"/>
- </clientFactories>
- </qpid.sasl>
-</configuration>
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<configuration>
+ <configSections>
+ <section name="qpid.sasl" type="Apache.Qpid.Sasl.Configuration.SaslConfigurationSectionHandler, Apache.Qpid.Sasl"/>
+ </configSections>
+
+ <qpid.sasl>
+ <clientFactories>
+ <add type="Apache.Qpid.Sasl.Tests.TestClientFactory, Apache.Qpid.Sasl.Tests"/>
+ </clientFactories>
+ </qpid.sasl>
+</configuration>
diff --git a/dotnet/Qpid.Sasl.Tests/Mechanisms/AnonymousSaslClientTests.cs b/dotnet/Qpid.Sasl.Tests/Mechanisms/AnonymousSaslClientTests.cs
index 09260736f0..5839f310e1 100644
--- a/dotnet/Qpid.Sasl.Tests/Mechanisms/AnonymousSaslClientTests.cs
+++ b/dotnet/Qpid.Sasl.Tests/Mechanisms/AnonymousSaslClientTests.cs
@@ -1,72 +1,72 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Text;
-
-using NUnit.Framework;
-using Apache.Qpid.Sasl;
-using Apache.Qpid.Sasl.Mechanisms;
-
-namespace Apache.Qpid.Sasl.Tests.Mechanisms
-{
- [TestFixture]
- public class AnonymousSaslClientTests : ISaslCallbackHandler
- {
- private const string AUTHID = "nobody@nowhere.com";
-
- [Test]
- public void ReturnsRightMechanismName()
- {
- ISaslClient client = new AnonymousSaslClient(AUTHID, new Hashtable(), this);
-
- Assert.AreEqual("ANONYMOUS", client.MechanismName);
- }
-
- [Test]
- public void HasInitialResponseReturnsTrue()
- {
- ISaslClient client = new AnonymousSaslClient(AUTHID, new Hashtable(), this);
-
- Assert.IsTrue(client.HasInitialResponse);
- }
-
- [Test]
- public void CanEvaluateChallenge()
- {
- Hashtable props = new Hashtable();
- ISaslClient client = new AnonymousSaslClient(AUTHID, props, this);
-
- Assert.IsFalse(client.IsComplete);
- byte[] response = client.EvaluateChallenge(new byte[0]);
- Assert.AreEqual(AUTHID, Encoding.UTF8.GetString(response));
-
- Assert.IsTrue(client.IsComplete);
- }
-
- void ISaslCallbackHandler.Handle(ISaslCallback[] callbacks)
- {
- }
-
- } // class AnonymousSaslClientTests
-
-} // namespace Apache.Qpid.Sasl.Tests.Mechanisms
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Text;
+
+using NUnit.Framework;
+using Apache.Qpid.Sasl;
+using Apache.Qpid.Sasl.Mechanisms;
+
+namespace Apache.Qpid.Sasl.Tests.Mechanisms
+{
+ [TestFixture]
+ public class AnonymousSaslClientTests : ISaslCallbackHandler
+ {
+ private const string AUTHID = "nobody@nowhere.com";
+
+ [Test]
+ public void ReturnsRightMechanismName()
+ {
+ ISaslClient client = new AnonymousSaslClient(AUTHID, new Hashtable(), this);
+
+ Assert.AreEqual("ANONYMOUS", client.MechanismName);
+ }
+
+ [Test]
+ public void HasInitialResponseReturnsTrue()
+ {
+ ISaslClient client = new AnonymousSaslClient(AUTHID, new Hashtable(), this);
+
+ Assert.IsTrue(client.HasInitialResponse);
+ }
+
+ [Test]
+ public void CanEvaluateChallenge()
+ {
+ Hashtable props = new Hashtable();
+ ISaslClient client = new AnonymousSaslClient(AUTHID, props, this);
+
+ Assert.IsFalse(client.IsComplete);
+ byte[] response = client.EvaluateChallenge(new byte[0]);
+ Assert.AreEqual(AUTHID, Encoding.UTF8.GetString(response));
+
+ Assert.IsTrue(client.IsComplete);
+ }
+
+ void ISaslCallbackHandler.Handle(ISaslCallback[] callbacks)
+ {
+ }
+
+ } // class AnonymousSaslClientTests
+
+} // namespace Apache.Qpid.Sasl.Tests.Mechanisms
diff --git a/dotnet/Qpid.Sasl.Tests/Mechanisms/CramMD5SaslClientTests.cs b/dotnet/Qpid.Sasl.Tests/Mechanisms/CramMD5SaslClientTests.cs
index e8b0ae5468..baeeafb2d2 100644
--- a/dotnet/Qpid.Sasl.Tests/Mechanisms/CramMD5SaslClientTests.cs
+++ b/dotnet/Qpid.Sasl.Tests/Mechanisms/CramMD5SaslClientTests.cs
@@ -1,90 +1,90 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Text;
-
-using NUnit.Framework;
-using Apache.Qpid.Sasl;
-using Apache.Qpid.Sasl.Mechanisms;
-
-namespace Apache.Qpid.Sasl.Tests.Mechanisms
-{
- [TestFixture]
- public class CramMD5SaslClientTests : ISaslCallbackHandler
- {
- private const string USERNAME = "testuser";
- private const string PASSWORD = "tanstaaftanstaaf";
- private const string AUTHID = "test";
-
- [Test]
- public void ReturnsRightMechanismName()
- {
- ISaslClient client = new CramMD5SaslClient(AUTHID, new Hashtable(), this);
-
- Assert.AreEqual("CRAM-MD5", client.MechanismName);
- }
-
- [Test]
- public void HasInitialResponseReturnsFalse()
- {
- ISaslClient client = new CramMD5SaslClient(AUTHID, new Hashtable(), this);
-
- Assert.IsFalse(client.HasInitialResponse);
- }
-
- [Test]
- public void CanEvaluateChallenge()
- {
- Hashtable props = new Hashtable();
-
- ISaslClient client = new CramMD5SaslClient(AUTHID, props, this);
-
- Assert.IsFalse(client.IsComplete);
-
- byte[] challenge =
- Encoding.UTF8.GetBytes("<1896.697170952@postoffice.reston.mci.net>");
- byte[] response = client.EvaluateChallenge(challenge);
- string[] parts = Encoding.UTF8.GetString(response).Split(' ');
-
- Assert.AreEqual(2, parts.Length);
- Assert.AreEqual(USERNAME, parts[0]);
- Assert.AreEqual("b913a602c7eda7a495b4e6e7334d3890", parts[1]);
- Assert.IsTrue(client.IsComplete);
- }
-
- void ISaslCallbackHandler.Handle(ISaslCallback[] callbacks)
- {
- foreach ( ISaslCallback cb in callbacks )
- {
- if ( cb is NameCallback )
- {
- ((NameCallback)cb).Text = USERNAME;
- } else if ( cb is PasswordCallback )
- {
- ((PasswordCallback)cb).Text = PASSWORD;
- }
- }
- }
- } // class CramMD5SaslClientTests
-
-} // namespace Apache.Qpid.Sasl.Tests.Mechanisms
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Text;
+
+using NUnit.Framework;
+using Apache.Qpid.Sasl;
+using Apache.Qpid.Sasl.Mechanisms;
+
+namespace Apache.Qpid.Sasl.Tests.Mechanisms
+{
+ [TestFixture]
+ public class CramMD5SaslClientTests : ISaslCallbackHandler
+ {
+ private const string USERNAME = "testuser";
+ private const string PASSWORD = "tanstaaftanstaaf";
+ private const string AUTHID = "test";
+
+ [Test]
+ public void ReturnsRightMechanismName()
+ {
+ ISaslClient client = new CramMD5SaslClient(AUTHID, new Hashtable(), this);
+
+ Assert.AreEqual("CRAM-MD5", client.MechanismName);
+ }
+
+ [Test]
+ public void HasInitialResponseReturnsFalse()
+ {
+ ISaslClient client = new CramMD5SaslClient(AUTHID, new Hashtable(), this);
+
+ Assert.IsFalse(client.HasInitialResponse);
+ }
+
+ [Test]
+ public void CanEvaluateChallenge()
+ {
+ Hashtable props = new Hashtable();
+
+ ISaslClient client = new CramMD5SaslClient(AUTHID, props, this);
+
+ Assert.IsFalse(client.IsComplete);
+
+ byte[] challenge =
+ Encoding.UTF8.GetBytes("<1896.697170952@postoffice.reston.mci.net>");
+ byte[] response = client.EvaluateChallenge(challenge);
+ string[] parts = Encoding.UTF8.GetString(response).Split(' ');
+
+ Assert.AreEqual(2, parts.Length);
+ Assert.AreEqual(USERNAME, parts[0]);
+ Assert.AreEqual("b913a602c7eda7a495b4e6e7334d3890", parts[1]);
+ Assert.IsTrue(client.IsComplete);
+ }
+
+ void ISaslCallbackHandler.Handle(ISaslCallback[] callbacks)
+ {
+ foreach ( ISaslCallback cb in callbacks )
+ {
+ if ( cb is NameCallback )
+ {
+ ((NameCallback)cb).Text = USERNAME;
+ } else if ( cb is PasswordCallback )
+ {
+ ((PasswordCallback)cb).Text = PASSWORD;
+ }
+ }
+ }
+ } // class CramMD5SaslClientTests
+
+} // namespace Apache.Qpid.Sasl.Tests.Mechanisms
diff --git a/dotnet/Qpid.Sasl.Tests/Mechanisms/DigestSaslClientTests.cs b/dotnet/Qpid.Sasl.Tests/Mechanisms/DigestSaslClientTests.cs
index eb7e7ebbd5..5a18ebaefd 100644
--- a/dotnet/Qpid.Sasl.Tests/Mechanisms/DigestSaslClientTests.cs
+++ b/dotnet/Qpid.Sasl.Tests/Mechanisms/DigestSaslClientTests.cs
@@ -1,249 +1,249 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Collections.Specialized;
-using System.Text;
-
-using NUnit.Framework;
-using Apache.Qpid.Sasl;
-using Apache.Qpid.Sasl.Mechanisms;
-
-namespace Apache.Qpid.Sasl.Tests.Mechanisms
-{
- [TestFixture]
- public class DigestSaslClientTests : ISaslCallbackHandler
- {
- private const string USERNAME = "chris";
- private const string PASSWORD = "secret";
- private const string AUTHID = null;
- private const string PROTOCOL = "IMAP";
- private const string SERVERNAME = "elwood.innosoft.com";
-
- #region Digest Challenge Parsing Tests
- //
- // Digest Challenge Parsing Tests
- //
-
- [Test]
- public void CanParseSimpleString()
- {
- string challenge = "realm=\"elwood.innosoft.com\", algorithm=md5-sess";
- StringDictionary values = DigestChallenge.ParseParameters(challenge);
- Assert.AreEqual(2, values.Count);
- Assert.AreEqual("elwood.innosoft.com", values["realm"]);
- Assert.AreEqual("md5-sess", values["algorithm"]);
- }
-
- [Test]
- public void CanParseEscapedQuotes()
- {
- string challenge = "realm=\"elwood\\\".innosoft.com\", algorithm=md5-sess";
- StringDictionary values = DigestChallenge.ParseParameters(challenge);
- Assert.AreEqual(2, values.Count);
- Assert.AreEqual("elwood\\\".innosoft.com", values["realm"]);
- Assert.AreEqual("md5-sess", values["algorithm"]);
- }
-
- [Test]
- public void CanParseEmbeddedDelimiter()
- {
- string challenge = "realm=\"elwood,innosoft.com\", algorithm=md5-sess";
- StringDictionary values = DigestChallenge.ParseParameters(challenge);
- Assert.AreEqual(2, values.Count);
- Assert.AreEqual("elwood,innosoft.com", values["realm"]);
- Assert.AreEqual("md5-sess", values["algorithm"]);
- }
-
- [Test]
- public void CanParse1()
- {
- string challenge = "realm=\"elwood.innosoft.com\",nonce=\"OA6MG9tEQGm2hh\",qop=\"auth\",algorithm=md5-sess,charset=utf-8";
- DigestChallenge parsed = DigestChallenge.Parse(challenge);
-
- Assert.AreEqual("elwood.innosoft.com", parsed.Realm);
- Assert.AreEqual("OA6MG9tEQGm2hh", parsed.Nonce);
- Assert.Contains("auth", parsed.QopOptions);
- Assert.AreEqual("md5-sess", parsed.Algorithm);
- Assert.AreEqual("utf-8", parsed.Charset);
- }
-
- #endregion // Digest Challenge Parsing Tests
-
-
- #region Digest Response Tests
- //
- // Digest Response Tests
- //
-
- [Test]
- public void CanWriteResponse()
- {
- DigestResponse resp = new DigestResponse();
- resp.Username = "user";
- resp.Realm = "nowhere.com";
- resp.Nonce = "OA9BSXrbuRhWay";
- resp.Cnonce = "OA9BSuZWMSpW8m";
- resp.NonceCount = 16;
- resp.DigestUri = "acap/elwood.innosoft.com";
- resp.Response = "6084c6db3fede7352c551284490fd0fc";
- resp.Qop = "auth";
- resp.MaxBuffer = 65536;
- resp.Cipher = "3des";
- resp.Authzid = "user2";
- resp.AuthParam = "ap";
- resp.Charset = "utf-8";
-
- string expected = "username=\"user\",realm=\"nowhere.com\",nonce=\"OA9BSXrbuRhWay\",cnonce=\"OA9BSuZWMSpW8m\",nc=00000010,qop=auth,digest-uri=\"acap/elwood.innosoft.com\",response=\"6084c6db3fede7352c551284490fd0fc\",maxbuf=65536,charset=utf-8,cipher=3des,authzid=\"user2\",auth-param=\"ap\"";
- Assert.AreEqual(expected, resp.ToString());
- }
-
- [Test]
- public void CanWriteEscapedSecuence()
- {
- DigestResponse resp = new DigestResponse();
- resp.Username = "us\"er";
-
- string expected = "username=\"us\\\"er\",nc=00000000,maxbuf=0";
- Assert.AreEqual(expected, resp.ToString());
- }
-
- #endregion // Digest Response Tests
-
-
- #region Authentication Tests
- //
- // Authentication Tests
- //
-
- [Test]
- public void ReturnsRightMechanismName()
- {
- ISaslClient client = CreateClient();
-
- Assert.AreEqual("DIGEST-MD5", client.MechanismName);
- }
-
- [Test]
- public void HasInitialResponseReturnsFalse()
- {
- ISaslClient client = CreateClient();
-
- Assert.IsFalse(client.HasInitialResponse);
- }
-
- [Test]
- public void CanAuthenticate()
- {
- string challenge = "realm=\"elwood.innosoft.com\",nonce=\"OA6MG9tEQGm2hh\",qop=\"auth\",algorithm=md5-sess,charset=utf-8";
- DigestSaslClient client = CreateClient();
- client.Cnonce = "OA6MHXh6VqTrRk";
-
- byte[] bresp = client.EvaluateChallenge(Encoding.UTF8.GetBytes(challenge));
- string response = Encoding.UTF8.GetString(bresp);
- string expectedResp = "username=\"chris\",realm=\"elwood.innosoft.com\",nonce=\"OA6MG9tEQGm2hh\",cnonce=\"" +
- client.Cnonce + "\",nc=00000001,qop=auth,digest-uri=\"imap/elwood.innosoft.com\",response=\"d388dad90d4bbd760a152321f2143af7\",maxbuf=65536,charset=utf-8";
-
- Assert.AreEqual(expectedResp, response);
- Assert.IsFalse(client.IsComplete);
-
- string challenge2 = "rspauth=ea40f60335c427b5527b84dbabcdfffd";
- bresp = client.EvaluateChallenge(Encoding.UTF8.GetBytes(challenge2));
- // client responds with zero-length array
- Assert.AreEqual(0, bresp.Length);
- Assert.IsTrue(client.IsComplete);
- }
-
- [Test]
- [ExpectedException(typeof(ArgumentNullException))]
- public void ThrowsExceptionWhenChallengeIsMissing()
- {
- DigestSaslClient client = CreateClient();
- client.EvaluateChallenge(null);
- }
-
-
- [Test]
- [ExpectedException(typeof(SaslException))]
- public void ThrowsExceptionWhenNonceMissing()
- {
- string challenge = "realm=\"elwood.innosoft.com\"";
- DigestSaslClient client = CreateClient();
-
- client.EvaluateChallenge(Encoding.UTF8.GetBytes(challenge));
- }
-
- [Test]
- [ExpectedException(typeof(SaslException))]
- public void ThrowsExceptionWhenAlgorithmMissing()
- {
- string challenge = "realm=\"elwood.innosoft.com\",nonce=\"asdasadsad\"";
- DigestSaslClient client = CreateClient();
-
- client.EvaluateChallenge(Encoding.UTF8.GetBytes(challenge));
- }
-
- [Test]
- [ExpectedException(typeof(SaslException))]
- public void ThrowsExceptionWhenSecondChallengeInvalid()
- {
- string challenge = "realm=\"elwood.innosoft.com\",nonce=\"OA6MG9tEQGm2hh\",qop=\"auth\",algorithm=md5-sess,charset=utf-8";
- DigestSaslClient client = CreateClient();
-
- byte[] bresp = client.EvaluateChallenge(Encoding.UTF8.GetBytes(challenge));
- Encoding.UTF8.GetString(bresp);
-
- // repeat challenge 1, which is incorrect
- client.EvaluateChallenge(Encoding.UTF8.GetBytes(challenge));
- }
-
- private DigestSaslClient CreateClient()
- {
- return new DigestSaslClient(
- AUTHID, SERVERNAME, PROTOCOL,
- new Hashtable(), this
- );
- }
-
- void ISaslCallbackHandler.Handle(ISaslCallback[] callbacks)
- {
- foreach ( ISaslCallback cb in callbacks )
- {
- if ( cb is NameCallback )
- {
- ((NameCallback)cb).Text = USERNAME;
- } else if ( cb is PasswordCallback )
- {
- ((PasswordCallback)cb).Text = PASSWORD;
- } else if ( cb is RealmCallback )
- {
- ((RealmCallback)cb).Text = SERVERNAME;
- }
- }
- }
-
- #endregion // Authentication Tests
-
-
- } // class DigestSaslClientTests
-
-} // namespace Apache.Qpid.Sasl.Tests.Mechanisms
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Text;
+
+using NUnit.Framework;
+using Apache.Qpid.Sasl;
+using Apache.Qpid.Sasl.Mechanisms;
+
+namespace Apache.Qpid.Sasl.Tests.Mechanisms
+{
+ [TestFixture]
+ public class DigestSaslClientTests : ISaslCallbackHandler
+ {
+ private const string USERNAME = "chris";
+ private const string PASSWORD = "secret";
+ private const string AUTHID = null;
+ private const string PROTOCOL = "IMAP";
+ private const string SERVERNAME = "elwood.innosoft.com";
+
+ #region Digest Challenge Parsing Tests
+ //
+ // Digest Challenge Parsing Tests
+ //
+
+ [Test]
+ public void CanParseSimpleString()
+ {
+ string challenge = "realm=\"elwood.innosoft.com\", algorithm=md5-sess";
+ StringDictionary values = DigestChallenge.ParseParameters(challenge);
+ Assert.AreEqual(2, values.Count);
+ Assert.AreEqual("elwood.innosoft.com", values["realm"]);
+ Assert.AreEqual("md5-sess", values["algorithm"]);
+ }
+
+ [Test]
+ public void CanParseEscapedQuotes()
+ {
+ string challenge = "realm=\"elwood\\\".innosoft.com\", algorithm=md5-sess";
+ StringDictionary values = DigestChallenge.ParseParameters(challenge);
+ Assert.AreEqual(2, values.Count);
+ Assert.AreEqual("elwood\\\".innosoft.com", values["realm"]);
+ Assert.AreEqual("md5-sess", values["algorithm"]);
+ }
+
+ [Test]
+ public void CanParseEmbeddedDelimiter()
+ {
+ string challenge = "realm=\"elwood,innosoft.com\", algorithm=md5-sess";
+ StringDictionary values = DigestChallenge.ParseParameters(challenge);
+ Assert.AreEqual(2, values.Count);
+ Assert.AreEqual("elwood,innosoft.com", values["realm"]);
+ Assert.AreEqual("md5-sess", values["algorithm"]);
+ }
+
+ [Test]
+ public void CanParse1()
+ {
+ string challenge = "realm=\"elwood.innosoft.com\",nonce=\"OA6MG9tEQGm2hh\",qop=\"auth\",algorithm=md5-sess,charset=utf-8";
+ DigestChallenge parsed = DigestChallenge.Parse(challenge);
+
+ Assert.AreEqual("elwood.innosoft.com", parsed.Realm);
+ Assert.AreEqual("OA6MG9tEQGm2hh", parsed.Nonce);
+ Assert.Contains("auth", parsed.QopOptions);
+ Assert.AreEqual("md5-sess", parsed.Algorithm);
+ Assert.AreEqual("utf-8", parsed.Charset);
+ }
+
+ #endregion // Digest Challenge Parsing Tests
+
+
+ #region Digest Response Tests
+ //
+ // Digest Response Tests
+ //
+
+ [Test]
+ public void CanWriteResponse()
+ {
+ DigestResponse resp = new DigestResponse();
+ resp.Username = "user";
+ resp.Realm = "nowhere.com";
+ resp.Nonce = "OA9BSXrbuRhWay";
+ resp.Cnonce = "OA9BSuZWMSpW8m";
+ resp.NonceCount = 16;
+ resp.DigestUri = "acap/elwood.innosoft.com";
+ resp.Response = "6084c6db3fede7352c551284490fd0fc";
+ resp.Qop = "auth";
+ resp.MaxBuffer = 65536;
+ resp.Cipher = "3des";
+ resp.Authzid = "user2";
+ resp.AuthParam = "ap";
+ resp.Charset = "utf-8";
+
+ string expected = "username=\"user\",realm=\"nowhere.com\",nonce=\"OA9BSXrbuRhWay\",cnonce=\"OA9BSuZWMSpW8m\",nc=00000010,qop=auth,digest-uri=\"acap/elwood.innosoft.com\",response=\"6084c6db3fede7352c551284490fd0fc\",maxbuf=65536,charset=utf-8,cipher=3des,authzid=\"user2\",auth-param=\"ap\"";
+ Assert.AreEqual(expected, resp.ToString());
+ }
+
+ [Test]
+ public void CanWriteEscapedSecuence()
+ {
+ DigestResponse resp = new DigestResponse();
+ resp.Username = "us\"er";
+
+ string expected = "username=\"us\\\"er\",nc=00000000,maxbuf=0";
+ Assert.AreEqual(expected, resp.ToString());
+ }
+
+ #endregion // Digest Response Tests
+
+
+ #region Authentication Tests
+ //
+ // Authentication Tests
+ //
+
+ [Test]
+ public void ReturnsRightMechanismName()
+ {
+ ISaslClient client = CreateClient();
+
+ Assert.AreEqual("DIGEST-MD5", client.MechanismName);
+ }
+
+ [Test]
+ public void HasInitialResponseReturnsFalse()
+ {
+ ISaslClient client = CreateClient();
+
+ Assert.IsFalse(client.HasInitialResponse);
+ }
+
+ [Test]
+ public void CanAuthenticate()
+ {
+ string challenge = "realm=\"elwood.innosoft.com\",nonce=\"OA6MG9tEQGm2hh\",qop=\"auth\",algorithm=md5-sess,charset=utf-8";
+ DigestSaslClient client = CreateClient();
+ client.Cnonce = "OA6MHXh6VqTrRk";
+
+ byte[] bresp = client.EvaluateChallenge(Encoding.UTF8.GetBytes(challenge));
+ string response = Encoding.UTF8.GetString(bresp);
+ string expectedResp = "username=\"chris\",realm=\"elwood.innosoft.com\",nonce=\"OA6MG9tEQGm2hh\",cnonce=\"" +
+ client.Cnonce + "\",nc=00000001,qop=auth,digest-uri=\"imap/elwood.innosoft.com\",response=\"d388dad90d4bbd760a152321f2143af7\",maxbuf=65536,charset=utf-8";
+
+ Assert.AreEqual(expectedResp, response);
+ Assert.IsFalse(client.IsComplete);
+
+ string challenge2 = "rspauth=ea40f60335c427b5527b84dbabcdfffd";
+ bresp = client.EvaluateChallenge(Encoding.UTF8.GetBytes(challenge2));
+ // client responds with zero-length array
+ Assert.AreEqual(0, bresp.Length);
+ Assert.IsTrue(client.IsComplete);
+ }
+
+ [Test]
+ [ExpectedException(typeof(ArgumentNullException))]
+ public void ThrowsExceptionWhenChallengeIsMissing()
+ {
+ DigestSaslClient client = CreateClient();
+ client.EvaluateChallenge(null);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(SaslException))]
+ public void ThrowsExceptionWhenNonceMissing()
+ {
+ string challenge = "realm=\"elwood.innosoft.com\"";
+ DigestSaslClient client = CreateClient();
+
+ client.EvaluateChallenge(Encoding.UTF8.GetBytes(challenge));
+ }
+
+ [Test]
+ [ExpectedException(typeof(SaslException))]
+ public void ThrowsExceptionWhenAlgorithmMissing()
+ {
+ string challenge = "realm=\"elwood.innosoft.com\",nonce=\"asdasadsad\"";
+ DigestSaslClient client = CreateClient();
+
+ client.EvaluateChallenge(Encoding.UTF8.GetBytes(challenge));
+ }
+
+ [Test]
+ [ExpectedException(typeof(SaslException))]
+ public void ThrowsExceptionWhenSecondChallengeInvalid()
+ {
+ string challenge = "realm=\"elwood.innosoft.com\",nonce=\"OA6MG9tEQGm2hh\",qop=\"auth\",algorithm=md5-sess,charset=utf-8";
+ DigestSaslClient client = CreateClient();
+
+ byte[] bresp = client.EvaluateChallenge(Encoding.UTF8.GetBytes(challenge));
+ Encoding.UTF8.GetString(bresp);
+
+ // repeat challenge 1, which is incorrect
+ client.EvaluateChallenge(Encoding.UTF8.GetBytes(challenge));
+ }
+
+ private DigestSaslClient CreateClient()
+ {
+ return new DigestSaslClient(
+ AUTHID, SERVERNAME, PROTOCOL,
+ new Hashtable(), this
+ );
+ }
+
+ void ISaslCallbackHandler.Handle(ISaslCallback[] callbacks)
+ {
+ foreach ( ISaslCallback cb in callbacks )
+ {
+ if ( cb is NameCallback )
+ {
+ ((NameCallback)cb).Text = USERNAME;
+ } else if ( cb is PasswordCallback )
+ {
+ ((PasswordCallback)cb).Text = PASSWORD;
+ } else if ( cb is RealmCallback )
+ {
+ ((RealmCallback)cb).Text = SERVERNAME;
+ }
+ }
+ }
+
+ #endregion // Authentication Tests
+
+
+ } // class DigestSaslClientTests
+
+} // namespace Apache.Qpid.Sasl.Tests.Mechanisms
diff --git a/dotnet/Qpid.Sasl.Tests/Mechanisms/ExternalSaslClientTests.cs b/dotnet/Qpid.Sasl.Tests/Mechanisms/ExternalSaslClientTests.cs
index 1864a6c957..57efcf7614 100644
--- a/dotnet/Qpid.Sasl.Tests/Mechanisms/ExternalSaslClientTests.cs
+++ b/dotnet/Qpid.Sasl.Tests/Mechanisms/ExternalSaslClientTests.cs
@@ -1,71 +1,71 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Text;
-
-using NUnit.Framework;
-using Apache.Qpid.Sasl;
-using Apache.Qpid.Sasl.Mechanisms;
-
-namespace Apache.Qpid.Sasl.Tests.Mechanisms
-{
- [TestFixture]
- public class ExternalSaslClientTests : ISaslCallbackHandler
- {
- private const string AUTHID = "nobody@nowhere.com";
-
- [Test]
- public void ReturnsRightMechanismName()
- {
- ISaslClient client = new ExternalSaslClient(AUTHID, new Hashtable(), this);
-
- Assert.AreEqual("EXTERNAL", client.MechanismName);
- }
-
- [Test]
- public void HasInitialResponseReturnsTrue()
- {
- ISaslClient client = new ExternalSaslClient(AUTHID, new Hashtable(), this);
-
- Assert.IsTrue(client.HasInitialResponse);
- }
-
- [Test]
- public void CanEvaluateChallenge()
- {
- ISaslClient client = new ExternalSaslClient(AUTHID, new Hashtable(), this);
-
- Assert.IsFalse(client.IsComplete);
- byte[] response = client.EvaluateChallenge(new byte[0]);
- Assert.AreEqual(AUTHID, Encoding.UTF8.GetString(response));
-
- Assert.IsTrue(client.IsComplete);
- }
-
- void ISaslCallbackHandler.Handle(ISaslCallback[] callbacks)
- {
- }
-
- } // class AnonymousSaslClientTests
-
-} // namespace Apache.Qpid.Sasl.Tests.Mechanisms
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Text;
+
+using NUnit.Framework;
+using Apache.Qpid.Sasl;
+using Apache.Qpid.Sasl.Mechanisms;
+
+namespace Apache.Qpid.Sasl.Tests.Mechanisms
+{
+ [TestFixture]
+ public class ExternalSaslClientTests : ISaslCallbackHandler
+ {
+ private const string AUTHID = "nobody@nowhere.com";
+
+ [Test]
+ public void ReturnsRightMechanismName()
+ {
+ ISaslClient client = new ExternalSaslClient(AUTHID, new Hashtable(), this);
+
+ Assert.AreEqual("EXTERNAL", client.MechanismName);
+ }
+
+ [Test]
+ public void HasInitialResponseReturnsTrue()
+ {
+ ISaslClient client = new ExternalSaslClient(AUTHID, new Hashtable(), this);
+
+ Assert.IsTrue(client.HasInitialResponse);
+ }
+
+ [Test]
+ public void CanEvaluateChallenge()
+ {
+ ISaslClient client = new ExternalSaslClient(AUTHID, new Hashtable(), this);
+
+ Assert.IsFalse(client.IsComplete);
+ byte[] response = client.EvaluateChallenge(new byte[0]);
+ Assert.AreEqual(AUTHID, Encoding.UTF8.GetString(response));
+
+ Assert.IsTrue(client.IsComplete);
+ }
+
+ void ISaslCallbackHandler.Handle(ISaslCallback[] callbacks)
+ {
+ }
+
+ } // class AnonymousSaslClientTests
+
+} // namespace Apache.Qpid.Sasl.Tests.Mechanisms
diff --git a/dotnet/Qpid.Sasl.Tests/Mechanisms/PlainSaslClientTests.cs b/dotnet/Qpid.Sasl.Tests/Mechanisms/PlainSaslClientTests.cs
index 4c82f7b126..f4fc00e038 100644
--- a/dotnet/Qpid.Sasl.Tests/Mechanisms/PlainSaslClientTests.cs
+++ b/dotnet/Qpid.Sasl.Tests/Mechanisms/PlainSaslClientTests.cs
@@ -1,88 +1,88 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Text;
-
-using NUnit.Framework;
-using Apache.Qpid.Sasl;
-using Apache.Qpid.Sasl.Mechanisms;
-
-namespace Apache.Qpid.Sasl.Tests.Mechanisms
-{
- [TestFixture]
- public class PlainSaslClientTests : ISaslCallbackHandler
- {
- private const string USERNAME = "testuser";
- private const string PASSWORD = "thepasswd";
- private const string AUTHID = "theauth";
-
- [Test]
- public void ReturnsRightMechanismName()
- {
- ISaslClient client = new PlainSaslClient(AUTHID, new Hashtable(), this);
-
- Assert.AreEqual("PLAIN", client.MechanismName);
- }
-
- [Test]
- public void HasInitialResponseReturnsTrue()
- {
- ISaslClient client = new PlainSaslClient(AUTHID, new Hashtable(), this);
-
- Assert.IsTrue(client.HasInitialResponse);
- }
-
- [Test]
- public void CanEvaluateChallenge()
- {
- Hashtable props = new Hashtable();
- ISaslClient client = new PlainSaslClient(AUTHID, props, this);
-
- Assert.IsFalse(client.IsComplete);
- byte[] response = client.EvaluateChallenge(new byte[0]);
- string[] parts = Encoding.UTF8.GetString(response).Split('\0');
-
- Assert.AreEqual(3, parts.Length);
- Assert.AreEqual(AUTHID, parts[0]);
- Assert.AreEqual(USERNAME, parts[1]);
- Assert.AreEqual(PASSWORD, parts[2]);
- Assert.IsTrue(client.IsComplete);
- }
-
- void ISaslCallbackHandler.Handle(ISaslCallback[] callbacks)
- {
- foreach ( ISaslCallback cb in callbacks )
- {
- if ( cb is NameCallback )
- {
- ((NameCallback)cb).Text = USERNAME;
- } else if ( cb is PasswordCallback )
- {
- ((PasswordCallback)cb).Text = PASSWORD;
- }
- }
- }
-
- } // class PlainSaslClientTests
-
-} // namespace Apache.Qpid.Sasl.Tests.Mechanisms
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Text;
+
+using NUnit.Framework;
+using Apache.Qpid.Sasl;
+using Apache.Qpid.Sasl.Mechanisms;
+
+namespace Apache.Qpid.Sasl.Tests.Mechanisms
+{
+ [TestFixture]
+ public class PlainSaslClientTests : ISaslCallbackHandler
+ {
+ private const string USERNAME = "testuser";
+ private const string PASSWORD = "thepasswd";
+ private const string AUTHID = "theauth";
+
+ [Test]
+ public void ReturnsRightMechanismName()
+ {
+ ISaslClient client = new PlainSaslClient(AUTHID, new Hashtable(), this);
+
+ Assert.AreEqual("PLAIN", client.MechanismName);
+ }
+
+ [Test]
+ public void HasInitialResponseReturnsTrue()
+ {
+ ISaslClient client = new PlainSaslClient(AUTHID, new Hashtable(), this);
+
+ Assert.IsTrue(client.HasInitialResponse);
+ }
+
+ [Test]
+ public void CanEvaluateChallenge()
+ {
+ Hashtable props = new Hashtable();
+ ISaslClient client = new PlainSaslClient(AUTHID, props, this);
+
+ Assert.IsFalse(client.IsComplete);
+ byte[] response = client.EvaluateChallenge(new byte[0]);
+ string[] parts = Encoding.UTF8.GetString(response).Split('\0');
+
+ Assert.AreEqual(3, parts.Length);
+ Assert.AreEqual(AUTHID, parts[0]);
+ Assert.AreEqual(USERNAME, parts[1]);
+ Assert.AreEqual(PASSWORD, parts[2]);
+ Assert.IsTrue(client.IsComplete);
+ }
+
+ void ISaslCallbackHandler.Handle(ISaslCallback[] callbacks)
+ {
+ foreach ( ISaslCallback cb in callbacks )
+ {
+ if ( cb is NameCallback )
+ {
+ ((NameCallback)cb).Text = USERNAME;
+ } else if ( cb is PasswordCallback )
+ {
+ ((PasswordCallback)cb).Text = PASSWORD;
+ }
+ }
+ }
+
+ } // class PlainSaslClientTests
+
+} // namespace Apache.Qpid.Sasl.Tests.Mechanisms
diff --git a/dotnet/Qpid.Sasl.Tests/Properties/AssemblyInfo.cs b/dotnet/Qpid.Sasl.Tests/Properties/AssemblyInfo.cs
index 74665f7b73..e795c267a7 100644
--- a/dotnet/Qpid.Sasl.Tests/Properties/AssemblyInfo.cs
+++ b/dotnet/Qpid.Sasl.Tests/Properties/AssemblyInfo.cs
@@ -1,35 +1,56 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Apache.Qpid.Sasl.Tests")]
-[assembly: AssemblyDescription("Built from svn revision number: ")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Apache Software Foundation")]
-[assembly: AssemblyProduct("Apache.Qpid.Sasl.Tests")]
-[assembly: AssemblyCopyright("Apache Software Foundation")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("84cc3267-8019-4fad-a426-0a40155b3352")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Revision and Build Numbers
-// by using the '*' as shown below:
-[assembly: AssemblyVersion("2.1.0.0")]
-[assembly: AssemblyFileVersion("1.0.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.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Apache.Qpid.Sasl.Tests")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("Apache.Qpid.Sasl.Tests")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("84cc3267-8019-4fad-a426-0a40155b3352")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/Qpid.Sasl.Tests/Qpid.Sasl.Tests.csproj b/dotnet/Qpid.Sasl.Tests/Qpid.Sasl.Tests.csproj
index 2868b1d73c..f1a7b07e5a 100644
--- a/dotnet/Qpid.Sasl.Tests/Qpid.Sasl.Tests.csproj
+++ b/dotnet/Qpid.Sasl.Tests/Qpid.Sasl.Tests.csproj
@@ -1,67 +1,86 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <PropertyGroup>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProductVersion>8.0.50727</ProductVersion>
- <SchemaVersion>2.0</SchemaVersion>
- <ProjectGuid>{587B3520-EBB9-41ED-B019-E96116B651CE}</ProjectGuid>
- <OutputType>Library</OutputType>
- <AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>Apache.Qpid.Sasl.Tests</RootNamespace>
- <AssemblyName>Apache.Qpid.Sasl.Tests</AssemblyName>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>..\bin\net-2.0\debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- <UseVSHostingProcess>true</UseVSHostingProcess>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>pdbonly</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>..\bin\net-2.0\release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <ItemGroup>
- <Reference Include="nunit.framework, Version=2.2.8.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\Qpid.Client.Tests\lib\nunit\nunit.framework.dll</HintPath>
- </Reference>
- <Reference Include="System" />
- <Reference Include="System.Data" />
- <Reference Include="System.Xml" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="Mechanisms\ExternalSaslClientTests.cs" />
- <Compile Include="TestClientFactory.cs" />
- <Compile Include="Mechanisms\AnonymousSaslClientTests.cs" />
- <Compile Include="Mechanisms\DigestSaslClientTests.cs" />
- <Compile Include="Mechanisms\CramMD5SaslClientTests.cs" />
- <Compile Include="Mechanisms\PlainSaslClientTests.cs" />
- <Compile Include="SaslTests.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- </ItemGroup>
- <ItemGroup>
- <ProjectReference Include="..\Qpid.Sasl\Qpid.Sasl.csproj">
- <Project>{1465B0EE-6452-42A6-AB73-B2F9EABEEE75}</Project>
- <Name>Qpid.Sasl</Name>
- </ProjectReference>
- </ItemGroup>
- <ItemGroup>
- <None Include="App.config" />
- </ItemGroup>
- <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
- <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
- Other similar extension points exist, see Microsoft.Common.targets.
- <Target Name="BeforeBuild">
- </Target>
- <Target Name="AfterBuild">
- </Target>
- -->
-</Project> \ No newline at end of file
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.50727</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{587B3520-EBB9-41ED-B019-E96116B651CE}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Apache.Qpid.Sasl.Tests</RootNamespace>
+ <AssemblyName>Apache.Qpid.Sasl.Tests</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\bin\net-2.0\debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <UseVSHostingProcess>true</UseVSHostingProcess>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\bin\net-2.0\release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="nunit.framework, Version=2.2.8.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\Qpid.Client.Tests\lib\nunit\nunit.framework.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="**\*.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Qpid.Sasl\Qpid.Sasl.csproj">
+ <Project>{1465B0EE-6452-42A6-AB73-B2F9EABEEE75}</Project>
+ <Name>Qpid.Sasl</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="App.config" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/dotnet/Qpid.Sasl.Tests/SaslTests.cs b/dotnet/Qpid.Sasl.Tests/SaslTests.cs
index 5b27949b98..e7ae91d6b6 100644
--- a/dotnet/Qpid.Sasl.Tests/SaslTests.cs
+++ b/dotnet/Qpid.Sasl.Tests/SaslTests.cs
@@ -1,133 +1,133 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Text;
-
-using NUnit.Framework;
-using Apache.Qpid.Sasl;
-using Apache.Qpid.Sasl.Mechanisms;
-
-namespace Apache.Qpid.Sasl.Tests
-{
- [TestFixture]
- public class SaslTests : ISaslCallbackHandler
- {
-
- [Test]
- public void CanCreatePlain()
- {
- Hashtable props = new Hashtable();
- string[] mechanisms = new string[] { "PLAIN", "OTHER" };
- ISaslClient client = Sasl.CreateClient(mechanisms, "", "", "", props, this);
-
- Assert.IsNotNull(client);
- Assert.IsInstanceOfType(typeof(PlainSaslClient), client);
- }
-
- [Test]
- public void CanCreateCramMD5()
- {
- Hashtable props = new Hashtable();
- string[] mechanisms = new string[] { "CRAM-MD5", "OTHER" };
- ISaslClient client = Sasl.CreateClient(mechanisms, "", "", "", props, this);
-
- Assert.IsNotNull(client);
- Assert.IsInstanceOfType(typeof(CramMD5SaslClient), client);
- }
-
- [Test]
- public void CanCreateAnonymous()
- {
- Hashtable props = new Hashtable();
- string[] mechanisms = new string[] { "ANONYMOUS", "OTHER" };
- ISaslClient client = Sasl.CreateClient(mechanisms, "", "", "", props, this);
-
- Assert.IsNotNull(client);
- Assert.IsInstanceOfType(typeof(AnonymousSaslClient), client);
- }
-
- [Test]
- public void CanCreateDigest()
- {
- Hashtable props = new Hashtable();
- string[] mechanisms = new string[] { "DIGEST-MD5", "OTHER" };
- ISaslClient client = Sasl.CreateClient(mechanisms, "", "", "", props, this);
-
- Assert.IsNotNull(client);
- Assert.IsInstanceOfType(typeof(DigestSaslClient), client);
- }
-
- [Test]
- public void CanCreateExternal()
- {
- Hashtable props = new Hashtable();
- string[] mechanisms = new string[] { "EXTERNAL", "OTHER" };
- ISaslClient client = Sasl.CreateClient(mechanisms, "", "", "", props, this);
-
- Assert.IsNotNull(client);
- Assert.IsInstanceOfType(typeof(ExternalSaslClient), client);
- }
-
- [Test]
- public void ReturnsNullIfNoFactoryFound()
- {
- Hashtable props = new Hashtable();
- props.Add(SaslProperties.PolicyNoPlainText, true);
- string[] mechanisms = new string[] { "PLAIN", "OTHER" };
- ISaslClient client = Sasl.CreateClient(mechanisms, "", "", "", props, this);
-
- Assert.IsNull(client);
- }
-
- [Test]
- public void ParsesConfigurationSection()
- {
- // if the TEST mechanism is available, then we know
- // the configuration section worked!
- Hashtable props = new Hashtable();
- string[] mechanisms = new string[] { "TEST" };
- ISaslClient client = Sasl.CreateClient(mechanisms, "", "", "", props, this);
-
- Assert.IsNotNull(client);
- Assert.IsInstanceOfType(typeof(TestSaslClient), client);
- }
-
- [Test]
- public void ChoosesStrongerMechanism()
- {
- Hashtable props = new Hashtable();
- string[] mechanisms = new string[] { "PLAIN", "OTHER", "CRAM-MD5" };
- ISaslClient client = Sasl.CreateClient(mechanisms, "", "", "", props, this);
-
- Assert.IsNotNull(client);
- Assert.IsInstanceOfType(typeof(CramMD5SaslClient), client);
- }
-
-
- void ISaslCallbackHandler.Handle(ISaslCallback[] callbacks)
- {
- }
-
- } // class SaslTests
-
-} // namespace Apache.Qpid.Sasl.Tests
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Text;
+
+using NUnit.Framework;
+using Apache.Qpid.Sasl;
+using Apache.Qpid.Sasl.Mechanisms;
+
+namespace Apache.Qpid.Sasl.Tests
+{
+ [TestFixture]
+ public class SaslTests : ISaslCallbackHandler
+ {
+
+ [Test]
+ public void CanCreatePlain()
+ {
+ Hashtable props = new Hashtable();
+ string[] mechanisms = new string[] { "PLAIN", "OTHER" };
+ ISaslClient client = Sasl.CreateClient(mechanisms, "", "", "", props, this);
+
+ Assert.IsNotNull(client);
+ Assert.IsInstanceOfType(typeof(PlainSaslClient), client);
+ }
+
+ [Test]
+ public void CanCreateCramMD5()
+ {
+ Hashtable props = new Hashtable();
+ string[] mechanisms = new string[] { "CRAM-MD5", "OTHER" };
+ ISaslClient client = Sasl.CreateClient(mechanisms, "", "", "", props, this);
+
+ Assert.IsNotNull(client);
+ Assert.IsInstanceOfType(typeof(CramMD5SaslClient), client);
+ }
+
+ [Test]
+ public void CanCreateAnonymous()
+ {
+ Hashtable props = new Hashtable();
+ string[] mechanisms = new string[] { "ANONYMOUS", "OTHER" };
+ ISaslClient client = Sasl.CreateClient(mechanisms, "", "", "", props, this);
+
+ Assert.IsNotNull(client);
+ Assert.IsInstanceOfType(typeof(AnonymousSaslClient), client);
+ }
+
+ [Test]
+ public void CanCreateDigest()
+ {
+ Hashtable props = new Hashtable();
+ string[] mechanisms = new string[] { "DIGEST-MD5", "OTHER" };
+ ISaslClient client = Sasl.CreateClient(mechanisms, "", "", "", props, this);
+
+ Assert.IsNotNull(client);
+ Assert.IsInstanceOfType(typeof(DigestSaslClient), client);
+ }
+
+ [Test]
+ public void CanCreateExternal()
+ {
+ Hashtable props = new Hashtable();
+ string[] mechanisms = new string[] { "EXTERNAL", "OTHER" };
+ ISaslClient client = Sasl.CreateClient(mechanisms, "", "", "", props, this);
+
+ Assert.IsNotNull(client);
+ Assert.IsInstanceOfType(typeof(ExternalSaslClient), client);
+ }
+
+ [Test]
+ public void ReturnsNullIfNoFactoryFound()
+ {
+ Hashtable props = new Hashtable();
+ props.Add(SaslProperties.PolicyNoPlainText, true);
+ string[] mechanisms = new string[] { "PLAIN", "OTHER" };
+ ISaslClient client = Sasl.CreateClient(mechanisms, "", "", "", props, this);
+
+ Assert.IsNull(client);
+ }
+
+ [Test]
+ public void ParsesConfigurationSection()
+ {
+ // if the TEST mechanism is available, then we know
+ // the configuration section worked!
+ Hashtable props = new Hashtable();
+ string[] mechanisms = new string[] { "TEST" };
+ ISaslClient client = Sasl.CreateClient(mechanisms, "", "", "", props, this);
+
+ Assert.IsNotNull(client);
+ Assert.IsInstanceOfType(typeof(TestSaslClient), client);
+ }
+
+ [Test]
+ public void ChoosesStrongerMechanism()
+ {
+ Hashtable props = new Hashtable();
+ string[] mechanisms = new string[] { "PLAIN", "OTHER", "CRAM-MD5" };
+ ISaslClient client = Sasl.CreateClient(mechanisms, "", "", "", props, this);
+
+ Assert.IsNotNull(client);
+ Assert.IsInstanceOfType(typeof(CramMD5SaslClient), client);
+ }
+
+
+ void ISaslCallbackHandler.Handle(ISaslCallback[] callbacks)
+ {
+ }
+
+ } // class SaslTests
+
+} // namespace Apache.Qpid.Sasl.Tests
diff --git a/dotnet/Qpid.Sasl.Tests/TestClientFactory.cs b/dotnet/Qpid.Sasl.Tests/TestClientFactory.cs
index 73c68ea2b3..62099237e9 100644
--- a/dotnet/Qpid.Sasl.Tests/TestClientFactory.cs
+++ b/dotnet/Qpid.Sasl.Tests/TestClientFactory.cs
@@ -1,75 +1,75 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Text;
-
-using NUnit.Framework;
-using Apache.Qpid.Sasl;
-using Apache.Qpid.Sasl.Mechanisms;
-
-namespace Apache.Qpid.Sasl.Tests
-{
- public class TestClientFactory : ISaslClientFactory
- {
- public string[] GetSupportedMechanisms(IDictionary props)
- {
- return new string[] { TestSaslClient.Mechanism };
- }
-
- public ISaslClient CreateClient(string[] mechanisms, string authorizationId, string protocol, string serverName, IDictionary props, ISaslCallbackHandler handler)
- {
- foreach ( string mech in mechanisms )
- {
- if ( mech == TestSaslClient.Mechanism )
- return new TestSaslClient(props, handler);
- }
- return null;
- }
-
- } // class TestClientFactory
-
- internal class TestSaslClient : SaslClient
- {
- public const string Mechanism = "TEST";
-
- public override string MechanismName
- {
- get { return Mechanism; }
- }
- public override bool HasInitialResponse
- {
- get { return false; }
- }
-
- public TestSaslClient(IDictionary props, ISaslCallbackHandler handler)
- : base("", "", "", props, handler)
- {
- }
-
- public override byte[] EvaluateChallenge(byte[] challenge)
- {
- throw new NotImplementedException();
- }
- } // class TestSaslClient
-
-} // namespace Apache.Qpid.Sasl.Tests
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Text;
+
+using NUnit.Framework;
+using Apache.Qpid.Sasl;
+using Apache.Qpid.Sasl.Mechanisms;
+
+namespace Apache.Qpid.Sasl.Tests
+{
+ public class TestClientFactory : ISaslClientFactory
+ {
+ public string[] GetSupportedMechanisms(IDictionary props)
+ {
+ return new string[] { TestSaslClient.Mechanism };
+ }
+
+ public ISaslClient CreateClient(string[] mechanisms, string authorizationId, string protocol, string serverName, IDictionary props, ISaslCallbackHandler handler)
+ {
+ foreach ( string mech in mechanisms )
+ {
+ if ( mech == TestSaslClient.Mechanism )
+ return new TestSaslClient(props, handler);
+ }
+ return null;
+ }
+
+ } // class TestClientFactory
+
+ internal class TestSaslClient : SaslClient
+ {
+ public const string Mechanism = "TEST";
+
+ public override string MechanismName
+ {
+ get { return Mechanism; }
+ }
+ public override bool HasInitialResponse
+ {
+ get { return false; }
+ }
+
+ public TestSaslClient(IDictionary props, ISaslCallbackHandler handler)
+ : base("", "", "", props, handler)
+ {
+ }
+
+ public override byte[] EvaluateChallenge(byte[] challenge)
+ {
+ throw new NotImplementedException();
+ }
+ } // class TestSaslClient
+
+} // namespace Apache.Qpid.Sasl.Tests
diff --git a/dotnet/Qpid.Sasl.Tests/default.build b/dotnet/Qpid.Sasl.Tests/default.build
index eb0514d417..5b51c0a6fa 100644
--- a/dotnet/Qpid.Sasl.Tests/default.build
+++ b/dotnet/Qpid.Sasl.Tests/default.build
@@ -1,31 +1,52 @@
-<?xml version="1.0"?>
-<project name="Apache.Qpid.Sasl" default="test">
-
- <target name="build">
- <csc target="library"
- define="${build.defines}"
- warnaserror="true" debug="${build.debug}"
- output="${build.dir}/${project::get-name()}.Tests.dll">
-
- <sources>
- <include name="**/*.cs" />
- </sources>
- <references>
- <include name="${build.dir}/nunit.framework.dll" />
- <include name="${build.dir}/${project::get-name()}.dll" />
- </references>
-
- </csc>
- <copy
- tofile="${build.dir}/${project::get-name()}.Tests.dll.config"
- file="App.config"
- />
- </target>
- <target name="test" depends="build">
- <nunit2>
- <formatter type="${nant.formatter}" usefile="false" />
- <test assemblyname="${build.dir}/${project::get-name()}.Tests.dll" />
- </nunit2>
- </target>
-</project>
-
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="Apache.Qpid.Sasl" default="test">
+
+ <target name="build">
+ <csc target="library"
+ define="${build.defines}"
+ warnaserror="true" debug="${build.debug}"
+ output="${build.dir}/${project::get-name()}.Tests.dll">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ <include name="${build.dir}/nunit.framework.dll" />
+ <include name="${build.dir}/${project::get-name()}.dll" />
+ </references>
+
+ </csc>
+ <copy
+ tofile="${build.dir}/${project::get-name()}.Tests.dll.config"
+ file="App.config"
+ />
+ </target>
+ <target name="test" depends="build">
+ <nunit2>
+ <formatter type="${nant.formatter}" usefile="false" />
+ <test assemblyname="${build.dir}/${project::get-name()}.Tests.dll" />
+ </nunit2>
+ </target>
+</project>
+
diff --git a/dotnet/Qpid.Sasl/Callbacks.cs b/dotnet/Qpid.Sasl/Callbacks.cs
index 90e36beeb8..f4fcc1c54b 100644
--- a/dotnet/Qpid.Sasl/Callbacks.cs
+++ b/dotnet/Qpid.Sasl/Callbacks.cs
@@ -1,106 +1,139 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Text;
-
-namespace Apache.Qpid.Sasl
-{
- /// <summary>
- /// Marker interface for Sasl Callbacks
- /// </summary>
- public interface ISaslCallback
- {
- } // interface ISaslCallback
-
- public abstract class TextSaslCallback : ISaslCallback
- {
- private string _prompt;
- private string _text;
- private string _defaultText;
-
- public string Prompt
- {
- get { return _prompt; }
- set { _prompt = value; }
- }
-
- public string Text
- {
- get {
- if ( _text == null || _text.Length == 0 )
- return DefaultText;
- else
- return _text;
- }
- set { _text = value; }
- }
-
- public string DefaultText
- {
- get { return _defaultText; }
- set { _defaultText = value; }
- }
-
- protected TextSaslCallback(string prompt, string text, string defaultText)
- {
- _prompt = prompt;
- _text = text;
- _defaultText = defaultText;
- }
-
- } // class TextSaslCallback
-
- public class NameCallback : TextSaslCallback
- {
- public NameCallback()
- : this(Environment.UserName)
- {
- }
- public NameCallback(string defaultText)
- : base("username:", "", defaultText)
- {
- }
- } // class NameCallback
-
- public class PasswordCallback : TextSaslCallback
- {
- public PasswordCallback()
- : base("password:", "", "")
- {
- }
- } // class PasswordCallback
-
- public class RealmCallback : TextSaslCallback
- {
- public RealmCallback()
- : this("localhost")
- {
- }
- public RealmCallback(string defaultText)
- : base("realm:", "", defaultText)
- {
- }
- } // class RealmCallback
-
-} // namespace Apache.Qpid.Sasl
-
-
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Text;
+using System.Globalization;
+using System.Security.Cryptography;
+
+namespace Apache.Qpid.Sasl
+{
+ /// <summary>
+ /// Marker interface for Sasl Callbacks
+ /// </summary>
+ public interface ISaslCallback
+ {
+ } // interface ISaslCallback
+
+ public abstract class TextSaslCallback : ISaslCallback
+ {
+ private string _prompt;
+ private string _text;
+ private string _defaultText;
+
+ public string Prompt
+ {
+ get { return _prompt; }
+ set { _prompt = value; }
+ }
+
+ public string Text
+ {
+ get {
+ if ( _text == null || _text.Length == 0 )
+ return DefaultText;
+ else
+ return _text;
+ }
+ set { _text = value; }
+ }
+
+ public string DefaultText
+ {
+ get { return _defaultText; }
+ set { _defaultText = value; }
+ }
+
+ protected TextSaslCallback(string prompt, string text, string defaultText)
+ {
+ _prompt = prompt;
+ _text = text;
+ _defaultText = defaultText;
+ }
+
+ } // class TextSaslCallback
+
+ public class NameCallback : TextSaslCallback
+ {
+ public NameCallback()
+ : this(Environment.UserName)
+ {
+ }
+ public NameCallback(string defaultText)
+ : base("username:", "", defaultText)
+ {
+ }
+ } // class NameCallback
+
+ public class PasswordCallback : TextSaslCallback
+ {
+ public PasswordCallback()
+ : base("password:", "", "")
+ {
+ }
+
+ public byte[] HashedText
+ {
+ get
+ {
+ string _text = this.Text;
+ System.Security.Cryptography.MD5CryptoServiceProvider x = new System.Security.Cryptography.MD5CryptoServiceProvider();
+ byte[] bs = x.ComputeHash(Encoding.UTF8.GetBytes(_text));
+ return bs;
+ }
+
+ }
+ } // class PasswordCallback
+
+ public class HashedPasswordCallback : TextSaslCallback
+ {
+ public HashedPasswordCallback()
+ : base("password:", "", "")
+ {
+ }
+
+ public byte[] HashedText
+ {
+ get {
+ string _text = this.Text;
+ System.Security.Cryptography.MD5CryptoServiceProvider x = new System.Security.Cryptography.MD5CryptoServiceProvider();
+ _text = _text.PadRight(16, '\0');
+ byte[] bs = x.ComputeHash(Encoding.UTF8.GetBytes(_text));
+ return bs;
+ }
+ }
+ } // class PasswordCallback
+
+ public class RealmCallback : TextSaslCallback
+ {
+ public RealmCallback()
+ : this("localhost")
+ {
+ }
+ public RealmCallback(string defaultText)
+ : base("realm:", "", defaultText)
+ {
+ }
+ } // class RealmCallback
+
+} // namespace Apache.Qpid.Sasl
+
+
diff --git a/dotnet/Qpid.Sasl/Configuration/SaslConfiguration.cs b/dotnet/Qpid.Sasl/Configuration/SaslConfiguration.cs
index 3446261724..7a71ec28da 100644
--- a/dotnet/Qpid.Sasl/Configuration/SaslConfiguration.cs
+++ b/dotnet/Qpid.Sasl/Configuration/SaslConfiguration.cs
@@ -1,90 +1,90 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Configuration;
-using System.Text;
-using System.Xml;
-
-namespace Apache.Qpid.Sasl.Configuration
-{
- /// <summary>
- /// Represents an Sasl configuration section
- /// in the config file
- /// </summary>
- internal class SaslConfiguration
- {
- private IList _clientFactories;
-
- /// <summary>
- /// Set of configured client factores
- /// </summary>
- public IList ClientFactories
- {
- get { return _clientFactories; }
- }
-
- internal SaslConfiguration(IList clientFactoryTypes)
- {
- _clientFactories = new ArrayList();
- foreach ( Type type in clientFactoryTypes )
- {
- _clientFactories.Add(Activator.CreateInstance(type));
- }
- }
-
- /// <summary>
- /// Get the configuration for the library
- /// </summary>
- /// <returns>The configuration from app.config or a default configuration</returns>
- internal static SaslConfiguration GetConfiguration()
- {
- // 'obsolete' warning, but needed for .NET 1.1 compatibility
- SaslConfiguration config = (SaslConfiguration)
- ConfigurationSettings.GetConfig("qpid.sasl");
- if ( config == null )
- {
- // create default configuration
- IList clientFactories = GetDefaultClientFactories();
- config = new SaslConfiguration(clientFactories);
- }
- return config;
- }
-
- /// <summary>
- /// Create a list filled with the default client
- /// factories supported by the library
- /// </summary>
- /// <returns>The list of client factory types</returns>
- internal static IList GetDefaultClientFactories()
- {
- IList clientFactories = new ArrayList();
- clientFactories.Add(typeof(DefaultClientFactory));
- return clientFactories;
- }
-
-
- } // class SaslConfiguration
-
-} // namespace Apache.Qpid.Sasl.Configuration
-
-
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Configuration;
+using System.Text;
+using System.Xml;
+
+namespace Apache.Qpid.Sasl.Configuration
+{
+ /// <summary>
+ /// Represents an Sasl configuration section
+ /// in the config file
+ /// </summary>
+ internal class SaslConfiguration
+ {
+ private IList _clientFactories;
+
+ /// <summary>
+ /// Set of configured client factores
+ /// </summary>
+ public IList ClientFactories
+ {
+ get { return _clientFactories; }
+ }
+
+ internal SaslConfiguration(IList clientFactoryTypes)
+ {
+ _clientFactories = new ArrayList();
+ foreach ( Type type in clientFactoryTypes )
+ {
+ _clientFactories.Add(Activator.CreateInstance(type));
+ }
+ }
+
+ /// <summary>
+ /// Get the configuration for the library
+ /// </summary>
+ /// <returns>The configuration from app.config or a default configuration</returns>
+ internal static SaslConfiguration GetConfiguration()
+ {
+ // 'obsolete' warning, but needed for .NET 1.1 compatibility
+ SaslConfiguration config = (SaslConfiguration)
+ ConfigurationSettings.GetConfig("qpid.sasl");
+ if ( config == null )
+ {
+ // create default configuration
+ IList clientFactories = GetDefaultClientFactories();
+ config = new SaslConfiguration(clientFactories);
+ }
+ return config;
+ }
+
+ /// <summary>
+ /// Create a list filled with the default client
+ /// factories supported by the library
+ /// </summary>
+ /// <returns>The list of client factory types</returns>
+ internal static IList GetDefaultClientFactories()
+ {
+ IList clientFactories = new ArrayList();
+ clientFactories.Add(typeof(DefaultClientFactory));
+ return clientFactories;
+ }
+
+
+ } // class SaslConfiguration
+
+} // namespace Apache.Qpid.Sasl.Configuration
+
+
diff --git a/dotnet/Qpid.Sasl/Configuration/SaslConfigurationSectionHandler.cs b/dotnet/Qpid.Sasl/Configuration/SaslConfigurationSectionHandler.cs
index 21f6b92414..ea8669f8c4 100644
--- a/dotnet/Qpid.Sasl/Configuration/SaslConfigurationSectionHandler.cs
+++ b/dotnet/Qpid.Sasl/Configuration/SaslConfigurationSectionHandler.cs
@@ -1,84 +1,84 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Configuration;
-using System.Text;
-using System.Xml;
-
-namespace Apache.Qpid.Sasl.Configuration
-{
- /// <summary>
- /// Defines the configuration section to configure extra
- /// Sasl client factories
- /// </summary>
- public class SaslConfigurationSectionHandler
- : IConfigurationSectionHandler
- {
- public object Create(object parent, object configContext, XmlNode section)
- {
- IList clientFactories = SaslConfiguration.GetDefaultClientFactories();
-
- foreach ( XmlNode node in section.ChildNodes )
- {
- if ( node.LocalName == "clientFactories" )
- {
- ProcessFactories(node, clientFactories);
- }
- }
-
- SaslConfiguration config = new SaslConfiguration(clientFactories);
- return config;
- }
-
-
- private void ProcessFactories(XmlNode node, IList factories)
- {
- foreach ( XmlNode child in node.ChildNodes )
- {
- Type type;
- switch ( child.LocalName )
- {
- case "add":
- type = Type.GetType(child.Attributes["type"].Value);
- if ( !factories.Contains(type) )
- factories.Add(type);
- break;
- case "remove":
- type = Type.GetType(child.Attributes["type"].Value);
- if ( factories.Contains(type) )
- factories.Remove(type);
- break;
- case "clear":
- factories.Clear();
- break;
- default:
- // gives obsolete warning but needed for .NET 1.1 support
- throw new ConfigurationException(string.Format("Unknown element '{0}' in section '{0}'", child.LocalName, node.LocalName));
- }
- }
- }
- } // class SaslConfigurationSectionHandler
-
-} // namespace Apache.Qpid.Sasl.Configuration
-
-
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Configuration;
+using System.Text;
+using System.Xml;
+
+namespace Apache.Qpid.Sasl.Configuration
+{
+ /// <summary>
+ /// Defines the configuration section to configure extra
+ /// Sasl client factories
+ /// </summary>
+ public class SaslConfigurationSectionHandler
+ : IConfigurationSectionHandler
+ {
+ public object Create(object parent, object configContext, XmlNode section)
+ {
+ IList clientFactories = SaslConfiguration.GetDefaultClientFactories();
+
+ foreach ( XmlNode node in section.ChildNodes )
+ {
+ if ( node.LocalName == "clientFactories" )
+ {
+ ProcessFactories(node, clientFactories);
+ }
+ }
+
+ SaslConfiguration config = new SaslConfiguration(clientFactories);
+ return config;
+ }
+
+
+ private void ProcessFactories(XmlNode node, IList factories)
+ {
+ foreach ( XmlNode child in node.ChildNodes )
+ {
+ Type type;
+ switch ( child.LocalName )
+ {
+ case "add":
+ type = Type.GetType(child.Attributes["type"].Value);
+ if ( !factories.Contains(type) )
+ factories.Add(type);
+ break;
+ case "remove":
+ type = Type.GetType(child.Attributes["type"].Value);
+ if ( factories.Contains(type) )
+ factories.Remove(type);
+ break;
+ case "clear":
+ factories.Clear();
+ break;
+ default:
+ // gives obsolete warning but needed for .NET 1.1 support
+ throw new ConfigurationException(string.Format("Unknown element '{0}' in section '{0}'", child.LocalName, node.LocalName));
+ }
+ }
+ }
+ } // class SaslConfigurationSectionHandler
+
+} // namespace Apache.Qpid.Sasl.Configuration
+
+
diff --git a/dotnet/Qpid.Sasl/DefaultClientFactory.cs b/dotnet/Qpid.Sasl/DefaultClientFactory.cs
index d552aa80c0..744d7cae40 100644
--- a/dotnet/Qpid.Sasl/DefaultClientFactory.cs
+++ b/dotnet/Qpid.Sasl/DefaultClientFactory.cs
@@ -1,95 +1,99 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-
-using Apache.Qpid.Sasl.Mechanisms;
-
-namespace Apache.Qpid.Sasl
-{
- public class DefaultClientFactory : ISaslClientFactory
- {
- private static readonly string[] SUPPORTED = new string[] {
- DigestSaslClient.Mechanism,
- CramMD5SaslClient.Mechanism,
- PlainSaslClient.Mechanism,
- AnonymousSaslClient.Mechanism,
- ExternalSaslClient.Mechanism,
- };
-
- public string[] GetSupportedMechanisms(IDictionary props)
- {
- if ( props == null )
- throw new ArgumentNullException("props");
-
- ArrayList vetoed = new ArrayList();
-
- if ( props.Contains(SaslProperties.PolicyNoPlainText) ||
- props.Contains(SaslProperties.PolicyNoDictionary) ||
- props.Contains(SaslProperties.PolicyNoActive) ||
- props.Contains(SaslProperties.PolicyForwardSecrecy) ||
- props.Contains(SaslProperties.PolicyPassCredentials) )
- {
- vetoed.Add(CramMD5SaslClient.Mechanism);
- vetoed.Add(PlainSaslClient.Mechanism);
- vetoed.Add(AnonymousSaslClient.Mechanism);
- vetoed.Add(ExternalSaslClient.Mechanism);
- }
- if ( props.Contains(SaslProperties.PolicyNoAnonymous) )
- {
- vetoed.Add(AnonymousSaslClient.Mechanism);
- }
-
- ArrayList available = new ArrayList();
- foreach ( string mech in SUPPORTED )
- {
- if ( !vetoed.Contains(mech) )
- available.Add(mech);
- }
- return (string[])available.ToArray(typeof(string));
- }
-
- public ISaslClient CreateClient(
- string[] mechanisms, string authorizationId,
- string protocol, string serverName,
- IDictionary props, ISaslCallbackHandler handler
- )
- {
- IList mechs = mechanisms;
- if ( mechs.Contains(ExternalSaslClient.Mechanism) )
- return new ExternalSaslClient(authorizationId, props, handler);
- if ( mechs.Contains(DigestSaslClient.Mechanism) )
- return new DigestSaslClient(authorizationId, serverName, protocol, props, handler);
- if ( mechs.Contains(CramMD5SaslClient.Mechanism) )
- return new CramMD5SaslClient(authorizationId, props, handler);
- if ( mechs.Contains(PlainSaslClient.Mechanism) )
- return new PlainSaslClient(authorizationId, props, handler);
- if ( mechs.Contains(AnonymousSaslClient.Mechanism) )
- return new AnonymousSaslClient(authorizationId, props, handler);
- // unknown mechanism
- return null;
- }
- } // class DefaultClientFactory
-
-} // namespace Apache.Qpid.Sasl
-
-
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+
+using Apache.Qpid.Sasl.Mechanisms;
+
+namespace Apache.Qpid.Sasl
+{
+ public class DefaultClientFactory : ISaslClientFactory
+ {
+ private static readonly string[] SUPPORTED = new string[] {
+ DigestSaslClient.Mechanism,
+ CramMD5SaslClient.Mechanism,
+ CramMD5HexSaslClient.Mechanism,
+ PlainSaslClient.Mechanism,
+ AnonymousSaslClient.Mechanism,
+ ExternalSaslClient.Mechanism,
+ };
+
+ public string[] GetSupportedMechanisms(IDictionary props)
+ {
+ if ( props == null )
+ throw new ArgumentNullException("props");
+
+ ArrayList vetoed = new ArrayList();
+
+ if ( props.Contains(SaslProperties.PolicyNoPlainText) ||
+ props.Contains(SaslProperties.PolicyNoDictionary) ||
+ props.Contains(SaslProperties.PolicyNoActive) ||
+ props.Contains(SaslProperties.PolicyForwardSecrecy) ||
+ props.Contains(SaslProperties.PolicyPassCredentials) )
+ {
+ vetoed.Add(CramMD5SaslClient.Mechanism);
+ vetoed.Add(CramMD5HexSaslClient.Mechanism);
+ vetoed.Add(PlainSaslClient.Mechanism);
+ vetoed.Add(AnonymousSaslClient.Mechanism);
+ vetoed.Add(ExternalSaslClient.Mechanism);
+ }
+ if ( props.Contains(SaslProperties.PolicyNoAnonymous) )
+ {
+ vetoed.Add(AnonymousSaslClient.Mechanism);
+ }
+
+ ArrayList available = new ArrayList();
+ foreach ( string mech in SUPPORTED )
+ {
+ if ( !vetoed.Contains(mech) )
+ available.Add(mech);
+ }
+ return (string[])available.ToArray(typeof(string));
+ }
+
+ public ISaslClient CreateClient(
+ string[] mechanisms, string authorizationId,
+ string protocol, string serverName,
+ IDictionary props, ISaslCallbackHandler handler
+ )
+ {
+ IList mechs = mechanisms;
+ if ( mechs.Contains(ExternalSaslClient.Mechanism) )
+ return new ExternalSaslClient(authorizationId, props, handler);
+ if ( mechs.Contains(DigestSaslClient.Mechanism) )
+ return new DigestSaslClient(authorizationId, serverName, protocol, props, handler);
+ if ( mechs.Contains(CramMD5SaslClient.Mechanism) )
+ return new CramMD5SaslClient(authorizationId, props, handler);
+ if ( mechs.Contains(CramMD5HexSaslClient.Mechanism) )
+ return new CramMD5HexSaslClient(authorizationId, props, handler);
+ if ( mechs.Contains(PlainSaslClient.Mechanism) )
+ return new PlainSaslClient(authorizationId, props, handler);
+ if ( mechs.Contains(AnonymousSaslClient.Mechanism) )
+ return new AnonymousSaslClient(authorizationId, props, handler);
+ // unknown mechanism
+ return null;
+ }
+ } // class DefaultClientFactory
+
+} // namespace Apache.Qpid.Sasl
+
+
diff --git a/dotnet/Qpid.Sasl/ISaslCallbackHandler.cs b/dotnet/Qpid.Sasl/ISaslCallbackHandler.cs
index 0dfc482333..c2638f245e 100644
--- a/dotnet/Qpid.Sasl/ISaslCallbackHandler.cs
+++ b/dotnet/Qpid.Sasl/ISaslCallbackHandler.cs
@@ -1,35 +1,35 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Text;
-
-namespace Apache.Qpid.Sasl
-{
- public interface ISaslCallbackHandler
- {
- void Handle(ISaslCallback[] callbacks);
-
- } // interface ISaslCallbackHandler
-
-} // namespace Apache.Qpid.Sasl
-
-
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Text;
+
+namespace Apache.Qpid.Sasl
+{
+ public interface ISaslCallbackHandler
+ {
+ void Handle(ISaslCallback[] callbacks);
+
+ } // interface ISaslCallbackHandler
+
+} // namespace Apache.Qpid.Sasl
+
+
diff --git a/dotnet/Qpid.Sasl/ISaslClient.cs b/dotnet/Qpid.Sasl/ISaslClient.cs
index 526cc1f43a..668ca05d26 100644
--- a/dotnet/Qpid.Sasl/ISaslClient.cs
+++ b/dotnet/Qpid.Sasl/ISaslClient.cs
@@ -1,42 +1,42 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Text;
-
-namespace Apache.Qpid.Sasl
-{
- public interface ISaslClient
- {
- string MechanismName { get; }
- bool HasInitialResponse { get; }
- bool IsComplete { get; }
-
- byte[] EvaluateChallenge(byte[] challenge);
- object GetNegotiatedProperty(string propName);
- byte[] Unwrap(byte[] buffer, int offset, int length);
- byte[] Wrap(byte[] buffer, int offset, int lenght);
-
- } // interface ISaslClient
-
-} // namespace Apache.Qpid.Sasl
-
-
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Text;
+
+namespace Apache.Qpid.Sasl
+{
+ public interface ISaslClient
+ {
+ string MechanismName { get; }
+ bool HasInitialResponse { get; }
+ bool IsComplete { get; }
+
+ byte[] EvaluateChallenge(byte[] challenge);
+ object GetNegotiatedProperty(string propName);
+ byte[] Unwrap(byte[] buffer, int offset, int length);
+ byte[] Wrap(byte[] buffer, int offset, int lenght);
+
+ } // interface ISaslClient
+
+} // namespace Apache.Qpid.Sasl
+
+
diff --git a/dotnet/Qpid.Sasl/ISaslClientFactory.cs b/dotnet/Qpid.Sasl/ISaslClientFactory.cs
index fc81057ec4..f052e07ad9 100644
--- a/dotnet/Qpid.Sasl/ISaslClientFactory.cs
+++ b/dotnet/Qpid.Sasl/ISaslClientFactory.cs
@@ -1,40 +1,40 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Text;
-
-namespace Apache.Qpid.Sasl
-{
- public interface ISaslClientFactory
- {
- string[] GetSupportedMechanisms(IDictionary props);
- ISaslClient CreateClient(
- string[] mechanisms, string authorizationId,
- string protocol, string serverName,
- IDictionary props, ISaslCallbackHandler handler
- );
- } // interface ISaslClientFactory
-
-} // namespace Apache.Qpid.Sasl
-
-
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Text;
+
+namespace Apache.Qpid.Sasl
+{
+ public interface ISaslClientFactory
+ {
+ string[] GetSupportedMechanisms(IDictionary props);
+ ISaslClient CreateClient(
+ string[] mechanisms, string authorizationId,
+ string protocol, string serverName,
+ IDictionary props, ISaslCallbackHandler handler
+ );
+ } // interface ISaslClientFactory
+
+} // namespace Apache.Qpid.Sasl
+
+
diff --git a/dotnet/Qpid.Sasl/MD5HMAC.cs b/dotnet/Qpid.Sasl/MD5HMAC.cs
index 134332284a..7e310c5364 100644
--- a/dotnet/Qpid.Sasl/MD5HMAC.cs
+++ b/dotnet/Qpid.Sasl/MD5HMAC.cs
@@ -1,115 +1,115 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Security.Cryptography;
-
-namespace Apache.Qpid.Sasl
-{
- /// <summary>
- /// Rough HMAC MD5 implementation as presented in
- /// RFC 2104. Used because the HMACMD5 class in the
- /// .NET framework is not available in v1.1.
- /// </summary>
- public sealed class MD5HMAC : IDisposable
- {
- private const int BLOCK_LEN = 64;
- private MD5 _hash;
- private byte[] _key;
- private byte[] _ipad;
- private byte[] _opad;
-
- public MD5HMAC(byte[] key)
- {
- if ( key == null || key.Length == 0 )
- throw new ArgumentNullException("key");
-
- _hash = new MD5CryptoServiceProvider();
-
- byte[] theKey = key;
- if ( theKey.Length > BLOCK_LEN )
- {
- theKey = _hash.ComputeHash(theKey);
- }
- // pad key with 0's up to BLOCK_LEN
- _key = new byte[BLOCK_LEN];
- Array.Copy(theKey, _key, theKey.Length);
-
- CreatePads();
- }
-
- public byte[] ComputeHash(byte[] input)
- {
- // H(K XOR opad, H(K XOR ipad, text))
- return H(_opad, H(_ipad, input));
- }
-
- public void Dispose()
- {
- if ( _hash != null )
- {
- ((IDisposable)_hash).Dispose();
- _hash = null;
- }
- }
-
- #region Private Methods
- //
- // Private Methods
- //
-
- private void CreatePads()
- {
- _ipad = new byte[BLOCK_LEN];
- _opad = new byte[BLOCK_LEN];
- for ( int i = 0; i < BLOCK_LEN; i++ )
- {
- _ipad[i] = 0x36;
- _opad[i] = 0x5c;
- }
-
- XOR(_ipad, _key);
- XOR(_opad, _key);
- }
-
- private static void XOR(byte[] dest, byte[] other)
- {
- // assume both are same size
- for ( int i = 0; i < dest.Length; i++ )
- {
- dest[i] ^= other[i];
- }
- }
-
- private byte[] H(byte[] v1, byte[] v2)
- {
- byte[] total = new byte[v1.Length + v2.Length];
- Array.Copy(v1, total, v1.Length);
- Array.Copy(v2, 0, total, v1.Length, v2.Length);
-
- return _hash.ComputeHash(total);
- }
-
- #endregion // Private Methods
-
- } // class MD5HMAC
-
-} // namespace Apache.Qpid.Sasl
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Security.Cryptography;
+
+namespace Apache.Qpid.Sasl
+{
+ /// <summary>
+ /// Rough HMAC MD5 implementation as presented in
+ /// RFC 2104. Used because the HMACMD5 class in the
+ /// .NET framework is not available in v1.1.
+ /// </summary>
+ public sealed class MD5HMAC : IDisposable
+ {
+ private const int BLOCK_LEN = 64;
+ private MD5 _hash;
+ private byte[] _key;
+ private byte[] _ipad;
+ private byte[] _opad;
+
+ public MD5HMAC(byte[] key)
+ {
+ if ( key == null || key.Length == 0 )
+ throw new ArgumentNullException("key");
+
+ _hash = new MD5CryptoServiceProvider();
+
+ byte[] theKey = key;
+ if ( theKey.Length > BLOCK_LEN )
+ {
+ theKey = _hash.ComputeHash(theKey);
+ }
+ // pad key with 0's up to BLOCK_LEN
+ _key = new byte[BLOCK_LEN];
+ Array.Copy(theKey, _key, theKey.Length);
+
+ CreatePads();
+ }
+
+ public byte[] ComputeHash(byte[] input)
+ {
+ // H(K XOR opad, H(K XOR ipad, text))
+ return H(_opad, H(_ipad, input));
+ }
+
+ public void Dispose()
+ {
+ if ( _hash != null )
+ {
+ ((IDisposable)_hash).Dispose();
+ _hash = null;
+ }
+ }
+
+ #region Private Methods
+ //
+ // Private Methods
+ //
+
+ private void CreatePads()
+ {
+ _ipad = new byte[BLOCK_LEN];
+ _opad = new byte[BLOCK_LEN];
+ for ( int i = 0; i < BLOCK_LEN; i++ )
+ {
+ _ipad[i] = 0x36;
+ _opad[i] = 0x5c;
+ }
+
+ XOR(_ipad, _key);
+ XOR(_opad, _key);
+ }
+
+ private static void XOR(byte[] dest, byte[] other)
+ {
+ // assume both are same size
+ for ( int i = 0; i < dest.Length; i++ )
+ {
+ dest[i] ^= other[i];
+ }
+ }
+
+ private byte[] H(byte[] v1, byte[] v2)
+ {
+ byte[] total = new byte[v1.Length + v2.Length];
+ Array.Copy(v1, total, v1.Length);
+ Array.Copy(v2, 0, total, v1.Length, v2.Length);
+
+ return _hash.ComputeHash(total);
+ }
+
+ #endregion // Private Methods
+
+ } // class MD5HMAC
+
+} // namespace Apache.Qpid.Sasl
diff --git a/dotnet/Qpid.Sasl/Mechanisms/AnonymousSaslClient.cs b/dotnet/Qpid.Sasl/Mechanisms/AnonymousSaslClient.cs
index 5e8c56ff51..e550d10d97 100644
--- a/dotnet/Qpid.Sasl/Mechanisms/AnonymousSaslClient.cs
+++ b/dotnet/Qpid.Sasl/Mechanisms/AnonymousSaslClient.cs
@@ -1,69 +1,69 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Text;
-
-namespace Apache.Qpid.Sasl.Mechanisms
-{
- /// <summary>
- /// Implements the ANONYMOUS authentication mechanism
- /// as outlined in RFC 2245
- /// </summary>
- public class AnonymousSaslClient : SaslClient
- {
- public const string Mechanism = "ANONYMOUS";
-
- public AnonymousSaslClient(
- string authid, IDictionary properties,
- ISaslCallbackHandler handler)
- : base(authid, null, null, properties, handler)
- {
- }
-
- #region ISaslClient Implementation
- //
- // ISaslClient Implementation
- //
-
- public override string MechanismName
- {
- get { return Mechanism; }
- }
-
- public override bool HasInitialResponse
- {
- get { return true; }
- }
-
- public override byte[] EvaluateChallenge(byte[] challenge)
- {
- // ignore challenge
- SetComplete();
- return Encoding.UTF8.GetBytes(AuthorizationId);
- }
-
- #endregion // ISaslClient Implementation
-
- } // class AnonymousSaslClient
-
-} // namespace Apache.Qpid.Sasl.Mechanisms
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Text;
+
+namespace Apache.Qpid.Sasl.Mechanisms
+{
+ /// <summary>
+ /// Implements the ANONYMOUS authentication mechanism
+ /// as outlined in RFC 2245
+ /// </summary>
+ public class AnonymousSaslClient : SaslClient
+ {
+ public const string Mechanism = "ANONYMOUS";
+
+ public AnonymousSaslClient(
+ string authid, IDictionary properties,
+ ISaslCallbackHandler handler)
+ : base(authid, null, null, properties, handler)
+ {
+ }
+
+ #region ISaslClient Implementation
+ //
+ // ISaslClient Implementation
+ //
+
+ public override string MechanismName
+ {
+ get { return Mechanism; }
+ }
+
+ public override bool HasInitialResponse
+ {
+ get { return true; }
+ }
+
+ public override byte[] EvaluateChallenge(byte[] challenge)
+ {
+ // ignore challenge
+ SetComplete();
+ return Encoding.UTF8.GetBytes(AuthorizationId);
+ }
+
+ #endregion // ISaslClient Implementation
+
+ } // class AnonymousSaslClient
+
+} // namespace Apache.Qpid.Sasl.Mechanisms
diff --git a/dotnet/Qpid.Sasl/Mechanisms/CramMD5HexSaslClient.cs b/dotnet/Qpid.Sasl/Mechanisms/CramMD5HexSaslClient.cs
new file mode 100644
index 0000000000..3cce0e3a2d
--- /dev/null
+++ b/dotnet/Qpid.Sasl/Mechanisms/CramMD5HexSaslClient.cs
@@ -0,0 +1,93 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace Apache.Qpid.Sasl.Mechanisms
+{
+ /// <summary>
+ /// Implements the CRAM-MD5 authentication mechanism as outlined
+ /// in RFC 2195
+ /// </summary>
+ public class CramMD5HexSaslClient : SaslClient
+ {
+ public const string Mechanism = "CRAM-MD5-HEX";
+ private const int MinPwdLen = 16;
+
+ public CramMD5HexSaslClient(
+ string authorizationId,
+ IDictionary properties,
+ ISaslCallbackHandler handler)
+ : base(authorizationId, null, null, properties, handler)
+ {
+ }
+
+ #region ISaslClient Implementation
+ //
+ // ISaslClient Implementation
+ //
+
+ public override string MechanismName
+ {
+ get { return Mechanism; }
+ }
+
+ public override bool HasInitialResponse
+ {
+ get { return false; }
+ }
+
+
+ public override byte[] EvaluateChallenge(byte[] challenge)
+ {
+ if ( challenge == null || challenge.Length == 0 )
+ throw new ArgumentNullException("challenge");
+
+
+ NameCallback nameCB = new NameCallback(AuthorizationId);
+ PasswordCallback pwdCB = new PasswordCallback();
+ ISaslCallback[] callbacks = { nameCB, pwdCB };
+ Handler.Handle(callbacks);
+
+ string username = nameCB.Text;
+
+ //Encode the Hashed Password as Hex
+ byte[] passwd = Encoding.UTF8.GetBytes(ToHex(pwdCB.HashedText));
+
+ string s = System.Text.UTF8Encoding.UTF8.GetString(challenge);
+
+ using ( HMAC hmac = new HMACMD5(passwd) )
+ {
+ byte[] value = hmac.ComputeHash(challenge);
+ string encoded = ToHex(value);
+ SetComplete();
+ return Encoding.UTF8.GetBytes(username + " " + encoded);
+ }
+ }
+
+ #endregion // ISaslClient Implementation
+
+ } // class CramMD5HashedSaslClient
+
+} // namespace Apache.Qpid.Sasl.Mechanisms
diff --git a/dotnet/Qpid.Sasl/Mechanisms/CramMD5SaslClient.cs b/dotnet/Qpid.Sasl/Mechanisms/CramMD5SaslClient.cs
index 672cc64c6a..56b0f6ecd4 100644
--- a/dotnet/Qpid.Sasl/Mechanisms/CramMD5SaslClient.cs
+++ b/dotnet/Qpid.Sasl/Mechanisms/CramMD5SaslClient.cs
@@ -1,91 +1,91 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Security.Cryptography;
-using System.Text;
-
-namespace Apache.Qpid.Sasl.Mechanisms
-{
- /// <summary>
- /// Implements the CRAM-MD5 authentication mechanism as outlined
- /// in RFC 2195
- /// </summary>
- public class CramMD5SaslClient : SaslClient
- {
- public const string Mechanism = "CRAM-MD5";
- private const int MinPwdLen = 16;
-
- public CramMD5SaslClient(
- string authorizationId,
- IDictionary properties,
- ISaslCallbackHandler handler)
- : base(authorizationId, null, null, properties, handler)
- {
- }
-
- #region ISaslClient Implementation
- //
- // ISaslClient Implementation
- //
-
- public override string MechanismName
- {
- get { return Mechanism; }
- }
-
- public override bool HasInitialResponse
- {
- get { return false; }
- }
-
- public override byte[] EvaluateChallenge(byte[] challenge)
- {
- if ( challenge == null || challenge.Length == 0 )
- throw new ArgumentNullException("challenge");
-
- NameCallback nameCB = new NameCallback(AuthorizationId);
- PasswordCallback pwdCB = new PasswordCallback();
- ISaslCallback[] callbacks = { nameCB, pwdCB };
- Handler.Handle(callbacks);
-
- string username = nameCB.Text;
- string passwd = pwdCB.Text.PadRight(MinPwdLen, '\0');
-
- byte[] secret = Encoding.UTF8.GetBytes(passwd);
-
- //using ( HMAC hmac = new HMACMD5(secret) )
- using ( MD5HMAC hmac = new MD5HMAC(secret) )
- {
- byte[] value = hmac.ComputeHash(challenge);
- string encoded = ToHex(value);
- SetComplete();
- return Encoding.UTF8.GetBytes(username + " " + encoded);
- }
-
- }
-
- #endregion // ISaslClient Implementation
-
- } // class CramMD5SaslClient
-
-} // namespace Apache.Qpid.Sasl.Mechanisms
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace Apache.Qpid.Sasl.Mechanisms
+{
+ /// <summary>
+ /// Implements the CRAM-MD5 authentication mechanism as outlined
+ /// in RFC 2195
+ /// </summary>
+ public class CramMD5SaslClient : SaslClient
+ {
+ public const string Mechanism = "CRAM-MD5";
+ private const int MinPwdLen = 16;
+
+ public CramMD5SaslClient(
+ string authorizationId,
+ IDictionary properties,
+ ISaslCallbackHandler handler)
+ : base(authorizationId, null, null, properties, handler)
+ {
+ }
+
+ #region ISaslClient Implementation
+ //
+ // ISaslClient Implementation
+ //
+
+ public override string MechanismName
+ {
+ get { return Mechanism; }
+ }
+
+ public override bool HasInitialResponse
+ {
+ get { return false; }
+ }
+
+ public override byte[] EvaluateChallenge(byte[] challenge)
+ {
+ if ( challenge == null || challenge.Length == 0 )
+ throw new ArgumentNullException("challenge");
+
+ NameCallback nameCB = new NameCallback(AuthorizationId);
+ PasswordCallback pwdCB = new PasswordCallback();
+ ISaslCallback[] callbacks = { nameCB, pwdCB };
+ Handler.Handle(callbacks);
+
+ string username = nameCB.Text;
+ string passwd = pwdCB.Text.PadRight(MinPwdLen, '\0');
+
+ byte[] secret = Encoding.UTF8.GetBytes(passwd);
+
+ //using ( HMAC hmac = new HMACMD5(secret) )
+ using ( MD5HMAC hmac = new MD5HMAC(secret) )
+ {
+ byte[] value = hmac.ComputeHash(challenge);
+ string encoded = ToHex(value);
+ SetComplete();
+ return Encoding.UTF8.GetBytes(username + " " + encoded);
+ }
+
+ }
+
+ #endregion // ISaslClient Implementation
+
+ } // class CramMD5SaslClient
+
+} // namespace Apache.Qpid.Sasl.Mechanisms
diff --git a/dotnet/Qpid.Sasl/Mechanisms/DigestSaslClient.cs b/dotnet/Qpid.Sasl/Mechanisms/DigestSaslClient.cs
index 59d3a88991..79843587c7 100644
--- a/dotnet/Qpid.Sasl/Mechanisms/DigestSaslClient.cs
+++ b/dotnet/Qpid.Sasl/Mechanisms/DigestSaslClient.cs
@@ -1,576 +1,576 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Collections.Specialized;
-using System.Globalization;
-using System.Security.Cryptography;
-using System.Text;
-
-namespace Apache.Qpid.Sasl.Mechanisms
-{
-
- /// <summary>
- /// Implements the DIGEST MD5 authentication mechanism
- /// as outlined in RFC 2831
- /// </summary>
- public class DigestSaslClient : SaslClient
- {
- public const string Mechanism = "DIGEST-MD5";
- private static readonly MD5 _md5 = new MD5CryptoServiceProvider();
- private int _state;
- private string _cnonce;
- private Encoding _encoding = Encoding.UTF8;
-
- public string Cnonce
- {
- get { return _cnonce; }
- set { _cnonce = value; }
- }
-
- public DigestSaslClient(
- string authid, string serverName, string protocol,
- IDictionary properties, ISaslCallbackHandler handler)
- : base(authid, serverName, protocol, properties, handler)
- {
- _cnonce = Guid.NewGuid().ToString("N");
- }
-
- #region ISaslClient Implementation
- //
- // ISaslClient Implementation
- //
-
- public override string MechanismName
- {
- get { return Mechanism; }
- }
-
- public override bool HasInitialResponse
- {
- get { return false; }
- }
-
- public override byte[] EvaluateChallenge(byte[] challenge)
- {
- if ( challenge == null || challenge.Length <= 0 )
- throw new ArgumentNullException("challenge");
-
- switch ( _state++ )
- {
- case 0: return OnInitialChallenge(challenge);
- case 1: return OnFinalResponse(challenge);
- }
- throw new SaslException("Invalid State for authentication");
- }
-
- #endregion // ISaslClient Implementation
-
-
- #region Private Methods
- //
- // Private Methods
- //
-
- /// <summary>
- /// Process the first challenge from the server
- /// and calculate a response
- /// </summary>
- /// <param name="challenge">The server issued challenge</param>
- /// <returns>Client response</returns>
- private byte[] OnInitialChallenge(byte[] challenge)
- {
- DigestChallenge dch =
- DigestChallenge.Parse(_encoding.GetString(challenge));
- // validate input challenge
- if ( dch.Nonce == null || dch.Nonce.Length == 0 )
- throw new SaslException("Nonce value missing in server challenge");
- if ( dch.Algorithm != "md5-sess" )
- throw new SaslException("Invalid or missing algorithm value in server challenge");
-
-
- NameCallback nameCB = new NameCallback(AuthorizationId);
- PasswordCallback pwdCB = new PasswordCallback();
- RealmCallback realmCB = new RealmCallback(dch.Realm);
- ISaslCallback[] callbacks = { nameCB, pwdCB, realmCB };
- Handler.Handle(callbacks);
-
- DigestResponse response = new DigestResponse();
- response.Username = nameCB.Text;
- response.Realm = realmCB.Text;
- response.Nonce = dch.Nonce;
- response.Cnonce = Cnonce;
- response.NonceCount = 1;
- response.Qop = DigestQop.Auth; // only auth supported for now
- response.DigestUri = Protocol.ToLower() + "/" + ServerName;
- response.MaxBuffer = dch.MaxBuffer;
- response.Charset = dch.Charset;
- response.Cipher = null; // not supported for now
- response.Authzid = AuthorizationId;
- response.AuthParam = dch.AuthParam;
-
- response.Response = CalculateResponse(
- nameCB.Text, realmCB.Text, pwdCB.Text,
- dch.Nonce, response.NonceCount, response.Qop, response.DigestUri
- );
-
- return _encoding.GetBytes(response.ToString());
- }
-
- /// <summary>
- /// Process the second server challenge
- /// </summary>
- /// <param name="challenge">Server issued challenge</param>
- /// <returns>The client response</returns>
- private byte[] OnFinalResponse(byte[] challenge)
- {
- DigestChallenge dch =
- DigestChallenge.Parse(_encoding.GetString(challenge));
-
- if ( dch.Rspauth == null || dch.Rspauth.Length == 0 )
- throw new SaslException("Expected 'rspauth' in server challenge not found");
-
- SetComplete();
- return new byte[0];
- }
-
-
-
- /// <summary>
- /// Calculate the response field of the client response
- /// </summary>
- /// <param name="username">The user name</param>
- /// <param name="realm">The realm</param>
- /// <param name="passwd">The user's password</param>
- /// <param name="nonce">Server nonce value</param>
- /// <param name="nc">Client nonce count (always 1)</param>
- /// <param name="qop">Quality of Protection</param>
- /// <param name="digestUri">Digest-URI</param>
- /// <returns>The value for the response field</returns>
- private string CalculateResponse(
- string username, string realm, string passwd,
- string nonce, int nc, string qop, string digestUri
- )
- {
- string a1 = CalcHexA1(username, realm, passwd, nonce);
- string a2 = CalcHexA2(digestUri, qop);
-
- string ncs = nc.ToString("x8", CultureInfo.InvariantCulture);
- StringBuilder prekd = new StringBuilder();
- prekd.Append(a1).Append(':').Append(nonce).Append(':')
- .Append(ncs).Append(':').Append(Cnonce)
- .Append(':').Append(qop).Append(':').Append(a2);
-
- return ToHex(CalcH(_encoding.GetBytes(prekd.ToString())));
- }
-
- private string CalcHexA1(
- string username, string realm,
- string passwd, string nonce
- )
- {
- bool hasAuthId = AuthorizationId != null && AuthorizationId.Length > 0;
-
- string premd = username + ":" + realm + ":" + passwd;
- byte[] temp1 = CalcH(_encoding.GetBytes(premd));
-
-
- int a1len = 16 + 1 + nonce.Length + 1 + Cnonce.Length;
- if ( hasAuthId )
- a1len += 1 + AuthorizationId.Length;
-
- byte[] buffer = new byte[a1len];
- Array.Copy(temp1, buffer, temp1.Length);
-
- string p2 = ":" + nonce + ":" + Cnonce;
- if ( hasAuthId )
- p2 += ":" + AuthorizationId;
-
- byte[] temp2 = _encoding.GetBytes(p2);
- Array.Copy(temp2, 0, buffer, 16, temp2.Length);
-
- return ToHex(CalcH(buffer));
- }
-
- private string CalcHexA2(string digestUri, string qop)
- {
- string a2 = "AUTHENTICATE:" + digestUri;
- if ( qop != DigestQop.Auth )
- a2 += ":00000000000000000000000000000000";
- return ToHex(CalcH(_encoding.GetBytes(a2)));
- }
-
- private static byte[] CalcH(byte[] value)
- {
- return _md5.ComputeHash(value);
- }
-
- #endregion // Private Methods
-
-
- } // class DigestSaslClient
-
-
- /// <summary>
- /// Available QOP options in the DIGEST scheme
- /// </summary>
- public sealed class DigestQop
- {
- public const string Auth = "auth";
- public const string AuthInt = "auth-int";
- public const string AuthConf = "auth-conf";
- } // class DigestQop
-
-
- /// <summary>
- /// Represents and parses a digest server challenge
- /// </summary>
- public class DigestChallenge
- {
- private string _realm = "localhost";
- private string _nonce;
- private string[] _qopOptions = { DigestQop.Auth };
- private bool _stale;
- private int _maxBuffer = 65536;
- private string _charset = "ISO 8859-1";
- private string _algorithm;
- private string[] _cipherOptions;
- private string _authParam;
- private string _rspauth;
-
- #region Properties
- //
- // Properties
- //
-
- public string Realm
- {
- get { return _realm; }
- }
-
- public string Nonce
- {
- get { return _nonce; }
- }
-
- public string[] QopOptions
- {
- get { return _qopOptions; }
- }
-
- public bool Stale
- {
- get { return _stale; }
- }
-
- public int MaxBuffer
- {
- get { return _maxBuffer; }
- set { _maxBuffer = value; }
- }
-
- public string Charset
- {
- get { return _charset; }
- }
-
- public string Algorithm
- {
- get { return _algorithm; }
- }
-
- public string[] CipherOptions
- {
- get { return _cipherOptions; }
- }
-
- public string AuthParam
- {
- get { return _authParam; }
- }
-
- public string Rspauth
- {
- get { return _rspauth; }
- }
-
- #endregion // Properties
-
- public static DigestChallenge Parse(string challenge)
- {
- DigestChallenge parsed = new DigestChallenge();
- StringDictionary parts = ParseParameters(challenge);
- foreach ( string optname in parts.Keys )
- {
- switch ( optname )
- {
- case "realm":
- parsed._realm = parts[optname];
- break;
- case "nonce":
- parsed._nonce = parts[optname];
- break;
- case "qop-options":
- parsed._qopOptions = GetOptions(parts[optname]);
- break;
- case "cipher-opts":
- parsed._cipherOptions = GetOptions(parts[optname]);
- break;
- case "stale":
- parsed._stale = Convert.ToBoolean(parts[optname], CultureInfo.InvariantCulture);
- break;
- case "maxbuf":
- parsed._maxBuffer = Convert.ToInt32(parts[optname], CultureInfo.InvariantCulture);
- break;
- case "charset":
- parsed._charset = parts[optname];
- break;
- case "algorithm":
- parsed._algorithm = parts[optname];
- break;
- case "auth-param":
- parsed._authParam = parts[optname];
- break;
- case "rspauth":
- parsed._rspauth = parts[optname];
- break;
- }
- }
-
- return parsed;
- }
-
-
- public static StringDictionary ParseParameters(string source)
- {
- if ( source == null )
- throw new ArgumentNullException("source");
-
- StringDictionary ret = new StringDictionary();
-
- string remaining = source.Trim();
- while ( remaining.Length > 0 )
- {
- int equals = remaining.IndexOf('=');
- if ( equals < 0 )
- break;
-
- string optname = remaining.Substring(0, equals).Trim();
- remaining = remaining.Substring(equals + 1);
-
- string value = ParseQuoted(ref remaining);
- ret[optname] = value.Trim();
- }
- return ret;
- }
-
- private static string ParseQuoted(ref string str)
- {
- string ns = str.TrimStart();
-
- int start = 0;
- bool quoted = ns[0] == '\"';
- if ( quoted ) start++;
- bool inquotes = quoted;
- bool escaped = false;
-
- int pos = start;
- for ( ; pos < ns.Length; pos++ )
- {
- if ( !inquotes && ns[pos] == ',' )
- break;
-
- // at end of quotes?
- if ( quoted && !escaped && ns[pos] == '\"' )
- inquotes = false;
- // is this char an escape for the next one?
- escaped = inquotes && ns[pos] == '\\';
- }
- // pos has end of string
- string value = ns.Substring(start, pos-start).Trim();
- if ( quoted )
- {
- // remove trailing quote
- value = value.Substring(0, value.Length - 1);
- }
- str = ns.Substring(pos < ns.Length-1 ? pos+1 : pos);
- return value;
- }
-
- private static string[] GetOptions(string value)
- {
- return value.Split(' ');
- }
-
- } // class DigestChallenge
-
-
- /// <summary>
- /// Represents and knows how to write a
- /// digest client response
- /// </summary>
- public class DigestResponse
- {
- private string _username;
- private string _realm;
- private string _nonce;
- private string _cnonce;
- private int _nonceCount;
- private string _qop;
- private string _digestUri;
- private string _response;
- private int _maxBuffer;
- private string _charset;
- private string _cipher;
- private string _authzid;
- private string _authParam;
-
- #region Properties
- //
- // Properties
- //
-
- public string Username
- {
- get { return _username; }
- set { _username = value; }
- }
-
- public string Realm
- {
- get { return _realm; }
- set { _realm = value; }
- }
-
- public string Nonce
- {
- get { return _nonce; }
- set { _nonce = value; }
- }
-
- public string Cnonce
- {
- get { return _cnonce; }
- set { _cnonce = value; }
- }
-
- public int NonceCount
- {
- get { return _nonceCount; }
- set { _nonceCount = value; }
- }
-
- public string Qop
- {
- get { return _qop; }
- set { _qop = value; }
- }
-
- public string DigestUri
- {
- get { return _digestUri; }
- set { _digestUri = value; }
- }
-
- public string Response
- {
- get { return _response; }
- set { _response = value; }
- }
-
- public int MaxBuffer
- {
- get { return _maxBuffer; }
- set { _maxBuffer = value; }
- }
-
- public string Charset
- {
- get { return _charset; }
- set { _charset = value; }
- }
-
- public string Cipher
- {
- get { return _cipher; }
- set { _cipher = value; }
- }
-
- public string Authzid
- {
- get { return _authzid; }
- set { _authzid = value; }
- }
-
- public string AuthParam
- {
- get { return _authParam; }
- set { _authParam = value; }
- }
-
- #endregion // Properties
-
-
- public override string ToString()
- {
- StringBuilder buffer = new StringBuilder();
- Pair(buffer, "username", Username, true);
- Pair(buffer, "realm", Realm, true);
- Pair(buffer, "nonce", Nonce, true);
- Pair(buffer, "cnonce", Cnonce, true);
- string nc = NonceCount.ToString("x8", CultureInfo.InvariantCulture);
- Pair(buffer, "nc", nc, false);
- Pair(buffer, "qop", Qop, false);
- Pair(buffer, "digest-uri", DigestUri, true);
- Pair(buffer, "response", Response, true);
- string maxBuffer = MaxBuffer.ToString(CultureInfo.InvariantCulture);
- Pair(buffer, "maxbuf", maxBuffer, false);
- Pair(buffer, "charset", Charset, false);
- Pair(buffer, "cipher", Cipher, false);
- Pair(buffer, "authzid", Authzid, true);
- Pair(buffer, "auth-param", AuthParam, true);
-
- return buffer.ToString().TrimEnd(',');
- }
-
- private static void Pair(StringBuilder buffer, string name, string value, bool quoted)
- {
- if ( value != null && value.Length > 0 )
- {
- buffer.Append(name);
- buffer.Append('=');
- if ( quoted )
- {
- buffer.Append('\"');
- buffer.Append(value.Replace("\"", "\\\""));
- buffer.Append('\"');
- } else
- {
- buffer.Append(value);
- }
- buffer.Append(',');
- }
- }
-
- } // class DigestResponse
-
-} // namespace Apache.Qpid.Sasl.Mechanisms
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Globalization;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace Apache.Qpid.Sasl.Mechanisms
+{
+
+ /// <summary>
+ /// Implements the DIGEST MD5 authentication mechanism
+ /// as outlined in RFC 2831
+ /// </summary>
+ public class DigestSaslClient : SaslClient
+ {
+ public const string Mechanism = "DIGEST-MD5";
+ private static readonly MD5 _md5 = new MD5CryptoServiceProvider();
+ private int _state;
+ private string _cnonce;
+ private Encoding _encoding = Encoding.UTF8;
+
+ public string Cnonce
+ {
+ get { return _cnonce; }
+ set { _cnonce = value; }
+ }
+
+ public DigestSaslClient(
+ string authid, string serverName, string protocol,
+ IDictionary properties, ISaslCallbackHandler handler)
+ : base(authid, serverName, protocol, properties, handler)
+ {
+ _cnonce = Guid.NewGuid().ToString("N");
+ }
+
+ #region ISaslClient Implementation
+ //
+ // ISaslClient Implementation
+ //
+
+ public override string MechanismName
+ {
+ get { return Mechanism; }
+ }
+
+ public override bool HasInitialResponse
+ {
+ get { return false; }
+ }
+
+ public override byte[] EvaluateChallenge(byte[] challenge)
+ {
+ if ( challenge == null || challenge.Length <= 0 )
+ throw new ArgumentNullException("challenge");
+
+ switch ( _state++ )
+ {
+ case 0: return OnInitialChallenge(challenge);
+ case 1: return OnFinalResponse(challenge);
+ }
+ throw new SaslException("Invalid State for authentication");
+ }
+
+ #endregion // ISaslClient Implementation
+
+
+ #region Private Methods
+ //
+ // Private Methods
+ //
+
+ /// <summary>
+ /// Process the first challenge from the server
+ /// and calculate a response
+ /// </summary>
+ /// <param name="challenge">The server issued challenge</param>
+ /// <returns>Client response</returns>
+ private byte[] OnInitialChallenge(byte[] challenge)
+ {
+ DigestChallenge dch =
+ DigestChallenge.Parse(_encoding.GetString(challenge));
+ // validate input challenge
+ if ( dch.Nonce == null || dch.Nonce.Length == 0 )
+ throw new SaslException("Nonce value missing in server challenge");
+ if ( dch.Algorithm != "md5-sess" )
+ throw new SaslException("Invalid or missing algorithm value in server challenge");
+
+
+ NameCallback nameCB = new NameCallback(AuthorizationId);
+ PasswordCallback pwdCB = new PasswordCallback();
+ RealmCallback realmCB = new RealmCallback(dch.Realm);
+ ISaslCallback[] callbacks = { nameCB, pwdCB, realmCB };
+ Handler.Handle(callbacks);
+
+ DigestResponse response = new DigestResponse();
+ response.Username = nameCB.Text;
+ response.Realm = realmCB.Text;
+ response.Nonce = dch.Nonce;
+ response.Cnonce = Cnonce;
+ response.NonceCount = 1;
+ response.Qop = DigestQop.Auth; // only auth supported for now
+ response.DigestUri = Protocol.ToLower() + "/" + ServerName;
+ response.MaxBuffer = dch.MaxBuffer;
+ response.Charset = dch.Charset;
+ response.Cipher = null; // not supported for now
+ response.Authzid = AuthorizationId;
+ response.AuthParam = dch.AuthParam;
+
+ response.Response = CalculateResponse(
+ nameCB.Text, realmCB.Text, pwdCB.Text,
+ dch.Nonce, response.NonceCount, response.Qop, response.DigestUri
+ );
+
+ return _encoding.GetBytes(response.ToString());
+ }
+
+ /// <summary>
+ /// Process the second server challenge
+ /// </summary>
+ /// <param name="challenge">Server issued challenge</param>
+ /// <returns>The client response</returns>
+ private byte[] OnFinalResponse(byte[] challenge)
+ {
+ DigestChallenge dch =
+ DigestChallenge.Parse(_encoding.GetString(challenge));
+
+ if ( dch.Rspauth == null || dch.Rspauth.Length == 0 )
+ throw new SaslException("Expected 'rspauth' in server challenge not found");
+
+ SetComplete();
+ return new byte[0];
+ }
+
+
+
+ /// <summary>
+ /// Calculate the response field of the client response
+ /// </summary>
+ /// <param name="username">The user name</param>
+ /// <param name="realm">The realm</param>
+ /// <param name="passwd">The user's password</param>
+ /// <param name="nonce">Server nonce value</param>
+ /// <param name="nc">Client nonce count (always 1)</param>
+ /// <param name="qop">Quality of Protection</param>
+ /// <param name="digestUri">Digest-URI</param>
+ /// <returns>The value for the response field</returns>
+ private string CalculateResponse(
+ string username, string realm, string passwd,
+ string nonce, int nc, string qop, string digestUri
+ )
+ {
+ string a1 = CalcHexA1(username, realm, passwd, nonce);
+ string a2 = CalcHexA2(digestUri, qop);
+
+ string ncs = nc.ToString("x8", CultureInfo.InvariantCulture);
+ StringBuilder prekd = new StringBuilder();
+ prekd.Append(a1).Append(':').Append(nonce).Append(':')
+ .Append(ncs).Append(':').Append(Cnonce)
+ .Append(':').Append(qop).Append(':').Append(a2);
+
+ return ToHex(CalcH(_encoding.GetBytes(prekd.ToString())));
+ }
+
+ private string CalcHexA1(
+ string username, string realm,
+ string passwd, string nonce
+ )
+ {
+ bool hasAuthId = AuthorizationId != null && AuthorizationId.Length > 0;
+
+ string premd = username + ":" + realm + ":" + passwd;
+ byte[] temp1 = CalcH(_encoding.GetBytes(premd));
+
+
+ int a1len = 16 + 1 + nonce.Length + 1 + Cnonce.Length;
+ if ( hasAuthId )
+ a1len += 1 + AuthorizationId.Length;
+
+ byte[] buffer = new byte[a1len];
+ Array.Copy(temp1, buffer, temp1.Length);
+
+ string p2 = ":" + nonce + ":" + Cnonce;
+ if ( hasAuthId )
+ p2 += ":" + AuthorizationId;
+
+ byte[] temp2 = _encoding.GetBytes(p2);
+ Array.Copy(temp2, 0, buffer, 16, temp2.Length);
+
+ return ToHex(CalcH(buffer));
+ }
+
+ private string CalcHexA2(string digestUri, string qop)
+ {
+ string a2 = "AUTHENTICATE:" + digestUri;
+ if ( qop != DigestQop.Auth )
+ a2 += ":00000000000000000000000000000000";
+ return ToHex(CalcH(_encoding.GetBytes(a2)));
+ }
+
+ private static byte[] CalcH(byte[] value)
+ {
+ return _md5.ComputeHash(value);
+ }
+
+ #endregion // Private Methods
+
+
+ } // class DigestSaslClient
+
+
+ /// <summary>
+ /// Available QOP options in the DIGEST scheme
+ /// </summary>
+ public sealed class DigestQop
+ {
+ public const string Auth = "auth";
+ public const string AuthInt = "auth-int";
+ public const string AuthConf = "auth-conf";
+ } // class DigestQop
+
+
+ /// <summary>
+ /// Represents and parses a digest server challenge
+ /// </summary>
+ public class DigestChallenge
+ {
+ private string _realm = "localhost";
+ private string _nonce;
+ private string[] _qopOptions = { DigestQop.Auth };
+ private bool _stale;
+ private int _maxBuffer = 65536;
+ private string _charset = "ISO 8859-1";
+ private string _algorithm;
+ private string[] _cipherOptions;
+ private string _authParam;
+ private string _rspauth;
+
+ #region Properties
+ //
+ // Properties
+ //
+
+ public string Realm
+ {
+ get { return _realm; }
+ }
+
+ public string Nonce
+ {
+ get { return _nonce; }
+ }
+
+ public string[] QopOptions
+ {
+ get { return _qopOptions; }
+ }
+
+ public bool Stale
+ {
+ get { return _stale; }
+ }
+
+ public int MaxBuffer
+ {
+ get { return _maxBuffer; }
+ set { _maxBuffer = value; }
+ }
+
+ public string Charset
+ {
+ get { return _charset; }
+ }
+
+ public string Algorithm
+ {
+ get { return _algorithm; }
+ }
+
+ public string[] CipherOptions
+ {
+ get { return _cipherOptions; }
+ }
+
+ public string AuthParam
+ {
+ get { return _authParam; }
+ }
+
+ public string Rspauth
+ {
+ get { return _rspauth; }
+ }
+
+ #endregion // Properties
+
+ public static DigestChallenge Parse(string challenge)
+ {
+ DigestChallenge parsed = new DigestChallenge();
+ StringDictionary parts = ParseParameters(challenge);
+ foreach ( string optname in parts.Keys )
+ {
+ switch ( optname )
+ {
+ case "realm":
+ parsed._realm = parts[optname];
+ break;
+ case "nonce":
+ parsed._nonce = parts[optname];
+ break;
+ case "qop-options":
+ parsed._qopOptions = GetOptions(parts[optname]);
+ break;
+ case "cipher-opts":
+ parsed._cipherOptions = GetOptions(parts[optname]);
+ break;
+ case "stale":
+ parsed._stale = Convert.ToBoolean(parts[optname], CultureInfo.InvariantCulture);
+ break;
+ case "maxbuf":
+ parsed._maxBuffer = Convert.ToInt32(parts[optname], CultureInfo.InvariantCulture);
+ break;
+ case "charset":
+ parsed._charset = parts[optname];
+ break;
+ case "algorithm":
+ parsed._algorithm = parts[optname];
+ break;
+ case "auth-param":
+ parsed._authParam = parts[optname];
+ break;
+ case "rspauth":
+ parsed._rspauth = parts[optname];
+ break;
+ }
+ }
+
+ return parsed;
+ }
+
+
+ public static StringDictionary ParseParameters(string source)
+ {
+ if ( source == null )
+ throw new ArgumentNullException("source");
+
+ StringDictionary ret = new StringDictionary();
+
+ string remaining = source.Trim();
+ while ( remaining.Length > 0 )
+ {
+ int equals = remaining.IndexOf('=');
+ if ( equals < 0 )
+ break;
+
+ string optname = remaining.Substring(0, equals).Trim();
+ remaining = remaining.Substring(equals + 1);
+
+ string value = ParseQuoted(ref remaining);
+ ret[optname] = value.Trim();
+ }
+ return ret;
+ }
+
+ private static string ParseQuoted(ref string str)
+ {
+ string ns = str.TrimStart();
+
+ int start = 0;
+ bool quoted = ns[0] == '\"';
+ if ( quoted ) start++;
+ bool inquotes = quoted;
+ bool escaped = false;
+
+ int pos = start;
+ for ( ; pos < ns.Length; pos++ )
+ {
+ if ( !inquotes && ns[pos] == ',' )
+ break;
+
+ // at end of quotes?
+ if ( quoted && !escaped && ns[pos] == '\"' )
+ inquotes = false;
+ // is this char an escape for the next one?
+ escaped = inquotes && ns[pos] == '\\';
+ }
+ // pos has end of string
+ string value = ns.Substring(start, pos-start).Trim();
+ if ( quoted )
+ {
+ // remove trailing quote
+ value = value.Substring(0, value.Length - 1);
+ }
+ str = ns.Substring(pos < ns.Length-1 ? pos+1 : pos);
+ return value;
+ }
+
+ private static string[] GetOptions(string value)
+ {
+ return value.Split(' ');
+ }
+
+ } // class DigestChallenge
+
+
+ /// <summary>
+ /// Represents and knows how to write a
+ /// digest client response
+ /// </summary>
+ public class DigestResponse
+ {
+ private string _username;
+ private string _realm;
+ private string _nonce;
+ private string _cnonce;
+ private int _nonceCount;
+ private string _qop;
+ private string _digestUri;
+ private string _response;
+ private int _maxBuffer;
+ private string _charset;
+ private string _cipher;
+ private string _authzid;
+ private string _authParam;
+
+ #region Properties
+ //
+ // Properties
+ //
+
+ public string Username
+ {
+ get { return _username; }
+ set { _username = value; }
+ }
+
+ public string Realm
+ {
+ get { return _realm; }
+ set { _realm = value; }
+ }
+
+ public string Nonce
+ {
+ get { return _nonce; }
+ set { _nonce = value; }
+ }
+
+ public string Cnonce
+ {
+ get { return _cnonce; }
+ set { _cnonce = value; }
+ }
+
+ public int NonceCount
+ {
+ get { return _nonceCount; }
+ set { _nonceCount = value; }
+ }
+
+ public string Qop
+ {
+ get { return _qop; }
+ set { _qop = value; }
+ }
+
+ public string DigestUri
+ {
+ get { return _digestUri; }
+ set { _digestUri = value; }
+ }
+
+ public string Response
+ {
+ get { return _response; }
+ set { _response = value; }
+ }
+
+ public int MaxBuffer
+ {
+ get { return _maxBuffer; }
+ set { _maxBuffer = value; }
+ }
+
+ public string Charset
+ {
+ get { return _charset; }
+ set { _charset = value; }
+ }
+
+ public string Cipher
+ {
+ get { return _cipher; }
+ set { _cipher = value; }
+ }
+
+ public string Authzid
+ {
+ get { return _authzid; }
+ set { _authzid = value; }
+ }
+
+ public string AuthParam
+ {
+ get { return _authParam; }
+ set { _authParam = value; }
+ }
+
+ #endregion // Properties
+
+
+ public override string ToString()
+ {
+ StringBuilder buffer = new StringBuilder();
+ Pair(buffer, "username", Username, true);
+ Pair(buffer, "realm", Realm, true);
+ Pair(buffer, "nonce", Nonce, true);
+ Pair(buffer, "cnonce", Cnonce, true);
+ string nc = NonceCount.ToString("x8", CultureInfo.InvariantCulture);
+ Pair(buffer, "nc", nc, false);
+ Pair(buffer, "qop", Qop, false);
+ Pair(buffer, "digest-uri", DigestUri, true);
+ Pair(buffer, "response", Response, true);
+ string maxBuffer = MaxBuffer.ToString(CultureInfo.InvariantCulture);
+ Pair(buffer, "maxbuf", maxBuffer, false);
+ Pair(buffer, "charset", Charset, false);
+ Pair(buffer, "cipher", Cipher, false);
+ Pair(buffer, "authzid", Authzid, true);
+ Pair(buffer, "auth-param", AuthParam, true);
+
+ return buffer.ToString().TrimEnd(',');
+ }
+
+ private static void Pair(StringBuilder buffer, string name, string value, bool quoted)
+ {
+ if ( value != null && value.Length > 0 )
+ {
+ buffer.Append(name);
+ buffer.Append('=');
+ if ( quoted )
+ {
+ buffer.Append('\"');
+ buffer.Append(value.Replace("\"", "\\\""));
+ buffer.Append('\"');
+ } else
+ {
+ buffer.Append(value);
+ }
+ buffer.Append(',');
+ }
+ }
+
+ } // class DigestResponse
+
+} // namespace Apache.Qpid.Sasl.Mechanisms
diff --git a/dotnet/Qpid.Sasl/Mechanisms/ExternalSaslClient.cs b/dotnet/Qpid.Sasl/Mechanisms/ExternalSaslClient.cs
index 5b513bda87..fec0d2d3c2 100644
--- a/dotnet/Qpid.Sasl/Mechanisms/ExternalSaslClient.cs
+++ b/dotnet/Qpid.Sasl/Mechanisms/ExternalSaslClient.cs
@@ -1,69 +1,69 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Text;
-
-namespace Apache.Qpid.Sasl.Mechanisms
-{
- /// <summary>
- /// Implements the EXTERNAL authentication mechanism
- /// as outlined in RFC 2222
- /// </summary>
- public class ExternalSaslClient : SaslClient
- {
- public const string Mechanism = "EXTERNAL";
-
- public ExternalSaslClient(
- string authid, IDictionary properties,
- ISaslCallbackHandler handler)
- : base(authid, null, null, properties, handler)
- {
- }
-
- #region ISaslClient Implementation
- //
- // ISaslClient Implementation
- //
-
- public override string MechanismName
- {
- get { return Mechanism; }
- }
-
- public override bool HasInitialResponse
- {
- get { return true; }
- }
-
- public override byte[] EvaluateChallenge(byte[] challenge)
- {
- // ignore challenge
- SetComplete();
- return Encoding.UTF8.GetBytes(AuthorizationId);
- }
-
- #endregion // ISaslClient Implementation
-
- } // class ExternalSaslClient
-
-} // namespace Apache.Qpid.Sasl.Mechanisms
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Text;
+
+namespace Apache.Qpid.Sasl.Mechanisms
+{
+ /// <summary>
+ /// Implements the EXTERNAL authentication mechanism
+ /// as outlined in RFC 2222
+ /// </summary>
+ public class ExternalSaslClient : SaslClient
+ {
+ public const string Mechanism = "EXTERNAL";
+
+ public ExternalSaslClient(
+ string authid, IDictionary properties,
+ ISaslCallbackHandler handler)
+ : base(authid, null, null, properties, handler)
+ {
+ }
+
+ #region ISaslClient Implementation
+ //
+ // ISaslClient Implementation
+ //
+
+ public override string MechanismName
+ {
+ get { return Mechanism; }
+ }
+
+ public override bool HasInitialResponse
+ {
+ get { return true; }
+ }
+
+ public override byte[] EvaluateChallenge(byte[] challenge)
+ {
+ // ignore challenge
+ SetComplete();
+ return Encoding.UTF8.GetBytes(AuthorizationId);
+ }
+
+ #endregion // ISaslClient Implementation
+
+ } // class ExternalSaslClient
+
+} // namespace Apache.Qpid.Sasl.Mechanisms
diff --git a/dotnet/Qpid.Sasl/Mechanisms/PlainSaslClient.cs b/dotnet/Qpid.Sasl/Mechanisms/PlainSaslClient.cs
index 3addeb2e83..534be171b7 100644
--- a/dotnet/Qpid.Sasl/Mechanisms/PlainSaslClient.cs
+++ b/dotnet/Qpid.Sasl/Mechanisms/PlainSaslClient.cs
@@ -1,81 +1,81 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Text;
-
-namespace Apache.Qpid.Sasl.Mechanisms
-{
-
- /// <summary>
- /// Implements the PLAIN authentication mechanism
- /// as outlined in RFC 4616
- /// </summary>
- public class PlainSaslClient : SaslClient
- {
- public const string Mechanism = "PLAIN";
-
- public PlainSaslClient(
- string authid, IDictionary properties,
- ISaslCallbackHandler handler)
- : base(authid, null, null, properties, handler)
- {
- }
-
- #region ISaslClient Implementation
- //
- // ISaslClient Implementation
- //
-
- public override string MechanismName
- {
- get { return Mechanism; }
- }
-
- public override bool HasInitialResponse
- {
- get { return true; }
- }
-
- public override byte[] EvaluateChallenge(byte[] challenge)
- {
- // ignore challenge
-
- NameCallback nameCB = new NameCallback();
- PasswordCallback pwdCB = new PasswordCallback();
- ISaslCallback[] callbacks = { nameCB, pwdCB };
- Handler.Handle(callbacks);
-
- string username = nameCB.Text;
- string authid = AuthorizationId;
- string passwd = pwdCB.Text;
-
- string response =
- string.Format("{0}\0{1}\0{2}", authid, username, passwd);
- SetComplete();
- return Encoding.UTF8.GetBytes(response);
- }
-
- #endregion // ISaslClient Implementation
-
- } // class PlainSaslClient
-} // namespace Apache.Qpid.Sasl.Mechanisms
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Text;
+
+namespace Apache.Qpid.Sasl.Mechanisms
+{
+
+ /// <summary>
+ /// Implements the PLAIN authentication mechanism
+ /// as outlined in RFC 4616
+ /// </summary>
+ public class PlainSaslClient : SaslClient
+ {
+ public const string Mechanism = "PLAIN";
+
+ public PlainSaslClient(
+ string authid, IDictionary properties,
+ ISaslCallbackHandler handler)
+ : base(authid, null, null, properties, handler)
+ {
+ }
+
+ #region ISaslClient Implementation
+ //
+ // ISaslClient Implementation
+ //
+
+ public override string MechanismName
+ {
+ get { return Mechanism; }
+ }
+
+ public override bool HasInitialResponse
+ {
+ get { return true; }
+ }
+
+ public override byte[] EvaluateChallenge(byte[] challenge)
+ {
+ // ignore challenge
+
+ NameCallback nameCB = new NameCallback();
+ PasswordCallback pwdCB = new PasswordCallback();
+ ISaslCallback[] callbacks = { nameCB, pwdCB };
+ Handler.Handle(callbacks);
+
+ string username = nameCB.Text;
+ string authid = AuthorizationId;
+ string passwd = pwdCB.Text;
+
+ string response =
+ string.Format("{0}\0{1}\0{2}", authid, username, passwd);
+ SetComplete();
+ return Encoding.UTF8.GetBytes(response);
+ }
+
+ #endregion // ISaslClient Implementation
+
+ } // class PlainSaslClient
+} // namespace Apache.Qpid.Sasl.Mechanisms
diff --git a/dotnet/Qpid.Sasl/Properties/AssemblyInfo.cs b/dotnet/Qpid.Sasl/Properties/AssemblyInfo.cs
index 8b4f9ce230..5245b97d1f 100644
--- a/dotnet/Qpid.Sasl/Properties/AssemblyInfo.cs
+++ b/dotnet/Qpid.Sasl/Properties/AssemblyInfo.cs
@@ -1,37 +1,57 @@
-using System;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Apache.Qpid.Sasl")]
-[assembly: AssemblyDescription("Built from svn revision number: ")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Apache Software Foundation")]
-[assembly: AssemblyProduct("Apache.Qpid.Sasl")]
-[assembly: AssemblyCopyright("Apache Software Foundation")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("27ea23e4-6f84-4a54-8f1f-5725e6d767cc")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Revision and Build Numbers
-// by using the '*' as shown below:
-[assembly: AssemblyVersion("2.1.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
-[assembly: CLSCompliant(true)]
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Apache.Qpid.Sasl")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("Apache.Qpid.Sasl")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("27ea23e4-6f84-4a54-8f1f-5725e6d767cc")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: CLSCompliant(true)]
diff --git a/dotnet/Qpid.Sasl/Qpid.Sasl.csproj b/dotnet/Qpid.Sasl/Qpid.Sasl.csproj
index 33619f2495..8c1d568aa3 100644
--- a/dotnet/Qpid.Sasl/Qpid.Sasl.csproj
+++ b/dotnet/Qpid.Sasl/Qpid.Sasl.csproj
@@ -1,64 +1,73 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <PropertyGroup>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProductVersion>8.0.50727</ProductVersion>
- <SchemaVersion>2.0</SchemaVersion>
- <ProjectGuid>{1465B0EE-6452-42A6-AB73-B2F9EABEEE75}</ProjectGuid>
- <OutputType>Library</OutputType>
- <AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>Apache.Qpid.Sasl</RootNamespace>
- <AssemblyName>Apache.Qpid.Sasl</AssemblyName>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>..\bin\net-2.0\debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- <UseVSHostingProcess>true</UseVSHostingProcess>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>pdbonly</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>bin\Release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <ItemGroup>
- <Reference Include="System" />
- <Reference Include="System.Data" />
- <Reference Include="System.Xml" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="Callbacks.cs" />
- <Compile Include="Configuration\SaslConfiguration.cs" />
- <Compile Include="Configuration\SaslConfigurationSectionHandler.cs" />
- <Compile Include="MD5HMAC.cs" />
- <Compile Include="Mechanisms\ExternalSaslClient.cs" />
- <Compile Include="SaslException.cs" />
- <Compile Include="Mechanisms\AnonymousSaslClient.cs" />
- <Compile Include="Mechanisms\DigestSaslClient.cs" />
- <Compile Include="Sasl.cs" />
- <Compile Include="DefaultClientFactory.cs" />
- <Compile Include="ISaslCallbackHandler.cs" />
- <Compile Include="ISaslClientFactory.cs" />
- <Compile Include="Mechanisms\CramMD5SaslClient.cs" />
- <Compile Include="SaslProperties.cs" />
- <Compile Include="ISaslClient.cs" />
- <Compile Include="Mechanisms\PlainSaslClient.cs" />
- <Compile Include="SaslClient.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- </ItemGroup>
- <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
- <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
- Other similar extension points exist, see Microsoft.Common.targets.
- <Target Name="BeforeBuild">
- </Target>
- <Target Name="AfterBuild">
- </Target>
- -->
-</Project> \ No newline at end of file
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.50727</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{1465B0EE-6452-42A6-AB73-B2F9EABEEE75}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Apache.Qpid.Sasl</RootNamespace>
+ <AssemblyName>Apache.Qpid.Sasl</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\bin\net-2.0\debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <UseVSHostingProcess>true</UseVSHostingProcess>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="**\*.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/dotnet/Qpid.Sasl/Sasl.cs b/dotnet/Qpid.Sasl/Sasl.cs
index 5a744a30d9..2f7bacb939 100644
--- a/dotnet/Qpid.Sasl/Sasl.cs
+++ b/dotnet/Qpid.Sasl/Sasl.cs
@@ -1,115 +1,115 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Configuration;
-using System.Text;
-
-using Apache.Qpid.Sasl.Configuration;
-
-namespace Apache.Qpid.Sasl
-{
- /// <summary>
- /// Static class used to access the SASL functionality.
- /// The core SASL mechanism is described in RFC 2222.
- /// </summary>
- /// <remarks>
- /// Only client side mechanisms are implemented.
- /// <para>
- /// New client side factories can be added programatically using the
- /// RegisterClientFactory method, or through the application
- /// configuration file, like this:
- /// </para>
- /// <example><![CDATA[
- /// <configuration>
- /// <configSections>
- /// <section name="qpid.sasl" type="Apache.Qpid.Sasl.Configuration.SaslConfigurationSectionHandler, Apache.Qpid.Sasl"/>
- /// </configSections>
- ///
- /// <qpid.sasl>
- /// <clientFactories>
- /// <add type="Apache.Qpid.Sasl.Tests.TestClientFactory, Apache.Qpid.Sasl.Tests"/>
- /// </clientFactories>
- /// </qpid.sasl>
- /// </configuration>
- /// ]]></example>
- /// </remarks>
- public sealed class Sasl
- {
- private static IList _clientFactories;
-
-
- static Sasl()
- {
- SaslConfiguration config = SaslConfiguration.GetConfiguration();
- _clientFactories = config.ClientFactories;
- }
- private Sasl()
- {
- }
-
- public static ISaslClient CreateClient(
- string[] mechanisms, string authorizationId,
- string protocol, string serverName,
- IDictionary props, ISaslCallbackHandler handler
- )
- {
- ISaslClientFactory factory = FindFactory(mechanisms, props);
- if ( factory == null )
- return null;
-
- return factory.CreateClient (
- mechanisms, authorizationId,
- protocol, serverName, props, handler
- );
- }
-
- public static void RegisterClientFactory(ISaslClientFactory factory)
- {
- lock ( _clientFactories )
- {
- _clientFactories.Add(factory);
- }
- }
-
- private static ISaslClientFactory FindFactory(string[] mechanisms, IDictionary props)
- {
- lock ( _clientFactories )
- {
- foreach ( ISaslClientFactory factory in _clientFactories )
- {
- string[] mechs = factory.GetSupportedMechanisms(props);
- foreach ( string m1 in mechs )
- {
- foreach (string m2 in mechanisms )
- {
- if ( m1 == m2 )
- return factory;
- }
- }
- }
- return null;
- }
- }
- } // class Sasl
-
-} // namespace Apache.Qpid.Sasl.Mechanisms
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Configuration;
+using System.Text;
+
+using Apache.Qpid.Sasl.Configuration;
+
+namespace Apache.Qpid.Sasl
+{
+ /// <summary>
+ /// Static class used to access the SASL functionality.
+ /// The core SASL mechanism is described in RFC 2222.
+ /// </summary>
+ /// <remarks>
+ /// Only client side mechanisms are implemented.
+ /// <para>
+ /// New client side factories can be added programatically using the
+ /// RegisterClientFactory method, or through the application
+ /// configuration file, like this:
+ /// </para>
+ /// <example><![CDATA[
+ /// <configuration>
+ /// <configSections>
+ /// <section name="qpid.sasl" type="Apache.Qpid.Sasl.Configuration.SaslConfigurationSectionHandler, Apache.Qpid.Sasl"/>
+ /// </configSections>
+ ///
+ /// <qpid.sasl>
+ /// <clientFactories>
+ /// <add type="Apache.Qpid.Sasl.Tests.TestClientFactory, Apache.Qpid.Sasl.Tests"/>
+ /// </clientFactories>
+ /// </qpid.sasl>
+ /// </configuration>
+ /// ]]></example>
+ /// </remarks>
+ public sealed class Sasl
+ {
+ private static IList _clientFactories;
+
+
+ static Sasl()
+ {
+ SaslConfiguration config = SaslConfiguration.GetConfiguration();
+ _clientFactories = config.ClientFactories;
+ }
+ private Sasl()
+ {
+ }
+
+ public static ISaslClient CreateClient(
+ string[] mechanisms, string authorizationId,
+ string protocol, string serverName,
+ IDictionary props, ISaslCallbackHandler handler
+ )
+ {
+ ISaslClientFactory factory = FindFactory(mechanisms, props);
+ if ( factory == null )
+ return null;
+
+ return factory.CreateClient (
+ mechanisms, authorizationId,
+ protocol, serverName, props, handler
+ );
+ }
+
+ public static void RegisterClientFactory(ISaslClientFactory factory)
+ {
+ lock ( _clientFactories )
+ {
+ _clientFactories.Add(factory);
+ }
+ }
+
+ private static ISaslClientFactory FindFactory(string[] mechanisms, IDictionary props)
+ {
+ lock ( _clientFactories )
+ {
+ foreach ( ISaslClientFactory factory in _clientFactories )
+ {
+ string[] mechs = factory.GetSupportedMechanisms(props);
+ foreach ( string m1 in mechs )
+ {
+ foreach (string m2 in mechanisms )
+ {
+ if ( m1 == m2 )
+ return factory;
+ }
+ }
+ }
+ return null;
+ }
+ }
+ } // class Sasl
+
+} // namespace Apache.Qpid.Sasl.Mechanisms
diff --git a/dotnet/Qpid.Sasl/SaslClient.cs b/dotnet/Qpid.Sasl/SaslClient.cs
index 1390b1b352..a22013181b 100644
--- a/dotnet/Qpid.Sasl/SaslClient.cs
+++ b/dotnet/Qpid.Sasl/SaslClient.cs
@@ -1,145 +1,145 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Globalization;
-using System.Text;
-
-namespace Apache.Qpid.Sasl
-{
- public abstract class SaslClient : ISaslClient
- {
- private bool _isComplete;
- private IDictionary _properties;
- private string _authorizationId;
- private string _serverName;
- private string _protocol;
- private ISaslCallbackHandler _handler;
-
- protected string AuthorizationId
- {
- get { return _authorizationId; }
- }
- protected string ServerName
- {
- get { return _serverName; }
- }
-
- protected string Protocol
- {
- get { return _protocol; }
- }
-
- protected ISaslCallbackHandler Handler
- {
- get { return _handler; }
- }
-
- protected IDictionary Properties
- {
- get { return _properties; }
- }
-
- protected SaslClient(
- string authid, string serverName,
- string protocol, IDictionary properties,
- ISaslCallbackHandler handler)
- {
- if ( properties == null )
- throw new ArgumentNullException("properties");
- if ( handler == null )
- throw new ArgumentNullException("handler");
-
- _authorizationId = authid==null ? "" : authid;
- _serverName = serverName;
- _protocol = protocol;
- _properties = properties;
- _handler = handler;
-
- if ( _serverName == null || _serverName.Length == 0 )
- {
- _serverName = System.Net.Dns.GetHostName();
- }
- }
-
-
-
-
- #region ISaslClient Implementation
- //
- // ISaslClient Implementation
- //
-
- public abstract string MechanismName { get; }
-
- public abstract bool HasInitialResponse { get; }
-
- public bool IsComplete
- {
- get { return _isComplete; }
- }
-
- public abstract byte[] EvaluateChallenge(byte[] challenge);
-
- public virtual object GetNegotiatedProperty(string propName)
- {
- return null;
- }
-
- public virtual byte[] Unwrap(byte[] buffer, int offset, int length)
- {
- throw new NotImplementedException();
- }
-
- public virtual byte[] Wrap(byte[] buffer, int offset, int lenght)
- {
- throw new NotImplementedException();
- }
-
- #endregion // ISaslClient Implementation
-
-
- #region Helper Methods
- //
- // Helper Methods
- //
-
- protected void SetComplete()
- {
- _isComplete = true;
- }
-
- protected static string ToHex(byte[] buffer)
- {
- StringBuilder builder = new StringBuilder();
- foreach ( byte b in buffer )
- {
- builder.Append(b.ToString("x2", CultureInfo.InvariantCulture));
- }
- return builder.ToString();
- }
-
- #endregion // Helper Methods
-
- } // class SaslClient
-
-} // namespace Apache.Qpid.Sasl.Mechanisms
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Globalization;
+using System.Text;
+
+namespace Apache.Qpid.Sasl
+{
+ public abstract class SaslClient : ISaslClient
+ {
+ private bool _isComplete;
+ private IDictionary _properties;
+ private string _authorizationId;
+ private string _serverName;
+ private string _protocol;
+ private ISaslCallbackHandler _handler;
+
+ protected string AuthorizationId
+ {
+ get { return _authorizationId; }
+ }
+ protected string ServerName
+ {
+ get { return _serverName; }
+ }
+
+ protected string Protocol
+ {
+ get { return _protocol; }
+ }
+
+ protected ISaslCallbackHandler Handler
+ {
+ get { return _handler; }
+ }
+
+ protected IDictionary Properties
+ {
+ get { return _properties; }
+ }
+
+ protected SaslClient(
+ string authid, string serverName,
+ string protocol, IDictionary properties,
+ ISaslCallbackHandler handler)
+ {
+ if ( properties == null )
+ throw new ArgumentNullException("properties");
+ if ( handler == null )
+ throw new ArgumentNullException("handler");
+
+ _authorizationId = authid==null ? "" : authid;
+ _serverName = serverName;
+ _protocol = protocol;
+ _properties = properties;
+ _handler = handler;
+
+ if ( _serverName == null || _serverName.Length == 0 )
+ {
+ _serverName = System.Net.Dns.GetHostName();
+ }
+ }
+
+
+
+
+ #region ISaslClient Implementation
+ //
+ // ISaslClient Implementation
+ //
+
+ public abstract string MechanismName { get; }
+
+ public abstract bool HasInitialResponse { get; }
+
+ public bool IsComplete
+ {
+ get { return _isComplete; }
+ }
+
+ public abstract byte[] EvaluateChallenge(byte[] challenge);
+
+ public virtual object GetNegotiatedProperty(string propName)
+ {
+ return null;
+ }
+
+ public virtual byte[] Unwrap(byte[] buffer, int offset, int length)
+ {
+ throw new NotImplementedException();
+ }
+
+ public virtual byte[] Wrap(byte[] buffer, int offset, int lenght)
+ {
+ throw new NotImplementedException();
+ }
+
+ #endregion // ISaslClient Implementation
+
+
+ #region Helper Methods
+ //
+ // Helper Methods
+ //
+
+ protected void SetComplete()
+ {
+ _isComplete = true;
+ }
+
+ protected static string ToHex(byte[] buffer)
+ {
+ StringBuilder builder = new StringBuilder();
+ foreach ( byte b in buffer )
+ {
+ builder.Append(b.ToString("x2", CultureInfo.InvariantCulture));
+ }
+ return builder.ToString();
+ }
+
+ #endregion // Helper Methods
+
+ } // class SaslClient
+
+} // namespace Apache.Qpid.Sasl.Mechanisms
diff --git a/dotnet/Qpid.Sasl/SaslException.cs b/dotnet/Qpid.Sasl/SaslException.cs
index 8f6e00a7ba..d770ee63fd 100644
--- a/dotnet/Qpid.Sasl/SaslException.cs
+++ b/dotnet/Qpid.Sasl/SaslException.cs
@@ -1,56 +1,56 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Runtime.Serialization;
-using System.Text;
-
-namespace Apache.Qpid.Sasl
-{
- /// <summary>
- /// Reports an exception during the processing of an SASL
- /// Operation. Only used for authentication-relared errors
- /// </summary>
- [Serializable]
- public class SaslException : Exception
- {
- public SaslException()
- {
- }
-
- public SaslException(string message)
- : base(message)
- {
- }
- public SaslException(string message, Exception innerException)
- : base(message, innerException)
- {
- }
-
- protected SaslException(SerializationInfo info, StreamingContext ctxt)
- : base(info, ctxt)
- {
- }
-
- } // class SaslException
-
-} // namespace Apache.Qpid.Sasl.Mechanisms
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Runtime.Serialization;
+using System.Text;
+
+namespace Apache.Qpid.Sasl
+{
+ /// <summary>
+ /// Reports an exception during the processing of an SASL
+ /// Operation. Only used for authentication-relared errors
+ /// </summary>
+ [Serializable]
+ public class SaslException : Exception
+ {
+ public SaslException()
+ {
+ }
+
+ public SaslException(string message)
+ : base(message)
+ {
+ }
+ public SaslException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+
+ protected SaslException(SerializationInfo info, StreamingContext ctxt)
+ : base(info, ctxt)
+ {
+ }
+
+ } // class SaslException
+
+} // namespace Apache.Qpid.Sasl.Mechanisms
diff --git a/dotnet/Qpid.Sasl/SaslProperties.cs b/dotnet/Qpid.Sasl/SaslProperties.cs
index 0658acda21..f9ad1c68cd 100644
--- a/dotnet/Qpid.Sasl/SaslProperties.cs
+++ b/dotnet/Qpid.Sasl/SaslProperties.cs
@@ -1,42 +1,42 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-using System;
-using System.Collections;
-using System.Text;
-
-namespace Apache.Qpid.Sasl
-{
- public sealed class SaslProperties
- {
- public const string PolicyNoPlainText = "NOPLAINTEXT";
- public const string PolicyNoActive = "NOACTIVE";
- public const string PolicyNoDictionary = "NODICTIONARY";
- public const string PolicyNoAnonymous = "NOANONYMOUS";
- public const string PolicyForwardSecrecy = "FORWARD_SECRECY";
- public const string PolicyPassCredentials = "PASS_CREDENTIALS";
-
- public const string Qop = "QOP";
- public const string Strength = "STRENGTH";
-
- } // class SaslProperties
-
-} // namespace Apache.Qpid.Sasl.Mechanisms
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Text;
+
+namespace Apache.Qpid.Sasl
+{
+ public sealed class SaslProperties
+ {
+ public const string PolicyNoPlainText = "NOPLAINTEXT";
+ public const string PolicyNoActive = "NOACTIVE";
+ public const string PolicyNoDictionary = "NODICTIONARY";
+ public const string PolicyNoAnonymous = "NOANONYMOUS";
+ public const string PolicyForwardSecrecy = "FORWARD_SECRECY";
+ public const string PolicyPassCredentials = "PASS_CREDENTIALS";
+
+ public const string Qop = "QOP";
+ public const string Strength = "STRENGTH";
+
+ } // class SaslProperties
+
+} // namespace Apache.Qpid.Sasl.Mechanisms
diff --git a/dotnet/Qpid.Sasl/default.build b/dotnet/Qpid.Sasl/default.build
index 5b44d6b9c4..57049ee2ee 100644
--- a/dotnet/Qpid.Sasl/default.build
+++ b/dotnet/Qpid.Sasl/default.build
@@ -1,24 +1,45 @@
-<?xml version="1.0"?>
-<project name="Apache.Qpid.Sasl" default="build">
- <!--
- Properties that come from master build file
- - build.dir: root directory for build
- - build.debug: true if building debug release
- - build.defines: variables to define during build
- -->
-
- <target name="build">
- <csc target="library"
- define="${build.defines}"
- debug="${build.debug}"
- output="${build.dir}/${project::get-name()}.dll">
-
- <sources>
- <include name="**/*.cs" />
- </sources>
- <references>
- </references>
- </csc>
- </target>
-</project>
-
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="Apache.Qpid.Sasl" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="library"
+ define="${build.defines}"
+ debug="${build.debug}"
+ output="${build.dir}/${project::get-name()}.dll">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ </references>
+ </csc>
+ </target>
+</project>
+
diff --git a/dotnet/README.txt b/dotnet/README.txt
index 1c0be05c11..0199ad6410 100644
--- a/dotnet/README.txt
+++ b/dotnet/README.txt
@@ -1,61 +1,58 @@
Info
====
-AMQP version currently 0.8 (see /Qpid.Common/amqp.xml)
+There are two separate .NET clients: one that implements AMQP 0-8 (and
+can communicate with the Java broker) and another that implements
+0-10 (and can communicate with the C++ broker).
+This README contains instructions for building the 0-8 client.
+
+Instructions for building and installing the 0-10 client are located in client-010/README.txt.
Setup
=====
-Install:
- Microsoft Visual Studio 2005 (VS2005)
- NAnt 0.85 - only required for builds outside VS2005 (.net 1.1, .net 2.0, mono 2.0)
- Ant 1.6.5
- Cygwin (or alternatively build via cmd but alter instructions below accordingly)
-
-Set up PATH to include Nant.exe:
+Essential:
- $ PATH=/cygdrive/c/WINDOWS/Microsoft.NET/Framework/v2.0.50727:$PATH
+ .NET 2.0 or later
+ Ant 1.6.5 (Java build tool, http://ant.apache.org)
+
+Either:
+ NAnt 0.85 - only required for builds outside Visual Studio
+OR
+ Microsoft Visual Studio 2008 (VS2008)
+
+Ensure that your PATH includes ant, e.g.:
-Set up PATH to include ant:
+ $ PATH=c:\java\ant\bin:%PATH%
+
+If using nant, set up PATH to include Nant.exe, e.g.:
- $ PATH=$ANT_HOME/bin:$PATH
+ $ set PATH=C:\dotnet\nant\bin;%PATH%
+If using msbuild, it is recommended to use a "Visual Studio Command Prompt"
Building
========
-Generate framing from /Qpid.Common/amqp.xml specificiation file:
+Generate framing from /Qpid.Common/amqp.xml specification file by running this script:
- $ build-framing
+ $ build-framing.bat
Alternatively, just switch to /Qpid.Common and run "ant" there.
-You can build from Visual Studio 2005 normally. Alternatively, you
-can build debug releases for any supported framework from the
-command line using Nant:
-
-To build .NET 2.0 executables (to bin/net-2.0):
-
- $ build-dotnet20
-
-To build .NET 1.1 executables (to bin/net-1.1):
+You can build from Visual Studio 2008 or from the command-line by running msbuild.
- $ build-dotnet11
-
-To build for Mono on Linux (to bin/mono-2.0):
-
- $ build-mono
+The script build-msbuild.bat provides some standard options to do a full build.
+If you are using nant, the script build-nant.bat contains standard arguments that do a full build.
+
+To build for Mono on Linux (to bin/mono-2.0) the build-mono shell script is provided.
Releasing
=========
-For .NET 1.1
-
- $ release net-1.1
-
-Generates ./bin/net-1.1/release/Qpid.NET-net-1.1-yyyyMMdd.zip
+nant can be used to create a release zip archive. A script is provided:
For .NET 2.0
diff --git a/dotnet/RELEASE_NOTES.txt b/dotnet/RELEASE_NOTES.txt
index 6b1295b03c..237f0278d9 100644
--- a/dotnet/RELEASE_NOTES.txt
+++ b/dotnet/RELEASE_NOTES.txt
@@ -1,9 +1,8 @@
-Apache Incubator Qpid .NET M2 Release Notes
+Apache Incubator Qpid .NET M4 Release Notes
-------------------------------------------
-The Qpid M2 release contains support the for AMQP 0-8 specification.
-You can access the 0-8 specification using the following link.
-http://www.amqp.org/tikiwiki/tiki-index.php?page=Download
+The Qpid M4 release contains seperate clients that support the AMQP
+0-10 and AMQP 0-8 protocols.
For full details of Qpid capabilities, as they currently stand, see our
detailed project documentation at:
@@ -21,48 +20,7 @@ You can view the outstanding task list for Qpid by visiting our JIRA:
http://issues.apache.org/jira/browse/QPID
-M2 Tasks Completed
--------------------
-
-The set of JIRA tasks completed as part of the M2 effort is available at:
-https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12310520&styleName=Html&version=12312116
-
-
-Here is a filtered list of JIRA items for the .NET Client
-
-Test QPID-435 HeadersExchangeTest fails
-
-New Feature QPID-136 implement prefetch
-New Feature QPID-291 Support SASL authentication in .NET client
-
-Improvement QPID-246 Custom Exception types should be serializable
-Improvement QPID-312 Inconsistency in naming conventions
-Improvement QPID-338 Integrate JDK 1.4 compatible SASL API Library & CRAM-MD5 Implementation
-Improvement QPID-345 Implement Blocking receive modes in BasicMessageConsumer
-Improvement QPID-398 Implement SSL/TLS support in the .NET Client
-Improvement QPID-452 Improve Message Classes and Message Creation APIs
-Improvement QPID-489 Create new build system for .NET Client
-Improvement QPID-490 Improve AmqChannel.PurgeQueue() and AmqChannel.DeleteQueue() methods
-Improvement QPID-495 Implement default timeouts for AttainState and SyncWriter operations
-
-Bug QPID-546 .Net does not handle reply to fields correctly.
-Bug QPID-237 Build broken because of missing IBytesMessage.Reset() impl in Qpid.Client.Message.QpidBytesMessage
-Bug QPID-238 Wrong call to string.Split() in AbstractQmsMessage.GetExchangeName()
-Bug QPID-239 Use of assembly name vs. assembly path in AMQConnection.LoadTransportFromAssembly()
-Bug QPID-250 .Net client does not use specs from the specs directory.
-Bug QPID-257 Test HeadersMatchingConsumer#Test fails.
-Bug QPID-258 Test ServiceProvidingClient#Test fails.
-Bug QPID-259 Test ServiceRequestingClient#SendMessages fails.
-Bug QPID-267 AMQConnection#Stop throws NotImplementedException
-Bug QPID-284 .Net build broekn due to missing HeadersMatchingProducers
-Bug QPID-335 .NET Client messages not interoperable with Java client
-Bug QPID-384 Update AMQConstant.cs to match response codes in AMQP 0.9
-Bug QPID-385 Failover support sometimes masks authentication errors
-Bug QPID-441 .NET Client does not properly handle bounced (undeliverable) messages
-Bug QPID-456 .NET Client doesn't enforce virtual host names start with '/'
-Bug QPID-467 Complete Interop Testing
-Bug QPID-485 AmqBrokerInfo.Equals method doesn't get the expected result
-Bug QPID-486 .NET Client SASL implementation chooses first matching mechanism instead of stronger
-Bug QPID-487 The QpidConnectionInfo.ToString() method returns a wrong value
-Bug QPID-492 Race condition causes received messages to read wrong headers and/or body
+Changes since M3
+----------------
+The major change since M3 has been the addition of a new client which implements 0-10 support.
diff --git a/dotnet/TODO.txt b/dotnet/TODO.txt
deleted file mode 100644
index d79fb8f5f7..0000000000
--- a/dotnet/TODO.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-
-* Implement durable subscriptions.
-* Implement prefetching
-* support multiple versions of AMQP from the same client.
-* Add new unit and integration tests
-* Implement Transactions
diff --git a/dotnet/TestClient/Program.cs b/dotnet/TestClient/Program.cs
index 10e7975fd3..f4b2db568e 100644
--- a/dotnet/TestClient/Program.cs
+++ b/dotnet/TestClient/Program.cs
@@ -1,10 +1,30 @@
-namespace TopicListener
-{
- class Program
- {
- static void Main(string[] args)
- {
- Apache.Qpid.Integration.Tests.interop.TestClient.Main(args);
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+namespace TopicListener
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ Apache.Qpid.Integration.Tests.interop.TestClient.Main(args);
+ }
+ }
+}
diff --git a/dotnet/TestClient/Properties/AssemblyInfo.cs b/dotnet/TestClient/Properties/AssemblyInfo.cs
index f230a443f0..e8ffbc5aba 100644
--- a/dotnet/TestClient/Properties/AssemblyInfo.cs
+++ b/dotnet/TestClient/Properties/AssemblyInfo.cs
@@ -1,33 +1,53 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("TestClient")]
-[assembly: AssemblyDescription("Built from svn revision number: ")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Apache Software Foundation")]
-[assembly: AssemblyProduct("TestClient")]
-[assembly: AssemblyCopyright("Apache Software Foundation")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("1c2db1cd-239f-495a-b6b4-c815ea534489")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-[assembly: AssemblyVersion("2.1.0.0")]
-[assembly: AssemblyFileVersion("1.0.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.
+ *
+ */
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("TestClient")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("TestClient")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("1c2db1cd-239f-495a-b6b4-c815ea534489")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/TestClient/TestClient.csproj b/dotnet/TestClient/TestClient.csproj
index b00994b265..3b54a27b44 100644
--- a/dotnet/TestClient/TestClient.csproj
+++ b/dotnet/TestClient/TestClient.csproj
@@ -1,89 +1,115 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <PropertyGroup>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProductVersion>8.0.50727</ProductVersion>
- <SchemaVersion>2.0</SchemaVersion>
- <ProjectGuid>{9A112DF2-146F-4CF4-919B-9D3BE7D088E9}</ProjectGuid>
- <OutputType>Exe</OutputType>
- <AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>TestClient</RootNamespace>
- <AssemblyName>TestClient</AssemblyName>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>..\bin\net-2.0\debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>pdbonly</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>..\bin\net-2.0\release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <ItemGroup>
- <Reference Include="System" />
- <Reference Include="System.Data" />
- <Reference Include="System.Xml" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="Program.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- </ItemGroup>
- <ItemGroup>
- <ProjectReference Include="..\Qpid.Buffer.Tests\Qpid.Buffer.Tests.csproj">
- <Project>{74640962-99D0-4D06-B57A-9CD66517CF52}</Project>
- <Name>Qpid.Buffer.Tests</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Buffer\Qpid.Buffer.csproj">
- <Project>{44384DF2-B0A4-4580-BDBC-EE4BAA87D995}</Project>
- <Name>Qpid.Buffer</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Client.Tests\Qpid.Client.Tests.csproj">
- <Project>{BA1B0032-4CE6-40DD-A2DC-119F0FFA0A1D}</Project>
- <Name>Qpid.Client.Tests</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Client\Qpid.Client.csproj">
- <Project>{68987C05-3768-452C-A6FC-6BA1D372852F}</Project>
- <Name>Qpid.Client</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Codec\Qpid.Codec.csproj">
- <Project>{22D0D0C2-77AF-4DE3-B456-7FF3893F9F88}</Project>
- <Name>Qpid.Codec</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Common.Tests\Qpid.Common.Tests.csproj">
- <Project>{F83624B0-762B-4D82-900D-FF4C1B36E36E}</Project>
- <Name>Qpid.Common.Tests</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Common\Qpid.Common.csproj">
- <Project>{77064C42-24D2-4CEB-9EA2-0EF481A43205}</Project>
- <Name>Qpid.Common</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Messaging\Qpid.Messaging.csproj">
- <Project>{6688F826-C58E-4C1B-AA1F-22AFAB4B7D07}</Project>
- <Name>Qpid.Messaging</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Sasl.Tests\Qpid.Sasl.Tests.csproj">
- <Project>{587B3520-EBB9-41ED-B019-E96116B651CE}</Project>
- <Name>Qpid.Sasl.Tests</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Sasl\Qpid.Sasl.csproj">
- <Project>{1465B0EE-6452-42A6-AB73-B2F9EABEEE75}</Project>
- <Name>Qpid.Sasl</Name>
- </ProjectReference>
- </ItemGroup>
- <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
- <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
- Other similar extension points exist, see Microsoft.Common.targets.
- <Target Name="BeforeBuild">
- </Target>
- <Target Name="AfterBuild">
- </Target>
- -->
-</Project> \ No newline at end of file
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{6E0374D9-99BE-4D4F-B41D-B227E37E04C6}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>TestClient</RootNamespace>
+ <AssemblyName>TestClient</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\bin\net-2.0\debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\bin\net-2.0\release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Qpid.Buffer.Tests\Qpid.Buffer.Tests.csproj">
+ <Project>{74640962-99D0-4D06-B57A-9CD66517CF52}</Project>
+ <Name>Qpid.Buffer.Tests</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Buffer\Qpid.Buffer.csproj">
+ <Project>{44384DF2-B0A4-4580-BDBC-EE4BAA87D995}</Project>
+ <Name>Qpid.Buffer</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Client.Tests\Qpid.Client.Tests.csproj">
+ <Project>{BA1B0032-4CE6-40DD-A2DC-119F0FFA0A1D}</Project>
+ <Name>Qpid.Client.Tests</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Client\Qpid.Client.csproj">
+ <Project>{68987C05-3768-452C-A6FC-6BA1D372852F}</Project>
+ <Name>Qpid.Client</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Codec\Qpid.Codec.csproj">
+ <Project>{22D0D0C2-77AF-4DE3-B456-7FF3893F9F88}</Project>
+ <Name>Qpid.Codec</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Common.Tests\Qpid.Common.Tests.csproj">
+ <Project>{F83624B0-762B-4D82-900D-FF4C1B36E36E}</Project>
+ <Name>Qpid.Common.Tests</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Common\Qpid.Common.csproj">
+ <Project>{77064C42-24D2-4CEB-9EA2-0EF481A43205}</Project>
+ <Name>Qpid.Common</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Messaging\Qpid.Messaging.csproj">
+ <Project>{6688F826-C58E-4C1B-AA1F-22AFAB4B7D07}</Project>
+ <Name>Qpid.Messaging</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Sasl.Tests\Qpid.Sasl.Tests.csproj">
+ <Project>{587B3520-EBB9-41ED-B019-E96116B651CE}</Project>
+ <Name>Qpid.Sasl.Tests</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Sasl\Qpid.Sasl.csproj">
+ <Project>{1465B0EE-6452-42A6-AB73-B2F9EABEEE75}</Project>
+ <Name>Qpid.Sasl</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/dotnet/TestClient/default.build b/dotnet/TestClient/default.build
index b7179106c2..ce1114425e 100644
--- a/dotnet/TestClient/default.build
+++ b/dotnet/TestClient/default.build
@@ -1,26 +1,47 @@
-<?xml version="1.0"?>
-<project name="TestClient" default="build">
- <!--
- Properties that come from master build file
- - build.dir: root directory for build
- - build.debug: true if building debug release
- - build.defines: variables to define during build
- -->
-
- <target name="build">
- <csc target="exe"
- define="${build.defines}"
- debug="${build.debug}"
- unsafe="true"
- output="${build.dir}/${project::get-name()}.exe">
-
- <sources>
- <include name="**/*.cs" />
- </sources>
- <references>
- <include name="${build.dir}\Apache.Qpid.Integration.Tests.dll"/>
- </references>
- </csc>
- </target>
-</project>
-
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="TestClient" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="exe"
+ define="${build.defines}"
+ debug="${build.debug}"
+ unsafe="true"
+ output="${build.dir}/${project::get-name()}.exe">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ <include name="${build.dir}\Apache.Qpid.Integration.Tests.dll"/>
+ </references>
+ </csc>
+ </target>
+</project>
+
diff --git a/dotnet/TopicListener/Program.cs b/dotnet/TopicListener/Program.cs
index 0134dca1ba..14626d6134 100644
--- a/dotnet/TopicListener/Program.cs
+++ b/dotnet/TopicListener/Program.cs
@@ -1,10 +1,30 @@
-namespace TopicListener
-{
- class Program
- {
- static void Main(string[] args)
- {
- Apache.Qpid.Client.Tests.interop.TopicListener.Main(args);
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+namespace TopicListener
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ Apache.Qpid.Client.Tests.interop.TopicListener.Main(args);
+ }
+ }
+}
diff --git a/dotnet/TopicListener/Properties/AssemblyInfo.cs b/dotnet/TopicListener/Properties/AssemblyInfo.cs
index 7a37b285fc..1fe9bb8249 100644
--- a/dotnet/TopicListener/Properties/AssemblyInfo.cs
+++ b/dotnet/TopicListener/Properties/AssemblyInfo.cs
@@ -1,33 +1,53 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("TopicListener")]
-[assembly: AssemblyDescription("Built from svn revision number: ")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Apache Software Foundation")]
-[assembly: AssemblyProduct("TopicListener")]
-[assembly: AssemblyCopyright("Apache Software Foundation")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("1c2db1cd-239f-495a-b6b4-c815ea534489")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-[assembly: AssemblyVersion("2.1.0.0")]
-[assembly: AssemblyFileVersion("1.0.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.
+ *
+ */
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("TopicListener")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("TopicListener")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("1c2db1cd-239f-495a-b6b4-c815ea534489")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/TopicListener/TopicListener.csproj b/dotnet/TopicListener/TopicListener.csproj
index 5522ada191..a1e95cd668 100644
--- a/dotnet/TopicListener/TopicListener.csproj
+++ b/dotnet/TopicListener/TopicListener.csproj
@@ -1,89 +1,115 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <PropertyGroup>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProductVersion>8.0.50727</ProductVersion>
- <SchemaVersion>2.0</SchemaVersion>
- <ProjectGuid>{9A112DF2-146F-4CF4-919B-9D3BE7D088E9}</ProjectGuid>
- <OutputType>Exe</OutputType>
- <AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>TopicListener</RootNamespace>
- <AssemblyName>TopicListener</AssemblyName>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>..\bin\net-2.0\debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>pdbonly</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>..\bin\net-2.0\release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <ItemGroup>
- <Reference Include="System" />
- <Reference Include="System.Data" />
- <Reference Include="System.Xml" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="Program.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- </ItemGroup>
- <ItemGroup>
- <ProjectReference Include="..\Qpid.Buffer.Tests\Qpid.Buffer.Tests.csproj">
- <Project>{74640962-99D0-4D06-B57A-9CD66517CF52}</Project>
- <Name>Qpid.Buffer.Tests</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Buffer\Qpid.Buffer.csproj">
- <Project>{44384DF2-B0A4-4580-BDBC-EE4BAA87D995}</Project>
- <Name>Qpid.Buffer</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Client.Tests\Qpid.Client.Tests.csproj">
- <Project>{BA1B0032-4CE6-40DD-A2DC-119F0FFA0A1D}</Project>
- <Name>Qpid.Client.Tests</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Client\Qpid.Client.csproj">
- <Project>{68987C05-3768-452C-A6FC-6BA1D372852F}</Project>
- <Name>Qpid.Client</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Codec\Qpid.Codec.csproj">
- <Project>{22D0D0C2-77AF-4DE3-B456-7FF3893F9F88}</Project>
- <Name>Qpid.Codec</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Common.Tests\Qpid.Common.Tests.csproj">
- <Project>{F83624B0-762B-4D82-900D-FF4C1B36E36E}</Project>
- <Name>Qpid.Common.Tests</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Common\Qpid.Common.csproj">
- <Project>{77064C42-24D2-4CEB-9EA2-0EF481A43205}</Project>
- <Name>Qpid.Common</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Messaging\Qpid.Messaging.csproj">
- <Project>{6688F826-C58E-4C1B-AA1F-22AFAB4B7D07}</Project>
- <Name>Qpid.Messaging</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Sasl.Tests\Qpid.Sasl.Tests.csproj">
- <Project>{587B3520-EBB9-41ED-B019-E96116B651CE}</Project>
- <Name>Qpid.Sasl.Tests</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Sasl\Qpid.Sasl.csproj">
- <Project>{1465B0EE-6452-42A6-AB73-B2F9EABEEE75}</Project>
- <Name>Qpid.Sasl</Name>
- </ProjectReference>
- </ItemGroup>
- <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
- <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
- Other similar extension points exist, see Microsoft.Common.targets.
- <Target Name="BeforeBuild">
- </Target>
- <Target Name="AfterBuild">
- </Target>
- -->
-</Project> \ No newline at end of file
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.50727</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{9A112DF2-146F-4CF4-919B-9D3BE7D088E9}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>TopicListener</RootNamespace>
+ <AssemblyName>TopicListener</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\bin\net-2.0\debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\bin\net-2.0\release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Qpid.Buffer.Tests\Qpid.Buffer.Tests.csproj">
+ <Project>{74640962-99D0-4D06-B57A-9CD66517CF52}</Project>
+ <Name>Qpid.Buffer.Tests</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Buffer\Qpid.Buffer.csproj">
+ <Project>{44384DF2-B0A4-4580-BDBC-EE4BAA87D995}</Project>
+ <Name>Qpid.Buffer</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Client.Tests\Qpid.Client.Tests.csproj">
+ <Project>{BA1B0032-4CE6-40DD-A2DC-119F0FFA0A1D}</Project>
+ <Name>Qpid.Client.Tests</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Client\Qpid.Client.csproj">
+ <Project>{68987C05-3768-452C-A6FC-6BA1D372852F}</Project>
+ <Name>Qpid.Client</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Codec\Qpid.Codec.csproj">
+ <Project>{22D0D0C2-77AF-4DE3-B456-7FF3893F9F88}</Project>
+ <Name>Qpid.Codec</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Common.Tests\Qpid.Common.Tests.csproj">
+ <Project>{F83624B0-762B-4D82-900D-FF4C1B36E36E}</Project>
+ <Name>Qpid.Common.Tests</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Common\Qpid.Common.csproj">
+ <Project>{77064C42-24D2-4CEB-9EA2-0EF481A43205}</Project>
+ <Name>Qpid.Common</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Messaging\Qpid.Messaging.csproj">
+ <Project>{6688F826-C58E-4C1B-AA1F-22AFAB4B7D07}</Project>
+ <Name>Qpid.Messaging</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Sasl.Tests\Qpid.Sasl.Tests.csproj">
+ <Project>{587B3520-EBB9-41ED-B019-E96116B651CE}</Project>
+ <Name>Qpid.Sasl.Tests</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Sasl\Qpid.Sasl.csproj">
+ <Project>{1465B0EE-6452-42A6-AB73-B2F9EABEEE75}</Project>
+ <Name>Qpid.Sasl</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/dotnet/TopicListener/default.build b/dotnet/TopicListener/default.build
index afde4d6937..f9b0f97094 100644
--- a/dotnet/TopicListener/default.build
+++ b/dotnet/TopicListener/default.build
@@ -1,26 +1,47 @@
-<?xml version="1.0"?>
-<project name="TopicListener" default="build">
- <!--
- Properties that come from master build file
- - build.dir: root directory for build
- - build.debug: true if building debug release
- - build.defines: variables to define during build
- -->
-
- <target name="build">
- <csc target="exe"
- define="${build.defines}"
- debug="${build.debug}"
- unsafe="true"
- output="${build.dir}/${project::get-name()}.exe">
-
- <sources>
- <include name="**/*.cs" />
- </sources>
- <references>
- <include name="${build.dir}\Apache.Qpid.Client.Tests.dll"/>
- </references>
- </csc>
- </target>
-</project>
-
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="TopicListener" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="exe"
+ define="${build.defines}"
+ debug="${build.debug}"
+ unsafe="true"
+ output="${build.dir}/${project::get-name()}.exe">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ <include name="${build.dir}\Apache.Qpid.Client.Tests.dll"/>
+ </references>
+ </csc>
+ </target>
+</project>
+
diff --git a/dotnet/TopicPublisher/Program.cs b/dotnet/TopicPublisher/Program.cs
index a68df14bb3..b5209b9317 100644
--- a/dotnet/TopicPublisher/Program.cs
+++ b/dotnet/TopicPublisher/Program.cs
@@ -1,10 +1,30 @@
-namespace TopicPublisher
-{
- class Program
- {
- static void Main(string[] args)
- {
- Apache.Qpid.Client.Tests.interop.TopicPublisher.Main(args);
- }
- }
-}
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+namespace TopicPublisher
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ Apache.Qpid.Client.Tests.interop.TopicPublisher.Main(args);
+ }
+ }
+}
diff --git a/dotnet/TopicPublisher/Properties/AssemblyInfo.cs b/dotnet/TopicPublisher/Properties/AssemblyInfo.cs
index d9585963d9..051b34ee37 100644
--- a/dotnet/TopicPublisher/Properties/AssemblyInfo.cs
+++ b/dotnet/TopicPublisher/Properties/AssemblyInfo.cs
@@ -1,33 +1,53 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("TopicPublisher")]
-[assembly: AssemblyDescription("Built from svn revision number: ")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Apache Software Foundation")]
-[assembly: AssemblyProduct("TopicPublisher")]
-[assembly: AssemblyCopyright("Apache Software Foundation")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("93fa1c32-c0f8-47e5-b167-dc581e33eb9b")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-[assembly: AssemblyVersion("2.1.0.0")]
-[assembly: AssemblyFileVersion("1.0.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.
+ *
+ */
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("TopicPublisher")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("TopicPublisher")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("93fa1c32-c0f8-47e5-b167-dc581e33eb9b")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/TopicPublisher/TopicPublisher.csproj b/dotnet/TopicPublisher/TopicPublisher.csproj
index 2e03ce858e..695d39ffe7 100644
--- a/dotnet/TopicPublisher/TopicPublisher.csproj
+++ b/dotnet/TopicPublisher/TopicPublisher.csproj
@@ -1,85 +1,111 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <PropertyGroup>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProductVersion>8.0.50727</ProductVersion>
- <SchemaVersion>2.0</SchemaVersion>
- <ProjectGuid>{A06C9FFD-22FF-4654-856D-897C230978AF}</ProjectGuid>
- <OutputType>Exe</OutputType>
- <AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>TopicPublisher</RootNamespace>
- <AssemblyName>TopicPublisher</AssemblyName>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>..\bin\net-2.0\debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>pdbonly</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>..\bin\net-2.0\release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <ItemGroup>
- <Reference Include="System" />
- <Reference Include="System.Data" />
- <Reference Include="System.Xml" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="Program.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- </ItemGroup>
- <ItemGroup>
- <ProjectReference Include="..\Qpid.Buffer\Qpid.Buffer.csproj">
- <Project>{44384DF2-B0A4-4580-BDBC-EE4BAA87D995}</Project>
- <Name>Qpid.Buffer</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Client.Tests\Qpid.Client.Tests.csproj">
- <Project>{BA1B0032-4CE6-40DD-A2DC-119F0FFA0A1D}</Project>
- <Name>Qpid.Client.Tests</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Client\Qpid.Client.csproj">
- <Project>{68987C05-3768-452C-A6FC-6BA1D372852F}</Project>
- <Name>Qpid.Client</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Codec\Qpid.Codec.csproj">
- <Project>{22D0D0C2-77AF-4DE3-B456-7FF3893F9F88}</Project>
- <Name>Qpid.Codec</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Common.Tests\Qpid.Common.Tests.csproj">
- <Project>{F83624B0-762B-4D82-900D-FF4C1B36E36E}</Project>
- <Name>Qpid.Common.Tests</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Common\Qpid.Common.csproj">
- <Project>{77064C42-24D2-4CEB-9EA2-0EF481A43205}</Project>
- <Name>Qpid.Common</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Messaging\Qpid.Messaging.csproj">
- <Project>{6688F826-C58E-4C1B-AA1F-22AFAB4B7D07}</Project>
- <Name>Qpid.Messaging</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Sasl.Tests\Qpid.Sasl.Tests.csproj">
- <Project>{587B3520-EBB9-41ED-B019-E96116B651CE}</Project>
- <Name>Qpid.Sasl.Tests</Name>
- </ProjectReference>
- <ProjectReference Include="..\Qpid.Sasl\Qpid.Sasl.csproj">
- <Project>{1465B0EE-6452-42A6-AB73-B2F9EABEEE75}</Project>
- <Name>Qpid.Sasl</Name>
- </ProjectReference>
- </ItemGroup>
- <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
- <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
- Other similar extension points exist, see Microsoft.Common.targets.
- <Target Name="BeforeBuild">
- </Target>
- <Target Name="AfterBuild">
- </Target>
- -->
-</Project> \ No newline at end of file
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.50727</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{A06C9FFD-22FF-4654-856D-897C230978AF}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>TopicPublisher</RootNamespace>
+ <AssemblyName>TopicPublisher</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\bin\net-2.0\debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\bin\net-2.0\release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Qpid.Buffer\Qpid.Buffer.csproj">
+ <Project>{44384DF2-B0A4-4580-BDBC-EE4BAA87D995}</Project>
+ <Name>Qpid.Buffer</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Client.Tests\Qpid.Client.Tests.csproj">
+ <Project>{BA1B0032-4CE6-40DD-A2DC-119F0FFA0A1D}</Project>
+ <Name>Qpid.Client.Tests</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Client\Qpid.Client.csproj">
+ <Project>{68987C05-3768-452C-A6FC-6BA1D372852F}</Project>
+ <Name>Qpid.Client</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Codec\Qpid.Codec.csproj">
+ <Project>{22D0D0C2-77AF-4DE3-B456-7FF3893F9F88}</Project>
+ <Name>Qpid.Codec</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Common.Tests\Qpid.Common.Tests.csproj">
+ <Project>{F83624B0-762B-4D82-900D-FF4C1B36E36E}</Project>
+ <Name>Qpid.Common.Tests</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Common\Qpid.Common.csproj">
+ <Project>{77064C42-24D2-4CEB-9EA2-0EF481A43205}</Project>
+ <Name>Qpid.Common</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Messaging\Qpid.Messaging.csproj">
+ <Project>{6688F826-C58E-4C1B-AA1F-22AFAB4B7D07}</Project>
+ <Name>Qpid.Messaging</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Sasl.Tests\Qpid.Sasl.Tests.csproj">
+ <Project>{587B3520-EBB9-41ED-B019-E96116B651CE}</Project>
+ <Name>Qpid.Sasl.Tests</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Qpid.Sasl\Qpid.Sasl.csproj">
+ <Project>{1465B0EE-6452-42A6-AB73-B2F9EABEEE75}</Project>
+ <Name>Qpid.Sasl</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/dotnet/TopicPublisher/default.build b/dotnet/TopicPublisher/default.build
index 8991aae751..9b01c2a1bc 100644
--- a/dotnet/TopicPublisher/default.build
+++ b/dotnet/TopicPublisher/default.build
@@ -1,26 +1,47 @@
-<?xml version="1.0"?>
-<project name="TopicPublisher" default="build">
- <!--
- Properties that come from master build file
- - build.dir: root directory for build
- - build.debug: true if building debug release
- - build.defines: variables to define during build
- -->
-
- <target name="build">
- <csc target="exe"
- define="${build.defines}"
- debug="${build.debug}"
- unsafe="true"
- output="${build.dir}/${project::get-name()}.exe">
-
- <sources>
- <include name="**/*.cs" />
- </sources>
- <references>
- <include name="${build.dir}\Apache.Qpid.Client.Tests.dll"/>
- </references>
- </csc>
- </target>
-</project>
-
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="TopicPublisher" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="exe"
+ define="${build.defines}"
+ debug="${build.debug}"
+ unsafe="true"
+ output="${build.dir}/${project::get-name()}.exe">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ <include name="${build.dir}\Apache.Qpid.Client.Tests.dll"/>
+ </references>
+ </csc>
+ </target>
+</project>
+
diff --git a/dotnet/build-dotnet11 b/dotnet/build-dotnet11
deleted file mode 100644
index 918010bf1f..0000000000
--- a/dotnet/build-dotnet11
+++ /dev/null
@@ -1 +0,0 @@
-nant -t:net-1.1
diff --git a/dotnet/build-dotnet11.bat b/dotnet/build-dotnet11.bat
deleted file mode 100644
index 4b58f13b2a..0000000000
--- a/dotnet/build-dotnet11.bat
+++ /dev/null
@@ -1 +0,0 @@
-nant -t:net-1.1
diff --git a/dotnet/build-dotnet20 b/dotnet/build-dotnet20
deleted file mode 100644
index 713a7aa55a..0000000000
--- a/dotnet/build-dotnet20
+++ /dev/null
@@ -1,3 +0,0 @@
-MSBuild.exe Qpid.NET.sln \
- /p:Configuration=Release \
- /t:rebuild
diff --git a/dotnet/build-framing b/dotnet/build-framing
deleted file mode 100644
index 315a1a1cb2..0000000000
--- a/dotnet/build-framing
+++ /dev/null
@@ -1,2 +0,0 @@
-cd Qpid.Common
-ant
diff --git a/dotnet/build-framing.bat b/dotnet/build-framing.bat
index bc5aa23ab7..ae9bc749a9 100644
--- a/dotnet/build-framing.bat
+++ b/dotnet/build-framing.bat
@@ -1,2 +1,23 @@
+@REM
+@REM
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM
+@REM
+
cd Qpid.Common
ant
diff --git a/dotnet/build-mono b/dotnet/build-mono
index 6f5cad5744..275922e623 100755
--- a/dotnet/build-mono
+++ b/dotnet/build-mono
@@ -1 +1,3 @@
+#!/bin/sh
+
nant -t:mono-2.0
diff --git a/dotnet/build-msbuild.bat b/dotnet/build-msbuild.bat
new file mode 100644
index 0000000000..1fe4b5d64c
--- /dev/null
+++ b/dotnet/build-msbuild.bat
@@ -0,0 +1,22 @@
+@REM
+@REM
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM
+@REM
+
+MSBuild.exe Qpid.NET.sln /p:Configuration=Release /t:rebuild
diff --git a/dotnet/build-nant-release b/dotnet/build-nant-release
new file mode 100755
index 0000000000..611a1efe08
--- /dev/null
+++ b/dotnet/build-nant-release
@@ -0,0 +1,55 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
+#!/bin/bash
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
+
+Usage()
+{
+ echo "usage: $0 net-2.0|mono-2.0"
+ exit 2
+}
+
+if [[ $# -ne 1 ]]; then
+ Usage
+fi
+
+nant -t:$1 release-pkg -D:build.config=release
diff --git a/dotnet/build-nant.bat b/dotnet/build-nant.bat
new file mode 100644
index 0000000000..785450a9f7
--- /dev/null
+++ b/dotnet/build-nant.bat
@@ -0,0 +1,22 @@
+@REM
+@REM
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM
+@REM
+
+nant -t:net-2.0
diff --git a/dotnet/client-010/App.config b/dotnet/client-010/App.config
new file mode 100644
index 0000000000..36b4ffab3e
--- /dev/null
+++ b/dotnet/client-010/App.config
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<configuration>
+ <appSettings>
+ <add key="Username" value="guest"/>
+ <add key="Password" value="guest123"/>
+ <add key="Host" value="localhost"/>
+ <add key="Port" value="5672"/>
+ <add key="VirtualHost" value="test"/>
+
+ <!-- <add key="ProcessorAssembly" value="C:\Project\qpid\dotnet\client-010\addins\ExcelAddInMessageProcessor\bin\Debug\ExcelAddInMessageProcessor.dll"/>
+ <add key="ProcessorClass" value="ExcelAddInMessageProcessor.Processor"/> -->
+ </appSettings>
+</configuration>
diff --git a/dotnet/client-010/LICENSE.txt b/dotnet/client-010/LICENSE.txt
new file mode 100644
index 0000000000..981d2f83c3
--- /dev/null
+++ b/dotnet/client-010/LICENSE.txt
@@ -0,0 +1,757 @@
+
+ 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.
+
+
+=========================================================================
+== Saxon XSLT License ==
+=========================================================================
+
+Mozilla Public License Version 1.0
+
+1. Definitions.
+
+ 1.1. "Contributor" means each entity that creates or contributes
+ to the creation of Modifications.
+
+ 1.2. "Contributor Version" means the combination of the
+ Original Code, prior Modifications used by a Contributor, and the
+ Modifications made by that particular Contributor.
+
+ 1.3. "Covered Code" means the Original Code or Modifications
+ or the combination of the Original Code and Modifications, in each case
+ including portions thereof.
+
+ 1.4. "Electronic Distribution Mechanism" means a mechanism
+ generally accepted in the software development community for the
+ electronic transfer of data.
+
+ 1.5. "Executable" means Covered Code in any form other than
+ Source Code.
+
+ 1.6. "Initial Developer" means the individual or entity
+ identified as the Initial Developer in the Source Code notice required by
+ Exhibit A.
+
+ 1.7. "Larger Work" means a work which combines Covered Code
+ or portions thereof with code not governed by the terms of this License.
+
+ 1.8. "License" means this document.
+
+ 1.9. "Modifications" means any addition to or deletion from
+ the substance or structure of either the Original Code or any previous
+ Modifications. When Covered Code is released as a series of files, a
+ Modification is:
+
+ A. Any addition to or deletion from the contents of a file
+ containing Original Code or previous Modifications.
+
+ B. Any new file that contains any part of the Original
+ Code or previous Modifications.
+
+ 1.10. "Original Code" means Source Code of computer software
+ code which is described in the Source Code notice required by Exhibit
+ A as Original Code, and which, at the time of its release under this
+ License is not already Covered Code governed by this License.
+
+ 1.11. "Source Code" means the preferred form of the Covered
+ Code for making modifications to it, including all modules it contains,
+ plus any associated interface definition files, scripts used to control
+ compilation and installation of an Executable, or a list of source code
+ differential comparisons against either the Original Code or another well
+ known, available Covered Code of the Contributor's choice. The Source
+ Code can be in a compressed or archival form, provided the appropriate
+ decompression or de-archiving software is widely available for no charge.
+
+ 1.12. "You" means an individual or a legal entity exercising
+ rights under, and complying with all of the terms of, this License or a
+ future version of this License issued under Section 6.1. For legal
+ entities, "You" includes any entity which controls, is controlled by,
+ or is under common control with You. For purposes of this definition,
+ "control" means (a) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or otherwise,
+ or (b) ownership of fifty percent (50%) or more of the outstanding shares
+ or beneficial ownership of such entity.
+
+2. Source Code License.
+
+ 2.1. The Initial Developer Grant.
+
+
+ The Initial Developer hereby grants You a world-wide, royalty-free,
+ non-exclusive license, subject to third party intellectual property
+ claims:
+
+ (a) to use, reproduce, modify, display, perform, sublicense
+ and distribute the Original Code (or portions thereof) with or
+ without Modifications, or as part of a Larger Work; and
+
+ (b) under patents now or hereafter owned or controlled by
+ Initial Developer, to make, have made, use and sell ("Utilize") the
+ Original Code (or portions thereof), but solely to the extent that
+ any such patent is reasonably necessary to enable You to Utilize the
+ Original Code (or portions thereof) and not to any greater extent
+ that may be necessary to Utilize further Modifications or
+ combinations.
+
+ 2.2. Contributor Grant.
+
+
+ Each Contributor hereby grants You a world-wide, royalty-free,
+ non-exclusive license, subject to third party intellectual property
+ claims:
+
+ (a) to use, reproduce, modify, display, perform, sublicense and
+ distribute the Modifications created by such Contributor (or portions
+ thereof) either on an unmodified basis, with other Modifications, as
+ Covered Code or as part of a Larger Work; and
+
+ (b) under patents now or hereafter owned or controlled by
+ Contributor, to Utilize the Contributor Version (or portions thereof),
+ but solely to the extent that any such patent is reasonably necessary to
+ enable You to Utilize the Contributor Version (or portions thereof), and
+ not to any greater extent that may be necessary to Utilize further
+ Modifications or combinations.
+
+3. Distribution Obligations.
+
+ 3.1. Application of License.
+
+
+ The Modifications which You create or to which You contribute are
+ governed by the terms of this License, including without limitation
+ Section 2.2. The Source Code version of Covered Code may be
+ distributed only under the terms of this License or a future version of
+ this License released under Section 6.1, and You must include a
+ copy of this License with every copy of the Source Code You
+ distribute. You may not offer or impose any terms on any Source Code
+ version that alters or restricts the applicable version of this License
+ or the recipients' rights hereunder. However, You may include an
+ additional document offering the additional rights described in Section
+ 3.5.
+
+ 3.2. Availability of Source Code.
+
+
+ Any Modification which You create or to which You contribute must be
+ made available in Source Code form under the terms of this License either
+ on the same media as an Executable version or via an accepted Electronic
+ Distribution Mechanism to anyone to whom you made an Executable version
+ available; and if made available via Electronic Distribution Mechanism,
+ must remain available for at least twelve (12) months after the date it
+ initially became available, or at least six (6) months after a subsequent
+ version of that particular Modification has been made available to such
+ recipients. You are responsible for ensuring that the Source Code version
+ remains available even if the Electronic Distribution Mechanism is
+ maintained by a third party.
+
+ 3.3. Description of Modifications.
+
+
+ You must cause all Covered Code to which you contribute to contain a
+ file documenting the changes You made to create that Covered Code and the
+ date of any change. You must include a prominent statement that the
+ Modification is derived, directly or indirectly, from Original Code
+ provided by the Initial Developer and including the name of the Initial
+ Developer in (a) the Source Code, and (b) in any notice in an Executable
+ version or related documentation in which You describe the origin or
+ ownership of the Covered Code.
+
+ 3.4. Intellectual Property Matters
+
+ (a) Third Party Claims.
+
+
+ If You have knowledge that a party claims an intellectual
+ property right in particular functionality or code (or its
+ utilization under this License), you must include a text file with
+ the source code distribution titled "LEGAL" which describes the
+ claim and the party making the claim in sufficient detail that a
+ recipient will know whom to contact. If you obtain such knowledge
+ after You make Your Modification available as described in Section
+ 3.2, You shall promptly modify the LEGAL file in all copies
+ You make available thereafter and shall take other steps (such as
+ notifying appropriate mailing lists or newsgroups) reasonably
+ calculated to inform those who received the Covered Code that new
+ knowledge has been obtained.
+
+ (b) Contributor APIs.
+
+
+ If Your Modification is an application programming interface and
+ You own or control patents which are reasonably necessary to
+ implement that API, you must also include this information in the
+ LEGAL file.
+
+ 3.5. Required Notices.
+
+
+ You must duplicate the notice in Exhibit A in each file of the
+ Source Code, and this License in any documentation for the Source Code,
+ where You describe recipients' rights relating to Covered Code. If You
+ created one or more Modification(s), You may add your name as a
+ Contributor to the notice described in Exhibit A. If it is not
+ possible to put such notice in a particular Source Code file due to its
+ structure, then you must include such notice in a location (such as a
+ relevant directory file) where a user would be likely to look for such a
+ notice. You may choose to offer, and to charge a fee for, warranty,
+ support, indemnity or liability obligations to one or more recipients of
+ Covered Code. However, You may do so only on Your own behalf, and not on
+ behalf of the Initial Developer or any Contributor. You must make it
+ absolutely clear than any such warranty, support, indemnity or liability
+ obligation is offered by You alone, and You hereby agree to indemnify the
+ Initial Developer and every Contributor for any liability incurred by the
+ Initial Developer or such Contributor as a result of warranty, support,
+ indemnity or liability terms You offer.
+
+ 3.6. Distribution of Executable Versions.
+
+
+ You may distribute Covered Code in Executable form only if the
+ requirements of Section 3.1-3.5 have been met for that Covered
+ Code, and if You include a notice stating that the Source Code version of
+ the Covered Code is available under the terms of this License, including
+ a description of how and where You have fulfilled the obligations of
+ Section 3.2. The notice must be conspicuously included in any
+ notice in an Executable version, related documentation or collateral in
+ which You describe recipients' rights relating to the Covered Code. You
+ may distribute the Executable version of Covered Code under a license of
+ Your choice, which may contain terms different from this License,
+ provided that You are in compliance with the terms of this License and
+ that the license for the Executable version does not attempt to limit or
+ alter the recipient's rights in the Source Code version from the rights
+ set forth in this License. If You distribute the Executable version under
+ a different license You must make it absolutely clear that any terms
+ which differ from this License are offered by You alone, not by the
+ Initial Developer or any Contributor. You hereby agree to indemnify the
+ Initial Developer and every Contributor for any liability incurred by the
+ Initial Developer or such Contributor as a result of any such terms You
+ offer.
+
+ 3.7. Larger Works.
+
+
+ You may create a Larger Work by combining Covered Code with other
+ code not governed by the terms of this License and distribute the Larger
+ Work as a single product. In such a case, You must make sure the
+ requirements of this License are fulfilled for the Covered Code.
+
+4. Inability to Comply Due to Statute or Regulation.
+
+ If it is impossible for You to comply with any of the terms of this
+ License with respect to some or all of the Covered Code due to statute or
+ regulation then You must: (a) comply with the terms of this License to
+ the maximum extent possible; and (b) describe the limitations and the
+ code they affect. Such description must be included in the LEGAL file
+ described in Section 3.4 and must be included with all
+ distributions of the Source Code. Except to the extent prohibited by
+ statute or regulation, such description must be sufficiently detailed for
+ a recipient of ordinary skill
+ to be able to understand it.
+
+5. Application of this License.
+
+ This License applies to code to which the Initial Developer has attached
+ the notice in Exhibit A, and to related Covered Code.
+
+6. Versions of the License.
+
+ 6.1. New Versions.
+
+
+ Netscape Communications Corporation ("Netscape") may publish
+ revised and/or new versions of the License from time to time. Each
+ version will be given a distinguishing version number.
+
+ 6.2. Effect of New Versions.
+
+
+ Once Covered Code has been published under a particular version of
+ the License, You may always continue to use it under the terms of that
+ version. You may also choose to use such Covered Code under the terms of
+ any subsequent version of the License published by Netscape. No one other
+ than Netscape has the right to modify the terms applicable to Covered
+ Code created under this License.
+
+ 6.3. Derivative Works.
+
+
+ If you create or use a modified version of this License (which you
+ may only do in order to apply it to code which is not already Covered
+ Code governed by this License), you must (a) rename Your license so that
+ the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", "NPL"
+ or any confusingly similar phrase do not appear anywhere in your license
+ and (b) otherwise make it clear that your version of the license contains
+ terms which differ from the Mozilla Public License and Netscape Public
+ License. (Filling in the name of the Initial Developer, Original Code or
+ Contributor in the notice described in Exhibit A shall not of
+ themselves be deemed to be modifications of this License.)
+
+7. DISCLAIMER OF WARRANTY.
+
+ COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS,
+ MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE
+ RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE IS WITH
+ YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
+ INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
+ NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY
+ CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED CODE
+ IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+8. TERMINATION.
+
+ This License and the rights granted hereunder will terminate
+ automatically if You fail to comply with terms herein and fail to cure
+ such breach within 30 days of becoming aware of the breach. All
+ sublicenses to the Covered Code which are properly granted shall survive
+ any termination of this License. Provisions which, by their nature, must
+ remain in effect beyond the termination of this License shall survive.
+
+9. LIMITATION OF LIABILITY.
+
+ UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING
+ NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL THE INITIAL DEVELOPER, ANY
+ OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, OR ANY SUPPLIER OF
+ ANY OF SUCH PARTIES, BE LIABLE TO YOU OR ANY OTHER PERSON FOR ANY
+ INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER
+ INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK
+ STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+ COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED
+ OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL
+ NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH
+ PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH
+ LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION
+ OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THAT EXCLUSION AND LIMITATION
+ MAY NOT APPLY TO YOU.
+
+10. U.S. GOVERNMENT END USERS.
+
+ The Covered Code is a "commercial item," as that term is defined in 48
+ C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software"
+ and "commercial computer software documentation," as such terms are
+ used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212
+ and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all
+ U.S. Government End Users acquire Covered Code with only those rights set
+ forth herein.
+
+11. MISCELLANEOUS.
+
+ This License represents the complete agreement concerning subject matter
+ hereof. If any provision of this License is held to be unenforceable,
+ such provision shall be reformed only to the extent necessary to make it
+ enforceable. This License shall be governed by California law provisions
+ (except to the extent applicable law, if any, provides otherwise),
+ excluding its conflict-of-law provisions. With respect to disputes in
+ which at least one party is a citizen of, or an entity chartered or
+ registered to do business in, the United States of America: (a) unless
+ otherwise agreed in writing, all disputes relating to this License
+ (excepting any dispute relating to intellectual property rights) shall be
+ subject to final and binding arbitration, with the losing party paying
+ all costs of arbitration; (b) any arbitration relating to this Agreement
+ shall be held in Santa Clara County, California, under the auspices of
+ JAMS/EndDispute; and (c) any litigation relating to this Agreement shall
+ be subject to the jurisdiction of the Federal Courts of the Northern
+ District of California, with venue lying in Santa Clara County,
+ California, with the losing party responsible for costs, including
+ without limitation, court costs and reasonable attorneys fees and
+ expenses. The application of the United Nations Convention on Contracts
+ for the International Sale of Goods is expressly excluded. Any law or
+ regulation which provides that the language of a contract shall be
+ construed against the drafter shall not apply to this License.
+
+12. RESPONSIBILITY FOR CLAIMS.
+
+ Except in cases where another Contributor has failed to comply with
+ Section 3.4, You are responsible for damages arising, directly or
+ indirectly, out of Your utilization of rights under this License, based
+ on the number of copies of Covered Code you made available, the revenues
+ you received from utilizing such rights, and other relevant factors. You
+ agree to work with affected parties to distribute responsibility on an
+ equitable basis.
+
+EXHIBIT A.
+
+ "The contents of this file are subject to the Mozilla Public License
+ Version 1.0 (the "License"); you may not use this file except in
+ compliance with the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ License for the specific language governing rights and limitations under
+ the License.
+
+ The Original Code is ______________________________________.
+
+ The Initial Developer of the Original Code is
+ ________________________. Portions created by ______________________ are
+ Copyright (C) ______ _______________________. All Rights Reserved.
+
+ Contributor(s): ______________________________________."
+
+
+=========================================================================
+== Nunit License ==
+=========================================================================
+Copyright (c) 2002 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov
+Copyright (c) 2000-2002 Philip A. Craig
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+
+ 3. This notice may not be removed or altered from any source
+ distribution.
+
+=========================================================================
+== Mentalis Security LibraryLicense ==
+=========================================================================
+
+Source Code License
+
+Copyright 2002-2007, The Mentalis.org Team
+All rights reserved.
+http://www.mentalis.org/
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+- Neither the name of the Mentalis.org Team, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+=========================================================================
+== AMQP License ==
+=========================================================================
+
+ Copyright Notice
+ ================
+ (c) Copyright JPMorgan Chase Bank & Co., Cisco Systems, Inc., Envoy Technologies Inc.,
+ iMatix Corporation, IONA\ufffd Technologies, Red Hat, Inc.,
+ TWIST Process Innovations, and 29West Inc. 2006. All rights reserved.
+
+ License
+ =======
+ JPMorgan Chase Bank & Co., Cisco Systems, Inc., Envoy Technologies Inc., iMatix
+ Corporation, IONA\ufffd Technologies, Red Hat, Inc., TWIST Process Innovations, and
+ 29West Inc. (collectively, the "Authors") each hereby grants to you a worldwide,
+ perpetual, royalty-free, nontransferable, nonexclusive license to
+ (i) copy, display, and implement the Advanced Messaging Queue Protocol
+ ("AMQP") Specification and (ii) the Licensed Claims that are held by
+ the Authors, all for the purpose of implementing the Advanced Messaging
+ Queue Protocol Specification. Your license and any rights under this
+ Agreement will terminate immediately without notice from
+ any Author if you bring any claim, suit, demand, or action related to
+ the Advanced Messaging Queue Protocol Specification against any Author.
+ Upon termination, you shall destroy all copies of the Advanced Messaging
+ Queue Protocol Specification in your possession or control.
+
+ As used hereunder, "Licensed Claims" means those claims of a patent or
+ patent application, throughout the world, excluding design patents and
+ design registrations, owned or controlled, or that can be sublicensed
+ without fee and in compliance with the requirements of this
+ Agreement, by an Author or its affiliates now or at any
+ future time and which would necessarily be infringed by implementation
+ of the Advanced Messaging Queue Protocol Specification. A claim is
+ necessarily infringed hereunder only when it is not possible to avoid
+ infringing it because there is no plausible non-infringing alternative
+ for implementing the required portions of the Advanced Messaging Queue
+ Protocol Specification. Notwithstanding the foregoing, Licensed Claims
+ shall not include any claims other than as set forth above even if
+ contained in the same patent as Licensed Claims; or that read solely
+ on any implementations of any portion of the Advanced Messaging Queue
+ Protocol Specification that are not required by the Advanced Messaging
+ Queue Protocol Specification, or that, if licensed, would require a
+ payment of royalties by the licensor to unaffiliated third parties.
+ Moreover, Licensed Claims shall not include (i) any enabling technologies
+ that may be necessary to make or use any Licensed Product but are not
+ themselves expressly set forth in the Advanced Messaging Queue Protocol
+ Specification (e.g., semiconductor manufacturing technology, compiler
+ technology, object oriented technology, networking technology, operating
+ system technology, and the like); or (ii) the implementation of other
+ published standards developed elsewhere and merely referred to in the
+ body of the Advanced Messaging Queue Protocol Specification, or
+ (iii) any Licensed Product and any combinations thereof the purpose or
+ function of which is not required for compliance with the Advanced
+ Messaging Queue Protocol Specification. For purposes of this definition,
+ the Advanced Messaging Queue Protocol Specification shall be deemed to
+ include both architectural and interconnection requirements essential
+ for interoperability and may also include supporting source code artifacts
+ where such architectural, interconnection requirements and source code
+ artifacts are expressly identified as being required or documentation to
+ achieve compliance with the Advanced Messaging Queue Protocol Specification.
+
+ As used hereunder, "Licensed Products" means only those specific portions
+ of products (hardware, software or combinations thereof) that implement
+ and are compliant with all relevant portions of the Advanced Messaging
+ Queue Protocol Specification.
+
+ The following disclaimers, which you hereby also acknowledge as to any
+ use you may make of the Advanced Messaging Queue Protocol Specification:
+
+ THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION IS PROVIDED "AS IS,"
+ AND THE AUTHORS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+ IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE
+ CONTENTS OF THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION ARE
+ SUITABLE FOR ANY PURPOSE; NOR THAT THE IMPLEMENTATION OF THE ADVANCED
+ MESSAGING QUEUE PROTOCOL SPECIFICATION WILL NOT INFRINGE ANY THIRD PARTY
+ PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
+
+ THE AUTHORS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL,
+ INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO ANY
+ USE, IMPLEMENTATION OR DISTRIBUTION OF THE ADVANCED MESSAGING QUEUE
+ PROTOCOL SPECIFICATION.
+
+ The name and trademarks of the Authors may NOT be used in any manner,
+ including advertising or publicity pertaining to the Advanced Messaging
+ Queue Protocol Specification or its contents without specific, written
+ prior permission. Title to copyright in the Advanced Messaging Queue
+ Protocol Specification will at all times remain with the Authors.
+
+ No other rights are granted by implication, estoppel or otherwise.
+
+ Upon termination of your license or rights under this Agreement, you
+ shall destroy all copies of the Advanced Messaging Queue Protocol
+ Specification in your possession or control.
+
+ Trademarks
+ ==========
+ "JPMorgan", "JPMorgan Chase", "Chase", the JPMorgan Chase logo and the
+ Octagon Symbol are trademarks of JPMorgan Chase & Co.
+
+ IMATIX and the iMatix logo are trademarks of iMatix Corporation sprl.
+
+ IONA, IONA Technologies, and the IONA logos are trademarks of IONA
+ Technologies PLC and/or its subsidiaries.
+
+ LINUX is a trademark of Linus Torvalds. RED HAT and JBOSS are registered
+ trademarks of Red Hat, Inc. in the US and other countries.
+
+ Java, all Java-based trademarks and OpenOffice.org are trademarks of
+ Sun Microsystems, Inc. in the United States, other countries, or both.
+
+ Other company, product, or service names may be trademarks or service
+ marks of others.
+
+ Links to full AMQP specification:
+ =================================
+ http://www.envoytech.org/spec/amq/
+ http://www.iona.com/opensource/amqp/
+ http://www.redhat.com/solutions/specifications/amqp/
+ http://www.twiststandards.org/tiki-index.php?page=AMQ
+ http://www.imatix.com/amqp
diff --git a/dotnet/client-010/NOTICE.txt b/dotnet/client-010/NOTICE.txt
new file mode 100644
index 0000000000..0b22ed3ab2
--- /dev/null
+++ b/dotnet/client-010/NOTICE.txt
@@ -0,0 +1,32 @@
+=========================================================================
+== NOTICE file corresponding to the section 4 d of ==
+== the Apache License, Version 2.0, ==
+== in this case for the Apache Ant distribution. ==
+=========================================================================
+
+Apache Qpid.NET
+Copyright 2006 The Apache Software Foundation
+
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).
+
+This product also includes software developed by:
+
+ - The SAXON XSLT Processor from Michael Kay distributed under the Mozilla
+ Public License v1.0, which is available for download at
+ http://saxon.sourceforge.net/
+
+ - The nunit library, Copyright 2002 James W. Newkirk, Michael C. Two,
+ Alexei A. Vorontsov or Copyright 2000-2002 Philip A. Craig. Available
+ under terms based on the zlib/libpng licence. Available from
+ http://www.nunit.org/
+
+ - The Mentalis Security Library, Copyright 2002-2006, , The Mentalis.org Team
+ under tterms based on the BSD license (http://www.mentalis.org/site/license.qpx).
+ Available from http://www.mentalis.org/soft/projects/seclib/
+
+This product includes software, Apache Log4Net
+(http://logging.apache.org/log4net)
+License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
+
+
diff --git a/dotnet/client-010/README.txt b/dotnet/client-010/README.txt
new file mode 100644
index 0000000000..74d54a9786
--- /dev/null
+++ b/dotnet/client-010/README.txt
@@ -0,0 +1,69 @@
+Info
+====
+
+AMQP 0.10 Native .NET client supporting WCF and xcel
+
+In order to build this client from the sources you'll need the following folders :
+- <project home>/java/lib
+- <project home>/python
+- <project home>/specs
+
+
+Setup
+=====
+
+Install:
+ Microsoft Visual Studio 2008 (VS2008). It's also possible to build with vs2005 by creating a new solution and adding Client.csproj
+ NAnt 0.85 - only required for builds outside VS2008 (.net 1.1, .net 2.0, mono 2.0)
+ Ant 1.6.5 (requires Java)
+ Cygwin (or alternatively build via cmd but alter instructions below accordingly)
+
+Set up PATH to include Nant.exe:
+
+ $ PATH=/cygdrive/c/WINDOWS/Microsoft.NET/Framework/v2.0.50727:$PATH
+
+Set up PATH to include ant:
+
+ $ PATH=$ANT_HOME/bin:$PATH
+
+
+Building
+========
+
+Generate code from <project home>/dotnet/client-010/gentool:
+
+ $ cd <project home>/dotnet/client-010/gentool
+ $ ant
+
+You can build from Visual Studio 2008 normally. Alternatively, you
+can build debug releases for any supported framework from the
+command line using Nant:
+
+To build .NET 2.0 executables (to bin/net-2.0):
+
+ $ cd <project home>/dotnet/client-010/
+ $ nant
+
+
+To build for Mono on Linux (to bin/mono-2.0):
+
+ $ cd <project home>/dotnet/client-010/
+ $ nant -t:mono-2.0
+
+Releasing
+=========
+
+For .NET 2.0
+
+ $ cd <project home>/dotnet/client-010/
+ $ nant release-pkg
+
+Generates ./bin/net-2.0/release/Qpid.NET-net-2.0-yyyyMMdd.zip
+
+For Mono
+
+ $ cd <project home>/dotnet/client-010/
+ $ nant -t:mono-2.0 release-pkg
+
+Generates ./bin/mono-2.0/release/Qpid.NET-mono-2.0-yyyyMMdd.zip
+
diff --git a/dotnet/client-010/addins/ExcelAddIn/Excel.exe.config b/dotnet/client-010/addins/ExcelAddIn/Excel.exe.config
new file mode 100644
index 0000000000..66bf63532e
--- /dev/null
+++ b/dotnet/client-010/addins/ExcelAddIn/Excel.exe.config
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+ <appSettings>
+ <add key="Host" value="localhost" />
+ <add key="Port" value="5672" />
+ <add key="VirtualHost" value="test" />
+ <add key="UserName" value="guest" />
+ <add key="Password" value="guest" />
+ <!-- <add key="ProcessorAssembly" value="C:\Project\qpid\dotnet\client-010\addins\ExcelAddInMessageProcessor\bin\Debug\ExcelAddInMessageProcessor.dll"/>
+ <add key="ProcessorClass" value="ExcelAddInMessageProcessor.Processor"/> -->
+ </appSettings>
+</configuration> \ No newline at end of file
diff --git a/dotnet/client-010/addins/ExcelAddIn/ExcelAddIn.cs b/dotnet/client-010/addins/ExcelAddIn/ExcelAddIn.cs
new file mode 100644
index 0000000000..66c9b7a8f9
--- /dev/null
+++ b/dotnet/client-010/addins/ExcelAddIn/ExcelAddIn.cs
@@ -0,0 +1,290 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Text;
+using Microsoft.Office.Interop.Excel;
+using org.apache.qpid.client;
+using org.apache.qpid.transport;
+
+namespace ExcelAddIn
+{
+ public delegate string ProcessMessage(IMessage m);
+
+ /// <summary>
+ /// This interface must be implemented so to use a user defined message processor
+ /// </summary>
+ public interface MessageProcessor
+ {
+ string ProcessMessage(IMessage m);
+ }
+
+ [ComVisible(true), ProgId("Qpid")]
+ public class ExcelAddIn : IRtdServer
+ {
+ private IRTDUpdateEvent _onMessage;
+ private readonly Dictionary<int, IMessage> _topicMessages = new Dictionary<int, IMessage>();
+ private readonly Dictionary<string, QpidListener> _queueListener = new Dictionary<string, QpidListener>();
+ private readonly Dictionary<int, string> _topicQueueName = new Dictionary<int, string>();
+ private IClient _client;
+ private IClientSession _session;
+ private ProcessMessage _messageProcessor;
+
+ #region properties
+
+ public IRTDUpdateEvent OnMessage
+ {
+ get { return _onMessage; }
+ }
+
+ public Dictionary<int, IMessage> TopicMessages
+ {
+ get { return _topicMessages; }
+ }
+
+ public IClientSession Session
+ {
+ get { return _session; }
+ }
+
+ #endregion
+
+
+ #region IRtdServer Members
+
+ /// <summary>
+ /// Called when Excel requests the first RTD topic for the server.
+ /// Connect to the broker, returns a on success and 0 otherwise
+ /// </summary>
+ /// <param name="CallbackObject"></param>
+ /// <returns></returns>
+ public int ServerStart(IRTDUpdateEvent CallbackObject)
+ {
+ _onMessage = CallbackObject;
+ string host = "localhost";
+ string port = "5673";
+ string virtualhost = "test";
+ string username = "guest";
+ string password = "guest";
+ _messageProcessor = getMessage;
+
+ if( ConfigurationManager.AppSettings["Host"] != null )
+ {
+ host = ConfigurationManager.AppSettings["Host"];
+ }
+ if (ConfigurationManager.AppSettings["Port"] != null)
+ {
+ port = ConfigurationManager.AppSettings["Port"];
+ }
+ if (ConfigurationManager.AppSettings["VirtualHost"] != null)
+ {
+ virtualhost = ConfigurationManager.AppSettings["VirtualHost"];
+ }
+ if (ConfigurationManager.AppSettings["Username"] != null)
+ {
+ username = ConfigurationManager.AppSettings["UserName"];
+ }
+ if (ConfigurationManager.AppSettings["Password"] != null)
+ {
+ password = ConfigurationManager.AppSettings["Password"];
+ }
+ if (ConfigurationManager.AppSettings["ProcessorAssembly"] != null)
+ {
+ try
+ {
+ Assembly a = Assembly.LoadFrom(ConfigurationManager.AppSettings["ProcessorAssembly"]);
+ Object o = a.CreateInstance(ConfigurationManager.AppSettings["ProcessorClass"]);
+ MessageProcessor p = (MessageProcessor) o;
+ _messageProcessor = p.ProcessMessage;
+ }
+ catch (Exception e)
+ {
+ System.Windows.Forms.MessageBox.Show("Error: \n" + e.StackTrace);
+ return 0;
+ }
+ }
+
+ System.Windows.Forms.MessageBox.Show("Connection parameters: \n host: " + host + "\n port: "
+ + port + "\n user: " + username);
+ try
+ {
+ _client = new Client();
+ _client.Connect(host, Convert.ToInt16(port), virtualhost, username, password);
+ // create a session
+ _session = _client.CreateSession(0);
+ }
+ catch (Exception e)
+ {
+ System.Windows.Forms.MessageBox.Show("Error: \n" + e.StackTrace);
+ return 0;
+ }
+
+ // always successful
+ return 1;
+ }
+
+ /// <summary>
+ /// Called whenever Excel requests a new RTD topic from the RealTimeData server.
+ /// </summary>
+ /// <param name="TopicID"></param>
+ /// <param name="Strings"></param>
+ /// <param name="GetNewValues"></param>
+ /// <returns></returns>
+ public object ConnectData(int TopicID, ref Array Strings, ref bool GetNewValues)
+ {
+ try
+ {
+ string queuename = "defaultExcelAddInQueue";
+ string destinationName = "ExcelAddIn-" + queuename;
+ if( Strings.Length > 0 )
+ {
+ queuename = (string) Strings.GetValue(0);
+ }
+ // Error message if the queue does not exist
+ QueueQueryResult result = (QueueQueryResult)_session.QueueQuery(queuename).Result;
+ if( result.GetQueue() == null )
+ {
+ System.Windows.Forms.MessageBox.Show("Error: \n queue " + queuename + " does not exist");
+ return "error";
+ }
+
+ QpidListener listener;
+ _topicMessages.Add(TopicID, null);
+ _topicQueueName.Add(TopicID, queuename);
+ if (_queueListener.ContainsKey(queuename))
+ {
+ listener = _queueListener[queuename];
+ listener.addTopic(TopicID);
+ }
+ else
+ {
+ listener = new QpidListener(this);
+ listener.addTopic(TopicID);
+ _queueListener.Add(queuename, listener);
+ _session.AttachMessageListener(listener, destinationName);
+ _session.MessageSubscribe(queuename, destinationName, MessageAcceptMode.EXPLICIT,
+ MessageAcquireMode.PRE_ACQUIRED, null, 0, null);
+ // issue credits
+ _session.MessageSetFlowMode(destinationName, MessageFlowMode.WINDOW);
+ _session.MessageFlow(destinationName, MessageCreditUnit.BYTE, ClientSession.MESSAGE_FLOW_MAX_BYTES);
+ _session.MessageFlow(destinationName, MessageCreditUnit.MESSAGE, 1000);
+ _session.Sync();
+ }
+ }
+ catch (Exception e)
+ {
+ System.Windows.Forms.MessageBox.Show("Error: \n" + e.StackTrace);
+ return "error";
+ }
+ return "waiting";
+ }
+
+ /// <summary>
+ /// Called whenever Excel no longer requires a specific topic.
+ /// </summary>
+ /// <param name="TopicID"></param>
+ public void DisconnectData(int TopicID)
+ {
+ _topicMessages.Remove(TopicID);
+ string queueName = _topicQueueName[TopicID];
+ if (_topicQueueName.Remove(TopicID) && !_topicQueueName.ContainsValue(queueName))
+ {
+ _session.MessageStop("ExcelAddIn-" + queueName);
+ _session.MessageListeners.Remove("ExcelAddIn-" + queueName);
+ }
+ }
+
+ public int Heartbeat()
+ {
+ return 1;
+ }
+
+ public Array RefreshData(ref int TopicCount)
+ {
+ Array result = new object[2, _topicMessages.Count];
+ foreach (KeyValuePair<int, IMessage> pair in _topicMessages)
+ {
+ result.SetValue(pair.Key, 0, pair.Key);
+ string value = _messageProcessor(pair.Value);
+ result.SetValue(value, 1, pair.Key);
+ }
+ TopicCount = _topicMessages.Count;
+ return result;
+ }
+
+ public void ServerTerminate()
+ {
+
+ }
+
+ #endregion
+ //END IRTDServer METHODS
+
+ private string getMessage(IMessage m)
+ {
+ string res;
+ BinaryReader reader = new BinaryReader(m.Body, Encoding.UTF8);
+ byte[] body = new byte[m.Body.Length - m.Body.Position];
+ reader.Read(body, 0, body.Length);
+ ASCIIEncoding enc = new ASCIIEncoding();
+ res = enc.GetString(body);
+ return res;
+ }
+
+ }
+
+ class QpidListener : IMessageListener
+ {
+ private readonly ExcelAddIn _excel;
+ private readonly List<int> _topics = new List<int>();
+
+ public QpidListener(ExcelAddIn excel)
+ {
+ _excel = excel;
+ }
+
+ public void addTopic(int topic)
+ {
+ _topics.Add(topic);
+ }
+
+ public void MessageTransfer(IMessage m)
+ {
+ foreach (int i in _topics)
+ {
+ if (_excel.TopicMessages.ContainsKey(i))
+ {
+ _excel.TopicMessages[i] = m;
+ }
+ }
+ // ack this message
+ RangeSet rs = new RangeSet();
+ rs.Add(m.Id);
+ _excel.Session.MessageAccept(rs);
+ _excel.OnMessage.UpdateNotify();
+ }
+ }
+}
diff --git a/dotnet/client-010/addins/ExcelAddIn/ExcelAddIn.csproj b/dotnet/client-010/addins/ExcelAddIn/ExcelAddIn.csproj
new file mode 100644
index 0000000000..34c8bda33b
--- /dev/null
+++ b/dotnet/client-010/addins/ExcelAddIn/ExcelAddIn.csproj
@@ -0,0 +1,69 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{85EFD719-39F6-4471-90FF-9E621430344B}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>ExcelAddIn</RootNamespace>
+ <AssemblyName>Qpid Excel AddIn</AssemblyName>
+ <StartupObject>
+ </StartupObject>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <RegisterForComInterop>true</RegisterForComInterop>
+ <DocumentationFile>bin\Debug\Qpid Excel AddIn.XML</DocumentationFile>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Microsoft.Office.Interop.Excel, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
+ <Reference Include="System" />
+ <Reference Include="System.configuration" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Windows.Forms" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="**\*.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\client\Client.csproj">
+ <Project>{B911FFD7-754F-4735-A188-218D5065BE79}</Project>
+ <Name>Client</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\App.config">
+ <Link>App.config</Link>
+ </None>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/dotnet/client-010/addins/ExcelAddIn/Properties/AssemblyInfo.cs b/dotnet/client-010/addins/ExcelAddIn/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..67e95f69a3
--- /dev/null
+++ b/dotnet/client-010/addins/ExcelAddIn/Properties/AssemblyInfo.cs
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Qpid Excel AddIn")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("Qpid Excel AddIn")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("3bbd4414-60df-407f-9c64-c14b221167af")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/client-010/addins/ExcelAddInMessageProcessor/ExcelAddInMessageProcessor.csproj b/dotnet/client-010/addins/ExcelAddInMessageProcessor/ExcelAddInMessageProcessor.csproj
new file mode 100644
index 0000000000..c7ae1d1c6d
--- /dev/null
+++ b/dotnet/client-010/addins/ExcelAddInMessageProcessor/ExcelAddInMessageProcessor.csproj
@@ -0,0 +1,66 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{C2AE83A3-D5D1-469D-8611-A4738B9997CF}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>ExcelAddInMessageProcessor</RootNamespace>
+ <AssemblyName>ExcelAddInMessageProcessor</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="**\*.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\client\Client.csproj">
+ <Project>{B911FFD7-754F-4735-A188-218D5065BE79}</Project>
+ <Name>Client</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\ExcelAddIn\ExcelAddIn.csproj">
+ <Project>{85EFD719-39F6-4471-90FF-9E621430344B}</Project>
+ <Name>ExcelAddIn</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\App.config">
+ <Link>App.config</Link>
+ </None>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/dotnet/client-010/addins/ExcelAddInMessageProcessor/Processor.cs b/dotnet/client-010/addins/ExcelAddInMessageProcessor/Processor.cs
new file mode 100644
index 0000000000..e414da131f
--- /dev/null
+++ b/dotnet/client-010/addins/ExcelAddInMessageProcessor/Processor.cs
@@ -0,0 +1,44 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System.IO;
+using System.Text;
+using org.apache.qpid.client;
+
+namespace ExcelAddInMessageProcessor
+{
+ class Processor : ExcelAddIn.MessageProcessor
+ {
+ public string ProcessMessage(IMessage m)
+ {
+ BinaryReader reader = new BinaryReader(m.Body, Encoding.UTF8);
+ byte[] body = new byte[m.Body.Length - m.Body.Position];
+ reader.Read(body, 0, body.Length);
+ ASCIIEncoding enc = new ASCIIEncoding();
+ string res = enc.GetString(body);
+ if (m.ApplicationHeaders.ContainsKey("price"))
+ {
+ res = res + ": price: " + m.ApplicationHeaders["price"];
+ }
+ return res;
+ }
+ }
+} \ No newline at end of file
diff --git a/dotnet/client-010/addins/ExcelAddInMessageProcessor/Properties/AssemblyInfo.cs b/dotnet/client-010/addins/ExcelAddInMessageProcessor/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..302007674f
--- /dev/null
+++ b/dotnet/client-010/addins/ExcelAddInMessageProcessor/Properties/AssemblyInfo.cs
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ExcelAddInMessageProcessor")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("ExcelAddInMessageProcessor")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("d20b2d75-7b8b-4f7d-8a81-40a4cce94195")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/client-010/addins/ExcelAddInProducer/ExcelAddInProducer.csproj b/dotnet/client-010/addins/ExcelAddInProducer/ExcelAddInProducer.csproj
new file mode 100644
index 0000000000..e69f4cf35a
--- /dev/null
+++ b/dotnet/client-010/addins/ExcelAddInProducer/ExcelAddInProducer.csproj
@@ -0,0 +1,63 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{80F00C3B-EB38-4B3B-9F77-68977A30B155}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>ExcelAddInProducer</RootNamespace>
+ <AssemblyName>Qpid Excel AddIn Producer</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.configuration" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="**\*.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\client\Client.csproj">
+ <Project>{B911FFD7-754F-4735-A188-218D5065BE79}</Project>
+ <Name>Client</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\App.config">
+ <Link>App.config</Link>
+ </None>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/dotnet/client-010/addins/ExcelAddInProducer/Program.cs b/dotnet/client-010/addins/ExcelAddInProducer/Program.cs
new file mode 100644
index 0000000000..a8bbdf2fbd
--- /dev/null
+++ b/dotnet/client-010/addins/ExcelAddInProducer/Program.cs
@@ -0,0 +1,62 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using System.Configuration;
+using System.Text;
+using System.Threading;
+using org.apache.qpid.client;
+
+namespace ExcelAddInProducer
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ string host = ConfigurationManager.AppSettings["Host"];
+ int port = int.Parse(ConfigurationManager.AppSettings["Port"]);
+ string virtualhost = ConfigurationManager.AppSettings["VirtualHost"];
+ string username = ConfigurationManager.AppSettings["Username"];
+ string password = ConfigurationManager.AppSettings["Password"];
+
+ Client client = new Client();
+ Console.WriteLine("Client created");
+ client.Connect(host, port, virtualhost, username, password);
+ Console.WriteLine("Connection established");
+
+ IClientSession ssn = client.CreateSession(50000);
+ Console.WriteLine("Session created");
+ ssn.QueueDeclare("queue1", null, null);
+ ssn.ExchangeBind("queue1", "amq.direct", "queue1", null);
+ IMessage message = new Message();
+ message.ApplicationHeaders.Add("price", 0);
+ for (int i = 0; i < 100; i++)
+ {
+ message.ClearData();
+ message.AppendData( Encoding.UTF8.GetBytes("test: " + i));
+ message.ApplicationHeaders["price"] = i;
+ ssn.MessageTransfer("amq.direct", "queue1", message);
+ Thread.Sleep(1000);
+ }
+
+ client.Close();
+ }
+ }
+}
diff --git a/dotnet/client-010/addins/ExcelAddInProducer/Properties/AssemblyInfo.cs b/dotnet/client-010/addins/ExcelAddInProducer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..28fe3427cb
--- /dev/null
+++ b/dotnet/client-010/addins/ExcelAddInProducer/Properties/AssemblyInfo.cs
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Qpid Excel AddIn Producer")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("Qpid Excel AddIn Producer")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("3416a5c2-eb70-4d77-b401-dfa659bd419e")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/client-010/addins/README.txt b/dotnet/client-010/addins/README.txt
new file mode 100644
index 0000000000..5f8df77189
--- /dev/null
+++ b/dotnet/client-010/addins/README.txt
@@ -0,0 +1,29 @@
+This project contains three sub-projects:
+- The RTD excell Addin
+- A sample client sending messages to queue1
+- A ample message processor
+
+RDT AddIn
+Excel provides a function called RTD (real-time data) that lets you specify a COM server via its ProgId here "Qpid" so that you can push qpid messages into Excel.
+For using the Qpid RTD follows those steps:
+
+1) Copy the configuration Excel.exe.config into C:\Program Files\Microsoft Office\Office12
+2) Edit Excel.exe.xml and set the targeted Qpid broker host, port number
+3) Select the cell or cell range to contain the information
+4) enter the following formula =rtd("Qpid",,"myQueue") Where MyQueue is the queue from which you wish to receive messages from
+
+Note: The Qpid RTD is a COM-AddIn that must be registered with Excel. This is done automatically when compiling the Addin with visual studio.
+
+The default behavior of the RDT AddIn is to display the message payload. This could be altered by specifying your own message processor.
+A Message processor is a class that implements the API ExcelAddIn.MessageProcessor. For example, the provided processor in client-010\addins\ExcelAddInMessageProcessor displays the message body and the the header price when specified.
+
+To use you own message processor follows those steps:
+1) Write your own message processor that extends ExcelAddIn.MessageProcessor
+2) Edit Excel.exe.config and uncomment the entries:
+ <add key="ProcessorAssembly" value="<path>\qpid\dotnet\client-010\addins\ExcelAddInMessageProcessor\bin\Debug\ExcelAddInMessageProcessor.dll"/>
+ <add key="ProcessorClass" value="ExcelAddInMessageProcessor.Processor"/>
+- ProcessorAssembly is the path on the Assembly that contains your processor class
+- ProcessorClass is your processor class name
+3) run excel and define a rtd function
+
+Note: the provided ExcelAddInProducer can be used for testing the provided message processor. As messages are sent to queue1 the following rtd fucntion should be used =rtd("Qpiud",,"queue1") \ No newline at end of file
diff --git a/dotnet/client-010/client/Client.csproj b/dotnet/client-010/client/Client.csproj
new file mode 100644
index 0000000000..5b71ad0581
--- /dev/null
+++ b/dotnet/client-010/client/Client.csproj
@@ -0,0 +1,222 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{B911FFD7-754F-4735-A188-218D5065BE79}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>client</RootNamespace>
+ <AssemblyName>Qpid Client</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\lib\log4net\log4net.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="client\Client.cs" />
+ <Compile Include="client\ClientConnectionDelegate.cs" />
+ <Compile Include="client\ClientSession.cs" />
+ <Compile Include="client\ClientSessionDelegate.cs" />
+ <Compile Include="client\ErrorCode.cs" />
+ <Compile Include="client\IClient.cs" />
+ <Compile Include="client\IClientSession.cs" />
+ <Compile Include="client\IClosedListener.cs" />
+ <Compile Include="client\IMessage.cs" />
+ <Compile Include="client\Message.cs" />
+ <Compile Include="client\IMessageListener.cs" />
+ <Compile Include="generated\Acquired.cs" />
+ <Compile Include="generated\ConnectionClose.cs" />
+ <Compile Include="generated\ConnectionCloseCode.cs" />
+ <Compile Include="generated\ConnectionCloseOk.cs" />
+ <Compile Include="generated\ConnectionHeartbeat.cs" />
+ <Compile Include="generated\ConnectionOpen.cs" />
+ <Compile Include="generated\ConnectionOpenOk.cs" />
+ <Compile Include="generated\ConnectionRedirect.cs" />
+ <Compile Include="generated\ConnectionSecure.cs" />
+ <Compile Include="generated\ConnectionSecureOk.cs" />
+ <Compile Include="generated\ConnectionStart.cs" />
+ <Compile Include="generated\ConnectionStartOk.cs" />
+ <Compile Include="generated\ConnectionTune.cs" />
+ <Compile Include="generated\ConnectionTuneOk.cs" />
+ <Compile Include="generated\Constant.cs" />
+ <Compile Include="generated\DeliveryProperties.cs" />
+ <Compile Include="generated\DtxCommit.cs" />
+ <Compile Include="generated\DtxEnd.cs" />
+ <Compile Include="generated\DtxForget.cs" />
+ <Compile Include="generated\DtxGetTimeout.cs" />
+ <Compile Include="generated\DtxPrepare.cs" />
+ <Compile Include="generated\DtxRecover.cs" />
+ <Compile Include="generated\DtxRollback.cs" />
+ <Compile Include="generated\DtxSelect.cs" />
+ <Compile Include="generated\DtxSetTimeout.cs" />
+ <Compile Include="generated\DtxStart.cs" />
+ <Compile Include="generated\DtxXaStatus.cs" />
+ <Compile Include="generated\ExchangeBind.cs" />
+ <Compile Include="generated\ExchangeBound.cs" />
+ <Compile Include="generated\ExchangeBoundResult.cs" />
+ <Compile Include="generated\ExchangeDeclare.cs" />
+ <Compile Include="generated\ExchangeDelete.cs" />
+ <Compile Include="generated\ExchangeQuery.cs" />
+ <Compile Include="generated\ExchangeQueryResult.cs" />
+ <Compile Include="generated\ExchangeUnbind.cs" />
+ <Compile Include="generated\ExecutionErrorCode.cs" />
+ <Compile Include="generated\ExecutionException.cs" />
+ <Compile Include="generated\ExecutionResult.cs" />
+ <Compile Include="generated\ExecutionSync.cs" />
+ <Compile Include="generated\FileReturnCode.cs" />
+ <Compile Include="generated\FragmentProperties.cs" />
+ <Compile Include="generated\GetTimeoutResult.cs" />
+ <Compile Include="generated\IInvoker.cs" />
+ <Compile Include="generated\Invoker.cs" />
+ <Compile Include="generated\MessageAccept.cs" />
+ <Compile Include="generated\MessageAcceptMode.cs" />
+ <Compile Include="generated\MessageAcquire.cs" />
+ <Compile Include="generated\MessageAcquireMode.cs" />
+ <Compile Include="generated\MessageCancel.cs" />
+ <Compile Include="generated\MessageCreditUnit.cs" />
+ <Compile Include="generated\MessageDeliveryMode.cs" />
+ <Compile Include="generated\MessageDeliveryPriority.cs" />
+ <Compile Include="generated\MessageFlow.cs" />
+ <Compile Include="generated\MessageFlowMode.cs" />
+ <Compile Include="generated\MessageFlush.cs" />
+ <Compile Include="generated\MessageProperties.cs" />
+ <Compile Include="generated\MessageReject.cs" />
+ <Compile Include="generated\MessageRejectCode.cs" />
+ <Compile Include="generated\MessageRelease.cs" />
+ <Compile Include="generated\MessageResume.cs" />
+ <Compile Include="generated\MessageResumeResult.cs" />
+ <Compile Include="generated\MessageSetFlowMode.cs" />
+ <Compile Include="generated\MessageStop.cs" />
+ <Compile Include="generated\MessageSubscribe.cs" />
+ <Compile Include="generated\MessageTransfer.cs" />
+ <Compile Include="generated\MethodDelegate.cs" />
+ <Compile Include="generated\Option.cs" />
+ <Compile Include="generated\QueueDeclare.cs" />
+ <Compile Include="generated\QueueDelete.cs" />
+ <Compile Include="generated\QueuePurge.cs" />
+ <Compile Include="generated\QueueQuery.cs" />
+ <Compile Include="generated\QueueQueryResult.cs" />
+ <Compile Include="generated\RecoverResult.cs" />
+ <Compile Include="generated\ReplyTo.cs" />
+ <Compile Include="generated\SegmentType.cs" />
+ <Compile Include="generated\SessionAttach.cs" />
+ <Compile Include="generated\SessionAttached.cs" />
+ <Compile Include="generated\SessionCommandFragment.cs" />
+ <Compile Include="generated\SessionCommandPoint.cs" />
+ <Compile Include="generated\SessionCompleted.cs" />
+ <Compile Include="generated\SessionConfirmed.cs" />
+ <Compile Include="generated\SessionDetach.cs" />
+ <Compile Include="generated\SessionDetachCode.cs" />
+ <Compile Include="generated\SessionDetached.cs" />
+ <Compile Include="generated\SessionExpected.cs" />
+ <Compile Include="generated\SessionFlush.cs" />
+ <Compile Include="generated\SessionGap.cs" />
+ <Compile Include="generated\SessionHeader.cs" />
+ <Compile Include="generated\SessionKnownCompleted.cs" />
+ <Compile Include="generated\SessionRequestTimeout.cs" />
+ <Compile Include="generated\SessionTimeout.cs" />
+ <Compile Include="generated\StreamReturnCode.cs" />
+ <Compile Include="generated\StructFactory.cs" />
+ <Compile Include="generated\Track.cs" />
+ <Compile Include="generated\TxCommit.cs" />
+ <Compile Include="generated\TxRollback.cs" />
+ <Compile Include="generated\TxSelect.cs" />
+ <Compile Include="generated\Type.cs" />
+ <Compile Include="generated\XaResult.cs" />
+ <Compile Include="generated\Xid.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="transport\Binary.cs" />
+ <Compile Include="transport\IBinding.cs" />
+ <Compile Include="transport\Channel.cs" />
+ <Compile Include="transport\ChannelDelegate.cs" />
+ <Compile Include="transport\ClientDelegate.cs" />
+ <Compile Include="transport\codec\AbstractDecoder.cs" />
+ <Compile Include="transport\codec\AbstractEncoder.cs" />
+ <Compile Include="transport\codec\IDecoder.cs" />
+ <Compile Include="transport\codec\IEncodable.cs" />
+ <Compile Include="transport\codec\IEncoder.cs" />
+ <Compile Include="transport\codec\MSDecoder.cs" />
+ <Compile Include="transport\codec\MSEncoder.cs" />
+ <Compile Include="transport\Connection.cs" />
+ <Compile Include="transport\ConnectionDelegate.cs" />
+ <Compile Include="transport\exception\ConnectionException.cs" />
+ <Compile Include="transport\exception\ExceptionArgs.cs" />
+ <Compile Include="transport\exception\ProtocolVersionException.cs" />
+ <Compile Include="transport\exception\SessionClosedException.cs" />
+ <Compile Include="transport\exception\SessionException.cs" />
+ <Compile Include="transport\exception\TransportException.cs" />
+ <Compile Include="transport\Field.cs" />
+ <Compile Include="transport\IFuture.cs" />
+ <Compile Include="transport\Header.cs" />
+ <Compile Include="transport\ISession.cs" />
+ <Compile Include="transport\Method.cs" />
+ <Compile Include="transport\network\Assembler.cs" />
+ <Compile Include="transport\network\Disassembler.cs" />
+ <Compile Include="transport\network\Frame.cs" />
+ <Compile Include="transport\network\io\IIoSender.cs" />
+ <Compile Include="transport\network\InputHandler.cs" />
+ <Compile Include="transport\network\io\IIoTransport.cs" />
+ <Compile Include="transport\network\io\IoReceiver.cs" />
+ <Compile Include="transport\network\io\IoSender.cs" />
+ <Compile Include="transport\network\io\IoSSLTransport.cs" />
+ <Compile Include="transport\network\io\IoTransport.cs" />
+ <Compile Include="transport\network\INetworkDelegate.cs" />
+ <Compile Include="transport\network\INetworkEvent.cs" />
+ <Compile Include="transport\IProtocolDelegate.cs" />
+ <Compile Include="transport\ProtocolError.cs" />
+ <Compile Include="transport\IProtocolEvent.cs" />
+ <Compile Include="transport\ProtocolHeader.cs" />
+ <Compile Include="transport\Range.cs" />
+ <Compile Include="transport\RangeSet.cs" />
+ <Compile Include="transport\ReceivedPayload.cs" />
+ <Compile Include="transport\IReceiver.cs" />
+ <Compile Include="transport\ISender.cs" />
+ <Compile Include="transport\Session.cs" />
+ <Compile Include="transport\SessionDelegate.cs" />
+ <Compile Include="transport\Struct.cs" />
+ <Compile Include="transport\util\ByteEncoder.cs" />
+ <Compile Include="transport\util\CircularBuffer.cs" />
+ <Compile Include="transport\util\Functions.cs" />
+ <Compile Include="transport\util\Logger.cs" />
+ <Compile Include="transport\util\ResultFuture.cs" />
+ <Compile Include="transport\util\Serial.cs" />
+ <Compile Include="transport\util\UUID.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/dotnet/client-010/client/Properties/AssemblyInfo.cs b/dotnet/client-010/client/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..2b6c525b86
--- /dev/null
+++ b/dotnet/client-010/client/Properties/AssemblyInfo.cs
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Qpid Client")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("Qpid Client")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("dac7ef42-e9c8-45a5-8050-1301b6f8160e")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/client-010/client/client.sln b/dotnet/client-010/client/client.sln
new file mode 100644
index 0000000000..0d7a57d880
--- /dev/null
+++ b/dotnet/client-010/client/client.sln
@@ -0,0 +1,109 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client", "Client.csproj", "{B911FFD7-754F-4735-A188-218D5065BE79}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo", "..\demo\Demo.csproj", "{E4C46FBC-7560-406D-BFEF-CA010E584DF4}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExcelAddIn", "..\addins\ExcelAddIn\ExcelAddIn.csproj", "{85EFD719-39F6-4471-90FF-9E621430344B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExcelAddInProducer", "..\addins\ExcelAddInProducer\ExcelAddInProducer.csproj", "{80F00C3B-EB38-4B3B-9F77-68977A30B155}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example-direct-producer", "..\examples\direct\example-direct-producer\example-direct-producer.csproj", "{96FCB250-8142-40EE-9BDD-CA839EE21021}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example-direct-Listener", "..\examples\direct\example-direct-Listener\example-direct-Listener.csproj", "{AE65B1B9-8779-4CB1-91AF-E7F6C7A736D7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example-pub-sub-Listener", "..\examples\pub-sub\example-pub-sub-Listener\example-pub-sub-Listener.csproj", "{2BCDC2CC-5BDA-4CC7-944D-2899AD8A53C7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example-pub-sub-Publisher", "..\examples\pub-sub\example-pub-sub-Publisher\example-pub-sub-Publisher.csproj", "{F8857634-A134-44E7-A953-F2B22688C599}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "..\test\Test.csproj", "{95CB4C90-7C53-44A9-B11C-96235F158ACA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example-request-response-Client", "..\examples\request-response\example-request-response-Client\example-request-response-Client.csproj", "{1BC63815-4029-4039-9207-35E7E06ECC99}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example-request-response-Server", "..\examples\request-response\example-request-response-Server\example-request-response-Server.csproj", "{922FBA9C-E483-4AEF-ABE8-AC87421E829B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example-fanout-Producer", "..\examples\fanout\example-fanout-Producer\example-fanout-Producer.csproj", "{4513BF94-D54A-42FE-8506-FE2CD57B2C51}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example-fanout-Listener", "..\examples\fanout\example-fanout-Listener\example-fanout-Listener.csproj", "{18A0792B-DC3A-4EC5-93D6-DB8A111D8F15}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "perftest", "..\perftest\perftest.csproj", "{7F7E8DE7-FDF2-4A52-A4CE-D3756B05273C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExcelAddInMessageProcessor", "..\addins\ExcelAddInMessageProcessor\ExcelAddInMessageProcessor.csproj", "{C2AE83A3-D5D1-469D-8611-A4738B9997CF}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3CE4FA2A-393F-4DED-ABDF-1BC2F253ACA8}"
+ ProjectSection(SolutionItems) = preProject
+ ..\App.config = ..\App.config
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {B911FFD7-754F-4735-A188-218D5065BE79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B911FFD7-754F-4735-A188-218D5065BE79}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B911FFD7-754F-4735-A188-218D5065BE79}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B911FFD7-754F-4735-A188-218D5065BE79}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E4C46FBC-7560-406D-BFEF-CA010E584DF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E4C46FBC-7560-406D-BFEF-CA010E584DF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E4C46FBC-7560-406D-BFEF-CA010E584DF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E4C46FBC-7560-406D-BFEF-CA010E584DF4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {85EFD719-39F6-4471-90FF-9E621430344B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {85EFD719-39F6-4471-90FF-9E621430344B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {85EFD719-39F6-4471-90FF-9E621430344B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {85EFD719-39F6-4471-90FF-9E621430344B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {80F00C3B-EB38-4B3B-9F77-68977A30B155}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {80F00C3B-EB38-4B3B-9F77-68977A30B155}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {80F00C3B-EB38-4B3B-9F77-68977A30B155}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {80F00C3B-EB38-4B3B-9F77-68977A30B155}.Release|Any CPU.Build.0 = Release|Any CPU
+ {96FCB250-8142-40EE-9BDD-CA839EE21021}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {96FCB250-8142-40EE-9BDD-CA839EE21021}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {96FCB250-8142-40EE-9BDD-CA839EE21021}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {96FCB250-8142-40EE-9BDD-CA839EE21021}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AE65B1B9-8779-4CB1-91AF-E7F6C7A736D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AE65B1B9-8779-4CB1-91AF-E7F6C7A736D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AE65B1B9-8779-4CB1-91AF-E7F6C7A736D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AE65B1B9-8779-4CB1-91AF-E7F6C7A736D7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2BCDC2CC-5BDA-4CC7-944D-2899AD8A53C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2BCDC2CC-5BDA-4CC7-944D-2899AD8A53C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2BCDC2CC-5BDA-4CC7-944D-2899AD8A53C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2BCDC2CC-5BDA-4CC7-944D-2899AD8A53C7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F8857634-A134-44E7-A953-F2B22688C599}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F8857634-A134-44E7-A953-F2B22688C599}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F8857634-A134-44E7-A953-F2B22688C599}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F8857634-A134-44E7-A953-F2B22688C599}.Release|Any CPU.Build.0 = Release|Any CPU
+ {95CB4C90-7C53-44A9-B11C-96235F158ACA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {95CB4C90-7C53-44A9-B11C-96235F158ACA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {95CB4C90-7C53-44A9-B11C-96235F158ACA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {95CB4C90-7C53-44A9-B11C-96235F158ACA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1BC63815-4029-4039-9207-35E7E06ECC99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1BC63815-4029-4039-9207-35E7E06ECC99}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1BC63815-4029-4039-9207-35E7E06ECC99}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1BC63815-4029-4039-9207-35E7E06ECC99}.Release|Any CPU.Build.0 = Release|Any CPU
+ {922FBA9C-E483-4AEF-ABE8-AC87421E829B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {922FBA9C-E483-4AEF-ABE8-AC87421E829B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {922FBA9C-E483-4AEF-ABE8-AC87421E829B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {922FBA9C-E483-4AEF-ABE8-AC87421E829B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4513BF94-D54A-42FE-8506-FE2CD57B2C51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4513BF94-D54A-42FE-8506-FE2CD57B2C51}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4513BF94-D54A-42FE-8506-FE2CD57B2C51}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4513BF94-D54A-42FE-8506-FE2CD57B2C51}.Release|Any CPU.Build.0 = Release|Any CPU
+ {18A0792B-DC3A-4EC5-93D6-DB8A111D8F15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {18A0792B-DC3A-4EC5-93D6-DB8A111D8F15}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {18A0792B-DC3A-4EC5-93D6-DB8A111D8F15}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {18A0792B-DC3A-4EC5-93D6-DB8A111D8F15}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7F7E8DE7-FDF2-4A52-A4CE-D3756B05273C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7F7E8DE7-FDF2-4A52-A4CE-D3756B05273C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7F7E8DE7-FDF2-4A52-A4CE-D3756B05273C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7F7E8DE7-FDF2-4A52-A4CE-D3756B05273C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C2AE83A3-D5D1-469D-8611-A4738B9997CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C2AE83A3-D5D1-469D-8611-A4738B9997CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C2AE83A3-D5D1-469D-8611-A4738B9997CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C2AE83A3-D5D1-469D-8611-A4738B9997CF}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/dotnet/client-010/client/client.suo b/dotnet/client-010/client/client.suo
new file mode 100644
index 0000000000..0640275f99
--- /dev/null
+++ b/dotnet/client-010/client/client.suo
Binary files differ
diff --git a/dotnet/client-010/client/client/Client.cs b/dotnet/client-010/client/client/Client.cs
new file mode 100644
index 0000000000..864cf65186
--- /dev/null
+++ b/dotnet/client-010/client/client/Client.cs
@@ -0,0 +1,170 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+using System;
+using System.Text;
+using System.Threading;
+using org.apache.qpid.transport;
+using org.apache.qpid.transport.network.io;
+using org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.client
+{
+ public class Client : IClient
+ {
+ private Connection _conn;
+ private static readonly Logger _log = Logger.Get(typeof (Client));
+ private const long timeout = 60000;
+ private bool _isClosed;
+ private readonly Object _closeOK;
+ private IClosedListener _closedListner;
+
+ public event EventHandler<ExceptionArgs> ExceptionRaised;
+ public event EventHandler ConnectionLost;
+
+ public bool IsClosed
+ {
+ get { return _isClosed; }
+ set
+ {
+ _isClosed = value;
+ if(_isClosed && ConnectionLost != null)
+ ConnectionLost(this, EventArgs.Empty);
+ }
+ }
+
+ public Object CloseOk
+ {
+ get { return _closeOK; }
+ }
+
+ public Client()
+ {
+ _isClosed = false;
+ _closeOK = new object();
+ }
+
+ #region Interface IClient
+
+ /// <summary>
+ /// Establishes a connection with a broker using the provided user auths
+ ///
+ /// </summary>
+ /// <param name="host">Host name on which a broker is deployed</param>
+ /// <param name="port">Broker port </param>
+ /// <param name="virtualHost">virtual host name</param>
+ /// <param name="username">User Name</param>
+ /// <param name="password">Password</param>
+ public void Connect(String host, int port, String virtualHost, String username, String password)
+ {
+ _log.Debug(String.Format("Client Connecting to host {0}; port {1}; virtualHost {2}; username {3}", host,
+ port, virtualHost, username));
+ ClientConnectionDelegate connectionDelegate = new ClientConnectionDelegate(this, username, password);
+ ManualResetEvent negotiationComplete = new ManualResetEvent(false);
+ connectionDelegate.SetCondition(negotiationComplete);
+ connectionDelegate.VirtualHost = virtualHost;
+ _conn = IoTransport.Connect(host, port, connectionDelegate);
+
+ _conn.Send(new ProtocolHeader(1, 0, 10));
+ negotiationComplete.WaitOne();
+
+ if (connectionDelegate.Exception != null)
+ throw connectionDelegate.Exception;
+
+ connectionDelegate.SetCondition(null);
+
+ }
+
+ /// <summary>
+ /// Establishes a connection with a broker using SSL
+ ///
+ /// </summary>
+ /// <param name="host">Host name on which a broker is deployed</param>
+ /// <param name="port">Broker port </param>
+ /// <param name="virtualHost">virtual host name</param>
+ /// <param name="username">User Name</param>
+ /// <param name="password">Password</param>
+ /// <param name="serverName">Name of the SSL server</param>
+ /// <param name="certPath">Path to the X509 certificate to be used for client authentication</param>
+ /// <param name="rejectUntrusted">If true connection will not be established if the broker is not trusted</param>
+ public void ConnectSSL(String host, int port, String virtualHost, String username, String password, string serverName, string certPath, bool rejectUntrusted)
+ {
+ _log.Debug(String.Format("Client Connecting to host {0}; port {1}; virtualHost {2}; username {3}", host,
+ port, virtualHost, username));
+ _log.Debug(String.Format("SSL paramters: serverName: {0}; certPath: {1}; rejectUntrusted: {2}", serverName, certPath, rejectUntrusted));
+ ClientConnectionDelegate connectionDelegate = new ClientConnectionDelegate(this, username, password);
+ ManualResetEvent negotiationComplete = new ManualResetEvent(false);
+ connectionDelegate.SetCondition(negotiationComplete);
+ connectionDelegate.VirtualHost = virtualHost;
+ _conn = IoSSLTransport.Connect(host, port, serverName, certPath, rejectUntrusted, connectionDelegate);
+
+ _conn.Send(new ProtocolHeader(1, 0, 10));
+ negotiationComplete.WaitOne();
+
+ if (connectionDelegate.Exception != null)
+ throw connectionDelegate.Exception;
+
+ connectionDelegate.SetCondition(null);
+ }
+
+ public void Close()
+ {
+ Channel ch = _conn.GetChannel(0);
+ ch.ConnectionClose(ConnectionCloseCode.NORMAL, "client is closing");
+ lock (CloseOk)
+ {
+ DateTime start = DateTime.Now;
+ long elapsed = 0;
+ while (!IsClosed && elapsed < timeout)
+ {
+ Monitor.Wait(CloseOk, (int) (timeout - elapsed));
+ elapsed = DateTime.Now.Subtract(start).Milliseconds;
+ }
+ if (!IsClosed)
+ {
+ throw new Exception("Timed out when closing connection");
+ }
+ _conn.Close();
+ }
+ }
+
+ public IClientSession CreateSession(long expiryInSeconds)
+ {
+ Channel ch = _conn.GetChannel();
+ ClientSession ssn = new ClientSession(Encoding.UTF8.GetBytes(UUID.RandomUuid().ToString()));
+ ssn.Attach(ch);
+ ssn.SessionAttach(ssn.GetName());
+ ssn.SessionRequestTimeout(expiryInSeconds);
+ return ssn;
+ }
+
+ public IClosedListener ClosedListener
+ {
+ set { _closedListner = value; }
+ get { return _closedListner; }
+ }
+
+ #endregion
+
+ public void RaiseException(Exception exception)
+ {
+ if (ExceptionRaised != null)
+ ExceptionRaised(this, new ExceptionArgs(exception));
+ }
+ }
+}
diff --git a/dotnet/client-010/client/client/ClientConnectionDelegate.cs b/dotnet/client-010/client/client/ClientConnectionDelegate.cs
new file mode 100644
index 0000000000..9999f5312d
--- /dev/null
+++ b/dotnet/client-010/client/client/ClientConnectionDelegate.cs
@@ -0,0 +1,108 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Threading;
+using org.apache.qpid.transport;
+using org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.client
+{
+ internal class ClientConnectionDelegate : ClientDelegate
+ {
+ private static readonly Logger log = Logger.Get(typeof (ClientConnectionDelegate));
+ private readonly Client _client;
+ private string _username;
+ private string _password;
+ private Exception _exception;
+
+ public ClientConnectionDelegate(Client client, string username, string pasword)
+ {
+ _client = client;
+ _username = username;
+ _password = pasword;
+ }
+
+ public Exception Exception
+ {
+ get { return _exception; }
+ }
+
+ public override SessionDelegate GetSessionDelegate()
+ {
+ return new ClientSessionDelegate();
+ }
+
+ public override void RaiseException(Exception exception)
+ {
+ _exception = exception;
+
+ if (_negotiationComplete != null)
+ _negotiationComplete.Set();
+ else
+ _client.RaiseException(exception);
+ }
+
+ public override void ConnectionStart(Channel context, ConnectionStart mystruct)
+ {
+ const string mechanism = "PLAIN";
+ MemoryStream stResponse = new MemoryStream();
+ byte[] part = Encoding.UTF8.GetBytes(_username);
+ stResponse.WriteByte(0);
+ stResponse.Write(part, 0, part.Length);
+ stResponse.WriteByte(0);
+ part = Encoding.UTF8.GetBytes(_password);
+ stResponse.Write(part, 0, part.Length);
+ Dictionary<String, Object> props = new Dictionary<String, Object>();
+ context.ConnectionStartOk(props, mechanism, stResponse.ToArray(), "utf8");
+ }
+
+ public override void Closed()
+ {
+ log.Debug("Delegate Closed");
+ lock (_client.CloseOk)
+ {
+ try
+ {
+ _client.IsClosed = true;
+ Monitor.PulseAll(_client.CloseOk);
+ }
+ catch (Exception e)
+ {
+ throw new SystemException("Error when closing client", e);
+ }
+ }
+ }
+
+ public override void ConnectionClose(Channel context, ConnectionClose connectionClose)
+ {
+ base.ConnectionClose(context, connectionClose);
+ ErrorCode errorCode = ErrorCode.GetErrorCode((int) connectionClose.GetReplyCode());
+
+ if(_client.ClosedListener != null)
+ _client.ClosedListener.OnClosed(errorCode, connectionClose.GetReplyText(), null);
+
+ if (errorCode.Code != (int)QpidErrorCode.NO_ERROR)
+ throw new Exception ("Server Closed the connection: Reason " + connectionClose.GetReplyText());
+ }
+ }
+}
diff --git a/dotnet/client-010/client/client/ClientInterface.cs b/dotnet/client-010/client/client/ClientInterface.cs
new file mode 100644
index 0000000000..fcf7ae9f31
--- /dev/null
+++ b/dotnet/client-010/client/client/ClientInterface.cs
@@ -0,0 +1,59 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System;
+
+namespace org.apache.qpid.client
+{
+ public interface ClientInterface
+ {
+ /// <summary>
+ /// Establish a connection with the broker using the given parameters
+ ///
+ /// </summary>
+ /// <param name="host">host name</param>
+ /// <param name="port">port number</param>
+ /// <param name="virtualHost">virtualHost the virtual host name</param>
+ /// <param name="username"> username user name</param>
+ /// <param name="passwor">password password</param>
+ void connect(String host, int port, String virtualHost, String username, String passwor);
+
+ /// <summary>
+ /// Close this client
+ /// </summary>
+ void close();
+
+ /// <summary>
+ /// Create a session for this connection.
+ /// The returned session is suspended
+ /// (i.e. this session is not attached to an underlying channel)
+ /// </summary>
+ /// <param name="expiryInSeconds">Expiry time expressed in seconds, if the value is less than
+ /// or equal to 0 then the session does not expire.</param>
+ /// <returns>A newly created (suspended) session.</returns>
+ ClientSession createSession(long expiryInSeconds);
+
+ /// <summary>
+ /// If the communication layer detects a serious problem with a connection, it
+ // informs the client's ClosedListener
+ /// </summary>
+ ///
+ ClosedListener ClosedListener { set; }
+ }
+}
diff --git a/dotnet/client-010/client/client/ClientSession.cs b/dotnet/client-010/client/client/ClientSession.cs
new file mode 100644
index 0000000000..190fd7c940
--- /dev/null
+++ b/dotnet/client-010/client/client/ClientSession.cs
@@ -0,0 +1,109 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using org.apache.qpid.transport;
+using org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.client
+{
+ /// <summary> Implements a Qpid Sesion.</summary>
+ public class ClientSession : Session, IClientSession
+ {
+ public static short TRANSFER_ACQUIRE_MODE_NO_ACQUIRE = 1;
+ public static short TRANSFER_ACQUIRE_MODE_PRE_ACQUIRE = 0;
+ public static short TRANSFER_CONFIRM_MODE_REQUIRED = 0;
+ public static short TRANSFER_CONFIRM_MODE_NOT_REQUIRED = 1;
+ public static short MESSAGE_FLOW_MODE_CREDIT = 0;
+ public static short MESSAGE_FLOW_MODE_WINDOW = 1;
+ public static short MESSAGE_FLOW_UNIT_MESSAGE = 0;
+ public static short MESSAGE_FLOW_UNIT_BYTE = 1;
+ public static long MESSAGE_FLOW_MAX_BYTES = 0xFFFFFFFF;
+ public static short MESSAGE_REJECT_CODE_GENERIC = 0;
+ public static short MESSAGE_REJECT_CODE_IMMEDIATE_DELIVERY_FAILED = 1;
+ public static short MESSAGE_ACQUIRE_ANY_AVAILABLE_MESSAGE = 0;
+ public static short MESSAGE_ACQUIRE_MESSAGES_IF_ALL_ARE_AVAILABLE = 1;
+
+ private readonly Dictionary<String, IMessageListener> _listeners = new Dictionary<String, IMessageListener>();
+
+ public ClientSession(byte[] name) : base(name)
+ {
+ }
+
+ public void AttachMessageListener(IMessageListener listener, string Destination)
+ {
+ _listeners.Add(Destination, listener);
+ }
+
+ public Dictionary<String, IMessageListener> MessageListeners
+ {
+ get { return _listeners; }
+ }
+
+ public void MessageTransfer(String destination, string routingkey, IMessage message)
+ {
+ message.DeliveryProperties.SetRoutingKey(routingkey);
+ MessageTransfer(destination, message);
+ }
+
+ public void MessageTransfer(String destination, IMessage message)
+ {
+ byte[] body = new byte[message.Body.Position];
+ message.Body.Seek(0, SeekOrigin.Begin);
+ message.Body.Read(body, 0, body.Length);
+ message.MessageProperties.SetMessageId(UUID.RandomUuid());
+ MessageTransfer(destination,
+ MessageAcceptMode.NONE,
+ MessageAcquireMode.PRE_ACQUIRED,
+ message.Header,
+ body);
+ }
+
+ public void QueueDeclare(String queue)
+ {
+ QueueDeclare(queue, null, null);
+ }
+
+ public void QueueDeclare(String queue, params Option[] options)
+ {
+ QueueDeclare(queue, null, null, options);
+ }
+
+ public void ExchangeBind(String queue, String exchange, String bindingKey)
+ {
+ ExchangeBind(queue, exchange, bindingKey, null);
+ }
+
+ public void MessageSubscribe(String queue)
+ {
+ MessageSubscribe(queue, queue, MessageAcceptMode.EXPLICIT, MessageAcquireMode.PRE_ACQUIRED, null, 0, null);
+ // issue credits
+ MessageSetFlowMode(queue, MessageFlowMode.WINDOW);
+ MessageFlow(queue, MessageCreditUnit.BYTE, MESSAGE_FLOW_MAX_BYTES);
+ MessageFlow(queue, MessageCreditUnit.MESSAGE, 10000);
+ }
+
+ }
+}
diff --git a/dotnet/client-010/client/client/ClientSessionDelegate.cs b/dotnet/client-010/client/client/ClientSessionDelegate.cs
new file mode 100644
index 0000000000..7cc4042557
--- /dev/null
+++ b/dotnet/client-010/client/client/ClientSessionDelegate.cs
@@ -0,0 +1,55 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+using org.apache.qpid.transport;
+using org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.client
+{
+ public class ClientSessionDelegate : SessionDelegate
+ {
+ private static readonly Logger _log = Logger.Get(typeof (ClientSessionDelegate));
+
+ // --------------------------------------------
+ // Message methods
+ // --------------------------------------------
+ public override void MessageTransfer(Session session, MessageTransfer xfr)
+ {
+ if (((ClientSession) session).MessageListeners.ContainsKey(xfr.GetDestination()))
+ {
+ IMessageListener listener = ((ClientSession)session).MessageListeners[xfr.GetDestination()];
+ listener.MessageTransfer( new Message(xfr));
+ }
+ else
+ {
+ _log.Warn("No listener set for: {0}", xfr);
+ }
+ }
+
+ public override void MessageReject(Session session, MessageReject mstruct)
+ {
+ foreach (Range range in mstruct.GetTransfers())
+ {
+ for (long l = range.Lower; l <= range.Upper; l++)
+ {
+ _log.Warn("message rejected: " + session.GetCommand((int) l));
+ }
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/client/client/ClosedListenerInterface.cs b/dotnet/client-010/client/client/ClosedListenerInterface.cs
new file mode 100644
index 0000000000..133b00abdd
--- /dev/null
+++ b/dotnet/client-010/client/client/ClosedListenerInterface.cs
@@ -0,0 +1,29 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System;
+
+namespace org.apache.qpid.client
+{
+ public interface ClosedListener
+ {
+
+ void onClosed(ErrorCode errorCode, String reason, Exception t);
+ }
+}
diff --git a/dotnet/client-010/client/client/ErrorCode.cs b/dotnet/client-010/client/client/ErrorCode.cs
new file mode 100644
index 0000000000..74c3daba4b
--- /dev/null
+++ b/dotnet/client-010/client/client/ErrorCode.cs
@@ -0,0 +1,140 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System;
+
+namespace org.apache.qpid.client
+{
+ public enum QpidErrorCode
+ {
+ NO_ERROR = 200,
+ CONTENT_TOO_LARGE = 311,
+ NO_ROUTE = 312,
+ NO_CONSUMERS = 313,
+ CONNECTION_FORCED = 320,
+ INVALID_PATH = 402,
+ ACCESS_REFUSED = 403,
+ NOT_FOUND = 404,
+ RESOURCE_LOCKED = 405,
+ PRE_CONDITION_FAILED = 406,
+ FRAME_ERROR = 501,
+ SYNTAX_ERROR = 502,
+ COMMAND_INVALID = 503,
+ SESSION_ERROR = 504,
+ NOT_ALLOWED = 530,
+ NOT_IMPLEMENTED = 540,
+ INTERNAL_ERROR = 541,
+ INVALID_ARGUMENT = 542,
+ UNDEFINED = 1
+ }
+
+ public struct ErrorCode
+ {
+ private int _code;
+ private String _desc;
+ private readonly bool _hardError;
+
+ public ErrorCode(int code, String desc, bool hardError)
+ {
+ _code = code;
+ _desc = desc;
+ _hardError = hardError;
+ }
+
+ public int Code
+ {
+ get { return _code; }
+ set { _code = value; }
+ }
+
+ public String Description
+ {
+ get { return _desc; }
+ set { _desc = value; }
+ }
+
+ public bool ISHardError
+ {
+ get { return _hardError; }
+ }
+
+ public static ErrorCode GetErrorCode(int code)
+ {
+ switch (code)
+ {
+ case 200:
+ return
+ new ErrorCode(200, "reply-success", true);
+ case 311:
+ return
+ new ErrorCode(311, "content-too-large", false);
+ case 312:
+ return
+ new ErrorCode(312, "no-route", false);
+ case 313:
+ return
+ new ErrorCode(313, "content-consumers", false);
+ case 320:
+ return
+ new ErrorCode(320, "connection-forced", true);
+ case 402:
+ return
+ new ErrorCode(402, "invalid-path", true);
+ case 403:
+ return
+ new ErrorCode(403, "access-refused", false);
+ case 404:
+ return
+ new ErrorCode(404, "not-found", false);
+ case 405:
+ return
+ new ErrorCode(405, "resource-locked", false);
+ case 406:
+ return
+ new ErrorCode(406, "precondition-failed", false);
+ case 501:
+ return
+ new ErrorCode(501, "frame_error", true);
+ case 502:
+ return
+ new ErrorCode(502, "syntax_error", true);
+ case 503:
+ return
+ new ErrorCode(503, "command_invalid", true);
+ case 504:
+ return
+ new ErrorCode(504, "sesion_error", true);
+ case 530:
+ return
+ new ErrorCode(530, "not_allowed", true);
+ case 540:
+ return
+ new ErrorCode(540, "not_implemented", true);
+ case 541:
+ return
+ new ErrorCode(541, "internal_error", true);
+ case 542:
+ return
+ new ErrorCode(542, "invalid_argument", true);
+ default:
+ return new ErrorCode(1, "undefined", true);
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/client/client/IClient.cs b/dotnet/client-010/client/client/IClient.cs
new file mode 100644
index 0000000000..6fe4a4d4b8
--- /dev/null
+++ b/dotnet/client-010/client/client/IClient.cs
@@ -0,0 +1,81 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System;
+using org.apache.qpid.transport;
+
+namespace org.apache.qpid.client
+{
+ public interface IClient
+ {
+ /// <summary>
+ /// Establish a connection with the broker using the given parameters
+ ///
+ /// </summary>
+ /// <param name="host">host name</param>
+ /// <param name="port">port number</param>
+ /// <param name="virtualHost">virtualHost the virtual host name</param>
+ /// <param name="username"> username user name</param>
+ /// <param name="passwor">password password</param>
+ void Connect(String host, int port, String virtualHost, String username, String passwor);
+
+ /// <summary>
+ /// Close this client
+ /// </summary>
+ void Close();
+
+ /// <summary>
+ /// Create a session for this connection.
+ /// The returned session is suspended
+ /// (i.e. this session is not attached to an underlying channel)
+ /// </summary>
+ /// <param name="expiryInSeconds">Expiry time expressed in seconds, if the value is less than
+ /// or equal to 0 then the session does not expire.</param>
+ /// <returns>A newly created (suspended) session.</returns>
+ IClientSession CreateSession(long expiryInSeconds);
+
+
+ event EventHandler<ExceptionArgs> ExceptionRaised;
+ event EventHandler ConnectionLost;
+
+ /// <summary>
+ /// If the broker sends a disconnect message, it will notify the ClosedListener
+ /// </summary>
+ ///
+ IClosedListener ClosedListener { set; }
+
+
+
+ bool IsClosed { get; set; }
+
+ /// <summary>
+ /// Establishes a connection with a broker using SSL
+ ///
+ /// </summary>
+ /// <param name="host">Host name on which a broker is deployed</param>
+ /// <param name="port">Broker port </param>
+ /// <param name="virtualHost">virtual host name</param>
+ /// <param name="username">User Name</param>
+ /// <param name="password">Password</param>
+ /// <param name="serverName">Name of the SSL server</param>
+ /// <param name="certPath">Path to the X509 certificate to be used for client authentication</param>
+ /// <param name="rejectUntrusted">If true connection will not be established if the broker is not trusted</param>
+ void ConnectSSL(String host, int port, String virtualHost, String username, String password, string serverName, string certPath, bool rejectUntrusted);
+ }
+}
diff --git a/dotnet/client-010/client/client/IClientSession.cs b/dotnet/client-010/client/client/IClientSession.cs
new file mode 100644
index 0000000000..b8bc7e4db8
--- /dev/null
+++ b/dotnet/client-010/client/client/IClientSession.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using org.apache.qpid.transport;
+
+namespace org.apache.qpid.client
+{
+ public interface IClientSession : ISession
+ {
+ void AttachMessageListener(IMessageListener listener, string Destination);
+ Dictionary<String, IMessageListener> MessageListeners { get; }
+ void MessageTransfer(String destination, string routingkey, IMessage message);
+ void MessageTransfer(String destination, IMessage message);
+ void QueueDeclare(String queue);
+ void QueueDeclare(String queue, params Option[] options);
+ void ExchangeBind(String queue, String exchange, String bindingKey);
+ void MessageSubscribe(String queue);
+ }
+}
diff --git a/dotnet/client-010/client/client/IClosedListener.cs b/dotnet/client-010/client/client/IClosedListener.cs
new file mode 100644
index 0000000000..0e2472bba6
--- /dev/null
+++ b/dotnet/client-010/client/client/IClosedListener.cs
@@ -0,0 +1,29 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System;
+
+namespace org.apache.qpid.client
+{
+ public interface IClosedListener
+ {
+
+ void OnClosed(ErrorCode errorCode, String reason, Exception t);
+ }
+}
diff --git a/dotnet/client-010/client/client/IMessage.cs b/dotnet/client-010/client/client/IMessage.cs
new file mode 100644
index 0000000000..6eae826a4c
--- /dev/null
+++ b/dotnet/client-010/client/client/IMessage.cs
@@ -0,0 +1,48 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using System.Collections.Generic;
+using System.IO;
+using org.apache.qpid.transport;
+
+namespace org.apache.qpid.client
+{
+ public interface IMessage
+ {
+ int Id { get; }
+
+ Header Header { get; set; }
+
+ MessageProperties MessageProperties { get; set; }
+
+ DeliveryProperties DeliveryProperties { get; set; }
+
+ Dictionary<String, Object> ApplicationHeaders { get; set; }
+
+ void AppendData(byte[] bytes);
+
+ MemoryStream Body { get; }
+
+ string Destination { get; }
+
+ void ClearData();
+ }
+}
diff --git a/dotnet/client-010/client/client/IMessageListener.cs b/dotnet/client-010/client/client/IMessageListener.cs
new file mode 100644
index 0000000000..44ceb3721e
--- /dev/null
+++ b/dotnet/client-010/client/client/IMessageListener.cs
@@ -0,0 +1,31 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+
+namespace org.apache.qpid.client
+{
+ public interface IMessageListener
+ {
+ /// <summary>
+ /// Inform the listener of the message transfer
+ /// </summary>
+ /// <param name="xfr">The message transfer object</param>
+ void MessageTransfer(IMessage xfr);
+ }
+}
diff --git a/dotnet/client-010/client/client/Message.cs b/dotnet/client-010/client/client/Message.cs
new file mode 100644
index 0000000000..6ab62070d2
--- /dev/null
+++ b/dotnet/client-010/client/client/Message.cs
@@ -0,0 +1,131 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System.Collections.Generic;
+using System.IO;
+using org.apache.qpid.transport;
+
+namespace org.apache.qpid.client
+{
+ public class Message : IMessage
+ {
+ private readonly MessageTransfer _message;
+
+ public Message(MessageTransfer m)
+ {
+ _message = m;
+ }
+
+ public Message()
+ {
+ _message = new MessageTransfer();
+ _message.Header = new Header( new MessageProperties(), new DeliveryProperties());
+ ((MessageProperties) _message.Header.Structs[0]).SetApplicationHeaders(new Dictionary<string, object>());
+ }
+
+ public MessageProperties MessageProperties
+ {
+ get
+ {
+ if (_message.Header != null && Header.Structs.Length > 1)
+ return (MessageProperties) Header.Structs[0];
+ return null;
+ }
+ set
+ {
+ if (_message.Header != null)
+ {
+ Header.Structs[0] = value;
+ }
+ }
+ }
+
+ public DeliveryProperties DeliveryProperties
+ {
+ get
+ {
+ if (Header != null)
+ {
+ if( Header.Structs.Length > 1 )
+ return (DeliveryProperties)Header.Structs[1];
+ return (DeliveryProperties)Header.Structs[0];
+ }
+
+ return null;
+ }
+ set
+ {
+ if (Header != null)
+ {
+ Header.Structs[1] = value;
+ }
+ }
+ }
+
+ public Dictionary<string, object> ApplicationHeaders
+ {
+ get
+ {
+ if (Header != null)
+ return ((MessageProperties) Header.Structs[0]).GetApplicationHeaders();
+ return null;
+ }
+ set
+ {
+ if (Header != null)
+ {
+ ((MessageProperties) Header.Structs[0]).SetApplicationHeaders(value);
+ }
+ }
+ }
+
+ public void AppendData(byte[] bytes)
+ {
+ Body.Write(bytes, 0, bytes.Length);
+ }
+
+ public void ClearData()
+ {
+ Body.Seek(0, SeekOrigin.Begin);
+ }
+
+ public Header Header
+ {
+ get{ return _message.Header;}
+ set{ _message.Header = value;}
+ }
+
+ public MemoryStream Body
+ {
+ get { return _message.Body; }
+ set { _message.Body = value; }
+ }
+
+ public int Id
+ {
+ get { return _message.Id; }
+ }
+
+ public string Destination
+ {
+ get{ return _message.GetDestination();}
+ }
+ }
+}
diff --git a/dotnet/client-010/client/default.build b/dotnet/client-010/client/default.build
new file mode 100644
index 0000000000..139796a58d
--- /dev/null
+++ b/dotnet/client-010/client/default.build
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="qpid.client" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="library"
+ define="${build.defines}"
+ debug="${build.debug}"
+ output="${build.dir}/${project::get-name()}.dll">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ <include name="${build.dir}/log4net.dll" />
+ </references>
+ </csc>
+ </target>
+</project>
+
diff --git a/dotnet/client-010/client/transport/Binary.cs b/dotnet/client-010/client/transport/Binary.cs
new file mode 100644
index 0000000000..f9bd3612dc
--- /dev/null
+++ b/dotnet/client-010/client/transport/Binary.cs
@@ -0,0 +1,129 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+namespace org.apache.qpid.transport
+{
+
+
+ /// <summary>
+ /// Binary
+ /// </summary>
+
+ public sealed class Binary
+ {
+
+ private readonly byte[] bytes;
+ private readonly int offset_Renamed_Field;
+ private readonly int size_Renamed_Field;
+ private int hash = 0;
+
+ public Binary(byte[] bytes, int offset, int size)
+ {
+ if (offset + size > bytes.Length)
+ {
+ throw new System.IndexOutOfRangeException();
+ }
+
+ this.bytes = bytes;
+ offset_Renamed_Field = offset;
+ size_Renamed_Field = size;
+ }
+
+ public Binary(byte[] bytes):this(bytes, 0, bytes.Length)
+ {
+ }
+
+ public byte[] Array()
+ {
+ return bytes;
+ }
+
+ public int Offset()
+ {
+ return offset_Renamed_Field;
+ }
+
+ public int Size()
+ {
+ return size_Renamed_Field;
+ }
+
+ public Binary Slice(int low, int high)
+ {
+ int sz;
+
+ if (high < 0)
+ {
+ sz = size_Renamed_Field + high;
+ }
+ else
+ {
+ sz = high - low;
+ }
+
+ if (sz < 0)
+ {
+ sz = 0;
+ }
+
+ return new Binary(bytes, offset_Renamed_Field + low, sz);
+ }
+
+ public override int GetHashCode()
+ {
+ if (hash == 0)
+ {
+ int hc = 0;
+ for (int i = 0; i < size_Renamed_Field; i++)
+ {
+ hc = 31 * hc + (0xFF & bytes[offset_Renamed_Field + i]);
+ }
+ hash = hc;
+ }
+
+ return hash;
+ }
+
+ public override bool Equals(System.Object o)
+ {
+ if (!(o is Binary))
+ {
+ return false;
+ }
+
+ Binary buf = (Binary) o;
+ if (size_Renamed_Field != buf.size_Renamed_Field)
+ {
+ return false;
+ }
+
+ for (int i = 0; i < size_Renamed_Field; i++)
+ {
+ if (bytes[offset_Renamed_Field + i] != buf.bytes[buf.offset_Renamed_Field + i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/Binding.cs b/dotnet/client-010/client/transport/Binding.cs
new file mode 100644
index 0000000000..a0899c1066
--- /dev/null
+++ b/dotnet/client-010/client/transport/Binding.cs
@@ -0,0 +1,34 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// Binding
+ /// </summary>
+ internal interface Binding<E, T>
+ {
+ E endpoint(Sender<T> sender);
+
+ Receiver<R> receiver<R>(E endpoint) where R : EventArgs;
+ }
+} \ No newline at end of file
diff --git a/dotnet/client-010/client/transport/Channel.cs b/dotnet/client-010/client/transport/Channel.cs
new file mode 100644
index 0000000000..48ba707182
--- /dev/null
+++ b/dotnet/client-010/client/transport/Channel.cs
@@ -0,0 +1,174 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using org.apache.qpid.transport.network;
+using org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// Channel
+ /// </summary>
+ public class Channel : Invoker, IProtocolDelegate<Object>
+ {
+ private static readonly Logger log = Logger.Get(typeof (Channel));
+
+ private readonly Connection _connection;
+ private readonly int _channel;
+ private readonly MethodDelegate<Channel> _methoddelegate;
+ private readonly SessionDelegate _sessionDelegate;
+ // session may be null
+ private Session _session;
+
+ public Channel(Connection connection, int channel, SessionDelegate sessionDelegate)
+ {
+ _connection = connection;
+ _channel = channel;
+ _methoddelegate = new ChannelDelegate();
+ _sessionDelegate = sessionDelegate;
+ }
+
+ public Connection Connection
+ {
+ get { return _connection; }
+ }
+
+ // Invoked when a network event is received
+ public void On_ReceivedEvent(object sender, ReceivedPayload<IProtocolEvent> payload)
+ {
+ if (payload.Payload.Channel == _channel)
+ {
+ payload.Payload.ProcessProtocolEvent(null, this);
+ }
+ }
+
+ #region ProtocolDelegate<T>
+
+ public void Init(Object v, ProtocolHeader hdr)
+ {
+ _connection.ConnectionDelegate.Init(this, hdr);
+ }
+
+ public void Control(Object v, Method method)
+ {
+ switch (method.EncodedTrack)
+ {
+ case Frame.L1:
+ method.Dispatch(this, _connection.ConnectionDelegate);
+ break;
+ case Frame.L2:
+ method.Dispatch(this, _methoddelegate);
+ break;
+ case Frame.L3:
+ method.ProcessProtocolEvent(_session, _sessionDelegate);
+ break;
+ default:
+ throw new Exception("unknown track: " + method.EncodedTrack);
+ }
+ }
+
+ public void Command(Object v, Method method)
+ {
+ method.ProcessProtocolEvent(_session, _sessionDelegate);
+ }
+
+ public void Error(Object v, ProtocolError error)
+ {
+ throw new Exception(error.Message);
+ }
+
+ #endregion
+
+ public void Exception(Exception t)
+ {
+ _session.Exception(t);
+ }
+
+ public void ClosedFromConnection()
+ {
+ log.Debug("channel Closed: ", this);
+ if (_session != null)
+ {
+ _session.Closed();
+ }
+ }
+
+ public void Closed()
+ {
+ log.Debug("channel Closed: ", this);
+ if (_session != null)
+ {
+ _session.Closed();
+ }
+ _connection.RemoveChannel(_channel);
+ }
+
+ public int EncodedChannel
+ {
+ get { return _channel; }
+ }
+
+ public Session Session
+ {
+ get { return _session; }
+ set { _session = value; }
+ }
+
+ public void CloseCode(ConnectionClose close)
+ {
+ if (_session != null)
+ {
+ _session.CloseCode(close);
+ }
+ }
+
+ private void Emit(IProtocolEvent pevent)
+ {
+ pevent.Channel = _channel;
+ _connection.Send(pevent);
+ }
+
+ public void Method(Method m)
+ {
+ Emit(m);
+
+ if (!m.Batch)
+ {
+ _connection.Flush();
+ }
+ }
+
+ protected override void Invoke(Method m)
+ {
+ Method(m);
+ }
+
+ public override IFuture Invoke(Method m, IFuture future)
+ {
+ throw new Exception("UnsupportedOperation");
+ }
+
+ public override String ToString()
+ {
+ return String.Format("{0}:{1}", _connection, _channel);
+ }
+ }
+} \ No newline at end of file
diff --git a/dotnet/client-010/client/transport/ChannelDelegate.cs b/dotnet/client-010/client/transport/ChannelDelegate.cs
new file mode 100644
index 0000000000..3a43d6d231
--- /dev/null
+++ b/dotnet/client-010/client/transport/ChannelDelegate.cs
@@ -0,0 +1,41 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// ChannelDelegate
+ ///
+ /// </summary>
+ internal class ChannelDelegate : MethodDelegate<Channel>
+ {
+ public override void SessionDetached(Channel channel, SessionDetached closed)
+ {
+ channel.Closed();
+ }
+
+ public override void SessionDetach(Channel channel, SessionDetach dtc)
+ {
+ channel.Session.Closed();
+ channel.SessionDetached(dtc.GetName(), SessionDetachCode.NORMAL);
+ channel.Closed();
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/ClientDelegate.cs b/dotnet/client-010/client/transport/ClientDelegate.cs
new file mode 100644
index 0000000000..957324ad41
--- /dev/null
+++ b/dotnet/client-010/client/transport/ClientDelegate.cs
@@ -0,0 +1,35 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using org.apache.qpid.transport;
+
+namespace org.apache.qpid.transport
+{
+ abstract class ClientDelegate : ConnectionDelegate
+ {
+ public override void Init(Channel ch, ProtocolHeader hdr)
+ {
+ if (hdr.Major != 0 && hdr.Minor != 10)
+ {
+ throw new ProtocolVersionException((sbyte) hdr.Major, (sbyte) hdr.Minor);
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/Connection.cs b/dotnet/client-010/client/transport/Connection.cs
new file mode 100644
index 0000000000..b97357a96b
--- /dev/null
+++ b/dotnet/client-010/client/transport/Connection.cs
@@ -0,0 +1,168 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using System.Collections.Generic;
+using Logger = org.apache.qpid.transport.util.Logger;
+
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// Connection
+ /// </summary>
+ public class Connection
+ {
+ private static readonly Logger log = Logger.Get(typeof (Connection));
+
+ private readonly ISender<IProtocolEvent> _sender;
+ private readonly ConnectionDelegate _connDdelegate;
+ private int _channelMax = 1;
+ private int _connectionId;
+ private readonly IReceiver<ReceivedPayload<IProtocolEvent>> _receiver;
+
+ private readonly Dictionary<int, Channel> _channels = new Dictionary<int, Channel>();
+
+ public Connection(IReceiver<ReceivedPayload<IProtocolEvent>> receiver, ISender<IProtocolEvent> sender, ConnectionDelegate connDdelegate)
+ {
+ _receiver = receiver;
+ _sender = sender;
+ _connDdelegate = connDdelegate;
+ }
+
+ public int ConnectionId
+ {
+ get { return _connectionId; }
+ set { _connectionId = value; }
+ }
+
+ public ConnectionDelegate ConnectionDelegate
+ {
+ get { return _connDdelegate; }
+ }
+
+ public int ChannelMax
+ {
+ get { return _channelMax; }
+ set { _channelMax = value; }
+ }
+
+ public void Send(IProtocolEvent pevent)
+ {
+ log.Debug("SEND: [{0}] {1}", this, pevent);
+ _sender.Send(pevent);
+ }
+
+ public void Flush()
+ {
+ log.Debug("FLUSH: [{0}]", this);
+ _sender.Flush();
+ }
+
+
+ public Channel GetChannel()
+ {
+ lock (_channels)
+ {
+ for (int i = 0; i < ChannelMax; i++)
+ {
+ if (!_channels.ContainsKey(i))
+ {
+ return GetChannel(i);
+ }
+ }
+ throw new Exception("no more _channels available");
+ }
+ }
+
+ public Channel GetChannel(int number)
+ {
+ lock (_channels)
+ {
+ Channel channel = null;
+ if (_channels.Count > 0)
+ {
+ if( _channels.ContainsKey(number))
+ channel = _channels[number];
+ }
+ if (channel == null)
+ {
+ channel = new Channel(this, number, _connDdelegate.GetSessionDelegate());
+ _receiver.Received += channel.On_ReceivedEvent;
+ _channels.Add(number, channel);
+ }
+ return channel;
+ }
+ }
+
+ public void RemoveChannel(int number)
+ {
+ lock (_channels)
+ {
+ _receiver.Received -= _channels[number].On_ReceivedEvent;
+ _channels.Remove(number);
+ }
+ }
+
+ public void On_ReceivedEvent(object sender, ReceivedPayload<IProtocolEvent> payload)
+ {
+ log.Debug("RECV: [{0}] {1}", this, payload.Payload);
+ if (_channels.ContainsKey(payload.Payload.Channel)) return;
+ Channel channel = GetChannel(payload.Payload.Channel);
+ channel.On_ReceivedEvent(sender, payload);
+ }
+
+ public void On_ReceivedException(Object sender, ExceptionArgs arg)
+ {
+ _connDdelegate.RaiseException(arg.Exception);
+ }
+
+ public void On_ReceivedClosed(Object sender, EventArgs arg)
+ {
+ log.Debug("Connection Closed: {0}", this);
+ lock (_channels)
+ {
+ foreach (Channel ch in _channels.Values)
+ {
+ ch.ClosedFromConnection();
+ }
+ }
+ _channels.Clear();
+ _connDdelegate.Closed();
+ }
+
+
+ public void CloseCode(ConnectionClose close)
+ {
+ lock (_channels)
+ {
+ foreach (Channel ch in _channels.Values)
+ {
+ ch.CloseCode(close);
+ }
+ }
+ }
+
+ public void Close()
+ {
+ _sender.Close();
+ }
+ }
+
+}
diff --git a/dotnet/client-010/client/transport/ConnectionDelegate.cs b/dotnet/client-010/client/transport/ConnectionDelegate.cs
new file mode 100644
index 0000000000..5d491bc06f
--- /dev/null
+++ b/dotnet/client-010/client/transport/ConnectionDelegate.cs
@@ -0,0 +1,108 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using Logger = org.apache.qpid.transport.util.Logger;
+
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// ConnectionDelegate
+ ///
+ /// Currently only implemented client specific methods
+ /// </summary>
+ public abstract class ConnectionDelegate : MethodDelegate<Channel>
+ {
+ private static readonly Logger log = Logger.Get(typeof(ConnectionDelegate));
+ private String _virtualHost;
+
+ protected ManualResetEvent _negotiationComplete;
+
+ public abstract SessionDelegate GetSessionDelegate();
+
+ public abstract void RaiseException(Exception t);
+
+ public abstract void Closed();
+
+ public void SetCondition(ManualResetEvent negotiationComplete)
+ {
+ _negotiationComplete = negotiationComplete;
+ }
+
+ public virtual void Init(Channel ch, ProtocolHeader hdr)
+ {
+ ch.Connection.Send(new ProtocolHeader((byte)1, hdr.Major, hdr.Minor));
+ List<Object> plain = new List<Object>();
+ plain.Add("PLAIN");
+ List<Object> utf8 = new List<Object>();
+ utf8.Add("utf8");
+ ch.ConnectionStart(null, plain, utf8);
+ }
+
+ public String VirtualHost
+ {
+ get { return _virtualHost; }
+ set { _virtualHost = value; }
+ }
+
+ // ----------------------------------------------
+ // Client side
+ //-----------------------------------------------
+ public override void ConnectionStart(Channel context, ConnectionStart mstruct)
+ {
+ Dictionary<String, Object> props = new Dictionary<String, Object>();
+ context.ConnectionStartOk(props, null, null, "utf8");
+ }
+
+ public override void ConnectionSecure(Channel context, ConnectionSecure mstruct)
+ { // todo SASL
+ context.ConnectionSecureOk(new byte[0]);
+ }
+
+ public override void ConnectionTune(Channel context, ConnectionTune mstruct)
+ {
+ context.Connection.ChannelMax = mstruct.GetChannelMax();
+ context.ConnectionTuneOk(mstruct.GetChannelMax(), mstruct.GetMaxFrameSize(), mstruct.GetHeartbeatMax());
+ context.ConnectionOpen(_virtualHost, null, Option.INSIST);
+ }
+
+ public override void ConnectionOpenOk(Channel context, ConnectionOpenOk mstruct)
+ {
+ List<Object> knownHosts = mstruct.GetKnownHosts();
+ if (_negotiationComplete != null)
+ {
+ _negotiationComplete.Set();
+ }
+ }
+
+ public override void ConnectionRedirect(Channel context, ConnectionRedirect mstruct)
+ {
+ // not going to bother at the moment
+ }
+
+ public override void ConnectionClose(Channel ch, ConnectionClose close)
+ {
+ ch.Connection.CloseCode(close);
+ ch.ConnectionCloseOk();
+ }
+ }
+} \ No newline at end of file
diff --git a/dotnet/client-010/client/transport/Field.cs b/dotnet/client-010/client/transport/Field.cs
new file mode 100644
index 0000000000..9af8c4a476
--- /dev/null
+++ b/dotnet/client-010/client/transport/Field.cs
@@ -0,0 +1,74 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using org.apache.qpid.transport.codec;
+
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// Field
+ /// </summary>
+ public abstract class Field<C, T>
+ {
+ private C container;
+ private T type;
+ private String name;
+ private int index;
+
+ protected Field(C container, T type, String name, int index)
+ {
+ this.container = container;
+ this.type = type;
+ this.name = name;
+ this.index = index;
+ }
+
+ public C Container
+ {
+ get { return container; }
+ }
+
+ public T Type
+ {
+ get { return type; }
+ }
+
+ public String Name
+ {
+ get { return name; }
+ }
+
+ public int Index
+ {
+ get { return index; }
+ }
+
+ public abstract bool Has(Object mystruct);
+
+ public abstract void Has(Object mystruct, bool value);
+
+ public abstract T Get(Object mystruct);
+
+ public abstract void Read(IDecoder dec, Object mystruct);
+
+ public abstract void Write(IEncoder enc, Object mystruct);
+ }
+}
diff --git a/dotnet/client-010/client/transport/Future.cs b/dotnet/client-010/client/transport/Future.cs
new file mode 100644
index 0000000000..c0eadfb7ae
--- /dev/null
+++ b/dotnet/client-010/client/transport/Future.cs
@@ -0,0 +1,38 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// Future
+ /// </summary>
+ public interface Future
+ {
+ Struct Result
+ {
+ get; set;
+ }
+
+ Session Session
+ { set;
+ }
+ }
+} \ No newline at end of file
diff --git a/dotnet/client-010/client/transport/Header.cs b/dotnet/client-010/client/transport/Header.cs
new file mode 100644
index 0000000000..742531cfd8
--- /dev/null
+++ b/dotnet/client-010/client/transport/Header.cs
@@ -0,0 +1,83 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// Header
+ /// </summary>
+ public class Header
+ {
+ private readonly Struct[] _mystructs;
+
+ public Header(List<Struct> structs)
+ : this(structs.ToArray())
+ {
+ }
+
+ public Header(params Struct[] structs)
+ {
+ _mystructs = structs;
+ }
+
+ public Struct[] Structs
+ {
+ get { return _mystructs; }
+ }
+
+
+ public Struct Get(Struct klass)
+ {
+ foreach (Struct st in _mystructs)
+ {
+ if (Equals(st.GetType(), klass.GetType()))
+ {
+ return st;
+ }
+ }
+ return null;
+ }
+
+ public override String ToString()
+ {
+ StringBuilder str = new StringBuilder();
+ str.Append(" Header(");
+ bool first = true;
+ foreach (Struct s in _mystructs)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ str.Append(", ");
+ }
+ str.Append(s);
+ }
+ str.Append(")");
+ return str.ToString();
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/IBinding.cs b/dotnet/client-010/client/transport/IBinding.cs
new file mode 100644
index 0000000000..607212f1fe
--- /dev/null
+++ b/dotnet/client-010/client/transport/IBinding.cs
@@ -0,0 +1,34 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// Binding
+ /// </summary>
+ internal interface IBinding<E, T>
+ {
+ E Endpoint(ISender<T> sender);
+
+ IReceiver<R> Receiver<R>(E endpoint) where R : EventArgs;
+ }
+}
diff --git a/dotnet/client-010/client/transport/IFuture.cs b/dotnet/client-010/client/transport/IFuture.cs
new file mode 100644
index 0000000000..054b828d13
--- /dev/null
+++ b/dotnet/client-010/client/transport/IFuture.cs
@@ -0,0 +1,38 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// Future
+ /// </summary>
+ public interface IFuture
+ {
+ Struct Result
+ {
+ get; set;
+ }
+
+ Session Session
+ { set;
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/IProtocolDelegate.cs b/dotnet/client-010/client/transport/IProtocolDelegate.cs
new file mode 100644
index 0000000000..a9875fd290
--- /dev/null
+++ b/dotnet/client-010/client/transport/IProtocolDelegate.cs
@@ -0,0 +1,37 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// ProtocolDelegate
+ /// </summary>
+ public interface IProtocolDelegate<T>
+ {
+ void Init(T context, ProtocolHeader header);
+
+ void Control(T context, Method control);
+
+ void Command(T context, Method command);
+
+ void Error(T context, ProtocolError error);
+ }
+}
diff --git a/dotnet/client-010/client/transport/IProtocolEvent.cs b/dotnet/client-010/client/transport/IProtocolEvent.cs
new file mode 100644
index 0000000000..8f915b204a
--- /dev/null
+++ b/dotnet/client-010/client/transport/IProtocolEvent.cs
@@ -0,0 +1,42 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// IProtocolEvent
+ /// </summary>
+ public interface IProtocolEvent
+ {
+ int Channel
+ {
+ get;
+ set;
+ }
+
+ byte EncodedTrack
+ {
+ set;
+ get;
+ }
+
+ void ProcessProtocolEvent<C>(C context, IProtocolDelegate<C> protocoldelegate);
+ }
+}
diff --git a/dotnet/client-010/client/transport/IReceiver.cs b/dotnet/client-010/client/transport/IReceiver.cs
new file mode 100644
index 0000000000..4c4c9572b9
--- /dev/null
+++ b/dotnet/client-010/client/transport/IReceiver.cs
@@ -0,0 +1,38 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// a receiver will raise an event when:
+ /// - data is received
+ /// - an exception is thrown
+ /// - it is Closed
+ /// </summary>
+ public interface IReceiver <T> where T : EventArgs
+ {
+ event EventHandler<T> Received;
+ event EventHandler<ExceptionArgs> Exception;
+ event EventHandler Closed;
+ }
+}
diff --git a/dotnet/client-010/client/transport/ISender.cs b/dotnet/client-010/client/transport/ISender.cs
new file mode 100644
index 0000000000..d7d1781aec
--- /dev/null
+++ b/dotnet/client-010/client/transport/ISender.cs
@@ -0,0 +1,32 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// Sender
+ /// </summary>
+ public interface ISender<T>
+ {
+ void Send(T msg);
+ void Flush();
+ void Close();
+ }
+}
diff --git a/dotnet/client-010/client/transport/ISession.cs b/dotnet/client-010/client/transport/ISession.cs
new file mode 100644
index 0000000000..257b42b455
--- /dev/null
+++ b/dotnet/client-010/client/transport/ISession.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+
+namespace org.apache.qpid.transport
+{
+ public interface ISession : IInvoker
+ {
+ bool IsClosed { get; set; }
+ string Name { get; }
+ int CommandsIn { get; set; }
+ byte[] GetName();
+ void SetAutoSync(bool value);
+ Dictionary<int, Method> GetOutstandingCommands();
+ int GetCommandsOut();
+ int NextCommandId();
+ void Identify(Method cmd);
+ void Processed(Method command);
+ void Processed(int command);
+ void Processed(int lower, int upper);
+ void Processed(Range range);
+ void FlushProcessed(params Option[] options);
+ void KnownComplete(RangeSet kc);
+ void SyncPoint();
+ void Attach(Channel channel);
+ Method GetCommand(int id);
+ bool Complete(int lower, int upper);
+ void Sync();
+ void Sync(long timeout);
+ void Result(int command, Struct result);
+ void AddException(ExecutionException exc);
+ void CloseCode(ConnectionClose close);
+ List<ExecutionException> GetExceptions();
+
+ void MessageTransfer(String destination,
+ MessageAcceptMode acceptMode,
+ MessageAcquireMode acquireMode,
+ Header header,
+ byte[] body,
+ params Option[] options);
+
+ void MessageTransfer(String destination,
+ MessageAcceptMode acceptMode,
+ MessageAcquireMode acquireMode,
+ Header header,
+ String body,
+ params Option[] options);
+
+ void Close();
+ void Exception(Exception t);
+ void Closed();
+ }
+}
diff --git a/dotnet/client-010/client/transport/Method.cs b/dotnet/client-010/client/transport/Method.cs
new file mode 100644
index 0000000000..8540698822
--- /dev/null
+++ b/dotnet/client-010/client/transport/Method.cs
@@ -0,0 +1,150 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using System.IO;
+using System.Text;
+using Frame = org.apache.qpid.transport.network.Frame;
+
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// Method
+ /// </summary>
+ public abstract class Method : Struct, IProtocolEvent
+ {
+ public new static Method Create(int type)
+ {
+ return (Method) StructFactory.createInstruction(type);
+ }
+
+ // XXX: command subclass?
+ private int id;
+ private int channel;
+ private bool idSet;
+ private bool sync;
+ private bool batch;
+
+ public int Id
+ {
+ get { return id; }
+ set
+ {
+ id = value;
+ idSet = true;
+ }
+ }
+
+
+ public bool Sync
+ {
+ get { return sync; }
+ set { sync = value; }
+ }
+
+ public bool Batch
+ {
+ get { return batch; }
+ set { batch = value; }
+ }
+
+ public abstract bool HasPayload();
+
+ public virtual Header Header
+ {
+ get { return null; }
+ set { throw new Exception(); }
+ }
+
+ public virtual MemoryStream Body
+ {
+ get { return null; }
+ set { throw new Exception(); }
+ }
+
+
+ public abstract void Dispatch<C>(C context, MethodDelegate<C> mdelegate );
+
+ #region IProtocolEvent
+
+ public int Channel
+ {
+ get { return channel; }
+ set { channel = value; }
+ }
+
+ public abstract byte EncodedTrack { get; set; }
+
+ public void ProcessProtocolEvent<C>(C context, IProtocolDelegate<C> protocoldelegate)
+ {
+ if (EncodedTrack == Frame.L4)
+ {
+ protocoldelegate.Command(context, this);
+ }
+ else
+ {
+ protocoldelegate.Control(context, this);
+ }
+ }
+
+ #endregion
+
+ public override String ToString()
+ {
+ StringBuilder str = new StringBuilder();
+
+ str.Append("ch=");
+ str.Append(channel);
+
+ if (EncodedTrack == Frame.L4 && idSet)
+ {
+ str.Append(" id=");
+ str.Append(id);
+ }
+
+ if (sync || batch)
+ {
+ str.Append(" ");
+ str.Append("[");
+ if (Sync)
+ {
+ str.Append("S");
+ }
+ if (Batch)
+ {
+ str.Append("B");
+ }
+ str.Append("]");
+ }
+ str.Append(" ");
+ str.Append(base.ToString());
+ if (Header != null)
+ {
+ str.Append(Header.ToString());
+ }
+ if (Body != null)
+ {
+ str.Append("\n body=");
+ str.Append(Body.ToString());
+ }
+ return str.ToString();
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/ProtocolDelegate.cs b/dotnet/client-010/client/transport/ProtocolDelegate.cs
new file mode 100644
index 0000000000..32dbd116ff
--- /dev/null
+++ b/dotnet/client-010/client/transport/ProtocolDelegate.cs
@@ -0,0 +1,37 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// ProtocolDelegate
+ /// </summary>
+ public interface ProtocolDelegate<T>
+ {
+ void Init(T context, ProtocolHeader header);
+
+ void Control(T context, Method control);
+
+ void Command(T context, Method command);
+
+ void Error(T context, ProtocolError error);
+ }
+} \ No newline at end of file
diff --git a/dotnet/client-010/client/transport/ProtocolError.cs b/dotnet/client-010/client/transport/ProtocolError.cs
new file mode 100644
index 0000000000..2a5bf39565
--- /dev/null
+++ b/dotnet/client-010/client/transport/ProtocolError.cs
@@ -0,0 +1,85 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using org.apache.qpid.transport.network;
+
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// ProtocolError
+ /// </summary>
+ public sealed class ProtocolError : INetworkEvent, IProtocolEvent
+ {
+ private int channel;
+ private byte track;
+ private String format;
+ private Object[] args;
+
+ public ProtocolError(byte track, String format, params Object[] args)
+ {
+ this.track = track;
+ this.format = format;
+ this.args = args;
+ }
+
+ #region INetworkEvent Methods
+
+ public void ProcessNetworkEvent(INetworkDelegate ndelegate)
+ {
+ ndelegate.Error(this);
+ }
+
+ #endregion
+
+ #region IProtocolEvent Methods
+
+ public int Channel
+ {
+ get { return channel; }
+ set { channel = value; }
+ }
+
+ public byte EncodedTrack
+ {
+ get { return track; }
+ set { throw new NotImplementedException(); }
+ }
+
+ public void ProcessProtocolEvent<C>(C context, IProtocolDelegate<C> protocoldelegate)
+ {
+ protocoldelegate.Error(context, this);
+ }
+
+ #endregion
+
+ public String Message
+ {
+ get { return String.Format(format, args); }
+ }
+
+
+ public override String ToString()
+ {
+ return String.Format("protocol error: {0}", Message);
+ }
+
+ }
+}
diff --git a/dotnet/client-010/client/transport/ProtocolEvent.cs b/dotnet/client-010/client/transport/ProtocolEvent.cs
new file mode 100644
index 0000000000..990d5ecc3a
--- /dev/null
+++ b/dotnet/client-010/client/transport/ProtocolEvent.cs
@@ -0,0 +1,42 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// ProtocolEvent
+ /// </summary>
+ public interface ProtocolEvent
+ {
+ int Channel
+ {
+ get;
+ set;
+ }
+
+ byte EncodedTrack
+ {
+ set;
+ get;
+ }
+
+ void ProcessProtocolEvent<C>(C context, ProtocolDelegate<C> protocoldelegate);
+ }
+} \ No newline at end of file
diff --git a/dotnet/client-010/client/transport/ProtocolHeader.cs b/dotnet/client-010/client/transport/ProtocolHeader.cs
new file mode 100644
index 0000000000..4adfee25df
--- /dev/null
+++ b/dotnet/client-010/client/transport/ProtocolHeader.cs
@@ -0,0 +1,124 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using System.IO;
+using System.Text;
+using org.apache.qpid.transport.network;
+using Frame = org.apache.qpid.transport.network.Frame;
+
+namespace org.apache.qpid.transport
+{
+ /// <summary> ProtocolHeader
+ ///
+ /// </summary>
+ public sealed class ProtocolHeader : INetworkEvent, IProtocolEvent
+ {
+ private readonly char[] AMQP = new char[] {'A', 'M', 'Q', 'P'};
+ private const byte CLASS = 1;
+
+ private readonly byte instance;
+ private readonly byte major;
+ private readonly byte minor;
+ private int channel;
+
+ public ProtocolHeader(byte instance, byte major, byte minor)
+ {
+ this.instance = instance;
+ this.major = major;
+ this.minor = minor;
+ }
+
+ public ProtocolHeader(int instance, int major, int minor) : this((byte)instance, (byte)major, (byte)minor)
+ {
+ }
+
+ #region INetworkEvent Methods
+
+ public void ProcessNetworkEvent(INetworkDelegate ndelegate)
+ {
+ ndelegate.Init(this);
+ }
+
+ #endregion
+
+ #region IProtocolEvent Methods
+
+ public int Channel
+ {
+ get
+ {
+ return channel;
+ }
+ set
+ {
+ channel = value;
+ }
+ }
+
+ public byte EncodedTrack
+ {
+ get
+ {
+ return Frame.L1;
+ }
+ set { throw new NotImplementedException(); }
+ }
+
+ public void ProcessProtocolEvent<C>(C context, IProtocolDelegate<C> protocoldelegate)
+ {
+ protocoldelegate.Init(context, this);
+ }
+
+ #endregion
+
+ public byte Instance
+ {
+ get { return instance; }
+ }
+
+ public byte Major
+ {
+ get { return major; }
+ }
+
+ public byte Minor
+ {
+ get { return minor; }
+ }
+
+ public MemoryStream ToMemoryStream()
+ {
+ MemoryStream buf = new MemoryStream(8);
+ BinaryWriter writer = new BinaryWriter(buf);
+ writer.Write(AMQP);
+ writer.Write(CLASS);
+ writer.Write(instance);
+ writer.Write((sbyte) major);
+ writer.Write((sbyte) minor);
+ return buf;
+ }
+
+ public override String ToString()
+ {
+ return String.Format("AMQP.{0:d} {1:d}-{2:d}", instance, major, minor);
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/Range.cs b/dotnet/client-010/client/transport/Range.cs
new file mode 100644
index 0000000000..904b1c1229
--- /dev/null
+++ b/dotnet/client-010/client/transport/Range.cs
@@ -0,0 +1,117 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using System.Collections.Generic;
+using org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.transport
+{
+
+ /// <summary>
+ /// Range
+ /// </summary>
+
+
+ public sealed class Range
+ {
+ private int _lower;
+ private int _upper;
+
+ public Range(int lower, int upper)
+ {
+ _lower = lower;
+ _upper = upper;
+ }
+
+ public int Lower
+ {
+ get { return _lower; }
+ set { _lower = value; }
+ }
+ public int Upper
+ {
+ get { return _upper; }
+ set { _upper = value; }
+ }
+
+ public bool Includes(int value)
+ {
+ return Serial.Le(_lower, value) && Serial.Le(value, _upper);
+ }
+
+ public bool Includes(Range range)
+ {
+ return Includes(range._lower) && Includes(range._upper);
+ }
+
+ public bool Intersects(Range range)
+ {
+ return (Includes(range._lower) || Includes(range._upper) ||
+ range.Includes(_lower) || range.Includes(_upper));
+ }
+
+ public bool Touches(Range range)
+ {
+ return (Intersects(range) ||
+ Includes(range._upper + 1) || Includes(range._lower - 1) ||
+ range.Includes(_upper + 1) || range.Includes(_lower - 1));
+ }
+
+ public Range Span(Range range)
+ {
+ return new Range(Serial.Min(_lower, range._lower), Serial.Max(_upper, range._upper));
+ }
+
+ public List<Range> Subtract(Range range)
+ {
+ List<Range> result = new List<Range>();
+
+ if (Includes(range._lower) && Serial.Le(_lower, range._lower - 1))
+ {
+ result.Add(new Range(_lower, range._lower - 1));
+ }
+
+ if (Includes(range._upper) && Serial.Le(range._upper + 1, _upper))
+ {
+ result.Add(new Range(range._upper + 1, _upper));
+ }
+
+ if (result.Count == 0 && !range.Includes(this))
+ {
+ result.Add(this);
+ }
+
+ return result;
+ }
+
+ public Range Intersect(Range range)
+ {
+ int l = Serial.Max(_lower, range._lower);
+ int r = Serial.Min(_upper, range._upper);
+ return Serial.Gt(l, r) ? null : new Range(l, r);
+ }
+
+ public override String ToString()
+ {
+ return "[" + _lower + ", " + _upper + "]";
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/RangeSet.cs b/dotnet/client-010/client/transport/RangeSet.cs
new file mode 100644
index 0000000000..0a856ee979
--- /dev/null
+++ b/dotnet/client-010/client/transport/RangeSet.cs
@@ -0,0 +1,150 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// RangeSet
+ /// </summary>
+ public sealed class RangeSet : IEnumerable<Range>
+ {
+ private readonly List<Range> _ranges = new List<Range>();
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ public IEnumerator<Range> GetEnumerator()
+ {
+ return _ranges.GetEnumerator();
+ }
+
+
+ public int Size()
+ {
+ return _ranges.Count;
+ }
+
+
+ public Range GetFirst()
+ {
+ return _ranges[0];
+ }
+
+ public bool Includes(Range range)
+ {
+ foreach (Range r in this)
+ {
+ if (r.Includes(range))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public bool Includes(int n)
+ {
+ foreach (Range r in this)
+ {
+ if (r.Includes(n))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public void Add(Range range)
+ {
+ for (int i = 0; i < _ranges.Count; i++)
+ {
+ Range r = _ranges[i];
+ if (range.Touches(r))
+ {
+ _ranges.Remove(r);
+ range = range.Span(r);
+ }
+ else if (Serial.Lt(range.Upper, r.Lower))
+ {
+ _ranges.Insert(i - 1 , range);
+ return;
+ }
+ }
+ _ranges.Add(range);
+ }
+
+ public void Add(int lower, int upper)
+ {
+ Add(new Range(lower, upper));
+ }
+
+ public void Add(int value)
+ {
+ Add(value, value);
+ }
+
+ public void Clear()
+ {
+ _ranges.Clear();
+ }
+
+ public RangeSet Copy()
+ {
+ RangeSet copy = new RangeSet();
+ foreach (Range r in _ranges)
+ {
+ copy._ranges.Add(r);
+ }
+ return copy;
+ }
+
+ public override String ToString()
+ {
+ StringBuilder str = new StringBuilder();
+ str.Append("{");
+ bool first = true;
+ foreach (Range range in _ranges)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ str.Append(", ");
+ }
+ str.Append(range);
+ }
+ str.Append("}");
+ return str.ToString();
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/ReceivedPayload.cs b/dotnet/client-010/client/transport/ReceivedPayload.cs
new file mode 100644
index 0000000000..e072ba7493
--- /dev/null
+++ b/dotnet/client-010/client/transport/ReceivedPayload.cs
@@ -0,0 +1,43 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+
+namespace org.apache.qpid.transport
+{
+ public class ReceivedPayload<T> : EventArgs
+ {
+ public ReceivedPayload()
+ {
+ }
+
+ public ReceivedPayload(T payload)
+ {
+ m_payload = payload;
+ }
+ private T m_payload;
+
+ public T Payload
+ {
+ get { return m_payload; }
+ set { m_payload = value; }
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/Receiver.cs b/dotnet/client-010/client/transport/Receiver.cs
new file mode 100644
index 0000000000..f8d91c3f10
--- /dev/null
+++ b/dotnet/client-010/client/transport/Receiver.cs
@@ -0,0 +1,38 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// a receiver will raise an event when:
+ /// - data is received
+ /// - an exception is thrown
+ /// - it is closed
+ /// </summary>
+ public interface Receiver <T> where T : EventArgs
+ {
+ event EventHandler<T> Received;
+ event EventHandler<ExceptionArgs> Exception;
+ event EventHandler Closed;
+ }
+} \ No newline at end of file
diff --git a/dotnet/client-010/client/transport/Sender.cs b/dotnet/client-010/client/transport/Sender.cs
new file mode 100644
index 0000000000..f8b5bdef06
--- /dev/null
+++ b/dotnet/client-010/client/transport/Sender.cs
@@ -0,0 +1,32 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// Sender
+ /// </summary>
+ public interface Sender<T>
+ {
+ void send(T msg);
+ void flush();
+ void close();
+ }
+} \ No newline at end of file
diff --git a/dotnet/client-010/client/transport/Session.cs b/dotnet/client-010/client/transport/Session.cs
new file mode 100644
index 0000000000..7b4aff9811
--- /dev/null
+++ b/dotnet/client-010/client/transport/Session.cs
@@ -0,0 +1,522 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Threading;
+using org.apache.qpid.transport.util;
+using Frame = org.apache.qpid.transport.network.Frame;
+using Logger = org.apache.qpid.transport.util.Logger;
+
+
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// Session
+ ///
+ /// </summary>
+ public class Session : Invoker, ISession
+ {
+ private static readonly Logger log = Logger.Get(typeof (Session));
+ private static readonly bool ENABLE_REPLAY;
+
+ static Session()
+ {
+ const string enableReplay = "enable_command_replay";
+ try
+ {
+ String var = Environment.GetEnvironmentVariable(enableReplay);
+ if (var != null)
+ {
+ ENABLE_REPLAY = bool.Parse(var);
+ }
+ }
+ catch (Exception)
+ {
+ ENABLE_REPLAY = false;
+ }
+ }
+
+ private readonly byte[] _name;
+ private const long _timeout = 600000;
+ private bool _autoSync = false;
+
+ // channel may be null
+ private Channel _channel;
+
+ // incoming command count
+ private int _commandsIn = 0;
+ // completed incoming commands
+ private readonly Object _processedLock = new Object();
+ private RangeSet _processed = new RangeSet();
+ private int _maxProcessed = - 1;
+ private int _syncPoint = -1;
+
+ // outgoing command count
+ private int _commandsOut = 0;
+ private readonly Dictionary<int, Method> _commands = new Dictionary<int, Method>();
+ private int _maxComplete = - 1;
+ private bool _needSync = false;
+ private bool _closed;
+ private readonly Dictionary<int, IFuture> _results = new Dictionary<int, IFuture>();
+ private readonly List<ExecutionException> _exceptions = new List<ExecutionException>();
+
+
+ public bool IsClosed
+ {
+ get
+ {
+ lock (this)
+ {
+ return _closed;
+ }
+ }
+ set
+ {
+ lock (this)
+ {
+ _closed = value;
+ }
+ }
+ }
+
+ public string Name
+ {
+ get
+ {
+ ASCIIEncoding enc = new ASCIIEncoding();
+ return enc.GetString(_name);
+ }
+ }
+
+ public Session(byte[] name)
+ {
+ _name = name;
+ }
+
+ public byte[] GetName()
+ {
+ return _name;
+ }
+
+ public void SetAutoSync(bool value)
+ {
+ lock (_commands)
+ {
+ _autoSync = value;
+ }
+ }
+
+ public Dictionary<int, Method> GetOutstandingCommands()
+ {
+ return _commands;
+ }
+
+ public int GetCommandsOut()
+ {
+ return _commandsOut;
+ }
+
+ public int CommandsIn
+ {
+ get { return _commandsIn; }
+ set { _commandsIn = value; }
+ }
+
+ public int NextCommandId()
+ {
+ return _commandsIn++;
+ }
+
+ public void Identify(Method cmd)
+ {
+ int id = NextCommandId();
+ cmd.Id = id;
+
+ if (log.IsDebugEnabled())
+ {
+ log.Debug("ID: [{0}] %{1}", _channel, id);
+ }
+
+ //if ((id % 65536) == 0)
+ if ((id & 0xff) == 0)
+ {
+ FlushProcessed(Option.TIMELY_REPLY);
+ }
+ }
+
+ public void Processed(Method command)
+ {
+ Processed(command.Id);
+ }
+
+ public void Processed(int command)
+ {
+ Processed(new Range(command, command));
+ }
+
+ public void Processed(int lower, int upper)
+ {
+ Processed(new Range(lower, upper));
+ }
+
+ public void Processed(Range range)
+ {
+ log.Debug("{0} processed({1})", this, range);
+
+ bool flush;
+ lock (_processedLock)
+ {
+ _processed.Add(range);
+ Range first = _processed.GetFirst();
+ int lower = first.Lower;
+ int upper = first.Upper;
+ int old = _maxProcessed;
+ if (Serial.Le(lower, _maxProcessed + 1))
+ {
+ _maxProcessed = Serial.Max(_maxProcessed, upper);
+ }
+ flush = Serial.Lt(old, _syncPoint) && Serial.Ge(_maxProcessed, _syncPoint);
+ _syncPoint = _maxProcessed;
+ }
+ if (flush)
+ {
+ FlushProcessed();
+ }
+ }
+
+ public void FlushProcessed(params Option[] options)
+ {
+ RangeSet copy;
+ lock (_processedLock)
+ {
+ copy = _processed.Copy();
+ }
+ SessionCompleted(copy, options);
+ }
+
+ public void KnownComplete(RangeSet kc)
+ {
+ lock (_processedLock)
+ {
+ RangeSet newProcessed = new RangeSet();
+ foreach (Range pr in _processed)
+ {
+ foreach (Range kr in kc)
+ {
+ foreach (Range r in pr.Subtract(kr))
+ {
+ newProcessed.Add(r);
+ }
+ }
+ }
+ _processed = newProcessed;
+ }
+ }
+
+ public void SyncPoint()
+ {
+ int id = CommandsIn - 1;
+ log.Debug("{0} synced to {1}", this, id);
+ bool flush;
+ lock (_processedLock)
+ {
+ _syncPoint = id;
+ flush = Serial.Ge(_maxProcessed, _syncPoint);
+ }
+ if (flush)
+ {
+ FlushProcessed();
+ }
+ }
+
+ public void Attach(Channel channel)
+ {
+ _channel = channel;
+ _channel.Session = this;
+ }
+
+ public Method GetCommand(int id)
+ {
+ lock (_commands)
+ {
+ return _commands[id];
+ }
+ }
+
+ public bool Complete(int lower, int upper)
+ {
+ //avoid autoboxing
+ if (log.IsDebugEnabled())
+ {
+ log.Debug("{0} complete({1}, {2})", this, lower, upper);
+ }
+ lock (_commands)
+ {
+ int old = _maxComplete;
+ for (int id = Serial.Max(_maxComplete, lower); Serial.Le(id, upper); id++)
+ {
+ _commands.Remove(id);
+ }
+ if (Serial.Le(lower, _maxComplete + 1))
+ {
+ _maxComplete = Serial.Max(_maxComplete, upper);
+ }
+ log.Debug("{0} commands remaining: {1}", this, _commands);
+ Monitor.PulseAll(_commands);
+ return Serial.Gt(_maxComplete, old);
+ }
+ }
+
+ protected override void Invoke(Method m)
+ {
+ if (IsClosed)
+ {
+ List<ExecutionException> exc = GetExceptions();
+ if (exc.Count > 0)
+ {
+ throw new SessionException(exc);
+ }
+ else if (_close != null)
+ {
+ throw new ConnectionException(_close);
+ }
+ else
+ {
+ throw new SessionClosedException();
+ }
+ }
+
+ if (m.EncodedTrack == Frame.L4)
+ {
+ lock (_commands)
+ {
+ int next = _commandsOut++;
+ m.Id = next;
+ if (next == 0)
+ {
+ SessionCommandPoint(0, 0);
+ }
+ if (ENABLE_REPLAY)
+ {
+ _commands.Add(next, m);
+ }
+ if (_autoSync)
+ {
+ m.Sync = true;
+ }
+ _needSync = ! m.Sync;
+ _channel.Method(m);
+ if (_autoSync)
+ {
+ Sync();
+ }
+
+ // flush every 64K commands to avoid ambiguity on
+ // wraparound
+ if ((next%65536) == 0)
+ {
+ SessionFlush(Option.COMPLETED);
+ }
+ }
+ }
+ else
+ {
+ _channel.Method(m);
+ }
+ }
+
+ public void Sync()
+ {
+ Sync(_timeout);
+ }
+
+ public void Sync(long timeout)
+ {
+ log.Debug("{0} sync()", this);
+ lock (_commands)
+ {
+ int point = _commandsOut - 1;
+
+ if (_needSync && Serial.Lt(_maxComplete, point))
+ {
+ ExecutionSync(Option.SYNC);
+ }
+
+ DateTime start = DateTime.Now;
+ long elapsed = 0;
+
+ while (!IsClosed && elapsed < timeout && Serial.Lt(_maxComplete, point))
+ {
+ log.Debug("{0} waiting for[{1}]: {2}, {3}", this, point,
+ _maxComplete, _commands);
+ Monitor.Wait(_commands, (int) (timeout - elapsed));
+ elapsed = DateTime.Now.Subtract(start).Milliseconds;
+ }
+
+ if (Serial.Lt(_maxComplete, point))
+ {
+ if (IsClosed)
+ {
+ throw new SessionException(GetExceptions());
+ }
+ else
+ {
+ throw new Exception
+ (String.Format
+ ("timed out waiting for sync: complete = {0}, point = {1}", _maxComplete, point));
+ }
+ }
+ }
+ }
+
+
+ public void Result(int command, Struct result)
+ {
+ IFuture future;
+ lock (_results)
+ {
+ if (_results.ContainsKey(command))
+ {
+ future = _results[command];
+ _results.Remove(command);
+ }
+ else
+ {
+ throw new Exception(String.Format("Cannot ger result {0} for {1}", command, result));
+ }
+ }
+ future.Result = result;
+ }
+
+ public void AddException(ExecutionException exc)
+ {
+ lock (_exceptions)
+ {
+ _exceptions.Add(exc);
+ }
+ }
+
+ private ConnectionClose _close = null;
+
+ public void CloseCode(ConnectionClose close)
+ {
+ _close = close;
+ }
+
+ public List<ExecutionException> GetExceptions()
+ {
+ lock (_exceptions)
+ {
+ return new List<ExecutionException>(_exceptions);
+ }
+ }
+
+ public override IFuture Invoke(Method m, IFuture future)
+ {
+ lock (_commands)
+ {
+ future.Session = this;
+ int command = _commandsOut;
+ lock (_results)
+ {
+ _results.Add(command, future);
+ }
+ Invoke(m);
+ }
+ return future;
+ }
+
+
+ public void MessageTransfer(String destination,
+ MessageAcceptMode acceptMode,
+ MessageAcquireMode acquireMode,
+ Header header,
+ byte[] body,
+ params Option[] options)
+ {
+ MemoryStream mbody = new MemoryStream();
+ mbody.Write(body,0, body.Length);
+ MessageTransfer(destination, acceptMode, acquireMode, header,
+ mbody, options);
+ }
+
+ public void MessageTransfer(String destination,
+ MessageAcceptMode acceptMode,
+ MessageAcquireMode acquireMode,
+ Header header,
+ String body,
+ params Option[] options)
+ {
+ MessageTransfer(destination, acceptMode, acquireMode, header,
+ new MemoryStream(Convert.ToByte(body)), options);
+ }
+
+ public void Close()
+ {
+ SessionRequestTimeout(0);
+ SessionDetach(_name);
+ lock (_commands)
+ {
+ DateTime start = DateTime.Now;
+ long elapsed = 0;
+
+ while (!IsClosed && elapsed < _timeout)
+ {
+ Monitor.Wait(_commands, (int) (_timeout - elapsed));
+ elapsed = DateTime.Now.Subtract(start).Milliseconds;
+ }
+ }
+ }
+
+ public void Exception(Exception t)
+ {
+ log.Error(t, "Caught exception");
+ }
+
+ public void Closed()
+ {
+ IsClosed = true;
+ lock (_commands)
+ {
+ Monitor.PulseAll(_commands);
+ }
+ lock (_results)
+ {
+ foreach (IFuture result in _results.Values)
+ {
+ lock (result)
+ {
+ Monitor.PulseAll(result);
+ }
+ }
+ }
+ _channel.Session = null;
+ _channel = null;
+ }
+
+ public override String ToString()
+ {
+ return String.Format("session:{0}", _name);
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/SessionDelegate.cs b/dotnet/client-010/client/transport/SessionDelegate.cs
new file mode 100644
index 0000000000..973e22df16
--- /dev/null
+++ b/dotnet/client-010/client/transport/SessionDelegate.cs
@@ -0,0 +1,126 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// SessionDelegate
+ ///
+ /// </summary>
+ public abstract class SessionDelegate : MethodDelegate<Session>, IProtocolDelegate<Session>
+ {
+ public void Init(Session ssn, ProtocolHeader hdr)
+ {
+ }
+
+ public void Control(Session ssn, Method method)
+ {
+ method.Dispatch(ssn, this);
+ }
+
+ public void Command(Session ssn, Method method)
+ {
+ ssn.Identify(method);
+ method.Dispatch(ssn, this);
+ if (!method.HasPayload())
+ {
+ ssn.Processed(method);
+ }
+ }
+
+ public void Error(Session ssn, ProtocolError error)
+ {
+ }
+
+ public override void ExecutionResult(Session ssn, ExecutionResult result)
+ {
+ ssn.Result(result.GetCommandId(), result.GetValue());
+ }
+
+ public override void ExecutionException(Session ssn, ExecutionException exc)
+ {
+ ssn.AddException(exc);
+ }
+
+ public override void SessionCompleted(Session ssn, SessionCompleted cmp)
+ {
+ RangeSet ranges = cmp.GetCommands();
+ RangeSet known = null;
+ if (cmp.GetTimelyReply())
+ {
+ known = new RangeSet();
+ }
+
+ if (ranges != null)
+ {
+ foreach (Range range in ranges)
+ {
+ bool advanced = ssn.Complete(range.Lower, range.Upper);
+ if (advanced && known != null)
+ {
+ known.Add(range);
+ }
+ }
+ }
+
+ if (known != null)
+ {
+ ssn.SessionKnownCompleted(known);
+ }
+ }
+
+ public override void SessionKnownCompleted(Session ssn, SessionKnownCompleted kcmp)
+ {
+ RangeSet kc = kcmp.GetCommands();
+ if (kc != null)
+ {
+ ssn.KnownComplete(kc);
+ }
+ }
+
+ public override void SessionFlush(Session ssn, SessionFlush flush)
+ {
+ if (flush.GetCompleted())
+ {
+ ssn.FlushProcessed();
+ }
+ if (flush.GetConfirmed())
+ {
+ ssn.FlushProcessed();
+ }
+ if (flush.GetExpected())
+ {
+ // to be done
+ //throw new Exception("not implemented");
+ }
+ }
+
+ public override void SessionCommandPoint(Session ssn, SessionCommandPoint scp)
+ {
+ ssn.CommandsIn = scp.GetCommandId();
+ }
+
+ public override void ExecutionSync(Session ssn, ExecutionSync sync)
+ {
+ ssn.SyncPoint();
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/Struct.cs b/dotnet/client-010/client/transport/Struct.cs
new file mode 100644
index 0000000000..ff8d80fcb1
--- /dev/null
+++ b/dotnet/client-010/client/transport/Struct.cs
@@ -0,0 +1,121 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.qpid.transport.codec;
+
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// Struct
+ /// </summary>
+
+ public abstract class Struct : IEncodable
+ {
+ public static Struct Create(int type)
+ {
+ return StructFactory.create(type);
+ }
+
+ bool dirty = true;
+
+ public bool Dirty
+ {
+ get { return dirty; }
+ set { dirty = value; }
+ }
+
+ public abstract int GetStructType();
+
+ public abstract int GetSizeWidth();
+
+ public abstract int GetPackWidth();
+
+ public int GetEncodedType()
+ {
+ int type = GetStructType();
+ if (type < 0)
+ {
+ throw new Exception();
+ }
+ return type;
+ }
+
+ private bool IsBit<C, T>(Field<C, T> f)
+ {
+ return Equals(f.Type, typeof(Boolean));
+ }
+
+ private bool Packed()
+ {
+ return GetPackWidth() > 0;
+ }
+
+ private bool Encoded<C, T>(Field<C, T> f)
+ {
+ return !Packed() || !IsBit(f) && f.Has(this);
+ }
+
+ private int GetFlagWidth()
+ {
+ return (Fields.Count + 7) / 8;
+ }
+
+ private int GetFlagCount()
+ {
+ return 8 * GetPackWidth();
+ }
+
+ public abstract void Read(IDecoder dec);
+
+ public abstract void Write(IEncoder enc);
+
+ public abstract Dictionary<String, Object> Fields
+ {
+ get;
+ }
+
+ public override String ToString()
+ {
+ StringBuilder str = new StringBuilder();
+ str.Append(GetType());
+ str.Append("(");
+ bool first = true;
+ foreach (KeyValuePair<String, Object> me in Fields)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ str.Append(", ");
+ }
+ str.Append(me.Key);
+ str.Append("=");
+ str.Append(me.Value);
+ }
+ str.Append(")");
+ return str.ToString();
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/codec/AbstractDecoder.cs b/dotnet/client-010/client/transport/codec/AbstractDecoder.cs
new file mode 100644
index 0000000000..2e9e587407
--- /dev/null
+++ b/dotnet/client-010/client/transport/codec/AbstractDecoder.cs
@@ -0,0 +1,399 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+using org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.transport.codec
+{
+ /// <summary>
+ /// AbstractDecoder
+ /// </summary>
+ public abstract class AbstractDecoder : IDecoder
+ {
+ private readonly Dictionary<Binary, String> str8cache = new Dictionary<Binary, String>();
+
+ protected abstract byte DoGet();
+
+ protected abstract void DoGet(byte[] bytes);
+ public abstract bool HasRemaining();
+
+ protected byte Get()
+ {
+ return DoGet();
+ }
+
+ protected void Get(byte[] bytes)
+ {
+ DoGet(bytes);
+ }
+
+ protected Binary Get(int size)
+ {
+ byte[] bytes = new byte[size];
+ Get(bytes);
+ return new Binary(bytes);
+ }
+
+ protected short Uget()
+ {
+ return (short) (0xFF & Get());
+ }
+
+ public virtual short ReadUint8()
+ {
+ return Uget();
+ }
+
+ public abstract int ReadUint16();
+
+
+ public abstract long ReadUint32();
+
+
+ public int ReadSequenceNo()
+ {
+ return (int) ReadUint32();
+ }
+
+ public virtual long ReadUint64()
+ {
+ long l = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ l |= ((long) (0xFF & Get())) << (56 - i*8);
+ }
+ return l;
+ }
+
+ public abstract short ReadInt8();
+ public abstract int ReadInt16();
+ public abstract long ReadInt32() ;
+ public abstract long ReadInt64();
+ public abstract float ReadFloat() ;
+ public abstract double ReadDouble() ;
+
+ public long ReadDatetime()
+ {
+ return ReadUint64();
+ }
+
+ private static String Decode(byte[] bytes, int offset, int length, Encoding encoding)
+ {
+ return encoding.GetString(bytes, offset, length);
+ }
+
+ private static String Decode(byte[] bytes, Encoding encoding)
+ {
+ return Decode(bytes, 0, bytes.Length, encoding);
+ }
+
+ public String ReadStr8()
+ {
+ short size = ReadUint8();
+ Binary bin = Get(size);
+ String str;
+ if (! str8cache.TryGetValue(bin, out str))
+ {
+ str = Decode(bin.Array(), bin.Offset(), bin.Size(), Encoding.UTF8);
+ str8cache.Add(bin, str);
+ }
+ return str;
+ }
+
+ public String ReadStr16()
+ {
+ int size = ReadUint16();
+ byte[] bytes = new byte[size];
+ Get(bytes);
+ return Decode(bytes, Encoding.UTF8);
+ }
+
+ public byte[] ReadVbin8()
+ {
+ int size = ReadUint8();
+ byte[] bytes = new byte[size];
+ Get(bytes);
+ return bytes;
+ }
+
+ public byte[] ReadVbin16()
+ {
+ int size = ReadUint16();
+ byte[] bytes = new byte[size];
+ Get(bytes);
+ return bytes;
+ }
+
+ public byte[] ReadVbin32()
+ {
+ int size = (int) ReadUint32();
+ byte[] bytes = new byte[size];
+ Get(bytes);
+ return bytes;
+ }
+
+ public RangeSet ReadSequenceSet()
+ {
+ int count = ReadUint16()/8;
+ if (count == 0)
+ {
+ return null;
+ }
+ RangeSet ranges = new RangeSet();
+ for (int i = 0; i < count; i++)
+ {
+ ranges.Add(ReadSequenceNo(), ReadSequenceNo());
+ }
+ return ranges;
+ }
+
+ public RangeSet ReadByteRanges()
+ {
+ throw new Exception("not implemented");
+ }
+
+ public UUID ReadUuid()
+ {
+ long msb = ReadUint64();
+ long lsb = ReadUint64();
+ return new UUID(msb, lsb);
+ }
+
+ public String ReadContent()
+ {
+ throw new Exception("Deprecated");
+ }
+
+ public Struct ReadStruct(int type)
+ {
+ Struct st = Struct.Create(type);
+ int width = st.GetSizeWidth();
+ if (width > 0)
+ {
+ long size = ReadSize(width);
+ if (size == 0)
+ {
+ return null;
+ }
+ }
+ if (type > 0)
+ {
+ int code = ReadUint16();
+ Debug.Assert(code == type);
+ }
+ st.Read(this);
+ return st;
+ }
+
+ public Struct ReadStruct32()
+ {
+ long size = ReadUint32();
+ if (size == 0)
+ {
+ return null;
+ }
+ int type = ReadUint16();
+ Struct result = Struct.Create(type);
+ result.Read(this);
+ return result;
+ }
+
+ public Dictionary<String, Object> ReadMap()
+ {
+ long size = ReadUint32();
+
+ if (size == 0)
+ {
+ return null;
+ }
+
+ long count = ReadUint32();
+
+ Dictionary<String, Object> result = new Dictionary<String, Object>();
+ for (int i = 0; i < count; i++)
+ {
+ String key = ReadStr8();
+ byte code = Get();
+ QpidType t = GetType(code);
+ Object value = Read(t);
+ result.Add(key, value);
+ }
+
+ return result;
+ }
+
+ public List<Object> ReadList()
+ {
+ long size = ReadUint32();
+
+ if (size == 0)
+ {
+ return null;
+ }
+
+ long count = ReadUint32();
+
+ List<Object> result = new List<Object>();
+ for (int i = 0; i < count; i++)
+ {
+ byte code = Get();
+ QpidType t = GetType(code);
+ Object value = Read(t);
+ result.Add(value);
+ }
+ return result;
+ }
+
+ public List<Object> ReadArray()
+ {
+ long size = ReadUint32();
+
+ if (size == 0)
+ {
+ return null;
+ }
+
+ byte code = Get();
+ QpidType t = GetType(code);
+ long count = ReadUint32();
+
+ List<Object> result = new List<Object>();
+ for (int i = 0; i < count; i++)
+ {
+ Object value = Read(t);
+ result.Add(value);
+ }
+ return result;
+ }
+
+ private QpidType GetType(byte code)
+ {
+ return QpidType.get(code);
+ }
+
+ private long ReadSize(QpidType t)
+ {
+ return t.Fixed ? t.Width : ReadSize(t.Width);
+ }
+
+ private long ReadSize(int width)
+ {
+ switch (width)
+ {
+ case 1:
+ return ReadUint8();
+ case 2:
+ return ReadUint16();
+ case 4:
+ return ReadUint32();
+ default:
+ throw new Exception("illegal width: " + width);
+ }
+ }
+
+ private byte[] ReadBytes(QpidType t)
+ {
+ long size = ReadSize(t);
+ byte[] result = new byte[(int) size];
+ Get(result);
+ return result;
+ }
+
+ private Object Read(QpidType t)
+ {
+ switch (t.Code)
+ {
+ case Code.BIN8:
+ case Code.UINT8:
+ return ReadUint8();
+ case Code.INT8:
+ return Get();
+ case Code.CHAR:
+ return (char) Get();
+ case Code.BOOLEAN:
+ return Get() > 0;
+
+ case Code.BIN16:
+ case Code.UINT16:
+ return ReadUint16();
+ case Code.INT16:
+ return (short) ReadUint16();
+
+ case Code.BIN32:
+ case Code.UINT32:
+ return ReadUint32();
+
+ case Code.CHAR_UTF32:
+ case Code.INT32:
+ return (int) ReadUint32();
+
+ case Code.FLOAT:
+ return (float)BitConverter.Int64BitsToDouble(ReadUint32() << 32);
+
+ case Code.BIN64:
+ case Code.UINT64:
+ case Code.INT64:
+ case Code.DATETIME:
+ return ReadUint64();
+
+ case Code.DOUBLE:
+ return BitConverter.Int64BitsToDouble(ReadUint64());
+ case Code.UUID:
+ return ReadUuid();
+ case Code.STR8:
+ return ReadStr8();
+ case Code.STR16:
+ return ReadStr16();
+ case Code.STR8_LATIN:
+ case Code.STR8_UTF16:
+ case Code.STR16_LATIN:
+ case Code.STR16_UTF16:
+ // XXX: need to do character conversion
+ return Encoding.UTF8.GetString(ReadBytes(t));
+
+ case Code.MAP:
+ return ReadMap();
+ case Code.LIST:
+ return ReadList();
+ case Code.ARRAY:
+ return ReadArray();
+ case Code.STRUCT32:
+ return ReadStruct32();
+
+ case Code.BIN40:
+ case Code.DEC32:
+ case Code.BIN72:
+ case Code.DEC64:
+ // XXX: what types are we supposed to use here?
+ return ReadBytes(t);
+
+ case Code.VOID:
+ return null;
+
+ default:
+ return ReadBytes(t);
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/codec/AbstractEncoder.cs b/dotnet/client-010/client/transport/codec/AbstractEncoder.cs
new file mode 100644
index 0000000000..eb8bdae80a
--- /dev/null
+++ b/dotnet/client-010/client/transport/codec/AbstractEncoder.cs
@@ -0,0 +1,590 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.transport.codec
+{
+ /// <summary>
+ /// AbstractEncoder
+ /// </summary>
+ public abstract class AbstractEncoder : IEncoder
+ {
+ private static readonly Dictionary<Type, Code> ENCODINGS = new Dictionary<Type, Code>();
+ private readonly Dictionary<String, byte[]> str8cache = new Dictionary<String, byte[]>();
+
+ static AbstractEncoder()
+ {
+ ENCODINGS.Add(typeof (Boolean), Code.BOOLEAN);
+ ENCODINGS.Add(typeof (String), Code.STR16);
+ ENCODINGS.Add(typeof (long), Code.INT64);
+ ENCODINGS.Add(typeof (int), Code.INT32);
+ ENCODINGS.Add(typeof (short), Code.INT16);
+ ENCODINGS.Add(typeof (Byte), Code.INT8);
+ ENCODINGS.Add(typeof (Dictionary<String, Object>), Code.MAP);
+ ENCODINGS.Add(typeof (List<Object>), Code.LIST);
+ ENCODINGS.Add(typeof (float), Code.FLOAT);
+ ENCODINGS.Add(typeof (Double), Code.DOUBLE);
+ ENCODINGS.Add(typeof (char), Code.CHAR);
+ ENCODINGS.Add(typeof (byte[]), Code.VBIN32);
+ ENCODINGS.Add(typeof (UUID), Code.UUID);
+ }
+
+ protected abstract void DoPut(byte b);
+
+ protected abstract void DoPut(MemoryStream src);
+
+
+ protected void Put(byte b)
+ {
+ DoPut(b);
+ }
+
+ protected void Put(MemoryStream src)
+ {
+ DoPut(src);
+ }
+
+ protected virtual void Put(byte[] bytes)
+ {
+ Put(new MemoryStream(bytes));
+ }
+
+ protected abstract int BeginSize8();
+ protected abstract void EndSize8(int pos);
+
+ protected abstract int BeginSize16();
+ protected abstract void EndSize16(int pos);
+
+ protected abstract int BeginSize32();
+ protected abstract void EndSize32(int pos);
+
+ public virtual void WriteUint8(short b)
+ {
+ Debug.Assert(b < 0x100);
+ Put((byte) b);
+ }
+
+ public virtual void WriteUint16(int s)
+ {
+ Debug.Assert(s < 0x10000);
+ Put((byte) Functions.Lsb(s >> 8));
+ Put((byte) Functions.Lsb(s));
+ }
+
+ public virtual void WriteUint32(long i)
+ {
+ Debug.Assert(i < 0x100000000L);
+ Put((byte) Functions.Lsb(i >> 24));
+ Put((byte) Functions.Lsb(i >> 16));
+ Put((byte) Functions.Lsb(i >> 8));
+ Put((byte) Functions.Lsb(i));
+ }
+
+ public void WriteSequenceNo(int i)
+ {
+ WriteUint32(i);
+ }
+
+ public virtual void WriteUint64(long l)
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ Put((byte) Functions.Lsb(l >> (56 - i*8)));
+ }
+ }
+
+ public abstract void WriteInt8(short b) ;
+ public abstract void WriteInt16(int s) ;
+ public abstract void WriteInt32(long i) ;
+ public abstract void WriteInt64(long l) ;
+ public abstract void WriteFloat(float f) ;
+ public abstract void WriteDouble(double d) ;
+
+ public void WriteDatetime(long l)
+ {
+ WriteUint64(l);
+ }
+
+ private static byte[] Encode(String s, Encoding encoding)
+ {
+ return encoding.GetBytes(s);
+ }
+
+ public void WriteStr8(String s)
+ {
+ if (s == null)
+ {
+ s = "";
+ }
+
+ byte[] bytes;
+ if (! str8cache.ContainsKey(s))
+ {
+ bytes = Encode(s, System.Text.Encoding.UTF8);
+ str8cache.Add(s, bytes);
+ }
+ else
+ {
+ bytes = str8cache[s];
+ }
+ WriteUint8((short) bytes.Length);
+ Put(bytes);
+ }
+
+ public void WriteStr16(String s)
+ {
+ if (s == null)
+ {
+ s = "";
+ }
+
+ byte[] bytes = Encode(s, System.Text.Encoding.UTF8);
+ WriteUint16(bytes.Length);
+ Put(bytes);
+ }
+
+ public void WriteVbin8(byte[] bytes)
+ {
+ if (bytes == null)
+ {
+ bytes = new byte[0];
+ }
+ if (bytes.Length > 255)
+ {
+ throw new Exception("array too long: " + bytes.Length);
+ }
+ WriteUint8((short) bytes.Length);
+ Put(bytes);
+ }
+
+ public void WriteVbin16(byte[] bytes)
+ {
+ if (bytes == null)
+ {
+ bytes = new byte[0];
+ }
+ WriteUint16(bytes.Length);
+ Put(bytes);
+ }
+
+ public void WriteVbin32(byte[] bytes)
+ {
+ if (bytes == null)
+ {
+ bytes = new byte[0];
+ }
+ WriteUint32(bytes.Length);
+ Put(bytes);
+ }
+
+ public void WriteSequenceSet(RangeSet ranges)
+ {
+ if (ranges == null)
+ {
+ WriteUint16(0);
+ }
+ else
+ {
+ WriteUint16(ranges.Size()*8);
+ foreach (Range range in ranges)
+ {
+ WriteSequenceNo(range.Lower);
+ WriteSequenceNo(range.Upper);
+ }
+ }
+ }
+
+ public void WriteByteRanges(RangeSet ranges)
+ {
+ throw new Exception("not implemented");
+ }
+
+ public void WriteUuid(UUID uuid)
+ {
+ long msb = 0;
+ long lsb = 0;
+ if (uuid != null)
+ {
+ msb = uuid.MostSignificantBits;
+ lsb = uuid.LeastSignificantBits;
+ }
+ WriteUint64(msb);
+ WriteUint64(lsb);
+ }
+
+ public void WriteStruct(int type, Struct s)
+ {
+ if (s == null)
+ {
+ s = Struct.Create(type);
+ }
+
+ int width = s.GetSizeWidth();
+ int pos = -1;
+ if (width > 0)
+ {
+ pos = BeginSize(width);
+ }
+
+ if (type > 0)
+ {
+ WriteUint16(type);
+ }
+
+ s.Write(this);
+
+ if (width > 0)
+ {
+ EndSize(width, pos);
+ }
+ }
+
+ public void WriteStruct32(Struct s)
+ {
+ if (s == null)
+ {
+ WriteUint32(0);
+ }
+ else
+ {
+ int pos = BeginSize32();
+ WriteUint16(s.GetEncodedType());
+ s.Write(this);
+ EndSize32(pos);
+ }
+ }
+
+ private Code Encoding(Object value)
+ {
+ if (value == null)
+ {
+ return Code.VOID;
+ }
+
+ Type klass = value.GetType();
+ Code type = Resolve(klass);
+
+ if (type == Code.VOID)
+ {
+ throw new Exception
+ ("unable to resolve type: " + klass + ", " + value);
+ }
+ else
+ {
+ return type;
+ }
+ }
+
+ private static Code Resolve(Type klass)
+ {
+ Code type;
+ if(ENCODINGS.ContainsKey(klass))
+ {
+ return ENCODINGS[klass];
+ }
+
+ Type sup = klass.BaseType;
+ if (sup != null)
+ {
+ type = Resolve(sup);
+
+ if (type != Code.VOID)
+ {
+ return type;
+ }
+ }
+ foreach (Type iface in klass.GetInterfaces())
+ {
+ type = Resolve(iface);
+ if (type != Code.VOID)
+ {
+ return type;
+ }
+ }
+ return Code.VOID;
+ }
+
+ public void WriteMap(Dictionary<String, Object> map)
+ {
+ int pos = BeginSize32();
+ if (map != null)
+ {
+ WriteUint32(map.Count);
+ WriteMapEntries(map);
+ }
+ EndSize32(pos);
+ }
+
+ protected void WriteMapEntries(Dictionary<String, Object> map)
+ {
+ foreach (KeyValuePair<String, Object> entry in map)
+ {
+ String key = entry.Key;
+ Object value = entry.Value;
+ Code type = Encoding(value);
+ WriteStr8(key);
+ Put((byte) type);
+ Write(type, value);
+ }
+ }
+
+ public void WriteList(List<Object> list)
+ {
+ int pos = BeginSize32();
+ if (list != null)
+ {
+ WriteUint32(list.Count);
+ WriteListEntries(list);
+ }
+ EndSize32(pos);
+ }
+
+ protected void WriteListEntries(List<Object> list)
+ {
+ foreach (Object value in list)
+ {
+ Code type = Encoding(value);
+ Put((byte) type);
+ Write(type, value);
+ }
+ }
+
+ public void WriteArray(List<Object> array)
+ {
+ int pos = BeginSize32();
+ if (array != null)
+ {
+ WriteArrayEntries(array);
+ }
+ EndSize32(pos);
+ }
+
+ protected void WriteArrayEntries(List<Object> array)
+ {
+ Code type;
+
+ if (array.Count == 0)
+ {
+ return;
+ }
+ else
+ {
+ type = Encoding(array[0]);
+ }
+ Put((byte) type);
+ WriteUint32(array.Count);
+
+ foreach (Object value in array)
+ {
+ Write(type, value);
+ }
+ }
+
+ private void WriteSize(QpidType t, int size)
+ {
+ if (t.Fixed)
+ {
+ if (size != t.width)
+ {
+ throw new Exception("size does not match fixed width " + t.width + ": " + size);
+ }
+ }
+ else
+ {
+ WriteSize(t.width, size);
+ }
+ }
+
+ private void WriteSize(int width, int size)
+ {
+ // XXX: should check lengths
+ switch (width)
+ {
+ case 1:
+ WriteUint8((short) size);
+ break;
+ case 2:
+ WriteUint16(size);
+ break;
+ case 4:
+ WriteUint32(size);
+ break;
+ default:
+ throw new Exception("illegal width: " + width);
+ }
+ }
+
+ private int BeginSize(int width)
+ {
+ switch (width)
+ {
+ case 1:
+ return BeginSize8();
+ case 2:
+ return BeginSize16();
+ case 4:
+ return BeginSize32();
+ default:
+ throw new Exception("illegal width: " + width);
+ }
+ }
+
+ private void EndSize(int width, int pos)
+ {
+ switch (width)
+ {
+ case 1:
+ EndSize8(pos);
+ break;
+ case 2:
+ EndSize16(pos);
+ break;
+ case 4:
+ EndSize32(pos);
+ break;
+ default:
+ throw new Exception("illegal width: " + width);
+ }
+ }
+
+ private void WriteBytes(QpidType t, byte[] bytes)
+ {
+ WriteSize(t, bytes.Length);
+ Put(bytes);
+ }
+
+ private void Write(Code t, Object value)
+ {
+ switch (t)
+ {
+ case Code.BIN8:
+ case Code.UINT8:
+ WriteUint8((short) value);
+ break;
+ case Code.INT8:
+ Put((Byte) value);
+ break;
+ case Code.CHAR:
+ byte[] b = BitConverter.GetBytes((char) value);
+ Put(b[0]);
+ break;
+ case Code.BOOLEAN:
+ if ((bool) value)
+ {
+ Put(1);
+ }
+ else
+ {
+ Put(0);
+ }
+
+ break;
+
+ case Code.BIN16:
+ case Code.UINT16:
+ WriteUint16((int) value);
+ break;
+
+ case Code.INT16:
+ WriteUint16((short) value);
+ break;
+
+ case Code.BIN32:
+ case Code.UINT32:
+ WriteUint32((long) value);
+ break;
+
+ case Code.CHAR_UTF32:
+ case Code.INT32:
+ WriteUint32((int) value);
+ break;
+
+ case Code.FLOAT:
+ WriteUint32(BitConverter.DoubleToInt64Bits((float) value) >> 32);
+ break;
+
+ case Code.BIN64:
+ case Code.UINT64:
+ case Code.INT64:
+ case Code.DATETIME:
+ WriteUint64((long) value);
+ break;
+
+ case Code.DOUBLE:
+ WriteUint64( BitConverter.DoubleToInt64Bits((double) value));
+ break;
+
+ case Code.UUID:
+ WriteUuid((UUID) value);
+ break;
+
+ case Code.STR8:
+ WriteStr8((string) value);
+ break;
+
+ case Code.STR16:
+ WriteStr16((string) value);
+ break;
+
+ case Code.STR8_LATIN:
+ case Code.STR8_UTF16:
+ case Code.STR16_LATIN:
+ case Code.STR16_UTF16:
+ // XXX: need to do character conversion
+ WriteBytes(QpidType.get((byte) t), Encode((string) value, System.Text.Encoding.Unicode));
+ break;
+
+ case Code.MAP:
+ WriteMap((Dictionary<String, Object>) value);
+ break;
+ case Code.LIST:
+ WriteList((List<Object>) value);
+ break;
+ case Code.ARRAY:
+ WriteList((List<Object>) value);
+ break;
+ case Code.STRUCT32:
+ WriteStruct32((Struct) value);
+ break;
+
+ case Code.BIN40:
+ case Code.DEC32:
+ case Code.BIN72:
+ case Code.DEC64:
+ // XXX: what types are we supposed to use here?
+ WriteBytes(QpidType.get((byte) t), (byte[]) value);
+ break;
+
+ case Code.VOID:
+ break;
+
+ default:
+ WriteBytes(QpidType.get((byte) t), (byte[]) value);
+ break;
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/codec/Decoder.cs b/dotnet/client-010/client/transport/codec/Decoder.cs
new file mode 100644
index 0000000000..9afc23fd4e
--- /dev/null
+++ b/dotnet/client-010/client/transport/codec/Decoder.cs
@@ -0,0 +1,72 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.Collections.Generic;
+using org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.transport.codec
+{
+ /// <summary>
+ /// Decoder
+ /// </summary>
+
+ public interface Decoder
+ {
+
+ bool hasRemaining();
+
+ short readUint8();
+ int readUint16();
+ long readUint32();
+ long readUint64();
+
+ short readInt8();
+ int readInt16();
+ long readInt32();
+ long readInt64();
+
+ double readDouble() ;
+ float readFloat() ;
+ long readDatetime();
+
+ UUID readUuid();
+
+ int readSequenceNo();
+ RangeSet readSequenceSet(); // XXX
+ RangeSet readByteRanges(); // XXX
+
+ String readStr8();
+ String readStr16();
+
+ byte[] readVbin8();
+ byte[] readVbin16();
+ byte[] readVbin32();
+
+ Struct readStruct32();
+ Dictionary<String, Object> readMap();
+ List<Object> readList();
+ List<Object> readArray();
+
+ Struct readStruct(int type);
+ }
+
+}
diff --git a/dotnet/client-010/client/transport/codec/Encodable.cs b/dotnet/client-010/client/transport/codec/Encodable.cs
new file mode 100644
index 0000000000..71f4f62458
--- /dev/null
+++ b/dotnet/client-010/client/transport/codec/Encodable.cs
@@ -0,0 +1,37 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+namespace org.apache.qpid.transport.codec
+{
+
+
+ /// <summary>
+ /// Encodable
+ /// </summary>
+
+ public interface Encodable
+ {
+
+ void write(Encoder enc);
+
+ void read(Decoder dec);
+ }
+} \ No newline at end of file
diff --git a/dotnet/client-010/client/transport/codec/Encoder.cs b/dotnet/client-010/client/transport/codec/Encoder.cs
new file mode 100644
index 0000000000..282e3ff5b5
--- /dev/null
+++ b/dotnet/client-010/client/transport/codec/Encoder.cs
@@ -0,0 +1,70 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.Collections.Generic;
+using org.apache.qpid.transport.util;
+using RangeSet = org.apache.qpid.transport.RangeSet;
+using Struct = org.apache.qpid.transport.Struct;
+namespace org.apache.qpid.transport.codec
+{
+ /// <summary>
+ /// Encoder
+ /// </summary>
+
+ public interface Encoder
+ {
+
+ void writeUint8(short b);
+ void writeUint16(int s);
+ void writeUint32(long i);
+ void writeUint64(long l);
+
+ void writeInt8(short b);
+ void writeInt16(int s);
+ void writeInt32(long i);
+ void writeInt64(long l);
+
+ void writeFloat(float f) ;
+ void writeDouble(double d) ;
+
+ void writeDatetime(long l);
+ void writeUuid(UUID uuid);
+
+ void writeSequenceNo(int s);
+ void writeSequenceSet(RangeSet ranges); // XXX
+ void writeByteRanges(RangeSet ranges); // XXX
+
+ void writeStr8(string s);
+ void writeStr16(string s);
+
+ void writeVbin8(byte[] bytes);
+ void writeVbin16(byte[] bytes);
+ void writeVbin32(byte[] bytes);
+
+ void writeStruct32(Struct s);
+ void writeMap(Dictionary<String, Object> map);
+ void writeList(List<Object> list);
+ void writeArray(List<Object> array);
+
+ void writeStruct(int type, Struct s);
+ }
+}
diff --git a/dotnet/client-010/client/transport/codec/IDecoder.cs b/dotnet/client-010/client/transport/codec/IDecoder.cs
new file mode 100644
index 0000000000..7de2e93fe7
--- /dev/null
+++ b/dotnet/client-010/client/transport/codec/IDecoder.cs
@@ -0,0 +1,72 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.Collections.Generic;
+using org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.transport.codec
+{
+ /// <summary>
+ /// Decoder
+ /// </summary>
+
+ public interface IDecoder
+ {
+
+ bool HasRemaining();
+
+ short ReadUint8();
+ int ReadUint16();
+ long ReadUint32();
+ long ReadUint64();
+
+ short ReadInt8();
+ int ReadInt16();
+ long ReadInt32();
+ long ReadInt64();
+
+ double ReadDouble() ;
+ float ReadFloat() ;
+ long ReadDatetime();
+
+ UUID ReadUuid();
+
+ int ReadSequenceNo();
+ RangeSet ReadSequenceSet(); // XXX
+ RangeSet ReadByteRanges(); // XXX
+
+ String ReadStr8();
+ String ReadStr16();
+
+ byte[] ReadVbin8();
+ byte[] ReadVbin16();
+ byte[] ReadVbin32();
+
+ Struct ReadStruct32();
+ Dictionary<String, Object> ReadMap();
+ List<Object> ReadList();
+ List<Object> ReadArray();
+
+ Struct ReadStruct(int type);
+ }
+
+}
diff --git a/dotnet/client-010/client/transport/codec/IEncodable.cs b/dotnet/client-010/client/transport/codec/IEncodable.cs
new file mode 100644
index 0000000000..5c63e17fdd
--- /dev/null
+++ b/dotnet/client-010/client/transport/codec/IEncodable.cs
@@ -0,0 +1,37 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+namespace org.apache.qpid.transport.codec
+{
+
+
+ /// <summary>
+ /// Encodable
+ /// </summary>
+
+ public interface IEncodable
+ {
+
+ void Write(IEncoder enc);
+
+ void Read(IDecoder dec);
+ }
+}
diff --git a/dotnet/client-010/client/transport/codec/IEncoder.cs b/dotnet/client-010/client/transport/codec/IEncoder.cs
new file mode 100644
index 0000000000..4ffc852052
--- /dev/null
+++ b/dotnet/client-010/client/transport/codec/IEncoder.cs
@@ -0,0 +1,70 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.Collections.Generic;
+using org.apache.qpid.transport.util;
+using RangeSet = org.apache.qpid.transport.RangeSet;
+using Struct = org.apache.qpid.transport.Struct;
+namespace org.apache.qpid.transport.codec
+{
+ /// <summary>
+ /// Encoder
+ /// </summary>
+
+ public interface IEncoder
+ {
+
+ void WriteUint8(short b);
+ void WriteUint16(int s);
+ void WriteUint32(long i);
+ void WriteUint64(long l);
+
+ void WriteInt8(short b);
+ void WriteInt16(int s);
+ void WriteInt32(long i);
+ void WriteInt64(long l);
+
+ void WriteFloat(float f) ;
+ void WriteDouble(double d) ;
+
+ void WriteDatetime(long l);
+ void WriteUuid(UUID uuid);
+
+ void WriteSequenceNo(int s);
+ void WriteSequenceSet(RangeSet ranges); // XXX
+ void WriteByteRanges(RangeSet ranges); // XXX
+
+ void WriteStr8(string s);
+ void WriteStr16(string s);
+
+ void WriteVbin8(byte[] bytes);
+ void WriteVbin16(byte[] bytes);
+ void WriteVbin32(byte[] bytes);
+
+ void WriteStruct32(Struct s);
+ void WriteMap(Dictionary<String, Object> map);
+ void WriteList(List<Object> list);
+ void WriteArray(List<Object> array);
+
+ void WriteStruct(int type, Struct s);
+ }
+}
diff --git a/dotnet/client-010/client/transport/codec/MSDecoder.cs b/dotnet/client-010/client/transport/codec/MSDecoder.cs
new file mode 100644
index 0000000000..59731b739a
--- /dev/null
+++ b/dotnet/client-010/client/transport/codec/MSDecoder.cs
@@ -0,0 +1,110 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.IO;
+using System.Text;
+using org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.transport.codec
+{
+
+
+ /// <summary>
+ /// MSDecoder
+ ///
+ /// </summary>
+
+
+ public sealed class MSDecoder : AbstractDecoder
+ {
+
+ private BinaryReader _reader;
+
+ public void Init(MemoryStream st)
+ {
+ _reader = new BinaryReader(st, Encoding.BigEndianUnicode);
+ }
+
+ protected override byte DoGet()
+ {
+ return _reader.ReadByte();
+ }
+
+ protected override void DoGet(byte[] bytes)
+ {
+ _reader.Read(bytes, 0, bytes.Length);
+ }
+
+ public override bool HasRemaining()
+ {
+ return (_reader.BaseStream.Position < _reader.BaseStream.Length);
+ }
+
+ public override short ReadUint8()
+ {
+ return (short) (0xFF & _reader.ReadByte());
+ }
+
+ public override int ReadUint16()
+ {
+ return ByteEncoder.GetBigEndian((UInt16) _reader.ReadInt16());
+ }
+
+ public override long ReadUint32()
+ {
+ return ByteEncoder.GetBigEndian((UInt32) _reader.ReadInt32());
+ }
+
+ public override long ReadUint64()
+ {
+ return (long) ByteEncoder.GetBigEndian(_reader.ReadInt64());
+ }
+
+ public override short ReadInt8()
+ {
+ return (short) (0xFF & _reader.ReadByte());
+ }
+
+ public override int ReadInt16()
+ {
+ return ByteEncoder.GetBigEndian((Int16) _reader.ReadInt16());
+ }
+
+ public override long ReadInt32()
+ {
+ return ByteEncoder.GetBigEndian((Int32) _reader.ReadInt32());
+ }
+
+ public override long ReadInt64()
+ {
+ return (long) ByteEncoder.GetBigEndian(_reader.ReadInt64());
+ }
+
+ public override double ReadDouble() {
+ return (double) ByteEncoder.GetBigEndian(_reader.ReadDouble()) ;
+ }
+
+ public override float ReadFloat() {
+ return (float) _reader.ReadSingle() ;
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/codec/MSEncoder.cs b/dotnet/client-010/client/transport/codec/MSEncoder.cs
new file mode 100644
index 0000000000..d863c57dee
--- /dev/null
+++ b/dotnet/client-010/client/transport/codec/MSEncoder.cs
@@ -0,0 +1,172 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.transport.codec
+{
+ /// <summary>
+ /// MSEncoder
+ /// </summary>
+ public sealed class MSEncoder : AbstractEncoder
+ {
+ private readonly MemoryStream _out;
+ private readonly BinaryWriter _writer;
+
+ public MSEncoder(int capacity)
+ {
+ _out = new MemoryStream(capacity);
+ _writer = new BinaryWriter(_out);
+ }
+
+ public void Init()
+ {
+ _out.Seek(0, SeekOrigin.Begin);
+ }
+
+ public MemoryStream Segment()
+ {
+ int length = (int) _out.Position;
+ MemoryStream result = new MemoryStream(_out.ToArray(), 0, length);
+ result.Seek(length, SeekOrigin.Begin);
+ _out.Seek(0, SeekOrigin.Begin);
+ return result;
+ }
+
+
+ protected override void DoPut(byte b)
+ {
+ _writer.Write(b);
+ }
+
+ protected override void DoPut(MemoryStream src)
+ {
+ _writer.Write(src.ToArray());
+ }
+
+ protected override void Put(byte[] bytes)
+ {
+ _writer.Write(bytes);
+ }
+
+ public override void WriteUint8(short b)
+ {
+ Debug.Assert(b < 0x100);
+ _writer.Write((byte) b);
+ }
+
+ public override void WriteUint16(int s)
+ {
+ Debug.Assert(s < 0x10000);
+ _writer.Write(ByteEncoder.GetBigEndian((UInt16) s));
+ }
+
+ public override void WriteUint32(long i)
+ {
+ Debug.Assert(i < 0x100000000L);
+ _writer.Write(ByteEncoder.GetBigEndian((UInt32) i));
+ }
+
+ public override void WriteUint64(long l)
+ {
+ _writer.Write(ByteEncoder.GetBigEndian(l));
+ }
+
+ public override void WriteInt8(short b)
+ {
+ Debug.Assert(b < 0x100);
+ _writer.Write((byte) b);
+ }
+
+ public override void WriteInt16(int s)
+ {
+ Debug.Assert(s < 0x10000);
+ _writer.Write(ByteEncoder.GetBigEndian((Int16) s));
+ }
+
+ public override void WriteInt32(long i)
+ {
+ Debug.Assert(i < 0x100000000L);
+ _writer.Write(ByteEncoder.GetBigEndian((Int32) i));
+ }
+
+ public override void WriteInt64(long l)
+ {
+ _writer.Write(ByteEncoder.GetBigEndian(l));
+ }
+
+ public override void WriteFloat(float f) {
+ _writer.Write(f) ;
+ }
+
+ public override void WriteDouble(double d) {
+ _writer.Write(ByteEncoder.GetBigEndian(d)) ;
+ }
+
+ protected override int BeginSize8()
+ {
+ int pos = (int) _out.Position;
+ _writer.Write((byte) 0);
+ return pos;
+ }
+
+ protected override void EndSize8(int pos)
+ {
+ int cur = (int) _out.Position;
+ _out.Seek(pos, SeekOrigin.Begin);
+ _writer.Write((byte) (cur - pos - 1));
+ _out.Seek(cur, SeekOrigin.Begin);
+ }
+
+ protected override int BeginSize16()
+ {
+ int pos = (int) _out.Position;
+ _writer.Write((short) 0);
+ return pos;
+ }
+
+ protected override void EndSize16(int pos)
+ {
+ int cur = (int) _out.Position;
+ _out.Seek(pos, SeekOrigin.Begin);
+ _writer.Write((short) (cur - pos - 2));
+ _out.Seek(cur, SeekOrigin.Begin);
+ }
+
+ protected override int BeginSize32()
+ {
+ int pos = (int) _out.Position;
+ _writer.Write(0);
+ return pos;
+ }
+
+ protected override void EndSize32(int pos)
+ {
+ int cur = (int) _out.Position;
+ _out.Seek(pos, SeekOrigin.Begin);
+ _writer.Write(ByteEncoder.GetBigEndian((Int32) cur - pos - 4));
+ _out.Seek(cur, SeekOrigin.Begin);
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/exception/ConnectionException.cs b/dotnet/client-010/client/transport/exception/ConnectionException.cs
new file mode 100644
index 0000000000..cbf5e39e52
--- /dev/null
+++ b/dotnet/client-010/client/transport/exception/ConnectionException.cs
@@ -0,0 +1,49 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+namespace org.apache.qpid.transport
+{
+
+
+ /// <summary>
+ /// ConnectionException
+ /// </summary>
+
+ [Serializable]
+ public class ConnectionException : Exception
+ {
+ virtual public ConnectionClose Close
+ {
+ get
+ {
+ return _close;
+ }
+
+ }
+
+ private ConnectionClose _close;
+
+ public ConnectionException(ConnectionClose close):base(close.GetReplyText())
+ {
+ _close = close;
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/exception/ExceptionArgs.cs b/dotnet/client-010/client/transport/exception/ExceptionArgs.cs
new file mode 100644
index 0000000000..01793a6ad0
--- /dev/null
+++ b/dotnet/client-010/client/transport/exception/ExceptionArgs.cs
@@ -0,0 +1,41 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+
+namespace org.apache.qpid.transport
+{
+ public class ExceptionArgs : EventArgs
+ {
+ public ExceptionArgs(Exception e)
+ {
+ _exception = e;
+ }
+ private Exception _exception;
+
+ public Exception Exception
+ {
+ get { return _exception; }
+ set { _exception = value; }
+ }
+
+ }
+}
diff --git a/dotnet/client-010/client/transport/exception/ProtocolVersionException.cs b/dotnet/client-010/client/transport/exception/ProtocolVersionException.cs
new file mode 100644
index 0000000000..f18fc1173f
--- /dev/null
+++ b/dotnet/client-010/client/transport/exception/ProtocolVersionException.cs
@@ -0,0 +1,59 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+namespace org.apache.qpid.transport
+{
+
+
+ /// <summary> ProtocolVersionException
+ ///
+ /// </summary>
+
+ [Serializable]
+ public sealed class ProtocolVersionException:TransportException
+ {
+ public sbyte Major
+ {
+ get
+ {
+ return _major;
+ }
+
+ }
+ public sbyte Minor
+ {
+ get
+ {
+ return _minor;
+ }
+
+ }
+
+ private sbyte _major;
+ private sbyte _minor;
+
+ public ProtocolVersionException(sbyte major, sbyte minor):base(String.Format("version missmatch: %{0}-{1}", major, minor))
+ {
+ this._major = major;
+ this._minor = minor;
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/exception/SessionClosedException.cs b/dotnet/client-010/client/transport/exception/SessionClosedException.cs
new file mode 100644
index 0000000000..89453433ee
--- /dev/null
+++ b/dotnet/client-010/client/transport/exception/SessionClosedException.cs
@@ -0,0 +1,38 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System.Collections.Generic;
+
+namespace org.apache.qpid.transport
+{
+
+
+ /// <summary>
+ /// SessionClosedException
+ /// </summary>
+
+ public class SessionClosedException : SessionException
+ {
+
+ public SessionClosedException(): base(new List<ExecutionException>())
+ {
+ }
+ }
+} \ No newline at end of file
diff --git a/dotnet/client-010/client/transport/exception/SessionException.cs b/dotnet/client-010/client/transport/exception/SessionException.cs
new file mode 100644
index 0000000000..f02ffa5c2f
--- /dev/null
+++ b/dotnet/client-010/client/transport/exception/SessionException.cs
@@ -0,0 +1,45 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using System.Collections.Generic;
+
+namespace org.apache.qpid.transport
+{
+ /// <summary>
+ /// SessionException
+ /// </summary>
+ public class SessionException : Exception
+ {
+ private readonly List<ExecutionException> _exceptions;
+
+ public SessionException(List<ExecutionException> exceptions)
+ : base(exceptions.Count == 0 ? "" : exceptions.ToString())
+
+ {
+ _exceptions = exceptions;
+ }
+
+ public List<ExecutionException> Exceptions
+ {
+ get { return _exceptions; }
+ }
+ }
+} \ No newline at end of file
diff --git a/dotnet/client-010/client/transport/exception/TransportException.cs b/dotnet/client-010/client/transport/exception/TransportException.cs
new file mode 100644
index 0000000000..d016f90a83
--- /dev/null
+++ b/dotnet/client-010/client/transport/exception/TransportException.cs
@@ -0,0 +1,46 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+namespace org.apache.qpid.transport
+{
+
+
+ /// <summary>
+ /// TransportException
+ /// </summary>
+
+
+ public class TransportException : Exception
+ {
+ public TransportException(String msg) : base(msg)
+ {
+ }
+
+ public TransportException(String msg, Exception cause) : base(msg, cause)
+ {
+ }
+
+ public TransportException(Exception cause): base("Transport Exception", cause)
+ {
+ }
+
+ }
+} \ No newline at end of file
diff --git a/dotnet/client-010/client/transport/network/Assembler.cs b/dotnet/client-010/client/transport/network/Assembler.cs
new file mode 100644
index 0000000000..ff85f11c2f
--- /dev/null
+++ b/dotnet/client-010/client/transport/network/Assembler.cs
@@ -0,0 +1,254 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using org.apache.qpid.transport.codec;
+using org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.transport.network
+{
+ /// <summary>
+ /// Assembler
+ /// </summary>
+ public delegate void Processor(INetworkDelegate ndelegate);
+
+ public class Assembler : INetworkDelegate, IReceiver<ReceivedPayload<IProtocolEvent>>
+ {
+ private static readonly Logger log = Logger.Get(typeof (Assembler));
+ private readonly Dictionary<int, List<byte[]>> segments;
+ private readonly Method[] incomplete;
+ [ThreadStatic] static MSDecoder _decoder;
+ private readonly Object m_objectLock = new object();
+
+ // the event raised when a buffer is read from the wire
+ public event EventHandler<ReceivedPayload<IProtocolEvent>> ReceivedEvent;
+ public event EventHandler Closed;
+
+
+ // Not in use :
+ public event EventHandler<ExceptionArgs> Exception;
+
+ event EventHandler<ReceivedPayload<IProtocolEvent>> IReceiver<ReceivedPayload<IProtocolEvent>>.Received
+ {
+ add
+ {
+ lock (m_objectLock)
+ {
+ ReceivedEvent += value;
+ }
+ }
+ remove
+ {
+ lock (m_objectLock)
+ {
+ ReceivedEvent -= value;
+ }
+ }
+ }
+
+ public Assembler()
+ {
+ segments = new Dictionary<int, List<byte[]>>();
+ incomplete = new Method[64*1024];
+ }
+
+ // Invoked when a network event is received
+ public void On_ReceivedEvent(object sender, ReceivedPayload<INetworkEvent> payload)
+ {
+ payload.Payload.ProcessNetworkEvent(this);
+ }
+
+ #region Interface INetworkDelegate
+
+ public void Init(ProtocolHeader header)
+ {
+ Emit(0, header);
+ }
+
+ public void Error(ProtocolError error)
+ {
+ Emit(0, error);
+ }
+
+ public void Frame(Frame frame)
+ {
+ MemoryStream segment;
+ if (frame.IsFirstFrame() && frame.IsLastFrame())
+ {
+ byte[] tmp = new byte[frame.BodySize];
+ frame.Body.Read(tmp, 0, tmp.Length);
+ segment = new MemoryStream();
+ BinaryWriter w = new BinaryWriter(segment);
+ w.Write(tmp);
+ Assemble(frame, new MemoryStream(tmp));
+ }
+ else
+ {
+ List<byte[]> frames;
+ if (frame.IsFirstFrame())
+ {
+ frames = new List<byte[]>();
+ SetSegment(frame, frames);
+ }
+ else
+ {
+ frames = GetSegment(frame);
+ }
+ byte[] tmp = new byte[frame.BodySize];
+ frame.Body.Read(tmp, 0, tmp.Length);
+ frames.Add(tmp);
+
+ if (frame.IsLastFrame())
+ {
+ ClearSegment(frame);
+ segment = new MemoryStream();
+ BinaryWriter w = new BinaryWriter(segment);
+ foreach (byte[] f in frames)
+ {
+ w.Write(f);
+ }
+ Assemble(frame, segment);
+ }
+ }
+ }
+
+ #endregion
+
+ #region Private Support Functions
+
+
+ private MSDecoder GetDecoder()
+ {
+ if( _decoder == null )
+ {
+ _decoder = new MSDecoder();
+ }
+ return _decoder;
+ }
+
+ private void Assemble(Frame frame, MemoryStream segment)
+ {
+ MSDecoder decoder = GetDecoder();
+ decoder.Init(segment);
+ int channel = frame.Channel;
+ Method command;
+ switch (frame.Type)
+ {
+ case SegmentType.CONTROL:
+ int controlType = decoder.ReadUint16();
+ Method control = Method.Create(controlType);
+ control.Read(decoder);
+ Emit(channel, control);
+ break;
+ case SegmentType.COMMAND:
+ int commandType = decoder.ReadUint16();
+ // read in the session header, right now we don't use it
+ decoder.ReadUint16();
+ command = Method.Create(commandType);
+ command.Read(decoder);
+ if (command.HasPayload())
+ {
+ incomplete[channel] = command;
+ }
+ else
+ {
+ Emit(channel, command);
+ }
+ break;
+ case SegmentType.HEADER:
+ command = incomplete[channel];
+ List<Struct> structs = new List<Struct>();
+ while (decoder.HasRemaining())
+ {
+ structs.Add(decoder.ReadStruct32());
+ }
+ command.Header = new Header(structs);
+ if (frame.IsLastSegment())
+ {
+ incomplete[channel] = null;
+ Emit(channel, command);
+ }
+ break;
+ case SegmentType.BODY:
+ command = incomplete[channel];
+ segment.Seek(0, SeekOrigin.Begin);
+ command.Body = segment;
+ incomplete[channel] = null;
+ Emit(channel, command);
+ break;
+ default:
+ throw new Exception("unknown frame type: " + frame.Type);
+ }
+ }
+
+ private int SegmentKey(Frame frame)
+ {
+ return (frame.Track + 1)*frame.Channel;
+ }
+
+ private List<byte[]> GetSegment(Frame frame)
+ {
+ return segments[SegmentKey(frame)];
+ }
+
+ private void SetSegment(Frame frame, List<byte[]> segment)
+ {
+ int key = SegmentKey(frame);
+ if (segments.ContainsKey(key))
+ {
+ Error(new ProtocolError(network.Frame.L2, "segment in progress: %s",
+ frame));
+ }
+ segments.Add(SegmentKey(frame), segment);
+ }
+
+ private void ClearSegment(Frame frame)
+ {
+ segments.Remove(SegmentKey(frame));
+ }
+
+ // Emit a protocol event
+ private void Emit(int channel, IProtocolEvent protevent)
+ {
+ protevent.Channel = channel;
+ log.Debug("Assembler: protocol event:", protevent);
+ ReceivedPayload<IProtocolEvent> payload = new ReceivedPayload<IProtocolEvent>();
+ payload.Payload = protevent;
+
+ if (protevent is ConnectionCloseOk)
+ {
+ if (Closed != null)
+ Closed(this, EventArgs.Empty);
+ }
+ else
+ {
+ if (ReceivedEvent != null)
+ ReceivedEvent(this, payload);
+ else
+ log.Debug("No listener for event: {0}", protevent);
+ }
+ }
+
+ #endregion
+ }
+} \ No newline at end of file
diff --git a/dotnet/client-010/client/transport/network/Disassembler.cs b/dotnet/client-010/client/transport/network/Disassembler.cs
new file mode 100644
index 0000000000..3f0a6a8974
--- /dev/null
+++ b/dotnet/client-010/client/transport/network/Disassembler.cs
@@ -0,0 +1,222 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using System.IO;
+using org.apache.qpid.transport.codec;
+using org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.transport.network
+{
+ /// <summary>
+ /// Disassembler
+ /// </summary>
+ public sealed class Disassembler : ISender<IProtocolEvent>, IProtocolDelegate<Object>
+ {
+ private readonly IIoSender<MemoryStream> _sender;
+ private readonly int _maxPayload;
+ private readonly MemoryStream _header;
+ private readonly BinaryWriter _writer;
+ private readonly Object _sendlock = new Object();
+ [ThreadStatic] static MSEncoder _encoder;
+
+
+ public Disassembler(IIoSender<MemoryStream> sender, int maxFrame)
+ {
+ if (maxFrame <= network.Frame.HEADER_SIZE || maxFrame >= 64*1024)
+ {
+ throw new Exception(String.Format("maxFrame must be > {0} and < 64K: ", network.Frame.HEADER_SIZE) + maxFrame);
+ }
+ _sender = sender;
+ _maxPayload = maxFrame - network.Frame.HEADER_SIZE;
+ _header = new MemoryStream(network.Frame.HEADER_SIZE);
+ _writer = new BinaryWriter(_header);
+ }
+
+ #region Sender Interface
+
+ public void Send(IProtocolEvent pevent)
+ {
+ pevent.ProcessProtocolEvent(null, this);
+ }
+
+ public void Flush()
+ {
+ lock (_sendlock)
+ {
+ _sender.Flush();
+ }
+ }
+
+ public void Close()
+ {
+ lock (_sendlock)
+ {
+ _sender.Close();
+ }
+ }
+
+ #endregion
+
+ #region ProtocolDelegate<Object> Interface
+
+ public void Init(Object v, ProtocolHeader header)
+ {
+ lock (_sendlock)
+ {
+ _sender.Send(header.ToMemoryStream());
+ _sender.Flush();
+ }
+ }
+
+ public void Control(Object v, Method method)
+ {
+ InvokeMethod(method, SegmentType.CONTROL);
+ }
+
+ public void Command(Object v, Method method)
+ {
+ InvokeMethod(method, SegmentType.COMMAND);
+ }
+
+ public void Error(Object v, ProtocolError error)
+ {
+ throw new Exception("Error: " + error);
+ }
+
+ #endregion
+
+ #region private
+
+ private void Frame(byte flags, byte type, byte track, int channel, int size, MemoryStream buf)
+ {
+ lock (_sendlock)
+ {
+ _writer.Write(flags);
+ _writer.Write(type);
+ _writer.Write(ByteEncoder.GetBigEndian((UInt16)(size + network.Frame.HEADER_SIZE)));
+ _writer.Write((byte)0);
+ _writer.Write(track);
+ _writer.Write(ByteEncoder.GetBigEndian((UInt16)( channel)));
+ _writer.Write((byte)0);
+ _writer.Write((byte)0);
+ _writer.Write((byte)0);
+ _writer.Write((byte)0);
+ _sender.Send(_header);
+ _header.Seek(0, SeekOrigin.Begin);
+ _sender.Send(buf, size);
+ }
+ }
+
+ private void Fragment(byte flags, SegmentType type, IProtocolEvent mevent, MemoryStream buf)
+ {
+ byte typeb = (byte) type;
+ byte track = mevent.EncodedTrack == network.Frame.L4 ? (byte) 1 : (byte) 0;
+ int remaining = (int) buf.Length;
+ buf.Seek(0, SeekOrigin.Begin);
+ bool first = true;
+ while (true)
+ {
+ int size = Math.Min(_maxPayload, remaining);
+ remaining -= size;
+
+ byte newflags = flags;
+ if (first)
+ {
+ newflags |= network.Frame.FIRST_FRAME;
+ first = false;
+ }
+ if (remaining == 0)
+ {
+ newflags |= network.Frame.LAST_FRAME;
+ }
+
+ Frame(newflags, typeb, track, mevent.Channel, size, buf);
+
+ if (remaining == 0)
+ {
+ break;
+ }
+ }
+ }
+
+ private MSEncoder GetEncoder()
+ {
+ if( _encoder == null)
+ {
+ _encoder = new MSEncoder(4 * 1024);
+ }
+ return _encoder;
+ }
+
+ private void InvokeMethod(Method method, SegmentType type)
+ {
+ MSEncoder encoder = GetEncoder();
+ encoder.Init();
+ encoder.WriteUint16(method.GetEncodedType());
+ if (type == SegmentType.COMMAND)
+ {
+ if (method.Sync)
+ {
+ encoder.WriteUint16(0x0101);
+ }
+ else
+ {
+ encoder.WriteUint16(0x0100);
+ }
+ }
+ method.Write(_encoder);
+ MemoryStream methodSeg = encoder.Segment();
+
+ byte flags = network.Frame.FIRST_SEG;
+
+ bool payload = method.HasPayload();
+ if (!payload)
+ {
+ flags |= network.Frame.LAST_SEG;
+ }
+
+ MemoryStream headerSeg = null;
+ if (payload)
+ {
+ Header hdr = method.Header;
+ Struct[] structs = hdr.Structs;
+
+ foreach (Struct st in structs)
+ {
+ encoder.WriteStruct32(st);
+ }
+ headerSeg = encoder.Segment();
+ }
+
+ lock (_sendlock)
+ {
+ Fragment(flags, type, method, methodSeg);
+ if (payload)
+ {
+ Fragment( 0x0, SegmentType.HEADER, method, headerSeg);
+ Fragment(network.Frame.LAST_SEG, SegmentType.BODY, method, method.Body);
+ }
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/dotnet/client-010/client/transport/network/Frame.cs b/dotnet/client-010/client/transport/network/Frame.cs
new file mode 100644
index 0000000000..b8ec36d8b6
--- /dev/null
+++ b/dotnet/client-010/client/transport/network/Frame.cs
@@ -0,0 +1,143 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using System.IO;
+
+namespace org.apache.qpid.transport.network
+{
+ public sealed class Frame : INetworkEvent
+ {
+ internal static int HEADER_SIZE = 12;
+
+ // XXX: enums?
+ public const byte L1 = 0;
+ public const byte L2 = 1;
+ public const byte L3 = 2;
+ public const byte L4 = 3;
+
+ public static byte RESERVED = 0x0;
+
+ public static byte VERSION = 0x0;
+
+ public static byte FIRST_SEG = 0x8;
+ public static byte LAST_SEG = 0x4;
+ public static byte FIRST_FRAME = 0x2;
+ public static byte LAST_FRAME = 0x1;
+
+ private readonly byte flags;
+ private readonly SegmentType type;
+ private readonly byte track;
+ private readonly int channel;
+ private readonly MemoryStream body;
+ private int _bodySize;
+
+
+ public Frame(byte flags, SegmentType type, byte track, int channel, int bodySize,
+ MemoryStream body)
+ {
+ this.flags = flags;
+ this.type = type;
+ this.track = track;
+ this.channel = channel;
+ this.body = body;
+ _bodySize = bodySize;
+ }
+
+ public int BodySize
+ {
+ get { return _bodySize; }
+ }
+
+ public MemoryStream Body
+ {
+ get { return body; }
+ }
+
+ public byte Flags
+ {
+ get { return flags; }
+ }
+
+ public int Channel
+ {
+ get { return channel; }
+ }
+
+ public int Size
+ {
+ get { return (int) body.Length;}
+ }
+
+ public SegmentType Type
+ {
+ get { return type; }
+ }
+
+ public byte Track
+ {
+ get { return track; }
+ }
+
+ private bool Flag(byte mask)
+ {
+ return (flags & mask) != 0;
+ }
+
+ public bool IsFirstSegment()
+ {
+ return Flag(FIRST_SEG);
+ }
+
+ public bool IsLastSegment()
+ {
+ return Flag(LAST_SEG);
+ }
+
+ public bool IsFirstFrame()
+ {
+ return Flag(FIRST_FRAME);
+ }
+
+ public bool IsLastFrame()
+ {
+ return Flag(LAST_FRAME);
+ }
+
+ #region INetworkEvent Methods
+
+ public void ProcessNetworkEvent(INetworkDelegate ndelegate)
+ {
+ ndelegate.Frame(this);
+ }
+
+ #endregion
+
+ public override String ToString()
+ {
+ return String.Format
+ ("[{0:d} {1:d} {2:d} {3} {4}{5}{6}{7}] ", Channel, Size, Track, Type,
+ IsFirstSegment() ? 1 : 0, IsLastSegment() ? 1 : 0,
+ IsFirstFrame() ? 1 : 0, IsLastFrame() ? 1 : 0);
+ }
+
+
+ }
+}
diff --git a/dotnet/client-010/client/transport/network/IIoSender.cs b/dotnet/client-010/client/transport/network/IIoSender.cs
new file mode 100644
index 0000000000..747b5b9f98
--- /dev/null
+++ b/dotnet/client-010/client/transport/network/IIoSender.cs
@@ -0,0 +1,28 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+namespace org.apache.qpid.transport.network
+{
+ public interface IIOSender<T>:Sender<T>
+ {
+ void send(T body, int siz);
+ }
+}
diff --git a/dotnet/client-010/client/transport/network/INetworkDelegate.cs b/dotnet/client-010/client/transport/network/INetworkDelegate.cs
new file mode 100644
index 0000000000..9226adc2b7
--- /dev/null
+++ b/dotnet/client-010/client/transport/network/INetworkDelegate.cs
@@ -0,0 +1,40 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using ProtocolError = org.apache.qpid.transport.ProtocolError;
+using ProtocolHeader = org.apache.qpid.transport.ProtocolHeader;
+namespace org.apache.qpid.transport.network
+{
+
+
+ /// <summary>
+ /// NetworkDelegate
+ /// </summary>
+
+ public interface INetworkDelegate
+ {
+
+ void Init(ProtocolHeader header);
+
+ void Frame(Frame frame);
+
+ void Error(ProtocolError error);
+ }
+}
diff --git a/dotnet/client-010/client/transport/network/INetworkEvent.cs b/dotnet/client-010/client/transport/network/INetworkEvent.cs
new file mode 100644
index 0000000000..e6f0d6fc8a
--- /dev/null
+++ b/dotnet/client-010/client/transport/network/INetworkEvent.cs
@@ -0,0 +1,32 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+namespace org.apache.qpid.transport.network
+{
+
+ /// <summary>
+ /// INetworkEvent
+ /// </summary>
+
+ public interface INetworkEvent
+ {
+ void ProcessNetworkEvent(INetworkDelegate networkDelegate);
+ }
+}
diff --git a/dotnet/client-010/client/transport/network/InputHandler.cs b/dotnet/client-010/client/transport/network/InputHandler.cs
new file mode 100644
index 0000000000..c5d5f13727
--- /dev/null
+++ b/dotnet/client-010/client/transport/network/InputHandler.cs
@@ -0,0 +1,266 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using System.IO;
+using System.Text;
+using org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.transport.network
+{
+ /// <summary>
+ /// InputHandler
+ /// </summary>
+ public sealed class InputHandler : IReceiver<ReceivedPayload<INetworkEvent>>
+ {
+ public enum State
+ {
+ PROTO_HDR,
+ FRAME_HDR,
+ FRAME_BODY,
+ ERROR
+ }
+
+ private static readonly Logger log = Logger.Get(typeof(InputHandler));
+ private readonly Object m_objectLock = new object();
+
+ // the event raised when a buffer is read from the wire
+ public event EventHandler<ReceivedPayload<INetworkEvent>> ReceivedEvent;
+ public event EventHandler<ExceptionArgs> ExceptionProcessing;
+
+ // Not in used... This even is never raised in the code => the application will block on Close() until the timeout is reached
+ public event EventHandler Closed;
+
+ event EventHandler<ReceivedPayload<INetworkEvent>> IReceiver<ReceivedPayload<INetworkEvent>>.Received
+ {
+ add
+ {
+ lock (m_objectLock)
+ {
+ ReceivedEvent += value;
+ }
+ }
+ remove
+ {
+ lock (m_objectLock)
+ {
+ ReceivedEvent -= value;
+ }
+ }
+ }
+
+ event EventHandler<ExceptionArgs> IReceiver<ReceivedPayload<INetworkEvent>>.Exception
+ {
+ add
+ {
+ lock (m_objectLock)
+ {
+ ExceptionProcessing += value;
+ }
+ }
+ remove
+ {
+ lock (m_objectLock)
+ {
+ ExceptionProcessing -= value;
+ }
+ }
+ }
+
+ private State state;
+ private MemoryStream input;
+ private int needed;
+
+ private byte flags;
+ private SegmentType type;
+ private byte track;
+ private int channel;
+
+ public InputHandler(State state)
+ {
+ this.state = state;
+ switch (state)
+ {
+ case State.PROTO_HDR:
+ needed = 8;
+ break;
+ case State.FRAME_HDR:
+ needed = Frame.HEADER_SIZE;
+ break;
+ }
+ }
+
+ // The command listening for a buffer read.
+ public void On_ReceivedBuffer(object sender, ReceivedPayload<MemoryStream> payload)
+ {
+ MemoryStream buf = payload.Payload;
+ int remaining = (int) buf.Length;
+ if( input != null )
+ {
+ remaining += (int) input.Length;
+ }
+ try
+ {
+ while (remaining > 0)
+ {
+ if (remaining >= needed)
+ {
+ if (input != null)
+ {
+ byte[] tmp = new byte[buf.Length];
+ buf.Read(tmp, 0, tmp.Length);
+ input.Write(tmp, 0, tmp.Length);
+ input.Seek(0, SeekOrigin.Begin);
+ buf = input;
+ }
+ int startPos = (int)buf.Position;
+ int consumed = needed;
+ state = Next(buf);
+ if ((buf.Position - startPos) < consumed)
+ {
+ buf.Seek(consumed - (buf.Position - startPos), SeekOrigin.Current);
+ }
+ remaining -= consumed;
+ input = null;
+ }
+ else
+ {
+ byte[] tmp;
+ if (input == null)
+ {
+ input = new MemoryStream();
+ tmp = new byte[remaining];
+ }
+ else
+ {
+ // this is a full buffer
+ tmp = new byte[buf.Length];
+ }
+ buf.Read(tmp, 0, tmp.Length);
+ input.Write(tmp, 0, tmp.Length);
+ remaining = 0;
+ }
+ }
+ }
+ catch (Exception t)
+ {
+ Console.Write(t);
+ if (ExceptionProcessing != null)
+ {
+ ExceptionProcessing(this, new ExceptionArgs(t));
+ }
+ }
+ }
+
+ #region Private Support Functions
+
+ private State Next(MemoryStream buf)
+ {
+ BinaryReader reader = new BinaryReader(buf);
+
+ switch (state)
+ {
+ case State.PROTO_HDR:
+ char a = reader.ReadChar();
+ char m = reader.ReadChar();
+ char q = reader.ReadChar();
+ char p = reader.ReadChar();
+ if (a != 'A' &&
+ m != 'M' &&
+ q != 'Q' &&
+ p != 'P')
+ {
+ Error("bad protocol header: {0}", buf.ToString());
+ return State.ERROR;
+ }
+ reader.ReadByte();
+ byte instance = reader.ReadByte();
+ byte major = reader.ReadByte();
+ byte minor = reader.ReadByte();
+ Fire_NetworkEvent(new ProtocolHeader(instance, major, minor));
+ needed = Frame.HEADER_SIZE;
+ return State.FRAME_HDR;
+ case State.FRAME_HDR:
+ reader = new BinaryReader(buf, Encoding.BigEndianUnicode);
+ flags = reader.ReadByte();
+ type = SegmentTypeGetter.Get(reader.ReadByte()); // generated code
+ int size = reader.ReadUInt16();
+ size = ByteEncoder.GetBigEndian((UInt16)size);
+ size -= Frame.HEADER_SIZE;
+ if (size < 0 || size > (64 * 1024 - 12))
+ {
+ Error("bad frame size: {0:d}", size);
+ return State.ERROR;
+ }
+ reader.ReadByte();
+ byte b = reader.ReadByte();
+ if ((b & 0xF0) != 0)
+ {
+ Error("non-zero reserved bits in upper nibble of " +
+ "frame header byte 5: {0}", b);
+ return State.ERROR;
+ }
+ track = (byte)(b & 0xF);
+ channel = reader.ReadUInt16();
+ channel = ByteEncoder.GetBigEndian((UInt16)channel);
+ if (size == 0)
+ {
+ Fire_NetworkEvent(new Frame(flags, type, track, channel, 0, new MemoryStream()));
+ needed = Frame.HEADER_SIZE;
+ return State.FRAME_HDR;
+ }
+ needed = size;
+ return State.FRAME_BODY;
+ case State.FRAME_BODY:
+ Fire_NetworkEvent(new Frame(flags, type, track, channel, needed, buf));
+ needed = Frame.HEADER_SIZE;
+ return State.FRAME_HDR;
+ default:
+ if (ExceptionProcessing != null)
+ {
+ ExceptionProcessing(this, new ExceptionArgs(new Exception("Error creating frame")));
+ }
+ throw new Exception("Error creating frame");
+ }
+ }
+
+ private void Error(String fmt, params Object[] args)
+ {
+ Fire_NetworkEvent(new ProtocolError(Frame.L1, fmt, args));
+ }
+
+ private void Fire_NetworkEvent(INetworkEvent netevent)
+ {
+ log.Debug("InputHandler: network event:", netevent);
+ ReceivedPayload<INetworkEvent> payload = new ReceivedPayload<INetworkEvent>();
+ payload.Payload = netevent;
+ if (ReceivedEvent != null)
+ {
+ ReceivedEvent(this, payload);
+ }
+ else
+ {
+ log.Debug("Nobody listening for event: {0}");
+ }
+ }
+
+ #endregion
+ }
+} \ No newline at end of file
diff --git a/dotnet/client-010/client/transport/network/NetworkDelegate.cs b/dotnet/client-010/client/transport/network/NetworkDelegate.cs
new file mode 100644
index 0000000000..69598a43e8
--- /dev/null
+++ b/dotnet/client-010/client/transport/network/NetworkDelegate.cs
@@ -0,0 +1,40 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using ProtocolError = org.apache.qpid.transport.ProtocolError;
+using ProtocolHeader = org.apache.qpid.transport.ProtocolHeader;
+namespace org.apache.qpid.transport.network
+{
+
+
+ /// <summary>
+ /// NetworkDelegate
+ /// </summary>
+
+ public interface NetworkDelegate
+ {
+
+ void Init(ProtocolHeader header);
+
+ void Frame(Frame frame);
+
+ void Error(ProtocolError error);
+ }
+} \ No newline at end of file
diff --git a/dotnet/client-010/client/transport/network/NetworkEvent.cs b/dotnet/client-010/client/transport/network/NetworkEvent.cs
new file mode 100644
index 0000000000..e5ac6de93a
--- /dev/null
+++ b/dotnet/client-010/client/transport/network/NetworkEvent.cs
@@ -0,0 +1,32 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+namespace org.apache.qpid.transport.network
+{
+
+ /// <summary>
+ /// NetworkEvent
+ /// </summary>
+
+ public interface NetworkEvent
+ {
+ void ProcessNetworkEvent(NetworkDelegate networkDelegate);
+ }
+} \ No newline at end of file
diff --git a/dotnet/client-010/client/transport/network/io/IIoSender.cs b/dotnet/client-010/client/transport/network/io/IIoSender.cs
new file mode 100644
index 0000000000..acc7724a06
--- /dev/null
+++ b/dotnet/client-010/client/transport/network/io/IIoSender.cs
@@ -0,0 +1,28 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+namespace org.apache.qpid.transport.network
+{
+ public interface IIoSender<T>:ISender<T>
+ {
+ void Send(T body, int siz);
+ }
+}
diff --git a/dotnet/client-010/client/transport/network/io/IIoTransport.cs b/dotnet/client-010/client/transport/network/io/IIoTransport.cs
new file mode 100644
index 0000000000..41a09e7079
--- /dev/null
+++ b/dotnet/client-010/client/transport/network/io/IIoTransport.cs
@@ -0,0 +1,57 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+using System.IO;
+using System.Net.Sockets;
+
+namespace org.apache.qpid.transport.network.io
+{
+ public interface IIoTransport
+ {
+ Connection Connection
+ {
+ get;
+ set;
+ }
+
+ IReceiver<ReceivedPayload<MemoryStream>> Receiver
+ {
+ get;
+ set;
+ }
+
+ IoSender Sender
+ {
+ get;
+ set;
+ }
+
+
+ Stream Stream
+ {
+ get;
+ set;
+ }
+
+ TcpClient Socket
+ {
+ get;
+ set;
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/network/io/IoReceiver.cs b/dotnet/client-010/client/transport/network/io/IoReceiver.cs
new file mode 100644
index 0000000000..b60444fa29
--- /dev/null
+++ b/dotnet/client-010/client/transport/network/io/IoReceiver.cs
@@ -0,0 +1,185 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using System.IO;
+using System.Threading;
+using Logger = org.apache.qpid.transport.util.Logger;
+
+
+namespace org.apache.qpid.transport.network.io
+{
+ /// <summary>
+ /// IoReceiver
+ /// </summary>
+ public sealed class IoReceiver : IReceiver<ReceivedPayload<MemoryStream>>
+ {
+ private static readonly Logger log = Logger.Get(typeof(IoReceiver));
+ private readonly int m_bufferSize;
+ private readonly Stream m_bufStream;
+ private readonly int m_timeout;
+ private readonly Thread m_thread;
+ private bool m_closed;
+ private readonly Object m_objectLock = new object();
+
+ // the event raised when a buffer is read from the wire
+ event EventHandler<ReceivedPayload<MemoryStream>> ReceivedBuffer;
+ event EventHandler<ExceptionArgs> ExceptionReading;
+ event EventHandler ReceiverClosed;
+
+ event EventHandler<ReceivedPayload<MemoryStream>> IReceiver<ReceivedPayload<MemoryStream>>.Received
+ {
+ add
+ {
+ lock (m_objectLock)
+ {
+ ReceivedBuffer += value;
+ }
+ }
+ remove
+ {
+ lock (m_objectLock)
+ {
+ ReceivedBuffer -= value;
+ }
+ }
+ }
+
+ event EventHandler<ExceptionArgs> IReceiver<ReceivedPayload<MemoryStream>>.Exception
+ {
+ add
+ {
+ lock (m_objectLock)
+ {
+ ExceptionReading += value;
+ }
+ }
+ remove
+ {
+ lock (m_objectLock)
+ {
+ ExceptionReading -= value;
+ }
+ }
+ }
+
+ event EventHandler IReceiver<ReceivedPayload<MemoryStream>>.Closed
+ {
+ add
+ {
+ lock (m_objectLock)
+ {
+ ReceiverClosed += value;
+ }
+ }
+ remove
+ {
+ lock (m_objectLock)
+ {
+ ReceiverClosed -= value;
+ }
+ }
+ }
+
+ public IoReceiver(Stream stream, int bufferSize, int timeout)
+ {
+ m_bufferSize = bufferSize;
+ m_bufStream = stream;
+ m_timeout = timeout;
+ m_thread = new Thread(Go);
+ m_thread.Name = String.Format("IoReceiver - {0}", stream);
+ m_thread.IsBackground = true;
+ m_thread.Start();
+ }
+
+ public void Close()
+ {
+ Mutex mut = new Mutex();
+ mut.WaitOne();
+ if (!m_closed)
+ {
+ m_closed = true;
+ try
+ {
+ log.Debug("Receiver closing");
+ m_bufStream.Close();
+ m_thread.Join(m_timeout);
+ if (m_thread.IsAlive)
+ {
+ throw new TransportException("join timed out");
+ }
+ }
+ catch (ThreadInterruptedException e)
+ {
+ throw new TransportException(e);
+ }
+ catch (IOException e)
+ {
+ throw new TransportException(e);
+ }
+ }
+ mut.ReleaseMutex();
+ }
+
+ void Go()
+ {
+ // create a BufferedStream on top of the NetworkStream.
+ int threshold = m_bufferSize/2;
+ byte[] buffer = new byte[m_bufferSize];
+ try
+ {
+ int read;
+ int offset = 0;
+ ReceivedPayload<MemoryStream> payload = new ReceivedPayload<MemoryStream>();
+ while ((read = m_bufStream.Read(buffer, offset, m_bufferSize - offset)) > 0)
+ {
+ MemoryStream memStream = new MemoryStream(buffer, offset, read);
+ if (ReceivedBuffer != null)
+ {
+ // call the event
+ payload.Payload = memStream;
+ ReceivedBuffer(this, payload);
+ }
+ offset += read;
+ if (offset > threshold)
+ {
+ offset = 0;
+ buffer = new byte[m_bufferSize];
+ }
+ }
+ log.Debug("Receiver thread terminating");
+ }
+ catch (Exception t)
+ {
+ if (ExceptionReading != null)
+ {
+ ExceptionReading(this, new ExceptionArgs(t));
+ }
+ }
+ finally
+ {
+ if (ReceiverClosed != null)
+ {
+ ReceiverClosed(this, new EventArgs());
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/dotnet/client-010/client/transport/network/io/IoSSLTransport.cs b/dotnet/client-010/client/transport/network/io/IoSSLTransport.cs
new file mode 100644
index 0000000000..8b36693bc2
--- /dev/null
+++ b/dotnet/client-010/client/transport/network/io/IoSSLTransport.cs
@@ -0,0 +1,192 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+using System;
+using System.IO;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
+using org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.transport.network.io
+{
+ public sealed class IoSSLTransport : IIoTransport
+ {
+ // constants
+ private const int DEFAULT_READ_WRITE_BUFFER_SIZE = 64*1024;
+ private const int TIMEOUT = 60000;
+ private const int QUEUE_SIZE = 1000;
+ // props
+ private static readonly Logger log = Logger.Get(typeof (IoSSLTransport));
+ private Stream m_stream;
+ private IoSender m_sender;
+ private IReceiver<ReceivedPayload<MemoryStream>> m_receiver;
+ private TcpClient m_socket;
+ private Connection m_con;
+ private readonly bool _rejectUntrusted;
+
+ public static Connection Connect(String host, int port, string serverName, string certPath, bool rejectUntrusted, ConnectionDelegate conndel)
+ {
+ IIoTransport transport = new IoSSLTransport(host, port, serverName, certPath, rejectUntrusted, conndel);
+ return transport.Connection;
+ }
+
+ public IoSSLTransport(String host, int port, string serverName, string certPath, bool rejectUntrusted, ConnectionDelegate conndel)
+ {
+ _rejectUntrusted = rejectUntrusted;
+ CreateSocket(host, port, serverName, certPath);
+ Sender = new IoSender(this, QUEUE_SIZE, TIMEOUT);
+ Receiver = new IoReceiver(Stream, Socket.ReceiveBufferSize*2, TIMEOUT);
+ Assembler assembler = new Assembler();
+ InputHandler inputHandler = new InputHandler(InputHandler.State.PROTO_HDR);
+ Connection = new Connection(assembler, new Disassembler(Sender, 64*1024 - 1), conndel);
+ // Input handler listen to Receiver events
+ Receiver.Received += inputHandler.On_ReceivedBuffer;
+ // Assembler listen to inputhandler events
+ inputHandler.ReceivedEvent += assembler.On_ReceivedEvent;
+ // Connection listen to asembler protocol event
+ Receiver.Closed += Connection.On_ReceivedClosed;
+ assembler.Closed += Connection.On_ReceivedClosed;
+ Receiver.Exception += Connection.On_ReceivedException;
+ inputHandler.ExceptionProcessing += Connection.On_ReceivedException;
+ assembler.ReceivedEvent += Connection.On_ReceivedEvent;
+ }
+
+ public Connection Connection
+ {
+ get { return m_con; }
+ set { m_con = value; }
+ }
+
+ public IReceiver<ReceivedPayload<MemoryStream>> Receiver
+ {
+ get { return m_receiver; }
+ set { m_receiver = value; }
+ }
+
+ public IoSender Sender
+ {
+ get { return m_sender; }
+ set { m_sender = value; }
+ }
+
+
+ public Stream Stream
+ {
+ get { return m_stream; }
+ set { m_stream = value; }
+ }
+
+ public TcpClient Socket
+ {
+ get { return m_socket; }
+ set { m_socket = value; }
+ }
+
+ #region Private Support Functions
+
+ private void CreateSocket(String host, int port, string serverName, string certPath)
+ {
+ TcpClient socket;
+ try
+ {
+ socket = new TcpClient();
+ String noDelay = Environment.GetEnvironmentVariable("qpid.tcpNoDelay");
+ String writeBufferSize = Environment.GetEnvironmentVariable("qpid.writeBufferSize");
+ String readBufferSize = Environment.GetEnvironmentVariable("qpid.readBufferSize");
+ socket.NoDelay = noDelay != null && bool.Parse(noDelay);
+ socket.ReceiveBufferSize = readBufferSize == null
+ ? DEFAULT_READ_WRITE_BUFFER_SIZE
+ : int.Parse(readBufferSize);
+ socket.SendBufferSize = writeBufferSize == null
+ ? DEFAULT_READ_WRITE_BUFFER_SIZE
+ : int.Parse(writeBufferSize);
+
+ log.Debug("NoDelay : {0}", socket.NoDelay);
+ log.Debug("ReceiveBufferSize : {0}", socket.ReceiveBufferSize);
+ log.Debug("SendBufferSize : {0}", socket.SendBufferSize);
+ log.Debug("Openning connection with host : {0}; port: {1}", host, port);
+
+ socket.Connect(host, port);
+ Socket = socket;
+ }
+ catch (Exception e)
+ {
+ throw new TransportException("Error connecting to broker", e);
+ }
+ try
+ {
+ //Initializes a new instance of the SslStream class using the specified Stream, stream closure behavior, certificate validation delegate and certificate selection delegate
+ SslStream sslStream = new SslStream(socket.GetStream(), false, ValidateServerCertificate, LocalCertificateSelection);
+ if (certPath != null)
+ {
+ X509CertificateCollection col = new X509CertificateCollection();
+ X509Certificate cert = X509Certificate.CreateFromCertFile(certPath);
+ col.Add(cert);
+ sslStream.AuthenticateAsClient(serverName, col, SslProtocols.Default, true);
+ }
+ else
+ {
+ sslStream.AuthenticateAsClient(serverName);
+ }
+ Stream = sslStream;
+ }
+ catch (AuthenticationException e)
+ {
+ log.Warn("Exception: {0}", e.Message);
+ if (e.InnerException != null)
+ {
+ log.Warn("Inner exception: {0}", e.InnerException.Message);
+ }
+ socket.Close();
+ throw new TransportException("Authentication failed - closing the connection.");
+ }
+ }
+
+ // The following method is invoked by the RemoteCertificateValidationDelegate.
+ public bool ValidateServerCertificate(
+ object sender,
+ X509Certificate certificate,
+ X509Chain chain,
+ SslPolicyErrors sslPolicyErrors)
+ {
+ bool result = true;
+ if (sslPolicyErrors != SslPolicyErrors.None && _rejectUntrusted )
+ {
+ log.Warn("Certificate error: {0}", sslPolicyErrors);
+ // Do not allow this client to communicate with unauthenticated servers.
+ result = false;
+ }
+ return result;
+ }
+
+ public X509Certificate LocalCertificateSelection(
+ Object sender,
+ string targetHost,
+ X509CertificateCollection localCertificates,
+ X509Certificate remoteCertificate,
+ string[] acceptableIssuers
+ )
+ {
+ return remoteCertificate;
+ }
+
+ #endregion
+ }
+}
diff --git a/dotnet/client-010/client/transport/network/io/IoSender.cs b/dotnet/client-010/client/transport/network/io/IoSender.cs
new file mode 100644
index 0000000000..4491d2e98b
--- /dev/null
+++ b/dotnet/client-010/client/transport/network/io/IoSender.cs
@@ -0,0 +1,134 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+using System;
+using System.IO;
+using System.Threading;
+using common.org.apache.qpid.transport.util;
+using org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.transport.network.io
+{
+ public sealed class IoSender : IIoSender<MemoryStream>
+ {
+ private static readonly Logger log = Logger.Get(typeof (IoReceiver));
+ private readonly Stream bufStream;
+ private bool closed;
+ private readonly Mutex mutClosed = new Mutex();
+ private readonly CircularBuffer<byte[]> queue;
+ private readonly Thread thread;
+ private readonly int timeout;
+ private readonly MemoryStream _tobeSent = new MemoryStream();
+ public IoSender(IIoTransport transport, int queueSize, int timeout)
+ {
+ this.timeout = timeout;
+ bufStream = transport.Stream;
+ queue = new CircularBuffer<byte[]>(queueSize);
+ thread = new Thread(Go);
+ log.Debug("Creating IoSender thread");
+ thread.Name = String.Format("IoSender - {0}", transport.Socket) ;
+ thread.IsBackground = true;
+ thread.Start();
+ }
+
+ public void Send(MemoryStream str)
+ {
+ int pos = (int) str.Position;
+ str.Seek(0, SeekOrigin.Begin);
+ Send(str, pos);
+ }
+
+ public void Send(MemoryStream str, int size)
+ {
+ mutClosed.WaitOne();
+ if (closed)
+ {
+ throw new TransportException("sender is Closed");
+ }
+ mutClosed.ReleaseMutex();
+ byte[] buf = new byte[size];
+ str.Read(buf, 0, size);
+ _tobeSent.Write(buf, 0, size);
+ }
+
+ public void Flush()
+ {
+ int length = (int)_tobeSent.Position;
+ byte[] buf = new byte[length];
+ _tobeSent.Seek(0, SeekOrigin.Begin);
+ _tobeSent.Read(buf, 0, length);
+ queue.Enqueue(buf);
+ // bufStream.Write(buf, 0, length);
+ // _tobeSent = new MemoryStream();
+ // _writer.Write(buf, 0, length);
+ // _writer.Flush();
+ _tobeSent.Seek(0, SeekOrigin.Begin);
+ }
+
+ public void Close()
+ {
+ log.Debug("Closing Sender");
+ mutClosed.WaitOne();
+ if (!closed)
+ {
+ try
+ {
+ closed = true;
+ queue.Close();
+ thread.Join(timeout);
+ if (thread.IsAlive)
+ {
+ throw new TransportException("join timed out");
+ }
+ }
+ catch (ThreadInterruptedException e)
+ {
+ throw new TransportException(e);
+ }
+ catch (IOException e)
+ {
+ throw new TransportException(e);
+ }
+ }
+ mutClosed.ReleaseMutex();
+ }
+
+ private void Go()
+ {
+ while (! closed)
+ {
+ //MemoryStream st = queue.Dequeue();
+ byte[] st = queue.Dequeue();
+ if (st != null)
+ {
+ try
+ {
+ // int length = (int) st.Length;
+ // byte[] buf = new byte[length];
+ // st.Read(buf, 0, length);
+ bufStream.Write(st, 0, st.Length);
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/network/io/IoTransport.cs b/dotnet/client-010/client/transport/network/io/IoTransport.cs
new file mode 100644
index 0000000000..483e5428b8
--- /dev/null
+++ b/dotnet/client-010/client/transport/network/io/IoTransport.cs
@@ -0,0 +1,141 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+using System;
+using System.IO;
+using System.Net.Sockets;
+using org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.transport.network.io
+{
+ /// <summary>
+ /// This class provides a socket based transport using sync io classes.
+ ///
+ /// The following params are configurable via JVM arguments
+ /// TCP_NO_DELAY - qpid.tcpNoDelay
+ /// SO_RCVBUF - qpid.readBufferSize
+ /// SO_SNDBUF - qpid.writeBufferSize
+ /// </summary>
+ public sealed class IoTransport : IIoTransport
+ {
+ // constants
+ private const int DEFAULT_READ_WRITE_BUFFER_SIZE = 64*1024;
+ private const int TIMEOUT = 60000;
+ private const int QUEUE_SIZE = 1000;
+ // props
+ private static readonly Logger log = Logger.Get(typeof (IoTransport));
+ private Stream m_stream;
+ private IoSender m_sender;
+ private IReceiver<ReceivedPayload<MemoryStream>> m_receiver;
+ private TcpClient m_socket;
+ private Connection m_con;
+
+ public static Connection Connect(String host, int port, ConnectionDelegate conndel)
+ {
+ IoTransport transport = new IoTransport(host, port, conndel);
+ return transport.Connection;
+ }
+
+ public IoTransport(String host, int port, ConnectionDelegate conndel)
+ {
+ CreateSocket(host, port);
+ Sender = new IoSender(this, QUEUE_SIZE, TIMEOUT);
+ Receiver = new IoReceiver(Stream, Socket.ReceiveBufferSize * 2, TIMEOUT);
+ Assembler assembler = new Assembler();
+ InputHandler inputHandler = new InputHandler(InputHandler.State.PROTO_HDR);
+ Connection = new Connection(assembler, new Disassembler(Sender, 64 * 1024 - 1), conndel);
+ // Input handler listen to Receiver events
+ Receiver.Received += inputHandler.On_ReceivedBuffer;
+ // Assembler listen to inputhandler events
+ inputHandler.ReceivedEvent += assembler.On_ReceivedEvent;
+ // Connection listen to asembler protocol event
+ Receiver.Closed += Connection.On_ReceivedClosed;
+ assembler.Closed += Connection.On_ReceivedClosed;
+ Receiver.Exception += Connection.On_ReceivedException;
+ inputHandler.ExceptionProcessing += Connection.On_ReceivedException;
+ assembler.ReceivedEvent += Connection.On_ReceivedEvent;
+ }
+
+ public Connection Connection
+ {
+ get { return m_con; }
+ set { m_con = value; }
+ }
+
+ public IReceiver<ReceivedPayload<MemoryStream>> Receiver
+ {
+ get { return m_receiver; }
+ set { m_receiver = value; }
+ }
+
+ public IoSender Sender
+ {
+ get { return m_sender; }
+ set { m_sender = value; }
+ }
+
+
+ public Stream Stream
+ {
+ get { return m_stream; }
+ set { m_stream = value; }
+ }
+
+ public TcpClient Socket
+ {
+ get { return m_socket; }
+ set { m_socket = value; }
+ }
+
+ #region Private Support Functions
+
+ private void CreateSocket(String host, int port)
+ {
+ try
+ {
+ TcpClient socket = new TcpClient();
+ String noDelay = Environment.GetEnvironmentVariable("qpid.tcpNoDelay");
+ String writeBufferSize = Environment.GetEnvironmentVariable("qpid.writeBufferSize");
+ String readBufferSize = Environment.GetEnvironmentVariable("qpid.readBufferSize");
+ socket.NoDelay = noDelay != null && bool.Parse(noDelay);
+ socket.ReceiveBufferSize = readBufferSize == null ? DEFAULT_READ_WRITE_BUFFER_SIZE : int.Parse(readBufferSize);
+ socket.SendBufferSize = writeBufferSize == null ? DEFAULT_READ_WRITE_BUFFER_SIZE : int.Parse(writeBufferSize);
+
+ log.Debug("NoDelay : {0}", socket.NoDelay);
+ log.Debug("ReceiveBufferSize : {0}", socket.ReceiveBufferSize);
+ log.Debug("SendBufferSize : {0}", socket.SendBufferSize);
+ log.Debug("Openning connection with host : {0}; port: {1}", host, port);
+
+ socket.Connect(host, port);
+ Socket = socket;
+ Stream = socket.GetStream();
+ }
+ catch (SocketException e)
+ {
+ Console.WriteLine(e.StackTrace);
+ throw new TransportException("Error connecting to broker", e);
+ }
+ catch (IOException e)
+ {
+ throw new TransportException("Error connecting to broker", e);
+ }
+ }
+
+ #endregion
+ }
+} \ No newline at end of file
diff --git a/dotnet/client-010/client/transport/util/ByteEncoder.cs b/dotnet/client-010/client/transport/util/ByteEncoder.cs
new file mode 100644
index 0000000000..873ca75688
--- /dev/null
+++ b/dotnet/client-010/client/transport/util/ByteEncoder.cs
@@ -0,0 +1,218 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+
+namespace org.apache.qpid.transport.util
+{
+ public static class ByteEncoder
+ {
+ #region Endian conversion helper routines
+ /// <summary>
+ /// Returns the value encoded in Big Endian (PPC, XDR) format.
+ /// </summary>
+ /// <param name="value">Value to encode.</param>
+ /// <returns>Big-endian encoded value.</returns>
+ public static Int32 GetBigEndian(Int32 value)
+ {
+ if (BitConverter.IsLittleEndian)
+ {
+ return SwapByteOrder(value);
+ }
+ return value;
+ }
+
+ /// <summary>
+ /// Returns the value encoded in Big Endian (PPC, XDR) format.
+ /// </summary>
+ /// <param name="value">Value to encode.</param>
+ /// <returns>Big-endian encoded value.</returns>
+ public static UInt16 GetBigEndian(UInt16 value)
+ {
+ if (BitConverter.IsLittleEndian)
+ {
+ return SwapByteOrder(value);
+ }
+ return value;
+ }
+
+ /// <summary>
+ /// Returns the value encoded in Big Endian (PPC, XDR) format.
+ /// </summary>
+ /// <param name="value">Value to encode.</param>
+ /// <returns>Big-endian encoded value.</returns>
+ public static UInt32 GetBigEndian(UInt32 value)
+ {
+ if (BitConverter.IsLittleEndian)
+ {
+ return SwapByteOrder(value);
+ }
+ return value;
+ }
+
+ /// <summary>
+ /// Returns the value encoded in Big Endian (PPC, XDR) format.
+ /// </summary>
+ /// <param name="value">Value to encode.</param>
+ /// <returns>Big-endian encoded value.</returns>
+ public static long GetBigEndian(long value)
+ {
+ if (BitConverter.IsLittleEndian)
+ {
+ return SwapByteOrder(value);
+ }
+ return value;
+ }
+
+ public static double GetBigEndian(double value)
+ {
+ if (BitConverter.IsLittleEndian)
+ {
+ return SwapByteOrder(value);
+ }
+ return value;
+ }
+
+ /// <summary>
+ /// Returns the value encoded in Little Endian (x86, NDR) format.
+ /// </summary>
+ /// <param name="value">Value to encode.</param>
+ /// <returns>Little-endian encoded value.</returns>
+ public static Int32 GetLittleEndian(Int32 value)
+ {
+ if (BitConverter.IsLittleEndian)
+ {
+ return value;
+ }
+ return SwapByteOrder(value);
+ }
+
+ /// <summary>
+ /// Returns the value encoded in Little Endian (x86, NDR) format.
+ /// </summary>
+ /// <param name="value">Value to encode.</param>
+ /// <returns>Little-endian encoded value.</returns>
+ public static UInt32 GetLittleEndian(UInt32 value)
+ {
+ if (BitConverter.IsLittleEndian)
+ {
+ return value;
+ }
+ return SwapByteOrder(value);
+ }
+
+ /// <summary>
+ /// Returns the value encoded in Little Endian (x86, NDR) format.
+ /// </summary>
+ /// <param name="value">Value to encode.</param>
+ /// <returns>Little-endian encoded value.</returns>
+ public static UInt16 GetLittleEndian(UInt16 value)
+ {
+ if (BitConverter.IsLittleEndian)
+ {
+ return value;
+ }
+ return SwapByteOrder(value);
+ }
+
+ /// <summary>
+ /// Returns the value encoded in Little Endian (x86, NDR) format.
+ /// </summary>
+ /// <param name="value">Value to encode.</param>
+ /// <returns>Little-endian encoded value.</returns>
+ public static long GetLittleEndian(long value)
+ {
+ if (BitConverter.IsLittleEndian)
+ {
+ return value;
+ }
+ return SwapByteOrder(value);
+ }
+
+ public static double GetLittleEndian(double value)
+ {
+ if (BitConverter.IsLittleEndian)
+ {
+ return value;
+ }
+ return SwapByteOrder(value);
+ }
+
+ /// <summary>
+ /// Swaps the Byte order of an <see cref="Int32"/>.
+ /// </summary>
+ /// <param name="value"><see cref="Int32"/> to swap the bytes of.</param>
+ /// <returns>Byte order swapped <see cref="Int32"/>.</returns>
+ private static Int32 SwapByteOrder(Int32 value)
+ {
+ Int32 swapped = (Int32)((0x000000FF) & (value >> 24)
+ | (0x0000FF00) & (value >> 8)
+ | (0x00FF0000) & (value << 8)
+ | (0xFF000000) & (value << 24));
+ return swapped;
+ }
+
+ /// <summary>
+ /// Swaps the byte order of a <see cref="UInt16"/>.
+ /// </summary>
+ /// <param name="value"><see cref="UInt16"/> to swap the bytes of.</param>
+ /// <returns>Byte order swapped <see cref="UInt16"/>.</returns>
+ private static UInt16 SwapByteOrder(UInt16 value)
+ {
+ return (UInt16)((0x00FF & (value >> 8))
+ | (0xFF00 & (value << 8)));
+ }
+
+ /// <summary>
+ /// Swaps the byte order of a <see cref="UInt32"/>.
+ /// </summary>
+ /// <param name="value"><see cref="UInt32"/> to swap the bytes of.</param>
+ /// <returns>Byte order swapped <see cref="UInt32"/>.</returns>
+ private static UInt32 SwapByteOrder(UInt32 value)
+ {
+ UInt32 swapped = ((0x000000FF) & (value >> 24)
+ | (0x0000FF00) & (value >> 8)
+ | (0x00FF0000) & (value << 8)
+ | (0xFF000000) & (value << 24));
+ return swapped;
+ }
+
+ /// <summary>
+ /// Swaps the byte order of a <see cref="Double"/> (double precision IEEE 754)
+ /// </summary>
+ /// <param name="value"><see cref="Double"/> to swap.</param>
+ /// <returns>Byte order swapped <see cref="Double"/> value.</returns>
+ private static long SwapByteOrder(long value)
+ {
+ Byte[] buffer = BitConverter.GetBytes(value);
+ Array.Reverse(buffer, 0, buffer.Length);
+ return BitConverter.ToInt64(buffer, 0);
+ }
+
+ private static double SwapByteOrder(double value)
+ {
+ Byte[] buffer = BitConverter.GetBytes(value);
+ Array.Reverse(buffer, 0, buffer.Length);
+ return BitConverter.ToDouble(buffer,0) ;
+ }
+ #endregion
+ }
+
+}
diff --git a/dotnet/client-010/client/transport/util/CircularBuffer.cs b/dotnet/client-010/client/transport/util/CircularBuffer.cs
new file mode 100644
index 0000000000..00d7b20d4c
--- /dev/null
+++ b/dotnet/client-010/client/transport/util/CircularBuffer.cs
@@ -0,0 +1,132 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.Threading;
+
+namespace common.org.apache.qpid.transport.util
+{
+ public class CircularBuffer<T>
+ {
+ private readonly T[] buffer;
+ private Int32 nrp, nwp;
+ private readonly Int32 len;
+ private Int32 countValue;
+ private readonly Int32 add;
+
+
+ /// <summary>
+ /// Constructor creates N=len element
+ /// Circular Buffer that olds MemoryStream
+ /// </summary>
+ public CircularBuffer(Int32 len)
+ {
+ buffer = new T[len];
+ this.len = len;
+ add = 1 - len;
+ nrp = 0;
+ nwp = 0;
+ countValue = 0;
+ }
+
+
+ public void Enqueue(T t)
+ {
+ lock (this)
+ {
+ if (countValue >= (len - 1))
+ {
+ // wait for room to be available
+ Monitor.Wait(this);
+ }
+ bool notifyDequeue = countValue <= 0;
+ Load(t);
+ if (notifyDequeue) //notifyDequeue)
+ {
+ Monitor.PulseAll(this);
+ }
+ }
+ }
+
+
+ public T Dequeue()
+ {
+ lock (this)
+ {
+ if (countValue <= 0)
+ {
+ Monitor.Wait(this);
+ }
+ bool notifyEnqueue = countValue >= (len - 1);
+ T temp = Get();
+ if (notifyEnqueue) //notifyEnqueue)
+ {
+ Monitor.PulseAll(this);
+ }
+ return temp;
+ }
+ }
+
+ public void Close()
+ {
+ nrp = 0;
+ nwp = 0;
+ countValue = 0;
+ Array.Clear(buffer, 0, len);
+ lock (this)
+ {
+ Monitor.PulseAll(this);
+ }
+ }
+
+ #region Private Support Functions
+
+ private void Load(T t)
+ {
+ Int32 i = nwp;
+ buffer[i] = t;
+ i += add;
+ if (i < 0) i += len;
+ nwp = i;
+ UpdateCount();
+ }
+
+ private void UpdateCount()
+ {
+ countValue = nwp - nrp;
+ if (countValue <= 0 )
+ countValue += len; // modulo buffer size
+ }
+
+ private T Get()
+ {
+ Int32 i = nrp;
+ T temp = buffer[i];
+ i += add;
+ if (i < 0) i += len;
+ nrp = i;
+ countValue--;
+ return (temp);
+ }
+
+ #endregion
+ }
+}
diff --git a/dotnet/client-010/client/transport/util/Functions.cs b/dotnet/client-010/client/transport/util/Functions.cs
new file mode 100644
index 0000000000..eee3848386
--- /dev/null
+++ b/dotnet/client-010/client/transport/util/Functions.cs
@@ -0,0 +1,41 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+namespace org.apache.qpid.transport.util
+{
+
+ /// <summary>
+ /// Functions
+ /// </summary>
+
+ public class Functions
+ {
+ public static sbyte Lsb(int i)
+ {
+ return (sbyte) (0xFF & i);
+ }
+
+ public static sbyte Lsb(long l)
+ {
+ return (sbyte) (0xFF & l);
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/util/Logger.cs b/dotnet/client-010/client/transport/util/Logger.cs
new file mode 100644
index 0000000000..f889fe2aab
--- /dev/null
+++ b/dotnet/client-010/client/transport/util/Logger.cs
@@ -0,0 +1,114 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using log4net;
+
+namespace org.apache.qpid.transport.util
+{
+
+ /// <summary> Logger
+ ///
+ /// </summary>
+
+ public sealed class Logger
+ {
+ private readonly ILog log;
+
+ public static Logger Get(Type type)
+ {
+ return new Logger(LogManager.GetLogger(type));
+ }
+
+ private Logger(ILog log)
+ {
+ this.log = log;
+ }
+
+ public bool IsDebugEnabled()
+ {
+ return log.IsDebugEnabled;
+ }
+
+ public void Debug(String message, params Object[] args)
+ {
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(String.Format(message, args));
+ }
+ }
+
+ public void Debug(Exception t, String message, params Object[] args)
+ {
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(String.Format(message, args), t);
+ }
+ }
+
+ public void Error(String message, params Object[] args)
+ {
+ if (log.IsErrorEnabled)
+ {
+ log.Error(String.Format(message, args));
+ }
+ }
+
+ public void Error(Exception t, String message, params Object[] args)
+ {
+ if (log.IsErrorEnabled)
+ {
+ log.Error(String.Format(message, args), t);
+ }
+ }
+
+ public void Warn(String message, params Object[] args)
+ {
+ if (log.IsWarnEnabled)
+ {
+ log.Warn(String.Format(message, args));
+ }
+ }
+
+ public void Warn(Exception t, String message, params Object[] args)
+ {
+ if (log.IsWarnEnabled)
+ {
+ log.Warn(String.Format(message, args), t);
+ }
+ }
+
+ public void Info(String message, params Object[] args)
+ {
+ if (log.IsInfoEnabled)
+ {
+ log.Info(String.Format(message, args));
+ }
+ }
+
+ public void Info(Exception t, String message, params Object[] args)
+ {
+ if (log.IsInfoEnabled)
+ {
+ log.Info(String.Format(message, args), t);
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/util/ResultFuture.cs b/dotnet/client-010/client/transport/util/ResultFuture.cs
new file mode 100644
index 0000000000..0de2b27656
--- /dev/null
+++ b/dotnet/client-010/client/transport/util/ResultFuture.cs
@@ -0,0 +1,80 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Threading;
+using org.apache.qpid.transport;
+using org.apache.qpid.transport.util;
+
+namespace common.org.apache.qpid.transport.util
+{
+ public class ResultFuture : IFuture
+ {
+ const long _timeout = 60000;
+ private Struct _result;
+ private Session _session;
+ private static readonly Logger log = Logger.Get(typeof(ResultFuture));
+
+ public Struct Get(long timeout)
+ {
+ lock (this)
+ {
+ DateTime start = DateTime.Now;
+ long elapsed = 0;
+ while (! _session.IsClosed && timeout - elapsed > 0 && _result == null)
+ {
+ log.Debug("{0} waiting for result: {1}", _session, this );
+ Monitor.Wait(this, (int) (timeout - elapsed));
+ elapsed = (long) (DateTime.Now.Subtract(start)).TotalMilliseconds;
+ }
+ }
+ if( _session.IsClosed )
+ {
+ throw new SessionException(_session.GetExceptions());
+ }
+ return _result;
+ }
+
+ public Struct Result
+ {
+ get { return Get(_timeout); }
+ set
+ {
+ lock (this)
+ {
+ _result = value;
+ Monitor.PulseAll(this);
+ }
+ }
+ }
+
+ public Session Session
+ {
+ set { _session = value; }
+ }
+
+ public override String ToString()
+ {
+ return String.Format("Future({0})", _result);
+ }
+
+ }
+}
diff --git a/dotnet/client-010/client/transport/util/Serial.cs b/dotnet/client-010/client/transport/util/Serial.cs
new file mode 100644
index 0000000000..874097084a
--- /dev/null
+++ b/dotnet/client-010/client/transport/util/Serial.cs
@@ -0,0 +1,94 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+namespace org.apache.qpid.transport.util
+{
+ /// <summary>
+ /// This class provides basic serial number comparisons as defined in
+ /// RFC 1982.
+ /// </summary>
+ public class Serial
+ {
+ ///
+ ///
+ ///Compares two numbers using serial arithmetic.
+ ///
+ /// param s1 the first serial number
+ /// param s2 the second serial number
+ ///
+ /// return a negative integer, zero, or a positive integer as the
+ /// first argument is less than, equal to, or greater than the
+ /// second
+ ///
+ public static int Compare(int s1, int s2)
+ {
+ return s1 - s2;
+ }
+
+ public static bool Lt(int s1, int s2)
+ {
+ return Compare(s1, s2) < 0;
+ }
+
+ public static bool Le(int s1, int s2)
+ {
+ return Compare(s1, s2) <= 0;
+ }
+
+ public static bool Gt(int s1, int s2)
+ {
+ return Compare(s1, s2) > 0;
+ }
+
+ public static bool Ge(int s1, int s2)
+ {
+ return Compare(s1, s2) >= 0;
+ }
+
+ public static bool Eq(int s1, int s2)
+ {
+ return s1 == s2;
+ }
+
+ public static int Min(int s1, int s2)
+ {
+ if (Lt(s1, s2))
+ {
+ return s1;
+ }
+ else
+ {
+ return s2;
+ }
+ }
+
+ public static int Max(int s1, int s2)
+ {
+ if (Gt(s1, s2))
+ {
+ return s1;
+ }
+ else
+ {
+ return s2;
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/client/transport/util/UUID.cs b/dotnet/client-010/client/transport/util/UUID.cs
new file mode 100644
index 0000000000..07a3d267a5
--- /dev/null
+++ b/dotnet/client-010/client/transport/util/UUID.cs
@@ -0,0 +1,129 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+
+namespace org.apache.qpid.transport.util
+{
+ public class UUID
+ {
+ private long _mostSigBits;
+ private long _leastSigBits;
+ private static readonly Random _random = new Random();
+ private static readonly object _randomLock = new object();
+
+
+ public UUID(long mostSigBits, long leastSigBits)
+ {
+ _mostSigBits = mostSigBits;
+ _leastSigBits = leastSigBits;
+ }
+
+ public long MostSignificantBits
+ {
+ get { return _mostSigBits; }
+ set { _mostSigBits = value; }
+ }
+
+ public long LeastSignificantBits
+ {
+ get { return _leastSigBits; }
+ set { _leastSigBits = value; }
+ }
+
+ internal UUID(byte[] r)
+ {
+ MostSignificantBits = 0;
+ LeastSignificantBits = 0;
+ for (int i = 0; i < 8; i++)
+ MostSignificantBits = (MostSignificantBits << 8) | (r[i] & 0xff);
+ for (int i = 8; i < 16; i++)
+ LeastSignificantBits = (LeastSignificantBits << 8) | (r[i] & 0xff);
+ }
+
+ public static UUID RandomUuid()
+ {
+ byte[] randomBytes = new byte[16];
+ lock (_randomLock)
+ {
+ _random.NextBytes(randomBytes);
+ }
+
+ randomBytes[6] &= 0x0f;
+ randomBytes[6] |= 0x40;
+ randomBytes[8] &= 0x3f;
+ randomBytes[8] |= 0x80;
+
+ return new UUID(randomBytes);
+ }
+
+
+ public override String ToString()
+ {
+ return (Digits(_mostSigBits >> 32, 8) + "-" +
+ Digits(_mostSigBits >> 16, 4) + "-" +
+ Digits(_mostSigBits, 4) + "-" +
+ Digits(_leastSigBits >> 48, 4) + "-" +
+ Digits(_leastSigBits, 12));
+ }
+
+ private static String Digits(long val, int digits)
+ {
+ long hi = 1L << (digits * 4);
+ return Convert.ToString((hi | (val & (hi - 1))), 16);
+ }
+
+ #region equality
+ public bool Equals(UUID other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return other._mostSigBits == _mostSigBits && other._leastSigBits == _leastSigBits;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != typeof (UUID)) return false;
+ return Equals((UUID) obj);
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ return (_mostSigBits.GetHashCode()*397) ^ _leastSigBits.GetHashCode();
+ }
+ }
+
+ public static bool operator ==(UUID left, UUID right)
+ {
+ return Equals(left, right);
+ }
+
+ public static bool operator !=(UUID left, UUID right)
+ {
+ return !Equals(left, right);
+ }
+ #endregion
+ }
+}
diff --git a/dotnet/client-010/default.build b/dotnet/client-010/default.build
new file mode 100644
index 0000000000..eb6ee371f7
--- /dev/null
+++ b/dotnet/client-010/default.build
@@ -0,0 +1,275 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="Qpid.NET" default="build">
+
+ <!-- Determines the formatter to use to format output of test results. -->
+ <property name="nant.formatter" value="Plain" />
+
+ <!-- Determines whether a 'debug' or 'release' build is to be done. Defaults to 'debug' -->
+ <property name="build.config" value="debug" />
+
+ <!-- Sets build properties consistently accross all assemblies in the project. -->
+ <property name="build.version.major" value="0"/>
+ <property name="build.version.minor" value="5"/>
+ <property name="build.version.build" value="0"/>
+ <property name="build.version.revision" value="0"/>
+ <property name="build.company" value="Apache Software Foundation"/>
+ <property name="build.copyright" value="Apache Software Foundation"/>
+ <property name="build.description" value="Built from svn revision number: "/>
+
+ <!-- Fileset with build files for each 'core' assembly. -->
+ <fileset id="src.builds">
+ <include name="client/default.build" />
+ <include name="management/console/default.build" />
+ <include name="demo/default.build" />
+ </fileset>
+
+ <!-- Fileset with build files for each 'core' assembly. -->
+ <fileset id="examples.builds">
+ <include name="examples/request-response/example-request-response-Client/default.build" />
+ <include name="examples/request-response/example-request-response-Server/default.build" />
+ <include name="examples/direct/example-direct-Listener/default.build" />
+ <include name="examples/direct/example-direct-producer/default.build" />
+ <include name="examples/fanout/example-fanout-Listener/default.build" />
+ <include name="examples/fanout/example-fanout-Producer/default.build" />
+ <include name="examples/pub-sub/example-pub-sub-Listener/default.build" />
+ <include name="examples/pub-sub/example-pub-sub-Publisher/default.build" />
+ </fileset>
+
+ <!-- Fileset with build files for 'integration' test assemblies. -->
+ <fileset id="tests.builds">
+ <include name="test/default.build" />
+ </fileset>
+
+ <!-- Fileset with build files for 'performence' test assemblies. -->
+ <fileset id="perftest.builds">
+ <include name="perftest/default.build" />
+ </fileset>
+
+ <!-- Prepare environment for a debug build. -->
+ <target name="debug">
+ <property name="build.debug" value="true" />
+ <property name="build.defines" value="DEBUG;TRACE"/>
+ </target>
+
+ <!-- Prepare environment for a release build. -->
+ <target name="release">
+ <property name="build.debug" value="false" />
+ <property name="build.defines" value=""/>
+ </target>
+
+ <!-- Prepare environment for build. -->
+ <target name="init">
+ <property name="base.dir" value="${project::get-base-directory()}" />
+ <property name="build.dir" value="${base.dir}/bin/${framework::get-target-framework()}/${build.config}" />
+ <call target="${build.config}" />
+ </target>
+
+ <!-- Cleans up the build output directory. -->
+ <target name="clean" depends="init">
+ <delete dir="${build.dir}" failonerror="false" />
+ </target>
+
+ <!-- Runs 'svnversion' to get the repository revision into the build property 'build.svnversion'. -->
+ <target name="svnversion" description="Runs svnversion to get the current repository version into a build script property.">
+ <exec program="svnversion" output="svnversion_tmp.txt">
+ <arg value="-n"/>
+ </exec>
+
+ <loadfile file="svnversion_tmp.txt" property="build.svnversion"/>
+ <delete file="svnversion_tmp.txt"/>
+
+ <!-- For some competely retarted reason the '-n' parameter to svnversion doesn't really work under windows...
+ Here is some code to strip the unwanted newlines. -->
+ <script language="C#">
+ <code><![CDATA[
+ public static void ScriptMain(Project project)
+ {
+ project.Properties["build.svnversion"] = project.Properties["build.svnversion"].Trim("\n\r".ToCharArray());
+ }
+ ]]>
+ </code>
+ </script>
+
+ </target>
+
+ <!-- Performs a regex find-and-replace on assembly info files, substituting fields defined as build properties. -->
+ <target name="setversion" description="Stamp the version info onto assemblyinfo.cs files" depends="svnversion">
+
+ <echo>build.svnversion = ${build.svnversion}</echo>
+
+ <foreach item="File" property="filename">
+ <in>
+ <items basedir=".">
+ <include name="**\AssemblyInfo.cs"></include>
+ </items>
+ </in>
+ <do>
+ <script language="C#">
+ <code><![CDATA[
+ public static void ScriptMain(Project project)
+ {
+ // Read in the entire file to perform the substitution in.
+ StreamReader reader = new StreamReader(project.Properties["filename"]);
+ string contents = reader.ReadToEnd();
+ reader.Close();
+
+ // Substitute the version numbers.
+ string replacement = string.Format("[assembly: AssemblyVersion(\"{0}.{1}.{2}.{3}\")]",
+ project.Properties["build.version.major"],
+ project.Properties["build.version.minor"],
+ project.Properties["build.version.build"],
+ project.Properties["build.version.revision"]);
+ contents = Regex.Replace(contents, @"\[assembly: AssemblyVersion\("".*""\)\]", replacement);
+
+ // Substitute the company name and copyright.
+ replacement = string.Format("[assembly: AssemblyCompany(\"{0}\")]",
+ project.Properties["build.company"]);
+ contents = Regex.Replace(contents, @"\[assembly: AssemblyCompany\("".*""\)\]", replacement);
+
+ replacement = string.Format("[assembly: AssemblyCopyright(\"{0}\")]",
+ project.Properties["build.copyright"]);
+ contents = Regex.Replace(contents, @"\[assembly: AssemblyCopyright\("".*""\)\]", replacement);
+
+ // Update the description.
+ //replacement = string.Format("[assembly: AssemblyDescription(\"{0} {1}\")]",
+ // project.Properties["build.description"],
+ // project.Properties["build.svnversion"]);
+ replacement = string.Format("[assembly: AssemblyDescription(\"{0}\")]",
+ project.Properties["build.description"]);
+ contents = Regex.Replace(contents, @"\[assembly: AssemblyDescription\("".*""\)\]", replacement);
+
+ // Write out the file with the substituted version.
+ StreamWriter writer = new StreamWriter(project.Properties["filename"], false);
+ writer.Write(contents);
+ writer.Close();
+ }
+ ]]>
+ </code>
+ </script>
+ </do>
+ </foreach>
+ </target>
+
+ <!-- Do the build. -->
+ <target name="build" depends="init, setversion">
+ <echo message="Building all modules including tests."/>
+
+ <!-- Make sure output folder exists. -->
+ <mkdir dir="${build.dir}" />
+
+ <echo message="Output folder: ${build.dir}"/>
+
+ <!-- copy reference assemblies over to the output dir -->
+ <copy todir="${build.dir}" file="lib/log4net/log4net.dll"/>
+ <copy todir="${build.dir}" file="lib/nunit/nunit.framework.dll"/>
+ <copy todir="${build.dir}" file="lib/plossum/C5.dll"/>
+ <copy todir="${build.dir}" file="lib/plossum/Plossum CommandLine.dll"/>
+
+ <!-- Compile assemblies. -->
+ <nant target="build">
+ <buildfiles refid="src.builds" />
+ </nant>
+
+ <!-- Compile test assemblies. -->
+ <nant target="build">
+ <buildfiles refid="examples.builds" />
+ </nant>
+
+ <!-- Compile test assemblies. -->
+ <nant target="build">
+ <buildfiles refid="tests.builds" />
+ </nant>
+
+ <!-- Compile test assemblies. -->
+ <nant target="build">
+ <buildfiles refid="perftest.builds" />
+ </nant>
+
+ <!-- copy config files over to the output dir -->
+ <copy todir="${build.dir}" file="test/Qpid Test.dll.config"/>
+ <copy todir="${build.dir}" file="log.xml"/>
+
+
+ </target>
+
+ <!-- Runs all 'pure unit' tests. -->
+ <target name="test" depends="build">
+ <echo message="Running all pure unit tests."/>
+ <nant target="test">
+ <buildfiles refid="tests.builds" />
+ </nant>
+ </target>
+
+ <!-- Creates a release package. -->
+ <target name="release-pkg">
+ <echo message="Building and packaging a release."/>
+
+ <call target="clean"/>
+ <call target="build"/>
+
+ <property name="build.date" value="${datetime::now()}"/>
+
+ <zip zipfile="${build.dir}/Qpid.NET-${framework::get-target-framework()}-${datetime::get-year(build.date)}${datetime::get-month(build.date)}${datetime::get-day(build.date)}.zip">
+ <fileset basedir="${build.dir}" prefix="qpid/lib">
+ <include name="**/*.*"/>
+ <exclude name="**/*.tests.*"/>
+ <exclude name="**/example*.*"/>
+ <exclude name="**/nunit.framework.dll"/>
+ <exclude name="**/*.exe"/>
+ <exclude name="**/*.pdb"/>
+ </fileset>
+
+ <fileset basedir="${build.dir}" prefix="qpid/examples/direct">
+ <include name="**/example*direct*.exe"/>
+ </fileset>
+
+ <fileset basedir="${build.dir}" prefix="qpid/examples/fanout">
+ <include name="**/example*fanout*.exe"/>
+ </fileset>
+
+ <fileset basedir="${build.dir}" prefix="qpid/examples/pub-sub">
+ <include name="**/example*pub-sub*.exe"/>
+ </fileset>
+
+ <fileset basedir="${build.dir}" prefix="qpid/examples/request-response">
+ <include name="**/example*request-response*.exe"/>
+ </fileset>
+
+ <fileset basedir="${base.dir}/.." prefix="qpid">
+ <include name="LICENSE.txt"/>
+ <include name="NOTICE.txt"/>
+ <include name="RELEASE_NOTES.txt"/>
+ <include name="DISCLAIMER"/>
+ </fileset>
+
+
+ <fileset basedir="${base.dir}" prefix="qpid">
+ <include name="README.txt"/>
+ </fileset>
+ </zip>
+ </target>
+
+</project>
+
+
diff --git a/dotnet/client-010/demo/Demo.csproj b/dotnet/client-010/demo/Demo.csproj
new file mode 100644
index 0000000000..6b1c36c633
--- /dev/null
+++ b/dotnet/client-010/demo/Demo.csproj
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{E4C46FBC-7560-406D-BFEF-CA010E584DF4}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>demo</RootNamespace>
+ <AssemblyName>Qpid Demo</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ <StartupObject>
+ </StartupObject>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\lib\log4net\log4net.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.configuration" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Deployment" />
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Windows.Forms" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="*.cs" />
+ <EmbeddedResource Include="Properties\Resources.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+ <SubType>Designer</SubType>
+ </EmbeddedResource>
+ <Compile Include="Properties\Resources.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DependentUpon>Resources.resx</DependentUpon>
+ <DesignTime>True</DesignTime>
+ </Compile>
+ <None Include="..\App.config">
+ <Link>App.config</Link>
+ </None>
+ <None Include="Properties\Settings.settings">
+ <Generator>SettingsSingleFileGenerator</Generator>
+ <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+ </None>
+ <Compile Include="Properties\Settings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DependentUpon>Settings.settings</DependentUpon>
+ <DesignTimeSharedInput>True</DesignTimeSharedInput>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\client\Client.csproj">
+ <Project>{B911FFD7-754F-4735-A188-218D5065BE79}</Project>
+ <Name>Client</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/dotnet/client-010/demo/Program.cs b/dotnet/client-010/demo/Program.cs
new file mode 100644
index 0000000000..aa748544a0
--- /dev/null
+++ b/dotnet/client-010/demo/Program.cs
@@ -0,0 +1,126 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Configuration;
+using System.IO;
+using System.Text;
+using System.Threading;
+using log4net.Config;
+using org.apache.qpid.client;
+using org.apache.qpid.transport;
+using org.apache.qpid.transport.util;
+
+namespace WindowsClient
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ XmlConfigurator.Configure(new FileInfo("..\\..\\log.xml"));
+ // DOMConfigurator.Configure()
+
+ string host = ConfigurationManager.AppSettings["Host"];
+ int port = int.Parse(ConfigurationManager.AppSettings["Port"]);
+ string virtualhost = ConfigurationManager.AppSettings["VirtualHost"];
+ string username = ConfigurationManager.AppSettings["Username"];
+ string password = ConfigurationManager.AppSettings["Password"];
+
+ Client client = new Client();
+ Console.WriteLine("Client created");
+ client.Connect(host, port, virtualhost, username, password);
+ Console.WriteLine("Connection established");
+
+ IClientSession ssn = client.CreateSession(50000);
+ Console.WriteLine("Session created");
+ ssn.QueueDeclare("queue1", null, null);
+ ssn.ExchangeBind("queue1", "amq.direct", "queue1", null);
+
+
+ Object wl = new Object();
+ ssn.AttachMessageListener(new MyListener(ssn, wl), "myDest");
+
+ ssn.MessageSubscribe("queue1", "myDest", MessageAcceptMode.EXPLICIT, MessageAcquireMode.PRE_ACQUIRED, null,
+ 0, null);
+ DateTime start = DateTime.Now;
+
+ // issue credits
+ ssn.MessageSetFlowMode("myDest", MessageFlowMode.WINDOW);
+ ssn.MessageFlow("myDest", MessageCreditUnit.BYTE, ClientSession.MESSAGE_FLOW_MAX_BYTES);
+ ssn.MessageFlow("myDest", MessageCreditUnit.MESSAGE, 10000);
+ ssn.Sync();
+
+
+ for (int i = 0; i < 10000; i ++)
+ {
+ ssn.MessageTransfer("amq.direct", MessageAcceptMode.NONE, MessageAcquireMode.PRE_ACQUIRED,
+ new Header(new DeliveryProperties().SetRoutingKey("queue1"),
+ new MessageProperties().SetMessageId(UUID.RandomUuid())),
+ Encoding.UTF8.GetBytes("test: " + i));
+ }
+
+ lock(wl)
+ {
+ Monitor.Wait(wl);
+ }
+ DateTime now = DateTime.Now;
+ Console.WriteLine("Start time " + start + " now: " + now);
+
+ Console.WriteLine("Done time: " + (now - start));
+ lock (wl)
+ {
+ Monitor.Wait(wl, 30000);
+ }
+ client.Close();
+ }
+ }
+
+ class MyListener : IMessageListener
+ {
+ private readonly Object _wl;
+ private IClientSession _session;
+ private int _count;
+
+ public MyListener(IClientSession session, object wl)
+ {
+ _wl = wl;
+ _session = session;
+ _count = 0;
+ }
+
+ public void MessageTransfer(IMessage m)
+ {
+ BinaryReader reader = new BinaryReader(m.Body, Encoding.UTF8);
+ byte[] body = new byte[m.Body.Length - m.Body.Position];
+ reader.Read(body, 0, body.Length);
+ ASCIIEncoding enc = new ASCIIEncoding();
+ // Console.WriteLine("Got a message: " + enc.GetString(body) + " count = " + _count);
+ _count++;
+ if (_count == 10000)
+ {
+ lock (_wl)
+ {
+ Monitor.PulseAll(_wl);
+ }
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/demo/Properties/AssemblyInfo.cs b/dotnet/client-010/demo/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..58c7baf4b4
--- /dev/null
+++ b/dotnet/client-010/demo/Properties/AssemblyInfo.cs
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Qpid Demo")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("Qpid Demo")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("434bc34e-b59b-4800-87cf-c2d301cb5082")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/client-010/demo/Properties/Resources.Designer.cs b/dotnet/client-010/demo/Properties/Resources.Designer.cs
new file mode 100644
index 0000000000..761056a770
--- /dev/null
+++ b/dotnet/client-010/demo/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.3053
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace demo.Properties {
+ using System;
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("demo.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/demo/Properties/Resources.resx b/dotnet/client-010/demo/Properties/Resources.resx
new file mode 100644
index 0000000000..af7dbebbac
--- /dev/null
+++ b/dotnet/client-010/demo/Properties/Resources.resx
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+</root> \ No newline at end of file
diff --git a/dotnet/client-010/demo/Properties/Settings.Designer.cs b/dotnet/client-010/demo/Properties/Settings.Designer.cs
new file mode 100644
index 0000000000..6bf34e7ce0
--- /dev/null
+++ b/dotnet/client-010/demo/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.3053
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace demo.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/demo/Properties/Settings.settings b/dotnet/client-010/demo/Properties/Settings.settings
new file mode 100644
index 0000000000..39645652af
--- /dev/null
+++ b/dotnet/client-010/demo/Properties/Settings.settings
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
+ <Profiles>
+ <Profile Name="(Default)" />
+ </Profiles>
+ <Settings />
+</SettingsFile>
diff --git a/dotnet/client-010/demo/default.build b/dotnet/client-010/demo/default.build
new file mode 100644
index 0000000000..f582e392f8
--- /dev/null
+++ b/dotnet/client-010/demo/default.build
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="qpid.client.demo" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="exe"
+ define="${build.defines}"
+ debug="${build.debug}"
+ output="${build.dir}/${project::get-name()}.exe">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ <include name="${build.dir}/log4net.dll" />
+ <include name="${build.dir}/qpid.client.dll" />
+ <include name="System.Configuration.dll"/>
+ </references>
+ </csc>
+ </target>
+</project>
+
diff --git a/dotnet/client-010/examples/direct/example-direct-Listener/Listener.cs b/dotnet/client-010/examples/direct/example-direct-Listener/Listener.cs
new file mode 100644
index 0000000000..f20090526d
--- /dev/null
+++ b/dotnet/client-010/examples/direct/example-direct-Listener/Listener.cs
@@ -0,0 +1,117 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System;
+using System.Configuration;
+using System.IO;
+using System.Text;
+using System.Threading;
+using org.apache.qpid.client;
+using org.apache.qpid.transport;
+
+namespace org.apache.qpid.example.direct
+{
+ /// <summary>
+ /// This program is one of three programs designed to be used
+ /// together. These programs use the "amq.direct" exchange.
+ ///
+ /// Producer:
+ ///
+ /// Publishes to a broker, specifying a routing key.
+ ///
+ /// Listener (this program):
+ ///
+ /// Reads from a queue on the broker using a message listener.
+ ///
+ /// </summary>
+ public class Listener
+ {
+ private static void Main(string[] args)
+ {
+ string host = ConfigurationManager.AppSettings["Host"];
+ int port = int.Parse(ConfigurationManager.AppSettings["Port"]);
+ string virtualhost = ConfigurationManager.AppSettings["VirtualHost"];
+ string username = ConfigurationManager.AppSettings["Username"];
+ string password = ConfigurationManager.AppSettings["Password"];
+
+ Client connection = new Client();
+ try
+ {
+ connection.Connect(host, port, virtualhost, username, password);
+ IClientSession session = connection.CreateSession(50000);
+
+ //--------- Main body of program --------------------------------------------
+ // Create a queue named "message_queue", and route all messages whose
+ // routing key is "routing_key" to this newly created queue.
+
+ session.QueueDeclare("message_queue");
+ session.ExchangeBind("message_queue", "amq.direct", "routing_key");
+
+ lock (session)
+ {
+ // Create a listener and subscribe it to the queue named "message_queue"
+ IMessageListener listener = new MessageListener(session);
+ session.AttachMessageListener(listener, "message_queue");
+ session.MessageSubscribe("message_queue");
+ // Receive messages until all messages are received
+ Monitor.Wait(session);
+ }
+
+ //---------------------------------------------------------------------------
+
+ connection.Close();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Error: \n" + e.StackTrace);
+ }
+ }
+ }
+
+ public class MessageListener : IMessageListener
+ {
+ private readonly IClientSession _session;
+ private readonly RangeSet _range = new RangeSet();
+ public MessageListener(IClientSession session)
+ {
+ _session = session;
+ }
+
+ public void MessageTransfer(IMessage m)
+ {
+ BinaryReader reader = new BinaryReader(m.Body, Encoding.UTF8);
+ byte[] body = new byte[m.Body.Length - m.Body.Position];
+ reader.Read(body, 0, body.Length);
+ ASCIIEncoding enc = new ASCIIEncoding();
+ string message = enc.GetString(body);
+ Console.WriteLine("Message: " + message);
+ // Add this message to the list of message to be acknowledged
+ _range.Add(m.Id);
+ if( message.Equals("That's all, folks!") )
+ {
+ // Acknowledge all the received messages
+ _session.MessageAccept(_range);
+ lock(_session)
+ {
+ Monitor.Pulse(_session);
+ }
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/examples/direct/example-direct-Listener/Properties/AssemblyInfo.cs b/dotnet/client-010/examples/direct/example-direct-Listener/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..2fab6a538a
--- /dev/null
+++ b/dotnet/client-010/examples/direct/example-direct-Listener/Properties/AssemblyInfo.cs
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("example-direct-Listener")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("example-direct-Listener")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("6a24bfe4-4714-4d2a-acf4-96cf9a678a06")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/client-010/examples/direct/example-direct-Listener/default.build b/dotnet/client-010/examples/direct/example-direct-Listener/default.build
new file mode 100644
index 0000000000..f5db519af7
--- /dev/null
+++ b/dotnet/client-010/examples/direct/example-direct-Listener/default.build
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="example-direct-Listener" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="exe"
+ define="${build.defines}"
+ debug="${build.debug}"
+ output="${build.dir}/${project::get-name()}.exe">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ <include name="${build.dir}/log4net.dll" />
+ <include name="${build.dir}/qpid.client.dll" />
+ <include name="System.Configuration.dll" />
+ </references>
+ </csc>
+ </target>
+</project>
+
diff --git a/dotnet/client-010/examples/direct/example-direct-Listener/example-direct-Listener.csproj b/dotnet/client-010/examples/direct/example-direct-Listener/example-direct-Listener.csproj
new file mode 100644
index 0000000000..dea7666e49
--- /dev/null
+++ b/dotnet/client-010/examples/direct/example-direct-Listener/example-direct-Listener.csproj
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{AE65B1B9-8779-4CB1-91AF-E7F6C7A736D7}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>example_direct_Listener</RootNamespace>
+ <AssemblyName>example-direct-Listener</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.configuration" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Listener.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\client\Client.csproj">
+ <Project>{B911FFD7-754F-4735-A188-218D5065BE79}</Project>
+ <Name>Client</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\..\App.config">
+ <Link>App.config</Link>
+ </None>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/dotnet/client-010/examples/direct/example-direct-producer/Producer.cs b/dotnet/client-010/examples/direct/example-direct-producer/Producer.cs
new file mode 100644
index 0000000000..f62667bf98
--- /dev/null
+++ b/dotnet/client-010/examples/direct/example-direct-producer/Producer.cs
@@ -0,0 +1,92 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System;
+using System.Configuration;
+using System.Text;
+using org.apache.qpid.client;
+
+namespace org.apache.qpid.example.direct
+{
+ /// <summary>
+ /// This program is one of three programs designed to be used
+ /// together. These programs use the "amq.direct" exchange.
+ ///
+ /// Producer (this program):
+ ///
+ /// Publishes to a broker, specifying a routing key.
+ ///
+ /// Listener:
+ ///
+ /// Reads from a queue on the broker using a message listener.
+ ///
+ /// </summary>
+ class Producer
+ {
+ static void Main(string[] args)
+ {
+ string host = ConfigurationManager.AppSettings["Host"];
+ int port = int.Parse(ConfigurationManager.AppSettings["Port"]);
+ string virtualhost = ConfigurationManager.AppSettings["VirtualHost"];
+ string username = ConfigurationManager.AppSettings["Username"];
+ string password = ConfigurationManager.AppSettings["Password"];
+
+ Client connection = new Client();
+ try
+ {
+ connection.Connect(host, port, virtualhost, username, password);
+ IClientSession session = connection.CreateSession(50000);
+
+ //--------- Main body of program --------------------------------------------
+
+ IMessage message = new Message();
+
+ // The routing key is a message property. We will use the same
+ // routing key for each message, so we'll set this property
+ // just once. (In most simple cases, there is no need to set
+ // other message properties.)
+
+ message.DeliveryProperties.SetRoutingKey("routing_key");
+
+ // Asynchronous transfer sends messages as quickly as
+ // possible without waiting for confirmation.
+ for (int i = 0; i < 10; i++)
+ {
+ message.ClearData();
+ message.AppendData(Encoding.UTF8.GetBytes("Message " + i));
+ session.MessageTransfer("amq.direct", message);
+ }
+
+ // And send a syncrhonous final message to indicate termination.
+ message.ClearData();
+ message.AppendData(Encoding.UTF8.GetBytes("That's all, folks!"));
+ session.MessageTransfer("amq.direct", "routing_key", message);
+ session.Sync();
+
+ //-----------------------------------------------------------------------------
+
+ connection.Close();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Error: \n" + e.StackTrace);
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/examples/direct/example-direct-producer/Properties/AssemblyInfo.cs b/dotnet/client-010/examples/direct/example-direct-producer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..84590e67c1
--- /dev/null
+++ b/dotnet/client-010/examples/direct/example-direct-producer/Properties/AssemblyInfo.cs
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("example-direct-producer")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("example-direct-producer")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("006144c2-5e45-4543-8e16-c09cd4309ed7")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/client-010/examples/direct/example-direct-producer/default.build b/dotnet/client-010/examples/direct/example-direct-producer/default.build
new file mode 100644
index 0000000000..c4e78444c7
--- /dev/null
+++ b/dotnet/client-010/examples/direct/example-direct-producer/default.build
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="example-direct-Producer" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="exe"
+ define="${build.defines}"
+ debug="${build.debug}"
+ output="${build.dir}/${project::get-name()}.exe">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ <include name="${build.dir}/log4net.dll" />
+ <include name="${build.dir}/qpid.client.dll" />
+ <include name="System.Configuration.dll" />
+ </references>
+ </csc>
+ </target>
+</project>
+
diff --git a/dotnet/client-010/examples/direct/example-direct-producer/example-direct-producer.csproj b/dotnet/client-010/examples/direct/example-direct-producer/example-direct-producer.csproj
new file mode 100644
index 0000000000..6a4c9ceb92
--- /dev/null
+++ b/dotnet/client-010/examples/direct/example-direct-producer/example-direct-producer.csproj
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{96FCB250-8142-40EE-9BDD-CA839EE21021}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>example_direct_producer</RootNamespace>
+ <AssemblyName>example-direct-producer</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.configuration" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Producer.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\client\Client.csproj">
+ <Project>{B911FFD7-754F-4735-A188-218D5065BE79}</Project>
+ <Name>Client</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\..\App.config">
+ <Link>App.config</Link>
+ </None>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/dotnet/client-010/examples/direct/verify b/dotnet/client-010/examples/direct/verify
new file mode 100644
index 0000000000..7da08480a2
--- /dev/null
+++ b/dotnet/client-010/examples/direct/verify
@@ -0,0 +1,37 @@
+#
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements. See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership. The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License. You may obtain a copy of the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied. See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+##
+#
+
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+cpp=$CPP/direct
+
+direct_listener_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-direct-Listener.exe localhost 5672
+}
+
+direct_producer_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-direct-Producer.exe localhost 5672
+}
+
+clients $cpp/declare_queues direct_producer_dotnet direct_listener_dotnet
+outputs $cpp/declare_queues.out ./direct_producer_dotnet.out ./direct_listener_dotnet.out
diff --git a/dotnet/client-010/examples/direct/verify.in b/dotnet/client-010/examples/direct/verify.in
new file mode 100644
index 0000000000..f57d931663
--- /dev/null
+++ b/dotnet/client-010/examples/direct/verify.in
@@ -0,0 +1,14 @@
+==== declare_queues.out
+==== direct_producer_dotnet.out
+==== direct_listener_dotnet.out
+Message: Message 0
+Message: Message 1
+Message: Message 2
+Message: Message 3
+Message: Message 4
+Message: Message 5
+Message: Message 6
+Message: Message 7
+Message: Message 8
+Message: Message 9
+Message: That's all, folks!
diff --git a/dotnet/client-010/examples/direct/verify_cpp_dotnet b/dotnet/client-010/examples/direct/verify_cpp_dotnet
new file mode 100644
index 0000000000..86fb7dddd4
--- /dev/null
+++ b/dotnet/client-010/examples/direct/verify_cpp_dotnet
@@ -0,0 +1,10 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+cpp=$CPP/direct
+
+direct_listener_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-direct-Listener.exe localhost 5672
+}
+
+clients $cpp/declare_queues $cpp/direct_producer direct_listener_dotnet
+outputs $cpp/declare_queues.out $cpp/direct_producer.out ./direct_listener_dotnet.out \ No newline at end of file
diff --git a/dotnet/client-010/examples/direct/verify_cpp_dotnet.in b/dotnet/client-010/examples/direct/verify_cpp_dotnet.in
new file mode 100644
index 0000000000..b3543cefe5
--- /dev/null
+++ b/dotnet/client-010/examples/direct/verify_cpp_dotnet.in
@@ -0,0 +1,14 @@
+==== declare_queues.out
+==== direct_producer.out
+==== direct_listener_dotnet.out
+Message: Message 0
+Message: Message 1
+Message: Message 2
+Message: Message 3
+Message: Message 4
+Message: Message 5
+Message: Message 6
+Message: Message 7
+Message: Message 8
+Message: Message 9
+Message: That's all, folks!
diff --git a/dotnet/client-010/examples/direct/verify_dotnet_cpp b/dotnet/client-010/examples/direct/verify_dotnet_cpp
new file mode 100644
index 0000000000..fe86159fcc
--- /dev/null
+++ b/dotnet/client-010/examples/direct/verify_dotnet_cpp
@@ -0,0 +1,10 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+cpp=$CPP/direct
+
+direct_producer_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-direct-Producer.exe localhost 5672
+}
+
+clients $cpp/declare_queues direct_producer_dotnet $cpp/listener
+outputs $cpp/declare_queues.out ./direct_producer_dotnet.out $cpp/listener.out \ No newline at end of file
diff --git a/dotnet/client-010/examples/direct/verify_dotnet_cpp.in b/dotnet/client-010/examples/direct/verify_dotnet_cpp.in
new file mode 100644
index 0000000000..fcb6cd66de
--- /dev/null
+++ b/dotnet/client-010/examples/direct/verify_dotnet_cpp.in
@@ -0,0 +1,15 @@
+==== declare_queues.out
+==== direct_producer_dotnet.out
+==== listener.out
+Message: Message 0
+Message: Message 1
+Message: Message 2
+Message: Message 3
+Message: Message 4
+Message: Message 5
+Message: Message 6
+Message: Message 7
+Message: Message 8
+Message: Message 9
+Message: That's all, folks!
+Shutting down listener for message_queue
diff --git a/dotnet/client-010/examples/direct/verify_dotnet_java b/dotnet/client-010/examples/direct/verify_dotnet_java
new file mode 100644
index 0000000000..528f3eb664
--- /dev/null
+++ b/dotnet/client-010/examples/direct/verify_dotnet_java
@@ -0,0 +1,15 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+cpp=$CPP/direct
+
+direct_consumer_java()
+{
+java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.direct.Consumer
+}
+
+direct_producer_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-direct-Producer.exe localhost 5672
+}
+
+clients $cpp/declare_queues direct_producer_dotnet direct_consumer_java
+outputs $cpp/declare_queues.out ./direct_producer_dotnet.out ./direct_consumer_java.out
diff --git a/dotnet/client-010/examples/direct/verify_dotnet_java.in b/dotnet/client-010/examples/direct/verify_dotnet_java.in
new file mode 100644
index 0000000000..cd87551305
--- /dev/null
+++ b/dotnet/client-010/examples/direct/verify_dotnet_java.in
@@ -0,0 +1,20 @@
+==== declare_queues.out
+==== direct_producer_dotnet.out
+==== direct_consumer_java.out
+Consumer: Setting an ExceptionListener on the connection as sample uses a MessageConsumer
+Consumer: Creating a non-transacted, auto-acknowledged session
+Consumer: Creating a MessageConsumer
+Consumer: Starting connection so MessageConsumer can receive messages
+Consumer: Received message: Message 0
+Consumer: Received message: Message 1
+Consumer: Received message: Message 2
+Consumer: Received message: Message 3
+Consumer: Received message: Message 4
+Consumer: Received message: Message 5
+Consumer: Received message: Message 6
+Consumer: Received message: Message 7
+Consumer: Received message: Message 8
+Consumer: Received message: Message 9
+Consumer: Received final message That's all, folks!
+Consumer: Closing connection
+Consumer: Closing JNDI context
diff --git a/dotnet/client-010/examples/direct/verify_dotnet_python b/dotnet/client-010/examples/direct/verify_dotnet_python
new file mode 100644
index 0000000000..0c70465bc5
--- /dev/null
+++ b/dotnet/client-010/examples/direct/verify_dotnet_python
@@ -0,0 +1,10 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+py=$PYTHON_EXAMPLES/direct
+
+direct_producer_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-direct-Producer.exe localhost 5672
+}
+
+clients $py/declare_queues.py direct_producer_dotnet $py/direct_consumer.py
+outputs $py/declare_queues.py.out ./direct_producer_dotnet.out $py/direct_consumer.py.out
diff --git a/dotnet/client-010/examples/direct/verify_dotnet_python.in b/dotnet/client-010/examples/direct/verify_dotnet_python.in
new file mode 100644
index 0000000000..7059b3079c
--- /dev/null
+++ b/dotnet/client-010/examples/direct/verify_dotnet_python.in
@@ -0,0 +1,14 @@
+==== declare_queues.py.out
+==== direct_producer_dotnet.out
+==== direct_consumer.py.out
+Message 0
+Message 1
+Message 2
+Message 3
+Message 4
+Message 5
+Message 6
+Message 7
+Message 8
+Message 9
+That's all, folks!
diff --git a/dotnet/client-010/examples/direct/verify_java_dotnet b/dotnet/client-010/examples/direct/verify_java_dotnet
new file mode 100644
index 0000000000..50eb73f9f5
--- /dev/null
+++ b/dotnet/client-010/examples/direct/verify_java_dotnet
@@ -0,0 +1,15 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+cpp=$CPP/direct
+
+direct_listener_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-direct-Listener.exe localhost 5672
+}
+
+direct_producer_java()
+{
+java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.direct.Producer
+}
+
+clients $cpp/declare_queues direct_producer_java direct_listener_dotnet
+outputs $cpp/declare_queues.out ./direct_producer_java.out ./direct_listener_dotnet.out
diff --git a/dotnet/client-010/examples/direct/verify_java_dotnet.in b/dotnet/client-010/examples/direct/verify_java_dotnet.in
new file mode 100644
index 0000000000..23628b89de
--- /dev/null
+++ b/dotnet/client-010/examples/direct/verify_java_dotnet.in
@@ -0,0 +1,29 @@
+==== declare_queues.out
+==== direct_producer_java.out
+Producer: Creating a non-transacted, auto-acknowledged session
+Producer: Creating a Message Producer
+Producer: Creating a TestMessage to send to the destination
+Producer: Sending message: 1
+Producer: Sending message: 2
+Producer: Sending message: 3
+Producer: Sending message: 4
+Producer: Sending message: 5
+Producer: Sending message: 6
+Producer: Sending message: 7
+Producer: Sending message: 8
+Producer: Sending message: 9
+Producer: Sending message: 10
+Producer: Closing connection
+Producer: Closing JNDI context
+==== direct_listener_dotnet.out
+Message: Message 1
+Message: Message 2
+Message: Message 3
+Message: Message 4
+Message: Message 5
+Message: Message 6
+Message: Message 7
+Message: Message 8
+Message: Message 9
+Message: Message 10
+Message: That's all, folks!
diff --git a/dotnet/client-010/examples/direct/verify_python_dotnet b/dotnet/client-010/examples/direct/verify_python_dotnet
new file mode 100644
index 0000000000..086b31caf4
--- /dev/null
+++ b/dotnet/client-010/examples/direct/verify_python_dotnet
@@ -0,0 +1,10 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+py=$PYTHON_EXAMPLES/direct
+
+direct_listener_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-direct-Listener.exe localhost 5672
+}
+
+clients $py/declare_queues.py $py/direct_producer.py direct_listener_dotnet
+outputs $py/declare_queues.py.out $py/direct_producer.py.out ./direct_listener_dotnet.out
diff --git a/dotnet/client-010/examples/direct/verify_python_dotnet.in b/dotnet/client-010/examples/direct/verify_python_dotnet.in
new file mode 100644
index 0000000000..a556e7ad86
--- /dev/null
+++ b/dotnet/client-010/examples/direct/verify_python_dotnet.in
@@ -0,0 +1,14 @@
+==== declare_queues.py.out
+==== direct_producer.py.out
+==== direct_listener_dotnet.out
+Message: message 0
+Message: message 1
+Message: message 2
+Message: message 3
+Message: message 4
+Message: message 5
+Message: message 6
+Message: message 7
+Message: message 8
+Message: message 9
+Message: That's all, folks!
diff --git a/dotnet/client-010/examples/fanout/example-fanout-Listener/Listener.cs b/dotnet/client-010/examples/fanout/example-fanout-Listener/Listener.cs
new file mode 100644
index 0000000000..b1967b59be
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/example-fanout-Listener/Listener.cs
@@ -0,0 +1,126 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System;
+using System.Configuration;
+using System.IO;
+using System.Text;
+using System.Threading;
+using org.apache.qpid.client;
+using org.apache.qpid.transport;
+
+namespace org.apache.qpid.example.fanout
+{
+ /// <summary>
+ /// This program is one of two programs designed to be used
+ /// together.
+ ///
+ /// Producer (this program):
+ ///
+ /// Publishes to a broker, specifying a routing key.
+ ///
+ /// Listener:
+ ///
+ /// Reads from a queue on the broker using a message listener.
+ ///
+ /// </summary>
+ public class Listener
+ {
+ private static void Main(string[] args)
+ {
+ string host = ConfigurationManager.AppSettings["Host"];
+ int port = int.Parse(ConfigurationManager.AppSettings["Port"]);
+ string virtualhost = ConfigurationManager.AppSettings["VirtualHost"];
+ string username = ConfigurationManager.AppSettings["Username"];
+ string password = ConfigurationManager.AppSettings["Password"];
+
+ Client connection = new Client();
+ try
+ {
+ connection.Connect(host, port, virtualhost, username, password);
+ IClientSession session = connection.CreateSession(50000);
+
+ //--------- Main body of program --------------------------------------------
+ // Each client creates its own private queue, using the
+ // session id to guarantee a unique name. It then routes
+ // all messages from the fanout exchange to its own queue
+ // by binding to the queue.
+ //
+ // The binding specifies a binding key, but for a fanout
+ // exchange, the binding key is optional and is not used
+ // for routing decisions. It can be useful for tracking
+ // messages and routing in logs.
+
+ string myQueue = session.Name;
+ session.QueueDeclare(myQueue, Option.EXCLUSIVE, Option.AUTO_DELETE);
+ session.ExchangeBind(myQueue, "amq.fanout", "my-key");
+
+ lock (session)
+ {
+ Console.WriteLine("Listening");
+ // Create a listener and subscribe it to my queue.
+ IMessageListener listener = new MessageListener(session);
+ session.AttachMessageListener(listener, myQueue);
+ session.MessageSubscribe(myQueue);
+ // Receive messages until all messages are received
+ Monitor.Wait(session);
+ }
+
+ //---------------------------------------------------------------------------
+
+ connection.Close();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Error: \n" + e.StackTrace);
+ }
+ }
+ }
+
+ public class MessageListener : IMessageListener
+ {
+ private readonly IClientSession _session;
+ private readonly RangeSet _range = new RangeSet();
+ public MessageListener(IClientSession session)
+ {
+ _session = session;
+ }
+
+ public void MessageTransfer(IMessage m)
+ {
+ BinaryReader reader = new BinaryReader(m.Body, Encoding.UTF8);
+ byte[] body = new byte[m.Body.Length - m.Body.Position];
+ reader.Read(body, 0, body.Length);
+ ASCIIEncoding enc = new ASCIIEncoding();
+ string message = enc.GetString(body);
+ Console.WriteLine("Message: " + message);
+ // Add this message to the list of message to be acknowledged
+ _range.Add(m.Id);
+ if (message.Equals("That's all, folks!"))
+ {
+ // Acknowledge all the received messages
+ _session.MessageAccept(_range);
+ lock (_session)
+ {
+ Monitor.Pulse(_session);
+ }
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/examples/fanout/example-fanout-Listener/Properties/AssemblyInfo.cs b/dotnet/client-010/examples/fanout/example-fanout-Listener/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..45ff62073e
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/example-fanout-Listener/Properties/AssemblyInfo.cs
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("example-fanout-Listener")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("example-fanout-Listener")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("68686ef9-aa0a-4334-9c52-d7e6fc507bec")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/client-010/examples/fanout/example-fanout-Listener/default.build b/dotnet/client-010/examples/fanout/example-fanout-Listener/default.build
new file mode 100644
index 0000000000..dde36daf17
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/example-fanout-Listener/default.build
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="example-fanout-Listener" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="exe"
+ define="${build.defines}"
+ debug="${build.debug}"
+ output="${build.dir}/${project::get-name()}.exe">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ <include name="${build.dir}/log4net.dll" />
+ <include name="${build.dir}/qpid.client.dll" />
+ <include name="System.Configuration.dll" />
+ </references>
+ </csc>
+ </target>
+</project>
+
diff --git a/dotnet/client-010/examples/fanout/example-fanout-Listener/example-fanout-Listener.csproj b/dotnet/client-010/examples/fanout/example-fanout-Listener/example-fanout-Listener.csproj
new file mode 100644
index 0000000000..771e6a6891
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/example-fanout-Listener/example-fanout-Listener.csproj
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{18A0792B-DC3A-4EC5-93D6-DB8A111D8F15}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>example_fanout_Listener</RootNamespace>
+ <AssemblyName>example-fanout-Listener</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.configuration" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Listener.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\client\Client.csproj">
+ <Project>{B911FFD7-754F-4735-A188-218D5065BE79}</Project>
+ <Name>Client</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\..\App.config">
+ <Link>App.config</Link>
+ </None>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/dotnet/client-010/examples/fanout/example-fanout-Producer/Producer.cs b/dotnet/client-010/examples/fanout/example-fanout-Producer/Producer.cs
new file mode 100644
index 0000000000..a781358a7e
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/example-fanout-Producer/Producer.cs
@@ -0,0 +1,89 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System;
+using System.Configuration;
+using System.Text;
+using org.apache.qpid.client;
+
+namespace org.apache.qpid.example.fanout
+{
+ /// <summary>
+ /// This program is one of two programs designed to be used
+ /// together. These programs do not specify the exchange type - the
+ /// default exchange type is the direct exchange.
+ ///
+ ///
+ /// Producer (this program):
+ ///
+ /// Publishes to a broker, specifying a routing key.
+ ///
+ /// Listener:
+ ///
+ /// Reads from a queue on the broker using a message listener.
+ ///
+ /// </summary>
+ class Producer
+ {
+ static void Main(string[] args)
+ {
+ string host = ConfigurationManager.AppSettings["Host"];
+ int port = int.Parse(ConfigurationManager.AppSettings["Port"]);
+ string virtualhost = ConfigurationManager.AppSettings["VirtualHost"];
+ string username = ConfigurationManager.AppSettings["Username"];
+ string password = ConfigurationManager.AppSettings["Password"];
+
+ Client connection = new Client();
+ try
+ {
+ connection.Connect(host, port, virtualhost, username, password);
+ IClientSession session = connection.CreateSession(50000);
+
+ //--------- Main body of program --------------------------------------------
+
+ // Unlike topic exchanges and direct exchanges, a fanout
+ // exchange need not set a routing key.
+ IMessage message = new Message();
+
+ // Asynchronous transfer sends messages as quickly as
+ // possible without waiting for confirmation.
+ for (int i = 0; i < 10; i++)
+ {
+ message.ClearData();
+ message.AppendData(Encoding.UTF8.GetBytes("Message " + i));
+ session.MessageTransfer("amq.fanout", message);
+ }
+
+ // And send a syncrhonous final message to indicate termination.
+ message.ClearData();
+ message.AppendData(Encoding.UTF8.GetBytes("That's all, folks!"));
+ session.MessageTransfer("amq.fanout", message);
+ session.Sync();
+
+ //-----------------------------------------------------------------------------
+
+ connection.Close();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Error: \n" + e.StackTrace);
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/examples/fanout/example-fanout-Producer/Properties/AssemblyInfo.cs b/dotnet/client-010/examples/fanout/example-fanout-Producer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..c19bb5b949
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/example-fanout-Producer/Properties/AssemblyInfo.cs
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("example-fanout-Producer")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("example-fanout-Producer")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("01c0ba10-2f23-409b-9adc-bc514a13131a")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/client-010/examples/fanout/example-fanout-Producer/default.build b/dotnet/client-010/examples/fanout/example-fanout-Producer/default.build
new file mode 100644
index 0000000000..c4d39e41da
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/example-fanout-Producer/default.build
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="example-fanout-Producer" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="exe"
+ define="${build.defines}"
+ debug="${build.debug}"
+ output="${build.dir}/${project::get-name()}.exe">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ <include name="${build.dir}/log4net.dll" />
+ <include name="${build.dir}/qpid.client.dll" />
+ <include name="System.Configuration.dll" />
+ </references>
+ </csc>
+ </target>
+</project>
+
diff --git a/dotnet/client-010/examples/fanout/example-fanout-Producer/example-fanout-Producer.csproj b/dotnet/client-010/examples/fanout/example-fanout-Producer/example-fanout-Producer.csproj
new file mode 100644
index 0000000000..6c164924a3
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/example-fanout-Producer/example-fanout-Producer.csproj
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{4513BF94-D54A-42FE-8506-FE2CD57B2C51}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>example_fanout_Producer</RootNamespace>
+ <AssemblyName>example-fanout-Producer</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.configuration" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Producer.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\client\Client.csproj">
+ <Project>{B911FFD7-754F-4735-A188-218D5065BE79}</Project>
+ <Name>Client</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\..\App.config">
+ <Link>App.config</Link>
+ </None>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/dotnet/client-010/examples/fanout/verify b/dotnet/client-010/examples/fanout/verify
new file mode 100644
index 0000000000..51b7327243
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/verify
@@ -0,0 +1,36 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+
+fanout_listener_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-fanout-Listener.exe localhost 5672
+}
+
+fanout_producer_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-fanout-Producer.exe localhost 5672
+}
+
+background "Listening" fanout_listener_dotnet
+clients fanout_producer_dotnet
+outputs ./fanout_listener_dotnet.out ./fanout_producer_dotnet.out
diff --git a/dotnet/client-010/examples/fanout/verify.in b/dotnet/client-010/examples/fanout/verify.in
new file mode 100644
index 0000000000..37a4a4aaa8
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/verify.in
@@ -0,0 +1,14 @@
+==== fanout_listener_dotnet.out
+Listening
+Message: Message 0
+Message: Message 1
+Message: Message 2
+Message: Message 3
+Message: Message 4
+Message: Message 5
+Message: Message 6
+Message: Message 7
+Message: Message 8
+Message: Message 9
+Message: That's all, folks!
+==== fanout_producer_dotnet.out
diff --git a/dotnet/client-010/examples/fanout/verify_cpp_dotnet b/dotnet/client-010/examples/fanout/verify_cpp_dotnet
new file mode 100644
index 0000000000..b9b0d94857
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/verify_cpp_dotnet
@@ -0,0 +1,11 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+cpp=$CPP/fanout
+
+fanout_listener_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-fanout-Listener.exe localhost 5672
+}
+
+background "Listening" fanout_listener_dotnet
+clients $cpp/fanout_producer
+outputs $cpp/fanout_producer.out "./fanout_listener_dotnet.out | remove_uuid"
diff --git a/dotnet/client-010/examples/fanout/verify_cpp_dotnet.in b/dotnet/client-010/examples/fanout/verify_cpp_dotnet.in
new file mode 100644
index 0000000000..0a72d8fd3c
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/verify_cpp_dotnet.in
@@ -0,0 +1,14 @@
+==== fanout_producer.out
+==== fanout_listener_dotnet.out | remove_uuid
+Listening
+Message: Message 0
+Message: Message 1
+Message: Message 2
+Message: Message 3
+Message: Message 4
+Message: Message 5
+Message: Message 6
+Message: Message 7
+Message: Message 8
+Message: Message 9
+Message: That's all, folks!
diff --git a/dotnet/client-010/examples/fanout/verify_dotnet_cpp b/dotnet/client-010/examples/fanout/verify_dotnet_cpp
new file mode 100644
index 0000000000..1b27ea8653
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/verify_dotnet_cpp
@@ -0,0 +1,12 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+cpp=$CPP/fanout
+
+fanout_producer_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-fanout-Producer.exe localhost 5672
+}
+
+
+background "Listening" $cpp/listener
+clients fanout_producer_dotnet
+outputs ./fanout_producer_dotnet.out "$cpp/listener.out | remove_uuid"
diff --git a/dotnet/client-010/examples/fanout/verify_dotnet_cpp.in b/dotnet/client-010/examples/fanout/verify_dotnet_cpp.in
new file mode 100644
index 0000000000..588559938f
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/verify_dotnet_cpp.in
@@ -0,0 +1,15 @@
+==== fanout_producer_dotnet.out
+==== listener.out | remove_uuid
+Listening
+Message: Message 0
+Message: Message 1
+Message: Message 2
+Message: Message 3
+Message: Message 4
+Message: Message 5
+Message: Message 6
+Message: Message 7
+Message: Message 8
+Message: Message 9
+Message: That's all, folks!
+Shutting down listener for
diff --git a/dotnet/client-010/examples/fanout/verify_dotnet_java b/dotnet/client-010/examples/fanout/verify_dotnet_java
new file mode 100644
index 0000000000..88576814d7
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/verify_dotnet_java
@@ -0,0 +1,16 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+
+fanout_producer_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-fanout-Producer.exe localhost 5672
+}
+
+
+fanout_listener_java()
+{
+java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.fanout.Listener $1
+}
+
+background "can receive messages" fanout_listener_java fanoutQueue1
+clients fanout_producer_dotnet
+outputs ./fanout_producer_dotnet.out "./fanout_listener_java.out | remove_uuid"
diff --git a/dotnet/client-010/examples/fanout/verify_dotnet_java.in b/dotnet/client-010/examples/fanout/verify_dotnet_java.in
new file mode 100644
index 0000000000..06d3a6e66b
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/verify_dotnet_java.in
@@ -0,0 +1,19 @@
+==== fanout_producer_dotnet.out
+==== fanout_listener_java.out | remove_uuid
+Listener: Setting an ExceptionListener on the connection as sample uses a MessageConsumer
+Listener: Creating a non-transacted, auto-acknowledged session
+Listener: Creating a MessageConsumer
+Listener: Starting connection so MessageConsumer can receive messages
+Listener: Received message: Message 0
+Listener: Received message: Message 1
+Listener: Received message: Message 2
+Listener: Received message: Message 3
+Listener: Received message: Message 4
+Listener: Received message: Message 5
+Listener: Received message: Message 6
+Listener: Received message: Message 7
+Listener: Received message: Message 8
+Listener: Received message: Message 9
+Listener: Received final message That's all, folks!
+Listener: Closing connection
+Listener: Closing JNDI context
diff --git a/dotnet/client-010/examples/fanout/verify_dotnet_python b/dotnet/client-010/examples/fanout/verify_dotnet_python
new file mode 100644
index 0000000000..a09b26ca6a
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/verify_dotnet_python
@@ -0,0 +1,11 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+py=$PYTHON_EXAMPLES/fanout
+
+fanout_producer_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-fanout-Producer.exe localhost 5672
+}
+
+background "Subscribed" $py/fanout_consumer.py
+clients fanout_producer_dotnet
+outputs ./fanout_producer_dotnet.out "$py/fanout_consumer.py.out | remove_uuid"
diff --git a/dotnet/client-010/examples/fanout/verify_dotnet_python.in b/dotnet/client-010/examples/fanout/verify_dotnet_python.in
new file mode 100644
index 0000000000..e9959c2e25
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/verify_dotnet_python.in
@@ -0,0 +1,14 @@
+==== fanout_producer_dotnet.out
+==== fanout_consumer.py.out | remove_uuid
+Subscribed to queue
+Message 0
+Message 1
+Message 2
+Message 3
+Message 4
+Message 5
+Message 6
+Message 7
+Message 8
+Message 9
+That's all, folks!
diff --git a/dotnet/client-010/examples/fanout/verify_java_dotnet b/dotnet/client-010/examples/fanout/verify_java_dotnet
new file mode 100644
index 0000000000..d72954de0e
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/verify_java_dotnet
@@ -0,0 +1,16 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+
+fanout_listener_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-fanout-Listener.exe localhost 5672
+}
+
+
+fanout_producer_java()
+{
+java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.fanout.Producer
+}
+
+background "Listening" fanout_listener_dotnet
+clients fanout_producer_java
+outputs fanout_producer_java.out "./fanout_listener_dotnet.out | remove_uuid"
diff --git a/dotnet/client-010/examples/fanout/verify_java_dotnet.in b/dotnet/client-010/examples/fanout/verify_java_dotnet.in
new file mode 100644
index 0000000000..acf1b61221
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/verify_java_dotnet.in
@@ -0,0 +1,29 @@
+==== fanout_producer_java.out
+Producer: Creating a non-transacted, auto-acknowledged session
+Producer: Creating a Message Producer
+Producer: Creating a TestMessage to send to the destination
+Producer: Sending message: 1
+Producer: Sending message: 2
+Producer: Sending message: 3
+Producer: Sending message: 4
+Producer: Sending message: 5
+Producer: Sending message: 6
+Producer: Sending message: 7
+Producer: Sending message: 8
+Producer: Sending message: 9
+Producer: Sending message: 10
+Producer: Closing connection
+Producer: Closing JNDI context
+==== fanout_listener_dotnet.out | remove_uuid
+Listening
+Message: Message 1
+Message: Message 2
+Message: Message 3
+Message: Message 4
+Message: Message 5
+Message: Message 6
+Message: Message 7
+Message: Message 8
+Message: Message 9
+Message: Message 10
+Message: That's all, folks!
diff --git a/dotnet/client-010/examples/fanout/verify_python_dotnet b/dotnet/client-010/examples/fanout/verify_python_dotnet
new file mode 100644
index 0000000000..ac472c0f72
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/verify_python_dotnet
@@ -0,0 +1,11 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+py=$PYTHON_EXAMPLES/fanout
+
+fanout_listener_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-fanout-Listener.exe localhost 5672
+}
+
+background "Listening" fanout_listener_dotnet
+clients $py/fanout_producer.py
+outputs $py/fanout_producer.py.out "./fanout_listener_dotnet.out | remove_uuid"
diff --git a/dotnet/client-010/examples/fanout/verify_python_dotnet.in b/dotnet/client-010/examples/fanout/verify_python_dotnet.in
new file mode 100644
index 0000000000..b489c63a2c
--- /dev/null
+++ b/dotnet/client-010/examples/fanout/verify_python_dotnet.in
@@ -0,0 +1,14 @@
+==== fanout_producer.py.out
+==== fanout_listener_dotnet.out | remove_uuid
+Listening
+Message: message 0
+Message: message 1
+Message: message 2
+Message: message 3
+Message: message 4
+Message: message 5
+Message: message 6
+Message: message 7
+Message: message 8
+Message: message 9
+Message: That's all, folks!
diff --git a/dotnet/client-010/examples/pub-sub/example-pub-sub-Listener/Listener.cs b/dotnet/client-010/examples/pub-sub/example-pub-sub-Listener/Listener.cs
new file mode 100644
index 0000000000..aeaf3f043b
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/example-pub-sub-Listener/Listener.cs
@@ -0,0 +1,143 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System;
+using System.Configuration;
+using System.IO;
+using System.Text;
+using System.Threading;
+using org.apache.qpid.client;
+using org.apache.qpid.transport;
+
+namespace org.apache.qpid.example.pubsub
+{
+ /// <summary>
+ /// This program is one of two programs designed to be used
+ /// together. These programs use the topic exchange.
+ ///
+ /// Publisher:
+ ///
+ /// Publishes to a broker, specifying a routing key.
+ ///
+ /// Listener (this program):
+ ///
+ /// Reads from a queue on the broker using a message listener.
+ ///
+ /// </summary>
+ internal class Listener
+ {
+ public static int _count = 4;
+
+ private static void Main(string[] args)
+ {
+ string host = ConfigurationManager.AppSettings["Host"];
+ int port = int.Parse(ConfigurationManager.AppSettings["Port"]);
+ string virtualhost = ConfigurationManager.AppSettings["VirtualHost"];
+ string username = ConfigurationManager.AppSettings["Username"];
+ string password = ConfigurationManager.AppSettings["Password"];
+
+ Client connection = new Client();
+ try
+ {
+ connection.Connect(host, port, virtualhost, username, password);
+ IClientSession session = connection.CreateSession(50000);
+
+ //--------- Main body of program --------------------------------------------
+
+ lock (session)
+ {
+ Console.WriteLine("Listening for messages ...");
+ // Create a listener
+ prepareQueue("usa", "usa.#", session);
+ prepareQueue("europe", "europe.#", session);
+ prepareQueue("news", "#.news", session);
+ prepareQueue("weather", "#.weather", session);
+ while (_count > 0)
+ {
+ Monitor.Wait(session);
+ }
+ }
+
+ //---------------------------------------------------------------------------
+
+ connection.Close();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Error: \n" + e.StackTrace);
+ }
+ }
+
+ private static void prepareQueue(string queue, string routing_key, IClientSession session)
+ {
+ // Create a unique queue name for this consumer by concatenating
+ // the queue name parameter with the Session ID.
+ Console.WriteLine("Declaring queue: " + queue);
+ session.QueueDeclare(queue, Option.EXCLUSIVE, Option.AUTO_DELETE);
+
+ // Route messages to the new queue if they match the routing key.
+ // Also route any messages to with the "control" routing key to
+ // this queue so we know when it's time to stop. A publisher sends
+ // a message with the content "That's all, Folks!", using the
+ // "control" routing key, when it is finished.
+
+ session.ExchangeBind(queue, "amq.topic", routing_key);
+ session.ExchangeBind(queue, "amq.topic", "control");
+
+ // subscribe the listener to the queue
+ IMessageListener listener = new MessageListener(session);
+ session.AttachMessageListener(listener, queue);
+ session.MessageSubscribe(queue);
+ }
+ }
+
+ public class MessageListener : IMessageListener
+ {
+ private readonly IClientSession _session;
+ private readonly RangeSet _range = new RangeSet();
+
+ public MessageListener(IClientSession session)
+ {
+ _session = session;
+ }
+
+ public void MessageTransfer(IMessage m)
+ {
+ BinaryReader reader = new BinaryReader(m.Body, Encoding.UTF8);
+ byte[] body = new byte[m.Body.Length - m.Body.Position];
+ reader.Read(body, 0, body.Length);
+ ASCIIEncoding enc = new ASCIIEncoding();
+ string message = enc.GetString(body);
+ Console.WriteLine("Message: " + message + " from " + m.Destination);
+ // Add this message to the list of message to be acknowledged
+ _range.Add(m.Id);
+ if (message.Equals("That's all, folks!"))
+ {
+ Console.WriteLine("Shutting down listener for " + m.DeliveryProperties.GetRoutingKey());
+ Listener._count--;
+ // Acknowledge all the received messages
+ _session.MessageAccept(_range);
+ lock (_session)
+ {
+ Monitor.Pulse(_session);
+ }
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/examples/pub-sub/example-pub-sub-Listener/Properties/AssemblyInfo.cs b/dotnet/client-010/examples/pub-sub/example-pub-sub-Listener/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..ef791c6738
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/example-pub-sub-Listener/Properties/AssemblyInfo.cs
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("example-pub-sub-Listener")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("example-pub-sub-Listener")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("74ab02ae-95d1-4bad-a7cf-9964005b9b05")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/client-010/examples/pub-sub/example-pub-sub-Listener/default.build b/dotnet/client-010/examples/pub-sub/example-pub-sub-Listener/default.build
new file mode 100644
index 0000000000..fe2d9bf4ba
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/example-pub-sub-Listener/default.build
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="example-pub-sub-Listener" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="exe"
+ define="${build.defines}"
+ debug="${build.debug}"
+ output="${build.dir}/${project::get-name()}.exe">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ <include name="${build.dir}/log4net.dll" />
+ <include name="${build.dir}/qpid.client.dll" />
+ <include name="System.Configuration.dll" />
+ </references>
+ </csc>
+ </target>
+</project>
+
diff --git a/dotnet/client-010/examples/pub-sub/example-pub-sub-Listener/example-pub-sub-Listener.csproj b/dotnet/client-010/examples/pub-sub/example-pub-sub-Listener/example-pub-sub-Listener.csproj
new file mode 100644
index 0000000000..f7222fc865
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/example-pub-sub-Listener/example-pub-sub-Listener.csproj
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{2BCDC2CC-5BDA-4CC7-944D-2899AD8A53C7}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>example_pub_sub_Listener</RootNamespace>
+ <AssemblyName>example-pub-sub-Listener</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.configuration" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Listener.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\client\Client.csproj">
+ <Project>{B911FFD7-754F-4735-A188-218D5065BE79}</Project>
+ <Name>Client</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\..\App.config">
+ <Link>App.config</Link>
+ </None>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/dotnet/client-010/examples/pub-sub/example-pub-sub-Publisher/Properties/AssemblyInfo.cs b/dotnet/client-010/examples/pub-sub/example-pub-sub-Publisher/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..b6d7f3c818
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/example-pub-sub-Publisher/Properties/AssemblyInfo.cs
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("example-pub-sub-Publisher")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("example-pub-sub-Publisher")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("f6d282a0-9dc5-46cf-a4cd-44ae402d667f")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/client-010/examples/pub-sub/example-pub-sub-Publisher/Publisher.cs b/dotnet/client-010/examples/pub-sub/example-pub-sub-Publisher/Publisher.cs
new file mode 100644
index 0000000000..c87985d288
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/example-pub-sub-Publisher/Publisher.cs
@@ -0,0 +1,98 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System;
+using System.Configuration;
+using System.Text;
+using org.apache.qpid.client;
+
+namespace org.apache.qpid.example.pubsub
+{
+ /// <summary>
+ /// This program is one of two programs designed to be used
+ /// together. These programs use the topic exchange.
+ ///
+ /// Publisher (this program):
+ ///
+ /// Publishes to a broker, specifying a routing key.
+ ///
+ /// Listener:
+ ///
+ /// Reads from a queue on the broker using a message listener.
+ ///
+ /// </summary>
+ internal class Publisher
+ {
+ private static void Main(string[] args)
+ {
+ string host = ConfigurationManager.AppSettings["Host"];
+ int port = int.Parse(ConfigurationManager.AppSettings["Port"]);
+ string virtualhost = ConfigurationManager.AppSettings["VirtualHost"];
+ string username = ConfigurationManager.AppSettings["Username"];
+ string password = ConfigurationManager.AppSettings["Password"];
+
+ Client connection = new Client();
+ try
+ {
+ connection.Connect(host, port, virtualhost, username, password);
+ IClientSession session = connection.CreateSession(50000);
+
+ //--------- Main body of program --------------------------------------------
+
+ publishMessages(session, "usa.news");
+ publishMessages(session, "usa.weather");
+ publishMessages(session, "europe.news");
+ publishMessages(session, "europe.weather");
+
+ noMoreMessages(session);
+
+ //-----------------------------------------------------------------------------
+
+ connection.Close();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Error: \n" + e.StackTrace);
+ }
+ }
+
+ private static void publishMessages(IClientSession session, string routing_key)
+ {
+ IMessage message = new Message();
+ // Asynchronous transfer sends messages as quickly as
+ // possible without waiting for confirmation.
+ for (int i = 0; i < 10; i++)
+ {
+ message.ClearData();
+ message.AppendData(Encoding.UTF8.GetBytes("Message " + i));
+ session.MessageTransfer("amq.topic", routing_key, message);
+ }
+ }
+
+ private static void noMoreMessages(IClientSession session)
+ {
+ IMessage message = new Message();
+ // And send a syncrhonous final message to indicate termination.
+ message.ClearData();
+ message.AppendData(Encoding.UTF8.GetBytes("That's all, folks!"));
+ session.MessageTransfer("amq.topic", "control", message);
+ session.Sync();
+ }
+ }
+}
diff --git a/dotnet/client-010/examples/pub-sub/example-pub-sub-Publisher/default.build b/dotnet/client-010/examples/pub-sub/example-pub-sub-Publisher/default.build
new file mode 100644
index 0000000000..3f270afe9e
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/example-pub-sub-Publisher/default.build
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="example-pub-sub-Publisher" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="exe"
+ define="${build.defines}"
+ debug="${build.debug}"
+ output="${build.dir}/${project::get-name()}.exe">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ <include name="${build.dir}/log4net.dll" />
+ <include name="${build.dir}/qpid.client.dll" />
+ <include name="System.Configuration.dll" />
+ </references>
+ </csc>
+ </target>
+</project>
+
diff --git a/dotnet/client-010/examples/pub-sub/example-pub-sub-Publisher/example-pub-sub-Publisher.csproj b/dotnet/client-010/examples/pub-sub/example-pub-sub-Publisher/example-pub-sub-Publisher.csproj
new file mode 100644
index 0000000000..3793b73625
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/example-pub-sub-Publisher/example-pub-sub-Publisher.csproj
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{F8857634-A134-44E7-A953-F2B22688C599}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>example_pub_sub_Publisher</RootNamespace>
+ <AssemblyName>example-pub-sub-Publisher</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.configuration" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Publisher.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\client\Client.csproj">
+ <Project>{B911FFD7-754F-4735-A188-218D5065BE79}</Project>
+ <Name>Client</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\..\App.config">
+ <Link>App.config</Link>
+ </None>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/dotnet/client-010/examples/pub-sub/verify b/dotnet/client-010/examples/pub-sub/verify
new file mode 100644
index 0000000000..45d80c4866
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/verify
@@ -0,0 +1,36 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+
+pubsub_listener_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-pub-sub-Listener.exe localhost 5672
+}
+
+pubsub_producer_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-pub-sub-Publisher.exe localhost 5672
+}
+
+background "Listening for messages ..." pubsub_listener_dotnet
+clients pubsub_producer_dotnet
+outputs pubsub_producer_dotnet.out "pubsub_listener_dotnet.out | remove_uuid | sort"
diff --git a/dotnet/client-010/examples/pub-sub/verify.in b/dotnet/client-010/examples/pub-sub/verify.in
new file mode 100644
index 0000000000..6a5adc4d89
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/verify.in
@@ -0,0 +1,95 @@
+==== pubsub_producer_dotnet.out
+==== pubsub_listener_dotnet.out | remove_uuid | sort
+Declaring queue: europe
+Declaring queue: news
+Declaring queue: usa
+Declaring queue: weather
+Listening for messages ...
+Message: Message 0 from europe
+Message: Message 0 from europe
+Message: Message 0 from news
+Message: Message 0 from news
+Message: Message 0 from usa
+Message: Message 0 from usa
+Message: Message 0 from weather
+Message: Message 0 from weather
+Message: Message 1 from europe
+Message: Message 1 from europe
+Message: Message 1 from news
+Message: Message 1 from news
+Message: Message 1 from usa
+Message: Message 1 from usa
+Message: Message 1 from weather
+Message: Message 1 from weather
+Message: Message 2 from europe
+Message: Message 2 from europe
+Message: Message 2 from news
+Message: Message 2 from news
+Message: Message 2 from usa
+Message: Message 2 from usa
+Message: Message 2 from weather
+Message: Message 2 from weather
+Message: Message 3 from europe
+Message: Message 3 from europe
+Message: Message 3 from news
+Message: Message 3 from news
+Message: Message 3 from usa
+Message: Message 3 from usa
+Message: Message 3 from weather
+Message: Message 3 from weather
+Message: Message 4 from europe
+Message: Message 4 from europe
+Message: Message 4 from news
+Message: Message 4 from news
+Message: Message 4 from usa
+Message: Message 4 from usa
+Message: Message 4 from weather
+Message: Message 4 from weather
+Message: Message 5 from europe
+Message: Message 5 from europe
+Message: Message 5 from news
+Message: Message 5 from news
+Message: Message 5 from usa
+Message: Message 5 from usa
+Message: Message 5 from weather
+Message: Message 5 from weather
+Message: Message 6 from europe
+Message: Message 6 from europe
+Message: Message 6 from news
+Message: Message 6 from news
+Message: Message 6 from usa
+Message: Message 6 from usa
+Message: Message 6 from weather
+Message: Message 6 from weather
+Message: Message 7 from europe
+Message: Message 7 from europe
+Message: Message 7 from news
+Message: Message 7 from news
+Message: Message 7 from usa
+Message: Message 7 from usa
+Message: Message 7 from weather
+Message: Message 7 from weather
+Message: Message 8 from europe
+Message: Message 8 from europe
+Message: Message 8 from news
+Message: Message 8 from news
+Message: Message 8 from usa
+Message: Message 8 from usa
+Message: Message 8 from weather
+Message: Message 8 from weather
+Message: Message 9 from europe
+Message: Message 9 from europe
+Message: Message 9 from news
+Message: Message 9 from news
+Message: Message 9 from usa
+Message: Message 9 from usa
+Message: Message 9 from weather
+Message: Message 9 from weather
+Message: That's all, folks! from europe
+Message: That's all, folks! from news
+Message: That's all, folks! from usa
+Message: That's all, folks! from weather
+Shutting down listener for control
+Shutting down listener for control
+Shutting down listener for control
+Shutting down listener for control
diff --git a/dotnet/client-010/examples/pub-sub/verify_cpp_dotnet b/dotnet/client-010/examples/pub-sub/verify_cpp_dotnet
new file mode 100644
index 0000000000..86d60578ad
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/verify_cpp_dotnet
@@ -0,0 +1,12 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+cpp=$CPP/pub-sub
+
+pubsub_listener_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-pub-sub-Listener.exe localhost 5672
+}
+
+
+background "Listening for messages ..." pubsub_listener_dotnet
+clients $cpp/topic_publisher
+outputs $cpp/topic_publisher.out "pubsub_listener_dotnet.out | remove_uuid | sort"
diff --git a/dotnet/client-010/examples/pub-sub/verify_cpp_dotnet.in b/dotnet/client-010/examples/pub-sub/verify_cpp_dotnet.in
new file mode 100644
index 0000000000..4e058f7645
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/verify_cpp_dotnet.in
@@ -0,0 +1,55 @@
+==== topic_publisher.out
+==== pubsub_listener_dotnet.out | remove_uuid | sort
+Declaring queue: europe
+Declaring queue: news
+Declaring queue: usa
+Declaring queue: weather
+Listening for messages ...
+Message: Message 0 from europe
+Message: Message 0 from europe
+Message: Message 0 from news
+Message: Message 0 from news
+Message: Message 0 from usa
+Message: Message 0 from usa
+Message: Message 0 from weather
+Message: Message 0 from weather
+Message: Message 1 from europe
+Message: Message 1 from europe
+Message: Message 1 from news
+Message: Message 1 from news
+Message: Message 1 from usa
+Message: Message 1 from usa
+Message: Message 1 from weather
+Message: Message 1 from weather
+Message: Message 2 from europe
+Message: Message 2 from europe
+Message: Message 2 from news
+Message: Message 2 from news
+Message: Message 2 from usa
+Message: Message 2 from usa
+Message: Message 2 from weather
+Message: Message 2 from weather
+Message: Message 3 from europe
+Message: Message 3 from europe
+Message: Message 3 from news
+Message: Message 3 from news
+Message: Message 3 from usa
+Message: Message 3 from usa
+Message: Message 3 from weather
+Message: Message 3 from weather
+Message: Message 4 from europe
+Message: Message 4 from europe
+Message: Message 4 from news
+Message: Message 4 from news
+Message: Message 4 from usa
+Message: Message 4 from usa
+Message: Message 4 from weather
+Message: Message 4 from weather
+Message: That's all, folks! from europe
+Message: That's all, folks! from news
+Message: That's all, folks! from usa
+Message: That's all, folks! from weather
+Shutting down listener for control
+Shutting down listener for control
+Shutting down listener for control
+Shutting down listener for control
diff --git a/dotnet/client-010/examples/pub-sub/verify_dotnet_cpp b/dotnet/client-010/examples/pub-sub/verify_dotnet_cpp
new file mode 100644
index 0000000000..66d0f5ba52
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/verify_dotnet_cpp
@@ -0,0 +1,11 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+cpp=$CPP/pub-sub
+
+pubsub_producer_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-pub-sub-Publisher.exe localhost 5672
+}
+
+background "Listening" $cpp/topic_listener
+clients pubsub_producer_dotnet
+outputs pubsub_producer_dotnet.out "$cpp/topic_listener.out | remove_uuid | sort"
diff --git a/dotnet/client-010/examples/pub-sub/verify_dotnet_cpp.in b/dotnet/client-010/examples/pub-sub/verify_dotnet_cpp.in
new file mode 100644
index 0000000000..64ac27846d
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/verify_dotnet_cpp.in
@@ -0,0 +1,99 @@
+==== pubsub_producer_dotnet.out
+==== topic_listener.out | remove_uuid | sort
+Declaring queue: europe
+Declaring queue: news
+Declaring queue: usa
+Declaring queue: weather
+Listening for messages ...
+Message: Message 0 from europe
+Message: Message 0 from europe
+Message: Message 0 from news
+Message: Message 0 from news
+Message: Message 0 from usa
+Message: Message 0 from usa
+Message: Message 0 from weather
+Message: Message 0 from weather
+Message: Message 1 from europe
+Message: Message 1 from europe
+Message: Message 1 from news
+Message: Message 1 from news
+Message: Message 1 from usa
+Message: Message 1 from usa
+Message: Message 1 from weather
+Message: Message 1 from weather
+Message: Message 2 from europe
+Message: Message 2 from europe
+Message: Message 2 from news
+Message: Message 2 from news
+Message: Message 2 from usa
+Message: Message 2 from usa
+Message: Message 2 from weather
+Message: Message 2 from weather
+Message: Message 3 from europe
+Message: Message 3 from europe
+Message: Message 3 from news
+Message: Message 3 from news
+Message: Message 3 from usa
+Message: Message 3 from usa
+Message: Message 3 from weather
+Message: Message 3 from weather
+Message: Message 4 from europe
+Message: Message 4 from europe
+Message: Message 4 from news
+Message: Message 4 from news
+Message: Message 4 from usa
+Message: Message 4 from usa
+Message: Message 4 from weather
+Message: Message 4 from weather
+Message: Message 5 from europe
+Message: Message 5 from europe
+Message: Message 5 from news
+Message: Message 5 from news
+Message: Message 5 from usa
+Message: Message 5 from usa
+Message: Message 5 from weather
+Message: Message 5 from weather
+Message: Message 6 from europe
+Message: Message 6 from europe
+Message: Message 6 from news
+Message: Message 6 from news
+Message: Message 6 from usa
+Message: Message 6 from usa
+Message: Message 6 from weather
+Message: Message 6 from weather
+Message: Message 7 from europe
+Message: Message 7 from europe
+Message: Message 7 from news
+Message: Message 7 from news
+Message: Message 7 from usa
+Message: Message 7 from usa
+Message: Message 7 from weather
+Message: Message 7 from weather
+Message: Message 8 from europe
+Message: Message 8 from europe
+Message: Message 8 from news
+Message: Message 8 from news
+Message: Message 8 from usa
+Message: Message 8 from usa
+Message: Message 8 from weather
+Message: Message 8 from weather
+Message: Message 9 from europe
+Message: Message 9 from europe
+Message: Message 9 from news
+Message: Message 9 from news
+Message: Message 9 from usa
+Message: Message 9 from usa
+Message: Message 9 from weather
+Message: Message 9 from weather
+Message: That's all, folks! from europe
+Message: That's all, folks! from news
+Message: That's all, folks! from usa
+Message: That's all, folks! from weather
+Shutting down listener for europe
+Shutting down listener for news
+Shutting down listener for usa
+Shutting down listener for weather
+Subscribing to queue europe
+Subscribing to queue news
+Subscribing to queue usa
+Subscribing to queue weather
diff --git a/dotnet/client-010/examples/pub-sub/verify_dotnet_java b/dotnet/client-010/examples/pub-sub/verify_dotnet_java
new file mode 100644
index 0000000000..0b90416a7e
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/verify_dotnet_java
@@ -0,0 +1,15 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+
+topic_listener_java()
+{
+java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.pubsub.Listener
+}
+
+pubsub_producer_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-pub-sub-Publisher.exe localhost 5672
+}
+
+background "can receive messages" topic_listener_java
+clients pubsub_producer_dotnet
+outputs pubsub_producer_dotnet.out "topic_listener_java.out | remove_uuid | sort"
diff --git a/dotnet/client-010/examples/pub-sub/verify_dotnet_java.in b/dotnet/client-010/examples/pub-sub/verify_dotnet_java.in
new file mode 100644
index 0000000000..5db02e64b1
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/verify_dotnet_java.in
@@ -0,0 +1,95 @@
+==== pubsub_producer_dotnet.out
+==== topic_listener_java.out | remove_uuid | sort
+Listener: Closing connection
+Listener: Closing JNDI context
+Listener: Creating a Message Subscriber for topic europe
+Listener: Creating a Message Subscriber for topic news
+Listener: Creating a Message Subscriber for topic usa
+Listener: Creating a Message Subscriber for topic weather
+Listener: Creating a non-transacted, auto-acknowledged session
+Listener: Received message for topic: europe: Message 0
+Listener: Received message for topic: europe: Message 0
+Listener: Received message for topic: europe: Message 1
+Listener: Received message for topic: europe: Message 1
+Listener: Received message for topic: europe: Message 2
+Listener: Received message for topic: europe: Message 2
+Listener: Received message for topic: europe: Message 3
+Listener: Received message for topic: europe: Message 3
+Listener: Received message for topic: europe: Message 4
+Listener: Received message for topic: europe: Message 4
+Listener: Received message for topic: europe: Message 5
+Listener: Received message for topic: europe: Message 5
+Listener: Received message for topic: europe: Message 6
+Listener: Received message for topic: europe: Message 6
+Listener: Received message for topic: europe: Message 7
+Listener: Received message for topic: europe: Message 7
+Listener: Received message for topic: europe: Message 8
+Listener: Received message for topic: europe: Message 8
+Listener: Received message for topic: europe: Message 9
+Listener: Received message for topic: europe: Message 9
+Listener: Received message for topic: news: Message 0
+Listener: Received message for topic: news: Message 0
+Listener: Received message for topic: news: Message 1
+Listener: Received message for topic: news: Message 1
+Listener: Received message for topic: news: Message 2
+Listener: Received message for topic: news: Message 2
+Listener: Received message for topic: news: Message 3
+Listener: Received message for topic: news: Message 3
+Listener: Received message for topic: news: Message 4
+Listener: Received message for topic: news: Message 4
+Listener: Received message for topic: news: Message 5
+Listener: Received message for topic: news: Message 5
+Listener: Received message for topic: news: Message 6
+Listener: Received message for topic: news: Message 6
+Listener: Received message for topic: news: Message 7
+Listener: Received message for topic: news: Message 7
+Listener: Received message for topic: news: Message 8
+Listener: Received message for topic: news: Message 8
+Listener: Received message for topic: news: Message 9
+Listener: Received message for topic: news: Message 9
+Listener: Received message for topic: usa: Message 0
+Listener: Received message for topic: usa: Message 0
+Listener: Received message for topic: usa: Message 1
+Listener: Received message for topic: usa: Message 1
+Listener: Received message for topic: usa: Message 2
+Listener: Received message for topic: usa: Message 2
+Listener: Received message for topic: usa: Message 3
+Listener: Received message for topic: usa: Message 3
+Listener: Received message for topic: usa: Message 4
+Listener: Received message for topic: usa: Message 4
+Listener: Received message for topic: usa: Message 5
+Listener: Received message for topic: usa: Message 5
+Listener: Received message for topic: usa: Message 6
+Listener: Received message for topic: usa: Message 6
+Listener: Received message for topic: usa: Message 7
+Listener: Received message for topic: usa: Message 7
+Listener: Received message for topic: usa: Message 8
+Listener: Received message for topic: usa: Message 8
+Listener: Received message for topic: usa: Message 9
+Listener: Received message for topic: usa: Message 9
+Listener: Received message for topic: weather: Message 0
+Listener: Received message for topic: weather: Message 0
+Listener: Received message for topic: weather: Message 1
+Listener: Received message for topic: weather: Message 1
+Listener: Received message for topic: weather: Message 2
+Listener: Received message for topic: weather: Message 2
+Listener: Received message for topic: weather: Message 3
+Listener: Received message for topic: weather: Message 3
+Listener: Received message for topic: weather: Message 4
+Listener: Received message for topic: weather: Message 4
+Listener: Received message for topic: weather: Message 5
+Listener: Received message for topic: weather: Message 5
+Listener: Received message for topic: weather: Message 6
+Listener: Received message for topic: weather: Message 6
+Listener: Received message for topic: weather: Message 7
+Listener: Received message for topic: weather: Message 7
+Listener: Received message for topic: weather: Message 8
+Listener: Received message for topic: weather: Message 8
+Listener: Received message for topic: weather: Message 9
+Listener: Received message for topic: weather: Message 9
+Listener: Setting an ExceptionListener on the connection as sample uses a TopicSubscriber
+Listener: Shutting down listener for europe
+Listener: Shutting down listener for news
+Listener: Shutting down listener for usa
+Listener: Shutting down listener for weather
+Listener: Starting connection so TopicSubscriber can receive messages
diff --git a/dotnet/client-010/examples/pub-sub/verify_dotnet_python b/dotnet/client-010/examples/pub-sub/verify_dotnet_python
new file mode 100644
index 0000000000..dd62dbcbeb
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/verify_dotnet_python
@@ -0,0 +1,11 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+py=$PYTHON_EXAMPLES/pubsub
+
+pubsub_producer_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-pub-sub-Publisher.exe localhost 5672
+}
+
+background "Queues created" $py/topic_subscriber.py
+clients pubsub_producer_dotnet
+outputs ./pubsub_producer_dotnet.out "$py/topic_subscriber.py.out | remove_uuid | sort"
diff --git a/dotnet/client-010/examples/pub-sub/verify_dotnet_python.in b/dotnet/client-010/examples/pub-sub/verify_dotnet_python.in
new file mode 100644
index 0000000000..130efa2b0e
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/verify_dotnet_python.in
@@ -0,0 +1,95 @@
+==== pubsub_producer_dotnet.out
+==== topic_subscriber.py.out | remove_uuid | sort
+Message 0
+Message 0
+Message 0
+Message 0
+Message 0
+Message 0
+Message 0
+Message 0
+Message 1
+Message 1
+Message 1
+Message 1
+Message 1
+Message 1
+Message 1
+Message 1
+Message 2
+Message 2
+Message 2
+Message 2
+Message 2
+Message 2
+Message 2
+Message 2
+Message 3
+Message 3
+Message 3
+Message 3
+Message 3
+Message 3
+Message 3
+Message 3
+Message 4
+Message 4
+Message 4
+Message 4
+Message 4
+Message 4
+Message 4
+Message 4
+Message 5
+Message 5
+Message 5
+Message 5
+Message 5
+Message 5
+Message 5
+Message 5
+Message 6
+Message 6
+Message 6
+Message 6
+Message 6
+Message 6
+Message 6
+Message 6
+Message 7
+Message 7
+Message 7
+Message 7
+Message 7
+Message 7
+Message 7
+Message 7
+Message 8
+Message 8
+Message 8
+Message 8
+Message 8
+Message 8
+Message 8
+Message 8
+Message 9
+Message 9
+Message 9
+Message 9
+Message 9
+Message 9
+Message 9
+Message 9
+Messages on 'europe' queue:
+Messages on 'news' queue:
+Messages on 'usa' queue:
+Messages on 'weather' queue:
+Queues created - please start the topic producer
+Subscribing local queue 'local_europe' to europe-'
+Subscribing local queue 'local_news' to news-'
+Subscribing local queue 'local_usa' to usa-'
+Subscribing local queue 'local_weather' to weather-'
+That's all, folks!
+That's all, folks!
+That's all, folks!
+That's all, folks!
diff --git a/dotnet/client-010/examples/pub-sub/verify_java_dotnet b/dotnet/client-010/examples/pub-sub/verify_java_dotnet
new file mode 100644
index 0000000000..52069957c5
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/verify_java_dotnet
@@ -0,0 +1,15 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+
+pubsub_listener_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-pub-sub-Listener.exe localhost 5672
+}
+
+topic_publisher_java()
+{
+java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.pubsub.Publisher
+}
+
+background "Listening for messages ..." pubsub_listener_dotnet
+clients topic_publisher_java
+outputs topic_publisher_java.out "pubsub_listener_dotnet.out | remove_uuid | sort"
diff --git a/dotnet/client-010/examples/pub-sub/verify_java_dotnet.in b/dotnet/client-010/examples/pub-sub/verify_java_dotnet.in
new file mode 100644
index 0000000000..1b37f711c4
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/verify_java_dotnet.in
@@ -0,0 +1,95 @@
+==== topic_publisher_java.out
+Publisher: Creating a non-transacted, auto-acknowledged session
+Publisher: Creating a TestMessage to send to the topics
+Publisher: Creating a Message Publisher for topic usa.weather
+Publisher: Sending message 1
+Publisher: Sending message 2
+Publisher: Sending message 3
+Publisher: Sending message 4
+Publisher: Sending message 5
+Publisher: Sending message 6
+Publisher: Creating a Message Publisher for topic usa.news
+Publisher: Sending message 1
+Publisher: Sending message 2
+Publisher: Sending message 3
+Publisher: Sending message 4
+Publisher: Sending message 5
+Publisher: Sending message 6
+Publisher: Creating a Message Publisher for topic europe.weather
+Publisher: Sending message 1
+Publisher: Sending message 2
+Publisher: Sending message 3
+Publisher: Sending message 4
+Publisher: Sending message 5
+Publisher: Sending message 6
+Publisher: Creating a Message Publisher for topic europe.news
+Publisher: Sending message 1
+Publisher: Sending message 2
+Publisher: Sending message 3
+Publisher: Sending message 4
+Publisher: Sending message 5
+Publisher: Sending message 6
+Publisher: Closing connection
+Publisher: Closing JNDI context
+==== pubsub_listener_dotnet.out | remove_uuid | sort
+Declaring queue: europe
+Declaring queue: news
+Declaring queue: usa
+Declaring queue: weather
+Listening for messages ...
+Message: message 1 from europe
+Message: message 1 from europe
+Message: message 1 from news
+Message: message 1 from news
+Message: message 1 from usa
+Message: message 1 from usa
+Message: message 1 from weather
+Message: message 1 from weather
+Message: message 2 from europe
+Message: message 2 from europe
+Message: message 2 from news
+Message: message 2 from news
+Message: message 2 from usa
+Message: message 2 from usa
+Message: message 2 from weather
+Message: message 2 from weather
+Message: message 3 from europe
+Message: message 3 from europe
+Message: message 3 from news
+Message: message 3 from news
+Message: message 3 from usa
+Message: message 3 from usa
+Message: message 3 from weather
+Message: message 3 from weather
+Message: message 4 from europe
+Message: message 4 from europe
+Message: message 4 from news
+Message: message 4 from news
+Message: message 4 from usa
+Message: message 4 from usa
+Message: message 4 from weather
+Message: message 4 from weather
+Message: message 5 from europe
+Message: message 5 from europe
+Message: message 5 from news
+Message: message 5 from news
+Message: message 5 from usa
+Message: message 5 from usa
+Message: message 5 from weather
+Message: message 5 from weather
+Message: message 6 from europe
+Message: message 6 from europe
+Message: message 6 from news
+Message: message 6 from news
+Message: message 6 from usa
+Message: message 6 from usa
+Message: message 6 from weather
+Message: message 6 from weather
+Message: That's all, folks! from europe
+Message: That's all, folks! from news
+Message: That's all, folks! from usa
+Message: That's all, folks! from weather
+Shutting down listener for control
+Shutting down listener for control
+Shutting down listener for control
+Shutting down listener for control
diff --git a/dotnet/client-010/examples/pub-sub/verify_python_dotnet b/dotnet/client-010/examples/pub-sub/verify_python_dotnet
new file mode 100644
index 0000000000..0366e3a9ac
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/verify_python_dotnet
@@ -0,0 +1,11 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+py=$PYTHON_EXAMPLES/pubsub
+
+pubsub_listener_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-pub-sub-Listener.exe localhost 5672
+}
+
+background "Listening for messages ..." pubsub_listener_dotnet
+clients $py/topic_publisher.py
+outputs $py/topic_publisher.py.out "pubsub_listener_dotnet.out | remove_uuid | sort"
diff --git a/dotnet/client-010/examples/pub-sub/verify_python_dotnet.in b/dotnet/client-010/examples/pub-sub/verify_python_dotnet.in
new file mode 100644
index 0000000000..ac1b681b32
--- /dev/null
+++ b/dotnet/client-010/examples/pub-sub/verify_python_dotnet.in
@@ -0,0 +1,55 @@
+==== topic_publisher.py.out
+==== pubsub_listener_dotnet.out | remove_uuid | sort
+Declaring queue: europe
+Declaring queue: news
+Declaring queue: usa
+Declaring queue: weather
+Listening for messages ...
+Message: europe.news 0 from europe
+Message: europe.news 0 from news
+Message: europe.news 1 from europe
+Message: europe.news 1 from news
+Message: europe.news 2 from europe
+Message: europe.news 2 from news
+Message: europe.news 3 from europe
+Message: europe.news 3 from news
+Message: europe.news 4 from europe
+Message: europe.news 4 from news
+Message: europe.weather 0 from europe
+Message: europe.weather 0 from weather
+Message: europe.weather 1 from europe
+Message: europe.weather 1 from weather
+Message: europe.weather 2 from europe
+Message: europe.weather 2 from weather
+Message: europe.weather 3 from europe
+Message: europe.weather 3 from weather
+Message: europe.weather 4 from europe
+Message: europe.weather 4 from weather
+Message: That's all, folks! from europe
+Message: That's all, folks! from news
+Message: That's all, folks! from usa
+Message: That's all, folks! from weather
+Message: usa.news 0 from news
+Message: usa.news 0 from usa
+Message: usa.news 1 from news
+Message: usa.news 1 from usa
+Message: usa.news 2 from news
+Message: usa.news 2 from usa
+Message: usa.news 3 from news
+Message: usa.news 3 from usa
+Message: usa.news 4 from news
+Message: usa.news 4 from usa
+Message: usa.weather 0 from usa
+Message: usa.weather 0 from weather
+Message: usa.weather 1 from usa
+Message: usa.weather 1 from weather
+Message: usa.weather 2 from usa
+Message: usa.weather 2 from weather
+Message: usa.weather 3 from usa
+Message: usa.weather 3 from weather
+Message: usa.weather 4 from usa
+Message: usa.weather 4 from weather
+Shutting down listener for control
+Shutting down listener for control
+Shutting down listener for control
+Shutting down listener for control
diff --git a/dotnet/client-010/examples/request-response/example-request-response-Client/Properties/AssemblyInfo.cs b/dotnet/client-010/examples/request-response/example-request-response-Client/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..a438acaa1f
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/example-request-response-Client/Properties/AssemblyInfo.cs
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("example-request-response-Client")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("example-request-response-Client")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("08bf6aed-bf79-4d16-9a28-6363d5322cdd")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/client-010/examples/request-response/example-request-response-Client/RequestResponseClient.cs b/dotnet/client-010/examples/request-response/example-request-response-Client/RequestResponseClient.cs
new file mode 100644
index 0000000000..170008c840
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/example-request-response-Client/RequestResponseClient.cs
@@ -0,0 +1,142 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System;
+using System.Configuration;
+using System.IO;
+using System.Text;
+using System.Threading;
+using org.apache.qpid.client;
+using org.apache.qpid.transport;
+
+namespace org.apache.qpid.example.requestresponse
+{
+ /// <summary>
+ /// This program is one of two programs that illustrate the
+ /// request/response pattern.
+ ///
+ /// Client (this program):
+ /// Make requests of a service, print the response.
+ ///
+ /// Server:
+ /// Accept requests, set the letters to uppercase in each message, and
+ /// return it as a response.
+ ///
+ /// </summary>
+ internal class RequestResponseClient
+ {
+ private static void Main(string[] args)
+ {
+ string host = ConfigurationManager.AppSettings["Host"];
+ int port = int.Parse(ConfigurationManager.AppSettings["Port"]);
+ string virtualhost = ConfigurationManager.AppSettings["VirtualHost"];
+ string username = ConfigurationManager.AppSettings["Username"];
+ string password = ConfigurationManager.AppSettings["Password"];
+
+ Client connection = new Client();
+ try
+ {
+ connection.Connect(host, port, virtualhost, username, password);
+ IClientSession session = connection.CreateSession(50000);
+ IMessage request = new Message();
+
+ //--------- Main body of program --------------------------------------------
+ // Create a response queue so the server can send us responses
+ // to our requests. Use the client's session ID as the name
+ // of the response queue.
+ string response_queue = "client" + session.GetName();
+ // Use the name of the response queue as the routing key
+ session.QueueDeclare(response_queue);
+ session.ExchangeBind(response_queue, "amq.direct", response_queue);
+
+ // Each client sends the name of their own response queue so
+ // the service knows where to route messages.
+ request.DeliveryProperties.SetRoutingKey("request");
+ request.MessageProperties.SetReplyTo(new ReplyTo("amq.direct", response_queue));
+
+ lock (session)
+ {
+ // Create a listener for the response queue and listen for response messages.
+ Console.WriteLine("Activating response queue listener for: " + response_queue);
+ IMessageListener listener = new ClientMessageListener(session);
+ session.AttachMessageListener(listener, response_queue);
+ session.MessageSubscribe(response_queue);
+
+ // Now send some requests ...
+ string[] strs = {
+ "Twas brillig, and the slithy toves",
+ "Did gire and gymble in the wabe.",
+ "All mimsy were the borogroves,",
+ "And the mome raths outgrabe.",
+ "That's all, folks!"
+ };
+ foreach (string s in strs)
+ {
+ request.ClearData();
+ request.AppendData(Encoding.UTF8.GetBytes(s));
+ session.MessageTransfer("amq.direct", request);
+ }
+ Console.WriteLine("Waiting for all responses to arrive ...");
+ Monitor.Wait(session);
+ }
+ //---------------------------------------------------------------------------
+
+ connection.Close();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Error: \n" + e.StackTrace);
+ }
+ }
+ }
+
+ public class ClientMessageListener : IMessageListener
+ {
+ private readonly IClientSession _session;
+ private readonly RangeSet _range = new RangeSet();
+ private int _counter;
+ public ClientMessageListener(IClientSession session)
+ {
+ _session = session;
+ }
+
+ public void MessageTransfer(IMessage m)
+ {
+ _counter++;
+ BinaryReader reader = new BinaryReader(m.Body, Encoding.UTF8);
+ byte[] body = new byte[m.Body.Length - m.Body.Position];
+ reader.Read(body, 0, body.Length);
+ ASCIIEncoding enc = new ASCIIEncoding();
+ string message = enc.GetString(body);
+ Console.WriteLine("Response: " + message);
+ // Add this message to the list of message to be acknowledged
+ _range.Add(m.Id);
+ if (_counter == 4)
+ {
+ Console.WriteLine("Shutting down listener for " + m.DeliveryProperties.GetRoutingKey());
+ // Acknowledge all the received messages
+ _session.MessageAccept(_range);
+ lock (_session)
+ {
+ Monitor.Pulse(_session);
+ }
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/examples/request-response/example-request-response-Client/default.build b/dotnet/client-010/examples/request-response/example-request-response-Client/default.build
new file mode 100644
index 0000000000..c3d9af9baf
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/example-request-response-Client/default.build
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="example-request-response-Client" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="exe"
+ define="${build.defines}"
+ debug="${build.debug}"
+ output="${build.dir}/${project::get-name()}.exe">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ <include name="${build.dir}/log4net.dll" />
+ <include name="${build.dir}/qpid.client.dll" />
+ <include name="System.Configuration.dll" />
+ </references>
+ </csc>
+ </target>
+</project>
+
diff --git a/dotnet/client-010/examples/request-response/example-request-response-Client/example-request-response-Client.csproj b/dotnet/client-010/examples/request-response/example-request-response-Client/example-request-response-Client.csproj
new file mode 100644
index 0000000000..858f4eaf13
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/example-request-response-Client/example-request-response-Client.csproj
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{1BC63815-4029-4039-9207-35E7E06ECC99}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>example_request_response_Client</RootNamespace>
+ <AssemblyName>example-request-response-Client</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.configuration" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="RequestResponseClient.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\client\Client.csproj">
+ <Project>{B911FFD7-754F-4735-A188-218D5065BE79}</Project>
+ <Name>Client</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\..\App.config">
+ <Link>App.config</Link>
+ </None>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/dotnet/client-010/examples/request-response/example-request-response-Server/Properties/AssemblyInfo.cs b/dotnet/client-010/examples/request-response/example-request-response-Server/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..ba702a28cc
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/example-request-response-Server/Properties/AssemblyInfo.cs
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("example-request-response-Server")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("example-request-response-Server")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("ef3456e2-7c19-47aa-8dd6-aeaa88c5c4ad")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/client-010/examples/request-response/example-request-response-Server/Server.cs b/dotnet/client-010/examples/request-response/example-request-response-Server/Server.cs
new file mode 100644
index 0000000000..ea87627dbf
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/example-request-response-Server/Server.cs
@@ -0,0 +1,141 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System;
+using System.Configuration;
+using System.IO;
+using System.Text;
+using System.Threading;
+using org.apache.qpid.client;
+using org.apache.qpid.transport;
+
+namespace org.apache.qpid.example.requestresponse
+{
+ /// <summary>
+ /// This program is one of two programs that illustrate the
+ /// request/response pattern.
+ ///
+ /// Client:
+ /// Make requests of a service, print the response.
+ ///
+ /// Server (this program):
+ /// Accept requests, set the letters to uppercase in each message, and
+ /// return it as a response.
+ ///
+ /// </summary>
+ class Server
+ {
+ static void Main(string[] args)
+ {
+ string host = ConfigurationManager.AppSettings["Host"];
+ int port = int.Parse(ConfigurationManager.AppSettings["Port"]);
+ string virtualhost = ConfigurationManager.AppSettings["VirtualHost"];
+ string username = ConfigurationManager.AppSettings["Username"];
+ string password = ConfigurationManager.AppSettings["Password"];
+
+ Client connection = new Client();
+ try
+ {
+ connection.Connect(host, port, virtualhost, username, password);
+ IClientSession session = connection.CreateSession(50000);
+
+ //--------- Main body of program --------------------------------------------
+ // Create a request queue for clients to use when making
+ // requests.
+ const string request_queue = "request";
+ // Use the name of the request queue as the routing key
+ session.QueueDeclare(request_queue);
+ session.ExchangeBind(request_queue, "amq.direct", request_queue);
+
+ lock (session)
+ {
+ // Create a listener and subscribe it to the request_queue
+ IMessageListener listener = new MessageListener(session);
+ session.AttachMessageListener(listener, request_queue);
+ session.MessageSubscribe(request_queue);
+ // Receive messages until all messages are received
+ Console.WriteLine("Waiting for requests");
+ Monitor.Wait(session);
+ }
+
+ //---------------------------------------------------------------------------
+
+ connection.Close();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Error: \n" + e.StackTrace);
+ }
+ }
+ }
+
+ public class MessageListener : IMessageListener
+ {
+ private readonly IClientSession _session;
+ private readonly RangeSet _range = new RangeSet();
+ public MessageListener(IClientSession session)
+ {
+ _session = session;
+ }
+
+ public void MessageTransfer(IMessage request)
+ {
+ IMessage response = new Message();
+
+ // Get routing key for response from the request's replyTo property
+ string routingKey;
+ if( request.MessageProperties.HasReplyTo() )
+ {
+ routingKey = request.MessageProperties.GetReplyTo().GetRoutingKey();
+ }
+ else
+ {
+ Console.WriteLine("Error: \n No routing key for request " + request);
+ return;
+ }
+
+ BinaryReader reader = new BinaryReader(request.Body, Encoding.UTF8);
+ byte[] body = new byte[request.Body.Length - request.Body.Position];
+ reader.Read(body, 0, body.Length);
+ ASCIIEncoding enc = new ASCIIEncoding();
+ string message = enc.GetString(body);
+ Console.WriteLine("Request: " + message);
+
+ // Transform message content to upper case
+ string responseBody = message.ToUpper();
+
+ // Send it back to the user
+ response.ClearData();
+ response.AppendData(Encoding.UTF8.GetBytes(responseBody));
+ _session.MessageTransfer("amq.direct", routingKey, response);
+
+ // Add this message to the list of message to be acknowledged
+ _range.Add(request.Id);
+ if (message.Equals("That's all, folks!"))
+ {
+ // Acknowledge all the received messages
+ _session.MessageAccept(_range);
+ lock (_session)
+ {
+ Monitor.Pulse(_session);
+ }
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/examples/request-response/example-request-response-Server/default.build b/dotnet/client-010/examples/request-response/example-request-response-Server/default.build
new file mode 100644
index 0000000000..a3e4691d10
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/example-request-response-Server/default.build
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="example-request-response-Server" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="exe"
+ define="${build.defines}"
+ debug="${build.debug}"
+ output="${build.dir}/${project::get-name()}.exe">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ <include name="${build.dir}/log4net.dll" />
+ <include name="${build.dir}/qpid.client.dll" />
+ <include name="System.Configuration.dll" />
+ </references>
+ </csc>
+ </target>
+</project>
+
diff --git a/dotnet/client-010/examples/request-response/example-request-response-Server/example-request-response-Server.csproj b/dotnet/client-010/examples/request-response/example-request-response-Server/example-request-response-Server.csproj
new file mode 100644
index 0000000000..71ae819961
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/example-request-response-Server/example-request-response-Server.csproj
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{922FBA9C-E483-4AEF-ABE8-AC87421E829B}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>example_request_response_Server</RootNamespace>
+ <AssemblyName>example-request-response-Server</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.configuration" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Server.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\client\Client.csproj">
+ <Project>{B911FFD7-754F-4735-A188-218D5065BE79}</Project>
+ <Name>Client</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\..\App.config">
+ <Link>App.config</Link>
+ </None>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/dotnet/client-010/examples/request-response/verify b/dotnet/client-010/examples/request-response/verify
new file mode 100644
index 0000000000..fa69461f68
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/verify
@@ -0,0 +1,36 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+
+server_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-request-response-Server.exe localhost 5672
+}
+
+client_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-request-response-Client.exe localhost 5672
+}
+
+background "Waiting for requests" server_dotnet
+clients client_dotnet
+outputs ./server_dotnet.out ./client_dotnet.out
diff --git a/dotnet/client-010/examples/request-response/verify.in b/dotnet/client-010/examples/request-response/verify.in
new file mode 100644
index 0000000000..5357591289
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/verify.in
@@ -0,0 +1,16 @@
+==== server_dotnet.out
+Waiting for requests
+Request: Twas brillig, and the slithy toves
+Request: Did gire and gymble in the wabe.
+Request: All mimsy were the borogroves,
+Request: And the mome raths outgrabe.
+Request: That's all, folks!
+==== client_dotnet.out
+Activating response queue listener for: clientSystem.Byte[]
+Waiting for all responses to arrive ...
+Response: TWAS BRILLIG, AND THE SLITHY TOVES
+Response: DID GIRE AND GYMBLE IN THE WABE.
+Response: ALL MIMSY WERE THE BOROGROVES,
+Response: AND THE MOME RATHS OUTGRABE.
+Shutting down listener for clientSystem.Byte[]
+Response: THAT'S ALL, FOLKS!
diff --git a/dotnet/client-010/examples/request-response/verify_cpp_dotnet b/dotnet/client-010/examples/request-response/verify_cpp_dotnet
new file mode 100644
index 0000000000..3cc0370ada
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/verify_cpp_dotnet
@@ -0,0 +1,12 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+cpp=$CPP/request-response
+
+client_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-request-response-Client.exe localhost 5672
+}
+
+background "Waiting" $cpp/server
+clients client_dotnet
+kill %%
+outputs ./client_dotnet.out "$cpp/server.out | remove_uuid"
diff --git a/dotnet/client-010/examples/request-response/verify_cpp_dotnet.in b/dotnet/client-010/examples/request-response/verify_cpp_dotnet.in
new file mode 100644
index 0000000000..0f4b5341b2
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/verify_cpp_dotnet.in
@@ -0,0 +1,17 @@
+==== client_dotnet.out
+Activating response queue listener for: clientSystem.Byte[]
+Waiting for all responses to arrive ...
+Response: TWAS BRILLIG, AND THE SLITHY TOVES
+Response: DID GIRE AND GYMBLE IN THE WABE.
+Response: ALL MIMSY WERE THE BOROGROVES,
+Response: AND THE MOME RATHS OUTGRABE.
+Shutting down listener for clientSystem.Byte[]
+Response: THAT'S ALL, FOLKS!
+==== server.out | remove_uuid
+Activating request queue listener for: request
+Waiting for requests
+Request: Twas brillig, and the slithy toves (clientSystem.Byte[])
+Request: Did gire and gymble in the wabe. (clientSystem.Byte[])
+Request: All mimsy were the borogroves, (clientSystem.Byte[])
+Request: And the mome raths outgrabe. (clientSystem.Byte[])
+Request: That's all, folks! (clientSystem.Byte[])
diff --git a/dotnet/client-010/examples/request-response/verify_dotnet_cpp b/dotnet/client-010/examples/request-response/verify_dotnet_cpp
new file mode 100644
index 0000000000..81b86a0b41
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/verify_dotnet_cpp
@@ -0,0 +1,12 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+cpp=$CPP/request-response
+
+server_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-request-response-Server.exe localhost 5672
+}
+
+background "Waiting for requests" server_dotnet
+clients $cpp/client
+kill %%
+outputs "$cpp/client.out | remove_uuid" ./server_dotnet.out
diff --git a/dotnet/client-010/examples/request-response/verify_dotnet_cpp.in b/dotnet/client-010/examples/request-response/verify_dotnet_cpp.in
new file mode 100644
index 0000000000..849fad39c6
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/verify_dotnet_cpp.in
@@ -0,0 +1,18 @@
+==== client.out | remove_uuid
+Activating response queue listener for: client
+Request: Twas brillig, and the slithy toves
+Request: Did gire and gymble in the wabe.
+Request: All mimsy were the borogroves,
+Request: And the mome raths outgrabe.
+Waiting for all responses to arrive ...
+Response: TWAS BRILLIG, AND THE SLITHY TOVES
+Response: DID GIRE AND GYMBLE IN THE WABE.
+Response: ALL MIMSY WERE THE BOROGROVES,
+Response: AND THE MOME RATHS OUTGRABE.
+Shutting down listener for client
+==== server_dotnet.out
+Waiting for requests
+Request: Twas brillig, and the slithy toves
+Request: Did gire and gymble in the wabe.
+Request: All mimsy were the borogroves,
+Request: And the mome raths outgrabe.
diff --git a/dotnet/client-010/examples/request-response/verify_dotnet_java b/dotnet/client-010/examples/request-response/verify_dotnet_java
new file mode 100644
index 0000000000..56477c623a
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/verify_dotnet_java
@@ -0,0 +1,16 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+
+server_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-request-response-Server.exe localhost 5672
+}
+
+client_java()
+{
+java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.requestResponse.Client
+}
+
+background "Waiting for requests" server_dotnet
+clients client_java
+kill %%
+outputs ./server_dotnet.out "client_java.out | remove_uuid"
diff --git a/dotnet/client-010/examples/request-response/verify_dotnet_java.in b/dotnet/client-010/examples/request-response/verify_dotnet_java.in
new file mode 100644
index 0000000000..96e8b8a255
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/verify_dotnet_java.in
@@ -0,0 +1,21 @@
+==== server_dotnet.out
+Waiting for requests
+Request: Twas brillig, and the slithy toves
+Request: Did gire and gymble in the wabe.
+Request: All mimsy were the borogroves,
+Request: And the mome raths outgrabe.
+==== client_java.out | remove_uuid
+Client: Setting an ExceptionListener on the connection as sample uses a MessageConsumer
+Client: Creating a non-transacted, auto-acknowledged session
+Client: Creating a QueueRequestor
+Client: Starting connection
+Client: Request Content= Twas brillig, and the slithy toves
+Client: Response Content= TWAS BRILLIG, AND THE SLITHY TOVES
+Client: Request Content= Did gire and gymble in the wabe.
+Client: Response Content= DID GIRE AND GYMBLE IN THE WABE.
+Client: Request Content= All mimsy were the borogroves,
+Client: Response Content= ALL MIMSY WERE THE BOROGROVES,
+Client: Request Content= And the mome raths outgrabe.
+Client: Response Content= AND THE MOME RATHS OUTGRABE.
+Client: Closing connection
+Client: Closing JNDI context
diff --git a/dotnet/client-010/examples/request-response/verify_dotnet_python b/dotnet/client-010/examples/request-response/verify_dotnet_python
new file mode 100644
index 0000000000..8ae2f41361
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/verify_dotnet_python
@@ -0,0 +1,12 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+py=$PYTHON_EXAMPLES/request-response
+
+server_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-request-response-Server.exe localhost 5672
+}
+
+background "Waiting for requests" server_dotnet
+clients $py/client.py
+kill %%
+outputs "$py/client.py.out | remove_uuid" "server_dotnet.out | remove_uuid"
diff --git a/dotnet/client-010/examples/request-response/verify_dotnet_python.in b/dotnet/client-010/examples/request-response/verify_dotnet_python.in
new file mode 100644
index 0000000000..4455f4e133
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/verify_dotnet_python.in
@@ -0,0 +1,17 @@
+==== client.py.out | remove_uuid
+Request: Twas brillig, and the slithy toves
+Request: Did gyre and gimble in the wabe.
+Request: All mimsy were the borogroves,
+Request: And the mome raths outgrabe.
+Messages on queue: reply_to:
+Response: TWAS BRILLIG, AND THE SLITHY TOVES
+Response: DID GYRE AND GIMBLE IN THE WABE.
+Response: ALL MIMSY WERE THE BOROGROVES,
+Response: AND THE MOME RATHS OUTGRABE.
+No more messages!
+==== server_dotnet.out | remove_uuid
+Waiting for requests
+Request: Twas brillig, and the slithy toves
+Request: Did gyre and gimble in the wabe.
+Request: All mimsy were the borogroves,
+Request: And the mome raths outgrabe.
diff --git a/dotnet/client-010/examples/request-response/verify_java_dotnet b/dotnet/client-010/examples/request-response/verify_java_dotnet
new file mode 100644
index 0000000000..6950a6a4ec
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/verify_java_dotnet
@@ -0,0 +1,15 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+
+server_java()
+{
+java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.requestResponse.Server
+}
+
+client_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-request-response-Client.exe localhost 5672
+}
+background "can receive messages" server_java
+clients client_dotnet
+kill %%
+outputs "server_java.out | remove_uuid" ./client_dotnet.out
diff --git a/dotnet/client-010/examples/request-response/verify_java_dotnet.in b/dotnet/client-010/examples/request-response/verify_java_dotnet.in
new file mode 100644
index 0000000000..16b1853f37
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/verify_java_dotnet.in
@@ -0,0 +1,36 @@
+==== server_java.out | remove_uuid
+Server: Setting an ExceptionListener on the connection as sample uses a MessageConsumer
+Server: Creating a non-transacted, auto-acknowledged session
+Server: Creating a MessageConsumer
+Server: Creating a MessageProducer
+Server: Starting connection so MessageConsumer can receive messages
+Server: Receiving the message
+Server: Activating response queue listener
+Server: Response = TWAS BRILLIG, AND THE SLITHY TOVES
+
+Server: Receiving the message
+Server: Activating response queue listener
+Server: Response = DID GIRE AND GYMBLE IN THE WABE.
+
+Server: Receiving the message
+Server: Activating response queue listener
+Server: Response = ALL MIMSY WERE THE BOROGROVES,
+
+Server: Receiving the message
+Server: Activating response queue listener
+Server: Response = AND THE MOME RATHS OUTGRABE.
+
+Server: Receiving the message
+Server: Activating response queue listener
+Server: Response = THAT'S ALL, FOLKS!
+
+Server: Receiving the message
+==== client_dotnet.out
+Activating response queue listener for: clientSystem.Byte[]
+Waiting for all responses to arrive ...
+Response: TWAS BRILLIG, AND THE SLITHY TOVES
+Response: DID GIRE AND GYMBLE IN THE WABE.
+Response: ALL MIMSY WERE THE BOROGROVES,
+Response: AND THE MOME RATHS OUTGRABE.
+Shutting down listener for clientSystem.Byte[]
+Response: THAT'S ALL, FOLKS!
diff --git a/dotnet/client-010/examples/request-response/verify_python_dotnet b/dotnet/client-010/examples/request-response/verify_python_dotnet
new file mode 100644
index 0000000000..f1b5d662bd
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/verify_python_dotnet
@@ -0,0 +1,12 @@
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+py=$PYTHON_EXAMPLES/request-response
+
+client_dotnet()
+{
+mono $DOTNET_EXAMPLES/example-request-response-Client.exe localhost 5672
+}
+
+background "Request server running" $py/server.py
+clients client_dotnet
+kill %%
+outputs "client_dotnet.out | remove_uuid" "$py/server.py.out | remove_uuid"
diff --git a/dotnet/client-010/examples/request-response/verify_python_dotnet.in b/dotnet/client-010/examples/request-response/verify_python_dotnet.in
new file mode 100644
index 0000000000..d982a61a04
--- /dev/null
+++ b/dotnet/client-010/examples/request-response/verify_python_dotnet.in
@@ -0,0 +1,12 @@
+==== client_dotnet.out | remove_uuid
+Activating response queue listener for: clientSystem.Byte[]
+Waiting for all responses to arrive ...
+Response: TWAS BRILLIG, AND THE SLITHY TOVES
+Response: DID GIRE AND GYMBLE IN THE WABE.
+Response: ALL MIMSY WERE THE BOROGROVES,
+Response: AND THE MOME RATHS OUTGRABE.
+Shutting down listener for clientSystem.Byte[]
+Response: THAT'S ALL, FOLKS!
+==== server.py.out | remove_uuid
+Request server running - run your client now.
+(Times out after 100 seconds ...)
diff --git a/dotnet/client-010/gentool/Composite.tpl b/dotnet/client-010/gentool/Composite.tpl
new file mode 100644
index 0000000000..c5a1099ef3
--- /dev/null
+++ b/dotnet/client-010/gentool/Composite.tpl
@@ -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.
+ *
+ */
+
+using System;
+using org.apache.qpid.transport.codec;
+using System.Collections.Generic;
+using org.apache.qpid.transport.util;
+using org.apache.qpid.transport.network;
+using System.IO;
+
+namespace org.apache.qpid.transport
+{
+
+${
+from genutil import *
+
+cls = klass(type)["@name"]
+
+segments = type["segments"]
+
+if type.name in ("control", "command"):
+ override = "override"
+ base = "Method"
+ size = 0
+ pack = 2
+ if segments:
+ payload = "true"
+ else:
+ payload = "false"
+ if type.name == "control" and cls == "connection":
+ track = "Frame.L1"
+ elif cls == "session" and type["@name"] in ("attach", "attached", "detach", "detached"):
+ track = "Frame.L2"
+ elif type.name == "command":
+ track = "Frame.L4"
+ else:
+ track = "Frame.L3"
+else:
+ override = ""
+ base = "Struct"
+ size = type["@size"]
+ pack = num(type["@pack"])
+ payload = "false"
+ track = "4"
+
+PACK_TYPES = {
+ 1: "byte",
+ 2: "int",
+ 4: "int"
+}
+
+typecode = code(type)
+}
+
+public sealed class $name : $base {
+
+ public const int TYPE = $typecode;
+
+ public override int GetStructType() {
+ return TYPE;
+ }
+
+ public override int GetSizeWidth() {
+ return $size;
+ }
+
+ public override int GetPackWidth() {
+ return $pack;
+ }
+
+ public $override bool HasPayload() {
+ return $payload;
+ }
+
+ public $override byte EncodedTrack
+ {
+ get{ return $track; }
+ set { throw new NotImplementedException(); }
+ }
+
+${
+from dotnetgenutil import *
+if pack > 0:
+ out(" private $(PACK_TYPES[pack]) packing_flags = 0;\n");
+
+fields = get_fields(type)
+params = get_dotnetparameters(type, fields)
+options = get_options(fields)
+
+for f in fields:
+ if not f.empty:
+ out(" private $(f.type) _$(f.name);\n")
+
+if segments:
+ out(" private Header _header;\n")
+ out(" private MemoryStream _body = new MemoryStream();\n")
+}
+
+${
+if fields:
+ out(" public $name() {}\n")
+}
+
+ public $name($(", ".join(params))) {
+${
+for f in fields:
+ if f.option: continue
+ out(" $(f.set)($(f.name));\n")
+
+if segments:
+ out(" Header = header;\n")
+ out(" Body = body;\n")
+
+if options or base == "Method":
+ out("""
+ for (int i=0; i < options.Length; i++) {
+ switch (options[i]) {
+""")
+
+ for f in options:
+ out(" case Option.$(f.option): packing_flags |= $(f.flag_mask(pack)); break;\n")
+
+ if base == "Method":
+ out(""" case Option.SYNC: Sync = true; break;
+ case Option.BATCH: Batch = true; break;
+""")
+ out(""" case Option.NONE: break;
+ default: throw new Exception("invalid option: " + options[i]);
+ }
+ }
+""")
+}
+ }
+
+ public $override void Dispatch<C>(C context, MethodDelegate<C> mdelegate) {
+ mdelegate.$(name)(context, this);
+ }
+
+${
+for f in fields:
+ if pack > 0:
+ out("""
+ public bool $(f.has)() {
+ return (packing_flags & $(f.flag_mask(pack))) != 0;
+ }
+
+ public $name $(f.clear)() {
+ packing_flags = (byte) (packing_flags & ~$(f.flag_mask(pack)));
+${
+if (not f.empty and not (f.default == "null")):
+ out(" _$(f.name) = $(f.default);")
+}
+ Dirty = true;
+ return this;
+ }
+""")
+
+ out("""
+ public $(f.type) $(f.get)() {
+${
+if f.empty:
+ out(" return $(f.has)();")
+else:
+ out(" return _$(f.name);")
+}
+ }
+
+ public $name $(f.set)($(f.type) value) {
+${
+if not f.empty:
+ out(" _$(f.name) = value;")
+}
+${
+if pack > 0:
+ out(" packing_flags |= $(f.flag_mask(pack));")
+}
+ Dirty = true;
+ return this;
+ }
+
+""")
+}
+
+${
+if segments:
+ out(""" public override Header Header {
+ get { return _header;}
+ set { _header = value;}
+ }
+
+ public $name SetHeader(Header header) {
+ Header = header;
+ return this;
+ }
+
+ public override MemoryStream Body
+ {
+ get{ return _body;}
+ set{ _body = value;}
+ }
+
+ public $name SetBody(MemoryStream body)
+ {
+ Body = body;
+ return this;
+ }
+""")
+}
+
+ public override void Write(IEncoder enc)
+ {
+${
+if pack > 0:
+ out(" enc.WriteUint%s(packing_flags);\n" % (pack*8));
+
+for f in fields:
+ if f.empty:
+ continue
+ if pack > 0:
+ out(" if ((packing_flags & $(f.flag_mask(pack))) != 0)\n ")
+ pre = ""
+ post = ""
+ if f.type_node.name == "struct":
+ pre = "%s.TYPE, " % cname(f.type_node)
+ elif f.type_node.name == "domain":
+ post = ""
+ pre = "(short)"
+ out(" enc.Write$(f.coder)($(pre)_$(f.name)$(post));\n")
+}
+ }
+
+ public override void Read(IDecoder dec)
+ {
+${
+if pack > 0:
+ out(" packing_flags = ($(PACK_TYPES[pack])) dec.ReadUint%s();\n" % (pack*8));
+
+for f in fields:
+ if f.empty:
+ continue
+ if pack > 0:
+ out(" if ((packing_flags & $(f.flag_mask(pack))) != 0)\n ")
+ pre = ""
+ post = ""
+ arg = ""
+ if f.type_node.name == "struct":
+ pre = "(%s)" % cname(f.type_node)
+ arg = "%s.TYPE" % cname(f.type_node)
+ elif f.type_node.name == "domain":
+ pre = "%sGetter.Get(" % cname(f.type_node)
+ post = ")"
+ out(" _$(f.name) = $(pre)dec.Read$(f.coder)($(arg))$(post);\n")
+}
+ }
+
+ public override Dictionary<String,Object> Fields
+ {
+ get
+ {
+ Dictionary<String,Object> result = new Dictionary<String,Object>();
+
+${
+for f in fields:
+ if pack > 0:
+ out(" if ((packing_flags & $(f.flag_mask(pack))) != 0)\n ")
+ out(' result.Add("_$(f.name)", $(f.get)());\n')
+}
+ return result;
+ }
+ }
+
+}
+}
diff --git a/dotnet/client-010/gentool/Constant.tpl b/dotnet/client-010/gentool/Constant.tpl
new file mode 100644
index 0000000000..191a1dbd6e
--- /dev/null
+++ b/dotnet/client-010/gentool/Constant.tpl
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+namespace org.apache.qpid.transport
+{
+
+${from genutil import *}
+
+public class Constant
+{
+${
+constants = spec.query["amqp/constant"]
+
+for c in constants:
+ name = scream(c["@name"])
+ value = c["@value"]
+ out(" public const int $name = $value;\n")
+}}
+}
diff --git a/dotnet/client-010/gentool/Enum.tpl b/dotnet/client-010/gentool/Enum.tpl
new file mode 100644
index 0000000000..33af038cc6
--- /dev/null
+++ b/dotnet/client-010/gentool/Enum.tpl
@@ -0,0 +1,38 @@
+using System;
+namespace org.apache.qpid.transport
+{
+${
+from genutil import *
+
+vtype = jtype(resolve_type(type))
+
+out(" public enum $name : $vtype")
+
+choices = [(scream(ch["@name"]), "= %s" % (ch["@value"]))
+ for ch in type.query["enum/choice"]]
+}
+ {
+ $(",\n ".join(["%s%s" % ch for ch in choices]))
+ }
+
+${
+
+out(" public struct $name")
+out("Getter")
+}
+ {
+ public static $name Get($vtype value)
+ {
+ switch (value)
+ {
+${
+choices = [(scream(ch["@name"]), "%s" % (ch["@value"]))
+ for ch in type.query["enum/choice"]]
+
+for ch, value in choices:
+ out(' case $value: return $name.$ch;\n')
+} default: throw new Exception("no such value: " + value);
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/gentool/IInvoker.tpl b/dotnet/client-010/gentool/IInvoker.tpl
new file mode 100644
index 0000000000..713d10c610
--- /dev/null
+++ b/dotnet/client-010/gentool/IInvoker.tpl
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace org.apache.qpid.transport
+{
+
+public interface IInvoker {
+
+ IFuture Invoke(Method method, IFuture resultClass);
+
+${
+from dotnetgenutil import *
+
+for c in composites:
+ name = cname(c)
+ fields = get_fields(c)
+ params = get_dotnetparameters(c, fields)
+ args = get_arguments(c, fields)
+ result = c["result"]
+ if result:
+ if not result["@type"]:
+ rname = cname(result["struct"])
+ else:
+ rname = cname(result, "@type")
+ jresult = "IFuture"
+ else:
+ jresult = "void"
+
+ out("""
+ $jresult $(name)($(", ".join(params)));
+""")
+}
+
+}
+}
diff --git a/dotnet/client-010/gentool/Invoker.tpl b/dotnet/client-010/gentool/Invoker.tpl
new file mode 100644
index 0000000000..2f69aee66d
--- /dev/null
+++ b/dotnet/client-010/gentool/Invoker.tpl
@@ -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.
+ *
+ */
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using common.org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.transport
+{
+
+public abstract class Invoker : IInvoker {
+
+ protected abstract void Invoke(Method method);
+ public abstract IFuture Invoke(Method method, IFuture resultClass);
+
+${
+from dotnetgenutil import *
+
+for c in composites:
+ name = cname(c)
+ fields = get_fields(c)
+ params = get_dotnetparameters(c, fields)
+ args = get_arguments(c, fields)
+ result = c["result"]
+ if result:
+ if not result["@type"]:
+ rname = cname(result["struct"])
+ else:
+ rname = cname(result, "@type")
+ jresult = "IFuture"
+ jreturn = "return "
+ jclass = ", new ResultFuture()"
+ jinvoke = "Invoke"
+ else:
+ jinvoke = "Invoke"
+ jresult = "void"
+ jreturn = ""
+ jclass = ""
+
+ out("""
+ public $jresult $(name)($(", ".join(params))) {
+ $(jreturn)$jinvoke(new $name($(", ".join(args)))$jclass);
+ }
+""")
+}
+
+}
+}
diff --git a/dotnet/client-010/gentool/MethodDelegate.tpl b/dotnet/client-010/gentool/MethodDelegate.tpl
new file mode 100644
index 0000000000..788d2e29e6
--- /dev/null
+++ b/dotnet/client-010/gentool/MethodDelegate.tpl
@@ -0,0 +1,35 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+namespace org.apache.qpid.transport
+{
+
+public abstract class MethodDelegate<C> {
+
+${
+from genutil import *
+
+for c in composites:
+ name = cname(c)
+ out(" public virtual void $(name)(C context, $name mystruct) {}\n")
+}
+}
+}
diff --git a/dotnet/client-010/gentool/Option.tpl b/dotnet/client-010/gentool/Option.tpl
new file mode 100644
index 0000000000..d6e1a44870
--- /dev/null
+++ b/dotnet/client-010/gentool/Option.tpl
@@ -0,0 +1,42 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+namespace org.apache.qpid.transport
+{
+public enum Option {
+
+${
+from genutil import *
+
+options = {}
+
+for c in composites:
+ for f in c.query["field"]:
+ t = resolve_type(f)
+ if t["@name"] == "bit":
+ option = scream(f["@name"])
+ if not options.has_key(option):
+ options[option] = None
+ out(" $option,\n")}
+ BATCH,
+ NONE
+}
+}
diff --git a/dotnet/client-010/gentool/StructFactory.tpl b/dotnet/client-010/gentool/StructFactory.tpl
new file mode 100644
index 0000000000..2a11e2530c
--- /dev/null
+++ b/dotnet/client-010/gentool/StructFactory.tpl
@@ -0,0 +1,64 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+
+namespace org.apache.qpid.transport
+{
+
+class StructFactory {
+
+ public static Struct create(int type)
+ {
+ switch (type)
+ {
+${
+from genutil import *
+
+fragment = """ case $name.TYPE:
+ return new $name();
+"""
+
+for c in composites:
+ name = cname(c)
+ if c.name == "struct":
+ out(fragment)
+} default:
+ throw new Exception("type: " + type);
+ }
+ }
+
+ public static Struct createInstruction(int type)
+ {
+ switch (type)
+ {
+${
+for c in composites:
+ name = cname(c)
+ if c.name in ("command", "control"):
+ out(fragment)
+} default:
+ throw new Exception("type: " + type);
+ }
+ }
+
+}
+}
diff --git a/dotnet/client-010/gentool/Type.tpl b/dotnet/client-010/gentool/Type.tpl
new file mode 100644
index 0000000000..c8ec7ac153
--- /dev/null
+++ b/dotnet/client-010/gentool/Type.tpl
@@ -0,0 +1,103 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+
+namespace org.apache.qpid.transport
+{
+
+${from genutil import *}
+
+public struct QpidType
+{
+ public Code code;
+ public int width;
+ public bool isfixed;
+
+ public Code Code
+ {
+ get { return code; }
+ set { code = value; }
+ }
+
+ public int Width
+ {
+ get { return width; }
+ set { width = value; }
+ }
+
+ public bool Fixed
+ {
+ get { return isfixed; }
+ set { isfixed = value; }
+ }
+
+ QpidType(Code code, int width, bool isfixed)
+ {
+ this.code = code;
+ this.width = width;
+ this.isfixed = isfixed;
+ }
+
+ public static QpidType get(byte code)
+ {
+ switch (code)
+ {
+${
+types = spec.query["amqp/type"] + spec.query["amqp/class/type"]
+codes = {}
+first = True
+for t in types:
+ code = t["@code"]
+ fix_width = t["@fixed-width"]
+ var_width = t["@variable-width"]
+
+ if code is None:
+ continue
+
+ if fix_width is None:
+ width = var_width
+ fixed = "false"
+ else:
+ width = fix_width
+ fixed = "true"
+
+ name = scream(t["@name"])
+ codes[code] = name
+
+ out(" case $code : return new QpidType(Code.$name, $width, $fixed);\n")
+}
+ default: throw new Exception("unknown code: " + code);
+ }
+ }
+}
+
+public enum Code : byte
+ {
+${
+keys = list(codes.keys())
+keys.sort()
+
+for code in keys:
+ out(" $(codes[code]) = $code,\n")
+}
+ }
+}
diff --git a/dotnet/client-010/gentool/build.xml b/dotnet/client-010/gentool/build.xml
new file mode 100644
index 0000000000..76ddb1571d
--- /dev/null
+++ b/dotnet/client-010/gentool/build.xml
@@ -0,0 +1,52 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<project name="GenTool" default="build">
+
+ <property name="generated.dir" location="../client/" />
+ <property name="gentools.timestamp" location="${generated.dir}/gentools.timestamp" />
+ <property name="jython.timestamp" location="${generated.dir}/jython.timestamp" />
+ <property name="java.basedir" location="../../../java/common" />
+ <property name="mllib.dir" location="../../../python" />
+ <property name="xml.spec.dir" location="../../../specs" />
+
+
+ <target name="check_jython_deps">
+ <uptodate property="jython.notRequired" targetfile="${jython.timestamp}">
+ <srcfiles dir="${xml.spec.dir}" includes="amqp.0-10-qpid-errata.xml" />
+ </uptodate>
+ </target>
+
+ <target name="build" depends="check_jython_deps" unless="jython.notRequired">
+ <java classname="org.python.util.jython" fork="true" failonerror="true">
+ <arg value="-Dpython.cachedir.skip=true"/>
+ <arg value="-Dpython.path=${java.basedir}/../lib/jython-lib.jar/Lib${path.separator}${mllib.dir}${path.separator}${java.basedir}${path.separator}${basedir}"/>
+ <arg value="${basedir}/codegen"/>
+ <arg value="${generated.dir}"/>
+ <arg value="${xml.spec.dir}/amqp.0-10-qpid-errata.xml"/>
+ <arg value="${basedir}"/>
+ <classpath>
+ <pathelement location="../../../java/lib/jython-2.5.0.jar"/>
+ </classpath>
+ </java>
+ <touch file="${jython.timestamp}" />
+ </target>
+
+</project>
diff --git a/dotnet/client-010/gentool/codegen b/dotnet/client-010/gentool/codegen
new file mode 100644
index 0000000000..baebf378fd
--- /dev/null
+++ b/dotnet/client-010/gentool/codegen
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
+
+import os, sys, mllib
+from templating import Parser
+from dotnetgenutil import *
+
+out_dir = sys.argv[1]
+spec_file = sys.argv[2]
+tpl_dir = sys.argv[3]
+pkg_dir = os.path.join(out_dir, "generated")
+
+if not os.path.exists(pkg_dir):
+ os.makedirs(pkg_dir)
+
+spec = mllib.xml_parse(spec_file)
+
+def excludes(nd):
+ if (nd.parent is not None and
+ nd.parent.name == "class" and
+ nd.parent["@name"] in ("file", "stream")):
+ return False
+ else:
+ return True
+
+def execute(output, template, **kwargs):
+ f = open(os.path.join(tpl_dir, template))
+ input = f.read()
+ f.close()
+ p = Parser(**kwargs)
+ p.parse(input)
+ fname = os.path.join(pkg_dir, output)
+ f = open(fname, "w")
+ f.write(p.output)
+ f.close()
+
+execute("Type.cs", "Type.tpl", spec = spec)
+execute("Constant.cs", "Constant.tpl", spec = spec)
+
+structs = spec.query["amqp/struct"] + \
+ spec.query["amqp/class/struct", excludes] + \
+ spec.query["amqp/class/command/result/struct", excludes]
+controls = spec.query["amqp/class/control", excludes]
+commands = spec.query["amqp/class/command", excludes]
+
+composites = structs + controls + commands
+
+for c in composites:
+ name = cname(c)
+ execute("%s.cs" % name, "Composite.tpl", type = c, name = name)
+
+execute("MethodDelegate.cs", "MethodDelegate.tpl", composites = composites)
+execute("Option.cs", "Option.tpl", composites = composites)
+execute("Invoker.cs", "Invoker.tpl", composites = controls + commands)
+execute("IInvoker.cs", "IInvoker.tpl", composites = controls + commands)
+execute("StructFactory.cs", "StructFactory.tpl", composites = composites)
+
+def is_enum(nd):
+ return nd["enum"] is not None
+
+enums = spec.query["amqp/domain", is_enum] + \
+ spec.query["amqp/class/domain", is_enum]
+
+for e in enums:
+ name = cname(e)
+ execute("%s.cs" % name, "Enum.tpl", name = name, type = e)
diff --git a/dotnet/client-010/gentool/dotnetgenutil.py b/dotnet/client-010/gentool/dotnetgenutil.py
new file mode 100644
index 0000000000..4d9c8a69d7
--- /dev/null
+++ b/dotnet/client-010/gentool/dotnetgenutil.py
@@ -0,0 +1,271 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
+
+def pascal(offset, *args):
+ parts = []
+ for a in args:
+ parts.extend(a.split("-"))
+ return "".join([p[0].upper() + p[1:] for p in parts[:offset]] + [p[0].upper() + p[1:] for p in parts[offset:]])
+
+
+def scream(*args):
+ return "_".join([a.replace("-", "_").upper() for a in args])
+
+def num(x, default=None):
+ if x is not None and x != "":
+ return int(x, 0)
+ else:
+ return default
+
+def klass(nd):
+ parent = nd.parent
+ while parent is not None:
+ if hasattr(parent, "name") and parent.name == "class":
+ return parent
+ parent = parent.parent
+
+untyped = -1
+
+def code(nd):
+ global untyped
+ cd = num(nd["@code"])
+ if cd is None:
+ cd = untyped
+ untyped -= 1
+ return cd
+
+ cls = klass(nd)
+ if cls:
+ cd |= (num(cls["@code"]) << 8)
+ return cd
+
+def root(nd):
+ if nd.parent is None:
+ return nd
+ else:
+ return root(nd.parent)
+
+def qname(nd):
+ name = nd["@name"]
+ cls = klass(nd)
+ if cls != None:
+ return "%s.%s" % (cls["@name"], name)
+ else:
+ return name
+
+RESOLVED = {}
+
+def resolve(node, name):
+ key = (node, name)
+ if RESOLVED.has_key(key):
+ return RESOLVED[key]
+ else:
+ spec = root(node)
+ cls = klass(node)
+ if cls:
+ for nd in cls.query["#tag"]:
+ if nd["@name"] == name:
+ RESOLVED[key] = nd
+ return nd
+ for nd in spec.query["amqp/#tag"] + spec.query["amqp/class/#tag"]:
+ if name == qname(nd):
+ RESOLVED[key] = nd
+ return nd
+ raise Exception("unresolved name: %s" % name)
+
+def resolve_type(nd):
+ if hasattr(nd, "_resolved_type"):
+ return nd._resolved_type
+ else:
+ name = nd["@type"]
+ type = resolve(nd, name)
+ if type.name == "domain" and not type["enum"]:
+ type = resolve_type(type)
+ nd._resolved_type = type
+ return type
+
+TYPES = {
+ "bit": "bool",
+ "uint8": "short",
+ "uint16": "int",
+ "uint32": "long",
+ "uint64": "long",
+ "datetime": "long",
+ "uuid": "UUID",
+ "sequence-no": "int",
+ "sequence-set": "RangeSet", # XXX
+ "byte-ranges": "RangeSet", # XXX
+ "str8": "String",
+ "str16": "String",
+ "vbin8": "byte[]",
+ "vbin16": "byte[]",
+ "vbin32": "byte[]",
+ "struct32": "Struct",
+ "map": "Dictionary<String,Object>",
+ "array": "List<Object>"
+ }
+
+def cname(nd, field="@name"):
+ cls = klass(nd)
+ if cls:
+ if (nd.name in ("struct", "result") and
+ cls["@name"] != "session" and
+ nd[field] != "header"):
+ return pascal(0, nd[field])
+ else:
+ return pascal(0, cls["@name"], nd[field])
+ else:
+ return pascal(0, nd[field])
+
+def jtype(nd):
+ if nd.name == "struct" or nd["enum"]:
+ return cname(nd)
+ else:
+ return TYPES[nd["@name"]]
+
+REFS = {
+ "bool": "Boolean",
+ "byte": "Byte",
+ "short": "Short",
+ "int": "Integer",
+ "long": "Long",
+ "float": "Float",
+ "double": "Double",
+ "char": "Character"
+}
+
+def jref(jt):
+ return REFS.get(jt, jt)
+
+def jclass(jt):
+ idx = jt.find('<')
+ if idx > 0:
+ return jt[:idx]
+ else:
+ return jt
+
+DEFAULTS = {
+ "long": 0,
+ "int": 0,
+ "short": 0,
+ "byte": 0,
+ "char": 0,
+ "bool": "false"
+ }
+
+class Field:
+
+ def __init__(self, index, nd):
+ self.index = index
+ self.name = pascal(1, nd["@name"])
+ self.type_node = resolve_type(nd)
+ if self.type_node.name == "domain":
+ self.prim_type = resolve_type(self.type_node)
+ else:
+ self.prim_type = self.type_node
+ self.variable_width = num(self.prim_type["@variable-width"], 0)
+ self.fixed_width = num(self.prim_type["@fixed-width"], 0)
+ self.empty = self.variable_width == 0 and self.fixed_width == 0 and self.prim_type.name != "struct"
+ tname = cname(self.type_node)
+ if self.type_node.name == "struct":
+ self.read = "(%s) dec.ReadStruct(%s.TYPE)" % (tname, tname)
+ self.write = "enc.WriteStruct(%s.TYPE, check(struct).%s)" % (tname, self.name)
+ self.coder = "Struct"
+ elif self.type_node.name == "domain":
+ self.coder = pascal(0, self.prim_type["@name"])
+ self.read = "%s.Get(dec.Read%s())" % (tname, self.coder)
+ self.write = "enc.Write%s(check(struct).%s.GetValue())" % (self.coder, self.name)
+ else:
+ self.coder = pascal(0, self.type_node["@name"])
+ self.read = "dec.Read%s()" % self.coder
+ self.write = "enc.Write%s(check(struct).%s)" % (self.coder, self.name)
+ self.type = jtype(self.type_node)
+ self.default = DEFAULTS.get(self.type, "null")
+ self.has = pascal(1, "Has", self.name)
+ self.get = pascal(1, "Get", self.name)
+ self.set = pascal(1, "Set", self.name)
+ self.clear = pascal(1, "clear", self.name)
+ if self.type == "bool":
+ self.option = scream(nd["@name"])
+ else:
+ self.option = None
+
+ def flag_mask(self, pack):
+ flag = pack * 8 - 8 - (self.index/8)*8 + (self.index % 8)
+ return 1 << flag
+
+
+def get_fields(nd):
+ fields = []
+ index = 0
+ for f in nd.query["field"]:
+ fields.append(Field(index, f))
+ index += 1
+ return fields
+
+def get_parameters(type, fields):
+ params = []
+ options = False
+ for f in fields:
+ if f.option:
+ options = True
+ else:
+ params.append("%s %s" % (f.type, f.name))
+ if type["segments"]:
+ params.append("Header header")
+ params.append("MemoryStream body")
+ if options or type.name in ("control", "command"):
+ params.append("Option ... options")
+ return params
+
+def get_arguments(type, fields):
+ args = []
+ options = False
+ for f in fields:
+ if f.option:
+ options = True
+ else:
+ args.append(f.name)
+ if type["segments"]:
+ args.append("header")
+ args.append("body")
+ if options or type.name in ("control", "command"):
+ args.append("options")
+ return args
+
+def get_options(fields):
+ return [f for f in fields if f.option]
+
+def get_dotnetparameters(type, fields):
+ params = []
+ options = False
+ for f in fields:
+ if f.option:
+ options = True
+ else:
+ params.append("%s %s" % (f.type, f.name))
+ if type["segments"]:
+ params.append("Header header")
+ params.append("MemoryStream body")
+ if options or type.name in ("control", "command"):
+ params.append("params Option[] options")
+ return params
diff --git a/dotnet/client-010/lib/log4net/log4net-licence.txt b/dotnet/client-010/lib/log4net/log4net-licence.txt
new file mode 100644
index 0000000000..261eeb9e9f
--- /dev/null
+++ b/dotnet/client-010/lib/log4net/log4net-licence.txt
@@ -0,0 +1,201 @@
+ 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/dotnet/client-010/lib/log4net/log4net.dll b/dotnet/client-010/lib/log4net/log4net.dll
new file mode 100644
index 0000000000..995816f27b
--- /dev/null
+++ b/dotnet/client-010/lib/log4net/log4net.dll
Binary files differ
diff --git a/dotnet/client-010/lib/log4net/log4net.xml b/dotnet/client-010/lib/log4net/log4net.xml
new file mode 100644
index 0000000000..5beb669ab0
--- /dev/null
+++ b/dotnet/client-010/lib/log4net/log4net.xml
@@ -0,0 +1,28676 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<doc>
+ <assembly>
+ <name>log4net</name>
+ </assembly>
+ <members>
+ <member name="T:log4net.Appender.AdoNetAppender">
+ <summary>
+ Appender that logs to a database.
+ </summary>
+ <remarks>
+ <para>
+ <see cref="T:log4net.Appender.AdoNetAppender"/> appends logging events to a table within a
+ database. The appender can be configured to specify the connection
+ string by setting the <see cref="P:log4net.Appender.AdoNetAppender.ConnectionString"/> property.
+ The connection type (provider) can be specified by setting the <see cref="P:log4net.Appender.AdoNetAppender.ConnectionType"/>
+ property. For more information on database connection strings for
+ your specific database see <a href="http://www.connectionstrings.com/">http://www.connectionstrings.com/</a>.
+ </para>
+ <para>
+ Records are written into the database either using a prepared
+ statement or a stored procedure. The <see cref="P:log4net.Appender.AdoNetAppender.CommandType"/> property
+ is set to <see cref="F:System.Data.CommandType.Text"/> (<c>System.Data.CommandType.Text</c>) to specify a prepared statement
+ or to <see cref="F:System.Data.CommandType.StoredProcedure"/> (<c>System.Data.CommandType.StoredProcedure</c>) to specify a stored
+ procedure.
+ </para>
+ <para>
+ The prepared statement text or the name of the stored procedure
+ must be set in the <see cref="P:log4net.Appender.AdoNetAppender.CommandText"/> property.
+ </para>
+ <para>
+ The prepared statement or stored procedure can take a number
+ of parameters. Parameters are added using the <see cref="M:log4net.Appender.AdoNetAppender.AddParameter(log4net.Appender.AdoNetAppenderParameter)"/>
+ method. This adds a single <see cref="T:log4net.Appender.AdoNetAppenderParameter"/> to the
+ ordered list of parameters. The <see cref="T:log4net.Appender.AdoNetAppenderParameter"/>
+ type may be subclassed if required to provide database specific
+ functionality. The <see cref="T:log4net.Appender.AdoNetAppenderParameter"/> specifies
+ the parameter name, database type, size, and how the value should
+ be generated using a <see cref="T:log4net.Layout.ILayout"/>.
+ </para>
+ </remarks>
+ <example>
+ An example of a SQL Server table that could be logged to:
+ <code lang="SQL">
+ CREATE TABLE [dbo].[Log] (
+ [ID] [int] IDENTITY (1, 1) NOT NULL ,
+ [Date] [datetime] NOT NULL ,
+ [Thread] [varchar] (255) NOT NULL ,
+ [Level] [varchar] (20) NOT NULL ,
+ [Logger] [varchar] (255) NOT NULL ,
+ [Message] [varchar] (4000) NOT NULL
+ ) ON [PRIMARY]
+ </code>
+ </example>
+ <example>
+ An example configuration to log to the above table:
+ <code lang="XML" escaped="true">
+ <appender name="AdoNetAppender_SqlServer" type="log4net.Appender.AdoNetAppender">
+ <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
+ <connectionString value="data source=SQLSVR;initial catalog=test_log4net;integrated security=false;persist security info=True;User ID=sa;Password=sa"/>
+ <commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message]) VALUES (@log_date, @thread, @log_level, @logger, @message)"/>
+ <parameter>
+ <parameterName value="@log_date"/>
+ <dbType value="DateTime"/>
+ <layout type="log4net.Layout.PatternLayout" value="%date{yyyy'-'MM'-'dd HH':'mm':'ss'.'fff}"/>
+ </parameter>
+ <parameter>
+ <parameterName value="@thread"/>
+ <dbType value="String"/>
+ <size value="255"/>
+ <layout type="log4net.Layout.PatternLayout" value="%thread"/>
+ </parameter>
+ <parameter>
+ <parameterName value="@log_level"/>
+ <dbType value="String"/>
+ <size value="50"/>
+ <layout type="log4net.Layout.PatternLayout" value="%level"/>
+ </parameter>
+ <parameter>
+ <parameterName value="@logger"/>
+ <dbType value="String"/>
+ <size value="255"/>
+ <layout type="log4net.Layout.PatternLayout" value="%logger"/>
+ </parameter>
+ <parameter>
+ <parameterName value="@message"/>
+ <dbType value="String"/>
+ <size value="4000"/>
+ <layout type="log4net.Layout.PatternLayout" value="%message"/>
+ </parameter>
+ </appender>
+ </code>
+ </example>
+ <author>Julian Biddle</author>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ <author>Lance Nehring</author>
+ </member>
+ <member name="T:log4net.Appender.BufferingAppenderSkeleton">
+ <summary>
+ Abstract base class implementation of <see cref="T:log4net.Appender.IAppender"/> that
+ buffers events in a fixed size buffer.
+ </summary>
+ <remarks>
+ <para>
+ This base class should be used by appenders that need to buffer a
+ number of events before logging them. For example the <see cref="T:log4net.Appender.AdoNetAppender"/>
+ buffers events and then submits the entire contents of the buffer to
+ the underlying database in one go.
+ </para>
+ <para>
+ Subclasses should override the <see cref="M:log4net.Appender.BufferingAppenderSkeleton.SendBuffer(log4net.Core.LoggingEvent[])"/>
+ method to deliver the buffered events.
+ </para>
+ <para>The BufferingAppenderSkeleton maintains a fixed size cyclic
+ buffer of events. The size of the buffer is set using
+ the <see cref="P:log4net.Appender.BufferingAppenderSkeleton.BufferSize"/> property.
+ </para>
+ <para>A <see cref="T:log4net.Core.ITriggeringEventEvaluator"/> is used to inspect
+ each event as it arrives in the appender. If the <see cref="P:log4net.Appender.BufferingAppenderSkeleton.Evaluator"/>
+ triggers, then the current buffer is sent immediately
+ (see <see cref="M:log4net.Appender.BufferingAppenderSkeleton.SendBuffer(log4net.Core.LoggingEvent[])"/>). Otherwise the event
+ is stored in the buffer. For example, an evaluator can be used to
+ deliver the events immediately when an ERROR event arrives.
+ </para>
+ <para>
+ The buffering appender can be configured in a <see cref="P:log4net.Appender.BufferingAppenderSkeleton.Lossy"/> mode.
+ By default the appender is NOT lossy. When the buffer is full all
+ the buffered events are sent with <see cref="M:log4net.Appender.BufferingAppenderSkeleton.SendBuffer(log4net.Core.LoggingEvent[])"/>.
+ If the <see cref="P:log4net.Appender.BufferingAppenderSkeleton.Lossy"/> property is set to <c>true</c> then the
+ buffer will not be sent when it is full, and new events arriving
+ in the appender will overwrite the oldest event in the buffer.
+ In lossy mode the buffer will only be sent when the <see cref="P:log4net.Appender.BufferingAppenderSkeleton.Evaluator"/>
+ triggers. This can be useful behavior when you need to know about
+ ERROR events but not about events with a lower level, configure an
+ evaluator that will trigger when an ERROR event arrives, the whole
+ buffer will be sent which gives a history of events leading up to
+ the ERROR event.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.Appender.AppenderSkeleton">
+ <summary>
+ Abstract base class implementation of <see cref="T:log4net.Appender.IAppender"/>.
+ </summary>
+ <remarks>
+ <para>
+ This class provides the code for common functionality, such
+ as support for threshold filtering and support for general filters.
+ </para>
+ <para>
+ Appenders can also implement the <see cref="T:log4net.Core.IOptionHandler"/> interface. Therefore
+ they would require that the <see cref="M:log4net.Core.IOptionHandler.ActivateOptions"/> method
+ be called after the appenders properties have been configured.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.Appender.IAppender">
+ <summary>
+ Implement this interface for your own strategies for printing log statements.
+ </summary>
+ <remarks>
+ <para>
+ Implementors should consider extending the <see cref="T:log4net.Appender.AppenderSkeleton"/>
+ class which provides a default implementation of this interface.
+ </para>
+ <para>
+ Appenders can also implement the <see cref="T:log4net.Core.IOptionHandler"/> interface. Therefore
+ they would require that the <see cref="M:log4net.Core.IOptionHandler.ActivateOptions"/> method
+ be called after the appenders properties have been configured.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Appender.IAppender.Close">
+ <summary>
+ Closes the appender and releases resources.
+ </summary>
+ <remarks>
+ <para>
+ Releases any resources allocated within the appender such as file handles,
+ network connections, etc.
+ </para>
+ <para>
+ It is a programming error to append to a closed appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.IAppender.DoAppend(log4net.Core.LoggingEvent)">
+ <summary>
+ Log the logging event in Appender specific way.
+ </summary>
+ <param name="loggingEvent">The event to log</param>
+ <remarks>
+ <para>
+ This method is called to log a message into this appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.IAppender.Name">
+ <summary>
+ Gets or sets the name of this appender.
+ </summary>
+ <value>The name of the appender.</value>
+ <remarks>
+ <para>The name uniquely identifies the appender.</para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.IBulkAppender">
+ <summary>
+ Interface for appenders that support bulk logging.
+ </summary>
+ <remarks>
+ <para>
+ This interface extends the <see cref="T:log4net.Appender.IAppender"/> interface to
+ support bulk logging of <see cref="T:log4net.Core.LoggingEvent"/> objects. Appenders
+ should only implement this interface if they can bulk log efficiently.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Appender.IBulkAppender.DoAppend(log4net.Core.LoggingEvent[])">
+ <summary>
+ Log the array of logging events in Appender specific way.
+ </summary>
+ <param name="loggingEvents">The events to log</param>
+ <remarks>
+ <para>
+ This method is called to log an array of events into this appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.IOptionHandler">
+ <summary>
+ Interface used to delay activate a configured object.
+ </summary>
+ <remarks>
+ <para>
+ This allows an object to defer activation of its options until all
+ options have been set. This is required for components which have
+ related options that remain ambiguous until all are set.
+ </para>
+ <para>
+ If a component implements this interface then the <see cref="M:log4net.Core.IOptionHandler.ActivateOptions"/> method
+ must be called by the container after its all the configured properties have been set
+ and before the component can be used.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Core.IOptionHandler.ActivateOptions">
+ <summary>
+ Activate the options that were previously set with calls to properties.
+ </summary>
+ <remarks>
+ <para>
+ This allows an object to defer activation of its options until all
+ options have been set. This is required for components which have
+ related options that remain ambiguous until all are set.
+ </para>
+ <para>
+ If a component implements this interface then this method must be called
+ after its properties have been set before the component can be used.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.AppenderSkeleton.c_renderBufferSize">
+ <summary>
+ Initial buffer size
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AppenderSkeleton.c_renderBufferMaxCapacity">
+ <summary>
+ Maximum buffer size before it is recycled
+ </summary>
+ </member>
+ <member name="M:log4net.Appender.AppenderSkeleton.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ <remarks>
+ <para>Empty default constructor</para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AppenderSkeleton.Finalize">
+ <summary>
+ Finalizes this appender by calling the implementation's
+ <see cref="M:log4net.Appender.AppenderSkeleton.Close"/> method.
+ </summary>
+ <remarks>
+ <para>
+ If this appender has not been closed then the <c>Finalize</c> method
+ will call <see cref="M:log4net.Appender.AppenderSkeleton.Close"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AppenderSkeleton.ActivateOptions">
+ <summary>
+ Initialize the appender based on the options set
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Appender.AppenderSkeleton.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Appender.AppenderSkeleton.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Appender.AppenderSkeleton.ActivateOptions"/> must be called again.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AppenderSkeleton.Close">
+ <summary>
+ Closes the appender and release resources.
+ </summary>
+ <remarks>
+ <para>
+ Release any resources allocated within the appender such as file handles,
+ network connections, etc.
+ </para>
+ <para>
+ It is a programming error to append to a closed appender.
+ </para>
+ <para>
+ This method cannot be overridden by subclasses. This method
+ delegates the closing of the appender to the <see cref="M:log4net.Appender.AppenderSkeleton.OnClose"/>
+ method which must be overridden in the subclass.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AppenderSkeleton.DoAppend(log4net.Core.LoggingEvent)">
+ <summary>
+ Performs threshold checks and invokes filters before
+ delegating actual logging to the subclasses specific
+ <see cref="M:log4net.Appender.AppenderSkeleton.Append(log4net.Core.LoggingEvent)"/> method.
+ </summary>
+ <param name="loggingEvent">The event to log.</param>
+ <remarks>
+ <para>
+ This method cannot be overridden by derived classes. A
+ derived class should override the <see cref="M:log4net.Appender.AppenderSkeleton.Append(log4net.Core.LoggingEvent)"/> method
+ which is called by this method.
+ </para>
+ <para>
+ The implementation of this method is as follows:
+ </para>
+ <para>
+ <list type="bullet">
+ <item>
+ <description>
+ Checks that the severity of the <paramref name="loggingEvent"/>
+ is greater than or equal to the <see cref="P:log4net.Appender.AppenderSkeleton.Threshold"/> of this
+ appender.</description>
+ </item>
+ <item>
+ <description>
+ Checks that the <see cref="T:log4net.Filter.IFilter"/> chain accepts the
+ <paramref name="loggingEvent"/>.
+ </description>
+ </item>
+ <item>
+ <description>
+ Calls <see cref="M:log4net.Appender.AppenderSkeleton.PreAppendCheck"/> and checks that
+ it returns <c>true</c>.</description>
+ </item>
+ </list>
+ </para>
+ <para>
+ If all of the above steps succeed then the <paramref name="loggingEvent"/>
+ will be passed to the abstract <see cref="M:log4net.Appender.AppenderSkeleton.Append(log4net.Core.LoggingEvent)"/> method.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AppenderSkeleton.DoAppend(log4net.Core.LoggingEvent[])">
+ <summary>
+ Performs threshold checks and invokes filters before
+ delegating actual logging to the subclasses specific
+ <see cref="M:log4net.Appender.AppenderSkeleton.Append(log4net.Core.LoggingEvent[])"/> method.
+ </summary>
+ <param name="loggingEvents">The array of events to log.</param>
+ <remarks>
+ <para>
+ This method cannot be overridden by derived classes. A
+ derived class should override the <see cref="M:log4net.Appender.AppenderSkeleton.Append(log4net.Core.LoggingEvent[])"/> method
+ which is called by this method.
+ </para>
+ <para>
+ The implementation of this method is as follows:
+ </para>
+ <para>
+ <list type="bullet">
+ <item>
+ <description>
+ Checks that the severity of the <paramref name="loggingEvent"/>
+ is greater than or equal to the <see cref="P:log4net.Appender.AppenderSkeleton.Threshold"/> of this
+ appender.</description>
+ </item>
+ <item>
+ <description>
+ Checks that the <see cref="T:log4net.Filter.IFilter"/> chain accepts the
+ <paramref name="loggingEvent"/>.
+ </description>
+ </item>
+ <item>
+ <description>
+ Calls <see cref="M:log4net.Appender.AppenderSkeleton.PreAppendCheck"/> and checks that
+ it returns <c>true</c>.</description>
+ </item>
+ </list>
+ </para>
+ <para>
+ If all of the above steps succeed then the <paramref name="loggingEvents"/>
+ will be passed to the <see cref="M:log4net.Appender.AppenderSkeleton.Append(log4net.Core.LoggingEvent[])"/> method.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AppenderSkeleton.FilterEvent(log4net.Core.LoggingEvent)">
+ <summary>
+ Test if the logging event should we output by this appender
+ </summary>
+ <param name="loggingEvent">the event to test</param>
+ <returns><c>true</c> if the event should be output, <c>false</c> if the event should be ignored</returns>
+ <remarks>
+ <para>
+ This method checks the logging event against the threshold level set
+ on this appender and also against the filters specified on this
+ appender.
+ </para>
+ <para>
+ The implementation of this method is as follows:
+ </para>
+ <para>
+ <list type="bullet">
+ <item>
+ <description>
+ Checks that the severity of the <paramref name="loggingEvent"/>
+ is greater than or equal to the <see cref="P:log4net.Appender.AppenderSkeleton.Threshold"/> of this
+ appender.</description>
+ </item>
+ <item>
+ <description>
+ Checks that the <see cref="T:log4net.Filter.IFilter"/> chain accepts the
+ <paramref name="loggingEvent"/>.
+ </description>
+ </item>
+ </list>
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AppenderSkeleton.AddFilter(log4net.Filter.IFilter)">
+ <summary>
+ Adds a filter to the end of the filter chain.
+ </summary>
+ <param name="filter">the filter to add to this appender</param>
+ <remarks>
+ <para>
+ The Filters are organized in a linked list.
+ </para>
+ <para>
+ Setting this property causes the new filter to be pushed onto the
+ back of the filter chain.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AppenderSkeleton.ClearFilters">
+ <summary>
+ Clears the filter list for this appender.
+ </summary>
+ <remarks>
+ <para>
+ Clears the filter list for this appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AppenderSkeleton.IsAsSevereAsThreshold(log4net.Core.Level)">
+ <summary>
+ Checks if the message level is below this appender's threshold.
+ </summary>
+ <param name="level"><see cref="T:log4net.Core.Level"/> to test against.</param>
+ <remarks>
+ <para>
+ If there is no threshold set, then the return value is always <c>true</c>.
+ </para>
+ </remarks>
+ <returns>
+ <c>true</c> if the <paramref name="level"/> meets the <see cref="P:log4net.Appender.AppenderSkeleton.Threshold"/>
+ requirements of this appender.
+ </returns>
+ </member>
+ <member name="M:log4net.Appender.AppenderSkeleton.OnClose">
+ <summary>
+ Is called when the appender is closed. Derived classes should override
+ this method if resources need to be released.
+ </summary>
+ <remarks>
+ <para>
+ Releases any resources allocated within the appender such as file handles,
+ network connections, etc.
+ </para>
+ <para>
+ It is a programming error to append to a closed appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AppenderSkeleton.Append(log4net.Core.LoggingEvent)">
+ <summary>
+ Subclasses of <see cref="T:log4net.Appender.AppenderSkeleton"/> should implement this method
+ to perform actual logging.
+ </summary>
+ <param name="loggingEvent">The event to append.</param>
+ <remarks>
+ <para>
+ A subclass must implement this method to perform
+ logging of the <paramref name="loggingEvent"/>.
+ </para>
+ <para>This method will be called by <see cref="M:log4net.Appender.AppenderSkeleton.DoAppend(log4net.Core.LoggingEvent)"/>
+ if all the conditions listed for that method are met.
+ </para>
+ <para>
+ To restrict the logging of events in the appender
+ override the <see cref="M:log4net.Appender.AppenderSkeleton.PreAppendCheck"/> method.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AppenderSkeleton.Append(log4net.Core.LoggingEvent[])">
+ <summary>
+ Append a bulk array of logging events.
+ </summary>
+ <param name="loggingEvents">the array of logging events</param>
+ <remarks>
+ <para>
+ This base class implementation calls the <see cref="M:log4net.Appender.AppenderSkeleton.Append(log4net.Core.LoggingEvent)"/>
+ method for each element in the bulk array.
+ </para>
+ <para>
+ A sub class that can better process a bulk array of events should
+ override this method in addition to <see cref="M:log4net.Appender.AppenderSkeleton.Append(log4net.Core.LoggingEvent)"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AppenderSkeleton.PreAppendCheck">
+ <summary>
+ Called before <see cref="M:log4net.Appender.AppenderSkeleton.Append(log4net.Core.LoggingEvent)"/> as a precondition.
+ </summary>
+ <remarks>
+ <para>
+ This method is called by <see cref="M:log4net.Appender.AppenderSkeleton.DoAppend(log4net.Core.LoggingEvent)"/>
+ before the call to the abstract <see cref="M:log4net.Appender.AppenderSkeleton.Append(log4net.Core.LoggingEvent)"/> method.
+ </para>
+ <para>
+ This method can be overridden in a subclass to extend the checks
+ made before the event is passed to the <see cref="M:log4net.Appender.AppenderSkeleton.Append(log4net.Core.LoggingEvent)"/> method.
+ </para>
+ <para>
+ A subclass should ensure that they delegate this call to
+ this base class if it is overridden.
+ </para>
+ </remarks>
+ <returns><c>true</c> if the call to <see cref="M:log4net.Appender.AppenderSkeleton.Append(log4net.Core.LoggingEvent)"/> should proceed.</returns>
+ </member>
+ <member name="M:log4net.Appender.AppenderSkeleton.RenderLoggingEvent(log4net.Core.LoggingEvent)">
+ <summary>
+ Renders the <see cref="T:log4net.Core.LoggingEvent"/> to a string.
+ </summary>
+ <param name="loggingEvent">The event to render.</param>
+ <returns>The event rendered as a string.</returns>
+ <remarks>
+ <para>
+ Helper method to render a <see cref="T:log4net.Core.LoggingEvent"/> to
+ a string. This appender must have a <see cref="P:log4net.Appender.AppenderSkeleton.Layout"/>
+ set to render the <paramref name="loggingEvent"/> to
+ a string.
+ </para>
+ <para>If there is exception data in the logging event and
+ the layout does not process the exception, this method
+ will append the exception text to the rendered string.
+ </para>
+ <para>
+ Where possible use the alternative version of this method
+ <see cref="M:log4net.Appender.AppenderSkeleton.RenderLoggingEvent(System.IO.TextWriter,log4net.Core.LoggingEvent)"/>.
+ That method streams the rendering onto an existing Writer
+ which can give better performance if the caller already has
+ a <see cref="T:System.IO.TextWriter"/> open and ready for writing.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AppenderSkeleton.RenderLoggingEvent(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Renders the <see cref="T:log4net.Core.LoggingEvent"/> to a string.
+ </summary>
+ <param name="loggingEvent">The event to render.</param>
+ <param name="writer">The TextWriter to write the formatted event to</param>
+ <remarks>
+ <para>
+ Helper method to render a <see cref="T:log4net.Core.LoggingEvent"/> to
+ a string. This appender must have a <see cref="P:log4net.Appender.AppenderSkeleton.Layout"/>
+ set to render the <paramref name="loggingEvent"/> to
+ a string.
+ </para>
+ <para>If there is exception data in the logging event and
+ the layout does not process the exception, this method
+ will append the exception text to the rendered string.
+ </para>
+ <para>
+ Use this method in preference to <see cref="M:log4net.Appender.AppenderSkeleton.RenderLoggingEvent(log4net.Core.LoggingEvent)"/>
+ where possible. If, however, the caller needs to render the event
+ to a string then <see cref="M:log4net.Appender.AppenderSkeleton.RenderLoggingEvent(log4net.Core.LoggingEvent)"/> does
+ provide an efficient mechanism for doing so.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.AppenderSkeleton.m_layout">
+ <summary>
+ The layout of this appender.
+ </summary>
+ <remarks>
+ See <see cref="P:log4net.Appender.AppenderSkeleton.Layout"/> for more information.
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.AppenderSkeleton.m_name">
+ <summary>
+ The name of this appender.
+ </summary>
+ <remarks>
+ See <see cref="P:log4net.Appender.AppenderSkeleton.Name"/> for more information.
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.AppenderSkeleton.m_threshold">
+ <summary>
+ The level threshold of this appender.
+ </summary>
+ <remarks>
+ <para>
+ There is no level threshold filtering by default.
+ </para>
+ <para>
+ See <see cref="P:log4net.Appender.AppenderSkeleton.Threshold"/> for more information.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.AppenderSkeleton.m_errorHandler">
+ <summary>
+ It is assumed and enforced that errorHandler is never null.
+ </summary>
+ <remarks>
+ <para>
+ It is assumed and enforced that errorHandler is never null.
+ </para>
+ <para>
+ See <see cref="P:log4net.Appender.AppenderSkeleton.ErrorHandler"/> for more information.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.AppenderSkeleton.m_headFilter">
+ <summary>
+ The first filter in the filter chain.
+ </summary>
+ <remarks>
+ <para>
+ Set to <c>null</c> initially.
+ </para>
+ <para>
+ See <see cref="T:log4net.Filter.IFilter"/> for more information.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.AppenderSkeleton.m_tailFilter">
+ <summary>
+ The last filter in the filter chain.
+ </summary>
+ <remarks>
+ See <see cref="T:log4net.Filter.IFilter"/> for more information.
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.AppenderSkeleton.m_closed">
+ <summary>
+ Flag indicating if this appender is closed.
+ </summary>
+ <remarks>
+ See <see cref="M:log4net.Appender.AppenderSkeleton.Close"/> for more information.
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.AppenderSkeleton.m_recursiveGuard">
+ <summary>
+ The guard prevents an appender from repeatedly calling its own DoAppend method
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AppenderSkeleton.m_renderWriter">
+ <summary>
+ StringWriter used to render events
+ </summary>
+ </member>
+ <member name="P:log4net.Appender.AppenderSkeleton.Threshold">
+ <summary>
+ Gets or sets the threshold <see cref="T:log4net.Core.Level"/> of this appender.
+ </summary>
+ <value>
+ The threshold <see cref="T:log4net.Core.Level"/> of the appender.
+ </value>
+ <remarks>
+ <para>
+ All log events with lower level than the threshold level are ignored
+ by the appender.
+ </para>
+ <para>
+ In configuration files this option is specified by setting the
+ value of the <see cref="P:log4net.Appender.AppenderSkeleton.Threshold"/> option to a level
+ string, such as "DEBUG", "INFO" and so on.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.AppenderSkeleton.ErrorHandler">
+ <summary>
+ Gets or sets the <see cref="T:log4net.Core.IErrorHandler"/> for this appender.
+ </summary>
+ <value>The <see cref="T:log4net.Core.IErrorHandler"/> of the appender</value>
+ <remarks>
+ <para>
+ The <see cref="T:log4net.Appender.AppenderSkeleton"/> provides a default
+ implementation for the <see cref="P:log4net.Appender.AppenderSkeleton.ErrorHandler"/> property.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.AppenderSkeleton.FilterHead">
+ <summary>
+ The filter chain.
+ </summary>
+ <value>The head of the filter chain filter chain.</value>
+ <remarks>
+ <para>
+ Returns the head Filter. The Filters are organized in a linked list
+ and so all Filters on this Appender are available through the result.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.AppenderSkeleton.Layout">
+ <summary>
+ Gets or sets the <see cref="T:log4net.Layout.ILayout"/> for this appender.
+ </summary>
+ <value>The layout of the appender.</value>
+ <remarks>
+ <para>
+ See <see cref="P:log4net.Appender.AppenderSkeleton.RequiresLayout"/> for more information.
+ </para>
+ </remarks>
+ <seealso cref="P:log4net.Appender.AppenderSkeleton.RequiresLayout"/>
+ </member>
+ <member name="P:log4net.Appender.AppenderSkeleton.Name">
+ <summary>
+ Gets or sets the name of this appender.
+ </summary>
+ <value>The name of the appender.</value>
+ <remarks>
+ <para>
+ The name uniquely identifies the appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.AppenderSkeleton.RequiresLayout">
+ <summary>
+ Tests if this appender requires a <see cref="P:log4net.Appender.AppenderSkeleton.Layout"/> to be set.
+ </summary>
+ <remarks>
+ <para>
+ In the rather exceptional case, where the appender
+ implementation admits a layout but can also work without it,
+ then the appender should return <c>true</c>.
+ </para>
+ <para>
+ This default implementation always returns <c>true</c>.
+ </para>
+ </remarks>
+ <returns>
+ <c>true</c> if the appender requires a layout object, otherwise <c>false</c>.
+ </returns>
+ </member>
+ <member name="F:log4net.Appender.BufferingAppenderSkeleton.DEFAULT_BUFFER_SIZE">
+ <summary>
+ The default buffer size.
+ </summary>
+ <remarks>
+ The default size of the cyclic buffer used to store events.
+ This is set to 512 by default.
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.BufferingAppenderSkeleton.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.BufferingAppenderSkeleton"/> class.
+ </summary>
+ <remarks>
+ <para>
+ Protected default constructor to allow subclassing.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.BufferingAppenderSkeleton.#ctor(System.Boolean)">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.BufferingAppenderSkeleton"/> class.
+ </summary>
+ <param name="eventMustBeFixed">the events passed through this appender must be
+ fixed by the time that they arrive in the derived class' <c>SendBuffer</c> method.</param>
+ <remarks>
+ <para>
+ Protected constructor to allow subclassing.
+ </para>
+ <para>
+ The <paramref name="eventMustBeFixed"/> should be set if the subclass
+ expects the events delivered to be fixed even if the
+ <see cref="P:log4net.Appender.BufferingAppenderSkeleton.BufferSize"/> is set to zero, i.e. when no buffering occurs.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.BufferingAppenderSkeleton.Flush">
+ <summary>
+ Flush the currently buffered events
+ </summary>
+ <remarks>
+ <para>
+ Flushes any events that have been buffered.
+ </para>
+ <para>
+ If the appender is buffering in <see cref="P:log4net.Appender.BufferingAppenderSkeleton.Lossy"/> mode then the contents
+ of the buffer will NOT be flushed to the appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.BufferingAppenderSkeleton.Flush(System.Boolean)">
+ <summary>
+ Flush the currently buffered events
+ </summary>
+ <param name="flushLossyBuffer">set to <c>true</c> to flush the buffer of lossy events</param>
+ <remarks>
+ <para>
+ Flushes events that have been buffered. If <paramref name="flushLossyBuffer"/> is
+ <c>false</c> then events will only be flushed if this buffer is non-lossy mode.
+ </para>
+ <para>
+ If the appender is buffering in <see cref="P:log4net.Appender.BufferingAppenderSkeleton.Lossy"/> mode then the contents
+ of the buffer will only be flushed if <paramref name="flushLossyBuffer"/> is <c>true</c>.
+ In this case the contents of the buffer will be tested against the
+ <see cref="P:log4net.Appender.BufferingAppenderSkeleton.LossyEvaluator"/> and if triggering will be output. All other buffered
+ events will be discarded.
+ </para>
+ <para>
+ If <paramref name="flushLossyBuffer"/> is <c>true</c> then the buffer will always
+ be emptied by calling this method.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.BufferingAppenderSkeleton.ActivateOptions">
+ <summary>
+ Initialize the appender based on the options set
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Appender.BufferingAppenderSkeleton.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Appender.BufferingAppenderSkeleton.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Appender.BufferingAppenderSkeleton.ActivateOptions"/> must be called again.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.BufferingAppenderSkeleton.OnClose">
+ <summary>
+ Close this appender instance.
+ </summary>
+ <remarks>
+ <para>
+ Close this appender instance. If this appender is marked
+ as not <see cref="P:log4net.Appender.BufferingAppenderSkeleton.Lossy"/> then the remaining events in
+ the buffer must be sent when the appender is closed.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.BufferingAppenderSkeleton.Append(log4net.Core.LoggingEvent)">
+ <summary>
+ This method is called by the <see cref="M:log4net.Appender.AppenderSkeleton.DoAppend(log4net.Core.LoggingEvent)"/> method.
+ </summary>
+ <param name="loggingEvent">the event to log</param>
+ <remarks>
+ <para>
+ Stores the <paramref name="loggingEvent"/> in the cyclic buffer.
+ </para>
+ <para>
+ The buffer will be sent (i.e. passed to the <see cref="M:log4net.Appender.BufferingAppenderSkeleton.SendBuffer(log4net.Core.LoggingEvent[])"/>
+ method) if one of the following conditions is met:
+ </para>
+ <list type="bullet">
+ <item>
+ <description>The cyclic buffer is full and this appender is
+ marked as not lossy (see <see cref="P:log4net.Appender.BufferingAppenderSkeleton.Lossy"/>)</description>
+ </item>
+ <item>
+ <description>An <see cref="P:log4net.Appender.BufferingAppenderSkeleton.Evaluator"/> is set and
+ it is triggered for the <paramref name="loggingEvent"/>
+ specified.</description>
+ </item>
+ </list>
+ <para>
+ Before the event is stored in the buffer it is fixed
+ (see <see cref="M:log4net.Core.LoggingEvent.FixVolatileData(log4net.Core.FixFlags)"/>) to ensure that
+ any data referenced by the event will be valid when the buffer
+ is processed.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.BufferingAppenderSkeleton.SendFromBuffer(log4net.Core.LoggingEvent,log4net.Util.CyclicBuffer)">
+ <summary>
+ Sends the contents of the buffer.
+ </summary>
+ <param name="firstLoggingEvent">The first logging event.</param>
+ <param name="buffer">The buffer containing the events that need to be send.</param>
+ <remarks>
+ <para>
+ The subclass must override <see cref="M:log4net.Appender.BufferingAppenderSkeleton.SendBuffer(log4net.Core.LoggingEvent[])"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.BufferingAppenderSkeleton.SendBuffer(log4net.Core.LoggingEvent[])">
+ <summary>
+ Sends the events.
+ </summary>
+ <param name="events">The events that need to be send.</param>
+ <remarks>
+ <para>
+ The subclass must override this method to process the buffered events.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.BufferingAppenderSkeleton.m_bufferSize">
+ <summary>
+ The size of the cyclic buffer used to hold the logging events.
+ </summary>
+ <remarks>
+ Set to <see cref="F:log4net.Appender.BufferingAppenderSkeleton.DEFAULT_BUFFER_SIZE"/> by default.
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.BufferingAppenderSkeleton.m_cb">
+ <summary>
+ The cyclic buffer used to store the logging events.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.BufferingAppenderSkeleton.m_evaluator">
+ <summary>
+ The triggering event evaluator that causes the buffer to be sent immediately.
+ </summary>
+ <remarks>
+ The object that is used to determine if an event causes the entire
+ buffer to be sent immediately. This field can be <c>null</c>, which
+ indicates that event triggering is not to be done. The evaluator
+ can be set using the <see cref="P:log4net.Appender.BufferingAppenderSkeleton.Evaluator"/> property. If this appender
+ has the <see cref="F:log4net.Appender.BufferingAppenderSkeleton.m_lossy"/> (<see cref="P:log4net.Appender.BufferingAppenderSkeleton.Lossy"/> property) set to
+ <c>true</c> then an <see cref="P:log4net.Appender.BufferingAppenderSkeleton.Evaluator"/> must be set.
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.BufferingAppenderSkeleton.m_lossy">
+ <summary>
+ Indicates if the appender should overwrite events in the cyclic buffer
+ when it becomes full, or if the buffer should be flushed when the
+ buffer is full.
+ </summary>
+ <remarks>
+ If this field is set to <c>true</c> then an <see cref="P:log4net.Appender.BufferingAppenderSkeleton.Evaluator"/> must
+ be set.
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.BufferingAppenderSkeleton.m_lossyEvaluator">
+ <summary>
+ The triggering event evaluator filters discarded events.
+ </summary>
+ <remarks>
+ The object that is used to determine if an event that is discarded should
+ really be discarded or if it should be sent to the appenders.
+ This field can be <c>null</c>, which indicates that all discarded events will
+ be discarded.
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.BufferingAppenderSkeleton.m_fixFlags">
+ <summary>
+ Value indicating which fields in the event should be fixed
+ </summary>
+ <remarks>
+ By default all fields are fixed
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.BufferingAppenderSkeleton.m_eventMustBeFixed">
+ <summary>
+ The events delivered to the subclass must be fixed.
+ </summary>
+ </member>
+ <member name="P:log4net.Appender.BufferingAppenderSkeleton.Lossy">
+ <summary>
+ Gets or sets a value that indicates whether the appender is lossy.
+ </summary>
+ <value>
+ <c>true</c> if the appender is lossy, otherwise <c>false</c>. The default is <c>false</c>.
+ </value>
+ <remarks>
+ <para>
+ This appender uses a buffer to store logging events before
+ delivering them. A triggering event causes the whole buffer
+ to be send to the remote sink. If the buffer overruns before
+ a triggering event then logging events could be lost. Set
+ <see cref="P:log4net.Appender.BufferingAppenderSkeleton.Lossy"/> to <c>false</c> to prevent logging events
+ from being lost.
+ </para>
+ <para>If <see cref="P:log4net.Appender.BufferingAppenderSkeleton.Lossy"/> is set to <c>true</c> then an
+ <see cref="P:log4net.Appender.BufferingAppenderSkeleton.Evaluator"/> must be specified.</para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.BufferingAppenderSkeleton.BufferSize">
+ <summary>
+ Gets or sets the size of the cyclic buffer used to hold the
+ logging events.
+ </summary>
+ <value>
+ The size of the cyclic buffer used to hold the logging events.
+ </value>
+ <remarks>
+ <para>
+ The <see cref="P:log4net.Appender.BufferingAppenderSkeleton.BufferSize"/> option takes a positive integer
+ representing the maximum number of logging events to collect in
+ a cyclic buffer. When the <see cref="P:log4net.Appender.BufferingAppenderSkeleton.BufferSize"/> is reached,
+ oldest events are deleted as new events are added to the
+ buffer. By default the size of the cyclic buffer is 512 events.
+ </para>
+ <para>
+ If the <see cref="P:log4net.Appender.BufferingAppenderSkeleton.BufferSize"/> is set to a value less than
+ or equal to 1 then no buffering will occur. The logging event
+ will be delivered synchronously (depending on the <see cref="P:log4net.Appender.BufferingAppenderSkeleton.Lossy"/>
+ and <see cref="P:log4net.Appender.BufferingAppenderSkeleton.Evaluator"/> properties). Otherwise the event will
+ be buffered.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.BufferingAppenderSkeleton.Evaluator">
+ <summary>
+ Gets or sets the <see cref="T:log4net.Core.ITriggeringEventEvaluator"/> that causes the
+ buffer to be sent immediately.
+ </summary>
+ <value>
+ The <see cref="T:log4net.Core.ITriggeringEventEvaluator"/> that causes the buffer to be
+ sent immediately.
+ </value>
+ <remarks>
+ <para>
+ The evaluator will be called for each event that is appended to this
+ appender. If the evaluator triggers then the current buffer will
+ immediately be sent (see <see cref="M:log4net.Appender.BufferingAppenderSkeleton.SendBuffer(log4net.Core.LoggingEvent[])"/>).
+ </para>
+ <para>If <see cref="P:log4net.Appender.BufferingAppenderSkeleton.Lossy"/> is set to <c>true</c> then an
+ <see cref="P:log4net.Appender.BufferingAppenderSkeleton.Evaluator"/> must be specified.</para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.BufferingAppenderSkeleton.LossyEvaluator">
+ <summary>
+ Gets or sets the value of the <see cref="T:log4net.Core.ITriggeringEventEvaluator"/> to use.
+ </summary>
+ <value>
+ The value of the <see cref="T:log4net.Core.ITriggeringEventEvaluator"/> to use.
+ </value>
+ <remarks>
+ <para>
+ The evaluator will be called for each event that is discarded from this
+ appender. If the evaluator triggers then the current buffer will immediately
+ be sent (see <see cref="M:log4net.Appender.BufferingAppenderSkeleton.SendBuffer(log4net.Core.LoggingEvent[])"/>).
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.BufferingAppenderSkeleton.OnlyFixPartialEventData">
+ <summary>
+ Gets or sets a value indicating if only part of the logging event data
+ should be fixed.
+ </summary>
+ <value>
+ <c>true</c> if the appender should only fix part of the logging event
+ data, otherwise <c>false</c>. The default is <c>false</c>.
+ </value>
+ <remarks>
+ <para>
+ Setting this property to <c>true</c> will cause only part of the
+ event data to be fixed and serialized. This will improve performance.
+ </para>
+ <para>
+ See <see cref="M:log4net.Core.LoggingEvent.FixVolatileData(log4net.Core.FixFlags)"/> for more information.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.BufferingAppenderSkeleton.Fix">
+ <summary>
+ Gets or sets a the fields that will be fixed in the event
+ </summary>
+ <value>
+ The event fields that will be fixed before the event is buffered
+ </value>
+ <remarks>
+ <para>
+ The logging event needs to have certain thread specific values
+ captured before it can be buffered. See <see cref="P:log4net.Core.LoggingEvent.Fix"/>
+ for details.
+ </para>
+ </remarks>
+ <seealso cref="P:log4net.Core.LoggingEvent.Fix"/>
+ </member>
+ <member name="M:log4net.Appender.AdoNetAppender.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.AdoNetAppender"/> class.
+ </summary>
+ <remarks>
+ Public default constructor to initialize a new instance of this class.
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AdoNetAppender.ActivateOptions">
+ <summary>
+ Initialize the appender based on the options set
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Appender.AdoNetAppender.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Appender.AdoNetAppender.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Appender.AdoNetAppender.ActivateOptions"/> must be called again.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AdoNetAppender.OnClose">
+ <summary>
+ Override the parent method to close the database
+ </summary>
+ <remarks>
+ <para>
+ Closes the database command and database connection.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AdoNetAppender.SendBuffer(log4net.Core.LoggingEvent[])">
+ <summary>
+ Inserts the events into the database.
+ </summary>
+ <param name="events">The events to insert into the database.</param>
+ <remarks>
+ <para>
+ Insert all the events specified in the <paramref name="events"/>
+ array into the database.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AdoNetAppender.AddParameter(log4net.Appender.AdoNetAppenderParameter)">
+ <summary>
+ Adds a parameter to the command.
+ </summary>
+ <param name="parameter">The parameter to add to the command.</param>
+ <remarks>
+ <para>
+ Adds a parameter to the ordered list of command parameters.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AdoNetAppender.SendBuffer(System.Data.IDbTransaction,log4net.Core.LoggingEvent[])">
+ <summary>
+ Writes the events to the database using the transaction specified.
+ </summary>
+ <param name="dbTran">The transaction that the events will be executed under.</param>
+ <param name="events">The array of events to insert into the database.</param>
+ <remarks>
+ <para>
+ The transaction argument can be <c>null</c> if the appender has been
+ configured not to use transactions. See <see cref="P:log4net.Appender.AdoNetAppender.UseTransactions"/>
+ property for more information.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AdoNetAppender.GetLogStatement(log4net.Core.LoggingEvent)">
+ <summary>
+ Formats the log message into database statement text.
+ </summary>
+ <param name="logEvent">The event being logged.</param>
+ <remarks>
+ This method can be overridden by subclasses to provide
+ more control over the format of the database statement.
+ </remarks>
+ <returns>
+ Text that can be passed to a <see cref="T:System.Data.IDbCommand"/>.
+ </returns>
+ </member>
+ <member name="M:log4net.Appender.AdoNetAppender.InitializeDatabaseConnection">
+ <summary>
+ Connects to the database.
+ </summary>
+ </member>
+ <member name="M:log4net.Appender.AdoNetAppender.ResolveConnectionType">
+ <summary>
+ Retrieves the class type of the ADO.NET provider.
+ </summary>
+ <remarks>
+ <para>
+ Gets the Type of the ADO.NET provider to use to connect to the
+ database. This method resolves the type specified in the
+ <see cref="P:log4net.Appender.AdoNetAppender.ConnectionType"/> property.
+ </para>
+ <para>
+ Subclasses can override this method to return a different type
+ if necessary.
+ </para>
+ </remarks>
+ <returns>The <see cref="T:System.Type"/> of the ADO.NET provider</returns>
+ </member>
+ <member name="M:log4net.Appender.AdoNetAppender.InitializeDatabaseCommand">
+ <summary>
+ Prepares the database command and initialize the parameters.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AdoNetAppender.m_usePreparedCommand">
+ <summary>
+ Flag to indicate if we are using a command object
+ </summary>
+ <remarks>
+ <para>
+ Set to <c>true</c> when the appender is to use a prepared
+ statement or stored procedure to insert into the database.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.AdoNetAppender.m_parameters">
+ <summary>
+ The list of <see cref="T:log4net.Appender.AdoNetAppenderParameter"/> objects.
+ </summary>
+ <remarks>
+ <para>
+ The list of <see cref="T:log4net.Appender.AdoNetAppenderParameter"/> objects.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.AdoNetAppender.m_securityContext">
+ <summary>
+ The security context to use for privileged calls
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AdoNetAppender.m_dbConnection">
+ <summary>
+ The <see cref="T:System.Data.IDbConnection"/> that will be used
+ to insert logging events into a database.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AdoNetAppender.m_dbCommand">
+ <summary>
+ The database command.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AdoNetAppender.m_connectionString">
+ <summary>
+ Database connection string.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AdoNetAppender.m_connectionType">
+ <summary>
+ String type name of the <see cref="T:System.Data.IDbConnection"/> type name.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AdoNetAppender.m_commandText">
+ <summary>
+ The text of the command.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AdoNetAppender.m_commandType">
+ <summary>
+ The command type.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AdoNetAppender.m_useTransactions">
+ <summary>
+ Indicates whether to use transactions when writing to the database.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AdoNetAppender.m_reconnectOnError">
+ <summary>
+ Indicates whether to use transactions when writing to the database.
+ </summary>
+ </member>
+ <member name="P:log4net.Appender.AdoNetAppender.ConnectionString">
+ <summary>
+ Gets or sets the database connection string that is used to connect to
+ the database.
+ </summary>
+ <value>
+ The database connection string used to connect to the database.
+ </value>
+ <remarks>
+ <para>
+ The connections string is specific to the connection type.
+ See <see cref="P:log4net.Appender.AdoNetAppender.ConnectionType"/> for more information.
+ </para>
+ </remarks>
+ <example>Connection string for MS Access via ODBC:
+ <code>"DSN=MS Access Database;UID=admin;PWD=;SystemDB=C:\data\System.mdw;SafeTransactions = 0;FIL=MS Access;DriverID = 25;DBQ=C:\data\train33.mdb"</code>
+ </example>
+ <example>Another connection string for MS Access via ODBC:
+ <code>"Driver={Microsoft Access Driver (*.mdb)};DBQ=C:\Work\cvs_root\log4net-1.2\access.mdb;UID=;PWD=;"</code>
+ </example>
+ <example>Connection string for MS Access via OLE DB:
+ <code>"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Work\cvs_root\log4net-1.2\access.mdb;User Id=;Password=;"</code>
+ </example>
+ </member>
+ <member name="P:log4net.Appender.AdoNetAppender.ConnectionType">
+ <summary>
+ Gets or sets the type name of the <see cref="T:System.Data.IDbConnection"/> connection
+ that should be created.
+ </summary>
+ <value>
+ The type name of the <see cref="T:System.Data.IDbConnection"/> connection.
+ </value>
+ <remarks>
+ <para>
+ The type name of the ADO.NET provider to use.
+ </para>
+ <para>
+ The default is to use the OLE DB provider.
+ </para>
+ </remarks>
+ <example>Use the OLE DB Provider. This is the default value.
+ <code>System.Data.OleDb.OleDbConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</code>
+ </example>
+ <example>Use the MS SQL Server Provider.
+ <code>System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</code>
+ </example>
+ <example>Use the ODBC Provider.
+ <code>Microsoft.Data.Odbc.OdbcConnection,Microsoft.Data.Odbc,version=1.0.3300.0,publicKeyToken=b77a5c561934e089,culture=neutral</code>
+ This is an optional package that you can download from
+ <a href="http://msdn.microsoft.com/downloads">http://msdn.microsoft.com/downloads</a>
+ search for <b>ODBC .NET Data Provider</b>.
+ </example>
+ <example>Use the Oracle Provider.
+ <code>System.Data.OracleClient.OracleConnection, System.Data.OracleClient, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</code>
+ This is an optional package that you can download from
+ <a href="http://msdn.microsoft.com/downloads">http://msdn.microsoft.com/downloads</a>
+ search for <b>.NET Managed Provider for Oracle</b>.
+ </example>
+ </member>
+ <member name="P:log4net.Appender.AdoNetAppender.CommandText">
+ <summary>
+ Gets or sets the command text that is used to insert logging events
+ into the database.
+ </summary>
+ <value>
+ The command text used to insert logging events into the database.
+ </value>
+ <remarks>
+ <para>
+ Either the text of the prepared statement or the
+ name of the stored procedure to execute to write into
+ the database.
+ </para>
+ <para>
+ The <see cref="P:log4net.Appender.AdoNetAppender.CommandType"/> property determines if
+ this text is a prepared statement or a stored procedure.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.AdoNetAppender.CommandType">
+ <summary>
+ Gets or sets the command type to execute.
+ </summary>
+ <value>
+ The command type to execute.
+ </value>
+ <remarks>
+ <para>
+ This value may be either <see cref="F:System.Data.CommandType.Text"/> (<c>System.Data.CommandType.Text</c>) to specify
+ that the <see cref="P:log4net.Appender.AdoNetAppender.CommandText"/> is a prepared statement to execute,
+ or <see cref="F:System.Data.CommandType.StoredProcedure"/> (<c>System.Data.CommandType.StoredProcedure</c>) to specify that the
+ <see cref="P:log4net.Appender.AdoNetAppender.CommandText"/> property is the name of a stored procedure
+ to execute.
+ </para>
+ <para>
+ The default value is <see cref="F:System.Data.CommandType.Text"/> (<c>System.Data.CommandType.Text</c>).
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.AdoNetAppender.UseTransactions">
+ <summary>
+ Should transactions be used to insert logging events in the database.
+ </summary>
+ <value>
+ <c>true</c> if transactions should be used to insert logging events in
+ the database, otherwise <c>false</c>. The default value is <c>true</c>.
+ </value>
+ <remarks>
+ <para>
+ Gets or sets a value that indicates whether transactions should be used
+ to insert logging events in the database.
+ </para>
+ <para>
+ When set a single transaction will be used to insert the buffered events
+ into the database. Otherwise each event will be inserted without using
+ an explicit transaction.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.AdoNetAppender.SecurityContext">
+ <summary>
+ Gets or sets the <see cref="P:log4net.Appender.AdoNetAppender.SecurityContext"/> used to call the NetSend method.
+ </summary>
+ <value>
+ The <see cref="P:log4net.Appender.AdoNetAppender.SecurityContext"/> used to call the NetSend method.
+ </value>
+ <remarks>
+ <para>
+ Unless a <see cref="P:log4net.Appender.AdoNetAppender.SecurityContext"/> specified here for this appender
+ the <see cref="P:log4net.Core.SecurityContextProvider.DefaultProvider"/> is queried for the
+ security context to use. The default behavior is to use the security context
+ of the current thread.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.AdoNetAppender.ReconnectOnError">
+ <summary>
+ Should this appender try to reconnect to the database on error.
+ </summary>
+ <value>
+ <c>true</c> if the appender should try to reconnect to the database after an
+ error has occurred, otherwise <c>false</c>. The default value is <c>false</c>,
+ i.e. not to try to reconnect.
+ </value>
+ <remarks>
+ <para>
+ The default behaviour is for the appender not to try to reconnect to the
+ database if an error occurs. Subsequent logging events are discarded.
+ </para>
+ <para>
+ To force the appender to attempt to reconnect to the database set this
+ property to <c>true</c>.
+ </para>
+ <note>
+ When the appender attempts to connect to the database there may be a
+ delay of up to the connection timeout specified in the connection string.
+ This delay will block the calling application's thread.
+ Until the connection can be reestablished this potential delay may occur multiple times.
+ </note>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.AdoNetAppender.Connection">
+ <summary>
+ Gets or sets the underlying <see cref="T:System.Data.IDbConnection"/>.
+ </summary>
+ <value>
+ The underlying <see cref="T:System.Data.IDbConnection"/>.
+ </value>
+ <remarks>
+ <see cref="T:log4net.Appender.AdoNetAppender"/> creates a <see cref="T:System.Data.IDbConnection"/> to insert
+ logging events into a database. Classes deriving from <see cref="T:log4net.Appender.AdoNetAppender"/>
+ can use this property to get or set this <see cref="T:System.Data.IDbConnection"/>. Use the
+ underlying <see cref="T:System.Data.IDbConnection"/> returned from <see cref="P:log4net.Appender.AdoNetAppender.Connection"/> if
+ you require access beyond that which <see cref="T:log4net.Appender.AdoNetAppender"/> provides.
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.AdoNetAppenderParameter">
+ <summary>
+ Parameter type used by the <see cref="T:log4net.Appender.AdoNetAppender"/>.
+ </summary>
+ <remarks>
+ <para>
+ This class provides the basic database parameter properties
+ as defined by the <see cref="T:System.Data.IDbDataParameter"/> interface.
+ </para>
+ <para>This type can be subclassed to provide database specific
+ functionality. The two methods that are called externally are
+ <see cref="M:log4net.Appender.AdoNetAppenderParameter.Prepare(System.Data.IDbCommand)"/> and <see cref="M:log4net.Appender.AdoNetAppenderParameter.FormatValue(System.Data.IDbCommand,log4net.Core.LoggingEvent)"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AdoNetAppenderParameter.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.AdoNetAppenderParameter"/> class.
+ </summary>
+ <remarks>
+ Default constructor for the AdoNetAppenderParameter class.
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AdoNetAppenderParameter.Prepare(System.Data.IDbCommand)">
+ <summary>
+ Prepare the specified database command object.
+ </summary>
+ <param name="command">The command to prepare.</param>
+ <remarks>
+ <para>
+ Prepares the database command object by adding
+ this parameter to its collection of parameters.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AdoNetAppenderParameter.FormatValue(System.Data.IDbCommand,log4net.Core.LoggingEvent)">
+ <summary>
+ Renders the logging event and set the parameter value in the command.
+ </summary>
+ <param name="command">The command containing the parameter.</param>
+ <param name="loggingEvent">The event to be rendered.</param>
+ <remarks>
+ <para>
+ Renders the logging event using this parameters layout
+ object. Sets the value of the parameter on the command object.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.AdoNetAppenderParameter.m_parameterName">
+ <summary>
+ The name of this parameter.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AdoNetAppenderParameter.m_dbType">
+ <summary>
+ The database type for this parameter.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AdoNetAppenderParameter.m_inferType">
+ <summary>
+ Flag to infer type rather than use the DbType
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AdoNetAppenderParameter.m_precision">
+ <summary>
+ The precision for this parameter.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AdoNetAppenderParameter.m_scale">
+ <summary>
+ The scale for this parameter.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AdoNetAppenderParameter.m_size">
+ <summary>
+ The size for this parameter.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AdoNetAppenderParameter.m_layout">
+ <summary>
+ The <see cref="T:log4net.Layout.IRawLayout"/> to use to render the
+ logging event into an object for this parameter.
+ </summary>
+ </member>
+ <member name="P:log4net.Appender.AdoNetAppenderParameter.ParameterName">
+ <summary>
+ Gets or sets the name of this parameter.
+ </summary>
+ <value>
+ The name of this parameter.
+ </value>
+ <remarks>
+ <para>
+ The name of this parameter. The parameter name
+ must match up to a named parameter to the SQL stored procedure
+ or prepared statement.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.AdoNetAppenderParameter.DbType">
+ <summary>
+ Gets or sets the database type for this parameter.
+ </summary>
+ <value>
+ The database type for this parameter.
+ </value>
+ <remarks>
+ <para>
+ The database type for this parameter. This property should
+ be set to the database type from the <see cref="P:log4net.Appender.AdoNetAppenderParameter.DbType"/>
+ enumeration. See <see cref="P:System.Data.IDataParameter.DbType"/>.
+ </para>
+ <para>
+ This property is optional. If not specified the ADO.NET provider
+ will attempt to infer the type from the value.
+ </para>
+ </remarks>
+ <seealso cref="P:System.Data.IDataParameter.DbType"/>
+ </member>
+ <member name="P:log4net.Appender.AdoNetAppenderParameter.Precision">
+ <summary>
+ Gets or sets the precision for this parameter.
+ </summary>
+ <value>
+ The precision for this parameter.
+ </value>
+ <remarks>
+ <para>
+ The maximum number of digits used to represent the Value.
+ </para>
+ <para>
+ This property is optional. If not specified the ADO.NET provider
+ will attempt to infer the precision from the value.
+ </para>
+ </remarks>
+ <seealso cref="P:System.Data.IDbDataParameter.Precision"/>
+ </member>
+ <member name="P:log4net.Appender.AdoNetAppenderParameter.Scale">
+ <summary>
+ Gets or sets the scale for this parameter.
+ </summary>
+ <value>
+ The scale for this parameter.
+ </value>
+ <remarks>
+ <para>
+ The number of decimal places to which Value is resolved.
+ </para>
+ <para>
+ This property is optional. If not specified the ADO.NET provider
+ will attempt to infer the scale from the value.
+ </para>
+ </remarks>
+ <seealso cref="P:System.Data.IDbDataParameter.Scale"/>
+ </member>
+ <member name="P:log4net.Appender.AdoNetAppenderParameter.Size">
+ <summary>
+ Gets or sets the size for this parameter.
+ </summary>
+ <value>
+ The size for this parameter.
+ </value>
+ <remarks>
+ <para>
+ The maximum size, in bytes, of the data within the column.
+ </para>
+ <para>
+ This property is optional. If not specified the ADO.NET provider
+ will attempt to infer the size from the value.
+ </para>
+ </remarks>
+ <seealso cref="P:System.Data.IDbDataParameter.Size"/>
+ </member>
+ <member name="P:log4net.Appender.AdoNetAppenderParameter.Layout">
+ <summary>
+ Gets or sets the <see cref="T:log4net.Layout.IRawLayout"/> to use to
+ render the logging event into an object for this
+ parameter.
+ </summary>
+ <value>
+ The <see cref="T:log4net.Layout.IRawLayout"/> used to render the
+ logging event into an object for this parameter.
+ </value>
+ <remarks>
+ <para>
+ The <see cref="T:log4net.Layout.IRawLayout"/> that renders the value for this
+ parameter.
+ </para>
+ <para>
+ The <see cref="T:log4net.Layout.RawLayoutConverter"/> can be used to adapt
+ any <see cref="T:log4net.Layout.ILayout"/> into a <see cref="T:log4net.Layout.IRawLayout"/>
+ for use in the property.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.AnsiColorTerminalAppender">
+ <summary>
+ Appends logging events to the terminal using ANSI color escape sequences.
+ </summary>
+ <remarks>
+ <para>
+ AnsiColorTerminalAppender appends log events to the standard output stream
+ or the error output stream using a layout specified by the
+ user. It also allows the color of a specific level of message to be set.
+ </para>
+ <note>
+ This appender expects the terminal to understand the VT100 control set
+ in order to interpret the color codes. If the terminal or console does not
+ understand the control codes the behavior is not defined.
+ </note>
+ <para>
+ By default, all output is written to the console's standard output stream.
+ The <see cref="P:log4net.Appender.AnsiColorTerminalAppender.Target"/> property can be set to direct the output to the
+ error stream.
+ </para>
+ <para>
+ NOTE: This appender writes each message to the <c>System.Console.Out</c> or
+ <c>System.Console.Error</c> that is set at the time the event is appended.
+ Therefore it is possible to programmatically redirect the output of this appender
+ (for example NUnit does this to capture program output). While this is the desired
+ behavior of this appender it may have security implications in your application.
+ </para>
+ <para>
+ When configuring the ANSI colored terminal appender, a mapping should be
+ specified to map a logging level to a color. For example:
+ </para>
+ <code lang="XML" escaped="true">
+ <mapping>
+ <level value="ERROR"/>
+ <foreColor value="White"/>
+ <backColor value="Red"/>
+ <attributes value="Bright,Underscore"/>
+ </mapping>
+ <mapping>
+ <level value="DEBUG"/>
+ <backColor value="Green"/>
+ </mapping>
+ </code>
+ <para>
+ The Level is the standard log4net logging level and ForeColor and BackColor can be any
+ of the following values:
+ <list type="bullet">
+ <item><term>Blue</term><description></description></item>
+ <item><term>Green</term><description></description></item>
+ <item><term>Red</term><description></description></item>
+ <item><term>White</term><description></description></item>
+ <item><term>Yellow</term><description></description></item>
+ <item><term>Purple</term><description></description></item>
+ <item><term>Cyan</term><description></description></item>
+ </list>
+ These color values cannot be combined together to make new colors.
+ </para>
+ <para>
+ The attributes can be any combination of the following:
+ <list type="bullet">
+ <item><term>Bright</term><description>foreground is brighter</description></item>
+ <item><term>Dim</term><description>foreground is dimmer</description></item>
+ <item><term>Underscore</term><description>message is underlined</description></item>
+ <item><term>Blink</term><description>foreground is blinking (does not work on all terminals)</description></item>
+ <item><term>Reverse</term><description>foreground and background are reversed</description></item>
+ <item><term>Hidden</term><description>output is hidden</description></item>
+ <item><term>Strikethrough</term><description>message has a line through it</description></item>
+ </list>
+ While any of these attributes may be combined together not all combinations
+ work well together, for example setting both <i>Bright</i> and <i>Dim</i> attributes makes
+ no sense.
+ </para>
+ </remarks>
+ <author>Patrick Wagstrom</author>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="F:log4net.Appender.AnsiColorTerminalAppender.ConsoleOut">
+ <summary>
+ The <see cref="P:log4net.Appender.AnsiColorTerminalAppender.Target"/> to use when writing to the Console
+ standard output stream.
+ </summary>
+ <remarks>
+ <para>
+ The <see cref="P:log4net.Appender.AnsiColorTerminalAppender.Target"/> to use when writing to the Console
+ standard output stream.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.AnsiColorTerminalAppender.ConsoleError">
+ <summary>
+ The <see cref="P:log4net.Appender.AnsiColorTerminalAppender.Target"/> to use when writing to the Console
+ standard error output stream.
+ </summary>
+ <remarks>
+ <para>
+ The <see cref="P:log4net.Appender.AnsiColorTerminalAppender.Target"/> to use when writing to the Console
+ standard error output stream.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.AnsiColorTerminalAppender.PostEventCodes">
+ <summary>
+ Ansi code to reset terminal
+ </summary>
+ </member>
+ <member name="M:log4net.Appender.AnsiColorTerminalAppender.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.AnsiColorTerminalAppender"/> class.
+ </summary>
+ <remarks>
+ The instance of the <see cref="T:log4net.Appender.AnsiColorTerminalAppender"/> class is set up to write
+ to the standard output stream.
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AnsiColorTerminalAppender.AddMapping(log4net.Appender.AnsiColorTerminalAppender.LevelColors)">
+ <summary>
+ Add a mapping of level to color
+ </summary>
+ <param name="mapping">The mapping to add</param>
+ <remarks>
+ <para>
+ Add a <see cref="T:log4net.Appender.AnsiColorTerminalAppender.LevelColors"/> mapping to this appender.
+ Each mapping defines the foreground and background colours
+ for a level.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AnsiColorTerminalAppender.Append(log4net.Core.LoggingEvent)">
+ <summary>
+ This method is called by the <see cref="M:log4net.Appender.AppenderSkeleton.DoAppend(log4net.Core.LoggingEvent)"/> method.
+ </summary>
+ <param name="loggingEvent">The event to log.</param>
+ <remarks>
+ <para>
+ Writes the event to the console.
+ </para>
+ <para>
+ The format of the output will depend on the appender's layout.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AnsiColorTerminalAppender.ActivateOptions">
+ <summary>
+ Initialize the options for this appender
+ </summary>
+ <remarks>
+ <para>
+ Initialize the level to color mappings set on this appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.AnsiColorTerminalAppender.m_writeToErrorStream">
+ <summary>
+ Flag to write output to the error stream rather than the standard output stream
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AnsiColorTerminalAppender.m_levelMapping">
+ <summary>
+ Mapping from level object to color value
+ </summary>
+ </member>
+ <member name="P:log4net.Appender.AnsiColorTerminalAppender.Target">
+ <summary>
+ Target is the value of the console output stream.
+ </summary>
+ <value>
+ Target is the value of the console output stream.
+ This is either <c>"Console.Out"</c> or <c>"Console.Error"</c>.
+ </value>
+ <remarks>
+ <para>
+ Target is the value of the console output stream.
+ This is either <c>"Console.Out"</c> or <c>"Console.Error"</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.AnsiColorTerminalAppender.RequiresLayout">
+ <summary>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </summary>
+ <value><c>true</c></value>
+ <remarks>
+ <para>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.AnsiColorTerminalAppender.AnsiAttributes">
+ <summary>
+ The enum of possible display attributes
+ </summary>
+ <remarks>
+ <para>
+ The following flags can be combined together to
+ form the ANSI color attributes.
+ </para>
+ </remarks>
+ <seealso cref="T:log4net.Appender.AnsiColorTerminalAppender"/>
+ </member>
+ <member name="F:log4net.Appender.AnsiColorTerminalAppender.AnsiAttributes.Bright">
+ <summary>
+ text is bright
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AnsiColorTerminalAppender.AnsiAttributes.Dim">
+ <summary>
+ text is dim
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AnsiColorTerminalAppender.AnsiAttributes.Underscore">
+ <summary>
+ text is underlined
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AnsiColorTerminalAppender.AnsiAttributes.Blink">
+ <summary>
+ text is blinking
+ </summary>
+ <remarks>
+ Not all terminals support this attribute
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.AnsiColorTerminalAppender.AnsiAttributes.Reverse">
+ <summary>
+ text and background colors are reversed
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AnsiColorTerminalAppender.AnsiAttributes.Hidden">
+ <summary>
+ text is hidden
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AnsiColorTerminalAppender.AnsiAttributes.Strikethrough">
+ <summary>
+ text is displayed with a strikethrough
+ </summary>
+ </member>
+ <member name="T:log4net.Appender.AnsiColorTerminalAppender.AnsiColor">
+ <summary>
+ The enum of possible foreground or background color values for
+ use with the color mapping method
+ </summary>
+ <remarks>
+ <para>
+ The output can be in one for the following ANSI colors.
+ </para>
+ </remarks>
+ <seealso cref="T:log4net.Appender.AnsiColorTerminalAppender"/>
+ </member>
+ <member name="F:log4net.Appender.AnsiColorTerminalAppender.AnsiColor.Black">
+ <summary>
+ color is black
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AnsiColorTerminalAppender.AnsiColor.Red">
+ <summary>
+ color is red
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AnsiColorTerminalAppender.AnsiColor.Green">
+ <summary>
+ color is green
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AnsiColorTerminalAppender.AnsiColor.Yellow">
+ <summary>
+ color is yellow
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AnsiColorTerminalAppender.AnsiColor.Blue">
+ <summary>
+ color is blue
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AnsiColorTerminalAppender.AnsiColor.Magenta">
+ <summary>
+ color is magenta
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AnsiColorTerminalAppender.AnsiColor.Cyan">
+ <summary>
+ color is cyan
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.AnsiColorTerminalAppender.AnsiColor.White">
+ <summary>
+ color is white
+ </summary>
+ </member>
+ <member name="T:log4net.Appender.AnsiColorTerminalAppender.LevelColors">
+ <summary>
+ A class to act as a mapping between the level that a logging call is made at and
+ the color it should be displayed as.
+ </summary>
+ <remarks>
+ <para>
+ Defines the mapping between a level and the color it should be displayed in.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.LevelMappingEntry">
+ <summary>
+ An entry in the <see cref="T:log4net.Util.LevelMapping"/>
+ </summary>
+ <remarks>
+ <para>
+ This is an abstract base class for types that are stored in the
+ <see cref="T:log4net.Util.LevelMapping"/> object.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.LevelMappingEntry.#ctor">
+ <summary>
+ Default protected constructor
+ </summary>
+ <remarks>
+ <para>
+ Default protected constructor
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.LevelMappingEntry.ActivateOptions">
+ <summary>
+ Initialize any options defined on this entry
+ </summary>
+ <remarks>
+ <para>
+ Should be overridden by any classes that need to initialise based on their options
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.LevelMappingEntry.Level">
+ <summary>
+ The level that is the key for this mapping
+ </summary>
+ <value>
+ The <see cref="P:log4net.Util.LevelMappingEntry.Level"/> that is the key for this mapping
+ </value>
+ <remarks>
+ <para>
+ Get or set the <see cref="P:log4net.Util.LevelMappingEntry.Level"/> that is the key for this
+ mapping subclass.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AnsiColorTerminalAppender.LevelColors.ActivateOptions">
+ <summary>
+ Initialize the options for the object
+ </summary>
+ <remarks>
+ <para>
+ Combine the <see cref="P:log4net.Appender.AnsiColorTerminalAppender.LevelColors.ForeColor"/> and <see cref="P:log4net.Appender.AnsiColorTerminalAppender.LevelColors.BackColor"/> together
+ and append the attributes.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.AnsiColorTerminalAppender.LevelColors.ForeColor">
+ <summary>
+ The mapped foreground color for the specified level
+ </summary>
+ <remarks>
+ <para>
+ Required property.
+ The mapped foreground color for the specified level
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.AnsiColorTerminalAppender.LevelColors.BackColor">
+ <summary>
+ The mapped background color for the specified level
+ </summary>
+ <remarks>
+ <para>
+ Required property.
+ The mapped background color for the specified level
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.AnsiColorTerminalAppender.LevelColors.Attributes">
+ <summary>
+ The color attributes for the specified level
+ </summary>
+ <remarks>
+ <para>
+ Required property.
+ The color attributes for the specified level
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.AnsiColorTerminalAppender.LevelColors.CombinedColor">
+ <summary>
+ The combined <see cref="P:log4net.Appender.AnsiColorTerminalAppender.LevelColors.ForeColor"/>, <see cref="P:log4net.Appender.AnsiColorTerminalAppender.LevelColors.BackColor"/> and
+ <see cref="P:log4net.Appender.AnsiColorTerminalAppender.LevelColors.Attributes"/> suitable for setting the ansi terminal color.
+ </summary>
+ </member>
+ <member name="T:log4net.Appender.AppenderCollection">
+ <summary>
+ A strongly-typed collection of <see cref="T:log4net.Appender.IAppender"/> objects.
+ </summary>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.ReadOnly(log4net.Appender.AppenderCollection)">
+ <summary>
+ Creates a read-only wrapper for a <c>AppenderCollection</c> instance.
+ </summary>
+ <param name="list">list to create a readonly wrapper arround</param>
+ <returns>
+ An <c>AppenderCollection</c> wrapper that is read-only.
+ </returns>
+ </member>
+ <member name="F:log4net.Appender.AppenderCollection.EmptyCollection">
+ <summary>
+ An empty readonly static AppenderCollection
+ </summary>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.#ctor">
+ <summary>
+ Initializes a new instance of the <c>AppenderCollection</c> class
+ that is empty and has the default initial capacity.
+ </summary>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.#ctor(System.Int32)">
+ <summary>
+ Initializes a new instance of the <c>AppenderCollection</c> class
+ that has the specified initial capacity.
+ </summary>
+ <param name="capacity">
+ The number of elements that the new <c>AppenderCollection</c> is initially capable of storing.
+ </param>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.#ctor(log4net.Appender.AppenderCollection)">
+ <summary>
+ Initializes a new instance of the <c>AppenderCollection</c> class
+ that contains elements copied from the specified <c>AppenderCollection</c>.
+ </summary>
+ <param name="c">The <c>AppenderCollection</c> whose elements are copied to the new collection.</param>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.#ctor(log4net.Appender.IAppender[])">
+ <summary>
+ Initializes a new instance of the <c>AppenderCollection</c> class
+ that contains elements copied from the specified <see cref="T:log4net.Appender.IAppender"/> array.
+ </summary>
+ <param name="a">The <see cref="T:log4net.Appender.IAppender"/> array whose elements are copied to the new list.</param>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.#ctor(System.Collections.ICollection)">
+ <summary>
+ Initializes a new instance of the <c>AppenderCollection</c> class
+ that contains elements copied from the specified <see cref="T:log4net.Appender.IAppender"/> collection.
+ </summary>
+ <param name="col">The <see cref="T:log4net.Appender.IAppender"/> collection whose elements are copied to the new list.</param>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.#ctor(log4net.Appender.AppenderCollection.Tag)">
+ <summary>
+ Allow subclasses to avoid our default constructors
+ </summary>
+ <param name="tag"></param>
+ <exclude/>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.CopyTo(log4net.Appender.IAppender[])">
+ <summary>
+ Copies the entire <c>AppenderCollection</c> to a one-dimensional
+ <see cref="T:log4net.Appender.IAppender"/> array.
+ </summary>
+ <param name="array">The one-dimensional <see cref="T:log4net.Appender.IAppender"/> array to copy to.</param>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.CopyTo(log4net.Appender.IAppender[],System.Int32)">
+ <summary>
+ Copies the entire <c>AppenderCollection</c> to a one-dimensional
+ <see cref="T:log4net.Appender.IAppender"/> array, starting at the specified index of the target array.
+ </summary>
+ <param name="array">The one-dimensional <see cref="T:log4net.Appender.IAppender"/> array to copy to.</param>
+ <param name="start">The zero-based index in <paramref name="array"/> at which copying begins.</param>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.Add(log4net.Appender.IAppender)">
+ <summary>
+ Adds a <see cref="T:log4net.Appender.IAppender"/> to the end of the <c>AppenderCollection</c>.
+ </summary>
+ <param name="item">The <see cref="T:log4net.Appender.IAppender"/> to be added to the end of the <c>AppenderCollection</c>.</param>
+ <returns>The index at which the value has been added.</returns>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.Clear">
+ <summary>
+ Removes all elements from the <c>AppenderCollection</c>.
+ </summary>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.Clone">
+ <summary>
+ Creates a shallow copy of the <see cref="T:log4net.Appender.AppenderCollection"/>.
+ </summary>
+ <returns>A new <see cref="T:log4net.Appender.AppenderCollection"/> with a shallow copy of the collection data.</returns>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.Contains(log4net.Appender.IAppender)">
+ <summary>
+ Determines whether a given <see cref="T:log4net.Appender.IAppender"/> is in the <c>AppenderCollection</c>.
+ </summary>
+ <param name="item">The <see cref="T:log4net.Appender.IAppender"/> to check for.</param>
+ <returns><c>true</c> if <paramref name="item"/> is found in the <c>AppenderCollection</c>; otherwise, <c>false</c>.</returns>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.IndexOf(log4net.Appender.IAppender)">
+ <summary>
+ Returns the zero-based index of the first occurrence of a <see cref="T:log4net.Appender.IAppender"/>
+ in the <c>AppenderCollection</c>.
+ </summary>
+ <param name="item">The <see cref="T:log4net.Appender.IAppender"/> to locate in the <c>AppenderCollection</c>.</param>
+ <returns>
+ The zero-based index of the first occurrence of <paramref name="item"/>
+ in the entire <c>AppenderCollection</c>, if found; otherwise, -1.
+ </returns>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.Insert(System.Int32,log4net.Appender.IAppender)">
+ <summary>
+ Inserts an element into the <c>AppenderCollection</c> at the specified index.
+ </summary>
+ <param name="index">The zero-based index at which <paramref name="item"/> should be inserted.</param>
+ <param name="item">The <see cref="T:log4net.Appender.IAppender"/> to insert.</param>
+ <exception cref="T:System.ArgumentOutOfRangeException">
+ <para><paramref name="index"/> is less than zero</para>
+ <para>-or-</para>
+ <para><paramref name="index"/> is equal to or greater than <see cref="P:log4net.Appender.AppenderCollection.Count"/>.</para>
+ </exception>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.Remove(log4net.Appender.IAppender)">
+ <summary>
+ Removes the first occurrence of a specific <see cref="T:log4net.Appender.IAppender"/> from the <c>AppenderCollection</c>.
+ </summary>
+ <param name="item">The <see cref="T:log4net.Appender.IAppender"/> to remove from the <c>AppenderCollection</c>.</param>
+ <exception cref="T:System.ArgumentException">
+ The specified <see cref="T:log4net.Appender.IAppender"/> was not found in the <c>AppenderCollection</c>.
+ </exception>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.RemoveAt(System.Int32)">
+ <summary>
+ Removes the element at the specified index of the <c>AppenderCollection</c>.
+ </summary>
+ <param name="index">The zero-based index of the element to remove.</param>
+ <exception cref="T:System.ArgumentOutOfRangeException">
+ <para><paramref name="index"/> is less than zero</para>
+ <para>-or-</para>
+ <para><paramref name="index"/> is equal to or greater than <see cref="P:log4net.Appender.AppenderCollection.Count"/>.</para>
+ </exception>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.GetEnumerator">
+ <summary>
+ Returns an enumerator that can iterate through the <c>AppenderCollection</c>.
+ </summary>
+ <returns>An <see cref="T:log4net.Appender.AppenderCollection.Enumerator"/> for the entire <c>AppenderCollection</c>.</returns>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.AddRange(log4net.Appender.AppenderCollection)">
+ <summary>
+ Adds the elements of another <c>AppenderCollection</c> to the current <c>AppenderCollection</c>.
+ </summary>
+ <param name="x">The <c>AppenderCollection</c> whose elements should be added to the end of the current <c>AppenderCollection</c>.</param>
+ <returns>The new <see cref="P:log4net.Appender.AppenderCollection.Count"/> of the <c>AppenderCollection</c>.</returns>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.AddRange(log4net.Appender.IAppender[])">
+ <summary>
+ Adds the elements of a <see cref="T:log4net.Appender.IAppender"/> array to the current <c>AppenderCollection</c>.
+ </summary>
+ <param name="x">The <see cref="T:log4net.Appender.IAppender"/> array whose elements should be added to the end of the <c>AppenderCollection</c>.</param>
+ <returns>The new <see cref="P:log4net.Appender.AppenderCollection.Count"/> of the <c>AppenderCollection</c>.</returns>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.AddRange(System.Collections.ICollection)">
+ <summary>
+ Adds the elements of a <see cref="T:log4net.Appender.IAppender"/> collection to the current <c>AppenderCollection</c>.
+ </summary>
+ <param name="col">The <see cref="T:log4net.Appender.IAppender"/> collection whose elements should be added to the end of the <c>AppenderCollection</c>.</param>
+ <returns>The new <see cref="P:log4net.Appender.AppenderCollection.Count"/> of the <c>AppenderCollection</c>.</returns>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.TrimToSize">
+ <summary>
+ Sets the capacity to the actual number of elements.
+ </summary>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.ToArray">
+ <summary>
+ Return the collection elements as an array
+ </summary>
+ <returns>the array</returns>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.ValidateIndex(System.Int32)">
+ <exception cref="T:System.ArgumentOutOfRangeException">
+ <para><paramref name="index"/> is less than zero</para>
+ <para>-or-</para>
+ <para><paramref name="index"/> is equal to or greater than <see cref="P:log4net.Appender.AppenderCollection.Count"/>.</para>
+ </exception>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.ValidateIndex(System.Int32,System.Boolean)">
+ <exception cref="T:System.ArgumentOutOfRangeException">
+ <para><paramref name="index"/> is less than zero</para>
+ <para>-or-</para>
+ <para><paramref name="index"/> is equal to or greater than <see cref="P:log4net.Appender.AppenderCollection.Count"/>.</para>
+ </exception>
+ </member>
+ <member name="P:log4net.Appender.AppenderCollection.Count">
+ <summary>
+ Gets the number of elements actually contained in the <c>AppenderCollection</c>.
+ </summary>
+ </member>
+ <member name="P:log4net.Appender.AppenderCollection.IsSynchronized">
+ <summary>
+ Gets a value indicating whether access to the collection is synchronized (thread-safe).
+ </summary>
+ <returns>true if access to the ICollection is synchronized (thread-safe); otherwise, false.</returns>
+ </member>
+ <member name="P:log4net.Appender.AppenderCollection.SyncRoot">
+ <summary>
+ Gets an object that can be used to synchronize access to the collection.
+ </summary>
+ </member>
+ <member name="P:log4net.Appender.AppenderCollection.Item(System.Int32)">
+ <summary>
+ Gets or sets the <see cref="T:log4net.Appender.IAppender"/> at the specified index.
+ </summary>
+ <param name="index">The zero-based index of the element to get or set.</param>
+ <exception cref="T:System.ArgumentOutOfRangeException">
+ <para><paramref name="index"/> is less than zero</para>
+ <para>-or-</para>
+ <para><paramref name="index"/> is equal to or greater than <see cref="P:log4net.Appender.AppenderCollection.Count"/>.</para>
+ </exception>
+ </member>
+ <member name="P:log4net.Appender.AppenderCollection.IsFixedSize">
+ <summary>
+ Gets a value indicating whether the collection has a fixed size.
+ </summary>
+ <value>true if the collection has a fixed size; otherwise, false. The default is false</value>
+ </member>
+ <member name="P:log4net.Appender.AppenderCollection.IsReadOnly">
+ <summary>
+ Gets a value indicating whether the IList is read-only.
+ </summary>
+ <value>true if the collection is read-only; otherwise, false. The default is false</value>
+ </member>
+ <member name="P:log4net.Appender.AppenderCollection.Capacity">
+ <summary>
+ Gets or sets the number of elements the <c>AppenderCollection</c> can contain.
+ </summary>
+ </member>
+ <member name="T:log4net.Appender.AppenderCollection.IAppenderCollectionEnumerator">
+ <summary>
+ Supports type-safe iteration over a <see cref="T:log4net.Appender.AppenderCollection"/>.
+ </summary>
+ <exclude/>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.IAppenderCollectionEnumerator.MoveNext">
+ <summary>
+ Advances the enumerator to the next element in the collection.
+ </summary>
+ <returns>
+ <c>true</c> if the enumerator was successfully advanced to the next element;
+ <c>false</c> if the enumerator has passed the end of the collection.
+ </returns>
+ <exception cref="T:System.InvalidOperationException">
+ The collection was modified after the enumerator was created.
+ </exception>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.IAppenderCollectionEnumerator.Reset">
+ <summary>
+ Sets the enumerator to its initial position, before the first element in the collection.
+ </summary>
+ </member>
+ <member name="P:log4net.Appender.AppenderCollection.IAppenderCollectionEnumerator.Current">
+ <summary>
+ Gets the current element in the collection.
+ </summary>
+ </member>
+ <member name="T:log4net.Appender.AppenderCollection.Tag">
+ <summary>
+ Type visible only to our subclasses
+ Used to access protected constructor
+ </summary>
+ <exclude/>
+ </member>
+ <member name="F:log4net.Appender.AppenderCollection.Tag.Default">
+ <summary>
+ A value
+ </summary>
+ </member>
+ <member name="T:log4net.Appender.AppenderCollection.Enumerator">
+ <summary>
+ Supports simple iteration over a <see cref="T:log4net.Appender.AppenderCollection"/>.
+ </summary>
+ <exclude/>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.Enumerator.#ctor(log4net.Appender.AppenderCollection)">
+ <summary>
+ Initializes a new instance of the <c>Enumerator</c> class.
+ </summary>
+ <param name="tc"></param>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.Enumerator.MoveNext">
+ <summary>
+ Advances the enumerator to the next element in the collection.
+ </summary>
+ <returns>
+ <c>true</c> if the enumerator was successfully advanced to the next element;
+ <c>false</c> if the enumerator has passed the end of the collection.
+ </returns>
+ <exception cref="T:System.InvalidOperationException">
+ The collection was modified after the enumerator was created.
+ </exception>
+ </member>
+ <member name="M:log4net.Appender.AppenderCollection.Enumerator.Reset">
+ <summary>
+ Sets the enumerator to its initial position, before the first element in the collection.
+ </summary>
+ </member>
+ <member name="P:log4net.Appender.AppenderCollection.Enumerator.Current">
+ <summary>
+ Gets the current element in the collection.
+ </summary>
+ </member>
+ <member name="T:log4net.Appender.AppenderCollection.ReadOnlyAppenderCollection">
+ <exclude/>
+ </member>
+ <member name="T:log4net.Appender.AspNetTraceAppender">
+ <summary>
+ <para>
+ Appends log events to the ASP.NET <see cref="T:System.Web.TraceContext"/> system.
+ </para>
+ </summary>
+ <remarks>
+ <para>
+ Diagnostic information and tracing messages that you specify are appended to the output
+ of the page that is sent to the requesting browser. Optionally, you can view this information
+ from a separate trace viewer (Trace.axd) that displays trace information for every page in a
+ given application.
+ </para>
+ <para>
+ Trace statements are processed and displayed only when tracing is enabled. You can control
+ whether tracing is displayed to a page, to the trace viewer, or both.
+ </para>
+ <para>
+ The logging event is passed to the <see cref="M:System.Web.TraceContext.Write(System.String)"/> or
+ <see cref="M:System.Web.TraceContext.Warn(System.String)"/> method depending on the level of the logging event.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Appender.AspNetTraceAppender.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.AspNetTraceAppender"/> class.
+ </summary>
+ <remarks>
+ <para>
+ Default constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.AspNetTraceAppender.Append(log4net.Core.LoggingEvent)">
+ <summary>
+ Write the logging event to the ASP.NET trace
+ </summary>
+ <param name="loggingEvent">the event to log</param>
+ <remarks>
+ <para>
+ Write the logging event to the ASP.NET trace
+ <c>HttpContext.Current.Trace</c>
+ (<see cref="T:System.Web.TraceContext"/>).
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.AspNetTraceAppender.RequiresLayout">
+ <summary>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </summary>
+ <value><c>true</c></value>
+ <remarks>
+ <para>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.BufferingForwardingAppender">
+ <summary>
+ Buffers events and then forwards them to attached appenders.
+ </summary>
+ <remarks>
+ <para>
+ The events are buffered in this appender until conditions are
+ met to allow the appender to deliver the events to the attached
+ appenders. See <see cref="T:log4net.Appender.BufferingAppenderSkeleton"/> for the
+ conditions that cause the buffer to be sent.
+ </para>
+ <para>The forwarding appender can be used to specify different
+ thresholds and filters for the same appender at different locations
+ within the hierarchy.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.Core.IAppenderAttachable">
+ <summary>
+ Interface for attaching appenders to objects.
+ </summary>
+ <remarks>
+ <para>
+ Interface for attaching, removing and retrieving appenders.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Core.IAppenderAttachable.AddAppender(log4net.Appender.IAppender)">
+ <summary>
+ Attaches an appender.
+ </summary>
+ <param name="appender">The appender to add.</param>
+ <remarks>
+ <para>
+ Add the specified appender. The implementation may
+ choose to allow or deny duplicate appenders.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.IAppenderAttachable.GetAppender(System.String)">
+ <summary>
+ Gets an attached appender with the specified name.
+ </summary>
+ <param name="name">The name of the appender to get.</param>
+ <returns>
+ The appender with the name specified, or <c>null</c> if no appender with the
+ specified name is found.
+ </returns>
+ <remarks>
+ <para>
+ Returns an attached appender with the <paramref name="name"/> specified.
+ If no appender with the specified name is found <c>null</c> will be
+ returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.IAppenderAttachable.RemoveAllAppenders">
+ <summary>
+ Removes all attached appenders.
+ </summary>
+ <remarks>
+ <para>
+ Removes and closes all attached appenders
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.IAppenderAttachable.RemoveAppender(log4net.Appender.IAppender)">
+ <summary>
+ Removes the specified appender from the list of attached appenders.
+ </summary>
+ <param name="appender">The appender to remove.</param>
+ <returns>The appender removed from the list</returns>
+ <remarks>
+ <para>
+ The appender removed is not closed.
+ If you are discarding the appender you must call
+ <see cref="M:log4net.Appender.IAppender.Close"/> on the appender removed.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.IAppenderAttachable.RemoveAppender(System.String)">
+ <summary>
+ Removes the appender with the specified name from the list of appenders.
+ </summary>
+ <param name="name">The name of the appender to remove.</param>
+ <returns>The appender removed from the list</returns>
+ <remarks>
+ <para>
+ The appender removed is not closed.
+ If you are discarding the appender you must call
+ <see cref="M:log4net.Appender.IAppender.Close"/> on the appender removed.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.IAppenderAttachable.Appenders">
+ <summary>
+ Gets all attached appenders.
+ </summary>
+ <value>
+ A collection of attached appenders.
+ </value>
+ <remarks>
+ <para>
+ Gets a collection of attached appenders.
+ If there are no attached appenders the
+ implementation should return an empty
+ collection rather than <c>null</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.BufferingForwardingAppender.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.BufferingForwardingAppender"/> class.
+ </summary>
+ <remarks>
+ <para>
+ Default constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.BufferingForwardingAppender.OnClose">
+ <summary>
+ Closes the appender and releases resources.
+ </summary>
+ <remarks>
+ <para>
+ Releases any resources allocated within the appender such as file handles,
+ network connections, etc.
+ </para>
+ <para>
+ It is a programming error to append to a closed appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.BufferingForwardingAppender.SendBuffer(log4net.Core.LoggingEvent[])">
+ <summary>
+ Send the events.
+ </summary>
+ <param name="events">The events that need to be send.</param>
+ <remarks>
+ <para>
+ Forwards the events to the attached appenders.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.BufferingForwardingAppender.AddAppender(log4net.Appender.IAppender)">
+ <summary>
+ Adds an <see cref="T:log4net.Appender.IAppender"/> to the list of appenders of this
+ instance.
+ </summary>
+ <param name="newAppender">The <see cref="T:log4net.Appender.IAppender"/> to add to this appender.</param>
+ <remarks>
+ <para>
+ If the specified <see cref="T:log4net.Appender.IAppender"/> is already in the list of
+ appenders, then it won't be added again.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.BufferingForwardingAppender.GetAppender(System.String)">
+ <summary>
+ Looks for the appender with the specified name.
+ </summary>
+ <param name="name">The name of the appender to lookup.</param>
+ <returns>
+ The appender with the specified name, or <c>null</c>.
+ </returns>
+ <remarks>
+ <para>
+ Get the named appender attached to this buffering appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.BufferingForwardingAppender.RemoveAllAppenders">
+ <summary>
+ Removes all previously added appenders from this appender.
+ </summary>
+ <remarks>
+ <para>
+ This is useful when re-reading configuration information.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.BufferingForwardingAppender.RemoveAppender(log4net.Appender.IAppender)">
+ <summary>
+ Removes the specified appender from the list of appenders.
+ </summary>
+ <param name="appender">The appender to remove.</param>
+ <returns>The appender removed from the list</returns>
+ <remarks>
+ The appender removed is not closed.
+ If you are discarding the appender you must call
+ <see cref="M:log4net.Appender.IAppender.Close"/> on the appender removed.
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.BufferingForwardingAppender.RemoveAppender(System.String)">
+ <summary>
+ Removes the appender with the specified name from the list of appenders.
+ </summary>
+ <param name="name">The name of the appender to remove.</param>
+ <returns>The appender removed from the list</returns>
+ <remarks>
+ The appender removed is not closed.
+ If you are discarding the appender you must call
+ <see cref="M:log4net.Appender.IAppender.Close"/> on the appender removed.
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.BufferingForwardingAppender.m_appenderAttachedImpl">
+ <summary>
+ Implementation of the <see cref="T:log4net.Core.IAppenderAttachable"/> interface
+ </summary>
+ </member>
+ <member name="P:log4net.Appender.BufferingForwardingAppender.Appenders">
+ <summary>
+ Gets the appenders contained in this appender as an
+ <see cref="T:System.Collections.ICollection"/>.
+ </summary>
+ <remarks>
+ If no appenders can be found, then an <see cref="T:log4net.Util.EmptyCollection"/>
+ is returned.
+ </remarks>
+ <returns>
+ A collection of the appenders in this appender.
+ </returns>
+ </member>
+ <member name="T:log4net.Appender.ColoredConsoleAppender">
+ <summary>
+ Appends logging events to the console.
+ </summary>
+ <remarks>
+ <para>
+ ColoredConsoleAppender appends log events to the standard output stream
+ or the error output stream using a layout specified by the
+ user. It also allows the color of a specific type of message to be set.
+ </para>
+ <para>
+ By default, all output is written to the console's standard output stream.
+ The <see cref="P:log4net.Appender.ColoredConsoleAppender.Target"/> property can be set to direct the output to the
+ error stream.
+ </para>
+ <para>
+ NOTE: This appender writes directly to the application's attached console
+ not to the <c>System.Console.Out</c> or <c>System.Console.Error</c> <c>TextWriter</c>.
+ The <c>System.Console.Out</c> and <c>System.Console.Error</c> streams can be
+ programmatically redirected (for example NUnit does this to capture program output).
+ This appender will ignore these redirections because it needs to use Win32
+ API calls to colorize the output. To respect these redirections the <see cref="T:log4net.Appender.ConsoleAppender"/>
+ must be used.
+ </para>
+ <para>
+ When configuring the colored console appender, mapping should be
+ specified to map a logging level to a color. For example:
+ </para>
+ <code lang="XML" escaped="true">
+ <mapping>
+ <level value="ERROR"/>
+ <foreColor value="White"/>
+ <backColor value="Red, HighIntensity"/>
+ </mapping>
+ <mapping>
+ <level value="DEBUG"/>
+ <backColor value="Green"/>
+ </mapping>
+ </code>
+ <para>
+ The Level is the standard log4net logging level and ForeColor and BackColor can be any
+ combination of the following values:
+ <list type="bullet">
+ <item><term>Blue</term><description></description></item>
+ <item><term>Green</term><description></description></item>
+ <item><term>Red</term><description></description></item>
+ <item><term>White</term><description></description></item>
+ <item><term>Yellow</term><description></description></item>
+ <item><term>Purple</term><description></description></item>
+ <item><term>Cyan</term><description></description></item>
+ <item><term>HighIntensity</term><description></description></item>
+ </list>
+ </para>
+ </remarks>
+ <author>Rick Hobbs</author>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="F:log4net.Appender.ColoredConsoleAppender.ConsoleOut">
+ <summary>
+ The <see cref="P:log4net.Appender.ColoredConsoleAppender.Target"/> to use when writing to the Console
+ standard output stream.
+ </summary>
+ <remarks>
+ <para>
+ The <see cref="P:log4net.Appender.ColoredConsoleAppender.Target"/> to use when writing to the Console
+ standard output stream.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.ColoredConsoleAppender.ConsoleError">
+ <summary>
+ The <see cref="P:log4net.Appender.ColoredConsoleAppender.Target"/> to use when writing to the Console
+ standard error output stream.
+ </summary>
+ <remarks>
+ <para>
+ The <see cref="P:log4net.Appender.ColoredConsoleAppender.Target"/> to use when writing to the Console
+ standard error output stream.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.ColoredConsoleAppender.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.ColoredConsoleAppender"/> class.
+ </summary>
+ <remarks>
+ The instance of the <see cref="T:log4net.Appender.ColoredConsoleAppender"/> class is set up to write
+ to the standard output stream.
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.ColoredConsoleAppender.#ctor(log4net.Layout.ILayout)">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.ColoredConsoleAppender"/> class
+ with the specified layout.
+ </summary>
+ <param name="layout">the layout to use for this appender</param>
+ <remarks>
+ The instance of the <see cref="T:log4net.Appender.ColoredConsoleAppender"/> class is set up to write
+ to the standard output stream.
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.ColoredConsoleAppender.#ctor(log4net.Layout.ILayout,System.Boolean)">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.ColoredConsoleAppender"/> class
+ with the specified layout.
+ </summary>
+ <param name="layout">the layout to use for this appender</param>
+ <param name="writeToErrorStream">flag set to <c>true</c> to write to the console error stream</param>
+ <remarks>
+ When <paramref name="writeToErrorStream"/> is set to <c>true</c>, output is written to
+ the standard error output stream. Otherwise, output is written to the standard
+ output stream.
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.ColoredConsoleAppender.AddMapping(log4net.Appender.ColoredConsoleAppender.LevelColors)">
+ <summary>
+ Add a mapping of level to color - done by the config file
+ </summary>
+ <param name="mapping">The mapping to add</param>
+ <remarks>
+ <para>
+ Add a <see cref="T:log4net.Appender.ColoredConsoleAppender.LevelColors"/> mapping to this appender.
+ Each mapping defines the foreground and background colors
+ for a level.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.ColoredConsoleAppender.Append(log4net.Core.LoggingEvent)">
+ <summary>
+ This method is called by the <see cref="M:log4net.Appender.AppenderSkeleton.DoAppend(log4net.Core.LoggingEvent)"/> method.
+ </summary>
+ <param name="loggingEvent">The event to log.</param>
+ <remarks>
+ <para>
+ Writes the event to the console.
+ </para>
+ <para>
+ The format of the output will depend on the appender's layout.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.ColoredConsoleAppender.ActivateOptions">
+ <summary>
+ Initialize the options for this appender
+ </summary>
+ <remarks>
+ <para>
+ Initialize the level to color mappings set on this appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.ColoredConsoleAppender.m_writeToErrorStream">
+ <summary>
+ Flag to write output to the error stream rather than the standard output stream
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.ColoredConsoleAppender.m_levelMapping">
+ <summary>
+ Mapping from level object to color value
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.ColoredConsoleAppender.m_consoleOutputWriter">
+ <summary>
+ The console output stream writer to write to
+ </summary>
+ <remarks>
+ <para>
+ This writer is not thread safe.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.ColoredConsoleAppender.Target">
+ <summary>
+ Target is the value of the console output stream.
+ This is either <c>"Console.Out"</c> or <c>"Console.Error"</c>.
+ </summary>
+ <value>
+ Target is the value of the console output stream.
+ This is either <c>"Console.Out"</c> or <c>"Console.Error"</c>.
+ </value>
+ <remarks>
+ <para>
+ Target is the value of the console output stream.
+ This is either <c>"Console.Out"</c> or <c>"Console.Error"</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.ColoredConsoleAppender.RequiresLayout">
+ <summary>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </summary>
+ <value><c>true</c></value>
+ <remarks>
+ <para>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.ColoredConsoleAppender.Colors">
+ <summary>
+ The enum of possible color values for use with the color mapping method
+ </summary>
+ <remarks>
+ <para>
+ The following flags can be combined together to
+ form the colors.
+ </para>
+ </remarks>
+ <seealso cref="T:log4net.Appender.ColoredConsoleAppender"/>
+ </member>
+ <member name="F:log4net.Appender.ColoredConsoleAppender.Colors.Blue">
+ <summary>
+ color is blue
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.ColoredConsoleAppender.Colors.Green">
+ <summary>
+ color is green
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.ColoredConsoleAppender.Colors.Red">
+ <summary>
+ color is red
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.ColoredConsoleAppender.Colors.White">
+ <summary>
+ color is white
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.ColoredConsoleAppender.Colors.Yellow">
+ <summary>
+ color is yellow
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.ColoredConsoleAppender.Colors.Purple">
+ <summary>
+ color is purple
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.ColoredConsoleAppender.Colors.Cyan">
+ <summary>
+ color is cyan
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.ColoredConsoleAppender.Colors.HighIntensity">
+ <summary>
+ color is intensified
+ </summary>
+ </member>
+ <member name="T:log4net.Appender.ColoredConsoleAppender.LevelColors">
+ <summary>
+ A class to act as a mapping between the level that a logging call is made at and
+ the color it should be displayed as.
+ </summary>
+ <remarks>
+ <para>
+ Defines the mapping between a level and the color it should be displayed in.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.ColoredConsoleAppender.LevelColors.ActivateOptions">
+ <summary>
+ Initialize the options for the object
+ </summary>
+ <remarks>
+ <para>
+ Combine the <see cref="P:log4net.Appender.ColoredConsoleAppender.LevelColors.ForeColor"/> and <see cref="P:log4net.Appender.ColoredConsoleAppender.LevelColors.BackColor"/> together.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.ColoredConsoleAppender.LevelColors.ForeColor">
+ <summary>
+ The mapped foreground color for the specified level
+ </summary>
+ <remarks>
+ <para>
+ Required property.
+ The mapped foreground color for the specified level.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.ColoredConsoleAppender.LevelColors.BackColor">
+ <summary>
+ The mapped background color for the specified level
+ </summary>
+ <remarks>
+ <para>
+ Required property.
+ The mapped background color for the specified level.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.ColoredConsoleAppender.LevelColors.CombinedColor">
+ <summary>
+ The combined <see cref="P:log4net.Appender.ColoredConsoleAppender.LevelColors.ForeColor"/> and <see cref="P:log4net.Appender.ColoredConsoleAppender.LevelColors.BackColor"/> suitable for
+ setting the console color.
+ </summary>
+ </member>
+ <member name="T:log4net.Appender.ConsoleAppender">
+ <summary>
+ Appends logging events to the console.
+ </summary>
+ <remarks>
+ <para>
+ ConsoleAppender appends log events to the standard output stream
+ or the error output stream using a layout specified by the
+ user.
+ </para>
+ <para>
+ By default, all output is written to the console's standard output stream.
+ The <see cref="P:log4net.Appender.ConsoleAppender.Target"/> property can be set to direct the output to the
+ error stream.
+ </para>
+ <para>
+ NOTE: This appender writes each message to the <c>System.Console.Out</c> or
+ <c>System.Console.Error</c> that is set at the time the event is appended.
+ Therefore it is possible to programmatically redirect the output of this appender
+ (for example NUnit does this to capture program output). While this is the desired
+ behavior of this appender it may have security implications in your application.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="F:log4net.Appender.ConsoleAppender.ConsoleOut">
+ <summary>
+ The <see cref="P:log4net.Appender.ConsoleAppender.Target"/> to use when writing to the Console
+ standard output stream.
+ </summary>
+ <remarks>
+ <para>
+ The <see cref="P:log4net.Appender.ConsoleAppender.Target"/> to use when writing to the Console
+ standard output stream.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.ConsoleAppender.ConsoleError">
+ <summary>
+ The <see cref="P:log4net.Appender.ConsoleAppender.Target"/> to use when writing to the Console
+ standard error output stream.
+ </summary>
+ <remarks>
+ <para>
+ The <see cref="P:log4net.Appender.ConsoleAppender.Target"/> to use when writing to the Console
+ standard error output stream.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.ConsoleAppender.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.ConsoleAppender"/> class.
+ </summary>
+ <remarks>
+ The instance of the <see cref="T:log4net.Appender.ConsoleAppender"/> class is set up to write
+ to the standard output stream.
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.ConsoleAppender.#ctor(log4net.Layout.ILayout)">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.ConsoleAppender"/> class
+ with the specified layout.
+ </summary>
+ <param name="layout">the layout to use for this appender</param>
+ <remarks>
+ The instance of the <see cref="T:log4net.Appender.ConsoleAppender"/> class is set up to write
+ to the standard output stream.
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.ConsoleAppender.#ctor(log4net.Layout.ILayout,System.Boolean)">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.ConsoleAppender"/> class
+ with the specified layout.
+ </summary>
+ <param name="layout">the layout to use for this appender</param>
+ <param name="writeToErrorStream">flag set to <c>true</c> to write to the console error stream</param>
+ <remarks>
+ When <paramref name="writeToErrorStream"/> is set to <c>true</c>, output is written to
+ the standard error output stream. Otherwise, output is written to the standard
+ output stream.
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.ConsoleAppender.Append(log4net.Core.LoggingEvent)">
+ <summary>
+ This method is called by the <see cref="M:log4net.Appender.AppenderSkeleton.DoAppend(log4net.Core.LoggingEvent)"/> method.
+ </summary>
+ <param name="loggingEvent">The event to log.</param>
+ <remarks>
+ <para>
+ Writes the event to the console.
+ </para>
+ <para>
+ The format of the output will depend on the appender's layout.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.ConsoleAppender.Target">
+ <summary>
+ Target is the value of the console output stream.
+ This is either <c>"Console.Out"</c> or <c>"Console.Error"</c>.
+ </summary>
+ <value>
+ Target is the value of the console output stream.
+ This is either <c>"Console.Out"</c> or <c>"Console.Error"</c>.
+ </value>
+ <remarks>
+ <para>
+ Target is the value of the console output stream.
+ This is either <c>"Console.Out"</c> or <c>"Console.Error"</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.ConsoleAppender.RequiresLayout">
+ <summary>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </summary>
+ <value><c>true</c></value>
+ <remarks>
+ <para>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.DebugAppender">
+ <summary>
+ Appends log events to the <see cref="T:System.Diagnostics.Debug"/> system.
+ </summary>
+ <remarks>
+ <para>
+ The application configuration file can be used to control what listeners
+ are actually used. See the MSDN documentation for the
+ <see cref="T:System.Diagnostics.Debug"/> class for details on configuring the
+ debug system.
+ </para>
+ <para>
+ Events are written using the <see cref="M:System.Diagnostics.Debug.Write(System.String,System.String)"/>
+ method. The event's logger name is passed as the value for the category name to the Write method.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Appender.DebugAppender.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.DebugAppender"/>.
+ </summary>
+ <remarks>
+ <para>
+ Default constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.DebugAppender.#ctor(log4net.Layout.ILayout)">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.DebugAppender"/>
+ with a specified layout.
+ </summary>
+ <param name="layout">The layout to use with this appender.</param>
+ <remarks>
+ <para>
+ Obsolete constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.DebugAppender.Append(log4net.Core.LoggingEvent)">
+ <summary>
+ Writes the logging event to the <see cref="T:System.Diagnostics.Debug"/> system.
+ </summary>
+ <param name="loggingEvent">The event to log.</param>
+ <remarks>
+ <para>
+ Writes the logging event to the <see cref="T:System.Diagnostics.Debug"/> system.
+ If <see cref="P:log4net.Appender.DebugAppender.ImmediateFlush"/> is <c>true</c> then the <see cref="M:System.Diagnostics.Debug.Flush"/>
+ is called.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.DebugAppender.m_immediateFlush">
+ <summary>
+ Immediate flush means that the underlying writer or output stream
+ will be flushed at the end of each append operation.
+ </summary>
+ <remarks>
+ <para>
+ Immediate flush is slower but ensures that each append request is
+ actually written. If <see cref="P:log4net.Appender.DebugAppender.ImmediateFlush"/> is set to
+ <c>false</c>, then there is a good chance that the last few
+ logs events are not actually written to persistent media if and
+ when the application crashes.
+ </para>
+ <para>
+ The default value is <c>true</c>.</para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.DebugAppender.ImmediateFlush">
+ <summary>
+ Gets or sets a value that indicates whether the appender will
+ flush at the end of each write.
+ </summary>
+ <remarks>
+ <para>The default behavior is to flush at the end of each
+ write. If the option is set to<c>false</c>, then the underlying
+ stream can defer writing to physical medium to a later time.
+ </para>
+ <para>
+ Avoiding the flush operation at the end of each append results
+ in a performance gain of 10 to 20 percent. However, there is safety
+ trade-off involved in skipping flushing. Indeed, when flushing is
+ skipped, then it is likely that the last few log events will not
+ be recorded on disk when the application exits. This is a high
+ price to pay even for a 20% performance gain.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.DebugAppender.RequiresLayout">
+ <summary>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </summary>
+ <value><c>true</c></value>
+ <remarks>
+ <para>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.EventLogAppender">
+ <summary>
+ Writes events to the system event log.
+ </summary>
+ <remarks>
+ <para>
+ The <c>EventID</c> of the event log entry can be
+ set using the <c>EventLogEventID</c> property (<see cref="P:log4net.Core.LoggingEvent.Properties"/>)
+ on the <see cref="T:log4net.Core.LoggingEvent"/>.
+ </para>
+ <para>
+ There is a limit of 32K characters for an event log message
+ </para>
+ <para>
+ When configuring the EventLogAppender a mapping can be
+ specified to map a logging level to an event log entry type. For example:
+ </para>
+ <code lang="XML">
+ &lt;mapping&gt;
+ &lt;level value="ERROR" /&gt;
+ &lt;eventLogEntryType value="Error" /&gt;
+ &lt;/mapping&gt;
+ &lt;mapping&gt;
+ &lt;level value="DEBUG" /&gt;
+ &lt;eventLogEntryType value="Information" /&gt;
+ &lt;/mapping&gt;
+ </code>
+ <para>
+ The Level is the standard log4net logging level and eventLogEntryType can be any value
+ from the <see cref="T:System.Diagnostics.EventLogEntryType"/> enum, i.e.:
+ <list type="bullet">
+ <item><term>Error</term><description>an error event</description></item>
+ <item><term>Warning</term><description>a warning event</description></item>
+ <item><term>Information</term><description>an informational event</description></item>
+ </list>
+ </para>
+ </remarks>
+ <author>Aspi Havewala</author>
+ <author>Douglas de la Torre</author>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ <author>Thomas Voss</author>
+ </member>
+ <member name="M:log4net.Appender.EventLogAppender.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.EventLogAppender"/> class.
+ </summary>
+ <remarks>
+ <para>
+ Default constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.EventLogAppender.#ctor(log4net.Layout.ILayout)">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.EventLogAppender"/> class
+ with the specified <see cref="T:log4net.Layout.ILayout"/>.
+ </summary>
+ <param name="layout">The <see cref="T:log4net.Layout.ILayout"/> to use with this appender.</param>
+ <remarks>
+ <para>
+ Obsolete constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.EventLogAppender.AddMapping(log4net.Appender.EventLogAppender.Level2EventLogEntryType)">
+ <summary>
+ Add a mapping of level to <see cref="T:System.Diagnostics.EventLogEntryType"/> - done by the config file
+ </summary>
+ <param name="mapping">The mapping to add</param>
+ <remarks>
+ <para>
+ Add a <see cref="T:log4net.Appender.EventLogAppender.Level2EventLogEntryType"/> mapping to this appender.
+ Each mapping defines the event log entry type for a level.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.EventLogAppender.ActivateOptions">
+ <summary>
+ Initialize the appender based on the options set
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Appender.EventLogAppender.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Appender.EventLogAppender.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Appender.EventLogAppender.ActivateOptions"/> must be called again.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.EventLogAppender.CreateEventSource(System.String,System.String,System.String)">
+ <summary>
+ Create an event log source
+ </summary>
+ <remarks>
+ Uses different API calls under NET_2_0
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.EventLogAppender.Append(log4net.Core.LoggingEvent)">
+ <summary>
+ This method is called by the <see cref="M:log4net.Appender.AppenderSkeleton.DoAppend(log4net.Core.LoggingEvent)"/>
+ method.
+ </summary>
+ <param name="loggingEvent">the event to log</param>
+ <remarks>
+ <para>Writes the event to the system event log using the
+ <see cref="P:log4net.Appender.EventLogAppender.ApplicationName"/>.</para>
+
+ <para>If the event has an <c>EventID</c> property (see <see cref="P:log4net.Core.LoggingEvent.Properties"/>)
+ set then this integer will be used as the event log event id.</para>
+
+ <para>
+ There is a limit of 32K characters for an event log message
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.EventLogAppender.GetEntryType(log4net.Core.Level)">
+ <summary>
+ Get the equivalent <see cref="T:System.Diagnostics.EventLogEntryType"/> for a <see cref="T:log4net.Core.Level"/> <paramref name="p"/>
+ </summary>
+ <param name="level">the Level to convert to an EventLogEntryType</param>
+ <returns>The equivalent <see cref="T:System.Diagnostics.EventLogEntryType"/> for a <see cref="T:log4net.Core.Level"/> <paramref name="p"/></returns>
+ <remarks>
+ Because there are fewer applicable <see cref="T:System.Diagnostics.EventLogEntryType"/>
+ values to use in logging levels than there are in the
+ <see cref="T:log4net.Core.Level"/> this is a one way mapping. There is
+ a loss of information during the conversion.
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.EventLogAppender.m_logName">
+ <summary>
+ The log name is the section in the event logs where the messages
+ are stored.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.EventLogAppender.m_applicationName">
+ <summary>
+ Name of the application to use when logging. This appears in the
+ application column of the event log named by <see cref="F:log4net.Appender.EventLogAppender.m_logName"/>.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.EventLogAppender.m_machineName">
+ <summary>
+ The name of the machine which holds the event log. This is
+ currently only allowed to be '.' i.e. the current machine.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.EventLogAppender.m_levelMapping">
+ <summary>
+ Mapping from level object to EventLogEntryType
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.EventLogAppender.m_securityContext">
+ <summary>
+ The security context to use for privileged calls
+ </summary>
+ </member>
+ <member name="P:log4net.Appender.EventLogAppender.LogName">
+ <summary>
+ The name of the log where messages will be stored.
+ </summary>
+ <value>
+ The string name of the log where messages will be stored.
+ </value>
+ <remarks>
+ <para>This is the name of the log as it appears in the Event Viewer
+ tree. The default value is to log into the <c>Application</c>
+ log, this is where most applications write their events. However
+ if you need a separate log for your application (or applications)
+ then you should set the <see cref="P:log4net.Appender.EventLogAppender.LogName"/> appropriately.</para>
+ <para>This should not be used to distinguish your event log messages
+ from those of other applications, the <see cref="P:log4net.Appender.EventLogAppender.ApplicationName"/>
+ property should be used to distinguish events. This property should be
+ used to group together events into a single log.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.EventLogAppender.ApplicationName">
+ <summary>
+ Property used to set the Application name. This appears in the
+ event logs when logging.
+ </summary>
+ <value>
+ The string used to distinguish events from different sources.
+ </value>
+ <remarks>
+ Sets the event log source property.
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.EventLogAppender.MachineName">
+ <summary>
+ This property is used to return the name of the computer to use
+ when accessing the event logs. Currently, this is the current
+ computer, denoted by a dot "."
+ </summary>
+ <value>
+ The string name of the machine holding the event log that
+ will be logged into.
+ </value>
+ <remarks>
+ This property cannot be changed. It is currently set to '.'
+ i.e. the local machine. This may be changed in future.
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.EventLogAppender.SecurityContext">
+ <summary>
+ Gets or sets the <see cref="P:log4net.Appender.EventLogAppender.SecurityContext"/> used to write to the EventLog.
+ </summary>
+ <value>
+ The <see cref="P:log4net.Appender.EventLogAppender.SecurityContext"/> used to write to the EventLog.
+ </value>
+ <remarks>
+ <para>
+ The system security context used to write to the EventLog.
+ </para>
+ <para>
+ Unless a <see cref="P:log4net.Appender.EventLogAppender.SecurityContext"/> specified here for this appender
+ the <see cref="P:log4net.Core.SecurityContextProvider.DefaultProvider"/> is queried for the
+ security context to use. The default behavior is to use the security context
+ of the current thread.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.EventLogAppender.RequiresLayout">
+ <summary>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </summary>
+ <value><c>true</c></value>
+ <remarks>
+ <para>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.EventLogAppender.Level2EventLogEntryType">
+ <summary>
+ A class to act as a mapping between the level that a logging call is made at and
+ the color it should be displayed as.
+ </summary>
+ <remarks>
+ <para>
+ Defines the mapping between a level and its event log entry type.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.EventLogAppender.Level2EventLogEntryType.EventLogEntryType">
+ <summary>
+ The <see cref="P:log4net.Appender.EventLogAppender.Level2EventLogEntryType.EventLogEntryType"/> for this entry
+ </summary>
+ <remarks>
+ <para>
+ Required property.
+ The <see cref="P:log4net.Appender.EventLogAppender.Level2EventLogEntryType.EventLogEntryType"/> for this entry
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.FileAppender">
+ <summary>
+ Appends logging events to a file.
+ </summary>
+ <remarks>
+ <para>
+ Logging events are sent to the file specified by
+ the <see cref="P:log4net.Appender.FileAppender.File"/> property.
+ </para>
+ <para>
+ The file can be opened in either append or overwrite mode
+ by specifying the <see cref="P:log4net.Appender.FileAppender.AppendToFile"/> property.
+ If the file path is relative it is taken as relative from
+ the application base directory. The file encoding can be
+ specified by setting the <see cref="P:log4net.Appender.FileAppender.Encoding"/> property.
+ </para>
+ <para>
+ The layout's <see cref="P:log4net.Layout.ILayout.Header"/> and <see cref="P:log4net.Layout.ILayout.Footer"/>
+ values will be written each time the file is opened and closed
+ respectively. If the <see cref="P:log4net.Appender.FileAppender.AppendToFile"/> property is <see langword="true"/>
+ then the file may contain multiple copies of the header and footer.
+ </para>
+ <para>
+ This appender will first try to open the file for writing when <see cref="M:log4net.Appender.FileAppender.ActivateOptions"/>
+ is called. This will typically be during configuration.
+ If the file cannot be opened for writing the appender will attempt
+ to open the file again each time a message is logged to the appender.
+ If the file cannot be opened for writing when a message is logged then
+ the message will be discarded by this appender.
+ </para>
+ <para>
+ The <see cref="T:log4net.Appender.FileAppender"/> supports pluggable file locking models via
+ the <see cref="P:log4net.Appender.FileAppender.LockingModel"/> property.
+ The default behavior, implemented by <see cref="T:log4net.Appender.FileAppender.ExclusiveLock"/>
+ is to obtain an exclusive write lock on the file until this appender is closed.
+ The alternative model, <see cref="T:log4net.Appender.FileAppender.MinimalLock"/>, only holds a
+ write lock while the appender is writing a logging event.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ <author>Rodrigo B. de Oliveira</author>
+ <author>Douglas de la Torre</author>
+ <author>Niall Daley</author>
+ </member>
+ <member name="T:log4net.Appender.TextWriterAppender">
+ <summary>
+ Sends logging events to a <see cref="T:System.IO.TextWriter"/>.
+ </summary>
+ <remarks>
+ <para>
+ An Appender that writes to a <see cref="T:System.IO.TextWriter"/>.
+ </para>
+ <para>
+ This appender may be used stand alone if initialized with an appropriate
+ writer, however it is typically used as a base class for an appender that
+ can open a <see cref="T:System.IO.TextWriter"/> to write to.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ <author>Douglas de la Torre</author>
+ </member>
+ <member name="M:log4net.Appender.TextWriterAppender.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.TextWriterAppender"/> class.
+ </summary>
+ <remarks>
+ <para>
+ Default constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TextWriterAppender.#ctor(log4net.Layout.ILayout,System.IO.Stream)">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.TextWriterAppender"/> class and
+ sets the output destination to a new <see cref="T:System.IO.StreamWriter"/> initialized
+ with the specified <see cref="T:System.IO.Stream"/>.
+ </summary>
+ <param name="layout">The layout to use with this appender.</param>
+ <param name="os">The <see cref="T:System.IO.Stream"/> to output to.</param>
+ <remarks>
+ <para>
+ Obsolete constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TextWriterAppender.#ctor(log4net.Layout.ILayout,System.IO.TextWriter)">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.TextWriterAppender"/> class and sets
+ the output destination to the specified <see cref="T:System.IO.StreamWriter"/>.
+ </summary>
+ <param name="layout">The layout to use with this appender</param>
+ <param name="writer">The <see cref="T:System.IO.TextWriter"/> to output to</param>
+ <remarks>
+ The <see cref="T:System.IO.TextWriter"/> must have been previously opened.
+ </remarks>
+ <remarks>
+ <para>
+ Obsolete constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TextWriterAppender.PreAppendCheck">
+ <summary>
+ This method determines if there is a sense in attempting to append.
+ </summary>
+ <remarks>
+ <para>
+ This method checked if an output target has been set and if a
+ layout has been set.
+ </para>
+ </remarks>
+ <returns><c>false</c> if any of the preconditions fail.</returns>
+ </member>
+ <member name="M:log4net.Appender.TextWriterAppender.Append(log4net.Core.LoggingEvent)">
+ <summary>
+ This method is called by the <see cref="M:log4net.Appender.AppenderSkeleton.DoAppend(log4net.Core.LoggingEvent)"/>
+ method.
+ </summary>
+ <param name="loggingEvent">The event to log.</param>
+ <remarks>
+ <para>
+ Writes a log statement to the output stream if the output stream exists
+ and is writable.
+ </para>
+ <para>
+ The format of the output will depend on the appender's layout.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TextWriterAppender.Append(log4net.Core.LoggingEvent[])">
+ <summary>
+ This method is called by the <see cref="M:log4net.Appender.AppenderSkeleton.DoAppend(log4net.Core.LoggingEvent[])"/>
+ method.
+ </summary>
+ <param name="loggingEvents">The array of events to log.</param>
+ <remarks>
+ <para>
+ This method writes all the bulk logged events to the output writer
+ before flushing the stream.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TextWriterAppender.OnClose">
+ <summary>
+ Close this appender instance. The underlying stream or writer is also closed.
+ </summary>
+ <remarks>
+ Closed appenders cannot be reused.
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TextWriterAppender.WriteFooterAndCloseWriter">
+ <summary>
+ Writes the footer and closes the underlying <see cref="T:System.IO.TextWriter"/>.
+ </summary>
+ <remarks>
+ <para>
+ Writes the footer and closes the underlying <see cref="T:System.IO.TextWriter"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TextWriterAppender.CloseWriter">
+ <summary>
+ Closes the underlying <see cref="T:System.IO.TextWriter"/>.
+ </summary>
+ <remarks>
+ <para>
+ Closes the underlying <see cref="T:System.IO.TextWriter"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TextWriterAppender.Reset">
+ <summary>
+ Clears internal references to the underlying <see cref="T:System.IO.TextWriter"/>
+ and other variables.
+ </summary>
+ <remarks>
+ <para>
+ Subclasses can override this method for an alternate closing behavior.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TextWriterAppender.WriteFooter">
+ <summary>
+ Writes a footer as produced by the embedded layout's <see cref="P:log4net.Layout.ILayout.Footer"/> property.
+ </summary>
+ <remarks>
+ <para>
+ Writes a footer as produced by the embedded layout's <see cref="P:log4net.Layout.ILayout.Footer"/> property.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TextWriterAppender.WriteHeader">
+ <summary>
+ Writes a header produced by the embedded layout's <see cref="P:log4net.Layout.ILayout.Header"/> property.
+ </summary>
+ <remarks>
+ <para>
+ Writes a header produced by the embedded layout's <see cref="P:log4net.Layout.ILayout.Header"/> property.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TextWriterAppender.PrepareWriter">
+ <summary>
+ Called to allow a subclass to lazily initialize the writer
+ </summary>
+ <remarks>
+ <para>
+ This method is called when an event is logged and the <see cref="P:log4net.Appender.TextWriterAppender.Writer"/> or
+ <see cref="P:log4net.Appender.TextWriterAppender.QuietWriter"/> have not been set. This allows a subclass to
+ attempt to initialize the writer multiple times.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.TextWriterAppender.m_qtw">
+ <summary>
+ This is the <see cref="T:log4net.Util.QuietTextWriter"/> where logging events
+ will be written to.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.TextWriterAppender.m_immediateFlush">
+ <summary>
+ Immediate flush means that the underlying <see cref="T:System.IO.TextWriter"/>
+ or output stream will be flushed at the end of each append operation.
+ </summary>
+ <remarks>
+ <para>
+ Immediate flush is slower but ensures that each append request is
+ actually written. If <see cref="P:log4net.Appender.TextWriterAppender.ImmediateFlush"/> is set to
+ <c>false</c>, then there is a good chance that the last few
+ logging events are not actually persisted if and when the application
+ crashes.
+ </para>
+ <para>
+ The default value is <c>true</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.TextWriterAppender.ImmediateFlush">
+ <summary>
+ Gets or set whether the appender will flush at the end
+ of each append operation.
+ </summary>
+ <value>
+ <para>
+ The default behavior is to flush at the end of each
+ append operation.
+ </para>
+ <para>
+ If this option is set to <c>false</c>, then the underlying
+ stream can defer persisting the logging event to a later
+ time.
+ </para>
+ </value>
+ <remarks>
+ Avoiding the flush operation at the end of each append results in
+ a performance gain of 10 to 20 percent. However, there is safety
+ trade-off involved in skipping flushing. Indeed, when flushing is
+ skipped, then it is likely that the last few log events will not
+ be recorded on disk when the application exits. This is a high
+ price to pay even for a 20% performance gain.
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.TextWriterAppender.Writer">
+ <summary>
+ Sets the <see cref="T:System.IO.TextWriter"/> where the log output will go.
+ </summary>
+ <remarks>
+ <para>
+ The specified <see cref="T:System.IO.TextWriter"/> must be open and writable.
+ </para>
+ <para>
+ The <see cref="T:System.IO.TextWriter"/> will be closed when the appender
+ instance is closed.
+ </para>
+ <para>
+ <b>Note:</b> Logging to an unopened <see cref="T:System.IO.TextWriter"/> will fail.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.TextWriterAppender.ErrorHandler">
+ <summary>
+ Gets or set the <see cref="T:log4net.Core.IErrorHandler"/> and the underlying
+ <see cref="T:log4net.Util.QuietTextWriter"/>, if any, for this appender.
+ </summary>
+ <value>
+ The <see cref="T:log4net.Core.IErrorHandler"/> for this appender.
+ </value>
+ </member>
+ <member name="P:log4net.Appender.TextWriterAppender.RequiresLayout">
+ <summary>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </summary>
+ <value><c>true</c></value>
+ <remarks>
+ <para>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.TextWriterAppender.QuietWriter">
+ <summary>
+ Gets or sets the <see cref="T:log4net.Util.QuietTextWriter"/> where logging events
+ will be written to.
+ </summary>
+ <value>
+ The <see cref="T:log4net.Util.QuietTextWriter"/> where logging events are written.
+ </value>
+ <remarks>
+ <para>
+ This is the <see cref="T:log4net.Util.QuietTextWriter"/> where logging events
+ will be written to.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ <remarks>
+ <para>
+ Default constructor
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.#ctor(log4net.Layout.ILayout,System.String,System.Boolean)">
+ <summary>
+ Construct a new appender using the layout, file and append mode.
+ </summary>
+ <param name="layout">the layout to use with this appender</param>
+ <param name="filename">the full path to the file to write to</param>
+ <param name="append">flag to indicate if the file should be appended to</param>
+ <remarks>
+ <para>
+ Obsolete constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.#ctor(log4net.Layout.ILayout,System.String)">
+ <summary>
+ Construct a new appender using the layout and file specified.
+ The file will be appended to.
+ </summary>
+ <param name="layout">the layout to use with this appender</param>
+ <param name="filename">the full path to the file to write to</param>
+ <remarks>
+ <para>
+ Obsolete constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.ActivateOptions">
+ <summary>
+ Activate the options on the file appender.
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Appender.FileAppender.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Appender.FileAppender.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Appender.FileAppender.ActivateOptions"/> must be called again.
+ </para>
+ <para>
+ This will cause the file to be opened.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.Reset">
+ <summary>
+ Closes any previously opened file and calls the parent's <see cref="M:log4net.Appender.TextWriterAppender.Reset"/>.
+ </summary>
+ <remarks>
+ <para>
+ Resets the filename and the file stream.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.PrepareWriter">
+ <summary>
+ Called to initialize the file writer
+ </summary>
+ <remarks>
+ <para>
+ Will be called for each logged message until the file is
+ successfully opened.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.Append(log4net.Core.LoggingEvent)">
+ <summary>
+ This method is called by the <see cref="M:log4net.Appender.AppenderSkeleton.DoAppend(log4net.Core.LoggingEvent)"/>
+ method.
+ </summary>
+ <param name="loggingEvent">The event to log.</param>
+ <remarks>
+ <para>
+ Writes a log statement to the output stream if the output stream exists
+ and is writable.
+ </para>
+ <para>
+ The format of the output will depend on the appender's layout.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.Append(log4net.Core.LoggingEvent[])">
+ <summary>
+ This method is called by the <see cref="M:log4net.Appender.AppenderSkeleton.DoAppend(log4net.Core.LoggingEvent[])"/>
+ method.
+ </summary>
+ <param name="loggingEvents">The array of events to log.</param>
+ <remarks>
+ <para>
+ Acquires the output file locks once before writing all the events to
+ the stream.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.WriteFooter">
+ <summary>
+ Writes a footer as produced by the embedded layout's <see cref="P:log4net.Layout.ILayout.Footer"/> property.
+ </summary>
+ <remarks>
+ <para>
+ Writes a footer as produced by the embedded layout's <see cref="P:log4net.Layout.ILayout.Footer"/> property.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.WriteHeader">
+ <summary>
+ Writes a header produced by the embedded layout's <see cref="P:log4net.Layout.ILayout.Header"/> property.
+ </summary>
+ <remarks>
+ <para>
+ Writes a header produced by the embedded layout's <see cref="P:log4net.Layout.ILayout.Header"/> property.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.CloseWriter">
+ <summary>
+ Closes the underlying <see cref="T:System.IO.TextWriter"/>.
+ </summary>
+ <remarks>
+ <para>
+ Closes the underlying <see cref="T:System.IO.TextWriter"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.CloseFile">
+ <summary>
+ Closes the previously opened file.
+ </summary>
+ <remarks>
+ <para>
+ Writes the <see cref="P:log4net.Layout.ILayout.Footer"/> to the file and then
+ closes the file.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.SafeOpenFile(System.String,System.Boolean)">
+ <summary>
+ Sets and <i>opens</i> the file where the log output will go. The specified file must be writable.
+ </summary>
+ <param name="fileName">The path to the log file. Must be a fully qualified path.</param>
+ <param name="append">If true will append to fileName. Otherwise will truncate fileName</param>
+ <remarks>
+ <para>
+ Calls <see cref="M:log4net.Appender.FileAppender.OpenFile(System.String,System.Boolean)"/> but guarantees not to throw an exception.
+ Errors are passed to the <see cref="P:log4net.Appender.TextWriterAppender.ErrorHandler"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.OpenFile(System.String,System.Boolean)">
+ <summary>
+ Sets and <i>opens</i> the file where the log output will go. The specified file must be writable.
+ </summary>
+ <param name="fileName">The path to the log file. Must be a fully qualified path.</param>
+ <param name="append">If true will append to fileName. Otherwise will truncate fileName</param>
+ <remarks>
+ <para>
+ If there was already an opened file, then the previous file
+ is closed first.
+ </para>
+ <para>
+ This method will ensure that the directory structure
+ for the <paramref name="fileName"/> specified exists.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.SetQWForFiles(System.IO.Stream)">
+ <summary>
+ Sets the quiet writer used for file output
+ </summary>
+ <param name="fileStream">the file stream that has been opened for writing</param>
+ <remarks>
+ <para>
+ This implementation of <see cref="M:log4net.Appender.FileAppender.SetQWForFiles(System.IO.Stream)"/> creates a <see cref="T:System.IO.StreamWriter"/>
+ over the <paramref name="fileStream"/> and passes it to the
+ <see cref="M:log4net.Appender.FileAppender.SetQWForFiles(System.IO.TextWriter)"/> method.
+ </para>
+ <para>
+ This method can be overridden by sub classes that want to wrap the
+ <see cref="T:System.IO.Stream"/> in some way, for example to encrypt the output
+ data using a <c>System.Security.Cryptography.CryptoStream</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.SetQWForFiles(System.IO.TextWriter)">
+ <summary>
+ Sets the quiet writer being used.
+ </summary>
+ <param name="writer">the writer over the file stream that has been opened for writing</param>
+ <remarks>
+ <para>
+ This method can be overridden by sub classes that want to
+ wrap the <see cref="T:System.IO.TextWriter"/> in some way.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.ConvertToFullPath(System.String)">
+ <summary>
+ Convert a path into a fully qualified path.
+ </summary>
+ <param name="path">The path to convert.</param>
+ <returns>The fully qualified path.</returns>
+ <remarks>
+ <para>
+ Converts the path specified to a fully
+ qualified path. If the path is relative it is
+ taken as relative from the application base
+ directory.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.FileAppender.m_appendToFile">
+ <summary>
+ Flag to indicate if we should append to the file
+ or overwrite the file. The default is to append.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.FileAppender.m_fileName">
+ <summary>
+ The name of the log file.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.FileAppender.m_encoding">
+ <summary>
+ The encoding to use for the file stream.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.FileAppender.m_securityContext">
+ <summary>
+ The security context to use for privileged calls
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.FileAppender.m_stream">
+ <summary>
+ The stream to log to. Has added locking semantics
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.FileAppender.m_lockingModel">
+ <summary>
+ The locking model to use
+ </summary>
+ </member>
+ <member name="P:log4net.Appender.FileAppender.File">
+ <summary>
+ Gets or sets the path to the file that logging will be written to.
+ </summary>
+ <value>
+ The path to the file that logging will be written to.
+ </value>
+ <remarks>
+ <para>
+ If the path is relative it is taken as relative from
+ the application base directory.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.FileAppender.AppendToFile">
+ <summary>
+ Gets or sets a flag that indicates whether the file should be
+ appended to or overwritten.
+ </summary>
+ <value>
+ Indicates whether the file should be appended to or overwritten.
+ </value>
+ <remarks>
+ <para>
+ If the value is set to false then the file will be overwritten, if
+ it is set to true then the file will be appended to.
+ </para>
+ The default value is true.
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.FileAppender.Encoding">
+ <summary>
+ Gets or sets <see cref="P:log4net.Appender.FileAppender.Encoding"/> used to write to the file.
+ </summary>
+ <value>
+ The <see cref="P:log4net.Appender.FileAppender.Encoding"/> used to write to the file.
+ </value>
+ <remarks>
+ <para>
+ The default encoding set is <see cref="P:System.Text.Encoding.Default"/>
+ which is the encoding for the system's current ANSI code page.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.FileAppender.SecurityContext">
+ <summary>
+ Gets or sets the <see cref="P:log4net.Appender.FileAppender.SecurityContext"/> used to write to the file.
+ </summary>
+ <value>
+ The <see cref="P:log4net.Appender.FileAppender.SecurityContext"/> used to write to the file.
+ </value>
+ <remarks>
+ <para>
+ Unless a <see cref="P:log4net.Appender.FileAppender.SecurityContext"/> specified here for this appender
+ the <see cref="P:log4net.Core.SecurityContextProvider.DefaultProvider"/> is queried for the
+ security context to use. The default behavior is to use the security context
+ of the current thread.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.FileAppender.LockingModel">
+ <summary>
+ Gets or sets the <see cref="P:log4net.Appender.FileAppender.LockingModel"/> used to handle locking of the file.
+ </summary>
+ <value>
+ The <see cref="P:log4net.Appender.FileAppender.LockingModel"/> used to lock the file.
+ </value>
+ <remarks>
+ <para>
+ Gets or sets the <see cref="P:log4net.Appender.FileAppender.LockingModel"/> used to handle locking of the file.
+ </para>
+ <para>
+ There are two built in locking models, <see cref="T:log4net.Appender.FileAppender.ExclusiveLock"/> and <see cref="T:log4net.Appender.FileAppender.MinimalLock"/>.
+ The former locks the file from the start of logging to the end and the
+ later lock only for the minimal amount of time when logging each message.
+ </para>
+ <para>
+ The default locking model is the <see cref="T:log4net.Appender.FileAppender.ExclusiveLock"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.FileAppender.LockingStream">
+ <summary>
+ Write only <see cref="T:System.IO.Stream"/> that uses the <see cref="T:log4net.Appender.FileAppender.LockingModelBase"/>
+ to manage access to an underlying resource.
+ </summary>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.LockingStream.BeginWrite(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object)">
+ <summary>
+ True asynchronous writes are not supported, the implementation forces a synchronous write.
+ </summary>
+ </member>
+ <member name="T:log4net.Core.LogException">
+ <summary>
+ Exception base type for log4net.
+ </summary>
+ <remarks>
+ <para>
+ This type extends <see cref="T:System.ApplicationException"/>. It
+ does not add any new functionality but does differentiate the
+ type of exception being thrown.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Core.LogException.#ctor">
+ <summary>
+ Constructor
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Core.LogException"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogException.#ctor(System.String)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="message">A message to include with the exception.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Core.LogException"/> class with
+ the specified message.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogException.#ctor(System.String,System.Exception)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="message">A message to include with the exception.</param>
+ <param name="innerException">A nested exception to include.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Core.LogException"/> class
+ with the specified message and inner exception.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)">
+ <summary>
+ Serialization constructor
+ </summary>
+ <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
+ <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext"/> that contains contextual information about the source or destination.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Core.LogException"/> class
+ with serialized data.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.FileAppender.LockingModelBase">
+ <summary>
+ Locking model base class
+ </summary>
+ <remarks>
+ <para>
+ Base class for the locking models available to the <see cref="T:log4net.Appender.FileAppender"/> derived loggers.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.LockingModelBase.OpenFile(System.String,System.Boolean,System.Text.Encoding)">
+ <summary>
+ Open the output file
+ </summary>
+ <param name="filename">The filename to use</param>
+ <param name="append">Whether to append to the file, or overwrite</param>
+ <param name="encoding">The encoding to use</param>
+ <remarks>
+ <para>
+ Open the file specified and prepare for logging.
+ No writes will be made until <see cref="M:log4net.Appender.FileAppender.LockingModelBase.AcquireLock"/> is called.
+ Must be called before any calls to <see cref="M:log4net.Appender.FileAppender.LockingModelBase.AcquireLock"/>,
+ <see cref="M:log4net.Appender.FileAppender.LockingModelBase.ReleaseLock"/> and <see cref="M:log4net.Appender.FileAppender.LockingModelBase.CloseFile"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.LockingModelBase.CloseFile">
+ <summary>
+ Close the file
+ </summary>
+ <remarks>
+ <para>
+ Close the file. No further writes will be made.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.LockingModelBase.AcquireLock">
+ <summary>
+ Acquire the lock on the file
+ </summary>
+ <returns>A stream that is ready to be written to.</returns>
+ <remarks>
+ <para>
+ Acquire the lock on the file in preparation for writing to it.
+ Return a stream pointing to the file. <see cref="M:log4net.Appender.FileAppender.LockingModelBase.ReleaseLock"/>
+ must be called to release the lock on the output file.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.LockingModelBase.ReleaseLock">
+ <summary>
+ Release the lock on the file
+ </summary>
+ <remarks>
+ <para>
+ Release the lock on the file. No further writes will be made to the
+ stream until <see cref="M:log4net.Appender.FileAppender.LockingModelBase.AcquireLock"/> is called again.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.FileAppender.LockingModelBase.CurrentAppender">
+ <summary>
+ Gets or sets the <see cref="T:log4net.Appender.FileAppender"/> for this LockingModel
+ </summary>
+ <value>
+ The <see cref="T:log4net.Appender.FileAppender"/> for this LockingModel
+ </value>
+ <remarks>
+ <para>
+ The file appender this locking model is attached to and working on
+ behalf of.
+ </para>
+ <para>
+ The file appender is used to locate the security context and the error handler to use.
+ </para>
+ <para>
+ The value of this property will be set before <see cref="M:log4net.Appender.FileAppender.LockingModelBase.OpenFile(System.String,System.Boolean,System.Text.Encoding)"/> is
+ called.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.FileAppender.ExclusiveLock">
+ <summary>
+ Hold an exclusive lock on the output file
+ </summary>
+ <remarks>
+ <para>
+ Open the file once for writing and hold it open until <see cref="M:log4net.Appender.FileAppender.ExclusiveLock.CloseFile"/> is called.
+ Maintains an exclusive lock on the file during this time.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.ExclusiveLock.OpenFile(System.String,System.Boolean,System.Text.Encoding)">
+ <summary>
+ Open the file specified and prepare for logging.
+ </summary>
+ <param name="filename">The filename to use</param>
+ <param name="append">Whether to append to the file, or overwrite</param>
+ <param name="encoding">The encoding to use</param>
+ <remarks>
+ <para>
+ Open the file specified and prepare for logging.
+ No writes will be made until <see cref="M:log4net.Appender.FileAppender.ExclusiveLock.AcquireLock"/> is called.
+ Must be called before any calls to <see cref="M:log4net.Appender.FileAppender.ExclusiveLock.AcquireLock"/>,
+ <see cref="M:log4net.Appender.FileAppender.ExclusiveLock.ReleaseLock"/> and <see cref="M:log4net.Appender.FileAppender.ExclusiveLock.CloseFile"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.ExclusiveLock.CloseFile">
+ <summary>
+ Close the file
+ </summary>
+ <remarks>
+ <para>
+ Close the file. No further writes will be made.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.ExclusiveLock.AcquireLock">
+ <summary>
+ Acquire the lock on the file
+ </summary>
+ <returns>A stream that is ready to be written to.</returns>
+ <remarks>
+ <para>
+ Does nothing. The lock is already taken
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.ExclusiveLock.ReleaseLock">
+ <summary>
+ Release the lock on the file
+ </summary>
+ <remarks>
+ <para>
+ Does nothing. The lock will be released when the file is closed.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.FileAppender.MinimalLock">
+ <summary>
+ Acquires the file lock for each write
+ </summary>
+ <remarks>
+ <para>
+ Opens the file once for each <see cref="M:log4net.Appender.FileAppender.MinimalLock.AcquireLock"/>/<see cref="M:log4net.Appender.FileAppender.MinimalLock.ReleaseLock"/> cycle,
+ thus holding the lock for the minimal amount of time. This method of locking
+ is considerably slower than <see cref="T:log4net.Appender.FileAppender.ExclusiveLock"/> but allows
+ other processes to move/delete the log file whilst logging continues.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.MinimalLock.OpenFile(System.String,System.Boolean,System.Text.Encoding)">
+ <summary>
+ Prepares to open the file when the first message is logged.
+ </summary>
+ <param name="filename">The filename to use</param>
+ <param name="append">Whether to append to the file, or overwrite</param>
+ <param name="encoding">The encoding to use</param>
+ <remarks>
+ <para>
+ Open the file specified and prepare for logging.
+ No writes will be made until <see cref="M:log4net.Appender.FileAppender.MinimalLock.AcquireLock"/> is called.
+ Must be called before any calls to <see cref="M:log4net.Appender.FileAppender.MinimalLock.AcquireLock"/>,
+ <see cref="M:log4net.Appender.FileAppender.MinimalLock.ReleaseLock"/> and <see cref="M:log4net.Appender.FileAppender.MinimalLock.CloseFile"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.MinimalLock.CloseFile">
+ <summary>
+ Close the file
+ </summary>
+ <remarks>
+ <para>
+ Close the file. No further writes will be made.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.MinimalLock.AcquireLock">
+ <summary>
+ Acquire the lock on the file
+ </summary>
+ <returns>A stream that is ready to be written to.</returns>
+ <remarks>
+ <para>
+ Acquire the lock on the file in preparation for writing to it.
+ Return a stream pointing to the file. <see cref="M:log4net.Appender.FileAppender.MinimalLock.ReleaseLock"/>
+ must be called to release the lock on the output file.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.FileAppender.MinimalLock.ReleaseLock">
+ <summary>
+ Release the lock on the file
+ </summary>
+ <remarks>
+ <para>
+ Release the lock on the file. No further writes will be made to the
+ stream until <see cref="M:log4net.Appender.FileAppender.MinimalLock.AcquireLock"/> is called again.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.ForwardingAppender">
+ <summary>
+ This appender forwards logging events to attached appenders.
+ </summary>
+ <remarks>
+ <para>
+ The forwarding appender can be used to specify different thresholds
+ and filters for the same appender at different locations within the hierarchy.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Appender.ForwardingAppender.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.ForwardingAppender"/> class.
+ </summary>
+ <remarks>
+ <para>
+ Default constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.ForwardingAppender.OnClose">
+ <summary>
+ Closes the appender and releases resources.
+ </summary>
+ <remarks>
+ <para>
+ Releases any resources allocated within the appender such as file handles,
+ network connections, etc.
+ </para>
+ <para>
+ It is a programming error to append to a closed appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.ForwardingAppender.Append(log4net.Core.LoggingEvent)">
+ <summary>
+ Forward the logging event to the attached appenders
+ </summary>
+ <param name="loggingEvent">The event to log.</param>
+ <remarks>
+ <para>
+ Delivers the logging event to all the attached appenders.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.ForwardingAppender.Append(log4net.Core.LoggingEvent[])">
+ <summary>
+ Forward the logging events to the attached appenders
+ </summary>
+ <param name="loggingEvents">The array of events to log.</param>
+ <remarks>
+ <para>
+ Delivers the logging events to all the attached appenders.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.ForwardingAppender.AddAppender(log4net.Appender.IAppender)">
+ <summary>
+ Adds an <see cref="T:log4net.Appender.IAppender"/> to the list of appenders of this
+ instance.
+ </summary>
+ <param name="newAppender">The <see cref="T:log4net.Appender.IAppender"/> to add to this appender.</param>
+ <remarks>
+ <para>
+ If the specified <see cref="T:log4net.Appender.IAppender"/> is already in the list of
+ appenders, then it won't be added again.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.ForwardingAppender.GetAppender(System.String)">
+ <summary>
+ Looks for the appender with the specified name.
+ </summary>
+ <param name="name">The name of the appender to lookup.</param>
+ <returns>
+ The appender with the specified name, or <c>null</c>.
+ </returns>
+ <remarks>
+ <para>
+ Get the named appender attached to this appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.ForwardingAppender.RemoveAllAppenders">
+ <summary>
+ Removes all previously added appenders from this appender.
+ </summary>
+ <remarks>
+ <para>
+ This is useful when re-reading configuration information.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.ForwardingAppender.RemoveAppender(log4net.Appender.IAppender)">
+ <summary>
+ Removes the specified appender from the list of appenders.
+ </summary>
+ <param name="appender">The appender to remove.</param>
+ <returns>The appender removed from the list</returns>
+ <remarks>
+ The appender removed is not closed.
+ If you are discarding the appender you must call
+ <see cref="M:log4net.Appender.IAppender.Close"/> on the appender removed.
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.ForwardingAppender.RemoveAppender(System.String)">
+ <summary>
+ Removes the appender with the specified name from the list of appenders.
+ </summary>
+ <param name="name">The name of the appender to remove.</param>
+ <returns>The appender removed from the list</returns>
+ <remarks>
+ The appender removed is not closed.
+ If you are discarding the appender you must call
+ <see cref="M:log4net.Appender.IAppender.Close"/> on the appender removed.
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.ForwardingAppender.m_appenderAttachedImpl">
+ <summary>
+ Implementation of the <see cref="T:log4net.Core.IAppenderAttachable"/> interface
+ </summary>
+ </member>
+ <member name="P:log4net.Appender.ForwardingAppender.Appenders">
+ <summary>
+ Gets the appenders contained in this appender as an
+ <see cref="T:System.Collections.ICollection"/>.
+ </summary>
+ <remarks>
+ If no appenders can be found, then an <see cref="T:log4net.Util.EmptyCollection"/>
+ is returned.
+ </remarks>
+ <returns>
+ A collection of the appenders in this appender.
+ </returns>
+ </member>
+ <member name="T:log4net.Appender.LocalSyslogAppender">
+ <summary>
+ Logs events to a local syslog service.
+ </summary>
+ <remarks>
+ <note>
+ This appender uses the POSIX libc library functions <c>openlog</c>, <c>syslog</c>, and <c>closelog</c>.
+ If these functions are not available on the local system then this appender will not work!
+ </note>
+ <para>
+ The functions <c>openlog</c>, <c>syslog</c>, and <c>closelog</c> are specified in SUSv2 and
+ POSIX 1003.1-2001 standards. These are used to log messages to the local syslog service.
+ </para>
+ <para>
+ This appender talks to a local syslog service. If you need to log to a remote syslog
+ daemon and you cannot configure your local syslog service to do this you may be
+ able to use the <see cref="T:log4net.Appender.RemoteSyslogAppender"/> to log via UDP.
+ </para>
+ <para>
+ Syslog messages must have a facility and and a severity. The severity
+ is derived from the Level of the logging event.
+ The facility must be chosen from the set of defined syslog
+ <see cref="T:log4net.Appender.LocalSyslogAppender.SyslogFacility"/> values. The facilities list is predefined
+ and cannot be extended.
+ </para>
+ <para>
+ An identifier is specified with each log message. This can be specified
+ by setting the <see cref="P:log4net.Appender.LocalSyslogAppender.Identity"/> property. The identity (also know
+ as the tag) must not contain white space. The default value for the
+ identity is the application name (from <see cref="P:log4net.Util.SystemInfo.ApplicationFriendlyName"/>).
+ </para>
+ </remarks>
+ <author>Rob Lyon</author>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Appender.LocalSyslogAppender.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.LocalSyslogAppender"/> class.
+ </summary>
+ <remarks>
+ This instance of the <see cref="T:log4net.Appender.LocalSyslogAppender"/> class is set up to write
+ to a local syslog service.
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.LocalSyslogAppender.AddMapping(log4net.Appender.LocalSyslogAppender.LevelSeverity)">
+ <summary>
+ Add a mapping of level to severity
+ </summary>
+ <param name="mapping">The mapping to add</param>
+ <remarks>
+ <para>
+ Adds a <see cref="T:log4net.Appender.LocalSyslogAppender.LevelSeverity"/> to this appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.LocalSyslogAppender.ActivateOptions">
+ <summary>
+ Initialize the appender based on the options set.
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Appender.LocalSyslogAppender.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Appender.LocalSyslogAppender.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Appender.LocalSyslogAppender.ActivateOptions"/> must be called again.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.LocalSyslogAppender.Append(log4net.Core.LoggingEvent)">
+ <summary>
+ This method is called by the <see cref="M:log4net.Appender.AppenderSkeleton.DoAppend(log4net.Core.LoggingEvent)"/> method.
+ </summary>
+ <param name="loggingEvent">The event to log.</param>
+ <remarks>
+ <para>
+ Writes the event to a remote syslog daemon.
+ </para>
+ <para>
+ The format of the output will depend on the appender's layout.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.LocalSyslogAppender.OnClose">
+ <summary>
+ Close the syslog when the appender is closed
+ </summary>
+ <remarks>
+ <para>
+ Close the syslog when the appender is closed
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.LocalSyslogAppender.GetSeverity(log4net.Core.Level)">
+ <summary>
+ Translates a log4net level to a syslog severity.
+ </summary>
+ <param name="level">A log4net level.</param>
+ <returns>A syslog severity.</returns>
+ <remarks>
+ <para>
+ Translates a log4net level to a syslog severity.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.LocalSyslogAppender.GeneratePriority(log4net.Appender.LocalSyslogAppender.SyslogFacility,log4net.Appender.LocalSyslogAppender.SyslogSeverity)">
+ <summary>
+ Generate a syslog priority.
+ </summary>
+ <param name="facility">The syslog facility.</param>
+ <param name="severity">The syslog severity.</param>
+ <returns>A syslog priority.</returns>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.m_facility">
+ <summary>
+ The facility. The default facility is <see cref="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.User"/>.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.m_identity">
+ <summary>
+ The message identity
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.m_handleToIdentity">
+ <summary>
+ Marshaled handle to the identity string. We have to hold on to the
+ string as the <c>openlog</c> and <c>syslog</c> APIs just hold the
+ pointer to the ident and dereference it for each log message.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.m_levelMapping">
+ <summary>
+ Mapping from level object to syslog severity
+ </summary>
+ </member>
+ <member name="M:log4net.Appender.LocalSyslogAppender.openlog(System.IntPtr,System.Int32,log4net.Appender.LocalSyslogAppender.SyslogFacility)">
+ <summary>
+ Open connection to system logger.
+ </summary>
+ </member>
+ <member name="M:log4net.Appender.LocalSyslogAppender.syslog(System.Int32,System.String,System.String)">
+ <summary>
+ Generate a log message.
+ </summary>
+ <remarks>
+ <para>
+ The libc syslog method takes a format string and a variable argument list similar
+ to the classic printf function. As this type of vararg list is not supported
+ by C# we need to specify the arguments explicitly. Here we have specified the
+ format string with a single message argument. The caller must set the format
+ string to <c>"%s"</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.LocalSyslogAppender.closelog">
+ <summary>
+ Close descriptor used to write to system logger.
+ </summary>
+ </member>
+ <member name="P:log4net.Appender.LocalSyslogAppender.Identity">
+ <summary>
+ Message identity
+ </summary>
+ <remarks>
+ <para>
+ An identifier is specified with each log message. This can be specified
+ by setting the <see cref="P:log4net.Appender.LocalSyslogAppender.Identity"/> property. The identity (also know
+ as the tag) must not contain white space. The default value for the
+ identity is the application name (from <see cref="P:log4net.Util.SystemInfo.ApplicationFriendlyName"/>).
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.LocalSyslogAppender.Facility">
+ <summary>
+ Syslog facility
+ </summary>
+ <remarks>
+ Set to one of the <see cref="T:log4net.Appender.LocalSyslogAppender.SyslogFacility"/> values. The list of
+ facilities is predefined and cannot be extended. The default value
+ is <see cref="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.User"/>.
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.LocalSyslogAppender.RequiresLayout">
+ <summary>
+ This appender requires a <see cref="P:log4net.Appender.AppenderSkeleton.Layout"/> to be set.
+ </summary>
+ <value><c>true</c></value>
+ <remarks>
+ <para>
+ This appender requires a <see cref="P:log4net.Appender.AppenderSkeleton.Layout"/> to be set.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.LocalSyslogAppender.SyslogSeverity">
+ <summary>
+ syslog severities
+ </summary>
+ <remarks>
+ <para>
+ The log4net Level maps to a syslog severity using the
+ <see cref="M:log4net.Appender.LocalSyslogAppender.AddMapping(log4net.Appender.LocalSyslogAppender.LevelSeverity)"/> method and the <see cref="T:log4net.Appender.LocalSyslogAppender.LevelSeverity"/>
+ class. The severity is set on <see cref="P:log4net.Appender.LocalSyslogAppender.LevelSeverity.Severity"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogSeverity.Emergency">
+ <summary>
+ system is unusable
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogSeverity.Alert">
+ <summary>
+ action must be taken immediately
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogSeverity.Critical">
+ <summary>
+ critical conditions
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogSeverity.Error">
+ <summary>
+ error conditions
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogSeverity.Warning">
+ <summary>
+ warning conditions
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogSeverity.Notice">
+ <summary>
+ normal but significant condition
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogSeverity.Informational">
+ <summary>
+ informational
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogSeverity.Debug">
+ <summary>
+ debug-level messages
+ </summary>
+ </member>
+ <member name="T:log4net.Appender.LocalSyslogAppender.SyslogFacility">
+ <summary>
+ syslog facilities
+ </summary>
+ <remarks>
+ <para>
+ The syslog facility defines which subsystem the logging comes from.
+ This is set on the <see cref="P:log4net.Appender.LocalSyslogAppender.Facility"/> property.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Kernel">
+ <summary>
+ kernel messages
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.User">
+ <summary>
+ random user-level messages
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Mail">
+ <summary>
+ mail system
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Daemons">
+ <summary>
+ system daemons
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Authorization">
+ <summary>
+ security/authorization messages
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Syslog">
+ <summary>
+ messages generated internally by syslogd
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Printer">
+ <summary>
+ line printer subsystem
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.News">
+ <summary>
+ network news subsystem
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Uucp">
+ <summary>
+ UUCP subsystem
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Clock">
+ <summary>
+ clock (cron/at) daemon
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Authorization2">
+ <summary>
+ security/authorization messages (private)
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Ftp">
+ <summary>
+ ftp daemon
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Ntp">
+ <summary>
+ NTP subsystem
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Audit">
+ <summary>
+ log audit
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Alert">
+ <summary>
+ log alert
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Clock2">
+ <summary>
+ clock daemon
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Local0">
+ <summary>
+ reserved for local use
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Local1">
+ <summary>
+ reserved for local use
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Local2">
+ <summary>
+ reserved for local use
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Local3">
+ <summary>
+ reserved for local use
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Local4">
+ <summary>
+ reserved for local use
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Local5">
+ <summary>
+ reserved for local use
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Local6">
+ <summary>
+ reserved for local use
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.LocalSyslogAppender.SyslogFacility.Local7">
+ <summary>
+ reserved for local use
+ </summary>
+ </member>
+ <member name="T:log4net.Appender.LocalSyslogAppender.LevelSeverity">
+ <summary>
+ A class to act as a mapping between the level that a logging call is made at and
+ the syslog severity that is should be logged at.
+ </summary>
+ <remarks>
+ <para>
+ A class to act as a mapping between the level that a logging call is made at and
+ the syslog severity that is should be logged at.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.LocalSyslogAppender.LevelSeverity.Severity">
+ <summary>
+ The mapped syslog severity for the specified level
+ </summary>
+ <remarks>
+ <para>
+ Required property.
+ The mapped syslog severity for the specified level
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.MemoryAppender">
+ <summary>
+ Stores logging events in an array.
+ </summary>
+ <remarks>
+ <para>
+ The memory appender stores all the logging events
+ that are appended in an in-memory array.
+ </para>
+ <para>
+ Use the <see cref="M:log4net.Appender.MemoryAppender.GetEvents"/> method to get
+ the current list of events that have been appended.
+ </para>
+ <para>
+ Use the <see cref="M:log4net.Appender.MemoryAppender.Clear"/> method to clear the
+ current list of events.
+ </para>
+ </remarks>
+ <author>Julian Biddle</author>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Appender.MemoryAppender.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.MemoryAppender"/> class.
+ </summary>
+ <remarks>
+ <para>
+ Default constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.MemoryAppender.GetEvents">
+ <summary>
+ Gets the events that have been logged.
+ </summary>
+ <returns>The events that have been logged</returns>
+ <remarks>
+ <para>
+ Gets the events that have been logged.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.MemoryAppender.Append(log4net.Core.LoggingEvent)">
+ <summary>
+ This method is called by the <see cref="M:log4net.Appender.AppenderSkeleton.DoAppend(log4net.Core.LoggingEvent)"/> method.
+ </summary>
+ <param name="loggingEvent">the event to log</param>
+ <remarks>
+ <para>Stores the <paramref name="loggingEvent"/> in the events list.</para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.MemoryAppender.Clear">
+ <summary>
+ Clear the list of events
+ </summary>
+ <remarks>
+ Clear the list of events
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.MemoryAppender.m_eventsList">
+ <summary>
+ The list of events that have been appended.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.MemoryAppender.m_fixFlags">
+ <summary>
+ Value indicating which fields in the event should be fixed
+ </summary>
+ <remarks>
+ By default all fields are fixed
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.MemoryAppender.OnlyFixPartialEventData">
+ <summary>
+ Gets or sets a value indicating whether only part of the logging event
+ data should be fixed.
+ </summary>
+ <value>
+ <c>true</c> if the appender should only fix part of the logging event
+ data, otherwise <c>false</c>. The default is <c>false</c>.
+ </value>
+ <remarks>
+ <para>
+ Setting this property to <c>true</c> will cause only part of the event
+ data to be fixed and stored in the appender, hereby improving performance.
+ </para>
+ <para>
+ See <see cref="M:log4net.Core.LoggingEvent.FixVolatileData(System.Boolean)"/> for more information.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.MemoryAppender.Fix">
+ <summary>
+ Gets or sets the fields that will be fixed in the event
+ </summary>
+ <remarks>
+ <para>
+ The logging event needs to have certain thread specific values
+ captured before it can be buffered. See <see cref="P:log4net.Core.LoggingEvent.Fix"/>
+ for details.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.NetSendAppender">
+ <summary>
+ Logs entries by sending network messages using the
+ <see cref="M:log4net.Appender.NetSendAppender.NetMessageBufferSend(System.String,System.String,System.String,System.String,System.Int32)"/> native function.
+ </summary>
+ <remarks>
+ <para>
+ You can send messages only to names that are active
+ on the network. If you send the message to a user name,
+ that user must be logged on and running the Messenger
+ service to receive the message.
+ </para>
+ <para>
+ The receiver will get a top most window displaying the
+ messages one at a time, therefore this appender should
+ not be used to deliver a high volume of messages.
+ </para>
+ <para>
+ The following table lists some possible uses for this appender :
+ </para>
+ <para>
+ <list type="table">
+ <listheader>
+ <term>Action</term>
+ <description>Property Value(s)</description>
+ </listheader>
+ <item>
+ <term>Send a message to a user account on the local machine</term>
+ <description>
+ <para>
+ <paramref name="Server"/> = &lt;name of the local machine&gt;
+ </para>
+ <para>
+ <paramref name="Recipient"/> = &lt;user name&gt;
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>Send a message to a user account on a remote machine</term>
+ <description>
+ <para>
+ <paramref name="Server"/> = &lt;name of the remote machine&gt;
+ </para>
+ <para>
+ <paramref name="Recipient"/> = &lt;user name&gt;
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>Send a message to a domain user account</term>
+ <description>
+ <para>
+ <paramref name="Server"/> = &lt;name of a domain controller | uninitialized&gt;
+ </para>
+ <para>
+ <paramref name="Recipient"/> = &lt;user name&gt;
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>Send a message to all the names in a workgroup or domain</term>
+ <description>
+ <para>
+ <paramref name="Recipient"/> = &lt;workgroup name | domain name&gt;*
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>Send a message from the local machine to a remote machine</term>
+ <description>
+ <para>
+ <paramref name="Server"/> = &lt;name of the local machine | uninitialized&gt;
+ </para>
+ <para>
+ <paramref name="Recipient"/> = &lt;name of the remote machine&gt;
+ </para>
+ </description>
+ </item>
+ </list>
+ </para>
+ <para>
+ <b>Note :</b> security restrictions apply for sending
+ network messages, see <see cref="M:log4net.Appender.NetSendAppender.NetMessageBufferSend(System.String,System.String,System.String,System.String,System.Int32)"/>
+ for more information.
+ </para>
+ </remarks>
+ <example>
+ <para>
+ An example configuration section to log information
+ using this appender from the local machine, named
+ LOCAL_PC, to machine OPERATOR_PC :
+ </para>
+ <code lang="XML" escaped="true">
+ <appender name="NetSendAppender_Operator" type="log4net.Appender.NetSendAppender">
+ <server value="LOCAL_PC"/>
+ <recipient value="OPERATOR_PC"/>
+ <layout type="log4net.Layout.PatternLayout" value="%-5p %c [%x] - %m%n"/>
+ </appender>
+ </code>
+ </example>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="F:log4net.Appender.NetSendAppender.m_server">
+ <summary>
+ The DNS or NetBIOS name of the server on which the function is to execute.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.NetSendAppender.m_sender">
+ <summary>
+ The sender of the network message.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.NetSendAppender.m_recipient">
+ <summary>
+ The message alias to which the message should be sent.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.NetSendAppender.m_securityContext">
+ <summary>
+ The security context to use for privileged calls
+ </summary>
+ </member>
+ <member name="M:log4net.Appender.NetSendAppender.#ctor">
+ <summary>
+ Initializes the appender.
+ </summary>
+ <remarks>
+ The default constructor initializes all fields to their default values.
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.NetSendAppender.ActivateOptions">
+ <summary>
+ Initialize the appender based on the options set.
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Appender.NetSendAppender.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Appender.NetSendAppender.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Appender.NetSendAppender.ActivateOptions"/> must be called again.
+ </para>
+ <para>
+ The appender will be ignored if no <see cref="P:log4net.Appender.NetSendAppender.Recipient"/> was specified.
+ </para>
+ </remarks>
+ <exception cref="T:System.ArgumentNullException">The required property <see cref="P:log4net.Appender.NetSendAppender.Recipient"/> was not specified.</exception>
+ </member>
+ <member name="M:log4net.Appender.NetSendAppender.Append(log4net.Core.LoggingEvent)">
+ <summary>
+ This method is called by the <see cref="M:log4net.Appender.AppenderSkeleton.DoAppend(log4net.Core.LoggingEvent)"/> method.
+ </summary>
+ <param name="loggingEvent">The event to log.</param>
+ <remarks>
+ <para>
+ Sends the event using a network message.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.NetSendAppender.NetMessageBufferSend(System.String,System.String,System.String,System.String,System.Int32)">
+ <summary>
+ Sends a buffer of information to a registered message alias.
+ </summary>
+ <param name="serverName">The DNS or NetBIOS name of the server on which the function is to execute.</param>
+ <param name="msgName">The message alias to which the message buffer should be sent</param>
+ <param name="fromName">The originator of the message.</param>
+ <param name="buffer">The message text.</param>
+ <param name="bufferSize">The length, in bytes, of the message text.</param>
+ <remarks>
+ <para>
+ The following restrictions apply for sending network messages:
+ </para>
+ <para>
+ <list type="table">
+ <listheader>
+ <term>Platform</term>
+ <description>Requirements</description>
+ </listheader>
+ <item>
+ <term>Windows NT</term>
+ <description>
+ <para>
+ No special group membership is required to send a network message.
+ </para>
+ <para>
+ Admin, Accounts, Print, or Server Operator group membership is required to
+ successfully send a network message on a remote server.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>Windows 2000 or later</term>
+ <description>
+ <para>
+ If you send a message on a domain controller that is running Active Directory,
+ access is allowed or denied based on the access control list (ACL) for the securable
+ object. The default ACL permits only Domain Admins and Account Operators to send a network message.
+ </para>
+ <para>
+ On a member server or workstation, only Administrators and Server Operators can send a network message.
+ </para>
+ </description>
+ </item>
+ </list>
+ </para>
+ <para>
+ For more information see <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netmgmt/netmgmt/security_requirements_for_the_network_management_functions.asp">Security Requirements for the Network Management Functions</a>.
+ </para>
+ </remarks>
+ <returns>
+ <para>
+ If the function succeeds, the return value is zero.
+ </para>
+ </returns>
+ </member>
+ <member name="P:log4net.Appender.NetSendAppender.Sender">
+ <summary>
+ Gets or sets the sender of the message.
+ </summary>
+ <value>
+ The sender of the message.
+ </value>
+ <remarks>
+ If this property is not specified, the message is sent from the local computer.
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.NetSendAppender.Recipient">
+ <summary>
+ Gets or sets the message alias to which the message should be sent.
+ </summary>
+ <value>
+ The recipient of the message.
+ </value>
+ <remarks>
+ This property should always be specified in order to send a message.
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.NetSendAppender.Server">
+ <summary>
+ Gets or sets the DNS or NetBIOS name of the remote server on which the function is to execute.
+ </summary>
+ <value>
+ DNS or NetBIOS name of the remote server on which the function is to execute.
+ </value>
+ <remarks>
+ <para>
+ For Windows NT 4.0 and earlier, the string should begin with \\.
+ </para>
+ <para>
+ If this property is not specified, the local computer is used.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.NetSendAppender.SecurityContext">
+ <summary>
+ Gets or sets the <see cref="P:log4net.Appender.NetSendAppender.SecurityContext"/> used to call the NetSend method.
+ </summary>
+ <value>
+ The <see cref="P:log4net.Appender.NetSendAppender.SecurityContext"/> used to call the NetSend method.
+ </value>
+ <remarks>
+ <para>
+ Unless a <see cref="P:log4net.Appender.NetSendAppender.SecurityContext"/> specified here for this appender
+ the <see cref="P:log4net.Core.SecurityContextProvider.DefaultProvider"/> is queried for the
+ security context to use. The default behavior is to use the security context
+ of the current thread.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.NetSendAppender.RequiresLayout">
+ <summary>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </summary>
+ <value><c>true</c></value>
+ <remarks>
+ <para>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.OutputDebugStringAppender">
+ <summary>
+ Appends log events to the OutputDebugString system.
+ </summary>
+ <remarks>
+ <para>
+ OutputDebugStringAppender appends log events to the
+ OutputDebugString system.
+ </para>
+ <para>
+ The string is passed to the native <c>OutputDebugString</c>
+ function.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Appender.OutputDebugStringAppender.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.OutputDebugStringAppender"/> class.
+ </summary>
+ <remarks>
+ <para>
+ Default constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.OutputDebugStringAppender.Append(log4net.Core.LoggingEvent)">
+ <summary>
+ Write the logging event to the output debug string API
+ </summary>
+ <param name="loggingEvent">the event to log</param>
+ <remarks>
+ <para>
+ Write the logging event to the output debug string API
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.OutputDebugStringAppender.OutputDebugString(System.String)">
+ <summary>
+ Stub for OutputDebugString native method
+ </summary>
+ <param name="message">the string to output</param>
+ <remarks>
+ <para>
+ Stub for OutputDebugString native method
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.OutputDebugStringAppender.RequiresLayout">
+ <summary>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </summary>
+ <value><c>true</c></value>
+ <remarks>
+ <para>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.RemoteSyslogAppender">
+ <summary>
+ Logs events to a remote syslog daemon.
+ </summary>
+ <remarks>
+ <para>
+ The BSD syslog protocol is used to remotely log to
+ a syslog daemon. The syslogd listens for for messages
+ on UDP port 514.
+ </para>
+ <para>
+ The syslog UDP protocol is not authenticated. Most syslog daemons
+ do not accept remote log messages because of the security implications.
+ You may be able to use the LocalSyslogAppender to talk to a local
+ syslog service.
+ </para>
+ <para>
+ There is an RFC 3164 that claims to document the BSD Syslog Protocol.
+ This RFC can be seen here: http://www.faqs.org/rfcs/rfc3164.html.
+ This appender generates what the RFC calls an "Original Device Message",
+ i.e. does not include the TIMESTAMP or HOSTNAME fields. By observation
+ this format of message will be accepted by all current syslog daemon
+ implementations. The daemon will attach the current time and the source
+ hostname or IP address to any messages received.
+ </para>
+ <para>
+ Syslog messages must have a facility and and a severity. The severity
+ is derived from the Level of the logging event.
+ The facility must be chosen from the set of defined syslog
+ <see cref="T:log4net.Appender.RemoteSyslogAppender.SyslogFacility"/> values. The facilities list is predefined
+ and cannot be extended.
+ </para>
+ <para>
+ An identifier is specified with each log message. This can be specified
+ by setting the <see cref="P:log4net.Appender.RemoteSyslogAppender.Identity"/> property. The identity (also know
+ as the tag) must not contain white space. The default value for the
+ identity is the application name (from <see cref="P:log4net.Core.LoggingEvent.Domain"/>).
+ </para>
+ </remarks>
+ <author>Rob Lyon</author>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="T:log4net.Appender.UdpAppender">
+ <summary>
+ Sends logging events as connectionless UDP datagrams to a remote host or a
+ multicast group using an <see cref="T:System.Net.Sockets.UdpClient"/>.
+ </summary>
+ <remarks>
+ <para>
+ UDP guarantees neither that messages arrive, nor that they arrive in the correct order.
+ </para>
+ <para>
+ To view the logging results, a custom application can be developed that listens for logging
+ events.
+ </para>
+ <para>
+ When decoding events send via this appender remember to use the same encoding
+ to decode the events as was used to send the events. See the <see cref="P:log4net.Appender.UdpAppender.Encoding"/>
+ property to specify the encoding to use.
+ </para>
+ </remarks>
+ <example>
+ This example shows how to log receive logging events that are sent
+ on IP address 244.0.0.1 and port 8080 to the console. The event is
+ encoded in the packet as a unicode string and it is decoded as such.
+ <code lang="C#">
+ IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
+ UdpClient udpClient;
+ byte[] buffer;
+ string loggingEvent;
+
+ try
+ {
+ udpClient = new UdpClient(8080);
+
+ while(true)
+ {
+ buffer = udpClient.Receive(ref remoteEndPoint);
+ loggingEvent = System.Text.Encoding.Unicode.GetString(buffer);
+ Console.WriteLine(loggingEvent);
+ }
+ }
+ catch(Exception e)
+ {
+ Console.WriteLine(e.ToString());
+ }
+ </code>
+ <code lang="Visual Basic">
+ Dim remoteEndPoint as IPEndPoint
+ Dim udpClient as UdpClient
+ Dim buffer as Byte()
+ Dim loggingEvent as String
+
+ Try
+ remoteEndPoint = new IPEndPoint(IPAddress.Any, 0)
+ udpClient = new UdpClient(8080)
+
+ While True
+ buffer = udpClient.Receive(ByRef remoteEndPoint)
+ loggingEvent = System.Text.Encoding.Unicode.GetString(buffer)
+ Console.WriteLine(loggingEvent)
+ Wend
+ Catch e As Exception
+ Console.WriteLine(e.ToString())
+ End Try
+ </code>
+ <para>
+ An example configuration section to log information using this appender to the
+ IP 224.0.0.1 on port 8080:
+ </para>
+ <code lang="XML" escaped="true">
+ <appender name="UdpAppender" type="log4net.Appender.UdpAppender">
+ <remoteAddress value="224.0.0.1"/>
+ <remotePort value="8080"/>
+ <layout type="log4net.Layout.PatternLayout" value="%-5level %logger [%ndc] - %message%newline"/>
+ </appender>
+ </code>
+ </example>
+ <author>Gert Driesen</author>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Appender.UdpAppender.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.UdpAppender"/> class.
+ </summary>
+ <remarks>
+ The default constructor initializes all fields to their default values.
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.UdpAppender.ActivateOptions">
+ <summary>
+ Initialize the appender based on the options set.
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Appender.UdpAppender.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Appender.UdpAppender.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Appender.UdpAppender.ActivateOptions"/> must be called again.
+ </para>
+ <para>
+ The appender will be ignored if no <see cref="P:log4net.Appender.UdpAppender.RemoteAddress"/> was specified or
+ an invalid remote or local TCP port number was specified.
+ </para>
+ </remarks>
+ <exception cref="T:System.ArgumentNullException">The required property <see cref="P:log4net.Appender.UdpAppender.RemoteAddress"/> was not specified.</exception>
+ <exception cref="T:System.ArgumentOutOfRangeException">The TCP port number assigned to <see cref="P:log4net.Appender.UdpAppender.LocalPort"/> or <see cref="P:log4net.Appender.UdpAppender.RemotePort"/> is less than <see cref="F:System.Net.IPEndPoint.MinPort"/> or greater than <see cref="F:System.Net.IPEndPoint.MaxPort"/>.</exception>
+ </member>
+ <member name="M:log4net.Appender.UdpAppender.Append(log4net.Core.LoggingEvent)">
+ <summary>
+ This method is called by the <see cref="M:log4net.Appender.AppenderSkeleton.DoAppend(log4net.Core.LoggingEvent)"/> method.
+ </summary>
+ <param name="loggingEvent">The event to log.</param>
+ <remarks>
+ <para>
+ Sends the event using an UDP datagram.
+ </para>
+ <para>
+ Exceptions are passed to the <see cref="P:log4net.Appender.AppenderSkeleton.ErrorHandler"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.UdpAppender.OnClose">
+ <summary>
+ Closes the UDP connection and releases all resources associated with
+ this <see cref="T:log4net.Appender.UdpAppender"/> instance.
+ </summary>
+ <remarks>
+ <para>
+ Disables the underlying <see cref="T:System.Net.Sockets.UdpClient"/> and releases all managed
+ and unmanaged resources associated with the <see cref="T:log4net.Appender.UdpAppender"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.UdpAppender.InitializeClientConnection">
+ <summary>
+ Initializes the underlying <see cref="T:System.Net.Sockets.UdpClient"/> connection.
+ </summary>
+ <remarks>
+ <para>
+ The underlying <see cref="T:System.Net.Sockets.UdpClient"/> is initialized and binds to the
+ port number from which you intend to communicate.
+ </para>
+ <para>
+ Exceptions are passed to the <see cref="P:log4net.Appender.AppenderSkeleton.ErrorHandler"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.UdpAppender.m_remoteAddress">
+ <summary>
+ The IP address of the remote host or multicast group to which
+ the logging event will be sent.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.UdpAppender.m_remotePort">
+ <summary>
+ The TCP port number of the remote host or multicast group to
+ which the logging event will be sent.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.UdpAppender.m_remoteEndPoint">
+ <summary>
+ The cached remote endpoint to which the logging events will be sent.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.UdpAppender.m_localPort">
+ <summary>
+ The TCP port number from which the <see cref="T:System.Net.Sockets.UdpClient"/> will communicate.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.UdpAppender.m_client">
+ <summary>
+ The <see cref="T:System.Net.Sockets.UdpClient"/> instance that will be used for sending the
+ logging events.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.UdpAppender.m_encoding">
+ <summary>
+ The encoding to use for the packet.
+ </summary>
+ </member>
+ <member name="P:log4net.Appender.UdpAppender.RemoteAddress">
+ <summary>
+ Gets or sets the IP address of the remote host or multicast group to which
+ the underlying <see cref="T:System.Net.Sockets.UdpClient"/> should sent the logging event.
+ </summary>
+ <value>
+ The IP address of the remote host or multicast group to which the logging event
+ will be sent.
+ </value>
+ <remarks>
+ <para>
+ Multicast addresses are identified by IP class <b>D</b> addresses (in the range 224.0.0.0 to
+ 239.255.255.255). Multicast packets can pass across different networks through routers, so
+ it is possible to use multicasts in an Internet scenario as long as your network provider
+ supports multicasting.
+ </para>
+ <para>
+ Hosts that want to receive particular multicast messages must register their interest by joining
+ the multicast group. Multicast messages are not sent to networks where no host has joined
+ the multicast group. Class <b>D</b> IP addresses are used for multicast groups, to differentiate
+ them from normal host addresses, allowing nodes to easily detect if a message is of interest.
+ </para>
+ <para>
+ Static multicast addresses that are needed globally are assigned by IANA. A few examples are listed in the table below:
+ </para>
+ <para>
+ <list type="table">
+ <listheader>
+ <term>IP Address</term>
+ <description>Description</description>
+ </listheader>
+ <item>
+ <term>224.0.0.1</term>
+ <description>
+ <para>
+ Sends a message to all system on the subnet.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>224.0.0.2</term>
+ <description>
+ <para>
+ Sends a message to all routers on the subnet.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>224.0.0.12</term>
+ <description>
+ <para>
+ The DHCP server answers messages on the IP address 224.0.0.12, but only on a subnet.
+ </para>
+ </description>
+ </item>
+ </list>
+ </para>
+ <para>
+ A complete list of actually reserved multicast addresses and their owners in the ranges
+ defined by RFC 3171 can be found at the <A href="http://www.iana.org/assignments/multicast-addresses">IANA web site</A>.
+ </para>
+ <para>
+ The address range 239.0.0.0 to 239.255.255.255 is reserved for administrative scope-relative
+ addresses. These addresses can be reused with other local groups. Routers are typically
+ configured with filters to prevent multicast traffic in this range from flowing outside
+ of the local network.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.UdpAppender.RemotePort">
+ <summary>
+ Gets or sets the TCP port number of the remote host or multicast group to which
+ the underlying <see cref="T:System.Net.Sockets.UdpClient"/> should sent the logging event.
+ </summary>
+ <value>
+ An integer value in the range <see cref="F:System.Net.IPEndPoint.MinPort"/> to <see cref="F:System.Net.IPEndPoint.MaxPort"/>
+ indicating the TCP port number of the remote host or multicast group to which the logging event
+ will be sent.
+ </value>
+ <remarks>
+ The underlying <see cref="T:System.Net.Sockets.UdpClient"/> will send messages to this TCP port number
+ on the remote host or multicast group.
+ </remarks>
+ <exception cref="T:System.ArgumentOutOfRangeException">The value specified is less than <see cref="F:System.Net.IPEndPoint.MinPort"/> or greater than <see cref="F:System.Net.IPEndPoint.MaxPort"/>.</exception>
+ </member>
+ <member name="P:log4net.Appender.UdpAppender.LocalPort">
+ <summary>
+ Gets or sets the TCP port number from which the underlying <see cref="T:System.Net.Sockets.UdpClient"/> will communicate.
+ </summary>
+ <value>
+ An integer value in the range <see cref="F:System.Net.IPEndPoint.MinPort"/> to <see cref="F:System.Net.IPEndPoint.MaxPort"/>
+ indicating the TCP port number from which the underlying <see cref="T:System.Net.Sockets.UdpClient"/> will communicate.
+ </value>
+ <remarks>
+ <para>
+ The underlying <see cref="T:System.Net.Sockets.UdpClient"/> will bind to this port for sending messages.
+ </para>
+ <para>
+ Setting the value to 0 (the default) will cause the udp client not to bind to
+ a local port.
+ </para>
+ </remarks>
+ <exception cref="T:System.ArgumentOutOfRangeException">The value specified is less than <see cref="F:System.Net.IPEndPoint.MinPort"/> or greater than <see cref="F:System.Net.IPEndPoint.MaxPort"/>.</exception>
+ </member>
+ <member name="P:log4net.Appender.UdpAppender.Encoding">
+ <summary>
+ Gets or sets <see cref="P:log4net.Appender.UdpAppender.Encoding"/> used to write the packets.
+ </summary>
+ <value>
+ The <see cref="P:log4net.Appender.UdpAppender.Encoding"/> used to write the packets.
+ </value>
+ <remarks>
+ <para>
+ The <see cref="P:log4net.Appender.UdpAppender.Encoding"/> used to write the packets.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.UdpAppender.Client">
+ <summary>
+ Gets or sets the underlying <see cref="T:System.Net.Sockets.UdpClient"/>.
+ </summary>
+ <value>
+ The underlying <see cref="T:System.Net.Sockets.UdpClient"/>.
+ </value>
+ <remarks>
+ <see cref="T:log4net.Appender.UdpAppender"/> creates a <see cref="T:System.Net.Sockets.UdpClient"/> to send logging events
+ over a network. Classes deriving from <see cref="T:log4net.Appender.UdpAppender"/> can use this
+ property to get or set this <see cref="T:System.Net.Sockets.UdpClient"/>. Use the underlying <see cref="T:System.Net.Sockets.UdpClient"/>
+ returned from <see cref="P:log4net.Appender.UdpAppender.Client"/> if you require access beyond that which
+ <see cref="T:log4net.Appender.UdpAppender"/> provides.
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.UdpAppender.RemoteEndPoint">
+ <summary>
+ Gets or sets the cached remote endpoint to which the logging events should be sent.
+ </summary>
+ <value>
+ The cached remote endpoint to which the logging events will be sent.
+ </value>
+ <remarks>
+ The <see cref="M:log4net.Appender.UdpAppender.ActivateOptions"/> method will initialize the remote endpoint
+ with the values of the <see cref="P:log4net.Appender.UdpAppender.RemoteAddress"/> and <see cref="P:log4net.Appender.UdpAppender.RemotePort"/>
+ properties.
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.UdpAppender.RequiresLayout">
+ <summary>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </summary>
+ <value><c>true</c></value>
+ <remarks>
+ <para>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.DefaultSyslogPort">
+ <summary>
+ Syslog port 514
+ </summary>
+ </member>
+ <member name="M:log4net.Appender.RemoteSyslogAppender.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.RemoteSyslogAppender"/> class.
+ </summary>
+ <remarks>
+ This instance of the <see cref="T:log4net.Appender.RemoteSyslogAppender"/> class is set up to write
+ to a remote syslog daemon.
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RemoteSyslogAppender.AddMapping(log4net.Appender.RemoteSyslogAppender.LevelSeverity)">
+ <summary>
+ Add a mapping of level to severity
+ </summary>
+ <param name="mapping">The mapping to add</param>
+ <remarks>
+ <para>
+ Add a <see cref="T:log4net.Appender.RemoteSyslogAppender.LevelSeverity"/> mapping to this appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RemoteSyslogAppender.Append(log4net.Core.LoggingEvent)">
+ <summary>
+ This method is called by the <see cref="M:log4net.Appender.AppenderSkeleton.DoAppend(log4net.Core.LoggingEvent)"/> method.
+ </summary>
+ <param name="loggingEvent">The event to log.</param>
+ <remarks>
+ <para>
+ Writes the event to a remote syslog daemon.
+ </para>
+ <para>
+ The format of the output will depend on the appender's layout.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RemoteSyslogAppender.ActivateOptions">
+ <summary>
+ Initialize the options for this appender
+ </summary>
+ <remarks>
+ <para>
+ Initialize the level to syslog severity mappings set on this appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RemoteSyslogAppender.GetSeverity(log4net.Core.Level)">
+ <summary>
+ Translates a log4net level to a syslog severity.
+ </summary>
+ <param name="level">A log4net level.</param>
+ <returns>A syslog severity.</returns>
+ <remarks>
+ <para>
+ Translates a log4net level to a syslog severity.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RemoteSyslogAppender.GeneratePriority(log4net.Appender.RemoteSyslogAppender.SyslogFacility,log4net.Appender.RemoteSyslogAppender.SyslogSeverity)">
+ <summary>
+ Generate a syslog priority.
+ </summary>
+ <param name="facility">The syslog facility.</param>
+ <param name="severity">The syslog severity.</param>
+ <returns>A syslog priority.</returns>
+ <remarks>
+ <para>
+ Generate a syslog priority.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.m_facility">
+ <summary>
+ The facility. The default facility is <see cref="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.User"/>.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.m_identity">
+ <summary>
+ The message identity
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.m_levelMapping">
+ <summary>
+ Mapping from level object to syslog severity
+ </summary>
+ </member>
+ <member name="P:log4net.Appender.RemoteSyslogAppender.Identity">
+ <summary>
+ Message identity
+ </summary>
+ <remarks>
+ <para>
+ An identifier is specified with each log message. This can be specified
+ by setting the <see cref="P:log4net.Appender.RemoteSyslogAppender.Identity"/> property. The identity (also know
+ as the tag) must not contain white space. The default value for the
+ identity is the application name (from <see cref="P:log4net.Core.LoggingEvent.Domain"/>).
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.RemoteSyslogAppender.Facility">
+ <summary>
+ Syslog facility
+ </summary>
+ <remarks>
+ Set to one of the <see cref="T:log4net.Appender.RemoteSyslogAppender.SyslogFacility"/> values. The list of
+ facilities is predefined and cannot be extended. The default value
+ is <see cref="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.User"/>.
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.RemoteSyslogAppender.SyslogSeverity">
+ <summary>
+ syslog severities
+ </summary>
+ <remarks>
+ <para>
+ The syslog severities.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogSeverity.Emergency">
+ <summary>
+ system is unusable
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogSeverity.Alert">
+ <summary>
+ action must be taken immediately
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogSeverity.Critical">
+ <summary>
+ critical conditions
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogSeverity.Error">
+ <summary>
+ error conditions
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogSeverity.Warning">
+ <summary>
+ warning conditions
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogSeverity.Notice">
+ <summary>
+ normal but significant condition
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogSeverity.Informational">
+ <summary>
+ informational
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogSeverity.Debug">
+ <summary>
+ debug-level messages
+ </summary>
+ </member>
+ <member name="T:log4net.Appender.RemoteSyslogAppender.SyslogFacility">
+ <summary>
+ syslog facilities
+ </summary>
+ <remarks>
+ <para>
+ The syslog facilities
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Kernel">
+ <summary>
+ kernel messages
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.User">
+ <summary>
+ random user-level messages
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Mail">
+ <summary>
+ mail system
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Daemons">
+ <summary>
+ system daemons
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Authorization">
+ <summary>
+ security/authorization messages
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Syslog">
+ <summary>
+ messages generated internally by syslogd
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Printer">
+ <summary>
+ line printer subsystem
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.News">
+ <summary>
+ network news subsystem
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Uucp">
+ <summary>
+ UUCP subsystem
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Clock">
+ <summary>
+ clock (cron/at) daemon
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Authorization2">
+ <summary>
+ security/authorization messages (private)
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Ftp">
+ <summary>
+ ftp daemon
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Ntp">
+ <summary>
+ NTP subsystem
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Audit">
+ <summary>
+ log audit
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Alert">
+ <summary>
+ log alert
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Clock2">
+ <summary>
+ clock daemon
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Local0">
+ <summary>
+ reserved for local use
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Local1">
+ <summary>
+ reserved for local use
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Local2">
+ <summary>
+ reserved for local use
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Local3">
+ <summary>
+ reserved for local use
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Local4">
+ <summary>
+ reserved for local use
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Local5">
+ <summary>
+ reserved for local use
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Local6">
+ <summary>
+ reserved for local use
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemoteSyslogAppender.SyslogFacility.Local7">
+ <summary>
+ reserved for local use
+ </summary>
+ </member>
+ <member name="T:log4net.Appender.RemoteSyslogAppender.LevelSeverity">
+ <summary>
+ A class to act as a mapping between the level that a logging call is made at and
+ the syslog severity that is should be logged at.
+ </summary>
+ <remarks>
+ <para>
+ A class to act as a mapping between the level that a logging call is made at and
+ the syslog severity that is should be logged at.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.RemoteSyslogAppender.LevelSeverity.Severity">
+ <summary>
+ The mapped syslog severity for the specified level
+ </summary>
+ <remarks>
+ <para>
+ Required property.
+ The mapped syslog severity for the specified level
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.RemotingAppender">
+ <summary>
+ Delivers logging events to a remote logging sink.
+ </summary>
+ <remarks>
+ <para>
+ This Appender is designed to deliver events to a remote sink.
+ That is any object that implements the <see cref="T:log4net.Appender.RemotingAppender.IRemoteLoggingSink"/>
+ interface. It delivers the events using .NET remoting. The
+ object to deliver events to is specified by setting the
+ appenders <see cref="P:log4net.Appender.RemotingAppender.Sink"/> property.</para>
+ <para>
+ The RemotingAppender buffers events before sending them. This allows it to
+ make more efficient use of the remoting infrastructure.</para>
+ <para>
+ Once the buffer is full the events are still not sent immediately.
+ They are scheduled to be sent using a pool thread. The effect is that
+ the send occurs asynchronously. This is very important for a
+ number of non obvious reasons. The remoting infrastructure will
+ flow thread local variables (stored in the <see cref="T:System.Runtime.Remoting.Messaging.CallContext"/>),
+ if they are marked as <see cref="T:System.Runtime.Remoting.Messaging.ILogicalThreadAffinative"/>, across the
+ remoting boundary. If the server is not contactable then
+ the remoting infrastructure will clear the <see cref="T:System.Runtime.Remoting.Messaging.ILogicalThreadAffinative"/>
+ objects from the <see cref="T:System.Runtime.Remoting.Messaging.CallContext"/>. To prevent a logging failure from
+ having side effects on the calling application the remoting call must be made
+ from a separate thread to the one used by the application. A <see cref="T:System.Threading.ThreadPool"/>
+ thread is used for this. If no <see cref="T:System.Threading.ThreadPool"/> thread is available then
+ the events will block in the thread pool manager until a thread is available.</para>
+ <para>
+ Because the events are sent asynchronously using pool threads it is possible to close
+ this appender before all the queued events have been sent.
+ When closing the appender attempts to wait until all the queued events have been sent, but
+ this will timeout after 30 seconds regardless.</para>
+ <para>
+ If this appender is being closed because the <see cref="E:System.AppDomain.ProcessExit"/>
+ event has fired it may not be possible to send all the queued events. During process
+ exit the runtime limits the time that a <see cref="E:System.AppDomain.ProcessExit"/>
+ event handler is allowed to run for. If the runtime terminates the threads before
+ the queued events have been sent then they will be lost. To ensure that all events
+ are sent the appender must be closed before the application exits. See
+ <see cref="M:log4net.Core.LoggerManager.Shutdown"/> for details on how to shutdown
+ log4net programmatically.</para>
+ </remarks>
+ <seealso cref="T:log4net.Appender.RemotingAppender.IRemoteLoggingSink"/>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ <author>Daniel Cazzulino</author>
+ </member>
+ <member name="M:log4net.Appender.RemotingAppender.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.RemotingAppender"/> class.
+ </summary>
+ <remarks>
+ <para>
+ Default constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RemotingAppender.ActivateOptions">
+ <summary>
+ Initialize the appender based on the options set
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Appender.RemotingAppender.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Appender.RemotingAppender.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Appender.RemotingAppender.ActivateOptions"/> must be called again.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RemotingAppender.SendBuffer(log4net.Core.LoggingEvent[])">
+ <summary>
+ Send the contents of the buffer to the remote sink.
+ </summary>
+ <remarks>
+ The events are not sent immediately. They are scheduled to be sent
+ using a pool thread. The effect is that the send occurs asynchronously.
+ This is very important for a number of non obvious reasons. The remoting
+ infrastructure will flow thread local variables (stored in the <see cref="T:System.Runtime.Remoting.Messaging.CallContext"/>),
+ if they are marked as <see cref="T:System.Runtime.Remoting.Messaging.ILogicalThreadAffinative"/>, across the
+ remoting boundary. If the server is not contactable then
+ the remoting infrastructure will clear the <see cref="T:System.Runtime.Remoting.Messaging.ILogicalThreadAffinative"/>
+ objects from the <see cref="T:System.Runtime.Remoting.Messaging.CallContext"/>. To prevent a logging failure from
+ having side effects on the calling application the remoting call must be made
+ from a separate thread to the one used by the application. A <see cref="T:System.Threading.ThreadPool"/>
+ thread is used for this. If no <see cref="T:System.Threading.ThreadPool"/> thread is available then
+ the events will block in the thread pool manager until a thread is available.
+ </remarks>
+ <param name="events">The events to send.</param>
+ </member>
+ <member name="M:log4net.Appender.RemotingAppender.OnClose">
+ <summary>
+ Override base class close.
+ </summary>
+ <remarks>
+ <para>
+ This method waits while there are queued work items. The events are
+ sent asynchronously using <see cref="T:System.Threading.ThreadPool"/> work items. These items
+ will be sent once a thread pool thread is available to send them, therefore
+ it is possible to close the appender before all the queued events have been
+ sent.</para>
+ <para>
+ This method attempts to wait until all the queued events have been sent, but this
+ method will timeout after 30 seconds regardless.</para>
+ <para>
+ If the appender is being closed because the <see cref="E:System.AppDomain.ProcessExit"/>
+ event has fired it may not be possible to send all the queued events. During process
+ exit the runtime limits the time that a <see cref="E:System.AppDomain.ProcessExit"/>
+ event handler is allowed to run for.</para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RemotingAppender.BeginAsyncSend">
+ <summary>
+ A work item is being queued into the thread pool
+ </summary>
+ </member>
+ <member name="M:log4net.Appender.RemotingAppender.EndAsyncSend">
+ <summary>
+ A work item from the thread pool has completed
+ </summary>
+ </member>
+ <member name="M:log4net.Appender.RemotingAppender.SendBufferCallback(System.Object)">
+ <summary>
+ Send the contents of the buffer to the remote sink.
+ </summary>
+ <remarks>
+ This method is designed to be used with the <see cref="T:System.Threading.ThreadPool"/>.
+ This method expects to be passed an array of <see cref="T:log4net.Core.LoggingEvent"/>
+ objects in the state param.
+ </remarks>
+ <param name="state">the logging events to send</param>
+ </member>
+ <member name="F:log4net.Appender.RemotingAppender.m_sinkUrl">
+ <summary>
+ The URL of the remote sink.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemotingAppender.m_sinkObj">
+ <summary>
+ The local proxy (.NET remoting) for the remote logging sink.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemotingAppender.m_queuedCallbackCount">
+ <summary>
+ The number of queued callbacks currently waiting or executing
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RemotingAppender.m_workQueueEmptyEvent">
+ <summary>
+ Event used to signal when there are no queued work items
+ </summary>
+ <remarks>
+ This event is set when there are no queued work items. In this
+ state it is safe to close the appender.
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.RemotingAppender.Sink">
+ <summary>
+ Gets or sets the URL of the well-known object that will accept
+ the logging events.
+ </summary>
+ <value>
+ The well-known URL of the remote sink.
+ </value>
+ <remarks>
+ <para>
+ The URL of the remoting sink that will accept logging events.
+ The sink must implement the <see cref="T:log4net.Appender.RemotingAppender.IRemoteLoggingSink"/>
+ interface.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.RemotingAppender.IRemoteLoggingSink">
+ <summary>
+ Interface used to deliver <see cref="T:log4net.Core.LoggingEvent"/> objects to a remote sink.
+ </summary>
+ <remarks>
+ This interface must be implemented by a remoting sink
+ if the <see cref="T:log4net.Appender.RemotingAppender"/> is to be used
+ to deliver logging events to the sink.
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RemotingAppender.IRemoteLoggingSink.LogEvents(log4net.Core.LoggingEvent[])">
+ <summary>
+ Delivers logging events to the remote sink
+ </summary>
+ <param name="events">Array of events to log.</param>
+ <remarks>
+ <para>
+ Delivers logging events to the remote sink
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.RollingFileAppender">
+ <summary>
+ Appender that rolls log files based on size or date or both.
+ </summary>
+ <remarks>
+ <para>
+ RollingFileAppender can roll log files based on size or date or both
+ depending on the setting of the <see cref="P:log4net.Appender.RollingFileAppender.RollingStyle"/> property.
+ When set to <see cref="F:log4net.Appender.RollingFileAppender.RollingMode.Size"/> the log file will be rolled
+ once its size exceeds the <see cref="P:log4net.Appender.RollingFileAppender.MaximumFileSize"/>.
+ When set to <see cref="F:log4net.Appender.RollingFileAppender.RollingMode.Date"/> the log file will be rolled
+ once the date boundary specified in the <see cref="P:log4net.Appender.RollingFileAppender.DatePattern"/> property
+ is crossed.
+ When set to <see cref="F:log4net.Appender.RollingFileAppender.RollingMode.Composite"/> the log file will be
+ rolled once the date boundary specified in the <see cref="P:log4net.Appender.RollingFileAppender.DatePattern"/> property
+ is crossed, but within a date boundary the file will also be rolled
+ once its size exceeds the <see cref="P:log4net.Appender.RollingFileAppender.MaximumFileSize"/>.
+ When set to <see cref="F:log4net.Appender.RollingFileAppender.RollingMode.Once"/> the log file will be rolled when
+ the appender is configured. This effectively means that the log file can be
+ rolled once per program execution.
+ </para>
+ <para>
+ A of few additional optional features have been added:
+ <list type="bullet">
+ <item>Attach date pattern for current log file <see cref="P:log4net.Appender.RollingFileAppender.StaticLogFileName"/></item>
+ <item>Backup number increments for newer files <see cref="P:log4net.Appender.RollingFileAppender.CountDirection"/></item>
+ <item>Infinite number of backups by file size <see cref="P:log4net.Appender.RollingFileAppender.MaxSizeRollBackups"/></item>
+ </list>
+ </para>
+
+ <note>
+ <para>
+ For large or infinite numbers of backup files a <see cref="P:log4net.Appender.RollingFileAppender.CountDirection"/>
+ greater than zero is highly recommended, otherwise all the backup files need
+ to be renamed each time a new backup is created.
+ </para>
+ <para>
+ When Date/Time based rolling is used setting <see cref="P:log4net.Appender.RollingFileAppender.StaticLogFileName"/>
+ to <see langword="true"/> will reduce the number of file renamings to few or none.
+ </para>
+ </note>
+
+ <note type="caution">
+ <para>
+ Changing <see cref="P:log4net.Appender.RollingFileAppender.StaticLogFileName"/> or <see cref="P:log4net.Appender.RollingFileAppender.CountDirection"/> without clearing
+ the log file directory of backup files will cause unexpected and unwanted side effects.
+ </para>
+ </note>
+
+ <para>
+ If Date/Time based rolling is enabled this appender will attempt to roll existing files
+ in the directory without a Date/Time tag based on the last write date of the base log file.
+ The appender only rolls the log file when a message is logged. If Date/Time based rolling
+ is enabled then the appender will not roll the log file at the Date/Time boundary but
+ at the point when the next message is logged after the boundary has been crossed.
+ </para>
+
+ <para>
+ The <see cref="T:log4net.Appender.RollingFileAppender"/> extends the <see cref="T:log4net.Appender.FileAppender"/> and
+ has the same behavior when opening the log file.
+ The appender will first try to open the file for writing when <see cref="M:log4net.Appender.RollingFileAppender.ActivateOptions"/>
+ is called. This will typically be during configuration.
+ If the file cannot be opened for writing the appender will attempt
+ to open the file again each time a message is logged to the appender.
+ If the file cannot be opened for writing when a message is logged then
+ the message will be discarded by this appender.
+ </para>
+ <para>
+ When rolling a backup file necessitates deleting an older backup file the
+ file to be deleted is moved to a temporary name before being deleted.
+ </para>
+
+ <note type="caution">
+ <para>
+ A maximum number of backup files when rolling on date/time boundaries is not supported.
+ </para>
+ </note>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ <author>Aspi Havewala</author>
+ <author>Douglas de la Torre</author>
+ <author>Edward Smit</author>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.RollingFileAppender"/> class.
+ </summary>
+ <remarks>
+ <para>
+ Default constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.SetQWForFiles(System.IO.TextWriter)">
+ <summary>
+ Sets the quiet writer being used.
+ </summary>
+ <remarks>
+ This method can be overridden by sub classes.
+ </remarks>
+ <param name="writer">the writer to set</param>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.Append(log4net.Core.LoggingEvent)">
+ <summary>
+ Write out a logging event.
+ </summary>
+ <param name="loggingEvent">the event to write to file.</param>
+ <remarks>
+ <para>
+ Handles append time behavior for RollingFileAppender. This checks
+ if a roll over either by date (checked first) or time (checked second)
+ is need and then appends to the file last.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.Append(log4net.Core.LoggingEvent[])">
+ <summary>
+ Write out an array of logging events.
+ </summary>
+ <param name="loggingEvents">the events to write to file.</param>
+ <remarks>
+ <para>
+ Handles append time behavior for RollingFileAppender. This checks
+ if a roll over either by date (checked first) or time (checked second)
+ is need and then appends to the file last.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.AdjustFileBeforeAppend">
+ <summary>
+ Performs any required rolling before outputting the next event
+ </summary>
+ <remarks>
+ <para>
+ Handles append time behavior for RollingFileAppender. This checks
+ if a roll over either by date (checked first) or time (checked second)
+ is need and then appends to the file last.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.OpenFile(System.String,System.Boolean)">
+ <summary>
+ Creates and opens the file for logging. If <see cref="P:log4net.Appender.RollingFileAppender.StaticLogFileName"/>
+ is false then the fully qualified name is determined and used.
+ </summary>
+ <param name="fileName">the name of the file to open</param>
+ <param name="append">true to append to existing file</param>
+ <remarks>
+ <para>This method will ensure that the directory structure
+ for the <paramref name="fileName"/> specified exists.</para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.GetNextOutputFileName(System.String)">
+ <summary>
+ Get the current output file name
+ </summary>
+ <param name="fileName">the base file name</param>
+ <returns>the output file name</returns>
+ <remarks>
+ The output file name is based on the base fileName specified.
+ If <see cref="P:log4net.Appender.RollingFileAppender.StaticLogFileName"/> is set then the output
+ file name is the same as the base file passed in. Otherwise
+ the output file depends on the date pattern, on the count
+ direction or both.
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.DetermineCurSizeRollBackups">
+ <summary>
+ Determines curSizeRollBackups (only within the current roll point)
+ </summary>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.GetWildcardPatternForFile(System.String)">
+ <summary>
+ Generates a wildcard pattern that can be used to find all files
+ that are similar to the base file name.
+ </summary>
+ <param name="baseFileName"></param>
+ <returns></returns>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.GetExistingFiles(System.String)">
+ <summary>
+ Builds a list of filenames for all files matching the base filename plus a file
+ pattern.
+ </summary>
+ <param name="baseFilePath"></param>
+ <returns></returns>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.RollOverIfDateBoundaryCrossing">
+ <summary>
+ Initiates a roll over if needed for crossing a date boundary since the last run.
+ </summary>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.ExistingInit">
+ <summary>
+ Initializes based on existing conditions at time of <see cref="M:log4net.Appender.RollingFileAppender.ActivateOptions"/>.
+ </summary>
+ <remarks>
+ <para>
+ Initializes based on existing conditions at time of <see cref="M:log4net.Appender.RollingFileAppender.ActivateOptions"/>.
+ The following is done
+ <list type="bullet">
+ <item>determine curSizeRollBackups (only within the current roll point)</item>
+ <item>initiates a roll over if needed for crossing a date boundary since the last run.</item>
+ </list>
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.InitializeFromOneFile(System.String,System.String)">
+ <summary>
+ Does the work of bumping the 'current' file counter higher
+ to the highest count when an incremental file name is seen.
+ The highest count is either the first file (when count direction
+ is greater than 0) or the last file (when count direction less than 0).
+ In either case, we want to know the highest count that is present.
+ </summary>
+ <param name="baseFile"></param>
+ <param name="curFileName"></param>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.InitializeRollBackups(System.String,System.Collections.ArrayList)">
+ <summary>
+ Takes a list of files and a base file name, and looks for
+ 'incremented' versions of the base file. Bumps the max
+ count up to the highest count seen.
+ </summary>
+ <param name="baseFile"></param>
+ <param name="arrayFiles"></param>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.ComputeCheckPeriod(System.String)">
+ <summary>
+ Calculates the RollPoint for the datePattern supplied.
+ </summary>
+ <param name="datePattern">the date pattern to calculate the check period for</param>
+ <returns>The RollPoint that is most accurate for the date pattern supplied</returns>
+ <remarks>
+ Essentially the date pattern is examined to determine what the
+ most suitable roll point is. The roll point chosen is the roll point
+ with the smallest period that can be detected using the date pattern
+ supplied. i.e. if the date pattern only outputs the year, month, day
+ and hour then the smallest roll point that can be detected would be
+ and hourly roll point as minutes could not be detected.
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.ActivateOptions">
+ <summary>
+ Initialize the appender based on the options set
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Appender.RollingFileAppender.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Appender.RollingFileAppender.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Appender.RollingFileAppender.ActivateOptions"/> must be called again.
+ </para>
+ <para>
+ Sets initial conditions including date/time roll over information, first check,
+ scheduledFilename, and calls <see cref="M:log4net.Appender.RollingFileAppender.ExistingInit"/> to initialize
+ the current number of backups.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.RollOverTime(System.Boolean)">
+ <summary>
+ Rollover the file(s) to date/time tagged file(s).
+ </summary>
+ <param name="fileIsOpen">set to true if the file to be rolled is currently open</param>
+ <remarks>
+ <para>
+ Rollover the file(s) to date/time tagged file(s).
+ Resets curSizeRollBackups.
+ If fileIsOpen is set then the new file is opened (through SafeOpenFile).
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.RollFile(System.String,System.String)">
+ <summary>
+ Renames file <paramref name="fromFile"/> to file <paramref name="toFile"/>.
+ </summary>
+ <param name="fromFile">Name of existing file to roll.</param>
+ <param name="toFile">New name for file.</param>
+ <remarks>
+ <para>
+ Renames file <paramref name="fromFile"/> to file <paramref name="toFile"/>. It
+ also checks for existence of target file and deletes if it does.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.FileExists(System.String)">
+ <summary>
+ Test if a file exists at a specified path
+ </summary>
+ <param name="path">the path to the file</param>
+ <returns>true if the file exists</returns>
+ <remarks>
+ <para>
+ Test if a file exists at a specified path
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.DeleteFile(System.String)">
+ <summary>
+ Deletes the specified file if it exists.
+ </summary>
+ <param name="fileName">The file to delete.</param>
+ <remarks>
+ <para>
+ Delete a file if is exists.
+ The file is first moved to a new filename then deleted.
+ This allows the file to be removed even when it cannot
+ be deleted, but it still can be moved.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.RollOverSize">
+ <summary>
+ Implements file roll base on file size.
+ </summary>
+ <remarks>
+ <para>
+ If the maximum number of size based backups is reached
+ (<c>curSizeRollBackups == maxSizeRollBackups</c>) then the oldest
+ file is deleted -- its index determined by the sign of countDirection.
+ If <c>countDirection</c> &lt; 0, then files
+ {<c>File.1</c>, ..., <c>File.curSizeRollBackups -1</c>}
+ are renamed to {<c>File.2</c>, ...,
+ <c>File.curSizeRollBackups</c>}. Moreover, <c>File</c> is
+ renamed <c>File.1</c> and closed.
+ </para>
+ <para>
+ A new file is created to receive further log output.
+ </para>
+ <para>
+ If <c>maxSizeRollBackups</c> is equal to zero, then the
+ <c>File</c> is truncated with no backup files created.
+ </para>
+ <para>
+ If <c>maxSizeRollBackups</c> &lt; 0, then <c>File</c> is
+ renamed if needed and no files are deleted.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.RollOverRenameFiles(System.String)">
+ <summary>
+ Implements file roll.
+ </summary>
+ <param name="baseFileName">the base name to rename</param>
+ <remarks>
+ <para>
+ If the maximum number of size based backups is reached
+ (<c>curSizeRollBackups == maxSizeRollBackups</c>) then the oldest
+ file is deleted -- its index determined by the sign of countDirection.
+ If <c>countDirection</c> &lt; 0, then files
+ {<c>File.1</c>, ..., <c>File.curSizeRollBackups -1</c>}
+ are renamed to {<c>File.2</c>, ...,
+ <c>File.curSizeRollBackups</c>}.
+ </para>
+ <para>
+ If <c>maxSizeRollBackups</c> is equal to zero, then the
+ <c>File</c> is truncated with no backup files created.
+ </para>
+ <para>
+ If <c>maxSizeRollBackups</c> &lt; 0, then <c>File</c> is
+ renamed if needed and no files are deleted.
+ </para>
+ <para>
+ This is called by <see cref="M:log4net.Appender.RollingFileAppender.RollOverSize"/> to rename the files.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.RollingFileAppender.NextCheckDate(System.DateTime,log4net.Appender.RollingFileAppender.RollPoint)">
+ <summary>
+ Get the start time of the next window for the current rollpoint
+ </summary>
+ <param name="currentDateTime">the current date</param>
+ <param name="rollPoint">the type of roll point we are working with</param>
+ <returns>the start time for the next roll point an interval after the currentDateTime date</returns>
+ <remarks>
+ <para>
+ Returns the date of the next roll point after the currentDateTime date passed to the method.
+ </para>
+ <para>
+ The basic strategy is to subtract the time parts that are less significant
+ than the rollpoint from the current time. This should roll the time back to
+ the start of the time window for the current rollpoint. Then we add 1 window
+ worth of time and get the start time of the next window for the rollpoint.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.m_dateTime">
+ <summary>
+ This object supplies the current date/time. Allows test code to plug in
+ a method to control this class when testing date/time based rolling.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.m_datePattern">
+ <summary>
+ The date pattern. By default, the pattern is set to <c>".yyyy-MM-dd"</c>
+ meaning daily rollover.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.m_scheduledFilename">
+ <summary>
+ The actual formatted filename that is currently being written to
+ or will be the file transferred to on roll over
+ (based on staticLogFileName).
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.m_nextCheck">
+ <summary>
+ The timestamp when we shall next recompute the filename.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.m_now">
+ <summary>
+ Holds date of last roll over
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.m_rollPoint">
+ <summary>
+ The type of rolling done
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.m_maxFileSize">
+ <summary>
+ The default maximum file size is 10MB
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.m_maxSizeRollBackups">
+ <summary>
+ There is zero backup files by default
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.m_curSizeRollBackups">
+ <summary>
+ How many sized based backups have been made so far
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.m_countDirection">
+ <summary>
+ The rolling file count direction.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.m_rollingStyle">
+ <summary>
+ The rolling mode used in this appender.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.m_rollDate">
+ <summary>
+ Cache flag set if we are rolling by date.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.m_rollSize">
+ <summary>
+ Cache flag set if we are rolling by size.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.m_staticLogFileName">
+ <summary>
+ Value indicating whether to always log to the same file.
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.m_baseFileName">
+ <summary>
+ FileName provided in configuration. Used for rolling properly
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.s_date1970">
+ <summary>
+ The 1st of January 1970 in UTC
+ </summary>
+ </member>
+ <member name="P:log4net.Appender.RollingFileAppender.DatePattern">
+ <summary>
+ Gets or sets the date pattern to be used for generating file names
+ when rolling over on date.
+ </summary>
+ <value>
+ The date pattern to be used for generating file names when rolling
+ over on date.
+ </value>
+ <remarks>
+ <para>
+ Takes a string in the same format as expected by
+ <see cref="T:log4net.DateFormatter.SimpleDateFormatter"/>.
+ </para>
+ <para>
+ This property determines the rollover schedule when rolling over
+ on date.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.RollingFileAppender.MaxSizeRollBackups">
+ <summary>
+ Gets or sets the maximum number of backup files that are kept before
+ the oldest is erased.
+ </summary>
+ <value>
+ The maximum number of backup files that are kept before the oldest is
+ erased.
+ </value>
+ <remarks>
+ <para>
+ If set to zero, then there will be no backup files and the log file
+ will be truncated when it reaches <see cref="P:log4net.Appender.RollingFileAppender.MaxFileSize"/>.
+ </para>
+ <para>
+ If a negative number is supplied then no deletions will be made. Note
+ that this could result in very slow performance as a large number of
+ files are rolled over unless <see cref="P:log4net.Appender.RollingFileAppender.CountDirection"/> is used.
+ </para>
+ <para>
+ The maximum applies to <b>each</b> time based group of files and
+ <b>not</b> the total.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.RollingFileAppender.MaxFileSize">
+ <summary>
+ Gets or sets the maximum size that the output file is allowed to reach
+ before being rolled over to backup files.
+ </summary>
+ <value>
+ The maximum size in bytes that the output file is allowed to reach before being
+ rolled over to backup files.
+ </value>
+ <remarks>
+ <para>
+ This property is equivalent to <see cref="P:log4net.Appender.RollingFileAppender.MaximumFileSize"/> except
+ that it is required for differentiating the setter taking a
+ <see cref="T:System.Int64"/> argument from the setter taking a <see cref="T:System.String"/>
+ argument.
+ </para>
+ <para>
+ The default maximum file size is 10MB (10*1024*1024).
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.RollingFileAppender.MaximumFileSize">
+ <summary>
+ Gets or sets the maximum size that the output file is allowed to reach
+ before being rolled over to backup files.
+ </summary>
+ <value>
+ The maximum size that the output file is allowed to reach before being
+ rolled over to backup files.
+ </value>
+ <remarks>
+ <para>
+ This property allows you to specify the maximum size with the
+ suffixes "KB", "MB" or "GB" so that the size is interpreted being
+ expressed respectively in kilobytes, megabytes or gigabytes.
+ </para>
+ <para>
+ For example, the value "10KB" will be interpreted as 10240 bytes.
+ </para>
+ <para>
+ The default maximum file size is 10MB.
+ </para>
+ <para>
+ If you have the option to set the maximum file size programmatically
+ consider using the <see cref="P:log4net.Appender.RollingFileAppender.MaxFileSize"/> property instead as this
+ allows you to set the size in bytes as a <see cref="T:System.Int64"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.RollingFileAppender.CountDirection">
+ <summary>
+ Gets or sets the rolling file count direction.
+ </summary>
+ <value>
+ The rolling file count direction.
+ </value>
+ <remarks>
+ <para>
+ Indicates if the current file is the lowest numbered file or the
+ highest numbered file.
+ </para>
+ <para>
+ By default newer files have lower numbers (<see cref="P:log4net.Appender.RollingFileAppender.CountDirection"/> &lt; 0),
+ i.e. log.1 is most recent, log.5 is the 5th backup, etc...
+ </para>
+ <para>
+ <see cref="P:log4net.Appender.RollingFileAppender.CountDirection"/> &gt;= 0 does the opposite i.e.
+ log.1 is the first backup made, log.5 is the 5th backup made, etc.
+ For infinite backups use <see cref="P:log4net.Appender.RollingFileAppender.CountDirection"/> &gt;= 0 to reduce
+ rollover costs.
+ </para>
+ <para>The default file count direction is -1.</para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.RollingFileAppender.RollingStyle">
+ <summary>
+ Gets or sets the rolling style.
+ </summary>
+ <value>The rolling style.</value>
+ <remarks>
+ <para>
+ The default rolling style is <see cref="F:log4net.Appender.RollingFileAppender.RollingMode.Composite"/>.
+ </para>
+ <para>
+ When set to <see cref="F:log4net.Appender.RollingFileAppender.RollingMode.Once"/> this appender's
+ <see cref="P:log4net.Appender.FileAppender.AppendToFile"/> property is set to <c>false</c>, otherwise
+ the appender would append to a single file rather than rolling
+ the file each time it is opened.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.RollingFileAppender.StaticLogFileName">
+ <summary>
+ Gets or sets a value indicating whether to always log to
+ the same file.
+ </summary>
+ <value>
+ <c>true</c> if always should be logged to the same file, otherwise <c>false</c>.
+ </value>
+ <remarks>
+ <para>
+ By default file.log is always the current file. Optionally
+ file.log.yyyy-mm-dd for current formatted datePattern can by the currently
+ logging file (or file.log.curSizeRollBackup or even
+ file.log.yyyy-mm-dd.curSizeRollBackup).
+ </para>
+ <para>
+ This will make time based rollovers with a large number of backups
+ much faster as the appender it won't have to rename all the backups!
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.RollingFileAppender.RollingMode">
+ <summary>
+ Style of rolling to use
+ </summary>
+ <remarks>
+ <para>
+ Style of rolling to use
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.RollingMode.Once">
+ <summary>
+ Roll files once per program execution
+ </summary>
+ <remarks>
+ <para>
+ Roll files once per program execution.
+ Well really once each time this appender is
+ configured.
+ </para>
+ <para>
+ Setting this option also sets <c>AppendToFile</c> to
+ <c>false</c> on the <c>RollingFileAppender</c>, otherwise
+ this appender would just be a normal file appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.RollingMode.Size">
+ <summary>
+ Roll files based only on the size of the file
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.RollingMode.Date">
+ <summary>
+ Roll files based only on the date
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.RollingMode.Composite">
+ <summary>
+ Roll files based on both the size and date of the file
+ </summary>
+ </member>
+ <member name="T:log4net.Appender.RollingFileAppender.RollPoint">
+ <summary>
+ The code assumes that the following 'time' constants are in a increasing sequence.
+ </summary>
+ <remarks>
+ <para>
+ The code assumes that the following 'time' constants are in a increasing sequence.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.RollPoint.InvalidRollPoint">
+ <summary>
+ Roll the log not based on the date
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.RollPoint.TopOfMinute">
+ <summary>
+ Roll the log for each minute
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.RollPoint.TopOfHour">
+ <summary>
+ Roll the log for each hour
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.RollPoint.HalfDay">
+ <summary>
+ Roll the log twice a day (midday and midnight)
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.RollPoint.TopOfDay">
+ <summary>
+ Roll the log each day (midnight)
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.RollPoint.TopOfWeek">
+ <summary>
+ Roll the log each week
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.RollingFileAppender.RollPoint.TopOfMonth">
+ <summary>
+ Roll the log each month
+ </summary>
+ </member>
+ <member name="T:log4net.Appender.RollingFileAppender.IDateTime">
+ <summary>
+ This interface is used to supply Date/Time information to the <see cref="T:log4net.Appender.RollingFileAppender"/>.
+ </summary>
+ <remarks>
+ This interface is used to supply Date/Time information to the <see cref="T:log4net.Appender.RollingFileAppender"/>.
+ Used primarily to allow test classes to plug themselves in so they can
+ supply test date/times.
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.RollingFileAppender.IDateTime.Now">
+ <summary>
+ Gets the <i>current</i> time.
+ </summary>
+ <value>The <i>current</i> time.</value>
+ <remarks>
+ <para>
+ Gets the <i>current</i> time.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.RollingFileAppender.DefaultDateTime">
+ <summary>
+ Default implementation of <see cref="T:log4net.Appender.RollingFileAppender.IDateTime"/> that returns the current time.
+ </summary>
+ </member>
+ <member name="P:log4net.Appender.RollingFileAppender.DefaultDateTime.Now">
+ <summary>
+ Gets the <b>current</b> time.
+ </summary>
+ <value>The <b>current</b> time.</value>
+ <remarks>
+ <para>
+ Gets the <b>current</b> time.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.SmtpAppender">
+ <summary>
+ Send an e-mail when a specific logging event occurs, typically on errors
+ or fatal errors.
+ </summary>
+ <remarks>
+ <para>
+ The number of logging events delivered in this e-mail depend on
+ the value of <see cref="P:log4net.Appender.BufferingAppenderSkeleton.BufferSize"/> option. The
+ <see cref="T:log4net.Appender.SmtpAppender"/> keeps only the last
+ <see cref="P:log4net.Appender.BufferingAppenderSkeleton.BufferSize"/> logging events in its
+ cyclic buffer. This keeps memory requirements at a reasonable level while
+ still delivering useful application context.
+ </para>
+ <note type="caution">
+ Authentication and setting the server Port are only available on the MS .NET 1.1 runtime.
+ For these features to be enabled you need to ensure that you are using a version of
+ the log4net assembly that is built against the MS .NET 1.1 framework and that you are
+ running the your application on the MS .NET 1.1 runtime. On all other platforms only sending
+ unauthenticated messages to a server listening on port 25 (the default) is supported.
+ </note>
+ <para>
+ Authentication is supported by setting the <see cref="P:log4net.Appender.SmtpAppender.Authentication"/> property to
+ either <see cref="F:log4net.Appender.SmtpAppender.SmtpAuthentication.Basic"/> or <see cref="F:log4net.Appender.SmtpAppender.SmtpAuthentication.Ntlm"/>.
+ If using <see cref="F:log4net.Appender.SmtpAppender.SmtpAuthentication.Basic"/> authentication then the <see cref="P:log4net.Appender.SmtpAppender.Username"/>
+ and <see cref="P:log4net.Appender.SmtpAppender.Password"/> properties must also be set.
+ </para>
+ <para>
+ To set the SMTP server port use the <see cref="P:log4net.Appender.SmtpAppender.Port"/> property. The default port is 25.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Appender.SmtpAppender.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ <remarks>
+ <para>
+ Default constructor
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.SmtpAppender.SendBuffer(log4net.Core.LoggingEvent[])">
+ <summary>
+ Sends the contents of the cyclic buffer as an e-mail message.
+ </summary>
+ <param name="events">The logging events to send.</param>
+ </member>
+ <member name="M:log4net.Appender.SmtpAppender.SendEmail(System.String)">
+ <summary>
+ Send the email message
+ </summary>
+ <param name="messageBody">the body text to include in the mail</param>
+ </member>
+ <member name="P:log4net.Appender.SmtpAppender.To">
+ <summary>
+ Gets or sets a semicolon-delimited list of recipient e-mail addresses.
+ </summary>
+ <value>
+ A semicolon-delimited list of e-mail addresses.
+ </value>
+ <remarks>
+ <para>
+ A semicolon-delimited list of recipient e-mail addresses.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.SmtpAppender.From">
+ <summary>
+ Gets or sets the e-mail address of the sender.
+ </summary>
+ <value>
+ The e-mail address of the sender.
+ </value>
+ <remarks>
+ <para>
+ The e-mail address of the sender.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.SmtpAppender.Subject">
+ <summary>
+ Gets or sets the subject line of the e-mail message.
+ </summary>
+ <value>
+ The subject line of the e-mail message.
+ </value>
+ <remarks>
+ <para>
+ The subject line of the e-mail message.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.SmtpAppender.SmtpHost">
+ <summary>
+ Gets or sets the name of the SMTP relay mail server to use to send
+ the e-mail messages.
+ </summary>
+ <value>
+ The name of the e-mail relay server. If SmtpServer is not set, the
+ name of the local SMTP server is used.
+ </value>
+ <remarks>
+ <para>
+ The name of the e-mail relay server. If SmtpServer is not set, the
+ name of the local SMTP server is used.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.SmtpAppender.LocationInfo">
+ <summary>
+ Obsolete
+ </summary>
+ <remarks>
+ Use the BufferingAppenderSkeleton Fix methods instead
+ </remarks>
+ <remarks>
+ <para>
+ Obsolete property.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.SmtpAppender.Authentication">
+ <summary>
+ The mode to use to authentication with the SMTP server
+ </summary>
+ <remarks>
+ <note type="caution">Authentication is only available on the MS .NET 1.1 runtime.</note>
+ <para>
+ Valid Authentication mode values are: <see cref="F:log4net.Appender.SmtpAppender.SmtpAuthentication.None"/>,
+ <see cref="F:log4net.Appender.SmtpAppender.SmtpAuthentication.Basic"/>, and <see cref="F:log4net.Appender.SmtpAppender.SmtpAuthentication.Ntlm"/>.
+ The default value is <see cref="F:log4net.Appender.SmtpAppender.SmtpAuthentication.None"/>. When using
+ <see cref="F:log4net.Appender.SmtpAppender.SmtpAuthentication.Basic"/> you must specify the <see cref="P:log4net.Appender.SmtpAppender.Username"/>
+ and <see cref="P:log4net.Appender.SmtpAppender.Password"/> to use to authenticate.
+ When using <see cref="F:log4net.Appender.SmtpAppender.SmtpAuthentication.Ntlm"/> the Windows credentials for the current
+ thread, if impersonating, or the process will be used to authenticate.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.SmtpAppender.Username">
+ <summary>
+ The username to use to authenticate with the SMTP server
+ </summary>
+ <remarks>
+ <note type="caution">Authentication is only available on the MS .NET 1.1 runtime.</note>
+ <para>
+ A <see cref="P:log4net.Appender.SmtpAppender.Username"/> and <see cref="P:log4net.Appender.SmtpAppender.Password"/> must be specified when
+ <see cref="P:log4net.Appender.SmtpAppender.Authentication"/> is set to <see cref="F:log4net.Appender.SmtpAppender.SmtpAuthentication.Basic"/>,
+ otherwise the username will be ignored.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.SmtpAppender.Password">
+ <summary>
+ The password to use to authenticate with the SMTP server
+ </summary>
+ <remarks>
+ <note type="caution">Authentication is only available on the MS .NET 1.1 runtime.</note>
+ <para>
+ A <see cref="P:log4net.Appender.SmtpAppender.Username"/> and <see cref="P:log4net.Appender.SmtpAppender.Password"/> must be specified when
+ <see cref="P:log4net.Appender.SmtpAppender.Authentication"/> is set to <see cref="F:log4net.Appender.SmtpAppender.SmtpAuthentication.Basic"/>,
+ otherwise the password will be ignored.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.SmtpAppender.Port">
+ <summary>
+ The port on which the SMTP server is listening
+ </summary>
+ <remarks>
+ <note type="caution">Server Port is only available on the MS .NET 1.1 runtime.</note>
+ <para>
+ The port on which the SMTP server is listening. The default
+ port is <c>25</c>. The Port can only be changed when running on
+ the MS .NET 1.1 runtime.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.SmtpAppender.Priority">
+ <summary>
+ Gets or sets the priority of the e-mail message
+ </summary>
+ <value>
+ One of the <see cref="T:System.Web.Mail.MailPriority"/> values.
+ </value>
+ <remarks>
+ <para>
+ Sets the priority of the e-mails generated by this
+ appender. The default priority is <see cref="F:System.Web.Mail.MailPriority.Normal"/>.
+ </para>
+ <para>
+ If you are using this appender to report errors then
+ you may want to set the priority to <see cref="F:System.Web.Mail.MailPriority.High"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.SmtpAppender.RequiresLayout">
+ <summary>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </summary>
+ <value><c>true</c></value>
+ <remarks>
+ <para>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.SmtpAppender.SmtpAuthentication">
+ <summary>
+ Values for the <see cref="P:log4net.Appender.SmtpAppender.Authentication"/> property.
+ </summary>
+ <remarks>
+ <para>
+ SMTP authentication modes.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.SmtpAppender.SmtpAuthentication.None">
+ <summary>
+ No authentication
+ </summary>
+ </member>
+ <member name="F:log4net.Appender.SmtpAppender.SmtpAuthentication.Basic">
+ <summary>
+ Basic authentication.
+ </summary>
+ <remarks>
+ Requires a username and password to be supplied
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.SmtpAppender.SmtpAuthentication.Ntlm">
+ <summary>
+ Integrated authentication
+ </summary>
+ <remarks>
+ Uses the Windows credentials from the current thread or process to authenticate.
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.SmtpPickupDirAppender">
+ <summary>
+ Send an email when a specific logging event occurs, typically on errors
+ or fatal errors. Rather than sending via smtp it writes a file into the
+ directory specified by <see cref="P:log4net.Appender.SmtpPickupDirAppender.PickupDir"/>. This allows services such
+ as the IIS SMTP agent to manage sending the messages.
+ </summary>
+ <remarks>
+ <para>
+ The configuration for this appender is identical to that of the <c>SMTPAppender</c>,
+ except that instead of specifying the <c>SMTPAppender.SMTPHost</c> you specify
+ <see cref="P:log4net.Appender.SmtpPickupDirAppender.PickupDir"/>.
+ </para>
+ <para>
+ The number of logging events delivered in this e-mail depend on
+ the value of <see cref="P:log4net.Appender.BufferingAppenderSkeleton.BufferSize"/> option. The
+ <see cref="T:log4net.Appender.SmtpPickupDirAppender"/> keeps only the last
+ <see cref="P:log4net.Appender.BufferingAppenderSkeleton.BufferSize"/> logging events in its
+ cyclic buffer. This keeps memory requirements at a reasonable level while
+ still delivering useful application context.
+ </para>
+ </remarks>
+ <author>Niall Daley</author>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Appender.SmtpPickupDirAppender.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ <remarks>
+ <para>
+ Default constructor
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.SmtpPickupDirAppender.SendBuffer(log4net.Core.LoggingEvent[])">
+ <summary>
+ Sends the contents of the cyclic buffer as an e-mail message.
+ </summary>
+ <param name="events">The logging events to send.</param>
+ <remarks>
+ <para>
+ Sends the contents of the cyclic buffer as an e-mail message.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.SmtpPickupDirAppender.ActivateOptions">
+ <summary>
+ Activate the options on this appender.
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Appender.SmtpPickupDirAppender.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Appender.SmtpPickupDirAppender.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Appender.SmtpPickupDirAppender.ActivateOptions"/> must be called again.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.SmtpPickupDirAppender.ConvertToFullPath(System.String)">
+ <summary>
+ Convert a path into a fully qualified path.
+ </summary>
+ <param name="path">The path to convert.</param>
+ <returns>The fully qualified path.</returns>
+ <remarks>
+ <para>
+ Converts the path specified to a fully
+ qualified path. If the path is relative it is
+ taken as relative from the application base
+ directory.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.SmtpPickupDirAppender.m_securityContext">
+ <summary>
+ The security context to use for privileged calls
+ </summary>
+ </member>
+ <member name="P:log4net.Appender.SmtpPickupDirAppender.To">
+ <summary>
+ Gets or sets a semicolon-delimited list of recipient e-mail addresses.
+ </summary>
+ <value>
+ A semicolon-delimited list of e-mail addresses.
+ </value>
+ <remarks>
+ <para>
+ A semicolon-delimited list of e-mail addresses.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.SmtpPickupDirAppender.From">
+ <summary>
+ Gets or sets the e-mail address of the sender.
+ </summary>
+ <value>
+ The e-mail address of the sender.
+ </value>
+ <remarks>
+ <para>
+ The e-mail address of the sender.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.SmtpPickupDirAppender.Subject">
+ <summary>
+ Gets or sets the subject line of the e-mail message.
+ </summary>
+ <value>
+ The subject line of the e-mail message.
+ </value>
+ <remarks>
+ <para>
+ The subject line of the e-mail message.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.SmtpPickupDirAppender.PickupDir">
+ <summary>
+ Gets or sets the path to write the messages to.
+ </summary>
+ <remarks>
+ <para>
+ Gets or sets the path to write the messages to. This should be the same
+ as that used by the agent sending the messages.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.SmtpPickupDirAppender.SecurityContext">
+ <summary>
+ Gets or sets the <see cref="P:log4net.Appender.SmtpPickupDirAppender.SecurityContext"/> used to write to the pickup directory.
+ </summary>
+ <value>
+ The <see cref="P:log4net.Appender.SmtpPickupDirAppender.SecurityContext"/> used to write to the pickup directory.
+ </value>
+ <remarks>
+ <para>
+ Unless a <see cref="P:log4net.Appender.SmtpPickupDirAppender.SecurityContext"/> specified here for this appender
+ the <see cref="P:log4net.Core.SecurityContextProvider.DefaultProvider"/> is queried for the
+ security context to use. The default behavior is to use the security context
+ of the current thread.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.SmtpPickupDirAppender.RequiresLayout">
+ <summary>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </summary>
+ <value><c>true</c></value>
+ <remarks>
+ <para>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.TelnetAppender">
+ <summary>
+ Appender that allows clients to connect via Telnet to receive log messages
+ </summary>
+ <remarks>
+ <para>
+ The TelnetAppender accepts socket connections and streams logging messages
+ back to the client.
+ The output is provided in a telnet-friendly way so that a log can be monitored
+ over a TCP/IP socket.
+ This allows simple remote monitoring of application logging.
+ </para>
+ <para>
+ The default <see cref="P:log4net.Appender.TelnetAppender.Port"/> is 23 (the telnet port).
+ </para>
+ </remarks>
+ <author>Keith Long</author>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Appender.TelnetAppender.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ <remarks>
+ <para>
+ Default constructor
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TelnetAppender.OnClose">
+ <summary>
+ Overrides the parent method to close the socket handler
+ </summary>
+ <remarks>
+ <para>
+ Closes all the outstanding connections.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TelnetAppender.ActivateOptions">
+ <summary>
+ Initialize the appender based on the options set.
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Appender.TelnetAppender.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Appender.TelnetAppender.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Appender.TelnetAppender.ActivateOptions"/> must be called again.
+ </para>
+ <para>
+ Create the socket handler and wait for connections
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TelnetAppender.Append(log4net.Core.LoggingEvent)">
+ <summary>
+ Writes the logging event to each connected client.
+ </summary>
+ <param name="loggingEvent">The event to log.</param>
+ <remarks>
+ <para>
+ Writes the logging event to each connected client.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.TelnetAppender.Port">
+ <summary>
+ Gets or sets the TCP port number on which this <see cref="T:log4net.Appender.TelnetAppender"/> will listen for connections.
+ </summary>
+ <value>
+ An integer value in the range <see cref="F:System.Net.IPEndPoint.MinPort"/> to <see cref="F:System.Net.IPEndPoint.MaxPort"/>
+ indicating the TCP port number on which this <see cref="T:log4net.Appender.TelnetAppender"/> will listen for connections.
+ </value>
+ <remarks>
+ <para>
+ The default value is 23 (the telnet port).
+ </para>
+ </remarks>
+ <exception cref="T:System.ArgumentOutOfRangeException">The value specified is less than <see cref="F:System.Net.IPEndPoint.MinPort"/>
+ or greater than <see cref="F:System.Net.IPEndPoint.MaxPort"/>.</exception>
+ </member>
+ <member name="P:log4net.Appender.TelnetAppender.RequiresLayout">
+ <summary>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </summary>
+ <value><c>true</c></value>
+ <remarks>
+ <para>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.TelnetAppender.SocketHandler">
+ <summary>
+ Helper class to manage connected clients
+ </summary>
+ <remarks>
+ <para>
+ The SocketHandler class is used to accept connections from
+ clients. It is threaded so that clients can connect/disconnect
+ asynchronously.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TelnetAppender.SocketHandler.#ctor(System.Int32)">
+ <summary>
+ Opens a new server port on <paramref ref="port"/>
+ </summary>
+ <param name="port">the local port to listen on for connections</param>
+ <remarks>
+ <para>
+ Creates a socket handler on the specified local server port.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TelnetAppender.SocketHandler.Send(System.String)">
+ <summary>
+ Sends a string message to each of the connected clients
+ </summary>
+ <param name="message">the text to send</param>
+ <remarks>
+ <para>
+ Sends a string message to each of the connected clients
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TelnetAppender.SocketHandler.AddClient(log4net.Appender.TelnetAppender.SocketHandler.SocketClient)">
+ <summary>
+ Add a client to the internal clients list
+ </summary>
+ <param name="client">client to add</param>
+ </member>
+ <member name="M:log4net.Appender.TelnetAppender.SocketHandler.RemoveClient(log4net.Appender.TelnetAppender.SocketHandler.SocketClient)">
+ <summary>
+ Remove a client from the internal clients list
+ </summary>
+ <param name="client">client to remove</param>
+ </member>
+ <member name="M:log4net.Appender.TelnetAppender.SocketHandler.OnConnect(System.IAsyncResult)">
+ <summary>
+ Callback used to accept a connection on the server socket
+ </summary>
+ <param name="asyncResult">The result of the asynchronous operation</param>
+ <remarks>
+ <para>
+ On connection adds to the list of connections
+ if there are two many open connections you will be disconnected
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TelnetAppender.SocketHandler.Dispose">
+ <summary>
+ Close all network connections
+ </summary>
+ <remarks>
+ <para>
+ Make sure we close all network connections
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.TelnetAppender.SocketHandler.HasConnections">
+ <summary>
+ Test if this handler has active connections
+ </summary>
+ <value>
+ <c>true</c> if this handler has active connections
+ </value>
+ <remarks>
+ <para>
+ This property will be <c>true</c> while this handler has
+ active connections, that is at least one connection that
+ the handler will attempt to send a message to.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.TelnetAppender.SocketHandler.SocketClient">
+ <summary>
+ Class that represents a client connected to this handler
+ </summary>
+ <remarks>
+ <para>
+ Class that represents a client connected to this handler
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TelnetAppender.SocketHandler.SocketClient.#ctor(System.Net.Sockets.Socket)">
+ <summary>
+ Create this <see cref="T:log4net.Appender.TelnetAppender.SocketHandler.SocketClient"/> for the specified <see cref="T:System.Net.Sockets.Socket"/>
+ </summary>
+ <param name="socket">the client's socket</param>
+ <remarks>
+ <para>
+ Opens a stream writer on the socket.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TelnetAppender.SocketHandler.SocketClient.Send(System.String)">
+ <summary>
+ Write a string to the client
+ </summary>
+ <param name="message">string to send</param>
+ <remarks>
+ <para>
+ Write a string to the client
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TelnetAppender.SocketHandler.SocketClient.Dispose">
+ <summary>
+ Cleanup the clients connection
+ </summary>
+ <remarks>
+ <para>
+ Close the socket connection.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Appender.TraceAppender">
+ <summary>
+ Appends log events to the <see cref="T:System.Diagnostics.Trace"/> system.
+ </summary>
+ <remarks>
+ <para>
+ The application configuration file can be used to control what listeners
+ are actually used. See the MSDN documentation for the
+ <see cref="T:System.Diagnostics.Trace"/> class for details on configuring the
+ trace system.
+ </para>
+ <para>
+ Events are written using the <c>System.Diagnostics.Trace.Write(string,string)</c>
+ method. The event's logger name is passed as the value for the category name to the Write method.
+ </para>
+ <para>
+ <b>Compact Framework</b><br/>
+ The Compact Framework does not support the <see cref="T:System.Diagnostics.Trace"/>
+ class for any operation except <c>Assert</c>. When using the Compact Framework this
+ appender will write to the <see cref="T:System.Diagnostics.Debug"/> system rather than
+ the Trace system. This appender will therefore behave like the <see cref="T:log4net.Appender.DebugAppender"/>.
+ </para>
+ </remarks>
+ <author>Douglas de la Torre</author>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Appender.TraceAppender.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.TraceAppender"/>.
+ </summary>
+ <remarks>
+ <para>
+ Default constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TraceAppender.#ctor(log4net.Layout.ILayout)">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Appender.TraceAppender"/>
+ with a specified layout.
+ </summary>
+ <param name="layout">The layout to use with this appender.</param>
+ <remarks>
+ <para>
+ Obsolete constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Appender.TraceAppender.Append(log4net.Core.LoggingEvent)">
+ <summary>
+ Writes the logging event to the <see cref="T:System.Diagnostics.Trace"/> system.
+ </summary>
+ <param name="loggingEvent">The event to log.</param>
+ <remarks>
+ <para>
+ Writes the logging event to the <see cref="T:System.Diagnostics.Trace"/> system.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Appender.TraceAppender.m_immediateFlush">
+ <summary>
+ Immediate flush means that the underlying writer or output stream
+ will be flushed at the end of each append operation.
+ </summary>
+ <remarks>
+ <para>
+ Immediate flush is slower but ensures that each append request is
+ actually written. If <see cref="P:log4net.Appender.TraceAppender.ImmediateFlush"/> is set to
+ <c>false</c>, then there is a good chance that the last few
+ logs events are not actually written to persistent media if and
+ when the application crashes.
+ </para>
+ <para>
+ The default value is <c>true</c>.</para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.TraceAppender.ImmediateFlush">
+ <summary>
+ Gets or sets a value that indicates whether the appender will
+ flush at the end of each write.
+ </summary>
+ <remarks>
+ <para>The default behavior is to flush at the end of each
+ write. If the option is set to<c>false</c>, then the underlying
+ stream can defer writing to physical medium to a later time.
+ </para>
+ <para>
+ Avoiding the flush operation at the end of each append results
+ in a performance gain of 10 to 20 percent. However, there is safety
+ trade-off involved in skipping flushing. Indeed, when flushing is
+ skipped, then it is likely that the last few log events will not
+ be recorded on disk when the application exits. This is a high
+ price to pay even for a 20% performance gain.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Appender.TraceAppender.RequiresLayout">
+ <summary>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </summary>
+ <value><c>true</c></value>
+ <remarks>
+ <para>
+ This appender requires a <see cref="N:log4net.Layout"/> to be set.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Config.AliasDomainAttribute">
+ <summary>
+ Assembly level attribute that specifies a domain to alias to this assembly's repository.
+ </summary>
+ <remarks>
+ <para>
+ <b>AliasDomainAttribute is obsolete. Use AliasRepositoryAttribute instead of AliasDomainAttribute.</b>
+ </para>
+ <para>
+ An assembly's logger repository is defined by its <see cref="T:log4net.Config.DomainAttribute"/>,
+ however this can be overridden by an assembly loaded before the target assembly.
+ </para>
+ <para>
+ An assembly can alias another assembly's domain to its repository by
+ specifying this attribute with the name of the target domain.
+ </para>
+ <para>
+ This attribute can only be specified on the assembly and may be used
+ as many times as necessary to alias all the required domains.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.Config.AliasRepositoryAttribute">
+ <summary>
+ Assembly level attribute that specifies a repository to alias to this assembly's repository.
+ </summary>
+ <remarks>
+ <para>
+ An assembly's logger repository is defined by its <see cref="T:log4net.Config.RepositoryAttribute"/>,
+ however this can be overridden by an assembly loaded before the target assembly.
+ </para>
+ <para>
+ An assembly can alias another assembly's repository to its repository by
+ specifying this attribute with the name of the target repository.
+ </para>
+ <para>
+ This attribute can only be specified on the assembly and may be used
+ as many times as necessary to alias all the required repositories.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Config.AliasRepositoryAttribute.#ctor(System.String)">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Config.AliasRepositoryAttribute"/> class with
+ the specified repository to alias to this assembly's repository.
+ </summary>
+ <param name="name">The repository to alias to this assemby's repository.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Config.AliasRepositoryAttribute"/> class with
+ the specified repository to alias to this assembly's repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Config.AliasRepositoryAttribute.Name">
+ <summary>
+ Gets or sets the repository to alias to this assemby's repository.
+ </summary>
+ <value>
+ The repository to alias to this assemby's repository.
+ </value>
+ <remarks>
+ <para>
+ The name of the repository to alias to this assemby's repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.AliasDomainAttribute.#ctor(System.String)">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Config.AliasDomainAttribute"/> class with
+ the specified domain to alias to this assembly's repository.
+ </summary>
+ <param name="name">The domain to alias to this assemby's repository.</param>
+ <remarks>
+ <para>
+ Obsolete. Use <see cref="T:log4net.Config.AliasRepositoryAttribute"/> instead of <see cref="T:log4net.Config.AliasDomainAttribute"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Config.BasicConfigurator">
+ <summary>
+ Use this class to quickly configure a <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/>.
+ </summary>
+ <remarks>
+ <para>
+ Allows very simple programmatic configuration of log4net.
+ </para>
+ <para>
+ Only one appender can be configured using this configurator.
+ The appender is set at the root of the hierarchy and all logging
+ events will be delivered to that appender.
+ </para>
+ <para>
+ Appenders can also implement the <see cref="T:log4net.Core.IOptionHandler"/> interface. Therefore
+ they would require that the <see cref="M:log4net.Core.IOptionHandler.ActivateOptions"/> method
+ be called after the appenders properties have been configured.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Config.BasicConfigurator.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Config.BasicConfigurator"/> class.
+ </summary>
+ <remarks>
+ <para>
+ Uses a private access modifier to prevent instantiation of this class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.BasicConfigurator.Configure">
+ <summary>
+ Initializes the log4net system with a default configuration.
+ </summary>
+ <remarks>
+ <para>
+ Initializes the log4net logging system using a <see cref="T:log4net.Appender.ConsoleAppender"/>
+ that will write to <c>Console.Out</c>. The log messages are
+ formatted using the <see cref="T:log4net.Layout.PatternLayout"/> layout object
+ with the <see cref="F:log4net.Layout.PatternLayout.DetailConversionPattern"/>
+ layout style.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.BasicConfigurator.Configure(log4net.Appender.IAppender)">
+ <summary>
+ Initializes the log4net system using the specified appender.
+ </summary>
+ <param name="appender">The appender to use to log all logging events.</param>
+ <remarks>
+ <para>
+ Initializes the log4net system using the specified appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.BasicConfigurator.Configure(log4net.Repository.ILoggerRepository)">
+ <summary>
+ Initializes the <see cref="T:log4net.Repository.ILoggerRepository"/> with a default configuration.
+ </summary>
+ <param name="repository">The repository to configure.</param>
+ <remarks>
+ <para>
+ Initializes the specified repository using a <see cref="T:log4net.Appender.ConsoleAppender"/>
+ that will write to <c>Console.Out</c>. The log messages are
+ formatted using the <see cref="T:log4net.Layout.PatternLayout"/> layout object
+ with the <see cref="F:log4net.Layout.PatternLayout.DetailConversionPattern"/>
+ layout style.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.BasicConfigurator.Configure(log4net.Repository.ILoggerRepository,log4net.Appender.IAppender)">
+ <summary>
+ Initializes the <see cref="T:log4net.Repository.ILoggerRepository"/> using the specified appender.
+ </summary>
+ <param name="repository">The repository to configure.</param>
+ <param name="appender">The appender to use to log all logging events.</param>
+ <remarks>
+ <para>
+ Initializes the <see cref="T:log4net.Repository.ILoggerRepository"/> using the specified appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Config.ConfiguratorAttribute">
+ <summary>
+ Base class for all log4net configuration attributes.
+ </summary>
+ <remarks>
+ This is an abstract class that must be extended by
+ specific configurators. This attribute allows the
+ configurator to be parameterized by an assembly level
+ attribute.
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Config.ConfiguratorAttribute.#ctor(System.Int32)">
+ <summary>
+ Constructor used by subclasses.
+ </summary>
+ <param name="priority">the ordering priority for this configurator</param>
+ <remarks>
+ <para>
+ The <paramref name="priority"/> is used to order the configurator
+ attributes before they are invoked. Higher priority configurators are executed
+ before lower priority ones.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.ConfiguratorAttribute.Configure(System.Reflection.Assembly,log4net.Repository.ILoggerRepository)">
+ <summary>
+ Configures the <see cref="T:log4net.Repository.ILoggerRepository"/> for the specified assembly.
+ </summary>
+ <param name="sourceAssembly">The assembly that this attribute was defined on.</param>
+ <param name="targetRepository">The repository to configure.</param>
+ <remarks>
+ <para>
+ Abstract method implemented by a subclass. When this method is called
+ the subclass should configure the <paramref name="targetRepository"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.ConfiguratorAttribute.CompareTo(System.Object)">
+ <summary>
+ Compare this instance to another ConfiguratorAttribute
+ </summary>
+ <param name="obj">the object to compare to</param>
+ <returns>see <see cref="M:System.IComparable.CompareTo(System.Object)"/></returns>
+ <remarks>
+ <para>
+ Compares the priorities of the two <see cref="T:log4net.Config.ConfiguratorAttribute"/> instances.
+ Sorts by priority in descending order. Objects with the same priority are
+ randomly ordered.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Config.DomainAttribute">
+ <summary>
+ Assembly level attribute that specifies the logging domain for the assembly.
+ </summary>
+ <remarks>
+ <para>
+ <b>DomainAttribute is obsolete. Use RepositoryAttribute instead of DomainAttribute.</b>
+ </para>
+ <para>
+ Assemblies are mapped to logging domains. Each domain has its own
+ logging repository. This attribute specified on the assembly controls
+ the configuration of the domain. The <see cref="P:log4net.Config.RepositoryAttribute.Name"/> property specifies the name
+ of the domain that this assembly is a part of. The <see cref="P:log4net.Config.RepositoryAttribute.RepositoryType"/>
+ specifies the type of the repository objects to create for the domain. If
+ this attribute is not specified and a <see cref="P:log4net.Config.RepositoryAttribute.Name"/> is not specified
+ then the assembly will be part of the default shared logging domain.
+ </para>
+ <para>
+ This attribute can only be specified on the assembly and may only be used
+ once per assembly.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.Config.RepositoryAttribute">
+ <summary>
+ Assembly level attribute that specifies the logging repository for the assembly.
+ </summary>
+ <remarks>
+ <para>
+ Assemblies are mapped to logging repository. This attribute specified
+ on the assembly controls
+ the configuration of the repository. The <see cref="P:log4net.Config.RepositoryAttribute.Name"/> property specifies the name
+ of the repository that this assembly is a part of. The <see cref="P:log4net.Config.RepositoryAttribute.RepositoryType"/>
+ specifies the type of the <see cref="T:log4net.Repository.ILoggerRepository"/> object
+ to create for the assembly. If this attribute is not specified or a <see cref="P:log4net.Config.RepositoryAttribute.Name"/>
+ is not specified then the assembly will be part of the default shared logging repository.
+ </para>
+ <para>
+ This attribute can only be specified on the assembly and may only be used
+ once per assembly.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Config.RepositoryAttribute.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Config.RepositoryAttribute"/> class.
+ </summary>
+ <remarks>
+ <para>
+ Default constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.RepositoryAttribute.#ctor(System.String)">
+ <summary>
+ Initialize a new instance of the <see cref="T:log4net.Config.RepositoryAttribute"/> class
+ with the name of the repository.
+ </summary>
+ <param name="name">The name of the repository.</param>
+ <remarks>
+ <para>
+ Initialize the attribute with the name for the assembly's repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Config.RepositoryAttribute.Name">
+ <summary>
+ Gets or sets the name of the logging repository.
+ </summary>
+ <value>
+ The string name to use as the name of the repository associated with this
+ assembly.
+ </value>
+ <remarks>
+ <para>
+ This value does not have to be unique. Several assemblies can share the
+ same repository. They will share the logging configuration of the repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Config.RepositoryAttribute.RepositoryType">
+ <summary>
+ Gets or sets the type of repository to create for this assembly.
+ </summary>
+ <value>
+ The type of repository to create for this assembly.
+ </value>
+ <remarks>
+ <para>
+ The type of the repository to create for the assembly.
+ The type must implement the <see cref="T:log4net.Repository.ILoggerRepository"/>
+ interface.
+ </para>
+ <para>
+ This will be the type of repository created when
+ the repository is created. If multiple assemblies reference the
+ same repository then the repository is only created once using the
+ <see cref="P:log4net.Config.RepositoryAttribute.RepositoryType"/> of the first assembly to call into the
+ repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.DomainAttribute.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Config.DomainAttribute"/> class.
+ </summary>
+ <remarks>
+ <para>
+ Obsolete. Use RepositoryAttribute instead of DomainAttribute.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.DomainAttribute.#ctor(System.String)">
+ <summary>
+ Initialize a new instance of the <see cref="T:log4net.Config.DomainAttribute"/> class
+ with the name of the domain.
+ </summary>
+ <param name="name">The name of the domain.</param>
+ <remarks>
+ <para>
+ Obsolete. Use RepositoryAttribute instead of DomainAttribute.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Config.DOMConfigurator">
+ <summary>
+ Use this class to initialize the log4net environment using an Xml tree.
+ </summary>
+ <remarks>
+ <para>
+ <b>DOMConfigurator is obsolete. Use XmlConfigurator instead of DOMConfigurator.</b>
+ </para>
+ <para>
+ Configures a <see cref="T:log4net.Repository.ILoggerRepository"/> using an Xml tree.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Config.DOMConfigurator.#ctor">
+ <summary>
+ Private constructor
+ </summary>
+ </member>
+ <member name="M:log4net.Config.DOMConfigurator.Configure">
+ <summary>
+ Automatically configures the log4net system based on the
+ application's configuration settings.
+ </summary>
+ <remarks>
+ <para>
+ <b>DOMConfigurator is obsolete. Use XmlConfigurator instead of DOMConfigurator.</b>
+ </para>
+ Each application has a configuration file. This has the
+ same name as the application with '.config' appended.
+ This file is XML and calling this function prompts the
+ configurator to look in that file for a section called
+ <c>log4net</c> that contains the configuration data.
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.DOMConfigurator.Configure(log4net.Repository.ILoggerRepository)">
+ <summary>
+ Automatically configures the <see cref="T:log4net.Repository.ILoggerRepository"/> using settings
+ stored in the application's configuration file.
+ </summary>
+ <remarks>
+ <para>
+ <b>DOMConfigurator is obsolete. Use XmlConfigurator instead of DOMConfigurator.</b>
+ </para>
+ Each application has a configuration file. This has the
+ same name as the application with '.config' appended.
+ This file is XML and calling this function prompts the
+ configurator to look in that file for a section called
+ <c>log4net</c> that contains the configuration data.
+ </remarks>
+ <param name="repository">The repository to configure.</param>
+ </member>
+ <member name="M:log4net.Config.DOMConfigurator.Configure(System.Xml.XmlElement)">
+ <summary>
+ Configures log4net using a <c>log4net</c> element
+ </summary>
+ <remarks>
+ <para>
+ <b>DOMConfigurator is obsolete. Use XmlConfigurator instead of DOMConfigurator.</b>
+ </para>
+ Loads the log4net configuration from the XML element
+ supplied as <paramref name="element"/>.
+ </remarks>
+ <param name="element">The element to parse.</param>
+ </member>
+ <member name="M:log4net.Config.DOMConfigurator.Configure(log4net.Repository.ILoggerRepository,System.Xml.XmlElement)">
+ <summary>
+ Configures the <see cref="T:log4net.Repository.ILoggerRepository"/> using the specified XML
+ element.
+ </summary>
+ <remarks>
+ <para>
+ <b>DOMConfigurator is obsolete. Use XmlConfigurator instead of DOMConfigurator.</b>
+ </para>
+ Loads the log4net configuration from the XML element
+ supplied as <paramref name="element"/>.
+ </remarks>
+ <param name="repository">The repository to configure.</param>
+ <param name="element">The element to parse.</param>
+ </member>
+ <member name="M:log4net.Config.DOMConfigurator.Configure(System.IO.FileInfo)">
+ <summary>
+ Configures log4net using the specified configuration file.
+ </summary>
+ <param name="configFile">The XML file to load the configuration from.</param>
+ <remarks>
+ <para>
+ <b>DOMConfigurator is obsolete. Use XmlConfigurator instead of DOMConfigurator.</b>
+ </para>
+ <para>
+ The configuration file must be valid XML. It must contain
+ at least one element called <c>log4net</c> that holds
+ the log4net configuration data.
+ </para>
+ <para>
+ The log4net configuration file can possible be specified in the application's
+ configuration file (either <c>MyAppName.exe.config</c> for a
+ normal application on <c>Web.config</c> for an ASP.NET application).
+ </para>
+ <example>
+ The following example configures log4net using a configuration file, of which the
+ location is stored in the application's configuration file :
+ </example>
+ <code lang="C#">
+ using log4net.Config;
+ using System.IO;
+ using System.Configuration;
+
+ ...
+
+ DOMConfigurator.Configure(new FileInfo(ConfigurationSettings.AppSettings["log4net-config-file"]));
+ </code>
+ <para>
+ In the <c>.config</c> file, the path to the log4net can be specified like this :
+ </para>
+ <code lang="XML" escaped="true">
+ <configuration>
+ <appSettings>
+ <add key="log4net-config-file" value="log.config"/>
+ </appSettings>
+ </configuration>
+ </code>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.DOMConfigurator.Configure(System.IO.Stream)">
+ <summary>
+ Configures log4net using the specified configuration file.
+ </summary>
+ <param name="configStream">A stream to load the XML configuration from.</param>
+ <remarks>
+ <para>
+ <b>DOMConfigurator is obsolete. Use XmlConfigurator instead of DOMConfigurator.</b>
+ </para>
+ <para>
+ The configuration data must be valid XML. It must contain
+ at least one element called <c>log4net</c> that holds
+ the log4net configuration data.
+ </para>
+ <para>
+ Note that this method will NOT close the stream parameter.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.DOMConfigurator.Configure(log4net.Repository.ILoggerRepository,System.IO.FileInfo)">
+ <summary>
+ Configures the <see cref="T:log4net.Repository.ILoggerRepository"/> using the specified configuration
+ file.
+ </summary>
+ <param name="repository">The repository to configure.</param>
+ <param name="configFile">The XML file to load the configuration from.</param>
+ <remarks>
+ <para>
+ <b>DOMConfigurator is obsolete. Use XmlConfigurator instead of DOMConfigurator.</b>
+ </para>
+ <para>
+ The configuration file must be valid XML. It must contain
+ at least one element called <c>log4net</c> that holds
+ the configuration data.
+ </para>
+ <para>
+ The log4net configuration file can possible be specified in the application's
+ configuration file (either <c>MyAppName.exe.config</c> for a
+ normal application on <c>Web.config</c> for an ASP.NET application).
+ </para>
+ <example>
+ The following example configures log4net using a configuration file, of which the
+ location is stored in the application's configuration file :
+ </example>
+ <code lang="C#">
+ using log4net.Config;
+ using System.IO;
+ using System.Configuration;
+
+ ...
+
+ DOMConfigurator.Configure(new FileInfo(ConfigurationSettings.AppSettings["log4net-config-file"]));
+ </code>
+ <para>
+ In the <c>.config</c> file, the path to the log4net can be specified like this :
+ </para>
+ <code lang="XML" escaped="true">
+ <configuration>
+ <appSettings>
+ <add key="log4net-config-file" value="log.config"/>
+ </appSettings>
+ </configuration>
+ </code>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.DOMConfigurator.Configure(log4net.Repository.ILoggerRepository,System.IO.Stream)">
+ <summary>
+ Configures the <see cref="T:log4net.Repository.ILoggerRepository"/> using the specified configuration
+ file.
+ </summary>
+ <param name="repository">The repository to configure.</param>
+ <param name="configStream">The stream to load the XML configuration from.</param>
+ <remarks>
+ <para>
+ <b>DOMConfigurator is obsolete. Use XmlConfigurator instead of DOMConfigurator.</b>
+ </para>
+ <para>
+ The configuration data must be valid XML. It must contain
+ at least one element called <c>log4net</c> that holds
+ the configuration data.
+ </para>
+ <para>
+ Note that this method will NOT close the stream parameter.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.DOMConfigurator.ConfigureAndWatch(System.IO.FileInfo)">
+ <summary>
+ Configures log4net using the file specified, monitors the file for changes
+ and reloads the configuration if a change is detected.
+ </summary>
+ <param name="configFile">The XML file to load the configuration from.</param>
+ <remarks>
+ <para>
+ <b>DOMConfigurator is obsolete. Use XmlConfigurator instead of DOMConfigurator.</b>
+ </para>
+ <para>
+ The configuration file must be valid XML. It must contain
+ at least one element called <c>log4net</c> that holds
+ the configuration data.
+ </para>
+ <para>
+ The configuration file will be monitored using a <see cref="T:System.IO.FileSystemWatcher"/>
+ and depends on the behavior of that class.
+ </para>
+ <para>
+ For more information on how to configure log4net using
+ a separate configuration file, see <see cref="M:log4net.Config.DOMConfigurator.Configure(System.IO.FileInfo)"/>.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.Config.DOMConfigurator.Configure(System.IO.FileInfo)"/>
+ </member>
+ <member name="M:log4net.Config.DOMConfigurator.ConfigureAndWatch(log4net.Repository.ILoggerRepository,System.IO.FileInfo)">
+ <summary>
+ Configures the <see cref="T:log4net.Repository.ILoggerRepository"/> using the file specified,
+ monitors the file for changes and reloads the configuration if a change
+ is detected.
+ </summary>
+ <param name="repository">The repository to configure.</param>
+ <param name="configFile">The XML file to load the configuration from.</param>
+ <remarks>
+ <para>
+ <b>DOMConfigurator is obsolete. Use XmlConfigurator instead of DOMConfigurator.</b>
+ </para>
+ <para>
+ The configuration file must be valid XML. It must contain
+ at least one element called <c>log4net</c> that holds
+ the configuration data.
+ </para>
+ <para>
+ The configuration file will be monitored using a <see cref="T:System.IO.FileSystemWatcher"/>
+ and depends on the behavior of that class.
+ </para>
+ <para>
+ For more information on how to configure log4net using
+ a separate configuration file, see <see cref="M:log4net.Config.DOMConfigurator.Configure(System.IO.FileInfo)"/>.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.Config.DOMConfigurator.Configure(System.IO.FileInfo)"/>
+ </member>
+ <member name="T:log4net.Config.DOMConfiguratorAttribute">
+ <summary>
+ Assembly level attribute to configure the <see cref="T:log4net.Config.XmlConfigurator"/>.
+ </summary>
+ <remarks>
+ <para>
+ <b>AliasDomainAttribute is obsolete. Use AliasRepositoryAttribute instead of AliasDomainAttribute.</b>
+ </para>
+ <para>
+ This attribute may only be used at the assembly scope and can only
+ be used once per assembly.
+ </para>
+ <para>
+ Use this attribute to configure the <see cref="T:log4net.Config.XmlConfigurator"/>
+ without calling one of the <see cref="M:log4net.Config.XmlConfigurator.Configure"/>
+ methods.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.Config.XmlConfiguratorAttribute">
+ <summary>
+ Assembly level attribute to configure the <see cref="T:log4net.Config.XmlConfigurator"/>.
+ </summary>
+ <remarks>
+ <para>
+ This attribute may only be used at the assembly scope and can only
+ be used once per assembly.
+ </para>
+ <para>
+ Use this attribute to configure the <see cref="T:log4net.Config.XmlConfigurator"/>
+ without calling one of the <see cref="M:log4net.Config.XmlConfigurator.Configure"/>
+ methods.
+ </para>
+ <para>
+ If neither of the <see cref="P:log4net.Config.XmlConfiguratorAttribute.ConfigFile"/> or <see cref="P:log4net.Config.XmlConfiguratorAttribute.ConfigFileExtension"/>
+ properties are set the configuration is loaded from the application's .config file.
+ If set the <see cref="P:log4net.Config.XmlConfiguratorAttribute.ConfigFile"/> property takes priority over the
+ <see cref="P:log4net.Config.XmlConfiguratorAttribute.ConfigFileExtension"/> property. The <see cref="P:log4net.Config.XmlConfiguratorAttribute.ConfigFile"/> property
+ specifies a path to a file to load the config from. The path is relative to the
+ application's base directory; <see cref="P:System.AppDomain.BaseDirectory"/>.
+ The <see cref="P:log4net.Config.XmlConfiguratorAttribute.ConfigFileExtension"/> property is used as a postfix to the assembly file name.
+ The config file must be located in the application's base directory; <see cref="P:System.AppDomain.BaseDirectory"/>.
+ For example in a console application setting the <see cref="P:log4net.Config.XmlConfiguratorAttribute.ConfigFileExtension"/> to
+ <c>config</c> has the same effect as not specifying the <see cref="P:log4net.Config.XmlConfiguratorAttribute.ConfigFile"/> or
+ <see cref="P:log4net.Config.XmlConfiguratorAttribute.ConfigFileExtension"/> properties.
+ </para>
+ <para>
+ The <see cref="P:log4net.Config.XmlConfiguratorAttribute.Watch"/> property can be set to cause the <see cref="T:log4net.Config.XmlConfigurator"/>
+ to watch the configuration file for changes.
+ </para>
+ <note>
+ <para>
+ Log4net will only look for assembly level configuration attributes once.
+ When using the log4net assembly level attributes to control the configuration
+ of log4net you must ensure that the first call to any of the
+ <see cref="T:log4net.Core.LoggerManager"/> methods is made from the assembly with the configuration
+ attributes.
+ </para>
+ <para>
+ If you cannot guarantee the order in which log4net calls will be made from
+ different assemblies you must use programmatic configuration instead, i.e.
+ call the <see cref="M:log4net.Config.XmlConfigurator.Configure"/> method directly.
+ </para>
+ </note>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Config.XmlConfiguratorAttribute.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ <remarks>
+ <para>
+ Default constructor
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.XmlConfiguratorAttribute.Configure(System.Reflection.Assembly,log4net.Repository.ILoggerRepository)">
+ <summary>
+ Configures the <see cref="T:log4net.Repository.ILoggerRepository"/> for the specified assembly.
+ </summary>
+ <param name="sourceAssembly">The assembly that this attribute was defined on.</param>
+ <param name="targetRepository">The repository to configure.</param>
+ <remarks>
+ <para>
+ Configure the repository using the <see cref="T:log4net.Config.XmlConfigurator"/>.
+ The <paramref name="targetRepository"/> specified must extend the <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/>
+ class otherwise the <see cref="T:log4net.Config.XmlConfigurator"/> will not be able to
+ configure it.
+ </para>
+ </remarks>
+ <exception cref="T:System.ArgumentOutOfRangeException">The <paramref name="repository"/> does not extend <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/>.</exception>
+ </member>
+ <member name="M:log4net.Config.XmlConfiguratorAttribute.ConfigureFromFile(System.Reflection.Assembly,log4net.Repository.ILoggerRepository)">
+ <summary>
+ Attempt to load configuration from the local file system
+ </summary>
+ <param name="sourceAssembly">The assembly that this attribute was defined on.</param>
+ <param name="targetRepository">The repository to configure.</param>
+ </member>
+ <member name="M:log4net.Config.XmlConfiguratorAttribute.ConfigureFromFile(log4net.Repository.ILoggerRepository,System.IO.FileInfo)">
+ <summary>
+ Configure the specified repository using a <see cref="T:System.IO.FileInfo"/>
+ </summary>
+ <param name="targetRepository">The repository to configure.</param>
+ <param name="configFile">the FileInfo pointing to the config file</param>
+ </member>
+ <member name="M:log4net.Config.XmlConfiguratorAttribute.ConfigureFromUri(System.Reflection.Assembly,log4net.Repository.ILoggerRepository)">
+ <summary>
+ Attempt to load configuration from a URI
+ </summary>
+ <param name="sourceAssembly">The assembly that this attribute was defined on.</param>
+ <param name="targetRepository">The repository to configure.</param>
+ </member>
+ <member name="P:log4net.Config.XmlConfiguratorAttribute.ConfigFile">
+ <summary>
+ Gets or sets the filename of the configuration file.
+ </summary>
+ <value>
+ The filename of the configuration file.
+ </value>
+ <remarks>
+ <para>
+ If specified, this is the name of the configuration file to use with
+ the <see cref="T:log4net.Config.XmlConfigurator"/>. This file path is relative to the
+ <b>application base</b> directory (<see cref="P:System.AppDomain.BaseDirectory"/>).
+ </para>
+ <para>
+ The <see cref="P:log4net.Config.XmlConfiguratorAttribute.ConfigFile"/> takes priority over the <see cref="P:log4net.Config.XmlConfiguratorAttribute.ConfigFileExtension"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Config.XmlConfiguratorAttribute.ConfigFileExtension">
+ <summary>
+ Gets or sets the extension of the configuration file.
+ </summary>
+ <value>
+ The extension of the configuration file.
+ </value>
+ <remarks>
+ <para>
+ If specified this is the extension for the configuration file.
+ The path to the config file is built by using the <b>application
+ base</b> directory (<see cref="P:System.AppDomain.BaseDirectory"/>),
+ the <b>assembly file name</b> and the config file extension.
+ </para>
+ <para>
+ If the <see cref="P:log4net.Config.XmlConfiguratorAttribute.ConfigFileExtension"/> is set to <c>MyExt</c> then
+ possible config file names would be: <c>MyConsoleApp.exe.MyExt</c> or
+ <c>MyClassLibrary.dll.MyExt</c>.
+ </para>
+ <para>
+ The <see cref="P:log4net.Config.XmlConfiguratorAttribute.ConfigFile"/> takes priority over the <see cref="P:log4net.Config.XmlConfiguratorAttribute.ConfigFileExtension"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Config.XmlConfiguratorAttribute.Watch">
+ <summary>
+ Gets or sets a value indicating whether to watch the configuration file.
+ </summary>
+ <value>
+ <c>true</c> if the configuration should be watched, <c>false</c> otherwise.
+ </value>
+ <remarks>
+ <para>
+ If this flag is specified and set to <c>true</c> then the framework
+ will watch the configuration file and will reload the config each time
+ the file is modified.
+ </para>
+ <para>
+ The config file can only be watched if it is loaded from local disk.
+ In a No-Touch (Smart Client) deployment where the application is downloaded
+ from a web server the config file may not reside on the local disk
+ and therefore it may not be able to watch it.
+ </para>
+ <note>
+ Watching configuration is not supported on the SSCLI.
+ </note>
+ </remarks>
+ </member>
+ <member name="T:log4net.Config.Log4NetConfigurationSectionHandler">
+ <summary>
+ Class to register for the log4net section of the configuration file
+ </summary>
+ <remarks>
+ The log4net section of the configuration file needs to have a section
+ handler registered. This is the section handler used. It simply returns
+ the XML element that is the root of the section.
+ </remarks>
+ <example>
+ Example of registering the log4net section handler :
+ <code lang="XML" escaped="true">
+ <configuration>
+ <configSections>
+ <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
+ </configSections>
+ <log4net>
+ log4net configuration XML goes here
+ </log4net>
+ </configuration>
+ </code>
+ </example>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Config.Log4NetConfigurationSectionHandler.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Config.Log4NetConfigurationSectionHandler"/> class.
+ </summary>
+ <remarks>
+ <para>
+ Default constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.Log4NetConfigurationSectionHandler.Create(System.Object,System.Object,System.Xml.XmlNode)">
+ <summary>
+ Parses the configuration section.
+ </summary>
+ <param name="parent">The configuration settings in a corresponding parent configuration section.</param>
+ <param name="configContext">The configuration context when called from the ASP.NET configuration system. Otherwise, this parameter is reserved and is a null reference.</param>
+ <param name="section">The <see cref="T:System.Xml.XmlNode"/> for the log4net section.</param>
+ <returns>The <see cref="T:System.Xml.XmlNode"/> for the log4net section.</returns>
+ <remarks>
+ <para>
+ Returns the <see cref="T:System.Xml.XmlNode"/> containing the configuration data,
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Config.PluginAttribute">
+ <summary>
+ Assembly level attribute that specifies a plugin to attach to
+ the repository.
+ </summary>
+ <remarks>
+ <para>
+ Specifies the type of a plugin to create and attach to the
+ assembly's repository. The plugin type must implement the
+ <see cref="T:log4net.Plugin.IPlugin"/> interface.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.Plugin.IPluginFactory">
+ <summary>
+ Interface used to create plugins.
+ </summary>
+ <remarks>
+ <para>
+ Interface used to create a plugin.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Plugin.IPluginFactory.CreatePlugin">
+ <summary>
+ Creates the plugin object.
+ </summary>
+ <returns>the new plugin instance</returns>
+ <remarks>
+ <para>
+ Create and return a new plugin instance.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.PluginAttribute.#ctor(System.String)">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Config.PluginAttribute"/> class
+ with the specified type.
+ </summary>
+ <param name="typeName">The type name of plugin to create.</param>
+ <remarks>
+ <para>
+ Create the attribute with the plugin type specified.
+ </para>
+ <para>
+ Where possible use the constructor that takes a <see cref="T:System.Type"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.PluginAttribute.#ctor(System.Type)">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Config.PluginAttribute"/> class
+ with the specified type.
+ </summary>
+ <param name="type">The type of plugin to create.</param>
+ <remarks>
+ <para>
+ Create the attribute with the plugin type specified.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.PluginAttribute.CreatePlugin">
+ <summary>
+ Creates the plugin object defined by this attribute.
+ </summary>
+ <remarks>
+ <para>
+ Creates the instance of the <see cref="T:log4net.Plugin.IPlugin"/> object as
+ specified by this attribute.
+ </para>
+ </remarks>
+ <returns>The plugin object.</returns>
+ </member>
+ <member name="M:log4net.Config.PluginAttribute.ToString">
+ <summary>
+ Returns a representation of the properties of this object.
+ </summary>
+ <remarks>
+ <para>
+ Overrides base class <see cref="M:System.Object.ToString"/> method to
+ return a representation of the properties of this object.
+ </para>
+ </remarks>
+ <returns>A representation of the properties of this object</returns>
+ </member>
+ <member name="P:log4net.Config.PluginAttribute.Type">
+ <summary>
+ Gets or sets the type for the plugin.
+ </summary>
+ <value>
+ The type for the plugin.
+ </value>
+ <remarks>
+ <para>
+ The type for the plugin.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Config.PluginAttribute.TypeName">
+ <summary>
+ Gets or sets the type name for the plugin.
+ </summary>
+ <value>
+ The type name for the plugin.
+ </value>
+ <remarks>
+ <para>
+ The type name for the plugin.
+ </para>
+ <para>
+ Where possible use the <see cref="P:log4net.Config.PluginAttribute.Type"/> property instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Config.SecurityContextProviderAttribute">
+ <summary>
+ Assembly level attribute to configure the <see cref="T:log4net.Core.SecurityContextProvider"/>.
+ </summary>
+ <remarks>
+ <para>
+ This attribute may only be used at the assembly scope and can only
+ be used once per assembly.
+ </para>
+ <para>
+ Use this attribute to configure the <see cref="T:log4net.Config.XmlConfigurator"/>
+ without calling one of the <see cref="M:log4net.Config.XmlConfigurator.Configure"/>
+ methods.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Config.SecurityContextProviderAttribute.#ctor(System.Type)">
+ <summary>
+ Construct provider attribute with type specified
+ </summary>
+ <param name="providerType">the type of the provider to use</param>
+ <remarks>
+ <para>
+ The provider specified must subclass the <see cref="T:log4net.Core.SecurityContextProvider"/>
+ class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.SecurityContextProviderAttribute.Configure(System.Reflection.Assembly,log4net.Repository.ILoggerRepository)">
+ <summary>
+ Configures the SecurityContextProvider
+ </summary>
+ <param name="sourceAssembly">The assembly that this attribute was defined on.</param>
+ <param name="targetRepository">The repository to configure.</param>
+ <remarks>
+ <para>
+ Creates a provider instance from the <see cref="P:log4net.Config.SecurityContextProviderAttribute.ProviderType"/> specified.
+ Sets this as the default security context provider <see cref="P:log4net.Core.SecurityContextProvider.DefaultProvider"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Config.SecurityContextProviderAttribute.ProviderType">
+ <summary>
+ Gets or sets the type of the provider to use.
+ </summary>
+ <value>
+ the type of the provider to use.
+ </value>
+ <remarks>
+ <para>
+ The provider specified must subclass the <see cref="T:log4net.Core.SecurityContextProvider"/>
+ class.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Config.XmlConfigurator">
+ <summary>
+ Use this class to initialize the log4net environment using an Xml tree.
+ </summary>
+ <remarks>
+ <para>
+ Configures a <see cref="T:log4net.Repository.ILoggerRepository"/> using an Xml tree.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Config.XmlConfigurator.#ctor">
+ <summary>
+ Private constructor
+ </summary>
+ </member>
+ <member name="M:log4net.Config.XmlConfigurator.Configure">
+ <summary>
+ Automatically configures the log4net system based on the
+ application's configuration settings.
+ </summary>
+ <remarks>
+ <para>
+ Each application has a configuration file. This has the
+ same name as the application with '.config' appended.
+ This file is XML and calling this function prompts the
+ configurator to look in that file for a section called
+ <c>log4net</c> that contains the configuration data.
+ </para>
+ <para>
+ To use this method to configure log4net you must specify
+ the <see cref="T:log4net.Config.Log4NetConfigurationSectionHandler"/> section
+ handler for the <c>log4net</c> configuration section. See the
+ <see cref="T:log4net.Config.Log4NetConfigurationSectionHandler"/> for an example.
+ </para>
+ </remarks>
+ <seealso cref="T:log4net.Config.Log4NetConfigurationSectionHandler"/>
+ </member>
+ <member name="M:log4net.Config.XmlConfigurator.Configure(log4net.Repository.ILoggerRepository)">
+ <summary>
+ Automatically configures the <see cref="T:log4net.Repository.ILoggerRepository"/> using settings
+ stored in the application's configuration file.
+ </summary>
+ <remarks>
+ <para>
+ Each application has a configuration file. This has the
+ same name as the application with '.config' appended.
+ This file is XML and calling this function prompts the
+ configurator to look in that file for a section called
+ <c>log4net</c> that contains the configuration data.
+ </para>
+ <para>
+ To use this method to configure log4net you must specify
+ the <see cref="T:log4net.Config.Log4NetConfigurationSectionHandler"/> section
+ handler for the <c>log4net</c> configuration section. See the
+ <see cref="T:log4net.Config.Log4NetConfigurationSectionHandler"/> for an example.
+ </para>
+ </remarks>
+ <param name="repository">The repository to configure.</param>
+ </member>
+ <member name="M:log4net.Config.XmlConfigurator.Configure(System.Xml.XmlElement)">
+ <summary>
+ Configures log4net using a <c>log4net</c> element
+ </summary>
+ <remarks>
+ <para>
+ Loads the log4net configuration from the XML element
+ supplied as <paramref name="element"/>.
+ </para>
+ </remarks>
+ <param name="element">The element to parse.</param>
+ </member>
+ <member name="M:log4net.Config.XmlConfigurator.Configure(log4net.Repository.ILoggerRepository,System.Xml.XmlElement)">
+ <summary>
+ Configures the <see cref="T:log4net.Repository.ILoggerRepository"/> using the specified XML
+ element.
+ </summary>
+ <remarks>
+ Loads the log4net configuration from the XML element
+ supplied as <paramref name="element"/>.
+ </remarks>
+ <param name="repository">The repository to configure.</param>
+ <param name="element">The element to parse.</param>
+ </member>
+ <member name="M:log4net.Config.XmlConfigurator.Configure(System.IO.FileInfo)">
+ <summary>
+ Configures log4net using the specified configuration file.
+ </summary>
+ <param name="configFile">The XML file to load the configuration from.</param>
+ <remarks>
+ <para>
+ The configuration file must be valid XML. It must contain
+ at least one element called <c>log4net</c> that holds
+ the log4net configuration data.
+ </para>
+ <para>
+ The log4net configuration file can possible be specified in the application's
+ configuration file (either <c>MyAppName.exe.config</c> for a
+ normal application on <c>Web.config</c> for an ASP.NET application).
+ </para>
+ <para>
+ The first element matching <c>&lt;configuration&gt;</c> will be read as the
+ configuration. If this file is also a .NET .config file then you must specify
+ a configuration section for the <c>log4net</c> element otherwise .NET will
+ complain. Set the type for the section handler to <see cref="T:System.Configuration.IgnoreSectionHandler"/>, for example:
+ <code lang="XML" escaped="true">
+ <configSections>
+ <section name="log4net" type="System.Configuration.IgnoreSectionHandler"/>
+ </configSections>
+ </code>
+ </para>
+ <example>
+ The following example configures log4net using a configuration file, of which the
+ location is stored in the application's configuration file :
+ </example>
+ <code lang="C#">
+ using log4net.Config;
+ using System.IO;
+ using System.Configuration;
+
+ ...
+
+ XmlConfigurator.Configure(new FileInfo(ConfigurationSettings.AppSettings["log4net-config-file"]));
+ </code>
+ <para>
+ In the <c>.config</c> file, the path to the log4net can be specified like this :
+ </para>
+ <code lang="XML" escaped="true">
+ <configuration>
+ <appSettings>
+ <add key="log4net-config-file" value="log.config"/>
+ </appSettings>
+ </configuration>
+ </code>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.XmlConfigurator.Configure(System.Uri)">
+ <summary>
+ Configures log4net using the specified configuration URI.
+ </summary>
+ <param name="configUri">A URI to load the XML configuration from.</param>
+ <remarks>
+ <para>
+ The configuration data must be valid XML. It must contain
+ at least one element called <c>log4net</c> that holds
+ the log4net configuration data.
+ </para>
+ <para>
+ The <see cref="T:System.Net.WebRequest"/> must support the URI scheme specified.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.XmlConfigurator.Configure(System.IO.Stream)">
+ <summary>
+ Configures log4net using the specified configuration data stream.
+ </summary>
+ <param name="configStream">A stream to load the XML configuration from.</param>
+ <remarks>
+ <para>
+ The configuration data must be valid XML. It must contain
+ at least one element called <c>log4net</c> that holds
+ the log4net configuration data.
+ </para>
+ <para>
+ Note that this method will NOT close the stream parameter.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.XmlConfigurator.Configure(log4net.Repository.ILoggerRepository,System.IO.FileInfo)">
+ <summary>
+ Configures the <see cref="T:log4net.Repository.ILoggerRepository"/> using the specified configuration
+ file.
+ </summary>
+ <param name="repository">The repository to configure.</param>
+ <param name="configFile">The XML file to load the configuration from.</param>
+ <remarks>
+ <para>
+ The configuration file must be valid XML. It must contain
+ at least one element called <c>log4net</c> that holds
+ the configuration data.
+ </para>
+ <para>
+ The log4net configuration file can possible be specified in the application's
+ configuration file (either <c>MyAppName.exe.config</c> for a
+ normal application on <c>Web.config</c> for an ASP.NET application).
+ </para>
+ <para>
+ The first element matching <c>&lt;configuration&gt;</c> will be read as the
+ configuration. If this file is also a .NET .config file then you must specify
+ a configuration section for the <c>log4net</c> element otherwise .NET will
+ complain. Set the type for the section handler to <see cref="T:System.Configuration.IgnoreSectionHandler"/>, for example:
+ <code lang="XML" escaped="true">
+ <configSections>
+ <section name="log4net" type="System.Configuration.IgnoreSectionHandler"/>
+ </configSections>
+ </code>
+ </para>
+ <example>
+ The following example configures log4net using a configuration file, of which the
+ location is stored in the application's configuration file :
+ </example>
+ <code lang="C#">
+ using log4net.Config;
+ using System.IO;
+ using System.Configuration;
+
+ ...
+
+ XmlConfigurator.Configure(new FileInfo(ConfigurationSettings.AppSettings["log4net-config-file"]));
+ </code>
+ <para>
+ In the <c>.config</c> file, the path to the log4net can be specified like this :
+ </para>
+ <code lang="XML" escaped="true">
+ <configuration>
+ <appSettings>
+ <add key="log4net-config-file" value="log.config"/>
+ </appSettings>
+ </configuration>
+ </code>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.XmlConfigurator.Configure(log4net.Repository.ILoggerRepository,System.Uri)">
+ <summary>
+ Configures the <see cref="T:log4net.Repository.ILoggerRepository"/> using the specified configuration
+ URI.
+ </summary>
+ <param name="repository">The repository to configure.</param>
+ <param name="configUri">A URI to load the XML configuration from.</param>
+ <remarks>
+ <para>
+ The configuration data must be valid XML. It must contain
+ at least one element called <c>log4net</c> that holds
+ the configuration data.
+ </para>
+ <para>
+ The <see cref="T:System.Net.WebRequest"/> must support the URI scheme specified.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.XmlConfigurator.Configure(log4net.Repository.ILoggerRepository,System.IO.Stream)">
+ <summary>
+ Configures the <see cref="T:log4net.Repository.ILoggerRepository"/> using the specified configuration
+ file.
+ </summary>
+ <param name="repository">The repository to configure.</param>
+ <param name="configStream">The stream to load the XML configuration from.</param>
+ <remarks>
+ <para>
+ The configuration data must be valid XML. It must contain
+ at least one element called <c>log4net</c> that holds
+ the configuration data.
+ </para>
+ <para>
+ Note that this method will NOT close the stream parameter.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.XmlConfigurator.ConfigureAndWatch(System.IO.FileInfo)">
+ <summary>
+ Configures log4net using the file specified, monitors the file for changes
+ and reloads the configuration if a change is detected.
+ </summary>
+ <param name="configFile">The XML file to load the configuration from.</param>
+ <remarks>
+ <para>
+ The configuration file must be valid XML. It must contain
+ at least one element called <c>log4net</c> that holds
+ the configuration data.
+ </para>
+ <para>
+ The configuration file will be monitored using a <see cref="T:System.IO.FileSystemWatcher"/>
+ and depends on the behavior of that class.
+ </para>
+ <para>
+ For more information on how to configure log4net using
+ a separate configuration file, see <see cref="M:log4net.Config.XmlConfigurator.Configure(System.IO.FileInfo)"/>.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.Config.XmlConfigurator.Configure(System.IO.FileInfo)"/>
+ </member>
+ <member name="M:log4net.Config.XmlConfigurator.ConfigureAndWatch(log4net.Repository.ILoggerRepository,System.IO.FileInfo)">
+ <summary>
+ Configures the <see cref="T:log4net.Repository.ILoggerRepository"/> using the file specified,
+ monitors the file for changes and reloads the configuration if a change
+ is detected.
+ </summary>
+ <param name="repository">The repository to configure.</param>
+ <param name="configFile">The XML file to load the configuration from.</param>
+ <remarks>
+ <para>
+ The configuration file must be valid XML. It must contain
+ at least one element called <c>log4net</c> that holds
+ the configuration data.
+ </para>
+ <para>
+ The configuration file will be monitored using a <see cref="T:System.IO.FileSystemWatcher"/>
+ and depends on the behavior of that class.
+ </para>
+ <para>
+ For more information on how to configure log4net using
+ a separate configuration file, see <see cref="M:log4net.Config.XmlConfigurator.Configure(System.IO.FileInfo)"/>.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.Config.XmlConfigurator.Configure(System.IO.FileInfo)"/>
+ </member>
+ <member name="M:log4net.Config.XmlConfigurator.ConfigureFromXml(log4net.Repository.ILoggerRepository,System.Xml.XmlElement)">
+ <summary>
+ Configures the specified repository using a <c>log4net</c> element.
+ </summary>
+ <param name="repository">The hierarchy to configure.</param>
+ <param name="element">The element to parse.</param>
+ <remarks>
+ <para>
+ Loads the log4net configuration from the XML element
+ supplied as <paramref name="element"/>.
+ </para>
+ <para>
+ This method is ultimately called by one of the Configure methods
+ to load the configuration from an <see cref="T:System.Xml.XmlElement"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Config.XmlConfigurator.ConfigureAndWatchHandler">
+ <summary>
+ Class used to watch config files.
+ </summary>
+ <remarks>
+ <para>
+ Uses the <see cref="T:System.IO.FileSystemWatcher"/> to monitor
+ changes to a specified file. Because multiple change notifications
+ may be raised when the file is modified, a timer is used to
+ compress the notifications into a single event. The timer
+ waits for <see cref="F:log4net.Config.XmlConfigurator.ConfigureAndWatchHandler.TimeoutMillis"/> time before delivering
+ the event notification. If any further <see cref="T:System.IO.FileSystemWatcher"/>
+ change notifications arrive while the timer is waiting it
+ is reset and waits again for <see cref="F:log4net.Config.XmlConfigurator.ConfigureAndWatchHandler.TimeoutMillis"/> to
+ elapse.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Config.XmlConfigurator.ConfigureAndWatchHandler.TimeoutMillis">
+ <summary>
+ The default amount of time to wait after receiving notification
+ before reloading the config file.
+ </summary>
+ </member>
+ <member name="M:log4net.Config.XmlConfigurator.ConfigureAndWatchHandler.StartWatching(log4net.Repository.ILoggerRepository,System.IO.FileInfo)">
+ <summary>
+ Watch a specified config file used to configure a repository
+ </summary>
+ <param name="repository">The repository to configure.</param>
+ <param name="configFile">The configuration file to watch.</param>
+ <remarks>
+ <para>
+ Watch a specified config file used to configure a repository
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Config.XmlConfigurator.ConfigureAndWatchHandler.m_configFile">
+ <summary>
+ Holds the FileInfo used to configure the XmlConfigurator
+ </summary>
+ </member>
+ <member name="F:log4net.Config.XmlConfigurator.ConfigureAndWatchHandler.m_repository">
+ <summary>
+ Holds the repository being configured.
+ </summary>
+ </member>
+ <member name="F:log4net.Config.XmlConfigurator.ConfigureAndWatchHandler.m_timer">
+ <summary>
+ The timer used to compress the notification events.
+ </summary>
+ </member>
+ <member name="M:log4net.Config.XmlConfigurator.ConfigureAndWatchHandler.#ctor(log4net.Repository.ILoggerRepository,System.IO.FileInfo)">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Config.XmlConfigurator.ConfigureAndWatchHandler"/> class.
+ </summary>
+ <param name="repository">The repository to configure.</param>
+ <param name="configFile">The configuration file to watch.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Config.XmlConfigurator.ConfigureAndWatchHandler"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.XmlConfigurator.ConfigureAndWatchHandler.ConfigureAndWatchHandler_OnChanged(System.Object,System.IO.FileSystemEventArgs)">
+ <summary>
+ Event handler used by <see cref="T:log4net.Config.XmlConfigurator.ConfigureAndWatchHandler"/>.
+ </summary>
+ <param name="source">The <see cref="T:System.IO.FileSystemWatcher"/> firing the event.</param>
+ <param name="e">The argument indicates the file that caused the event to be fired.</param>
+ <remarks>
+ <para>
+ This handler reloads the configuration from the file when the event is fired.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.XmlConfigurator.ConfigureAndWatchHandler.ConfigureAndWatchHandler_OnRenamed(System.Object,System.IO.RenamedEventArgs)">
+ <summary>
+ Event handler used by <see cref="T:log4net.Config.XmlConfigurator.ConfigureAndWatchHandler"/>.
+ </summary>
+ <param name="source">The <see cref="T:System.IO.FileSystemWatcher"/> firing the event.</param>
+ <param name="e">The argument indicates the file that caused the event to be fired.</param>
+ <remarks>
+ <para>
+ This handler reloads the configuration from the file when the event is fired.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Config.XmlConfigurator.ConfigureAndWatchHandler.OnWatchedFileChange(System.Object)">
+ <summary>
+ Called by the timer when the configuration has been updated.
+ </summary>
+ <param name="state">null</param>
+ </member>
+ <member name="T:log4net.Core.CompactRepositorySelector">
+ <summary>
+ The implementation of the <see cref="T:log4net.Core.IRepositorySelector"/> interface suitable
+ for use with the compact framework
+ </summary>
+ <remarks>
+ <para>
+ This <see cref="T:log4net.Core.IRepositorySelector"/> implementation is a simple
+ mapping between repository name and <see cref="T:log4net.Repository.ILoggerRepository"/>
+ object.
+ </para>
+ <para>
+ The .NET Compact Framework 1.0 does not support retrieving assembly
+ level attributes therefore unlike the <c>DefaultRepositorySelector</c>
+ this selector does not examine the calling assembly for attributes.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="T:log4net.Core.IRepositorySelector">
+ <summary>
+ Interface used by the <see cref="T:log4net.LogManager"/> to select the <see cref="T:log4net.Repository.ILoggerRepository"/>.
+ </summary>
+ <remarks>
+ <para>
+ The <see cref="T:log4net.LogManager"/> uses a <see cref="T:log4net.Core.IRepositorySelector"/>
+ to specify the policy for selecting the correct <see cref="T:log4net.Repository.ILoggerRepository"/>
+ to return to the caller.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Core.IRepositorySelector.GetRepository(System.Reflection.Assembly)">
+ <summary>
+ Gets the <see cref="T:log4net.Repository.ILoggerRepository"/> for the specified assembly.
+ </summary>
+ <param name="assembly">The assembly to use to lookup to the <see cref="T:log4net.Repository.ILoggerRepository"/></param>
+ <returns>The <see cref="T:log4net.Repository.ILoggerRepository"/> for the assembly.</returns>
+ <remarks>
+ <para>
+ Gets the <see cref="T:log4net.Repository.ILoggerRepository"/> for the specified assembly.
+ </para>
+ <para>
+ How the association between <see cref="T:System.Reflection.Assembly"/> and <see cref="T:log4net.Repository.ILoggerRepository"/>
+ is made is not defined. The implementation may choose any method for
+ this association. The results of this method must be repeatable, i.e.
+ when called again with the same arguments the result must be the
+ save value.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.IRepositorySelector.GetRepository(System.String)">
+ <summary>
+ Gets the named <see cref="T:log4net.Repository.ILoggerRepository"/>.
+ </summary>
+ <param name="repositoryName">The name to use to lookup to the <see cref="T:log4net.Repository.ILoggerRepository"/>.</param>
+ <returns>The named <see cref="T:log4net.Repository.ILoggerRepository"/></returns>
+ <remarks>
+ Lookup a named <see cref="T:log4net.Repository.ILoggerRepository"/>. This is the repository created by
+ calling <see cref="M:log4net.Core.IRepositorySelector.CreateRepository(System.String,System.Type)"/>.
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.IRepositorySelector.CreateRepository(System.Reflection.Assembly,System.Type)">
+ <summary>
+ Creates a new repository for the assembly specified.
+ </summary>
+ <param name="assembly">The assembly to use to create the domain to associate with the <see cref="T:log4net.Repository.ILoggerRepository"/>.</param>
+ <param name="repositoryType">The type of repository to create, must implement <see cref="T:log4net.Repository.ILoggerRepository"/>.</param>
+ <returns>The repository created.</returns>
+ <remarks>
+ <para>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> created will be associated with the domain
+ specified such that a call to <see cref="M:log4net.Core.IRepositorySelector.GetRepository(System.Reflection.Assembly)"/> with the
+ same assembly specified will return the same repository instance.
+ </para>
+ <para>
+ How the association between <see cref="T:System.Reflection.Assembly"/> and <see cref="T:log4net.Repository.ILoggerRepository"/>
+ is made is not defined. The implementation may choose any method for
+ this association.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.IRepositorySelector.CreateRepository(System.String,System.Type)">
+ <summary>
+ Creates a new repository with the name specified.
+ </summary>
+ <param name="repositoryName">The name to associate with the <see cref="T:log4net.Repository.ILoggerRepository"/>.</param>
+ <param name="repositoryType">The type of repository to create, must implement <see cref="T:log4net.Repository.ILoggerRepository"/>.</param>
+ <returns>The repository created.</returns>
+ <remarks>
+ <para>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> created will be associated with the name
+ specified such that a call to <see cref="M:log4net.Core.IRepositorySelector.GetRepository(System.String)"/> with the
+ same name will return the same repository instance.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.IRepositorySelector.ExistsRepository(System.String)">
+ <summary>
+ Test if a named repository exists
+ </summary>
+ <param name="repositoryName">the named repository to check</param>
+ <returns><c>true</c> if the repository exists</returns>
+ <remarks>
+ <para>
+ Test if a named repository exists. Use <see cref="M:log4net.Core.IRepositorySelector.CreateRepository(System.Reflection.Assembly,System.Type)"/>
+ to create a new repository and <see cref="M:log4net.Core.IRepositorySelector.GetRepository(System.Reflection.Assembly)"/> to retrieve
+ a repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.IRepositorySelector.GetAllRepositories">
+ <summary>
+ Gets an array of all currently defined repositories.
+ </summary>
+ <returns>
+ An array of the <see cref="T:log4net.Repository.ILoggerRepository"/> instances created by
+ this <see cref="T:log4net.Core.IRepositorySelector"/>.</returns>
+ <remarks>
+ <para>
+ Gets an array of all of the repositories created by this selector.
+ </para>
+ </remarks>
+ </member>
+ <member name="E:log4net.Core.IRepositorySelector.LoggerRepositoryCreatedEvent">
+ <summary>
+ Event to notify that a logger repository has been created.
+ </summary>
+ <value>
+ Event to notify that a logger repository has been created.
+ </value>
+ <remarks>
+ <para>
+ Event raised when a new repository is created.
+ The event source will be this selector. The event args will
+ be a <see cref="T:log4net.Core.LoggerRepositoryCreationEventArgs"/> which
+ holds the newly created <see cref="T:log4net.Repository.ILoggerRepository"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.CompactRepositorySelector.#ctor(System.Type)">
+ <summary>
+ Create a new repository selector
+ </summary>
+ <param name="defaultRepositoryType">the type of the repositories to create, must implement <see cref="T:log4net.Repository.ILoggerRepository"/></param>
+ <remarks>
+ <para>
+ Create an new compact repository selector.
+ The default type for repositories must be specified,
+ an appropriate value would be <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/>.
+ </para>
+ </remarks>
+ <exception cref="T:System.ArgumentNullException">throw if <paramref name="defaultRepositoryType"/> is null</exception>
+ <exception cref="T:System.ArgumentOutOfRangeException">throw if <paramref name="defaultRepositoryType"/> does not implement <see cref="T:log4net.Repository.ILoggerRepository"/></exception>
+ </member>
+ <member name="M:log4net.Core.CompactRepositorySelector.GetRepository(System.Reflection.Assembly)">
+ <summary>
+ Get the <see cref="T:log4net.Repository.ILoggerRepository"/> for the specified assembly
+ </summary>
+ <param name="assembly">not used</param>
+ <returns>The default <see cref="T:log4net.Repository.ILoggerRepository"/></returns>
+ <remarks>
+ <para>
+ The <paramref name="assembly"/> argument is not used. This selector does not create a
+ separate repository for each assembly.
+ </para>
+ <para>
+ As a named repository is not specified the default repository is
+ returned. The default repository is named <c>log4net-default-repository</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.CompactRepositorySelector.GetRepository(System.String)">
+ <summary>
+ Get the named <see cref="T:log4net.Repository.ILoggerRepository"/>
+ </summary>
+ <param name="repositoryName">the name of the repository to lookup</param>
+ <returns>The named <see cref="T:log4net.Repository.ILoggerRepository"/></returns>
+ <remarks>
+ <para>
+ Get the named <see cref="T:log4net.Repository.ILoggerRepository"/>. The default
+ repository is <c>log4net-default-repository</c>. Other repositories
+ must be created using the <see cref="M:log4net.Core.CompactRepositorySelector.CreateRepository(System.String,System.Type)"/>.
+ If the named repository does not exist an exception is thrown.
+ </para>
+ </remarks>
+ <exception cref="T:System.ArgumentNullException">throw if <paramref name="repositoryName"/> is null</exception>
+ <exception cref="T:log4net.Core.LogException">throw if the <paramref name="repositoryName"/> does not exist</exception>
+ </member>
+ <member name="M:log4net.Core.CompactRepositorySelector.CreateRepository(System.Reflection.Assembly,System.Type)">
+ <summary>
+ Create a new repository for the assembly specified
+ </summary>
+ <param name="assembly">not used</param>
+ <param name="repositoryType">the type of repository to create, must implement <see cref="T:log4net.Repository.ILoggerRepository"/></param>
+ <returns>the repository created</returns>
+ <remarks>
+ <para>
+ The <paramref name="assembly"/> argument is not used. This selector does not create a
+ separate repository for each assembly.
+ </para>
+ <para>
+ If the <paramref name="repositoryType"/> is <c>null</c> then the
+ default repository type specified to the constructor is used.
+ </para>
+ <para>
+ As a named repository is not specified the default repository is
+ returned. The default repository is named <c>log4net-default-repository</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.CompactRepositorySelector.CreateRepository(System.String,System.Type)">
+ <summary>
+ Create a new repository for the repository specified
+ </summary>
+ <param name="repositoryName">the repository to associate with the <see cref="T:log4net.Repository.ILoggerRepository"/></param>
+ <param name="repositoryType">the type of repository to create, must implement <see cref="T:log4net.Repository.ILoggerRepository"/>.
+ If this param is null then the default repository type is used.</param>
+ <returns>the repository created</returns>
+ <remarks>
+ <para>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> created will be associated with the repository
+ specified such that a call to <see cref="M:log4net.Core.CompactRepositorySelector.GetRepository(System.String)"/> with the
+ same repository specified will return the same repository instance.
+ </para>
+ <para>
+ If the named repository already exists an exception will be thrown.
+ </para>
+ <para>
+ If <paramref name="repositoryType"/> is <c>null</c> then the default
+ repository type specified to the constructor is used.
+ </para>
+ </remarks>
+ <exception cref="T:System.ArgumentNullException">throw if <paramref name="repositoryName"/> is null</exception>
+ <exception cref="T:log4net.Core.LogException">throw if the <paramref name="repositoryName"/> already exists</exception>
+ </member>
+ <member name="M:log4net.Core.CompactRepositorySelector.ExistsRepository(System.String)">
+ <summary>
+ Test if a named repository exists
+ </summary>
+ <param name="repositoryName">the named repository to check</param>
+ <returns><c>true</c> if the repository exists</returns>
+ <remarks>
+ <para>
+ Test if a named repository exists. Use <see cref="M:log4net.Core.CompactRepositorySelector.CreateRepository(System.String,System.Type)"/>
+ to create a new repository and <see cref="M:log4net.Core.CompactRepositorySelector.GetRepository(System.String)"/> to retrieve
+ a repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.CompactRepositorySelector.GetAllRepositories">
+ <summary>
+ Gets a list of <see cref="T:log4net.Repository.ILoggerRepository"/> objects
+ </summary>
+ <returns>an array of all known <see cref="T:log4net.Repository.ILoggerRepository"/> objects</returns>
+ <remarks>
+ <para>
+ Gets an array of all of the repositories created by this selector.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.CompactRepositorySelector.OnLoggerRepositoryCreatedEvent(log4net.Repository.ILoggerRepository)">
+ <summary>
+ Notify the registered listeners that the repository has been created
+ </summary>
+ <param name="repository">The repository that has been created</param>
+ <remarks>
+ <para>
+ Raises the <event cref="E:log4net.Core.CompactRepositorySelector.LoggerRepositoryCreatedEvent">LoggerRepositoryCreatedEvent</event>
+ event.
+ </para>
+ </remarks>
+ </member>
+ <member name="E:log4net.Core.CompactRepositorySelector.LoggerRepositoryCreatedEvent">
+ <summary>
+ Event to notify that a logger repository has been created.
+ </summary>
+ <value>
+ Event to notify that a logger repository has been created.
+ </value>
+ <remarks>
+ <para>
+ Event raised when a new repository is created.
+ The event source will be this selector. The event args will
+ be a <see cref="T:log4net.Core.LoggerRepositoryCreationEventArgs"/> which
+ holds the newly created <see cref="T:log4net.Repository.ILoggerRepository"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.DefaultRepositorySelector">
+ <summary>
+ The default implementation of the <see cref="T:log4net.Core.IRepositorySelector"/> interface.
+ </summary>
+ <remarks>
+ <para>
+ Uses attributes defined on the calling assembly to determine how to
+ configure the hierarchy for the repository.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Core.DefaultRepositorySelector.#ctor(System.Type)">
+ <summary>
+ Creates a new repository selector.
+ </summary>
+ <param name="defaultRepositoryType">The type of the repositories to create, must implement <see cref="T:log4net.Repository.ILoggerRepository"/></param>
+ <remarks>
+ <para>
+ Create an new repository selector.
+ The default type for repositories must be specified,
+ an appropriate value would be <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/>.
+ </para>
+ </remarks>
+ <exception cref="T:System.ArgumentNullException"><paramref name="defaultRepositoryType"/> is <see langword="null"/>.</exception>
+ <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="defaultRepositoryType"/> does not implement <see cref="T:log4net.Repository.ILoggerRepository"/>.</exception>
+ </member>
+ <member name="M:log4net.Core.DefaultRepositorySelector.GetRepository(System.Reflection.Assembly)">
+ <summary>
+ Gets the <see cref="T:log4net.Repository.ILoggerRepository"/> for the specified assembly.
+ </summary>
+ <param name="repositoryAssembly">The assembly use to lookup the <see cref="T:log4net.Repository.ILoggerRepository"/>.</param>
+ <remarks>
+ <para>
+ The type of the <see cref="T:log4net.Repository.ILoggerRepository"/> created and the repository
+ to create can be overridden by specifying the <see cref="T:log4net.Config.RepositoryAttribute"/>
+ attribute on the <paramref name="repositoryAssembly"/>.
+ </para>
+ <para>
+ The default values are to use the <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/>
+ implementation of the <see cref="T:log4net.Repository.ILoggerRepository"/> interface and to use the
+ <see cref="P:System.Reflection.AssemblyName.Name"/> as the name of the repository.
+ </para>
+ <para>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> created will be automatically configured using
+ any <see cref="T:log4net.Config.ConfiguratorAttribute"/> attributes defined on
+ the <paramref name="repositoryAssembly"/>.
+ </para>
+ </remarks>
+ <returns>The <see cref="T:log4net.Repository.ILoggerRepository"/> for the assembly</returns>
+ <exception cref="T:System.ArgumentNullException"><paramref name="repositoryAssembly"/> is <see langword="null"/>.</exception>
+ </member>
+ <member name="M:log4net.Core.DefaultRepositorySelector.GetRepository(System.String)">
+ <summary>
+ Gets the <see cref="T:log4net.Repository.ILoggerRepository"/> for the specified repository.
+ </summary>
+ <param name="repositoryName">The repository to use to lookup the <see cref="T:log4net.Repository.ILoggerRepository"/>.</param>
+ <returns>The <see cref="T:log4net.Repository.ILoggerRepository"/> for the specified repository.</returns>
+ <remarks>
+ <para>
+ Returns the named repository. If <paramref name="repositoryName"/> is <c>null</c>
+ a <see cref="T:System.ArgumentNullException"/> is thrown. If the repository
+ does not exist a <see cref="T:log4net.Core.LogException"/> is thrown.
+ </para>
+ <para>
+ Use <see cref="M:log4net.Core.DefaultRepositorySelector.CreateRepository(System.String,System.Type)"/> to create a repository.
+ </para>
+ </remarks>
+ <exception cref="T:System.ArgumentNullException"><paramref name="repositoryName"/> is <see langword="null"/>.</exception>
+ <exception cref="T:log4net.Core.LogException"><paramref name="repositoryName"/> does not exist.</exception>
+ </member>
+ <member name="M:log4net.Core.DefaultRepositorySelector.CreateRepository(System.Reflection.Assembly,System.Type)">
+ <summary>
+ Create a new repository for the assembly specified
+ </summary>
+ <param name="repositoryAssembly">the assembly to use to create the repository to associate with the <see cref="T:log4net.Repository.ILoggerRepository"/>.</param>
+ <param name="repositoryType">The type of repository to create, must implement <see cref="T:log4net.Repository.ILoggerRepository"/>.</param>
+ <returns>The repository created.</returns>
+ <remarks>
+ <para>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> created will be associated with the repository
+ specified such that a call to <see cref="M:log4net.Core.DefaultRepositorySelector.GetRepository(System.Reflection.Assembly)"/> with the
+ same assembly specified will return the same repository instance.
+ </para>
+ <para>
+ The type of the <see cref="T:log4net.Repository.ILoggerRepository"/> created and
+ the repository to create can be overridden by specifying the
+ <see cref="T:log4net.Config.RepositoryAttribute"/> attribute on the
+ <paramref name="repositoryAssembly"/>. The default values are to use the
+ <paramref name="repositoryType"/> implementation of the
+ <see cref="T:log4net.Repository.ILoggerRepository"/> interface and to use the
+ <see cref="P:System.Reflection.AssemblyName.Name"/> as the name of the repository.
+ </para>
+ <para>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> created will be automatically
+ configured using any <see cref="T:log4net.Config.ConfiguratorAttribute"/>
+ attributes defined on the <paramref name="repositoryAssembly"/>.
+ </para>
+ <para>
+ If a repository for the <paramref name="repositoryAssembly"/> already exists
+ that repository will be returned. An error will not be raised and that
+ repository may be of a different type to that specified in <paramref name="repositoryType"/>.
+ Also the <see cref="T:log4net.Config.RepositoryAttribute"/> attribute on the
+ assembly may be used to override the repository type specified in
+ <paramref name="repositoryType"/>.
+ </para>
+ </remarks>
+ <exception cref="T:System.ArgumentNullException"><paramref name="repositoryAssembly"/> is <see langword="null"/>.</exception>
+ </member>
+ <member name="M:log4net.Core.DefaultRepositorySelector.CreateRepository(System.Reflection.Assembly,System.Type,System.String,System.Boolean)">
+ <summary>
+ Creates a new repository for the assembly specified.
+ </summary>
+ <param name="repositoryAssembly">the assembly to use to create the repository to associate with the <see cref="T:log4net.Repository.ILoggerRepository"/>.</param>
+ <param name="repositoryType">The type of repository to create, must implement <see cref="T:log4net.Repository.ILoggerRepository"/>.</param>
+ <param name="repositoryName">The name to assign to the created repository</param>
+ <param name="readAssemblyAttributes">Set to <c>true</c> to read and apply the assembly attributes</param>
+ <returns>The repository created.</returns>
+ <remarks>
+ <para>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> created will be associated with the repository
+ specified such that a call to <see cref="M:log4net.Core.DefaultRepositorySelector.GetRepository(System.Reflection.Assembly)"/> with the
+ same assembly specified will return the same repository instance.
+ </para>
+ <para>
+ The type of the <see cref="T:log4net.Repository.ILoggerRepository"/> created and
+ the repository to create can be overridden by specifying the
+ <see cref="T:log4net.Config.RepositoryAttribute"/> attribute on the
+ <paramref name="repositoryAssembly"/>. The default values are to use the
+ <paramref name="repositoryType"/> implementation of the
+ <see cref="T:log4net.Repository.ILoggerRepository"/> interface and to use the
+ <see cref="P:System.Reflection.AssemblyName.Name"/> as the name of the repository.
+ </para>
+ <para>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> created will be automatically
+ configured using any <see cref="T:log4net.Config.ConfiguratorAttribute"/>
+ attributes defined on the <paramref name="repositoryAssembly"/>.
+ </para>
+ <para>
+ If a repository for the <paramref name="repositoryAssembly"/> already exists
+ that repository will be returned. An error will not be raised and that
+ repository may be of a different type to that specified in <paramref name="repositoryType"/>.
+ Also the <see cref="T:log4net.Config.RepositoryAttribute"/> attribute on the
+ assembly may be used to override the repository type specified in
+ <paramref name="repositoryType"/>.
+ </para>
+ </remarks>
+ <exception cref="T:System.ArgumentNullException"><paramref name="repositoryAssembly"/> is <see langword="null"/>.</exception>
+ </member>
+ <member name="M:log4net.Core.DefaultRepositorySelector.CreateRepository(System.String,System.Type)">
+ <summary>
+ Creates a new repository for the specified repository.
+ </summary>
+ <param name="repositoryName">The repository to associate with the <see cref="T:log4net.Repository.ILoggerRepository"/>.</param>
+ <param name="repositoryType">The type of repository to create, must implement <see cref="T:log4net.Repository.ILoggerRepository"/>.
+ If this param is <see langword="null"/> then the default repository type is used.</param>
+ <returns>The new repository.</returns>
+ <remarks>
+ <para>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> created will be associated with the repository
+ specified such that a call to <see cref="M:log4net.Core.DefaultRepositorySelector.GetRepository(System.String)"/> with the
+ same repository specified will return the same repository instance.
+ </para>
+ </remarks>
+ <exception cref="T:System.ArgumentNullException"><paramref name="repositoryName"/> is <see langword="null"/>.</exception>
+ <exception cref="T:log4net.Core.LogException"><paramref name="repositoryName"/> already exists.</exception>
+ </member>
+ <member name="M:log4net.Core.DefaultRepositorySelector.ExistsRepository(System.String)">
+ <summary>
+ Test if a named repository exists
+ </summary>
+ <param name="repositoryName">the named repository to check</param>
+ <returns><c>true</c> if the repository exists</returns>
+ <remarks>
+ <para>
+ Test if a named repository exists. Use <see cref="M:log4net.Core.DefaultRepositorySelector.CreateRepository(System.String,System.Type)"/>
+ to create a new repository and <see cref="M:log4net.Core.DefaultRepositorySelector.GetRepository(System.String)"/> to retrieve
+ a repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.DefaultRepositorySelector.GetAllRepositories">
+ <summary>
+ Gets a list of <see cref="T:log4net.Repository.ILoggerRepository"/> objects
+ </summary>
+ <returns>an array of all known <see cref="T:log4net.Repository.ILoggerRepository"/> objects</returns>
+ <remarks>
+ <para>
+ Gets an array of all of the repositories created by this selector.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.DefaultRepositorySelector.AliasRepository(System.String,log4net.Repository.ILoggerRepository)">
+ <summary>
+ Aliases a repository to an existing repository.
+ </summary>
+ <param name="repositoryAlias">The repository to alias.</param>
+ <param name="repositoryTarget">The repository that the repository is aliased to.</param>
+ <remarks>
+ <para>
+ The repository specified will be aliased to the repository when created.
+ The repository must not already exist.
+ </para>
+ <para>
+ When the repository is created it must utilize the same repository type as
+ the repository it is aliased to, otherwise the aliasing will fail.
+ </para>
+ </remarks>
+ <exception cref="T:System.ArgumentNullException">
+ <para><paramref name="repositoryAlias"/> is <see langword="null"/>.</para>
+ <para>-or-</para>
+ <para><paramref name="repositoryTarget"/> is <see langword="null"/>.</para>
+ </exception>
+ </member>
+ <member name="M:log4net.Core.DefaultRepositorySelector.OnLoggerRepositoryCreatedEvent(log4net.Repository.ILoggerRepository)">
+ <summary>
+ Notifies the registered listeners that the repository has been created.
+ </summary>
+ <param name="repository">The repository that has been created.</param>
+ <remarks>
+ <para>
+ Raises the <see cref="E:log4net.Core.DefaultRepositorySelector.LoggerRepositoryCreatedEvent"/> event.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.DefaultRepositorySelector.GetInfoForAssembly(System.Reflection.Assembly,System.String@,System.Type@)">
+ <summary>
+ Gets the repository name and repository type for the specified assembly.
+ </summary>
+ <param name="assembly">The assembly that has a <see cref="T:log4net.Config.RepositoryAttribute"/>.</param>
+ <param name="repositoryName">in/out param to hold the repository name to use for the assembly, caller should set this to the default value before calling.</param>
+ <param name="repositoryType">in/out param to hold the type of the repository to create for the assembly, caller should set this to the default value before calling.</param>
+ <exception cref="T:System.ArgumentNullException"><paramref name="assembly"/> is <see langword="null"/>.</exception>
+ </member>
+ <member name="M:log4net.Core.DefaultRepositorySelector.ConfigureRepository(System.Reflection.Assembly,log4net.Repository.ILoggerRepository)">
+ <summary>
+ Configures the repository using information from the assembly.
+ </summary>
+ <param name="assembly">The assembly containing <see cref="T:log4net.Config.ConfiguratorAttribute"/>
+ attributes which define the configuration for the repository.</param>
+ <param name="repository">The repository to configure.</param>
+ <exception cref="T:System.ArgumentNullException">
+ <para><paramref name="assembly"/> is <see langword="null"/>.</para>
+ <para>-or-</para>
+ <para><paramref name="repository"/> is <see langword="null"/>.</para>
+ </exception>
+ </member>
+ <member name="M:log4net.Core.DefaultRepositorySelector.LoadPlugins(System.Reflection.Assembly,log4net.Repository.ILoggerRepository)">
+ <summary>
+ Loads the attribute defined plugins on the assembly.
+ </summary>
+ <param name="assembly">The assembly that contains the attributes.</param>
+ <param name="repository">The repository to add the plugins to.</param>
+ <exception cref="T:System.ArgumentNullException">
+ <para><paramref name="assembly"/> is <see langword="null"/>.</para>
+ <para>-or-</para>
+ <para><paramref name="repository"/> is <see langword="null"/>.</para>
+ </exception>
+ </member>
+ <member name="M:log4net.Core.DefaultRepositorySelector.LoadAliases(System.Reflection.Assembly,log4net.Repository.ILoggerRepository)">
+ <summary>
+ Loads the attribute defined aliases on the assembly.
+ </summary>
+ <param name="assembly">The assembly that contains the attributes.</param>
+ <param name="repository">The repository to alias to.</param>
+ <exception cref="T:System.ArgumentNullException">
+ <para><paramref name="assembly"/> is <see langword="null"/>.</para>
+ <para>-or-</para>
+ <para><paramref name="repository"/> is <see langword="null"/>.</para>
+ </exception>
+ </member>
+ <member name="E:log4net.Core.DefaultRepositorySelector.LoggerRepositoryCreatedEvent">
+ <summary>
+ Event to notify that a logger repository has been created.
+ </summary>
+ <value>
+ Event to notify that a logger repository has been created.
+ </value>
+ <remarks>
+ <para>
+ Event raised when a new repository is created.
+ The event source will be this selector. The event args will
+ be a <see cref="T:log4net.Core.LoggerRepositoryCreationEventArgs"/> which
+ holds the newly created <see cref="T:log4net.Repository.ILoggerRepository"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.ErrorCode">
+ <summary>
+ Defined error codes that can be passed to the <see cref="M:log4net.Core.IErrorHandler.Error(System.String,System.Exception,log4net.Core.ErrorCode)"/> method.
+ </summary>
+ <remarks>
+ <para>
+ Values passed to the <see cref="M:log4net.Core.IErrorHandler.Error(System.String,System.Exception,log4net.Core.ErrorCode)"/> method.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="F:log4net.Core.ErrorCode.GenericFailure">
+ <summary>
+ A general error
+ </summary>
+ </member>
+ <member name="F:log4net.Core.ErrorCode.WriteFailure">
+ <summary>
+ Error while writing output
+ </summary>
+ </member>
+ <member name="F:log4net.Core.ErrorCode.FlushFailure">
+ <summary>
+ Failed to flush file
+ </summary>
+ </member>
+ <member name="F:log4net.Core.ErrorCode.CloseFailure">
+ <summary>
+ Failed to close file
+ </summary>
+ </member>
+ <member name="F:log4net.Core.ErrorCode.FileOpenFailure">
+ <summary>
+ Unable to open output file
+ </summary>
+ </member>
+ <member name="F:log4net.Core.ErrorCode.MissingLayout">
+ <summary>
+ No layout specified
+ </summary>
+ </member>
+ <member name="F:log4net.Core.ErrorCode.AddressParseFailure">
+ <summary>
+ Failed to parse address
+ </summary>
+ </member>
+ <member name="T:log4net.Core.IErrorHandler">
+ <summary>
+ Appenders may delegate their error handling to an <see cref="T:log4net.Core.IErrorHandler"/>.
+ </summary>
+ <remarks>
+ <para>
+ Error handling is a particularly tedious to get right because by
+ definition errors are hard to predict and to reproduce.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Core.IErrorHandler.Error(System.String,System.Exception,log4net.Core.ErrorCode)">
+ <summary>
+ Handles the error and information about the error condition is passed as
+ a parameter.
+ </summary>
+ <param name="message">The message associated with the error.</param>
+ <param name="e">The <see cref="T:System.Exception"/> that was thrown when the error occurred.</param>
+ <param name="errorCode">The error code associated with the error.</param>
+ <remarks>
+ <para>
+ Handles the error and information about the error condition is passed as
+ a parameter.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.IErrorHandler.Error(System.String,System.Exception)">
+ <summary>
+ Prints the error message passed as a parameter.
+ </summary>
+ <param name="message">The message associated with the error.</param>
+ <param name="e">The <see cref="T:System.Exception"/> that was thrown when the error occurred.</param>
+ <remarks>
+ <para>
+ See <see cref="M:log4net.Core.IErrorHandler.Error(System.String,System.Exception,log4net.Core.ErrorCode)"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.IErrorHandler.Error(System.String)">
+ <summary>
+ Prints the error message passed as a parameter.
+ </summary>
+ <param name="message">The message associated with the error.</param>
+ <remarks>
+ <para>
+ See <see cref="M:log4net.Core.IErrorHandler.Error(System.String,System.Exception,log4net.Core.ErrorCode)"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.IFixingRequired">
+ <summary>
+ Interface for objects that require fixing.
+ </summary>
+ <remarks>
+ <para>
+ Interface that indicates that the object requires fixing before it
+ can be taken outside the context of the appender's
+ <see cref="M:log4net.Appender.IAppender.DoAppend(log4net.Core.LoggingEvent)"/> method.
+ </para>
+ <para>
+ When objects that implement this interface are stored
+ in the context properties maps <see cref="T:log4net.GlobalContext"/>
+ <see cref="P:log4net.GlobalContext.Properties"/> and <see cref="T:log4net.ThreadContext"/>
+ <see cref="P:log4net.ThreadContext.Properties"/> are fixed
+ (see <see cref="P:log4net.Core.LoggingEvent.Fix"/>) the <see cref="M:log4net.Core.IFixingRequired.GetFixedObject"/>
+ method will be called.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Core.IFixingRequired.GetFixedObject">
+ <summary>
+ Get a portable version of this object
+ </summary>
+ <returns>the portable instance of this object</returns>
+ <remarks>
+ <para>
+ Get a portable instance object that represents the current
+ state of this object. The portable object can be stored
+ and logged from any thread with identical results.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.ILogger">
+ <summary>
+ Interface that all loggers implement
+ </summary>
+ <remarks>
+ <para>
+ This interface supports logging events and testing if a level
+ is enabled for logging.
+ </para>
+ <para>
+ These methods will not throw exceptions. Note to implementor, ensure
+ that the implementation of these methods cannot allow an exception
+ to be thrown to the caller.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Core.ILogger.Log(System.Type,log4net.Core.Level,System.Object,System.Exception)">
+ <summary>
+ This generic form is intended to be used by wrappers.
+ </summary>
+ <param name="callerStackBoundaryDeclaringType">The declaring type of the method that is
+ the stack boundary into the logging system for this call.</param>
+ <param name="level">The level of the message to be logged.</param>
+ <param name="message">The message object to log.</param>
+ <param name="exception">the exception to log, including its stack trace. Pass <c>null</c> to not log an exception.</param>
+ <remarks>
+ <para>
+ Generates a logging event for the specified <paramref name="level"/> using
+ the <paramref name="message"/> and <paramref name="exception"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.ILogger.Log(log4net.Core.LoggingEvent)">
+ <summary>
+ This is the most generic printing method that is intended to be used
+ by wrappers.
+ </summary>
+ <param name="logEvent">The event being logged.</param>
+ <remarks>
+ <para>
+ Logs the specified logging event through this logger.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.ILogger.IsEnabledFor(log4net.Core.Level)">
+ <summary>
+ Checks if this logger is enabled for a given <see cref="T:log4net.Core.Level"/> passed as parameter.
+ </summary>
+ <param name="level">The level to check.</param>
+ <returns>
+ <c>true</c> if this logger is enabled for <c>level</c>, otherwise <c>false</c>.
+ </returns>
+ <remarks>
+ <para>
+ Test if this logger is going to log events of the specified <paramref name="level"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.ILogger.Name">
+ <summary>
+ Gets the name of the logger.
+ </summary>
+ <value>
+ The name of the logger.
+ </value>
+ <remarks>
+ <para>
+ The name of this logger
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.ILogger.Repository">
+ <summary>
+ Gets the <see cref="T:log4net.Repository.ILoggerRepository"/> where this
+ <c>Logger</c> instance is attached to.
+ </summary>
+ <value>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> that this logger belongs to.
+ </value>
+ <remarks>
+ <para>
+ Gets the <see cref="T:log4net.Repository.ILoggerRepository"/> where this
+ <c>Logger</c> instance is attached to.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.ILoggerWrapper">
+ <summary>
+ Base interface for all wrappers
+ </summary>
+ <remarks>
+ <para>
+ Base interface for all wrappers.
+ </para>
+ <para>
+ All wrappers must implement this interface.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="P:log4net.Core.ILoggerWrapper.Logger">
+ <summary>
+ Get the implementation behind this wrapper object.
+ </summary>
+ <value>
+ The <see cref="T:log4net.Core.ILogger"/> object that in implementing this object.
+ </value>
+ <remarks>
+ <para>
+ The <see cref="T:log4net.Core.ILogger"/> object that in implementing this
+ object. The <c>Logger</c> object may not
+ be the same object as this object because of logger decorators.
+ This gets the actual underlying objects that is used to process
+ the log events.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.LoggerRepositoryCreationEventHandler">
+ <summary>
+ Delegate used to handle logger repository creation event notifications
+ </summary>
+ <param name="sender">The <see cref="T:log4net.Core.IRepositorySelector"/> which created the repository.</param>
+ <param name="e">The <see cref="T:log4net.Core.LoggerRepositoryCreationEventArgs"/> event args
+ that holds the <see cref="T:log4net.Repository.ILoggerRepository"/> instance that has been created.</param>
+ <remarks>
+ <para>
+ Delegate used to handle logger repository creation event notifications.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.LoggerRepositoryCreationEventArgs">
+ <summary>
+ Provides data for the <see cref="E:log4net.Core.IRepositorySelector.LoggerRepositoryCreatedEvent"/> event.
+ </summary>
+ <remarks>
+ <para>
+ A <see cref="E:log4net.Core.IRepositorySelector.LoggerRepositoryCreatedEvent"/>
+ event is raised every time a <see cref="T:log4net.Repository.ILoggerRepository"/> is created.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Core.LoggerRepositoryCreationEventArgs.m_repository">
+ <summary>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> created
+ </summary>
+ </member>
+ <member name="M:log4net.Core.LoggerRepositoryCreationEventArgs.#ctor(log4net.Repository.ILoggerRepository)">
+ <summary>
+ Construct instance using <see cref="T:log4net.Repository.ILoggerRepository"/> specified
+ </summary>
+ <param name="repository">the <see cref="T:log4net.Repository.ILoggerRepository"/> that has been created</param>
+ <remarks>
+ <para>
+ Construct instance using <see cref="T:log4net.Repository.ILoggerRepository"/> specified
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LoggerRepositoryCreationEventArgs.LoggerRepository">
+ <summary>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> that has been created
+ </summary>
+ <value>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> that has been created
+ </value>
+ <remarks>
+ <para>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> that has been created
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.ITriggeringEventEvaluator">
+ <summary>
+ Test if an <see cref="T:log4net.Core.LoggingEvent"/> triggers an action
+ </summary>
+ <remarks>
+ <para>
+ Implementations of this interface allow certain appenders to decide
+ when to perform an appender specific action.
+ </para>
+ <para>
+ The action or behavior triggered is defined by the implementation.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Core.ITriggeringEventEvaluator.IsTriggeringEvent(log4net.Core.LoggingEvent)">
+ <summary>
+ Test if this event triggers the action
+ </summary>
+ <param name="loggingEvent">The event to check</param>
+ <returns><c>true</c> if this event triggers the action, otherwise <c>false</c></returns>
+ <remarks>
+ <para>
+ Return <c>true</c> if this event triggers the action
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.Level">
+ <summary>
+ Defines the default set of levels recognized by the system.
+ </summary>
+ <remarks>
+ <para>
+ Each <see cref="T:log4net.Core.LoggingEvent"/> has an associated <see cref="T:log4net.Core.Level"/>.
+ </para>
+ <para>
+ Levels have a numeric <see cref="P:log4net.Core.Level.Value"/> that defines the relative
+ ordering between levels. Two Levels with the same <see cref="P:log4net.Core.Level.Value"/>
+ are deemed to be equivalent.
+ </para>
+ <para>
+ The levels that are recognized by log4net are set for each <see cref="T:log4net.Repository.ILoggerRepository"/>
+ and each repository can have different levels defined. The levels are stored
+ in the <see cref="P:log4net.Repository.ILoggerRepository.LevelMap"/> on the repository. Levels are
+ looked up by name from the <see cref="P:log4net.Repository.ILoggerRepository.LevelMap"/>.
+ </para>
+ <para>
+ When logging at level INFO the actual level used is not <see cref="F:log4net.Core.Level.Info"/> but
+ the value of <c>LoggerRepository.LevelMap["INFO"]</c>. The default value for this is
+ <see cref="F:log4net.Core.Level.Info"/>, but this can be changed by reconfiguring the level map.
+ </para>
+ <para>
+ Each level has a <see cref="P:log4net.Core.Level.DisplayName"/> in addition to its <see cref="P:log4net.Core.Level.Name"/>. The
+ <see cref="P:log4net.Core.Level.DisplayName"/> is the string that is written into the output log. By default
+ the display name is the same as the level name, but this can be used to alias levels
+ or to localize the log output.
+ </para>
+ <para>
+ Some of the predefined levels recognized by the system are:
+ </para>
+ <list type="bullet">
+ <item>
+ <description><see cref="F:log4net.Core.Level.Off"/>.</description>
+ </item>
+ <item>
+ <description><see cref="F:log4net.Core.Level.Fatal"/>.</description>
+ </item>
+ <item>
+ <description><see cref="F:log4net.Core.Level.Error"/>.</description>
+ </item>
+ <item>
+ <description><see cref="F:log4net.Core.Level.Warn"/>.</description>
+ </item>
+ <item>
+ <description><see cref="F:log4net.Core.Level.Info"/>.</description>
+ </item>
+ <item>
+ <description><see cref="F:log4net.Core.Level.Debug"/>.</description>
+ </item>
+ <item>
+ <description><see cref="F:log4net.Core.Level.All"/>.</description>
+ </item>
+ </list>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Core.Level.#ctor(System.Int32,System.String,System.String)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="level">Integer value for this level, higher values represent more severe levels.</param>
+ <param name="levelName">The string name of this level.</param>
+ <param name="displayName">The display name for this level. This may be localized or otherwise different from the name</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Core.Level"/> class with
+ the specified level name and value.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.Level.#ctor(System.Int32,System.String)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="level">Integer value for this level, higher values represent more severe levels.</param>
+ <param name="levelName">The string name of this level.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Core.Level"/> class with
+ the specified level name and value.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.Level.ToString">
+ <summary>
+ Returns the <see cref="T:System.String"/> representation of the current
+ <see cref="T:log4net.Core.Level"/>.
+ </summary>
+ <returns>
+ A <see cref="T:System.String"/> representation of the current <see cref="T:log4net.Core.Level"/>.
+ </returns>
+ <remarks>
+ <para>
+ Returns the level <see cref="P:log4net.Core.Level.Name"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.Level.Equals(System.Object)">
+ <summary>
+ Compares levels.
+ </summary>
+ <param name="o">The object to compare against.</param>
+ <returns><c>true</c> if the objects are equal.</returns>
+ <remarks>
+ <para>
+ Compares the levels of <see cref="T:log4net.Core.Level"/> instances, and
+ defers to base class if the target object is not a <see cref="T:log4net.Core.Level"/>
+ instance.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.Level.GetHashCode">
+ <summary>
+ Returns a hash code
+ </summary>
+ <returns>A hash code for the current <see cref="T:log4net.Core.Level"/>.</returns>
+ <remarks>
+ <para>
+ Returns a hash code suitable for use in hashing algorithms and data
+ structures like a hash table.
+ </para>
+ <para>
+ Returns the hash code of the level <see cref="P:log4net.Core.Level.Value"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.Level.CompareTo(System.Object)">
+ <summary>
+ Compares this instance to a specified object and returns an
+ indication of their relative values.
+ </summary>
+ <param name="r">A <see cref="T:log4net.Core.Level"/> instance or <see langword="null"/> to compare with this instance.</param>
+ <returns>
+ A 32-bit signed integer that indicates the relative order of the
+ values compared. The return value has these meanings:
+ <list type="table">
+ <listheader>
+ <term>Value</term>
+ <description>Meaning</description>
+ </listheader>
+ <item>
+ <term>Less than zero</term>
+ <description>This instance is less than <paramref name="r"/>.</description>
+ </item>
+ <item>
+ <term>Zero</term>
+ <description>This instance is equal to <paramref name="r"/>.</description>
+ </item>
+ <item>
+ <term>Greater than zero</term>
+ <description>
+ <para>This instance is greater than <paramref name="r"/>.</para>
+ <para>-or-</para>
+ <para><paramref name="r"/> is <see langword="null"/>.</para>
+ </description>
+ </item>
+ </list>
+ </returns>
+ <remarks>
+ <para>
+ <paramref name="r"/> must be an instance of <see cref="T:log4net.Core.Level"/>
+ or <see langword="null"/>; otherwise, an exception is thrown.
+ </para>
+ </remarks>
+ <exception cref="T:System.ArgumentException"><paramref name="r"/> is not a <see cref="T:log4net.Core.Level"/>.</exception>
+ </member>
+ <member name="M:log4net.Core.Level.op_GreaterThan(log4net.Core.Level,log4net.Core.Level)">
+ <summary>
+ Returns a value indicating whether a specified <see cref="T:log4net.Core.Level"/>
+ is greater than another specified <see cref="T:log4net.Core.Level"/>.
+ </summary>
+ <param name="l">A <see cref="T:log4net.Core.Level"/></param>
+ <param name="r">A <see cref="T:log4net.Core.Level"/></param>
+ <returns>
+ <c>true</c> if <paramref name="l"/> is greater than
+ <paramref name="r"/>; otherwise, <c>false</c>.
+ </returns>
+ <remarks>
+ <para>
+ Compares two levels.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.Level.op_LessThan(log4net.Core.Level,log4net.Core.Level)">
+ <summary>
+ Returns a value indicating whether a specified <see cref="T:log4net.Core.Level"/>
+ is less than another specified <see cref="T:log4net.Core.Level"/>.
+ </summary>
+ <param name="l">A <see cref="T:log4net.Core.Level"/></param>
+ <param name="r">A <see cref="T:log4net.Core.Level"/></param>
+ <returns>
+ <c>true</c> if <paramref name="l"/> is less than
+ <paramref name="r"/>; otherwise, <c>false</c>.
+ </returns>
+ <remarks>
+ <para>
+ Compares two levels.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.Level.op_GreaterThanOrEqual(log4net.Core.Level,log4net.Core.Level)">
+ <summary>
+ Returns a value indicating whether a specified <see cref="T:log4net.Core.Level"/>
+ is greater than or equal to another specified <see cref="T:log4net.Core.Level"/>.
+ </summary>
+ <param name="l">A <see cref="T:log4net.Core.Level"/></param>
+ <param name="r">A <see cref="T:log4net.Core.Level"/></param>
+ <returns>
+ <c>true</c> if <paramref name="l"/> is greater than or equal to
+ <paramref name="r"/>; otherwise, <c>false</c>.
+ </returns>
+ <remarks>
+ <para>
+ Compares two levels.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.Level.op_LessThanOrEqual(log4net.Core.Level,log4net.Core.Level)">
+ <summary>
+ Returns a value indicating whether a specified <see cref="T:log4net.Core.Level"/>
+ is less than or equal to another specified <see cref="T:log4net.Core.Level"/>.
+ </summary>
+ <param name="l">A <see cref="T:log4net.Core.Level"/></param>
+ <param name="r">A <see cref="T:log4net.Core.Level"/></param>
+ <returns>
+ <c>true</c> if <paramref name="l"/> is less than or equal to
+ <paramref name="r"/>; otherwise, <c>false</c>.
+ </returns>
+ <remarks>
+ <para>
+ Compares two levels.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.Level.op_Equality(log4net.Core.Level,log4net.Core.Level)">
+ <summary>
+ Returns a value indicating whether two specified <see cref="T:log4net.Core.Level"/>
+ objects have the same value.
+ </summary>
+ <param name="l">A <see cref="T:log4net.Core.Level"/> or <see langword="null"/>.</param>
+ <param name="r">A <see cref="T:log4net.Core.Level"/> or <see langword="null"/>.</param>
+ <returns>
+ <c>true</c> if the value of <paramref name="l"/> is the same as the
+ value of <paramref name="r"/>; otherwise, <c>false</c>.
+ </returns>
+ <remarks>
+ <para>
+ Compares two levels.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.Level.op_Inequality(log4net.Core.Level,log4net.Core.Level)">
+ <summary>
+ Returns a value indicating whether two specified <see cref="T:log4net.Core.Level"/>
+ objects have different values.
+ </summary>
+ <param name="l">A <see cref="T:log4net.Core.Level"/> or <see langword="null"/>.</param>
+ <param name="r">A <see cref="T:log4net.Core.Level"/> or <see langword="null"/>.</param>
+ <returns>
+ <c>true</c> if the value of <paramref name="l"/> is different from
+ the value of <paramref name="r"/>; otherwise, <c>false</c>.
+ </returns>
+ <remarks>
+ <para>
+ Compares two levels.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.Level.Compare(log4net.Core.Level,log4net.Core.Level)">
+ <summary>
+ Compares two specified <see cref="T:log4net.Core.Level"/> instances.
+ </summary>
+ <param name="l">The first <see cref="T:log4net.Core.Level"/> to compare.</param>
+ <param name="r">The second <see cref="T:log4net.Core.Level"/> to compare.</param>
+ <returns>
+ A 32-bit signed integer that indicates the relative order of the
+ two values compared. The return value has these meanings:
+ <list type="table">
+ <listheader>
+ <term>Value</term>
+ <description>Meaning</description>
+ </listheader>
+ <item>
+ <term>Less than zero</term>
+ <description><paramref name="l"/> is less than <paramref name="r"/>.</description>
+ </item>
+ <item>
+ <term>Zero</term>
+ <description><paramref name="l"/> is equal to <paramref name="r"/>.</description>
+ </item>
+ <item>
+ <term>Greater than zero</term>
+ <description><paramref name="l"/> is greater than <paramref name="r"/>.</description>
+ </item>
+ </list>
+ </returns>
+ <remarks>
+ <para>
+ Compares two levels.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Core.Level.Off">
+ <summary>
+ The <see cref="F:log4net.Core.Level.Off"/> level designates a higher level than all the rest.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.Level.Emergency">
+ <summary>
+ The <see cref="F:log4net.Core.Level.Emergency"/> level designates very severe error events.
+ System unusable, emergencies.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.Level.Fatal">
+ <summary>
+ The <see cref="F:log4net.Core.Level.Fatal"/> level designates very severe error events
+ that will presumably lead the application to abort.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.Level.Alert">
+ <summary>
+ The <see cref="F:log4net.Core.Level.Alert"/> level designates very severe error events.
+ Take immediate action, alerts.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.Level.Critical">
+ <summary>
+ The <see cref="F:log4net.Core.Level.Critical"/> level designates very severe error events.
+ Critical condition, critical.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.Level.Severe">
+ <summary>
+ The <see cref="F:log4net.Core.Level.Severe"/> level designates very severe error events.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.Level.Error">
+ <summary>
+ The <see cref="F:log4net.Core.Level.Error"/> level designates error events that might
+ still allow the application to continue running.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.Level.Warn">
+ <summary>
+ The <see cref="F:log4net.Core.Level.Warn"/> level designates potentially harmful
+ situations.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.Level.Notice">
+ <summary>
+ The <see cref="F:log4net.Core.Level.Notice"/> level designates informational messages
+ that highlight the progress of the application at the highest level.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.Level.Info">
+ <summary>
+ The <see cref="F:log4net.Core.Level.Info"/> level designates informational messages that
+ highlight the progress of the application at coarse-grained level.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.Level.Debug">
+ <summary>
+ The <see cref="F:log4net.Core.Level.Debug"/> level designates fine-grained informational
+ events that are most useful to debug an application.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.Level.Fine">
+ <summary>
+ The <see cref="F:log4net.Core.Level.Fine"/> level designates fine-grained informational
+ events that are most useful to debug an application.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.Level.Trace">
+ <summary>
+ The <see cref="F:log4net.Core.Level.Trace"/> level designates fine-grained informational
+ events that are most useful to debug an application.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.Level.Finer">
+ <summary>
+ The <see cref="F:log4net.Core.Level.Finer"/> level designates fine-grained informational
+ events that are most useful to debug an application.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.Level.Verbose">
+ <summary>
+ The <see cref="F:log4net.Core.Level.Verbose"/> level designates fine-grained informational
+ events that are most useful to debug an application.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.Level.Finest">
+ <summary>
+ The <see cref="F:log4net.Core.Level.Finest"/> level designates fine-grained informational
+ events that are most useful to debug an application.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.Level.All">
+ <summary>
+ The <see cref="F:log4net.Core.Level.All"/> level designates the lowest level possible.
+ </summary>
+ </member>
+ <member name="P:log4net.Core.Level.Name">
+ <summary>
+ Gets the name of this level.
+ </summary>
+ <value>
+ The name of this level.
+ </value>
+ <remarks>
+ <para>
+ Gets the name of this level.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.Level.Value">
+ <summary>
+ Gets the value of this level.
+ </summary>
+ <value>
+ The value of this level.
+ </value>
+ <remarks>
+ <para>
+ Gets the value of this level.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.Level.DisplayName">
+ <summary>
+ Gets the display name of this level.
+ </summary>
+ <value>
+ The display name of this level.
+ </value>
+ <remarks>
+ <para>
+ Gets the display name of this level.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.LevelCollection">
+ <summary>
+ A strongly-typed collection of <see cref="T:log4net.Core.Level"/> objects.
+ </summary>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.ReadOnly(log4net.Core.LevelCollection)">
+ <summary>
+ Creates a read-only wrapper for a <c>LevelCollection</c> instance.
+ </summary>
+ <param name="list">list to create a readonly wrapper arround</param>
+ <returns>
+ A <c>LevelCollection</c> wrapper that is read-only.
+ </returns>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.#ctor">
+ <summary>
+ Initializes a new instance of the <c>LevelCollection</c> class
+ that is empty and has the default initial capacity.
+ </summary>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.#ctor(System.Int32)">
+ <summary>
+ Initializes a new instance of the <c>LevelCollection</c> class
+ that has the specified initial capacity.
+ </summary>
+ <param name="capacity">
+ The number of elements that the new <c>LevelCollection</c> is initially capable of storing.
+ </param>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.#ctor(log4net.Core.LevelCollection)">
+ <summary>
+ Initializes a new instance of the <c>LevelCollection</c> class
+ that contains elements copied from the specified <c>LevelCollection</c>.
+ </summary>
+ <param name="c">The <c>LevelCollection</c> whose elements are copied to the new collection.</param>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.#ctor(log4net.Core.Level[])">
+ <summary>
+ Initializes a new instance of the <c>LevelCollection</c> class
+ that contains elements copied from the specified <see cref="T:log4net.Core.Level"/> array.
+ </summary>
+ <param name="a">The <see cref="T:log4net.Core.Level"/> array whose elements are copied to the new list.</param>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.#ctor(System.Collections.ICollection)">
+ <summary>
+ Initializes a new instance of the <c>LevelCollection</c> class
+ that contains elements copied from the specified <see cref="T:log4net.Core.Level"/> collection.
+ </summary>
+ <param name="col">The <see cref="T:log4net.Core.Level"/> collection whose elements are copied to the new list.</param>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.#ctor(log4net.Core.LevelCollection.Tag)">
+ <summary>
+ Allow subclasses to avoid our default constructors
+ </summary>
+ <param name="tag"></param>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.CopyTo(log4net.Core.Level[])">
+ <summary>
+ Copies the entire <c>LevelCollection</c> to a one-dimensional
+ <see cref="T:log4net.Core.Level"/> array.
+ </summary>
+ <param name="array">The one-dimensional <see cref="T:log4net.Core.Level"/> array to copy to.</param>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.CopyTo(log4net.Core.Level[],System.Int32)">
+ <summary>
+ Copies the entire <c>LevelCollection</c> to a one-dimensional
+ <see cref="T:log4net.Core.Level"/> array, starting at the specified index of the target array.
+ </summary>
+ <param name="array">The one-dimensional <see cref="T:log4net.Core.Level"/> array to copy to.</param>
+ <param name="start">The zero-based index in <paramref name="array"/> at which copying begins.</param>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.Add(log4net.Core.Level)">
+ <summary>
+ Adds a <see cref="T:log4net.Core.Level"/> to the end of the <c>LevelCollection</c>.
+ </summary>
+ <param name="item">The <see cref="T:log4net.Core.Level"/> to be added to the end of the <c>LevelCollection</c>.</param>
+ <returns>The index at which the value has been added.</returns>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.Clear">
+ <summary>
+ Removes all elements from the <c>LevelCollection</c>.
+ </summary>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.Clone">
+ <summary>
+ Creates a shallow copy of the <see cref="T:log4net.Core.LevelCollection"/>.
+ </summary>
+ <returns>A new <see cref="T:log4net.Core.LevelCollection"/> with a shallow copy of the collection data.</returns>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.Contains(log4net.Core.Level)">
+ <summary>
+ Determines whether a given <see cref="T:log4net.Core.Level"/> is in the <c>LevelCollection</c>.
+ </summary>
+ <param name="item">The <see cref="T:log4net.Core.Level"/> to check for.</param>
+ <returns><c>true</c> if <paramref name="item"/> is found in the <c>LevelCollection</c>; otherwise, <c>false</c>.</returns>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.IndexOf(log4net.Core.Level)">
+ <summary>
+ Returns the zero-based index of the first occurrence of a <see cref="T:log4net.Core.Level"/>
+ in the <c>LevelCollection</c>.
+ </summary>
+ <param name="item">The <see cref="T:log4net.Core.Level"/> to locate in the <c>LevelCollection</c>.</param>
+ <returns>
+ The zero-based index of the first occurrence of <paramref name="item"/>
+ in the entire <c>LevelCollection</c>, if found; otherwise, -1.
+ </returns>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.Insert(System.Int32,log4net.Core.Level)">
+ <summary>
+ Inserts an element into the <c>LevelCollection</c> at the specified index.
+ </summary>
+ <param name="index">The zero-based index at which <paramref name="item"/> should be inserted.</param>
+ <param name="item">The <see cref="T:log4net.Core.Level"/> to insert.</param>
+ <exception cref="T:System.ArgumentOutOfRangeException">
+ <para><paramref name="index"/> is less than zero</para>
+ <para>-or-</para>
+ <para><paramref name="index"/> is equal to or greater than <see cref="P:log4net.Core.LevelCollection.Count"/>.</para>
+ </exception>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.Remove(log4net.Core.Level)">
+ <summary>
+ Removes the first occurrence of a specific <see cref="T:log4net.Core.Level"/> from the <c>LevelCollection</c>.
+ </summary>
+ <param name="item">The <see cref="T:log4net.Core.Level"/> to remove from the <c>LevelCollection</c>.</param>
+ <exception cref="T:System.ArgumentException">
+ The specified <see cref="T:log4net.Core.Level"/> was not found in the <c>LevelCollection</c>.
+ </exception>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.RemoveAt(System.Int32)">
+ <summary>
+ Removes the element at the specified index of the <c>LevelCollection</c>.
+ </summary>
+ <param name="index">The zero-based index of the element to remove.</param>
+ <exception cref="T:System.ArgumentOutOfRangeException">
+ <para><paramref name="index"/> is less than zero</para>
+ <para>-or-</para>
+ <para><paramref name="index"/> is equal to or greater than <see cref="P:log4net.Core.LevelCollection.Count"/>.</para>
+ </exception>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.GetEnumerator">
+ <summary>
+ Returns an enumerator that can iterate through the <c>LevelCollection</c>.
+ </summary>
+ <returns>An <see cref="T:log4net.Core.LevelCollection.Enumerator"/> for the entire <c>LevelCollection</c>.</returns>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.AddRange(log4net.Core.LevelCollection)">
+ <summary>
+ Adds the elements of another <c>LevelCollection</c> to the current <c>LevelCollection</c>.
+ </summary>
+ <param name="x">The <c>LevelCollection</c> whose elements should be added to the end of the current <c>LevelCollection</c>.</param>
+ <returns>The new <see cref="P:log4net.Core.LevelCollection.Count"/> of the <c>LevelCollection</c>.</returns>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.AddRange(log4net.Core.Level[])">
+ <summary>
+ Adds the elements of a <see cref="T:log4net.Core.Level"/> array to the current <c>LevelCollection</c>.
+ </summary>
+ <param name="x">The <see cref="T:log4net.Core.Level"/> array whose elements should be added to the end of the <c>LevelCollection</c>.</param>
+ <returns>The new <see cref="P:log4net.Core.LevelCollection.Count"/> of the <c>LevelCollection</c>.</returns>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.AddRange(System.Collections.ICollection)">
+ <summary>
+ Adds the elements of a <see cref="T:log4net.Core.Level"/> collection to the current <c>LevelCollection</c>.
+ </summary>
+ <param name="col">The <see cref="T:log4net.Core.Level"/> collection whose elements should be added to the end of the <c>LevelCollection</c>.</param>
+ <returns>The new <see cref="P:log4net.Core.LevelCollection.Count"/> of the <c>LevelCollection</c>.</returns>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.TrimToSize">
+ <summary>
+ Sets the capacity to the actual number of elements.
+ </summary>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.ValidateIndex(System.Int32)">
+ <exception cref="T:System.ArgumentOutOfRangeException">
+ <para><paramref name="index"/> is less than zero</para>
+ <para>-or-</para>
+ <para><paramref name="index"/> is equal to or greater than <see cref="P:log4net.Core.LevelCollection.Count"/>.</para>
+ </exception>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.ValidateIndex(System.Int32,System.Boolean)">
+ <exception cref="T:System.ArgumentOutOfRangeException">
+ <para><paramref name="index"/> is less than zero</para>
+ <para>-or-</para>
+ <para><paramref name="index"/> is equal to or greater than <see cref="P:log4net.Core.LevelCollection.Count"/>.</para>
+ </exception>
+ </member>
+ <member name="P:log4net.Core.LevelCollection.Count">
+ <summary>
+ Gets the number of elements actually contained in the <c>LevelCollection</c>.
+ </summary>
+ </member>
+ <member name="P:log4net.Core.LevelCollection.IsSynchronized">
+ <summary>
+ Gets a value indicating whether access to the collection is synchronized (thread-safe).
+ </summary>
+ <value>true if access to the ICollection is synchronized (thread-safe); otherwise, false.</value>
+ </member>
+ <member name="P:log4net.Core.LevelCollection.SyncRoot">
+ <summary>
+ Gets an object that can be used to synchronize access to the collection.
+ </summary>
+ </member>
+ <member name="P:log4net.Core.LevelCollection.Item(System.Int32)">
+ <summary>
+ Gets or sets the <see cref="T:log4net.Core.Level"/> at the specified index.
+ </summary>
+ <param name="index">The zero-based index of the element to get or set.</param>
+ <exception cref="T:System.ArgumentOutOfRangeException">
+ <para><paramref name="index"/> is less than zero</para>
+ <para>-or-</para>
+ <para><paramref name="index"/> is equal to or greater than <see cref="P:log4net.Core.LevelCollection.Count"/>.</para>
+ </exception>
+ </member>
+ <member name="P:log4net.Core.LevelCollection.IsFixedSize">
+ <summary>
+ Gets a value indicating whether the collection has a fixed size.
+ </summary>
+ <value>true if the collection has a fixed size; otherwise, false. The default is false</value>
+ </member>
+ <member name="P:log4net.Core.LevelCollection.IsReadOnly">
+ <summary>
+ Gets a value indicating whether the IList is read-only.
+ </summary>
+ <value>true if the collection is read-only; otherwise, false. The default is false</value>
+ </member>
+ <member name="P:log4net.Core.LevelCollection.Capacity">
+ <summary>
+ Gets or sets the number of elements the <c>LevelCollection</c> can contain.
+ </summary>
+ </member>
+ <member name="T:log4net.Core.LevelCollection.ILevelCollectionEnumerator">
+ <summary>
+ Supports type-safe iteration over a <see cref="T:log4net.Core.LevelCollection"/>.
+ </summary>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.ILevelCollectionEnumerator.MoveNext">
+ <summary>
+ Advances the enumerator to the next element in the collection.
+ </summary>
+ <returns>
+ <c>true</c> if the enumerator was successfully advanced to the next element;
+ <c>false</c> if the enumerator has passed the end of the collection.
+ </returns>
+ <exception cref="T:System.InvalidOperationException">
+ The collection was modified after the enumerator was created.
+ </exception>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.ILevelCollectionEnumerator.Reset">
+ <summary>
+ Sets the enumerator to its initial position, before the first element in the collection.
+ </summary>
+ </member>
+ <member name="P:log4net.Core.LevelCollection.ILevelCollectionEnumerator.Current">
+ <summary>
+ Gets the current element in the collection.
+ </summary>
+ </member>
+ <member name="T:log4net.Core.LevelCollection.Tag">
+ <summary>
+ Type visible only to our subclasses
+ Used to access protected constructor
+ </summary>
+ </member>
+ <member name="F:log4net.Core.LevelCollection.Tag.Default">
+ <summary>
+ A value
+ </summary>
+ </member>
+ <member name="T:log4net.Core.LevelCollection.Enumerator">
+ <summary>
+ Supports simple iteration over a <see cref="T:log4net.Core.LevelCollection"/>.
+ </summary>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.Enumerator.#ctor(log4net.Core.LevelCollection)">
+ <summary>
+ Initializes a new instance of the <c>Enumerator</c> class.
+ </summary>
+ <param name="tc"></param>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.Enumerator.MoveNext">
+ <summary>
+ Advances the enumerator to the next element in the collection.
+ </summary>
+ <returns>
+ <c>true</c> if the enumerator was successfully advanced to the next element;
+ <c>false</c> if the enumerator has passed the end of the collection.
+ </returns>
+ <exception cref="T:System.InvalidOperationException">
+ The collection was modified after the enumerator was created.
+ </exception>
+ </member>
+ <member name="M:log4net.Core.LevelCollection.Enumerator.Reset">
+ <summary>
+ Sets the enumerator to its initial position, before the first element in the collection.
+ </summary>
+ </member>
+ <member name="P:log4net.Core.LevelCollection.Enumerator.Current">
+ <summary>
+ Gets the current element in the collection.
+ </summary>
+ </member>
+ <member name="T:log4net.Core.LevelEvaluator">
+ <summary>
+ An evaluator that triggers at a threshold level
+ </summary>
+ <remarks>
+ <para>
+ This evaluator will trigger if the level of the event
+ passed to <see cref="M:log4net.Core.LevelEvaluator.IsTriggeringEvent(log4net.Core.LoggingEvent)"/>
+ is equal to or greater than the <see cref="P:log4net.Core.LevelEvaluator.Threshold"/>
+ level.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="F:log4net.Core.LevelEvaluator.m_threshold">
+ <summary>
+ The threshold for triggering
+ </summary>
+ </member>
+ <member name="M:log4net.Core.LevelEvaluator.#ctor">
+ <summary>
+ Create a new evaluator using the <see cref="F:log4net.Core.Level.Off"/> threshold.
+ </summary>
+ <remarks>
+ <para>
+ Create a new evaluator using the <see cref="F:log4net.Core.Level.Off"/> threshold.
+ </para>
+ <para>
+ This evaluator will trigger if the level of the event
+ passed to <see cref="M:log4net.Core.LevelEvaluator.IsTriggeringEvent(log4net.Core.LoggingEvent)"/>
+ is equal to or greater than the <see cref="P:log4net.Core.LevelEvaluator.Threshold"/>
+ level.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LevelEvaluator.#ctor(log4net.Core.Level)">
+ <summary>
+ Create a new evaluator using the specified <see cref="T:log4net.Core.Level"/> threshold.
+ </summary>
+ <param name="threshold">the threshold to trigger at</param>
+ <remarks>
+ <para>
+ Create a new evaluator using the specified <see cref="T:log4net.Core.Level"/> threshold.
+ </para>
+ <para>
+ This evaluator will trigger if the level of the event
+ passed to <see cref="M:log4net.Core.LevelEvaluator.IsTriggeringEvent(log4net.Core.LoggingEvent)"/>
+ is equal to or greater than the <see cref="P:log4net.Core.LevelEvaluator.Threshold"/>
+ level.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LevelEvaluator.IsTriggeringEvent(log4net.Core.LoggingEvent)">
+ <summary>
+ Is this <paramref name="loggingEvent"/> the triggering event?
+ </summary>
+ <param name="loggingEvent">The event to check</param>
+ <returns>This method returns <c>true</c>, if the event level
+ is equal or higher than the <see cref="P:log4net.Core.LevelEvaluator.Threshold"/>.
+ Otherwise it returns <c>false</c></returns>
+ <remarks>
+ <para>
+ This evaluator will trigger if the level of the event
+ passed to <see cref="M:log4net.Core.LevelEvaluator.IsTriggeringEvent(log4net.Core.LoggingEvent)"/>
+ is equal to or greater than the <see cref="P:log4net.Core.LevelEvaluator.Threshold"/>
+ level.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LevelEvaluator.Threshold">
+ <summary>
+ the threshold to trigger at
+ </summary>
+ <value>
+ The <see cref="T:log4net.Core.Level"/> that will cause this evaluator to trigger
+ </value>
+ <remarks>
+ <para>
+ This evaluator will trigger if the level of the event
+ passed to <see cref="M:log4net.Core.LevelEvaluator.IsTriggeringEvent(log4net.Core.LoggingEvent)"/>
+ is equal to or greater than the <see cref="P:log4net.Core.LevelEvaluator.Threshold"/>
+ level.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.LevelMap">
+ <summary>
+ Mapping between string name and Level object
+ </summary>
+ <remarks>
+ <para>
+ Mapping between string name and <see cref="T:log4net.Core.Level"/> object.
+ This mapping is held separately for each <see cref="T:log4net.Repository.ILoggerRepository"/>.
+ The level name is case insensitive.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="F:log4net.Core.LevelMap.m_mapName2Level">
+ <summary>
+ Mapping from level name to Level object. The
+ level name is case insensitive
+ </summary>
+ </member>
+ <member name="M:log4net.Core.LevelMap.#ctor">
+ <summary>
+ Construct the level map
+ </summary>
+ <remarks>
+ <para>
+ Construct the level map.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LevelMap.Clear">
+ <summary>
+ Clear the internal maps of all levels
+ </summary>
+ <remarks>
+ <para>
+ Clear the internal maps of all levels
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LevelMap.Add(System.String,System.Int32)">
+ <summary>
+ Create a new Level and add it to the map
+ </summary>
+ <param name="name">the string to display for the Level</param>
+ <param name="value">the level value to give to the Level</param>
+ <remarks>
+ <para>
+ Create a new Level and add it to the map
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.Core.LevelMap.Add(System.String,System.Int32,System.String)"/>
+ </member>
+ <member name="M:log4net.Core.LevelMap.Add(System.String,System.Int32,System.String)">
+ <summary>
+ Create a new Level and add it to the map
+ </summary>
+ <param name="name">the string to display for the Level</param>
+ <param name="value">the level value to give to the Level</param>
+ <param name="displayName">the display name to give to the Level</param>
+ <remarks>
+ <para>
+ Create a new Level and add it to the map
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LevelMap.Add(log4net.Core.Level)">
+ <summary>
+ Add a Level to the map
+ </summary>
+ <param name="level">the Level to add</param>
+ <remarks>
+ <para>
+ Add a Level to the map
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LevelMap.LookupWithDefault(log4net.Core.Level)">
+ <summary>
+ Lookup a named level from the map
+ </summary>
+ <param name="defaultLevel">the name of the level to lookup is taken from this level.
+ If the level is not set on the map then this level is added</param>
+ <returns>the level in the map with the name specified</returns>
+ <remarks>
+ <para>
+ Lookup a named level from the map. The name of the level to lookup is taken
+ from the <see cref="P:log4net.Core.Level.Name"/> property of the <paramref name="defaultLevel"/>
+ argument.
+ </para>
+ <para>
+ If no level with the specified name is found then the
+ <paramref name="defaultLevel"/> argument is added to the level map
+ and returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LevelMap.Item(System.String)">
+ <summary>
+ Lookup a <see cref="T:log4net.Core.Level"/> by name
+ </summary>
+ <param name="name">The name of the Level to lookup</param>
+ <returns>a Level from the map with the name specified</returns>
+ <remarks>
+ <para>
+ Returns the <see cref="T:log4net.Core.Level"/> from the
+ map with the name specified. If the no level is
+ found then <c>null</c> is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LevelMap.AllLevels">
+ <summary>
+ Return all possible levels as a list of Level objects.
+ </summary>
+ <returns>all possible levels as a list of Level objects</returns>
+ <remarks>
+ <para>
+ Return all possible levels as a list of Level objects.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.LocationInfo">
+ <summary>
+ The internal representation of caller location information.
+ </summary>
+ <remarks>
+ <para>
+ This class uses the <c>System.Diagnostics.StackTrace</c> class to generate
+ a call stack. The caller's information is then extracted from this stack.
+ </para>
+ <para>
+ The <c>System.Diagnostics.StackTrace</c> class is not supported on the
+ .NET Compact Framework 1.0 therefore caller location information is not
+ available on that framework.
+ </para>
+ <para>
+ The <c>System.Diagnostics.StackTrace</c> class has this to say about Release builds:
+ </para>
+ <para>
+ "StackTrace information will be most informative with Debug build configurations.
+ By default, Debug builds include debug symbols, while Release builds do not. The
+ debug symbols contain most of the file, method name, line number, and column
+ information used in constructing StackFrame and StackTrace objects. StackTrace
+ might not report as many method calls as expected, due to code transformations
+ that occur during optimization."
+ </para>
+ <para>
+ This means that in a Release build the caller information may be incomplete or may
+ not exist at all! Therefore caller location information cannot be relied upon in a Release build.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="F:log4net.Core.LocationInfo.NA">
+ <summary>
+ When location information is not available the constant
+ <c>NA</c> is returned. Current value of this string
+ constant is <b>?</b>.
+ </summary>
+ </member>
+ <member name="M:log4net.Core.LocationInfo.#ctor(System.Type)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="callerStackBoundaryDeclaringType">The declaring type of the method that is
+ the stack boundary into the logging system for this call.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Core.LocationInfo"/>
+ class based on the current thread.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LocationInfo.#ctor(System.String,System.String,System.String,System.String)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="className">The fully qualified class name.</param>
+ <param name="methodName">The method name.</param>
+ <param name="fileName">The file name.</param>
+ <param name="lineNumber">The line number of the method within the file.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Core.LocationInfo"/>
+ class with the specified data.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LocationInfo.ClassName">
+ <summary>
+ Gets the fully qualified class name of the caller making the logging
+ request.
+ </summary>
+ <value>
+ The fully qualified class name of the caller making the logging
+ request.
+ </value>
+ <remarks>
+ <para>
+ Gets the fully qualified class name of the caller making the logging
+ request.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LocationInfo.FileName">
+ <summary>
+ Gets the file name of the caller.
+ </summary>
+ <value>
+ The file name of the caller.
+ </value>
+ <remarks>
+ <para>
+ Gets the file name of the caller.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LocationInfo.LineNumber">
+ <summary>
+ Gets the line number of the caller.
+ </summary>
+ <value>
+ The line number of the caller.
+ </value>
+ <remarks>
+ <para>
+ Gets the line number of the caller.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LocationInfo.MethodName">
+ <summary>
+ Gets the method name of the caller.
+ </summary>
+ <value>
+ The method name of the caller.
+ </value>
+ <remarks>
+ <para>
+ Gets the method name of the caller.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LocationInfo.FullInfo">
+ <summary>
+ Gets all available caller information
+ </summary>
+ <value>
+ All available caller information, in the format
+ <c>fully.qualified.classname.of.caller.methodName(Filename:line)</c>
+ </value>
+ <remarks>
+ <para>
+ Gets all available caller information, in the format
+ <c>fully.qualified.classname.of.caller.methodName(Filename:line)</c>
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.LoggerManager">
+ <summary>
+ Static manager that controls the creation of repositories
+ </summary>
+ <remarks>
+ <para>
+ Static manager that controls the creation of repositories
+ </para>
+ <para>
+ This class is used by the wrapper managers (e.g. <see cref="T:log4net.LogManager"/>)
+ to provide access to the <see cref="T:log4net.Core.ILogger"/> objects.
+ </para>
+ <para>
+ This manager also holds the <see cref="T:log4net.Core.IRepositorySelector"/> that is used to
+ lookup and create repositories. The selector can be set either programmatically using
+ the <see cref="P:log4net.Core.LoggerManager.RepositorySelector"/> property, or by setting the <c>log4net.RepositorySelector</c>
+ AppSetting in the applications config file to the fully qualified type name of the
+ selector to use.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.#ctor">
+ <summary>
+ Private constructor to prevent instances. Only static methods should be used.
+ </summary>
+ <remarks>
+ <para>
+ Private constructor to prevent instances. Only static methods should be used.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.#cctor">
+ <summary>
+ Hook the shutdown event
+ </summary>
+ <remarks>
+ <para>
+ On the full .NET runtime, the static constructor hooks up the
+ <c>AppDomain.ProcessExit</c> and <c>AppDomain.DomainUnload</c>> events.
+ These are used to shutdown the log4net system as the application exits.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.RegisterAppDomainEvents">
+ <summary>
+ Register for ProcessExit and DomainUnload events on the AppDomain
+ </summary>
+ <remarks>
+ <para>
+ This needs to be in a separate method because the events make
+ a LinkDemand for the ControlAppDomain SecurityPermission. Because
+ this is a LinkDemand it is demanded at JIT time. Therefore we cannot
+ catch the exception in the method itself, we have to catch it in the
+ caller.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.GetLoggerRepository(System.String)">
+ <summary>
+ Return the default <see cref="T:log4net.Repository.ILoggerRepository"/> instance.
+ </summary>
+ <param name="repository">the repository to lookup in</param>
+ <returns>Return the default <see cref="T:log4net.Repository.ILoggerRepository"/> instance</returns>
+ <remarks>
+ <para>
+ Gets the <see cref="T:log4net.Repository.ILoggerRepository"/> for the repository specified
+ by the <paramref name="repository"/> argument.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.GetLoggerRepository(System.Reflection.Assembly)">
+ <summary>
+ Returns the default <see cref="T:log4net.Repository.ILoggerRepository"/> instance.
+ </summary>
+ <param name="repositoryAssembly">The assembly to use to lookup the repository.</param>
+ <returns>The default <see cref="T:log4net.Repository.ILoggerRepository"/> instance.</returns>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.GetRepository(System.String)">
+ <summary>
+ Return the default <see cref="T:log4net.Repository.ILoggerRepository"/> instance.
+ </summary>
+ <param name="repository">the repository to lookup in</param>
+ <returns>Return the default <see cref="T:log4net.Repository.ILoggerRepository"/> instance</returns>
+ <remarks>
+ <para>
+ Gets the <see cref="T:log4net.Repository.ILoggerRepository"/> for the repository specified
+ by the <paramref name="repository"/> argument.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.GetRepository(System.Reflection.Assembly)">
+ <summary>
+ Returns the default <see cref="T:log4net.Repository.ILoggerRepository"/> instance.
+ </summary>
+ <param name="repositoryAssembly">The assembly to use to lookup the repository.</param>
+ <returns>The default <see cref="T:log4net.Repository.ILoggerRepository"/> instance.</returns>
+ <remarks>
+ <para>
+ Returns the default <see cref="T:log4net.Repository.ILoggerRepository"/> instance.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.Exists(System.String,System.String)">
+ <summary>
+ Returns the named logger if it exists.
+ </summary>
+ <param name="repository">The repository to lookup in.</param>
+ <param name="name">The fully qualified logger name to look for.</param>
+ <returns>
+ The logger found, or <c>null</c> if the named logger does not exist in the
+ specified repository.
+ </returns>
+ <remarks>
+ <para>
+ If the named logger exists (in the specified repository) then it
+ returns a reference to the logger, otherwise it returns
+ <c>null</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.Exists(System.Reflection.Assembly,System.String)">
+ <summary>
+ Returns the named logger if it exists.
+ </summary>
+ <param name="repositoryAssembly">The assembly to use to lookup the repository.</param>
+ <param name="name">The fully qualified logger name to look for.</param>
+ <returns>
+ The logger found, or <c>null</c> if the named logger does not exist in the
+ specified assembly's repository.
+ </returns>
+ <remarks>
+ <para>
+ If the named logger exists (in the specified assembly's repository) then it
+ returns a reference to the logger, otherwise it returns
+ <c>null</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.GetCurrentLoggers(System.String)">
+ <summary>
+ Returns all the currently defined loggers in the specified repository.
+ </summary>
+ <param name="repository">The repository to lookup in.</param>
+ <returns>All the defined loggers.</returns>
+ <remarks>
+ <para>
+ The root logger is <b>not</b> included in the returned array.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.GetCurrentLoggers(System.Reflection.Assembly)">
+ <summary>
+ Returns all the currently defined loggers in the specified assembly's repository.
+ </summary>
+ <param name="repositoryAssembly">The assembly to use to lookup the repository.</param>
+ <returns>All the defined loggers.</returns>
+ <remarks>
+ <para>
+ The root logger is <b>not</b> included in the returned array.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.GetLogger(System.String,System.String)">
+ <summary>
+ Retrieves or creates a named logger.
+ </summary>
+ <param name="repository">The repository to lookup in.</param>
+ <param name="name">The name of the logger to retrieve.</param>
+ <returns>The logger with the name specified.</returns>
+ <remarks>
+ <para>
+ Retrieves a logger named as the <paramref name="name"/>
+ parameter. If the named logger already exists, then the
+ existing instance will be returned. Otherwise, a new instance is
+ created.
+ </para>
+ <para>
+ By default, loggers do not have a set level but inherit
+ it from the hierarchy. This is one of the central features of
+ log4net.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.GetLogger(System.Reflection.Assembly,System.String)">
+ <summary>
+ Retrieves or creates a named logger.
+ </summary>
+ <param name="repositoryAssembly">The assembly to use to lookup the repository.</param>
+ <param name="name">The name of the logger to retrieve.</param>
+ <returns>The logger with the name specified.</returns>
+ <remarks>
+ <para>
+ Retrieves a logger named as the <paramref name="name"/>
+ parameter. If the named logger already exists, then the
+ existing instance will be returned. Otherwise, a new instance is
+ created.
+ </para>
+ <para>
+ By default, loggers do not have a set level but inherit
+ it from the hierarchy. This is one of the central features of
+ log4net.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.GetLogger(System.String,System.Type)">
+ <summary>
+ Shorthand for <see cref="M:log4net.LogManager.GetLogger(System.String)"/>.
+ </summary>
+ <param name="repository">The repository to lookup in.</param>
+ <param name="type">The <paramref name="type"/> of which the fullname will be used as the name of the logger to retrieve.</param>
+ <returns>The logger with the name specified.</returns>
+ <remarks>
+ <para>
+ Gets the logger for the fully qualified name of the type specified.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.GetLogger(System.Reflection.Assembly,System.Type)">
+ <summary>
+ Shorthand for <see cref="M:log4net.LogManager.GetLogger(System.String)"/>.
+ </summary>
+ <param name="repositoryAssembly">the assembly to use to lookup the repository</param>
+ <param name="type">The <paramref name="type"/> of which the fullname will be used as the name of the logger to retrieve.</param>
+ <returns>The logger with the name specified.</returns>
+ <remarks>
+ <para>
+ Gets the logger for the fully qualified name of the type specified.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.Shutdown">
+ <summary>
+ Shuts down the log4net system.
+ </summary>
+ <remarks>
+ <para>
+ Calling this method will <b>safely</b> close and remove all
+ appenders in all the loggers including root contained in all the
+ default repositories.
+ </para>
+ <para>
+ Some appenders need to be closed before the application exists.
+ Otherwise, pending logging events might be lost.
+ </para>
+ <para>
+ The <c>shutdown</c> method is careful to close nested
+ appenders before closing regular appenders. This is allows
+ configurations where a regular appender is attached to a logger
+ and again to a nested appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.ShutdownRepository(System.String)">
+ <summary>
+ Shuts down the repository for the repository specified.
+ </summary>
+ <param name="repository">The repository to shutdown.</param>
+ <remarks>
+ <para>
+ Calling this method will <b>safely</b> close and remove all
+ appenders in all the loggers including root contained in the
+ repository for the <paramref name="repository"/> specified.
+ </para>
+ <para>
+ Some appenders need to be closed before the application exists.
+ Otherwise, pending logging events might be lost.
+ </para>
+ <para>
+ The <c>shutdown</c> method is careful to close nested
+ appenders before closing regular appenders. This is allows
+ configurations where a regular appender is attached to a logger
+ and again to a nested appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.ShutdownRepository(System.Reflection.Assembly)">
+ <summary>
+ Shuts down the repository for the repository specified.
+ </summary>
+ <param name="repositoryAssembly">The assembly to use to lookup the repository.</param>
+ <remarks>
+ <para>
+ Calling this method will <b>safely</b> close and remove all
+ appenders in all the loggers including root contained in the
+ repository for the repository. The repository is looked up using
+ the <paramref name="repositoryAssembly"/> specified.
+ </para>
+ <para>
+ Some appenders need to be closed before the application exists.
+ Otherwise, pending logging events might be lost.
+ </para>
+ <para>
+ The <c>shutdown</c> method is careful to close nested
+ appenders before closing regular appenders. This is allows
+ configurations where a regular appender is attached to a logger
+ and again to a nested appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.ResetConfiguration(System.String)">
+ <summary>
+ Resets all values contained in this repository instance to their defaults.
+ </summary>
+ <param name="repository">The repository to reset.</param>
+ <remarks>
+ <para>
+ Resets all values contained in the repository instance to their
+ defaults. This removes all appenders from all loggers, sets
+ the level of all non-root loggers to <c>null</c>,
+ sets their additivity flag to <c>true</c> and sets the level
+ of the root logger to <see cref="F:log4net.Core.Level.Debug"/>. Moreover,
+ message disabling is set its default "off" value.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.ResetConfiguration(System.Reflection.Assembly)">
+ <summary>
+ Resets all values contained in this repository instance to their defaults.
+ </summary>
+ <param name="repositoryAssembly">The assembly to use to lookup the repository to reset.</param>
+ <remarks>
+ <para>
+ Resets all values contained in the repository instance to their
+ defaults. This removes all appenders from all loggers, sets
+ the level of all non-root loggers to <c>null</c>,
+ sets their additivity flag to <c>true</c> and sets the level
+ of the root logger to <see cref="F:log4net.Core.Level.Debug"/>. Moreover,
+ message disabling is set its default "off" value.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.CreateDomain(System.String)">
+ <summary>
+ Creates a repository with the specified name.
+ </summary>
+ <param name="repository">The name of the repository, this must be unique amongst repositories.</param>
+ <returns>The <see cref="T:log4net.Repository.ILoggerRepository"/> created for the repository.</returns>
+ <remarks>
+ <para>
+ <b>CreateDomain is obsolete. Use CreateRepository instead of CreateDomain.</b>
+ </para>
+ <para>
+ Creates the default type of <see cref="T:log4net.Repository.ILoggerRepository"/> which is a
+ <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/> object.
+ </para>
+ <para>
+ The <paramref name="repository"/> name must be unique. Repositories cannot be redefined.
+ An <see cref="T:System.Exception"/> will be thrown if the repository already exists.
+ </para>
+ </remarks>
+ <exception cref="T:log4net.Core.LogException">The specified repository already exists.</exception>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.CreateRepository(System.String)">
+ <summary>
+ Creates a repository with the specified name.
+ </summary>
+ <param name="repository">The name of the repository, this must be unique amongst repositories.</param>
+ <returns>The <see cref="T:log4net.Repository.ILoggerRepository"/> created for the repository.</returns>
+ <remarks>
+ <para>
+ Creates the default type of <see cref="T:log4net.Repository.ILoggerRepository"/> which is a
+ <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/> object.
+ </para>
+ <para>
+ The <paramref name="repository"/> name must be unique. Repositories cannot be redefined.
+ An <see cref="T:System.Exception"/> will be thrown if the repository already exists.
+ </para>
+ </remarks>
+ <exception cref="T:log4net.Core.LogException">The specified repository already exists.</exception>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.CreateDomain(System.String,System.Type)">
+ <summary>
+ Creates a repository with the specified name and repository type.
+ </summary>
+ <param name="repository">The name of the repository, this must be unique to the repository.</param>
+ <param name="repositoryType">A <see cref="T:System.Type"/> that implements <see cref="T:log4net.Repository.ILoggerRepository"/>
+ and has a no arg constructor. An instance of this type will be created to act
+ as the <see cref="T:log4net.Repository.ILoggerRepository"/> for the repository specified.</param>
+ <returns>The <see cref="T:log4net.Repository.ILoggerRepository"/> created for the repository.</returns>
+ <remarks>
+ <para>
+ <b>CreateDomain is obsolete. Use CreateRepository instead of CreateDomain.</b>
+ </para>
+ <para>
+ The <paramref name="repository"/> name must be unique. Repositories cannot be redefined.
+ An Exception will be thrown if the repository already exists.
+ </para>
+ </remarks>
+ <exception cref="T:log4net.Core.LogException">The specified repository already exists.</exception>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.CreateRepository(System.String,System.Type)">
+ <summary>
+ Creates a repository with the specified name and repository type.
+ </summary>
+ <param name="repository">The name of the repository, this must be unique to the repository.</param>
+ <param name="repositoryType">A <see cref="T:System.Type"/> that implements <see cref="T:log4net.Repository.ILoggerRepository"/>
+ and has a no arg constructor. An instance of this type will be created to act
+ as the <see cref="T:log4net.Repository.ILoggerRepository"/> for the repository specified.</param>
+ <returns>The <see cref="T:log4net.Repository.ILoggerRepository"/> created for the repository.</returns>
+ <remarks>
+ <para>
+ The <paramref name="repository"/> name must be unique. Repositories cannot be redefined.
+ An Exception will be thrown if the repository already exists.
+ </para>
+ </remarks>
+ <exception cref="T:log4net.Core.LogException">The specified repository already exists.</exception>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.CreateDomain(System.Reflection.Assembly,System.Type)">
+ <summary>
+ Creates a repository for the specified assembly and repository type.
+ </summary>
+ <param name="repositoryAssembly">The assembly to use to get the name of the repository.</param>
+ <param name="repositoryType">A <see cref="T:System.Type"/> that implements <see cref="T:log4net.Repository.ILoggerRepository"/>
+ and has a no arg constructor. An instance of this type will be created to act
+ as the <see cref="T:log4net.Repository.ILoggerRepository"/> for the repository specified.</param>
+ <returns>The <see cref="T:log4net.Repository.ILoggerRepository"/> created for the repository.</returns>
+ <remarks>
+ <para>
+ <b>CreateDomain is obsolete. Use CreateRepository instead of CreateDomain.</b>
+ </para>
+ <para>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> created will be associated with the repository
+ specified such that a call to <see cref="M:log4net.Core.LoggerManager.GetRepository(System.Reflection.Assembly)"/> with the
+ same assembly specified will return the same repository instance.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.CreateRepository(System.Reflection.Assembly,System.Type)">
+ <summary>
+ Creates a repository for the specified assembly and repository type.
+ </summary>
+ <param name="repositoryAssembly">The assembly to use to get the name of the repository.</param>
+ <param name="repositoryType">A <see cref="T:System.Type"/> that implements <see cref="T:log4net.Repository.ILoggerRepository"/>
+ and has a no arg constructor. An instance of this type will be created to act
+ as the <see cref="T:log4net.Repository.ILoggerRepository"/> for the repository specified.</param>
+ <returns>The <see cref="T:log4net.Repository.ILoggerRepository"/> created for the repository.</returns>
+ <remarks>
+ <para>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> created will be associated with the repository
+ specified such that a call to <see cref="M:log4net.Core.LoggerManager.GetRepository(System.Reflection.Assembly)"/> with the
+ same assembly specified will return the same repository instance.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.GetAllRepositories">
+ <summary>
+ Gets an array of all currently defined repositories.
+ </summary>
+ <returns>An array of all the known <see cref="T:log4net.Repository.ILoggerRepository"/> objects.</returns>
+ <remarks>
+ <para>
+ Gets an array of all currently defined repositories.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.GetVersionInfo">
+ <summary>
+ Internal method to get pertinent version info.
+ </summary>
+ <returns>A string of version info.</returns>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.OnDomainUnload(System.Object,System.EventArgs)">
+ <summary>
+ Called when the <see cref="E:System.AppDomain.DomainUnload"/> event fires
+ </summary>
+ <param name="sender">the <see cref="T:System.AppDomain"/> that is exiting</param>
+ <param name="e">null</param>
+ <remarks>
+ <para>
+ Called when the <see cref="E:System.AppDomain.DomainUnload"/> event fires.
+ </para>
+ <para>
+ When the event is triggered the log4net system is <see cref="M:log4net.Core.LoggerManager.Shutdown"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggerManager.OnProcessExit(System.Object,System.EventArgs)">
+ <summary>
+ Called when the <see cref="E:System.AppDomain.ProcessExit"/> event fires
+ </summary>
+ <param name="sender">the <see cref="T:System.AppDomain"/> that is exiting</param>
+ <param name="e">null</param>
+ <remarks>
+ <para>
+ Called when the <see cref="E:System.AppDomain.ProcessExit"/> event fires.
+ </para>
+ <para>
+ When the event is triggered the log4net system is <see cref="M:log4net.Core.LoggerManager.Shutdown"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Core.LoggerManager.s_repositorySelector">
+ <summary>
+ Initialize the default repository selector
+ </summary>
+ </member>
+ <member name="P:log4net.Core.LoggerManager.RepositorySelector">
+ <summary>
+ Gets or sets the repository selector used by the <see cref="T:log4net.LogManager"/>.
+ </summary>
+ <value>
+ The repository selector used by the <see cref="T:log4net.LogManager"/>.
+ </value>
+ <remarks>
+ <para>
+ The repository selector (<see cref="T:log4net.Core.IRepositorySelector"/>) is used by
+ the <see cref="T:log4net.LogManager"/> to create and select repositories
+ (<see cref="T:log4net.Repository.ILoggerRepository"/>).
+ </para>
+ <para>
+ The caller to <see cref="T:log4net.LogManager"/> supplies either a string name
+ or an assembly (if not supplied the assembly is inferred using
+ <see cref="M:System.Reflection.Assembly.GetCallingAssembly"/>).
+ </para>
+ <para>
+ This context is used by the selector to lookup a specific repository.
+ </para>
+ <para>
+ For the full .NET Framework, the default repository is <c>DefaultRepositorySelector</c>;
+ for the .NET Compact Framework <c>CompactRepositorySelector</c> is the default
+ repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.LoggerWrapperImpl">
+ <summary>
+ Implementation of the <see cref="T:log4net.Core.ILoggerWrapper"/> interface.
+ </summary>
+ <remarks>
+ <para>
+ This class should be used as the base for all wrapper implementations.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Core.LoggerWrapperImpl.#ctor(log4net.Core.ILogger)">
+ <summary>
+ Constructs a new wrapper for the specified logger.
+ </summary>
+ <param name="logger">The logger to wrap.</param>
+ <remarks>
+ <para>
+ Constructs a new wrapper for the specified logger.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Core.LoggerWrapperImpl.m_logger">
+ <summary>
+ The logger that this object is wrapping
+ </summary>
+ </member>
+ <member name="P:log4net.Core.LoggerWrapperImpl.Logger">
+ <summary>
+ Gets the implementation behind this wrapper object.
+ </summary>
+ <value>
+ The <see cref="T:log4net.Core.ILogger"/> object that this object is implementing.
+ </value>
+ <remarks>
+ <para>
+ The <c>Logger</c> object may not be the same object as this object
+ because of logger decorators.
+ </para>
+ <para>
+ This gets the actual underlying objects that is used to process
+ the log events.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.LoggingEventData">
+ <summary>
+ Portable data structure used by <see cref="T:log4net.Core.LoggingEvent"/>
+ </summary>
+ <remarks>
+ <para>
+ Portable data structure used by <see cref="T:log4net.Core.LoggingEvent"/>
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="F:log4net.Core.LoggingEventData.LoggerName">
+ <summary>
+ The logger name.
+ </summary>
+ <remarks>
+ <para>
+ The logger name.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Core.LoggingEventData.Level">
+ <summary>
+ Level of logging event.
+ </summary>
+ <remarks>
+ <para>
+ Level of logging event. Level cannot be Serializable
+ because it is a flyweight. Due to its special serialization it
+ cannot be declared final either.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Core.LoggingEventData.Message">
+ <summary>
+ The application supplied message.
+ </summary>
+ <remarks>
+ <para>
+ The application supplied message of logging event.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Core.LoggingEventData.ThreadName">
+ <summary>
+ The name of thread
+ </summary>
+ <remarks>
+ <para>
+ The name of thread in which this logging event was generated
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Core.LoggingEventData.TimeStamp">
+ <summary>
+ The time the event was logged
+ </summary>
+ <remarks>
+ <para>
+ The TimeStamp is stored in the local time zone for this computer.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Core.LoggingEventData.LocationInfo">
+ <summary>
+ Location information for the caller.
+ </summary>
+ <remarks>
+ <para>
+ Location information for the caller.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Core.LoggingEventData.UserName">
+ <summary>
+ String representation of the user
+ </summary>
+ <remarks>
+ <para>
+ String representation of the user's windows name,
+ like DOMAIN\username
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Core.LoggingEventData.Identity">
+ <summary>
+ String representation of the identity.
+ </summary>
+ <remarks>
+ <para>
+ String representation of the current thread's principal identity.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Core.LoggingEventData.ExceptionString">
+ <summary>
+ The string representation of the exception
+ </summary>
+ <remarks>
+ <para>
+ The string representation of the exception
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Core.LoggingEventData.Domain">
+ <summary>
+ String representation of the AppDomain.
+ </summary>
+ <remarks>
+ <para>
+ String representation of the AppDomain.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Core.LoggingEventData.Properties">
+ <summary>
+ Additional event specific properties
+ </summary>
+ <remarks>
+ <para>
+ A logger or an appender may attach additional
+ properties to specific events. These properties
+ have a string key and an object value.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.FixFlags">
+ <summary>
+ Flags passed to the <see cref="P:log4net.Core.LoggingEvent.Fix"/> property
+ </summary>
+ <remarks>
+ <para>
+ Flags passed to the <see cref="P:log4net.Core.LoggingEvent.Fix"/> property
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="F:log4net.Core.FixFlags.Mdc">
+ <summary>
+ Fix the MDC
+ </summary>
+ </member>
+ <member name="F:log4net.Core.FixFlags.Ndc">
+ <summary>
+ Fix the NDC
+ </summary>
+ </member>
+ <member name="F:log4net.Core.FixFlags.Message">
+ <summary>
+ Fix the rendered message
+ </summary>
+ </member>
+ <member name="F:log4net.Core.FixFlags.ThreadName">
+ <summary>
+ Fix the thread name
+ </summary>
+ </member>
+ <member name="F:log4net.Core.FixFlags.LocationInfo">
+ <summary>
+ Fix the callers location information
+ </summary>
+ <remarks>
+ CAUTION: Very slow to generate
+ </remarks>
+ </member>
+ <member name="F:log4net.Core.FixFlags.UserName">
+ <summary>
+ Fix the callers windows user name
+ </summary>
+ <remarks>
+ CAUTION: Slow to generate
+ </remarks>
+ </member>
+ <member name="F:log4net.Core.FixFlags.Domain">
+ <summary>
+ Fix the domain friendly name
+ </summary>
+ </member>
+ <member name="F:log4net.Core.FixFlags.Identity">
+ <summary>
+ Fix the callers principal name
+ </summary>
+ <remarks>
+ CAUTION: May be slow to generate
+ </remarks>
+ </member>
+ <member name="F:log4net.Core.FixFlags.Exception">
+ <summary>
+ Fix the exception text
+ </summary>
+ </member>
+ <member name="F:log4net.Core.FixFlags.Properties">
+ <summary>
+ Fix the event properties
+ </summary>
+ </member>
+ <member name="F:log4net.Core.FixFlags.None">
+ <summary>
+ No fields fixed
+ </summary>
+ </member>
+ <member name="F:log4net.Core.FixFlags.All">
+ <summary>
+ All fields fixed
+ </summary>
+ </member>
+ <member name="F:log4net.Core.FixFlags.Partial">
+ <summary>
+ Partial fields fixed
+ </summary>
+ <remarks>
+ <para>
+ This set of partial fields gives good performance. The following fields are fixed:
+ </para>
+ <list type="bullet">
+ <item><description><see cref="F:log4net.Core.FixFlags.Message"/></description></item>
+ <item><description><see cref="F:log4net.Core.FixFlags.ThreadName"/></description></item>
+ <item><description><see cref="F:log4net.Core.FixFlags.Exception"/></description></item>
+ <item><description><see cref="F:log4net.Core.FixFlags.Domain"/></description></item>
+ <item><description><see cref="F:log4net.Core.FixFlags.Properties"/></description></item>
+ </list>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.LoggingEvent">
+ <summary>
+ The internal representation of logging events.
+ </summary>
+ <remarks>
+ <para>
+ When an affirmative decision is made to log then a
+ <see cref="T:log4net.Core.LoggingEvent"/> instance is created. This instance
+ is passed around to the different log4net components.
+ </para>
+ <para>
+ This class is of concern to those wishing to extend log4net.
+ </para>
+ <para>
+ Some of the values in instances of <see cref="T:log4net.Core.LoggingEvent"/>
+ are considered volatile, that is the values are correct at the
+ time the event is delivered to appenders, but will not be consistent
+ at any time afterwards. If an event is to be stored and then processed
+ at a later time these volatile values must be fixed by calling
+ <see cref="M:log4net.Core.LoggingEvent.FixVolatileData"/>. There is a performance penalty
+ for incurred by calling <see cref="M:log4net.Core.LoggingEvent.FixVolatileData"/> but it
+ is essential to maintaining data consistency.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ <author>Douglas de la Torre</author>
+ <author>Daniel Cazzulino</author>
+ </member>
+ <member name="F:log4net.Core.LoggingEvent.HostNameProperty">
+ <summary>
+ The key into the Properties map for the host name value.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.LoggingEvent.IdentityProperty">
+ <summary>
+ The key into the Properties map for the thread identity value.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.LoggingEvent.UserNameProperty">
+ <summary>
+ The key into the Properties map for the user name value.
+ </summary>
+ </member>
+ <member name="M:log4net.Core.LoggingEvent.#ctor(System.Type,log4net.Repository.ILoggerRepository,System.String,log4net.Core.Level,System.Object,System.Exception)">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Core.LoggingEvent"/> class
+ from the supplied parameters.
+ </summary>
+ <param name="callerStackBoundaryDeclaringType">The declaring type of the method that is
+ the stack boundary into the logging system for this call.</param>
+ <param name="repository">The repository this event is logged in.</param>
+ <param name="loggerName">The name of the logger of this event.</param>
+ <param name="level">The level of this event.</param>
+ <param name="message">The message of this event.</param>
+ <param name="exception">The exception for this event.</param>
+ <remarks>
+ <para>
+ Except <see cref="P:log4net.Core.LoggingEvent.TimeStamp"/>, <see cref="P:log4net.Core.LoggingEvent.Level"/> and <see cref="P:log4net.Core.LoggingEvent.LoggerName"/>,
+ all fields of <c>LoggingEvent</c> are filled when actually needed. Call
+ <see cref="M:log4net.Core.LoggingEvent.FixVolatileData"/> to cache all data locally
+ to prevent inconsistencies.
+ </para>
+ <para>This method is called by the log4net framework
+ to create a logging event.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggingEvent.#ctor(System.Type,log4net.Repository.ILoggerRepository,log4net.Core.LoggingEventData,log4net.Core.FixFlags)">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Core.LoggingEvent"/> class
+ using specific data.
+ </summary>
+ <param name="callerStackBoundaryDeclaringType">The declaring type of the method that is
+ the stack boundary into the logging system for this call.</param>
+ <param name="repository">The repository this event is logged in.</param>
+ <param name="data">Data used to initialize the logging event.</param>
+ <param name="fixedData">The fields in the <paranref name="data"/> struct that have already been fixed.</param>
+ <remarks>
+ <para>
+ This constructor is provided to allow a <see cref="T:log4net.Core.LoggingEvent"/>
+ to be created independently of the log4net framework. This can
+ be useful if you require a custom serialization scheme.
+ </para>
+ <para>
+ Use the <see cref="M:log4net.Core.LoggingEvent.GetLoggingEventData(log4net.Core.FixFlags)"/> method to obtain an
+ instance of the <see cref="T:log4net.Core.LoggingEventData"/> class.
+ </para>
+ <para>
+ The <paramref name="fixedData"/> parameter should be used to specify which fields in the
+ <paramref name="data"/> struct have been preset. Fields not specified in the <paramref name="fixedData"/>
+ will be captured from the environment if requested or fixed.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggingEvent.#ctor(System.Type,log4net.Repository.ILoggerRepository,log4net.Core.LoggingEventData)">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Core.LoggingEvent"/> class
+ using specific data.
+ </summary>
+ <param name="callerStackBoundaryDeclaringType">The declaring type of the method that is
+ the stack boundary into the logging system for this call.</param>
+ <param name="repository">The repository this event is logged in.</param>
+ <param name="data">Data used to initialize the logging event.</param>
+ <remarks>
+ <para>
+ This constructor is provided to allow a <see cref="T:log4net.Core.LoggingEvent"/>
+ to be created independently of the log4net framework. This can
+ be useful if you require a custom serialization scheme.
+ </para>
+ <para>
+ Use the <see cref="M:log4net.Core.LoggingEvent.GetLoggingEventData(log4net.Core.FixFlags)"/> method to obtain an
+ instance of the <see cref="T:log4net.Core.LoggingEventData"/> class.
+ </para>
+ <para>
+ This constructor sets this objects <see cref="P:log4net.Core.LoggingEvent.Fix"/> flags to <see cref="F:log4net.Core.FixFlags.All"/>,
+ this assumes that all the data relating to this event is passed in via the <paramref name="data"/>
+ parameter and no other data should be captured from the environment.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggingEvent.#ctor(log4net.Core.LoggingEventData)">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Core.LoggingEvent"/> class
+ using specific data.
+ </summary>
+ <param name="data">Data used to initialize the logging event.</param>
+ <remarks>
+ <para>
+ This constructor is provided to allow a <see cref="T:log4net.Core.LoggingEvent"/>
+ to be created independently of the log4net framework. This can
+ be useful if you require a custom serialization scheme.
+ </para>
+ <para>
+ Use the <see cref="M:log4net.Core.LoggingEvent.GetLoggingEventData(log4net.Core.FixFlags)"/> method to obtain an
+ instance of the <see cref="T:log4net.Core.LoggingEventData"/> class.
+ </para>
+ <para>
+ This constructor sets this objects <see cref="P:log4net.Core.LoggingEvent.Fix"/> flags to <see cref="F:log4net.Core.FixFlags.All"/>,
+ this assumes that all the data relating to this event is passed in via the <paramref name="data"/>
+ parameter and no other data should be captured from the environment.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggingEvent.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)">
+ <summary>
+ Serialization constructor
+ </summary>
+ <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> that holds the serialized object data.</param>
+ <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext"/> that contains contextual information about the source or destination.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Core.LoggingEvent"/> class
+ with serialized data.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggingEvent.EnsureRepository(log4net.Repository.ILoggerRepository)">
+ <summary>
+ Ensure that the repository is set.
+ </summary>
+ <param name="repository">the value for the repository</param>
+ </member>
+ <member name="M:log4net.Core.LoggingEvent.WriteRenderedMessage(System.IO.TextWriter)">
+ <summary>
+ Write the rendered message to a TextWriter
+ </summary>
+ <param name="writer">the writer to write the message to</param>
+ <remarks>
+ <para>
+ Unlike the <see cref="P:log4net.Core.LoggingEvent.RenderedMessage"/> property this method
+ does store the message data in the internal cache. Therefore
+ if called only once this method should be faster than the
+ <see cref="P:log4net.Core.LoggingEvent.RenderedMessage"/> property, however if the message is
+ to be accessed multiple times then the property will be more efficient.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggingEvent.GetObjectData(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)">
+ <summary>
+ Serializes this object into the <see cref="T:System.Runtime.Serialization.SerializationInfo"/> provided.
+ </summary>
+ <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> to populate with data.</param>
+ <param name="context">The destination for this serialization.</param>
+ <remarks>
+ <para>
+ The data in this event must be fixed before it can be serialized.
+ </para>
+ <para>
+ The <see cref="M:log4net.Core.LoggingEvent.FixVolatileData"/> method must be called during the
+ <see cref="M:log4net.Appender.IAppender.DoAppend(log4net.Core.LoggingEvent)"/> method call if this event
+ is to be used outside that method.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggingEvent.GetLoggingEventData">
+ <summary>
+ Gets the portable data for this <see cref="T:log4net.Core.LoggingEvent"/>.
+ </summary>
+ <returns>The <see cref="T:log4net.Core.LoggingEventData"/> for this event.</returns>
+ <remarks>
+ <para>
+ A new <see cref="T:log4net.Core.LoggingEvent"/> can be constructed using a
+ <see cref="T:log4net.Core.LoggingEventData"/> instance.
+ </para>
+ <para>
+ Does a <see cref="F:log4net.Core.FixFlags.Partial"/> fix of the data
+ in the logging event before returning the event data.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggingEvent.GetLoggingEventData(log4net.Core.FixFlags)">
+ <summary>
+ Gets the portable data for this <see cref="T:log4net.Core.LoggingEvent"/>.
+ </summary>
+ <param name="fixFlags">The set of data to ensure is fixed in the LoggingEventData</param>
+ <returns>The <see cref="T:log4net.Core.LoggingEventData"/> for this event.</returns>
+ <remarks>
+ <para>
+ A new <see cref="T:log4net.Core.LoggingEvent"/> can be constructed using a
+ <see cref="T:log4net.Core.LoggingEventData"/> instance.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggingEvent.GetExceptionStrRep">
+ <summary>
+ Returns this event's exception's rendered using the
+ <see cref="P:log4net.Repository.ILoggerRepository.RendererMap"/>.
+ </summary>
+ <returns>
+ This event's exception's rendered using the <see cref="P:log4net.Repository.ILoggerRepository.RendererMap"/>.
+ </returns>
+ <remarks>
+ <para>
+ <b>Obsolete. Use <see cref="M:log4net.Core.LoggingEvent.GetExceptionString"/> instead.</b>
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggingEvent.GetExceptionString">
+ <summary>
+ Returns this event's exception's rendered using the
+ <see cref="P:log4net.Repository.ILoggerRepository.RendererMap"/>.
+ </summary>
+ <returns>
+ This event's exception's rendered using the <see cref="P:log4net.Repository.ILoggerRepository.RendererMap"/>.
+ </returns>
+ <remarks>
+ <para>
+ Returns this event's exception's rendered using the
+ <see cref="P:log4net.Repository.ILoggerRepository.RendererMap"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggingEvent.FixVolatileData">
+ <summary>
+ Fix instance fields that hold volatile data.
+ </summary>
+ <remarks>
+ <para>
+ Some of the values in instances of <see cref="T:log4net.Core.LoggingEvent"/>
+ are considered volatile, that is the values are correct at the
+ time the event is delivered to appenders, but will not be consistent
+ at any time afterwards. If an event is to be stored and then processed
+ at a later time these volatile values must be fixed by calling
+ <see cref="M:log4net.Core.LoggingEvent.FixVolatileData"/>. There is a performance penalty
+ incurred by calling <see cref="M:log4net.Core.LoggingEvent.FixVolatileData"/> but it
+ is essential to maintaining data consistency.
+ </para>
+ <para>
+ Calling <see cref="M:log4net.Core.LoggingEvent.FixVolatileData"/> is equivalent to
+ calling <see cref="M:log4net.Core.LoggingEvent.FixVolatileData(System.Boolean)"/> passing the parameter
+ <c>false</c>.
+ </para>
+ <para>
+ See <see cref="M:log4net.Core.LoggingEvent.FixVolatileData(System.Boolean)"/> for more
+ information.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggingEvent.FixVolatileData(System.Boolean)">
+ <summary>
+ Fixes instance fields that hold volatile data.
+ </summary>
+ <param name="fastButLoose">Set to <c>true</c> to not fix data that takes a long time to fix.</param>
+ <remarks>
+ <para>
+ Some of the values in instances of <see cref="T:log4net.Core.LoggingEvent"/>
+ are considered volatile, that is the values are correct at the
+ time the event is delivered to appenders, but will not be consistent
+ at any time afterwards. If an event is to be stored and then processed
+ at a later time these volatile values must be fixed by calling
+ <see cref="M:log4net.Core.LoggingEvent.FixVolatileData"/>. There is a performance penalty
+ for incurred by calling <see cref="M:log4net.Core.LoggingEvent.FixVolatileData"/> but it
+ is essential to maintaining data consistency.
+ </para>
+ <para>
+ The <paramref name="fastButLoose"/> param controls the data that
+ is fixed. Some of the data that can be fixed takes a long time to
+ generate, therefore if you do not require those settings to be fixed
+ they can be ignored by setting the <paramref name="fastButLoose"/> param
+ to <c>true</c>. This setting will ignore the <see cref="P:log4net.Core.LoggingEvent.LocationInformation"/>
+ and <see cref="P:log4net.Core.LoggingEvent.UserName"/> settings.
+ </para>
+ <para>
+ Set <paramref name="fastButLoose"/> to <c>false</c> to ensure that all
+ settings are fixed.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggingEvent.FixVolatileData(log4net.Core.FixFlags)">
+ <summary>
+ Fix the fields specified by the <see cref="T:log4net.Core.FixFlags"/> parameter
+ </summary>
+ <param name="flags">the fields to fix</param>
+ <remarks>
+ <para>
+ Only fields specified in the <paramref name="flags"/> will be fixed.
+ Fields will not be fixed if they have previously been fixed.
+ It is not possible to 'unfix' a field.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggingEvent.LookupProperty(System.String)">
+ <summary>
+ Lookup a composite property in this event
+ </summary>
+ <param name="key">the key for the property to lookup</param>
+ <returns>the value for the property</returns>
+ <remarks>
+ <para>
+ This event has composite properties that combine together properties from
+ several different contexts in the following order:
+ <list type="definition">
+ <item>
+ <term>this events properties</term>
+ <description>
+ This event has <see cref="P:log4net.Core.LoggingEvent.Properties"/> that can be set. These
+ properties are specific to this event only.
+ </description>
+ </item>
+ <item>
+ <term>the thread properties</term>
+ <description>
+ The <see cref="P:log4net.ThreadContext.Properties"/> that are set on the current
+ thread. These properties are shared by all events logged on this thread.
+ </description>
+ </item>
+ <item>
+ <term>the global properties</term>
+ <description>
+ The <see cref="P:log4net.GlobalContext.Properties"/> that are set globally. These
+ properties are shared by all the threads in the AppDomain.
+ </description>
+ </item>
+ </list>
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LoggingEvent.GetProperties">
+ <summary>
+ Get all the composite properties in this event
+ </summary>
+ <returns>the <see cref="T:log4net.Util.PropertiesDictionary"/> containing all the properties</returns>
+ <remarks>
+ <para>
+ See <see cref="M:log4net.Core.LoggingEvent.LookupProperty(System.String)"/> for details of the composite properties
+ stored by the event.
+ </para>
+ <para>
+ This method returns a single <see cref="T:log4net.Util.PropertiesDictionary"/> containing all the
+ properties defined for this event.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Core.LoggingEvent.m_data">
+ <summary>
+ The internal logging event data.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.LoggingEvent.m_compositeProperties">
+ <summary>
+ The internal logging event data.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.LoggingEvent.m_eventProperties">
+ <summary>
+ The internal logging event data.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.LoggingEvent.m_callerStackBoundaryDeclaringType">
+ <summary>
+ The fully qualified Type of the calling
+ logger class in the stack frame (i.e. the declaring type of the method).
+ </summary>
+ </member>
+ <member name="F:log4net.Core.LoggingEvent.m_message">
+ <summary>
+ The application supplied message of logging event.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.LoggingEvent.m_thrownException">
+ <summary>
+ The exception that was thrown.
+ </summary>
+ <remarks>
+ This is not serialized. The string representation
+ is serialized instead.
+ </remarks>
+ </member>
+ <member name="F:log4net.Core.LoggingEvent.m_repository">
+ <summary>
+ The repository that generated the logging event
+ </summary>
+ <remarks>
+ This is not serialized.
+ </remarks>
+ </member>
+ <member name="F:log4net.Core.LoggingEvent.m_fixFlags">
+ <summary>
+ The fix state for this event
+ </summary>
+ <remarks>
+ These flags indicate which fields have been fixed.
+ Not serialized.
+ </remarks>
+ </member>
+ <member name="F:log4net.Core.LoggingEvent.m_cacheUpdatable">
+ <summary>
+ Indicated that the internal cache is updateable (ie not fixed)
+ </summary>
+ <remarks>
+ This is a seperate flag to m_fixFlags as it allows incrementel fixing and simpler
+ changes in the caching strategy.
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LoggingEvent.StartTime">
+ <summary>
+ Gets the time when the current process started.
+ </summary>
+ <value>
+ This is the time when this process started.
+ </value>
+ <remarks>
+ <para>
+ The TimeStamp is stored in the local time zone for this computer.
+ </para>
+ <para>
+ Tries to get the start time for the current process.
+ Failing that it returns the time of the first call to
+ this property.
+ </para>
+ <para>
+ Note that AppDomains may be loaded and unloaded within the
+ same process without the process terminating and therefore
+ without the process start time being reset.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LoggingEvent.Level">
+ <summary>
+ Gets the <see cref="P:log4net.Core.LoggingEvent.Level"/> of the logging event.
+ </summary>
+ <value>
+ The <see cref="P:log4net.Core.LoggingEvent.Level"/> of the logging event.
+ </value>
+ <remarks>
+ <para>
+ Gets the <see cref="P:log4net.Core.LoggingEvent.Level"/> of the logging event.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LoggingEvent.TimeStamp">
+ <summary>
+ Gets the time of the logging event.
+ </summary>
+ <value>
+ The time of the logging event.
+ </value>
+ <remarks>
+ <para>
+ The TimeStamp is stored in the local time zone for this computer.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LoggingEvent.LoggerName">
+ <summary>
+ Gets the name of the logger that logged the event.
+ </summary>
+ <value>
+ The name of the logger that logged the event.
+ </value>
+ <remarks>
+ <para>
+ Gets the name of the logger that logged the event.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LoggingEvent.LocationInformation">
+ <summary>
+ Gets the location information for this logging event.
+ </summary>
+ <value>
+ The location information for this logging event.
+ </value>
+ <remarks>
+ <para>
+ The collected information is cached for future use.
+ </para>
+ <para>
+ See the <see cref="T:log4net.Core.LocationInfo"/> class for more information on
+ supported frameworks and the different behavior in Debug and
+ Release builds.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LoggingEvent.MessageObject">
+ <summary>
+ Gets the message object used to initialize this event.
+ </summary>
+ <value>
+ The message object used to initialize this event.
+ </value>
+ <remarks>
+ <para>
+ Gets the message object used to initialize this event.
+ Note that this event may not have a valid message object.
+ If the event is serialized the message object will not
+ be transferred. To get the text of the message the
+ <see cref="P:log4net.Core.LoggingEvent.RenderedMessage"/> property must be used
+ not this property.
+ </para>
+ <para>
+ If there is no defined message object for this event then
+ null will be returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LoggingEvent.ExceptionObject">
+ <summary>
+ Gets the exception object used to initialize this event.
+ </summary>
+ <value>
+ The exception object used to initialize this event.
+ </value>
+ <remarks>
+ <para>
+ Gets the exception object used to initialize this event.
+ Note that this event may not have a valid exception object.
+ If the event is serialized the exception object will not
+ be transferred. To get the text of the exception the
+ <see cref="M:log4net.Core.LoggingEvent.GetExceptionString"/> method must be used
+ not this property.
+ </para>
+ <para>
+ If there is no defined exception object for this event then
+ null will be returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LoggingEvent.Repository">
+ <summary>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> that this event was created in.
+ </summary>
+ <remarks>
+ <para>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> that this event was created in.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LoggingEvent.RenderedMessage">
+ <summary>
+ Gets the message, rendered through the <see cref="P:log4net.Repository.ILoggerRepository.RendererMap"/>.
+ </summary>
+ <value>
+ The message rendered through the <see cref="P:log4net.Repository.ILoggerRepository.RendererMap"/>.
+ </value>
+ <remarks>
+ <para>
+ The collected information is cached for future use.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LoggingEvent.ThreadName">
+ <summary>
+ Gets the name of the current thread.
+ </summary>
+ <value>
+ The name of the current thread, or the thread ID when
+ the name is not available.
+ </value>
+ <remarks>
+ <para>
+ The collected information is cached for future use.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LoggingEvent.UserName">
+ <summary>
+ Gets the name of the current user.
+ </summary>
+ <value>
+ The name of the current user, or <c>NOT AVAILABLE</c> when the
+ underlying runtime has no support for retrieving the name of the
+ current user.
+ </value>
+ <remarks>
+ <para>
+ Calls <c>WindowsIdentity.GetCurrent().Name</c> to get the name of
+ the current windows user.
+ </para>
+ <para>
+ To improve performance, we could cache the string representation of
+ the name, and reuse that as long as the identity stayed constant.
+ Once the identity changed, we would need to re-assign and re-render
+ the string.
+ </para>
+ <para>
+ However, the <c>WindowsIdentity.GetCurrent()</c> call seems to
+ return different objects every time, so the current implementation
+ doesn't do this type of caching.
+ </para>
+ <para>
+ Timing for these operations:
+ </para>
+ <list type="table">
+ <listheader>
+ <term>Method</term>
+ <description>Results</description>
+ </listheader>
+ <item>
+ <term><c>WindowsIdentity.GetCurrent()</c></term>
+ <description>10000 loops, 00:00:00.2031250 seconds</description>
+ </item>
+ <item>
+ <term><c>WindowsIdentity.GetCurrent().Name</c></term>
+ <description>10000 loops, 00:00:08.0468750 seconds</description>
+ </item>
+ </list>
+ <para>
+ This means we could speed things up almost 40 times by caching the
+ value of the <c>WindowsIdentity.GetCurrent().Name</c> property, since
+ this takes (8.04-0.20) = 7.84375 seconds.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LoggingEvent.Identity">
+ <summary>
+ Gets the identity of the current thread principal.
+ </summary>
+ <value>
+ The string name of the identity of the current thread principal.
+ </value>
+ <remarks>
+ <para>
+ Calls <c>System.Threading.Thread.CurrentPrincipal.Identity.Name</c> to get
+ the name of the current thread principal.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LoggingEvent.Domain">
+ <summary>
+ Gets the AppDomain friendly name.
+ </summary>
+ <value>
+ The AppDomain friendly name.
+ </value>
+ <remarks>
+ <para>
+ Gets the AppDomain friendly name.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LoggingEvent.Properties">
+ <summary>
+ Additional event specific properties.
+ </summary>
+ <value>
+ Additional event specific properties.
+ </value>
+ <remarks>
+ <para>
+ A logger or an appender may attach additional
+ properties to specific events. These properties
+ have a string key and an object value.
+ </para>
+ <para>
+ This property is for events that have been added directly to
+ this event. The aggregate properties (which include these
+ event properties) can be retrieved using <see cref="M:log4net.Core.LoggingEvent.LookupProperty(System.String)"/>
+ and <see cref="M:log4net.Core.LoggingEvent.GetProperties"/>.
+ </para>
+ <para>
+ Once the properties have been fixed <see cref="P:log4net.Core.LoggingEvent.Fix"/> this property
+ returns the combined cached properties. This ensures that updates to
+ this property are always reflected in the underlying storage. When
+ returning the combined properties there may be more keys in the
+ Dictionary than expected.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LoggingEvent.Fix">
+ <summary>
+ The fixed fields in this event
+ </summary>
+ <value>
+ The set of fields that are fixed in this event
+ </value>
+ <remarks>
+ <para>
+ Fields will not be fixed if they have previously been fixed.
+ It is not possible to 'unfix' a field.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.LogImpl">
+ <summary>
+ Implementation of <see cref="T:log4net.ILog"/> wrapper interface.
+ </summary>
+ <remarks>
+ <para>
+ This implementation of the <see cref="T:log4net.ILog"/> interface
+ forwards to the <see cref="T:log4net.Core.ILogger"/> held by the base class.
+ </para>
+ <para>
+ This logger has methods to allow the caller to log at the following
+ levels:
+ </para>
+ <list type="definition">
+ <item>
+ <term>DEBUG</term>
+ <description>
+ The <see cref="M:log4net.Core.LogImpl.Debug(System.Object)"/> and <see cref="M:log4net.Core.LogImpl.DebugFormat(System.String,System.Object[])"/> methods log messages
+ at the <c>DEBUG</c> level. That is the level with that name defined in the
+ repositories <see cref="P:log4net.Repository.ILoggerRepository.LevelMap"/>. The default value
+ for this level is <see cref="F:log4net.Core.Level.Debug"/>. The <see cref="P:log4net.Core.LogImpl.IsDebugEnabled"/>
+ property tests if this level is enabled for logging.
+ </description>
+ </item>
+ <item>
+ <term>INFO</term>
+ <description>
+ The <see cref="M:log4net.Core.LogImpl.Info(System.Object)"/> and <see cref="M:log4net.Core.LogImpl.InfoFormat(System.String,System.Object[])"/> methods log messages
+ at the <c>INFO</c> level. That is the level with that name defined in the
+ repositories <see cref="P:log4net.Repository.ILoggerRepository.LevelMap"/>. The default value
+ for this level is <see cref="F:log4net.Core.Level.Info"/>. The <see cref="P:log4net.Core.LogImpl.IsInfoEnabled"/>
+ property tests if this level is enabled for logging.
+ </description>
+ </item>
+ <item>
+ <term>WARN</term>
+ <description>
+ The <see cref="M:log4net.Core.LogImpl.Warn(System.Object)"/> and <see cref="M:log4net.Core.LogImpl.WarnFormat(System.String,System.Object[])"/> methods log messages
+ at the <c>WARN</c> level. That is the level with that name defined in the
+ repositories <see cref="P:log4net.Repository.ILoggerRepository.LevelMap"/>. The default value
+ for this level is <see cref="F:log4net.Core.Level.Warn"/>. The <see cref="P:log4net.Core.LogImpl.IsWarnEnabled"/>
+ property tests if this level is enabled for logging.
+ </description>
+ </item>
+ <item>
+ <term>ERROR</term>
+ <description>
+ The <see cref="M:log4net.Core.LogImpl.Error(System.Object)"/> and <see cref="M:log4net.Core.LogImpl.ErrorFormat(System.String,System.Object[])"/> methods log messages
+ at the <c>ERROR</c> level. That is the level with that name defined in the
+ repositories <see cref="P:log4net.Repository.ILoggerRepository.LevelMap"/>. The default value
+ for this level is <see cref="F:log4net.Core.Level.Error"/>. The <see cref="P:log4net.Core.LogImpl.IsErrorEnabled"/>
+ property tests if this level is enabled for logging.
+ </description>
+ </item>
+ <item>
+ <term>FATAL</term>
+ <description>
+ The <see cref="M:log4net.Core.LogImpl.Fatal(System.Object)"/> and <see cref="M:log4net.Core.LogImpl.FatalFormat(System.String,System.Object[])"/> methods log messages
+ at the <c>FATAL</c> level. That is the level with that name defined in the
+ repositories <see cref="P:log4net.Repository.ILoggerRepository.LevelMap"/>. The default value
+ for this level is <see cref="F:log4net.Core.Level.Fatal"/>. The <see cref="P:log4net.Core.LogImpl.IsFatalEnabled"/>
+ property tests if this level is enabled for logging.
+ </description>
+ </item>
+ </list>
+ <para>
+ The values for these levels and their semantic meanings can be changed by
+ configuring the <see cref="P:log4net.Repository.ILoggerRepository.LevelMap"/> for the repository.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.ILog">
+ <summary>
+ The ILog interface is use by application to log messages into
+ the log4net framework.
+ </summary>
+ <remarks>
+ <para>
+ Use the <see cref="T:log4net.LogManager"/> to obtain logger instances
+ that implement this interface. The <see cref="M:log4net.LogManager.GetLogger(System.Reflection.Assembly,System.Type)"/>
+ static method is used to get logger instances.
+ </para>
+ <para>
+ This class contains methods for logging at different levels and also
+ has properties for determining if those logging levels are
+ enabled in the current configuration.
+ </para>
+ <para>
+ This interface can be implemented in different ways. This documentation
+ specifies reasonable behavior that a caller can expect from the actual
+ implementation, however different implementations reserve the right to
+ do things differently.
+ </para>
+ </remarks>
+ <example>Simple example of logging messages
+ <code lang="C#">
+ ILog log = LogManager.GetLogger("application-log");
+
+ log.Info("Application Start");
+ log.Debug("This is a debug message");
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("This is another debug message");
+ }
+ </code>
+ </example>
+ <seealso cref="T:log4net.LogManager"/>
+ <seealso cref="M:log4net.LogManager.GetLogger(System.Reflection.Assembly,System.Type)"/>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.ILog.Debug(System.Object)">
+ <overloads>Log a message object with the <see cref="F:log4net.Core.Level.Debug"/> level.</overloads>
+ <summary>
+ Log a message object with the <see cref="F:log4net.Core.Level.Debug"/> level.
+ </summary>
+ <param name="message">The message object to log.</param>
+ <remarks>
+ <para>
+ This method first checks if this logger is <c>DEBUG</c>
+ enabled by comparing the level of this logger with the
+ <see cref="F:log4net.Core.Level.Debug"/> level. If this logger is
+ <c>DEBUG</c> enabled, then it converts the message object
+ (passed as parameter) to a string by invoking the appropriate
+ <see cref="T:log4net.ObjectRenderer.IObjectRenderer"/>. It then
+ proceeds to call all the registered appenders in this logger
+ and also higher in the hierarchy depending on the value of
+ the additivity flag.
+ </para>
+ <para><b>WARNING</b> Note that passing an <see cref="T:System.Exception"/>
+ to this method will print the name of the <see cref="T:System.Exception"/>
+ but no stack trace. To print a stack trace use the
+ <see cref="M:log4net.ILog.Debug(System.Object,System.Exception)"/> form instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Debug(System.Object,System.Exception)"/>
+ <seealso cref="P:log4net.ILog.IsDebugEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.Debug(System.Object,System.Exception)">
+ <summary>
+ Log a message object with the <see cref="F:log4net.Core.Level.Debug"/> level including
+ the stack trace of the <see cref="T:System.Exception"/> passed
+ as a parameter.
+ </summary>
+ <param name="message">The message object to log.</param>
+ <param name="exception">The exception to log, including its stack trace.</param>
+ <remarks>
+ <para>
+ See the <see cref="M:log4net.ILog.Debug(System.Object)"/> form for more detailed information.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Debug(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsDebugEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.DebugFormat(System.String,System.Object[])">
+ <overloads>Log a formatted string with the <see cref="F:log4net.Core.Level.Debug"/> level.</overloads>
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Debug"/> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="args">An Object array containing zero or more objects to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Debug(System.Object,System.Exception)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Debug(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsDebugEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.DebugFormat(System.String,System.Object)">
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Debug"/> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Debug(System.Object,System.Exception)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Debug(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsDebugEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.DebugFormat(System.String,System.Object,System.Object)">
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Debug"/> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <param name="arg1">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Debug(System.Object,System.Exception)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Debug(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsDebugEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.DebugFormat(System.String,System.Object,System.Object,System.Object)">
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Debug"/> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <param name="arg1">An Object to format</param>
+ <param name="arg2">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Debug(System.Object,System.Exception)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Debug(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsDebugEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.DebugFormat(System.IFormatProvider,System.String,System.Object[])">
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Debug"/> level.
+ </summary>
+ <param name="provider">An <see cref="T:System.IFormatProvider"/> that supplies culture-specific formatting information</param>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="args">An Object array containing zero or more objects to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Debug(System.Object,System.Exception)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Debug(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsDebugEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.Info(System.Object)">
+ <overloads>Log a message object with the <see cref="F:log4net.Core.Level.Info"/> level.</overloads>
+ <summary>
+ Logs a message object with the <see cref="F:log4net.Core.Level.Info"/> level.
+ </summary>
+ <remarks>
+ <para>
+ This method first checks if this logger is <c>INFO</c>
+ enabled by comparing the level of this logger with the
+ <see cref="F:log4net.Core.Level.Info"/> level. If this logger is
+ <c>INFO</c> enabled, then it converts the message object
+ (passed as parameter) to a string by invoking the appropriate
+ <see cref="T:log4net.ObjectRenderer.IObjectRenderer"/>. It then
+ proceeds to call all the registered appenders in this logger
+ and also higher in the hierarchy depending on the value of the
+ additivity flag.
+ </para>
+ <para><b>WARNING</b> Note that passing an <see cref="T:System.Exception"/>
+ to this method will print the name of the <see cref="T:System.Exception"/>
+ but no stack trace. To print a stack trace use the
+ <see cref="M:log4net.ILog.Info(System.Object,System.Exception)"/> form instead.
+ </para>
+ </remarks>
+ <param name="message">The message object to log.</param>
+ <seealso cref="M:log4net.ILog.Info(System.Object,System.Exception)"/>
+ <seealso cref="P:log4net.ILog.IsInfoEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.Info(System.Object,System.Exception)">
+ <summary>
+ Logs a message object with the <c>INFO</c> level including
+ the stack trace of the <see cref="T:System.Exception"/> passed
+ as a parameter.
+ </summary>
+ <param name="message">The message object to log.</param>
+ <param name="exception">The exception to log, including its stack trace.</param>
+ <remarks>
+ <para>
+ See the <see cref="M:log4net.ILog.Info(System.Object)"/> form for more detailed information.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Info(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsInfoEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.InfoFormat(System.String,System.Object[])">
+ <overloads>Log a formatted message string with the <see cref="F:log4net.Core.Level.Info"/> level.</overloads>
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Info"/> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="args">An Object array containing zero or more objects to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Info(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Info(System.Object,System.Exception)"/>
+ <seealso cref="P:log4net.ILog.IsInfoEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.InfoFormat(System.String,System.Object)">
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Info"/> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Info(System.Object,System.Exception)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Info(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsInfoEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.InfoFormat(System.String,System.Object,System.Object)">
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Info"/> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <param name="arg1">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Info(System.Object,System.Exception)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Info(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsInfoEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.InfoFormat(System.String,System.Object,System.Object,System.Object)">
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Info"/> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <param name="arg1">An Object to format</param>
+ <param name="arg2">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Info(System.Object,System.Exception)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Info(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsInfoEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.InfoFormat(System.IFormatProvider,System.String,System.Object[])">
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Info"/> level.
+ </summary>
+ <param name="provider">An <see cref="T:System.IFormatProvider"/> that supplies culture-specific formatting information</param>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="args">An Object array containing zero or more objects to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Info(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Info(System.Object,System.Exception)"/>
+ <seealso cref="P:log4net.ILog.IsInfoEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.Warn(System.Object)">
+ <overloads>Log a message object with the <see cref="F:log4net.Core.Level.Warn"/> level.</overloads>
+ <summary>
+ Log a message object with the <see cref="F:log4net.Core.Level.Warn"/> level.
+ </summary>
+ <remarks>
+ <para>
+ This method first checks if this logger is <c>WARN</c>
+ enabled by comparing the level of this logger with the
+ <see cref="F:log4net.Core.Level.Warn"/> level. If this logger is
+ <c>WARN</c> enabled, then it converts the message object
+ (passed as parameter) to a string by invoking the appropriate
+ <see cref="T:log4net.ObjectRenderer.IObjectRenderer"/>. It then
+ proceeds to call all the registered appenders in this logger
+ and also higher in the hierarchy depending on the value of the
+ additivity flag.
+ </para>
+ <para><b>WARNING</b> Note that passing an <see cref="T:System.Exception"/>
+ to this method will print the name of the <see cref="T:System.Exception"/>
+ but no stack trace. To print a stack trace use the
+ <see cref="M:log4net.ILog.Warn(System.Object,System.Exception)"/> form instead.
+ </para>
+ </remarks>
+ <param name="message">The message object to log.</param>
+ <seealso cref="M:log4net.ILog.Warn(System.Object,System.Exception)"/>
+ <seealso cref="P:log4net.ILog.IsWarnEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.Warn(System.Object,System.Exception)">
+ <summary>
+ Log a message object with the <see cref="F:log4net.Core.Level.Warn"/> level including
+ the stack trace of the <see cref="T:System.Exception"/> passed
+ as a parameter.
+ </summary>
+ <param name="message">The message object to log.</param>
+ <param name="exception">The exception to log, including its stack trace.</param>
+ <remarks>
+ <para>
+ See the <see cref="M:log4net.ILog.Warn(System.Object)"/> form for more detailed information.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Warn(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsWarnEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.WarnFormat(System.String,System.Object[])">
+ <overloads>Log a formatted message string with the <see cref="F:log4net.Core.Level.Warn"/> level.</overloads>
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Warn"/> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="args">An Object array containing zero or more objects to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Warn(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Warn(System.Object,System.Exception)"/>
+ <seealso cref="P:log4net.ILog.IsWarnEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.WarnFormat(System.String,System.Object)">
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Warn"/> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Warn(System.Object,System.Exception)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Warn(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsWarnEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.WarnFormat(System.String,System.Object,System.Object)">
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Warn"/> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <param name="arg1">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Warn(System.Object,System.Exception)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Warn(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsWarnEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.WarnFormat(System.String,System.Object,System.Object,System.Object)">
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Warn"/> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <param name="arg1">An Object to format</param>
+ <param name="arg2">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Warn(System.Object,System.Exception)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Warn(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsWarnEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.WarnFormat(System.IFormatProvider,System.String,System.Object[])">
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Warn"/> level.
+ </summary>
+ <param name="provider">An <see cref="T:System.IFormatProvider"/> that supplies culture-specific formatting information</param>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="args">An Object array containing zero or more objects to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Warn(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Warn(System.Object,System.Exception)"/>
+ <seealso cref="P:log4net.ILog.IsWarnEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.Error(System.Object)">
+ <overloads>Log a message object with the <see cref="F:log4net.Core.Level.Error"/> level.</overloads>
+ <summary>
+ Logs a message object with the <see cref="F:log4net.Core.Level.Error"/> level.
+ </summary>
+ <param name="message">The message object to log.</param>
+ <remarks>
+ <para>
+ This method first checks if this logger is <c>ERROR</c>
+ enabled by comparing the level of this logger with the
+ <see cref="F:log4net.Core.Level.Error"/> level. If this logger is
+ <c>ERROR</c> enabled, then it converts the message object
+ (passed as parameter) to a string by invoking the appropriate
+ <see cref="T:log4net.ObjectRenderer.IObjectRenderer"/>. It then
+ proceeds to call all the registered appenders in this logger
+ and also higher in the hierarchy depending on the value of the
+ additivity flag.
+ </para>
+ <para><b>WARNING</b> Note that passing an <see cref="T:System.Exception"/>
+ to this method will print the name of the <see cref="T:System.Exception"/>
+ but no stack trace. To print a stack trace use the
+ <see cref="M:log4net.ILog.Error(System.Object,System.Exception)"/> form instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Error(System.Object,System.Exception)"/>
+ <seealso cref="P:log4net.ILog.IsErrorEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.Error(System.Object,System.Exception)">
+ <summary>
+ Log a message object with the <see cref="F:log4net.Core.Level.Error"/> level including
+ the stack trace of the <see cref="T:System.Exception"/> passed
+ as a parameter.
+ </summary>
+ <param name="message">The message object to log.</param>
+ <param name="exception">The exception to log, including its stack trace.</param>
+ <remarks>
+ <para>
+ See the <see cref="M:log4net.ILog.Error(System.Object)"/> form for more detailed information.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Error(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsErrorEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.ErrorFormat(System.String,System.Object[])">
+ <overloads>Log a formatted message string with the <see cref="F:log4net.Core.Level.Error"/> level.</overloads>
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Error"/> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="args">An Object array containing zero or more objects to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Error(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Error(System.Object,System.Exception)"/>
+ <seealso cref="P:log4net.ILog.IsErrorEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.ErrorFormat(System.String,System.Object)">
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Error"/> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Error(System.Object,System.Exception)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Error(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsErrorEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.ErrorFormat(System.String,System.Object,System.Object)">
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Error"/> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <param name="arg1">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Error(System.Object,System.Exception)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Error(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsErrorEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.ErrorFormat(System.String,System.Object,System.Object,System.Object)">
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Error"/> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <param name="arg1">An Object to format</param>
+ <param name="arg2">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Error(System.Object,System.Exception)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Error(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsErrorEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.ErrorFormat(System.IFormatProvider,System.String,System.Object[])">
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Error"/> level.
+ </summary>
+ <param name="provider">An <see cref="T:System.IFormatProvider"/> that supplies culture-specific formatting information</param>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="args">An Object array containing zero or more objects to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Error(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Error(System.Object,System.Exception)"/>
+ <seealso cref="P:log4net.ILog.IsErrorEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.Fatal(System.Object)">
+ <overloads>Log a message object with the <see cref="F:log4net.Core.Level.Fatal"/> level.</overloads>
+ <summary>
+ Log a message object with the <see cref="F:log4net.Core.Level.Fatal"/> level.
+ </summary>
+ <remarks>
+ <para>
+ This method first checks if this logger is <c>FATAL</c>
+ enabled by comparing the level of this logger with the
+ <see cref="F:log4net.Core.Level.Fatal"/> level. If this logger is
+ <c>FATAL</c> enabled, then it converts the message object
+ (passed as parameter) to a string by invoking the appropriate
+ <see cref="T:log4net.ObjectRenderer.IObjectRenderer"/>. It then
+ proceeds to call all the registered appenders in this logger
+ and also higher in the hierarchy depending on the value of the
+ additivity flag.
+ </para>
+ <para><b>WARNING</b> Note that passing an <see cref="T:System.Exception"/>
+ to this method will print the name of the <see cref="T:System.Exception"/>
+ but no stack trace. To print a stack trace use the
+ <see cref="M:log4net.ILog.Fatal(System.Object,System.Exception)"/> form instead.
+ </para>
+ </remarks>
+ <param name="message">The message object to log.</param>
+ <seealso cref="M:log4net.ILog.Fatal(System.Object,System.Exception)"/>
+ <seealso cref="P:log4net.ILog.IsFatalEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.Fatal(System.Object,System.Exception)">
+ <summary>
+ Log a message object with the <see cref="F:log4net.Core.Level.Fatal"/> level including
+ the stack trace of the <see cref="T:System.Exception"/> passed
+ as a parameter.
+ </summary>
+ <param name="message">The message object to log.</param>
+ <param name="exception">The exception to log, including its stack trace.</param>
+ <remarks>
+ <para>
+ See the <see cref="M:log4net.ILog.Fatal(System.Object)"/> form for more detailed information.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Fatal(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsFatalEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.FatalFormat(System.String,System.Object[])">
+ <overloads>Log a formatted message string with the <see cref="F:log4net.Core.Level.Fatal"/> level.</overloads>
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Fatal"/> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="args">An Object array containing zero or more objects to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Fatal(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Fatal(System.Object,System.Exception)"/>
+ <seealso cref="P:log4net.ILog.IsFatalEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.FatalFormat(System.String,System.Object)">
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Fatal"/> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Fatal(System.Object,System.Exception)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Fatal(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsFatalEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.FatalFormat(System.String,System.Object,System.Object)">
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Fatal"/> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <param name="arg1">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Fatal(System.Object,System.Exception)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Fatal(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsFatalEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.FatalFormat(System.String,System.Object,System.Object,System.Object)">
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Fatal"/> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <param name="arg1">An Object to format</param>
+ <param name="arg2">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Fatal(System.Object,System.Exception)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Fatal(System.Object)"/>
+ <seealso cref="P:log4net.ILog.IsFatalEnabled"/>
+ </member>
+ <member name="M:log4net.ILog.FatalFormat(System.IFormatProvider,System.String,System.Object[])">
+ <summary>
+ Logs a formatted message string with the <see cref="F:log4net.Core.Level.Fatal"/> level.
+ </summary>
+ <param name="provider">An <see cref="T:System.IFormatProvider"/> that supplies culture-specific formatting information</param>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="args">An Object array containing zero or more objects to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <c>String.Format</c> method. See
+ <see cref="M:System.String.Format(System.String,System.Object[])"/> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.ILog.Fatal(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Fatal(System.Object,System.Exception)"/>
+ <seealso cref="P:log4net.ILog.IsFatalEnabled"/>
+ </member>
+ <member name="P:log4net.ILog.IsDebugEnabled">
+ <summary>
+ Checks if this logger is enabled for the <see cref="F:log4net.Core.Level.Debug"/> level.
+ </summary>
+ <value>
+ <c>true</c> if this logger is enabled for <see cref="F:log4net.Core.Level.Debug"/> events, <c>false</c> otherwise.
+ </value>
+ <remarks>
+ <para>
+ This function is intended to lessen the computational cost of
+ disabled log debug statements.
+ </para>
+ <para> For some ILog interface <c>log</c>, when you write:</para>
+ <code lang="C#">
+ log.Debug("This is entry number: " + i );
+ </code>
+ <para>
+ You incur the cost constructing the message, string construction and concatenation in
+ this case, regardless of whether the message is logged or not.
+ </para>
+ <para>
+ If you are worried about speed (who isn't), then you should write:
+ </para>
+ <code lang="C#">
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("This is entry number: " + i );
+ }
+ </code>
+ <para>
+ This way you will not incur the cost of parameter
+ construction if debugging is disabled for <c>log</c>. On
+ the other hand, if the <c>log</c> is debug enabled, you
+ will incur the cost of evaluating whether the logger is debug
+ enabled twice. Once in <see cref="P:log4net.ILog.IsDebugEnabled"/> and once in
+ the <see cref="M:log4net.ILog.Debug(System.Object)"/>. This is an insignificant overhead
+ since evaluating a logger takes about 1% of the time it
+ takes to actually log. This is the preferred style of logging.
+ </para>
+ <para>Alternatively if your logger is available statically then the is debug
+ enabled state can be stored in a static variable like this:
+ </para>
+ <code lang="C#">
+ private static readonly bool isDebugEnabled = log.IsDebugEnabled;
+ </code>
+ <para>
+ Then when you come to log you can write:
+ </para>
+ <code lang="C#">
+ if (isDebugEnabled)
+ {
+ log.Debug("This is entry number: " + i );
+ }
+ </code>
+ <para>
+ This way the debug enabled state is only queried once
+ when the class is loaded. Using a <c>private static readonly</c>
+ variable is the most efficient because it is a run time constant
+ and can be heavily optimized by the JIT compiler.
+ </para>
+ <para>
+ Of course if you use a static readonly variable to
+ hold the enabled state of the logger then you cannot
+ change the enabled state at runtime to vary the logging
+ that is produced. You have to decide if you need absolute
+ speed or runtime flexibility.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.ILog.Debug(System.Object)"/>
+ <seealso cref="M:log4net.ILog.DebugFormat(System.IFormatProvider,System.String,System.Object[])"/>
+ </member>
+ <member name="P:log4net.ILog.IsInfoEnabled">
+ <summary>
+ Checks if this logger is enabled for the <see cref="F:log4net.Core.Level.Info"/> level.
+ </summary>
+ <value>
+ <c>true</c> if this logger is enabled for <see cref="F:log4net.Core.Level.Info"/> events, <c>false</c> otherwise.
+ </value>
+ <remarks>
+ For more information see <see cref="P:log4net.ILog.IsDebugEnabled"/>.
+ </remarks>
+ <seealso cref="M:log4net.ILog.Info(System.Object)"/>
+ <seealso cref="M:log4net.ILog.InfoFormat(System.IFormatProvider,System.String,System.Object[])"/>
+ <seealso cref="P:log4net.ILog.IsDebugEnabled"/>
+ </member>
+ <member name="P:log4net.ILog.IsWarnEnabled">
+ <summary>
+ Checks if this logger is enabled for the <see cref="F:log4net.Core.Level.Warn"/> level.
+ </summary>
+ <value>
+ <c>true</c> if this logger is enabled for <see cref="F:log4net.Core.Level.Warn"/> events, <c>false</c> otherwise.
+ </value>
+ <remarks>
+ For more information see <see cref="P:log4net.ILog.IsDebugEnabled"/>.
+ </remarks>
+ <seealso cref="M:log4net.ILog.Warn(System.Object)"/>
+ <seealso cref="M:log4net.ILog.WarnFormat(System.IFormatProvider,System.String,System.Object[])"/>
+ <seealso cref="P:log4net.ILog.IsDebugEnabled"/>
+ </member>
+ <member name="P:log4net.ILog.IsErrorEnabled">
+ <summary>
+ Checks if this logger is enabled for the <see cref="F:log4net.Core.Level.Error"/> level.
+ </summary>
+ <value>
+ <c>true</c> if this logger is enabled for <see cref="F:log4net.Core.Level.Error"/> events, <c>false</c> otherwise.
+ </value>
+ <remarks>
+ For more information see <see cref="P:log4net.ILog.IsDebugEnabled"/>.
+ </remarks>
+ <seealso cref="M:log4net.ILog.Error(System.Object)"/>
+ <seealso cref="M:log4net.ILog.ErrorFormat(System.IFormatProvider,System.String,System.Object[])"/>
+ <seealso cref="P:log4net.ILog.IsDebugEnabled"/>
+ </member>
+ <member name="P:log4net.ILog.IsFatalEnabled">
+ <summary>
+ Checks if this logger is enabled for the <see cref="F:log4net.Core.Level.Fatal"/> level.
+ </summary>
+ <value>
+ <c>true</c> if this logger is enabled for <see cref="F:log4net.Core.Level.Fatal"/> events, <c>false</c> otherwise.
+ </value>
+ <remarks>
+ For more information see <see cref="P:log4net.ILog.IsDebugEnabled"/>.
+ </remarks>
+ <seealso cref="M:log4net.ILog.Fatal(System.Object)"/>
+ <seealso cref="M:log4net.ILog.FatalFormat(System.IFormatProvider,System.String,System.Object[])"/>
+ <seealso cref="P:log4net.ILog.IsDebugEnabled"/>
+ </member>
+ <member name="M:log4net.Core.LogImpl.#ctor(log4net.Core.ILogger)">
+ <summary>
+ Construct a new wrapper for the specified logger.
+ </summary>
+ <param name="logger">The logger to wrap.</param>
+ <remarks>
+ <para>
+ Construct a new wrapper for the specified logger.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.ReloadLevels(log4net.Repository.ILoggerRepository)">
+ <summary>
+ Virtual method called when the configuration of the repository changes
+ </summary>
+ <param name="repository">the repository holding the levels</param>
+ <remarks>
+ <para>
+ Virtual method called when the configuration of the repository changes
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.Debug(System.Object)">
+ <summary>
+ Logs a message object with the <c>DEBUG</c> level.
+ </summary>
+ <param name="message">The message object to log.</param>
+ <remarks>
+ <para>
+ This method first checks if this logger is <c>DEBUG</c>
+ enabled by comparing the level of this logger with the
+ <c>DEBUG</c> level. If this logger is
+ <c>DEBUG</c> enabled, then it converts the message object
+ (passed as parameter) to a string by invoking the appropriate
+ <see cref="T:log4net.ObjectRenderer.IObjectRenderer"/>. It then
+ proceeds to call all the registered appenders in this logger
+ and also higher in the hierarchy depending on the value of the
+ additivity flag.
+ </para>
+ <para>
+ <b>WARNING</b> Note that passing an <see cref="T:System.Exception"/>
+ to this method will print the name of the <see cref="T:System.Exception"/>
+ but no stack trace. To print a stack trace use the
+ <see cref="M:log4net.Core.LogImpl.Debug(System.Object,System.Exception)"/> form instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.Debug(System.Object,System.Exception)">
+ <summary>
+ Logs a message object with the <c>DEBUG</c> level
+ </summary>
+ <param name="message">The message object to log.</param>
+ <param name="exception">The exception to log, including its stack trace.</param>
+ <remarks>
+ <para>
+ Logs a message object with the <c>DEBUG</c> level including
+ the stack trace of the <see cref="T:System.Exception"/> <paramref name="exception"/> passed
+ as a parameter.
+ </para>
+ <para>
+ See the <see cref="M:log4net.Core.LogImpl.Debug(System.Object)"/> form for more detailed information.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.Core.LogImpl.Debug(System.Object)"/>
+ </member>
+ <member name="M:log4net.Core.LogImpl.DebugFormat(System.String,System.Object[])">
+ <summary>
+ Logs a formatted message string with the <c>DEBUG</c> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="args">An Object array containing zero or more objects to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ The string is formatted using the <see cref="P:System.Globalization.CultureInfo.InvariantCulture"/>
+ format provider. To specify a localized provider use the
+ <see cref="M:log4net.Core.LogImpl.DebugFormat(System.IFormatProvider,System.String,System.Object[])"/> method.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Debug(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.DebugFormat(System.String,System.Object)">
+ <summary>
+ Logs a formatted message string with the <c>DEBUG</c> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ The string is formatted using the <see cref="P:System.Globalization.CultureInfo.InvariantCulture"/>
+ format provider. To specify a localized provider use the
+ <see cref="M:log4net.Core.LogImpl.DebugFormat(System.IFormatProvider,System.String,System.Object[])"/> method.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Debug(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.DebugFormat(System.String,System.Object,System.Object)">
+ <summary>
+ Logs a formatted message string with the <c>DEBUG</c> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <param name="arg1">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ The string is formatted using the <see cref="P:System.Globalization.CultureInfo.InvariantCulture"/>
+ format provider. To specify a localized provider use the
+ <see cref="M:log4net.Core.LogImpl.DebugFormat(System.IFormatProvider,System.String,System.Object[])"/> method.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Debug(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.DebugFormat(System.String,System.Object,System.Object,System.Object)">
+ <summary>
+ Logs a formatted message string with the <c>DEBUG</c> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <param name="arg1">An Object to format</param>
+ <param name="arg2">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ The string is formatted using the <see cref="P:System.Globalization.CultureInfo.InvariantCulture"/>
+ format provider. To specify a localized provider use the
+ <see cref="M:log4net.Core.LogImpl.DebugFormat(System.IFormatProvider,System.String,System.Object[])"/> method.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Debug(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.DebugFormat(System.IFormatProvider,System.String,System.Object[])">
+ <summary>
+ Logs a formatted message string with the <c>DEBUG</c> level.
+ </summary>
+ <param name="provider">An <see cref="T:System.IFormatProvider"/> that supplies culture-specific formatting information</param>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="args">An Object array containing zero or more objects to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Debug(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.Info(System.Object)">
+ <summary>
+ Logs a message object with the <c>INFO</c> level.
+ </summary>
+ <param name="message">The message object to log.</param>
+ <remarks>
+ <para>
+ This method first checks if this logger is <c>INFO</c>
+ enabled by comparing the level of this logger with the
+ <c>INFO</c> level. If this logger is
+ <c>INFO</c> enabled, then it converts the message object
+ (passed as parameter) to a string by invoking the appropriate
+ <see cref="T:log4net.ObjectRenderer.IObjectRenderer"/>. It then
+ proceeds to call all the registered appenders in this logger
+ and also higher in the hierarchy depending on the value of
+ the additivity flag.
+ </para>
+ <para>
+ <b>WARNING</b> Note that passing an <see cref="T:System.Exception"/>
+ to this method will print the name of the <see cref="T:System.Exception"/>
+ but no stack trace. To print a stack trace use the
+ <see cref="M:log4net.Core.LogImpl.Info(System.Object,System.Exception)"/> form instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.Info(System.Object,System.Exception)">
+ <summary>
+ Logs a message object with the <c>INFO</c> level.
+ </summary>
+ <param name="message">The message object to log.</param>
+ <param name="exception">The exception to log, including its stack trace.</param>
+ <remarks>
+ <para>
+ Logs a message object with the <c>INFO</c> level including
+ the stack trace of the <see cref="T:System.Exception"/> <paramref name="exception"/>
+ passed as a parameter.
+ </para>
+ <para>
+ See the <see cref="M:log4net.Core.LogImpl.Info(System.Object)"/> form for more detailed information.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.Core.LogImpl.Info(System.Object)"/>
+ </member>
+ <member name="M:log4net.Core.LogImpl.InfoFormat(System.String,System.Object[])">
+ <summary>
+ Logs a formatted message string with the <c>INFO</c> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="args">An Object array containing zero or more objects to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ The string is formatted using the <see cref="P:System.Globalization.CultureInfo.InvariantCulture"/>
+ format provider. To specify a localized provider use the
+ <see cref="M:log4net.Core.LogImpl.InfoFormat(System.IFormatProvider,System.String,System.Object[])"/> method.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Info(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.InfoFormat(System.String,System.Object)">
+ <summary>
+ Logs a formatted message string with the <c>INFO</c> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ The string is formatted using the <see cref="P:System.Globalization.CultureInfo.InvariantCulture"/>
+ format provider. To specify a localized provider use the
+ <see cref="M:log4net.Core.LogImpl.InfoFormat(System.IFormatProvider,System.String,System.Object[])"/> method.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Info(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.InfoFormat(System.String,System.Object,System.Object)">
+ <summary>
+ Logs a formatted message string with the <c>INFO</c> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <param name="arg1">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ The string is formatted using the <see cref="P:System.Globalization.CultureInfo.InvariantCulture"/>
+ format provider. To specify a localized provider use the
+ <see cref="M:log4net.Core.LogImpl.InfoFormat(System.IFormatProvider,System.String,System.Object[])"/> method.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Info(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.InfoFormat(System.String,System.Object,System.Object,System.Object)">
+ <summary>
+ Logs a formatted message string with the <c>INFO</c> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <param name="arg1">An Object to format</param>
+ <param name="arg2">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ The string is formatted using the <see cref="P:System.Globalization.CultureInfo.InvariantCulture"/>
+ format provider. To specify a localized provider use the
+ <see cref="M:log4net.Core.LogImpl.InfoFormat(System.IFormatProvider,System.String,System.Object[])"/> method.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Info(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.InfoFormat(System.IFormatProvider,System.String,System.Object[])">
+ <summary>
+ Logs a formatted message string with the <c>INFO</c> level.
+ </summary>
+ <param name="provider">An <see cref="T:System.IFormatProvider"/> that supplies culture-specific formatting information</param>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="args">An Object array containing zero or more objects to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Info(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.Warn(System.Object)">
+ <summary>
+ Logs a message object with the <c>WARN</c> level.
+ </summary>
+ <param name="message">the message object to log</param>
+ <remarks>
+ <para>
+ This method first checks if this logger is <c>WARN</c>
+ enabled by comparing the level of this logger with the
+ <c>WARN</c> level. If this logger is
+ <c>WARN</c> enabled, then it converts the message object
+ (passed as parameter) to a string by invoking the appropriate
+ <see cref="T:log4net.ObjectRenderer.IObjectRenderer"/>. It then
+ proceeds to call all the registered appenders in this logger and
+ also higher in the hierarchy depending on the value of the
+ additivity flag.
+ </para>
+ <para>
+ <b>WARNING</b> Note that passing an <see cref="T:System.Exception"/> to this
+ method will print the name of the <see cref="T:System.Exception"/> but no
+ stack trace. To print a stack trace use the
+ <see cref="M:log4net.Core.LogImpl.Warn(System.Object,System.Exception)"/> form instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.Warn(System.Object,System.Exception)">
+ <summary>
+ Logs a message object with the <c>WARN</c> level
+ </summary>
+ <param name="message">The message object to log.</param>
+ <param name="exception">The exception to log, including its stack trace.</param>
+ <remarks>
+ <para>
+ Logs a message object with the <c>WARN</c> level including
+ the stack trace of the <see cref="T:System.Exception"/> <paramref name="exception"/>
+ passed as a parameter.
+ </para>
+ <para>
+ See the <see cref="M:log4net.Core.LogImpl.Warn(System.Object)"/> form for more detailed information.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.Core.LogImpl.Warn(System.Object)"/>
+ </member>
+ <member name="M:log4net.Core.LogImpl.WarnFormat(System.String,System.Object[])">
+ <summary>
+ Logs a formatted message string with the <c>WARN</c> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="args">An Object array containing zero or more objects to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ The string is formatted using the <see cref="P:System.Globalization.CultureInfo.InvariantCulture"/>
+ format provider. To specify a localized provider use the
+ <see cref="M:log4net.Core.LogImpl.WarnFormat(System.IFormatProvider,System.String,System.Object[])"/> method.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Warn(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.WarnFormat(System.String,System.Object)">
+ <summary>
+ Logs a formatted message string with the <c>WARN</c> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ The string is formatted using the <see cref="P:System.Globalization.CultureInfo.InvariantCulture"/>
+ format provider. To specify a localized provider use the
+ <see cref="M:log4net.Core.LogImpl.WarnFormat(System.IFormatProvider,System.String,System.Object[])"/> method.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Warn(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.WarnFormat(System.String,System.Object,System.Object)">
+ <summary>
+ Logs a formatted message string with the <c>WARN</c> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <param name="arg1">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ The string is formatted using the <see cref="P:System.Globalization.CultureInfo.InvariantCulture"/>
+ format provider. To specify a localized provider use the
+ <see cref="M:log4net.Core.LogImpl.WarnFormat(System.IFormatProvider,System.String,System.Object[])"/> method.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Warn(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.WarnFormat(System.String,System.Object,System.Object,System.Object)">
+ <summary>
+ Logs a formatted message string with the <c>WARN</c> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <param name="arg1">An Object to format</param>
+ <param name="arg2">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ The string is formatted using the <see cref="P:System.Globalization.CultureInfo.InvariantCulture"/>
+ format provider. To specify a localized provider use the
+ <see cref="M:log4net.Core.LogImpl.WarnFormat(System.IFormatProvider,System.String,System.Object[])"/> method.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Warn(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.WarnFormat(System.IFormatProvider,System.String,System.Object[])">
+ <summary>
+ Logs a formatted message string with the <c>WARN</c> level.
+ </summary>
+ <param name="provider">An <see cref="T:System.IFormatProvider"/> that supplies culture-specific formatting information</param>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="args">An Object array containing zero or more objects to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Warn(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.Error(System.Object)">
+ <summary>
+ Logs a message object with the <c>ERROR</c> level.
+ </summary>
+ <param name="message">The message object to log.</param>
+ <remarks>
+ <para>
+ This method first checks if this logger is <c>ERROR</c>
+ enabled by comparing the level of this logger with the
+ <c>ERROR</c> level. If this logger is
+ <c>ERROR</c> enabled, then it converts the message object
+ (passed as parameter) to a string by invoking the appropriate
+ <see cref="T:log4net.ObjectRenderer.IObjectRenderer"/>. It then
+ proceeds to call all the registered appenders in this logger and
+ also higher in the hierarchy depending on the value of the
+ additivity flag.
+ </para>
+ <para>
+ <b>WARNING</b> Note that passing an <see cref="T:System.Exception"/> to this
+ method will print the name of the <see cref="T:System.Exception"/> but no
+ stack trace. To print a stack trace use the
+ <see cref="M:log4net.Core.LogImpl.Error(System.Object,System.Exception)"/> form instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.Error(System.Object,System.Exception)">
+ <summary>
+ Logs a message object with the <c>ERROR</c> level
+ </summary>
+ <param name="message">The message object to log.</param>
+ <param name="exception">The exception to log, including its stack trace.</param>
+ <remarks>
+ <para>
+ Logs a message object with the <c>ERROR</c> level including
+ the stack trace of the <see cref="T:System.Exception"/> <paramref name="exception"/>
+ passed as a parameter.
+ </para>
+ <para>
+ See the <see cref="M:log4net.Core.LogImpl.Error(System.Object)"/> form for more detailed information.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.Core.LogImpl.Error(System.Object)"/>
+ </member>
+ <member name="M:log4net.Core.LogImpl.ErrorFormat(System.String,System.Object[])">
+ <summary>
+ Logs a formatted message string with the <c>ERROR</c> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="args">An Object array containing zero or more objects to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ The string is formatted using the <see cref="P:System.Globalization.CultureInfo.InvariantCulture"/>
+ format provider. To specify a localized provider use the
+ <see cref="M:log4net.Core.LogImpl.ErrorFormat(System.IFormatProvider,System.String,System.Object[])"/> method.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Error(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.ErrorFormat(System.String,System.Object)">
+ <summary>
+ Logs a formatted message string with the <c>ERROR</c> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ The string is formatted using the <see cref="P:System.Globalization.CultureInfo.InvariantCulture"/>
+ format provider. To specify a localized provider use the
+ <see cref="M:log4net.Core.LogImpl.ErrorFormat(System.IFormatProvider,System.String,System.Object[])"/> method.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Error(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.ErrorFormat(System.String,System.Object,System.Object)">
+ <summary>
+ Logs a formatted message string with the <c>ERROR</c> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <param name="arg1">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ The string is formatted using the <see cref="P:System.Globalization.CultureInfo.InvariantCulture"/>
+ format provider. To specify a localized provider use the
+ <see cref="M:log4net.Core.LogImpl.ErrorFormat(System.IFormatProvider,System.String,System.Object[])"/> method.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Error(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.ErrorFormat(System.String,System.Object,System.Object,System.Object)">
+ <summary>
+ Logs a formatted message string with the <c>ERROR</c> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <param name="arg1">An Object to format</param>
+ <param name="arg2">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ The string is formatted using the <see cref="P:System.Globalization.CultureInfo.InvariantCulture"/>
+ format provider. To specify a localized provider use the
+ <see cref="M:log4net.Core.LogImpl.ErrorFormat(System.IFormatProvider,System.String,System.Object[])"/> method.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Error(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.ErrorFormat(System.IFormatProvider,System.String,System.Object[])">
+ <summary>
+ Logs a formatted message string with the <c>ERROR</c> level.
+ </summary>
+ <param name="provider">An <see cref="T:System.IFormatProvider"/> that supplies culture-specific formatting information</param>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="args">An Object array containing zero or more objects to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Error(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.Fatal(System.Object)">
+ <summary>
+ Logs a message object with the <c>FATAL</c> level.
+ </summary>
+ <param name="message">The message object to log.</param>
+ <remarks>
+ <para>
+ This method first checks if this logger is <c>FATAL</c>
+ enabled by comparing the level of this logger with the
+ <c>FATAL</c> level. If this logger is
+ <c>FATAL</c> enabled, then it converts the message object
+ (passed as parameter) to a string by invoking the appropriate
+ <see cref="T:log4net.ObjectRenderer.IObjectRenderer"/>. It then
+ proceeds to call all the registered appenders in this logger and
+ also higher in the hierarchy depending on the value of the
+ additivity flag.
+ </para>
+ <para>
+ <b>WARNING</b> Note that passing an <see cref="T:System.Exception"/> to this
+ method will print the name of the <see cref="T:System.Exception"/> but no
+ stack trace. To print a stack trace use the
+ <see cref="M:log4net.Core.LogImpl.Fatal(System.Object,System.Exception)"/> form instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.Fatal(System.Object,System.Exception)">
+ <summary>
+ Logs a message object with the <c>FATAL</c> level
+ </summary>
+ <param name="message">The message object to log.</param>
+ <param name="exception">The exception to log, including its stack trace.</param>
+ <remarks>
+ <para>
+ Logs a message object with the <c>FATAL</c> level including
+ the stack trace of the <see cref="T:System.Exception"/> <paramref name="exception"/>
+ passed as a parameter.
+ </para>
+ <para>
+ See the <see cref="M:log4net.Core.LogImpl.Fatal(System.Object)"/> form for more detailed information.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.Core.LogImpl.Fatal(System.Object)"/>
+ </member>
+ <member name="M:log4net.Core.LogImpl.FatalFormat(System.String,System.Object[])">
+ <summary>
+ Logs a formatted message string with the <c>FATAL</c> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="args">An Object array containing zero or more objects to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ The string is formatted using the <see cref="P:System.Globalization.CultureInfo.InvariantCulture"/>
+ format provider. To specify a localized provider use the
+ <see cref="M:log4net.Core.LogImpl.FatalFormat(System.IFormatProvider,System.String,System.Object[])"/> method.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Fatal(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.FatalFormat(System.String,System.Object)">
+ <summary>
+ Logs a formatted message string with the <c>FATAL</c> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ The string is formatted using the <see cref="P:System.Globalization.CultureInfo.InvariantCulture"/>
+ format provider. To specify a localized provider use the
+ <see cref="M:log4net.Core.LogImpl.FatalFormat(System.IFormatProvider,System.String,System.Object[])"/> method.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Fatal(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.FatalFormat(System.String,System.Object,System.Object)">
+ <summary>
+ Logs a formatted message string with the <c>FATAL</c> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <param name="arg1">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ The string is formatted using the <see cref="P:System.Globalization.CultureInfo.InvariantCulture"/>
+ format provider. To specify a localized provider use the
+ <see cref="M:log4net.Core.LogImpl.FatalFormat(System.IFormatProvider,System.String,System.Object[])"/> method.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Fatal(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.FatalFormat(System.String,System.Object,System.Object,System.Object)">
+ <summary>
+ Logs a formatted message string with the <c>FATAL</c> level.
+ </summary>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="arg0">An Object to format</param>
+ <param name="arg1">An Object to format</param>
+ <param name="arg2">An Object to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ The string is formatted using the <see cref="P:System.Globalization.CultureInfo.InvariantCulture"/>
+ format provider. To specify a localized provider use the
+ <see cref="M:log4net.Core.LogImpl.FatalFormat(System.IFormatProvider,System.String,System.Object[])"/> method.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Fatal(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.FatalFormat(System.IFormatProvider,System.String,System.Object[])">
+ <summary>
+ Logs a formatted message string with the <c>FATAL</c> level.
+ </summary>
+ <param name="provider">An <see cref="T:System.IFormatProvider"/> that supplies culture-specific formatting information</param>
+ <param name="format">A String containing zero or more format items</param>
+ <param name="args">An Object array containing zero or more objects to format</param>
+ <remarks>
+ <para>
+ The message is formatted using the <see cref="M:System.String.Format(System.IFormatProvider,System.String,System.Object[])"/> method. See
+ <c>String.Format</c> for details of the syntax of the format string and the behavior
+ of the formatting.
+ </para>
+ <para>
+ This method does not take an <see cref="T:System.Exception"/> object to include in the
+ log event. To pass an <see cref="T:System.Exception"/> use one of the <see cref="M:log4net.Core.LogImpl.Fatal(System.Object)"/>
+ methods instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.LogImpl.LoggerRepositoryConfigurationChanged(System.Object,System.EventArgs)">
+ <summary>
+ Event handler for the <see cref="E:log4net.Repository.ILoggerRepository.ConfigurationChanged"/> event
+ </summary>
+ <param name="sender">the repository</param>
+ <param name="e">Empty</param>
+ </member>
+ <member name="F:log4net.Core.LogImpl.ThisDeclaringType">
+ <summary>
+ The fully qualified name of this declaring type not the type of any subclass.
+ </summary>
+ </member>
+ <member name="P:log4net.Core.LogImpl.IsDebugEnabled">
+ <summary>
+ Checks if this logger is enabled for the <c>DEBUG</c>
+ level.
+ </summary>
+ <value>
+ <c>true</c> if this logger is enabled for <c>DEBUG</c> events,
+ <c>false</c> otherwise.
+ </value>
+ <remarks>
+ <para>
+ This function is intended to lessen the computational cost of
+ disabled log debug statements.
+ </para>
+ <para>
+ For some <c>log</c> Logger object, when you write:
+ </para>
+ <code lang="C#">
+ log.Debug("This is entry number: " + i );
+ </code>
+ <para>
+ You incur the cost constructing the message, concatenation in
+ this case, regardless of whether the message is logged or not.
+ </para>
+ <para>
+ If you are worried about speed, then you should write:
+ </para>
+ <code lang="C#">
+ if (log.IsDebugEnabled())
+ {
+ log.Debug("This is entry number: " + i );
+ }
+ </code>
+ <para>
+ This way you will not incur the cost of parameter
+ construction if debugging is disabled for <c>log</c>. On
+ the other hand, if the <c>log</c> is debug enabled, you
+ will incur the cost of evaluating whether the logger is debug
+ enabled twice. Once in <c>IsDebugEnabled</c> and once in
+ the <c>Debug</c>. This is an insignificant overhead
+ since evaluating a logger takes about 1% of the time it
+ takes to actually log.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.LogImpl.IsInfoEnabled">
+ <summary>
+ Checks if this logger is enabled for the <c>INFO</c> level.
+ </summary>
+ <value>
+ <c>true</c> if this logger is enabled for <c>INFO</c> events,
+ <c>false</c> otherwise.
+ </value>
+ <remarks>
+ <para>
+ See <see cref="P:log4net.Core.LogImpl.IsDebugEnabled"/> for more information and examples
+ of using this method.
+ </para>
+ </remarks>
+ <seealso cref="P:log4net.Core.LogImpl.IsDebugEnabled"/>
+ </member>
+ <member name="P:log4net.Core.LogImpl.IsWarnEnabled">
+ <summary>
+ Checks if this logger is enabled for the <c>WARN</c> level.
+ </summary>
+ <value>
+ <c>true</c> if this logger is enabled for <c>WARN</c> events,
+ <c>false</c> otherwise.
+ </value>
+ <remarks>
+ <para>
+ See <see cref="P:log4net.Core.LogImpl.IsDebugEnabled"/> for more information and examples
+ of using this method.
+ </para>
+ </remarks>
+ <seealso cref="P:log4net.ILog.IsDebugEnabled"/>
+ </member>
+ <member name="P:log4net.Core.LogImpl.IsErrorEnabled">
+ <summary>
+ Checks if this logger is enabled for the <c>ERROR</c> level.
+ </summary>
+ <value>
+ <c>true</c> if this logger is enabled for <c>ERROR</c> events,
+ <c>false</c> otherwise.
+ </value>
+ <remarks>
+ <para>
+ See <see cref="P:log4net.Core.LogImpl.IsDebugEnabled"/> for more information and examples of using this method.
+ </para>
+ </remarks>
+ <seealso cref="P:log4net.ILog.IsDebugEnabled"/>
+ </member>
+ <member name="P:log4net.Core.LogImpl.IsFatalEnabled">
+ <summary>
+ Checks if this logger is enabled for the <c>FATAL</c> level.
+ </summary>
+ <value>
+ <c>true</c> if this logger is enabled for <c>FATAL</c> events,
+ <c>false</c> otherwise.
+ </value>
+ <remarks>
+ <para>
+ See <see cref="P:log4net.Core.LogImpl.IsDebugEnabled"/> for more information and examples of using this method.
+ </para>
+ </remarks>
+ <seealso cref="P:log4net.ILog.IsDebugEnabled"/>
+ </member>
+ <member name="T:log4net.Core.SecurityContext">
+ <summary>
+ A SecurityContext used by log4net when interacting with protected resources
+ </summary>
+ <remarks>
+ <para>
+ A SecurityContext used by log4net when interacting with protected resources
+ for example with operating system services. This can be used to impersonate
+ a principal that has been granted privileges on the system resources.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Core.SecurityContext.Impersonate(System.Object)">
+ <summary>
+ Impersonate this SecurityContext
+ </summary>
+ <param name="state">State supplied by the caller</param>
+ <returns>An <see cref="T:System.IDisposable"/> instance that will
+ revoke the impersonation of this SecurityContext, or <c>null</c></returns>
+ <remarks>
+ <para>
+ Impersonate this security context. Further calls on the current
+ thread should now be made in the security context provided
+ by this object. When the <see cref="T:System.IDisposable"/> result
+ <see cref="M:System.IDisposable.Dispose"/> method is called the security
+ context of the thread should be reverted to the state it was in
+ before <see cref="M:log4net.Core.SecurityContext.Impersonate(System.Object)"/> was called.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.SecurityContextProvider">
+ <summary>
+ The <see cref="T:log4net.Core.SecurityContextProvider"/> providers default <see cref="T:log4net.Core.SecurityContext"/> instances.
+ </summary>
+ <remarks>
+ <para>
+ A configured component that interacts with potentially protected system
+ resources uses a <see cref="T:log4net.Core.SecurityContext"/> to provide the elevated
+ privileges required. If the <see cref="T:log4net.Core.SecurityContext"/> object has
+ been not been explicitly provided to the component then the component
+ will request one from this <see cref="T:log4net.Core.SecurityContextProvider"/>.
+ </para>
+ <para>
+ By default the <see cref="P:log4net.Core.SecurityContextProvider.DefaultProvider"/> is
+ an instance of <see cref="T:log4net.Core.SecurityContextProvider"/> which returns only
+ <see cref="T:log4net.Util.NullSecurityContext"/> objects. This is a reasonable default
+ where the privileges required are not know by the system.
+ </para>
+ <para>
+ This default behavior can be overridden by subclassing the <see cref="T:log4net.Core.SecurityContextProvider"/>
+ and overriding the <see cref="M:log4net.Core.SecurityContextProvider.CreateSecurityContext(System.Object)"/> method to return
+ the desired <see cref="T:log4net.Core.SecurityContext"/> objects. The default provider
+ can be replaced by programmatically setting the value of the
+ <see cref="P:log4net.Core.SecurityContextProvider.DefaultProvider"/> property.
+ </para>
+ <para>
+ An alternative is to use the <c>log4net.Config.SecurityContextProviderAttribute</c>
+ This attribute can be applied to an assembly in the same way as the
+ <c>log4net.Config.XmlConfiguratorAttribute"</c>. The attribute takes
+ the type to use as the <see cref="T:log4net.Core.SecurityContextProvider"/> as an argument.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="F:log4net.Core.SecurityContextProvider.s_defaultProvider">
+ <summary>
+ The default provider
+ </summary>
+ </member>
+ <member name="M:log4net.Core.SecurityContextProvider.#ctor">
+ <summary>
+ Protected default constructor to allow subclassing
+ </summary>
+ <remarks>
+ <para>
+ Protected default constructor to allow subclassing
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.SecurityContextProvider.CreateSecurityContext(System.Object)">
+ <summary>
+ Create a SecurityContext for a consumer
+ </summary>
+ <param name="consumer">The consumer requesting the SecurityContext</param>
+ <returns>An impersonation context</returns>
+ <remarks>
+ <para>
+ The default implementation is to return a <see cref="T:log4net.Util.NullSecurityContext"/>.
+ </para>
+ <para>
+ Subclasses should override this method to provide their own
+ behavior.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Core.SecurityContextProvider.DefaultProvider">
+ <summary>
+ Gets or sets the default SecurityContextProvider
+ </summary>
+ <value>
+ The default SecurityContextProvider
+ </value>
+ <remarks>
+ <para>
+ The default provider is used by configured components that
+ require a <see cref="T:log4net.Core.SecurityContext"/> and have not had one
+ given to them.
+ </para>
+ <para>
+ By default this is an instance of <see cref="T:log4net.Core.SecurityContextProvider"/>
+ that returns <see cref="T:log4net.Util.NullSecurityContext"/> objects.
+ </para>
+ <para>
+ The default provider can be set programmatically by setting
+ the value of this property to a sub class of <see cref="T:log4net.Core.SecurityContextProvider"/>
+ that has the desired behavior.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.WrapperCreationHandler">
+ <summary>
+ Delegate used to handle creation of new wrappers.
+ </summary>
+ <param name="logger">The logger to wrap in a wrapper.</param>
+ <remarks>
+ <para>
+ Delegate used to handle creation of new wrappers. This delegate
+ is called from the <see cref="M:log4net.Core.WrapperMap.CreateNewWrapperObject(log4net.Core.ILogger)"/>
+ method to construct the wrapper for the specified logger.
+ </para>
+ <para>
+ The delegate to use is supplied to the <see cref="T:log4net.Core.WrapperMap"/>
+ constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Core.WrapperMap">
+ <summary>
+ Maps between logger objects and wrapper objects.
+ </summary>
+ <remarks>
+ <para>
+ This class maintains a mapping between <see cref="T:log4net.Core.ILogger"/> objects and
+ <see cref="T:log4net.Core.ILoggerWrapper"/> objects. Use the <see cref="M:log4net.Core.WrapperMap.GetWrapper(log4net.Core.ILogger)"/> method to
+ lookup the <see cref="T:log4net.Core.ILoggerWrapper"/> for the specified <see cref="T:log4net.Core.ILogger"/>.
+ </para>
+ <para>
+ New wrapper instances are created by the <see cref="M:log4net.Core.WrapperMap.CreateNewWrapperObject(log4net.Core.ILogger)"/>
+ method. The default behavior is for this method to delegate construction
+ of the wrapper to the <see cref="T:log4net.Core.WrapperCreationHandler"/> delegate supplied
+ to the constructor. This allows specialization of the behavior without
+ requiring subclassing of this type.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Core.WrapperMap.#ctor(log4net.Core.WrapperCreationHandler)">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Core.WrapperMap"/>
+ </summary>
+ <param name="createWrapperHandler">The handler to use to create the wrapper objects.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Core.WrapperMap"/> class with
+ the specified handler to create the wrapper objects.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.WrapperMap.GetWrapper(log4net.Core.ILogger)">
+ <summary>
+ Gets the wrapper object for the specified logger.
+ </summary>
+ <returns>The wrapper object for the specified logger</returns>
+ <remarks>
+ <para>
+ If the logger is null then the corresponding wrapper is null.
+ </para>
+ <para>
+ Looks up the wrapper it it has previously been requested and
+ returns it. If the wrapper has never been requested before then
+ the <see cref="M:log4net.Core.WrapperMap.CreateNewWrapperObject(log4net.Core.ILogger)"/> virtual method is
+ called.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.WrapperMap.CreateNewWrapperObject(log4net.Core.ILogger)">
+ <summary>
+ Creates the wrapper object for the specified logger.
+ </summary>
+ <param name="logger">The logger to wrap in a wrapper.</param>
+ <returns>The wrapper object for the logger.</returns>
+ <remarks>
+ <para>
+ This implementation uses the <see cref="T:log4net.Core.WrapperCreationHandler"/>
+ passed to the constructor to create the wrapper. This method
+ can be overridden in a subclass.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.WrapperMap.RepositoryShutdown(log4net.Repository.ILoggerRepository)">
+ <summary>
+ Called when a monitored repository shutdown event is received.
+ </summary>
+ <param name="repository">The <see cref="T:log4net.Repository.ILoggerRepository"/> that is shutting down</param>
+ <remarks>
+ <para>
+ This method is called when a <see cref="T:log4net.Repository.ILoggerRepository"/> that this
+ <see cref="T:log4net.Core.WrapperMap"/> is holding loggers for has signaled its shutdown
+ event <see cref="E:log4net.Repository.ILoggerRepository.ShutdownEvent"/>. The default
+ behavior of this method is to release the references to the loggers
+ and their wrappers generated for this repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Core.WrapperMap.ILoggerRepository_Shutdown(System.Object,System.EventArgs)">
+ <summary>
+ Event handler for repository shutdown event.
+ </summary>
+ <param name="sender">The sender of the event.</param>
+ <param name="e">The event args.</param>
+ </member>
+ <member name="F:log4net.Core.WrapperMap.m_repositories">
+ <summary>
+ Map of logger repositories to hashtables of ILogger to ILoggerWrapper mappings
+ </summary>
+ </member>
+ <member name="F:log4net.Core.WrapperMap.m_createWrapperHandler">
+ <summary>
+ The handler to use to create the extension wrapper objects.
+ </summary>
+ </member>
+ <member name="F:log4net.Core.WrapperMap.m_shutdownHandler">
+ <summary>
+ Internal reference to the delegate used to register for repository shutdown events.
+ </summary>
+ </member>
+ <member name="P:log4net.Core.WrapperMap.Repositories">
+ <summary>
+ Gets the map of logger repositories.
+ </summary>
+ <value>
+ Map of logger repositories.
+ </value>
+ <remarks>
+ <para>
+ Gets the hashtable that is keyed on <see cref="T:log4net.Repository.ILoggerRepository"/>. The
+ values are hashtables keyed on <see cref="T:log4net.Core.ILogger"/> with the
+ value being the corresponding <see cref="T:log4net.Core.ILoggerWrapper"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.DateFormatter.AbsoluteTimeDateFormatter">
+ <summary>
+ Formats a <see cref="T:System.DateTime"/> as <c>"HH:mm:ss,fff"</c>.
+ </summary>
+ <remarks>
+ <para>
+ Formats a <see cref="T:System.DateTime"/> in the format <c>"HH:mm:ss,fff"</c> for example, <c>"15:49:37,459"</c>.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.DateFormatter.IDateFormatter">
+ <summary>
+ Render a <see cref="T:System.DateTime"/> as a string.
+ </summary>
+ <remarks>
+ <para>
+ Interface to abstract the rendering of a <see cref="T:System.DateTime"/>
+ instance into a string.
+ </para>
+ <para>
+ The <see cref="M:log4net.DateFormatter.IDateFormatter.FormatDate(System.DateTime,System.IO.TextWriter)"/> method is used to render the
+ date to a text writer.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.DateFormatter.IDateFormatter.FormatDate(System.DateTime,System.IO.TextWriter)">
+ <summary>
+ Formats the specified date as a string.
+ </summary>
+ <param name="dateToFormat">The date to format.</param>
+ <param name="writer">The writer to write to.</param>
+ <remarks>
+ <para>
+ Format the <see cref="T:System.DateTime"/> as a string and write it
+ to the <see cref="T:System.IO.TextWriter"/> provided.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.DateFormatter.AbsoluteTimeDateFormatter.AbsoluteTimeDateFormat">
+ <summary>
+ String constant used to specify AbsoluteTimeDateFormat in layouts. Current value is <b>ABSOLUTE</b>.
+ </summary>
+ </member>
+ <member name="F:log4net.DateFormatter.AbsoluteTimeDateFormatter.DateAndTimeDateFormat">
+ <summary>
+ String constant used to specify DateTimeDateFormat in layouts. Current value is <b>DATE</b>.
+ </summary>
+ </member>
+ <member name="F:log4net.DateFormatter.AbsoluteTimeDateFormatter.Iso8601TimeDateFormat">
+ <summary>
+ String constant used to specify ISO8601DateFormat in layouts. Current value is <b>ISO8601</b>.
+ </summary>
+ </member>
+ <member name="M:log4net.DateFormatter.AbsoluteTimeDateFormatter.FormatDateWithoutMillis(System.DateTime,System.Text.StringBuilder)">
+ <summary>
+ Renders the date into a string. Format is <c>"HH:mm:ss"</c>.
+ </summary>
+ <param name="dateToFormat">The date to render into a string.</param>
+ <param name="buffer">The string builder to write to.</param>
+ <remarks>
+ <para>
+ Subclasses should override this method to render the date
+ into a string using a precision up to the second. This method
+ will be called at most once per second and the result will be
+ reused if it is needed again during the same second.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.DateFormatter.AbsoluteTimeDateFormatter.FormatDate(System.DateTime,System.IO.TextWriter)">
+ <summary>
+ Renders the date into a string. Format is "HH:mm:ss,fff".
+ </summary>
+ <param name="dateToFormat">The date to render into a string.</param>
+ <param name="writer">The writer to write to.</param>
+ <remarks>
+ <para>
+ Uses the <see cref="M:log4net.DateFormatter.AbsoluteTimeDateFormatter.FormatDateWithoutMillis(System.DateTime,System.Text.StringBuilder)"/> method to generate the
+ time string up to the seconds and then appends the current
+ milliseconds. The results from <see cref="M:log4net.DateFormatter.AbsoluteTimeDateFormatter.FormatDateWithoutMillis(System.DateTime,System.Text.StringBuilder)"/> are
+ cached and <see cref="M:log4net.DateFormatter.AbsoluteTimeDateFormatter.FormatDateWithoutMillis(System.DateTime,System.Text.StringBuilder)"/> is called at most once
+ per second.
+ </para>
+ <para>
+ Sub classes should override <see cref="M:log4net.DateFormatter.AbsoluteTimeDateFormatter.FormatDateWithoutMillis(System.DateTime,System.Text.StringBuilder)"/>
+ rather than <see cref="M:log4net.DateFormatter.AbsoluteTimeDateFormatter.FormatDate(System.DateTime,System.IO.TextWriter)"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.DateFormatter.AbsoluteTimeDateFormatter.s_lastTimeToTheSecond">
+ <summary>
+ Last stored time with precision up to the second.
+ </summary>
+ </member>
+ <member name="F:log4net.DateFormatter.AbsoluteTimeDateFormatter.s_lastTimeBuf">
+ <summary>
+ Last stored time with precision up to the second, formatted
+ as a string.
+ </summary>
+ </member>
+ <member name="F:log4net.DateFormatter.AbsoluteTimeDateFormatter.s_lastTimeString">
+ <summary>
+ Last stored time with precision up to the second, formatted
+ as a string.
+ </summary>
+ </member>
+ <member name="T:log4net.DateFormatter.DateTimeDateFormatter">
+ <summary>
+ Formats a <see cref="T:System.DateTime"/> as <c>"dd MMM yyyy HH:mm:ss,fff"</c>
+ </summary>
+ <remarks>
+ <para>
+ Formats a <see cref="T:System.DateTime"/> in the format
+ <c>"dd MMM yyyy HH:mm:ss,fff"</c> for example,
+ <c>"06 Nov 1994 15:49:37,459"</c>.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ <author>Angelika Schnagl</author>
+ </member>
+ <member name="M:log4net.DateFormatter.DateTimeDateFormatter.#ctor">
+ <summary>
+ Default constructor.
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.DateFormatter.DateTimeDateFormatter"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.DateFormatter.DateTimeDateFormatter.FormatDateWithoutMillis(System.DateTime,System.Text.StringBuilder)">
+ <summary>
+ Formats the date without the milliseconds part
+ </summary>
+ <param name="dateToFormat">The date to format.</param>
+ <param name="buffer">The string builder to write to.</param>
+ <remarks>
+ <para>
+ Formats a DateTime in the format <c>"dd MMM yyyy HH:mm:ss"</c>
+ for example, <c>"06 Nov 1994 15:49:37"</c>.
+ </para>
+ <para>
+ The base class will append the <c>",fff"</c> milliseconds section.
+ This method will only be called at most once per second.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.DateFormatter.DateTimeDateFormatter.m_dateTimeFormatInfo">
+ <summary>
+ The format info for the invariant culture.
+ </summary>
+ </member>
+ <member name="T:log4net.DateFormatter.Iso8601DateFormatter">
+ <summary>
+ Formats the <see cref="T:System.DateTime"/> as <c>"yyyy-MM-dd HH:mm:ss,fff"</c>.
+ </summary>
+ <remarks>
+ <para>
+ Formats the <see cref="T:System.DateTime"/> specified as a string: <c>"yyyy-MM-dd HH:mm:ss,fff"</c>.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.DateFormatter.Iso8601DateFormatter.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.DateFormatter.Iso8601DateFormatter"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.DateFormatter.Iso8601DateFormatter.FormatDateWithoutMillis(System.DateTime,System.Text.StringBuilder)">
+ <summary>
+ Formats the date without the milliseconds part
+ </summary>
+ <param name="dateToFormat">The date to format.</param>
+ <param name="buffer">The string builder to write to.</param>
+ <remarks>
+ <para>
+ Formats the date specified as a string: <c>"yyyy-MM-dd HH:mm:ss"</c>.
+ </para>
+ <para>
+ The base class will append the <c>",fff"</c> milliseconds section.
+ This method will only be called at most once per second.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.DateFormatter.SimpleDateFormatter">
+ <summary>
+ Formats the <see cref="T:System.DateTime"/> using the <see cref="M:System.DateTime.ToString(System.String,System.IFormatProvider)"/> method.
+ </summary>
+ <remarks>
+ <para>
+ Formats the <see cref="T:System.DateTime"/> using the <see cref="T:System.DateTime"/> <see cref="M:System.DateTime.ToString(System.String,System.IFormatProvider)"/> method.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.DateFormatter.SimpleDateFormatter.#ctor(System.String)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="format">The format string.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.DateFormatter.SimpleDateFormatter"/> class
+ with the specified format string.
+ </para>
+ <para>
+ The format string must be compatible with the options
+ that can be supplied to <see cref="M:System.DateTime.ToString(System.String,System.IFormatProvider)"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.DateFormatter.SimpleDateFormatter.FormatDate(System.DateTime,System.IO.TextWriter)">
+ <summary>
+ Formats the date using <see cref="M:System.DateTime.ToString(System.String,System.IFormatProvider)"/>.
+ </summary>
+ <param name="dateToFormat">The date to convert to a string.</param>
+ <param name="writer">The writer to write to.</param>
+ <remarks>
+ <para>
+ Uses the date format string supplied to the constructor to call
+ the <see cref="M:System.DateTime.ToString(System.String,System.IFormatProvider)"/> method to format the date.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.DateFormatter.SimpleDateFormatter.m_formatString">
+ <summary>
+ The format string used to format the <see cref="T:System.DateTime"/>.
+ </summary>
+ <remarks>
+ <para>
+ The format string must be compatible with the options
+ that can be supplied to <see cref="M:System.DateTime.ToString(System.String,System.IFormatProvider)"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Filter.DenyAllFilter">
+ <summary>
+ This filter drops all <see cref="T:log4net.Core.LoggingEvent"/>.
+ </summary>
+ <remarks>
+ <para>
+ You can add this filter to the end of a filter chain to
+ switch from the default "accept all unless instructed otherwise"
+ filtering behavior to a "deny all unless instructed otherwise"
+ behavior.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.Filter.FilterSkeleton">
+ <summary>
+ Subclass this type to implement customized logging event filtering
+ </summary>
+ <remarks>
+ <para>
+ Users should extend this class to implement customized logging
+ event filtering. Note that <see cref="T:log4net.Repository.Hierarchy.Logger"/> and
+ <see cref="T:log4net.Appender.AppenderSkeleton"/>, the parent class of all standard
+ appenders, have built-in filtering rules. It is suggested that you
+ first use and understand the built-in rules before rushing to write
+ your own custom filters.
+ </para>
+ <para>
+ This abstract class assumes and also imposes that filters be
+ organized in a linear chain. The <see cref="M:log4net.Filter.FilterSkeleton.Decide(log4net.Core.LoggingEvent)"/>
+ method of each filter is called sequentially, in the order of their
+ addition to the chain.
+ </para>
+ <para>
+ The <see cref="M:log4net.Filter.FilterSkeleton.Decide(log4net.Core.LoggingEvent)"/> method must return one
+ of the integer constants <see cref="F:log4net.Filter.FilterDecision.Deny"/>,
+ <see cref="F:log4net.Filter.FilterDecision.Neutral"/> or <see cref="F:log4net.Filter.FilterDecision.Accept"/>.
+ </para>
+ <para>
+ If the value <see cref="F:log4net.Filter.FilterDecision.Deny"/> is returned, then the log event is dropped
+ immediately without consulting with the remaining filters.
+ </para>
+ <para>
+ If the value <see cref="F:log4net.Filter.FilterDecision.Neutral"/> is returned, then the next filter
+ in the chain is consulted. If there are no more filters in the
+ chain, then the log event is logged. Thus, in the presence of no
+ filters, the default behavior is to log all logging events.
+ </para>
+ <para>
+ If the value <see cref="F:log4net.Filter.FilterDecision.Accept"/> is returned, then the log
+ event is logged without consulting the remaining filters.
+ </para>
+ <para>
+ The philosophy of log4net filters is largely inspired from the
+ Linux ipchains.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.Filter.IFilter">
+ <summary>
+ Implement this interface to provide customized logging event filtering
+ </summary>
+ <remarks>
+ <para>
+ Users should implement this interface to implement customized logging
+ event filtering. Note that <see cref="T:log4net.Repository.Hierarchy.Logger"/> and
+ <see cref="T:log4net.Appender.AppenderSkeleton"/>, the parent class of all standard
+ appenders, have built-in filtering rules. It is suggested that you
+ first use and understand the built-in rules before rushing to write
+ your own custom filters.
+ </para>
+ <para>
+ This abstract class assumes and also imposes that filters be
+ organized in a linear chain. The <see cref="M:log4net.Filter.IFilter.Decide(log4net.Core.LoggingEvent)"/>
+ method of each filter is called sequentially, in the order of their
+ addition to the chain.
+ </para>
+ <para>
+ The <see cref="M:log4net.Filter.IFilter.Decide(log4net.Core.LoggingEvent)"/> method must return one
+ of the integer constants <see cref="F:log4net.Filter.FilterDecision.Deny"/>,
+ <see cref="F:log4net.Filter.FilterDecision.Neutral"/> or <see cref="F:log4net.Filter.FilterDecision.Accept"/>.
+ </para>
+ <para>
+ If the value <see cref="F:log4net.Filter.FilterDecision.Deny"/> is returned, then the log event is dropped
+ immediately without consulting with the remaining filters.
+ </para>
+ <para>
+ If the value <see cref="F:log4net.Filter.FilterDecision.Neutral"/> is returned, then the next filter
+ in the chain is consulted. If there are no more filters in the
+ chain, then the log event is logged. Thus, in the presence of no
+ filters, the default behavior is to log all logging events.
+ </para>
+ <para>
+ If the value <see cref="F:log4net.Filter.FilterDecision.Accept"/> is returned, then the log
+ event is logged without consulting the remaining filters.
+ </para>
+ <para>
+ The philosophy of log4net filters is largely inspired from the
+ Linux ipchains.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Filter.IFilter.Decide(log4net.Core.LoggingEvent)">
+ <summary>
+ Decide if the logging event should be logged through an appender.
+ </summary>
+ <param name="loggingEvent">The LoggingEvent to decide upon</param>
+ <returns>The decision of the filter</returns>
+ <remarks>
+ <para>
+ If the decision is <see cref="F:log4net.Filter.FilterDecision.Deny"/>, then the event will be
+ dropped. If the decision is <see cref="F:log4net.Filter.FilterDecision.Neutral"/>, then the next
+ filter, if any, will be invoked. If the decision is <see cref="F:log4net.Filter.FilterDecision.Accept"/> then
+ the event will be logged without consulting with other filters in
+ the chain.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Filter.IFilter.Next">
+ <summary>
+ Property to get and set the next filter
+ </summary>
+ <value>
+ The next filter in the chain
+ </value>
+ <remarks>
+ <para>
+ Filters are typically composed into chains. This property allows the next filter in
+ the chain to be accessed.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Filter.FilterSkeleton.m_next">
+ <summary>
+ Points to the next filter in the filter chain.
+ </summary>
+ <remarks>
+ <para>
+ See <see cref="P:log4net.Filter.FilterSkeleton.Next"/> for more information.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Filter.FilterSkeleton.ActivateOptions">
+ <summary>
+ Initialize the filter with the options set
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Filter.FilterSkeleton.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Filter.FilterSkeleton.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Filter.FilterSkeleton.ActivateOptions"/> must be called again.
+ </para>
+ <para>
+ Typically filter's options become active immediately on set,
+ however this method must still be called.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Filter.FilterSkeleton.Decide(log4net.Core.LoggingEvent)">
+ <summary>
+ Decide if the <see cref="T:log4net.Core.LoggingEvent"/> should be logged through an appender.
+ </summary>
+ <param name="loggingEvent">The <see cref="T:log4net.Core.LoggingEvent"/> to decide upon</param>
+ <returns>The decision of the filter</returns>
+ <remarks>
+ <para>
+ If the decision is <see cref="F:log4net.Filter.FilterDecision.Deny"/>, then the event will be
+ dropped. If the decision is <see cref="F:log4net.Filter.FilterDecision.Neutral"/>, then the next
+ filter, if any, will be invoked. If the decision is <see cref="F:log4net.Filter.FilterDecision.Accept"/> then
+ the event will be logged without consulting with other filters in
+ the chain.
+ </para>
+ <para>
+ This method is marked <c>abstract</c> and must be implemented
+ in a subclass.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Filter.FilterSkeleton.Next">
+ <summary>
+ Property to get and set the next filter
+ </summary>
+ <value>
+ The next filter in the chain
+ </value>
+ <remarks>
+ <para>
+ Filters are typically composed into chains. This property allows the next filter in
+ the chain to be accessed.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Filter.DenyAllFilter.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ </member>
+ <member name="M:log4net.Filter.DenyAllFilter.Decide(log4net.Core.LoggingEvent)">
+ <summary>
+ Always returns the integer constant <see cref="F:log4net.Filter.FilterDecision.Deny"/>
+ </summary>
+ <param name="loggingEvent">the LoggingEvent to filter</param>
+ <returns>Always returns <see cref="F:log4net.Filter.FilterDecision.Deny"/></returns>
+ <remarks>
+ <para>
+ Ignores the event being logged and just returns
+ <see cref="F:log4net.Filter.FilterDecision.Deny"/>. This can be used to change the default filter
+ chain behavior from <see cref="F:log4net.Filter.FilterDecision.Accept"/> to <see cref="F:log4net.Filter.FilterDecision.Deny"/>. This filter
+ should only be used as the last filter in the chain
+ as any further filters will be ignored!
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Filter.FilterDecision">
+ <summary>
+ The return result from <see cref="M:log4net.Filter.IFilter.Decide(log4net.Core.LoggingEvent)"/>
+ </summary>
+ <remarks>
+ <para>
+ The return result from <see cref="M:log4net.Filter.IFilter.Decide(log4net.Core.LoggingEvent)"/>
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Filter.FilterDecision.Deny">
+ <summary>
+ The log event must be dropped immediately without
+ consulting with the remaining filters, if any, in the chain.
+ </summary>
+ </member>
+ <member name="F:log4net.Filter.FilterDecision.Neutral">
+ <summary>
+ This filter is neutral with respect to the log event.
+ The remaining filters, if any, should be consulted for a final decision.
+ </summary>
+ </member>
+ <member name="F:log4net.Filter.FilterDecision.Accept">
+ <summary>
+ The log event must be logged immediately without
+ consulting with the remaining filters, if any, in the chain.
+ </summary>
+ </member>
+ <member name="T:log4net.Filter.LevelMatchFilter">
+ <summary>
+ This is a very simple filter based on <see cref="T:log4net.Core.Level"/> matching.
+ </summary>
+ <remarks>
+ <para>
+ The filter admits two options <see cref="P:log4net.Filter.LevelMatchFilter.LevelToMatch"/> and
+ <see cref="P:log4net.Filter.LevelMatchFilter.AcceptOnMatch"/>. If there is an exact match between the value
+ of the <see cref="P:log4net.Filter.LevelMatchFilter.LevelToMatch"/> option and the <see cref="T:log4net.Core.Level"/> of the
+ <see cref="T:log4net.Core.LoggingEvent"/>, then the <see cref="M:log4net.Filter.LevelMatchFilter.Decide(log4net.Core.LoggingEvent)"/> method returns <see cref="F:log4net.Filter.FilterDecision.Accept"/> in
+ case the <see cref="P:log4net.Filter.LevelMatchFilter.AcceptOnMatch"/> option value is set
+ to <c>true</c>, if it is <c>false</c> then
+ <see cref="F:log4net.Filter.FilterDecision.Deny"/> is returned. If the <see cref="T:log4net.Core.Level"/> does not match then
+ the result will be <see cref="F:log4net.Filter.FilterDecision.Neutral"/>.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="F:log4net.Filter.LevelMatchFilter.m_acceptOnMatch">
+ <summary>
+ flag to indicate if the filter should <see cref="F:log4net.Filter.FilterDecision.Accept"/> on a match
+ </summary>
+ </member>
+ <member name="F:log4net.Filter.LevelMatchFilter.m_levelToMatch">
+ <summary>
+ the <see cref="T:log4net.Core.Level"/> to match against
+ </summary>
+ </member>
+ <member name="M:log4net.Filter.LevelMatchFilter.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ </member>
+ <member name="M:log4net.Filter.LevelMatchFilter.Decide(log4net.Core.LoggingEvent)">
+ <summary>
+ Tests if the <see cref="T:log4net.Core.Level"/> of the logging event matches that of the filter
+ </summary>
+ <param name="loggingEvent">the event to filter</param>
+ <returns>see remarks</returns>
+ <remarks>
+ <para>
+ If the <see cref="T:log4net.Core.Level"/> of the event matches the level of the
+ filter then the result of the function depends on the
+ value of <see cref="P:log4net.Filter.LevelMatchFilter.AcceptOnMatch"/>. If it is true then
+ the function will return <see cref="F:log4net.Filter.FilterDecision.Accept"/>, it it is false then it
+ will return <see cref="F:log4net.Filter.FilterDecision.Deny"/>. If the <see cref="T:log4net.Core.Level"/> does not match then
+ the result will be <see cref="F:log4net.Filter.FilterDecision.Neutral"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Filter.LevelMatchFilter.AcceptOnMatch">
+ <summary>
+ <see cref="F:log4net.Filter.FilterDecision.Accept"/> when matching <see cref="P:log4net.Filter.LevelMatchFilter.LevelToMatch"/>
+ </summary>
+ <remarks>
+ <para>
+ The <see cref="P:log4net.Filter.LevelMatchFilter.AcceptOnMatch"/> property is a flag that determines
+ the behavior when a matching <see cref="T:log4net.Core.Level"/> is found. If the
+ flag is set to true then the filter will <see cref="F:log4net.Filter.FilterDecision.Accept"/> the
+ logging event, otherwise it will <see cref="F:log4net.Filter.FilterDecision.Deny"/> the event.
+ </para>
+ <para>
+ The default is <c>true</c> i.e. to <see cref="F:log4net.Filter.FilterDecision.Accept"/> the event.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Filter.LevelMatchFilter.LevelToMatch">
+ <summary>
+ The <see cref="T:log4net.Core.Level"/> that the filter will match
+ </summary>
+ <remarks>
+ <para>
+ The level that this filter will attempt to match against the
+ <see cref="T:log4net.Core.LoggingEvent"/> level. If a match is found then
+ the result depends on the value of <see cref="P:log4net.Filter.LevelMatchFilter.AcceptOnMatch"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Filter.LevelRangeFilter">
+ <summary>
+ This is a simple filter based on <see cref="T:log4net.Core.Level"/> matching.
+ </summary>
+ <remarks>
+ <para>
+ The filter admits three options <see cref="P:log4net.Filter.LevelRangeFilter.LevelMin"/> and <see cref="P:log4net.Filter.LevelRangeFilter.LevelMax"/>
+ that determine the range of priorities that are matched, and
+ <see cref="P:log4net.Filter.LevelRangeFilter.AcceptOnMatch"/>. If there is a match between the range
+ of priorities and the <see cref="T:log4net.Core.Level"/> of the <see cref="T:log4net.Core.LoggingEvent"/>, then the
+ <see cref="M:log4net.Filter.LevelRangeFilter.Decide(log4net.Core.LoggingEvent)"/> method returns <see cref="F:log4net.Filter.FilterDecision.Accept"/> in case the <see cref="P:log4net.Filter.LevelRangeFilter.AcceptOnMatch"/>
+ option value is set to <c>true</c>, if it is <c>false</c>
+ then <see cref="F:log4net.Filter.FilterDecision.Deny"/> is returned. If there is no match, <see cref="F:log4net.Filter.FilterDecision.Deny"/> is returned.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="F:log4net.Filter.LevelRangeFilter.m_acceptOnMatch">
+ <summary>
+ Flag to indicate the behavior when matching a <see cref="T:log4net.Core.Level"/>
+ </summary>
+ </member>
+ <member name="F:log4net.Filter.LevelRangeFilter.m_levelMin">
+ <summary>
+ the minimum <see cref="T:log4net.Core.Level"/> value to match
+ </summary>
+ </member>
+ <member name="F:log4net.Filter.LevelRangeFilter.m_levelMax">
+ <summary>
+ the maximum <see cref="T:log4net.Core.Level"/> value to match
+ </summary>
+ </member>
+ <member name="M:log4net.Filter.LevelRangeFilter.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ </member>
+ <member name="M:log4net.Filter.LevelRangeFilter.Decide(log4net.Core.LoggingEvent)">
+ <summary>
+ Check if the event should be logged.
+ </summary>
+ <param name="loggingEvent">the logging event to check</param>
+ <returns>see remarks</returns>
+ <remarks>
+ <para>
+ If the <see cref="T:log4net.Core.Level"/> of the logging event is outside the range
+ matched by this filter then <see cref="F:log4net.Filter.FilterDecision.Deny"/>
+ is returned. If the <see cref="T:log4net.Core.Level"/> is matched then the value of
+ <see cref="P:log4net.Filter.LevelRangeFilter.AcceptOnMatch"/> is checked. If it is true then
+ <see cref="F:log4net.Filter.FilterDecision.Accept"/> is returned, otherwise
+ <see cref="F:log4net.Filter.FilterDecision.Neutral"/> is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Filter.LevelRangeFilter.AcceptOnMatch">
+ <summary>
+ <see cref="F:log4net.Filter.FilterDecision.Accept"/> when matching <see cref="P:log4net.Filter.LevelRangeFilter.LevelMin"/> and <see cref="P:log4net.Filter.LevelRangeFilter.LevelMax"/>
+ </summary>
+ <remarks>
+ <para>
+ The <see cref="P:log4net.Filter.LevelRangeFilter.AcceptOnMatch"/> property is a flag that determines
+ the behavior when a matching <see cref="T:log4net.Core.Level"/> is found. If the
+ flag is set to true then the filter will <see cref="F:log4net.Filter.FilterDecision.Accept"/> the
+ logging event, otherwise it will <see cref="F:log4net.Filter.FilterDecision.Neutral"/> the event.
+ </para>
+ <para>
+ The default is <c>true</c> i.e. to <see cref="F:log4net.Filter.FilterDecision.Accept"/> the event.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Filter.LevelRangeFilter.LevelMin">
+ <summary>
+ Set the minimum matched <see cref="T:log4net.Core.Level"/>
+ </summary>
+ <remarks>
+ <para>
+ The minimum level that this filter will attempt to match against the
+ <see cref="T:log4net.Core.LoggingEvent"/> level. If a match is found then
+ the result depends on the value of <see cref="P:log4net.Filter.LevelRangeFilter.AcceptOnMatch"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Filter.LevelRangeFilter.LevelMax">
+ <summary>
+ Sets the maximum matched <see cref="T:log4net.Core.Level"/>
+ </summary>
+ <remarks>
+ <para>
+ The maximum level that this filter will attempt to match against the
+ <see cref="T:log4net.Core.LoggingEvent"/> level. If a match is found then
+ the result depends on the value of <see cref="P:log4net.Filter.LevelRangeFilter.AcceptOnMatch"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Filter.LoggerMatchFilter">
+ <summary>
+ Simple filter to match a string in the event's logger name.
+ </summary>
+ <remarks>
+ <para>
+ The works very similar to the <see cref="T:log4net.Filter.LevelMatchFilter"/>. It admits two
+ options <see cref="P:log4net.Filter.LoggerMatchFilter.LoggerToMatch"/> and <see cref="P:log4net.Filter.LoggerMatchFilter.AcceptOnMatch"/>. If the
+ <see cref="P:log4net.Core.LoggingEvent.LoggerName"/> of the <see cref="T:log4net.Core.LoggingEvent"/> starts
+ with the value of the <see cref="P:log4net.Filter.LoggerMatchFilter.LoggerToMatch"/> option, then the
+ <see cref="M:log4net.Filter.LoggerMatchFilter.Decide(log4net.Core.LoggingEvent)"/> method returns <see cref="F:log4net.Filter.FilterDecision.Accept"/> in
+ case the <see cref="P:log4net.Filter.LoggerMatchFilter.AcceptOnMatch"/> option value is set to <c>true</c>,
+ if it is <c>false</c> then <see cref="F:log4net.Filter.FilterDecision.Deny"/> is returned.
+ </para>
+ </remarks>
+ <author>Daniel Cazzulino</author>
+ </member>
+ <member name="F:log4net.Filter.LoggerMatchFilter.m_acceptOnMatch">
+ <summary>
+ Flag to indicate the behavior when we have a match
+ </summary>
+ </member>
+ <member name="F:log4net.Filter.LoggerMatchFilter.m_loggerToMatch">
+ <summary>
+ The logger name string to substring match against the event
+ </summary>
+ </member>
+ <member name="M:log4net.Filter.LoggerMatchFilter.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ </member>
+ <member name="M:log4net.Filter.LoggerMatchFilter.Decide(log4net.Core.LoggingEvent)">
+ <summary>
+ Check if this filter should allow the event to be logged
+ </summary>
+ <param name="loggingEvent">the event being logged</param>
+ <returns>see remarks</returns>
+ <remarks>
+ <para>
+ The rendered message is matched against the <see cref="P:log4net.Filter.LoggerMatchFilter.LoggerToMatch"/>.
+ If the <see cref="P:log4net.Filter.LoggerMatchFilter.LoggerToMatch"/> equals the beginning of
+ the incoming <see cref="P:log4net.Core.LoggingEvent.LoggerName"/> (<see cref="M:System.String.StartsWith(System.String)"/>)
+ then a match will have occurred. If no match occurs
+ this function will return <see cref="F:log4net.Filter.FilterDecision.Neutral"/>
+ allowing other filters to check the event. If a match occurs then
+ the value of <see cref="P:log4net.Filter.LoggerMatchFilter.AcceptOnMatch"/> is checked. If it is
+ true then <see cref="F:log4net.Filter.FilterDecision.Accept"/> is returned otherwise
+ <see cref="F:log4net.Filter.FilterDecision.Deny"/> is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Filter.LoggerMatchFilter.AcceptOnMatch">
+ <summary>
+ <see cref="F:log4net.Filter.FilterDecision.Accept"/> when matching <see cref="P:log4net.Filter.LoggerMatchFilter.LoggerToMatch"/>
+ </summary>
+ <remarks>
+ <para>
+ The <see cref="P:log4net.Filter.LoggerMatchFilter.AcceptOnMatch"/> property is a flag that determines
+ the behavior when a matching <see cref="T:log4net.Core.Level"/> is found. If the
+ flag is set to true then the filter will <see cref="F:log4net.Filter.FilterDecision.Accept"/> the
+ logging event, otherwise it will <see cref="F:log4net.Filter.FilterDecision.Deny"/> the event.
+ </para>
+ <para>
+ The default is <c>true</c> i.e. to <see cref="F:log4net.Filter.FilterDecision.Accept"/> the event.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Filter.LoggerMatchFilter.LoggerToMatch">
+ <summary>
+ The <see cref="P:log4net.Core.LoggingEvent.LoggerName"/> that the filter will match
+ </summary>
+ <remarks>
+ <para>
+ This filter will attempt to match this value against logger name in
+ the following way. The match will be done against the beginning of the
+ logger name (using <see cref="M:System.String.StartsWith(System.String)"/>). The match is
+ case sensitive. If a match is found then
+ the result depends on the value of <see cref="P:log4net.Filter.LoggerMatchFilter.AcceptOnMatch"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Filter.MdcFilter">
+ <summary>
+ Simple filter to match a keyed string in the <see cref="T:log4net.MDC"/>
+ </summary>
+ <remarks>
+ <para>
+ Simple filter to match a keyed string in the <see cref="T:log4net.MDC"/>
+ </para>
+ <para>
+ As the MDC has been replaced with layered properties the
+ <see cref="T:log4net.Filter.PropertyFilter"/> should be used instead.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.Filter.PropertyFilter">
+ <summary>
+ Simple filter to match a string an event property
+ </summary>
+ <remarks>
+ <para>
+ Simple filter to match a string in the value for a
+ specific event property
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="T:log4net.Filter.StringMatchFilter">
+ <summary>
+ Simple filter to match a string in the rendered message
+ </summary>
+ <remarks>
+ <para>
+ Simple filter to match a string in the rendered message
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="F:log4net.Filter.StringMatchFilter.m_acceptOnMatch">
+ <summary>
+ Flag to indicate the behavior when we have a match
+ </summary>
+ </member>
+ <member name="F:log4net.Filter.StringMatchFilter.m_stringToMatch">
+ <summary>
+ The string to substring match against the message
+ </summary>
+ </member>
+ <member name="F:log4net.Filter.StringMatchFilter.m_stringRegexToMatch">
+ <summary>
+ A string regex to match
+ </summary>
+ </member>
+ <member name="F:log4net.Filter.StringMatchFilter.m_regexToMatch">
+ <summary>
+ A regex object to match (generated from m_stringRegexToMatch)
+ </summary>
+ </member>
+ <member name="M:log4net.Filter.StringMatchFilter.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ </member>
+ <member name="M:log4net.Filter.StringMatchFilter.ActivateOptions">
+ <summary>
+ Initialize and precompile the Regex if required
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Filter.StringMatchFilter.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Filter.StringMatchFilter.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Filter.StringMatchFilter.ActivateOptions"/> must be called again.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Filter.StringMatchFilter.Decide(log4net.Core.LoggingEvent)">
+ <summary>
+ Check if this filter should allow the event to be logged
+ </summary>
+ <param name="loggingEvent">the event being logged</param>
+ <returns>see remarks</returns>
+ <remarks>
+ <para>
+ The rendered message is matched against the <see cref="P:log4net.Filter.StringMatchFilter.StringToMatch"/>.
+ If the <see cref="P:log4net.Filter.StringMatchFilter.StringToMatch"/> occurs as a substring within
+ the message then a match will have occurred. If no match occurs
+ this function will return <see cref="F:log4net.Filter.FilterDecision.Neutral"/>
+ allowing other filters to check the event. If a match occurs then
+ the value of <see cref="P:log4net.Filter.StringMatchFilter.AcceptOnMatch"/> is checked. If it is
+ true then <see cref="F:log4net.Filter.FilterDecision.Accept"/> is returned otherwise
+ <see cref="F:log4net.Filter.FilterDecision.Deny"/> is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Filter.StringMatchFilter.AcceptOnMatch">
+ <summary>
+ <see cref="F:log4net.Filter.FilterDecision.Accept"/> when matching <see cref="P:log4net.Filter.StringMatchFilter.StringToMatch"/> or <see cref="P:log4net.Filter.StringMatchFilter.RegexToMatch"/>
+ </summary>
+ <remarks>
+ <para>
+ The <see cref="P:log4net.Filter.StringMatchFilter.AcceptOnMatch"/> property is a flag that determines
+ the behavior when a matching <see cref="T:log4net.Core.Level"/> is found. If the
+ flag is set to true then the filter will <see cref="F:log4net.Filter.FilterDecision.Accept"/> the
+ logging event, otherwise it will <see cref="F:log4net.Filter.FilterDecision.Neutral"/> the event.
+ </para>
+ <para>
+ The default is <c>true</c> i.e. to <see cref="F:log4net.Filter.FilterDecision.Accept"/> the event.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Filter.StringMatchFilter.StringToMatch">
+ <summary>
+ Sets the static string to match
+ </summary>
+ <remarks>
+ <para>
+ The string that will be substring matched against
+ the rendered message. If the message contains this
+ string then the filter will match. If a match is found then
+ the result depends on the value of <see cref="P:log4net.Filter.StringMatchFilter.AcceptOnMatch"/>.
+ </para>
+ <para>
+ One of <see cref="P:log4net.Filter.StringMatchFilter.StringToMatch"/> or <see cref="P:log4net.Filter.StringMatchFilter.RegexToMatch"/>
+ must be specified.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Filter.StringMatchFilter.RegexToMatch">
+ <summary>
+ Sets the regular expression to match
+ </summary>
+ <remarks>
+ <para>
+ The regular expression pattern that will be matched against
+ the rendered message. If the message matches this
+ pattern then the filter will match. If a match is found then
+ the result depends on the value of <see cref="P:log4net.Filter.StringMatchFilter.AcceptOnMatch"/>.
+ </para>
+ <para>
+ One of <see cref="P:log4net.Filter.StringMatchFilter.StringToMatch"/> or <see cref="P:log4net.Filter.StringMatchFilter.RegexToMatch"/>
+ must be specified.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Filter.PropertyFilter.m_key">
+ <summary>
+ The key to use to lookup the string from the event properties
+ </summary>
+ </member>
+ <member name="M:log4net.Filter.PropertyFilter.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ </member>
+ <member name="M:log4net.Filter.PropertyFilter.Decide(log4net.Core.LoggingEvent)">
+ <summary>
+ Check if this filter should allow the event to be logged
+ </summary>
+ <param name="loggingEvent">the event being logged</param>
+ <returns>see remarks</returns>
+ <remarks>
+ <para>
+ The event property for the <see cref="P:log4net.Filter.PropertyFilter.Key"/> is matched against
+ the <see cref="P:log4net.Filter.StringMatchFilter.StringToMatch"/>.
+ If the <see cref="P:log4net.Filter.StringMatchFilter.StringToMatch"/> occurs as a substring within
+ the property value then a match will have occurred. If no match occurs
+ this function will return <see cref="F:log4net.Filter.FilterDecision.Neutral"/>
+ allowing other filters to check the event. If a match occurs then
+ the value of <see cref="P:log4net.Filter.StringMatchFilter.AcceptOnMatch"/> is checked. If it is
+ true then <see cref="F:log4net.Filter.FilterDecision.Accept"/> is returned otherwise
+ <see cref="F:log4net.Filter.FilterDecision.Deny"/> is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Filter.PropertyFilter.Key">
+ <summary>
+ The key to lookup in the event properties and then match against.
+ </summary>
+ <remarks>
+ <para>
+ The key name to use to lookup in the properties map of the
+ <see cref="T:log4net.Core.LoggingEvent"/>. The match will be performed against
+ the value of this property if it exists.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Filter.NdcFilter">
+ <summary>
+ Simple filter to match a string in the <see cref="T:log4net.NDC"/>
+ </summary>
+ <remarks>
+ <para>
+ Simple filter to match a string in the <see cref="T:log4net.NDC"/>
+ </para>
+ <para>
+ As the MDC has been replaced with named stacks stored in the
+ properties collections the <see cref="T:log4net.Filter.PropertyFilter"/> should
+ be used instead.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Filter.NdcFilter.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ <remarks>
+ <para>
+ Sets the <see cref="P:log4net.Filter.PropertyFilter.Key"/> to <c>"NDC"</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.Pattern.AppDomainPatternConverter">
+ <summary>
+ Write the event appdomain name to the output
+ </summary>
+ <remarks>
+ <para>
+ Writes the <see cref="P:log4net.Core.LoggingEvent.Domain"/> to the output writer.
+ </para>
+ </remarks>
+ <author>Daniel Cazzulino</author>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="T:log4net.Layout.Pattern.PatternLayoutConverter">
+ <summary>
+ Abstract class that provides the formatting functionality that
+ derived classes need.
+ </summary>
+ <remarks>
+ Conversion specifiers in a conversion patterns are parsed to
+ individual PatternConverters. Each of which is responsible for
+ converting a logging event in a converter specific manner.
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="T:log4net.Util.PatternConverter">
+ <summary>
+ Abstract class that provides the formatting functionality that
+ derived classes need.
+ </summary>
+ <remarks>
+ <para>
+ Conversion specifiers in a conversion patterns are parsed to
+ individual PatternConverters. Each of which is responsible for
+ converting a logging event in a converter specific manner.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="F:log4net.Util.PatternConverter.c_renderBufferSize">
+ <summary>
+ Initial buffer size
+ </summary>
+ </member>
+ <member name="F:log4net.Util.PatternConverter.c_renderBufferMaxCapacity">
+ <summary>
+ Maximum buffer size before it is recycled
+ </summary>
+ </member>
+ <member name="M:log4net.Util.PatternConverter.#ctor">
+ <summary>
+ Protected constructor
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.PatternConverter"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternConverter.Convert(System.IO.TextWriter,System.Object)">
+ <summary>
+ Evaluate this pattern converter and write the output to a writer.
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="state">The state object on which the pattern converter should be executed.</param>
+ <remarks>
+ <para>
+ Derived pattern converters must override this method in order to
+ convert conversion specifiers in the appropriate way.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternConverter.SetNext(log4net.Util.PatternConverter)">
+ <summary>
+ Set the next pattern converter in the chains
+ </summary>
+ <param name="patternConverter">the pattern converter that should follow this converter in the chain</param>
+ <returns>the next converter</returns>
+ <remarks>
+ <para>
+ The PatternConverter can merge with its neighbor during this method (or a sub class).
+ Therefore the return value may or may not be the value of the argument passed in.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternConverter.Format(System.IO.TextWriter,System.Object)">
+ <summary>
+ Write the pattern converter to the writer with appropriate formatting
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="state">The state object on which the pattern converter should be executed.</param>
+ <remarks>
+ <para>
+ This method calls <see cref="M:log4net.Util.PatternConverter.Convert(System.IO.TextWriter,System.Object)"/> to allow the subclass to perform
+ appropriate conversion of the pattern converter. If formatting options have
+ been specified via the <see cref="P:log4net.Util.PatternConverter.FormattingInfo"/> then this method will
+ apply those formattings before writing the output.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternConverter.SpacePad(System.IO.TextWriter,System.Int32)">
+ <summary>
+ Fast space padding method.
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> to which the spaces will be appended.</param>
+ <param name="length">The number of spaces to be padded.</param>
+ <remarks>
+ <para>
+ Fast space padding method.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Util.PatternConverter.m_option">
+ <summary>
+ The option string to the converter
+ </summary>
+ </member>
+ <member name="M:log4net.Util.PatternConverter.WriteDictionary(System.IO.TextWriter,log4net.Repository.ILoggerRepository,System.Collections.IDictionary)">
+ <summary>
+ Write an dictionary to a <see cref="T:System.IO.TextWriter"/>
+ </summary>
+ <param name="writer">the writer to write to</param>
+ <param name="repository">a <see cref="T:log4net.Repository.ILoggerRepository"/> to use for object conversion</param>
+ <param name="value">the value to write to the writer</param>
+ <remarks>
+ <para>
+ Writes the <see cref="T:System.Collections.IDictionary"/> to a writer in the form:
+ </para>
+ <code>
+ {key1=value1, key2=value2, key3=value3}
+ </code>
+ <para>
+ If the <see cref="T:log4net.Repository.ILoggerRepository"/> specified
+ is not null then it is used to render the key and value to text, otherwise
+ the object's ToString method is called.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternConverter.WriteObject(System.IO.TextWriter,log4net.Repository.ILoggerRepository,System.Object)">
+ <summary>
+ Write an object to a <see cref="T:System.IO.TextWriter"/>
+ </summary>
+ <param name="writer">the writer to write to</param>
+ <param name="repository">a <see cref="T:log4net.Repository.ILoggerRepository"/> to use for object conversion</param>
+ <param name="value">the value to write to the writer</param>
+ <remarks>
+ <para>
+ Writes the Object to a writer. If the <see cref="T:log4net.Repository.ILoggerRepository"/> specified
+ is not null then it is used to render the object to text, otherwise
+ the object's ToString method is called.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.PatternConverter.Next">
+ <summary>
+ Get the next pattern converter in the chain
+ </summary>
+ <value>
+ the next pattern converter in the chain
+ </value>
+ <remarks>
+ <para>
+ Get the next pattern converter in the chain
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.PatternConverter.FormattingInfo">
+ <summary>
+ Gets or sets the formatting info for this converter
+ </summary>
+ <value>
+ The formatting info for this converter
+ </value>
+ <remarks>
+ <para>
+ Gets or sets the formatting info for this converter
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.PatternConverter.Option">
+ <summary>
+ Gets or sets the option value for this converter
+ </summary>
+ <summary>
+ The option for this converter
+ </summary>
+ <remarks>
+ <para>
+ Gets or sets the option value for this converter
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.Pattern.PatternLayoutConverter.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Layout.Pattern.PatternLayoutConverter"/> class.
+ </summary>
+ </member>
+ <member name="M:log4net.Layout.Pattern.PatternLayoutConverter.Convert(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Derived pattern converters must override this method in order to
+ convert conversion specifiers in the correct way.
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="loggingEvent">The <see cref="T:log4net.Core.LoggingEvent"/> on which the pattern converter should be executed.</param>
+ </member>
+ <member name="M:log4net.Layout.Pattern.PatternLayoutConverter.Convert(System.IO.TextWriter,System.Object)">
+ <summary>
+ Derived pattern converters must override this method in order to
+ convert conversion specifiers in the correct way.
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="state">The state object on which the pattern converter should be executed.</param>
+ </member>
+ <member name="F:log4net.Layout.Pattern.PatternLayoutConverter.m_ignoresException">
+ <summary>
+ Flag indicating if this converter handles exceptions
+ </summary>
+ <remarks>
+ <c>false</c> if this converter handles exceptions
+ </remarks>
+ </member>
+ <member name="P:log4net.Layout.Pattern.PatternLayoutConverter.IgnoresException">
+ <summary>
+ Flag indicating if this converter handles the logging event exception
+ </summary>
+ <value><c>false</c> if this converter handles the logging event exception</value>
+ <remarks>
+ <para>
+ If this converter handles the exception object contained within
+ <see cref="T:log4net.Core.LoggingEvent"/>, then this property should be set to
+ <c>false</c>. Otherwise, if the layout ignores the exception
+ object, then the property should be set to <c>true</c>.
+ </para>
+ <para>
+ Set this value to override a this default setting. The default
+ value is <c>true</c>, this converter does not handle the exception.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.Pattern.AppDomainPatternConverter.Convert(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Write the event appdomain name to the output
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="loggingEvent">the event being logged</param>
+ <remarks>
+ <para>
+ Writes the <see cref="P:log4net.Core.LoggingEvent.Domain"/> to the output <paramref name="writer"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.Pattern.DatePatternConverter">
+ <summary>
+ Date pattern converter, uses a <see cref="T:log4net.DateFormatter.IDateFormatter"/> to format
+ the date of a <see cref="T:log4net.Core.LoggingEvent"/>.
+ </summary>
+ <remarks>
+ <para>
+ Render the <see cref="P:log4net.Core.LoggingEvent.TimeStamp"/> to the writer as a string.
+ </para>
+ <para>
+ The value of the <see cref="P:log4net.Util.PatternConverter.Option"/> determines
+ the formatting of the date. The following values are allowed:
+ <list type="definition">
+ <listheader>
+ <term>Option value</term>
+ <description>Output</description>
+ </listheader>
+ <item>
+ <term>ISO8601</term>
+ <description>
+ Uses the <see cref="T:log4net.DateFormatter.Iso8601DateFormatter"/> formatter.
+ Formats using the <c>"yyyy-MM-dd HH:mm:ss,fff"</c> pattern.
+ </description>
+ </item>
+ <item>
+ <term>DATE</term>
+ <description>
+ Uses the <see cref="T:log4net.DateFormatter.DateTimeDateFormatter"/> formatter.
+ Formats using the <c>"dd MMM yyyy HH:mm:ss,fff"</c> for example, <c>"06 Nov 1994 15:49:37,459"</c>.
+ </description>
+ </item>
+ <item>
+ <term>ABSOLUTE</term>
+ <description>
+ Uses the <see cref="T:log4net.DateFormatter.AbsoluteTimeDateFormatter"/> formatter.
+ Formats using the <c>"HH:mm:ss,yyyy"</c> for example, <c>"15:49:37,459"</c>.
+ </description>
+ </item>
+ <item>
+ <term>other</term>
+ <description>
+ Any other pattern string uses the <see cref="T:log4net.DateFormatter.SimpleDateFormatter"/> formatter.
+ This formatter passes the pattern string to the <see cref="T:System.DateTime"/>
+ <see cref="M:System.DateTime.ToString(System.String)"/> method.
+ For details on valid patterns see
+ <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemglobalizationdatetimeformatinfoclasstopic.asp">DateTimeFormatInfo Class</a>.
+ </description>
+ </item>
+ </list>
+ </para>
+ <para>
+ The <see cref="P:log4net.Core.LoggingEvent.TimeStamp"/> is in the local time zone and is rendered in that zone.
+ To output the time in Universal time see <see cref="T:log4net.Layout.Pattern.UtcDatePatternConverter"/>.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="F:log4net.Layout.Pattern.DatePatternConverter.m_dateFormatter">
+ <summary>
+ The <see cref="T:log4net.DateFormatter.IDateFormatter"/> used to render the date to a string
+ </summary>
+ <remarks>
+ <para>
+ The <see cref="T:log4net.DateFormatter.IDateFormatter"/> used to render the date to a string
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.Pattern.DatePatternConverter.ActivateOptions">
+ <summary>
+ Initialize the converter pattern based on the <see cref="P:log4net.Util.PatternConverter.Option"/> property.
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Layout.Pattern.DatePatternConverter.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Layout.Pattern.DatePatternConverter.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Layout.Pattern.DatePatternConverter.ActivateOptions"/> must be called again.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.Pattern.DatePatternConverter.Convert(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Convert the pattern into the rendered message
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="loggingEvent">the event being logged</param>
+ <remarks>
+ <para>
+ Pass the <see cref="P:log4net.Core.LoggingEvent.TimeStamp"/> to the <see cref="T:log4net.DateFormatter.IDateFormatter"/>
+ for it to render it to the writer.
+ </para>
+ <para>
+ The <see cref="P:log4net.Core.LoggingEvent.TimeStamp"/> passed is in the local time zone.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.Pattern.ExceptionPatternConverter">
+ <summary>
+ Write the exception text to the output
+ </summary>
+ <remarks>
+ <para>
+ If an exception object is stored in the logging event
+ it will be rendered into the pattern output with a
+ trailing newline.
+ </para>
+ <para>
+ If there is no exception then nothing will be output
+ and no trailing newline will be appended.
+ It is typical to put a newline before the exception
+ and to have the exception as the last data in the pattern.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Layout.Pattern.ExceptionPatternConverter.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ </member>
+ <member name="M:log4net.Layout.Pattern.ExceptionPatternConverter.Convert(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Write the exception text to the output
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="loggingEvent">the event being logged</param>
+ <remarks>
+ <para>
+ If an exception object is stored in the logging event
+ it will be rendered into the pattern output with a
+ trailing newline.
+ </para>
+ <para>
+ If there is no exception then nothing will be output
+ and no trailing newline will be appended.
+ It is typical to put a newline before the exception
+ and to have the exception as the last data in the pattern.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.Pattern.FileLocationPatternConverter">
+ <summary>
+ Writes the caller location file name to the output
+ </summary>
+ <remarks>
+ <para>
+ Writes the value of the <see cref="P:log4net.Core.LocationInfo.FileName"/> for
+ the event to the output writer.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Layout.Pattern.FileLocationPatternConverter.Convert(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Write the caller location file name to the output
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="loggingEvent">the event being logged</param>
+ <remarks>
+ <para>
+ Writes the value of the <see cref="P:log4net.Core.LocationInfo.FileName"/> for
+ the <paramref name="loggingEvent"/> to the output <paramref name="writer"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.Pattern.FullLocationPatternConverter">
+ <summary>
+ Write the caller location info to the output
+ </summary>
+ <remarks>
+ <para>
+ Writes the <see cref="P:log4net.Core.LocationInfo.FullInfo"/> to the output writer.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Layout.Pattern.FullLocationPatternConverter.Convert(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Write the caller location info to the output
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="loggingEvent">the event being logged</param>
+ <remarks>
+ <para>
+ Writes the <see cref="P:log4net.Core.LocationInfo.FullInfo"/> to the output writer.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.Pattern.IdentityPatternConverter">
+ <summary>
+ Writes the event identity to the output
+ </summary>
+ <remarks>
+ <para>
+ Writes the value of the <see cref="P:log4net.Core.LoggingEvent.Identity"/> to
+ the output writer.
+ </para>
+ </remarks>
+ <author>Daniel Cazzulino</author>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Layout.Pattern.IdentityPatternConverter.Convert(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Writes the event identity to the output
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="loggingEvent">the event being logged</param>
+ <remarks>
+ <para>
+ Writes the value of the <paramref name="loggingEvent"/>
+ <see cref="P:log4net.Core.LoggingEvent.Identity"/> to
+ the output <paramref name="writer"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.Pattern.LevelPatternConverter">
+ <summary>
+ Write the event level to the output
+ </summary>
+ <remarks>
+ <para>
+ Writes the display name of the event <see cref="P:log4net.Core.LoggingEvent.Level"/>
+ to the writer.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Layout.Pattern.LevelPatternConverter.Convert(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Write the event level to the output
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="loggingEvent">the event being logged</param>
+ <remarks>
+ <para>
+ Writes the <see cref="P:log4net.Core.Level.DisplayName"/> of the <paramref name="loggingEvent"/> <see cref="P:log4net.Core.LoggingEvent.Level"/>
+ to the <paramref name="writer"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.Pattern.LineLocationPatternConverter">
+ <summary>
+ Write the caller location line number to the output
+ </summary>
+ <remarks>
+ <para>
+ Writes the value of the <see cref="P:log4net.Core.LocationInfo.LineNumber"/> for
+ the event to the output writer.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Layout.Pattern.LineLocationPatternConverter.Convert(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Write the caller location line number to the output
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="loggingEvent">the event being logged</param>
+ <remarks>
+ <para>
+ Writes the value of the <see cref="P:log4net.Core.LocationInfo.LineNumber"/> for
+ the <paramref name="loggingEvent"/> to the output <paramref name="writer"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.Pattern.LoggerPatternConverter">
+ <summary>
+ Converter for logger name
+ </summary>
+ <remarks>
+ <para>
+ Outputs the <see cref="P:log4net.Core.LoggingEvent.LoggerName"/> of the event.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="T:log4net.Layout.Pattern.NamedPatternConverter">
+ <summary>
+ Converter to output and truncate <c>'.'</c> separated strings
+ </summary>
+ <remarks>
+ <para>
+ This abstract class supports truncating a <c>'.'</c> separated string
+ to show a specified number of elements from the right hand side.
+ This is used to truncate class names that are fully qualified.
+ </para>
+ <para>
+ Subclasses should override the <see cref="M:log4net.Layout.Pattern.NamedPatternConverter.GetFullyQualifiedName(log4net.Core.LoggingEvent)"/> method to
+ return the fully qualified string.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Layout.Pattern.NamedPatternConverter.ActivateOptions">
+ <summary>
+ Initialize the converter
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Layout.Pattern.NamedPatternConverter.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Layout.Pattern.NamedPatternConverter.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Layout.Pattern.NamedPatternConverter.ActivateOptions"/> must be called again.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.Pattern.NamedPatternConverter.GetFullyQualifiedName(log4net.Core.LoggingEvent)">
+ <summary>
+ Get the fully qualified string data
+ </summary>
+ <param name="loggingEvent">the event being logged</param>
+ <returns>the fully qualified name</returns>
+ <remarks>
+ <para>
+ Overridden by subclasses to get the fully qualified name before the
+ precision is applied to it.
+ </para>
+ <para>
+ Return the fully qualified <c>'.'</c> (dot/period) separated string.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.Pattern.NamedPatternConverter.Convert(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Convert the pattern to the rendered message
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="loggingEvent">the event being logged</param>
+ <remarks>
+ Render the <see cref="M:log4net.Layout.Pattern.NamedPatternConverter.GetFullyQualifiedName(log4net.Core.LoggingEvent)"/> to the precision
+ specified by the <see cref="P:log4net.Util.PatternConverter.Option"/> property.
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.Pattern.LoggerPatternConverter.GetFullyQualifiedName(log4net.Core.LoggingEvent)">
+ <summary>
+ Gets the fully qualified name of the logger
+ </summary>
+ <param name="loggingEvent">the event being logged</param>
+ <returns>The fully qualified logger name</returns>
+ <remarks>
+ <para>
+ Returns the <see cref="P:log4net.Core.LoggingEvent.LoggerName"/> of the <paramref name="loggingEvent"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.Pattern.MessagePatternConverter">
+ <summary>
+ Writes the event message to the output
+ </summary>
+ <remarks>
+ <para>
+ Uses the <see cref="M:log4net.Core.LoggingEvent.WriteRenderedMessage(System.IO.TextWriter)"/> method
+ to write out the event message.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Layout.Pattern.MessagePatternConverter.Convert(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Writes the event message to the output
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="loggingEvent">the event being logged</param>
+ <remarks>
+ <para>
+ Uses the <see cref="M:log4net.Core.LoggingEvent.WriteRenderedMessage(System.IO.TextWriter)"/> method
+ to write out the event message.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.Pattern.MethodLocationPatternConverter">
+ <summary>
+ Write the method name to the output
+ </summary>
+ <remarks>
+ <para>
+ Writes the caller location <see cref="P:log4net.Core.LocationInfo.MethodName"/> to
+ the output.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Layout.Pattern.MethodLocationPatternConverter.Convert(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Write the method name to the output
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="loggingEvent">the event being logged</param>
+ <remarks>
+ <para>
+ Writes the caller location <see cref="P:log4net.Core.LocationInfo.MethodName"/> to
+ the output.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.Pattern.NdcPatternConverter">
+ <summary>
+ Converter to include event NDC
+ </summary>
+ <remarks>
+ <para>
+ Outputs the value of the event property named <c>NDC</c>.
+ </para>
+ <para>
+ The <see cref="T:log4net.Layout.Pattern.PropertyPatternConverter"/> should be used instead.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Layout.Pattern.NdcPatternConverter.Convert(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Write the event NDC to the output
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="loggingEvent">the event being logged</param>
+ <remarks>
+ <para>
+ As the thread context stacks are now stored in named event properties
+ this converter simply looks up the value of the <c>NDC</c> property.
+ </para>
+ <para>
+ The <see cref="T:log4net.Layout.Pattern.PropertyPatternConverter"/> should be used instead.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.Pattern.PropertyPatternConverter">
+ <summary>
+ Property pattern converter
+ </summary>
+ <remarks>
+ <para>
+ Writes out the value of a named property. The property name
+ should be set in the <see cref="P:log4net.Util.PatternConverter.Option"/>
+ property.
+ </para>
+ <para>
+ If the <see cref="P:log4net.Util.PatternConverter.Option"/> is set to <c>null</c>
+ then all the properties are written as key value pairs.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Layout.Pattern.PropertyPatternConverter.Convert(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Write the property value to the output
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="loggingEvent">the event being logged</param>
+ <remarks>
+ <para>
+ Writes out the value of a named property. The property name
+ should be set in the <see cref="P:log4net.Util.PatternConverter.Option"/>
+ property.
+ </para>
+ <para>
+ If the <see cref="P:log4net.Util.PatternConverter.Option"/> is set to <c>null</c>
+ then all the properties are written as key value pairs.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.Pattern.RelativeTimePatternConverter">
+ <summary>
+ Converter to output the relative time of the event
+ </summary>
+ <remarks>
+ <para>
+ Converter to output the time of the event relative to the start of the program.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Layout.Pattern.RelativeTimePatternConverter.Convert(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Write the relative time to the output
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="loggingEvent">the event being logged</param>
+ <remarks>
+ <para>
+ Writes out the relative time of the event in milliseconds.
+ That is the number of milliseconds between the event <see cref="P:log4net.Core.LoggingEvent.TimeStamp"/>
+ and the <see cref="P:log4net.Core.LoggingEvent.StartTime"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.Pattern.RelativeTimePatternConverter.TimeDifferenceInMillis(System.DateTime,System.DateTime)">
+ <summary>
+ Helper method to get the time difference between two DateTime objects
+ </summary>
+ <param name="start">start time (in the current local time zone)</param>
+ <param name="end">end time (in the current local time zone)</param>
+ <returns>the time difference in milliseconds</returns>
+ </member>
+ <member name="T:log4net.Layout.Pattern.ThreadPatternConverter">
+ <summary>
+ Converter to include event thread name
+ </summary>
+ <remarks>
+ <para>
+ Writes the <see cref="P:log4net.Core.LoggingEvent.ThreadName"/> to the output.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Layout.Pattern.ThreadPatternConverter.Convert(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Write the ThreadName to the output
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="loggingEvent">the event being logged</param>
+ <remarks>
+ <para>
+ Writes the <see cref="P:log4net.Core.LoggingEvent.ThreadName"/> to the <paramref name="writer"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.Pattern.TypeNamePatternConverter">
+ <summary>
+ Pattern converter for the class name
+ </summary>
+ <remarks>
+ <para>
+ Outputs the <see cref="P:log4net.Core.LocationInfo.ClassName"/> of the event.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Layout.Pattern.TypeNamePatternConverter.GetFullyQualifiedName(log4net.Core.LoggingEvent)">
+ <summary>
+ Gets the fully qualified name of the class
+ </summary>
+ <param name="loggingEvent">the event being logged</param>
+ <returns>The fully qualified type name for the caller location</returns>
+ <remarks>
+ <para>
+ Returns the <see cref="P:log4net.Core.LocationInfo.ClassName"/> of the <paramref name="loggingEvent"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.Pattern.UserNamePatternConverter">
+ <summary>
+ Converter to include event user name
+ </summary>
+ <author>Douglas de la Torre</author>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Layout.Pattern.UserNamePatternConverter.Convert(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Convert the pattern to the rendered message
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="loggingEvent">the event being logged</param>
+ </member>
+ <member name="T:log4net.Layout.Pattern.UtcDatePatternConverter">
+ <summary>
+ Write the TimeStamp to the output
+ </summary>
+ <remarks>
+ <para>
+ Date pattern converter, uses a <see cref="T:log4net.DateFormatter.IDateFormatter"/> to format
+ the date of a <see cref="T:log4net.Core.LoggingEvent"/>.
+ </para>
+ <para>
+ Uses a <see cref="T:log4net.DateFormatter.IDateFormatter"/> to format the <see cref="P:log4net.Core.LoggingEvent.TimeStamp"/>
+ in Universal time.
+ </para>
+ <para>
+ See the <see cref="T:log4net.Layout.Pattern.DatePatternConverter"/> for details on the date pattern syntax.
+ </para>
+ </remarks>
+ <seealso cref="T:log4net.Layout.Pattern.DatePatternConverter"/>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Layout.Pattern.UtcDatePatternConverter.Convert(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Write the TimeStamp to the output
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="loggingEvent">the event being logged</param>
+ <remarks>
+ <para>
+ Pass the <see cref="P:log4net.Core.LoggingEvent.TimeStamp"/> to the <see cref="T:log4net.DateFormatter.IDateFormatter"/>
+ for it to render it to the writer.
+ </para>
+ <para>
+ The <see cref="P:log4net.Core.LoggingEvent.TimeStamp"/> passed is in the local time zone, this is converted
+ to Universal time before it is rendered.
+ </para>
+ </remarks>
+ <seealso cref="T:log4net.Layout.Pattern.DatePatternConverter"/>
+ </member>
+ <member name="T:log4net.Layout.ExceptionLayout">
+ <summary>
+ A Layout that renders only the Exception text from the logging event
+ </summary>
+ <remarks>
+ <para>
+ A Layout that renders only the Exception text from the logging event.
+ </para>
+ <para>
+ This Layout should only be used with appenders that utilize multiple
+ layouts (e.g. <see cref="T:log4net.Appender.AdoNetAppender"/>).
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.Layout.LayoutSkeleton">
+ <summary>
+ Extend this abstract class to create your own log layout format.
+ </summary>
+ <remarks>
+ <para>
+ This is the base implementation of the <see cref="T:log4net.Layout.ILayout"/>
+ interface. Most layout objects should extend this class.
+ </para>
+ </remarks>
+ <remarks>
+ <note type="inheritinfo">
+ <para>
+ Subclasses must implement the <see cref="M:log4net.Layout.LayoutSkeleton.Format(System.IO.TextWriter,log4net.Core.LoggingEvent)"/>
+ method.
+ </para>
+ <para>
+ Subclasses should set the <see cref="P:log4net.Layout.LayoutSkeleton.IgnoresException"/> in their default
+ constructor.
+ </para>
+ </note>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.Layout.ILayout">
+ <summary>
+ Interface implemented by layout objects
+ </summary>
+ <remarks>
+ <para>
+ An <see cref="T:log4net.Layout.ILayout"/> object is used to format a <see cref="T:log4net.Core.LoggingEvent"/>
+ as text. The <see cref="M:log4net.Layout.ILayout.Format(System.IO.TextWriter,log4net.Core.LoggingEvent)"/> method is called by an
+ appender to transform the <see cref="T:log4net.Core.LoggingEvent"/> into a string.
+ </para>
+ <para>
+ The layout can also supply <see cref="P:log4net.Layout.ILayout.Header"/> and <see cref="P:log4net.Layout.ILayout.Footer"/>
+ text that is appender before any events and after all the events respectively.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Layout.ILayout.Format(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Implement this method to create your own layout format.
+ </summary>
+ <param name="writer">The TextWriter to write the formatted event to</param>
+ <param name="loggingEvent">The event to format</param>
+ <remarks>
+ <para>
+ This method is called by an appender to format
+ the <paramref name="loggingEvent"/> as text and output to a writer.
+ </para>
+ <para>
+ If the caller does not have a <see cref="T:System.IO.TextWriter"/> and prefers the
+ event to be formatted as a <see cref="T:System.String"/> then the following
+ code can be used to format the event into a <see cref="T:System.IO.StringWriter"/>.
+ </para>
+ <code lang="C#">
+ StringWriter writer = new StringWriter();
+ Layout.Format(writer, loggingEvent);
+ string formattedEvent = writer.ToString();
+ </code>
+ </remarks>
+ </member>
+ <member name="P:log4net.Layout.ILayout.ContentType">
+ <summary>
+ The content type output by this layout.
+ </summary>
+ <value>The content type</value>
+ <remarks>
+ <para>
+ The content type output by this layout.
+ </para>
+ <para>
+ This is a MIME type e.g. <c>"text/plain"</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Layout.ILayout.Header">
+ <summary>
+ The header for the layout format.
+ </summary>
+ <value>the layout header</value>
+ <remarks>
+ <para>
+ The Header text will be appended before any logging events
+ are formatted and appended.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Layout.ILayout.Footer">
+ <summary>
+ The footer for the layout format.
+ </summary>
+ <value>the layout footer</value>
+ <remarks>
+ <para>
+ The Footer text will be appended after all the logging events
+ have been formatted and appended.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Layout.ILayout.IgnoresException">
+ <summary>
+ Flag indicating if this layout handle exceptions
+ </summary>
+ <value><c>false</c> if this layout handles exceptions</value>
+ <remarks>
+ <para>
+ If this layout handles the exception object contained within
+ <see cref="T:log4net.Core.LoggingEvent"/>, then the layout should return
+ <c>false</c>. Otherwise, if the layout ignores the exception
+ object, then the layout should return <c>true</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Layout.LayoutSkeleton.m_header">
+ <summary>
+ The header text
+ </summary>
+ <remarks>
+ <para>
+ See <see cref="P:log4net.Layout.LayoutSkeleton.Header"/> for more information.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Layout.LayoutSkeleton.m_footer">
+ <summary>
+ The footer text
+ </summary>
+ <remarks>
+ <para>
+ See <see cref="P:log4net.Layout.LayoutSkeleton.Footer"/> for more information.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Layout.LayoutSkeleton.m_ignoresException">
+ <summary>
+ Flag indicating if this layout handles exceptions
+ </summary>
+ <remarks>
+ <para>
+ <c>false</c> if this layout handles exceptions
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.LayoutSkeleton.#ctor">
+ <summary>
+ Empty default constructor
+ </summary>
+ <remarks>
+ <para>
+ Empty default constructor
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.LayoutSkeleton.ActivateOptions">
+ <summary>
+ Activate component options
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Layout.LayoutSkeleton.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Layout.LayoutSkeleton.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Layout.LayoutSkeleton.ActivateOptions"/> must be called again.
+ </para>
+ <para>
+ This method must be implemented by the subclass.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.LayoutSkeleton.Format(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Implement this method to create your own layout format.
+ </summary>
+ <param name="writer">The TextWriter to write the formatted event to</param>
+ <param name="loggingEvent">The event to format</param>
+ <remarks>
+ <para>
+ This method is called by an appender to format
+ the <paramref name="loggingEvent"/> as text.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Layout.LayoutSkeleton.ContentType">
+ <summary>
+ The content type output by this layout.
+ </summary>
+ <value>The content type is <c>"text/plain"</c></value>
+ <remarks>
+ <para>
+ The content type output by this layout.
+ </para>
+ <para>
+ This base class uses the value <c>"text/plain"</c>.
+ To change this value a subclass must override this
+ property.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Layout.LayoutSkeleton.Header">
+ <summary>
+ The header for the layout format.
+ </summary>
+ <value>the layout header</value>
+ <remarks>
+ <para>
+ The Header text will be appended before any logging events
+ are formatted and appended.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Layout.LayoutSkeleton.Footer">
+ <summary>
+ The footer for the layout format.
+ </summary>
+ <value>the layout footer</value>
+ <remarks>
+ <para>
+ The Footer text will be appended after all the logging events
+ have been formatted and appended.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Layout.LayoutSkeleton.IgnoresException">
+ <summary>
+ Flag indicating if this layout handles exceptions
+ </summary>
+ <value><c>false</c> if this layout handles exceptions</value>
+ <remarks>
+ <para>
+ If this layout handles the exception object contained within
+ <see cref="T:log4net.Core.LoggingEvent"/>, then the layout should return
+ <c>false</c>. Otherwise, if the layout ignores the exception
+ object, then the layout should return <c>true</c>.
+ </para>
+ <para>
+ Set this value to override a this default setting. The default
+ value is <c>true</c>, this layout does not handle the exception.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.ExceptionLayout.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ <remarks>
+ <para>
+ Constructs a ExceptionLayout
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.ExceptionLayout.ActivateOptions">
+ <summary>
+ Activate component options
+ </summary>
+ <remarks>
+ <para>
+ Part of the <see cref="T:log4net.Core.IOptionHandler"/> component activation
+ framework.
+ </para>
+ <para>
+ This method does nothing as options become effective immediately.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.ExceptionLayout.Format(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Gets the exception text from the logging event
+ </summary>
+ <param name="writer">The TextWriter to write the formatted event to</param>
+ <param name="loggingEvent">the event being logged</param>
+ <remarks>
+ <para>
+ Write the exception string to the <see cref="T:System.IO.TextWriter"/>.
+ The exception string is retrieved from <see cref="M:log4net.Core.LoggingEvent.GetExceptionString"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.IRawLayout">
+ <summary>
+ Interface for raw layout objects
+ </summary>
+ <remarks>
+ <para>
+ Interface used to format a <see cref="T:log4net.Core.LoggingEvent"/>
+ to an object.
+ </para>
+ <para>
+ This interface should not be confused with the
+ <see cref="T:log4net.Layout.ILayout"/> interface. This interface is used in
+ only certain specialized situations where a raw object is
+ required rather than a formatted string. The <see cref="T:log4net.Layout.ILayout"/>
+ is not generally useful than this interface.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Layout.IRawLayout.Format(log4net.Core.LoggingEvent)">
+ <summary>
+ Implement this method to create your own layout format.
+ </summary>
+ <param name="loggingEvent">The event to format</param>
+ <returns>returns the formatted event</returns>
+ <remarks>
+ <para>
+ Implement this method to create your own layout format.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.Layout2RawLayoutAdapter">
+ <summary>
+ Adapts any <see cref="T:log4net.Layout.ILayout"/> to a <see cref="T:log4net.Layout.IRawLayout"/>
+ </summary>
+ <remarks>
+ <para>
+ Where an <see cref="T:log4net.Layout.IRawLayout"/> is required this adapter
+ allows a <see cref="T:log4net.Layout.ILayout"/> to be specified.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="F:log4net.Layout.Layout2RawLayoutAdapter.m_layout">
+ <summary>
+ The layout to adapt
+ </summary>
+ </member>
+ <member name="M:log4net.Layout.Layout2RawLayoutAdapter.#ctor(log4net.Layout.ILayout)">
+ <summary>
+ Construct a new adapter
+ </summary>
+ <param name="layout">the layout to adapt</param>
+ <remarks>
+ <para>
+ Create the adapter for the specified <paramref name="layout"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.Layout2RawLayoutAdapter.Format(log4net.Core.LoggingEvent)">
+ <summary>
+ Format the logging event as an object.
+ </summary>
+ <param name="loggingEvent">The event to format</param>
+ <returns>returns the formatted event</returns>
+ <remarks>
+ <para>
+ Format the logging event as an object.
+ </para>
+ <para>
+ Uses the <see cref="T:log4net.Layout.ILayout"/> object supplied to
+ the constructor to perform the formatting.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.PatternLayout">
+ <summary>
+ A flexible layout configurable with pattern string.
+ </summary>
+ <remarks>
+ <para>
+ The goal of this class is to <see cref="M:log4net.Layout.PatternLayout.Format(System.IO.TextWriter,log4net.Core.LoggingEvent)"/> a
+ <see cref="T:log4net.Core.LoggingEvent"/> as a string. The results
+ depend on the <i>conversion pattern</i>.
+ </para>
+ <para>
+ The conversion pattern is closely related to the conversion
+ pattern of the printf function in C. A conversion pattern is
+ composed of literal text and format control expressions called
+ <i>conversion specifiers</i>.
+ </para>
+ <para>
+ <i>You are free to insert any literal text within the conversion
+ pattern.</i>
+ </para>
+ <para>
+ Each conversion specifier starts with a percent sign (%) and is
+ followed by optional <i>format modifiers</i> and a <i>conversion
+ pattern name</i>. The conversion pattern name specifies the type of
+ data, e.g. logger, level, date, thread name. The format
+ modifiers control such things as field width, padding, left and
+ right justification. The following is a simple example.
+ </para>
+ <para>
+ Let the conversion pattern be <b>"%-5level [%thread]: %message%newline"</b> and assume
+ that the log4net environment was set to use a PatternLayout. Then the
+ statements
+ </para>
+ <code lang="C#">
+ ILog log = LogManager.GetLogger(typeof(TestApp));
+ log.Debug("Message 1");
+ log.Warn("Message 2");
+ </code>
+ <para>would yield the output</para>
+ <code>
+ DEBUG [main]: Message 1
+ WARN [main]: Message 2
+ </code>
+ <para>
+ Note that there is no explicit separator between text and
+ conversion specifiers. The pattern parser knows when it has reached
+ the end of a conversion specifier when it reads a conversion
+ character. In the example above the conversion specifier
+ <b>%-5level</b> means the level of the logging event should be left
+ justified to a width of five characters.
+ </para>
+ <para>
+ The recognized conversion pattern names are:
+ </para>
+ <list type="table">
+ <listheader>
+ <term>Conversion Pattern Name</term>
+ <description>Effect</description>
+ </listheader>
+ <item>
+ <term>a</term>
+ <description>Equivalent to <b>appdomain</b></description>
+ </item>
+ <item>
+ <term>appdomain</term>
+ <description>
+ Used to output the friendly name of the AppDomain where the
+ logging event was generated.
+ </description>
+ </item>
+ <item>
+ <term>c</term>
+ <description>Equivalent to <b>logger</b></description>
+ </item>
+ <item>
+ <term>C</term>
+ <description>Equivalent to <b>type</b></description>
+ </item>
+ <item>
+ <term>class</term>
+ <description>Equivalent to <b>type</b></description>
+ </item>
+ <item>
+ <term>d</term>
+ <description>Equivalent to <b>date</b></description>
+ </item>
+ <item>
+ <term>date</term>
+ <description>
+ <para>
+ Used to output the date of the logging event in the local time zone.
+ To output the date in universal time use the <c>%utcdate</c> pattern.
+ The date conversion
+ specifier may be followed by a <i>date format specifier</i> enclosed
+ between braces. For example, <b>%date{HH:mm:ss,fff}</b> or
+ <b>%date{dd MMM yyyy HH:mm:ss,fff}</b>. If no date format specifier is
+ given then ISO8601 format is
+ assumed (<see cref="T:log4net.DateFormatter.Iso8601DateFormatter"/>).
+ </para>
+ <para>
+ The date format specifier admits the same syntax as the
+ time pattern string of the <see cref="M:System.DateTime.ToString(System.String)"/>.
+ </para>
+ <para>
+ For better results it is recommended to use the log4net date
+ formatters. These can be specified using one of the strings
+ "ABSOLUTE", "DATE" and "ISO8601" for specifying
+ <see cref="T:log4net.DateFormatter.AbsoluteTimeDateFormatter"/>,
+ <see cref="T:log4net.DateFormatter.DateTimeDateFormatter"/> and respectively
+ <see cref="T:log4net.DateFormatter.Iso8601DateFormatter"/>. For example,
+ <b>%date{ISO8601}</b> or <b>%date{ABSOLUTE}</b>.
+ </para>
+ <para>
+ These dedicated date formatters perform significantly
+ better than <see cref="M:System.DateTime.ToString(System.String)"/>.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>exception</term>
+ <description>
+ <para>
+ Used to output the exception passed in with the log message.
+ </para>
+ <para>
+ If an exception object is stored in the logging event
+ it will be rendered into the pattern output with a
+ trailing newline.
+ If there is no exception then nothing will be output
+ and no trailing newline will be appended.
+ It is typical to put a newline before the exception
+ and to have the exception as the last data in the pattern.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>F</term>
+ <description>Equivalent to <b>file</b></description>
+ </item>
+ <item>
+ <term>file</term>
+ <description>
+ <para>
+ Used to output the file name where the logging request was
+ issued.
+ </para>
+ <para>
+ <b>WARNING</b> Generating caller location information is
+ extremely slow. Its use should be avoided unless execution speed
+ is not an issue.
+ </para>
+ <para>
+ See the note below on the availability of caller location information.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>identity</term>
+ <description>
+ <para>
+ Used to output the user name for the currently active user
+ (Principal.Identity.Name).
+ </para>
+ <para>
+ <b>WARNING</b> Generating caller information is
+ extremely slow. Its use should be avoided unless execution speed
+ is not an issue.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>l</term>
+ <description>Equivalent to <b>location</b></description>
+ </item>
+ <item>
+ <term>L</term>
+ <description>Equivalent to <b>line</b></description>
+ </item>
+ <item>
+ <term>location</term>
+ <description>
+ <para>
+ Used to output location information of the caller which generated
+ the logging event.
+ </para>
+ <para>
+ The location information depends on the CLI implementation but
+ usually consists of the fully qualified name of the calling
+ method followed by the callers source the file name and line
+ number between parentheses.
+ </para>
+ <para>
+ The location information can be very useful. However, its
+ generation is <b>extremely</b> slow. Its use should be avoided
+ unless execution speed is not an issue.
+ </para>
+ <para>
+ See the note below on the availability of caller location information.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>level</term>
+ <description>
+ <para>
+ Used to output the level of the logging event.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>line</term>
+ <description>
+ <para>
+ Used to output the line number from where the logging request
+ was issued.
+ </para>
+ <para>
+ <b>WARNING</b> Generating caller location information is
+ extremely slow. Its use should be avoided unless execution speed
+ is not an issue.
+ </para>
+ <para>
+ See the note below on the availability of caller location information.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>logger</term>
+ <description>
+ <para>
+ Used to output the logger of the logging event. The
+ logger conversion specifier can be optionally followed by
+ <i>precision specifier</i>, that is a decimal constant in
+ brackets.
+ </para>
+ <para>
+ If a precision specifier is given, then only the corresponding
+ number of right most components of the logger name will be
+ printed. By default the logger name is printed in full.
+ </para>
+ <para>
+ For example, for the logger name "a.b.c" the pattern
+ <b>%logger{2}</b> will output "b.c".
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>m</term>
+ <description>Equivalent to <b>message</b></description>
+ </item>
+ <item>
+ <term>M</term>
+ <description>Equivalent to <b>method</b></description>
+ </item>
+ <item>
+ <term>message</term>
+ <description>
+ <para>
+ Used to output the application supplied message associated with
+ the logging event.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>mdc</term>
+ <description>
+ <para>
+ The MDC (old name for the ThreadContext.Properties) is now part of the
+ combined event properties. This pattern is supported for compatibility
+ but is equivalent to <b>property</b>.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>method</term>
+ <description>
+ <para>
+ Used to output the method name where the logging request was
+ issued.
+ </para>
+ <para>
+ <b>WARNING</b> Generating caller location information is
+ extremely slow. Its use should be avoided unless execution speed
+ is not an issue.
+ </para>
+ <para>
+ See the note below on the availability of caller location information.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>n</term>
+ <description>Equivalent to <b>newline</b></description>
+ </item>
+ <item>
+ <term>newline</term>
+ <description>
+ <para>
+ Outputs the platform dependent line separator character or
+ characters.
+ </para>
+ <para>
+ This conversion pattern offers the same performance as using
+ non-portable line separator strings such as "\n", or "\r\n".
+ Thus, it is the preferred way of specifying a line separator.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>ndc</term>
+ <description>
+ <para>
+ Used to output the NDC (nested diagnostic context) associated
+ with the thread that generated the logging event.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>p</term>
+ <description>Equivalent to <b>level</b></description>
+ </item>
+ <item>
+ <term>P</term>
+ <description>Equivalent to <b>property</b></description>
+ </item>
+ <item>
+ <term>properties</term>
+ <description>Equivalent to <b>property</b></description>
+ </item>
+ <item>
+ <term>property</term>
+ <description>
+ <para>
+ Used to output the an event specific property. The key to
+ lookup must be specified within braces and directly following the
+ pattern specifier, e.g. <b>%property{user}</b> would include the value
+ from the property that is keyed by the string 'user'. Each property value
+ that is to be included in the log must be specified separately.
+ Properties are added to events by loggers or appenders. By default
+ the <c>log4net:HostName</c> property is set to the name of machine on
+ which the event was originally logged.
+ </para>
+ <para>
+ If no key is specified, e.g. <b>%property</b> then all the keys and their
+ values are printed in a comma separated list.
+ </para>
+ <para>
+ The properties of an event are combined from a number of different
+ contexts. These are listed below in the order in which they are searched.
+ </para>
+ <list type="definition">
+ <item>
+ <term>the event properties</term>
+ <description>
+ The event has <see cref="P:log4net.Core.LoggingEvent.Properties"/> that can be set. These
+ properties are specific to this event only.
+ </description>
+ </item>
+ <item>
+ <term>the thread properties</term>
+ <description>
+ The <see cref="P:log4net.ThreadContext.Properties"/> that are set on the current
+ thread. These properties are shared by all events logged on this thread.
+ </description>
+ </item>
+ <item>
+ <term>the global properties</term>
+ <description>
+ The <see cref="P:log4net.GlobalContext.Properties"/> that are set globally. These
+ properties are shared by all the threads in the AppDomain.
+ </description>
+ </item>
+ </list>
+
+ </description>
+ </item>
+ <item>
+ <term>r</term>
+ <description>Equivalent to <b>timestamp</b></description>
+ </item>
+ <item>
+ <term>t</term>
+ <description>Equivalent to <b>thread</b></description>
+ </item>
+ <item>
+ <term>timestamp</term>
+ <description>
+ <para>
+ Used to output the number of milliseconds elapsed since the start
+ of the application until the creation of the logging event.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>thread</term>
+ <description>
+ <para>
+ Used to output the name of the thread that generated the
+ logging event. Uses the thread number if no name is available.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>type</term>
+ <description>
+ <para>
+ Used to output the fully qualified type name of the caller
+ issuing the logging request. This conversion specifier
+ can be optionally followed by <i>precision specifier</i>, that
+ is a decimal constant in brackets.
+ </para>
+ <para>
+ If a precision specifier is given, then only the corresponding
+ number of right most components of the class name will be
+ printed. By default the class name is output in fully qualified form.
+ </para>
+ <para>
+ For example, for the class name "log4net.Layout.PatternLayout", the
+ pattern <b>%type{1}</b> will output "PatternLayout".
+ </para>
+ <para>
+ <b>WARNING</b> Generating the caller class information is
+ slow. Thus, its use should be avoided unless execution speed is
+ not an issue.
+ </para>
+ <para>
+ See the note below on the availability of caller location information.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>u</term>
+ <description>Equivalent to <b>identity</b></description>
+ </item>
+ <item>
+ <term>username</term>
+ <description>
+ <para>
+ Used to output the WindowsIdentity for the currently
+ active user.
+ </para>
+ <para>
+ <b>WARNING</b> Generating caller WindowsIdentity information is
+ extremely slow. Its use should be avoided unless execution speed
+ is not an issue.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>utcdate</term>
+ <description>
+ <para>
+ Used to output the date of the logging event in universal time.
+ The date conversion
+ specifier may be followed by a <i>date format specifier</i> enclosed
+ between braces. For example, <b>%utcdate{HH:mm:ss,fff}</b> or
+ <b>%utcdate{dd MMM yyyy HH:mm:ss,fff}</b>. If no date format specifier is
+ given then ISO8601 format is
+ assumed (<see cref="T:log4net.DateFormatter.Iso8601DateFormatter"/>).
+ </para>
+ <para>
+ The date format specifier admits the same syntax as the
+ time pattern string of the <see cref="M:System.DateTime.ToString(System.String)"/>.
+ </para>
+ <para>
+ For better results it is recommended to use the log4net date
+ formatters. These can be specified using one of the strings
+ "ABSOLUTE", "DATE" and "ISO8601" for specifying
+ <see cref="T:log4net.DateFormatter.AbsoluteTimeDateFormatter"/>,
+ <see cref="T:log4net.DateFormatter.DateTimeDateFormatter"/> and respectively
+ <see cref="T:log4net.DateFormatter.Iso8601DateFormatter"/>. For example,
+ <b>%utcdate{ISO8601}</b> or <b>%utcdate{ABSOLUTE}</b>.
+ </para>
+ <para>
+ These dedicated date formatters perform significantly
+ better than <see cref="M:System.DateTime.ToString(System.String)"/>.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>w</term>
+ <description>Equivalent to <b>username</b></description>
+ </item>
+ <item>
+ <term>x</term>
+ <description>Equivalent to <b>ndc</b></description>
+ </item>
+ <item>
+ <term>X</term>
+ <description>Equivalent to <b>mdc</b></description>
+ </item>
+ <item>
+ <term>%</term>
+ <description>
+ <para>
+ The sequence %% outputs a single percent sign.
+ </para>
+ </description>
+ </item>
+ </list>
+ <para>
+ The single letter patterns are deprecated in favor of the
+ longer more descriptive pattern names.
+ </para>
+ <para>
+ By default the relevant information is output as is. However,
+ with the aid of format modifiers it is possible to change the
+ minimum field width, the maximum field width and justification.
+ </para>
+ <para>
+ The optional format modifier is placed between the percent sign
+ and the conversion pattern name.
+ </para>
+ <para>
+ The first optional format modifier is the <i>left justification
+ flag</i> which is just the minus (-) character. Then comes the
+ optional <i>minimum field width</i> modifier. This is a decimal
+ constant that represents the minimum number of characters to
+ output. If the data item requires fewer characters, it is padded on
+ either the left or the right until the minimum width is
+ reached. The default is to pad on the left (right justify) but you
+ can specify right padding with the left justification flag. The
+ padding character is space. If the data item is larger than the
+ minimum field width, the field is expanded to accommodate the
+ data. The value is never truncated.
+ </para>
+ <para>
+ This behavior can be changed using the <i>maximum field
+ width</i> modifier which is designated by a period followed by a
+ decimal constant. If the data item is longer than the maximum
+ field, then the extra characters are removed from the
+ <i>beginning</i> of the data item and not from the end. For
+ example, it the maximum field width is eight and the data item is
+ ten characters long, then the first two characters of the data item
+ are dropped. This behavior deviates from the printf function in C
+ where truncation is done from the end.
+ </para>
+ <para>
+ Below are various format modifier examples for the logger
+ conversion specifier.
+ </para>
+ <div class="tablediv">
+ <table class="dtTABLE" cellspacing="0">
+ <tr>
+ <th>Format modifier</th>
+ <th>left justify</th>
+ <th>minimum width</th>
+ <th>maximum width</th>
+ <th>comment</th>
+ </tr>
+ <tr>
+ <td align="center">%20logger</td>
+ <td align="center">false</td>
+ <td align="center">20</td>
+ <td align="center">none</td>
+ <td>
+ <para>
+ Left pad with spaces if the logger name is less than 20
+ characters long.
+ </para>
+ </td>
+ </tr>
+ <tr>
+ <td align="center">%-20logger</td>
+ <td align="center">true</td>
+ <td align="center">20</td>
+ <td align="center">none</td>
+ <td>
+ <para>
+ Right pad with spaces if the logger
+ name is less than 20 characters long.
+ </para>
+ </td>
+ </tr>
+ <tr>
+ <td align="center">%.30logger</td>
+ <td align="center">NA</td>
+ <td align="center">none</td>
+ <td align="center">30</td>
+ <td>
+ <para>
+ Truncate from the beginning if the logger
+ name is longer than 30 characters.
+ </para>
+ </td>
+ </tr>
+ <tr>
+ <td align="center"><nobr>%20.30logger</nobr></td>
+ <td align="center">false</td>
+ <td align="center">20</td>
+ <td align="center">30</td>
+ <td>
+ <para>
+ Left pad with spaces if the logger name is shorter than 20
+ characters. However, if logger name is longer than 30 characters,
+ then truncate from the beginning.
+ </para>
+ </td>
+ </tr>
+ <tr>
+ <td align="center">%-20.30logger</td>
+ <td align="center">true</td>
+ <td align="center">20</td>
+ <td align="center">30</td>
+ <td>
+ <para>
+ Right pad with spaces if the logger name is shorter than 20
+ characters. However, if logger name is longer than 30 characters,
+ then truncate from the beginning.
+ </para>
+ </td>
+ </tr>
+ </table>
+ </div>
+ <para>
+ <b>Note about caller location information.</b><br/>
+ The following patterns <c>%type %file %line %method %location %class %C %F %L %l %M</c>
+ all generate caller location information.
+ Location information uses the <c>System.Diagnostics.StackTrace</c> class to generate
+ a call stack. The caller's information is then extracted from this stack.
+ </para>
+ <note type="caution">
+ <para>
+ The <c>System.Diagnostics.StackTrace</c> class is not supported on the
+ .NET Compact Framework 1.0 therefore caller location information is not
+ available on that framework.
+ </para>
+ </note>
+ <note type="caution">
+ <para>
+ The <c>System.Diagnostics.StackTrace</c> class has this to say about Release builds:
+ </para>
+ <para>
+ "StackTrace information will be most informative with Debug build configurations.
+ By default, Debug builds include debug symbols, while Release builds do not. The
+ debug symbols contain most of the file, method name, line number, and column
+ information used in constructing StackFrame and StackTrace objects. StackTrace
+ might not report as many method calls as expected, due to code transformations
+ that occur during optimization."
+ </para>
+ <para>
+ This means that in a Release build the caller information may be incomplete or may
+ not exist at all! Therefore caller location information cannot be relied upon in a Release build.
+ </para>
+ </note>
+ <para>
+ Additional pattern converters may be registered with a specific <see cref="T:log4net.Layout.PatternLayout"/>
+ instance using the <see cref="M:log4net.Layout.PatternLayout.AddConverter(System.String,System.Type)"/> method.
+ </para>
+ </remarks>
+ <example>
+ This is a more detailed pattern.
+ <code><b>%timestamp [%thread] %level %logger %ndc - %message%newline</b></code>
+ </example>
+ <example>
+ A similar pattern except that the relative time is
+ right padded if less than 6 digits, thread name is right padded if
+ less than 15 characters and truncated if longer and the logger
+ name is left padded if shorter than 30 characters and truncated if
+ longer.
+ <code><b>%-6timestamp [%15.15thread] %-5level %30.30logger %ndc - %message%newline</b></code>
+ </example>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ <author>Douglas de la Torre</author>
+ <author>Daniel Cazzulino</author>
+ </member>
+ <member name="F:log4net.Layout.PatternLayout.DefaultConversionPattern">
+ <summary>
+ Default pattern string for log output.
+ </summary>
+ <remarks>
+ <para>
+ Default pattern string for log output.
+ Currently set to the string <b>"%message%newline"</b>
+ which just prints the application supplied message.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Layout.PatternLayout.DetailConversionPattern">
+ <summary>
+ A detailed conversion pattern
+ </summary>
+ <remarks>
+ <para>
+ A conversion pattern which includes Time, Thread, Logger, and Nested Context.
+ Current value is <b>%timestamp [%thread] %level %logger %ndc - %message%newline</b>.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Layout.PatternLayout.s_globalRulesRegistry">
+ <summary>
+ Internal map of converter identifiers to converter types.
+ </summary>
+ <remarks>
+ <para>
+ This static map is overridden by the m_converterRegistry instance map
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Layout.PatternLayout.m_pattern">
+ <summary>
+ the pattern
+ </summary>
+ </member>
+ <member name="F:log4net.Layout.PatternLayout.m_head">
+ <summary>
+ the head of the pattern converter chain
+ </summary>
+ </member>
+ <member name="F:log4net.Layout.PatternLayout.m_instanceRulesRegistry">
+ <summary>
+ patterns defined on this PatternLayout only
+ </summary>
+ </member>
+ <member name="M:log4net.Layout.PatternLayout.#cctor">
+ <summary>
+ Initialize the global registry
+ </summary>
+ <remarks>
+ <para>
+ Defines the builtin global rules.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.PatternLayout.#ctor">
+ <summary>
+ Constructs a PatternLayout using the DefaultConversionPattern
+ </summary>
+ <remarks>
+ <para>
+ The default pattern just produces the application supplied message.
+ </para>
+ <para>
+ Note to Inheritors: This constructor calls the virtual method
+ <see cref="M:log4net.Layout.PatternLayout.CreatePatternParser(System.String)"/>. If you override this method be
+ aware that it will be called before your is called constructor.
+ </para>
+ <para>
+ As per the <see cref="T:log4net.Core.IOptionHandler"/> contract the <see cref="M:log4net.Layout.PatternLayout.ActivateOptions"/>
+ method must be called after the properties on this object have been
+ configured.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.PatternLayout.#ctor(System.String)">
+ <summary>
+ Constructs a PatternLayout using the supplied conversion pattern
+ </summary>
+ <param name="pattern">the pattern to use</param>
+ <remarks>
+ <para>
+ Note to Inheritors: This constructor calls the virtual method
+ <see cref="M:log4net.Layout.PatternLayout.CreatePatternParser(System.String)"/>. If you override this method be
+ aware that it will be called before your is called constructor.
+ </para>
+ <para>
+ When using this constructor the <see cref="M:log4net.Layout.PatternLayout.ActivateOptions"/> method
+ need not be called. This may not be the case when using a subclass.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.PatternLayout.CreatePatternParser(System.String)">
+ <summary>
+ Create the pattern parser instance
+ </summary>
+ <param name="pattern">the pattern to parse</param>
+ <returns>The <see cref="T:log4net.Util.PatternParser"/> that will format the event</returns>
+ <remarks>
+ <para>
+ Creates the <see cref="T:log4net.Util.PatternParser"/> used to parse the conversion string. Sets the
+ global and instance rules on the <see cref="T:log4net.Util.PatternParser"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.PatternLayout.ActivateOptions">
+ <summary>
+ Initialize layout options
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Layout.PatternLayout.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Layout.PatternLayout.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Layout.PatternLayout.ActivateOptions"/> must be called again.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.PatternLayout.Format(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Produces a formatted string as specified by the conversion pattern.
+ </summary>
+ <param name="loggingEvent">the event being logged</param>
+ <param name="writer">The TextWriter to write the formatted event to</param>
+ <remarks>
+ <para>
+ Parse the <see cref="T:log4net.Core.LoggingEvent"/> using the patter format
+ specified in the <see cref="P:log4net.Layout.PatternLayout.ConversionPattern"/> property.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.PatternLayout.AddConverter(log4net.Layout.PatternLayout.ConverterInfo)">
+ <summary>
+ Add a converter to this PatternLayout
+ </summary>
+ <param name="converterInfo">the converter info</param>
+ <remarks>
+ <para>
+ This version of the method is used by the configurator.
+ Programmatic users should use the alternative <see cref="M:log4net.Layout.PatternLayout.AddConverter(System.String,System.Type)"/> method.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.PatternLayout.AddConverter(System.String,System.Type)">
+ <summary>
+ Add a converter to this PatternLayout
+ </summary>
+ <param name="name">the name of the conversion pattern for this converter</param>
+ <param name="type">the type of the converter</param>
+ <remarks>
+ <para>
+ Add a named pattern converter to this instance. This
+ converter will be used in the formatting of the event.
+ This method must be called before <see cref="M:log4net.Layout.PatternLayout.ActivateOptions"/>.
+ </para>
+ <para>
+ The <paramref name="type"/> specified must extend the
+ <see cref="T:log4net.Util.PatternConverter"/> type.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Layout.PatternLayout.ConversionPattern">
+ <summary>
+ The pattern formatting string
+ </summary>
+ <remarks>
+ <para>
+ The <b>ConversionPattern</b> option. This is the string which
+ controls formatting and consists of a mix of literal content and
+ conversion specifiers.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.PatternLayout.ConverterInfo">
+ <summary>
+ Wrapper class used to map converter names to converter types
+ </summary>
+ <remarks>
+ <para>
+ Pattern converter info class used during configuration to
+ pass to the <see cref="M:log4net.Layout.PatternLayout.AddConverter(log4net.Layout.PatternLayout.ConverterInfo)"/>
+ method.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.PatternLayout.ConverterInfo.#ctor">
+ <summary>
+ default constructor
+ </summary>
+ </member>
+ <member name="P:log4net.Layout.PatternLayout.ConverterInfo.Name">
+ <summary>
+ Gets or sets the name of the conversion pattern
+ </summary>
+ <remarks>
+ <para>
+ The name of the pattern in the format string
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Layout.PatternLayout.ConverterInfo.Type">
+ <summary>
+ Gets or sets the type of the converter
+ </summary>
+ <remarks>
+ <para>
+ The value specified must extend the
+ <see cref="T:log4net.Util.PatternConverter"/> type.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.RawLayoutConverter">
+ <summary>
+ Type converter for the <see cref="T:log4net.Layout.IRawLayout"/> interface
+ </summary>
+ <remarks>
+ <para>
+ Used to convert objects to the <see cref="T:log4net.Layout.IRawLayout"/> interface.
+ Supports converting from the <see cref="T:log4net.Layout.ILayout"/> interface to
+ the <see cref="T:log4net.Layout.IRawLayout"/> interface using the <see cref="T:log4net.Layout.Layout2RawLayoutAdapter"/>.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.Util.TypeConverters.IConvertFrom">
+ <summary>
+ Interface supported by type converters
+ </summary>
+ <remarks>
+ <para>
+ This interface supports conversion from arbitrary types
+ to a single target type. See <see cref="T:log4net.Util.TypeConverters.TypeConverterAttribute"/>.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.IConvertFrom.CanConvertFrom(System.Type)">
+ <summary>
+ Can the source type be converted to the type supported by this object
+ </summary>
+ <param name="sourceType">the type to convert</param>
+ <returns>true if the conversion is possible</returns>
+ <remarks>
+ <para>
+ Test if the <paramref name="sourceType"/> can be converted to the
+ type supported by this converter.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.IConvertFrom.ConvertFrom(System.Object)">
+ <summary>
+ Convert the source object to the type supported by this object
+ </summary>
+ <param name="source">the object to convert</param>
+ <returns>the converted object</returns>
+ <remarks>
+ <para>
+ Converts the <paramref name="source"/> to the type supported
+ by this converter.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.RawLayoutConverter.CanConvertFrom(System.Type)">
+ <summary>
+ Can the sourceType be converted to an <see cref="T:log4net.Layout.IRawLayout"/>
+ </summary>
+ <param name="sourceType">the source to be to be converted</param>
+ <returns><c>true</c> if the source type can be converted to <see cref="T:log4net.Layout.IRawLayout"/></returns>
+ <remarks>
+ <para>
+ Test if the <paramref name="sourceType"/> can be converted to a
+ <see cref="T:log4net.Layout.IRawLayout"/>. Only <see cref="T:log4net.Layout.ILayout"/> is supported
+ as the <paramref name="sourceType"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.RawLayoutConverter.ConvertFrom(System.Object)">
+ <summary>
+ Convert the value to a <see cref="T:log4net.Layout.IRawLayout"/> object
+ </summary>
+ <param name="source">the value to convert</param>
+ <returns>the <see cref="T:log4net.Layout.IRawLayout"/> object</returns>
+ <remarks>
+ <para>
+ Convert the <paramref name="source"/> object to a
+ <see cref="T:log4net.Layout.IRawLayout"/> object. If the <paramref name="source"/> object
+ is a <see cref="T:log4net.Layout.ILayout"/> then the <see cref="T:log4net.Layout.Layout2RawLayoutAdapter"/>
+ is used to adapt between the two interfaces, otherwise an
+ exception is thrown.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.RawPropertyLayout">
+ <summary>
+ Extract the value of a property from the <see cref="T:log4net.Core.LoggingEvent"/>
+ </summary>
+ <remarks>
+ <para>
+ Extract the value of a property from the <see cref="T:log4net.Core.LoggingEvent"/>
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Layout.RawPropertyLayout.#ctor">
+ <summary>
+ Constructs a RawPropertyLayout
+ </summary>
+ </member>
+ <member name="M:log4net.Layout.RawPropertyLayout.Format(log4net.Core.LoggingEvent)">
+ <summary>
+ Lookup the property for <see cref="P:log4net.Layout.RawPropertyLayout.Key"/>
+ </summary>
+ <param name="loggingEvent">The event to format</param>
+ <returns>returns property value</returns>
+ <remarks>
+ <para>
+ Looks up and returns the object value of the property
+ named <see cref="P:log4net.Layout.RawPropertyLayout.Key"/>. If there is no property defined
+ with than name then <c>null</c> will be returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Layout.RawPropertyLayout.Key">
+ <summary>
+ The name of the value to lookup in the LoggingEvent Properties collection.
+ </summary>
+ <value>
+ Value to lookup in the LoggingEvent Properties collection
+ </value>
+ <remarks>
+ <para>
+ String name of the property to lookup in the <see cref="T:log4net.Core.LoggingEvent"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.RawTimeStampLayout">
+ <summary>
+ Extract the date from the <see cref="T:log4net.Core.LoggingEvent"/>
+ </summary>
+ <remarks>
+ <para>
+ Extract the date from the <see cref="T:log4net.Core.LoggingEvent"/>
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Layout.RawTimeStampLayout.#ctor">
+ <summary>
+ Constructs a RawTimeStampLayout
+ </summary>
+ </member>
+ <member name="M:log4net.Layout.RawTimeStampLayout.Format(log4net.Core.LoggingEvent)">
+ <summary>
+ Gets the <see cref="P:log4net.Core.LoggingEvent.TimeStamp"/> as a <see cref="T:System.DateTime"/>.
+ </summary>
+ <param name="loggingEvent">The event to format</param>
+ <returns>returns the time stamp</returns>
+ <remarks>
+ <para>
+ Gets the <see cref="P:log4net.Core.LoggingEvent.TimeStamp"/> as a <see cref="T:System.DateTime"/>.
+ </para>
+ <para>
+ The time stamp is in local time. To format the time stamp
+ in universal time use <see cref="T:log4net.Layout.RawUtcTimeStampLayout"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.RawUtcTimeStampLayout">
+ <summary>
+ Extract the date from the <see cref="T:log4net.Core.LoggingEvent"/>
+ </summary>
+ <remarks>
+ <para>
+ Extract the date from the <see cref="T:log4net.Core.LoggingEvent"/>
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Layout.RawUtcTimeStampLayout.#ctor">
+ <summary>
+ Constructs a RawUtcTimeStampLayout
+ </summary>
+ </member>
+ <member name="M:log4net.Layout.RawUtcTimeStampLayout.Format(log4net.Core.LoggingEvent)">
+ <summary>
+ Gets the <see cref="P:log4net.Core.LoggingEvent.TimeStamp"/> as a <see cref="T:System.DateTime"/>.
+ </summary>
+ <param name="loggingEvent">The event to format</param>
+ <returns>returns the time stamp</returns>
+ <remarks>
+ <para>
+ Gets the <see cref="P:log4net.Core.LoggingEvent.TimeStamp"/> as a <see cref="T:System.DateTime"/>.
+ </para>
+ <para>
+ The time stamp is in universal time. To format the time stamp
+ in local time use <see cref="T:log4net.Layout.RawTimeStampLayout"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.SimpleLayout">
+ <summary>
+ A very simple layout
+ </summary>
+ <remarks>
+ <para>
+ SimpleLayout consists of the level of the log statement,
+ followed by " - " and then the log message itself. For example,
+ <code>
+ DEBUG - Hello world
+ </code>
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Layout.SimpleLayout.#ctor">
+ <summary>
+ Constructs a SimpleLayout
+ </summary>
+ </member>
+ <member name="M:log4net.Layout.SimpleLayout.ActivateOptions">
+ <summary>
+ Initialize layout options
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Layout.SimpleLayout.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Layout.SimpleLayout.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Layout.SimpleLayout.ActivateOptions"/> must be called again.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.SimpleLayout.Format(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Produces a simple formatted output.
+ </summary>
+ <param name="loggingEvent">the event being logged</param>
+ <param name="writer">The TextWriter to write the formatted event to</param>
+ <remarks>
+ <para>
+ Formats the event as the level of the even,
+ followed by " - " and then the log message itself. The
+ output is terminated by a newline.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.XmlLayout">
+ <summary>
+ Layout that formats the log events as XML elements.
+ </summary>
+ <remarks>
+ <para>
+ The output of the <see cref="T:log4net.Layout.XmlLayout"/> consists of a series of
+ log4net:event elements. It does not output a complete well-formed XML
+ file. The output is designed to be included as an <em>external entity</em>
+ in a separate file to form a correct XML file.
+ </para>
+ <para>
+ For example, if <c>abc</c> is the name of the file where
+ the <see cref="T:log4net.Layout.XmlLayout"/> output goes, then a well-formed XML file would
+ be:
+ </para>
+ <code lang="XML">
+ &lt;?xml version="1.0" ?&gt;
+
+ &lt;!DOCTYPE log4net:events SYSTEM "log4net-events.dtd" [&lt;!ENTITY data SYSTEM "abc"&gt;]&gt;
+
+ &lt;log4net:events version="1.2" xmlns:log4net="http://logging.apache.org/log4net/schemas/log4net-events-1.2&gt;
+ &amp;data;
+ &lt;/log4net:events&gt;
+ </code>
+ <para>
+ This approach enforces the independence of the <see cref="T:log4net.Layout.XmlLayout"/>
+ and the appender where it is embedded.
+ </para>
+ <para>
+ The <c>version</c> attribute helps components to correctly
+ interpret output generated by <see cref="T:log4net.Layout.XmlLayout"/>. The value of
+ this attribute should be "1.2" for release 1.2 and later.
+ </para>
+ <para>
+ Alternatively the <c>Header</c> and <c>Footer</c> properties can be
+ configured to output the correct XML header, open tag and close tag.
+ When setting the <c>Header</c> and <c>Footer</c> properties it is essential
+ that the underlying data store not be appendable otherwise the data
+ will become invalid XML.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.Layout.XmlLayoutBase">
+ <summary>
+ Layout that formats the log events as XML elements.
+ </summary>
+ <remarks>
+ <para>
+ This is an abstract class that must be subclassed by an implementation
+ to conform to a specific schema.
+ </para>
+ <para>
+ Deriving classes must implement the <see cref="M:log4net.Layout.XmlLayoutBase.FormatXml(System.Xml.XmlWriter,log4net.Core.LoggingEvent)"/> method.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Layout.XmlLayoutBase.#ctor">
+ <summary>
+ Protected constructor to support subclasses
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Layout.XmlLayoutBase"/> class
+ with no location info.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.XmlLayoutBase.#ctor(System.Boolean)">
+ <summary>
+ Protected constructor to support subclasses
+ </summary>
+ <remarks>
+ <para>
+ The <paramref name="locationInfo" /> parameter determines whether
+ location information will be output by the layout. If
+ <paramref name="locationInfo" /> is set to <c>true</c>, then the
+ file name and line number of the statement at the origin of the log
+ statement will be output.
+ </para>
+ <para>
+ If you are embedding this layout within an SMTPAppender
+ then make sure to set the <b>LocationInfo</b> option of that
+ appender as well.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.XmlLayoutBase.ActivateOptions">
+ <summary>
+ Initialize layout options
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Layout.XmlLayoutBase.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Layout.XmlLayoutBase.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Layout.XmlLayoutBase.ActivateOptions"/> must be called again.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.XmlLayoutBase.Format(System.IO.TextWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Produces a formatted string.
+ </summary>
+ <param name="loggingEvent">The event being logged.</param>
+ <param name="writer">The TextWriter to write the formatted event to</param>
+ <remarks>
+ <para>
+ Format the <see cref="T:log4net.Core.LoggingEvent"/> and write it to the <see cref="T:System.IO.TextWriter"/>.
+ </para>
+ <para>
+ This method creates an <see cref="T:System.Xml.XmlTextWriter"/> that writes to the
+ <paramref name="writer"/>. The <see cref="T:System.Xml.XmlTextWriter"/> is passed
+ to the <see cref="M:log4net.Layout.XmlLayoutBase.FormatXml(System.Xml.XmlWriter,log4net.Core.LoggingEvent)"/> method. Subclasses should override the
+ <see cref="M:log4net.Layout.XmlLayoutBase.FormatXml(System.Xml.XmlWriter,log4net.Core.LoggingEvent)"/> method rather than this method.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.XmlLayoutBase.FormatXml(System.Xml.XmlWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Does the actual writing of the XML.
+ </summary>
+ <param name="writer">The writer to use to output the event to.</param>
+ <param name="loggingEvent">The event to write.</param>
+ <remarks>
+ <para>
+ Subclasses should override this method to format
+ the <see cref="T:log4net.Core.LoggingEvent"/> as XML.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Layout.XmlLayoutBase.m_locationInfo">
+ <summary>
+ Flag to indicate if location information should be included in
+ the XML events.
+ </summary>
+ </member>
+ <member name="F:log4net.Layout.XmlLayoutBase.m_protectCloseTextWriter">
+ <summary>
+ Writer adapter that ignores Close
+ </summary>
+ </member>
+ <member name="F:log4net.Layout.XmlLayoutBase.m_invalidCharReplacement">
+ <summary>
+ The string to replace invalid chars with
+ </summary>
+ </member>
+ <member name="P:log4net.Layout.XmlLayoutBase.LocationInfo">
+ <summary>
+ Gets a value indicating whether to include location information in
+ the XML events.
+ </summary>
+ <value>
+ <c>true</c> if location information should be included in the XML
+ events; otherwise, <c>false</c>.
+ </value>
+ <remarks>
+ <para>
+ If <see cref="P:log4net.Layout.XmlLayoutBase.LocationInfo"/> is set to <c>true</c>, then the file
+ name and line number of the statement at the origin of the log
+ statement will be output.
+ </para>
+ <para>
+ If you are embedding this layout within an <c>SMTPAppender</c>
+ then make sure to set the <b>LocationInfo</b> option of that
+ appender as well.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Layout.XmlLayoutBase.InvalidCharReplacement">
+ <summary>
+ The string to replace characters that can not be expressed in XML with.
+ <remarks>
+ <para>
+ Not all characters may be expressed in XML. This property contains the
+ string to replace those that can not with. This defaults to a ?. Set it
+ to the empty string to simply remove offending characters. For more
+ details on the allowed character ranges see http://www.w3.org/TR/REC-xml/#charsets
+ Character replacement will occur in the log message, the property names
+ and the property values.
+ </para>
+ </remarks>
+ </summary>
+ </member>
+ <member name="P:log4net.Layout.XmlLayoutBase.ContentType">
+ <summary>
+ Gets the content type output by this layout.
+ </summary>
+ <value>
+ As this is the XML layout, the value is always <c>"text/xml"</c>.
+ </value>
+ <remarks>
+ <para>
+ As this is the XML layout, the value is always <c>"text/xml"</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.XmlLayout.#ctor">
+ <summary>
+ Constructs an XmlLayout
+ </summary>
+ </member>
+ <member name="M:log4net.Layout.XmlLayout.#ctor(System.Boolean)">
+ <summary>
+ Constructs an XmlLayout.
+ </summary>
+ <remarks>
+ <para>
+ The <b>LocationInfo</b> option takes a boolean value. By
+ default, it is set to false which means there will be no location
+ information output by this layout. If the the option is set to
+ true, then the file name and line number of the statement
+ at the origin of the log statement will be output.
+ </para>
+ <para>
+ If you are embedding this layout within an SmtpAppender
+ then make sure to set the <b>LocationInfo</b> option of that
+ appender as well.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.XmlLayout.ActivateOptions">
+ <summary>
+ Initialize layout options
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Layout.XmlLayout.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Layout.XmlLayout.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Layout.XmlLayout.ActivateOptions"/> must be called again.
+ </para>
+ <para>
+ Builds a cache of the element names
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.XmlLayout.FormatXml(System.Xml.XmlWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Does the actual writing of the XML.
+ </summary>
+ <param name="writer">The writer to use to output the event to.</param>
+ <param name="loggingEvent">The event to write.</param>
+ <remarks>
+ <para>
+ Override the base class <see cref="M:log4net.Layout.XmlLayoutBase.FormatXml(System.Xml.XmlWriter,log4net.Core.LoggingEvent)"/> method
+ to write the <see cref="T:log4net.Core.LoggingEvent"/> to the <see cref="T:System.Xml.XmlWriter"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Layout.XmlLayout.m_prefix">
+ <summary>
+ The prefix to use for all generated element names
+ </summary>
+ </member>
+ <member name="P:log4net.Layout.XmlLayout.Prefix">
+ <summary>
+ The prefix to use for all element names
+ </summary>
+ <remarks>
+ <para>
+ The default prefix is <b>log4net</b>. Set this property
+ to change the prefix. If the prefix is set to an empty string
+ then no prefix will be written.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Layout.XmlLayout.Base64EncodeMessage">
+ <summary>
+ Set whether or not to base64 encode the message.
+ </summary>
+ <remarks>
+ <para>
+ By default the log message will be written as text to the xml
+ output. This can cause problems when the message contains binary
+ data. By setting this to true the contents of the message will be
+ base64 encoded. If this is set then invalid character replacement
+ (see <see cref="P:log4net.Layout.XmlLayoutBase.InvalidCharReplacement"/>) will not be performed
+ on the log message.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Layout.XmlLayout.Base64EncodeProperties">
+ <summary>
+ Set whether or not to base64 encode the property values.
+ </summary>
+ <remarks>
+ <para>
+ By default the properties will be written as text to the xml
+ output. This can cause problems when one or more properties contain
+ binary data. By setting this to true the values of the properties
+ will be base64 encoded. If this is set then invalid character replacement
+ (see <see cref="P:log4net.Layout.XmlLayoutBase.InvalidCharReplacement"/>) will not be performed
+ on the property values.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Layout.XmlLayoutSchemaLog4j">
+ <summary>
+ Layout that formats the log events as XML elements compatible with the log4j schema
+ </summary>
+ <remarks>
+ <para>
+ Formats the log events according to the http://logging.apache.org/log4j schema.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="F:log4net.Layout.XmlLayoutSchemaLog4j.s_date1970">
+ <summary>
+ The 1st of January 1970 in UTC
+ </summary>
+ </member>
+ <member name="M:log4net.Layout.XmlLayoutSchemaLog4j.#ctor">
+ <summary>
+ Constructs an XMLLayoutSchemaLog4j
+ </summary>
+ </member>
+ <member name="M:log4net.Layout.XmlLayoutSchemaLog4j.#ctor(System.Boolean)">
+ <summary>
+ Constructs an XMLLayoutSchemaLog4j.
+ </summary>
+ <remarks>
+ <para>
+ The <b>LocationInfo</b> option takes a boolean value. By
+ default, it is set to false which means there will be no location
+ information output by this layout. If the the option is set to
+ true, then the file name and line number of the statement
+ at the origin of the log statement will be output.
+ </para>
+ <para>
+ If you are embedding this layout within an SMTPAppender
+ then make sure to set the <b>LocationInfo</b> option of that
+ appender as well.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Layout.XmlLayoutSchemaLog4j.FormatXml(System.Xml.XmlWriter,log4net.Core.LoggingEvent)">
+ <summary>
+ Actually do the writing of the xml
+ </summary>
+ <param name="writer">the writer to use</param>
+ <param name="loggingEvent">the event to write</param>
+ <remarks>
+ <para>
+ Generate XML that is compatible with the log4j schema.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Layout.XmlLayoutSchemaLog4j.Version">
+ <summary>
+ The version of the log4j schema to use.
+ </summary>
+ <remarks>
+ <para>
+ Only version 1.2 of the log4j schema is supported.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.ObjectRenderer.DefaultRenderer">
+ <summary>
+ The default object Renderer.
+ </summary>
+ <remarks>
+ <para>
+ The default renderer supports rendering objects and collections to strings.
+ </para>
+ <para>
+ See the <see cref="M:log4net.ObjectRenderer.DefaultRenderer.RenderObject(log4net.ObjectRenderer.RendererMap,System.Object,System.IO.TextWriter)"/> method for details of the output.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.ObjectRenderer.IObjectRenderer">
+ <summary>
+ Implement this interface in order to render objects as strings
+ </summary>
+ <remarks>
+ <para>
+ Certain types require special case conversion to
+ string form. This conversion is done by an object renderer.
+ Object renderers implement the <see cref="T:log4net.ObjectRenderer.IObjectRenderer"/>
+ interface.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.ObjectRenderer.IObjectRenderer.RenderObject(log4net.ObjectRenderer.RendererMap,System.Object,System.IO.TextWriter)">
+ <summary>
+ Render the object <paramref name="obj"/> to a string
+ </summary>
+ <param name="rendererMap">The map used to lookup renderers</param>
+ <param name="obj">The object to render</param>
+ <param name="writer">The writer to render to</param>
+ <remarks>
+ <para>
+ Render the object <paramref name="obj"/> to a
+ string.
+ </para>
+ <para>
+ The <paramref name="rendererMap"/> parameter is
+ provided to lookup and render other objects. This is
+ very useful where <paramref name="obj"/> contains
+ nested objects of unknown type. The <see cref="M:log4net.ObjectRenderer.RendererMap.FindAndRender(System.Object,System.IO.TextWriter)"/>
+ method can be used to render these objects.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.ObjectRenderer.DefaultRenderer.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ <remarks>
+ <para>
+ Default constructor
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.ObjectRenderer.DefaultRenderer.RenderObject(log4net.ObjectRenderer.RendererMap,System.Object,System.IO.TextWriter)">
+ <summary>
+ Render the object <paramref name="obj"/> to a string
+ </summary>
+ <param name="rendererMap">The map used to lookup renderers</param>
+ <param name="obj">The object to render</param>
+ <param name="writer">The writer to render to</param>
+ <remarks>
+ <para>
+ Render the object <paramref name="obj"/> to a string.
+ </para>
+ <para>
+ The <paramref name="rendererMap"/> parameter is
+ provided to lookup and render other objects. This is
+ very useful where <paramref name="obj"/> contains
+ nested objects of unknown type. The <see cref="M:log4net.ObjectRenderer.RendererMap.FindAndRender(System.Object)"/>
+ method can be used to render these objects.
+ </para>
+ <para>
+ The default renderer supports rendering objects to strings as follows:
+ </para>
+ <list type="table">
+ <listheader>
+ <term>Value</term>
+ <description>Rendered String</description>
+ </listheader>
+ <item>
+ <term><c>null</c></term>
+ <description>
+ <para>"(null)"</para>
+ </description>
+ </item>
+ <item>
+ <term><see cref="T:System.Array"/></term>
+ <description>
+ <para>
+ For a one dimensional array this is the
+ array type name, an open brace, followed by a comma
+ separated list of the elements (using the appropriate
+ renderer), followed by a close brace.
+ </para>
+ <para>
+ For example: <c>int[] {1, 2, 3}</c>.
+ </para>
+ <para>
+ If the array is not one dimensional the
+ <c>Array.ToString()</c> is returned.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term><see cref="T:System.Collections.IEnumerable"/>, <see cref="T:System.Collections.ICollection"/> &amp; <see cref="T:System.Collections.IEnumerator"/></term>
+ <description>
+ <para>
+ Rendered as an open brace, followed by a comma
+ separated list of the elements (using the appropriate
+ renderer), followed by a close brace.
+ </para>
+ <para>
+ For example: <c>{a, b, c}</c>.
+ </para>
+ <para>
+ All collection classes that implement <see cref="T:System.Collections.ICollection"/> its subclasses,
+ or generic equivalents all implement the <see cref="T:System.Collections.IEnumerable"/> interface.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term><see cref="T:System.Collections.DictionaryEntry"/></term>
+ <description>
+ <para>
+ Rendered as the key, an equals sign ('='), and the value (using the appropriate
+ renderer).
+ </para>
+ <para>
+ For example: <c>key=value</c>.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>other</term>
+ <description>
+ <para><c>Object.ToString()</c></para>
+ </description>
+ </item>
+ </list>
+ </remarks>
+ </member>
+ <member name="M:log4net.ObjectRenderer.DefaultRenderer.RenderArray(log4net.ObjectRenderer.RendererMap,System.Array,System.IO.TextWriter)">
+ <summary>
+ Render the array argument into a string
+ </summary>
+ <param name="rendererMap">The map used to lookup renderers</param>
+ <param name="array">the array to render</param>
+ <param name="writer">The writer to render to</param>
+ <remarks>
+ <para>
+ For a one dimensional array this is the
+ array type name, an open brace, followed by a comma
+ separated list of the elements (using the appropriate
+ renderer), followed by a close brace. For example:
+ <c>int[] {1, 2, 3}</c>.
+ </para>
+ <para>
+ If the array is not one dimensional the
+ <c>Array.ToString()</c> is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.ObjectRenderer.DefaultRenderer.RenderEnumerator(log4net.ObjectRenderer.RendererMap,System.Collections.IEnumerator,System.IO.TextWriter)">
+ <summary>
+ Render the enumerator argument into a string
+ </summary>
+ <param name="rendererMap">The map used to lookup renderers</param>
+ <param name="enumerator">the enumerator to render</param>
+ <param name="writer">The writer to render to</param>
+ <remarks>
+ <para>
+ Rendered as an open brace, followed by a comma
+ separated list of the elements (using the appropriate
+ renderer), followed by a close brace. For example:
+ <c>{a, b, c}</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.ObjectRenderer.DefaultRenderer.RenderDictionaryEntry(log4net.ObjectRenderer.RendererMap,System.Collections.DictionaryEntry,System.IO.TextWriter)">
+ <summary>
+ Render the DictionaryEntry argument into a string
+ </summary>
+ <param name="rendererMap">The map used to lookup renderers</param>
+ <param name="entry">the DictionaryEntry to render</param>
+ <param name="writer">The writer to render to</param>
+ <remarks>
+ <para>
+ Render the key, an equals sign ('='), and the value (using the appropriate
+ renderer). For example: <c>key=value</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.ObjectRenderer.RendererMap">
+ <summary>
+ Map class objects to an <see cref="T:log4net.ObjectRenderer.IObjectRenderer"/>.
+ </summary>
+ <remarks>
+ <para>
+ Maintains a mapping between types that require special
+ rendering and the <see cref="T:log4net.ObjectRenderer.IObjectRenderer"/> that
+ is used to render them.
+ </para>
+ <para>
+ The <see cref="M:log4net.ObjectRenderer.RendererMap.FindAndRender(System.Object)"/> method is used to render an
+ <c>object</c> using the appropriate renderers defined in this map.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.ObjectRenderer.RendererMap.#ctor">
+ <summary>
+ Default Constructor
+ </summary>
+ <remarks>
+ <para>
+ Default constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.ObjectRenderer.RendererMap.FindAndRender(System.Object)">
+ <summary>
+ Render <paramref name="obj"/> using the appropriate renderer.
+ </summary>
+ <param name="obj">the object to render to a string</param>
+ <returns>the object rendered as a string</returns>
+ <remarks>
+ <para>
+ This is a convenience method used to render an object to a string.
+ The alternative method <see cref="M:log4net.ObjectRenderer.RendererMap.FindAndRender(System.Object,System.IO.TextWriter)"/>
+ should be used when streaming output to a <see cref="T:System.IO.TextWriter"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.ObjectRenderer.RendererMap.FindAndRender(System.Object,System.IO.TextWriter)">
+ <summary>
+ Render <paramref name="obj"/> using the appropriate renderer.
+ </summary>
+ <param name="obj">the object to render to a string</param>
+ <param name="writer">The writer to render to</param>
+ <remarks>
+ <para>
+ Find the appropriate renderer for the type of the
+ <paramref name="obj"/> parameter. This is accomplished by calling the
+ <see cref="M:log4net.ObjectRenderer.RendererMap.Get(System.Type)"/> method. Once a renderer is found, it is
+ applied on the object <paramref name="obj"/> and the result is returned
+ as a <see cref="T:System.String"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.ObjectRenderer.RendererMap.Get(System.Object)">
+ <summary>
+ Gets the renderer for the specified object type
+ </summary>
+ <param name="obj">the object to lookup the renderer for</param>
+ <returns>the renderer for <paramref name="obj"/></returns>
+ <remarks>
+ <param>
+ Gets the renderer for the specified object type.
+ </param>
+ <param>
+ Syntactic sugar method that calls <see cref="M:log4net.ObjectRenderer.RendererMap.Get(System.Type)"/>
+ with the type of the object parameter.
+ </param>
+ </remarks>
+ </member>
+ <member name="M:log4net.ObjectRenderer.RendererMap.Get(System.Type)">
+ <summary>
+ Gets the renderer for the specified type
+ </summary>
+ <param name="type">the type to lookup the renderer for</param>
+ <returns>the renderer for the specified type</returns>
+ <remarks>
+ <para>
+ Returns the renderer for the specified type.
+ If no specific renderer has been defined the
+ <see cref="P:log4net.ObjectRenderer.RendererMap.DefaultRenderer"/> will be returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.ObjectRenderer.RendererMap.SearchTypeAndInterfaces(System.Type)">
+ <summary>
+ Internal function to recursively search interfaces
+ </summary>
+ <param name="type">the type to lookup the renderer for</param>
+ <returns>the renderer for the specified type</returns>
+ </member>
+ <member name="M:log4net.ObjectRenderer.RendererMap.Clear">
+ <summary>
+ Clear the map of renderers
+ </summary>
+ <remarks>
+ <para>
+ Clear the custom renderers defined by using
+ <see cref="M:log4net.ObjectRenderer.RendererMap.Put(System.Type,log4net.ObjectRenderer.IObjectRenderer)"/>. The <see cref="P:log4net.ObjectRenderer.RendererMap.DefaultRenderer"/>
+ cannot be removed.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.ObjectRenderer.RendererMap.Put(System.Type,log4net.ObjectRenderer.IObjectRenderer)">
+ <summary>
+ Register an <see cref="T:log4net.ObjectRenderer.IObjectRenderer"/> for <paramref name="typeToRender"/>.
+ </summary>
+ <param name="typeToRender">the type that will be rendered by <paramref name="renderer"/></param>
+ <param name="renderer">the renderer for <paramref name="typeToRender"/></param>
+ <remarks>
+ <para>
+ Register an object renderer for a specific source type.
+ This renderer will be returned from a call to <see cref="M:log4net.ObjectRenderer.RendererMap.Get(System.Type)"/>
+ specifying the same <paramref name="typeToRender"/> as an argument.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.ObjectRenderer.RendererMap.DefaultRenderer">
+ <summary>
+ Get the default renderer instance
+ </summary>
+ <value>the default renderer</value>
+ <remarks>
+ <para>
+ Get the default renderer
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Plugin.IPlugin">
+ <summary>
+ Interface implemented by logger repository plugins.
+ </summary>
+ <remarks>
+ <para>
+ Plugins define additional behavior that can be associated
+ with a <see cref="T:log4net.Repository.ILoggerRepository"/>.
+ The <see cref="T:log4net.Plugin.PluginMap"/> held by the <see cref="P:log4net.Repository.ILoggerRepository.PluginMap"/>
+ property is used to store the plugins for a repository.
+ </para>
+ <para>
+ The <c>log4net.Config.PluginAttribute</c> can be used to
+ attach plugins to repositories created using configuration
+ attributes.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Plugin.IPlugin.Attach(log4net.Repository.ILoggerRepository)">
+ <summary>
+ Attaches the plugin to the specified <see cref="T:log4net.Repository.ILoggerRepository"/>.
+ </summary>
+ <param name="repository">The <see cref="T:log4net.Repository.ILoggerRepository"/> that this plugin should be attached to.</param>
+ <remarks>
+ <para>
+ A plugin may only be attached to a single repository.
+ </para>
+ <para>
+ This method is called when the plugin is attached to the repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Plugin.IPlugin.Shutdown">
+ <summary>
+ Is called when the plugin is to shutdown.
+ </summary>
+ <remarks>
+ <para>
+ This method is called to notify the plugin that
+ it should stop operating and should detach from
+ the repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Plugin.IPlugin.Name">
+ <summary>
+ Gets the name of the plugin.
+ </summary>
+ <value>
+ The name of the plugin.
+ </value>
+ <remarks>
+ <para>
+ Plugins are stored in the <see cref="T:log4net.Plugin.PluginMap"/>
+ keyed by name. Each plugin instance attached to a
+ repository must be a unique name.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Plugin.PluginCollection">
+ <summary>
+ A strongly-typed collection of <see cref="T:log4net.Plugin.IPlugin"/> objects.
+ </summary>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.ReadOnly(log4net.Plugin.PluginCollection)">
+ <summary>
+ Creates a read-only wrapper for a <c>PluginCollection</c> instance.
+ </summary>
+ <param name="list">list to create a readonly wrapper arround</param>
+ <returns>
+ A <c>PluginCollection</c> wrapper that is read-only.
+ </returns>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.#ctor">
+ <summary>
+ Initializes a new instance of the <c>PluginCollection</c> class
+ that is empty and has the default initial capacity.
+ </summary>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.#ctor(System.Int32)">
+ <summary>
+ Initializes a new instance of the <c>PluginCollection</c> class
+ that has the specified initial capacity.
+ </summary>
+ <param name="capacity">
+ The number of elements that the new <c>PluginCollection</c> is initially capable of storing.
+ </param>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.#ctor(log4net.Plugin.PluginCollection)">
+ <summary>
+ Initializes a new instance of the <c>PluginCollection</c> class
+ that contains elements copied from the specified <c>PluginCollection</c>.
+ </summary>
+ <param name="c">The <c>PluginCollection</c> whose elements are copied to the new collection.</param>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.#ctor(log4net.Plugin.IPlugin[])">
+ <summary>
+ Initializes a new instance of the <c>PluginCollection</c> class
+ that contains elements copied from the specified <see cref="T:log4net.Plugin.IPlugin"/> array.
+ </summary>
+ <param name="a">The <see cref="T:log4net.Plugin.IPlugin"/> array whose elements are copied to the new list.</param>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.#ctor(System.Collections.ICollection)">
+ <summary>
+ Initializes a new instance of the <c>PluginCollection</c> class
+ that contains elements copied from the specified <see cref="T:log4net.Plugin.IPlugin"/> collection.
+ </summary>
+ <param name="col">The <see cref="T:log4net.Plugin.IPlugin"/> collection whose elements are copied to the new list.</param>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.#ctor(log4net.Plugin.PluginCollection.Tag)">
+ <summary>
+ Allow subclasses to avoid our default constructors
+ </summary>
+ <param name="tag"></param>
+ <exclude/>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.CopyTo(log4net.Plugin.IPlugin[])">
+ <summary>
+ Copies the entire <c>PluginCollection</c> to a one-dimensional
+ <see cref="T:log4net.Plugin.IPlugin"/> array.
+ </summary>
+ <param name="array">The one-dimensional <see cref="T:log4net.Plugin.IPlugin"/> array to copy to.</param>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.CopyTo(log4net.Plugin.IPlugin[],System.Int32)">
+ <summary>
+ Copies the entire <c>PluginCollection</c> to a one-dimensional
+ <see cref="T:log4net.Plugin.IPlugin"/> array, starting at the specified index of the target array.
+ </summary>
+ <param name="array">The one-dimensional <see cref="T:log4net.Plugin.IPlugin"/> array to copy to.</param>
+ <param name="start">The zero-based index in <paramref name="array"/> at which copying begins.</param>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.Add(log4net.Plugin.IPlugin)">
+ <summary>
+ Adds a <see cref="T:log4net.Plugin.IPlugin"/> to the end of the <c>PluginCollection</c>.
+ </summary>
+ <param name="item">The <see cref="T:log4net.Plugin.IPlugin"/> to be added to the end of the <c>PluginCollection</c>.</param>
+ <returns>The index at which the value has been added.</returns>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.Clear">
+ <summary>
+ Removes all elements from the <c>PluginCollection</c>.
+ </summary>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.Clone">
+ <summary>
+ Creates a shallow copy of the <see cref="T:log4net.Plugin.PluginCollection"/>.
+ </summary>
+ <returns>A new <see cref="T:log4net.Plugin.PluginCollection"/> with a shallow copy of the collection data.</returns>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.Contains(log4net.Plugin.IPlugin)">
+ <summary>
+ Determines whether a given <see cref="T:log4net.Plugin.IPlugin"/> is in the <c>PluginCollection</c>.
+ </summary>
+ <param name="item">The <see cref="T:log4net.Plugin.IPlugin"/> to check for.</param>
+ <returns><c>true</c> if <paramref name="item"/> is found in the <c>PluginCollection</c>; otherwise, <c>false</c>.</returns>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.IndexOf(log4net.Plugin.IPlugin)">
+ <summary>
+ Returns the zero-based index of the first occurrence of a <see cref="T:log4net.Plugin.IPlugin"/>
+ in the <c>PluginCollection</c>.
+ </summary>
+ <param name="item">The <see cref="T:log4net.Plugin.IPlugin"/> to locate in the <c>PluginCollection</c>.</param>
+ <returns>
+ The zero-based index of the first occurrence of <paramref name="item"/>
+ in the entire <c>PluginCollection</c>, if found; otherwise, -1.
+ </returns>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.Insert(System.Int32,log4net.Plugin.IPlugin)">
+ <summary>
+ Inserts an element into the <c>PluginCollection</c> at the specified index.
+ </summary>
+ <param name="index">The zero-based index at which <paramref name="item"/> should be inserted.</param>
+ <param name="item">The <see cref="T:log4net.Plugin.IPlugin"/> to insert.</param>
+ <exception cref="T:System.ArgumentOutOfRangeException">
+ <para><paramref name="index"/> is less than zero</para>
+ <para>-or-</para>
+ <para><paramref name="index"/> is equal to or greater than <see cref="P:log4net.Plugin.PluginCollection.Count"/>.</para>
+ </exception>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.Remove(log4net.Plugin.IPlugin)">
+ <summary>
+ Removes the first occurrence of a specific <see cref="T:log4net.Plugin.IPlugin"/> from the <c>PluginCollection</c>.
+ </summary>
+ <param name="item">The <see cref="T:log4net.Plugin.IPlugin"/> to remove from the <c>PluginCollection</c>.</param>
+ <exception cref="T:System.ArgumentException">
+ The specified <see cref="T:log4net.Plugin.IPlugin"/> was not found in the <c>PluginCollection</c>.
+ </exception>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.RemoveAt(System.Int32)">
+ <summary>
+ Removes the element at the specified index of the <c>PluginCollection</c>.
+ </summary>
+ <param name="index">The zero-based index of the element to remove.</param>
+ <exception cref="T:System.ArgumentOutOfRangeException">
+ <para><paramref name="index"/> is less than zero.</para>
+ <para>-or-</para>
+ <para><paramref name="index"/> is equal to or greater than <see cref="P:log4net.Plugin.PluginCollection.Count"/>.</para>
+ </exception>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.GetEnumerator">
+ <summary>
+ Returns an enumerator that can iterate through the <c>PluginCollection</c>.
+ </summary>
+ <returns>An <see cref="T:log4net.Plugin.PluginCollection.Enumerator"/> for the entire <c>PluginCollection</c>.</returns>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.AddRange(log4net.Plugin.PluginCollection)">
+ <summary>
+ Adds the elements of another <c>PluginCollection</c> to the current <c>PluginCollection</c>.
+ </summary>
+ <param name="x">The <c>PluginCollection</c> whose elements should be added to the end of the current <c>PluginCollection</c>.</param>
+ <returns>The new <see cref="P:log4net.Plugin.PluginCollection.Count"/> of the <c>PluginCollection</c>.</returns>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.AddRange(log4net.Plugin.IPlugin[])">
+ <summary>
+ Adds the elements of a <see cref="T:log4net.Plugin.IPlugin"/> array to the current <c>PluginCollection</c>.
+ </summary>
+ <param name="x">The <see cref="T:log4net.Plugin.IPlugin"/> array whose elements should be added to the end of the <c>PluginCollection</c>.</param>
+ <returns>The new <see cref="P:log4net.Plugin.PluginCollection.Count"/> of the <c>PluginCollection</c>.</returns>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.AddRange(System.Collections.ICollection)">
+ <summary>
+ Adds the elements of a <see cref="T:log4net.Plugin.IPlugin"/> collection to the current <c>PluginCollection</c>.
+ </summary>
+ <param name="col">The <see cref="T:log4net.Plugin.IPlugin"/> collection whose elements should be added to the end of the <c>PluginCollection</c>.</param>
+ <returns>The new <see cref="P:log4net.Plugin.PluginCollection.Count"/> of the <c>PluginCollection</c>.</returns>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.TrimToSize">
+ <summary>
+ Sets the capacity to the actual number of elements.
+ </summary>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.ValidateIndex(System.Int32)">
+ <exception cref="T:System.ArgumentOutOfRangeException">
+ <para><paramref name="index"/> is less than zero.</para>
+ <para>-or-</para>
+ <para><paramref name="index"/> is equal to or greater than <see cref="P:log4net.Plugin.PluginCollection.Count"/>.</para>
+ </exception>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.ValidateIndex(System.Int32,System.Boolean)">
+ <exception cref="T:System.ArgumentOutOfRangeException">
+ <para><paramref name="index"/> is less than zero.</para>
+ <para>-or-</para>
+ <para><paramref name="index"/> is equal to or greater than <see cref="P:log4net.Plugin.PluginCollection.Count"/>.</para>
+ </exception>
+ </member>
+ <member name="P:log4net.Plugin.PluginCollection.Count">
+ <summary>
+ Gets the number of elements actually contained in the <c>PluginCollection</c>.
+ </summary>
+ </member>
+ <member name="P:log4net.Plugin.PluginCollection.IsSynchronized">
+ <summary>
+ Gets a value indicating whether access to the collection is synchronized (thread-safe).
+ </summary>
+ <returns>true if access to the ICollection is synchronized (thread-safe); otherwise, false.</returns>
+ </member>
+ <member name="P:log4net.Plugin.PluginCollection.SyncRoot">
+ <summary>
+ Gets an object that can be used to synchronize access to the collection.
+ </summary>
+ <value>
+ An object that can be used to synchronize access to the collection.
+ </value>
+ </member>
+ <member name="P:log4net.Plugin.PluginCollection.Item(System.Int32)">
+ <summary>
+ Gets or sets the <see cref="T:log4net.Plugin.IPlugin"/> at the specified index.
+ </summary>
+ <value>
+ The <see cref="T:log4net.Plugin.IPlugin"/> at the specified index.
+ </value>
+ <param name="index">The zero-based index of the element to get or set.</param>
+ <exception cref="T:System.ArgumentOutOfRangeException">
+ <para><paramref name="index"/> is less than zero.</para>
+ <para>-or-</para>
+ <para><paramref name="index"/> is equal to or greater than <see cref="P:log4net.Plugin.PluginCollection.Count"/>.</para>
+ </exception>
+ </member>
+ <member name="P:log4net.Plugin.PluginCollection.IsFixedSize">
+ <summary>
+ Gets a value indicating whether the collection has a fixed size.
+ </summary>
+ <value><c>true</c> if the collection has a fixed size; otherwise, <c>false</c>. The default is <c>false</c>.</value>
+ </member>
+ <member name="P:log4net.Plugin.PluginCollection.IsReadOnly">
+ <summary>
+ Gets a value indicating whether the IList is read-only.
+ </summary>
+ <value><c>true</c> if the collection is read-only; otherwise, <c>false</c>. The default is <c>false</c>.</value>
+ </member>
+ <member name="P:log4net.Plugin.PluginCollection.Capacity">
+ <summary>
+ Gets or sets the number of elements the <c>PluginCollection</c> can contain.
+ </summary>
+ <value>
+ The number of elements the <c>PluginCollection</c> can contain.
+ </value>
+ </member>
+ <member name="T:log4net.Plugin.PluginCollection.IPluginCollectionEnumerator">
+ <summary>
+ Supports type-safe iteration over a <see cref="T:log4net.Plugin.PluginCollection"/>.
+ </summary>
+ <exclude/>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.IPluginCollectionEnumerator.MoveNext">
+ <summary>
+ Advances the enumerator to the next element in the collection.
+ </summary>
+ <returns>
+ <c>true</c> if the enumerator was successfully advanced to the next element;
+ <c>false</c> if the enumerator has passed the end of the collection.
+ </returns>
+ <exception cref="T:System.InvalidOperationException">
+ The collection was modified after the enumerator was created.
+ </exception>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.IPluginCollectionEnumerator.Reset">
+ <summary>
+ Sets the enumerator to its initial position, before the first element in the collection.
+ </summary>
+ </member>
+ <member name="P:log4net.Plugin.PluginCollection.IPluginCollectionEnumerator.Current">
+ <summary>
+ Gets the current element in the collection.
+ </summary>
+ </member>
+ <member name="T:log4net.Plugin.PluginCollection.Tag">
+ <summary>
+ Type visible only to our subclasses
+ Used to access protected constructor
+ </summary>
+ <exclude/>
+ </member>
+ <member name="F:log4net.Plugin.PluginCollection.Tag.Default">
+ <summary>
+ A value
+ </summary>
+ </member>
+ <member name="T:log4net.Plugin.PluginCollection.Enumerator">
+ <summary>
+ Supports simple iteration over a <see cref="T:log4net.Plugin.PluginCollection"/>.
+ </summary>
+ <exclude/>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.Enumerator.#ctor(log4net.Plugin.PluginCollection)">
+ <summary>
+ Initializes a new instance of the <c>Enumerator</c> class.
+ </summary>
+ <param name="tc"></param>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.Enumerator.MoveNext">
+ <summary>
+ Advances the enumerator to the next element in the collection.
+ </summary>
+ <returns>
+ <c>true</c> if the enumerator was successfully advanced to the next element;
+ <c>false</c> if the enumerator has passed the end of the collection.
+ </returns>
+ <exception cref="T:System.InvalidOperationException">
+ The collection was modified after the enumerator was created.
+ </exception>
+ </member>
+ <member name="M:log4net.Plugin.PluginCollection.Enumerator.Reset">
+ <summary>
+ Sets the enumerator to its initial position, before the first element in the collection.
+ </summary>
+ </member>
+ <member name="P:log4net.Plugin.PluginCollection.Enumerator.Current">
+ <summary>
+ Gets the current element in the collection.
+ </summary>
+ <value>
+ The current element in the collection.
+ </value>
+ </member>
+ <member name="T:log4net.Plugin.PluginCollection.ReadOnlyPluginCollection">
+ <exclude/>
+ </member>
+ <member name="T:log4net.Plugin.PluginMap">
+ <summary>
+ Map of repository plugins.
+ </summary>
+ <remarks>
+ <para>
+ This class is a name keyed map of the plugins that are
+ attached to a repository.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Plugin.PluginMap.#ctor(log4net.Repository.ILoggerRepository)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="repository">The repository that the plugins should be attached to.</param>
+ <remarks>
+ <para>
+ Initialize a new instance of the <see cref="T:log4net.Plugin.PluginMap"/> class with a
+ repository that the plugins should be attached to.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Plugin.PluginMap.Add(log4net.Plugin.IPlugin)">
+ <summary>
+ Adds a <see cref="T:log4net.Plugin.IPlugin"/> to the map.
+ </summary>
+ <param name="plugin">The <see cref="T:log4net.Plugin.IPlugin"/> to add to the map.</param>
+ <remarks>
+ <para>
+ The <see cref="T:log4net.Plugin.IPlugin"/> will be attached to the repository when added.
+ </para>
+ <para>
+ If there already exists a plugin with the same name
+ attached to the repository then the old plugin will
+ be <see cref="M:log4net.Plugin.IPlugin.Shutdown"/> and replaced with
+ the new plugin.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Plugin.PluginMap.Remove(log4net.Plugin.IPlugin)">
+ <summary>
+ Removes a <see cref="T:log4net.Plugin.IPlugin"/> from the map.
+ </summary>
+ <param name="plugin">The <see cref="T:log4net.Plugin.IPlugin"/> to remove from the map.</param>
+ <remarks>
+ <para>
+ Remove a specific plugin from this map.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Plugin.PluginMap.Item(System.String)">
+ <summary>
+ Gets a <see cref="T:log4net.Plugin.IPlugin"/> by name.
+ </summary>
+ <param name="name">The name of the <see cref="T:log4net.Plugin.IPlugin"/> to lookup.</param>
+ <returns>
+ The <see cref="T:log4net.Plugin.IPlugin"/> from the map with the name specified, or
+ <c>null</c> if no plugin is found.
+ </returns>
+ <remarks>
+ <para>
+ Lookup a plugin by name. If the plugin is not found <c>null</c>
+ will be returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Plugin.PluginMap.AllPlugins">
+ <summary>
+ Gets all possible plugins as a list of <see cref="T:log4net.Plugin.IPlugin"/> objects.
+ </summary>
+ <value>All possible plugins as a list of <see cref="T:log4net.Plugin.IPlugin"/> objects.</value>
+ <remarks>
+ <para>
+ Get a collection of all the plugins defined in this map.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Plugin.PluginSkeleton">
+ <summary>
+ Base implementation of <see cref="T:log4net.Plugin.IPlugin"/>
+ </summary>
+ <remarks>
+ <para>
+ Default abstract implementation of the <see cref="T:log4net.Plugin.IPlugin"/>
+ interface. This base class can be used by implementors
+ of the <see cref="T:log4net.Plugin.IPlugin"/> interface.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Plugin.PluginSkeleton.#ctor(System.String)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="name">the name of the plugin</param>
+ <remarks>
+ Initializes a new Plugin with the specified name.
+ </remarks>
+ </member>
+ <member name="M:log4net.Plugin.PluginSkeleton.Attach(log4net.Repository.ILoggerRepository)">
+ <summary>
+ Attaches this plugin to a <see cref="T:log4net.Repository.ILoggerRepository"/>.
+ </summary>
+ <param name="repository">The <see cref="T:log4net.Repository.ILoggerRepository"/> that this plugin should be attached to.</param>
+ <remarks>
+ <para>
+ A plugin may only be attached to a single repository.
+ </para>
+ <para>
+ This method is called when the plugin is attached to the repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Plugin.PluginSkeleton.Shutdown">
+ <summary>
+ Is called when the plugin is to shutdown.
+ </summary>
+ <remarks>
+ <para>
+ This method is called to notify the plugin that
+ it should stop operating and should detach from
+ the repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Plugin.PluginSkeleton.m_name">
+ <summary>
+ The name of this plugin.
+ </summary>
+ </member>
+ <member name="F:log4net.Plugin.PluginSkeleton.m_repository">
+ <summary>
+ The repository this plugin is attached to.
+ </summary>
+ </member>
+ <member name="P:log4net.Plugin.PluginSkeleton.Name">
+ <summary>
+ Gets or sets the name of the plugin.
+ </summary>
+ <value>
+ The name of the plugin.
+ </value>
+ <remarks>
+ <para>
+ Plugins are stored in the <see cref="T:log4net.Plugin.PluginMap"/>
+ keyed by name. Each plugin instance attached to a
+ repository must be a unique name.
+ </para>
+ <para>
+ The name of the plugin must not change one the
+ plugin has been attached to a repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Plugin.PluginSkeleton.LoggerRepository">
+ <summary>
+ The repository for this plugin
+ </summary>
+ <value>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> that this plugin is attached to.
+ </value>
+ <remarks>
+ <para>
+ Gets or sets the <see cref="T:log4net.Repository.ILoggerRepository"/> that this plugin is
+ attached to.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Plugin.RemoteLoggingServerPlugin">
+ <summary>
+ Plugin that listens for events from the <see cref="T:log4net.Appender.RemotingAppender"/>
+ </summary>
+ <remarks>
+ <para>
+ This plugin publishes an instance of <see cref="T:log4net.Appender.RemotingAppender.IRemoteLoggingSink"/>
+ on a specified <see cref="P:log4net.Plugin.RemoteLoggingServerPlugin.SinkUri"/>. This listens for logging events delivered from
+ a remote <see cref="T:log4net.Appender.RemotingAppender"/>.
+ </para>
+ <para>
+ When an event is received it is relogged within the attached repository
+ as if it had been raised locally.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Plugin.RemoteLoggingServerPlugin.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Plugin.RemoteLoggingServerPlugin"/> class.
+ </para>
+ <para>
+ The <see cref="P:log4net.Plugin.RemoteLoggingServerPlugin.SinkUri"/> property must be set.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Plugin.RemoteLoggingServerPlugin.#ctor(System.String)">
+ <summary>
+ Construct with sink Uri.
+ </summary>
+ <param name="sinkUri">The name to publish the sink under in the remoting infrastructure.
+ See <see cref="P:log4net.Plugin.RemoteLoggingServerPlugin.SinkUri"/> for more details.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Plugin.RemoteLoggingServerPlugin"/> class
+ with specified name.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Plugin.RemoteLoggingServerPlugin.Attach(log4net.Repository.ILoggerRepository)">
+ <summary>
+ Attaches this plugin to a <see cref="T:log4net.Repository.ILoggerRepository"/>.
+ </summary>
+ <param name="repository">The <see cref="T:log4net.Repository.ILoggerRepository"/> that this plugin should be attached to.</param>
+ <remarks>
+ <para>
+ A plugin may only be attached to a single repository.
+ </para>
+ <para>
+ This method is called when the plugin is attached to the repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Plugin.RemoteLoggingServerPlugin.Shutdown">
+ <summary>
+ Is called when the plugin is to shutdown.
+ </summary>
+ <remarks>
+ <para>
+ When the plugin is shutdown the remote logging
+ sink is disconnected.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Plugin.RemoteLoggingServerPlugin.SinkUri">
+ <summary>
+ Gets or sets the URI of this sink.
+ </summary>
+ <value>
+ The URI of this sink.
+ </value>
+ <remarks>
+ <para>
+ This is the name under which the object is marshaled.
+ <see cref="M:System.Runtime.Remoting.RemotingServices.Marshal(System.MarshalByRefObject,System.String,System.Type)"/>
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Plugin.RemoteLoggingServerPlugin.RemoteLoggingSinkImpl">
+ <summary>
+ Delivers <see cref="T:log4net.Core.LoggingEvent"/> objects to a remote sink.
+ </summary>
+ <remarks>
+ <para>
+ Internal class used to listen for logging events
+ and deliver them to the local repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Plugin.RemoteLoggingServerPlugin.RemoteLoggingSinkImpl.#ctor(log4net.Repository.ILoggerRepository)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="repository">The repository to log to.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Plugin.RemoteLoggingServerPlugin.RemoteLoggingSinkImpl"/> for the
+ specified <see cref="T:log4net.Repository.ILoggerRepository"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Plugin.RemoteLoggingServerPlugin.RemoteLoggingSinkImpl.LogEvents(log4net.Core.LoggingEvent[])">
+ <summary>
+ Logs the events to the repository.
+ </summary>
+ <param name="events">The events to log.</param>
+ <remarks>
+ <para>
+ The events passed are logged to the <see cref="T:log4net.Repository.ILoggerRepository"/>
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Plugin.RemoteLoggingServerPlugin.RemoteLoggingSinkImpl.InitializeLifetimeService">
+ <summary>
+ Obtains a lifetime service object to control the lifetime
+ policy for this instance.
+ </summary>
+ <returns><c>null</c> to indicate that this instance should live forever.</returns>
+ <remarks>
+ <para>
+ Obtains a lifetime service object to control the lifetime
+ policy for this instance. This object should live forever
+ therefore this implementation returns <c>null</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Plugin.RemoteLoggingServerPlugin.RemoteLoggingSinkImpl.m_repository">
+ <summary>
+ The underlying <see cref="T:log4net.Repository.ILoggerRepository"/> that events should
+ be logged to.
+ </summary>
+ </member>
+ <member name="T:log4net.Repository.Hierarchy.DefaultLoggerFactory">
+ <summary>
+ Default implementation of <see cref="T:log4net.Repository.Hierarchy.ILoggerFactory"/>
+ </summary>
+ <remarks>
+ <para>
+ This default implementation of the <see cref="T:log4net.Repository.Hierarchy.ILoggerFactory"/>
+ interface is used to create the default subclass
+ of the <see cref="T:log4net.Repository.Hierarchy.Logger"/> object.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.Repository.Hierarchy.ILoggerFactory">
+ <summary>
+ Interface abstracts creation of <see cref="T:log4net.Repository.Hierarchy.Logger"/> instances
+ </summary>
+ <remarks>
+ <para>
+ This interface is used by the <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/> to
+ create new <see cref="T:log4net.Repository.Hierarchy.Logger"/> objects.
+ </para>
+ <para>
+ The <see cref="M:log4net.Repository.Hierarchy.ILoggerFactory.CreateLogger(System.String)"/> method is called
+ to create a named <see cref="T:log4net.Repository.Hierarchy.Logger"/>.
+ </para>
+ <para>
+ Implement this interface to create new subclasses of <see cref="T:log4net.Repository.Hierarchy.Logger"/>.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.ILoggerFactory.CreateLogger(System.String)">
+ <summary>
+ Create a new <see cref="T:log4net.Repository.Hierarchy.Logger"/> instance
+ </summary>
+ <param name="name">The name of the <see cref="T:log4net.Repository.Hierarchy.Logger"/>.</param>
+ <returns>The <see cref="T:log4net.Repository.Hierarchy.Logger"/> instance for the specified name.</returns>
+ <remarks>
+ <para>
+ Create a new <see cref="T:log4net.Repository.Hierarchy.Logger"/> instance with the
+ specified name.
+ </para>
+ <para>
+ Called by the <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/> to create
+ new named <see cref="T:log4net.Repository.Hierarchy.Logger"/> instances.
+ </para>
+ <para>
+ If the <paramref name="name"/> is <c>null</c> then the root logger
+ must be returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.DefaultLoggerFactory.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Repository.Hierarchy.DefaultLoggerFactory"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.DefaultLoggerFactory.CreateLogger(System.String)">
+ <summary>
+ Create a new <see cref="T:log4net.Repository.Hierarchy.Logger"/> instance
+ </summary>
+ <param name="name">The name of the <see cref="T:log4net.Repository.Hierarchy.Logger"/>.</param>
+ <returns>The <see cref="T:log4net.Repository.Hierarchy.Logger"/> instance for the specified name.</returns>
+ <remarks>
+ <para>
+ Create a new <see cref="T:log4net.Repository.Hierarchy.Logger"/> instance with the
+ specified name.
+ </para>
+ <para>
+ Called by the <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/> to create
+ new named <see cref="T:log4net.Repository.Hierarchy.Logger"/> instances.
+ </para>
+ <para>
+ If the <paramref name="name"/> is <c>null</c> then the root logger
+ must be returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Repository.Hierarchy.DefaultLoggerFactory.LoggerImpl">
+ <summary>
+ Default internal subclass of <see cref="T:log4net.Repository.Hierarchy.Logger"/>
+ </summary>
+ <remarks>
+ <para>
+ This subclass has no additional behavior over the
+ <see cref="T:log4net.Repository.Hierarchy.Logger"/> class but does allow instances
+ to be created.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Repository.Hierarchy.Logger">
+ <summary>
+ Implementation of <see cref="T:log4net.Core.ILogger"/> used by <see cref="P:log4net.Repository.Hierarchy.Logger.Hierarchy"/>
+ </summary>
+ <remarks>
+ <para>
+ Internal class used to provide implementation of <see cref="T:log4net.Core.ILogger"/>
+ interface. Applications should use <see cref="T:log4net.LogManager"/> to get
+ logger instances.
+ </para>
+ <para>
+ This is one of the central classes in the log4net implementation. One of the
+ distinctive features of log4net are hierarchical loggers and their
+ evaluation. The <see cref="P:log4net.Repository.Hierarchy.Logger.Hierarchy"/> organizes the <see cref="T:log4net.Repository.Hierarchy.Logger"/>
+ instances into a rooted tree hierarchy.
+ </para>
+ <para>
+ The <see cref="T:log4net.Repository.Hierarchy.Logger"/> class is abstract. Only concrete subclasses of
+ <see cref="T:log4net.Repository.Hierarchy.Logger"/> can be created. The <see cref="T:log4net.Repository.Hierarchy.ILoggerFactory"/>
+ is used to create instances of this type for the <see cref="P:log4net.Repository.Hierarchy.Logger.Hierarchy"/>.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ <author>Aspi Havewala</author>
+ <author>Douglas de la Torre</author>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Logger.#ctor(System.String)">
+ <summary>
+ This constructor created a new <see cref="T:log4net.Repository.Hierarchy.Logger"/> instance and
+ sets its name.
+ </summary>
+ <param name="name">The name of the <see cref="T:log4net.Repository.Hierarchy.Logger"/>.</param>
+ <remarks>
+ <para>
+ This constructor is protected and designed to be used by
+ a subclass that is not abstract.
+ </para>
+ <para>
+ Loggers are constructed by <see cref="T:log4net.Repository.Hierarchy.ILoggerFactory"/>
+ objects. See <see cref="T:log4net.Repository.Hierarchy.DefaultLoggerFactory"/> for the default
+ logger creator.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Logger.AddAppender(log4net.Appender.IAppender)">
+ <summary>
+ Add <paramref name="newAppender"/> to the list of appenders of this
+ Logger instance.
+ </summary>
+ <param name="newAppender">An appender to add to this logger</param>
+ <remarks>
+ <para>
+ Add <paramref name="newAppender"/> to the list of appenders of this
+ Logger instance.
+ </para>
+ <para>
+ If <paramref name="newAppender"/> is already in the list of
+ appenders, then it won't be added again.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Logger.GetAppender(System.String)">
+ <summary>
+ Look for the appender named as <c>name</c>
+ </summary>
+ <param name="name">The name of the appender to lookup</param>
+ <returns>The appender with the name specified, or <c>null</c>.</returns>
+ <remarks>
+ <para>
+ Returns the named appender, or null if the appender is not found.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Logger.RemoveAllAppenders">
+ <summary>
+ Remove all previously added appenders from this Logger instance.
+ </summary>
+ <remarks>
+ <para>
+ Remove all previously added appenders from this Logger instance.
+ </para>
+ <para>
+ This is useful when re-reading configuration information.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Logger.RemoveAppender(log4net.Appender.IAppender)">
+ <summary>
+ Remove the appender passed as parameter form the list of appenders.
+ </summary>
+ <param name="appender">The appender to remove</param>
+ <returns>The appender removed from the list</returns>
+ <remarks>
+ <para>
+ Remove the appender passed as parameter form the list of appenders.
+ The appender removed is not closed.
+ If you are discarding the appender you must call
+ <see cref="M:log4net.Appender.IAppender.Close"/> on the appender removed.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Logger.RemoveAppender(System.String)">
+ <summary>
+ Remove the appender passed as parameter form the list of appenders.
+ </summary>
+ <param name="name">The name of the appender to remove</param>
+ <returns>The appender removed from the list</returns>
+ <remarks>
+ <para>
+ Remove the named appender passed as parameter form the list of appenders.
+ The appender removed is not closed.
+ If you are discarding the appender you must call
+ <see cref="M:log4net.Appender.IAppender.Close"/> on the appender removed.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Logger.Log(System.Type,log4net.Core.Level,System.Object,System.Exception)">
+ <summary>
+ This generic form is intended to be used by wrappers.
+ </summary>
+ <param name="callerStackBoundaryDeclaringType">The declaring type of the method that is
+ the stack boundary into the logging system for this call.</param>
+ <param name="level">The level of the message to be logged.</param>
+ <param name="message">The message object to log.</param>
+ <param name="exception">The exception to log, including its stack trace.</param>
+ <remarks>
+ <para>
+ Generate a logging event for the specified <paramref name="level"/> using
+ the <paramref name="message"/> and <paramref name="exception"/>.
+ </para>
+ <para>
+ This method must not throw any exception to the caller.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Logger.Log(log4net.Core.LoggingEvent)">
+ <summary>
+ This is the most generic printing method that is intended to be used
+ by wrappers.
+ </summary>
+ <param name="logEvent">The event being logged.</param>
+ <remarks>
+ <para>
+ Logs the specified logging event through this logger.
+ </para>
+ <para>
+ This method must not throw any exception to the caller.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Logger.IsEnabledFor(log4net.Core.Level)">
+ <summary>
+ Checks if this logger is enabled for a given <see cref="P:log4net.Repository.Hierarchy.Logger.Level"/> passed as parameter.
+ </summary>
+ <param name="level">The level to check.</param>
+ <returns>
+ <c>true</c> if this logger is enabled for <c>level</c>, otherwise <c>false</c>.
+ </returns>
+ <remarks>
+ <para>
+ Test if this logger is going to log events of the specified <paramref name="level"/>.
+ </para>
+ <para>
+ This method must not throw any exception to the caller.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Logger.CallAppenders(log4net.Core.LoggingEvent)">
+ <summary>
+ Deliver the <see cref="T:log4net.Core.LoggingEvent"/> to the attached appenders.
+ </summary>
+ <param name="loggingEvent">The event to log.</param>
+ <remarks>
+ <para>
+ Call the appenders in the hierarchy starting at
+ <c>this</c>. If no appenders could be found, emit a
+ warning.
+ </para>
+ <para>
+ This method calls all the appenders inherited from the
+ hierarchy circumventing any evaluation of whether to log or not
+ to log the particular log request.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Logger.CloseNestedAppenders">
+ <summary>
+ Closes all attached appenders implementing the <see cref="T:log4net.Core.IAppenderAttachable"/> interface.
+ </summary>
+ <remarks>
+ <para>
+ Used to ensure that the appenders are correctly shutdown.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Logger.Log(log4net.Core.Level,System.Object,System.Exception)">
+ <summary>
+ This is the most generic printing method. This generic form is intended to be used by wrappers
+ </summary>
+ <param name="level">The level of the message to be logged.</param>
+ <param name="message">The message object to log.</param>
+ <param name="exception">The exception to log, including its stack trace.</param>
+ <remarks>
+ <para>
+ Generate a logging event for the specified <paramref name="level"/> using
+ the <paramref name="message"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Logger.ForcedLog(System.Type,log4net.Core.Level,System.Object,System.Exception)">
+ <summary>
+ Creates a new logging event and logs the event without further checks.
+ </summary>
+ <param name="callerStackBoundaryDeclaringType">The declaring type of the method that is
+ the stack boundary into the logging system for this call.</param>
+ <param name="level">The level of the message to be logged.</param>
+ <param name="message">The message object to log.</param>
+ <param name="exception">The exception to log, including its stack trace.</param>
+ <remarks>
+ <para>
+ Generates a logging event and delivers it to the attached
+ appenders.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Logger.ForcedLog(log4net.Core.LoggingEvent)">
+ <summary>
+ Creates a new logging event and logs the event without further checks.
+ </summary>
+ <param name="logEvent">The event being logged.</param>
+ <remarks>
+ <para>
+ Delivers the logging event to the attached appenders.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Repository.Hierarchy.Logger.ThisDeclaringType">
+ <summary>
+ The fully qualified type of the Logger class.
+ </summary>
+ </member>
+ <member name="F:log4net.Repository.Hierarchy.Logger.m_name">
+ <summary>
+ The name of this logger.
+ </summary>
+ </member>
+ <member name="F:log4net.Repository.Hierarchy.Logger.m_level">
+ <summary>
+ The assigned level of this logger.
+ </summary>
+ <remarks>
+ <para>
+ The <c>level</c> variable need not be
+ assigned a value in which case it is inherited
+ form the hierarchy.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Repository.Hierarchy.Logger.m_parent">
+ <summary>
+ The parent of this logger.
+ </summary>
+ <remarks>
+ <para>
+ The parent of this logger.
+ All loggers have at least one ancestor which is the root logger.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Repository.Hierarchy.Logger.m_hierarchy">
+ <summary>
+ Loggers need to know what Hierarchy they are in.
+ </summary>
+ <remarks>
+ <para>
+ Loggers need to know what Hierarchy they are in.
+ The hierarchy that this logger is a member of is stored
+ here.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Repository.Hierarchy.Logger.m_appenderAttachedImpl">
+ <summary>
+ Helper implementation of the <see cref="T:log4net.Core.IAppenderAttachable"/> interface
+ </summary>
+ </member>
+ <member name="F:log4net.Repository.Hierarchy.Logger.m_additive">
+ <summary>
+ Flag indicating if child loggers inherit their parents appenders
+ </summary>
+ <remarks>
+ <para>
+ Additivity is set to true by default, that is children inherit
+ the appenders of their ancestors by default. If this variable is
+ set to <c>false</c> then the appenders found in the
+ ancestors of this logger are not used. However, the children
+ of this logger will inherit its appenders, unless the children
+ have their additivity flag set to <c>false</c> too. See
+ the user manual for more details.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Repository.Hierarchy.Logger.m_appenderLock">
+ <summary>
+ Lock to protect AppenderAttachedImpl variable m_appenderAttachedImpl
+ </summary>
+ </member>
+ <member name="P:log4net.Repository.Hierarchy.Logger.Parent">
+ <summary>
+ Gets or sets the parent logger in the hierarchy.
+ </summary>
+ <value>
+ The parent logger in the hierarchy.
+ </value>
+ <remarks>
+ <para>
+ Part of the Composite pattern that makes the hierarchy.
+ The hierarchy is parent linked rather than child linked.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.Hierarchy.Logger.Additivity">
+ <summary>
+ Gets or sets a value indicating if child loggers inherit their parent's appenders.
+ </summary>
+ <value>
+ <c>true</c> if child loggers inherit their parent's appenders.
+ </value>
+ <remarks>
+ <para>
+ Additivity is set to <c>true</c> by default, that is children inherit
+ the appenders of their ancestors by default. If this variable is
+ set to <c>false</c> then the appenders found in the
+ ancestors of this logger are not used. However, the children
+ of this logger will inherit its appenders, unless the children
+ have their additivity flag set to <c>false</c> too. See
+ the user manual for more details.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.Hierarchy.Logger.EffectiveLevel">
+ <summary>
+ Gets the effective level for this logger.
+ </summary>
+ <returns>The nearest level in the logger hierarchy.</returns>
+ <remarks>
+ <para>
+ Starting from this logger, searches the logger hierarchy for a
+ non-null level and returns it. Otherwise, returns the level of the
+ root logger.
+ </para>
+ <para>The Logger class is designed so that this method executes as
+ quickly as possible.</para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.Hierarchy.Logger.Hierarchy">
+ <summary>
+ Gets or sets the <see cref="P:log4net.Repository.Hierarchy.Logger.Hierarchy"/> where this
+ <c>Logger</c> instance is attached to.
+ </summary>
+ <value>The hierarchy that this logger belongs to.</value>
+ <remarks>
+ <para>
+ This logger must be attached to a single <see cref="P:log4net.Repository.Hierarchy.Logger.Hierarchy"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.Hierarchy.Logger.Level">
+ <summary>
+ Gets or sets the assigned <see cref="P:log4net.Repository.Hierarchy.Logger.Level"/>, if any, for this Logger.
+ </summary>
+ <value>
+ The <see cref="P:log4net.Repository.Hierarchy.Logger.Level"/> of this logger.
+ </value>
+ <remarks>
+ <para>
+ The assigned <see cref="P:log4net.Repository.Hierarchy.Logger.Level"/> can be <c>null</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.Hierarchy.Logger.Appenders">
+ <summary>
+ Get the appenders contained in this logger as an
+ <see cref="T:System.Collections.ICollection"/>.
+ </summary>
+ <returns>A collection of the appenders in this logger</returns>
+ <remarks>
+ <para>
+ Get the appenders contained in this logger as an
+ <see cref="T:System.Collections.ICollection"/>. If no appenders
+ can be found, then a <see cref="T:log4net.Util.EmptyCollection"/> is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.Hierarchy.Logger.Name">
+ <summary>
+ Gets the logger name.
+ </summary>
+ <value>
+ The name of the logger.
+ </value>
+ <remarks>
+ <para>
+ The name of this logger
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.Hierarchy.Logger.Repository">
+ <summary>
+ Gets the <see cref="T:log4net.Repository.ILoggerRepository"/> where this
+ <c>Logger</c> instance is attached to.
+ </summary>
+ <value>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> that this logger belongs to.
+ </value>
+ <remarks>
+ <para>
+ Gets the <see cref="T:log4net.Repository.ILoggerRepository"/> where this
+ <c>Logger</c> instance is attached to.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.DefaultLoggerFactory.LoggerImpl.#ctor(System.String)">
+ <summary>
+ Construct a new Logger
+ </summary>
+ <param name="name">the name of the logger</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Repository.Hierarchy.DefaultLoggerFactory.LoggerImpl"/> class
+ with the specified name.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Repository.Hierarchy.LoggerCreationEventHandler">
+ <summary>
+ Delegate used to handle logger creation event notifications.
+ </summary>
+ <param name="sender">The <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/> in which the <see cref="T:log4net.Repository.Hierarchy.Logger"/> has been created.</param>
+ <param name="e">The <see cref="T:log4net.Repository.Hierarchy.LoggerCreationEventArgs"/> event args that hold the <see cref="T:log4net.Repository.Hierarchy.Logger"/> instance that has been created.</param>
+ <remarks>
+ <para>
+ Delegate used to handle logger creation event notifications.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Repository.Hierarchy.LoggerCreationEventArgs">
+ <summary>
+ Provides data for the <see cref="E:log4net.Repository.Hierarchy.Hierarchy.LoggerCreatedEvent"/> event.
+ </summary>
+ <remarks>
+ <para>
+ A <see cref="E:log4net.Repository.Hierarchy.Hierarchy.LoggerCreatedEvent"/> event is raised every time a
+ <see cref="P:log4net.Repository.Hierarchy.LoggerCreationEventArgs.Logger"/> is created.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Repository.Hierarchy.LoggerCreationEventArgs.m_log">
+ <summary>
+ The <see cref="P:log4net.Repository.Hierarchy.LoggerCreationEventArgs.Logger"/> created
+ </summary>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.LoggerCreationEventArgs.#ctor(log4net.Repository.Hierarchy.Logger)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="log">The <see cref="P:log4net.Repository.Hierarchy.LoggerCreationEventArgs.Logger"/> that has been created.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Repository.Hierarchy.LoggerCreationEventArgs"/> event argument
+ class,with the specified <see cref="P:log4net.Repository.Hierarchy.LoggerCreationEventArgs.Logger"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.Hierarchy.LoggerCreationEventArgs.Logger">
+ <summary>
+ Gets the <see cref="P:log4net.Repository.Hierarchy.LoggerCreationEventArgs.Logger"/> that has been created.
+ </summary>
+ <value>
+ The <see cref="P:log4net.Repository.Hierarchy.LoggerCreationEventArgs.Logger"/> that has been created.
+ </value>
+ <remarks>
+ <para>
+ The <see cref="P:log4net.Repository.Hierarchy.LoggerCreationEventArgs.Logger"/> that has been created.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Repository.Hierarchy.Hierarchy">
+ <summary>
+ Hierarchical organization of loggers
+ </summary>
+ <remarks>
+ <para>
+ <i>The casual user should not have to deal with this class
+ directly.</i>
+ </para>
+ <para>
+ This class is specialized in retrieving loggers by name and
+ also maintaining the logger hierarchy. Implements the
+ <see cref="T:log4net.Repository.ILoggerRepository"/> interface.
+ </para>
+ <para>
+ The structure of the logger hierarchy is maintained by the
+ <see cref="M:log4net.Repository.Hierarchy.Hierarchy.GetLogger(System.String)"/> method. The hierarchy is such that children
+ link to their parent but parents do not have any references to their
+ children. Moreover, loggers can be instantiated in any order, in
+ particular descendant before ancestor.
+ </para>
+ <para>
+ In case a descendant is created before a particular ancestor,
+ then it creates a provision node for the ancestor and adds itself
+ to the provision node. Other descendants of the same ancestor add
+ themselves to the previously created provision node.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.Repository.LoggerRepositorySkeleton">
+ <summary>
+ Base implementation of <see cref="T:log4net.Repository.ILoggerRepository"/>
+ </summary>
+ <remarks>
+ <para>
+ Default abstract implementation of the <see cref="T:log4net.Repository.ILoggerRepository"/> interface.
+ </para>
+ <para>
+ Skeleton implementation of the <see cref="T:log4net.Repository.ILoggerRepository"/> interface.
+ All <see cref="T:log4net.Repository.ILoggerRepository"/> types can extend this type.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.Repository.ILoggerRepository">
+ <summary>
+ Interface implemented by logger repositories.
+ </summary>
+ <remarks>
+ <para>
+ This interface is implemented by logger repositories. e.g.
+ <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/>.
+ </para>
+ <para>
+ This interface is used by the <see cref="T:log4net.LogManager"/>
+ to obtain <see cref="T:log4net.ILog"/> interfaces.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Repository.ILoggerRepository.Exists(System.String)">
+ <summary>
+ Check if the named logger exists in the repository. If so return
+ its reference, otherwise returns <c>null</c>.
+ </summary>
+ <param name="name">The name of the logger to lookup</param>
+ <returns>The Logger object with the name specified</returns>
+ <remarks>
+ <para>
+ If the names logger exists it is returned, otherwise
+ <c>null</c> is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.ILoggerRepository.GetCurrentLoggers">
+ <summary>
+ Returns all the currently defined loggers as an Array.
+ </summary>
+ <returns>All the defined loggers</returns>
+ <remarks>
+ <para>
+ Returns all the currently defined loggers as an Array.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.ILoggerRepository.GetLogger(System.String)">
+ <summary>
+ Returns a named logger instance
+ </summary>
+ <param name="name">The name of the logger to retrieve</param>
+ <returns>The logger object with the name specified</returns>
+ <remarks>
+ <para>
+ Returns a named logger instance.
+ </para>
+ <para>
+ If a logger of that name already exists, then it will be
+ returned. Otherwise, a new logger will be instantiated and
+ then linked with its existing ancestors as well as children.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.ILoggerRepository.Shutdown">
+ <summary>Shutdown the repository</summary>
+ <remarks>
+ <para>
+ Shutting down a repository will <i>safely</i> close and remove
+ all appenders in all loggers including the root logger.
+ </para>
+ <para>
+ Some appenders need to be closed before the
+ application exists. Otherwise, pending logging events might be
+ lost.
+ </para>
+ <para>
+ The <see cref="M:log4net.Repository.ILoggerRepository.Shutdown"/> method is careful to close nested
+ appenders before closing regular appenders. This is allows
+ configurations where a regular appender is attached to a logger
+ and again to a nested appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.ILoggerRepository.ResetConfiguration">
+ <summary>
+ Reset the repositories configuration to a default state
+ </summary>
+ <remarks>
+ <para>
+ Reset all values contained in this instance to their
+ default state.
+ </para>
+ <para>
+ Existing loggers are not removed. They are just reset.
+ </para>
+ <para>
+ This method should be used sparingly and with care as it will
+ block all logging until it is completed.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.ILoggerRepository.Log(log4net.Core.LoggingEvent)">
+ <summary>
+ Log the <see cref="T:log4net.Core.LoggingEvent"/> through this repository.
+ </summary>
+ <param name="logEvent">the event to log</param>
+ <remarks>
+ <para>
+ This method should not normally be used to log.
+ The <see cref="T:log4net.ILog"/> interface should be used
+ for routine logging. This interface can be obtained
+ using the <see cref="M:log4net.LogManager.GetLogger(System.String)"/> method.
+ </para>
+ <para>
+ The <c>logEvent</c> is delivered to the appropriate logger and
+ that logger is then responsible for logging the event.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.ILoggerRepository.GetAppenders">
+ <summary>
+ Returns all the Appenders that are configured as an Array.
+ </summary>
+ <returns>All the Appenders</returns>
+ <remarks>
+ <para>
+ Returns all the Appenders that are configured as an Array.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.ILoggerRepository.Name">
+ <summary>
+ The name of the repository
+ </summary>
+ <value>
+ The name of the repository
+ </value>
+ <remarks>
+ <para>
+ The name of the repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.ILoggerRepository.RendererMap">
+ <summary>
+ RendererMap accesses the object renderer map for this repository.
+ </summary>
+ <value>
+ RendererMap accesses the object renderer map for this repository.
+ </value>
+ <remarks>
+ <para>
+ RendererMap accesses the object renderer map for this repository.
+ </para>
+ <para>
+ The RendererMap holds a mapping between types and
+ <see cref="T:log4net.ObjectRenderer.IObjectRenderer"/> objects.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.ILoggerRepository.PluginMap">
+ <summary>
+ The plugin map for this repository.
+ </summary>
+ <value>
+ The plugin map for this repository.
+ </value>
+ <remarks>
+ <para>
+ The plugin map holds the <see cref="T:log4net.Plugin.IPlugin"/> instances
+ that have been attached to this repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.ILoggerRepository.LevelMap">
+ <summary>
+ Get the level map for the Repository.
+ </summary>
+ <remarks>
+ <para>
+ Get the level map for the Repository.
+ </para>
+ <para>
+ The level map defines the mappings between
+ level names and <see cref="T:log4net.Core.Level"/> objects in
+ this repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.ILoggerRepository.Threshold">
+ <summary>
+ The threshold for all events in this repository
+ </summary>
+ <value>
+ The threshold for all events in this repository
+ </value>
+ <remarks>
+ <para>
+ The threshold for all events in this repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.ILoggerRepository.Configured">
+ <summary>
+ Flag indicates if this repository has been configured.
+ </summary>
+ <value>
+ Flag indicates if this repository has been configured.
+ </value>
+ <remarks>
+ <para>
+ Flag indicates if this repository has been configured.
+ </para>
+ </remarks>
+ </member>
+ <member name="E:log4net.Repository.ILoggerRepository.ShutdownEvent">
+ <summary>
+ Event to notify that the repository has been shutdown.
+ </summary>
+ <value>
+ Event to notify that the repository has been shutdown.
+ </value>
+ <remarks>
+ <para>
+ Event raised when the repository has been shutdown.
+ </para>
+ </remarks>
+ </member>
+ <member name="E:log4net.Repository.ILoggerRepository.ConfigurationReset">
+ <summary>
+ Event to notify that the repository has had its configuration reset.
+ </summary>
+ <value>
+ Event to notify that the repository has had its configuration reset.
+ </value>
+ <remarks>
+ <para>
+ Event raised when the repository's configuration has been
+ reset to default.
+ </para>
+ </remarks>
+ </member>
+ <member name="E:log4net.Repository.ILoggerRepository.ConfigurationChanged">
+ <summary>
+ Event to notify that the repository has had its configuration changed.
+ </summary>
+ <value>
+ Event to notify that the repository has had its configuration changed.
+ </value>
+ <remarks>
+ <para>
+ Event raised when the repository's configuration has been changed.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.ILoggerRepository.Properties">
+ <summary>
+ Repository specific properties
+ </summary>
+ <value>
+ Repository specific properties
+ </value>
+ <remarks>
+ <para>
+ These properties can be specified on a repository specific basis.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.LoggerRepositorySkeleton.#ctor">
+ <summary>
+ Default Constructor
+ </summary>
+ <remarks>
+ <para>
+ Initializes the repository with default (empty) properties.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.LoggerRepositorySkeleton.#ctor(log4net.Util.PropertiesDictionary)">
+ <summary>
+ Construct the repository using specific properties
+ </summary>
+ <param name="properties">the properties to set for this repository</param>
+ <remarks>
+ <para>
+ Initializes the repository with specified properties.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.LoggerRepositorySkeleton.Exists(System.String)">
+ <summary>
+ Test if logger exists
+ </summary>
+ <param name="name">The name of the logger to lookup</param>
+ <returns>The Logger object with the name specified</returns>
+ <remarks>
+ <para>
+ Check if the named logger exists in the repository. If so return
+ its reference, otherwise returns <c>null</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.LoggerRepositorySkeleton.GetCurrentLoggers">
+ <summary>
+ Returns all the currently defined loggers in the repository
+ </summary>
+ <returns>All the defined loggers</returns>
+ <remarks>
+ <para>
+ Returns all the currently defined loggers in the repository as an Array.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.LoggerRepositorySkeleton.GetLogger(System.String)">
+ <summary>
+ Return a new logger instance
+ </summary>
+ <param name="name">The name of the logger to retrieve</param>
+ <returns>The logger object with the name specified</returns>
+ <remarks>
+ <para>
+ Return a new logger instance.
+ </para>
+ <para>
+ If a logger of that name already exists, then it will be
+ returned. Otherwise, a new logger will be instantiated and
+ then linked with its existing ancestors as well as children.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.LoggerRepositorySkeleton.Shutdown">
+ <summary>
+ Shutdown the repository
+ </summary>
+ <remarks>
+ <para>
+ Shutdown the repository. Can be overridden in a subclass.
+ This base class implementation notifies the <see cref="E:log4net.Repository.LoggerRepositorySkeleton.ShutdownEvent"/>
+ listeners and all attached plugins of the shutdown event.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.LoggerRepositorySkeleton.ResetConfiguration">
+ <summary>
+ Reset the repositories configuration to a default state
+ </summary>
+ <remarks>
+ <para>
+ Reset all values contained in this instance to their
+ default state.
+ </para>
+ <para>
+ Existing loggers are not removed. They are just reset.
+ </para>
+ <para>
+ This method should be used sparingly and with care as it will
+ block all logging until it is completed.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.LoggerRepositorySkeleton.Log(log4net.Core.LoggingEvent)">
+ <summary>
+ Log the logEvent through this repository.
+ </summary>
+ <param name="logEvent">the event to log</param>
+ <remarks>
+ <para>
+ This method should not normally be used to log.
+ The <see cref="T:log4net.ILog"/> interface should be used
+ for routine logging. This interface can be obtained
+ using the <see cref="M:log4net.LogManager.GetLogger(System.String)"/> method.
+ </para>
+ <para>
+ The <c>logEvent</c> is delivered to the appropriate logger and
+ that logger is then responsible for logging the event.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.LoggerRepositorySkeleton.GetAppenders">
+ <summary>
+ Returns all the Appenders that are configured as an Array.
+ </summary>
+ <returns>All the Appenders</returns>
+ <remarks>
+ <para>
+ Returns all the Appenders that are configured as an Array.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.LoggerRepositorySkeleton.AddRenderer(System.Type,log4net.ObjectRenderer.IObjectRenderer)">
+ <summary>
+ Adds an object renderer for a specific class.
+ </summary>
+ <param name="typeToRender">The type that will be rendered by the renderer supplied.</param>
+ <param name="rendererInstance">The object renderer used to render the object.</param>
+ <remarks>
+ <para>
+ Adds an object renderer for a specific class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.LoggerRepositorySkeleton.OnShutdown(System.EventArgs)">
+ <summary>
+ Notify the registered listeners that the repository is shutting down
+ </summary>
+ <param name="e">Empty EventArgs</param>
+ <remarks>
+ <para>
+ Notify any listeners that this repository is shutting down.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.LoggerRepositorySkeleton.OnConfigurationReset(System.EventArgs)">
+ <summary>
+ Notify the registered listeners that the repository has had its configuration reset
+ </summary>
+ <param name="e">Empty EventArgs</param>
+ <remarks>
+ <para>
+ Notify any listeners that this repository's configuration has been reset.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.LoggerRepositorySkeleton.OnConfigurationChanged(System.EventArgs)">
+ <summary>
+ Notify the registered listeners that the repository has had its configuration changed
+ </summary>
+ <param name="e">Empty EventArgs</param>
+ <remarks>
+ <para>
+ Notify any listeners that this repository's configuration has changed.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.LoggerRepositorySkeleton.RaiseConfigurationChanged(System.EventArgs)">
+ <summary>
+ Raise a configuration changed event on this repository
+ </summary>
+ <param name="e">EventArgs.Empty</param>
+ <remarks>
+ <para>
+ Applications that programmatically change the configuration of the repository should
+ raise this event notification to notify listeners.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.LoggerRepositorySkeleton.Name">
+ <summary>
+ The name of the repository
+ </summary>
+ <value>
+ The string name of the repository
+ </value>
+ <remarks>
+ <para>
+ The name of this repository. The name is
+ used to store and lookup the repositories
+ stored by the <see cref="T:log4net.Core.IRepositorySelector"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.LoggerRepositorySkeleton.Threshold">
+ <summary>
+ The threshold for all events in this repository
+ </summary>
+ <value>
+ The threshold for all events in this repository
+ </value>
+ <remarks>
+ <para>
+ The threshold for all events in this repository
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.LoggerRepositorySkeleton.RendererMap">
+ <summary>
+ RendererMap accesses the object renderer map for this repository.
+ </summary>
+ <value>
+ RendererMap accesses the object renderer map for this repository.
+ </value>
+ <remarks>
+ <para>
+ RendererMap accesses the object renderer map for this repository.
+ </para>
+ <para>
+ The RendererMap holds a mapping between types and
+ <see cref="T:log4net.ObjectRenderer.IObjectRenderer"/> objects.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.LoggerRepositorySkeleton.PluginMap">
+ <summary>
+ The plugin map for this repository.
+ </summary>
+ <value>
+ The plugin map for this repository.
+ </value>
+ <remarks>
+ <para>
+ The plugin map holds the <see cref="T:log4net.Plugin.IPlugin"/> instances
+ that have been attached to this repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.LoggerRepositorySkeleton.LevelMap">
+ <summary>
+ Get the level map for the Repository.
+ </summary>
+ <remarks>
+ <para>
+ Get the level map for the Repository.
+ </para>
+ <para>
+ The level map defines the mappings between
+ level names and <see cref="T:log4net.Core.Level"/> objects in
+ this repository.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.LoggerRepositorySkeleton.Configured">
+ <summary>
+ Flag indicates if this repository has been configured.
+ </summary>
+ <value>
+ Flag indicates if this repository has been configured.
+ </value>
+ <remarks>
+ <para>
+ Flag indicates if this repository has been configured.
+ </para>
+ </remarks>
+ </member>
+ <member name="E:log4net.Repository.LoggerRepositorySkeleton.ShutdownEvent">
+ <summary>
+ Event to notify that the repository has been shutdown.
+ </summary>
+ <value>
+ Event to notify that the repository has been shutdown.
+ </value>
+ <remarks>
+ <para>
+ Event raised when the repository has been shutdown.
+ </para>
+ </remarks>
+ </member>
+ <member name="E:log4net.Repository.LoggerRepositorySkeleton.ConfigurationReset">
+ <summary>
+ Event to notify that the repository has had its configuration reset.
+ </summary>
+ <value>
+ Event to notify that the repository has had its configuration reset.
+ </value>
+ <remarks>
+ <para>
+ Event raised when the repository's configuration has been
+ reset to default.
+ </para>
+ </remarks>
+ </member>
+ <member name="E:log4net.Repository.LoggerRepositorySkeleton.ConfigurationChanged">
+ <summary>
+ Event to notify that the repository has had its configuration changed.
+ </summary>
+ <value>
+ Event to notify that the repository has had its configuration changed.
+ </value>
+ <remarks>
+ <para>
+ Event raised when the repository's configuration has been changed.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.LoggerRepositorySkeleton.Properties">
+ <summary>
+ Repository specific properties
+ </summary>
+ <value>
+ Repository specific properties
+ </value>
+ <remarks>
+ These properties can be specified on a repository specific basis
+ </remarks>
+ </member>
+ <member name="T:log4net.Repository.IBasicRepositoryConfigurator">
+ <summary>
+ Basic Configurator interface for repositories
+ </summary>
+ <remarks>
+ <para>
+ Interface used by basic configurator to configure a <see cref="T:log4net.Repository.ILoggerRepository"/>
+ with a default <see cref="T:log4net.Appender.IAppender"/>.
+ </para>
+ <para>
+ A <see cref="T:log4net.Repository.ILoggerRepository"/> should implement this interface to support
+ configuration by the <see cref="T:log4net.Config.BasicConfigurator"/>.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Repository.IBasicRepositoryConfigurator.Configure(log4net.Appender.IAppender)">
+ <summary>
+ Initialize the repository using the specified appender
+ </summary>
+ <param name="appender">the appender to use to log all logging events</param>
+ <remarks>
+ <para>
+ Configure the repository to route all logging events to the
+ specified appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Repository.IXmlRepositoryConfigurator">
+ <summary>
+ Configure repository using XML
+ </summary>
+ <remarks>
+ <para>
+ Interface used by Xml configurator to configure a <see cref="T:log4net.Repository.ILoggerRepository"/>.
+ </para>
+ <para>
+ A <see cref="T:log4net.Repository.ILoggerRepository"/> should implement this interface to support
+ configuration by the <see cref="T:log4net.Config.XmlConfigurator"/>.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Repository.IXmlRepositoryConfigurator.Configure(System.Xml.XmlElement)">
+ <summary>
+ Initialize the repository using the specified config
+ </summary>
+ <param name="element">the element containing the root of the config</param>
+ <remarks>
+ <para>
+ The schema for the XML configuration data is defined by
+ the implementation.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.#ctor(log4net.Util.PropertiesDictionary)">
+ <summary>
+ Construct with properties
+ </summary>
+ <param name="properties">The properties to pass to this repository.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.#ctor(log4net.Repository.Hierarchy.ILoggerFactory)">
+ <summary>
+ Construct with a logger factory
+ </summary>
+ <param name="loggerFactory">The factory to use to create new logger instances.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/> class with
+ the specified <see cref="T:log4net.Repository.Hierarchy.ILoggerFactory"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.#ctor(log4net.Util.PropertiesDictionary,log4net.Repository.Hierarchy.ILoggerFactory)">
+ <summary>
+ Construct with properties and a logger factory
+ </summary>
+ <param name="properties">The properties to pass to this repository.</param>
+ <param name="loggerFactory">The factory to use to create new logger instances.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/> class with
+ the specified <see cref="T:log4net.Repository.Hierarchy.ILoggerFactory"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.Exists(System.String)">
+ <summary>
+ Test if a logger exists
+ </summary>
+ <param name="name">The name of the logger to lookup</param>
+ <returns>The Logger object with the name specified</returns>
+ <remarks>
+ <para>
+ Check if the named logger exists in the hierarchy. If so return
+ its reference, otherwise returns <c>null</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.GetCurrentLoggers">
+ <summary>
+ Returns all the currently defined loggers in the hierarchy as an Array
+ </summary>
+ <returns>All the defined loggers</returns>
+ <remarks>
+ <para>
+ Returns all the currently defined loggers in the hierarchy as an Array.
+ The root logger is <b>not</b> included in the returned
+ enumeration.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.GetLogger(System.String)">
+ <summary>
+ Return a new logger instance named as the first parameter using
+ the default factory.
+ </summary>
+ <remarks>
+ <para>
+ Return a new logger instance named as the first parameter using
+ the default factory.
+ </para>
+ <para>
+ If a logger of that name already exists, then it will be
+ returned. Otherwise, a new logger will be instantiated and
+ then linked with its existing ancestors as well as children.
+ </para>
+ </remarks>
+ <param name="name">The name of the logger to retrieve</param>
+ <returns>The logger object with the name specified</returns>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.Shutdown">
+ <summary>
+ Shutting down a hierarchy will <i>safely</i> close and remove
+ all appenders in all loggers including the root logger.
+ </summary>
+ <remarks>
+ <para>
+ Shutting down a hierarchy will <i>safely</i> close and remove
+ all appenders in all loggers including the root logger.
+ </para>
+ <para>
+ Some appenders need to be closed before the
+ application exists. Otherwise, pending logging events might be
+ lost.
+ </para>
+ <para>
+ The <c>Shutdown</c> method is careful to close nested
+ appenders before closing regular appenders. This is allows
+ configurations where a regular appender is attached to a logger
+ and again to a nested appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.ResetConfiguration">
+ <summary>
+ Reset all values contained in this hierarchy instance to their default.
+ </summary>
+ <remarks>
+ <para>
+ Reset all values contained in this hierarchy instance to their
+ default. This removes all appenders from all loggers, sets
+ the level of all non-root loggers to <c>null</c>,
+ sets their additivity flag to <c>true</c> and sets the level
+ of the root logger to <see cref="F:log4net.Core.Level.Debug"/>. Moreover,
+ message disabling is set its default "off" value.
+ </para>
+ <para>
+ Existing loggers are not removed. They are just reset.
+ </para>
+ <para>
+ This method should be used sparingly and with care as it will
+ block all logging until it is completed.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.Log(log4net.Core.LoggingEvent)">
+ <summary>
+ Log the logEvent through this hierarchy.
+ </summary>
+ <param name="logEvent">the event to log</param>
+ <remarks>
+ <para>
+ This method should not normally be used to log.
+ The <see cref="T:log4net.ILog"/> interface should be used
+ for routine logging. This interface can be obtained
+ using the <see cref="M:log4net.LogManager.GetLogger(System.String)"/> method.
+ </para>
+ <para>
+ The <c>logEvent</c> is delivered to the appropriate logger and
+ that logger is then responsible for logging the event.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.GetAppenders">
+ <summary>
+ Returns all the Appenders that are currently configured
+ </summary>
+ <returns>An array containing all the currently configured appenders</returns>
+ <remarks>
+ <para>
+ Returns all the <see cref="T:log4net.Appender.IAppender"/> instances that are currently configured.
+ All the loggers are searched for appenders. The appenders may also be containers
+ for appenders and these are also searched for additional loggers.
+ </para>
+ <para>
+ The list returned is unordered but does not contain duplicates.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.CollectAppender(System.Collections.ArrayList,log4net.Appender.IAppender)">
+ <summary>
+ Collect the appenders from an <see cref="T:log4net.Core.IAppenderAttachable"/>.
+ The appender may also be a container.
+ </summary>
+ <param name="appenderList"></param>
+ <param name="appender"></param>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.CollectAppenders(System.Collections.ArrayList,log4net.Core.IAppenderAttachable)">
+ <summary>
+ Collect the appenders from an <see cref="T:log4net.Core.IAppenderAttachable"/> container
+ </summary>
+ <param name="appenderList"></param>
+ <param name="container"></param>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.log4net#Repository#IBasicRepositoryConfigurator#Configure(log4net.Appender.IAppender)">
+ <summary>
+ Initialize the log4net system using the specified appender
+ </summary>
+ <param name="appender">the appender to use to log all logging events</param>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.BasicRepositoryConfigure(log4net.Appender.IAppender)">
+ <summary>
+ Initialize the log4net system using the specified appender
+ </summary>
+ <param name="appender">the appender to use to log all logging events</param>
+ <remarks>
+ <para>
+ This method provides the same functionality as the
+ <see cref="M:log4net.Repository.IBasicRepositoryConfigurator.Configure(log4net.Appender.IAppender)"/> method implemented
+ on this object, but it is protected and therefore can be called by subclasses.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.log4net#Repository#IXmlRepositoryConfigurator#Configure(System.Xml.XmlElement)">
+ <summary>
+ Initialize the log4net system using the specified config
+ </summary>
+ <param name="element">the element containing the root of the config</param>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.XmlRepositoryConfigure(System.Xml.XmlElement)">
+ <summary>
+ Initialize the log4net system using the specified config
+ </summary>
+ <param name="element">the element containing the root of the config</param>
+ <remarks>
+ <para>
+ This method provides the same functionality as the
+ <see cref="M:log4net.Repository.IBasicRepositoryConfigurator.Configure(log4net.Appender.IAppender)"/> method implemented
+ on this object, but it is protected and therefore can be called by subclasses.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.IsDisabled(log4net.Core.Level)">
+ <summary>
+ Test if this hierarchy is disabled for the specified <see cref="T:log4net.Core.Level"/>.
+ </summary>
+ <param name="level">The level to check against.</param>
+ <returns>
+ <c>true</c> if the repository is disabled for the level argument, <c>false</c> otherwise.
+ </returns>
+ <remarks>
+ <para>
+ If this hierarchy has not been configured then this method will
+ always return <c>true</c>.
+ </para>
+ <para>
+ This method will return <c>true</c> if this repository is
+ disabled for <c>level</c> object passed as parameter and
+ <c>false</c> otherwise.
+ </para>
+ <para>
+ See also the <see cref="P:log4net.Repository.ILoggerRepository.Threshold"/> property.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.Clear">
+ <summary>
+ Clear all logger definitions from the internal hashtable
+ </summary>
+ <remarks>
+ <para>
+ This call will clear all logger definitions from the internal
+ hashtable. Invoking this method will irrevocably mess up the
+ logger hierarchy.
+ </para>
+ <para>
+ You should <b>really</b> know what you are doing before
+ invoking this method.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.GetLogger(System.String,log4net.Repository.Hierarchy.ILoggerFactory)">
+ <summary>
+ Return a new logger instance named as the first parameter using
+ <paramref name="factory"/>.
+ </summary>
+ <param name="name">The name of the logger to retrieve</param>
+ <param name="factory">The factory that will make the new logger instance</param>
+ <returns>The logger object with the name specified</returns>
+ <remarks>
+ <para>
+ If a logger of that name already exists, then it will be
+ returned. Otherwise, a new logger will be instantiated by the
+ <paramref name="factory"/> parameter and linked with its existing
+ ancestors as well as children.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.OnLoggerCreationEvent(log4net.Repository.Hierarchy.Logger)">
+ <summary>
+ Sends a logger creation event to all registered listeners
+ </summary>
+ <param name="logger">The newly created logger</param>
+ <remarks>
+ Raises the logger creation event.
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.UpdateParents(log4net.Repository.Hierarchy.Logger)">
+ <summary>
+ Updates all the parents of the specified logger
+ </summary>
+ <param name="log">The logger to update the parents for</param>
+ <remarks>
+ <para>
+ This method loops through all the <i>potential</i> parents of
+ <paramref name="log"/>. There 3 possible cases:
+ </para>
+ <list type="number">
+ <item>
+ <term>No entry for the potential parent of <paramref name="log"/> exists</term>
+ <description>
+ We create a ProvisionNode for this potential
+ parent and insert <paramref name="log"/> in that provision node.
+ </description>
+ </item>
+ <item>
+ <term>The entry is of type Logger for the potential parent.</term>
+ <description>
+ The entry is <paramref name="log"/>'s nearest existing parent. We
+ update <paramref name="log"/>'s parent field with this entry. We also break from
+ he loop because updating our parent's parent is our parent's
+ responsibility.
+ </description>
+ </item>
+ <item>
+ <term>The entry is of type ProvisionNode for this potential parent.</term>
+ <description>
+ We add <paramref name="log"/> to the list of children for this
+ potential parent.
+ </description>
+ </item>
+ </list>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.UpdateChildren(log4net.Repository.Hierarchy.ProvisionNode,log4net.Repository.Hierarchy.Logger)">
+ <summary>
+ Replace a <see cref="T:log4net.Repository.Hierarchy.ProvisionNode"/> with a <see cref="T:log4net.Repository.Hierarchy.Logger"/> in the hierarchy.
+ </summary>
+ <param name="pn"></param>
+ <param name="log"></param>
+ <remarks>
+ <para>
+ We update the links for all the children that placed themselves
+ in the provision node 'pn'. The second argument 'log' is a
+ reference for the newly created Logger, parent of all the
+ children in 'pn'.
+ </para>
+ <para>
+ We loop on all the children 'c' in 'pn'.
+ </para>
+ <para>
+ If the child 'c' has been already linked to a child of
+ 'log' then there is no need to update 'c'.
+ </para>
+ <para>
+ Otherwise, we set log's parent field to c's parent and set
+ c's parent field to log.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.AddLevel(log4net.Repository.Hierarchy.Hierarchy.LevelEntry)">
+ <summary>
+ Define or redefine a Level using the values in the <see cref="T:log4net.Repository.Hierarchy.Hierarchy.LevelEntry"/> argument
+ </summary>
+ <param name="levelEntry">the level values</param>
+ <remarks>
+ <para>
+ Define or redefine a Level using the values in the <see cref="T:log4net.Repository.Hierarchy.Hierarchy.LevelEntry"/> argument
+ </para>
+ <para>
+ Supports setting levels via the configuration file.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.AddProperty(log4net.Repository.Hierarchy.Hierarchy.PropertyEntry)">
+ <summary>
+ Set a Property using the values in the <see cref="T:log4net.Repository.Hierarchy.Hierarchy.LevelEntry"/> argument
+ </summary>
+ <param name="propertyEntry">the property value</param>
+ <remarks>
+ <para>
+ Set a Property using the values in the <see cref="T:log4net.Repository.Hierarchy.Hierarchy.LevelEntry"/> argument.
+ </para>
+ <para>
+ Supports setting property values via the configuration file.
+ </para>
+ </remarks>
+ </member>
+ <member name="E:log4net.Repository.Hierarchy.Hierarchy.LoggerCreatedEvent">
+ <summary>
+ Event used to notify that a logger has been created.
+ </summary>
+ <remarks>
+ <para>
+ Event raised when a logger is created.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.Hierarchy.Hierarchy.EmittedNoAppenderWarning">
+ <summary>
+ Has no appender warning been emitted
+ </summary>
+ <remarks>
+ <para>
+ Flag to indicate if we have already issued a warning
+ about not having an appender warning.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.Hierarchy.Hierarchy.Root">
+ <summary>
+ Get the root of this hierarchy
+ </summary>
+ <remarks>
+ <para>
+ Get the root of this hierarchy.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.Hierarchy.Hierarchy.LoggerFactory">
+ <summary>
+ Gets or sets the default <see cref="T:log4net.Repository.Hierarchy.ILoggerFactory"/> instance.
+ </summary>
+ <value>The default <see cref="T:log4net.Repository.Hierarchy.ILoggerFactory"/></value>
+ <remarks>
+ <para>
+ The logger factory is used to create logger instances.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Repository.Hierarchy.Hierarchy.LevelEntry">
+ <summary>
+ A class to hold the value, name and display name for a level
+ </summary>
+ <remarks>
+ <para>
+ A class to hold the value, name and display name for a level
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.LevelEntry.ToString">
+ <summary>
+ Override <c>Object.ToString</c> to return sensible debug info
+ </summary>
+ <returns>string info about this object</returns>
+ </member>
+ <member name="P:log4net.Repository.Hierarchy.Hierarchy.LevelEntry.Value">
+ <summary>
+ Value of the level
+ </summary>
+ <remarks>
+ <para>
+ If the value is not set (defaults to -1) the value will be looked
+ up for the current level with the same name.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.Hierarchy.Hierarchy.LevelEntry.Name">
+ <summary>
+ Name of the level
+ </summary>
+ <value>
+ The name of the level
+ </value>
+ <remarks>
+ <para>
+ The name of the level.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.Hierarchy.Hierarchy.LevelEntry.DisplayName">
+ <summary>
+ Display name for the level
+ </summary>
+ <value>
+ The display name of the level
+ </value>
+ <remarks>
+ <para>
+ The display name of the level.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Repository.Hierarchy.Hierarchy.PropertyEntry">
+ <summary>
+ A class to hold the key and data for a property set in the config file
+ </summary>
+ <remarks>
+ <para>
+ A class to hold the key and data for a property set in the config file
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.Hierarchy.PropertyEntry.ToString">
+ <summary>
+ Override <c>Object.ToString</c> to return sensible debug info
+ </summary>
+ <returns>string info about this object</returns>
+ </member>
+ <member name="P:log4net.Repository.Hierarchy.Hierarchy.PropertyEntry.Key">
+ <summary>
+ Property Key
+ </summary>
+ <value>
+ Property Key
+ </value>
+ <remarks>
+ <para>
+ Property Key.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.Hierarchy.Hierarchy.PropertyEntry.Value">
+ <summary>
+ Property Value
+ </summary>
+ <value>
+ Property Value
+ </value>
+ <remarks>
+ <para>
+ Property Value.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Repository.Hierarchy.LoggerKey">
+ <summary>
+ Used internally to accelerate hash table searches.
+ </summary>
+ <remarks>
+ <para>
+ Internal class used to improve performance of
+ string keyed hashtables.
+ </para>
+ <para>
+ The hashcode of the string is cached for reuse.
+ The string is stored as an interned value.
+ When comparing two <see cref="T:log4net.Repository.Hierarchy.LoggerKey"/> objects for equality
+ the reference equality of the interned strings is compared.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.LoggerKey.#ctor(System.String)">
+ <summary>
+ Construct key with string name
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Repository.Hierarchy.LoggerKey"/> class
+ with the specified name.
+ </para>
+ <para>
+ Stores the hashcode of the string and interns
+ the string key to optimize comparisons.
+ </para>
+ <note>
+ The Compact Framework 1.0 the <see cref="M:System.String.Intern(System.String)"/>
+ method does not work. On the Compact Framework
+ the string keys are not interned nor are they
+ compared by reference.
+ </note>
+ </remarks>
+ <param name="name">The name of the logger.</param>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.LoggerKey.GetHashCode">
+ <summary>
+ Returns a hash code for the current instance.
+ </summary>
+ <returns>A hash code for the current instance.</returns>
+ <remarks>
+ <para>
+ Returns the cached hashcode.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.LoggerKey.Equals(System.Object)">
+ <summary>
+ Determines whether two <see cref="T:log4net.Repository.Hierarchy.LoggerKey"/> instances
+ are equal.
+ </summary>
+ <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:log4net.Repository.Hierarchy.LoggerKey"/>.</param>
+ <returns>
+ <c>true</c> if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:log4net.Repository.Hierarchy.LoggerKey"/>; otherwise, <c>false</c>.
+ </returns>
+ <remarks>
+ <para>
+ Compares the references of the interned strings.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Repository.Hierarchy.ProvisionNode">
+ <summary>
+ Provision nodes are used where no logger instance has been specified
+ </summary>
+ <remarks>
+ <para>
+ <see cref="T:log4net.Repository.Hierarchy.ProvisionNode"/> instances are used in the
+ <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/> when there is no specified
+ <see cref="T:log4net.Repository.Hierarchy.Logger"/> for that node.
+ </para>
+ <para>
+ A provision node holds a list of child loggers on behalf of
+ a logger that does not exist.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.ProvisionNode.#ctor(log4net.Repository.Hierarchy.Logger)">
+ <summary>
+ Create a new provision node with child node
+ </summary>
+ <param name="log">A child logger to add to this node.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Repository.Hierarchy.ProvisionNode"/> class
+ with the specified child logger.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Repository.Hierarchy.RootLogger">
+ <summary>
+ The <see cref="T:log4net.Repository.Hierarchy.RootLogger"/> sits at the root of the logger hierarchy tree.
+ </summary>
+ <remarks>
+ <para>
+ The <see cref="T:log4net.Repository.Hierarchy.RootLogger"/> is a regular <see cref="T:log4net.Repository.Hierarchy.Logger"/> except
+ that it provides several guarantees.
+ </para>
+ <para>
+ First, it cannot be assigned a <c>null</c>
+ level. Second, since the root logger cannot have a parent, the
+ <see cref="P:log4net.Repository.Hierarchy.RootLogger.EffectiveLevel"/> property always returns the value of the
+ level field without walking the hierarchy.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.RootLogger.#ctor(log4net.Core.Level)">
+ <summary>
+ Construct a <see cref="T:log4net.Repository.Hierarchy.RootLogger"/>
+ </summary>
+ <param name="level">The level to assign to the root logger.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Repository.Hierarchy.RootLogger"/> class with
+ the specified logging level.
+ </para>
+ <para>
+ The root logger names itself as "root". However, the root
+ logger cannot be retrieved by name.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.Hierarchy.RootLogger.EffectiveLevel">
+ <summary>
+ Gets the assigned level value without walking the logger hierarchy.
+ </summary>
+ <value>The assigned level value without walking the logger hierarchy.</value>
+ <remarks>
+ <para>
+ Because the root logger cannot have a parent and its level
+ must not be <c>null</c> this property just returns the
+ value of <see cref="P:log4net.Repository.Hierarchy.Logger.Level"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Repository.Hierarchy.RootLogger.Level">
+ <summary>
+ Gets or sets the assigned <see cref="P:log4net.Repository.Hierarchy.RootLogger.Level"/> for the root logger.
+ </summary>
+ <value>
+ The <see cref="P:log4net.Repository.Hierarchy.RootLogger.Level"/> of the root logger.
+ </value>
+ <remarks>
+ <para>
+ Setting the level of the root logger to a <c>null</c> reference
+ may have catastrophic results. We prevent this here.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Repository.Hierarchy.XmlHierarchyConfigurator">
+ <summary>
+ Initializes the log4net environment using an XML DOM.
+ </summary>
+ <remarks>
+ <para>
+ Configures a <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/> using an XML DOM.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.XmlHierarchyConfigurator.#ctor(log4net.Repository.Hierarchy.Hierarchy)">
+ <summary>
+ Construct the configurator for a hierarchy
+ </summary>
+ <param name="hierarchy">The hierarchy to build.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Repository.Hierarchy.XmlHierarchyConfigurator"/> class
+ with the specified <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.XmlHierarchyConfigurator.Configure(System.Xml.XmlElement)">
+ <summary>
+ Configure the hierarchy by parsing a DOM tree of XML elements.
+ </summary>
+ <param name="element">The root element to parse.</param>
+ <remarks>
+ <para>
+ Configure the hierarchy by parsing a DOM tree of XML elements.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.XmlHierarchyConfigurator.FindAppenderByReference(System.Xml.XmlElement)">
+ <summary>
+ Parse appenders by IDREF.
+ </summary>
+ <param name="appenderRef">The appender ref element.</param>
+ <returns>The instance of the appender that the ref refers to.</returns>
+ <remarks>
+ <para>
+ Parse an XML element that represents an appender and return
+ the appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.XmlHierarchyConfigurator.ParseAppender(System.Xml.XmlElement)">
+ <summary>
+ Parses an appender element.
+ </summary>
+ <param name="appenderElement">The appender element.</param>
+ <returns>The appender instance or <c>null</c> when parsing failed.</returns>
+ <remarks>
+ <para>
+ Parse an XML element that represents an appender and return
+ the appender instance.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.XmlHierarchyConfigurator.ParseLogger(System.Xml.XmlElement)">
+ <summary>
+ Parses a logger element.
+ </summary>
+ <param name="loggerElement">The logger element.</param>
+ <remarks>
+ <para>
+ Parse an XML element that represents a logger.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.XmlHierarchyConfigurator.ParseRoot(System.Xml.XmlElement)">
+ <summary>
+ Parses the root logger element.
+ </summary>
+ <param name="rootElement">The root element.</param>
+ <remarks>
+ <para>
+ Parse an XML element that represents the root logger.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.XmlHierarchyConfigurator.ParseChildrenOfLoggerElement(System.Xml.XmlElement,log4net.Repository.Hierarchy.Logger,System.Boolean)">
+ <summary>
+ Parses the children of a logger element.
+ </summary>
+ <param name="catElement">The category element.</param>
+ <param name="log">The logger instance.</param>
+ <param name="isRoot">Flag to indicate if the logger is the root logger.</param>
+ <remarks>
+ <para>
+ Parse the child elements of a &lt;logger&gt; element.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.XmlHierarchyConfigurator.ParseRenderer(System.Xml.XmlElement)">
+ <summary>
+ Parses an object renderer.
+ </summary>
+ <param name="element">The renderer element.</param>
+ <remarks>
+ <para>
+ Parse an XML element that represents a renderer.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.XmlHierarchyConfigurator.ParseLevel(System.Xml.XmlElement,log4net.Repository.Hierarchy.Logger,System.Boolean)">
+ <summary>
+ Parses a level element.
+ </summary>
+ <param name="element">The level element.</param>
+ <param name="log">The logger object to set the level on.</param>
+ <param name="isRoot">Flag to indicate if the logger is the root logger.</param>
+ <remarks>
+ <para>
+ Parse an XML element that represents a level.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.XmlHierarchyConfigurator.SetParameter(System.Xml.XmlElement,System.Object)">
+ <summary>
+ Sets a parameter on an object.
+ </summary>
+ <param name="element">The parameter element.</param>
+ <param name="target">The object to set the parameter on.</param>
+ <remarks>
+ The parameter name must correspond to a writable property
+ on the object. The value of the parameter is a string,
+ therefore this function will attempt to set a string
+ property first. If unable to set a string property it
+ will inspect the property and its argument type. It will
+ attempt to call a static method called <c>Parse</c> on the
+ type of the property. This method will take a single
+ string argument and return a value that can be used to
+ set the property.
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.XmlHierarchyConfigurator.HasAttributesOrElements(System.Xml.XmlElement)">
+ <summary>
+ Test if an element has no attributes or child elements
+ </summary>
+ <param name="element">the element to inspect</param>
+ <returns><c>true</c> if the element has any attributes or child elements, <c>false</c> otherwise</returns>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.XmlHierarchyConfigurator.IsTypeConstructible(System.Type)">
+ <summary>
+ Test if a <see cref="T:System.Type"/> is constructible with <c>Activator.CreateInstance</c>.
+ </summary>
+ <param name="type">the type to inspect</param>
+ <returns><c>true</c> if the type is creatable using a default constructor, <c>false</c> otherwise</returns>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.XmlHierarchyConfigurator.FindMethodInfo(System.Type,System.String)">
+ <summary>
+ Look for a method on the <paramref name="targetType"/> that matches the <paramref name="name"/> supplied
+ </summary>
+ <param name="targetType">the type that has the method</param>
+ <param name="name">the name of the method</param>
+ <returns>the method info found</returns>
+ <remarks>
+ <para>
+ The method must be a public instance method on the <paramref name="targetType"/>.
+ The method must be named <paramref name="name"/> or "Add" followed by <paramref name="name"/>.
+ The method must take a single parameter.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.XmlHierarchyConfigurator.ConvertStringTo(System.Type,System.String)">
+ <summary>
+ Converts a string value to a target type.
+ </summary>
+ <param name="type">The type of object to convert the string to.</param>
+ <param name="value">The string value to use as the value of the object.</param>
+ <returns>
+ <para>
+ An object of type <paramref name="type"/> with value <paramref name="value"/> or
+ <c>null</c> when the conversion could not be performed.
+ </para>
+ </returns>
+ </member>
+ <member name="M:log4net.Repository.Hierarchy.XmlHierarchyConfigurator.CreateObjectFromXml(System.Xml.XmlElement,System.Type,System.Type)">
+ <summary>
+ Creates an object as specified in XML.
+ </summary>
+ <param name="element">The XML element that contains the definition of the object.</param>
+ <param name="defaultTargetType">The object type to use if not explicitly specified.</param>
+ <param name="typeConstraint">The type that the returned object must be or must inherit from.</param>
+ <returns>The object or <c>null</c></returns>
+ <remarks>
+ <para>
+ Parse an XML element and create an object instance based on the configuration
+ data.
+ </para>
+ <para>
+ The type of the instance may be specified in the XML. If not
+ specified then the <paramref name="defaultTargetType"/> is used
+ as the type. However the type is specified it must support the
+ <paramref name="typeConstraint"/> type.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Repository.Hierarchy.XmlHierarchyConfigurator.m_appenderBag">
+ <summary>
+ key: appenderName, value: appender.
+ </summary>
+ </member>
+ <member name="F:log4net.Repository.Hierarchy.XmlHierarchyConfigurator.m_hierarchy">
+ <summary>
+ The Hierarchy being configured.
+ </summary>
+ </member>
+ <member name="T:log4net.Repository.LoggerRepositoryShutdownEventHandler">
+ <summary>
+ Delegate used to handle logger repository shutdown event notifications
+ </summary>
+ <param name="sender">The <see cref="T:log4net.Repository.ILoggerRepository"/> that is shutting down.</param>
+ <param name="e">Empty event args</param>
+ <remarks>
+ <para>
+ Delegate used to handle logger repository shutdown event notifications.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Repository.LoggerRepositoryConfigurationResetEventHandler">
+ <summary>
+ Delegate used to handle logger repository configuration reset event notifications
+ </summary>
+ <param name="sender">The <see cref="T:log4net.Repository.ILoggerRepository"/> that has had its configuration reset.</param>
+ <param name="e">Empty event args</param>
+ <remarks>
+ <para>
+ Delegate used to handle logger repository configuration reset event notifications.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Repository.LoggerRepositoryConfigurationChangedEventHandler">
+ <summary>
+ Delegate used to handle event notifications for logger repository configuration changes.
+ </summary>
+ <param name="sender">The <see cref="T:log4net.Repository.ILoggerRepository"/> that has had its configuration changed.</param>
+ <param name="e">Empty event arguments.</param>
+ <remarks>
+ <para>
+ Delegate used to handle event notifications for logger repository configuration changes.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.PatternStringConverters.AppDomainPatternConverter">
+ <summary>
+ Write the name of the current AppDomain to the output
+ </summary>
+ <remarks>
+ <para>
+ Write the name of the current AppDomain to the output writer
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.PatternStringConverters.AppDomainPatternConverter.Convert(System.IO.TextWriter,System.Object)">
+ <summary>
+ Write the name of the current AppDomain to the output
+ </summary>
+ <param name="writer">the writer to write to</param>
+ <param name="state">null, state is not set</param>
+ <remarks>
+ <para>
+ Writes name of the current AppDomain to the output <paramref name="writer"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.PatternStringConverters.DatePatternConverter">
+ <summary>
+ Write the current date to the output
+ </summary>
+ <remarks>
+ <para>
+ Date pattern converter, uses a <see cref="T:log4net.DateFormatter.IDateFormatter"/> to format
+ the current date and time to the writer as a string.
+ </para>
+ <para>
+ The value of the <see cref="P:log4net.Util.PatternConverter.Option"/> determines
+ the formatting of the date. The following values are allowed:
+ <list type="definition">
+ <listheader>
+ <term>Option value</term>
+ <description>Output</description>
+ </listheader>
+ <item>
+ <term>ISO8601</term>
+ <description>
+ Uses the <see cref="T:log4net.DateFormatter.Iso8601DateFormatter"/> formatter.
+ Formats using the <c>"yyyy-MM-dd HH:mm:ss,fff"</c> pattern.
+ </description>
+ </item>
+ <item>
+ <term>DATE</term>
+ <description>
+ Uses the <see cref="T:log4net.DateFormatter.DateTimeDateFormatter"/> formatter.
+ Formats using the <c>"dd MMM yyyy HH:mm:ss,fff"</c> for example, <c>"06 Nov 1994 15:49:37,459"</c>.
+ </description>
+ </item>
+ <item>
+ <term>ABSOLUTE</term>
+ <description>
+ Uses the <see cref="T:log4net.DateFormatter.AbsoluteTimeDateFormatter"/> formatter.
+ Formats using the <c>"HH:mm:ss,fff"</c> for example, <c>"15:49:37,459"</c>.
+ </description>
+ </item>
+ <item>
+ <term>other</term>
+ <description>
+ Any other pattern string uses the <see cref="T:log4net.DateFormatter.SimpleDateFormatter"/> formatter.
+ This formatter passes the pattern string to the <see cref="T:System.DateTime"/>
+ <see cref="M:System.DateTime.ToString(System.String)"/> method.
+ For details on valid patterns see
+ <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemglobalizationdatetimeformatinfoclasstopic.asp">DateTimeFormatInfo Class</a>.
+ </description>
+ </item>
+ </list>
+ </para>
+ <para>
+ The date and time is in the local time zone and is rendered in that zone.
+ To output the time in Universal time see <see cref="T:log4net.Util.PatternStringConverters.UtcDatePatternConverter"/>.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="F:log4net.Util.PatternStringConverters.DatePatternConverter.m_dateFormatter">
+ <summary>
+ The <see cref="T:log4net.DateFormatter.IDateFormatter"/> used to render the date to a string
+ </summary>
+ <remarks>
+ <para>
+ The <see cref="T:log4net.DateFormatter.IDateFormatter"/> used to render the date to a string
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternStringConverters.DatePatternConverter.ActivateOptions">
+ <summary>
+ Initialize the converter options
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Util.PatternStringConverters.DatePatternConverter.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Util.PatternStringConverters.DatePatternConverter.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Util.PatternStringConverters.DatePatternConverter.ActivateOptions"/> must be called again.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternStringConverters.DatePatternConverter.Convert(System.IO.TextWriter,System.Object)">
+ <summary>
+ Write the current date to the output
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="state">null, state is not set</param>
+ <remarks>
+ <para>
+ Pass the current date and time to the <see cref="T:log4net.DateFormatter.IDateFormatter"/>
+ for it to render it to the writer.
+ </para>
+ <para>
+ The date and time passed is in the local time zone.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.PatternStringConverters.EnvironmentPatternConverter">
+ <summary>
+ Write an environment variable to the output
+ </summary>
+ <remarks>
+ <para>
+ Write an environment variable to the output writer.
+ The value of the <see cref="P:log4net.Util.PatternConverter.Option"/> determines
+ the name of the variable to output.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.PatternStringConverters.EnvironmentPatternConverter.Convert(System.IO.TextWriter,System.Object)">
+ <summary>
+ Write an environment variable to the output
+ </summary>
+ <param name="writer">the writer to write to</param>
+ <param name="state">null, state is not set</param>
+ <remarks>
+ <para>
+ Writes the environment variable to the output <paramref name="writer"/>.
+ The name of the environment variable to output must be set
+ using the <see cref="P:log4net.Util.PatternConverter.Option"/>
+ property.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.PatternStringConverters.IdentityPatternConverter">
+ <summary>
+ Write the current thread identity to the output
+ </summary>
+ <remarks>
+ <para>
+ Write the current thread identity to the output writer
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.PatternStringConverters.IdentityPatternConverter.Convert(System.IO.TextWriter,System.Object)">
+ <summary>
+ Write the current thread identity to the output
+ </summary>
+ <param name="writer">the writer to write to</param>
+ <param name="state">null, state is not set</param>
+ <remarks>
+ <para>
+ Writes the current thread identity to the output <paramref name="writer"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.PatternStringConverters.LiteralPatternConverter">
+ <summary>
+ Pattern converter for literal string instances in the pattern
+ </summary>
+ <remarks>
+ <para>
+ Writes the literal string value specified in the
+ <see cref="P:log4net.Util.PatternConverter.Option"/> property to
+ the output.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.PatternStringConverters.LiteralPatternConverter.SetNext(log4net.Util.PatternConverter)">
+ <summary>
+ Set the next converter in the chain
+ </summary>
+ <param name="pc">The next pattern converter in the chain</param>
+ <returns>The next pattern converter</returns>
+ <remarks>
+ <para>
+ Special case the building of the pattern converter chain
+ for <see cref="T:log4net.Util.PatternStringConverters.LiteralPatternConverter"/> instances. Two adjacent
+ literals in the pattern can be represented by a single combined
+ pattern converter. This implementation detects when a
+ <see cref="T:log4net.Util.PatternStringConverters.LiteralPatternConverter"/> is added to the chain
+ after this converter and combines its value with this converter's
+ literal value.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternStringConverters.LiteralPatternConverter.Format(System.IO.TextWriter,System.Object)">
+ <summary>
+ Write the literal to the output
+ </summary>
+ <param name="writer">the writer to write to</param>
+ <param name="state">null, not set</param>
+ <remarks>
+ <para>
+ Override the formatting behavior to ignore the FormattingInfo
+ because we have a literal instead.
+ </para>
+ <para>
+ Writes the value of <see cref="P:log4net.Util.PatternConverter.Option"/>
+ to the output <paramref name="writer"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternStringConverters.LiteralPatternConverter.Convert(System.IO.TextWriter,System.Object)">
+ <summary>
+ Convert this pattern into the rendered message
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="state">null, not set</param>
+ <remarks>
+ <para>
+ This method is not used.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.PatternStringConverters.NewLinePatternConverter">
+ <summary>
+ Writes a newline to the output
+ </summary>
+ <remarks>
+ <para>
+ Writes the system dependent line terminator to the output.
+ This behavior can be overridden by setting the <see cref="P:log4net.Util.PatternConverter.Option"/>:
+ </para>
+ <list type="definition">
+ <listheader>
+ <term>Option Value</term>
+ <description>Output</description>
+ </listheader>
+ <item>
+ <term>DOS</term>
+ <description>DOS or Windows line terminator <c>"\r\n"</c></description>
+ </item>
+ <item>
+ <term>UNIX</term>
+ <description>UNIX line terminator <c>"\n"</c></description>
+ </item>
+ </list>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.PatternStringConverters.NewLinePatternConverter.ActivateOptions">
+ <summary>
+ Initialize the converter
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Util.PatternStringConverters.NewLinePatternConverter.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Util.PatternStringConverters.NewLinePatternConverter.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Util.PatternStringConverters.NewLinePatternConverter.ActivateOptions"/> must be called again.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.PatternStringConverters.ProcessIdPatternConverter">
+ <summary>
+ Write the current process ID to the output
+ </summary>
+ <remarks>
+ <para>
+ Write the current process ID to the output writer
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.PatternStringConverters.ProcessIdPatternConverter.Convert(System.IO.TextWriter,System.Object)">
+ <summary>
+ Write the current process ID to the output
+ </summary>
+ <param name="writer">the writer to write to</param>
+ <param name="state">null, state is not set</param>
+ <remarks>
+ <para>
+ Write the current process ID to the output <paramref name="writer"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.PatternStringConverters.PropertyPatternConverter">
+ <summary>
+ Property pattern converter
+ </summary>
+ <remarks>
+ <para>
+ This pattern converter reads the thread and global properties.
+ The thread properties take priority over global properties.
+ See <see cref="P:log4net.ThreadContext.Properties"/> for details of the
+ thread properties. See <see cref="P:log4net.GlobalContext.Properties"/> for
+ details of the global properties.
+ </para>
+ <para>
+ If the <see cref="P:log4net.Util.PatternConverter.Option"/> is specified then that will be used to
+ lookup a single property. If no <see cref="P:log4net.Util.PatternConverter.Option"/> is specified
+ then all properties will be dumped as a list of key value pairs.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.PatternStringConverters.PropertyPatternConverter.Convert(System.IO.TextWriter,System.Object)">
+ <summary>
+ Write the property value to the output
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="state">null, state is not set</param>
+ <remarks>
+ <para>
+ Writes out the value of a named property. The property name
+ should be set in the <see cref="P:log4net.Util.PatternConverter.Option"/>
+ property.
+ </para>
+ <para>
+ If the <see cref="P:log4net.Util.PatternConverter.Option"/> is set to <c>null</c>
+ then all the properties are written as key value pairs.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.PatternStringConverters.RandomStringPatternConverter">
+ <summary>
+ A Pattern converter that generates a string of random characters
+ </summary>
+ <remarks>
+ <para>
+ The converter generates a string of random characters. By default
+ the string is length 4. This can be changed by setting the <see cref="P:log4net.Util.PatternConverter.Option"/>
+ to the string value of the length required.
+ </para>
+ <para>
+ The random characters in the string are limited to uppercase letters
+ and numbers only.
+ </para>
+ <para>
+ The random number generator used by this class is not cryptographically secure.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="F:log4net.Util.PatternStringConverters.RandomStringPatternConverter.s_random">
+ <summary>
+ Shared random number generator
+ </summary>
+ </member>
+ <member name="F:log4net.Util.PatternStringConverters.RandomStringPatternConverter.m_length">
+ <summary>
+ Length of random string to generate. Default length 4.
+ </summary>
+ </member>
+ <member name="M:log4net.Util.PatternStringConverters.RandomStringPatternConverter.ActivateOptions">
+ <summary>
+ Initialize the converter options
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Util.PatternStringConverters.RandomStringPatternConverter.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Util.PatternStringConverters.RandomStringPatternConverter.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Util.PatternStringConverters.RandomStringPatternConverter.ActivateOptions"/> must be called again.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternStringConverters.RandomStringPatternConverter.Convert(System.IO.TextWriter,System.Object)">
+ <summary>
+ Write a randoim string to the output
+ </summary>
+ <param name="writer">the writer to write to</param>
+ <param name="state">null, state is not set</param>
+ <remarks>
+ <para>
+ Write a randoim string to the output <paramref name="writer"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.PatternStringConverters.UserNamePatternConverter">
+ <summary>
+ Write the current threads username to the output
+ </summary>
+ <remarks>
+ <para>
+ Write the current threads username to the output writer
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.PatternStringConverters.UserNamePatternConverter.Convert(System.IO.TextWriter,System.Object)">
+ <summary>
+ Write the current threads username to the output
+ </summary>
+ <param name="writer">the writer to write to</param>
+ <param name="state">null, state is not set</param>
+ <remarks>
+ <para>
+ Write the current threads username to the output <paramref name="writer"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.PatternStringConverters.UtcDatePatternConverter">
+ <summary>
+ Write the UTC date time to the output
+ </summary>
+ <remarks>
+ <para>
+ Date pattern converter, uses a <see cref="T:log4net.DateFormatter.IDateFormatter"/> to format
+ the current date and time in Universal time.
+ </para>
+ <para>
+ See the <see cref="T:log4net.Util.PatternStringConverters.DatePatternConverter"/> for details on the date pattern syntax.
+ </para>
+ </remarks>
+ <seealso cref="T:log4net.Util.PatternStringConverters.DatePatternConverter"/>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.PatternStringConverters.UtcDatePatternConverter.Convert(System.IO.TextWriter,System.Object)">
+ <summary>
+ Write the current date and time to the output
+ </summary>
+ <param name="writer"><see cref="T:System.IO.TextWriter"/> that will receive the formatted result.</param>
+ <param name="state">null, state is not set</param>
+ <remarks>
+ <para>
+ Pass the current date and time to the <see cref="T:log4net.DateFormatter.IDateFormatter"/>
+ for it to render it to the writer.
+ </para>
+ <para>
+ The date is in Universal time when it is rendered.
+ </para>
+ </remarks>
+ <seealso cref="T:log4net.Util.PatternStringConverters.DatePatternConverter"/>
+ </member>
+ <member name="T:log4net.Util.TypeConverters.BooleanConverter">
+ <summary>
+ Type converter for Boolean.
+ </summary>
+ <remarks>
+ <para>
+ Supports conversion from string to <c>bool</c> type.
+ </para>
+ </remarks>
+ <seealso cref="T:log4net.Util.TypeConverters.ConverterRegistry"/>
+ <seealso cref="T:log4net.Util.TypeConverters.IConvertFrom"/>
+ <seealso cref="T:log4net.Util.TypeConverters.IConvertTo"/>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.BooleanConverter.CanConvertFrom(System.Type)">
+ <summary>
+ Can the source type be converted to the type supported by this object
+ </summary>
+ <param name="sourceType">the type to convert</param>
+ <returns>true if the conversion is possible</returns>
+ <remarks>
+ <para>
+ Returns <c>true</c> if the <paramref name="sourceType"/> is
+ the <see cref="T:System.String"/> type.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.BooleanConverter.ConvertFrom(System.Object)">
+ <summary>
+ Convert the source object to the type supported by this object
+ </summary>
+ <param name="source">the object to convert</param>
+ <returns>the converted object</returns>
+ <remarks>
+ <para>
+ Uses the <see cref="M:System.Boolean.Parse(System.String)"/> method to convert the
+ <see cref="T:System.String"/> argument to a <see cref="T:System.Boolean"/>.
+ </para>
+ </remarks>
+ <exception cref="T:log4net.Util.TypeConverters.ConversionNotSupportedException">
+ The <paramref name="source"/> object cannot be converted to the
+ target type. To check for this condition use the <see cref="M:log4net.Util.TypeConverters.BooleanConverter.CanConvertFrom(System.Type)"/>
+ method.
+ </exception>
+ </member>
+ <member name="T:log4net.Util.TypeConverters.ConversionNotSupportedException">
+ <summary>
+ Exception base type for conversion errors.
+ </summary>
+ <remarks>
+ <para>
+ This type extends <see cref="T:System.ApplicationException"/>. It
+ does not add any new functionality but does differentiate the
+ type of exception being thrown.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.ConversionNotSupportedException.#ctor">
+ <summary>
+ Constructor
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.TypeConverters.ConversionNotSupportedException"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.ConversionNotSupportedException.#ctor(System.String)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="message">A message to include with the exception.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.TypeConverters.ConversionNotSupportedException"/> class
+ with the specified message.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.ConversionNotSupportedException.#ctor(System.String,System.Exception)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="message">A message to include with the exception.</param>
+ <param name="innerException">A nested exception to include.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.TypeConverters.ConversionNotSupportedException"/> class
+ with the specified message and inner exception.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.ConversionNotSupportedException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)">
+ <summary>
+ Serialization constructor
+ </summary>
+ <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
+ <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext"/> that contains contextual information about the source or destination.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.TypeConverters.ConversionNotSupportedException"/> class
+ with serialized data.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.ConversionNotSupportedException.Create(System.Type,System.Object)">
+ <summary>
+ Creates a new instance of the <see cref="T:log4net.Util.TypeConverters.ConversionNotSupportedException"/> class.
+ </summary>
+ <param name="destinationType">The conversion destination type.</param>
+ <param name="sourceValue">The value to convert.</param>
+ <returns>An instance of the <see cref="T:log4net.Util.TypeConverters.ConversionNotSupportedException"/>.</returns>
+ <remarks>
+ <para>
+ Creates a new instance of the <see cref="T:log4net.Util.TypeConverters.ConversionNotSupportedException"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.ConversionNotSupportedException.Create(System.Type,System.Object,System.Exception)">
+ <summary>
+ Creates a new instance of the <see cref="T:log4net.Util.TypeConverters.ConversionNotSupportedException"/> class.
+ </summary>
+ <param name="destinationType">The conversion destination type.</param>
+ <param name="sourceValue">The value to convert.</param>
+ <param name="innerException">A nested exception to include.</param>
+ <returns>An instance of the <see cref="T:log4net.Util.TypeConverters.ConversionNotSupportedException"/>.</returns>
+ <remarks>
+ <para>
+ Creates a new instance of the <see cref="T:log4net.Util.TypeConverters.ConversionNotSupportedException"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.TypeConverters.ConverterRegistry">
+ <summary>
+ Register of type converters for specific types.
+ </summary>
+ <remarks>
+ <para>
+ Maintains a registry of type converters used to convert between
+ types.
+ </para>
+ <para>
+ Use the <see cref="M:log4net.Util.TypeConverters.ConverterRegistry.AddConverter(System.Type,System.Object)"/> and
+ <see cref="M:log4net.Util.TypeConverters.ConverterRegistry.AddConverter(System.Type,System.Type)"/> methods to register new converters.
+ The <see cref="M:log4net.Util.TypeConverters.ConverterRegistry.GetConvertTo(System.Type,System.Type)"/> and <see cref="M:log4net.Util.TypeConverters.ConverterRegistry.GetConvertFrom(System.Type)"/> methods
+ lookup appropriate converters to use.
+ </para>
+ </remarks>
+ <seealso cref="T:log4net.Util.TypeConverters.IConvertFrom"/>
+ <seealso cref="T:log4net.Util.TypeConverters.IConvertTo"/>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.ConverterRegistry.#ctor">
+ <summary>
+ Private constructor
+ </summary>
+ <remarks>
+ Initializes a new instance of the <see cref="T:log4net.Util.TypeConverters.ConverterRegistry"/> class.
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.ConverterRegistry.#cctor">
+ <summary>
+ Static constructor.
+ </summary>
+ <remarks>
+ <para>
+ This constructor defines the intrinsic type converters.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.ConverterRegistry.AddConverter(System.Type,System.Object)">
+ <summary>
+ Adds a converter for a specific type.
+ </summary>
+ <param name="destinationType">The type being converted to.</param>
+ <param name="converter">The type converter to use to convert to the destination type.</param>
+ <remarks>
+ <para>
+ Adds a converter instance for a specific type.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.ConverterRegistry.AddConverter(System.Type,System.Type)">
+ <summary>
+ Adds a converter for a specific type.
+ </summary>
+ <param name="destinationType">The type being converted to.</param>
+ <param name="converterType">The type of the type converter to use to convert to the destination type.</param>
+ <remarks>
+ <para>
+ Adds a converter <see cref="T:System.Type"/> for a specific type.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.ConverterRegistry.GetConvertTo(System.Type,System.Type)">
+ <summary>
+ Gets the type converter to use to convert values to the destination type.
+ </summary>
+ <param name="sourceType">The type being converted from.</param>
+ <param name="destinationType">The type being converted to.</param>
+ <returns>
+ The type converter instance to use for type conversions or <c>null</c>
+ if no type converter is found.
+ </returns>
+ <remarks>
+ <para>
+ Gets the type converter to use to convert values to the destination type.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.ConverterRegistry.GetConvertFrom(System.Type)">
+ <summary>
+ Gets the type converter to use to convert values to the destination type.
+ </summary>
+ <param name="destinationType">The type being converted to.</param>
+ <returns>
+ The type converter instance to use for type conversions or <c>null</c>
+ if no type converter is found.
+ </returns>
+ <remarks>
+ <para>
+ Gets the type converter to use to convert values to the destination type.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.ConverterRegistry.GetConverterFromAttribute(System.Type)">
+ <summary>
+ Lookups the type converter to use as specified by the attributes on the
+ destination type.
+ </summary>
+ <param name="destinationType">The type being converted to.</param>
+ <returns>
+ The type converter instance to use for type conversions or <c>null</c>
+ if no type converter is found.
+ </returns>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.ConverterRegistry.CreateConverterInstance(System.Type)">
+ <summary>
+ Creates the instance of the type converter.
+ </summary>
+ <param name="converterType">The type of the type converter.</param>
+ <returns>
+ The type converter instance to use for type conversions or <c>null</c>
+ if no type converter is found.
+ </returns>
+ <remarks>
+ <para>
+ The type specified for the type converter must implement
+ the <see cref="T:log4net.Util.TypeConverters.IConvertFrom"/> or <see cref="T:log4net.Util.TypeConverters.IConvertTo"/> interfaces
+ and must have a public default (no argument) constructor.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Util.TypeConverters.ConverterRegistry.s_type2converter">
+ <summary>
+ Mapping from <see cref="T:System.Type"/> to type converter.
+ </summary>
+ </member>
+ <member name="T:log4net.Util.TypeConverters.EncodingConverter">
+ <summary>
+ Supports conversion from string to <see cref="T:System.Text.Encoding"/> type.
+ </summary>
+ <remarks>
+ <para>
+ Supports conversion from string to <see cref="T:System.Text.Encoding"/> type.
+ </para>
+ </remarks>
+ <seealso cref="T:log4net.Util.TypeConverters.ConverterRegistry"/>
+ <seealso cref="T:log4net.Util.TypeConverters.IConvertFrom"/>
+ <seealso cref="T:log4net.Util.TypeConverters.IConvertTo"/>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.EncodingConverter.CanConvertFrom(System.Type)">
+ <summary>
+ Can the source type be converted to the type supported by this object
+ </summary>
+ <param name="sourceType">the type to convert</param>
+ <returns>true if the conversion is possible</returns>
+ <remarks>
+ <para>
+ Returns <c>true</c> if the <paramref name="sourceType"/> is
+ the <see cref="T:System.String"/> type.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.EncodingConverter.ConvertFrom(System.Object)">
+ <summary>
+ Overrides the ConvertFrom method of IConvertFrom.
+ </summary>
+ <param name="source">the object to convert to an encoding</param>
+ <returns>the encoding</returns>
+ <remarks>
+ <para>
+ Uses the <see cref="M:System.Text.Encoding.GetEncoding(System.String)"/> method to
+ convert the <see cref="T:System.String"/> argument to an <see cref="T:System.Text.Encoding"/>.
+ </para>
+ </remarks>
+ <exception cref="T:log4net.Util.TypeConverters.ConversionNotSupportedException">
+ The <paramref name="source"/> object cannot be converted to the
+ target type. To check for this condition use the <see cref="M:log4net.Util.TypeConverters.EncodingConverter.CanConvertFrom(System.Type)"/>
+ method.
+ </exception>
+ </member>
+ <member name="T:log4net.Util.TypeConverters.IConvertTo">
+ <summary>
+ Interface supported by type converters
+ </summary>
+ <remarks>
+ <para>
+ This interface supports conversion from a single type to arbitrary types.
+ See <see cref="T:log4net.Util.TypeConverters.TypeConverterAttribute"/>.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.IConvertTo.CanConvertTo(System.Type)">
+ <summary>
+ Returns whether this converter can convert the object to the specified type
+ </summary>
+ <param name="targetType">A Type that represents the type you want to convert to</param>
+ <returns>true if the conversion is possible</returns>
+ <remarks>
+ <para>
+ Test if the type supported by this converter can be converted to the
+ <paramref name="targetType"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.IConvertTo.ConvertTo(System.Object,System.Type)">
+ <summary>
+ Converts the given value object to the specified type, using the arguments
+ </summary>
+ <param name="source">the object to convert</param>
+ <param name="targetType">The Type to convert the value parameter to</param>
+ <returns>the converted object</returns>
+ <remarks>
+ <para>
+ Converts the <paramref name="source"/> (which must be of the type supported
+ by this converter) to the <paramref name="targetType"/> specified..
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.TypeConverters.IPAddressConverter">
+ <summary>
+ Supports conversion from string to <see cref="T:System.Net.IPAddress"/> type.
+ </summary>
+ <remarks>
+ <para>
+ Supports conversion from string to <see cref="T:System.Net.IPAddress"/> type.
+ </para>
+ </remarks>
+ <seealso cref="T:log4net.Util.TypeConverters.ConverterRegistry"/>
+ <seealso cref="T:log4net.Util.TypeConverters.IConvertFrom"/>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.IPAddressConverter.CanConvertFrom(System.Type)">
+ <summary>
+ Can the source type be converted to the type supported by this object
+ </summary>
+ <param name="sourceType">the type to convert</param>
+ <returns>true if the conversion is possible</returns>
+ <remarks>
+ <para>
+ Returns <c>true</c> if the <paramref name="sourceType"/> is
+ the <see cref="T:System.String"/> type.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.IPAddressConverter.ConvertFrom(System.Object)">
+ <summary>
+ Overrides the ConvertFrom method of IConvertFrom.
+ </summary>
+ <param name="source">the object to convert to an IPAddress</param>
+ <returns>the IPAddress</returns>
+ <remarks>
+ <para>
+ Uses the <see cref="M:System.Net.IPAddress.Parse(System.String)"/> method to convert the
+ <see cref="T:System.String"/> argument to an <see cref="T:System.Net.IPAddress"/>.
+ If that fails then the string is resolved as a DNS hostname.
+ </para>
+ </remarks>
+ <exception cref="T:log4net.Util.TypeConverters.ConversionNotSupportedException">
+ The <paramref name="source"/> object cannot be converted to the
+ target type. To check for this condition use the <see cref="M:log4net.Util.TypeConverters.IPAddressConverter.CanConvertFrom(System.Type)"/>
+ method.
+ </exception>
+ </member>
+ <member name="F:log4net.Util.TypeConverters.IPAddressConverter.validIpAddressChars">
+ <summary>
+ Valid characters in an IPv4 or IPv6 address string. (Does not support subnets)
+ </summary>
+ </member>
+ <member name="T:log4net.Util.TypeConverters.PatternLayoutConverter">
+ <summary>
+ Supports conversion from string to <see cref="T:log4net.Layout.PatternLayout"/> type.
+ </summary>
+ <remarks>
+ <para>
+ Supports conversion from string to <see cref="T:log4net.Layout.PatternLayout"/> type.
+ </para>
+ <para>
+ The string is used as the <see cref="P:log4net.Layout.PatternLayout.ConversionPattern"/>
+ of the <see cref="T:log4net.Layout.PatternLayout"/>.
+ </para>
+ </remarks>
+ <seealso cref="T:log4net.Util.TypeConverters.ConverterRegistry"/>
+ <seealso cref="T:log4net.Util.TypeConverters.IConvertFrom"/>
+ <seealso cref="T:log4net.Util.TypeConverters.IConvertTo"/>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.PatternLayoutConverter.CanConvertFrom(System.Type)">
+ <summary>
+ Can the source type be converted to the type supported by this object
+ </summary>
+ <param name="sourceType">the type to convert</param>
+ <returns>true if the conversion is possible</returns>
+ <remarks>
+ <para>
+ Returns <c>true</c> if the <paramref name="sourceType"/> is
+ the <see cref="T:System.String"/> type.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.PatternLayoutConverter.ConvertFrom(System.Object)">
+ <summary>
+ Overrides the ConvertFrom method of IConvertFrom.
+ </summary>
+ <param name="source">the object to convert to a PatternLayout</param>
+ <returns>the PatternLayout</returns>
+ <remarks>
+ <para>
+ Creates and returns a new <see cref="T:log4net.Layout.PatternLayout"/> using
+ the <paramref name="source"/> <see cref="T:System.String"/> as the
+ <see cref="P:log4net.Layout.PatternLayout.ConversionPattern"/>.
+ </para>
+ </remarks>
+ <exception cref="T:log4net.Util.TypeConverters.ConversionNotSupportedException">
+ The <paramref name="source"/> object cannot be converted to the
+ target type. To check for this condition use the <see cref="M:log4net.Util.TypeConverters.PatternLayoutConverter.CanConvertFrom(System.Type)"/>
+ method.
+ </exception>
+ </member>
+ <member name="T:log4net.Util.TypeConverters.PatternStringConverter">
+ <summary>
+ Convert between string and <see cref="T:log4net.Util.PatternString"/>
+ </summary>
+ <remarks>
+ <para>
+ Supports conversion from string to <see cref="T:log4net.Util.PatternString"/> type,
+ and from a <see cref="T:log4net.Util.PatternString"/> type to a string.
+ </para>
+ <para>
+ The string is used as the <see cref="P:log4net.Util.PatternString.ConversionPattern"/>
+ of the <see cref="T:log4net.Util.PatternString"/>.
+ </para>
+ </remarks>
+ <seealso cref="T:log4net.Util.TypeConverters.ConverterRegistry"/>
+ <seealso cref="T:log4net.Util.TypeConverters.IConvertFrom"/>
+ <seealso cref="T:log4net.Util.TypeConverters.IConvertTo"/>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.PatternStringConverter.CanConvertTo(System.Type)">
+ <summary>
+ Can the target type be converted to the type supported by this object
+ </summary>
+ <param name="targetType">A <see cref="T:System.Type"/> that represents the type you want to convert to</param>
+ <returns>true if the conversion is possible</returns>
+ <remarks>
+ <para>
+ Returns <c>true</c> if the <paramref name="targetType"/> is
+ assignable from a <see cref="T:System.String"/> type.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.PatternStringConverter.ConvertTo(System.Object,System.Type)">
+ <summary>
+ Converts the given value object to the specified type, using the arguments
+ </summary>
+ <param name="source">the object to convert</param>
+ <param name="targetType">The Type to convert the value parameter to</param>
+ <returns>the converted object</returns>
+ <remarks>
+ <para>
+ Uses the <see cref="M:log4net.Util.PatternString.Format"/> method to convert the
+ <see cref="T:log4net.Util.PatternString"/> argument to a <see cref="T:System.String"/>.
+ </para>
+ </remarks>
+ <exception cref="T:log4net.Util.TypeConverters.ConversionNotSupportedException">
+ The <paramref name="source"/> object cannot be converted to the
+ <paramref name="targetType"/>. To check for this condition use the
+ <see cref="M:log4net.Util.TypeConverters.PatternStringConverter.CanConvertTo(System.Type)"/> method.
+ </exception>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.PatternStringConverter.CanConvertFrom(System.Type)">
+ <summary>
+ Can the source type be converted to the type supported by this object
+ </summary>
+ <param name="sourceType">the type to convert</param>
+ <returns>true if the conversion is possible</returns>
+ <remarks>
+ <para>
+ Returns <c>true</c> if the <paramref name="sourceType"/> is
+ the <see cref="T:System.String"/> type.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.PatternStringConverter.ConvertFrom(System.Object)">
+ <summary>
+ Overrides the ConvertFrom method of IConvertFrom.
+ </summary>
+ <param name="source">the object to convert to a PatternString</param>
+ <returns>the PatternString</returns>
+ <remarks>
+ <para>
+ Creates and returns a new <see cref="T:log4net.Util.PatternString"/> using
+ the <paramref name="source"/> <see cref="T:System.String"/> as the
+ <see cref="P:log4net.Util.PatternString.ConversionPattern"/>.
+ </para>
+ </remarks>
+ <exception cref="T:log4net.Util.TypeConverters.ConversionNotSupportedException">
+ The <paramref name="source"/> object cannot be converted to the
+ target type. To check for this condition use the <see cref="M:log4net.Util.TypeConverters.PatternStringConverter.CanConvertFrom(System.Type)"/>
+ method.
+ </exception>
+ </member>
+ <member name="T:log4net.Util.TypeConverters.TypeConverter">
+ <summary>
+ Supports conversion from string to <see cref="T:System.Type"/> type.
+ </summary>
+ <remarks>
+ <para>
+ Supports conversion from string to <see cref="T:System.Type"/> type.
+ </para>
+ </remarks>
+ <seealso cref="T:log4net.Util.TypeConverters.ConverterRegistry"/>
+ <seealso cref="T:log4net.Util.TypeConverters.IConvertFrom"/>
+ <seealso cref="T:log4net.Util.TypeConverters.IConvertTo"/>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.TypeConverter.CanConvertFrom(System.Type)">
+ <summary>
+ Can the source type be converted to the type supported by this object
+ </summary>
+ <param name="sourceType">the type to convert</param>
+ <returns>true if the conversion is possible</returns>
+ <remarks>
+ <para>
+ Returns <c>true</c> if the <paramref name="sourceType"/> is
+ the <see cref="T:System.String"/> type.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.TypeConverter.ConvertFrom(System.Object)">
+ <summary>
+ Overrides the ConvertFrom method of IConvertFrom.
+ </summary>
+ <param name="source">the object to convert to a Type</param>
+ <returns>the Type</returns>
+ <remarks>
+ <para>
+ Uses the <see cref="M:System.Type.GetType(System.String,System.Boolean)"/> method to convert the
+ <see cref="T:System.String"/> argument to a <see cref="T:System.Type"/>.
+ Additional effort is made to locate partially specified types
+ by searching the loaded assemblies.
+ </para>
+ </remarks>
+ <exception cref="T:log4net.Util.TypeConverters.ConversionNotSupportedException">
+ The <paramref name="source"/> object cannot be converted to the
+ target type. To check for this condition use the <see cref="M:log4net.Util.TypeConverters.TypeConverter.CanConvertFrom(System.Type)"/>
+ method.
+ </exception>
+ </member>
+ <member name="T:log4net.Util.TypeConverters.TypeConverterAttribute">
+ <summary>
+ Attribute used to associate a type converter
+ </summary>
+ <remarks>
+ <para>
+ Class and Interface level attribute that specifies a type converter
+ to use with the associated type.
+ </para>
+ <para>
+ To associate a type converter with a target type apply a
+ <c>TypeConverterAttribute</c> to the target type. Specify the
+ type of the type converter on the attribute.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="F:log4net.Util.TypeConverters.TypeConverterAttribute.m_typeName">
+ <summary>
+ The string type name of the type converter
+ </summary>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.TypeConverterAttribute.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ <remarks>
+ <para>
+ Default constructor
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.TypeConverterAttribute.#ctor(System.String)">
+ <summary>
+ Create a new type converter attribute for the specified type name
+ </summary>
+ <param name="typeName">The string type name of the type converter</param>
+ <remarks>
+ <para>
+ The type specified must implement the <see cref="T:log4net.Util.TypeConverters.IConvertFrom"/>
+ or the <see cref="T:log4net.Util.TypeConverters.IConvertTo"/> interfaces.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TypeConverters.TypeConverterAttribute.#ctor(System.Type)">
+ <summary>
+ Create a new type converter attribute for the specified type
+ </summary>
+ <param name="converterType">The type of the type converter</param>
+ <remarks>
+ <para>
+ The type specified must implement the <see cref="T:log4net.Util.TypeConverters.IConvertFrom"/>
+ or the <see cref="T:log4net.Util.TypeConverters.IConvertTo"/> interfaces.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.TypeConverters.TypeConverterAttribute.ConverterTypeName">
+ <summary>
+ The string type name of the type converter
+ </summary>
+ <value>
+ The string type name of the type converter
+ </value>
+ <remarks>
+ <para>
+ The type specified must implement the <see cref="T:log4net.Util.TypeConverters.IConvertFrom"/>
+ or the <see cref="T:log4net.Util.TypeConverters.IConvertTo"/> interfaces.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.AppenderAttachedImpl">
+ <summary>
+ A straightforward implementation of the <see cref="T:log4net.Core.IAppenderAttachable"/> interface.
+ </summary>
+ <remarks>
+ <para>
+ This is the default implementation of the <see cref="T:log4net.Core.IAppenderAttachable"/>
+ interface. Implementors of the <see cref="T:log4net.Core.IAppenderAttachable"/> interface
+ should aggregate an instance of this type.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Util.AppenderAttachedImpl.#ctor">
+ <summary>
+ Constructor
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.AppenderAttachedImpl"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.AppenderAttachedImpl.AppendLoopOnAppenders(log4net.Core.LoggingEvent)">
+ <summary>
+ Append on on all attached appenders.
+ </summary>
+ <param name="loggingEvent">The event being logged.</param>
+ <returns>The number of appenders called.</returns>
+ <remarks>
+ <para>
+ Calls the <see cref="M:log4net.Appender.IAppender.DoAppend(log4net.Core.LoggingEvent)"/> method on all
+ attached appenders.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.AppenderAttachedImpl.AppendLoopOnAppenders(log4net.Core.LoggingEvent[])">
+ <summary>
+ Append on on all attached appenders.
+ </summary>
+ <param name="loggingEvents">The array of events being logged.</param>
+ <returns>The number of appenders called.</returns>
+ <remarks>
+ <para>
+ Calls the <see cref="M:log4net.Appender.IAppender.DoAppend(log4net.Core.LoggingEvent)"/> method on all
+ attached appenders.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.AppenderAttachedImpl.CallAppend(log4net.Appender.IAppender,log4net.Core.LoggingEvent[])">
+ <summary>
+ Calls the DoAppende method on the <see cref="T:log4net.Appender.IAppender"/> with
+ the <see cref="T:log4net.Core.LoggingEvent"/> objects supplied.
+ </summary>
+ <param name="appender">The appender</param>
+ <param name="loggingEvents">The events</param>
+ <remarks>
+ <para>
+ If the <paramref name="appender"/> supports the <see cref="T:log4net.Appender.IBulkAppender"/>
+ interface then the <paramref name="loggingEvents"/> will be passed
+ through using that interface. Otherwise the <see cref="T:log4net.Core.LoggingEvent"/>
+ objects in the array will be passed one at a time.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.AppenderAttachedImpl.AddAppender(log4net.Appender.IAppender)">
+ <summary>
+ Attaches an appender.
+ </summary>
+ <param name="newAppender">The appender to add.</param>
+ <remarks>
+ <para>
+ If the appender is already in the list it won't be added again.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.AppenderAttachedImpl.GetAppender(System.String)">
+ <summary>
+ Gets an attached appender with the specified name.
+ </summary>
+ <param name="name">The name of the appender to get.</param>
+ <returns>
+ The appender with the name specified, or <c>null</c> if no appender with the
+ specified name is found.
+ </returns>
+ <remarks>
+ <para>
+ Lookup an attached appender by name.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.AppenderAttachedImpl.RemoveAllAppenders">
+ <summary>
+ Removes all attached appenders.
+ </summary>
+ <remarks>
+ <para>
+ Removes and closes all attached appenders
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.AppenderAttachedImpl.RemoveAppender(log4net.Appender.IAppender)">
+ <summary>
+ Removes the specified appender from the list of attached appenders.
+ </summary>
+ <param name="appender">The appender to remove.</param>
+ <returns>The appender removed from the list</returns>
+ <remarks>
+ <para>
+ The appender removed is not closed.
+ If you are discarding the appender you must call
+ <see cref="M:log4net.Appender.IAppender.Close"/> on the appender removed.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.AppenderAttachedImpl.RemoveAppender(System.String)">
+ <summary>
+ Removes the appender with the specified name from the list of appenders.
+ </summary>
+ <param name="name">The name of the appender to remove.</param>
+ <returns>The appender removed from the list</returns>
+ <remarks>
+ <para>
+ The appender removed is not closed.
+ If you are discarding the appender you must call
+ <see cref="M:log4net.Appender.IAppender.Close"/> on the appender removed.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Util.AppenderAttachedImpl.m_appenderList">
+ <summary>
+ List of appenders
+ </summary>
+ </member>
+ <member name="F:log4net.Util.AppenderAttachedImpl.m_appenderArray">
+ <summary>
+ Array of appenders, used to cache the m_appenderList
+ </summary>
+ </member>
+ <member name="P:log4net.Util.AppenderAttachedImpl.Appenders">
+ <summary>
+ Gets all attached appenders.
+ </summary>
+ <returns>
+ A collection of attached appenders, or <c>null</c> if there
+ are no attached appenders.
+ </returns>
+ <remarks>
+ <para>
+ The read only collection of all currently attached appenders.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.CompositeProperties">
+ <summary>
+ This class aggregates several PropertiesDictionary collections together.
+ </summary>
+ <remarks>
+ <para>
+ Provides a dictionary style lookup over an ordered list of
+ <see cref="T:log4net.Util.PropertiesDictionary"/> collections.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.CompositeProperties.#ctor">
+ <summary>
+ Constructor
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.CompositeProperties"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.CompositeProperties.Add(log4net.Util.ReadOnlyPropertiesDictionary)">
+ <summary>
+ Add a Properties Dictionary to this composite collection
+ </summary>
+ <param name="properties">the properties to add</param>
+ <remarks>
+ <para>
+ Properties dictionaries added first take precedence over dictionaries added
+ later.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.CompositeProperties.Flatten">
+ <summary>
+ Flatten this composite collection into a single properties dictionary
+ </summary>
+ <returns>the flattened dictionary</returns>
+ <remarks>
+ <para>
+ Reduces the collection of ordered dictionaries to a single dictionary
+ containing the resultant values for the keys.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.CompositeProperties.Item(System.String)">
+ <summary>
+ Gets the value of a property
+ </summary>
+ <value>
+ The value for the property with the specified key
+ </value>
+ <remarks>
+ <para>
+ Looks up the value for the <paramref name="key"/> specified.
+ The <see cref="T:log4net.Util.PropertiesDictionary"/> collections are searched
+ in the order in which they were added to this collection. The value
+ returned is the value held by the first collection that contains
+ the specified key.
+ </para>
+ <para>
+ If none of the collections contain the specified key then
+ <c>null</c> is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.ContextPropertiesBase">
+ <summary>
+ Base class for Context Properties implementations
+ </summary>
+ <remarks>
+ <para>
+ This class defines a basic property get set accessor
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="P:log4net.Util.ContextPropertiesBase.Item(System.String)">
+ <summary>
+ Gets or sets the value of a property
+ </summary>
+ <value>
+ The value for the property with the specified key
+ </value>
+ <remarks>
+ <para>
+ Gets or sets the value of a property
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.CountingQuietTextWriter">
+ <summary>
+ Subclass of <see cref="T:log4net.Util.QuietTextWriter"/> that maintains a count of
+ the number of bytes written.
+ </summary>
+ <remarks>
+ <para>
+ This writer counts the number of bytes written.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.Util.QuietTextWriter">
+ <summary>
+ <see cref="T:System.IO.TextWriter"/> that does not leak exceptions
+ </summary>
+ <remarks>
+ <para>
+ <see cref="T:log4net.Util.QuietTextWriter"/> does not throw exceptions when things go wrong.
+ Instead, it delegates error handling to its <see cref="T:log4net.Core.IErrorHandler"/>.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.Util.TextWriterAdapter">
+ <summary>
+ Adapter that extends <see cref="T:System.IO.TextWriter"/> and forwards all
+ messages to an instance of <see cref="T:System.IO.TextWriter"/>.
+ </summary>
+ <remarks>
+ <para>
+ Adapter that extends <see cref="T:System.IO.TextWriter"/> and forwards all
+ messages to an instance of <see cref="T:System.IO.TextWriter"/>.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="F:log4net.Util.TextWriterAdapter.m_writer">
+ <summary>
+ The writer to forward messages to
+ </summary>
+ </member>
+ <member name="M:log4net.Util.TextWriterAdapter.#ctor(System.IO.TextWriter)">
+ <summary>
+ Create an instance of <see cref="T:log4net.Util.TextWriterAdapter"/> that forwards all
+ messages to a <see cref="T:System.IO.TextWriter"/>.
+ </summary>
+ <param name="writer">The <see cref="T:System.IO.TextWriter"/> to forward to</param>
+ <remarks>
+ <para>
+ Create an instance of <see cref="T:log4net.Util.TextWriterAdapter"/> that forwards all
+ messages to a <see cref="T:System.IO.TextWriter"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TextWriterAdapter.Close">
+ <summary>
+ Closes the writer and releases any system resources associated with the writer
+ </summary>
+ <remarks>
+ <para>
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TextWriterAdapter.Dispose(System.Boolean)">
+ <summary>
+ Dispose this writer
+ </summary>
+ <param name="disposing">flag indicating if we are being disposed</param>
+ <remarks>
+ <para>
+ Dispose this writer
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TextWriterAdapter.Flush">
+ <summary>
+ Flushes any buffered output
+ </summary>
+ <remarks>
+ <para>
+ Clears all buffers for the writer and causes any buffered data to be written
+ to the underlying device
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TextWriterAdapter.Write(System.Char)">
+ <summary>
+ Writes a character to the wrapped TextWriter
+ </summary>
+ <param name="value">the value to write to the TextWriter</param>
+ <remarks>
+ <para>
+ Writes a character to the wrapped TextWriter
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TextWriterAdapter.Write(System.Char[],System.Int32,System.Int32)">
+ <summary>
+ Writes a character buffer to the wrapped TextWriter
+ </summary>
+ <param name="buffer">the data buffer</param>
+ <param name="index">the start index</param>
+ <param name="count">the number of characters to write</param>
+ <remarks>
+ <para>
+ Writes a character buffer to the wrapped TextWriter
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.TextWriterAdapter.Write(System.String)">
+ <summary>
+ Writes a string to the wrapped TextWriter
+ </summary>
+ <param name="value">the value to write to the TextWriter</param>
+ <remarks>
+ <para>
+ Writes a string to the wrapped TextWriter
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.TextWriterAdapter.Writer">
+ <summary>
+ Gets or sets the underlying <see cref="T:System.IO.TextWriter"/>.
+ </summary>
+ <value>
+ The underlying <see cref="T:System.IO.TextWriter"/>.
+ </value>
+ <remarks>
+ <para>
+ Gets or sets the underlying <see cref="T:System.IO.TextWriter"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.TextWriterAdapter.Encoding">
+ <summary>
+ The Encoding in which the output is written
+ </summary>
+ <value>
+ The <see cref="P:log4net.Util.TextWriterAdapter.Encoding"/>
+ </value>
+ <remarks>
+ <para>
+ The Encoding in which the output is written
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.TextWriterAdapter.FormatProvider">
+ <summary>
+ Gets an object that controls formatting
+ </summary>
+ <value>
+ The format provider
+ </value>
+ <remarks>
+ <para>
+ Gets an object that controls formatting
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.TextWriterAdapter.NewLine">
+ <summary>
+ Gets or sets the line terminator string used by the TextWriter
+ </summary>
+ <value>
+ The line terminator to use
+ </value>
+ <remarks>
+ <para>
+ Gets or sets the line terminator string used by the TextWriter
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.QuietTextWriter.#ctor(System.IO.TextWriter,log4net.Core.IErrorHandler)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="writer">the writer to actually write to</param>
+ <param name="errorHandler">the error handler to report error to</param>
+ <remarks>
+ <para>
+ Create a new QuietTextWriter using a writer and error handler
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.QuietTextWriter.Write(System.Char)">
+ <summary>
+ Writes a character to the underlying writer
+ </summary>
+ <param name="value">the char to write</param>
+ <remarks>
+ <para>
+ Writes a character to the underlying writer
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.QuietTextWriter.Write(System.Char[],System.Int32,System.Int32)">
+ <summary>
+ Writes a buffer to the underlying writer
+ </summary>
+ <param name="buffer">the buffer to write</param>
+ <param name="index">the start index to write from</param>
+ <param name="count">the number of characters to write</param>
+ <remarks>
+ <para>
+ Writes a buffer to the underlying writer
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.QuietTextWriter.Write(System.String)">
+ <summary>
+ Writes a string to the output.
+ </summary>
+ <param name="value">The string data to write to the output.</param>
+ <remarks>
+ <para>
+ Writes a string to the output.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.QuietTextWriter.Close">
+ <summary>
+ Closes the underlying output writer.
+ </summary>
+ <remarks>
+ <para>
+ Closes the underlying output writer.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Util.QuietTextWriter.m_errorHandler">
+ <summary>
+ The error handler instance to pass all errors to
+ </summary>
+ </member>
+ <member name="F:log4net.Util.QuietTextWriter.m_closed">
+ <summary>
+ Flag to indicate if this writer is closed
+ </summary>
+ </member>
+ <member name="P:log4net.Util.QuietTextWriter.ErrorHandler">
+ <summary>
+ Gets or sets the error handler that all errors are passed to.
+ </summary>
+ <value>
+ The error handler that all errors are passed to.
+ </value>
+ <remarks>
+ <para>
+ Gets or sets the error handler that all errors are passed to.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.QuietTextWriter.Closed">
+ <summary>
+ Gets a value indicating whether this writer is closed.
+ </summary>
+ <value>
+ <c>true</c> if this writer is closed, otherwise <c>false</c>.
+ </value>
+ <remarks>
+ <para>
+ Gets a value indicating whether this writer is closed.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.CountingQuietTextWriter.#ctor(System.IO.TextWriter,log4net.Core.IErrorHandler)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="writer">The <see cref="T:System.IO.TextWriter"/> to actually write to.</param>
+ <param name="errorHandler">The <see cref="T:log4net.Core.IErrorHandler"/> to report errors to.</param>
+ <remarks>
+ <para>
+ Creates a new instance of the <see cref="T:log4net.Util.CountingQuietTextWriter"/> class
+ with the specified <see cref="T:System.IO.TextWriter"/> and <see cref="T:log4net.Core.IErrorHandler"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.CountingQuietTextWriter.Write(System.Char)">
+ <summary>
+ Writes a character to the underlying writer and counts the number of bytes written.
+ </summary>
+ <param name="value">the char to write</param>
+ <remarks>
+ <para>
+ Overrides implementation of <see cref="T:log4net.Util.QuietTextWriter"/>. Counts
+ the number of bytes written.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.CountingQuietTextWriter.Write(System.Char[],System.Int32,System.Int32)">
+ <summary>
+ Writes a buffer to the underlying writer and counts the number of bytes written.
+ </summary>
+ <param name="buffer">the buffer to write</param>
+ <param name="index">the start index to write from</param>
+ <param name="count">the number of characters to write</param>
+ <remarks>
+ <para>
+ Overrides implementation of <see cref="T:log4net.Util.QuietTextWriter"/>. Counts
+ the number of bytes written.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.CountingQuietTextWriter.Write(System.String)">
+ <summary>
+ Writes a string to the output and counts the number of bytes written.
+ </summary>
+ <param name="str">The string data to write to the output.</param>
+ <remarks>
+ <para>
+ Overrides implementation of <see cref="T:log4net.Util.QuietTextWriter"/>. Counts
+ the number of bytes written.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Util.CountingQuietTextWriter.m_countBytes">
+ <summary>
+ Total number of bytes written.
+ </summary>
+ </member>
+ <member name="P:log4net.Util.CountingQuietTextWriter.Count">
+ <summary>
+ Gets or sets the total number of bytes written.
+ </summary>
+ <value>
+ The total number of bytes written.
+ </value>
+ <remarks>
+ <para>
+ Gets or sets the total number of bytes written.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.CyclicBuffer">
+ <summary>
+ A fixed size rolling buffer of logging events.
+ </summary>
+ <remarks>
+ <para>
+ An array backed fixed size leaky bucket.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Util.CyclicBuffer.#ctor(System.Int32)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="maxSize">The maximum number of logging events in the buffer.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.CyclicBuffer"/> class with
+ the specified maximum number of buffered logging events.
+ </para>
+ </remarks>
+ <exception cref="T:System.ArgumentOutOfRangeException">The <paramref name="maxSize"/> argument is not a positive integer.</exception>
+ </member>
+ <member name="M:log4net.Util.CyclicBuffer.Append(log4net.Core.LoggingEvent)">
+ <summary>
+ Appends a <paramref name="loggingEvent"/> to the buffer.
+ </summary>
+ <param name="loggingEvent">The event to append to the buffer.</param>
+ <returns>The event discarded from the buffer, if the buffer is full, otherwise <c>null</c>.</returns>
+ <remarks>
+ <para>
+ Append an event to the buffer. If the buffer still contains free space then
+ <c>null</c> is returned. If the buffer is full then an event will be dropped
+ to make space for the new event, the event dropped is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.CyclicBuffer.PopOldest">
+ <summary>
+ Get and remove the oldest event in the buffer.
+ </summary>
+ <returns>The oldest logging event in the buffer</returns>
+ <remarks>
+ <para>
+ Gets the oldest (first) logging event in the buffer and removes it
+ from the buffer.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.CyclicBuffer.PopAll">
+ <summary>
+ Pops all the logging events from the buffer into an array.
+ </summary>
+ <returns>An array of all the logging events in the buffer.</returns>
+ <remarks>
+ <para>
+ Get all the events in the buffer and clear the buffer.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.CyclicBuffer.Clear">
+ <summary>
+ Clear the buffer
+ </summary>
+ <remarks>
+ <para>
+ Clear the buffer of all events. The events in the buffer are lost.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.CyclicBuffer.Item(System.Int32)">
+ <summary>
+ Gets the <paramref name="i"/>th oldest event currently in the buffer.
+ </summary>
+ <value>The <paramref name="i"/>th oldest event currently in the buffer.</value>
+ <remarks>
+ <para>
+ If <paramref name="i"/> is outside the range 0 to the number of events
+ currently in the buffer, then <c>null</c> is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.CyclicBuffer.MaxSize">
+ <summary>
+ Gets the maximum size of the buffer.
+ </summary>
+ <value>The maximum size of the buffer.</value>
+ <remarks>
+ <para>
+ Gets the maximum size of the buffer
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.CyclicBuffer.Length">
+ <summary>
+ Gets the number of logging events in the buffer.
+ </summary>
+ <value>The number of logging events in the buffer.</value>
+ <remarks>
+ <para>
+ This number is guaranteed to be in the range 0 to <see cref="P:log4net.Util.CyclicBuffer.MaxSize"/>
+ (inclusive).
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.EmptyCollection">
+ <summary>
+ An always empty <see cref="T:System.Collections.ICollection"/>.
+ </summary>
+ <remarks>
+ <para>
+ A singleton implementation of the <see cref="T:System.Collections.ICollection"/>
+ interface that always represents an empty collection.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Util.EmptyCollection.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Util.EmptyCollection"/> class.
+ </summary>
+ <remarks>
+ <para>
+ Uses a private access modifier to enforce the singleton pattern.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.EmptyCollection.CopyTo(System.Array,System.Int32)">
+ <summary>
+ Copies the elements of the <see cref="T:System.Collections.ICollection"/> to an
+ <see cref="T:System.Array"/>, starting at a particular Array index.
+ </summary>
+ <param name="array">The one-dimensional <see cref="T:System.Array"/>
+ that is the destination of the elements copied from
+ <see cref="T:System.Collections.ICollection"/>. The Array must have zero-based
+ indexing.</param>
+ <param name="index">The zero-based index in array at which
+ copying begins.</param>
+ <remarks>
+ <para>
+ As the collection is empty no values are copied into the array.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.EmptyCollection.GetEnumerator">
+ <summary>
+ Returns an enumerator that can iterate through a collection.
+ </summary>
+ <returns>
+ An <see cref="T:System.Collections.IEnumerator"/> that can be used to
+ iterate through the collection.
+ </returns>
+ <remarks>
+ <para>
+ As the collection is empty a <see cref="T:log4net.Util.NullEnumerator"/> is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Util.EmptyCollection.s_instance">
+ <summary>
+ The singleton instance of the empty collection.
+ </summary>
+ </member>
+ <member name="P:log4net.Util.EmptyCollection.Instance">
+ <summary>
+ Gets the singleton instance of the empty collection.
+ </summary>
+ <returns>The singleton instance of the empty collection.</returns>
+ <remarks>
+ <para>
+ Gets the singleton instance of the empty collection.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.EmptyCollection.IsSynchronized">
+ <summary>
+ Gets a value indicating if access to the <see cref="T:System.Collections.ICollection"/> is synchronized (thread-safe).
+ </summary>
+ <value>
+ <b>true</b> if access to the <see cref="T:System.Collections.ICollection"/> is synchronized (thread-safe); otherwise, <b>false</b>.
+ </value>
+ <remarks>
+ <para>
+ For the <see cref="T:log4net.Util.EmptyCollection"/> this property is always <c>true</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.EmptyCollection.Count">
+ <summary>
+ Gets the number of elements contained in the <see cref="T:System.Collections.ICollection"/>.
+ </summary>
+ <value>
+ The number of elements contained in the <see cref="T:System.Collections.ICollection"/>.
+ </value>
+ <remarks>
+ <para>
+ As the collection is empty the <see cref="P:log4net.Util.EmptyCollection.Count"/> is always <c>0</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.EmptyCollection.SyncRoot">
+ <summary>
+ Gets an object that can be used to synchronize access to the <see cref="T:System.Collections.ICollection"/>.
+ </summary>
+ <value>
+ An object that can be used to synchronize access to the <see cref="T:System.Collections.ICollection"/>.
+ </value>
+ <remarks>
+ <para>
+ As the collection is empty and thread safe and synchronized this instance is also
+ the <see cref="P:log4net.Util.EmptyCollection.SyncRoot"/> object.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.EmptyDictionary">
+ <summary>
+ An always empty <see cref="T:System.Collections.IDictionary"/>.
+ </summary>
+ <remarks>
+ <para>
+ A singleton implementation of the <see cref="T:System.Collections.IDictionary"/>
+ interface that always represents an empty collection.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Util.EmptyDictionary.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Util.EmptyDictionary"/> class.
+ </summary>
+ <remarks>
+ <para>
+ Uses a private access modifier to enforce the singleton pattern.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.EmptyDictionary.CopyTo(System.Array,System.Int32)">
+ <summary>
+ Copies the elements of the <see cref="T:System.Collections.ICollection"/> to an
+ <see cref="T:System.Array"/>, starting at a particular Array index.
+ </summary>
+ <param name="array">The one-dimensional <see cref="T:System.Array"/>
+ that is the destination of the elements copied from
+ <see cref="T:System.Collections.ICollection"/>. The Array must have zero-based
+ indexing.</param>
+ <param name="index">The zero-based index in array at which
+ copying begins.</param>
+ <remarks>
+ <para>
+ As the collection is empty no values are copied into the array.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.EmptyDictionary.System#Collections#IEnumerable#GetEnumerator">
+ <summary>
+ Returns an enumerator that can iterate through a collection.
+ </summary>
+ <returns>
+ An <see cref="T:System.Collections.IEnumerator"/> that can be used to
+ iterate through the collection.
+ </returns>
+ <remarks>
+ <para>
+ As the collection is empty a <see cref="T:log4net.Util.NullEnumerator"/> is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.EmptyDictionary.Add(System.Object,System.Object)">
+ <summary>
+ Adds an element with the provided key and value to the
+ <see cref="T:log4net.Util.EmptyDictionary"/>.
+ </summary>
+ <param name="key">The <see cref="T:System.Object"/> to use as the key of the element to add.</param>
+ <param name="value">The <see cref="T:System.Object"/> to use as the value of the element to add.</param>
+ <remarks>
+ <para>
+ As the collection is empty no new values can be added. A <see cref="T:System.InvalidOperationException"/>
+ is thrown if this method is called.
+ </para>
+ </remarks>
+ <exception cref="T:System.InvalidOperationException">This dictionary is always empty and cannot be modified.</exception>
+ </member>
+ <member name="M:log4net.Util.EmptyDictionary.Clear">
+ <summary>
+ Removes all elements from the <see cref="T:log4net.Util.EmptyDictionary"/>.
+ </summary>
+ <remarks>
+ <para>
+ As the collection is empty no values can be removed. A <see cref="T:System.InvalidOperationException"/>
+ is thrown if this method is called.
+ </para>
+ </remarks>
+ <exception cref="T:System.InvalidOperationException">This dictionary is always empty and cannot be modified.</exception>
+ </member>
+ <member name="M:log4net.Util.EmptyDictionary.Contains(System.Object)">
+ <summary>
+ Determines whether the <see cref="T:log4net.Util.EmptyDictionary"/> contains an element
+ with the specified key.
+ </summary>
+ <param name="key">The key to locate in the <see cref="T:log4net.Util.EmptyDictionary"/>.</param>
+ <returns><c>false</c></returns>
+ <remarks>
+ <para>
+ As the collection is empty the <see cref="M:log4net.Util.EmptyDictionary.Contains(System.Object)"/> method always returns <c>false</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.EmptyDictionary.GetEnumerator">
+ <summary>
+ Returns an enumerator that can iterate through a collection.
+ </summary>
+ <returns>
+ An <see cref="T:System.Collections.IEnumerator"/> that can be used to
+ iterate through the collection.
+ </returns>
+ <remarks>
+ <para>
+ As the collection is empty a <see cref="T:log4net.Util.NullEnumerator"/> is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.EmptyDictionary.Remove(System.Object)">
+ <summary>
+ Removes the element with the specified key from the <see cref="T:log4net.Util.EmptyDictionary"/>.
+ </summary>
+ <param name="key">The key of the element to remove.</param>
+ <remarks>
+ <para>
+ As the collection is empty no values can be removed. A <see cref="T:System.InvalidOperationException"/>
+ is thrown if this method is called.
+ </para>
+ </remarks>
+ <exception cref="T:System.InvalidOperationException">This dictionary is always empty and cannot be modified.</exception>
+ </member>
+ <member name="F:log4net.Util.EmptyDictionary.s_instance">
+ <summary>
+ The singleton instance of the empty dictionary.
+ </summary>
+ </member>
+ <member name="P:log4net.Util.EmptyDictionary.Instance">
+ <summary>
+ Gets the singleton instance of the <see cref="T:log4net.Util.EmptyDictionary"/>.
+ </summary>
+ <returns>The singleton instance of the <see cref="T:log4net.Util.EmptyDictionary"/>.</returns>
+ <remarks>
+ <para>
+ Gets the singleton instance of the <see cref="T:log4net.Util.EmptyDictionary"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.EmptyDictionary.IsSynchronized">
+ <summary>
+ Gets a value indicating if access to the <see cref="T:System.Collections.ICollection"/> is synchronized (thread-safe).
+ </summary>
+ <value>
+ <b>true</b> if access to the <see cref="T:System.Collections.ICollection"/> is synchronized (thread-safe); otherwise, <b>false</b>.
+ </value>
+ <remarks>
+ <para>
+ For the <see cref="T:log4net.Util.EmptyCollection"/> this property is always <b>true</b>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.EmptyDictionary.Count">
+ <summary>
+ Gets the number of elements contained in the <see cref="T:System.Collections.ICollection"/>
+ </summary>
+ <value>
+ The number of elements contained in the <see cref="T:System.Collections.ICollection"/>.
+ </value>
+ <remarks>
+ <para>
+ As the collection is empty the <see cref="P:log4net.Util.EmptyDictionary.Count"/> is always <c>0</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.EmptyDictionary.SyncRoot">
+ <summary>
+ Gets an object that can be used to synchronize access to the <see cref="T:System.Collections.ICollection"/>.
+ </summary>
+ <value>
+ An object that can be used to synchronize access to the <see cref="T:System.Collections.ICollection"/>.
+ </value>
+ <remarks>
+ <para>
+ As the collection is empty and thread safe and synchronized this instance is also
+ the <see cref="P:log4net.Util.EmptyDictionary.SyncRoot"/> object.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.EmptyDictionary.IsFixedSize">
+ <summary>
+ Gets a value indicating whether the <see cref="T:log4net.Util.EmptyDictionary"/> has a fixed size.
+ </summary>
+ <value><c>true</c></value>
+ <remarks>
+ <para>
+ As the collection is empty <see cref="P:log4net.Util.EmptyDictionary.IsFixedSize"/> always returns <c>true</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.EmptyDictionary.IsReadOnly">
+ <summary>
+ Gets a value indicating whether the <see cref="T:log4net.Util.EmptyDictionary"/> is read-only.
+ </summary>
+ <value><c>true</c></value>
+ <remarks>
+ <para>
+ As the collection is empty <see cref="P:log4net.Util.EmptyDictionary.IsReadOnly"/> always returns <c>true</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.EmptyDictionary.Keys">
+ <summary>
+ Gets an <see cref="T:System.Collections.ICollection"/> containing the keys of the <see cref="T:log4net.Util.EmptyDictionary"/>.
+ </summary>
+ <value>An <see cref="T:System.Collections.ICollection"/> containing the keys of the <see cref="T:log4net.Util.EmptyDictionary"/>.</value>
+ <remarks>
+ <para>
+ As the collection is empty a <see cref="T:log4net.Util.EmptyCollection"/> is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.EmptyDictionary.Values">
+ <summary>
+ Gets an <see cref="T:System.Collections.ICollection"/> containing the values of the <see cref="T:log4net.Util.EmptyDictionary"/>.
+ </summary>
+ <value>An <see cref="T:System.Collections.ICollection"/> containing the values of the <see cref="T:log4net.Util.EmptyDictionary"/>.</value>
+ <remarks>
+ <para>
+ As the collection is empty a <see cref="T:log4net.Util.EmptyCollection"/> is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.EmptyDictionary.Item(System.Object)">
+ <summary>
+ Gets or sets the element with the specified key.
+ </summary>
+ <param name="key">The key of the element to get or set.</param>
+ <value><c>null</c></value>
+ <remarks>
+ <para>
+ As the collection is empty no values can be looked up or stored.
+ If the index getter is called then <c>null</c> is returned.
+ A <see cref="T:System.InvalidOperationException"/> is thrown if the setter is called.
+ </para>
+ </remarks>
+ <exception cref="T:System.InvalidOperationException">This dictionary is always empty and cannot be modified.</exception>
+ </member>
+ <member name="T:log4net.Util.FormattingInfo">
+ <summary>
+ Contain the information obtained when parsing formatting modifiers
+ in conversion modifiers.
+ </summary>
+ <remarks>
+ <para>
+ Holds the formatting information extracted from the format string by
+ the <see cref="T:log4net.Util.PatternParser"/>. This is used by the <see cref="T:log4net.Util.PatternConverter"/>
+ objects when rendering the output.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Util.FormattingInfo.#ctor">
+ <summary>
+ Defaut Constructor
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.FormattingInfo"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.FormattingInfo.#ctor(System.Int32,System.Int32,System.Boolean)">
+ <summary>
+ Constructor
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.FormattingInfo"/> class
+ with the specified parameters.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.FormattingInfo.Min">
+ <summary>
+ Gets or sets the minimum value.
+ </summary>
+ <value>
+ The minimum value.
+ </value>
+ <remarks>
+ <para>
+ Gets or sets the minimum value.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.FormattingInfo.Max">
+ <summary>
+ Gets or sets the maximum value.
+ </summary>
+ <value>
+ The maximum value.
+ </value>
+ <remarks>
+ <para>
+ Gets or sets the maximum value.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.FormattingInfo.LeftAlign">
+ <summary>
+ Gets or sets a flag indicating whether left align is enabled
+ or not.
+ </summary>
+ <value>
+ A flag indicating whether left align is enabled or not.
+ </value>
+ <remarks>
+ <para>
+ Gets or sets a flag indicating whether left align is enabled or not.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.GlobalContextProperties">
+ <summary>
+ Implementation of Properties collection for the <see cref="T:log4net.GlobalContext"/>
+ </summary>
+ <remarks>
+ <para>
+ This class implements a properties collection that is thread safe and supports both
+ storing properties and capturing a read only copy of the current propertied.
+ </para>
+ <para>
+ This class is optimized to the scenario where the properties are read frequently
+ and are modified infrequently.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="F:log4net.Util.GlobalContextProperties.m_readOnlyProperties">
+ <summary>
+ The read only copy of the properties.
+ </summary>
+ <remarks>
+ <para>
+ This variable is declared <c>volatile</c> to prevent the compiler and JIT from
+ reordering reads and writes of this thread performed on different threads.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Util.GlobalContextProperties.m_syncRoot">
+ <summary>
+ Lock object used to synchronize updates within this instance
+ </summary>
+ </member>
+ <member name="M:log4net.Util.GlobalContextProperties.#ctor">
+ <summary>
+ Constructor
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.GlobalContextProperties"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.GlobalContextProperties.Remove(System.String)">
+ <summary>
+ Remove a property from the global context
+ </summary>
+ <param name="key">the key for the entry to remove</param>
+ <remarks>
+ <para>
+ Removing an entry from the global context properties is relatively expensive compared
+ with reading a value.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.GlobalContextProperties.Clear">
+ <summary>
+ Clear the global context properties
+ </summary>
+ </member>
+ <member name="M:log4net.Util.GlobalContextProperties.GetReadOnlyProperties">
+ <summary>
+ Get a readonly immutable copy of the properties
+ </summary>
+ <returns>the current global context properties</returns>
+ <remarks>
+ <para>
+ This implementation is fast because the GlobalContextProperties class
+ stores a readonly copy of the properties.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.GlobalContextProperties.Item(System.String)">
+ <summary>
+ Gets or sets the value of a property
+ </summary>
+ <value>
+ The value for the property with the specified key
+ </value>
+ <remarks>
+ <para>
+ Reading the value for a key is faster than setting the value.
+ When the value is written a new read only copy of
+ the properties is created.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.LevelMapping">
+ <summary>
+ Manages a mapping from levels to <see cref="T:log4net.Util.LevelMappingEntry"/>
+ </summary>
+ <remarks>
+ <para>
+ Manages an ordered mapping from <see cref="T:log4net.Core.Level"/> instances
+ to <see cref="T:log4net.Util.LevelMappingEntry"/> subclasses.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.LevelMapping.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ <remarks>
+ <para>
+ Initialise a new instance of <see cref="T:log4net.Util.LevelMapping"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.LevelMapping.Add(log4net.Util.LevelMappingEntry)">
+ <summary>
+ Add a <see cref="T:log4net.Util.LevelMappingEntry"/> to this mapping
+ </summary>
+ <param name="entry">the entry to add</param>
+ <remarks>
+ <para>
+ If a <see cref="T:log4net.Util.LevelMappingEntry"/> has previously been added
+ for the same <see cref="T:log4net.Core.Level"/> then that entry will be
+ overwritten.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.LevelMapping.Lookup(log4net.Core.Level)">
+ <summary>
+ Lookup the mapping for the specified level
+ </summary>
+ <param name="level">the level to lookup</param>
+ <returns>the <see cref="T:log4net.Util.LevelMappingEntry"/> for the level or <c>null</c> if no mapping found</returns>
+ <remarks>
+ <para>
+ Lookup the value for the specified level. Finds the nearest
+ mapping value for the level that is equal to or less than the
+ <paramref name="level"/> specified.
+ </para>
+ <para>
+ If no mapping could be found then <c>null</c> is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.LevelMapping.ActivateOptions">
+ <summary>
+ Initialize options
+ </summary>
+ <remarks>
+ <para>
+ Caches the sorted list of <see cref="T:log4net.Util.LevelMappingEntry"/> in an array
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.LogicalThreadContextProperties">
+ <summary>
+ Implementation of Properties collection for the <see cref="T:log4net.LogicalThreadContext"/>
+ </summary>
+ <remarks>
+ <para>
+ Class implements a collection of properties that is specific to each thread.
+ The class is not synchronized as each thread has its own <see cref="T:log4net.Util.PropertiesDictionary"/>.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.LogicalThreadContextProperties.#ctor">
+ <summary>
+ Constructor
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.LogicalThreadContextProperties"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.LogicalThreadContextProperties.Remove(System.String)">
+ <summary>
+ Remove a property
+ </summary>
+ <param name="key">the key for the entry to remove</param>
+ <remarks>
+ <para>
+ Remove the value for the specified <paramref name="key"/> from the context.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.LogicalThreadContextProperties.Clear">
+ <summary>
+ Clear all the context properties
+ </summary>
+ <remarks>
+ <para>
+ Clear all the context properties
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.LogicalThreadContextProperties.GetProperties(System.Boolean)">
+ <summary>
+ Get the PropertiesDictionary stored in the LocalDataStoreSlot for this thread.
+ </summary>
+ <param name="create">create the dictionary if it does not exist, otherwise return null if is does not exist</param>
+ <returns>the properties for this thread</returns>
+ <remarks>
+ <para>
+ The collection returned is only to be used on the calling thread. If the
+ caller needs to share the collection between different threads then the
+ caller must clone the collection before doings so.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.LogicalThreadContextProperties.Item(System.String)">
+ <summary>
+ Gets or sets the value of a property
+ </summary>
+ <value>
+ The value for the property with the specified key
+ </value>
+ <remarks>
+ <para>
+ Get or set the property value for the <paramref name="key"/> specified.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.LogLog">
+ <summary>
+ Outputs log statements from within the log4net assembly.
+ </summary>
+ <remarks>
+ <para>
+ Log4net components cannot make log4net logging calls. However, it is
+ sometimes useful for the user to learn about what log4net is
+ doing.
+ </para>
+ <para>
+ All log4net internal debug calls go to the standard output stream
+ whereas internal error messages are sent to the standard error output
+ stream.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Util.LogLog.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Util.LogLog"/> class.
+ </summary>
+ <remarks>
+ <para>
+ Uses a private access modifier to prevent instantiation of this class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.LogLog.#cctor">
+ <summary>
+ Static constructor that initializes logging by reading
+ settings from the application configuration file.
+ </summary>
+ <remarks>
+ <para>
+ The <c>log4net.Internal.Debug</c> application setting
+ controls internal debugging. This setting should be set
+ to <c>true</c> to enable debugging.
+ </para>
+ <para>
+ The <c>log4net.Internal.Quiet</c> application setting
+ suppresses all internal logging including error messages.
+ This setting should be set to <c>true</c> to enable message
+ suppression.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.LogLog.Debug(System.String)">
+ <summary>
+ Writes log4net internal debug messages to the
+ standard output stream.
+ </summary>
+ <param name="message">The message to log.</param>
+ <remarks>
+ <para>
+ All internal debug messages are prepended with
+ the string "log4net: ".
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.LogLog.Debug(System.String,System.Exception)">
+ <summary>
+ Writes log4net internal debug messages to the
+ standard output stream.
+ </summary>
+ <param name="message">The message to log.</param>
+ <param name="exception">An exception to log.</param>
+ <remarks>
+ <para>
+ All internal debug messages are prepended with
+ the string "log4net: ".
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.LogLog.Warn(System.String)">
+ <summary>
+ Writes log4net internal warning messages to the
+ standard error stream.
+ </summary>
+ <param name="message">The message to log.</param>
+ <remarks>
+ <para>
+ All internal warning messages are prepended with
+ the string "log4net:WARN ".
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.LogLog.Warn(System.String,System.Exception)">
+ <summary>
+ Writes log4net internal warning messages to the
+ standard error stream.
+ </summary>
+ <param name="message">The message to log.</param>
+ <param name="exception">An exception to log.</param>
+ <remarks>
+ <para>
+ All internal warning messages are prepended with
+ the string "log4net:WARN ".
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.LogLog.Error(System.String)">
+ <summary>
+ Writes log4net internal error messages to the
+ standard error stream.
+ </summary>
+ <param name="message">The message to log.</param>
+ <remarks>
+ <para>
+ All internal error messages are prepended with
+ the string "log4net:ERROR ".
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.LogLog.Error(System.String,System.Exception)">
+ <summary>
+ Writes log4net internal error messages to the
+ standard error stream.
+ </summary>
+ <param name="message">The message to log.</param>
+ <param name="exception">An exception to log.</param>
+ <remarks>
+ <para>
+ All internal debug messages are prepended with
+ the string "log4net:ERROR ".
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.LogLog.EmitOutLine(System.String)">
+ <summary>
+ Writes output to the standard output stream.
+ </summary>
+ <param name="message">The message to log.</param>
+ <remarks>
+ <para>
+ Writes to both Console.Out and System.Diagnostics.Trace.
+ Note that the System.Diagnostics.Trace is not supported
+ on the Compact Framework.
+ </para>
+ <para>
+ If the AppDomain is not configured with a config file then
+ the call to System.Diagnostics.Trace may fail. This is only
+ an issue if you are programmatically creating your own AppDomains.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.LogLog.EmitErrorLine(System.String)">
+ <summary>
+ Writes output to the standard error stream.
+ </summary>
+ <param name="message">The message to log.</param>
+ <remarks>
+ <para>
+ Writes to both Console.Error and System.Diagnostics.Trace.
+ Note that the System.Diagnostics.Trace is not supported
+ on the Compact Framework.
+ </para>
+ <para>
+ If the AppDomain is not configured with a config file then
+ the call to System.Diagnostics.Trace may fail. This is only
+ an issue if you are programmatically creating your own AppDomains.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Util.LogLog.s_debugEnabled">
+ <summary>
+ Default debug level
+ </summary>
+ </member>
+ <member name="F:log4net.Util.LogLog.s_quietMode">
+ <summary>
+ In quietMode not even errors generate any output.
+ </summary>
+ </member>
+ <member name="P:log4net.Util.LogLog.InternalDebugging">
+ <summary>
+ Gets or sets a value indicating whether log4net internal logging
+ is enabled or disabled.
+ </summary>
+ <value>
+ <c>true</c> if log4net internal logging is enabled, otherwise
+ <c>false</c>.
+ </value>
+ <remarks>
+ <para>
+ When set to <c>true</c>, internal debug level logging will be
+ displayed.
+ </para>
+ <para>
+ This value can be set by setting the application setting
+ <c>log4net.Internal.Debug</c> in the application configuration
+ file.
+ </para>
+ <para>
+ The default value is <c>false</c>, i.e. debugging is
+ disabled.
+ </para>
+ </remarks>
+ <example>
+ <para>
+ The following example enables internal debugging using the
+ application configuration file :
+ </para>
+ <code lang="XML" escaped="true">
+ <configuration>
+ <appSettings>
+ <add key="log4net.Internal.Debug" value="true" />
+ </appSettings>
+ </configuration>
+ </code>
+ </example>
+ </member>
+ <member name="P:log4net.Util.LogLog.QuietMode">
+ <summary>
+ Gets or sets a value indicating whether log4net should generate no output
+ from internal logging, not even for errors.
+ </summary>
+ <value>
+ <c>true</c> if log4net should generate no output at all from internal
+ logging, otherwise <c>false</c>.
+ </value>
+ <remarks>
+ <para>
+ When set to <c>true</c> will cause internal logging at all levels to be
+ suppressed. This means that no warning or error reports will be logged.
+ This option overrides the <see cref="P:log4net.Util.LogLog.InternalDebugging"/> setting and
+ disables all debug also.
+ </para>
+ <para>This value can be set by setting the application setting
+ <c>log4net.Internal.Quiet</c> in the application configuration file.
+ </para>
+ <para>
+ The default value is <c>false</c>, i.e. internal logging is not
+ disabled.
+ </para>
+ </remarks>
+ <example>
+ The following example disables internal logging using the
+ application configuration file :
+ <code lang="XML" escaped="true">
+ <configuration>
+ <appSettings>
+ <add key="log4net.Internal.Quiet" value="true"/>
+ </appSettings>
+ </configuration>
+ </code>
+ </example>
+ </member>
+ <member name="P:log4net.Util.LogLog.IsDebugEnabled">
+ <summary>
+ Test if LogLog.Debug is enabled for output.
+ </summary>
+ <value>
+ <c>true</c> if Debug is enabled
+ </value>
+ <remarks>
+ <para>
+ Test if LogLog.Debug is enabled for output.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.LogLog.IsWarnEnabled">
+ <summary>
+ Test if LogLog.Warn is enabled for output.
+ </summary>
+ <value>
+ <c>true</c> if Warn is enabled
+ </value>
+ <remarks>
+ <para>
+ Test if LogLog.Warn is enabled for output.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.LogLog.IsErrorEnabled">
+ <summary>
+ Test if LogLog.Error is enabled for output.
+ </summary>
+ <value>
+ <c>true</c> if Error is enabled
+ </value>
+ <remarks>
+ <para>
+ Test if LogLog.Error is enabled for output.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.NativeError">
+ <summary>
+ Represents a native error code and message.
+ </summary>
+ <remarks>
+ <para>
+ Represents a Win32 platform native error.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Util.NativeError.#ctor(System.Int32,System.String)">
+ <summary>
+ Create an instance of the <see cref="T:log4net.Util.NativeError"/> class with the specified
+ error number and message.
+ </summary>
+ <param name="number">The number of the native error.</param>
+ <param name="message">The message of the native error.</param>
+ <remarks>
+ <para>
+ Create an instance of the <see cref="T:log4net.Util.NativeError"/> class with the specified
+ error number and message.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.NativeError.GetLastError">
+ <summary>
+ Create a new instance of the <see cref="T:log4net.Util.NativeError"/> class for the last Windows error.
+ </summary>
+ <returns>
+ An instance of the <see cref="T:log4net.Util.NativeError"/> class for the last windows error.
+ </returns>
+ <remarks>
+ <para>
+ The message for the <see cref="M:System.Runtime.InteropServices.Marshal.GetLastWin32Error"/> error number is lookup up using the
+ native Win32 <c>FormatMessage</c> function.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.NativeError.GetError(System.Int32)">
+ <summary>
+ Create a new instance of the <see cref="T:log4net.Util.NativeError"/> class.
+ </summary>
+ <param name="number">the error number for the native error</param>
+ <returns>
+ An instance of the <see cref="T:log4net.Util.NativeError"/> class for the specified
+ error number.
+ </returns>
+ <remarks>
+ <para>
+ The message for the specified error number is lookup up using the
+ native Win32 <c>FormatMessage</c> function.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.NativeError.GetErrorMessage(System.Int32)">
+ <summary>
+ Retrieves the message corresponding with a Win32 message identifier.
+ </summary>
+ <param name="messageId">Message identifier for the requested message.</param>
+ <returns>
+ The message corresponding with the specified message identifier.
+ </returns>
+ <remarks>
+ <para>
+ The message will be searched for in system message-table resource(s)
+ using the native <c>FormatMessage</c> function.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.NativeError.ToString">
+ <summary>
+ Return error information string
+ </summary>
+ <returns>error information string</returns>
+ <remarks>
+ <para>
+ Return error information string
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.NativeError.FormatMessage(System.Int32,System.IntPtr@,System.Int32,System.Int32,System.String@,System.Int32,System.IntPtr)">
+ <summary>
+ Formats a message string.
+ </summary>
+ <param name="dwFlags">Formatting options, and how to interpret the <paramref name="lpSource"/> parameter.</param>
+ <param name="lpSource">Location of the message definition.</param>
+ <param name="dwMessageId">Message identifier for the requested message.</param>
+ <param name="dwLanguageId">Language identifier for the requested message.</param>
+ <param name="lpBuffer">If <paramref name="dwFlags"/> includes FORMAT_MESSAGE_ALLOCATE_BUFFER, the function allocates a buffer using the <c>LocalAlloc</c> function, and places the pointer to the buffer at the address specified in <paramref name="lpBuffer"/>.</param>
+ <param name="nSize">If the FORMAT_MESSAGE_ALLOCATE_BUFFER flag is not set, this parameter specifies the maximum number of TCHARs that can be stored in the output buffer. If FORMAT_MESSAGE_ALLOCATE_BUFFER is set, this parameter specifies the minimum number of TCHARs to allocate for an output buffer.</param>
+ <param name="Arguments">Pointer to an array of values that are used as insert values in the formatted message.</param>
+ <remarks>
+ <para>
+ The function requires a message definition as input. The message definition can come from a
+ buffer passed into the function. It can come from a message table resource in an
+ already-loaded module. Or the caller can ask the function to search the system's message
+ table resource(s) for the message definition. The function finds the message definition
+ in a message table resource based on a message identifier and a language identifier.
+ The function copies the formatted message text to an output buffer, processing any embedded
+ insert sequences if requested.
+ </para>
+ <para>
+ To prevent the usage of unsafe code, this stub does not support inserting values in the formatted message.
+ </para>
+ </remarks>
+ <returns>
+ <para>
+ If the function succeeds, the return value is the number of TCHARs stored in the output
+ buffer, excluding the terminating null character.
+ </para>
+ <para>
+ If the function fails, the return value is zero. To get extended error information,
+ call <see cref="M:System.Runtime.InteropServices.Marshal.GetLastWin32Error"/>.
+ </para>
+ </returns>
+ </member>
+ <member name="P:log4net.Util.NativeError.Number">
+ <summary>
+ Gets the number of the native error.
+ </summary>
+ <value>
+ The number of the native error.
+ </value>
+ <remarks>
+ <para>
+ Gets the number of the native error.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.NativeError.Message">
+ <summary>
+ Gets the message of the native error.
+ </summary>
+ <value>
+ The message of the native error.
+ </value>
+ <remarks>
+ <para>
+ </para>
+ Gets the message of the native error.
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.NullDictionaryEnumerator">
+ <summary>
+ An always empty <see cref="T:System.Collections.IDictionaryEnumerator"/>.
+ </summary>
+ <remarks>
+ <para>
+ A singleton implementation of the <see cref="T:System.Collections.IDictionaryEnumerator"/> over a collection
+ that is empty and not modifiable.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Util.NullDictionaryEnumerator.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Util.NullDictionaryEnumerator"/> class.
+ </summary>
+ <remarks>
+ <para>
+ Uses a private access modifier to enforce the singleton pattern.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.NullDictionaryEnumerator.MoveNext">
+ <summary>
+ Test if the enumerator can advance, if so advance.
+ </summary>
+ <returns><c>false</c> as the <see cref="T:log4net.Util.NullDictionaryEnumerator"/> cannot advance.</returns>
+ <remarks>
+ <para>
+ As the enumerator is over an empty collection its <see cref="P:log4net.Util.NullDictionaryEnumerator.Current"/>
+ value cannot be moved over a valid position, therefore <see cref="M:log4net.Util.NullDictionaryEnumerator.MoveNext"/>
+ will always return <c>false</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.NullDictionaryEnumerator.Reset">
+ <summary>
+ Resets the enumerator back to the start.
+ </summary>
+ <remarks>
+ <para>
+ As the enumerator is over an empty collection <see cref="M:log4net.Util.NullDictionaryEnumerator.Reset"/> does nothing.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Util.NullDictionaryEnumerator.s_instance">
+ <summary>
+ The singleton instance of the <see cref="T:log4net.Util.NullDictionaryEnumerator"/>.
+ </summary>
+ </member>
+ <member name="P:log4net.Util.NullDictionaryEnumerator.Instance">
+ <summary>
+ Gets the singleton instance of the <see cref="T:log4net.Util.NullDictionaryEnumerator"/>.
+ </summary>
+ <returns>The singleton instance of the <see cref="T:log4net.Util.NullDictionaryEnumerator"/>.</returns>
+ <remarks>
+ <para>
+ Gets the singleton instance of the <see cref="T:log4net.Util.NullDictionaryEnumerator"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.NullDictionaryEnumerator.Current">
+ <summary>
+ Gets the current object from the enumerator.
+ </summary>
+ <remarks>
+ Throws an <see cref="T:System.InvalidOperationException"/> because the
+ <see cref="T:log4net.Util.NullDictionaryEnumerator"/> never has a current value.
+ </remarks>
+ <remarks>
+ <para>
+ As the enumerator is over an empty collection its <see cref="P:log4net.Util.NullDictionaryEnumerator.Current"/>
+ value cannot be moved over a valid position, therefore <see cref="P:log4net.Util.NullDictionaryEnumerator.Current"/>
+ will throw an <see cref="T:System.InvalidOperationException"/>.
+ </para>
+ </remarks>
+ <exception cref="T:System.InvalidOperationException">The collection is empty and <see cref="P:log4net.Util.NullDictionaryEnumerator.Current"/>
+ cannot be positioned over a valid location.</exception>
+ </member>
+ <member name="P:log4net.Util.NullDictionaryEnumerator.Key">
+ <summary>
+ Gets the current key from the enumerator.
+ </summary>
+ <remarks>
+ Throws an exception because the <see cref="T:log4net.Util.NullDictionaryEnumerator"/>
+ never has a current value.
+ </remarks>
+ <remarks>
+ <para>
+ As the enumerator is over an empty collection its <see cref="P:log4net.Util.NullDictionaryEnumerator.Current"/>
+ value cannot be moved over a valid position, therefore <see cref="P:log4net.Util.NullDictionaryEnumerator.Key"/>
+ will throw an <see cref="T:System.InvalidOperationException"/>.
+ </para>
+ </remarks>
+ <exception cref="T:System.InvalidOperationException">The collection is empty and <see cref="P:log4net.Util.NullDictionaryEnumerator.Current"/>
+ cannot be positioned over a valid location.</exception>
+ </member>
+ <member name="P:log4net.Util.NullDictionaryEnumerator.Value">
+ <summary>
+ Gets the current value from the enumerator.
+ </summary>
+ <value>The current value from the enumerator.</value>
+ <remarks>
+ Throws an <see cref="T:System.InvalidOperationException"/> because the
+ <see cref="T:log4net.Util.NullDictionaryEnumerator"/> never has a current value.
+ </remarks>
+ <remarks>
+ <para>
+ As the enumerator is over an empty collection its <see cref="P:log4net.Util.NullDictionaryEnumerator.Current"/>
+ value cannot be moved over a valid position, therefore <see cref="P:log4net.Util.NullDictionaryEnumerator.Value"/>
+ will throw an <see cref="T:System.InvalidOperationException"/>.
+ </para>
+ </remarks>
+ <exception cref="T:System.InvalidOperationException">The collection is empty and <see cref="P:log4net.Util.NullDictionaryEnumerator.Current"/>
+ cannot be positioned over a valid location.</exception>
+ </member>
+ <member name="P:log4net.Util.NullDictionaryEnumerator.Entry">
+ <summary>
+ Gets the current entry from the enumerator.
+ </summary>
+ <remarks>
+ Throws an <see cref="T:System.InvalidOperationException"/> because the
+ <see cref="T:log4net.Util.NullDictionaryEnumerator"/> never has a current entry.
+ </remarks>
+ <remarks>
+ <para>
+ As the enumerator is over an empty collection its <see cref="P:log4net.Util.NullDictionaryEnumerator.Current"/>
+ value cannot be moved over a valid position, therefore <see cref="P:log4net.Util.NullDictionaryEnumerator.Entry"/>
+ will throw an <see cref="T:System.InvalidOperationException"/>.
+ </para>
+ </remarks>
+ <exception cref="T:System.InvalidOperationException">The collection is empty and <see cref="P:log4net.Util.NullDictionaryEnumerator.Current"/>
+ cannot be positioned over a valid location.</exception>
+ </member>
+ <member name="T:log4net.Util.NullEnumerator">
+ <summary>
+ An always empty <see cref="T:System.Collections.IEnumerator"/>.
+ </summary>
+ <remarks>
+ <para>
+ A singleton implementation of the <see cref="T:System.Collections.IEnumerator"/> over a collection
+ that is empty and not modifiable.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Util.NullEnumerator.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Util.NullEnumerator"/> class.
+ </summary>
+ <remarks>
+ <para>
+ Uses a private access modifier to enforce the singleton pattern.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.NullEnumerator.MoveNext">
+ <summary>
+ Test if the enumerator can advance, if so advance
+ </summary>
+ <returns><c>false</c> as the <see cref="T:log4net.Util.NullEnumerator"/> cannot advance.</returns>
+ <remarks>
+ <para>
+ As the enumerator is over an empty collection its <see cref="P:log4net.Util.NullEnumerator.Current"/>
+ value cannot be moved over a valid position, therefore <see cref="M:log4net.Util.NullEnumerator.MoveNext"/>
+ will always return <c>false</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.NullEnumerator.Reset">
+ <summary>
+ Resets the enumerator back to the start.
+ </summary>
+ <remarks>
+ <para>
+ As the enumerator is over an empty collection <see cref="M:log4net.Util.NullEnumerator.Reset"/> does nothing.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Util.NullEnumerator.s_instance">
+ <summary>
+ The singleton instance of the <see cref="T:log4net.Util.NullEnumerator"/>.
+ </summary>
+ </member>
+ <member name="P:log4net.Util.NullEnumerator.Instance">
+ <summary>
+ Get the singleton instance of the <see cref="T:log4net.Util.NullEnumerator"/>.
+ </summary>
+ <returns>The singleton instance of the <see cref="T:log4net.Util.NullEnumerator"/>.</returns>
+ <remarks>
+ <para>
+ Gets the singleton instance of the <see cref="T:log4net.Util.NullEnumerator"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.NullEnumerator.Current">
+ <summary>
+ Gets the current object from the enumerator.
+ </summary>
+ <remarks>
+ Throws an <see cref="T:System.InvalidOperationException"/> because the
+ <see cref="T:log4net.Util.NullDictionaryEnumerator"/> never has a current value.
+ </remarks>
+ <remarks>
+ <para>
+ As the enumerator is over an empty collection its <see cref="P:log4net.Util.NullEnumerator.Current"/>
+ value cannot be moved over a valid position, therefore <see cref="P:log4net.Util.NullEnumerator.Current"/>
+ will throw an <see cref="T:System.InvalidOperationException"/>.
+ </para>
+ </remarks>
+ <exception cref="T:System.InvalidOperationException">The collection is empty and <see cref="P:log4net.Util.NullEnumerator.Current"/>
+ cannot be positioned over a valid location.</exception>
+ </member>
+ <member name="T:log4net.Util.NullSecurityContext">
+ <summary>
+ A SecurityContext used when a SecurityContext is not required
+ </summary>
+ <remarks>
+ <para>
+ The <see cref="T:log4net.Util.NullSecurityContext"/> is a no-op implementation of the
+ <see cref="T:log4net.Core.SecurityContext"/> base class. It is used where a <see cref="T:log4net.Core.SecurityContext"/>
+ is required but one has not been provided.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="F:log4net.Util.NullSecurityContext.Instance">
+ <summary>
+ Singleton instance of <see cref="T:log4net.Util.NullSecurityContext"/>
+ </summary>
+ <remarks>
+ <para>
+ Singleton instance of <see cref="T:log4net.Util.NullSecurityContext"/>
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.NullSecurityContext.#ctor">
+ <summary>
+ Private constructor
+ </summary>
+ <remarks>
+ <para>
+ Private constructor for singleton pattern.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.NullSecurityContext.Impersonate(System.Object)">
+ <summary>
+ Impersonate this SecurityContext
+ </summary>
+ <param name="state">State supplied by the caller</param>
+ <returns><c>null</c></returns>
+ <remarks>
+ <para>
+ No impersonation is done and <c>null</c> is always returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.OnlyOnceErrorHandler">
+ <summary>
+ Implements log4net's default error handling policy which consists
+ of emitting a message for the first error in an appender and
+ ignoring all subsequent errors.
+ </summary>
+ <remarks>
+ <para>
+ The error message is printed on the standard error output stream.
+ </para>
+ <para>
+ This policy aims at protecting an otherwise working application
+ from being flooded with error messages when logging fails.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Util.OnlyOnceErrorHandler.#ctor">
+ <summary>
+ Default Constructor
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.OnlyOnceErrorHandler"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.OnlyOnceErrorHandler.#ctor(System.String)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="prefix">The prefix to use for each message.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.OnlyOnceErrorHandler"/> class
+ with the specified prefix.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.OnlyOnceErrorHandler.Error(System.String,System.Exception,log4net.Core.ErrorCode)">
+ <summary>
+ Log an Error
+ </summary>
+ <param name="message">The error message.</param>
+ <param name="e">The exception.</param>
+ <param name="errorCode">The internal error code.</param>
+ <remarks>
+ <para>
+ Prints the message and the stack trace of the exception on the standard
+ error output stream.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.OnlyOnceErrorHandler.Error(System.String,System.Exception)">
+ <summary>
+ Log an Error
+ </summary>
+ <param name="message">The error message.</param>
+ <param name="e">The exception.</param>
+ <remarks>
+ <para>
+ Prints the message and the stack trace of the exception on the standard
+ error output stream.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.OnlyOnceErrorHandler.Error(System.String)">
+ <summary>
+ Log an error
+ </summary>
+ <param name="message">The error message.</param>
+ <remarks>
+ <para>
+ Print a the error message passed as parameter on the standard
+ error output stream.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Util.OnlyOnceErrorHandler.m_firstTime">
+ <summary>
+ Flag to indicate if it is the first error
+ </summary>
+ </member>
+ <member name="F:log4net.Util.OnlyOnceErrorHandler.m_prefix">
+ <summary>
+ String to prefix each message with
+ </summary>
+ </member>
+ <member name="P:log4net.Util.OnlyOnceErrorHandler.IsEnabled">
+ <summary>
+ Is error logging enabled
+ </summary>
+ <remarks>
+ <para>
+ Is error logging enabled. Logging is only enabled for the
+ first error delivered to the <see cref="T:log4net.Util.OnlyOnceErrorHandler"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.OptionConverter">
+ <summary>
+ A convenience class to convert property values to specific types.
+ </summary>
+ <remarks>
+ <para>
+ Utility functions for converting types and parsing values.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Util.OptionConverter.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Util.OptionConverter"/> class.
+ </summary>
+ <remarks>
+ <para>
+ Uses a private access modifier to prevent instantiation of this class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.OptionConverter.ToBoolean(System.String,System.Boolean)">
+ <summary>
+ Converts a string to a <see cref="T:System.Boolean"/> value.
+ </summary>
+ <param name="argValue">String to convert.</param>
+ <param name="defaultValue">The default value.</param>
+ <returns>The <see cref="T:System.Boolean"/> value of <paramref name="argValue"/>.</returns>
+ <remarks>
+ <para>
+ If <paramref name="argValue"/> is "true", then <c>true</c> is returned.
+ If <paramref name="argValue"/> is "false", then <c>false</c> is returned.
+ Otherwise, <paramref name="defaultValue"/> is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.OptionConverter.ToFileSize(System.String,System.Int64)">
+ <summary>
+ Parses a file size into a number.
+ </summary>
+ <param name="argValue">String to parse.</param>
+ <param name="defaultValue">The default value.</param>
+ <returns>The <see cref="T:System.Int64"/> value of <paramref name="argValue"/>.</returns>
+ <remarks>
+ <para>
+ Parses a file size of the form: number[KB|MB|GB] into a
+ long value. It is scaled with the appropriate multiplier.
+ </para>
+ <para>
+ <paramref name="defaultValue"/> is returned when <paramref name="argValue"/>
+ cannot be converted to a <see cref="T:System.Int64"/> value.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.OptionConverter.ConvertStringTo(System.Type,System.String)">
+ <summary>
+ Converts a string to an object.
+ </summary>
+ <param name="target">The target type to convert to.</param>
+ <param name="txt">The string to convert to an object.</param>
+ <returns>
+ The object converted from a string or <c>null</c> when the
+ conversion failed.
+ </returns>
+ <remarks>
+ <para>
+ Converts a string to an object. Uses the converter registry to try
+ to convert the string value into the specified target type.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.OptionConverter.CanConvertTypeTo(System.Type,System.Type)">
+ <summary>
+ Checks if there is an appropriate type conversion from the source type to the target type.
+ </summary>
+ <param name="sourceType">The type to convert from.</param>
+ <param name="targetType">The type to convert to.</param>
+ <returns><c>true</c> if there is a conversion from the source type to the target type.</returns>
+ <remarks>
+ Checks if there is an appropriate type conversion from the source type to the target type.
+ <para>
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.OptionConverter.ConvertTypeTo(System.Object,System.Type)">
+ <summary>
+ Converts an object to the target type.
+ </summary>
+ <param name="sourceInstance">The object to convert to the target type.</param>
+ <param name="targetType">The type to convert to.</param>
+ <returns>The converted object.</returns>
+ <remarks>
+ <para>
+ Converts an object to the target type.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.OptionConverter.InstantiateByClassName(System.String,System.Type,System.Object)">
+ <summary>
+ Instantiates an object given a class name.
+ </summary>
+ <param name="className">The fully qualified class name of the object to instantiate.</param>
+ <param name="superClass">The class to which the new object should belong.</param>
+ <param name="defaultValue">The object to return in case of non-fulfillment.</param>
+ <returns>
+ An instance of the <paramref name="className"/> or <paramref name="defaultValue"/>
+ if the object could not be instantiated.
+ </returns>
+ <remarks>
+ <para>
+ Checks that the <paramref name="className"/> is a subclass of
+ <paramref name="superClass"/>. If that test fails or the object could
+ not be instantiated, then <paramref name="defaultValue"/> is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.OptionConverter.SubstituteVariables(System.String,System.Collections.IDictionary)">
+ <summary>
+ Performs variable substitution in string <paramref name="val"/> from the
+ values of keys found in <paramref name="props"/>.
+ </summary>
+ <param name="value">The string on which variable substitution is performed.</param>
+ <param name="props">The dictionary to use to lookup variables.</param>
+ <returns>The result of the substitutions.</returns>
+ <remarks>
+ <para>
+ The variable substitution delimiters are <b>${</b> and <b>}</b>.
+ </para>
+ <para>
+ For example, if props contains <c>key=value</c>, then the call
+ </para>
+ <para>
+ <code lang="C#">
+ string s = OptionConverter.SubstituteVariables("Value of key is ${key}.");
+ </code>
+ </para>
+ <para>
+ will set the variable <c>s</c> to "Value of key is value.".
+ </para>
+ <para>
+ If no value could be found for the specified key, then substitution
+ defaults to an empty string.
+ </para>
+ <para>
+ For example, if system properties contains no value for the key
+ "nonExistentKey", then the call
+ </para>
+ <para>
+ <code lang="C#">
+ string s = OptionConverter.SubstituteVariables("Value of nonExistentKey is [${nonExistentKey}]");
+ </code>
+ </para>
+ <para>
+ will set <s>s</s> to "Value of nonExistentKey is []".
+ </para>
+ <para>
+ An Exception is thrown if <paramref name="value"/> contains a start
+ delimiter "${" which is not balanced by a stop delimiter "}".
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.OptionConverter.ParseEnum(System.Type,System.String,System.Boolean)">
+ <summary>
+ Converts the string representation of the name or numeric value of one or
+ more enumerated constants to an equivalent enumerated object.
+ </summary>
+ <param name="enumType">The type to convert to.</param>
+ <param name="value">The enum string value.</param>
+ <param name="ignoreCase">If <c>true</c>, ignore case; otherwise, regard case.</param>
+ <returns>An object of type <paramref name="enumType" /> whose value is represented by <paramref name="value" />.</returns>
+ </member>
+ <member name="T:log4net.Util.PatternParser">
+ <summary>
+ Most of the work of the <see cref="T:log4net.Layout.PatternLayout"/> class
+ is delegated to the PatternParser class.
+ </summary>
+ <remarks>
+ <para>
+ The <c>PatternParser</c> processes a pattern string and
+ returns a chain of <see cref="T:log4net.Util.PatternConverter"/> objects.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Util.PatternParser.#ctor(System.String)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="pattern">The pattern to parse.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.PatternParser"/> class
+ with the specified pattern string.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternParser.Parse">
+ <summary>
+ Parses the pattern into a chain of pattern converters.
+ </summary>
+ <returns>The head of a chain of pattern converters.</returns>
+ <remarks>
+ <para>
+ Parses the pattern into a chain of pattern converters.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternParser.BuildCache">
+ <summary>
+ Build the unified cache of converters from the static and instance maps
+ </summary>
+ <returns>the list of all the converter names</returns>
+ <remarks>
+ <para>
+ Build the unified cache of converters from the static and instance maps
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternParser.ParseInternal(System.String,System.String[])">
+ <summary>
+ Internal method to parse the specified pattern to find specified matches
+ </summary>
+ <param name="pattern">the pattern to parse</param>
+ <param name="matches">the converter names to match in the pattern</param>
+ <remarks>
+ <para>
+ The matches param must be sorted such that longer strings come before shorter ones.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternParser.ProcessLiteral(System.String)">
+ <summary>
+ Process a parsed literal
+ </summary>
+ <param name="text">the literal text</param>
+ </member>
+ <member name="M:log4net.Util.PatternParser.ProcessConverter(System.String,System.String,log4net.Util.FormattingInfo)">
+ <summary>
+ Process a parsed converter pattern
+ </summary>
+ <param name="converterName">the name of the converter</param>
+ <param name="option">the optional option for the converter</param>
+ <param name="formattingInfo">the formatting info for the converter</param>
+ </member>
+ <member name="M:log4net.Util.PatternParser.AddConverter(log4net.Util.PatternConverter)">
+ <summary>
+ Resets the internal state of the parser and adds the specified pattern converter
+ to the chain.
+ </summary>
+ <param name="pc">The pattern converter to add.</param>
+ </member>
+ <member name="F:log4net.Util.PatternParser.m_head">
+ <summary>
+ The first pattern converter in the chain
+ </summary>
+ </member>
+ <member name="F:log4net.Util.PatternParser.m_tail">
+ <summary>
+ the last pattern converter in the chain
+ </summary>
+ </member>
+ <member name="F:log4net.Util.PatternParser.m_pattern">
+ <summary>
+ The pattern
+ </summary>
+ </member>
+ <member name="F:log4net.Util.PatternParser.m_patternConverters">
+ <summary>
+ Internal map of converter identifiers to converter types
+ </summary>
+ <remarks>
+ <para>
+ This map overrides the static s_globalRulesRegistry map.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.PatternParser.PatternConverters">
+ <summary>
+ Get the converter registry used by this parser
+ </summary>
+ <value>
+ The converter registry used by this parser
+ </value>
+ <remarks>
+ <para>
+ Get the converter registry used by this parser
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.PatternParser.StringLengthComparer">
+ <summary>
+ Sort strings by length
+ </summary>
+ <remarks>
+ <para>
+ <see cref="T:System.Collections.IComparer"/> that orders strings by string length.
+ The longest strings are placed first
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.PatternString">
+ <summary>
+ This class implements a patterned string.
+ </summary>
+ <remarks>
+ <para>
+ This string has embedded patterns that are resolved and expanded
+ when the string is formatted.
+ </para>
+ <para>
+ This class functions similarly to the <see cref="T:log4net.Layout.PatternLayout"/>
+ in that it accepts a pattern and renders it to a string. Unlike the
+ <see cref="T:log4net.Layout.PatternLayout"/> however the <c>PatternString</c>
+ does not render the properties of a specific <see cref="T:log4net.Core.LoggingEvent"/> but
+ of the process in general.
+ </para>
+ <para>
+ The recognized conversion pattern names are:
+ </para>
+ <list type="table">
+ <listheader>
+ <term>Conversion Pattern Name</term>
+ <description>Effect</description>
+ </listheader>
+ <item>
+ <term>appdomain</term>
+ <description>
+ <para>
+ Used to output the friendly name of the current AppDomain.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>date</term>
+ <description>
+ <para>
+ Used to output the date of the logging event in the local time zone.
+ To output the date in universal time use the <c>%utcdate</c> pattern.
+ The date conversion
+ specifier may be followed by a <i>date format specifier</i> enclosed
+ between braces. For example, <b>%date{HH:mm:ss,fff}</b> or
+ <b>%date{dd MMM yyyy HH:mm:ss,fff}</b>. If no date format specifier is
+ given then ISO8601 format is
+ assumed (<see cref="T:log4net.DateFormatter.Iso8601DateFormatter"/>).
+ </para>
+ <para>
+ The date format specifier admits the same syntax as the
+ time pattern string of the <see cref="M:System.DateTime.ToString(System.String)"/>.
+ </para>
+ <para>
+ For better results it is recommended to use the log4net date
+ formatters. These can be specified using one of the strings
+ "ABSOLUTE", "DATE" and "ISO8601" for specifying
+ <see cref="T:log4net.DateFormatter.AbsoluteTimeDateFormatter"/>,
+ <see cref="T:log4net.DateFormatter.DateTimeDateFormatter"/> and respectively
+ <see cref="T:log4net.DateFormatter.Iso8601DateFormatter"/>. For example,
+ <b>%date{ISO8601}</b> or <b>%date{ABSOLUTE}</b>.
+ </para>
+ <para>
+ These dedicated date formatters perform significantly
+ better than <see cref="M:System.DateTime.ToString(System.String)"/>.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>env</term>
+ <description>
+ <para>
+ Used to output the a specific environment variable. The key to
+ lookup must be specified within braces and directly following the
+ pattern specifier, e.g. <b>%env{COMPUTERNAME}</b> would include the value
+ of the <c>COMPUTERNAME</c> environment variable.
+ </para>
+ <para>
+ The <c>env</c> pattern is not supported on the .NET Compact Framework.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>identity</term>
+ <description>
+ <para>
+ Used to output the user name for the currently active user
+ (Principal.Identity.Name).
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>newline</term>
+ <description>
+ <para>
+ Outputs the platform dependent line separator character or
+ characters.
+ </para>
+ <para>
+ This conversion pattern name offers the same performance as using
+ non-portable line separator strings such as "\n", or "\r\n".
+ Thus, it is the preferred way of specifying a line separator.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>processid</term>
+ <description>
+ <para>
+ Used to output the system process ID for the current process.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>property</term>
+ <description>
+ <para>
+ Used to output a specific context property. The key to
+ lookup must be specified within braces and directly following the
+ pattern specifier, e.g. <b>%property{user}</b> would include the value
+ from the property that is keyed by the string 'user'. Each property value
+ that is to be included in the log must be specified separately.
+ Properties are stored in logging contexts. By default
+ the <c>log4net:HostName</c> property is set to the name of machine on
+ which the event was originally logged.
+ </para>
+ <para>
+ If no key is specified, e.g. <b>%property</b> then all the keys and their
+ values are printed in a comma separated list.
+ </para>
+ <para>
+ The properties of an event are combined from a number of different
+ contexts. These are listed below in the order in which they are searched.
+ </para>
+ <list type="definition">
+ <item>
+ <term>the thread properties</term>
+ <description>
+ The <see cref="P:log4net.ThreadContext.Properties"/> that are set on the current
+ thread. These properties are shared by all events logged on this thread.
+ </description>
+ </item>
+ <item>
+ <term>the global properties</term>
+ <description>
+ The <see cref="P:log4net.GlobalContext.Properties"/> that are set globally. These
+ properties are shared by all the threads in the AppDomain.
+ </description>
+ </item>
+ </list>
+ </description>
+ </item>
+ <item>
+ <term>random</term>
+ <description>
+ <para>
+ Used to output a random string of characters. The string is made up of
+ uppercase letters and numbers. By default the string is 4 characters long.
+ The length of the string can be specified within braces directly following the
+ pattern specifier, e.g. <b>%random{8}</b> would output an 8 character string.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>username</term>
+ <description>
+ <para>
+ Used to output the WindowsIdentity for the currently
+ active user.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>utcdate</term>
+ <description>
+ <para>
+ Used to output the date of the logging event in universal time.
+ The date conversion
+ specifier may be followed by a <i>date format specifier</i> enclosed
+ between braces. For example, <b>%utcdate{HH:mm:ss,fff}</b> or
+ <b>%utcdate{dd MMM yyyy HH:mm:ss,fff}</b>. If no date format specifier is
+ given then ISO8601 format is
+ assumed (<see cref="T:log4net.DateFormatter.Iso8601DateFormatter"/>).
+ </para>
+ <para>
+ The date format specifier admits the same syntax as the
+ time pattern string of the <see cref="M:System.DateTime.ToString(System.String)"/>.
+ </para>
+ <para>
+ For better results it is recommended to use the log4net date
+ formatters. These can be specified using one of the strings
+ "ABSOLUTE", "DATE" and "ISO8601" for specifying
+ <see cref="T:log4net.DateFormatter.AbsoluteTimeDateFormatter"/>,
+ <see cref="T:log4net.DateFormatter.DateTimeDateFormatter"/> and respectively
+ <see cref="T:log4net.DateFormatter.Iso8601DateFormatter"/>. For example,
+ <b>%utcdate{ISO8601}</b> or <b>%utcdate{ABSOLUTE}</b>.
+ </para>
+ <para>
+ These dedicated date formatters perform significantly
+ better than <see cref="M:System.DateTime.ToString(System.String)"/>.
+ </para>
+ </description>
+ </item>
+ <item>
+ <term>%</term>
+ <description>
+ <para>
+ The sequence %% outputs a single percent sign.
+ </para>
+ </description>
+ </item>
+ </list>
+ <para>
+ Additional pattern converters may be registered with a specific <see cref="T:log4net.Util.PatternString"/>
+ instance using <see cref="M:log4net.Util.PatternString.AddConverter(log4net.Util.PatternString.ConverterInfo)"/> or
+ <see cref="M:log4net.Util.PatternString.AddConverter(System.String,System.Type)"/>.
+ </para>
+ <para>
+ See the <see cref="T:log4net.Layout.PatternLayout"/> for details on the
+ <i>format modifiers</i> supported by the patterns.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="F:log4net.Util.PatternString.s_globalRulesRegistry">
+ <summary>
+ Internal map of converter identifiers to converter types.
+ </summary>
+ </member>
+ <member name="F:log4net.Util.PatternString.m_pattern">
+ <summary>
+ the pattern
+ </summary>
+ </member>
+ <member name="F:log4net.Util.PatternString.m_head">
+ <summary>
+ the head of the pattern converter chain
+ </summary>
+ </member>
+ <member name="F:log4net.Util.PatternString.m_instanceRulesRegistry">
+ <summary>
+ patterns defined on this PatternString only
+ </summary>
+ </member>
+ <member name="M:log4net.Util.PatternString.#cctor">
+ <summary>
+ Initialize the global registry
+ </summary>
+ </member>
+ <member name="M:log4net.Util.PatternString.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ <remarks>
+ <para>
+ Initialize a new instance of <see cref="T:log4net.Util.PatternString"/>
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternString.#ctor(System.String)">
+ <summary>
+ Constructs a PatternString
+ </summary>
+ <param name="pattern">The pattern to use with this PatternString</param>
+ <remarks>
+ <para>
+ Initialize a new instance of <see cref="T:log4net.Util.PatternString"/> with the pattern specified.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternString.ActivateOptions">
+ <summary>
+ Initialize object options
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Util.PatternString.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Util.PatternString.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Util.PatternString.ActivateOptions"/> must be called again.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternString.CreatePatternParser(System.String)">
+ <summary>
+ Create the <see cref="T:log4net.Util.PatternParser"/> used to parse the pattern
+ </summary>
+ <param name="pattern">the pattern to parse</param>
+ <returns>The <see cref="T:log4net.Util.PatternParser"/></returns>
+ <remarks>
+ <para>
+ Returns PatternParser used to parse the conversion string. Subclasses
+ may override this to return a subclass of PatternParser which recognize
+ custom conversion pattern name.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternString.Format(System.IO.TextWriter)">
+ <summary>
+ Produces a formatted string as specified by the conversion pattern.
+ </summary>
+ <param name="writer">The TextWriter to write the formatted event to</param>
+ <remarks>
+ <para>
+ Format the pattern to the <paramref name="writer"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternString.Format">
+ <summary>
+ Format the pattern as a string
+ </summary>
+ <returns>the pattern formatted as a string</returns>
+ <remarks>
+ <para>
+ Format the pattern to a string.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternString.AddConverter(log4net.Util.PatternString.ConverterInfo)">
+ <summary>
+ Add a converter to this PatternString
+ </summary>
+ <param name="converterInfo">the converter info</param>
+ <remarks>
+ <para>
+ This version of the method is used by the configurator.
+ Programmatic users should use the alternative <see cref="M:log4net.Util.PatternString.AddConverter(System.String,System.Type)"/> method.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternString.AddConverter(System.String,System.Type)">
+ <summary>
+ Add a converter to this PatternString
+ </summary>
+ <param name="name">the name of the conversion pattern for this converter</param>
+ <param name="type">the type of the converter</param>
+ <remarks>
+ <para>
+ Add a converter to this PatternString
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.PatternString.ConversionPattern">
+ <summary>
+ Gets or sets the pattern formatting string
+ </summary>
+ <value>
+ The pattern formatting string
+ </value>
+ <remarks>
+ <para>
+ The <b>ConversionPattern</b> option. This is the string which
+ controls formatting and consists of a mix of literal content and
+ conversion specifiers.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.PatternString.ConverterInfo">
+ <summary>
+ Wrapper class used to map converter names to converter types
+ </summary>
+ <remarks>
+ <para>
+ Wrapper class used to map converter names to converter types
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PatternString.ConverterInfo.#ctor">
+ <summary>
+ default constructor
+ </summary>
+ </member>
+ <member name="P:log4net.Util.PatternString.ConverterInfo.Name">
+ <summary>
+ Gets or sets the name of the conversion pattern
+ </summary>
+ <value>
+ The name of the conversion pattern
+ </value>
+ <remarks>
+ <para>
+ Gets or sets the name of the conversion pattern
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.PatternString.ConverterInfo.Type">
+ <summary>
+ Gets or sets the type of the converter
+ </summary>
+ <value>
+ The type of the converter
+ </value>
+ <remarks>
+ <para>
+ Gets or sets the type of the converter
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.PropertiesDictionary">
+ <summary>
+ String keyed object map.
+ </summary>
+ <remarks>
+ <para>
+ While this collection is serializable only member
+ objects that are serializable will
+ be serialized along with this collection.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="T:log4net.Util.ReadOnlyPropertiesDictionary">
+ <summary>
+ String keyed object map that is read only.
+ </summary>
+ <remarks>
+ <para>
+ This collection is readonly and cannot be modified.
+ </para>
+ <para>
+ While this collection is serializable only member
+ objects that are serializable will
+ be serialized along with this collection.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="F:log4net.Util.ReadOnlyPropertiesDictionary.m_hashtable">
+ <summary>
+ The Hashtable used to store the properties data
+ </summary>
+ </member>
+ <member name="M:log4net.Util.ReadOnlyPropertiesDictionary.#ctor">
+ <summary>
+ Constructor
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.ReadOnlyPropertiesDictionary"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ReadOnlyPropertiesDictionary.#ctor(log4net.Util.ReadOnlyPropertiesDictionary)">
+ <summary>
+ Copy Constructor
+ </summary>
+ <param name="propertiesDictionary">properties to copy</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.ReadOnlyPropertiesDictionary"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ReadOnlyPropertiesDictionary.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)">
+ <summary>
+ Deserialization constructor
+ </summary>
+ <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> that holds the serialized object data.</param>
+ <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext"/> that contains contextual information about the source or destination.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.ReadOnlyPropertiesDictionary"/> class
+ with serialized data.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ReadOnlyPropertiesDictionary.GetKeys">
+ <summary>
+ Gets the key names.
+ </summary>
+ <returns>An array of all the keys.</returns>
+ <remarks>
+ <para>
+ Gets the key names.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ReadOnlyPropertiesDictionary.Contains(System.String)">
+ <summary>
+ Test if the dictionary contains a specified key
+ </summary>
+ <param name="key">the key to look for</param>
+ <returns>true if the dictionary contains the specified key</returns>
+ <remarks>
+ <para>
+ Test if the dictionary contains a specified key
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ReadOnlyPropertiesDictionary.GetObjectData(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)">
+ <summary>
+ Serializes this object into the <see cref="T:System.Runtime.Serialization.SerializationInfo"/> provided.
+ </summary>
+ <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> to populate with data.</param>
+ <param name="context">The destination for this serialization.</param>
+ <remarks>
+ <para>
+ Serializes this object into the <see cref="T:System.Runtime.Serialization.SerializationInfo"/> provided.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ReadOnlyPropertiesDictionary.System#Collections#IDictionary#GetEnumerator">
+ <summary>
+ See <see cref="M:System.Collections.IDictionary.GetEnumerator"/>
+ </summary>
+ </member>
+ <member name="M:log4net.Util.ReadOnlyPropertiesDictionary.System#Collections#IDictionary#Remove(System.Object)">
+ <summary>
+ See <see cref="M:System.Collections.IDictionary.Remove(System.Object)"/>
+ </summary>
+ <param name="key"></param>
+ </member>
+ <member name="M:log4net.Util.ReadOnlyPropertiesDictionary.System#Collections#IDictionary#Contains(System.Object)">
+ <summary>
+ See <see cref="M:System.Collections.IDictionary.Contains(System.Object)"/>
+ </summary>
+ <param name="key"></param>
+ <returns></returns>
+ </member>
+ <member name="M:log4net.Util.ReadOnlyPropertiesDictionary.Clear">
+ <summary>
+ Remove all properties from the properties collection
+ </summary>
+ </member>
+ <member name="M:log4net.Util.ReadOnlyPropertiesDictionary.System#Collections#IDictionary#Add(System.Object,System.Object)">
+ <summary>
+ See <see cref="M:System.Collections.IDictionary.Add(System.Object,System.Object)"/>
+ </summary>
+ <param name="key"></param>
+ <param name="value"></param>
+ </member>
+ <member name="M:log4net.Util.ReadOnlyPropertiesDictionary.System#Collections#ICollection#CopyTo(System.Array,System.Int32)">
+ <summary>
+ See <see cref="M:System.Collections.ICollection.CopyTo(System.Array,System.Int32)"/>
+ </summary>
+ <param name="array"></param>
+ <param name="index"></param>
+ </member>
+ <member name="M:log4net.Util.ReadOnlyPropertiesDictionary.System#Collections#IEnumerable#GetEnumerator">
+ <summary>
+ See <see cref="M:System.Collections.IEnumerable.GetEnumerator"/>
+ </summary>
+ </member>
+ <member name="P:log4net.Util.ReadOnlyPropertiesDictionary.Item(System.String)">
+ <summary>
+ Gets or sets the value of the property with the specified key.
+ </summary>
+ <value>
+ The value of the property with the specified key.
+ </value>
+ <param name="key">The key of the property to get or set.</param>
+ <remarks>
+ <para>
+ The property value will only be serialized if it is serializable.
+ If it cannot be serialized it will be silently ignored if
+ a serialization operation is performed.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.ReadOnlyPropertiesDictionary.InnerHashtable">
+ <summary>
+ The hashtable used to store the properties
+ </summary>
+ <value>
+ The internal collection used to store the properties
+ </value>
+ <remarks>
+ <para>
+ The hashtable used to store the properties
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.ReadOnlyPropertiesDictionary.System#Collections#IDictionary#IsReadOnly">
+ <summary>
+ See <see cref="P:System.Collections.IDictionary.IsReadOnly"/>
+ </summary>
+ </member>
+ <member name="P:log4net.Util.ReadOnlyPropertiesDictionary.System#Collections#IDictionary#Item(System.Object)">
+ <summary>
+ See <see cref="P:System.Collections.IDictionary.Item(System.Object)"/>
+ </summary>
+ </member>
+ <member name="P:log4net.Util.ReadOnlyPropertiesDictionary.System#Collections#IDictionary#Values">
+ <summary>
+ See <see cref="P:System.Collections.IDictionary.Values"/>
+ </summary>
+ </member>
+ <member name="P:log4net.Util.ReadOnlyPropertiesDictionary.System#Collections#IDictionary#Keys">
+ <summary>
+ See <see cref="P:System.Collections.IDictionary.Keys"/>
+ </summary>
+ </member>
+ <member name="P:log4net.Util.ReadOnlyPropertiesDictionary.System#Collections#IDictionary#IsFixedSize">
+ <summary>
+ See <see cref="P:System.Collections.IDictionary.IsFixedSize"/>
+ </summary>
+ </member>
+ <member name="P:log4net.Util.ReadOnlyPropertiesDictionary.System#Collections#ICollection#IsSynchronized">
+ <summary>
+ See <see cref="P:System.Collections.ICollection.IsSynchronized"/>
+ </summary>
+ </member>
+ <member name="P:log4net.Util.ReadOnlyPropertiesDictionary.Count">
+ <summary>
+ The number of properties in this collection
+ </summary>
+ </member>
+ <member name="P:log4net.Util.ReadOnlyPropertiesDictionary.System#Collections#ICollection#SyncRoot">
+ <summary>
+ See <see cref="P:System.Collections.ICollection.SyncRoot"/>
+ </summary>
+ </member>
+ <member name="M:log4net.Util.PropertiesDictionary.#ctor">
+ <summary>
+ Constructor
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.PropertiesDictionary"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PropertiesDictionary.#ctor(log4net.Util.ReadOnlyPropertiesDictionary)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="propertiesDictionary">properties to copy</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.PropertiesDictionary"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PropertiesDictionary.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Util.PropertiesDictionary"/> class
+ with serialized data.
+ </summary>
+ <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> that holds the serialized object data.</param>
+ <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext"/> that contains contextual information about the source or destination.</param>
+ <remarks>
+ <para>
+ Because this class is sealed the serialization constructor is private.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PropertiesDictionary.Remove(System.String)">
+ <summary>
+ Remove the entry with the specified key from this dictionary
+ </summary>
+ <param name="key">the key for the entry to remove</param>
+ <remarks>
+ <para>
+ Remove the entry with the specified key from this dictionary
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PropertiesDictionary.System#Collections#IDictionary#GetEnumerator">
+ <summary>
+ See <see cref="M:System.Collections.IDictionary.GetEnumerator"/>
+ </summary>
+ <returns>an enumerator</returns>
+ <remarks>
+ <para>
+ Returns a <see cref="T:System.Collections.IDictionaryEnumerator"/> over the contest of this collection.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PropertiesDictionary.System#Collections#IDictionary#Remove(System.Object)">
+ <summary>
+ See <see cref="M:System.Collections.IDictionary.Remove(System.Object)"/>
+ </summary>
+ <param name="key">the key to remove</param>
+ <remarks>
+ <para>
+ Remove the entry with the specified key from this dictionary
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PropertiesDictionary.System#Collections#IDictionary#Contains(System.Object)">
+ <summary>
+ See <see cref="M:System.Collections.IDictionary.Contains(System.Object)"/>
+ </summary>
+ <param name="key">the key to lookup in the collection</param>
+ <returns><c>true</c> if the collection contains the specified key</returns>
+ <remarks>
+ <para>
+ Test if this collection contains a specified key.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PropertiesDictionary.Clear">
+ <summary>
+ Remove all properties from the properties collection
+ </summary>
+ <remarks>
+ <para>
+ Remove all properties from the properties collection
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.PropertiesDictionary.System#Collections#IDictionary#Add(System.Object,System.Object)">
+ <summary>
+ See <see cref="M:System.Collections.IDictionary.Add(System.Object,System.Object)"/>
+ </summary>
+ <param name="key">the key</param>
+ <param name="value">the value to store for the key</param>
+ <remarks>
+ <para>
+ Store a value for the specified <see cref="T:System.String"/> <paramref name="key"/>.
+ </para>
+ </remarks>
+ <exception cref="T:System.ArgumentException">Thrown if the <paramref name="key"/> is not a string</exception>
+ </member>
+ <member name="M:log4net.Util.PropertiesDictionary.System#Collections#ICollection#CopyTo(System.Array,System.Int32)">
+ <summary>
+ See <see cref="M:System.Collections.ICollection.CopyTo(System.Array,System.Int32)"/>
+ </summary>
+ <param name="array"></param>
+ <param name="index"></param>
+ </member>
+ <member name="M:log4net.Util.PropertiesDictionary.System#Collections#IEnumerable#GetEnumerator">
+ <summary>
+ See <see cref="M:System.Collections.IEnumerable.GetEnumerator"/>
+ </summary>
+ </member>
+ <member name="P:log4net.Util.PropertiesDictionary.Item(System.String)">
+ <summary>
+ Gets or sets the value of the property with the specified key.
+ </summary>
+ <value>
+ The value of the property with the specified key.
+ </value>
+ <param name="key">The key of the property to get or set.</param>
+ <remarks>
+ <para>
+ The property value will only be serialized if it is serializable.
+ If it cannot be serialized it will be silently ignored if
+ a serialization operation is performed.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.PropertiesDictionary.System#Collections#IDictionary#IsReadOnly">
+ <summary>
+ See <see cref="P:System.Collections.IDictionary.IsReadOnly"/>
+ </summary>
+ <value>
+ <c>false</c>
+ </value>
+ <remarks>
+ <para>
+ This collection is modifiable. This property always
+ returns <c>false</c>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.PropertiesDictionary.System#Collections#IDictionary#Item(System.Object)">
+ <summary>
+ See <see cref="P:System.Collections.IDictionary.Item(System.Object)"/>
+ </summary>
+ <value>
+ The value for the key specified.
+ </value>
+ <remarks>
+ <para>
+ Get or set a value for the specified <see cref="T:System.String"/> <paramref name="key"/>.
+ </para>
+ </remarks>
+ <exception cref="T:System.ArgumentException">Thrown if the <paramref name="key"/> is not a string</exception>
+ </member>
+ <member name="P:log4net.Util.PropertiesDictionary.System#Collections#IDictionary#Values">
+ <summary>
+ See <see cref="P:System.Collections.IDictionary.Values"/>
+ </summary>
+ </member>
+ <member name="P:log4net.Util.PropertiesDictionary.System#Collections#IDictionary#Keys">
+ <summary>
+ See <see cref="P:System.Collections.IDictionary.Keys"/>
+ </summary>
+ </member>
+ <member name="P:log4net.Util.PropertiesDictionary.System#Collections#IDictionary#IsFixedSize">
+ <summary>
+ See <see cref="P:System.Collections.IDictionary.IsFixedSize"/>
+ </summary>
+ </member>
+ <member name="P:log4net.Util.PropertiesDictionary.System#Collections#ICollection#IsSynchronized">
+ <summary>
+ See <see cref="P:System.Collections.ICollection.IsSynchronized"/>
+ </summary>
+ </member>
+ <member name="P:log4net.Util.PropertiesDictionary.System#Collections#ICollection#SyncRoot">
+ <summary>
+ See <see cref="P:System.Collections.ICollection.SyncRoot"/>
+ </summary>
+ </member>
+ <member name="T:log4net.Util.ProtectCloseTextWriter">
+ <summary>
+ A <see cref="T:System.IO.TextWriter"/> that ignores the <see cref="M:log4net.Util.ProtectCloseTextWriter.Close"/> message
+ </summary>
+ <remarks>
+ <para>
+ This writer is used in special cases where it is necessary
+ to protect a writer from being closed by a client.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.ProtectCloseTextWriter.#ctor(System.IO.TextWriter)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="writer">the writer to actually write to</param>
+ <remarks>
+ <para>
+ Create a new ProtectCloseTextWriter using a writer
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ProtectCloseTextWriter.Attach(System.IO.TextWriter)">
+ <summary>
+ Attach this instance to a different underlying <see cref="T:System.IO.TextWriter"/>
+ </summary>
+ <param name="writer">the writer to attach to</param>
+ <remarks>
+ <para>
+ Attach this instance to a different underlying <see cref="T:System.IO.TextWriter"/>
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ProtectCloseTextWriter.Close">
+ <summary>
+ Does not close the underlying output writer.
+ </summary>
+ <remarks>
+ <para>
+ Does not close the underlying output writer.
+ This method does nothing.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.ReaderWriterLock">
+ <summary>
+ Defines a lock that supports single writers and multiple readers
+ </summary>
+ <remarks>
+ <para>
+ <c>ReaderWriterLock</c> is used to synchronize access to a resource.
+ At any given time, it allows either concurrent read access for
+ multiple threads, or write access for a single thread. In a
+ situation where a resource is changed infrequently, a
+ <c>ReaderWriterLock</c> provides better throughput than a simple
+ one-at-a-time lock, such as <see cref="T:System.Threading.Monitor"/>.
+ </para>
+ <para>
+ If a platform does not support a <c>System.Threading.ReaderWriterLock</c>
+ implementation then all readers and writers are serialized. Therefore
+ the caller must not rely on multiple simultaneous readers.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.ReaderWriterLock.#ctor">
+ <summary>
+ Constructor
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.ReaderWriterLock"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ReaderWriterLock.AcquireReaderLock">
+ <summary>
+ Acquires a reader lock
+ </summary>
+ <remarks>
+ <para>
+ <see cref="M:log4net.Util.ReaderWriterLock.AcquireReaderLock"/> blocks if a different thread has the writer
+ lock, or if at least one thread is waiting for the writer lock.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ReaderWriterLock.ReleaseReaderLock">
+ <summary>
+ Decrements the lock count
+ </summary>
+ <remarks>
+ <para>
+ <see cref="M:log4net.Util.ReaderWriterLock.ReleaseReaderLock"/> decrements the lock count. When the count
+ reaches zero, the lock is released.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ReaderWriterLock.AcquireWriterLock">
+ <summary>
+ Acquires the writer lock
+ </summary>
+ <remarks>
+ <para>
+ This method blocks if another thread has a reader lock or writer lock.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ReaderWriterLock.ReleaseWriterLock">
+ <summary>
+ Decrements the lock count on the writer lock
+ </summary>
+ <remarks>
+ <para>
+ ReleaseWriterLock decrements the writer lock count.
+ When the count reaches zero, the writer lock is released.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.ReusableStringWriter">
+ <summary>
+ A <see cref="T:System.IO.StringWriter"/> that can be <see cref="M:log4net.Util.ReusableStringWriter.Reset(System.Int32,System.Int32)"/> and reused
+ </summary>
+ <remarks>
+ <para>
+ A <see cref="T:System.IO.StringWriter"/> that can be <see cref="M:log4net.Util.ReusableStringWriter.Reset(System.Int32,System.Int32)"/> and reused.
+ This uses a single buffer for string operations.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.ReusableStringWriter.#ctor(System.IFormatProvider)">
+ <summary>
+ Create an instance of <see cref="T:log4net.Util.ReusableStringWriter"/>
+ </summary>
+ <param name="formatProvider">the format provider to use</param>
+ <remarks>
+ <para>
+ Create an instance of <see cref="T:log4net.Util.ReusableStringWriter"/>
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ReusableStringWriter.Dispose(System.Boolean)">
+ <summary>
+ Override Dispose to prevent closing of writer
+ </summary>
+ <param name="disposing">flag</param>
+ <remarks>
+ <para>
+ Override Dispose to prevent closing of writer
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ReusableStringWriter.Reset(System.Int32,System.Int32)">
+ <summary>
+ Reset this string writer so that it can be reused.
+ </summary>
+ <param name="maxCapacity">the maximum buffer capacity before it is trimmed</param>
+ <param name="defaultSize">the default size to make the buffer</param>
+ <remarks>
+ <para>
+ Reset this string writer so that it can be reused.
+ The internal buffers are cleared and reset.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.SystemInfo">
+ <summary>
+ Utility class for system specific information.
+ </summary>
+ <remarks>
+ <para>
+ Utility class of static methods for system specific information.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ <author>Alexey Solofnenko</author>
+ </member>
+ <member name="M:log4net.Util.SystemInfo.#ctor">
+ <summary>
+ Private constructor to prevent instances.
+ </summary>
+ <remarks>
+ <para>
+ Only static methods are exposed from this type.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.SystemInfo.#cctor">
+ <summary>
+ Initialize default values for private static fields.
+ </summary>
+ <remarks>
+ <para>
+ Only static methods are exposed from this type.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.SystemInfo.AssemblyLocationInfo(System.Reflection.Assembly)">
+ <summary>
+ Gets the assembly location path for the specified assembly.
+ </summary>
+ <param name="myAssembly">The assembly to get the location for.</param>
+ <returns>The location of the assembly.</returns>
+ <remarks>
+ <para>
+ This method does not guarantee to return the correct path
+ to the assembly. If only tries to give an indication as to
+ where the assembly was loaded from.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.SystemInfo.AssemblyQualifiedName(System.Type)">
+ <summary>
+ Gets the fully qualified name of the <see cref="T:System.Type"/>, including
+ the name of the assembly from which the <see cref="T:System.Type"/> was
+ loaded.
+ </summary>
+ <param name="type">The <see cref="T:System.Type"/> to get the fully qualified name for.</param>
+ <returns>The fully qualified name for the <see cref="T:System.Type"/>.</returns>
+ <remarks>
+ <para>
+ This is equivalent to the <c>Type.AssemblyQualifiedName</c> property,
+ but this method works on the .NET Compact Framework 1.0 as well as
+ the full .NET runtime.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.SystemInfo.AssemblyShortName(System.Reflection.Assembly)">
+ <summary>
+ Gets the short name of the <see cref="T:System.Reflection.Assembly"/>.
+ </summary>
+ <param name="myAssembly">The <see cref="T:System.Reflection.Assembly"/> to get the name for.</param>
+ <returns>The short name of the <see cref="T:System.Reflection.Assembly"/>.</returns>
+ <remarks>
+ <para>
+ The short name of the assembly is the <see cref="P:System.Reflection.Assembly.FullName"/>
+ without the version, culture, or public key. i.e. it is just the
+ assembly's file name without the extension.
+ </para>
+ <para>
+ Use this rather than <c>Assembly.GetName().Name</c> because that
+ is not available on the Compact Framework.
+ </para>
+ <para>
+ Because of a FileIOPermission security demand we cannot do
+ the obvious Assembly.GetName().Name. We are allowed to get
+ the <see cref="P:System.Reflection.Assembly.FullName"/> of the assembly so we
+ start from there and strip out just the assembly name.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.SystemInfo.AssemblyFileName(System.Reflection.Assembly)">
+ <summary>
+ Gets the file name portion of the <see cref="T:System.Reflection.Assembly"/>, including the extension.
+ </summary>
+ <param name="myAssembly">The <see cref="T:System.Reflection.Assembly"/> to get the file name for.</param>
+ <returns>The file name of the assembly.</returns>
+ <remarks>
+ <para>
+ Gets the file name portion of the <see cref="T:System.Reflection.Assembly"/>, including the extension.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.SystemInfo.GetTypeFromString(System.Type,System.String,System.Boolean,System.Boolean)">
+ <summary>
+ Loads the type specified in the type string.
+ </summary>
+ <param name="relativeType">A sibling type to use to load the type.</param>
+ <param name="typeName">The name of the type to load.</param>
+ <param name="throwOnError">Flag set to <c>true</c> to throw an exception if the type cannot be loaded.</param>
+ <param name="ignoreCase"><c>true</c> to ignore the case of the type name; otherwise, <c>false</c></param>
+ <returns>The type loaded or <c>null</c> if it could not be loaded.</returns>
+ <remarks>
+ <para>
+ If the type name is fully qualified, i.e. if contains an assembly name in
+ the type name, the type will be loaded from the system using
+ <see cref="M:System.Type.GetType(System.String,System.Boolean)"/>.
+ </para>
+ <para>
+ If the type name is not fully qualified, it will be loaded from the assembly
+ containing the specified relative type. If the type is not found in the assembly
+ then all the loaded assemblies will be searched for the type.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.SystemInfo.GetTypeFromString(System.String,System.Boolean,System.Boolean)">
+ <summary>
+ Loads the type specified in the type string.
+ </summary>
+ <param name="typeName">The name of the type to load.</param>
+ <param name="throwOnError">Flag set to <c>true</c> to throw an exception if the type cannot be loaded.</param>
+ <param name="ignoreCase"><c>true</c> to ignore the case of the type name; otherwise, <c>false</c></param>
+ <returns>The type loaded or <c>null</c> if it could not be loaded.</returns>
+ <remarks>
+ <para>
+ If the type name is fully qualified, i.e. if contains an assembly name in
+ the type name, the type will be loaded from the system using
+ <see cref="M:System.Type.GetType(System.String,System.Boolean)"/>.
+ </para>
+ <para>
+ If the type name is not fully qualified it will be loaded from the
+ assembly that is directly calling this method. If the type is not found
+ in the assembly then all the loaded assemblies will be searched for the type.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.SystemInfo.GetTypeFromString(System.Reflection.Assembly,System.String,System.Boolean,System.Boolean)">
+ <summary>
+ Loads the type specified in the type string.
+ </summary>
+ <param name="relativeAssembly">An assembly to load the type from.</param>
+ <param name="typeName">The name of the type to load.</param>
+ <param name="throwOnError">Flag set to <c>true</c> to throw an exception if the type cannot be loaded.</param>
+ <param name="ignoreCase"><c>true</c> to ignore the case of the type name; otherwise, <c>false</c></param>
+ <returns>The type loaded or <c>null</c> if it could not be loaded.</returns>
+ <remarks>
+ <para>
+ If the type name is fully qualified, i.e. if contains an assembly name in
+ the type name, the type will be loaded from the system using
+ <see cref="M:System.Type.GetType(System.String,System.Boolean)"/>.
+ </para>
+ <para>
+ If the type name is not fully qualified it will be loaded from the specified
+ assembly. If the type is not found in the assembly then all the loaded assemblies
+ will be searched for the type.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.SystemInfo.NewGuid">
+ <summary>
+ Generate a new guid
+ </summary>
+ <returns>A new Guid</returns>
+ <remarks>
+ <para>
+ Generate a new guid
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.SystemInfo.CreateArgumentOutOfRangeException(System.String,System.Object,System.String)">
+ <summary>
+ Create an <see cref="T:System.ArgumentOutOfRangeException"/>
+ </summary>
+ <param name="parameterName">The name of the parameter that caused the exception</param>
+ <param name="actualValue">The value of the argument that causes this exception</param>
+ <param name="message">The message that describes the error</param>
+ <returns>the ArgumentOutOfRangeException object</returns>
+ <remarks>
+ <para>
+ Create a new instance of the <see cref="T:System.ArgumentOutOfRangeException"/> class
+ with a specified error message, the parameter name, and the value
+ of the argument.
+ </para>
+ <para>
+ The Compact Framework does not support the 3 parameter constructor for the
+ <see cref="T:System.ArgumentOutOfRangeException"/> type. This method provides an
+ implementation that works for all platforms.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.SystemInfo.TryParse(System.String,System.Int32@)">
+ <summary>
+ Parse a string into an <see cref="T:System.Int32"/> value
+ </summary>
+ <param name="s">the string to parse</param>
+ <param name="val">out param where the parsed value is placed</param>
+ <returns><c>true</c> if the string was able to be parsed into an integer</returns>
+ <remarks>
+ <para>
+ Attempts to parse the string into an integer. If the string cannot
+ be parsed then this method returns <c>false</c>. The method does not throw an exception.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.SystemInfo.TryParse(System.String,System.Int64@)">
+ <summary>
+ Parse a string into an <see cref="T:System.Int64"/> value
+ </summary>
+ <param name="s">the string to parse</param>
+ <param name="val">out param where the parsed value is placed</param>
+ <returns><c>true</c> if the string was able to be parsed into an integer</returns>
+ <remarks>
+ <para>
+ Attempts to parse the string into an integer. If the string cannot
+ be parsed then this method returns <c>false</c>. The method does not throw an exception.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.SystemInfo.GetAppSetting(System.String)">
+ <summary>
+ Lookup an application setting
+ </summary>
+ <param name="key">the application settings key to lookup</param>
+ <returns>the value for the key, or <c>null</c></returns>
+ <remarks>
+ <para>
+ Configuration APIs are not supported under the Compact Framework
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.SystemInfo.ConvertToFullPath(System.String)">
+ <summary>
+ Convert a path into a fully qualified local file path.
+ </summary>
+ <param name="path">The path to convert.</param>
+ <returns>The fully qualified path.</returns>
+ <remarks>
+ <para>
+ Converts the path specified to a fully
+ qualified path. If the path is relative it is
+ taken as relative from the application base
+ directory.
+ </para>
+ <para>
+ The path specified must be a local file path, a URI is not supported.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.SystemInfo.CreateCaseInsensitiveHashtable">
+ <summary>
+ Creates a new case-insensitive instance of the <see cref="T:System.Collections.Hashtable"/> class with the default initial capacity.
+ </summary>
+ <returns>A new case-insensitive instance of the <see cref="T:System.Collections.Hashtable"/> class with the default initial capacity</returns>
+ <remarks>
+ <para>
+ The new Hashtable instance uses the default load factor, the CaseInsensitiveHashCodeProvider, and the CaseInsensitiveComparer.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Util.SystemInfo.EmptyTypes">
+ <summary>
+ Gets an empty array of types.
+ </summary>
+ <remarks>
+ <para>
+ The <c>Type.EmptyTypes</c> field is not available on
+ the .NET Compact Framework 1.0.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Util.SystemInfo.s_hostName">
+ <summary>
+ Cache the host name for the current machine
+ </summary>
+ </member>
+ <member name="F:log4net.Util.SystemInfo.s_appFriendlyName">
+ <summary>
+ Cache the application friendly name
+ </summary>
+ </member>
+ <member name="F:log4net.Util.SystemInfo.s_nullText">
+ <summary>
+ Text to output when a <c>null</c> is encountered.
+ </summary>
+ </member>
+ <member name="F:log4net.Util.SystemInfo.s_notAvailableText">
+ <summary>
+ Text to output when an unsupported feature is requested.
+ </summary>
+ </member>
+ <member name="F:log4net.Util.SystemInfo.s_processStartTime">
+ <summary>
+ Start time for the current process.
+ </summary>
+ </member>
+ <member name="P:log4net.Util.SystemInfo.NewLine">
+ <summary>
+ Gets the system dependent line terminator.
+ </summary>
+ <value>
+ The system dependent line terminator.
+ </value>
+ <remarks>
+ <para>
+ Gets the system dependent line terminator.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.SystemInfo.ApplicationBaseDirectory">
+ <summary>
+ Gets the base directory for this <see cref="T:System.AppDomain"/>.
+ </summary>
+ <value>The base directory path for the current <see cref="T:System.AppDomain"/>.</value>
+ <remarks>
+ <para>
+ Gets the base directory for this <see cref="T:System.AppDomain"/>.
+ </para>
+ <para>
+ The value returned may be either a local file path or a URI.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.SystemInfo.ConfigurationFileLocation">
+ <summary>
+ Gets the path to the configuration file for the current <see cref="T:System.AppDomain"/>.
+ </summary>
+ <value>The path to the configuration file for the current <see cref="T:System.AppDomain"/>.</value>
+ <remarks>
+ <para>
+ The .NET Compact Framework 1.0 does not have a concept of a configuration
+ file. For this runtime, we use the entry assembly location as the root for
+ the configuration file name.
+ </para>
+ <para>
+ The value returned may be either a local file path or a URI.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.SystemInfo.EntryAssemblyLocation">
+ <summary>
+ Gets the path to the file that first executed in the current <see cref="T:System.AppDomain"/>.
+ </summary>
+ <value>The path to the entry assembly.</value>
+ <remarks>
+ <para>
+ Gets the path to the file that first executed in the current <see cref="T:System.AppDomain"/>.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.SystemInfo.CurrentThreadId">
+ <summary>
+ Gets the ID of the current thread.
+ </summary>
+ <value>The ID of the current thread.</value>
+ <remarks>
+ <para>
+ On the .NET framework, the <c>AppDomain.GetCurrentThreadId</c> method
+ is used to obtain the thread ID for the current thread. This is the
+ operating system ID for the thread.
+ </para>
+ <para>
+ On the .NET Compact Framework 1.0 it is not possible to get the
+ operating system thread ID for the current thread. The native method
+ <c>GetCurrentThreadId</c> is implemented inline in a header file
+ and cannot be called.
+ </para>
+ <para>
+ On the .NET Framework 2.0 the <c>Thread.ManagedThreadId</c> is used as this
+ gives a stable id unrelated to the operating system thread ID which may
+ change if the runtime is using fibers.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.SystemInfo.HostName">
+ <summary>
+ Get the host name or machine name for the current machine
+ </summary>
+ <value>
+ The hostname or machine name
+ </value>
+ <remarks>
+ <para>
+ Get the host name or machine name for the current machine
+ </para>
+ <para>
+ The host name (<see cref="M:System.Net.Dns.GetHostName"/>) or
+ the machine name (<c>Environment.MachineName</c>) for
+ the current machine, or if neither of these are available
+ then <c>NOT AVAILABLE</c> is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.SystemInfo.ApplicationFriendlyName">
+ <summary>
+ Get this application's friendly name
+ </summary>
+ <value>
+ The friendly name of this application as a string
+ </value>
+ <remarks>
+ <para>
+ If available the name of the application is retrieved from
+ the <c>AppDomain</c> using <c>AppDomain.CurrentDomain.FriendlyName</c>.
+ </para>
+ <para>
+ Otherwise the file name of the entry assembly is used.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.SystemInfo.ProcessStartTime">
+ <summary>
+ Get the start time for the current process.
+ </summary>
+ <remarks>
+ <para>
+ This is the time at which the log4net library was loaded into the
+ AppDomain. Due to reports of a hang in the call to <c>System.Diagnostics.Process.StartTime</c>
+ this is not the start time for the current process.
+ </para>
+ <para>
+ The log4net library should be loaded by an application early during its
+ startup, therefore this start time should be a good approximation for
+ the actual start time.
+ </para>
+ <para>
+ Note that AppDomains may be loaded and unloaded within the
+ same process without the process terminating, however this start time
+ will be set per AppDomain.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.SystemInfo.NullText">
+ <summary>
+ Text to output when a <c>null</c> is encountered.
+ </summary>
+ <remarks>
+ <para>
+ Use this value to indicate a <c>null</c> has been encountered while
+ outputting a string representation of an item.
+ </para>
+ <para>
+ The default value is <c>(null)</c>. This value can be overridden by specifying
+ a value for the <c>log4net.NullText</c> appSetting in the application's
+ .config file.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.SystemInfo.NotAvailableText">
+ <summary>
+ Text to output when an unsupported feature is requested.
+ </summary>
+ <remarks>
+ <para>
+ Use this value when an unsupported feature is requested.
+ </para>
+ <para>
+ The default value is <c>NOT AVAILABLE</c>. This value can be overridden by specifying
+ a value for the <c>log4net.NotAvailableText</c> appSetting in the application's
+ .config file.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.SystemStringFormat">
+ <summary>
+ Utility class that represents a format string.
+ </summary>
+ <remarks>
+ <para>
+ Utility class that represents a format string.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.SystemStringFormat.#ctor(System.IFormatProvider,System.String,System.Object[])">
+ <summary>
+ Initialise the <see cref="T:log4net.Util.SystemStringFormat"/>
+ </summary>
+ <param name="provider">An <see cref="T:System.IFormatProvider"/> that supplies culture-specific formatting information.</param>
+ <param name="format">A <see cref="T:System.String"/> containing zero or more format items.</param>
+ <param name="args">An <see cref="T:System.Object"/> array containing zero or more objects to format.</param>
+ </member>
+ <member name="M:log4net.Util.SystemStringFormat.ToString">
+ <summary>
+ Format the string and arguments
+ </summary>
+ <returns>the formatted string</returns>
+ </member>
+ <member name="M:log4net.Util.SystemStringFormat.StringFormat(System.IFormatProvider,System.String,System.Object[])">
+ <summary>
+ Replaces the format item in a specified <see cref="T:System.String"/> with the text equivalent
+ of the value of a corresponding <see cref="T:System.Object"/> instance in a specified array.
+ A specified parameter supplies culture-specific formatting information.
+ </summary>
+ <param name="provider">An <see cref="T:System.IFormatProvider"/> that supplies culture-specific formatting information.</param>
+ <param name="format">A <see cref="T:System.String"/> containing zero or more format items.</param>
+ <param name="args">An <see cref="T:System.Object"/> array containing zero or more objects to format.</param>
+ <returns>
+ A copy of format in which the format items have been replaced by the <see cref="T:System.String"/>
+ equivalent of the corresponding instances of <see cref="T:System.Object"/> in args.
+ </returns>
+ <remarks>
+ <para>
+ This method does not throw exceptions. If an exception thrown while formatting the result the
+ exception and arguments are returned in the result string.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.SystemStringFormat.StringFormatError(System.Exception,System.String,System.Object[])">
+ <summary>
+ Process an error during StringFormat
+ </summary>
+ </member>
+ <member name="M:log4net.Util.SystemStringFormat.RenderArray(System.Array,System.Text.StringBuilder)">
+ <summary>
+ Dump the contents of an array into a string builder
+ </summary>
+ </member>
+ <member name="M:log4net.Util.SystemStringFormat.RenderObject(System.Object,System.Text.StringBuilder)">
+ <summary>
+ Dump an object to a string
+ </summary>
+ </member>
+ <member name="T:log4net.Util.ThreadContextProperties">
+ <summary>
+ Implementation of Properties collection for the <see cref="T:log4net.ThreadContext"/>
+ </summary>
+ <remarks>
+ <para>
+ Class implements a collection of properties that is specific to each thread.
+ The class is not synchronized as each thread has its own <see cref="T:log4net.Util.PropertiesDictionary"/>.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="F:log4net.Util.ThreadContextProperties.s_threadLocalSlot">
+ <summary>
+ The thread local data slot to use to store a PropertiesDictionary.
+ </summary>
+ </member>
+ <member name="M:log4net.Util.ThreadContextProperties.#ctor">
+ <summary>
+ Internal constructor
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.ThreadContextProperties"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ThreadContextProperties.Remove(System.String)">
+ <summary>
+ Remove a property
+ </summary>
+ <param name="key">the key for the entry to remove</param>
+ <remarks>
+ <para>
+ Remove a property
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ThreadContextProperties.Clear">
+ <summary>
+ Clear all properties
+ </summary>
+ <remarks>
+ <para>
+ Clear all properties
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ThreadContextProperties.GetProperties(System.Boolean)">
+ <summary>
+ Get the <c>PropertiesDictionary</c> for this thread.
+ </summary>
+ <param name="create">create the dictionary if it does not exist, otherwise return null if is does not exist</param>
+ <returns>the properties for this thread</returns>
+ <remarks>
+ <para>
+ The collection returned is only to be used on the calling thread. If the
+ caller needs to share the collection between different threads then the
+ caller must clone the collection before doing so.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.ThreadContextProperties.Item(System.String)">
+ <summary>
+ Gets or sets the value of a property
+ </summary>
+ <value>
+ The value for the property with the specified key
+ </value>
+ <remarks>
+ <para>
+ Gets or sets the value of a property
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.ThreadContextStack">
+ <summary>
+ Implementation of Stack for the <see cref="T:log4net.ThreadContext"/>
+ </summary>
+ <remarks>
+ <para>
+ Implementation of Stack for the <see cref="T:log4net.ThreadContext"/>
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="F:log4net.Util.ThreadContextStack.m_stack">
+ <summary>
+ The stack store.
+ </summary>
+ </member>
+ <member name="M:log4net.Util.ThreadContextStack.#ctor">
+ <summary>
+ Internal constructor
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.ThreadContextStack"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ThreadContextStack.Clear">
+ <summary>
+ Clears all the contextual information held in this stack.
+ </summary>
+ <remarks>
+ <para>
+ Clears all the contextual information held in this stack.
+ Only call this if you think that this tread is being reused after
+ a previous call execution which may not have completed correctly.
+ You do not need to use this method if you always guarantee to call
+ the <see cref="M:System.IDisposable.Dispose"/> method of the <see cref="T:System.IDisposable"/>
+ returned from <see cref="M:log4net.Util.ThreadContextStack.Push(System.String)"/> even in exceptional circumstances,
+ for example by using the <c>using(log4net.ThreadContext.Stacks["NDC"].Push("Stack_Message"))</c>
+ syntax.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ThreadContextStack.Pop">
+ <summary>
+ Removes the top context from this stack.
+ </summary>
+ <returns>The message in the context that was removed from the top of this stack.</returns>
+ <remarks>
+ <para>
+ Remove the top context from this stack, and return
+ it to the caller. If this stack is empty then an
+ empty string (not <see langword="null"/>) is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ThreadContextStack.Push(System.String)">
+ <summary>
+ Pushes a new context message into this stack.
+ </summary>
+ <param name="message">The new context message.</param>
+ <returns>
+ An <see cref="T:System.IDisposable"/> that can be used to clean up the context stack.
+ </returns>
+ <remarks>
+ <para>
+ Pushes a new context onto this stack. An <see cref="T:System.IDisposable"/>
+ is returned that can be used to clean up this stack. This
+ can be easily combined with the <c>using</c> keyword to scope the
+ context.
+ </para>
+ </remarks>
+ <example>Simple example of using the <c>Push</c> method with the <c>using</c> keyword.
+ <code lang="C#">
+ using(log4net.ThreadContext.Stacks["NDC"].Push("Stack_Message"))
+ {
+ log.Warn("This should have an ThreadContext Stack message");
+ }
+ </code>
+ </example>
+ </member>
+ <member name="M:log4net.Util.ThreadContextStack.GetFullMessage">
+ <summary>
+ Gets the current context information for this stack.
+ </summary>
+ <returns>The current context information.</returns>
+ </member>
+ <member name="M:log4net.Util.ThreadContextStack.ToString">
+ <summary>
+ Gets the current context information for this stack.
+ </summary>
+ <returns>Gets the current context information</returns>
+ <remarks>
+ <para>
+ Gets the current context information for this stack.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ThreadContextStack.log4net#Core#IFixingRequired#GetFixedObject">
+ <summary>
+ Get a portable version of this object
+ </summary>
+ <returns>the portable instance of this object</returns>
+ <remarks>
+ <para>
+ Get a cross thread portable version of this object
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.ThreadContextStack.Count">
+ <summary>
+ The number of messages in the stack
+ </summary>
+ <value>
+ The current number of messages in the stack
+ </value>
+ <remarks>
+ <para>
+ The current number of messages in the stack. That is
+ the number of times <see cref="M:log4net.Util.ThreadContextStack.Push(System.String)"/> has been called
+ minus the number of times <see cref="M:log4net.Util.ThreadContextStack.Pop"/> has been called.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.ThreadContextStack.InternalStack">
+ <summary>
+ Gets and sets the internal stack used by this <see cref="T:log4net.Util.ThreadContextStack"/>
+ </summary>
+ <value>The internal storage stack</value>
+ <remarks>
+ <para>
+ This property is provided only to support backward compatability
+ of the <see cref="T:log4net.NDC"/>. Tytpically the internal stack should not
+ be modified.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.ThreadContextStack.StackFrame">
+ <summary>
+ Inner class used to represent a single context frame in the stack.
+ </summary>
+ <remarks>
+ <para>
+ Inner class used to represent a single context frame in the stack.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ThreadContextStack.StackFrame.#ctor(System.String,log4net.Util.ThreadContextStack.StackFrame)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="message">The message for this context.</param>
+ <param name="parent">The parent context in the chain.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.ThreadContextStack.StackFrame"/> class
+ with the specified message and parent context.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.ThreadContextStack.StackFrame.Message">
+ <summary>
+ Get the message.
+ </summary>
+ <value>The message.</value>
+ <remarks>
+ <para>
+ Get the message.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.ThreadContextStack.StackFrame.FullMessage">
+ <summary>
+ Gets the full text of the context down to the root level.
+ </summary>
+ <value>
+ The full text of the context down to the root level.
+ </value>
+ <remarks>
+ <para>
+ Gets the full text of the context down to the root level.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.ThreadContextStack.AutoPopStackFrame">
+ <summary>
+ Struct returned from the <see cref="M:log4net.Util.ThreadContextStack.Push(System.String)"/> method.
+ </summary>
+ <remarks>
+ <para>
+ This struct implements the <see cref="T:System.IDisposable"/> and is designed to be used
+ with the <see langword="using"/> pattern to remove the stack frame at the end of the scope.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Util.ThreadContextStack.AutoPopStackFrame.m_frameStack">
+ <summary>
+ The ThreadContextStack internal stack
+ </summary>
+ </member>
+ <member name="F:log4net.Util.ThreadContextStack.AutoPopStackFrame.m_frameDepth">
+ <summary>
+ The depth to trim the stack to when this instance is disposed
+ </summary>
+ </member>
+ <member name="M:log4net.Util.ThreadContextStack.AutoPopStackFrame.#ctor(System.Collections.Stack,System.Int32)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="frameStack">The internal stack used by the ThreadContextStack.</param>
+ <param name="frameDepth">The depth to return the stack to when this object is disposed.</param>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.ThreadContextStack.AutoPopStackFrame"/> class with
+ the specified stack and return depth.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.ThreadContextStack.AutoPopStackFrame.Dispose">
+ <summary>
+ Returns the stack to the correct depth.
+ </summary>
+ <remarks>
+ <para>
+ Returns the stack to the correct depth.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.ThreadContextStacks">
+ <summary>
+ Implementation of Stacks collection for the <see cref="T:log4net.ThreadContext"/>
+ </summary>
+ <remarks>
+ <para>
+ Implementation of Stacks collection for the <see cref="T:log4net.ThreadContext"/>
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.Util.ThreadContextStacks.#ctor(log4net.Util.ContextPropertiesBase)">
+ <summary>
+ Internal constructor
+ </summary>
+ <remarks>
+ <para>
+ Initializes a new instance of the <see cref="T:log4net.Util.ThreadContextStacks"/> class.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.ThreadContextStacks.Item(System.String)">
+ <summary>
+ Gets the named thread context stack
+ </summary>
+ <value>
+ The named stack
+ </value>
+ <remarks>
+ <para>
+ Gets the named thread context stack
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.Transform">
+ <summary>
+ Utility class for transforming strings.
+ </summary>
+ <remarks>
+ <para>
+ Utility class for transforming strings.
+ </para>
+ </remarks>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.Util.Transform.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.Util.Transform"/> class.
+ </summary>
+ <remarks>
+ <para>
+ Uses a private access modifier to prevent instantiation of this class.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.Transform.WriteEscapedXmlString(System.Xml.XmlWriter,System.String,System.String)">
+ <summary>
+ Write a string to an <see cref="T:System.Xml.XmlWriter"/>
+ </summary>
+ <param name="writer">the writer to write to</param>
+ <param name="textData">the string to write</param>
+ <param name="invalidCharReplacement">The string to replace non XML compliant chars with</param>
+ <remarks>
+ <para>
+ The test is escaped either using XML escape entities
+ or using CDATA sections.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.Transform.MaskXmlInvalidCharacters(System.String,System.String)">
+ <summary>
+ Replace invalid XML characters in text string
+ </summary>
+ <param name="textData">the XML text input string</param>
+ <param name="mask">the string to use in place of invalid characters</param>
+ <returns>A string that does not contain invalid XML characters.</returns>
+ <remarks>
+ <para>
+ Certain Unicode code points are not allowed in the XML InfoSet, for
+ details see: <a href="http://www.w3.org/TR/REC-xml/#charsets">http://www.w3.org/TR/REC-xml/#charsets</a>.
+ </para>
+ <para>
+ This method replaces any illegal characters in the input string
+ with the mask string specified.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.Transform.CountSubstrings(System.String,System.String)">
+ <summary>
+ Count the number of times that the substring occurs in the text
+ </summary>
+ <param name="text">the text to search</param>
+ <param name="substring">the substring to find</param>
+ <returns>the number of times the substring occurs in the text</returns>
+ <remarks>
+ <para>
+ The substring is assumed to be non repeating within itself.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.WindowsSecurityContext">
+ <summary>
+ Impersonate a Windows Account
+ </summary>
+ <remarks>
+ <para>
+ This <see cref="T:log4net.Core.SecurityContext"/> impersonates a Windows account.
+ </para>
+ <para>
+ How the impersonation is done depends on the value of <see cref="M:log4net.Util.WindowsSecurityContext.Impersonate(System.Object)"/>.
+ This allows the context to either impersonate a set of user credentials specified
+ using username, domain name and password or to revert to the process credentials.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.WindowsSecurityContext.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ <remarks>
+ <para>
+ Default constructor
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.WindowsSecurityContext.ActivateOptions">
+ <summary>
+ Initialize the SecurityContext based on the options set.
+ </summary>
+ <remarks>
+ <para>
+ This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
+ activation scheme. The <see cref="M:log4net.Util.WindowsSecurityContext.ActivateOptions"/> method must
+ be called on this object after the configuration properties have
+ been set. Until <see cref="M:log4net.Util.WindowsSecurityContext.ActivateOptions"/> is called this
+ object is in an undefined state and must not be used.
+ </para>
+ <para>
+ If any of the configuration properties are modified then
+ <see cref="M:log4net.Util.WindowsSecurityContext.ActivateOptions"/> must be called again.
+ </para>
+ <para>
+ The security context will try to Logon the specified user account and
+ capture a primary token for impersonation.
+ </para>
+ </remarks>
+ <exception cref="T:System.ArgumentNullException">The required <see cref="P:log4net.Util.WindowsSecurityContext.UserName"/>,
+ <see cref="P:log4net.Util.WindowsSecurityContext.DomainName"/> or <see cref="P:log4net.Util.WindowsSecurityContext.Password"/> properties were not specified.</exception>
+ </member>
+ <member name="M:log4net.Util.WindowsSecurityContext.Impersonate(System.Object)">
+ <summary>
+ Impersonate the Windows account specified by the <see cref="P:log4net.Util.WindowsSecurityContext.UserName"/> and <see cref="P:log4net.Util.WindowsSecurityContext.DomainName"/> properties.
+ </summary>
+ <param name="state">caller provided state</param>
+ <returns>
+ An <see cref="T:System.IDisposable"/> instance that will revoke the impersonation of this SecurityContext
+ </returns>
+ <remarks>
+ <para>
+ Depending on the <see cref="P:log4net.Util.WindowsSecurityContext.Credentials"/> property either
+ impersonate a user using credentials supplied or revert
+ to the process credentials.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.WindowsSecurityContext.LogonUser(System.String,System.String,System.String)">
+ <summary>
+ Create a <see cref="T:System.Security.Principal.WindowsIdentity"/> given the userName, domainName and password.
+ </summary>
+ <param name="userName">the user name</param>
+ <param name="domainName">the domain name</param>
+ <param name="password">the password</param>
+ <returns>the <see cref="T:System.Security.Principal.WindowsIdentity"/> for the account specified</returns>
+ <remarks>
+ <para>
+ Uses the Windows API call LogonUser to get a principal token for the account. This
+ token is used to initialize the WindowsIdentity.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.WindowsSecurityContext.Credentials">
+ <summary>
+ Gets or sets the impersonation mode for this security context
+ </summary>
+ <value>
+ The impersonation mode for this security context
+ </value>
+ <remarks>
+ <para>
+ Impersonate either a user with user credentials or
+ revert this thread to the credentials of the process.
+ The value is one of the <see cref="T:log4net.Util.WindowsSecurityContext.ImpersonationMode"/>
+ enum.
+ </para>
+ <para>
+ The default value is <see cref="F:log4net.Util.WindowsSecurityContext.ImpersonationMode.User"/>
+ </para>
+ <para>
+ When the mode is set to <see cref="F:log4net.Util.WindowsSecurityContext.ImpersonationMode.User"/>
+ the user's credentials are established using the
+ <see cref="P:log4net.Util.WindowsSecurityContext.UserName"/>, <see cref="P:log4net.Util.WindowsSecurityContext.DomainName"/> and <see cref="P:log4net.Util.WindowsSecurityContext.Password"/>
+ values.
+ </para>
+ <para>
+ When the mode is set to <see cref="F:log4net.Util.WindowsSecurityContext.ImpersonationMode.Process"/>
+ no other properties need to be set. If the calling thread is
+ impersonating then it will be reverted back to the process credentials.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.WindowsSecurityContext.UserName">
+ <summary>
+ Gets or sets the Windows username for this security context
+ </summary>
+ <value>
+ The Windows username for this security context
+ </value>
+ <remarks>
+ <para>
+ This property must be set if <see cref="P:log4net.Util.WindowsSecurityContext.Credentials"/>
+ is set to <see cref="F:log4net.Util.WindowsSecurityContext.ImpersonationMode.User"/> (the default setting).
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.WindowsSecurityContext.DomainName">
+ <summary>
+ Gets or sets the Windows domain name for this security context
+ </summary>
+ <value>
+ The Windows domain name for this security context
+ </value>
+ <remarks>
+ <para>
+ The default value for <see cref="P:log4net.Util.WindowsSecurityContext.DomainName"/> is the local machine name
+ taken from the <see cref="P:System.Environment.MachineName"/> property.
+ </para>
+ <para>
+ This property must be set if <see cref="P:log4net.Util.WindowsSecurityContext.Credentials"/>
+ is set to <see cref="F:log4net.Util.WindowsSecurityContext.ImpersonationMode.User"/> (the default setting).
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.Util.WindowsSecurityContext.Password">
+ <summary>
+ Sets the password for the Windows account specified by the <see cref="P:log4net.Util.WindowsSecurityContext.UserName"/> and <see cref="P:log4net.Util.WindowsSecurityContext.DomainName"/> properties.
+ </summary>
+ <value>
+ The password for the Windows account specified by the <see cref="P:log4net.Util.WindowsSecurityContext.UserName"/> and <see cref="P:log4net.Util.WindowsSecurityContext.DomainName"/> properties.
+ </value>
+ <remarks>
+ <para>
+ This property must be set if <see cref="P:log4net.Util.WindowsSecurityContext.Credentials"/>
+ is set to <see cref="F:log4net.Util.WindowsSecurityContext.ImpersonationMode.User"/> (the default setting).
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.Util.WindowsSecurityContext.ImpersonationMode">
+ <summary>
+ The impersonation modes for the <see cref="T:log4net.Util.WindowsSecurityContext"/>
+ </summary>
+ <remarks>
+ <para>
+ See the <see cref="P:log4net.Util.WindowsSecurityContext.Credentials"/> property for
+ details.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.Util.WindowsSecurityContext.ImpersonationMode.User">
+ <summary>
+ Impersonate a user using the credentials supplied
+ </summary>
+ </member>
+ <member name="F:log4net.Util.WindowsSecurityContext.ImpersonationMode.Process">
+ <summary>
+ Revert this the thread to the credentials of the process
+ </summary>
+ </member>
+ <member name="T:log4net.Util.WindowsSecurityContext.DisposableImpersonationContext">
+ <summary>
+ Adds <see cref="T:System.IDisposable"/> to <see cref="T:System.Security.Principal.WindowsImpersonationContext"/>
+ </summary>
+ <remarks>
+ <para>
+ Helper class to expose the <see cref="T:System.Security.Principal.WindowsImpersonationContext"/>
+ through the <see cref="T:System.IDisposable"/> interface.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.WindowsSecurityContext.DisposableImpersonationContext.#ctor(System.Security.Principal.WindowsImpersonationContext)">
+ <summary>
+ Constructor
+ </summary>
+ <param name="impersonationContext">the impersonation context being wrapped</param>
+ <remarks>
+ <para>
+ Constructor
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.Util.WindowsSecurityContext.DisposableImpersonationContext.Dispose">
+ <summary>
+ Revert the impersonation
+ </summary>
+ <remarks>
+ <para>
+ Revert the impersonation
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.GlobalContext">
+ <summary>
+ The log4net Global Context.
+ </summary>
+ <remarks>
+ <para>
+ The <c>GlobalContext</c> provides a location for global debugging
+ information to be stored.
+ </para>
+ <para>
+ The global context has a properties map and these properties can
+ be included in the output of log messages. The <see cref="T:log4net.Layout.PatternLayout"/>
+ supports selecting and outputing these properties.
+ </para>
+ <para>
+ By default the <c>log4net:HostName</c> property is set to the name of
+ the current machine.
+ </para>
+ </remarks>
+ <example>
+ <code lang="C#">
+ GlobalContext.Properties["hostname"] = Environment.MachineName;
+ </code>
+ </example>
+ <threadsafety static="true" instance="true"/>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.GlobalContext.#ctor">
+ <summary>
+ Private Constructor.
+ </summary>
+ <remarks>
+ Uses a private access modifier to prevent instantiation of this class.
+ </remarks>
+ </member>
+ <member name="F:log4net.GlobalContext.s_properties">
+ <summary>
+ The global context properties instance
+ </summary>
+ </member>
+ <member name="P:log4net.GlobalContext.Properties">
+ <summary>
+ The global properties map.
+ </summary>
+ <value>
+ The global properties map.
+ </value>
+ <remarks>
+ <para>
+ The global properties map.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.LogicalThreadContext">
+ <summary>
+ The log4net Logical Thread Context.
+ </summary>
+ <remarks>
+ <para>
+ The <c>LogicalThreadContext</c> provides a location for <see cref="T:System.Runtime.Remoting.Messaging.CallContext"/> specific debugging
+ information to be stored.
+ The <c>LogicalThreadContext</c> properties override any <see cref="T:log4net.ThreadContext"/> or <see cref="T:log4net.GlobalContext"/>
+ properties with the same name.
+ </para>
+ <para>
+ The Logical Thread Context has a properties map and a stack.
+ The properties and stack can
+ be included in the output of log messages. The <see cref="T:log4net.Layout.PatternLayout"/>
+ supports selecting and outputting these properties.
+ </para>
+ <para>
+ The Logical Thread Context provides a diagnostic context for the current call context.
+ This is an instrument for distinguishing interleaved log
+ output from different sources. Log output is typically interleaved
+ when a server handles multiple clients near-simultaneously.
+ </para>
+ <para>
+ The Logical Thread Context is managed on a per <see cref="T:System.Runtime.Remoting.Messaging.CallContext"/> basis.
+ </para>
+ </remarks>
+ <example>Example of using the thread context properties to store a username.
+ <code lang="C#">
+ LogicalThreadContext.Properties["user"] = userName;
+ log.Info("This log message has a LogicalThreadContext Property called 'user'");
+ </code>
+ </example>
+ <example>Example of how to push a message into the context stack
+ <code lang="C#">
+ using(LogicalThreadContext.Stacks["LDC"].Push("my context message"))
+ {
+ log.Info("This log message has a LogicalThreadContext Stack message that includes 'my context message'");
+
+ } // at the end of the using block the message is automatically popped
+ </code>
+ </example>
+ <threadsafety static="true" instance="true"/>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.LogicalThreadContext.#ctor">
+ <summary>
+ Private Constructor.
+ </summary>
+ <remarks>
+ <para>
+ Uses a private access modifier to prevent instantiation of this class.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.LogicalThreadContext.s_properties">
+ <summary>
+ The thread context properties instance
+ </summary>
+ </member>
+ <member name="F:log4net.LogicalThreadContext.s_stacks">
+ <summary>
+ The thread context stacks instance
+ </summary>
+ </member>
+ <member name="P:log4net.LogicalThreadContext.Properties">
+ <summary>
+ The thread properties map
+ </summary>
+ <value>
+ The thread properties map
+ </value>
+ <remarks>
+ <para>
+ The <c>LogicalThreadContext</c> properties override any <see cref="T:log4net.ThreadContext"/>
+ or <see cref="T:log4net.GlobalContext"/> properties with the same name.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.LogicalThreadContext.Stacks">
+ <summary>
+ The thread stacks
+ </summary>
+ <value>
+ stack map
+ </value>
+ <remarks>
+ <para>
+ The logical thread stacks.
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.LogManager">
+ <summary>
+ This class is used by client applications to request logger instances.
+ </summary>
+ <remarks>
+ <para>
+ This class has static methods that are used by a client to request
+ a logger instance. The <see cref="M:log4net.LogManager.GetLogger(System.String)"/> method is
+ used to retrieve a logger.
+ </para>
+ <para>
+ See the <see cref="T:log4net.ILog"/> interface for more details.
+ </para>
+ </remarks>
+ <example>Simple example of logging messages
+ <code lang="C#">
+ ILog log = LogManager.GetLogger("application-log");
+
+ log.Info("Application Start");
+ log.Debug("This is a debug message");
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("This is another debug message");
+ }
+ </code>
+ </example>
+ <threadsafety static="true" instance="true"/>
+ <seealso cref="T:log4net.ILog"/>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.LogManager.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.LogManager"/> class.
+ </summary>
+ <remarks>
+ Uses a private access modifier to prevent instantiation of this class.
+ </remarks>
+ </member>
+ <member name="M:log4net.LogManager.Exists(System.String)">
+ <overloads>Returns the named logger if it exists.</overloads>
+ <summary>
+ Returns the named logger if it exists.
+ </summary>
+ <remarks>
+ <para>
+ If the named logger exists (in the default repository) then it
+ returns a reference to the logger, otherwise it returns <c>null</c>.
+ </para>
+ </remarks>
+ <param name="name">The fully qualified logger name to look for.</param>
+ <returns>The logger found, or <c>null</c> if no logger could be found.</returns>
+ </member>
+ <member name="M:log4net.LogManager.Exists(System.String,System.String)">
+ <summary>
+ Returns the named logger if it exists.
+ </summary>
+ <remarks>
+ <para>
+ If the named logger exists (in the specified repository) then it
+ returns a reference to the logger, otherwise it returns
+ <c>null</c>.
+ </para>
+ </remarks>
+ <param name="repository">The repository to lookup in.</param>
+ <param name="name">The fully qualified logger name to look for.</param>
+ <returns>
+ The logger found, or <c>null</c> if the logger doesn't exist in the specified
+ repository.
+ </returns>
+ </member>
+ <member name="M:log4net.LogManager.Exists(System.Reflection.Assembly,System.String)">
+ <summary>
+ Returns the named logger if it exists.
+ </summary>
+ <remarks>
+ <para>
+ If the named logger exists (in the repository for the specified assembly) then it
+ returns a reference to the logger, otherwise it returns
+ <c>null</c>.
+ </para>
+ </remarks>
+ <param name="repositoryAssembly">The assembly to use to lookup the repository.</param>
+ <param name="name">The fully qualified logger name to look for.</param>
+ <returns>
+ The logger, or <c>null</c> if the logger doesn't exist in the specified
+ assembly's repository.
+ </returns>
+ </member>
+ <member name="M:log4net.LogManager.GetCurrentLoggers">
+ <overloads>Get the currently defined loggers.</overloads>
+ <summary>
+ Returns all the currently defined loggers in the default repository.
+ </summary>
+ <remarks>
+ <para>The root logger is <b>not</b> included in the returned array.</para>
+ </remarks>
+ <returns>All the defined loggers.</returns>
+ </member>
+ <member name="M:log4net.LogManager.GetCurrentLoggers(System.String)">
+ <summary>
+ Returns all the currently defined loggers in the specified repository.
+ </summary>
+ <param name="repository">The repository to lookup in.</param>
+ <remarks>
+ The root logger is <b>not</b> included in the returned array.
+ </remarks>
+ <returns>All the defined loggers.</returns>
+ </member>
+ <member name="M:log4net.LogManager.GetCurrentLoggers(System.Reflection.Assembly)">
+ <summary>
+ Returns all the currently defined loggers in the specified assembly's repository.
+ </summary>
+ <param name="repositoryAssembly">The assembly to use to lookup the repository.</param>
+ <remarks>
+ The root logger is <b>not</b> included in the returned array.
+ </remarks>
+ <returns>All the defined loggers.</returns>
+ </member>
+ <member name="M:log4net.LogManager.GetLogger(System.String)">
+ <overloads>Get or create a logger.</overloads>
+ <summary>
+ Retrieves or creates a named logger.
+ </summary>
+ <remarks>
+ <para>
+ Retrieves a logger named as the <paramref name="name"/>
+ parameter. If the named logger already exists, then the
+ existing instance will be returned. Otherwise, a new instance is
+ created.
+ </para>
+ <para>By default, loggers do not have a set level but inherit
+ it from the hierarchy. This is one of the central features of
+ log4net.
+ </para>
+ </remarks>
+ <param name="name">The name of the logger to retrieve.</param>
+ <returns>The logger with the name specified.</returns>
+ </member>
+ <member name="M:log4net.LogManager.GetLogger(System.String,System.String)">
+ <summary>
+ Retrieves or creates a named logger.
+ </summary>
+ <remarks>
+ <para>
+ Retrieve a logger named as the <paramref name="name"/>
+ parameter. If the named logger already exists, then the
+ existing instance will be returned. Otherwise, a new instance is
+ created.
+ </para>
+ <para>
+ By default, loggers do not have a set level but inherit
+ it from the hierarchy. This is one of the central features of
+ log4net.
+ </para>
+ </remarks>
+ <param name="repository">The repository to lookup in.</param>
+ <param name="name">The name of the logger to retrieve.</param>
+ <returns>The logger with the name specified.</returns>
+ </member>
+ <member name="M:log4net.LogManager.GetLogger(System.Reflection.Assembly,System.String)">
+ <summary>
+ Retrieves or creates a named logger.
+ </summary>
+ <remarks>
+ <para>
+ Retrieve a logger named as the <paramref name="name"/>
+ parameter. If the named logger already exists, then the
+ existing instance will be returned. Otherwise, a new instance is
+ created.
+ </para>
+ <para>
+ By default, loggers do not have a set level but inherit
+ it from the hierarchy. This is one of the central features of
+ log4net.
+ </para>
+ </remarks>
+ <param name="repositoryAssembly">The assembly to use to lookup the repository.</param>
+ <param name="name">The name of the logger to retrieve.</param>
+ <returns>The logger with the name specified.</returns>
+ </member>
+ <member name="M:log4net.LogManager.GetLogger(System.Type)">
+ <summary>
+ Shorthand for <see cref="M:log4net.LogManager.GetLogger(System.String)"/>.
+ </summary>
+ <remarks>
+ Get the logger for the fully qualified name of the type specified.
+ </remarks>
+ <param name="type">The full name of <paramref name="type"/> will be used as the name of the logger to retrieve.</param>
+ <returns>The logger with the name specified.</returns>
+ </member>
+ <member name="M:log4net.LogManager.GetLogger(System.String,System.Type)">
+ <summary>
+ Shorthand for <see cref="M:log4net.LogManager.GetLogger(System.String)"/>.
+ </summary>
+ <remarks>
+ Gets the logger for the fully qualified name of the type specified.
+ </remarks>
+ <param name="repository">The repository to lookup in.</param>
+ <param name="type">The full name of <paramref name="type"/> will be used as the name of the logger to retrieve.</param>
+ <returns>The logger with the name specified.</returns>
+ </member>
+ <member name="M:log4net.LogManager.GetLogger(System.Reflection.Assembly,System.Type)">
+ <summary>
+ Shorthand for <see cref="M:log4net.LogManager.GetLogger(System.String)"/>.
+ </summary>
+ <remarks>
+ Gets the logger for the fully qualified name of the type specified.
+ </remarks>
+ <param name="repositoryAssembly">The assembly to use to lookup the repository.</param>
+ <param name="type">The full name of <paramref name="type"/> will be used as the name of the logger to retrieve.</param>
+ <returns>The logger with the name specified.</returns>
+ </member>
+ <member name="M:log4net.LogManager.Shutdown">
+ <summary>
+ Shuts down the log4net system.
+ </summary>
+ <remarks>
+ <para>
+ Calling this method will <b>safely</b> close and remove all
+ appenders in all the loggers including root contained in all the
+ default repositories.
+ </para>
+ <para>
+ Some appenders need to be closed before the application exists.
+ Otherwise, pending logging events might be lost.
+ </para>
+ <para>The <c>shutdown</c> method is careful to close nested
+ appenders before closing regular appenders. This is allows
+ configurations where a regular appender is attached to a logger
+ and again to a nested appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.LogManager.ShutdownRepository">
+ <overloads>Shutdown a logger repository.</overloads>
+ <summary>
+ Shuts down the default repository.
+ </summary>
+ <remarks>
+ <para>
+ Calling this method will <b>safely</b> close and remove all
+ appenders in all the loggers including root contained in the
+ default repository.
+ </para>
+ <para>Some appenders need to be closed before the application exists.
+ Otherwise, pending logging events might be lost.
+ </para>
+ <para>The <c>shutdown</c> method is careful to close nested
+ appenders before closing regular appenders. This is allows
+ configurations where a regular appender is attached to a logger
+ and again to a nested appender.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.LogManager.ShutdownRepository(System.String)">
+ <summary>
+ Shuts down the repository for the repository specified.
+ </summary>
+ <remarks>
+ <para>
+ Calling this method will <b>safely</b> close and remove all
+ appenders in all the loggers including root contained in the
+ <paramref name="repository"/> specified.
+ </para>
+ <para>
+ Some appenders need to be closed before the application exists.
+ Otherwise, pending logging events might be lost.
+ </para>
+ <para>The <c>shutdown</c> method is careful to close nested
+ appenders before closing regular appenders. This is allows
+ configurations where a regular appender is attached to a logger
+ and again to a nested appender.
+ </para>
+ </remarks>
+ <param name="repository">The repository to shutdown.</param>
+ </member>
+ <member name="M:log4net.LogManager.ShutdownRepository(System.Reflection.Assembly)">
+ <summary>
+ Shuts down the repository specified.
+ </summary>
+ <remarks>
+ <para>
+ Calling this method will <b>safely</b> close and remove all
+ appenders in all the loggers including root contained in the
+ repository. The repository is looked up using
+ the <paramref name="repositoryAssembly"/> specified.
+ </para>
+ <para>
+ Some appenders need to be closed before the application exists.
+ Otherwise, pending logging events might be lost.
+ </para>
+ <para>
+ The <c>shutdown</c> method is careful to close nested
+ appenders before closing regular appenders. This is allows
+ configurations where a regular appender is attached to a logger
+ and again to a nested appender.
+ </para>
+ </remarks>
+ <param name="repositoryAssembly">The assembly to use to lookup the repository.</param>
+ </member>
+ <member name="M:log4net.LogManager.ResetConfiguration">
+ <overloads>Reset the configuration of a repository</overloads>
+ <summary>
+ Resets all values contained in this repository instance to their defaults.
+ </summary>
+ <remarks>
+ <para>
+ Resets all values contained in the repository instance to their
+ defaults. This removes all appenders from all loggers, sets
+ the level of all non-root loggers to <c>null</c>,
+ sets their additivity flag to <c>true</c> and sets the level
+ of the root logger to <see cref="F:log4net.Core.Level.Debug"/>. Moreover,
+ message disabling is set to its default "off" value.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.LogManager.ResetConfiguration(System.String)">
+ <summary>
+ Resets all values contained in this repository instance to their defaults.
+ </summary>
+ <remarks>
+ <para>
+ Reset all values contained in the repository instance to their
+ defaults. This removes all appenders from all loggers, sets
+ the level of all non-root loggers to <c>null</c>,
+ sets their additivity flag to <c>true</c> and sets the level
+ of the root logger to <see cref="F:log4net.Core.Level.Debug"/>. Moreover,
+ message disabling is set to its default "off" value.
+ </para>
+ </remarks>
+ <param name="repository">The repository to reset.</param>
+ </member>
+ <member name="M:log4net.LogManager.ResetConfiguration(System.Reflection.Assembly)">
+ <summary>
+ Resets all values contained in this repository instance to their defaults.
+ </summary>
+ <remarks>
+ <para>
+ Reset all values contained in the repository instance to their
+ defaults. This removes all appenders from all loggers, sets
+ the level of all non-root loggers to <c>null</c>,
+ sets their additivity flag to <c>true</c> and sets the level
+ of the root logger to <see cref="F:log4net.Core.Level.Debug"/>. Moreover,
+ message disabling is set to its default "off" value.
+ </para>
+ </remarks>
+ <param name="repositoryAssembly">The assembly to use to lookup the repository to reset.</param>
+ </member>
+ <member name="M:log4net.LogManager.GetLoggerRepository">
+ <overloads>Get the logger repository.</overloads>
+ <summary>
+ Returns the default <see cref="T:log4net.Repository.ILoggerRepository"/> instance.
+ </summary>
+ <remarks>
+ <para>
+ Gets the <see cref="T:log4net.Repository.ILoggerRepository"/> for the repository specified
+ by the callers assembly (<see cref="M:System.Reflection.Assembly.GetCallingAssembly"/>).
+ </para>
+ </remarks>
+ <returns>The <see cref="T:log4net.Repository.ILoggerRepository"/> instance for the default repository.</returns>
+ </member>
+ <member name="M:log4net.LogManager.GetLoggerRepository(System.String)">
+ <summary>
+ Returns the default <see cref="T:log4net.Repository.ILoggerRepository"/> instance.
+ </summary>
+ <returns>The default <see cref="T:log4net.Repository.ILoggerRepository"/> instance.</returns>
+ <remarks>
+ <para>
+ Gets the <see cref="T:log4net.Repository.ILoggerRepository"/> for the repository specified
+ by the <paramref name="repository"/> argument.
+ </para>
+ </remarks>
+ <param name="repository">The repository to lookup in.</param>
+ </member>
+ <member name="M:log4net.LogManager.GetLoggerRepository(System.Reflection.Assembly)">
+ <summary>
+ Returns the default <see cref="T:log4net.Repository.ILoggerRepository"/> instance.
+ </summary>
+ <returns>The default <see cref="T:log4net.Repository.ILoggerRepository"/> instance.</returns>
+ <remarks>
+ <para>
+ Gets the <see cref="T:log4net.Repository.ILoggerRepository"/> for the repository specified
+ by the <paramref name="repositoryAssembly"/> argument.
+ </para>
+ </remarks>
+ <param name="repositoryAssembly">The assembly to use to lookup the repository.</param>
+ </member>
+ <member name="M:log4net.LogManager.GetRepository">
+ <overloads>Get a logger repository.</overloads>
+ <summary>
+ Returns the default <see cref="T:log4net.Repository.ILoggerRepository"/> instance.
+ </summary>
+ <remarks>
+ <para>
+ Gets the <see cref="T:log4net.Repository.ILoggerRepository"/> for the repository specified
+ by the callers assembly (<see cref="M:System.Reflection.Assembly.GetCallingAssembly"/>).
+ </para>
+ </remarks>
+ <returns>The <see cref="T:log4net.Repository.ILoggerRepository"/> instance for the default repository.</returns>
+ </member>
+ <member name="M:log4net.LogManager.GetRepository(System.String)">
+ <summary>
+ Returns the default <see cref="T:log4net.Repository.ILoggerRepository"/> instance.
+ </summary>
+ <returns>The default <see cref="T:log4net.Repository.ILoggerRepository"/> instance.</returns>
+ <remarks>
+ <para>
+ Gets the <see cref="T:log4net.Repository.ILoggerRepository"/> for the repository specified
+ by the <paramref name="repository"/> argument.
+ </para>
+ </remarks>
+ <param name="repository">The repository to lookup in.</param>
+ </member>
+ <member name="M:log4net.LogManager.GetRepository(System.Reflection.Assembly)">
+ <summary>
+ Returns the default <see cref="T:log4net.Repository.ILoggerRepository"/> instance.
+ </summary>
+ <returns>The default <see cref="T:log4net.Repository.ILoggerRepository"/> instance.</returns>
+ <remarks>
+ <para>
+ Gets the <see cref="T:log4net.Repository.ILoggerRepository"/> for the repository specified
+ by the <paramref name="repositoryAssembly"/> argument.
+ </para>
+ </remarks>
+ <param name="repositoryAssembly">The assembly to use to lookup the repository.</param>
+ </member>
+ <member name="M:log4net.LogManager.CreateDomain(System.Type)">
+ <overloads>Create a domain</overloads>
+ <summary>
+ Creates a repository with the specified repository type.
+ </summary>
+ <remarks>
+ <para>
+ <b>CreateDomain is obsolete. Use CreateRepository instead of CreateDomain.</b>
+ </para>
+ <para>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> created will be associated with the repository
+ specified such that a call to <see cref="M:log4net.LogManager.GetRepository"/> will return
+ the same repository instance.
+ </para>
+ </remarks>
+ <param name="repositoryType">A <see cref="T:System.Type"/> that implements <see cref="T:log4net.Repository.ILoggerRepository"/>
+ and has a no arg constructor. An instance of this type will be created to act
+ as the <see cref="T:log4net.Repository.ILoggerRepository"/> for the repository specified.</param>
+ <returns>The <see cref="T:log4net.Repository.ILoggerRepository"/> created for the repository.</returns>
+ </member>
+ <member name="M:log4net.LogManager.CreateRepository(System.Type)">
+ <overloads>Create a logger repository.</overloads>
+ <summary>
+ Creates a repository with the specified repository type.
+ </summary>
+ <param name="repositoryType">A <see cref="T:System.Type"/> that implements <see cref="T:log4net.Repository.ILoggerRepository"/>
+ and has a no arg constructor. An instance of this type will be created to act
+ as the <see cref="T:log4net.Repository.ILoggerRepository"/> for the repository specified.</param>
+ <returns>The <see cref="T:log4net.Repository.ILoggerRepository"/> created for the repository.</returns>
+ <remarks>
+ <para>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> created will be associated with the repository
+ specified such that a call to <see cref="M:log4net.LogManager.GetRepository"/> will return
+ the same repository instance.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.LogManager.CreateDomain(System.String)">
+ <summary>
+ Creates a repository with the specified name.
+ </summary>
+ <remarks>
+ <para>
+ <b>CreateDomain is obsolete. Use CreateRepository instead of CreateDomain.</b>
+ </para>
+ <para>
+ Creates the default type of <see cref="T:log4net.Repository.ILoggerRepository"/> which is a
+ <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/> object.
+ </para>
+ <para>
+ The <paramref name="repository"/> name must be unique. Repositories cannot be redefined.
+ An <see cref="T:System.Exception"/> will be thrown if the repository already exists.
+ </para>
+ </remarks>
+ <param name="repository">The name of the repository, this must be unique amongst repositories.</param>
+ <returns>The <see cref="T:log4net.Repository.ILoggerRepository"/> created for the repository.</returns>
+ <exception cref="T:log4net.Core.LogException">The specified repository already exists.</exception>
+ </member>
+ <member name="M:log4net.LogManager.CreateRepository(System.String)">
+ <summary>
+ Creates a repository with the specified name.
+ </summary>
+ <remarks>
+ <para>
+ Creates the default type of <see cref="T:log4net.Repository.ILoggerRepository"/> which is a
+ <see cref="T:log4net.Repository.Hierarchy.Hierarchy"/> object.
+ </para>
+ <para>
+ The <paramref name="repository"/> name must be unique. Repositories cannot be redefined.
+ An <see cref="T:System.Exception"/> will be thrown if the repository already exists.
+ </para>
+ </remarks>
+ <param name="repository">The name of the repository, this must be unique amongst repositories.</param>
+ <returns>The <see cref="T:log4net.Repository.ILoggerRepository"/> created for the repository.</returns>
+ <exception cref="T:log4net.Core.LogException">The specified repository already exists.</exception>
+ </member>
+ <member name="M:log4net.LogManager.CreateDomain(System.String,System.Type)">
+ <summary>
+ Creates a repository with the specified name and repository type.
+ </summary>
+ <remarks>
+ <para>
+ <b>CreateDomain is obsolete. Use CreateRepository instead of CreateDomain.</b>
+ </para>
+ <para>
+ The <paramref name="repository"/> name must be unique. Repositories cannot be redefined.
+ An <see cref="T:System.Exception"/> will be thrown if the repository already exists.
+ </para>
+ </remarks>
+ <param name="repository">The name of the repository, this must be unique to the repository.</param>
+ <param name="repositoryType">A <see cref="T:System.Type"/> that implements <see cref="T:log4net.Repository.ILoggerRepository"/>
+ and has a no arg constructor. An instance of this type will be created to act
+ as the <see cref="T:log4net.Repository.ILoggerRepository"/> for the repository specified.</param>
+ <returns>The <see cref="T:log4net.Repository.ILoggerRepository"/> created for the repository.</returns>
+ <exception cref="T:log4net.Core.LogException">The specified repository already exists.</exception>
+ </member>
+ <member name="M:log4net.LogManager.CreateRepository(System.String,System.Type)">
+ <summary>
+ Creates a repository with the specified name and repository type.
+ </summary>
+ <remarks>
+ <para>
+ The <paramref name="repository"/> name must be unique. Repositories cannot be redefined.
+ An <see cref="T:System.Exception"/> will be thrown if the repository already exists.
+ </para>
+ </remarks>
+ <param name="repository">The name of the repository, this must be unique to the repository.</param>
+ <param name="repositoryType">A <see cref="T:System.Type"/> that implements <see cref="T:log4net.Repository.ILoggerRepository"/>
+ and has a no arg constructor. An instance of this type will be created to act
+ as the <see cref="T:log4net.Repository.ILoggerRepository"/> for the repository specified.</param>
+ <returns>The <see cref="T:log4net.Repository.ILoggerRepository"/> created for the repository.</returns>
+ <exception cref="T:log4net.Core.LogException">The specified repository already exists.</exception>
+ </member>
+ <member name="M:log4net.LogManager.CreateDomain(System.Reflection.Assembly,System.Type)">
+ <summary>
+ Creates a repository for the specified assembly and repository type.
+ </summary>
+ <remarks>
+ <para>
+ <b>CreateDomain is obsolete. Use CreateRepository instead of CreateDomain.</b>
+ </para>
+ <para>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> created will be associated with the repository
+ specified such that a call to <see cref="M:log4net.LogManager.GetRepository(System.Reflection.Assembly)"/> with the
+ same assembly specified will return the same repository instance.
+ </para>
+ </remarks>
+ <param name="repositoryAssembly">The assembly to use to get the name of the repository.</param>
+ <param name="repositoryType">A <see cref="T:System.Type"/> that implements <see cref="T:log4net.Repository.ILoggerRepository"/>
+ and has a no arg constructor. An instance of this type will be created to act
+ as the <see cref="T:log4net.Repository.ILoggerRepository"/> for the repository specified.</param>
+ <returns>The <see cref="T:log4net.Repository.ILoggerRepository"/> created for the repository.</returns>
+ </member>
+ <member name="M:log4net.LogManager.CreateRepository(System.Reflection.Assembly,System.Type)">
+ <summary>
+ Creates a repository for the specified assembly and repository type.
+ </summary>
+ <remarks>
+ <para>
+ The <see cref="T:log4net.Repository.ILoggerRepository"/> created will be associated with the repository
+ specified such that a call to <see cref="M:log4net.LogManager.GetRepository(System.Reflection.Assembly)"/> with the
+ same assembly specified will return the same repository instance.
+ </para>
+ </remarks>
+ <param name="repositoryAssembly">The assembly to use to get the name of the repository.</param>
+ <param name="repositoryType">A <see cref="T:System.Type"/> that implements <see cref="T:log4net.Repository.ILoggerRepository"/>
+ and has a no arg constructor. An instance of this type will be created to act
+ as the <see cref="T:log4net.Repository.ILoggerRepository"/> for the repository specified.</param>
+ <returns>The <see cref="T:log4net.Repository.ILoggerRepository"/> created for the repository.</returns>
+ </member>
+ <member name="M:log4net.LogManager.GetAllRepositories">
+ <summary>
+ Gets the list of currently defined repositories.
+ </summary>
+ <remarks>
+ <para>
+ Get an array of all the <see cref="T:log4net.Repository.ILoggerRepository"/> objects that have been created.
+ </para>
+ </remarks>
+ <returns>An array of all the known <see cref="T:log4net.Repository.ILoggerRepository"/> objects.</returns>
+ </member>
+ <member name="M:log4net.LogManager.WrapLogger(log4net.Core.ILogger)">
+ <summary>
+ Looks up the wrapper object for the logger specified.
+ </summary>
+ <param name="logger">The logger to get the wrapper for.</param>
+ <returns>The wrapper for the logger specified.</returns>
+ </member>
+ <member name="M:log4net.LogManager.WrapLoggers(log4net.Core.ILogger[])">
+ <summary>
+ Looks up the wrapper objects for the loggers specified.
+ </summary>
+ <param name="loggers">The loggers to get the wrappers for.</param>
+ <returns>The wrapper objects for the loggers specified.</returns>
+ </member>
+ <member name="M:log4net.LogManager.WrapperCreationHandler(log4net.Core.ILogger)">
+ <summary>
+ Create the <see cref="T:log4net.Core.ILoggerWrapper"/> objects used by
+ this manager.
+ </summary>
+ <param name="logger">The logger to wrap.</param>
+ <returns>The wrapper for the logger specified.</returns>
+ </member>
+ <member name="F:log4net.LogManager.s_wrapperMap">
+ <summary>
+ The wrapper map to use to hold the <see cref="T:log4net.Core.LogImpl"/> objects.
+ </summary>
+ </member>
+ <member name="T:log4net.MDC">
+ <summary>
+ Implementation of Mapped Diagnostic Contexts.
+ </summary>
+ <remarks>
+ <note>
+ <para>
+ The MDC is deprecated and has been replaced by the <see cref="P:log4net.ThreadContext.Properties"/>.
+ The current MDC implementation forwards to the <c>ThreadContext.Properties</c>.
+ </para>
+ </note>
+ <para>
+ The MDC class is similar to the <see cref="T:log4net.NDC"/> class except that it is
+ based on a map instead of a stack. It provides <i>mapped
+ diagnostic contexts</i>. A <i>Mapped Diagnostic Context</i>, or
+ MDC in short, is an instrument for distinguishing interleaved log
+ output from different sources. Log output is typically interleaved
+ when a server handles multiple clients near-simultaneously.
+ </para>
+ <para>
+ The MDC is managed on a per thread basis.
+ </para>
+ </remarks>
+ <threadsafety static="true" instance="true"/>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.MDC.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.MDC"/> class.
+ </summary>
+ <remarks>
+ Uses a private access modifier to prevent instantiation of this class.
+ </remarks>
+ </member>
+ <member name="M:log4net.MDC.Get(System.String)">
+ <summary>
+ Gets the context value identified by the <paramref name="key"/> parameter.
+ </summary>
+ <param name="key">The key to lookup in the MDC.</param>
+ <returns>The string value held for the key, or a <c>null</c> reference if no corresponding value is found.</returns>
+ <remarks>
+ <note>
+ <para>
+ The MDC is deprecated and has been replaced by the <see cref="P:log4net.ThreadContext.Properties"/>.
+ The current MDC implementation forwards to the <c>ThreadContext.Properties</c>.
+ </para>
+ </note>
+ <para>
+ If the <paramref name="key"/> parameter does not look up to a
+ previously defined context then <c>null</c> will be returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.MDC.Set(System.String,System.String)">
+ <summary>
+ Add an entry to the MDC
+ </summary>
+ <param name="key">The key to store the value under.</param>
+ <param name="value">The value to store.</param>
+ <remarks>
+ <note>
+ <para>
+ The MDC is deprecated and has been replaced by the <see cref="P:log4net.ThreadContext.Properties"/>.
+ The current MDC implementation forwards to the <c>ThreadContext.Properties</c>.
+ </para>
+ </note>
+ <para>
+ Puts a context value (the <paramref name="val"/> parameter) as identified
+ with the <paramref name="key"/> parameter into the current thread's
+ context map.
+ </para>
+ <para>
+ If a value is already defined for the <paramref name="key"/>
+ specified then the value will be replaced. If the <paramref name="val"/>
+ is specified as <c>null</c> then the key value mapping will be removed.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.MDC.Remove(System.String)">
+ <summary>
+ Removes the key value mapping for the key specified.
+ </summary>
+ <param name="key">The key to remove.</param>
+ <remarks>
+ <note>
+ <para>
+ The MDC is deprecated and has been replaced by the <see cref="P:log4net.ThreadContext.Properties"/>.
+ The current MDC implementation forwards to the <c>ThreadContext.Properties</c>.
+ </para>
+ </note>
+ <para>
+ Remove the specified entry from this thread's MDC
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.MDC.Clear">
+ <summary>
+ Clear all entries in the MDC
+ </summary>
+ <remarks>
+ <note>
+ <para>
+ The MDC is deprecated and has been replaced by the <see cref="P:log4net.ThreadContext.Properties"/>.
+ The current MDC implementation forwards to the <c>ThreadContext.Properties</c>.
+ </para>
+ </note>
+ <para>
+ Remove all the entries from this thread's MDC
+ </para>
+ </remarks>
+ </member>
+ <member name="T:log4net.NDC">
+ <summary>
+ Implementation of Nested Diagnostic Contexts.
+ </summary>
+ <remarks>
+ <note>
+ <para>
+ The NDC is deprecated and has been replaced by the <see cref="P:log4net.ThreadContext.Stacks"/>.
+ The current NDC implementation forwards to the <c>ThreadContext.Stacks["NDC"]</c>.
+ </para>
+ </note>
+ <para>
+ A Nested Diagnostic Context, or NDC in short, is an instrument
+ to distinguish interleaved log output from different sources. Log
+ output is typically interleaved when a server handles multiple
+ clients near-simultaneously.
+ </para>
+ <para>
+ Interleaved log output can still be meaningful if each log entry
+ from different contexts had a distinctive stamp. This is where NDCs
+ come into play.
+ </para>
+ <para>
+ Note that NDCs are managed on a per thread basis. The NDC class
+ is made up of static methods that operate on the context of the
+ calling thread.
+ </para>
+ </remarks>
+ <example>How to push a message into the context
+ <code lang="C#">
+ using(NDC.Push("my context message"))
+ {
+ ... all log calls will have 'my context message' included ...
+
+ } // at the end of the using block the message is automatically removed
+ </code>
+ </example>
+ <threadsafety static="true" instance="true"/>
+ <author>Nicko Cadell</author>
+ <author>Gert Driesen</author>
+ </member>
+ <member name="M:log4net.NDC.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:log4net.NDC"/> class.
+ </summary>
+ <remarks>
+ Uses a private access modifier to prevent instantiation of this class.
+ </remarks>
+ </member>
+ <member name="M:log4net.NDC.Clear">
+ <summary>
+ Clears all the contextual information held on the current thread.
+ </summary>
+ <remarks>
+ <note>
+ <para>
+ The NDC is deprecated and has been replaced by the <see cref="P:log4net.ThreadContext.Stacks"/>.
+ The current NDC implementation forwards to the <c>ThreadContext.Stacks["NDC"]</c>.
+ </para>
+ </note>
+ <para>
+ Clears the stack of NDC data held on the current thread.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.NDC.CloneStack">
+ <summary>
+ Creates a clone of the stack of context information.
+ </summary>
+ <returns>A clone of the context info for this thread.</returns>
+ <remarks>
+ <note>
+ <para>
+ The NDC is deprecated and has been replaced by the <see cref="P:log4net.ThreadContext.Stacks"/>.
+ The current NDC implementation forwards to the <c>ThreadContext.Stacks["NDC"]</c>.
+ </para>
+ </note>
+ <para>
+ The results of this method can be passed to the <see cref="M:log4net.NDC.Inherit(System.Collections.Stack)"/>
+ method to allow child threads to inherit the context of their
+ parent thread.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.NDC.Inherit(System.Collections.Stack)">
+ <summary>
+ Inherits the contextual information from another thread.
+ </summary>
+ <param name="stack">The context stack to inherit.</param>
+ <remarks>
+ <note>
+ <para>
+ The NDC is deprecated and has been replaced by the <see cref="P:log4net.ThreadContext.Stacks"/>.
+ The current NDC implementation forwards to the <c>ThreadContext.Stacks["NDC"]</c>.
+ </para>
+ </note>
+ <para>
+ This thread will use the context information from the stack
+ supplied. This can be used to initialize child threads with
+ the same contextual information as their parent threads. These
+ contexts will <b>NOT</b> be shared. Any further contexts that
+ are pushed onto the stack will not be visible to the other.
+ Call <see cref="M:log4net.NDC.CloneStack"/> to obtain a stack to pass to
+ this method.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.NDC.Pop">
+ <summary>
+ Removes the top context from the stack.
+ </summary>
+ <returns>
+ The message in the context that was removed from the top
+ of the stack.
+ </returns>
+ <remarks>
+ <note>
+ <para>
+ The NDC is deprecated and has been replaced by the <see cref="P:log4net.ThreadContext.Stacks"/>.
+ The current NDC implementation forwards to the <c>ThreadContext.Stacks["NDC"]</c>.
+ </para>
+ </note>
+ <para>
+ Remove the top context from the stack, and return
+ it to the caller. If the stack is empty then an
+ empty string (not <c>null</c>) is returned.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.NDC.Push(System.String)">
+ <summary>
+ Pushes a new context message.
+ </summary>
+ <param name="message">The new context message.</param>
+ <returns>
+ An <see cref="T:System.IDisposable"/> that can be used to clean up
+ the context stack.
+ </returns>
+ <remarks>
+ <note>
+ <para>
+ The NDC is deprecated and has been replaced by the <see cref="P:log4net.ThreadContext.Stacks"/>.
+ The current NDC implementation forwards to the <c>ThreadContext.Stacks["NDC"]</c>.
+ </para>
+ </note>
+ <para>
+ Pushes a new context onto the context stack. An <see cref="T:System.IDisposable"/>
+ is returned that can be used to clean up the context stack. This
+ can be easily combined with the <c>using</c> keyword to scope the
+ context.
+ </para>
+ </remarks>
+ <example>Simple example of using the <c>Push</c> method with the <c>using</c> keyword.
+ <code lang="C#">
+ using(log4net.NDC.Push("NDC_Message"))
+ {
+ log.Warn("This should have an NDC message");
+ }
+ </code>
+ </example>
+ </member>
+ <member name="M:log4net.NDC.Remove">
+ <summary>
+ Removes the context information for this thread. It is
+ not required to call this method.
+ </summary>
+ <remarks>
+ <note>
+ <para>
+ The NDC is deprecated and has been replaced by the <see cref="P:log4net.ThreadContext.Stacks"/>.
+ The current NDC implementation forwards to the <c>ThreadContext.Stacks["NDC"]</c>.
+ </para>
+ </note>
+ <para>
+ This method is not implemented.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:log4net.NDC.SetMaxDepth(System.Int32)">
+ <summary>
+ Forces the stack depth to be at most <paramref name="maxDepth"/>.
+ </summary>
+ <param name="maxDepth">The maximum depth of the stack</param>
+ <remarks>
+ <note>
+ <para>
+ The NDC is deprecated and has been replaced by the <see cref="P:log4net.ThreadContext.Stacks"/>.
+ The current NDC implementation forwards to the <c>ThreadContext.Stacks["NDC"]</c>.
+ </para>
+ </note>
+ <para>
+ Forces the stack depth to be at most <paramref name="maxDepth"/>.
+ This may truncate the head of the stack. This only affects the
+ stack in the current thread. Also it does not prevent it from
+ growing, it only sets the maximum depth at the time of the
+ call. This can be used to return to a known context depth.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.NDC.Depth">
+ <summary>
+ Gets the current context depth.
+ </summary>
+ <value>The current context depth.</value>
+ <remarks>
+ <note>
+ <para>
+ The NDC is deprecated and has been replaced by the <see cref="P:log4net.ThreadContext.Stacks"/>.
+ The current NDC implementation forwards to the <c>ThreadContext.Stacks["NDC"]</c>.
+ </para>
+ </note>
+ <para>
+ The number of context values pushed onto the context stack.
+ </para>
+ <para>
+ Used to record the current depth of the context. This can then
+ be restored using the <see cref="M:log4net.NDC.SetMaxDepth(System.Int32)"/> method.
+ </para>
+ </remarks>
+ <seealso cref="M:log4net.NDC.SetMaxDepth(System.Int32)"/>
+ </member>
+ <member name="T:log4net.ThreadContext">
+ <summary>
+ The log4net Thread Context.
+ </summary>
+ <remarks>
+ <para>
+ The <c>ThreadContext</c> provides a location for thread specific debugging
+ information to be stored.
+ The <c>ThreadContext</c> properties override any <see cref="T:log4net.GlobalContext"/>
+ properties with the same name.
+ </para>
+ <para>
+ The thread context has a properties map and a stack.
+ The properties and stack can
+ be included in the output of log messages. The <see cref="T:log4net.Layout.PatternLayout"/>
+ supports selecting and outputting these properties.
+ </para>
+ <para>
+ The Thread Context provides a diagnostic context for the current thread.
+ This is an instrument for distinguishing interleaved log
+ output from different sources. Log output is typically interleaved
+ when a server handles multiple clients near-simultaneously.
+ </para>
+ <para>
+ The Thread Context is managed on a per thread basis.
+ </para>
+ </remarks>
+ <example>Example of using the thread context properties to store a username.
+ <code lang="C#">
+ ThreadContext.Properties["user"] = userName;
+ log.Info("This log message has a ThreadContext Property called 'user'");
+ </code>
+ </example>
+ <example>Example of how to push a message into the context stack
+ <code lang="C#">
+ using(ThreadContext.Stacks["NDC"].Push("my context message"))
+ {
+ log.Info("This log message has a ThreadContext Stack message that includes 'my context message'");
+
+ } // at the end of the using block the message is automatically popped
+ </code>
+ </example>
+ <threadsafety static="true" instance="true"/>
+ <author>Nicko Cadell</author>
+ </member>
+ <member name="M:log4net.ThreadContext.#ctor">
+ <summary>
+ Private Constructor.
+ </summary>
+ <remarks>
+ <para>
+ Uses a private access modifier to prevent instantiation of this class.
+ </para>
+ </remarks>
+ </member>
+ <member name="F:log4net.ThreadContext.s_properties">
+ <summary>
+ The thread context properties instance
+ </summary>
+ </member>
+ <member name="F:log4net.ThreadContext.s_stacks">
+ <summary>
+ The thread context stacks instance
+ </summary>
+ </member>
+ <member name="P:log4net.ThreadContext.Properties">
+ <summary>
+ The thread properties map
+ </summary>
+ <value>
+ The thread properties map
+ </value>
+ <remarks>
+ <para>
+ The <c>ThreadContext</c> properties override any <see cref="T:log4net.GlobalContext"/>
+ properties with the same name.
+ </para>
+ </remarks>
+ </member>
+ <member name="P:log4net.ThreadContext.Stacks">
+ <summary>
+ The thread stacks
+ </summary>
+ <value>
+ stack map
+ </value>
+ <remarks>
+ <para>
+ The thread local stacks.
+ </para>
+ </remarks>
+ </member>
+ </members>
+</doc>
diff --git a/dotnet/client-010/lib/nunit/nunit-licence.txt b/dotnet/client-010/lib/nunit/nunit-licence.txt
new file mode 100644
index 0000000000..b2316295d3
--- /dev/null
+++ b/dotnet/client-010/lib/nunit/nunit-licence.txt
@@ -0,0 +1,23 @@
+Copyright 2002-2004 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov,
+ Charlie Poole
+Copyright 2000-2004 Philip A. Craig
+
+This software is provided 'as-is', without any express or implied warranty. In
+no event will the authors be held liable for any damages arising from the use
+of this software.
+
+Permission is granted to anyone to use this software for any purpose, including
+commercial applications, and to alter it and redistribute it freely, subject to
+the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim
+ that you wrote the original software. If you use this software in a product, an
+ acknowledgment (see the following) in the product documentation is required.
+
+ Portions Copyright 2002 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov
+ or Copyright 2000-2002 Philip A. Craig
+
+2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source distribution.
diff --git a/dotnet/client-010/lib/nunit/nunit.framework.dll b/dotnet/client-010/lib/nunit/nunit.framework.dll
new file mode 100644
index 0000000000..53666e74c9
--- /dev/null
+++ b/dotnet/client-010/lib/nunit/nunit.framework.dll
Binary files differ
diff --git a/dotnet/client-010/lib/plossum/C5-License.txt b/dotnet/client-010/lib/plossum/C5-License.txt
new file mode 100644
index 0000000000..5649c70cf3
--- /dev/null
+++ b/dotnet/client-010/lib/plossum/C5-License.txt
@@ -0,0 +1,27 @@
+-----------------------------------------------------------------------------
+
+The following license applies to the C5 library (found in C5.dll and C5.pdb)
+The source code for this library together with more information can be found on
+http://www.itu.dk/research/c5/.
+
+-----------------------------------------------------------------------------
+
+Copyright (c) 2003-2007 Niels Kokholm and Peter Sestoft.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/dotnet/client-010/lib/plossum/C5.dll b/dotnet/client-010/lib/plossum/C5.dll
new file mode 100644
index 0000000000..08362849c9
--- /dev/null
+++ b/dotnet/client-010/lib/plossum/C5.dll
Binary files differ
diff --git a/dotnet/client-010/lib/plossum/Plossum CommandLine.dll b/dotnet/client-010/lib/plossum/Plossum CommandLine.dll
new file mode 100644
index 0000000000..d3aad9485d
--- /dev/null
+++ b/dotnet/client-010/lib/plossum/Plossum CommandLine.dll
Binary files differ
diff --git a/dotnet/client-010/lib/plossum/license.txt b/dotnet/client-010/lib/plossum/license.txt
new file mode 100644
index 0000000000..532b9c11a3
--- /dev/null
+++ b/dotnet/client-010/lib/plossum/license.txt
@@ -0,0 +1,28 @@
+Copyright (c) Peter Palotas 2007
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/dotnet/client-010/log.xml b/dotnet/client-010/log.xml
new file mode 100644
index 0000000000..cda84d7c7b
--- /dev/null
+++ b/dotnet/client-010/log.xml
@@ -0,0 +1,46 @@
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<log4net>
+ <appender name="Console" type="log4net.Appender.ConsoleAppender">
+ <layout type="log4net.Layout.PatternLayout">
+ <!-- Pattern to output the caller's file name and line number -->
+ <conversionPattern value="%5level [%thread] (%file:%line) - %message%newline" />
+ </layout>
+ </appender>
+
+ <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
+ <file value="logs/mylogfile.log" />
+ <appendToFile value="true" />
+ <maximumFileSize value="8192KB" />
+ <maxSizeRollBackups value="2" />
+
+ <layout type="log4net.Layout.PatternLayout">
+ <conversionPattern value="%date [%thread] %-5level %ndc - %message%newline" />
+ <!--<conversionPattern value="%level %thread %logger - %message%newline" />-->
+ </layout>
+ </appender>
+
+ <root>
+ <level value="DEBUG" />
+ <appender-ref ref="Console" />
+ <appender-ref ref="RollingFile" />
+ </root>
+</log4net>
diff --git a/dotnet/client-010/management/console/AbstractConsole.cs b/dotnet/client-010/management/console/AbstractConsole.cs
new file mode 100644
index 0000000000..315b2b6d48
--- /dev/null
+++ b/dotnet/client-010/management/console/AbstractConsole.cs
@@ -0,0 +1,45 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+
+namespace org.apache.qpid.console
+{
+ public class AbstractConsole : Console
+ {
+ public AbstractConsole(){}
+ public virtual void NewAgent(Agent agent) {}
+ public virtual void AgentRemoved(Agent agent) {}
+ public virtual void BrokerConnected(Broker broker) {}
+ public virtual void BrokerDisconnected(Broker broker) {}
+ public virtual void BrokerInformation(Broker broker) {}
+ public virtual void NewPackage(String packageName) {}
+ public virtual void NewClass(short kind, ClassKey key) {}
+ public virtual void ObjectProperties(Broker broker, QMFObject obj) {}
+ public virtual void ObjectStatistics(Broker broker, QMFObject obj) {}
+ public virtual void MethodResponse(Broker broker, long seq, MethodResult response) {}
+ public virtual void EventRecieved(Broker broker, QMFEvent anEvent) {}
+ public virtual void HearbeatRecieved(Agent agent, long timestamp) {}
+ public virtual Type TypeMapping(ClassKey key) {
+ return typeof(QMFObject) ;
+ }
+ }
+}
diff --git a/dotnet/client-010/management/console/Agent.cs b/dotnet/client-010/management/console/Agent.cs
new file mode 100644
index 0000000000..df544a4dd0
--- /dev/null
+++ b/dotnet/client-010/management/console/Agent.cs
@@ -0,0 +1,75 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using log4net ;
+
+namespace org.apache.qpid.console
+{
+
+ /**
+ * Local representation of a remote agent which has been found on the bus.
+ */
+ public class Agent
+ {
+ public static ILog log = LogManager.GetLogger(typeof(Agent)) ;
+
+ public Broker Broker {get;set;}
+ public long BrokerBank {get;set;}
+ public long AgentBank {get;set;}
+ public string label {get;set;}
+
+ public Agent(Broker broker, long agentBank, string label)
+ {
+ this.Broker = broker ;
+ this.BrokerBank = broker.BrokerBank() ;
+ this.AgentBank = agentBank ;
+ this.label = label ;
+ }
+
+ public string AgentKey() {
+ return Agent.AgentKey(AgentBank, BrokerBank) ;
+ }
+
+ public string RoutingCode() {
+ return Agent.RoutingCode(AgentBank, BrokerBank) ;
+ }
+
+ public static string AgentKey(long AgentBank, long BrokerBank) {
+ return String.Format("{0}:{1}", AgentBank, BrokerBank) ;
+ }
+
+ public static string RoutingCode(long AgentBank, long BrokerBank) {
+ return String.Format("agent.{0}.{1}", BrokerBank, AgentBank) ;
+ }
+
+ public static long GetBrokerBank(string routingKey) {
+ string delim = "." ;
+ return long.Parse(routingKey.Split(delim.ToCharArray())[2]) ;
+ }
+
+ public static long GetAgentBank(string routingKey) {
+ string delim = "." ;
+ return long.Parse(routingKey.Split(delim.ToCharArray())[3]) ;
+ }
+
+ }
+}
diff --git a/dotnet/client-010/management/console/Broker.cs b/dotnet/client-010/management/console/Broker.cs
new file mode 100644
index 0000000000..7684da9e12
--- /dev/null
+++ b/dotnet/client-010/management/console/Broker.cs
@@ -0,0 +1,351 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic ;
+using System.Threading ;
+using org.apache.qpid.client ;
+using org.apache.qpid.transport ;
+using org.apache.qpid.transport.codec ;
+using log4net ;
+
+namespace org.apache.qpid.console
+{
+
+ /**
+ * Controls all communication with a broker. Works with the session to provide
+ * synhchronous method calls across the asynchronous QMF bus.
+ */
+ public class Broker : IMessageListener
+ {
+ public static ILog log = LogManager.GetLogger(typeof(Broker)) ;
+ public static int SYNC_TIME = 60000 ;
+
+ public BrokerURL url ;
+ public Dictionary<string, Agent> Agents = new Dictionary<string, Agent>() ;
+
+ private IClient client ;
+ private IClientSession clientSession ;
+ //FIXME This second session should not be needed. There is a bug in the underlieing code.
+ private IClientSession outSession ;
+ private int timeout = 50000 ;
+ private string replyName ;
+ private string topicName ;
+ private bool connected = false ;
+ private bool syncInFlight = false ;
+ private bool topicBound = false ;
+ private int reqsOutstanding = 0 ;
+ private org.apache.qpid.console.Session consoleSession ;
+ private object lockObject = new Object() ;
+
+
+ public Broker(org.apache.qpid.console.Session session, BrokerURL url)
+ {
+ log.Debug("Creating a new Broker for url " + url) ;
+ this.url = url;
+ consoleSession = session ;
+ this.TryToConnect() ;
+ }
+
+ ~Broker() {
+ if (connected) {
+ this.Shutdown() ;
+ }
+ }
+
+ public int BrokerBank() {
+ return 1 ;
+ }
+
+ public bool IsConnected() {
+ return connected ;
+ }
+
+ protected void TryToConnect() {
+ reqsOutstanding = 1 ;
+ Agent newAgent = new Agent(this,0,"BrokerAgent") ;
+ Agents.Add(newAgent.AgentKey(), newAgent) ;
+ client = new Client() ;
+ client.Connect(url.Hostname, url.Port, null, url.AuthName, url.AuthPassword) ;
+ clientSession = client.CreateSession(timeout) ;
+ //clientSession.SetAutoSync(false) ;
+ string name = System.Text.Encoding.UTF8.GetString(clientSession.GetName()) ;
+ replyName = "reply-" + name ;
+ topicName = "topic-" + name ;
+ clientSession.SetAutoSync(true) ;
+ Option[] options = new Option[] {Option.EXCLUSIVE, Option.AUTO_DELETE} ;
+
+ // This queue is used for responses to messages which are sent.
+ clientSession.QueueDeclare(replyName,options) ;
+ clientSession.ExchangeBind(replyName,"amq.direct",replyName) ;
+ clientSession.AttachMessageListener(this, "rdest") ;
+ clientSession.MessageSubscribe(replyName,"rdest",MessageAcceptMode.NONE,MessageAcquireMode.PRE_ACQUIRED,null,0,null) ;
+ clientSession.MessageSetFlowMode("rdest", MessageFlowMode.WINDOW);
+ clientSession.MessageFlow("rdest", MessageCreditUnit.BYTE, ClientSession.MESSAGE_FLOW_MAX_BYTES);
+ clientSession.MessageFlow("rdest", MessageCreditUnit.MESSAGE, ClientSession.MESSAGE_FLOW_MAX_BYTES);
+
+ // This queue is used for unsolicited messages sent to this class.
+ clientSession.QueueDeclare(topicName, options) ;
+ clientSession.AttachMessageListener(this, "tdest") ;
+ clientSession.MessageSubscribe(topicName,"tdest",MessageAcceptMode.NONE,MessageAcquireMode.PRE_ACQUIRED,null,0,null) ;
+ clientSession.MessageSetFlowMode("tdest", MessageFlowMode.WINDOW);
+ clientSession.MessageFlow("tdest", MessageCreditUnit.BYTE, ClientSession.MESSAGE_FLOW_MAX_BYTES);
+ clientSession.MessageFlow("tdest", MessageCreditUnit.MESSAGE, ClientSession.MESSAGE_FLOW_MAX_BYTES);
+
+ outSession = client.CreateSession(timeout) ;
+ outSession.ExchangeBind(replyName,"amq.direct",replyName) ;
+
+ connected = true ;
+ consoleSession.HandleBrokerConnect(this) ;
+
+
+ IEncoder encoder = CreateEncoder() ;
+ this.SetHeader(encoder, 'B', 0) ;
+ this.Send(encoder) ;
+ }
+
+ public void Shutdown() {
+ if (connected) {
+ this.WaitForStable() ;
+ clientSession.MessageStop("rdest") ;
+ clientSession.MessageStop("tdest") ;
+ clientSession.Close() ;
+ client.Close() ;
+ this.connected = false ;
+ }
+ }
+
+ public void UpdateAgent(QMFObject obj) {
+ long agentBank = (long)obj.GetProperty("agentBank") ;
+ long brokerBank = (long)obj.GetProperty("brokerBank") ;
+ String key = Agent.AgentKey(agentBank, brokerBank) ;
+ if (obj.IsDeleted()) {
+ if (Agents.ContainsKey(key)) {
+ Agent agent = Agents[key] ;
+ Agents.Remove(key) ;
+ consoleSession.HandleAgentRemoved(agent) ;
+ }
+ }
+ else {
+ if (! Agents.ContainsKey(key)) {
+ Agent newAgent = new Agent(this, agentBank, (string)obj.GetProperty("label")) ;
+ Agents.Add(key, newAgent) ;
+ consoleSession.HandleNewAgent(newAgent) ;
+ }
+ }
+ }
+
+ public IEncoder CreateEncoder() {
+ return new MSEncoder(1000) ;
+ }
+
+
+ public IEncoder CreateEncoder(char opcode, long sequence) {
+ return SetHeader(this.CreateEncoder(), opcode, sequence) ;
+ }
+
+ public IEncoder SetHeader(IEncoder enc, char opcode, long sequence) {
+ enc.WriteUint8((short)'A') ;
+ enc.WriteUint8((short)'M') ;
+ enc.WriteUint8((short)'2') ;
+ enc.WriteUint8((short)opcode) ;
+ enc.WriteUint32(sequence) ;
+ return enc ;
+ }
+
+ public Message CreateMessage(IEncoder enc) {
+ return this.CreateMessage(enc, "broker", -1) ;
+ }
+
+ public Message CreateMessage(IEncoder enc, string routingKey) {
+ return this.CreateMessage(enc, routingKey, -1) ;
+ }
+
+ public Message CreateMessage(IEncoder enc, string routingKey, long ttl) {
+ Message msg = new Message() ;
+ msg.Body = ((MSEncoder)enc).Segment() ;
+ msg.DeliveryProperties.SetRoutingKey(routingKey) ;
+ if (-1 != ttl) {
+ msg.DeliveryProperties.SetTtl(ttl) ;
+ }
+ msg.MessageProperties.SetContentType("x-application/qmf") ;
+ msg.MessageProperties.SetReplyTo(new ReplyTo("amq.direct", replyName)) ;
+ return msg ;
+ }
+
+ public void Send(IEncoder enc) {
+ this.Send(this.CreateMessage(enc)) ;
+ }
+
+ public void Send(Message msg) {
+
+ lock (lockObject) {
+ log.Debug(String.Format("Sending message to routing key '{0}'", msg.DeliveryProperties.GetRoutingKey())) ;
+ //log.Debug(System.Text.Encoding.UTF8.GetString(msg.Body.ToArray())) ;
+ outSession.MessageTransfer("qpid.management", msg) ;
+ //clientSession.sync() ;
+ }
+ }
+
+ protected bool CheckHeader(IDecoder decoder, out char opcode, out long sequence) {
+ bool returnValue = false ;
+ opcode = 'x' ;
+ sequence = -1 ;
+ if(decoder.HasRemaining()) {
+ char character = (char) decoder.ReadUint8() ;
+ if (character != 'A') {
+ return returnValue ;
+ }
+ character = (char) decoder.ReadUint8() ;
+ if (character != 'M') {
+ return returnValue ;
+ }
+ character = (char) decoder.ReadUint8() ;
+ if (character != '2') {
+ return returnValue ;
+ }
+ returnValue = true ;
+ opcode = (char) decoder.ReadUint8() ;
+ sequence = decoder.ReadUint32() ;
+ }
+ return returnValue ;
+ }
+
+ public void MessageTransfer(IMessage msg) {
+ MSDecoder decoder = new MSDecoder() ;
+ decoder.Init(msg.Body) ;
+ RangeSet rangeSet = new RangeSet() ;
+ rangeSet.Add(msg.Id) ;
+ char opcode = 'x' ;
+ long seq = -1 ;
+ while (this.CheckHeader(decoder, out opcode, out seq)) {
+ //log.Debug("Message recieved with opcode " + opcode + " and sequence " + seq) ;
+ //log.Debug(System.Text.Encoding.UTF8.GetString(msg.Body.ToArray())) ;
+ switch (opcode) {
+ case 'b':
+ consoleSession.HandleBrokerResponse(this, decoder, seq) ;
+ break ;
+ case 'p':
+ consoleSession.HandlePackageIndicator(this, decoder, seq) ;
+ break ;
+ case 'z':
+ consoleSession.HandleCommandComplete(this, decoder, seq) ;
+ break ;
+ case 'q':
+ consoleSession.HandleClassIndicator(this, decoder, seq) ;
+ break ;
+ case 'm':
+ consoleSession.HandleMethodResponse(this, decoder, seq) ;
+ break ;
+ case 'h':
+ consoleSession.HandleHeartbeatIndicator(this, decoder, seq, msg) ;
+ break ;
+ case 'e':
+ consoleSession.HandleEventIndicator(this, decoder, seq) ;
+ break ;
+ case 's':
+ consoleSession.HandleSchemaResponse(this, decoder, seq) ;
+ break ;
+ case 'c':
+ consoleSession.HandleContentIndicator(this, decoder, seq, true, false) ;
+ break ;
+ case 'i':
+ consoleSession.HandleContentIndicator(this, decoder, seq, false, true) ;
+ break ;
+ case 'g':
+ consoleSession.HandleContentIndicator(this, decoder, seq, true, true) ;
+ break ;
+ default:
+ log.Error("Invalid message type recieved with opcode " + opcode) ;
+ break ;
+ }
+ }
+ lock (lockObject) {
+ outSession.MessageAccept(rangeSet) ;
+ }
+ }
+
+ public void IncrementOutstanding() {
+ lock (lockObject) {
+ this.reqsOutstanding += 1 ;
+ }
+ }
+
+ public void DecrementOutstanding() {
+ lock (lockObject) {
+ this.reqsOutstanding -= 1 ;
+ if ((reqsOutstanding == 0) & !topicBound) {
+ foreach (string key in consoleSession.BindingKeys()) {
+ //this.clientSession.ExchangeBind(topicName, "qpid.mannagement", key) ;
+ log.Debug("Setting Topic Binding " + key) ;
+ this.outSession.ExchangeBind(topicName, "qpid.management", key) ;
+ }
+ topicBound = true ;
+ }
+ if ((reqsOutstanding == 0) & syncInFlight) {
+ syncInFlight = false ;
+ Monitor.PulseAll(lockObject) ;
+ }
+ }
+ }
+
+ public void WaitForStable() {
+ lock (lockObject) {
+ if (connected) {
+ DateTime start = DateTime.Now ;
+ syncInFlight = true ;
+ while (reqsOutstanding != 0) {
+ log.Debug("Waiting to recieve messages") ;
+ Monitor.Wait(lockObject,SYNC_TIME) ;
+ TimeSpan duration = DateTime.Now - start;
+ if (duration.TotalMilliseconds > SYNC_TIME) {
+ throw new Exception("Timeout waiting for Broker to Sync") ;
+ }
+ }
+ }
+ }
+ }
+
+ public void SetSyncInFlight(bool inFlight) {
+ lock(lockObject) {
+ syncInFlight = inFlight ;
+ Monitor.PulseAll(lockObject) ;
+ }
+ }
+
+ public bool GetSyncInFlight() {
+ return syncInFlight ;
+ }
+
+ public void WaitForSync(int timeout) {
+ lock(lockObject) {
+ DateTime start = DateTime.Now ;
+ while (syncInFlight) {
+ Monitor.Wait(lockObject,timeout) ;
+ }
+ TimeSpan duration = DateTime.Now - start;
+ if (duration.TotalMilliseconds > timeout) {
+ throw new Exception("Timeout waiting for Broker to Sync") ;
+ }
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/management/console/BrokerURL.cs b/dotnet/client-010/management/console/BrokerURL.cs
new file mode 100644
index 0000000000..77318e4295
--- /dev/null
+++ b/dotnet/client-010/management/console/BrokerURL.cs
@@ -0,0 +1,71 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+
+namespace org.apache.qpid.console
+{
+
+ /**
+ * URL which defines the connection to the broker to hook up to the QMF
+ * Bus.
+ */
+ public class BrokerURL
+ {
+ public string Hostname {get;set;}
+ public int Port {get;set;}
+ public string AuthName {get;set;}
+ public string AuthPassword {get;set;}
+ public string AuthMechanism {get;set;}
+ protected bool ssl = false ;
+
+ public BrokerURL(string str)
+ {
+ Uri uri = new Uri(str) ;
+ this.Hostname = uri.Host ;
+ if (uri.Scheme.Equals("amqp")) {
+ Port=5672 ;
+ } else {
+ ssl = true ;
+ Port=5673 ;
+ }
+
+ //FIXME Make this more robust
+ this.AuthName = "guest" ;
+ this.AuthPassword = "guest" ;
+ this.AuthMechanism = "PLAIN" ;
+ }
+
+ public string GetURI() {
+ return Hostname ;
+ }
+
+ public override string ToString ()
+ {
+ if (ssl) {
+ return String.Format("amqps://{0}:{1}", Hostname, Port) ;
+ } else {
+ return String.Format("amqp://{0}:{1}", Hostname, Port) ;
+ }
+ }
+
+ }
+}
diff --git a/dotnet/client-010/management/console/ClassKey.cs b/dotnet/client-010/management/console/ClassKey.cs
new file mode 100644
index 0000000000..a3aba2761a
--- /dev/null
+++ b/dotnet/client-010/management/console/ClassKey.cs
@@ -0,0 +1,107 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Globalization ;
+using org.apache.qpid.transport.util;
+using org.apache.qpid.transport.codec ;
+
+namespace org.apache.qpid.console
+{
+
+ /**
+ * Identifies a specific class and version on the bus.
+ */
+ public class ClassKey
+ {
+ public string PackageName { get; set; }
+ public string ClassName { get; set; }
+ public long[] Hash = new long[4] ;
+
+ public ClassKey(String keyString) {
+ string delims = ":()" ;
+ string[] parts = keyString.Split(delims.ToCharArray()) ;
+ if (parts.Length < 3) {
+ throw new Exception("Invalid class key format. Format should be package:class(bytes)") ;
+ }
+ PackageName = parts[0] ;
+ ClassName = parts[1] ;
+ delims = "-" ;
+ string[] bytes = parts[2].Split(delims.ToCharArray()) ;
+ if (bytes.Length != 4) {
+ throw new Exception("Invalid class key format. Bytes should be in the format HEX-HEX-HEX-HEX") ;
+ }
+ Hash[0] = long.Parse(bytes[0], NumberStyles.HexNumber) ;
+ Hash[1] = long.Parse(bytes[1], NumberStyles.HexNumber) ;
+ Hash[2] = long.Parse(bytes[2], NumberStyles.HexNumber) ;
+ Hash[3] = long.Parse(bytes[3], NumberStyles.HexNumber) ;
+ }
+
+ public ClassKey(IDecoder dec) {
+ PackageName = dec.ReadStr8() ;
+ ClassName = dec.ReadStr8() ;
+ Hash[0] = dec.ReadUint32() ;
+ Hash[1] = dec.ReadUint32() ;
+ Hash[2] = dec.ReadUint32() ;
+ Hash[3] = dec.ReadUint32() ;
+
+ }
+
+ public string GetKeyString() {
+ string hashString = GetHashString() ;
+ return String.Format("{0}:{1}({2})", PackageName, ClassName, hashString) ;
+ }
+
+ public string GetHashString() {
+ return String.Format("{0:x8}-{1:x8}-{2:x8}-{3:x8}", (long) Hash[0],Hash[1], Hash[2],Hash[3]) ;
+ }
+
+ public void encode(IEncoder enc) {
+ enc.WriteStr8(PackageName) ;
+ enc.WriteStr8(ClassName) ;
+ enc.WriteUint32(Hash[0]) ;
+ enc.WriteUint32(Hash[1]) ;
+ enc.WriteUint32(Hash[2]) ;
+ enc.WriteUint32(Hash[3]) ;
+ }
+
+ override public string ToString() {
+ return String.Format("ClassKey: {0}", GetKeyString()) ;
+ }
+
+ public override int GetHashCode ()
+ {
+ return GetKeyString().GetHashCode() ;
+ }
+
+ public override bool Equals (object obj)
+ {
+ if (obj.GetType().Equals(this.GetType())) {
+ ClassKey other = (ClassKey) obj ;
+ return (other.GetKeyString().Equals(this.GetKeyString())) ;
+ }
+ else {
+ return false ;
+ }
+ }
+
+ }
+}
diff --git a/dotnet/client-010/management/console/Console.cs b/dotnet/client-010/management/console/Console.cs
new file mode 100644
index 0000000000..8ff201c676
--- /dev/null
+++ b/dotnet/client-010/management/console/Console.cs
@@ -0,0 +1,46 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+
+namespace org.apache.qpid.console
+{
+ /**
+ * Callbacks which are exposed by the Session. Clients should create anm implementaiton of this
+ * for more fine grained interaction with the bus.
+ */
+ public interface Console
+ {
+ void NewAgent(Agent agent) ;
+ void AgentRemoved(Agent agent) ;
+ void BrokerConnected(Broker broker) ;
+ void BrokerDisconnected(Broker broker) ;
+ void BrokerInformation(Broker broker) ;
+ void NewPackage(String packageName) ;
+ void NewClass(short kind, ClassKey key) ;
+ void ObjectProperties(Broker broker, QMFObject obj) ;
+ void ObjectStatistics(Broker broker, QMFObject obj) ;
+ void MethodResponse(Broker broker, long seq, MethodResult response) ;
+ void EventRecieved(Broker broker, QMFEvent anEvent) ;
+ void HearbeatRecieved(Agent agent, long timestamp) ;
+ Type TypeMapping(ClassKey key) ;
+ }
+}
diff --git a/dotnet/client-010/management/console/MethodResult.cs b/dotnet/client-010/management/console/MethodResult.cs
new file mode 100644
index 0000000000..7215f5dcbc
--- /dev/null
+++ b/dotnet/client-010/management/console/MethodResult.cs
@@ -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.
+ *
+ */
+
+using System;
+using System.Collections.Generic ;
+
+namespace org.apache.qpid.console
+{
+ /**
+ * The result on invoking a method on a managed object
+ */
+ public class MethodResult
+ {
+
+ public long ReturnCode {get;set;}
+ public string Text {get;set;}
+ protected Dictionary<string, object> ReturnValues ;
+
+ public MethodResult(long aCode, string aMsg, Dictionary<string, object> args)
+ {
+ ReturnCode = aCode ;
+ Text = aMsg ;
+ ReturnValues = args ;
+ }
+
+ public object GetReturnValue(string name) {
+ object returnValue = null ;
+ if (ReturnValues.ContainsKey(name)) {
+ returnValue = ReturnValues[name] ;
+ }
+ return returnValue ;
+ }
+
+ public Dictionary<string, object> GetReturnValues() {
+ return ReturnValues ;
+ }
+
+ public override string ToString()
+ {
+ string returnString = "" ;
+ foreach (KeyValuePair<string, object> pair in ReturnValues) {
+ returnString = returnString + String.Format("(Key: '{0}' Value: '{1}')", pair.Key, pair.Value) ;
+ }
+
+ return string.Format("MethodResult: ReturnCode={0}, Text={1} Values=[{2}]", ReturnCode, Text, returnString);
+ }
+
+ }
+}
diff --git a/dotnet/client-010/management/console/ObjectID.cs b/dotnet/client-010/management/console/ObjectID.cs
new file mode 100644
index 0000000000..9532c8e64c
--- /dev/null
+++ b/dotnet/client-010/management/console/ObjectID.cs
@@ -0,0 +1,88 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using org.apache.qpid.transport.codec ;
+
+namespace org.apache.qpid.console
+{
+
+ /**
+ * Uniquely identifies an object on the bus.
+ */
+ public class ObjectID
+ {
+
+ protected long first ;
+ protected long second ;
+
+ public ObjectID() {
+ }
+
+ public ObjectID(IDecoder dec)
+ {
+ first = (long)dec.ReadUint64() ;
+ second = (long)dec.ReadUint64() ;
+ }
+
+ public ObjectID(long first, long second) {
+ this.first = first ;
+ this.second = second ;
+ }
+
+ public long Flags() {
+ return (long) ((ulong)this.first & 0xF000000000000000) >> 60 ;
+ }
+
+ public long Sequence() {
+ return (long)((ulong)this.first & 0x0FFF000000000000) >> 48 ;
+ }
+
+ public long BrokerBank() {
+ return (long)((ulong)this.first & 0x0000FFFFF0000000) >> 28 ;
+ }
+
+ public long AgentBank() {
+ return (this.first & 0x000000000FFFFFFF) ;
+ }
+
+ public long Object() {
+ return second ;
+ }
+
+ public bool IsDurable() {
+ return Sequence() == 0 ;
+ }
+
+ public void encode(IEncoder enc) {
+ enc.WriteUint64((long)first) ;
+ enc.WriteUint64((long)second) ;
+ }
+
+ override public string ToString() {
+ return "" + Flags() + "-" + Sequence() + "-" + BrokerBank() + "-" + AgentBank() + "-" + Object() ;
+ }
+
+ public string RoutingCode() {
+ return Agent.RoutingCode((long)AgentBank(), (long)BrokerBank()) ;
+ }
+ }
+}
diff --git a/dotnet/client-010/management/console/QMFEvent.cs b/dotnet/client-010/management/console/QMFEvent.cs
new file mode 100644
index 0000000000..73e1a34c43
--- /dev/null
+++ b/dotnet/client-010/management/console/QMFEvent.cs
@@ -0,0 +1,74 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic;
+using org.apache.qpid.transport.codec ;
+
+
+namespace org.apache.qpid.console
+{
+ public enum EventSeverity : short {
+ EMER = 0 ,
+ ALERT = 1 ,
+ CRIT = 2 ,
+ ERROR = 3 ,
+ WARN = 4 ,
+ NOTIC = 5 ,
+ INFO = 6 ,
+ DEBUG = 7
+ }
+
+ /**
+ * An event raised by an agent on the bus.
+ */
+ public class QMFEvent
+ {
+ public Session Session { get;set; }
+ public ClassKey ClassKey {get;set;}
+ //FIXME time?
+ public long Timestamp {get;set;}
+ public EventSeverity Severity {get;set;}
+ public Dictionary<string, object> Arguments {get;set;}
+
+ public QMFEvent(Session session, IDecoder dec)
+ {
+ Session = session ;
+ ClassKey = new ClassKey(dec) ;
+ Timestamp = dec.ReadInt64() ;
+ Severity = (EventSeverity) dec.ReadUint8() ;
+ SchemaClass sClass = Session.GetSchema(ClassKey) ;
+ Arguments = new Dictionary<string, object>() ;
+
+ if (sClass != null) {
+ foreach (SchemaArgument arg in sClass.Arguments) {
+ Arguments[arg.Name] = Session.DecodeValue(dec, arg.Type) ;
+ }
+ }
+ }
+
+ public object GetArgument(string argName) {
+ object returnValue = null ;
+ Arguments.TryGetValue(argName, out returnValue) ;
+ return returnValue ;
+ }
+ }
+}
diff --git a/dotnet/client-010/management/console/QMFObject.cs b/dotnet/client-010/management/console/QMFObject.cs
new file mode 100644
index 0000000000..905422efd9
--- /dev/null
+++ b/dotnet/client-010/management/console/QMFObject.cs
@@ -0,0 +1,294 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic ;
+using log4net ;
+using org.apache.qpid.transport.codec ;
+
+namespace org.apache.qpid.console
+{
+
+ /**
+ * An object which is returned from an agent by the Session. It can have
+ * methods, properties, and statistics.
+ */
+ public class QMFObject
+ {
+
+ public static ILog log = LogManager.GetLogger(typeof(QMFObject)) ;
+
+ public Session Session {get;set;}
+ protected SchemaClass _Schema ;
+ virtual public SchemaClass Schema {get {return _Schema;} set {_Schema=value;}}
+ bool Managed ;
+ public DateTime CurrentTime {get;set;}
+ public DateTime CreateTime {get;set;}
+ public DateTime DeleteTime {get;set;}
+ public ObjectID ObjectID {get;set;}
+ public Dictionary<string, object> Properties = new Dictionary<string, object>() ;
+ public Dictionary<string, object> Statistics = new Dictionary<string, object>() ;
+
+
+ // This constructor is the "naked" constructor which creates
+ // an object without a session or a schema. It is used by
+ // subclasses which are auto generated
+ public QMFObject() {
+ }
+
+ public QMFObject(QMFObject source) {
+ this.Session = source.Session ;
+ this.Schema = source.Schema ;
+ this.Managed = source.Managed ;
+ this.CurrentTime = source.CurrentTime ;
+ this.CreateTime = source.CreateTime ;
+ this.DeleteTime = source.DeleteTime ;
+ this.ObjectID = source.ObjectID ;
+ this.Properties = source.Properties ;
+ this.Statistics = source.Statistics ;
+ }
+
+ // This constructor is used by a session make object call to
+ // create a blank object from a schema.
+ public QMFObject(Session session, SchemaClass schema, bool hasProperties, bool hasStats , bool isManaged) {
+ Session = session ;
+ Schema = schema ;
+ Managed = isManaged ;
+
+ if (hasProperties) {
+ foreach (SchemaProperty prop in Schema.GetAllProperties()) {
+ object propValue = null ;
+ if (!prop.Optional) {
+ propValue = Util.DefaultValue(prop.Type) ;
+ }
+ this.SetProperty(prop.Name, propValue) ;
+ }
+ }
+
+ if (hasStats) {
+ foreach (SchemaStatistic stat in Schema.Statistics) {
+ SetStatistic(stat.Name, Util.DefaultValue(stat.Type)) ;
+ }
+ }
+ }
+
+ // This constructor is used by the session to create an object based on a data
+ // stream by the agent.
+ public QMFObject(Session session, SchemaClass schema, IDecoder dec, bool hasProperties, bool hasStats , bool isManaged)
+ {
+ Session = session ;
+ Schema = schema ;
+ Managed = isManaged ;
+
+ if (Managed) {
+ // FIXME DateTime or Uint64??
+ CurrentTime = new DateTime(dec.ReadDatetime()) ;
+ CreateTime = new DateTime(dec.ReadDatetime()) ;
+ DeleteTime = new DateTime(dec.ReadDatetime()) ;
+ ObjectID = new ObjectID(dec) ;
+ }
+
+ if (hasProperties) {
+ List<string> excluded = ProcessPresenceMasks(dec, Schema) ;
+
+ foreach (SchemaProperty prop in Schema.GetAllProperties()) {
+ if (excluded.Contains(prop.Name)) {
+ log.Debug(String.Format("Setting Property Default {0}", prop.Name)) ;
+ safeAddProperty(prop.Name, null) ;
+ } else {
+ //log.Debug(String.Format("Setting Property {0}", prop.Name)) ;
+ safeAddProperty(prop.Name, session.DecodeValue(dec, prop.Type)) ;
+ }
+ }
+ }
+
+ if (hasStats) {
+ foreach (SchemaStatistic stat in Schema.GetAllStatistics()) {
+ //log.Debug(String.Format("Setting Statistic {0}", stat.Name)) ;
+ Statistics.Add(stat.Name, session.DecodeValue(dec, stat.Type)) ;
+ }
+ }
+
+ }
+
+ protected List<string> ProcessPresenceMasks(IDecoder dec, SchemaClass schema) {
+ List<string> excludes = new List<string> () ;
+ short bit = 0 ;
+ short mask = 0 ;
+ foreach (SchemaProperty prop in Schema.GetAllProperties()) {
+ if (prop.Optional) {
+ //log.Debug(String.Format("Property named {0} is optional", prop.Name)) ;
+ if (bit == 0) {
+ mask=dec.ReadUint8() ;
+ bit = 1 ;
+ }
+
+ if ((mask & bit) == 0) {
+ //log.Debug(String.Format("Property named {0} is not present", prop.Name)) ;
+ excludes.Add(prop.Name) ;
+ }
+ bit *= 2 ;
+ if (bit == 256) {
+ bit = 0 ;
+ }
+ }
+ }
+ return excludes ;
+ }
+
+ protected List<SchemaMethod> getMethods() {
+ return Schema.GetAllMethods() ;
+ }
+
+ public object GetProperty(string attributeName) {
+ //FIXME any object refs?
+ object returnValue = null ;
+ Properties.TryGetValue(attributeName, out returnValue) ;
+ return returnValue ;
+ }
+
+ protected void SetStatistic(string attributeName, object newValue) {
+ Statistics.Remove(attributeName) ;
+ Statistics.Add(attributeName, newValue) ;
+ }
+
+ public void SetProperty(string attributeName, object newValue) {
+ Properties.Remove(attributeName) ;
+ Properties.Add(attributeName, newValue) ;
+ }
+
+ public bool IsDeleted() {
+ return !DeleteTime.Equals(new DateTime(0)) ;
+ }
+
+ public string RoutingKey() {
+ return ObjectID.RoutingCode() ;
+ }
+
+ public long AgentBank() {
+ return ObjectID.AgentBank() ;
+ }
+
+ public long BrokerBank() {
+ return ObjectID.BrokerBank() ;
+ }
+
+ override public string ToString() {
+ string propertyString = "" ;
+ foreach (KeyValuePair<string, object> pair in Properties) {
+ propertyString = propertyString + String.Format("(Name: '{0}' Value: '{1}')", pair.Key, pair.Value) ;
+ }
+
+ string statsString = "" ;
+ foreach (KeyValuePair<string, object> sPair in Statistics) {
+ statsString = statsString + String.Format("(Name: '{0}' Value: '{1}')", sPair.Key, sPair.Value) ;
+ }
+ if (Managed) {
+ return String.Format("Managed QMFObject {0}:{1}({2}) Properties: [{3}] Statistics: [{4}])", Schema.PackageName, Schema.ClassName, ObjectID, propertyString, statsString) ;
+ } else {
+ return String.Format("QMFObject {0}:{1} Properties: [{2}] Statistics: [{3}]", Schema.PackageName, Schema.ClassName, propertyString, statsString) ;
+ }
+ }
+
+ public MethodResult InvokeMethod(string name, params object[] args) {
+ return this.InternalInvokeMethod(name, new List<object>(args), true, Broker.SYNC_TIME ) ;
+ }
+
+ public MethodResult InvokeMethod(string name, int timeToLive, params object[] args) {
+ return this.InternalInvokeMethod(name, new List<object>(args), true, timeToLive) ;
+ }
+
+ public MethodResult InvokeMethod(string name, bool synchronous, int timeToLive, params object[] args) {
+ return this.InternalInvokeMethod(name, new List<object>(args), synchronous, timeToLive ) ;
+ }
+
+ public MethodResult InvokeMethod(string name, bool synchronous, params object[] args) {
+ return this.InternalInvokeMethod(name, new List<object>(args), synchronous, Broker.SYNC_TIME) ;
+ }
+
+ protected MethodResult InternalInvokeMethod(string name, List<object> args, bool synchronous, int timeToLive) {
+ if (!Managed) {
+ throw new Exception ("Object is not Managed") ;
+ }
+ if (Schema.GetMethod(name) == null) {
+ throw new Exception (String.Format("Method named '{0}' does not exist", name)) ;
+ }
+ return Session.InvokeMethod(this, name, args, synchronous, timeToLive) ;
+ }
+
+ public void Encode (IEncoder enc) {
+ int mask = 0 ;
+ int bit = 0 ;
+ List<SchemaProperty> propsToEncode = new List<SchemaProperty>() ;
+ log.Debug(String.Format("Encoding class {0}:{1}", Schema.PackageName, Schema.ClassName)) ;
+
+ enc.WriteUint8(20) ;
+ Schema.Key.encode(enc) ;
+
+ foreach (SchemaProperty prop in Schema.GetAllProperties()) {
+ if (prop.Optional) {
+ if (bit == 0) {
+ bit =1 ;
+ }
+ if ((Properties.ContainsKey(prop.Name)) && (Properties[prop.Name] != null)) {
+ mask |= bit ;
+ propsToEncode.Add(prop) ;
+ } else {
+ }
+ bit = bit << 1 ;
+ if (bit == 256) {
+ bit = 0 ;
+ enc.WriteUint8((short)mask) ;
+ mask = 0 ;
+ }
+ } else {
+ propsToEncode.Add(prop) ;
+ }
+ }
+ if (bit != 0) {
+ enc.WriteUint8((short)mask) ;
+ }
+
+ foreach (SchemaProperty prop in propsToEncode) {
+ object obj = Properties[prop.Name] ;
+ //log.Debug(String.Format("Encoding property {0}", prop.Name)) ;
+ Session.EncodeValue(enc, prop.Type, obj) ;
+ }
+ foreach (SchemaStatistic stat in Schema.Statistics) {
+ object obj = Statistics[stat.Name] ;
+ Session.EncodeValue(enc, stat.Type, obj) ;
+ }
+ log.Debug("Done") ;
+
+ }
+
+
+ protected void safeAddProperty(string propName, object value) {
+ if (Properties.ContainsKey(propName)) {
+ Properties[propName] = value ;
+ } else {
+ Properties.Add(propName, value) ;
+ }
+ }
+
+
+ }
+}
diff --git a/dotnet/client-010/management/console/SchemaArgument.cs b/dotnet/client-010/management/console/SchemaArgument.cs
new file mode 100644
index 0000000000..d3ee508b31
--- /dev/null
+++ b/dotnet/client-010/management/console/SchemaArgument.cs
@@ -0,0 +1,59 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic ;
+using org.apache.qpid.transport.codec ;
+
+namespace org.apache.qpid.console
+{
+
+ /**
+ * Metadata that describes the mapping of a method parameter to a QMF Object
+ */
+ public class SchemaArgument : SchemaVariable
+ {
+
+ public string Direction {get;set;}
+
+ public SchemaArgument(IDecoder dec, bool methodArg)
+ {
+ Dictionary<string, Object> map = dec.ReadMap() ;
+ base.PopulateData(map) ;
+
+ if (map.ContainsKey("dir")) {
+ Direction = (string) map["dir"] ;
+ }
+ }
+
+ public bool IsInput() {
+ return Direction.Equals("I") | Direction.Equals("IO") ;
+ }
+
+ public bool IsOutput() {
+ return Direction.Equals("O") | Direction.Equals("IO") ;
+ }
+
+ public bool IsBidirectional() {
+ return Direction.Equals("IO") ;
+ }
+ }
+}
diff --git a/dotnet/client-010/management/console/SchemaClass.cs b/dotnet/client-010/management/console/SchemaClass.cs
new file mode 100644
index 0000000000..320312b61d
--- /dev/null
+++ b/dotnet/client-010/management/console/SchemaClass.cs
@@ -0,0 +1,141 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic ;
+using org.apache.qpid.transport;
+using org.apache.qpid.transport.codec ;
+
+using log4net ;
+
+namespace org.apache.qpid.console
+{
+
+ /**
+ * Metadata that describes the mapping of a class to a QMF Object
+ */
+ public class SchemaClass
+ {
+ public static int CLASS_KIND_TABLE = 1 ;
+ public static int CLASS_KIND_EVENT = 2 ;
+
+ public static ILog log = LogManager.GetLogger(typeof(SchemaClass)) ;
+
+
+ public ClassKey Key {get;set;}
+ public ClassKey SuperType {get;set;}
+ public int Kind {get;set;}
+ public List<SchemaMethod> Methods = new List<SchemaMethod>() ;
+ public List<SchemaArgument> Arguments = new List<SchemaArgument>() ;
+ public List<SchemaProperty> Properties = new List<SchemaProperty>() ;
+ public List<SchemaStatistic> Statistics = new List<SchemaStatistic>() ;
+
+ public string ClassName { get { return Key.ClassName;}}
+ public string PackageName { get { return Key.PackageName;}}
+ public string ClassKeyString { get { return Key.GetKeyString();}}
+
+ protected Session Session {get;set;}
+
+ public SchemaClass(int kind, ClassKey key, IDecoder dec, Session session)
+ {
+ log.Debug(String.Format("New schema class {0}", key)) ;
+ Kind = kind ;
+ Session = session ;
+ this.Key = key ;
+ bool hasSupertype = false ;
+
+ if (kind == CLASS_KIND_TABLE) {
+ int propCount = dec.ReadUint16() ;
+ int statCount = dec.ReadUint16() ;
+ int methodCount = dec.ReadUint16() ;
+
+ if (hasSupertype) {
+ SuperType = new ClassKey(dec) ;
+ }
+
+ for(int x = 0 ; x < propCount ; x++) {
+ Properties.Add(new SchemaProperty(dec)) ;
+ }
+ for(int x = 0 ; x < statCount ; x++) {
+ Statistics.Add(new SchemaStatistic(dec)) ;
+ }
+ for(int x = 0 ; x < methodCount ; x++) {
+ Methods.Add(new SchemaMethod(dec)) ;
+ }
+ }
+
+ if (kind == CLASS_KIND_EVENT) {
+ int argCount = dec.ReadUint16() ;
+ if (hasSupertype) {
+ SuperType = new ClassKey(dec) ;
+ }
+ for(int x = 0 ; x < argCount ; x++) {
+ Arguments.Add(new SchemaArgument(dec, false)) ;
+ }
+ }
+ }
+
+ public SchemaMethod GetMethod(string name) {
+ SchemaMethod returnValue = null ;
+ foreach(SchemaMethod method in Methods) {
+ if (method.Name.Equals(name)) {
+ returnValue = method ;
+ break ;
+ }
+ }
+ return returnValue ;
+ }
+
+ public List<SchemaProperty> GetAllProperties() {
+ if (SuperType == null) {
+ return Properties ;
+ } else {
+ List<SchemaProperty> allProperties = new List<SchemaProperty>(Properties) ;
+ allProperties.AddRange(Session.GetSchema(SuperType).GetAllProperties()) ;
+ return allProperties ;
+ }
+ }
+
+ public List<SchemaStatistic> GetAllStatistics() {
+ if (SuperType == null) {
+ return Statistics ;
+ } else {
+ List<SchemaStatistic> allStats = new List<SchemaStatistic>(Statistics) ;
+ allStats.AddRange(Session.GetSchema(SuperType).GetAllStatistics()) ;
+ return allStats ;
+ }
+ }
+
+ public List<SchemaMethod> GetAllMethods() {
+ if (SuperType == null) {
+ return Methods ;
+ } else {
+ List<SchemaMethod> allMethods = new List<SchemaMethod>(Methods) ;
+ allMethods.AddRange(Session.GetSchema(SuperType).GetAllMethods()) ;
+ return allMethods ;
+ }
+ }
+
+ public bool HasSuperType() {
+ return SuperType != null ;
+ }
+ }
+}
diff --git a/dotnet/client-010/management/console/SchemaMethod.cs b/dotnet/client-010/management/console/SchemaMethod.cs
new file mode 100644
index 0000000000..0a843262a4
--- /dev/null
+++ b/dotnet/client-010/management/console/SchemaMethod.cs
@@ -0,0 +1,66 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic ;
+using org.apache.qpid.transport;
+using org.apache.qpid.transport.codec ;
+
+namespace org.apache.qpid.console
+{
+
+ /**
+ * Metadata that describes the mapping of a method to a QMF Object
+ */
+ public class SchemaMethod
+ {
+ public string Name {get;set;}
+ public int ArgCount {get;set;}
+ public int InputArgCount {get;set;}
+ public int OutputArgCount {get;set;}
+ public int BidirectionalArgCount {get;set;}
+ public string Description {get;set;}
+ public List<SchemaArgument> Arguments = new List<SchemaArgument>();
+
+ public SchemaMethod(IDecoder dec)
+ {
+ Dictionary<string, Object> map = dec.ReadMap() ;
+ Name = (string) map["name"] ;
+ ArgCount = (int) map["argCount"] ;
+ if (map.ContainsKey("desc")) {
+ Description = (string) map["desc"] ;
+ }
+ for (int x = 0 ; x < ArgCount ; x++) {
+ SchemaArgument arg = new SchemaArgument(dec, true) ;
+ Arguments.Add(arg) ;
+ if (arg.IsInput()) {
+ InputArgCount += 1 ;
+ }
+ if (arg.IsOutput()) {
+ OutputArgCount += 1 ;
+ }
+ if (arg.IsBidirectional()) {
+ BidirectionalArgCount += 1 ;
+ }
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/management/console/SchemaProperty.cs b/dotnet/client-010/management/console/SchemaProperty.cs
new file mode 100644
index 0000000000..50d3c62f8d
--- /dev/null
+++ b/dotnet/client-010/management/console/SchemaProperty.cs
@@ -0,0 +1,59 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic ;
+using org.apache.qpid.transport.codec ;
+
+namespace org.apache.qpid.console
+{
+
+ /**
+ * Metadata that describes the mapping of an object property to a QMF Object
+ */
+ public class SchemaProperty : SchemaVariable
+ {
+ public int Access {get;set;}
+ public bool Index {get;set;}
+ public bool Optional {get;set;}
+
+ public SchemaProperty(IDecoder dec)
+ {
+ Dictionary<string, Object> map = dec.ReadMap() ;
+ base.PopulateData(map) ;
+ Name = (string) map["name"] ;
+
+ if (map.ContainsKey("optional")) {
+ //System.Console.WriteLine("optional") ;
+ Optional = (int)map["optional"] != 0 ;
+ }
+ if (map.ContainsKey("index")) {
+ //System.Console.WriteLine("index") ;
+ Index = (int)map["index"] != 0 ;
+ }
+ if (map.ContainsKey("access")) {
+ //System.Console.WriteLine("access") ;
+ Access = (int) map["access"] ;
+ }
+
+ }
+ }
+}
diff --git a/dotnet/client-010/management/console/SchemaStatistic.cs b/dotnet/client-010/management/console/SchemaStatistic.cs
new file mode 100644
index 0000000000..ff96b98388
--- /dev/null
+++ b/dotnet/client-010/management/console/SchemaStatistic.cs
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic ;
+using org.apache.qpid.transport.codec ;
+
+namespace org.apache.qpid.console
+{
+
+ /**
+ * Metadata that describes the mapping of an object Statistic
+ */
+ public class SchemaStatistic
+ {
+
+ public string Name {get;set;}
+ public short Type {get;set;}
+ public string Description {get;set;}
+ public string Unit {get;set;}
+
+ public SchemaStatistic(IDecoder dec)
+ {
+ Dictionary<string, Object> map = dec.ReadMap() ;
+ Name = (string) map["name"] ;
+ Type = (short) short.Parse(""+map["type"]) ;
+
+ if (map.ContainsKey("unit")) {
+ Unit = (string) map["unit"] ;
+ }
+ if (map.ContainsKey("description")) {
+ Description = (string) map["description"] ;
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/management/console/SchemaVariable.cs b/dotnet/client-010/management/console/SchemaVariable.cs
new file mode 100644
index 0000000000..50455ab38a
--- /dev/null
+++ b/dotnet/client-010/management/console/SchemaVariable.cs
@@ -0,0 +1,84 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic ;
+using org.apache.qpid.transport.codec ;
+
+namespace org.apache.qpid.console
+{
+
+ /**
+ * Metadata for mapping properties, arguments, and statistics
+ */
+ public abstract class SchemaVariable
+ {
+ public string Name {get;set;}
+ public short Type {get;set;}
+ public string Description {get;set;}
+ public string Unit {get;set;}
+ public int? Min {get;set;}
+ public int? Max {get;set;}
+ public int? MaxLength {get;set;}
+ public string Default {get;set;}
+ public string RefPackage {get;set;}
+ public string RefClass {get;set;}
+
+ public SchemaVariable() {
+ }
+
+ protected void PopulateData(Dictionary<string, Object> map)
+ {
+
+ if (map.ContainsKey("name")) {
+ Name = (string) map["name"] ;
+ }
+ if (map.ContainsKey("type")) {
+ Type = short.Parse((""+ map["type"])) ;
+ }
+
+ if (map.ContainsKey("unit")) {
+ Unit = (string) map["unit"] ;
+ }
+ if (map.ContainsKey("min")) {
+ Min = (int) map["min"] ;
+ }
+ if (map.ContainsKey("max")) {
+ Max = (int) map["max"] ;
+ }
+ if (map.ContainsKey("maxlen")) {
+ MaxLength = (int) map["maxlen"] ;
+ }
+ if (map.ContainsKey("description")) {
+ Description = (string) map["description"] ;
+ }
+ if (map.ContainsKey("refClass")) {
+ RefClass = (string) map["refClass"] ;
+ }
+ if (map.ContainsKey("refPackage")) {
+ RefPackage = (string) map["refPackage"] ;
+ }
+ if (map.ContainsKey("Default")) {
+ Default = (string) map["default"] ;
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/management/console/SequenceManager.cs b/dotnet/client-010/management/console/SequenceManager.cs
new file mode 100644
index 0000000000..29f1ba26b0
--- /dev/null
+++ b/dotnet/client-010/management/console/SequenceManager.cs
@@ -0,0 +1,62 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Threading ;
+
+namespace org.apache.qpid.console
+{
+
+ /**
+ * Holds state during asynchronous calls to the broker.
+ */
+ public class SequenceManager
+ {
+ long sequence = 0 ;
+ Dictionary<long, Object> pending = new Dictionary<long, Object>() ;
+ Object lockObject = new Object() ;
+
+ public SequenceManager()
+ {
+ }
+
+ public long Reserve(Object data) {
+ long returnValue = 0 ;
+ lock(lockObject) {
+ returnValue = sequence ;
+ sequence += 1 ;
+ pending.Add(returnValue, data) ;
+ }
+ return returnValue;
+ }
+
+ public Object Release(long seq) {
+ Object returnValue = null ;
+ lock(lockObject) {
+ returnValue = pending[seq] ;
+ pending.Remove(seq) ;
+ }
+
+ return returnValue ;
+ }
+ }
+}
diff --git a/dotnet/client-010/management/console/Session.cs b/dotnet/client-010/management/console/Session.cs
new file mode 100644
index 0000000000..d9c5948e57
--- /dev/null
+++ b/dotnet/client-010/management/console/Session.cs
@@ -0,0 +1,796 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic;
+using System.IO ;
+using System.Reflection ;
+using System.Threading ;
+using log4net ;
+using org.apache.qpid.client ;
+using org.apache.qpid.transport.util;
+using org.apache.qpid.transport.codec ;
+
+namespace org.apache.qpid.console
+{
+
+ /**
+ * Main Interaction point for interaction with the bus. Can be used to locate objects
+ * on the bus, and invoke messages on them.
+ */
+ public class Session
+ {
+ public static ILog log = LogManager.GetLogger(typeof(Session)) ;
+
+ public static int CONTEXT_SYNC = 1 ;
+ public static int CONTEXT_STARTUP = 2 ;
+ public static int CONTEXT_MULTIGET = 3 ;
+ public static int DEFAULT_GET_WAIT_TIME = 60000 ;
+
+ public bool RecieveObjects = true ;
+ public bool RecieveEvents = true ;
+ public bool RecieveHeartbeat = true ;
+ public bool UserBindings = false ;
+ public Console Console ;
+
+ protected Dictionary<string, Dictionary<string, SchemaClass>> Packages = new Dictionary<string, Dictionary<string, SchemaClass>>() ;
+ protected List<Broker> Brokers = new List<Broker>() ;
+ protected SequenceManager SequenceManager = new SequenceManager() ;
+ protected object LockObject = new Object();
+ protected List<long> SyncSequenceList = new List<long>() ;
+ protected List<QMFObject> GetResult ;
+ protected Object SyncResult ;
+
+ public Session()
+ {
+ }
+
+ public Session(Console console) {
+ Console = console ;
+ }
+
+ public void AddBroker(string url) {
+ BrokerURL brokerurl = GetBrokerURL(url) ;
+ Broker broker = new Broker(this, brokerurl) ;
+ Brokers.Add(broker) ;
+
+ Dictionary<string, object> args = new Dictionary<string, object>() ;
+ args.Add("_class", "agent") ;
+ args.Add("_broker", broker) ;
+ this.GetObjects(args) ;
+ }
+
+ public void RemoveBroker(Broker broker) {
+ if (Brokers.Contains(broker)) {
+ Brokers.Remove(broker) ;
+ }
+
+ broker.Shutdown() ;
+ }
+
+ public void Close() {
+ foreach (Broker broker in Brokers.ToArray()) {
+ this.RemoveBroker(broker) ;
+ }
+ }
+
+ protected BrokerURL GetBrokerURL(string url) {
+ return new BrokerURL(url) ;
+ }
+
+
+ public List<QMFObject> GetObjects(Dictionary<string, object> args) {
+ List<Broker> brokerList = null ;
+ List<Agent> agentList = new List<Agent>() ;
+
+ if (args.ContainsKey("_broker")) {
+ brokerList = new List<Broker>() ;
+ brokerList.Add((Broker)args["_broker"]) ;
+ } else {
+ brokerList = this.Brokers ;
+ }
+
+ foreach (Broker broker in brokerList) {
+ broker.WaitForStable() ;
+ }
+
+ if (args.ContainsKey("_agent")) {
+ Agent agent = (Agent)args["_agent"] ;
+ if (brokerList.Contains(agent.Broker)) {
+ agentList.Add(agent) ;
+ } else {
+ throw new Exception("Agent is not managed by this console or the supplied broker") ;
+ }
+ } else {
+ if (args.ContainsKey("_objectId")) {
+ ObjectID oid = (ObjectID) args["_objectId"] ;
+ foreach (Broker broker in Brokers) {
+ foreach (Agent agent in broker.Agents.Values) {
+ if ((agent.AgentBank == oid.AgentBank()) && (agent.BrokerBank == oid.BrokerBank())) {
+ agentList.Add(agent) ;
+ }
+ }
+ }
+ }
+ else {
+ foreach (Broker broker in brokerList) {
+ foreach (Agent agent in broker.Agents.Values) {
+ if (agent.Broker.IsConnected()) {
+ agentList.Add(agent) ;
+ }
+ }
+ }
+ }
+ }
+
+ GetResult = new List<QMFObject>() ;
+
+ if (agentList.Count > 0) {
+ //FIXME Add a bunch of other suff too
+ foreach (Agent agent in agentList) {
+ Dictionary<string, object> getParameters = new Dictionary<string, object>() ;
+ Broker broker = agent.Broker ;
+ long seq = -1 ;
+ lock(LockObject) {
+ seq = SequenceManager.Reserve(Session.CONTEXT_MULTIGET) ;
+ SyncSequenceList.Add(seq) ;
+ }
+ object packageName = null ;
+ object className = null ;
+ object key = null ;
+ object sClass = null ;
+ object oid = null ;
+ object hash = null ;
+
+ args.TryGetValue("_schema", out sClass) ;
+ args.TryGetValue("_key", out key) ;
+ args.TryGetValue("_class", out className) ;
+ args.TryGetValue("_package", out packageName) ;
+ args.TryGetValue("_objectID", out oid) ;
+ args.TryGetValue("_hash", out hash) ;
+
+ if ((className == null) && (oid == null) && (oid == null)) {
+ throw new Exception("No class supplied, use '_schema', '_key', '_class', or '_objectId' argument") ;
+ }
+
+ if (oid != null) {
+ getParameters.Add("_objectID", oid) ;
+ }
+ else {
+ if (sClass != null) {
+ key = key ?? ((SchemaClass)sClass).Key ;
+ }
+ if (key != null) {
+ ClassKey cKey = (ClassKey)key ;
+ className = className ?? cKey.ClassName ;
+ packageName = packageName ?? cKey.PackageName ;
+ hash = hash ?? cKey.Hash ;
+ }
+
+ if (packageName != null) {
+ getParameters.Add("_package", packageName) ;
+ }
+ if (className != null) {
+ getParameters.Add("_class", className) ;
+ }
+ if (hash != null) {
+ getParameters.Add("_hash", hash) ;
+ }
+ foreach (KeyValuePair<string, object> pair in args) {
+ if (!pair.Key.StartsWith("_")) {
+ getParameters.Add(pair.Key, pair.Value) ;
+ }
+ }
+ }
+
+ IEncoder enc = broker.CreateEncoder('G', seq) ;
+ enc.WriteMap(getParameters) ;
+ string routingKey = String.Format("agent.{0}.{1}", agent.BrokerBank, agent.AgentBank) ;
+ Message msg = broker.CreateMessage(enc, routingKey) ;
+ log.Debug("Get Object Keys: ") ;
+ foreach (string pKey in getParameters.Keys) {
+ log.Debug(String.Format("\tKey: '{0}' Value: '{1}'", pKey, getParameters[pKey])) ;
+ }
+ broker.Send(msg) ;
+ }
+
+ int waittime = DEFAULT_GET_WAIT_TIME ;
+ bool timeout = false ;
+ if (args.ContainsKey("_timeout")) {
+ waittime = (int) args["_timeout"] ;
+ }
+ DateTime start = DateTime.Now ;
+ lock (LockObject) {
+ // FIXME ERROR
+ while (SyncSequenceList.Count > 0){
+ Monitor.Wait(LockObject,waittime) ;
+ TimeSpan duration = DateTime.Now - start;
+ if (duration.TotalMilliseconds > waittime) {
+ foreach (long pendingSeq in SyncSequenceList) {
+ SequenceManager.Release(pendingSeq) ;
+ }
+ SyncSequenceList.Clear() ;
+ timeout = true ;
+ }
+ }
+ }
+
+ //FIXME Add the error logic
+ if ((GetResult.Count == 0) && timeout) {
+ throw new Exception ("Get Request timed out") ;
+ }
+ }
+ return GetResult ;
+ }
+
+ public List<string> GetPackages() {
+ this.WaitForStable() ;
+ List<string> returnValue = new List<string>() ;
+ foreach (String name in Packages.Keys) {
+ returnValue.Add(name) ;
+ }
+
+ return returnValue ;
+ }
+
+ public List<ClassKey> GetClasses(string packageName) {
+ List<ClassKey> returnValue = new List<ClassKey>() ;
+ this.WaitForStable() ;
+
+ if (Packages.ContainsKey(packageName)) {
+ foreach (SchemaClass sClass in Packages[packageName].Values) {
+ returnValue.Add(sClass.Key) ;
+ }
+ }
+
+ return returnValue ;
+ }
+
+ public SchemaClass GetSchema(ClassKey key) {
+ return GetSchema(key, true) ;
+ }
+
+ protected SchemaClass GetSchema(ClassKey key, bool waitForStable) {
+ if (waitForStable) {
+ this.WaitForStable() ;
+ }
+
+ SchemaClass returnValue = null ;
+
+ try {
+ returnValue = Packages[key.PackageName][key.GetKeyString()] ;
+ }
+ catch (KeyNotFoundException) {
+ // eat it
+ }
+
+ return returnValue ;
+ }
+
+
+ protected void WaitForStable() {
+ foreach (Broker broker in Brokers) {
+ broker.WaitForStable() ;
+ }
+ }
+
+
+ public Broker GetBroker(long BrokerBank) {
+ Broker returnValue = null ;
+
+ foreach (Broker broker in Brokers) {
+ if (broker.BrokerBank() == BrokerBank) {
+ returnValue = broker ;
+ break ;
+ }
+ }
+
+ return returnValue ;
+ }
+
+ public MethodResult InvokeMethod(QMFObject obj, string name, List<object> args, bool synchronous, int timeToLive) {
+ Broker aBroker = this.GetBroker(obj.BrokerBank()) ;
+
+ long seq = this.SendMethodRequest(obj, aBroker, name, args, synchronous, timeToLive) ;
+ if (seq != 0) {
+ if (!synchronous) {
+ return null ;
+ }
+ try {
+ aBroker.WaitForSync(timeToLive) ;
+ } catch (Exception e) {
+ SequenceManager.Release(seq) ;
+ throw e ;
+ }
+
+ // FIXME missing error logic in the broker
+ return (MethodResult) SyncResult ;
+ }
+
+ return null ;
+ }
+
+ protected long SendMethodRequest(QMFObject obj, Broker aBroker, string name, List<object> args, bool synchronous, int timeToLive) {
+
+ SchemaMethod method = obj.Schema.GetMethod(name) ;
+ if (args == null) {
+ args = new List<object>() ;
+ }
+
+ long seq = 0 ;
+ if (method != null) {
+ KeyValuePair<SchemaMethod, bool> pair = new KeyValuePair<SchemaMethod, bool>(method, synchronous) ;
+ seq = SequenceManager.Reserve(pair) ;
+ IEncoder enc = aBroker.CreateEncoder('M', seq) ;
+ obj.ObjectID.encode(enc) ;
+ obj.Schema.Key.encode(enc) ;
+ enc.WriteStr8(name) ;
+
+ if (args.Count < method.InputArgCount) {
+ throw new Exception(String.Format("Incorrect number of arguments: expected {0}, got{1}", method.InputArgCount, args.Count)) ;
+ }
+
+ int argIndex = 0 ;
+ foreach (SchemaArgument arg in method.Arguments) {
+ if (arg.IsInput()) {;
+ this.EncodeValue(enc, arg.Type, args[argIndex]) ;
+ argIndex += 1 ;
+ }
+ }
+
+ Message msg = aBroker.CreateMessage(enc,obj.RoutingKey(),timeToLive) ;
+
+ if (synchronous) {
+ aBroker.SetSyncInFlight(true) ;
+ }
+ aBroker.Send(msg) ;
+ }
+ return seq ;
+ }
+
+ public QMFObject MakeObject(ClassKey key) {
+ SchemaClass sClass = this.GetSchema(key) ;
+ if (sClass == null) {
+ throw new Exception("No schema found for class " + key.ToString()) ;
+ }
+
+ return this.CreateQMFObject(sClass, true, true, false) ;
+ }
+
+ public QMFObject MakeObject(String keyString) {
+ return this.MakeObject(new ClassKey(keyString)) ;
+ }
+
+ // Callback Methods
+ public void HandleNewAgent(Agent agent) {
+ if (Console != null) {
+ Console.NewAgent(agent) ;
+ }
+ }
+
+ public void HandleAgentRemoved(Agent agent) {
+ if (Console != null) {
+ Console.AgentRemoved(agent) ;
+ }
+ }
+
+ public void HandleBrokerConnect(Broker broker) {
+ if (Console != null) {
+ Console.BrokerConnected(broker) ;
+ }
+ }
+
+ public void HandleBrokerDisconnect(Broker broker) {
+ if (Console != null) {
+ Console.BrokerDisconnected(broker) ;
+ }
+ }
+
+ public void HandleBrokerResponse(Broker broker, IDecoder decoder, long sequence) {
+ if (Console != null) {
+ Console.BrokerInformation(broker) ;
+ }
+
+ long seq = SequenceManager.Reserve(CONTEXT_STARTUP) ;
+ IEncoder endocder = broker.CreateEncoder('P', seq) ;
+ broker.Send(endocder) ;
+ }
+
+ public void HandlePackageIndicator(Broker broker, IDecoder decoder, long sequence) {
+ string packageName = decoder.ReadStr8() ;
+ bool notify = false ;
+ if (!Packages.ContainsKey(packageName)) {
+ lock (LockObject) {
+ Packages[packageName] = new Dictionary<string, SchemaClass>() ;
+ notify = true ;
+ }
+ }
+
+ if (notify && Console != null) {
+ Console.NewPackage(packageName) ;
+ }
+
+ broker.IncrementOutstanding() ;
+ long seq = SequenceManager.Reserve(Session.CONTEXT_STARTUP) ;
+ IEncoder enc = broker.CreateEncoder('Q', seq) ;
+ enc.WriteStr8(packageName) ;
+ broker.Send(enc) ;
+ }
+
+ public void HandleCommandComplete(Broker broker, IDecoder decoder, long sequence) {
+
+ long code = decoder.ReadUint32() ;
+ string text = decoder.ReadStr8() ;
+ Object context = this.SequenceManager.Release(sequence) ;
+
+ if (context.Equals(CONTEXT_STARTUP)) {
+ broker.DecrementOutstanding() ;
+ } else {
+ if ((context.Equals(CONTEXT_SYNC)) & broker.GetSyncInFlight()) {
+ broker.SetSyncInFlight(false) ;
+ } else {
+ if (context.Equals(CONTEXT_MULTIGET) && SyncSequenceList.Contains(sequence)) {
+ lock(LockObject) {
+ SyncSequenceList.Remove(sequence) ;
+ if (SyncSequenceList.Count == 0) {
+ Monitor.PulseAll(LockObject) ;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void HandleClassIndicator(Broker broker, IDecoder decoder, long sequence) {
+ short kind = decoder.ReadUint8() ;
+ ClassKey classKey = new ClassKey(decoder) ;
+ bool unknown = false ;
+
+
+ lock (LockObject) {
+ if (Packages.ContainsKey(classKey.PackageName)) {
+ if (!Packages[classKey.PackageName].ContainsKey(classKey.GetKeyString())) {
+ unknown = true ;
+ }
+ }
+ }
+
+ if (unknown) {
+ broker.IncrementOutstanding() ;
+ long seq = SequenceManager.Reserve(Session.CONTEXT_STARTUP) ;
+ IEncoder enc = broker.CreateEncoder('S', seq) ;
+ classKey.encode(enc) ;
+ broker.Send(enc) ;
+ }
+ }
+
+ public void HandleMethodResponse(Broker broker, IDecoder decoder, long sequence) {
+ long code = decoder.ReadUint32() ;
+ string text = decoder.ReadStr16() ;
+
+ Dictionary<string, object> outArgs = new Dictionary<string, object>() ;
+ object obj = SequenceManager.Release(sequence) ;
+
+ if (obj == null) {
+ return ;
+ }
+
+ KeyValuePair<SchemaMethod, bool> pair = (KeyValuePair<SchemaMethod, bool>) obj ;
+ if (code == 0) {
+ foreach (SchemaArgument arg in pair.Key.Arguments) {
+ if (arg.IsOutput()) {
+ outArgs.Add(arg.Name, this.DecodeValue(decoder, arg.Type)) ;
+ }
+ }
+ }
+
+ MethodResult result = new MethodResult(code, text, outArgs) ;
+
+ if (pair.Value) {
+ this.SyncResult = result;
+ broker.SetSyncInFlight(false) ;
+ }
+
+ if (Console != null) {
+ Console.MethodResponse(broker, sequence, result) ;
+ }
+ }
+
+ public void HandleHeartbeatIndicator(Broker broker, IDecoder decoder, long sequence, IMessage msg) {
+ if (Console != null) {
+ long brokerBank = 1 ;
+ long agentBank = 0 ;
+ try {
+ string routingKey = msg.DeliveryProperties.GetRoutingKey() ;
+ if (routingKey != null) {
+ agentBank = Agent.GetBrokerBank(routingKey) ;
+ brokerBank = Agent.GetBrokerBank(routingKey) ;
+ }
+ }
+ catch (Exception e) {
+ log.Warn("Internal QPID error", e) ;
+ }
+
+ string agentKey = Agent.AgentKey(agentBank, brokerBank) ;
+ long timestamp = decoder.ReadUint64() ;
+ if (broker.Agents.ContainsKey(agentKey)) {
+ Agent agent = broker.Agents[agentKey] ;
+ Console.HearbeatRecieved(agent, timestamp) ;
+ }
+ }
+
+ }
+
+ public void HandleEventIndicator(Broker broker, IDecoder decoder, long sequence) {
+ if (Console != null) {
+ QMFEvent newEvent = new QMFEvent(this, decoder) ;
+ Console.EventRecieved(broker, newEvent) ;
+ }
+ }
+
+ public void HandleSchemaResponse(Broker broker, IDecoder decoder, long sequence) {
+ short kind = decoder.ReadUint8() ;
+ ClassKey classKey = new ClassKey(decoder) ;
+ SchemaClass sClass = new SchemaClass(kind, classKey, decoder, this) ;
+ lock(LockObject) {
+ Dictionary<string, SchemaClass> classMappings = Packages[sClass.PackageName] ;
+ classMappings.Remove(sClass.ClassKeyString) ;
+ classMappings.Add(sClass.ClassKeyString, sClass) ;
+ }
+
+ SequenceManager.Release(sequence) ;
+ broker.DecrementOutstanding() ;
+ if (Console != null) {
+ this.Console.NewClass(kind, classKey) ;
+ }
+ }
+
+ public void HandleContentIndicator(Broker broker, IDecoder decoder, long sequence, bool hasProperties, bool hasStatistics) {
+
+ ClassKey key = new ClassKey(decoder) ;
+ SchemaClass sClass = null ;;
+ lock (LockObject) {
+ sClass = GetSchema(key, false) ;
+ }
+ if (sClass != null) {
+ QMFObject obj = this.CreateQMFObject(sClass, decoder, hasProperties, hasStatistics, true) ;
+
+ if (key.PackageName.Equals("org.apache.qpid.broker") && key.ClassName.Equals("agent") && hasProperties) {
+ broker.UpdateAgent(obj) ;
+ }
+
+ lock (LockObject) {
+ if (SyncSequenceList.Contains(sequence)) {
+ if (!obj.IsDeleted() && this.SelectMatch(obj)) {
+ GetResult.Add(obj) ;
+ }
+ }
+ }
+
+ if (Console != null) {
+ if (hasProperties) {
+ Console.ObjectProperties(broker, obj) ;
+ }
+ if (hasStatistics) {
+ Console.ObjectStatistics(broker, obj) ;
+ }
+ }
+ }
+ }
+
+ public bool SelectMatch(QMFObject obj) {
+ return true ;
+ }
+
+ public object DecodeValue(IDecoder dec, short type) {
+
+ switch (type) {
+ case 1: return dec.ReadUint8() ; // U8
+ case 2: return dec.ReadUint16() ; // U16
+ case 3: return dec.ReadUint32() ; // U32
+ case 4: return dec.ReadUint64() ; // U64
+ case 6: return dec.ReadStr8() ; // SSTR
+ case 7: return dec.ReadStr16() ; // LSTR
+ case 8: return dec.ReadDatetime() ; // ABSTIME
+ case 9: return dec.ReadUint32() ; // DELTATIME
+ case 10: return new ObjectID(dec) ; // ref
+ case 11: return dec.ReadUint8() != 0 ; // bool
+ case 12: return dec.ReadFloat() ; // float
+ case 13: return dec.ReadDouble() ; // double
+ case 14: return dec.ReadUuid() ; // UUID
+ case 15: return dec.ReadMap() ; // Ftable
+ case 16: return dec.ReadInt8() ; // int8
+ case 17: return dec.ReadInt16() ; // int16
+ case 18: return dec.ReadInt32() ; // int32
+ case 19: return dec.ReadInt64() ; // int64
+ case 20: // Object
+ // Peek into the inner type code, make sure
+ // it is actually an object
+ object returnValue = null ;
+ short innerTypeCode = dec.ReadUint8() ;
+ if (innerTypeCode != 20) {
+ returnValue = this.DecodeValue(dec, innerTypeCode) ;
+ }
+ else {
+ ClassKey classKey = new ClassKey(dec) ;
+ lock(LockObject) {
+ SchemaClass sClass = GetSchema(classKey) ;
+ if (sClass != null) {
+ returnValue = this.CreateQMFObject(sClass, dec, true, true, false) ;
+ }
+ }
+ }
+ return returnValue;
+ case 21: // List
+ {
+ MSDecoder lDec = new MSDecoder();
+ lDec.Init(new MemoryStream(dec.ReadVbin32()));
+ long count = lDec.ReadUint32();
+ List<object> newList = new List<object>();
+ while (count > 0)
+ {
+ short innerType = lDec.ReadUint8();
+ newList.Add(this.DecodeValue(lDec, innerType));
+ count -= 1;
+ }
+ return newList;
+ }
+ case 22: // Array
+ {
+ MSDecoder aDec = new MSDecoder();
+ aDec.Init(new MemoryStream(dec.ReadVbin32()));
+ long cnt = aDec.ReadUint32();
+ short innerType = aDec.ReadUint8();
+ List<object> aList = new List<object>();
+ while (cnt > 0)
+ {
+ aList.Add(this.DecodeValue(aDec, innerType));
+ cnt -= 1;
+ }
+ return aList;
+ }
+ default:
+ throw new Exception(String.Format("Invalid Type Code: {0}", type)) ;
+ }
+ }
+
+
+ public void EncodeValue(IEncoder enc, short type, object val) {
+ try {
+ switch ((int)type) {
+ case 1: enc.WriteUint8((short) val) ; break; // U8
+ case 2: enc.WriteUint16((int) val) ; break; // U16
+ case 3: enc.WriteUint32((long) val) ; break; // U32
+ case 4: enc.WriteUint64((long) val) ; break; // U64
+ case 6: enc.WriteStr8((string) val) ; break; // SSTR
+ case 7: enc.WriteStr16((string) val) ; break; // LSTR
+ case 8: enc.WriteDatetime((long) val); break; // ABSTIME
+ case 9: enc.WriteUint32((long) val); break; // DELTATIME
+ case 10: ((ObjectID)val).encode(enc) ; break; // ref
+ case 11:
+ if ((bool) val) {
+ enc.WriteUint8(1) ;
+ } else {
+ enc.WriteUint8(0) ;
+ }
+ break ;
+ case 12: enc.WriteFloat((float) val); break; // FLOAT
+ case 13: enc.WriteDouble((double) val); break; // DOUBLE
+ case 14: enc.WriteUuid((UUID) val) ; break ; // UUID
+ case 15: enc.WriteMap((Dictionary<string, object>) val) ; break ; // Ftable
+ case 16: enc.WriteInt8((short) val) ; break; // int8
+ case 17: enc.WriteInt16((int) val) ; break; // int16
+ case 18: enc.WriteInt32(long.Parse(""+ val)) ; break; // int32
+ case 19: enc.WriteInt64(long.Parse("" + val)) ; break; // int64
+ case 20: // Object
+ // Check that the object has a session, if not
+ // take ownership of it
+ QMFObject qObj = (QMFObject) val ;
+ if (qObj.Session == null) {
+ qObj.Session = this ;
+ }
+ qObj.Encode(enc) ;
+ break;
+ case 21: // List
+ List<object> items = (List<object>) val ;
+ MSEncoder lEnc = new MSEncoder(1) ;
+ lEnc.Init() ;
+ lEnc.WriteUint32(items.Count) ;
+ foreach (object obj in items) {
+ short innerType = Util.QMFType(obj) ;
+ lEnc.WriteUint8(innerType) ;
+ this.EncodeValue(lEnc,innerType,obj) ;
+ }
+ enc.WriteVbin32(lEnc.Segment().ToArray()) ;
+ break ;
+ case 22: // Array
+ List<object> aItems = (List<object>) val ;
+ MSEncoder aEnc = new MSEncoder(1) ;
+ aEnc.Init() ;
+ long aCount = aItems.Count ;
+ aEnc.WriteUint32(aCount) ;
+ if (aCount > 0) {
+ Object anObj = aItems[0] ;
+ short innerType = Util.QMFType(anObj) ;
+ aEnc.WriteUint8(innerType) ;
+ foreach (object obj in aItems) {
+ this.EncodeValue(aEnc,innerType,obj) ;
+ }
+ }
+ enc.WriteVbin32(aEnc.Segment().ToArray()) ;
+ break ;
+ default:
+ throw new Exception(String.Format("Invalid Type Code: {0}", type)) ;
+ }
+ }
+ catch (System.InvalidCastException e) {
+ string msg = String.Format("Class cast exception for typecode {0}, type {1} ", type, val.GetType()) ;
+ log.Error(msg) ;
+ throw new Exception(msg + type, e) ;
+ }
+ }
+
+ public List<string> BindingKeys() {
+ List<string> bindings = new List<string>() ;
+ bindings.Add("schema.#") ;
+ if (RecieveObjects & RecieveEvents & RecieveHeartbeat & !UserBindings) {
+ bindings.Add("console.#") ;
+ }
+ else {
+ if (RecieveObjects & !UserBindings) {
+ bindings.Add("console.obj.#") ;
+ }
+ else {
+ bindings.Add("console.obj.*.*.org.apache.qpid.broker.agent") ;
+ }
+ if (RecieveEvents) {
+ bindings.Add("console.event.#") ;
+ }
+ if (RecieveHeartbeat) {
+ bindings.Add("console.heartbeat.#") ;
+ }
+ }
+ return bindings ;
+ }
+
+ protected QMFObject CreateQMFObject(SchemaClass schema, bool hasProperties, bool hasStats , bool isManaged) {
+ Type realClass = typeof(QMFObject) ;
+ if (Console != null) {
+ realClass = Console.TypeMapping(schema.Key) ;
+ }
+ Type[] types = new Type[] {typeof(Session), typeof(SchemaClass), typeof(bool), typeof(bool),typeof(bool)} ;
+ object[] args = new object[] {this, schema, hasProperties, hasStats, isManaged} ;
+ ConstructorInfo ci = realClass.GetConstructor(types);
+ return (QMFObject) ci.Invoke(args) ;
+ }
+
+ protected QMFObject CreateQMFObject(SchemaClass schema, IDecoder dec, bool hasProperties, bool hasStats , bool isManaged) {
+ Type realClass = typeof(QMFObject) ;
+ if (Console != null) {
+ realClass = Console.TypeMapping(schema.Key) ;
+ }
+ Type[] types = new Type[] {typeof(Session), typeof(SchemaClass), typeof(IDecoder), typeof(bool), typeof(bool),typeof(bool)} ;
+ object[] args = new object[] {this, schema, dec, hasProperties, hasStats, isManaged} ;
+ ConstructorInfo ci = realClass.GetConstructor(types);
+ return (QMFObject) ci.Invoke(args) ;
+ }
+ }
+}
diff --git a/dotnet/client-010/management/console/Util.cs b/dotnet/client-010/management/console/Util.cs
new file mode 100644
index 0000000000..4a06f4e6af
--- /dev/null
+++ b/dotnet/client-010/management/console/Util.cs
@@ -0,0 +1,150 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic;
+using org.apache.qpid.client ;
+using org.apache.qpid.transport.util;
+using org.apache.qpid.transport.codec ;
+
+namespace org.apache.qpid.console
+{
+ public class Util
+ {
+ static Dictionary<Type, short> ENCODINGS = new Dictionary<Type, short>() ;
+
+
+ static Util() {
+ ENCODINGS.Add(typeof(string), 7) ;
+ ENCODINGS.Add(typeof(short), 1) ;
+ //ENCODINGS.Add(typeof(int), 2) ;
+ //ENCODINGS.Add(typeof(long), 3) ;
+ ENCODINGS.Add(typeof(float), 13) ;
+ ENCODINGS.Add(typeof(QMFObject), 20) ;
+ ENCODINGS.Add(typeof(int), 17) ;
+ ENCODINGS.Add(typeof(long), 18) ;
+ ENCODINGS.Add(typeof(System.Collections.Generic.List<>), 21) ;
+ }
+
+ /**
+ * Converts type numbers to schema type names
+ */
+ public static string TypeName(short type) {
+ switch(type) {
+ //case 0: return "UNKNOWN" ;
+ case 1: return "uint8" ;
+ case 2: return "uint16" ;
+ case 3: return "uint32" ;
+ case 4: return "uint64" ;
+ case 5: return "bool" ;
+ case 6: return "short-string" ;
+ case 7: return "long-string" ;
+ case 8: return "abs-time" ;
+ case 9: return "delta-time" ;
+ case 10: return "reference" ;
+ case 11: return "boolean" ;
+ case 12: return "float" ;
+ case 13: return "double" ;
+ case 14: return "uuid" ;
+ case 15: return "field-table" ;
+ case 16: return "int8" ;
+ case 17: return "int16" ;
+ case 18: return "int32" ;
+ case 19: return "int64" ;
+ case 20: return "object" ;
+ case 21: return "list" ;
+ case 22: return "array" ;
+ }
+
+ throw new Exception(String.Format("Invalid Type Code: {0}", type)) ;
+ }
+
+ /**
+ * Converts schema numbers to schema access names
+ */
+ public static string AccessName(int type) {
+ switch(type) {
+ //case 0: return "UNKNOWN" ;
+ case 1: return "ReadCreate" ;
+ case 2: return "ReadWrite" ;
+ case 3: return "ReadOnly" ;
+ }
+
+ throw new Exception(String.Format("Invalid Access Code: {0}", type)) ;
+ }
+
+ /**
+ * Default values per schema type
+ */
+ public static object DefaultValue(short type) {
+ switch(type) {
+ //case 0: return "UNKNOWN" ;
+ case 1: return 0 ;
+ case 2: return 0 ;
+ case 3: return 0l ;
+ case 4: return 0l ;
+ case 5: return false ;
+ case 6: return "" ;
+ case 7: return "" ;
+ case 8: return 0l ;
+ case 9: return 0l ;
+ case 10: return new ObjectID() ;
+ case 11: return false ;
+ case 12: return 0f ;
+ case 13: return 0d ;
+ case 14: return new UUID(0,0) ;
+ case 15: return new Dictionary<string, object>();
+ case 16: return 0 ;
+ case 17: return 0 ;
+ case 18: return 0l ;
+ case 19: return 0l ;
+ case 20: return null ;
+ case 21: return new List<object>() ;
+ case 22: return new List<object>() ;
+ }
+
+ throw new Exception(String.Format("Invalid Type Code: {0}", type)) ;
+ }
+
+ /**
+ * Returns a QMF type based on C# object type
+ */
+ public static short QMFType(object obj) {
+ if (ENCODINGS.ContainsKey(obj.GetType())) {
+ return ENCODINGS[obj.GetType()] ;
+ } else {
+ throw new Exception (String.Format("Unkown Type of {0}", obj.GetType())) ;
+ }
+ }
+
+ /**
+ * Grabs a friendly string version of bytes.
+ */
+ public static string ByteString(byte[] bytes) {
+ return System.Text.Encoding.UTF8.GetString(bytes) ;
+ }
+
+ protected Util()
+ {
+
+ }
+ }
+}
diff --git a/dotnet/client-010/management/console/XMLUtil.cs b/dotnet/client-010/management/console/XMLUtil.cs
new file mode 100644
index 0000000000..255b9c4dd1
--- /dev/null
+++ b/dotnet/client-010/management/console/XMLUtil.cs
@@ -0,0 +1,106 @@
+
+using System;
+using System.Collections.Generic;
+using org.apache.qpid.client ;
+
+namespace org.apache.qpid.console
+{
+
+
+ public class XMLUtil
+ {
+
+ public static string CommonAttributes(SchemaVariable var) {
+ string returnString = "" ;
+ if (var.Description != null){
+ returnString = returnString + String.Format(" desc='{0}'", var.Description) ;
+ }
+
+ if (var.RefPackage != null){
+ returnString = returnString + String.Format(" refPackage='{0}'", var.RefPackage) ;
+ }
+
+ if (var.RefClass != null){
+ returnString = returnString + String.Format(" refClass='{0}'", var.RefClass) ;
+ }
+
+ if (var.Unit != null){
+ returnString = returnString + String.Format(" unit='{0}'", var.Unit) ;
+ }
+
+ if (var.Min != null){
+ returnString = returnString + String.Format(" min='{0}'", var.Min) ;
+ }
+ if (var.Max != null){
+ returnString = returnString + String.Format(" max='{0}'", var.Max) ;
+ }
+ if (var.MaxLength != null){
+ returnString = returnString + String.Format(" maxLength='{0}'", var.MaxLength) ;
+ }
+
+ return returnString ;
+ }
+
+ public static string SchemaXML(Session sess, string packageName) {
+ string returnValue = String.Format("<schema package='{0}'>\n", packageName) ;
+ foreach (ClassKey key in sess.GetClasses(packageName)) {
+ SchemaClass schema = sess.GetSchema(key) ;
+ if (schema.Kind == 1) {
+ if (schema.SuperType == null)
+ returnValue += String.Format("\t<class name='{0}' hash='{1}'>\n", key.ClassName, key.GetHashString()) ;
+ else
+ returnValue += String.Format("\t<class name='{0}' hash='{1}' extends='{2}'>\n", key.ClassName, key.GetHashString(), schema.SuperType.GetKeyString()) ;
+ foreach (SchemaProperty prop in schema.Properties) {
+ object[] attributes = new object[5] ;
+ attributes[0] = prop.Name ;
+ attributes[1] = Util.TypeName(prop.Type) ;
+ attributes[2] = Util.AccessName(prop.Access) ;
+ attributes[3] = prop.Optional ;
+ attributes[4] = XMLUtil.CommonAttributes(prop);
+ returnValue += String.Format("\t\t<property name='{0}' type='{1}' access='{2}' optional='{3}'{4}/>\n", attributes) ;
+ }
+ foreach (SchemaMethod meth in schema.Methods) {
+ returnValue += String.Format("\t\t<method name='{0}'/>\n", meth.Name) ;
+ foreach (SchemaArgument arg in meth.Arguments) {
+ object[] attributes = new object[4] ;
+ attributes[0] = arg.Name ;
+ attributes[1] = arg.Direction ;
+ attributes[2] = Util.TypeName(arg.Type) ;
+ attributes[3] = XMLUtil.CommonAttributes(arg);
+ returnValue += String.Format("\t\t\t<arg name='{0}' dir='{1}' type='{2}'{3}/>\n", attributes) ;
+ }
+ returnValue += String.Format("\t\t</method>\n") ;
+ }
+ returnValue += String.Format("\t</class>\n") ;
+ } else {
+ returnValue += String.Format("\t<event name='{0}' hash='{1}'>\n", key.ClassName, key.GetHashString()) ;
+ foreach (SchemaArgument arg in schema.Arguments) {
+ object[] attributes = new object[4] ;
+ attributes[0] = arg.Name ;
+ attributes[1] = Util.TypeName(arg.Type) ;
+ attributes[2] = XMLUtil.CommonAttributes(arg);
+ returnValue += String.Format("\t\t\t<arg name='{0}' type='{1}'{2}/>\n", attributes) ;
+ }
+ returnValue += String.Format("\t</event>\n") ;
+ }
+ }
+ returnValue += String.Format("</schema>\n") ;
+
+ return returnValue ;
+ }
+
+ public static string SchemaXML(Session sess, string[] packageNames) {
+ string returnValue = "<schemas>\n" ;
+ foreach (string package in packageNames) {
+ returnValue += XMLUtil.SchemaXML(sess, package) ;
+ returnValue += "\n" ;
+ }
+ returnValue += "</schemas>\n" ;
+ return returnValue ;
+ }
+
+ protected XMLUtil()
+ {
+ }
+ }
+}
diff --git a/dotnet/client-010/management/console/console.csproj b/dotnet/client-010/management/console/console.csproj
new file mode 100644
index 0000000000..27e7360672
--- /dev/null
+++ b/dotnet/client-010/management/console/console.csproj
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{E8D2202F-3959-4F29-AA0D-875CD37905CA}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Console</RootNamespace>
+ <AssemblyName>Console</AssemblyName>
+ <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\..\lib\log4net\log4net.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="AbstractConsole.cs" />
+ <Compile Include="Agent.cs" />
+ <Compile Include="Broker.cs" />
+ <Compile Include="BrokerURL.cs" />
+ <Compile Include="ClassKey.cs" />
+ <Compile Include="Console.cs" />
+ <Compile Include="MethodResult.cs" />
+ <Compile Include="ObjectID.cs" />
+ <Compile Include="QMFEvent.cs" />
+ <Compile Include="QMFObject.cs" />
+ <Compile Include="SchemaArgument.cs" />
+ <Compile Include="SchemaClass.cs" />
+ <Compile Include="SchemaMethod.cs" />
+ <Compile Include="SchemaProperty.cs" />
+ <Compile Include="SchemaStatistic.cs" />
+ <Compile Include="SchemaVariable.cs" />
+ <Compile Include="SequenceManager.cs" />
+ <Compile Include="Session.cs" />
+ <Compile Include="Util.cs" />
+ <Compile Include="XMLUtil.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\client\Client.csproj">
+ <Project>{B911FFD7-754F-4735-A188-218D5065BE79}</Project>
+ <Name>Client</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Folder Include="Properties\" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/dotnet/client-010/management/console/console.sln b/dotnet/client-010/management/console/console.sln
new file mode 100644
index 0000000000..8555aa79cc
--- /dev/null
+++ b/dotnet/client-010/management/console/console.sln
@@ -0,0 +1,26 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Console", "Console.csproj", "{E8D2202F-3959-4F29-AA0D-875CD37905CA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client", "..\..\client\Client.csproj", "{B911FFD7-754F-4735-A188-218D5065BE79}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {E8D2202F-3959-4F29-AA0D-875CD37905CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E8D2202F-3959-4F29-AA0D-875CD37905CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E8D2202F-3959-4F29-AA0D-875CD37905CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E8D2202F-3959-4F29-AA0D-875CD37905CA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B911FFD7-754F-4735-A188-218D5065BE79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B911FFD7-754F-4735-A188-218D5065BE79}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B911FFD7-754F-4735-A188-218D5065BE79}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B911FFD7-754F-4735-A188-218D5065BE79}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/dotnet/client-010/management/console/console.userprefs b/dotnet/client-010/management/console/console.userprefs
new file mode 100644
index 0000000000..3dbea952ee
--- /dev/null
+++ b/dotnet/client-010/management/console/console.userprefs
@@ -0,0 +1,42 @@
+<Properties>
+ <MonoDevelop.Ide.Workbench ActiveDocument="../../../../../../test/csharpQmfExample/QmfExample.cs" ctype="Workbench">
+ <Files>
+ <File FileName="../../../../../../test/csharpQmfExample/QmfExample.cs" Line="32" Column="24" />
+ <File FileName="../../../../../../console/test/Test.cs" Line="164" Column="33" />
+ <File FileName="../../../../../../test/csharpQmfExample/log.xml" Line="32" Column="1" />
+ <File FileName="Broker.cs" Line="211" Column="19" />
+ <File FileName="Agent.cs" Line="38" Column="4" />
+ </Files>
+ <Pads>
+ <Pad Id="ProjectPad">
+ <State expanded="True">
+ <Node name="console" expanded="True">
+ <Node name="Agent.cs" selected="True" />
+ </Node>
+ </State>
+ </Pad>
+ <Pad Id="ClassPad">
+ <State expanded="True" selected="True">
+ <Node name="console" expanded="True">
+ <Node name="References">
+ <Option id="ShowProjects" value="True" />
+ <Option id="NestedNamespaces" value="False" />
+ <Option id="PublicApiOnly" value="False" />
+ <Option id="GroupByType" value="True" />
+ <Option id="GroupByAccess" value="False" />
+ </Node>
+ <Node name="org" expanded="True">
+ <Node name="apache" expanded="True">
+ <Node name="qpid" expanded="True" />
+ </Node>
+ </Node>
+ </Node>
+ </State>
+ </Pad>
+ </Pads>
+ </MonoDevelop.Ide.Workbench>
+ <MonoDevelop.Ide.DebuggingService>
+ <BreakpointStore />
+ </MonoDevelop.Ide.DebuggingService>
+ <MonoDevelop.Ide.Workspace ActiveConfiguration="Debug" ctype="Workspace" />
+</Properties> \ No newline at end of file
diff --git a/dotnet/client-010/management/console/console.usertasks b/dotnet/client-010/management/console/console.usertasks
new file mode 100644
index 0000000000..d887d0ef8d
--- /dev/null
+++ b/dotnet/client-010/management/console/console.usertasks
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ArrayOfUserTask xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> \ No newline at end of file
diff --git a/dotnet/client-010/management/console/default.build b/dotnet/client-010/management/console/default.build
new file mode 100644
index 0000000000..c71e695569
--- /dev/null
+++ b/dotnet/client-010/management/console/default.build
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="qpid.console" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <property name="build.config" value="debug" />
+ <property name="build.debug" value="true" />
+ <property name="build.defines" value="DEBUG;TRACE"/>
+ <property name="base.dir" value="${project::get-base-directory()}/../.." />
+ <property name="build.dir" value="${base.dir}/bin/${framework::get-target-framework()}/${build.config}" />
+
+
+ <target name="build">
+ <csc target="library"
+ define="${build.defines}"
+ debug="${build.debug}"
+ output="${build.dir}/${project::get-name()}.dll">
+
+ <sources>
+ <include name="***.cs" />
+ <exclude name="test/*.cs"/>
+ </sources>
+ <references>
+ <include name="${build.dir}/log4net.dll" />
+ <include name="${build.dir}/qpid.client.dll" />
+ </references>
+ </csc>
+ </target>
+</project>
diff --git a/dotnet/client-010/perftest/PerfTest.cs b/dotnet/client-010/perftest/PerfTest.cs
new file mode 100644
index 0000000000..c94dd865d5
--- /dev/null
+++ b/dotnet/client-010/perftest/PerfTest.cs
@@ -0,0 +1,715 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Threading;
+using common.org.apache.qpid.transport.util;
+using org.apache.qpid.client;
+using org.apache.qpid.transport;
+using org.apache.qpid.transport.util;
+using Plossum.CommandLine;
+
+namespace PerfTest
+{
+ [CommandLineManager(ApplicationName = "Qpid Perf Tests", Copyright = "Apache Software Foundation")]
+ public class Options
+ {
+ [CommandLineOption(Description = "Displays this help text")]
+ public bool Help;
+
+ [CommandLineOption(Description = "Create shared queues.", MinOccurs = 0)]
+ public Boolean Setup;
+
+ [CommandLineOption(Description = "Run test, print report.", MinOccurs = 0)]
+ public Boolean Control;
+
+ [CommandLineOption(Description = "Publish messages.", MinOccurs = 0)]
+ public Boolean Publish;
+
+ [CommandLineOption(Description = "Subscribe for messages.", MinOccurs = 0)]
+ public Boolean Subscribe;
+
+ [CommandLineOption(Description = "Test mode: [shared|fanout|topic]", MinOccurs = 0)]
+ public string Mode
+ {
+ get { return _mMode; }
+ set
+ {
+ if (! value.Equals("shared") && ! value.Equals("fanout") && ! value.Equals("topic"))
+ throw new InvalidOptionValueException(
+ "The mode must not be shared|fanout|topic", false);
+ _mMode = value;
+ }
+ }
+
+ private string _mMode = "shared";
+
+ [CommandLineOption(Description = "Specifies the broler name", MinOccurs = 0)]
+ public string Broker
+ {
+ get { return _broker; }
+ set
+ {
+ if (String.IsNullOrEmpty(value))
+ throw new InvalidOptionValueException(
+ "The broker name must not be empty", false);
+ _broker = value;
+ }
+ }
+
+ private string _broker = "localhost";
+
+ [CommandLineOption(Description = "Specifies the port name", MinOccurs = 0)]
+ public int Port
+ {
+ get { return _port; }
+ set { _port = value; }
+ }
+
+ private int _port = 5672;
+
+ #region Publisher
+
+ [CommandLineOption(Description = "Create N publishers.", MinOccurs = 0)]
+ public int Pubs
+ {
+ get { return _pubs; }
+ set { _pubs = value; }
+ }
+
+ private int _pubs = 1;
+
+ [CommandLineOption(Description = "Each publisher sends N messages.", MinOccurs = 0)]
+ public double Count
+ {
+ get { return _count; }
+ set { _count = value; }
+ }
+
+ private double _count = 5000;
+
+ [CommandLineOption(Description = "Size of messages in bytes.", MinOccurs = 0)]
+ public long Size
+ {
+ get { return _size; }
+ set { _size = value; }
+ }
+
+ private long _size = 1024;
+
+ [CommandLineOption(Description = "Publisher use confirm-mode.", MinOccurs = 0)]
+ public Boolean Confirm = true;
+
+ [CommandLineOption(Description = "Publish messages as durable.", MinOccurs = 0)]
+ public Boolean Durable;
+
+ [CommandLineOption(Description = "Make data for each message unique.", MinOccurs = 0)]
+ public Boolean UniqueData;
+
+ [CommandLineOption(Description = "Wait for confirmation of each message before sending the next one.",
+ MinOccurs = 0)]
+ public Boolean SyncPub;
+
+ [CommandLineOption(Description = ">=0 delay between msg publish.", MinOccurs = 0)]
+ public double IntervalPub
+ {
+ get { return _interval_pub; }
+ set { _interval_pub = value; }
+ }
+
+ private double _interval_pub;
+
+ #endregion
+
+ #region Subscriber
+
+ [CommandLineOption(Description = "Create N subscribers.", MinOccurs = 0)]
+ public int Subs
+ {
+ get { return _subs; }
+ set { _subs = value; }
+ }
+
+ private int _subs = 1;
+
+ [CommandLineOption(Description = "N>0: Subscriber acks batches of N.\n N==0: Subscriber uses unconfirmed mode",
+ MinOccurs = 0)]
+ public int SubAck
+ {
+ get { return _suback; }
+ set { _suback = value; }
+ }
+
+ private int _suback;
+
+ [CommandLineOption(Description = ">=0 delay between msg consume", MinOccurs = 0)]
+ public double IntervalSub
+ {
+ get { return _interval_sub; }
+ set { _interval_sub = value; }
+ }
+
+ private double _interval_sub;
+
+ #endregion
+
+ [CommandLineOption(Description = "Create N queues.", MinOccurs = 0)]
+ public int Queues
+ {
+ get { return _qt; }
+ set { _qt = value; }
+ }
+
+ private int _qt = 1;
+
+ [CommandLineOption(Description = "Desired number of iterations of the test.", MinOccurs = 0)]
+ public int Iterations
+ {
+ get { return _iterations; }
+ set { _iterations = value; }
+ }
+
+ private int _iterations = 1;
+
+ [CommandLineOption(Description = "If non-zero, the transaction batch size.", MinOccurs = 0)]
+ public int Tx
+ {
+ get { return _tx; }
+ set { _tx = value; }
+ }
+
+ private int _tx;
+
+ [CommandLineOption(Description = "Make queue durable (implied if durable set.", MinOccurs = 0)]
+ public Boolean QueueDurable;
+
+ [CommandLineOption(Description = "Queue policy: count to trigger 'flow to disk'", MinOccurs = 0)]
+ public double QueueMaxCount
+ {
+ get { return _queueMaxCount; }
+ set { _queueMaxCount = value; }
+ }
+
+ private double _queueMaxCount;
+
+ [CommandLineOption(Description = "Queue policy: accumulated size to trigger 'flow to disk'", MinOccurs = 0)]
+ public double QueueMaxSize
+ {
+ get { return _queueMaxSize; }
+ set { _queueMaxSize = value; }
+ }
+
+ private double _queueMaxSize;
+
+ public double SubQuota
+ {
+ get { return _subQuota; }
+ set { _subQuota = value; }
+ }
+
+ private double _subQuota;
+ }
+
+ internal interface Startable
+ {
+ void Start();
+ }
+
+ public abstract class PerfTestClient : Startable
+ {
+ private readonly IClient _connection;
+ private readonly IClientSession _session;
+ private readonly Options _options;
+
+ public IClientSession Session
+ {
+ get { return _session; }
+ }
+
+ public Options Options
+ {
+ get { return _options; }
+ }
+
+ protected PerfTestClient(Options options)
+ {
+ _options = options;
+ _connection = new Client();
+ _connection.Connect(options.Broker, options.Port, "test", "guest", "guest");
+ _session = _connection.CreateSession(50000);
+ }
+
+ public abstract void Start();
+ }
+
+ public class SetupTest : PerfTestClient
+ {
+ public SetupTest(Options options)
+ : base(options)
+ {
+ }
+
+ private void queueInit(String name, Boolean durable, Dictionary<String, Object> arguments)
+ {
+ Session.QueueDeclare(name, null, arguments, durable ? Option.DURABLE : Option.NONE);
+ Session.QueuePurge(name);
+ Session.ExchangeBind(name, "amq.direct", name);
+ Session.Sync();
+ }
+
+ public override void Start()
+ {
+ queueInit("pub_start", false, null);
+ queueInit("pub_done", false, null);
+ queueInit("sub_ready", false, null);
+ queueInit("sub_done", false, null);
+ if (Options.Mode.Equals("shared"))
+ {
+ Dictionary<String, Object> settings = new Dictionary<string, object>();
+ if (Options.QueueMaxCount > 0)
+ settings.Add("qpid.max_count", Options.QueueMaxCount);
+ if (Options.QueueMaxSize > 0)
+ settings.Add("qpid.max_size", Options.QueueMaxSize);
+ for (int i = 0; i < Options.Queues; ++i)
+ {
+ string qname = "perftest" + i;
+ queueInit(qname, Options.Durable || Options.QueueDurable, settings);
+ }
+ }
+ }
+ }
+
+ public class SubscribeThread : PerfTestClient
+ {
+ private readonly string _queue;
+
+ public SubscribeThread(Options options, string key, string exchange)
+ : base(options)
+ {
+ _queue = "perftest" + (new UUID(10, 10));
+ Session.QueueDeclare(_queue, null, null, Option.EXCLUSIVE, Option.AUTO_DELETE,
+ Options.Durable ? Option.DURABLE : Option.NONE);
+ Session.ExchangeBind(_queue, exchange, key);
+ }
+
+ public SubscribeThread(Options options, string key)
+ : base(options)
+ {
+ _queue = key;
+ }
+
+ public override void Start()
+ {
+ if (Options.Tx > 0)
+ {
+ Session.TxSelect();
+ Session.Sync();
+ }
+ CircularBuffer<IMessage> buffer = new CircularBuffer<IMessage>(100);
+ // Create a listener and subscribe it to the queue named "message_queue"
+ IMessageListener listener = new SyncListener(buffer);
+
+ string dest = "dest" + UUID.RandomUuid();
+ Session.AttachMessageListener(listener, dest);
+ Session.MessageSubscribe(_queue, dest,
+ Options.Tx > 0 || Options.SubAck > 0
+ ? MessageAcceptMode.EXPLICIT
+ : MessageAcceptMode.NONE,
+ MessageAcquireMode.PRE_ACQUIRED, null, 0, null);
+ // issue credits
+ Session.MessageSetFlowMode(dest, MessageFlowMode.WINDOW);
+ Session.MessageFlow(dest, MessageCreditUnit.BYTE, ClientSession.MESSAGE_FLOW_MAX_BYTES);
+
+ // Notify controller we are ready.
+ IMessage message = new Message();
+ message.DeliveryProperties.SetRoutingKey("sub_ready");
+
+ message.AppendData(Encoding.UTF8.GetBytes("ready"));
+ Session.MessageTransfer("amq.direct", message);
+
+ if (Options.Tx > 0)
+ {
+ Session.TxCommit();
+ Session.Sync();
+ }
+
+
+ for (int j = 0; j < Options.Iterations; ++j)
+ {
+
+ //need to allocate some more credit
+ Session.MessageFlow(dest, MessageCreditUnit.MESSAGE, (long)Options.SubQuota);
+
+ RangeSet range = new RangeSet();
+ IMessage msg;
+ DateTime start = DateTime.Now;
+ for (long i = 0; i < Options.SubQuota; ++i)
+ {
+ msg = buffer.Dequeue();
+ if (Options.Tx > 0 && ((i + 1)%Options.Tx == 0))
+ {
+ Session.TxCommit();
+ Session.Sync();
+ }
+ if (Options.IntervalSub > 0)
+ {
+ Thread.Sleep((int) Options.IntervalSub*1000);
+ }
+ range.Add(msg.Id);
+ }
+ if (Options.Tx > 0 || Options.SubAck > 0)
+ Session.MessageAccept(range);
+ range.Clear();
+ if (Options.Tx > 0)
+ {
+ Session.TxSelect();
+ Session.Sync();
+ }
+ DateTime end = DateTime.Now;
+
+ // Report to publisher.
+ message.DeliveryProperties.SetRoutingKey("sub_done");
+ message.ClearData();
+ message.AppendData(BitConverter.GetBytes(Options.SubQuota / end.Subtract(start).TotalMilliseconds ));
+ Session.MessageTransfer("amq.direct", message);
+ if (Options.Tx > 0)
+ {
+ Session.TxSelect();
+ Session.Sync();
+ }
+ }
+ Session.Close();
+ }
+ }
+
+ public class SyncListener : IMessageListener
+ {
+ private readonly CircularBuffer<IMessage> _buffer;
+
+ public SyncListener(CircularBuffer<IMessage> buffer)
+ {
+ _buffer = buffer;
+ }
+
+ public void MessageTransfer(IMessage m)
+ {
+ _buffer.Enqueue(m);
+ }
+ }
+
+
+ public class PublishThread : PerfTestClient
+ {
+ private readonly string _exchange;
+ private readonly string _key;
+
+ public PublishThread(Options options, string key, string exchange)
+ : base(options)
+ {
+ _key = key;
+ _exchange = exchange;
+ }
+
+
+ public override void Start()
+ {
+ byte[] data = new byte[Options.Size];
+ // randomly populate data
+ Random r = new Random(34);
+ r.NextBytes(data);
+ IMessage message = new Message();
+ message.AppendData(data);
+
+ message.DeliveryProperties.SetRoutingKey(_key);
+
+ if (Options.Durable)
+ message.DeliveryProperties.SetDeliveryMode(MessageDeliveryMode.PERSISTENT);
+
+ if (Options.Tx > 0)
+ {
+ Session.TxSelect();
+ Session.Sync();
+ }
+
+ CircularBuffer<IMessage> buffer = new CircularBuffer<IMessage>(100);
+ // Create a listener and subscribe it to the queue named "pub_start"
+ IMessageListener listener = new SyncListener(buffer);
+ string localQueue = "localQueue-" + UUID.RandomUuid().ToString();
+ Session.QueueDeclare(localQueue, null, null, Option.AUTO_DELETE);
+ Session.ExchangeBind(localQueue, "amq.direct", "pub_start");
+ Session.AttachMessageListener(listener, localQueue);
+ Session.MessageSubscribe(localQueue);
+ if (Options.Tx > 0)
+ {
+ Session.TxCommit();
+ Session.Sync();
+ }
+ buffer.Dequeue();
+
+ for (int j = 0; j < Options.Iterations; ++j)
+ {
+ DateTime start = DateTime.Now;
+ for (long i = 0; i < Options.Count; ++i)
+ {
+ Session.MessageTransfer(_exchange, message);
+
+ if (Options.SyncPub)
+ {
+ Session.Sync();
+ }
+ if (Options.Tx > 0 && (i + 1)%Options.Tx == 0)
+ {
+ Session.TxSelect();
+ Session.Sync();
+ }
+ if (Options.IntervalPub > 0)
+ {
+ Thread.Sleep((int) Options.IntervalSub*1000);
+ }
+ }
+ Session.Sync();
+ DateTime end = DateTime.Now;
+
+ // Report to publisher.
+ message.DeliveryProperties.SetRoutingKey("pub_done");
+ message.ClearData();
+ double time = end.Subtract(start).TotalMilliseconds;
+ byte[] rate = BitConverter.GetBytes( Options.Count / time );
+ message.AppendData(rate);
+ Session.MessageTransfer("amq.direct", message);
+ if (Options.Tx > 0)
+ {
+ Session.TxSelect();
+ Session.Sync();
+ }
+ }
+ Session.Close();
+ }
+ }
+
+ public class Controller : PerfTestClient
+ {
+ public Controller(Options options)
+ : base(options)
+ {
+ }
+
+ private void process(int size, string queue)
+ {
+ CircularBuffer<IMessage> buffer = new CircularBuffer<IMessage>(100);
+ IMessageListener listener = new SyncListener(buffer);
+ string localQueue = "queue-" + UUID.RandomUuid();
+ Session.QueueDeclare(localQueue, null, null, Option.AUTO_DELETE);
+ Session.ExchangeBind(localQueue, "amq.direct", queue);
+ Session.AttachMessageListener(listener, localQueue);
+ Session.MessageSubscribe(localQueue);
+ for (int i = 0; i < size; ++i)
+ {
+ buffer.Dequeue();
+ }
+ }
+
+ private double processRate(int size, string queue)
+ {
+ CircularBuffer<IMessage> buffer = new CircularBuffer<IMessage>(100);
+ IMessageListener listener = new SyncListener(buffer);
+ string localQueue = "queue-" + UUID.RandomUuid();
+ Session.QueueDeclare(localQueue, null, null, Option.AUTO_DELETE);
+ Session.ExchangeBind(localQueue, "amq.direct", queue);
+ Session.AttachMessageListener(listener, localQueue);
+ Session.MessageSubscribe(localQueue);
+ double rate = 0;
+ RangeSet range = new RangeSet();
+ for (int i = 0; i < size; ++i)
+ {
+ IMessage m = buffer.Dequeue();
+ range.Add(m.Id);
+ BinaryReader reader = new BinaryReader(m.Body, Encoding.UTF8);
+ byte[] body = new byte[m.Body.Length - m.Body.Position];
+ reader.Read(body, 0, body.Length);
+ rate += BitConverter.ToDouble(body,0);
+ }
+ Session.MessageAccept(range);
+ return rate;
+ }
+
+ private void send(int size, string queue, string data)
+ {
+ IMessage message = new Message();
+ message.DeliveryProperties.SetRoutingKey(queue);
+ message.AppendData(Encoding.UTF8.GetBytes(data));
+ for (int i = 0; i < size; ++i)
+ {
+ Session.MessageTransfer("amq.direct", message);
+ }
+ }
+
+ public override void Start()
+ {
+ process(Options.Subs, "sub_ready");
+ for (int j = 0; j < Options.Iterations; ++j)
+ {
+ DateTime start = DateTime.Now;
+ send(Options.Pubs, "pub_start", "start"); // Start publishers
+ double pubrate = processRate(Options.Pubs, "pub_done");
+ double subrate = processRate(Options.Subs, "sub_done");
+ DateTime end = DateTime.Now;
+
+ double transfers = (Options.Pubs*Options.Count) + (Options.Subs*Options.SubQuota);
+ double time = end.Subtract(start).TotalSeconds;
+ double txrate = transfers/time;
+ double mbytes = (txrate*Options.Size) / (1024 * 1024) ;
+
+ Console.WriteLine("Total: " + transfers + " transfers of " + Options.Size + " bytes in "
+ + time + " seconds.\n" +
+ "Publish transfers/sec: " + pubrate * 1000 + "\n" +
+ "Subscribe transfers/sec: " + subrate * 1000 + "\n" +
+ "Total transfers/sec: " + txrate + "\n" +
+ "Total Mbytes/sec: " + mbytes);
+ Console.WriteLine("done");
+ }
+
+ }
+ }
+
+
+ public class PerfTest
+ {
+ private static int Main(string[] args)
+ {
+ Options options = new Options();
+ CommandLineParser parser = new CommandLineParser(options);
+ parser.Parse();
+ if (parser.HasErrors)
+ {
+ Console.WriteLine(parser.UsageInfo.GetErrorsAsString(78));
+ return -1;
+ }
+ if (options.Help)
+ {
+ Console.WriteLine(parser.UsageInfo.GetOptionsAsString(78));
+ return 0;
+ }
+ bool singleProcess =
+ (!options.Setup && !options.Control && !options.Publish && !options.Subscribe);
+ if (singleProcess)
+ {
+ options.Setup = options.Control = options.Publish = true;
+ options.Subscribe = true;
+ }
+
+
+ string exchange = "amq.direct";
+ switch (options.Mode)
+ {
+ case "shared":
+ options.SubQuota = (options.Pubs*options.Count)/options.Subs;
+ break;
+ case "fanout":
+ options.SubQuota = (options.Pubs*options.Count);
+ exchange = "amq.fanout";
+ break;
+ case "topic":
+ options.SubQuota = (options.Pubs*options.Count);
+ exchange = "amq.topic";
+ break;
+ }
+
+ if (options.Setup)
+ {
+ SetupTest setup = new SetupTest(options);
+ setup.Start(); // Set up queues
+ }
+
+ Thread contT = null;
+ if ( options.Control)
+ {
+ Controller c = new Controller(options);
+ contT = new Thread(c.Start);
+ contT.Start();
+ }
+
+ Thread[] publishers = null;
+ Thread[] subscribers = null;
+
+ // Start pubs/subs for each queue/topic.
+ for (int i = 0; i < options.Queues; ++i)
+ {
+ string key = "perftest" + i; // Queue or topic name.
+ if (options.Publish)
+ {
+ int n = singleProcess ? options.Pubs : 1;
+ publishers = new Thread[n];
+ for (int j = 0; j < n; ++j)
+ {
+ PublishThread pt = new PublishThread(options, key, exchange);
+ publishers[i] = new Thread(pt.Start);
+ publishers[i].Start();
+ }
+ }
+ if ( options.Subscribe)
+ {
+ int n = singleProcess ? options.Subs : 1;
+ subscribers = new Thread[n];
+ for (int j = 0; j < n; ++j)
+ {
+ SubscribeThread st;
+ if (options.Mode.Equals("shared"))
+ st = new SubscribeThread(options, key);
+ else
+ st = new SubscribeThread(options, key, exchange);
+ subscribers[i] = new Thread(st.Start);
+ subscribers[i].Start();
+ }
+ }
+ }
+
+ if (options.Control)
+ {
+ contT.Join();
+ }
+
+
+ // Wait for started threads.
+ if (options.Publish)
+ {
+ foreach (Thread t in publishers)
+ {
+ t.Join();
+ }
+ }
+
+ if (options.Subscribe)
+ {
+ foreach (Thread t in subscribers)
+ {
+ t.Join();
+ }
+ }
+
+
+ return 0;
+ }
+ }
+}
diff --git a/dotnet/client-010/perftest/Properties/AssemblyInfo.cs b/dotnet/client-010/perftest/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..415ad1f1ae
--- /dev/null
+++ b/dotnet/client-010/perftest/Properties/AssemblyInfo.cs
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("perftest")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("perftest")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("11b542db-0d57-4a67-8b92-24ac1d4ed4cf")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/client-010/perftest/README.txt b/dotnet/client-010/perftest/README.txt
new file mode 100644
index 0000000000..1c920a30b6
--- /dev/null
+++ b/dotnet/client-010/perftest/README.txt
@@ -0,0 +1,38 @@
+There are two ways to use perftest:
+- single process:
+If none of the -Setup, -Publish, -Subscribe or -Control options are given perftest will run a single-process test.
+- multi-process:
+For a multi-process test first run:
+Perftest.exe -Setup <other options>
+and wait for it to complete. The remaining process should run concurrently:
+Run -Pubs times: Perftest.exe -Publish <other options>
+Run -Subs times: Perftest.exe -Subscribe <other options>
+Run once: Perftest.exe -Control <other options>
+Note the <other options> must be identical for all processes.
+
+Options:
+ -Broker Specifies the broler name
+ -Confirm Publisher use confirm-mode.
+ -Control Run test, print report.
+ -Count Each publisher sends N messages.
+ -Durable Publish messages as durable.
+ -Help Displays this help text
+ -IntervalPub >=0 delay between msg publish.
+ -IntervalSub >=0 delay between msg consume
+ -Iterations Desired number of iterations of the test.
+ -Mode Test mode: [shared|fanout|topic]
+ -Port Specifies the port name
+ -Publish Publish messages.
+ -Pubs Create N publishers.
+ -QueueDurable Make queue durable (implied if durable set.
+ -QueueMaxCount Queue policy: count to trigger 'flow to disk'
+ -QueueMaxSize Queue policy: accumulated size to trigger 'flow to disk'
+ -Queues Create N queues.
+ -Setup Create shared queues.
+ -Size Size of messages in bytes.
+ -SubAck N>0: Subscriber acks batches of N. N==0: Subscriber uses unconfirmed mode
+ -Subs Create N subscribers.
+ -Subscribe Subscribe for messages.
+ -SyncPub Wait for confirmation of each message before sending the next one.
+ -Tx If non-zero, the transaction batch size.
+ -UniqueData Make data for each message unique. \ No newline at end of file
diff --git a/dotnet/client-010/perftest/default.build b/dotnet/client-010/perftest/default.build
new file mode 100644
index 0000000000..756f6c6493
--- /dev/null
+++ b/dotnet/client-010/perftest/default.build
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="perftest" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="exe"
+ define="${build.defines}"
+ debug="${build.debug}"
+ output="${build.dir}/${project::get-name()}.exe">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ <include name="${build.dir}/log4net.dll" />
+ <include name="${build.dir}/qpid.client.dll" />
+ <include name="${build.dir}/C5.dll" />
+ <include name="${build.dir}/Plossum CommandLine.dll" />
+ </references>
+ </csc>
+ </target>
+
+</project>
+
diff --git a/dotnet/client-010/perftest/perftest.csproj b/dotnet/client-010/perftest/perftest.csproj
new file mode 100644
index 0000000000..34632d94a5
--- /dev/null
+++ b/dotnet/client-010/perftest/perftest.csproj
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{7F7E8DE7-FDF2-4A52-A4CE-D3756B05273C}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>perftest</RootNamespace>
+ <AssemblyName>perftest</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="C5, Version=1.0.2.0, Culture=neutral, PublicKeyToken=06a1b38866503b69, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\lib\plossum\C5.dll</HintPath>
+ </Reference>
+ <Reference Include="Plossum CommandLine, Version=0.3.0.14, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\lib\plossum\Plossum CommandLine.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="PerfTest.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\client\Client.csproj">
+ <Project>{B911FFD7-754F-4735-A188-218D5065BE79}</Project>
+ <Name>Client</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\App.config">
+ <Link>App.config</Link>
+ </None>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/dotnet/client-010/test/Helpers/ConfigHelpers.cs b/dotnet/client-010/test/Helpers/ConfigHelpers.cs
new file mode 100644
index 0000000000..92374b5c41
--- /dev/null
+++ b/dotnet/client-010/test/Helpers/ConfigHelpers.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Xml;
+using log4net.Config;
+
+namespace test.Helpers
+{
+ class ConfigHelpers
+ {
+ public static Dictionary<string, string> LoadConfig()
+ {
+ Dictionary<string, string> properties = new Dictionary<string, string>();
+
+ XmlConfigurator.Configure(new FileInfo("/log.xml"));
+ // populate default properties
+ properties.Add("Username", "guest");
+ properties.Add("Password", "guest");
+ properties.Add("Host", "localhost");
+ properties.Add("Port", "5672");
+ properties.Add("VirtualHost", "test");
+ //Read the test config file
+ XmlTextReader reader = new XmlTextReader(Environment.CurrentDirectory + "/Qpid Test.dll.config");
+ while (reader.Read())
+ {
+ // if node type is an element
+ if (reader.NodeType == XmlNodeType.Element && reader.Name.Equals("add"))
+ {
+ if (properties.ContainsKey(reader.GetAttribute("key")))
+ {
+ properties[reader.GetAttribute("key")] = reader.GetAttribute("value");
+ }
+ else
+ {
+ properties.Add(reader.GetAttribute("key"), reader.GetAttribute("value"));
+ }
+ }
+ }
+
+ return properties;
+ }
+ }
+}
diff --git a/dotnet/client-010/test/Properties/AssemblyInfo.cs b/dotnet/client-010/test/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..871d450240
--- /dev/null
+++ b/dotnet/client-010/test/Properties/AssemblyInfo.cs
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Qpid Test")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("Qpid Test")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("3d62cb4f-4353-4eed-9669-3e1bc902081d")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/client-010/test/Qpid Test.dll.config b/dotnet/client-010/test/Qpid Test.dll.config
new file mode 100644
index 0000000000..2a2fb72b61
--- /dev/null
+++ b/dotnet/client-010/test/Qpid Test.dll.config
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<configuration>
+ <appSettings>
+ <add key="UserMame" value="guest"/>
+ <add key="Password" value="guest"/>
+ <add key="Host" value="localhost"/>
+ <add key="Port" value="5672"/>
+ <add key="VirtualHost" value="test"/>
+ </appSettings>
+</configuration>
diff --git a/dotnet/client-010/test/Test.csproj b/dotnet/client-010/test/Test.csproj
new file mode 100644
index 0000000000..7bb6eaa999
--- /dev/null
+++ b/dotnet/client-010/test/Test.csproj
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{95CB4C90-7C53-44A9-B11C-96235F158ACA}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>test</RootNamespace>
+ <AssemblyName>Qpid Test</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\lib\log4net\log4net.dll</HintPath>
+ </Reference>
+ <Reference Include="nunit.framework, Version=2.2.8.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\lib\nunit\nunit.framework.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="interop\ConnectionTests.cs" />
+ <Compile Include="Helpers\ConfigHelpers.cs" />
+ <Compile Include="interop\Admin.cs" />
+ <Compile Include="interop\ApplicationHeaders.cs" />
+ <Compile Include="interop\Message.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="interop\TestCase.cs" />
+ <Compile Include="transport\util\ByteEncoderTest.cs" />
+ <Compile Include="transport\util\CircularBufferTest.cs" />
+ <Compile Include="transport\util\ResultFutureTest.cs" />
+ <Compile Include="transport\util\SerialTest.cs" />
+ <Compile Include="transport\util\UUIDTest.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\client\Client.csproj">
+ <Project>{B911FFD7-754F-4735-A188-218D5065BE79}</Project>
+ <Name>Client</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\App.config">
+ <Link>App.config</Link>
+ </None>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/dotnet/client-010/test/default.build b/dotnet/client-010/test/default.build
new file mode 100644
index 0000000000..f9dadb174b
--- /dev/null
+++ b/dotnet/client-010/test/default.build
@@ -0,0 +1,55 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="qpid.client.tests" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="library"
+ define="${build.defines}"
+ debug="${build.debug}"
+ output="${build.dir}/${project::get-name()}.dll">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ <include name="${build.dir}/log4net.dll" />
+ <include name="${build.dir}/nunit.framework.dll" />
+ <include name="${build.dir}/qpid.client.dll" />
+ </references>
+ </csc>
+ </target>
+
+ <target name="test" depends="build">
+ <nunit2>
+ <formatter type="${nant.formatter}" usefile="false" />
+ <test assemblyname="${build.dir}/qpid.client.tests.dll" />
+ </nunit2>
+ </target>
+</project>
+
diff --git a/dotnet/client-010/test/interop/Admin.cs b/dotnet/client-010/test/interop/Admin.cs
new file mode 100644
index 0000000000..163e4cf49a
--- /dev/null
+++ b/dotnet/client-010/test/interop/Admin.cs
@@ -0,0 +1,90 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using NUnit.Framework;
+using org.apache.qpid.client;
+using org.apache.qpid.transport;
+using org.apache.qpid.transport.util;
+
+namespace test.interop
+{
+ public class Admin : TestCase
+ {
+ private static readonly Logger _log = Logger.Get(typeof(Admin));
+
+ [Test]
+ public void createSession()
+ {
+ _log.Debug("Running: CreateSession");
+ IClientSession ssn = Client.CreateSession(0);
+ ssn.Close();
+ // This test fails if an exception is thrown
+ }
+
+ [Test]
+ public void queueLifecycle()
+ {
+ _log.Debug("Running: queueLifecycle");
+ IClientSession ssn = Client.CreateSession(0);
+ ssn.QueueDeclare("queue1", null, null);
+ ssn.Sync();
+ ssn.QueueDelete("queue1");
+ ssn.Sync();
+ try
+ {
+ ssn.ExchangeBind("queue1", "amq.direct", "queue1", null);
+ ssn.Sync();
+ }
+ catch (SessionException)
+ {
+ // as expected
+ }
+ // This test fails if an exception is thrown
+ }
+
+ [Test]
+ public void exchangeCheck()
+ {
+ _log.Debug("Running: exchangeCheck");
+ IClientSession ssn = Client.CreateSession(0);
+ ExchangeQueryResult query = (ExchangeQueryResult) ssn.ExchangeQuery("amq.direct").Result;
+ Assert.IsFalse(query.GetNotFound());
+ Assert.IsTrue(query.GetDurable());
+ query = (ExchangeQueryResult)ssn.ExchangeQuery("amq.topic").Result;
+ Assert.IsFalse(query.GetNotFound());
+ Assert.IsTrue(query.GetDurable());
+ query = (ExchangeQueryResult) ssn.ExchangeQuery("foo").Result;
+ Assert.IsTrue(query.GetNotFound());
+ }
+
+ [Test]
+ public void exchangeBind()
+ {
+ _log.Debug("Running: ExchangeBind");
+ IClientSession ssn = Client.CreateSession(0);
+ ssn.QueueDeclare("queue1", null, null);
+ ssn.ExchangeBind("queue1", "amq.direct", "queue1", null);
+ // This test fails if an exception is thrown
+ }
+
+
+ }
+}
diff --git a/dotnet/client-010/test/interop/ApplicationHeaders.cs b/dotnet/client-010/test/interop/ApplicationHeaders.cs
new file mode 100644
index 0000000000..d932057fd2
--- /dev/null
+++ b/dotnet/client-010/test/interop/ApplicationHeaders.cs
@@ -0,0 +1,83 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using common.org.apache.qpid.transport.util;
+using NUnit.Framework;
+using org.apache.qpid.client;
+using org.apache.qpid.transport.util;
+
+namespace test.interop
+{
+ public class ApplicationHeaders:TestCase
+ {
+ private static readonly Logger _log = Logger.Get(typeof(ApplicationHeaders));
+
+ [Test]
+ public void setHeaders()
+ {
+ _log.Debug("Running: setHeaders");
+ IClientSession ssn = Client.CreateSession(0);
+ ssn.QueueDeclare("queue1");
+ ssn.ExchangeBind("queue1", "amq.direct", "queue1");
+ ssn.Sync();
+ CircularBuffer<IMessage> buff = new CircularBuffer<IMessage>(10);
+ SyncListener listener = new SyncListener(ssn, buff);
+ ssn.AttachMessageListener(listener, "queue1");
+ ssn.MessageSubscribe("queue1");
+
+ IMessage message = new org.apache.qpid.client.Message();
+ message.DeliveryProperties.SetRoutingKey("queue1");
+ const long someLong = 14444444;
+ message.ApplicationHeaders.Add("someLong", someLong);
+ const int someInt = 14;
+ message.ApplicationHeaders.Add("soneInt", someInt);
+ const float someFloat = 14.001F;
+ message.ApplicationHeaders.Add("soneFloat", someFloat);
+ const double someDouble = 14.5555555;
+ message.ApplicationHeaders.Add("someDouble", someDouble);
+ const byte someByte = 2;
+ message.ApplicationHeaders.Add("someByte", someByte);
+ const string someString = "someString";
+ message.ApplicationHeaders.Add("someString", someString);
+ const char someChar = 'a';
+ message.ApplicationHeaders.Add("someChar", someChar);
+ const Boolean someBoolean = true;
+ message.ApplicationHeaders.Add("someBoolean", someBoolean);
+
+ // transfer the message
+ ssn.MessageTransfer("amq.direct", message);
+
+ // get the message and check the headers
+ IMessage messageBack = buff.Dequeue();
+ Assert.IsTrue(((string) messageBack.ApplicationHeaders["someString"]).Equals(someString));
+ Assert.IsTrue(((char)messageBack.ApplicationHeaders["someChar"]).Equals(someChar));
+ Assert.IsTrue((long)messageBack.ApplicationHeaders["someLong"] == someLong);
+ Assert.IsTrue((int)messageBack.ApplicationHeaders["soneInt"] == someInt);
+ Assert.IsTrue((double)messageBack.ApplicationHeaders["someDouble"] == someDouble);
+ Assert.IsTrue((byte) messageBack.ApplicationHeaders["someByte"] == someByte);
+ Assert.IsTrue((Boolean)messageBack.ApplicationHeaders["someBoolean"]);
+ // c# has an conversion precision issue with decimal
+ Assert.IsTrue((float) messageBack.ApplicationHeaders["soneFloat"] <= someFloat);
+ float b = (float) messageBack.ApplicationHeaders["soneFloat"];
+ Assert.IsTrue(Convert.ToInt32(b) == Convert.ToInt32(someFloat));
+ }
+ }
+}
diff --git a/dotnet/client-010/test/interop/ConnectionTests.cs b/dotnet/client-010/test/interop/ConnectionTests.cs
new file mode 100644
index 0000000000..0c2ea8a648
--- /dev/null
+++ b/dotnet/client-010/test/interop/ConnectionTests.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Net.Sockets;
+using NUnit.Framework;
+using org.apache.qpid.client;
+using test.Helpers;
+
+namespace test
+{
+ [TestFixture]
+ public class ConnectionTests
+ {
+ [SetUp]
+ public void Setup()
+ {
+
+ }
+
+ [Test]
+ [ExpectedException(typeof(Exception))]
+ public void should_raise_exception_in_calling_thread_on_authentification_failure()
+ {
+ var properties = ConfigHelpers.LoadConfig();
+
+ var client = new Client();
+ client.Connect(properties["Host"], Convert.ToInt16(properties["Port"]), properties["VirtualHost"],
+ properties["Username"], "some silly password to make sure the authentification fail");
+ }
+
+ [Test]
+ [ExpectedException(typeof(Exception))]
+ public void should_raise_exception_in_calling_thread_on_authentification_failure_with_clodedListener()
+ {
+ var properties = ConfigHelpers.LoadConfig();
+
+ var client = new Client();
+ client.ClosedListener = new FakeListener();
+ client.Connect(properties["Host"], Convert.ToInt16(properties["Port"]), properties["VirtualHost"],
+ properties["Username"], "some silly password to make sure the authentification fail");
+ }
+
+ [Test]
+ public void should_not_block_on_close()
+ {
+ var properties = ConfigHelpers.LoadConfig();
+
+ var client = new Client();
+ client.Connect(properties["Host"], Convert.ToInt16(properties["Port"]), properties["VirtualHost"],
+ properties["Username"], properties["Password"]);
+ client.Close();
+ }
+ }
+
+ public class FakeListener : IClosedListener
+ {
+ public void OnClosed(ErrorCode errorCode, string reason, Exception t)
+ {
+ }
+ }
+}
diff --git a/dotnet/client-010/test/interop/Message.cs b/dotnet/client-010/test/interop/Message.cs
new file mode 100644
index 0000000000..107e69c287
--- /dev/null
+++ b/dotnet/client-010/test/interop/Message.cs
@@ -0,0 +1,180 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using System.Text;
+using System.Threading;
+using NUnit.Framework;
+using org.apache.qpid.client;
+using org.apache.qpid.transport;
+using org.apache.qpid.transport.util;
+
+namespace test.interop
+{
+ public class Message : TestCase
+ {
+ private static readonly Logger _log = Logger.Get(typeof (Message));
+
+ [Test]
+ public void sendAndPurge()
+ {
+ _log.Debug("Running: ExchangeBind");
+ IClientSession ssn = Client.CreateSession(0);
+ ssn.QueueDelete("queue1");
+ QueueQueryResult result = (QueueQueryResult) ssn.QueueQuery("queue1").Result;
+ Assert.IsNull(result.GetQueue());
+ ssn.QueueDeclare("queue1", null, null);
+ ssn.ExchangeBind("queue1", "amq.direct", "queue1", null);
+
+ for (int i = 0; i < 10; i++)
+ {
+ ssn.MessageTransfer("amq.direct", MessageAcceptMode.NONE, MessageAcquireMode.PRE_ACQUIRED,
+ new Header(new DeliveryProperties().SetRoutingKey("queue1"),
+ new MessageProperties().SetMessageId(UUID.RandomUuid())),
+ Encoding.UTF8.GetBytes("test: " + i));
+ }
+ ssn.Sync();
+ result = (QueueQueryResult) ssn.QueueQuery("queue1").Result;
+ Assert.IsTrue(result.GetMessageCount() == 10);
+ ssn.QueuePurge("queue1");
+ ssn.Sync();
+ result = (QueueQueryResult) ssn.QueueQuery("queue1").Result;
+ Assert.IsTrue(result.GetMessageCount() == 0);
+ }
+
+ [Test]
+ public void sendAndReceiveSmallMessages()
+ {
+ _log.Debug("Running: sendAndReceiveSmallMessages");
+ byte[] smallMessage = Encoding.UTF8.GetBytes("test");
+ sendAndReceive(smallMessage, 100);
+ }
+
+ [Test]
+ public void sendAndReceiveLargeMessages()
+ {
+ _log.Debug("Running: sendAndReceiveSmallMessages");
+ byte[] largeMessage = new byte[100 * 1024];
+ Random random = new Random();
+ random.NextBytes(largeMessage);
+ sendAndReceive(largeMessage, 10);
+ }
+
+ [Test]
+ public void sendAndReceiveVeryLargeMessages()
+ {
+ _log.Debug("Running: sendAndReceiveSmallMessages");
+ byte[] verylargeMessage = new byte[1000 * 1024];
+ Random random = new Random();
+ random.NextBytes(verylargeMessage);
+ sendAndReceive(verylargeMessage, 2);
+ }
+
+ private void sendAndReceive(byte[] messageBody, int count)
+ {
+ IClientSession ssn = Client.CreateSession(0);
+ ssn.Sync();
+ ssn.QueueDeclare("queue1", null, null);
+ ssn.QueueDelete("queue1");
+ QueueQueryResult result = (QueueQueryResult) ssn.QueueQuery("queue1").Result;
+ Assert.IsNull(result.GetQueue());
+ ssn.QueueDeclare("queue1", null, null);
+ ssn.ExchangeBind("queue1", "amq.direct", "queue1", null);
+ Object myLock = new Object();
+ MyListener myListener = new MyListener(myLock, count);
+ ssn.AttachMessageListener(myListener, "myDest");
+
+ ssn.MessageSubscribe("queue1", "myDest", MessageAcceptMode.EXPLICIT, MessageAcquireMode.PRE_ACQUIRED, null,
+ 0, null);
+
+
+ // issue credits
+ ssn.MessageSetFlowMode("myDest", MessageFlowMode.WINDOW);
+ ssn.MessageFlow("myDest", MessageCreditUnit.BYTE, ClientSession.MESSAGE_FLOW_MAX_BYTES);
+ ssn.MessageFlow("myDest", MessageCreditUnit.MESSAGE, 10000);
+ ssn.Sync();
+
+ for (int i = 0; i < count; i++)
+ {
+ ssn.MessageTransfer("amq.direct", MessageAcceptMode.NONE, MessageAcquireMode.PRE_ACQUIRED,
+ new Header(new DeliveryProperties().SetRoutingKey("queue1"),
+ new MessageProperties().SetMessageId(UUID.RandomUuid())),
+ messageBody);
+ }
+ ssn.Sync();
+
+ lock (myLock)
+ {
+ if (myListener.Count != 0)
+ {
+ Monitor.Wait(myLock, 10000000);
+ }
+ }
+ Assert.IsTrue(myListener.Count == 0);
+ ssn.MessageAccept(myListener.UnAck);
+ ssn.Sync();
+ // the queue should be empty
+ result = (QueueQueryResult)ssn.QueueQuery("queue1").Result;
+ Assert.IsTrue(result.GetMessageCount() == 0);
+ ssn.Close();
+ }
+
+
+
+ private class MyListener : IMessageListener
+ {
+ private static readonly Logger _log = Logger.Get(typeof (MyListener));
+ private readonly Object _wl;
+ private int _count;
+ private RangeSet _rs = new RangeSet();
+
+ public MyListener(Object wl, int count)
+ {
+ _wl = wl;
+ _count = count;
+ }
+
+ public void MessageTransfer(IMessage m)
+ {
+ byte[] body = new byte[m.Body.Length - m.Body.Position];
+ _log.Debug("Got a message of size: " + body.Length + " count = " + _count);
+ _rs.Add(m.Id);
+ lock (_wl)
+ {
+ _count--;
+ if (_count == 0)
+ {
+ Monitor.PulseAll(_wl);
+ }
+ }
+ }
+
+ public int Count
+ {
+ get { return _count; }
+ }
+
+ public RangeSet UnAck
+ {
+ get { return _rs; }
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/test/interop/TestCase.cs b/dotnet/client-010/test/interop/TestCase.cs
new file mode 100644
index 0000000000..867f082000
--- /dev/null
+++ b/dotnet/client-010/test/interop/TestCase.cs
@@ -0,0 +1,96 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+using System.Xml;
+using common.org.apache.qpid.transport.util;
+using log4net.Config;
+using NUnit.Framework;
+using org.apache.qpid.client;
+using org.apache.qpid.transport;
+using org.apache.qpid.transport.util;
+using test.Helpers;
+
+namespace test.interop
+{
+ [TestFixture]
+
+ public class TestCase
+ {
+ private readonly Dictionary<string,string> _properties = new Dictionary<string, string>();
+ private Client _client;
+
+ [TestFixtureSetUp]
+ public void Init()
+ {
+ var properties = ConfigHelpers.LoadConfig();
+ // create a client and connect to the broker
+ _client = new Client();
+ _client.Connect(properties["Host"], Convert.ToInt16(properties["Port"]), properties["VirtualHost"],
+ properties["Username"], properties["Password"]);
+
+ }
+
+ [TestFixtureTearDown]
+ public void Cleanup()
+ {
+ // Note : breaks the Resharper nunit test runner. It blocks on the Monitor.WaitAll()
+ // Certainly a problem with the threading context..
+ //_client.Close();
+ }
+
+ public Client Client
+ {
+ get{ return _client;}
+ }
+
+ public Dictionary<string,string> Properties
+ {
+ get { return _properties; }
+ }
+
+
+ public class SyncListener : IMessageListener
+ {
+ private static readonly Logger _log = Logger.Get(typeof(SyncListener));
+ private readonly CircularBuffer<IMessage> _buffer;
+ private readonly RangeSet _range = new RangeSet();
+ private readonly IClientSession _session;
+
+ public SyncListener(IClientSession session, CircularBuffer<IMessage> buffer)
+ {
+ _buffer = buffer;
+ _session = session;
+ }
+
+ public void MessageTransfer(IMessage m)
+ {
+ _range.Clear();
+ _range.Add(m.Id);
+ _session.MessageAccept(_range);
+ _buffer.Enqueue(m);
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/test/transport/util/ByteEncoderTest.cs b/dotnet/client-010/test/transport/util/ByteEncoderTest.cs
new file mode 100644
index 0000000000..f3a05f1c3c
--- /dev/null
+++ b/dotnet/client-010/test/transport/util/ByteEncoderTest.cs
@@ -0,0 +1,106 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using NUnit.Framework;
+using org.apache.qpid.transport.util;
+
+
+namespace test.transport.util
+{
+ [TestFixture]
+
+ public class ByteEncoderTest
+ {
+ private static readonly Logger _log = Logger.Get(typeof(ByteEncoderTest));
+
+ [Test]
+ public void GetBigEndianInt32()
+ {
+ _log.Debug("Running: GetBigEndianInt32");
+ const int anInt = -12345;
+ Int32 aNewInt = ByteEncoder.GetBigEndian(anInt);
+ Assert.IsTrue( anInt == ByteEncoder.GetBigEndian(aNewInt) );
+ }
+
+ [Test]
+ public void GetBigEndianUInt16()
+ {
+ _log.Debug("Running: GetBigEndianUInt16");
+ const UInt16 anInt = 123;
+ UInt16 aNewInt = ByteEncoder.GetBigEndian(anInt);
+ Assert.IsTrue(anInt == ByteEncoder.GetBigEndian(aNewInt));
+ }
+
+ [Test]
+ public void GetBigEndianUInt32()
+ {
+ _log.Debug("Running: GetBigEndianUInt32");
+ const UInt32 anInt = 12345;
+ UInt32 aNewInt = ByteEncoder.GetBigEndian(anInt);
+ Assert.IsTrue(anInt == ByteEncoder.GetBigEndian(aNewInt));
+ }
+
+ [Test]
+ public void GetBigEndianlong()
+ {
+ _log.Debug("Running: GetBigEndianlong");
+ const long anInt = 123456660700770;
+ long aNewInt = ByteEncoder.GetBigEndian(anInt);
+ Assert.IsTrue(anInt == ByteEncoder.GetBigEndian(aNewInt));
+ }
+
+ [Test]
+ public void GetLittleEndianInt32()
+ {
+ _log.Debug("Running: GetBigEndianInt32");
+ const int anInt = -12345;
+ Int32 aNewInt = ByteEncoder.GetLittleEndian(anInt);
+ Assert.IsTrue(anInt == ByteEncoder.GetLittleEndian(aNewInt));
+ }
+
+ [Test]
+ public void GetLittleEndianUInt16()
+ {
+ _log.Debug("Running: GetLittleEndianUInt16");
+ const UInt16 anInt = 123;
+ UInt16 aNewInt = ByteEncoder.GetLittleEndian(anInt);
+ Assert.IsTrue(anInt == ByteEncoder.GetLittleEndian(aNewInt));
+ }
+
+ [Test]
+ public void GetLittleEndianUInt32()
+ {
+ _log.Debug("Running: GetLittleEndianUInt32");
+ const UInt32 anInt = 12345;
+ UInt32 aNewInt = ByteEncoder.GetLittleEndian(anInt);
+ Assert.IsTrue(anInt == ByteEncoder.GetLittleEndian(aNewInt));
+ }
+
+ [Test]
+ public void GetLittleEndianlong()
+ {
+ _log.Debug("Running: GetLittleEndianlong");
+ const long anInt = 123456660700770;
+ long aNewInt = ByteEncoder.GetLittleEndian(anInt);
+ Assert.IsTrue(anInt == ByteEncoder.GetLittleEndian(aNewInt));
+ }
+ }
+}
diff --git a/dotnet/client-010/test/transport/util/CircularBufferTest.cs b/dotnet/client-010/test/transport/util/CircularBufferTest.cs
new file mode 100644
index 0000000000..5e39569cf8
--- /dev/null
+++ b/dotnet/client-010/test/transport/util/CircularBufferTest.cs
@@ -0,0 +1,89 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.Threading;
+using common.org.apache.qpid.transport.util;
+using NUnit.Framework;
+using org.apache.qpid.transport.util;
+
+namespace test.transport.util
+{
+ [TestFixture]
+
+ public class CircularBufferTest
+ {
+ private CircularBuffer<Object> _buf;
+ private static readonly Logger _log = Logger.Get(typeof(CircularBufferTest));
+
+ [Test]
+ public void BlockingEnqueue()
+ {
+ _log.Debug("Running: BlockingEnqueue");
+ const int size = 10;
+ _buf = new CircularBuffer<Object>(size);
+ // add size element anc check that the size +1 add blocks
+ for (int i = 1; i < size; i++ )
+ {
+ _buf.Enqueue(new object());
+ }
+ // check tha the buffer is now full
+ Thread t = new Thread(Go);
+ t.Start();
+ Thread.Sleep(100);
+ // the trhead t should block until an element is dequeued
+ Assert.IsTrue(t.ThreadState == ThreadState.WaitSleepJoin);
+ _buf.Dequeue();
+ // t should now be stopped
+ Thread.Sleep(100);
+ Assert.IsTrue(t.ThreadState == ThreadState.Stopped);
+ }
+
+ [Test]
+ public void Close()
+ {
+ _log.Debug("Running: BlockingEnqueue");
+ const int size = 10;
+ _buf = new CircularBuffer<Object>(size);
+ // add size element anc check that the size +1 add blocks
+ for (int i = 1; i < size; i++)
+ {
+ _buf.Enqueue(new object());
+ }
+ // check tha the buffer is now full
+ Thread t = new Thread(Go);
+ t.Start();
+ Thread.Sleep(1000);
+ // the trhead t should block until the buffer is closed
+ Assert.IsTrue(t.ThreadState == ThreadState.WaitSleepJoin);
+ _buf.Close();
+ Thread.Sleep(100);
+ // t should now be stopped
+ Assert.IsTrue(t.ThreadState == ThreadState.Stopped);
+ }
+
+ void Go()
+ {
+ _buf.Enqueue(new object());
+ }
+
+ }
+}
diff --git a/dotnet/client-010/test/transport/util/ResultFutureTest.cs b/dotnet/client-010/test/transport/util/ResultFutureTest.cs
new file mode 100644
index 0000000000..e8e011a1e9
--- /dev/null
+++ b/dotnet/client-010/test/transport/util/ResultFutureTest.cs
@@ -0,0 +1,103 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using common.org.apache.qpid.transport.util;
+using NUnit.Framework;
+using org.apache.qpid.transport;
+using org.apache.qpid.transport.codec;
+using org.apache.qpid.transport.util;
+
+
+namespace test.transport.util
+{
+ [TestFixture]
+ public class ResultFutureTest
+ {
+ private static readonly Logger _log = Logger.Get(typeof (ByteEncoderTest));
+ private static ResultFuture _future;
+
+ [Test]
+ public void getFutureTimeout()
+ {
+ _log.Debug("Running: getFutureTimeout");
+ _future = new ResultFuture();
+ _future.Session = new Session(new byte[1]);
+ DateTime start = DateTime.Now;
+ Struct result = _future.Get(1000);
+ Assert.IsTrue(DateTime.Now.Subtract(start).TotalMilliseconds >= 1000);
+ Assert.IsNull(result);
+ }
+
+ [Test]
+ public void getFuture()
+ {
+ _log.Debug("Running: getFuture");
+ _future = new ResultFuture();
+ _future.Session = new Session(new byte[1]);
+ Thread t = new Thread(Go);
+ t.Start();
+ Struct result = _future.Get(2000);
+ Assert.IsNotNull(result);
+ }
+
+
+ void Go()
+ {
+ Thread.Sleep(500);
+ _future.Result = new myStruct();
+ }
+ }
+
+ public class myStruct:Struct
+ {
+ public override int GetStructType()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override int GetSizeWidth()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override int GetPackWidth()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override void Read(IDecoder dec)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override void Write(IEncoder enc)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override Dictionary<string, object> Fields
+ {
+ get { throw new System.NotImplementedException(); }
+ }
+ }
+}
diff --git a/dotnet/client-010/test/transport/util/SerialTest.cs b/dotnet/client-010/test/transport/util/SerialTest.cs
new file mode 100644
index 0000000000..772327c3b0
--- /dev/null
+++ b/dotnet/client-010/test/transport/util/SerialTest.cs
@@ -0,0 +1,75 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using NUnit.Framework;
+using org.apache.qpid.transport.util;
+
+namespace test.transport.util
+{
+ [TestFixture]
+ public class SerialTest
+ {
+ private static readonly Logger _log = Logger.Get(typeof (SerialTest));
+
+ [Test]
+ ///
+ /// Test the key boundaries where wraparound occurs.
+ ///
+ public void testBoundaries()
+ {
+ Assert.IsTrue(Serial.Gt(1, 0));
+ Assert.IsTrue(Serial.Lt(0, 1));
+
+ Assert.IsTrue(Serial.Gt(int.MaxValue, int.MaxValue - 1));
+ Assert.IsTrue(Serial.Lt(int.MaxValue - 1, int.MaxValue));
+ }
+
+ ///
+ /// Test the first Corollary of RFC 1982
+ /// For any sequence number s and any integer n such that addition of n
+ /// to s is well defined, (s + n) >= s. Further (s + n) == s only when
+ /// n == 0, in all other defined cases, (s + n) > s.
+ ///
+ public void testCorollary1()
+ {
+ int wrapcount = 0;
+
+ int s = 0;
+
+ for (int i = 0; i < 67108664; i++)
+ {
+ for (int n = 1; n < 4096; n += 512)
+ {
+ Assert.IsTrue(Serial.Gt(s + n, s));
+ Assert.IsTrue(Serial.Lt(s, s + n));
+ }
+
+ s += 1024;
+
+ if (s == 0)
+ {
+ wrapcount += 1;
+ }
+ }
+
+ Assert.IsTrue(wrapcount > 0);
+ }
+ }
+}
diff --git a/dotnet/client-010/test/transport/util/UUIDTest.cs b/dotnet/client-010/test/transport/util/UUIDTest.cs
new file mode 100644
index 0000000000..41104f8873
--- /dev/null
+++ b/dotnet/client-010/test/transport/util/UUIDTest.cs
@@ -0,0 +1,64 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System;
+using NUnit.Framework;
+using org.apache.qpid.transport.util;
+
+namespace test.transport.util
+{
+ [TestFixture]
+
+ public class UUIDTest
+ {
+
+
+ [Test]
+ public void createUUID()
+ {
+ UUID uuid = UUID.RandomUuid();
+ String uuidStr = uuid.ToString();
+ Assert.IsNotNull(uuid);
+ UUID uuid2 = UUID.RandomUuid();
+ Assert.AreNotSame(uuid, uuid2);
+ }
+
+ [Test]
+ public void ToString_should_override_and_not_hide_base()
+ {
+ UUID uuid = UUID.RandomUuid();
+
+ string uuidStr = uuid.ToString();
+ string uuidConcat = "Test." + uuid;
+
+ Assert.AreEqual("Test." + uuidStr, uuidConcat);
+ }
+
+ [Test]
+ public void two_uuid_with_same_value_should_have_same_hash_code()
+ {
+ UUID uuid = UUID.RandomUuid();
+ UUID uuid2 = new UUID(uuid.MostSignificantBits, uuid.LeastSignificantBits);
+
+ Assert.AreEqual(uuid, uuid2);
+ Assert.AreEqual(uuid.GetHashCode(), uuid2.GetHashCode());
+ }
+ }
+}
diff --git a/dotnet/client-010/wcf/Properties/AssemblyInfo.cs b/dotnet/client-010/wcf/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..66f2bb1268
--- /dev/null
+++ b/dotnet/client-010/wcf/Properties/AssemblyInfo.cs
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Qpid WCF")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("Qpid WCF")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("a39d56ec-7d81-48e1-9602-347a3ce6f638")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/client-010/wcf/demo/ConfigDemo.suo b/dotnet/client-010/wcf/demo/ConfigDemo.suo
new file mode 100644
index 0000000000..baa935693b
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/ConfigDemo.suo
Binary files differ
diff --git a/dotnet/client-010/wcf/demo/Demo.suo b/dotnet/client-010/wcf/demo/Demo.suo
new file mode 100644
index 0000000000..ee4cb5d21e
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/Demo.suo
Binary files differ
diff --git a/dotnet/client-010/wcf/demo/wcfBookingClient/Form1.Designer.cs b/dotnet/client-010/wcf/demo/wcfBookingClient/Form1.Designer.cs
new file mode 100644
index 0000000000..9ec3a08359
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfBookingClient/Form1.Designer.cs
@@ -0,0 +1,185 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+namespace WindowsFormsBooking
+{
+ partial class Form1
+ {
+ /// <summary>
+ /// Required designer variable.
+ /// </summary>
+ private System.ComponentModel.IContainer components = null;
+
+ /// <summary>
+ /// Clean up any resources being used.
+ /// </summary>
+ /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ /// <summary>
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ /// </summary>
+ private void InitializeComponent()
+ {
+ this.comboBox1 = new System.Windows.Forms.ComboBox();
+ this.label1 = new System.Windows.Forms.Label();
+ this.numericUpDown1 = new System.Windows.Forms.NumericUpDown();
+ this.label2 = new System.Windows.Forms.Label();
+ this.button1 = new System.Windows.Forms.Button();
+ this.richTextBox1 = new System.Windows.Forms.RichTextBox();
+ this.button2 = new System.Windows.Forms.Button();
+ ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit();
+ this.SuspendLayout();
+ //
+ // comboBox1
+ //
+ this.comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.comboBox1.FormattingEnabled = true;
+ this.comboBox1.Items.AddRange(new object[] {
+ "Hotel",
+ "Taxi",
+ "Train",
+ "Cinema",
+ "Theater",
+ "Restaurant"});
+ this.comboBox1.Location = new System.Drawing.Point(60, 20);
+ this.comboBox1.Name = "comboBox1";
+ this.comboBox1.Size = new System.Drawing.Size(76, 21);
+ this.comboBox1.TabIndex = 0;
+ this.comboBox1.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged);
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(23, 20);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(31, 13);
+ this.label1.TabIndex = 1;
+ this.label1.Text = "Type";
+ //
+ // numericUpDown1
+ //
+ this.numericUpDown1.Increment = new decimal(new int[] {
+ 10,
+ 0,
+ 0,
+ 0});
+ this.numericUpDown1.Location = new System.Drawing.Point(60, 49);
+ this.numericUpDown1.Maximum = new decimal(new int[] {
+ 200,
+ 0,
+ 0,
+ 0});
+ this.numericUpDown1.Minimum = new decimal(new int[] {
+ 30,
+ 0,
+ 0,
+ 0});
+ this.numericUpDown1.Name = "numericUpDown1";
+ this.numericUpDown1.Size = new System.Drawing.Size(76, 20);
+ this.numericUpDown1.TabIndex = 2;
+ this.numericUpDown1.Value = new decimal(new int[] {
+ 30,
+ 0,
+ 0,
+ 0});
+ this.numericUpDown1.ValueChanged += new System.EventHandler(this.numericUpDown1_ValueChanged);
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.Location = new System.Drawing.Point(23, 56);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(31, 13);
+ this.label2.TabIndex = 3;
+ this.label2.Text = "Price";
+ //
+ // button1
+ //
+ this.button1.Location = new System.Drawing.Point(142, 20);
+ this.button1.Name = "button1";
+ this.button1.Size = new System.Drawing.Size(40, 49);
+ this.button1.TabIndex = 4;
+ this.button1.Text = "Add";
+ this.button1.UseVisualStyleBackColor = true;
+ this.button1.Click += new System.EventHandler(this.button1_Click);
+ //
+ // richTextBox1
+ //
+ this.richTextBox1.ForeColor = System.Drawing.SystemColors.ControlText;
+ this.richTextBox1.Location = new System.Drawing.Point(27, 113);
+ this.richTextBox1.Name = "richTextBox1";
+ this.richTextBox1.Size = new System.Drawing.Size(155, 83);
+ this.richTextBox1.TabIndex = 5;
+ this.richTextBox1.Text = "";
+ //
+ // button2
+ //
+ this.button2.Location = new System.Drawing.Point(27, 81);
+ this.button2.Name = "button2";
+ this.button2.Size = new System.Drawing.Size(155, 29);
+ this.button2.TabIndex = 6;
+ this.button2.Text = "Receipt";
+ this.button2.UseVisualStyleBackColor = true;
+ this.button2.Click += new System.EventHandler(this.button2_Click);
+ //
+ // Form1
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(211, 211);
+ this.Controls.Add(this.button2);
+ this.Controls.Add(this.richTextBox1);
+ this.Controls.Add(this.button1);
+ this.Controls.Add(this.label2);
+ this.Controls.Add(this.numericUpDown1);
+ this.Controls.Add(this.label1);
+ this.Controls.Add(this.comboBox1);
+ this.Name = "Form1";
+ this.Text = "Booking Client";
+ ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.ComboBox comboBox1;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.NumericUpDown numericUpDown1;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.Button button1;
+ private System.Windows.Forms.RichTextBox richTextBox1;
+ private System.Windows.Forms.Button button2;
+ }
+}
+
diff --git a/dotnet/client-010/wcf/demo/wcfBookingClient/Form1.cs b/dotnet/client-010/wcf/demo/wcfBookingClient/Form1.cs
new file mode 100644
index 0000000000..89205bd6bd
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfBookingClient/Form1.cs
@@ -0,0 +1,96 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.ServiceModel;
+using System.Windows.Forms;
+using org.apache.qpid.wcf.demo;
+using org.apache.qpid.wcf.model;
+using org.apache.qpid.wcf.demo.bookingServer;
+
+namespace WindowsFormsBooking
+{
+ public partial class Form1 : Form
+ {
+ private ChannelFactory<IBooking> _fac;
+ private readonly Order _order = new Order();
+ private IBooking _calc;
+
+ public Form1()
+ {
+ InitializeComponent();
+ _calc = StartClient(new QpidBinding("192.168.1.14", 5673));
+ _order.Type = "Default";
+ _order.Price = 0;
+ }
+
+ public IBooking StartClient(System.ServiceModel.Channels.Binding binding)
+ {
+ IBooking res = null;
+ try
+ {
+ Console.WriteLine(" Starting Client...");
+ _fac = new ChannelFactory<IBooking>(binding, "soap.amqp:///Booking");
+ _fac.Open();
+ res = _fac.CreateChannel();
+ Console.WriteLine("[DONE]");
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ }
+ return res;
+ }
+
+ public void StopClient(IBooking client)
+ {
+ Console.WriteLine(" Stopping Client...");
+ ((System.ServiceModel.Channels.IChannel)client).Close();
+ _fac.Close();
+ Console.WriteLine("[DONE]");
+ }
+
+ private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ _order.Type = ((ComboBox) sender).SelectedItem.ToString();
+ }
+
+ private void numericUpDown1_ValueChanged(object sender, EventArgs e)
+ {
+ _order.Price = (double) ((NumericUpDown) sender).Value;
+ }
+
+ private void button1_Click(object sender, EventArgs e)
+ {
+ _calc.Add(_order);
+ }
+
+ private void button2_Click(object sender, EventArgs e)
+ {
+ Receipt r = _calc.Checkout();
+ richTextBox1.Text = r.Summary + "\n" + "Total Price = " + r.Price;
+ // reset
+ _calc = StartClient(new QpidBinding("192.168.1.14", 5673));
+ }
+
+
+ }
+}
diff --git a/dotnet/client-010/wcf/demo/wcfBookingClient/Form1.resx b/dotnet/client-010/wcf/demo/wcfBookingClient/Form1.resx
new file mode 100644
index 0000000000..360ccecbfe
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfBookingClient/Form1.resx
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <metadata name="richTextBox1.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+ <value>True</value>
+ </metadata>
+</root> \ No newline at end of file
diff --git a/dotnet/client-010/wcf/demo/wcfBookingClient/Program.cs b/dotnet/client-010/wcf/demo/wcfBookingClient/Program.cs
new file mode 100644
index 0000000000..59189bf600
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfBookingClient/Program.cs
@@ -0,0 +1,41 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Windows.Forms;
+
+namespace WindowsFormsBooking
+{
+ static class Program
+ {
+ /// <summary>
+ /// The main entry point for the application.
+ /// </summary>
+ [STAThread]
+ static void Main()
+ {
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
+ Application.Run(new Form1());
+ }
+ }
+}
diff --git a/dotnet/client-010/wcf/demo/wcfBookingClient/Properties/AssemblyInfo.cs b/dotnet/client-010/wcf/demo/wcfBookingClient/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..be301395d3
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfBookingClient/Properties/AssemblyInfo.cs
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Booking Client")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("Booking Client")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("fc8b1e0e-1ca9-46fe-9aae-b1ed046716b8")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/client-010/wcf/demo/wcfBookingClient/Properties/Resources.Designer.cs b/dotnet/client-010/wcf/demo/wcfBookingClient/Properties/Resources.Designer.cs
new file mode 100644
index 0000000000..42f9731a3d
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfBookingClient/Properties/Resources.Designer.cs
@@ -0,0 +1,92 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.1433
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace WindowsFormsBooking.Properties
+{
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources
+ {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources()
+ {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager
+ {
+ get
+ {
+ if ((resourceMan == null))
+ {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WindowsFormsBooking.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture
+ {
+ get
+ {
+ return resourceCulture;
+ }
+ set
+ {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/wcf/demo/wcfBookingClient/Properties/Resources.resx b/dotnet/client-010/wcf/demo/wcfBookingClient/Properties/Resources.resx
new file mode 100644
index 0000000000..af7dbebbac
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfBookingClient/Properties/Resources.resx
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+</root> \ No newline at end of file
diff --git a/dotnet/client-010/wcf/demo/wcfBookingClient/Properties/Settings.Designer.cs b/dotnet/client-010/wcf/demo/wcfBookingClient/Properties/Settings.Designer.cs
new file mode 100644
index 0000000000..212fb91438
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfBookingClient/Properties/Settings.Designer.cs
@@ -0,0 +1,51 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.1433
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace WindowsFormsBooking.Properties
+{
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
+ {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default
+ {
+ get
+ {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/wcf/demo/wcfBookingClient/Properties/Settings.settings b/dotnet/client-010/wcf/demo/wcfBookingClient/Properties/Settings.settings
new file mode 100644
index 0000000000..39645652af
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfBookingClient/Properties/Settings.settings
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
+ <Profiles>
+ <Profile Name="(Default)" />
+ </Profiles>
+ <Settings />
+</SettingsFile>
diff --git a/dotnet/client-010/wcf/demo/wcfBookingClient/wcBookingClient.csproj b/dotnet/client-010/wcf/demo/wcfBookingClient/wcBookingClient.csproj
new file mode 100644
index 0000000000..dbf12d376c
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfBookingClient/wcBookingClient.csproj
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{4086B3FE-F745-4DCC-952A-682CAE01F4C9}</ProjectGuid>
+ <OutputType>WinExe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>WindowsFormsBooking</RootNamespace>
+ <AssemblyName>Booking Client</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Deployment" />
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Windows.Forms" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Form1.cs">
+ <SubType>Form</SubType>
+ </Compile>
+ <Compile Include="Form1.Designer.cs">
+ <DependentUpon>Form1.cs</DependentUpon>
+ </Compile>
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <EmbeddedResource Include="Form1.resx">
+ <DependentUpon>Form1.cs</DependentUpon>
+ <SubType>Designer</SubType>
+ </EmbeddedResource>
+ <EmbeddedResource Include="Properties\Resources.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+ <SubType>Designer</SubType>
+ </EmbeddedResource>
+ <Compile Include="Properties\Resources.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DependentUpon>Resources.resx</DependentUpon>
+ </Compile>
+ <None Include="Properties\Settings.settings">
+ <Generator>SettingsSingleFileGenerator</Generator>
+ <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+ </None>
+ <Compile Include="Properties\Settings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DependentUpon>Settings.settings</DependentUpon>
+ <DesignTimeSharedInput>True</DesignTimeSharedInput>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\wcf.csproj">
+ <Project>{F1D80D9D-FE22-4213-A760-BFFDE7D131DD}</Project>
+ <Name>wcf</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\wcfBookingServer\wcfBookingServer.csproj">
+ <Project>{B34E21C4-A742-4886-8569-1A89490E093E}</Project>
+ <Name>wcfBookingServer</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/dotnet/client-010/wcf/demo/wcfBookingServer/Booking.cs b/dotnet/client-010/wcf/demo/wcfBookingServer/Booking.cs
new file mode 100644
index 0000000000..7c0fbb39b4
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfBookingServer/Booking.cs
@@ -0,0 +1,62 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.Collections.Generic;
+using System.ServiceModel;
+
+
+namespace org.apache.qpid.wcf.demo.bookingServer
+{
+ [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
+ public class Booking : IBooking
+ {
+ private Guid _id;
+ private List<Order> _orders;
+
+ public Booking()
+ {
+ _id = Guid.NewGuid();
+ _orders = new List<Order>();
+ }
+
+ public void Add(Order order)
+ {
+ _orders.Add(order);
+ }
+
+ public Receipt Checkout()
+ {
+ var r = new Receipt();
+ foreach (Order order in _orders)
+ {
+ r.Price += order.Price;
+ r.Summary = r.Summary + " \n " + order.Type + " Price: " + order.Price;
+ }
+ return r;
+ }
+
+ public Guid Id
+ {
+ get { return _id; }
+ }
+ }
+}
diff --git a/dotnet/client-010/wcf/demo/wcfBookingServer/IBooking.cs b/dotnet/client-010/wcf/demo/wcfBookingServer/IBooking.cs
new file mode 100644
index 0000000000..cead4d0471
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfBookingServer/IBooking.cs
@@ -0,0 +1,43 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.ServiceModel;
+
+namespace org.apache.qpid.wcf.demo.bookingServer
+{
+ [ServiceContract(SessionMode=SessionMode.Required)]
+ public interface IBooking
+ {
+ [OperationContract]
+ void Add(Order order);
+
+ [OperationContract]
+ Receipt Checkout();
+
+ Guid Id
+ {
+ [OperationContract]
+ get;
+ }
+ }
+
+}
diff --git a/dotnet/client-010/wcf/demo/wcfBookingServer/Order.cs b/dotnet/client-010/wcf/demo/wcfBookingServer/Order.cs
new file mode 100644
index 0000000000..aa52908692
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfBookingServer/Order.cs
@@ -0,0 +1,45 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System.Runtime.Serialization;
+
+namespace org.apache.qpid.wcf.demo.bookingServer
+{
+ [DataContract]
+ public sealed class Order
+ {
+ private double _price;
+ private string _type;
+
+ [DataMember]
+ public double Price
+ {
+ get { return _price; }
+ set { _price = value; }
+ }
+
+ [DataMember]
+ public string Type
+ {
+ get { return _type; }
+ set { _type = value; }
+ }
+ }
+}
diff --git a/dotnet/client-010/wcf/demo/wcfBookingServer/Program.cs b/dotnet/client-010/wcf/demo/wcfBookingServer/Program.cs
new file mode 100644
index 0000000000..ebb75308cf
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfBookingServer/Program.cs
@@ -0,0 +1,98 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.ServiceModel;
+using System.ServiceModel.Channels;
+using System.Threading;
+using org.apache.qpid.wcf.model;
+
+
+namespace org.apache.qpid.wcf.demo.bookingServer
+{
+ internal class Program
+ {
+ private ServiceHost _service;
+ private ChannelFactory<IBooking> fac;
+
+ public void StartService(Binding binding)
+ {
+ try
+ {
+ Console.WriteLine(" Binding Service...");
+ _service = new ServiceHost(typeof(Booking), new Uri("soap.amqp:///"));
+ _service.AddServiceEndpoint(typeof(IBooking), binding, "Booking");
+ _service.Open();
+ Thread.Sleep(500);
+ Console.WriteLine("[DONE]");
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ }
+ }
+
+ public void StopService()
+ {
+ Console.WriteLine(" Stopping Service...");
+ _service.Close();
+ Console.WriteLine("[DONE]");
+ }
+
+ public IBooking StartClient(Binding binding)
+ {
+ IBooking res = null;
+ try
+ {
+ Console.WriteLine(" Starting Client...");
+ fac = new ChannelFactory<IBooking>(binding, "soap.amqp:///Booking");
+ fac.Open();
+ res = fac.CreateChannel();
+ Console.WriteLine("[DONE]");
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ }
+ return res;
+ }
+
+ public void StopClient(IBooking client)
+ {
+ Console.WriteLine(" Stopping Client...");
+ ((IChannel)client).Close();
+ fac.Close();
+ Console.WriteLine("[DONE]");
+ }
+
+ private static void Main(string[] args)
+ {
+ var p = new Program();
+
+ Binding binding = new QpidBinding("192.168.1.14", 5673);
+ p.StartService(binding);
+
+ Console.ReadLine();
+
+ p.StopService();
+ }
+ }
+}
diff --git a/dotnet/client-010/wcf/demo/wcfBookingServer/Properties/AssemblyInfo.cs b/dotnet/client-010/wcf/demo/wcfBookingServer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..cc0208c9ca
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfBookingServer/Properties/AssemblyInfo.cs
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Booking Server")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("Booking Server")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("12ef158b-ac5f-43b3-99f6-e4a4c096d6f8")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/client-010/wcf/demo/wcfBookingServer/Receipt.cs b/dotnet/client-010/wcf/demo/wcfBookingServer/Receipt.cs
new file mode 100644
index 0000000000..d5ab0f3eb3
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfBookingServer/Receipt.cs
@@ -0,0 +1,46 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System.Runtime.Serialization;
+
+namespace org.apache.qpid.wcf.demo.bookingServer
+{
+ [DataContract]
+ public sealed class Receipt
+ {
+ private double _price;
+ private string _summary;
+
+ [DataMember]
+ public double Price
+ {
+ get { return _price; }
+ set { _price = value; }
+ }
+
+ [DataMember]
+ public string Summary
+ {
+ get { return _summary; }
+ set { _summary = value; }
+ }
+ }
+}
diff --git a/dotnet/client-010/wcf/demo/wcfBookingServer/wcfBookingServer.csproj b/dotnet/client-010/wcf/demo/wcfBookingServer/wcfBookingServer.csproj
new file mode 100644
index 0000000000..84e8bd5a06
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfBookingServer/wcfBookingServer.csproj
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{B34E21C4-A742-4886-8569-1A89490E093E}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>wcfSession</RootNamespace>
+ <AssemblyName>Booking Server</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Runtime.Serialization">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Windows.Forms" />
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Booking.cs" />
+ <Compile Include="Receipt.cs" />
+ <Compile Include="IBooking.cs" />
+ <Compile Include="Order.cs" />
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\wcf.csproj">
+ <Project>{F1D80D9D-FE22-4213-A760-BFFDE7D131DD}</Project>
+ <Name>wcf</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/dotnet/client-010/wcf/demo/wcfHelloClient/App.config b/dotnet/client-010/wcf/demo/wcfHelloClient/App.config
new file mode 100644
index 0000000000..1545d71d6f
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfHelloClient/App.config
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<configuration>
+ <system.serviceModel>
+
+ <client>
+ <endpoint address="soap.amqp:///Hello"
+ binding="customBinding"
+ bindingConfiguration="QpidBinding"
+ contract="org.apache.qpid.wcf.demo.helloClient.IHelloContract"
+ name="HelloService" />
+ </client>
+
+
+ <bindings>
+ <customBinding>
+ <binding name="QpidBinding">
+ <textMessageEncoding />
+ <QpidTransport
+ host="localhost"
+ port="5672" />
+ </binding>
+ </customBinding>
+ </bindings>
+
+ <extensions>
+ <bindingElementExtensions>
+ <add
+ name="QpidTransport"
+ type="org.apache.qpid.wcf.model.QpidTransportElement, qpidWCFModel"/>
+ </bindingElementExtensions>
+ </extensions>
+
+
+ </system.serviceModel>
+</configuration>
diff --git a/dotnet/client-010/wcf/demo/wcfHelloClient/HelloClient.cs b/dotnet/client-010/wcf/demo/wcfHelloClient/HelloClient.cs
new file mode 100644
index 0000000000..31743c62cf
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfHelloClient/HelloClient.cs
@@ -0,0 +1,36 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System.ServiceModel;
+
+namespace org.apache.qpid.wcf.demo.helloClient
+{
+ public class HelloClient : ClientBase<IHelloContract>, IHelloContract
+ {
+ public HelloClient(string configurationName)
+ : base(configurationName) { }
+
+ public void Hello(string name)
+ {
+ Channel.Hello(name);
+ }
+ }
+}
diff --git a/dotnet/client-010/wcf/demo/wcfHelloClient/IHelloService.cs b/dotnet/client-010/wcf/demo/wcfHelloClient/IHelloService.cs
new file mode 100644
index 0000000000..d3b9a354ba
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfHelloClient/IHelloService.cs
@@ -0,0 +1,33 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System.ServiceModel;
+
+namespace org.apache.qpid.wcf.demo.helloClient
+{
+ [ServiceContract]
+ public interface IHelloContract
+ {
+ [OperationContract(IsOneWay=true)]
+ void Hello(string name);
+ }
+
+}
diff --git a/dotnet/client-010/wcf/demo/wcfHelloClient/Program.cs b/dotnet/client-010/wcf/demo/wcfHelloClient/Program.cs
new file mode 100644
index 0000000000..fc68d2556a
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfHelloClient/Program.cs
@@ -0,0 +1,48 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+
+namespace org.apache.qpid.wcf.demo.helloClient
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ Console.Title = "Hello Service Client";
+ Console.ForegroundColor = ConsoleColor.White;
+ Console.WriteLine("Hello Service Client");
+ Console.ForegroundColor = ConsoleColor.Gray;
+ Console.WriteLine();
+ // create a client using the configuration file App.config
+ var client = new HelloClient("HelloService");
+ Console.WriteLine("Client Saying Hello to Qpid");
+ client.Hello("Qpid");
+ Console.WriteLine("Client Saying Hello to AMQP");
+ client.Hello("AMQP");
+ // closing the client service
+ client.ChannelFactory.Close();
+ Console.WriteLine();
+ Console.Write("Press Enter to Exit...");
+ Console.ReadLine();
+ }
+ }
+}
diff --git a/dotnet/client-010/wcf/demo/wcfHelloClient/Properties/AssemblyInfo.cs b/dotnet/client-010/wcf/demo/wcfHelloClient/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..83dfbcd5f4
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfHelloClient/Properties/AssemblyInfo.cs
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Qpid WCF Hello Client")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("Qpid WCF Hello Client")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("f7628695-280a-4689-ac6f-1186177f9a25")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/client-010/wcf/demo/wcfHelloClient/wcfHelloClient.csproj b/dotnet/client-010/wcf/demo/wcfHelloClient/wcfHelloClient.csproj
new file mode 100644
index 0000000000..5ad1e9624e
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfHelloClient/wcfHelloClient.csproj
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{A24E27DB-A38D-40C9-9879-8390B68C2F06}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>wcfHelloClient</RootNamespace>
+ <AssemblyName>Qpid WCF Hello Client</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.configuration" />
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="HelloClient.cs" />
+ <Compile Include="IHelloService.cs" />
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="App.config" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\wcf.csproj">
+ <Project>{F1D80D9D-FE22-4213-A760-BFFDE7D131DD}</Project>
+ <Name>wcf</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/dotnet/client-010/wcf/demo/wcfHelloServer/App.config b/dotnet/client-010/wcf/demo/wcfHelloServer/App.config
new file mode 100644
index 0000000000..de71f890b5
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfHelloServer/App.config
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<configuration>
+ <system.serviceModel>
+
+
+ <services>
+ <service name="org.apache.qpid.wcf.demo.HelloService">
+ <host>
+ <baseAddresses>
+ <add baseAddress="soap.amqp:///" />
+ </baseAddresses>
+ </host>
+ <endpoint
+ address="Hello"
+ binding="customBinding"
+ bindingConfiguration="QpidBinding"
+ contract="org.apache.qpid.wcf.demo.IHelloContract"/>
+ </service>
+ </services>
+
+
+ <bindings>
+ <customBinding>
+ <binding name="QpidBinding">
+ <textMessageEncoding />
+ <QpidTransport
+ host="192.168.1.14"
+ port="5673" />
+ </binding>
+ </customBinding>
+ </bindings>
+
+ <extensions>
+ <bindingElementExtensions>
+ <add
+ name="QpidTransport"
+ type="org.apache.qpid.wcf.model.QpidTransportElement, qpidWCFModel"/>
+ </bindingElementExtensions>
+ </extensions>
+
+
+ </system.serviceModel>
+</configuration>
diff --git a/dotnet/client-010/wcf/demo/wcfHelloServer/HelloService.cs b/dotnet/client-010/wcf/demo/wcfHelloServer/HelloService.cs
new file mode 100644
index 0000000000..3b7df01ece
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfHelloServer/HelloService.cs
@@ -0,0 +1,34 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+
+namespace org.apache.qpid.wcf.demo.helloServer
+{
+ public class HelloService : IHelloContract
+ {
+ public void Hello(string name)
+ {
+ Console.WriteLine("Hello {0}!", name);
+
+ }
+ }
+}
diff --git a/dotnet/client-010/wcf/demo/wcfHelloServer/IHelloService.cs b/dotnet/client-010/wcf/demo/wcfHelloServer/IHelloService.cs
new file mode 100644
index 0000000000..1609439b94
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfHelloServer/IHelloService.cs
@@ -0,0 +1,32 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System.ServiceModel;
+
+namespace org.apache.qpid.wcf.demo.helloServer
+{
+ [ServiceContract]
+ public interface IHelloContract
+ {
+ [OperationContract(IsOneWay=true)]
+ void Hello(string name);
+ }
+
+}
diff --git a/dotnet/client-010/wcf/demo/wcfHelloServer/Program.cs b/dotnet/client-010/wcf/demo/wcfHelloServer/Program.cs
new file mode 100644
index 0000000000..1b8b8947ee
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfHelloServer/Program.cs
@@ -0,0 +1,47 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.ServiceModel;
+
+namespace org.apache.qpid.wcf.demo.helloServer
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ Console.Title = "Hello Service Server";
+ Console.ForegroundColor = ConsoleColor.White;
+ Console.WriteLine("Hello Service Server");
+ Console.ForegroundColor = ConsoleColor.Gray;
+ Console.WriteLine();
+
+ var host = new ServiceHost(typeof(HelloService));
+ host.Open();
+
+ Console.WriteLine("Service Ready");
+ Console.WriteLine("Press Enter to Exit...");
+ Console.ReadLine();
+
+ host.Close();
+ }
+ }
+}
diff --git a/dotnet/client-010/wcf/demo/wcfHelloServer/Properties/AssemblyInfo.cs b/dotnet/client-010/wcf/demo/wcfHelloServer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..a32f32e864
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfHelloServer/Properties/AssemblyInfo.cs
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Qpid WCF Hello Server")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("Qpid WCF Hello Server")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("afa87185-f224-4948-904c-b4f3cd19dadb")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/client-010/wcf/demo/wcfHelloServer/wcfHelloServer.csproj b/dotnet/client-010/wcf/demo/wcfHelloServer/wcfHelloServer.csproj
new file mode 100644
index 0000000000..b32c353c18
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfHelloServer/wcfHelloServer.csproj
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{3EF848D7-5FAC-482C-922A-D4D45A4CCD2A}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>wcfHelloServer</RootNamespace>
+ <AssemblyName>Qpid WCF Hello Server</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="HelloService.cs" />
+ <Compile Include="IHelloService.cs" />
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="App.config" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/dotnet/client-010/wcf/demo/wcfRPC/IUpperCase.cs b/dotnet/client-010/wcf/demo/wcfRPC/IUpperCase.cs
new file mode 100644
index 0000000000..668450948d
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfRPC/IUpperCase.cs
@@ -0,0 +1,31 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System.ServiceModel;
+
+namespace org.apache.qpid.wcf.demo.rpc
+{
+ [ServiceContract]
+ public interface IUpperCase
+ {
+ [OperationContract]
+ string ToUpperCase(string message);
+ }
+}
diff --git a/dotnet/client-010/wcf/demo/wcfRPC/Program.cs b/dotnet/client-010/wcf/demo/wcfRPC/Program.cs
new file mode 100644
index 0000000000..e2b54a0f61
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfRPC/Program.cs
@@ -0,0 +1,113 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.ServiceModel;
+using System.ServiceModel.Channels;
+using System.Threading;
+using org.apache.qpid.wcf.model;
+
+
+namespace org.apache.qpid.wcf.demo.rpc
+{
+ internal class Program
+ {
+ private ServiceHost _service;
+ private ChannelFactory<IUpperCase> fac;
+
+ public void StartService(Binding binding)
+ {
+ try
+ {
+ Console.WriteLine(" Binding Service...");
+ _service = new ServiceHost(typeof (UpperCase), new Uri("soap.amqp:///"));
+ _service.AddServiceEndpoint(typeof(IUpperCase), binding, "UpperCase");
+ _service.Open();
+ Thread.Sleep(500);
+ Console.WriteLine("[DONE]");
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ }
+ }
+
+ public void StopService()
+ {
+ Console.WriteLine(" Stopping Service...");
+ _service.Close();
+ Console.WriteLine("[DONE]");
+ }
+
+ public IUpperCase StartClient(Binding binding)
+ {
+ IUpperCase res = null;
+ try
+ {
+ Console.WriteLine(" Starting Client...");
+ fac = new ChannelFactory<IUpperCase>(binding, "soap.amqp:///UpperCase");
+ fac.Open();
+ res = fac.CreateChannel();
+ Console.WriteLine("[DONE]");
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ }
+ return res;
+ }
+
+ public void StopClient(IUpperCase client)
+ {
+ Console.WriteLine(" Stopping Client...");
+ ((IChannel) client).Close();
+ fac.Close();
+ Console.WriteLine("[DONE]");
+ }
+
+ private static void Main(string[] args)
+ {
+ var p = new Program();
+
+ Binding binding = new QpidBinding("192.168.1.14", 5673);
+ p.StartService(binding);
+
+
+ IUpperCase calc = p.StartClient(new QpidBinding("192.168.1.14", 5673));
+
+ string[] messages = {"Twas brillig, and the slithy toves",
+ "Did gire and gymble in the wabe. ",
+ "All mimsy were the borogroves, ",
+ "And the mome raths outgrabe. "};
+ foreach (string m in messages)
+ {
+ Console.Write(m + " --UperCase--> " );
+ Console.Write(calc.ToUpperCase(m));
+ Console.WriteLine();
+ }
+
+ Console.ReadLine();
+
+ p.StopClient(calc);
+ p.StopService();
+ }
+ }
+}
diff --git a/dotnet/client-010/wcf/demo/wcfRPC/Properties/AssemblyInfo.cs b/dotnet/client-010/wcf/demo/wcfRPC/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..703fb9fcea
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfRPC/Properties/AssemblyInfo.cs
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Qpid WCF UpperCase")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("Qpid WCF UpperCase")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("14ba3707-3fcc-4033-8bbc-0db65c5424f3")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/dotnet/client-010/wcf/demo/wcfRPC/QpidBindingConfigurationElement.cs b/dotnet/client-010/wcf/demo/wcfRPC/QpidBindingConfigurationElement.cs
new file mode 100644
index 0000000000..1d12868497
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfRPC/QpidBindingConfigurationElement.cs
@@ -0,0 +1,205 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.Reflection;
+using System.ServiceModel.Channels;
+using System.ServiceModel.Configuration;
+using System.Configuration;
+
+namespace org.apache.qpid.wcf.model
+{
+
+ /// <remarks>
+ /// This configuration element should be imported into the client
+ /// and server configuration files to provide declarative configuration
+ /// of a AMQP bound service.
+ /// </remarks>
+ public sealed class QpidBindingConfigurationElement : StandardBindingElement
+ {
+ /// <summary>
+ /// Creates a new instance of the QpidBindingConfigurationElement
+ /// Class initialized with values from the specified configuration.
+ /// </summary>
+ /// <param name="configurationName"></param>
+ public QpidBindingConfigurationElement(string configurationName)
+ : base(configurationName)
+ {
+ }
+
+ /// <summary>
+ /// Creates a new instance of the RabbitMQBindingConfigurationElement Class.
+ /// </summary>
+ public QpidBindingConfigurationElement()
+ : this(null)
+ {
+ }
+
+
+ protected override void InitializeFrom(Binding binding)
+ {
+ base.InitializeFrom(binding);
+ QpidBinding qpidbinding = binding as QpidBinding;
+ if (qpidbinding != null)
+ {
+ Host = qpidbinding.Host;
+ OneWayOnly = qpidbinding.OneWayOnly;
+ TransactionFlowEnabled = qpidbinding.TransactionFlow;
+ VirtualHost = qpidbinding.VirtualHost;
+ PortNumber = qpidbinding.PortNumber;
+ UserName = qpidbinding.UserName;
+ Password = qpidbinding.Password;
+ }
+ }
+
+ protected override void OnApplyConfiguration(Binding binding)
+ {
+ if (binding == null)
+ throw new ArgumentNullException("binding");
+
+ var qpidbinding = binding as QpidBinding;
+ if (qpidbinding == null)
+ {
+ throw new ArgumentException(
+ string.Format("Invalid type for binding. Expected {0}, Passed: {1}",
+ typeof(QpidBinding).AssemblyQualifiedName,
+ binding.GetType().AssemblyQualifiedName));
+ }
+
+ qpidbinding.Host = Host;
+ qpidbinding.OneWayOnly = OneWayOnly;
+ qpidbinding.TransactionFlow = TransactionFlowEnabled;
+ qpidbinding.Password = Password;
+ qpidbinding.UserName = UserName;
+ qpidbinding.VirtualHost = VirtualHost;
+ qpidbinding.PortNumber = PortNumber;
+ }
+
+
+ /// <summary>
+ /// Specifies the host that the binding should connect to.
+ /// </summary>
+ [ConfigurationProperty("host", DefaultValue = "localhost")]
+ public string Host
+ {
+ get { return ((string) base["host"]); }
+ set { base["host"] = value; }
+ }
+
+ /// <summary>
+ /// Specifies the broker port number that the binding should connect to.
+ /// </summary>
+ [ConfigurationProperty("port", DefaultValue = "5672")]
+ public int PortNumber
+ {
+ get { return (Convert.ToInt16(base["port"])); }
+ set { base["port"] = value; }
+ }
+
+
+ /// <summary>
+ /// Specifies whether or not the CompositeDuplex and ReliableSession
+ /// binding elements are added to the channel stack.
+ /// </summary>
+ [ConfigurationProperty("oneWay", DefaultValue = false)]
+ public bool OneWayOnly
+ {
+ get { return ((bool)base["oneWay"]); }
+ set { base["oneWay"] = value; }
+ }
+
+ /// <summary>
+ /// Password to use when authenticating with the broker
+ /// </summary>
+ [ConfigurationProperty("password", DefaultValue = "guest")]
+ public string Password
+ {
+ get { return ((string)base["password"]); }
+ set { base["password"] = value; }
+ }
+
+ /// <summary>
+ /// Specifies whether or not WS-AtomicTransactions are supported by the binding
+ /// </summary>
+ [ConfigurationProperty("transactionFlow", DefaultValue = false)]
+ public bool TransactionFlowEnabled
+ {
+ get { return ((bool)base["transactionFlow"]); }
+ set { base["transactionFlow"] = value; }
+ }
+
+ /// <summary>
+ /// The username to use when authenticating with the broker
+ /// </summary>
+ [ConfigurationProperty("username", DefaultValue = "guest")]
+ public string UserName
+ {
+ get { return ((string)base["username"]); }
+ set { base["username"] = value; }
+ }
+
+
+
+
+ /// <summary>
+ /// The virtual host to access.
+ /// </summary>
+ [ConfigurationProperty("virtualHost", DefaultValue = "test")]
+ public string VirtualHost
+ {
+ get { return ((string)base["virtualHost"]); }
+ set { base["virtualHost"] = value; }
+ }
+
+ ///<summary>The security realm to use when calling IModel.AccessRequest</summary>
+ [ConfigurationProperty("realm", DefaultValue = "plain")]
+ public string Realm
+ {
+ get { return ((string)base["realm"]); }
+ set { base["realm"] = value; }
+ }
+
+ protected override Type BindingElementType
+ {
+ get { return typeof(QpidBinding); }
+ }
+
+ protected override ConfigurationPropertyCollection Properties
+ {
+ get
+ {
+ ConfigurationPropertyCollection configProperties = base.Properties;
+ foreach (PropertyInfo prop in this.GetType().GetProperties(BindingFlags.DeclaredOnly
+ | BindingFlags.Public
+ | BindingFlags.Instance))
+ {
+ foreach (ConfigurationPropertyAttribute attr in prop.GetCustomAttributes(typeof(ConfigurationPropertyAttribute), false))
+ {
+ configProperties.Add(
+ new ConfigurationProperty(attr.Name, prop.PropertyType, attr.DefaultValue));
+ }
+ }
+
+ return configProperties;
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/wcf/demo/wcfRPC/UpperCase.cs b/dotnet/client-010/wcf/demo/wcfRPC/UpperCase.cs
new file mode 100644
index 0000000000..3e10926be4
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfRPC/UpperCase.cs
@@ -0,0 +1,33 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+using System.ServiceModel;
+
+namespace org.apache.qpid.wcf.demo.rpc
+{
+ [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
+ public sealed class UpperCase : IUpperCase
+ {
+ public string ToUpperCase(string message)
+ {
+ return message.ToUpper();
+ }
+ }
+}
diff --git a/dotnet/client-010/wcf/demo/wcfRPC/wcfRPC.csproj b/dotnet/client-010/wcf/demo/wcfRPC/wcfRPC.csproj
new file mode 100644
index 0000000000..c45dea2d39
--- /dev/null
+++ b/dotnet/client-010/wcf/demo/wcfRPC/wcfRPC.csproj
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{C988F456-1025-486F-9BCD-49C0F83B91DB}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>wcfRPC</RootNamespace>
+ <AssemblyName>Qpid WCF UpperCase</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.configuration" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Windows.Forms" />
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="IUpperCase.cs" />
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="UpperCase.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\wcf.csproj">
+ <Project>{F1D80D9D-FE22-4213-A760-BFFDE7D131DD}</Project>
+ <Name>wcf</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/dotnet/client-010/wcf/model/CommunicationOperation.cs b/dotnet/client-010/wcf/model/CommunicationOperation.cs
new file mode 100644
index 0000000000..3506d6729c
--- /dev/null
+++ b/dotnet/client-010/wcf/model/CommunicationOperation.cs
@@ -0,0 +1,31 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.ServiceModel.Channels;
+
+namespace org.apache.qpid.wcf.model
+{
+ internal delegate void CommunicationOperation(TimeSpan timeout);
+ internal delegate TResult CommunicationOperation<TResult>(TimeSpan timeout);
+ internal delegate TResult CommunicationOperation<TResult, TArg>(TimeSpan timeout, out TArg arg0);
+ internal delegate void SendOperation(Message message, TimeSpan timeout);
+}
diff --git a/dotnet/client-010/wcf/model/QpidBinding.cs b/dotnet/client-010/wcf/model/QpidBinding.cs
new file mode 100644
index 0000000000..8f4684c1a1
--- /dev/null
+++ b/dotnet/client-010/wcf/model/QpidBinding.cs
@@ -0,0 +1,185 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System.Configuration;
+using System.ServiceModel;
+using System.ServiceModel.Channels;
+
+namespace org.apache.qpid.wcf.model
+{
+ public sealed class QpidBinding : Binding
+ {
+ private string _host;
+ private int _port;
+ private string _username;
+ private string _password;
+ private string _virtuaHost;
+ private readonly CompositeDuplexBindingElement _compositeDuplex;
+ private readonly MessageEncodingBindingElement _encoding;
+ private bool _oneWayOnly;
+ private readonly ReliableSessionBindingElement _session;
+ private readonly TransactionFlowBindingElement _transactionFlow;
+ private bool _transactionsEnabled;
+ private readonly QpidTransportBindingElement _transport;
+
+
+
+ public QpidBinding() : this("localhost", 5672, "guest", "guest", "test")
+ {
+ }
+
+
+ public QpidBinding(string host, int port ) : this (host, port, "guest", "guest", "test")
+ {
+ }
+
+ public QpidBinding(string host, int port, string username, string password, string virtualhost)
+ {
+ Host = host;
+ PortNumber = port;
+ UserName = username;
+ Password = password;
+ VirtualHost = virtualhost;
+ _transport = new QpidTransportBindingElement();
+ _transport.Host = host;
+ _transport.PortNumber = port;
+ _transport.Password = password;
+ _transport.UserName = username;
+ _transport.VirtualHost = virtualhost;
+ _encoding = new TextMessageEncodingBindingElement();
+ _session = new ReliableSessionBindingElement();
+ _compositeDuplex = new CompositeDuplexBindingElement();
+ _transactionFlow = new TransactionFlowBindingElement();
+ }
+
+ public override BindingElementCollection CreateBindingElements()
+ {
+ var elements = new BindingElementCollection();
+
+ if (_transactionsEnabled)
+ {
+ elements.Add(_transactionFlow);
+ }
+ if (!OneWayOnly)
+ {
+ elements.Add(_session);
+ elements.Add(_compositeDuplex);
+ }
+ elements.Add(_encoding);
+ elements.Add(_transport);
+
+ return elements;
+ }
+
+
+
+ /// <summary>
+ /// Gets the scheme used by the binding, soap.amqp
+ /// </summary>
+ public override string Scheme
+ {
+ get { return "soap.amqp"; }
+ }
+
+ /// <summary>
+ /// Specifies the broker host
+ /// </summary>
+ [ConfigurationProperty("host")]
+ public string Host
+ {
+ get { return _host; }
+ set { _host = value; }
+ }
+
+ /// <summary>
+ /// Specifies the broker port
+ /// </summary>
+ public int PortNumber
+ {
+ get { return _port; }
+ set { _port = value; }
+ }
+
+ /// <summary>
+ /// Specifies the username
+ /// </summary>
+ public string UserName
+ {
+ get { return _username; }
+ set { _username = value; }
+ }
+
+ /// <summary>
+ /// Specifies the password
+ /// </summary>
+ public string Password
+ {
+ get { return _password; }
+ set { _password = value; }
+ }
+
+ /// <summary>
+ /// Specifies the virtualhost
+ /// </summary>
+ public string VirtualHost
+ {
+ get { return _virtuaHost; }
+ set { _virtuaHost = value; }
+ }
+
+
+ /// <summary>
+ /// Gets the AMQP _transport binding element
+ /// </summary>
+ public QpidTransportBindingElement Transport
+ {
+ get { return _transport; }
+ }
+
+ /// <summary>
+ /// Gets the reliable _session parameters for this binding instance
+ /// </summary>
+ public ReliableSession ReliableSession
+ {
+ get { return new ReliableSession(_session); }
+ }
+
+ /// <summary>
+ /// Determines whether or not the TransactionFlowBindingElement will
+ /// be added to the channel stack
+ /// </summary>
+ public bool TransactionFlow
+ {
+ get { return _transactionsEnabled; }
+ set { _transactionsEnabled = value; }
+ }
+
+ /// <summary>
+ /// Specifies whether or not the CompositeDuplex and ReliableSession
+ /// binding elements are added to the channel stack.
+ /// </summary>
+ public bool OneWayOnly
+ {
+ get { return _oneWayOnly; }
+ set { _oneWayOnly = value; }
+ }
+ }
+} \ No newline at end of file
diff --git a/dotnet/client-010/wcf/model/QpidChannelBase.cs b/dotnet/client-010/wcf/model/QpidChannelBase.cs
new file mode 100644
index 0000000000..174c28e108
--- /dev/null
+++ b/dotnet/client-010/wcf/model/QpidChannelBase.cs
@@ -0,0 +1,167 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.ServiceModel;
+using System.ServiceModel.Channels;
+
+namespace org.apache.qpid.wcf.model
+{
+ internal abstract class QpidChannelBase : IChannel
+ {
+ private readonly CommunicationOperation _closeMethod;
+ private readonly BindingContext _context;
+ private readonly CommunicationOperation _openMethod;
+ private CommunicationState _state;
+
+ private QpidChannelBase()
+ {
+ _state = CommunicationState.Created;
+ _closeMethod = Close;
+ _openMethod = Open;
+ }
+
+ protected QpidChannelBase(BindingContext context)
+ : this()
+ {
+ _context = context;
+ }
+
+ public abstract void Close(TimeSpan timeout);
+
+ public abstract void Open(TimeSpan timeout);
+
+ public virtual void Abort()
+ {
+ Close();
+ }
+
+ public virtual void Close()
+ {
+ Close(_context.Binding.CloseTimeout);
+ }
+
+ public virtual T GetProperty<T>() where T : class
+ {
+ return default(T);
+ }
+
+ public virtual void Open()
+ {
+ Open(_context.Binding.OpenTimeout);
+ }
+
+ #region Async Methods
+
+ public virtual IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return _closeMethod.BeginInvoke(timeout, callback, state);
+ }
+
+ public virtual IAsyncResult BeginClose(AsyncCallback callback, object state)
+ {
+ return _closeMethod.BeginInvoke(_context.Binding.CloseTimeout, callback, state);
+ }
+
+ public virtual IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return _openMethod.BeginInvoke(timeout, callback, state);
+ }
+
+ public virtual IAsyncResult BeginOpen(AsyncCallback callback, object state)
+ {
+ return _openMethod.BeginInvoke(_context.Binding.OpenTimeout, callback, state);
+ }
+
+ public virtual void EndClose(IAsyncResult result)
+ {
+ _closeMethod.EndInvoke(result);
+ }
+
+ public virtual void EndOpen(IAsyncResult result)
+ {
+ _openMethod.EndInvoke(result);
+ }
+
+ #endregion
+
+ #region Event Raising Methods
+
+ protected void OnOpening()
+ {
+ _state = CommunicationState.Opening;
+ if (Opening != null)
+ Opening(this, null);
+ }
+
+ protected void OnOpened()
+ {
+ _state = CommunicationState.Opened;
+ if (Opened != null)
+ Opened(this, null);
+ }
+
+ protected void OnClosing()
+ {
+ _state = CommunicationState.Closing;
+ if (Closing != null)
+ Closing(this, null);
+ }
+
+ protected void OnClosed()
+ {
+ _state = CommunicationState.Closed;
+ if (Closed != null)
+ Closed(this, null);
+ }
+
+ protected void OnFaulted()
+ {
+ _state = CommunicationState.Faulted;
+ if (Faulted != null)
+ Faulted(this, null);
+ }
+
+ #endregion
+
+
+ public CommunicationState State
+ {
+ get { return _state; }
+ }
+
+ protected BindingContext Context
+ {
+ get { return _context; }
+ }
+
+
+ public event EventHandler Closed;
+
+ public event EventHandler Closing;
+
+ public event EventHandler Faulted;
+
+ public event EventHandler Opened;
+
+ public event EventHandler Opening;
+ }
+}
diff --git a/dotnet/client-010/wcf/model/QpidChannelFactory.cs b/dotnet/client-010/wcf/model/QpidChannelFactory.cs
new file mode 100644
index 0000000000..84518cb1c3
--- /dev/null
+++ b/dotnet/client-010/wcf/model/QpidChannelFactory.cs
@@ -0,0 +1,74 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.ServiceModel;
+using System.ServiceModel.Channels;
+using org.apache.qpid.client;
+
+namespace org.apache.qpid.wcf.model
+{
+ public class QpidChannelFactory : ChannelFactoryBase<IOutputChannel>
+ {
+ private readonly BindingContext _context;
+ private readonly CommunicationOperation _openMethod;
+ private readonly QpidTransportBindingElement _bindingElement;
+ private ClientSession _session;
+
+ public QpidChannelFactory(BindingContext context)
+ {
+ _context = context;
+ _openMethod = Open;
+ _bindingElement = context.Binding.Elements.Find<QpidTransportBindingElement>();
+ }
+
+ protected override IOutputChannel OnCreateChannel(EndpointAddress address, Uri via)
+ {
+ return new QpidOutputChannel(_context, _session, address);
+ }
+
+ protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return _openMethod.BeginInvoke(timeout, callback, state);
+ }
+
+ protected override void OnEndOpen(IAsyncResult result)
+ {
+ _openMethod.EndInvoke(result);
+ }
+
+ protected override void OnOpen(TimeSpan timeout)
+ {
+ _session = _bindingElement.Open(timeout.Milliseconds);
+ }
+
+ protected override void OnClose(TimeSpan timeout)
+ {
+ _bindingElement.Close();
+ }
+
+ protected override void OnAbort()
+ {
+ base.OnAbort();
+ OnClose(_context.Binding.CloseTimeout);
+ }
+ }
+}
diff --git a/dotnet/client-010/wcf/model/QpidChannelListener.cs b/dotnet/client-010/wcf/model/QpidChannelListener.cs
new file mode 100644
index 0000000000..f776fce9a5
--- /dev/null
+++ b/dotnet/client-010/wcf/model/QpidChannelListener.cs
@@ -0,0 +1,79 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.ServiceModel;
+using System.ServiceModel.Channels;
+using org.apache.qpid.client;
+
+namespace org.apache.qpid.wcf.model
+{
+ public sealed class QpidChannelListener : QpidChannelListenerBase<IInputChannel>
+ {
+
+ private IInputChannel _channel;
+ private ClientSession _session;
+
+ public QpidChannelListener(BindingContext context)
+ : base(context)
+ {
+ _channel = null;
+ _session = null;
+ }
+
+ protected override IInputChannel OnAcceptChannel(TimeSpan timeout)
+ {
+ // Since only one connection to a broker is required (even for communication
+ // with multiple exchanges
+ if (_channel != null)
+ return null;
+
+ _channel = new QpidInputChannel(Context, _session, new EndpointAddress(Uri.ToString()));
+ _channel.Closed += ListenChannelClosed;
+ return _channel;
+ }
+
+ protected override bool OnWaitForChannel(TimeSpan timeout)
+ {
+ return false;
+ }
+
+ protected override void OnOpen(TimeSpan timeout)
+ {
+ _session = _bindingElement.Open(timeout.Milliseconds);
+ }
+
+ protected override void OnClose(TimeSpan timeout)
+ {
+ if (_channel != null)
+ {
+ _channel.Close();
+ _channel = null;
+ }
+ _bindingElement.Close();
+ }
+
+ private void ListenChannelClosed(object sender, EventArgs args)
+ {
+ Close();
+ }
+}
+}
diff --git a/dotnet/client-010/wcf/model/QpidChannelListenerBase.cs b/dotnet/client-010/wcf/model/QpidChannelListenerBase.cs
new file mode 100644
index 0000000000..bdecb38c9d
--- /dev/null
+++ b/dotnet/client-010/wcf/model/QpidChannelListenerBase.cs
@@ -0,0 +1,111 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.ServiceModel.Channels;
+using System.ServiceModel.Description;
+
+namespace org.apache.qpid.wcf.model
+{
+ public abstract class QpidChannelListenerBase<TChannel> : ChannelListenerBase<TChannel> where TChannel: class, IChannel
+ {
+ private readonly Uri _listenUri;
+ private readonly BindingContext _context;
+ protected QpidTransportBindingElement _bindingElement;
+ private readonly CommunicationOperation _closeMethod;
+ private readonly CommunicationOperation _openMethod;
+ private readonly CommunicationOperation<TChannel> _acceptChannelMethod;
+ private readonly CommunicationOperation<bool> _waitForChannelMethod;
+
+ protected QpidChannelListenerBase(BindingContext context)
+ {
+ _context = context;
+ _bindingElement = context.Binding.Elements.Find<QpidTransportBindingElement>();
+ _closeMethod = OnClose;
+ _openMethod = OnOpen;
+ _waitForChannelMethod = OnWaitForChannel;
+ _acceptChannelMethod = OnAcceptChannel;
+ if (context.ListenUriMode == ListenUriMode.Explicit && context.ListenUriBaseAddress != null)
+ {
+ _listenUri = new Uri(context.ListenUriBaseAddress, context.ListenUriRelativeAddress);
+ }
+ else
+ {
+ _listenUri = new Uri(new Uri("soap.amqp:///"), Guid.NewGuid().ToString());
+ }
+ }
+
+ protected override void OnAbort()
+ {
+ OnClose(_context.Binding.CloseTimeout);
+ }
+
+ protected override IAsyncResult OnBeginAcceptChannel(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return _acceptChannelMethod.BeginInvoke(timeout, callback, state);
+ }
+
+ protected override TChannel OnEndAcceptChannel(IAsyncResult result)
+ {
+ return _acceptChannelMethod.EndInvoke(result);
+ }
+
+ protected override IAsyncResult OnBeginWaitForChannel(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return _waitForChannelMethod.BeginInvoke(timeout, callback, state);
+ }
+
+ protected override bool OnEndWaitForChannel(IAsyncResult result)
+ {
+ return _waitForChannelMethod.EndInvoke(result);
+ }
+
+ protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return _closeMethod.BeginInvoke(timeout, callback, state);
+ }
+
+ protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return _openMethod.BeginInvoke(timeout, callback, state);
+ }
+
+ protected override void OnEndClose(IAsyncResult result)
+ {
+ _closeMethod.EndInvoke(result);
+ }
+
+ protected override void OnEndOpen(IAsyncResult result)
+ {
+ _openMethod.EndInvoke(result);
+ }
+
+ public override Uri Uri
+ {
+ get { return _listenUri; }
+ }
+
+ protected BindingContext Context
+ {
+ get { return _context; }
+ }
+ }
+}
diff --git a/dotnet/client-010/wcf/model/QpidInputChannel.cs b/dotnet/client-010/wcf/model/QpidInputChannel.cs
new file mode 100644
index 0000000000..7a05153df9
--- /dev/null
+++ b/dotnet/client-010/wcf/model/QpidInputChannel.cs
@@ -0,0 +1,218 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.ServiceModel;
+using System.ServiceModel.Channels;
+using System.Text;
+using System.Threading;
+using org.apache.qpid.client;
+using org.apache.qpid.transport;
+using org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.wcf.model
+{
+ internal sealed class QpidInputChannel : QpidInputChannelBase
+ {
+ private static readonly Logger _log = Logger.get(typeof (QpidInputChannel));
+
+ private readonly QpidTransportBindingElement _bindingElement;
+ private readonly MessageEncoder _encoder;
+ private readonly ClientSession _session;
+ private readonly string _queueName;
+ private BlockingQueue _queue;
+ private bool _closed = false;
+
+ public QpidInputChannel(BindingContext context, ClientSession session, EndpointAddress address)
+ : base(context, address)
+ {
+ _bindingElement = context.Binding.Elements.Find<QpidTransportBindingElement>();
+ var encoderElem = context.BindingParameters.Find<MessageEncodingBindingElement>();
+ if (encoderElem != null)
+ {
+ _encoder = encoderElem.CreateMessageEncoderFactory().Encoder;
+ }
+ _session = session;
+ _queueName = address.Uri.ToString();
+ _queue = new BlockingQueue();
+ }
+
+
+ public override System.ServiceModel.Channels.Message Receive(TimeSpan timeout)
+ {
+ _session.messageFlow("myDest", MessageCreditUnit.MESSAGE, 1);
+ _session.sync();
+ IMessage m = _queue.Dequeue();
+ System.ServiceModel.Channels.Message result = null;
+ if (m != null)
+ {
+ var reader = new BinaryReader(m.Body, Encoding.UTF8);
+ var body = new byte[m.Body.Length - m.Body.Position];
+ reader.Read(body, 0, body.Length);
+ try
+ {
+ result = _encoder.ReadMessage(new MemoryStream(body),
+ (int) _bindingElement.MaxReceivedMessageSize);
+ }
+ catch(Exception e)
+ {
+ Console.WriteLine(e.StackTrace);
+ }
+ result.Headers.To = LocalAddress.Uri;
+
+ var ack = new RangeSet();
+ // ack this message
+ ack.add(m.Id);
+ _session.messageAccept(ack);
+ _session.sync();
+ }
+ else
+ {
+ if(! _closed )
+ {
+ return Receive(timeout);
+ }
+ }
+ return result;
+ }
+
+ public override bool TryReceive(TimeSpan timeout, out System.ServiceModel.Channels.Message message)
+ {
+ message = Receive(timeout);
+ return message != null;
+ }
+
+ public override bool WaitForMessage(TimeSpan timeout)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void Close(TimeSpan timeout)
+ {
+ _closed = true;
+ _queue = null;
+ }
+
+ public override void Open(TimeSpan timeout)
+ {
+ if (State != CommunicationState.Created && State != CommunicationState.Closed)
+ throw new InvalidOperationException(string.Format("Cannot open the channel from the {0} state.", State));
+
+ OnOpening();
+
+ var qr = (QueueQueryResult) _session.queueQuery(_queueName).Result;
+ if (qr.getQueue() == null)
+ {
+ // create the queue
+ _session.queueDeclare(_queueName, null, null);
+ }
+ // bind the queue
+ _session.exchangeBind(_queueName, "amq.direct", _queueName, null);
+ var myListener = new WCFListener(_queue);
+ _session.attachMessageListener(myListener, "myDest");
+ _session.messageSubscribe(_queueName, "myDest", MessageAcceptMode.EXPLICIT, MessageAcquireMode.PRE_ACQUIRED,
+ null,
+ 0, null);
+ // issue credits
+ _session.messageSetFlowMode("myDest", MessageFlowMode.WINDOW);
+ _session.messageFlow("myDest", MessageCreditUnit.BYTE, ClientSession.MESSAGE_FLOW_MAX_BYTES);
+ _session.sync();
+
+ OnOpened();
+ }
+ }
+
+ internal class WCFListener : IMessageListener
+ {
+ private static readonly Logger _log = Logger.get(typeof (WCFListener));
+ private readonly BlockingQueue _q;
+
+ public WCFListener(BlockingQueue q)
+ {
+ _q = q;
+ }
+
+ public void messageTransfer(IMessage m)
+ {
+ _log.debug("message received by listener");
+ _q.Enqueue(m);
+ }
+ }
+
+ internal class BlockingQueue
+ {
+ private int _count;
+ private readonly Queue<IMessage> _queue = new Queue<IMessage>();
+
+ public IMessage Dequeue(TimeSpan timeout)
+ {
+ lock (_queue)
+ {
+ DateTime start = DateTime.Now;
+ long elapsed = 0;
+ while (_count <= 0 && elapsed < timeout.Milliseconds)
+ {
+ Monitor.Wait(_queue, new TimeSpan(timeout.Milliseconds - elapsed));
+ elapsed = DateTime.Now.Subtract(start).Milliseconds;
+ }
+ if (_count > 0)
+ {
+ _count--;
+ return _queue.Dequeue();
+ }
+ return null;
+ }
+ }
+
+ public IMessage Dequeue()
+ {
+ lock (_queue)
+ {
+ while (_count <= 0)
+ {
+ Monitor.Wait(_queue);
+ }
+ if (_count > 0)
+ {
+ _count--;
+ return _queue.Dequeue();
+ }
+ return null;
+ }
+ }
+
+ public void Enqueue(IMessage data)
+ {
+ if (data != null)
+ {
+ lock (_queue)
+ {
+ _queue.Enqueue(data);
+ _count++;
+ Monitor.Pulse(_queue);
+ }
+ }
+ }
+ }
+}
+
diff --git a/dotnet/client-010/wcf/model/QpidInputChannelBase.cs b/dotnet/client-010/wcf/model/QpidInputChannelBase.cs
new file mode 100644
index 0000000000..0bd9e85c0a
--- /dev/null
+++ b/dotnet/client-010/wcf/model/QpidInputChannelBase.cs
@@ -0,0 +1,101 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.ServiceModel;
+using System.ServiceModel.Channels;
+
+namespace org.apache.qpid.wcf.model
+{
+ internal abstract class QpidInputChannelBase : QpidChannelBase, IInputChannel
+ {
+ private readonly EndpointAddress _localAddress;
+ private readonly CommunicationOperation<Message> _receiveMethod;
+ private readonly CommunicationOperation<bool, Message> _tryReceiveMethod;
+ private readonly CommunicationOperation<bool> _waitForMessage;
+
+
+ protected QpidInputChannelBase(BindingContext context, EndpointAddress localAddress)
+ :base(context)
+ {
+ _localAddress = localAddress;
+ _receiveMethod = Receive;
+ _tryReceiveMethod = TryReceive;
+ _waitForMessage = WaitForMessage;
+ }
+
+
+ #region Async Methods
+ public virtual IAsyncResult BeginReceive(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return _receiveMethod.BeginInvoke(timeout, callback, state);
+ }
+
+ public virtual IAsyncResult BeginReceive(AsyncCallback callback, object state)
+ {
+ return _receiveMethod.BeginInvoke(Context.Binding.ReceiveTimeout, callback, state);
+ }
+
+ public virtual IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ Message message;
+ return _tryReceiveMethod.BeginInvoke(timeout, out message, callback, state);
+ }
+
+ public virtual IAsyncResult BeginWaitForMessage(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return _waitForMessage.BeginInvoke(timeout, callback, state);
+ }
+
+ public virtual Message EndReceive(IAsyncResult result)
+ {
+ return _receiveMethod.EndInvoke(result);
+ }
+
+ public virtual bool EndTryReceive(IAsyncResult result, out Message message)
+ {
+ return _tryReceiveMethod.EndInvoke(out message, result);
+ }
+
+ public virtual bool EndWaitForMessage(IAsyncResult result)
+ {
+ return _waitForMessage.EndInvoke(result);
+ }
+ #endregion
+
+ public abstract Message Receive(TimeSpan timeout);
+
+ public abstract bool TryReceive(TimeSpan timeout, out Message message);
+
+ public abstract bool WaitForMessage(TimeSpan timeout);
+
+ public virtual Message Receive()
+ {
+ return Receive(Context.Binding.ReceiveTimeout);
+ }
+
+
+ public EndpointAddress LocalAddress
+ {
+ get { return _localAddress; }
+ }
+ }
+}
diff --git a/dotnet/client-010/wcf/model/QpidOutputChannel.cs b/dotnet/client-010/wcf/model/QpidOutputChannel.cs
new file mode 100644
index 0000000000..f53ed9b9b8
--- /dev/null
+++ b/dotnet/client-010/wcf/model/QpidOutputChannel.cs
@@ -0,0 +1,89 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.IO;
+using System.ServiceModel;
+using System.ServiceModel.Channels;
+using org.apache.qpid.client;
+using org.apache.qpid.transport;
+using org.apache.qpid.transport.util;
+
+namespace org.apache.qpid.wcf.model
+{
+ internal sealed class QpidOutputChannel : QpidOutputChannelBase
+ {
+ private readonly MessageEncoder _encoder;
+ private readonly ClientSession _session;
+ private readonly string _queueName;
+
+ public QpidOutputChannel(BindingContext context, ClientSession session, EndpointAddress address)
+ : base(context, address)
+ {
+ var encoderElement = context.Binding.Elements.Find<MessageEncodingBindingElement>();
+ if (encoderElement != null)
+ {
+ _encoder = encoderElement.CreateMessageEncoderFactory().Encoder;
+ }
+ _queueName = address.Uri.ToString();
+ _session = session;
+ }
+
+ public override void Send(System.ServiceModel.Channels.Message message, TimeSpan timeout)
+ {
+ if (message.State != MessageState.Closed)
+ {
+ byte[] body;
+ using (var str = new MemoryStream())
+ {
+ _encoder.WriteMessage(message, str);
+ body = str.ToArray();
+ }
+ _session.messageTransfer("amq.direct", MessageAcceptMode.NONE, MessageAcquireMode.PRE_ACQUIRED,
+ new Header(new DeliveryProperties().setRoutingKey(_queueName),
+ new transport.MessageProperties().setMessageId(UUID.randomUUID())),
+ body);
+ }
+ }
+
+ public override void Close(TimeSpan timeout)
+ {
+ if (State == CommunicationState.Closed || State == CommunicationState.Closing)
+ return; // Ignore the call, we're already closing.
+ OnClosing();
+ OnClosed();
+ }
+
+ public override void Open(TimeSpan timeout)
+ {
+ if (State != CommunicationState.Created && State != CommunicationState.Closed)
+ throw new InvalidOperationException(string.Format("Cannot open the channel from the {0} state.", State));
+ OnOpening();
+ var qr = (QueueQueryResult) _session.queueQuery(_queueName).Result;
+ if (qr.getQueue() == null)
+ {
+ // create the queue
+ _session.queueDeclare(_queueName, null, null);
+ }
+ OnOpened();
+ }
+ }
+}
diff --git a/dotnet/client-010/wcf/model/QpidOutputChannelBase.cs b/dotnet/client-010/wcf/model/QpidOutputChannelBase.cs
new file mode 100644
index 0000000000..a3cd9020ff
--- /dev/null
+++ b/dotnet/client-010/wcf/model/QpidOutputChannelBase.cs
@@ -0,0 +1,77 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.ServiceModel;
+using System.ServiceModel.Channels;
+
+namespace org.apache.qpid.wcf.model
+{
+ internal abstract class QpidOutputChannelBase : QpidChannelBase, IOutputChannel
+ {
+
+ private readonly SendOperation _sendMethod;
+ private readonly EndpointAddress _address;
+
+ protected QpidOutputChannelBase(BindingContext context, EndpointAddress address)
+ : base(context)
+ {
+ _address = address;
+ _sendMethod = Send;
+ }
+
+ #region Async Methods
+
+ public IAsyncResult BeginSend(Message message, TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return _sendMethod.BeginInvoke(message, timeout, callback, state);
+ }
+
+ public IAsyncResult BeginSend(Message message, AsyncCallback callback, object state)
+ {
+ return _sendMethod.BeginInvoke(message, Context.Binding.SendTimeout, callback, state);
+ }
+
+ public void EndSend(IAsyncResult result)
+ {
+ _sendMethod.EndInvoke(result);
+ }
+
+ #endregion
+
+ public abstract void Send(Message message, TimeSpan timeout);
+
+ public virtual void Send(Message message)
+ {
+ Send(message, Context.Binding.SendTimeout);
+ }
+
+ public EndpointAddress RemoteAddress
+ {
+ get { return _address; }
+ }
+
+ public Uri Via
+ {
+ get { throw new NotImplementedException(); }
+ }
+ }
+}
diff --git a/dotnet/client-010/wcf/model/QpidTransportBindingElement.cs b/dotnet/client-010/wcf/model/QpidTransportBindingElement.cs
new file mode 100644
index 0000000000..50cc80422a
--- /dev/null
+++ b/dotnet/client-010/wcf/model/QpidTransportBindingElement.cs
@@ -0,0 +1,186 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.Configuration;
+using System.ServiceModel.Channels;
+using org.apache.qpid.client;
+
+namespace org.apache.qpid.wcf.model
+{
+ public sealed class QpidTransportBindingElement : TransportBindingElement
+ {
+ private Client _connection;
+ private string _host;
+ private int _port;
+ private string _username;
+ private string _password;
+ private string _virtuaHost;
+
+ /// <summary>
+ /// Creates a new instance of the QpidTransportBindingElement Class
+ /// </summary>
+ public QpidTransportBindingElement()
+ {
+ _host = "localhost";
+ _port = 5672;
+ _username = "guest";
+ _password = "guest";
+ _virtuaHost = "test";
+ }
+
+ private QpidTransportBindingElement(QpidTransportBindingElement other)
+ : this()
+ {
+ Connection = other.Connection;
+ Host = other.Host;
+ PortNumber = other.PortNumber;
+ UserName = other.UserName;
+ Password = other.Password;
+ }
+
+
+ public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
+ {
+ if (Host == null)
+ throw new InvalidOperationException("No broker was specified.");
+ return (IChannelFactory<TChannel>) new QpidChannelFactory(context);
+ }
+
+ public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
+ {
+ if (Host == null)
+ throw new InvalidOperationException("No broker was specified.");
+
+ return (IChannelListener<TChannel>) ((object) new QpidChannelListener(context));
+ }
+
+ public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
+ {
+ return typeof (TChannel) == typeof (IOutputChannel);
+ }
+
+ public override bool CanBuildChannelListener<TChannel>(BindingContext context)
+ {
+ return typeof (TChannel) == typeof (IInputChannel);
+ }
+
+ public override BindingElement Clone()
+ {
+ return new QpidTransportBindingElement(this);
+ }
+
+ public override T GetProperty<T>(BindingContext context)
+ {
+ return context.GetInnerProperty<T>();
+ }
+
+ /// <summary>
+ /// Gets the scheme used by the binding, this is 0.10 as default for now.
+ /// </summary>
+ public override string Scheme
+ {
+ get { return "soap.amqp"; }
+ }
+
+
+ /// <summary>
+ /// Specifies the broker host
+ /// </summary>
+ [ConfigurationProperty("host")]
+ public string Host
+ {
+ get { return _host; }
+ set { _host = value; }
+ }
+
+ /// <summary>
+ /// Specifies the broker port
+ /// </summary>
+ public int PortNumber
+ {
+ get { return _port; }
+ set { _port = value; }
+ }
+
+ /// <summary>
+ /// Specifies the username
+ /// </summary>
+ public string UserName
+ {
+ get { return _username; }
+ set { _username = value; }
+ }
+
+ /// <summary>
+ /// Specifies the password
+ /// </summary>
+ public string Password
+ {
+ get { return _password; }
+ set { _password = value; }
+ }
+
+ /// <summary>
+ /// Specifies the virtualhost
+ /// </summary>
+ public string VirtualHost
+ {
+ get { return _virtuaHost; }
+ set { _virtuaHost = value; }
+ }
+
+ /// <summary>
+ /// Specifies the connection
+ /// </summary>
+ public Client Connection
+ {
+ get { return _connection; }
+ set { _connection = value; }
+ }
+
+
+ internal ClientSession Open(long timeout)
+ {
+ if (Connection == null)
+ {
+ Connection = new Client();
+ }
+ Connection.connect(Host, PortNumber, VirtualHost, UserName, Password);
+ return Connection.createSession(timeout);
+ }
+
+ internal void Close()
+ {
+ if (Connection != null)
+ {
+ try
+ {
+ Connection.close();
+ }
+ catch (Exception e)
+ {
+ // todo log it
+ }
+ }
+ }
+ }
+}
diff --git a/dotnet/client-010/wcf/model/QpidTransportElement.cs b/dotnet/client-010/wcf/model/QpidTransportElement.cs
new file mode 100644
index 0000000000..f531186148
--- /dev/null
+++ b/dotnet/client-010/wcf/model/QpidTransportElement.cs
@@ -0,0 +1,183 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+using System;
+using System.Configuration;
+using System.Reflection;
+using System.ServiceModel.Channels;
+using System.ServiceModel.Configuration;
+
+namespace org.apache.qpid.wcf.model
+{
+ public sealed class QpidTransportElement : TransportElement
+ {
+
+ public override void ApplyConfiguration(BindingElement bindingElement)
+ {
+ base.ApplyConfiguration(bindingElement);
+ if (bindingElement == null)
+ throw new ArgumentNullException("bindingElement");
+
+ var bindind = bindingElement as QpidTransportBindingElement;
+ if (bindind == null)
+ {
+ throw new ArgumentException(
+ string.Format("Invalid type for binding. Expected {0}, Passed: {1}",
+ typeof(QpidTransportBindingElement).AssemblyQualifiedName,
+ bindingElement.GetType().AssemblyQualifiedName));
+ }
+
+ bindind.Host = Host;
+ bindind.Password = Password;
+ bindind.UserName = UserName;
+ bindind.VirtualHost = VirtualHost;
+ bindind.PortNumber = PortNumber;
+ }
+
+ public override void CopyFrom(ServiceModelExtensionElement from)
+ {
+ base.CopyFrom(from);
+ var element = from as QpidTransportElement;
+ if (element != null)
+ {
+ Host = element.Host;
+ PortNumber = element.PortNumber;
+ Password = element.Password;
+ UserName = element.UserName;
+ VirtualHost = element.VirtualHost;
+ }
+ }
+
+ protected override BindingElement CreateBindingElement()
+ {
+ TransportBindingElement element = CreateDefaultBindingElement();
+ ApplyConfiguration(element);
+ return element;
+ }
+
+ protected override TransportBindingElement CreateDefaultBindingElement()
+ {
+ return new QpidTransportBindingElement();
+ }
+
+ protected override void InitializeFrom(BindingElement bindingElement)
+ {
+ base.InitializeFrom(bindingElement);
+
+ if (bindingElement == null)
+ throw new ArgumentNullException("bindingElement");
+
+ var binding = bindingElement as QpidTransportBindingElement;
+ if (binding == null)
+ {
+ throw new ArgumentException(
+ string.Format("Invalid type for binding. Expected {0}, Passed: {1}",
+ typeof(QpidTransportBindingElement).AssemblyQualifiedName,
+ bindingElement.GetType().AssemblyQualifiedName));
+ }
+
+ Host = binding.Host;
+ PortNumber = binding.PortNumber;
+ Password = binding.Password;
+ UserName = binding.UserName;
+ VirtualHost = binding.VirtualHost;
+ }
+
+ public override Type BindingElementType
+ {
+ get { return typeof(QpidTransportElement); }
+ }
+
+
+
+ /// <summary>
+ /// Specifies the broker host name that the binding should connect to.
+ /// </summary>
+ [ConfigurationProperty("host", DefaultValue = "localhost")]
+ public string Host
+ {
+ get { return ((string) base["host"]); }
+ set { base["host"] = value; }
+ }
+
+ /// <summary>
+ /// Specifies the broker port number that the binding should connect to.
+ /// </summary>
+ [ConfigurationProperty("port", DefaultValue = "5672")]
+ public int PortNumber
+ {
+ get { return (Convert.ToInt16(base["port"])); }
+ set { base["port"] = value; }
+ }
+
+ /// <summary>
+ /// Password to use when authenticating with the broker
+ /// </summary>
+ [ConfigurationProperty("password", DefaultValue = "guest")]
+ public string Password
+ {
+ get { return ((string)base["password"]); }
+ set { base["password"] = value; }
+ }
+
+ /// <summary>
+ /// The username to use when authenticating with the broker
+ /// </summary>
+ [ConfigurationProperty("username", DefaultValue = "guest")]
+ public string UserName
+ {
+ get { return ((string)base["username"]); }
+ set { base["username"] = value; }
+ }
+
+
+ /// <summary>
+ /// The virtual host to access.
+ /// </summary>
+ [ConfigurationProperty("virtualHost", DefaultValue = "test")]
+ public string VirtualHost
+ {
+ get { return ((string)base["virtualHost"]); }
+ set { base["virtualHost"] = value; }
+ }
+
+
+ protected override ConfigurationPropertyCollection Properties
+ {
+ get
+ {
+ ConfigurationPropertyCollection configProperties = base.Properties;
+ foreach (PropertyInfo prop in GetType().GetProperties(BindingFlags.DeclaredOnly
+ | BindingFlags.Public
+ | BindingFlags.Instance))
+ {
+ foreach (ConfigurationPropertyAttribute attr in prop.GetCustomAttributes(typeof(ConfigurationPropertyAttribute), false))
+ {
+ configProperties.Add(
+ new ConfigurationProperty(attr.Name, prop.PropertyType, attr.DefaultValue));
+ }
+ }
+
+ return configProperties;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/dotnet/client-010/wcf/wcf.csproj b/dotnet/client-010/wcf/wcf.csproj
new file mode 100644
index 0000000000..d04fefbfc2
--- /dev/null
+++ b/dotnet/client-010/wcf/wcf.csproj
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{F1D80D9D-FE22-4213-A760-BFFDE7D131DD}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>WCF</RootNamespace>
+ <AssemblyName>qpidWCFModel</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Qpid Client, Version=0.10.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\client\bin\Debug\Qpid Client.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.configuration" />
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Windows.Forms" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="model\*.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/dotnet/client-010/wcf/wcf.sln b/dotnet/client-010/wcf/wcf.sln
new file mode 100644
index 0000000000..f65368bd66
--- /dev/null
+++ b/dotnet/client-010/wcf/wcf.sln
@@ -0,0 +1,50 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "wcfHelloClient", "demo\wcfHelloClient\wcfHelloClient.csproj", "{A24E27DB-A38D-40C9-9879-8390B68C2F06}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "wcfHelloServer", "demo\wcfHelloServer\wcfHelloServer.csproj", "{3EF848D7-5FAC-482C-922A-D4D45A4CCD2A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "wcfRPC", "demo\wcfRPC\wcfRPC.csproj", "{C988F456-1025-486F-9BCD-49C0F83B91DB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "wcBookingClient", "demo\wcfBookingClient\wcBookingClient.csproj", "{4086B3FE-F745-4DCC-952A-682CAE01F4C9}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "wcfBookingServer", "demo\wcfBookingServer\wcfBookingServer.csproj", "{B34E21C4-A742-4886-8569-1A89490E093E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "wcf", "wcf.csproj", "{F1D80D9D-FE22-4213-A760-BFFDE7D131DD}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A24E27DB-A38D-40C9-9879-8390B68C2F06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A24E27DB-A38D-40C9-9879-8390B68C2F06}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A24E27DB-A38D-40C9-9879-8390B68C2F06}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A24E27DB-A38D-40C9-9879-8390B68C2F06}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3EF848D7-5FAC-482C-922A-D4D45A4CCD2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3EF848D7-5FAC-482C-922A-D4D45A4CCD2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3EF848D7-5FAC-482C-922A-D4D45A4CCD2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3EF848D7-5FAC-482C-922A-D4D45A4CCD2A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C988F456-1025-486F-9BCD-49C0F83B91DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C988F456-1025-486F-9BCD-49C0F83B91DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C988F456-1025-486F-9BCD-49C0F83B91DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C988F456-1025-486F-9BCD-49C0F83B91DB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4086B3FE-F745-4DCC-952A-682CAE01F4C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4086B3FE-F745-4DCC-952A-682CAE01F4C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4086B3FE-F745-4DCC-952A-682CAE01F4C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4086B3FE-F745-4DCC-952A-682CAE01F4C9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B34E21C4-A742-4886-8569-1A89490E093E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B34E21C4-A742-4886-8569-1A89490E093E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B34E21C4-A742-4886-8569-1A89490E093E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B34E21C4-A742-4886-8569-1A89490E093E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F1D80D9D-FE22-4213-A760-BFFDE7D131DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F1D80D9D-FE22-4213-A760-BFFDE7D131DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F1D80D9D-FE22-4213-A760-BFFDE7D131DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F1D80D9D-FE22-4213-A760-BFFDE7D131DD}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/dotnet/client-010/wcf/wcf.suo b/dotnet/client-010/wcf/wcf.suo
new file mode 100644
index 0000000000..60339d33e4
--- /dev/null
+++ b/dotnet/client-010/wcf/wcf.suo
Binary files differ
diff --git a/dotnet/default.build b/dotnet/default.build
index 52a67ff638..bfd6ada094 100644
--- a/dotnet/default.build
+++ b/dotnet/default.build
@@ -1,230 +1,252 @@
-<?xml version="1.0"?>
-<project name="Qpid.NET" default="build">
-
- <!-- Determines the formatter to use to format output of test results. -->
- <property name="nant.formatter" value="Plain" />
-
- <!-- Determines whether a 'debug' or 'release' build is to be done. Defaults to 'debug' -->
- <property name="build.config" value="debug" />
-
- <!-- Sets build properties consistently accross all assemblies in the project. -->
- <property name="build.version.major" value="2"/>
- <property name="build.version.minor" value="1"/>
- <property name="build.version.build" value="0"/>
- <property name="build.version.revision" value="0"/>
- <property name="build.company" value="Apache Software Foundation"/>
- <property name="build.copyright" value="Apache Software Foundation"/>
- <property name="build.description" value="Built from svn revision number: "/>
-
- <!-- Fileset with build files for each 'core' assembly. -->
- <fileset id="src.builds">
- <include name="Qpid.Buffer/default.build" />
- <include name="Qpid.Sasl/default.build" />
- <include name="Qpid.Messaging/default.build" />
- <include name="Qpid.Codec/default.build" />
- <include name="Qpid.Common/default.build" />
- <include name="Qpid.Client/default.build" />
- </fileset>
-
- <!-- Fileset with build files for 'pure unit' test assemblies. -->
- <fileset id="tests.pure.builds">
- <include name="Qpid.Buffer.Tests/default.build" />
- <include name="Qpid.Sasl.Tests/default.build" />
- <include name="Qpid.Common.Tests/default.build" />
- <include name="Qpid.Client.Tests/default.build" />
- </fileset>
-
- <!-- Fileset with build files for 'integration' test assemblies. -->
- <fileset id="tests.integration.builds">
- <include name="Qpid.Integration.Tests/default.build" />
- </fileset>
-
- <!-- Other test or utility assemblies. -->
- <fileset id='other.builds'>
- <include name="TopicListener/default.build" />
- <include name="TopicPublisher/default.build" />
- <include name="TestClient/default.build" />
- </fileset>
-
- <!-- Prepare environment for a debug build. -->
- <target name="debug">
- <property name="build.debug" value="true" />
- <property name="build.defines" value="DEBUG;TRACE"/>
- </target>
-
- <!-- Prepare environment for a release build. -->
- <target name="release">
- <property name="build.debug" value="false" />
- <property name="build.defines" value=""/>
- </target>
-
- <!-- Prepare environment for build. -->
- <target name="init">
- <property name="base.dir" value="${project::get-base-directory()}" />
- <property name="build.dir" value="${base.dir}/bin/${framework::get-target-framework()}/${build.config}" />
- <call target="${build.config}" />
- </target>
-
- <!-- Cleans up the build output directory. -->
- <target name="clean" depends="init">
- <delete dir="${build.dir}" failonerror="false" />
- </target>
-
- <!-- Runs 'svnversion' to get the repository revision into the build property 'build.svnversion'. -->
- <target name="svnversion" description="Runs svnversion to get the current repository version into a build script property.">
- <exec program="svnversion" output="svnversion_tmp.txt">
- <arg value="-n"/>
- </exec>
-
- <loadfile file="svnversion_tmp.txt" property="build.svnversion"/>
- <delete file="svnversion_tmp.txt"/>
-
- <!-- For some competely retarted reason the '-n' parameter to svnversion doesn't really work under windows...
- Here is some code to strip the unwanted newlines. -->
- <script language="C#">
- <code><![CDATA[
- public static void ScriptMain(Project project)
- {
- project.Properties["build.svnversion"] = project.Properties["build.svnversion"].Trim("\n\r".ToCharArray());
- }
- ]]>
- </code>
- </script>
-
- </target>
-
- <!-- Performs a regex find-and-replace on assembly info files, substituting fields defined as build properties. -->
- <target name="setversion" description="Stamp the version info onto assemblyinfo.cs files" depends="svnversion">
-
- <echo>build.svnversion = ${build.svnversion}</echo>
-
- <foreach item="File" property="filename">
- <in>
- <items basedir=".">
- <include name="**\AssemblyInfo.cs"></include>
- </items>
- </in>
- <do>
- <script language="C#">
- <code><![CDATA[
- public static void ScriptMain(Project project)
- {
- // Read in the entire file to perform the substitution in.
- StreamReader reader = new StreamReader(project.Properties["filename"]);
- string contents = reader.ReadToEnd();
- reader.Close();
-
- // Substitute the version numbers.
- string replacement = string.Format("[assembly: AssemblyVersion(\"{0}.{1}.{2}.{3}\")]",
- project.Properties["build.version.major"],
- project.Properties["build.version.minor"],
- project.Properties["build.version.build"],
- project.Properties["build.version.revision"]);
- contents = Regex.Replace(contents, @"\[assembly: AssemblyVersion\("".*""\)\]", replacement);
-
- // Substitute the company name and copyright.
- replacement = string.Format("[assembly: AssemblyCompany(\"{0}\")]",
- project.Properties["build.company"]);
- contents = Regex.Replace(contents, @"\[assembly: AssemblyCompany\("".*""\)\]", replacement);
-
- replacement = string.Format("[assembly: AssemblyCopyright(\"{0}\")]",
- project.Properties["build.copyright"]);
- contents = Regex.Replace(contents, @"\[assembly: AssemblyCopyright\("".*""\)\]", replacement);
-
- // Update the description.
- //replacement = string.Format("[assembly: AssemblyDescription(\"{0} {1}\")]",
- // project.Properties["build.description"],
- // project.Properties["build.svnversion"]);
- replacement = string.Format("[assembly: AssemblyDescription(\"{0}\")]",
- project.Properties["build.description"]);
- contents = Regex.Replace(contents, @"\[assembly: AssemblyDescription\("".*""\)\]", replacement);
-
- // Write out the file with the substituted version.
- StreamWriter writer = new StreamWriter(project.Properties["filename"], false);
- writer.Write(contents);
- writer.Close();
- }
- ]]>
- </code>
- </script>
- </do>
- </foreach>
- </target>
-
- <!-- Do the build. -->
- <target name="build" depends="init, setversion">
- <echo message="Building all modules including tests."/>
-
- <!-- Make sure output folder exists. -->
- <mkdir dir="${build.dir}" />
-
- <!-- copy reference assemblies over to the output dir -->
- <copy todir="${build.dir}" file="Qpid.Common/lib/seclib-1.0.0/Org.Mentalis.Security.dll"/>
- <copy todir="${build.dir}" file="Qpid.Common/lib/log4net/log4net.dll"/>
- <copy todir="${build.dir}" file="Qpid.Client.Tests/lib/nunit/nunit.framework.dll"/>
-
- <!-- Compile assemblies. -->
- <nant target="build">
- <buildfiles refid="src.builds" />
- </nant>
-
- <!-- Compile test assemblies. -->
- <nant target="build">
- <buildfiles refid="tests.pure.builds" />
- </nant>
- <nant target="build">
- <buildfiles refid="tests.integration.builds" />
- </nant>
-
- <!-- Compile test assemblies. -->
- <nant target="build">
- <buildfiles refid="other.builds" />
- </nant>
- </target>
-
- <!-- Runs all 'pure unit' tests. -->
- <target name="test" depends="build">
- <echo message="Running all pure unit tests."/>
- <nant target="test">
- <buildfiles refid="tests.pure.builds" />
- </nant>
- </target>
-
- <!-- Runs all 'integration' tests. -->
- <target name="integrationtest" depends="build">
- <echo message="Running all integration tests."/>
- <nant target="test">
- <buildfiles refid="tests.integration.builds" />
- </nant>
- </target>
-
- <!-- Creates a release package. -->
- <target name="release-pkg">
- <echo message="Building and packaging a release."/>
-
- <call target="clean"/>
- <call target="build"/>
-
- <property name="build.date" value="${datetime::now()}"/>
-
- <zip zipfile="${build.dir}/Qpid.NET-${framework::get-target-framework()}-${datetime::get-year(build.date)}${datetime::get-month(build.date)}${datetime::get-day(build.date)}.zip">
- <fileset basedir="${build.dir}">
- <include name="**/*.*"/>
- <exclude name="**/*.Tests.*"/>
- <exclude name="**/nunit.framework.dll"/>
- <exclude name="**/*.exe"/>
- </fileset>
-
- <fileset basedir="${base.dir}">
- <include name="LICENSE.txt"/>
- <include name="NOTICE.txt"/>
- <include name="README.txt"/>
- <include name="RELEASE_NOTES.txt"/>
- <include name="DISCLAIMER"/>
- </fileset>
- </zip>
- </target>
-
-</project>
-
-
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<project name="Qpid.NET" default="build">
+
+ <!-- Determines the formatter to use to format output of test results. -->
+ <property name="nant.formatter" value="Plain" />
+
+ <!-- Determines whether a 'debug' or 'release' build is to be done. Defaults to 'debug' -->
+ <property name="build.config" value="debug" />
+
+ <!-- Sets build properties consistently accross all assemblies in the project. -->
+ <property name="build.version.major" value="0"/>
+ <property name="build.version.minor" value="5"/>
+ <property name="build.version.build" value="0"/>
+ <property name="build.version.revision" value="0"/>
+ <property name="build.company" value="Apache Software Foundation"/>
+ <property name="build.copyright" value="Apache Software Foundation"/>
+ <property name="build.description" value="Built from svn revision number: "/>
+
+ <!-- Fileset with build files for each 'core' assembly. -->
+ <fileset id="src.builds">
+ <include name="Qpid.Buffer/default.build" />
+ <include name="Qpid.Sasl/default.build" />
+ <include name="Qpid.Messaging/default.build" />
+ <include name="Qpid.Codec/default.build" />
+ <include name="Qpid.Common/default.build" />
+ <include name="Qpid.Client/default.build" />
+ </fileset>
+
+ <!-- Fileset with build files for 'pure unit' test assemblies. -->
+ <fileset id="tests.pure.builds">
+ <include name="Qpid.Buffer.Tests/default.build" />
+ <include name="Qpid.Sasl.Tests/default.build" />
+ <include name="Qpid.Common.Tests/default.build" />
+ <include name="Qpid.Client.Tests/default.build" />
+ </fileset>
+
+ <!-- Fileset with build files for 'integration' test assemblies. -->
+ <fileset id="tests.integration.builds">
+ <include name="Qpid.Integration.Tests/default.build" />
+ </fileset>
+
+ <!-- Other test or utility assemblies. -->
+ <fileset id='other.builds'>
+ <include name="TopicListener/default.build" />
+ <include name="TopicPublisher/default.build" />
+ <include name="TestClient/default.build" />
+ </fileset>
+
+ <!-- Prepare environment for a debug build. -->
+ <target name="debug">
+ <property name="build.debug" value="true" />
+ <property name="build.defines" value="DEBUG;TRACE"/>
+ </target>
+
+ <!-- Prepare environment for a release build. -->
+ <target name="release">
+ <property name="build.debug" value="false" />
+ <property name="build.defines" value=""/>
+ </target>
+
+ <!-- Prepare environment for build. -->
+ <target name="init">
+ <property name="base.dir" value="${project::get-base-directory()}" />
+ <property name="build.dir" value="${base.dir}/bin/${framework::get-target-framework()}/${build.config}" />
+ <call target="${build.config}" />
+ </target>
+
+ <!-- Cleans up the build output directory. -->
+ <target name="clean" depends="init">
+ <delete dir="${build.dir}" failonerror="false" />
+ </target>
+
+ <!-- Runs 'svnversion' to get the repository revision into the build property 'build.svnversion'. -->
+ <target name="svnversion" description="Runs svnversion to get the current repository version into a build script property.">
+ <exec program="svnversion" output="svnversion_tmp.txt">
+ <arg value="-n"/>
+ </exec>
+
+ <loadfile file="svnversion_tmp.txt" property="build.svnversion"/>
+ <delete file="svnversion_tmp.txt"/>
+
+ <!-- For some competely retarted reason the '-n' parameter to svnversion doesn't really work under windows...
+ Here is some code to strip the unwanted newlines. -->
+ <script language="C#">
+ <code><![CDATA[
+ public static void ScriptMain(Project project)
+ {
+ project.Properties["build.svnversion"] = project.Properties["build.svnversion"].Trim("\n\r".ToCharArray());
+ }
+ ]]>
+ </code>
+ </script>
+
+ </target>
+
+ <!-- Performs a regex find-and-replace on assembly info files, substituting fields defined as build properties. -->
+ <target name="setversion" description="Stamp the version info onto assemblyinfo.cs files" depends="svnversion">
+
+ <echo>build.svnversion = ${build.svnversion}</echo>
+
+ <foreach item="File" property="filename">
+ <in>
+ <items basedir=".">
+ <include name="**\AssemblyInfo.cs"></include>
+ </items>
+ </in>
+ <do>
+ <script language="C#">
+ <code><![CDATA[
+ public static void ScriptMain(Project project)
+ {
+ // Read in the entire file to perform the substitution in.
+ StreamReader reader = new StreamReader(project.Properties["filename"]);
+ string contents = reader.ReadToEnd();
+ reader.Close();
+
+ // Substitute the version numbers.
+ string replacement = string.Format("[assembly: AssemblyVersion(\"{0}.{1}.{2}.{3}\")]",
+ project.Properties["build.version.major"],
+ project.Properties["build.version.minor"],
+ project.Properties["build.version.build"],
+ project.Properties["build.version.revision"]);
+ contents = Regex.Replace(contents, @"\[assembly: AssemblyVersion\("".*""\)\]", replacement);
+
+ // Substitute the company name and copyright.
+ replacement = string.Format("[assembly: AssemblyCompany(\"{0}\")]",
+ project.Properties["build.company"]);
+ contents = Regex.Replace(contents, @"\[assembly: AssemblyCompany\("".*""\)\]", replacement);
+
+ replacement = string.Format("[assembly: AssemblyCopyright(\"{0}\")]",
+ project.Properties["build.copyright"]);
+ contents = Regex.Replace(contents, @"\[assembly: AssemblyCopyright\("".*""\)\]", replacement);
+
+ // Update the description.
+ //replacement = string.Format("[assembly: AssemblyDescription(\"{0} {1}\")]",
+ // project.Properties["build.description"],
+ // project.Properties["build.svnversion"]);
+ replacement = string.Format("[assembly: AssemblyDescription(\"{0}\")]",
+ project.Properties["build.description"]);
+ contents = Regex.Replace(contents, @"\[assembly: AssemblyDescription\("".*""\)\]", replacement);
+
+ // Write out the file with the substituted version.
+ StreamWriter writer = new StreamWriter(project.Properties["filename"], false);
+ writer.Write(contents);
+ writer.Close();
+ }
+ ]]>
+ </code>
+ </script>
+ </do>
+ </foreach>
+ </target>
+
+ <!-- Do the build. -->
+ <target name="build" depends="init, setversion">
+ <echo message="Building all modules including tests."/>
+
+ <!-- Make sure output folder exists. -->
+ <mkdir dir="${build.dir}" />
+
+ <!-- copy reference assemblies over to the output dir -->
+ <copy todir="${build.dir}" file="Qpid.Common/lib/seclib-1.0.0/Org.Mentalis.Security.dll"/>
+ <copy todir="${build.dir}" file="Qpid.Common/lib/log4net/log4net.dll"/>
+ <copy todir="${build.dir}" file="Qpid.Client.Tests/lib/nunit/nunit.framework.dll"/>
+
+ <!-- Compile assemblies. -->
+ <nant target="build">
+ <buildfiles refid="src.builds" />
+ </nant>
+
+ <!-- Compile test assemblies. -->
+ <nant target="build">
+ <buildfiles refid="tests.pure.builds" />
+ </nant>
+ <nant target="build">
+ <buildfiles refid="tests.integration.builds" />
+ </nant>
+
+ <!-- Compile test assemblies. -->
+ <nant target="build">
+ <buildfiles refid="other.builds" />
+ </nant>
+ </target>
+
+ <!-- Runs all 'pure unit' tests. -->
+ <target name="test" depends="build">
+ <echo message="Running all pure unit tests."/>
+ <nant target="test">
+ <buildfiles refid="tests.pure.builds" />
+ </nant>
+ </target>
+
+ <!-- Runs all 'integration' tests. -->
+ <target name="integrationtest" depends="build">
+ <echo message="Running all integration tests."/>
+ <nant target="test">
+ <buildfiles refid="tests.integration.builds" />
+ </nant>
+ </target>
+
+ <!-- Creates a release package. -->
+ <target name="release-pkg">
+ <echo message="Building and packaging a release."/>
+
+ <call target="clean"/>
+ <call target="build"/>
+
+ <property name="build.date" value="${datetime::now()}"/>
+ <property name="build.timestamp" value="${framework::get-target-framework()}-${datetime::get-year(build.date)}${datetime::get-month(build.date)}${datetime::get-day(build.date)}"/>
+
+ <zip zipfile="${build.dir}/Qpid.NET-${build.timestamp}.zip">
+ <fileset basedir="${build.dir}" prefix="Qpid.NET-${build.timestamp}">
+ <include name="**/*.*"/>
+ <exclude name="**/*.Tests.*"/>
+ <exclude name="**/nunit.framework.dll"/>
+ <exclude name="**/*.exe"/>
+ </fileset>
+
+ <fileset basedir="${base.dir}" prefix="Qpid.NET-${build.timestamp}">
+ <include name="LICENSE.txt"/>
+ <include name="NOTICE.txt"/>
+ <include name="README.txt"/>
+ <include name="RELEASE_NOTES.txt"/>
+ <include name="DISCLAIMER"/>
+ </fileset>
+ </zip>
+ </target>
+
+</project>
+
+
diff --git a/dotnet/release b/dotnet/release
deleted file mode 100755
index 11291e87d6..0000000000
--- a/dotnet/release
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-Usage()
-{
- echo "usage: $0 net-1.1|net-2.0|mono-2.0"
- exit 2
-}
-
-if [[ $# -ne 1 ]]; then
- Usage
-fi
-
-nant -t:$1 release-pkg -D:build.config=release
diff --git a/etc/LICENSE b/etc/LICENSE
new file mode 100644
index 0000000000..bc46b77047
--- /dev/null
+++ b/etc/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/etc/NOTICE b/etc/NOTICE
new file mode 100644
index 0000000000..05f39ba176
--- /dev/null
+++ b/etc/NOTICE
@@ -0,0 +1,8 @@
+// ------------------------------------------------------------------
+// NOTICE file corresponding to the section 4d of The Apache License,
+// Version 2.0, in this case for Qpid bin scripts
+// ------------------------------------------------------------------
+
+Apache Qpid
+Copyright 2006-2008 Apache Software Foundation
+
diff --git a/extras/sasl/LICENSE b/extras/sasl/LICENSE
new file mode 100644
index 0000000000..cff2a5e25d
--- /dev/null
+++ b/extras/sasl/LICENSE
@@ -0,0 +1,234 @@
+=========================================================================
+== 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.
+
+=========================================================================
+== Boost License ==
+=========================================================================
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
diff --git a/extras/sasl/Makefile.am b/extras/sasl/Makefile.am
new file mode 100644
index 0000000000..efa6d4f2d3
--- /dev/null
+++ b/extras/sasl/Makefile.am
@@ -0,0 +1,30 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+LIBTOOL_DEPS = @LIBTOOL_DEPS@
+
+AUTOMAKE_OPTIONS = 1.9.2 foreign
+ACLOCAL_AMFLAGS = -I m4
+
+EXTRA_DIST = LICENSE
+SUBDIRS = src python ruby
+
+# Update libtool, if needed.
+libtool: $(LIBTOOL_DEPS)
+ $(SHELL) ./config.status --recheck
diff --git a/extras/sasl/bootstrap b/extras/sasl/bootstrap
new file mode 100755
index 0000000000..dfd5b7db1f
--- /dev/null
+++ b/extras/sasl/bootstrap
@@ -0,0 +1,15 @@
+#!/bin/sh
+set -e
+aclocal -I m4
+autoheader
+libtoolize --automake
+
+automake
+autoconf
+
+if [ "$1" = "-build" -o "$1" = "--build" ] ; then
+ shift
+ ./configure "$@"
+ make
+ make check
+fi
diff --git a/extras/sasl/build-aux/compile b/extras/sasl/build-aux/compile
new file mode 100755
index 0000000000..1b1d232169
--- /dev/null
+++ b/extras/sasl/build-aux/compile
@@ -0,0 +1,142 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand `-c -o'.
+
+scriptversion=2005-05-14.22
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand `-c -o'.
+Remove `-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file `INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "compile $scriptversion"
+ exit $?
+ ;;
+esac
+
+ofile=
+cfile=
+eat=
+
+for arg
+do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as `compile cc -o foo foo.c'.
+ # So we strip `-o arg' only if arg is an object.
+ eat=1
+ case $2 in
+ *.o | *.obj)
+ ofile=$2
+ ;;
+ *)
+ set x "$@" -o "$2"
+ shift
+ ;;
+ esac
+ ;;
+ *.c)
+ cfile=$1
+ set x "$@" "$1"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+ # If no `-o' option was seen then we might have been invoked from a
+ # pattern rule where we don't need one. That is ok -- this is a
+ # normal compilation that the losing compiler can handle. If no
+ # `.c' file was seen then we are probably linking. That is also
+ # ok.
+ exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use `[/.-]' here to ensure that we don't use the same name
+# that we are using for the .o file. Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d
+while true; do
+ if mkdir "$lockdir" >/dev/null 2>&1; then
+ break
+ fi
+ sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+ mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+ mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/extras/sasl/build-aux/config.guess b/extras/sasl/build-aux/config.guess
new file mode 100755
index 0000000000..c93201a4d2
--- /dev/null
+++ b/extras/sasl/build-aux/config.guess
@@ -0,0 +1,1501 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
+# Inc.
+
+timestamp='2006-11-08'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ *:SolidBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm:riscos:*:*|arm:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[45])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep __LP64__ >/dev/null
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ case ${UNAME_MACHINE} in
+ pc98)
+ echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ amd64)
+ echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ *)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ esac
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ x86:Interix*:[3456]*)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+ EM64T:Interix*:[3456]* | authenticamd:Interix*:[3456]*)
+ echo x86_64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ arm*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ avr32*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ cris:Linux:*:*)
+ echo cris-axis-linux-gnu
+ exit ;;
+ crisv32:Linux:*:*)
+ echo crisv32-axis-linux-gnu
+ exit ;;
+ frv:Linux:*:*)
+ echo frv-unknown-linux-gnu
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ mips:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips
+ #undef mipsel
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mipsel
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+ /^CPU/{
+ s: ::g
+ p
+ }'`"
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips64
+ #undef mips64el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mips64el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips64
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+ /^CPU/{
+ s: ::g
+ p
+ }'`"
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ or32:Linux:*:*)
+ echo or32-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ vax:Linux:*:*)
+ echo ${UNAME_MACHINE}-dec-linux-gnu
+ exit ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit ;;
+ i*86:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ # Set LC_ALL=C to ensure ld outputs messages in English.
+ ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported targets: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ ;;
+ a.out-i386-linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit ;;
+ coff-i386)
+ echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+ exit ;;
+ "")
+ # Either a pre-BFD a.out linker (linux-gnuoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+ exit ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #ifdef __ELF__
+ # ifdef __GLIBC__
+ # if __GLIBC__ >= 2
+ LIBC=gnu
+ # else
+ LIBC=gnulibc1
+ # endif
+ # else
+ LIBC=gnulibc1
+ # endif
+ #else
+ #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+ LIBC=gnu
+ #else
+ LIBC=gnuaout
+ #endif
+ #endif
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+ /^LIBC/{
+ s: ::g
+ p
+ }'`"
+ test x"${LIBC}" != x && {
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+ exit
+ }
+ test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
+ ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ case $UNAME_PROCESSOR in
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NSE-?:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+ i*86:rdos:*:*)
+ echo ${UNAME_MACHINE}-pc-rdos
+ exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ c34*)
+ echo c34-convex-bsd
+ exit ;;
+ c38*)
+ echo c38-convex-bsd
+ exit ;;
+ c4*)
+ echo c4-convex-bsd
+ exit ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
+and
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/extras/sasl/build-aux/config.rpath b/extras/sasl/build-aux/config.rpath
new file mode 100755
index 0000000000..c492a93b66
--- /dev/null
+++ b/extras/sasl/build-aux/config.rpath
@@ -0,0 +1,614 @@
+#! /bin/sh
+# Output a system dependent set of variables, describing how to set the
+# run time search path of shared libraries in an executable.
+#
+# Copyright 1996-2006 Free Software Foundation, Inc.
+# Taken from GNU libtool, 2001
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# The first argument passed to this file is the canonical host specification,
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld
+# should be set by the caller.
+#
+# The set of defined variables is at the end of this script.
+
+# Known limitations:
+# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer
+# than 256 bytes, otherwise the compiler driver will dump core. The only
+# known workaround is to choose shorter directory names for the build
+# directory and/or the installation directory.
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+shrext=.so
+
+host="$1"
+host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+# Code taken from libtool.m4's _LT_CC_BASENAME.
+
+for cc_temp in $CC""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'`
+
+# Code taken from libtool.m4's AC_LIBTOOL_PROG_COMPILER_PIC.
+
+wl=
+if test "$GCC" = yes; then
+ wl='-Wl,'
+else
+ case "$host_os" in
+ aix*)
+ wl='-Wl,'
+ ;;
+ darwin*)
+ case $cc_basename in
+ xlc*)
+ wl='-Wl,'
+ ;;
+ esac
+ ;;
+ mingw* | pw32* | os2*)
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ wl='-Wl,'
+ ;;
+ irix5* | irix6* | nonstopux*)
+ wl='-Wl,'
+ ;;
+ newsos6)
+ ;;
+ linux*)
+ case $cc_basename in
+ icc* | ecc*)
+ wl='-Wl,'
+ ;;
+ pgcc | pgf77 | pgf90)
+ wl='-Wl,'
+ ;;
+ ccc*)
+ wl='-Wl,'
+ ;;
+ como)
+ wl='-lopt='
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ wl='-Wl,'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ osf3* | osf4* | osf5*)
+ wl='-Wl,'
+ ;;
+ sco3.2v5*)
+ ;;
+ solaris*)
+ wl='-Wl,'
+ ;;
+ sunos4*)
+ wl='-Qoption ld '
+ ;;
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ wl='-Wl,'
+ ;;
+ sysv4*MP*)
+ ;;
+ unicos*)
+ wl='-Wl,'
+ ;;
+ uts4*)
+ ;;
+ esac
+fi
+
+# Code taken from libtool.m4's AC_LIBTOOL_PROG_LD_SHLIBS.
+
+hardcode_libdir_flag_spec=
+hardcode_libdir_separator=
+hardcode_direct=no
+hardcode_minus_L=no
+
+case "$host_os" in
+ cygwin* | mingw* | pw32*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+esac
+
+ld_shlibs=yes
+if test "$with_gnu_ld" = yes; then
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ # Unlike libtool, we use -rpath here, not --rpath, since the documented
+ # option of GNU ld is called -rpath, not --rpath.
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ case "$host_os" in
+ aix3* | aix4* | aix5*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs=no
+ fi
+ ;;
+ amigaos*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+ # that the semantics of dynamic libraries on AmigaOS, at least up
+ # to version 4, is to share data among multiple programs linked
+ # with the same dynamic library. Since this doesn't match the
+ # behavior of shared libraries on other platforms, we cannot use
+ # them.
+ ld_shlibs=no
+ ;;
+ beos*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ :
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ cygwin* | mingw* | pw32*)
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec='-L$libdir'
+ if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+ :
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ interix3*)
+ hardcode_direct=no
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ ;;
+ linux*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ :
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ netbsd*)
+ ;;
+ solaris*)
+ if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+ ld_shlibs=no
+ elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ :
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+ ld_shlibs=no
+ ;;
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ ;;
+ sunos4*)
+ hardcode_direct=yes
+ ;;
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ :
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ if test "$ld_shlibs" = no; then
+ hardcode_libdir_flag_spec=
+ fi
+else
+ case "$host_os" in
+ aix3*)
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L=yes
+ if test "$GCC" = yes; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct=unsupported
+ fi
+ ;;
+ aix4* | aix5*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ else
+ aix_use_runtimelinking=no
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix5*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+ fi
+ hardcode_direct=yes
+ hardcode_libdir_separator=':'
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" && \
+ strings "$collect2name" | grep resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ hardcode_direct=yes
+ else
+ # We have old collect2
+ hardcode_direct=unsupported
+ hardcode_minus_L=yes
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_libdir_separator=
+ fi
+ ;;
+ esac
+ fi
+ # Begin _LT_AC_SYS_LIBPATH_AIX.
+ echo 'int main () { return 0; }' > conftest.c
+ ${CC} ${LDFLAGS} conftest.c -o conftest
+ aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+ if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+ fi
+ if test -z "$aix_libpath"; then
+ aix_libpath="/usr/lib:/lib"
+ fi
+ rm -f conftest.c conftest
+ # End _LT_AC_SYS_LIBPATH_AIX.
+ if test "$aix_use_runtimelinking" = yes; then
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+ else
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ fi
+ fi
+ ;;
+ amigaos*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ # see comment about different semantics on the GNU ld section
+ ld_shlibs=no
+ ;;
+ bsdi[45]*)
+ ;;
+ cygwin* | mingw* | pw32*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec=' '
+ libext=lib
+ ;;
+ darwin* | rhapsody*)
+ hardcode_direct=no
+ if test "$GCC" = yes ; then
+ :
+ else
+ case $cc_basename in
+ xlc*)
+ ;;
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+ fi
+ ;;
+ dgux*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ ;;
+ freebsd1*)
+ ld_shlibs=no
+ ;;
+ freebsd2.2*)
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ ;;
+ freebsd2*)
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ ;;
+ freebsd* | kfreebsd*-gnu | dragonfly*)
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ ;;
+ hpux9*)
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ hpux10*)
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ fi
+ ;;
+ hpux11*)
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ case $host_cpu in
+ hppa*64*|ia64*)
+ hardcode_direct=no
+ ;;
+ *)
+ hardcode_direct=yes
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ esac
+ fi
+ ;;
+ irix5* | irix6* | nonstopux*)
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+ netbsd*)
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ ;;
+ newsos6)
+ hardcode_direct=yes
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+ openbsd*)
+ hardcode_direct=yes
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ else
+ case "$host_os" in
+ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+ hardcode_libdir_flag_spec='-R$libdir'
+ ;;
+ *)
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ ;;
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ osf3*)
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+ osf4* | osf5*)
+ if test "$GCC" = yes; then
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ else
+ # Both cc and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec='-rpath $libdir'
+ fi
+ hardcode_libdir_separator=:
+ ;;
+ solaris*)
+ hardcode_libdir_flag_spec='-R$libdir'
+ ;;
+ sunos4*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ ;;
+ sysv4)
+ case $host_vendor in
+ sni)
+ hardcode_direct=yes # is this really true???
+ ;;
+ siemens)
+ hardcode_direct=no
+ ;;
+ motorola)
+ hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ ;;
+ sysv4.3*)
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ ld_shlibs=yes
+ fi
+ ;;
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7*)
+ ;;
+ sysv5* | sco3.2v5* | sco5v6*)
+ hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+ hardcode_libdir_separator=':'
+ ;;
+ uts4*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ ;;
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+fi
+
+# Check dynamic linker characteristics
+# Code taken from libtool.m4's AC_LIBTOOL_SYS_DYNAMIC_LINKER.
+libname_spec='lib$name'
+case "$host_os" in
+ aix3*)
+ ;;
+ aix4* | aix5*)
+ ;;
+ amigaos*)
+ ;;
+ beos*)
+ ;;
+ bsdi[45]*)
+ ;;
+ cygwin* | mingw* | pw32*)
+ shrext=.dll
+ ;;
+ darwin* | rhapsody*)
+ shrext=.dylib
+ ;;
+ dgux*)
+ ;;
+ freebsd1*)
+ ;;
+ kfreebsd*-gnu)
+ ;;
+ freebsd* | dragonfly*)
+ ;;
+ gnu*)
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $host_cpu in
+ ia64*)
+ shrext=.so
+ ;;
+ hppa*64*)
+ shrext=.sl
+ ;;
+ *)
+ shrext=.sl
+ ;;
+ esac
+ ;;
+ interix3*)
+ ;;
+ irix5* | irix6* | nonstopux*)
+ case "$host_os" in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;;
+ *) libsuff= shlibsuff= ;;
+ esac
+ ;;
+ esac
+ ;;
+ linux*oldld* | linux*aout* | linux*coff*)
+ ;;
+ linux*)
+ ;;
+ knetbsd*-gnu)
+ ;;
+ netbsd*)
+ ;;
+ newsos6)
+ ;;
+ nto-qnx*)
+ ;;
+ openbsd*)
+ ;;
+ os2*)
+ libname_spec='$name'
+ shrext=.dll
+ ;;
+ osf3* | osf4* | osf5*)
+ ;;
+ solaris*)
+ ;;
+ sunos4*)
+ ;;
+ sysv4 | sysv4.3*)
+ ;;
+ sysv4*MP*)
+ ;;
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ ;;
+ uts4*)
+ ;;
+esac
+
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"`
+shlibext=`echo "$shrext" | sed -e 's,^\.,,'`
+escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
+
+LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <<EOF
+
+# How to pass a linker flag through the compiler.
+wl="$escaped_wl"
+
+# Static library suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally "so").
+shlibext="$shlibext"
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec"
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator="$hardcode_libdir_separator"
+
+# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct="$hardcode_direct"
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L="$hardcode_minus_L"
+
+EOF
diff --git a/extras/sasl/build-aux/config.sub b/extras/sasl/build-aux/config.sub
new file mode 100755
index 0000000000..7ccee73057
--- /dev/null
+++ b/extras/sasl/build-aux/config.sub
@@ -0,0 +1,1619 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
+# Inc.
+
+timestamp='2006-11-07'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray)
+ os=
+ basic_machine=$1
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+ | bfin \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | mcore \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64vr | mips64vrel \
+ | mips64orion | mips64orionel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | mt \
+ | msp430 \
+ | nios | nios2 \
+ | ns16k | ns32k \
+ | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu | strongarm \
+ | tahoe | thumb | tic4x | tic80 | tron \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+ | z8k)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* | avr32-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+ | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+ | nios-* | nios2-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tron-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+ | xstormy16-* | xtensa-* \
+ | ymp-* \
+ | z8k-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16c)
+ basic_machine=cr16c-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ ms1-*)
+ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rdos)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tic55x | c55x*)
+ basic_machine=tic55x-unknown
+ os=-coff
+ ;;
+ tic6x | c6x*)
+ basic_machine=tic6x-unknown
+ os=-coff
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -openbsd* | -solidbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos* | -toppers*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/extras/sasl/build-aux/depcomp b/extras/sasl/build-aux/depcomp
new file mode 100755
index 0000000000..ca5ea4e1ef
--- /dev/null
+++ b/extras/sasl/build-aux/depcomp
@@ -0,0 +1,584 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2006-10-15.18
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006 Free Software
+# Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+ depmode Dependency tracking mode.
+ source Source file read by `PROGRAMS ARGS'.
+ object Object file output by `PROGRAMS ARGS'.
+ DEPDIR directory where to store dependencies.
+ depfile Dependency file to output.
+ tmpdepfile Temporary file to use when outputing dependencies.
+ libtool Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "depcomp $scriptversion"
+ exit $?
+ ;;
+esac
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+ sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am. Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+ for arg
+ do
+ case $arg in
+ -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+ *) set fnord "$@" "$arg" ;;
+ esac
+ shift # fnord
+ shift # $arg
+ done
+ "$@"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "$@" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the `deleted header file' problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+ tr ' ' '
+' < "$tmpdepfile" |
+## Some versions of gcc put a space before the `:'. On the theory
+## that the space means something, we add a space to the output as
+## well.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "$@" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "$@" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like `#:fec' to the end of the
+ # dependency line.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+ tr '
+' ' ' >> $depfile
+ echo >> $depfile
+
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> $depfile
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. In older versions, this file always lives in the
+ # current directory. Also, the AIX compiler puts `$object:' at the
+ # start of each line; $object doesn't have directory information.
+ # Version 6 uses the directory in both cases.
+ stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'`
+ tmpdepfile="$stripped.u"
+ if test "$libtool" = yes; then
+ "$@" -Wc,-M
+ else
+ "$@" -M
+ fi
+ stat=$?
+
+ if test -f "$tmpdepfile"; then :
+ else
+ stripped=`echo "$stripped" | sed 's,^.*/,,'`
+ tmpdepfile="$stripped.u"
+ fi
+
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+
+ if test -f "$tmpdepfile"; then
+ outname="$stripped.o"
+ # Each line is of the form `foo.o: dependent.h'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
+ sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+icc)
+ # Intel's C compiler understands `-MD -MF file'. However on
+ # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+ # ICC 7.0 will fill foo.d with something like
+ # foo.o: sub/foo.c
+ # foo.o: sub/foo.h
+ # which is wrong. We want:
+ # sub/foo.o: sub/foo.c
+ # sub/foo.o: sub/foo.h
+ # sub/foo.c:
+ # sub/foo.h:
+ # ICC 7.1 will output
+ # foo.o: sub/foo.c sub/foo.h
+ # and will wrap long lines using \ :
+ # foo.o: sub/foo.c ... \
+ # sub/foo.h ... \
+ # ...
+
+ "$@" -MD -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each line is of the form `foo.o: dependent.h',
+ # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
+ sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp2)
+ # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+ # compilers, which have integrated preprocessors. The correct option
+ # to use with these is +Maked; it writes dependencies to a file named
+ # 'foo.d', which lands next to the object file, wherever that
+ # happens to be.
+ # Much of this is similar to the tru64 case; see comments there.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir.libs/$base.d
+ "$@" -Wc,+Maked
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ "$@" +Maked
+ fi
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
+ # Add `dependent.h:' lines.
+ sed -ne '2,${; s/^ *//; s/ \\*$//; s/$/:/; p;}' "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile" "$tmpdepfile2"
+ ;;
+
+tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in `foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+ if test "$libtool" = yes; then
+ # With Tru64 cc, shared objects can also be used to make a
+ # static library. This mechanism is used in libtool 1.4 series to
+ # handle both shared and static libraries in a single compilation.
+ # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
+ #
+ # With libtool 1.5 this exception was removed, and libtool now
+ # generates 2 separate objects for the 2 libraries. These two
+ # compilations output dependencies in $dir.libs/$base.o.d and
+ # in $dir$base.o.d. We have to check for both files, because
+ # one of the two compilations can be disabled. We should prefer
+ # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+ # automatically cleaned when .libs/ is deleted, while ignoring
+ # the former would cause a distcleancheck panic.
+ tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4
+ tmpdepfile2=$dir$base.o.d # libtool 1.5
+ tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5
+ tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504
+ "$@" -Wc,-MD
+ else
+ tmpdepfile1=$dir$base.o.d
+ tmpdepfile2=$dir$base.d
+ tmpdepfile3=$dir$base.d
+ tmpdepfile4=$dir$base.d
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+ # That's a tab and a space in the [].
+ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ test -z "$dashmflag" && dashmflag=-M
+ # Require at least two characters before searching for `:'
+ # in the target name. This is to cope with DOS-style filenames:
+ # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
+ "$@" $dashmflag |
+ sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ tr ' ' '
+' < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ "$@" || exit $?
+ # Remove any Libtool call
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+ cleared=no
+ for arg in "$@"; do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift ;;
+ # Strip any option that makedepend may not understand. Remove
+ # the object too, otherwise makedepend will parse it as a source file.
+ -*|$object)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift ;;
+ esac
+ done
+ obj_suffix="`echo $object | sed 's/^.*\././'`"
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ sed '1,2d' "$tmpdepfile" | tr ' ' '
+' | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ "$@" -E |
+ sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+ sed '$ s: \\$::' > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o,
+ # because we must use -o when running libtool.
+ "$@" || exit $?
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "$@" -E |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
+ echo " " >> "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+none)
+ exec "$@"
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/extras/sasl/build-aux/install-sh b/extras/sasl/build-aux/install-sh
new file mode 100755
index 0000000000..4fbbae7b7f
--- /dev/null
+++ b/extras/sasl/build-aux/install-sh
@@ -0,0 +1,507 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2006-10-14.15
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+nl='
+'
+IFS=" "" $nl"
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+if test -z "$doit"; then
+ doit_exec=exec
+else
+ doit_exec=$doit
+fi
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+posix_glob=
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chmodcmd=$chmodprog
+chowncmd=
+chgrpcmd=
+stripcmd=
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=
+dst=
+dir_arg=
+dstarg=
+no_target_directory=
+
+usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+-c (ignored)
+-d create directories instead of installing files.
+-g GROUP $chgrpprog installed files to GROUP.
+-m MODE $chmodprog installed files to MODE.
+-o USER $chownprog installed files to USER.
+-s $stripprog installed files.
+-t DIRECTORY install into DIRECTORY.
+-T report an error if DSTFILE is a directory.
+--help display this help and exit.
+--version display version info and exit.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+ case $1 in
+ -c) shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ --help) echo "$usage"; exit $?;;
+
+ -m) mode=$2
+ shift
+ shift
+ case $mode in
+ *' '* | *' '* | *'
+'* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd=$stripprog
+ shift
+ continue;;
+
+ -t) dstarg=$2
+ shift
+ shift
+ continue;;
+
+ -T) no_target_directory=true
+ shift
+ continue;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+ --) shift
+ break;;
+
+ -*) echo "$0: invalid option: $1" >&2
+ exit 1;;
+
+ *) break;;
+ esac
+done
+
+if test $# -ne 0 && test -z "$dir_arg$dstarg"; then
+ # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dstarg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dstarg"
+ shift # fnord
+ fi
+ shift # arg
+ dstarg=$arg
+ done
+fi
+
+if test $# -eq 0; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call `install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+if test -z "$dir_arg"; then
+ trap '(exit $?); exit' 1 2 13 15
+
+ # Set umask so as not to create temps with too-generous modes.
+ # However, 'strip' requires both read and write access to temps.
+ case $mode in
+ # Optimize common cases.
+ *644) cp_umask=133;;
+ *755) cp_umask=22;;
+
+ *[0-7])
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw='% 200'
+ fi
+ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+ *)
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw=,u+rw
+ fi
+ cp_umask=$mode$u_plus_rw;;
+ esac
+fi
+
+for src
+do
+ # Protect names starting with `-'.
+ case $src in
+ -*) src=./$src ;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ dstdir=$dst
+ test -d "$dstdir"
+ dstdir_status=$?
+ else
+
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dstarg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+
+ dst=$dstarg
+ # Protect names starting with `-'.
+ case $dst in
+ -*) dst=./$dst ;;
+ esac
+
+ # If destination is a directory, append the input filename; won't work
+ # if double slashes aren't ignored.
+ if test -d "$dst"; then
+ if test -n "$no_target_directory"; then
+ echo "$0: $dstarg: Is a directory" >&2
+ exit 1
+ fi
+ dstdir=$dst
+ dst=$dstdir/`basename "$src"`
+ dstdir_status=0
+ else
+ # Prefer dirname, but fall back on a substitute if dirname fails.
+ dstdir=`
+ (dirname "$dst") 2>/dev/null ||
+ expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$dst" : 'X\(//\)[^/]' \| \
+ X"$dst" : 'X\(//\)$' \| \
+ X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+ echo X"$dst" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'
+ `
+
+ test -d "$dstdir"
+ dstdir_status=$?
+ fi
+ fi
+
+ obsolete_mkdir_used=false
+
+ if test $dstdir_status != 0; then
+ case $posix_mkdir in
+ '')
+ # Create intermediate dirs using mode 755 as modified by the umask.
+ # This is like FreeBSD 'install' as of 1997-10-28.
+ umask=`umask`
+ case $stripcmd.$umask in
+ # Optimize common cases.
+ *[2367][2367]) mkdir_umask=$umask;;
+ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+ *[0-7])
+ mkdir_umask=`expr $umask + 22 \
+ - $umask % 100 % 40 + $umask % 20 \
+ - $umask % 10 % 4 + $umask % 2
+ `;;
+ *) mkdir_umask=$umask,go-w;;
+ esac
+
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, rely on $mkdir_umask.
+ if test -n "$dir_arg"; then
+ mkdir_mode=-m$mode
+ else
+ mkdir_mode=
+ fi
+
+ posix_mkdir=false
+ case $umask in
+ *[123567][0-7][0-7])
+ # POSIX mkdir -p sets u+wx bits regardless of umask, which
+ # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+ ;;
+ *)
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+ if (umask $mkdir_umask &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities with -m.
+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+ # other-writeable bit of parent directory when it shouldn't.
+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+ ls_ld_tmpdir=`ls -ld "$tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/d" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+ fi
+ trap '' 0;;
+ esac;;
+ esac
+
+ if
+ $posix_mkdir && (
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ )
+ then :
+ else
+
+ # The umask is ridiculous, or mkdir does not conform to POSIX,
+ # or it failed possibly due to a race condition. Create the
+ # directory the slow way, step by step, checking for races as we go.
+
+ case $dstdir in
+ /*) prefix=/ ;;
+ -*) prefix=./ ;;
+ *) prefix= ;;
+ esac
+
+ case $posix_glob in
+ '')
+ if (set -f) 2>/dev/null; then
+ posix_glob=true
+ else
+ posix_glob=false
+ fi ;;
+ esac
+
+ oIFS=$IFS
+ IFS=/
+ $posix_glob && set -f
+ set fnord $dstdir
+ shift
+ $posix_glob && set +f
+ IFS=$oIFS
+
+ prefixes=
+
+ for d
+ do
+ test -z "$d" && continue
+
+ prefix=$prefix$d
+ if test -d "$prefix"; then
+ prefixes=
+ else
+ if $posix_mkdir; then
+ (umask=$mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+ # Don't fail if two instances are running concurrently.
+ test -d "$prefix" || exit 1
+ else
+ case $prefix in
+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) qprefix=$prefix;;
+ esac
+ prefixes="$prefixes '$qprefix'"
+ fi
+ fi
+ prefix=$prefix/
+ done
+
+ if test -n "$prefixes"; then
+ # Don't fail if two instances are running concurrently.
+ (umask $mkdir_umask &&
+ eval "\$doit_exec \$mkdirprog $prefixes") ||
+ test -d "$dstdir" || exit 1
+ obsolete_mkdir_used=true
+ fi
+ fi
+ fi
+
+ if test -n "$dir_arg"; then
+ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+ else
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=$dstdir/_inst.$$_
+ rmtmp=$dstdir/_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+ # Copy the file name to the temp name.
+ (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
+ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
+ && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
+ && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+ # Now rename the file to the real destination.
+ { $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \
+ || {
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ if test -f "$dst"; then
+ $doit $rmcmd -f "$dst" 2>/dev/null \
+ || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \
+ && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\
+ || {
+ echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ else
+ :
+ fi
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
+ }
+ } || exit 1
+
+ trap '' 0
+ fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/extras/sasl/build-aux/mdate-sh b/extras/sasl/build-aux/mdate-sh
new file mode 100755
index 0000000000..cd916c0a34
--- /dev/null
+++ b/extras/sasl/build-aux/mdate-sh
@@ -0,0 +1,201 @@
+#!/bin/sh
+# Get modification time of a file or directory and pretty-print it.
+
+scriptversion=2005-06-29.22
+
+# Copyright (C) 1995, 1996, 1997, 2003, 2004, 2005 Free Software
+# Foundation, Inc.
+# written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, June 1995
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+case $1 in
+ '')
+ echo "$0: No file. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: mdate-sh [--help] [--version] FILE
+
+Pretty-print the modification time of FILE.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "mdate-sh $scriptversion"
+ exit $?
+ ;;
+esac
+
+# Prevent date giving response in another language.
+LANG=C
+export LANG
+LC_ALL=C
+export LC_ALL
+LC_TIME=C
+export LC_TIME
+
+# GNU ls changes its time format in response to the TIME_STYLE
+# variable. Since we cannot assume `unset' works, revert this
+# variable to its documented default.
+if test "${TIME_STYLE+set}" = set; then
+ TIME_STYLE=posix-long-iso
+ export TIME_STYLE
+fi
+
+save_arg1=$1
+
+# Find out how to get the extended ls output of a file or directory.
+if ls -L /dev/null 1>/dev/null 2>&1; then
+ ls_command='ls -L -l -d'
+else
+ ls_command='ls -l -d'
+fi
+
+# A `ls -l' line looks as follows on OS/2.
+# drwxrwx--- 0 Aug 11 2001 foo
+# This differs from Unix, which adds ownership information.
+# drwxrwx--- 2 root root 4096 Aug 11 2001 foo
+#
+# To find the date, we split the line on spaces and iterate on words
+# until we find a month. This cannot work with files whose owner is a
+# user named `Jan', or `Feb', etc. However, it's unlikely that `/'
+# will be owned by a user whose name is a month. So we first look at
+# the extended ls output of the root directory to decide how many
+# words should be skipped to get the date.
+
+# On HPUX /bin/sh, "set" interprets "-rw-r--r--" as options, so the "x" below.
+set x`ls -l -d /`
+
+# Find which argument is the month.
+month=
+command=
+until test $month
+do
+ shift
+ # Add another shift to the command.
+ command="$command shift;"
+ case $1 in
+ Jan) month=January; nummonth=1;;
+ Feb) month=February; nummonth=2;;
+ Mar) month=March; nummonth=3;;
+ Apr) month=April; nummonth=4;;
+ May) month=May; nummonth=5;;
+ Jun) month=June; nummonth=6;;
+ Jul) month=July; nummonth=7;;
+ Aug) month=August; nummonth=8;;
+ Sep) month=September; nummonth=9;;
+ Oct) month=October; nummonth=10;;
+ Nov) month=November; nummonth=11;;
+ Dec) month=December; nummonth=12;;
+ esac
+done
+
+# Get the extended ls output of the file or directory.
+set dummy x`eval "$ls_command \"\$save_arg1\""`
+
+# Remove all preceding arguments
+eval $command
+
+# Because of the dummy argument above, month is in $2.
+#
+# On a POSIX system, we should have
+#
+# $# = 5
+# $1 = file size
+# $2 = month
+# $3 = day
+# $4 = year or time
+# $5 = filename
+#
+# On Darwin 7.7.0 and 7.6.0, we have
+#
+# $# = 4
+# $1 = day
+# $2 = month
+# $3 = year or time
+# $4 = filename
+
+# Get the month.
+case $2 in
+ Jan) month=January; nummonth=1;;
+ Feb) month=February; nummonth=2;;
+ Mar) month=March; nummonth=3;;
+ Apr) month=April; nummonth=4;;
+ May) month=May; nummonth=5;;
+ Jun) month=June; nummonth=6;;
+ Jul) month=July; nummonth=7;;
+ Aug) month=August; nummonth=8;;
+ Sep) month=September; nummonth=9;;
+ Oct) month=October; nummonth=10;;
+ Nov) month=November; nummonth=11;;
+ Dec) month=December; nummonth=12;;
+esac
+
+case $3 in
+ ???*) day=$1;;
+ *) day=$3; shift;;
+esac
+
+# Here we have to deal with the problem that the ls output gives either
+# the time of day or the year.
+case $3 in
+ *:*) set `date`; eval year=\$$#
+ case $2 in
+ Jan) nummonthtod=1;;
+ Feb) nummonthtod=2;;
+ Mar) nummonthtod=3;;
+ Apr) nummonthtod=4;;
+ May) nummonthtod=5;;
+ Jun) nummonthtod=6;;
+ Jul) nummonthtod=7;;
+ Aug) nummonthtod=8;;
+ Sep) nummonthtod=9;;
+ Oct) nummonthtod=10;;
+ Nov) nummonthtod=11;;
+ Dec) nummonthtod=12;;
+ esac
+ # For the first six month of the year the time notation can also
+ # be used for files modified in the last year.
+ if (expr $nummonth \> $nummonthtod) > /dev/null;
+ then
+ year=`expr $year - 1`
+ fi;;
+ *) year=$3;;
+esac
+
+# The result.
+echo $day $month $year
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/extras/sasl/build-aux/missing b/extras/sasl/build-aux/missing
new file mode 100755
index 0000000000..1c8ff7049d
--- /dev/null
+++ b/extras/sasl/build-aux/missing
@@ -0,0 +1,367 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+
+scriptversion=2006-05-10.23
+
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006
+# Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+run=:
+sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p'
+sed_minuso='s/.* -o \([^ ]*\).*/\1/p'
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+ configure_ac=configure.ac
+else
+ configure_ac=configure.in
+fi
+
+msg="missing on your system"
+
+case $1 in
+--run)
+ # Try to run requested program, and just exit if it succeeds.
+ run=
+ shift
+ "$@" && exit 0
+ # Exit code 63 means version mismatch. This often happens
+ # when the user try to use an ancient version of a tool on
+ # a file that requires a minimum version. In this case we
+ # we should proceed has if the program had been absent, or
+ # if --run hadn't been passed.
+ if test $? = 63; then
+ run=:
+ msg="probably too old"
+ fi
+ ;;
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+ --run try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ autom4te touch the output file, or create a stub one
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ help2man touch the output file
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ tar try tar, gnutar, gtar, then tar without non-portable flags
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]
+
+Send bug reports to <bug-automake@gnu.org>."
+ exit $?
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing $scriptversion (GNU Automake)"
+ exit $?
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+esac
+
+# Now exit if we have it, but it failed. Also exit now if we
+# don't have it and --version was passed (most likely to detect
+# the program).
+case $1 in
+ lex|yacc)
+ # Not GNU programs, they don't have --version.
+ ;;
+
+ tar)
+ if test -n "$run"; then
+ echo 1>&2 "ERROR: \`tar' requires --run"
+ exit 1
+ elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+ exit 1
+ fi
+ ;;
+
+ *)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+ # Could not run --version or --help. This is probably someone
+ # running `$TOOL --version' or `$TOOL --help' to check whether
+ # $TOOL exists and not knowing $TOOL uses missing.
+ exit 1
+ fi
+ ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case $1 in
+ aclocal*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acinclude.m4' or \`${configure_ac}'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`${configure_ac}'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acconfig.h' or \`${configure_ac}'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case $f in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
+ ;;
+
+ automake*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ autom4te)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, but is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them.
+ You can get \`$1' as part of \`Autoconf' from any GNU
+ archive site."
+
+ file=`echo "$*" | sed -n "$sed_output"`
+ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo "#! /bin/sh"
+ echo "# Created by GNU Automake missing as a replacement of"
+ echo "# $ $@"
+ echo "exit 0"
+ chmod +x $file
+ exit 1
+ fi
+ ;;
+
+ bison|yacc)
+ echo 1>&2 "\
+WARNING: \`$1' $msg. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if test $# -ne 1; then
+ eval LASTARG="\${$#}"
+ case $LASTARG in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if test ! -f y.tab.h; then
+ echo >y.tab.h
+ fi
+ if test ! -f y.tab.c; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex|flex)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if test $# -ne 1; then
+ eval LASTARG="\${$#}"
+ case $LASTARG in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if test ! -f lex.yy.c; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ help2man)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a dependency of a manual page. You may need the
+ \`Help2man' package in order for those modifications to take
+ effect. You can get \`Help2man' from any GNU archive site."
+
+ file=`echo "$*" | sed -n "$sed_output"`
+ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo ".ab help2man is required to generate this page"
+ exit 1
+ fi
+ ;;
+
+ makeinfo)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ # The file to touch is that specified with -o ...
+ file=`echo "$*" | sed -n "$sed_output"`
+ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -z "$file"; then
+ # ... or it is the one specified with @setfilename ...
+ infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '
+ /^@setfilename/{
+ s/.* \([^ ]*\) *$/\1/
+ p
+ q
+ }' $infile`
+ # ... or it is derived from the source name (dir/f.texi becomes f.info)
+ test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
+ fi
+ # If the file does not exist, the user really needs makeinfo;
+ # let's fail without touching anything.
+ test -f $file || exit 1
+ touch $file
+ ;;
+
+ tar)
+ shift
+
+ # We have already tried tar in the generic part.
+ # Look for gnutar/gtar before invocation to avoid ugly error
+ # messages.
+ if (gnutar --version > /dev/null 2>&1); then
+ gnutar "$@" && exit 0
+ fi
+ if (gtar --version > /dev/null 2>&1); then
+ gtar "$@" && exit 0
+ fi
+ firstarg="$1"
+ if shift; then
+ case $firstarg in
+ *o*)
+ firstarg=`echo "$firstarg" | sed s/o//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ case $firstarg in
+ *h*)
+ firstarg=`echo "$firstarg" | sed s/h//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ fi
+
+ echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+ You may want to install GNU tar or Free paxutils, or check the
+ command line arguments."
+ exit 1
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequisites for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/extras/sasl/configure.ac b/extras/sasl/configure.ac
new file mode 100644
index 0000000000..bc0fadbb31
--- /dev/null
+++ b/extras/sasl/configure.ac
@@ -0,0 +1,318 @@
+dnl Process this file with autoconf to produce a configure script.
+dnl
+dnl This file is free software; as a special exception the author gives
+dnl unlimited permission to copy and/or distribute it, with or without
+dnl modifications, as long as this notice is preserved.
+dnl
+dnl This program is distributed in the hope that it will be useful, but
+dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+dnl
+dnl When updating the name/version number here, also update it in
+dnl src/qpid/Version.h
+
+AC_INIT([saslwrapper], [0.1], [dev@qpid.apache.org])
+AC_CONFIG_AUX_DIR([build-aux])
+AM_INIT_AUTOMAKE([dist-bzip2 subdir-objects])
+
+# Minimum Autoconf version required.
+AC_PREREQ(2.59)
+
+AC_CONFIG_HEADERS([config.h])
+
+AC_PROG_CC_STDC
+AM_PROG_CC_C_O
+AC_PROG_CXX
+AC_USE_SYSTEM_EXTENSIONS
+AC_LANG([C++])
+
+# Check for optional use of help2man
+AC_CHECK_PROG([HELP2MAN], [help2man], [help2man])
+AC_ARG_WITH([help2man],
+ [AS_HELP_STRING([--with-help2man], [Use help2man to generate man pages.])],
+ [case "$withval" in
+ yes) test -z "$HELP2MAN" && AC_MSG_ERROR([help2man not found.]) ;;
+ no) HELP2MAN="" ;;
+ *) AC_MSG_ERROR([Bad value ${withval} for --with-help2man.]) ;;
+ esac])
+AM_CONDITIONAL([HAVE_HELP2MAN], [test -n "$HELP2MAN"])
+
+# Check for optional use of doxygen
+AC_CHECK_PROG([DOXYGEN], [doxygen], [doxygen])
+AC_ARG_WITH([doxygen],
+ [AS_HELP_STRING([--with-doxygen], [Use doxygen to generate API documentation.])],
+ [case "$withval" in
+ yes) test -z "$DOXYGEN" && AC_MSG_ERROR([doxygen not found.]) ;;
+ no) DOXYGEN="" ;;
+ *) AC_MSG_ERROR([Bad value ${withval} for --with-doxygen.]) ;;
+ esac])
+AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"])
+
+AC_ARG_ENABLE(warnings,
+[ --enable-warnings turn on lots of compiler warnings (recommended)],
+[case "${enableval}" in
+ yes|no) ;;
+ *) AC_MSG_ERROR([bad value ${enableval} for warnings option]) ;;
+ esac],
+ [enableval=yes])
+
+# Set up for gcc as compiler
+if test x$GXX = xyes; then
+ # Warnings: Enable as many as possible, keep the code clean. Please
+ # do not disable warnings or remove -Werror without discussing on
+ # qpid-dev list.
+ #
+ # The following warnings are deliberately omitted, they warn on valid code.
+ # -Wunreachable-code -Wpadded -Winline
+ # -Wshadow - warns about boost headers.
+ if test "${enableval}" = yes; then
+ gl_COMPILER_FLAGS(-Werror)
+ gl_COMPILER_FLAGS(-pedantic)
+ gl_COMPILER_FLAGS(-Wall)
+ gl_COMPILER_FLAGS(-Wextra)
+ gl_COMPILER_FLAGS(-Wno-shadow)
+ gl_COMPILER_FLAGS(-Wpointer-arith)
+ gl_COMPILER_FLAGS(-Wcast-qual)
+ gl_COMPILER_FLAGS(-Wcast-align)
+ gl_COMPILER_FLAGS(-Wno-long-long)
+ gl_COMPILER_FLAGS(-Wvolatile-register-var)
+ gl_COMPILER_FLAGS(-Winvalid-pch)
+ gl_COMPILER_FLAGS(-Wno-system-headers)
+ gl_COMPILER_FLAGS(-Woverloaded-virtual)
+ AC_SUBST([WARNING_CFLAGS], [$COMPILER_FLAGS])
+ AC_DEFINE([lint], 1, [Define to 1 if the compiler is checking for lint.])
+ COMPILER_FLAGS=
+ fi
+else
+ AC_CHECK_DECL([__SUNPRO_CC], [SUNCC=yes], [SUNCC=no])
+
+ # Set up for sun CC compiler
+ if test x$SUNCC = xyes; then
+ if test "${enableval}" = yes; then
+ WARNING_FLAGS=+w
+ fi
+ CXXFLAGS="$CXXFLAGS -library=stlport4 -mt"
+ LD="$CXX"
+ LDFLAGS="$LDFLAGS -library=stlport4 -mt"
+ AC_SUBST([SUNCC_RUNTIME_LIBS], [-lCrun])
+ fi
+fi
+
+AC_DISABLE_STATIC
+AC_PROG_LIBTOOL
+AC_SUBST([LIBTOOL_DEPS])
+
+# For libraries (libcommon) that use dlopen, dlerror, etc.,
+# test whether we need to link with -ldl.
+gl_saved_libs=$LIBS
+ AC_SEARCH_LIBS(dlopen, [dl],
+ [test "$ac_cv_search_dlopen" = "none required" ||
+ LIB_DLOPEN=$ac_cv_search_dlopen])
+ AC_SUBST([LIB_DLOPEN])
+LIBS=$gl_saved_libs
+
+# Set the argument to be used in "libtool -version-info ARG".
+QPID_CURRENT=2
+QPID_REVISION=0
+QPID_AGE=0
+LIBTOOL_VERSION_INFO_ARG=$QPID_CURRENT:$QPID_REVISION:$QPID_AGE
+AC_SUBST(LIBTOOL_VERSION_INFO_ARG)
+
+gl_CLOCK_TIME
+
+# Enable Valgrind
+AC_ARG_ENABLE([valgrind],
+ [AS_HELP_STRING([--enable-valgrind],
+ [run valgrind memory checker on tests, if available (default yes)])],
+ [case $enableval in
+ yes|no) enable_VALGRIND=$enableval;;
+ *) AC_MSG_ERROR([Invalid value for --enable-valgrind: $enableval]);;
+ esac],
+ [enable_VALGRIND=yes]
+)
+
+# We use valgrind for the tests. See if it's available.
+# Check for it unconditionally, so we don't have to duplicate its
+# use of AC_SUBST([VALGRIND]).
+AC_CHECK_PROG([VALGRIND], [valgrind], [valgrind])
+test "$enable_VALGRIND" = no && VALGRIND=
+
+# If rpmlint is available we'll run it when building RPMs.
+AC_CHECK_PROG([RPMLINT], [rpmlint], [rpmlint])
+AM_CONDITIONAL([HAS_RPMLINT], [test -n "$RPMLINT"])
+
+# Code generation: generated code is included in the distribution
+# so code generation is only required in an svn checkout.
+# It requires several external tools and files, which we check for here.
+
+AC_CHECK_PROG([RUBY], [ruby], [ruby])
+test -n "$RUBY" && generate=yes
+test -z "$RUBY" && AC_MSG_ERROR([Missing ruby installation (try "yum install ruby").])
+
+# Swig binding generator is needed for the script (Ruby, Python, etc.) bindings.
+AC_PROG_SWIG(1.3.26)
+test ! -x "$SWIG" && SWIG=""
+AC_ARG_WITH([swig],
+ [AS_HELP_STRING([--with-swig], [Use swig to generate qmf bindings.])],
+ [case "$withval" in
+ yes) test -z "$SWIG" && AC_MSG_ERROR([swig not found.]) ;;
+ no) SWIG="" ;;
+ *) AC_MSG_ERROR([Bad value ${withval} for --with-swig.]) ;;
+ esac])
+AM_CONDITIONAL([HAVE_SWIG], [test -n "$SWIG"])
+
+# Ruby bindings: To build ruby wrappers, the ruby-devel files must be present.
+
+AC_PATH_PROGS(RUBY, [ruby1.8 ruby], [])
+AC_ARG_VAR(RUBY, [Ruby interpreter])
+if test -n "$RUBY" ; then
+ AC_ARG_VAR(RUBY_INC, [Directory where ruby.h can be found])
+ if test -z "$RUBY_INC" ; then
+ [RUBY_INC=`$RUBY -rrbconfig -e 'puts Config::CONFIG["rubyhdrdir"] || Config::CONFIG["archdir"]'`]
+ fi
+ AC_SUBST(RUBY_INC)
+
+ AC_ARG_VAR(RUBY_INC_ARCH, [Directory where ruby/config.h can be found (needed from Ruby 1.9)])
+ if test -z "$RUBY_INC_ARCH" ; then
+ [RUBY_INC_ARCH=`$RUBY -rrbconfig -e 'd = Config::CONFIG["rubyhdrdir"];if d != nil; print d + "/" + Config::CONFIG["arch"]; end'`]
+ dnl For earlier versions, just make it the same as RUBY_INC.
+ test x"$RUBY_INC_ARCH" != x || RUBY_INC_ARCH=$RUBY_INC
+ fi
+ AC_SUBST(RUBY_INC_ARCH)
+ AC_ARG_VAR(RUBY_LIB, [Directory to install ruby files into])
+ if test -z "$RUBY_LIB" ; then
+ dnl Kludge to install ruby files under $prefix
+ [RUBY_LIB=`$RUBY -rrbconfig -e 'puts Config::CONFIG["sitelibdir"].gsub("/usr", "${prefix}")'`]
+ fi
+ AC_SUBST(RUBY_LIB)
+
+ AC_ARG_VAR(RUBY_LIB_ARCH, [Directory to install ruby binary modules into])
+ if test -z "$RUBY_LIB_ARCH" ; then
+ dnl Kludge to install ruby files under $prefix
+ [RUBY_LIB_ARCH=`$RUBY -rrbconfig -e 'puts Config::CONFIG["sitearchdir"].gsub("/usr", "${prefix}")'`]
+ fi
+ AC_SUBST(RUBY_LIB_ARCH)
+
+ RUBY_LIBS=
+ case $host_os in
+ cygwin*) RUBY_LIBS=-lruby ;;
+ esac
+ AC_SUBST(RUBY_LIBS)
+
+ RUBY_DLEXT=`$RUBY -rrbconfig -e 'puts Config::CONFIG[["DLEXT"]]'`
+ AC_SUBST(RUBY_DLEXT)
+fi
+AM_CONDITIONAL([HAVE_RUBY_DEVEL], [test -f $RUBY_INC/ruby.h && test -n "$SWIG"])
+
+# Python bindings: To build python wrappers, the ruby-devel files must be present.
+
+AM_PATH_PYTHON()
+if test -n "$PYTHON" ; then
+ AC_MSG_CHECKING([$PYTHON include dir])
+ if $PYTHON -c 'import distutils.sysconfig' 2>/dev/null ; then
+ PYTHON_INC=`$PYTHON -c 'import os,distutils.sysconfig;print(distutils.sysconfig.get_python_inc().replace(os.sep,"/"))'`
+ AC_SUBST(PYTHON_INC)
+ else
+ if test yes = "$with_python" ; then
+ AC_MSG_ERROR([Couldn't import Python module distutils.sysconfig - you probably need to install a python-dev or python-devel package])
+ else
+ AC_MSG_WARN([Couldn't import Python module distutils.sysconfig - you probably don't have a python-dev or python-devel package installed])
+ fi
+ fi
+ AC_MSG_RESULT([$PYTHON_INC])
+ AC_MSG_CHECKING([for directory to install python bindings in])
+ if test -z "$PYTHON_LIB" ; then
+ PYTHON_LIB=`$PYTHON -c 'import os,distutils.sysconfig;print(distutils.sysconfig.get_python_lib(1).replace(os.sep,"/"))'`
+ fi
+ AC_MSG_RESULT([$PYTHON_LIB])
+ AC_ARG_VAR(PYTHON_LIB, [Directory to install python bindings in])
+
+ AC_MSG_CHECKING([for python libraries to link against])
+ PYTHON_LIBS=`$PYTHON -c 'import os,sys;print("-L"+os.path.join(sys.path[[3]],"config")+" -lpython"+sys.version[[:3]])'`
+ AC_SUBST(PYTHON_LIBS)
+ AC_MSG_RESULT([$PYTHON_LIBS])
+fi
+AM_CONDITIONAL([HAVE_PYTHON_DEVEL], [test -f $PYTHON_INC/Python.h && test -n "$SWIG"])
+
+
+LIBS=$tmp_LIBS
+
+# Setup --with-sasl/--without-sasl as arguments to configure
+AC_ARG_WITH([sasl],
+ [AS_HELP_STRING([--with-sasl], [Build with SASL authentication support])],
+ [WANT_SASL="$withval"],
+ [WANT_SASL=check])
+
+# Make sure --with-sasl/--without-sasl were only give yes|no|check
+AS_IF([test "x$WANT_SASL" != xyes -a \
+ "x$WANT_SASL" != xno -a \
+ "x$WANT_SASL" != xcheck],
+ [AC_MSG_ERROR([Bad value for --with-sasl: $withval])])
+
+# If we weren't explicitly asked /not/ to test, i.e. not given --without-sasl
+have_sasl=no
+AS_IF([test "x$WANT_SASL" != xno],
+ # Perform tests for headers and libraries. Remember, AC_CHECK_LIB
+ # will give you some useful default behavior, e.g. setup LDFLAGS, if
+ # you do not give it a second argument, so try not to
+ [AC_CHECK_HEADER([sasl/sasl.h], , [HAVE_SASL_H=no])
+ tmp_LIBS=$LIBS
+ AC_CHECK_LIB([sasl2], [sasl_checkpass], , [HAVE_SASL_LIB=no])
+ # Remove from LIBS, we will link it explicitly in make files.
+ LIBS=$tmp_LIBS
+ # If any of the tests failed
+ AS_IF([test "x$HAVE_SASL_H" = xno -o \
+ "x$HAVE_SASL_LIB" = xno],
+ # And we were given --with, then fail
+ [AS_IF([test "x$WANT_SASL" = xyes],
+ [AC_MSG_ERROR([sasl requested but not available])])],
+ # Otherwise, no tests failed, setup AC_SUBST/AC_DEFINE/vars for AM_CONDITIONALs
+ [AC_DEFINE([BROKER_SASL_NAME], ["qpidd"],
+ [The SASL app name for the qpid Broker])
+ AC_DEFINE([HAVE_SASL], [1], [Enable if libsasl is present])
+ have_sasl=yes])])
+AM_CONDITIONAL([HAVE_SASL], [test "x$have_sasl" = xyes])
+
+
+#Guess host architecture, to choose platform-dependent objects
+case "$host" in
+ *sun-solaris*)
+ arch=solaris
+ ;;
+esac
+AM_CONDITIONAL([SUNOS], [test x$arch = xsolaris])
+
+# Check for some syslog capabilities not present in all systems
+AC_TRY_COMPILE([#include <sys/syslog.h>],
+ [int v = LOG_AUTHPRIV;],
+ [AC_DEFINE([HAVE_LOG_AUTHPRIV], [1], [Set to 1 whether LOG_AUTHPRIV is supported.])],)
+
+AC_TRY_COMPILE([#include <sys/syslog.h>],
+ [int v = LOG_FTP;],
+ [AC_DEFINE([HAVE_LOG_FTP], [1], [Set to 1 whether LOG_FTP is supported.])],)
+
+#Check if we need to include libacl to provide acl API
+gl_saved_libs=$LIBS
+ AC_SEARCH_LIBS(acl, [acl],
+ [test "$ac_cv_search_acl" = "none required" ||
+ LIB_ACL=$ac_cv_search_acl])
+ AC_SUBST([LIB_ACL])
+LIBS=$gl_saved_libs
+
+SOCKLIBS=""
+AC_CHECK_LIB([socket],[socket],[SOCKET_LIB="-lsocket"],[SOCKET_LIB=""],[])
+AC_CHECK_LIB([nsl],[getipnodebyname],[NSL_LIB="-lnsl"],[NSL_LIB=""],[])
+SOCKLIBS="$SOCKET_LIB $NSL_LIB"
+AC_SUBST([SOCKLIBS])
+
+AM_PATH_PYTHON()
+
+# Files to generate
+AC_CONFIG_FILES([
+ Makefile
+ src/Makefile
+ python/Makefile
+ ruby/Makefile
+ ])
+AC_OUTPUT
+
diff --git a/extras/sasl/include/saslwrapper.h b/extras/sasl/include/saslwrapper.h
new file mode 100644
index 0000000000..bb2a9af7ff
--- /dev/null
+++ b/extras/sasl/include/saslwrapper.h
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+*/
+
+#include <stdint.h>
+#include <string>
+
+namespace saslwrapper {
+
+ /**
+ * The following type is used for output arguments (that are strings). The fact that it has
+ * a unique name is used in a SWIG typemap to indicate output arguments. For scripting languages
+ * such as Python and Ruby (which do not support output arguments), the outputs are placed in and
+ * array that is returned by the function. For example, a function that looks like:
+ *
+ * bool function(const string& input, output_string& out1, output_string& out2);
+ *
+ * would be called (in Python) like this:
+ *
+ * boolResult, out1, out2 = function(input)
+ */
+ typedef std::string output_string;
+ class ClientImpl;
+
+ class Client {
+ public:
+
+ Client();
+ ~Client();
+
+ /**
+ * Set attributes to be used in authenticating the session. All attributes should be set
+ * before init() is called.
+ *
+ * @param key Name of attribute being set
+ * @param value Value of attribute being set
+ * @return true iff success. If false is returned, call getError() for error details.
+ *
+ * Available attribute keys:
+ *
+ * service - Name of the service being accessed
+ * username - User identity for authentication
+ * authname - User identity for authorization (if different from username)
+ * password - Password associated with username
+ * host - Fully qualified domain name of the server host
+ * maxbufsize - Maximum receive buffer size for the security layer
+ * minssf - Minimum acceptable security strength factor (integer)
+ * maxssf - Maximum acceptable security strength factor (integer)
+ * externalssf - Security strength factor supplied by external mechanism (i.e. SSL/TLS)
+ * externaluser - Authentication ID (of client) as established by external mechanism
+ */
+ bool setAttr(const std::string& key, const std::string& value);
+ bool setAttr(const std::string& key, uint32_t value);
+
+ /**
+ * Initialize the client object. This should be called after all of the properties have been set.
+ *
+ * @return true iff success. If false is returned, call getError() for error details.
+ */
+ bool init();
+
+ /**
+ * Start the SASL exchange with the server.
+ *
+ * @param mechList List of mechanisms provided by the server
+ * @param chosen The mechanism chosen by the client
+ * @param initialResponse Initial block of data to send to the server
+ *
+ * @return true iff success. If false is returned, call getError() for error details.
+ */
+ bool start(const std::string& mechList, output_string& chosen, output_string& initialResponse);
+
+ /**
+ * Step the SASL handshake.
+ *
+ * @param challenge The challenge supplied by the server
+ * @param response (output) The response to be sent back to the server
+ *
+ * @return true iff success. If false is returned, call getError() for error details.
+ */
+ bool step(const std::string& challenge, output_string& response);
+
+ /**
+ * Encode data for secure transmission to the server.
+ *
+ * @param clearText Clear text data to be encrypted
+ * @param cipherText (output) Encrypted data to be transmitted
+ *
+ * @return true iff success. If false is returned, call getError() for error details.
+ */
+ bool encode(const std::string& clearText, output_string& cipherText);
+
+ /**
+ * Decode data received from the server.
+ *
+ * @param cipherText Encrypted data received from the server
+ * @param clearText (output) Decrypted clear text data
+ *
+ * @return true iff success. If false is returned, call getError() for error details.
+ */
+ bool decode(const std::string& cipherText, output_string& clearText);
+
+ /**
+ * Get the user identity (used for authentication) associated with this session.
+ * Note that this is particularly useful for single-sign-on mechanisms in which the
+ * username is not supplied by the application.
+ *
+ * @param userId (output) Authenticated user ID for this session.
+ */
+ bool getUserId(output_string& userId);
+
+ /**
+ * Get error message for last error.
+ * This function will return the last error message then clear the error state.
+ * If there was no error or the error state has been cleared, this function will output
+ * an empty string.
+ *
+ * @param error Error message string
+ */
+ void getError(output_string& error);
+
+ private:
+ ClientImpl* impl;
+
+ // Declare private copy constructor and assignment operator. Ensure that this
+ // class is non-copyable.
+ Client(const Client&);
+ const Client& operator=(const Client&);
+ };
+
+}
diff --git a/extras/sasl/m4/ac_pkg_swig.m4 b/extras/sasl/m4/ac_pkg_swig.m4
new file mode 100644
index 0000000000..3bff433f80
--- /dev/null
+++ b/extras/sasl/m4/ac_pkg_swig.m4
@@ -0,0 +1,118 @@
+# ===========================================================================
+# http://www.nongnu.org/autoconf-archive/ac_pkg_swig.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AC_PROG_SWIG([major.minor.micro])
+#
+# DESCRIPTION
+#
+# This macro searches for a SWIG installation on your system. If found you
+# should call SWIG via $(SWIG). You can use the optional first argument to
+# check if the version of the available SWIG is greater than or equal to
+# the value of the argument. It should have the format: N[.N[.N]] (N is a
+# number between 0 and 999. Only the first N is mandatory.)
+#
+# If the version argument is given (e.g. 1.3.17), AC_PROG_SWIG checks that
+# the swig package is this version number or higher.
+#
+# In configure.in, use as:
+#
+# AC_PROG_SWIG(1.3.17)
+# SWIG_ENABLE_CXX
+# SWIG_MULTI_MODULE_SUPPORT
+# SWIG_PYTHON
+#
+# LICENSE
+#
+# Copyright (c) 2008 Sebastian Huber <sebastian-huber@web.de>
+# Copyright (c) 2008 Alan W. Irwin <irwin@beluga.phys.uvic.ca>
+# Copyright (c) 2008 Rafael Laboissiere <rafael@laboissiere.net>
+# Copyright (c) 2008 Andrew Collier <colliera@ukzn.ac.za>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright owner
+# gives unlimited permission to copy, distribute and modify the configure
+# scripts that are the output of Autoconf when processing the Macro. You
+# need not follow the terms of the GNU General Public License when using
+# or distributing such scripts, even though portions of the text of the
+# Macro appear in them. The GNU General Public License (GPL) does govern
+# all other use of the material that constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the Autoconf
+# Macro released by the Autoconf Archive. When you make and distribute a
+# modified version of the Autoconf Macro, you may extend this special
+# exception to the GPL to apply to your modified version as well.
+
+AC_DEFUN([AC_PROG_SWIG],[
+ AC_PATH_PROG([SWIG],[swig])
+ if test -z "$SWIG" ; then
+ AC_MSG_WARN([cannot find 'swig' program. You should look at http://www.swig.org])
+ SWIG='echo "Error: SWIG is not installed. You should look at http://www.swig.org" ; false'
+ elif test -n "$1" ; then
+ AC_MSG_CHECKING([for SWIG version])
+ [swig_version=`$SWIG -version 2>&1 | grep 'SWIG Version' | sed 's/.*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/g'`]
+ AC_MSG_RESULT([$swig_version])
+ if test -n "$swig_version" ; then
+ # Calculate the required version number components
+ [required=$1]
+ [required_major=`echo $required | sed 's/[^0-9].*//'`]
+ if test -z "$required_major" ; then
+ [required_major=0]
+ fi
+ [required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
+ [required_minor=`echo $required | sed 's/[^0-9].*//'`]
+ if test -z "$required_minor" ; then
+ [required_minor=0]
+ fi
+ [required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
+ [required_patch=`echo $required | sed 's/[^0-9].*//'`]
+ if test -z "$required_patch" ; then
+ [required_patch=0]
+ fi
+ # Calculate the available version number components
+ [available=$swig_version]
+ [available_major=`echo $available | sed 's/[^0-9].*//'`]
+ if test -z "$available_major" ; then
+ [available_major=0]
+ fi
+ [available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
+ [available_minor=`echo $available | sed 's/[^0-9].*//'`]
+ if test -z "$available_minor" ; then
+ [available_minor=0]
+ fi
+ [available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
+ [available_patch=`echo $available | sed 's/[^0-9].*//'`]
+ if test -z "$available_patch" ; then
+ [available_patch=0]
+ fi
+ if test $available_major -ne $required_major \
+ -o $available_minor -ne $required_minor \
+ -o $available_patch -lt $required_patch ; then
+ AC_MSG_WARN([SWIG version >= $1 is required. You have $swig_version. You should look at http://www.swig.org])
+ SWIG='echo "Error: SWIG version >= $1 is required. You have '"$swig_version"'. You should look at http://www.swig.org" ; false'
+ else
+ AC_MSG_NOTICE([SWIG executable is '$SWIG'])
+ SWIG_LIB=`$SWIG -swiglib`
+ AC_MSG_NOTICE([SWIG library directory is '$SWIG_LIB'])
+ fi
+ else
+ AC_MSG_WARN([cannot determine SWIG version])
+ SWIG='echo "Error: Cannot determine SWIG version. You should look at http://www.swig.org" ; false'
+ fi
+ fi
+ AC_SUBST([SWIG_LIB])
+])
diff --git a/extras/sasl/m4/clock_time.m4 b/extras/sasl/m4/clock_time.m4
new file mode 100644
index 0000000000..227a5978e5
--- /dev/null
+++ b/extras/sasl/m4/clock_time.m4
@@ -0,0 +1,30 @@
+# clock_time.m4 serial 8
+dnl Copyright (C) 2002-2006 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# Check for clock_gettime and clock_settime, and set LIB_CLOCK_GETTIME.
+# For a program named, say foo, you should add a line like the following
+# in the corresponding Makefile.am file:
+# foo_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
+
+AC_DEFUN([gl_CLOCK_TIME],
+[
+ dnl Persuade glibc and Solaris <time.h> to declare these functions.
+ AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+
+ # Solaris 2.5.1 needs -lposix4 to get the clock_gettime function.
+ # Solaris 7 prefers the library name -lrt to the obsolescent name -lposix4.
+
+ # Save and restore LIBS so e.g., -lrt, isn't added to it. Otherwise, *all*
+ # programs in the package would end up linked with that potentially-shared
+ # library, inducing unnecessary run-time overhead.
+ gl_saved_libs=$LIBS
+ AC_SEARCH_LIBS(clock_gettime, [rt posix4],
+ [test "$ac_cv_search_clock_gettime" = "none required" ||
+ LIB_CLOCK_GETTIME=$ac_cv_search_clock_gettime])
+ AC_SUBST([LIB_CLOCK_GETTIME])
+ AC_CHECK_FUNCS(clock_gettime clock_settime)
+ LIBS=$gl_saved_libs
+])
diff --git a/extras/sasl/m4/compiler-flags.m4 b/extras/sasl/m4/compiler-flags.m4
new file mode 100644
index 0000000000..01cb728f02
--- /dev/null
+++ b/extras/sasl/m4/compiler-flags.m4
@@ -0,0 +1,23 @@
+# serial 3
+# Find valid warning flags for the C Compiler. -*-Autoconf-*-
+dnl Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl Written by Jesse Thilo.
+
+AC_DEFUN([gl_COMPILER_FLAGS],
+ [AC_MSG_CHECKING(whether compiler accepts $1)
+ AC_SUBST(COMPILER_FLAGS)
+ ac_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $1"
+ ac_save_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS="$CXXFLAGS $1"
+ AC_TRY_COMPILE(,
+ [int x;],
+ COMPILER_FLAGS="$COMPILER_FLAGS $1"
+ AC_MSG_RESULT(yes),
+ AC_MSG_RESULT(no))
+ CFLAGS="$ac_save_CFLAGS"
+ CXXFLAGS="$ac_save_CXXFLAGS"
+ ])
diff --git a/extras/sasl/m4/cppunit.m4 b/extras/sasl/m4/cppunit.m4
new file mode 100644
index 0000000000..f009086f9d
--- /dev/null
+++ b/extras/sasl/m4/cppunit.m4
@@ -0,0 +1,89 @@
+dnl
+dnl AM_PATH_CPPUNIT(MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl
+AC_DEFUN([AM_PATH_CPPUNIT],
+[
+
+AC_ARG_WITH(cppunit-prefix,[ --with-cppunit-prefix=PFX Prefix where CppUnit is installed (optional)],
+ cppunit_config_prefix="$withval", cppunit_config_prefix="")
+AC_ARG_WITH(cppunit-exec-prefix,[ --with-cppunit-exec-prefix=PFX Exec prefix where CppUnit is installed (optional)],
+ cppunit_config_exec_prefix="$withval", cppunit_config_exec_prefix="")
+
+ if test x$cppunit_config_exec_prefix != x ; then
+ cppunit_config_args="$cppunit_config_args --exec-prefix=$cppunit_config_exec_prefix"
+ if test x${CPPUNIT_CONFIG+set} != xset ; then
+ CPPUNIT_CONFIG=$cppunit_config_exec_prefix/bin/cppunit-config
+ fi
+ fi
+ if test x$cppunit_config_prefix != x ; then
+ cppunit_config_args="$cppunit_config_args --prefix=$cppunit_config_prefix"
+ if test x${CPPUNIT_CONFIG+set} != xset ; then
+ CPPUNIT_CONFIG=$cppunit_config_prefix/bin/cppunit-config
+ fi
+ fi
+
+ AC_PATH_PROG(CPPUNIT_CONFIG, cppunit-config, no)
+ cppunit_version_min=$1
+
+ AC_MSG_CHECKING(for Cppunit - version >= $cppunit_version_min)
+ no_cppunit=""
+ if test "$CPPUNIT_CONFIG" = "no" ; then
+ AC_MSG_RESULT(no)
+ no_cppunit=yes
+ else
+ CPPUNIT_CFLAGS=`$CPPUNIT_CONFIG --cflags`
+ CPPUNIT_LIBS=`$CPPUNIT_CONFIG --libs`
+ cppunit_version=`$CPPUNIT_CONFIG --version`
+
+ cppunit_major_version=`echo $cppunit_version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+ cppunit_minor_version=`echo $cppunit_version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+ cppunit_micro_version=`echo $cppunit_version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+
+ cppunit_major_min=`echo $cppunit_version_min | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+ if test "x${cppunit_major_min}" = "x" ; then
+ cppunit_major_min=0
+ fi
+
+ cppunit_minor_min=`echo $cppunit_version_min | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+ if test "x${cppunit_minor_min}" = "x" ; then
+ cppunit_minor_min=0
+ fi
+
+ cppunit_micro_min=`echo $cppunit_version_min | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+ if test "x${cppunit_micro_min}" = "x" ; then
+ cppunit_micro_min=0
+ fi
+
+ cppunit_version_proper=`expr \
+ $cppunit_major_version \> $cppunit_major_min \| \
+ $cppunit_major_version \= $cppunit_major_min \& \
+ $cppunit_minor_version \> $cppunit_minor_min \| \
+ $cppunit_major_version \= $cppunit_major_min \& \
+ $cppunit_minor_version \= $cppunit_minor_min \& \
+ $cppunit_micro_version \>= $cppunit_micro_min `
+
+ if test "$cppunit_version_proper" = "1" ; then
+ AC_MSG_RESULT([$cppunit_major_version.$cppunit_minor_version.$cppunit_micro_version])
+ else
+ AC_MSG_RESULT(no)
+ no_cppunit=yes
+ fi
+ fi
+
+ if test "x$no_cppunit" = x ; then
+ ifelse([$2], , :, [$2])
+ else
+ CPPUNIT_CFLAGS=""
+ CPPUNIT_LIBS=""
+ ifelse([$3], , :, [$3])
+ fi
+
+ AC_SUBST(CPPUNIT_CFLAGS)
+ AC_SUBST(CPPUNIT_LIBS)
+])
diff --git a/extras/sasl/m4/extensions.m4 b/extras/sasl/m4/extensions.m4
new file mode 100644
index 0000000000..fe7398b046
--- /dev/null
+++ b/extras/sasl/m4/extensions.m4
@@ -0,0 +1,59 @@
+# serial 5 -*- Autoconf -*-
+# Enable extensions on systems that normally disable them.
+
+# Copyright (C) 2003, 2006, 2008 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This definition of AC_USE_SYSTEM_EXTENSIONS is stolen from CVS
+# Autoconf. Perhaps we can remove this once we can assume Autoconf
+# 2.61 or later everywhere, but since CVS Autoconf mutates rapidly
+# enough in this area it's likely we'll need to redefine
+# AC_USE_SYSTEM_EXTENSIONS for quite some time.
+
+# AC_USE_SYSTEM_EXTENSIONS
+# ------------------------
+# Enable extensions on systems that normally disable them,
+# typically due to standards-conformance issues.
+m4_ifdef([AC_USE_SYSTEM_EXTENSIONS], [], [
+AC_DEFUN([AC_USE_SYSTEM_EXTENSIONS],
+[
+ AC_BEFORE([$0], [AC_COMPILE_IFELSE])
+ AC_BEFORE([$0], [AC_RUN_IFELSE])
+
+ AC_REQUIRE([AC_GNU_SOURCE])
+ AC_REQUIRE([AC_AIX])
+ AC_REQUIRE([AC_MINIX])
+
+ AH_VERBATIM([__EXTENSIONS__],
+[/* Enable extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif])
+ AC_CACHE_CHECK([whether it is safe to define __EXTENSIONS__],
+ [ac_cv_safe_to_define___extensions__],
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([
+# define __EXTENSIONS__ 1
+ AC_INCLUDES_DEFAULT])],
+ [ac_cv_safe_to_define___extensions__=yes],
+ [ac_cv_safe_to_define___extensions__=no])])
+ test $ac_cv_safe_to_define___extensions__ = yes &&
+ AC_DEFINE([__EXTENSIONS__])
+ AC_DEFINE([_POSIX_PTHREAD_SEMANTICS])
+ AC_DEFINE([_TANDEM_SOURCE])
+])])
+
+# gl_USE_SYSTEM_EXTENSIONS
+# ------------------------
+# Enable extensions on systems that normally disable them,
+# typically due to standards-conformance issues.
+AC_DEFUN([gl_USE_SYSTEM_EXTENSIONS],
+ [AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])])
diff --git a/extras/sasl/m4/libtool.m4 b/extras/sasl/m4/libtool.m4
new file mode 100644
index 0000000000..671cde117d
--- /dev/null
+++ b/extras/sasl/m4/libtool.m4
@@ -0,0 +1,7360 @@
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+m4_define([_LT_COPYING], [dnl
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+])
+
+# serial 56 LT_INIT
+
+
+# LT_PREREQ(VERSION)
+# ------------------
+# Complain and exit if this libtool version is less that VERSION.
+m4_defun([LT_PREREQ],
+[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
+ [m4_default([$3],
+ [m4_fatal([Libtool version $1 or higher is required],
+ 63)])],
+ [$2])])
+
+
+# _LT_CHECK_BUILDDIR
+# ------------------
+# Complain if the absolute build directory name contains unusual characters
+m4_defun([_LT_CHECK_BUILDDIR],
+[case `pwd` in
+ *\ * | *\ *)
+ AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
+esac
+])
+
+
+# LT_INIT([OPTIONS])
+# ------------------
+AC_DEFUN([LT_INIT],
+[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
+AC_BEFORE([$0], [LT_LANG])dnl
+AC_BEFORE([$0], [LT_OUTPUT])dnl
+AC_BEFORE([$0], [LTDL_INIT])dnl
+m4_require([_LT_CHECK_BUILDDIR])dnl
+
+dnl Autoconf doesn't catch unexpanded LT_ macros by default:
+m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
+m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
+dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
+dnl unless we require an AC_DEFUNed macro:
+AC_REQUIRE([LTOPTIONS_VERSION])dnl
+AC_REQUIRE([LTSUGAR_VERSION])dnl
+AC_REQUIRE([LTVERSION_VERSION])dnl
+AC_REQUIRE([LTOBSOLETE_VERSION])dnl
+m4_require([_LT_PROG_LTMAIN])dnl
+
+dnl Parse OPTIONS
+_LT_SET_OPTIONS([$0], [$1])
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+_LT_SETUP
+
+# Only expand once:
+m4_define([LT_INIT])
+])# LT_INIT
+
+# Old names:
+AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
+AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
+dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+m4_defun([_LT_CC_BASENAME],
+[for cc_temp in $1""; do
+ case $cc_temp in
+ compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+ distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+])
+
+
+# _LT_FILEUTILS_DEFAULTS
+# ----------------------
+# It is okay to use these file commands and assume they have been set
+# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
+m4_defun([_LT_FILEUTILS_DEFAULTS],
+[: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+])# _LT_FILEUTILS_DEFAULTS
+
+
+# _LT_SETUP
+# ---------
+m4_defun([_LT_SETUP],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+_LT_DECL([], [host_alias], [0], [The host system])dnl
+_LT_DECL([], [host], [0])dnl
+_LT_DECL([], [host_os], [0])dnl
+dnl
+_LT_DECL([], [build_alias], [0], [The build system])dnl
+_LT_DECL([], [build], [0])dnl
+_LT_DECL([], [build_os], [0])dnl
+dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+test -z "$LN_S" && LN_S="ln -s"
+_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+dnl
+AC_REQUIRE([LT_CMD_MAX_LEN])dnl
+_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
+_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
+dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_CMD_RELOAD])dnl
+m4_require([_LT_CHECK_MAGIC_METHOD])dnl
+m4_require([_LT_CMD_OLD_ARCHIVE])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+
+_LT_CONFIG_LIBTOOL_INIT([
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+])
+if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+_LT_CHECK_OBJDIR
+
+m4_require([_LT_TAG_COMPILER])dnl
+_LT_PROG_ECHO_BACKSLASH
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ _LT_PATH_MAGIC
+ fi
+ ;;
+esac
+
+# Use C for the default configuration in the libtool script
+LT_SUPPORTED_TAG([CC])
+_LT_LANG_C_CONFIG
+_LT_LANG_DEFAULT_CONFIG
+_LT_CONFIG_COMMANDS
+])# _LT_SETUP
+
+
+# _LT_PROG_LTMAIN
+# ---------------
+# Note that this code is called both from `configure', and `config.status'
+# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably,
+# `config.status' has no value for ac_aux_dir unless we are using Automake,
+# so we pass a copy along to make sure it has a sensible value anyway.
+m4_defun([_LT_PROG_LTMAIN],
+[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
+_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
+ltmain="$ac_aux_dir/ltmain.sh"
+])# _LT_PROG_LTMAIN
+
+
+## ------------------------------------- ##
+## Accumulate code for creating libtool. ##
+## ------------------------------------- ##
+
+# So that we can recreate a full libtool script including additional
+# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
+# in macros and then make a single call at the end using the `libtool'
+# label.
+
+
+# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
+# ----------------------------------------
+# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL_INIT],
+[m4_ifval([$1],
+ [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
+ [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_INIT])
+
+
+# _LT_CONFIG_LIBTOOL([COMMANDS])
+# ------------------------------
+# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL],
+[m4_ifval([$1],
+ [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
+ [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
+
+
+# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
+# -----------------------------------------------------
+m4_defun([_LT_CONFIG_SAVE_COMMANDS],
+[_LT_CONFIG_LIBTOOL([$1])
+_LT_CONFIG_LIBTOOL_INIT([$2])
+])
+
+
+# _LT_FORMAT_COMMENT([COMMENT])
+# -----------------------------
+# Add leading comment marks to the start of each line, and a trailing
+# full-stop to the whole comment if one is not present already.
+m4_define([_LT_FORMAT_COMMENT],
+[m4_ifval([$1], [
+m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
+ [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
+)])
+
+
+
+## ------------------------ ##
+## FIXME: Eliminate VARNAME ##
+## ------------------------ ##
+
+
+# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
+# -------------------------------------------------------------------
+# CONFIGNAME is the name given to the value in the libtool script.
+# VARNAME is the (base) name used in the configure script.
+# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
+# VARNAME. Any other value will be used directly.
+m4_define([_LT_DECL],
+[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
+ [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
+ [m4_ifval([$1], [$1], [$2])])
+ lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
+ m4_ifval([$4],
+ [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
+ lt_dict_add_subkey([lt_decl_dict], [$2],
+ [tagged?], [m4_ifval([$5], [yes], [no])])])
+])
+
+
+# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
+# --------------------------------------------------------
+m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
+
+
+# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_tag_varnames],
+[_lt_decl_filter([tagged?], [yes], $@)])
+
+
+# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
+# ---------------------------------------------------------
+m4_define([_lt_decl_filter],
+[m4_case([$#],
+ [0], [m4_fatal([$0: too few arguments: $#])],
+ [1], [m4_fatal([$0: too few arguments: $#: $1])],
+ [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
+ [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
+ [lt_dict_filter([lt_decl_dict], $@)])[]dnl
+])
+
+
+# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
+# --------------------------------------------------
+m4_define([lt_decl_quote_varnames],
+[_lt_decl_filter([value], [1], $@)])
+
+
+# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_dquote_varnames],
+[_lt_decl_filter([value], [2], $@)])
+
+
+# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_varnames_tagged],
+[m4_assert([$# <= 2])dnl
+_$0(m4_quote(m4_default([$1], [[, ]])),
+ m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
+ m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
+m4_define([_lt_decl_varnames_tagged],
+[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
+
+
+# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_all_varnames],
+[_$0(m4_quote(m4_default([$1], [[, ]])),
+ m4_if([$2], [],
+ m4_quote(lt_decl_varnames),
+ m4_quote(m4_shift($@))))[]dnl
+])
+m4_define([_lt_decl_all_varnames],
+[lt_join($@, lt_decl_varnames_tagged([$1],
+ lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
+])
+
+
+# _LT_CONFIG_STATUS_DECLARE([VARNAME])
+# ------------------------------------
+# Quote a variable value, and forward it to `config.status' so that its
+# declaration there will have the same value as in `configure'. VARNAME
+# must have a single quote delimited value for this to work.
+m4_define([_LT_CONFIG_STATUS_DECLARE],
+[$1='`$ECHO "X$][$1" | $Xsed -e "$delay_single_quote_subst"`'])
+
+
+# _LT_CONFIG_STATUS_DECLARATIONS
+# ------------------------------
+# We delimit libtool config variables with single quotes, so when
+# we write them to config.status, we have to be sure to quote all
+# embedded single quotes properly. In configure, this macro expands
+# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
+#
+# <var>='`$ECHO "X$<var>" | $Xsed -e "$delay_single_quote_subst"`'
+m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
+ [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAGS
+# ----------------
+# Output comment and list of tags supported by the script
+m4_defun([_LT_LIBTOOL_TAGS],
+[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
+available_tags="_LT_TAGS"dnl
+])
+
+
+# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
+# -----------------------------------
+# Extract the dictionary values for VARNAME (optionally with TAG) and
+# expand to a commented shell variable setting:
+#
+# # Some comment about what VAR is for.
+# visible_name=$lt_internal_name
+m4_define([_LT_LIBTOOL_DECLARE],
+[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
+ [description])))[]dnl
+m4_pushdef([_libtool_name],
+ m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
+m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
+ [0], [_libtool_name=[$]$1],
+ [1], [_libtool_name=$lt_[]$1],
+ [2], [_libtool_name=$lt_[]$1],
+ [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
+m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
+])
+
+
+# _LT_LIBTOOL_CONFIG_VARS
+# -----------------------
+# Produce commented declarations of non-tagged libtool config variables
+# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
+# script. Tagged libtool config variables (even for the LIBTOOL CONFIG
+# section) are produced by _LT_LIBTOOL_TAG_VARS.
+m4_defun([_LT_LIBTOOL_CONFIG_VARS],
+[m4_foreach([_lt_var],
+ m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
+ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAG_VARS(TAG)
+# -------------------------
+m4_define([_LT_LIBTOOL_TAG_VARS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
+ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+
+
+# _LT_TAGVAR(VARNAME, [TAGNAME])
+# ------------------------------
+m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+
+
+# _LT_CONFIG_COMMANDS
+# -------------------
+# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of
+# variables for single and double quote escaping we saved from calls
+# to _LT_DECL, we can put quote escaped variables declarations
+# into `config.status', and then the shell code to quote escape them in
+# for loops in `config.status'. Finally, any additional code accumulated
+# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
+m4_defun([_LT_CONFIG_COMMANDS],
+[AC_PROVIDE_IFELSE([LT_OUTPUT],
+ dnl If the libtool generation code has been placed in $CONFIG_LT,
+ dnl instead of duplicating it all over again into config.status,
+ dnl then we will have config.status run $CONFIG_LT later, so it
+ dnl needs to know what name is stored there:
+ [AC_CONFIG_COMMANDS([libtool],
+ [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
+ dnl If the libtool generation code is destined for config.status,
+ dnl expand the accumulated commands and init code now:
+ [AC_CONFIG_COMMANDS([libtool],
+ [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
+])#_LT_CONFIG_COMMANDS
+
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
+[
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+_LT_CONFIG_STATUS_DECLARATIONS
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# Quote evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_quote_varnames); do
+ case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
+ *[[\\\\\\\`\\"\\\$]]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Double-quote double-evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_dquote_varnames); do
+ case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
+ *[[\\\\\\\`\\"\\\$]]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Fix-up fallback echo if it was mangled by the above quoting rules.
+case \$lt_ECHO in
+*'\\\[$]0 --fallback-echo"')dnl "
+ lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\[$]0 --fallback-echo"\[$]/\[$]0 --fallback-echo"/'\`
+ ;;
+esac
+
+_LT_OUTPUT_LIBTOOL_INIT
+])
+
+
+# LT_OUTPUT
+# ---------
+# This macro allows early generation of the libtool script (before
+# AC_OUTPUT is called), incase it is used in configure for compilation
+# tests.
+AC_DEFUN([LT_OUTPUT],
+[: ${CONFIG_LT=./config.lt}
+AC_MSG_NOTICE([creating $CONFIG_LT])
+cat >"$CONFIG_LT" <<_LTEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate a libtool stub with the current configuration.
+
+lt_cl_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AS_SHELL_SANITIZE
+_AS_PREPARE
+
+exec AS_MESSAGE_FD>&1
+exec AS_MESSAGE_LOG_FD>>config.log
+{
+ echo
+ AS_BOX([Running $as_me.])
+} >&AS_MESSAGE_LOG_FD
+
+lt_cl_help="\
+\`$as_me' creates a local libtool stub from the current configuration,
+for use in further configure time tests before the real libtool is
+generated.
+
+Usage: $[0] [[OPTIONS]]
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+
+Report bugs to <bug-libtool@gnu.org>."
+
+lt_cl_version="\
+m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
+m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
+configured by $[0], generated by m4_PACKAGE_STRING.
+
+Copyright (C) 2008 Free Software Foundation, Inc.
+This config.lt script is free software; the Free Software Foundation
+gives unlimited permision to copy, distribute and modify it."
+
+while test $[#] != 0
+do
+ case $[1] in
+ --version | --v* | -V )
+ echo "$lt_cl_version"; exit 0 ;;
+ --help | --h* | -h )
+ echo "$lt_cl_help"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --quiet | --q* | --silent | --s* | -q )
+ lt_cl_silent=: ;;
+
+ -*) AC_MSG_ERROR([unrecognized option: $[1]
+Try \`$[0] --help' for more information.]) ;;
+
+ *) AC_MSG_ERROR([unrecognized argument: $[1]
+Try \`$[0] --help' for more information.]) ;;
+ esac
+ shift
+done
+
+if $lt_cl_silent; then
+ exec AS_MESSAGE_FD>/dev/null
+fi
+_LTEOF
+
+cat >>"$CONFIG_LT" <<_LTEOF
+_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AC_MSG_NOTICE([creating $ofile])
+_LT_OUTPUT_LIBTOOL_COMMANDS
+AS_EXIT(0)
+_LTEOF
+chmod +x "$CONFIG_LT"
+
+# configure is writing to config.log, but config.lt does its own redirection,
+# appending to config.log, which fails on DOS, as config.log is still kept
+# open by configure. Here we exec the FD to /dev/null, effectively closing
+# config.log, so it can be properly (re)opened and appended to by config.lt.
+if test "$no_create" != yes; then
+ lt_cl_success=:
+ test "$silent" = yes &&
+ lt_config_lt_args="$lt_config_lt_args --quiet"
+ exec AS_MESSAGE_LOG_FD>/dev/null
+ $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
+ exec AS_MESSAGE_LOG_FD>>config.log
+ $lt_cl_success || AS_EXIT(1)
+fi
+])# LT_OUTPUT
+
+
+# _LT_CONFIG(TAG)
+# ---------------
+# If TAG is the built-in tag, create an initial libtool script with a
+# default configuration from the untagged config vars. Otherwise add code
+# to config.status for appending the configuration named by TAG from the
+# matching tagged config vars.
+m4_defun([_LT_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_CONFIG_SAVE_COMMANDS([
+ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
+ m4_if(_LT_TAG, [C], [
+ # See if we are running on zsh, and set the options which allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile="${ofile}T"
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+_LT_COPYING
+_LT_LIBTOOL_TAGS
+
+# ### BEGIN LIBTOOL CONFIG
+_LT_LIBTOOL_CONFIG_VARS
+_LT_LIBTOOL_TAG_VARS
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+ case $host_os in
+ aix3*)
+ cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+_LT_EOF
+ ;;
+ esac
+
+ _LT_PROG_LTMAIN
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ _LT_PROG_XSI_SHELLFNS
+
+ sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ mv -f "$cfgfile" "$ofile" ||
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+],
+[cat <<_LT_EOF >> "$ofile"
+
+dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
+dnl in a comment (ie after a #).
+# ### BEGIN LIBTOOL TAG CONFIG: $1
+_LT_LIBTOOL_TAG_VARS(_LT_TAG)
+# ### END LIBTOOL TAG CONFIG: $1
+_LT_EOF
+])dnl /m4_if
+],
+[m4_if([$1], [], [
+ PACKAGE='$PACKAGE'
+ VERSION='$VERSION'
+ TIMESTAMP='$TIMESTAMP'
+ RM='$RM'
+ ofile='$ofile'], [])
+])dnl /_LT_CONFIG_SAVE_COMMANDS
+])# _LT_CONFIG
+
+
+# LT_SUPPORTED_TAG(TAG)
+# ---------------------
+# Trace this macro to discover what tags are supported by the libtool
+# --tag option, using:
+# autoconf --trace 'LT_SUPPORTED_TAG:$1'
+AC_DEFUN([LT_SUPPORTED_TAG], [])
+
+
+# C support is built-in for now
+m4_define([_LT_LANG_C_enabled], [])
+m4_define([_LT_TAGS], [])
+
+
+# LT_LANG(LANG)
+# -------------
+# Enable libtool support for the given language if not already enabled.
+AC_DEFUN([LT_LANG],
+[AC_BEFORE([$0], [LT_OUTPUT])dnl
+m4_case([$1],
+ [C], [_LT_LANG(C)],
+ [C++], [_LT_LANG(CXX)],
+ [Java], [_LT_LANG(GCJ)],
+ [Fortran 77], [_LT_LANG(F77)],
+ [Fortran], [_LT_LANG(FC)],
+ [Windows Resource], [_LT_LANG(RC)],
+ [m4_ifdef([_LT_LANG_]$1[_CONFIG],
+ [_LT_LANG($1)],
+ [m4_fatal([$0: unsupported language: "$1"])])])dnl
+])# LT_LANG
+
+
+# _LT_LANG(LANGNAME)
+# ------------------
+m4_defun([_LT_LANG],
+[m4_ifdef([_LT_LANG_]$1[_enabled], [],
+ [LT_SUPPORTED_TAG([$1])dnl
+ m4_append([_LT_TAGS], [$1 ])dnl
+ m4_define([_LT_LANG_]$1[_enabled], [])dnl
+ _LT_LANG_$1_CONFIG($1)])dnl
+])# _LT_LANG
+
+
+# _LT_LANG_DEFAULT_CONFIG
+# -----------------------
+m4_defun([_LT_LANG_DEFAULT_CONFIG],
+[AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [LT_LANG(CXX)],
+ [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_F77],
+ [LT_LANG(F77)],
+ [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_FC],
+ [LT_LANG(FC)],
+ [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
+
+dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
+dnl pulling things in needlessly.
+AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [m4_ifdef([AC_PROG_GCJ],
+ [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
+ m4_ifdef([A][M_PROG_GCJ],
+ [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
+ m4_ifdef([LT_PROG_GCJ],
+ [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
+
+AC_PROVIDE_IFELSE([LT_PROG_RC],
+ [LT_LANG(RC)],
+ [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
+])# _LT_LANG_DEFAULT_CONFIG
+
+# Obsolete macros:
+AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
+AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
+AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
+AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
+dnl AC_DEFUN([AC_LIBTOOL_F77], [])
+dnl AC_DEFUN([AC_LIBTOOL_FC], [])
+dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+
+
+# _LT_TAG_COMPILER
+# ----------------
+m4_defun([_LT_TAG_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
+_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
+_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
+_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_TAG_COMPILER
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+m4_defun([_LT_COMPILER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+m4_defun([_LT_LINKER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+])# _LT_LINKER_BOILERPLATE
+
+# _LT_REQUIRED_DARWIN_CHECKS
+# -------------------------
+m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
+ case $host_os in
+ rhapsody* | darwin*)
+ AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
+ AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
+ AC_CHECK_TOOL([LIPO], [lipo], [:])
+ AC_CHECK_TOOL([OTOOL], [otool], [:])
+ AC_CHECK_TOOL([OTOOL64], [otool64], [:])
+ _LT_DECL([], [DSYMUTIL], [1],
+ [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
+ _LT_DECL([], [NMEDIT], [1],
+ [Tool to change global to local symbols on Mac OS X])
+ _LT_DECL([], [LIPO], [1],
+ [Tool to manipulate fat objects and archives on Mac OS X])
+ _LT_DECL([], [OTOOL], [1],
+ [ldd/readelf like tool for Mach-O binaries on Mac OS X])
+ _LT_DECL([], [OTOOL64], [1],
+ [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
+
+ AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
+ [lt_cv_apple_cc_single_mod=no
+ if test -z "${LT_MULTI_MODULE}"; then
+ # By default we will add the -single_module flag. You can override
+ # by either setting the environment variable LT_MULTI_MODULE
+ # non-empty at configure time, or by adding -multi_module to the
+ # link flags.
+ rm -rf libconftest.dylib*
+ echo "int foo(void){return 1;}" > conftest.c
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+ _lt_result=$?
+ if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then
+ lt_cv_apple_cc_single_mod=yes
+ else
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ fi
+ rm -rf libconftest.dylib*
+ rm -f conftest.*
+ fi])
+ AC_CACHE_CHECK([for -exported_symbols_list linker flag],
+ [lt_cv_ld_exported_symbols_list],
+ [lt_cv_ld_exported_symbols_list=no
+ save_LDFLAGS=$LDFLAGS
+ echo "_main" > conftest.sym
+ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+ [lt_cv_ld_exported_symbols_list=yes],
+ [lt_cv_ld_exported_symbols_list=no])
+ LDFLAGS="$save_LDFLAGS"
+ ])
+ case $host_os in
+ rhapsody* | darwin1.[[012]])
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+ darwin1.*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ darwin*) # darwin 5.x on
+ # if running on 10.5 or later, the deployment target defaults
+ # to the OS version, if on x86, and 10.4, the deployment
+ # target defaults to 10.4. Don't you love it?
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+ 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ 10.[[012]]*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ 10.*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ esac
+ ;;
+ esac
+ if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+ _lt_dar_single_mod='$single_module'
+ fi
+ if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+ _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+ else
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ if test "$DSYMUTIL" != ":"; then
+ _lt_dsymutil='~$DSYMUTIL $lib || :'
+ else
+ _lt_dsymutil=
+ fi
+ ;;
+ esac
+])
+
+
+# _LT_DARWIN_LINKER_FEATURES
+# --------------------------
+# Checks for linker and compiler features on darwin
+m4_defun([_LT_DARWIN_LINKER_FEATURES],
+[
+ m4_require([_LT_REQUIRED_DARWIN_CHECKS])
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_automatic, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
+ case $cc_basename in
+ ifort*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test "$_lt_dar_can_shared" = "yes"; then
+ output_verbose_link_cmd=echo
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+ _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+ _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+ m4_if([$1], [CXX],
+[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+ fi
+],[])
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+])
+
+# _LT_SYS_MODULE_PATH_AIX
+# -----------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+m4_defun([_LT_SYS_MODULE_PATH_AIX],
+[m4_require([_LT_DECL_SED])dnl
+AC_LINK_IFELSE(AC_LANG_PROGRAM,[
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi],[])
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+])# _LT_SYS_MODULE_PATH_AIX
+
+
+# _LT_SHELL_INIT(ARG)
+# -------------------
+m4_define([_LT_SHELL_INIT],
+[ifdef([AC_DIVERSION_NOTICE],
+ [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)],
+ [AC_DIVERT_PUSH(NOTICE)])
+$1
+AC_DIVERT_POP
+])# _LT_SHELL_INIT
+
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Add some code to the start of the generated configure script which
+# will find an echo command which doesn't interpret backslashes.
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
+[_LT_SHELL_INIT([
+# Check that we are running under the correct shell.
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+case X$lt_ECHO in
+X*--fallback-echo)
+ # Remove one level of quotation (which was required for Make).
+ ECHO=`echo "$lt_ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','`
+ ;;
+esac
+
+ECHO=${lt_ECHO-echo}
+if test "X[$]1" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+elif test "X[$]1" = X--fallback-echo; then
+ # Avoid inline document here, it may be left over
+ :
+elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then
+ # Yippee, $ECHO works!
+ :
+else
+ # Restart under the correct shell.
+ exec $SHELL "[$]0" --no-reexec ${1+"[$]@"}
+fi
+
+if test "X[$]1" = X--fallback-echo; then
+ # used as fallback echo
+ shift
+ cat <<_LT_EOF
+[$]*
+_LT_EOF
+ exit 0
+fi
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test -z "$lt_ECHO"; then
+ if test "X${echo_test_string+set}" != Xset; then
+ # find a string as large as possible, as long as the shell can cope with it
+ for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do
+ # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+ if { echo_test_string=`eval $cmd`; } 2>/dev/null &&
+ { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null
+ then
+ break
+ fi
+ done
+ fi
+
+ if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ :
+ else
+ # The Solaris, AIX, and Digital Unix default echo programs unquote
+ # backslashes. This makes it impossible to quote backslashes using
+ # echo "$something" | sed 's/\\/\\\\/g'
+ #
+ # So, first we look for a working echo in the user's PATH.
+
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for dir in $PATH /usr/ucb; do
+ IFS="$lt_save_ifs"
+ if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
+ test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ ECHO="$dir/echo"
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+
+ if test "X$ECHO" = Xecho; then
+ # We didn't find a better echo, so look for alternatives.
+ if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ # This shell has a builtin print -r that does the trick.
+ ECHO='print -r'
+ elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } &&
+ test "X$CONFIG_SHELL" != X/bin/ksh; then
+ # If we have ksh, try running configure again with it.
+ ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+ export ORIGINAL_CONFIG_SHELL
+ CONFIG_SHELL=/bin/ksh
+ export CONFIG_SHELL
+ exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"}
+ else
+ # Try using printf.
+ ECHO='printf %s\n'
+ if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ # Cool, printf works
+ :
+ elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+ test "X$echo_testing_string" = 'X\t' &&
+ echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
+ export CONFIG_SHELL
+ SHELL="$CONFIG_SHELL"
+ export SHELL
+ ECHO="$CONFIG_SHELL [$]0 --fallback-echo"
+ elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+ test "X$echo_testing_string" = 'X\t' &&
+ echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ ECHO="$CONFIG_SHELL [$]0 --fallback-echo"
+ else
+ # maybe with a smaller string...
+ prev=:
+
+ for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do
+ if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null
+ then
+ break
+ fi
+ prev="$cmd"
+ done
+
+ if test "$prev" != 'sed 50q "[$]0"'; then
+ echo_test_string=`eval $prev`
+ export echo_test_string
+ exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"}
+ else
+ # Oops. We lost completely, so just stick with echo.
+ ECHO=echo
+ fi
+ fi
+ fi
+ fi
+ fi
+fi
+
+# Copy echo and quote the copy suitably for passing to libtool from
+# the Makefile, instead of quoting the original, which is used later.
+lt_ECHO=$ECHO
+if test "X$lt_ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then
+ lt_ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo"
+fi
+
+AC_SUBST(lt_ECHO)
+])
+_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
+_LT_DECL([], [ECHO], [1],
+ [An echo program that does not interpret backslashes])
+])# _LT_PROG_ECHO_BACKSLASH
+
+
+# _LT_ENABLE_LOCK
+# ---------------
+m4_defun([_LT_ENABLE_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+ [AS_HELP_STRING([--disable-libtool-lock],
+ [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE="32"
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE="64"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out which ABI we are using.
+ echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ ppc64-*linux*|powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ ppc*-*linux*|powerpc*-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*|s390*-*tpf*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -belf"
+ AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+ [AC_LANG_PUSH(C)
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+ AC_LANG_POP])
+ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ ;;
+sparc*-*solaris*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*) LD="${LD-ld} -m elf64_sparc" ;;
+ *)
+ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+ LD="${LD-ld} -64"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+esac
+
+need_locks="$enable_libtool_lock"
+])# _LT_ENABLE_LOCK
+
+
+# _LT_CMD_OLD_ARCHIVE
+# -------------------
+m4_defun([_LT_CMD_OLD_ARCHIVE],
+[AC_CHECK_TOOL(AR, ar, false)
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+_LT_DECL([], [AR], [1], [The archiver])
+_LT_DECL([], [AR_FLAGS], [1])
+
+AC_CHECK_TOOL(STRIP, strip, :)
+test -z "$STRIP" && STRIP=:
+_LT_DECL([], [STRIP], [1], [A symbol stripping program])
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+test -z "$RANLIB" && RANLIB=:
+_LT_DECL([], [RANLIB], [1],
+ [Commands used to install an old-style archive])
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+_LT_DECL([], [old_postinstall_cmds], [2])
+_LT_DECL([], [old_postuninstall_cmds], [2])
+_LT_TAGDECL([], [old_archive_cmds], [2],
+ [Commands used to build an old-style archive])
+])# _LT_CMD_OLD_ARCHIVE
+
+
+# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([_LT_COMPILER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$3"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ fi
+ $RM conftest*
+])
+
+if test x"[$]$2" = xyes; then
+ m4_if([$5], , :, [$5])
+else
+ m4_if([$6], , :, [$6])
+fi
+])# _LT_COMPILER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+
+
+# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------
+# Check whether the given linker option works
+AC_DEFUN([_LT_LINKER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $3"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&AS_MESSAGE_LOG_FD
+ $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ else
+ $2=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+ m4_if([$4], , :, [$4])
+else
+ m4_if([$5], , :, [$5])
+fi
+])# _LT_LINKER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
+
+
+# LT_CMD_MAX_LEN
+#---------------
+AC_DEFUN([LT_CMD_MAX_LEN],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+ i=0
+ teststring="ABCD"
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw* | cegcc*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+ if test -n "$lt_cv_sys_max_cmd_len"; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ # Make teststring a little bigger before we do anything with it.
+ # a 1K string should be a reasonable start.
+ for i in 1 2 3 4 5 6 7 8 ; do
+ teststring=$teststring$teststring
+ done
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \
+ = "XX$teststring$teststring"; } >/dev/null 2>&1 &&
+ test $i != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ # Only check the string length outside the loop.
+ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on
+ # massive amounts of additional arguments before passing them to the
+ # linker. It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+ AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+ AC_MSG_RESULT(none)
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+_LT_DECL([], [max_cmd_len], [0],
+ [What is the maximum length of a command?])
+])# LT_CMD_MAX_LEN
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+
+
+# _LT_HEADER_DLFCN
+# ----------------
+m4_defun([_LT_HEADER_DLFCN],
+[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
+])# _LT_HEADER_DLFCN
+
+
+# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ----------------------------------------------------------------
+m4_defun([_LT_TRY_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
+ [$4]
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+[#line __oline__ "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}]
+_LT_EOF
+ if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) $1 ;;
+ x$lt_dlneed_uscore) $2 ;;
+ x$lt_dlunknown|x*) $3 ;;
+ esac
+ else :
+ # compilation failed
+ $3
+ fi
+fi
+rm -fr conftest*
+])# _LT_TRY_DLOPEN_SELF
+
+
+# LT_SYS_DLOPEN_SELF
+# ------------------
+AC_DEFUN([LT_SYS_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32* | cegcc*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ])
+ ;;
+
+ *)
+ AC_CHECK_FUNC([shl_load],
+ [lt_cv_dlopen="shl_load"],
+ [AC_CHECK_LIB([dld], [shl_load],
+ [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
+ [AC_CHECK_FUNC([dlopen],
+ [lt_cv_dlopen="dlopen"],
+ [AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+ [AC_CHECK_LIB([svld], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+ [AC_CHECK_LIB([dld], [dld_link],
+ [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
+ ])
+ ])
+ ])
+ ])
+ ])
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ AC_CACHE_CHECK([whether a program can dlopen itself],
+ lt_cv_dlopen_self, [dnl
+ _LT_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+ lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+ ])
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+ lt_cv_dlopen_self_static, [dnl
+ _LT_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+ lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross)
+ ])
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+_LT_DECL([dlopen_support], [enable_dlopen], [0],
+ [Whether dlopen is supported])
+_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
+ [Whether dlopen of programs is supported])
+_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
+ [Whether dlopen of statically linked programs is supported])
+])# LT_SYS_DLOPEN_SELF
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+
+
+# _LT_COMPILER_C_O([TAGNAME])
+# ---------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler.
+# This macro does not hard code the compiler like AC_PROG_CC_C_O.
+m4_defun([_LT_COMPILER_C_O],
+[m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+ fi
+ fi
+ chmod u+w . 2>&AS_MESSAGE_LOG_FD
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+])
+_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
+ [Does compiler simultaneously support -c and -o options?])
+])# _LT_COMPILER_C_O
+
+
+# _LT_COMPILER_FILE_LOCKS([TAGNAME])
+# ----------------------------------
+# Check to see if we can do hard links to lock some files if needed
+m4_defun([_LT_COMPILER_FILE_LOCKS],
+[m4_require([_LT_ENABLE_LOCK])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_COMPILER_C_O([$1])
+
+hard_links="nottested"
+if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ AC_MSG_CHECKING([if we can lock with hard links])
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ AC_MSG_RESULT([$hard_links])
+ if test "$hard_links" = no; then
+ AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
+])# _LT_COMPILER_FILE_LOCKS
+
+
+# _LT_CHECK_OBJDIR
+# ----------------
+m4_defun([_LT_CHECK_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+_LT_DECL([], [objdir], [0],
+ [The name of the directory that contains temporary libtool files])dnl
+m4_pattern_allow([LT_OBJDIR])dnl
+AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
+ [Define to the sub-directory in which libtool stores uninstalled libraries.])
+])# _LT_CHECK_OBJDIR
+
+
+# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
+# --------------------------------------
+# Check hardcoding attributes.
+m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
+ test -n "$_LT_TAGVAR(runpath_var, $1)" ||
+ test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+
+ # We can hardcode non-existent directories.
+ if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+ test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
+ # Linking always hardcodes the temporary library directory.
+ _LT_TAGVAR(hardcode_action, $1)=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ _LT_TAGVAR(hardcode_action, $1)=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ _LT_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
+
+if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
+ test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+_LT_TAGDECL([], [hardcode_action], [0],
+ [How to hardcode a shared library path into an executable])
+])# _LT_LINKER_HARDCODE_LIBPATH
+
+
+# _LT_CMD_STRIPLIB
+# ----------------
+m4_defun([_LT_CMD_STRIPLIB],
+[m4_require([_LT_DECL_EGREP])
+striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ ;;
+ *)
+ AC_MSG_RESULT([no])
+ ;;
+ esac
+fi
+_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
+_LT_DECL([], [striplib], [1])
+])# _LT_CMD_STRIPLIB
+
+
+# _LT_SYS_DYNAMIC_LINKER([TAG])
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+m4_defun([_LT_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_OBJDUMP])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+m4_if([$1],
+ [], [
+if test "$GCC" = yes; then
+ case $host_os in
+ darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+ *) lt_awk_arg="/^libraries:/" ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary.
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+ else
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+ lt_foo="";
+ lt_count=0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo="/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+ if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+ sys_lib_search_path_spec=`$ECHO $lt_search_path_spec`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix[[4-9]]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[[01]] | aix4.[[01]].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[[45]]*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
+ # It is most probably a Windows format PATH printed by
+ # mingw gcc, but we are running on Cygwin. Gcc prints its search
+ # path with ; separators, and with drive letters. We can handle the
+ # drive letters (cygwin fileutils understands them), so leave them,
+ # especially as we might pass files found there to a mingw objdump,
+ # which wouldn't understand a cygwinified path. Ahh.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+m4_if([$1], [],[
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd1*)
+ dynamic_linker=no
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[[123]]*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555.
+ postinstall_cmds='chmod 555 $lib'
+ ;;
+
+interix[[3-9]]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ # Some binutils ld are patched to set DT_RUNPATH
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
+ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+ [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
+ [shlibpath_overrides_runpath=yes])])
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Add ABI-specific directories to the system library path.
+ sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib"
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
+ need_lib_prefix=no
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[[89]] | openbsd2.[[89]].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+ sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+ sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+_LT_DECL([], [variables_saved_for_relink], [1],
+ [Variables whose values should be saved in libtool wrapper scripts and
+ restored at link time])
+_LT_DECL([], [need_lib_prefix], [0],
+ [Do we need the "lib" prefix for modules?])
+_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
+_LT_DECL([], [version_type], [0], [Library versioning type])
+_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable])
+_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
+_LT_DECL([], [shlibpath_overrides_runpath], [0],
+ [Is shlibpath searched before the hard-coded library search path?])
+_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
+_LT_DECL([], [library_names_spec], [1],
+ [[List of archive names. First name is the real one, the rest are links.
+ The last name is the one that the linker finds with -lNAME]])
+_LT_DECL([], [soname_spec], [1],
+ [[The coded name of the library, if different from the real name]])
+_LT_DECL([], [postinstall_cmds], [2],
+ [Command to use after installation of a shared archive])
+_LT_DECL([], [postuninstall_cmds], [2],
+ [Command to use after uninstallation of a shared archive])
+_LT_DECL([], [finish_cmds], [2],
+ [Commands used to finish a libtool library installation in a directory])
+_LT_DECL([], [finish_eval], [1],
+ [[As "finish_cmds", except a single script fragment to be evaled but
+ not shown]])
+_LT_DECL([], [hardcode_into_libs], [0],
+ [Whether we should hardcode library paths into libraries])
+_LT_DECL([], [sys_lib_search_path_spec], [2],
+ [Compile-time system search path for libraries])
+_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
+ [Run-time system search path for libraries])
+])# _LT_SYS_DYNAMIC_LINKER
+
+
+# _LT_PATH_TOOL_PREFIX(TOOL)
+# --------------------------
+# find a file program which can recognize shared library
+AC_DEFUN([_LT_PATH_TOOL_PREFIX],
+[m4_require([_LT_DECL_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] | ?:[\\/]*])
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word. This closes a longstanding sh security hole.
+ ac_dummy="m4_if([$2], , $PATH, [$2])"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$1; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ AC_MSG_RESULT($MAGIC_CMD)
+else
+ AC_MSG_RESULT(no)
+fi
+_LT_DECL([], [MAGIC_CMD], [0],
+ [Used to examine libraries when file_magic_cmd begins with "file"])dnl
+])# _LT_PATH_TOOL_PREFIX
+
+# Old name:
+AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+
+
+# _LT_PATH_MAGIC
+# --------------
+# find a file program which can recognize a shared library
+m4_defun([_LT_PATH_MAGIC],
+[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+ else
+ MAGIC_CMD=:
+ fi
+fi
+])# _LT_PATH_MAGIC
+
+
+# LT_PATH_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([LT_PATH_LD],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+
+AC_ARG_WITH([gnu-ld],
+ [AS_HELP_STRING([--with-gnu-ld],
+ [assume the C compiler uses GNU ld @<:@default=no@:>@])],
+ [test "$withval" = no || with_gnu_ld=yes],
+ [with_gnu_ld=no])dnl
+
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ AC_MSG_CHECKING([for ld used by $CC])
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [[\\/]]* | ?:[[\\/]]*)
+ re_direlt='/[[^/]][[^/]]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ AC_MSG_CHECKING([for GNU ld])
+else
+ AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ AC_MSG_RESULT($LD)
+else
+ AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+_LT_PATH_LD_GNU
+AC_SUBST([LD])
+
+_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
+])# LT_PATH_LD
+
+# Old names:
+AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
+AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_LD], [])
+dnl AC_DEFUN([AC_PROG_LD], [])
+
+
+# _LT_PATH_LD_GNU
+#- --------------
+m4_defun([_LT_PATH_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# _LT_PATH_LD_GNU
+
+
+# _LT_CMD_RELOAD
+# --------------
+# find reload flag for linker
+# -- PORTME Some linkers may need a different reload flag.
+m4_defun([_LT_CMD_RELOAD],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+ lt_cv_ld_reload_flag,
+ [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ darwin*)
+ if test "$GCC" = yes; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+_LT_DECL([], [reload_flag], [1], [How to create reloadable object files])dnl
+_LT_DECL([], [reload_cmds], [2])dnl
+])# _LT_CMD_RELOAD
+
+
+# _LT_CHECK_MAGIC_METHOD
+# ----------------------
+# how to check for library dependencies
+# -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_MAGIC_METHOD],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[[4-9]]*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[[45]]*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ if ( file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
+ ;;
+
+cegcc)
+ # use the weaker test based on 'objdump'. See mingw*.
+ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case $host_cpu in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]']
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+interix[[3-9]]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+*nto* | *qnx*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+openbsd*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+rdos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.3*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+tpf*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+])
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+_LT_DECL([], [deplibs_check_method], [1],
+ [Method to check whether dependent libraries are shared objects])
+_LT_DECL([], [file_magic_cmd], [1],
+ [Command to use when deplibs_check_method == "file_magic"])
+])# _LT_CHECK_MAGIC_METHOD
+
+
+# LT_PATH_NM
+# ----------
+# find the pathname to a BSD- or MS-compatible name lister
+AC_DEFUN([LT_PATH_NM],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
+[if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM="$NM"
+else
+ lt_nm_to_check="${ac_tool_prefix}nm"
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm="$ac_dir/$lt_tmp_nm"
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+ */dev/null* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+ done
+ : ${lt_cv_path_NM=no}
+fi])
+if test "$lt_cv_path_NM" != "no"; then
+ NM="$lt_cv_path_NM"
+else
+ # Didn't find any BSD compatible name lister, look for dumpbin.
+ AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :)
+ AC_SUBST([DUMPBIN])
+ if test "$DUMPBIN" != ":"; then
+ NM="$DUMPBIN"
+ fi
+fi
+test -z "$NM" && NM=nm
+AC_SUBST([NM])
+_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
+
+AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
+ [lt_cv_nm_interface="BSD nm"
+ echo "int some_variable = 0;" > conftest.$ac_ext
+ (eval echo "\"\$as_me:__oline__: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$ac_compile" 2>conftest.err)
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ (eval echo "\"\$as_me:__oline__: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ (eval echo "\"\$as_me:__oline__: output\"" >&AS_MESSAGE_LOG_FD)
+ cat conftest.out >&AS_MESSAGE_LOG_FD
+ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+ lt_cv_nm_interface="MS dumpbin"
+ fi
+ rm -f conftest*])
+])# LT_PATH_NM
+
+# Old names:
+AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
+AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_NM], [])
+dnl AC_DEFUN([AC_PROG_NM], [])
+
+
+# LT_LIB_M
+# --------
+# check for math library
+AC_DEFUN([LT_LIB_M],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*)
+ # These system don't have libm, or don't need it
+ ;;
+*-ncr-sysv4.3*)
+ AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+ AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+ ;;
+*)
+ AC_CHECK_LIB(m, cos, LIBM="-lm")
+ ;;
+esac
+AC_SUBST([LIBM])
+])# LT_LIB_M
+
+# Old name:
+AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_CHECK_LIBM], [])
+
+
+# _LT_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------
+m4_defun([_LT_COMPILER_NO_RTTI],
+[m4_require([_LT_TAG_COMPILER])dnl
+
+_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+
+ _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+ lt_cv_prog_compiler_rtti_exceptions,
+ [-fno-rtti -fno-exceptions], [],
+ [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
+ [Compiler flag to turn off builtin functions])
+])# _LT_COMPILER_NO_RTTI
+
+
+# _LT_CMD_GLOBAL_SYMBOLS
+# ----------------------
+m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[[BCDT]]'
+ ;;
+cygwin* | mingw* | pw32* | cegcc*)
+ symcode='[[ABCDGISTW]]'
+ ;;
+hpux*)
+ if test "$host_cpu" = ia64; then
+ symcode='[[ABCDEGRST]]'
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[[BCDEGRST]]'
+ ;;
+osf*)
+ symcode='[[BCDEGQRST]]'
+ ;;
+solaris*)
+ symcode='[[BDRT]]'
+ ;;
+sco3.2v5*)
+ symcode='[[DT]]'
+ ;;
+sysv4.2uw2*)
+ symcode='[[DT]]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[[ABDT]]'
+ ;;
+sysv4)
+ symcode='[[DFNSTU]]'
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Fake it for dumpbin and say T for any non-static function
+ # and D for any global variable.
+ # Also find C++ and __fastcall symbols from MSVC++,
+ # which start with @ or ?.
+ lt_cv_sys_global_symbol_pipe="$AWK ['"\
+" {last_section=section; section=\$ 3};"\
+" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" \$ 0!~/External *\|/{next};"\
+" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+" {if(hide[section]) next};"\
+" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+" s[1]~/^[@?]/{print s[1], s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+" ' prfx=^$ac_symprfx]"
+ else
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ fi
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+ if AC_TRY_EVAL(ac_compile); then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<_LT_EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+ cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols. */
+const struct {
+ const char *name;
+ void *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[[]] =
+{
+ { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ cat <<\_LT_EOF >> conftest.$ac_ext
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_save_LIBS="$LIBS"
+ lt_save_CFLAGS="$CFLAGS"
+ LIBS="conftstm.$ac_objext"
+ CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+ if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+ pipe_works=yes
+ fi
+ LIBS="$lt_save_LIBS"
+ CFLAGS="$lt_save_CFLAGS"
+ else
+ echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+ cat conftest.$ac_ext >&5
+ fi
+ rm -rf conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ AC_MSG_RESULT(failed)
+else
+ AC_MSG_RESULT(ok)
+fi
+
+_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
+ [Take the output of nm and produce a listing of raw symbols and C names])
+_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
+ [Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_c_name_address],
+ [lt_cv_sys_global_symbol_to_c_name_address], [1],
+ [Transform the output of nm in a C name address pair])
+_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
+ [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
+ [Transform the output of nm in a C name address pair when lib prefix is needed])
+]) # _LT_CMD_GLOBAL_SYMBOLS
+
+
+# _LT_COMPILER_PIC([TAGNAME])
+# ---------------------------
+m4_defun([_LT_COMPILER_PIC],
+[m4_require([_LT_TAG_COMPILER])dnl
+_LT_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_TAGVAR(lt_prog_compiler_static, $1)=
+
+AC_MSG_CHECKING([for $compiler option to produce PIC])
+m4_if([$1], [CXX], [
+ # C++ specific cases for pic, static, wl, etc.
+ if test "$GXX" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+ mingw* | cygwin* | os2* | pw32* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+ *djgpp*)
+ # DJGPP does not support shared libraries at all
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ else
+ case $host_os in
+ aix[[4-9]]*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ cxch68*)
+ # Green Hills C++ Compiler
+ # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+ ;;
+ esac
+ ;;
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ freebsd* | dragonfly*)
+ # FreeBSD uses GNU C++
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ if test "$host_cpu" != ia64; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ fi
+ ;;
+ aCC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ interix*)
+ # This is c89, which is MS Visual C++ (no shared libs)
+ # Anyone wants to do a port?
+ ;;
+ irix5* | irix6* | nonstopux*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ # CC pic flag -KPIC is the default.
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ linux* | k*bsd*-gnu)
+ case $cc_basename in
+ KCC*)
+ # KAI C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ ecpc* )
+ # old Intel C++ for x86_64 which still supported -KPIC.
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ icpc* )
+ # Intel C++, used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ cxx*)
+ # Compaq C++
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ xlc* | xlC*)
+ # IBM XL 8.0 on PPC
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ lynxos*)
+ ;;
+ m88k*)
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ netbsd*)
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ cxx*)
+ # Digital/Compaq C++
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ psos*)
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ lcc*)
+ # Lucid
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ vxworks*)
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+],
+[
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC (with -KPIC) is the default.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu)
+ case $cc_basename in
+ # old Intel for x86_64 which still supported -KPIC.
+ ecc*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # icc used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ icc* | ifort*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # Lahey Fortran 8.1.
+ lf95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ ccc*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All Alpha code is PIC.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ xl*)
+ # IBM XL C 8.0/Fortran 10.1 on PPC
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C 5.9
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ ;;
+ *Sun\ F*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All OSF/1 code is PIC.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ rdos*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ solaris*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ unicos*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+
+ uts4*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *)
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+])
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
+ ;;
+esac
+AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
+_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
+ [How to pass a linker flag through the compiler])
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+ _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
+ [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
+ [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
+ "" | " "*) ;;
+ *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+ esac],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
+ [Additional compiler flags for building library objects])
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
+_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+ _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
+ $lt_tmp_static_flag,
+ [],
+ [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
+_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
+ [Compiler flag to prevent dynamic linking])
+])# _LT_COMPILER_PIC
+
+
+# _LT_LINKER_SHLIBS([TAGNAME])
+# ----------------------------
+# See if the linker supports building shared libraries.
+m4_defun([_LT_LINKER_SHLIBS],
+[AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+m4_if([$1], [CXX], [
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ case $host_os in
+ aix[[4-9]]*)
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ ;;
+ pw32*)
+ _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+ ;;
+ cygwin* | mingw* | cegcc*)
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ *)
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ esac
+ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+], [
+ runpath_var=
+ _LT_TAGVAR(allow_undefined_flag, $1)=
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(archive_cmds, $1)=
+ _LT_TAGVAR(archive_expsym_cmds, $1)=
+ _LT_TAGVAR(compiler_needs_object, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(hardcode_automatic, $1)=no
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ _LT_TAGVAR(hardcode_minus_L, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ _LT_TAGVAR(inherit_rpath, $1)=no
+ _LT_TAGVAR(link_all_deplibs, $1)=unknown
+ _LT_TAGVAR(module_cmds, $1)=
+ _LT_TAGVAR(module_expsym_cmds, $1)=
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)=
+ _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+ _LT_TAGVAR(thread_safe_flag_spec, $1)=
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ _LT_TAGVAR(include_expsyms, $1)=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ # Exclude shared library initialization/finalization symbols.
+dnl Note also adjust exclude_expsyms for C++ above.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ esac
+
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ if test "$with_gnu_ld" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>&1` in
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[[3-9]]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)=''
+ ;;
+ m68k)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ interix[[3-9]]*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu)
+ tmp_diet=no
+ if test "$host_os" = linux-dietlibc; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test "$tmp_diet" = no
+ then
+ tmp_addflag=
+ tmp_sharedflag='-shared'
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ lf95*) # Lahey Fortran 8.1
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ tmp_sharedflag='--shared' ;;
+ xl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+ tmp_sharedflag='-qmkshrobj'
+ tmp_addflag= ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+
+ case $cc_basename in
+ xlf*)
+ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ esac
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+
+ if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
+ runpath_var=
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ fi
+ ;;
+
+ aix[[4-9]]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_TAGVAR(archive_cmds, $1)=''
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ # This is similar to how AIX traditionally builds its shared libraries.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)=''
+ ;;
+ m68k)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ ;;
+
+ bsdi[[45]]*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ # FIXME: Should let the user specify the lib program.
+ _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+
+ darwin* | rhapsody*)
+ _LT_DARWIN_LINKER_FEATURES($1)
+ ;;
+
+ dgux*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ freebsd1*)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ ;;
+
+ hpux10*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+ AC_LINK_IFELSE(int foo(void) {},
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+ )
+ LDFLAGS="$save_LDFLAGS"
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(inherit_rpath, $1)=yes
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ newsos6)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ else
+ case $host_os in
+ openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ os2*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ else
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ solaris*)
+ _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
+ if test "$GCC" = yes; then
+ wlarc='${wl}'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='${wl}'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ ;;
+ motorola)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4.3*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+
+ if test x$host_vendor = xsni; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+])
+AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+
+_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
+_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
+_LT_DECL([], [extract_expsyms_cmds], [2],
+ [The commands to extract the exported symbol list from a shared archive])
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+ # Assume -lc should be added
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $_LT_TAGVAR(archive_cmds, $1) in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ AC_MSG_CHECKING([whether -lc should be explicitly linked in])
+ $RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
+ pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
+ _LT_TAGVAR(allow_undefined_flag, $1)=
+ if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
+ then
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ else
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ fi
+ _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+ AC_MSG_RESULT([$_LT_TAGVAR(archive_cmds_need_lc, $1)])
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
+ [Whether or not to add -lc for building shared libraries])
+_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
+ [enable_shared_with_static_runtimes], [0],
+ [Whether or not to disallow shared libs when runtime libs are static])
+_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
+ [Compiler flag to allow reflexive dlopens])
+_LT_TAGDECL([], [whole_archive_flag_spec], [1],
+ [Compiler flag to generate shared objects directly from archives])
+_LT_TAGDECL([], [compiler_needs_object], [1],
+ [Whether the compiler copes with passing no objects directly])
+_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
+ [Create an old-style archive from a shared archive])
+_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
+ [Create a temporary old-style archive to link instead of a shared archive])
+_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
+_LT_TAGDECL([], [archive_expsym_cmds], [2])
+_LT_TAGDECL([], [module_cmds], [2],
+ [Commands used to build a loadable module if different from building
+ a shared archive.])
+_LT_TAGDECL([], [module_expsym_cmds], [2])
+_LT_TAGDECL([], [with_gnu_ld], [1],
+ [Whether we are building with GNU ld or not])
+_LT_TAGDECL([], [allow_undefined_flag], [1],
+ [Flag that allows shared libraries with undefined symbols to be built])
+_LT_TAGDECL([], [no_undefined_flag], [1],
+ [Flag that enforces no undefined symbols])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
+ [Flag to hardcode $libdir into a binary during linking.
+ This must work even if $libdir does not exist])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1],
+ [[If ld is used when linking, flag to hardcode $libdir into a binary
+ during linking. This must work even if $libdir does not exist]])
+_LT_TAGDECL([], [hardcode_libdir_separator], [1],
+ [Whether we need a single "-rpath" flag with a separated argument])
+_LT_TAGDECL([], [hardcode_direct], [0],
+ [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+ DIR into the resulting binary])
+_LT_TAGDECL([], [hardcode_direct_absolute], [0],
+ [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+ DIR into the resulting binary and the resulting library dependency is
+ "absolute", i.e impossible to change by setting ${shlibpath_var} if the
+ library is relocated])
+_LT_TAGDECL([], [hardcode_minus_L], [0],
+ [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+ into the resulting binary])
+_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
+ [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+ into the resulting binary])
+_LT_TAGDECL([], [hardcode_automatic], [0],
+ [Set to "yes" if building a shared library automatically hardcodes DIR
+ into the library and all subsequent libraries and executables linked
+ against it])
+_LT_TAGDECL([], [inherit_rpath], [0],
+ [Set to yes if linker adds runtime paths of dependent libraries
+ to runtime path list])
+_LT_TAGDECL([], [link_all_deplibs], [0],
+ [Whether libtool must link a program against all its dependency libraries])
+_LT_TAGDECL([], [fix_srcfile_path], [1],
+ [Fix the shell variable $srcfile for the compiler])
+_LT_TAGDECL([], [always_export_symbols], [0],
+ [Set to "yes" if exported symbols are required])
+_LT_TAGDECL([], [export_symbols_cmds], [2],
+ [The commands to list exported symbols])
+_LT_TAGDECL([], [exclude_expsyms], [1],
+ [Symbols that should not be listed in the preloaded symbols])
+_LT_TAGDECL([], [include_expsyms], [1],
+ [Symbols that must always be exported])
+_LT_TAGDECL([], [prelink_cmds], [2],
+ [Commands necessary for linking programs (against libraries) with templates])
+_LT_TAGDECL([], [file_list_spec], [1],
+ [Specify filename containing input files])
+dnl FIXME: Not yet implemented
+dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
+dnl [Compiler flag to generate thread safe objects])
+])# _LT_LINKER_SHLIBS
+
+
+# _LT_LANG_C_CONFIG([TAG])
+# ------------------------
+# Ensure that the configuration variables for a C compiler are suitably
+# defined. These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_C_CONFIG],
+[m4_require([_LT_DECL_EGREP])dnl
+lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_TAG_COMPILER
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+ LT_SYS_DLOPEN_SELF
+ _LT_CMD_STRIPLIB
+
+ # Report which library types will actually be built
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+ aix[[4-9]]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_CONFIG($1)
+fi
+AC_LANG_POP
+CC="$lt_save_CC"
+])# _LT_LANG_C_CONFIG
+
+
+# _LT_PROG_CXX
+# ------------
+# Since AC_PROG_CXX is broken, in that it returns g++ if there is no c++
+# compiler, we have our own version here.
+m4_defun([_LT_PROG_CXX],
+[
+pushdef([AC_MSG_ERROR], [_lt_caught_CXX_error=yes])
+AC_PROG_CXX
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+ ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+ (test "X$CXX" != "Xg++"))) ; then
+ AC_PROG_CXXCPP
+else
+ _lt_caught_CXX_error=yes
+fi
+popdef([AC_MSG_ERROR])
+])# _LT_PROG_CXX
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([_LT_PROG_CXX], [])
+
+
+# _LT_LANG_CXX_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a C++ compiler are suitably
+# defined. These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_CXX_CONFIG],
+[AC_REQUIRE([_LT_PROG_CXX])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+
+AC_LANG_PUSH(C++)
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(compiler_needs_object, $1)=no
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_caught_CXX_error" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="int some_variable = 0;"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC=$CC
+ lt_save_LD=$LD
+ lt_save_GCC=$GCC
+ GCC=$GXX
+ lt_save_with_gnu_ld=$with_gnu_ld
+ lt_save_path_LD=$lt_cv_path_LD
+ if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+ lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+ else
+ $as_unset lt_cv_prog_gnu_ld
+ fi
+ if test -n "${lt_cv_path_LDCXX+set}"; then
+ lt_cv_path_LD=$lt_cv_path_LDCXX
+ else
+ $as_unset lt_cv_path_LD
+ fi
+ test -z "${LDCXX+set}" || LD=$LDCXX
+ CC=${CXX-"c++"}
+ compiler=$CC
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+
+ if test -n "$compiler"; then
+ # We don't want -fno-exception when compiling C++ code, so set the
+ # no_builtin_flag separately
+ if test "$GXX" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+ else
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+ fi
+
+ if test "$GXX" = yes; then
+ # Set up default GNU C++ configuration
+
+ LT_PATH_LD
+
+ # Check if GNU C++ uses GNU ld as the underlying linker, since the
+ # archiving commands below assume that GNU ld is being used.
+ if test "$with_gnu_ld" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+ # investigate it a little bit more. (MM)
+ wlarc='${wl}'
+
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+ $GREP 'no-whole-archive' > /dev/null; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ with_gnu_ld=no
+ wlarc=
+
+ # A generic and very simple default shared library creation
+ # command for GNU C++ for the case where it uses the native
+ # linker, instead of GNU ld. If possible, this setting should
+ # overridden to take advantage of the native linker features on
+ # the platform it is being used on.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ fi
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
+
+ else
+ GXX=no
+ with_gnu_ld=no
+ wlarc=
+ fi
+
+ # PORTME: fill in a description of your system's C++ link characteristics
+ AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ case $host_os in
+ aix3*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aix[[4-9]]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+ for ld_flag in $LDFLAGS; do
+ case $ld_flag in
+ *-brtl*)
+ aix_use_runtimelinking=yes
+ break
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_TAGVAR(archive_cmds, $1)=''
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+ if test "$GXX" = yes; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to
+ # export.
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # Determine the default libpath from the value encoded in an empty
+ # executable.
+ _LT_SYS_MODULE_PATH_AIX
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ # This is similar to how AIX traditionally builds its shared
+ # libraries.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ chorus*)
+ case $cc_basename in
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ darwin* | rhapsody*)
+ _LT_DARWIN_LINKER_FEATURES($1)
+ ;;
+
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ freebsd[[12]]*)
+ # C++ shared libraries reported to be fairly broken before
+ # switch to ELF
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ freebsd-elf*)
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ ;;
+
+ freebsd* | dragonfly*)
+ # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+ # conventions
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+
+ gnu*)
+ ;;
+
+ hpux9*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ hpux10*|hpux11*)
+ if test $with_gnu_ld = no; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ ;;
+ *)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ ;;
+ esac
+ fi
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+ ;;
+ esac
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test $with_gnu_ld = no; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ fi
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ interix[[3-9]]*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+ irix5* | irix6*)
+ case $cc_basename in
+ CC*)
+ # SGI C++
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+
+ # Archives containing C++ object files must be created using
+ # "CC -ar", where "CC" is the IRIX C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib'
+ fi
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+ esac
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(inherit_rpath, $1)=yes
+ ;;
+
+ linux* | k*bsd*-gnu)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+ ;;
+ icpc* | ecpc* )
+ # Intel C++
+ with_gnu_ld=yes
+ # version 8.0 and above of icpc choke on multiply defined symbols
+ # if we add $predep_objects and $postdep_objects, however 7.1 and
+ # earlier do not add the objects themselves.
+ case `$CC -V 2>&1` in
+ *"Version 7."*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ *) # Version 8.0 or newer
+ tmp_idyn=
+ case $host_cpu in
+ ia64*) tmp_idyn=' -i_dynamic';;
+ esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ esac
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ case `$CC -V` in
+ *pgCC\ [[1-5]]* | *pgcpp\ [[1-5]]*)
+ _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+ compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
+ _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
+ $RANLIB $oldlib'
+ _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 will use weak symbols
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+ ;;
+ cxx*)
+ # Compaq C++
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+ runpath_var=LD_RUN_PATH
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+ ;;
+ xl*)
+ # IBM XL 8.0 on PPC, with GNU ld
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+
+ # Not sure whether something based on
+ # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+ # would be better.
+ output_verbose_link_cmd='echo'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ lynxos*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ m88k*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+ wlarc=
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ fi
+ # Workaround some broken pre-1.5 toolchains
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+ ;;
+
+ *nto* | *qnx*)
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+
+ openbsd2*)
+ # C++ shared libraries are fairly broken
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ fi
+ output_verbose_link_cmd=echo
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Archives containing C++ object files must be created using
+ # the KAI C++ compiler.
+ case $host in
+ osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
+ *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
+ esac
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ cxx*)
+ case $host in
+ osf3*)
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ ;;
+ *)
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+ echo "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~
+ $RM $lib.exp'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+ ;;
+ *)
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ case $host in
+ osf3*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
+
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ psos*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ lcc*)
+ # Lucid
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ solaris*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
+ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ ;;
+ esac
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+
+ output_verbose_link_cmd='echo'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+ # The C++ compiler must be used to create the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+ ;;
+ *)
+ # GNU C++ compiler with Solaris linker
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+ if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
+ else
+ # g++ 2.7 appears to require `-G' NOT `-shared' on this
+ # platform.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
+ fi
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ vxworks*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+
+ AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+ test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+ _LT_TAGVAR(GCC, $1)="$GXX"
+ _LT_TAGVAR(LD, $1)="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_SYS_HIDDEN_LIBDEPS($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ CC=$lt_save_CC
+ LDCXX=$LD
+ LD=$lt_save_LD
+ GCC=$lt_save_GCC
+ with_gnu_ld=$lt_save_with_gnu_ld
+ lt_cv_path_LDCXX=$lt_cv_path_LD
+ lt_cv_path_LD=$lt_save_path_LD
+ lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+ lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test "$_lt_caught_CXX_error" != yes
+
+AC_LANG_POP
+])# _LT_LANG_CXX_CONFIG
+
+
+# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
+# ---------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+# Dependencies to place before and after the object being linked:
+_LT_TAGVAR(predep_objects, $1)=
+_LT_TAGVAR(postdep_objects, $1)=
+_LT_TAGVAR(predeps, $1)=
+_LT_TAGVAR(postdeps, $1)=
+_LT_TAGVAR(compiler_lib_search_path, $1)=
+
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library. It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
+int a;
+void foo (void) { a = 0; }
+_LT_EOF
+], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+ Foo (void) { a = 0; }
+private:
+ int a;
+};
+_LT_EOF
+], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
+ subroutine foo
+ implicit none
+ integer*4 a
+ a=0
+ return
+ end
+_LT_EOF
+], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
+ subroutine foo
+ implicit none
+ integer a
+ a=0
+ return
+ end
+_LT_EOF
+], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
+public class foo {
+ private int a;
+ public void bar (void) {
+ a = 0;
+ }
+};
+_LT_EOF
+])
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+ # Parse the compiler output and extract the necessary
+ # objects, libraries and library flags.
+
+ # Sentinel used to keep track of whether or not we are before
+ # the conftest object file.
+ pre_test_object_deps_done=no
+
+ for p in `eval "$output_verbose_link_cmd"`; do
+ case $p in
+
+ -L* | -R* | -l*)
+ # Some compilers place space between "-{L,R}" and the path.
+ # Remove the space.
+ if test $p = "-L" ||
+ test $p = "-R"; then
+ prev=$p
+ continue
+ else
+ prev=
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ case $p in
+ -L* | -R*)
+ # Internal compiler library paths should come after those
+ # provided the user. The postdeps already come after the
+ # user supplied libs so there is no need to process them.
+ if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
+ _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+ else
+ _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+ fi
+ ;;
+ # The "-l" case would never come before the object being
+ # linked, so don't bother handling this case.
+ esac
+ else
+ if test -z "$_LT_TAGVAR(postdeps, $1)"; then
+ _LT_TAGVAR(postdeps, $1)="${prev}${p}"
+ else
+ _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
+ fi
+ fi
+ ;;
+
+ *.$objext)
+ # This assumes that the test object file only shows up
+ # once in the compiler output.
+ if test "$p" = "conftest.$objext"; then
+ pre_test_object_deps_done=yes
+ continue
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
+ _LT_TAGVAR(predep_objects, $1)="$p"
+ else
+ _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
+ fi
+ else
+ if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
+ _LT_TAGVAR(postdep_objects, $1)="$p"
+ else
+ _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
+ fi
+ fi
+ ;;
+
+ *) ;; # Ignore the rest.
+
+ esac
+ done
+
+ # Clean up.
+ rm -f a.out a.exe
+else
+ echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$RM -f confest.$objext
+
+# PORTME: override above test on systems where it is broken
+m4_if([$1], [CXX],
+[case $host_os in
+interix[[3-9]]*)
+ # Interix 3.5 installs completely hosed .la files for C++, so rather than
+ # hack all around it, let's just trust "g++" to DTRT.
+ _LT_TAGVAR(predep_objects,$1)=
+ _LT_TAGVAR(postdep_objects,$1)=
+ _LT_TAGVAR(postdeps,$1)=
+ ;;
+
+linux*)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+
+ if test "$solaris_use_stlport4" != yes; then
+ _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+
+solaris*)
+ case $cc_basename in
+ CC*)
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+
+ # Adding this requires a known-good setup of shared libraries for
+ # Sun compiler versions before 5.6, else PIC objects from an old
+ # archive will be linked into the output, leading to subtle bugs.
+ if test "$solaris_use_stlport4" != yes; then
+ _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+esac
+])
+
+case " $_LT_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
+if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+fi
+_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
+ [The directories searched by this compiler when creating a shared library])
+_LT_TAGDECL([], [predep_objects], [1],
+ [Dependencies to place before and after the objects being linked to
+ create a shared library])
+_LT_TAGDECL([], [postdep_objects], [1])
+_LT_TAGDECL([], [predeps], [1])
+_LT_TAGDECL([], [postdeps], [1])
+_LT_TAGDECL([], [compiler_lib_search_path], [1],
+ [The library search path used internally by the compiler when linking
+ a shared library])
+])# _LT_SYS_HIDDEN_LIBDEPS
+
+
+# _LT_PROG_F77
+# ------------
+# Since AC_PROG_F77 is broken, in that it returns the empty string
+# if there is no fortran compiler, we have our own version here.
+m4_defun([_LT_PROG_F77],
+[
+pushdef([AC_MSG_ERROR], [_lt_disable_F77=yes])
+AC_PROG_F77
+if test -z "$F77" || test "X$F77" = "Xno"; then
+ _lt_disable_F77=yes
+fi
+popdef([AC_MSG_ERROR])
+])# _LT_PROG_F77
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([_LT_PROG_F77], [])
+
+
+# _LT_LANG_F77_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a Fortran 77 compiler are
+# suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_F77_CONFIG],
+[AC_REQUIRE([_LT_PROG_F77])dnl
+AC_LANG_PUSH(Fortran 77)
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the F77 compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_F77" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code="\
+ program t
+ end
+"
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC="$CC"
+ lt_save_GCC=$GCC
+ CC=${F77-"f77"}
+ compiler=$CC
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+ GCC=$G77
+ if test -n "$compiler"; then
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+ aix[[4-9]]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_TAGVAR(GCC, $1)="$G77"
+ _LT_TAGVAR(LD, $1)="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ GCC=$lt_save_GCC
+ CC="$lt_save_CC"
+fi # test "$_lt_disable_F77" != yes
+
+AC_LANG_POP
+])# _LT_LANG_F77_CONFIG
+
+
+# _LT_PROG_FC
+# -----------
+# Since AC_PROG_FC is broken, in that it returns the empty string
+# if there is no fortran compiler, we have our own version here.
+m4_defun([_LT_PROG_FC],
+[
+pushdef([AC_MSG_ERROR], [_lt_disable_FC=yes])
+AC_PROG_FC
+if test -z "$FC" || test "X$FC" = "Xno"; then
+ _lt_disable_FC=yes
+fi
+popdef([AC_MSG_ERROR])
+])# _LT_PROG_FC
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([_LT_PROG_FC], [])
+
+
+# _LT_LANG_FC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for a Fortran compiler are
+# suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_FC_CONFIG],
+[AC_REQUIRE([_LT_PROG_FC])dnl
+AC_LANG_PUSH(Fortran)
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for fc test sources.
+ac_ext=${ac_fc_srcext-f}
+
+# Object file extension for compiled fc test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the FC compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_FC" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code="\
+ program t
+ end
+"
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC="$CC"
+ lt_save_GCC=$GCC
+ CC=${FC-"f95"}
+ compiler=$CC
+ GCC=$ac_cv_fc_compiler_gnu
+
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+
+ if test -n "$compiler"; then
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+ aix[[4-9]]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
+ _LT_TAGVAR(LD, $1)="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_SYS_HIDDEN_LIBDEPS($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ GCC=$lt_save_GCC
+ CC="$lt_save_CC"
+fi # test "$_lt_disable_FC" != yes
+
+AC_LANG_POP
+])# _LT_LANG_FC_CONFIG
+
+
+# _LT_LANG_GCJ_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Java Compiler compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GCJ_CONFIG],
+[AC_REQUIRE([LT_PROG_GCJ])dnl
+AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GCJ-"gcj"}
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC="$lt_save_CC"
+])# _LT_LANG_GCJ_CONFIG
+
+
+# _LT_LANG_RC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for the Windows resource compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_RC_CONFIG],
+[AC_REQUIRE([LT_PROG_RC])dnl
+AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_GCC=$GCC
+GCC=
+CC=${RC-"windres"}
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+if test -n "$compiler"; then
+ :
+ _LT_CONFIG($1)
+fi
+
+GCC=$lt_save_GCC
+AC_LANG_RESTORE
+CC="$lt_save_CC"
+])# _LT_LANG_RC_CONFIG
+
+
+# LT_PROG_GCJ
+# -----------
+AC_DEFUN([LT_PROG_GCJ],
+[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
+ [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
+ [AC_CHECK_TOOL(GCJ, gcj,)
+ test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+ AC_SUBST(GCJFLAGS)])])[]dnl
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+
+
+# LT_PROG_RC
+# ----------
+AC_DEFUN([LT_PROG_RC],
+[AC_CHECK_TOOL(RC, windres,)
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_RC], [])
+
+
+# _LT_DECL_EGREP
+# --------------
+# If we don't have a new enough Autoconf to choose the best grep
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_EGREP],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_REQUIRE([AC_PROG_FGREP])dnl
+test -z "$GREP" && GREP=grep
+_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
+_LT_DECL([], [EGREP], [1], [An ERE matcher])
+_LT_DECL([], [FGREP], [1], [A literal string matcher])
+dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
+AC_SUBST([GREP])
+])
+
+
+# _LT_DECL_OBJDUMP
+# --------------
+# If we don't have a new enough Autoconf to choose the best objdump
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_OBJDUMP],
+[AC_CHECK_TOOL(OBJDUMP, objdump, false)
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
+AC_SUBST([OBJDUMP])
+])
+
+
+# _LT_DECL_SED
+# ------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible. Prefer GNU sed if found.
+m4_defun([_LT_DECL_SED],
+[AC_PROG_SED
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
+_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
+ [Sed that helps us avoid accidentally triggering echo(1) options like -n])
+])# _LT_DECL_SED
+
+m4_ifndef([AC_PROG_SED], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into #
+# GNU Autoconf as AC_PROG_SED. When it is available in #
+# a released version of Autoconf we should remove this #
+# macro and use it instead. #
+############################################################
+
+m4_defun([AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for lt_ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+ lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+ fi
+ done
+ done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+ test ! -f $lt_ac_sed && continue
+ cat /dev/null > conftest.in
+ lt_ac_count=0
+ echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+ # Check for GNU sed and select it if it is found.
+ if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+ lt_cv_path_SED=$lt_ac_sed
+ break
+ fi
+ while true; do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo >>conftest.nl
+ $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+ cmp -s conftest.out conftest.nl || break
+ # 10000 chars as input seems more than enough
+ test $lt_ac_count -gt 10 && break
+ lt_ac_count=`expr $lt_ac_count + 1`
+ if test $lt_ac_count -gt $lt_ac_max; then
+ lt_ac_max=$lt_ac_count
+ lt_cv_path_SED=$lt_ac_sed
+ fi
+ done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])#AC_PROG_SED
+])#m4_ifndef
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_SED], [])
+
+
+# _LT_CHECK_SHELL_FEATURES
+# ------------------------
+# Find out whether the shell is Bourne or XSI compatible,
+# or has some other useful features.
+m4_defun([_LT_CHECK_SHELL_FEATURES],
+[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+ test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \
+ = c,a/b,, \
+ && eval 'test $(( 1 + 1 )) -eq 2 \
+ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+ && xsi_shell=yes
+AC_MSG_RESULT([$xsi_shell])
+_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
+
+AC_MSG_CHECKING([whether the shell understands "+="])
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
+ >/dev/null 2>&1 \
+ && lt_shell_append=yes
+AC_MSG_RESULT([$lt_shell_append])
+_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ lt_unset=unset
+else
+ lt_unset=false
+fi
+_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ lt_SP2NL='tr \040 \012'
+ lt_NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ lt_SP2NL='tr \100 \n'
+ lt_NL2SP='tr \r\n \100\100'
+ ;;
+esac
+_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
+_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
+])# _LT_CHECK_SHELL_FEATURES
+
+
+# _LT_PROG_XSI_SHELLFNS
+# ---------------------
+# Bourne and XSI compatible variants of some useful shell functions.
+m4_defun([_LT_PROG_XSI_SHELLFNS],
+[case $xsi_shell in
+ yes)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac
+}
+
+# func_basename file
+func_basename ()
+{
+ func_basename_result="${1##*/}"
+}
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+# dirname: Compute the dirname of FILE. If nonempty,
+# add APPEND to the result, otherwise set result
+# to NONDIR_REPLACEMENT.
+# value returned in "$func_dirname_result"
+# basename: Compute filename of FILE.
+# value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac
+ func_basename_result="${1##*/}"
+}
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+func_stripname ()
+{
+ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+ # positional parameters, so assign one to ordinary parameter first.
+ func_stripname_result=${3}
+ func_stripname_result=${func_stripname_result#"${1}"}
+ func_stripname_result=${func_stripname_result%"${2}"}
+}
+
+# func_opt_split
+func_opt_split ()
+{
+ func_opt_split_opt=${1%%=*}
+ func_opt_split_arg=${1#*=}
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+ case ${1} in
+ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+ *) func_lo2o_result=${1} ;;
+ esac
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+ func_xform_result=${1%.*}.lo
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+ func_arith_result=$(( $[*] ))
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+ func_len_result=${#1}
+}
+
+_LT_EOF
+ ;;
+ *) # Bourne compatible functions.
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+ # Extract subdirectory from the argument.
+ func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"`
+ if test "X$func_dirname_result" = "X${1}"; then
+ func_dirname_result="${3}"
+ else
+ func_dirname_result="$func_dirname_result${2}"
+ fi
+}
+
+# func_basename file
+func_basename ()
+{
+ func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"`
+}
+
+dnl func_dirname_and_basename
+dnl A portable version of this function is already defined in general.m4sh
+dnl so there is no need for it here.
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+# func_strip_suffix prefix name
+func_stripname ()
+{
+ case ${2} in
+ .*) func_stripname_result=`$ECHO "X${3}" \
+ | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;;
+ *) func_stripname_result=`$ECHO "X${3}" \
+ | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;;
+ esac
+}
+
+# sed scripts:
+my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q'
+my_sed_long_arg='1s/^-[[^=]]*=//'
+
+# func_opt_split
+func_opt_split ()
+{
+ func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"`
+ func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"`
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+ func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"`
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+ func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[[^.]]*$/.lo/'`
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+ func_arith_result=`expr "$[@]"`
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+ func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len`
+}
+
+_LT_EOF
+esac
+
+case $lt_shell_append in
+ yes)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+ eval "$[1]+=\$[2]"
+}
+_LT_EOF
+ ;;
+ *)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+ eval "$[1]=\$$[1]\$[2]"
+}
+
+_LT_EOF
+ ;;
+ esac
+])
diff --git a/extras/sasl/m4/ltoptions.m4 b/extras/sasl/m4/ltoptions.m4
new file mode 100644
index 0000000000..34151a3ba6
--- /dev/null
+++ b/extras/sasl/m4/ltoptions.m4
@@ -0,0 +1,368 @@
+# Helper functions for option handling. -*- Autoconf -*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltoptions.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
+
+
+# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
+# ------------------------------------------
+m4_define([_LT_MANGLE_OPTION],
+[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
+
+
+# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
+# ---------------------------------------
+# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
+# matching handler defined, dispatch to it. Other OPTION-NAMEs are
+# saved as a flag.
+m4_define([_LT_SET_OPTION],
+[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
+m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
+ _LT_MANGLE_DEFUN([$1], [$2]),
+ [m4_warning([Unknown $1 option `$2'])])[]dnl
+])
+
+
+# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
+# ------------------------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+m4_define([_LT_IF_OPTION],
+[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
+
+
+# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
+# -------------------------------------------------------
+# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
+# are set.
+m4_define([_LT_UNLESS_OPTIONS],
+[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+ [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
+ [m4_define([$0_found])])])[]dnl
+m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
+])[]dnl
+])
+
+
+# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
+# ----------------------------------------
+# OPTION-LIST is a space-separated list of Libtool options associated
+# with MACRO-NAME. If any OPTION has a matching handler declared with
+# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
+# the unknown option and exit.
+m4_defun([_LT_SET_OPTIONS],
+[# Set options
+m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+ [_LT_SET_OPTION([$1], _LT_Option)])
+
+m4_if([$1],[LT_INIT],[
+ dnl
+ dnl Simply set some default values (i.e off) if boolean options were not
+ dnl specified:
+ _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
+ ])
+ _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
+ ])
+ dnl
+ dnl If no reference was made to various pairs of opposing options, then
+ dnl we run the default mode handler for the pair. For example, if neither
+ dnl `shared' nor `disable-shared' was passed, we enable building of shared
+ dnl archives by default:
+ _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
+ _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
+ _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
+ _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
+ [_LT_ENABLE_FAST_INSTALL])
+ ])
+])# _LT_SET_OPTIONS
+
+
+## --------------------------------- ##
+## Macros to handle LT_INIT options. ##
+## --------------------------------- ##
+
+# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
+# -----------------------------------------
+m4_define([_LT_MANGLE_DEFUN],
+[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
+
+
+# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
+# -----------------------------------------------
+m4_define([LT_OPTION_DEFINE],
+[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
+])# LT_OPTION_DEFINE
+
+
+# dlopen
+# ------
+LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
+])
+
+AU_DEFUN([AC_LIBTOOL_DLOPEN],
+[_LT_SET_OPTION([LT_INIT], [dlopen])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `dlopen' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
+
+
+# win32-dll
+# ---------
+# Declare package support for building win32 dll's.
+LT_OPTION_DEFINE([LT_INIT], [win32-dll],
+[enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*)
+ AC_CHECK_TOOL(AS, as, false)
+ AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+ AC_CHECK_TOOL(OBJDUMP, objdump, false)
+ ;;
+esac
+
+test -z "$AS" && AS=as
+_LT_DECL([], [AS], [0], [Assembler program])dnl
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl
+])# win32-dll
+
+AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+_LT_SET_OPTION([LT_INIT], [win32-dll])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `win32-dll' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
+
+
+# _LT_ENABLE_SHARED([DEFAULT])
+# ----------------------------
+# implement the --enable-shared flag, and supports the `shared' and
+# `disable-shared' LT_INIT options.
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_SHARED],
+[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([shared],
+ [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+ [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
+
+ _LT_DECL([build_libtool_libs], [enable_shared], [0],
+ [Whether or not to build shared libraries])
+])# _LT_ENABLE_SHARED
+
+LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
+])
+
+AC_DEFUN([AC_DISABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], [disable-shared])
+])
+
+AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_SHARED], [])
+dnl AC_DEFUN([AM_DISABLE_SHARED], [])
+
+
+
+# _LT_ENABLE_STATIC([DEFAULT])
+# ----------------------------
+# implement the --enable-static flag, and support the `static' and
+# `disable-static' LT_INIT options.
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_STATIC],
+[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([static],
+ [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+ [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
+
+ _LT_DECL([build_old_libs], [enable_static], [0],
+ [Whether or not to build static libraries])
+])# _LT_ENABLE_STATIC
+
+LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
+])
+
+AC_DEFUN([AC_DISABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], [disable-static])
+])
+
+AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_STATIC], [])
+dnl AC_DEFUN([AM_DISABLE_STATIC], [])
+
+
+
+# _LT_ENABLE_FAST_INSTALL([DEFAULT])
+# ----------------------------------
+# implement the --enable-fast-install flag, and support the `fast-install'
+# and `disable-fast-install' LT_INIT options.
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_FAST_INSTALL],
+[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([fast-install],
+ [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+ [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
+
+_LT_DECL([fast_install], [enable_fast_install], [0],
+ [Whether or not to optimize for fast installation])dnl
+])# _LT_ENABLE_FAST_INSTALL
+
+LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
+
+# Old names:
+AU_DEFUN([AC_ENABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `fast-install' option into LT_INIT's first parameter.])
+])
+
+AU_DEFUN([AC_DISABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `disable-fast-install' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
+dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+
+
+# _LT_WITH_PIC([MODE])
+# --------------------
+# implement the --with-pic flag, and support the `pic-only' and `no-pic'
+# LT_INIT options.
+# MODE is either `yes' or `no'. If omitted, it defaults to `both'.
+m4_define([_LT_WITH_PIC],
+[AC_ARG_WITH([pic],
+ [AS_HELP_STRING([--with-pic],
+ [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+ [pic_mode="$withval"],
+ [pic_mode=default])
+
+test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
+
+_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
+])# _LT_WITH_PIC
+
+LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
+
+# Old name:
+AU_DEFUN([AC_LIBTOOL_PICMODE],
+[_LT_SET_OPTION([LT_INIT], [pic-only])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `pic-only' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
+
+## ----------------- ##
+## LTDL_INIT Options ##
+## ----------------- ##
+
+m4_define([_LTDL_MODE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
+ [m4_define([_LTDL_MODE], [nonrecursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [recursive],
+ [m4_define([_LTDL_MODE], [recursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [subproject],
+ [m4_define([_LTDL_MODE], [subproject])])
+
+m4_define([_LTDL_TYPE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [installable],
+ [m4_define([_LTDL_TYPE], [installable])])
+LT_OPTION_DEFINE([LTDL_INIT], [convenience],
+ [m4_define([_LTDL_TYPE], [convenience])])
diff --git a/extras/sasl/m4/ltsugar.m4 b/extras/sasl/m4/ltsugar.m4
new file mode 100644
index 0000000000..9000a057d3
--- /dev/null
+++ b/extras/sasl/m4/ltsugar.m4
@@ -0,0 +1,123 @@
+# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltsugar.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
+
+
+# lt_join(SEP, ARG1, [ARG2...])
+# -----------------------------
+# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
+# associated separator.
+# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
+# versions in m4sugar had bugs.
+m4_define([lt_join],
+[m4_if([$#], [1], [],
+ [$#], [2], [[$2]],
+ [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
+m4_define([_lt_join],
+[m4_if([$#$2], [2], [],
+ [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
+
+
+# lt_car(LIST)
+# lt_cdr(LIST)
+# ------------
+# Manipulate m4 lists.
+# These macros are necessary as long as will still need to support
+# Autoconf-2.59 which quotes differently.
+m4_define([lt_car], [[$1]])
+m4_define([lt_cdr],
+[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
+ [$#], 1, [],
+ [m4_dquote(m4_shift($@))])])
+m4_define([lt_unquote], $1)
+
+
+# lt_append(MACRO-NAME, STRING, [SEPARATOR])
+# ------------------------------------------
+# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
+# Note that neither SEPARATOR nor STRING are expanded; they are appended
+# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
+# No SEPARATOR is output if MACRO-NAME was previously undefined (different
+# than defined and empty).
+#
+# This macro is needed until we can rely on Autoconf 2.62, since earlier
+# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
+m4_define([lt_append],
+[m4_define([$1],
+ m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
+
+
+
+# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
+# ----------------------------------------------------------
+# Produce a SEP delimited list of all paired combinations of elements of
+# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
+# has the form PREFIXmINFIXSUFFIXn.
+# Needed until we can rely on m4_combine added in Autoconf 2.62.
+m4_define([lt_combine],
+[m4_if(m4_eval([$# > 3]), [1],
+ [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
+[[m4_foreach([_Lt_prefix], [$2],
+ [m4_foreach([_Lt_suffix],
+ ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
+ [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
+
+
+# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
+# -----------------------------------------------------------------------
+# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
+# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
+m4_define([lt_if_append_uniq],
+[m4_ifdef([$1],
+ [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
+ [lt_append([$1], [$2], [$3])$4],
+ [$5])],
+ [lt_append([$1], [$2], [$3])$4])])
+
+
+# lt_dict_add(DICT, KEY, VALUE)
+# -----------------------------
+m4_define([lt_dict_add],
+[m4_define([$1($2)], [$3])])
+
+
+# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
+# --------------------------------------------
+m4_define([lt_dict_add_subkey],
+[m4_define([$1($2:$3)], [$4])])
+
+
+# lt_dict_fetch(DICT, KEY, [SUBKEY])
+# ----------------------------------
+m4_define([lt_dict_fetch],
+[m4_ifval([$3],
+ m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
+ m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
+
+
+# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------------------
+m4_define([lt_if_dict_fetch],
+[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
+ [$5],
+ [$6])])
+
+
+# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
+# --------------------------------------------------------------
+m4_define([lt_dict_filter],
+[m4_if([$5], [], [],
+ [lt_join(m4_quote(m4_default([$4], [[, ]])),
+ lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
+ [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
+])
diff --git a/extras/sasl/m4/ltversion.m4 b/extras/sasl/m4/ltversion.m4
new file mode 100644
index 0000000000..b8e154fe6e
--- /dev/null
+++ b/extras/sasl/m4/ltversion.m4
@@ -0,0 +1,23 @@
+# ltversion.m4 -- version numbers -*- Autoconf -*-
+#
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# Written by Scott James Remnant, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# Generated from ltversion.in.
+
+# serial 3012 ltversion.m4
+# This file is part of GNU Libtool
+
+m4_define([LT_PACKAGE_VERSION], [2.2.6])
+m4_define([LT_PACKAGE_REVISION], [1.3012])
+
+AC_DEFUN([LTVERSION_VERSION],
+[macro_version='2.2.6'
+macro_revision='1.3012'
+_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
+_LT_DECL(, macro_revision, 0)
+])
diff --git a/extras/sasl/m4/lt~obsolete.m4 b/extras/sasl/m4/lt~obsolete.m4
new file mode 100644
index 0000000000..637bb2066c
--- /dev/null
+++ b/extras/sasl/m4/lt~obsolete.m4
@@ -0,0 +1,92 @@
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
+# Written by Scott James Remnant, 2004.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 4 lt~obsolete.m4
+
+# These exist entirely to fool aclocal when bootstrapping libtool.
+#
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
+# which have later been changed to m4_define as they aren't part of the
+# exported API, or moved to Autoconf or Automake where they belong.
+#
+# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
+# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
+# using a macro with the same name in our local m4/libtool.m4 it'll
+# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
+# and doesn't know about Autoconf macros at all.)
+#
+# So we provide this file, which has a silly filename so it's always
+# included after everything else. This provides aclocal with the
+# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
+# because those macros already exist, or will be overwritten later.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
+#
+# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
+# Yes, that means every name once taken will need to remain here until
+# we give up compatibility with versions before 1.7, at which point
+# we need to keep only those names which we still refer to.
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+
+m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
+m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
+m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
+m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
+m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
+m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
+m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
+m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
+m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
+m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
+m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
+m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
+m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
+m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
+m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
+m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
+m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
+m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
+m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
+m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
+m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
+m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
+m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
+m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
+m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
+m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
+m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
+m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
+m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
+m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
+m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
+m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
+m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
+m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
+m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
+m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
+m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
+m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])])
+m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
+m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
+m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
+m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
+m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
+m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
+m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
+m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
diff --git a/extras/sasl/m4/python.m4 b/extras/sasl/m4/python.m4
new file mode 100644
index 0000000000..229fd5547b
--- /dev/null
+++ b/extras/sasl/m4/python.m4
@@ -0,0 +1,168 @@
+## ------------------------ -*- Autoconf -*-
+## Python file handling
+## From Andrew Dalke
+## Updated by James Henstridge
+## ------------------------
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PATH_PYTHON([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+# ---------------------------------------------------------------------------
+# Adds support for distributing Python modules and packages. To
+# install modules, copy them to $(pythondir), using the python_PYTHON
+# automake variable. To install a package with the same name as the
+# automake package, install to $(pkgpythondir), or use the
+# pkgpython_PYTHON automake variable.
+#
+# The variables $(pyexecdir) and $(pkgpyexecdir) are provided as
+# locations to install python extension modules (shared libraries).
+# Another macro is required to find the appropriate flags to compile
+# extension modules.
+#
+# If your package is configured with a different prefix to python,
+# users will have to add the install directory to the PYTHONPATH
+# environment variable, or create a .pth file (see the python
+# documentation for details).
+#
+# If the MINIMUM-VERSION argument is passed, AM_PATH_PYTHON will
+# cause an error if the version of python installed on the system
+# doesn't meet the requirement. MINIMUM-VERSION should consist of
+# numbers and dots only.
+AC_DEFUN([AM_PATH_PYTHON],
+ [
+ dnl Find a Python interpreter. Python versions prior to 1.5 are not
+ dnl supported because the default installation locations changed from
+ dnl $prefix/lib/site-python in 1.4 to $prefix/lib/python1.5/site-packages
+ dnl in 1.5.
+ m4_define_default([_AM_PYTHON_INTERPRETER_LIST],
+ [python python2 python2.5 python2.4 python2.3 python2.2 dnl
+python2.1 python2.0 python1.6 python1.5])
+
+ m4_if([$1],[],[
+ dnl No version check is needed.
+ # Find any Python interpreter.
+ if test -z "$PYTHON"; then
+ AC_PATH_PROGS([PYTHON], _AM_PYTHON_INTERPRETER_LIST, :)
+ fi
+ am_display_PYTHON=python
+ ], [
+ dnl A version check is needed.
+ if test -n "$PYTHON"; then
+ # If the user set $PYTHON, use it and don't search something else.
+ AC_MSG_CHECKING([whether $PYTHON version >= $1])
+ AM_PYTHON_CHECK_VERSION([$PYTHON], [$1],
+ [AC_MSG_RESULT(yes)],
+ [AC_MSG_ERROR(too old)])
+ am_display_PYTHON=$PYTHON
+ else
+ # Otherwise, try each interpreter until we find one that satisfies
+ # VERSION.
+ AC_CACHE_CHECK([for a Python interpreter with version >= $1],
+ [am_cv_pathless_PYTHON],[
+ for am_cv_pathless_PYTHON in _AM_PYTHON_INTERPRETER_LIST none; do
+ test "$am_cv_pathless_PYTHON" = none && break
+ AM_PYTHON_CHECK_VERSION([$am_cv_pathless_PYTHON], [$1], [break])
+ done])
+ # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON.
+ if test "$am_cv_pathless_PYTHON" = none; then
+ PYTHON=:
+ else
+ AC_PATH_PROG([PYTHON], [$am_cv_pathless_PYTHON])
+ fi
+ am_display_PYTHON=$am_cv_pathless_PYTHON
+ fi
+ ])
+
+ if test "$PYTHON" = :; then
+ dnl Run any user-specified action, or abort.
+ m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])])
+ else
+
+ dnl Query Python for its version number. Getting [:3] seems to be
+ dnl the best way to do this; it's what "site.py" does in the standard
+ dnl library.
+
+ AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version],
+ [am_cv_python_version=`$PYTHON -c "import sys; print sys.version[[:3]]"`])
+ AC_SUBST([PYTHON_VERSION], [$am_cv_python_version])
+
+ dnl Use the values of $prefix and $exec_prefix for the corresponding
+ dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made
+ dnl distinct variables so they can be overridden if need be. However,
+ dnl general consensus is that you shouldn't need this ability.
+
+ AC_SUBST([PYTHON_PREFIX], ['${prefix}'])
+ AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}'])
+
+ dnl At times (like when building shared libraries) you may want
+ dnl to know which OS platform Python thinks this is.
+
+ AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform],
+ [am_cv_python_platform=`$PYTHON -c "import sys; print sys.platform"`])
+ AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform])
+
+
+ dnl Set up 4 directories:
+
+ dnl pythondir -- where to install python scripts. This is the
+ dnl site-packages directory, not the python standard library
+ dnl directory like in previous automake betas. This behavior
+ dnl is more consistent with lispdir.m4 for example.
+ dnl Query distutils for this directory. distutils does not exist in
+ dnl Python 1.5, so we fall back to the hardcoded directory if it
+ dnl doesn't work.
+ AC_CACHE_CHECK([for $am_display_PYTHON script directory],
+ [am_cv_python_pythondir],
+ [am_cv_python_pythondir=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_python_lib(0,0,prefix='$PYTHON_PREFIX')" 2>/dev/null ||
+ echo "$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages"`])
+ AC_SUBST([pythondir], [$am_cv_python_pythondir])
+
+ dnl pkgpythondir -- $PACKAGE directory under pythondir. Was
+ dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is
+ dnl more consistent with the rest of automake.
+
+ AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE])
+
+ dnl pyexecdir -- directory for installing python extension modules
+ dnl (shared libraries)
+ dnl Query distutils for this directory. distutils does not exist in
+ dnl Python 1.5, so we fall back to the hardcoded directory if it
+ dnl doesn't work.
+ AC_CACHE_CHECK([for $am_display_PYTHON extension module directory],
+ [am_cv_python_pyexecdir],
+ [am_cv_python_pyexecdir=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_python_lib(1,0,prefix='$PYTHON_EXEC_PREFIX')" 2>/dev/null ||
+ echo "${PYTHON_EXEC_PREFIX}/lib/python${PYTHON_VERSION}/site-packages"`])
+ AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir])
+
+ dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE)
+
+ AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE])
+
+ dnl Run any user-specified action.
+ $2
+ fi
+
+])
+
+
+# AM_PYTHON_CHECK_VERSION(PROG, VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
+# ---------------------------------------------------------------------------
+# Run ACTION-IF-TRUE if the Python interpreter PROG has version >= VERSION.
+# Run ACTION-IF-FALSE otherwise.
+# This test uses sys.hexversion instead of the string equivalent (first
+# word of sys.version), in order to cope with versions such as 2.2c1.
+# hexversion has been introduced in Python 1.5.2; it's probably not
+# worth to support older versions (1.5.1 was released on October 31, 1998).
+AC_DEFUN([AM_PYTHON_CHECK_VERSION],
+ [prog="import sys, string
+# split strings by '.' and convert to numeric. Append some zeros
+# because we need at least 4 digits for the hex conversion.
+minver = map(int, string.split('$2', '.')) + [[0, 0, 0]]
+minverhex = 0
+for i in xrange(0, 4): minverhex = (minverhex << 8) + minver[[i]]
+sys.exit(sys.hexversion < minverhex)"
+ AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])])
diff --git a/extras/sasl/python/Makefile.am b/extras/sasl/python/Makefile.am
new file mode 100644
index 0000000000..67b608281f
--- /dev/null
+++ b/extras/sasl/python/Makefile.am
@@ -0,0 +1,43 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+if HAVE_SWIG
+if HAVE_PYTHON_DEVEL
+
+EXTRA_DIST = python.i
+INCLUDES = -I$(top_srcdir)/include
+
+generated_file_list = saslwrapper.cpp saslwrapper.py
+BUILT_SOURCES = $(generated_file_list)
+
+$(generated_file_list): python.i $(top_srcdir)/src/saslwrapper.i
+ $(SWIG) -c++ -python -Wall -I/usr/include $(INCLUDES) -o saslwrapper.cpp $(srcdir)/python.i
+
+pylibdir = $(PYTHON_LIB)
+lib_LTLIBRARIES = _saslwrapper.la
+
+_saslwrapper_la_LDFLAGS = -avoid-version -module -shared
+_saslwrapper_la_LIBADD = $(PYTHON_LIBS) $(top_builddir)/src/libsaslwrapper.la -lsasl2
+_saslwrapper_la_CXXFLAGS = -I$(PYTHON_INC)
+nodist__saslwrapper_la_SOURCES = saslwrapper.cpp
+
+CLEANFILES = $(generated_file_list)
+
+endif
+endif
diff --git a/extras/sasl/python/python.i b/extras/sasl/python/python.i
new file mode 100644
index 0000000000..9f4e7ee8af
--- /dev/null
+++ b/extras/sasl/python/python.i
@@ -0,0 +1,169 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 saslwrapper
+
+
+/* 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");
+ }
+}
+
+/* unsigned32 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);
+}
+
+%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;
+}
+
+/* Handle output arguments of type "output_string" */
+%typemap(in, numinputs=0) saslwrapper::output_string& (std::string temp) {
+ $1 = &temp;
+}
+
+%typemap(argout) saslwrapper::output_string& {
+ // Append output value $1 to $result
+ PyObject *o, *o2, *o3;
+ o = PyString_FromStringAndSize($1->c_str(), $1->length());
+ if ((!$result) || ($result == Py_None)) {
+ $result = o;
+ } else {
+ if (!PyTuple_Check($result)) {
+ PyObject *o2 = $result;
+ $result = PyTuple_New(1);
+ PyTuple_SetItem($result,0,o2);
+ }
+ o3 = PyTuple_New(1);
+ PyTuple_SetItem(o3,0,o);
+ o2 = $result;
+ $result = PySequence_Concat(o2,o3);
+ Py_DECREF(o2);
+ Py_DECREF(o3);
+ }
+}
+
+
+
+%include "../src/saslwrapper.i"
+
diff --git a/extras/sasl/ruby/Makefile.am b/extras/sasl/ruby/Makefile.am
new file mode 100644
index 0000000000..7112a647dc
--- /dev/null
+++ b/extras/sasl/ruby/Makefile.am
@@ -0,0 +1,43 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+if HAVE_SWIG
+if HAVE_RUBY_DEVEL
+
+EXTRA_DIST = ruby.i
+INCLUDES = -I$(top_srcdir)/include
+
+generated_file_list = saslwrapper.cpp
+BUILT_SOURCES = $(generated_file_list)
+
+$(generated_file_list): ruby.i $(top_srcdir)/src/saslwrapper.i
+ $(SWIG) -c++ -ruby -Wall -I/usr/include $(INCLUDES) -o saslwrapper.cpp $(srcdir)/ruby.i
+
+rubylibdir = $(RUBY_LIB)
+lib_LTLIBRARIES = saslwrapper.la
+
+saslwrapper_la_LDFLAGS = -avoid-version -module -shared ".$(RUBY_DLEXT)"
+saslwrapper_la_LIBADD = $(RUBY_LIBS) $(top_builddir)/src/libsaslwrapper.la -lsasl2
+saslwrapper_la_CXXFLAGS = $(INCLUDES) -I$(RUBY_INC) -I$(RUBY_INC_ARCH)
+nodist_saslwrapper_la_SOURCES = saslwrapper.cpp
+
+CLEANFILES = $(generated_file_list)
+
+endif
+endif
diff --git a/extras/sasl/ruby/ruby.i b/extras/sasl/ruby/ruby.i
new file mode 100644
index 0000000000..7c20f7f071
--- /dev/null
+++ b/extras/sasl/ruby/ruby.i
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 saslwrapper
+%include "typemaps.i"
+%include "stl.i"
+
+%{
+#include "saslwrapper.h"
+%}
+
+%typemap (in) void *
+{
+ $1 = (void *) $input;
+}
+
+%typemap (out) void *
+{
+ $result = (VALUE) $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) FIX2LONG($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);
+}
+
+%typemap (typecheck, precedence=SWIG_TYPECHECK_INTEGER) uint64_t {
+ $1 = FIXNUM_P($input);
+}
+
+namespace saslwrapper {
+ class Client {
+ public:
+
+ Client();
+ ~Client();
+ bool setAttr(const std::string& INPUT, const std::string& INPUT);
+ bool setAttr(const std::string& INPUT, uint32_t INPUT);
+ bool init();
+ bool start(const std::string& INPUT, std::string& OUTPUT, std::string& OUTPUT);
+ bool step(const std::string& INPUT, std::string& OUTPUT);
+ bool encode(const std::string& INPUT, std::string& OUTPUT);
+ bool decode(const std::string& INPUT, std::string& OUTPUT);
+ bool getUserId(std::string& OUTPUT);
+ void getError(std::string& OUTPUT);
+ };
+}
diff --git a/extras/sasl/src/Makefile.am b/extras/sasl/src/Makefile.am
new file mode 100644
index 0000000000..25529a3607
--- /dev/null
+++ b/extras/sasl/src/Makefile.am
@@ -0,0 +1,39 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+EXTRA_DIST = saslwrapper.i
+INCLUDES = -I$(top_srcdir)/include
+
+nobase_include_HEADERS = ../include/saslwrapper.h
+
+lib_LTLIBRARIES = libsaslwrapper.la
+libsaslwrapper_la_SOURCES = cyrus/saslwrapper.cpp
+
+# Library Version Information:
+#
+# CURRENT => API/ABI version. Bump this if the interface changes
+# REVISION => Version of underlying implementation.
+# Bump if implementation changes but API/ABI doesn't
+# AGE => Number of API/ABI versions this is backward compatible with
+#
+CURRENT = 1
+REVISION = 0
+AGE = 0
+
+libsaslwrapper_la_LDFLAGS = -version-info $(CURRENT):$(REVISION):$(AGE)
diff --git a/extras/sasl/src/cyrus/saslwrapper.cpp b/extras/sasl/src/cyrus/saslwrapper.cpp
new file mode 100644
index 0000000000..0243eaa168
--- /dev/null
+++ b/extras/sasl/src/cyrus/saslwrapper.cpp
@@ -0,0 +1,372 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+*/
+
+#include "saslwrapper.h"
+#include <sasl/sasl.h>
+#include <sstream>
+#include <malloc.h>
+#include <string.h>
+#include <unistd.h>
+#include <iostream>
+
+using namespace std;
+using namespace saslwrapper;
+
+namespace saslwrapper {
+
+ class ClientImpl {
+ friend class Client;
+ ClientImpl() : conn(0), cbIndex(0), maxBufSize(65535), minSsf(0), maxSsf(65535), externalSsf(0), secret(0) {}
+ ~ClientImpl() { if (conn) sasl_dispose(&conn); conn = 0; }
+ bool setAttr(const string& key, const string& value);
+ bool setAttr(const string& key, uint32_t value);
+ bool init();
+ bool start(const string& mechList, output_string& chosen, output_string& initialResponse);
+ bool step(const string& challenge, output_string& response);
+ bool encode(const string& clearText, output_string& cipherText);
+ bool decode(const string& cipherText, output_string& clearText);
+ bool getUserId(output_string& userId);
+ void getError(output_string& error);
+
+ void addCallback(unsigned long id, void* proc);
+ void lastCallback() { addCallback(SASL_CB_LIST_END, 0); }
+ void setError(const string& context, int code, const string& text = "", const string& text2 = "");
+ void interact(sasl_interact_t* prompt);
+
+ static int cbName(void *context, int id, const char **result, unsigned *len);
+ static int cbPassword(sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret);
+
+ static bool initialized;
+ sasl_conn_t* conn;
+ sasl_callback_t callbacks[8];
+ int cbIndex;
+ string error;
+ string serviceName;
+ string userName;
+ string authName;
+ string password;
+ string hostName;
+ string externalUserName;
+ uint32_t maxBufSize;
+ uint32_t minSsf;
+ uint32_t maxSsf;
+ uint32_t externalSsf;
+ sasl_secret_t* secret;
+ };
+}
+
+bool ClientImpl::initialized = false;
+
+bool ClientImpl::init()
+{
+ int result;
+
+ if (!initialized) {
+ initialized = true;
+ result = sasl_client_init(0);
+ if (result != SASL_OK) {
+ setError("sasl_client_init", result, sasl_errstring(result, 0, 0));
+ return false;
+ }
+ }
+
+ int cbIndex = 0;
+
+ addCallback(SASL_CB_GETREALM, 0);
+ if (!userName.empty()) {
+ addCallback(SASL_CB_USER, (void*) cbName);
+ addCallback(SASL_CB_AUTHNAME, (void*) cbName);
+
+ if (!password.empty())
+ addCallback(SASL_CB_PASS, (void*) cbPassword);
+ else
+ addCallback(SASL_CB_PASS, 0);
+ }
+ lastCallback();
+
+ unsigned flags;
+
+ flags = 0;
+ if (!authName.empty() && authName != userName)
+ flags |= SASL_NEED_PROXY;
+
+ result = sasl_client_new(serviceName.c_str(), hostName.c_str(), 0, 0, callbacks, flags, &conn);
+ if (result != SASL_OK) {
+ setError("sasl_client_new", result, sasl_errstring(result, 0, 0));
+ return false;
+ }
+
+ sasl_security_properties_t secprops;
+
+ secprops.min_ssf = minSsf;
+ secprops.max_ssf = maxSsf;
+ secprops.maxbufsize = maxBufSize;
+ secprops.property_names = 0;
+ secprops.property_values = 0;
+ secprops.security_flags = 0;
+
+ result = sasl_setprop(conn, SASL_SEC_PROPS, &secprops);
+ if (result != SASL_OK) {
+ setError("sasl_setprop(SASL_SEC_PROPS)", result);
+ sasl_dispose(&conn);
+ conn = 0;
+ return false;
+ }
+
+ if (!externalUserName.empty()) {
+ result = sasl_setprop(conn, SASL_AUTH_EXTERNAL, externalUserName.c_str());
+ if (result != SASL_OK) {
+ setError("sasl_setprop(SASL_AUTH_EXTERNAL)", result);
+ sasl_dispose(&conn);
+ conn = 0;
+ return false;
+ }
+
+ result = sasl_setprop(conn, SASL_SSF_EXTERNAL, &externalSsf);
+ if (result != SASL_OK) {
+ setError("sasl_setprop(SASL_SSF_EXTERNAL)", result);
+ sasl_dispose(&conn);
+ conn = 0;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool ClientImpl::setAttr(const string& key, const string& value)
+{
+ if (key == "service")
+ serviceName = value;
+ else if (key == "username")
+ userName = value;
+ else if (key == "authname")
+ authName = value;
+ else if (key == "password") {
+ password = value;
+ free(secret);
+ secret = (sasl_secret_t*) malloc(sizeof(sasl_secret_t) + password.length());
+ }
+ else if (key == "host")
+ hostName = value;
+ else if (key == "externaluser")
+ externalUserName = value;
+ else {
+ setError("setAttr", -1, "Unknown string attribute name", key);
+ return false;
+ }
+
+ return true;
+}
+
+bool ClientImpl::setAttr(const string& key, uint32_t value)
+{
+ if (key == "minssf")
+ minSsf = value;
+ else if (key == "maxssf")
+ maxSsf = value;
+ else if (key == "externalssf")
+ externalSsf = value;
+ else if (key == "maxbufsize")
+ maxBufSize = value;
+ else {
+ setError("setAttr", -1, "Unknown integer attribute name", key);
+ return false;
+ }
+
+ return true;
+}
+
+bool ClientImpl::start(const string& mechList, output_string& chosen, output_string& initialResponse)
+{
+ int result;
+ sasl_interact_t* prompt = 0;
+ const char* resp;
+ const char* mech;
+ unsigned int len;
+
+ do {
+ result = sasl_client_start(conn, mechList.c_str(), &prompt, &resp, &len, &mech);
+ if (result == SASL_INTERACT)
+ interact(prompt);
+ } while (result == SASL_INTERACT);
+ if (result != SASL_OK && result != SASL_CONTINUE) {
+ setError("sasl_client_start", result);
+ return false;
+ }
+
+ chosen = string(mech);
+ initialResponse = string(resp, len);
+ return true;
+}
+
+bool ClientImpl::step(const string& challenge, output_string& response)
+{
+ int result;
+ sasl_interact_t* prompt = 0;
+ const char* resp;
+ unsigned int len;
+
+ do {
+ result = sasl_client_step(conn, challenge.c_str(), challenge.size(), &prompt, &resp, &len);
+ if (result == SASL_INTERACT)
+ interact(prompt);
+ } while (result == SASL_INTERACT);
+ if (result != SASL_OK && result != SASL_CONTINUE) {
+ setError("sasl_client_step", result);
+ return false;
+ }
+
+ response = string(resp, len);
+ return true;
+}
+
+bool ClientImpl::encode(const string& clearText, output_string& cipherText)
+{
+ const char* output;
+ unsigned int outlen;
+ int result = sasl_encode(conn, clearText.c_str(), clearText.size(), &output, &outlen);
+ if (result != SASL_OK) {
+ setError("sasl_encode", result);
+ return false;
+ }
+ cipherText = string(output, outlen);
+ return true;
+}
+
+bool ClientImpl::decode(const string& cipherText, output_string& clearText)
+{
+ const char* output;
+ unsigned int outlen;
+ int result = sasl_decode(conn, cipherText.c_str(), cipherText.size(), &output, &outlen);
+ if (result != SASL_OK) {
+ setError("sasl_decode", result);
+ return false;
+ }
+ clearText = string(output, outlen);
+ return true;
+}
+
+bool ClientImpl::getUserId(output_string& userId)
+{
+ int result;
+ const char* operName;
+
+ result = sasl_getprop(conn, SASL_USERNAME, (const void**) &operName);
+ if (result != SASL_OK) {
+ setError("sasl_getprop(SASL_USERNAME)", result);
+ return false;
+ }
+
+ userId = string(operName);
+ return true;
+}
+
+void ClientImpl::getError(output_string& _error)
+{
+ _error = error;
+ error.clear();
+}
+
+void ClientImpl::addCallback(unsigned long id, void* proc)
+{
+ callbacks[cbIndex].id = id;
+ callbacks[cbIndex].proc = (int (*)()) proc;
+ callbacks[cbIndex].context = this;
+ cbIndex++;
+}
+
+void ClientImpl::setError(const string& context, int code, const string& text, const string& text2)
+{
+ stringstream err;
+ string etext(text.empty() ? sasl_errdetail(conn) : text);
+ err << "Error in " << context << " (" << code << ") " << etext;
+ if (!text2.empty())
+ err << " - " << text2;
+ error = err.str();
+}
+
+void ClientImpl::interact(sasl_interact_t* prompt)
+{
+ string output;
+ char* input;
+
+ if (prompt->id == SASL_CB_PASS) {
+ string ppt(prompt->prompt);
+ ppt += ": ";
+ char* pass = getpass(ppt.c_str());
+ output = string(pass);
+ } else {
+ cout << prompt->prompt;
+ if (prompt->defresult)
+ cout << " [" << prompt->defresult << "]";
+ cout << ": ";
+ cin >> output;
+ }
+ prompt->result = output.c_str();
+ prompt->len = output.length();
+}
+
+int ClientImpl::cbName(void *context, int id, const char **result, unsigned *len)
+{
+ ClientImpl* impl = (ClientImpl*) context;
+
+ if (id == SASL_CB_USER || (id == SASL_CB_AUTHNAME && impl->authName.empty())) {
+ *result = impl->userName.c_str();
+ //*len = impl->userName.length();
+ } else if (id == SASL_CB_AUTHNAME) {
+ *result = impl->authName.c_str();
+ //*len = impl->authName.length();
+ }
+
+ return SASL_OK;
+}
+
+int ClientImpl::cbPassword(sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret)
+{
+ ClientImpl* impl = (ClientImpl*) context;
+ size_t length = impl->password.length();
+
+ if (id == SASL_CB_PASS) {
+ impl->secret->len = length;
+ ::memcpy(impl->secret->data, impl->password.c_str(), length);
+ } else
+ impl->secret->len = 0;
+
+ *psecret = impl->secret;
+ return SASL_OK;
+}
+
+
+//==========================================================
+// WRAPPERS
+//==========================================================
+
+Client::Client() : impl(new ClientImpl()) {}
+Client::~Client() { delete impl; }
+bool Client::setAttr(const string& key, const string& value) { return impl->setAttr(key, value); }
+bool Client::setAttr(const string& key, uint32_t value) { return impl->setAttr(key, value); }
+bool Client::init() { return impl->init(); }
+bool Client::start(const string& mechList, output_string& chosen, output_string& initialResponse) { return impl->start(mechList, chosen, initialResponse); }
+bool Client::step(const string& challenge, output_string& response) { return impl->step(challenge, response); }
+bool Client::encode(const string& clearText, output_string& cipherText) { return impl->encode(clearText, cipherText); }
+bool Client::decode(const string& cipherText, output_string& clearText) { return impl->decode(cipherText, clearText); }
+bool Client::getUserId(output_string& userId) { return impl->getUserId(userId); }
+void Client::getError(output_string& error) { impl->getError(error); }
+
diff --git a/extras/sasl/src/saslwrapper.i b/extras/sasl/src/saslwrapper.i
new file mode 100644
index 0000000000..533ac79ce5
--- /dev/null
+++ b/extras/sasl/src/saslwrapper.i
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+%{
+#include "saslwrapper.h"
+%}
+
+%include stl.i
+%include <saslwrapper.h>
+
+%inline {
+
+using namespace std;
+using namespace saslwrapper;
+
+namespace saslwrapper {
+
+}
+}
+
+%{
+
+%};
+
diff --git a/gentools/LICENSE b/gentools/LICENSE
new file mode 100644
index 0000000000..43fa6abd19
--- /dev/null
+++ b/gentools/LICENSE
@@ -0,0 +1,202 @@
+ 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/gentools/NOTICE b/gentools/NOTICE
new file mode 100644
index 0000000000..09e9ae4902
--- /dev/null
+++ b/gentools/NOTICE
@@ -0,0 +1,2 @@
+This product includes software developed by The Apache Software Foundation (http://www.apache.org/).
+
diff --git a/gentools/README.txt b/gentools/README.txt
new file mode 100644
index 0000000000..eb364ece53
--- /dev/null
+++ b/gentools/README.txt
@@ -0,0 +1,102 @@
+--------
+Velocity
+--------
+
+Welcome to Velocity. Velocity is a general purpose template engine
+written in Java. For more information about Velocity, please look at the
+HTML documentation in the docs/ directory, as well as the Velocity
+web site
+
+ http://jakarta.apache.org/velocity/index.html
+
+Here is a description of what each of the top level directories
+contains. Please consult the documentation in each of the lower level
+directories for information that is specific to their contents.
+
+bin/ This is a temporary build directory.
+build/ This is where the build scripts live.
+docs/ This is where the documentation lives.
+examples/ This is where the examples live.
+src/ This is where all of the source code to Velocity lives.
+test/ This is where all of the tests live.
+xdocs/ This is the .xml files for building the .html files
+ related to the website and documentation.
+
+REQUIREMENTS
+------------
+
+The Java 2 SDK is required to build Velocity.
+
+For users that wish to use Log4J as the logging
+system, version 1.1 or newer of Log4J is required.
+
+
+INCLUDED PRE-BUILT JARS
+-----------------------
+If you are using an offical Velocity release distribution,
+you will find two pre-built Velocity jars in the top level
+directory.
+
+PLEASE NOTE : Starting with the 1.2 release, we include two jars
+ with the distribution.
+
+1) velocity-<version>.jar : The Velocity jar that does not include
+any external dependencies needed by Velocity, such as the
+jakarta-commons-collection classes, Jakarta Avalon Logkit, or
+Jakarta ORO. We do this to allow you to use whatever version of
+collections, logkit, etc that you wish w/o fear of collision.
+These jars are included in the distribution, in
+the build/lib directory, or at the respective project sites.
+
+2) velocity-dep-<version>.jar : This is a Velocity jar that includes
+all dependencies that were included with previous distribution
+jars. It is intended as a convenience to allow you to drop
+this 1.3 (or later) distribution in place of existing 1.1 or 1.2-dep
+ distributions.
+
+Please see the developers guide for more information.
+
+BUILDING VELOCITY
+-----------------
+
+In order to get started with Velocity, you may want to build it.
+
+Building Velocity is easy. All components necessary to build Velocity are
+included, except for the Java 2 SDK and the fabulous Ant build tool
+from the Jakarta project.
+
+http://jakarta.apache.org/ant/
+
+Note that you must use Ant version 1.4 or later.
+
+To build Velocity's jar, change directory into the build/ directory and
+simply type :
+
+ant jar
+
+This will create a bin/ directory containing the Velocity .jar file. Be
+sure to update your classpath to include Velocity's .jar file, or when using a
+modern servlet container, put it in the WEB-INF/lib directory.
+
+If you wish to build a Velocity jar that contains all dependencies, we have
+provided an optional build target for our convenience :
+
+ant jar-dep
+
+This will build a complete Velocity jar with dependencies included, and it can
+be found in the /bin directory as
+
+velocity-dep-<version>.jar
+
+TRYING THE EXAMPLES
+-------------------
+
+After building Velocity, you can also buld the examples that are included
+with the Velocity distribution. These examples show how to use Velocity
+in your Java applications and Servlets. There also are examples of
+how to use Anakia, a XML transformation engine and an example of a servlet-
+based forum application.
+
+For more information, please see the README.txt in the examples/ directory.
+
+-The Velocity Team
diff --git a/gentools/build b/gentools/build
index 4114babe72..a18a984dff 100755
--- a/gentools/build
+++ b/gentools/build
@@ -1,4 +1,26 @@
#!/bin/bash
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
+
cd src
echo "--------- Building gentools ----------"
echo "Clearing out old build files..."
diff --git a/gentools/lib/LICENSE b/gentools/lib/LICENSE
index 43fa6abd19..e69de29bb2 100644
--- a/gentools/lib/LICENSE
+++ b/gentools/lib/LICENSE
@@ -1,202 +0,0 @@
- 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/gentools/lib/NOTICE b/gentools/lib/NOTICE
index 09e9ae4902..e69de29bb2 100644
--- a/gentools/lib/NOTICE
+++ b/gentools/lib/NOTICE
@@ -1,2 +0,0 @@
-This product includes software developed by The Apache Software Foundation (http://www.apache.org/).
-
diff --git a/gentools/lib/README.txt b/gentools/lib/README.txt
index eb364ece53..e69de29bb2 100644
--- a/gentools/lib/README.txt
+++ b/gentools/lib/README.txt
@@ -1,102 +0,0 @@
---------
-Velocity
---------
-
-Welcome to Velocity. Velocity is a general purpose template engine
-written in Java. For more information about Velocity, please look at the
-HTML documentation in the docs/ directory, as well as the Velocity
-web site
-
- http://jakarta.apache.org/velocity/index.html
-
-Here is a description of what each of the top level directories
-contains. Please consult the documentation in each of the lower level
-directories for information that is specific to their contents.
-
-bin/ This is a temporary build directory.
-build/ This is where the build scripts live.
-docs/ This is where the documentation lives.
-examples/ This is where the examples live.
-src/ This is where all of the source code to Velocity lives.
-test/ This is where all of the tests live.
-xdocs/ This is the .xml files for building the .html files
- related to the website and documentation.
-
-REQUIREMENTS
-------------
-
-The Java 2 SDK is required to build Velocity.
-
-For users that wish to use Log4J as the logging
-system, version 1.1 or newer of Log4J is required.
-
-
-INCLUDED PRE-BUILT JARS
------------------------
-If you are using an offical Velocity release distribution,
-you will find two pre-built Velocity jars in the top level
-directory.
-
-PLEASE NOTE : Starting with the 1.2 release, we include two jars
- with the distribution.
-
-1) velocity-<version>.jar : The Velocity jar that does not include
-any external dependencies needed by Velocity, such as the
-jakarta-commons-collection classes, Jakarta Avalon Logkit, or
-Jakarta ORO. We do this to allow you to use whatever version of
-collections, logkit, etc that you wish w/o fear of collision.
-These jars are included in the distribution, in
-the build/lib directory, or at the respective project sites.
-
-2) velocity-dep-<version>.jar : This is a Velocity jar that includes
-all dependencies that were included with previous distribution
-jars. It is intended as a convenience to allow you to drop
-this 1.3 (or later) distribution in place of existing 1.1 or 1.2-dep
- distributions.
-
-Please see the developers guide for more information.
-
-BUILDING VELOCITY
------------------
-
-In order to get started with Velocity, you may want to build it.
-
-Building Velocity is easy. All components necessary to build Velocity are
-included, except for the Java 2 SDK and the fabulous Ant build tool
-from the Jakarta project.
-
-http://jakarta.apache.org/ant/
-
-Note that you must use Ant version 1.4 or later.
-
-To build Velocity's jar, change directory into the build/ directory and
-simply type :
-
-ant jar
-
-This will create a bin/ directory containing the Velocity .jar file. Be
-sure to update your classpath to include Velocity's .jar file, or when using a
-modern servlet container, put it in the WEB-INF/lib directory.
-
-If you wish to build a Velocity jar that contains all dependencies, we have
-provided an optional build target for our convenience :
-
-ant jar-dep
-
-This will build a complete Velocity jar with dependencies included, and it can
-be found in the /bin directory as
-
-velocity-dep-<version>.jar
-
-TRYING THE EXAMPLES
--------------------
-
-After building Velocity, you can also buld the examples that are included
-with the Velocity distribution. These examples show how to use Velocity
-in your Java applications and Servlets. There also are examples of
-how to use Anakia, a XML transformation engine and an example of a servlet-
-based forum application.
-
-For more information, please see the README.txt in the examples/ directory.
-
--The Velocity Team
diff --git a/gentools/src/org/apache/qpid/gentools/ConsolidatedField.java b/gentools/src/org/apache/qpid/gentools/ConsolidatedField.java
index 71d1425d12..9ab7eb178b 100644
--- a/gentools/src/org/apache/qpid/gentools/ConsolidatedField.java
+++ b/gentools/src/org/apache/qpid/gentools/ConsolidatedField.java
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
package org.apache.qpid.gentools;
import java.util.List;
diff --git a/gentools/templ.java/model/ProtocolVersionListClass.vm b/gentools/templ.java/model/ProtocolVersionListClass.vm
index 18d90fab29..bcf7db345b 100644
--- a/gentools/templ.java/model/ProtocolVersionListClass.vm
+++ b/gentools/templ.java/model/ProtocolVersionListClass.vm
@@ -39,12 +39,14 @@ public class ProtocolVersion implements Comparable
{
private final byte _majorVersion;
private final byte _minorVersion;
+ private final String _stringFormat;
public ProtocolVersion(byte majorVersion, byte minorVersion)
{
_majorVersion = majorVersion;
_minorVersion = minorVersion;
+ _stringFormat = _majorVersion+"-"+_minorVersion;
}
public byte getMajorVersion()
@@ -57,6 +59,10 @@ public class ProtocolVersion implements Comparable
return _minorVersion;
}
+ public String toString()
+ {
+ return _stringFormat;
+ }
public int compareTo(Object o)
{
diff --git a/java/010ExcludeList b/java/010ExcludeList
deleted file mode 100644
index 813d4ada35..0000000000
--- a/java/010ExcludeList
+++ /dev/null
@@ -1,65 +0,0 @@
-org.apache.qpid.test.unit.client.channelclose.ChannelCloseTest#*
-org.apache.qpid.client.ResetMessageListenerTest#*
-// those tests should be run with prefetch off
-org.apache.qpid.client.MessageListenerMultiConsumerTest#testRecieveC2Only
-org.apache.qpid.client.MessageListenerMultiConsumerTest#testRecieveBoth
-org.apache.qpid.test.unit.xa.TopicTest#testMigrateDurableSubscriber
-org.apache.qpid.test.unit.ack.AcknowledgeTest#*
-// those tests need durable subscribe states to be persisted
-org.apache.qpid.test.unit.topic.DurableSubscriptionTest#testDurSubRestoredAfterNonPersistentMessageSent
-// those tests require broker recovery
-org.apache.qpid.test.unit.ct.DurableSubscriberTest#*
-org.apache.qpid.test.unit.xa.TopicTest#testDurSubCrash
-org.apache.qpid.test.unit.xa.TopicTest#testMultiMessagesDurSubCrash
-org.apache.qpid.test.unit.xa.TopicTest#testRecover
-org.apache.qpid.test.unit.xa.QueueTest#testRecover
-org.apache.qpid.test.unit.xa.QueueTest#testSendAndRecover
-//These tests are for the java broker
-org.apache.qpid.server.security.acl.SimpleACLTest#*
-org.apache.qpid.server.plugins.PluginTest#*
-// This test is not finished
-org.apache.qpid.test.testcases.TTLTest#*
-// Those tests require failover support
-org.apache.qpid.test.client.QueueBrowserAutoAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserAutoAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserClientAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserClientAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserDupsOkTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserDupsOkTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserNoAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserNoAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserPreAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserPreAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserTransactedTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserTransactedTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.testcases.FailoverTest#*
-org.apache.qpid.test.client.failover.FailoverTest#*
-// Those tests are testing 0.8 specific semantics
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsConsumerDisconnectedNoTxP2P
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsConsumerDisconnectedTxP2P
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsNoRouteNoTxP2P
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsNoRouteTxP2P
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsConsumerDisconnectedNoTxPubSub
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsConsumerDisconnectedTxPubSub
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsNoRouteNoTxPubSub
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsNoRouteTxPubSub
-org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFailsNoRouteNoTxP2P
-org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFailsNoRouteTxP2P
-org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFailsNoRouteNoTxPubSub
-org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFailsNoRouteTxPubSub
-org.apache.qpid.test.client.FlowControlTest#*
-org.apache.qpid.test.unit.client.connection.ConnectionTest#testDefaultExchanges
-org.apache.qpid.test.unit.client.connection.ConnectionTest#testUnresolvedVirtualHostFailure
-// the 0.10 c++ broker does not implement forget
-org.apache.qpid.test.unit.xa.FaultTest#testForget
-// the 0-10 c++ broker does not implement priority / this test depends on a Java broker extension for queue creation
-org.apache.qpid.server.queue.PriorityTest
-//this test checks explicitly for 0-8 flow control semantics
-org.apache.qpid.test.client.FlowControlTest
-// 0-10 c++ broker doesn't implement virtual hosts, or those wackhy exchanges
-org.apache.qpid.test.unit.client.connection.ConnectionTest#testUnresolvedVirtualHostFailure
-org.apache.qpid.test.unit.client.connection.ConnectionTest#testDefaultExchanges
-// 0-10 c++ broker in cpp.testprofile is started with no auth so won't pass this test
-org.apache.qpid.test.unit.client.connection.ConnectionTest#testPasswordFailureConnection
-// c++ broker doesn't do selectors, so this will fail
-org.apache.qpid.test.unit.topic.TopicSessionTest#testNonMatchingMessagesDoNotFillQueue
diff --git a/java/010ExcludeList-noPrefetch b/java/010ExcludeList-noPrefetch
deleted file mode 100644
index 610e31717a..0000000000
--- a/java/010ExcludeList-noPrefetch
+++ /dev/null
@@ -1,55 +0,0 @@
-org.apache.qpid.test.unit.client.channelclose.ChannelCloseTest#*
-org.apache.qpid.client.ResetMessageListenerTest#*
-org.apache.qpid.test.unit.transacted.TransactedTest#testRollback
-// those tests need durable subscribe states to be persisted
-org.apache.qpid.test.unit.topic.DurableSubscriptionTest#testDurSubRestoredAfterNonPersistentMessageSent
-org.apache.qpid.test.unit.ct.DurableSubscriberTest#testDurSubRestoresMessageSelector
-// This test cannot be run with no-prefetch
-org.apache.qpid.test.unit.xa.TopicTest#testMultiMessagesDurSubCrash
-//These tests are for the java broker
-org.apache.qpid.server.security.acl.SimpleACLTest#*
-org.apache.qpid.server.plugins.PluginTest#*
-// This test is not finished
-org.apache.qpid.test.testcases.TTLTest#*
-// Those tests require failover support
-org.apache.qpid.test.client.QueueBrowserAutoAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserAutoAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserClientAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserClientAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserDupsOkTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserDupsOkTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserNoAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserNoAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserPreAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserPreAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserTransactedTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserTransactedTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.testcases.FailoverTest#*
-org.apache.qpid.test.client.failover.FailoverTest#*
-// Those tests are testing 0.8 specific semantics
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsConsumerDisconnectedNoTxP2P
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsConsumerDisconnectedTxP2P
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsNoRouteNoTxP2P
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsNoRouteTxP2P
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsConsumerDisconnectedNoTxPubSub
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsConsumerDisconnectedTxPubSub
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsNoRouteNoTxPubSub
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsNoRouteTxPubSub
-org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFailsNoRouteNoTxP2P
-org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFailsNoRouteTxP2P
-org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFailsNoRouteNoTxPubSub
-org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFailsNoRouteTxPubSub
-org.apache.qpid.test.client.FlowControlTest#*
-org.apache.qpid.test.unit.client.connection.ConnectionTest#testDefaultExchanges
-org.apache.qpid.test.unit.client.connection.ConnectionTest#testUnresolvedVirtualHostFailure
-// the 0.10 c++ broker does not implement forget
-org.apache.qpid.test.unit.xa.FaultTest#testForget
-// the 0-10 c++ broker does not implement priority / this test depends on a Java broker extension for queue creation
-org.apache.qpid.server.queue.PriorityTest
-//this test checks explicitly for 0-8 flow control semantics
-org.apache.qpid.test.client.FlowControlTest
-// The default cpp.testprofile does not start the cpp broker with authentication so this test will fail.
-org.apache.qpid.test.unit.client.connection.ConnectionTest#testPasswordFailureConnection
-// c++ broker doesn't do selectors, so this will fail
-org.apache.qpid.test.unit.topic.TopicSessionTest#testNonMatchingMessagesDoNotFillQueue
-
diff --git a/java/010ExcludeList-store b/java/010ExcludeList-store
deleted file mode 100644
index 1ff2b4bbc6..0000000000
--- a/java/010ExcludeList-store
+++ /dev/null
@@ -1,57 +0,0 @@
-org.apache.qpid.test.unit.client.channelclose.ChannelCloseTest#*
-org.apache.qpid.client.ResetMessageListenerTest#*
-// those tests should be run with prefetch off
-org.apache.qpid.client.MessageListenerMultiConsumerTest#testRecieveC2Only
-org.apache.qpid.client.MessageListenerMultiConsumerTest#testRecieveBoth
-org.apache.qpid.test.unit.xa.TopicTest#testMultiMessagesDurSubCrash
-org.apache.qpid.test.unit.xa.TopicTest#testMigrateDurableSubscriber
-org.apache.qpid.test.unit.ack.AcknowledgeTest#*
-// those tests need durable subscribe states to be persisted
-org.apache.qpid.test.unit.topic.DurableSubscriptionTest#testDurSubRestoredAfterNonPersistentMessageSent
-org.apache.qpid.test.unit.ct.DurableSubscriberTest#testDurSubRestoresMessageSelector
-//These tests are for the java broker
-org.apache.qpid.server.security.acl.SimpleACLTest#*
-org.apache.qpid.server.plugins.PluginTest#*
-// This test is not finished
-org.apache.qpid.test.testcases.TTLTest#*
-// Those tests require failover support
-org.apache.qpid.test.client.QueueBrowserAutoAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserAutoAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserClientAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserClientAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserDupsOkTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserDupsOkTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserNoAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserNoAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserPreAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserPreAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserTransactedTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserTransactedTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.testcases.FailoverTest#*
-org.apache.qpid.test.client.failover.FailoverTest#*
-// Those tests are testing 0.8 specific semantics
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsConsumerDisconnectedNoTxP2P
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsConsumerDisconnectedTxP2P
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsNoRouteNoTxP2P
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsNoRouteTxP2P
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsConsumerDisconnectedNoTxPubSub
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsConsumerDisconnectedTxPubSub
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsNoRouteNoTxPubSub
-org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsNoRouteTxPubSub
-org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFailsNoRouteNoTxP2P
-org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFailsNoRouteTxP2P
-org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFailsNoRouteNoTxPubSub
-org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFailsNoRouteTxPubSub
-org.apache.qpid.test.client.FlowControlTest#*
-org.apache.qpid.test.unit.client.connection.ConnectionTest#testDefaultExchanges
-org.apache.qpid.test.unit.client.connection.ConnectionTest#testUnresolvedVirtualHostFailure
-// the 0.10 c++ broker does not implement forget
-org.apache.qpid.test.unit.xa.FaultTest#testForget
-// the 0-10 c++ broker does not implement priority / this test depends on a Java broker extension for queue creation
-org.apache.qpid.server.queue.PriorityTest
-//this test checks explicitly for 0-8 flow control semantics
-org.apache.qpid.test.client.FlowControlTest
-// The default cpp.testprofile does not start the cpp broker with authentication so this test will fail.
-org.apache.qpid.test.unit.client.connection.ConnectionTest#testPasswordFailureConnection
-// c++ broker doesn't do selectors, so this will fail
-org.apache.qpid.test.unit.topic.TopicSessionTest#testNonMatchingMessagesDoNotFillQueue
diff --git a/java/08ExcludeList b/java/08ExcludeList
deleted file mode 100644
index a3caba4df3..0000000000
--- a/java/08ExcludeList
+++ /dev/null
@@ -1,9 +0,0 @@
-org.apache.qpid.test.unit.xa.QueueTest#*
-org.apache.qpid.test.unit.xa.TopicTest#*
-org.apache.qpid.test.unit.xa.FaultTest#*
-org.apache.qpid.test.unit.ct.DurableSubscriberTests#*
-// Those tests are not finished
-org.apache.qpid.test.testcases.TTLTest#*
-org.apache.qpid.test.testcases.FailoverTest#*
-// This is a long running test so should exclude from normal runs
-org.apache.qpid.test.client.failover.FailoverTest#test4MinuteFailover
diff --git a/java/08ExcludeList-nonvm b/java/08ExcludeList-nonvm
deleted file mode 100644
index d377824c09..0000000000
--- a/java/08ExcludeList-nonvm
+++ /dev/null
@@ -1,24 +0,0 @@
-org.apache.qpid.test.unit.xa.QueueTest#*
-org.apache.qpid.test.unit.xa.TopicTest#*
-org.apache.qpid.test.unit.xa.FaultTest#*
-org.apache.qpid.test.unit.ct.DurableSubscriberTests#*
-// Those tests are not finished
-org.apache.qpid.test.testcases.TTLTest#*
-org.apache.qpid.test.testcases.FailoverTest#*
-// This is a long running test so should exclude from normal runs
-org.apache.qpid.test.client.failover.FailoverTest#test4MinuteFailover
-// Those tests require failover support
-org.apache.qpid.test.client.QueueBrowserAutoAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserAutoAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserClientAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserClientAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserDupsOkTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserDupsOkTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserNoAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserNoAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserPreAckTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserPreAckTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.client.QueueBrowserTransactedTest#testFailoverAsQueueBrowserCreated
-org.apache.qpid.test.client.QueueBrowserTransactedTest#testFailoverWithQueueBrowser
-org.apache.qpid.test.testcases.FailoverTest#*
-org.apache.qpid.test.client.failover.FailoverTest#*
diff --git a/java/KEYS b/java/KEYS
deleted file mode 100644
index fabfa79997..0000000000
--- a/java/KEYS
+++ /dev/null
@@ -1,32 +0,0 @@
-pub 2048R/18806464 2006-11-14
-uid Rajith Attapattu <rajith@apache.org>
-sig 3 18806464 2006-11-14 Rajith Attapattu <rajith@apache.org>
-uid Rajith Attapattu <rajith77@gmail.com>
-sig 3 18806464 2006-11-14 Rajith Attapattu <rajith@apache.org>
-
------BEGIN PGP PUBLIC KEY BLOCK-----
-Version: GnuPG v1.4.2.1 (GNU/Linux)
-
-mQELBEVaPcABCAC+iLSVxk/TZ2i5Kq4KhdYdBdpXizwRsKdCq9m9DwD20yke0rZL
-067ka5z4gA2prOUUCJ51G/CFhDgngiK0awnhcMgdNZzMQoOIJC044qgRLeg12IvI
-bzdtzK+DknPW3MC5QbmuJiozBPokyhyHR/C+889f2lR8OTjSGagLwjtHf0oEuEn4
-RdTBWWzNZclKe4J6UIbi3VG5kgUmThCm12TmtABmJmXpeNl3wpyYNPxZkU1huKNl
-Pi0Buu1SroWoIlwR8n2DNvDIU8PvzmtrfZoDBMopC1a6lBiZX9tKwZLUDb28AgaB
-XelJ+L+nkaoLjbNgNxGRMT7N99hWXsOcWlUVAAYptCVSYWppdGggQXR0YXBhdHR1
-IDxyYWppdGg3N0BnbWFpbC5jb20+iQE2BBMBAgAgBQJFWj3AAhsDBgsJCAcDAgQV
-AggDBBYCAwECHgECF4AACgkQdt2xaBiAZGS/AQf/fCrR7bLqAhiI9ojuOgTfwzRv
-9Hf3FcNdRCnVzmRFzE4WGHSG7R92xLL8avtiPEdC7p80d3+bf+QKGSJ/Ym4a0JqE
-KeX08brWOtIfQQK7wd7UgCJ3ufWcbQgnHzhgc7oY00FZAmQfv8TF8Uxqpe6dKXep
-4S3RN1c9ygg643ey7u85knAk+rs1OevZ+xl/IsLN6rSnQ1B8uIJUCct8+5YuGxd7
-VHCAgDEri0zf7+CMWxVpOJgcegn9Iy8rfmif8BUs0620xvNRha03of2UQZau0WzB
-MIMkSgOUhSBdsYNYe8TU9SfJGXabB4R6xDimMDbOXs75ypQMoPiEsf9urx7T6rQk
-UmFqaXRoIEF0dGFwYXR0dSA8cmFqaXRoQGFwYWNoZS5vcmc+iQE2BBMBAgAgBQJF
-Wj7qAhsDBgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQdt2xaBiAZGQEYQf/SocY
-SONVEePlZtFlLmsebZLZ8sn+HZBPepcJf81eK7YdXcca7QSeY3Q6vwshbfZsUOJZ
-fu+6gaD1MnPtBLF4RWjLBW1OOmxLJPtv5bNifjciuhuvRgBA7y3xWenfNgV4FeKk
-qX8ArRYJQVgy7X5Lv3ccbXcaNq6ajT2xDi0krMkn0TtU1vdkDSK56PRzAwWxA/X+
-4MKQZF/6964or2rz91iX2OnylEj38q+F7/dOaasD/EZpjAh8nipqVBVL3Rcy2gFy
-7EkTao4tOSo1JVrHW7lgfEBxKVSrgHyhnSxx3Z773edp2qnjZPAcv0qiEawszhkI
-vIuNSo3oTbrOW9w2tA==
-=FCqB
------END PGP PUBLIC KEY BLOCK-----
diff --git a/java/broker-plugins/build.xml b/java/broker-plugins/build.xml
index 9787eeebc3..b12b3e3132 100644
--- a/java/broker-plugins/build.xml
+++ b/java/broker-plugins/build.xml
@@ -20,7 +20,7 @@ nn - or more contributor license agreements. See the NOTICE file
-->
<project name="AMQ Broker-Plugins" default="build">
- <property name="module.depends" value="client broker common junit-toolkit"/>
+ <property name="module.depends" value="client management/common broker common junit-toolkit"/>
<property name="module.manifest" value="MANIFEST.MF"/>
<property name="module.plugin" value="true"/>
diff --git a/java/broker-plugins/pom.xml b/java/broker-plugins/pom.xml
deleted file mode 100644
index 9777b7c502..0000000000
--- a/java/broker-plugins/pom.xml
+++ /dev/null
@@ -1,100 +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.
--->
-<project>
-
- <properties>
- <topDirectoryLocation>.</topDirectoryLocation>
- <java.source.version>1.5</java.source.version>
- <compile.flags>-Xlint:fallthrough,finally</compile.flags>
- <compiler.version>2.0.1</compiler.version>
- </properties>
-
- <parent>
- <groupId>org.apache</groupId>
- <artifactId>apache</artifactId>
- <version>4</version>
- </parent>
-
- <modelVersion>4.0.0</modelVersion>
- <packaging>bundle</packaging>
- <name>Qpid Plugins</name>
- <description>A simple plugin for qpid.</description>
- <groupId>org.apache.qpid.extras</groupId>
- <artifactId>example-plugin</artifactId>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <dependencies>
- <dependency>
- <groupId>org.apache.felix</groupId>
- <artifactId>org.osgi.core</artifactId>
- <version>1.0.0</version>
- </dependency>
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-broker</artifactId>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>junit-toolkit</artifactId>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- </dependency>
-
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <version>1.0.0</version>
- <extensions>true</extensions>
- <configuration>
- <instructions>
- <Private-Package>
- org.apache.qpid.extras.*
- </Private-Package>
- <Bundle-Activator>
- org.apache.qpid.extras.Activator
- </Bundle-Activator>
- </instructions>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>${compiler.version}</version>
- <configuration>
- <source>${java.source.version}</source>
- <target>${java.source.version}</target>
- </configuration>
- </plugin>
- </plugins>
- <resources>
- <resource>
- <directory>src/main/java</directory>
- <excludes>
- <exclude>**/*.java</exclude>
- <exclude>**/log4j.properties</exclude>
- </excludes>
- </resource>
- </resources>
- </build>
-
-</project>
diff --git a/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchange.java b/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchange.java
index 027d220538..637997a947 100644
--- a/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchange.java
+++ b/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchange.java
@@ -20,10 +20,8 @@
*/
package org.apache.qpid.extras.exchanges.diagnostic;
-import java.util.List;
-import java.util.Map;
import java.util.ArrayList;
-import java.util.Collection;
+import java.util.Map;
import javax.management.JMException;
import javax.management.openmbean.OpenDataException;
@@ -34,27 +32,31 @@ import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.BasicContentHeaderProperties;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.server.exchange.AbstractExchange;
-import org.apache.qpid.server.management.MBeanConstructor;
-import org.apache.qpid.server.management.MBeanDescription;
-import org.apache.qpid.server.queue.IncomingMessage;
import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.message.InboundMessage;
import org.apache.qpid.junit.extensions.util.SizeOf;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
+import org.apache.log4j.Logger;
/**
- *
+ *
* This is a special diagnostic exchange type which doesn't actually do anything
* with messages. When it receives a message, it writes information about the
* current memory usage to the "memory" property of the message and places it on the
- * diagnosticqueue for retrieval
- *
+ * diagnosticqueue for retrieval
+ *
* @author Aidan Skinner
- *
+ *
*/
public class DiagnosticExchange extends AbstractExchange
{
-
+
+ private static final Logger _logger = Logger.getLogger(DiagnosticExchange.class);
+
+
public static final AMQShortString DIAGNOSTIC_EXCHANGE_CLASS = new AMQShortString("x-diagnostic");
public static final AMQShortString DIAGNOSTIC_EXCHANGE_NAME = new AMQShortString("diagnostic");
@@ -72,7 +74,7 @@ public class DiagnosticExchange extends AbstractExchange
/**
* Usual constructor.
- *
+ *
* @throws JMException
*/
@MBeanConstructor("Creates an MBean for AMQ Diagnostic exchange")
@@ -85,7 +87,7 @@ public class DiagnosticExchange extends AbstractExchange
/**
* Returns nothing, there can be no tabular data for this...
- *
+ *
* @throws OpenDataException
* @returns null
* @todo ... or can there? Could this actually return all the
@@ -99,7 +101,7 @@ public class DiagnosticExchange extends AbstractExchange
/**
* This exchange type doesn't support queues, so this method does
* nothing.
- *
+ *
* @param queueName
* the queue you'll fail to create
* @param binding
@@ -116,22 +118,20 @@ public class DiagnosticExchange extends AbstractExchange
/**
* Creates a new MBean instance
- *
+ *
* @return the newly created MBean
* @throws AMQException
* if something goes wrong
*/
- protected ExchangeMBean createMBean() throws AMQException
+ protected ExchangeMBean createMBean() throws JMException
{
- try
- {
- return new DiagnosticExchange.DiagnosticExchangeMBean();
- }
- catch (JMException ex)
- {
- // _logger.error("Exception occured in creating the direct exchange mbean", ex);
- throw new AMQException(null, "Exception occured in creating the direct exchange mbean", ex);
- }
+ return new DiagnosticExchange.DiagnosticExchangeMBean();
+
+ }
+
+ public Logger getLogger()
+ {
+ return _logger;
}
public AMQShortString getType()
@@ -141,7 +141,7 @@ public class DiagnosticExchange extends AbstractExchange
/**
* Does nothing.
- *
+ *
* @param routingKey
* pointless
* @param queue
@@ -156,9 +156,15 @@ public class DiagnosticExchange extends AbstractExchange
// No op
}
+ public void registerQueue(String routingKey, AMQQueue queue, Map<String, Object> args) throws AMQException
+ {
+ // No op
+ }
+
+
/**
* Does nothing.
- *
+ *
* @param routingKey
* pointless
* @param queue
@@ -193,27 +199,29 @@ public class DiagnosticExchange extends AbstractExchange
return false;
}
- public void route(IncomingMessage payload) throws AMQException
+ public ArrayList<AMQQueue> route(InboundMessage payload)
{
-
+
Long value = new Long(SizeOf.getUsedMemory());
AMQShortString key = new AMQShortString("memory");
-
- FieldTable headers = ((BasicContentHeaderProperties)payload.getContentHeaderBody().properties).getHeaders();
+
+ //TODO shouldn't modify messages... perhaps put a new message on the queue?
+/* FieldTable headers = ((BasicContentHeaderProperties)payload.getMessageHeader().properties).getHeaders();
headers.put(key, value);
- ((BasicContentHeaderProperties)payload.getContentHeaderBody().properties).setHeaders(headers);
+ ((BasicContentHeaderProperties)payload.getMessageHeader().properties).setHeaders(headers);*/
AMQQueue q = getQueueRegistry().getQueue(new AMQShortString("diagnosticqueue"));
ArrayList<AMQQueue> queues = new ArrayList<AMQQueue>();
queues.add(q);
- payload.enqueue(queues);
-
+ return queues;
+
}
-
+
public boolean isBound(AMQShortString routingKey, FieldTable arguments,
AMQQueue queue) {
// TODO Auto-generated method stub
return false;
}
+
}
diff --git a/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchangeType.java b/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchangeType.java
index d96b4dc99e..b4d0d1aa0d 100644
--- a/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchangeType.java
+++ b/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchangeType.java
@@ -31,7 +31,7 @@ import org.apache.qpid.server.virtualhost.VirtualHost;
*/
public final class DiagnosticExchangeType implements ExchangeType<DiagnosticExchange>
{
-
+
public AMQShortString getName()
{
return DiagnosticExchange.DIAGNOSTIC_EXCHANGE_CLASS;
diff --git a/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchange.java b/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchange.java
index 067125de56..cb46b9c815 100644
--- a/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchange.java
+++ b/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchange.java
@@ -1,15 +1,38 @@
package org.apache.qpid.extras.exchanges.example;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import java.util.List;
import java.util.Map;
+import java.util.ArrayList;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.queue.IncomingMessage;
+import org.apache.qpid.server.exchange.ExchangeReferrer;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.message.InboundMessage;
public class TestExchange implements Exchange
{
@@ -42,6 +65,41 @@ public class TestExchange implements Exchange
return false;
}
+ public boolean isBound(String bindingKey, AMQQueue queue)
+ {
+ return false;
+ }
+
+ public boolean isBound(String bindingKey)
+ {
+ return false;
+ }
+
+ public Exchange getAlternateExchange()
+ {
+ return null;
+ }
+
+ public void setAlternateExchange(Exchange exchange)
+ {
+
+ }
+
+ public void removeReference(ExchangeReferrer exchange)
+ {
+
+ }
+
+ public void addReference(ExchangeReferrer exchange)
+ {
+
+ }
+
+ public boolean hasReferrers()
+ {
+ return false;
+ }
+
public void initialise(VirtualHost host, AMQShortString name, boolean durable, boolean autoDelete)
throws AMQException
{
@@ -81,8 +139,9 @@ public class TestExchange implements Exchange
{
}
- public void route(IncomingMessage message) throws AMQException
+ public ArrayList<AMQQueue> route(InboundMessage message)
{
+ return new ArrayList<AMQQueue>();
}
public int getTicket()
diff --git a/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchangeType.java b/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchangeType.java
index 22833693ca..db02ca13ea 100644
--- a/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchangeType.java
+++ b/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchangeType.java
@@ -40,7 +40,7 @@ public class TestExchangeType implements ExchangeType
return null;
}
- public Exchange newInstance(VirtualHost host, AMQShortString name, boolean durable,
+ public Exchange newInstance(VirtualHost host, AMQShortString name, boolean durable,
int token, boolean autoDelete)
throws AMQException
{
diff --git a/java/broker/bin/create-example-ssl-stores.bat b/java/broker/bin/create-example-ssl-stores.bat
new file mode 100644
index 0000000000..5419c098d5
--- /dev/null
+++ b/java/broker/bin/create-example-ssl-stores.bat
@@ -0,0 +1,36 @@
+@REM
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM
+
+@REM Create example keystore for broker and trust store for client/management console.
+@REM
+@REM Use generated qpid.keystore as the brokers keystore
+@REM Use generated qpid.truststore as client/consoles truststore
+@REM All passwords have value: password
+
+@REM Create Broker Keystore:
+keytool -genkey -alias qpidBroker -keyalg RSA -validity 365 -keystore qpid.keystore -storepass password -keypass password -dname "CN=hostname, OU=OrgUnit, O=Org, L=City, C=US"
+
+@REM Export Self Signed Cert:
+keytool -export -alias qpidBroker -keystore qpid.keystore -file qpidBroker.cer -storepass password
+
+@REM Import Broker Cert Into MC TrustStore:
+keytool -import -alias qpidBrokerCert -file qpidBroker.cer -keystore qpid.truststore -storepass password -noprompt
+
+@REM Delete the cert
+del qpidBroker.cer \ No newline at end of file
diff --git a/java/broker/bin/create-example-ssl-stores.sh b/java/broker/bin/create-example-ssl-stores.sh
new file mode 100755
index 0000000000..bfcb3dfecf
--- /dev/null
+++ b/java/broker/bin/create-example-ssl-stores.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Create example keystore for broker and trust store for client/management console.
+#
+# Use generated qpid.keystore as the brokers keystore
+# Use generated qpid.truststore as client/consoles truststore
+# All passwords have value: password
+
+#Create Broker Keystore:
+keytool -genkey -alias qpidBroker -keyalg RSA -validity 365 -keystore qpid.keystore \
+-storepass password -keypass password -dname "CN=hostname, OU=OrgUnit, O=Org, L=City, C=US"
+
+#Export Self Signed Cert:
+keytool -export -alias qpidBroker -keystore qpid.keystore -file qpidBroker.cer -storepass password
+
+#Import Broker Cert Into MC TrustStore:
+keytool -import -alias qpidBrokerCert -file qpidBroker.cer -keystore qpid.truststore -storepass password -noprompt
+
+#Delete the cert
+rm qpidBroker.cer
diff --git a/java/broker/bin/msTool.sh b/java/broker/bin/msTool.sh
index 73b1eb2ec7..e190a0a46a 100755
--- a/java/broker/bin/msTool.sh
+++ b/java/broker/bin/msTool.sh
@@ -49,7 +49,7 @@ if $cygwin; then
fi
# Set classpath to include Qpid jar with all required jars in manifest
-QPID_LIBS=$QPID_TOOLS/lib/qpid-incubating.jar
+QPID_LIBS=$QPID_TOOLS/lib/qpid-all.jar
# Set other variables used by the qpid-run script before calling
export JAVA=java \
diff --git a/java/broker/bin/qpid-passwd b/java/broker/bin/qpid-passwd
index f425eed72b..b84580da60 100755
--- a/java/broker/bin/qpid-passwd
+++ b/java/broker/bin/qpid-passwd
@@ -1,35 +1,35 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-if [ -z "$QPID_HOME" ]; then
- export QPID_HOME=$(dirname $(dirname $(readlink -f $0)))
- export PATH=${PATH}:${QPID_HOME}/bin
-fi
-
-# Set classpath to include Qpid jar with all required jars in manifest
-QPID_LIBS=$QPID_HOME/lib/qpid-incubating.jar
-
-# Set other variables used by the qpid-run script before calling
-export JAVA=java \
- JAVA_VM=-server \
- JAVA_MEM=-Xmx1024m \
- QPID_CLASSPATH=$QPID_LIBS
-
-. qpid-run org.apache.qpid.tools.security.Passwd "$@"
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+if [ -z "$QPID_HOME" ]; then
+ export QPID_HOME=$(dirname $(dirname $(readlink -f $0)))
+ export PATH=${PATH}:${QPID_HOME}/bin
+fi
+
+# Set classpath to include Qpid jar with all required jars in manifest
+QPID_LIBS=$QPID_HOME/lib/qpid-all.jar
+
+# Set other variables used by the qpid-run script before calling
+export JAVA=java \
+ JAVA_VM=-server \
+ JAVA_MEM=-Xmx1024m \
+ QPID_CLASSPATH=$QPID_LIBS
+
+. qpid-run org.apache.qpid.tools.security.Passwd "$@"
diff --git a/java/broker/bin/qpid-server b/java/broker/bin/qpid-server
index b8d6c8e3fd..4e11fd5fe7 100755
--- a/java/broker/bin/qpid-server
+++ b/java/broker/bin/qpid-server
@@ -24,7 +24,7 @@ if [ -z "$QPID_HOME" ]; then
fi
# Set classpath to include Qpid jar with all required jars in manifest
-QPID_LIBS=$QPID_HOME/lib/qpid-incubating.jar:$QPID_HOME/lib/bdbstore-launch.jar
+QPID_LIBS=$QPID_HOME/lib/qpid-all.jar:$QPID_HOME/lib/bdbstore-launch.jar
# Set other variables used by the qpid-run script before calling
export JAVA=java \
@@ -32,6 +32,8 @@ export JAVA=java \
JAVA_MEM=-Xmx1024m \
JAVA_GC="-XX:+UseConcMarkSweepGC -XX:+HeapDumpOnOutOfMemoryError" \
QPID_CLASSPATH=$QPID_LIBS \
- QPID_RUN_LOG=2
+ QPID_RUN_LOG=2
+
+QPID_OPTS="$QPID_OPTS -Damqj.read_write_pool_size=32 -DQPID_LOG_APPEND=$QPID_LOG_APPEND"
. qpid-run org.apache.qpid.server.Main "$@"
diff --git a/java/broker/bin/qpid-server.bat b/java/broker/bin/qpid-server.bat
index 6af214f939..2687baa111 100755..100644
--- a/java/broker/bin/qpid-server.bat
+++ b/java/broker/bin/qpid-server.bat
@@ -76,8 +76,8 @@ echo Using CLASSPATH: %CLASSPATH%
goto afterQpidClasspath
:noQpidClasspath
-echo Warning: Qpid classpath not set. CLASSPATH set to %QPID_HOME%\lib\qpid-incubating.jar
-set CLASSPATH=%QPID_HOME%\lib\qpid-incubating.jar
+echo Warning: Qpid classpath not set. CLASSPATH set to %QPID_HOME%\lib\qpid-all.jar
+set CLASSPATH=%QPID_HOME%\lib\qpid-all.jar
:afterQpidClasspath
REM start parsing -run arguments
diff --git a/java/broker/bin/qpid.stop b/java/broker/bin/qpid.stop
index 6482fc3293..316f8dff46 100755
--- a/java/broker/bin/qpid.stop
+++ b/java/broker/bin/qpid.stop
@@ -20,23 +20,18 @@
# qpid.stop Script
#
-# Script checks for a given pid running PROGRAM and attempts to quit it
+# Script checks for a given pid running DEFAULT_SEARCH and attempts to quit it
#
-MAX_ATTEMPTS=1
+MAX_ATTEMPTS=2
SLEEP_DELAY=1
-PROGRAM="DQPID"
+DEFAULT_SEARCH="PNAME=QPBRKR"
-
-#
-# Print what is going to be done
-#
-printActions()
-{
-#ps=`ps o command p $1|grep $PROGRAM`
-ps=`ps -o args -p $1|grep $PROGRAM`
-echo "Attempting to kill: $ps"
-}
+if [ -z "$QPID_STOP_SEARCH" ]; then
+ SEARCH=$DEFAULT_SEARCH;
+else
+ SEARCH=$QPID_STOP_SEARCH;
+fi
#
# Forcably Quit the specified PID($1)
@@ -46,7 +41,6 @@ forceQuit()
kill -9 $1
}
-
#
# Gracefully ask the PID($1) to quit
#
@@ -56,11 +50,36 @@ kill $1
}
#
-# Grep the ps log for the PID ($1) to ensure that it has quit
+# grep for the session ID ($1) and return 0 for successful quit and 1 for process alive
+#
+lookup_pid()
+{
+result=`ps -e | grep $1 | wc -l`
+}
+
+#
+# grep ps for all instances of $SEARCH for the current user and collect PIDs
+#
+lookup_all_pids()
+{
+pids=`pgrep -f -U $USER $SEARCH`
+result_all=`echo -n $pids | wc -w`
+}
+
+#
+# check that the PID passed in is for a Qpid broker owned by this user and alive
+#
+validate_pid()
+{
+result=`pgrep -fl $SEARCH | grep $1 | wc -l`
+}
+
+#
+# Show the PS output for given set of pids
#
-lookup()
+showPids()
{
-result=`ps -o args -p $1 |grep -v grep |grep $PROGRAM |wc -l`
+ps -o user,pid,args -p $pids
}
#
@@ -70,68 +89,90 @@ check()
{
echo "Waiting $SLEEP_DELAY second for $1 to exit"
sleep $SLEEP_DELAY
-lookup $1
+lookup_pid $1
}
-
-
#
# Verify the PID($1) is available
#
verifyPid()
{
-lookup $1
+validate_pid $1
if [[ $[$result] == 1 ]] ; then
brokerspid=$1
else
- echo "Unable to locate Qpid Process with PID $1"
+ echo "Unable to locate Qpid Broker Process with PID $1. Check PID and try again."
exit -1
fi
}
#
-# Main Run
+# Stops all Qpid brokers for current user
#
+qpid_stopall_brokers()
+{
+for pid in $pids ; do
+ lookup_pid $pid;
+ brokerspid=$pid;
+ stop_broker $pid;
+done
+}
-# Check if we are killing all qpid pids or just one.
-if [[ $# == 0 ]] ; then
- echo "Killing All Qpid Brokers for user: '$USER'"
- qpid.stopall
- exit $?
-else
- verifyPid $1
-fi
-
-printActions $brokerspid
-
+#
+# Stops Qpid broker with brokerspid id
+#
+stop_broker()
+{
# Attempt to quit the process MAX_ATTEMPTS Times
attempt=0
while [[ $[$result] > 0 && $[$attempt] < $[$MAX_ATTEMPTS] ]] ; do
- quit $brokerspid
- check $brokerspid
- attempt=$[$attempt + 1]
+ quit $brokerspid
+ check $brokerspid
+ attempt=$[$attempt + 1]
done
# Check that it has quit
if [[ $[$result] == 0 ]] ; then
- echo "Process quit"
- exit 0
+ echo "Process quit"
else
- # Now attempt to force quit the process
attempt=0
- while [[ $[$result] > 0 && $[$attempt] < $[$MAX_ATTEMPTS] ]] ; do
- forceQuit $brokerspid
- check $brokerspid
- attempt=$[$attempt + 1]
- done
-
+ # Now attempt to force quit the process
+ while [[ $[$result] > 0 && $[$attempt] < $[$MAX_ATTEMPTS] ]] ; do
+ forceQuit $brokerspid
+ check $brokerspid
+ attempt=$[$attempt + 1]
+ done
# Output final status
- if [[ $[$result] > 0 && $[$attempt] == $[$MAX_ATTEMPTS] ]] ; then
- echo "Stopped trying to kill process: $brokerspid"
- echo "Attempted to stop $attempt times"
- else
- echo "Done "
- fi
+ if [[ $[$result] > 0 && $[$attempt] == $[$MAX_ATTEMPTS] ]] ; then
+ echo "Stopped trying to kill process: $brokerspid"
+ echo "Attempted to stop $attempt times"
+ else
+ echo "Done "
+ fi
fi
+
+}
+
+#
+# Main Run
+#
+
+# Check if we are killing all qpid pids or just one.
+# Now uses local function qpid_stopall_brokers
+if [[ $# == 0 ]] ; then
+ lookup_all_pids
+ if [[ $[$result_all] > 0 ]] ; then
+ echo "Killing All Qpid Brokers for user: '$USER'"
+ qpid_stopall_brokers
+ else
+ echo "No Qpid Brokers found running for user: " $USER
+ fi
+ exit $result
+else
+ verifyPid $1
+ stop_broker
+ exit $result
+fi
+
diff --git a/java/broker/bin/qpid.stopall b/java/broker/bin/qpid.stopall
index d71f591de8..b0ad506629 100755
--- a/java/broker/bin/qpid.stopall
+++ b/java/broker/bin/qpid.stopall
@@ -24,51 +24,4 @@
# Utilises qpid.stop to perform the actual stopping
#
-PROGRAM="DQPID"
-
-#
-# grep ps for instances of $PROGRAM and collect PIDs
-#
-lookup()
-{
-#pids=`ps o pid,command | grep $PROGRAM | grep -v grep | cut -d ' ' -f 1`
-pids=`ps -ef |grep $USER | grep $PROGRAM | grep -v grep | awk '{print $2}'`
-result=`echo -n $pids | wc -w`
-}
-
-
-#
-# Show the PS output for given set of pids
-#
-showPids()
-{
-ps -o user,pid,args -p $pids
-}
-
-
-#
-# Main Run
-#
-
-lookup
-
-if [[ $[$result] == 0 ]] ; then
- echo "No Qpid Brokers found running under user '$USER'"
- exit 0
-fi
-
-for pid in $pids ; do
-
-qpid.stop $pid
-
-done
-
-# Check we have quit all
-lookup
-
-if [[ $[$result] == 0 ]] ; then
- echo "All Qpid brokers successfully quit"
-else
- echo "Some brokers were not quit"
- showPids $pids
-fi
+qpid.stop $*
diff --git a/java/broker/bin/run.bat b/java/broker/bin/run.bat
deleted file mode 100755
index 5b0aa0f23b..0000000000
--- a/java/broker/bin/run.bat
+++ /dev/null
@@ -1,31 +0,0 @@
-@REM
-@REM Licensed to the Apache Software Foundation (ASF) under one
-@REM or more contributor license agreements. See the NOTICE file
-@REM distributed with this work for additional information
-@REM regarding copyright ownership. The ASF licenses this file
-@REM to you under the Apache License, Version 2.0 (the
-@REM "License"); you may not use this file except in compliance
-@REM with the License. You may obtain a copy of the License at
-@REM
-@REM http://www.apache.org/licenses/LICENSE-2.0
-@REM
-@REM Unless required by applicable law or agreed to in writing,
-@REM software distributed under the License is distributed on an
-@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-@REM KIND, either express or implied. See the License for the
-@REM specific language governing permissions and limitations
-@REM under the License.
-@REM
-
-@echo off
-set CORE_CLASSES=..\classes;..\testclasses
-
-set COMMONDIR=..\..\common
-
-set COMMONLIB=%COMMONDIR%\lib\slf4j\slf4j-simple.jar;%COMMONDIR%\lib\logging-log4j\log4j-1.2.9.jar;%COMMONDIR%\lib\mina\mina-core-0.9.2.jar
-
-set DIST=..\lib\bdb\je-3.0.12.jar;..\dist\amqpd.jar;..\..\client\dist\amqp-common.jar
-
-set CP=%CORE_CLASSES%;%DIST%;%COMMONLIB%
-
-"%JAVA_HOME%\bin\java" -Xmx512m -Damqj.logging.level=INFO -cp %CP% %*
diff --git a/java/broker/bin/run.sh b/java/broker/bin/run.sh
deleted file mode 100755
index 6b62049e94..0000000000
--- a/java/broker/bin/run.sh
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-
-COMMONDIR=../../common
-
-COMMONLIB=$COMMONLIB:$COMMONDIR/lib/slf4j/slf4j-simple.jar
-COMMONLIB=$COMMONLIB:$COMMONDIR/lib/logging-log4j/log4j-1.2.13.jar
-COMMONLIB=$COMMONLIB:$COMMONDIR/lib/mina/mina-core-0.9.5-SNAPSHOT.jar
-COMMONLIB=$COMMONLIB:$COMMONDIR/lib/mina/mina-filter-ssl-0.9.5-SNAPSHOT.jar
-COMMONLIB=$COMMONLIB:$COMMONDIR/lib/commons-collections/commons-collections-3.1.jar
-COMMONLIB=$COMMONLIB:$COMMONDIR/lib/commons-cli/commons-cli-1.0.jar
-COMMONLIB=$COMMONLIB:$COMMONDIR/lib/commons-configuration/commons-configuration-1.2.jar
-COMMONLIB=$COMMONLIB:$COMMONDIR/lib/commons-logging/commons-logging-api.jar
-COMMONLIB=$COMMONLIB:$COMMONDIR/lib/commons-logging/commons-logging.jar
-COMMONLIB=$COMMONLIB:$COMMONDIR/lib/commons-lang/commons-lang-2.1.jar
-COMMONLIB=$COMMONLIB:$COMMONDIR/lib/junit/junit-4.0.jar
-
-DIST=../lib/bdb/je-3.0.12.jar:../dist/amqpd-tests.jar:../dist/amqpd.jar:../../client/dist/amqp-common.jar
-
-CP=../intellijclasses:$DIST:$COMMONLIB
-
-if [ "$(uname -a | fgrep Cygwin)" != "" ]; then
- CP=$(cygpath --mixed --path $CP)
-fi
-
-"$JAVA_HOME/bin/java" -Xmx512m -Dprepopulate=10 -Damqj.logging.level=INFO -cp $CP $*
diff --git a/java/broker/bin/runAll b/java/broker/bin/runAll
deleted file mode 100755
index 4ced1d263b..0000000000
--- a/java/broker/bin/runAll
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/sh
-
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-doRun()
-{
- class=$1
- shift
- echo
- echo ================================================================================
- echo Running $class
- ./run.sh $class "$@"
-}
-
-# parameters are: clients messages iterations
-doRun org.apache.qpid.server.queue.SendPerfTest 10 1000 100
-
-doRun org.apache.qpid.server.queue.QueuePerfTest
-
-doRun org.apache.qpid.server.queue.QueueConcurrentPerfTest
diff --git a/java/broker/build.xml b/java/broker/build.xml
index 295c38a3a3..ae133d1a96 100644
--- a/java/broker/build.xml
+++ b/java/broker/build.xml
@@ -20,18 +20,86 @@
-->
<project name="AMQ Broker" default="build">
- <property name="module.depends" value="common"/>
- <property name="module.main" value="org.apache.qpid.server.Main"/>
+ <property name="module.depends" value="management/common common"/>
+ <property name="module.test.depends" value="common/test" />
+ <property name="module.main" value="org.apache.qpid.server.Main"/>
- <import file="../module.xml"/>
+ <import file="../module.xml"/>
- <property name="output.dir" value="${module.precompiled}/org/apache/qpid/server/filter/jms/selector"/>
+ <property name="output.dir" value="${module.precompiled}/org/apache/qpid/server/filter/jms/selector"/>
- <target name="precompile">
- <mkdir dir="${output.dir}"/>
- <javacc target="src/main/grammar/SelectorParser.jj"
- outputdirectory="${output.dir}"
- javacchome="${project.root}/lib"/>
+ <property name="gentools.home" location="${project.root}/../gentools" />
+ <property name="generated.package" value="org/apache/qpid/server/logging/messages" />
+ <property name="generated.dir" location="${module.precompiled}/${generated.package}" />
+ <property name="velocity.compile.dir" value="${module.build}/velocity"/>
+ <property name="velocity.timestamp" location="${generated.dir}/velocity.timestamp" />
+
+
+ <target name="precompile" depends="gen_logging">
+ <mkdir dir="${output.dir}"/>
+ <!-- Compile Selcector Code -->
+ <javacc target="src/main/grammar/SelectorParser.jj"
+ outputdirectory="${output.dir}"
+ javacchome="${project.root}/lib"/>
+ </target>
+
+ <target name="compile_velocity" >
+ <mkdir dir="${velocity.compile.dir}" />
+ <!-- Compile LogMessages Velocity Generator -->
+ <javac source="${java.source}" target="${java.target}"
+ destdir="${velocity.compile.dir}" debug="on"
+ deprecation="${javac.deprecation}"
+ srcdir="src/velocity/java" >
+ <classpath>
+ <pathelement path="${gentools.home}/lib/velocity-1.4.jar" />
+ </classpath>
+ <compilerarg line="${javac.compiler.args}"/>
+ </javac>
+ </target>
+
+ <property name="velocity.properties.dir" value="${project.root}/broker/src/main/java/org/apache/qpid/server/logging/messages"/>
+
+ <target name="check_velocity_deps">
+ <uptodate property="velocity.notRequired" targetfile="${velocity.timestamp}">
+ <srcfiles dir="${velocity.properties.dir}" includes="LogMessages**" />
+ <srcfiles dir="src/velocity/" includes="**/*.java **/*.vm" />
+ </uptodate>
+ </target>
+
+ <target name="gen_logging" depends="compile_velocity,check_velocity_deps" unless="velocity.notRequired">
+ <mkdir dir="${generated.dir}"/>
+ <java classname="org.apache.qpid.server.logging.GenerateLogMessages" fork="true" dir="${gentools.home}/src" failonerror="true">
+ <arg line="-j -o ${generated.dir} -t ${project.root}/broker/src/velocity/templates/org/apache/qpid/server/logging/messages"/>
+ <classpath>
+ <pathelement path="${project.root}/broker/src/main/java"/>
+ <pathelement path="${velocity.compile.dir}" />
+ <fileset dir="${project.root}/lib">
+ <include name="**/*.jar"/>
+ </fileset>
+ <pathelement path="${gentools.home}/lib/velocity-1.4.jar" />
+ </classpath>
+ </java>
+ <touch file="${velocity.timestamp}" />
</target>
+
+ <target name="copy-etc-release" if="module.etc.exists" description="copy etc directory if it exists to build tree">
+ <copy todir="${module.release}/etc" failonerror="false" flatten="true">
+ <fileset dir="${module.etc}" excludes="*.conf,*.jpp"/>
+ </copy>
+ </target>
+
+ <target name="copy-bin-release" description="copy dependencies into module release">
+ <copy todir="${module.release}/bin" failonerror="true">
+ <fileset dir="${module.bin}"/>
+ </copy>
+ <copy todir="${module.release}/bin" failonerror="true" flatten="true">
+ <fileset dir="${basedir}/../common/bin"/>
+ </copy>
+ <chmod dir="${module.release}/bin" perm="ugo+rx" includes="**/*"/>
+
+ </target>
+
+ <target name="release-bin" depends="release-bin-tasks"/>
+
</project>
diff --git a/java/broker/distribution/pom.xml b/java/broker/distribution/pom.xml
deleted file mode 100644
index 9875e9bf2b..0000000000
--- a/java/broker/distribution/pom.xml
+++ /dev/null
@@ -1,153 +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.
- -->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-broker-distribution</artifactId>
- <packaging>jar</packaging>
- <version>1.0-incubating-M2-SNAPSHOT</version>
- <name>Qpid Broker Distributions</name>
- <url>http://cwiki.apache.org/confluence/display/qpid</url>
-
- <parent>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid</artifactId>
- <version>1.0-incubating-M2-SNAPSHOT</version>
- </parent>
-
- <properties>
- <topDirectoryLocation>..</topDirectoryLocation>
- <java.source.version>1.5</java.source.version>
- <qpid.version>${pom.version}</qpid.version>
- <qpid.targetDir>${project.build.directory}</qpid.targetDir>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-broker</artifactId>
- <type>jar</type>
- </dependency>
- </dependencies>
-
- <build>
- <pluginManagement>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>${java.source.version}</source>
- <target>${java.source.version}</target>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-assembly-plugin</artifactId>
- <version>${assembly.version}</version>
- <configuration>
- <descriptors>
- <descriptor>src/main/assembly/broker-bin.xml</descriptor>
- </descriptors>
- <finalName>qpid-${pom.version}</finalName>
- <outputDirectory>${qpid.targetDir}</outputDirectory>
- <tarLongFileMode>gnu</tarLongFileMode>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <configuration>
- <finalName>qpid-incubating</finalName>
- <archive>
- <manifest>
- <addClasspath>true</addClasspath>
- </manifest>
- </archive>
- </configuration>
- </plugin>
-
- </plugins>
- </pluginManagement>
-
- <plugins>
- <plugin>
- <artifactId>maven-assembly-plugin</artifactId>
- <executions>
- <execution>
- <id>distribution-package</id>
- <phase>package</phase>
- <goals>
- <goal>single</goal>
- </goals>
- <configuration>
- <descriptors>
- <descriptor>src/main/assembly/broker-bin.xml</descriptor>
- <descriptor>src/main/assembly/broker-src.xml</descriptor>
- </descriptors>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
-
- </build>
-
- <profiles>
- <profile>
- <id>tests</id>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-broker</artifactId>
- <type>test-jar</type>
- <version>${project.version}</version>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <artifactId>maven-assembly-plugin</artifactId>
- <executions>
- <execution>
- <id>distribution-package</id>
- <phase>package</phase>
- <goals>
- <goal>single</goal>
- </goals>
- <configuration>
- <descriptors>
- <descriptor>src/main/assembly/broker-bin-tests.xml</descriptor>
- </descriptors>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
-
- </build>
- </profile>
- </profiles>
-</project>
diff --git a/java/broker/distribution/src/main/assembly/broker-bin-tests.xml b/java/broker/distribution/src/main/assembly/broker-bin-tests.xml
deleted file mode 100644
index fa017d6232..0000000000
--- a/java/broker/distribution/src/main/assembly/broker-bin-tests.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
--->
-<assembly>
- <id>java-broker-bin-with-tests</id>
- <includeBaseDirectory>false</includeBaseDirectory>
- <formats>
- <format>tar.gz</format>
- <format>zip</format>
- </formats>
-
- <fileSets>
- <fileSet>
- <!-- Apache license files -->
- <directory>../../resources</directory>
- <outputDirectory>qpid-${qpid.version}</outputDirectory>
- <includes>
- <include>DISCLAIMER</include>
- <include>LICENSE.txt</include>
- <include>NOTICE.txt</include>
- <include>README.txt</include>
- </includes>
- </fileSet>
-
- <fileSet>
- <directory>../../release-docs</directory>
- <outputDirectory>qpid-${qpid.version}/docs</outputDirectory>
- <includes>
- <include>RELEASE_NOTES.txt</include>
- </includes>
- </fileSet>
-
- <!-- Include easy access to test source-->
- <fileSet>
- <directory>../src/test</directory>
- <outputDirectory>qpid-${qpid.version}/src</outputDirectory>
- <includes>
- <include>**/*.java</include>
- </includes>
- </fileSet>
-
- <!-- Execution Scripts -->
- <fileSet>
- <directory>../bin/</directory>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <includes>
- <include>**/*</include>
- </includes>
- <fileMode>777</fileMode> <!-- RWX -->
- </fileSet>
-
- <!-- Configuration -->
- <fileSet>
- <directory>../etc/</directory>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <includes>
- <include>**/*</include>
- </includes>
- <fileMode>420</fileMode>
- </fileSet>
-
- <!-- Metadata Jar -->
- <fileSet>
- <directory>target</directory>
- <outputDirectory>qpid-${qpid.version}/lib</outputDirectory>
- <includes>
- <include>qpid-incubating.jar</include>
- </includes>
- </fileSet>
- </fileSets>
-
-
- <files>
- <!-- Common Run scripts -->
- <file>
- <source>../../common/bin/qpid-run</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>qpid-run</destName>
- <fileMode>493</fileMode>
- </file>
-
- <!-- Common Configuration -->
- <file>
- <source>../../common/etc/qpid-run.conf</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>qpid-run.conf</destName>
- <fileMode>420</fileMode>
- </file>
- </files>
-
- <dependencySets>
- <dependencySet>
- <outputDirectory>qpid-${qpid.version}/lib</outputDirectory>
- <unpack>false</unpack>
- <excludes>
- <exclude>org.apache.qpid:qpid-broker-distribution</exclude>
- </excludes>
- </dependencySet>
- </dependencySets>
-</assembly>
diff --git a/java/broker/distribution/src/main/assembly/broker-bin.xml b/java/broker/distribution/src/main/assembly/broker-bin.xml
deleted file mode 100644
index e66190a3f4..0000000000
--- a/java/broker/distribution/src/main/assembly/broker-bin.xml
+++ /dev/null
@@ -1,183 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
--->
-<assembly>
- <!-- id typically identifies the "type" (src vs bin etc) of the assembly -->
- <id>java-broker-bin</id>
- <includeBaseDirectory>false</includeBaseDirectory>
- <formats>
- <format>tar.gz</format>
- <format>zip</format>
- </formats>
-
- <fileSets>
- <!-- Apache Licensing -->
- <fileSet>
- <directory>../../resources</directory>
- <outputDirectory>qpid-${qpid.version}</outputDirectory>
- <includes>
- <include>DISCLAIMER</include>
- <include>LICENSE.txt</include>
- <include>NOTICE.txt</include>
- <include>README.txt</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>../..</directory>
- <outputDirectory>qpid-${qpid.version}</outputDirectory>
- <includes>
- <include>*.txt</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>../../src/main/release-docs</directory>
- <outputDirectory>qpid-${qpid.version}/docs</outputDirectory>
- <includes>
- <include>RELEASE_NOTES.txt</include>
- </includes>
- </fileSet>
-
- <!-- Metadata Jar -->
- <fileSet>
- <directory>target</directory>
- <outputDirectory>qpid-${qpid.version}/lib</outputDirectory>
- <includes>
- <include>qpid-incubating.jar</include>
- </includes>
- </fileSet>
- </fileSets>
- <files>
- <!-- due to a bug in the assembly plugin (MASSEMBLY-153) you have
- to use decimal numbers to specify fileMode -->
- <file>
- <source>../../common/etc/qpid-run.conf</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>qpid-run.conf</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../etc/config.xml</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>config.xml</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../etc/jmxremote.access</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>jmxremote.access</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../etc/log4j.xml</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>log4j.xml</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../etc/passwd</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>passwd</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../etc/qpid-server.conf</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>qpid-server.conf</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../etc/virtualhosts.xml</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>virtualhosts.xml</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../../common/bin/qpid-run</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>qpid-run</destName>
- <fileMode>473</fileMode>
- </file>
- <file>
- <source>../bin/qpid-passwd</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>qpid-passwd</destName>
- <fileMode>473</fileMode>
- </file>
- <file>
- <source>../bin/qpid-server</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>qpid-server</destName>
- <fileMode>473</fileMode>
- </file>
- <file>
- <source>../bin/qpid-server.bat</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>qpid-server.bat</destName>
- <fileMode>473</fileMode>
- </file>
- <file>
- <source>../bin/run.bat</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>run.bat</destName>
- <fileMode>473</fileMode>
- </file>
- <file>
- <source>../bin/run.sh</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>run.sh</destName>
- <fileMode>473</fileMode>
- </file>
- <file>
- <source>../bin/runAll</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>runAll</destName>
- <fileMode>473</fileMode>
- </file>
- </files>
-
- <dependencySets>
- <dependencySet>
- <outputDirectory>qpid-${qpid.version}/lib</outputDirectory>
- <unpack>false</unpack>
- <!-- This needs to be tidied up QPID-280 -->
- <excludes>
- <exclude>org.apache.qpid:qpid-broker-distribution</exclude>
- <exclude>org.apache.qpid.management:org.apache.qpid.management.ui</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.commands</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.contenttype</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.expressions</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.jobs</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.runtime</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.runtime.compatibility.auth</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.runtime.compatibility.registry</exclude>
- <exclude>org.eclipse.equinox:org.eclipse.equinox.common</exclude>
- <exclude>org.eclipse.equinox:org.eclipse.equinox.preferences</exclude>
- <exclude>org.eclipse.equinox:org.eclipse.equinox.registry</exclude>
- <exclude>org.eclipse.help:org.eclipse.help</exclude>
- <exclude>org.eclipse.jface:org.eclipse.jface</exclude>
- <exclude>org.eclipse.osgi:org.eclipse.osgi</exclude>
- <exclude>org.eclipse.swt:org.eclipse.swt</exclude>
- <exclude>org.eclipse.swt:org.eclipse.swt.win32.win32.x86</exclude>
- <exclude>org.eclipse.ui:org.eclipse.ui</exclude>
- <exclude>org.eclipse.ui:org.eclipse.ui.forms</exclude>
- <exclude>org.eclipse.ui:org.eclipse.ui.workbench</exclude>
- </excludes>
- </dependencySet>
- </dependencySets>
-</assembly>
diff --git a/java/broker/distribution/src/main/assembly/broker-src.xml b/java/broker/distribution/src/main/assembly/broker-src.xml
deleted file mode 100644
index 28a22c3851..0000000000
--- a/java/broker/distribution/src/main/assembly/broker-src.xml
+++ /dev/null
@@ -1,78 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
--->
-<assembly>
- <!-- id typically identifies the "type" (src vs bin etc) of the assembly -->
- <id>java-broker-src</id>
- <includeBaseDirectory>false</includeBaseDirectory>
- <formats>
- <format>tar.gz</format>
- <format>zip</format>
- </formats>
-
- <fileSets>
- <!-- Apache Licensing -->
- <fileSet>
- <directory>../../resources</directory>
- <outputDirectory>qpid-${qpid.version}-src</outputDirectory>
- <includes>
- <include>DISCLAIMER</include>
- <include>LICENSE.txt</include>
- <include>licenses/*.*</include>
- <include>NOTICE.txt</include>
- <include>README.txt</include>
- <include>BUILDING.txt</include>
- </includes>
- </fileSet>
- <!-- Broker source -->
- <fileSet>
- <directory>..</directory>
- <outputDirectory>qpid-${qpid.version}-src</outputDirectory>
- <includes>
- <include>**/*</include>
- </includes>
- <!-- Tidy up wrt to QPID-280 -->
- <excludes>
- <exclude>build.xml</exclude>
- <exclude>distribution/build.xml</exclude>
- <exclude>benchmark</exclude>
- <exclude>benchmark/**/*</exclude>
- <exclude>**/target</exclude>
- <exclude>**/target/**/*</exclude>
- <exclude>**/build</exclude>
- <exclude>**/build/**/*</exclude>
- <exclude>**/.settings</exclude>
- <exclude>**/.classpath</exclude>
- <exclude>**/.project</exclude>
- <exclude>**/.wtpmodules</exclude>
- <exclude>**/surefire*</exclude>
- <exclude>**/cobertura.ser</exclude>
- <exclude>bin</exclude>
- <exclude>bin/*</exclude>
- <exclude>lib</exclude>
- <exclude>lib/**/*</exclude>
- <exclude>**/var/journal</exclude>
- <exclude>**/build.out*</exclude>
- <exclude>**/eclipse-plugin/bin/**</exclude>
- <exclude>**/eclipse-plugin/plugins/**</exclude>
- <exclude>**/eclipse-plugin/src/main/resources/**</exclude>
- </excludes>
- </fileSet>
- </fileSets>
-</assembly>
diff --git a/java/broker/etc/acl.config.xml b/java/broker/etc/acl.config.xml
deleted file mode 100644
index 614ecf0a88..0000000000
--- a/java/broker/etc/acl.config.xml
+++ /dev/null
@@ -1,231 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<!--
- -
- - Licensed to the Apache Software Foundation (ASF) under one
- - or more contributor license agreements. See the NOTICE file
- - distributed with this work for additional information
- - regarding copyright ownership. The ASF licenses this file
- - to you under the Apache License, Version 2.0 (the
- - "License"); you may not use this file except in compliance
- - with the License. You may obtain a copy of the License at
- -
- - http://www.apache.org/licenses/LICENSE-2.0
- -
- - Unless required by applicable law or agreed to in writing,
- - software distributed under the License is distributed on an
- - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- - KIND, either express or implied. See the License for the
- - specific language governing permissions and limitations
- - under the License.
- -
- -->
-<broker>
- <prefix>${QPID_HOME}</prefix>
- <work>${QPID_WORK}</work>
- <conf>${prefix}/etc</conf>
- <connector>
- <!-- Uncomment out this block and edit the keystorePath and keystorePassword
- to enable SSL support
- <ssl>
- <enabled>true</enabled>
- <sslOnly>true</sslOnly>
- <keystorePath>/path/to/keystore.ks</keystorePath>
- <keystorePassword>keystorepass</keystorePassword>
- </ssl>-->
- <qpidnio>false</qpidnio>
- <!-- I've had the 0.0 and 0.1 Reader threads continually throwing IOException when client closes-->
- <protectio>false</protectio>
- <transport>nio</transport>
- <port>5672</port>
- <sslport>8672</sslport>
- <socketReceiveBuffer>32768</socketReceiveBuffer>
- <socketSendBuffer>32768</socketSendBuffer>
- </connector>
- <management>
- <enabled>false</enabled>
- <jmxport>8999</jmxport>
- <security-enabled>false</security-enabled>
- </management>
- <advanced>
- <filterchain enableExecutorPool="true"/>
- <enablePooledAllocator>false</enablePooledAllocator>
- <enableDirectBuffers>false</enableDirectBuffers>
- <framesize>65535</framesize>
- <compressBufferOnQueue>false</compressBufferOnQueue>
- <enableJMSXUserID>false</enableJMSXUserID>
- </advanced>
-
- <security>
- <principal-databases>
- <!-- Example use of Base64 encoded MD5 hashes for authentication via CRAM-MD5-Hashed -->
- <principal-database>
- <name>passwordfile</name>
- <class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>
- <attributes>
- <attribute>
- <name>passwordFile</name>
- <value>${conf}/passwd</value>
- </attribute>
- </attributes>
- </principal-database>
- </principal-databases>
-
- <access>
- <class>org.apache.qpid.server.security.access.plugins.DenyAll</class>
- </access>
-
- <jmx>
- <access>${conf}/jmxremote.access</access>
- <principal-database>passwordfile</principal-database>
- </jmx>
- </security>
-
- <virtualhosts>
- <directory>${conf}/virtualhosts</directory>
-
- <virtualhost>
- <name>test</name>
- <test>
- <store>
- <class>org.apache.qpid.server.store.MemoryMessageStore</class>
- </store>
-
- <queues>
- <exchange>amq.direct</exchange>
- <!-- 4Mb -->
- <maximumQueueDepth>4235264</maximumQueueDepth>
- <!-- 2Mb -->
- <maximumMessageSize>2117632</maximumMessageSize>
- <!-- 10 mins -->
- <maximumMessageAge>600000</maximumMessageAge>
- </queues>
-
-
- <security>
- <access>
- <class>org.apache.qpid.server.security.access.plugins.SimpleXML</class>
- </access>
-
- <access_control_list>
- <!-- This section grants pubish rights to an exchange + routing key pair -->
- <publish>
- <exchanges>
- <exchange>
- <name>amq.direct</name>
- <routing_keys>
-
- <!-- Allow clients to publish requests -->
- <routing_key>
- <value>example.RequestQueue</value>
- <users>
- <user>client</user>
- </users>
- </routing_key>
-
- <!-- Allow the processor to respond to a client on their Temporary Topic -->
- <routing_key>
- <value>tmp_*</value>
- <users>
- <user>server</user>
- </users>
- </routing_key>
- <routing_key>
- <value>TempQueue*</value>
- <users>
- <user>server</user>
- </users>
- </routing_key>
- </routing_keys>
-
- </exchange>
- </exchanges>
- </publish>
-
- <!-- This section grants users the ability to consume from the broker -->
- <consume>
- <queues>
-
- <!-- Allow the clients to consume from their temporary queues-->
- <queue>
- <temporary/>
- <users>
- <user>client</user>
- </users>
- </queue>
-
-
- <!-- Only allow the server to consume from the Request Queue-->
- <queue>
- <name>example.RequestQueue</name>
- <users>
- <user>server</user>
- </users>
- </queue>
-
-
- </queues>
- </consume>
-
- <!-- This section grants clients the ability to create queues and exchanges -->
- <create>
- <queues>
- <!-- Allow clients to create temporary queues-->
- <queue>
- <temporary/>
- <exchanges>
- <exchange>
- <name>amq.direct</name>
- <users>
- <user>client</user>
- </users>
- </exchange>
- </exchanges>
- </queue>
- <!-- Allow the server to create the Request Queue-->
- <queue>
- <name>example.RequestQueue</name>
- <users>
- <user>server</user>
- </users>
- </queue>
-
- </queues>
- </create>
-
-
- </access_control_list>
-
- </security>
- </test>
- </virtualhost>
-
-
- <virtualhost>
- <name>development</name>
- <development>
- <store>
- <class>org.apache.qpid.server.store.MemoryMessageStore</class>
- </store>
- </development>
- </virtualhost>
-
- <virtualhost>
- <name>localhost</name>
- <localhost>
- <store>
- <class>org.apache.qpid.server.store.MemoryMessageStore</class>
- </store>
- </localhost>
- </virtualhost>
-
- </virtualhosts>
-
- <heartbeat>
- <delay>0</delay>
- <timeoutFactor>2.0</timeoutFactor>
- </heartbeat>
-
- <virtualhosts>${conf}/virtualhosts.xml</virtualhosts>
-</broker>
-
-
diff --git a/java/broker/etc/config.xml b/java/broker/etc/config.xml
index 80ee039ee5..8fb3a8cf5a 100644
--- a/java/broker/etc/config.xml
+++ b/java/broker/etc/config.xml
@@ -24,17 +24,20 @@
<work>${QPID_WORK}</work>
<conf>${prefix}/etc</conf>
<connector>
- <!-- Uncomment out this block and edit the keystorePath and keystorePassword
- to enable SSL support
+ <!-- To enable SSL edit the keystorePath and keystorePassword
+ and set enabled to true.
+ To disasble Non-SSL port set sslOnly to true -->
<ssl>
- <enabled>true</enabled>
- <sslOnly>true</sslOnly>
+ <enabled>false</enabled>
+ <sslOnly>false</sslOnly>
<keystorePath>/path/to/keystore.ks</keystorePath>
<keystorePassword>keystorepass</keystorePassword>
- </ssl>-->
+ </ssl>
<qpidnio>false</qpidnio>
<protectio>
<enabled>false</enabled>
+ <readBufferLimitSize>262144</readBufferLimitSize>
+ <writeBufferLimitSize>262144</writeBufferLimitSize>
</protectio>
<transport>nio</transport>
<port>5672</port>
@@ -45,7 +48,12 @@
<management>
<enabled>true</enabled>
<jmxport>8999</jmxport>
- <security-enabled>false</security-enabled>
+ <ssl>
+ <enabled>true</enabled>
+ <!-- Update below path to your keystore location, eg ${conf}/qpid.keystore -->
+ <keyStorePath>${prefix}/../test-profiles/test_resources/ssl/keystore.jks</keyStorePath>
+ <keyStorePassword>password</keyStorePassword>
+ </ssl>
</management>
<advanced>
<filterchain enableExecutorPool="true"/>
@@ -54,6 +62,7 @@
<framesize>65535</framesize>
<compressBufferOnQueue>false</compressBufferOnQueue>
<enableJMSXUserID>false</enableJMSXUserID>
+ <locale>en_US</locale>
</advanced>
<security>
@@ -74,6 +83,9 @@
<access>
<class>org.apache.qpid.server.security.access.plugins.AllowAll</class>
</access>
+
+ <msg-auth>false</msg-auth>
+
<jmx>
<access>${conf}/jmxremote.access</access>
<principal-database>passwordfile</principal-database>
@@ -81,40 +93,143 @@
</security>
<virtualhosts>
- <directory>${conf}/virtualhosts</directory>
+ <default>test</default>
<virtualhost>
<name>localhost</name>
<localhost>
<store>
- <class>org.apache.qpid.server.store.MemoryMessageStore</class>
+ <class>org.apache.qpid.server.store.MemoryMessageStore
+ </class>
</store>
<housekeeping>
<expiredMessageCheckPeriod>20000</expiredMessageCheckPeriod>
</housekeeping>
+ <exchanges>
+ <exchange>
+ <type>direct</type>
+ <name>test.direct</name>
+ <durable>true</durable>
+ </exchange>
+ <exchange>
+ <type>topic</type>
+ <name>test.topic</name>
+ </exchange>
+ </exchanges>
+ <queues>
+ <exchange>amq.direct</exchange>
+ <maximumQueueDepth>4235264</maximumQueueDepth>
+ <!-- 4Mb -->
+ <maximumMessageSize>2117632</maximumMessageSize>
+ <!-- 2Mb -->
+ <maximumMessageAge>600000</maximumMessageAge>
+ <!-- 10 mins -->
+ <maximumMessageCount>50</maximumMessageCount>
+ <!-- 50 messages -->
+
+ <queue>
+ <name>queue</name>
+ </queue>
+ <queue>
+ <name>ping</name>
+ </queue>
+ <queue>
+ <name>test-queue</name>
+ <test-queue>
+ <exchange>test.direct</exchange>
+ <durable>true</durable>
+ </test-queue>
+ </queue>
+ <queue>
+ <name>test-ping</name>
+ <test-ping>
+ <exchange>test.direct</exchange>
+ </test-ping>
+ </queue>
+
+ </queues>
</localhost>
</virtualhost>
+
<virtualhost>
<name>development</name>
<development>
<store>
- <class>org.apache.qpid.server.store.MemoryMessageStore</class>
+ <class>org.apache.qpid.server.store.MemoryMessageStore
+ </class>
</store>
+
+ <queues>
+ <minimumAlertRepeatGap>30000</minimumAlertRepeatGap>
+ <maximumMessageCount>50</maximumMessageCount>
+ <queue>
+ <name>queue</name>
+ <queue>
+ <exchange>amq.direct</exchange>
+ <maximumQueueDepth>4235264</maximumQueueDepth>
+ <!-- 4Mb -->
+ <maximumMessageSize>2117632</maximumMessageSize>
+ <!-- 2Mb -->
+ <maximumMessageAge>600000</maximumMessageAge>
+ <!-- 10 mins -->
+ </queue>
+ </queue>
+ <queue>
+ <name>ping</name>
+ <ping>
+ <exchange>amq.direct</exchange>
+ <maximumQueueDepth>4235264</maximumQueueDepth>
+ <!-- 4Mb -->
+ <maximumMessageSize>2117632</maximumMessageSize>
+ <!-- 2Mb -->
+ <maximumMessageAge>600000</maximumMessageAge>
+ <!-- 10 mins -->
+ </ping>
+ </queue>
+ </queues>
</development>
</virtualhost>
-
<virtualhost>
<name>test</name>
<test>
<store>
- <class>org.apache.qpid.server.store.MemoryMessageStore</class>
+ <class>org.apache.qpid.server.store.MemoryMessageStore
+ </class>
</store>
+
+ <queues>
+ <minimumAlertRepeatGap>30000</minimumAlertRepeatGap>
+ <maximumMessageCount>50</maximumMessageCount>
+ <queue>
+ <name>queue</name>
+ <queue>
+ <exchange>amq.direct</exchange>
+ <maximumQueueDepth>4235264</maximumQueueDepth>
+ <!-- 4Mb -->
+ <maximumMessageSize>2117632</maximumMessageSize>
+ <!-- 2Mb -->
+ <maximumMessageAge>600000</maximumMessageAge>
+ <!-- 10 mins -->
+ </queue>
+ </queue>
+ <queue>
+ <name>ping</name>
+ <ping>
+ <exchange>amq.direct</exchange>
+ <maximumQueueDepth>4235264</maximumQueueDepth>
+ <!-- 4Mb -->
+ <maximumMessageSize>2117632</maximumMessageSize>
+ <!-- 2Mb -->
+ <maximumMessageAge>600000</maximumMessageAge>
+ <!-- 10 mins -->
+ </ping>
+ </queue>
+ </queues>
</test>
</virtualhost>
-
</virtualhosts>
<heartbeat>
<delay>0</delay>
@@ -124,7 +239,8 @@
<auto_register>true</auto_register>
</queue>
- <virtualhosts>${conf}/virtualhosts.xml</virtualhosts>
+ <status-updates>ON</status-updates>
+
</broker>
diff --git a/java/broker/etc/debug.log4j.xml b/java/broker/etc/debug.log4j.xml
index 71f9502b75..fc0bd9f34f 100644
--- a/java/broker/etc/debug.log4j.xml
+++ b/java/broker/etc/debug.log4j.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
<!--
-
- Licensed to the Apache Software Foundation (ASF) under one
@@ -18,10 +18,10 @@
- specific language governing permissions and limitations
- under the License.
-
- -->
-<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
-<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
- <appender name="ArchivingFileAppender" class="org.apache.log4j.QpidCompositeRollingAppender">
+ --><!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="null" threshold="null">
+ <appender class="org.apache.log4j.QpidCompositeRollingAppender" name="ArchivingFileAppender">
<!-- Ensure that logs allways have the dateFormat set-->
<param name="StaticLogFileName" value="false"/>
<param name="File" value="${QPID_WORK}/log/${logprefix}qpid${logsuffix}.log"/>
@@ -48,7 +48,7 @@
</layout>
</appender>
- <appender name="FileAppender" class="org.apache.log4j.FileAppender">
+ <appender class="org.apache.log4j.FileAppender" name="FileAppender">
<param name="File" value="${QPID_WORK}/log/${logprefix}qpid${logsuffix}.log"/>
<param name="Append" value="false"/>
@@ -57,7 +57,7 @@
</layout>
</appender>
- <appender name="AlertFile" class="org.apache.log4j.FileAppender">
+ <appender class="org.apache.log4j.FileAppender" name="AlertFile">
<param name="File" value="${QPID_WORK}/log/alert.log"/>
<param name="Append" value="false"/>
@@ -66,28 +66,28 @@
</layout>
</appender>
- <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
+ <appender class="org.apache.log4j.ConsoleAppender" name="STDOUT">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
</layout>
</appender>
- <category name="Qpid.Broker">
+ <category additivity="true" name="Qpid.Broker">
<priority value="debug"/>
<appender-ref ref="AlertFile"/>
<!--appender-ref ref="STDOUT"/-->
</category>
- <category name="org.apache.qpid.server.queue.AMQQueueMBean">
+ <category additivity="true" name="org.apache.qpid.server.queue.AMQQueueMBean">
<priority value="info"/>
<appender-ref ref="AlertFile"/>
</category>
<!-- Provide warnings to standard output -->
- <!--category name="org.apache.qpid">
+ <!--category additivity="true" name="org.apache.qpid">
<priority value="warn"/>
<appender-ref ref="STDOUT"/>
</category-->
@@ -96,11 +96,11 @@
<!-- Additional level settings for debugging -->
<!-- Each class in the Broker is a category that can have its logging level adjusted. -->
<!-- This will provide more details if available about that classes processing. -->
- <!--category name="org.apache.qpid.server.txn">
+ <!--category additivity="true" name="org.apache.qpid.server.txn">
<priority value="debug"/>
</category>-->
- <!--<category name="org.apache.qpid.server.store">
+ <!--<category additivity="true" name="org.apache.qpid.server.store">
<priority value="debug"/>
</category-->
diff --git a/java/broker/etc/log4j.xml b/java/broker/etc/log4j.xml
index af8e7a8293..ba8950dcd0 100644
--- a/java/broker/etc/log4j.xml
+++ b/java/broker/etc/log4j.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
<!--
-
- Licensed to the Apache Software Foundation (ASF) under one
@@ -18,47 +18,51 @@
- specific language governing permissions and limitations
- under the License.
-
- -->
-<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
-<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
- <appender name="ArchivingFileAppender" class="org.apache.log4j.QpidCompositeRollingAppender">
- <!-- Ensure that logs allways have the dateFormat set-->
- <param name="StaticLogFileName" value="false"/>
- <param name="File" value="${QPID_WORK}/log/${logprefix}qpid${logsuffix}.log"/>
- <param name="Append" value="false"/>
+ --><!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="null" threshold="null">
+ <appender class="org.apache.log4j.QpidCompositeRollingAppender" name="ArchivingFileAppender">
+ <!-- Ensure that logs allways have the dateFormat set Default: TRUE-->
+ <param name="StaticLogFileName" value="true"/>
+ <param name="file" value="${QPID_WORK}/log/${logprefix}qpid${logsuffix}.log"/>
+ <!-- Style of rolling to use, by:
+ File Size (1),
+ Date(2),
+ Both(3) - DEFAULT
+ When Date (or Both) is enabled then the value of DatePattern will determine
+ when the new file is made. e.g. a DatePattern of "'.'yyyy-MM-dd-HH-mm"
+ which includes minutes will cause a new backup file to be made every minute.
+ -->
+ <param name="RollingStyle" value="1"/>
<!-- Change the direction so newer files have bigger numbers -->
- <!-- So log.1 is written then log.2 etc This prevents a lot of file renames at log rollover -->
- <param name="CountDirection" value="1"/>
- <!-- Use default 10MB -->
- <!--param name="MaxFileSize" value="100000"/-->
+ <!--
+ negative means backups become <latest>,.0,.1,2,...,n
+ 0 means backup name is date stampted and follow Positive number if DataPattern clashes.
+ Positive means backup becomes <lastest,n,n-1,n-2,..0
+
+ Default is negative.
+ -->
+ <param name="CountDirection" value="0"/>
+ <!-- Use default 1MB -->
+ <param name="MaxFileSize" value="1MB"/>
<param name="DatePattern" value="'.'yyyy-MM-dd-HH-mm"/>
- <!-- Unlimited number of backups -->
+ <!-- Unlimited number of backups : Default: 0, no backups, -1 infinite -->
<param name="MaxSizeRollBackups" value="-1"/>
- <!-- Compress(gzip) the backup files-->
+ <!-- Compress(gzip) the backup files default:FALSE-->
<param name="CompressBackupFiles" value="true"/>
- <!-- Compress the backup files using a second thread -->
+ <!-- Compress the backup files using a second thread DEFAULT: FALSE-->
<param name="CompressAsync" value="true"/>
- <!-- Start at zero numbered files-->
- <param name="ZeroBased" value="true"/>
- <!-- Backup Location -->
- <param name="backupFilesToPath" value="${QPID_WORK}/backup/log"/>
+ <!-- Backup Location : Default same dir as log file -->
+ <param name="backupFilesToPath" value="${QPID_WORK}/backup/log"/>
- <layout class="org.apache.log4j.PatternLayout">
- <param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
- </layout>
- </appender>
-
- <appender name="FileAppender" class="org.apache.log4j.FileAppender">
- <param name="File" value="${QPID_WORK}/log/${logprefix}qpid${logsuffix}.log"/>
- <param name="Append" value="false"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
</layout>
</appender>
- <appender name="AlertFile" class="org.apache.log4j.FileAppender">
- <param name="File" value="${QPID_WORK}/log/alert.log"/>
+ <appender class="org.apache.log4j.FileAppender" name="FileAppender">
+ <param name="File" value="${QPID_WORK}/log/${logprefix}qpid${logsuffix}.log"/>
<param name="Append" value="false"/>
<layout class="org.apache.log4j.PatternLayout">
@@ -66,41 +70,40 @@
</layout>
</appender>
- <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
+ <appender class="org.apache.log4j.ConsoleAppender" name="STDOUT">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
</layout>
</appender>
- <category name="Qpid.Broker">
+ <!-- Qpid.Broker log is a special log category used to log only useful broker startup details -->
+ <category additivity="true" name="Qpid.Broker">
<priority value="debug"/>
- <appender-ref ref="AlertFile"/>
<appender-ref ref="STDOUT"/>
</category>
- <category name="org.apache.qpid.server.queue.AMQQueueMBean">
+ <category additivity="true" name="org.apache.qpid.server.queue.AMQQueueMBean">
<priority value="info"/>
- <appender-ref ref="AlertFile"/>
</category>
<!-- Provide warnings to standard output -->
- <category name="org.apache.qpid">
+ <category additivity="true" name="org.apache.qpid">
<priority value="warn"/>
- <appender-ref ref="STDOUT"/>
</category>
<!-- Examples of additional logging settings -->
<!-- Used to generate extra debug. See debug.log4j.xml -->
- <!--<category name="org.apache.qpid.server.store">
+ <!--<category additivity="true" name="org.apache.qpid.server.store">
<priority value="debug"/>
</category-->
- <!--category name="org.apache.qpid.server.txn">
- <priority value="debug"/>
- </category>-->
+ <!-- Set the commons logging that the XML parser uses to WARN, it is very chatty at debug -->
+ <logger name="org.apache.commons">
+ <level value="WARN"/>
+ </logger>
<!-- Log all info events to file -->
<root>
diff --git a/java/broker/etc/passwd b/java/broker/etc/passwd
index 7aca438551..99f0f05c6a 100644
--- a/java/broker/etc/passwd
+++ b/java/broker/etc/passwd
@@ -19,4 +19,5 @@
guest:guest
client:guest
server:guest
+admin:admin
diff --git a/java/broker/etc/persistent_config.xml b/java/broker/etc/persistent_config.xml
index 2143009711..67ef28117d 100644
--- a/java/broker/etc/persistent_config.xml
+++ b/java/broker/etc/persistent_config.xml
@@ -37,6 +37,12 @@
<management>
<enabled>true</enabled>
<jmxport>8999</jmxport>
+ <ssl>
+ <enabled>true</enabled>
+ <!-- Update below path to your keystore location, eg ${conf}/qpid.keystore -->
+ <keyStorePath>${prefix}/../test_resources/ssl/keystore.jks</keyStorePath>
+ <keyStorePassword>password</keyStorePassword>
+ </ssl>
</management>
<advanced>
<filterchain enableExecutorPool="true"/>
diff --git a/java/broker/etc/qpid-server.conf b/java/broker/etc/qpid-server.conf
index c310094817..8a16849b04 100644
--- a/java/broker/etc/qpid-server.conf
+++ b/java/broker/etc/qpid-server.conf
@@ -17,7 +17,7 @@
# under the License.
#
-QPID_LIBS=$QPID_HOME/lib/qpid-incubating.jar:$QPID_HOME/lib/bdbstore-launch.jar
+QPID_LIBS=$QPID_HOME/lib/qpid-all.jar:$QPID_HOME/lib/bdbstore-launch.jar
export JAVA=java \
JAVA_VM=-server \
diff --git a/java/broker/etc/transient_config.xml b/java/broker/etc/transient_config.xml
index 062552ea2d..a21afe7d21 100644
--- a/java/broker/etc/transient_config.xml
+++ b/java/broker/etc/transient_config.xml
@@ -37,6 +37,12 @@
<management>
<enabled>true</enabled>
<jmxport>8999</jmxport>
+ <ssl>
+ <enabled>true</enabled>
+ <!-- Update below path to your keystore location, eg ${conf}/qpid.keystore -->
+ <keyStorePath>${prefix}/../test_resources/ssl/keystore.jks</keyStorePath>
+ <keyStorePassword>password</keyStorePassword>
+ </ssl>
</management>
<advanced>
<filterchain enableExecutorPool="true"/>
diff --git a/java/broker/etc/virtualhosts.xml b/java/broker/etc/virtualhosts.xml
deleted file mode 100644
index f62ec3f5d7..0000000000
--- a/java/broker/etc/virtualhosts.xml
+++ /dev/null
@@ -1,123 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<!--
- -
- - Licensed to the Apache Software Foundation (ASF) under one
- - or more contributor license agreements. See the NOTICE file
- - distributed with this work for additional information
- - regarding copyright ownership. The ASF licenses this file
- - to you under the Apache License, Version 2.0 (the
- - "License"); you may not use this file except in compliance
- - with the License. You may obtain a copy of the License at
- -
- - http://www.apache.org/licenses/LICENSE-2.0
- -
- - Unless required by applicable law or agreed to in writing,
- - software distributed under the License is distributed on an
- - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- - KIND, either express or implied. See the License for the
- - specific language governing permissions and limitations
- - under the License.
- -
- -->
-<virtualhosts>
- <default>test</default>
- <virtualhost>
- <name>localhost</name>
- <localhost>
- <exchanges>
- <exchange>
- <type>direct</type>
- <name>test.direct</name>
- <durable>true</durable>
- </exchange>
- <exchange>
- <type>topic</type>
- <name>test.topic</name>
- </exchange>
- </exchanges>
- <queues>
- <exchange>amq.direct</exchange>
- <maximumQueueDepth>4235264</maximumQueueDepth> <!-- 4Mb -->
- <maximumMessageSize>2117632</maximumMessageSize> <!-- 2Mb -->
- <maximumMessageAge>600000</maximumMessageAge> <!-- 10 mins -->
-
- <queue>
- <name>queue</name>
- </queue>
- <queue>
- <name>ping</name>
- </queue>
- <queue>
- <name>test-queue</name>
- <test-queue>
- <exchange>test.direct</exchange>
- <durable>true</durable>
- </test-queue>
- </queue>
- <queue>
- <name>test-ping</name>
- <test-ping>
- <exchange>test.direct</exchange>
- </test-ping>
- </queue>
-
- </queues>
- </localhost>
- </virtualhost>
-
-
- <virtualhost>
- <name>development</name>
- <development>
- <queues>
- <minimumAlertRepeatGap>30000</minimumAlertRepeatGap>
- <maximumMessageCount>5000</maximumMessageCount>
- <queue>
- <name>queue</name>
- <queue>
- <exchange>amq.direct</exchange>
- <maximumQueueDepth>4235264</maximumQueueDepth> <!-- 4Mb -->
- <maximumMessageSize>2117632</maximumMessageSize> <!-- 2Mb -->
- <maximumMessageAge>600000</maximumMessageAge> <!-- 10 mins -->
- </queue>
- </queue>
- <queue>
- <name>ping</name>
- <ping>
- <exchange>amq.direct</exchange>
- <maximumQueueDepth>4235264</maximumQueueDepth> <!-- 4Mb -->
- <maximumMessageSize>2117632</maximumMessageSize> <!-- 2Mb -->
- <maximumMessageAge>600000</maximumMessageAge> <!-- 10 mins -->
- </ping>
- </queue>
- </queues>
- </development>
- </virtualhost>
- <virtualhost>
- <name>test</name>
- <test>
- <queues>
- <minimumAlertRepeatGap>30000</minimumAlertRepeatGap>
- <maximumMessageCount>5000</maximumMessageCount>
- <queue>
- <name>queue</name>
- <queue>
- <exchange>amq.direct</exchange>
- <maximumQueueDepth>4235264</maximumQueueDepth> <!-- 4Mb -->
- <maximumMessageSize>2117632</maximumMessageSize> <!-- 2Mb -->
- <maximumMessageAge>600000</maximumMessageAge> <!-- 10 mins -->
- </queue>
- </queue>
- <queue>
- <name>ping</name>
- <ping>
- <exchange>amq.direct</exchange>
- <maximumQueueDepth>4235264</maximumQueueDepth> <!-- 4Mb -->
- <maximumMessageSize>2117632</maximumMessageSize> <!-- 2Mb -->
- <maximumMessageAge>600000</maximumMessageAge> <!-- 10 mins -->
- </ping>
- </queue>
- </queues>
- </test>
- </virtualhost>
-</virtualhosts>
diff --git a/java/broker/pom.xml b/java/broker/pom.xml
deleted file mode 100644
index 53913f161f..0000000000
--- a/java/broker/pom.xml
+++ /dev/null
@@ -1,277 +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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-broker</artifactId>
- <packaging>jar</packaging>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <name>Qpid Broker</name>
- <url>http://cwiki.apache.org/confluence/display/qpid</url>
-
- <parent>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid</artifactId>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <relativePath>../pom.xml</relativePath>
- </parent>
-
- <properties>
- <topDirectoryLocation>..</topDirectoryLocation>
- </properties>
-
- <dependencies>
-
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-common</artifactId>
- </dependency>
-
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <version>1.4.0</version>
- </dependency>
-
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.4.0</version>
- </dependency>
-
- <dependency>
- <groupId>commons-cli</groupId>
- <artifactId>commons-cli</artifactId>
- <exclusions>
- <exclusion>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
-
- <dependency>
- <groupId>commons-configuration</groupId>
- <artifactId>commons-configuration</artifactId>
- <exclusions>
- <exclusion>
- <groupId>javax.servlet</groupId>
- <artifactId>servlet-api</artifactId>
- </exclusion>
- <exclusion>
- <groupId>dom4j</groupId>
- <artifactId>dom4j</artifactId>
- </exclusion>
- <exclusion>
- <groupId>commons-beanutils</groupId>
- <artifactId>commons-beanutils</artifactId>
- </exclusion>
- <exclusion>
- <groupId>commons-beanutils</groupId>
- <artifactId>commons-beanutils-core</artifactId>
- </exclusion>
- <exclusion>
- <groupId>commons-digester</groupId>
- <artifactId>commons-digester</artifactId>
- </exclusion>
- <exclusion>
- <groupId>xerces</groupId>
- <artifactId>xercesImpl</artifactId>
- </exclusion>
- <exclusion>
- <groupId>xml-apis</groupId>
- <artifactId>xml-apis</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
-
- <dependency>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- </dependency>
-
- <!-- Test Dependencies -->
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.felix</groupId>
- <artifactId>org.osgi.core</artifactId>
- <version>1.0.0</version>
- </dependency>
- <dependency>
- <groupId>org.apache.felix</groupId>
- <artifactId>org.apache.felix.framework</artifactId>
- <version>1.0.0</version>
- </dependency>
- <dependency>
- <groupId>org.apache.derby</groupId>
- <artifactId>derby</artifactId>
- <version>10.3.2.1</version>
- </dependency>
- </dependencies>
-
- <build>
-
- <plugins>
-
-
- <!--plugin>
- <artifactId>minijar-maven-plugin</artifactId>
- <groupId>org.codehaus.mojo</groupId>
- <executions>
- <execution>
- <phase>package</phase>
- <goals>
- <goal>minijars</goal>
- </goals>
- <configuration>
- <stripUnusedClasses>true</stripUnusedClasses>
- </configuration>
- </execution>
- </executions>
- </plugin-->
-
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-antrun-plugin</artifactId>
- </plugin>
-
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>javacc-maven-plugin</artifactId>
- <version>2.0</version>
- <executions>
- <execution>
- <phase>generate-sources</phase>
- <configuration>
- <sourceDirectory>${basedir}/src/main/grammar</sourceDirectory>
- <outputDirectory>${basedir}/target/generated-sources</outputDirectory>
- <packageName>org.apache.qpid.server.filter.jms.selector</packageName>
- </configuration>
- <goals>
- <goal>javacc</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <systemProperties>
- <property>
- <name>amqj.noAutoCreateVMBroker</name>
- <value>true</value>
- </property>
- <property>
- <name>amqj.logging.level</name>
- <value>${amqj.logging.level}</value>
- </property>
- <property>
- <name>log4j.configuration</name>
- <value>file:///${basedir}/src/main/java/log4j.properties</value>
- </property>
- </systemProperties>
- </configuration>
- </plugin>
-
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <executions>
- <execution>
- <phase>package</phase>
- <goals>
- <goal>test-jar</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- </plugins>
-
- <testResources>
- <testResource>
- <targetPath>src/</targetPath>
- <filtering>false</filtering>
- <directory>src/test/java</directory>
- <includes>
- <include>**/*.java</include>
- </includes>
- </testResource>
- </testResources>
-
- <pluginManagement>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-antrun-plugin</artifactId>
- <version>${antrun.version}</version>
- <dependencies>
- <dependency>
- <groupId>ant</groupId>
- <artifactId>ant-nodeps</artifactId>
- <version>1.6.5</version>
- </dependency>
- </dependencies>
-
- <executions>
- <execution>
- <id>python_test</id>
- <phase>test</phase>
- <configuration>
- <tasks>
-
- <condition property="skip-python-tests" value="true">
- <isset property="skip.python.tests"/>
- </condition>
-
- <property name="command"
- value="python run-tests -v -I java_failing.txt -b localhost:2110 -s ../specs/amqp.0-9.no-wip.xml"/>
- <!--value="bash -c 'python run-tests -v -I java_failing.txt'"/>-->
-
- <ant antfile="python-test.xml" inheritRefs="true">
- <target name="run-tests" />
- </ant>
-
- </tasks>
- </configuration>
- <goals>
- <goal>run</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </pluginManagement>
-
-
- </build>
-
-</project>
diff --git a/java/broker/scripts/resetAlerting.sh b/java/broker/scripts/resetAlerting.sh
new file mode 100644
index 0000000000..57a38f3ed1
--- /dev/null
+++ b/java/broker/scripts/resetAlerting.sh
@@ -0,0 +1,95 @@
+#!/bin/bash
+#
+# Alerting Rest Scripts to renabled the alerts on the queue.
+#
+# Defaults to Localhost broker
+#
+
+if [ -z "$QPID_ALERT_HOME" ]; then
+ export QPID_ALERT_HOME=$(dirname $(dirname $(readlink -f $0)))
+ export PATH=${PATH}:${QPID_ALERT_HOME}/bin
+fi
+
+USERNAME=$1
+PASSWORD=$2
+HOSTNAME=$3
+PORT=$4
+
+CLI="$QPID_ALERT_HOME/bin/qpid-cli -h ${HOSTNAME:-localhost} -p ${PORT:-8999}"
+AUTH=
+if [ -n $USERNAME ] ; then
+ if [ "$USERNAME" == "-h" ] ; then
+ echo "resetAlerting.sh: [<username> <password> [<hostname> [<port>]]]"
+ exit 0
+ fi
+ if [ -n $PASSWORD ] ; then
+ AUTH="-u $USERNAME -w $PASSWORD"
+ else
+ echo "Password must be specified with username"
+ fi
+fi
+
+
+OUTPUT=0
+
+runCommand()
+{
+ RET=`$CLI $1 $AUTH`
+}
+
+resetQueue()
+{
+ vhost=$1
+ queue=$2
+ runCommand "get -o queue -v $vhost -n $queue -a MaximumQueueDepth"
+ rawQDepth=$RET
+ # Note that MaxQueueDepth is returned as Kb but set as b!
+ queueDepth=$[ $rawQDepth * 1024 ]
+ runCommand "get -o queue -v $vhost -n $queue -a MaximumMessageAge"
+ messageAge=$RET
+ runCommand "get -o queue -v $vhost -n $queue -a MaximumMessageCount"
+ messageCount=$RET
+ runCommand "get -o queue -v $vhost -n $queue -a MaximumMessageSize"
+ messageSize=$RET
+
+ if [ $OUTPUT == 1 ] ; then
+ echo Current Values:
+ echo MaximumQueueDepth : $queueDepth
+ echo MaximumMessageAge : $messageAge
+ echo MaximumMessageCount : $messageCount
+ echo MaximumMessageSize : $messageSize
+ fi
+
+ runCommand "set -o queue -v $vhost -n $queue -a MaximumMessageSize -s $messageSize"
+ runCommand "set -o queue -v $vhost -n $queue -a MaximumMessageAge -s $messageAge"
+ runCommand "set -o queue -v $vhost -n $queue -a MaximumMessageCount -s $messageCount"
+ runCommand "set -o queue -v $vhost -n $queue -a MaximumQueueDepth -s $queueDepth"
+}
+
+resetVirtualHost()
+{
+ vhost=$1
+ ignore=0
+ for queue in `$CLI list -o queue -v $vhost $AUTH |grep '|' | cut -d '|' -f 1 ` ; do
+
+ if [ $ignore == 0 ] ; then
+ ignore=1
+ else
+ resetQueue $vhost $queue
+ fi
+
+ done
+}
+
+VHOST=`$CLI list -o virtualhost $AUTH`
+COUNT=`echo $VHOST | grep -c VirtualHost`
+if [ $COUNT -gt 0 ] ; then
+ for vhost in `echo $VHOST |grep VirtualHost|cut -d '=' -f 3` ; do
+
+ echo "Resetting alert levels for $vhost";
+ resetVirtualHost $vhost;
+ done
+ echo "Alerting levels reset"
+else
+ echo $VHOST
+fi
diff --git a/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java b/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java
index 7e0c4defe1..be52b82789 100644
--- a/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java
+++ b/java/broker/src/main/java/org/apache/log4j/QpidCompositeRollingAppender.java
@@ -157,6 +157,7 @@ public class QpidCompositeRollingAppender extends FileAppender
protected String backupFilesToPath = null;
private final ConcurrentLinkedQueue<CompressJob> _compress = new ConcurrentLinkedQueue<CompressJob>();
private AtomicBoolean _compressing = new AtomicBoolean(false);
+ private static final String COMPRESS_EXTENSION = ".gz";
/** The default constructor does nothing. */
public QpidCompositeRollingAppender()
@@ -370,10 +371,6 @@ public class QpidCompositeRollingAppender extends FileAppender
if (!staticLogFileName)
{
scheduledFilename = fileName = fileName.trim() + sdf.format(now);
- if (countDirection > 0)
- {
- scheduledFilename = fileName = fileName + '.' + (++curSizeRollBackups);
- }
}
super.setFile(fileName, append, bufferedIO, bufferSize);
@@ -513,75 +510,10 @@ public class QpidCompositeRollingAppender extends FileAppender
*/
protected void existingInit()
{
-
- if (zeroBased)
- {
- curSizeRollBackups = -1;
- }
-
curTimeRollBackups = 0;
// part A starts here
- String filter;
- if (staticLogFileName || !rollDate)
- {
- filter = baseFileName + ".*";
- }
- else
- {
- filter = scheduledFilename + ".*";
- }
-
- File f = new File(baseFileName);
- f = f.getParentFile();
- if (f == null)
- {
- f = new File(".");
- }
-
- LogLog.debug("Searching for existing files in: " + f);
- String[] files = f.list();
-
- if (files != null)
- {
- for (int i = 0; i < files.length; i++)
- {
- if (!files[i].startsWith(baseFileName))
- {
- continue;
- }
-
- int index = files[i].lastIndexOf(".");
-
- if (staticLogFileName)
- {
- int endLength = files[i].length() - index;
- if ((baseFileName.length() + endLength) != files[i].length())
- {
- // file is probably scheduledFilename + .x so I don't care
- continue;
- }
- }
-
- try
- {
- int backup = Integer.parseInt(files[i].substring(index + 1, files[i].length()));
- LogLog.debug("From file: " + files[i] + " -> " + backup);
- if (backup > curSizeRollBackups)
- {
- curSizeRollBackups = backup;
- }
- }
- catch (Exception e)
- {
- // this happens when file.log -> file.log.yyyy-mm-dd which is normal
- // when staticLogFileName == false
- LogLog.debug("Encountered a backup file not ending in .x " + files[i]);
- }
- }
- }
-
- LogLog.debug("curSizeRollBackups starts at: " + curSizeRollBackups);
+ // This is now down at first log when curSizeRollBackup==0 see rollFile
// part A ends here
// part B not yet implemented
@@ -663,55 +595,11 @@ public class QpidCompositeRollingAppender extends FileAppender
this.closeFile(); // keep windows happy.
- // delete the old stuff here
-
- if (staticLogFileName)
- {
- /* Compute filename, but only if datePattern is specified */
- if (datePattern == null)
- {
- errorHandler.error("Missing DatePattern option in rollOver().");
- return;
- }
-
- // is the new file name equivalent to the 'current' one
- // something has gone wrong if we hit this -- we should only
- // roll over if the new file will be different from the old
- String dateFormat = sdf.format(now);
- if (scheduledFilename.equals(fileName + dateFormat))
- {
- errorHandler.error("Compare " + scheduledFilename + " : " + fileName + dateFormat);
-
- return;
- }
-
- // close current file, and rename it to datedFilename
- this.closeFile();
-
- // we may have to roll over a large number of backups here
- String from, to;
- for (int i = 1; i <= curSizeRollBackups; i++)
- {
- from = fileName + '.' + i;
- to = scheduledFilename + '.' + i;
- rollFile(from, to, false);
- }
-
- rollFile(fileName, scheduledFilename, compress);
- }
- else
- {
- if (compress)
- {
- compress(fileName);
- }
- }
+ rollFile();
try
{
- // This will also close the file. This is OK since multiple
- // close operations are safe.
curSizeRollBackups = 0; // We're cleared out the old date and are ready for the new
// new scheduled name
@@ -735,55 +623,46 @@ public class QpidCompositeRollingAppender extends FileAppender
{
if (compress)
{
- LogLog.debug("Attempting to compress file with same output name.");
+ LogLog.error("Attempting to compress file with same output name.");
}
return;
}
File target = new File(to);
- if (target.exists())
- {
- LogLog.debug("deleting existing target file: " + target);
- target.delete();
- }
File file = new File(from);
- if (compress)
+ // Perform Roll by renaming
+ if (!file.getPath().equals(target.getPath()))
{
- compress(file, target);
+ file.renameTo(target);
}
- else
+
+ // Compress file after it has been moved out the way... this is safe
+ // as it will gain a .gz ending and we can then safely delete this file
+ // as it will not be the statically named value.
+ if (compress)
{
- if (!file.getPath().equals(target.getPath()))
- {
- file.renameTo(target);
- }
+ compress(target);
}
LogLog.debug(from + " -> " + to);
}
- protected void compress(String file)
- {
- File f = new File(file);
- compress(f, f);
- }
-
- private void compress(File from, File target)
+ private void compress(File target)
{
if (compressAsync)
{
synchronized (_compress)
{
- _compress.offer(new CompressJob(from, target));
+ _compress.offer(new CompressJob(target, target));
}
startCompression();
}
else
{
- doCompress(from, target);
+ doCompress(target, target);
}
}
@@ -796,9 +675,9 @@ public class QpidCompositeRollingAppender extends FileAppender
}
/** Delete's the specified file if it exists */
- protected static void deleteFile(String fileName)
+ protected void deleteFile(String fileName)
{
- File file = new File(fileName);
+ File file = compress ? new File(fileName + COMPRESS_EXTENSION) : new File(fileName);
if (file.exists())
{
file.delete();
@@ -837,69 +716,277 @@ public class QpidCompositeRollingAppender extends FileAppender
// If maxBackups <= 0, then there is no file renaming to be done.
if (maxSizeRollBackups != 0)
{
+ rollFile();
+ }
- if (countDirection < 0)
+ try
+ {
+ // This will also close the file. This is OK since multiple
+ // close operations are safe.
+ this.setFile(baseFileName, false);
+ }
+ catch (IOException e)
+ {
+ LogLog.error("setFile(" + fileName + ", false) call failed.", e);
+ }
+ }
+
+ /**
+ * Perform file Rollover ensuring the countDirection is applied along with
+ * the other options
+ */
+ private void rollFile()
+ {
+ LogLog.debug("CD="+countDirection+",start");
+ if (countDirection < 0)
+ {
+ // If we haven't rolled yet then validate we have the right value
+ // for curSizeRollBackups
+ if (curSizeRollBackups == 0)
{
- // Delete the oldest file, to keep Windows happy.
- if (curSizeRollBackups == maxSizeRollBackups)
+ //Validate curSizeRollBackups
+ curSizeRollBackups = countFileIndex(fileName);
+ // decrement to offset the later increment
+ curSizeRollBackups--;
+ }
+
+ // If we are not keeping an infinite set of backups the delete oldest
+ if (maxSizeRollBackups > 0)
+ {
+ LogLog.debug("CD=-1,curSizeRollBackups:"+curSizeRollBackups);
+ LogLog.debug("CD=-1,maxSizeRollBackups:"+maxSizeRollBackups);
+
+ // Delete the oldest file.
+ // curSizeRollBackups is never -1 so infinite backups are ok here
+ if ((curSizeRollBackups - maxSizeRollBackups) >= 0)
{
- deleteFile(fileName + '.' + maxSizeRollBackups);
+ //The oldest file is the one with the largest number
+ // as the 0 is always fileName
+ // which moves to fileName.1 etc.
+ LogLog.debug("CD=-1,deleteFile:"+curSizeRollBackups);
+ deleteFile(fileName + '.' + curSizeRollBackups);
+ // decrement to offset the later increment
curSizeRollBackups--;
}
+ }
+ // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2}
+ for (int i = curSizeRollBackups; i >= 1; i--)
+ {
+ String oldName = (fileName + "." + i);
+ String newName = (fileName + '.' + (i + 1));
- // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2}
- for (int i = curSizeRollBackups; i >= 1; i--)
+ // Ensure that when compressing we rename the compressed archives
+ if (compress)
{
- rollFile((fileName + "." + i), (fileName + '.' + (i + 1)), false);
+ rollFile(oldName + COMPRESS_EXTENSION, newName + COMPRESS_EXTENSION, false);
}
+ else
+ {
+ rollFile(oldName, newName, false);
+ }
+ }
- curSizeRollBackups++;
- // Rename fileName to fileName.1
- rollFile(fileName, fileName + ".1", compress);
+ curSizeRollBackups++;
+ // Rename fileName to fileName.1
+ rollFile(fileName, fileName + ".1", compress);
- } // REMOVE This code branching for Alexander Cerna's request
- else if (countDirection == 0)
+ } // REMOVE This code branching for Alexander Cerna's request
+ else if (countDirection == 0)
+ {
+ // rollFile based on date pattern
+ now.setTime(System.currentTimeMillis());
+ String newFile = fileName + sdf.format(now);
+
+ // If we haven't rolled yet then validate we have the right value
+ // for curSizeRollBackups
+ if (curSizeRollBackups == 0)
{
- // rollFile based on date pattern
- curSizeRollBackups++;
- now.setTime(System.currentTimeMillis());
- scheduledFilename = fileName + sdf.format(now);
- rollFile(fileName, scheduledFilename, compress);
+ //Validate curSizeRollBackups
+ curSizeRollBackups = countFileIndex(newFile);
+ // to balance the increment just coming up. as the count returns
+ // the next free number not the last used.
+ curSizeRollBackups--;
}
- else
- { // countDirection > 0
- if ((curSizeRollBackups >= maxSizeRollBackups) && (maxSizeRollBackups > 0))
+
+ // If we are not keeping an infinite set of backups the delete oldest
+ if (maxSizeRollBackups > 0)
+ {
+ // Don't prune older files if they exist just go for the last
+ // one based on our maxSizeRollBackups. This means we may have
+ // more files left on disk that maxSizeRollBackups if this value
+ // is adjusted between runs but that is an acceptable state.
+ // Otherwise we would have to check on startup that we didn't
+ // have more than maxSizeRollBackups and prune then.
+
+ if (((curSizeRollBackups - maxSizeRollBackups) >= 0))
{
- // delete the first and keep counting up.
+ LogLog.debug("CD=0,curSizeRollBackups:"+curSizeRollBackups);
+ LogLog.debug("CD=0,maxSizeRollBackups:"+maxSizeRollBackups);
+
+ // delete the first and keep counting up.
int oldestFileIndex = curSizeRollBackups - maxSizeRollBackups + 1;
- deleteFile(fileName + '.' + oldestFileIndex);
+ LogLog.debug("CD=0,deleteFile:"+oldestFileIndex);
+ deleteFile(newFile + '.' + oldestFileIndex);
}
+ }
+
+
+ String finalName = newFile;
+
+ curSizeRollBackups++;
+
+ // Add rollSize if it is > 0
+ if (curSizeRollBackups > 0 )
+ {
+ finalName = newFile + '.' + curSizeRollBackups;
+
+ }
- if (staticLogFileName)
+ rollFile(fileName, finalName, compress);
+ }
+ else
+ { // countDirection > 0
+ // If we haven't rolled yet then validate we have the right value
+ // for curSizeRollBackups
+ if (curSizeRollBackups == 0)
+ {
+ //Validate curSizeRollBackups
+ curSizeRollBackups = countFileIndex(fileName);
+ // to balance the increment just coming up. as the count returns
+ // the next free number not the last used.
+ curSizeRollBackups--;
+ }
+
+ // If we are not keeping an infinite set of backups the delete oldest
+ if (maxSizeRollBackups > 0)
+ {
+ LogLog.debug("CD=1,curSizeRollBackups:"+curSizeRollBackups);
+ LogLog.debug("CD=1,maxSizeRollBackups:"+maxSizeRollBackups);
+
+ // Don't prune older files if they exist just go for the last
+ // one based on our maxSizeRollBackups. This means we may have
+ // more files left on disk that maxSizeRollBackups if this value
+ // is adjusted between runs but that is an acceptable state.
+ // Otherwise we would have to check on startup that we didn't
+ // have more than maxSizeRollBackups and prune then.
+
+ if (((curSizeRollBackups - maxSizeRollBackups) >= 0))
{
- curSizeRollBackups++;
- rollFile(fileName, fileName + '.' + curSizeRollBackups, compress);
+ // delete the first and keep counting up.
+ int oldestFileIndex = curSizeRollBackups - maxSizeRollBackups + 1;
+ LogLog.debug("CD=1,deleteFile:"+oldestFileIndex);
+ deleteFile(fileName + '.' + oldestFileIndex);
}
- else
+ }
+
+
+ curSizeRollBackups++;
+
+ rollFile(fileName, fileName + '.' + curSizeRollBackups, compress);
+
+ }
+ LogLog.debug("CD="+countDirection+",done");
+ }
+
+
+ private int countFileIndex(String fileName)
+ {
+ return countFileIndex(fileName, true);
+ }
+ /**
+ * Use filename as a base name and find what count number we are up to by
+ * looking at the files in this format:
+ *
+ * <filename>.<count>[COMPRESS_EXTENSION]
+ *
+ * If a count value of 1 cannot be found then a directory listing is
+ * performed to try and identify if there is a valid value for <count>.
+ *
+ *
+ * @param fileName the basefilename to use
+ * @param checkBackupLocation should backupFilesToPath location be checked for existing backups
+ * @return int the next free index
+ */
+ private int countFileIndex(String fileName, boolean checkBackupLocation)
+ {
+ String testFileName;
+
+ // It is possible for index 1..n to be missing leaving n+1..n+1+m logs
+ // in this scenario we should still return n+1+m+1
+ int index=1;
+
+ testFileName = fileName + "." + index;
+
+ // Bail out early if there is a problem with the file
+ if (new File(testFileName) == null
+ || new File(testFileName + COMPRESS_EXTENSION) == null)
+
+ {
+ return index;
+ }
+
+ // Check that we do not have the 1..n missing scenario
+ if (!(new File(testFileName).exists()
+ || new File(testFileName + COMPRESS_EXTENSION).exists()))
+
+ {
+ int max=0;
+ String prunedFileName = new File(fileName).getName();
+
+ // Look through all files to find next index
+ if (new File(fileName).getParentFile() != null)
+ {
+ for (File file : new File(fileName).getParentFile().listFiles())
{
- if (compress)
+ String name = file.getName();
+
+ if (name.startsWith(prunedFileName) && !name.equals(prunedFileName))
{
- compress(fileName);
+ String parsedCount = name.substring(prunedFileName.length() + 1);
+
+ if (parsedCount.endsWith(COMPRESS_EXTENSION))
+ {
+ parsedCount = parsedCount.substring(0, parsedCount.indexOf(COMPRESS_EXTENSION));
+ }
+
+ try
+ {
+ max = Integer.parseInt(parsedCount);
+
+ // if we got a good value then update our index value.
+ if (max > index)
+ {
+ // +1 as we want to return the next free value.
+ index = max + 1;
+ }
+ }
+ catch (NumberFormatException nfe)
+ {
+ //ignore it assume file doesn't exist.
+ }
}
}
}
+
+ // Update testFileName
+ testFileName = fileName + "." + index;
}
- try
+
+ while (new File(testFileName).exists()
+ || new File(testFileName + COMPRESS_EXTENSION).exists())
{
- // This will also close the file. This is OK since multiple
- // close operations are safe.
- this.setFile(baseFileName, false);
+ index++;
+ testFileName = fileName + "." + index;
}
- catch (IOException e)
+
+ if (checkBackupLocation && index == 1 && backupFilesToPath != null)
{
- LogLog.error("setFile(" + fileName + ", false) call failed.", e);
+ LogLog.debug("Trying backup location:"+backupFilesToPath + System.getProperty("file.separator") + fileName);
+ return countFileIndex(backupFilesToPath + System.getProperty("file.separator") + new File(fileName).getName(), false);
}
+
+ return index;
}
protected synchronized void doCompress(File from, File to)
@@ -907,11 +994,11 @@ public class QpidCompositeRollingAppender extends FileAppender
String toFile;
if (backupFilesToPath == null)
{
- toFile = to.getPath() + ".gz";
+ toFile = to.getPath() + COMPRESS_EXTENSION;
}
else
{
- toFile = backupFilesToPath + System.getProperty("file.separator") + to.getName() + ".gz";
+ toFile = backupFilesToPath + System.getProperty("file.separator") + to.getName() + COMPRESS_EXTENSION;
}
File target = new File(toFile);
diff --git a/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java b/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java
new file mode 100644
index 0000000000..4afc209ba7
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java
@@ -0,0 +1,319 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.log4j.xml;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.qpid.server.logging.management.LoggingManagementMBean;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+/**
+ * Substitute for the Log4J XMLWatchdog (as used by DOMConfigurator.configureAndWatch)
+ *
+ * Extends the default behaviour with a strict parser check on the XML file before allowing the reconfiguration to proceed,
+ * ensuring that any parser error or warning prevents initiation of a configuration update by Log4J, which aborts mid-update
+ * upon fatal errors from the parser and proceeds in the event of 'regular' parser errors and warnings, in all cases allowing
+ * startup to proceed with whatever half-baked configuration then exists.
+ */
+public class QpidLog4JConfigurator
+{
+ //lock to protect access to the configuration file
+ //shared with LoggingManagementMBean
+ public static final ReentrantLock LOCK = new ReentrantLock();
+ private static Logger _logger;
+ private static DOMConfigurator domConfig = new DOMConfigurator();
+
+ private QpidLog4JConfigurator()
+ {
+ //no instances
+ }
+
+ public static void configure(String filename) throws IOException, ParserConfigurationException,
+ SAXException, IllegalLoggerLevelException
+ {
+ try
+ {
+ LOCK.lock();
+
+ parseXMLConfigFile(filename);
+ checkLoggerLevels(filename);
+
+ DOMConfigurator.configure(filename);
+
+ if(_logger == null)
+ {
+ _logger = Logger.getLogger(QpidLog4JConfigurator.class);
+ }
+ }
+ finally
+ {
+ LOCK.unlock();
+ }
+ }
+
+ public static void configureAndWatch(String filename, long delay) throws IOException, ParserConfigurationException,
+ SAXException, IllegalLoggerLevelException
+ {
+ parseXMLConfigFile(filename);
+ checkLoggerLevels(filename);
+
+ QpidLog4JXMLWatchdog watchdog = new QpidLog4JXMLWatchdog(filename);
+ watchdog.setDelay(delay);
+ watchdog.start();
+ }
+
+ private static void parseXMLConfigFile(String fileName) throws IOException, SAXException,
+ ParserConfigurationException
+ {
+ try
+ {
+ LOCK.lock();
+
+ //check file was specified, exists, and is readable
+ if(fileName == null)
+ {
+ throw new IOException("Provided log4j XML configuration filename was null");
+ }
+
+ File configFile = new File(fileName);
+
+ if (!configFile.exists())
+ {
+ throw new IOException("The log4j XML configuration file does not exist: " + fileName);
+ }
+ else if (!configFile.canRead())
+ {
+ throw new IOException("The log4j XML configuration file is not readable: " + fileName);
+ }
+
+ //parse it
+ DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder docBuilder;
+
+ ErrorHandler errHandler = new QpidLog4JSaxErrorHandler();
+
+ docFactory.setValidating(true);
+ docBuilder = docFactory.newDocumentBuilder();
+ docBuilder.setErrorHandler(errHandler);
+ docBuilder.setEntityResolver(new Log4jEntityResolver());
+ docBuilder.parse(fileName);
+ }
+ finally
+ {
+ LOCK.unlock();
+ }
+ }
+
+ public static class QpidLog4JSaxErrorHandler implements ErrorHandler
+ {
+ public void error(SAXParseException e) throws SAXException
+ {
+ if(_logger != null)
+ {
+ _logger.warn(constructMessage("Error parsing XML file", e));
+ }
+ else
+ {
+ System.err.println(constructMessage("Error parsing XML file", e));
+ }
+ }
+
+ public void fatalError(SAXParseException e) throws SAXException
+ {
+ throw new SAXException(constructMessage("Fatal error parsing XML file", e));
+ }
+
+ public void warning(SAXParseException e) throws SAXException
+ {
+ if(_logger != null)
+ {
+ _logger.warn(constructMessage("Warning parsing XML file", e));
+ }
+ else
+ {
+ System.err.println(constructMessage("Warning parsing XML file", e));
+ }
+ }
+
+ private static String constructMessage(final String msg, final SAXParseException ex)
+ {
+ return new String(msg + ": Line " + ex.getLineNumber()+" column " +ex.getColumnNumber() + ": " + ex.getMessage());
+ }
+ }
+
+ private static class QpidLog4JXMLWatchdog extends XMLWatchdog
+ {
+ public QpidLog4JXMLWatchdog(String filename)
+ {
+ super(filename);
+ }
+
+ public void doOnChange()
+ {
+ try
+ {
+ LOCK.lock();
+
+ try
+ {
+ parseXMLConfigFile(filename);
+ }
+ catch (Exception e)
+ {
+ //logger will be instantiated following first configuration success, which has been pre-validated
+ //and so the null check should never actually be required.
+ if(_logger != null)
+ {
+ _logger.warn("Parsing the log4j XML configuration file generated errors/warnings. " +
+ "The new configuration was not applied. Correct the issues to prompt " +
+ "another update attempt: " + e.getMessage());
+ }
+ return;
+ }
+
+ try
+ {
+ checkLoggerLevels(filename);
+ }
+ catch (Exception e)
+ {
+ //logger will be instantiated following first configuration success, which has been pre-validated
+ //and so the null check should never actually be required.
+ if(_logger != null)
+ {
+ _logger.warn("Errors were found when validating the logger level values in the " +
+ "log4j XML configuration file. The new configuration was not applied. " +
+ "Correct the issues to prompt another update attempt: " + e.getMessage());
+ }
+ return;
+ }
+
+ //everything checked was ok, let the normal update process proceed
+ super.doOnChange();
+
+ //a configuration has now been applied, enable logging for future attempts
+ if(_logger == null)
+ {
+ _logger = Logger.getLogger(QpidLog4JConfigurator.class);
+ }
+
+ _logger.info("Applied log4j configuration from: " + filename);
+ }
+ finally
+ {
+ LOCK.unlock();
+ }
+
+ }
+ }
+
+ protected static void checkLoggerLevels(String filename) throws IllegalLoggerLevelException, IOException
+ {
+ //check that the logger levels specified in the XML are actually valid
+
+ try
+ {
+ LOCK.lock();
+
+ //get the Logger levels to check
+ Map<String, String> loggersLevels;
+ loggersLevels = LoggingManagementMBean.retrieveConfigFileLoggersLevels(filename);
+ //add the RootLogger to the list too
+ String rootLoggerlevelString = LoggingManagementMBean.retrieveConfigFileRootLoggerLevel(filename);
+ loggersLevels.put("Root", rootLoggerlevelString);
+
+
+ for (String loggerName : loggersLevels.keySet())
+ {
+ String levelString = loggersLevels.get(loggerName);
+
+ //let log4j replace any properties in the string
+ String log4jConfiguredString = domConfig.subst(levelString);
+
+ if(log4jConfiguredString.equals("") & ! log4jConfiguredString.equals(levelString))
+ {
+ //log4j has returned an empty string but this isnt what we gave it.
+ //There may have been an undefined property. Unlike an incorrect
+ //literal value, we will allow this case to proceed, but warn users.
+
+ if(_logger != null)
+ {
+ _logger.warn("Unable to detect Level value from '" + levelString
+ +"' for logger '" + loggerName + "', Log4J will default this to DEBUG");
+ }
+ else
+ {
+ System.err.println("Unable to detect Level value from '" + levelString
+ +"' for logger " + loggerName + ", Log4J will default this to DEBUG");
+ }
+
+ continue;
+ }
+
+ checkLevel(loggerName,log4jConfiguredString);
+ }
+ }
+ finally
+ {
+ LOCK.unlock();
+ }
+ }
+
+ private static void checkLevel(String loggerName, String levelString) throws IllegalLoggerLevelException
+ {
+ if("null".equalsIgnoreCase(levelString) || "inherited".equalsIgnoreCase(levelString))
+ {
+ //the string "null" signals to inherit from a parent logger
+ return;
+ }
+
+ Level level = Level.toLevel(levelString);
+
+ //above Level.toLevel call returns a DEBUG Level if the request fails. Check the result.
+ if (level.equals(Level.DEBUG) && !(levelString.equalsIgnoreCase("debug")))
+ {
+ //received DEBUG but we did not ask for it, the Level request failed.
+ throw new IllegalLoggerLevelException("Level '" + levelString + "' specified for Logger '" + loggerName + "' is invalid");
+ }
+ }
+
+ public static class IllegalLoggerLevelException extends Exception
+ {
+ private static final long serialVersionUID = 1L;
+
+ public IllegalLoggerLevelException(String msg)
+ {
+ super(msg);
+ }
+ }
+}
+
diff --git a/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java
index 88d5360f3e..08b3c08215 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java
@@ -37,30 +37,37 @@
*/
package org.apache.qpid.server;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
import javax.management.JMException;
import javax.management.MBeanException;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
-import org.apache.commons.configuration.Configuration;
-
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.configuration.Configurator;
-import org.apache.qpid.server.configuration.VirtualHostConfiguration;
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedQueue;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.server.exchange.ExchangeFactory;
import org.apache.qpid.server.exchange.ExchangeRegistry;
+import org.apache.qpid.server.exchange.ExchangeType;
import org.apache.qpid.server.management.AMQManagedObject;
-import org.apache.qpid.server.management.MBeanConstructor;
-import org.apache.qpid.server.management.MBeanDescription;
-import org.apache.qpid.server.management.ManagedBroker;
import org.apache.qpid.server.management.ManagedObject;
-import org.apache.qpid.server.queue.QueueRegistry;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.AMQQueueFactory;
-import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.queue.AMQQueueMBean;
+import org.apache.qpid.server.queue.QueueRegistry;
+import org.apache.qpid.server.store.DurableConfigurationStore;
import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.virtualhost.VirtualHostImpl;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.ManagementActor;
/**
* This MBean implements the broker management interface and exposes the
@@ -72,21 +79,21 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
private final QueueRegistry _queueRegistry;
private final ExchangeRegistry _exchangeRegistry;
private final ExchangeFactory _exchangeFactory;
- private final MessageStore _messageStore;
+ private final DurableConfigurationStore _durableConfig;
- private final VirtualHost.VirtualHostMBean _virtualHostMBean;
+ private final VirtualHostImpl.VirtualHostMBean _virtualHostMBean;
@MBeanConstructor("Creates the Broker Manager MBean")
- public AMQBrokerManagerMBean(VirtualHost.VirtualHostMBean virtualHostMBean) throws JMException
+ public AMQBrokerManagerMBean(VirtualHostImpl.VirtualHostMBean virtualHostMBean) throws JMException
{
- super(ManagedBroker.class, ManagedBroker.TYPE);
+ super(ManagedBroker.class, ManagedBroker.TYPE, ManagedBroker.VERSION);
_virtualHostMBean = virtualHostMBean;
VirtualHost virtualHost = virtualHostMBean.getVirtualHost();
_queueRegistry = virtualHost.getQueueRegistry();
_exchangeRegistry = virtualHost.getExchangeRegistry();
- _messageStore = virtualHost.getMessageStore();
+ _durableConfig = virtualHost.getDurableConfigurationStore();
_exchangeFactory = virtualHost.getExchangeFactory();
}
@@ -96,6 +103,86 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
}
/**
+ * Returns an array of the exchange types available for creation.
+ * @since Qpid JMX API 1.3
+ * @throws IOException
+ */
+ public String[] getExchangeTypes() throws IOException
+ {
+ ArrayList<String> exchangeTypes = new ArrayList<String>();
+ for(ExchangeType<? extends Exchange> ex : _exchangeFactory.getRegisteredTypes())
+ {
+ exchangeTypes.add(ex.getName().toString());
+ }
+
+ return exchangeTypes.toArray(new String[0]);
+ }
+
+ /**
+ * Returns a list containing the names of the attributes available for the Queue mbeans.
+ * @since Qpid JMX API 1.3
+ * @throws IOException
+ */
+ public List<String> retrieveQueueAttributeNames() throws IOException
+ {
+ List<String> attributeList = new ArrayList<String>();
+ for(String attr : ManagedQueue.QUEUE_ATTRIBUTES)
+ {
+ attributeList.add(attr);
+ }
+
+ Collections.sort(attributeList);
+
+ return attributeList;
+ }
+
+ /**
+ * Returns a List of Object Lists containing the requested attribute values (in the same sequence requested) for each queue in the virtualhost.
+ * If a particular attribute cant be found or raises an mbean/reflection exception whilst being gathered its value is substituted with the String "-".
+ * @since Qpid JMX API 1.3
+ * @throws IOException
+ */
+ public List<List<Object>> retrieveQueueAttributeValues(String[] attributes) throws IOException
+ {
+ if(_queueRegistry.getQueues().size() == 0)
+ {
+ return new ArrayList<List<Object>>();
+ }
+
+ List<List<Object>> queueAttributesList = new ArrayList<List<Object>>(_queueRegistry.getQueues().size());
+
+ int attributesLength = attributes.length;
+
+ for(AMQQueue queue : _queueRegistry.getQueues())
+ {
+ AMQQueueMBean mbean = (AMQQueueMBean) queue.getManagedObject();
+
+ if(mbean == null)
+ {
+ continue;
+ }
+
+ List<Object> attributeValues = new ArrayList<Object>(attributesLength);
+
+ for(int i=0; i < attributesLength; i++)
+ {
+ try
+ {
+ attributeValues.add(mbean.getAttribute(attributes[i]));
+ }
+ catch (Exception e)
+ {
+ attributeValues.add(new String("-"));
+ }
+ }
+
+ queueAttributesList.add(attributeValues);
+ }
+
+ return queueAttributesList;
+ }
+
+ /**
* Creates new exchange and registers it with the registry.
*
* @param exchangeName
@@ -105,6 +192,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
*/
public void createNewExchange(String exchangeName, String type, boolean durable) throws JMException
{
+ CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger()));
try
{
synchronized (_exchangeRegistry)
@@ -126,6 +214,10 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
{
throw new MBeanException(ex, "Error in creating exchange " + exchangeName);
}
+ finally
+ {
+ CurrentActor.remove();
+ }
}
/**
@@ -141,6 +233,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
// boolean inUse = false;
// Check if there are queue-bindings with the exchange and unregister
// when there are no bindings.
+ CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger()));
try
{
_exchangeRegistry.unregisterExchange(new AMQShortString(exchangeName), false);
@@ -149,6 +242,10 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
{
throw new MBeanException(ex, "Error in unregistering exchange " + exchangeName);
}
+ finally
+ {
+ CurrentActor.remove();
+ }
}
/**
@@ -168,6 +265,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
throw new JMException("The queue \"" + queueName + "\" already exists.");
}
+ CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger()));
try
{
AMQShortString ownerShortString = null;
@@ -180,14 +278,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
null);
if (queue.isDurable() && !queue.isAutoDelete())
{
- _messageStore.createQueue(queue);
- }
-
- Configuration virtualHostDefaultQueueConfiguration =
- VirtualHostConfiguration.getDefaultQueueConfiguration(queue);
- if (virtualHostDefaultQueueConfiguration != null)
- {
- Configurator.configure(queue, virtualHostDefaultQueueConfiguration);
+ _durableConfig.createQueue(queue);
}
_queueRegistry.registerQueue(queue);
@@ -198,6 +289,10 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
jme.initCause(ex);
throw new MBeanException(jme, "Error in creating queue " + queueName);
}
+ finally
+ {
+ CurrentActor.remove();
+ }
}
private VirtualHost getVirtualHost()
@@ -219,11 +314,14 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
throw new JMException("The Queue " + queueName + " is not a registerd queue.");
}
+ CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger()));
try
{
queue.delete();
- _messageStore.removeQueue(queue);
-
+ if (queue.isDurable())
+ {
+ _durableConfig.removeQueue(queue);
+ }
}
catch (AMQException ex)
{
@@ -231,6 +329,10 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
jme.initCause(ex);
throw new MBeanException(jme, "Error in deleting queue " + queueName);
}
+ finally
+ {
+ CurrentActor.remove();
+ }
}
public ManagedObject getParentObject()
diff --git a/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
index 847c8b8459..333c1b9cac 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
@@ -20,52 +20,53 @@
*/
package org.apache.qpid.server;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentHashMap;
+
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
-import org.apache.qpid.configuration.Configured;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.BasicContentHeaderProperties;
-import org.apache.qpid.framing.ContentBody;
-import org.apache.qpid.framing.ContentHeaderBody;
-import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.framing.*;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.framing.abstraction.ContentChunk;
import org.apache.qpid.server.ack.UnacknowledgedMessageMap;
import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl;
-import org.apache.qpid.server.configuration.Configurator;
import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.exchange.NoRouteException;
import org.apache.qpid.server.flow.FlowCreditManager;
import org.apache.qpid.server.flow.Pre0_10CreditManager;
import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.IncomingMessage;
-import org.apache.qpid.server.queue.MessageHandleFactory;
-import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.queue.*;
import org.apache.qpid.server.subscription.Subscription;
import org.apache.qpid.server.subscription.SubscriptionFactoryImpl;
import org.apache.qpid.server.subscription.ClientDeliveryMethod;
import org.apache.qpid.server.subscription.RecordDeliveryMethod;
import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.StoreContext;
-import org.apache.qpid.server.txn.LocalTransactionalContext;
-import org.apache.qpid.server.txn.NonTransactionalContext;
-import org.apache.qpid.server.txn.TransactionalContext;
-
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.qpid.server.store.StoredMessage;
+import org.apache.qpid.server.txn.*;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.message.MessageMetaData;
+import org.apache.qpid.server.message.MessageReference;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.logging.LogActor;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.logging.messages.ChannelMessages;
+import org.apache.qpid.server.logging.subjects.ChannelLogSubject;
+import org.apache.qpid.server.logging.actors.AMQPChannelActor;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.output.ProtocolOutputConverter;
public class AMQChannel
{
public static final int DEFAULT_PREFETCH = 5000;
- private static final Logger _log = Logger.getLogger(AMQChannel.class);
+ private static final Logger _logger = Logger.getLogger(AMQChannel.class);
+
+ private static final boolean MSG_AUTH =
+ ApplicationRegistry.getInstance().getConfiguration().getMsgAuth();
+
private final int _channelId;
@@ -92,57 +93,58 @@ public class AMQChannel
private IncomingMessage _currentMessage;
/** Maps from consumer tag to subscription instance. Allows us to unsubscribe from a queue. */
- private final Map<AMQShortString, Subscription> _tag2SubscriptionMap = new HashMap<AMQShortString, Subscription>();
-
+ protected final Map<AMQShortString, Subscription> _tag2SubscriptionMap = new HashMap<AMQShortString, Subscription>();
private final MessageStore _messageStore;
private UnacknowledgedMessageMap _unacknowledgedMessageMap = new UnacknowledgedMessageMapImpl(DEFAULT_PREFETCH);
- private final AtomicBoolean _suspended = new AtomicBoolean(false);
-
- private TransactionalContext _txnContext;
-
- /**
- * A context used by the message store enabling it to track context for a given channel even across thread
- * boundaries
- */
- private final StoreContext _storeContext;
+ // Set of messages being acknoweledged in the current transaction
+ private SortedSet<QueueEntry> _acknowledgedMessages = new TreeSet<QueueEntry>();
- private final List<RequiredDeliveryException> _returnMessages = new LinkedList<RequiredDeliveryException>();
+ private final AtomicBoolean _suspended = new AtomicBoolean(false);
- private MessageHandleFactory _messageHandleFactory = new MessageHandleFactory();
+ private ServerTransaction _transaction;
// Why do we need this reference ? - ritchiem
private final AMQProtocolSession _session;
private boolean _closing;
- @Configured(path = "advanced.enableJMSXUserID",
- defaultValue = "false")
- public boolean ENABLE_JMSXUserID;
-
+ private final ConcurrentMap<AMQQueue, Boolean> _blockingQueues = new ConcurrentHashMap<AMQQueue, Boolean>();
+
+ private final AtomicBoolean _blocking = new AtomicBoolean(false);
+
+
+ private LogActor _actor;
+ private LogSubject _logSubject;
+ private volatile boolean _rollingBack;
+
+ private static final Runnable NULL_TASK = new Runnable() { public void run() {} };
+ private List<QueueEntry> _resendList = new ArrayList<QueueEntry>();
+ private static final
+ AMQShortString IMMEDIATE_DELIVERY_REPLY_TEXT = new AMQShortString("Immediate delivery is not possible.");
public AMQChannel(AMQProtocolSession session, int channelId, MessageStore messageStore)
throws AMQException
{
- //Set values from configuration
- Configurator.configure(this);
-
_session = session;
_channelId = channelId;
- _storeContext = new StoreContext("Session: " + session.getClientIdentifier() + "; channel: " + channelId);
+ _actor = new AMQPChannelActor(this, session.getLogActor().getRootMessageLogger());
+ _logSubject = new ChannelLogSubject(this);
+
+ _actor.message(ChannelMessages.CHN_CREATE());
_messageStore = messageStore;
// by default the session is non-transactional
- _txnContext = new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages);
+ _transaction = new AutoCommitTransaction(_messageStore);
}
/** Sets this channel to be part of a local transaction */
public void setLocalTransactional()
{
- _txnContext = new LocalTransactionalContext(this);
+ _transaction = new LocalTransaction(_messageStore);
}
public boolean isTransactional()
@@ -150,7 +152,7 @@ public class AMQChannel
// this does not look great but there should only be one "non-transactional"
// transactional context, while there could be several transactional ones in
// theory
- return !(_txnContext instanceof NonTransactionalContext);
+ return !(_transaction instanceof AutoCommitTransaction);
}
public int getChannelId()
@@ -161,8 +163,7 @@ public class AMQChannel
public void setPublishFrame(MessagePublishInfo info, final Exchange e) throws AMQException
{
- _currentMessage = new IncomingMessage(_messageStore.getNewMessageId(), info, _txnContext, _session);
- _currentMessage.setMessageStore(_messageStore);
+ _currentMessage = new IncomingMessage(info);
_currentMessage.setExchange(e);
}
@@ -175,28 +176,35 @@ public class AMQChannel
}
else
{
- if (_log.isDebugEnabled())
- {
- _log.debug("Content header received on channel " + _channelId);
- }
-
- if (ENABLE_JMSXUserID)
+ if (_logger.isDebugEnabled())
{
- //Set JMSXUserID
- BasicContentHeaderProperties properties = (BasicContentHeaderProperties) contentHeaderBody.properties;
- //fixme: fudge for QPID-677
- properties.getHeaders().keySet();
-
- properties.setUserId(_session.getAuthorizedID().getName());
+ _logger.debug("Content header received on channel " + _channelId);
}
_currentMessage.setContentHeaderBody(contentHeaderBody);
_currentMessage.setExpiration();
+
+ MessageMetaData mmd = _currentMessage.headersReceived();
+ final StoredMessage<MessageMetaData> handle = _messageStore.addMessage(mmd);
+ _currentMessage.setStoredMessage(handle);
+
routeCurrentMessage();
- _currentMessage.routingComplete(_messageStore, _messageHandleFactory);
+
+ _transaction.addPostCommitAction(new ServerTransaction.Action()
+ {
+
+ public void postCommit()
+ {
+ }
+
+ public void onRollback()
+ {
+ handle.remove();
+ }
+ });
deliverCurrentMessageIfComplete();
@@ -211,17 +219,36 @@ public class AMQChannel
{
try
{
- _currentMessage.deliverToQueues();
- }
- catch (NoRouteException e)
- {
- _returnMessages.add(e);
+
+ final ArrayList<AMQQueue> destinationQueues = _currentMessage.getDestinationQueues();
+
+ if(!checkMessageUserId(_currentMessage.getContentHeader()))
+ {
+ _transaction.addPostCommitAction(new WriteReturnAction(AMQConstant.ACCESS_REFUSED, "Access Refused", _currentMessage));
+ }
+ else
+ {
+ if(destinationQueues == null || _currentMessage.getDestinationQueues().isEmpty())
+ {
+ if (_currentMessage.isMandatory() || _currentMessage.isImmediate())
+ {
+ _transaction.addPostCommitAction(new WriteReturnAction(AMQConstant.NO_ROUTE, "No Route for message", _currentMessage));
+ }
+ else
+ {
+ _logger.warn("MESSAGE DISCARDED: No routes for message - " + createAMQMessage(_currentMessage));
+ }
+
+ }
+ else
+ {
+ _transaction.enqueue(destinationQueues, _currentMessage, new MessageDeliveryAction(_currentMessage, destinationQueues));
+
+ }
+ }
}
finally
{
- // callback to allow the context to do any post message processing
- // primary use is to allow message return processing in the non-tx case
- _txnContext.messageProcessed(_session);
_currentMessage = null;
}
}
@@ -235,9 +262,9 @@ public class AMQChannel
throw new AMQException("Received content body without previously receiving a JmsPublishBody");
}
- if (_log.isDebugEnabled())
+ if (_logger.isDebugEnabled())
{
- _log.debug(debugIdentity() + "Content body received on channel " + _channelId);
+ _logger.debug(debugIdentity() + "Content body received on channel " + _channelId);
}
try
@@ -245,9 +272,10 @@ public class AMQChannel
// returns true iff the message was delivered (i.e. if all data was
// received
- _currentMessage.addContentBodyFrame(
- _session.getMethodRegistry().getProtocolVersionMethodConverter().convertToContentChunk(
- contentBody));
+ final ContentChunk contentChunk =
+ _session.getMethodRegistry().getProtocolVersionMethodConverter().convertToContentChunk(contentBody);
+
+ _currentMessage.addContentBodyFrame(contentChunk);
deliverCurrentMessageIfComplete();
}
@@ -262,15 +290,7 @@ public class AMQChannel
protected void routeCurrentMessage() throws AMQException
{
- try
- {
- _currentMessage.route();
- }
- catch (NoRouteException e)
- {
- //_currentMessage.incrementReference();
- _returnMessages.add(e);
- }
+ _currentMessage.route();
}
public long getNextDeliveryTag()
@@ -283,6 +303,12 @@ public class AMQChannel
return ++_consumerTag;
}
+
+ public Subscription getSubscription(AMQShortString subscription)
+ {
+ return _tag2SubscriptionMap.get(subscription);
+ }
+
/**
* Subscribe to a queue. We register all subscriptions in the channel so that if the channel is closed we can clean
* up all subscriptions, even if the client does not explicitly unsubscribe from all queues.
@@ -296,11 +322,10 @@ public class AMQChannel
* @param exclusive Flag requesting exclusive access to the queue
* @return the consumer tag. This is returned to the subscriber and used in subsequent unsubscribe requests
*
- * @throws ConsumerTagNotUniqueException if the tag is not unique
* @throws AMQException if something goes wrong
*/
public AMQShortString subscribeToQueue(AMQShortString tag, AMQQueue queue, boolean acks,
- FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException, ConsumerTagNotUniqueException
+ FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException
{
if (tag == null)
{
@@ -309,7 +334,7 @@ public class AMQChannel
if (_tag2SubscriptionMap.containsKey(tag))
{
- throw new ConsumerTagNotUniqueException();
+ throw new AMQException("Consumer already exists with same tag: " + tag);
}
Subscription subscription =
@@ -347,12 +372,20 @@ public class AMQChannel
Subscription sub = _tag2SubscriptionMap.remove(consumerTag);
if (sub != null)
{
- sub.getQueue().unregisterSubscription(sub);
+ try
+ {
+ sub.getSendLock();
+ sub.getQueue().unregisterSubscription(sub);
+ }
+ finally
+ {
+ sub.releaseSendLock();
+ }
return true;
}
else
{
- _log.warn("Attempt to unsubscribe consumer with tag '"+consumerTag+"' which is not registered.");
+ _logger.warn("Attempt to unsubscribe consumer with tag '"+consumerTag+"' which is not registered.");
}
return false;
}
@@ -364,49 +397,62 @@ public class AMQChannel
*/
public void close() throws AMQException
{
- _txnContext.rollback();
+ setClosing(true);
+
unsubscribeAllConsumers();
+ _transaction.rollback();
+
try
{
requeue();
}
catch (AMQException e)
{
- _log.error("Caught AMQException whilst attempting to reque:" + e);
+ _logger.error("Caught AMQException whilst attempting to reque:" + e);
}
- setClosing(true);
}
private void setClosing(boolean closing)
{
_closing = closing;
+
+ CurrentActor.get().message(_logSubject, ChannelMessages.CHN_CLOSE());
}
private void unsubscribeAllConsumers() throws AMQException
{
- if (_log.isInfoEnabled())
+ if (_logger.isInfoEnabled())
{
if (!_tag2SubscriptionMap.isEmpty())
{
- _log.info("Unsubscribing all consumers on channel " + toString());
+ _logger.info("Unsubscribing all consumers on channel " + toString());
}
else
{
- _log.info("No consumers to unsubscribe on channel " + toString());
+ _logger.info("No consumers to unsubscribe on channel " + toString());
}
}
for (Map.Entry<AMQShortString, Subscription> me : _tag2SubscriptionMap.entrySet())
{
- if (_log.isInfoEnabled())
+ if (_logger.isInfoEnabled())
{
- _log.info("Unsubscribing consumer '" + me.getKey() + "' on channel " + toString());
+ _logger.info("Unsubscribing consumer '" + me.getKey() + "' on channel " + toString());
}
Subscription sub = me.getValue();
- sub.getQueue().unregisterSubscription(sub);
+ try
+ {
+ sub.getSendLock();
+ sub.getQueue().unregisterSubscription(sub);
+ }
+ finally
+ {
+ sub.releaseSendLock();
+ }
+
}
_tag2SubscriptionMap.clear();
@@ -422,17 +468,17 @@ public class AMQChannel
*/
public void addUnacknowledgedMessage(QueueEntry entry, long deliveryTag, Subscription subscription)
{
- if (_log.isDebugEnabled())
+ if (_logger.isDebugEnabled())
{
if (entry.getQueue() == null)
{
- _log.debug("Adding unacked message with a null queue:" + entry.debugIdentity());
+ _logger.debug("Adding unacked message with a null queue:" + entry);
}
else
{
- if (_log.isDebugEnabled())
+ if (_logger.isDebugEnabled())
{
- _log.debug(debugIdentity() + " Adding unacked message(" + entry.getMessage().toString() + " DT:" + deliveryTag
+ _logger.debug(debugIdentity() + " Adding unacked message(" + entry.getMessage().toString() + " DT:" + deliveryTag
+ ") with a queue(" + entry.getQueue() + ") for " + subscription);
}
}
@@ -460,27 +506,13 @@ public class AMQChannel
// we must create a new map since all the messages will get a new delivery tag when they are redelivered
Collection<QueueEntry> messagesToBeDelivered = _unacknowledgedMessageMap.cancelAllMessages();
- // Deliver these messages out of the transaction as their delivery was never
- // part of the transaction only the receive.
- TransactionalContext deliveryContext = null;
-
if (!messagesToBeDelivered.isEmpty())
{
- if (_log.isInfoEnabled())
+ if (_logger.isInfoEnabled())
{
- _log.info("Requeuing " + messagesToBeDelivered.size() + " unacked messages. for " + toString());
+ _logger.info("Requeuing " + messagesToBeDelivered.size() + " unacked messages. for " + toString());
}
- if (!(_txnContext instanceof NonTransactionalContext))
- {
-
- deliveryContext =
- new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages);
- }
- else
- {
- deliveryContext = _txnContext;
- }
}
for (QueueEntry unacked : messagesToBeDelivered)
@@ -488,18 +520,15 @@ public class AMQChannel
if (!unacked.isQueueDeleted())
{
// Mark message redelivered
- unacked.getMessage().setRedelivered(true);
+ unacked.setRedelivered();
// Ensure message is released for redelivery
unacked.release();
- // Deliver Message
- deliveryContext.requeue(unacked);
-
}
else
{
- unacked.discard(_storeContext);
+ unacked.discard();
}
}
@@ -519,48 +548,27 @@ public class AMQChannel
if (unacked != null)
{
// Mark message redelivered
- unacked.getMessage().setRedelivered(true);
+ unacked.setRedelivered();
// Ensure message is released for redelivery
if (!unacked.isQueueDeleted())
{
- unacked.release();
- }
-
-
- // Deliver these messages out of the transaction as their delivery was never
- // part of the transaction only the receive.
- TransactionalContext deliveryContext;
- if (!(_txnContext instanceof NonTransactionalContext))
- {
- deliveryContext =
- new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages);
-
- }
- else
- {
- deliveryContext = _txnContext;
- }
+ // Ensure message is released for redelivery
+ unacked.release();
- if (!unacked.isQueueDeleted())
- {
- // Redeliver the messages to the front of the queue
- deliveryContext.requeue(unacked);
- // Deliver increments the message count but we have already deliverted this once so don't increment it again
- // this was because deliver did an increment changed this.
}
else
{
- _log.warn(System.identityHashCode(this) + " Requested requeue of message(" + unacked.getMessage().debugIdentity()
+ _logger.warn(System.identityHashCode(this) + " Requested requeue of message(" + unacked
+ "):" + deliveryTag + " but no queue defined and no DeadLetter queue so DROPPING message.");
- unacked.discard(_storeContext);
+ unacked.discard();
}
}
else
{
- _log.warn("Requested requeue of message:" + deliveryTag + " but no such delivery tag exists."
+ _logger.warn("Requested requeue of message:" + deliveryTag + " but no such delivery tag exists."
+ _unacknowledgedMessageMap.size());
}
@@ -581,79 +589,31 @@ public class AMQChannel
final Map<Long, QueueEntry> msgToRequeue = new LinkedHashMap<Long, QueueEntry>();
final Map<Long, QueueEntry> msgToResend = new LinkedHashMap<Long, QueueEntry>();
- if (_log.isDebugEnabled())
+ if (_logger.isDebugEnabled())
{
- _log.debug("unacked map Size:" + _unacknowledgedMessageMap.size());
+ _logger.debug("unacked map Size:" + _unacknowledgedMessageMap.size());
}
// Process the Unacked-Map.
// Marking messages who still have a consumer for to be resent
// and those that don't to be requeued.
+ _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap,
+ msgToRequeue,
+ msgToResend,
+ requeue,
+ _messageStore));
- _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor()
- {
- public boolean callback(final long deliveryTag, QueueEntry message) throws AMQException
- {
-
- AMQMessage msg = message.getMessage();
- msg.setRedelivered(true);
- final Subscription subscription = message.getDeliveredSubscription();
- if (subscription != null)
- {
- // Consumer exists
- if (!subscription.isClosed())
- {
- msgToResend.put(deliveryTag, message);
- }
- else // consumer has gone
- {
- msgToRequeue.put(deliveryTag, message);
- }
- }
- else
- {
- // Message has no consumer tag, so was "delivered" to a GET
- // or consumer no longer registered
- // cannot resend, so re-queue.
- if (!message.isQueueDeleted())
- {
- if (requeue)
- {
- msgToRequeue.put(deliveryTag, message);
- }
- else
- {
- _log.info("No DeadLetter Queue and requeue not requested so dropping message:" + message);
- }
- }
- else
- {
- message.discard(_storeContext);
- _log.warn("Message.queue is null and no DeadLetter Queue so dropping message:" + message);
- }
- }
-
- // false means continue processing
- return false;
- }
-
- public void visitComplete()
- {
- }
- });
-
- _unacknowledgedMessageMap.clear();
// Process Messages to Resend
- if (_log.isDebugEnabled())
+ if (_logger.isDebugEnabled())
{
if (!msgToResend.isEmpty())
{
- _log.debug("Preparing (" + msgToResend.size() + ") message to resend.");
+ _logger.debug("Preparing (" + msgToResend.size() + ") message to resend.");
}
else
{
- _log.debug("No message to resend.");
+ _logger.debug("No message to resend.");
}
}
@@ -664,7 +624,7 @@ public class AMQChannel
- AMQMessage msg = message.getMessage();
+ ServerMessage msg = message.getMessage();
AMQQueue queue = message.getQueue();
// Our Java Client will always suspend the channel when resending!
@@ -673,7 +633,7 @@ public class AMQChannel
// i.e. The channel hasn't been server side suspended.
// if (isSuspended())
// {
- // _log.info("Channel is suspended so requeuing");
+ // _logger.info("Channel is suspended so requeuing");
// //move this message to requeue
// msgToRequeue.add(message);
// }
@@ -683,14 +643,14 @@ public class AMQChannel
// Without any details from the client about what has been processed we have to mark
// all messages in the unacked map as redelivered.
- msg.setRedelivered(true);
+ message.setRedelivered();
Subscription sub = message.getDeliveredSubscription();
if (sub != null)
{
-
- if(!queue.resend(message, sub))
+
+ if(!queue.resend(message,sub))
{
msgToRequeue.put(deliveryTag, message);
}
@@ -698,9 +658,9 @@ public class AMQChannel
else
{
- if (_log.isInfoEnabled())
+ if (_logger.isInfoEnabled())
{
- _log.info("DeliveredSubscription not recorded so just requeueing(" + message.toString()
+ _logger.info("DeliveredSubscription not recorded so just requeueing(" + message.toString()
+ ")to prevent loss");
}
// move this message to requeue
@@ -709,91 +669,28 @@ public class AMQChannel
} // for all messages
// } else !isSuspend
- if (_log.isInfoEnabled())
+ if (_logger.isInfoEnabled())
{
if (!msgToRequeue.isEmpty())
{
- _log.info("Preparing (" + msgToRequeue.size() + ") message to requeue to.");
+ _logger.info("Preparing (" + msgToRequeue.size() + ") message to requeue to.");
}
}
- // Deliver these messages out of the transaction as their delivery was never
- // part of the transaction only the receive.
- TransactionalContext deliveryContext;
- if (!(_txnContext instanceof NonTransactionalContext))
- {
-
- deliveryContext =
- new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages);
- }
- else
- {
- deliveryContext = _txnContext;
- }
-
// Process Messages to Requeue at the front of the queue
for (Map.Entry<Long, QueueEntry> entry : msgToRequeue.entrySet())
{
QueueEntry message = entry.getValue();
long deliveryTag = entry.getKey();
-
- message.release();
- message.setRedelivered(true);
+ _unacknowledgedMessageMap.remove(deliveryTag);
- deliveryContext.requeue(message);
+ message.setRedelivered();
+ message.release();
- _unacknowledgedMessageMap.remove(deliveryTag);
}
}
- /**
- * Callback indicating that a queue has been deleted. We must update the structure of unacknowledged messages to
- * remove the queue reference and also decrement any message reference counts, without actually removing the item
- * since we may get an ack for a delivery tag that was generated from the deleted queue.
- *
- * @param queue the queue that has been deleted
- *
- */
- /* public void queueDeleted(final AMQQueue queue)
- {
- try
- {
- _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor()
- {
- public boolean callback(UnacknowledgedMessage message)
- {
- if (message.getQueue() == queue)
- {
- try
- {
- message.discard(_storeContext);
- message.setQueueDeleted(true);
-
- }
- catch (AMQException e)
- {
- _log.error(
- "Error decrementing ref count on message " + message.getMessage().getMessageId() + ": " + e, e);
- throw new RuntimeException(e);
- }
- }
-
- return false;
- }
-
- public void visitComplete()
- {
- }
- });
- }
- catch (AMQException e)
- {
- _log.error("Unexpected Error while handling deletion of queue", e);
- throw new RuntimeException(e);
- }
- }
-*/
/**
* Acknowledge one or more messages.
*
@@ -805,7 +702,17 @@ public class AMQChannel
*/
public void acknowledgeMessage(long deliveryTag, boolean multiple) throws AMQException
{
- _unacknowledgedMessageMap.acknowledgeMessage(deliveryTag, multiple, _txnContext);
+ Collection<QueueEntry> ackedMessages = getAckedMessages(deliveryTag, multiple);
+ _transaction.dequeue(ackedMessages, new MessageAcknowledgeAction(ackedMessages));
+ }
+
+ private Collection<QueueEntry> getAckedMessages(long deliveryTag, boolean multiple)
+ {
+
+ Map<Long, QueueEntry> ackedMessageMap = new LinkedHashMap<Long,QueueEntry>();
+ _unacknowledgedMessageMap.collect(deliveryTag, multiple, ackedMessageMap);
+ _unacknowledgedMessageMap.remove(ackedMessageMap);
+ return ackedMessageMap.values();
}
/**
@@ -818,14 +725,32 @@ public class AMQChannel
return _unacknowledgedMessageMap;
}
-
+ /**
+ * Called from the ChannelFlowHandler to suspend this Channel
+ * @param suspended boolean, should this Channel be suspended
+ */
public void setSuspended(boolean suspended)
{
-
-
boolean wasSuspended = _suspended.getAndSet(suspended);
if (wasSuspended != suspended)
{
+ // Log Flow Started before we start the subscriptions
+ if (!suspended)
+ {
+ _actor.message(_logSubject, ChannelMessages.CHN_FLOW("Started"));
+ }
+
+
+ // This section takes two different approaches to perform to perform
+ // the same function. Ensuring that the Subscription has taken note
+ // of the change in Channel State
+
+ // Here we have become unsuspended and so we ask each the queue to
+ // perform an Async delivery for each of the subscriptions in this
+ // Channel. The alternative would be to ensure that the subscription
+ // had received the change in suspension state. That way the logic
+ // behind decieding to start an async delivery was located with the
+ // Subscription.
if (wasSuspended)
{
// may need to deliver queued messages
@@ -834,12 +759,44 @@ public class AMQChannel
s.getQueue().deliverAsync(s);
}
}
+
+
+ // Here we have become suspended so we need to ensure that each of
+ // the Subscriptions has noticed this change so that we can be sure
+ // they are not still sending messages. Again the code here is a
+ // very simplistic approach to ensure that the change of suspension
+ // has been noticed by each of the Subscriptions. Unlike the above
+ // case we don't actually need to do anything else.
+ if (!wasSuspended)
+ {
+ // may need to deliver queued messages
+ for (Subscription s : _tag2SubscriptionMap.values())
+ {
+ try
+ {
+ s.getSendLock();
+ }
+ finally
+ {
+ s.releaseSendLock();
+ }
+ }
+ }
+
+
+ // Log Suspension only after we have confirmed all suspensions are
+ // stopped.
+ if (suspended)
+ {
+ _actor.message(_logSubject, ChannelMessages.CHN_FLOW("Stopped"));
+ }
+
}
}
public boolean isSuspended()
{
- return _suspended.get();
+ return _suspended.get() || _closing || _session.isClosing();
}
public void commit() throws AMQException
@@ -849,57 +806,87 @@ public class AMQChannel
throw new AMQException("Fatal error: commit called on non-transactional channel");
}
- _txnContext.commit();
+ _transaction.commit();
+
}
public void rollback() throws AMQException
{
- _txnContext.rollback();
+ rollback(NULL_TASK);
}
- public String toString()
+ public void rollback(Runnable postRollbackTask) throws AMQException
{
- return "["+_session.toString()+":"+_channelId+"]";
- }
+ if (!isTransactional())
+ {
+ throw new AMQException("Fatal error: commit called on non-transactional channel");
+ }
- public void setDefaultQueue(AMQQueue queue)
- {
- _defaultQueue = queue;
- }
+ // stop all subscriptions
+ _rollingBack = true;
+ boolean requiresSuspend = _suspended.compareAndSet(false,true);
- public AMQQueue getDefaultQueue()
- {
- return _defaultQueue;
- }
+ // ensure all subscriptions have seen the change to the channel state
+ for(Subscription sub : _tag2SubscriptionMap.values())
+ {
+ sub.getSendLock();
+ sub.releaseSendLock();
+ }
- public StoreContext getStoreContext()
- {
- return _storeContext;
- }
+ try
+ {
+ _transaction.rollback();
+ }
+ finally
+ {
+ _rollingBack = false;
+ }
- public void processReturns() throws AMQException
- {
- if (!_returnMessages.isEmpty())
+ postRollbackTask.run();
+
+ for(QueueEntry entry : _resendList)
{
- for (RequiredDeliveryException bouncedMessage : _returnMessages)
+ Subscription sub = entry.getDeliveredSubscription();
+ if(sub == null || sub.isClosed())
+ {
+ entry.release();
+ }
+ else
{
- AMQMessage message = bouncedMessage.getAMQMessage();
- _session.getProtocolOutputConverter().writeReturn(message, _channelId, bouncedMessage.getReplyCode().getCode(),
- new AMQShortString(bouncedMessage.getMessage()));
+ sub.getQueue().resend(entry, sub);
+ }
+ }
+ _resendList.clear();
- message.decrementReference(_storeContext);
+ if(requiresSuspend)
+ {
+ _suspended.set(false);
+ for(Subscription sub : _tag2SubscriptionMap.values())
+ {
+ sub.getQueue().deliverAsync(sub);
}
- _returnMessages.clear();
}
+
+
+ }
+
+ public String toString()
+ {
+ return "["+_session.toString()+":"+_channelId+"]";
}
+ public void setDefaultQueue(AMQQueue queue)
+ {
+ _defaultQueue = queue;
+ }
- public TransactionalContext getTransactionalContext()
+ public AMQQueue getDefaultQueue()
{
- return _txnContext;
+ return _defaultQueue;
}
+
public boolean isClosing()
{
return _closing;
@@ -917,14 +904,10 @@ public class AMQChannel
public void setCredit(final long prefetchSize, final int prefetchCount)
{
+ _actor.message(ChannelMessages.CHN_PREFETCH_SIZE(prefetchSize, prefetchCount));
_creditManager.setCreditLimits(prefetchSize, prefetchCount);
}
- public List<RequiredDeliveryException> getReturnMessages()
- {
- return _returnMessages;
- }
-
public MessageStore getMessageStore()
{
return _messageStore;
@@ -936,8 +919,10 @@ public class AMQChannel
public void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag)
throws AMQException
{
- getProtocolSession().getProtocolOutputConverter().writeDeliver(entry.getMessage(), getChannelId(), deliveryTag, sub.getConsumerTag());
+ getProtocolSession().getProtocolOutputConverter().writeDeliver(entry, getChannelId(),
+ deliveryTag, sub.getConsumerTag());
}
+
};
public ClientDeliveryMethod getClientDeliveryMethod()
@@ -958,4 +943,254 @@ public class AMQChannel
{
return _recordDeliveryMethod;
}
+
+
+ private AMQMessage createAMQMessage(IncomingMessage incomingMessage)
+ throws AMQException
+ {
+
+ AMQMessage message = new AMQMessage(incomingMessage.getStoredMessage());
+
+ message.setExpiration(incomingMessage.getExpiration());
+ message.setClientIdentifier(_session);
+ return message;
+ }
+
+ private boolean checkMessageUserId(ContentHeaderBody header)
+ {
+ AMQShortString userID =
+ header.properties instanceof BasicContentHeaderProperties
+ ? ((BasicContentHeaderProperties) header.properties).getUserId()
+ : null;
+
+ return (!MSG_AUTH || _session.getPrincipal().getName().equals(userID == null? "" : userID.toString()));
+
+ }
+
+ private class MessageDeliveryAction implements ServerTransaction.Action
+ {
+ private IncomingMessage _incommingMessage;
+ private ArrayList<AMQQueue> _destinationQueues;
+
+ public MessageDeliveryAction(IncomingMessage currentMessage,
+ ArrayList<AMQQueue> destinationQueues)
+ {
+ _incommingMessage = currentMessage;
+ _destinationQueues = destinationQueues;
+ }
+
+ public void postCommit()
+ {
+ try
+ {
+ final boolean immediate = _incommingMessage.isImmediate();
+
+ final AMQMessage amqMessage = createAMQMessage(_incommingMessage);
+ MessageReference ref = amqMessage.newReference();
+
+ for(AMQQueue queue : _destinationQueues)
+ {
+
+ QueueEntry entry = queue.enqueue(amqMessage);
+ queue.checkCapacity(AMQChannel.this);
+
+
+ if(immediate && !entry.getDeliveredToConsumer() && entry.acquire())
+ {
+
+
+ ServerTransaction txn = new LocalTransaction(_messageStore);
+ Collection<QueueEntry> entries = new ArrayList<QueueEntry>(1);
+ entries.add(entry);
+ final AMQMessage message = (AMQMessage) entry.getMessage();
+ txn.dequeue(queue, entry.getMessage(),
+ new MessageAcknowledgeAction(entries)
+ {
+ @Override
+ public void postCommit()
+ {
+ try
+ {
+ final
+ ProtocolOutputConverter outputConverter =
+ _session.getProtocolOutputConverter();
+
+ outputConverter.writeReturn(message.getMessagePublishInfo(),
+ message.getContentHeaderBody(),
+ message,
+ _channelId,
+ AMQConstant.NO_CONSUMERS.getCode(),
+ IMMEDIATE_DELIVERY_REPLY_TEXT);
+ }
+ catch (AMQException e)
+ {
+ throw new RuntimeException(e);
+ }
+ super.postCommit();
+ }
+ }
+ );
+ txn.commit();
+
+
+
+
+ }
+
+ }
+ ref.release();
+ }
+ catch (AMQException e)
+ {
+ // TODO
+ throw new RuntimeException(e);
+ }
+
+
+
+
+
+ }
+
+ public void onRollback()
+ {
+ // Maybe keep track of entries that were created and then delete them here in case of failure
+ // to in memory enqueue
+ }
+ }
+
+ private class MessageAcknowledgeAction implements ServerTransaction.Action
+ {
+ private final Collection<QueueEntry> _ackedMessages;
+
+
+ public MessageAcknowledgeAction(Collection<QueueEntry> ackedMessages)
+ {
+ _ackedMessages = ackedMessages;
+ }
+
+ public void postCommit()
+ {
+ try
+ {
+ for(QueueEntry entry : _ackedMessages)
+ {
+ entry.discard();
+ }
+ }
+ finally
+ {
+ _acknowledgedMessages.clear();
+ }
+
+ }
+
+ public void onRollback()
+ {
+ // explicit rollbacks resend the message after the rollback-ok is sent
+ if(_rollingBack)
+ {
+ _resendList.addAll(_ackedMessages);
+ }
+ else
+ {
+ try
+ {
+ for(QueueEntry entry : _ackedMessages)
+ {
+ entry.release();
+ }
+ }
+ finally
+ {
+ _acknowledgedMessages.clear();
+ }
+ }
+
+ }
+ }
+
+ private class WriteReturnAction implements ServerTransaction.Action
+ {
+ private final AMQConstant _errorCode;
+ private final IncomingMessage _message;
+ private final String _description;
+
+ public WriteReturnAction(AMQConstant errorCode,
+ String description,
+ IncomingMessage message)
+ {
+ _errorCode = errorCode;
+ _message = message;
+ _description = description;
+ }
+
+ public void postCommit()
+ {
+ try
+ {
+ _session.getProtocolOutputConverter().writeReturn(_message.getMessagePublishInfo(),
+ _message.getContentHeader(),
+ _message,
+ _channelId,
+ _errorCode.getCode(),
+ new AMQShortString(_description));
+ }
+ catch (AMQException e)
+ {
+ //TODO
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public void onRollback()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+ }
+
+
+ public LogActor getLogActor()
+ {
+ return _actor;
+ }
+
+ public void block(AMQQueue queue)
+ {
+ if(_blockingQueues.putIfAbsent(queue, Boolean.TRUE) == null)
+ {
+
+ if(_blocking.compareAndSet(false,true))
+ {
+ _actor.message(_logSubject, ChannelMessages.CHN_FLOW_ENFORCED(queue.getName().toString()));
+ flow(false);
+ }
+ }
+ }
+
+ public void unblock(AMQQueue queue)
+ {
+ if(_blockingQueues.remove(queue))
+ {
+ if(_blocking.compareAndSet(true,false))
+ {
+ _actor.message(_logSubject, ChannelMessages.CHN_FLOW_REMOVED());
+
+ flow(true);
+ }
+ }
+ }
+
+ private void flow(boolean flow)
+ {
+ MethodRegistry methodRegistry = _session.getMethodRegistry();
+ AMQMethodBody responseBody = methodRegistry.createChannelFlowBody(flow);
+ _session.writeFrame(responseBody.generateFrame(_channelId));
+ }
+
+ public boolean getBlocking()
+ {
+ return _blocking.get();
+ }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java b/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java
deleted file mode 100644
index 9a98af5689..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java
+++ /dev/null
@@ -1,25 +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.
- *
- */
-package org.apache.qpid.server;
-
-public class ConsumerTagNotUniqueException extends Exception
-{
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java b/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java
new file mode 100644
index 0000000000..9da02e0600
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java
@@ -0,0 +1,133 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server;
+
+import org.apache.qpid.server.ack.UnacknowledgedMessageMap;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.store.TransactionLog;
+import org.apache.qpid.server.txn.ServerTransaction;
+import org.apache.qpid.server.txn.AutoCommitTransaction;
+import org.apache.qpid.AMQException;
+import org.apache.log4j.Logger;
+
+import java.util.Map;
+
+public class ExtractResendAndRequeue implements UnacknowledgedMessageMap.Visitor
+{
+ private static final Logger _log = Logger.getLogger(ExtractResendAndRequeue.class);
+
+ private final Map<Long, QueueEntry> _msgToRequeue;
+ private final Map<Long, QueueEntry> _msgToResend;
+ private final boolean _requeueIfUnabletoResend;
+ private final UnacknowledgedMessageMap _unacknowledgedMessageMap;
+ private final TransactionLog _transactionLog;
+
+ public ExtractResendAndRequeue(UnacknowledgedMessageMap unacknowledgedMessageMap,
+ Map<Long, QueueEntry> msgToRequeue,
+ Map<Long, QueueEntry> msgToResend,
+ boolean requeueIfUnabletoResend,
+ TransactionLog txnLog)
+ {
+ _unacknowledgedMessageMap = unacknowledgedMessageMap;
+ _msgToRequeue = msgToRequeue;
+ _msgToResend = msgToResend;
+ _requeueIfUnabletoResend = requeueIfUnabletoResend;
+ _transactionLog = txnLog;
+ }
+
+ public boolean callback(final long deliveryTag, QueueEntry message) throws AMQException
+ {
+
+ message.setRedelivered();
+ final Subscription subscription = message.getDeliveredSubscription();
+ if (subscription != null)
+ {
+ // Consumer exists
+ if (!subscription.isClosed())
+ {
+ _msgToResend.put(deliveryTag, message);
+ }
+ else // consumer has gone
+ {
+ _msgToRequeue.put(deliveryTag, message);
+ }
+ }
+ else
+ {
+ // Message has no consumer tag, so was "delivered" to a GET
+ // or consumer no longer registered
+ // cannot resend, so re-queue.
+ if (!message.isQueueDeleted())
+ {
+ if (_requeueIfUnabletoResend)
+ {
+ _msgToRequeue.put(deliveryTag, message);
+ }
+ else
+ {
+
+ dequeueEntry(message);
+ _log.info("No DeadLetter Queue and requeue not requested so dropping message:" + message);
+ }
+ }
+ else
+ {
+ dequeueEntry(message);
+ _log.warn("Message.queue is null and no DeadLetter Queue so dropping message:" + message);
+ }
+ }
+
+ // false means continue processing
+ return false;
+ }
+
+
+ private void dequeueEntry(final QueueEntry node)
+ {
+ ServerTransaction txn = new AutoCommitTransaction(_transactionLog);
+ dequeueEntry(node, txn);
+ }
+
+ private void dequeueEntry(final QueueEntry node, ServerTransaction txn)
+ {
+ txn.dequeue(node.getQueue(), node.getMessage(),
+ new ServerTransaction.Action()
+ {
+
+ public void postCommit()
+ {
+ node.discard();
+ }
+
+ public void onRollback()
+ {
+
+ }
+ });
+ }
+
+ public void visitComplete()
+ {
+ _unacknowledgedMessageMap.clear();
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/Main.java b/java/broker/src/main/java/org/apache/qpid/server/Main.java
index 8ad2ace1b2..90afd2e4ac 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/Main.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/Main.java
@@ -20,6 +20,18 @@
*/
package org.apache.qpid.server;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.util.Properties;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Collection;
+import java.util.Arrays;
+
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
@@ -27,36 +39,32 @@ import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.ConfigurationException;
-import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
-import org.apache.log4j.xml.DOMConfigurator;
-import org.apache.mina.common.ByteBuffer;
-import org.apache.mina.common.IoAcceptor;
-import org.apache.mina.common.FixedSizeByteBufferAllocator;
-import org.apache.mina.transport.socket.nio.SocketAcceptorConfig;
-import org.apache.mina.transport.socket.nio.SocketSessionConfig;
-import org.apache.qpid.AMQException;
+import org.apache.log4j.PropertyConfigurator;
+import org.apache.log4j.xml.QpidLog4JConfigurator;
+import org.apache.qpid.transport.network.ConnectionBinding;
+import org.apache.qpid.transport.*;
import org.apache.qpid.common.QpidProperties;
import org.apache.qpid.framing.ProtocolVersion;
-import org.apache.qpid.pool.ReadWriteThreadModel;
-import org.apache.qpid.server.configuration.VirtualHostConfiguration;
-import org.apache.qpid.server.management.JMXManagedObjectRegistry;
-import org.apache.qpid.server.protocol.AMQPFastProtocolHandler;
-import org.apache.qpid.server.protocol.AMQPProtocolProvider;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.configuration.management.ConfigurationManagementMBean;
+import org.apache.qpid.server.information.management.ServerInformationMBean;
+import org.apache.qpid.server.logging.StartupRootMessageLogger;
+import org.apache.qpid.server.logging.actors.BrokerActor;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.management.LoggingManagementMBean;
+import org.apache.qpid.server.logging.messages.BrokerMessages;
+import org.apache.qpid.server.protocol.AMQProtocolEngineFactory;
+import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry;
-import org.apache.qpid.server.transport.ConnectorConfiguration;
-import org.apache.qpid.url.URLSyntaxException;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.BindException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.util.Collection;
-import java.util.List;
+import org.apache.qpid.server.registry.IApplicationRegistry;
+import org.apache.qpid.server.transport.ServerConnection;
+import org.apache.qpid.server.transport.QpidAcceptor;
+import org.apache.qpid.ssl.SSLContextFactory;
+import org.apache.qpid.transport.NetworkDriver;
+import org.apache.qpid.transport.network.mina.MINANetworkDriver;
+import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory.VERSION;
/**
* Main entry point for AMQPD.
@@ -65,16 +73,17 @@ import java.util.List;
@SuppressWarnings({"AccessStaticViaInstance"})
public class Main
{
- private static final Logger _logger = Logger.getLogger(Main.class);
- public static final Logger _brokerLogger = Logger.getLogger("Qpid.Broker");
+ private static Logger _logger;
+ private static Logger _brokerLogger;
private static final String DEFAULT_CONFIG_FILE = "etc/config.xml";
- private static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml";
+ public static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml";
public static final String QPID_HOME = "QPID_HOME";
private static final int IPV4_ADDRESS_LENGTH = 4;
private static final char IPV4_LITERAL_SEPARATOR = '.';
+ private static final Collection<VERSION> ALL_VERSIONS = Arrays.asList(VERSION.values());
protected static class InitException extends Exception
{
@@ -125,6 +134,30 @@ public class Main
OptionBuilder.withArgName("port").hasArg()
.withDescription("listen on the specified port. Overrides any value in the config file")
.withLongOpt("port").create("p");
+
+ Option exclude0_10 =
+ OptionBuilder.withArgName("exclude-0-10").hasArg()
+ .withDescription("when listening on the specified port do not accept AMQP0-10 connections. The specified port must be one specified on the command line")
+ .withLongOpt("exclude-0-10").create();
+
+ Option exclude0_9_1 =
+ OptionBuilder.withArgName("exclude-0-9-1").hasArg()
+ .withDescription("when listening on the specified port do not accept AMQP0-9-1 connections. The specified port must be one specified on the command line")
+ .withLongOpt("exclude-0-9-1").create();
+
+
+ Option exclude0_9 =
+ OptionBuilder.withArgName("exclude-0-9").hasArg()
+ .withDescription("when listening on the specified port do not accept AMQP0-9 connections. The specified port must be one specified on the command line")
+ .withLongOpt("exclude-0-9").create();
+
+
+ Option exclude0_8 =
+ OptionBuilder.withArgName("exclude-0-8").hasArg()
+ .withDescription("when listening on the specified port do not accept AMQP0-8 connections. The specified port must be one specified on the command line")
+ .withLongOpt("exclude-0-8").create();
+
+
Option mport =
OptionBuilder.withArgName("mport").hasArg()
.withDescription("listen on the specified management port. Overrides any value in the config file")
@@ -151,6 +184,10 @@ public class Main
options.addOption(logconfig);
options.addOption(logwatchconfig);
options.addOption(port);
+ options.addOption(exclude0_10);
+ options.addOption(exclude0_9_1);
+ options.addOption(exclude0_9);
+ options.addOption(exclude0_8);
options.addOption(mport);
options.addOption(bind);
}
@@ -192,30 +229,33 @@ public class Main
{
try
{
+ CurrentActor.set(new BrokerActor(new StartupRootMessageLogger()));
startup();
+ CurrentActor.remove();
}
catch (InitException e)
{
- System.out.println(e.getMessage());
+ System.out.println("Initialisation Error : " + e.getMessage());
_brokerLogger.error("Initialisation Error : " + e.getMessage());
-
+ shutdown(1);
}
- catch (ConfigurationException e)
+ catch (Throwable e)
{
- System.out.println("Error configuring message broker: " + e);
- _brokerLogger.error("Error configuring message broker: " + e);
- e.printStackTrace();
- }
- catch (Exception e)
- {
- System.out.println("Error intialising message broker: " + e);
- _brokerLogger.error("Error intialising message broker: " + e);
+ System.out.println("Error initialising message broker: " + e);
+ _brokerLogger.error("Error initialising message broker: " + e);
e.printStackTrace();
+ shutdown(1);
}
}
}
- protected void startup() throws InitException, ConfigurationException, Exception
+ protected void shutdown(int status)
+ {
+ ApplicationRegistry.removeAll();
+ System.exit(status);
+ }
+
+ protected void startup() throws Exception
{
final String QpidHome = System.getProperty(QPID_HOME);
final File defaultConfigFile = new File(QpidHome, DEFAULT_CONFIG_FILE);
@@ -233,248 +273,270 @@ public class Main
}
else
{
- System.out.println("Using configuration file " + configFile.getAbsolutePath());
+ CurrentActor.get().message(BrokerMessages.BRK_CONFIG(configFile.getAbsolutePath()));
}
String logConfig = commandLine.getOptionValue("l");
String logWatchConfig = commandLine.getOptionValue("w", "0");
+
+ int logWatchTime = 0;
+ try
+ {
+ logWatchTime = Integer.parseInt(logWatchConfig);
+ }
+ catch (NumberFormatException e)
+ {
+ System.err.println("Log watch configuration value of " + logWatchConfig + " is invalid. Must be "
+ + "a non-negative integer. Using default of zero (no watching configured");
+ }
+
+ File logConfigFile;
if (logConfig != null)
{
- File logConfigFile = new File(logConfig);
- configureLogging(logConfigFile, logWatchConfig);
+ logConfigFile = new File(logConfig);
+ configureLogging(logConfigFile, logWatchTime);
}
else
{
File configFileDirectory = configFile.getParentFile();
- File logConfigFile = new File(configFileDirectory, DEFAULT_LOG_CONFIG_FILENAME);
- configureLogging(logConfigFile, logWatchConfig);
+ logConfigFile = new File(configFileDirectory, DEFAULT_LOG_CONFIG_FILENAME);
+ configureLogging(logConfigFile, logWatchTime);
}
ConfigurationFileApplicationRegistry config = new ConfigurationFileApplicationRegistry(configFile);
+ ServerConfiguration serverConfig = config.getConfiguration();
+ updateManagementPort(serverConfig, commandLine.getOptionValue("m"));
+ ApplicationRegistry.initialise(config);
- updateManagementPort(config.getConfiguration(), commandLine.getOptionValue("m"));
+ // We have already loaded the BrokerMessages class by this point so we
+ // need to refresh the locale setting incase we had a different value in
+ // the configuration.
+ BrokerMessages.reload();
+ // AR.initialise() sets its own actor so we now need to set the actor
+ // for the remainder of the startup
+ CurrentActor.set(new BrokerActor(config.getRootMessageLogger()));
+ CurrentActor.setDefault(new BrokerActor(config.getRootMessageLogger()));
+ try
+ {
+ configureLoggingManagementMBean(logConfigFile, logWatchTime);
- ApplicationRegistry.initialise(config);
+ ConfigurationManagementMBean configMBean = new ConfigurationManagementMBean();
+ configMBean.register();
+ ServerInformationMBean sysInfoMBean =
+ new ServerInformationMBean(QpidProperties.getBuildVersion(), QpidProperties.getReleaseVersion());
+ sysInfoMBean.register();
- //fixme .. use QpidProperties.getVersionString when we have fixed the classpath issues
- // that are causing the broker build to pick up the wrong properties file and hence say
- // Starting Qpid Client
- _brokerLogger.info("Starting Qpid Broker " + QpidProperties.getReleaseVersion()
- + " build: " + QpidProperties.getBuildVersion());
+ //fixme .. use QpidProperties.getVersionString when we have fixed the classpath issues
+ // that are causing the broker build to pick up the wrong properties file and hence say
+ // Starting Qpid Client
+ _brokerLogger.info("Starting Qpid Broker " + QpidProperties.getReleaseVersion()
+ + " build: " + QpidProperties.getBuildVersion());
- ConnectorConfiguration connectorConfig =
- ApplicationRegistry.getInstance().getConfiguredObject(ConnectorConfiguration.class);
- ByteBuffer.setUseDirectBuffers(connectorConfig.enableDirectBuffers);
- // the MINA default is currently to use the pooled allocator although this may change in future
- // once more testing of the performance of the simple allocator has been done
- if (!connectorConfig.enablePooledAllocator)
- {
- ByteBuffer.setAllocator(new FixedSizeByteBufferAllocator());
- }
+ String[] portStr = commandLine.getOptionValues("p");
+ Set<Integer> ports = new HashSet<Integer>();
+ Set<Integer> exclude_0_10 = new HashSet<Integer>();
+ Set<Integer> exclude_0_9_1 = new HashSet<Integer>();
+ Set<Integer> exclude_0_9 = new HashSet<Integer>();
+ Set<Integer> exclude_0_8 = new HashSet<Integer>();
- if(connectorConfig.useBiasedWrites)
- {
- System.setProperty("org.apache.qpid.use_write_biased_pool","true");
- }
+ if(portStr == null || portStr.length == 0)
+ {
- int port = connectorConfig.port;
+ parsePortList(ports, serverConfig.getPorts());
+ parsePortList(exclude_0_10, serverConfig.getPortExclude010());
+ parsePortList(exclude_0_9_1, serverConfig.getPortExclude091());
+ parsePortList(exclude_0_9, serverConfig.getPortExclude09());
+ parsePortList(exclude_0_8, serverConfig.getPortExclude08());
- String portStr = commandLine.getOptionValue("p");
- if (portStr != null)
- {
- try
+ }
+ else
{
- port = Integer.parseInt(portStr);
+ parsePortArray(ports, portStr);
+ parsePortArray(exclude_0_10, commandLine.getOptionValues("exclude-0-10"));
+ parsePortArray(exclude_0_9_1, commandLine.getOptionValues("exclude-0-9-1"));
+ parsePortArray(exclude_0_9, commandLine.getOptionValues("exclude-0-9"));
+ parsePortArray(exclude_0_8, commandLine.getOptionValues("exclude-0-8"));
+
}
- catch (NumberFormatException e)
+
+
+
+
+ String bindAddr = commandLine.getOptionValue("b");
+ if (bindAddr == null)
{
- throw new InitException("Invalid port: " + portStr, e);
+ bindAddr = serverConfig.getBind();
}
- }
+ InetAddress bindAddress = null;
- String VIRTUAL_HOSTS = "virtualhosts";
- Object virtualHosts = ApplicationRegistry.getInstance().getConfiguration().getProperty(VIRTUAL_HOSTS);
- if (virtualHosts != null)
- {
- if (virtualHosts instanceof Collection)
+ if (bindAddr.equals("wildcard"))
{
- int totalVHosts = ((Collection) virtualHosts).size();
- for (int vhost = 0; vhost < totalVHosts; vhost++)
- {
- setupVirtualHosts(configFile.getParent(), (String) ((List) virtualHosts).get(vhost));
- }
+ bindAddress = new InetSocketAddress(0).getAddress();
}
else
{
- setupVirtualHosts(configFile.getParent(), (String) virtualHosts);
+ bindAddress = InetAddress.getByAddress(parseIP(bindAddr));
}
- }
- bind(port, connectorConfig);
+ String hostName = bindAddress.getCanonicalHostName();
- }
- /**
- * Update the configuration data with the management port.
- * @param configuration
- * @param managementPort The string from the command line
- */
- private void updateManagementPort(Configuration configuration, String managementPort)
- {
- if (managementPort != null)
- {
- int mport;
- int defaultMPort = configuration.getInt(JMXManagedObjectRegistry.MANAGEMENT_PORT_CONFIG_PATH);
- try
+ String keystorePath = serverConfig.getKeystorePath();
+ String keystorePassword = serverConfig.getKeystorePassword();
+ String certType = serverConfig.getCertType();
+ SSLContextFactory sslFactory = null;
+
+ if (!serverConfig.getSSLOnly())
{
- mport = Integer.parseInt(managementPort);
- configuration.setProperty(JMXManagedObjectRegistry.MANAGEMENT_PORT_CONFIG_PATH, mport);
+
+ for(int port : ports)
+ {
+
+ NetworkDriver driver = new MINANetworkDriver();
+
+ Set<VERSION> supported = new HashSet<VERSION>(ALL_VERSIONS);
+
+ if(exclude_0_10.contains(port))
+ {
+ supported.remove(VERSION.v0_10);
+ }
+
+ if(exclude_0_9_1.contains(port))
+ {
+ supported.remove(VERSION.v0_9_1);
+ }
+ if(exclude_0_9.contains(port))
+ {
+ supported.remove(VERSION.v0_9);
+ }
+ if(exclude_0_8.contains(port))
+ {
+ supported.remove(VERSION.v0_8);
+ }
+
+ MultiVersionProtocolEngineFactory protocolEngineFactory =
+ new MultiVersionProtocolEngineFactory(hostName, supported);
+
+
+
+ driver.bind(port, new InetAddress[]{bindAddress}, protocolEngineFactory,
+ serverConfig.getNetworkConfiguration(), null);
+ ApplicationRegistry.getInstance().addAcceptor(new InetSocketAddress(bindAddress, port),
+ new QpidAcceptor(driver,"TCP"));
+ CurrentActor.get().message(BrokerMessages.BRK_LISTENING("TCP", port));
+
+ }
+
}
- catch (NumberFormatException e)
+
+ if (serverConfig.getEnableSSL())
{
- _logger.warn("Invalid management port: " + managementPort + " will use default:" + defaultMPort, e);
+ sslFactory = new SSLContextFactory(keystorePath, keystorePassword, certType);
+ NetworkDriver driver = new MINANetworkDriver();
+ driver.bind(serverConfig.getSSLPort(), new InetAddress[]{bindAddress},
+ new AMQProtocolEngineFactory(), serverConfig.getNetworkConfiguration(), sslFactory);
+ ApplicationRegistry.getInstance().addAcceptor(new InetSocketAddress(bindAddress, serverConfig.getSSLPort()),
+ new QpidAcceptor(driver,"TCP"));
+ CurrentActor.get().message(BrokerMessages.BRK_LISTENING("TCP/SSL", serverConfig.getSSLPort()));
}
- }
- }
- protected void setupVirtualHosts(String configFileParent, String configFilePath)
- throws ConfigurationException, AMQException, URLSyntaxException
- {
- String configVar = "${conf}";
+ //fixme qpid.AMQP should be using qpidproperties to get value
+ _brokerLogger.info("Qpid Broker Ready :" + QpidProperties.getReleaseVersion()
+ + " build: " + QpidProperties.getBuildVersion());
- if (configFilePath.startsWith(configVar))
- {
- configFilePath = configFileParent + configFilePath.substring(configVar.length());
- }
+ CurrentActor.get().message(BrokerMessages.BRK_READY());
- if (configFilePath.indexOf(".xml") != -1)
- {
- VirtualHostConfiguration vHostConfig = new VirtualHostConfiguration(configFilePath);
- vHostConfig.performBindings();
}
- else
+ finally
{
- // the virtualhosts value is a path. Search it for XML files.
+ // Startup is complete so remove the AR initialised Startup actor
+ CurrentActor.remove();
+ }
- File virtualHostDir = new File(configFilePath);
- String[] fileNames = virtualHostDir.list();
- for (int each = 0; each < fileNames.length; each++)
- {
- if (fileNames[each].endsWith(".xml"))
- {
- VirtualHostConfiguration vHostConfig =
- new VirtualHostConfiguration(configFilePath + "/" + fileNames[each]);
- vHostConfig.performBindings();
- }
- }
- }
}
- protected void bind(int port, ConnectorConfiguration connectorConfig) throws BindException
+ private void parsePortArray(Set<Integer> ports, String[] portStr)
+ throws InitException
{
- String bindAddr = commandLine.getOptionValue("b");
- if (bindAddr == null)
- {
- bindAddr = connectorConfig.bindAddress;
- }
-
- try
+ if(portStr != null)
{
- // IoAcceptor acceptor = new SocketAcceptor(connectorConfig.processors);
- IoAcceptor acceptor = connectorConfig.createAcceptor();
- SocketAcceptorConfig sconfig = (SocketAcceptorConfig) acceptor.getDefaultConfig();
- SocketSessionConfig sc = (SocketSessionConfig) sconfig.getSessionConfig();
-
- sc.setReceiveBufferSize(connectorConfig.socketReceiveBufferSize);
- sc.setSendBufferSize(connectorConfig.socketWriteBuferSize);
- sc.setTcpNoDelay(connectorConfig.tcpNoDelay);
-
- // if we do not use the executor pool threading model we get the default leader follower
- // implementation provided by MINA
- if (connectorConfig.enableExecutorPool)
+ for(int i = 0; i < portStr.length; i++)
{
- sconfig.setThreadModel(ReadWriteThreadModel.getInstance());
- }
-
- if (!connectorConfig.enableSSL || !connectorConfig.sslOnly)
- {
- AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler();
- InetSocketAddress bindAddress;
- if (bindAddr.equals("wildcard"))
+ try
{
- bindAddress = new InetSocketAddress(port);
+ ports.add(Integer.parseInt(portStr[i]));
}
- else
+ catch (NumberFormatException e)
{
- bindAddress = new InetSocketAddress(InetAddress.getByAddress(parseIP(bindAddr)), port);
+ throw new InitException("Invalid port: " + portStr[i], e);
}
-
- bind(acceptor, bindAddress, handler, sconfig);
-
- //fixme qpid.AMQP should be using qpidproperties to get value
- _brokerLogger.info("Qpid.AMQP listening on non-SSL address " + bindAddress);
}
+ }
+ }
- if (connectorConfig.enableSSL)
+ private void parsePortList(Set<Integer> output, List input)
+ throws InitException
+ {
+ if(input != null)
+ {
+ for(Object port : input)
{
- AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler();
try
{
-
- bind(acceptor, new InetSocketAddress(connectorConfig.sslPort), handler, sconfig);
-
- //fixme qpid.AMQP should be using qpidproperties to get value
- _brokerLogger.info("Qpid.AMQP listening on SSL port " + connectorConfig.sslPort);
-
+ output.add(Integer.parseInt(String.valueOf(port)));
}
- catch (IOException e)
+ catch (NumberFormatException e)
{
- _brokerLogger.error("Unable to listen on SSL port: " + e, e);
+ throw new InitException("Invalid port: " + port, e);
}
}
-
- //fixme qpid.AMQP should be using qpidproperties to get value
- _brokerLogger.info("Qpid Broker Ready :" + QpidProperties.getReleaseVersion()
- + " build: " + QpidProperties.getBuildVersion());
- }
- catch (Exception e)
- {
- _logger.error("Unable to bind service to registry: " + e, e);
- //fixme this need tidying up
- throw new BindException(e.getMessage());
}
}
/**
- * Ensure that any bound Acceptors are recorded in the registry so they can be closed later.
- *
- * @param acceptor
- * @param bindAddress
- * @param handler
- * @param sconfig
- *
- * @throws IOException from the acceptor.bind command
+ * Update the configuration data with the management port.
+ * @param configuration
+ * @param managementPort The string from the command line
*/
- private void bind(IoAcceptor acceptor, InetSocketAddress bindAddress, AMQPFastProtocolHandler handler, SocketAcceptorConfig sconfig) throws IOException
+ private void updateManagementPort(ServerConfiguration configuration, String managementPort)
{
- acceptor.bind(bindAddress, handler, sconfig);
-
- ApplicationRegistry.getInstance().addAcceptor(bindAddress, acceptor);
+ if (managementPort != null)
+ {
+ try
+ {
+ configuration.setJMXManagementPort(Integer.parseInt(managementPort));
+ }
+ catch (NumberFormatException e)
+ {
+ _logger.warn("Invalid management port: " + managementPort + " will use:" + configuration.getJMXManagementPort(), e);
+ }
+ }
}
public static void main(String[] args)
{
+ //if the -Dlog4j.configuration property has not been set, enable the init override
+ //to stop Log4J wondering off and picking up the first log4j.xml/properties file it
+ //finds from the classpath when we get the first Loggers
+ if(System.getProperty("log4j.configuration") == null)
+ {
+ System.setProperty("log4j.defaultInitOverride", "true");
+ }
+
+ //now that the override status is know, we can instantiate the Loggers
+ _logger = Logger.getLogger(Main.class);
+ _brokerLogger = Logger.getLogger("Qpid.Broker");
new Main(args);
}
@@ -507,40 +569,61 @@ public class Main
return ip;
}
- private void configureLogging(File logConfigFile, String logWatchConfig)
+ private void configureLogging(File logConfigFile, int logWatchTime) throws InitException, IOException
{
- int logWatchTime = 0;
- try
- {
- logWatchTime = Integer.parseInt(logWatchConfig);
- }
- catch (NumberFormatException e)
- {
- System.err.println("Log watch configuration value of " + logWatchConfig + " is invalid. Must be "
- + "a non-negative integer. Using default of zero (no watching configured");
- }
-
if (logConfigFile.exists() && logConfigFile.canRead())
{
+ CurrentActor.get().message(BrokerMessages.BRK_LOG_CONFIG(logConfigFile.getAbsolutePath()));
System.out.println("Configuring logger using configuration file " + logConfigFile.getAbsolutePath());
if (logWatchTime > 0)
{
System.out.println("log file " + logConfigFile.getAbsolutePath() + " will be checked for changes every "
+ logWatchTime + " seconds");
// log4j expects the watch interval in milliseconds
- DOMConfigurator.configureAndWatch(logConfigFile.getAbsolutePath(), logWatchTime * 1000);
+ try
+ {
+ QpidLog4JConfigurator.configureAndWatch(logConfigFile.getPath(), logWatchTime * 1000);
+ }
+ catch (Exception e)
+ {
+ throw new InitException(e.getMessage(),e);
+ }
}
else
{
- DOMConfigurator.configure(logConfigFile.getAbsolutePath());
+ try
+ {
+ QpidLog4JConfigurator.configure(logConfigFile.getPath());
+ }
+ catch (Exception e)
+ {
+ throw new InitException(e.getMessage(),e);
+ }
}
}
else
{
System.err.println("Logging configuration error: unable to read file " + logConfigFile.getAbsolutePath());
- System.err.println("Using basic log4j configuration");
- BasicConfigurator.configure();
+ System.err.println("Using the fallback internal log4j.properties configuration");
+
+ InputStream propsFile = this.getClass().getResourceAsStream("/log4j.properties");
+ if(propsFile == null)
+ {
+ throw new IOException("Unable to load the fallback internal log4j.properties configuration file");
+ }
+ else
+ {
+ Properties fallbackProps = new Properties();
+ fallbackProps.load(propsFile);
+ PropertyConfigurator.configure(fallbackProps);
+ }
}
}
+ private void configureLoggingManagementMBean(File logConfigFile, int logWatchTime) throws Exception
+ {
+ LoggingManagementMBean blm = new LoggingManagementMBean(logConfigFile.getPath(),logWatchTime);
+
+ blm.register();
+ }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java b/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java
deleted file mode 100644
index 3f1947d65a..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java
+++ /dev/null
@@ -1,79 +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.
- *
- */
-package org.apache.qpid.server;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.server.queue.AMQMessage;
-
-/**
- * Signals that a required delivery could not be made. This could be bacuse of the immediate flag being set and the
- * queue having no consumers, or the mandatory flag being set and the exchange having no valid bindings.
- *
- * <p/>The failed message is associated with this error condition, by taking a reference to it. This enables the
- * correct compensating action to be taken against the message, for example, bouncing it back to the sender.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Represent failure to deliver a message that must be delivered.
- * <tr><td> Associate the failed message with the error condition. <td> {@link AMQMessage}
- * </table>
- */
-public abstract class RequiredDeliveryException extends AMQException
-{
- private AMQMessage _amqMessage;
-
- public RequiredDeliveryException(String message, AMQMessage payload)
- {
- super(message);
-
- setMessage(payload);
- }
-
-
- public RequiredDeliveryException(String message)
- {
- super(message);
- }
-
- public void setMessage(final AMQMessage payload)
- {
-
- // Increment the reference as this message is in the routing phase
- // and so will have the ref decremented as routing fails.
- // we need to keep this message around so we can return it in the
- // handler. So increment here.
- _amqMessage = payload.takeReference();
-
- }
-
- public AMQMessage getAMQMessage()
- {
- return _amqMessage;
- }
-
- public AMQConstant getErrorCode()
- {
- return getReplyCode();
- }
-
- public abstract AMQConstant getReplyCode();
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java b/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java
deleted file mode 100644
index db3a05eb52..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java
+++ /dev/null
@@ -1,148 +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.
- *
- */
-package org.apache.qpid.server.ack;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.ArrayList;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.server.store.StoreContext;
-import org.apache.qpid.server.txn.TxnOp;
-import org.apache.qpid.server.queue.QueueEntry;
-
-/**
- * A TxnOp implementation for handling accumulated acks
- */
-public class TxAck implements TxnOp
-{
- private final UnacknowledgedMessageMap _map;
- private final Map<Long, QueueEntry> _unacked = new HashMap<Long,QueueEntry>();
- private List<Long> _individual;
- private long _deliveryTag;
- private boolean _multiple;
-
- public TxAck(UnacknowledgedMessageMap map)
- {
- _map = map;
- }
-
- public void update(long deliveryTag, boolean multiple)
- {
- _unacked.clear();
- if (!multiple)
- {
- if(_individual == null)
- {
- _individual = new ArrayList<Long>();
- }
- //have acked a single message that is not part of
- //the previously acked region so record
- //individually
- _individual.add(deliveryTag);//_multiple && !multiple
- }
- else if (deliveryTag > _deliveryTag)
- {
- //have simply moved the last acked message on a
- //bit
- _deliveryTag = deliveryTag;
- _multiple = true;
- }
- }
-
- public void consolidate()
- {
- if(_unacked.isEmpty())
- {
- //lookup all the unacked messages that have been acked in this transaction
- if (_multiple)
- {
- //get all the unacked messages for the accumulated
- //multiple acks
- _map.collect(_deliveryTag, true, _unacked);
- }
- if(_individual != null)
- {
- //get any unacked messages for individual acks outside the
- //range covered by multiple acks
- for (long tag : _individual)
- {
- if(_deliveryTag < tag)
- {
- _map.collect(tag, false, _unacked);
- }
- }
- }
- }
- }
-
- public boolean checkPersistent() throws AMQException
- {
- consolidate();
- //if any of the messages in unacked are persistent the txn
- //buffer must be marked as persistent:
- for (QueueEntry msg : _unacked.values())
- {
- if (msg.getMessage().isPersistent())
- {
- return true;
- }
- }
- return false;
- }
-
- public void prepare(StoreContext storeContext) throws AMQException
- {
- //make persistent changes, i.e. dequeue and decrementReference
- for (QueueEntry msg : _unacked.values())
- {
- //Message has been ack so discard it. This will dequeue and decrement the reference.
- msg.discard(storeContext);
-
- }
- }
-
- public void undoPrepare()
- {
- //decrementReference is annoyingly untransactional (due to
- //in memory counter) so if we failed in prepare for full
- //txn, this op will have to compensate by fixing the count
- //in memory (persistent changes will be rolled back by store)
- for (QueueEntry msg : _unacked.values())
- {
- msg.getMessage().takeReference();
- }
- }
-
- public void commit(StoreContext storeContext)
- {
- //remove the unacked messages from the channels map
- _map.remove(_unacked);
- }
-
- public void rollback(StoreContext storeContext)
- {
- }
-}
-
-
diff --git a/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java b/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java
index c80a96f967..3bad73d86d 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java
@@ -21,14 +21,12 @@
package org.apache.qpid.server.ack;
import java.util.Collection;
-import java.util.List;
import java.util.Set;
import java.util.Map;
import org.apache.qpid.AMQException;
-import org.apache.qpid.server.txn.TransactionalContext;
import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.store.StoreContext;
+
public interface UnacknowledgedMessageMap
{
@@ -50,18 +48,12 @@ public interface UnacknowledgedMessageMap
void collect(long deliveryTag, boolean multiple, Map<Long, QueueEntry> msgs);
- boolean contains(long deliveryTag) throws AMQException;
-
void remove(Map<Long,QueueEntry> msgs);
QueueEntry remove(long deliveryTag);
- public void drainTo(long deliveryTag, StoreContext storeContext) throws AMQException;
-
Collection<QueueEntry> cancelAllMessages();
- void acknowledgeMessage(long deliveryTag, boolean multiple, TransactionalContext txnContext) throws AMQException;
-
int size();
void clear();
@@ -75,7 +67,6 @@ public interface UnacknowledgedMessageMap
*/
Set<Long> getDeliveryTags();
- public long getUnacknowledgeBytes();
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java
index c567387662..d920d97c1a 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java
@@ -20,20 +20,13 @@
*/
package org.apache.qpid.server.ack;
-import org.apache.qpid.server.store.StoreContext;
import java.util.Collection;
-import java.util.Iterator;
import java.util.LinkedHashMap;
-import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.queue.AMQMessage;
import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.txn.TransactionalContext;
public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap
{
@@ -61,19 +54,15 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap
}
else
{
- msgs.put(deliveryTag, get(deliveryTag));
+ final QueueEntry entry = get(deliveryTag);
+ if(entry != null)
+ {
+ msgs.put(deliveryTag, entry);
+ }
}
}
- public boolean contains(long deliveryTag) throws AMQException
- {
- synchronized (_lock)
- {
- return _map.containsKey(deliveryTag);
- }
- }
-
public void remove(Map<Long,QueueEntry> msgs)
{
synchronized (_lock)
@@ -135,15 +124,6 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap
}
}
- public void acknowledgeMessage(long deliveryTag, boolean multiple, TransactionalContext txnContext)
- throws AMQException
- {
- synchronized (_lock)
- {
- txnContext.acknowledgeMessage(deliveryTag, _lastDeliveryTag, multiple, this);
- }
- }
-
public int size()
{
synchronized (_lock)
@@ -161,39 +141,6 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap
}
}
- public void drainTo(long deliveryTag, StoreContext storeContext) throws AMQException
-
- {
- synchronized (_lock)
- {
- Iterator<Map.Entry<Long, QueueEntry>> it = _map.entrySet().iterator();
- while (it.hasNext())
- {
- Map.Entry<Long, QueueEntry> unacked = it.next();
-
- if (unacked.getKey() > deliveryTag)
- {
- //This should not occur now.
- throw new AMQException("UnacknowledgedMessageMap is out of order:" + unacked.getKey() +
- " When deliveryTag is:" + deliveryTag + "ES:" + _map.entrySet().toString());
- }
-
- //Message has been ack so discard it. This will dequeue and decrement the reference.
- unacked.getValue().discard(storeContext);
-
- it.remove();
-
- _unackedSize -= unacked.getValue().getMessage().getSize();
-
-
- if (unacked.getKey() == deliveryTag)
- {
- break;
- }
- }
- }
- }
-
public QueueEntry get(long key)
{
synchronized (_lock)
@@ -225,8 +172,4 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap
}
}
- public long getUnacknowledgeBytes()
- {
- return _unackedSize;
- }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java b/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java
deleted file mode 100644
index 31c1b61a21..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java
+++ /dev/null
@@ -1,118 +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.
- *
- */
-package org.apache.qpid.server.configuration;
-
-import java.lang.reflect.Field;
-
-import org.apache.commons.configuration.Configuration;
-import org.apache.log4j.Logger;
-import org.apache.qpid.configuration.Configured;
-import org.apache.qpid.configuration.PropertyException;
-import org.apache.qpid.configuration.PropertyUtils;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-
-/**
- * This class contains utilities for populating classes automatically from values pulled from configuration
- * files.
- */
-public class Configurator
-{
- private static final Logger _logger = Logger.getLogger(Configurator.class);
-
-
- /**
- * Configure a given instance using the supplied configuration. Note that superclasses are <b>not</b>
- * currently configured but this could easily be added if required.
- * @param instance the instance to configure
- * @param config the configuration to use to configure the object
- */
- public static void configure(Object instance, Configuration config)
- {
-
- for (Field f : instance.getClass().getDeclaredFields())
- {
- Configured annotation = f.getAnnotation(Configured.class);
- if (annotation != null)
- {
- setValueInField(f, instance, config, annotation);
- }
- }
- }
-
-
-
- /**
- * Configure a given instance using the application configuration. Note that superclasses are <b>not</b>
- * currently configured but this could easily be added if required.
- * @param instance the instance to configure
- */
- public static void configure(Object instance)
- {
- configure(instance, ApplicationRegistry.getInstance().getConfiguration());
- }
-
- private static void setValueInField(Field f, Object instance, Configuration config, Configured annotation)
- {
- Class fieldClass = f.getType();
- String configPath = annotation.path();
- try
- {
- if (fieldClass == String.class)
- {
- String val = config.getString(configPath, annotation.defaultValue());
- val = PropertyUtils.replaceProperties(val);
- f.set(instance, val);
- }
- else if (fieldClass == int.class)
- {
- int val = config.getInt(configPath, Integer.parseInt(annotation.defaultValue()));
- f.setInt(instance, val);
- }
- else if (fieldClass == long.class)
- {
- long val = config.getLong(configPath, Long.parseLong(annotation.defaultValue()));
- f.setLong(instance, val);
- }
- else if (fieldClass == double.class)
- {
- double val = config.getDouble(configPath, Double.parseDouble(annotation.defaultValue()));
- f.setDouble(instance, val);
- }
- else if (fieldClass == boolean.class)
- {
- boolean val = config.getBoolean(configPath, Boolean.parseBoolean(annotation.defaultValue()));
- f.setBoolean(instance, val);
- }
- else
- {
- _logger.error("Unsupported field type " + fieldClass + " for " + f + " IGNORING configured value");
- }
- }
- catch (PropertyException e)
- {
- _logger.error("Unable to expand property: " + e + " INGORING field " + f, e);
- }
- catch (IllegalAccessException e)
- {
- _logger.error("Unable to access field " + f + " IGNORING configured value");
- }
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfiguration.java b/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfiguration.java
new file mode 100644
index 0000000000..c7cf0c0892
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfiguration.java
@@ -0,0 +1,58 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.configuration;
+
+import org.apache.commons.configuration.Configuration;
+
+
+public class ExchangeConfiguration
+{
+
+ private Configuration _config;
+ private String _name;
+
+ public ExchangeConfiguration(String exchName, Configuration subset)
+ {
+ _name = exchName;
+ _config = subset;
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public String getType()
+ {
+ return _config.getString("type","direct");
+ }
+
+ public boolean getDurable()
+ {
+ return _config.getBoolean("durable", false);
+ }
+
+ public boolean getAutoDelete()
+ {
+ return _config.getBoolean("autodelete",false);
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java
new file mode 100644
index 0000000000..5c73e353de
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java
@@ -0,0 +1,121 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.configuration;
+
+import java.util.List;
+
+import org.apache.commons.configuration.Configuration;
+
+public class QueueConfiguration
+{
+
+ private Configuration _config;
+ private String _name;
+ private VirtualHostConfiguration _vHostConfig;
+
+ public QueueConfiguration(String name, Configuration config, VirtualHostConfiguration virtualHostConfiguration)
+ {
+ _vHostConfig = virtualHostConfiguration;
+ _config = config;
+ _name = name;
+ }
+
+ public VirtualHostConfiguration getVirtualHostConfiguration()
+ {
+ return _vHostConfig;
+ }
+
+ public boolean getDurable()
+ {
+ return _config.getBoolean("durable" ,false);
+ }
+
+ public boolean getAutoDelete()
+ {
+ return _config.getBoolean("autodelete", false);
+ }
+
+ public String getOwner()
+ {
+ return _config.getString("owner", null);
+ }
+
+ public boolean getPriority()
+ {
+ return _config.getBoolean("priority", false);
+ }
+
+ public int getPriorities()
+ {
+ return _config.getInt("priorities", -1);
+ }
+
+ public String getExchange()
+ {
+ return _config.getString("exchange", null);
+ }
+
+ public List getRoutingKeys()
+ {
+ return _config.getList("routingKey");
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public int getMaximumMessageAge()
+ {
+ return _config.getInt("maximumMessageAge", _vHostConfig.getMaximumMessageAge());
+ }
+
+ public long getMaximumQueueDepth()
+ {
+ return _config.getLong("maximumQueueDepth", _vHostConfig.getMaximumQueueDepth());
+ }
+
+ public long getMaximumMessageSize()
+ {
+ return _config.getLong("maximumMessageSize", _vHostConfig.getMaximumMessageSize());
+ }
+
+ public long getMaximumMessageCount()
+ {
+ return _config.getLong("maximumMessageCount", _vHostConfig.getMaximumMessageCount());
+ }
+
+ public long getMinimumAlertRepeatGap()
+ {
+ return _config.getLong("minimumAlertRepeatGap", _vHostConfig.getMinimumAlertRepeatGap());
+ }
+
+ public long getCapacity()
+ {
+ return _config.getLong("capacity", _vHostConfig.getCapacity());
+ }
+
+ public long getFlowResumeCapacity()
+ {
+ return _config.getLong("flowResumeCapacity", _vHostConfig.getFlowResumeCapacity());
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/configuration/SecurityConfiguration.java b/java/broker/src/main/java/org/apache/qpid/server/configuration/SecurityConfiguration.java
new file mode 100644
index 0000000000..5d080f8df1
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/configuration/SecurityConfiguration.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+
+package org.apache.qpid.server.configuration;
+
+import org.apache.commons.configuration.Configuration;
+
+public class SecurityConfiguration
+{
+
+ private Configuration _conf;
+
+ public SecurityConfiguration(Configuration configuration)
+ {
+ _conf = configuration;
+ }
+
+ public Configuration getConfiguration()
+ {
+ return _conf;
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
new file mode 100644
index 0000000000..879eb7c9e6
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
@@ -0,0 +1,701 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.configuration;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Locale;
+import java.util.Collections;
+import java.util.Map.Entry;
+
+import org.apache.commons.configuration.CompositeConfiguration;
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.ConfigurationFactory;
+import org.apache.commons.configuration.SystemConfiguration;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.qpid.server.configuration.management.ConfigurationManagementMBean;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
+import org.apache.qpid.transport.NetworkDriverConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import sun.misc.Signal;
+import sun.misc.SignalHandler;
+
+public class ServerConfiguration implements SignalHandler
+{
+
+ private Configuration _config;
+
+ // Default Configuration values
+ //todo make these all public, to make validation of configuration easier.
+ public static final int DEFAULT_BUFFER_READ_LIMIT_SIZE = 262144;
+ public static final int DEFAULT_BUFFER_WRITE_LIMIT_SIZE = 262144;
+ public static final boolean DEFAULT_BROKER_CONNECTOR_PROTECTIO_ENABLED = false;
+ public static final String DEFAULT_STATUS_UPDATES = "on";
+ public static final String SECURITY_CONFIG_RELOADED = "SECURITY CONFIGURATION RELOADED";
+
+ private static final int DEFAULT_FRAME_SIZE = 65536;
+ private static final int DEFAULT_PORT = 5672;
+ private static final int DEFAUL_SSL_PORT = 8672;
+ private static final long DEFAULT_HOUSEKEEPING_PERIOD = 30000L;
+ private static final int DEFAULT_JMXPORT = 8999;
+
+ private static int _jmxPort = DEFAULT_JMXPORT;
+
+ private Map<String, VirtualHostConfiguration> _virtualHosts = new HashMap<String, VirtualHostConfiguration>();
+ private SecurityConfiguration _securityConfiguration = null;
+
+ private File _configFile;
+
+ private Logger _log = LoggerFactory.getLogger(this.getClass());
+
+ private ConfigurationManagementMBean _mbean;
+
+
+ // Map of environment variables to config items
+ private static final Map<String, String> envVarMap = new HashMap<String, String>();
+
+ // Configuration values to be read from the configuration file
+ //todo Move all properties to static values to ensure system testing can be performed.
+ public static final String CONNECTOR_PROTECTIO_ENABLED = "connector.protectio.enabled";
+ public static final String CONNECTOR_PROTECTIO_READ_BUFFER_LIMIT_SIZE = "connector.protectio.readBufferLimitSize";
+ public static final String CONNECTOR_PROTECTIO_WRITE_BUFFER_LIMIT_SIZE = "connector.protectio.writeBufferLimitSize";
+ public static final String STATUS_UPDATES = "status-updates";
+ public static final String ADVANCED_LOCALE = "advanced.locale";
+
+ {
+ envVarMap.put("QPID_PORT", "connector.port");
+ envVarMap.put("QPID_ENABLEDIRECTBUFFERS", "advanced.enableDirectBuffers");
+ envVarMap.put("QPID_SSLPORT", "connector.ssl.port");
+ envVarMap.put("QPID_NIO", "connector.qpidnio");
+ envVarMap.put("QPID_WRITEBIASED", "advanced.useWriteBiasedPool");
+ envVarMap.put("QPID_JMXPORT", "management.jmxport");
+ envVarMap.put("QPID_FRAMESIZE", "advanced.framesize");
+ envVarMap.put("QPID_MSGAUTH", "security.msg-auth");
+ envVarMap.put("QPID_AUTOREGISTER", "auto_register");
+ envVarMap.put("QPID_MANAGEMENTENABLED", "management.enabled");
+ envVarMap.put("QPID_HEARTBEATDELAY", "heartbeat.delay");
+ envVarMap.put("QPID_HEARTBEATTIMEOUTFACTOR", "heartbeat.timeoutFactor");
+ envVarMap.put("QPID_MAXIMUMMESSAGEAGE", "maximumMessageAge");
+ envVarMap.put("QPID_MAXIMUMMESSAGECOUNT", "maximumMessageCount");
+ envVarMap.put("QPID_MAXIMUMQUEUEDEPTH", "maximumQueueDepth");
+ envVarMap.put("QPID_MAXIMUMMESSAGESIZE", "maximumMessageSize");
+ envVarMap.put("QPID_MINIMUMALERTREPEATGAP", "minimumAlertRepeatGap");
+ envVarMap.put("QPID_QUEUECAPACITY", "capacity");
+ envVarMap.put("QPID_FLOWRESUMECAPACITY", "flowResumeCapacity");
+ envVarMap.put("QPID_SOCKETRECEIVEBUFFER", "connector.socketReceiveBuffer");
+ envVarMap.put("QPID_SOCKETWRITEBUFFER", "connector.socketWriteBuffer");
+ envVarMap.put("QPID_TCPNODELAY", "connector.tcpNoDelay");
+ envVarMap.put("QPID_ENABLEPOOLEDALLOCATOR", "advanced.enablePooledAllocator");
+ envVarMap.put("QPID_STATUS-UPDATES", "status-updates");
+ }
+
+ public ServerConfiguration(File configurationURL) throws ConfigurationException
+ {
+ this(parseConfig(configurationURL));
+ _configFile = configurationURL;
+ try
+ {
+ Signal sig = new sun.misc.Signal("HUP");
+ sun.misc.Signal.handle(sig, this);
+ }
+ catch (IllegalArgumentException e)
+ {
+ // We're on something that doesn't handle SIGHUP, how sad, Windows.
+ }
+ }
+
+ public ServerConfiguration(Configuration conf) throws ConfigurationException
+ {
+ setConfig(conf);
+
+ substituteEnvironmentVariables();
+
+ _jmxPort = getConfig().getInt("management.jmxport", 8999);
+ _securityConfiguration = new SecurityConfiguration(conf.subset("security"));
+
+ setupVirtualHosts(conf);
+
+ }
+
+ private void setupVirtualHosts(Configuration conf) throws ConfigurationException
+ {
+ List vhosts = conf.getList("virtualhosts");
+ Iterator i = vhosts.iterator();
+ while (i.hasNext())
+ {
+ Object thing = i.next();
+ if (thing instanceof String)
+ {
+ //Open the Virtualhost.xml file and copy values in to main config
+ XMLConfiguration vhostConfiguration = new XMLConfiguration((String) thing);
+ Iterator keys = vhostConfiguration.getKeys();
+ while (keys.hasNext())
+ {
+ String key = (String) keys.next();
+ conf.setProperty("virtualhosts." + key, vhostConfiguration.getProperty(key));
+ }
+ }
+ }
+
+ List hosts = conf.getList("virtualhosts.virtualhost.name");
+ for (int j = 0; j < hosts.size(); j++)
+ {
+ String name = (String) hosts.get(j);
+ // Add the keys of the virtual host to the main config then bail out
+
+ VirtualHostConfiguration vhostConfig = new VirtualHostConfiguration(name, conf.subset("virtualhosts.virtualhost." + name));
+ _virtualHosts.put(vhostConfig.getName(), vhostConfig);
+ }
+
+ }
+
+ private void substituteEnvironmentVariables()
+ {
+ for (Entry<String, String> var : envVarMap.entrySet())
+ {
+ String val = System.getenv(var.getKey());
+ if (val != null)
+ {
+ getConfig().setProperty(var.getValue(), val);
+ }
+ }
+ }
+
+ private final static Configuration parseConfig(File file) throws ConfigurationException
+ {
+ ConfigurationFactory factory = new ConfigurationFactory();
+ factory.setConfigurationFileName(file.getAbsolutePath());
+ Configuration conf = factory.getConfiguration();
+ Iterator keys = conf.getKeys();
+ if (!keys.hasNext())
+ {
+ keys = null;
+ conf = flatConfig(file);
+ }
+ return conf;
+ }
+
+ /**
+ * Check the configuration file to see if status updates are enabled.
+ * @return true if status updates are enabled
+ */
+ public boolean getStatusUpdatesEnabled()
+ {
+ // Retrieve the setting from configuration but default to on.
+ String value = getConfig().getString(STATUS_UPDATES, DEFAULT_STATUS_UPDATES);
+
+ return value.equalsIgnoreCase("on");
+ }
+
+ /**
+ * The currently defined {@see Locale} for this broker
+ * @return the configuration defined locale
+ */
+ public Locale getLocale()
+ {
+
+ String localeString = getConfig().getString(ADVANCED_LOCALE);
+ // Expecting locale of format langauge_country_variant
+
+ // If the configuration does not have a defined locale use the JVM default
+ if (localeString == null)
+ {
+ return Locale.getDefault();
+ }
+
+ String[] parts = localeString.split("_");
+
+ Locale locale;
+ switch (parts.length)
+ {
+ case 1:
+ locale = new Locale(localeString);
+ break;
+ case 2:
+ locale = new Locale(parts[0], parts[1]);
+ break;
+ default:
+ String variant = parts[2];
+ // If we have a variant such as the Java doc suggests for Spanish
+ // Traditional_WIN we may end up with more than 3 parts on a
+ // split with '_'. So we should recombine the variant.
+ if (parts.length > 3)
+ {
+ for (int index = 3; index < parts.length; index++)
+ {
+ variant = variant + "_" + parts[index];
+ }
+ }
+
+ locale = new Locale(parts[0], parts[1], variant);
+ }
+
+ return locale;
+ }
+
+ // Our configuration class needs to make the interpolate method
+ // public so it can be called below from the config method.
+ public static class MyConfiguration extends CompositeConfiguration
+ {
+ public String interpolate(String obj)
+ {
+ return super.interpolate(obj);
+ }
+ }
+
+ public final static Configuration flatConfig(File file) throws ConfigurationException
+ {
+ // We have to override the interpolate methods so that
+ // interpolation takes place accross the entirety of the
+ // composite configuration. Without doing this each
+ // configuration object only interpolates variables defined
+ // inside itself.
+ final MyConfiguration conf = new MyConfiguration();
+ conf.addConfiguration(new SystemConfiguration()
+ {
+ protected String interpolate(String o)
+ {
+ return conf.interpolate(o);
+ }
+ });
+ conf.addConfiguration(new XMLConfiguration(file)
+ {
+ protected String interpolate(String o)
+ {
+ return conf.interpolate(o);
+ }
+ });
+ return conf;
+ }
+
+ public void handle(Signal arg0)
+ {
+ try
+ {
+ reparseConfigFileSecuritySections();
+ }
+ catch (ConfigurationException e)
+ {
+ _log.error("Could not reload configuration file security sections", e);
+ }
+ }
+
+ public void reparseConfigFileSecuritySections() throws ConfigurationException
+ {
+ if (_configFile != null)
+ {
+ Configuration newConfig = parseConfig(_configFile);
+ _securityConfiguration = new SecurityConfiguration(newConfig.subset("security"));
+
+ VirtualHostRegistry vhostRegistry = ApplicationRegistry.getInstance().getVirtualHostRegistry();
+ for (String hostname : _virtualHosts.keySet())
+ {
+ VirtualHost vhost = vhostRegistry.getVirtualHost(hostname);
+ SecurityConfiguration hostSecurityConfig = new SecurityConfiguration(newConfig.subset("virtualhosts.virtualhost."+hostname+".security"));
+ vhost.getAccessManager().configureGlobalPlugins(_securityConfiguration);
+ vhost.getAccessManager().configureHostPlugins(hostSecurityConfig);
+ }
+
+ _log.warn(SECURITY_CONFIG_RELOADED);
+ }
+ }
+
+ public void setConfig(Configuration _config)
+ {
+ this._config = _config;
+ }
+
+ public Configuration getConfig()
+ {
+ return _config;
+ }
+
+ public String getQpidWork()
+ {
+ return System.getProperty("QPID_WORK", System.getProperty("java.io.tmpdir"));
+ }
+
+ public void setJMXManagementPort(int mport)
+ {
+ _jmxPort = mport;
+ }
+
+ public int getJMXManagementPort()
+ {
+ return _jmxPort;
+ }
+
+ public boolean getPlatformMbeanserver()
+ {
+ return getConfig().getBoolean("management.platform-mbeanserver", true);
+ }
+
+ public String[] getVirtualHosts()
+ {
+ return _virtualHosts.keySet().toArray(new String[_virtualHosts.size()]);
+ }
+
+ public String getPluginDirectory()
+ {
+ return getConfig().getString("plugin-directory");
+ }
+
+ public VirtualHostConfiguration getVirtualHostConfig(String name)
+ {
+ return _virtualHosts.get(name);
+ }
+
+ public List<String> getPrincipalDatabaseNames()
+ {
+ return getConfig().getList("security.principal-databases.principal-database.name");
+ }
+
+ public List<String> getPrincipalDatabaseClass()
+ {
+ return getConfig().getList("security.principal-databases.principal-database.class");
+ }
+
+ public List<String> getPrincipalDatabaseAttributeNames(int index)
+ {
+ String name = "security.principal-databases.principal-database(" + index + ")." + "attributes.attribute.name";
+ return getConfig().getList(name);
+ }
+
+ public List<String> getPrincipalDatabaseAttributeValues(int index)
+ {
+ String name = "security.principal-databases.principal-database(" + index + ")." + "attributes.attribute.value";
+ return getConfig().getList(name);
+ }
+
+ public List<String> getManagementPrincipalDBs()
+ {
+ return getConfig().getList("security.jmx.principal-database");
+ }
+
+ public List<String> getManagementAccessList()
+ {
+ return getConfig().getList("security.jmx.access");
+ }
+
+ public int getFrameSize()
+ {
+ return getConfig().getInt("advanced.framesize", DEFAULT_FRAME_SIZE);
+ }
+
+ public boolean getProtectIOEnabled()
+ {
+ return getConfig().getBoolean(CONNECTOR_PROTECTIO_ENABLED, DEFAULT_BROKER_CONNECTOR_PROTECTIO_ENABLED);
+ }
+
+ public int getBufferReadLimit()
+ {
+ return getConfig().getInt(CONNECTOR_PROTECTIO_READ_BUFFER_LIMIT_SIZE, DEFAULT_BUFFER_READ_LIMIT_SIZE);
+ }
+
+ public int getBufferWriteLimit()
+ {
+ return getConfig().getInt(CONNECTOR_PROTECTIO_WRITE_BUFFER_LIMIT_SIZE, DEFAULT_BUFFER_WRITE_LIMIT_SIZE);
+ }
+
+ public boolean getSynchedClocks()
+ {
+ return getConfig().getBoolean("advanced.synced-clocks", false);
+ }
+
+ public boolean getMsgAuth()
+ {
+ return getConfig().getBoolean("security.msg-auth", false);
+ }
+
+ public String getJMXPrincipalDatabase()
+ {
+ return getConfig().getString("security.jmx.principal-database");
+ }
+
+ public String getManagementKeyStorePath()
+ {
+ return getConfig().getString("management.ssl.keyStorePath", null);
+ }
+
+ public boolean getManagementSSLEnabled()
+ {
+ return getConfig().getBoolean("management.ssl.enabled", true);
+ }
+
+ public String getManagementKeyStorePassword()
+ {
+ return getConfig().getString("management.ssl.keyStorePassword");
+ }
+
+ public SecurityConfiguration getSecurityConfiguration()
+ {
+ return _securityConfiguration;
+ }
+
+ public boolean getQueueAutoRegister()
+ {
+ return getConfig().getBoolean("queue.auto_register", true);
+ }
+
+ public boolean getManagementEnabled()
+ {
+ return getConfig().getBoolean("management.enabled", true);
+ }
+
+ public void setManagementEnabled(boolean enabled)
+ {
+ getConfig().setProperty("management.enabled", enabled);
+ }
+
+ public int getHeartBeatDelay()
+ {
+ return getConfig().getInt("heartbeat.delay", 5);
+ }
+
+ public double getHeartBeatTimeout()
+ {
+ return getConfig().getDouble("heartbeat.timeoutFactor", 2.0);
+ }
+
+ public int getDeliveryPoolSize()
+ {
+ return getConfig().getInt("delivery.poolsize", 0);
+ }
+
+ public long getMaximumMessageAge()
+ {
+ return getConfig().getLong("maximumMessageAge", 0);
+ }
+
+ public long getMaximumMessageCount()
+ {
+ return getConfig().getLong("maximumMessageCount", 0);
+ }
+
+ public long getMaximumQueueDepth()
+ {
+ return getConfig().getLong("maximumQueueDepth", 0);
+ }
+
+ public long getMaximumMessageSize()
+ {
+ return getConfig().getLong("maximumMessageSize", 0);
+ }
+
+ public long getMinimumAlertRepeatGap()
+ {
+ return getConfig().getLong("minimumAlertRepeatGap", 0);
+ }
+
+ public long getCapacity()
+ {
+ return getConfig().getLong("capacity", 0L);
+ }
+
+ public long getFlowResumeCapacity()
+ {
+ return getConfig().getLong("flowResumeCapacity", getCapacity());
+ }
+
+ public int getProcessors()
+ {
+ return getConfig().getInt("connector.processors", 4);
+ }
+
+ public List getPorts()
+ {
+ return getConfig().getList("connector.port", Collections.singletonList(DEFAULT_PORT));
+ }
+
+ public List getPortExclude010()
+ {
+ return getConfig().getList("connector.non010port", Collections.EMPTY_LIST);
+ }
+
+ public List getPortExclude091()
+ {
+ return getConfig().getList("connector.non091port", Collections.EMPTY_LIST);
+ }
+
+ public List getPortExclude09()
+ {
+ return getConfig().getList("connector.non09port", Collections.EMPTY_LIST);
+ }
+
+ public List getPortExclude08()
+ {
+ return getConfig().getList("connector.non08port", Collections.EMPTY_LIST);
+ }
+
+
+ public String getBind()
+ {
+ return getConfig().getString("connector.bind", "wildcard");
+ }
+
+ public int getReceiveBufferSize()
+ {
+ return getConfig().getInt("connector.socketReceiveBuffer", 32767);
+ }
+
+ public int getWriteBufferSize()
+ {
+ return getConfig().getInt("connector.socketWriteBuffer", 32767);
+ }
+
+ public boolean getTcpNoDelay()
+ {
+ return getConfig().getBoolean("connector.tcpNoDelay", true);
+ }
+
+ public boolean getEnableExecutorPool()
+ {
+ return getConfig().getBoolean("advanced.filterchain[@enableExecutorPool]", false);
+ }
+
+ public boolean getEnablePooledAllocator()
+ {
+ return getConfig().getBoolean("advanced.enablePooledAllocator", false);
+ }
+
+ public boolean getEnableDirectBuffers()
+ {
+ return getConfig().getBoolean("advanced.enableDirectBuffers", false);
+ }
+
+ public boolean getEnableSSL()
+ {
+ return getConfig().getBoolean("connector.ssl.enabled", false);
+ }
+
+ public boolean getSSLOnly()
+ {
+ return getConfig().getBoolean("connector.ssl.sslOnly", false);
+ }
+
+ public int getSSLPort()
+ {
+ return getConfig().getInt("connector.ssl.port", DEFAUL_SSL_PORT);
+ }
+
+ public String getKeystorePath()
+ {
+ return getConfig().getString("connector.ssl.keystorePath", "none");
+ }
+
+ public String getKeystorePassword()
+ {
+ return getConfig().getString("connector.ssl.keystorePassword", "none");
+ }
+
+ public String getCertType()
+ {
+ return getConfig().getString("connector.ssl.certType", "SunX509");
+ }
+
+ public boolean getQpidNIO()
+ {
+ return getConfig().getBoolean("connector.qpidnio", false);
+ }
+
+ public boolean getUseBiasedWrites()
+ {
+ return getConfig().getBoolean("advanced.useWriteBiasedPool", false);
+ }
+
+ public String getDefaultVirtualHost()
+ {
+ return getConfig().getString("virtualhosts.default");
+ }
+
+ public void setHousekeepingExpiredMessageCheckPeriod(long value)
+ {
+ getConfig().setProperty("housekeeping.expiredMessageCheckPeriod", value);
+ }
+
+ public long getHousekeepingCheckPeriod()
+ {
+ return getConfig().getLong("housekeeping.checkPeriod",
+ getConfig().getLong("housekeeping.expiredMessageCheckPeriod",
+ DEFAULT_HOUSEKEEPING_PERIOD));
+ }
+
+ public NetworkDriverConfiguration getNetworkConfiguration()
+ {
+ return new NetworkDriverConfiguration()
+ {
+
+ public Integer getTrafficClass()
+ {
+ return null;
+ }
+
+ public Boolean getTcpNoDelay()
+ {
+ // Can't call parent getTcpNoDelay since it just calls this one
+ return getConfig().getBoolean("connector.tcpNoDelay", true);
+ }
+
+ public Integer getSoTimeout()
+ {
+ return null;
+ }
+
+ public Integer getSoLinger()
+ {
+ return null;
+ }
+
+ public Integer getSendBufferSize()
+ {
+ return getBufferWriteLimit();
+ }
+
+ public Boolean getReuseAddress()
+ {
+ return null;
+ }
+
+ public Integer getReceiveBufferSize()
+ {
+ return getBufferReadLimit();
+ }
+
+ public Boolean getOOBInline()
+ {
+ return null;
+ }
+
+ public Boolean getKeepAlive()
+ {
+ return null;
+ }
+ };
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java
index bd3e5b1f72..6c72025ec2 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java
@@ -20,263 +20,161 @@
*/
package org.apache.qpid.server.configuration;
-import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
-import org.apache.commons.configuration.XMLConfiguration;
-import org.apache.log4j.Logger;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.exchange.ExchangeRegistry;
-import org.apache.qpid.server.exchange.ExchangeFactory;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.QueueRegistry;
-import org.apache.qpid.server.queue.AMQQueueFactory;
+import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.store.MemoryMessageStore;
public class VirtualHostConfiguration
{
- private static final Logger _logger = Logger.getLogger(VirtualHostConfiguration.class);
+ private Configuration _config;
+ private String _name;
+ private Map<String, QueueConfiguration> _queues = new HashMap<String, QueueConfiguration>();
+ private Map<String, ExchangeConfiguration> _exchanges = new HashMap<String, ExchangeConfiguration>();
+
+ public VirtualHostConfiguration(String name, Configuration config) throws ConfigurationException
+ {
+ _config = config;
+ _name = name;
+ Iterator i = _config.getList("queues.queue.name").iterator();
+
+ while (i.hasNext())
+ {
+ String queueName = (String) i.next();
+ CompositeConfiguration mungedConf = new CompositeConfiguration();
+ mungedConf.addConfiguration(_config.subset("queues.queue." + queueName));
+ mungedConf.addConfiguration(_config.subset("queues"));
+ _queues.put(queueName, new QueueConfiguration(queueName, mungedConf, this));
+ }
- private static XMLConfiguration _config;
+ i = _config.getList("exchanges.exchange.name").iterator();
+ int count = 0;
+ while (i.hasNext())
+ {
+ CompositeConfiguration mungedConf = new CompositeConfiguration();
+ mungedConf.addConfiguration(config.subset("exchanges.exchange(" + count++ + ")"));
+ mungedConf.addConfiguration(_config.subset("exchanges"));
+ String exchName = (String) i.next();
+ _exchanges.put(exchName, new ExchangeConfiguration(exchName, mungedConf));
+ }
- private static final String VIRTUALHOST_PROPERTY_BASE = "virtualhost.";
+ }
+ public String getName()
+ {
+ return _name;
+ }
- public VirtualHostConfiguration(String configFile) throws ConfigurationException
+ public long getHousekeepingExpiredMessageCheckPeriod()
+ {
+ return _config.getLong("housekeeping.expiredMessageCheckPeriod", ApplicationRegistry.getInstance().getConfiguration().getHousekeepingCheckPeriod());
+ }
+
+ public String getAuthenticationDatabase()
+ {
+ return _config.getString("security.authentication.name");
+ }
+
+ public List getCustomExchanges()
+ {
+ return _config.getList("custom-exchanges.class-name");
+ }
+
+ public SecurityConfiguration getSecurityConfiguration()
+ {
+ return new SecurityConfiguration(_config.subset("security"));
+ }
+
+ public Configuration getStoreConfiguration()
+ {
+ return _config.subset("store");
+ }
+
+ public String getMessageStoreClass()
+ {
+ return _config.getString("store.class", MemoryMessageStore.class.getName());
+ }
+
+ public List getExchanges()
+ {
+ return _config.getList("exchanges.exchange.name");
+ }
+
+ public String[] getQueueNames()
+ {
+ return _queues.keySet().toArray(new String[_queues.size()]);
+ }
+
+ public ExchangeConfiguration getExchangeConfiguration(String exchangeName)
{
- _logger.info("Loading Config file:" + configFile);
-
- _config = new XMLConfiguration(configFile);
-
+ return _exchanges.get(exchangeName);
}
-
-
- private void configureVirtualHost(String virtualHostName, Configuration configuration) throws ConfigurationException, AMQException
+ public QueueConfiguration getQueueConfiguration(String queueName)
{
- _logger.debug("Loding configuration for virtaulhost: "+virtualHostName);
-
-
- VirtualHost virtualHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost(virtualHostName);
-
-
-
- if(virtualHost == null)
+ // We might be asked for the config for a queue we don't know about,
+ // such as one that's been dynamically created. Those get the defaults by default.
+ if (_queues.containsKey(queueName))
{
- throw new ConfigurationException("Unknown virtual host: " + virtualHostName);
- }
-
- List exchangeNames = configuration.getList("exchanges.exchange.name");
-
- for(Object exchangeNameObj : exchangeNames)
- {
- String exchangeName = String.valueOf(exchangeNameObj);
- configureExchange(virtualHost, exchangeName, configuration);
- }
-
-
- List queueNames = configuration.getList("queues.queue.name");
-
- for(Object queueNameObj : queueNames)
+ return _queues.get(queueName);
+ }
+ else
{
- String queueName = String.valueOf(queueNameObj);
- configureQueue(virtualHost, queueName, configuration);
+ return new QueueConfiguration(queueName, new PropertiesConfiguration(), this);
}
-
}
- private void configureExchange(VirtualHost virtualHost, String exchangeNameString, Configuration configuration) throws AMQException
+ public long getMemoryUsageMaximum()
{
-
- CompositeConfiguration exchangeConfiguration = new CompositeConfiguration();
-
- exchangeConfiguration.addConfiguration(configuration.subset("exchanges.exchange."+ exchangeNameString));
- exchangeConfiguration.addConfiguration(configuration.subset("exchanges"));
-
- QueueRegistry queueRegistry = virtualHost.getQueueRegistry();
- MessageStore messageStore = virtualHost.getMessageStore();
- ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry();
- ExchangeFactory exchangeFactory = virtualHost.getExchangeFactory();
-
- AMQShortString exchangeName = new AMQShortString(exchangeNameString);
-
-
- Exchange exchange;
-
-
-
- synchronized (exchangeRegistry)
- {
- exchange = exchangeRegistry.getExchange(exchangeName);
- if(exchange == null)
- {
-
- AMQShortString type = new AMQShortString(exchangeConfiguration.getString("type","direct"));
- boolean durable = exchangeConfiguration.getBoolean("durable",false);
- boolean autodelete = exchangeConfiguration.getBoolean("autodelete",false);
-
- Exchange newExchange = exchangeFactory.createExchange(exchangeName,type,durable,autodelete,0);
- exchangeRegistry.registerExchange(newExchange);
- }
-
- }
+ return _config.getLong("queues.maximumMemoryUsage", 0);
}
- public static CompositeConfiguration getDefaultQueueConfiguration(AMQQueue queue)
+ public long getMemoryUsageMinimum()
{
- CompositeConfiguration queueConfiguration = null;
- if (_config == null)
- return null;
-
- Configuration vHostConfiguration = _config.subset(VIRTUALHOST_PROPERTY_BASE + queue.getVirtualHost().getName());
-
- if (vHostConfiguration == null)
- return null;
-
- Configuration defaultQueueConfiguration = vHostConfiguration.subset("queues");
- if (defaultQueueConfiguration != null)
- {
- queueConfiguration = new CompositeConfiguration();
- queueConfiguration.addConfiguration(defaultQueueConfiguration);
- }
-
- return queueConfiguration;
+ return _config.getLong("queues.minimumMemoryUsage", 0);
}
-
- private void configureQueue(VirtualHost virtualHost, String queueNameString, Configuration configuration) throws AMQException, ConfigurationException
+
+ public int getMaximumMessageAge()
{
- CompositeConfiguration queueConfiguration = new CompositeConfiguration();
-
- queueConfiguration.addConfiguration(configuration.subset("queues.queue."+ queueNameString));
- queueConfiguration.addConfiguration(configuration.subset("queues"));
-
- QueueRegistry queueRegistry = virtualHost.getQueueRegistry();
- MessageStore messageStore = virtualHost.getMessageStore();
- ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry();
-
-
- AMQShortString queueName = new AMQShortString(queueNameString);
-
- AMQQueue queue;
-
- synchronized (queueRegistry)
- {
- queue = queueRegistry.getQueue(queueName);
-
- if (queue == null)
- {
- _logger.info("Creating queue '" + queueName + "' on virtual host " + virtualHost.getName());
-
- boolean durable = queueConfiguration.getBoolean("durable" ,false);
- boolean autodelete = queueConfiguration.getBoolean("autodelete", false);
- String owner = queueConfiguration.getString("owner", null);
- FieldTable arguments = null;
- Integer priorities = queueConfiguration.getInteger("priorities", null);
- if(priorities != null && priorities.intValue() > 1)
- {
- if(arguments == null)
- {
- arguments = new FieldTable();
- }
- arguments.put(new AMQShortString("x-qpid-priorities"), priorities);
- }
-
-
- queue = AMQQueueFactory.createAMQQueueImpl(queueName,
- durable,
- owner == null ? null : new AMQShortString(owner) /* These queues will have no owner */,
- autodelete /* Therefore autodelete makes no sence */, virtualHost, arguments);
-
- if (queue.isDurable())
- {
- messageStore.createQueue(queue);
- }
-
- queueRegistry.registerQueue(queue);
- }
- else
- {
- _logger.info("Queue '" + queueNameString + "' already exists on virtual host "+virtualHost.getName()+", not creating.");
- }
-
- String exchangeName = queueConfiguration.getString("exchange", null);
-
- Exchange exchange = exchangeRegistry.getExchange(exchangeName == null ? null : new AMQShortString(exchangeName));
-
- if(exchange == null)
- {
- exchange = virtualHost.getExchangeRegistry().getDefaultExchange();
- }
-
- if (exchange == null)
- {
- throw new ConfigurationException("Attempt to bind queue to unknown exchange:" + exchangeName);
- }
-
- synchronized (exchange)
- {
- List routingKeys = queueConfiguration.getList("routingKey");
- if(routingKeys == null || routingKeys.isEmpty())
- {
- routingKeys = Collections.singletonList(queue.getName());
- }
-
- for(Object routingKeyNameObj : routingKeys)
- {
- AMQShortString routingKey = new AMQShortString(String.valueOf(routingKeyNameObj));
-
-
- queue.bind(exchange, routingKey, null);
-
-
- _logger.info("Queue '" + queue.getName() + "' bound to exchange:" + exchangeName + " RK:'" + routingKey + "'");
- }
-
- if(exchange != virtualHost.getExchangeRegistry().getDefaultExchange())
- {
- queue.bind(virtualHost.getExchangeRegistry().getDefaultExchange(), queue.getName(), null);
- }
- }
-
- }
-
+ return _config.getInt("queues.maximumMessageAge", 0);
+ }
+ public Long getMaximumQueueDepth()
+ {
+ return _config.getLong("queues.maximumQueueDepth", 0);
+ }
- Configurator.configure(queue, queueConfiguration);
+ public Long getMaximumMessageSize()
+ {
+ return _config.getLong("queues.maximumMessageSize", 0);
}
+ public Long getMaximumMessageCount()
+ {
+ return _config.getLong("queues.maximumMessageCount", 0);
+ }
- public void performBindings() throws AMQException, ConfigurationException
+ public Long getMinimumAlertRepeatGap()
{
- List virtualHostNames = _config.getList(VIRTUALHOST_PROPERTY_BASE + "name");
- String defaultVirtualHostName = _config.getString("default");
- if(defaultVirtualHostName != null)
- {
- ApplicationRegistry.getInstance().getVirtualHostRegistry().setDefaultVirtualHostName(defaultVirtualHostName);
- }
- _logger.info("Configuring " + virtualHostNames == null ? 0 : virtualHostNames.size() + " virtual hosts: " + virtualHostNames);
+ return _config.getLong("queues.minimumAlertRepeatGap", 0);
+ }
- for(Object nameObject : virtualHostNames)
- {
- String name = String.valueOf(nameObject);
- configureVirtualHost(name, _config.subset(VIRTUALHOST_PROPERTY_BASE + name));
- }
- if (virtualHostNames == null || virtualHostNames.isEmpty())
- {
- throw new ConfigurationException(
- "Virtualhost Configuration document does not contain a valid virtualhost.");
- }
+ public long getCapacity()
+ {
+ return _config.getLong("queues.capacity", 0l);
}
-
+ public long getFlowResumeCapacity()
+ {
+ return _config.getLong("queues.flowResumeCapacity", getCapacity());
+ }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java b/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java
new file mode 100644
index 0000000000..24f8e8878e
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java
@@ -0,0 +1,48 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.configuration.management;
+
+import javax.management.NotCompliantMBeanException;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.management.common.mbeans.ConfigurationManagement;
+import org.apache.qpid.server.management.AMQManagedObject;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+
+public class ConfigurationManagementMBean extends AMQManagedObject implements ConfigurationManagement
+{
+
+ public ConfigurationManagementMBean() throws NotCompliantMBeanException
+ {
+ super(ConfigurationManagement.class, ConfigurationManagement.TYPE, ConfigurationManagement.VERSION);
+ }
+
+ public String getObjectInstanceName()
+ {
+ return ConfigurationManagement.TYPE;
+ }
+
+ public void reloadSecurityConfiguration() throws Exception
+ {
+ ApplicationRegistry.getInstance().getConfiguration().reparseConfigFileSecuritySections();
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java
index d287595e2d..7b50a2e3ad 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java
@@ -21,7 +21,6 @@
package org.apache.qpid.server.connection;
import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.protocol.AMQMinaProtocolSession;
import org.apache.qpid.server.protocol.AMQProtocolSession;
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQConnectionException;
@@ -45,6 +44,14 @@ public class ConnectionRegistry implements IConnectionRegistry
{
}
+
+ public void expireClosedChannels()
+ {
+ for (AMQProtocolSession connection : _registry)
+ {
+ connection.closeIfLingeringClosedChannels();
+ }
+ }
/** Close all of the currently open connections. */
public void close() throws AMQException
diff --git a/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java
index d64fde1c20..002269bbaa 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/connection/IConnectionRegistry.java
@@ -20,7 +20,6 @@
*/
package org.apache.qpid.server.connection;
-import org.apache.qpid.server.protocol.AMQMinaProtocolSession;
import org.apache.qpid.server.protocol.AMQProtocolSession;
import org.apache.qpid.AMQException;
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java
index 8d24626b73..33af910f1a 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -23,6 +23,7 @@ package org.apache.qpid.server.exchange;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
+import javax.management.JMException;
import javax.management.openmbean.OpenType;
import javax.management.openmbean.CompositeType;
import javax.management.openmbean.TabularType;
@@ -33,6 +34,7 @@ import javax.management.openmbean.ArrayType;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.management.common.mbeans.ManagedExchange;
import org.apache.qpid.server.management.AMQManagedObject;
import org.apache.qpid.server.management.Managable;
import org.apache.qpid.server.management.ManagedObject;
@@ -41,15 +43,20 @@ import org.apache.qpid.server.queue.QueueRegistry;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.messages.ExchangeMessages;
+import org.apache.qpid.server.logging.subjects.ExchangeLogSubject;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.log4j.Logger;
-import java.util.List;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
public abstract class AbstractExchange implements Exchange, Managable
{
private AMQShortString _name;
-
+ private Exchange _alternateExchange;
protected boolean _durable;
protected String _exchangeType;
@@ -64,6 +71,10 @@ public abstract class AbstractExchange implements Exchange, Managable
*/
protected boolean _autoDelete;
+ //The logSubject for ths exchange
+ private LogSubject _logSubject;
+ private Map<ExchangeReferrer,Object> _referrers = new ConcurrentHashMap<ExchangeReferrer,Object>();
+
/**
* Abstract MBean class. This has some of the methods implemented from
* management intrerface for exchanges. Any implementaion of an
@@ -72,30 +83,25 @@ public abstract class AbstractExchange implements Exchange, Managable
protected abstract class ExchangeMBean extends AMQManagedObject implements ManagedExchange
{
// open mbean data types for representing exchange bindings
- protected String[] _bindingItemNames;
- protected String[] _bindingItemIndexNames;
protected OpenType[] _bindingItemTypes;
protected CompositeType _bindingDataType;
protected TabularType _bindinglistDataType;
protected TabularDataSupport _bindingList;
-
+
public ExchangeMBean() throws NotCompliantMBeanException
{
- super(ManagedExchange.class, ManagedExchange.TYPE);
+ super(ManagedExchange.class, ManagedExchange.TYPE, ManagedExchange.VERSION);
}
protected void init() throws OpenDataException
{
- _bindingItemNames = new String[]{"Binding Key", "Queue Names"};
- _bindingItemIndexNames = new String[]{_bindingItemNames[0]};
-
_bindingItemTypes = new OpenType[2];
_bindingItemTypes[0] = SimpleType.STRING;
_bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING);
_bindingDataType = new CompositeType("Exchange Binding", "Binding key and Queue names",
- _bindingItemNames, _bindingItemNames, _bindingItemTypes);
+ COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS, _bindingItemTypes);
_bindinglistDataType = new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(),
- _bindingDataType, _bindingItemIndexNames);
+ _bindingDataType, TABULAR_UNIQUE_INDEX);
}
public ManagedObject getParentObject()
@@ -157,19 +163,33 @@ public abstract class AbstractExchange implements Exchange, Managable
* called during initialisation (template method pattern).
* @return the MBean
*/
- protected abstract ExchangeMBean createMBean() throws AMQException;
+ protected abstract ExchangeMBean createMBean() throws JMException;
- public void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException
+ public void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete)
+ throws AMQException
{
_virtualHost = host;
_name = name;
_durable = durable;
_autoDelete = autoDelete;
_ticket = ticket;
- _exchangeMbean = createMBean();
- _exchangeMbean.register();
+ try
+ {
+ _exchangeMbean = createMBean();
+ _exchangeMbean.register();
+ }
+ catch (JMException e)
+ {
+ getLogger().error(e);
+ }
+ _logSubject = new ExchangeLogSubject(this, this.getVirtualHost());
+
+ // Log Exchange creation
+ CurrentActor.get().message(ExchangeMessages.EXH_CREATED(String.valueOf(getType()), String.valueOf(name), durable));
}
+ public abstract Logger getLogger();
+
public boolean isDurable()
{
return _durable;
@@ -191,11 +211,17 @@ public abstract class AbstractExchange implements Exchange, Managable
{
_exchangeMbean.unregister();
}
- }
+ if(_alternateExchange != null)
+ {
+ _alternateExchange.removeReference(this);
+ }
+
+ CurrentActor.get().message(_logSubject, ExchangeMessages.EXH_DELETED());
+ }
public String toString()
{
- return getClass().getName() + "[" + getName() +"]";
+ return getClass().getSimpleName() + "[" + getName() +"]";
}
public ManagedObject getManagedObject()
@@ -212,4 +238,54 @@ public abstract class AbstractExchange implements Exchange, Managable
{
return getVirtualHost().getQueueRegistry();
}
+
+ public boolean isBound(String bindingKey, Map<String,Object> arguments, AMQQueue queue)
+ {
+ return isBound(new AMQShortString(bindingKey), queue);
+ }
+
+
+ public boolean isBound(String bindingKey, AMQQueue queue)
+ {
+ return isBound(new AMQShortString(bindingKey), queue);
+ }
+
+ public boolean isBound(String bindingKey)
+ {
+ return isBound(new AMQShortString(bindingKey));
+ }
+
+ public Exchange getAlternateExchange()
+ {
+ return _alternateExchange;
+ }
+
+ public void setAlternateExchange(Exchange exchange)
+ {
+ if(_alternateExchange != null)
+ {
+ _alternateExchange.removeReference(this);
+ }
+ if(exchange != null)
+ {
+ exchange.addReference(this);
+ }
+ _alternateExchange = exchange;
+
+ }
+
+ public void removeReference(ExchangeReferrer exchange)
+ {
+ _referrers.remove(exchange);
+ }
+
+ public void addReference(ExchangeReferrer exchange)
+ {
+ _referrers.put(exchange, Boolean.TRUE);
+ }
+
+ public boolean hasReferrers()
+ {
+ return !_referrers.isEmpty();
+ }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
index 9d4c090971..6b0cf89b95 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
@@ -25,11 +25,11 @@ import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
-import org.apache.commons.configuration.Configuration;
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQUnknownExchangeType;
import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.configuration.VirtualHostConfiguration;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -59,6 +59,20 @@ public class DefaultExchangeFactory implements ExchangeFactory
return _exchangeClassMap.values();
}
+ public Exchange createExchange(String exchange, String type, boolean durable, boolean autoDelete)
+ throws AMQException
+ {
+ ExchangeType<? extends Exchange> exchType = _exchangeClassMap.get(new AMQShortString(type));
+ if (exchType == null)
+ {
+
+ throw new AMQUnknownExchangeType("Unknown exchange type: " + type,null);
+ }
+ Exchange e = exchType.newInstance(_host, (new AMQShortString(exchange)).intern(), durable, 0, autoDelete);
+ return e;
+
+ }
+
public Exchange createExchange(AMQShortString exchange, AMQShortString type, boolean durable, boolean autoDelete,
int ticket)
throws AMQException
@@ -73,7 +87,7 @@ public class DefaultExchangeFactory implements ExchangeFactory
return e;
}
- public void initialise(Configuration hostConfig)
+ public void initialise(VirtualHostConfiguration hostConfig)
{
if (hostConfig == null)
@@ -81,7 +95,7 @@ public class DefaultExchangeFactory implements ExchangeFactory
return;
}
- for(Object className : hostConfig.getList("custom-exchanges.class-name"))
+ for(Object className : hostConfig.getCustomExchanges())
{
try
{
@@ -92,7 +106,7 @@ public class DefaultExchangeFactory implements ExchangeFactory
return;
}
Class<? extends ExchangeType> exchangeTypeClass = exchangeType.getClass();
- ExchangeType type = exchangeTypeClass.newInstance();
+ ExchangeType<? extends ExchangeType> type = exchangeTypeClass.newInstance();
registerExchangeType(type);
}
catch (ClassCastException classCastEx)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java
index 0ab8208d88..2a8a87be7d 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -23,10 +23,9 @@ package org.apache.qpid.server.exchange;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.protocol.ExchangeInitialiser;
-import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.exchange.ExchangeInitialiser;
import org.apache.qpid.server.queue.IncomingMessage;
-import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.DurableConfigurationStore;
import org.apache.qpid.server.virtualhost.VirtualHost;
import java.util.Collection;
@@ -41,6 +40,7 @@ public class DefaultExchangeRegistry implements ExchangeRegistry
* Maps from exchange name to exchange instance
*/
private ConcurrentMap<AMQShortString, Exchange> _exchangeMap = new ConcurrentHashMap<AMQShortString, Exchange>();
+ private ConcurrentMap<String, Exchange> _exchangeMapStr = new ConcurrentHashMap<String, Exchange>();
private Exchange _defaultExchange;
private VirtualHost _host;
@@ -57,17 +57,20 @@ public class DefaultExchangeRegistry implements ExchangeRegistry
new ExchangeInitialiser().initialise(_host.getExchangeFactory(), this);
}
- public MessageStore getMessageStore()
+
+
+ public DurableConfigurationStore getDurableConfigurationStore()
{
- return _host.getMessageStore();
+ return _host.getDurableConfigurationStore();
}
public void registerExchange(Exchange exchange) throws AMQException
{
_exchangeMap.put(exchange.getName(), exchange);
+ _exchangeMapStr.put(exchange.getName().toString(), exchange);
if (exchange.isDurable())
{
- getMessageStore().createExchange(exchange);
+ getDurableConfigurationStore().createExchange(exchange);
}
}
@@ -90,11 +93,12 @@ public class DefaultExchangeRegistry implements ExchangeRegistry
{
// TODO: check inUse argument
Exchange e = _exchangeMap.remove(name);
+ _exchangeMapStr.remove(name.toString());
if (e != null)
{
if (e.isDurable())
{
- getMessageStore().removeExchange(e);
+ getDurableConfigurationStore().removeExchange(e);
}
e.close();
}
@@ -104,6 +108,11 @@ public class DefaultExchangeRegistry implements ExchangeRegistry
}
}
+ public void unregisterExchange(String name, boolean inUse) throws AMQException
+ {
+ unregisterExchange(new AMQShortString(name), inUse);
+ }
+
public Exchange getExchange(AMQShortString name)
{
if ((name == null) || name.length() == 0)
@@ -117,6 +126,19 @@ public class DefaultExchangeRegistry implements ExchangeRegistry
}
+ public Exchange getExchange(String name)
+ {
+ if ((name == null) || name.length() == 0)
+ {
+ return getDefaultExchange();
+ }
+ else
+ {
+ return _exchangeMapStr.get(name);
+ }
+ }
+
+
/**
* Routes content through exchanges, delivering it to 1 or more queues.
* @param payload
@@ -134,6 +156,6 @@ public class DefaultExchangeRegistry implements ExchangeRegistry
{
throw new AMQException("Exchange '" + exchange + "' does not exist");
}
- exch.route(payload);
+ payload.enqueue(exch.route(payload));
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java
index e39c005750..3c3902c545 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java
@@ -34,15 +34,17 @@ import javax.management.openmbean.TabularDataSupport;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.server.management.MBeanConstructor;
-import org.apache.qpid.server.management.MBeanDescription;
-import org.apache.qpid.server.queue.IncomingMessage;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.message.InboundMessage;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.ManagementActor;
public class DirectExchange extends AbstractExchange
{
@@ -114,7 +116,7 @@ public class DirectExchange extends AbstractExchange
}
Object[] bindingItemValues = {key.toString(), queueList.toArray(new String[0])};
- CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues);
+ CompositeData bindingData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues);
_bindingList.put(bindingData);
}
@@ -129,6 +131,7 @@ public class DirectExchange extends AbstractExchange
throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange.");
}
+ CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger()));
try
{
queue.bind(DirectExchange.this, new AMQShortString(binding), null);
@@ -137,22 +140,23 @@ public class DirectExchange extends AbstractExchange
{
throw new MBeanException(ex);
}
+ finally
+ {
+ CurrentActor.remove();
+ }
}
}// End of MBean class
- protected ExchangeMBean createMBean() throws AMQException
+ protected ExchangeMBean createMBean() throws JMException
{
- try
- {
- return new DirectExchangeMBean();
- }
- catch (JMException ex)
- {
- _logger.error("Exception occured in creating the direct exchange mbean", ex);
- throw new AMQException("Exception occured in creating the direct exchange mbean", ex);
- }
+ return new DirectExchangeMBean();
+ }
+
+ public Logger getLogger()
+ {
+ return _logger;
}
public AMQShortString getType()
@@ -160,24 +164,32 @@ public class DirectExchange extends AbstractExchange
return ExchangeDefaults.DIRECT_EXCHANGE_CLASS;
}
+ public void registerQueue(String routingKey, AMQQueue queue, Map<String,Object> args) throws AMQException
+ {
+ registerQueue(new AMQShortString(routingKey), queue);
+ }
+
public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException
{
+ registerQueue(routingKey, queue);
+ }
+
+ private void registerQueue(AMQShortString routingKey, AMQQueue queue) throws AMQException
+ {
assert queue != null;
assert routingKey != null;
if (!_index.add(routingKey, queue))
{
if (_logger.isDebugEnabled())
{
- _logger.debug("Queue (" + queue.getName() + ")" + queue + " is already registered with routing key " + routingKey);
+ _logger.debug("Queue (" + queue + ") is already registered with routing key " + routingKey);
}
}
else
{
if (_logger.isDebugEnabled())
{
- _logger.debug("Binding queue(" + queue.getName() + ") " + queue + " with routing key " + routingKey
- + (args == null ? "" : " and arguments " + args.toString())
- + " to exchange " + this);
+ _logger.debug("Binding queue:" + queue + " with routing key '" + routingKey +"' to exchange:" + this);
}
}
}
@@ -194,19 +206,21 @@ public class DirectExchange extends AbstractExchange
}
}
- public void route(IncomingMessage payload) throws AMQException
+ public ArrayList<AMQQueue> route(InboundMessage payload)
{
- final AMQShortString routingKey = payload.getRoutingKey() == null ? AMQShortString.EMPTY_STRING : payload.getRoutingKey();
+ final String routingKey = payload.getRoutingKey();
- final ArrayList<AMQQueue> queues = (routingKey == null) ? null : _index.get(routingKey);
+
+ final ArrayList<AMQQueue> queues = (routingKey == null) ? _index.get("") : _index.get(routingKey);
if (_logger.isDebugEnabled())
{
_logger.debug("Publishing message to queue " + queues);
}
- payload.enqueue(queues);
+ return queues;
+
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java
index 06209c5458..4bbdeaef1c 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java
@@ -24,20 +24,21 @@ import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.server.queue.IncomingMessage;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.message.InboundMessage;
-import java.util.List;
-import java.util.Map;
+import javax.management.JMException;
+import java.util.ArrayList;
-public interface Exchange
+public interface Exchange extends ExchangeReferrer
{
AMQShortString getName();
AMQShortString getType();
- void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException;
+ void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete)
+ throws AMQException, JMException;
boolean isDurable();
@@ -52,9 +53,11 @@ public interface Exchange
void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException;
+
+
void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException;
- void route(IncomingMessage message) throws AMQException;
+ ArrayList<AMQQueue> route(InboundMessage message);
/**
@@ -93,6 +96,18 @@ public interface Exchange
*/
boolean hasBindings();
-
+ boolean isBound(String bindingKey, AMQQueue queue);
+
+ boolean isBound(String bindingKey);
+
+ Exchange getAlternateExchange();
+
+ void setAlternateExchange(Exchange exchange);
+
+ void removeReference(ExchangeReferrer exchange);
+
+ void addReference(ExchangeReferrer exchange);
+
+ boolean hasReferrers();
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java
index 0bcfec7181..b91bf559f1 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java
@@ -26,6 +26,7 @@ import org.apache.commons.configuration.Configuration;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.configuration.VirtualHostConfiguration;
public interface ExchangeFactory
@@ -34,7 +35,9 @@ public interface ExchangeFactory
int ticket)
throws AMQException;
- void initialise(Configuration hostConfig);
+ void initialise(VirtualHostConfiguration hostConfig);
Collection<ExchangeType<? extends Exchange>> getRegisteredTypes();
+
+ Exchange createExchange(String exchange, String type, boolean durable, boolean autoDelete) throws AMQException;
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInitialiser.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInitialiser.java
new file mode 100644
index 0000000000..59fe94ddc0
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInitialiser.java
@@ -0,0 +1,47 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.exchange;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.framing.AMQShortString;
+
+public class ExchangeInitialiser
+{
+ public void initialise(ExchangeFactory factory, ExchangeRegistry registry) throws AMQException{
+ for (ExchangeType<? extends Exchange> type : factory.getRegisteredTypes())
+ {
+ define (registry, factory, type.getDefaultExchangeName(), type.getName());
+ }
+
+ define(registry, factory, ExchangeDefaults.DEFAULT_EXCHANGE_NAME, ExchangeDefaults.DIRECT_EXCHANGE_CLASS);
+ registry.setDefaultExchange(registry.getExchange(ExchangeDefaults.DEFAULT_EXCHANGE_NAME));
+ }
+
+ private void define(ExchangeRegistry r, ExchangeFactory f,
+ AMQShortString name, AMQShortString type) throws AMQException
+ {
+ if(r.getExchange(name)== null)
+ {
+ r.registerExchange(f.createExchange(name, type, true, false, 0));
+ }
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeReferrer.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeReferrer.java
new file mode 100755
index 0000000000..e41d63d97d
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeReferrer.java
@@ -0,0 +1,26 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.exchange;
+
+public interface ExchangeReferrer
+{
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java
index fe3b19e74e..e34ef29d9b 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java
@@ -48,4 +48,8 @@ public interface ExchangeRegistry extends MessageRouter
Collection<AMQShortString> getExchangeNames();
void initialise() throws AMQException;
+
+ Exchange getExchange(String exchangeName);
+
+ void unregisterExchange(String exchange, boolean ifUnused) throws ExchangeInUseException, AMQException;;
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java
index e9fd4d548b..00f8ebd856 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java
@@ -22,15 +22,17 @@ package org.apache.qpid.server.exchange;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.server.management.MBeanConstructor;
-import org.apache.qpid.server.management.MBeanDescription;
-import org.apache.qpid.server.queue.IncomingMessage;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.message.InboundMessage;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.ManagementActor;
import javax.management.JMException;
import javax.management.MBeanException;
@@ -59,6 +61,8 @@ public class FanoutExchange extends AbstractExchange
@MBeanDescription("Management Bean for Fanout Exchange")
private final class FanoutExchangeMBean extends ExchangeMBean
{
+ private static final String BINDING_KEY_SUBSTITUTE = "*";
+
@MBeanConstructor("Creates an MBean for AMQ fanout exchange")
public FanoutExchangeMBean() throws JMException
{
@@ -72,15 +76,23 @@ public class FanoutExchange extends AbstractExchange
_bindingList = new TabularDataSupport(_bindinglistDataType);
+ if(_queues.isEmpty())
+ {
+ return _bindingList;
+ }
+
+ ArrayList<String> queueNames = new ArrayList<String>();
+
for (AMQQueue queue : _queues)
{
String queueName = queue.getName().toString();
-
- Object[] bindingItemValues = {queueName, new String[]{queueName}};
- CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues);
- _bindingList.put(bindingData);
+ queueNames.add(queueName);
}
+ Object[] bindingItemValues = {BINDING_KEY_SUBSTITUTE, queueNames.toArray(new String[0])};
+ CompositeData bindingData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues);
+ _bindingList.put(bindingData);
+
return _bindingList;
}
@@ -92,29 +104,31 @@ public class FanoutExchange extends AbstractExchange
throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange.");
}
+ CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger()));
try
{
- queue.bind(FanoutExchange.this, new AMQShortString(binding), null);
+ queue.bind(FanoutExchange.this, new AMQShortString(BINDING_KEY_SUBSTITUTE), null);
}
catch (AMQException ex)
{
throw new MBeanException(ex);
}
+ finally
+ {
+ CurrentActor.remove();
+ }
}
} // End of MBean class
- protected ExchangeMBean createMBean() throws AMQException
+ protected ExchangeMBean createMBean() throws JMException
{
- try
- {
- return new FanoutExchange.FanoutExchangeMBean();
- }
- catch (JMException ex)
- {
- _logger.error("Exception occured in creating the direct exchange mbean", ex);
- throw new AMQException("Exception occured in creating the direct exchange mbean", ex);
- }
+ return new FanoutExchange.FanoutExchangeMBean();
+ }
+
+ public Logger getLogger()
+ {
+ return _logger;
}
public static final ExchangeType<FanoutExchange> TYPE = new ExchangeType<FanoutExchange>()
@@ -182,16 +196,16 @@ public class FanoutExchange extends AbstractExchange
}
}
- public void route(IncomingMessage payload) throws AMQException
+ public ArrayList<AMQQueue> route(InboundMessage payload)
{
-
+
if (_logger.isDebugEnabled())
{
_logger.debug("Publishing message to queue " + _queues);
}
- payload.enqueue(new ArrayList(_queues));
+ return new ArrayList(_queues);
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java
index 2b7df4361a..35c4a8f9b2 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -28,6 +28,7 @@ import java.util.Set;
import org.apache.log4j.Logger;
import org.apache.qpid.framing.AMQTypedValue;
import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.server.message.AMQMessageHeader;
/**
* Defines binding and matching based on a set of headers.
@@ -87,7 +88,7 @@ class HeadersBinding
* Creates a binding for a set of mappings. Those mappings whose value is
* null or the empty string are assumed only to be required headers, with
* no constraint on the value. Those with a non-null value are assumed to
- * define a required match of value.
+ * define a required match of value.
* @param mappings the defined mappings this binding should use
*/
@@ -139,7 +140,7 @@ class HeadersBinding
* @return true if the headers define any required keys and match any required
* values
*/
- public boolean matches(FieldTable headers)
+ public boolean matches(AMQMessageHeader headers)
{
if(headers == null)
{
@@ -151,13 +152,13 @@ class HeadersBinding
}
}
- private boolean and(FieldTable headers)
+ private boolean and(AMQMessageHeader headers)
{
- if(headers.keys().containsAll(required))
+ if(headers.containsHeaders(required))
{
for(Map.Entry<String, Object> e : matches.entrySet())
{
- if(!e.getValue().equals(headers.getObject(e.getKey())))
+ if(!e.getValue().equals(headers.getHeader(e.getKey())))
{
return false;
}
@@ -171,17 +172,50 @@ class HeadersBinding
}
- private boolean or(final FieldTable headers)
+ private boolean or(final AMQMessageHeader headers)
{
- if(required.isEmpty() || !(Boolean) headers.processOverElements(new RequiredOrProcessor()))
+ if(required.isEmpty())
{
- return ((!matches.isEmpty()) && (Boolean) headers.processOverElements(new MatchesOrProcessor()))
- || (required.isEmpty() && matches.isEmpty());
+ return matches.isEmpty() || passesMatchesOr(headers);
}
else
{
- return true;
+ if(!passesRequiredOr(headers))
+ {
+ return !matches.isEmpty() && passesMatchesOr(headers);
+ }
+ else
+ {
+ return true;
+ }
+
+ }
+ }
+
+ private boolean passesMatchesOr(AMQMessageHeader headers)
+ {
+ for(Map.Entry<String,Object> entry : matches.entrySet())
+ {
+ if(headers.containsHeader(entry.getKey())
+ && ((entry.getValue() == null && headers.getHeader(entry.getKey()) == null)
+ || (entry.getValue().equals(headers.getHeader(entry.getKey())))))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean passesRequiredOr(AMQMessageHeader headers)
+ {
+ for(String name : required)
+ {
+ if(headers.containsHeader(name))
+ {
+ return true;
+ }
}
+ return false;
}
private void processSpecial(String key, Object value)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java
index 1ee1f35de6..5677cc4510 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java
@@ -22,6 +22,8 @@ package org.apache.qpid.server.exchange;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.framing.AMQShortString;
@@ -29,11 +31,10 @@ import org.apache.qpid.framing.AMQTypedValue;
import org.apache.qpid.framing.BasicContentHeaderProperties;
import org.apache.qpid.framing.ContentHeaderBody;
import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.server.management.MBeanConstructor;
-import org.apache.qpid.server.management.MBeanDescription;
-import org.apache.qpid.server.queue.IncomingMessage;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.message.InboundMessage;
+import org.apache.qpid.server.message.AMQMessageHeader;
import javax.management.JMException;
import javax.management.openmbean.ArrayType;
@@ -50,8 +51,8 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Collection;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ConcurrentHashMap;
/**
* An exchange that binds queues based on a set of required headers and header values
@@ -82,9 +83,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
*/
public class HeadersExchange extends AbstractExchange
{
- private static final Logger _logger = Logger.getLogger(HeadersExchange.class);
-
+ private static final Logger _logger = Logger.getLogger(HeadersExchange.class);
public static final ExchangeType<HeadersExchange> TYPE = new ExchangeType<HeadersExchange>()
{
@@ -103,6 +103,7 @@ public class HeadersExchange extends AbstractExchange
boolean autoDelete) throws AMQException
{
HeadersExchange exch = new HeadersExchange();
+
exch.initialise(host, name, durable, ticket, autoDelete);
return exch;
}
@@ -116,6 +117,7 @@ public class HeadersExchange extends AbstractExchange
private final List<Registration> _bindings = new CopyOnWriteArrayList<Registration>();
+ private Map<AMQShortString, Registration> _bindingByKey = new ConcurrentHashMap<AMQShortString, Registration>();
/**
* HeadersExchangeMBean class implements the management interface for the
@@ -137,17 +139,15 @@ public class HeadersExchange extends AbstractExchange
*/
protected void init() throws OpenDataException
{
- _bindingItemNames = new String[]{"Binding No", "Queue Name", "Queue Bindings"};
- _bindingItemIndexNames = new String[]{_bindingItemNames[0]};
_bindingItemTypes = new OpenType[3];
_bindingItemTypes[0] = SimpleType.INTEGER;
_bindingItemTypes[1] = SimpleType.STRING;
_bindingItemTypes[2] = new ArrayType(1, SimpleType.STRING);
_bindingDataType = new CompositeType("Exchange Binding", "Queue name and header bindings",
- _bindingItemNames, _bindingItemNames, _bindingItemTypes);
+ HEADERS_COMPOSITE_ITEM_NAMES, HEADERS_COMPOSITE_ITEM_DESC, _bindingItemTypes);
_bindinglistDataType = new TabularType("Exchange Bindings", "List of exchange bindings for " + getName(),
- _bindingDataType, _bindingItemIndexNames);
+ _bindingDataType, HEADERS_TABULAR_UNIQUE_INDEX);
}
public TabularData bindings() throws OpenDataException
@@ -180,7 +180,7 @@ public class HeadersExchange extends AbstractExchange
Object[] bindingItemValues = {count++, queueName, mappingList.toArray(new String[0])};
- CompositeData bindingData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues);
+ CompositeData bindingData = new CompositeDataSupport(_bindingDataType, HEADERS_COMPOSITE_ITEM_NAMES, bindingItemValues);
_bindingList.put(bindingData);
}
@@ -208,14 +208,24 @@ public class HeadersExchange extends AbstractExchange
for (int i = 0; i < bindings.length; i++)
{
String[] keyAndValue = bindings[i].split("=");
- if (keyAndValue == null || keyAndValue.length < 2)
+ if (keyAndValue == null || keyAndValue.length == 0 || keyAndValue.length > 2)
{
throw new JMException("Format for headers binding should be \"<attribute1>=<value1>,<attribute2>=<value2>\" ");
}
- bindingMap.setString(keyAndValue[0], keyAndValue[1]);
+
+ if(keyAndValue.length ==1)
+ {
+ //no value was given, only a key. Use an empty value
+ //to signal match on key presence alone
+ bindingMap.setString(keyAndValue[0], "");
+ }
+ else
+ {
+ bindingMap.setString(keyAndValue[0], keyAndValue[1]);
+ }
}
- _bindings.add(new Registration(new HeadersBinding(bindingMap), queue));
+ _bindings.add(new Registration(new HeadersBinding(bindingMap), queue, new AMQShortString(binding)));
}
} // End of MBean class
@@ -228,44 +238,48 @@ public class HeadersExchange extends AbstractExchange
public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException
{
_logger.debug("Exchange " + getName() + ": Binding " + queue.getName() + " with " + args);
- _bindings.add(new Registration(new HeadersBinding(args), queue));
+
+ Registration registration = new Registration(new HeadersBinding(args), queue, routingKey);
+ _bindings.add(registration);
+
}
public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException
{
_logger.debug("Exchange " + getName() + ": Unbinding " + queue.getName());
- if(!_bindings.remove(new Registration(new HeadersBinding(args), queue)))
+
+ if(!_bindings.remove(new Registration(args == null ? null : new HeadersBinding(args), queue, routingKey)))
{
throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName()
- + " with headers args " + args);
+ + " with headers args " + args);
}
}
- public void route(IncomingMessage payload) throws AMQException
+ public ArrayList<AMQQueue> route(InboundMessage payload)
{
- FieldTable headers = getHeaders(payload.getContentHeaderBody());
+ AMQMessageHeader header = payload.getMessageHeader();
if (_logger.isDebugEnabled())
{
- _logger.debug("Exchange " + getName() + ": routing message with headers " + headers);
+ _logger.debug("Exchange " + getName() + ": routing message with headers " + header);
}
boolean routed = false;
ArrayList<AMQQueue> queues = new ArrayList<AMQQueue>();
for (Registration e : _bindings)
{
- if (e.binding.matches(headers))
+ if (e.binding.matches(header))
{
if (_logger.isDebugEnabled())
{
_logger.debug("Exchange " + getName() + ": delivering message with headers " +
- headers + " to " + e.queue.getName());
+ header + " to " + e.queue.getName());
}
queues.add(e.queue);
routed = true;
}
}
- payload.enqueue(queues);
+ return queues;
}
public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue)
@@ -308,17 +322,9 @@ public class HeadersExchange extends AbstractExchange
return ((BasicContentHeaderProperties) contentHeaderFrame.properties).getHeaders();
}
- protected ExchangeMBean createMBean() throws AMQException
+ protected ExchangeMBean createMBean() throws JMException
{
- try
- {
- return new HeadersExchangeMBean();
- }
- catch (JMException ex)
- {
- _logger.error("Exception occured in creating the HeadersExchangeMBean", ex);
- throw new AMQException("Exception occured in creating the HeadersExchangeMBean", ex);
- }
+ return new HeadersExchangeMBean();
}
public Map<AMQShortString, List<AMQQueue>> getBindings()
@@ -326,25 +332,38 @@ public class HeadersExchange extends AbstractExchange
return null;
}
+ public Logger getLogger()
+ {
+ return _logger;
+ }
+
+
private static class Registration
{
private final HeadersBinding binding;
private final AMQQueue queue;
+ private final AMQShortString routingKey;
- Registration(HeadersBinding binding, AMQQueue queue)
+ Registration(HeadersBinding binding, AMQQueue queue, AMQShortString routingKey)
{
this.binding = binding;
this.queue = queue;
+ this.routingKey = routingKey;
}
public int hashCode()
{
- return queue.hashCode();
+ int queueHash = queue.hashCode();
+ int routingHash = routingKey == null ? 0 : routingKey.hashCode();
+ return queueHash + routingHash;
}
public boolean equals(Object o)
{
- return o instanceof Registration && ((Registration) o).queue.equals(queue);
+ return o instanceof Registration
+ && ((Registration) o).queue.equals(queue)
+ && (routingKey == null ? ((Registration)o).routingKey == null
+ : routingKey.equals(((Registration)o).routingKey));
}
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java
index ec83161029..90d04c814a 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java
@@ -39,6 +39,9 @@ class Index
{
private ConcurrentMap<AMQShortString, ArrayList<AMQQueue>> _index
= new ConcurrentHashMap<AMQShortString, ArrayList<AMQQueue>>();
+ private ConcurrentMap<String, ArrayList<AMQQueue>> _stringIndex
+ = new ConcurrentHashMap<String, ArrayList<AMQQueue>>();
+
synchronized boolean add(AMQShortString key, AMQQueue queue)
{
@@ -51,8 +54,10 @@ class Index
{
queues = new ArrayList<AMQQueue>(queues);
}
+
//next call is atomic, so there is no race to create the list
_index.put(key, queues);
+ _stringIndex.put(key.toString(), queues);
if(queues.contains(queue))
{
@@ -64,6 +69,8 @@ class Index
}
}
+
+
synchronized boolean remove(AMQShortString key, AMQQueue queue)
{
ArrayList<AMQQueue> queues = _index.get(key);
@@ -76,10 +83,12 @@ class Index
if (queues.size() == 0)
{
_index.remove(key);
+ _stringIndex.remove(key.toString());
}
else
{
_index.put(key, queues);
+ _stringIndex.put(key.toString(), queues);
}
}
return removed;
@@ -92,6 +101,12 @@ class Index
return _index.get(key);
}
+ ArrayList<AMQQueue> get(String key)
+ {
+ return _stringIndex.get(key);
+ }
+
+
Map<AMQShortString, List<AMQQueue>> getBindingsMap()
{
return new HashMap<AMQShortString, List<AMQQueue>>(_index);
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java
deleted file mode 100644
index 5d6d68b3c8..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java
+++ /dev/null
@@ -1,98 +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.
- *
- */
-package org.apache.qpid.server.exchange;
-
-import java.io.IOException;
-
-import javax.management.JMException;
-import javax.management.MBeanOperationInfo;
-import javax.management.openmbean.TabularData;
-
-import org.apache.qpid.server.management.MBeanAttribute;
-import org.apache.qpid.server.management.MBeanOperation;
-import org.apache.qpid.server.management.MBeanOperationParameter;
-import org.apache.qpid.server.queue.ManagedQueue;
-
-/**
- * The management interface exposed to allow management of an Exchange.
- * @author Robert J. Greig
- * @author Bhupendra Bhardwaj
- * @version 0.1
- */
-public interface ManagedExchange
-{
- static final String TYPE = "Exchange";
-
- /**
- * Returns the name of the managed exchange.
- * @return the name of the exchange.
- * @throws IOException
- */
- @MBeanAttribute(name="Name", description=TYPE + " Name")
- String getName() throws IOException;
-
- @MBeanAttribute(name="ExchangeType", description="Exchange Type")
- String getExchangeType() throws IOException;
-
- @MBeanAttribute(name="TicketNo", description="Exchange Ticket No")
- Integer getTicketNo() throws IOException;
-
- /**
- * Tells if the exchange is durable or not.
- * @return true if the exchange is durable.
- * @throws IOException
- */
- @MBeanAttribute(name="Durable", description="true if Exchange is durable")
- boolean isDurable() throws IOException;
-
- /**
- * Tells if the exchange is set for autodelete or not.
- * @return true if the exchange is set as autodelete.
- * @throws IOException
- */
- @MBeanAttribute(name="AutoDelete", description="true if Exchange is AutoDelete")
- boolean isAutoDelete() throws IOException;
-
- // Operations
-
- /**
- * Returns all the bindings this exchange has with the queues.
- * @return the bindings with the exchange.
- * @throws IOException
- * @throws JMException
- */
- @MBeanOperation(name="bindings", description="view the queue bindings for this exchange")
- TabularData bindings() throws IOException, JMException;
-
- /**
- * Creates new binding with the given queue and binding.
- * @param queueName
- * @param binding
- * @throws JMException
- */
- @MBeanOperation(name="createNewBinding",
- description="create a new binding with this exchange",
- impact= MBeanOperationInfo.ACTION)
- void createNewBinding(@MBeanOperationParameter(name= ManagedQueue.TYPE, description="Queue name") String queueName,
- @MBeanOperationParameter(name="Binding", description="New binding")String binding)
- throws JMException;
-
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java
index db9beb6da7..025a8014aa 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -21,7 +21,6 @@
package org.apache.qpid.server.exchange;
import org.apache.qpid.AMQException;
-import org.apache.qpid.server.queue.AMQMessage;
import org.apache.qpid.server.queue.IncomingMessage;
/**
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java
deleted file mode 100644
index d18ad7ab14..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java
+++ /dev/null
@@ -1,49 +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.
- *
- */
-package org.apache.qpid.server.exchange;
-
-import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.server.RequiredDeliveryException;
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.queue.IncomingMessage;
-
-/**
- * NoRouteException is a {@link RequiredDeliveryException} that represents the failure case where a manadatory message
- * cannot be delivered because there is no route for the message. The AMQP status code, 312, is always used to report
- * this condition.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Represent failure to deliver a message that must be delivered.
- * </table>
- */
-public class NoRouteException extends RequiredDeliveryException
-{
- public NoRouteException(String msg, AMQMessage amqMessage)
- {
- super(msg, amqMessage);
- }
-
- public AMQConstant getReplyCode()
- {
- return AMQConstant.NO_ROUTE;
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java
index 59a8339346..d5ca5a8a81 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java
@@ -23,20 +23,22 @@ package org.apache.qpid.server.exchange;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.common.AMQPFilterTypes;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.framing.AMQShortStringTokenizer;
-import org.apache.qpid.server.management.MBeanConstructor;
-import org.apache.qpid.server.management.MBeanDescription;
-import org.apache.qpid.server.queue.IncomingMessage;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.exchange.topic.TopicParser;
import org.apache.qpid.server.exchange.topic.TopicMatcherResult;
import org.apache.qpid.server.filter.MessageFilter;
import org.apache.qpid.server.filter.JMSSelectorFilter;
+import org.apache.qpid.server.message.InboundMessage;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.ManagementActor;
import javax.management.JMException;
import javax.management.MBeanException;
@@ -109,7 +111,7 @@ public class TopicExchange extends AbstractExchange
private final Map<Binding, FieldTable> _bindings = new HashMap<Binding, FieldTable>();
- private final Map<String, WeakReference<JMSSelectorFilter<RuntimeException>>> _selectorCache = new WeakHashMap<String, WeakReference<JMSSelectorFilter<RuntimeException>>>();
+ private final Map<String, WeakReference<JMSSelectorFilter>> _selectorCache = new WeakHashMap<String, WeakReference<JMSSelectorFilter>>();
public static class Binding
{
@@ -160,7 +162,7 @@ public class TopicExchange extends AbstractExchange
private final class TopicExchangeResult implements TopicMatcherResult
{
private final Map<AMQQueue, Integer> _unfilteredQueues = new ConcurrentHashMap<AMQQueue, Integer>();
- private final ConcurrentHashMap<AMQQueue, Map<MessageFilter<RuntimeException>,Integer>> _filteredQueues = new ConcurrentHashMap<AMQQueue, Map<MessageFilter<RuntimeException>, Integer>>();
+ private final ConcurrentHashMap<AMQQueue, Map<MessageFilter,Integer>> _filteredQueues = new ConcurrentHashMap<AMQQueue, Map<MessageFilter, Integer>>();
public void addUnfilteredQueue(AMQQueue queue)
{
@@ -190,12 +192,12 @@ public class TopicExchange extends AbstractExchange
}
- public void addFilteredQueue(AMQQueue queue, MessageFilter<RuntimeException> filter)
+ public void addFilteredQueue(AMQQueue queue, MessageFilter filter)
{
- Map<MessageFilter<RuntimeException>,Integer> filters = _filteredQueues.get(queue);
+ Map<MessageFilter,Integer> filters = _filteredQueues.get(queue);
if(filters == null)
{
- filters = new ConcurrentHashMap<MessageFilter<RuntimeException>,Integer>();
+ filters = new ConcurrentHashMap<MessageFilter,Integer>();
_filteredQueues.put(queue, filters);
}
Integer instances = filters.get(filter);
@@ -210,23 +212,26 @@ public class TopicExchange extends AbstractExchange
}
- public void removeFilteredQueue(AMQQueue queue, MessageFilter<RuntimeException> filter)
+ public void removeFilteredQueue(AMQQueue queue, MessageFilter filter)
{
- Map<MessageFilter<RuntimeException>,Integer> filters = _filteredQueues.get(queue);
+ Map<MessageFilter,Integer> filters = _filteredQueues.get(queue);
if(filters != null)
{
Integer instances = filters.get(filter);
- if(instances == 1)
+ if(instances != null)
{
- filters.remove(filter);
- if(filters.isEmpty())
+ if(instances == 1)
{
- _filteredQueues.remove(queue);
+ filters.remove(filter);
+ if(filters.isEmpty())
+ {
+ _filteredQueues.remove(queue);
+ }
+ }
+ else
+ {
+ filters.put(filter, instances - 1);
}
- }
- else if(instances != null)
- {
- filters.put(filter, instances - 1);
}
}
@@ -234,11 +239,11 @@ public class TopicExchange extends AbstractExchange
}
public void replaceQueueFilter(AMQQueue queue,
- MessageFilter<RuntimeException> oldFilter,
- MessageFilter<RuntimeException> newFilter)
+ MessageFilter oldFilter,
+ MessageFilter newFilter)
{
- Map<MessageFilter<RuntimeException>,Integer> filters = _filteredQueues.get(queue);
- Map<MessageFilter<RuntimeException>,Integer> newFilters = new ConcurrentHashMap<MessageFilter<RuntimeException>,Integer>(filters);
+ Map<MessageFilter,Integer> filters = _filteredQueues.get(queue);
+ Map<MessageFilter,Integer> newFilters = new ConcurrentHashMap<MessageFilter,Integer>(filters);
Integer oldFilterInstances = filters.get(oldFilter);
if(oldFilterInstances == 1)
{
@@ -260,7 +265,7 @@ public class TopicExchange extends AbstractExchange
_filteredQueues.put(queue,newFilters);
}
- public Collection<AMQQueue> processMessage(IncomingMessage msg, Collection<AMQQueue> queues)
+ public Collection<AMQQueue> processMessage(InboundMessage msg, Collection<AMQQueue> queues)
{
if(queues == null)
{
@@ -281,11 +286,11 @@ public class TopicExchange extends AbstractExchange
queues.addAll(_unfilteredQueues.keySet());
if(!_filteredQueues.isEmpty())
{
- for(Map.Entry<AMQQueue, Map<MessageFilter<RuntimeException>, Integer>> entry : _filteredQueues.entrySet())
+ for(Map.Entry<AMQQueue, Map<MessageFilter, Integer>> entry : _filteredQueues.entrySet())
{
if(!queues.contains(entry.getKey()))
{
- for(MessageFilter<RuntimeException> filter : entry.getValue().keySet())
+ for(MessageFilter filter : entry.getValue().keySet())
{
if(filter.matches(msg))
{
@@ -333,7 +338,7 @@ public class TopicExchange extends AbstractExchange
for(Map.Entry<String, List<String>> entry : bindingData.entrySet())
{
Object[] bindingItemValues = {entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]) };
- CompositeData bindingCompositeData = new CompositeDataSupport(_bindingDataType, _bindingItemNames, bindingItemValues);
+ CompositeData bindingCompositeData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues);
_bindingList.put(bindingCompositeData);
}
@@ -348,6 +353,7 @@ public class TopicExchange extends AbstractExchange
throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange.");
}
+ CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger()));
try
{
queue.bind(TopicExchange.this, new AMQShortString(binding), null);
@@ -356,6 +362,10 @@ public class TopicExchange extends AbstractExchange
{
throw new MBeanException(ex);
}
+ finally
+ {
+ CurrentActor.remove();
+ }
}
} // End of MBean class
@@ -433,10 +443,10 @@ public class TopicExchange extends AbstractExchange
{
result.addUnfilteredQueue(queue);
}
- _parser.addBinding(routingKey, result);
+ _parser.addBinding(routingKey, result);
_topicExchangeResults.put(routingKey,result);
}
- else
+ else
{
if(argumentsContainSelector(args))
{
@@ -453,18 +463,18 @@ public class TopicExchange extends AbstractExchange
}
- private JMSSelectorFilter<RuntimeException> createSelectorFilter(final FieldTable args)
+ private JMSSelectorFilter createSelectorFilter(final FieldTable args)
throws AMQException
{
final String selectorString = args.getString(AMQPFilterTypes.JMS_SELECTOR.getValue());
- WeakReference<JMSSelectorFilter<RuntimeException>> selectorRef = _selectorCache.get(selectorString);
+ WeakReference<JMSSelectorFilter> selectorRef = _selectorCache.get(selectorString);
JMSSelectorFilter selector = null;
if(selectorRef == null || (selector = selectorRef.get())==null)
{
- selector = new JMSSelectorFilter<RuntimeException>(selectorString);
- _selectorCache.put(selectorString, new WeakReference<JMSSelectorFilter<RuntimeException>>(selector));
+ selector = new JMSSelectorFilter(selectorString);
+ _selectorCache.put(selectorString, new WeakReference<JMSSelectorFilter>(selector));
}
return selector;
}
@@ -480,7 +490,7 @@ public class TopicExchange extends AbstractExchange
{
routingKey = AMQShortString.EMPTY_STRING;
}
-
+
AMQShortStringTokenizer routingTokens = routingKey.tokenize(TOPIC_SEPARATOR);
List<AMQShortString> subscriptionList = new ArrayList<AMQShortString>();
@@ -525,10 +535,12 @@ public class TopicExchange extends AbstractExchange
return normalizedString;
}
- public void route(IncomingMessage payload) throws AMQException
+ public ArrayList<AMQQueue> route(InboundMessage payload)
{
- final AMQShortString routingKey = payload.getRoutingKey();
+ final AMQShortString routingKey = payload.getRoutingKey() == null
+ ? AMQShortString.EMPTY_STRING
+ : new AMQShortString(payload.getRoutingKey());
// The copy here is unfortunate, but not too bad relevant to the amount of
// things created and copied in getMatchedQueues
@@ -540,7 +552,7 @@ public class TopicExchange extends AbstractExchange
_logger.info("Message routing key: " + payload.getRoutingKey() + " No routes.");
}
- payload.enqueue(queues);
+ return queues;
}
@@ -562,7 +574,7 @@ public class TopicExchange extends AbstractExchange
{
return false;
}
-
+
}
}
@@ -630,20 +642,17 @@ public class TopicExchange extends AbstractExchange
}
- protected ExchangeMBean createMBean() throws AMQException
+ protected ExchangeMBean createMBean() throws JMException
{
- try
- {
- return new TopicExchangeMBean();
- }
- catch (JMException ex)
- {
- _logger.error("Exception occured in creating the topic exchenge mbean", ex);
- throw new AMQException("Exception occured in creating the topic exchenge mbean", ex);
- }
+ return new TopicExchangeMBean();
+ }
+
+ public Logger getLogger()
+ {
+ return _logger;
}
- private Collection<AMQQueue> getMatchedQueues(IncomingMessage message, AMQShortString routingKey)
+ private Collection<AMQQueue> getMatchedQueues(InboundMessage message, AMQShortString routingKey)
{
Collection<TopicMatcherResult> results = _parser.parse(routingKey);
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java
index a964bce306..2ead9e57af 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java
@@ -26,7 +26,7 @@ import org.apache.qpid.server.queue.Filterable;
/**
* An expression which performs an operation on two expression values
*/
-public abstract class ArithmeticExpression<E extends Exception> extends BinaryExpression<E>
+public abstract class ArithmeticExpression extends BinaryExpression
{
protected static final int INTEGER = 1;
@@ -248,7 +248,7 @@ public abstract class ArithmeticExpression<E extends Exception> extends BinaryEx
}
}
- public Object evaluate(Filterable<E> message) throws E
+ public Object evaluate(Filterable message)
{
Object lvalue = left.evaluate(message);
if (lvalue == null)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java
index 7308de80d6..024257bea9 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java
@@ -23,23 +23,23 @@ package org.apache.qpid.server.filter;
/**
* An expression which performs an operation on two expression values.
*/
-public abstract class BinaryExpression<E extends Exception> implements Expression<E>
+public abstract class BinaryExpression implements Expression
{
- protected Expression<E> left;
- protected Expression<E> right;
+ protected Expression left;
+ protected Expression right;
- public BinaryExpression(Expression<E> left, Expression<E> right)
+ public BinaryExpression(Expression left, Expression right)
{
this.left = left;
this.right = right;
}
- public Expression<E> getLeft()
+ public Expression getLeft()
{
return left;
}
- public Expression<E> getRight()
+ public Expression getRight()
{
return right;
}
@@ -90,7 +90,7 @@ public abstract class BinaryExpression<E extends Exception> implements Expressio
/**
* @param expression
*/
- public void setRight(Expression<E> expression)
+ public void setRight(Expression expression)
{
right = expression;
}
@@ -98,7 +98,7 @@ public abstract class BinaryExpression<E extends Exception> implements Expressio
/**
* @param expression
*/
- public void setLeft(Expression<E> expression)
+ public void setLeft(Expression expression)
{
left = expression;
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java
index 9beb9798d0..06e8664470 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java
@@ -20,22 +20,19 @@ package org.apache.qpid.server.filter;
// Based on like named file from r450141 of the Apache ActiveMQ project <http://www.activemq.org/site/home.html>
//
-import org.apache.qpid.AMQException;
-import org.apache.qpid.server.queue.AMQMessage;
import org.apache.qpid.server.queue.Filterable;
/**
* A BooleanExpression is an expression that always
* produces a Boolean result.
*/
-public interface BooleanExpression<E extends Exception> extends Expression<E>
+public interface BooleanExpression extends Expression
{
/**
* @param message
* @return true if the expression evaluates to Boolean.TRUE.
- * @throws E
*/
- public boolean matches(Filterable<E> message) throws E;
+ public boolean matches(Filterable message);
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java
index 921005c462..f0650cb642 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java
@@ -27,22 +27,20 @@ import java.util.HashSet;
import java.util.List;
import java.util.regex.Pattern;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.server.queue.AMQMessage;
import org.apache.qpid.server.queue.Filterable;
/**
* A filter performing a comparison of two objects
*/
-public abstract class ComparisonExpression<E extends Exception> extends BinaryExpression<E> implements BooleanExpression<E>
+public abstract class ComparisonExpression extends BinaryExpression implements BooleanExpression
{
- public static<E extends Exception> BooleanExpression<E> createBetween(Expression<E> value, Expression left, Expression<E> right)
+ public static BooleanExpression createBetween(Expression value, Expression left, Expression right)
{
return LogicExpression.createAND(createGreaterThanEqual(value, left), createLessThanEqual(value, right));
}
- public static<E extends Exception> BooleanExpression<E> createNotBetween(Expression<E> value, Expression<E> left, Expression<E> right)
+ public static BooleanExpression createNotBetween(Expression value, Expression left, Expression right)
{
return LogicExpression.createOR(createLessThan(value, left), createGreaterThan(value, right));
}
@@ -73,7 +71,7 @@ public abstract class ComparisonExpression<E extends Exception> extends BinaryEx
REGEXP_CONTROL_CHARS.add(new Character('!'));
}
- static class LikeExpression<E extends Exception> extends UnaryExpression<E> implements BooleanExpression<E>
+ static class LikeExpression extends UnaryExpression implements BooleanExpression
{
Pattern likePattern;
@@ -81,7 +79,7 @@ public abstract class ComparisonExpression<E extends Exception> extends BinaryEx
/**
* @param right
*/
- public LikeExpression(Expression<E> right, String like, int escape)
+ public LikeExpression(Expression right, String like, int escape)
{
super(right);
@@ -138,7 +136,7 @@ public abstract class ComparisonExpression<E extends Exception> extends BinaryEx
/**
* org.apache.activemq.filter.Expression#evaluate(MessageEvaluationContext)
*/
- public Object evaluate(Filterable<E> message) throws E
+ public Object evaluate(Filterable message)
{
Object rv = this.getRight().evaluate(message);
@@ -158,7 +156,7 @@ public abstract class ComparisonExpression<E extends Exception> extends BinaryEx
return likePattern.matcher((String) rv).matches() ? Boolean.TRUE : Boolean.FALSE;
}
- public boolean matches(Filterable<E> message) throws E
+ public boolean matches(Filterable message)
{
Object object = evaluate(message);
@@ -236,7 +234,7 @@ public abstract class ComparisonExpression<E extends Exception> extends BinaryEx
return doCreateEqual(left, right);
}
- private static<E extends Exception> BooleanExpression<E> doCreateEqual(Expression<E> left, Expression<E> right)
+ private static BooleanExpression doCreateEqual(Expression left, Expression right)
{
return new EqualExpression(left, right);
}
@@ -388,7 +386,7 @@ public abstract class ComparisonExpression<E extends Exception> extends BinaryEx
super(left, right);
}
- public Object evaluate(Filterable<E> message) throws E
+ public Object evaluate(Filterable message)
{
Comparable lv = (Comparable) left.evaluate(message);
if (lv == null)
@@ -550,21 +548,21 @@ public abstract class ComparisonExpression<E extends Exception> extends BinaryEx
protected abstract boolean asBoolean(int answer);
- public boolean matches(Filterable<E> message) throws E
+ public boolean matches(Filterable message)
{
Object object = evaluate(message);
return (object != null) && (object == Boolean.TRUE);
}
- private static class EqualExpression<E extends Exception> extends ComparisonExpression<E>
+ private static class EqualExpression extends ComparisonExpression
{
- public EqualExpression(final Expression<E> left, final Expression<E> right)
+ public EqualExpression(final Expression left, final Expression right)
{
super(left, right);
}
- public Object evaluate(Filterable<E> message) throws E
+ public Object evaluate(Filterable message)
{
Object lv = left.evaluate(message);
Object rv = right.evaluate(message);
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java
index 3ed2286f2e..15cb770216 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java
@@ -25,24 +25,22 @@ package org.apache.qpid.server.filter;
import java.math.BigDecimal;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.server.queue.AMQMessage;
import org.apache.qpid.server.queue.Filterable;
/**
* Represents a constant expression
*/
-public class ConstantExpression<E extends Exception> implements Expression<E>
+public class ConstantExpression implements Expression
{
- static class BooleanConstantExpression<E extends Exception> extends ConstantExpression<E> implements BooleanExpression<E>
+ static class BooleanConstantExpression extends ConstantExpression implements BooleanExpression
{
public BooleanConstantExpression(Object value)
{
super(value);
}
- public boolean matches(Filterable<E> message) throws E
+ public boolean matches(Filterable message)
{
Object object = evaluate(message);
@@ -121,7 +119,7 @@ public class ConstantExpression<E extends Exception> implements Expression<E>
this.value = value;
}
- public Object evaluate(Filterable<E> message) throws E
+ public Object evaluate(Filterable message)
{
return value;
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java
index f2ebe41d26..97e9915271 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java
@@ -20,19 +20,17 @@ package org.apache.qpid.server.filter;
// Based on like named file from r450141 of the Apache ActiveMQ project <http://www.activemq.org/site/home.html>
//
-import org.apache.qpid.AMQException;
-import org.apache.qpid.server.queue.AMQMessage;
import org.apache.qpid.server.queue.Filterable;
/**
* Represents an expression
*/
-public interface Expression<E extends Exception>
+public interface Expression
{
/**
* @return the value of this expression
*/
- public Object evaluate(Filterable<E> message) throws E;
+ public Object evaluate(Filterable message);
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java b/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java
index dd3c126ee5..b5e282038b 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java
@@ -14,26 +14,24 @@
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
- * under the License.
+ * under the License.
+ *
*
- *
*/
package org.apache.qpid.server.filter;
//
// Based on like named file from r450141 of the Apache ActiveMQ project <http://www.activemq.org/site/home.html>
//
-import org.apache.qpid.server.queue.AMQMessage;
import org.apache.qpid.server.queue.Filterable;
-import org.apache.qpid.AMQException;
-public interface FilterManager<E extends Exception>
+public interface FilterManager
{
- void add(MessageFilter<E> filter);
+ void add(MessageFilter filter);
- void remove(MessageFilter<E> filter);
+ void remove(MessageFilter filter);
- boolean allAllow(Filterable<E> msg);
+ boolean allAllow(Filterable msg);
boolean hasFilters();
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java b/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java
index 96c9353872..dacd047fea 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java
@@ -26,12 +26,12 @@ import org.apache.qpid.server.filter.jms.selector.SelectorParser;
import org.apache.qpid.server.queue.Filterable;
-public class JMSSelectorFilter<E extends Exception> implements MessageFilter<E>
+public class JMSSelectorFilter implements MessageFilter
{
private final static Logger _logger = org.apache.log4j.Logger.getLogger(JMSSelectorFilter.class);
private String _selector;
- private BooleanExpression<E> _matcher;
+ private BooleanExpression _matcher;
public JMSSelectorFilter(String selector) throws AMQException
{
@@ -39,7 +39,7 @@ public class JMSSelectorFilter<E extends Exception> implements MessageFilter<E>
_matcher = new SelectorParser().parse(selector);
}
- public boolean matches(Filterable<E> message) throws E
+ public boolean matches(Filterable message)
{
boolean match = _matcher.matches(message);
if(_logger.isDebugEnabled())
@@ -53,4 +53,10 @@ public class JMSSelectorFilter<E extends Exception> implements MessageFilter<E>
{
return _selector;
}
+
+ @Override
+ public String toString()
+ {
+ return "JMSSelector("+_selector+")";
+ }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java
index 094363ed9a..fdba184da4 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java
@@ -20,22 +20,20 @@ package org.apache.qpid.server.filter;
// Based on like named file from r450141 of the Apache ActiveMQ project <http://www.activemq.org/site/home.html>
//
-import org.apache.qpid.AMQException;
-import org.apache.qpid.server.queue.AMQMessage;
import org.apache.qpid.server.queue.Filterable;
/**
* A filter performing a comparison of two objects
*/
-public abstract class LogicExpression<E extends Exception> extends BinaryExpression<E> implements BooleanExpression<E>
+public abstract class LogicExpression extends BinaryExpression implements BooleanExpression
{
- public static<E extends Exception> BooleanExpression createOR(BooleanExpression<E> lvalue, BooleanExpression<E> rvalue)
+ public static BooleanExpression createOR(BooleanExpression lvalue, BooleanExpression rvalue)
{
return new OrExpression(lvalue, rvalue);
}
- public static<E extends Exception> BooleanExpression createAND(BooleanExpression<E> lvalue, BooleanExpression<E> rvalue)
+ public static BooleanExpression createAND(BooleanExpression lvalue, BooleanExpression rvalue)
{
return new AndExpression(lvalue, rvalue);
}
@@ -49,23 +47,23 @@ public abstract class LogicExpression<E extends Exception> extends BinaryExpress
super(left, right);
}
- public abstract Object evaluate(Filterable<E> message) throws E;
+ public abstract Object evaluate(Filterable message);
- public boolean matches(Filterable<E> message) throws E
+ public boolean matches(Filterable message)
{
Object object = evaluate(message);
return (object != null) && (object == Boolean.TRUE);
}
- private static class OrExpression<E extends Exception> extends LogicExpression<E>
+ private static class OrExpression extends LogicExpression
{
- public OrExpression(final BooleanExpression<E> lvalue, final BooleanExpression<E> rvalue)
+ public OrExpression(final BooleanExpression lvalue, final BooleanExpression rvalue)
{
super(lvalue, rvalue);
}
- public Object evaluate(Filterable<E> message) throws E
+ public Object evaluate(Filterable message)
{
Boolean lv = (Boolean) left.evaluate(message);
@@ -86,14 +84,14 @@ public abstract class LogicExpression<E extends Exception> extends BinaryExpress
}
}
- private static class AndExpression<E extends Exception> extends LogicExpression<E>
+ private static class AndExpression extends LogicExpression
{
- public AndExpression(final BooleanExpression<E> lvalue, final BooleanExpression<E> rvalue)
+ public AndExpression(final BooleanExpression lvalue, final BooleanExpression rvalue)
{
super(lvalue, rvalue);
}
- public Object evaluate(Filterable<E> message) throws E
+ public Object evaluate(Filterable message)
{
Boolean lv = (Boolean) left.evaluate(message);
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java b/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java
index 58fc55f8e6..f5416af09a 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java
@@ -14,17 +14,15 @@
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
- * under the License.
+ * under the License.
+ *
*
- *
*/
package org.apache.qpid.server.filter;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.server.queue.AMQMessage;
import org.apache.qpid.server.queue.Filterable;
-public interface MessageFilter<E extends Exception>
+public interface MessageFilter
{
- boolean matches(Filterable<E> message) throws E;
+ boolean matches(Filterable message);
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java b/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java
index f1b3b2511d..65ddf19fc4 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/NoConsumerFilter.java
@@ -39,4 +39,10 @@ public class NoConsumerFilter implements MessageFilter
return true;
}
+ @Override
+ public String toString()
+ {
+ return "NoConsumer";
+ }
+
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java
index b30c70dac3..11fdeae2b1 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java
@@ -27,7 +27,6 @@ import java.util.HashMap;
import org.apache.log4j.Logger;
-import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.CommonContentHeaderProperties;
import org.apache.qpid.server.queue.Filterable;
@@ -35,7 +34,7 @@ import org.apache.qpid.server.queue.Filterable;
/**
* Represents a property expression
*/
-public class PropertyExpression<E extends Exception> implements Expression<E>
+public class PropertyExpression implements Expression
{
// Constants - defined the same as JMS
private static final int NON_PERSISTENT = 1;
@@ -44,12 +43,12 @@ public class PropertyExpression<E extends Exception> implements Expression<E>
private static final Logger _logger = org.apache.log4j.Logger.getLogger(PropertyExpression.class);
- private static final HashMap<String, Expression<? extends Exception>> JMS_PROPERTY_EXPRESSIONS = new HashMap<String, Expression<? extends Exception>>();
+ private static final HashMap<String, Expression> JMS_PROPERTY_EXPRESSIONS = new HashMap<String, Expression>();
{
- JMS_PROPERTY_EXPRESSIONS.put("JMSDestination", new Expression<E>()
+ JMS_PROPERTY_EXPRESSIONS.put("JMSDestination", new Expression()
{
- public Object evaluate(Filterable<E> message)
+ public Object evaluate(Filterable message)
{
//TODO
return null;
@@ -63,6 +62,8 @@ public class PropertyExpression<E extends Exception> implements Expression<E>
JMS_PROPERTY_EXPRESSIONS.put("JMSPriority", new PriorityExpression());
+ JMS_PROPERTY_EXPRESSIONS.put("JMSMessageID", new MessageIDExpression());
+
JMS_PROPERTY_EXPRESSIONS.put("AMQMessageID", new MessageIDExpression());
JMS_PROPERTY_EXPRESSIONS.put("JMSTimestamp", new TimestampExpression());
@@ -71,9 +72,9 @@ public class PropertyExpression<E extends Exception> implements Expression<E>
JMS_PROPERTY_EXPRESSIONS.put("JMSExpiration", new ExpirationExpression());
- JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", new Expression<E>()
+ JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", new Expression()
{
- public Object evaluate(Filterable message) throws E
+ public Object evaluate(Filterable message)
{
return message.isRedelivered();
}
@@ -81,7 +82,7 @@ public class PropertyExpression<E extends Exception> implements Expression<E>
}
private final String name;
- private final Expression<E> jmsPropertyExpression;
+ private final Expression jmsPropertyExpression;
public boolean outerTest()
{
@@ -94,10 +95,10 @@ public class PropertyExpression<E extends Exception> implements Expression<E>
- jmsPropertyExpression = (Expression<E>) JMS_PROPERTY_EXPRESSIONS.get(name);
+ jmsPropertyExpression = (Expression) JMS_PROPERTY_EXPRESSIONS.get(name);
}
- public Object evaluate(Filterable<E> message) throws E
+ public Object evaluate(Filterable message)
{
if (jmsPropertyExpression != null)
@@ -106,17 +107,7 @@ public class PropertyExpression<E extends Exception> implements Expression<E>
}
else
{
-
- CommonContentHeaderProperties _properties =
- (CommonContentHeaderProperties) message.getContentHeaderBody().properties;
-
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Looking up property:" + name);
- _logger.debug("Properties are:" + _properties.getHeaders().keySet());
- }
-
- return _properties.getHeaders().getObject(name);
+ return message.getMessageHeader().getHeader(name);
}
}
@@ -156,39 +147,30 @@ public class PropertyExpression<E extends Exception> implements Expression<E>
}
- private static class ReplyToExpression<E extends Exception> implements Expression<E>
+ private static class ReplyToExpression implements Expression
{
- public Object evaluate(Filterable<E> message) throws E
+ public Object evaluate(Filterable message)
{
-
- CommonContentHeaderProperties _properties =
- (CommonContentHeaderProperties)
- message.getContentHeaderBody().properties;
- AMQShortString replyTo = _properties.getReplyTo();
-
- return (replyTo == null) ? null : replyTo.toString();
-
+ String replyTo = message.getMessageHeader().getReplyTo();
+ return replyTo;
}
}
- private static class TypeExpression<E extends Exception> implements Expression<E>
+ private static class TypeExpression implements Expression
{
- public Object evaluate(Filterable<E> message) throws E
+ public Object evaluate(Filterable message)
{
- CommonContentHeaderProperties _properties =
- (CommonContentHeaderProperties)
- message.getContentHeaderBody().properties;
- AMQShortString type = _properties.getType();
- return (type == null) ? null : type.toString();
+ String type = message.getMessageHeader().getType();
+ return type;
}
}
- private static class DeliveryModeExpression<E extends Exception> implements Expression<E>
+ private static class DeliveryModeExpression implements Expression
{
- public Object evaluate(Filterable<E> message) throws E
+ public Object evaluate(Filterable message)
{
int mode = message.isPersistent() ? PERSISTENT : NON_PERSISTENT;
if (_logger.isDebugEnabled())
@@ -200,68 +182,53 @@ public class PropertyExpression<E extends Exception> implements Expression<E>
}
}
- private static class PriorityExpression<E extends Exception> implements Expression<E>
+ private static class PriorityExpression implements Expression
{
- public Object evaluate(Filterable<E> message) throws E
+ public Object evaluate(Filterable message)
{
- CommonContentHeaderProperties _properties =
- (CommonContentHeaderProperties)
- message.getContentHeaderBody().properties;
-
- return (int) _properties.getPriority();
+ byte priority = message.getMessageHeader().getPriority();
+ return (int) priority;
}
}
- private static class MessageIDExpression<E extends Exception> implements Expression<E>
+ private static class MessageIDExpression implements Expression
{
- public Object evaluate(Filterable<E> message) throws E
+ public Object evaluate(Filterable message)
{
- CommonContentHeaderProperties _properties =
- (CommonContentHeaderProperties)
- message.getContentHeaderBody().properties;
- AMQShortString messageId = _properties.getMessageId();
+ String messageId = message.getMessageHeader().getMessageId();
- return (messageId == null) ? null : messageId;
+ return messageId;
}
}
- private static class TimestampExpression<E extends Exception> implements Expression<E>
+ private static class TimestampExpression implements Expression
{
- public Object evaluate(Filterable<E> message) throws E
+ public Object evaluate(Filterable message)
{
- CommonContentHeaderProperties _properties =
- (CommonContentHeaderProperties)
- message.getContentHeaderBody().properties;
-
- return _properties.getTimestamp();
+ long timestamp = message.getMessageHeader().getTimestamp();
+ return timestamp;
}
}
- private static class CorrelationIdExpression<E extends Exception> implements Expression<E>
+ private static class CorrelationIdExpression implements Expression
{
- public Object evaluate(Filterable<E> message) throws E
+ public Object evaluate(Filterable message)
{
- CommonContentHeaderProperties _properties =
- (CommonContentHeaderProperties)
- message.getContentHeaderBody().properties;
- AMQShortString correlationId = _properties.getCorrelationId();
- return (correlationId == null) ? null : correlationId.toString();
+ String correlationId = message.getMessageHeader().getCorrelationId();
+
+ return correlationId;
}
}
- private static class ExpirationExpression<E extends Exception> implements Expression<E>
+ private static class ExpirationExpression implements Expression
{
- public Object evaluate(Filterable<E> message) throws E
+ public Object evaluate(Filterable message)
{
-
- CommonContentHeaderProperties _properties =
- (CommonContentHeaderProperties)
- message.getContentHeaderBody().properties;
-
- return _properties.getExpiration();
+ long expiration = message.getMessageHeader().getExpiration();
+ return expiration;
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java b/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java
index cb738e1489..c563569cb4 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java
@@ -24,46 +24,39 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
-import org.apache.qpid.server.queue.AMQMessage;
import org.apache.qpid.server.queue.Filterable;
-public class SimpleFilterManager implements FilterManager<AMQException>
+public class SimpleFilterManager implements FilterManager
{
private final Logger _logger = Logger.getLogger(SimpleFilterManager.class);
- private final ConcurrentLinkedQueue<MessageFilter<AMQException>> _filters;
+ private final ConcurrentLinkedQueue<MessageFilter> _filters;
+ private String _toString = "";
public SimpleFilterManager()
{
_logger.debug("Creating SimpleFilterManager");
- _filters = new ConcurrentLinkedQueue<MessageFilter<AMQException>>();
+ _filters = new ConcurrentLinkedQueue<MessageFilter>();
}
- public void add(MessageFilter<AMQException> filter)
+ public void add(MessageFilter filter)
{
_filters.add(filter);
+ updateStringValue();
}
- public void remove(MessageFilter<AMQException> filter)
+ public void remove(MessageFilter filter)
{
_filters.remove(filter);
+ updateStringValue();
}
- public boolean allAllow(Filterable<AMQException> msg)
+ public boolean allAllow(Filterable msg)
{
- for (MessageFilter<AMQException> filter : _filters)
+ for (MessageFilter filter : _filters)
{
- try
+ if (!filter.matches(msg))
{
- if (!filter.matches(msg))
- {
- return false;
- }
- }
- catch (AMQException e)
- {
- //fixme
- e.printStackTrace();
return false;
}
}
@@ -74,4 +67,28 @@ public class SimpleFilterManager implements FilterManager<AMQException>
{
return !_filters.isEmpty();
}
+
+
+ @Override
+ public String toString()
+ {
+ return _toString;
+ }
+
+ private void updateStringValue()
+ {
+ StringBuilder toString = new StringBuilder();
+ for (MessageFilter filter : _filters)
+ {
+ toString.append(filter.toString());
+ toString.append(",");
+ }
+
+ if (_filters.size() > 0)
+ {
+ //Remove the last ','
+ toString.deleteCharAt(toString.length()-1);
+ }
+ _toString = toString.toString();
+ }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java
index 799a38af5a..9e03ecd8bd 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java
@@ -35,18 +35,18 @@ import org.apache.qpid.server.queue.Filterable;
/**
* An expression which performs an operation on two expression values
*/
-public abstract class UnaryExpression<E extends Exception> implements Expression<E>
+public abstract class UnaryExpression implements Expression
{
private static final BigDecimal BD_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE);
- protected Expression<E> right;
+ protected Expression right;
- public static<E extends Exception> Expression<E> createNegate(Expression<E> left)
+ public static Expression createNegate(Expression left)
{
return new NegativeExpression(left);
}
- public static<E extends Exception> BooleanExpression createInExpression(PropertyExpression<E> right, List elements, final boolean not)
+ public static BooleanExpression createInExpression(PropertyExpression right, List elements, final boolean not)
{
// Use a HashSet if there are many elements.
@@ -69,14 +69,14 @@ public abstract class UnaryExpression<E extends Exception> implements Expression
return new InExpression(right, inList, not);
}
- abstract static class BooleanUnaryExpression<E extends Exception> extends UnaryExpression<E> implements BooleanExpression<E>
+ abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression
{
- public BooleanUnaryExpression(Expression<E> left)
+ public BooleanUnaryExpression(Expression left)
{
super(left);
}
- public boolean matches(Filterable<E> message) throws E
+ public boolean matches(Filterable message)
{
Object object = evaluate(message);
@@ -85,7 +85,7 @@ public abstract class UnaryExpression<E extends Exception> implements Expression
}
;
- public static<E extends Exception> BooleanExpression<E> createNOT(BooleanExpression<E> left)
+ public static<E extends Exception> BooleanExpression createNOT(BooleanExpression left)
{
return new NotExpression(left);
}
@@ -100,7 +100,7 @@ public abstract class UnaryExpression<E extends Exception> implements Expression
return new XQueryExpression(xpath);
}
- public static<E extends Exception> BooleanExpression createBooleanCast(Expression<E> left)
+ public static<E extends Exception> BooleanExpression createBooleanCast(Expression left)
{
return new BooleanCastExpression(left);
}
@@ -151,7 +151,7 @@ public abstract class UnaryExpression<E extends Exception> implements Expression
this.right = left;
}
- public Expression<E> getRight()
+ public Expression getRight()
{
return right;
}
@@ -204,14 +204,14 @@ public abstract class UnaryExpression<E extends Exception> implements Expression
*/
public abstract String getExpressionSymbol();
- private static class NegativeExpression<E extends Exception> extends UnaryExpression<E>
+ private static class NegativeExpression extends UnaryExpression
{
- public NegativeExpression(final Expression<E> left)
+ public NegativeExpression(final Expression left)
{
super(left);
}
- public Object evaluate(Filterable<E> message) throws E
+ public Object evaluate(Filterable message)
{
Object rvalue = right.evaluate(message);
if (rvalue == null)
@@ -233,19 +233,19 @@ public abstract class UnaryExpression<E extends Exception> implements Expression
}
}
- private static class InExpression<E extends Exception> extends BooleanUnaryExpression<E>
+ private static class InExpression extends BooleanUnaryExpression
{
private final Collection _inList;
private final boolean _not;
- public InExpression(final PropertyExpression<E> right, final Collection inList, final boolean not)
+ public InExpression(final PropertyExpression right, final Collection inList, final boolean not)
{
super(right);
_inList = inList;
_not = not;
}
- public Object evaluate(Filterable<E> message) throws E
+ public Object evaluate(Filterable message)
{
Object rvalue = right.evaluate(message);
@@ -309,14 +309,14 @@ public abstract class UnaryExpression<E extends Exception> implements Expression
}
}
- private static class NotExpression<E extends Exception> extends BooleanUnaryExpression<E>
+ private static class NotExpression extends BooleanUnaryExpression
{
- public NotExpression(final BooleanExpression<E> left)
+ public NotExpression(final BooleanExpression left)
{
super(left);
}
- public Object evaluate(Filterable<E> message) throws E
+ public Object evaluate(Filterable message)
{
Boolean lvalue = (Boolean) right.evaluate(message);
if (lvalue == null)
@@ -333,14 +333,14 @@ public abstract class UnaryExpression<E extends Exception> implements Expression
}
}
- private static class BooleanCastExpression<E extends Exception> extends BooleanUnaryExpression<E>
+ private static class BooleanCastExpression extends BooleanUnaryExpression
{
- public BooleanCastExpression(final Expression<E> left)
+ public BooleanCastExpression(final Expression left)
{
super(left);
}
- public Object evaluate(Filterable<E> message) throws E
+ public Object evaluate(Filterable message)
{
Object rvalue = right.evaluate(message);
if (rvalue == null)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java
index 1311178fb1..aa35cb5a76 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java
@@ -22,7 +22,6 @@ package org.apache.qpid.server.filter;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
-import org.apache.qpid.server.queue.AMQMessage;
import org.apache.qpid.server.queue.Filterable;
import java.lang.reflect.Constructor;
@@ -71,7 +70,7 @@ public final class XPathExpression implements BooleanExpression {
private final XPathEvaluator evaluator;
static public interface XPathEvaluator {
- public boolean evaluate(Filterable message) throws AMQException;
+ public boolean evaluate(Filterable message);
}
XPathExpression(String xpath) {
@@ -93,7 +92,7 @@ public final class XPathExpression implements BooleanExpression {
}
}
- public Object evaluate(Filterable message) throws AMQException {
+ public Object evaluate(Filterable message) {
// try {
//FIXME this is flow to disk work
// if( message.isDropped() )
@@ -118,7 +117,7 @@ public final class XPathExpression implements BooleanExpression {
* @return true if the expression evaluates to Boolean.TRUE.
* @throws AMQException
*/
- public boolean matches(Filterable message) throws AMQException
+ public boolean matches(Filterable message)
{
Object object = evaluate(message);
return object!=null && object==Boolean.TRUE;
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java b/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java
index c13f81cd08..ae22f17413 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java
@@ -18,7 +18,6 @@
package org.apache.qpid.server.filter;
import org.apache.qpid.AMQException;
-import org.apache.qpid.server.queue.AMQMessage;
import org.apache.qpid.server.queue.Filterable;
//
@@ -36,23 +35,23 @@ public final class XQueryExpression implements BooleanExpression {
this.xpath = xpath;
}
- public Object evaluate(Filterable message) throws AMQException {
+ public Object evaluate(Filterable message) {
return Boolean.FALSE;
}
public String toString() {
return "XQUERY "+ConstantExpression.encodeString(xpath);
}
-
+
/**
* @param message
* @return true if the expression evaluates to Boolean.TRUE.
* @throws AMQException
*/
- public boolean matches(Filterable message) throws AMQException
+ public boolean matches(Filterable message)
{
Object object = evaluate(message);
- return object!=null && object==Boolean.TRUE;
+ return object!=null && object==Boolean.TRUE;
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java b/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java
index cc67776682..f83eb63ac5 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java
@@ -27,8 +27,6 @@ import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.server.queue.AMQMessage;
import org.apache.qpid.server.queue.Filterable;
import org.apache.xpath.CachedXPathAPI;
import org.w3c.dom.Document;
@@ -36,14 +34,14 @@ import org.w3c.dom.traversal.NodeIterator;
import org.xml.sax.InputSource;
public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator {
-
+
private final String xpath;
public XalanXPathEvaluator(String xpath) {
this.xpath = xpath;
}
-
- public boolean evaluate(Filterable m) throws AMQException
+
+ public boolean evaluate(Filterable m)
{
// TODO - we would have to check the content type and then evaluate the content
// here... is this really a feature we wish to implement? - RobG
@@ -65,18 +63,18 @@ public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator {
private boolean evaluate(byte[] data) {
try {
-
+
InputSource inputSource = new InputSource(new ByteArrayInputStream(data));
-
+
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder dbuilder = factory.newDocumentBuilder();
Document doc = dbuilder.parse(inputSource);
-
+
CachedXPathAPI cachedXPathAPI = new CachedXPathAPI();
NodeIterator iterator = cachedXPathAPI.selectNodeIterator(doc,xpath);
return iterator.nextNode()!=null;
-
+
} catch (Throwable e) {
return false;
}
@@ -85,12 +83,12 @@ public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator {
private boolean evaluate(String text) {
try {
InputSource inputSource = new InputSource(new StringReader(text));
-
+
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder dbuilder = factory.newDocumentBuilder();
Document doc = dbuilder.parse(inputSource);
-
+
// We should associated the cachedXPathAPI object with the message being evaluated
// since that should speedup subsequent xpath expressions.
CachedXPathAPI cachedXPathAPI = new CachedXPathAPI();
diff --git a/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java b/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java
index 895db7b15b..cfe5aedd61 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java
@@ -31,19 +31,28 @@ public abstract class AbstractFlowCreditManager implements FlowCreditManager
public final void addStateListener(FlowCreditManagerListener listener)
{
- _listeners.add(listener);
+ synchronized(_listeners)
+ {
+ _listeners.add(listener);
+ }
}
public final boolean removeListener(FlowCreditManagerListener listener)
{
- return _listeners.remove(listener);
+ synchronized(_listeners)
+ {
+ return _listeners.remove(listener);
+ }
}
private void notifyListeners(final boolean suspended)
{
- for(FlowCreditManagerListener listener : _listeners)
+ synchronized(_listeners)
{
- listener.creditStateChanged(!suspended);
+ for(FlowCreditManagerListener listener : _listeners)
+ {
+ listener.creditStateChanged(!suspended);
+ }
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java b/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java
index 96a1071135..c5f2d1e808 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java
@@ -1,11 +1,8 @@
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.message.ServerMessage;
import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.Set;
-import java.util.HashSet;
/*
*
@@ -36,7 +33,17 @@ public class BytesOnlyCreditManager extends AbstractFlowCreditManager
_bytesCredit = new AtomicLong(initialCredit);
}
- public void addCredit(long messageCredit, long bytesCredit)
+ public long getMessageCredit()
+ {
+ return -1L;
+ }
+
+ public long getBytesCredit()
+ {
+ return _bytesCredit.get();
+ }
+
+ public void restoreCredit(long messageCredit, long bytesCredit)
{
_bytesCredit.addAndGet(bytesCredit);
setSuspended(false);
@@ -52,7 +59,7 @@ public class BytesOnlyCreditManager extends AbstractFlowCreditManager
return _bytesCredit.get() > 0L;
}
- public boolean useCreditForMessage(AMQMessage msg)
+ public boolean useCreditForMessage(ServerMessage msg)
{
final long msgSize = msg.getSize();
if(hasCredit())
@@ -74,4 +81,9 @@ public class BytesOnlyCreditManager extends AbstractFlowCreditManager
}
}
+
+ public void setBytesCredit(long bytesCredit)
+ {
+ _bytesCredit.set( bytesCredit );
+ }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/flow/CreditCreditManager.java b/java/broker/src/main/java/org/apache/qpid/server/flow/CreditCreditManager.java
new file mode 100644
index 0000000000..b47f986155
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/flow/CreditCreditManager.java
@@ -0,0 +1,188 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.flow;
+
+import org.apache.qpid.server.message.ServerMessage;
+
+public class CreditCreditManager extends AbstractFlowCreditManager implements FlowCreditManager_0_10
+{
+ private volatile long _bytesCredit;
+ private volatile long _messageCredit;
+
+
+ public CreditCreditManager()
+ {
+ this(0L, 0L);
+ }
+
+ public CreditCreditManager(long bytesCredit, long messageCredit)
+ {
+ _bytesCredit = bytesCredit;
+ _messageCredit = messageCredit;
+ setSuspended(!hasCredit());
+
+ }
+
+
+ public synchronized void setCreditLimits(final long bytesCredit, final long messageCredit)
+ {
+ _bytesCredit = bytesCredit;
+ _messageCredit = messageCredit;
+
+ setSuspended(!hasCredit());
+
+ }
+
+
+ public long getMessageCredit()
+ {
+ return _messageCredit == -1L
+ ? Long.MAX_VALUE
+ : _messageCredit;
+ }
+
+ public long getBytesCredit()
+ {
+ return _bytesCredit == -1L
+ ? Long.MAX_VALUE
+ : _bytesCredit;
+ }
+
+ public synchronized void restoreCredit(final long messageCredit, final long bytesCredit)
+ {
+ /*_bytesCredit = 0l;
+ _messageCredit = 0l;
+ setSuspended(true);*/
+ }
+
+
+ public synchronized void addCredit(final long messageCredit, final long bytesCredit)
+ {
+ boolean notifyIncrease = true;
+ if(_messageCredit >= 0L && messageCredit > 0L)
+ {
+ notifyIncrease = _messageCredit != 0L;
+ _messageCredit += messageCredit;
+ }
+
+
+
+ if(_bytesCredit >= 0L && bytesCredit > 0L)
+ {
+ notifyIncrease = notifyIncrease && bytesCredit>0;
+ _bytesCredit += bytesCredit;
+
+
+
+ if(notifyIncrease)
+ {
+ notifyIncreaseBytesCredit();
+ }
+ }
+
+
+
+ setSuspended(!hasCredit());
+
+ }
+
+ public void clearCredit()
+ {
+ _bytesCredit = 0l;
+ _messageCredit = 0l;
+ setSuspended(true);
+ }
+
+
+ public synchronized boolean hasCredit()
+ {
+ // Note !=, if credit is < 0 that indicates infinite credit
+ return (_bytesCredit != 0L && _messageCredit != 0L);
+ }
+
+ public synchronized boolean useCreditForMessage(final ServerMessage msg)
+ {
+ if(_messageCredit >= 0L)
+ {
+ if(_messageCredit > 0)
+ {
+ if(_bytesCredit < 0L)
+ {
+ _messageCredit--;
+
+ return true;
+ }
+ else if(msg.getSize() <= _bytesCredit)
+ {
+ _messageCredit--;
+ _bytesCredit -= msg.getSize();
+
+ return true;
+ }
+ else
+ {
+ //setSuspended(true);
+ return false;
+ }
+ }
+ else
+ {
+ setSuspended(true);
+ return false;
+ }
+ }
+ else if(_bytesCredit >= 0L)
+ {
+ if(msg.getSize() <= _bytesCredit)
+ {
+ _bytesCredit -= msg.getSize();
+
+ return true;
+ }
+ else
+ {
+ //setSuspended(true);
+ return false;
+ }
+
+ }
+ else
+ {
+ return true;
+ }
+
+ }
+
+ public synchronized void stop()
+ {
+ if(_bytesCredit > 0)
+ {
+ _bytesCredit = 0;
+ }
+ if(_messageCredit > 0)
+ {
+ _messageCredit = 0;
+ }
+
+ }
+
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java b/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java
index a249a6e63a..bec51d361d 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java
@@ -1,6 +1,6 @@
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.message.ServerMessage;
/*
*
@@ -24,6 +24,9 @@ import org.apache.qpid.server.queue.AMQMessage;
*/
public interface FlowCreditManager
{
+ long getMessageCredit();
+
+ long getBytesCredit();
public static interface FlowCreditManagerListener
{
@@ -34,11 +37,10 @@ public interface FlowCreditManager
boolean removeListener(FlowCreditManagerListener listener);
- public void addCredit(long messageCredit, long bytesCredit);
-
- public void removeAllCredit();
+ public void restoreCredit(long messageCredit, long bytesCredit);
public boolean hasCredit();
- public boolean useCreditForMessage(AMQMessage msg);
+ public boolean useCreditForMessage(ServerMessage msg);
+
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager_0_10.java b/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager_0_10.java
new file mode 100755
index 0000000000..48c336c0b1
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager_0_10.java
@@ -0,0 +1,28 @@
+package org.apache.qpid.server.flow;
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+public interface FlowCreditManager_0_10 extends FlowCreditManager
+{
+ public void addCredit(long count, long bytes);
+
+ void clearCredit();
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java b/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java
index d63431c3eb..901b71fd1f 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java
@@ -1,6 +1,6 @@
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.message.ServerMessage;
/*
*
@@ -24,7 +24,17 @@ import org.apache.qpid.server.queue.AMQMessage;
*/
public class LimitlessCreditManager extends AbstractFlowCreditManager implements FlowCreditManager
{
- public void addCredit(long messageCredit, long bytesCredit)
+ public long getMessageCredit()
+ {
+ return -1L;
+ }
+
+ public long getBytesCredit()
+ {
+ return -1L;
+ }
+
+ public void restoreCredit(long messageCredit, long bytesCredit)
{
}
@@ -37,7 +47,7 @@ public class LimitlessCreditManager extends AbstractFlowCreditManager implements
return true;
}
- public boolean useCreditForMessage(AMQMessage msg)
+ public boolean useCreditForMessage(ServerMessage msg)
{
return true;
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java b/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java
index 9c377481de..19a9ac1d23 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java
@@ -1,8 +1,6 @@
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.queue.AMQMessage;
-
-import java.util.concurrent.atomic.AtomicLong;
+import org.apache.qpid.server.message.ServerMessage;
/*
*
@@ -29,14 +27,24 @@ public class MessageAndBytesCreditManager extends AbstractFlowCreditManager impl
private long _messageCredit;
private long _bytesCredit;
- MessageAndBytesCreditManager(final long messageCredit, final long bytesCredit)
+ public MessageAndBytesCreditManager(final long messageCredit, final long bytesCredit)
{
_messageCredit = messageCredit;
_bytesCredit = bytesCredit;
}
- public synchronized void addCredit(long messageCredit, long bytesCredit)
+ public synchronized long getMessageCredit()
{
+ return _messageCredit;
+ }
+
+ public synchronized long getBytesCredit()
+ {
+ return _bytesCredit;
+ }
+
+ public synchronized void restoreCredit(long messageCredit, long bytesCredit)
+ {
_messageCredit += messageCredit;
_bytesCredit += bytesCredit;
setSuspended(hasCredit());
@@ -54,7 +62,7 @@ public class MessageAndBytesCreditManager extends AbstractFlowCreditManager impl
return (_messageCredit > 0L) && ( _bytesCredit > 0L );
}
- public synchronized boolean useCreditForMessage(AMQMessage msg)
+ public synchronized boolean useCreditForMessage(ServerMessage msg)
{
if(_messageCredit == 0L)
{
@@ -76,4 +84,9 @@ public class MessageAndBytesCreditManager extends AbstractFlowCreditManager impl
}
}
+
+ public synchronized void setBytesCredit(long bytesCredit)
+ {
+ _bytesCredit = bytesCredit;
+ }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java b/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java
index c1b3a09006..a386f66b11 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java
@@ -1,6 +1,6 @@
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.message.ServerMessage;
import java.util.concurrent.atomic.AtomicLong;
@@ -33,10 +33,21 @@ public class MessageOnlyCreditManager extends AbstractFlowCreditManager implemen
_messageCredit = new AtomicLong(initialCredit);
}
- public void addCredit(long messageCredit, long bytesCredit)
+ public long getMessageCredit()
+ {
+ return _messageCredit.get();
+ }
+
+ public long getBytesCredit()
+ {
+ return -1L;
+ }
+
+ public void restoreCredit(long messageCredit, long bytesCredit)
{
- setSuspended(false);
_messageCredit.addAndGet(messageCredit);
+ setSuspended(false);
+
}
public void removeAllCredit()
@@ -50,7 +61,7 @@ public class MessageOnlyCreditManager extends AbstractFlowCreditManager implemen
return _messageCredit.get() > 0L;
}
- public boolean useCreditForMessage(AMQMessage msg)
+ public boolean useCreditForMessage(ServerMessage msg)
{
if(hasCredit())
{
@@ -73,4 +84,5 @@ public class MessageOnlyCreditManager extends AbstractFlowCreditManager implemen
}
}
+
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java b/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java
index be0300f2c1..026804439c 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java
@@ -20,7 +20,7 @@
*/
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.message.ServerMessage;
public class Pre0_10CreditManager extends AbstractFlowCreditManager implements FlowCreditManager
{
@@ -81,7 +81,17 @@ public class Pre0_10CreditManager extends AbstractFlowCreditManager implements F
}
- public synchronized void addCredit(final long messageCredit, final long bytesCredit)
+ public long getMessageCredit()
+ {
+ return _messageCredit;
+ }
+
+ public long getBytesCredit()
+ {
+ return _bytesCredit;
+ }
+
+ public synchronized void restoreCredit(final long messageCredit, final long bytesCredit)
{
final long messageCreditLimit = _messageCreditLimit;
boolean notifyIncrease = true;
@@ -123,7 +133,7 @@ public class Pre0_10CreditManager extends AbstractFlowCreditManager implements F
&& (_messageCreditLimit == 0L || _messageCredit > 0);
}
- public synchronized boolean useCreditForMessage(final AMQMessage msg)
+ public synchronized boolean useCreditForMessage(final ServerMessage msg)
{
if(_messageCreditLimit != 0L)
{
diff --git a/java/broker/src/main/java/org/apache/qpid/server/flow/WindowCreditManager.java b/java/broker/src/main/java/org/apache/qpid/server/flow/WindowCreditManager.java
new file mode 100644
index 0000000000..10f578551a
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/flow/WindowCreditManager.java
@@ -0,0 +1,213 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.flow;
+
+import org.apache.qpid.server.message.ServerMessage;
+
+public class WindowCreditManager extends AbstractFlowCreditManager implements FlowCreditManager_0_10
+{
+ private volatile long _bytesCreditLimit;
+ private volatile long _messageCreditLimit;
+
+ private volatile long _bytesUsed;
+ private volatile long _messageUsed;
+
+ public WindowCreditManager()
+ {
+ this(0L, 0L);
+ }
+
+ public WindowCreditManager(long bytesCreditLimit, long messageCreditLimit)
+ {
+ _bytesCreditLimit = bytesCreditLimit;
+ _messageCreditLimit = messageCreditLimit;
+ setSuspended(!hasCredit());
+
+ }
+
+
+ public synchronized void setCreditLimits(final long bytesCreditLimit, final long messageCreditLimit)
+ {
+ _bytesCreditLimit = bytesCreditLimit;
+ _messageCreditLimit = messageCreditLimit;
+
+ setSuspended(!hasCredit());
+
+ }
+
+
+ public long getMessageCredit()
+ {
+ return _messageCreditLimit == -1L
+ ? Long.MAX_VALUE
+ : _messageUsed < _messageCreditLimit ? _messageCreditLimit - _messageUsed : 0L;
+ }
+
+ public long getBytesCredit()
+ {
+ return _bytesCreditLimit == -1L
+ ? Long.MAX_VALUE
+ : _bytesUsed < _bytesCreditLimit ? _bytesCreditLimit - _bytesUsed : 0L;
+ }
+
+ public synchronized void restoreCredit(final long messageCredit, final long bytesCredit)
+ {
+ boolean notifyIncrease = true;
+ if(_messageCreditLimit > 0L)
+ {
+ notifyIncrease = (_messageUsed != _messageCreditLimit);
+ _messageUsed -= messageCredit;
+
+ //TODO log warning
+ if(_messageUsed < 0L)
+ {
+ _messageUsed = 0;
+ }
+ }
+
+
+
+ if(_bytesCreditLimit > 0L)
+ {
+ notifyIncrease = notifyIncrease && bytesCredit>0;
+ _bytesUsed -= bytesCredit;
+
+ //TODO log warning
+ if(_bytesUsed < 0L)
+ {
+ _bytesUsed = 0;
+ }
+
+ if(notifyIncrease)
+ {
+ notifyIncreaseBytesCredit();
+ }
+ }
+
+
+
+ setSuspended(!hasCredit());
+
+ }
+
+
+
+ public synchronized boolean hasCredit()
+ {
+ return (_bytesCreditLimit < 0L || _bytesCreditLimit > _bytesUsed)
+ && (_messageCreditLimit < 0L || _messageCreditLimit > _messageUsed);
+ }
+
+ public synchronized boolean useCreditForMessage(final ServerMessage msg)
+ {
+ if(_messageCreditLimit >= 0L)
+ {
+ if(_messageUsed < _messageCreditLimit)
+ {
+ if(_bytesCreditLimit < 0L)
+ {
+ _messageUsed++;
+
+ return true;
+ }
+ else if(_bytesUsed + msg.getSize() <= _bytesCreditLimit)
+ {
+ _messageUsed++;
+ _bytesUsed += msg.getSize();
+
+ return true;
+ }
+ else
+ {
+ //setSuspended(true);
+ return false;
+ }
+ }
+ else
+ {
+ setSuspended(true);
+ return false;
+ }
+ }
+ else if(_bytesCreditLimit >= 0L)
+ {
+ if(_bytesUsed + msg.getSize() <= _bytesCreditLimit)
+ {
+ _bytesUsed += msg.getSize();
+
+ return true;
+ }
+ else
+ {
+ //setSuspended(true);
+ return false;
+ }
+
+ }
+ else
+ {
+ return true;
+ }
+
+ }
+
+ public void stop()
+ {
+ if(_bytesCreditLimit > 0)
+ {
+ _bytesCreditLimit = 0;
+ }
+ if(_messageCreditLimit > 0)
+ {
+ _messageCreditLimit = 0;
+ }
+
+ }
+
+ public synchronized void addCredit(long count, long bytes)
+ {
+ if(bytes > 0)
+ {
+ _bytesCreditLimit += bytes;
+ }
+ else if(bytes == -1)
+ {
+ _bytesCreditLimit = -1;
+ }
+
+
+ if(count > 0)
+ {
+ _messageCreditLimit += count;
+ }
+ else if(count == -1)
+ {
+ _messageCreditLimit = -1;
+ }
+ }
+
+ public void clearCredit()
+ {
+ _bytesCreditLimit = 0l;
+ _messageCreditLimit = 0l;
+ setSuspended(true);
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java
index c13a69b793..d587ef0c16 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/AccessRequestHandler.java
@@ -1,10 +1,34 @@
package org.apache.qpid.server.handler;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import org.apache.qpid.framing.*;
+import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0;
+import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9;
import org.apache.qpid.server.state.StateAwareMethodListener;
import org.apache.qpid.server.state.AMQStateManager;
import org.apache.qpid.server.protocol.AMQProtocolSession;
import org.apache.qpid.AMQException;
+import org.apache.qpid.protocol.AMQConstant;
/**
* @author Apache Software Foundation
@@ -33,7 +57,20 @@ public class AccessRequestHandler implements StateAwareMethodListener<AccessRequ
// We don't implement access control class, but to keep clients happy that expect it
// always use the "0" ticket.
- AccessRequestOkBody response = methodRegistry.createAccessRequestOkBody(0);
+ AccessRequestOkBody response;
+ if(methodRegistry instanceof MethodRegistry_0_9)
+ {
+ response = ((MethodRegistry_0_9)methodRegistry).createAccessRequestOkBody(0);
+ }
+ else if(methodRegistry instanceof MethodRegistry_8_0)
+ {
+ response = ((MethodRegistry_8_0)methodRegistry).createAccessRequestOkBody(0);
+ }
+ else
+ {
+ throw new AMQException(AMQConstant.COMMAND_INVALID, "AccessRequest not present in AMQP versions other than 0-8, 0-9");
+ }
+
session.writeFrame(response.generateFrame(channelId));
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java
index 5342a7f518..0343457a73 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java
@@ -25,7 +25,6 @@ import org.apache.qpid.AMQException;
import org.apache.qpid.framing.*;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.ConsumerTagNotUniqueException;
import org.apache.qpid.server.protocol.AMQProtocolSession;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.security.access.Permission;
@@ -97,8 +96,18 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener<Basic
final AMQShortString consumerTagName;
- //Perform ACLs
- vHost.getAccessManager().authorise(session, Permission.CONSUME, body, queue);
+ // Check authz
+ if (!vHost.getAccessManager().authoriseConsume(session,
+ body.getExclusive(), body.getNoAck(),
+ body.getNoLocal(), body.getNowait(), queue))
+ {
+ throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
+ }
+ else if (queue.isExclusive() && !queue.isDurable() && queue.getExclusiveOwner() != session)
+ {
+ throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
+ "Queue " + queue.getName() + " is exclusive, but not created on this Connection.");
+ }
if (body.getConsumerTag() != null)
{
@@ -111,17 +120,31 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener<Basic
try
{
- AMQShortString consumerTag = channel.subscribeToQueue(consumerTagName, queue, !body.getNoAck(),
- body.getArguments(), body.getNoLocal(), body.getExclusive());
- if (!body.getNowait())
+ if(consumerTagName == null || channel.getSubscription(consumerTagName) == null)
{
- MethodRegistry methodRegistry = session.getMethodRegistry();
- AMQMethodBody responseBody = methodRegistry.createBasicConsumeOkBody(consumerTag);
- session.writeFrame(responseBody.generateFrame(channelId));
+ AMQShortString consumerTag = channel.subscribeToQueue(consumerTagName, queue, !body.getNoAck(),
+ body.getArguments(), body.getNoLocal(), body.getExclusive());
+ if (!body.getNowait())
+ {
+ MethodRegistry methodRegistry = session.getMethodRegistry();
+ AMQMethodBody responseBody = methodRegistry.createBasicConsumeOkBody(consumerTag);
+ session.writeFrame(responseBody.generateFrame(channelId));
+
+ }
+ }
+ else
+ {
+ AMQShortString msg = new AMQShortString("Non-unique consumer tag, '" + body.getConsumerTag() + "'");
+
+ MethodRegistry methodRegistry = session.getMethodRegistry();
+ AMQMethodBody responseBody = methodRegistry.createConnectionCloseBody(AMQConstant.NOT_ALLOWED.getCode(), // replyCode
+ msg, // replytext
+ body.getClazz(),
+ body.getMethod());
+ session.writeFrame(responseBody.generateFrame(0));
}
-
}
catch (org.apache.qpid.AMQInvalidArgumentException ise)
{
@@ -136,17 +159,6 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener<Basic
}
- catch (ConsumerTagNotUniqueException e)
- {
- AMQShortString msg = new AMQShortString("Non-unique consumer tag, '" + body.getConsumerTag() + "'");
-
- MethodRegistry methodRegistry = session.getMethodRegistry();
- AMQMethodBody responseBody = methodRegistry.createConnectionCloseBody(AMQConstant.NOT_ALLOWED.getCode(), // replyCode
- msg, // replytext
- body.getClazz(),
- body.getMethod());
- session.writeFrame(responseBody.generateFrame(0));
- }
catch (AMQQueue.ExistingExclusiveSubscription e)
{
throw body.getChannelException(AMQConstant.ACCESS_REFUSED,
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java
index be1135dd91..2c4a9b310a 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java
@@ -30,6 +30,7 @@ import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.message.AMQMessage;
import org.apache.qpid.server.flow.FlowCreditManager;
import org.apache.qpid.server.flow.MessageOnlyCreditManager;
import org.apache.qpid.server.subscription.SubscriptionImpl;
@@ -40,8 +41,6 @@ import org.apache.qpid.server.subscription.SubscriptionFactoryImpl;
import org.apache.qpid.server.protocol.AMQProtocolSession;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.queue.SimpleAMQQueue;
-import org.apache.qpid.server.security.access.Permission;
import org.apache.qpid.server.state.AMQStateManager;
import org.apache.qpid.server.state.StateAwareMethodListener;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -94,7 +93,15 @@ public class BasicGetMethodHandler implements StateAwareMethodListener<BasicGetB
{
//Perform ACLs
- vHost.getAccessManager().authorise(session, Permission.CONSUME, body, queue);
+ if (!vHost.getAccessManager().authoriseConsume(session, body.getNoAck(), queue))
+ {
+ throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
+ }
+ else if (queue.isExclusive() && queue.getExclusiveOwner() != session)
+ {
+ throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
+ "Queue is exclusive, but not created on this Connection.");
+ }
if (!performGet(queue,session, channel, !body.getNoAck()))
{
@@ -127,8 +134,16 @@ public class BasicGetMethodHandler implements StateAwareMethodListener<BasicGetB
throws AMQException
{
singleMessageCredit.useCreditForMessage(entry.getMessage());
- session.getProtocolOutputConverter().writeGetOk(entry.getMessage(), channel.getChannelId(),
- deliveryTag, queue.getMessageCount());
+ if(entry.getMessage() instanceof AMQMessage)
+ {
+ session.getProtocolOutputConverter().writeGetOk(entry, channel.getChannelId(),
+ deliveryTag, queue.getMessageCount());
+ }
+ else
+ {
+ //TODO Convert AMQP 0-10 message
+ throw new RuntimeException("Not implemented conversion of 0-10 message");
+ }
}
};
@@ -178,6 +193,11 @@ public class BasicGetMethodHandler implements StateAwareMethodListener<BasicGetB
super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod);
}
+ public boolean isTransient()
+ {
+ return true;
+ }
+
public boolean wouldSuspend(QueueEntry msg)
{
return !getCreditManager().useCreditForMessage(msg.getMessage());
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java
index e8e42454de..a7d3ad6217 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java
@@ -87,7 +87,12 @@ public class BasicPublishMethodHandler implements StateAwareMethodListener<Basic
}
//Access Control
- vHost.getAccessManager().authorise(session, Permission.PUBLISH, body, e);
+ if (!vHost.getAccessManager().authorisePublish(session,
+ body.getImmediate(), body.getMandatory(),
+ body.getRoutingKey(), e))
+ {
+ throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
+ }
MessagePublishInfo info = session.getMethodRegistry().getProtocolVersionMethodConverter().convertToInfo(body);
info.setExchange(exchange);
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java
index 15484273c8..f9feada6fe 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverSyncMethodHandler.java
@@ -1,4 +1,25 @@
package org.apache.qpid.server.handler;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import org.apache.log4j.Logger;
@@ -6,6 +27,7 @@ import org.apache.qpid.framing.BasicRecoverBody;
import org.apache.qpid.framing.ProtocolVersion;
import org.apache.qpid.framing.AMQMethodBody;
import org.apache.qpid.framing.BasicRecoverSyncBody;
+import org.apache.qpid.framing.amqp_0_91.MethodRegistry_0_91;
import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9;
import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0;
import org.apache.qpid.server.state.StateAwareMethodListener;
@@ -49,6 +71,13 @@ public class BasicRecoverSyncMethodHandler implements StateAwareMethodListener<B
session.writeFrame(recoverOk.generateFrame(channelId));
}
+ else if(session.getProtocolVersion().equals(ProtocolVersion.v0_91))
+ {
+ MethodRegistry_0_91 methodRegistry = (MethodRegistry_0_91) session.getMethodRegistry();
+ AMQMethodBody recoverOk = methodRegistry.createBasicRecoverSyncOkBody();
+ session.writeFrame(recoverOk.generateFrame(channelId));
+
+ }
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java
index f3cab10ed7..62dd76f832 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java
@@ -71,7 +71,7 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener<BasicR
{
_logger.warn("Dropping reject request as message is null for tag:" + deliveryTag);
// throw evt.getMethod().getChannelException(AMQConstant.NOT_FOUND, "Delivery Tag(" + deliveryTag + ")not known");
- }
+ }
else
{
if (message.isQueueDeleted())
@@ -81,13 +81,13 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener<BasicR
message = channel.getUnacknowledgedMessageMap().remove(deliveryTag);
if(message != null)
{
- message.discard(channel.getStoreContext());
+ message.discard();
}
//sendtoDeadLetterQueue(msg)
return;
}
- if (!message.getMessage().isReferenced())
+ if (message.getMessage() == null)
{
_logger.warn("Message as already been purged, unable to Reject.");
return;
@@ -96,7 +96,7 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener<BasicR
if (_logger.isDebugEnabled())
{
- _logger.debug("Rejecting: DT:" + deliveryTag + "-" + message.getMessage().debugIdentity() +
+ _logger.debug("Rejecting: DT:" + deliveryTag + "-" + message.getMessage() +
": Requeue:" + body.getRequeue() +
//": Resend:" + evt.getMethod().resend +
" on channel:" + channel.debugIdentity());
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java
index 054674aed4..f5c2b93f46 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java
@@ -27,6 +27,7 @@ import java.io.IOException;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.*;
+import org.apache.qpid.framing.amqp_0_91.MethodRegistry_0_91;
import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9;
import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0;
import org.apache.qpid.protocol.AMQConstant;
@@ -54,8 +55,18 @@ public class ChannelOpenHandler implements StateAwareMethodListener<ChannelOpenB
AMQProtocolSession session = stateManager.getProtocolSession();
VirtualHost virtualHost = session.getVirtualHost();
- final AMQChannel channel = new AMQChannel(session,channelId, virtualHost.getMessageStore()
- );
+
+ // Protect the broker against out of order frame request.
+ if (virtualHost == null)
+ {
+ throw new AMQException(AMQConstant.COMMAND_INVALID, "Virtualhost has not yet been set. ConnectionOpen has not been called.", null);
+ }
+
+ final AMQChannel channel = new AMQChannel(session,channelId,
+ virtualHost.getMessageStore());
+
+
+
session.addChannel(channel);
ChannelOpenOkBody response;
@@ -92,6 +103,30 @@ public class ChannelOpenHandler implements StateAwareMethodListener<ChannelOpenB
response = methodRegistry.createChannelOpenOkBody(channelName);
}
+ else if(pv.equals(ProtocolVersion.v0_91))
+ {
+ MethodRegistry_0_91 methodRegistry = (MethodRegistry_0_91) MethodRegistry.getMethodRegistry(ProtocolVersion.v0_91);
+ UUID uuid = UUID.randomUUID();
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ DataOutputStream dataOut = new DataOutputStream(output);
+ try
+ {
+ dataOut.writeLong(uuid.getMostSignificantBits());
+ dataOut.writeLong(uuid.getLeastSignificantBits());
+ dataOut.flush();
+ dataOut.close();
+ }
+ catch (IOException e)
+ {
+ // This *really* shouldn't happen as we're not doing any I/O
+ throw new RuntimeException("I/O exception when writing to byte array", e);
+ }
+
+ // should really associate this channelId to the session
+ byte[] channelName = output.toByteArray();
+
+ response = methodRegistry.createChannelOpenOkBody(channelName);
+ }
else
{
throw new AMQException(AMQConstant.INTERNAL_ERROR, "Got channel open for protocol version not catered for: " + pv, null);
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java
index f99e650979..b5194084f2 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java
@@ -22,9 +22,11 @@ package org.apache.qpid.server.handler;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.*;
+import org.apache.qpid.framing.amqp_0_91.MethodRegistry_0_91;
+import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9;
+import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.security.access.Permission;
import org.apache.qpid.server.state.AMQState;
import org.apache.qpid.server.state.AMQStateManager;
import org.apache.qpid.server.state.StateAwareMethodListener;
@@ -78,22 +80,25 @@ public class ConnectionOpenMethodHandler implements StateAwareMethodListener<Con
session.setVirtualHost(virtualHost);
//Perform ACL
- virtualHost.getAccessManager().authorise(session, Permission.ACCESS ,body, virtualHost);
+ if (!virtualHost.getAccessManager().authoriseConnect(session, virtualHost))
+ {
+ throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
+ }
// See Spec (0.8.2). Section 3.1.2 Virtual Hosts
if (session.getContextKey() == null)
{
session.setContextKey(generateClientID());
- }
+ }
MethodRegistry methodRegistry = session.getMethodRegistry();
- AMQMethodBody responseBody = methodRegistry.createConnectionOpenOkBody(body.getVirtualHost());
+ AMQMethodBody responseBody = methodRegistry.createConnectionOpenOkBody(body.getVirtualHost());
stateManager.changeState(AMQState.CONNECTION_OPEN);
session.writeFrame(responseBody.generateFrame(channelId));
-
+
}
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java
index 621003be90..a2a6faf21b 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java
@@ -25,14 +25,16 @@ import javax.security.sasl.SaslServer;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.*;
+import org.apache.qpid.framing.ConnectionCloseBody;
+import org.apache.qpid.framing.ConnectionSecureBody;
+import org.apache.qpid.framing.ConnectionSecureOkBody;
+import org.apache.qpid.framing.ConnectionTuneBody;
+import org.apache.qpid.framing.MethodRegistry;
import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.protocol.AMQMethodEvent;
import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.protocol.HeartbeatConfig;
import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
import org.apache.qpid.server.security.auth.AuthenticationResult;
+import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
import org.apache.qpid.server.state.AMQState;
import org.apache.qpid.server.state.AMQStateManager;
@@ -92,7 +94,7 @@ public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener
ConnectionTuneBody tuneBody =
methodRegistry.createConnectionTuneBody(0xFFFF,
ConnectionStartOkMethodHandler.getConfiguredFrameSize(),
- HeartbeatConfig.getInstance().getDelay());
+ ApplicationRegistry.getInstance().getConfiguration().getHeartBeatDelay());
session.writeFrame(tuneBody.generateFrame(0));
session.setAuthorizedID(new UsernamePrincipal(ss.getAuthorizationID()));
disposeSaslServer(session);
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java
index f53e56601b..6698ae888a 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java
@@ -23,18 +23,19 @@ package org.apache.qpid.server.handler;
import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer;
-import org.apache.commons.configuration.Configuration;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.*;
-import org.apache.qpid.protocol.AMQMethodEvent;
+import org.apache.qpid.framing.ConnectionCloseBody;
+import org.apache.qpid.framing.ConnectionSecureBody;
+import org.apache.qpid.framing.ConnectionStartOkBody;
+import org.apache.qpid.framing.ConnectionTuneBody;
+import org.apache.qpid.framing.MethodRegistry;
import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.server.configuration.ServerConfiguration;
import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.protocol.HeartbeatConfig;
-import org.apache.qpid.server.protocol.AMQMinaProtocolSession;
import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
import org.apache.qpid.server.security.auth.AuthenticationResult;
+import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
import org.apache.qpid.server.state.AMQState;
import org.apache.qpid.server.state.AMQStateManager;
@@ -47,8 +48,6 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener<
private static ConnectionStartOkMethodHandler _instance = new ConnectionStartOkMethodHandler();
- private static final int DEFAULT_FRAME_SIZE = 65536;
-
public static ConnectionStartOkMethodHandler getInstance()
{
return _instance;
@@ -117,7 +116,7 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener<
ConnectionTuneBody tuneBody = methodRegistry.createConnectionTuneBody(0xFFFF,
getConfiguredFrameSize(),
- HeartbeatConfig.getInstance().getDelay());
+ ApplicationRegistry.getInstance().getConfiguration().getHeartBeatDelay());
session.writeFrame(tuneBody.generateFrame(0));
break;
case CONTINUE:
@@ -153,8 +152,8 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener<
static int getConfiguredFrameSize()
{
- final Configuration config = ApplicationRegistry.getInstance().getConfiguration();
- final int framesize = config.getInt("advanced.framesize", DEFAULT_FRAME_SIZE);
+ final ServerConfiguration config = ApplicationRegistry.getInstance().getConfiguration();
+ final int framesize = config.getFrameSize();
_logger.info("Framesize set to " + framesize);
return framesize;
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java
index 0fe8c5dc92..9f392ffc44 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java
@@ -50,5 +50,6 @@ public class ConnectionTuneOkMethodHandler implements StateAwareMethodListener<C
}
stateManager.changeState(AMQState.CONNECTION_NOT_OPENED);
session.initHeartbeats(body.getHeartbeat());
+ session.setMaxFrameSize(body.getFrameMax());
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java
index 39b048aecb..b0ee5fff08 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -61,8 +61,14 @@ public class ExchangeDeclareHandler implements StateAwareMethodListener<Exchange
if (!body.getPassive())
{
- //Perform ACL if request is not passive
- virtualHost.getAccessManager().authorise(session, Permission.CREATE, body);
+ // Perform ACL if request is not passive
+ if (!virtualHost.getAccessManager().authoriseCreateExchange(session, body.getAutoDelete(),
+ body.getDurable(), body.getExchange(), body.getInternal(), body.getNowait(), body.getPassive(),
+ body.getType()))
+ {
+ throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
+ }
+
}
if (_logger.isDebugEnabled())
@@ -86,11 +92,11 @@ public class ExchangeDeclareHandler implements StateAwareMethodListener<Exchange
try
{
- exchange = exchangeFactory.createExchange(body.getExchange() == null ? null : body.getExchange().intern(),
- body.getType() == null ? null : body.getType().intern(),
- body.getDurable(),
- body.getPassive(), body.getTicket());
- exchangeRegistry.registerExchange(exchange);
+ exchange = exchangeFactory.createExchange(body.getExchange() == null ? null : body.getExchange().intern(),
+ body.getType() == null ? null : body.getType().intern(),
+ body.getDurable(),
+ body.getPassive(), body.getTicket());
+ exchangeRegistry.registerExchange(exchange);
}
catch(AMQUnknownExchangeType e)
{
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java
index 888ffcb2e5..8dbd457cc9 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java
@@ -23,6 +23,7 @@ package org.apache.qpid.server.handler;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.ExchangeDeleteBody;
import org.apache.qpid.framing.ExchangeDeleteOkBody;
+import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.exchange.ExchangeInUseException;
import org.apache.qpid.server.exchange.ExchangeRegistry;
import org.apache.qpid.server.protocol.AMQProtocolSession;
@@ -51,11 +52,18 @@ public class ExchangeDeleteHandler implements StateAwareMethodListener<ExchangeD
ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry();
//Perform ACLs
- virtualHost.getAccessManager().authorise(session, Permission.DELETE,body,
- exchangeRegistry.getExchange(body.getExchange()));
+ if (!virtualHost.getAccessManager().authoriseDelete(session,
+ exchangeRegistry.getExchange(body.getExchange())))
+ {
+ throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
+ }
try
{
+ if(exchangeRegistry.getExchange(body.getExchange()) == null)
+ {
+ throw body.getChannelException(AMQConstant.NOT_FOUND, "No such exchange: " + body.getExchange());
+ }
exchangeRegistry.unregisterExchange(body.getExchange(), body.getIfUnused());
ExchangeDeleteOkBody responseBody = session.getMethodRegistry().createExchangeDeleteOkBody();
@@ -64,6 +72,7 @@ public class ExchangeDeleteHandler implements StateAwareMethodListener<ExchangeD
}
catch (ExchangeInUseException e)
{
+ throw body.getChannelException(AMQConstant.IN_USE, "Exchange in use");
// TODO: sort out consistent channel close mechanism that does all clean up etc.
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java
index 46182e8c00..57ce7a7240 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java
@@ -108,7 +108,16 @@ public class QueueBindHandler implements StateAwareMethodListener<QueueBindBody>
{
//Perform ACLs
- virtualHost.getAccessManager().authorise(session, Permission.BIND, body, exch, queue, routingKey);
+ if (!virtualHost.getAccessManager().authoriseBind(session, exch,
+ queue, routingKey))
+ {
+ throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
+ }
+ else if (queue.isExclusive() && !queue.isDurable() && queue.getExclusiveOwner() != session)
+ {
+ throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
+ "Queue " + queue.getName() + " is exclusive, but not created on this Connection.");
+ }
if (!exch.isBound(routingKey, body.getArguments(), queue))
{
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java
index 447482ccf3..bb57fdbc36 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java
@@ -20,30 +20,28 @@
*/
package org.apache.qpid.server.handler;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
-import org.apache.qpid.configuration.Configured;
-
-import org.apache.qpid.framing.*;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.MethodRegistry;
+import org.apache.qpid.framing.QueueDeclareBody;
+import org.apache.qpid.framing.QueueDeclareOkBody;
import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.server.configuration.Configurator;
-import org.apache.qpid.server.configuration.VirtualHostConfiguration;
+import org.apache.qpid.server.AMQChannel;
import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.server.exchange.ExchangeRegistry;
import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.queue.QueueRegistry;
-import org.apache.qpid.server.security.access.Permission;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.AMQQueueFactory;
+import org.apache.qpid.server.queue.QueueRegistry;
+import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.state.AMQStateManager;
import org.apache.qpid.server.state.StateAwareMethodListener;
-import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.DurableConfigurationStore;
import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.AMQChannel;
-import org.apache.commons.configuration.Configuration;
public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclareBody>
{
@@ -56,33 +54,29 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar
return _instance;
}
- @Configured(path = "queue.auto_register", defaultValue = "true")
- public boolean autoRegister;
+ public boolean autoRegister = ApplicationRegistry.getInstance().getConfiguration().getQueueAutoRegister();
private final AtomicInteger _counter = new AtomicInteger();
-
- protected QueueDeclareHandler()
- {
- Configurator.configure(this);
- }
-
public void methodReceived(AMQStateManager stateManager, QueueDeclareBody body, int channelId) throws AMQException
{
- AMQProtocolSession session = stateManager.getProtocolSession();
+ final AMQProtocolSession session = stateManager.getProtocolSession();
VirtualHost virtualHost = session.getVirtualHost();
ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry();
QueueRegistry queueRegistry = virtualHost.getQueueRegistry();
- MessageStore store = virtualHost.getMessageStore();
+ DurableConfigurationStore store = virtualHost.getDurableConfigurationStore();
if (!body.getPassive())
{
- //Perform ACL if request is not passive
- virtualHost.getAccessManager().authorise(session, Permission.CREATE, body);
+ // Perform ACL if request is not passive
+ if (!virtualHost.getAccessManager().authoriseCreateQueue(session, body.getAutoDelete(), body.getDurable(),
+ body.getExclusive(), body.getNowait(), body.getPassive(), body.getQueue()))
+ {
+ throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
+ }
}
-
final AMQShortString queueName;
// if we aren't given a queue name, we create one which we return to the client
@@ -115,11 +109,43 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar
else
{
queue = createQueue(queueName, body, virtualHost, session);
+ queue.setPrincipalHolder(session);
if (queue.isDurable() && !queue.isAutoDelete())
{
store.createQueue(queue, body.getArguments());
}
+ if(body.getAutoDelete())
+ {
+ queue.setDeleteOnNoConsumers(true);
+ }
queueRegistry.registerQueue(queue);
+ if(body.getExclusive())
+ {
+ if(body.getDurable())
+ {
+ queue.setExclusiveOwner(session.getPrincipal().getName());
+ }
+ else
+ {
+ final AMQQueue q = queue;
+ queue.setExclusiveOwner(session);
+ final AMQProtocolSession.Task sessionCloseTask = new AMQProtocolSession.Task()
+ {
+ public void doTask(AMQProtocolSession session) throws AMQException
+ {
+ q.setExclusiveOwner(null);
+ }
+ };
+ session.addSessionCloseTask(sessionCloseTask);
+ queue.addQueueDeleteTask(new AMQQueue.Task() {
+ public void doTask(AMQQueue queue) throws AMQException
+ {
+ session.removeSessionCloseTask(sessionCloseTask);
+ }
+ });
+ }
+
+ }
if (autoRegister)
{
Exchange defaultExchange = exchangeRegistry.getDefaultExchange();
@@ -129,14 +155,40 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar
}
}
}
- else if (queue.getOwner() != null && !session.getContextKey().equals(queue.getOwner()))
+ else if (queue.isExclusive() && !queue.isDurable() && queue.getExclusiveOwner() != session)
+ {
+ throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
+ "Queue " + queue.getName() + " is exclusive, but not created on this Connection.");
+ }
+ else if(!body.getPassive() && ((queue.isExclusive()) != body.getExclusive()))
+ {
+
+ throw body.getChannelException(AMQConstant.ALREADY_EXISTS,
+ "Cannot re-declare queue '" + queue.getName() + "' with different exclusivity (was: "
+ + queue.isExclusive() + " requested " + body.getExclusive() + ")");
+ }
+ else if (!body.getPassive() && body.getExclusive() && !queue.getExclusiveOwner().equals(queue.isDurable() ? session.getPrincipal().getName() : session))
{
throw body.getChannelException(AMQConstant.ALREADY_EXISTS, "Cannot declare queue('" + queueName + "'),"
+ " as exclusive queue with same name "
+ "declared on another client ID('"
- + queue.getOwner() + "')");
+ + queue.getPrincipalHolder().getPrincipal().getName() + "')");
+
+ }
+ else if(!body.getPassive() && queue.isAutoDelete() != body.getAutoDelete())
+ {
+ throw body.getChannelException(AMQConstant.ALREADY_EXISTS,
+ "Cannot re-declare queue '" + queue.getName() + "' with different auto-delete (was: "
+ + queue.isAutoDelete() + " requested " + body.getAutoDelete() + ")");
+ }
+ else if(!body.getPassive() && queue.isDurable() != body.getDurable())
+ {
+ throw body.getChannelException(AMQConstant.ALREADY_EXISTS,
+ "Cannot re-declare queue '" + queue.getName() + "' with different durability (was: "
+ + queue.isDurable() + " requested " + body.getDurable() + ")");
}
+
AMQChannel channel = session.getChannel(channelId);
if (channel == null)
@@ -204,12 +256,6 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar
});
}// if exclusive and not durable
- Configuration virtualHostDefaultQueueConfiguration = VirtualHostConfiguration.getDefaultQueueConfiguration(queue);
- if (virtualHostDefaultQueueConfiguration != null)
- {
- Configurator.configure(queue, virtualHostDefaultQueueConfiguration);
- }
-
return queue;
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java
index dfc36f5b93..3d58ec2133 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java
@@ -31,6 +31,7 @@ import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.state.AMQStateManager;
import org.apache.qpid.server.state.StateAwareMethodListener;
import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.DurableConfigurationStore;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.AMQChannel;
import org.apache.qpid.server.security.access.Permission;
@@ -62,7 +63,7 @@ public class QueueDeleteHandler implements StateAwareMethodListener<QueueDeleteB
AMQProtocolSession session = stateManager.getProtocolSession();
VirtualHost virtualHost = session.getVirtualHost();
QueueRegistry queueRegistry = virtualHost.getQueueRegistry();
- MessageStore store = virtualHost.getMessageStore();
+ DurableConfigurationStore store = virtualHost.getDurableConfigurationStore();
AMQQueue queue;
if (body.getQueue() == null)
@@ -105,8 +106,15 @@ public class QueueDeleteHandler implements StateAwareMethodListener<QueueDeleteB
{
//Perform ACLs
- virtualHost.getAccessManager().authorise(session, Permission.DELETE, body, queue);
-
+ if (!virtualHost.getAccessManager().authoriseDelete(session, queue))
+ {
+ throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
+ }
+ else if (queue.isExclusive() && !queue.isDurable() && queue.getExclusiveOwner() != session)
+ {
+ throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
+ "Queue " + queue.getName() + " is exclusive, but not created on this Connection.");
+ }
int purged = queue.delete();
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java
index 7377862875..b94ebb6538 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java
@@ -33,7 +33,6 @@ import org.apache.qpid.server.state.AMQStateManager;
import org.apache.qpid.server.state.StateAwareMethodListener;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.security.access.Permission;
public class QueuePurgeHandler implements StateAwareMethodListener<QueuePurgeBody>
{
@@ -101,9 +100,17 @@ public class QueuePurgeHandler implements StateAwareMethodListener<QueuePurgeBod
{
//Perform ACLs
- virtualHost.getAccessManager().authorise(session, Permission.PURGE, body, queue);
+ if (!virtualHost.getAccessManager().authorisePurge(session, queue))
+ {
+ throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
+ }
+ else if (queue.isExclusive() && queue.getExclusiveOwner() != session)
+ {
+ throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
+ "Queue is exclusive, but not created on this Connection.");
+ }
- long purged = queue.clearQueue(channel.getStoreContext());
+ long purged = queue.clearQueue();
if(!body.getNowait())
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java
index d73e33d6c8..31401ce9d9 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java
@@ -1,4 +1,25 @@
package org.apache.qpid.server.handler;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import org.apache.log4j.Logger;
@@ -57,7 +78,7 @@ public class QueueUnbindHandler implements StateAwareMethodListener<QueueUnbindB
if (queue == null)
{
- throw body.getConnectionException(AMQConstant.NOT_FOUND, "No default queue defined on channel and queue was null");
+ throw body.getChannelException(AMQConstant.NOT_FOUND, "No default queue defined on channel and queue was null");
}
routingKey = body.getRoutingKey() == null ? null : body.getRoutingKey().intern();
@@ -71,7 +92,7 @@ public class QueueUnbindHandler implements StateAwareMethodListener<QueueUnbindB
if (queue == null)
{
- throw body.getConnectionException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist.");
+ throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist.");
}
final Exchange exch = exchangeRegistry.getExchange(body.getExchange());
if (exch == null)
@@ -80,7 +101,10 @@ public class QueueUnbindHandler implements StateAwareMethodListener<QueueUnbindB
}
//Perform ACLs
- virtualHost.getAccessManager().authorise(session, Permission.UNBIND, body, queue);
+ if (!virtualHost.getAccessManager().authoriseUnbind(session, exch, routingKey, queue))
+ {
+ throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
+ }
try
{
@@ -94,7 +118,7 @@ public class QueueUnbindHandler implements StateAwareMethodListener<QueueUnbindB
{
if(e.getErrorCode() == AMQConstant.NOT_FOUND)
{
- throw body.getConnectionException(AMQConstant.NOT_FOUND,e.getMessage(),e);
+ throw body.getChannelException(AMQConstant.NOT_FOUND,e.getMessage(),e);
}
throw body.getChannelException(AMQConstant.CHANNEL_ERROR, e.toString());
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java
index 9475b83c8f..e290afcde3 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl.java
@@ -59,6 +59,14 @@ public class ServerMethodDispatcherImpl implements MethodDispatcher
return new ServerMethodDispatcherImpl_0_9(stateManager);
}
});
+ _dispatcherFactories.put(ProtocolVersion.v0_91,
+ new DispatcherFactory()
+ {
+ public MethodDispatcher createMethodDispatcher(AMQStateManager stateManager)
+ {
+ return new ServerMethodDispatcherImpl_0_91(stateManager);
+ }
+ });
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_91.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_91.java
new file mode 100644
index 0000000000..32cd4c4e9f
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ServerMethodDispatcherImpl_0_91.java
@@ -0,0 +1,168 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.handler;
+
+
+import org.apache.qpid.framing.*;
+import org.apache.qpid.framing.amqp_0_91.MethodDispatcher_0_91;
+import org.apache.qpid.server.state.AMQStateManager;
+import org.apache.qpid.AMQException;
+
+
+public class ServerMethodDispatcherImpl_0_91
+ extends ServerMethodDispatcherImpl
+ implements MethodDispatcher_0_91
+
+{
+
+ private static final BasicRecoverSyncMethodHandler _basicRecoverSyncMethodHandler =
+ BasicRecoverSyncMethodHandler.getInstance();
+ private static final QueueUnbindHandler _queueUnbindHandler =
+ QueueUnbindHandler.getInstance();
+
+
+ public ServerMethodDispatcherImpl_0_91(AMQStateManager stateManager)
+ {
+ super(stateManager);
+ }
+
+ public boolean dispatchBasicRecoverSync(BasicRecoverSyncBody body, int channelId) throws AMQException
+ {
+ _basicRecoverSyncMethodHandler.methodReceived(getStateManager(), body, channelId);
+ return true;
+ }
+
+ public boolean dispatchBasicRecoverSyncOk(BasicRecoverSyncOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchChannelOk(ChannelOkBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchChannelPing(ChannelPingBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchChannelPong(ChannelPongBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchChannelResume(ChannelResumeBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageAppend(MessageAppendBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageCancel(MessageCancelBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageCheckpoint(MessageCheckpointBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageClose(MessageCloseBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageConsume(MessageConsumeBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageEmpty(MessageEmptyBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageGet(MessageGetBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageOffset(MessageOffsetBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageOk(MessageOkBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageOpen(MessageOpenBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageQos(MessageQosBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageRecover(MessageRecoverBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageReject(MessageRejectBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageResume(MessageResumeBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageTransfer(MessageTransferBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchBasicRecoverOk(BasicRecoverOkBody body, int channelId) throws AMQException
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean dispatchQueueUnbindOk(QueueUnbindOkBody body, int channelId) throws AMQException
+ {
+ throw new UnexpectedMethodException(body);
+ }
+
+ public boolean dispatchQueueUnbind(QueueUnbindBody body, int channelId) throws AMQException
+ {
+ _queueUnbindHandler.methodReceived(getStateManager(),body,channelId);
+ return true;
+ }
+} \ No newline at end of file
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java
index 9b23d88838..abd2bccc8d 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java
@@ -61,14 +61,12 @@ public class TxCommitHandler implements StateAwareMethodListener<TxCommitBody>
{
throw body.getChannelNotFoundException(channelId);
}
-
channel.commit();
MethodRegistry methodRegistry = session.getMethodRegistry();
AMQMethodBody responseBody = methodRegistry.createTxCommitOkBody();
session.writeFrame(responseBody.generateFrame(channelId));
-
- channel.processReturns();
+
}
catch (AMQException e)
{
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java
index 5f402f3fda..4643dee0a3 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java
@@ -44,9 +44,9 @@ public class TxRollbackHandler implements StateAwareMethodListener<TxRollbackBod
{
}
- public void methodReceived(AMQStateManager stateManager, TxRollbackBody body, int channelId) throws AMQException
+ public void methodReceived(AMQStateManager stateManager, TxRollbackBody body, final int channelId) throws AMQException
{
- AMQProtocolSession session = stateManager.getProtocolSession();
+ final AMQProtocolSession session = stateManager.getProtocolSession();
try
{
@@ -57,17 +57,22 @@ public class TxRollbackHandler implements StateAwareMethodListener<TxRollbackBod
throw body.getChannelNotFoundException(channelId);
}
- channel.rollback();
- MethodRegistry methodRegistry = session.getMethodRegistry();
- AMQMethodBody responseBody = methodRegistry.createTxRollbackOkBody();
- session.writeFrame(responseBody.generateFrame(channelId));
+ final MethodRegistry methodRegistry = session.getMethodRegistry();
+ final AMQMethodBody responseBody = methodRegistry.createTxRollbackOkBody();
+
+ Runnable task = new Runnable()
+ {
+
+ public void run()
+ {
+ session.writeFrame(responseBody.generateFrame(channelId));
+ }
+ };
+
+ channel.rollback(task);
- //Now resend all the unacknowledged messages back to the original subscribers.
- //(Must be done after the TxnRollback-ok response).
- // Why, are we not allowed to send messages back to client before the ok method?
- channel.resend(false);
}
catch (AMQException e)
{
diff --git a/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java b/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java
new file mode 100644
index 0000000000..6247404d90
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.information.management;
+
+import java.io.IOException;
+
+import org.apache.qpid.management.common.mbeans.ServerInformation;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
+import org.apache.qpid.server.management.AMQManagedObject;
+
+import javax.management.JMException;
+
+/** MBean class for the ServerInformationMBean. */
+@MBeanDescription("Server Information Interface")
+public class ServerInformationMBean extends AMQManagedObject implements ServerInformation
+{
+ private String buildVersion;
+ private String productVersion;
+
+ public ServerInformationMBean(String buildVersion, String productVersion) throws JMException
+ {
+ super(ServerInformation.class, ServerInformation.TYPE, ServerInformation.VERSION);
+ this.buildVersion = buildVersion;
+ this.productVersion = productVersion;
+ }
+
+ public String getObjectInstanceName()
+ {
+ return ServerInformation.TYPE;
+ }
+
+ public Integer getManagementApiMajorVersion() throws IOException
+ {
+ return QPID_JMX_API_MAJOR_VERSION;
+ }
+
+ public Integer getManagementApiMinorVersion() throws IOException
+ {
+ return QPID_JMX_API_MINOR_VERSION;
+ }
+
+ public String getBuildVersion() throws IOException
+ {
+ return buildVersion;
+ }
+
+ public String getProductVersion() throws IOException
+ {
+ return productVersion;
+ }
+
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java b/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java
deleted file mode 100644
index c08fae4e4e..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java
+++ /dev/null
@@ -1,110 +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.
- *
- */
-package org.apache.qpid.server.jms;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-
-public class JmsConsumer
-{
- private int _prefetchValue;
-
- private PrefetchUnits _prefetchUnits;
-
- private boolean _noLocal;
-
- private boolean _autoAck;
-
- private boolean _exclusive;
-
- private AMQProtocolSession _protocolSession;
-
- public enum PrefetchUnits
- {
- OCTETS,
- MESSAGES
- }
-
- public int getPrefetchValue()
- {
- return _prefetchValue;
- }
-
- public void setPrefetchValue(int prefetchValue)
- {
- _prefetchValue = prefetchValue;
- }
-
- public PrefetchUnits getPrefetchUnits()
- {
- return _prefetchUnits;
- }
-
- public void setPrefetchUnits(PrefetchUnits prefetchUnits)
- {
- _prefetchUnits = prefetchUnits;
- }
-
- public boolean isNoLocal()
- {
- return _noLocal;
- }
-
- public void setNoLocal(boolean noLocal)
- {
- _noLocal = noLocal;
- }
-
- public boolean isAutoAck()
- {
- return _autoAck;
- }
-
- public void setAutoAck(boolean autoAck)
- {
- _autoAck = autoAck;
- }
-
- public boolean isExclusive()
- {
- return _exclusive;
- }
-
- public void setExclusive(boolean exclusive)
- {
- _exclusive = exclusive;
- }
-
- public AMQProtocolSession getProtocolSession()
- {
- return _protocolSession;
- }
-
- public void setProtocolSession(AMQProtocolSession protocolSession)
- {
- _protocolSession = protocolSession;
- }
-
- public void deliverMessage() throws AMQException
- {
-
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/LogActor.java b/java/broker/src/main/java/org/apache/qpid/server/logging/LogActor.java
new file mode 100644
index 0000000000..18f03c2716
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/LogActor.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.logging;
+
+/**
+ * LogActor the entity that is stored as in a ThreadLocal and used to perform logging.
+ *
+ * The actor is responsible for formatting its display name for the log entry.
+ *
+ * The actor performs the requested logging.
+ */
+public interface LogActor
+{
+ /**
+ * Logs the specified LogMessage about the LogSubject
+ *
+ * Currently logging has a global setting however this will later be revised and
+ * as such the LogActor will need to take into consideration any new configuration
+ * as a means of enabling the logging of LogActors and LogSubjects.
+ *
+ * @param subject The subject that is being logged
+ * @param message The message to log
+ */
+ public void message(LogSubject subject, LogMessage message);
+
+ /**
+ * Logs the specified LogMessage against this actor
+ *
+ * Currently logging has a global setting however this will later be revised and
+ * as such the LogActor will need to take into consideration any new configuration
+ * as a means of enabling the logging of LogActors and LogSubjects.
+ *
+ * @param message The message to log
+ */
+ public void message(LogMessage message);
+
+ /**
+ *
+ * @return the RootMessageLogger that is currently in use by this LogActor.
+ */
+ RootMessageLogger getRootMessageLogger();
+
+ /**
+ *
+ * @return the String representing this LogActor
+ */
+ public String getLogMessage();
+} \ No newline at end of file
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/LogMessage.java b/java/broker/src/main/java/org/apache/qpid/server/logging/LogMessage.java
new file mode 100644
index 0000000000..5c112ff100
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/LogMessage.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.logging;
+
+public interface LogMessage
+{
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/LogSubject.java b/java/broker/src/main/java/org/apache/qpid/server/logging/LogSubject.java
new file mode 100644
index 0000000000..e53ef364bf
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/LogSubject.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.logging;
+
+/**
+ * Each LogSubject that wishes to be logged will implement this to provide their
+ * own display representation.
+ *
+ * The display representation is retrieved through the toString() method.
+ */
+public interface LogSubject
+{
+ /**
+ * Logs the message as provided by String.valueOf(message).
+ *
+ * @returns String the display representation of this LogSubject
+ */
+ public String toString();
+} \ No newline at end of file
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/NullRootMessageLogger.java b/java/broker/src/main/java/org/apache/qpid/server/logging/NullRootMessageLogger.java
new file mode 100644
index 0000000000..6cd29b95fb
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/NullRootMessageLogger.java
@@ -0,0 +1,60 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging;
+
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.configuration.ConfigurationException;
+
+public class NullRootMessageLogger extends RootMessageLoggerImpl
+{
+
+ public NullRootMessageLogger() throws ConfigurationException
+ {
+ super(new ServerConfiguration(new PropertiesConfiguration()), new NullMessageLogger());
+ }
+
+ @Override
+ public boolean isMessageEnabled(LogActor actor, LogSubject subject)
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isMessageEnabled(LogActor actor)
+ {
+ return false;
+ }
+
+ public static class NullMessageLogger implements RawMessageLogger
+ {
+ public void rawMessage(String message)
+ {
+ // drop message
+ }
+
+ public void rawMessage(String message, Throwable throwable)
+ {
+ // drop message
+ }
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/RawMessageLogger.java b/java/broker/src/main/java/org/apache/qpid/server/logging/RawMessageLogger.java
new file mode 100644
index 0000000000..7d515f3263
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/RawMessageLogger.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.logging;
+
+/**
+ * A RawMessage Logger takes the given String and any Throwable and writes the
+ * data to its resource.
+ */
+public interface RawMessageLogger
+{
+
+ /**
+ * Log the given message.
+ *
+ * @param message String to log.
+ */
+ public void rawMessage(String message);
+
+ /**
+ * Log the message and formatted stack trace for any Throwable.
+ *
+ * @param message String to log.
+ * @param throwable Throwable for which to provide stack trace.
+ */
+ public void rawMessage(String message, Throwable throwable);
+} \ No newline at end of file
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLogger.java b/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLogger.java
new file mode 100644
index 0000000000..5ac5eab6c4
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLogger.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.logging;
+
+/**
+ * The RootMessageLogger is used by the LogActors to query if
+ * logging is enabled for the requested message and to provide the actual
+ * message that should be logged.
+ */
+public interface RootMessageLogger
+{
+ /**
+ * Determine if the LogSubject and the LogActor should be
+ * generating log messages.
+ *
+ * @param subject The subject of this log request
+ * @param actor The actor requesting the logging
+ * @return boolean true if the message should be logged.
+ */
+ boolean isMessageEnabled(LogActor actor, LogSubject subject);
+
+ /**
+ * Determine if the LogActor should be generating log messages.
+ *
+ * @param actor The actor requesting the logging
+ *
+ * @return boolean true if the message should be logged.
+ */
+ boolean isMessageEnabled(LogActor actor);
+
+ /**
+ * Log the raw message to the configured logger.
+ *
+ * @param message The message to log
+ */
+ public void rawMessage(String message);
+
+ /**
+ * Log the raw message to the configured logger.
+ * Along with a formated stack trace from the Throwable.
+ *
+ * @param message The message to log
+ * @param throwable Optional Throwable that should provide stact trace
+ */
+ void rawMessage(String message, Throwable throwable);
+} \ No newline at end of file
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLoggerImpl.java b/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLoggerImpl.java
new file mode 100644
index 0000000000..a3bf276d1e
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/RootMessageLoggerImpl.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.logging;
+
+import org.apache.qpid.server.configuration.ServerConfiguration;
+
+public class RootMessageLoggerImpl implements RootMessageLogger
+{
+ private boolean _enabled;
+
+ RawMessageLogger _rawLogger;
+ private static final String MESSAGE = "MESSAGE ";
+
+ public RootMessageLoggerImpl(ServerConfiguration configuration, RawMessageLogger rawLogger)
+ {
+ _enabled = configuration.getStatusUpdatesEnabled();
+ _rawLogger = rawLogger;
+ }
+
+ public boolean isMessageEnabled(LogActor actor, LogSubject subject)
+ {
+ return _enabled;
+ }
+
+ public boolean isMessageEnabled(LogActor actor)
+ {
+ return _enabled;
+ }
+
+ public void rawMessage(String message)
+ {
+ _rawLogger.rawMessage(MESSAGE + message);
+ }
+
+ public void rawMessage(String message, Throwable throwable)
+ {
+ _rawLogger.rawMessage(MESSAGE + message, throwable);
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/StartupRootMessageLogger.java b/java/broker/src/main/java/org/apache/qpid/server/logging/StartupRootMessageLogger.java
new file mode 100644
index 0000000000..bfb122985b
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/StartupRootMessageLogger.java
@@ -0,0 +1,49 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging;
+
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.logging.rawloggers.SystemOutMessageLogger;
+
+public class StartupRootMessageLogger extends RootMessageLoggerImpl
+{
+ public StartupRootMessageLogger() throws ConfigurationException
+ {
+ super(new ServerConfiguration(new PropertiesConfiguration()),
+ new SystemOutMessageLogger());
+ }
+
+ @Override
+ public boolean isMessageEnabled(LogActor actor, LogSubject subject)
+ {
+ return true;
+ }
+
+ @Override
+ public boolean isMessageEnabled(LogActor actor)
+ {
+ return true;
+ }
+
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java b/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java
new file mode 100644
index 0000000000..d961836acc
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.logging.actors;
+
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.logging.RootMessageLogger;
+import org.apache.qpid.server.logging.subjects.ChannelLogSubject;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+
+import java.text.MessageFormat;
+
+/**
+ * An AMQPChannelActor represtents a connection through the AMQP port with an
+ * associated Channel.
+ *
+ * <p/>
+ * This is responsible for correctly formatting the LogActor String in the log
+ * <p/>
+ * [con:1(user@127.0.0.1/)/ch:1]
+ * <p/>
+ * To do this it requires access to the IO Layers as well as a Channel
+ */
+public class AMQPChannelActor extends AbstractActor
+{
+ private final ChannelLogSubject _logString;
+
+ /**
+ * Create a new ChannelActor
+ *
+ * @param channel The Channel for this LogActor
+ * @param rootLogger The root Logger that this LogActor should use
+ */
+ public AMQPChannelActor(AMQChannel channel, RootMessageLogger rootLogger)
+ {
+ super(rootLogger);
+
+
+ _logString = new ChannelLogSubject(channel);
+ }
+
+ public String getLogMessage()
+ {
+ return _logString.toString();
+ }
+}
+
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java b/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java
new file mode 100644
index 0000000000..4149aed529
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.logging.actors;
+
+import org.apache.qpid.server.logging.RootMessageLogger;
+import org.apache.qpid.server.logging.subjects.ConnectionLogSubject;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+
+
+
+/**
+ * An AMQPConnectionActor represtents a connectionthrough the AMQP port.
+ * <p/>
+ * This is responsible for correctly formatting the LogActor String in the log
+ * <p/>
+ * [ con:1(user@127.0.0.1/) ]
+ * <p/>
+ * To do this it requires access to the IO Layers.
+ */
+public class AMQPConnectionActor extends AbstractActor
+{
+ private ConnectionLogSubject _logSubject;
+
+ public AMQPConnectionActor(AMQProtocolSession session, RootMessageLogger rootLogger)
+ {
+ super(rootLogger);
+
+ _logSubject = new ConnectionLogSubject(session);
+ }
+
+ public String getLogMessage()
+ {
+ return _logSubject.toString();
+ }
+}
+
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java b/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java
new file mode 100644
index 0000000000..1fa2bd9600
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractActor.java
@@ -0,0 +1,69 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.actors;
+
+import org.apache.qpid.server.logging.LogActor;
+import org.apache.qpid.server.logging.LogMessage;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.logging.RootMessageLogger;
+
+public abstract class AbstractActor implements LogActor
+{
+ protected RootMessageLogger _rootLogger;
+
+ public AbstractActor(RootMessageLogger rootLogger)
+ {
+ if(rootLogger == null)
+ {
+ throw new NullPointerException("RootMessageLogger cannot be null");
+ }
+ _rootLogger = rootLogger;
+ }
+
+ public void message(LogSubject subject, LogMessage message)
+ {
+ if (_rootLogger.isMessageEnabled(this, subject))
+ {
+ _rootLogger.rawMessage(getLogMessage() + String.valueOf(subject) + message);
+ }
+ }
+
+ public void message(LogMessage message)
+ {
+ if (_rootLogger.isMessageEnabled(this))
+ {
+ _rootLogger.rawMessage(getLogMessage() + message);
+ }
+ }
+
+ public RootMessageLogger getRootMessageLogger()
+ {
+ return _rootLogger;
+ }
+
+ public String toString()
+ {
+ return getLogMessage();
+ }
+
+ abstract public String getLogMessage();
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/actors/BrokerActor.java b/java/broker/src/main/java/org/apache/qpid/server/logging/actors/BrokerActor.java
new file mode 100644
index 0000000000..9e77452228
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/actors/BrokerActor.java
@@ -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 org.apache.qpid.server.logging.actors;
+
+import org.apache.qpid.server.logging.RootMessageLogger;
+
+public class BrokerActor extends AbstractActor
+{
+ private final String _logString;
+
+ /**
+ * Create a new BrokerActor
+ *
+ * @param logger
+ */
+ public BrokerActor(RootMessageLogger logger)
+ {
+ super(logger);
+
+ _logString = "[Broker] ";
+ }
+
+ public BrokerActor(String name, RootMessageLogger logger)
+ {
+ super(logger);
+
+ _logString = "[Broker(" + name + ")] ";
+ }
+
+ public String getLogMessage()
+ {
+ return _logString;
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java b/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java
new file mode 100644
index 0000000000..3d31a705fe
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java
@@ -0,0 +1,121 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.actors;
+
+import org.apache.qpid.server.logging.LogActor;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.logging.LogMessage;
+import org.apache.qpid.server.logging.RootMessageLogger;
+
+import java.util.EmptyStackException;
+import java.util.Stack;
+
+/**
+ * The CurrentActor is a ThreadLocal wrapper that allows threads in the broker
+ * to retrieve an actor to perform logging. This approach is used so for two
+ * reasons:
+ * 1) We do not have to pass a logging actor around the system
+ * 2) We can set new actors at the point we have enough information. i.e.
+ * - Set a low level ConnectionActor when processing bytes from the wire.
+ * - Set a ChannelActor when we are processing the frame
+ * - Set a SubscriptionActor when we are handling the subscription.
+ * <p/>
+ * The code performing the logging need not worry about what type of actor is
+ * currently set so can perform its logging. The resulting log entry though will
+ * contain customised details from the the currently set Actor.
+ * <p/>
+ * The Actor model also allows the pre-creation of fixed messages so the
+ * performance impact of the additional logging data is minimised.
+ * <p/>
+ * This class does not perform any checks to ensure that there is an Actor set
+ * when calling remove or get. As a result the application developer must ensure
+ * that they have called set before they attempt to use the actor via get or
+ * remove the set actor.
+ * <p/>
+ * The checking of the return via get should not be done as the logging is
+ * desired. It is preferable to cause the NullPointerException to highlight the
+ * programming error rather than miss a log message.
+ * <p/>
+ * The same is true for the remove. A NPE will occur if no set has been called
+ * highlighting the programming error.
+ */
+public class CurrentActor
+{
+ /** The ThreadLocal variable with initialiser */
+ private static final ThreadLocal<Stack<LogActor>> _currentActor = new ThreadLocal<Stack<LogActor>>()
+ {
+ // Initialise the CurrentActor to be an empty List
+ protected Stack<LogActor> initialValue()
+ {
+ return new Stack<LogActor>();
+ }
+ };
+
+ private static LogActor _defaultActor;
+
+ /**
+ * Set a new LogActor to be the Current Actor
+ * <p/>
+ * This pushes the Actor in to the LIFO Queue
+ *
+ * @param actor The new LogActor
+ */
+ public static void set(LogActor actor)
+ {
+ Stack<LogActor> stack = _currentActor.get();
+ stack.push(actor);
+ }
+
+ /**
+ * Remove the current LogActor.
+ * <p/>
+ * Calling remove without calling set will result in an EmptyStackException.
+ */
+ public static void remove()
+ {
+ Stack<LogActor> stack = _currentActor.get();
+ stack.pop();
+ }
+
+ /**
+ * Return the current head of the list of LogActors.
+ * <p/>
+ * If there has been no set call then this will return Null.
+ *
+ * @return Current LogActor
+ */
+ public static LogActor get()
+ {
+ try
+ {
+ return _currentActor.get().peek();
+ }
+ catch (EmptyStackException ese)
+ {
+ return _defaultActor;
+ }
+ }
+
+ public static void setDefault(LogActor defaultActor)
+ {
+ _defaultActor = defaultActor;
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java b/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java
new file mode 100644
index 0000000000..2825fa1b75
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java
@@ -0,0 +1,114 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.actors;
+
+import org.apache.qpid.server.logging.LogMessage;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.logging.RootMessageLogger;
+
+import java.text.MessageFormat;
+
+/**
+ * NOTE: This actor is not thread safe.
+ *
+ * Sharing of a ManagementActor instance between threads may result in an
+ * incorrect actor value being logged.
+ *
+ * This is due to the fact that calls to message will dynamically query the
+ * thread name and use that to set the log format during each message() call.
+ *
+ * This is currently not an issue as each MBean operation creates a new Actor
+ * that is unique for each operation.
+ */
+public class ManagementActor extends AbstractActor
+{
+ String _lastThreadName = null;
+
+ /**
+ * LOG FORMAT for the ManagementActor,
+ * Uses a MessageFormat call to insert the requried values according to
+ * these indicies:
+ *
+ * 0 - Connection ID
+ * 1 - User ID
+ * 2 - IP
+ */
+ public static final String MANAGEMENT_FORMAT = "mng:{0}({1})";
+
+ /**
+ * The logString to be used for logging
+ */
+ private String _logString;
+
+ /** @param rootLogger The RootLogger to use for this Actor */
+ public ManagementActor(RootMessageLogger rootLogger)
+ {
+ super(rootLogger);
+ }
+
+ private void updateLogString()
+ {
+ String currentName = Thread.currentThread().getName();
+
+ String actor;
+ // Record the last thread name so we don't have to recreate the log string
+ if (!currentName.equals(_lastThreadName))
+ {
+ _lastThreadName = currentName;
+
+ // Management Thread names have this format.
+ //RMI TCP Connection(2)-169.24.29.116
+ // This is true for both LocalAPI and JMX Connections
+ // However to be defensive lets test.
+
+ String[] split = currentName.split("\\(");
+ if (split.length == 2)
+ {
+ String connectionID = split[1].split("\\)")[0];
+ String ip = currentName.split("-")[1];
+
+ actor = MessageFormat.format(MANAGEMENT_FORMAT,
+ connectionID,
+ ip);
+ }
+ else
+ {
+ // This is a precautionary path as it is not expected to occur
+ // however rather than adjusting the thread name of the two
+ // tests that will use this it is safer all round to do this.
+ // it is also currently used by tests :
+ // AMQBrokerManagerMBeanTest
+ // ExchangeMBeanTest
+ actor = currentName;
+ }
+
+ _logString = "[" + actor + "] ";
+
+ }
+ }
+
+ public String getLogMessage()
+ {
+ updateLogString();
+ return _logString;
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/actors/QueueActor.java b/java/broker/src/main/java/org/apache/qpid/server/logging/actors/QueueActor.java
new file mode 100644
index 0000000000..7d81b03de4
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/actors/QueueActor.java
@@ -0,0 +1,55 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.actors;
+
+import org.apache.qpid.server.logging.RootMessageLogger;
+import org.apache.qpid.server.logging.subjects.QueueLogSubject;
+import org.apache.qpid.server.queue.AMQQueue;
+
+import java.text.MessageFormat;
+
+/**
+ * This Actor is used when while the queue is performing an asynchronous process
+ * of its queue.
+ */
+public class QueueActor extends AbstractActor
+{
+ private QueueLogSubject _logSubject;
+
+ /**
+ * Create an QueueLogSubject that Logs in the following format.
+ *
+ * @param queue The queue that this Actor is working for
+ * @param rootLogger the Root logger to use.
+ */
+ public QueueActor(AMQQueue queue, RootMessageLogger rootLogger)
+ {
+ super(rootLogger);
+
+ _logSubject = new QueueLogSubject(queue);
+ }
+
+ public String getLogMessage()
+ {
+ return _logSubject.toString();
+ }
+}
+
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java b/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java
new file mode 100644
index 0000000000..542984e76c
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/actors/SubscriptionActor.java
@@ -0,0 +1,49 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.actors;
+
+import org.apache.qpid.server.logging.RootMessageLogger;
+import org.apache.qpid.server.logging.subjects.QueueLogSubject;
+import org.apache.qpid.server.logging.subjects.SubscriptionLogSubject;
+import org.apache.qpid.server.subscription.Subscription;
+
+import java.text.MessageFormat;
+
+/**
+ * The subscription actor provides formatted logging for actions that are
+ * performed by the subsciption. Such as SUB_STATE changes.
+ */
+public class SubscriptionActor extends AbstractActor
+{
+ private SubscriptionLogSubject _logSubject;
+
+ public SubscriptionActor(RootMessageLogger logger, Subscription subscription)
+ {
+ super(logger);
+
+ _logSubject = new SubscriptionLogSubject(subscription);
+ }
+
+ public String getLogMessage()
+ {
+ return _logSubject.toString();
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java b/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java
new file mode 100644
index 0000000000..c36eeb5016
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java
@@ -0,0 +1,819 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.logging.management;
+
+import static org.apache.log4j.xml.QpidLog4JConfigurator.LOCK;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import org.apache.qpid.management.common.mbeans.LoggingManagement;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
+import org.apache.qpid.server.management.AMQManagedObject;
+import org.apache.qpid.util.FileUtils;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.log4j.xml.Log4jEntityResolver;
+import org.apache.log4j.xml.QpidLog4JConfigurator;
+import org.apache.log4j.xml.QpidLog4JConfigurator.QpidLog4JSaxErrorHandler;
+import org.apache.log4j.xml.QpidLog4JConfigurator.IllegalLoggerLevelException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+import javax.management.JMException;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularDataSupport;
+import javax.management.openmbean.TabularType;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+
+/** MBean class for BrokerLoggingManagerMBean. It implements all the management features exposed for managing logging. */
+@MBeanDescription("Logging Management Interface")
+public class LoggingManagementMBean extends AMQManagedObject implements LoggingManagement
+{
+
+ private static final Logger _logger = Logger.getLogger(LoggingManagementMBean.class);
+ private String _log4jConfigFileName;
+ private int _log4jLogWatchInterval;
+ private static final String INHERITED = "INHERITED";
+ private static final String[] LEVELS = new String[]{Level.ALL.toString(), Level.TRACE.toString(),
+ Level.DEBUG.toString(), Level.INFO.toString(),
+ Level.WARN.toString(), Level.ERROR.toString(),
+ Level.FATAL.toString(),Level.OFF.toString(),
+ INHERITED};
+ static TabularType _loggerLevelTabularType;
+ static CompositeType _loggerLevelCompositeType;
+
+ static
+ {
+ try
+ {
+ OpenType[] loggerLevelItemTypes = new OpenType[]{SimpleType.STRING, SimpleType.STRING};
+
+ _loggerLevelCompositeType = new CompositeType("LoggerLevelList", "Logger Level Data",
+ COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS, loggerLevelItemTypes);
+
+ _loggerLevelTabularType = new TabularType("LoggerLevel", "List of loggers with levels",
+ _loggerLevelCompositeType, TABULAR_UNIQUE_INDEX);
+ }
+ catch (OpenDataException e)
+ {
+ _logger.error("Tabular data setup for viewing logger levels was incorrect.");
+ _loggerLevelTabularType = null;
+ }
+ }
+
+ public LoggingManagementMBean(String log4jConfigFileName, int log4jLogWatchInterval) throws JMException
+ {
+ super(LoggingManagement.class, LoggingManagement.TYPE, LoggingManagement.VERSION);
+ _log4jConfigFileName = log4jConfigFileName;
+ _log4jLogWatchInterval = log4jLogWatchInterval;
+ }
+
+ public String getObjectInstanceName()
+ {
+ return LoggingManagement.TYPE;
+ }
+
+ public Integer getLog4jLogWatchInterval()
+ {
+ return _log4jLogWatchInterval;
+ }
+
+ public String[] getAvailableLoggerLevels()
+ {
+ return LEVELS;
+ }
+ @SuppressWarnings("unchecked")
+ public synchronized boolean setRuntimeLoggerLevel(String logger, String level)
+ {
+ //check specified level is valid
+ Level newLevel;
+ try
+ {
+ newLevel = getLevel(level);
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+
+ //check specified logger exists
+ Enumeration loggers = LogManager.getCurrentLoggers();
+ Boolean loggerExists = false;
+
+ while(loggers.hasMoreElements())
+ {
+ Logger log = (Logger) loggers.nextElement();
+ if (log.getName().equals(logger))
+ {
+ loggerExists = true;
+ break;
+ }
+ }
+
+ if(!loggerExists)
+ {
+ return false;
+ }
+
+ //set the logger to the new level
+ _logger.info("Setting level to " + level + " for logger: " + logger);
+
+ Logger log = Logger.getLogger(logger);
+ log.setLevel(newLevel);
+
+ return true;
+ }
+
+ @SuppressWarnings("unchecked")
+ public synchronized TabularData viewEffectiveRuntimeLoggerLevels()
+ {
+ if (_loggerLevelTabularType == null)
+ {
+ _logger.warn("TabluarData type not set up correctly");
+ return null;
+ }
+
+ _logger.info("Getting levels for currently active log4j loggers");
+
+ Enumeration loggers = LogManager.getCurrentLoggers();
+
+ TabularData loggerLevelList = new TabularDataSupport(_loggerLevelTabularType);
+
+ Logger logger;
+ String loggerName;
+ String level;
+
+ try
+ {
+ while(loggers.hasMoreElements()){
+ logger = (Logger) loggers.nextElement();
+
+ loggerName = logger.getName();
+ level = logger.getEffectiveLevel().toString();
+
+ Object[] itemData = {loggerName, level};
+ CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData);
+ loggerLevelList.put(loggerData);
+ }
+ }
+ catch (OpenDataException e)
+ {
+ _logger.warn("Unable to create logger level list due to :" + e);
+ return null;
+ }
+
+ return loggerLevelList;
+
+ }
+
+ public synchronized String getRuntimeRootLoggerLevel()
+ {
+ Logger rootLogger = Logger.getRootLogger();
+
+ return rootLogger.getLevel().toString();
+ }
+
+ public synchronized boolean setRuntimeRootLoggerLevel(String level)
+ {
+ Level newLevel;
+ try
+ {
+ newLevel = getLevel(level);
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+
+ if(newLevel == null)
+ {
+ //A null Level reference implies inheritance. Setting the runtime RootLogger
+ //to null is catastrophic (and prevented by Log4J at startup and runtime anyway).
+ return false;
+ }
+
+ _logger.info("Setting RootLogger level to " + level);
+
+ Logger log = Logger.getRootLogger();
+ log.setLevel(newLevel);
+
+ return true;
+ }
+
+ //method to convert from a string to a log4j Level, throws exception if the given value is invalid
+ private Level getLevel(String level) throws Exception
+ {
+ if("null".equalsIgnoreCase(level) || INHERITED.equalsIgnoreCase(level))
+ {
+ //the string "null" or "inherited" signals to inherit from a parent logger,
+ //using a null Level reference for the logger.
+ return null;
+ }
+
+ Level newLevel = Level.toLevel(level);
+
+ //above Level.toLevel call returns a DEBUG Level if the request fails. Check the result.
+ if (newLevel.equals(Level.DEBUG) && !(level.equalsIgnoreCase("debug")))
+ {
+ //received DEBUG but we did not ask for it, the Level request failed.
+ throw new Exception("Invalid level name");
+ }
+
+ return newLevel;
+ }
+
+ //method to parse the XML configuration file, validating it in the process, and returning a DOM Document of the content.
+ private static synchronized Document parseConfigFile(String fileName) throws IOException
+ {
+ try
+ {
+ LOCK.lock();
+
+ //check file was specified, exists, and is readable
+ if(fileName == null)
+ {
+ _logger.warn("Provided log4j XML configuration filename is null");
+ throw new IOException("Provided log4j XML configuration filename is null");
+ }
+
+ File configFile = new File(fileName);
+
+ if (!configFile.exists())
+ {
+ _logger.warn("The log4j XML configuration file could not be found: " + fileName);
+ throw new IOException("The log4j XML configuration file could not be found");
+ }
+ else if (!configFile.canRead())
+ {
+ _logger.warn("The log4j XML configuration file is not readable: " + fileName);
+ throw new IOException("The log4j XML configuration file is not readable");
+ }
+
+ //parse it
+ DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder docBuilder;
+ Document doc;
+
+ ErrorHandler errHandler = new QpidLog4JSaxErrorHandler();
+ try
+ {
+ docFactory.setValidating(true);
+ docBuilder = docFactory.newDocumentBuilder();
+ docBuilder.setErrorHandler(errHandler);
+ docBuilder.setEntityResolver(new Log4jEntityResolver());
+ doc = docBuilder.parse(fileName);
+ }
+ catch (ParserConfigurationException e)
+ {
+ _logger.warn("Unable to parse the log4j XML file due to possible configuration error: " + e);
+ //recommended that MBeans should use java.* and javax.* exceptions only
+ throw new IOException("Unable to parse the log4j XML file due to possible configuration error: " + e.getMessage());
+ }
+ catch (SAXException e)
+ {
+ _logger.warn("The specified log4j XML file is invalid: " + e);
+ //recommended that MBeans should use standard java.* and javax.* exceptions only
+ throw new IOException("The specified log4j XML file is invalid: " + e.getMessage());
+ }
+ catch (IOException e)
+ {
+ _logger.warn("Unable to parse the specified log4j XML file" + e);
+ throw new IOException("Unable to parse the specified log4j XML file: " + e.getMessage());
+ }
+
+ return doc;
+ }
+ finally
+ {
+ LOCK.unlock();
+ }
+ }
+
+
+ private static synchronized boolean writeUpdatedConfigFile(String log4jConfigFileName, Document doc) throws IOException
+ {
+ try
+ {
+ LOCK.lock();
+
+ File log4jConfigFile = new File(log4jConfigFileName);
+
+ if (!log4jConfigFile.canWrite())
+ {
+ _logger.warn("Specified log4j XML configuration file is not writable: " + log4jConfigFile);
+ throw new IOException("Specified log4j XML configuration file is not writable");
+ }
+
+ Transformer transformer = null;
+ try
+ {
+ transformer = TransformerFactory.newInstance().newTransformer();
+ }
+ catch (Exception e)
+ {
+ _logger.warn("Could not create an XML transformer: " +e);
+ return false;
+ }
+
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "log4j.dtd");
+ DOMSource source = new DOMSource(doc);
+
+ File tmp;
+ Random r = new Random();
+ do
+ {
+ tmp = new File(log4jConfigFile.getPath() + r.nextInt() + ".tmp");
+ }
+ while(tmp.exists());
+
+ tmp.deleteOnExit();
+
+ try
+ {
+ StreamResult result = new StreamResult(tmp);
+ transformer.transform(source, result);
+ }
+ catch (TransformerException e)
+ {
+ _logger.warn("Could not transform the XML into new file: " +e);
+ throw new IOException("Could not transform the XML into new file: " +e);
+ }
+
+ // Swap temp file in to replace existing configuration file.
+ File old = new File(log4jConfigFile.getAbsoluteFile() + ".old");
+ if (old.exists())
+ {
+ old.delete();
+ }
+
+ if(!log4jConfigFile.renameTo(old))
+ {
+ //unable to rename the existing file to the backup name
+ _logger.error("Could not backup the existing log4j XML file");
+ throw new IOException("Could not backup the existing log4j XML file");
+ }
+
+ if(!tmp.renameTo(log4jConfigFile))
+ {
+ //failed to rename the new file to the required filename
+
+ if(!old.renameTo(log4jConfigFile))
+ {
+ //unable to return the backup to required filename
+ _logger.error("Could not rename the new log4j configuration file into place, and unable to restore original file");
+ throw new IOException("Could not rename the new log4j configuration file into place, and unable to restore original file");
+ }
+
+ _logger.error("Could not rename the new log4j configuration file into place");
+ throw new IOException("Could not rename the new log4j configuration file into place");
+ }
+
+ return true;
+ }
+ finally
+ {
+ LOCK.unlock();
+ }
+ }
+
+
+ /* The log4j XML configuration file DTD defines three possible element
+ * combinations for specifying optional logger+level settings.
+ * Must account for the following:
+ *
+ * <category name="x"> <priority value="y"/> </category> OR
+ * <category name="x"> <level value="y"/> </category> OR
+ * <logger name="x"> <level value="y"/> </logger>
+ *
+ * Noting also that the level/priority child element is optional too,
+ * and not the only possible child element.
+ */
+
+ public static synchronized Map<String,String> retrieveConfigFileLoggersLevels(String fileName) throws IOException
+ {
+ try
+ {
+ LOCK.lock();
+
+ Document doc = parseConfigFile(fileName);
+
+ HashMap<String,String> loggerLevelList = new HashMap<String,String>();
+
+ //retrieve the 'category' element nodes
+ NodeList categoryElements = doc.getElementsByTagName("category");
+
+ String categoryName;
+ String priority = null;
+
+ for (int i = 0; i < categoryElements.getLength(); i++)
+ {
+ Element categoryElement = (Element) categoryElements.item(i);
+ categoryName = categoryElement.getAttribute("name");
+
+ //retrieve the category's mandatory 'priority' or 'level' element's value.
+ //It may not be the only child node, so request by tag name.
+ NodeList priorityElements = categoryElement.getElementsByTagName("priority");
+ NodeList levelElements = categoryElement.getElementsByTagName("level");
+
+ if (priorityElements.getLength() != 0)
+ {
+ Element priorityElement = (Element) priorityElements.item(0);
+ priority = priorityElement.getAttribute("value");
+ }
+ else if (levelElements.getLength() != 0)
+ {
+ Element levelElement = (Element) levelElements.item(0);
+ priority = levelElement.getAttribute("value");
+ }
+ else
+ {
+ //there is no exiting priority or level to view, move onto next category/logger
+ continue;
+ }
+
+ loggerLevelList.put(categoryName, priority);
+ }
+
+ //retrieve the 'logger' element nodes
+ NodeList loggerElements = doc.getElementsByTagName("logger");
+
+ String loggerName;
+ String level;
+
+ for (int i = 0; i < loggerElements.getLength(); i++)
+ {
+ Element loggerElement = (Element) loggerElements.item(i);
+ loggerName = loggerElement.getAttribute("name");
+
+ //retrieve the logger's mandatory 'level' element's value
+ //It may not be the only child node, so request by tag name.
+ NodeList levelElements = loggerElement.getElementsByTagName("level");
+
+ Element levelElement = (Element) levelElements.item(0);
+ level = levelElement.getAttribute("value");
+
+ loggerLevelList.put(loggerName, level);
+ }
+
+ return loggerLevelList;
+ }
+ finally
+ {
+ LOCK.unlock();
+ }
+ }
+
+ public synchronized TabularData viewConfigFileLoggerLevels() throws IOException
+ {
+ try
+ {
+ LOCK.lock();
+
+ if (_loggerLevelTabularType == null)
+ {
+ _logger.warn("TabluarData type not set up correctly");
+ return null;
+ }
+
+ _logger.info("Getting logger levels from log4j configuration file");
+
+ TabularData loggerLevelList = new TabularDataSupport(_loggerLevelTabularType);
+
+ Map<String,String> levels = retrieveConfigFileLoggersLevels(_log4jConfigFileName);
+
+ for (String loggerName : levels.keySet())
+ {
+ String level = levels.get(loggerName);
+
+ try
+ {
+ Object[] itemData = {loggerName, level.toUpperCase()};
+ CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData);
+ loggerLevelList.put(loggerData);
+ }
+ catch (OpenDataException e)
+ {
+ _logger.warn("Unable to create logger level list due to :" + e);
+ return null;
+ }
+ }
+
+ return loggerLevelList;
+ }
+ finally
+ {
+ LOCK.unlock();
+ }
+ }
+
+ public synchronized boolean setConfigFileLoggerLevel(String logger, String level) throws IOException
+ {
+ try
+ {
+ LOCK.lock();
+
+ //check that the specified level is a valid log4j Level
+ try
+ {
+ getLevel(level);
+ }
+ catch (Exception e)
+ {
+ //it isnt a valid level
+ return false;
+ }
+
+ _logger.info("Setting level to " + level + " for logger '" + logger
+ + "' in log4j xml configuration file: " + _log4jConfigFileName);
+
+ Document doc = parseConfigFile(_log4jConfigFileName);
+
+ //retrieve the 'category' and 'logger' element nodes
+ NodeList categoryElements = doc.getElementsByTagName("category");
+ NodeList loggerElements = doc.getElementsByTagName("logger");
+
+ //collect them into a single elements list
+ List<Element> logElements = new ArrayList<Element>();
+
+ for (int i = 0; i < categoryElements.getLength(); i++)
+ {
+ logElements.add((Element) categoryElements.item(i));
+ }
+ for (int i = 0; i < loggerElements.getLength(); i++)
+ {
+ logElements.add((Element) loggerElements.item(i));
+ }
+
+ //try to locate the specified logger/category in the elements retrieved
+ Element logElement = null;
+ for (Element e : logElements)
+ {
+ if (e.getAttribute("name").equals(logger))
+ {
+ logElement = e;
+ break;
+ }
+ }
+
+ if (logElement == null)
+ {
+ //no loggers/categories with given name found, does not exist to update
+ _logger.warn("Specified logger does not exist in the configuration file: " +logger);
+ return false;
+ }
+
+ //retrieve the optional 'priority' or 'level' sub-element value.
+ //It may not be the only child node, so request by tag name.
+ NodeList priorityElements = logElement.getElementsByTagName("priority");
+ NodeList levelElements = logElement.getElementsByTagName("level");
+
+ Element levelElement = null;
+ if (priorityElements.getLength() != 0)
+ {
+ levelElement = (Element) priorityElements.item(0);
+ }
+ else if (levelElements.getLength() != 0)
+ {
+ levelElement = (Element) levelElements.item(0);
+ }
+ else
+ {
+ //there is no exiting priority or level element to update
+ return false;
+ }
+
+ //update the element with the new level/priority
+ levelElement.setAttribute("value", level.toLowerCase());
+
+ //output the new file
+ return writeUpdatedConfigFile(_log4jConfigFileName, doc);
+ }
+ finally
+ {
+ LOCK.unlock();
+ }
+ }
+
+
+ /* The log4j XML configuration file DTD defines 2 possible element
+ * combinations for specifying the optional root logger level settings
+ * Must account for the following:
+ *
+ * <root> <priority value="y"/> </root> OR
+ * <root> <level value="y"/> </root>
+ *
+ * Noting also that the level/priority child element is optional too,
+ * and not the only possible child element.
+ */
+
+ public static synchronized String retrieveConfigFileRootLoggerLevel(String fileName) throws IOException
+ {
+ try
+ {
+ LOCK.lock();
+
+ Document doc = parseConfigFile(fileName);
+
+ //retrieve the optional 'root' element node
+ NodeList rootElements = doc.getElementsByTagName("root");
+
+ if (rootElements.getLength() == 0)
+ {
+ //there is no root logger definition
+ return "N/A";
+ }
+
+ Element rootElement = (Element) rootElements.item(0);
+
+ //retrieve the optional 'priority' or 'level' element value.
+ //It may not be the only child node, so request by tag name.
+ NodeList priorityElements = rootElement.getElementsByTagName("priority");
+ NodeList levelElements = rootElement.getElementsByTagName("level");
+ String priority = null;
+
+ if (priorityElements.getLength() != 0)
+ {
+ Element priorityElement = (Element) priorityElements.item(0);
+ priority = priorityElement.getAttribute("value");
+ }
+ else if(levelElements.getLength() != 0)
+ {
+ Element levelElement = (Element) levelElements.item(0);
+ priority = levelElement.getAttribute("value");
+ }
+
+ if(priority != null)
+ {
+ return priority;
+ }
+ else
+ {
+ return "N/A";
+ }
+ }
+ finally
+ {
+ LOCK.unlock();
+ }
+ }
+
+ public synchronized String getConfigFileRootLoggerLevel() throws IOException
+ {
+ return retrieveConfigFileRootLoggerLevel(_log4jConfigFileName).toUpperCase();
+ }
+
+ public synchronized boolean setConfigFileRootLoggerLevel(String level) throws IOException
+ {
+ try
+ {
+ LOCK.lock();
+
+ //check that the specified level is a valid log4j Level
+ try
+ {
+ Level newLevel = getLevel(level);
+ if(newLevel == null)
+ {
+ //A null Level reference implies inheritance. Setting the config file RootLogger
+ //to "null" or "inherited" just ensures it defaults to DEBUG at startup as Log4J
+ //prevents this catastrophic situation at startup and runtime anyway.
+ return false;
+ }
+ }
+ catch (Exception e)
+ {
+ //it isnt a valid level
+ return false;
+ }
+
+ _logger.info("Setting level to " + level + " for the Root logger in " +
+ "log4j xml configuration file: " + _log4jConfigFileName);
+
+ Document doc = parseConfigFile(_log4jConfigFileName);
+
+ //retrieve the optional 'root' element node
+ NodeList rootElements = doc.getElementsByTagName("root");
+
+ if (rootElements.getLength() == 0)
+ {
+ return false;
+ }
+
+ Element rootElement = (Element) rootElements.item(0);
+
+ //retrieve the optional 'priority' or 'level' sub-element value.
+ //It may not be the only child node, so request by tag name.
+ NodeList priorityElements = rootElement.getElementsByTagName("priority");
+ NodeList levelElements = rootElement.getElementsByTagName("level");
+
+ Element levelElement = null;
+ if (priorityElements.getLength() != 0)
+ {
+ levelElement = (Element) priorityElements.item(0);
+ }
+ else if (levelElements.getLength() != 0)
+ {
+ levelElement = (Element) levelElements.item(0);
+ }
+ else
+ {
+ //there is no exiting priority/level to update
+ return false;
+ }
+
+ //update the element with the new level/priority
+ levelElement.setAttribute("value", level);
+
+ //output the new file
+ return writeUpdatedConfigFile(_log4jConfigFileName, doc);
+ }
+ finally
+ {
+ LOCK.unlock();
+ }
+ }
+
+ public synchronized void reloadConfigFile() throws IOException
+ {
+ try
+ {
+ LOCK.lock();
+
+ QpidLog4JConfigurator.configure(_log4jConfigFileName);
+ _logger.info("Applied log4j configuration from: " + _log4jConfigFileName);
+ }
+ catch (IllegalLoggerLevelException e)
+ {
+ _logger.warn("The log4j configuration reload request was aborted: " + e);
+ //recommended that MBeans should use standard java.* and javax.* exceptions only
+ throw new IOException("The log4j configuration reload request was aborted: " + e.getMessage());
+ }
+ catch (ParserConfigurationException e)
+ {
+ _logger.warn("The log4j configuration reload request was aborted: " + e);
+ throw new IOException("The log4j configuration reload request was aborted: " + e.getMessage());
+ }
+ catch (SAXException e)
+ {
+ _logger.warn("The log4j configuration reload request was aborted: " + e);
+ //recommended that MBeans should use standard java.* and javax.* exceptions only
+ throw new IOException("The log4j configuration reload request was aborted: " + e.getMessage());
+ }
+ catch (IOException e)
+ {
+ _logger.warn("The log4j configuration reload request was aborted: " + e);
+ throw new IOException("The log4j configuration reload request was aborted: " + e.getMessage());
+ }
+ finally
+ {
+ LOCK.unlock();
+ }
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties b/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties
new file mode 100644
index 0000000000..7159c6b02c
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties
@@ -0,0 +1,323 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# Default File used for all non-defined locales.
+#
+# LogMessages used within the Java Broker as originally defined on the wiki:
+# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages
+#
+# Technical Notes:
+# This is a standard Java Properties file so white space is respected at the
+# end of the lines. This file is processed in a number of ways.
+# 1) ResourceBundle
+# This file is loaded through a ResourceBundle named LogMessages. the en_US
+# addition to the file is the localisation. Additional localisations can be
+# provided and will automatically be selected based on the <locale> value in
+# the config.xml. The default is en_US.
+#
+# 2) MessasgeFormat
+# Each entry is prepared with the Java Core MessageFormat methods. Therefore
+# most functionality you can do via MessageFormat can be done here:
+#
+# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html
+#
+# The cavet here is that only default String and number FormatTypes can be used.
+# This is due to the processing described in 3 below. If support for date, time
+# or choice is requried then the GenerateLogMessages class should be updated to
+# provide support.
+#
+# Format Note:
+# As mentioned earlier white space in this file is very important. One thing
+# in particular to note is the way MessageFormat peforms its replacements.
+# The replacement text will totally replace the {xxx} section so there will be
+# no addtion of white space or removal e.g.
+# MSG = Text----{0}----
+# When given parameter 'Hello' result in text:
+# Text----Hello----
+#
+# For simple arguments this is expected however when using Style formats then
+# it can be a little unexepcted. In particular a common pattern is used for
+# number replacements : {0,number,#}. This is used in the Broker to display an
+# Integer simply as the Integer with no formating. e.g new Integer(1234567)
+# becomes the String "1234567" which is can be contrasted with the pattern
+# without a style format field : {0,number} which becomes string "1,234,567".
+#
+# What you may not expect is that {0,number, #} would produce the String " 1234567"
+# note the space after the ',' here /\ has resulted in a space /\ in
+# the output.
+#
+# More details on the SubformatPattern can be found on the API link above.
+#
+# 3) GenerateLogMessage/Velocity Macro
+# This is the first and final stage of processing that this file goes through.
+# 1) Class Generation:
+# The GenerateLogMessage processes this file and uses the velocity Macro
+# to create classes with static methods to perform the logging and give us
+# compile time validation.
+#
+# 2) Property Processing:
+# During the class generation the message properties ({x}) are identified
+# and used to create the method signature.
+#
+# 3) Option Processing:
+# The Classes perform final formatting of the messages at runtime based on
+# optional parameters that are defined within the message. Optional
+# paramters are enclosed in square brackets e.g. [optional].
+#
+# To provide fixed log messages as required by the Technical Specification:
+# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages
+#
+# This file is processed by Velocity to create a number of classes that contain
+# static methods that provide LogMessages in the code to provide compile time
+# validation.
+#
+# For details of what processing is done see GenerateLogMessages.
+#
+# What a localiser or developer need know is the following:
+#
+# The Property structure is important is it defines how the class and methods
+# will be built.
+#
+# Class Generation:
+# =================
+#
+# Each class of messages will be split in to their own <Class>Messages.java
+# Currently the following classes are created and are populated with the
+# messages that bear their 3-digit type identifier:
+#
+# Class | Type
+# ---------------------|--------
+# Broker | BKR
+# ManagementConsole | MNG
+# VirtualHost | VHT
+# MessageStore | MST
+# ConfigStore | CFG
+# TransactionLog | TXN
+# Connection | CON
+# Channel | CHN
+# Queue | QUE
+# Exchange | EXH
+# Binding | BND
+# Subscription | SUB
+#
+# Property Format
+# ===============
+# The property format MUST adhere to the follow format to make it easier to
+# use the logging API as a developer but also so that operations staff can
+# easily locate log messages in the output.
+#
+# The property file should contain entries in the following format
+#
+# <Log Identifier, developer focused> = <Log Identifier, Operate focus> : <Log Message>
+#
+# eg:
+# BRK_SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#}
+#
+# Note: the developer focused identifier will become a method name so only a
+# valid method name should be used. Currently only '-' are converted to '_'.
+#
+# That said properties generate the logging code at build time so any error
+# can be easily identified.
+#
+# Property Processing:
+# ====================
+#
+# Each property is then processed by the GenerateLogMessages class to identify
+# The number and type of parameters, {x} entries. Parameters are defaulted to
+# String types but the use of FormatType number (e.g.{0,number}) will result
+# in a Number type being used. These parameters are then used to build the
+# method parameter list. e.g:
+# Property:
+# BRK_SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#}
+# becomes Method:
+# public static LogMessage BRK_SHUTTING_DOWN(String param1, Number param2)
+#
+# This improves our compile time validation of log message content and
+# ensures that change in the message format does not accidentally cause
+# erroneous messages.
+#
+# Option Processing:
+# ====================
+#
+# Options are identified in the log message as being surrounded by square
+# brackets ([ ]). These optional values can themselves contain paramters
+# however nesting of options is not permitted. Identification is performed on
+# first matchings so give the message:
+# Msg = Log Message [option1] [option2]
+# Two options will be identifed and enabled to select text 'option1 and
+# 'option2'.
+#
+# The nesting of a options is not supported and will provide
+# unexpected results. e.g. Using Message:
+# Msg = Log Message [option1 [sub-option2]]
+#
+# The options will be 'option1 [sub-option2' and 'sub-option2'. The first
+# option includes the second option as the nesting is not detected.
+#
+# The detected options are presented in the method signature as boolean options
+# numerically identified by their position in the message. e.g.
+# Property:
+# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}]
+# becomes Method:
+# public static LogMessage CON_1001(String param1, String param2, boolean opt1)
+#
+# The value of 'opt1' will show/hide the option in the message. Note that
+# 'param2' is still required however a null value can be used if the optional
+# section is not desired.
+#
+# Again here the importance of white space needs to be highlighted.
+# Looking at the QUE-1001 message as an example. The first thought on how this
+# would look would be as follows:
+# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}]
+# Each option is correctly defined so the text that is defined will appear when
+# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is
+# the white space. Using the above definition of QUE-1001 if we were to print
+# the message with only the Priority option displayed it would appear as this:
+# "Create : Owner: guest Priority: 1"
+# Note the spaces here /\ This is because only the text between the brackets
+# has been removed.
+#
+# Each option needs to include white space to correctly format the message. So
+# the correct definition of QUE-1001 is as follows:
+# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}]
+# Note that white space is included with each option and there is no extra
+# white space between the options. As a result the output with just Priority
+# enabled is as follows:
+# "Create : Owner: guest Priority: 1"
+#
+# The final processing that is done in the generation is the conversion of the
+# property name. As a '-' is an illegal character in the method name it is
+# converted to '_' This processing gives the final method signature as follows:
+# <Class>Message.<Type>_<Number>(<parmaters>,<options>)
+#
+#
+# Default File used for all non-defined locales.
+#Broker
+# 0 - Version
+# 1 = Build
+BRK_STARTUP = BRK-1001 : Startup : Version: {0} Build: {1}
+# 0 - Transport
+# 1 - Port
+BRK_LISTENING = BRK-1002 : Starting : Listening on {0} port {1,number,#}
+# 0 - Transport
+# 1 - Port
+BRK_SHUTTING_DOWN = BRK-1003 : Shuting down : {0} port {1,number,#}
+BRK_READY = BRK-1004 : Ready
+BRK_STOPPED = BRK-1005 : Stopped
+# 0 - path
+BRK_CONFIG = BRK-1006 : Using configuration : {0}
+# 0 - path
+BRK_LOG_CONFIG = BRK-1007 : Using logging configuration : {0}
+
+#ManagementConsole
+MNG_STARTUP = MNG-1001 : Startup
+# 0 - Service
+# 1 - Port
+MNG_LISTENING = MNG-1002 : Starting : {0} : Listening on port {1,number,#}
+# 0 - Service
+# 1 - Port
+MNG_SHUTTING_DOWN = MNG-1003 : Shuting down : {0} : port {1,number,#}
+MNG_READY = MNG-1004 : Ready
+MNG_STOPPED = MNG-1005 : Stopped
+# 0 - Path
+MNG_SSL_KEYSTORE = MNG-1006 : Using SSL Keystore : {0}
+MNG_OPEN = MNG-1007 : Open : User {0}
+MNG_CLOSE = MNG-1008 : Close
+
+
+#VirtualHost
+# 0 - name
+VHT_CREATED = VHT-1001 : Created : {0}
+VHT_CLOSED = VHT-1002 : Closed
+
+#MessageStore
+# 0 - name
+MST_CREATED = MST-1001 : Created : {0}
+# 0 - path
+MST_STORE_LOCATION = MST-1002 : Store location : {0}
+MST_CLOSED = MST-1003 : Closed
+MST_RECOVERY_START = MST-1004 : Recovery Start
+MST_RECOVERED = MST-1005 : Recovered {0,number} messages
+MST_RECOVERY_COMPLETE = MST-1006 : Recovery Complete
+
+#ConfigStore
+# 0 - name
+CFG-1001 = CFG-1001 : Created : {0}
+# 0 - path
+CFG-1002 = CFG-1002 : Store location : {0}
+CFG-1003 = CFG-1003 : Closed
+CFG-1004 = CFG-1004 : Recovery Start
+CFG-1005 = CFG-1005 : Recovery Complete
+
+#TransactionLog
+# 0 - name
+TXN-1001 = TXN-1001 : Created : {0}
+# 0 - path
+TXN-1002 = TXN-1002 : Store location : {0}
+TXN-1003 = TXN-1003 : Closed
+# 0 - queue name
+TXN-1004 = TXN-1004 : Recovery Start[ : {0}]
+# 0 - count
+# 1 - queue count
+TXN-1005 = TXN-1005 : Recovered {0,number} messages for queue {1}
+# 0 - queue name
+TXN-1006 = TXN-1006 : Recovery Complete[ : {0}]
+
+#Connection
+# 0 - Client id
+# 1 - Protocol Version
+CON_OPEN = CON-1001 : Open[ : Client ID : {0}][ : Protocol Version : {1}]
+CON_CLOSE = CON-1002 : Close
+
+#Channel
+CHN_CREATE = CHN-1001 : Create
+# 0 - flow
+CHN_FLOW = CHN-1002 : Flow {0}
+CHN_CLOSE = CHN-1003 : Close
+# 0 - bytes allowed in prefetch
+# 1 - number of messagse.
+CHN_PREFETCH_SIZE = CHN-1004 : Prefetch Size (bytes) {0,number} : Count {1,number}
+# 0 - queue causing flow control
+CHN_FLOW_ENFORCED = CHN-1005 : Flow Control Enforced (Queue {0})
+CHN_FLOW_REMOVED = CHN-1006 : Flow Control Removed
+
+#Queue
+# 0 - owner
+# 1 - priority
+QUE_CREATED = QUE-1001 : Create :[ Owner: {0}][ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}]
+QUE_DELETED = QUE-1002 : Deleted
+QUE_OVERFULL = QUE-1003 : Overfull : Size : {0,number} bytes, Capacity : {1,number}
+QUE_UNDERFULL = QUE-1004 : Underfull : Size : {0,number} bytes, Resume Capacity : {1,number}
+
+
+#Exchange
+# 0 - type
+# 1 - name
+EXH_CREATED = EXH-1001 : Create :[ Durable] Type: {0} Name: {1}
+EXH_DELETED = EXH-1002 : Deleted
+
+#Binding
+BND_CREATED = BND-1001 : Create[ : Arguments : {0}]
+BND_DELETED = BND-1002 : Deleted
+
+#Subscription
+SUB_CREATE = SUB-1001 : Create[ : Durable][ : Arguments : {0}]
+SUB_CLOSE = SUB-1002 : Close
+# 0 - The current subscription state
+SUB_STATE = SUB-1003 : State : {0}
+
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLogger.java b/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLogger.java
new file mode 100644
index 0000000000..f996576f31
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLogger.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.logging.rawloggers;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.qpid.server.logging.RawMessageLogger;
+
+public class Log4jMessageLogger implements RawMessageLogger
+{
+ public static final String DEFAULT_LEVEL = "INFO";
+ public static final String DEFAULT_LOGGER = "qpid.message";
+ private Level _level;
+ private Logger _rawMessageLogger;
+
+ public Log4jMessageLogger()
+ {
+ this(DEFAULT_LEVEL, DEFAULT_LOGGER);
+ }
+
+ public Log4jMessageLogger(String level, String logger)
+ {
+ _level = Level.toLevel(level);
+
+ _rawMessageLogger = Logger.getLogger(logger);
+ _rawMessageLogger.setLevel(_level);
+ }
+
+ public void rawMessage(String message)
+ {
+ rawMessage(message, null);
+ }
+
+ public void rawMessage(String message, Throwable throwable)
+ {
+ _rawMessageLogger.log(_level, message, throwable);
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/SystemOutMessageLogger.java b/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/SystemOutMessageLogger.java
new file mode 100644
index 0000000000..b9f0532d05
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/rawloggers/SystemOutMessageLogger.java
@@ -0,0 +1,40 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.rawloggers;
+
+import org.apache.qpid.server.logging.RawMessageLogger;
+
+public class SystemOutMessageLogger implements RawMessageLogger
+{
+ public void rawMessage(String message)
+ {
+ rawMessage(message, null);
+ }
+
+ public void rawMessage(String message, Throwable throwable)
+ {
+ System.out.println(message);
+ if (throwable != null)
+ {
+ throwable.printStackTrace(System.out);
+ }
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/AbstractLogSubject.java b/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/AbstractLogSubject.java
new file mode 100644
index 0000000000..d7be9ea4c7
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/AbstractLogSubject.java
@@ -0,0 +1,64 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.subjects;
+
+import org.apache.qpid.server.logging.LogSubject;
+
+import java.text.MessageFormat;
+
+/**
+ * The LogSubjects all have a similar requriement to format their output and
+ * provide the String value.
+ *
+ * This Abstract LogSubject provides this basic functionality, allowing the
+ * actual LogSubjects to provide their formating and data.
+ */
+public abstract class AbstractLogSubject implements LogSubject
+{
+ /**
+ * The logString that will be returned via toString
+ */
+ protected String _logString;
+
+ /**
+ * Set the toString logging of this LogSubject. Based on a format provided
+ * by format and the var args.
+ * @param format The Message to format
+ * @param args The values to put in to the message.
+ */
+ protected void setLogStringWithFormat(String format, Object... args)
+ {
+ _logString = "[" + MessageFormat.format(format, args) + "] ";
+ }
+
+ /**
+ * ToString is how the Logging infrastructure will get the text for this
+ * LogSubject
+ *
+ * @return String representing this LogSubject
+ */
+ @Override
+ public String toString()
+ {
+ return _logString;
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/BindingLogSubject.java b/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/BindingLogSubject.java
new file mode 100644
index 0000000000..fd171fea5a
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/BindingLogSubject.java
@@ -0,0 +1,62 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.subjects;
+
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.queue.AMQQueue;
+
+public class BindingLogSubject extends AbstractLogSubject
+{
+
+ /**
+ * LOG FORMAT for the ChannelLogSubject,
+ * Uses a MessageFormat call to insert the requried values according to
+ * these indicies:
+ *
+ * 0 - Virtualhost Name
+ * 1 - Exchange Type
+ * 2 - Exchange Name
+ * 3 - Queue Name
+ * 4 - Binding RoutingKey
+ */
+ protected static String BINDING_FORMAT = "vh(/{0})/ex({1}/{2})/qu({3})/rk({4})";
+
+ /**
+ * Create a BindingLogSubject that Logs in the following format.
+ *
+ * [ vh(/)/ex(amq.direct)/qu(testQueue)/bd(testQueue) ]
+ *
+ * @param routingKey
+ * @param exchange
+ * @param queue
+ */
+ public BindingLogSubject(AMQShortString routingKey, Exchange exchange,
+ AMQQueue queue)
+ {
+ setLogStringWithFormat(BINDING_FORMAT, queue.getVirtualHost().getName(),
+ exchange.getType(),
+ exchange.getName(),
+ queue.getName(),
+ routingKey);
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java b/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java
new file mode 100644
index 0000000000..dc6e79a214
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java
@@ -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.
+ *
+ */
+package org.apache.qpid.server.logging.subjects;
+
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+
+public class ChannelLogSubject extends AbstractLogSubject
+{
+ /**
+ * LOG FORMAT for the ChannelLogSubject,
+ * Uses a MessageFormat call to insert the requried values according to
+ * these indicies:
+ *
+ * 0 - Connection ID
+ * 1 - User ID
+ * 2 - IP
+ * 3 - Virtualhost
+ * 4 - Channel ID
+ */
+ public static String CHANNEL_FORMAT = ConnectionLogSubject.CONNECTION_FORMAT
+ + "/ch:{4}";
+
+ public ChannelLogSubject(AMQChannel channel)
+ {
+ AMQProtocolSession session = channel.getProtocolSession();
+
+ /**
+ * LOG FORMAT used by the AMQPConnectorActor follows
+ * ChannelLogSubject.CHANNEL_FORMAT :
+ * con:{0}({1}@{2}/{3})/ch:{4}
+ *
+ * Uses a MessageFormat call to insert the required values according to
+ * these indices:
+ *
+ * 0 - Connection ID
+ * 1 - User ID
+ * 2 - IP
+ * 3 - Virtualhost
+ * 4 - Channel ID
+ */
+ setLogStringWithFormat(CHANNEL_FORMAT,
+ session.getSessionID(),
+ session.getPrincipal().getName(),
+ session.getRemoteAddress(),
+ session.getVirtualHost().getName(),
+ channel.getChannelId());
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java b/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java
new file mode 100644
index 0000000000..f3df87c432
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java
@@ -0,0 +1,137 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.subjects;
+
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+
+import java.text.MessageFormat;
+
+/** The Connection LogSubject */
+public class ConnectionLogSubject extends AbstractLogSubject
+{
+
+ /**
+ * 0 - Connection ID
+ * 1 - Remote Address
+ */
+ public static String SOCKET_FORMAT = "con:{0}({1})";
+
+ /**
+ * LOG FORMAT for the ConnectionLogSubject,
+ * Uses a MessageFormat call to insert the requried values according to
+ * these indicies:
+ *
+ * 0 - Connection ID
+ * 1 - User ID
+ * 2 - IP
+ */
+ public static final String USER_FORMAT = "con:{0}({1}@{2})";
+
+ /**
+ * LOG FORMAT for the ConnectionLogSubject,
+ * Uses a MessageFormat call to insert the required values according to
+ * these indices:
+ *
+ * 0 - Connection ID
+ * 1 - User ID
+ * 2 - IP
+ * 3 - Virtualhost
+ */
+ public static final String CONNECTION_FORMAT = "con:{0}({1}@{2}/{3})";
+
+
+ public ConnectionLogSubject(AMQProtocolSession session)
+ {
+ _session = session;
+ }
+
+ // The Session this Actor is representing
+ private AMQProtocolSession _session;
+
+ // Used to stop re-creating the _logString when we reach our final format
+ private boolean _upToDate = false;
+
+ /**
+ * Update the LogString as the Connection process proceeds.
+ *
+ * When the Session has an authorized ID add that to the string.
+ *
+ * When the Session then gains a Vhost add that to the string, at this point
+ * we can set upToDate = true as the _logString will not need to be updated
+ * from this point onwards.
+ */
+ private void updateLogString()
+ {
+ if (!_upToDate)
+ {
+ if (_session.getPrincipal() != null)
+ {
+ if (_session.getVirtualHost() != null)
+ {
+ /**
+ * LOG FORMAT used by the AMQPConnectorActor follows
+ * ConnectionLogSubject.CONNECTION_FORMAT :
+ * con:{0}({1}@{2}/{3})
+ *
+ * Uses a MessageFormat call to insert the required values according to
+ * these indices:
+ *
+ * 0 - Connection ID
+ * 1 - User ID
+ * 2 - IP
+ * 3 - Virtualhost
+ */
+ _logString = "[" + MessageFormat.format(ConnectionLogSubject.CONNECTION_FORMAT,
+ _session.getSessionID(),
+ _session.getPrincipal().getName(),
+ _session.getRemoteAddress(),
+ _session.getVirtualHost().getName())
+ + "] ";
+
+ _upToDate = true;
+ }
+ else
+ {
+ _logString = "[" + MessageFormat.format(USER_FORMAT,
+ _session.getSessionID(),
+ _session.getPrincipal().getName(),
+ _session.getRemoteAddress())
+ + "] ";
+
+ }
+ }
+ else
+ {
+ _logString = "[" + MessageFormat.format(SOCKET_FORMAT,
+ _session.getSessionID(),
+ _session.getRemoteAddress())
+ + "] ";
+ }
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ updateLogString();
+ return super.toString();
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubject.java b/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubject.java
new file mode 100644
index 0000000000..21e5f5e4ce
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubject.java
@@ -0,0 +1,46 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.subjects;
+
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+public class ExchangeLogSubject extends AbstractLogSubject
+{
+
+ /**
+ * LOG FORMAT for the ExchangeLogSubject,
+ * Uses a MessageFormat call to insert the requried values according to
+ * these indicies:
+ *
+ * 0 - Virtualhost Name
+ * 1 - Exchange Type
+ * 2 - Exchange Name
+ */
+ protected static String BINDING_FORMAT = "vh(/{0})/ex({1}/{2})";
+
+ /** Create an ExchangeLogSubject that Logs in the following format. */
+ public ExchangeLogSubject(Exchange exchange, VirtualHost vhost)
+ {
+ setLogStringWithFormat(BINDING_FORMAT, vhost.getName(),
+ exchange.getType(), exchange.getName());
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessageStoreLogSubject.java b/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessageStoreLogSubject.java
new file mode 100644
index 0000000000..e11cbba4f4
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/MessageStoreLogSubject.java
@@ -0,0 +1,45 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.subjects;
+
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.store.MessageStore;
+
+public class MessageStoreLogSubject extends AbstractLogSubject
+{
+
+ /**
+ * LOG FORMAT for the MessagesStoreLogSubject,
+ * Uses a MessageFormat call to insert the requried values according to
+ * these indicies:
+ *
+ * 0 - Virtualhost Name
+ * 1 - Message Store Type
+ */
+ protected static String BINDING_FORMAT = "vh(/{0})/ms({1})";
+
+ /** Create an ExchangeLogSubject that Logs in the following format. */
+ public MessageStoreLogSubject(VirtualHost vhost, MessageStore store)
+ {
+ setLogStringWithFormat(BINDING_FORMAT, vhost.getName(),
+ store.getClass().getSimpleName());
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java b/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java
new file mode 100644
index 0000000000..b132d9e93f
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java
@@ -0,0 +1,45 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.subjects;
+
+import org.apache.qpid.server.queue.AMQQueue;
+
+public class QueueLogSubject extends AbstractLogSubject
+{
+
+ /**
+ * LOG FORMAT for the ExchangeLogSubject,
+ * Uses a MessageFormat call to insert the requried values according to
+ * these indicies:
+ *
+ * 0 - Virtualhost name
+ * 1 - queue name
+ */
+ public static String LOG_FORMAT = "vh(/{0})/qu({1})";
+
+ /** Create an QueueLogSubject that Logs in the following format. */
+ public QueueLogSubject(AMQQueue queue)
+ {
+ setLogStringWithFormat(LOG_FORMAT,
+ queue.getVirtualHost().getName(),
+ queue.getName());
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java b/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java
new file mode 100644
index 0000000000..2dde1b6b41
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubject.java
@@ -0,0 +1,62 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.subjects;
+
+import org.apache.qpid.server.subscription.Subscription;
+
+import java.text.MessageFormat;
+
+public class SubscriptionLogSubject extends AbstractLogSubject
+{
+
+ /**
+ * LOG FORMAT for the SubscriptionLogSubject,
+ * Uses a MessageFormat call to insert the requried values according to
+ * these indicies:
+ *
+ * 0 - Subscription ID
+ */
+ public static String SUBSCRIPTION_FORMAT = "sub:{0}";
+
+ /**
+ * Create an QueueLogSubject that Logs in the following format.
+ *
+ * @param subscription
+ */
+ public SubscriptionLogSubject(Subscription subscription)
+ {
+ // Delegate the formating of the Queue to the QueueLogSubject. So final
+ // log string format is:
+ // [ sub:<id>(vh(<vhost>)/qu(<queue>)) ]
+
+ String queueString = new QueueLogSubject(subscription.getQueue()).toString();
+
+ _logString = "[" + MessageFormat.format(SubscriptionLogSubject.SUBSCRIPTION_FORMAT,
+ subscription.getSubscriptionID())
+ + "("
+ // queueString is [vh(/{0})/qu({1}) ] so need to trim
+ // ^ ^^
+ + queueString.substring(1,queueString.length() - 3)
+ + ")"
+ + "] ";
+
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java b/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java
index a2c2bd62a2..594ae24502 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java
@@ -20,6 +20,10 @@
*/
package org.apache.qpid.server.management;
+import org.apache.qpid.server.logging.actors.ManagementActor;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.LogActor;
+
import javax.management.ListenerNotFoundException;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
@@ -50,10 +54,15 @@ public abstract class AMQManagedObject extends DefaultManagedObject
protected MBeanInfo _mbeanInfo;
- protected AMQManagedObject(Class<?> managementInterface, String typeName)
+ protected LogActor _logActor;
+
+ protected AMQManagedObject(Class<?> managementInterface, String typeName, int version)
throws NotCompliantMBeanException
{
- super(managementInterface, typeName);
+ super(managementInterface, typeName, version);
+ // CurrentActor will be defined as these objects are created during
+ // broker startup.
+ _logActor = new ManagementActor(CurrentActor.get().getRootMessageLogger());
buildMBeanInfo();
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java b/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java
index 84526dbc11..d72b8f24ec 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -39,13 +39,15 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana
private Class<?> _managementInterface;
private String _typeName;
+ private int _version;
- protected DefaultManagedObject(Class<?> managementInterface, String typeName)
+ protected DefaultManagedObject(Class<?> managementInterface, String typeName, int version)
throws NotCompliantMBeanException
{
super(managementInterface);
_managementInterface = managementInterface;
_typeName = typeName;
+ _version = version;
}
public String getType()
@@ -63,16 +65,9 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana
return null;
}
- public void register() throws AMQException
+ public void register() throws JMException
{
- try
- {
- getManagedObjectRegistry().registerObject(this);
- }
- catch (JMException e)
- {
- throw new AMQException("Error registering managed object " + this + ": " + e, e);
- }
+ getManagedObjectRegistry().registerObject(this);
}
protected ManagedObjectRegistry getManagedObjectRegistry()
@@ -96,7 +91,7 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana
{
return getObjectInstanceName() + "[" + getType() + "]";
}
-
+
/**
* Created the ObjectName as per the JMX Specs
@@ -115,6 +110,10 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana
objectName.append(getHierarchicalName(this));
objectName.append("name=").append(name);
+ objectName.append(",");
+ objectName.append("version=").append(_version);
+
+
return new ObjectName(objectName.toString());
}
@@ -132,6 +131,9 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana
objectName.append(hierarchyName.substring(0, hierarchyName.lastIndexOf(",")));
}
+ objectName.append(",");
+ objectName.append("version=").append(_version);
+
return new ObjectName(objectName.toString());
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java
index 4caae2b26f..048551010e 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java
@@ -20,54 +20,68 @@
*/
package org.apache.qpid.server.management;
+import org.apache.commons.configuration.ConfigurationException;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.registry.IApplicationRegistry;
-import org.apache.qpid.server.security.auth.database.Base64MD5PasswordFilePrincipalDatabase;
-import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase;
import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
-import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser;
+import org.apache.qpid.server.security.auth.rmi.RMIPasswordAuthenticator;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.messages.ManagementConsoleMessages;
import javax.management.JMException;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
+import javax.management.ObjectName;
+import javax.management.NotificationListener;
+import javax.management.NotificationFilterSupport;
import javax.management.remote.JMXConnectorServer;
-import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.MBeanServerForwarder;
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.UnsupportedCallbackException;
-import javax.security.auth.login.AccountNotFoundException;
-import javax.security.sasl.AuthorizeCallback;
+import javax.management.remote.JMXConnectionNotification;
+import javax.management.remote.rmi.RMIConnectorServer;
+import javax.management.remote.rmi.RMIJRMPServerImpl;
+import javax.management.remote.rmi.RMIServerImpl;
+import javax.rmi.ssl.SslRMIClientSocketFactory;
+import javax.rmi.ssl.SslRMIServerSocketFactory;
+
+import java.io.File;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.management.ManagementFactory;
+import java.lang.reflect.Proxy;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
import java.util.Map;
/**
- * This class starts up an MBeanserver. If out of the box agent is being used then there are no security features
- * implemented. To use the security features like user authentication, turn off the jmx options in the "QPID_OPTS" env
- * variable and use JMXMP connector server. If JMXMP connector is not available, then the standard JMXConnector will be
- * used, which again doesn't have user authentication.
+ * This class starts up an MBeanserver. If out of the box agent has been enabled then there are no
+ * security features implemented like user authentication and authorisation.
*/
public class JMXManagedObjectRegistry implements ManagedObjectRegistry
{
private static final Logger _log = Logger.getLogger(JMXManagedObjectRegistry.class);
+ private static final Logger _startupLog = Logger.getLogger("Qpid.Broker");
+
+ public static final String MANAGEMENT_PORT_CONFIG_PATH = "management.jmxport";
+ public static final int MANAGEMENT_PORT_DEFAULT = 8999;
+ public static final int PORT_EXPORT_OFFSET = 100;
private final MBeanServer _mbeanServer;
+ private JMXConnectorServer _cs;
private Registry _rmiRegistry;
- private JMXServiceURL _jmxURL;
- public static final String MANAGEMENT_PORT_CONFIG_PATH = "management.jmxport";
- public static final int MANAGEMENT_PORT_DEFAULT = 8999;
public JMXManagedObjectRegistry() throws AMQException
{
@@ -75,7 +89,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry
IApplicationRegistry appRegistry = ApplicationRegistry.getInstance();
// Retrieve the config parameters
- boolean platformServer = appRegistry.getConfiguration().getBoolean("management.platform-mbeanserver", true);
+ boolean platformServer = appRegistry.getConfiguration().getPlatformMbeanserver();
_mbeanServer =
platformServer ? ManagementFactory.getPlatformMBeanServer()
@@ -83,92 +97,257 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry
}
- public void start() throws IOException
+ public void start() throws IOException, ConfigurationException
{
- // Check if the "QPID_OPTS" is set to use Out of the Box JMXAgent
+
+ CurrentActor.get().message(ManagementConsoleMessages.MNG_STARTUP());
+
+ //check if system properties are set to use the JVM's out-of-the-box JMXAgent
if (areOutOfTheBoxJMXOptionsSet())
{
- _log.info("JMX: Using the out of the box JMX Agent");
+ _log.warn("JMX: Using the out of the box JMX Agent");
+ _startupLog.warn("JMX: Using the out of the box JMX Agent");
return;
}
IApplicationRegistry appRegistry = ApplicationRegistry.getInstance();
+ int port = appRegistry.getConfiguration().getJMXManagementPort();
- boolean security = appRegistry.getConfiguration().getBoolean("management.security-enabled", false);
- int port = appRegistry.getConfiguration().getInt(MANAGEMENT_PORT_CONFIG_PATH, MANAGEMENT_PORT_DEFAULT);
+ //retrieve the Principal Database assigned to JMX authentication duties
+ String jmxDatabaseName = appRegistry.getConfiguration().getJMXPrincipalDatabase();
+ Map<String, PrincipalDatabase> map = appRegistry.getDatabaseManager().getDatabases();
+ PrincipalDatabase db = map.get(jmxDatabaseName);
- if (security)
+ HashMap<String,Object> env = new HashMap<String,Object>();
+
+ //Socket factories for the RMIConnectorServer, either default or SLL depending on configuration
+ RMIClientSocketFactory csf;
+ RMIServerSocketFactory ssf;
+
+ //check ssl enabled option in config, default to true if option is not set
+ boolean sslEnabled = appRegistry.getConfiguration().getManagementSSLEnabled();
+
+ if (sslEnabled)
{
- // For SASL using JMXMP
- _jmxURL = new JMXServiceURL("jmxmp", null, port);
+ //set the SSL related system properties used by the SSL RMI socket factories to the values
+ //given in the configuration file, unless command line settings have already been specified
+ String keyStorePath;
- Map env = new HashMap();
- Map<String, PrincipalDatabase> map = appRegistry.getDatabaseManager().getDatabases();
- PrincipalDatabase db = null;
+ if(System.getProperty("javax.net.ssl.keyStore") != null)
+ {
+ keyStorePath = System.getProperty("javax.net.ssl.keyStore");
+ }
+ else
+ {
+ keyStorePath = appRegistry.getConfiguration().getManagementKeyStorePath();
+ }
- for (Map.Entry<String, PrincipalDatabase> entry : map.entrySet())
+ //check the keystore path value is valid
+ if (keyStorePath == null)
{
- if (entry.getValue() instanceof Base64MD5PasswordFilePrincipalDatabase)
+ throw new ConfigurationException("JMX management SSL keystore path not defined, " +
+ "unable to start SSL protected JMX ConnectorServer");
+ }
+ else
+ {
+ //ensure the system property is set
+ System.setProperty("javax.net.ssl.keyStore", keyStorePath);
+
+ //check the file is usable
+ File ksf = new File(keyStorePath);
+
+ if (!ksf.exists())
{
- db = entry.getValue();
- break;
+ throw new FileNotFoundException("Cannot find JMX management SSL keystore file " + ksf + "\n"
+ + "Check broker configuration, or see create-example-ssl-stores script"
+ + "in the bin/ directory if you need to generate an example store.");
}
- else if (entry.getValue() instanceof PlainPasswordFilePrincipalDatabase)
+ if (!ksf.canRead())
{
- db = entry.getValue();
+ throw new FileNotFoundException("Cannot read JMX management SSL keystore file: "
+ + ksf + ". Check permissions.");
}
- }
+
+ _log.info("JMX ConnectorServer using SSL keystore file " + ksf.getAbsolutePath());
+ _startupLog.info("JMX ConnectorServer using SSL keystore file " + ksf.getAbsolutePath());
- if (db instanceof Base64MD5PasswordFilePrincipalDatabase)
- {
- env.put("jmx.remote.profiles", "SASL/CRAM-MD5");
- CRAMMD5HashedInitialiser initialiser = new CRAMMD5HashedInitialiser();
- initialiser.initialise(db);
- env.put("jmx.remote.sasl.callback.handler", initialiser.getCallbackHandler());
+ CurrentActor.get().message(ManagementConsoleMessages.MNG_SSL_KEYSTORE(ksf.getAbsolutePath()));
}
- else if (db instanceof PlainPasswordFilePrincipalDatabase)
+
+ //check the key store password is set
+ if (System.getProperty("javax.net.ssl.keyStorePassword") == null)
{
- env.put("jmx.remote.profiles", "SASL/PLAIN");
- env.put("jmx.remote.sasl.callback.handler", new UserCallbackHandler(db));
+
+ if (appRegistry.getConfiguration().getManagementKeyStorePassword() == null)
+ {
+ throw new ConfigurationException("JMX management SSL keystore password not defined, " +
+ "unable to start requested SSL protected JMX server");
+ }
+ else
+ {
+ System.setProperty("javax.net.ssl.keyStorePassword",
+ appRegistry.getConfiguration().getManagementKeyStorePassword());
+ }
}
- // Enable the SSL security and server authentication
- /*
- SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory();
- SslRMIServerSocketFactory ssf = new SslRMIServerSocketFactory();
- env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf);
- env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf);
- */
+ //create the SSL RMI socket factories
+ csf = new SslRMIClientSocketFactory();
+ ssf = new SslRMIServerSocketFactory();
- JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, env, _mbeanServer);
- MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance();
- cs.setMBeanServerForwarder(mbsf);
- cs.start();
- _log.warn("JMX: Started JMXConnector server on port '" + port + "' with SASL");
+ _log.warn("Starting JMX ConnectorServer on port '"+ port + "' (+" +
+ (port +PORT_EXPORT_OFFSET) + ") with SSL");
+ _startupLog.warn("Starting JMX ConnectorServer on port '"+ port + "' (+" +
+ (port +PORT_EXPORT_OFFSET) + ") with SSL");
+
+ CurrentActor.get().message(ManagementConsoleMessages.MNG_LISTENING("SSL RMI Registry", port));
+ CurrentActor.get().message(ManagementConsoleMessages.MNG_LISTENING("SSL RMI ConnectorServer", port + PORT_EXPORT_OFFSET));
}
else
{
- startJMXConnectorServer(port);
- _log.warn("JMX: Started JMXConnector server on port '" + port + "' with security disabled");
+ //Do not specify any specific RMI socket factories, resulting in use of the defaults.
+ csf = null;
+ ssf = null;
+
+ _log.warn("Starting JMX ConnectorServer on port '" + port + "' (+" + (port +PORT_EXPORT_OFFSET) + ")");
+ _startupLog.warn("Starting JMX ConnectorServer on port '" + port + "' (+" + (port +PORT_EXPORT_OFFSET) + ")");
+ CurrentActor.get().message(ManagementConsoleMessages.MNG_LISTENING("RMI Registry", port));
+ CurrentActor.get().message(ManagementConsoleMessages.MNG_LISTENING("RMI ConnectorServer", port + PORT_EXPORT_OFFSET));
+ }
+
+ //add a JMXAuthenticator implementation the env map to authenticate the RMI based JMX connector server
+ RMIPasswordAuthenticator rmipa = new RMIPasswordAuthenticator();
+ rmipa.setPrincipalDatabase(db);
+ env.put(JMXConnectorServer.AUTHENTICATOR, rmipa);
+
+ /*
+ * Start a RMI registry on the management port, to hold the JMX RMI ConnectorServer stub.
+ * Using custom socket factory to prevent anyone (including us unfortunately) binding to the registry using RMI.
+ * As a result, only binds made using the object reference will succeed, thus securing it from external change.
+ */
+ System.setProperty("java.rmi.server.randomIDs", "true");
+ _rmiRegistry = LocateRegistry.createRegistry(port, null, new CustomRMIServerSocketFactory());
+
+ /*
+ * We must now create the RMI ConnectorServer manually, as the JMX Factory methods use RMI calls
+ * to bind the ConnectorServer to the registry, which will now fail as for security we have
+ * locked it from any RMI based modifications, including our own. Instead, we will manually bind
+ * the RMIConnectorServer stub to the registry using its object reference, which will still succeed.
+ *
+ * The registry is exported on the defined management port 'port'. We will export the RMIConnectorServer
+ * on 'port +1'. Use of these two well-defined ports will ease any navigation through firewall's.
+ */
+ final RMIServerImpl rmiConnectorServerStub = new RMIJRMPServerImpl(port+PORT_EXPORT_OFFSET, csf, ssf, env);
+ String localHost;
+ try
+ {
+ localHost = InetAddress.getLocalHost().getHostName();
+ }
+ catch(UnknownHostException ex)
+ {
+ localHost="127.0.0.1";
}
+ final String hostname = localHost;
+ final JMXServiceURL externalUrl = new JMXServiceURL(
+ "service:jmx:rmi://"+hostname+":"+(port+PORT_EXPORT_OFFSET)+"/jndi/rmi://"+hostname+":"+port+"/jmxrmi");
+
+ final JMXServiceURL internalUrl = new JMXServiceURL("rmi", hostname, port+PORT_EXPORT_OFFSET);
+ _cs = new RMIConnectorServer(internalUrl, env, rmiConnectorServerStub, _mbeanServer)
+ {
+ @Override
+ public synchronized void start() throws IOException
+ {
+ try
+ {
+ //manually bind the connector server to the registry at key 'jmxrmi', like the out-of-the-box agent
+ _rmiRegistry.bind("jmxrmi", rmiConnectorServerStub);
+ }
+ catch (AlreadyBoundException abe)
+ {
+ //key was already in use. shouldnt happen here as its a new registry, unbindable by normal means.
+
+ //IOExceptions are the only checked type throwable by the method, wrap and rethrow
+ IOException ioe = new IOException(abe.getMessage());
+ ioe.initCause(abe);
+ throw ioe;
+ }
+
+ //now do the normal tasks
+ super.start();
+ }
+
+ @Override
+ public JMXServiceURL getAddress()
+ {
+ //must return our pre-crafted url that includes the full details, inc JNDI details
+ return externalUrl;
+ }
+
+ };
+
+
+ //Add the custom invoker as an MBeanServerForwarder, and start the RMIConnectorServer.
+ MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance();
+ _cs.setMBeanServerForwarder(mbsf);
+
+ NotificationFilterSupport filter = new NotificationFilterSupport();
+ filter.enableType(JMXConnectionNotification.OPENED);
+ filter.enableType(JMXConnectionNotification.CLOSED);
+ filter.enableType(JMXConnectionNotification.FAILED);
+ // Get the handler that is used by the above MBInvocationHandler Proxy.
+ // which is the MBeanInvocationHandlerImpl and so also a NotificationListener
+ _cs.addNotificationListener((NotificationListener) Proxy.getInvocationHandler(mbsf), filter, null);
+
+ _cs.start();
+
+
+ CurrentActor.get().message(ManagementConsoleMessages.MNG_READY());
}
- /**
- * Starts up an RMIRegistry at configured port and attaches a JMXConnectorServer to it.
- *
- * @param port
- *
- * @throws IOException
+ /*
+ * Custom RMIServerSocketFactory class, used to prevent updates to the RMI registry.
+ * Supplied to the registry at creation, this will prevent RMI-based operations on the
+ * registry such as attempting to bind a new object, thereby securing it from tampering.
+ * This is accomplished by always returning null when attempting to determine the address
+ * of the caller, thus ensuring the registry will refuse the attempt. Calls to bind etc
+ * made using the object reference will not be affected and continue to operate normally.
*/
- private void startJMXConnectorServer(int port) throws IOException
+
+ private class CustomRMIServerSocketFactory implements RMIServerSocketFactory
{
- startRMIRegistry(port);
- _jmxURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + port + "/jmxrmi");
- JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, null, _mbeanServer);
- cs.start();
+
+ public ServerSocket createServerSocket(int port) throws IOException
+ {
+ return new NoLocalAddressServerSocket(port);
+ }
+
+ private class NoLocalAddressServerSocket extends ServerSocket
+ {
+ NoLocalAddressServerSocket(int port) throws IOException
+ {
+ super(port);
+ }
+
+ @Override
+ public Socket accept() throws IOException
+ {
+ Socket s = new NoLocalAddressSocket();
+ super.implAccept(s);
+ return s;
+ }
+ }
+
+ private class NoLocalAddressSocket extends Socket
+ {
+ @Override
+ public InetAddress getInetAddress()
+ {
+ return null;
+ }
+ }
}
+
public void registerObject(ManagedObject managedObject) throws JMException
{
_mbeanServer.registerMBean(managedObject, managedObject.getObjectName());
@@ -179,11 +358,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry
_mbeanServer.unregisterMBean(managedObject.getObjectName());
}
- /**
- * Checks is the "QPID_OPTS" env variable is set to use the out of the box JMXAgent.
- *
- * @return
- */
+ // checks if the system properties are set which enable the JVM's out-of-the-box JMXAgent.
private boolean areOutOfTheBoxJMXOptionsSet()
{
if (System.getProperty("com.sun.management.jmxremote") != null)
@@ -199,20 +374,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry
return false;
}
- /**
- * Starts the rmi registry at given port
- *
- * @param port
- *
- * @throws RemoteException
- */
- private void startRMIRegistry(int port) throws RemoteException
- {
- System.setProperty("java.rmi.server.randomIDs", "true");
- _rmiRegistry = LocateRegistry.createRegistry(port);
- }
-
- // stops the RMIRegistry, if it was running and bound to a port
+ // stops the RMIRegistry and unregisters the MBeans from the MBeanServer
public void close() throws RemoteException
{
if (_rmiRegistry != null)
@@ -220,64 +382,46 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry
// Stopping the RMI registry
UnicastRemoteObject.unexportObject(_rmiRegistry, true);
}
- }
-
- /** This class is used for SASL enabled JMXConnector for performing user authentication. */
- private class UserCallbackHandler implements CallbackHandler
- {
- private final PrincipalDatabase _principalDatabase;
-
- protected UserCallbackHandler(PrincipalDatabase database)
+
+ if (_cs != null)
{
- _principalDatabase = database;
- }
-
- public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
- {
- // Retrieve callbacks
- NameCallback ncb = null;
- PasswordCallback pcb = null;
- for (int i = 0; i < callbacks.length; i++)
+ // Stopping the JMX ConnectorServer
+ try
{
- if (callbacks[i] instanceof NameCallback)
- {
- ncb = (NameCallback) callbacks[i];
- }
- else if (callbacks[i] instanceof PasswordCallback)
- {
- pcb = (PasswordCallback) callbacks[i];
- }
- else if (callbacks[i] instanceof AuthorizeCallback)
- {
- ((AuthorizeCallback) callbacks[i]).setAuthorized(true);
- }
- else
- {
- throw new UnsupportedCallbackException(callbacks[i]);
- }
+ _cs.stop();
+ CurrentActor.get().message(ManagementConsoleMessages.MNG_SHUTTING_DOWN("RMI Registry", _cs.getAddress().getPort() - PORT_EXPORT_OFFSET));
+ CurrentActor.get().message(ManagementConsoleMessages.MNG_SHUTTING_DOWN("RMI ConnectorServer", _cs.getAddress().getPort()));
}
-
- boolean authorized = false;
- // Process retrieval of password; can get password if username is available in NameCallback
- if ((ncb != null) && (pcb != null))
+ catch (IOException e)
{
- String username = ncb.getDefaultName();
- try
- {
- authorized = _principalDatabase.verifyPassword(username, pcb.getPassword());
- }
- catch (AccountNotFoundException e)
- {
- IOException ioe = new IOException("User not authorized. " + e);
- ioe.initCause(e);
- throw ioe;
- }
+ _log.warn("Error while closing the JMX ConnectorServer: " + e.getMessage());
}
+ }
+
+ //ObjectName query to gather all Qpid related MBeans
+ ObjectName mbeanNameQuery = null;
+ try
+ {
+ mbeanNameQuery = new ObjectName(ManagedObject.DOMAIN + ":*");
+ }
+ catch (Exception e1)
+ {
+ _log.warn("Unable to generate MBean ObjectName query for close operation");
+ }
- if (!authorized)
+ for (ObjectName name : _mbeanServer.queryNames(mbeanNameQuery, null))
+ {
+ try
+ {
+ _mbeanServer.unregisterMBean(name);
+ }
+ catch (JMException e)
{
- throw new IOException("User not authorized.");
+ _log.error("Exception unregistering MBean '"+ name +"': " + e.getMessage());
}
}
+
+ CurrentActor.get().message(ManagementConsoleMessages.MNG_STOPPED());
}
+
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java
deleted file mode 100644
index 7d42297699..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java
+++ /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.
- *
- *
- */
-
-package org.apache.qpid.server.management;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Annotation for MBean attributes. This should be used with getter or setter
- * methods of attributes.
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.METHOD)
-@Inherited
-public @interface MBeanAttribute
-{
- String name();
- String description();
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java
deleted file mode 100644
index 9138e03085..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java
+++ /dev/null
@@ -1,39 +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.
- *
- *
- */
-
-package org.apache.qpid.server.management;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Annotation for MBean constructors.
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.CONSTRUCTOR)
-@Inherited
-public @interface MBeanConstructor
-{
- String value();
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java
deleted file mode 100644
index 448fed3280..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java
+++ /dev/null
@@ -1,38 +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.
- *
- *
- */
-
-package org.apache.qpid.server.management;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Annotation for MBean class.
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-@Inherited
-public @interface MBeanDescription {
- String value();
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java
index 0c2ec2aebd..9c2a455897 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java
@@ -32,6 +32,12 @@ import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.NotCompliantMBeanException;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanAttribute;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanOperationParameter;
+
/**
* This class is a utility class to introspect the MBean class and the management
* interface class for various purposes.
diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java
index a0ecc2bd85..0ee5763d91 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java
@@ -20,16 +20,24 @@
*/
package org.apache.qpid.server.management;
-import org.apache.qpid.server.security.access.management.UserManagement;
+import org.apache.qpid.management.common.mbeans.ConfigurationManagement;
+import org.apache.qpid.management.common.mbeans.LoggingManagement;
+import org.apache.qpid.management.common.mbeans.UserManagement;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.ManagementActor;
+import org.apache.qpid.server.logging.messages.ManagementConsoleMessages;
import org.apache.log4j.Logger;
import javax.management.remote.MBeanServerForwarder;
import javax.management.remote.JMXPrincipal;
+import javax.management.remote.JMXConnectionNotification;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.JMException;
+import javax.management.NotificationListener;
+import javax.management.Notification;
import javax.security.auth.Subject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
@@ -37,6 +45,7 @@ import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.Principal;
import java.security.AccessControlContext;
+import java.util.HashSet;
import java.util.Set;
import java.util.Properties;
@@ -45,7 +54,7 @@ import java.util.Properties;
* the logic for allowing the users to invoke MBean operations and implements the restrictions for readOnly, readWrite
* and admin users.
*/
-public class MBeanInvocationHandlerImpl implements InvocationHandler
+public class MBeanInvocationHandlerImpl implements InvocationHandler, NotificationListener
{
private static final Logger _logger = Logger.getLogger(MBeanInvocationHandlerImpl.class);
@@ -53,14 +62,25 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler
public final static String READWRITE = "readwrite";
public final static String READONLY = "readonly";
private final static String DELEGATE = "JMImplementation:type=MBeanServerDelegate";
- private MBeanServer mbs;
+ private MBeanServer _mbs;
private static Properties _userRoles = new Properties();
+ private static ManagementActor _logActor;
+ private static HashSet<String> _adminOnlyMethods = new HashSet<String>();
+ {
+ _adminOnlyMethods.add(UserManagement.TYPE);
+ _adminOnlyMethods.add(LoggingManagement.TYPE);
+ _adminOnlyMethods.add(ConfigurationManagement.TYPE);
+ }
+
public static MBeanServerForwarder newProxyInstance()
{
final InvocationHandler handler = new MBeanInvocationHandlerImpl();
final Class[] interfaces = new Class[]{MBeanServerForwarder.class};
+
+ _logActor = new ManagementActor(CurrentActor.get().getRootMessageLogger());
+
Object proxy = Proxy.newProxyInstance(MBeanServerForwarder.class.getClassLoader(), interfaces, handler);
return MBeanServerForwarder.class.cast(proxy);
}
@@ -71,7 +91,7 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler
if (methodName.equals("getMBeanServer"))
{
- return mbs;
+ return _mbs;
}
if (methodName.equals("setMBeanServer"))
@@ -80,11 +100,11 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler
{
throw new IllegalArgumentException("Null MBeanServer");
}
- if (mbs != null)
+ if (_mbs != null)
{
throw new IllegalArgumentException("MBeanServer object already initialized");
}
- mbs = (MBeanServer) args[0];
+ _mbs = (MBeanServer) args[0];
return null;
}
@@ -95,12 +115,12 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler
// Allow operations performed locally on behalf of the connector server itself
if (subject == null)
{
- return method.invoke(mbs, args);
+ return method.invoke(_mbs, args);
}
if (args == null || DELEGATE.equals(args[0]))
{
- return method.invoke(mbs, args);
+ return method.invoke(_mbs, args);
}
// Restrict access to "createMBean" and "unregisterMBean" to any user
@@ -124,7 +144,7 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler
{
if (isAdmin(identity))
{
- return method.invoke(mbs, args);
+ return method.invoke(_mbs, args);
}
else
{
@@ -135,14 +155,14 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler
// Following users can perform any operation other than "createMBean" and "unregisterMBean"
if (isAllowedToModify(identity))
{
- return method.invoke(mbs, args);
+ return method.invoke(_mbs, args);
}
// These users can only call "getAttribute" on the MBeanServerDelegate MBean
// Here we can add other fine grained permissions like specific method for a particular mbean
if (isReadOnlyUser(identity) && isReadOnlyMethod(method, args))
{
- return method.invoke(mbs, args);
+ return method.invoke(_mbs, args);
}
throw new SecurityException("Access denied");
@@ -153,9 +173,9 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler
if (args[0] instanceof ObjectName)
{
ObjectName object = (ObjectName) args[0];
- return UserManagement.TYPE.equals(object.getKeyProperty("type"));
+
+ return _adminOnlyMethods.contains(object.getKeyProperty("type"));
}
-
return false;
}
@@ -196,7 +216,10 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler
private boolean isReadOnlyMethod(Method method, Object[] args)
{
String methodName = method.getName();
- if (methodName.startsWith("query") || methodName.startsWith("get"))
+
+ //handle standard get/set/query and select 'is' methods from MBeanServer
+ if (methodName.startsWith("query") || methodName.startsWith("get")
+ ||methodName.startsWith("isInstanceOf") || methodName.startsWith("isRegistered"))
{
return true;
}
@@ -205,8 +228,11 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler
return false;
}
+ //handle invocation of other methods on mbeans
if ((args[0] instanceof ObjectName) && (methodName.equals("invoke")))
{
+
+ //get invoked method name
String mbeanMethod = (args.length > 1) ? (String) args[1] : null;
if (mbeanMethod == null)
{
@@ -215,7 +241,8 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler
try
{
- MBeanInfo mbeanInfo = mbs.getMBeanInfo((ObjectName) args[0]);
+ //check if the given method is tagged with an INFO impact attribute
+ MBeanInfo mbeanInfo = _mbs.getMBeanInfo((ObjectName) args[0]);
if (mbeanInfo != null)
{
MBeanOperationInfo[] opInfos = mbeanInfo.getOperations();
@@ -236,4 +263,23 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler
return false;
}
+
+ public void handleNotification(Notification notification, Object handback)
+ {
+ // only RMI Connections are serviced here, Local API atta
+ // rmi://169.24.29.116 guest 3
+ String[] connectionData = ((JMXConnectionNotification) notification).getConnectionId().split(" ");
+ String user = connectionData[1];
+
+ if (notification.getType().equals(JMXConnectionNotification.OPENED))
+ {
+ _logActor.message(ManagementConsoleMessages.MNG_OPEN(user));
+ }
+ else if (notification.getType().equals(JMXConnectionNotification.CLOSED) ||
+ notification.getType().equals(JMXConnectionNotification.FAILED))
+ {
+ _logActor.message(ManagementConsoleMessages.MNG_CLOSE());
+ }
+ }
}
+
diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java
deleted file mode 100644
index a2dca3e51d..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java
+++ /dev/null
@@ -1,43 +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.
- *
- *
- */
-
-package org.apache.qpid.server.management;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-import javax.management.MBeanOperationInfo;
-
-/**
- * Annotation for MBean operations.
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.METHOD)
-@Inherited
-public @interface MBeanOperation
-{
- String name();
- String description();
- int impact() default MBeanOperationInfo.INFO;
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java
deleted file mode 100644
index aba5ec70d8..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java
+++ /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.
- *
- *
- */
-
-package org.apache.qpid.server.management;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Annotation for MBean operation parameters.
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.PARAMETER)
-public @interface MBeanOperationParameter {
- String name();
- String description();
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java b/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java
deleted file mode 100644
index 45e2e91ed7..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java
+++ /dev/null
@@ -1,98 +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.
- *
- */
-
-package org.apache.qpid.server.management;
-
-import java.io.IOException;
-
-import javax.management.JMException;
-import javax.management.MBeanOperationInfo;
-
-import org.apache.qpid.server.exchange.ManagedExchange;
-import org.apache.qpid.server.queue.ManagedQueue;
-
-/**
- * The ManagedBroker is the management interface to expose management
- * features of the Broker.
- *
- * @author Bhupendra Bhardwaj
- * @version 0.1
- */
-public interface ManagedBroker
-{
- static final String TYPE = "VirtualHostManager";
-
- /**
- * Creates a new Exchange.
- * @param name
- * @param type
- * @param durable
- * @param passive
- * @throws IOException
- * @throws JMException
- */
- @MBeanOperation(name="createNewExchange", description="Creates a new Exchange", impact= MBeanOperationInfo.ACTION)
- void createNewExchange(@MBeanOperationParameter(name="name", description="Name of the new exchange")String name,
- @MBeanOperationParameter(name="ExchangeType", description="Type of the exchange")String type,
- @MBeanOperationParameter(name="durable", description="true if the Exchang should be durable")boolean durable)
- throws IOException, JMException;
-
- /**
- * unregisters all the channels, queuebindings etc and unregisters
- * this exchange from managed objects.
- * @param exchange
- * @throws IOException
- * @throws JMException
- */
- @MBeanOperation(name="unregisterExchange",
- description="Unregisters all the related channels and queuebindings of this exchange",
- impact= MBeanOperationInfo.ACTION)
- void unregisterExchange(@MBeanOperationParameter(name= ManagedExchange.TYPE, description="Exchange Name")String exchange)
- throws IOException, JMException;
-
- /**
- * Create a new Queue on the Broker server
- * @param queueName
- * @param durable
- * @param owner
- * @param autoDelete
- * @throws IOException
- * @throws JMException
- */
- @MBeanOperation(name="createNewQueue", description="Create a new Queue on the Broker server", impact= MBeanOperationInfo.ACTION)
- void createNewQueue(@MBeanOperationParameter(name="queue name", description="Name of the new queue")String queueName,
- @MBeanOperationParameter(name="owner", description="Owner name")String owner,
- @MBeanOperationParameter(name="durable", description="true if the queue should be durable")boolean durable)
- throws IOException, JMException;
-
- /**
- * Unregisters the Queue bindings, removes the subscriptions and unregisters
- * from the managed objects.
- * @param queueName
- * @throws IOException
- * @throws JMException
- */
- @MBeanOperation(name="deleteQueue",
- description="Unregisters the Queue bindings, removes the subscriptions and deletes the queue",
- impact= MBeanOperationInfo.ACTION)
- void deleteQueue(@MBeanOperationParameter(name= ManagedQueue.TYPE, description="Queue Name")String queueName)
- throws IOException, JMException;
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java b/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java
index 42ea8921a4..de14785fb0 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -22,6 +22,7 @@ package org.apache.qpid.server.management;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
+import javax.management.JMException;
import org.apache.qpid.AMQException;
@@ -45,7 +46,7 @@ public interface ManagedObject
ManagedObject getParentObject();
- void register() throws AMQException;
+ void register() throws AMQException, JMException;
void unregister() throws AMQException;
diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java
index d8d87ef881..b58b17ba86 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java
@@ -21,6 +21,9 @@
package org.apache.qpid.server.management;
import javax.management.JMException;
+
+import org.apache.commons.configuration.ConfigurationException;
+
import java.rmi.RemoteException;
import java.io.IOException;
@@ -38,7 +41,7 @@ import java.io.IOException;
*/
public interface ManagedObjectRegistry
{
- void start() throws IOException;
+ void start() throws IOException, ConfigurationException;
void registerObject(ManagedObject managedObject) throws JMException;
diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/ManagementConfiguration.java b/java/broker/src/main/java/org/apache/qpid/server/management/ManagementConfiguration.java
deleted file mode 100644
index 042f626e8b..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/management/ManagementConfiguration.java
+++ /dev/null
@@ -1,30 +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.
- *
- */
-package org.apache.qpid.server.management;
-
-import org.apache.qpid.configuration.Configured;
-
-public class ManagementConfiguration
-{
- @Configured(path = "management.enabled",
- defaultValue = "true")
- public boolean enabled;
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java b/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java
new file mode 100644
index 0000000000..b8a36aba58
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java
@@ -0,0 +1,329 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.message;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.server.store.StoredMessage;
+import org.apache.qpid.server.queue.AMQQueue;
+
+
+import java.util.concurrent.atomic.AtomicInteger;
+import java.nio.ByteBuffer;
+
+/**
+ * A deliverable message.
+ */
+public class AMQMessage implements ServerMessage
+{
+ /** Used for debugging purposes. */
+ private static final Logger _log = Logger.getLogger(AMQMessage.class);
+
+ private final AtomicInteger _referenceCount = new AtomicInteger(0);
+
+ /** Flag to indicate that this message requires 'immediate' delivery. */
+
+ private static final byte IMMEDIATE = 0x01;
+
+ /**
+ * Flag to indicate whether this message has been delivered to a consumer. Used in implementing return functionality
+ * for messages published with the 'immediate' flag.
+ */
+
+ private static final byte DELIVERED_TO_CONSUMER = 0x02;
+
+ private byte _flags = 0;
+
+ private long _expiration;
+
+ private final long _size;
+
+ private Object _sessionIdentifier;
+ private static final byte IMMEDIATE_AND_DELIVERED = (byte) (IMMEDIATE | DELIVERED_TO_CONSUMER);
+
+ private final StoredMessage<MessageMetaData> _handle;
+
+
+ public AMQMessage(StoredMessage<MessageMetaData> handle)
+ {
+ _handle = handle;
+ final MessageMetaData metaData = handle.getMetaData();
+ _size = metaData.getContentSize();
+ final MessagePublishInfo messagePublishInfo = metaData.getMessagePublishInfo();
+
+ if(messagePublishInfo.isImmediate())
+ {
+ _flags |= IMMEDIATE;
+ }
+ }
+
+
+ public String debugIdentity()
+ {
+ return "(HC:" + System.identityHashCode(this) + " ID:" + getMessageId() + " Ref:" + _referenceCount.get() + ")";
+ }
+
+ public void setExpiration(final long expiration)
+ {
+
+ _expiration = expiration;
+
+ }
+
+ public boolean isReferenced()
+ {
+ return _referenceCount.get() > 0;
+ }
+
+ public MessageMetaData getMessageMetaData()
+ {
+ return _handle.getMetaData();
+ }
+
+ public ContentHeaderBody getContentHeaderBody() throws AMQException
+ {
+ return getMessageMetaData().getContentHeaderBody();
+ }
+
+
+
+ public Long getMessageId()
+ {
+ return _handle.getMessageNumber();
+ }
+
+ /**
+ * Creates a long-lived reference to this message, and increments the count of such references, as an atomic
+ * operation.
+ */
+ public AMQMessage takeReference()
+ {
+ incrementReference(); // _referenceCount.incrementAndGet();
+
+ return this;
+ }
+
+ public boolean incrementReference()
+ {
+ return incrementReference(1);
+ }
+
+ /* Threadsafe. Increment the reference count on the message. */
+ public boolean incrementReference(int count)
+ {
+
+ if(_referenceCount.addAndGet(count) <= 0)
+ {
+ _referenceCount.addAndGet(-count);
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+
+ }
+
+ /**
+ * Threadsafe. This will decrement the reference count and when it reaches zero will remove the message from the
+ * message store.
+ *
+ *
+ * @throws org.apache.qpid.server.queue.MessageCleanupException when an attempt was made to remove the message from the message store and that
+ * failed
+ */
+ public void decrementReference()
+ {
+ int count = _referenceCount.decrementAndGet();
+
+ // note that the operation of decrementing the reference count and then removing the message does not
+ // have to be atomic since the ref count starts at 1 and the exchange itself decrements that after
+ // the message has been passed to all queues. i.e. we are
+ // not relying on the all the increments having taken place before the delivery manager decrements.
+ if (count == 0)
+ {
+ // set the reference count way below 0 so that we can detect that the message has been deleted
+ // this is to guard against the message being spontaneously recreated (from the mgmt console)
+ // by copying from other queues at the same time as it is being removed.
+ _referenceCount.set(Integer.MIN_VALUE/2);
+
+ // must check if the handle is null since there may be cases where we decide to throw away a message
+ // and the handle has not yet been constructed
+ if (_handle != null)
+ {
+ _handle.remove();
+
+ }
+ }
+ else
+ {
+ if (count < 0)
+ {
+ throw new RuntimeException("Reference count for message id " + debugIdentity()
+ + " has gone below 0.");
+ }
+ }
+ }
+
+
+ /**
+ * Called selectors to determin if the message has already been sent
+ *
+ * @return _deliveredToConsumer
+ */
+ public boolean getDeliveredToConsumer()
+ {
+ return (_flags & DELIVERED_TO_CONSUMER) != 0;
+ }
+
+ public String getRoutingKey()
+ {
+ // TODO
+ return null;
+ }
+
+ public AMQMessageHeader getMessageHeader()
+ {
+ return getMessageMetaData().getMessageHeader();
+ }
+
+ public boolean isPersistent()
+ {
+ return getMessageMetaData().isPersistent();
+ }
+
+ /**
+ * Called to enforce the 'immediate' flag.
+ *
+ * @returns true if the message is marked for immediate delivery but has not been marked as delivered
+ * to a consumer
+ */
+ public boolean immediateAndNotDelivered()
+ {
+
+ return (_flags & IMMEDIATE_AND_DELIVERED) == IMMEDIATE;
+
+ }
+
+ public MessagePublishInfo getMessagePublishInfo() throws AMQException
+ {
+ return getMessageMetaData().getMessagePublishInfo();
+ }
+
+ public long getArrivalTime()
+ {
+ return getMessageMetaData().getArrivalTime();
+ }
+
+ /**
+ * Checks to see if the message has expired. If it has the message is dequeued.
+ *
+ * @param queue The queue to check the expiration against. (Currently not used)
+ *
+ * @return true if the message has expire
+ *
+ * @throws AMQException
+ */
+ public boolean expired(AMQQueue queue) throws AMQException
+ {
+
+ if (_expiration != 0L)
+ {
+ long now = System.currentTimeMillis();
+
+ return (now > _expiration);
+ }
+
+ return false;
+ }
+
+ /**
+ * Called when this message is delivered to a consumer. (used to implement the 'immediate' flag functionality).
+ * And for selector efficiency.
+ */
+ public void setDeliveredToConsumer()
+ {
+ _flags |= DELIVERED_TO_CONSUMER;
+ }
+
+ public long getSize()
+ {
+ return _size;
+
+ }
+
+ public boolean isImmediate()
+ {
+ return (_flags & IMMEDIATE) == IMMEDIATE;
+ }
+
+ public long getExpiration()
+ {
+ return _expiration;
+ }
+
+ public MessageReference newReference()
+ {
+ return new AMQMessageReference(this);
+ }
+
+ public Long getMessageNumber()
+ {
+ return getMessageId();
+ }
+
+
+ public Object getPublisherIdentifier()
+ {
+ //todo store sessionIdentifier/client id with message in store
+ //Currently the _sessionIdentifier will be null if the message has been
+ // restored from a message Store
+
+ return _sessionIdentifier;
+
+ }
+
+ public void setClientIdentifier(final Object sessionIdentifier)
+ {
+ _sessionIdentifier = sessionIdentifier;
+ }
+
+
+ public String toString()
+ {
+ // return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " +
+ // _taken + " by :" + _takenBySubcription;
+
+ return "Message[" + debugIdentity() + "]: " + getMessageId() + "; ref count: " + _referenceCount;
+ }
+
+ public int getContent(ByteBuffer buf, int offset)
+ {
+ return _handle.getContent(offset, buf);
+ }
+
+ public StoredMessage<MessageMetaData> getStoredMessage()
+ {
+ return _handle;
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageHeader.java b/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageHeader.java
new file mode 100644
index 0000000000..6c9311c3de
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageHeader.java
@@ -0,0 +1,51 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.message;
+
+import java.util.Set;
+
+public interface AMQMessageHeader
+{
+ String getCorrelationId();
+
+ long getExpiration();
+
+ String getMessageId();
+
+ String getMimeType();
+
+ String getEncoding();
+
+ byte getPriority();
+
+ long getTimestamp();
+
+ String getType();
+
+ String getReplyTo();
+
+ Object getHeader(String name);
+
+ boolean containsHeaders(Set<String> names);
+
+ boolean containsHeader(String name);
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageReference.java b/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageReference.java
new file mode 100644
index 0000000000..940caaefe4
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageReference.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.message;
+
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.queue.MessageCleanupException;
+
+public class AMQMessageReference extends MessageReference<AMQMessage>
+{
+
+
+ public AMQMessageReference(AMQMessage message)
+ {
+ super(message);
+ }
+
+ protected void onReference(AMQMessage message)
+ {
+ message.incrementReference();
+ }
+
+ protected void onRelease(AMQMessage message)
+ {
+ message.decrementReference();
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java b/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java
new file mode 100644
index 0000000000..4a1f8dd191
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java
@@ -0,0 +1,114 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.message;
+
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.FieldTable;
+
+import java.util.Set;
+
+public class ContentHeaderBodyAdapter implements AMQMessageHeader
+{
+ private final ContentHeaderBody _contentHeaderBody;
+
+ public ContentHeaderBodyAdapter(ContentHeaderBody contentHeaderBody)
+ {
+ _contentHeaderBody = contentHeaderBody;
+ }
+
+ private BasicContentHeaderProperties getProperties()
+ {
+ return (BasicContentHeaderProperties) _contentHeaderBody.properties;
+ }
+
+ public String getCorrelationId()
+ {
+ return getProperties().getCorrelationIdAsString();
+ }
+
+ public long getExpiration()
+ {
+ return getProperties().getExpiration();
+ }
+
+ public String getMessageId()
+ {
+ return getProperties().getMessageIdAsString();
+ }
+
+ public String getMimeType()
+ {
+ return getProperties().getContentTypeAsString();
+ }
+
+ public String getEncoding()
+ {
+ return getProperties().getEncodingAsString();
+ }
+
+ public byte getPriority()
+ {
+ return getProperties().getPriority();
+ }
+
+ public long getTimestamp()
+ {
+ return getProperties().getTimestamp();
+ }
+
+ public String getType()
+ {
+ return getProperties().getTypeAsString();
+ }
+
+ public String getReplyTo()
+ {
+ return getProperties().getReplyToAsString();
+ }
+
+ public Object getHeader(String name)
+ {
+ FieldTable ft = getProperties().getHeaders();
+ return ft.get(name);
+ }
+
+ public boolean containsHeaders(Set<String> names)
+ {
+ FieldTable ft = getProperties().getHeaders();
+ for(String name : names)
+ {
+ if(!ft.containsKey(name))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean containsHeader(String name)
+ {
+ FieldTable ft = getProperties().getHeaders();
+ return ft.containsKey(name);
+ }
+
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/message/EnqueableMessage.java b/java/broker/src/main/java/org/apache/qpid/server/message/EnqueableMessage.java
new file mode 100755
index 0000000000..c32f80fc5b
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/message/EnqueableMessage.java
@@ -0,0 +1,27 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+package org.apache.qpid.server.message;
+
+public interface EnqueableMessage
+{
+ Long getMessageNumber();
+ boolean isPersistent();
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/message/InboundMessage.java b/java/broker/src/main/java/org/apache/qpid/server/message/InboundMessage.java
new file mode 100644
index 0000000000..1b3fdb1870
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/message/InboundMessage.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.message;
+
+
+import org.apache.qpid.server.queue.Filterable;
+
+public interface InboundMessage extends Filterable
+{
+ String getRoutingKey();
+
+ AMQMessageHeader getMessageHeader();
+
+ boolean isPersistent();
+
+ boolean isRedelivered();
+
+ long getSize();
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/message/MessageContentSource.java b/java/broker/src/main/java/org/apache/qpid/server/message/MessageContentSource.java
new file mode 100755
index 0000000000..08a09c4a85
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/message/MessageContentSource.java
@@ -0,0 +1,31 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.message;
+
+import java.nio.ByteBuffer;
+
+public interface MessageContentSource
+{
+ public int getContent(ByteBuffer buf, int offset);
+
+ long getSize();
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java b/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java
new file mode 100644
index 0000000000..b34a8fc470
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java
@@ -0,0 +1,309 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.message;
+
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.EncodingUtils;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.server.store.StorableMessageMetaData;
+import org.apache.qpid.server.store.MessageMetaDataType;
+import org.apache.qpid.AMQException;
+
+import java.nio.ByteBuffer;
+import java.util.Set;
+
+/**
+ * Encapsulates a publish body and a content header. In the context of the message store these are treated as a
+ * single unit.
+ */
+public class MessageMetaData implements StorableMessageMetaData
+{
+ private MessagePublishInfo _messagePublishInfo;
+
+ private ContentHeaderBody _contentHeaderBody;
+
+ private int _contentChunkCount;
+
+ private long _arrivalTime;
+ private static final byte MANDATORY_FLAG = 1;
+ private static final byte IMMEDIATE_FLAG = 2;
+ public static final MessageMetaDataType.Factory<MessageMetaData> FACTORY = new MetaDataFactory();
+
+ public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount)
+ {
+ this(publishBody,contentHeaderBody, contentChunkCount, System.currentTimeMillis());
+ }
+
+ public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount, long arrivalTime)
+ {
+ _contentHeaderBody = contentHeaderBody;
+ _messagePublishInfo = publishBody;
+ _contentChunkCount = contentChunkCount;
+ _arrivalTime = arrivalTime;
+ }
+
+ public int getContentChunkCount()
+ {
+ return _contentChunkCount;
+ }
+
+ public void setContentChunkCount(int contentChunkCount)
+ {
+ _contentChunkCount = contentChunkCount;
+ }
+
+ public ContentHeaderBody getContentHeaderBody()
+ {
+ return _contentHeaderBody;
+ }
+
+ public void setContentHeaderBody(ContentHeaderBody contentHeaderBody)
+ {
+ _contentHeaderBody = contentHeaderBody;
+ }
+
+ public MessagePublishInfo getMessagePublishInfo()
+ {
+ return _messagePublishInfo;
+ }
+
+ public void setMessagePublishInfo(MessagePublishInfo messagePublishInfo)
+ {
+ _messagePublishInfo = messagePublishInfo;
+ }
+
+ public long getArrivalTime()
+ {
+ return _arrivalTime;
+ }
+
+ public void setArrivalTime(long arrivalTime)
+ {
+ _arrivalTime = arrivalTime;
+ }
+
+ public MessageMetaDataType getType()
+ {
+ return MessageMetaDataType.META_DATA_0_8;
+ }
+
+ public int getStorableSize()
+ {
+ BasicContentHeaderProperties properties = (BasicContentHeaderProperties) (_contentHeaderBody.properties);
+ int size = _contentHeaderBody.getSize();
+ size += 4;
+ size += EncodingUtils.encodedShortStringLength(_messagePublishInfo.getExchange());
+ size += EncodingUtils.encodedShortStringLength(_messagePublishInfo.getRoutingKey());
+ size += 1; // flags for immediate/mandatory
+ size += EncodingUtils.encodedLongLength();
+
+ return size;
+ }
+
+ public int writeToBuffer(int offset, ByteBuffer dest)
+ {
+ ByteBuffer src = ByteBuffer.allocate((int)getStorableSize());
+
+ org.apache.mina.common.ByteBuffer minaSrc = org.apache.mina.common.ByteBuffer.wrap(src);
+ EncodingUtils.writeInteger(minaSrc, _contentHeaderBody.getSize());
+ _contentHeaderBody.writePayload(minaSrc);
+ EncodingUtils.writeShortStringBytes(minaSrc, _messagePublishInfo.getExchange());
+ EncodingUtils.writeShortStringBytes(minaSrc, _messagePublishInfo.getRoutingKey());
+ byte flags = 0;
+ if(_messagePublishInfo.isMandatory())
+ {
+ flags |= MANDATORY_FLAG;
+ }
+ if(_messagePublishInfo.isImmediate())
+ {
+ flags |= IMMEDIATE_FLAG;
+ }
+ EncodingUtils.writeByte(minaSrc, flags);
+ EncodingUtils.writeLong(minaSrc,_arrivalTime);
+ src.position(minaSrc.position());
+ src.flip();
+ src.position(offset);
+ src = src.slice();
+ if(dest.remaining() < src.limit())
+ {
+ src.limit(dest.remaining());
+ }
+ dest.put(src);
+
+
+ return src.limit();
+ }
+
+ public int getContentSize()
+ {
+ return (int) _contentHeaderBody.bodySize;
+ }
+
+ public boolean isPersistent()
+ {
+ BasicContentHeaderProperties properties = (BasicContentHeaderProperties) (_contentHeaderBody.properties);
+ return properties.getDeliveryMode() == BasicContentHeaderProperties.PERSISTENT;
+ }
+
+ private static class MetaDataFactory implements MessageMetaDataType.Factory
+ {
+
+
+ public MessageMetaData createMetaData(ByteBuffer buf)
+ {
+ try
+ {
+ org.apache.mina.common.ByteBuffer minaSrc = org.apache.mina.common.ByteBuffer.wrap(buf);
+ int size = EncodingUtils.readInteger(minaSrc);
+ ContentHeaderBody chb = ContentHeaderBody.createFromBuffer(minaSrc, size);
+ final AMQShortString exchange = EncodingUtils.readAMQShortString(minaSrc);
+ final AMQShortString routingKey = EncodingUtils.readAMQShortString(minaSrc);
+
+ final byte flags = EncodingUtils.readByte(minaSrc);
+ long arrivalTime = EncodingUtils.readLong(minaSrc);
+
+ MessagePublishInfo publishBody =
+ new MessagePublishInfo()
+ {
+
+ public AMQShortString getExchange()
+ {
+ return exchange;
+ }
+
+ public void setExchange(AMQShortString exchange)
+ {
+ }
+
+ public boolean isImmediate()
+ {
+ return (flags & IMMEDIATE_FLAG) != 0;
+ }
+
+ public boolean isMandatory()
+ {
+ return (flags & MANDATORY_FLAG) != 0;
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return routingKey;
+ }
+ };
+ return new MessageMetaData(publishBody, chb, 0, arrivalTime);
+ }
+ catch (AMQException e)
+ {
+ throw new RuntimeException(e);
+ }
+
+ }
+ };
+
+ public AMQMessageHeader getMessageHeader()
+ {
+ return new MessageHeaderAdapter();
+ }
+
+ private final class MessageHeaderAdapter implements AMQMessageHeader
+ {
+ private BasicContentHeaderProperties getProperties()
+ {
+ return (BasicContentHeaderProperties) getContentHeaderBody().properties;
+ }
+
+ public String getCorrelationId()
+ {
+ return getProperties().getCorrelationIdAsString();
+ }
+
+ public long getExpiration()
+ {
+ return getProperties().getExpiration();
+ }
+
+ public String getMessageId()
+ {
+ return getProperties().getMessageIdAsString();
+ }
+
+ public String getMimeType()
+ {
+ return getProperties().getContentTypeAsString();
+ }
+
+ public String getEncoding()
+ {
+ return getProperties().getEncodingAsString();
+ }
+
+ public byte getPriority()
+ {
+ return getProperties().getPriority();
+ }
+
+ public long getTimestamp()
+ {
+ return getProperties().getTimestamp();
+ }
+
+ public String getType()
+ {
+ return getProperties().getTypeAsString();
+ }
+
+ public String getReplyTo()
+ {
+ return getProperties().getReplyToAsString();
+ }
+
+ public Object getHeader(String name)
+ {
+ FieldTable ft = getProperties().getHeaders();
+ return ft.get(name);
+ }
+
+ public boolean containsHeaders(Set<String> names)
+ {
+ FieldTable ft = getProperties().getHeaders();
+ for(String name : names)
+ {
+ if(!ft.containsKey(name))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean containsHeader(String name)
+ {
+ FieldTable ft = getProperties().getHeaders();
+ return ft.containsKey(name);
+ }
+
+
+
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java b/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java
new file mode 100755
index 0000000000..5a5e2fe5b4
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java
@@ -0,0 +1,242 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+package org.apache.qpid.server.message;
+
+import org.apache.qpid.server.store.StorableMessageMetaData;
+import org.apache.qpid.server.store.MessageMetaDataType;
+import org.apache.qpid.transport.MessageTransfer;
+import org.apache.qpid.transport.DeliveryProperties;
+import org.apache.qpid.transport.MessageProperties;
+import org.apache.qpid.transport.Header;
+import org.apache.qpid.transport.MessageDeliveryMode;
+import org.apache.qpid.transport.Struct;
+import org.apache.qpid.transport.codec.BBEncoder;
+import org.apache.qpid.transport.codec.BBDecoder;
+
+import java.nio.ByteBuffer;
+import java.lang.ref.WeakReference;
+
+public class MessageMetaData_0_10 implements StorableMessageMetaData
+{
+ private Header _header;
+ private DeliveryProperties _deliveryProps;
+ private MessageProperties _messageProps;
+ private MessageTransferHeader _messageHeader;
+ private long _arrivalTime;
+ private int _bodySize;
+ private volatile WeakReference<ByteBuffer> _body;
+
+ private static final int ENCODER_SIZE = 1 << 16;
+
+ public static final MessageMetaDataType.Factory<MessageMetaData_0_10> FACTORY = new MetaDataFactory();
+
+ private volatile ByteBuffer _encoded;
+
+
+ public MessageMetaData_0_10(MessageTransfer xfr)
+ {
+ this(xfr.getHeader(), xfr.getBodySize(), xfr.getBody(), System.currentTimeMillis());
+ }
+
+ private MessageMetaData_0_10(Header header, int bodySize, long arrivalTime)
+ {
+ this(header, bodySize, null, arrivalTime);
+ }
+
+ private MessageMetaData_0_10(Header header, int bodySize, ByteBuffer xfrBody, long arrivalTime)
+ {
+ _header = header;
+ if(_header != null)
+ {
+ _deliveryProps = _header.get(DeliveryProperties.class);
+ _messageProps = _header.get(MessageProperties.class);
+ }
+ else
+ {
+ _deliveryProps = null;
+ _messageProps = null;
+ }
+ _messageHeader = new MessageTransferHeader(_deliveryProps, _messageProps);
+ _arrivalTime = arrivalTime;
+ _bodySize = bodySize;
+
+
+
+ if(xfrBody == null)
+ {
+ _body = null;
+ }
+ else
+ {
+ ByteBuffer body = ByteBuffer.allocate(_bodySize);
+ body.put(xfrBody);
+ body.flip();
+ _body = new WeakReference(body);
+ }
+
+
+ }
+
+
+
+ public MessageMetaDataType getType()
+ {
+ return MessageMetaDataType.META_DATA_0_10;
+ }
+
+ public int getStorableSize()
+ {
+ ByteBuffer buf = _encoded;
+
+ if(buf == null)
+ {
+ buf = encodeAsBuffer();
+ _encoded = buf;
+ }
+
+ //TODO -- need to add stuff
+ return buf.limit();
+ }
+
+ private ByteBuffer encodeAsBuffer()
+ {
+ BBEncoder encoder = new BBEncoder(ENCODER_SIZE);
+
+ encoder.writeInt64(_arrivalTime);
+ encoder.writeInt32(_bodySize);
+ Struct[] headers = _header == null ? new Struct[0] : _header.getStructs();
+ encoder.writeInt32(headers.length);
+
+
+ for(Struct header : headers)
+ {
+ encoder.writeStruct32(header);
+
+ }
+
+ ByteBuffer buf = encoder.buffer();
+ return buf;
+ }
+
+ public int writeToBuffer(int offsetInMetaData, ByteBuffer dest)
+ {
+ ByteBuffer buf = _encoded;
+
+ if(buf == null)
+ {
+ buf = encodeAsBuffer();
+ _encoded = buf;
+ }
+
+ buf = buf.duplicate();
+
+ buf.position(offsetInMetaData);
+
+ if(dest.remaining() < buf.limit())
+ {
+ buf.limit(dest.remaining());
+ }
+ dest.put(buf);
+ return buf.limit();
+ }
+
+ public int getContentSize()
+ {
+ return _bodySize;
+ }
+
+ public boolean isPersistent()
+ {
+ return _deliveryProps == null ? false : _deliveryProps.getDeliveryMode() == MessageDeliveryMode.PERSISTENT;
+ }
+
+ public String getRoutingKey()
+ {
+ return _deliveryProps == null ? null : _deliveryProps.getRoutingKey();
+ }
+
+ public AMQMessageHeader getMessageHeader()
+ {
+ return _messageHeader;
+ }
+
+ public long getSize()
+ {
+
+ return _bodySize;
+ }
+
+ public boolean isImmediate()
+ {
+ return _deliveryProps != null && _deliveryProps.getImmediate();
+ }
+
+ public long getExpiration()
+ {
+ return _deliveryProps == null ? 0L : _deliveryProps.getExpiration();
+ }
+
+ public long getArrivalTime()
+ {
+ return _arrivalTime;
+ }
+
+ public Header getHeader()
+ {
+ return _header;
+ }
+
+ public ByteBuffer getBody()
+ {
+ ByteBuffer body = _body == null ? null : _body.get();
+ return body;
+ }
+
+ public void setBody(ByteBuffer body)
+ {
+ _body = new WeakReference(body);
+ }
+
+ private static class MetaDataFactory implements MessageMetaDataType.Factory<MessageMetaData_0_10>
+ {
+ public MessageMetaData_0_10 createMetaData(ByteBuffer buf)
+ {
+ BBDecoder decoder = new BBDecoder();
+ decoder.init(buf);
+
+ long arrivalTime = decoder.readInt64();
+ int bodySize = decoder.readInt32();
+ int headerCount = decoder.readInt32();
+
+ Struct[] headers = new Struct[headerCount];
+
+ for(int i = 0 ; i < headerCount; i++)
+ {
+ headers[i] = decoder.readStruct32();
+ }
+
+ Header header = new Header(headers);
+
+ return new MessageMetaData_0_10(header, bodySize, arrivalTime);
+
+ }
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/message/MessageReference.java b/java/broker/src/main/java/org/apache/qpid/server/message/MessageReference.java
new file mode 100644
index 0000000000..055403ff08
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/message/MessageReference.java
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.message;
+
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+public abstract class MessageReference<M extends ServerMessage>
+{
+
+ private static final AtomicReferenceFieldUpdater<MessageReference, ServerMessage> _messageUpdater =
+ AtomicReferenceFieldUpdater.newUpdater(MessageReference.class, ServerMessage.class,"_message");
+
+ private volatile M _message;
+
+ public MessageReference(M message)
+ {
+ _message = message;
+ onReference(message);
+ }
+
+ abstract protected void onReference(M message);
+
+ abstract protected void onRelease(M message);
+
+ public M getMessage()
+ {
+ return _message;
+ }
+
+ public void release()
+ {
+ M message = (M) _messageUpdater.getAndSet(this,null);
+ if(message != null)
+ {
+ onRelease(message);
+ }
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java b/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java
new file mode 100644
index 0000000000..7fac7ab164
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java
@@ -0,0 +1,126 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.message;
+
+import org.apache.qpid.transport.DeliveryProperties;
+import org.apache.qpid.transport.MessageProperties;
+import org.apache.qpid.transport.MessageDeliveryPriority;
+
+import java.util.Set;
+import java.util.Map;
+
+class MessageTransferHeader implements AMQMessageHeader
+{
+
+
+ public static final String JMS_TYPE = "x-jms-type";
+
+ private final DeliveryProperties _deliveryProps;
+ private final MessageProperties _messageProps;
+
+ public MessageTransferHeader(DeliveryProperties deliveryProps, MessageProperties messageProps)
+ {
+ _deliveryProps = deliveryProps;
+ _messageProps = messageProps;
+ }
+
+ public String getCorrelationId()
+ {
+ if (_messageProps != null && _messageProps.getCorrelationId() != null)
+ {
+ return new String(_messageProps.getCorrelationId());
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public long getExpiration()
+ {
+ return _deliveryProps == null ? null : _deliveryProps.getExpiration();
+ }
+
+ public String getMessageId()
+ {
+ return _messageProps == null ? null : String.valueOf(_messageProps.getMessageId());
+ }
+
+ public String getMimeType()
+ {
+ return _messageProps == null ? null : _messageProps.getContentType();
+ }
+
+ public String getEncoding()
+ {
+ return _messageProps == null ? null : _messageProps.getContentEncoding();
+ }
+
+ public byte getPriority()
+ {
+ MessageDeliveryPriority priority = _deliveryProps == null
+ ? MessageDeliveryPriority.MEDIUM
+ : _deliveryProps.getPriority();
+ return (byte) priority.getValue();
+ }
+
+ public long getTimestamp()
+ {
+ return _deliveryProps == null ? 0L : _deliveryProps.getTimestamp();
+ }
+
+ public String getType()
+ {
+ Object type = getHeader(JMS_TYPE);
+ return type instanceof String ? (String) type : null;
+ }
+
+ public String getReplyTo()
+ {
+ if (_messageProps != null && _messageProps.getReplyTo() != null)
+ {
+ return _messageProps.getReplyTo().toString();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public Object getHeader(String name)
+ {
+ Map<String, Object> appHeaders = _messageProps == null ? null : _messageProps.getApplicationHeaders();
+ return appHeaders == null ? null : appHeaders.get(name);
+ }
+
+ public boolean containsHeaders(Set<String> names)
+ {
+ Map<String, Object> appHeaders = _messageProps == null ? null : _messageProps.getApplicationHeaders();
+ return appHeaders != null && appHeaders.keySet().containsAll(names);
+
+ }
+
+ public boolean containsHeader(String name)
+ {
+ Map<String, Object> appHeaders = _messageProps == null ? null : _messageProps.getApplicationHeaders();
+ return appHeaders != null && appHeaders.containsKey(name);
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java b/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java
new file mode 100644
index 0000000000..e866ad5078
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java
@@ -0,0 +1,146 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.message;
+
+import org.apache.qpid.transport.*;
+import org.apache.qpid.server.store.StoredMessage;
+
+import java.util.concurrent.atomic.AtomicLong;
+import java.nio.ByteBuffer;
+import java.lang.ref.WeakReference;
+
+
+public class MessageTransferMessage implements InboundMessage, ServerMessage
+{
+
+
+ private StoredMessage<MessageMetaData_0_10> _storeMessage;
+
+
+ private WeakReference<Session> _sessionRef;
+
+
+ public MessageTransferMessage(StoredMessage<MessageMetaData_0_10> storeMessage, WeakReference<Session> sessionRef)
+ {
+
+ _storeMessage = storeMessage;
+ _sessionRef = sessionRef;
+
+ }
+
+ private MessageMetaData_0_10 getMetaData()
+ {
+ return _storeMessage.getMetaData();
+ }
+
+ public String getRoutingKey()
+ {
+ return getMetaData().getRoutingKey();
+
+ }
+
+ public AMQMessageHeader getMessageHeader()
+ {
+ return getMetaData().getMessageHeader();
+ }
+
+ public boolean isPersistent()
+ {
+ return getMetaData().isPersistent();
+ }
+
+
+ public boolean isRedelivered()
+ {
+ // The *Message* is never redelivered, only queue entries are... this is here so that filters
+ // can run against the message on entry to an exchange
+ return false;
+ }
+
+ public long getSize()
+ {
+
+ return getMetaData().getSize();
+ }
+
+ public boolean isImmediate()
+ {
+ return getMetaData().isImmediate();
+ }
+
+ public long getExpiration()
+ {
+ return getMetaData().getExpiration();
+ }
+
+ public MessageReference newReference()
+ {
+ return new TransferMessageReference(this);
+ }
+
+ public Long getMessageNumber()
+ {
+ return _storeMessage.getMessageNumber();
+ }
+
+ public long getArrivalTime()
+ {
+ return getMetaData().getArrivalTime();
+ }
+
+ public int getContent(ByteBuffer buf, int offset)
+ {
+ return _storeMessage.getContent(offset, buf);
+ }
+
+ public Header getHeader()
+ {
+ return getMetaData().getHeader();
+ }
+
+ public ByteBuffer getBody()
+ {
+ ByteBuffer body = getMetaData().getBody();
+ if(body == null)
+ {
+ final int size = (int) getSize();
+ int pos = 0;
+ body = ByteBuffer.allocate(size);
+
+ while(pos < size)
+ {
+ pos += getContent(body, pos);
+ }
+
+ body.flip();
+
+ getMetaData().setBody(body.duplicate());
+ }
+ return body;
+ }
+
+ public Session getSession()
+ {
+ return _sessionRef == null ? null : _sessionRef.get();
+ }
+
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java b/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java
new file mode 100644
index 0000000000..1ac538c15b
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java
@@ -0,0 +1,47 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.message;
+
+import java.nio.ByteBuffer;
+
+public interface ServerMessage extends EnqueableMessage, MessageContentSource
+{
+ String getRoutingKey();
+
+ AMQMessageHeader getMessageHeader();
+
+ boolean isPersistent();
+
+ long getSize();
+
+ boolean isImmediate();
+
+ long getExpiration();
+
+ MessageReference newReference();
+
+ Long getMessageNumber();
+
+ long getArrivalTime();
+
+ public int getContent(ByteBuffer buf, int offset);
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/message/TransferMessageReference.java b/java/broker/src/main/java/org/apache/qpid/server/message/TransferMessageReference.java
new file mode 100644
index 0000000000..ed189c49c4
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/message/TransferMessageReference.java
@@ -0,0 +1,39 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.message;
+
+public class TransferMessageReference extends MessageReference<MessageTransferMessage>
+{
+ public TransferMessageReference(MessageTransferMessage message)
+ {
+ super(message);
+ }
+
+ protected void onReference(MessageTransferMessage message)
+ {
+
+ }
+
+ protected void onRelease(MessageTransferMessage message)
+ {
+
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/output/HeaderPropertiesConverter.java b/java/broker/src/main/java/org/apache/qpid/server/output/HeaderPropertiesConverter.java
new file mode 100755
index 0000000000..aded3f3d2a
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/output/HeaderPropertiesConverter.java
@@ -0,0 +1,124 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+package org.apache.qpid.server.output;
+
+import org.apache.qpid.server.message.MessageTransferMessage;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.transport.Header;
+import org.apache.qpid.transport.DeliveryProperties;
+import org.apache.qpid.transport.MessageProperties;
+import org.apache.qpid.transport.MessageDeliveryMode;
+import org.apache.qpid.AMQPInvalidClassException;
+
+import java.util.Map;
+
+public class HeaderPropertiesConverter
+{
+
+ public static BasicContentHeaderProperties convert(MessageTransferMessage messageTransferMessage)
+ {
+ BasicContentHeaderProperties props = new BasicContentHeaderProperties();
+
+ Header header = messageTransferMessage.getHeader();
+ DeliveryProperties deliveryProps = header.get(DeliveryProperties.class);
+ MessageProperties messageProps = header.get(MessageProperties.class);
+
+ if(deliveryProps != null)
+ {
+ if(deliveryProps.hasDeliveryMode())
+ {
+ props.setDeliveryMode((byte)(deliveryProps.getDeliveryMode() == MessageDeliveryMode.PERSISTENT ? BasicContentHeaderProperties.PERSISTENT : BasicContentHeaderProperties.NON_PERSISTENT));
+ }
+ if(deliveryProps.hasExpiration())
+ {
+ props.setExpiration(deliveryProps.getExpiration());
+ }
+ if(deliveryProps.hasPriority())
+ {
+ props.setPriority((byte)deliveryProps.getPriority().getValue());
+ }
+ if(deliveryProps.hasTimestamp())
+ {
+ props.setTimestamp(deliveryProps.getTimestamp());
+ }
+ }
+ if(messageProps != null)
+ {
+ if(messageProps.hasAppId())
+ {
+ props.setAppId(new AMQShortString(messageProps.getAppId()));
+ }
+ if(messageProps.hasContentType())
+ {
+ props.setContentType(messageProps.getContentType());
+ }
+ if(messageProps.hasCorrelationId())
+ {
+ props.setCorrelationId(new AMQShortString(messageProps.getCorrelationId()));
+ }
+ if(messageProps.hasContentEncoding())
+ {
+ props.setEncoding(messageProps.getContentEncoding());
+ }
+ if(messageProps.hasMessageId())
+ {
+ props.setMessageId(messageProps.getMessageId().toString());
+ }
+
+ // TODO Reply-to
+
+ if(messageProps.hasUserId())
+ {
+ props.setUserId(new AMQShortString(messageProps.getUserId()));
+ }
+
+ if(messageProps.hasApplicationHeaders())
+ {
+ Map<String, Object> appHeaders = messageProps.getApplicationHeaders();
+ FieldTable ft = new FieldTable();
+ for(Map.Entry<String, Object> entry : appHeaders.entrySet())
+ {
+ try
+ {
+ ft.put(new AMQShortString(entry.getKey()), entry.getValue());
+ }
+ catch(AMQPInvalidClassException e)
+ {
+ // TODO
+ // log here, but ignore - just can;t convert
+ }
+ }
+ props.setHeaders(ft);
+
+ }
+ }
+
+
+
+
+
+
+
+ return props;
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java b/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java
index e01c5aabbf..5300bad613 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java
@@ -26,10 +26,13 @@
*/
package org.apache.qpid.server.output;
-import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.message.MessageContentSource;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.AMQDataBlock;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.AMQException;
public interface ProtocolOutputConverter
@@ -41,16 +44,16 @@ public interface ProtocolOutputConverter
ProtocolOutputConverter newInstance(AMQProtocolSession session);
}
- void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag)
+ void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag)
throws AMQException;
- void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException;
+ void writeGetOk(QueueEntry message, int channelId, long deliveryTag, int queueSize) throws AMQException;
byte getProtocolMinorVersion();
byte getProtocolMajorVersion();
- void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText)
+ void writeReturn(MessagePublishInfo messagePublishInfo, ContentHeaderBody header, MessageContentSource msgContent, int channelId, int replyCode, AMQShortString replyText)
throws AMQException;
void writeFrame(AMQDataBlock block);
diff --git a/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java
index 36e7e88fd6..dbefeb61f2 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverterRegistry.java
@@ -44,7 +44,7 @@ public class ProtocolOutputConverterRegistry
{
register(ProtocolVersion.v8_0, org.apache.qpid.server.output.amqp0_8.ProtocolOutputConverterImpl.getInstanceFactory());
register(ProtocolVersion.v0_9, org.apache.qpid.server.output.amqp0_9.ProtocolOutputConverterImpl.getInstanceFactory());
-
+ register(ProtocolVersion.v0_91, org.apache.qpid.server.output.amqp0_9_1.ProtocolOutputConverterImpl.getInstanceFactory());
}
private static void register(ProtocolVersion version, Factory converter)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java b/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java
index 2b55d294b5..2cebec373e 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java
@@ -27,28 +27,34 @@
package org.apache.qpid.server.output.amqp0_8;
import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.queue.AMQMessageHandle;
-import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.output.ProtocolOutputConverter;
+import org.apache.qpid.server.output.HeaderPropertiesConverter;
+import org.apache.qpid.server.message.MessageContentSource;
+import org.apache.qpid.server.message.MessageTransferMessage;
import org.apache.qpid.framing.*;
-import org.apache.qpid.framing.abstraction.ContentChunk;
+import org.apache.qpid.framing.amqp_8_0.BasicGetBodyImpl;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;
import org.apache.qpid.AMQException;
+import org.apache.qpid.transport.DeliveryProperties;
-import org.apache.mina.common.ByteBuffer;
-
-import java.util.Iterator;
+import java.nio.ByteBuffer;
public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
{
+ private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0);
+
+ private static final ProtocolVersionMethodConverter PROTOCOL_CONVERTER =
+ METHOD_REGISTRY.getProtocolVersionMethodConverter();
public static Factory getInstanceFactory()
{
return new Factory()
{
-
+
public ProtocolOutputConverter newInstance(AMQProtocolSession session)
{
return new ProtocolOutputConverterImpl(session);
@@ -69,71 +75,47 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
return _protocolSession;
}
- public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag)
+ public void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag)
throws AMQException
{
- AMQDataBlock deliver = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag);
- AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
- message.getContentHeaderBody());
-
- final AMQMessageHandle messageHandle = message.getMessageHandle();
- final StoreContext storeContext = message.getStoreContext();
-
-
- final int bodyCount = messageHandle.getBodyCount(storeContext);
+ AMQDataBlock deliver = createEncodedDeliverFrame(entry, channelId, deliveryTag, consumerTag);
+ writeMessageDelivery(entry.getMessage(), getContentHeaderBody(entry), channelId, deliver);
+ }
- if(bodyCount == 0)
+ private ContentHeaderBody getContentHeaderBody(QueueEntry entry)
+ throws AMQException
+ {
+ if(entry.getMessage() instanceof AMQMessage)
{
- SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver,
- contentHeader);
-
- writeFrame(compositeBlock);
+ return ((AMQMessage)entry.getMessage()).getContentHeaderBody();
}
else
{
-
-
- //
- // Optimise the case where we have a single content body. In that case we create a composite block
- // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
- //
- ContentChunk cb = messageHandle.getContentChunk(storeContext, 0);
-
- AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb));
- AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody};
- CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks);
- writeFrame(compositeBlock);
-
- //
- // Now start writing out the other content bodies
- //
- for(int i = 1; i < bodyCount; i++)
- {
- cb = messageHandle.getContentChunk(storeContext, i);
- writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)));
- }
-
-
+ final MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+ BasicContentHeaderProperties props = HeaderPropertiesConverter.convert(message);
+ ContentHeaderBody chb = new ContentHeaderBody(props, BasicGetBodyImpl.CLASS_ID);
+ chb.bodySize = message.getSize();
+ return chb;
}
-
-
}
- public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException
+ public void writeGetOk(QueueEntry entry, int channelId, long deliveryTag, int queueSize) throws AMQException
{
+ AMQDataBlock deliver = createEncodedGetOkFrame(entry, channelId, deliveryTag, queueSize);
+ writeMessageDelivery(entry.getMessage(), getContentHeaderBody(entry), channelId, deliver);
+ }
- final AMQMessageHandle messageHandle = message.getMessageHandle();
- final StoreContext storeContext = message.getStoreContext();
+ private void writeMessageDelivery(MessageContentSource message, ContentHeaderBody chb, int channelId, AMQDataBlock deliver)
+ throws AMQException
+ {
- AMQDataBlock deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize);
+ AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, chb);
- AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
- message.getContentHeaderBody());
- final int bodyCount = messageHandle.getBodyCount(storeContext);
- if(bodyCount == 0)
+ final int bodySize = (int) message.getSize();
+ if(bodySize == 0)
{
SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver,
contentHeader);
@@ -141,66 +123,97 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
}
else
{
+ int maxBodySize = (int) getProtocolSession().getMaxFrameSize() - AMQFrame.getFrameOverhead();
+ final int capacity = bodySize > maxBodySize ? maxBodySize : bodySize;
+ ByteBuffer buf = ByteBuffer.allocate(capacity);
- //
- // Optimise the case where we have a single content body. In that case we create a composite block
- // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
- //
- ContentChunk cb = messageHandle.getContentChunk(storeContext, 0);
+ int writtenSize = 0;
- AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb));
+ writtenSize += message.getContent(buf, writtenSize);
+ buf.flip();
+ AMQDataBlock firstContentBody = new AMQFrame(channelId, PROTOCOL_CONVERTER.convertToBody(buf));
AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody};
CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks);
writeFrame(compositeBlock);
- //
- // Now start writing out the other content bodies
- //
- for(int i = 1; i < bodyCount; i++)
+ while(writtenSize < bodySize)
{
- cb = messageHandle.getContentChunk(storeContext, i);
- writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)));
+ buf = java.nio.ByteBuffer.allocate(capacity);
+ writtenSize += message.getContent(buf, writtenSize);
+ buf.flip();
+ writeFrame(new AMQFrame(channelId, PROTOCOL_CONVERTER.convertToBody(buf)));
}
-
}
-
-
}
- private AMQDataBlock createEncodedDeliverFrame(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag)
+ private AMQDataBlock createEncodedDeliverFrame(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag)
throws AMQException
{
- final MessagePublishInfo pb = message.getMessagePublishInfo();
- final AMQMessageHandle messageHandle = message.getMessageHandle();
+ final AMQShortString exchangeName;
+ final AMQShortString routingKey;
+
+ if(entry.getMessage() instanceof AMQMessage)
+ {
+ final AMQMessage message = (AMQMessage) entry.getMessage();
+ final MessagePublishInfo pb = message.getMessagePublishInfo();
+ exchangeName = pb.getExchange();
+ routingKey = pb.getRoutingKey();
+ }
+ else
+ {
+ MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+ DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);
+ exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
+ routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
+ }
+
+ final boolean isRedelivered = entry.isRedelivered();
+
- MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0);
BasicDeliverBody deliverBody =
- methodRegistry.createBasicDeliverBody(consumerTag,
+ METHOD_REGISTRY.createBasicDeliverBody(consumerTag,
deliveryTag,
- messageHandle.isRedelivered(),
- pb.getExchange(),
- pb.getRoutingKey());
+ isRedelivered,
+ exchangeName,
+ routingKey);
+
AMQFrame deliverFrame = deliverBody.generateFrame(channelId);
return deliverFrame;
}
- private AMQDataBlock createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize)
+ private AMQDataBlock createEncodedGetOkFrame(QueueEntry entry, int channelId, long deliveryTag, int queueSize)
throws AMQException
{
- final MessagePublishInfo pb = message.getMessagePublishInfo();
- final AMQMessageHandle messageHandle = message.getMessageHandle();
+ final AMQShortString exchangeName;
+ final AMQShortString routingKey;
+
+ if(entry.getMessage() instanceof AMQMessage)
+ {
+ final AMQMessage message = (AMQMessage) entry.getMessage();
+ final MessagePublishInfo pb = message.getMessagePublishInfo();
+ exchangeName = pb.getExchange();
+ routingKey = pb.getRoutingKey();
+ }
+ else
+ {
+ MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+ DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);
+ exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
+ routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
+ }
+
+ final boolean isRedelivered = entry.isRedelivered();
- MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0);
BasicGetOkBody getOkBody =
- methodRegistry.createBasicGetOkBody(deliveryTag,
- messageHandle.isRedelivered(),
- pb.getExchange(),
- pb.getRoutingKey(),
+ METHOD_REGISTRY.createBasicGetOkBody(deliveryTag,
+ isRedelivered,
+ exchangeName,
+ routingKey,
queueSize);
AMQFrame getOkFrame = getOkBody.generateFrame(channelId);
@@ -217,54 +230,31 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
return getProtocolSession().getProtocolMajorVersion();
}
- private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException
+ private AMQDataBlock createEncodedReturnFrame(MessagePublishInfo messagePublishInfo, int channelId, int replyCode, AMQShortString replyText) throws AMQException
{
- MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0);
BasicReturnBody basicReturnBody =
- methodRegistry.createBasicReturnBody(replyCode,
+ METHOD_REGISTRY.createBasicReturnBody(replyCode,
replyText,
- message.getMessagePublishInfo().getExchange(),
- message.getMessagePublishInfo().getRoutingKey());
+ messagePublishInfo.getExchange(),
+ messagePublishInfo.getRoutingKey());
AMQFrame returnFrame = basicReturnBody.generateFrame(channelId);
return returnFrame;
}
- public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText)
+ public void writeReturn(MessagePublishInfo messagePublishInfo,
+ ContentHeaderBody header,
+ MessageContentSource content,
+ int channelId,
+ int replyCode,
+ AMQShortString replyText)
throws AMQException
{
- AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText);
-
- AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
- message.getContentHeaderBody());
- Iterator<AMQDataBlock> bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId);
- //
- // Optimise the case where we have a single content body. In that case we create a composite block
- // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
- //
- if (bodyFrameIterator.hasNext())
- {
- AMQDataBlock firstContentBody = bodyFrameIterator.next();
- AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody};
- CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks);
- writeFrame(compositeBlock);
- }
- else
- {
- CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader});
+ AMQDataBlock returnFrame = createEncodedReturnFrame(messagePublishInfo, channelId, replyCode, replyText);
- writeFrame(compositeBlock);
- }
+ writeMessageDelivery(content, header, channelId, returnFrame);
- //
- // Now start writing out the other content bodies
- // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded
- //
- while (bodyFrameIterator.hasNext())
- {
- writeFrame(bodyFrameIterator.next());
- }
}
@@ -276,8 +266,7 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag)
{
- MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0);
- BasicCancelOkBody basicCancelOkBody = methodRegistry.createBasicCancelOkBody(consumerTag);
+ BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag);
writeFrame(basicCancelOkBody.generateFrame(channelId));
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java b/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java
index c76c262edd..319b5cc7bd 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java
@@ -1,25 +1,48 @@
package org.apache.qpid.server.output.amqp0_9;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
-import org.apache.mina.common.ByteBuffer;
-import java.util.Iterator;
+import org.apache.mina.common.ByteBuffer;
import org.apache.qpid.server.output.ProtocolOutputConverter;
+import org.apache.qpid.server.output.HeaderPropertiesConverter;
import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.queue.AMQMessageHandle;
-import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.message.MessageContentSource;
+import org.apache.qpid.server.message.MessageTransferMessage;
import org.apache.qpid.framing.*;
-import org.apache.qpid.framing.abstraction.ContentChunk;
+import org.apache.qpid.framing.amqp_0_9.BasicGetBodyImpl;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;
import org.apache.qpid.AMQException;
+import org.apache.qpid.transport.DeliveryProperties;
import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
{
private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9);
- private static final ProtocolVersionMethodConverter PROTOCOL_METHOD_CONVERTER = METHOD_REGISTRY.getProtocolVersionMethodConverter();
+ private static final ProtocolVersionMethodConverter
+ PROTOCOL_CONVERTER = METHOD_REGISTRY.getProtocolVersionMethodConverter();
public static Factory getInstanceFactory()
@@ -47,20 +70,46 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
return _protocolSession;
}
- public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag)
+ public void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag)
throws AMQException
{
- AMQBody deliverBody = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag);
- final ContentHeaderBody contentHeaderBody = message.getContentHeaderBody();
+ AMQBody deliverBody = createEncodedDeliverBody(entry, deliveryTag, consumerTag);
+ writeMessageDelivery(entry, channelId, deliverBody);
+ }
- final AMQMessageHandle messageHandle = message.getMessageHandle();
- final StoreContext storeContext = message.getStoreContext();
+ private ContentHeaderBody getContentHeaderBody(QueueEntry entry)
+ throws AMQException
+ {
+ if(entry.getMessage() instanceof AMQMessage)
+ {
+ return ((AMQMessage)entry.getMessage()).getContentHeaderBody();
+ }
+ else
+ {
+ final MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+ BasicContentHeaderProperties props = HeaderPropertiesConverter.convert(message);
+ ContentHeaderBody chb = new ContentHeaderBody(props, BasicGetBodyImpl.CLASS_ID);
+ chb.bodySize = message.getSize();
+ return chb;
+ }
+ }
- final int bodyCount = messageHandle.getBodyCount(storeContext);
+ private void writeMessageDelivery(QueueEntry entry, int channelId, AMQBody deliverBody)
+ throws AMQException
+ {
+ writeMessageDelivery(entry.getMessage(), getContentHeaderBody(entry), channelId, deliverBody);
+ }
+
+ private void writeMessageDelivery(MessageContentSource message, ContentHeaderBody contentHeaderBody, int channelId, AMQBody deliverBody)
+ throws AMQException
+ {
- if(bodyCount == 0)
+
+ int bodySize = (int) message.getSize();
+
+ if(bodySize == 0)
{
SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody,
contentHeaderBody);
@@ -69,101 +118,75 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
}
else
{
+ int maxBodySize = (int) getProtocolSession().getMaxFrameSize() - AMQFrame.getFrameOverhead();
+
+
+ final int capacity = bodySize > maxBodySize ? maxBodySize : bodySize;
+ java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocate(capacity);
+ int writtenSize = 0;
- //
- // Optimise the case where we have a single content body. In that case we create a composite block
- // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
- //
- ContentChunk cb = messageHandle.getContentChunk(storeContext, 0);
- AMQBody firstContentBody = PROTOCOL_METHOD_CONVERTER.convertToBody(cb);
+ writtenSize += message.getContent(buf, writtenSize);
+ buf.flip();
+ AMQBody firstContentBody = PROTOCOL_CONVERTER.convertToBody(buf);
- CompositeAMQBodyBlock compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody);
+ CompositeAMQBodyBlock
+ compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody);
writeFrame(compositeBlock);
- //
- // Now start writing out the other content bodies
- //
- for(int i = 1; i < bodyCount; i++)
+ while(writtenSize < bodySize)
{
- cb = messageHandle.getContentChunk(storeContext, i);
- writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb)));
- }
-
+ buf = java.nio.ByteBuffer.allocate(capacity);
+ writtenSize += message.getContent(buf, writtenSize);
+ buf.flip();
+ writeFrame(new AMQFrame(channelId, PROTOCOL_CONVERTER.convertToBody(buf)));
+ }
}
-
}
private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody)
{
-
+
AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
contentHeaderBody);
return contentHeader;
}
- public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException
+ public void writeGetOk(QueueEntry entry, int channelId, long deliveryTag, int queueSize) throws AMQException
{
+ AMQBody deliver = createEncodedGetOkBody(entry, deliveryTag, queueSize);
+ writeMessageDelivery(entry, channelId, deliver);
+ }
- final AMQMessageHandle messageHandle = message.getMessageHandle();
- final StoreContext storeContext = message.getStoreContext();
-
- AMQFrame deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize);
+ private AMQBody createEncodedDeliverBody(QueueEntry entry,
+ final long deliveryTag,
+ final AMQShortString consumerTag)
+ throws AMQException
+ {
- AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody());
+ final AMQShortString exchangeName;
+ final AMQShortString routingKey;
- final int bodyCount = messageHandle.getBodyCount(storeContext);
- if(bodyCount == 0)
+ if(entry.getMessage() instanceof AMQMessage)
{
- SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver,
- contentHeader);
- writeFrame(compositeBlock);
+ final AMQMessage message = (AMQMessage) entry.getMessage();
+ final MessagePublishInfo pb = message.getMessagePublishInfo();
+ exchangeName = pb.getExchange();
+ routingKey = pb.getRoutingKey();
}
else
{
-
-
- //
- // Optimise the case where we have a single content body. In that case we create a composite block
- // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
- //
- ContentChunk cb = messageHandle.getContentChunk(storeContext, 0);
-
- AMQDataBlock firstContentBody = new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb));
- AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody};
- CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks);
- writeFrame(compositeBlock);
-
- //
- // Now start writing out the other content bodies
- //
- for(int i = 1; i < bodyCount; i++)
- {
- cb = messageHandle.getContentChunk(storeContext, i);
- writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb)));
- }
-
-
+ MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+ DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);
+ exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
+ routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
}
-
- }
-
-
- private AMQBody createEncodedDeliverFrame(AMQMessage message, final int channelId, final long deliveryTag, final AMQShortString consumerTag)
- throws AMQException
- {
- final MessagePublishInfo pb = message.getMessagePublishInfo();
- final AMQMessageHandle messageHandle = message.getMessageHandle();
-
-
- final boolean isRedelivered = messageHandle.isRedelivered();
- final AMQShortString exchangeName = pb.getExchange();
- final AMQShortString routingKey = pb.getRoutingKey();
+ final boolean isRedelivered = entry.isRedelivered();
final AMQBody returnBlock = new AMQBody()
{
@@ -216,22 +239,37 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
return returnBlock;
}
- private AMQFrame createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize)
+ private AMQBody createEncodedGetOkBody(QueueEntry entry, long deliveryTag, int queueSize)
throws AMQException
{
- final MessagePublishInfo pb = message.getMessagePublishInfo();
- final AMQMessageHandle messageHandle = message.getMessageHandle();
+ final AMQShortString exchangeName;
+ final AMQShortString routingKey;
+
+ if(entry.getMessage() instanceof AMQMessage)
+ {
+ final AMQMessage message = (AMQMessage) entry.getMessage();
+ final MessagePublishInfo pb = message.getMessagePublishInfo();
+ exchangeName = pb.getExchange();
+ routingKey = pb.getRoutingKey();
+ }
+ else
+ {
+ MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+ DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);
+ exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
+ routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
+ }
+ final boolean isRedelivered = entry.isRedelivered();
BasicGetOkBody getOkBody =
METHOD_REGISTRY.createBasicGetOkBody(deliveryTag,
- messageHandle.isRedelivered(),
- pb.getExchange(),
- pb.getRoutingKey(),
+ isRedelivered,
+ exchangeName,
+ routingKey,
queueSize);
- AMQFrame getOkFrame = getOkBody.generateFrame(channelId);
- return getOkFrame;
+ return getOkBody;
}
public byte getProtocolMinorVersion()
@@ -244,53 +282,28 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
return getProtocolSession().getProtocolMajorVersion();
}
- private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException
+ private AMQBody createEncodedReturnFrame(MessagePublishInfo messagePublishInfo,
+ int replyCode,
+ AMQShortString replyText) throws AMQException
{
BasicReturnBody basicReturnBody =
METHOD_REGISTRY.createBasicReturnBody(replyCode,
replyText,
- message.getMessagePublishInfo().getExchange(),
- message.getMessagePublishInfo().getRoutingKey());
- AMQFrame returnFrame = basicReturnBody.generateFrame(channelId);
+ messagePublishInfo.getExchange(),
+ messagePublishInfo.getRoutingKey());
- return returnFrame;
+
+ return basicReturnBody;
}
- public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText)
+ public void writeReturn(MessagePublishInfo messagePublishInfo, ContentHeaderBody header, MessageContentSource message, int channelId, int replyCode, AMQShortString replyText)
throws AMQException
{
- AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText);
-
- AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody());
-
- Iterator<AMQDataBlock> bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId);
- //
- // Optimise the case where we have a single content body. In that case we create a composite block
- // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
- //
- if (bodyFrameIterator.hasNext())
- {
- AMQDataBlock firstContentBody = bodyFrameIterator.next();
- AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody};
- CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks);
- writeFrame(compositeBlock);
- }
- else
- {
- CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader});
- writeFrame(compositeBlock);
- }
+ AMQBody returnFrame = createEncodedReturnFrame(messagePublishInfo, replyCode, replyText);
- //
- // Now start writing out the other content bodies
- // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded
- //
- while (bodyFrameIterator.hasNext())
- {
- writeFrame(bodyFrameIterator.next());
- }
+ writeMessageDelivery(message, header, channelId, returnFrame);
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9_1/ProtocolOutputConverterImpl.java b/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9_1/ProtocolOutputConverterImpl.java
new file mode 100644
index 0000000000..cffbe445ee
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9_1/ProtocolOutputConverterImpl.java
@@ -0,0 +1,383 @@
+package org.apache.qpid.server.output.amqp0_9_1;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+import org.apache.mina.common.ByteBuffer;
+
+import org.apache.qpid.server.output.ProtocolOutputConverter;
+import org.apache.qpid.server.output.HeaderPropertiesConverter;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.message.MessageContentSource;
+import org.apache.qpid.server.message.MessageTransferMessage;
+import org.apache.qpid.framing.*;
+import org.apache.qpid.framing.amqp_0_91.BasicGetBodyImpl;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.transport.DeliveryProperties;
+import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
+
+public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
+{
+ private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v0_91);
+ private static final ProtocolVersionMethodConverter
+ PROTOCOL_CONVERTER = METHOD_REGISTRY.getProtocolVersionMethodConverter();
+
+
+ public static Factory getInstanceFactory()
+ {
+ return new Factory()
+ {
+
+ public ProtocolOutputConverter newInstance(AMQProtocolSession session)
+ {
+ return new ProtocolOutputConverterImpl(session);
+ }
+ };
+ }
+
+ private final AMQProtocolSession _protocolSession;
+
+ private ProtocolOutputConverterImpl(AMQProtocolSession session)
+ {
+ _protocolSession = session;
+ }
+
+
+ public AMQProtocolSession getProtocolSession()
+ {
+ return _protocolSession;
+ }
+
+ public void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag)
+ throws AMQException
+ {
+ AMQBody deliverBody = createEncodedDeliverBody(entry, deliveryTag, consumerTag);
+ writeMessageDelivery(entry, channelId, deliverBody);
+ }
+
+
+ private ContentHeaderBody getContentHeaderBody(QueueEntry entry)
+ throws AMQException
+ {
+ if(entry.getMessage() instanceof AMQMessage)
+ {
+ return ((AMQMessage)entry.getMessage()).getContentHeaderBody();
+ }
+ else
+ {
+ final MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+ BasicContentHeaderProperties props = HeaderPropertiesConverter.convert(message);
+ ContentHeaderBody chb = new ContentHeaderBody(props, BasicGetBodyImpl.CLASS_ID);
+ chb.bodySize = message.getSize();
+ return chb;
+ }
+ }
+
+
+ private void writeMessageDelivery(QueueEntry entry, int channelId, AMQBody deliverBody)
+ throws AMQException
+ {
+ writeMessageDelivery(entry.getMessage(), getContentHeaderBody(entry), channelId, deliverBody);
+ }
+
+ private void writeMessageDelivery(MessageContentSource message, ContentHeaderBody contentHeaderBody, int channelId, AMQBody deliverBody)
+ throws AMQException
+ {
+
+
+ int bodySize = (int) message.getSize();
+
+ if(bodySize == 0)
+ {
+ SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody,
+ contentHeaderBody);
+
+ writeFrame(compositeBlock);
+ }
+ else
+ {
+ int maxBodySize = (int) getProtocolSession().getMaxFrameSize() - AMQFrame.getFrameOverhead();
+
+
+ final int capacity = bodySize > maxBodySize ? maxBodySize : bodySize;
+ java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocate(capacity);
+
+ int writtenSize = 0;
+
+
+ writtenSize += message.getContent(buf, writtenSize);
+ buf.flip();
+ AMQBody firstContentBody = PROTOCOL_CONVERTER.convertToBody(buf);
+
+ CompositeAMQBodyBlock
+ compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody);
+ writeFrame(compositeBlock);
+
+ while(writtenSize < bodySize)
+ {
+ buf = java.nio.ByteBuffer.allocate(capacity);
+
+ writtenSize += message.getContent(buf, writtenSize);
+ buf.flip();
+ writeFrame(new AMQFrame(channelId, PROTOCOL_CONVERTER.convertToBody(buf)));
+ }
+ }
+ }
+
+ private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody)
+ {
+
+ AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
+ contentHeaderBody);
+ return contentHeader;
+ }
+
+
+ public void writeGetOk(QueueEntry entry, int channelId, long deliveryTag, int queueSize) throws AMQException
+ {
+ AMQBody deliver = createEncodedGetOkBody(entry, deliveryTag, queueSize);
+ writeMessageDelivery(entry, channelId, deliver);
+ }
+
+
+ private AMQBody createEncodedDeliverBody(QueueEntry entry,
+ final long deliveryTag,
+ final AMQShortString consumerTag)
+ throws AMQException
+ {
+
+ final AMQShortString exchangeName;
+ final AMQShortString routingKey;
+
+ if(entry.getMessage() instanceof AMQMessage)
+ {
+ final AMQMessage message = (AMQMessage) entry.getMessage();
+ final MessagePublishInfo pb = message.getMessagePublishInfo();
+ exchangeName = pb.getExchange();
+ routingKey = pb.getRoutingKey();
+ }
+ else
+ {
+ MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+ DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);
+ exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
+ routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
+ }
+
+ final boolean isRedelivered = entry.isRedelivered();
+
+ final AMQBody returnBlock = new AMQBody()
+ {
+
+ public AMQBody _underlyingBody;
+
+ public AMQBody createAMQBody()
+ {
+ return METHOD_REGISTRY.createBasicDeliverBody(consumerTag,
+ deliveryTag,
+ isRedelivered,
+ exchangeName,
+ routingKey);
+
+
+
+
+
+ }
+
+ public byte getFrameType()
+ {
+ return AMQMethodBody.TYPE;
+ }
+
+ public int getSize()
+ {
+ if(_underlyingBody == null)
+ {
+ _underlyingBody = createAMQBody();
+ }
+ return _underlyingBody.getSize();
+ }
+
+ public void writePayload(ByteBuffer buffer)
+ {
+ if(_underlyingBody == null)
+ {
+ _underlyingBody = createAMQBody();
+ }
+ _underlyingBody.writePayload(buffer);
+ }
+
+ public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession)
+ throws AMQException
+ {
+ throw new AMQException("This block should never be dispatched!");
+ }
+ };
+ return returnBlock;
+ }
+
+ private AMQBody createEncodedGetOkBody(QueueEntry entry, long deliveryTag, int queueSize)
+ throws AMQException
+ {
+ final AMQShortString exchangeName;
+ final AMQShortString routingKey;
+
+ if(entry.getMessage() instanceof AMQMessage)
+ {
+ final AMQMessage message = (AMQMessage) entry.getMessage();
+ final MessagePublishInfo pb = message.getMessagePublishInfo();
+ exchangeName = pb.getExchange();
+ routingKey = pb.getRoutingKey();
+ }
+ else
+ {
+ MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+ DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);
+ exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
+ routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
+ }
+
+ final boolean isRedelivered = entry.isRedelivered();
+
+ BasicGetOkBody getOkBody =
+ METHOD_REGISTRY.createBasicGetOkBody(deliveryTag,
+ isRedelivered,
+ exchangeName,
+ routingKey,
+ queueSize);
+
+ return getOkBody;
+ }
+
+ public byte getProtocolMinorVersion()
+ {
+ return getProtocolSession().getProtocolMinorVersion();
+ }
+
+ public byte getProtocolMajorVersion()
+ {
+ return getProtocolSession().getProtocolMajorVersion();
+ }
+
+ private AMQBody createEncodedReturnFrame(MessagePublishInfo messagePublishInfo,
+ int replyCode,
+ AMQShortString replyText) throws AMQException
+ {
+
+ BasicReturnBody basicReturnBody =
+ METHOD_REGISTRY.createBasicReturnBody(replyCode,
+ replyText,
+ messagePublishInfo.getExchange(),
+ messagePublishInfo.getRoutingKey());
+
+
+ return basicReturnBody;
+ }
+
+ public void writeReturn(MessagePublishInfo messagePublishInfo, ContentHeaderBody header, MessageContentSource message, int channelId, int replyCode, AMQShortString replyText)
+ throws AMQException
+ {
+
+ AMQBody returnFrame = createEncodedReturnFrame(messagePublishInfo, replyCode, replyText);
+
+ writeMessageDelivery(message, header, channelId, returnFrame);
+ }
+
+
+ public void writeFrame(AMQDataBlock block)
+ {
+ getProtocolSession().writeFrame(block);
+ }
+
+
+ public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag)
+ {
+
+ BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag);
+ writeFrame(basicCancelOkBody.generateFrame(channelId));
+
+ }
+
+
+ public static final class CompositeAMQBodyBlock extends AMQDataBlock
+ {
+ public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead();
+
+ private final AMQBody _methodBody;
+ private final AMQBody _headerBody;
+ private final AMQBody _contentBody;
+ private final int _channel;
+
+
+ public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody)
+ {
+ _channel = channel;
+ _methodBody = methodBody;
+ _headerBody = headerBody;
+ _contentBody = contentBody;
+
+ }
+
+ public long getSize()
+ {
+ return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize();
+ }
+
+ public void writePayload(ByteBuffer buffer)
+ {
+ AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody);
+ }
+ }
+
+ public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock
+ {
+ public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead();
+
+ private final AMQBody _methodBody;
+ private final AMQBody _headerBody;
+ private final int _channel;
+
+
+ public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody)
+ {
+ _channel = channel;
+ _methodBody = methodBody;
+ _headerBody = headerBody;
+
+ }
+
+ public long getSize()
+ {
+ return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ;
+ }
+
+ public void writePayload(ByteBuffer buffer)
+ {
+ AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody);
+ }
+ }
+
+} \ No newline at end of file
diff --git a/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java
index 9191ecf6ed..dbfcefb6ab 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java
@@ -30,6 +30,13 @@ import org.apache.felix.framework.cache.BundleCache;
import org.apache.felix.framework.util.FelixConstants;
import org.apache.felix.framework.util.StringMap;
import org.apache.qpid.server.exchange.ExchangeType;
+import org.apache.qpid.server.security.access.ACLPlugin;
+import org.apache.qpid.server.security.access.ACLPluginFactory;
+import org.apache.qpid.server.security.access.plugins.AllowAll;
+import org.apache.qpid.server.security.access.plugins.DenyAll;
+import org.apache.qpid.server.security.access.plugins.LegacyAccessPlugin;
+import org.apache.qpid.server.security.access.plugins.SimpleXML;
+import org.apache.qpid.server.security.access.plugins.network.FirewallPlugin;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleException;
import org.osgi.util.tracker.ServiceTracker;
@@ -46,8 +53,10 @@ public class PluginManager
private Felix _felix = null;
private ServiceTracker _exchangeTracker = null;
+ private ServiceTracker _securityTracker = null;
private Activator _activator = null;
private boolean _empty;
+ private Map<String, ACLPluginFactory> _securityPlugins;
public PluginManager(String plugindir) throws Exception
{
@@ -115,8 +124,13 @@ public class PluginManager
try
{
_felix.start();
+
_exchangeTracker = new ServiceTracker(_activator.getContext(), ExchangeType.class.getName(), null);
_exchangeTracker.open();
+
+ _securityTracker = new ServiceTracker(_activator.getContext(), ACLPlugin.class.getName(), null);
+ _exchangeTracker.open();
+
}
catch (BundleException e)
{
@@ -124,22 +138,39 @@ public class PluginManager
}
}
- public Map<String, ExchangeType<?>> getExchanges()
- {
- if (_empty)
- {
- return null;
- }
- Map<String, ExchangeType<?>>exchanges = new HashMap<String, ExchangeType<?>>();
- for (Object service : _exchangeTracker.getServices())
+ private <type> Map<String, type> getServices(ServiceTracker tracker)
+ {
+ Map<String, type>exchanges = new HashMap<String, type>();
+
+ if (tracker != null)
{
- if (service instanceof ExchangeType<?>)
+ for (Object service : tracker.getServices())
{
- exchanges.put(service.getClass().getName(), (ExchangeType<?>) service);
+ exchanges.put(service.getClass().getName(), (type) service);
}
}
return exchanges;
}
+
+ public Map<String, ExchangeType<?>> getExchanges()
+ {
+ return getServices(_exchangeTracker);
+ }
+
+ public Map<String, ACLPluginFactory> getSecurityPlugins()
+ {
+ if (_securityPlugins == null)
+ {
+ _securityPlugins = getServices(_securityTracker);
+ // A little gross that we have to add them here, but not all the plugins are OSGIfied
+ _securityPlugins.put(SimpleXML.class.getName(), SimpleXML.FACTORY);
+ _securityPlugins.put(AllowAll.class.getName(), AllowAll.FACTORY);
+ _securityPlugins.put(DenyAll.class.getName(), DenyAll.FACTORY);
+ _securityPlugins.put(LegacyAccessPlugin.class.getName(), LegacyAccessPlugin.FACTORY);
+ _securityPlugins.put(FirewallPlugin.class.getName(), FirewallPlugin.FACTORY);
+ }
+ return _securityPlugins;
+ }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java
deleted file mode 100644
index 64914b407d..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java
+++ /dev/null
@@ -1,859 +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.
- *
- */
-package org.apache.qpid.server.protocol;
-
-import org.apache.log4j.Logger;
-
-import org.apache.mina.common.IdleStatus;
-import org.apache.mina.common.IoServiceConfig;
-import org.apache.mina.common.IoSession;
-import org.apache.mina.common.CloseFuture;
-import org.apache.mina.transport.vmpipe.VmPipeAddress;
-
-import org.apache.qpid.AMQChannelException;
-import org.apache.qpid.AMQConnectionException;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.codec.AMQCodecFactory;
-import org.apache.qpid.codec.AMQDecoder;
-import org.apache.qpid.common.ClientProperties;
-import org.apache.qpid.framing.*;
-import org.apache.qpid.pool.ReadWriteThreadModel;
-import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.protocol.AMQMethodEvent;
-import org.apache.qpid.protocol.AMQMethodListener;
-import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.handler.ServerMethodDispatcherImpl;
-import org.apache.qpid.server.management.Managable;
-import org.apache.qpid.server.management.ManagedObject;
-import org.apache.qpid.server.output.ProtocolOutputConverter;
-import org.apache.qpid.server.output.ProtocolOutputConverterRegistry;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.state.AMQState;
-import org.apache.qpid.server.state.AMQStateManager;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
-import org.apache.qpid.transport.Sender;
-
-import javax.management.JMException;
-import javax.security.sasl.SaslServer;
-
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.security.Principal;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.CopyOnWriteArraySet;
-
-public class AMQMinaProtocolSession implements AMQProtocolSession, Managable
-{
- private static final Logger _logger = Logger.getLogger(AMQProtocolSession.class);
-
- private static final String CLIENT_PROPERTIES_INSTANCE = ClientProperties.instance.toString();
-
- // to save boxing the channelId and looking up in a map... cache in an array the low numbered
- // channels. This value must be of the form 2^x - 1.
- private static final int CHANNEL_CACHE_SIZE = 0xff;
-
- private final IoSession _minaProtocolSession;
-
- private AMQShortString _contextKey;
-
- private AMQShortString _clientVersion = null;
-
- private VirtualHost _virtualHost;
-
- private final Map<Integer, AMQChannel> _channelMap = new HashMap<Integer, AMQChannel>();
-
- private final AMQChannel[] _cachedChannels = new AMQChannel[CHANNEL_CACHE_SIZE + 1];
-
- private final CopyOnWriteArraySet<AMQMethodListener> _frameListeners = new CopyOnWriteArraySet<AMQMethodListener>();
-
- private final AMQStateManager _stateManager;
-
- private AMQCodecFactory _codecFactory;
-
- private AMQProtocolSessionMBean _managedObject;
-
- private SaslServer _saslServer;
-
- private Object _lastReceived;
-
- private Object _lastSent;
-
- protected boolean _closed;
- // maximum number of channels this session should have
- private long _maxNoOfChannels = 1000;
-
- /* AMQP Version for this session */
- private ProtocolVersion _protocolVersion = ProtocolVersion.getLatestSupportedVersion();
-
- private FieldTable _clientProperties;
- private final List<Task> _taskList = new CopyOnWriteArrayList<Task>();
-
- private List<Integer> _closingChannelsList = new CopyOnWriteArrayList<Integer>();
- private ProtocolOutputConverter _protocolOutputConverter;
- private Principal _authorizedID;
- private MethodDispatcher _dispatcher;
- private ProtocolSessionIdentifier _sessionIdentifier;
-
- private static final long LAST_WRITE_FUTURE_JOIN_TIMEOUT = 60000L;
- private org.apache.mina.common.WriteFuture _lastWriteFuture;
-
- public ManagedObject getManagedObject()
- {
- return _managedObject;
- }
-
- public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, AMQCodecFactory codecFactory)
- throws AMQException
- {
- _stateManager = new AMQStateManager(virtualHostRegistry, this);
- _minaProtocolSession = session;
- session.setAttachment(this);
-
- _codecFactory = codecFactory;
-
- try
- {
- IoServiceConfig config = session.getServiceConfig();
- ReadWriteThreadModel threadModel = (ReadWriteThreadModel) config.getThreadModel();
- threadModel.getAsynchronousReadFilter().createNewJobForSession(session);
- threadModel.getAsynchronousWriteFilter().createNewJobForSession(session);
- }
- catch (RuntimeException e)
- {
- e.printStackTrace();
- throw e;
-
- }
- }
-
- public AMQMinaProtocolSession(IoSession session, VirtualHostRegistry virtualHostRegistry, AMQCodecFactory codecFactory,
- AMQStateManager stateManager) throws AMQException
- {
- _stateManager = stateManager;
- _minaProtocolSession = session;
- session.setAttachment(this);
-
- _codecFactory = codecFactory;
-
- }
-
- private AMQProtocolSessionMBean createMBean() throws AMQException
- {
- try
- {
- return new AMQProtocolSessionMBean(this);
- }
- catch (JMException ex)
- {
- _logger.error("AMQProtocolSession MBean creation has failed ", ex);
- throw new AMQException("AMQProtocolSession MBean creation has failed ", ex);
- }
- }
-
- public IoSession getIOSession()
- {
- return _minaProtocolSession;
- }
-
- public static AMQProtocolSession getAMQProtocolSession(IoSession minaProtocolSession)
- {
- return (AMQProtocolSession) minaProtocolSession.getAttachment();
- }
-
- public void dataBlockReceived(AMQDataBlock message) throws Exception
- {
- _lastReceived = message;
- if (message instanceof ProtocolInitiation)
- {
- protocolInitiationReceived((ProtocolInitiation) message);
-
- }
- else if (message instanceof AMQFrame)
- {
- AMQFrame frame = (AMQFrame) message;
- frameReceived(frame);
-
- }
- else
- {
- throw new UnknnownMessageTypeException(message);
- }
- }
-
- private void frameReceived(AMQFrame frame) throws AMQException
- {
- int channelId = frame.getChannel();
- AMQBody body = frame.getBodyFrame();
-
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Frame Received: " + frame);
- }
-
- // Check that this channel is not closing
- if (channelAwaitingClosure(channelId))
- {
- if ((frame.getBodyFrame() instanceof ChannelCloseOkBody))
- {
- if (_logger.isInfoEnabled())
- {
- _logger.info("Channel[" + channelId + "] awaiting closure - processing close-ok");
- }
- }
- else
- {
- if (_logger.isInfoEnabled())
- {
- _logger.info("Channel[" + channelId + "] awaiting closure. Should close socket as client did not close-ok :" + frame);
- }
-
- closeProtocolSession();
- return;
- }
- }
-
- try
- {
- body.handle(channelId, this);
- }
- catch (AMQException e)
- {
- closeChannel(channelId);
- throw e;
- }
-
- }
-
- private void protocolInitiationReceived(ProtocolInitiation pi)
- {
- // this ensures the codec never checks for a PI message again
- ((AMQDecoder) _codecFactory.getDecoder()).setExpectProtocolInitiation(false);
- try
- {
- ProtocolVersion pv = pi.checkVersion(); // Fails if not correct
-
- // This sets the protocol version (and hence framing classes) for this session.
- setProtocolVersion(pv);
-
- String mechanisms = ApplicationRegistry.getInstance().getAuthenticationManager().getMechanisms();
-
- String locales = "en_US";
-
- AMQMethodBody responseBody = getMethodRegistry().createConnectionStartBody((short) getProtocolMajorVersion(),
- (short) getProtocolMinorVersion(),
- null,
- mechanisms.getBytes(),
- locales.getBytes());
- _minaProtocolSession.write(responseBody.generateFrame(0));
-
- }
- catch (AMQException e)
- {
- _logger.error("Received incorrect protocol initiation", e);
-
- _minaProtocolSession.write(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion()));
-
- // TODO: Close connection (but how to wait until message is sent?)
- // ritchiem 2006-12-04 will this not do?
- // WriteFuture future = _minaProtocolSession.write(new ProtocolInitiation(pv[i][PROTOCOLgetProtocolMajorVersion()], pv[i][PROTOCOLgetProtocolMinorVersion()]));
- // future.join();
- // close connection
-
- }
- }
-
- public void methodFrameReceived(int channelId, AMQMethodBody methodBody)
- {
-
- final AMQMethodEvent<AMQMethodBody> evt = new AMQMethodEvent<AMQMethodBody>(channelId, methodBody);
-
- try
- {
- try
- {
-
- boolean wasAnyoneInterested = _stateManager.methodReceived(evt);
-
- if (!_frameListeners.isEmpty())
- {
- for (AMQMethodListener listener : _frameListeners)
- {
- wasAnyoneInterested = listener.methodReceived(evt) || wasAnyoneInterested;
- }
- }
-
- if (!wasAnyoneInterested)
- {
- throw new AMQNoMethodHandlerException(evt);
- }
- }
- catch (AMQChannelException e)
- {
- if (getChannel(channelId) != null)
- {
- if (_logger.isInfoEnabled())
- {
- _logger.info("Closing channel due to: " + e.getMessage());
- }
-
- writeFrame(e.getCloseFrame(channelId));
- closeChannel(channelId);
- }
- else
- {
- if (_logger.isDebugEnabled())
- {
- _logger.debug("ChannelException occured on non-existent channel:" + e.getMessage());
- }
-
- if (_logger.isInfoEnabled())
- {
- _logger.info("Closing connection due to: " + e.getMessage());
- }
-
- AMQConnectionException ce =
- evt.getMethod().getConnectionException(AMQConstant.CHANNEL_ERROR,
- AMQConstant.CHANNEL_ERROR.getName().toString());
-
- closeConnection(channelId, ce, false);
- }
- }
- catch (AMQConnectionException e)
- {
- closeConnection(channelId, e, false);
- }
- }
- catch (Exception e)
- {
-
- for (AMQMethodListener listener : _frameListeners)
- {
- listener.error(e);
- }
-
- _logger.error("Unexpected exception while processing frame. Closing connection.", e);
-
- closeProtocolSession();
- }
- }
-
- public void contentHeaderReceived(int channelId, ContentHeaderBody body) throws AMQException
- {
-
- AMQChannel channel = getAndAssertChannel(channelId);
-
- channel.publishContentHeader(body);
-
- }
-
- public void contentBodyReceived(int channelId, ContentBody body) throws AMQException
- {
- AMQChannel channel = getAndAssertChannel(channelId);
-
- channel.publishContentBody(body);
- }
-
- public void heartbeatBodyReceived(int channelId, HeartbeatBody body)
- {
- // NO - OP
- }
-
- /**
- * Convenience method that writes a frame to the protocol session. Equivalent to calling
- * getProtocolSession().write().
- *
- * @param frame the frame to write
- */
- public void writeFrame(AMQDataBlock frame)
- {
- _lastSent = frame;
-
- _lastWriteFuture = _minaProtocolSession.write(frame);
- }
-
- public AMQShortString getContextKey()
- {
- return _contextKey;
- }
-
- public void setContextKey(AMQShortString contextKey)
- {
- _contextKey = contextKey;
- }
-
- public List<AMQChannel> getChannels()
- {
- return new ArrayList<AMQChannel>(_channelMap.values());
- }
-
- public AMQChannel getAndAssertChannel(int channelId) throws AMQException
- {
- AMQChannel channel = getChannel(channelId);
- if (channel == null)
- {
- throw new AMQException(AMQConstant.NOT_FOUND, "Channel not found with id:" + channelId);
- }
-
- return channel;
- }
-
- public AMQChannel getChannel(int channelId) throws AMQException
- {
- final AMQChannel channel =
- ((channelId & CHANNEL_CACHE_SIZE) == channelId) ? _cachedChannels[channelId] : _channelMap.get(channelId);
- if ((channel == null) || channel.isClosing())
- {
- return null;
- }
- else
- {
- return channel;
- }
- }
-
- public boolean channelAwaitingClosure(int channelId)
- {
- return !_closingChannelsList.isEmpty() && _closingChannelsList.contains(channelId);
- }
-
- public void addChannel(AMQChannel channel) throws AMQException
- {
- if (_closed)
- {
- throw new AMQException("Session is closed");
- }
-
- final int channelId = channel.getChannelId();
-
- if (_closingChannelsList.contains(channelId))
- {
- throw new AMQException("Session is marked awaiting channel close");
- }
-
- if (_channelMap.size() == _maxNoOfChannels)
- {
- String errorMessage =
- toString() + ": maximum number of channels has been reached (" + _maxNoOfChannels
- + "); can't create channel";
- _logger.error(errorMessage);
- throw new AMQException(AMQConstant.NOT_ALLOWED, errorMessage);
- }
- else
- {
- _channelMap.put(channel.getChannelId(), channel);
- }
-
- if (((channelId & CHANNEL_CACHE_SIZE) == channelId))
- {
- _cachedChannels[channelId] = channel;
- }
-
- checkForNotification();
- }
-
- private void checkForNotification()
- {
- int channelsCount = _channelMap.size();
- if (channelsCount >= _maxNoOfChannels)
- {
- _managedObject.notifyClients("Channel count (" + channelsCount + ") has reached the threshold value");
- }
- }
-
- public Long getMaximumNumberOfChannels()
- {
- return _maxNoOfChannels;
- }
-
- public void setMaximumNumberOfChannels(Long value)
- {
- _maxNoOfChannels = value;
- }
-
- public void commitTransactions(AMQChannel channel) throws AMQException
- {
- if ((channel != null) && channel.isTransactional())
- {
- channel.commit();
- }
- }
-
- public void rollbackTransactions(AMQChannel channel) throws AMQException
- {
- if ((channel != null) && channel.isTransactional())
- {
- channel.rollback();
- }
- }
-
- /**
- * Close a specific channel. This will remove any resources used by the channel, including: <ul><li>any queue
- * subscriptions (this may in turn remove queues if they are auto delete</li> </ul>
- *
- * @param channelId id of the channel to close
- *
- * @throws AMQException if an error occurs closing the channel
- * @throws IllegalArgumentException if the channel id is not valid
- */
- public void closeChannel(int channelId) throws AMQException
- {
- final AMQChannel channel = getChannel(channelId);
- if (channel == null)
- {
- throw new IllegalArgumentException("Unknown channel id");
- }
- else
- {
- try
- {
- channel.close();
- markChannelAwaitingCloseOk(channelId);
- }
- finally
- {
- removeChannel(channelId);
- }
- }
- }
-
- public void closeChannelOk(int channelId)
- {
- // todo QPID-847 - This is called from two lcoations ChannelCloseHandler and ChannelCloseOkHandler.
- // When it is the CC_OK_Handler then it makes sence to remove the channel else we will leak memory.
- // We do it from the Close Handler as we are sending the OK back to the client.
- // While this is AMQP spec compliant. The Java client in the event of an IllegalArgumentException
- // will send a close-ok.. Where we should call removeChannel.
- // However, due to the poor exception handling on the client. The client-user will be notified of the
- // InvalidArgument and if they then decide to close the session/connection then the there will be time
- // for that to occur i.e. a new close method be sent before the exeption handling can mark the session closed.
- //removeChannel(channelId);
- _closingChannelsList.remove(new Integer(channelId));
- }
-
- private void markChannelAwaitingCloseOk(int channelId)
- {
- _closingChannelsList.add(channelId);
- }
-
- /**
- * In our current implementation this is used by the clustering code.
- *
- * @param channelId The channel to remove
- */
- public void removeChannel(int channelId)
- {
- _channelMap.remove(channelId);
- if ((channelId & CHANNEL_CACHE_SIZE) == channelId)
- {
- _cachedChannels[channelId] = null;
- }
- }
-
- /**
- * Initialise heartbeats on the session.
- *
- * @param delay delay in seconds (not ms)
- */
- public void initHeartbeats(int delay)
- {
- if (delay > 0)
- {
- _minaProtocolSession.setIdleTime(IdleStatus.WRITER_IDLE, delay);
- _minaProtocolSession.setIdleTime(IdleStatus.READER_IDLE, HeartbeatConfig.getInstance().getTimeout(delay));
- }
- }
-
- /**
- * Closes all channels that were opened by this protocol session. This frees up all resources used by the channel.
- *
- * @throws AMQException if an error occurs while closing any channel
- */
- private void closeAllChannels() throws AMQException
- {
- for (AMQChannel channel : _channelMap.values())
- {
- channel.close();
- }
-
- _channelMap.clear();
- for (int i = 0; i <= CHANNEL_CACHE_SIZE; i++)
- {
- _cachedChannels[i] = null;
- }
- }
-
- /** This must be called when the session is _closed in order to free up any resources managed by the session. */
- public void closeSession() throws AMQException
- {
- if (!_closed)
- {
- _closed = true;
-
- if (_virtualHost != null)
- {
- _virtualHost.getConnectionRegistry().deregisterConnection(this);
- }
-
- closeAllChannels();
- if (_managedObject != null)
- {
- _managedObject.unregister();
- }
-
- for (Task task : _taskList)
- {
- task.doTask(this);
- }
- }
- }
-
- public void closeConnection(int channelId, AMQConnectionException e, boolean closeProtocolSession) throws AMQException
- {
- if (_logger.isInfoEnabled())
- {
- _logger.info("Closing connection due to: " + e.getMessage());
- }
-
- markChannelAwaitingCloseOk(channelId);
- closeSession();
- _stateManager.changeState(AMQState.CONNECTION_CLOSING);
- writeFrame(e.getCloseFrame(channelId));
-
- if (closeProtocolSession)
- {
- closeProtocolSession();
- }
- }
-
- public void closeProtocolSession()
- {
- closeProtocolSession(true);
- }
-
- public void closeProtocolSession(boolean waitLast)
- {
- _logger.debug("Waiting for last write to join.");
- if (waitLast && (_lastWriteFuture != null))
- {
- _lastWriteFuture.join(LAST_WRITE_FUTURE_JOIN_TIMEOUT);
- }
-
- _logger.debug("REALLY Closing protocol session:" + _minaProtocolSession);
- final CloseFuture future = _minaProtocolSession.close();
- future.join(LAST_WRITE_FUTURE_JOIN_TIMEOUT);
-
- try
- {
- _stateManager.changeState(AMQState.CONNECTION_CLOSED);
- }
- catch (AMQException e)
- {
- _logger.info(e.getMessage());
- }
- }
-
- public String toString()
- {
- return _minaProtocolSession.getRemoteAddress() + "(" + (getAuthorizedID() == null ? "?" : getAuthorizedID().getName() + ")");
- }
-
- public String dump()
- {
- return this + " last_sent=" + _lastSent + " last_received=" + _lastReceived;
- }
-
- /** @return an object that can be used to identity */
- public Object getKey()
- {
- return _minaProtocolSession.getRemoteAddress();
- }
-
- /**
- * Get the fully qualified domain name of the local address to which this session is bound. Since some servers may
- * be bound to multiple addresses this could vary depending on the acceptor this session was created from.
- *
- * @return a String FQDN
- */
- public String getLocalFQDN()
- {
- SocketAddress address = _minaProtocolSession.getLocalAddress();
- // we use the vmpipe address in some tests hence the need for this rather ugly test. The host
- // information is used by SASL primary.
- if (address instanceof InetSocketAddress)
- {
- return ((InetSocketAddress) address).getHostName();
- }
- else if (address instanceof VmPipeAddress)
- {
- return "vmpipe:" + ((VmPipeAddress) address).getPort();
- }
- else
- {
- throw new IllegalArgumentException("Unsupported socket address class: " + address);
- }
- }
-
- public SaslServer getSaslServer()
- {
- return _saslServer;
- }
-
- public void setSaslServer(SaslServer saslServer)
- {
- _saslServer = saslServer;
- }
-
- public FieldTable getClientProperties()
- {
- return _clientProperties;
- }
-
- public void setClientProperties(FieldTable clientProperties)
- {
- _clientProperties = clientProperties;
- if (_clientProperties != null)
- {
- if (_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE) != null)
- {
- setContextKey(new AMQShortString(_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE)));
- }
-
- if (_clientProperties.getString(ClientProperties.version.toString()) != null)
- {
- _clientVersion = new AMQShortString(_clientProperties.getString(ClientProperties.version.toString()));
- }
- }
- _sessionIdentifier = new ProtocolSessionIdentifier(this);
- }
-
- private void setProtocolVersion(ProtocolVersion pv)
- {
- _protocolVersion = pv;
-
- _protocolOutputConverter = ProtocolOutputConverterRegistry.getConverter(this);
- _dispatcher = ServerMethodDispatcherImpl.createMethodDispatcher(_stateManager, _protocolVersion);
- }
-
- public byte getProtocolMajorVersion()
- {
- return _protocolVersion.getMajorVersion();
- }
-
- public ProtocolVersion getProtocolVersion()
- {
- return _protocolVersion;
- }
-
- public byte getProtocolMinorVersion()
- {
- return _protocolVersion.getMinorVersion();
- }
-
- public boolean isProtocolVersion(byte major, byte minor)
- {
- return (getProtocolMajorVersion() == major) && (getProtocolMinorVersion() == minor);
- }
-
- public MethodRegistry getRegistry()
- {
- return getMethodRegistry();
- }
-
- public Object getClientIdentifier()
- {
- return (_minaProtocolSession != null) ? _minaProtocolSession.getRemoteAddress() : null;
- }
-
- public VirtualHost getVirtualHost()
- {
- return _virtualHost;
- }
-
- public void setVirtualHost(VirtualHost virtualHost) throws AMQException
- {
- _virtualHost = virtualHost;
-
- _virtualHost.getConnectionRegistry().registerConnection(this);
-
- _managedObject = createMBean();
- _managedObject.register();
- }
-
- public void addSessionCloseTask(Task task)
- {
- _taskList.add(task);
- }
-
- public void removeSessionCloseTask(Task task)
- {
- _taskList.remove(task);
- }
-
- public ProtocolOutputConverter getProtocolOutputConverter()
- {
- return _protocolOutputConverter;
- }
-
- public void setAuthorizedID(Principal authorizedID)
- {
- _authorizedID = authorizedID;
- }
-
- public Principal getAuthorizedID()
- {
- return _authorizedID;
- }
-
- public MethodRegistry getMethodRegistry()
- {
- return MethodRegistry.getMethodRegistry(getProtocolVersion());
- }
-
- public MethodDispatcher getMethodDispatcher()
- {
- return _dispatcher;
- }
-
- public ProtocolSessionIdentifier getSessionIdentifier()
- {
- return _sessionIdentifier;
- }
-
- public String getClientVersion()
- {
- return (_clientVersion == null) ? null : _clientVersion.toString();
- }
-
- public void setSender(Sender<java.nio.ByteBuffer> sender)
- {
- // No-op, interface munging between this and AMQProtocolSession
- }
-
- public void init()
- {
- // No-op, interface munging between this and AMQProtocolSession
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java
deleted file mode 100644
index d8dbf97e49..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java
+++ /dev/null
@@ -1,280 +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.
- *
- */
-package org.apache.qpid.server.protocol;
-
-import org.apache.log4j.Logger;
-import org.apache.mina.common.ByteBuffer;
-import org.apache.mina.common.IdleStatus;
-import org.apache.mina.common.IoFilterChain;
-import org.apache.mina.common.IoHandlerAdapter;
-import org.apache.mina.common.IoSession;
-import org.apache.mina.filter.ReadThrottleFilterBuilder;
-import org.apache.mina.filter.SSLFilter;
-import org.apache.mina.filter.WriteBufferLimitFilterBuilder;
-import org.apache.mina.filter.codec.QpidProtocolCodecFilter;
-import org.apache.mina.filter.executor.ExecutorFilter;
-import org.apache.mina.util.SessionUtil;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.codec.AMQCodecFactory;
-import org.apache.qpid.framing.*;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.registry.IApplicationRegistry;
-import org.apache.qpid.server.transport.ConnectorConfiguration;
-import org.apache.qpid.ssl.SSLContextFactory;
-
-import java.io.IOException;
-import java.net.InetSocketAddress;
-
-/**
- * The protocol handler handles "protocol events" for all connections. The state
- * associated with an individual connection is accessed through the protocol session.
- *
- * We delegate all frame (message) processing to the AMQProtocolSession which wraps
- * the state for the connection.
- */
-public class AMQPFastProtocolHandler extends IoHandlerAdapter
-{
- private static final Logger _logger = Logger.getLogger(AMQPFastProtocolHandler.class);
-
- private final IApplicationRegistry _applicationRegistry;
-
- private static String DEFAULT_BUFFER_READ_LIMIT_SIZE = "262144";
- private static String DEFAULT_BUFFER_WRITE_LIMIT_SIZE = "262144";
-
- private final int BUFFER_READ_LIMIT_SIZE;
- private final int BUFFER_WRITE_LIMIT_SIZE;
-
- public AMQPFastProtocolHandler(Integer applicationRegistryInstance)
- {
- this(ApplicationRegistry.getInstance(applicationRegistryInstance));
- }
-
- public AMQPFastProtocolHandler(IApplicationRegistry applicationRegistry)
- {
- _applicationRegistry = applicationRegistry;
-
- // Read the configuration from the application registry
- BUFFER_READ_LIMIT_SIZE = Integer.parseInt(_applicationRegistry.getConfiguration().getString("broker.connector.protectio.readBufferLimitSize", DEFAULT_BUFFER_READ_LIMIT_SIZE));
- BUFFER_WRITE_LIMIT_SIZE = Integer.parseInt(_applicationRegistry.getConfiguration().getString("broker.connector.protectio.writeBufferLimitSize", DEFAULT_BUFFER_WRITE_LIMIT_SIZE));
-
- _logger.debug("AMQPFastProtocolHandler created");
- }
-
- protected AMQPFastProtocolHandler(AMQPFastProtocolHandler handler)
- {
- this(handler._applicationRegistry);
- }
-
- public void sessionCreated(IoSession protocolSession) throws Exception
- {
- SessionUtil.initialize(protocolSession);
- final AMQCodecFactory codecFactory = new AMQCodecFactory(true);
-
- createSession(protocolSession, _applicationRegistry, codecFactory);
- _logger.info("Protocol session created for:" + protocolSession.getRemoteAddress());
-
- final QpidProtocolCodecFilter pcf = new QpidProtocolCodecFilter(codecFactory);
-
- ConnectorConfiguration connectorConfig = ApplicationRegistry.getInstance().
- getConfiguredObject(ConnectorConfiguration.class);
- if (connectorConfig.enableExecutorPool)
- {
- if (connectorConfig.enableSSL && isSSLClient(connectorConfig, protocolSession))
- {
- String keystorePath = connectorConfig.keystorePath;
- String keystorePassword = connectorConfig.keystorePassword;
- String certType = connectorConfig.certType;
- SSLContextFactory sslContextFactory = new SSLContextFactory(keystorePath, keystorePassword, certType);
- protocolSession.getFilterChain().addAfter("AsynchronousReadFilter", "sslFilter",
- new SSLFilter(sslContextFactory.buildServerContext()));
- }
- protocolSession.getFilterChain().addBefore("AsynchronousWriteFilter", "protocolFilter", pcf);
- }
- else
- {
- protocolSession.getFilterChain().addLast("protocolFilter", pcf);
- if (connectorConfig.enableSSL && isSSLClient(connectorConfig, protocolSession))
- {
- String keystorePath = connectorConfig.keystorePath;
- String keystorePassword = connectorConfig.keystorePassword;
- String certType = connectorConfig.certType;
- SSLContextFactory sslContextFactory = new SSLContextFactory(keystorePath, keystorePassword, certType);
- protocolSession.getFilterChain().addBefore("protocolFilter", "sslFilter",
- new SSLFilter(sslContextFactory.buildServerContext()));
- }
-
- }
-
- if (ApplicationRegistry.getInstance().getConfiguration().getBoolean("broker.connector.protectio.enabled", false))
- {
- try
- {
-// //Add IO Protection Filters
- IoFilterChain chain = protocolSession.getFilterChain();
-
-
- protocolSession.getFilterChain().addLast("tempExecutorFilterForFilterBuilder", new ExecutorFilter());
-
- ReadThrottleFilterBuilder readfilter = new ReadThrottleFilterBuilder();
- readfilter.setMaximumConnectionBufferSize(BUFFER_READ_LIMIT_SIZE);
- readfilter.attach(chain);
-
- WriteBufferLimitFilterBuilder writefilter = new WriteBufferLimitFilterBuilder();
- writefilter.setMaximumConnectionBufferSize(BUFFER_WRITE_LIMIT_SIZE);
- writefilter.attach(chain);
-
- protocolSession.getFilterChain().remove("tempExecutorFilterForFilterBuilder");
- _logger.info("Using IO Read/Write Filter Protection");
- }
- catch (Exception e)
- {
- _logger.error("Unable to attach IO Read/Write Filter Protection :" + e.getMessage());
- }
- }
- }
-
- /** Separated into its own, protected, method to allow easier reuse */
- protected void createSession(IoSession session, IApplicationRegistry applicationRegistry, AMQCodecFactory codec) throws AMQException
- {
- new AMQMinaProtocolSession(session, applicationRegistry.getVirtualHostRegistry(), codec);
- }
-
- public void sessionOpened(IoSession protocolSession) throws Exception
- {
- _logger.info("Session opened for:" + protocolSession.getRemoteAddress());
- }
-
- public void sessionClosed(IoSession protocolSession) throws Exception
- {
- _logger.info("Protocol Session closed for:" + protocolSession.getRemoteAddress());
- final AMQProtocolSession amqProtocolSession = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession);
- //fixme -- this can be null
- if (amqProtocolSession != null)
- {
- try
- {
- amqProtocolSession.closeSession();
- }
- catch (AMQException e)
- {
- _logger.error("Caught AMQException whilst closingSession:" + e);
- }
- }
- }
-
- public void sessionIdle(IoSession session, IdleStatus status) throws Exception
- {
- _logger.debug("Protocol Session [" + this + "] idle: " + status + " :for:" + session.getRemoteAddress());
- if (IdleStatus.WRITER_IDLE.equals(status))
- {
- //write heartbeat frame:
- session.write(HeartbeatBody.FRAME);
- }
- else if (IdleStatus.READER_IDLE.equals(status))
- {
- //failover:
- throw new IOException("Timed out while waiting for heartbeat from peer.");
- }
-
- }
-
- public void exceptionCaught(IoSession protocolSession, Throwable throwable) throws Exception
- {
- AMQProtocolSession session = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession);
- if (throwable instanceof AMQProtocolHeaderException)
- {
-
- protocolSession.write(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion()));
-
- protocolSession.close();
-
- _logger.error("Error in protocol initiation " + session + ":" + protocolSession.getRemoteAddress() + " :" + throwable.getMessage(), throwable);
- }
- else if (throwable instanceof IOException)
- {
- _logger.error("IOException caught in" + session + ", session closed implictly: " + throwable);
- }
- else
- {
- _logger.error("Exception caught in" + session + ", closing session explictly: " + throwable, throwable);
-
-
- MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(session.getProtocolVersion());
- ConnectionCloseBody closeBody = methodRegistry.createConnectionCloseBody(200,new AMQShortString(throwable.getMessage()),0,0);
-
- protocolSession.write(closeBody.generateFrame(0));
-
- protocolSession.close();
- }
- }
-
- /**
- * Invoked when a message is received on a particular protocol session. Note that a
- * protocol session is directly tied to a particular physical connection.
- *
- * @param protocolSession the protocol session that received the message
- * @param message the message itself (i.e. a decoded frame)
- *
- * @throws Exception if the message cannot be processed
- */
- public void messageReceived(IoSession protocolSession, Object message) throws Exception
- {
- final AMQProtocolSession amqProtocolSession = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession);
-
- if (message instanceof AMQDataBlock)
- {
- amqProtocolSession.dataBlockReceived((AMQDataBlock) message);
-
- }
- else if (message instanceof ByteBuffer)
- {
- throw new IllegalStateException("Handed undecoded ByteBuffer buf = " + message);
- }
- else
- {
- throw new IllegalStateException("Handed unhandled message. message.class = " + message.getClass() + " message = " + message);
- }
- }
-
- /**
- * Called after a message has been sent out on a particular protocol session
- *
- * @param protocolSession the protocol session (i.e. connection) on which this
- * message was sent
- * @param object the message (frame) that was encoded and sent
- *
- * @throws Exception if we want to indicate an error
- */
- public void messageSent(IoSession protocolSession, Object object) throws Exception
- {
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Message sent: " + object);
- }
- }
-
- protected boolean isSSLClient(ConnectorConfiguration connectionConfig,
- IoSession protocolSession)
- {
- InetSocketAddress addr = (InetSocketAddress) protocolSession.getLocalAddress();
- return addr.getPort() == connectionConfig.sslPort;
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java
deleted file mode 100644
index 07c153bfe8..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java
+++ /dev/null
@@ -1,52 +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.
- *
- */
-package org.apache.qpid.server.protocol;
-
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.registry.IApplicationRegistry;
-
-/**
- * The protocol provide's role is to encapsulate the initialisation of the protocol handler.
- *
- * The protocol handler (see AMQPFastProtocolHandler class) handles protocol events
- * such as connection closing or a frame being received. It can either do this directly
- * or pass off to the protocol session in the cases where state information is required to
- * deal with the event.
- *
- */
-public class AMQPProtocolProvider
-{
- /**
- * Handler for protocol events
- */
- private AMQPFastProtocolHandler _handler;
-
- public AMQPProtocolProvider()
- {
- IApplicationRegistry registry = ApplicationRegistry.getInstance();
- _handler = new AMQPFastProtocolHandler(registry);
- }
-
- public AMQPFastProtocolHandler getHandler()
- {
- return _handler;
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
new file mode 100644
index 0000000000..ea8fbbd68f
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
@@ -0,0 +1,1070 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.protocol;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicMarkableReference;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.management.JMException;
+import javax.security.sasl.SaslServer;
+
+import org.apache.log4j.Logger;
+import org.apache.mina.transport.vmpipe.VmPipeAddress;
+import org.apache.qpid.AMQChannelException;
+import org.apache.qpid.AMQConnectionException;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.codec.AMQCodecFactory;
+import org.apache.qpid.codec.AMQDecoder;
+import org.apache.qpid.common.ClientProperties;
+import org.apache.qpid.framing.AMQBody;
+import org.apache.qpid.framing.AMQDataBlock;
+import org.apache.qpid.framing.AMQFrame;
+import org.apache.qpid.framing.AMQMethodBody;
+import org.apache.qpid.framing.AMQProtocolHeaderException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ChannelCloseOkBody;
+import org.apache.qpid.framing.ConnectionCloseBody;
+import org.apache.qpid.framing.ContentBody;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.HeartbeatBody;
+import org.apache.qpid.framing.MethodDispatcher;
+import org.apache.qpid.framing.MethodRegistry;
+import org.apache.qpid.framing.ProtocolInitiation;
+import org.apache.qpid.framing.ProtocolVersion;
+import org.apache.qpid.pool.Job;
+import org.apache.qpid.pool.ReferenceCountingExecutorService;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.protocol.AMQMethodEvent;
+import org.apache.qpid.protocol.AMQMethodListener;
+import org.apache.qpid.protocol.ProtocolEngine;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.handler.ServerMethodDispatcherImpl;
+import org.apache.qpid.server.logging.LogActor;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.logging.actors.AMQPConnectionActor;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.messages.ConnectionMessages;
+import org.apache.qpid.server.logging.subjects.ConnectionLogSubject;
+import org.apache.qpid.server.management.Managable;
+import org.apache.qpid.server.management.ManagedObject;
+import org.apache.qpid.server.output.ProtocolOutputConverter;
+import org.apache.qpid.server.output.ProtocolOutputConverterRegistry;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.state.AMQState;
+import org.apache.qpid.server.state.AMQStateManager;
+import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.transport.NetworkDriver;
+import org.apache.qpid.transport.Sender;
+
+public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocolSession
+{
+ private static final Logger _logger = Logger.getLogger(AMQProtocolEngine.class);
+
+ private static final String CLIENT_PROPERTIES_INSTANCE = ClientProperties.instance.toString();
+
+ private static final AtomicLong idGenerator = new AtomicLong(0);
+
+ // to save boxing the channelId and looking up in a map... cache in an array the low numbered
+ // channels. This value must be of the form 2^x - 1.
+ private static final int CHANNEL_CACHE_SIZE = 0xff;
+
+ private AMQShortString _contextKey;
+
+ private AMQShortString _clientVersion = null;
+
+ private VirtualHost _virtualHost;
+
+ private final Map<Integer, AMQChannel> _channelMap = new HashMap<Integer, AMQChannel>();
+
+ private final AMQChannel[] _cachedChannels = new AMQChannel[CHANNEL_CACHE_SIZE + 1];
+
+ private final CopyOnWriteArraySet<AMQMethodListener> _frameListeners = new CopyOnWriteArraySet<AMQMethodListener>();
+
+ private final AMQStateManager _stateManager;
+
+ private AMQCodecFactory _codecFactory;
+
+ private AMQProtocolSessionMBean _managedObject;
+
+ private SaslServer _saslServer;
+
+ private Object _lastReceived;
+
+ private Object _lastSent;
+
+ protected volatile boolean _closed;
+ // maximum number of channels this session should have
+ private long _maxNoOfChannels = 1000;
+
+ /* AMQP Version for this session */
+ private ProtocolVersion _protocolVersion = ProtocolVersion.getLatestSupportedVersion();
+
+ private FieldTable _clientProperties;
+ private final List<Task> _taskList = new CopyOnWriteArrayList<Task>();
+
+ private Map<Integer, Long> _closingChannelsList = new ConcurrentHashMap<Integer, Long>();
+ private ProtocolOutputConverter _protocolOutputConverter;
+ private Principal _authorizedID;
+ private MethodDispatcher _dispatcher;
+ private ProtocolSessionIdentifier _sessionIdentifier;
+
+ // Create a simple ID that increments for ever new Session
+ private final long _sessionID = idGenerator.getAndIncrement();
+
+ private AMQPConnectionActor _actor;
+ private LogSubject _logSubject;
+
+ private NetworkDriver _networkDriver;
+
+ private long _lastIoTime;
+
+ private long _writtenBytes;
+ private long _readBytes;
+
+ private Job _readJob;
+ private Job _writeJob;
+
+ private ReferenceCountingExecutorService _poolReference = ReferenceCountingExecutorService.getInstance();
+ private long _maxFrameSize;
+ private final AtomicBoolean _closing = new AtomicBoolean(false);
+
+ public ManagedObject getManagedObject()
+ {
+ return _managedObject;
+ }
+
+ public AMQProtocolEngine(VirtualHostRegistry virtualHostRegistry, NetworkDriver driver)
+ {
+ _stateManager = new AMQStateManager(virtualHostRegistry, this);
+ _networkDriver = driver;
+
+ _codecFactory = new AMQCodecFactory(true, this);
+ _poolReference.acquireExecutorService();
+ _readJob = new Job(_poolReference, Job.MAX_JOB_EVENTS, true);
+ _writeJob = new Job(_poolReference, Job.MAX_JOB_EVENTS, false);
+
+ _actor = new AMQPConnectionActor(this, virtualHostRegistry.getApplicationRegistry().getRootMessageLogger());
+
+ _logSubject = new ConnectionLogSubject(this);
+
+ _actor.message(ConnectionMessages.CON_OPEN(null, null, false, false));
+
+ }
+
+ private AMQProtocolSessionMBean createMBean() throws JMException
+ {
+ return new AMQProtocolSessionMBean(this);
+ }
+
+ public long getSessionID()
+ {
+ return _sessionID;
+ }
+
+ public LogActor getLogActor()
+ {
+ return _actor;
+ }
+
+ public void setMaxFrameSize(long frameMax)
+ {
+ _maxFrameSize = frameMax;
+ }
+
+ public long getMaxFrameSize()
+ {
+ return _maxFrameSize;
+ }
+
+ public boolean isClosing()
+ {
+ return _closing.get();
+ }
+
+ public void received(final ByteBuffer msg)
+ {
+ _lastIoTime = System.currentTimeMillis();
+ try
+ {
+ final ArrayList<AMQDataBlock> dataBlocks = _codecFactory.getDecoder().decodeBuffer(msg);
+ Job.fireAsynchEvent(_poolReference.getPool(), _readJob, new Runnable()
+ {
+ public void run()
+ {
+ // Decode buffer
+
+ for (AMQDataBlock dataBlock : dataBlocks)
+ {
+ try
+ {
+ dataBlockReceived(dataBlock);
+ }
+ catch (Exception e)
+ {
+ _logger.error("Unexpected exception when processing datablock", e);
+ closeProtocolSession();
+ }
+ }
+ }
+ });
+ }
+ catch (Exception e)
+ {
+ _logger.error("Unexpected exception when processing datablock", e);
+ closeProtocolSession();
+ }
+ }
+
+ public void dataBlockReceived(AMQDataBlock message) throws Exception
+ {
+ _lastReceived = message;
+ if (message instanceof ProtocolInitiation)
+ {
+ protocolInitiationReceived((ProtocolInitiation) message);
+
+ }
+ else if (message instanceof AMQFrame)
+ {
+ AMQFrame frame = (AMQFrame) message;
+ frameReceived(frame);
+
+ }
+ else
+ {
+ throw new UnknnownMessageTypeException(message);
+ }
+ }
+
+ private void frameReceived(AMQFrame frame) throws AMQException
+ {
+ int channelId = frame.getChannel();
+ AMQBody body = frame.getBodyFrame();
+
+ //Look up the Channel's Actor and set that as the current actor
+ // If that is not available then we can use the ConnectionActor
+ // that is associated with this AMQMPSession.
+ LogActor channelActor = null;
+ if (_channelMap.get(channelId) != null)
+ {
+ channelActor = _channelMap.get(channelId).getLogActor();
+ }
+ CurrentActor.set(channelActor == null ? _actor : channelActor);
+
+ try
+ {
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Frame Received: " + frame);
+ }
+
+ // Check that this channel is not closing
+ if (channelAwaitingClosure(channelId))
+ {
+ if ((frame.getBodyFrame() instanceof ChannelCloseOkBody))
+ {
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Channel[" + channelId + "] awaiting closure - processing close-ok");
+ }
+ }
+ else
+ {
+ // The channel has been told to close, we don't process any more frames until
+ // it's closed.
+ return;
+ }
+ }
+
+ try
+ {
+ body.handle(channelId, this);
+ }
+ catch (AMQException e)
+ {
+ closeChannel(channelId);
+ throw e;
+ }
+ }
+ finally
+ {
+ CurrentActor.remove();
+ }
+ }
+
+ private void protocolInitiationReceived(ProtocolInitiation pi)
+ {
+ // this ensures the codec never checks for a PI message again
+ ((AMQDecoder) _codecFactory.getDecoder()).setExpectProtocolInitiation(false);
+ try
+ {
+ // Log incomming protocol negotiation request
+ _actor.message(ConnectionMessages.CON_OPEN(null, pi._protocolMajor + "-" + pi._protocolMinor, false, true));
+
+ ProtocolVersion pv = pi.checkVersion(); // Fails if not correct
+
+ // This sets the protocol version (and hence framing classes) for this session.
+ setProtocolVersion(pv);
+
+ String mechanisms = ApplicationRegistry.getInstance().getAuthenticationManager().getMechanisms();
+
+ String locales = "en_US";
+
+ AMQMethodBody responseBody = getMethodRegistry().createConnectionStartBody((short) getProtocolMajorVersion(),
+ (short) pv.getActualMinorVersion(),
+ null,
+ mechanisms.getBytes(),
+ locales.getBytes());
+ _networkDriver.send(responseBody.generateFrame(0).toNioByteBuffer());
+
+ }
+ catch (AMQException e)
+ {
+ _logger.info("Received unsupported protocol initiation for protocol version: " + getProtocolVersion());
+
+ _networkDriver.send(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion()).toNioByteBuffer());
+ }
+ }
+
+ public void methodFrameReceived(int channelId, AMQMethodBody methodBody)
+ {
+
+ final AMQMethodEvent<AMQMethodBody> evt = new AMQMethodEvent<AMQMethodBody>(channelId, methodBody);
+
+ try
+ {
+ try
+ {
+
+ boolean wasAnyoneInterested = _stateManager.methodReceived(evt);
+
+ if (!_frameListeners.isEmpty())
+ {
+ for (AMQMethodListener listener : _frameListeners)
+ {
+ wasAnyoneInterested = listener.methodReceived(evt) || wasAnyoneInterested;
+ }
+ }
+
+ if (!wasAnyoneInterested)
+ {
+ throw new AMQNoMethodHandlerException(evt);
+ }
+ }
+ catch (AMQChannelException e)
+ {
+ if (getChannel(channelId) != null)
+ {
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Closing channel due to: " + e.getMessage());
+ }
+
+ writeFrame(e.getCloseFrame(channelId));
+ closeChannel(channelId);
+ }
+ else
+ {
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("ChannelException occured on non-existent channel:" + e.getMessage());
+ }
+
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Closing connection due to: " + e.getMessage());
+ }
+
+ AMQConnectionException ce =
+ evt.getMethod().getConnectionException(AMQConstant.CHANNEL_ERROR,
+ AMQConstant.CHANNEL_ERROR.getName().toString());
+
+ closeConnection(channelId, ce, false);
+ }
+ }
+ catch (AMQConnectionException e)
+ {
+ closeConnection(channelId, e, false);
+ }
+ }
+ catch (Exception e)
+ {
+
+ for (AMQMethodListener listener : _frameListeners)
+ {
+ listener.error(e);
+ }
+
+ _logger.error("Unexpected exception while processing frame. Closing connection.", e);
+
+ closeProtocolSession();
+ }
+ }
+
+ public void contentHeaderReceived(int channelId, ContentHeaderBody body) throws AMQException
+ {
+
+ AMQChannel channel = getAndAssertChannel(channelId);
+
+ channel.publishContentHeader(body);
+
+ }
+
+ public void contentBodyReceived(int channelId, ContentBody body) throws AMQException
+ {
+ AMQChannel channel = getAndAssertChannel(channelId);
+
+ channel.publishContentBody(body);
+ }
+
+ public void heartbeatBodyReceived(int channelId, HeartbeatBody body)
+ {
+ // NO - OP
+ }
+
+ /**
+ * Convenience method that writes a frame to the protocol session. Equivalent to calling
+ * getProtocolSession().write().
+ *
+ * @param frame the frame to write
+ */
+ public void writeFrame(AMQDataBlock frame)
+ {
+ _lastSent = frame;
+ final ByteBuffer buf = frame.toNioByteBuffer();
+ _lastIoTime = System.currentTimeMillis();
+ _writtenBytes += buf.remaining();
+ Job.fireAsynchEvent(_poolReference.getPool(), _writeJob, new Runnable()
+ {
+ public void run()
+ {
+ _networkDriver.send(buf);
+ }
+ });
+ }
+
+ public AMQShortString getContextKey()
+ {
+ return _contextKey;
+ }
+
+ public void setContextKey(AMQShortString contextKey)
+ {
+ _contextKey = contextKey;
+ }
+
+ public List<AMQChannel> getChannels()
+ {
+ return new ArrayList<AMQChannel>(_channelMap.values());
+ }
+
+ public AMQChannel getAndAssertChannel(int channelId) throws AMQException
+ {
+ AMQChannel channel = getChannel(channelId);
+ if (channel == null)
+ {
+ throw new AMQException(AMQConstant.NOT_FOUND, "Channel not found with id:" + channelId);
+ }
+
+ return channel;
+ }
+
+ public AMQChannel getChannel(int channelId) throws AMQException
+ {
+ final AMQChannel channel =
+ ((channelId & CHANNEL_CACHE_SIZE) == channelId) ? _cachedChannels[channelId] : _channelMap.get(channelId);
+ if ((channel == null) || channel.isClosing())
+ {
+ return null;
+ }
+ else
+ {
+ return channel;
+ }
+ }
+
+ public boolean channelAwaitingClosure(int channelId)
+ {
+ return !_closingChannelsList.isEmpty() && _closingChannelsList.containsKey(channelId);
+ }
+
+ public void addChannel(AMQChannel channel) throws AMQException
+ {
+ if (_closed)
+ {
+ throw new AMQException("Session is closed");
+ }
+
+ final int channelId = channel.getChannelId();
+
+ if (_closingChannelsList.containsKey(channelId))
+ {
+ throw new AMQException("Session is marked awaiting channel close");
+ }
+
+ if (_channelMap.size() == _maxNoOfChannels)
+ {
+ String errorMessage =
+ toString() + ": maximum number of channels has been reached (" + _maxNoOfChannels
+ + "); can't create channel";
+ _logger.error(errorMessage);
+ throw new AMQException(AMQConstant.NOT_ALLOWED, errorMessage);
+ }
+ else
+ {
+ _channelMap.put(channel.getChannelId(), channel);
+ }
+
+ if (((channelId & CHANNEL_CACHE_SIZE) == channelId))
+ {
+ _cachedChannels[channelId] = channel;
+ }
+
+ checkForNotification();
+ }
+
+ private void checkForNotification()
+ {
+ int channelsCount = _channelMap.size();
+ if (_managedObject != null && channelsCount >= _maxNoOfChannels)
+ {
+ _managedObject.notifyClients("Channel count (" + channelsCount + ") has reached the threshold value");
+ }
+ }
+
+ public Long getMaximumNumberOfChannels()
+ {
+ return _maxNoOfChannels;
+ }
+
+ public void setMaximumNumberOfChannels(Long value)
+ {
+ _maxNoOfChannels = value;
+ }
+
+ public void commitTransactions(AMQChannel channel) throws AMQException
+ {
+ if ((channel != null) && channel.isTransactional())
+ {
+ channel.commit();
+ }
+ }
+
+ public void rollbackTransactions(AMQChannel channel) throws AMQException
+ {
+ if ((channel != null) && channel.isTransactional())
+ {
+ channel.rollback();
+ }
+ }
+
+ /**
+ * Close a specific channel. This will remove any resources used by the channel, including: <ul><li>any queue
+ * subscriptions (this may in turn remove queues if they are auto delete</li> </ul>
+ *
+ * @param channelId id of the channel to close
+ *
+ * @throws AMQException if an error occurs closing the channel
+ * @throws IllegalArgumentException if the channel id is not valid
+ */
+ public void closeChannel(int channelId) throws AMQException
+ {
+ final AMQChannel channel = getChannel(channelId);
+ if (channel == null)
+ {
+ throw new IllegalArgumentException("Unknown channel id");
+ }
+ else
+ {
+ try
+ {
+ channel.close();
+ markChannelAwaitingCloseOk(channelId);
+ }
+ finally
+ {
+ removeChannel(channelId);
+ }
+ }
+ }
+
+ public void closeChannelOk(int channelId)
+ {
+ // todo QPID-847 - This is called from two lcoations ChannelCloseHandler and ChannelCloseOkHandler.
+ // When it is the CC_OK_Handler then it makes sence to remove the channel else we will leak memory.
+ // We do it from the Close Handler as we are sending the OK back to the client.
+ // While this is AMQP spec compliant. The Java client in the event of an IllegalArgumentException
+ // will send a close-ok.. Where we should call removeChannel.
+ // However, due to the poor exception handling on the client. The client-user will be notified of the
+ // InvalidArgument and if they then decide to close the session/connection then the there will be time
+ // for that to occur i.e. a new close method be sent before the exeption handling can mark the session closed.
+ //removeChannel(channelId);
+ _closingChannelsList.remove(new Integer(channelId));
+ }
+
+ private void markChannelAwaitingCloseOk(int channelId)
+ {
+ _closingChannelsList.put(channelId, System.currentTimeMillis());
+ }
+
+ /**
+ * In our current implementation this is used by the clustering code.
+ *
+ * @param channelId The channel to remove
+ */
+ public void removeChannel(int channelId)
+ {
+ _channelMap.remove(channelId);
+ if ((channelId & CHANNEL_CACHE_SIZE) == channelId)
+ {
+ _cachedChannels[channelId] = null;
+ }
+ }
+
+ /**
+ * Initialise heartbeats on the session.
+ *
+ * @param delay delay in seconds (not ms)
+ */
+ public void initHeartbeats(int delay)
+ {
+ if (delay > 0)
+ {
+ _networkDriver.setMaxWriteIdle(delay);
+ _networkDriver.setMaxReadIdle((int) (ApplicationRegistry.getInstance().getConfiguration().getHeartBeatTimeout() * delay));
+ }
+ }
+
+ /**
+ * Closes all channels that were opened by this protocol session. This frees up all resources used by the channel.
+ *
+ * @throws AMQException if an error occurs while closing any channel
+ */
+ private void closeAllChannels() throws AMQException
+ {
+ for (AMQChannel channel : _channelMap.values())
+ {
+ channel.close();
+ }
+
+ _channelMap.clear();
+ for (int i = 0; i <= CHANNEL_CACHE_SIZE; i++)
+ {
+ _cachedChannels[i] = null;
+ }
+ }
+
+ /** This must be called when the session is _closed in order to free up any resources managed by the session. */
+ public void closeSession() throws AMQException
+ {
+ if(_closing.compareAndSet(false,true))
+ {
+ // REMOVE THIS SHOULD NOT BE HERE.
+ if (CurrentActor.get() == null)
+ {
+ CurrentActor.set(_actor);
+ }
+ if (!_closed)
+ {
+ if (_virtualHost != null)
+ {
+ _virtualHost.getConnectionRegistry().deregisterConnection(this);
+ }
+
+ closeAllChannels();
+ if (_managedObject != null)
+ {
+ _managedObject.unregister();
+ // Ensure we only do this once.
+ _managedObject = null;
+ }
+
+ for (Task task : _taskList)
+ {
+ task.doTask(this);
+ }
+
+ synchronized(this)
+ {
+ _closed = true;
+ notifyAll();
+ }
+ _poolReference.releaseExecutorService();
+ CurrentActor.get().message(_logSubject, ConnectionMessages.CON_CLOSE());
+ }
+ }
+ else
+ {
+ synchronized(this)
+ {
+ while(!_closed)
+ {
+ try
+ {
+ wait(1000);
+ }
+ catch (InterruptedException e)
+ {
+
+ }
+ }
+ }
+ }
+ }
+
+ public void closeConnection(int channelId, AMQConnectionException e, boolean closeProtocolSession) throws AMQException
+ {
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Closing connection due to: " + e.getMessage());
+ }
+
+ markChannelAwaitingCloseOk(channelId);
+ closeSession();
+ _stateManager.changeState(AMQState.CONNECTION_CLOSING);
+ writeFrame(e.getCloseFrame(channelId));
+
+ if (closeProtocolSession)
+ {
+ closeProtocolSession();
+ }
+ }
+
+ public void closeProtocolSession()
+ {
+ _networkDriver.close();
+ try
+ {
+ _stateManager.changeState(AMQState.CONNECTION_CLOSED);
+ }
+ catch (AMQException e)
+ {
+ _logger.info(e.getMessage());
+ }
+ }
+
+ public String toString()
+ {
+ return getRemoteAddress() + "(" + (getAuthorizedID() == null ? "?" : getAuthorizedID().getName() + ")");
+ }
+
+ public String dump()
+ {
+ return this + " last_sent=" + _lastSent + " last_received=" + _lastReceived;
+ }
+
+ /** @return an object that can be used to identity */
+ public Object getKey()
+ {
+ return getRemoteAddress();
+ }
+
+ /**
+ * Get the fully qualified domain name of the local address to which this session is bound. Since some servers may
+ * be bound to multiple addresses this could vary depending on the acceptor this session was created from.
+ *
+ * @return a String FQDN
+ */
+ public String getLocalFQDN()
+ {
+ SocketAddress address = _networkDriver.getLocalAddress();
+ // we use the vmpipe address in some tests hence the need for this rather ugly test. The host
+ // information is used by SASL primary.
+ if (address instanceof InetSocketAddress)
+ {
+ return ((InetSocketAddress) address).getHostName();
+ }
+ else if (address instanceof VmPipeAddress)
+ {
+ return "vmpipe:" + ((VmPipeAddress) address).getPort();
+ }
+ else
+ {
+ throw new IllegalArgumentException("Unsupported socket address class: " + address);
+ }
+ }
+
+ public SaslServer getSaslServer()
+ {
+ return _saslServer;
+ }
+
+ public void setSaslServer(SaslServer saslServer)
+ {
+ _saslServer = saslServer;
+ }
+
+ public FieldTable getClientProperties()
+ {
+ return _clientProperties;
+ }
+
+ public void setClientProperties(FieldTable clientProperties)
+ {
+ _clientProperties = clientProperties;
+ if (_clientProperties != null)
+ {
+ if (_clientProperties.getString(CLIENT_PROPERTIES_INSTANCE) != null)
+ {
+ String clientID = _clientProperties.getString(CLIENT_PROPERTIES_INSTANCE);
+ setContextKey(new AMQShortString(clientID));
+
+ // Log the Opening of the connection for this client
+ _actor.message(ConnectionMessages.CON_OPEN(clientID, _protocolVersion.toString(), true, true));
+ }
+
+ if (_clientProperties.getString(ClientProperties.version.toString()) != null)
+ {
+ _clientVersion = new AMQShortString(_clientProperties.getString(ClientProperties.version.toString()));
+ }
+ }
+ _sessionIdentifier = new ProtocolSessionIdentifier(this);
+ }
+
+ private void setProtocolVersion(ProtocolVersion pv)
+ {
+ _protocolVersion = pv;
+
+ _protocolOutputConverter = ProtocolOutputConverterRegistry.getConverter(this);
+ _dispatcher = ServerMethodDispatcherImpl.createMethodDispatcher(_stateManager, _protocolVersion);
+ }
+
+ public byte getProtocolMajorVersion()
+ {
+ return _protocolVersion.getMajorVersion();
+ }
+
+ public ProtocolVersion getProtocolVersion()
+ {
+ return _protocolVersion;
+ }
+
+ public byte getProtocolMinorVersion()
+ {
+ return _protocolVersion.getMinorVersion();
+ }
+
+ public boolean isProtocolVersion(byte major, byte minor)
+ {
+ return (getProtocolMajorVersion() == major) && (getProtocolMinorVersion() == minor);
+ }
+
+ public MethodRegistry getRegistry()
+ {
+ return getMethodRegistry();
+ }
+
+ public Object getClientIdentifier()
+ {
+ return (_networkDriver != null) ? _networkDriver.getRemoteAddress() : null;
+ }
+
+ public VirtualHost getVirtualHost()
+ {
+ return _virtualHost;
+ }
+
+ public void setVirtualHost(VirtualHost virtualHost) throws AMQException
+ {
+ _virtualHost = virtualHost;
+
+ _virtualHost.getConnectionRegistry().registerConnection(this);
+
+ try
+ {
+ _managedObject = createMBean();
+ _managedObject.register();
+ }
+ catch (JMException e)
+ {
+ _logger.error(e);
+ }
+ }
+
+ public void addSessionCloseTask(Task task)
+ {
+ _taskList.add(task);
+ }
+
+ public void removeSessionCloseTask(Task task)
+ {
+ _taskList.remove(task);
+ }
+
+ public ProtocolOutputConverter getProtocolOutputConverter()
+ {
+ return _protocolOutputConverter;
+ }
+
+ public void setAuthorizedID(Principal authorizedID)
+ {
+ _authorizedID = authorizedID;
+ }
+
+ public Principal getAuthorizedID()
+ {
+ return _authorizedID;
+ }
+
+ public Principal getPrincipal()
+ {
+ return _authorizedID;
+ }
+
+ public SocketAddress getRemoteAddress()
+ {
+ return _networkDriver.getRemoteAddress();
+ }
+
+ public SocketAddress getLocalAddress()
+ {
+ return _networkDriver.getLocalAddress();
+ }
+
+ public MethodRegistry getMethodRegistry()
+ {
+ return MethodRegistry.getMethodRegistry(getProtocolVersion());
+ }
+
+ public MethodDispatcher getMethodDispatcher()
+ {
+ return _dispatcher;
+ }
+
+ public void closed()
+ {
+ try
+ {
+ closeSession();
+ }
+ catch (AMQException e)
+ {
+ _logger.error("Could not close protocol engine", e);
+ }
+ }
+
+ public void readerIdle()
+ {
+ // Nothing
+ }
+
+ public void setNetworkDriver(NetworkDriver driver)
+ {
+ _networkDriver = driver;
+ }
+
+ public void writerIdle()
+ {
+ _networkDriver.send(HeartbeatBody.FRAME.toNioByteBuffer());
+ }
+
+ public void exception(Throwable throwable)
+ {
+ if (throwable instanceof AMQProtocolHeaderException)
+ {
+
+ writeFrame(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion()));
+ _networkDriver.close();
+
+ _logger.error("Error in protocol initiation " + this + ":" + getRemoteAddress() + " :" + throwable.getMessage(), throwable);
+ }
+ else if (throwable instanceof IOException)
+ {
+ _logger.error("IOException caught in" + this + ", session closed implictly: " + throwable);
+ }
+ else
+ {
+ _logger.error("Exception caught in" + this + ", closing session explictly: " + throwable, throwable);
+
+
+ MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(getProtocolVersion());
+ ConnectionCloseBody closeBody = methodRegistry.createConnectionCloseBody(200,new AMQShortString(throwable.getMessage()),0,0);
+
+ writeFrame(closeBody.generateFrame(0));
+
+ _networkDriver.close();
+ }
+ }
+
+ public void init()
+ {
+ // Do nothing
+ }
+
+ public void setSender(Sender<ByteBuffer> sender)
+ {
+ // Do nothing
+ }
+
+ public long getReadBytes()
+ {
+ return _readBytes;
+ }
+
+ public long getWrittenBytes()
+ {
+ return _writtenBytes;
+ }
+
+ public long getLastIoTime()
+ {
+ return _lastIoTime;
+ }
+
+ public ProtocolSessionIdentifier getSessionIdentifier()
+ {
+ return _sessionIdentifier;
+ }
+
+ public String getClientVersion()
+ {
+ return (_clientVersion == null) ? null : _clientVersion.toString();
+ }
+
+ public void closeIfLingeringClosedChannels()
+ {
+ for (Entry<Integer, Long>id : _closingChannelsList.entrySet())
+ {
+ if (id.getValue() + 30000 > System.currentTimeMillis())
+ {
+ // We have a channel that we closed 30 seconds ago. Client's dead, kill the connection
+ _logger.error("Closing connection as channel was closed more than 30 seconds ago and no ChannelCloseOk has been processed");
+ closeProtocolSession();
+ }
+ }
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngineFactory.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngineFactory.java
new file mode 100644
index 0000000000..ff0c007a60
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngineFactory.java
@@ -0,0 +1,29 @@
+package org.apache.qpid.server.protocol;
+
+import org.apache.qpid.protocol.ProtocolEngine;
+import org.apache.qpid.protocol.ProtocolEngineFactory;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
+import org.apache.qpid.transport.NetworkDriver;
+
+public class AMQProtocolEngineFactory implements ProtocolEngineFactory
+{
+ private VirtualHostRegistry _vhosts;
+
+ public AMQProtocolEngineFactory()
+ {
+ this(1);
+ }
+
+ public AMQProtocolEngineFactory(Integer port)
+ {
+ _vhosts = ApplicationRegistry.getInstance(port).getVirtualHostRegistry();
+ }
+
+
+ public ProtocolEngine newProtocolEngine(NetworkDriver networkDriver)
+ {
+ return new AMQProtocolEngine(_vhosts, networkDriver);
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java
index 1bac601225..48dd16a98c 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -28,14 +28,26 @@ import org.apache.qpid.framing.*;
import org.apache.qpid.AMQConnectionException;
import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.security.PrincipalHolder;
+import org.apache.qpid.server.logging.LogActor;
import org.apache.qpid.server.output.ProtocolOutputConverter;
import org.apache.qpid.server.virtualhost.VirtualHost;
import java.security.Principal;
+import java.util.List;
-public interface AMQProtocolSession extends AMQVersionAwareProtocolSession
+public interface AMQProtocolSession extends AMQVersionAwareProtocolSession, PrincipalHolder
{
+ long getSessionID();
+
+ LogActor getLogActor();
+
+ void setMaxFrameSize(long frameMax);
+
+ long getMaxFrameSize();
+
+ boolean isClosing();
public static final class ProtocolSessionIdentifier
{
@@ -195,13 +207,30 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession
void setAuthorizedID(Principal authorizedID);
- /** @return a Principal that was used to authorized this session */
- Principal getAuthorizedID();
+ public java.net.SocketAddress getRemoteAddress();
public MethodRegistry getMethodRegistry();
public MethodDispatcher getMethodDispatcher();
public ProtocolSessionIdentifier getSessionIdentifier();
-
+
+ String getClientVersion();
+
+ long getLastIoTime();
+
+ long getWrittenBytes();
+
+ Long getMaximumNumberOfChannels();
+
+ void setMaximumNumberOfChannels(Long value);
+
+ void commitTransactions(AMQChannel channel) throws AMQException;
+
+ void rollbackTransactions(AMQChannel channel) throws AMQException;
+
+ List<AMQChannel> getChannels();
+
+ void closeIfLingeringClosedChannels();
+
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java
index bd072985c4..72788bdb0f 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java
@@ -37,7 +37,6 @@
*/
package org.apache.qpid.server.protocol;
-import java.security.Principal;
import java.util.Date;
import java.util.List;
@@ -58,15 +57,19 @@ import javax.management.openmbean.TabularDataSupport;
import javax.management.openmbean.TabularType;
import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQFrame;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.ConnectionCloseBody;
import org.apache.qpid.framing.MethodRegistry;
+import org.apache.qpid.management.common.mbeans.ManagedConnection;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.ManagementActor;
+import org.apache.qpid.server.logging.LogActor;
+import org.apache.qpid.server.logging.RootMessageLogger;
import org.apache.qpid.server.management.AMQManagedObject;
-import org.apache.qpid.server.management.MBeanConstructor;
-import org.apache.qpid.server.management.MBeanDescription;
import org.apache.qpid.server.management.ManagedObject;
/**
@@ -76,25 +79,23 @@ import org.apache.qpid.server.management.ManagedObject;
@MBeanDescription("Management Bean for an AMQ Broker Connection")
public class AMQProtocolSessionMBean extends AMQManagedObject implements ManagedConnection
{
- private AMQMinaProtocolSession _session = null;
+ private AMQProtocolSession _protocolSession = null;
private String _name = null;
// openmbean data types for representing the channel attributes
- private static final String[] _channelAtttibuteNames =
- { "Channel Id", "Transactional", "Default Queue", "Unacknowledged Message Count" };
- private static final String[] _indexNames = { _channelAtttibuteNames[0] };
+
private static final OpenType[] _channelAttributeTypes =
- { SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER };
+ { SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER, SimpleType.BOOLEAN };
private static CompositeType _channelType = null; // represents the data type for channel data
private static TabularType _channelsType = null; // Data type for list of channels type
private static final AMQShortString BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION =
new AMQShortString("Broker Management Console has closed the connection.");
@MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection")
- public AMQProtocolSessionMBean(AMQMinaProtocolSession session) throws NotCompliantMBeanException, OpenDataException
+ public AMQProtocolSessionMBean(AMQProtocolSession amqProtocolSession) throws NotCompliantMBeanException, OpenDataException
{
- super(ManagedConnection.class, ManagedConnection.TYPE);
- _session = session;
+ super(ManagedConnection.class, ManagedConnection.TYPE, ManagedConnection.VERSION);
+ _protocolSession = amqProtocolSession;
String remote = getRemoteAddress();
remote = "anonymous".equals(remote) ? (remote + hashCode()) : remote;
_name = jmxEncode(new StringBuffer(remote), 0).toString();
@@ -120,59 +121,59 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed
private static void init() throws OpenDataException
{
_channelType =
- new CompositeType("Channel", "Channel Details", _channelAtttibuteNames, _channelAtttibuteNames,
+ new CompositeType("Channel", "Channel Details", COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS,
_channelAttributeTypes);
- _channelsType = new TabularType("Channels", "Channels", _channelType, _indexNames);
+ _channelsType = new TabularType("Channels", "Channels", _channelType, TABULAR_UNIQUE_INDEX);
}
public String getClientId()
{
- return (_session.getContextKey() == null) ? null : _session.getContextKey().toString();
+ return (_protocolSession.getContextKey() == null) ? null : _protocolSession.getContextKey().toString();
}
public String getAuthorizedId()
{
- return (_session.getAuthorizedID() != null ) ? _session.getAuthorizedID().getName() : null;
+ return (_protocolSession.getPrincipal() != null ) ? _protocolSession.getPrincipal().getName() : null;
}
public String getVersion()
{
- return (_session.getClientVersion() == null) ? null : _session.getClientVersion().toString();
+ return (_protocolSession.getClientVersion() == null) ? null : _protocolSession.getClientVersion().toString();
}
public Date getLastIoTime()
{
- return new Date(_session.getIOSession().getLastIoTime());
+ return new Date(_protocolSession.getLastIoTime());
}
public String getRemoteAddress()
{
- return _session.getIOSession().getRemoteAddress().toString();
+ return _protocolSession.getRemoteAddress().toString();
}
public ManagedObject getParentObject()
{
- return _session.getVirtualHost().getManagedObject();
+ return _protocolSession.getVirtualHost().getManagedObject();
}
public Long getWrittenBytes()
{
- return _session.getIOSession().getWrittenBytes();
+ return _protocolSession.getWrittenBytes();
}
public Long getReadBytes()
{
- return _session.getIOSession().getReadBytes();
+ return _protocolSession.getWrittenBytes();
}
public Long getMaximumNumberOfChannels()
{
- return _session.getMaximumNumberOfChannels();
+ return _protocolSession.getMaximumNumberOfChannels();
}
public void setMaximumNumberOfChannels(Long value)
{
- _session.setMaximumNumberOfChannels(value);
+ _protocolSession.setMaximumNumberOfChannels(value);
}
public String getObjectInstanceName()
@@ -188,20 +189,25 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed
*/
public void commitTransactions(int channelId) throws JMException
{
+ CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger()));
try
{
- AMQChannel channel = _session.getChannel(channelId);
+ AMQChannel channel = _protocolSession.getChannel(channelId);
if (channel == null)
{
throw new JMException("The channel (channel Id = " + channelId + ") does not exist");
}
- _session.commitTransactions(channel);
+ _protocolSession.commitTransactions(channel);
}
catch (AMQException ex)
{
throw new MBeanException(ex, ex.toString());
}
+ finally
+ {
+ CurrentActor.remove();
+ }
}
/**
@@ -212,20 +218,25 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed
*/
public void rollbackTransactions(int channelId) throws JMException
{
+ CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger()));
try
{
- AMQChannel channel = _session.getChannel(channelId);
+ AMQChannel channel = _protocolSession.getChannel(channelId);
if (channel == null)
{
throw new JMException("The channel (channel Id = " + channelId + ") does not exist");
}
- _session.rollbackTransactions(channel);
+ _protocolSession.rollbackTransactions(channel);
}
catch (AMQException ex)
{
throw new MBeanException(ex, ex.toString());
}
+ finally
+ {
+ CurrentActor.remove();
+ }
}
/**
@@ -237,7 +248,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed
public TabularData channels() throws OpenDataException
{
TabularDataSupport channelsList = new TabularDataSupport(_channelsType);
- List<AMQChannel> list = _session.getChannels();
+ List<AMQChannel> list = _protocolSession.getChannels();
for (AMQChannel channel : list)
{
@@ -245,10 +256,10 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed
{
channel.getChannelId(), channel.isTransactional(),
(channel.getDefaultQueue() != null) ? channel.getDefaultQueue().getName().asString() : null,
- channel.getUnacknowledgedMessageMap().size()
+ channel.getUnacknowledgedMessageMap().size(), channel.getBlocking()
};
- CompositeData channelData = new CompositeDataSupport(_channelType, _channelAtttibuteNames, itemValues);
+ CompositeData channelData = new CompositeDataSupport(_channelType, COMPOSITE_ITEM_NAMES, itemValues);
channelsList.put(channelData);
}
@@ -263,7 +274,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed
public void closeConnection() throws JMException
{
- MethodRegistry methodRegistry = _session.getMethodRegistry();
+ MethodRegistry methodRegistry = _protocolSession.getMethodRegistry();
ConnectionCloseBody responseBody =
methodRegistry.createConnectionCloseBody(AMQConstant.REPLY_SUCCESS.getCode(),
// replyCode
@@ -272,15 +283,42 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed
0,
0);
- _session.writeFrame(responseBody.generateFrame(0));
+ // This seems ugly but because we use closeConnection in both normal
+ // broker operation and as part of the management interface it cannot
+ // be avoided. The Current Actor will be null when this method is
+ // called via the Management interface. This is because we allow the
+ // Local API connection with JConsole. If we did not allow that option
+ // then the CurrentActor could be set in our JMX Proxy object.
+ // As it is we need to set the CurrentActor on all MBean methods
+ // Ideally we would not have a single method that can be called from
+ // two contexts.
+ boolean removeActor = false;
+ if (CurrentActor.get() == null)
+ {
+ removeActor = true;
+ CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger()));
+ }
try
{
- _session.closeSession();
+ _protocolSession.writeFrame(responseBody.generateFrame(0));
+
+ try
+ {
+
+ _protocolSession.closeSession();
+ }
+ catch (AMQException ex)
+ {
+ throw new MBeanException(ex, ex.toString());
+ }
}
- catch (AMQException ex)
+ finally
{
- throw new MBeanException(ex, ex.toString());
+ if (removeActor)
+ {
+ CurrentActor.remove();
+ }
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java
deleted file mode 100644
index 2abcecb6de..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java
+++ /dev/null
@@ -1,51 +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.
- *
- */
-package org.apache.qpid.server.protocol;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.exchange.ExchangeDefaults;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.exchange.ExchangeFactory;
-import org.apache.qpid.server.exchange.ExchangeRegistry;
-import org.apache.qpid.server.exchange.ExchangeType;
-
-public class ExchangeInitialiser
-{
- public void initialise(ExchangeFactory factory, ExchangeRegistry registry) throws AMQException{
- for (ExchangeType<? extends Exchange> type : factory.getRegisteredTypes())
- {
- define (registry, factory, type.getDefaultExchangeName(), type.getName());
- }
-
- define(registry, factory, ExchangeDefaults.DEFAULT_EXCHANGE_NAME, ExchangeDefaults.DIRECT_EXCHANGE_CLASS);
- registry.setDefaultExchange(registry.getExchange(ExchangeDefaults.DEFAULT_EXCHANGE_NAME));
- }
-
- private void define(ExchangeRegistry r, ExchangeFactory f,
- AMQShortString name, AMQShortString type) throws AMQException
- {
- if(r.getExchange(name)== null)
- {
- r.registerExchange(f.createExchange(name, type, true, false, 0));
- }
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/HeartbeatConfig.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/HeartbeatConfig.java
deleted file mode 100644
index 310deaaf55..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/protocol/HeartbeatConfig.java
+++ /dev/null
@@ -1,67 +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.
- *
- */
-package org.apache.qpid.server.protocol;
-
-import org.apache.qpid.configuration.Configured;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-
-public class HeartbeatConfig
-{
- @Configured(path = "heartbeat.delay", defaultValue = "5")
- public int delay = 5;//in secs
- @Configured(path = "heartbeat.timeoutFactor", defaultValue = "2.0")
- public double timeoutFactor = 2;
-
- public double getTimeoutFactor()
- {
- return timeoutFactor;
- }
-
- public void setTimeoutFactor(double timeoutFactor)
- {
- this.timeoutFactor = timeoutFactor;
- }
-
- public int getDelay()
- {
- return delay;
- }
-
- public void setDelay(int delay)
- {
- this.delay = delay;
- }
-
- int getTimeout(int writeDelay)
- {
- return (int) (timeoutFactor * writeDelay);
- }
-
- public static HeartbeatConfig getInstance()
- {
- return ApplicationRegistry.getInstance().getConfiguredObject(HeartbeatConfig.class);
- }
-
- public String toString()
- {
- return "HeartBeatConfig{delay = " + delay + " timeoutFactor = " + timeoutFactor + "}";
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java
deleted file mode 100644
index e6e713ac6d..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java
+++ /dev/null
@@ -1,135 +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.
- *
- */
-
-package org.apache.qpid.server.protocol;
-
-import java.io.IOException;
-import java.util.Date;
-import java.security.Principal;
-
-import javax.management.JMException;
-import javax.management.MBeanOperationInfo;
-import javax.management.openmbean.TabularData;
-
-import org.apache.qpid.server.management.MBeanAttribute;
-import org.apache.qpid.server.management.MBeanOperation;
-import org.apache.qpid.server.management.MBeanOperationParameter;
-
-/**
- * The management interface exposed to allow management of Connections.
- * @author Bhupendra Bhardwaj
- * @version 0.1
- */
-public interface ManagedConnection
-{
- static final String TYPE = "Connection";
-
- @MBeanAttribute(name = "ClientId", description = "Client Id")
- String getClientId();
-
- @MBeanAttribute(name = "AuthorizedId", description = "User Name")
- String getAuthorizedId();
-
- @MBeanAttribute(name = "Version", description = "Client Version")
- String getVersion();
-
- /**
- * Tells the remote address of this connection.
- * @return remote address
- */
- @MBeanAttribute(name="RemoteAddress", description=TYPE + " Address")
- String getRemoteAddress();
-
- /**
- * Tells the last time, the IO operation was done.
- * @return last IO time.
- */
- @MBeanAttribute(name="LastIOTime", description="The last time, the IO operation was done")
- Date getLastIoTime();
-
- /**
- * Tells the total number of bytes written till now.
- * @return number of bytes written.
- *
- @MBeanAttribute(name="WrittenBytes", description="The total number of bytes written till now")
- Long getWrittenBytes();
- */
- /**
- * Tells the total number of bytes read till now.
- * @return number of bytes read.
- *
- @MBeanAttribute(name="ReadBytes", description="The total number of bytes read till now")
- Long getReadBytes();
- */
-
- /**
- * Threshold high value for no of channels. This is useful in setting notifications or
- * taking required action is there are more channels being created.
- * @return threshold limit for no of channels
- */
- Long getMaximumNumberOfChannels();
-
- /**
- * Sets the threshold high value for number of channels for a connection
- * @param value
- */
- @MBeanAttribute(name="MaximumNumberOfChannels", description="The threshold high value for number of channels for this connection")
- void setMaximumNumberOfChannels(Long value);
-
- //********** Operations *****************//
-
- /**
- * channel details of all the channels opened for this connection.
- * @return general channel details
- * @throws IOException
- * @throws JMException
- */
- @MBeanOperation(name="channels", description="Channel details for this connection")
- TabularData channels() throws IOException, JMException;
-
- /**
- * Commits the transactions if the channel is transactional.
- * @param channelId
- * @throws JMException
- */
- @MBeanOperation(name="commitTransaction",
- description="Commits the transactions for given channel Id, if the channel is transactional",
- impact= MBeanOperationInfo.ACTION)
- void commitTransactions(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) throws JMException;
-
- /**
- * Rollsback the transactions if the channel is transactional.
- * @param channelId
- * @throws JMException
- */
- @MBeanOperation(name="rollbackTransactions",
- description="Rollsback the transactions for given channel Id, if the channel is transactional",
- impact= MBeanOperationInfo.ACTION)
- void rollbackTransactions(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) throws JMException;
-
- /**
- * Closes all the related channels and unregisters this connection from managed objects.
- */
- @MBeanOperation(name="closeConnection",
- description="Closes this connection and all related channels",
- impact= MBeanOperationInfo.ACTION)
- void closeConnection() throws Exception;
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java
new file mode 100755
index 0000000000..9a1c6c9418
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java
@@ -0,0 +1,425 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+package org.apache.qpid.server.protocol;
+
+import org.apache.qpid.protocol.ProtocolEngine;
+import org.apache.qpid.server.registry.IApplicationRegistry;
+import org.apache.qpid.transport.NetworkDriver;
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.ConnectionDelegate;
+import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory.VERSION;
+import org.apache.qpid.server.transport.ServerConnection;
+import org.apache.log4j.Logger;
+
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.util.Set;
+
+public class MultiVersionProtocolEngine implements ProtocolEngine
+{
+ private static final Logger _logger = Logger.getLogger(MultiVersionProtocolEngine.class);
+
+
+
+ private NetworkDriver _networkDriver;
+ private Set<VERSION> _supported;
+ private String _fqdn;
+ private IApplicationRegistry _appRegistry;
+
+ private volatile ProtocolEngine _delegate = new SelfDelegateProtocolEngine();
+
+ public MultiVersionProtocolEngine(IApplicationRegistry appRegistry,
+ String fqdn,
+ Set<VERSION> supported, NetworkDriver networkDriver)
+ {
+ _appRegistry = appRegistry;
+ _fqdn = fqdn;
+ _supported = supported;
+ _networkDriver = networkDriver;
+ }
+
+ public void setNetworkDriver(NetworkDriver driver)
+ {
+ _delegate.setNetworkDriver(driver);
+ }
+
+ public SocketAddress getRemoteAddress()
+ {
+ return _delegate.getRemoteAddress();
+ }
+
+ public SocketAddress getLocalAddress()
+ {
+ return _delegate.getLocalAddress();
+ }
+
+ public long getWrittenBytes()
+ {
+ return _delegate.getWrittenBytes();
+ }
+
+ public long getReadBytes()
+ {
+ return _delegate.getReadBytes();
+ }
+
+ public void closed()
+ {
+ _delegate.closed();
+ }
+
+ public void writerIdle()
+ {
+ _delegate.writerIdle();
+ }
+
+ public void readerIdle()
+ {
+ _delegate.readerIdle();
+ }
+
+ public void received(ByteBuffer msg)
+ {
+ _delegate.received(msg);
+ }
+
+ public void exception(Throwable t)
+ {
+ _delegate.exception(t);
+ }
+
+ private static final int MINIMUM_REQUIRED_HEADER_BYTES = 8;
+
+ private static final byte[] AMQP_0_8_HEADER =
+ new byte[] { (byte) 'A',
+ (byte) 'M',
+ (byte) 'Q',
+ (byte) 'P',
+ (byte) 1,
+ (byte) 1,
+ (byte) 8,
+ (byte) 0
+ };
+
+ private static final byte[] AMQP_0_9_HEADER =
+ new byte[] { (byte) 'A',
+ (byte) 'M',
+ (byte) 'Q',
+ (byte) 'P',
+ (byte) 1,
+ (byte) 1,
+ (byte) 0,
+ (byte) 9
+ };
+
+private static final byte[] AMQP_0_9_1_HEADER =
+ new byte[] { (byte) 'A',
+ (byte) 'M',
+ (byte) 'Q',
+ (byte) 'P',
+ (byte) 0,
+ (byte) 0,
+ (byte) 9,
+ (byte) 1
+ };
+
+
+ private static final byte[] AMQP_0_10_HEADER =
+ new byte[] { (byte) 'A',
+ (byte) 'M',
+ (byte) 'Q',
+ (byte) 'P',
+ (byte) 1,
+ (byte) 1,
+ (byte) 0,
+ (byte) 10
+ };
+
+ private static interface DelegateCreator
+ {
+ VERSION getVersion();
+ byte[] getHeaderIdentifier();
+ ProtocolEngine getProtocolEngine();
+ }
+
+ private DelegateCreator creator_0_8 = new DelegateCreator()
+ {
+
+ public VERSION getVersion()
+ {
+ return VERSION.v0_8;
+ }
+
+ public byte[] getHeaderIdentifier()
+ {
+ return AMQP_0_8_HEADER;
+ }
+
+ public ProtocolEngine getProtocolEngine()
+ {
+ return new AMQProtocolEngine(_appRegistry.getVirtualHostRegistry(), _networkDriver);
+ }
+ };
+
+ private DelegateCreator creator_0_9 = new DelegateCreator()
+ {
+
+ public VERSION getVersion()
+ {
+ return VERSION.v0_9;
+ }
+
+
+ public byte[] getHeaderIdentifier()
+ {
+ return AMQP_0_9_HEADER;
+ }
+
+ public ProtocolEngine getProtocolEngine()
+ {
+ return new AMQProtocolEngine(_appRegistry.getVirtualHostRegistry(), _networkDriver);
+ }
+ };
+
+ private DelegateCreator creator_0_9_1 = new DelegateCreator()
+ {
+
+ public VERSION getVersion()
+ {
+ return VERSION.v0_9_1;
+ }
+
+
+ public byte[] getHeaderIdentifier()
+ {
+ return AMQP_0_9_1_HEADER;
+ }
+
+ public ProtocolEngine getProtocolEngine()
+ {
+ return new AMQProtocolEngine(_appRegistry.getVirtualHostRegistry(), _networkDriver);
+ }
+ };
+
+
+ private DelegateCreator creator_0_10 = new DelegateCreator()
+ {
+
+ public VERSION getVersion()
+ {
+ return VERSION.v0_10;
+ }
+
+
+ public byte[] getHeaderIdentifier()
+ {
+ return AMQP_0_10_HEADER;
+ }
+
+ public ProtocolEngine getProtocolEngine()
+ {
+ final ConnectionDelegate connDelegate =
+ new org.apache.qpid.server.transport.ServerConnectionDelegate(_appRegistry, _fqdn);
+
+ Connection conn = new ServerConnection();
+ conn.setConnectionDelegate(connDelegate);
+
+ return new ProtocolEngine_0_10( conn, _networkDriver);
+ }
+ };
+
+ private final DelegateCreator[] _creators =
+ new DelegateCreator[] { creator_0_8, creator_0_9, creator_0_9_1, creator_0_10 };
+
+
+ private class ClosedDelegateProtocolEngine implements ProtocolEngine
+ {
+ public void setNetworkDriver(NetworkDriver driver)
+ {
+ _networkDriver = driver;
+ }
+
+ public SocketAddress getRemoteAddress()
+ {
+ return _networkDriver.getRemoteAddress();
+ }
+
+ public SocketAddress getLocalAddress()
+ {
+ return _networkDriver.getLocalAddress();
+ }
+
+ public long getWrittenBytes()
+ {
+ return 0;
+ }
+
+ public long getReadBytes()
+ {
+ return 0;
+ }
+
+ public void received(ByteBuffer msg)
+ {
+ _logger.error("Error processing incoming data, could not negotiate a common protocol");
+ }
+
+ public void exception(Throwable t)
+ {
+ _logger.error("Error establishing session", t);
+ }
+
+ public void closed()
+ {
+
+ }
+
+ public void writerIdle()
+ {
+
+ }
+
+ public void readerIdle()
+ {
+
+ }
+ }
+
+ private class SelfDelegateProtocolEngine implements ProtocolEngine
+ {
+
+ private final ByteBuffer _header = ByteBuffer.allocate(MINIMUM_REQUIRED_HEADER_BYTES);
+
+ public void setNetworkDriver(NetworkDriver driver)
+ {
+ _networkDriver = driver;
+ }
+
+ public SocketAddress getRemoteAddress()
+ {
+ return _networkDriver.getRemoteAddress();
+ }
+
+ public SocketAddress getLocalAddress()
+ {
+ return _networkDriver.getLocalAddress();
+ }
+
+ public long getWrittenBytes()
+ {
+ return 0;
+ }
+
+ public long getReadBytes()
+ {
+ return 0;
+ }
+
+ public void received(ByteBuffer msg)
+ {
+ ByteBuffer msgheader = msg.duplicate();
+ if(_header.remaining() > msgheader.limit())
+ {
+ msg.position(msg.limit());
+ }
+ else
+ {
+ msgheader.limit(_header.remaining());
+ msg.position(_header.remaining());
+ }
+
+ _header.put(msgheader);
+
+ if(!_header.hasRemaining())
+ {
+ _header.flip();
+ byte[] headerBytes = new byte[MINIMUM_REQUIRED_HEADER_BYTES];
+ _header.get(headerBytes);
+
+
+ ProtocolEngine newDelegate = null;
+ byte[] newestSupported = null;
+
+ for(int i = 0; newDelegate == null && i < _creators.length; i++)
+ {
+
+ if(_supported.contains(_creators[i].getVersion()))
+ {
+ newestSupported = _creators[i].getHeaderIdentifier();
+ byte[] compareBytes = _creators[i].getHeaderIdentifier();
+ boolean equal = true;
+ for(int j = 0; equal && j<compareBytes.length; j++)
+ {
+ equal = headerBytes[j] == compareBytes[j];
+ }
+ if(equal)
+ {
+ newDelegate = _creators[i].getProtocolEngine();
+ }
+ }
+ }
+
+ // If no delegate is found then send back the most recent support protocol version id
+ if(newDelegate == null)
+ {
+ _networkDriver.send(ByteBuffer.wrap(newestSupported));
+
+ newDelegate = new ClosedDelegateProtocolEngine();
+ }
+ else
+ {
+ newDelegate.setNetworkDriver(_networkDriver);
+
+ _delegate = newDelegate;
+
+ _header.flip();
+ _delegate.received(_header);
+ if(msg.hasRemaining())
+ {
+ _delegate.received(msg);
+ }
+ }
+
+ }
+
+ }
+
+ public void exception(Throwable t)
+ {
+ _logger.error("Error establishing session", t);
+ }
+
+ public void closed()
+ {
+
+ }
+
+ public void writerIdle()
+ {
+
+ }
+
+ public void readerIdle()
+ {
+
+ }
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngineFactory.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngineFactory.java
new file mode 100755
index 0000000000..75358c42d9
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngineFactory.java
@@ -0,0 +1,75 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+package org.apache.qpid.server.protocol;
+
+import org.apache.qpid.protocol.ProtocolEngineFactory;
+import org.apache.qpid.protocol.ProtocolEngine;
+import org.apache.qpid.transport.NetworkDriver;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.registry.IApplicationRegistry;
+
+import java.util.Set;
+import java.util.Arrays;
+import java.util.HashSet;
+
+public class MultiVersionProtocolEngineFactory implements ProtocolEngineFactory
+{
+ ;
+
+
+ public enum VERSION { v0_8, v0_9, v0_9_1, v0_10 };
+
+ private static final Set<VERSION> ALL_VERSIONS = new HashSet<VERSION>(Arrays.asList(VERSION.values()));
+
+ private final IApplicationRegistry _appRegistry;
+ private final String _fqdn;
+ private final Set<VERSION> _supported;
+
+
+ public MultiVersionProtocolEngineFactory()
+ {
+ this(1, "localhost", ALL_VERSIONS);
+ }
+
+ public MultiVersionProtocolEngineFactory(String fqdn, Set<VERSION> versions)
+ {
+ this(1, fqdn, versions);
+ }
+
+
+ public MultiVersionProtocolEngineFactory(String fqdn)
+ {
+ this(1, fqdn, ALL_VERSIONS);
+ }
+
+ public MultiVersionProtocolEngineFactory(int instance, String fqdn, Set<VERSION> supportedVersions)
+ {
+ _appRegistry = ApplicationRegistry.getInstance(instance);
+ _fqdn = fqdn;
+ _supported = supportedVersions;
+ }
+
+
+ public ProtocolEngine newProtocolEngine(NetworkDriver networkDriver)
+ {
+ return new MultiVersionProtocolEngine(_appRegistry, _fqdn, _supported, networkDriver);
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngineFactory_0_10.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngineFactory_0_10.java
new file mode 100755
index 0000000000..7c3adf8b7d
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngineFactory_0_10.java
@@ -0,0 +1,46 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.protocol;
+
+import org.apache.qpid.protocol.ProtocolEngineFactory;
+import org.apache.qpid.protocol.ProtocolEngine;
+import org.apache.qpid.transport.NetworkDriver;
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.ConnectionDelegate;
+import org.apache.qpid.server.transport.ServerConnection;
+import org.apache.qpid.server.protocol.ProtocolEngine_0_10;
+
+public class ProtocolEngineFactory_0_10 implements ProtocolEngineFactory
+{
+ private ConnectionDelegate _delegate;
+
+ public ProtocolEngineFactory_0_10(ConnectionDelegate delegate)
+ {
+ _delegate = delegate;
+ }
+
+ public ProtocolEngine newProtocolEngine(NetworkDriver networkDriver)
+ {
+ Connection conn = new ServerConnection();
+ conn.setConnectionDelegate(_delegate);
+ return new ProtocolEngine_0_10(conn, networkDriver);
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java
new file mode 100755
index 0000000000..e3cd3acd98
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java
@@ -0,0 +1,84 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.protocol;
+
+import org.apache.qpid.protocol.ProtocolEngine;
+import org.apache.qpid.transport.NetworkDriver;
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.network.InputHandler;
+import org.apache.qpid.transport.network.Assembler;
+import org.apache.qpid.transport.network.Disassembler;
+
+import java.net.SocketAddress;
+
+public class ProtocolEngine_0_10 extends InputHandler implements ProtocolEngine
+{
+ public static final int MAX_FRAME_SIZE = 64 * 1024 - 1;
+
+ private NetworkDriver _networkDriver;
+ private long _readBytes;
+ private long _writtenBytes;
+ private Connection _connection;
+
+ public ProtocolEngine_0_10(Connection conn, NetworkDriver networkDriver)
+ {
+ super(new Assembler(conn));
+ _connection = conn;
+ _networkDriver = networkDriver;
+ }
+
+ public void setNetworkDriver(NetworkDriver driver)
+ {
+ _networkDriver = driver;
+ Disassembler dis = new Disassembler(driver, MAX_FRAME_SIZE);
+ _connection.setSender(dis);
+ }
+
+ public SocketAddress getRemoteAddress()
+ {
+ return _networkDriver.getRemoteAddress();
+ }
+
+ public SocketAddress getLocalAddress()
+ {
+ return _networkDriver.getLocalAddress();
+ }
+
+ public long getReadBytes()
+ {
+ return _readBytes;
+ }
+
+ public long getWrittenBytes()
+ {
+ return _writtenBytes;
+ }
+
+ public void writerIdle()
+ {
+ //Todo
+ }
+
+ public void readerIdle()
+ {
+ //Todo
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java
deleted file mode 100644
index a485649410..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java
+++ /dev/null
@@ -1,482 +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.
- *
- */
-package org.apache.qpid.server.queue;
-
-import org.apache.log4j.Logger;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQBody;
-import org.apache.qpid.framing.AMQDataBlock;
-import org.apache.qpid.framing.AMQFrame;
-import org.apache.qpid.framing.ContentHeaderBody;
-import org.apache.qpid.framing.abstraction.ContentChunk;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.StoreContext;
-import org.apache.qpid.server.txn.TransactionalContext;
-
-
-import java.util.Iterator;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * A deliverable message.
- */
-public class AMQMessage implements Filterable<AMQException>
-{
- /** Used for debugging purposes. */
- private static final Logger _log = Logger.getLogger(AMQMessage.class);
-
- private final AtomicInteger _referenceCount = new AtomicInteger(1);
-
- private final AMQMessageHandle _messageHandle;
-
- /** Holds the transactional context in which this message is being processed. */
- private StoreContext _storeContext;
-
- /** Flag to indicate that this message requires 'immediate' delivery. */
-
- private static final byte IMMEDIATE = 0x01;
-
- /**
- * Flag to indicate whether this message has been delivered to a consumer. Used in implementing return functionality
- * for messages published with the 'immediate' flag.
- */
-
- private static final byte DELIVERED_TO_CONSUMER = 0x02;
-
- private byte _flags = 0;
-
- private long _expiration;
-
- private final long _size;
-
- private AMQProtocolSession.ProtocolSessionIdentifier _sessionIdentifier;
- private static final byte IMMEDIATE_AND_DELIVERED = (byte) (IMMEDIATE | DELIVERED_TO_CONSUMER);
-
-
-
- /**
- * Used to iterate through all the body frames associated with this message. Will not keep all the data in memory
- * therefore is memory-efficient.
- */
- private class BodyFrameIterator implements Iterator<AMQDataBlock>
- {
- private int _channel;
-
- private int _index = -1;
- private AMQProtocolSession _protocolSession;
-
- private BodyFrameIterator(AMQProtocolSession protocolSession, int channel)
- {
- _channel = channel;
- _protocolSession = protocolSession;
- }
-
- public boolean hasNext()
- {
- try
- {
- return _index < (_messageHandle.getBodyCount(getStoreContext()) - 1);
- }
- catch (AMQException e)
- {
- _log.error("Unable to get body count: " + e, e);
-
- return false;
- }
- }
-
- public AMQDataBlock next()
- {
- try
- {
-
- AMQBody cb =
- getProtocolVersionMethodConverter().convertToBody(_messageHandle.getContentChunk(getStoreContext(),
- ++_index));
-
- return new AMQFrame(_channel, cb);
- }
- catch (AMQException e)
- {
- // have no choice but to throw a runtime exception
- throw new RuntimeException("Error getting content body: " + e, e);
- }
-
- }
-
- private ProtocolVersionMethodConverter getProtocolVersionMethodConverter()
- {
- return _protocolSession.getMethodRegistry().getProtocolVersionMethodConverter();
- }
-
- public void remove()
- {
- throw new UnsupportedOperationException();
- }
- }
-
- public void clearStoreContext()
- {
- _storeContext = new StoreContext();
- }
-
- public StoreContext getStoreContext()
- {
- return _storeContext;
- }
-
- private class BodyContentIterator implements Iterator<ContentChunk>
- {
-
- private int _index = -1;
-
- public boolean hasNext()
- {
- try
- {
- return _index < (_messageHandle.getBodyCount(getStoreContext()) - 1);
- }
- catch (AMQException e)
- {
- _log.error("Error getting body count: " + e, e);
-
- return false;
- }
- }
-
- public ContentChunk next()
- {
- try
- {
- return _messageHandle.getContentChunk(getStoreContext(), ++_index);
- }
- catch (AMQException e)
- {
- throw new RuntimeException("Error getting content body: " + e, e);
- }
- }
-
- public void remove()
- {
- throw new UnsupportedOperationException();
- }
- }
-
-
-
- /**
- * Used when recovering, i.e. when the message store is creating references to messages. In that case, the normal
- * enqueue/routingComplete is not done since the recovery process is responsible for routing the messages to
- * queues.
- *
- * @param messageId
- * @param store
- * @param factory
- *
- * @throws AMQException
- */
- public AMQMessage(Long messageId, MessageStore store, MessageHandleFactory factory, TransactionalContext txnConext)
- throws AMQException
- {
- _messageHandle = factory.createMessageHandle(messageId, store, true);
- _storeContext = txnConext.getStoreContext();
- _size = _messageHandle.getBodySize(txnConext.getStoreContext());
- }
-
- /**
- * Used when recovering, i.e. when the message store is creating references to messages. In that case, the normal
- * enqueue/routingComplete is not done since the recovery process is responsible for routing the messages to
- * queues.
- *
- * @param messageHandle
- *
- * @throws AMQException
- */
- public AMQMessage(
- AMQMessageHandle messageHandle,
- StoreContext storeConext,
- MessagePublishInfo info)
- throws AMQException
- {
- _messageHandle = messageHandle;
- _storeContext = storeConext;
-
- if(info.isImmediate())
- {
- _flags |= IMMEDIATE;
- }
- _size = messageHandle.getBodySize(storeConext);
-
- }
-
-
- protected AMQMessage(AMQMessage msg) throws AMQException
- {
- _messageHandle = msg._messageHandle;
- _storeContext = msg._storeContext;
- _flags = msg._flags;
- _size = msg._size;
-
- }
-
-
- public String debugIdentity()
- {
- return "(HC:" + System.identityHashCode(this) + " ID:" + getMessageId() + " Ref:" + _referenceCount.get() + ")";
- }
-
- public void setExpiration(final long expiration)
- {
-
- _expiration = expiration;
-
- }
-
- public boolean isReferenced()
- {
- return _referenceCount.get() > 0;
- }
-
- public Iterator<AMQDataBlock> getBodyFrameIterator(AMQProtocolSession protocolSession, int channel)
- {
- return new BodyFrameIterator(protocolSession, channel);
- }
-
- public Iterator<ContentChunk> getContentBodyIterator()
- {
- return new BodyContentIterator();
- }
-
- public ContentHeaderBody getContentHeaderBody() throws AMQException
- {
- return _messageHandle.getContentHeaderBody(getStoreContext());
- }
-
-
-
- public Long getMessageId()
- {
- return _messageHandle.getMessageId();
- }
-
- /**
- * Creates a long-lived reference to this message, and increments the count of such references, as an atomic
- * operation.
- */
- public AMQMessage takeReference()
- {
- incrementReference(); // _referenceCount.incrementAndGet();
-
- return this;
- }
-
- public boolean incrementReference()
- {
- return incrementReference(1);
- }
-
- /* Threadsafe. Increment the reference count on the message. */
- public boolean incrementReference(int count)
- {
- if(_referenceCount.addAndGet(count) <= 1)
- {
- _referenceCount.addAndGet(-count);
- return false;
- }
- else
- {
- return true;
- }
-
- }
-
- /**
- * Threadsafe. This will decrement the reference count and when it reaches zero will remove the message from the
- * message store.
- *
- * @param storeContext
- *
- * @throws MessageCleanupException when an attempt was made to remove the message from the message store and that
- * failed
- */
- public void decrementReference(StoreContext storeContext) throws MessageCleanupException
- {
-
- int count = _referenceCount.decrementAndGet();
-
- // note that the operation of decrementing the reference count and then removing the message does not
- // have to be atomic since the ref count starts at 1 and the exchange itself decrements that after
- // the message has been passed to all queues. i.e. we are
- // not relying on the all the increments having taken place before the delivery manager decrements.
- if (count == 0)
- {
- // set the reference count way below 0 so that we can detect that the message has been deleted
- // this is to guard against the message being spontaneously recreated (from the mgmt console)
- // by copying from other queues at the same time as it is being removed.
- _referenceCount.set(Integer.MIN_VALUE/2);
-
- try
- {
- // must check if the handle is null since there may be cases where we decide to throw away a message
- // and the handle has not yet been constructed
- if (_messageHandle != null)
- {
- _messageHandle.removeMessage(storeContext);
- }
- }
- catch (AMQException e)
- {
- // to maintain consistency, we revert the count
- incrementReference();
- throw new MessageCleanupException(getMessageId(), e);
- }
- }
- else
- {
- if (count < 0)
- {
- throw new MessageCleanupException("Reference count for message id " + debugIdentity()
- + " has gone below 0.");
- }
- }
- }
-
-
- /**
- * Called selectors to determin if the message has already been sent
- *
- * @return _deliveredToConsumer
- */
- public boolean getDeliveredToConsumer()
- {
- return (_flags & DELIVERED_TO_CONSUMER) != 0;
- }
-
- public boolean isPersistent() throws AMQException
- {
- return _messageHandle.isPersistent();
- }
-
- /**
- * Called to enforce the 'immediate' flag.
- *
- * @returns true if the message is marked for immediate delivery but has not been marked as delivered
- * to a consumer
- */
- public boolean immediateAndNotDelivered()
- {
-
- return (_flags & IMMEDIATE_AND_DELIVERED) == IMMEDIATE;
-
- }
-
- public MessagePublishInfo getMessagePublishInfo() throws AMQException
- {
- return _messageHandle.getMessagePublishInfo(getStoreContext());
- }
-
- public boolean isRedelivered()
- {
- return _messageHandle.isRedelivered();
- }
-
- public void setRedelivered(boolean redelivered)
- {
- _messageHandle.setRedelivered(redelivered);
- }
-
- public long getArrivalTime()
- {
- return _messageHandle.getArrivalTime();
- }
-
- /**
- * Checks to see if the message has expired. If it has the message is dequeued.
- *
- * @param queue The queue to check the expiration against. (Currently not used)
- *
- * @return true if the message has expire
- *
- * @throws AMQException
- */
- public boolean expired(AMQQueue queue) throws AMQException
- {
-
- if (_expiration != 0L)
- {
- long now = System.currentTimeMillis();
-
- return (now > _expiration);
- }
-
- return false;
- }
-
- /**
- * Called when this message is delivered to a consumer. (used to implement the 'immediate' flag functionality).
- * And for selector efficiency.
- */
- public void setDeliveredToConsumer()
- {
- _flags |= DELIVERED_TO_CONSUMER;
- }
-
-
-
- public AMQMessageHandle getMessageHandle()
- {
- return _messageHandle;
- }
-
- public long getSize()
- {
- return _size;
-
- }
-
- public Object getPublisherClientInstance()
- {
- return _sessionIdentifier.getSessionInstance();
- }
-
- public Object getPublisherIdentifier()
- {
- return _sessionIdentifier.getSessionIdentifier();
- }
-
- public void setClientIdentifier(final AMQProtocolSession.ProtocolSessionIdentifier sessionIdentifier)
- {
- _sessionIdentifier = sessionIdentifier;
- }
-
-
- public String toString()
- {
- // return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " +
- // _taken + " by :" + _takenBySubcription;
-
- return "Message[" + debugIdentity() + "]: " + getMessageId() + "; ref count: " + _referenceCount;
- }
-
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java
deleted file mode 100644
index 0ddd4e4d92..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java
+++ /dev/null
@@ -1,79 +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.
- *
- */
-package org.apache.qpid.server.queue;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.ContentHeaderBody;
-import org.apache.qpid.server.store.StoreContext;
-import org.apache.qpid.framing.abstraction.ContentChunk;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-
-/**
- * A pluggable way of getting message data. Implementations can provide intelligent caching for example or
- * even no caching at all to minimise the broker memory footprint.
- */
-public interface AMQMessageHandle
-{
- ContentHeaderBody getContentHeaderBody(StoreContext context) throws AMQException;
-
- /**
- *
- * @return the messageId for the message associated with this handle
- */
- Long getMessageId();
-
-
- /**
- * @return the number of body frames associated with this message
- */
- int getBodyCount(StoreContext context) throws AMQException;
-
- /**
- * @return the size of the body
- */
- long getBodySize(StoreContext context) throws AMQException;
-
- /**
- * Get a particular content body
- * @param index the index of the body to retrieve, must be between 0 and getBodyCount() - 1
- * @return a content body
- * @throws IllegalArgumentException if the index is invalid
- */
- ContentChunk getContentChunk(StoreContext context, int index) throws IllegalArgumentException, AMQException;
-
- void addContentBodyFrame(StoreContext storeContext, ContentChunk contentBody, boolean isLastContentBody) throws AMQException;
-
- MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException;
-
- boolean isRedelivered();
-
- void setRedelivered(boolean redelivered);
-
- boolean isPersistent();
-
- void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo,
- ContentHeaderBody contentHeaderBody)
- throws AMQException;
-
- void removeMessage(StoreContext storeContext) throws AMQException;
-
- long getArrivalTime();
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java
index e14ed0f41d..51fbff76f4 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java
@@ -24,7 +24,6 @@ import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.subscription.SubscriptionList;
import org.apache.qpid.server.subscription.Subscription;
-import org.apache.qpid.AMQException;
public class AMQPriorityQueue extends SimpleAMQQueue
{
@@ -34,11 +33,19 @@ public class AMQPriorityQueue extends SimpleAMQQueue
final boolean autoDelete,
final VirtualHost virtualHost,
int priorities)
- throws AMQException
{
super(name, durable, owner, autoDelete, virtualHost, new PriorityQueueList.Factory(priorities));
}
+ public AMQPriorityQueue(String queueName,
+ boolean durable,
+ String owner,
+ boolean autoDelete,
+ VirtualHost virtualHost, int priorities)
+ {
+ this(new AMQShortString(queueName), durable, new AMQShortString(owner),autoDelete,virtualHost,priorities);
+ }
+
public int getPriorities()
{
return ((PriorityQueueList) _entries).getPriorities();
@@ -52,20 +59,28 @@ public class AMQPriorityQueue extends SimpleAMQQueue
while(subIter.advance() && !entry.isAcquired())
{
final Subscription subscription = subIter.getNode().getSubscription();
- QueueEntry subnode = subscription.getLastSeenEntry();
- while((entry.compareTo(subnode) < 0) && !entry.isAcquired())
+ if(!subscription.isClosed())
{
- if(subscription.setLastSeenEntry(subnode,entry))
+ QueueContext context = (QueueContext) subscription.getQueueContext();
+ if(context != null)
{
- break;
- }
- else
- {
- subnode = subscription.getLastSeenEntry();
+ QueueEntry subnode = context._lastSeenEntry;
+ QueueEntry released = context._releasedEntry;
+ while(subnode != null && entry.compareTo(subnode) < 0 && !entry.isAcquired() && (released == null || released.compareTo(entry) < 0))
+ {
+ if(QueueContext._releasedUpdater.compareAndSet(context,released,entry))
+ {
+ break;
+ }
+ else
+ {
+ subnode = context._lastSeenEntry;
+ released = context._releasedEntry;
+ }
+ }
}
}
}
}
-
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
index c9c252f06d..028f7e15a4 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
@@ -21,29 +21,51 @@
package org.apache.qpid.server.queue;
import org.apache.qpid.server.management.Managable;
-import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.management.ManagedObject;
+import org.apache.qpid.server.configuration.QueueConfiguration;
import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.exchange.ExchangeReferrer;
import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.message.ServerMessage;
import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.store.TransactionLogResource;
+import org.apache.qpid.server.security.PrincipalHolder;
+import org.apache.qpid.server.txn.ServerTransaction;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.AMQException;
import java.util.List;
import java.util.Set;
+import java.util.Map;
-public interface AMQQueue extends Managable, Comparable<AMQQueue>
+public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeReferrer, TransactionLogResource
{
+ boolean getDeleteOnNoConsumers();
+
+ void setDeleteOnNoConsumers(boolean b);
+
+
+ public interface Context
+ {
+ QueueEntry getLastSeenEntry();
+ }
AMQShortString getName();
+ void setNoLocal(boolean b);
+
boolean isDurable();
boolean isAutoDelete();
AMQShortString getOwner();
+ PrincipalHolder getPrincipalHolder();
+ void setPrincipalHolder(PrincipalHolder principalHolder);
+
+ void setExclusiveOwner(Object owner);
+ Object getExclusiveOwner();
VirtualHost getVirtualHost();
@@ -85,17 +107,19 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>
int delete() throws AMQException;
- QueueEntry enqueue(StoreContext storeContext, AMQMessage message) throws AMQException;
+ QueueEntry enqueue(ServerMessage message) throws AMQException;
+
+ void requeue(QueueEntry entry);
- void requeue(StoreContext storeContext, QueueEntry entry) throws AMQException;
+ void requeue(QueueEntryImpl storeContext, Subscription subscription);
- void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException;
+ void dequeue(QueueEntry entry);
boolean resend(final QueueEntry entry, final Subscription subscription) throws AMQException;
-
+
void addQueueDeleteTask(final Task task);
@@ -110,13 +134,24 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>
QueueEntry getMessageOnTheQueue(long messageId);
+ /**
+ * Returns a list of QueEntries from a given range of queue positions, eg messages 5 to 10 on the queue.
+ *
+ * The 'queue position' index starts from 1. Using 0 in 'from' will be ignored and continue from 1.
+ * Using 0 in the 'to' field will return an empty list regardless of the 'from' value.
+ * @param fromPosition
+ * @param toPosition
+ * @return
+ */
+ public List<QueueEntry> getMessagesRangeOnTheQueue(final long fromPosition, final long toPosition);
+
void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName,
- StoreContext storeContext);
+ ServerTransaction transaction);
- void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, StoreContext storeContext);
+ void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, ServerTransaction transaction);
- void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext);
+ void removeMessagesFromQueue(long fromMessageId, long toMessageId);
@@ -142,14 +177,29 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>
long getMinimumAlertRepeatGap();
+ void setMinimumAlertRepeatGap(long value);
- void deleteMessageFromTop(StoreContext storeContext) throws AMQException;
- long clearQueue(StoreContext storeContext) throws AMQException;
+ long getCapacity();
+ void setCapacity(long capacity);
- void removeExpiredIfNoSubscribers() throws AMQException;
+ long getFlowResumeCapacity();
+
+ void setFlowResumeCapacity(long flowResumeCapacity);
+
+ boolean isOverfull();
+
+ void deleteMessageFromTop();
+
+ long clearQueue();
+
+ /**
+ * Checks the status of messages on the queue, purging expired ones, firing age related alerts etc.
+ * @throws AMQException
+ */
+ void checkMessageStatus() throws AMQException;
Set<NotificationCheck> getNotificationChecks();
@@ -159,6 +209,17 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>
void deliverAsync();
+ void stop();
+
+ boolean isExclusive();
+
+ Exchange getAlternateExchange();
+
+ void setAlternateExchange(Exchange exchange);
+
+ Map<String, Object> getArguments();
+
+ void checkCapacity(AMQChannel channel);
/**
* ExistingExclusiveSubscription signals a failure to create a subscription, because an exclusive subscription
@@ -207,4 +268,8 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>
{
public void doTask(AMQQueue queue) throws AMQException;
}
+
+ void configure(QueueConfiguration config);
+
+ ManagedObject getManagedObject();
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java
index 9dfc4449bb..d4a5b3258b 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java
@@ -20,33 +20,206 @@
*/
package org.apache.qpid.server.queue;
+import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.server.configuration.QueueConfiguration;
import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.AMQException;
+
+import java.util.Map;
public class AMQQueueFactory
{
public static final AMQShortString X_QPID_PRIORITIES = new AMQShortString("x-qpid-priorities");
+ private abstract static class QueueProperty
+ {
+
+ private final AMQShortString _argumentName;
+
+
+ public QueueProperty(String argumentName)
+ {
+ _argumentName = new AMQShortString(argumentName);
+ }
+
+ public AMQShortString getArgumentName()
+ {
+ return _argumentName;
+ }
+
+
+ public abstract void setPropertyValue(AMQQueue queue, Object value);
+
+ }
+
+ private abstract static class QueueLongProperty extends QueueProperty
+ {
+
+ public QueueLongProperty(String argumentName)
+ {
+ super(argumentName);
+ }
+
+ public void setPropertyValue(AMQQueue queue, Object value)
+ {
+ if(value instanceof Number)
+ {
+ setPropertyValue(queue, ((Number)value).longValue());
+ }
+
+ }
+
+ abstract void setPropertyValue(AMQQueue queue, long value);
+
+
+ }
+
+ private static final QueueProperty[] DECLAREABLE_PROPERTIES = {
+ new QueueLongProperty("x-qpid-maximum-message-age")
+ {
+ public void setPropertyValue(AMQQueue queue, long value)
+ {
+ queue.setMaximumMessageAge(value);
+ }
+ },
+ new QueueLongProperty("x-qpid-maximum-message-size")
+ {
+ public void setPropertyValue(AMQQueue queue, long value)
+ {
+ queue.setMaximumMessageSize(value);
+ }
+ },
+ new QueueLongProperty("x-qpid-maximum-message-count")
+ {
+ public void setPropertyValue(AMQQueue queue, long value)
+ {
+ queue.setMaximumMessageCount(value);
+ }
+ },
+ new QueueLongProperty("x-qpid-minimum-alert-repeat-gap")
+ {
+ public void setPropertyValue(AMQQueue queue, long value)
+ {
+ queue.setMinimumAlertRepeatGap(value);
+ }
+ },
+ new QueueLongProperty("x-qpid-capacity")
+ {
+ public void setPropertyValue(AMQQueue queue, long value)
+ {
+ queue.setCapacity(value);
+ }
+ },
+ new QueueLongProperty("x-qpid-flow-resume-capacity")
+ {
+ public void setPropertyValue(AMQQueue queue, long value)
+ {
+ queue.setFlowResumeCapacity(value);
+ }
+ }
+
+ };
+
+
+
public static AMQQueue createAMQQueueImpl(AMQShortString name,
boolean durable,
AMQShortString owner,
boolean autoDelete,
VirtualHost virtualHost, final FieldTable arguments)
+ {
+ final int priorities = arguments == null ? 1 : arguments.containsKey(X_QPID_PRIORITIES) ? arguments.getInteger(X_QPID_PRIORITIES) : 1;
+
+ AMQQueue q = null;
+ if(priorities > 1)
+ {
+ q = new AMQPriorityQueue(name, durable, owner, autoDelete, virtualHost, priorities);
+ }
+ else
+ {
+ q = new SimpleAMQQueue(name, durable, owner, autoDelete, virtualHost);
+ }
+
+ //Register the new queue
+ virtualHost.getQueueRegistry().registerQueue(q);
+ q.configure(virtualHost.getConfiguration().getQueueConfiguration(name.asString()));
+
+ if(arguments != null)
+ {
+ for(QueueProperty p : DECLAREABLE_PROPERTIES)
+ {
+ if(arguments.containsKey(p.getArgumentName()))
+ {
+ p.setPropertyValue(q, arguments.get(p.getArgumentName()));
+ }
+ }
+ }
+
+ return q;
+ }
+
+ public static AMQQueue createAMQQueueImpl(QueueConfiguration config, VirtualHost host) throws AMQException
+ {
+ AMQShortString queueName = new AMQShortString(config.getName());
+
+ boolean durable = config.getDurable();
+ boolean autodelete = config.getAutoDelete();
+ AMQShortString owner = (config.getOwner() != null) ? new AMQShortString(config.getOwner()) : null;
+ FieldTable arguments = null;
+ boolean priority = config.getPriority();
+ int priorities = config.getPriorities();
+ if(priority || priorities > 0)
+ {
+ if(arguments == null)
+ {
+ arguments = new FieldTable();
+ }
+ if (priorities < 0)
+ {
+ priorities = 10;
+ }
+ arguments.put(new AMQShortString("x-qpid-priorities"), priorities);
+ }
+
+ AMQQueue q = createAMQQueueImpl(queueName, durable, owner, autodelete, host, arguments);
+ q.configure(config);
+ return q;
+ }
+
+ public static AMQQueue createAMQQueueImpl(String queueName,
+ boolean durable,
+ String owner,
+ boolean autoDelete,
+ VirtualHost virtualHost, Map<String, Object> arguments)
throws AMQException
{
+ int priorities = 1;
+ if(arguments != null && arguments.containsKey(X_QPID_PRIORITIES))
+ {
+ Object prioritiesObj = arguments.get(X_QPID_PRIORITIES);
+ if(prioritiesObj instanceof Number)
+ {
+ priorities = ((Number)prioritiesObj).intValue();
+ }
+ }
- final int priorities = arguments == null ? 1 : arguments.containsKey(X_QPID_PRIORITIES) ? arguments.getInteger(X_QPID_PRIORITIES) : 1;
+ AMQQueue q = null;
if(priorities > 1)
{
- return new AMQPriorityQueue(name, durable, owner, autoDelete, virtualHost, priorities);
+ q = new AMQPriorityQueue(queueName, durable, owner, autoDelete, virtualHost, priorities);
}
else
{
- return new SimpleAMQQueue(name, durable, owner, autoDelete, virtualHost);
+ q = new SimpleAMQQueue(queueName, durable, owner, autoDelete, virtualHost);
}
+
+ //Register the new queue
+ virtualHost.getQueueRegistry().registerQueue(q);
+ q.configure(virtualHost.getConfiguration().getQueueConfiguration(queueName));
+ return q;
+
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
index 2ed6be77c6..021128d2fc 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
@@ -22,22 +22,23 @@ package org.apache.qpid.server.queue;
import org.apache.log4j.Logger;
-import org.apache.mina.common.ByteBuffer;
-
import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.BasicContentHeaderProperties;
-import org.apache.qpid.framing.CommonContentHeaderProperties;
import org.apache.qpid.framing.ContentHeaderBody;
-import org.apache.qpid.framing.abstraction.ContentChunk;
+import org.apache.qpid.management.common.mbeans.ManagedQueue;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
import org.apache.qpid.server.management.AMQManagedObject;
-import org.apache.qpid.server.management.MBeanConstructor;
-import org.apache.qpid.server.management.MBeanDescription;
import org.apache.qpid.server.management.ManagedObject;
-import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.message.AMQMessageHeader;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.message.MessageTransferMessage;
+import org.apache.qpid.server.txn.ServerTransaction;
+import org.apache.qpid.server.txn.LocalTransaction;
+import org.apache.qpid.transport.MessageProperties;
import javax.management.JMException;
-import javax.management.MBeanException;
import javax.management.MBeanNotificationInfo;
import javax.management.Notification;
import javax.management.OperationsException;
@@ -71,24 +72,16 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
private static final SimpleDateFormat _dateFormat = new SimpleDateFormat("MM-dd-yy HH:mm:ss.SSS z");
- /**
- * Since the MBean is not associated with a real channel we can safely create our own store context
- * for use in the few methods that require one.
- */
- private StoreContext _storeContext = new StoreContext();
-
private AMQQueue _queue = null;
private String _queueName = null;
// OpenMBean data types for viewMessages method
- private static final String[] _msgAttributeNames = { "AMQ MessageId", "Header", "Size(bytes)", "Redelivered" };
- private static String[] _msgAttributeIndex = { _msgAttributeNames[0] };
- private static OpenType[] _msgAttributeTypes = new OpenType[4]; // AMQ message attribute types.
+
+ private static OpenType[] _msgAttributeTypes = new OpenType[5]; // AMQ message attribute types.
private static CompositeType _messageDataType = null; // Composite type for representing AMQ Message data.
private static TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list.
// OpenMBean data types for viewMessageContent method
private static CompositeType _msgContentType = null;
- private static final String[] _msgContentAttributes = { "AMQ MessageId", "MimeType", "Encoding", "Content" };
private static OpenType[] _msgContentAttributeTypes = new OpenType[4];
private final long[] _lastNotificationTimes = new long[NotificationCheck.values().length];
@@ -100,7 +93,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
@MBeanConstructor("Creates an MBean exposing an AMQQueue")
public AMQQueueMBean(AMQQueue queue) throws JMException
{
- super(ManagedQueue.class, ManagedQueue.TYPE);
+ super(ManagedQueue.class, ManagedQueue.TYPE, ManagedQueue.VERSION);
_queue = queue;
_queueName = jmxEncode(new StringBuffer(queue.getName()), 0).toString();
}
@@ -132,18 +125,20 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
_msgContentAttributeTypes[1] = SimpleType.STRING; // For MimeType
_msgContentAttributeTypes[2] = SimpleType.STRING; // For Encoding
_msgContentAttributeTypes[3] = new ArrayType(1, SimpleType.BYTE); // For message content
- _msgContentType =
- new CompositeType("Message Content", "AMQ Message Content", _msgContentAttributes, _msgContentAttributes,
- _msgContentAttributeTypes);
+ _msgContentType = new CompositeType("Message Content", "AMQ Message Content",
+ VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES, VIEW_MSG_CONTENT_COMPOSITE_ITEM_DESCRIPTIONS,
+ _msgContentAttributeTypes);
_msgAttributeTypes[0] = SimpleType.LONG; // For message id
_msgAttributeTypes[1] = new ArrayType(1, SimpleType.STRING); // For header attributes
_msgAttributeTypes[2] = SimpleType.LONG; // For size
_msgAttributeTypes[3] = SimpleType.BOOLEAN; // For redelivered
+ _msgAttributeTypes[4] = SimpleType.LONG; // For queue position
- _messageDataType =
- new CompositeType("Message", "AMQ Message", _msgAttributeNames, _msgAttributeNames, _msgAttributeTypes);
- _messagelistDataType = new TabularType("Messages", "List of messages", _messageDataType, _msgAttributeIndex);
+ _messageDataType = new CompositeType("Message", "AMQ Message", VIEW_MSGS_COMPOSITE_ITEM_NAMES,
+ VIEW_MSGS_COMPOSITE_ITEM_DESCRIPTIONS, _msgAttributeTypes);
+ _messagelistDataType = new TabularType("Messages", "List of messages", _messageDataType,
+ VIEW_MSGS_TABULAR_UNIQUE_INDEX);
}
public String getObjectInstanceName()
@@ -163,7 +158,11 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
public String getOwner()
{
- return String.valueOf(_queue.getOwner());
+ return String.valueOf(_queue.getPrincipalHolder() == null
+ ? null
+ : _queue.getPrincipalHolder().getPrincipal() == null
+ ? null
+ : _queue.getPrincipalHolder().getPrincipal().getName());
}
public boolean isAutoDelete()
@@ -221,11 +220,12 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
_queue.setMaximumMessageCount(value);
}
+ /**
+ * returns the maximum total size of messages(bytes) in the queue.
+ */
public Long getMaximumQueueDepth()
{
- long queueDepthInBytes = _queue.getMaximumQueueDepth();
-
- return queueDepthInBytes >> 10;
+ return _queue.getMaximumQueueDepth();
}
public void setMaximumQueueDepth(Long value)
@@ -234,19 +234,52 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
}
/**
- * returns the size of messages(KB) in the queue.
+ * returns the total size of messages(bytes) in the queue.
*/
public Long getQueueDepth() throws JMException
{
- long queueBytesSize = _queue.getQueueDepth();
+ return _queue.getQueueDepth();
+ }
+
+ public Long getCapacity()
+ {
+ return _queue.getCapacity();
+ }
+
+ public void setCapacity(Long capacity) throws IllegalArgumentException
+ {
+ if( _queue.getFlowResumeCapacity() > capacity )
+ {
+ throw new IllegalArgumentException("Capacity must not be less than FlowResumeCapacity");
+ }
+
+ _queue.setCapacity(capacity);
+ }
+
+ public Long getFlowResumeCapacity()
+ {
+ return _queue.getFlowResumeCapacity();
+ }
- return queueBytesSize >> 10;
+ public void setFlowResumeCapacity(Long flowResumeCapacity) throws IllegalArgumentException
+ {
+ if( _queue.getCapacity() < flowResumeCapacity )
+ {
+ throw new IllegalArgumentException("FlowResumeCapacity must not exceed Capacity");
+ }
+
+ _queue.setFlowResumeCapacity(flowResumeCapacity);
+ }
+
+ public boolean isFlowOverfull()
+ {
+ return _queue.isOverfull();
}
/**
* Checks if there is any notification to be send to the listeners
*/
- public void checkForNotification(AMQMessage msg) throws AMQException, JMException
+ public void checkForNotification(ServerMessage msg) throws AMQException
{
final Set<NotificationCheck> notificationChecks = _queue.getNotificationChecks();
@@ -296,29 +329,18 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
*/
public void deleteMessageFromTop() throws JMException
{
- try
- {
- _queue.deleteMessageFromTop(_storeContext);
- }
- catch (AMQException ex)
- {
- throw new MBeanException(ex, ex.toString());
- }
+ _queue.deleteMessageFromTop();
}
/**
+ * Clears the queue of non-acquired messages
+ *
+ * @return the number of messages deleted
* @see AMQQueue#clearQueue
*/
- public void clearQueue() throws JMException
+ public Long clearQueue() throws JMException
{
- try
- {
- _queue.clearQueue(_storeContext);
- }
- catch (AMQException ex)
- {
- throw new MBeanException(ex, ex.toString());
- }
+ return _queue.clearQueue();
}
/**
@@ -333,77 +355,115 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
throw new OperationsException("AMQMessage with message id = " + msgId + " is not in the " + _queueName);
}
- AMQMessage msg = entry.getMessage();
- // get message content
- Iterator<ContentChunk> cBodies = msg.getContentBodyIterator();
+ ServerMessage serverMsg = entry.getMessage();
+ final int bodySize = (int) serverMsg.getSize();
+
+
List<Byte> msgContent = new ArrayList<Byte>();
- while (cBodies.hasNext())
- {
- ContentChunk body = cBodies.next();
- if (body.getSize() != 0)
- {
- if (body.getSize() != 0)
- {
- ByteBuffer slice = body.getData().slice();
- for (int j = 0; j < slice.limit(); j++)
- {
- msgContent.add(slice.get());
- }
- }
- }
- }
- try
+ java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocate(bodySize);
+ int position = 0;
+
+ while(position < bodySize)
{
- // Create header attributes list
- CommonContentHeaderProperties headerProperties =
- (CommonContentHeaderProperties) msg.getContentHeaderBody().properties;
- String mimeType = null, encoding = null;
- if (headerProperties != null)
+ position += serverMsg.getContent(buf, position);
+ buf.flip();
+ for(int i = 0; i < buf.limit(); i++)
{
- AMQShortString mimeTypeShortSting = headerProperties.getContentType();
- mimeType = (mimeTypeShortSting == null) ? null : mimeTypeShortSting.toString();
- encoding = (headerProperties.getEncoding() == null) ? "" : headerProperties.getEncoding().toString();
+ msgContent.add(buf.get(i));
}
+ buf.clear();
+ }
- Object[] itemValues = { msgId, mimeType, encoding, msgContent.toArray(new Byte[0]) };
+ AMQMessageHeader header = serverMsg.getMessageHeader();
- return new CompositeDataSupport(_msgContentType, _msgContentAttributes, itemValues);
- }
- catch (AMQException e)
+ String mimeType = null, encoding = null;
+ if (header != null)
{
- JMException jme = new JMException("Error creating header attributes list: " + e);
- jme.initCause(e);
- throw jme;
+ mimeType = header.getMimeType();
+
+ encoding = header.getEncoding();
}
+
+
+ Object[] itemValues = { msgId, mimeType, encoding, msgContent.toArray(new Byte[0]) };
+
+ return new CompositeDataSupport(_msgContentType, VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES, itemValues);
+
}
/**
* Returns the header contents of the messages stored in this queue in tabular form.
+ * Deprecated as of Qpid JMX API 1.3
*/
+ @Deprecated
public TabularData viewMessages(int beginIndex, int endIndex) throws JMException
{
- if ((beginIndex > endIndex) || (beginIndex < 1))
+ return viewMessages((long)beginIndex,(long)endIndex);
+ }
+
+
+ /**
+ * Returns the header contents of the messages stored in this queue in tabular form.
+ * @param startPosition The queue position of the first message to be viewed
+ * @param endPosition The queue position of the last message to be viewed
+ */
+ public TabularData viewMessages(long startPosition, long endPosition) throws JMException
+ {
+ if ((startPosition > endPosition) || (startPosition < 1))
{
- throw new OperationsException("From Index = " + beginIndex + ", To Index = " + endIndex
+ throw new OperationsException("From Index = " + startPosition + ", To Index = " + endPosition
+ "\n\"From Index\" should be greater than 0 and less than \"To Index\"");
}
- List<QueueEntry> list = _queue.getMessagesOnTheQueue();
+ if ((endPosition - startPosition) > Integer.MAX_VALUE)
+ {
+ throw new OperationsException("Specified MessageID interval is too large. Intervals must be less than 2^31 in size");
+ }
+
+ List<QueueEntry> list = _queue.getMessagesRangeOnTheQueue(startPosition,endPosition);
TabularDataSupport _messageList = new TabularDataSupport(_messagelistDataType);
try
{
// Create the tabular list of message header contents
- for (int i = beginIndex; (i <= endIndex) && (i <= list.size()); i++)
+ int size = list.size();
+
+ for (int i = 0; i < size ; i++)
{
- AMQMessage msg = list.get(i - 1).getMessage();
- ContentHeaderBody headerBody = msg.getContentHeaderBody();
- // Create header attributes list
- String[] headerAttributes = getMessageHeaderProperties(headerBody);
- Object[] itemValues = { msg.getMessageId(), headerAttributes, headerBody.bodySize, msg.isRedelivered() };
- CompositeData messageData = new CompositeDataSupport(_messageDataType, _msgAttributeNames, itemValues);
- _messageList.put(messageData);
+ long position = startPosition + i;
+ final QueueEntry queueEntry = list.get(i);
+ ServerMessage serverMsg = queueEntry.getMessage();
+ if(serverMsg instanceof AMQMessage)
+ {
+ AMQMessage msg = (AMQMessage) serverMsg;
+ ContentHeaderBody headerBody = msg.getContentHeaderBody();
+ // Create header attributes list
+ String[] headerAttributes = getMessageHeaderProperties(headerBody);
+ Object[] itemValues = {msg.getMessageId(), headerAttributes, headerBody.bodySize, queueEntry.isRedelivered(), position};
+ CompositeData messageData = new CompositeDataSupport(_messageDataType, VIEW_MSGS_COMPOSITE_ITEM_NAMES, itemValues);
+ _messageList.put(messageData);
+
+ }
+ else if(serverMsg instanceof MessageTransferMessage)
+ {
+ // We have a 0-10 message
+ MessageTransferMessage msg = (MessageTransferMessage) serverMsg;
+
+ // Create header attributes list
+ String[] headerAttributes = getMessageTransferMessageHeaderProps(msg);
+ Object[] itemValues = {msg.getMessageNumber(), headerAttributes, msg.getSize(), queueEntry.isRedelivered(), position};
+ CompositeData messageData = new CompositeDataSupport(_messageDataType, VIEW_MSGS_COMPOSITE_ITEM_NAMES, itemValues);
+ _messageList.put(messageData);
+ }
+ else
+ {
+ //unknown message
+ String[] headerAttributes = new String[]{"N/A"};
+ Object[] itemValues = { serverMsg.getMessageNumber(), headerAttributes, serverMsg.getSize(), queueEntry.isRedelivered(), position};
+ CompositeData messageData = new CompositeDataSupport(_messageDataType, VIEW_MSGS_COMPOSITE_ITEM_NAMES, itemValues);
+ _messageList.put(messageData);
+ }
}
}
catch (AMQException e)
@@ -429,7 +489,8 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
list.add("JMSCorrelationID = " + headerProperties.getCorrelationIdAsString());
int delMode = headerProperties.getDeliveryMode();
- list.add("JMSDeliveryMode = " + ((delMode == 1) ? "Persistent" : "Non_Persistent"));
+ list.add("JMSDeliveryMode = " +
+ ((delMode == BasicContentHeaderProperties.PERSISTENT) ? "Persistent" : "Non_Persistent"));
list.add("JMSPriority = " + headerProperties.getPriority());
list.add("JMSType = " + headerProperties.getType());
@@ -445,6 +506,44 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
return list.toArray(new String[list.size()]);
}
+ private String[] getMessageTransferMessageHeaderProps(MessageTransferMessage msg)
+ {
+ List<String> list = new ArrayList<String>();
+
+ AMQMessageHeader header = msg.getMessageHeader();
+ MessageProperties msgProps = msg.getHeader().get(MessageProperties.class);
+
+ String appID = null;
+ String userID = null;
+
+ if(msgProps != null)
+ {
+ appID = msgProps.getAppId() == null ? "null" : new String(msgProps.getAppId());
+ userID = msgProps.getUserId() == null ? "null" : new String(msgProps.getUserId());
+ }
+
+ list.add("reply-to = " + header.getReplyTo());
+ list.add("propertyFlags = "); //TODO
+ list.add("ApplicationID = " + appID);
+ list.add("ClusterID = "); //TODO
+ list.add("UserId = " + userID);
+ list.add("JMSMessageID = " + header.getMessageId());
+ list.add("JMSCorrelationID = " + header.getCorrelationId());
+ list.add("JMSDeliveryMode = " + (msg.isPersistent() ? "Persistent" : "Non_Persistent"));
+ list.add("JMSPriority = " + header.getPriority());
+ list.add("JMSType = " + header.getType());
+
+ long longDate = header.getExpiration();
+ String strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null;
+ list.add("JMSExpiration = " + strDate);
+
+ longDate = header.getTimestamp();
+ strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null;
+ list.add("JMSTimestamp = " + strDate);
+
+ return list.toArray(new String[list.size()]);
+ }
+
/**
* @see ManagedQueue#moveMessages
* @param fromMessageId
@@ -456,10 +555,51 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
{
if ((fromMessageId > toMessageId) || (fromMessageId < 1))
{
- throw new OperationsException("\"From MessageId\" should be greater then 0 and less then \"To MessageId\"");
+ throw new OperationsException("\"From MessageId\" should be greater than 0 and less than \"To MessageId\"");
+ }
+
+ ServerTransaction txn = new LocalTransaction(_queue.getVirtualHost().getTransactionLog());
+ _queue.moveMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, txn);
+ txn.commit();
+ }
+
+ /**
+ * @see ManagedQueue#deleteMessages
+ * @param fromMessageId
+ * @param toMessageId
+ * @throws JMException
+ */
+ public void deleteMessages(long fromMessageId, long toMessageId) throws JMException
+ {
+ if ((fromMessageId > toMessageId) || (fromMessageId < 1))
+ {
+ throw new OperationsException("\"From MessageId\" should be greater than 0 and less than \"To MessageId\"");
+ }
+
+ _queue.removeMessagesFromQueue(fromMessageId, toMessageId);
+ }
+
+ /**
+ * @see ManagedQueue#copyMessages
+ * @param fromMessageId
+ * @param toMessageId
+ * @param toQueueName
+ * @throws JMException
+ */
+ public void copyMessages(long fromMessageId, long toMessageId, String toQueueName) throws JMException
+ {
+ if ((fromMessageId > toMessageId) || (fromMessageId < 1))
+ {
+ throw new OperationsException("\"From MessageId\" should be greater than 0 and less than \"To MessageId\"");
}
- _queue.moveMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, _storeContext);
+ ServerTransaction txn = new LocalTransaction(_queue.getVirtualHost().getTransactionLog());
+
+ _queue.copyMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, txn);
+
+ txn.commit();
+
+
}
/**
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java
deleted file mode 100644
index 290fedcf7b..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java
+++ /dev/null
@@ -1,56 +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.
- *
- */
-package org.apache.qpid.server.queue;
-
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-
-import org.apache.qpid.configuration.Configured;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-
-public class AsyncDeliveryConfig
-{
- private Executor _executor;
-
- @Configured(path = "delivery.poolsize", defaultValue = "0")
- public int poolSize;
-
- public Executor getExecutor()
- {
- if (_executor == null)
- {
- if (poolSize > 0)
- {
- _executor = Executors.newFixedThreadPool(poolSize);
- }
- else
- {
- _executor = Executors.newCachedThreadPool();
- }
- }
- return _executor;
- }
-
- public static Executor getAsyncDeliveryExecutor()
- {
- return ApplicationRegistry.getInstance().getConfiguredObject(AsyncDeliveryConfig.class).getExecutor();
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java
index cbe9246f09..aea485e749 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -44,12 +44,12 @@ public class DefaultQueueRegistry implements QueueRegistry
return _virtualHost;
}
- public void registerQueue(AMQQueue queue) throws AMQException
+ public void registerQueue(AMQQueue queue)
{
_queueMap.put(queue.getName(), queue);
}
- public void unregisterQueue(AMQShortString name) throws AMQException
+ public void unregisterQueue(AMQShortString name)
{
_queueMap.remove(name);
}
@@ -68,4 +68,9 @@ public class DefaultQueueRegistry implements QueueRegistry
{
return _queueMap.values();
}
+
+ public AMQQueue getQueue(String queue)
+ {
+ return getQueue(new AMQShortString(queue));
+ }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java b/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java
index a2fcab9e73..2fd8e32fcd 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java
@@ -21,6 +21,10 @@
package org.apache.qpid.server.queue;
import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.messages.BindingMessages;
+import org.apache.qpid.server.logging.subjects.BindingLogSubject;
+import org.apache.qpid.server.logging.LogSubject;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.AMQException;
@@ -31,23 +35,26 @@ public class ExchangeBinding
private final AMQShortString _routingKey;
private final FieldTable _arguments;
- private static final FieldTable EMPTY_ARGUMENTS = new FieldTable();
+ private static final FieldTable EMPTY_ARGUMENTS = new FieldTable();
+ private LogSubject _logSubject;
- ExchangeBinding(AMQShortString routingKey, Exchange exchange)
- {
- this(routingKey, exchange, EMPTY_ARGUMENTS);
- }
-
- ExchangeBinding(AMQShortString routingKey, Exchange exchange, FieldTable arguments)
+ ExchangeBinding(AMQShortString routingKey, Exchange exchange, AMQQueue queue, FieldTable arguments)
{
_routingKey = routingKey == null ? AMQShortString.EMPTY_STRING : routingKey;
_exchange = exchange;
_arguments = arguments == null ? EMPTY_ARGUMENTS : arguments;
+ _logSubject = new BindingLogSubject(routingKey,exchange,queue);
+
+ CurrentActor.get().message(_logSubject, BindingMessages.BND_CREATED(String.valueOf(_arguments), arguments != null));
}
+
+
void unbind(AMQQueue queue) throws AMQException
{
_exchange.deregisterQueue(_routingKey, queue, _arguments);
+
+ CurrentActor.get().message(_logSubject, BindingMessages.BND_DELETED());
}
public Exchange getExchange()
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java b/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java
index fb839c1783..89262aee59 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java
@@ -52,13 +52,13 @@ class ExchangeBindings
*/
void addBinding(AMQShortString routingKey, FieldTable arguments, Exchange exchange)
{
- _bindings.add(new ExchangeBinding(routingKey, exchange, arguments));
+ _bindings.add(new ExchangeBinding(routingKey, exchange, _queue, arguments));
}
public boolean remove(AMQShortString routingKey, FieldTable arguments, Exchange exchange)
{
- return _bindings.remove(new ExchangeBinding(routingKey, exchange, arguments));
+ return _bindings.remove(new ExchangeBinding(routingKey, exchange, _queue, arguments));
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java b/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java
index d38932bb61..eaa3992e98 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java
@@ -22,12 +22,13 @@ package org.apache.qpid.server.queue;
import org.apache.qpid.framing.ContentHeaderBody;
import org.apache.qpid.AMQException;
+import org.apache.qpid.server.message.AMQMessageHeader;
-public interface Filterable<E extends Exception>
+public interface Filterable
{
- ContentHeaderBody getContentHeaderBody() throws E;
+ AMQMessageHeader getMessageHeader();
- boolean isPersistent() throws E;
+ boolean isPersistent();
boolean isRedelivered();
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java b/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java
deleted file mode 100644
index 35ad5be4e0..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java
+++ /dev/null
@@ -1,157 +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.
- *
- */
-package org.apache.qpid.server.queue;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Collections;
-import java.util.ArrayList;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.ContentHeaderBody;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.framing.abstraction.ContentChunk;
-import org.apache.qpid.server.store.StoreContext;
-
-/**
- */
-public class InMemoryMessageHandle implements AMQMessageHandle
-{
-
- private ContentHeaderBody _contentHeaderBody;
-
- private MessagePublishInfo _messagePublishInfo;
-
- private List<ContentChunk> _contentBodies;
-
- private boolean _redelivered;
-
- private long _arrivalTime;
-
- private final Long _messageId;
-
- public InMemoryMessageHandle(final Long messageId)
- {
- _messageId = messageId;
- }
-
- public ContentHeaderBody getContentHeaderBody(StoreContext context) throws AMQException
- {
- return _contentHeaderBody;
- }
-
- public Long getMessageId()
- {
- return _messageId;
- }
-
- public int getBodyCount(StoreContext context)
- {
- return _contentBodies.size();
- }
-
- public long getBodySize(StoreContext context) throws AMQException
- {
- return getContentHeaderBody(context).bodySize;
- }
-
- public ContentChunk getContentChunk(StoreContext context, int index) throws AMQException, IllegalArgumentException
- {
- if (index > _contentBodies.size() - 1)
- {
- throw new IllegalArgumentException("Index " + index + " out of valid range 0 to " +
- (_contentBodies.size() - 1));
- }
- return _contentBodies.get(index);
- }
-
- public void addContentBodyFrame(StoreContext storeContext, ContentChunk contentBody, boolean isLastContentBody)
- throws AMQException
- {
- if(_contentBodies == null)
- {
- if(isLastContentBody)
- {
- _contentBodies = Collections.singletonList(contentBody);
- }
- else
- {
- _contentBodies = new ArrayList<ContentChunk>();
- _contentBodies.add(contentBody);
- }
- }
- else
- {
- _contentBodies.add(contentBody);
- }
- }
-
- public MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException
- {
- return _messagePublishInfo;
- }
-
- public boolean isRedelivered()
- {
- return _redelivered;
- }
-
-
- public void setRedelivered(boolean redelivered)
- {
- _redelivered = redelivered;
- }
-
- public boolean isPersistent()
- {
- return false;
- }
-
- /**
- * This is called when all the content has been received.
- * @param messagePublishInfo
- * @param contentHeaderBody
- * @throws AMQException
- */
- public void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo,
- ContentHeaderBody contentHeaderBody)
- throws AMQException
- {
- _messagePublishInfo = messagePublishInfo;
- _contentHeaderBody = contentHeaderBody;
- if(contentHeaderBody.bodySize == 0)
- {
- _contentBodies = Collections.EMPTY_LIST;
- }
- _arrivalTime = System.currentTimeMillis();
- }
-
- public void removeMessage(StoreContext storeContext) throws AMQException
- {
- // NO OP
- }
-
- public long getArrivalTime()
- {
- return _arrivalTime;
- }
-
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java b/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java
new file mode 100755
index 0000000000..77da08d8c4
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java
@@ -0,0 +1,71 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.server.message.InboundMessage;
+import org.apache.qpid.server.message.AMQMessageHeader;
+
+class InboundMessageAdapter implements InboundMessage
+{
+
+ private QueueEntry _entry;
+
+ InboundMessageAdapter()
+ {
+ }
+
+ InboundMessageAdapter(QueueEntry entry)
+ {
+ _entry = entry;
+ }
+
+ public void setEntry(QueueEntry entry)
+ {
+ _entry = entry;
+ }
+
+
+ public String getRoutingKey()
+ {
+ return _entry.getMessage().getRoutingKey();
+ }
+
+ public AMQMessageHeader getMessageHeader()
+ {
+ return _entry.getMessageHeader();
+ }
+
+ public boolean isPersistent()
+ {
+ return _entry.isPersistent();
+ }
+
+ public boolean isRedelivered()
+ {
+ return _entry.isRedelivered();
+ }
+
+ public long getSize()
+ {
+ return _entry.getSize();
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java
index 6287172ce8..da4173d5d3 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java
@@ -25,33 +25,32 @@ import org.apache.qpid.framing.abstraction.ContentChunk;
import org.apache.qpid.framing.ContentHeaderBody;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.BasicContentHeaderProperties;
-import org.apache.qpid.server.txn.TransactionalContext;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.StoredMessage;
import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.exchange.NoRouteException;
import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.message.InboundMessage;
+import org.apache.qpid.server.message.AMQMessageHeader;
+import org.apache.qpid.server.message.EnqueableMessage;
+import org.apache.qpid.server.message.MessageContentSource;
+import org.apache.qpid.server.message.MessageMetaData;
import org.apache.qpid.AMQException;
import org.apache.log4j.Logger;
import java.util.ArrayList;
-import java.util.Collection;
+import java.util.List;
+import java.nio.ByteBuffer;
-public class IncomingMessage implements Filterable<RuntimeException>
+public class IncomingMessage implements Filterable, InboundMessage, EnqueableMessage, MessageContentSource
{
/** Used for debugging purposes. */
private static final Logger _logger = Logger.getLogger(IncomingMessage.class);
private static final boolean SYNCHED_CLOCKS =
- ApplicationRegistry.getInstance().getConfiguration().getBoolean("advanced.synced-clocks", false);
+ ApplicationRegistry.getInstance().getConfiguration().getSynchedClocks();
private final MessagePublishInfo _messagePublishInfo;
private ContentHeaderBody _contentHeaderBody;
- private AMQMessageHandle _messageHandle;
- private final Long _messageId;
- private final TransactionalContext _txnContext;
-
/**
@@ -66,23 +65,27 @@ public class IncomingMessage implements Filterable<RuntimeException>
*/
private ArrayList<AMQQueue> _destinationQueues;
- private AMQProtocolSession _publisher;
- private MessageStore _messageStore;
private long _expiration;
private Exchange _exchange;
- public IncomingMessage(final Long messageId,
- final MessagePublishInfo info,
- final TransactionalContext txnContext,
- final AMQProtocolSession publisher)
+ private int _receivedChunkCount = 0;
+ private List<ContentChunk> _contentChunks = new ArrayList<ContentChunk>();
+
+ // we keep both the original meta data object and the store reference to it just in case the
+ // store would otherwise flow it to disk
+
+ private MessageMetaData _messageMetaData;
+
+ private StoredMessage<MessageMetaData> _storedMessageHandle;
+
+
+ public IncomingMessage(
+ final MessagePublishInfo info
+ )
{
- _messageId = messageId;
_messagePublishInfo = info;
- _txnContext = txnContext;
- _publisher = publisher;
-
}
public void setContentHeaderBody(final ContentHeaderBody contentHeaderBody) throws AMQException
@@ -121,158 +124,78 @@ public class IncomingMessage implements Filterable<RuntimeException>
}
- public void routingComplete(final MessageStore store,
- final MessageHandleFactory factory) throws AMQException
+ public MessageMetaData headersReceived()
{
-
- final boolean persistent = isPersistent();
- _messageHandle = factory.createMessageHandle(_messageId, store, persistent);
- if (persistent)
- {
- _txnContext.beginTranIfNecessary();
- // enqueuing the messages ensure that if required the destinations are recorded to a
- // persistent store
-
- if(_destinationQueues != null)
- {
- for (int i = 0; i < _destinationQueues.size(); i++)
- {
- store.enqueueMessage(_txnContext.getStoreContext(),
- _destinationQueues.get(i), _messageId);
- }
- }
- }
+ _messageMetaData = new MessageMetaData(_messagePublishInfo, _contentHeaderBody, 0);
+ return _messageMetaData;
}
- public AMQMessage deliverToQueues()
- throws AMQException
- {
-
- // we get a reference to the destination queues now so that we can clear the
- // transient message data as quickly as possible
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Delivering message " + _messageId + " to " + _destinationQueues);
- }
-
- AMQMessage message = null;
-
- try
- {
- // first we allow the handle to know that the message has been fully received. This is useful if it is
- // maintaining any calculated values based on content chunks
- _messageHandle.setPublishAndContentHeaderBody(_txnContext.getStoreContext(),
- _messagePublishInfo, getContentHeaderBody());
-
-
- message = new AMQMessage(_messageHandle,_txnContext.getStoreContext(), _messagePublishInfo);
-
- message.setExpiration(_expiration);
- message.setClientIdentifier(_publisher.getSessionIdentifier());
-
- if ((_destinationQueues == null) || _destinationQueues.size() == 0)
- {
-
- if (isMandatory() || isImmediate())
- {
- throw new NoRouteException("No Route for message", message);
-
- }
- else
- {
- _logger.warn("MESSAGE DISCARDED: No routes for message - " + message);
- }
- }
- else
- {
- int offset;
- final int queueCount = _destinationQueues.size();
- message.incrementReference(queueCount);
- if(queueCount == 1)
- {
- offset = 0;
- }
- else
- {
- offset = ((int)(message.getMessageId().longValue())) % queueCount;
- if(offset < 0)
- {
- offset = -offset;
- }
- }
- for (int i = offset; i < queueCount; i++)
- {
- // normal deliver so add this message at the end.
- _txnContext.deliver(_destinationQueues.get(i), message);
- }
- for (int i = 0; i < offset; i++)
- {
- // normal deliver so add this message at the end.
- _txnContext.deliver(_destinationQueues.get(i), message);
- }
- }
-
- // we then allow the transactional context to do something with the message content
- // now that it has all been received, before we attempt delivery
- _txnContext.messageFullyReceived(isPersistent());
- message.clearStoreContext();
- return message;
- }
- finally
- {
- // Remove refence for routing process . Reference count should now == delivered queue count
- if(message != null) message.decrementReference(_txnContext.getStoreContext());
- }
+ public ArrayList<AMQQueue> getDestinationQueues()
+ {
+ return _destinationQueues;
}
- public void addContentBodyFrame(final ContentChunk contentChunk)
+ public int addContentBodyFrame(final ContentChunk contentChunk)
throws AMQException
{
-
+ _storedMessageHandle.addContent((int)_bodyLengthReceived, contentChunk.getData().buf());
_bodyLengthReceived += contentChunk.getSize();
+ _contentChunks.add(contentChunk);
- _messageHandle.addContentBodyFrame(_txnContext.getStoreContext(), contentChunk, allContentReceived());
+
+ return _receivedChunkCount++;
}
public boolean allContentReceived()
{
- return (_bodyLengthReceived == getContentHeaderBody().bodySize);
+ return (_bodyLengthReceived == getContentHeader().bodySize);
}
- public AMQShortString getExchange() throws AMQException
+ public AMQShortString getExchange()
{
return _messagePublishInfo.getExchange();
}
- public AMQShortString getRoutingKey() throws AMQException
+ public String getRoutingKey()
{
- return _messagePublishInfo.getRoutingKey();
+ return _messagePublishInfo.getRoutingKey() == null ? null : _messagePublishInfo.getRoutingKey().toString();
}
- public boolean isMandatory() throws AMQException
+ public String getBinding()
+ {
+ return _messagePublishInfo.getRoutingKey() == null ? null : _messagePublishInfo.getRoutingKey().toString();
+ }
+
+
+ public boolean isMandatory()
{
return _messagePublishInfo.isMandatory();
}
- public boolean isImmediate() throws AMQException
+ public boolean isImmediate()
{
return _messagePublishInfo.isImmediate();
}
- public ContentHeaderBody getContentHeaderBody()
+ public ContentHeaderBody getContentHeader()
{
return _contentHeaderBody;
}
+ public AMQMessageHeader getMessageHeader()
+ {
+ return _messageMetaData.getMessageHeader();
+ }
+
public boolean isPersistent()
{
- //todo remove literal values to a constant file such as AMQConstants in common
- return getContentHeaderBody().properties instanceof BasicContentHeaderProperties &&
- ((BasicContentHeaderProperties) getContentHeaderBody().properties).getDeliveryMode() == 2;
+ return getContentHeader().properties instanceof BasicContentHeaderProperties &&
+ ((BasicContentHeaderProperties) getContentHeader().properties).getDeliveryMode() ==
+ BasicContentHeaderProperties.PERSISTENT;
}
public boolean isRedelivered()
@@ -280,14 +203,15 @@ public class IncomingMessage implements Filterable<RuntimeException>
return false;
}
- public void setMessageStore(final MessageStore messageStore)
+
+ public long getSize()
{
- _messageStore = messageStore;
+ return getContentHeader().bodySize;
}
- public Long getMessageId()
+ public Long getMessageNumber()
{
- return _messageId;
+ return _storedMessageHandle.getMessageNumber();
}
public void setExchange(final Exchange e)
@@ -295,13 +219,82 @@ public class IncomingMessage implements Filterable<RuntimeException>
_exchange = e;
}
- public void route() throws AMQException
+ public void route()
{
- _exchange.route(this);
+ enqueue(_exchange.route(this));
+
}
public void enqueue(final ArrayList<AMQQueue> queues)
{
_destinationQueues = queues;
}
+
+ public MessagePublishInfo getMessagePublishInfo()
+ {
+ return _messagePublishInfo;
+ }
+
+ public long getExpiration()
+ {
+ return _expiration;
+ }
+
+ public int getReceivedChunkCount()
+ {
+ return _receivedChunkCount;
+ }
+
+
+ public int getBodyCount() throws AMQException
+ {
+ return _contentChunks.size();
+ }
+
+ public ContentChunk getContentChunk(int index) throws IllegalArgumentException, AMQException
+ {
+ return _contentChunks.get(index);
+ }
+
+
+ public int getContent(ByteBuffer buf, int offset)
+ {
+ int pos = 0;
+ int written = 0;
+ for(ContentChunk cb : _contentChunks)
+ {
+ ByteBuffer data = cb.getData().buf();
+ if(offset+written >= pos && offset < pos + data.limit())
+ {
+ ByteBuffer src = data.duplicate();
+ src.position(offset+written - pos);
+ src = src.slice();
+
+ if(buf.remaining() < src.limit())
+ {
+ src.limit(buf.remaining());
+ }
+ int count = src.limit();
+ buf.put(src);
+ written += count;
+ if(buf.remaining() == 0)
+ {
+ break;
+ }
+ }
+ pos+=data.limit();
+ }
+ return written;
+
+ }
+
+ public void setStoredMessage(StoredMessage<MessageMetaData> storedMessageHandle)
+ {
+ _storedMessageHandle = storedMessageHandle;
+ }
+
+ public StoredMessage<MessageMetaData> getStoredMessage()
+ {
+ return _storedMessageHandle;
+ }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java
deleted file mode 100644
index 2bc94995e9..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java
+++ /dev/null
@@ -1,245 +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.
- *
- */
-package org.apache.qpid.server.queue;
-
-import java.io.IOException;
-
-import javax.management.JMException;
-import javax.management.MBeanOperationInfo;
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.TabularData;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.server.management.MBeanAttribute;
-import org.apache.qpid.server.management.MBeanOperation;
-import org.apache.qpid.server.management.MBeanOperationParameter;
-
-/**
- * The management interface exposed to allow management of a queue.
- * @author Robert J. Greig
- * @author Bhupendra Bhardwaj
- * @version 0.1
- */
-public interface ManagedQueue
-{
- static final String TYPE = "Queue";
-
- /**
- * Returns the Name of the ManagedQueue.
- * @return the name of the managedQueue.
- * @throws IOException
- */
- @MBeanAttribute(name="Name", description = TYPE + " Name")
- String getName() throws IOException;
-
- /**
- * Total number of messages on the queue, which are yet to be delivered to the consumer(s).
- * @return number of undelivered message in the Queue.
- * @throws IOException
- */
- @MBeanAttribute(name="MessageCount", description = "Total number of undelivered messages on the queue")
- Integer getMessageCount() throws IOException;
-
- /**
- * Tells the total number of messages receieved by the queue since startup.
- * @return total number of messages received.
- * @throws IOException
- */
- @MBeanAttribute(name="ReceivedMessageCount", description="The total number of messages receieved by the queue since startup")
- Long getReceivedMessageCount() throws IOException;
-
- /**
- * Size of messages in the queue
- * @return
- * @throws IOException
- */
- @MBeanAttribute(name="QueueDepth", description="Size of messages(KB) in the queue")
- Long getQueueDepth() throws IOException, JMException;
-
- /**
- * Returns the total number of active subscribers to the queue.
- * @return the number of active subscribers
- * @throws IOException
- */
- @MBeanAttribute(name="ActiveConsumerCount", description="The total number of active subscribers to the queue")
- Integer getActiveConsumerCount() throws IOException;
-
- /**
- * Returns the total number of subscribers to the queue.
- * @return the number of subscribers.
- * @throws IOException
- */
- @MBeanAttribute(name="ConsumerCount", description="The total number of subscribers to the queue")
- Integer getConsumerCount() throws IOException;
-
- /**
- * Tells the Owner of the ManagedQueue.
- * @return the owner's name.
- * @throws IOException
- */
- @MBeanAttribute(name="Owner", description = "Owner")
- String getOwner() throws IOException;
-
- /**
- * Tells whether this ManagedQueue is durable or not.
- * @return true if this ManagedQueue is a durable queue.
- * @throws IOException
- */
- @MBeanAttribute(name="Durable", description = "true if the AMQQueue is durable")
- boolean isDurable() throws IOException;
-
- /**
- * Tells if the ManagedQueue is set to AutoDelete.
- * @return true if the ManagedQueue is set to AutoDelete.
- * @throws IOException
- */
- @MBeanAttribute(name="AutoDelete", description = "true if the AMQQueue is AutoDelete")
- boolean isAutoDelete() throws IOException;
-
- /**
- * Returns the maximum age of a message (expiration time)
- * @return the maximum age
- * @throws IOException
- */
- Long getMaximumMessageAge() throws IOException;
-
- /**
- * Sets the maximum age of a message
- * @param age maximum age of message.
- * @throws IOException
- */
- @MBeanAttribute(name="MaximumMessageAge", description="Threshold high value for message age on the broker")
- void setMaximumMessageAge(Long age) throws IOException;
-
- /**
- * Returns the maximum size of a message (in kbytes) allowed to be accepted by the
- * ManagedQueue. This is useful in setting notifications or taking
- * appropriate action, if the size of the message received is more than
- * the allowed size.
- * @return the maximum size of a message allowed to be aceepted by the
- * ManagedQueue.
- * @throws IOException
- */
- Long getMaximumMessageSize() throws IOException;
-
- /**
- * Sets the maximum size of the message (in kbytes) that is allowed to be
- * accepted by the Queue.
- * @param size maximum size of message.
- * @throws IOException
- */
- @MBeanAttribute(name="MaximumMessageSize", description="Threshold high value(KB) for a message size")
- void setMaximumMessageSize(Long size) throws IOException;
-
- /**
- * Tells the maximum number of messages that can be stored in the queue.
- * This is useful in setting the notifications or taking required
- * action is the number of message increase this limit.
- * @return maximum muber of message allowed to be stored in the queue.
- * @throws IOException
- */
- Long getMaximumMessageCount() throws IOException;
-
- /**
- * Sets the maximum number of messages allowed to be stored in the queue.
- * @param value the maximum number of messages allowed to be stored in the queue.
- * @throws IOException
- */
- @MBeanAttribute(name="MaximumMessageCount", description="Threshold high value for number of undelivered messages in the queue")
- void setMaximumMessageCount(Long value) throws IOException;
-
- /**
- * This is useful for setting notifications or taking required action if the size of messages
- * stored in the queue increases over this limit.
- * @return threshold high value for Queue Depth
- * @throws IOException
- */
- Long getMaximumQueueDepth() throws IOException;
-
- /**
- * Sets the maximum size of all the messages together, that can be stored
- * in the queue.
- * @param value
- * @throws IOException
- */
- @MBeanAttribute(name="MaximumQueueDepth", description="The threshold high value(KB) for Queue Depth")
- void setMaximumQueueDepth(Long value) throws IOException;
-
-
-
- //********** Operations *****************//
-
-
- /**
- * Returns a subset of all the messages stored in the queue. The messages
- * are returned based on the given index numbers.
- * @param fromIndex
- * @param toIndex
- * @return
- * @throws IOException
- * @throws JMException
- */
- @MBeanOperation(name="viewMessages",
- description="Message headers for messages in this queue within given index range. eg. from index 1 - 100")
- TabularData viewMessages(@MBeanOperationParameter(name="from index", description="from index")int fromIndex,
- @MBeanOperationParameter(name="to index", description="to index")int toIndex)
- throws IOException, JMException, AMQException;
-
- @MBeanOperation(name="viewMessageContent", description="The message content for given Message Id")
- CompositeData viewMessageContent(@MBeanOperationParameter(name="Message Id", description="Message Id")long messageId)
- throws IOException, JMException;
-
- /**
- * Deletes the first message from top.
- * @throws IOException
- * @throws JMException
- */
- @MBeanOperation(name="deleteMessageFromTop", description="Deletes the first message from top",
- impact= MBeanOperationInfo.ACTION)
- void deleteMessageFromTop() throws IOException, JMException;
-
- /**
- * Clears the queue by deleting all the undelivered messages from the queue.
- * @throws IOException
- * @throws JMException
- */
- @MBeanOperation(name="clearQueue",
- description="Clears the queue by deleting all the undelivered messages from the queue",
- impact= MBeanOperationInfo.ACTION)
- void clearQueue() throws IOException, JMException;
-
- /**
- * Moves the messages in given range of message Ids to given Queue. QPID-170
- * @param fromMessageId first in the range of message ids
- * @param toMessageId last in the range of message ids
- * @param toQueue where the messages are to be moved
- * @throws IOException
- * @throws JMException
- * @throws AMQException
- */
- @MBeanOperation(name="moveMessages",
- description="You can move messages to another queue from this queue ",
- impact= MBeanOperationInfo.ACTION)
- void moveMessages(@MBeanOperationParameter(name="from MessageId", description="from MessageId")long fromMessageId,
- @MBeanOperationParameter(name="to MessageId", description="to MessageId")long toMessageId,
- @MBeanOperationParameter(name= ManagedQueue.TYPE, description="to Queue Name")String toQueue)
- throws IOException, JMException, AMQException;
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java b/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java
deleted file mode 100644
index 0b214ca336..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java
+++ /dev/null
@@ -1,46 +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.
- *
- */
-package org.apache.qpid.server.queue;
-
-import org.apache.qpid.server.store.MessageStore;
-
-/**
- * Constructs a message handle based on the publish body, the content header and the queue to which the message
- * has been routed.
- *
- * @author Robert Greig (robert.j.greig@jpmorgan.com)
- */
-public class MessageHandleFactory
-{
-
- public AMQMessageHandle createMessageHandle(Long messageId, MessageStore store, boolean persistent)
- {
- // just hardcoded for now
- if (persistent)
- {
- return new WeakReferenceMessageHandle(messageId, store);
- }
- else
- {
- return new InMemoryMessageHandle(messageId);
- }
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java b/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java
deleted file mode 100644
index 6118a4c11f..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java
+++ /dev/null
@@ -1,92 +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.
- *
- */
-package org.apache.qpid.server.queue;
-
-import org.apache.qpid.framing.ContentHeaderBody;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-
-/**
- * Encapsulates a publish body and a content header. In the context of the message store these are treated as a
- * single unit.
- */
-public class MessageMetaData
-{
- private MessagePublishInfo _messagePublishInfo;
-
- private ContentHeaderBody _contentHeaderBody;
-
- private int _contentChunkCount;
-
- private long _arrivalTime;
-
- public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount)
- {
- this(publishBody,contentHeaderBody, contentChunkCount, System.currentTimeMillis());
- }
-
- public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount, long arrivalTime)
- {
- _contentHeaderBody = contentHeaderBody;
- _messagePublishInfo = publishBody;
- _contentChunkCount = contentChunkCount;
- _arrivalTime = arrivalTime;
- }
-
- public int getContentChunkCount()
- {
- return _contentChunkCount;
- }
-
- public void setContentChunkCount(int contentChunkCount)
- {
- _contentChunkCount = contentChunkCount;
- }
-
- public ContentHeaderBody getContentHeaderBody()
- {
- return _contentHeaderBody;
- }
-
- public void setContentHeaderBody(ContentHeaderBody contentHeaderBody)
- {
- _contentHeaderBody = contentHeaderBody;
- }
-
- public MessagePublishInfo getMessagePublishInfo()
- {
- return _messagePublishInfo;
- }
-
- public void setMessagePublishInfo(MessagePublishInfo messagePublishInfo)
- {
- _messagePublishInfo = messagePublishInfo;
- }
-
- public long getArrivalTime()
- {
- return _arrivalTime;
- }
-
- public void setArrivalTime(long arrivalTime)
- {
- _arrivalTime = arrivalTime;
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java b/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java
deleted file mode 100644
index d6fd1eec89..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java
+++ /dev/null
@@ -1,47 +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.
- *
- */
-package org.apache.qpid.server.queue;
-
-import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.server.RequiredDeliveryException;
-
-/**
- * NoConsumersException is a {@link RequiredDeliveryException} that represents the failure case where an immediate
- * message cannot be delivered because there are presently no consumers for the message. The AMQP status code, 313, is
- * always used to report this condition.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Represent failure to deliver a message that must be delivered.
- * </table>
- */
-public class NoConsumersException extends RequiredDeliveryException
-{
- public NoConsumersException(AMQMessage message)
- {
- super("Immediate delivery is not possible.", message);
- }
-
- public AMQConstant getReplyCode()
- {
- return AMQConstant.NO_CONSUMERS;
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java b/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java
index 6f9efd3200..d1fb0f3fe6 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java
@@ -21,13 +21,14 @@
package org.apache.qpid.server.queue;
import org.apache.qpid.AMQException;
+import org.apache.qpid.server.message.ServerMessage;
public enum NotificationCheck
{
MESSAGE_COUNT_ALERT
{
- boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener)
+ boolean notifyIfNecessary(ServerMessage msg, AMQQueue queue, QueueNotificationListener listener)
{
int msgCount;
final long maximumMessageCount = queue.getMaximumMessageCount();
@@ -41,26 +42,19 @@ public enum NotificationCheck
},
MESSAGE_SIZE_ALERT(true)
{
- boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener)
+ boolean notifyIfNecessary(ServerMessage msg, AMQQueue queue, QueueNotificationListener listener)
{
final long maximumMessageSize = queue.getMaximumMessageSize();
if(maximumMessageSize != 0)
{
// Check for threshold message size
long messageSize;
- try
- {
- messageSize = (msg == null) ? 0 : msg.getContentHeaderBody().bodySize;
- }
- catch (AMQException e)
- {
- messageSize = 0;
- }
+ messageSize = (msg == null) ? 0 : msg.getSize();
if (messageSize >= maximumMessageSize)
{
- listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold ("+ maximumMessageSize +") breached. [Message ID=" + msg.getMessageId() + "]");
+ listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold ("+ maximumMessageSize +") breached. [Message ID=" + msg.getMessageNumber() + "]");
return true;
}
}
@@ -70,7 +64,7 @@ public enum NotificationCheck
},
QUEUE_DEPTH_ALERT
{
- boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener)
+ boolean notifyIfNecessary(ServerMessage msg, AMQQueue queue, QueueNotificationListener listener)
{
// Check for threshold queue depth in bytes
final long maximumQueueDepth = queue.getMaximumQueueDepth();
@@ -91,7 +85,7 @@ public enum NotificationCheck
},
MESSAGE_AGE_ALERT
{
- boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener)
+ boolean notifyIfNecessary(ServerMessage msg, AMQQueue queue, QueueNotificationListener listener)
{
final long maxMessageAge = queue.getMaximumMessageAge();
@@ -133,6 +127,6 @@ public enum NotificationCheck
return _messageSpecific;
}
- abstract boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener);
+ abstract boolean notifyIfNecessary(ServerMessage msg, AMQQueue queue, QueueNotificationListener listener);
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java b/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java
index fd46a8a5ff..0c6b84d2b6 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java
@@ -22,6 +22,7 @@ package org.apache.qpid.server.queue;
import org.apache.qpid.framing.CommonContentHeaderProperties;
import org.apache.qpid.AMQException;
+import org.apache.qpid.server.message.ServerMessage;
public class PriorityQueueList implements QueueEntryList
{
@@ -52,26 +53,18 @@ public class PriorityQueueList implements QueueEntryList
return _queue;
}
- public QueueEntry add(AMQMessage message)
+ public QueueEntry add(ServerMessage message)
{
- try
+ int index = message.getMessageHeader().getPriority() - _priorityOffset;
+ if(index >= _priorities)
{
- int index = ((CommonContentHeaderProperties)((message.getContentHeaderBody().properties))).getPriority() - _priorityOffset;
- if(index >= _priorities)
- {
- index = _priorities-1;
- }
- else if(index < 0)
- {
- index = 0;
- }
- return _priorityLists[index].add(message);
+ index = _priorities-1;
}
- catch (AMQException e)
+ else if(index < 0)
{
- // TODO - fix AMQ Exception
- throw new RuntimeException(e);
+ index = 0;
}
+ return _priorityLists[index].add(message);
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/QueueContext.java b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueContext.java
new file mode 100755
index 0000000000..825a85a89c
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueContext.java
@@ -0,0 +1,49 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.queue;
+
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+final class QueueContext implements AMQQueue.Context
+{
+ volatile QueueEntry _lastSeenEntry;
+ volatile QueueEntry _releasedEntry;
+
+ static final AtomicReferenceFieldUpdater<QueueContext, QueueEntry>
+ _lastSeenUpdater =
+ AtomicReferenceFieldUpdater.newUpdater
+ (QueueContext.class, QueueEntry.class, "_lastSeenEntry");
+ static final AtomicReferenceFieldUpdater<QueueContext, QueueEntry>
+ _releasedUpdater =
+ AtomicReferenceFieldUpdater.newUpdater
+ (QueueContext.class, QueueEntry.class, "_releasedEntry");
+
+ public QueueContext(QueueEntry head)
+ {
+ _lastSeenEntry = head;
+ }
+
+ public QueueEntry getLastSeenEntry()
+ {
+ return _lastSeenEntry;
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java
index 2657c459a9..a50e2b561d 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java
@@ -1,8 +1,8 @@
package org.apache.qpid.server.queue;
import org.apache.qpid.AMQException;
-import org.apache.qpid.server.store.StoreContext;
import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.message.ServerMessage;
/*
*
@@ -24,18 +24,19 @@ import org.apache.qpid.server.subscription.Subscription;
* under the License.
*
*/
-public interface QueueEntry extends Comparable<QueueEntry>
+public interface QueueEntry extends Comparable<QueueEntry>, Filterable
{
-
public static enum State
{
AVAILABLE,
ACQUIRED,
EXPIRED,
DEQUEUED,
- DELETED
+ DELETED;
+
+
}
public static interface StateChangeListener
@@ -121,6 +122,27 @@ public interface QueueEntry extends Comparable<QueueEntry>
}
}
+ public final class SubscriptionAssignedState extends EntryState
+ {
+ private final Subscription _subscription;
+
+ public SubscriptionAssignedState(Subscription subscription)
+ {
+ _subscription = subscription;
+ }
+
+
+ public State getState()
+ {
+ return State.AVAILABLE;
+ }
+
+ public Subscription getSubscription()
+ {
+ return _subscription;
+ }
+ }
+
final static EntryState AVAILABLE_STATE = new AvailableState();
final static EntryState DELETED_STATE = new DeletedState();
@@ -133,7 +155,7 @@ public interface QueueEntry extends Comparable<QueueEntry>
AMQQueue getQueue();
- AMQMessage getMessage();
+ ServerMessage getMessage();
long getSize();
@@ -150,16 +172,17 @@ public interface QueueEntry extends Comparable<QueueEntry>
boolean isDeleted();
boolean acquiredBySubscription();
-
- void setDeliveredToSubscription();
+ boolean isAcquiredBy(Subscription subscription);
void release();
+ boolean releaseButRetain();
- String debugIdentity();
boolean immediateAndNotDelivered();
- void setRedelivered(boolean b);
+ void setRedelivered();
+
+ boolean isRedelivered();
Subscription getDeliveredSubscription();
@@ -169,13 +192,15 @@ public interface QueueEntry extends Comparable<QueueEntry>
boolean isRejectedBy(Subscription subscription);
- void requeue(StoreContext storeContext) throws AMQException;
+ void requeue(Subscription subscription);
+
+ void dequeue();
- void dequeue(final StoreContext storeContext) throws FailedDequeueException;
+ void dispose();
- void dispose(final StoreContext storeContext) throws MessageCleanupException;
+ void discard();
- void discard(StoreContext storeContext) throws FailedDequeueException, MessageCleanupException;
+ void routeToAlternate();
boolean isQueueDeleted();
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
index dbad5438dc..5873e8f566 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
@@ -21,12 +21,16 @@
package org.apache.qpid.server.queue;
import org.apache.qpid.AMQException;
-import org.apache.qpid.server.store.StoreContext;
import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.message.MessageReference;
+import org.apache.qpid.server.message.AMQMessageHeader;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.txn.AutoCommitTransaction;
+import org.apache.qpid.server.txn.ServerTransaction;
import org.apache.log4j.Logger;
-import java.util.Set;
-import java.util.HashSet;
+import java.util.*;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import java.util.concurrent.CopyOnWriteArraySet;
@@ -42,8 +46,7 @@ public class QueueEntryImpl implements QueueEntry
private final SimpleQueueEntryList _queueEntryList;
- private AMQMessage _message;
-
+ private MessageReference _message;
private Set<Subscription> _rejectedBy = null;
@@ -76,6 +79,11 @@ public class QueueEntryImpl implements QueueEntry
volatile QueueEntryImpl _next;
+ private static final int DELIVERED_TO_CONSUMER = 1;
+ private static final int REDELIVERED = 2;
+
+ private volatile int _deliveryState;
+
QueueEntryImpl(SimpleQueueEntryList queueEntryList)
{
@@ -84,18 +92,19 @@ public class QueueEntryImpl implements QueueEntry
}
- public QueueEntryImpl(SimpleQueueEntryList queueEntryList, AMQMessage message, final long entryId)
+ public QueueEntryImpl(SimpleQueueEntryList queueEntryList, ServerMessage message, final long entryId)
{
_queueEntryList = queueEntryList;
- _message = message;
+
+ _message = message == null ? null : message.newReference();
_entryIdUpdater.set(this, entryId);
}
- public QueueEntryImpl(SimpleQueueEntryList queueEntryList, AMQMessage message)
+ public QueueEntryImpl(SimpleQueueEntryList queueEntryList, ServerMessage message)
{
_queueEntryList = queueEntryList;
- _message = message;
+ _message = message == null ? null : message.newReference();
}
protected void setEntryId(long entryId)
@@ -113,24 +122,36 @@ public class QueueEntryImpl implements QueueEntry
return _queueEntryList.getQueue();
}
- public AMQMessage getMessage()
+ public ServerMessage getMessage()
{
- return _message;
+ return _message == null ? null : _message.getMessage();
}
public long getSize()
{
- return getMessage().getSize();
+ return getMessage() == null ? 0 : getMessage().getSize();
}
public boolean getDeliveredToConsumer()
{
- return getMessage().getDeliveredToConsumer();
+ return (_deliveryState & DELIVERED_TO_CONSUMER) != 0;
}
public boolean expired() throws AMQException
{
- return getMessage().expired(getQueue());
+ ServerMessage message = getMessage();
+ if(message != null)
+ {
+ long expiration = message.getExpiration();
+ if (expiration != 0L)
+ {
+ long now = System.currentTimeMillis();
+
+ return (now > expiration);
+ }
+ }
+ return false;
+
}
public boolean isAcquired()
@@ -146,6 +167,24 @@ public class QueueEntryImpl implements QueueEntry
private boolean acquire(final EntryState state)
{
boolean acquired = _stateUpdater.compareAndSet(this,AVAILABLE_STATE, state);
+
+ // deal with the case where the node has been assigned to a given subscription already
+ // including the case that the node is assigned to a closed subscription
+ if(!acquired)
+ {
+ if(state != NON_SUBSCRIPTION_ACQUIRED_STATE)
+ {
+ EntryState currentState = _state;
+ if(currentState.getState() == State.AVAILABLE
+ && ((currentState == AVAILABLE_STATE)
+ || (((SubscriptionAcquiredState)state).getSubscription() ==
+ ((SubscriptionAssignedState)currentState).getSubscription())
+ || ((SubscriptionAssignedState)currentState).getSubscription().isClosed() ))
+ {
+ acquired = _stateUpdater.compareAndSet(this,currentState, state);
+ }
+ }
+ }
if(acquired && _stateChangeListeners != null)
{
notifyStateChange(State.AVAILABLE, State.ACQUIRED);
@@ -156,7 +195,12 @@ public class QueueEntryImpl implements QueueEntry
public boolean acquire(Subscription sub)
{
- return acquire(sub.getOwningState());
+ final boolean acquired = acquire(sub.getOwningState());
+ if(acquired)
+ {
+ _deliveryState |= DELIVERED_TO_CONSUMER;
+ }
+ return acquired;
}
public boolean acquiredBySubscription()
@@ -165,30 +209,89 @@ public class QueueEntryImpl implements QueueEntry
return (_state instanceof SubscriptionAcquiredState);
}
- public void setDeliveredToSubscription()
+ public boolean isAcquiredBy(Subscription subscription)
{
- getMessage().setDeliveredToConsumer();
+ EntryState state = _state;
+ return state instanceof SubscriptionAcquiredState
+ && ((SubscriptionAcquiredState)state).getSubscription() == subscription;
}
public void release()
{
_stateUpdater.set(this,AVAILABLE_STATE);
+ if(!getQueue().isDeleted())
+ {
+ getQueue().requeue(this);
+ if(_stateChangeListeners != null)
+ {
+ notifyStateChange(QueueEntry.State.ACQUIRED, QueueEntry.State.AVAILABLE);
+ }
+
+ }
+ else if(acquire())
+ {
+ routeToAlternate();
+ }
+
+
}
- public String debugIdentity()
+ public boolean releaseButRetain()
{
- return getMessage().debugIdentity();
+ EntryState state = _state;
+
+ boolean stateUpdated = false;
+
+ if(state instanceof SubscriptionAcquiredState)
+ {
+ Subscription sub = ((SubscriptionAcquiredState) state).getSubscription();
+ if(_stateUpdater.compareAndSet(this, state, sub.getAssignedState()))
+ {
+ System.err.println("Message released (and retained)" + getMessage().getMessageNumber());
+ getQueue().requeue(this);
+ if(_stateChangeListeners != null)
+ {
+ notifyStateChange(QueueEntry.State.ACQUIRED, QueueEntry.State.AVAILABLE);
+ }
+ stateUpdated = true;
+ }
+ }
+
+ return stateUpdated;
+
}
+ public boolean immediateAndNotDelivered()
+ {
+ return !getDeliveredToConsumer() && isImmediate();
+ }
- public boolean immediateAndNotDelivered()
+ private boolean isImmediate()
{
- return _message.immediateAndNotDelivered();
+ final ServerMessage message = getMessage();
+ return message != null && message.isImmediate();
}
- public void setRedelivered(boolean b)
+ public void setRedelivered()
{
- getMessage().setRedelivered(b);
+ _deliveryState |= REDELIVERED;
+ }
+
+ public AMQMessageHeader getMessageHeader()
+ {
+ final ServerMessage message = getMessage();
+ return message == null ? null : message.getMessageHeader();
+ }
+
+ public boolean isPersistent()
+ {
+ final ServerMessage message = getMessage();
+ return message != null && message.isPersistent();
+ }
+
+ public boolean isRedelivered()
+ {
+ return (_deliveryState & REDELIVERED) != 0;
}
public Subscription getDeliveredSubscription()
@@ -223,12 +326,12 @@ public class QueueEntryImpl implements QueueEntry
}
else
{
- _log.warn("Requesting rejection by null subscriber:" + debugIdentity());
+ _log.warn("Requesting rejection by null subscriber:" + this);
}
}
public boolean isRejectedBy(Subscription subscription)
- {
+ {
if (_rejectedBy != null) // We have subscriptions that rejected this message
{
@@ -240,17 +343,16 @@ public class QueueEntryImpl implements QueueEntry
}
}
-
- public void requeue(final StoreContext storeContext) throws AMQException
+ public void requeue(Subscription subscription)
{
- getQueue().requeue(storeContext, this);
+ getQueue().requeue(this, subscription);
if(_stateChangeListeners != null)
{
notifyStateChange(QueueEntry.State.ACQUIRED, QueueEntry.State.AVAILABLE);
}
}
- public void dequeue(final StoreContext storeContext) throws FailedDequeueException
+ public void dequeue()
{
EntryState state = _state;
@@ -259,10 +361,10 @@ public class QueueEntryImpl implements QueueEntry
if (state instanceof SubscriptionAcquiredState)
{
Subscription s = ((SubscriptionAcquiredState) state).getSubscription();
- s.restoreCredit(this);
+ s.onDequeue(this);
}
- getQueue().dequeue(storeContext, this);
+ getQueue().dequeue(this);
if(_stateChangeListeners != null)
{
notifyStateChange(state.getState() , QueueEntry.State.DEQUEUED);
@@ -280,23 +382,74 @@ public class QueueEntryImpl implements QueueEntry
}
}
- public void dispose(final StoreContext storeContext) throws MessageCleanupException
+ public void dispose()
{
if(delete())
{
- getMessage().decrementReference(storeContext);
+ _message.release();
}
}
- public void discard(StoreContext storeContext) throws FailedDequeueException, MessageCleanupException
+ public void discard()
{
//if the queue is null then the message is waiting to be acked, but has been removed.
if (getQueue() != null)
{
- dequeue(storeContext);
+ dequeue();
}
- dispose(storeContext);
+ dispose();
+ }
+
+ public void routeToAlternate()
+ {
+ final AMQQueue currentQueue = getQueue();
+ Exchange alternateExchange = currentQueue.getAlternateExchange();
+
+ if(alternateExchange != null)
+ {
+ final List<AMQQueue> rerouteQueues = alternateExchange.route(new InboundMessageAdapter(this));
+ final ServerMessage message = getMessage();
+ if(rerouteQueues != null && rerouteQueues.size() != 0)
+ {
+ ServerTransaction txn = new AutoCommitTransaction(getQueue().getVirtualHost().getTransactionLog());
+
+ txn.enqueue(rerouteQueues, message, new ServerTransaction.Action() {
+ public void postCommit()
+ {
+ try
+ {
+ for(AMQQueue queue : rerouteQueues)
+ {
+ QueueEntry entry = queue.enqueue(message);
+ }
+ }
+ catch (AMQException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void onRollback()
+ {
+
+ }
+ });
+ txn.dequeue(currentQueue,message,
+ new ServerTransaction.Action()
+ {
+ public void postCommit()
+ {
+ discard();
+ }
+
+ public void onRollback()
+ {
+
+ }
+ });
+ }
+ }
}
public boolean isQueueDeleted()
@@ -372,7 +525,7 @@ public class QueueEntryImpl implements QueueEntry
if(state != DELETED_STATE && _stateUpdater.compareAndSet(this,state,DELETED_STATE))
{
- _queueEntryList.advanceHead();
+ _queueEntryList.advanceHead();
return true;
}
else
@@ -385,4 +538,5 @@ public class QueueEntryImpl implements QueueEntry
{
return _queueEntryList;
}
+
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java
index 313e076f61..b4042ce02c 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java
@@ -20,11 +20,13 @@
*/
package org.apache.qpid.server.queue;
+import org.apache.qpid.server.message.ServerMessage;
+
public interface QueueEntryList
{
AMQQueue getQueue();
- QueueEntry add(AMQMessage message);
+ QueueEntry add(ServerMessage message);
QueueEntry next(QueueEntry node);
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java
index 1210f0e97c..a537e0c83f 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -30,9 +30,9 @@ public interface QueueRegistry
{
VirtualHost getVirtualHost();
- void registerQueue(AMQQueue queue) throws AMQException;
+ void registerQueue(AMQQueue queue);
- void unregisterQueue(AMQShortString name) throws AMQException;
+ void unregisterQueue(AMQShortString name);
AMQQueue getQueue(AMQShortString name);
@@ -40,4 +40,5 @@ public interface QueueRegistry
Collection<AMQQueue> getQueues();
+ AMQQueue getQueue(String queue);
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
index b0f700d4a1..825aa9795e 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
@@ -1,32 +1,39 @@
package org.apache.qpid.server.queue;
+import java.util.*;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.management.JMException;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.pool.ReadWriteRunnable;
+import org.apache.qpid.pool.ReferenceCountingExecutorService;
+import org.apache.qpid.server.configuration.QueueConfiguration;
import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.store.StoreContext;
-import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.management.ManagedObject;
+import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.subscription.Subscription;
import org.apache.qpid.server.subscription.SubscriptionList;
-import org.apache.qpid.server.output.ProtocolOutputConverter;
-import org.apache.qpid.server.management.ManagedObject;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.pool.ReadWriteRunnable;
-import org.apache.qpid.pool.ReferenceCountingExecutorService;
-import org.apache.qpid.configuration.Configured;
-import org.apache.log4j.Logger;
-
-import javax.management.JMException;
-import java.util.List;
-import java.util.Set;
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.Executor;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.atomic.AtomicReference;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.security.PrincipalHolder;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.QueueActor;
+import org.apache.qpid.server.logging.subjects.QueueLogSubject;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.logging.LogActor;
+import org.apache.qpid.server.logging.messages.QueueMessages;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.txn.ServerTransaction;
+import org.apache.qpid.server.txn.AutoCommitTransaction;
+import org.apache.qpid.server.txn.LocalTransaction;
/*
*
@@ -52,24 +59,40 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
{
private static final Logger _logger = Logger.getLogger(SimpleAMQQueue.class);
+
+ private final VirtualHost _virtualHost;
+
private final AMQShortString _name;
+ private final String _resourceName;
/** null means shared */
private final AMQShortString _owner;
+ private PrincipalHolder _prinicpalHolder;
+
+ private Object _exclusiveOwner;
+
+
private final boolean _durable;
/** If true, this queue is deleted when the last subscriber is removed */
private final boolean _autoDelete;
- private final VirtualHost _virtualHost;
+ private Exchange _alternateExchange;
/** Used to track bindings to exchanges so that on deletion they can easily be cancelled. */
private final ExchangeBindings _bindings = new ExchangeBindings(this);
- private final AtomicBoolean _deleted = new AtomicBoolean(false);
- private final List<Task> _deleteTaskList = new CopyOnWriteArrayList<Task>();
+ protected final QueueEntryList _entries;
+
+ protected final SubscriptionList _subscriptionList = new SubscriptionList(this);
+
+ private final AtomicReference<SubscriptionList.SubscriptionNode> _lastSubscriptionNode = new AtomicReference<SubscriptionList.SubscriptionNode>(_subscriptionList.getHead());
+
+ private volatile Subscription _exclusiveSubscriber;
+
+
private final AtomicInteger _atomicQueueCount = new AtomicInteger(0);
@@ -77,47 +100,59 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
private final AtomicInteger _activeSubscriberCount = new AtomicInteger();
- protected final SubscriptionList _subscriptionList = new SubscriptionList(this);
- private final AtomicReference<SubscriptionList.SubscriptionNode> _lastSubscriptionNode = new AtomicReference<SubscriptionList.SubscriptionNode>(_subscriptionList.getHead());
+ private final AtomicLong _totalMessagesReceived = new AtomicLong();
- private volatile Subscription _exclusiveSubscriber;
- protected final QueueEntryList _entries;
- private final AMQQueueMBean _managedObject;
- private final Executor _asyncDelivery;
- private final AtomicLong _totalMessagesReceived = new AtomicLong();
/** max allowed size(KB) of a single message */
- @Configured(path = "maximumMessageSize", defaultValue = "0")
- public long _maximumMessageSize;
+ public long _maximumMessageSize = ApplicationRegistry.getInstance().getConfiguration().getMaximumMessageSize();
/** max allowed number of messages on a queue. */
- @Configured(path = "maximumMessageCount", defaultValue = "0")
- public long _maximumMessageCount;
+ public long _maximumMessageCount = ApplicationRegistry.getInstance().getConfiguration().getMaximumMessageCount();
/** max queue depth for the queue */
- @Configured(path = "maximumQueueDepth", defaultValue = "0")
- public long _maximumQueueDepth;
+ public long _maximumQueueDepth = ApplicationRegistry.getInstance().getConfiguration().getMaximumQueueDepth();
/** maximum message age before alerts occur */
- @Configured(path = "maximumMessageAge", defaultValue = "0")
- public long _maximumMessageAge;
+ public long _maximumMessageAge = ApplicationRegistry.getInstance().getConfiguration().getMaximumMessageAge();
+
+ /** the minimum interval between sending out consecutive alerts of the same type */
+ public long _minimumAlertRepeatGap = ApplicationRegistry.getInstance().getConfiguration().getMinimumAlertRepeatGap();
- /** the minimum interval between sending out consequetive alerts of the same type */
- @Configured(path = "minimumAlertRepeatGap", defaultValue = "0")
- public long _minimumAlertRepeatGap;
+ private long _capacity = ApplicationRegistry.getInstance().getConfiguration().getCapacity();
- private static final int MAX_ASYNC_DELIVERIES = 10;
+ private long _flowResumeCapacity = ApplicationRegistry.getInstance().getConfiguration().getFlowResumeCapacity();
private final Set<NotificationCheck> _notificationChecks = EnumSet.noneOf(NotificationCheck.class);
+
+ static final int MAX_ASYNC_DELIVERIES = 10;
+
+
private final AtomicLong _stateChangeCount = new AtomicLong(Long.MIN_VALUE);
private AtomicReference _asynchronousRunner = new AtomicReference(null);
+ private final Executor _asyncDelivery;
private AtomicInteger _deliveredMessages = new AtomicInteger();
+ private AtomicBoolean _stopped = new AtomicBoolean(false);
+
+ private final ConcurrentMap<AMQChannel, Boolean> _blockedChannels = new ConcurrentHashMap<AMQChannel, Boolean>();
+
+ private final AtomicBoolean _deleted = new AtomicBoolean(false);
+ private final List<Task> _deleteTaskList = new CopyOnWriteArrayList<Task>();
+
+
+ private LogSubject _logSubject;
+ private LogActor _logActor;
+
+ private AMQQueueMBean _managedObject;
+ private static final String SUB_FLUSH_RUNNER = "SUB_FLUSH_RUNNER";
+ private boolean _nolocal;
+
+ private final AtomicBoolean _overfull = new AtomicBoolean(false);
+ private boolean _deleteOnNoConsumers;
protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost)
- throws AMQException
{
this(name, durable, owner, autoDelete, virtualHost, new SimpleQueueEntryList.Factory());
}
@@ -128,7 +163,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
boolean autoDelete,
VirtualHost virtualHost,
QueueEntryListFactory entryListFactory)
- throws AMQException
{
if (name == null)
@@ -142,6 +176,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
}
_name = name;
+ _resourceName = String.valueOf(name);
_durable = durable;
_owner = owner;
_autoDelete = autoDelete;
@@ -150,6 +185,29 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
_asyncDelivery = ReferenceCountingExecutorService.getInstance().acquireExecutorService();
+ _logSubject = new QueueLogSubject(this);
+ _logActor = new QueueActor(this, CurrentActor.get().getRootMessageLogger());
+
+ // Log the correct creation message
+
+ // Extract the number of priorities for this Queue.
+ // Leave it as 0 if we are a SimpleQueueEntryList
+ int priorities = 0;
+ if (entryListFactory instanceof PriorityQueueList.Factory)
+ {
+ priorities = ((PriorityQueueList)_entries).getPriorities();
+ }
+
+ // Log the creation of this Queue.
+ // The priorities display is toggled on if we set priorities > 0
+ CurrentActor.get().message(_logSubject,
+ QueueMessages.QUE_CREATED(String.valueOf(_owner),
+ priorities,
+ _owner != null,
+ autoDelete,
+ durable, !durable,
+ priorities > 0));
+
try
{
_managedObject = new AMQQueueMBean(this);
@@ -157,29 +215,78 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
}
catch (JMException e)
{
- throw new AMQException("AMQQueue MBean creation has failed ", e);
+ _logger.error("AMQQueue MBean creation has failed ", e);
}
+ resetNotifications();
+
+ }
+
+ public SimpleAMQQueue(String queueName, boolean durable, String owner, boolean autoDelete, VirtualHost virtualHost)
+ throws AMQException
+ {
+ this(new AMQShortString(queueName), durable, owner == null ? null : new AMQShortString(owner),autoDelete,virtualHost);
+ }
+
+ public void resetNotifications()
+ {
// This ensure that the notification checks for the configured alerts are created.
setMaximumMessageAge(_maximumMessageAge);
setMaximumMessageCount(_maximumMessageCount);
setMaximumMessageSize(_maximumMessageSize);
setMaximumQueueDepth(_maximumQueueDepth);
-
}
// ------ Getters and Setters
+ public void execute(ReadWriteRunnable runnable)
+ {
+ _asyncDelivery.execute(runnable);
+ }
+
public AMQShortString getName()
{
return _name;
}
+ public void setNoLocal(boolean nolocal)
+ {
+ _nolocal = nolocal;
+ }
+
public boolean isDurable()
{
return _durable;
}
+ public boolean isExclusive()
+ {
+ return _exclusiveOwner != null;
+ }
+
+ public Exchange getAlternateExchange()
+ {
+ return _alternateExchange;
+ }
+
+ public void setAlternateExchange(Exchange exchange)
+ {
+ if(_alternateExchange != null)
+ {
+ _alternateExchange.removeReference(this);
+ }
+ if(exchange != null)
+ {
+ exchange.addReference(this);
+ }
+ _alternateExchange = exchange;
+ }
+
+ public Map<String, Object> getArguments()
+ {
+ return null;
+ }
+
public boolean isAutoDelete()
{
return _autoDelete;
@@ -190,6 +297,17 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
return _owner;
}
+ public PrincipalHolder getPrincipalHolder()
+ {
+ return _prinicpalHolder;
+ }
+
+ public void setPrincipalHolder(PrincipalHolder prinicpalHolder)
+ {
+ _prinicpalHolder = prinicpalHolder;
+ }
+
+
public VirtualHost getVirtualHost()
{
return _virtualHost;
@@ -197,12 +315,31 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
// ------ bind and unbind
+ public void bind(Exchange exchange, String bindingKey, Map<String, Object> arguments) throws AMQException
+ {
+
+ FieldTable fieldTable = FieldTable.convertToFieldTable(arguments);
+ AMQShortString routingKey = new AMQShortString(bindingKey);
+
+ exchange.registerQueue(routingKey, this, fieldTable);
+
+ if (isDurable() && exchange.isDurable())
+ {
+
+ _virtualHost.getDurableConfigurationStore().bindQueue(exchange, routingKey, this, fieldTable);
+ }
+
+ _bindings.addBinding(routingKey, fieldTable, exchange);
+ }
+
+
public void bind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException
{
+
exchange.registerQueue(routingKey, this, arguments);
if (isDurable() && exchange.isDurable())
{
- _virtualHost.getMessageStore().bindQueue(exchange, routingKey, this, arguments);
+ _virtualHost.getDurableConfigurationStore().bindQueue(exchange, routingKey, this, arguments);
}
_bindings.addBinding(routingKey, arguments, exchange);
@@ -213,7 +350,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
exchange.deregisterQueue(routingKey, this, arguments);
if (isDurable() && exchange.isDurable())
{
- _virtualHost.getMessageStore().unbindQueue(exchange, routingKey, this, arguments);
+ _virtualHost.getDurableConfigurationStore().unbindQueue(exchange, routingKey, this, arguments);
}
boolean removed = _bindings.remove(routingKey, arguments, exchange);
@@ -238,7 +375,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
throw new ExistingExclusiveSubscription();
}
- if (exclusive)
+ if (exclusive && !subscription.isTransient())
{
if (getConsumerCount() != 0)
{
@@ -253,11 +390,15 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
_activeSubscriberCount.incrementAndGet();
subscription.setStateListener(this);
- subscription.setLastSeenEntry(null, _entries.getHead());
+ subscription.setQueueContext(new QueueContext(_entries.getHead()));
if (!isDeleted())
{
- subscription.setQueue(this);
+ subscription.setQueue(this, exclusive);
+ if(_nolocal)
+ {
+ subscription.setNoLocal(_nolocal);
+ }
_subscriptionList.add(subscription);
if (isDeleted())
{
@@ -287,17 +428,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
subscription.close();
// No longer can the queue have an exclusive consumer
setExclusiveSubscriber(null);
-
- QueueEntry lastSeen;
-
- while ((lastSeen = subscription.getLastSeenEntry()) != null)
- {
- subscription.setLastSeenEntry(lastSeen, null);
- }
+ subscription.setQueueContext(null);
// auto-delete queues must be deleted if there are no remaining subscribers
- if (_autoDelete && getConsumerCount() == 0)
+ if (_autoDelete && getDeleteOnNoConsumers() && !subscription.isTransient() && getConsumerCount() == 0 )
{
if (_logger.isInfoEnabled())
{
@@ -314,9 +449,20 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
}
+ public boolean getDeleteOnNoConsumers()
+ {
+ return _deleteOnNoConsumers;
+ }
+
+ public void setDeleteOnNoConsumers(boolean b)
+ {
+ _deleteOnNoConsumers = b;
+ }
+
+
// ------ Enqueue / Dequeue
- public QueueEntry enqueue(StoreContext storeContext, AMQMessage message) throws AMQException
+ public QueueEntry enqueue(ServerMessage message) throws AMQException
{
incrementQueueCount();
@@ -336,14 +482,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
entry = _entries.add(message);
deliverToSubscription(exclusiveSub, entry);
-
- // where there is more than one producer there's a reasonable chance that even though there is
- // no "queueing" we do not deliver because we get an interleving of _entries.add and
- // deliverToSubscription between threads. Therefore have one more try.
- if (!(entry.isAcquired() || entry.isDeleted()))
- {
- deliverToSubscription(exclusiveSub, entry);
- }
}
finally
{
@@ -403,29 +541,20 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
}
}
- if (entry.immediateAndNotDelivered())
- {
- dequeue(storeContext, entry);
- entry.dispose(storeContext);
- }
- else if (!(entry.isAcquired() || entry.isDeleted()))
+
+ if (!(entry.isAcquired() || entry.isDeleted()))
{
checkSubscriptionsNotAheadOfDelivery(entry);
deliverAsync();
}
- try
+ if(_managedObject != null)
{
_managedObject.checkForNotification(entry.getMessage());
}
- catch (JMException e)
- {
- throw new AMQException("Unable to get notification from manage queue: " + e, e);
- }
return entry;
-
}
private void deliverToSubscription(final Subscription sub, final QueueEntry entry)
@@ -440,17 +569,15 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
{
if (!sub.wouldSuspend(entry))
{
- if (!sub.isBrowser() && !entry.acquire(sub))
+ if (sub.acquires() && !entry.acquire(sub))
{
// restore credit here that would have been taken away by wouldSuspend since we didn't manage
// to acquire the entry for this subscription
- sub.restoreCredit(entry);
+ sub.onDequeue(entry);
}
else
{
-
deliverMessage(sub, entry);
-
}
}
}
@@ -467,7 +594,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
// Simple Queues don't :-)
}
- private void incrementQueueSize(final AMQMessage message)
+ private void incrementQueueSize(final ServerMessage message)
{
getAtomicQueueSize().addAndGet(message.getSize());
}
@@ -483,71 +610,46 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
_deliveredMessages.incrementAndGet();
sub.send(entry);
+ setLastSeenEntry(sub,entry);
}
- private boolean subscriptionReadyAndHasInterest(final Subscription sub, final QueueEntry entry)
+ private boolean subscriptionReadyAndHasInterest(final Subscription sub, final QueueEntry entry) throws AMQException
{
+ return sub.hasInterest(entry) && (getNextAvailableEntry(sub) == entry);
+ }
- // We need to move this subscription on, past entries which are already acquired, or deleted or ones it has no
- // interest in.
- QueueEntry node = sub.getLastSeenEntry();
- while (node != null && (node.isAcquired() || node.isDeleted() || !sub.hasInterest(node)))
- {
- QueueEntry newNode = _entries.next(node);
- if (newNode != null)
- {
- sub.setLastSeenEntry(node, newNode);
- node = sub.getLastSeenEntry();
- }
- else
- {
- node = null;
- break;
- }
-
- }
+ private void setLastSeenEntry(final Subscription sub, final QueueEntry entry)
+ {
+ QueueContext subContext = (QueueContext) sub.getQueueContext();
+ QueueEntry releasedEntry = subContext._releasedEntry;
- if (node == entry)
- {
- // If the first entry that subscription can process is the one we are trying to deliver to it, then we are
- // good
- return true;
- }
- else
+ QueueContext._lastSeenUpdater.set(subContext, entry);
+ if(releasedEntry == entry)
{
- // Otherwise we should try to update the subscription's last seen entry to the entry we got to, providing
- // no-one else has updated it to something furhter on in the list
- //TODO - check
- //updateLastSeenEntry(sub, entry);
- return false;
+ QueueContext._releasedUpdater.compareAndSet(subContext, releasedEntry, null);
}
-
}
- private void updateLastSeenEntry(final Subscription sub, final QueueEntry entry)
+ private void updateSubRequeueEntry(final Subscription sub, final QueueEntry entry)
{
- QueueEntry node = sub.getLastSeenEntry();
- if (node != null && entry.compareTo(node) < 0 && sub.hasInterest(entry))
+ QueueContext subContext = (QueueContext) sub.getQueueContext();
+ if(subContext != null)
{
- do
+ QueueEntry oldEntry;
+
+ while((oldEntry = subContext._releasedEntry) == null || oldEntry.compareTo(entry) > 0)
{
- if (sub.setLastSeenEntry(node, entry))
+ if(QueueContext._releasedUpdater.compareAndSet(subContext, oldEntry, entry))
{
- return;
- }
- else
- {
- node = sub.getLastSeenEntry();
+ break;
}
}
- while (node != null && entry.compareTo(node) < 0);
}
-
}
- public void requeue(StoreContext storeContext, QueueEntry entry) throws AMQException
+ public void requeue(QueueEntry entry)
{
SubscriptionList.SubscriptionNodeIterator subscriberIter = _subscriptionList.iterator();
@@ -557,9 +659,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
Subscription sub = subscriberIter.getNode().getSubscription();
// we don't make browsers send the same stuff twice
- if (!sub.isBrowser())
+ if (sub.seesRequeues())
{
- updateLastSeenEntry(sub, entry);
+ updateSubRequeueEntry(sub, entry);
}
}
@@ -567,38 +669,35 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
}
- public void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException
+ public void requeue(QueueEntryImpl entry, Subscription subscription)
{
- decrementQueueCount();
- decrementQueueSize(entry);
- if (entry.acquiredBySubscription())
+ SubscriptionList.SubscriptionNodeIterator subscriberIter = _subscriptionList.iterator();
+ // iterate over all the subscribers, and if they are in advance of this queue entry then move them backwards
+ while (subscriberIter.advance())
{
- _deliveredMessages.decrementAndGet();
- }
+ Subscription sub = subscriberIter.getNode().getSubscription();
- try
- {
- AMQMessage msg = entry.getMessage();
- if (isDurable() && msg.isPersistent())
+ // we don't make browsers send the same stuff twice
+ if (sub.seesRequeues() && (!sub.acquires() && sub == subscription))
{
- _virtualHost.getMessageStore().dequeueMessage(storeContext, this, msg.getMessageId());
+ updateSubRequeueEntry(sub, entry);
}
- //entry.dispose(storeContext);
-
}
- catch (MessageCleanupException e)
- {
- // Message was dequeued, but could not then be deleted
- // though it is no longer referenced. This should be very
- // rare and can be detected and cleaned up on recovery or
- // done through some form of manual intervention.
- _logger.error(e, e);
- }
- catch (AMQException e)
+
+ deliverAsync();
+ }
+
+ public void dequeue(QueueEntry entry)
+ {
+ decrementQueueCount();
+ decrementQueueSize(entry);
+ if (entry.acquiredBySubscription())
{
- throw new FailedDequeueException(_name.toString(), e);
+ _deliveredMessages.decrementAndGet();
}
+ checkCapacity();
+
}
private void decrementQueueSize(final QueueEntry entry)
@@ -772,7 +871,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
public boolean accept(QueueEntry entry)
{
- final long messageId = entry.getMessage().getMessageId();
+ final long messageId = entry.getMessage().getMessageNumber();
return messageId >= fromMessageId && messageId <= toMessageId;
}
@@ -791,7 +890,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
public boolean accept(QueueEntry entry)
{
- _complete = entry.getMessage().getMessageId() == messageId;
+ _complete = entry.getMessage().getMessageNumber() == messageId;
return _complete;
}
@@ -819,21 +918,51 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
}
+ /**
+ * Returns a list of QueEntries from a given range of queue positions, eg messages 5 to 10 on the queue.
+ *
+ * The 'queue position' index starts from 1. Using 0 in 'from' will be ignored and continue from 1.
+ * Using 0 in the 'to' field will return an empty list regardless of the 'from' value.
+ * @param fromPosition
+ * @param toPosition
+ * @return
+ */
+ public List<QueueEntry> getMessagesRangeOnTheQueue(final long fromPosition, final long toPosition)
+ {
+ List<QueueEntry> entries = getMessagesOnTheQueue(new QueueEntryFilter()
+ {
+ private long position = 0;
+
+ public boolean accept(QueueEntry entry)
+ {
+ position++;
+ return (position >= fromPosition) && (position <= toPosition);
+ }
+
+ public boolean filterComplete()
+ {
+ return position >= toPosition;
+ }
+ });
+
+ return entries;
+ }
+
public void moveMessagesToAnotherQueue(final long fromMessageId,
final long toMessageId,
String queueName,
- StoreContext storeContext)
+ ServerTransaction txn)
{
- AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName));
- MessageStore store = getVirtualHost().getMessageStore();
+ final AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName));
+
List<QueueEntry> entries = getMessagesOnTheQueue(new QueueEntryFilter()
{
public boolean accept(QueueEntry entry)
{
- final long messageId = entry.getMessage().getMessageId();
+ final long messageId = entry.getMessage().getMessageNumber();
return (messageId >= fromMessageId)
&& (messageId <= toMessageId)
&& entry.acquire();
@@ -845,61 +974,48 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
}
});
- try
+
+
+ // Move the messages in on the message store.
+ for (final QueueEntry entry : entries)
{
- store.beginTran(storeContext);
+ final ServerMessage message = entry.getMessage();
+ txn.enqueue(toQueue, message,
+ new ServerTransaction.Action()
+ {
- // Move the messages in on the message store.
- for (QueueEntry entry : entries)
- {
- AMQMessage message = entry.getMessage();
+ public void postCommit()
+ {
+ try
+ {
+ toQueue.enqueue(message);
+ }
+ catch (AMQException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
- if (message.isPersistent() && toQueue.isDurable())
- {
- store.enqueueMessage(storeContext, toQueue, message.getMessageId());
- }
- // dequeue does not decrement the refence count
- entry.dequeue(storeContext);
- }
+ public void onRollback()
+ {
+ entry.release();
+ }
+ });
+ txn.dequeue(this, message,
+ new ServerTransaction.Action()
+ {
- // Commit and flush the move transcations.
- try
- {
- store.commitTran(storeContext);
- }
- catch (AMQException e)
- {
- throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e);
- }
- }
- catch (AMQException e)
- {
- try
- {
- store.abortTran(storeContext);
- }
- catch (AMQException rollbackEx)
- {
- _logger.error("Failed to rollback transaction when error occured moving messages", rollbackEx);
- }
- throw new RuntimeException(e);
- }
+ public void postCommit()
+ {
+ entry.discard();
+ }
- try
- {
- for (QueueEntry entry : entries)
- {
- toQueue.enqueue(storeContext, entry.getMessage());
+ public void onRollback()
+ {
+
+ }
+ });
- }
- }
- catch (MessageCleanupException e)
- {
- throw new RuntimeException(e);
- }
- catch (AMQException e)
- {
- throw new RuntimeException(e);
}
}
@@ -907,27 +1023,18 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
public void copyMessagesToAnotherQueue(final long fromMessageId,
final long toMessageId,
String queueName,
- final StoreContext storeContext)
+ final ServerTransaction txn)
{
- AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName));
- MessageStore store = getVirtualHost().getMessageStore();
+ final AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName));
List<QueueEntry> entries = getMessagesOnTheQueue(new QueueEntryFilter()
{
public boolean accept(QueueEntry entry)
{
- final long messageId = entry.getMessage().getMessageId();
- if ((messageId >= fromMessageId)
- && (messageId <= toMessageId))
- {
- if (!entry.isDeleted())
- {
- return entry.getMessage().incrementReference();
- }
- }
-
- return false;
+ final long messageId = entry.getMessage().getMessageNumber();
+ return ((messageId >= fromMessageId)
+ && (messageId <= toMessageId));
}
public boolean filterComplete()
@@ -936,98 +1043,65 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
}
});
- try
+
+ // Move the messages in on the message store.
+ for (QueueEntry entry : entries)
{
- store.beginTran(storeContext);
+ final ServerMessage message = entry.getMessage();
- // Move the messages in on the message store.
- for (QueueEntry entry : entries)
+ txn.enqueue(toQueue, message, new ServerTransaction.Action()
{
- AMQMessage message = entry.getMessage();
-
- if (message.isReferenced() && message.isPersistent() && toQueue.isDurable())
+ public void postCommit()
{
- store.enqueueMessage(storeContext, toQueue, message.getMessageId());
+ try
+ {
+ toQueue.enqueue(message);
+ }
+ catch (AMQException e)
+ {
+ throw new RuntimeException(e);
+ }
}
- }
- // Commit and flush the move transcations.
- try
- {
- store.commitTran(storeContext);
- }
- catch (AMQException e)
- {
- throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e);
- }
- }
- catch (AMQException e)
- {
- try
- {
- store.abortTran(storeContext);
- }
- catch (AMQException rollbackEx)
- {
- _logger.error("Failed to rollback transaction when error occured moving messages", rollbackEx);
- }
- throw new RuntimeException(e);
- }
-
- try
- {
- for (QueueEntry entry : entries)
- {
- if (entry.getMessage().isReferenced())
+ public void onRollback()
{
- toQueue.enqueue(storeContext, entry.getMessage());
+
}
- }
- }
- catch (MessageCleanupException e)
- {
- throw new RuntimeException(e);
- }
- catch (AMQException e)
- {
- throw new RuntimeException(e);
+ });
+
}
}
- public void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext)
+ public void removeMessagesFromQueue(long fromMessageId, long toMessageId)
{
- try
+ QueueEntryIterator queueListIterator = _entries.iterator();
+
+ while (queueListIterator.advance())
{
- QueueEntryIterator queueListIterator = _entries.iterator();
+ QueueEntry node = queueListIterator.getNode();
- while (queueListIterator.advance())
+ final ServerMessage message = node.getMessage();
+ if(message != null)
{
- QueueEntry node = queueListIterator.getNode();
-
- final long messageId = node.getMessage().getMessageId();
+ final long messageId = message.getMessageNumber();
if ((messageId >= fromMessageId)
&& (messageId <= toMessageId)
&& !node.isDeleted()
&& node.acquire())
{
- node.discard(storeContext);
+ dequeueEntry(node);
}
-
}
}
- catch (AMQException e)
- {
- throw new RuntimeException(e);
- }
}
// ------ Management functions
- public void deleteMessageFromTop(StoreContext storeContext) throws AMQException
+ public void deleteMessageFromTop()
{
QueueEntryIterator queueListIterator = _entries.iterator();
boolean noDeletes = true;
@@ -1037,33 +1111,62 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
QueueEntry node = queueListIterator.getNode();
if (!node.isDeleted() && node.acquire())
{
- node.discard(storeContext);
+ dequeueEntry(node);
noDeletes = false;
}
}
}
- public long clearQueue(StoreContext storeContext) throws AMQException
+ public long clearQueue()
{
QueueEntryIterator queueListIterator = _entries.iterator();
long count = 0;
+ ServerTransaction txn = new LocalTransaction(getVirtualHost().getTransactionLog());
+
while (queueListIterator.advance())
{
QueueEntry node = queueListIterator.getNode();
if (!node.isDeleted() && node.acquire())
{
- node.discard(storeContext);
+ dequeueEntry(node, txn);
count++;
}
}
+
+ txn.commit();
+
return count;
}
+ private void dequeueEntry(final QueueEntry node)
+ {
+ ServerTransaction txn = new AutoCommitTransaction(getVirtualHost().getTransactionLog());
+ dequeueEntry(node, txn);
+ }
+
+ private void dequeueEntry(final QueueEntry node, ServerTransaction txn)
+ {
+ txn.dequeue(this, node.getMessage(),
+ new ServerTransaction.Action()
+ {
+
+ public void postCommit()
+ {
+ node.discard();
+ }
+
+ public void onRollback()
+ {
+
+ }
+ });
+ }
+
public void addQueueDeleteTask(final Task task)
{
_deleteTaskList.add(task);
@@ -1088,88 +1191,239 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
_bindings.deregister();
_virtualHost.getQueueRegistry().unregisterQueue(_name);
- _managedObject.unregister();
+ List<QueueEntry> entries = getMessagesOnTheQueue(new QueueEntryFilter()
+ {
+
+ public boolean accept(QueueEntry entry)
+ {
+ return entry.acquire();
+ }
+
+ public boolean filterComplete()
+ {
+ return false;
+ }
+ });
+
+ ServerTransaction txn = new LocalTransaction(getVirtualHost().getTransactionLog());
+
+ if(_alternateExchange != null)
+ {
+
+ InboundMessageAdapter adapter = new InboundMessageAdapter();
+ for(final QueueEntry entry : entries)
+ {
+ adapter.setEntry(entry);
+ final List<AMQQueue> rerouteQueues = _alternateExchange.route(adapter);
+ final ServerMessage message = entry.getMessage();
+ if(rerouteQueues != null & rerouteQueues.size() != 0)
+ {
+ txn.enqueue(rerouteQueues, entry.getMessage(),
+ new ServerTransaction.Action()
+ {
+
+ public void postCommit()
+ {
+ try
+ {
+ for(AMQQueue queue : rerouteQueues)
+ {
+ QueueEntry entry = queue.enqueue(message);
+ }
+ }
+ catch (AMQException e)
+ {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public void onRollback()
+ {
+
+ }
+ });
+ txn.dequeue(this, entry.getMessage(),
+ new ServerTransaction.Action()
+ {
+
+ public void postCommit()
+ {
+ entry.discard();
+ }
+
+ public void onRollback()
+ {
+ }
+ });
+ }
+
+ }
+
+ _alternateExchange.removeReference(this);
+ }
+ else
+ {
+ // TODO log discard
+
+ for(final QueueEntry entry : entries)
+ {
+ final ServerMessage message = entry.getMessage();
+ if(message != null)
+ {
+ txn.dequeue(this, message,
+ new ServerTransaction.Action()
+ {
+
+ public void postCommit()
+ {
+ entry.discard();
+ }
+
+ public void onRollback()
+ {
+ }
+ });
+ }
+ }
+ }
+
+ txn.commit();
+
+
+ if(_managedObject!=null)
+ {
+ _managedObject.unregister();
+ }
+
for (Task task : _deleteTaskList)
{
task.doTask(this);
}
_deleteTaskList.clear();
- ReferenceCountingExecutorService.getInstance().releaseExecutorService();
+ stop();
+
+ //Log Queue Deletion
+ CurrentActor.get().message(_logSubject, QueueMessages.QUE_DELETED());
+
}
return getMessageCount();
}
- public void deliverAsync()
+ public void stop()
{
- _stateChangeCount.incrementAndGet();
-
- Runner runner = new Runner();
-
- if (_asynchronousRunner.compareAndSet(null, runner))
+ if (!_stopped.getAndSet(true))
{
- _asyncDelivery.execute(runner);
+ ReferenceCountingExecutorService.getInstance().releaseExecutorService();
}
}
- public void deliverAsync(Subscription sub)
+ public void checkCapacity(AMQChannel channel)
{
- _asyncDelivery.execute(new SubFlushRunner(sub));
+ if(_capacity != 0l)
+ {
+ if(_atomicQueueSize.get() > _capacity)
+ {
+ _overfull.set(true);
+ //Overfull log message
+ _logActor.message(_logSubject, QueueMessages.QUE_OVERFULL(_atomicQueueSize.get(), _capacity));
+
+ if(_blockedChannels.putIfAbsent(channel, Boolean.TRUE)==null)
+ {
+ channel.block(this);
+ }
+
+ if(_atomicQueueSize.get() <= _flowResumeCapacity)
+ {
+
+ //Underfull log message
+ _logActor.message(_logSubject, QueueMessages.QUE_UNDERFULL(_atomicQueueSize.get(), _flowResumeCapacity));
+
+ channel.unblock(this);
+ _blockedChannels.remove(channel);
+
+ }
+
+ }
+
+
+
+ }
}
- private class Runner implements ReadWriteRunnable
+ private void checkCapacity()
{
- public void run()
+ if(_capacity != 0L)
{
- try
+ if(_overfull.get() && _atomicQueueSize.get() <= _flowResumeCapacity)
{
- processQueue(this);
- }
- catch (AMQException e)
- {
- _logger.error(e);
- }
+ if(_overfull.compareAndSet(true,false))
+ {//Underfull log message
+ _logActor.message(_logSubject, QueueMessages.QUE_UNDERFULL(_atomicQueueSize.get(), _flowResumeCapacity));
+ }
+
+ for(AMQChannel c : _blockedChannels.keySet())
+ {
+ c.unblock(this);
+ _blockedChannels.remove(c);
+ }
+ }
}
+ }
- public boolean isRead()
+
+ public void deliverAsync()
+ {
+ Runner runner = new Runner(_stateChangeCount.incrementAndGet());
+
+ if (_asynchronousRunner.compareAndSet(null, runner))
{
- return false;
+ _asyncDelivery.execute(runner);
}
+ }
- public boolean isWrite()
+ public void deliverAsync(Subscription sub)
+ {
+ SubFlushRunner flusher = (SubFlushRunner) sub.get(SUB_FLUSH_RUNNER);
+ if(flusher == null)
{
- return true;
+ flusher = new SubFlushRunner(sub);
+ sub.set(SUB_FLUSH_RUNNER, flusher);
}
+ _asyncDelivery.execute(flusher);
}
- private class SubFlushRunner implements ReadWriteRunnable
- {
- private final Subscription _sub;
- public SubFlushRunner(Subscription sub)
+ private class Runner implements ReadWriteRunnable
+ {
+ String _name;
+ public Runner(long count)
{
- _sub = sub;
+ _name = "QueueRunner-" + count + "-" + _logActor;
}
public void run()
{
- boolean complete = false;
+ String originalName = Thread.currentThread().getName();
try
{
- complete = flushSubscription(_sub, MAX_ASYNC_DELIVERIES);
+ Thread.currentThread().setName(_name);
+ CurrentActor.set(_logActor);
+ processQueue(this);
}
catch (AMQException e)
{
_logger.error(e);
}
- if (!complete && !_sub.isSuspended())
+ finally
{
- _asyncDelivery.execute(this);
+ CurrentActor.remove();
+ Thread.currentThread().setName(originalName);
}
-
}
public boolean isRead()
@@ -1181,6 +1435,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
{
return true;
}
+
+ public String toString()
+ {
+ return _name;
+ }
}
public void flushSubscription(Subscription sub) throws AMQException
@@ -1188,79 +1447,32 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
flushSubscription(sub, Long.MAX_VALUE);
}
- public boolean flushSubscription(Subscription sub, long deliveries) throws AMQException
+ public boolean flushSubscription(Subscription sub, long iterations) throws AMQException
{
boolean atTail = false;
- boolean advanced;
- while (!sub.isSuspended() && !atTail && deliveries != 0)
+ while (!sub.isSuspended() && !atTail && iterations != 0)
{
-
- advanced = false;
- sub.getSendLock();
try
{
- if (sub.isActive())
+ sub.getSendLock();
+ atTail = attemptDelivery(sub);
+ if (atTail && sub.isAutoClose())
{
- QueueEntry node = moveSubscriptionToNextNode(sub);
- if (!(node.isAcquired() || node.isDeleted()))
- {
- if (!sub.isSuspended())
- {
- if (sub.hasInterest(node))
- {
- if (!sub.wouldSuspend(node))
- {
- if (!sub.isBrowser() && !node.acquire(sub))
- {
- sub.restoreCredit(node);
+ unregisterSubscription(sub);
- }
- else
- {
- deliveries--;
- deliverMessage(sub, node);
-
- if (sub.isBrowser())
- {
- QueueEntry newNode = _entries.next(node);
-
- if (newNode != null)
- {
- advanced = true;
- sub.setLastSeenEntry(node, newNode);
- node = sub.getLastSeenEntry();
- }
- }
- }
-
- }
- else
- {
- break;
- }
- }
- else
- {
- // this subscription is not interested in this node so we can skip over it
- QueueEntry newNode = _entries.next(node);
- if (newNode != null)
- {
- sub.setLastSeenEntry(node, newNode);
- }
- }
- }
-
- }
- atTail = (_entries.next(node) == null) && !advanced;
+ sub.confirmAutoClose();
}
+ else if (!atTail)
+ {
+ iterations--;
+ }
}
finally
{
sub.releaseSendLock();
}
-
}
// if there's (potentially) more than one subscription the others will potentially not have been advanced to the
@@ -1271,16 +1483,57 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
{
advanceAllSubscriptions();
}
+ return atTail;
+ }
+
+ /**
+ * Attempt delivery for the given subscription.
+ *
+ * Looks up the next node for the subscription and attempts to deliver it.
+ *
+ * @param sub
+ * @return true if we have completed all possible deliveries for this sub.
+ * @throws AMQException
+ */
+ private boolean attemptDelivery(Subscription sub) throws AMQException
+ {
+ boolean atTail = false;
- if (atTail && sub.isAutoClose())
+ boolean subActive = sub.isActive() && !sub.isSuspended();
+ if (subActive)
{
- unregisterSubscription(sub);
- ProtocolOutputConverter converter = sub.getChannel().getProtocolSession().getProtocolOutputConverter();
- converter.confirmConsumerAutoClose(sub.getChannel().getChannelId(), sub.getConsumerTag());
- }
+ QueueEntry node = getNextAvailableEntry(sub);
- return atTail;
+ if (node != null && !(node.isAcquired() || node.isDeleted()))
+ {
+ if (sub.hasInterest(node))
+ {
+ if (!sub.wouldSuspend(node))
+ {
+ if (sub.acquires() && !node.acquire(sub))
+ {
+ sub.onDequeue(node);
+ }
+ else
+ {
+ deliverMessage(sub, node);
+ }
+
+ }
+ else // Not enough Credit for message and wouldSuspend
+ {
+ //QPID-1187 - Treat the subscription as suspended for this message
+ // and wait for the message to be removed to continue delivery.
+ subActive = false;
+ node.addStateChangeListener(new QueueEntryListener(sub));
+ }
+ }
+
+ }
+ atTail = (node == null) || (_entries.next(node) == null);
+ }
+ return atTail || !subActive;
}
protected void advanceAllSubscriptions() throws AMQException
@@ -1290,40 +1543,58 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
{
SubscriptionList.SubscriptionNode subNode = subscriberIter.getNode();
Subscription sub = subNode.getSubscription();
- moveSubscriptionToNextNode(sub);
+ if(sub.acquires())
+ {
+ getNextAvailableEntry(sub);
+ }
+ else
+ {
+ // TODO
+ }
}
}
- private QueueEntry moveSubscriptionToNextNode(final Subscription sub)
+ private QueueEntry getNextAvailableEntry(final Subscription sub)
throws AMQException
{
- QueueEntry node = sub.getLastSeenEntry();
-
- while (node != null && (node.isAcquired() || node.isDeleted() || node.expired()))
+ QueueContext context = (QueueContext) sub.getQueueContext();
+ if(context != null)
{
- if (!node.isAcquired() && !node.isDeleted() && node.expired())
+ QueueEntry lastSeen = context._lastSeenEntry;
+ QueueEntry releasedNode = context._releasedEntry;
+
+ QueueEntry node = (releasedNode != null && lastSeen.compareTo(releasedNode)>=0) ? releasedNode : _entries.next(lastSeen);
+
+ boolean expired = false;
+ while (node != null && (node.isAcquired() || node.isDeleted() || (expired = node.expired()) || !sub.hasInterest(node)))
{
- if (node.acquire())
+ if (expired)
{
- final StoreContext reapingStoreContext = new StoreContext();
- node.discard(reapingStoreContext);
+ expired = false;
+ if (node.acquire())
+ {
+ dequeueEntry(node);
+ }
}
- }
- QueueEntry newNode = _entries.next(node);
- if (newNode != null)
- {
- sub.setLastSeenEntry(node, newNode);
- node = sub.getLastSeenEntry();
- }
- else
- {
- break;
- }
+ if(QueueContext._lastSeenUpdater.compareAndSet(context, lastSeen, node))
+ {
+ QueueContext._releasedUpdater.compareAndSet(context, releasedNode, null);
+ }
+
+ lastSeen = context._lastSeenEntry;
+ releasedNode = context._releasedEntry;
+ node = (releasedNode != null && lastSeen.compareTo(releasedNode)>0) ? releasedNode : _entries.next(lastSeen);
+ }
+ return node;
+ }
+ else
+ {
+ return null;
}
- return node;
}
+
private void processQueue(Runnable runner) throws AMQException
{
long stateChangeCount;
@@ -1331,11 +1602,16 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
boolean deliveryIncomplete = true;
int extraLoops = 1;
- int deliveries = MAX_ASYNC_DELIVERIES;
+ Long iterations = new Long(MAX_ASYNC_DELIVERIES);
_asynchronousRunner.compareAndSet(runner, null);
- while (deliveries != 0 && ((previousStateChangeCount != (stateChangeCount = _stateChangeCount.get())) || deliveryIncomplete) && _asynchronousRunner.compareAndSet(null, runner))
+ // For every message enqueue/requeue the we fire deliveryAsync() which
+ // increases _stateChangeCount. If _sCC changes whilst we are in our loop
+ // (detected by setting previousStateChangeCount to stateChangeCount in the loop body)
+ // then we will continue to run for a maximum of iterations.
+ // So whilst delivery/rejection is going on a processQueue thread will be running
+ while (iterations != 0 && ((previousStateChangeCount != (stateChangeCount = _stateChangeCount.get())) || deliveryIncomplete) && _asynchronousRunner.compareAndSet(null, runner))
{
// we want to have one extra loop after every subscription has reached the point where it cannot move
// further, just in case the advance of one subscription in the last loop allows a different subscription to
@@ -1354,139 +1630,89 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
//iterate over the subscribers and try to advance their pointer
while (subscriptionIter.advance())
{
- boolean closeConsumer = false;
Subscription sub = subscriptionIter.getNode().getSubscription();
- if (sub != null)
+ sub.getSendLock();
+ try
{
- sub.getSendLock();
- try
+ if (sub != null)
{
- QueueEntry node = moveSubscriptionToNextNode(sub);
-
- if (node != null && sub.isActive())
+ done = attemptDelivery(sub);
+ }
+ if (done)
+ {
+ if (extraLoops == 0)
{
- boolean advanced = false;
- boolean subActive = false;
-
- if (!(node.isAcquired() || node.isDeleted()))
+ deliveryIncomplete = false;
+ if (sub.isAutoClose())
{
- if (!sub.isSuspended())
- {
- subActive = true;
- if (sub.hasInterest(node))
- {
- if (!sub.wouldSuspend(node))
- {
- if (!sub.isBrowser() && !node.acquire(sub))
- {
- sub.restoreCredit(node);
-
- }
- else
- {
- deliverMessage(sub, node);
- deliveries--;
-
- if (sub.isBrowser())
- {
- QueueEntry newNode = _entries.next(node);
-
- if (newNode != null)
- {
- sub.setLastSeenEntry(node, newNode);
- node = sub.getLastSeenEntry();
- advanced = true;
- }
+ unregisterSubscription(sub);
- }
- }
- done = false;
- }
- else // Not enough Credit for message and wouldSuspend
- {
- //QPID-1187 - Treat the subscription as suspended for this message
- // and wait for the message to be removed to continue delivery.
- subActive = false;
-
- node.addStateChangeListener(new QueueEntryListener(sub, node));
- }
- }
- else
- {
- // this subscription is not interested in this node so we can skip over it
- QueueEntry newNode = _entries.next(node);
- if (newNode != null)
- {
- sub.setLastSeenEntry(node, newNode);
- }
- }
- }
+ sub.confirmAutoClose();
}
- final boolean atTail = (_entries.next(node) == null);
-
- done = done && (!subActive || atTail);
-
- closeConsumer = (atTail && !advanced && sub.isAutoClose());
}
- }
- finally
- {
- sub.releaseSendLock();
- }
-
- if (closeConsumer)
- {
- unregisterSubscription(sub);
-
- ProtocolOutputConverter converter = sub.getChannel().getProtocolSession().getProtocolOutputConverter();
- converter.confirmConsumerAutoClose(sub.getChannel().getChannelId(), sub.getConsumerTag());
- }
-
- }
- if (done)
- {
- if (extraLoops == 0)
- {
- deliveryIncomplete = false;
+ else
+ {
+ extraLoops--;
+ }
}
else
{
- extraLoops--;
+ iterations--;
+ extraLoops = 1;
}
}
- else
+ finally
{
- extraLoops = 1;
+ sub.releaseSendLock();
}
}
-
_asynchronousRunner.set(null);
}
// If deliveries == 0 then the limitting factor was the time-slicing rather than available messages or credit
// therefore we should schedule this runner again (unless someone beats us to it :-) ).
- if (deliveries == 0 && _asynchronousRunner.compareAndSet(null, runner))
+ if (iterations == 0 && _asynchronousRunner.compareAndSet(null, runner))
{
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Rescheduling runner:" + runner);
+ }
_asyncDelivery.execute(runner);
}
}
- public void removeExpiredIfNoSubscribers() throws AMQException
+ public void checkMessageStatus() throws AMQException
{
- final StoreContext storeContext = new StoreContext();
-
QueueEntryIterator queueListIterator = _entries.iterator();
while (queueListIterator.advance())
{
QueueEntry node = queueListIterator.getNode();
- if (!node.isDeleted() && node.expired() && node.acquire())
+ // Only process nodes that are not currently deleted
+ if (!node.isDeleted())
{
-
- node.discard(storeContext);
+ // If the node has exired then aquire it
+ if (node.expired() && node.acquire())
+ {
+ // Then dequeue it.
+ dequeueEntry(node);
+ }
+ else
+ {
+ if (_managedObject != null)
+ {
+ // There is a chance that the node could be deleted by
+ // the time the check actually occurs. So verify we
+ // can actually get the message to perform the check.
+ ServerMessage msg = node.getMessage();
+ if (msg != null)
+ {
+ _managedObject.checkForNotification(msg);
+ }
+ }
+ }
}
-
}
}
@@ -1576,6 +1802,33 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
}
}
+ public long getCapacity()
+ {
+ return _capacity;
+ }
+
+ public void setCapacity(long capacity)
+ {
+ _capacity = capacity;
+ }
+
+ public long getFlowResumeCapacity()
+ {
+ return _flowResumeCapacity;
+ }
+
+ public void setFlowResumeCapacity(long flowResumeCapacity)
+ {
+ _flowResumeCapacity = flowResumeCapacity;
+
+ checkCapacity();
+ }
+
+ public boolean isOverfull()
+ {
+ return _overfull.get();
+ }
+
public Set<NotificationCheck> getNotificationChecks()
{
return _notificationChecks;
@@ -1588,23 +1841,22 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
private final class QueueEntryListener implements QueueEntry.StateChangeListener
{
- private final QueueEntry _entry;
+
private final Subscription _sub;
- public QueueEntryListener(final Subscription sub, final QueueEntry entry)
+ public QueueEntryListener(final Subscription sub)
{
- _entry = entry;
_sub = sub;
}
public boolean equals(Object o)
{
- return _entry == ((QueueEntryListener) o)._entry && _sub == ((QueueEntryListener) o)._sub;
+ return _sub == ((QueueEntryListener) o)._sub;
}
public int hashCode()
{
- return System.identityHashCode(_entry) ^ System.identityHashCode(_sub);
+ return System.identityHashCode(_sub);
}
public void stateChanged(QueueEntry entry, QueueEntry.State oldSate, QueueEntry.State newState)
@@ -1631,8 +1883,45 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
for (int i = 0; i < num && !it.atTail(); i++)
{
it.advance();
- ids.add(it.getNode().getMessage().getMessageId());
+ ids.add(it.getNode().getMessage().getMessageNumber());
}
return ids;
}
-} \ No newline at end of file
+
+ public Object getExclusiveOwner()
+ {
+ return _exclusiveOwner;
+ }
+
+ public void setExclusiveOwner(Object exclusiveOwner)
+ {
+ _exclusiveOwner = exclusiveOwner;
+ }
+
+
+ public void configure(QueueConfiguration config)
+ {
+ if (config != null)
+ {
+ setMaximumMessageAge(config.getMaximumMessageAge());
+ setMaximumQueueDepth(config.getMaximumQueueDepth());
+ setMaximumMessageSize(config.getMaximumMessageSize());
+ setMaximumMessageCount(config.getMaximumMessageCount());
+ setMinimumAlertRepeatGap(config.getMinimumAlertRepeatGap());
+ _capacity = config.getCapacity();
+ _flowResumeCapacity = config.getFlowResumeCapacity();
+ }
+ }
+
+ public String getResourceName()
+ {
+ return _resourceName;
+ }
+
+
+ @Override
+ public String toString()
+ {
+ return String.valueOf(getName());
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java b/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java
index a46c5ae2e8..d27a5ed234 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java
@@ -1,6 +1,10 @@
package org.apache.qpid.server.queue;
+import org.apache.qpid.server.message.InboundMessage;
+import org.apache.qpid.server.message.ServerMessage;
+
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+import java.util.concurrent.atomic.AtomicLong;
/*
*
@@ -24,6 +28,7 @@ import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
*/
public class SimpleQueueEntryList implements QueueEntryList
{
+
private final QueueEntryImpl _head;
private volatile QueueEntryImpl _tail;
@@ -40,9 +45,7 @@ public class SimpleQueueEntryList implements QueueEntryList
_nextUpdater =
AtomicReferenceFieldUpdater.newUpdater
(QueueEntryImpl.class, QueueEntryImpl.class, "_next");
-
-
-
+ private AtomicLong _deletes = new AtomicLong(0L);
public SimpleQueueEntryList(AMQQueue queue)
@@ -52,21 +55,77 @@ public class SimpleQueueEntryList implements QueueEntryList
_tail = _head;
}
+
+
void advanceHead()
{
+ _deletes.incrementAndGet();
QueueEntryImpl head = _head.nextNode();
+ boolean deleted = head.isDeleted();
while(head._next != null && head.isDeleted())
{
+ deleted = true;
final QueueEntryImpl newhead = head.nextNode();
if(newhead != null)
{
- _nextUpdater.compareAndSet(_head,head, newhead);
+ if(_nextUpdater.compareAndSet(_head,head, newhead))
+ {
+ _deletes.decrementAndGet();
+ }
}
head = _head.nextNode();
}
+
+ if(!deleted)
+ {
+ deleted = true;
+ }
+
+ if(_deletes.get() > 1000L)
+ {
+ _deletes.set(0L);
+ scavenge();
+ }
}
+ void scavenge()
+ {
+ QueueEntryImpl root = _head;
+ QueueEntryImpl next = root.nextNode();
+
+ do
+ {
+
+
+ while(next._next != null && next.isDeleted())
+ {
+
+ final QueueEntryImpl newhead = next.nextNode();
+ if(newhead != null)
+ {
+ _nextUpdater.compareAndSet(root,next, newhead);
+ }
+ next = root.nextNode();
+ }
+ if(next._next != null)
+ {
+ if(!next.isDeleted())
+ {
+ root = next;
+ next = root.nextNode();
+ }
+ }
+ else
+ {
+ break;
+ }
+
+ } while (next != null && next._next != null);
+
+ }
+
+
public AMQQueue getQueue()
{
@@ -74,7 +133,7 @@ public class SimpleQueueEntryList implements QueueEntryList
}
- public QueueEntry add(AMQMessage message)
+ public QueueEntry add(ServerMessage message)
{
QueueEntryImpl node = new QueueEntryImpl(this, message);
for (;;)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java b/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java
new file mode 100755
index 0000000000..547365f647
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java
@@ -0,0 +1,68 @@
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.pool.ReadWriteRunnable;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.AMQException;
+import org.apache.log4j.Logger;
+
+
+class SubFlushRunner implements ReadWriteRunnable
+{
+ private static final Logger _logger = Logger.getLogger(SimpleAMQQueue.class);
+
+
+ private final Subscription _sub;
+ private final String _name;
+ private static final long ITERATIONS = SimpleAMQQueue.MAX_ASYNC_DELIVERIES;
+
+ public SubFlushRunner(Subscription sub)
+ {
+ _sub = sub;
+ _name = "SubFlushRunner-"+_sub;
+ }
+
+ public void run()
+ {
+
+
+ Thread.currentThread().setName(_name);
+
+ boolean complete = false;
+ try
+ {
+ CurrentActor.set(_sub.getLogActor());
+ complete = getQueue().flushSubscription(_sub, ITERATIONS);
+
+ }
+ catch (AMQException e)
+ {
+ _logger.error(e);
+ }
+ finally
+ {
+ CurrentActor.remove();
+ }
+ if (!complete && !_sub.isSuspended())
+ {
+ getQueue().execute(this);
+ }
+
+
+ }
+
+ private SimpleAMQQueue getQueue()
+ {
+ return (SimpleAMQQueue) _sub.getQueue();
+ }
+
+ public boolean isRead()
+ {
+ return false;
+ }
+
+ public boolean isWrite()
+ {
+ return true;
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java b/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java
deleted file mode 100644
index 9b91c71a1d..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java
+++ /dev/null
@@ -1,127 +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.
- *
- */
-package org.apache.qpid.server.queue;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Collections;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.framing.BasicContentHeaderProperties;
-import org.apache.qpid.framing.ContentHeaderBody;
-
-/**
- * Contains data that is only used in AMQMessage transiently, e.g. while the content
- * body fragments are arriving.
- *
- * Having this data stored in a separate class means that the AMQMessage class avoids
- * the small overhead of numerous guaranteed-null references.
- *
- * @author Apache Software Foundation
- */
-public class TransientMessageData
-{
- /**
- * Stored temporarily until the header has been received at which point it is used when
- * constructing the handle
- */
- private MessagePublishInfo _messagePublishInfo;
-
- /**
- * Also stored temporarily.
- */
- private ContentHeaderBody _contentHeaderBody;
-
- /**
- * Keeps a track of how many bytes we have received in body frames
- */
- private long _bodyLengthReceived = 0;
-
- /**
- * This is stored during routing, to know the queues to which this message should immediately be
- * delivered. It is <b>cleared after delivery has been attempted</b>. Any persistent record of destinations is done
- * by the message handle.
- */
- private List<AMQQueue> _destinationQueues;
-
- public MessagePublishInfo getMessagePublishInfo()
- {
- return _messagePublishInfo;
- }
-
- public void setMessagePublishInfo(MessagePublishInfo messagePublishInfo)
- {
- _messagePublishInfo = messagePublishInfo;
- }
-
- public List<AMQQueue> getDestinationQueues()
- {
- return _destinationQueues == null ? (List<AMQQueue>) Collections.EMPTY_LIST : _destinationQueues;
- }
-
- public void setDestinationQueues(List<AMQQueue> destinationQueues)
- {
- _destinationQueues = destinationQueues;
- }
-
- public ContentHeaderBody getContentHeaderBody()
- {
- return _contentHeaderBody;
- }
-
- public void setContentHeaderBody(ContentHeaderBody contentHeaderBody)
- {
- _contentHeaderBody = contentHeaderBody;
- }
-
- public long getBodyLengthReceived()
- {
- return _bodyLengthReceived;
- }
-
- public void addBodyLength(int value)
- {
- _bodyLengthReceived += value;
- }
-
- public boolean isAllContentReceived() throws AMQException
- {
- return _bodyLengthReceived == _contentHeaderBody.bodySize;
- }
-
- public void addDestinationQueue(AMQQueue queue)
- {
- if(_destinationQueues == null)
- {
- _destinationQueues = new ArrayList<AMQQueue>();
- }
- _destinationQueues.add(queue);
- }
-
- public boolean isPersistent()
- {
- //todo remove literal values to a constant file such as AMQConstants in common
- return _contentHeaderBody.properties instanceof BasicContentHeaderProperties &&
- ((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == 2;
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java
deleted file mode 100644
index 3ed8b0e55c..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java
+++ /dev/null
@@ -1,219 +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.
- *
- */
-package org.apache.qpid.server.queue;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.ContentHeaderBody;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.framing.abstraction.ContentChunk;
-import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.StoreContext;
-
-/**
- * @author Robert Greig (robert.j.greig@jpmorgan.com)
- */
-public class WeakReferenceMessageHandle implements AMQMessageHandle
-{
- private WeakReference<ContentHeaderBody> _contentHeaderBody;
-
- private WeakReference<MessagePublishInfo> _messagePublishInfo;
-
- private List<WeakReference<ContentChunk>> _contentBodies;
-
- private boolean _redelivered;
-
- private final MessageStore _messageStore;
-
- private final Long _messageId;
- private long _arrivalTime;
-
- public WeakReferenceMessageHandle(final Long messageId, MessageStore messageStore)
- {
- _messageId = messageId;
- _messageStore = messageStore;
- }
-
- public ContentHeaderBody getContentHeaderBody(StoreContext context) throws AMQException
- {
- ContentHeaderBody chb = (_contentHeaderBody != null ? _contentHeaderBody.get() : null);
- if (chb == null)
- {
- MessageMetaData mmd = loadMessageMetaData(context);
- chb = mmd.getContentHeaderBody();
- }
- return chb;
- }
-
- public Long getMessageId()
- {
- return _messageId;
- }
-
- private MessageMetaData loadMessageMetaData(StoreContext context)
- throws AMQException
- {
- MessageMetaData mmd = _messageStore.getMessageMetaData(context, _messageId);
- populateFromMessageMetaData(mmd);
- return mmd;
- }
-
- private void populateFromMessageMetaData(MessageMetaData mmd)
- {
- _arrivalTime = mmd.getArrivalTime();
- _contentHeaderBody = new WeakReference<ContentHeaderBody>(mmd.getContentHeaderBody());
- _messagePublishInfo = new WeakReference<MessagePublishInfo>(mmd.getMessagePublishInfo());
- }
-
- public int getBodyCount(StoreContext context) throws AMQException
- {
- if (_contentBodies == null)
- {
- MessageMetaData mmd = _messageStore.getMessageMetaData(context, _messageId);
- int chunkCount = mmd.getContentChunkCount();
- _contentBodies = new ArrayList<WeakReference<ContentChunk>>(chunkCount);
- for (int i = 0; i < chunkCount; i++)
- {
- _contentBodies.add(new WeakReference<ContentChunk>(null));
- }
- }
- return _contentBodies.size();
- }
-
- public long getBodySize(StoreContext context) throws AMQException
- {
- return getContentHeaderBody(context).bodySize;
- }
-
- public ContentChunk getContentChunk(StoreContext context, int index) throws AMQException, IllegalArgumentException
- {
- if (index > _contentBodies.size() - 1)
- {
- throw new IllegalArgumentException("Index " + index + " out of valid range 0 to " +
- (_contentBodies.size() - 1));
- }
- WeakReference<ContentChunk> wr = _contentBodies.get(index);
- ContentChunk cb = wr.get();
- if (cb == null)
- {
- cb = _messageStore.getContentBodyChunk(context, _messageId, index);
- _contentBodies.set(index, new WeakReference<ContentChunk>(cb));
- }
- return cb;
- }
-
- /**
- * Content bodies are set <i>before</i> the publish and header frames
- *
- * @param storeContext
- * @param contentChunk
- * @param isLastContentBody
- * @throws AMQException
- */
- public void addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk, boolean isLastContentBody) throws AMQException
- {
- if (_contentBodies == null && isLastContentBody)
- {
- _contentBodies = new ArrayList<WeakReference<ContentChunk>>(1);
- }
- else
- {
- if (_contentBodies == null)
- {
- _contentBodies = new LinkedList<WeakReference<ContentChunk>>();
- }
- }
- _contentBodies.add(new WeakReference<ContentChunk>(contentChunk));
- _messageStore.storeContentBodyChunk(storeContext, _messageId, _contentBodies.size() - 1,
- contentChunk, isLastContentBody);
- }
-
- public MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException
- {
- MessagePublishInfo bpb = (_messagePublishInfo != null ? _messagePublishInfo.get() : null);
- if (bpb == null)
- {
- MessageMetaData mmd = loadMessageMetaData(context);
-
- bpb = mmd.getMessagePublishInfo();
- }
- return bpb;
- }
-
- public boolean isRedelivered()
- {
- return _redelivered;
- }
-
- public void setRedelivered(boolean redelivered)
- {
- _redelivered = redelivered;
- }
-
- public boolean isPersistent()
- {
- return true;
- }
-
- /**
- * This is called when all the content has been received.
- *
- * @param publishBody
- * @param contentHeaderBody
- * @throws AMQException
- */
- public void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo publishBody,
- ContentHeaderBody contentHeaderBody)
- throws AMQException
- {
- // if there are no content bodies the list will be null so we must
- // create en empty list here
- if (contentHeaderBody.bodySize == 0)
- {
- _contentBodies = new LinkedList<WeakReference<ContentChunk>>();
- }
-
- final long arrivalTime = System.currentTimeMillis();
-
-
- MessageMetaData mmd = new MessageMetaData(publishBody, contentHeaderBody, _contentBodies.size(), arrivalTime);
-
- _messageStore.storeMessageMetaData(storeContext, _messageId, mmd);
-
-
- populateFromMessageMetaData(mmd);
- }
-
- public void removeMessage(StoreContext storeContext) throws AMQException
- {
- _messageStore.removeMessage(storeContext, _messageId);
- }
-
- public long getArrivalTime()
- {
- return _arrivalTime;
- }
-
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
index 63171d583a..5cb379f10d 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
@@ -20,21 +20,24 @@
*/
package org.apache.qpid.server.registry;
-import org.apache.commons.configuration.Configuration;
+import java.net.InetSocketAddress;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.configuration.ConfigurationException;
import org.apache.log4j.Logger;
-import org.apache.qpid.server.configuration.Configurator;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
+import org.apache.qpid.server.configuration.ServerConfiguration;
import org.apache.qpid.server.management.ManagedObjectRegistry;
-import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
-import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager;
-import org.apache.qpid.server.security.access.ACLPlugin;
import org.apache.qpid.server.plugins.PluginManager;
-import org.apache.mina.common.IoAcceptor;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.net.InetSocketAddress;
+import org.apache.qpid.server.security.access.ACLManager;
+import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager;
+import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
+import org.apache.qpid.server.logging.RootMessageLogger;
+import org.apache.qpid.server.logging.messages.BrokerMessages;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.transport.QpidAcceptor;
/**
* An abstract application registry that provides access to configuration information and handles the
@@ -50,13 +53,13 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
private final Map<Class<?>, Object> _configuredObjects = new HashMap<Class<?>, Object>();
- protected final Configuration _configuration;
+ protected final ServerConfiguration _configuration;
public static final int DEFAULT_INSTANCE = 1;
public static final String DEFAULT_APPLICATION_REGISTRY = "org.apache.qpid.server.util.NullApplicationRegistry";
public static String _APPLICATION_REGISTRY = DEFAULT_APPLICATION_REGISTRY;
- protected final Map<InetSocketAddress, IoAcceptor> _acceptors = new HashMap<InetSocketAddress, IoAcceptor>();
+ protected final Map<InetSocketAddress, QpidAcceptor> _acceptors = new HashMap<InetSocketAddress, QpidAcceptor>();
protected ManagedObjectRegistry _managedObjectRegistry;
@@ -64,12 +67,14 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
protected VirtualHostRegistry _virtualHostRegistry;
- protected ACLPlugin _accessManager;
+ protected ACLManager _accessManager;
protected PrincipalDatabaseManager _databaseManager;
protected PluginManager _pluginManager;
+ protected RootMessageLogger _rootMessageLogger;
+
static
{
Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownService()));
@@ -97,7 +102,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
try
{
- instance.initialise();
+ instance.initialise(instanceID);
}
catch (Exception e)
{
@@ -111,12 +116,29 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
}
}
+ public static boolean isConfigured()
+ {
+ return isConfigured(DEFAULT_INSTANCE);
+ }
+
+ public static boolean isConfigured(int instanceID)
+ {
+ return _instanceMap.containsKey(instanceID);
+ }
+
+ /**
+ * Method to cleanly shutdown the default registry running in this JVM
+ */
+ public static void remove()
+ {
+ remove(DEFAULT_INSTANCE);
+ }
+
/**
* Method to cleanly shutdown specified registry running in this JVM
*
* @param instanceID the instance to shutdown
*/
-
public static void remove(int instanceID)
{
try
@@ -151,7 +173,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
}
}
- protected ApplicationRegistry(Configuration configuration)
+ protected ApplicationRegistry(ServerConfiguration configuration)
{
_configuration = configuration;
}
@@ -207,11 +229,26 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
virtualHost.close();
}
+ // Replace above with this
+// _virtualHostRegistry.close();
+
+// _accessManager.close();
+
+// _databaseManager.close();
+
+ _authenticationManager.close();
+
+// _databaseManager.close();
+
// close the rmi registry(if any) started for management
- if (getManagedObjectRegistry() != null)
+ if (_managedObjectRegistry != null)
{
- getManagedObjectRegistry().close();
+ _managedObjectRegistry.close();
}
+
+// _pluginManager.close();
+
+ CurrentActor.get().message(BrokerMessages.BRK_STOPPED());
}
private void unbind()
@@ -220,18 +257,19 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
{
for (InetSocketAddress bindAddress : _acceptors.keySet())
{
- IoAcceptor acceptor = _acceptors.get(bindAddress);
- acceptor.unbind(bindAddress);
+ QpidAcceptor acceptor = _acceptors.get(bindAddress);
+ acceptor.getNetworkDriver().close();
+ CurrentActor.get().message(BrokerMessages.BRK_SHUTTING_DOWN(acceptor.toString(), bindAddress.getPort()));
}
}
}
- public Configuration getConfiguration()
+ public ServerConfiguration getConfiguration()
{
return _configuration;
}
- public void addAcceptor(InetSocketAddress bindAddress, IoAcceptor acceptor)
+ public void addAcceptor(InetSocketAddress bindAddress, QpidAcceptor acceptor)
{
synchronized (_acceptors)
{
@@ -239,26 +277,6 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
}
}
- public <T> T getConfiguredObject(Class<T> instanceType)
- {
- T instance = (T) _configuredObjects.get(instanceType);
- if (instance == null)
- {
- try
- {
- instance = instanceType.newInstance();
- }
- catch (Exception e)
- {
- _logger.error("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor");
- throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor", e);
- }
- Configurator.configure(instance);
- _configuredObjects.put(instanceType, instance);
- }
- return instance;
- }
-
public static void setDefaultApplicationRegistry(String clazz)
{
_APPLICATION_REGISTRY = clazz;
@@ -269,9 +287,9 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
return _virtualHostRegistry;
}
- public ACLPlugin getAccessManager()
+ public ACLManager getAccessManager() throws ConfigurationException
{
- return _accessManager;
+ return new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager);
}
public ManagedObjectRegistry getManagedObjectRegistry()
@@ -294,4 +312,9 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
return _pluginManager;
}
+ public RootMessageLogger getRootMessageLogger()
+ {
+ return _rootMessageLogger;
+ }
+
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java
index baab56a4a4..f325b53dfb 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java
@@ -20,82 +20,54 @@
*/
package org.apache.qpid.server.registry;
-import java.io.File;
-import java.util.Collection;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.commons.configuration.CompositeConfiguration;
-import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
-import org.apache.commons.configuration.SystemConfiguration;
-import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.common.QpidProperties;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.logging.RootMessageLoggerImpl;
+import org.apache.qpid.server.logging.messages.BrokerMessages;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.BrokerActor;
+import org.apache.qpid.server.logging.rawloggers.Log4jMessageLogger;
import org.apache.qpid.server.management.JMXManagedObjectRegistry;
-import org.apache.qpid.server.management.ManagedObjectRegistry;
-import org.apache.qpid.server.management.ManagementConfiguration;
import org.apache.qpid.server.management.NoopManagedObjectRegistry;
import org.apache.qpid.server.plugins.PluginManager;
-import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
+import org.apache.qpid.server.security.access.ACLManager;
import org.apache.qpid.server.security.auth.database.ConfigurationFilePrincipalDatabaseManager;
-import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager;
import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager;
-import org.apache.qpid.server.security.access.ACLPlugin;
-import org.apache.qpid.server.security.access.ACLManager;
-import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
-import org.apache.qpid.AMQException;
+import org.apache.qpid.server.virtualhost.VirtualHostImpl;
+
+import java.io.File;
public class ConfigurationFileApplicationRegistry extends ApplicationRegistry
{
-
+ private String _registryName;
public ConfigurationFileApplicationRegistry(File configurationURL) throws ConfigurationException
{
- super(config(configurationURL));
+ super(new ServerConfiguration(configurationURL));
}
- // Our configuration class needs to make the interpolate method
- // public so it can be called below from the config method.
- private static class MyConfiguration extends CompositeConfiguration
+ public void initialise(int instanceID) throws Exception
{
- public String interpolate(String obj)
- {
- return super.interpolate(obj);
- }
- }
+ _rootMessageLogger = new RootMessageLoggerImpl(_configuration,
+ new Log4jMessageLogger());
- private static final Configuration config(File url) throws ConfigurationException
- {
- // We have to override the interpolate methods so that
- // interpolation takes place accross the entirety of the
- // composite configuration. Without doing this each
- // configuration object only interpolates variables defined
- // inside itself.
- final MyConfiguration conf = new MyConfiguration();
- conf.addConfiguration(new SystemConfiguration()
- {
- protected String interpolate(String o)
- {
- return conf.interpolate(o);
- }
- });
- conf.addConfiguration(new XMLConfiguration(url)
- {
- protected String interpolate(String o)
- {
- return conf.interpolate(o);
- }
- });
- return conf;
- }
+ _registryName = String.valueOf(instanceID);
+
+ // Set the Actor for current log messages
+ CurrentActor.set(new BrokerActor(_registryName, _rootMessageLogger));
+
+ CurrentActor.get().message(BrokerMessages.BRK_STARTUP(QpidProperties.getReleaseVersion(),QpidProperties.getBuildVersion()));
- public void initialise() throws Exception
- {
initialiseManagedObjectRegistry();
- _virtualHostRegistry = new VirtualHostRegistry();
+ _virtualHostRegistry = new VirtualHostRegistry(this);
- _accessManager = ACLManager.loadACLManager("default", _configuration);
+ _pluginManager = new PluginManager(_configuration.getPluginDirectory());
+
+ _accessManager = new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager);
_databaseManager = new ConfigurationFilePrincipalDatabaseManager(_configuration);
@@ -105,25 +77,39 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry
_managedObjectRegistry.start();
- _pluginManager = new PluginManager(_configuration.getString("plugin-directory"));
-
initialiseVirtualHosts();
+ // Startup complete pop the current actor
+ CurrentActor.remove();
}
- private void initialiseVirtualHosts() throws Exception
+ @Override
+ public void close() throws Exception
{
- for (String name : getVirtualHostNames())
+ //Set the Actor for Broker Shutdown
+ CurrentActor.set(new BrokerActor(_registryName, _rootMessageLogger));
+ try
+ {
+ super.close();
+ }
+ finally
{
+ CurrentActor.remove();
+ }
+ }
- _virtualHostRegistry.registerVirtualHost(new VirtualHost(name, getConfiguration().subset("virtualhosts.virtualhost." + name)));
+ private void initialiseVirtualHosts() throws Exception
+ {
+ for (String name : _configuration.getVirtualHosts())
+ {
+ _virtualHostRegistry.registerVirtualHost(new VirtualHostImpl(_configuration.getVirtualHostConfig(name)));
}
+ getVirtualHostRegistry().setDefaultVirtualHostName(_configuration.getDefaultVirtualHost());
}
private void initialiseManagedObjectRegistry() throws AMQException
{
- ManagementConfiguration config = getConfiguredObject(ManagementConfiguration.class);
- if (config.enabled)
+ if (_configuration.getManagementEnabled())
{
_managedObjectRegistry = new JMXManagedObjectRegistry();
}
@@ -132,10 +118,4 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry
_managedObjectRegistry = new NoopManagedObjectRegistry();
}
}
-
- public Collection<String> getVirtualHostNames()
- {
- return getConfiguration().getList("virtualhosts.virtualhost.name");
- }
-
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java
index 597ef042f9..92accb3499 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java
@@ -24,12 +24,17 @@ import java.util.Collection;
import java.net.InetSocketAddress;
import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.server.configuration.ServerConfiguration;
import org.apache.qpid.server.management.ManagedObjectRegistry;
import org.apache.qpid.server.plugins.PluginManager;
import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager;
+import org.apache.qpid.server.security.access.ACLManager;
import org.apache.qpid.server.security.access.ACLPlugin;
import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
+import org.apache.qpid.server.logging.RootMessageLogger;
+import org.apache.qpid.server.transport.QpidAcceptor;
import org.apache.mina.common.IoAcceptor;
public interface IApplicationRegistry
@@ -38,8 +43,9 @@ public interface IApplicationRegistry
* Initialise the application registry. All initialisation must be done in this method so that any components
* that need access to the application registry itself for initialisation are able to use it. Attempting to
* initialise in the constructor will lead to failures since the registry reference will not have been set.
+ * @param instanceID the instanceID that we can use to identify this AR.
*/
- void initialise() throws Exception;
+ void initialise(int instanceID) throws Exception;
/**
* Shutdown this Registry
@@ -48,21 +54,11 @@ public interface IApplicationRegistry
void close() throws Exception;
/**
- * This gets access to a "configured object". A configured object has fields populated from a the configuration
- * object (Commons Configuration) automatically, where it has the appropriate attributes defined on fields.
- * Application registry implementations can choose the refresh strategy or caching approach.
- * @param instanceType the type of object you want initialised. This must be unique - i.e. you can only
- * have a single object of this type in the system.
- * @return the configured object
- */
- <T> T getConfiguredObject(Class<T> instanceType);
-
- /**
* Get the low level configuration. For use cases where the configured object approach is not required
* you can get the complete configuration information.
* @return a Commons Configuration instance
*/
- Configuration getConfiguration();
+ ServerConfiguration getConfiguration();
ManagedObjectRegistry getManagedObjectRegistry();
@@ -70,19 +66,19 @@ public interface IApplicationRegistry
AuthenticationManager getAuthenticationManager();
- Collection<String> getVirtualHostNames();
-
VirtualHostRegistry getVirtualHostRegistry();
- ACLPlugin getAccessManager();
+ ACLManager getAccessManager() throws ConfigurationException;
PluginManager getPluginManager();
+ RootMessageLogger getRootMessageLogger();
+
/**
* Register any acceptors for this registry
* @param bindAddress The address that the acceptor has been bound with
* @param acceptor The acceptor in use
*/
- void addAcceptor(InetSocketAddress bindAddress, IoAcceptor acceptor);
+ void addAcceptor(InetSocketAddress bindAddress, QpidAcceptor acceptor);
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/PrincipalHolder.java b/java/broker/src/main/java/org/apache/qpid/server/security/PrincipalHolder.java
new file mode 100755
index 0000000000..7e93623cab
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/PrincipalHolder.java
@@ -0,0 +1,29 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security;
+
+import java.security.Principal;
+
+public interface PrincipalHolder
+{
+ /** @return a Principal that was used to authorized this session */
+ Principal getPrincipal();
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java
index 539f32a732..7d6ae285c5 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java
@@ -14,148 +14,310 @@
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
- * under the License.
+ * under the License.
+ *
*
- *
*/
package org.apache.qpid.server.security.access;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.security.access.plugins.DenyAll;
-import org.apache.qpid.configuration.PropertyUtils;
import org.apache.log4j.Logger;
-
-import java.util.List;
-import java.lang.reflect.Method;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.configuration.SecurityConfiguration;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.plugins.PluginManager;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult;
+import org.apache.qpid.server.security.PrincipalHolder;
+import org.apache.qpid.server.virtualhost.VirtualHost;
public class ACLManager
{
private static final Logger _logger = Logger.getLogger(ACLManager.class);
+ private PluginManager _pluginManager;
+ private Map<String, ACLPluginFactory> _allSecurityPlugins = new HashMap<String, ACLPluginFactory>();
+ private Map<String, ACLPlugin> _globalPlugins = new HashMap<String, ACLPlugin>();
+ private Map<String, ACLPlugin> _hostPlugins = new HashMap<String, ACLPlugin>();
- public static ACLPlugin loadACLManager(String name, Configuration hostConfig) throws ConfigurationException
+ public ACLManager(SecurityConfiguration configuration, PluginManager manager) throws ConfigurationException
{
- ACLPlugin aclPlugin = ApplicationRegistry.getInstance().getAccessManager();
+ this(configuration, manager, null);
+ }
- if (hostConfig == null)
+ public ACLManager(SecurityConfiguration configuration, PluginManager manager, ACLPluginFactory securityPlugin) throws ConfigurationException
+ {
+ _pluginManager = manager;
+
+ if (manager == null) // No plugin manager, no plugins
{
- _logger.warn("No Configuration specified. Using default ACLPlugin '" + aclPlugin.getPluginName()
- + "' for VirtualHost:'" + name + "'");
- return aclPlugin;
+ return;
}
- String accessClass = hostConfig.getString("security.access.class");
- if (accessClass == null)
+ _allSecurityPlugins = _pluginManager.getSecurityPlugins();
+ if (securityPlugin != null)
{
-
- _logger.warn("No ACL Plugin specified. Using default ACL Plugin '" + aclPlugin.getPluginName() +
- "' for VirtualHost:'" + name + "'");
- return aclPlugin;
+ _allSecurityPlugins.put(securityPlugin.getClass().getName(), securityPlugin);
}
- Object o;
- try
+ configureGlobalPlugins(configuration);
+ }
+
+ public void configureHostPlugins(SecurityConfiguration hostConfig) throws ConfigurationException
+ {
+ _hostPlugins = configurePlugins(hostConfig);
+ }
+
+ public void configureGlobalPlugins(SecurityConfiguration configuration) throws ConfigurationException
+ {
+ _globalPlugins = configurePlugins(configuration);
+ }
+
+ public Map<String, ACLPlugin> configurePlugins(SecurityConfiguration hostConfig) throws ConfigurationException
+ {
+ Configuration securityConfig = hostConfig.getConfiguration();
+ Map<String, ACLPlugin> plugins = new HashMap<String, ACLPlugin>();
+ Iterator keys = securityConfig.getKeys();
+ Collection<String> handledTags = new HashSet();
+ while (keys.hasNext())
{
- o = Class.forName(accessClass).newInstance();
+ // Splitting the string is necessary here because of the way that getKeys() returns only
+ // bottom level children
+ String tag = ((String) keys.next()).split("\\.", 2)[0];
+ if (!handledTags.contains(tag))
+ {
+ for (ACLPluginFactory plugin : _allSecurityPlugins.values())
+ {
+ if (plugin.supportsTag(tag))
+ {
+ _logger.info("Plugin handling security section "+tag+" is "+plugin);
+ handledTags.add(tag);
+ plugins.put(plugin.getClass().getName(), plugin.newInstance(securityConfig));
+ }
+ }
+ }
+ if (!handledTags.contains(tag))
+ {
+ _logger.warn("No plugin handled security section "+tag);
+ }
}
- catch (Exception e)
+ return plugins;
+ }
+
+ public static Logger getLogger()
+ {
+ return _logger;
+ }
+
+ private abstract class AccessCheck
+ {
+ abstract AuthzResult allowed(ACLPlugin plugin);
+ }
+
+ private boolean checkAllPlugins(AccessCheck checker)
+ {
+ AuthzResult result = AuthzResult.ABSTAIN;
+ HashMap<String, ACLPlugin> remainingPlugins = new HashMap<String, ACLPlugin>();
+ remainingPlugins.putAll(_globalPlugins);
+ for (Entry<String, ACLPlugin> plugin : _hostPlugins.entrySet())
{
- throw new ConfigurationException("Error initialising ACL: " + e, e);
+ result = checker.allowed(plugin.getValue());
+ if (result == AuthzResult.DENIED)
+ {
+ // Something vetoed the access, we're done
+ return false;
+ }
+ else if (result == AuthzResult.ALLOWED)
+ {
+ // Remove plugin from global check list since
+ // host allow overrides global allow
+ remainingPlugins.remove(plugin.getKey());
+ }
}
- if (!(o instanceof ACLPlugin))
+ for (ACLPlugin plugin : remainingPlugins.values())
{
- throw new ConfigurationException("ACL Plugins must implement the ACLPlugin interface");
+ result = checker.allowed(plugin);
+ if (result == AuthzResult.DENIED)
+ {
+ return false;
+ }
}
+ return true;
+ }
- initialiseAccessControl((ACLPlugin) o, hostConfig);
-
- aclPlugin = getManager((ACLPlugin) o);
- if (_logger.isInfoEnabled())
+ public boolean authoriseBind(final PrincipalHolder session, final Exchange exch, final AMQQueue queue,
+ final AMQShortString routingKey)
+ {
+ return checkAllPlugins(new AccessCheck()
{
- _logger.info("Initialised ACL Plugin '" + aclPlugin.getPluginName()
- + "' for virtualhost '" + name + "' successfully");
- }
- return aclPlugin;
- }
+ @Override
+ AuthzResult allowed(ACLPlugin plugin)
+ {
+ return plugin.authoriseBind(session, exch, queue, routingKey);
+ }
+ });
+ }
- private static void initialiseAccessControl(ACLPlugin accessManager, Configuration config)
- throws ConfigurationException
+ public boolean authoriseConnect(final PrincipalHolder session, final VirtualHost virtualHost)
{
- //First provide the ACLPlugin with the host configuration
+ return checkAllPlugins(new AccessCheck()
+ {
- accessManager.setConfiguaration(config);
+ @Override
+ AuthzResult allowed(ACLPlugin plugin)
+ {
+ return plugin.authoriseConnect(session, virtualHost);
+ }
+
+ });
+ }
- //Provide additional attribute customisation.
- String baseName = "security.access.attributes.attribute.";
- List<String> argumentNames = config.getList(baseName + "name");
- List<String> argumentValues = config.getList(baseName + "value");
- for (int i = 0; i < argumentNames.size(); i++)
+ public boolean authoriseConsume(final PrincipalHolder session, final boolean noAck, final AMQQueue queue)
+ {
+ return checkAllPlugins(new AccessCheck()
{
- String argName = argumentNames.get(i);
- if (argName == null || argName.length() == 0)
+
+ @Override
+ AuthzResult allowed(ACLPlugin plugin)
{
- throw new ConfigurationException("Access Control argument names must have length >= 1 character");
+ return plugin.authoriseConsume(session, noAck, queue);
}
- if (Character.isLowerCase(argName.charAt(0)))
+
+ });
+ }
+
+ public boolean authoriseConsume(final PrincipalHolder session, final boolean exclusive, final boolean noAck,
+ final boolean noLocal, final boolean nowait, final AMQQueue queue)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+
+ @Override
+ AuthzResult allowed(ACLPlugin plugin)
{
- argName = Character.toUpperCase(argName.charAt(0)) + argName.substring(1);
+ return plugin.authoriseConsume(session, exclusive, noAck, noLocal, nowait, queue);
}
- String methodName = "set" + argName;
- Method method = null;
- try
+
+ });
+ }
+
+ public boolean authoriseCreateExchange(final PrincipalHolder session, final boolean autoDelete,
+ final boolean durable, final AMQShortString exchangeName, final boolean internal, final boolean nowait,
+ final boolean passive, final AMQShortString exchangeType)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+
+ @Override
+ AuthzResult allowed(ACLPlugin plugin)
{
- method = accessManager.getClass().getMethod(methodName, String.class);
+ return plugin.authoriseCreateExchange(session, autoDelete, durable, exchangeName, internal, nowait,
+ passive, exchangeType);
}
- catch (NoSuchMethodException e)
+
+ });
+ }
+
+ public boolean authoriseCreateQueue(final PrincipalHolder session, final boolean autoDelete,
+ final boolean durable, final boolean exclusive, final boolean nowait, final boolean passive,
+ final AMQShortString queue)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+
+ @Override
+ AuthzResult allowed(ACLPlugin plugin)
{
- //do nothing as method will be null
+ return plugin.authoriseCreateQueue(session, autoDelete, durable, exclusive, nowait, passive, queue);
}
- if (method == null)
+ });
+ }
+
+ public boolean authoriseDelete(final PrincipalHolder session, final AMQQueue queue)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+
+ @Override
+ AuthzResult allowed(ACLPlugin plugin)
{
- throw new ConfigurationException("No method " + methodName + " found in class " + accessManager.getClass() +
- " hence unable to configure access control. The method must be public and " +
- "have a single String argument with a void return type");
+ return plugin.authoriseDelete(session, queue);
}
- try
+
+ });
+ }
+
+ public boolean authoriseDelete(final PrincipalHolder session, final Exchange exchange)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+
+ @Override
+ AuthzResult allowed(ACLPlugin plugin)
{
- method.invoke(accessManager, PropertyUtils.replaceProperties(argumentValues.get(i)));
+ return plugin.authoriseDelete(session, exchange);
}
- catch (Exception e)
+
+ });
+ }
+
+ public boolean authorisePublish(final PrincipalHolder session, final boolean immediate, final boolean mandatory,
+ final AMQShortString routingKey, final Exchange e)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+
+ @Override
+ AuthzResult allowed(ACLPlugin plugin)
{
- ConfigurationException ce = new ConfigurationException(e.getMessage(), e.getCause());
- ce.initCause(e);
- throw ce;
+ return plugin.authorisePublish(session, immediate, mandatory, routingKey, e);
}
- }
- }
+ });
+ }
- private static ACLPlugin getManager(ACLPlugin manager)
+ public boolean authorisePurge(final PrincipalHolder session, final AMQQueue queue)
{
- if (manager == null)
+ return checkAllPlugins(new AccessCheck()
{
- if (ApplicationRegistry.getInstance().getAccessManager() == null)
+
+ @Override
+ AuthzResult allowed(ACLPlugin plugin)
{
- return new DenyAll();
+ return plugin.authorisePurge(session, queue);
}
- else
+
+ });
+ }
+
+ public boolean authoriseUnbind(final PrincipalHolder session, final Exchange exch,
+ final AMQShortString routingKey, final AMQQueue queue)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+
+ @Override
+ AuthzResult allowed(ACLPlugin plugin)
{
- return ApplicationRegistry.getInstance().getAccessManager();
+ return plugin.authoriseUnbind(session, exch, routingKey, queue);
}
- }
- else
- {
- return manager;
- }
+
+ });
}
- public static Logger getLogger()
+ public void addHostPlugin(ACLPlugin aclPlugin)
{
- return _logger;
+ _hostPlugins.put(aclPlugin.getClass().getName(), aclPlugin);
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java
index 7855f147b4..cf8a3fede9 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java
@@ -20,39 +20,51 @@
*/
package org.apache.qpid.server.security.access;
-import org.apache.qpid.framing.AMQMethodBody;
-
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.AMQConnectionException;
import org.apache.commons.configuration.Configuration;
-
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.security.PrincipalHolder;
public interface ACLPlugin
{
- /**
- * Pseudo-Code:
- * Identify requested RighConnectiont
- * Lookup users ability for that right.
- * if rightsExists
- * Validate right on object
- * Return result
- * e.g
- * User, CONSUME , Queue
- * User, CONSUME , Exchange + RoutingKey
- * User, PUBLISH , Exchange + RoutingKey
- * User, CREATE , Exchange || Queue
- * User, BIND , Exchange + RoutingKey + Queue
- *
- * @param session - The session requesting access
- * @param permission - The permission requested
- * @param parameters - The above objects that are used to authorise the request.
- * @return The AccessResult decision
- */
- //todo potential refactor this ConnectionException Out of here
- AccessResult authorise(AMQProtocolSession session, Permission permission, AMQMethodBody body, Object... parameters) throws AMQConnectionException;
-
- String getPluginName();
-
- void setConfiguaration(Configuration config);
+ public enum AuthzResult
+ {
+ ALLOWED,
+ DENIED,
+ ABSTAIN
+ }
+
+ void setConfiguration(Configuration config) throws ConfigurationException;
+
+ // These return true if the plugin thinks the action should be allowed, and false if not.
+
+ AuthzResult authoriseBind(PrincipalHolder session, Exchange exch, AMQQueue queue, AMQShortString routingKey);
+
+ AuthzResult authoriseCreateExchange(PrincipalHolder session, boolean autoDelete, boolean durable,
+ AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType);
+
+ AuthzResult authoriseCreateQueue(PrincipalHolder session, boolean autoDelete, boolean durable, boolean exclusive,
+ boolean nowait, boolean passive, AMQShortString queue);
+
+ AuthzResult authoriseConnect(PrincipalHolder session, VirtualHost virtualHost);
+
+ AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck, AMQQueue queue);
+
+ AuthzResult authoriseConsume(PrincipalHolder session, boolean exclusive, boolean noAck, boolean noLocal,
+ boolean nowait, AMQQueue queue);
+
+ AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue);
+
+ AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange);
+
+ AuthzResult authorisePublish(PrincipalHolder session, boolean immediate, boolean mandatory,
+ AMQShortString routingKey, Exchange e);
+
+ AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue);
+
+ AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch, AMQShortString routingKey, AMQQueue queue);
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java
new file mode 100644
index 0000000000..256f093477
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java
@@ -0,0 +1,33 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.access;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+
+public interface ACLPluginFactory
+{
+
+ public boolean supportsTag(String name);
+
+ public ACLPlugin newInstance(Configuration config) throws ConfigurationException;
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java
index 86f155d862..d722da4ae0 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java
@@ -33,12 +33,12 @@ public class AccessResult
public AccessResult(ACLPlugin authorizer, AccessStatus status)
{
_status = status;
- _authorizer = authorizer.getPluginName();
+ _authorizer = authorizer.getClass().getSimpleName();
}
public void setAuthorizer(ACLPlugin authorizer)
{
- _authorizer += authorizer.getPluginName();
+ _authorizer += authorizer.getClass().getSimpleName();
}
public String getAuthorizer()
@@ -58,7 +58,7 @@ public class AccessResult
public void addAuthorizer(ACLPlugin accessManager)
{
- _authorizer = accessManager.getPluginName() + "->" + _authorizer;
+ _authorizer = accessManager.getClass().getSimpleName() + "->" + _authorizer;
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java
new file mode 100644
index 0000000000..9527120f30
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java
@@ -0,0 +1,6 @@
+package org.apache.qpid.server.security.access;
+
+public class AuthorizationManager
+{
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java
index 00757a4f8c..b65b0cdc6c 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java
@@ -28,7 +28,8 @@ public enum Permission
{
CONSUME,
PUBLISH,
- CREATE,
+ CREATEQUEUE,
+ CREATEEXCHANGE,
ACCESS,
BIND,
UNBIND,
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java
index 23073e0613..a299907e42 100755
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java
@@ -20,15 +20,17 @@
*/
package org.apache.qpid.server.security.access;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.QueueBindBody;
-import org.apache.qpid.framing.QueueDeclareBody;
-import org.apache.qpid.framing.ExchangeDeclareBody;
-import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.exchange.Exchange;
-
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult;
public class PrincipalPermissions
{
@@ -40,16 +42,17 @@ public class PrincipalPermissions
private static final Object CREATE_QUEUES_KEY = new Object();
private static final Object CREATE_EXCHANGES_KEY = new Object();
+
private static final Object CREATE_QUEUE_TEMPORARY_KEY = new Object();
private static final Object CREATE_QUEUE_QUEUES_KEY = new Object();
private static final Object CREATE_QUEUE_EXCHANGES_KEY = new Object();
- private static final Object CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY = new Object();
private static final Object CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY = new Object();
private static final int PUBLISH_EXCHANGES_KEY = 0;
private Map _permissions;
+ private boolean _fullVHostAccess = false;
private String _user;
@@ -60,520 +63,611 @@ public class PrincipalPermissions
_permissions = new ConcurrentHashMap();
}
+ /**
+ *
+ * @param permission the type of permission to check
+ *
+ * @param parameters vararg depending on what permission was passed in
+ * ACCESS: none
+ * BIND: none
+ * CONSUME: AMQShortString queueName, Boolean temporary, Boolean ownQueueOnly
+ * CREATEQUEUE: Boolean temporary, AMQShortString queueName, AMQShortString exchangeName, AMQShortString routingKey
+ * CREATEEXCHANGE: AMQShortString exchangeName, AMQShortString Class
+ * DELETE: none
+ * PUBLISH: Exchange exchange, AMQShortString routingKey
+ * PURGE: none
+ * UNBIND: none
+ */
public void grant(Permission permission, Object... parameters)
{
switch (permission)
{
- case ACCESS:
- break; // This is a no-op as the existence of this PrincipalPermission object is scoped per VHost for ACCESS
- case BIND:
- break; // All the details are currently included in the create setup.
+ case ACCESS:// Parameters : None
+ grantAccess(permission);
+ break;
case CONSUME: // Parameters : AMQShortString queueName, Boolean Temporary, Boolean ownQueueOnly
- Map consumeRights = (Map) _permissions.get(permission);
-
- if (consumeRights == null)
- {
- consumeRights = new ConcurrentHashMap();
- _permissions.put(permission, consumeRights);
- }
-
- //if we have parametsre
- if (parameters.length > 0)
- {
- AMQShortString queueName = (AMQShortString) parameters[0];
- Boolean temporary = (Boolean) parameters[1];
- Boolean ownQueueOnly = (Boolean) parameters[2];
-
- if (temporary)
- {
- consumeRights.put(CONSUME_TEMPORARY_KEY, true);
- }
- else
- {
- consumeRights.put(CONSUME_TEMPORARY_KEY, false);
- }
-
- if (ownQueueOnly)
- {
- consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, true);
- }
- else
- {
- consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, false);
- }
-
-
- LinkedList queues = (LinkedList) consumeRights.get(CONSUME_QUEUES_KEY);
- if (queues == null)
- {
- queues = new LinkedList();
- consumeRights.put(CONSUME_QUEUES_KEY, queues);
- }
-
- if (queueName != null)
- {
- queues.add(queueName);
- }
- }
-
-
+ grantConsume(permission, parameters);
break;
- case CREATE: // Parameters : Boolean temporary, AMQShortString queueName
+ case CREATEQUEUE: // Parameters : Boolean temporary, AMQShortString queueName
// , AMQShortString exchangeName , AMQShortString routingKey
- // || AMQShortString exchangeName , AMQShortString Class
-
- Map createRights = (Map) _permissions.get(permission);
-
- if (createRights == null)
- {
- createRights = new ConcurrentHashMap();
- _permissions.put(permission, createRights);
-
- }
-
- //The existence of the empty map mean permission to all.
- if (parameters.length == 0)
- {
- return;
- }
-
-
- if (parameters[0] instanceof Boolean) //Create Queue :
- // Boolean temporary, [AMQShortString queueName, AMQShortString exchangeName , AMQShortString routingKey]
- {
- Boolean temporary = (Boolean) parameters[0];
-
- AMQShortString queueName = parameters.length > 1 ? (AMQShortString) parameters[1] : null;
- AMQShortString exchangeName = parameters.length > 2 ? (AMQShortString) parameters[2] : null;
- //Set the routingkey to the specified value or the queueName if present
- AMQShortString routingKey = parameters.length > 3 ? (AMQShortString) parameters[3] : queueName;
-
- // Get the queues map
- Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY);
-
- if (create_queues == null)
- {
- create_queues = new ConcurrentHashMap();
- createRights.put(CREATE_QUEUES_KEY, create_queues);
- }
-
- //Allow all temp queues to be created
- create_queues.put(CREATE_QUEUE_TEMPORARY_KEY, temporary);
-
- //Create empty list of queues
- Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY);
-
- if (create_queues_queues == null)
- {
- create_queues_queues = new ConcurrentHashMap();
- create_queues.put(CREATE_QUEUE_QUEUES_KEY, create_queues_queues);
- }
-
- // We are granting CREATE rights to all temporary queues only
- if (parameters.length == 1)
- {
- return;
- }
-
- // if we have a queueName then we need to store any associated exchange / rk bindings
- if (queueName != null)
- {
- Map queue = (Map) create_queues_queues.get(queueName);
- if (queue == null)
- {
- queue = new ConcurrentHashMap();
- create_queues_queues.put(queueName, queue);
- }
-
- if (exchangeName != null)
- {
- queue.put(exchangeName, routingKey);
- }
-
- //If no exchange is specified then the presence of the queueName in the map says any exchange is ok
- }
-
- // Store the exchange that we are being granted rights to. This will be used as part of binding
-
- //Lookup the list of exchanges
- Map create_queues_exchanges = (Map) create_queues.get(CREATE_QUEUE_EXCHANGES_KEY);
-
- if (create_queues_exchanges == null)
- {
- create_queues_exchanges = new ConcurrentHashMap();
- create_queues.put(CREATE_QUEUE_EXCHANGES_KEY, create_queues_exchanges);
- }
-
- //if we have an exchange
- if (exchangeName != null)
- {
- //Retrieve the list of permitted exchanges.
- Map exchanges = (Map) create_queues_exchanges.get(exchangeName);
-
- if (exchanges == null)
- {
- exchanges = new ConcurrentHashMap();
- create_queues_exchanges.put(exchangeName, exchanges);
- }
-
- //Store the temporary setting CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY
- exchanges.put(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY, temporary);
-
- //Store the binding details of queue/rk for this exchange.
- if (queueName != null)
- {
- //Retrieve the list of permitted routingKeys.
- Map rKeys = (Map) exchanges.get(exchangeName);
-
- if (rKeys == null)
- {
- rKeys = new ConcurrentHashMap();
- exchanges.put(CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY, rKeys);
- }
-
- rKeys.put(queueName, routingKey);
- }
- }
- }
- else // Create Exchange : AMQShortString exchangeName , AMQShortString Class
- {
- Map create_exchanges = (Map) createRights.get(CREATE_EXCHANGES_KEY);
-
- if (create_exchanges == null)
- {
- create_exchanges = new ConcurrentHashMap();
- createRights.put(CREATE_EXCHANGES_KEY, create_exchanges);
- }
-
- //Should perhaps error if parameters[0] is null;
- AMQShortString exchangeName = parameters.length > 0 ? (AMQShortString) parameters[0] : null;
- AMQShortString className = parameters.length > 1 ? (AMQShortString) parameters[1] : null;
-
- //Store the exchangeName / class mapping if the mapping is null
- createRights.put(exchangeName, className);
- }
+ grantCreateQueue(permission, parameters);
break;
- case DELETE:
+ case CREATEEXCHANGE:
+ // Parameters AMQShortString exchangeName , AMQShortString Class
+ grantCreateExchange(permission, parameters);
break;
-
case PUBLISH: // Parameters : Exchange exchange, AMQShortString routingKey
- Map publishRights = (Map) _permissions.get(permission);
-
- if (publishRights == null)
- {
- publishRights = new ConcurrentHashMap();
- _permissions.put(permission, publishRights);
- }
-
- if (parameters == null || parameters.length == 0)
- {
- //If we have no parameters then allow publish to all destinations
- // this is signified by having a null value for publish_exchanges
- }
- else
- {
- Map publish_exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY);
-
- if (publish_exchanges == null)
- {
- publish_exchanges = new ConcurrentHashMap();
- publishRights.put(PUBLISH_EXCHANGES_KEY, publish_exchanges);
- }
-
-
- HashSet routingKeys = (HashSet) publish_exchanges.get(parameters[0]);
-
- // Check to see if we have a routing key
- if (parameters.length == 2)
- {
- if (routingKeys == null)
- {
- routingKeys = new HashSet<AMQShortString>();
- }
- //Add routing key to permitted publish destinations
- routingKeys.add(parameters[1]);
- }
-
- // Add the updated routingkey list or null if all values allowed
- publish_exchanges.put(parameters[0], routingKeys);
- }
+ grantPublish(permission, parameters);
break;
+ /* The other cases just fall through to no-op */
+ case DELETE:
+ case BIND: // All the details are currently included in the create setup.
case PURGE:
- break;
case UNBIND:
break;
}
}
- public boolean authorise(Permission permission, Object... parameters)
+ private void grantAccess(Permission permission)
{
+ _fullVHostAccess = true;
+ }
+
+ private void grantPublish(Permission permission, Object... parameters) {
+ Map publishRights = (Map) _permissions.get(permission);
+
+ if (publishRights == null)
+ {
+ publishRights = new ConcurrentHashMap();
+ _permissions.put(permission, publishRights);
+ }
+
+ if (parameters == null || parameters.length == 0)
+ {
+ //If we have no parameters then allow publish to all destinations
+ // this is signified by having a null value for publish_exchanges
+ }
+ else
+ {
+ Map publish_exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY);
+
+ if (publish_exchanges == null)
+ {
+ publish_exchanges = new ConcurrentHashMap();
+ publishRights.put(PUBLISH_EXCHANGES_KEY, publish_exchanges);
+ }
+
+
+ HashSet routingKeys = (HashSet) publish_exchanges.get(parameters[0]);
+
+ // Check to see if we have a routing key
+ if (parameters.length == 2)
+ {
+ if (routingKeys == null)
+ {
+ routingKeys = new HashSet<AMQShortString>();
+ }
+ //Add routing key to permitted publish destinations
+ routingKeys.add(parameters[1]);
+ }
+
+ // Add the updated routingkey list or null if all values allowed
+ publish_exchanges.put(parameters[0], routingKeys);
+ }
+ }
+
+ private void grantCreateExchange(Permission permission, Object... parameters) {
+ Map rights = (Map) _permissions.get(permission);
+ if (rights == null)
+ {
+ rights = new ConcurrentHashMap();
+ _permissions.put(permission, rights);
+ }
+
+ Map create_exchanges = (Map) rights.get(CREATE_EXCHANGES_KEY);
+ if (create_exchanges == null)
+ {
+ create_exchanges = new ConcurrentHashMap();
+ rights.put(CREATE_EXCHANGES_KEY, create_exchanges);
+ }
+
+ //Should perhaps error if parameters[0] is null;
+ AMQShortString name = parameters.length > 0 ? (AMQShortString) parameters[0] : null;
+ AMQShortString className = parameters.length > 1 ? (AMQShortString) parameters[1] : new AMQShortString("direct");
+
+ //Store the exchangeName / class mapping if the mapping is null
+ rights.put(name, className);
+ }
+
+ private void grantCreateQueue(Permission permission, Object... parameters)
+ {
+ Map createRights = (Map) _permissions.get(permission);
- switch (permission)
+ if (createRights == null)
{
- case ACCESS:
- return true; // This is here for completeness but the SimpleXML ACLManager never calls it.
- // The existence of this user specific PP can be validated in the map SimpleXML maintains.
- case BIND: // Parameters : QueueBindMethod , Exchange , AMQQueue, AMQShortString routingKey
-
- Exchange exchange = (Exchange) parameters[1];
-
- AMQQueue bind_queueName = (AMQQueue) parameters[2];
- AMQShortString routingKey = (AMQShortString) parameters[3];
-
- //Get all Create Rights for this user
- Map bindCreateRights = (Map) _permissions.get(Permission.CREATE);
-
- //Look up the Queue Creation Rights
- Map bind_create_queues = (Map) bindCreateRights.get(CREATE_QUEUES_KEY);
-
- //Lookup the list of queues
- Map bind_create_queues_queues = (Map) bindCreateRights.get(CREATE_QUEUE_QUEUES_KEY);
-
- // Check and see if we have a queue white list to check
- if (bind_create_queues_queues != null)
- {
- //There a white list for queues
- Map exchangeDetails = (Map) bind_create_queues_queues.get(bind_queueName);
-
- if (exchangeDetails == null) //Then all queue can be bound to all exchanges.
- {
- return true;
- }
-
- // Check to see if we have a white list of routingkeys to check
- Map rkeys = (Map) exchangeDetails.get(exchange.getName());
+ createRights = new ConcurrentHashMap();
+ _permissions.put(permission, createRights);
+ }
- // if keys is null then any rkey is allowed on this exchange
- if (rkeys == null)
- {
- // There is no routingkey white list
- return true;
- }
- else
- {
- // We have routingKeys so a match must be found to allowed binding
- Iterator keys = rkeys.keySet().iterator();
-
- boolean matched = false;
- while (keys.hasNext() && !matched)
- {
- AMQShortString rkey = (AMQShortString) keys.next();
- if (rkey.endsWith("*"))
- {
- matched = routingKey.startsWith(rkey.subSequence(0, rkey.length() - 1).toString());
- }
- else
- {
- matched = routingKey.equals(rkey);
- }
- }
-
-
- return matched;
- }
+ //The existence of the empty map mean permission to all.
+ if (parameters.length == 0)
+ {
+ return;
+ }
+ // Get the queues map
+ Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY);
- }
- else
- {
- //There a is no white list for queues
+ //Initialiase the queue permissions if not already done
+ if (create_queues == null)
+ {
+ create_queues = new ConcurrentHashMap();
+ //initialise temp queue permission to false and overwrite below if true
+ create_queues.put(CREATE_QUEUE_TEMPORARY_KEY, false);
+ createRights.put(CREATE_QUEUES_KEY, create_queues);
+ }
- // So can allow all queues to be bound
- // but we should first check and see if we have a temp queue and validate that we are allowed
- // to bind temp queues.
+ //Create empty list of queues
+ Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY);
- //Check to see if we have a temporary queue
- if (bind_queueName.isAutoDelete())
- {
- // Check and see if we have an exchange white list.
- Map bind_exchanges = (Map) bind_create_queues.get(CREATE_QUEUE_EXCHANGES_KEY);
-
- // If the exchange exists then we must check to see if temporary queues are allowed here
- if (bind_exchanges != null)
- {
- // Check to see if the requested exchange is allowed.
- Map exchangeDetails = (Map) bind_exchanges.get(exchange.getName());
+ if (create_queues_queues == null)
+ {
+ create_queues_queues = new ConcurrentHashMap();
+ create_queues.put(CREATE_QUEUE_QUEUES_KEY, create_queues_queues);
+ }
- return (Boolean) exchangeDetails.get(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY);
- }
+ // If we are initialising and granting CREATE rights to all temporary queues, then that's all we do
+ Boolean temporary = false;
+ if (parameters.length == 1)
+ {
+ temporary = (Boolean) parameters[0];
+ create_queues.put(CREATE_QUEUE_TEMPORARY_KEY, temporary);
+ return;
+ }
- //no white list so all allowed, drop through to return true below.
- }
+ //From here we can be permissioning a variety of things, with varying parameters
+ AMQShortString queueName = parameters.length > 1 ? (AMQShortString) parameters[1] : null;
+ AMQShortString exchangeName = parameters.length > 2 ? (AMQShortString) parameters[2] : null;
+ //Set the routingkey to the specified value or the queueName if present
+ AMQShortString routingKey = (parameters.length > 3 && null != parameters[3]) ? (AMQShortString) parameters[3] : queueName;
+ // if we have a queueName then we need to store any associated exchange / rk bindings
+ if (queueName != null)
+ {
+ Map queue = (Map) create_queues_queues.get(queueName);
+ if (queue == null)
+ {
+ queue = new ConcurrentHashMap();
+ create_queues_queues.put(queueName, queue);
+ }
+
+ if (exchangeName != null)
+ {
+ queue.put(exchangeName, routingKey);
+ }
+
+ //If no exchange is specified then the presence of the queueName in the map says any exchange is ok
+ }
- // not a temporary queue and no white list so all allowed.
- return true;
- }
+ // Store the exchange that we are being granted rights to. This will be used as part of binding
- case CREATE:// Paramters : QueueDeclareBody || ExchangeDeclareBody
+ //Lookup the list of exchanges
+ Map create_queues_exchanges = (Map) create_queues.get(CREATE_QUEUE_EXCHANGES_KEY);
- Map createRights = (Map) _permissions.get(permission);
+ if (create_queues_exchanges == null)
+ {
+ create_queues_exchanges = new ConcurrentHashMap();
+ create_queues.put(CREATE_QUEUE_EXCHANGES_KEY, create_queues_exchanges);
+ }
- // If there are no create rights then deny request
- if (createRights == null)
+ //if we have an exchange
+ if (exchangeName != null)
+ {
+ //Retrieve the list of permitted exchanges.
+ Map exchanges = (Map) create_queues_exchanges.get(exchangeName);
+
+ if (exchanges == null)
+ {
+ exchanges = new ConcurrentHashMap();
+ create_queues_exchanges.put(exchangeName, exchanges);
+ }
+
+ //Store the binding details of queue/rk for this exchange.
+ if (queueName != null)
+ {
+ //Retrieve the list of permitted routingKeys.
+ Map rKeys = (Map) exchanges.get(exchangeName);
+
+ if (rKeys == null)
{
- return false;
+ rKeys = new ConcurrentHashMap();
+ exchanges.put(CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY, rKeys);
}
- if (parameters.length == 1)
- {
- if (parameters[0] instanceof QueueDeclareBody)
- {
- QueueDeclareBody body = (QueueDeclareBody) parameters[0];
-
- //Look up the Queue Creation Rights
- Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY);
+ rKeys.put(queueName, routingKey);
+ }
+ }
+ }
- //Lookup the list of queues allowed to be created
- Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY);
+ /**
+ * Grant consume permissions
+ */
+ private void grantConsume(Permission permission, Object... parameters)
+ {
+ Map consumeRights = (Map) _permissions.get(permission);
+ if (consumeRights == null)
+ {
+ consumeRights = new ConcurrentHashMap();
+ _permissions.put(permission, consumeRights);
- AMQShortString queueName = body.getQueue();
+ //initialise own and temporary rights to false to be overwritten below if set
+ consumeRights.put(CONSUME_TEMPORARY_KEY, false);
+ consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, false);
+ }
- if (body.getAutoDelete())// we have a temporary queue
- {
- return (Boolean) create_queues.get(CREATE_QUEUE_TEMPORARY_KEY);
- }
- else
- {
- // If there is a white list then check
- return create_queues_queues == null || create_queues_queues.containsKey(queueName);
- }
+ //if we only have one param then we're permissioning temporary queues and topics
+ if (parameters.length == 1)
+ {
+ Boolean temporary = (Boolean) parameters[0];
- }
- else if (parameters[0] instanceof ExchangeDeclareBody)
- {
- ExchangeDeclareBody body = (ExchangeDeclareBody) parameters[0];
+ if (temporary)
+ {
+ consumeRights.put(CONSUME_TEMPORARY_KEY, true);
+ }
+ }
- AMQShortString exchangeName = body.getExchange();
+ //if we have 2 parameters - should be a contract for this, but for now we'll handle it as is
+ if (parameters.length == 2)
+ {
+ AMQShortString queueName = (AMQShortString) parameters[0];
+ Boolean ownQueueOnly = (Boolean) parameters[1];
+
+ if (ownQueueOnly)
+ {
+ consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, true);
+ }
+
+ LinkedList queues = (LinkedList) consumeRights.get(CONSUME_QUEUES_KEY);
+ if (queues == null)
+ {
+ queues = new LinkedList();
+ consumeRights.put(CONSUME_QUEUES_KEY, queues);
+ }
+
+ if (queueName != null)
+ {
+ queues.add(queueName);
+ }
+ }
+ }
- Map create_exchanges = (Map) createRights.get(CREATE_EXCHANGES_KEY);
+ /**
+ *
+ * @param permission the type of permission to check
+ *
+ * @param parameters vararg depending on what permission was passed in
+ * ACCESS: none
+ * BIND: QueueBindBody bindmethod, Exchange exchange, AMQQueue queue, AMQShortString routingKey
+ * CONSUME: AMQQueue queue
+ * CREATEQUEUE: Boolean autodelete, AMQShortString name
+ * CREATEEXCHANGE: AMQShortString exchangeName
+ * DELETE: none
+ * PUBLISH: Exchange exchange, AMQShortString routingKey
+ * PURGE: none
+ * UNBIND: none
+ */
+ public AuthzResult authorise(Permission permission, Object... parameters)
+ {
- // If the exchange list is doesn't exist then all is allowed else check the valid exchanges
- return create_exchanges == null || create_exchanges.containsKey(exchangeName);
- }
- }
- break;
+ switch (permission)
+ {
+ case ACCESS://No Parameters
+ return AuthzResult.ALLOWED; // The existence of this user-specific PP infers some level of access is authorised
+ case BIND: // Parameters : QueueBindMethod , Exchange , AMQQueue, AMQShortString routingKey
+ return authoriseBind(parameters);
+ case CREATEQUEUE:// Parameters : boolean autodelete, AMQShortString name
+ return authoriseCreateQueue(permission, parameters);
+ case CREATEEXCHANGE:
+ return authoriseCreateExchange(permission, parameters);
case CONSUME: // Parameters : AMQQueue
-
- if (parameters.length == 1 && parameters[0] instanceof AMQQueue)
+ return authoriseConsume(permission, parameters);
+ case PUBLISH: // Parameters : Exchange exchange, AMQShortString routingKey
+ return authorisePublish(permission, parameters);
+ /* Fall through */
+ case DELETE:
+ case PURGE:
+ case UNBIND:
+ default:
+ if(_fullVHostAccess)
{
- AMQQueue queue = ((AMQQueue) parameters[0]);
- Map queuePermissions = (Map) _permissions.get(permission);
-
- List queues = (List) queuePermissions.get(CONSUME_QUEUES_KEY);
+ //user has been granted full access to the vhost
+ return AuthzResult.ALLOWED;
+ }
+ else
+ {
+ //SimpleXML ACL does not implement these permissions and should abstain
+ return AuthzResult.ABSTAIN;
+ }
+ }
- Boolean temporayQueues = (Boolean) queuePermissions.get(CONSUME_TEMPORARY_KEY);
- Boolean ownQueuesOnly = (Boolean) queuePermissions.get(CONSUME_OWN_QUEUES_ONLY_KEY);
+ }
- // If user is allowed to publish to temporary queues and this is a temp queue then allow it.
- if (temporayQueues)
- {
- if (queue.isAutoDelete())
- // This will allow consumption from any temporary queue including ones not owned by this user.
- // Of course the exclusivity will not be broken.
- {
- // if not limited to ownQueuesOnly then ok else check queue Owner.
- return !ownQueuesOnly || queue.getOwner().equals(_user);
- }
- else
- {
- return false;
- }
- }
+ private AuthzResult authoriseConsume(Permission permission, Object... parameters)
+ {
+ if(_fullVHostAccess)
+ {
+ //user has been granted full access to the vhost
+ return AuthzResult.ALLOWED;
+ }
- // if queues are white listed then ensure it is ok
- if (queues != null)
- {
- // if no queues are listed then ALL are ok othereise it must be specified.
- if (ownQueuesOnly)
- {
- if (queue.getOwner().equals(_user))
- {
- return queues.size() == 0 || queues.contains(queue.getName());
- }
- else
- {
- return false;
- }
- }
-
- // If we are
- return queues.size() == 0 || queues.contains(queue.getName());
- }
- }
+ if (parameters.length == 1 && parameters[0] instanceof AMQQueue)
+ {
+ AMQQueue queue = ((AMQQueue) parameters[0]);
+ Map queuePermissions = (Map) _permissions.get(permission);
- // Can't authenticate without the right parameters
- return false;
- case DELETE:
- break;
+ if (queuePermissions == null)
+ {
+ //we have a problem - we've never granted this type of permission .....
+ return AuthzResult.DENIED;
+ }
- case PUBLISH: // Parameters : Exchange exchange, AMQShortString routingKey
- Map publishRights = (Map) _permissions.get(permission);
+ List queues = (List) queuePermissions.get(CONSUME_QUEUES_KEY);
- if (publishRights == null)
- {
- return false;
- }
+ Boolean temporaryQueues = (Boolean) queuePermissions.get(CONSUME_TEMPORARY_KEY);
+ Boolean ownQueuesOnly = (Boolean) queuePermissions.get(CONSUME_OWN_QUEUES_ONLY_KEY);
- Map exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY);
- // Having no exchanges listed gives full publish rights to all exchanges
- if (exchanges == null)
+ // If user is allowed to consume from temporary queues and this is a temp queue then allow it.
+ if (temporaryQueues && queue.isAutoDelete())
+ {
+ // This will allow consumption from any temporary queue including ones not owned by this user.
+ // Of course the exclusivity will not be broken.
{
- return true;
- }
- // Otherwise exchange must be listed in the white list
- // If the map doesn't have the exchange then it isn't allowed
- if (!exchanges.containsKey(parameters[0]))
- {
- return false;
+ // if not limited to ownQueuesOnly then ok else check queue Owner.
+ return (!ownQueuesOnly || new AMQShortString(queue.getPrincipalHolder().getPrincipal().getName()).equals(_user)) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
}
- else
+ }
+ //if this is a temporary queue and the user does not have permissions for temporary queues then deny
+ else if (!temporaryQueues && queue.isAutoDelete())
+ {
+ return AuthzResult.DENIED;
+ }
+
+ // if queues are white listed then ensure it is ok
+ if (queues != null)
+ {
+ // if no queues are listed then ALL are ok othereise it must be specified.
+ if (ownQueuesOnly)
{
-
- // Get valid routing keys
- HashSet routingKeys = (HashSet) exchanges.get(parameters[0]);
-
- // Having no routingKeys in the map then all are allowed.
- if (routingKeys == null)
+ if ( new AMQShortString(queue.getPrincipalHolder().getPrincipal().getName()).equals(_user))
{
- return true;
+ return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
}
else
{
- // We have routingKeys so a match must be found to allowed binding
- Iterator keys = routingKeys.iterator();
-
-
- AMQShortString publishRKey = (AMQShortString)parameters[1];
-
- boolean matched = false;
- while (keys.hasNext() && !matched)
- {
- AMQShortString rkey = (AMQShortString) keys.next();
-
- if (rkey.endsWith("*"))
- {
- matched = publishRKey.startsWith(rkey.subSequence(0, rkey.length() - 1));
- }
- else
- {
- matched = publishRKey.equals(rkey);
- }
- }
- return matched;
+ return AuthzResult.DENIED;
}
}
- case PURGE:
- break;
- case UNBIND:
- break;
+ // If we are
+ return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
+ }
}
- return false;
- }
+ // Can't authenticate without the right parameters
+ return AuthzResult.DENIED;
+ }
+
+ private AuthzResult authorisePublish(Permission permission, Object... parameters)
+ {
+ if(_fullVHostAccess)
+ {
+ //user has been granted full access to the vhost
+ return AuthzResult.ALLOWED;
+ }
+
+ Map publishRights = (Map) _permissions.get(permission);
+
+ if (publishRights == null)
+ {
+ return AuthzResult.DENIED;
+ }
+
+ Map exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY);
+
+ // Having no exchanges listed gives full publish rights to all exchanges
+ if (exchanges == null)
+ {
+ return AuthzResult.ALLOWED;
+ }
+ // Otherwise exchange must be listed in the white list
+
+ // If the map doesn't have the exchange then it isn't allowed
+ if (!exchanges.containsKey(((Exchange) parameters[0]).getName()))
+ {
+ return AuthzResult.DENIED;
+ }
+ else
+ {
+
+ // Get valid routing keys
+ HashSet routingKeys = (HashSet) exchanges.get(((Exchange)parameters[0]).getName());
+
+ // Having no routingKeys in the map then all are allowed.
+ if (routingKeys == null)
+ {
+ return AuthzResult.ALLOWED;
+ }
+ else
+ {
+ // We have routingKeys so a match must be found to allowed binding
+ Iterator keys = routingKeys.iterator();
+
+
+ AMQShortString publishRKey = (AMQShortString)parameters[1];
+
+ boolean matched = false;
+ while (keys.hasNext() && !matched)
+ {
+ AMQShortString rkey = (AMQShortString) keys.next();
+
+ if (rkey.endsWith("*"))
+ {
+ matched = publishRKey.startsWith(rkey.subSequence(0, rkey.length() - 1));
+ }
+ else
+ {
+ matched = publishRKey.equals(rkey);
+ }
+ }
+ return (matched) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
+ }
+ }
+ }
+
+ private AuthzResult authoriseCreateExchange(Permission permission, Object... parameters)
+ {
+ if(_fullVHostAccess)
+ {
+ //user has been granted full access to the vhost
+ return AuthzResult.ALLOWED;
+ }
+
+ Map rights = (Map) _permissions.get(permission);
+
+ AMQShortString exchangeName = (AMQShortString) parameters[0];
+
+ // If the exchange list is doesn't exist then all is allowed else
+ // check the valid exchanges
+ if (rights == null || rights.containsKey(exchangeName))
+ {
+ return AuthzResult.ALLOWED;
+ }
+ else
+ {
+ return AuthzResult.DENIED;
+ }
+ }
+
+ private AuthzResult authoriseCreateQueue(Permission permission, Object... parameters)
+ {
+ if(_fullVHostAccess)
+ {
+ //user has been granted full access to the vhost
+ return AuthzResult.ALLOWED;
+ }
+
+ Map createRights = (Map) _permissions.get(permission);
+
+ // If there are no create rights then deny request
+ if (createRights == null)
+ {
+ return AuthzResult.DENIED;
+ }
+
+ //Look up the Queue Creation Rights
+ Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY);
+
+ //Lookup the list of queues allowed to be created
+ Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY);
+
+
+ AMQShortString queueName = (AMQShortString) parameters[1];
+ Boolean autoDelete = (Boolean) parameters[0];
+
+ if (autoDelete)// we have a temporary queue
+ {
+ return ((Boolean) create_queues.get(CREATE_QUEUE_TEMPORARY_KEY)) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
+ }
+ else
+ {
+ // If there is a white list then check
+ if (create_queues_queues == null || create_queues_queues.containsKey(queueName))
+ {
+ return AuthzResult.ALLOWED;
+ }
+ else
+ {
+ return AuthzResult.DENIED;
+ }
+
+ }
+ }
+
+ private AuthzResult authoriseBind(Object... parameters)
+ {
+ if(_fullVHostAccess)
+ {
+ //user has been granted full access to the vhost
+ return AuthzResult.ALLOWED;
+ }
+
+ Exchange exchange = (Exchange) parameters[1];
+
+ AMQQueue bind_queueName = (AMQQueue) parameters[2];
+ AMQShortString routingKey = (AMQShortString) parameters[3];
+
+ //Get all Create Rights for this user
+ Map bindCreateRights = (Map) _permissions.get(Permission.CREATEQUEUE);
+
+ //Look up the Queue Creation Rights
+ Map bind_create_queues = (Map) bindCreateRights.get(CREATE_QUEUES_KEY);
+
+ //Lookup the list of queues
+ Map bind_create_queues_queues = (Map) bindCreateRights.get(CREATE_QUEUE_QUEUES_KEY);
+
+ // Check and see if we have a queue white list to check
+ if (bind_create_queues_queues != null)
+ {
+ //There a white list for queues
+ Map exchangeDetails = (Map) bind_create_queues_queues.get(bind_queueName);
+
+ if (exchangeDetails == null) //Then all queue can be bound to all exchanges.
+ {
+ return AuthzResult.ALLOWED;
+ }
+
+ // Check to see if we have a white list of routingkeys to check
+ Map rkeys = (Map) exchangeDetails.get(exchange.getName());
+
+ // if keys is null then any rkey is allowed on this exchange
+ if (rkeys == null)
+ {
+ // There is no routingkey white list
+ return AuthzResult.ALLOWED;
+ }
+ else
+ {
+ // We have routingKeys so a match must be found to allowed binding
+ Iterator keys = rkeys.keySet().iterator();
+
+ boolean matched = false;
+ while (keys.hasNext() && !matched)
+ {
+ AMQShortString rkey = (AMQShortString) keys.next();
+ if (rkey.endsWith("*"))
+ {
+ matched = routingKey.startsWith(rkey.subSequence(0, rkey.length() - 1).toString());
+ }
+ else
+ {
+ matched = routingKey.equals(rkey);
+ }
+ }
+
+
+ return (matched) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
+ }
+
+
+ }
+ else
+ {
+ //no white list so all allowed.
+ return AuthzResult.ALLOWED;
+ }
+ }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java
index a8ae03cc5d..69abac7bd6 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java
@@ -20,13 +20,14 @@
*/
package org.apache.qpid.server.security.access.management;
-import org.apache.qpid.server.management.MBeanDescription;
+import org.apache.qpid.management.common.mbeans.UserManagement;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation;
import org.apache.qpid.server.management.AMQManagedObject;
-import org.apache.qpid.server.management.MBeanOperation;
import org.apache.qpid.server.management.MBeanInvocationHandlerImpl;
import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
-import org.apache.qpid.server.security.access.management.UserManagement;
+import org.apache.qpid.util.FileUtils;
import org.apache.log4j.Logger;
import org.apache.commons.configuration.ConfigurationException;
@@ -50,6 +51,7 @@ import java.io.FileOutputStream;
import java.util.Properties;
import java.util.List;
import java.util.Enumeration;
+import java.util.Random;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import java.security.Principal;
@@ -64,35 +66,29 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana
private static final Logger _logger = Logger.getLogger(AMQUserManagementMBean.class);
private PrincipalDatabase _principalDatabase;
- private String _accessFileName;
private Properties _accessRights;
- // private File _accessFile;
+ private File _accessFile;
+
private ReentrantLock _accessRightsUpdate = new ReentrantLock();
// Setup for the TabularType
static TabularType _userlistDataType; // Datatype for representing User Lists
-
static CompositeType _userDataType; // Composite type for representing User
- static String[] _userItemNames = {"Username", "read", "write", "admin"};
static
{
- String[] userItemDesc = {"Broker Login username", "Management Console Read Permission",
- "Management Console Write Permission", "Management Console Admin Permission"};
-
OpenType[] userItemTypes = new OpenType[4]; // User item types.
userItemTypes[0] = SimpleType.STRING; // For Username
userItemTypes[1] = SimpleType.BOOLEAN; // For Rights - Read
userItemTypes[2] = SimpleType.BOOLEAN; // For Rights - Write
userItemTypes[3] = SimpleType.BOOLEAN; // For Rights - Admin
- String[] userDataIndex = {_userItemNames[0]};
try
{
_userDataType =
- new CompositeType("User", "User Data", _userItemNames, userItemDesc, userItemTypes);
+ new CompositeType("User", "User Data", COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS, userItemTypes);
- _userlistDataType = new TabularType("Users", "List of users", _userDataType, userDataIndex);
+ _userlistDataType = new TabularType("Users", "List of users", _userDataType, TABULAR_UNIQUE_INDEX);
}
catch (OpenDataException e)
{
@@ -104,7 +100,7 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana
public AMQUserManagementMBean() throws JMException
{
- super(UserManagement.class, UserManagement.TYPE);
+ super(UserManagement.class, UserManagement.TYPE, UserManagement.VERSION);
}
public String getObjectInstanceName()
@@ -129,9 +125,10 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana
public boolean setRights(String username, boolean read, boolean write, boolean admin)
{
- if (_accessRights.get(username) == null)
+ Object oldRights = null;
+ if ((oldRights =_accessRights.get(username)) == null)
{
- // If the user doesn't exist in the user rights file check that they at least have an account.
+ // If the user doesn't exist in the access rights file check that they at least have an account.
if (_principalDatabase.getUser(username) == null)
{
return false;
@@ -140,7 +137,6 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana
try
{
-
_accessRightsUpdate.lock();
// Update the access rights
@@ -166,8 +162,29 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana
_accessRights.remove(username);
}
}
+
+ //save the rights file
+ try
+ {
+ saveAccessFile();
+ }
+ catch (IOException e)
+ {
+ _logger.warn("Problem occured saving '" + _accessFile + "', the access right changes will not be preserved: " + e);
- saveAccessFile();
+ //the rights file was not successfully saved, restore user rights to previous value
+ _logger.warn("Reverting attempted rights update for user'" + username + "'");
+ if (oldRights != null)
+ {
+ _accessRights.put(username, oldRights);
+ }
+ else
+ {
+ _accessRights.remove(username);
+ }
+
+ return false;
+ }
}
finally
{
@@ -184,9 +201,23 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana
{
if (_principalDatabase.createPrincipal(new UsernamePrincipal(username), password))
{
- _accessRights.put(username, "");
-
- return setRights(username, read, write, admin);
+ if (!setRights(username, read, write, admin))
+ {
+ //unable to set rights for user, remove account
+ try
+ {
+ _principalDatabase.deletePrincipal(new UsernamePrincipal(username));
+ }
+ catch (AccountNotFoundException e)
+ {
+ //ignore
+ }
+ return false;
+ }
+ else
+ {
+ return true;
+ }
}
return false;
@@ -194,7 +225,6 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana
public boolean deleteUser(String username)
{
-
try
{
if (_principalDatabase.deletePrincipal(new UsernamePrincipal(username)))
@@ -204,7 +234,16 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana
_accessRightsUpdate.lock();
_accessRights.remove(username);
- saveAccessFile();
+
+ try
+ {
+ saveAccessFile();
+ }
+ catch (IOException e)
+ {
+ _logger.warn("Problem occured saving '" + _accessFile + "', the access right changes will not be preserved: " + e);
+ return false;
+ }
}
finally
{
@@ -213,40 +252,36 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana
_accessRightsUpdate.unlock();
}
}
- return true;
}
}
catch (AccountNotFoundException e)
{
_logger.warn("Attempt to delete user (" + username + ") that doesn't exist");
+ return false;
}
- return false;
+ return true;
}
public boolean reloadData()
{
- try
- {
try
{
loadAccessFile();
+ _principalDatabase.reload();
}
catch (ConfigurationException e)
{
- _logger.info("Reload failed due to:" + e);
+ _logger.warn("Reload failed due to:" + e);
+ return false;
+ }
+ catch (IOException e)
+ {
+ _logger.warn("Reload failed due to:" + e);
return false;
}
-
// Reload successful
return true;
- }
- catch (IOException e)
- {
- _logger.info("Reload failed due to:" + e);
- // Reload unsuccessful
- return false;
- }
}
@@ -288,7 +323,7 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana
}
Object[] itemData = {user.getName(), read, write, admin};
- CompositeData messageData = new CompositeDataSupport(_userDataType, _userItemNames, itemData);
+ CompositeData messageData = new CompositeDataSupport(_userDataType, COMPOSITE_ITEM_NAMES, itemData);
userList.put(messageData);
}
}
@@ -324,10 +359,24 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana
*/
public void setAccessFile(String accessFile) throws IOException, ConfigurationException
{
- _accessFileName = accessFile;
-
- if (_accessFileName != null)
+ if (accessFile != null)
{
+ _accessFile = new File(accessFile);
+ if (!_accessFile.exists())
+ {
+ throw new ConfigurationException("'" + _accessFile + "' does not exist");
+ }
+
+ if (!_accessFile.canRead())
+ {
+ throw new ConfigurationException("Cannot read '" + _accessFile + "'.");
+ }
+
+ if (!_accessFile.canWrite())
+ {
+ _logger.warn("Unable to write to access rights file '" + _accessFile + "', changes will not be preserved.");
+ }
+
loadAccessFile();
}
else
@@ -338,39 +387,34 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana
private void loadAccessFile() throws IOException, ConfigurationException
{
- try
+ if(_accessFile == null)
{
- _accessRightsUpdate.lock();
-
- Properties accessRights = new Properties();
-
- File accessFile = new File(_accessFileName);
-
- if (!accessFile.exists())
+ _logger.error("No jmx access rights file has been specified.");
+ return;
+ }
+
+ if(_accessFile.exists())
+ {
+ try
{
- throw new ConfigurationException("'" + _accessFileName + "' does not exist");
- }
+ _accessRightsUpdate.lock();
- if (!accessFile.canRead())
- {
- throw new ConfigurationException("Cannot read '" + _accessFileName + "'.");
+ Properties accessRights = new Properties();
+ accessRights.load(new FileInputStream(_accessFile));
+ checkAccessRights(accessRights);
+ setAccessRights(accessRights);
}
-
- if (!accessFile.canWrite())
+ finally
{
- _logger.warn("Unable to write to access file '" + _accessFileName + "' changes will not be preserved.");
+ if (_accessRightsUpdate.isHeldByCurrentThread())
+ {
+ _accessRightsUpdate.unlock();
+ }
}
-
- accessRights.load(new FileInputStream(accessFile));
- checkAccessRights(accessRights);
- setAccessRights(accessRights);
}
- finally
+ else
{
- if (_accessRightsUpdate.isHeldByCurrentThread())
- {
- _accessRightsUpdate.unlock();
- }
+ _logger.error("Specified jmxaccess rights file '" + _accessFile + "' does not exist.");
}
}
@@ -389,44 +433,54 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana
}
}
- private void saveAccessFile()
+ private void saveAccessFile() throws IOException
{
try
{
_accessRightsUpdate.lock();
- try
- {
- // remove old temporary file
- File tmp = new File(_accessFileName + ".tmp");
- if (tmp.exists())
- {
- tmp.delete();
- }
-
- //remove old backup
- File old = new File(_accessFileName + ".old");
- if (old.exists())
- {
- old.delete();
- }
- // Rename current file
- File rights = new File(_accessFileName);
- rights.renameTo(old);
-
- FileOutputStream output = new FileOutputStream(tmp);
- _accessRights.store(output, "Generated by AMQUserManagementMBean Console : Last edited by user:" + getCurrentJMXUser());
- output.close();
+ // Create temporary file
+ Random r = new Random();
+ File tmp;
+ do
+ {
+ tmp = new File(_accessFile.getPath() + r.nextInt() + ".tmp");
+ }
+ while(tmp.exists());
+
+ tmp.deleteOnExit();
- // Rename new file to main file
- tmp.renameTo(rights);
+ FileOutputStream output = new FileOutputStream(tmp);
+ _accessRights.store(output, "Generated by AMQUserManagementMBean Console : Last edited by user:" + getCurrentJMXUser());
+ output.close();
- // delete tmp
- tmp.delete();
+ // Swap temp file to main rights file.
+ File old = new File(_accessFile.getAbsoluteFile() + ".old");
+ if (old.exists())
+ {
+ old.delete();
}
- catch (IOException e)
+
+ if(!_accessFile.renameTo(old))
+ {
+ //unable to rename the existing file to the backup name
+ _logger.error("Could not backup the existing management rights file");
+ throw new IOException("Could not backup the existing management rights file");
+ }
+
+ if(!tmp.renameTo(_accessFile))
{
- _logger.warn("Problem occured saving '" + _accessFileName + "' changes may not be preserved. :" + e);
+ //failed to rename the new file to the required filename
+
+ if(!old.renameTo(_accessFile))
+ {
+ //unable to return the backup to required filename
+ _logger.error("Could not rename the new management rights file into place, and unable to restore original file");
+ throw new IOException("Could not rename the new management rights file into place, and unable to restore original file");
+ }
+
+ _logger.error("Could not rename the new management rights file into place");
+ throw new IOException("Could not rename the new management rights file into place");
}
}
finally
@@ -436,12 +490,18 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana
_accessRightsUpdate.unlock();
}
}
+
}
private String getCurrentJMXUser()
{
AccessControlContext acc = AccessController.getContext();
+
Subject subject = Subject.getSubject(acc);
+ if (subject == null)
+ {
+ return "Unknown user, authentication Subject was null";
+ }
// Retrieve JMXPrincipal from Subject
Set<JMXPrincipal> principals = subject.getPrincipals(JMXPrincipal.class);
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java
deleted file mode 100644
index 658d7ebbd3..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/management/UserManagement.java
+++ /dev/null
@@ -1,118 +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.
- *
- *
- */
-package org.apache.qpid.server.security.access.management;
-
-import org.apache.qpid.server.management.MBeanOperation;
-import org.apache.qpid.server.management.MBeanOperationParameter;
-import org.apache.qpid.server.management.MBeanAttribute;
-import org.apache.qpid.AMQException;
-
-import javax.management.openmbean.TabularData;
-import javax.management.openmbean.CompositeData;
-import javax.management.JMException;
-import javax.management.MBeanOperationInfo;
-import java.io.IOException;
-
-public interface UserManagement
-{
- String TYPE = "UserManagement";
-
- //********** Operations *****************//
- /**
- * set password for user
- *
- * @param username The username to create
- * @param password The password for the user
- *
- * @return The result of the operation
- */
- @MBeanOperation(name = "setPassword", description = "Set password for user.",
- impact = MBeanOperationInfo.ACTION)
- boolean setPassword(@MBeanOperationParameter(name = "username", description = "Username")String username,
- @MBeanOperationParameter(name = "password", description = "Password")char[] password);
-
- /**
- * set rights for users with given details
- *
- * @param username The username to create
- * @param read The set of permission to give the new user
- * @param write The set of permission to give the new user
- * @param admin The set of permission to give the new user
- *
- * @return The result of the operation
- */
- @MBeanOperation(name = "setRights", description = "Set access rights for user.",
- impact = MBeanOperationInfo.ACTION)
- boolean setRights(@MBeanOperationParameter(name = "username", description = "Username")String username,
- @MBeanOperationParameter(name = "read", description = "Administration read")boolean read,
- @MBeanOperationParameter(name = "readAndWrite", description = "Administration write")boolean write,
- @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin);
-
- /**
- * Create users with given details
- *
- * @param username The username to create
- * @param password The password for the user
- * @param read The set of permission to give the new user
- * @param write The set of permission to give the new user
- * @param admin The set of permission to give the new user
- *
- * @return The result of the operation
- */
- @MBeanOperation(name = "createUser", description = "Create new user from system.",
- impact = MBeanOperationInfo.ACTION)
- boolean createUser(@MBeanOperationParameter(name = "username", description = "Username")String username,
- @MBeanOperationParameter(name = "password", description = "Password")char[] password,
- @MBeanOperationParameter(name = "read", description = "Administration read")boolean read,
- @MBeanOperationParameter(name = "readAndWrite", description = "Administration write")boolean write,
- @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin);
-
- /**
- * View users returns all the users that are currently available to the system.
- *
- * @param username The user to delete
- *
- * @return The result of the operation
- */
- @MBeanOperation(name = "deleteUser", description = "Delete user from system.",
- impact = MBeanOperationInfo.ACTION)
- boolean deleteUser(@MBeanOperationParameter(name = "username", description = "Username")String username);
-
-
- /**
- * Reload the date from disk
- *
- * @return The result of the operation
- */
- @MBeanOperation(name = "reloadData", description = "Reload the authentication file from disk.",
- impact = MBeanOperationInfo.ACTION)
- boolean reloadData();
-
- /**
- * View users returns all the users that are currently available to the system.
- *
- * @return a table of users data (Username, read, write, admin)
- */
- @MBeanOperation(name = "viewUsers", description = "All users with access rights to the system.",
- impact = MBeanOperationInfo.INFO)
- TabularData viewUsers();
-
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java
new file mode 100644
index 0000000000..f99f3a60f7
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java
@@ -0,0 +1,99 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.access.plugins;
+
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.security.access.ACLPlugin;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.security.PrincipalHolder;
+
+/**
+ * This ACLPlugin abstains from all votes. Useful if your plugin only cares about a few operations.
+ */
+public abstract class AbstractACLPlugin implements ACLPlugin
+{
+
+ private static final AuthzResult DEFAULT_ANSWER = AuthzResult.ABSTAIN;
+
+ public AuthzResult authoriseBind(PrincipalHolder session, Exchange exch, AMQQueue queue,
+ AMQShortString routingKey)
+ {
+ return DEFAULT_ANSWER;
+ }
+
+ public AuthzResult authoriseConnect(PrincipalHolder session, VirtualHost virtualHost)
+ {
+ return DEFAULT_ANSWER;
+ }
+
+ public AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck, AMQQueue queue)
+ {
+ return DEFAULT_ANSWER;
+ }
+
+ public AuthzResult authoriseConsume(PrincipalHolder session, boolean exclusive, boolean noAck, boolean noLocal,
+ boolean nowait, AMQQueue queue)
+ {
+ return DEFAULT_ANSWER;
+ }
+
+ public AuthzResult authoriseCreateExchange(PrincipalHolder session, boolean autoDelete, boolean durable,
+ AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public AuthzResult authoriseCreateQueue(PrincipalHolder session, boolean autoDelete, boolean durable,
+ boolean exclusive, boolean nowait, boolean passive, AMQShortString queue)
+ {
+ return DEFAULT_ANSWER;
+ }
+
+ public AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue)
+ {
+ return DEFAULT_ANSWER;
+ }
+
+ public AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange)
+ {
+ return DEFAULT_ANSWER;
+ }
+
+ public AuthzResult authorisePublish(PrincipalHolder session, boolean immediate, boolean mandatory,
+ AMQShortString routingKey, Exchange e)
+ {
+ return DEFAULT_ANSWER;
+ }
+
+ public AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue)
+ {
+ return DEFAULT_ANSWER;
+ }
+
+ public AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch, AMQShortString routingKey,
+ AMQQueue queue)
+ {
+ return DEFAULT_ANSWER;
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java
index 9b784069dd..4af178574b 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java
@@ -20,49 +20,35 @@
*/
package org.apache.qpid.server.security.access.plugins;
-import org.apache.qpid.framing.AMQMethodBody;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.security.access.ACLPlugin;
-import org.apache.qpid.server.security.access.ACLManager;
-import org.apache.qpid.server.security.access.AccessResult;
-import org.apache.qpid.server.security.access.Accessable;
-import org.apache.qpid.server.security.access.Permission;
import org.apache.commons.configuration.Configuration;
+import org.apache.qpid.server.security.access.ACLPlugin;
+import org.apache.qpid.server.security.access.ACLPluginFactory;
-public class AllowAll implements ACLPlugin
+public class AllowAll extends BasicACLPlugin
{
- public AccessResult authorise(AMQProtocolSession session, Permission permission, AMQMethodBody body, Object... parameters)
+
+ public static final ACLPluginFactory FACTORY = new ACLPluginFactory()
{
- if (ACLManager.getLogger().isDebugEnabled())
+ public boolean supportsTag(String name)
{
- ACLManager.getLogger().debug("Allowing user:" + session.getAuthorizedID() + " for :" + permission.toString()
- + " on " + body.getClass().getSimpleName()
- + (parameters == null || parameters.length == 0 ? "" : "-" + accessablesToString(parameters)));
+ return false;
}
- return new AccessResult(this, AccessResult.AccessStatus.GRANTED);
- }
-
- public static String accessablesToString(Object[] accessObject)
- {
- StringBuilder sb = new StringBuilder();
-
- for (Object access : accessObject)
+ public ACLPlugin newInstance(Configuration config)
{
- sb.append(access.getClass().getSimpleName() + ":" + access.toString() + ", ");
+ return new AllowAll();
}
-
- return sb.delete(sb.length() - 2, sb.length()).toString();
- }
+ };
public String getPluginName()
{
- return "AllowAll";
+ return this.getClass().getSimpleName();
}
- public void setConfiguaration(Configuration config)
+ @Override
+ protected AuthzResult getResult()
{
- //no-op
+ // Always allow
+ return AuthzResult.ALLOWED;
}
-
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java
new file mode 100644
index 0000000000..d0df354d78
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.security.access.plugins;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.security.access.ACLPlugin;
+import org.apache.qpid.server.security.PrincipalHolder;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+public abstract class BasicACLPlugin implements ACLPlugin
+{
+
+ // Returns true or false if the plugin should authorise or deny the request
+ protected abstract AuthzResult getResult();
+
+ public AuthzResult authoriseBind(PrincipalHolder session, Exchange exch,
+ AMQQueue queue, AMQShortString routingKey)
+ {
+ return getResult();
+ }
+
+ public AuthzResult authoriseConnect(PrincipalHolder session,
+ VirtualHost virtualHost)
+ {
+ return getResult();
+ }
+
+ public AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck,
+ AMQQueue queue)
+ {
+ return getResult();
+ }
+
+ public AuthzResult authoriseConsume(PrincipalHolder session,
+ boolean exclusive, boolean noAck, boolean noLocal, boolean nowait,
+ AMQQueue queue)
+ {
+ return getResult();
+ }
+
+ public AuthzResult authoriseCreateExchange(PrincipalHolder session,
+ boolean autoDelete, boolean durable, AMQShortString exchangeName,
+ boolean internal, boolean nowait, boolean passive,
+ AMQShortString exchangeType)
+ {
+ return getResult();
+ }
+
+ public AuthzResult authoriseCreateQueue(PrincipalHolder session,
+ boolean autoDelete, boolean durable, boolean exclusive,
+ boolean nowait, boolean passive, AMQShortString queue)
+ {
+ return getResult();
+ }
+
+ public AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue)
+ {
+ return getResult();
+ }
+
+ public AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange)
+ {
+ return getResult();
+ }
+
+ public AuthzResult authorisePublish(PrincipalHolder session,
+ boolean immediate, boolean mandatory, AMQShortString routingKey,
+ Exchange e)
+ {
+ return getResult();
+ }
+
+ public AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue)
+ {
+ return getResult();
+ }
+
+ public AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch,
+ AMQShortString routingKey, AMQQueue queue)
+ {
+ return getResult();
+ }
+
+ public void setConfiguration(Configuration config)
+ {
+ // no-op
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java
index 80c125e737..77d3c4bcdf 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java
@@ -20,38 +20,56 @@
*/
package org.apache.qpid.server.security.access.plugins;
+import org.apache.commons.configuration.Configuration;
+import org.apache.qpid.AMQConnectionException;
import org.apache.qpid.framing.AMQMethodBody;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.protocol.AMQProtocolSession;
import org.apache.qpid.server.security.access.ACLManager;
import org.apache.qpid.server.security.access.ACLPlugin;
+import org.apache.qpid.server.security.access.ACLPluginFactory;
import org.apache.qpid.server.security.access.AccessResult;
import org.apache.qpid.server.security.access.Permission;
-import org.apache.qpid.AMQConnectionException;
-import org.apache.commons.configuration.Configuration;
-public class DenyAll implements ACLPlugin
+public class DenyAll extends BasicACLPlugin
{
- public AccessResult authorise(AMQProtocolSession session, Permission permission, AMQMethodBody body, Object... parameters) throws AMQConnectionException
+ public static final ACLPluginFactory FACTORY = new ACLPluginFactory()
+ {
+ public boolean supportsTag(String name)
+ {
+ return false;
+ }
+
+ public ACLPlugin newInstance(Configuration config)
+ {
+ return new DenyAll();
+ }
+ };
+
+ public AccessResult authorise(AMQProtocolSession session,
+ Permission permission, AMQMethodBody body, Object... parameters)
+ throws AMQConnectionException
{
if (ACLManager.getLogger().isInfoEnabled())
{
+ ACLManager.getLogger().info(
+ "Denying user:" + session.getPrincipal());
}
- ACLManager.getLogger().info("Denying user:" + session.getAuthorizedID() + " for :" + permission.toString()
- + " on " + body.getClass().getSimpleName()
- + (parameters == null || parameters.length == 0 ? "" : "-" + AllowAll.accessablesToString(parameters)));
-
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "DenyAll Plugin");
+ throw body.getConnectionException(AMQConstant.ACCESS_REFUSED,
+ "DenyAll Plugin");
}
public String getPluginName()
{
- return "DenyAll";
+ return getClass().getSimpleName();
}
- public void setConfiguaration(Configuration config)
+ @Override
+ protected AuthzResult getResult()
{
- //no-op
+ // Always deny
+ return AuthzResult.DENIED;
}
+
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java
new file mode 100644
index 0000000000..fc1bc048d4
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.security.access.plugins;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.qpid.server.security.access.ACLPlugin;
+import org.apache.qpid.server.security.access.ACLPluginFactory;
+
+/**
+ *
+ * Used to suppress warnings in legacy config files that have things in <security> which aren't handled by a plugin directly.
+ *
+ */
+public class LegacyAccessPlugin extends BasicACLPlugin
+{
+ public static final ACLPluginFactory FACTORY = new ACLPluginFactory()
+ {
+ private Collection maskedTags = new HashSet<String>();
+ {
+ maskedTags.add("principal-databases");
+ maskedTags.add("access");
+ maskedTags.add("msg-auth");
+ maskedTags.add("false");
+ maskedTags.add("jmx");
+ }
+
+ public boolean supportsTag(String name)
+ {
+ return maskedTags .contains(name);
+ }
+
+ public ACLPlugin newInstance(Configuration config)
+ {
+ return new LegacyAccessPlugin();
+ }
+ };
+
+ public String getPluginName()
+ {
+ return getClass().getSimpleName();
+ }
+
+ @Override
+ protected AuthzResult getResult()
+ {
+ // Always abstain
+ return AuthzResult.ABSTAIN;
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java
index 251f4e6330..a5bdf662af 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java
@@ -22,21 +22,17 @@
package org.apache.qpid.server.security.access.plugins;
import org.apache.commons.configuration.Configuration;
-import org.apache.log4j.Logger;
-import org.apache.qpid.AMQConnectionException;
-import org.apache.qpid.framing.AMQMethodBody;
import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.BasicConsumeBody;
-import org.apache.qpid.framing.BasicPublishBody;
-import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.security.access.ACLManager;
+import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.security.access.ACLPlugin;
+import org.apache.qpid.server.security.access.ACLPluginFactory;
import org.apache.qpid.server.security.access.AccessResult;
import org.apache.qpid.server.security.access.Permission;
import org.apache.qpid.server.security.access.PrincipalPermissions;
+import org.apache.qpid.server.security.PrincipalHolder;
+import org.apache.qpid.server.virtualhost.VirtualHost;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -46,6 +42,21 @@ import java.util.concurrent.ConcurrentHashMap;
*/
public class SimpleXML implements ACLPlugin
{
+ public static final ACLPluginFactory FACTORY = new ACLPluginFactory()
+ {
+ public boolean supportsTag(String name)
+ {
+ return name.startsWith("access_control_list");
+ }
+
+ public ACLPlugin newInstance(Configuration config)
+ {
+ SimpleXML plugin = new SimpleXML();
+ plugin.setConfiguration(config);
+ return plugin;
+ }
+ };
+
private Map<String, PrincipalPermissions> _users;
private final AccessResult GRANTED = new AccessResult(this, AccessResult.AccessStatus.GRANTED);
@@ -54,7 +65,7 @@ public class SimpleXML implements ACLPlugin
_users = new ConcurrentHashMap<String, PrincipalPermissions>();
}
- public void setConfiguaration(Configuration config)
+ public void setConfiguration(Configuration config)
{
processConfig(config);
}
@@ -66,19 +77,40 @@ public class SimpleXML implements ACLPlugin
processConsume(config);
processCreate(config);
+
+ processAccess(config);
}
+ private void processAccess(Configuration config)
+ {
+ Configuration accessConfig = config.subset("access_control_list.access");
+
+ if(accessConfig.isEmpty())
+ {
+ //there is no access configuration to process
+ return;
+ }
+
+ // Process users that have full access permission
+ String[] users = accessConfig.getStringArray("users.user");
+
+ for (String user : users)
+ {
+ grant(Permission.ACCESS, user);
+ }
+ }
+
/**
- * Publish format takes
- * Exchange + Routing Key Pairs
+ * Publish format takes Exchange + Routing Key Pairs
*
- * @param config XML Configuration
+ * @param config
+ * XML Configuration
*/
private void processPublish(Configuration config)
{
- Configuration publishConfig = config.subset("security.access_control_list.publish");
+ Configuration publishConfig = config.subset("access_control_list.publish");
- //Process users that have full publish permission
+ // Process users that have full publish permission
String[] users = publishConfig.getStringArray("users.user");
for (String user : users)
@@ -92,33 +124,33 @@ public class SimpleXML implements ACLPlugin
while (!exchangeConfig.isEmpty())
{
- //Get Exchange Name
+ // Get Exchange Name
AMQShortString exchangeName = new AMQShortString(exchangeConfig.getString("name"));
- //Get Routing Keys
+ // Get Routing Keys
int keyCount = 0;
Configuration routingkeyConfig = exchangeConfig.subset("routing_keys.routing_key(" + keyCount + ")");
while (!routingkeyConfig.isEmpty())
{
- //Get RoutingKey Value
+ // Get RoutingKey Value
AMQShortString routingKeyValue = new AMQShortString(routingkeyConfig.getString("value"));
- //Apply Exchange + RoutingKey permissions to Users
+ // Apply Exchange + RoutingKey permissions to Users
users = routingkeyConfig.getStringArray("users.user");
for (String user : users)
{
grant(Permission.PUBLISH, user, exchangeName, routingKeyValue);
}
- //Apply permissions to Groups
+ // Apply permissions to Groups
// Check for more configs
keyCount++;
routingkeyConfig = exchangeConfig.subset("routing_keys.routing_key(" + keyCount + ")");
}
- //Apply Exchange wide permissions to Users
+ // Apply Exchange wide permissions to Users
users = exchangeConfig.getStringArray("exchange(" + exchangeCount + ").users.user");
for (String user : users)
@@ -126,7 +158,7 @@ public class SimpleXML implements ACLPlugin
grant(Permission.PUBLISH, user, exchangeName);
}
- //Apply permissions to Groups
+ // Apply permissions to Groups
exchangeCount++;
exchangeConfig = publishConfig.subset("exchanges.exchange(" + exchangeCount + ")");
}
@@ -147,7 +179,25 @@ public class SimpleXML implements ACLPlugin
private void processConsume(Configuration config)
{
- Configuration consumeConfig = config.subset("security.access_control_list.consume");
+ boolean temporary = false;
+ Configuration tempConfig = null;
+ Configuration consumeConfig = config.subset("access_control_list.consume");
+
+ tempConfig = consumeConfig.subset("queues.temporary(0)");
+ if (tempConfig != null)
+ {
+ temporary = true;
+ }
+
+ //Permission all users who have rights to temp queues and topics
+ if (tempConfig != null && !tempConfig.isEmpty())
+ {
+ String[] tempUsers = tempConfig.getStringArray("users.user");
+ for (String user : tempUsers)
+ {
+ grant(Permission.CONSUME, user, temporary);
+ }
+ }
// Process queue limited users
int queueCount = 0;
@@ -155,20 +205,20 @@ public class SimpleXML implements ACLPlugin
while (!queueConfig.isEmpty())
{
- //Get queue Name
+ // Get queue Name
AMQShortString queueName = new AMQShortString(queueConfig.getString("name"));
// if there is no name then there may be a temporary element
- boolean temporary = queueConfig.containsKey("temporary");
+
boolean ownQueues = queueConfig.containsKey("own_queues");
- //Process permissions for this queue
+ // Process permissions for this queue
String[] users = queueConfig.getStringArray("users.user");
for (String user : users)
{
- grant(Permission.CONSUME, user, queueName, temporary, ownQueues);
+ grant(Permission.CONSUME, user, queueName, ownQueues);
}
- //See if we have another config
+ // See if we have another config
queueCount++;
queueConfig = consumeConfig.subset("queues.queue(" + queueCount + ")");
}
@@ -178,26 +228,42 @@ public class SimpleXML implements ACLPlugin
for (String user : users)
{
+ //NOTE: this call does not appear to do anything inside the grant section for consume
grant(Permission.CONSUME, user);
}
}
private void processCreate(Configuration config)
{
- Configuration createConfig = config.subset("security.access_control_list.create");
+ boolean temporary = false;
+ Configuration tempConfig = null;
+ Configuration createConfig = config.subset("access_control_list.create");
+
+ tempConfig = createConfig.subset("queues.temporary(0)");
+ if (tempConfig != null)
+ {
+ temporary = true;
+ }
+
+ //Permission all users who have rights to temp queues and topics
+ if (tempConfig != null && !tempConfig.isEmpty())
+ {
+ String[] tempUsers = tempConfig.getStringArray("users.user");
+ for (String user : tempUsers)
+ {
+ grant(Permission.CREATEQUEUE, user, temporary);
+ }
+ }
// Process create permissions for queue creation
int queueCount = 0;
Configuration queueConfig = createConfig.subset("queues.queue(" + queueCount + ")");
while (!queueConfig.isEmpty())
{
- //Get queue Name
+ // Get queue Name
AMQShortString queueName = new AMQShortString(queueConfig.getString("name"));
- // if there is no name then there may be a temporary element
- boolean temporary = queueConfig.containsKey("temporary");
-
int exchangeCount = 0;
Configuration exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")");
@@ -206,18 +272,20 @@ public class SimpleXML implements ACLPlugin
AMQShortString exchange = new AMQShortString(exchangeConfig.getString("name"));
AMQShortString routingKey = new AMQShortString(exchangeConfig.getString("routing_key"));
-
- //Process permissions for this queue
+
+ // Process permissions for this queue
String[] users = exchangeConfig.getStringArray("users.user");
for (String user : users)
{
- grant(Permission.CREATE, user, temporary,
- (queueName.equals("") ? null : queueName),
- (exchange.equals("") ? null : exchange),
- (routingKey.equals("") ? null : routingKey));
+ //This is broken as the user name is not stored
+ grant(Permission.CREATEEXCHANGE, user, exchange);
+
+ //This call could be cleaned up as temporary is now being set earlier (above)
+ grant(Permission.CREATEQUEUE, user, temporary, (queueName.equals("") ? null : queueName), (exchange
+ .equals("") ? null : exchange), (routingKey.equals("") ? null : routingKey));
}
- //See if we have another config
+ // See if we have another config
exchangeCount++;
exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")");
}
@@ -227,10 +295,10 @@ public class SimpleXML implements ACLPlugin
for (String user : users)
{
- grant(Permission.CREATE, user, temporary, queueName);
+ grant(Permission.CREATEQUEUE, user, temporary, queueName);
}
- //See if we have another config
+ // See if we have another config
queueCount++;
queueConfig = createConfig.subset("queues.queue(" + queueCount + ")");
}
@@ -244,14 +312,15 @@ public class SimpleXML implements ACLPlugin
AMQShortString exchange = new AMQShortString(exchangeConfig.getString("name"));
AMQShortString clazz = new AMQShortString(exchangeConfig.getString("class"));
- //Process permissions for this queue
+ // Process permissions for this queue
String[] users = exchangeConfig.getStringArray("users.user");
for (String user : users)
{
- grant(Permission.CREATE, user, exchange, clazz);
+ //And this is broken too
+ grant(Permission.CREATEEXCHANGE, user, exchange, clazz);
}
- //See if we have another config
+ // See if we have another config
exchangeCount++;
exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")");
}
@@ -261,10 +330,10 @@ public class SimpleXML implements ACLPlugin
for (String user : users)
{
- grant(Permission.CREATE, user);
+ grant(Permission.CREATEEXCHANGE, user);
+ grant(Permission.CREATEQUEUE, user);
}
-
}
public String getPluginName()
@@ -272,71 +341,143 @@ public class SimpleXML implements ACLPlugin
return "Simple";
}
- public AccessResult authorise(AMQProtocolSession session, Permission permission, AMQMethodBody body, Object... parameters) throws AMQConnectionException
+ public AuthzResult authoriseBind(PrincipalHolder session, Exchange exch, AMQQueue queue, AMQShortString routingKey)
{
- String error = "";
-
- if (ACLManager.getLogger().isInfoEnabled())
+ PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName());
+ if (principalPermissions == null)
+ {
+ return AuthzResult.DENIED;
+ }
+ else
+ {
+ return principalPermissions.authorise(Permission.BIND, null, exch, queue, routingKey);
+ }
+ }
+
+ public AuthzResult authoriseConnect(PrincipalHolder session, VirtualHost virtualHost)
+ {
+ PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName());
+ if (principalPermissions == null)
+ {
+ return AuthzResult.DENIED;
+ }
+ else
+ {
+ return principalPermissions.authorise(Permission.ACCESS);
+ }
+ }
+
+ public AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck, AMQQueue queue)
+ {
+ PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName());
+ if (principalPermissions == null)
+ {
+ return AuthzResult.DENIED;
+ }
+ else
{
- ACLManager.getLogger().info("Simple Authorisation processing user:" + session.getAuthorizedID() + " for :" + permission.toString()
- + " on " + body.getClass().getSimpleName()
- + (parameters == null || parameters.length == 0 ? "" : "-" + AllowAll.accessablesToString(parameters)));
+ return principalPermissions.authorise(Permission.CONSUME, queue);
}
+ }
- String username = session.getAuthorizedID().getName();
+ public AuthzResult authoriseConsume(PrincipalHolder session, boolean exclusive, boolean noAck, boolean noLocal,
+ boolean nowait, AMQQueue queue)
+ {
+ return authoriseConsume(session, noAck, queue);
+ }
- //Get the Users Permissions
- PrincipalPermissions permissions = _users.get(username);
+ public AuthzResult authoriseCreateExchange(PrincipalHolder session, boolean autoDelete, boolean durable,
+ AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType)
+ {
+ PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName());
+ if (principalPermissions == null)
+ {
+ return AuthzResult.DENIED;
+ }
+ else
+ {
+ return principalPermissions.authorise(Permission.CREATEEXCHANGE, exchangeName);
+ }
+ }
- if (permissions != null)
+ public AuthzResult authoriseCreateQueue(PrincipalHolder session, boolean autoDelete, boolean durable, boolean exclusive,
+ boolean nowait, boolean passive, AMQShortString queue)
+ {
+ PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName());
+ if (principalPermissions == null)
{
- switch (permission)
- {
- case ACCESS:
- return GRANTED;
- case BIND: // Body QueueDeclareBody - Parameters : Exchange, Queue, QueueName
- // Body QueueBindBody - Paramters : Exchange, Queue, QueueName
- if (parameters.length == 3)
- {
- // Parameters : Exchange, Queue, RoutingKey
- if (permissions.authorise(Permission.BIND, body, parameters[0], parameters[1], parameters[2]))
- {
- return GRANTED;
- }
- }
- break;
- case CONSUME: // Parameters : none
- if (parameters.length == 1 && permissions.authorise(Permission.CONSUME, parameters[0]))
- {
- return GRANTED;
- }
- break;
- case CREATE: // Body : QueueDeclareBody | ExchangeDeclareBody - Parameters : none
- if (permissions.authorise(Permission.CREATE, body))
- {
- return GRANTED;
- }
- break;
- case PUBLISH: // Body : BasicPublishBody Parameters : exchange
- if (parameters.length == 1 && parameters[0] instanceof Exchange)
- {
- if (permissions.authorise(Permission.PUBLISH, ((Exchange) parameters[0]).getName(),
- ((BasicPublishBody) body).getRoutingKey()))
- {
- return GRANTED;
- }
- }
- break;
- case PURGE:
- break;
- case DELETE:
- break;
- case UNBIND:
- break;
- }
+ return AuthzResult.DENIED;
+ }
+ else
+ {
+ return principalPermissions.authorise(Permission.CREATEQUEUE, autoDelete, queue);
}
+ }
- //todo potential refactor this ConnectionException Out of here
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, error);
+ public AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue)
+ {
+ PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName());
+ if (principalPermissions == null)
+ {
+ return AuthzResult.DENIED;
+ }
+ else
+ {
+ return principalPermissions.authorise(Permission.DELETE);
+ }
}
+
+ public AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange)
+ {
+ PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName());
+ if (principalPermissions == null)
+ {
+ return AuthzResult.DENIED;
+ }
+ else
+ {
+ return principalPermissions.authorise(Permission.DELETE);
+ }
+ }
+
+ public AuthzResult authorisePublish(PrincipalHolder session, boolean immediate, boolean mandatory,
+ AMQShortString routingKey, Exchange e)
+ {
+ PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName());
+ if (principalPermissions == null)
+ {
+ return AuthzResult.DENIED;
+ }
+ else
+ {
+ return principalPermissions.authorise(Permission.PUBLISH, e, routingKey);
+ }
+ }
+
+ public AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue)
+ {
+ PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName());
+ if (principalPermissions == null)
+ {
+ return AuthzResult.DENIED;
+ }
+ else
+ {
+ return principalPermissions.authorise(Permission.PURGE);
+ }
+ }
+
+ public AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch, AMQShortString routingKey, AMQQueue queue)
+ {
+ PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName());
+ if (principalPermissions == null)
+ {
+ return AuthzResult.DENIED;
+ }
+ else
+ {
+ return principalPermissions.authorise(Permission.UNBIND);
+ }
+ }
+
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java
new file mode 100644
index 0000000000..17d80c63fa
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java
@@ -0,0 +1,256 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.access.plugins.network;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.regex.Pattern;
+
+import org.apache.commons.configuration.CompositeConfiguration;
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.qpid.protocol.ProtocolEngine;
+import org.apache.qpid.server.security.access.ACLPlugin;
+import org.apache.qpid.server.security.access.ACLPluginFactory;
+import org.apache.qpid.server.security.access.plugins.AbstractACLPlugin;
+import org.apache.qpid.server.security.PrincipalHolder;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.util.NetMatcher;
+
+public class FirewallPlugin extends AbstractACLPlugin
+{
+
+ public class FirewallPluginException extends Exception {}
+
+ public static final ACLPluginFactory FACTORY = new ACLPluginFactory()
+ {
+ public boolean supportsTag(String name)
+ {
+ return name.startsWith("firewall");
+ }
+
+ public ACLPlugin newInstance(Configuration config) throws ConfigurationException
+ {
+ FirewallPlugin plugin = new FirewallPlugin();
+ plugin.setConfiguration(config.subset("firewall"));
+ return plugin;
+ }
+ };
+
+ public class FirewallRule
+ {
+
+ private static final long DNS_TIMEOUT = 30000;
+ private AuthzResult _access;
+ private NetMatcher _network;
+ private Pattern[] _hostnamePatterns;
+
+ public FirewallRule(String access, List networks, List hostnames)
+ {
+ _access = (access.equals("allow")) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
+
+ if (networks != null && networks.size() > 0)
+ {
+ String[] networkStrings = objListToStringArray(networks);
+ _network = new NetMatcher(networkStrings);
+ }
+
+ if (hostnames != null && hostnames.size() > 0)
+ {
+ int i = 0;
+ _hostnamePatterns = new Pattern[hostnames.size()];
+ for (String hostname : objListToStringArray(hostnames))
+ {
+ _hostnamePatterns[i++] = Pattern.compile(hostname);
+ }
+ }
+
+ }
+
+ private String[] objListToStringArray(List objList)
+ {
+ String[] networkStrings = new String[objList.size()];
+ int i = 0;
+ for (Object network : objList)
+ {
+ networkStrings[i++] = (String) network;
+ }
+ return networkStrings;
+ }
+
+ public boolean match(InetAddress remote) throws FirewallPluginException
+ {
+ if (_hostnamePatterns != null)
+ {
+ String hostname = getHostname(remote);
+ if (hostname == null)
+ {
+ throw new FirewallPluginException();
+ }
+ for (Pattern pattern : _hostnamePatterns)
+ {
+ if (pattern.matcher(hostname).matches())
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ else
+ {
+ return _network.matchInetNetwork(remote);
+ }
+ }
+
+ /**
+ * @param remote the InetAddress to look up
+ * @return the hostname, null if not found or takes longer than 30s to find
+ */
+ private String getHostname(final InetAddress remote)
+ {
+ final String[] hostname = new String[]{null};
+ final AtomicBoolean done = new AtomicBoolean(false);
+ // Spawn thread
+ Thread thread = new Thread(new Runnable()
+ {
+ public void run()
+ {
+ hostname[0] = remote.getCanonicalHostName();
+ done.getAndSet(true);
+ synchronized (done)
+ {
+ done.notifyAll();
+ }
+ }
+ });
+
+ thread.run();
+ long endTime = System.currentTimeMillis() + DNS_TIMEOUT;
+
+ while (System.currentTimeMillis() < endTime && !done.get())
+ {
+ try
+ {
+ synchronized (done)
+ {
+ done.wait(endTime - System.currentTimeMillis());
+ }
+ }
+ catch (InterruptedException e)
+ {
+ // Check the time and if necessary sleep for a bit longer
+ }
+ }
+ return hostname[0];
+ }
+
+ public AuthzResult getAccess()
+ {
+ return _access;
+ }
+
+ }
+
+ private AuthzResult _default = AuthzResult.ABSTAIN;
+ private FirewallRule[] _rules;
+
+ @Override
+ public AuthzResult authoriseConnect(PrincipalHolder principalHolder, VirtualHost virtualHost)
+ {
+ if(!(principalHolder instanceof ProtocolEngine))
+ {
+ return AuthzResult.ABSTAIN; // We only deal with tcp sessions
+ }
+
+ ProtocolEngine session = (ProtocolEngine) principalHolder;
+
+ SocketAddress sockAddr = session.getRemoteAddress();
+ if (!(sockAddr instanceof InetSocketAddress))
+ {
+ return AuthzResult.ABSTAIN; // We only deal with tcp sessions
+ }
+
+ InetAddress addr = ((InetSocketAddress) sockAddr).getAddress();
+
+ if (addr == null)
+ {
+ return AuthzResult.ABSTAIN; // Not an Inet socket on the other end
+ }
+
+ boolean match = false;
+ for (FirewallRule rule : _rules)
+ {
+ try
+ {
+ match = rule.match(addr);
+ }
+ catch (FirewallPluginException e)
+ {
+ return AuthzResult.DENIED;
+ }
+ if (match)
+ {
+ return rule.getAccess();
+ }
+ }
+ return _default;
+
+ }
+
+ public void setConfiguration(Configuration config) throws ConfigurationException
+ {
+ // Get default action
+ String defaultAction = config.getString("[@default-action]");
+ if (defaultAction == null)
+ {
+ _default = AuthzResult.ABSTAIN;
+ }
+ else if (defaultAction.toLowerCase().equals("allow"))
+ {
+ _default = AuthzResult.ALLOWED;
+ }
+ else
+ {
+ _default = AuthzResult.DENIED;
+ }
+ CompositeConfiguration finalConfig = new CompositeConfiguration(config);
+
+ List subFiles = config.getList("xml[@fileName]");
+ for (Object subFile : subFiles)
+ {
+ finalConfig.addConfiguration(new XMLConfiguration((String) subFile));
+ }
+
+ // all rules must have an access attribute
+ int numRules = finalConfig.getList("rule[@access]").size();
+ _rules = new FirewallRule[numRules];
+ for (int i = 0; i < numRules; i++)
+ {
+ FirewallRule rule = new FirewallRule(finalConfig.getString("rule(" + i + ")[@access]"), finalConfig.getList("rule("
+ + i + ")[@network]"), finalConfig.getList("rule(" + i + ")[@hostname]"));
+ _rules[i] = rule;
+ }
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java
index 348bccb4e9..889ce815f4 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java
@@ -21,30 +21,29 @@
package org.apache.qpid.server.security.auth.database;
import org.apache.log4j.Logger;
+import org.apache.qpid.server.security.access.management.AMQUserManagementMBean;
import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser;
import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HexInitialiser;
import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser;
-import org.apache.qpid.server.security.access.management.AMQUserManagementMBean;
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.codec.EncoderException;
+import org.apache.qpid.util.FileUtils;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.AccountNotFoundException;
+import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.BufferedReader;
import java.io.FileReader;
-import java.io.UnsupportedEncodingException;
+import java.io.IOException;
import java.io.PrintStream;
-import java.util.regex.Pattern;
-import java.util.Map;
+import java.security.Principal;
import java.util.HashMap;
-import java.util.List;
import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
import java.util.concurrent.locks.ReentrantLock;
-import java.security.Principal;
-import java.security.NoSuchAlgorithmException;
+import java.util.regex.Pattern;
/**
* Represents a user database where the account information is stored in a simple flat file.
@@ -64,8 +63,8 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
private Map<String, AuthenticationProviderInitialiser> _saslServers;
AMQUserManagementMBean _mbean;
- private static final String DEFAULT_ENCODING = "utf-8";
- private Map<String, User> _users = new HashMap<String, User>();
+ public static final String DEFAULT_ENCODING = "utf-8";
+ private Map<String, HashedUser> _users = new HashMap<String, HashedUser>();
private ReentrantLock _userUpdate = new ReentrantLock();
public Base64MD5PasswordFilePrincipalDatabase()
@@ -81,6 +80,11 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
cram.initialise(this);
_saslServers.put(cram.getMechanismName(), cram);
+ //Add the Hex initialiser
+ CRAMMD5HexInitialiser cramHex = new CRAMMD5HexInitialiser();
+ cramHex.initialise(this);
+ _saslServers.put(cramHex.getMechanismName(), cramHex);
+
//fixme The PDs should setup a PD Mangement MBean
// try
// {
@@ -113,6 +117,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
/**
* SASL Callback Mechanism - sets the Password in the PasswordCallback based on the value in the PasswordFile
+ * If you want to change the password for a user, use updatePassword instead.
*
* @param principal The Principal to set the password for
* @param callback The PasswordCallback to call setPassword on
@@ -155,21 +160,66 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException
{
char[] pwd = lookupPassword(principal);
-
+
+ if (pwd == null)
+ {
+ throw new AccountNotFoundException("Unable to lookup the specfied users password");
+ }
+
+ byte[] byteArray = new byte[password.length];
int index = 0;
- boolean verified = true;
+ for (char c : password)
+ {
+ byteArray[index++] = (byte) c;
+ }
+
+ byte[] MD5byteArray;
+ try
+ {
+ MD5byteArray = HashedUser.getMD5(byteArray);
+ }
+ catch (Exception e1)
+ {
+ _logger.warn("Unable to hash password for user '" + principal + "' for comparison");
+ return false;
+ }
+
+ char[] hashedPassword = new char[MD5byteArray.length];
+
+ index = 0;
+ for (byte c : MD5byteArray)
+ {
+ hashedPassword[index++] = (char) c;
+ }
- while (verified & index < password.length)
+ return compareCharArray(pwd, hashedPassword);
+ }
+
+ private boolean compareCharArray(char[] a, char[] b)
+ {
+ boolean equal = false;
+ if (a.length == b.length)
{
- verified = (pwd[index] == password[index]);
- index++;
+ equal = true;
+ int index = 0;
+ while (equal && index < a.length)
+ {
+ equal = a[index] == b[index];
+ index++;
+ }
}
- return verified;
+ return equal;
}
+ /**
+ * Changes the password for the specified user
+ *
+ * @param principal to change the password for
+ * @param password plaintext password to set the password too
+ */
public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException
{
- User user = _users.get(principal.getName());
+ HashedUser user = _users.get(principal.getName());
if (user == null)
{
@@ -182,7 +232,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
{
_userUpdate.lock();
char[] orig = user.getPassword();
- user.setPassword(password);
+ user.setPassword(password,false);
try
{
@@ -193,7 +243,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
_logger.error("Unable to save password file, password change for user'"
+ principal + "' will revert at restart");
//revert the password change
- user.setPassword(orig);
+ user.setPassword(orig,true);
return false;
}
return true;
@@ -219,7 +269,17 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
return false;
}
- User user = new User(principal.getName(), password);
+ HashedUser user;
+ try
+ {
+ user = new HashedUser(principal.getName(), password);
+ }
+ catch (Exception e1)
+ {
+ _logger.warn("Unable to create new user '" + principal.getName() + "'");
+ return false;
+ }
+
try
{
@@ -249,7 +309,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
public boolean deletePrincipal(Principal principal) throws AccountNotFoundException
{
- User user = _users.get(principal.getName());
+ HashedUser user = _users.get(principal.getName());
if (user == null)
{
@@ -284,7 +344,6 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
return true;
}
-
public Map<String, AuthenticationProviderInitialiser> getMechanisms()
{
return _saslServers;
@@ -314,7 +373,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
*/
private char[] lookupPassword(String name)
{
- User user = _users.get(name);
+ HashedUser user = _users.get(name);
if (user == null)
{
return null;
@@ -325,7 +384,6 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
}
}
-
private void loadPasswordFile() throws IOException
{
try
@@ -347,7 +405,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
continue;
}
- User user = new User(result);
+ HashedUser user = new HashedUser(result);
_logger.info("Created user:" + user);
_users.put(user.getName(), user);
}
@@ -377,11 +435,17 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
BufferedReader reader = null;
PrintStream writer = null;
- File tmp = new File(_passwordFile.getAbsolutePath() + ".tmp");
- if (tmp.exists())
+
+ Random r = new Random();
+ File tmp;
+ do
{
- tmp.delete();
+ tmp = new File(_passwordFile.getPath() + r.nextInt() + ".tmp");
}
+ while(tmp.exists());
+
+ tmp.deleteOnExit();
+
try
{
writer = new PrintStream(tmp);
@@ -394,10 +458,11 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
if (result == null || result.length < 2 || result[0].startsWith("#"))
{
writer.write(line.getBytes(DEFAULT_ENCODING));
+ writer.println();
continue;
}
- User user = _users.get(result[0]);
+ HashedUser user = _users.get(result[0]);
if (user == null)
{
@@ -415,7 +480,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
{
try
{
- byte[] encodedPassword = user.getEncodePassword();
+ byte[] encodedPassword = user.getEncodedPassword();
writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING));
writer.write(encodedPassword);
@@ -433,14 +498,14 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
}
}
- for (User user : _users.values())
+ for (HashedUser user : _users.values())
{
if (user.isModified())
{
byte[] encodedPassword;
try
{
- encodedPassword = user.getEncodePassword();
+ encodedPassword = user.getEncodedPassword();
writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING));
writer.write(encodedPassword);
writer.println();
@@ -453,6 +518,11 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
}
}
}
+ catch(IOException e)
+ {
+ _logger.error("Unable to create the new password file: " + e);
+ throw new IOException("Unable to create the new password file" + e);
+ }
finally
{
if (reader != null)
@@ -464,16 +534,35 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
{
writer.close();
}
+ }
+
+ // Swap temp file to main password file.
+ File old = new File(_passwordFile.getAbsoluteFile() + ".old");
+ if (old.exists())
+ {
+ old.delete();
+ }
+
+ if(!_passwordFile.renameTo(old))
+ {
+ //unable to rename the existing file to the backup name
+ _logger.error("Could not backup the existing password file");
+ throw new IOException("Could not backup the existing password file");
+ }
- // Swap temp file to main password file.
- File old = new File(_passwordFile.getAbsoluteFile() + ".old");
- if (old.exists())
+ if(!tmp.renameTo(_passwordFile))
+ {
+ //failed to rename the new file to the required filename
+
+ if(!old.renameTo(_passwordFile))
{
- old.delete();
+ //unable to return the backup to required filename
+ _logger.error("Could not rename the new password file into place, and unable to restore original file");
+ throw new IOException("Could not rename the new password file into place, and unable to restore original file");
}
- _passwordFile.renameTo(old);
- tmp.renameTo(_passwordFile);
- tmp.delete();
+
+ _logger.error("Could not rename the new password file into place");
+ throw new IOException("Could not rename the new password file into place");
}
}
finally
@@ -485,114 +574,9 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
}
}
- private class User implements Principal
+ public void reload() throws IOException
{
- String _name;
- char[] _password;
- byte[] _encodedPassword = null;
- private boolean _modified = false;
- private boolean _deleted = false;
-
- User(String[] data) throws UnsupportedEncodingException
- {
- if (data.length != 2)
- {
- throw new IllegalArgumentException("User Data should be lenght 2, username, password");
- }
-
- _name = data[0];
-
- byte[] encoded_password = data[1].getBytes(DEFAULT_ENCODING);
-
- Base64 b64 = new Base64();
- byte[] decoded = b64.decode(encoded_password);
-
- _encodedPassword = encoded_password;
-
- _password = new char[decoded.length];
-
- int index = 0;
- for (byte c : decoded)
- {
- _password[index++] = (char) c;
- }
- }
-
- public User(String name, char[] password)
- {
- _name = name;
- setPassword(password);
- }
-
- public String getName()
- {
- return _name;
- }
-
- public String toString()
- {
- if (_logger.isDebugEnabled())
- {
- return getName() + ((_encodedPassword == null) ? "" : ":" + new String(_encodedPassword));
- }
- else
- {
- return _name;
- }
- }
-
- char[] getPassword()
- {
- return _password;
- }
-
- void setPassword(char[] password)
- {
- _password = password;
- _modified = true;
- _encodedPassword = null;
- }
-
-
- byte[] getEncodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException
- {
- if (_encodedPassword == null)
- {
- encodePassword();
- }
- return _encodedPassword;
- }
-
- private void encodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException
- {
- byte[] byteArray = new byte[_password.length];
- int index = 0;
- for (char c : _password)
- {
- byteArray[index++] = (byte) c;
- }
- _encodedPassword = (new Base64()).encode(byteArray);
- }
-
- public boolean isModified()
- {
- return _modified;
- }
-
- public boolean isDeleted()
- {
- return _deleted;
- }
-
- public void delete()
- {
- _deleted = true;
- }
-
- public void saved()
- {
- _modified = false;
- }
-
+ loadPasswordFile();
}
+
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java
index 15c62a62e4..2619a69cfd 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java
@@ -34,6 +34,7 @@ import org.apache.log4j.Logger;
import org.apache.qpid.configuration.PropertyUtils;
import org.apache.qpid.configuration.PropertyException;
+import org.apache.qpid.server.configuration.ServerConfiguration;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager;
@@ -46,20 +47,18 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab
{
private static final Logger _logger = Logger.getLogger(ConfigurationFilePrincipalDatabaseManager.class);
- private static final String _base = "security.principal-databases.principal-database";
-
Map<String, PrincipalDatabase> _databases;
- public ConfigurationFilePrincipalDatabaseManager(Configuration configuration) throws Exception
+ public ConfigurationFilePrincipalDatabaseManager(ServerConfiguration _configuration) throws Exception
{
_logger.info("Initialising PrincipleDatabase authentication manager");
- _databases = initialisePrincipalDatabases(configuration);
+ _databases = initialisePrincipalDatabases(_configuration);
}
- private Map<String, PrincipalDatabase> initialisePrincipalDatabases(Configuration configuration) throws Exception
+ private Map<String, PrincipalDatabase> initialisePrincipalDatabases(ServerConfiguration _configuration) throws Exception
{
- List<String> databaseNames = configuration.getList(_base + ".name");
- List<String> databaseClasses = configuration.getList(_base + ".class");
+ List<String> databaseNames = _configuration.getPrincipalDatabaseNames();
+ List<String> databaseClasses = _configuration.getPrincipalDatabaseClass();
Map<String, PrincipalDatabase> databases = new HashMap<String, PrincipalDatabase>();
if (databaseNames.size() == 0)
@@ -84,7 +83,7 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab
throw new Exception("Principal databases must implement the PrincipalDatabase interface");
}
- initialisePrincipalDatabase((PrincipalDatabase) o, configuration, i);
+ initialisePrincipalDatabase((PrincipalDatabase) o, _configuration, i);
String name = databaseNames.get(i);
if ((name == null) || (name.length() == 0))
@@ -95,7 +94,7 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab
PrincipalDatabase pd = databases.get(name);
if (pd != null)
{
- throw new Exception("Duplicate principal database name not provided");
+ throw new Exception("Duplicate principal database name not permitted");
}
_logger.info("Initialised principal database '" + name + "' successfully");
@@ -105,12 +104,11 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab
return databases;
}
- private void initialisePrincipalDatabase(PrincipalDatabase principalDatabase, Configuration config, int index)
+ private void initialisePrincipalDatabase(PrincipalDatabase principalDatabase, ServerConfiguration _configuration, int index)
throws FileNotFoundException, ConfigurationException
{
- String baseName = _base + "(" + index + ").attributes.attribute.";
- List<String> argumentNames = config.getList(baseName + "name");
- List<String> argumentValues = config.getList(baseName + "value");
+ List<String> argumentNames = _configuration.getPrincipalDatabaseAttributeNames(index);
+ List<String> argumentValues = _configuration.getPrincipalDatabaseAttributeValues(index);
for (int i = 0; i < argumentNames.size(); i++)
{
String argName = argumentNames.get(i);
@@ -166,18 +164,17 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab
return _databases;
}
- public void initialiseManagement(Configuration config) throws ConfigurationException
+ public void initialiseManagement(ServerConfiguration config) throws ConfigurationException
{
try
{
AMQUserManagementMBean _mbean = new AMQUserManagementMBean();
- String baseSecurity = "security.jmx";
- List<String> principalDBs = config.getList(baseSecurity + ".principal-database");
+ List<String> principalDBs = config.getManagementPrincipalDBs();
if (principalDBs.size() == 0)
{
- throw new ConfigurationException("No principal-database specified for jmx security(" + baseSecurity + ".principal-database)");
+ throw new ConfigurationException("No principal-database specified for jmx security");
}
String databaseName = principalDBs.get(0);
@@ -191,11 +188,11 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab
_mbean.setPrincipalDatabase(database);
- List<String> jmxaccesslist = config.getList(baseSecurity + ".access");
+ List<String> jmxaccesslist = config.getManagementAccessList();
if (jmxaccesslist.size() == 0)
{
- throw new ConfigurationException("No access control files specified for jmx security(" + baseSecurity + ".access)");
+ throw new ConfigurationException("No access control files specified for jmx security");
}
String jmxaccesssFile = null;
@@ -218,14 +215,7 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab
_logger.warn("Unable to load access file:" + jmxaccesssFile);
}
- try
- {
- _mbean.register();
- }
- catch (AMQException e)
- {
- _logger.warn("Unable to register user management MBean");
- }
+ _mbean.register();
}
catch (JMException e)
{
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java
new file mode 100644
index 0000000000..3690e7f92a
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java
@@ -0,0 +1,169 @@
+/*
+*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.auth.database;
+
+import org.apache.commons.codec.EncoderException;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.log4j.Logger;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+
+public class HashedUser implements Principal
+{
+ private static final Logger _logger = Logger.getLogger(HashedUser.class);
+
+ String _name;
+ char[] _password;
+ byte[] _encodedPassword = null;
+ private boolean _modified = false;
+ private boolean _deleted = false;
+
+ HashedUser(String[] data) throws UnsupportedEncodingException
+ {
+ if (data.length != 2)
+ {
+ throw new IllegalArgumentException("User Data should be length 2, username, password");
+ }
+
+ _name = data[0];
+
+ byte[] encoded_password = data[1].getBytes(Base64MD5PasswordFilePrincipalDatabase.DEFAULT_ENCODING);
+
+ Base64 b64 = new Base64();
+ byte[] decoded = b64.decode(encoded_password);
+
+ _encodedPassword = encoded_password;
+
+ _password = new char[decoded.length];
+
+ int index = 0;
+ for (byte c : decoded)
+ {
+ _password[index++] = (char) c;
+ }
+ }
+
+ public HashedUser(String name, char[] password) throws UnsupportedEncodingException, NoSuchAlgorithmException
+ {
+ _name = name;
+ setPassword(password,false);
+ }
+
+ public static byte[] getMD5(byte[] data) throws NoSuchAlgorithmException, UnsupportedEncodingException
+ {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+
+ for (byte b : data)
+ {
+ md.update(b);
+ }
+
+ return md.digest();
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public String toString()
+ {
+ return _name;
+ }
+
+ char[] getPassword()
+ {
+ return _password;
+ }
+
+ void setPassword(char[] password, boolean alreadyHashed) throws UnsupportedEncodingException, NoSuchAlgorithmException
+ {
+ if(alreadyHashed){
+ _password = password;
+ }
+ else
+ {
+ byte[] byteArray = new byte[password.length];
+ int index = 0;
+ for (char c : password)
+ {
+ byteArray[index++] = (byte) c;
+ }
+
+ byte[] MD5byteArray = getMD5(byteArray);
+
+ _password = new char[MD5byteArray.length];
+
+ index = 0;
+ for (byte c : MD5byteArray)
+ {
+ _password[index++] = (char) c;
+ }
+ }
+
+ _modified = true;
+ _encodedPassword = null;
+ }
+
+ byte[] getEncodedPassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException
+ {
+ if (_encodedPassword == null)
+ {
+ encodePassword();
+ }
+ return _encodedPassword;
+ }
+
+ private void encodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException
+ {
+ byte[] byteArray = new byte[_password.length];
+ int index = 0;
+ for (char c : _password)
+ {
+ byteArray[index++] = (byte) c;
+ }
+ _encodedPassword = (new Base64()).encode(byteArray);
+ }
+
+ public boolean isModified()
+ {
+ return _modified;
+ }
+
+ public boolean isDeleted()
+ {
+ return _deleted;
+ }
+
+ public void delete()
+ {
+ _deleted = true;
+ }
+
+ public void saved()
+ {
+ _modified = false;
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java
index 352d41a0ba..8665e579ba 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java
@@ -34,11 +34,14 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
+import java.io.PrintStream;
import java.security.Principal;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Pattern;
/**
@@ -50,13 +53,18 @@ import java.util.regex.Pattern;
*/
public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase
{
+ public static final String DEFAULT_ENCODING = "utf-8";
+
private static final Logger _logger = Logger.getLogger(PlainPasswordFilePrincipalDatabase.class);
- protected File _passwordFile;
+ private File _passwordFile;
- protected Pattern _regexp = Pattern.compile(":");
+ private Pattern _regexp = Pattern.compile(":");
- protected Map<String, AuthenticationProviderInitialiser> _saslServers;
+ private Map<String, AuthenticationProviderInitialiser> _saslServers;
+
+ private Map<String, PlainUser> _users = new HashMap<String, PlainUser>();
+ private ReentrantLock _userUpdate = new ReentrantLock();
public PlainPasswordFilePrincipalDatabase()
{
@@ -83,7 +91,7 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase
_saslServers.put(cram.getMechanismName(), cram);
}
- public void setPasswordFile(String passwordFile) throws FileNotFoundException
+ public void setPasswordFile(String passwordFile) throws IOException
{
File f = new File(passwordFile);
_logger.info("PlainPasswordFile using file " + f.getAbsolutePath());
@@ -97,10 +105,20 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase
throw new FileNotFoundException("Cannot read password file " + f +
". Check permissions.");
}
+
+ loadPasswordFile();
}
- public void setPassword(Principal principal, PasswordCallback callback) throws IOException,
- AccountNotFoundException
+ /**
+ * SASL Callback Mechanism - sets the Password in the PasswordCallback based on the value in the PasswordFile
+ * If you want to change the password for a user, use updatePassword instead.
+ *
+ * @param principal The Principal to set the password for
+ * @param callback The PasswordCallback to call setPassword on
+ *
+ * @throws AccountNotFoundException If the Principal cannot be found in this Database
+ */
+ public void setPassword(Principal principal, PasswordCallback callback) throws AccountNotFoundException
{
if (_passwordFile == null)
{
@@ -111,6 +129,7 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase
throw new IllegalArgumentException("principal must not be null");
}
char[] pwd = lookupPassword(principal.getName());
+
if (pwd != null)
{
callback.setPassword(pwd);
@@ -121,33 +140,151 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase
}
}
+ /**
+ * Used to verify that the presented Password is correct. Currently only used by Management Console
+ *
+ * @param principal The principal to authenticate
+ * @param password The plaintext password to check
+ *
+ * @return true if password is correct
+ *
+ * @throws AccountNotFoundException if the principal cannot be found
+ */
public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException
{
- try
- {
- char[] pwd = lookupPassword(principal);
- return compareCharArray(pwd, password);
- }
- catch (IOException e)
+ char[] pwd = lookupPassword(principal);
+
+ if (pwd == null)
{
- return false;
+ throw new AccountNotFoundException("Unable to lookup the specfied users password");
}
+
+ return compareCharArray(pwd, password);
+
}
+ /**
+ * Changes the password for the specified user
+ *
+ * @param principal to change the password for
+ * @param password plaintext password to set the password too
+ */
public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException
{
- return false; // updates denied
+ PlainUser user = _users.get(principal.getName());
+
+ if (user == null)
+ {
+ throw new AccountNotFoundException(principal.getName());
+ }
+
+ try
+ {
+ try
+ {
+ _userUpdate.lock();
+ char[] orig = user.getPassword();
+ user.setPassword(password);
+
+ try
+ {
+ savePasswordFile();
+ }
+ catch (IOException e)
+ {
+ _logger.error("Unable to save password file, password change for user '" + principal + "' discarded");
+ //revert the password change
+ user.setPassword(orig);
+ return false;
+ }
+ return true;
+ }
+ finally
+ {
+ if (_userUpdate.isHeldByCurrentThread())
+ {
+ _userUpdate.unlock();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
}
public boolean createPrincipal(Principal principal, char[] password)
{
- return false; // updates denied
+ if (_users.get(principal.getName()) != null)
+ {
+ return false;
+ }
+
+ PlainUser user = new PlainUser(principal.getName(), password);
+
+ try
+ {
+ _userUpdate.lock();
+ _users.put(user.getName(), user);
+
+ try
+ {
+ savePasswordFile();
+ return true;
+ }
+ catch (IOException e)
+ {
+ //remove the use on failure.
+ _users.remove(user.getName());
+ _logger.warn("Unable to create user '" + user.getName());
+ return false;
+ }
+ }
+ finally
+ {
+ if (_userUpdate.isHeldByCurrentThread())
+ {
+ _userUpdate.unlock();
+ }
+ }
}
public boolean deletePrincipal(Principal principal) throws AccountNotFoundException
{
- return false; // updates denied
+ PlainUser user = _users.get(principal.getName());
+
+ if (user == null)
+ {
+ throw new AccountNotFoundException(principal.getName());
+ }
+
+ try
+ {
+ _userUpdate.lock();
+ user.delete();
+
+ try
+ {
+ savePasswordFile();
+ }
+ catch (IOException e)
+ {
+ _logger.error("Unable to remove user '" + user.getName() + "' from password file.");
+ return false;
+ }
+
+ _users.remove(user.getName());
+ }
+ finally
+ {
+ if (_userUpdate.isHeldByCurrentThread())
+ {
+ _userUpdate.unlock();
+ }
+ }
+
+ return true;
}
public Map<String, AuthenticationProviderInitialiser> getMechanisms()
@@ -157,21 +294,14 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase
public List<Principal> getUsers()
{
- return new LinkedList<Principal>(); //todo
+ return new LinkedList<Principal>(_users.values());
}
public Principal getUser(String username)
{
- try
+ if (_users.containsKey(username))
{
- if (lookupPassword(username) != null)
- {
- return new UsernamePrincipal(username);
- }
- }
- catch (IOException e)
- {
- //fall through to null return
+ return new UsernamePrincipal(username);
}
return null;
}
@@ -197,44 +327,200 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase
* Looks up the password for a specified user in the password file. Note this code is <b>not</b> secure since it
* creates strings of passwords. It should be modified to create only char arrays which get nulled out.
*
- * @param name the name of the principal to lookup
- *
- * @return char[] of the password
+ * @param name The principal name to lookup
*
- * @throws java.io.IOException whilst accessing the file
+ * @return a char[] for use in SASL.
*/
- private char[] lookupPassword(String name) throws IOException
+ private char[] lookupPassword(String name)
+ {
+ PlainUser user = _users.get(name);
+ if (user == null)
+ {
+ return null;
+ }
+ else
+ {
+ return user.getPassword();
+ }
+ }
+
+ private void loadPasswordFile() throws IOException
{
- BufferedReader reader = null;
try
{
- reader = new BufferedReader(new FileReader(_passwordFile));
- String line;
+ _userUpdate.lock();
+ _users.clear();
- while ((line = reader.readLine()) != null)
+ BufferedReader reader = null;
+ try
{
- if (!line.startsWith("#"))
+ reader = new BufferedReader(new FileReader(_passwordFile));
+ String line;
+
+ while ((line = reader.readLine()) != null)
{
String[] result = _regexp.split(line);
- if (result == null || result.length < 2)
+ if (result == null || result.length < 2 || result[0].startsWith("#"))
{
continue;
}
- if (name.equals(result[0]))
+ PlainUser user = new PlainUser(result);
+ _logger.info("Created user:" + user);
+ _users.put(user.getName(), user);
+ }
+ }
+ finally
+ {
+ if (reader != null)
+ {
+ reader.close();
+ }
+ }
+ }
+ finally
+ {
+ if (_userUpdate.isHeldByCurrentThread())
+ {
+ _userUpdate.unlock();
+ }
+ }
+ }
+
+ private void savePasswordFile() throws IOException
+ {
+ try
+ {
+ _userUpdate.lock();
+
+ BufferedReader reader = null;
+ PrintStream writer = null;
+
+ Random r = new Random();
+ File tmp;
+ do
+ {
+ tmp = new File(_passwordFile.getPath() + r.nextInt() + ".tmp");
+ }
+ while(tmp.exists());
+
+ tmp.deleteOnExit();
+
+ try
+ {
+ writer = new PrintStream(tmp);
+ reader = new BufferedReader(new FileReader(_passwordFile));
+ String line;
+
+ while ((line = reader.readLine()) != null)
+ {
+ String[] result = _regexp.split(line);
+ if (result == null || result.length < 2 || result[0].startsWith("#"))
+ {
+ writer.write(line.getBytes(DEFAULT_ENCODING));
+ writer.println();
+ continue;
+ }
+
+ PlainUser user = _users.get(result[0]);
+
+ if (user == null)
{
- return result[1].toCharArray();
+ writer.write(line.getBytes(DEFAULT_ENCODING));
+ writer.println();
+ }
+ else if (!user.isDeleted())
+ {
+ if (!user.isModified())
+ {
+ writer.write(line.getBytes(DEFAULT_ENCODING));
+ writer.println();
+ }
+ else
+ {
+ byte[] password = user.getPasswordBytes();
+
+ writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING));
+ writer.write(password);
+ writer.println();
+
+ user.saved();
+ }
+ }
+ }
+
+ for (PlainUser user : _users.values())
+ {
+ if (user.isModified())
+ {
+ byte[] password;
+ password = user.getPasswordBytes();
+ writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING));
+ writer.write(password);
+ writer.println();
+ user.saved();
}
}
}
- return null;
+ catch(IOException e)
+ {
+ _logger.error("Unable to create the new password file: " + e);
+ throw new IOException("Unable to create the new password file" + e);
+ }
+ finally
+ {
+ if (reader != null)
+ {
+ reader.close();
+ }
+
+ if (writer != null)
+ {
+ writer.close();
+ }
+ }
+
+ // Swap temp file to main password file.
+ File old = new File(_passwordFile.getAbsoluteFile() + ".old");
+ if (old.exists())
+ {
+ old.delete();
+ }
+
+ if(!_passwordFile.renameTo(old))
+ {
+ //unable to rename the existing file to the backup name
+ _logger.error("Could not backup the existing password file");
+ throw new IOException("Could not backup the existing password file");
+ }
+
+ if(!tmp.renameTo(_passwordFile))
+ {
+ //failed to rename the new file to the required filename
+
+ if(!old.renameTo(_passwordFile))
+ {
+ //unable to return the backup to required filename
+ _logger.error("Could not rename the new password file into place, and unable to restore original file");
+ throw new IOException("Could not rename the new password file into place, and unable to restore original file");
+ }
+
+ _logger.error("Could not rename the new password file into place");
+ throw new IOException("Could not rename the new password file into place");
+ }
+
}
finally
{
- if (reader != null)
+ if (_userUpdate.isHeldByCurrentThread())
{
- reader.close();
+ _userUpdate.unlock();
}
}
}
+
+ public void reload() throws IOException
+ {
+ loadPasswordFile();
+ }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainUser.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainUser.java
new file mode 100644
index 0000000000..46a78a55aa
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainUser.java
@@ -0,0 +1,106 @@
+/*
+*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.auth.database;
+
+import org.apache.log4j.Logger;
+
+import java.security.Principal;
+
+public class PlainUser implements Principal
+{
+ private String _name;
+ private char[] _password;
+ private boolean _modified = false;
+ private boolean _deleted = false;
+
+ PlainUser(String[] data)
+ {
+ if (data.length != 2)
+ {
+ throw new IllegalArgumentException("User Data should be length 2, username, password");
+ }
+
+ _name = data[0];
+
+ _password = data[1].toCharArray();
+
+ }
+
+ public PlainUser(String name, char[] password)
+ {
+ _name = name;
+ _password = password;
+ _modified = true;
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public String toString()
+ {
+ return _name;
+ }
+
+ char[] getPassword()
+ {
+ return _password;
+ }
+
+ byte[] getPasswordBytes()
+ {
+ byte[] byteArray = new byte[_password.length];
+ int index = 0;
+ for (char c : _password)
+ {
+ byteArray[index++] = (byte) c;
+ }
+ return byteArray;
+ }
+
+ void setPassword(char[] password)
+ {
+ _password = password;
+ _modified = true;
+ }
+
+ public boolean isModified()
+ {
+ return _modified;
+ }
+
+ public boolean isDeleted()
+ {
+ return _deleted;
+ }
+
+ public void delete()
+ {
+ _deleted = true;
+ }
+
+ public void saved()
+ {
+ _modified = false;
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java
index a82f9ed40b..ef37e043a6 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java
@@ -92,6 +92,11 @@ public interface PrincipalDatabase
*/
Principal getUser(String username);
+ /**
+ * Reload the database to its ensure contents are up to date
+ * @throws IOException If there was an error reloading the database
+ */
+ void reload() throws IOException;
public Map<String, AuthenticationProviderInitialiser> getMechanisms();
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java
index 2c553ae76a..f9882f8810 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java
@@ -20,6 +20,7 @@
*/
package org.apache.qpid.server.security.auth.database;
+import org.apache.qpid.server.configuration.ServerConfiguration;
import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
@@ -30,5 +31,5 @@ public interface PrincipalDatabaseManager
{
public Map<String, PrincipalDatabase> getDatabases();
- public void initialiseManagement(Configuration config) throws ConfigurationException;
+ public void initialiseManagement(ServerConfiguration _configuration) throws ConfigurationException;
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java
index c8a4add0f1..ff8851306f 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java
@@ -161,4 +161,9 @@ public class PropertiesPrincipalDatabase implements PrincipalDatabase
return null;
}
}
+
+ public void reload() throws IOException
+ {
+ //No file to update from, so do nothing.
+ }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java
index 6b86a46bd2..8658101cd8 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java
@@ -20,7 +20,8 @@
*/
package org.apache.qpid.server.security.auth.database;
-import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.server.configuration.ServerConfiguration;
import java.util.Map;
import java.util.Properties;
@@ -41,7 +42,7 @@ public class PropertiesPrincipalDatabaseManager implements PrincipalDatabaseMana
return _databases;
}
- public void initialiseManagement(Configuration config)
+ public void initialiseManagement(ServerConfiguration _configuration) throws ConfigurationException
{
//todo
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java
index bb94e0b7bf..d1803124a7 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java
@@ -34,4 +34,5 @@ public interface AuthenticationManager
AuthenticationResult authenticate(SaslServer server, byte[] response);
+ void close();
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java
index e5bf3edfca..98c060599a 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java
@@ -23,9 +23,8 @@ package org.apache.qpid.server.security.auth.manager;
import org.apache.log4j.Logger;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
-import org.apache.commons.configuration.SubsetConfiguration;
+import org.apache.qpid.server.configuration.VirtualHostConfiguration;
import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
import org.apache.qpid.server.security.auth.sasl.JCAProvider;
@@ -59,8 +58,10 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan
private Map<String, Map<String, ?>> _serverCreationProperties = new HashMap<String, Map<String, ?>>();
private AuthenticationManager _default = null;
+ /** The name for the required SASL Server mechanisms */
+ public static final String PROVIDER_NAME= "AMQSASLProvider-Server";
- public PrincipalDatabaseAuthenticationManager(String name, Configuration hostConfig) throws Exception
+ public PrincipalDatabaseAuthenticationManager(String name, VirtualHostConfiguration hostConfig) throws Exception
{
_logger.info("Initialising " + (name == null ? "Default" : "'" + name + "'")
+ " PrincipleDatabase authentication manager.");
@@ -77,7 +78,7 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan
}
else
{
- String databaseName = hostConfig.getString("security.authentication.name");
+ String databaseName = hostConfig.getAuthenticationDatabase();
if (databaseName == null)
{
@@ -101,10 +102,15 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan
if (providerMap.size() > 0)
{
// Ensure we are used before the defaults
- if (Security.insertProviderAt(new JCAProvider(providerMap), 1) == -1)
+ if (Security.insertProviderAt(new JCAProvider(PROVIDER_NAME, providerMap), 1) == -1)
{
- _logger.warn("Unable to set order of providers.");
+ _logger.error("Unable to load custom SASL providers. Qpid custom SASL authenticators unavailable.");
}
+ else
+ {
+ _logger.info("Additional SASL providers successfully registered.");
+ }
+
}
else
{
@@ -116,14 +122,6 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan
private void initialiseAuthenticationMechanisms(Map<String, Class<? extends SaslServerFactory>> providerMap, Map<String, PrincipalDatabase> databases) throws Exception
{
-// Configuration config = ApplicationRegistry.getInstance().getConfiguration();
-// List<String> mechanisms = config.getList("security.sasl.mechanisms.mechanism.initialiser.class");
-//
-// // Maps from the mechanism to the properties used to initialise the server. See the method
-// // Sasl.createSaslServer for details of the use of these properties. This map is populated during initialisation
-// // of each provider.
-
-
if (databases.size() > 1)
{
_logger.warn("More than one principle database provided currently authentication mechanism will override each other.");
@@ -131,13 +129,11 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan
for (Map.Entry<String, PrincipalDatabase> entry : databases.entrySet())
{
-
// fixme As the database now provide the mechanisms they support, they will ...
// overwrite each other in the map. There should only be one database per vhost.
// But currently we must have authentication before vhost definition.
initialiseAuthenticationMechanisms(providerMap, entry.getValue());
}
-
}
private void initialiseAuthenticationMechanisms(Map<String, Class<? extends SaslServerFactory>> providerMap, PrincipalDatabase database) throws Exception
@@ -233,4 +229,9 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan
return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR, e);
}
}
+
+ public void close()
+ {
+ Security.removeProvider(PROVIDER_NAME);
+ }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java
new file mode 100644
index 0000000000..77040e896c
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java
@@ -0,0 +1,119 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.auth.rmi;
+
+import java.util.Collections;
+
+import javax.management.remote.JMXAuthenticator;
+import javax.management.remote.JMXPrincipal;
+import javax.security.auth.Subject;
+import javax.security.auth.login.AccountNotFoundException;
+
+import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
+
+public class RMIPasswordAuthenticator implements JMXAuthenticator
+{
+ static final String UNABLE_TO_LOOKUP = "The broker was unable to lookup the user details";
+ static final String SHOULD_BE_STRING_ARRAY = "User details should be String[]";
+ static final String SHOULD_HAVE_2_ELEMENTS = "User details should have 2 elements, username, password";
+ static final String SHOULD_BE_NON_NULL = "Supplied username and password should be non-null";
+ static final String INVALID_CREDENTIALS = "Invalid user details supplied";
+ static final String CREDENTIALS_REQUIRED = "User details are required. " +
+ "Please ensure you are using an up to date management console to connect.";
+
+ private PrincipalDatabase _db = null;
+
+ public RMIPasswordAuthenticator()
+ {
+ }
+
+ public void setPrincipalDatabase(PrincipalDatabase pd)
+ {
+ this._db = pd;
+ }
+
+ public Subject authenticate(Object credentials) throws SecurityException
+ {
+ // Verify that credential's are of type String[].
+ if (!(credentials instanceof String[]))
+ {
+ if (credentials == null)
+ {
+ throw new SecurityException(CREDENTIALS_REQUIRED);
+ }
+ else
+ {
+ throw new SecurityException(SHOULD_BE_STRING_ARRAY);
+ }
+ }
+
+ // Verify that required number of credential's.
+ final String[] userCredentials = (String[]) credentials;
+ if (userCredentials.length != 2)
+ {
+ throw new SecurityException(SHOULD_HAVE_2_ELEMENTS);
+ }
+
+ String username = (String) userCredentials[0];
+ String password = (String) userCredentials[1];
+
+ // Verify that all required credential's are actually present.
+ if (username == null || password == null)
+ {
+ throw new SecurityException(SHOULD_BE_NON_NULL);
+ }
+
+ // Verify that a PD has been set.
+ if (_db == null)
+ {
+ throw new SecurityException(UNABLE_TO_LOOKUP);
+ }
+
+ boolean authenticated = false;
+
+ // Perform authentication
+ try
+ {
+ if (_db.verifyPassword(username, password.toCharArray()))
+ {
+ authenticated = true;
+ }
+ }
+ catch (AccountNotFoundException e)
+ {
+ throw new SecurityException(INVALID_CREDENTIALS);
+ }
+
+ if (authenticated)
+ {
+ //credential's check out, return the appropriate JAAS Subject
+ return new Subject(true,
+ Collections.singleton(new JMXPrincipal(username)),
+ Collections.EMPTY_SET,
+ Collections.EMPTY_SET);
+ }
+ else
+ {
+ throw new SecurityException(INVALID_CREDENTIALS);
+ }
+ }
+
+} \ No newline at end of file
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java
index fd4ad86055..d6a09d8217 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java
@@ -28,12 +28,11 @@ import javax.security.sasl.SaslServerFactory;
public final class JCAProvider extends Provider
{
- public JCAProvider(Map<String, Class<? extends SaslServerFactory>> providerMap)
+ public JCAProvider(String name, Map<String, Class<? extends SaslServerFactory>> providerMap)
{
- super("AMQSASLProvider", 1.0, "A JCA provider that registers all " +
+ super(name, 1.0, "A JCA provider that registers all " +
"AMQ SASL providers that want to be registered");
register(providerMap);
- //Security.addProvider(this);
}
private void register(Map<String, Class<? extends SaslServerFactory>> providerMap)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java
new file mode 100644
index 0000000000..38e84c799b
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java
@@ -0,0 +1,144 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.auth.sasl.crammd5;
+
+import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
+import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser;
+import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser;
+
+import javax.security.sasl.SaslServerFactory;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.login.AccountNotFoundException;
+import java.util.Map;
+import java.util.List;
+import java.security.Principal;
+import java.io.IOException;
+
+public class CRAMMD5HexInitialiser extends UsernamePasswordInitialiser
+{
+ public String getMechanismName()
+ {
+ return CRAMMD5HexSaslServer.MECHANISM;
+ }
+
+ public Class<? extends SaslServerFactory> getServerFactoryClassForJCARegistration()
+ {
+ return CRAMMD5HexServerFactory.class;
+ }
+
+ public Map<String, ?> getProperties()
+ {
+ return null;
+ }
+
+ public void initialise(PrincipalDatabase db)
+ {
+ super.initialise(new HexifyPrincipalDatabase(db));
+
+ }
+
+ private class HexifyPrincipalDatabase implements PrincipalDatabase
+ {
+ private PrincipalDatabase _realPricipalDatabase;
+
+ HexifyPrincipalDatabase(PrincipalDatabase db)
+ {
+ _realPricipalDatabase = db;
+ }
+
+ private char[] toHex(char[] password)
+ {
+ StringBuilder sb = new StringBuilder();
+ for (char c : password)
+ {
+ //toHexString does not prepend 0 so we have to
+ if (((byte) c > -1) && (byte) c < 10)
+ {
+ sb.append(0);
+ }
+
+ sb.append(Integer.toHexString(c & 0xFF));
+ }
+
+ //Extract the hex string as char[]
+ char[] hex = new char[sb.length()];
+
+ sb.getChars(0, sb.length(), hex, 0);
+
+ return hex;
+ }
+
+ public void setPassword(Principal principal, PasswordCallback callback) throws IOException, AccountNotFoundException
+ {
+ //Let the read DB set the password
+ _realPricipalDatabase.setPassword(principal, callback);
+
+ //Retrieve the setpassword
+ char[] plainPassword = callback.getPassword();
+
+ char[] hexPassword = toHex(plainPassword);
+
+ callback.setPassword(hexPassword);
+ }
+
+ // Simply delegate to the real PrincipalDB
+ public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException
+ {
+ return _realPricipalDatabase.verifyPassword(principal, password);
+ }
+
+ public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException
+ {
+ return _realPricipalDatabase.updatePassword(principal, password);
+ }
+
+ public boolean createPrincipal(Principal principal, char[] password)
+ {
+ return _realPricipalDatabase.createPrincipal(principal, password);
+ }
+
+ public boolean deletePrincipal(Principal principal) throws AccountNotFoundException
+ {
+ return _realPricipalDatabase.deletePrincipal(principal);
+ }
+
+ public Principal getUser(String username)
+ {
+ return _realPricipalDatabase.getUser(username);
+ }
+
+ public Map<String, AuthenticationProviderInitialiser> getMechanisms()
+ {
+ return _realPricipalDatabase.getMechanisms();
+ }
+
+ public List<Principal> getUsers()
+ {
+ return _realPricipalDatabase.getUsers();
+ }
+
+ public void reload() throws IOException
+ {
+ _realPricipalDatabase.reload();
+ }
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexSaslServer.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexSaslServer.java
new file mode 100644
index 0000000000..192ff74bff
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexSaslServer.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.security.auth.sasl.crammd5;
+
+import javax.security.sasl.SaslServer;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslServerFactory;
+import javax.security.auth.callback.CallbackHandler;
+import java.util.Enumeration;
+import java.util.Map;
+
+public class CRAMMD5HexSaslServer implements SaslServer
+{
+ public static final String MECHANISM = "CRAM-MD5-HEX";
+
+ private SaslServer _realServer;
+
+ public CRAMMD5HexSaslServer(String mechanism, String protocol, String serverName, Map<String, ?> props,
+ CallbackHandler cbh) throws SaslException
+ {
+ Enumeration factories = Sasl.getSaslServerFactories();
+
+ while (factories.hasMoreElements())
+ {
+ SaslServerFactory factory = (SaslServerFactory) factories.nextElement();
+
+ if (factory instanceof CRAMMD5HexServerFactory)
+ {
+ continue;
+ }
+
+ String[] mechs = factory.getMechanismNames(props);
+
+ for (String mech : mechs)
+ {
+ if (mech.equals("CRAM-MD5"))
+ {
+ _realServer = factory.createSaslServer("CRAM-MD5", protocol, serverName, props, cbh);
+ return;
+ }
+ }
+ }
+
+ throw new RuntimeException("No default SaslServer found for mechanism:" + "CRAM-MD5");
+ }
+
+ public String getMechanismName()
+ {
+ return MECHANISM;
+ }
+
+ public byte[] evaluateResponse(byte[] response) throws SaslException
+ {
+ return _realServer.evaluateResponse(response);
+ }
+
+ public boolean isComplete()
+ {
+ return _realServer.isComplete();
+ }
+
+ public String getAuthorizationID()
+ {
+ return _realServer.getAuthorizationID();
+ }
+
+ public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException
+ {
+ return _realServer.unwrap(incoming, offset, len);
+ }
+
+ public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException
+ {
+ return _realServer.wrap(outgoing, offset, len);
+ }
+
+ public Object getNegotiatedProperty(String propName)
+ {
+ return _realServer.getNegotiatedProperty(propName);
+ }
+
+ public void dispose() throws SaslException
+ {
+ _realServer.dispose();
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexServerFactory.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexServerFactory.java
new file mode 100644
index 0000000000..ce0e19abf9
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexServerFactory.java
@@ -0,0 +1,61 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.auth.sasl.crammd5;
+
+import java.util.Map;
+
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+import javax.security.sasl.SaslServerFactory;
+
+public class CRAMMD5HexServerFactory implements SaslServerFactory
+{
+ public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map<String, ?> props,
+ CallbackHandler cbh) throws SaslException
+ {
+ if (mechanism.equals(CRAMMD5HexSaslServer.MECHANISM))
+ {
+ return new CRAMMD5HexSaslServer(mechanism, protocol, serverName, props, cbh);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public String[] getMechanismNames(Map props)
+ {
+ if (props != null)
+ {
+ if (props.containsKey(Sasl.POLICY_NOPLAINTEXT) ||
+ props.containsKey(Sasl.POLICY_NODICTIONARY) ||
+ props.containsKey(Sasl.POLICY_NOACTIVE))
+ {
+ // returned array must be non null according to interface documentation
+ return new String[0];
+ }
+ }
+
+ return new String[]{CRAMMD5HexSaslServer.MECHANISM};
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java b/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java
new file mode 100644
index 0000000000..ef8f1ab70e
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.store;
+
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.configuration.VirtualHostConfiguration;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.messages.MessageStoreMessages;
+import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject;
+import org.apache.qpid.server.logging.LogSubject;
+
+public abstract class AbstractMessageStore implements MessageStore
+{
+ protected LogSubject _logSubject;
+
+ public void configure(VirtualHost virtualHost) throws Exception
+ {
+ _logSubject = new MessageStoreLogSubject(virtualHost, this);
+ CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_CREATED(this.getClass().getName()));
+ }
+
+ public void close() throws Exception
+ {
+ CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_CLOSED());
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java b/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java
new file mode 100755
index 0000000000..c7606832d0
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java
@@ -0,0 +1,57 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+package org.apache.qpid.server.store;
+
+import java.nio.ByteBuffer;
+import org.apache.qpid.framing.FieldTable;
+
+public interface ConfigurationRecoveryHandler
+{
+ QueueRecoveryHandler begin(MessageStore store);
+
+ public static interface QueueRecoveryHandler
+ {
+ void queue(String queueName, String owner, FieldTable arguments);
+ ExchangeRecoveryHandler completeQueueRecovery();
+ }
+
+ public static interface ExchangeRecoveryHandler
+ {
+ void exchange(String exchangeName, String type, boolean autoDelete);
+ BindingRecoveryHandler completeExchangeRecovery();
+ }
+
+ public static interface BindingRecoveryHandler
+ {
+ void binding(String exchangeName, String queueName, String bindingKey, ByteBuffer buf);
+ void completeBindingRecovery();
+ }
+
+ public static interface QueueEntryRecoveryHandler
+ {
+ void complete();
+
+ void queueEntry(String queueName, long messageId);
+ }
+
+
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java
index 743a736884..1764e2324e 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java
@@ -20,45 +20,37 @@
*/
package org.apache.qpid.server.store;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.AMQQueueFactory;
-import org.apache.qpid.server.queue.MessageMetaData;
-import org.apache.qpid.server.queue.QueueRegistry;
-
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.queue.MessageHandleFactory;
-import org.apache.qpid.server.txn.TransactionalContext;
-import org.apache.qpid.server.txn.NonTransactionalContext;
+import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.framing.ContentHeaderBody;
-import org.apache.qpid.framing.abstraction.ContentChunk;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.messages.MessageStoreMessages;
+import org.apache.qpid.server.logging.messages.ConfigStoreMessages;
+import org.apache.qpid.server.logging.messages.TransactionLogMessages;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.queue.AMQQueue;
import org.apache.commons.configuration.Configuration;
-import org.apache.log4j.Logger;
-import org.apache.mina.common.ByteBuffer;
-import java.io.File;
+
import java.io.ByteArrayInputStream;
-import java.sql.DriverManager;
-import java.sql.Driver;
+import java.io.File;
+import java.sql.Blob;
import java.sql.Connection;
-import java.sql.SQLException;
-import java.sql.Statement;
+import java.sql.Driver;
+import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
-import java.sql.Blob;
+import java.sql.SQLException;
+import java.sql.Statement;
import java.sql.Types;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.List;
import java.util.ArrayList;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.TreeMap;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.lang.ref.WeakReference;
+import java.nio.ByteBuffer;
public class DerbyMessageStore implements MessageStore
@@ -66,7 +58,7 @@ public class DerbyMessageStore implements MessageStore
private static final Logger _logger = Logger.getLogger(DerbyMessageStore.class);
- private static final String ENVIRONMENT_PATH_PROPERTY = "environment-path";
+ public static final String ENVIRONMENT_PATH_PROPERTY = "environment-path";
private static final String SQL_DRIVER_NAME = "org.apache.derby.jdbc.EmbeddedDriver";
@@ -77,53 +69,66 @@ public class DerbyMessageStore implements MessageStore
private static final String QUEUE_TABLE_NAME = "QPID_QUEUE";
private static final String BINDINGS_TABLE_NAME = "QPID_BINDINGS";
private static final String QUEUE_ENTRY_TABLE_NAME = "QPID_QUEUE_ENTRY";
- private static final String MESSAGE_META_DATA_TABLE_NAME = "QPID_MESSAGE_META_DATA";
+
+ private static final String META_DATA_TABLE_NAME = "QPID_META_DATA";
private static final String MESSAGE_CONTENT_TABLE_NAME = "QPID_MESSAGE_CONTENT";
private static final int DB_VERSION = 1;
- private VirtualHost _virtualHost;
private static Class<Driver> DRIVER_CLASS;
- private final AtomicLong _messageId = new AtomicLong(1);
+ private final AtomicLong _messageId = new AtomicLong(0);
private AtomicBoolean _closed = new AtomicBoolean(false);
private String _connectionURL;
-
+ private static final String TABLE_EXISTANCE_QUERY = "SELECT 1 FROM SYS.SYSTABLES WHERE TABLENAME = ?";
private static final String CREATE_DB_VERSION_TABLE = "CREATE TABLE "+DB_VERSION_TABLE_NAME+" ( version int not null )";
private static final String INSERT_INTO_DB_VERSION = "INSERT INTO "+DB_VERSION_TABLE_NAME+" ( version ) VALUES ( ? )";
+
private static final String CREATE_EXCHANGE_TABLE = "CREATE TABLE "+EXCHANGE_TABLE_NAME+" ( name varchar(255) not null, type varchar(255) not null, autodelete SMALLINT not null, PRIMARY KEY ( name ) )";
private static final String CREATE_QUEUE_TABLE = "CREATE TABLE "+QUEUE_TABLE_NAME+" ( name varchar(255) not null, owner varchar(255), PRIMARY KEY ( name ) )";
private static final String CREATE_BINDINGS_TABLE = "CREATE TABLE "+BINDINGS_TABLE_NAME+" ( exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255) not null, arguments blob , PRIMARY KEY ( exchange_name, queue_name, binding_key ) )";
- private static final String CREATE_QUEUE_ENTRY_TABLE = "CREATE TABLE "+QUEUE_ENTRY_TABLE_NAME+" ( queue_name varchar(255) not null, message_id bigint not null, PRIMARY KEY (queue_name, message_id) )";
- private static final String CREATE_MESSAGE_META_DATA_TABLE = "CREATE TABLE "+MESSAGE_META_DATA_TABLE_NAME+" ( message_id bigint not null, exchange_name varchar(255) not null, routing_key varchar(255), flag_mandatory smallint not null, flag_immediate smallint not null, content_header blob, chunk_count int not null, PRIMARY KEY ( message_id ) )";
- private static final String CREATE_MESSAGE_CONTENT_TABLE = "CREATE TABLE "+MESSAGE_CONTENT_TABLE_NAME+" ( message_id bigint not null, chunk_id int not null, content_chunk blob , PRIMARY KEY (message_id, chunk_id) )";
private static final String SELECT_FROM_QUEUE = "SELECT name, owner FROM " + QUEUE_TABLE_NAME;
+ private static final String FIND_QUEUE = "SELECT name, owner FROM " + QUEUE_TABLE_NAME + " WHERE name = ?";
private static final String SELECT_FROM_EXCHANGE = "SELECT name, type, autodelete FROM " + EXCHANGE_TABLE_NAME;
private static final String SELECT_FROM_BINDINGS =
- "SELECT queue_name, binding_key, arguments FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ?";
- private static final String DELETE_FROM_MESSAGE_META_DATA = "DELETE FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?";
- private static final String DELETE_FROM_MESSAGE_CONTENT = "DELETE FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ?";
+ "SELECT exchange_name, queue_name, binding_key, arguments FROM " + BINDINGS_TABLE_NAME + " ORDER BY exchange_name";
+ private static final String FIND_BINDING =
+ "SELECT * FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ? AND queue_name = ? AND binding_key = ? ";
private static final String INSERT_INTO_EXCHANGE = "INSERT INTO " + EXCHANGE_TABLE_NAME + " ( name, type, autodelete ) VALUES ( ?, ?, ? )";
private static final String DELETE_FROM_EXCHANGE = "DELETE FROM " + EXCHANGE_TABLE_NAME + " WHERE name = ?";
private static final String INSERT_INTO_BINDINGS = "INSERT INTO " + BINDINGS_TABLE_NAME + " ( exchange_name, queue_name, binding_key, arguments ) values ( ?, ?, ?, ? )";
private static final String DELETE_FROM_BINDINGS = "DELETE FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ? AND queue_name = ? AND binding_key = ?";
private static final String INSERT_INTO_QUEUE = "INSERT INTO " + QUEUE_TABLE_NAME + " (name, owner) VALUES (?, ?)";
private static final String DELETE_FROM_QUEUE = "DELETE FROM " + QUEUE_TABLE_NAME + " WHERE name = ?";
+
+ private static final String CREATE_QUEUE_ENTRY_TABLE = "CREATE TABLE "+QUEUE_ENTRY_TABLE_NAME+" ( queue_name varchar(255) not null, message_id bigint not null, PRIMARY KEY (queue_name, message_id) )";
private static final String INSERT_INTO_QUEUE_ENTRY = "INSERT INTO " + QUEUE_ENTRY_TABLE_NAME + " (queue_name, message_id) values (?,?)";
private static final String DELETE_FROM_QUEUE_ENTRY = "DELETE FROM " + QUEUE_ENTRY_TABLE_NAME + " WHERE queue_name = ? AND message_id =?";
- private static final String INSERT_INTO_MESSAGE_CONTENT = "INSERT INTO " + MESSAGE_CONTENT_TABLE_NAME + "( message_id, chunk_id, content_chunk ) values (?, ?, ?)";
- private static final String INSERT_INTO_MESSAGE_META_DATA = "INSERT INTO " + MESSAGE_META_DATA_TABLE_NAME + "( message_id , exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count ) values (?, ?, ?, ?, ?, ?, ?)";
- private static final String SELECT_FROM_MESSAGE_META_DATA =
- "SELECT exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?";
+ private static final String SELECT_FROM_QUEUE_ENTRY = "SELECT queue_name, message_id FROM " + QUEUE_ENTRY_TABLE_NAME + " ORDER BY queue_name, message_id";
+
+
+ private static final String CREATE_META_DATA_TABLE = "CREATE TABLE "+META_DATA_TABLE_NAME+" ( message_id bigint not null, meta_data blob, PRIMARY KEY ( message_id ) )";
+ private static final String CREATE_MESSAGE_CONTENT_TABLE = "CREATE TABLE "+MESSAGE_CONTENT_TABLE_NAME+" ( message_id bigint not null, offset int not null, last_byte int not null, content blob , PRIMARY KEY (message_id, offset) )";
+
+ private static final String INSERT_INTO_MESSAGE_CONTENT = "INSERT INTO " + MESSAGE_CONTENT_TABLE_NAME + "( message_id, offset, last_byte, content ) values (?, ?, ?, ?)";
private static final String SELECT_FROM_MESSAGE_CONTENT =
- "SELECT content_chunk FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ? and chunk_id = ?";
- private static final String SELECT_FROM_QUEUE_ENTRY = "SELECT queue_name, message_id FROM " + QUEUE_ENTRY_TABLE_NAME;
- private static final String TABLE_EXISTANCE_QUERY = "SELECT 1 FROM SYS.SYSTABLES WHERE TABLENAME = ?";
+ "SELECT offset, content FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ? AND last_byte > ? AND offset < ? ORDER BY message_id, offset";
+ private static final String DELETE_FROM_MESSAGE_CONTENT = "DELETE FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ?";
+
+ private static final String INSERT_INTO_META_DATA = "INSERT INTO " + META_DATA_TABLE_NAME + "( message_id , meta_data ) values (?, ?)";;
+ private static final String SELECT_FROM_META_DATA =
+ "SELECT meta_data FROM " + META_DATA_TABLE_NAME + " WHERE message_id = ?";
+ private static final String DELETE_FROM_META_DATA = "DELETE FROM " + META_DATA_TABLE_NAME + " WHERE message_id = ?";
+ private static final String SELECT_ALL_FROM_META_DATA = "SELECT message_id, meta_data FROM " + META_DATA_TABLE_NAME;
+
+
+ private LogSubject _logSubject;
+ private boolean _configured;
private enum State
@@ -139,18 +144,82 @@ public class DerbyMessageStore implements MessageStore
private State _state = State.INITIAL;
- public void configure(VirtualHost virtualHost, String base, Configuration config) throws Exception
+ public void configureConfigStore(String name,
+ ConfigurationRecoveryHandler recoveryHandler,
+ Configuration storeConfiguration,
+ LogSubject logSubject) throws Exception
{
stateTransition(State.INITIAL, State.CONFIGURING);
+ _logSubject = logSubject;
+ CurrentActor.get().message(_logSubject, ConfigStoreMessages.CFG_1001(this.getClass().getName()));
- initialiseDriver();
+ if(!_configured)
+ {
+ commonConfiguration(name, storeConfiguration, logSubject);
+ _configured = true;
+ }
- _virtualHost = virtualHost;
+ // this recovers durable exchanges, queues, and bindings
+ recover(recoveryHandler);
- _logger.info("Configuring Derby message store for virtual host " + virtualHost.getName());
- QueueRegistry queueRegistry = virtualHost.getQueueRegistry();
- final String databasePath = config.getString(base + "." + ENVIRONMENT_PATH_PROPERTY, "derbyDB");
+ stateTransition(State.RECOVERING, State.STARTED);
+
+ }
+
+
+ public void configureMessageStore(String name,
+ MessageStoreRecoveryHandler recoveryHandler,
+ Configuration storeConfiguration,
+ LogSubject logSubject) throws Exception
+ {
+ CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_CREATED(this.getClass().getName()));
+
+ if(!_configured)
+ {
+
+ _logSubject = logSubject;
+
+ commonConfiguration(name, storeConfiguration, logSubject);
+ _configured = true;
+ }
+
+ recoverMessages(recoveryHandler);
+
+ }
+
+
+
+ public void configureTransactionLog(String name,
+ TransactionLogRecoveryHandler recoveryHandler,
+ Configuration storeConfiguration,
+ LogSubject logSubject) throws Exception
+ {
+ CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1001(this.getClass().getName()));
+
+ if(!_configured)
+ {
+
+ _logSubject = logSubject;
+
+ commonConfiguration(name, storeConfiguration, logSubject);
+ _configured = true;
+ }
+
+ recoverQueueEntries(recoveryHandler);
+
+ }
+
+
+
+ private void commonConfiguration(String name, Configuration storeConfiguration, LogSubject logSubject)
+ throws ClassNotFoundException, SQLException
+ {
+ initialiseDriver();
+
+ //Update to pick up QPID_WORK and use that as the default location not just derbyDB
+
+ final String databasePath = storeConfiguration.getString(ENVIRONMENT_PATH_PROPERTY, System.getProperty("QPID_WORK")+"/derbyDB");
File environmentPath = new File(databasePath);
if (!environmentPath.exists())
@@ -162,14 +231,9 @@ public class DerbyMessageStore implements MessageStore
}
}
- createOrOpenDatabase(databasePath);
-
- // this recovers durable queues and persistent messages
-
- recover();
-
- stateTransition(State.RECOVERING, State.STARTED);
+ CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_STORE_LOCATION(environmentPath.getAbsolutePath()));
+ createOrOpenDatabase(name, databasePath);
}
private static synchronized void initialiseDriver() throws ClassNotFoundException
@@ -180,9 +244,10 @@ public class DerbyMessageStore implements MessageStore
}
}
- private void createOrOpenDatabase(final String environmentPath) throws SQLException
+ private void createOrOpenDatabase(String name, final String environmentPath) throws SQLException
{
- _connectionURL = "jdbc:derby:" + environmentPath + "/" + _virtualHost.getName() + ";create=true";
+ //fixme this the _vhost name should not be added here.
+ _connectionURL = "jdbc:derby:" + environmentPath + "/" + name + ";create=true";
Connection conn = newConnection();
@@ -191,7 +256,7 @@ public class DerbyMessageStore implements MessageStore
createQueueTable(conn);
createBindingsTable(conn);
createQueueEntryTable(conn);
- createMessageMetaDataTable(conn);
+ createMetaDataTable(conn);
createMessageContentTable(conn);
conn.close();
@@ -262,12 +327,12 @@ public class DerbyMessageStore implements MessageStore
}
- private void createMessageMetaDataTable(final Connection conn) throws SQLException
+ private void createMetaDataTable(final Connection conn) throws SQLException
{
- if(!tableExists(MESSAGE_META_DATA_TABLE_NAME, conn))
+ if(!tableExists(META_DATA_TABLE_NAME, conn))
{
Statement stmt = conn.createStatement();
- stmt.execute(CREATE_MESSAGE_META_DATA_TABLE);
+ stmt.execute(CREATE_META_DATA_TABLE);
stmt.close();
}
@@ -300,36 +365,22 @@ public class DerbyMessageStore implements MessageStore
return exists;
}
- public void recover() throws AMQException
+ public void recover(ConfigurationRecoveryHandler recoveryHandler) throws AMQException
{
stateTransition(State.CONFIGURING, State.RECOVERING);
- _logger.info("Recovering persistent state...");
- StoreContext context = new StoreContext();
+ CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_RECOVERY_START());
try
{
- Map<AMQShortString, AMQQueue> queues = loadQueues();
-
- recoverExchanges();
-
- try
- {
-
- beginTran(context);
-
- deliverMessages(context, queues);
- _logger.info("Persistent state recovered successfully");
- commitTran(context);
+ ConfigurationRecoveryHandler.QueueRecoveryHandler qrh = recoveryHandler.begin(this);
+ List<String> queues = loadQueues(qrh);
- }
- finally
- {
- if(inTran(context))
- {
- abortTran(context);
- }
- }
+ ConfigurationRecoveryHandler.ExchangeRecoveryHandler erh = qrh.completeQueueRecovery();
+ List<String> exchanges = loadExchanges(erh);
+ ConfigurationRecoveryHandler.BindingRecoveryHandler brh = erh.completeExchangeRecovery();
+ recoverBindings(brh, exchanges);
+ brh.completeBindingRecovery();
}
catch (SQLException e)
{
@@ -337,43 +388,34 @@ public class DerbyMessageStore implements MessageStore
throw new AMQException("Error recovering persistent state: " + e, e);
}
+
}
- private Map<AMQShortString, AMQQueue> loadQueues() throws SQLException, AMQException
+ private List<String> loadQueues(ConfigurationRecoveryHandler.QueueRecoveryHandler qrh) throws SQLException, AMQException
{
Connection conn = newConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE);
- Map<AMQShortString, AMQQueue> queueMap = new HashMap<AMQShortString, AMQQueue>();
+ List<String> queues = new ArrayList<String>();
+
while(rs.next())
{
String queueName = rs.getString(1);
String owner = rs.getString(2);
- AMQShortString queueNameShortString = new AMQShortString(queueName);
- AMQQueue q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, _virtualHost,
- null);
- _virtualHost.getQueueRegistry().registerQueue(q);
- queueMap.put(queueNameShortString,q);
-
- }
- return queueMap;
- }
+ qrh.queue(queueName, owner, null);
- private void recoverExchanges() throws AMQException, SQLException
- {
- for (Exchange exchange : loadExchanges())
- {
- recoverExchange(exchange);
+ queues.add(queueName);
}
+ return queues;
}
- private List<Exchange> loadExchanges() throws AMQException, SQLException
+ private List<String> loadExchanges(ConfigurationRecoveryHandler.ExchangeRecoveryHandler erh) throws AMQException, SQLException
{
- List<Exchange> exchanges = new ArrayList<Exchange>();
+ List<String> exchanges = new ArrayList<String>();
Connection conn = null;
try
{
@@ -383,16 +425,15 @@ public class DerbyMessageStore implements MessageStore
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(SELECT_FROM_EXCHANGE);
- Exchange exchange;
while(rs.next())
{
String exchangeName = rs.getString(1);
String type = rs.getString(2);
boolean autoDelete = rs.getShort(3) != 0;
- exchange = _virtualHost.getExchangeFactory().createExchange(new AMQShortString(exchangeName), new AMQShortString(type), true, autoDelete, 0);
- _virtualHost.getExchangeRegistry().registerExchange(exchange);
- exchanges.add(exchange);
+ exchanges.add(exchangeName);
+
+ erh.exchange(exchangeName, type, autoDelete);
}
return exchanges;
@@ -408,11 +449,13 @@ public class DerbyMessageStore implements MessageStore
}
- private void recoverExchange(Exchange exchange) throws AMQException, SQLException
+ private void recoverBindings(ConfigurationRecoveryHandler.BindingRecoveryHandler brh, List<String> exchanges) throws AMQException, SQLException
{
- _logger.info("Recovering durable exchange " + exchange.getName() + " of type " + exchange.getType() + "...");
- QueueRegistry queueRegistry = _virtualHost.getQueueRegistry();
+
+ _logger.info("Recovering bindings...");
+
+
Connection conn = null;
try
@@ -420,41 +463,29 @@ public class DerbyMessageStore implements MessageStore
conn = newConnection();
PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_BINDINGS);
- stmt.setString(1, exchange.getName().toString());
ResultSet rs = stmt.executeQuery();
while(rs.next())
{
- String queueName = rs.getString(1);
- String bindingKey = rs.getString(2);
- Blob arguments = rs.getBlob(3);
-
+ String exchangeName = rs.getString(1);
+ String queueName = rs.getString(2);
+ String bindingKey = rs.getString(3);
+ Blob arguments = rs.getBlob(4);
+ java.nio.ByteBuffer buf;
- AMQQueue queue = queueRegistry.getQueue(new AMQShortString(queueName));
- if (queue == null)
+ if(arguments != null && arguments.length() != 0)
{
- _logger.error("Unkown queue: " + queueName + " cannot be bound to exchange: "
- + exchange.getName());
+ byte[] argumentBytes = arguments.getBytes(1, (int) arguments.length());
+ buf = java.nio.ByteBuffer.wrap(argumentBytes);
}
else
{
- _logger.info("Restoring binding: (Exchange: " + exchange.getName() + ", Queue: " + queueName
- + ", Routing Key: " + bindingKey + ", Arguments: " + arguments
- + ")");
-
- FieldTable argumentsFT = null;
- if(arguments != null)
- {
- byte[] argumentBytes = arguments.getBytes(0, (int) arguments.length());
- ByteBuffer buf = ByteBuffer.wrap(argumentBytes);
- argumentsFT = new FieldTable(buf,arguments.length());
- }
-
- queue.bind(exchange, bindingKey == null ? null : new AMQShortString(bindingKey), argumentsFT);
-
+ buf = null;
}
+
+ brh.binding(exchangeName, queueName, bindingKey, buf);
}
}
finally
@@ -466,42 +497,48 @@ public class DerbyMessageStore implements MessageStore
}
}
+
+
public void close() throws Exception
{
+ CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_CLOSED());
_closed.getAndSet(true);
}
- public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException
+ public StoredMessage addMessage(StorableMessageMetaData metaData)
{
-
- boolean localTx = getOrCreateTransaction(storeContext);
-
- Connection conn = getConnection(storeContext);
- ConnectionWrapper wrapper = (ConnectionWrapper) storeContext.getPayload();
-
-
- if (_logger.isDebugEnabled())
+ if(metaData.isPersistent())
{
- _logger.debug("Message Id: " + messageId + " Removing");
+ return new StoredDerbyMessage(_messageId.incrementAndGet(), metaData);
}
+ else
+ {
+ return new StoredMemoryMessage(_messageId.incrementAndGet(), metaData);
+ }
+ }
+
+ public StoredMessage getMessage(long messageNumber)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
- // first we need to look up the header to get the chunk count
- MessageMetaData mmd = getMessageMetaData(storeContext, messageId);
+ public void removeMessage(long messageId)
+ {
+ Connection conn = null;
try
{
- PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_MESSAGE_META_DATA);
+
+
+ conn = newConnection();
+ PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_META_DATA);
stmt.setLong(1,messageId);
- wrapper.setRequiresCommit();
int results = stmt.executeUpdate();
if (results == 0)
{
- if (localTx)
- {
- abortTran(storeContext);
- }
- throw new AMQException("Message metadata not found for message id " + messageId);
+
+ throw new RuntimeException("Message metadata not found for message id " + messageId);
}
stmt.close();
@@ -514,29 +551,27 @@ public class DerbyMessageStore implements MessageStore
stmt.setLong(1,messageId);
results = stmt.executeUpdate();
- if(results != mmd.getContentChunkCount())
- {
- if (localTx)
- {
- abortTran(storeContext);
- }
- throw new AMQException("Unexpected number of content chunks when deleting message. Expected " + mmd.getContentChunkCount() + " but found " + results);
- }
- if (localTx)
- {
- commitTran(storeContext);
- }
+ conn.commit();
+ conn.close();
}
catch (SQLException e)
{
- if ((conn != null) && localTx)
+ if ((conn != null))
{
- abortTran(storeContext);
+ try
+ {
+ conn.rollback();
+ conn.close();
+ }
+ catch (SQLException e1)
+ {
+
+ }
}
- throw new AMQException("Error writing AMQMessage with id " + messageId + " to database: " + e, e);
+ throw new RuntimeException("Error removing Message with id " + messageId + " to database: " + e, e);
}
}
@@ -630,29 +665,41 @@ public class DerbyMessageStore implements MessageStore
try
{
conn = newConnection();
- PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_BINDINGS);
+
+ PreparedStatement stmt = conn.prepareStatement(FIND_BINDING);
stmt.setString(1, exchange.getName().toString() );
stmt.setString(2, queue.getName().toString());
stmt.setString(3, routingKey == null ? null : routingKey.toString());
- if(args != null)
- {
- /* This would be the Java 6 way of setting a Blob
- Blob blobArgs = conn.createBlob();
- blobArgs.setBytes(0, args.getDataAsBytes());
- stmt.setBlob(4, blobArgs);
- */
- byte[] bytes = args.getDataAsBytes();
- ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
- stmt.setBinaryStream(4, bis, bytes.length);
- }
- else
+
+ ResultSet rs = stmt.executeQuery();
+
+ // If this binding is not already in the store then create it.
+ if (!rs.next())
{
- stmt.setNull(4, Types.BLOB);
- }
+ stmt = conn.prepareStatement(INSERT_INTO_BINDINGS);
+ stmt.setString(1, exchange.getName().toString() );
+ stmt.setString(2, queue.getName().toString());
+ stmt.setString(3, routingKey == null ? null : routingKey.toString());
+ if(args != null)
+ {
+ /* This would be the Java 6 way of setting a Blob
+ Blob blobArgs = conn.createBlob();
+ blobArgs.setBytes(0, args.getDataAsBytes());
+ stmt.setBlob(4, blobArgs);
+ */
+ byte[] bytes = args.getDataAsBytes();
+ ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
+ stmt.setBinaryStream(4, bis, bytes.length);
+ }
+ else
+ {
+ stmt.setNull(4, Types.BLOB);
+ }
- stmt.executeUpdate();
- conn.commit();
- stmt.close();
+ stmt.executeUpdate();
+ conn.commit();
+ stmt.close();
+ }
}
catch (SQLException e)
{
@@ -743,19 +790,33 @@ public class DerbyMessageStore implements MessageStore
{
Connection conn = newConnection();
- PreparedStatement stmt =
- conn.prepareStatement(INSERT_INTO_QUEUE);
-
+ PreparedStatement stmt = conn.prepareStatement(FIND_QUEUE);
stmt.setString(1, queue.getName().toString());
- stmt.setString(2, queue.getOwner() == null ? null : queue.getOwner().toString());
- stmt.execute();
+ ResultSet rs = stmt.executeQuery();
- stmt.close();
+ // If we don't have any data in the result set then we can add this queue
+ if (!rs.next())
+ {
+ stmt = conn.prepareStatement(INSERT_INTO_QUEUE);
- conn.commit();
+ String owner = queue.getPrincipalHolder() == null
+ ? null
+ : queue.getPrincipalHolder().getPrincipal() == null
+ ? null
+ : queue.getPrincipalHolder().getPrincipal().getName();
- conn.close();
+ stmt.setString(1, queue.getName().toString());
+ stmt.setString(2, owner);
+
+ stmt.execute();
+
+ stmt.close();
+
+ conn.commit();
+
+ conn.close();
+ }
}
catch (SQLException e)
{
@@ -816,29 +877,26 @@ public class DerbyMessageStore implements MessageStore
}
- public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException
+ public Transaction newTransaction()
{
- AMQShortString name = queue.getName();
+ return new DerbyTransaction();
+ }
+
+ public void enqueueMessage(ConnectionWrapper connWrapper, final TransactionLogResource queue, Long messageId) throws AMQException
+ {
+ String name = queue.getResourceName();
+
+ Connection conn = connWrapper.getConnection();
- boolean localTx = getOrCreateTransaction(context);
- Connection conn = getConnection(context);
- ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload();
try
{
PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_QUEUE_ENTRY);
- stmt.setString(1,name.toString());
+ stmt.setString(1,name);
stmt.setLong(2,messageId);
stmt.executeUpdate();
connWrapper.requiresCommit();
- if(localTx)
- {
- commitTran(context);
- }
-
-
-
if (_logger.isDebugEnabled())
{
_logger.debug("Enqueuing message " + messageId + " on queue " + name + "[Connection" + conn + "]");
@@ -846,10 +904,6 @@ public class DerbyMessageStore implements MessageStore
}
catch (SQLException e)
{
- if(localTx)
- {
- abortTran(context);
- }
_logger.error("Failed to enqueue: " + e, e);
throw new AMQException("Error writing enqueued message with id " + messageId + " for queue " + name
+ " to database", e);
@@ -857,18 +911,18 @@ public class DerbyMessageStore implements MessageStore
}
- public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException
+ public void dequeueMessage(ConnectionWrapper connWrapper, final TransactionLogResource queue, Long messageId) throws AMQException
{
- AMQShortString name = queue.getName();
+ String name = queue.getResourceName();
+
+
+ Connection conn = connWrapper.getConnection();
- boolean localTx = getOrCreateTransaction(context);
- Connection conn = getConnection(context);
- ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload();
try
{
PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_QUEUE_ENTRY);
- stmt.setString(1,name.toString());
+ stmt.setString(1,name);
stmt.setLong(2,messageId);
int results = stmt.executeUpdate();
@@ -879,24 +933,13 @@ public class DerbyMessageStore implements MessageStore
throw new AMQException("Unable to find message with id " + messageId + " on queue " + name);
}
- if(localTx)
- {
- commitTran(context);
- }
-
-
-
if (_logger.isDebugEnabled())
{
- _logger.debug("Dequeuing message " + messageId + " on queue " + name + "[Connection" + conn + "]");
+ _logger.debug("Dequeuing message " + messageId + " on queue " + name );//+ "[Connection" + conn + "]");
}
}
catch (SQLException e)
{
- if(localTx)
- {
- abortTran(context);
- }
_logger.error("Failed to dequeue: " + e, e);
throw new AMQException("Error deleting enqueued message with id " + messageId + " for queue " + name
+ " from database", e);
@@ -930,51 +973,20 @@ public class DerbyMessageStore implements MessageStore
}
}
- public void beginTran(StoreContext context) throws AMQException
- {
- if (context.getPayload() != null)
- {
- throw new AMQException("Fatal internal error: transactional context is not empty at beginTran: "
- + context.getPayload());
- }
- else
- {
- try
- {
- Connection conn = newConnection();
-
- context.setPayload(new ConnectionWrapper(conn));
- }
- catch (SQLException e)
- {
- throw new AMQException("Error starting transaction: " + e, e);
- }
- }
- }
-
- public void commitTran(StoreContext context) throws AMQException
+ public void commitTran(ConnectionWrapper connWrapper) throws AMQException
{
- ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload();
-
- if (connWrapper == null)
- {
- throw new AMQException("Fatal internal error: transactional context is empty at commitTran");
- }
try
{
Connection conn = connWrapper.getConnection();
- if(connWrapper.requiresCommit())
- {
- conn.commit();
-
- if (_logger.isDebugEnabled())
- {
- _logger.debug("commit tran completed");
- }
+ conn.commit();
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("commit tran completed");
}
+
conn.close();
}
catch (SQLException e)
@@ -983,14 +995,30 @@ public class DerbyMessageStore implements MessageStore
}
finally
{
- context.setPayload(null);
+
}
}
- public void abortTran(StoreContext context) throws AMQException
+ public StoreFuture commitTranAsync(ConnectionWrapper connWrapper) throws AMQException
{
- ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload();
+ commitTran(connWrapper);
+ return new StoreFuture()
+ {
+ public boolean isComplete()
+ {
+ return true;
+ }
+ public void waitForCompletion()
+ {
+
+ }
+ };
+
+ }
+
+ public void abortTran(ConnectionWrapper connWrapper) throws AMQException
+ {
if (connWrapper == null)
{
throw new AMQException("Fatal internal error: transactional context is empty at abortTran");
@@ -1015,272 +1043,261 @@ public class DerbyMessageStore implements MessageStore
{
throw new AMQException("Error aborting transaction: " + e, e);
}
- finally
- {
- context.setPayload(null);
- }
+
}
- public boolean inTran(StoreContext context)
+ public Long getNewMessageId()
{
- return context.getPayload() != null;
+ return _messageId.incrementAndGet();
}
- public Long getNewMessageId()
+
+ private void storeMetaData(Connection conn, long messageId, StorableMessageMetaData metaData)
+ throws SQLException
{
- return _messageId.getAndIncrement();
+ PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_META_DATA);
+ stmt.setLong(1,messageId);
+
+ final int bodySize = 1 + metaData.getStorableSize();
+ byte[] underlying = new byte[bodySize];
+ underlying[0] = (byte) metaData.getType().ordinal();
+ java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(underlying);
+ buf.position(1);
+ buf = buf.slice();
+
+ metaData.writeToBuffer(0, buf);
+ ByteArrayInputStream bis = new ByteArrayInputStream(underlying);
+ stmt.setBinaryStream(2,bis,underlying.length);
+ stmt.executeUpdate();
+
}
- public void storeContentBodyChunk(StoreContext context,
- Long messageId,
- int index,
- ContentChunk contentBody,
- boolean lastContentBody) throws AMQException
+
+
+
+ private void recoverMessages(MessageStoreRecoveryHandler recoveryHandler) throws SQLException
{
- boolean localTx = getOrCreateTransaction(context);
- Connection conn = getConnection(context);
- ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload();
+ Connection conn = newConnection();
- try
- {
- PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_CONTENT);
- stmt.setLong(1,messageId);
- stmt.setInt(2, index);
- byte[] chunkData = new byte[contentBody.getSize()];
- contentBody.getData().duplicate().get(chunkData);
- /* this would be the Java 6 way of doing things
- Blob dataAsBlob = conn.createBlob();
- dataAsBlob.setBytes(1L, chunkData);
- stmt.setBlob(3, dataAsBlob);
- */
- ByteArrayInputStream bis = new ByteArrayInputStream(chunkData);
- stmt.setBinaryStream(3, bis, chunkData.length);
- stmt.executeUpdate();
- connWrapper.requiresCommit();
+ MessageStoreRecoveryHandler.StoredMessageRecoveryHandler messageHandler = recoveryHandler.begin();
- if(localTx)
- {
- commitTran(context);
- }
- }
- catch (SQLException e)
+ Statement stmt = conn.createStatement();
+ ResultSet rs = stmt.executeQuery(SELECT_ALL_FROM_META_DATA);
+
+ long maxId = 0;
+
+ while(rs.next())
{
- if(localTx)
+
+ long messageId = rs.getLong(1);
+ Blob dataAsBlob = rs.getBlob(2);
+
+ if(messageId > maxId)
{
- abortTran(context);
+ maxId = messageId;
}
- throw new AMQException("Error writing AMQMessage with id " + messageId + " to database: " + e, e);
+ byte[] dataAsBytes = dataAsBlob.getBytes(1,(int) dataAsBlob.length());
+ java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(dataAsBytes);
+ buf.position(1);
+ buf = buf.slice();
+ MessageMetaDataType type = MessageMetaDataType.values()[dataAsBytes[0]];
+ StorableMessageMetaData metaData = type.getFactory().createMetaData(buf);
+ StoredDerbyMessage message = new StoredDerbyMessage(messageId, metaData, false);
+ messageHandler.message(message);
+
+
}
+ _messageId.set(maxId);
+
+ messageHandler.completeMessageRecovery();
}
- public void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData mmd)
- throws AMQException
- {
- boolean localTx = getOrCreateTransaction(context);
- Connection conn = getConnection(context);
- ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload();
- try
- {
+ private void recoverQueueEntries(TransactionLogRecoveryHandler recoveryHandler) throws SQLException
+ {
+ Connection conn = newConnection();
- PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_META_DATA);
- stmt.setLong(1,messageId);
- stmt.setString(2, mmd.getMessagePublishInfo().getExchange().toString());
- stmt.setString(3, mmd.getMessagePublishInfo().getRoutingKey().toString());
- stmt.setShort(4, mmd.getMessagePublishInfo().isMandatory() ? (short) 1 : (short) 0);
- stmt.setShort(5, mmd.getMessagePublishInfo().isImmediate() ? (short) 1 : (short) 0);
-
- ContentHeaderBody headerBody = mmd.getContentHeaderBody();
- final int bodySize = headerBody.getSize();
- byte[] underlying = new byte[bodySize];
- ByteBuffer buf = ByteBuffer.wrap(underlying);
- headerBody.writePayload(buf);
-/*
- Blob dataAsBlob = conn.createBlob();
- dataAsBlob.setBytes(1L, underlying);
- stmt.setBlob(6, dataAsBlob);
-*/
- ByteArrayInputStream bis = new ByteArrayInputStream(underlying);
- stmt.setBinaryStream(6,bis,underlying.length);
+ TransactionLogRecoveryHandler.QueueEntryRecoveryHandler queueEntryHandler = recoveryHandler.begin(this);
- stmt.setInt(7, mmd.getContentChunkCount());
+ Statement stmt = conn.createStatement();
+ ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE_ENTRY);
- stmt.executeUpdate();
- connWrapper.requiresCommit();
- if(localTx)
- {
- commitTran(context);
- }
- }
- catch (SQLException e)
+ while(rs.next())
{
- if(localTx)
- {
- abortTran(context);
- }
- throw new AMQException("Error writing AMQMessage with id " + messageId + " to database: " + e, e);
+ String queueName = rs.getString(1);
+ long messageId = rs.getLong(2);
+ queueEntryHandler.queueEntry(queueName,messageId);
}
+
+ queueEntryHandler.completeQueueEntryRecovery();
+
}
- public MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException
+ StorableMessageMetaData getMetaData(long messageId) throws SQLException
{
- boolean localTx = getOrCreateTransaction(context);
- Connection conn = getConnection(context);
-
+ Connection conn = newConnection();
try
{
-
- PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_META_DATA);
+ PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_META_DATA);
stmt.setLong(1,messageId);
ResultSet rs = stmt.executeQuery();
if(rs.next())
{
- final AMQShortString exchange = new AMQShortString(rs.getString(1));
- final AMQShortString routingKey = rs.getString(2) == null ? null : new AMQShortString(rs.getString(2));
- final boolean mandatory = (rs.getShort(3) != (short)0);
- final boolean immediate = (rs.getShort(4) != (short)0);
- MessagePublishInfo info = new MessagePublishInfo()
- {
- public AMQShortString getExchange()
- {
- return exchange;
- }
+ Blob dataAsBlob = rs.getBlob(1);
- public void setExchange(AMQShortString exchange)
- {
+ byte[] dataAsBytes = dataAsBlob.getBytes(1,(int) dataAsBlob.length());
+ java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(dataAsBytes);
+ buf.position(1);
+ buf = buf.slice();
+ MessageMetaDataType type = MessageMetaDataType.values()[dataAsBytes[0]];
+ StorableMessageMetaData metaData = type.getFactory().createMetaData(buf);
- }
+ return metaData;
+ }
+ else
+ {
+ throw new RuntimeException("Meta data not found for message with id " + messageId);
+ }
- public boolean isImmediate()
- {
- return immediate;
- }
+ }
+ finally
+ {
+ conn.close();
+ }
+ }
- public boolean isMandatory()
- {
- return mandatory;
- }
- public AMQShortString getRoutingKey()
- {
- return routingKey;
- }
- } ;
+ private void addContent(Connection conn, long messageId, int offset, ByteBuffer src)
+ {
- Blob dataAsBlob = rs.getBlob(5);
- byte[] dataAsBytes = dataAsBlob.getBytes(1,(int) dataAsBlob.length());
- ByteBuffer buf = ByteBuffer.wrap(dataAsBytes);
- ContentHeaderBody chb = ContentHeaderBody.createFromBuffer(buf, dataAsBytes.length);
+ try
+ {
+ final boolean newConnection = conn == null;
- if(localTx)
- {
- commitTran(context);
- }
+ if(newConnection)
+ {
+ conn = newConnection();
+ }
- return new MessageMetaData(info, chb, rs.getInt(6));
+ src = src.slice();
- }
- else
+ byte[] chunkData = new byte[src.limit()];
+ src.duplicate().get(chunkData);
+
+ PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_CONTENT);
+ stmt.setLong(1,messageId);
+ stmt.setInt(2, offset);
+ stmt.setInt(3, offset+chunkData.length);
+
+
+ /* this would be the Java 6 way of doing things
+ Blob dataAsBlob = conn.createBlob();
+ dataAsBlob.setBytes(1L, chunkData);
+ stmt.setBlob(3, dataAsBlob);
+ */
+ ByteArrayInputStream bis = new ByteArrayInputStream(chunkData);
+ stmt.setBinaryStream(4, bis, chunkData.length);
+ stmt.executeUpdate();
+
+ if(newConnection)
{
- if(localTx)
- {
- abortTran(context);
- }
- throw new AMQException("Metadata not found for message with id " + messageId);
+ conn.commit();
+ conn.close();
}
}
catch (SQLException e)
{
- if(localTx)
+ if(conn != null)
{
- abortTran(context);
+ try
+ {
+ conn.close();
+ }
+ catch (SQLException e1)
+ {
+
+ }
}
- throw new AMQException("Error reading AMQMessage with id " + messageId + " from database: " + e, e);
+ throw new RuntimeException("Error reading AMQMessage with id " + messageId + " from database: " + e, e);
}
}
- public ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException
- {
- boolean localTx = getOrCreateTransaction(context);
- Connection conn = getConnection(context);
-
- try
- {
+ public int getContent(long messageId, int offset, ByteBuffer dst)
+ {
+ Connection conn = null;
- PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_CONTENT);
- stmt.setLong(1,messageId);
- stmt.setInt(2, index);
- ResultSet rs = stmt.executeQuery();
- if(rs.next())
- {
- Blob dataAsBlob = rs.getBlob(1);
-
- final int size = (int) dataAsBlob.length();
- byte[] dataAsBytes = dataAsBlob.getBytes(1, size);
- final ByteBuffer buf = ByteBuffer.wrap(dataAsBytes);
+ try
+ {
+ conn = newConnection();
- ContentChunk cb = new ContentChunk()
- {
+ PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_CONTENT);
+ stmt.setLong(1,messageId);
+ stmt.setInt(2, offset);
+ stmt.setInt(3, offset+dst.remaining());
+ ResultSet rs = stmt.executeQuery();
- public int getSize()
- {
- return size;
- }
+ int written = 0;
- public ByteBuffer getData()
- {
- return buf;
- }
+ while(rs.next())
+ {
+ int offsetInMessage = rs.getInt(1);
+ Blob dataAsBlob = rs.getBlob(2);
- public void reduceToFit()
- {
+ final int size = (int) dataAsBlob.length();
+ byte[] dataAsBytes = dataAsBlob.getBytes(1, size);
- }
- };
+ int posInArray = offset + written - offsetInMessage;
+ int count = size - posInArray;
+ if(count > dst.remaining())
+ {
+ count = dst.remaining();
+ }
+ dst.put(dataAsBytes,posInArray,count);
+ written+=count;
- if(localTx)
- {
- commitTran(context);
- }
+ if(dst.remaining() == 0)
+ {
+ break;
+ }
+ }
- return cb;
+ conn.close();
+ return written;
- }
- else
- {
- if(localTx)
- {
- abortTran(context);
- }
- throw new AMQException("Message not found for message with id " + messageId);
- }
+ }
+ catch (SQLException e)
+ {
+ if(conn != null)
+ {
+ try
+ {
+ conn.close();
}
- catch (SQLException e)
+ catch (SQLException e1)
{
- if(localTx)
- {
- abortTran(context);
- }
- throw new AMQException("Error reading AMQMessage with id " + messageId + " from database: " + e, e);
}
+ }
+
+ throw new RuntimeException("Error reading AMQMessage with id " + messageId + " from database: " + e, e);
+ }
@@ -1291,173 +1308,158 @@ public class DerbyMessageStore implements MessageStore
return true;
}
- private void checkNotClosed() throws MessageStoreClosedException
- {
- if (_closed.get())
- {
- throw new MessageStoreClosedException();
- }
- }
-
- private static final class ProcessAction
+ private synchronized void stateTransition(State requiredState, State newState) throws AMQException
{
- private final AMQQueue _queue;
- private final StoreContext _context;
- private final AMQMessage _message;
-
- public ProcessAction(AMQQueue queue, StoreContext context, AMQMessage message)
- {
- _queue = queue;
- _context = context;
- _message = message;
- }
-
- public void process() throws AMQException
+ if (_state != requiredState)
{
- _queue.enqueue(_context, _message);
-
+ throw new AMQException("Cannot transition to the state: " + newState + "; need to be in state: " + requiredState
+ + "; currently in state: " + _state);
}
+ _state = newState;
}
- private void deliverMessages(final StoreContext context, Map<AMQShortString, AMQQueue> queues)
- throws SQLException, AMQException
+ private class DerbyTransaction implements Transaction
{
- Map<Long, AMQMessage> msgMap = new HashMap<Long,AMQMessage>();
- List<ProcessAction> actions = new ArrayList<ProcessAction>();
+ private final ConnectionWrapper _connWrapper;
- Map<AMQShortString, Integer> queueRecoveries = new TreeMap<AMQShortString, Integer>();
- final boolean inLocaltran = inTran(context);
- Connection conn = null;
- try
+ private DerbyTransaction()
{
-
- if(inLocaltran)
+ try
{
- conn = getConnection(context);
+ _connWrapper = new ConnectionWrapper(newConnection());
}
- else
+ catch (SQLException e)
{
- conn = newConnection();
+ throw new RuntimeException(e);
}
+ }
+ public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQException
+ {
+ DerbyMessageStore.this.enqueueMessage(_connWrapper, queue, messageId);
+ }
- MessageHandleFactory messageHandleFactory = new MessageHandleFactory();
- long maxId = 1;
-
- TransactionalContext txnContext = new NonTransactionalContext(this, new StoreContext(), null, null);
+ public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQException
+ {
+ DerbyMessageStore.this.dequeueMessage(_connWrapper, queue, messageId);
- Statement stmt = conn.createStatement();
- ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE_ENTRY);
+ }
+ public void commitTran() throws AMQException
+ {
+ DerbyMessageStore.this.commitTran(_connWrapper);
+ }
- while (rs.next())
- {
+ public StoreFuture commitTranAsync() throws AMQException
+ {
+ return DerbyMessageStore.this.commitTranAsync(_connWrapper);
+ }
+ public void abortTran() throws AMQException
+ {
+ DerbyMessageStore.this.abortTran(_connWrapper);
+ }
+ }
+ private class StoredDerbyMessage implements StoredMessage
+ {
- AMQShortString queueName = new AMQShortString(rs.getString(1));
+ private final long _messageId;
+ private volatile WeakReference<StorableMessageMetaData> _metaDataRef;
+ private Connection _conn;
+ StoredDerbyMessage(long messageId, StorableMessageMetaData metaData)
+ {
+ this(messageId, metaData, true);
+ }
- AMQQueue queue = queues.get(queueName);
- if (queue == null)
- {
- queue = AMQQueueFactory.createAMQQueueImpl(queueName, false, null, false, _virtualHost, null);
- _virtualHost.getQueueRegistry().registerQueue(queue);
- queues.put(queueName, queue);
- }
-
- long messageId = rs.getLong(2);
- maxId = Math.max(maxId, messageId);
- AMQMessage message = msgMap.get(messageId);
+ StoredDerbyMessage(long messageId,
+ StorableMessageMetaData metaData, boolean persist)
+ {
+ try
+ {
+ _messageId = messageId;
- if(message != null)
+ _metaDataRef = new WeakReference(metaData);
+ if(persist)
{
- message.incrementReference();
- }
- else
- {
- message = new AMQMessage(messageId, this, messageHandleFactory, txnContext);
- msgMap.put(messageId,message);
+ _conn = newConnection();
+ storeMetaData(_conn, messageId, metaData);
}
+ }
+ catch (SQLException e)
+ {
+ throw new RuntimeException(e);
+ }
+
+ }
- if (_logger.isDebugEnabled())
+ public StorableMessageMetaData getMetaData()
+ {
+ StorableMessageMetaData metaData = _metaDataRef.get();
+ if(metaData == null)
+ {
+ try
{
- _logger.debug("On recovery, delivering " + message.getMessageId() + " to " + queue.getName());
+ metaData = DerbyMessageStore.this.getMetaData(_messageId);
}
-
- if (_logger.isInfoEnabled())
+ catch (SQLException e)
{
- Integer count = queueRecoveries.get(queueName);
- if (count == null)
- {
- count = 0;
- }
-
- queueRecoveries.put(queueName, ++count);
-
+ throw new RuntimeException(e);
}
-
- actions.add(new ProcessAction(queue, context, message));
-
+ _metaDataRef = new WeakReference(metaData);
}
- for(ProcessAction action : actions)
- {
- action.process();
- }
-
- _messageId.set(maxId + 1);
+ return metaData;
}
- catch (SQLException e)
+
+ public long getMessageNumber()
{
- _logger.error("Error: " + e, e);
- throw e;
+ return _messageId;
}
- finally
+
+ public void addContent(int offsetInMessage, java.nio.ByteBuffer src)
{
- if (inLocaltran && conn != null)
- {
- conn.close();
- }
+ DerbyMessageStore.this.addContent(_conn, _messageId, offsetInMessage, src);
}
- if (_logger.isInfoEnabled())
+ public int getContent(int offsetInMessage, java.nio.ByteBuffer dst)
{
- _logger.info("Recovered message counts: " + queueRecoveries);
+ return DerbyMessageStore.this.getContent(_messageId, offsetInMessage, dst);
}
- }
-
- private Connection getConnection(final StoreContext context)
- {
- return ((ConnectionWrapper)context.getPayload()).getConnection();
- }
-
- private boolean getOrCreateTransaction(StoreContext context) throws AMQException
- {
- ConnectionWrapper tx = (ConnectionWrapper) context.getPayload();
- if (tx == null)
+ public StoreFuture flushToStore()
{
- beginTran(context);
- return true;
+ try
+ {
+ if(_conn != null)
+ {
+ _conn.commit();
+ _conn.close();
+ }
+ }
+ catch (SQLException e)
+ {
+ throw new RuntimeException(e);
+ }
+ finally
+ {
+ _conn = null;
+ }
+ return IMMEDIATE_FUTURE;
}
- return false;
- }
-
- private synchronized void stateTransition(State requiredState, State newState) throws AMQException
- {
- if (_state != requiredState)
+ public void remove()
{
- throw new AMQException("Cannot transition to the state: " + newState + "; need to be in state: " + requiredState
- + "; currently in state: " + _state);
+ flushToStore();
+ DerbyMessageStore.this.removeMessage(_messageId);
}
-
- _state = newState;
}
+
+
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java b/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java
new file mode 100755
index 0000000000..cfbacd28c8
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java
@@ -0,0 +1,116 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.store;
+
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.commons.configuration.Configuration;
+
+public interface DurableConfigurationStore
+{
+
+ /**
+ * Called after instantiation in order to configure the message store. A particular implementation can define
+ * whatever parameters it wants.
+ *
+ * @param name The name to be used by this storem
+ * @param recoveryHandler Handler to be called as the store recovers on start up
+ * @param config The apache commons configuration object.
+ *
+ * @throws Exception If any error occurs that means the store is unable to configure itself.
+ */
+ void configureConfigStore(String name,
+ ConfigurationRecoveryHandler recoveryHandler,
+ Configuration config,
+ LogSubject logSubject) throws Exception;
+ /**
+ * Makes the specified exchange persistent.
+ *
+ * @param exchange The exchange to persist.
+ *
+ * @throws org.apache.qpid.AMQException If the operation fails for any reason.
+ */
+ void createExchange(Exchange exchange) throws AMQException;
+
+ /**
+ * Removes the specified persistent exchange.
+ *
+ * @param exchange The exchange to remove.
+ *
+ * @throws org.apache.qpid.AMQException If the operation fails for any reason.
+ */
+ void removeExchange(Exchange exchange) throws AMQException;
+
+ /**
+ * Binds the specified queue to an exchange with a routing key.
+ *
+ * @param exchange The exchange to bind to.
+ * @param routingKey The routing key to bind by.
+ * @param queue The queue to bind.
+ * @param args Additional parameters.
+ *
+ * @throws org.apache.qpid.AMQException If the operation fails for any reason.
+ */
+ void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException;
+
+ /**
+ * Unbinds the specified from an exchange under a particular routing key.
+ *
+ * @param exchange The exchange to unbind from.
+ * @param routingKey The routing key to unbind.
+ * @param queue The queue to unbind.
+ * @param args Additonal parameters.
+ *
+ * @throws org.apache.qpid.AMQException If the operation fails for any reason.
+ */
+ void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException;
+
+ /**
+ * Makes the specified queue persistent.
+ *
+ * @param queue The queue to store.
+ *
+ * @throws org.apache.qpid.AMQException If the operation fails for any reason.
+ */
+ void createQueue(AMQQueue queue) throws AMQException;
+
+ /**
+ * Makes the specified queue persistent.
+ *
+ * @param queue The queue to store.
+ *
+ * @param arguments The additional arguments to the binding
+ * @throws org.apache.qpid.AMQException If the operation fails for any reason.
+ */
+ void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException;
+
+ /**
+ * Removes the specified queue from the persistent store.
+ *
+ * @param queue The queue to remove.
+ * @throws org.apache.qpid.AMQException If the operation fails for any reason.
+ */
+ void removeQueue(AMQQueue queue) throws AMQException;
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java
index 587c85fc12..e3e9432e6b 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java
@@ -20,16 +20,20 @@
*/
package org.apache.qpid.server.store;
-import org.apache.commons.configuration.Configuration;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.framing.abstraction.ContentChunk;
-import org.apache.qpid.server.queue.MessageMetaData;
+import org.apache.qpid.server.message.MessageMetaData;
import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.logging.messages.MessageStoreMessages;
+import org.apache.qpid.server.logging.messages.ConfigStoreMessages;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.commons.configuration.Configuration;
import java.util.ArrayList;
import java.util.Collections;
@@ -38,6 +42,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
+import java.nio.ByteBuffer;
/** A simple message store that stores the messages in a threadsafe structure in memory. */
public class MemoryMessageStore implements MessageStore
@@ -48,59 +53,74 @@ public class MemoryMessageStore implements MessageStore
private static final String HASHTABLE_CAPACITY_CONFIG = "hashtable-capacity";
- protected ConcurrentMap<Long, MessageMetaData> _metaDataMap;
-
- protected ConcurrentMap<Long, List<ContentChunk>> _contentBodyMap;
private final AtomicLong _messageId = new AtomicLong(1);
private AtomicBoolean _closed = new AtomicBoolean(false);
+ private LogSubject _logSubject;
- public void configure()
+ private static final Transaction IN_MEMORY_TRANSACTION = new Transaction()
{
- _log.info("Using capacity " + DEFAULT_HASHTABLE_CAPACITY + " for hash tables");
- _metaDataMap = new ConcurrentHashMap<Long, MessageMetaData>(DEFAULT_HASHTABLE_CAPACITY);
- _contentBodyMap = new ConcurrentHashMap<Long, List<ContentChunk>>(DEFAULT_HASHTABLE_CAPACITY);
- }
+ public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQException
+ {
+ }
+
+ public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQException
+ {
+ }
+
+ public void commitTran() throws AMQException
+ {
+ }
+
+ public StoreFuture commitTranAsync() throws AMQException
+ {
+ return IMMEDIATE_FUTURE;
+ }
+
+ public void abortTran() throws AMQException
+ {
+ }
- public void configure(String base, Configuration config)
+ };
+
+ public void configureConfigStore(String name, ConfigurationRecoveryHandler handler, Configuration configuration, LogSubject logSubject) throws Exception
{
- int hashtableCapacity = config.getInt(base + "." + HASHTABLE_CAPACITY_CONFIG, DEFAULT_HASHTABLE_CAPACITY);
- _log.info("Using capacity " + hashtableCapacity + " for hash tables");
- _metaDataMap = new ConcurrentHashMap<Long, MessageMetaData>(hashtableCapacity);
- _contentBodyMap = new ConcurrentHashMap<Long, List<ContentChunk>>(hashtableCapacity);
+ _logSubject = logSubject;
+ CurrentActor.get().message(_logSubject, ConfigStoreMessages.CFG_1001(this.getClass().getName()));
+
+
}
- public void configure(VirtualHost virtualHost, String base, Configuration config) throws Exception
+ public void configureMessageStore(String name,
+ MessageStoreRecoveryHandler recoveryHandler,
+ Configuration config,
+ LogSubject logSubject) throws Exception
{
- configure(base, config);
+ if(_logSubject == null)
+ {
+ _logSubject = logSubject;
+ }
+ int hashtableCapacity = config.getInt(name + "." + HASHTABLE_CAPACITY_CONFIG, DEFAULT_HASHTABLE_CAPACITY);
+ _log.info("Using capacity " + hashtableCapacity + " for hash tables");
+ CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_CREATED(this.getClass().getName()));
}
public void close() throws Exception
{
_closed.getAndSet(true);
- if (_metaDataMap != null)
- {
- _metaDataMap.clear();
- _metaDataMap = null;
- }
- if (_contentBodyMap != null)
- {
- _contentBodyMap.clear();
- _contentBodyMap = null;
- }
+ CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_CLOSED());
+
}
- public void removeMessage(StoreContext context, Long messageId) throws AMQException
+ public StoredMessage addMessage(StorableMessageMetaData metaData)
{
- checkNotClosed();
- if (_log.isDebugEnabled())
- {
- _log.debug("Removing message with id " + messageId);
- }
- _metaDataMap.remove(messageId);
- _contentBodyMap.remove(messageId);
+ final long id = _messageId.getAndIncrement();
+ StoredMemoryMessage message = new StoredMemoryMessage(id, metaData);
+
+ return message;
}
+
public void createExchange(Exchange exchange) throws AMQException
{
@@ -137,35 +157,19 @@ public class MemoryMessageStore implements MessageStore
// Not required to do anything
}
- public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException
+ public void configureTransactionLog(String name,
+ TransactionLogRecoveryHandler recoveryHandler,
+ Configuration storeConfiguration,
+ LogSubject logSubject) throws Exception
{
- // Not required to do anything
+ //To change body of implemented methods use File | Settings | File Templates.
}
- public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException
+ public Transaction newTransaction()
{
- // Not required to do anything
+ return IN_MEMORY_TRANSACTION;
}
- public void beginTran(StoreContext context) throws AMQException
- {
- // Not required to do anything
- }
-
- public void commitTran(StoreContext context) throws AMQException
- {
- // Not required to do anything
- }
-
- public void abortTran(StoreContext context) throws AMQException
- {
- // Not required to do anything
- }
-
- public boolean inTran(StoreContext context)
- {
- return false;
- }
public List<AMQQueue> createQueues() throws AMQException
{
@@ -177,48 +181,6 @@ public class MemoryMessageStore implements MessageStore
return _messageId.getAndIncrement();
}
- public void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, boolean lastContentBody)
- throws AMQException
- {
- checkNotClosed();
- List<ContentChunk> bodyList = _contentBodyMap.get(messageId);
-
- if (bodyList == null && lastContentBody)
- {
- _contentBodyMap.put(messageId, Collections.singletonList(contentBody));
- }
- else
- {
- if (bodyList == null)
- {
- bodyList = new ArrayList<ContentChunk>();
- _contentBodyMap.put(messageId, bodyList);
- }
-
- bodyList.add(index, contentBody);
- }
- }
-
- public void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData)
- throws AMQException
- {
- checkNotClosed();
- _metaDataMap.put(messageId, messageMetaData);
- }
-
- public MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException
- {
- checkNotClosed();
- return _metaDataMap.get(messageId);
- }
-
- public ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException
- {
- checkNotClosed();
- List<ContentChunk> bodyList = _contentBodyMap.get(messageId);
- return bodyList.get(index);
- }
-
public boolean isPersistent()
{
return false;
@@ -231,4 +193,6 @@ public class MemoryMessageStore implements MessageStore
throw new MessageStoreClosedException();
}
}
+
+
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/store/MessageMetaDataType.java b/java/broker/src/main/java/org/apache/qpid/server/store/MessageMetaDataType.java
new file mode 100755
index 0000000000..428bb1e41b
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/store/MessageMetaDataType.java
@@ -0,0 +1,41 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.store;
+
+import org.apache.qpid.server.message.MessageMetaData;
+import org.apache.qpid.server.message.MessageMetaData_0_10;
+
+import java.nio.ByteBuffer;
+
+public enum MessageMetaDataType
+{
+ META_DATA_0_8 { public Factory<MessageMetaData> getFactory() { return MessageMetaData.FACTORY; } },
+ META_DATA_0_10 { public Factory<MessageMetaData_0_10> getFactory() { return MessageMetaData_0_10.FACTORY; } };
+
+
+ public static interface Factory<M extends StorableMessageMetaData>
+ {
+ M createMetaData(ByteBuffer buf);
+ }
+
+ abstract public Factory<? extends StorableMessageMetaData> getFactory();
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java
index f2910acb77..e2fca2f9c7 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java
@@ -20,52 +20,43 @@
*/
package org.apache.qpid.server.store;
+import org.apache.qpid.server.logging.LogSubject;
import org.apache.commons.configuration.Configuration;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.framing.abstraction.ContentChunk;
-import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.queue.MessageMetaData;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-
/**
- * MessageStore defines the interface to a storage area, which can be used to preserve the state of messages, queues
- * and exchanges in a transactional manner.
- *
- * <p/>All message store, remove, enqueue and dequeue operations are carried out against a {@link StoreContext} which
- * encapsulates the transactional context they are performed in. Many such operations can be carried out in a single
- * transaction.
+ * MessageStore defines the interface to a storage area, which can be used to preserve the state of messages.
*
- * <p/>The storage and removal of queues and exchanges, are not carried out in a transactional context.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities
- * <tr><td> Accept transaction boundary demarcations: Begin, Commit, Abort.
- * <tr><td> Store and remove queues.
- * <tr><td> Store and remove exchanges.
- * <tr><td> Store and remove messages.
- * <tr><td> Bind and unbind queues to exchanges.
- * <tr><td> Enqueue and dequeue messages to queues.
- * <tr><td> Generate message identifiers.
- * </table>
*/
-public interface MessageStore
+public interface MessageStore extends DurableConfigurationStore, TransactionLog
{
+ StoreFuture IMMEDIATE_FUTURE = new StoreFuture()
+ {
+ public boolean isComplete()
+ {
+ return true;
+ }
+
+ public void waitForCompletion()
+ {
+
+ }
+ };
+
+
/**
* Called after instantiation in order to configure the message store. A particular implementation can define
* whatever parameters it wants.
*
- * @param virtualHost The virtual host using by this store
- * @param base The base element identifier from which all configuration items are relative. For example, if
- * the base element is "store", the all elements used by concrete classes will be "store.foo" etc.
- * @param config The apache commons configuration object.
+ * @param name The name to be used by this storem
+ * @param recoveryHandler Handler to be called as the store recovers on start up
+ * @param config The apache commons configuration object.
*
* @throws Exception If any error occurs that means the store is unable to configure itself.
*/
- void configure(VirtualHost virtualHost, String base, Configuration config) throws Exception;
+ void configureMessageStore(String name,
+ MessageStoreRecoveryHandler recoveryHandler,
+ Configuration config,
+ LogSubject logSubject) throws Exception;
/**
* Called to close and cleanup any resources used by the message store.
@@ -74,203 +65,16 @@ public interface MessageStore
*/
void close() throws Exception;
- /**
- * Removes the specified message from the store in the given transactional store context.
- *
- * @param storeContext The transactional context to remove the message in.
- * @param messageId Identifies the message to remove.
- *
- * @throws AMQException If the operation fails for any reason.
- */
- void removeMessage(StoreContext storeContext, Long messageId) throws AMQException;
-
- /**
- * Makes the specified exchange persistent.
- *
- * @param exchange The exchange to persist.
- *
- * @throws AMQException If the operation fails for any reason.
- */
- void createExchange(Exchange exchange) throws AMQException;
-
- /**
- * Removes the specified persistent exchange.
- *
- * @param exchange The exchange to remove.
- *
- * @throws AMQException If the operation fails for any reason.
- */
- void removeExchange(Exchange exchange) throws AMQException;
-
- /**
- * Binds the specified queue to an exchange with a routing key.
- *
- * @param exchange The exchange to bind to.
- * @param routingKey The routing key to bind by.
- * @param queue The queue to bind.
- * @param args Additional parameters.
- *
- * @throws AMQException If the operation fails for any reason.
- */
- void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException;
-
- /**
- * Unbinds the specified from an exchange under a particular routing key.
- *
- * @param exchange The exchange to unbind from.
- * @param routingKey The routing key to unbind.
- * @param queue The queue to unbind.
- * @param args Additonal parameters.
- *
- * @throws AMQException If the operation fails for any reason.
- */
- void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException;
- /**
- * Makes the specified queue persistent.
- *
- * @param queue The queue to store.
- *
- * @throws AMQException If the operation fails for any reason.
- */
- void createQueue(AMQQueue queue) throws AMQException;
+ public <T extends StorableMessageMetaData> StoredMessage<T> addMessage(T metaData);
- /**
- * Makes the specified queue persistent.
- *
- * @param queue The queue to store.
- *
- * @param arguments The additional arguments to the binding
- * @throws AMQException If the operation fails for any reason.
- */
- void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException;
-
- /**
- * Removes the specified queue from the persistent store.
- *
- * @param queue The queue to remove.
- * @throws AMQException If the operation fails for any reason.
- */
- void removeQueue(final AMQQueue queue) throws AMQException;
-
- /**
- * Places a message onto a specified queue, in a given transactional context.
- *
- * @param context The transactional context for the operation.
- * @param queue The queue to place the message on.
- * @param messageId The message to enqueue.
- * @throws AMQException If the operation fails for any reason.
- */
- void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException;
-
- /**
- * Extracts a message from a specified queue, in a given transactional context.
- *
- * @param context The transactional context for the operation.
- * @param queue The queue to place the message on.
- * @param messageId The message to dequeue.
- * @throws AMQException If the operation fails for any reason, or if the specified message does not exist.
- */
- void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException;
-
- /**
- * Begins a transactional context.
- *
- * @param context The transactional context to begin.
- *
- * @throws AMQException If the operation fails for any reason.
- */
- void beginTran(StoreContext context) throws AMQException;
-
- /**
- * Commits all operations performed within a given transactional context.
- *
- * @param context The transactional context to commit all operations for.
- *
- * @throws AMQException If the operation fails for any reason.
- */
- void commitTran(StoreContext context) throws AMQException;
-
- /**
- * Abandons all operations performed within a given transactional context.
- *
- * @param context The transactional context to abandon.
- *
- * @throws AMQException If the operation fails for any reason.
- */
- void abortTran(StoreContext context) throws AMQException;
-
- /**
- * Tests a transactional context to see if it has been begun but not yet committed or aborted.
- *
- * @param context The transactional context to test.
- *
- * @return <tt>true</tt> if the transactional context is live, <tt>false</tt> otherwise.
- */
- boolean inTran(StoreContext context);
-
- /**
- * Return a valid, currently unused message id.
- *
- * @return A fresh message id.
- */
- Long getNewMessageId();
-
- /**
- * Stores a chunk of message data.
- *
- * @param context The transactional context for the operation.
- * @param messageId The message to store the data for.
- * @param index The index of the data chunk.
- * @param contentBody The content of the data chunk.
- * @param lastContentBody Flag to indicate that this is the last such chunk for the message.
- *
- * @throws AMQException If the operation fails for any reason, or if the specified message does not exist.
- */
- void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody,
- boolean lastContentBody) throws AMQException;
-
- /**
- * Stores message meta-data.
- *
- * @param context The transactional context for the operation.
- * @param messageId The message to store the data for.
- * @param messageMetaData The message meta data to store.
- *
- * @throws AMQException If the operation fails for any reason, or if the specified message does not exist.
- */
- void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) throws AMQException;
-
- /**
- * Retrieves message meta-data.
- *
- * @param context The transactional context for the operation.
- * @param messageId The message to get the meta-data for.
- *
- * @return The message meta data.
- *
- * @throws AMQException If the operation fails for any reason, or if the specified message does not exist.
- */
- MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException;
-
- /**
- * Retrieves a chunk of message data.
- *
- * @param context The transactional context for the operation.
- * @param messageId The message to get the data chunk for.
- * @param index The offset index of the data chunk within the message.
- *
- * @return A chunk of message data.
- *
- * @throws AMQException If the operation fails for any reason, or if the specified message does not exist.
- */
- ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException;
/**
* Is this store capable of persisting the data
- *
+ *
* @return true if this store is capable of persisting data
*/
boolean isPersistent();
+
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreRecoveryHandler.java b/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreRecoveryHandler.java
new file mode 100755
index 0000000000..ba65b8e1ec
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreRecoveryHandler.java
@@ -0,0 +1,33 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+package org.apache.qpid.server.store;
+
+public interface MessageStoreRecoveryHandler
+{
+ StoredMessageRecoveryHandler begin();
+
+ public static interface StoredMessageRecoveryHandler
+ {
+ void message(StoredMessage message);
+
+ void completeMessageRecovery();
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/store/StorableMessageMetaData.java b/java/broker/src/main/java/org/apache/qpid/server/store/StorableMessageMetaData.java
new file mode 100755
index 0000000000..12d2a6a6c7
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/store/StorableMessageMetaData.java
@@ -0,0 +1,36 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.store;
+
+import java.nio.ByteBuffer;
+
+public interface StorableMessageMetaData
+{
+ MessageMetaDataType getType();
+
+ int getStorableSize();
+
+ int writeToBuffer(int offsetInMetaData, ByteBuffer dest);
+
+ int getContentSize();
+
+ boolean isPersistent();
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java b/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java
index fdb56a1a55..88cc68bc71 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java
@@ -35,6 +35,7 @@ public class StoreContext
private String _name;
private Object _payload;
+
public StoreContext()
{
_name = "StoreContext";
@@ -68,4 +69,5 @@ public class StoreContext
{
return "<_name = " + _name + ", _payload = " + _payload + ">";
}
+
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java b/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java
new file mode 100755
index 0000000000..867fb4f9c7
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java
@@ -0,0 +1,80 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.store;
+
+import java.nio.ByteBuffer;
+
+public class StoredMemoryMessage implements StoredMessage
+{
+ private final long _messageNumber;
+ private final ByteBuffer _content;
+ private final StorableMessageMetaData _metaData;
+
+ StoredMemoryMessage(long messageNumber, StorableMessageMetaData metaData)
+ {
+ _messageNumber = messageNumber;
+ _metaData = metaData;
+ _content = ByteBuffer.allocate(metaData.getContentSize());
+
+ }
+
+ public long getMessageNumber()
+ {
+ return _messageNumber;
+ }
+
+ public void addContent(int offsetInMessage, ByteBuffer src)
+ {
+ src = src.duplicate();
+ ByteBuffer dst = _content.duplicate();
+ dst.position(offsetInMessage);
+ dst.put(src);
+ }
+
+ public int getContent(int offset, ByteBuffer dst)
+ {
+ ByteBuffer src = _content.duplicate();
+ src.position(offset);
+ src = src.slice();
+ if(dst.remaining() < src.limit())
+ {
+ src.limit(dst.remaining());
+ }
+ dst.put(src);
+ return src.limit();
+ }
+
+ public TransactionLog.StoreFuture flushToStore()
+ {
+ return MessageStore.IMMEDIATE_FUTURE;
+ }
+
+
+ public StorableMessageMetaData getMetaData()
+ {
+ return _metaData;
+ }
+
+ public void remove()
+ {
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/store/StoredMessage.java b/java/broker/src/main/java/org/apache/qpid/server/store/StoredMessage.java
new file mode 100755
index 0000000000..0bc45c6718
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/store/StoredMessage.java
@@ -0,0 +1,38 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+package org.apache.qpid.server.store;
+
+import java.nio.ByteBuffer;
+
+public interface StoredMessage<M extends StorableMessageMetaData>
+{
+ M getMetaData();
+
+ public long getMessageNumber();
+
+ void addContent(int offsetInMessage, ByteBuffer src);
+
+ int getContent(int offsetInMessage, ByteBuffer dst);
+
+ TransactionLog.StoreFuture flushToStore();
+
+ void remove();
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLog.java b/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLog.java
new file mode 100755
index 0000000000..e6a33e23d6
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLog.java
@@ -0,0 +1,92 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.store;
+
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.AMQException;
+import org.apache.commons.configuration.Configuration;
+
+public interface TransactionLog
+{
+
+ public static interface Transaction
+ {
+ /**
+ * Places a message onto a specified queue, in a given transactional context.
+ *
+ * @param queue The queue to place the message on.
+ * @param messageId The message to enqueue.
+ * @throws org.apache.qpid.AMQException If the operation fails for any reason.
+ */
+ void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQException;
+
+ /**
+ * Extracts a message from a specified queue, in a given transactional context.
+ *
+ * @param queue The queue to place the message on.
+ * @param messageId The message to dequeue.
+ * @throws org.apache.qpid.AMQException If the operation fails for any reason, or if the specified message does not exist.
+ */
+ void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQException;
+
+
+ /**
+ * Commits all operations performed within a given transactional context.
+ *
+ * @throws org.apache.qpid.AMQException If the operation fails for any reason.
+ */
+ void commitTran() throws AMQException;
+
+ /**
+ * Commits all operations performed within a given transactional context.
+ *
+ * @throws org.apache.qpid.AMQException If the operation fails for any reason.
+ */
+ StoreFuture commitTranAsync() throws AMQException;
+
+ /**
+ * Abandons all operations performed within a given transactional context.
+ *
+ * @throws org.apache.qpid.AMQException If the operation fails for any reason.
+ */
+ void abortTran() throws AMQException;
+
+
+
+ }
+
+ public void configureTransactionLog(String name,
+ TransactionLogRecoveryHandler recoveryHandler,
+ Configuration storeConfiguration,
+ LogSubject logSubject) throws Exception;
+
+ Transaction newTransaction();
+
+
+
+ public static interface StoreFuture
+ {
+ boolean isComplete();
+
+ void waitForCompletion();
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogRecoveryHandler.java b/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogRecoveryHandler.java
new file mode 100755
index 0000000000..7781c52df3
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogRecoveryHandler.java
@@ -0,0 +1,33 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+package org.apache.qpid.server.store;
+
+public interface TransactionLogRecoveryHandler
+{
+ QueueEntryRecoveryHandler begin(TransactionLog log);
+
+ public static interface QueueEntryRecoveryHandler
+ {
+ void queueEntry(String queuename, long messageId);
+
+ void completeQueueEntryRecovery();
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogResource.java b/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogResource.java
new file mode 100755
index 0000000000..0d81dd151d
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogResource.java
@@ -0,0 +1,26 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+package org.apache.qpid.server.store;
+
+public interface TransactionLogResource
+{
+ public String getResourceName();
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java b/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java
new file mode 100755
index 0000000000..b49b12fb79
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java
@@ -0,0 +1,93 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.subscription;
+
+import org.apache.qpid.server.transport.ServerSession;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.log4j.Logger;
+
+
+class ExplicitAcceptDispositionChangeListener implements ServerSession.MessageDispositionChangeListener
+{
+ private static final Logger _logger = Logger.getLogger(ExplicitAcceptDispositionChangeListener.class);
+
+
+ private final QueueEntry _entry;
+ private final Subscription_0_10 _sub;
+
+ public ExplicitAcceptDispositionChangeListener(QueueEntry entry, Subscription_0_10 subscription_0_10)
+ {
+ _entry = entry;
+ _sub = subscription_0_10;
+ }
+
+ public void onAccept()
+ {
+ final Subscription_0_10 subscription = getSubscription();
+ if(subscription != null && _entry.isAcquiredBy(_sub))
+ {
+ subscription.getSession().acknowledge(subscription, _entry);
+ }
+ else
+ {
+ _logger.warn("MessageAccept received for message which has not been acquired (likely client error)");
+ }
+
+ }
+
+ public void onRelease()
+ {
+ final Subscription_0_10 subscription = getSubscription();
+ if(subscription != null && _entry.isAcquiredBy(_sub))
+ {
+ subscription.release(_entry);
+ }
+ else
+ {
+ _logger.warn("MessageRelease received for message which has not been acquired (likely client error)");
+ }
+ }
+
+ public void onReject()
+ {
+ final Subscription_0_10 subscription = getSubscription();
+ if(subscription != null && _entry.isAcquiredBy(_sub))
+ {
+ subscription.reject(_entry);
+ }
+ else
+ {
+ _logger.warn("MessageReject received for message which has not been acquired (likely client error)");
+ }
+
+ }
+
+ public boolean acquire()
+ {
+ return _entry.acquire(getSubscription());
+ }
+
+
+ private Subscription_0_10 getSubscription()
+ {
+ return _sub;
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java b/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java
new file mode 100755
index 0000000000..b5bb2014b5
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java
@@ -0,0 +1,86 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.subscription;
+
+import org.apache.qpid.server.transport.ServerSession;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.log4j.Logger;
+
+class ImplicitAcceptDispositionChangeListener implements ServerSession.MessageDispositionChangeListener
+{
+ private static final Logger _logger = Logger.getLogger(ImplicitAcceptDispositionChangeListener.class);
+
+
+ private final QueueEntry _entry;
+ private Subscription_0_10 _sub;
+
+ public ImplicitAcceptDispositionChangeListener(QueueEntry entry, Subscription_0_10 subscription_0_10)
+ {
+ _entry = entry;
+ _sub = subscription_0_10;
+ }
+
+ public void onAccept()
+ {
+ _logger.warn("MessageAccept received for message which is using NONE as the accept mode (likely client error)");
+ }
+
+ public void onRelease()
+ {
+ if(_entry.isAcquiredBy(_sub))
+ {
+ getSubscription().release(_entry);
+ }
+ else
+ {
+ _logger.warn("MessageRelease received for message which has not been acquired (likely client error)");
+ }
+ }
+
+ public void onReject()
+ {
+ if(_entry.isAcquiredBy(_sub))
+ {
+ getSubscription().reject(_entry);
+ }
+ else
+ {
+ _logger.warn("MessageReject received for message which has not been acquired (likely client error)");
+ }
+
+ }
+
+ public boolean acquire()
+ {
+ boolean acquired = _entry.acquire(getSubscription());
+ //TODO - why acknowledge here??? seems bizarre...
+ // getSubscription().getSession().acknowledge(getSubscription(), _entry);
+ return acquired;
+
+ }
+
+ public Subscription_0_10 getSubscription()
+ {
+ return _sub;
+ }
+
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/subscription/MessageAcceptCompletionListener.java b/java/broker/src/main/java/org/apache/qpid/server/subscription/MessageAcceptCompletionListener.java
new file mode 100755
index 0000000000..8a2a370236
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/subscription/MessageAcceptCompletionListener.java
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.subscription;
+
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.transport.ServerSession;
+import org.apache.qpid.transport.Method;
+
+public class MessageAcceptCompletionListener implements Method.CompletionListener
+{
+ private final Subscription_0_10 _sub;
+ private final QueueEntry _entry;
+ private final ServerSession _session;
+ private boolean _restoreCredit;
+
+ public MessageAcceptCompletionListener(Subscription_0_10 sub, ServerSession session, QueueEntry entry, boolean restoreCredit)
+ {
+ super();
+ _sub = sub;
+ _entry = entry;
+ _session = session;
+ _restoreCredit = restoreCredit;
+ }
+
+ public void onComplete(Method method)
+ {
+ if(_restoreCredit)
+ {
+ _sub.restoreCredit(_entry);
+ }
+ if(_entry.isAcquiredBy(_sub))
+ {
+ _session.acknowledge(_sub, _entry);
+ }
+
+ _session.removeDispositionListener(method);
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java b/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java
index 408defe453..9e9d2da579 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java
@@ -23,12 +23,15 @@ package org.apache.qpid.server.subscription;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.logging.LogActor;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.QueueEntry;
public interface Subscription
{
+ LogActor getLogActor();
+ boolean isTransient();
public static enum State
{
@@ -45,13 +48,17 @@ public interface Subscription
AMQQueue getQueue();
QueueEntry.SubscriptionAcquiredState getOwningState();
+ QueueEntry.SubscriptionAssignedState getAssignedState();
- void setQueue(AMQQueue queue);
- AMQChannel getChannel();
+ void setQueue(AMQQueue queue, boolean exclusive);
+
+ void setNoLocal(boolean noLocal);
AMQShortString getConsumerTag();
+ long getSubscriptionID();
+
boolean isSuspended();
boolean hasInterest(QueueEntry msg);
@@ -60,35 +67,42 @@ public interface Subscription
boolean isClosed();
- boolean isBrowser();
+ boolean acquires();
- void close();
+ boolean seesRequeues();
- boolean filtersMessages();
+ void close();
void send(QueueEntry msg) throws AMQException;
- void queueDeleted(AMQQueue queue);
+ void queueDeleted(AMQQueue queue);
boolean wouldSuspend(QueueEntry msg);
void getSendLock();
+
void releaseSendLock();
- void resend(final QueueEntry entry) throws AMQException;
+ void onDequeue(final QueueEntry queueEntry);
void restoreCredit(final QueueEntry queueEntry);
void setStateListener(final StateListener listener);
- QueueEntry getLastSeenEntry();
+ public State getState();
+
+ AMQQueue.Context getQueueContext();
- boolean setLastSeenEntry(QueueEntry expected, QueueEntry newValue);
+ void setQueueContext(AMQQueue.Context queueContext);
boolean isActive();
+ void confirmAutoClose();
+
+ public void set(String key, Object value);
+ public Object get(String key);
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java
index 556b87590c..684d3c2e74 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java
@@ -22,8 +22,11 @@ package org.apache.qpid.server.subscription;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.Map;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
@@ -32,14 +35,20 @@ import org.apache.qpid.common.ClientProperties;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.output.ProtocolOutputConverter;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.SubscriptionActor;
+import org.apache.qpid.server.logging.messages.SubscriptionMessages;
+import org.apache.qpid.server.logging.subjects.SubscriptionLogSubject;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.logging.LogActor;
import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.subscription.Subscription;
import org.apache.qpid.server.flow.FlowCreditManager;
import org.apache.qpid.server.filter.FilterManager;
import org.apache.qpid.server.filter.FilterManagerFactory;
import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.store.StoreContext;
/**
* Encapsulation of a supscription to a queue. <p/> Ties together the protocol session of a subscriber, the consumer tag
@@ -59,13 +68,25 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
private final AtomicReference<State> _state = new AtomicReference<State>(State.ACTIVE);
- private final AtomicReference<QueueEntry> _queueContext = new AtomicReference<QueueEntry>(null);
+ private AMQQueue.Context _queueContext;
+
private final ClientDeliveryMethod _deliveryMethod;
private final RecordDeliveryMethod _recordMethod;
-
- private QueueEntry.SubscriptionAcquiredState _owningState = new QueueEntry.SubscriptionAcquiredState(this);
+
+ private final QueueEntry.SubscriptionAcquiredState _owningState = new QueueEntry.SubscriptionAcquiredState(this);
+ private final QueueEntry.SubscriptionAssignedState _assignedState = new QueueEntry.SubscriptionAssignedState(this);
+
+ private final Map<String, Object> _properties = new ConcurrentHashMap<String, Object>();
+
private final Lock _stateChangeLock;
+ private static final AtomicLong idGenerator = new AtomicLong(0);
+ // Create a simple ID that increments for ever new Subscription
+ private final long _subscriptionID = idGenerator.getAndIncrement();
+ private LogSubject _logSubject;
+ private LogActor _logActor;
+
+
static final class BrowserSubscription extends SubscriptionImpl
{
public BrowserSubscription(AMQChannel channel, AMQProtocolSession protocolSession,
@@ -91,6 +112,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
* @param msg The message to send
* @throws AMQException
*/
+ @Override
public void send(QueueEntry msg) throws AMQException
{
// We don't decrement the reference here as we don't want to consume the message
@@ -103,6 +125,13 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
}
}
+
+ @Override
+ public boolean wouldSuspend(QueueEntry msg)
+ {
+ return false;
+ }
+
}
public static class NoAckSubscription extends SubscriptionImpl
@@ -130,42 +159,34 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
* @param entry The message to send
* @throws AMQException
*/
+ @Override
public void send(QueueEntry entry) throws AMQException
{
+ // if we do not need to wait for client acknowledgements
+ // we can decrement the reference count immediately.
- StoreContext storeContext = getChannel().getStoreContext();
- try
- { // if we do not need to wait for client acknowledgements
- // we can decrement the reference count immediately.
+ // By doing this _before_ the send we ensure that it
+ // doesn't get sent if it can't be dequeued, preventing
+ // duplicate delivery on recovery.
- // By doing this _before_ the send we ensure that it
- // doesn't get sent if it can't be dequeued, preventing
- // duplicate delivery on recovery.
+ // The send may of course still fail, in which case, as
+ // the message is unacked, it will be lost.
+ entry.dequeue();
- // The send may of course still fail, in which case, as
- // the message is unacked, it will be lost.
- entry.dequeue(storeContext);
+ synchronized (getChannel())
+ {
+ long deliveryTag = getChannel().getNextDeliveryTag();
- synchronized (getChannel())
- {
- long deliveryTag = getChannel().getNextDeliveryTag();
-
- sendToClient(entry, deliveryTag);
+ sendToClient(entry, deliveryTag);
- }
- entry.dispose(storeContext);
}
- finally
- {
- //Only set delivered if it actually was writen successfully..
- // using a try->finally would set it even if an error occured.
- // Is this what we want?
+ entry.dispose();
+
- entry.setDeliveredToSubscription();
- }
}
+ @Override
public boolean wouldSuspend(QueueEntry msg)
{
return false;
@@ -185,6 +206,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
super(channel, protocolSession, consumerTag, filters, noLocal, creditManager, deliveryMethod, recordMethod);
}
+
public boolean isBrowser()
{
return false;
@@ -198,42 +220,34 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
* @param entry The message to send
* @throws AMQException
*/
+ @Override
public void send(QueueEntry entry) throws AMQException
{
- try
- { // if we do not need to wait for client acknowledgements
- // we can decrement the reference count immediately.
+ // if we do not need to wait for client acknowledgements
+ // we can decrement the reference count immediately.
- // By doing this _before_ the send we ensure that it
- // doesn't get sent if it can't be dequeued, preventing
- // duplicate delivery on recovery.
+ // By doing this _before_ the send we ensure that it
+ // doesn't get sent if it can't be dequeued, preventing
+ // duplicate delivery on recovery.
- // The send may of course still fail, in which case, as
- // the message is unacked, it will be lost.
-
- synchronized (getChannel())
- {
- long deliveryTag = getChannel().getNextDeliveryTag();
+ // The send may of course still fail, in which case, as
+ // the message is unacked, it will be lost.
+ synchronized (getChannel())
+ {
+ long deliveryTag = getChannel().getNextDeliveryTag();
- recordMessageDelivery(entry, deliveryTag);
- sendToClient(entry, deliveryTag);
+ recordMessageDelivery(entry, deliveryTag);
+ sendToClient(entry, deliveryTag);
- }
- }
- finally
- {
- //Only set delivered if it actually was writen successfully..
- // using a try->finally would set it even if an error occured.
- // Is this what we want?
- entry.setDeliveredToSubscription();
}
}
+
}
@@ -244,7 +258,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
private final AMQShortString _consumerTag;
- private final boolean _noLocal;
+ private boolean _noLocal;
private final FlowCreditManager _creditManager;
@@ -260,7 +274,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
-
+
public SubscriptionImpl(AMQChannel channel , AMQProtocolSession protocolSession,
AMQShortString consumerTag, FieldTable arguments,
boolean noLocal, FlowCreditManager creditManager,
@@ -309,13 +323,52 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
- public synchronized void setQueue(AMQQueue queue)
+ public synchronized void setQueue(AMQQueue queue, boolean exclusive)
{
if(getQueue() != null)
{
throw new IllegalStateException("Attempt to set queue for subscription " + this + " to " + queue + "when already set to " + getQueue());
}
_queue = queue;
+
+ _logSubject = new SubscriptionLogSubject(this);
+ _logActor = new SubscriptionActor(CurrentActor.get().getRootMessageLogger(), this);
+
+ if (CurrentActor.get().getRootMessageLogger().
+ isMessageEnabled(CurrentActor.get(), _logSubject))
+ {
+ // Get the string value of the filters
+ String filterLogString = null;
+ if (_filters != null && _filters.hasFilters())
+ {
+ filterLogString = _filters.toString();
+ }
+
+ if (isAutoClose())
+ {
+ if (filterLogString == null)
+ {
+ filterLogString = "";
+ }
+ else
+ {
+ filterLogString += ",";
+ }
+ filterLogString += "AutoClose";
+ }
+
+ if (isBrowser())
+ {
+ // We do not need to check for null here as all Browsers are AutoClose
+ filterLogString +=",Browser";
+ }
+
+ CurrentActor.get().
+ message(_logSubject,
+ SubscriptionMessages.SUB_CREATE(filterLogString,
+ queue.isDurable() && exclusive,
+ filterLogString != null));
+ }
}
public String toString()
@@ -360,45 +413,35 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
public boolean hasInterest(QueueEntry entry)
{
+
+
+
+
//check that the message hasn't been rejected
if (entry.isRejectedBy(this))
{
if (_logger.isDebugEnabled())
{
- _logger.debug("Subscription:" + debugIdentity() + " rejected message:" + entry.debugIdentity());
+ _logger.debug("Subscription:" + this + " rejected message:" + entry);
}
// return false;
}
-
-
- //todo - client id should be recoreded and this test removed but handled below
if (_noLocal)
{
- final Object publisherId = entry.getMessage().getPublisherClientInstance();
- // We don't want local messages so check to see if message is one we sent
- Object localInstance;
+ AMQMessage message = (AMQMessage) entry.getMessage();
- if (publisherId != null && (getProtocolSession().getClientProperties() != null) &&
- (localInstance = getProtocolSession().getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null)
- {
- if(publisherId.equals(localInstance))
- {
- return false;
- }
- }
- else
- {
-
- localInstance = getProtocolSession().getClientIdentifier();
- //todo - client id should be recoreded and this test removed but handled here
+ //todo - client id should be recorded so we don't have to handle
+ // the case where this is null.
+ final Object publisher = message.getPublisherIdentifier();
+ // We don't want local messages so check to see if message is one we sent
+ Object localInstance = getProtocolSession();
- if (localInstance != null && localInstance.equals(entry.getMessage().getPublisherIdentifier()))
- {
- return false;
- }
+ if(publisher.equals(localInstance))
+ {
+ return false;
}
@@ -407,7 +450,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
if (_logger.isDebugEnabled())
{
- _logger.debug("(" + debugIdentity() + ") checking filters for message (" + entry.debugIdentity());
+ _logger.debug("(" + this + ") checking filters for message (" + entry);
}
return checkFilters(entry);
@@ -422,7 +465,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
private boolean checkFilters(QueueEntry msg)
{
- return (_filters == null) || _filters.allAllow(msg.getMessage());
+ return (_filters == null) || _filters.allAllow(msg);
}
public boolean isAutoClose()
@@ -464,20 +507,8 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
}
- if (closed)
- {
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Called close() on a closed subscription");
- }
-
- return;
- }
-
- if (_logger.isInfoEnabled())
- {
- _logger.info("Closing subscription (" + debugIdentity() + "):" + this);
- }
+ //Log Subscription closed
+ CurrentActor.get().message(_logSubject, SubscriptionMessages.SUB_CLOSE());
}
public boolean isClosed()
@@ -501,11 +532,6 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
_stateChangeLock.unlock();
}
- public void resend(final QueueEntry entry) throws AMQException
- {
- _queue.resend(entry, this);
- }
-
public AMQChannel getChannel()
{
return _channel;
@@ -516,25 +542,41 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
return _consumerTag;
}
+ public long getSubscriptionID()
+ {
+ return _subscriptionID;
+ }
+
public AMQProtocolSession getProtocolSession()
{
return _channel.getProtocolSession();
}
+ public LogActor getLogActor()
+ {
+ return _logActor;
+ }
+
public AMQQueue getQueue()
{
- return _queue;
+ return _queue;
+ }
+
+ public void onDequeue(final QueueEntry queueEntry)
+ {
+ restoreCredit(queueEntry);
}
public void restoreCredit(final QueueEntry queueEntry)
{
- _creditManager.addCredit(1, queueEntry.getSize());
+ _creditManager.restoreCredit(1, queueEntry.getSize());
}
+
public void creditStateChanged(boolean hasCredit)
{
-
+
if(hasCredit)
{
if(_state.compareAndSet(State.SUSPENDED, State.ACTIVE))
@@ -554,6 +596,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
_stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED);
}
}
+ CurrentActor.get().message(_logSubject,SubscriptionMessages.SUB_STATE(_state.get().toString()));
}
public State getState()
@@ -568,14 +611,14 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
}
- public QueueEntry getLastSeenEntry()
+ public AMQQueue.Context getQueueContext()
{
- return _queueContext.get();
+ return _queueContext;
}
- public boolean setLastSeenEntry(QueueEntry expected, QueueEntry newvalue)
+ public void setQueueContext(AMQQueue.Context context)
{
- return _queueContext.compareAndSet(expected,newvalue);
+ _queueContext = context;
}
@@ -602,4 +645,48 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
return _owningState;
}
+ public QueueEntry.SubscriptionAssignedState getAssignedState()
+ {
+ return _assignedState;
+ }
+
+
+ public void confirmAutoClose()
+ {
+ ProtocolOutputConverter converter = getChannel().getProtocolSession().getProtocolOutputConverter();
+ converter.confirmConsumerAutoClose(getChannel().getChannelId(), getConsumerTag());
+ }
+
+ public boolean acquires()
+ {
+ return !isBrowser();
+ }
+
+ public boolean seesRequeues()
+ {
+ return !isBrowser();
+ }
+
+ public boolean isTransient()
+ {
+ return false;
+ }
+
+ public void set(String key, Object value)
+ {
+ _properties.put(key, value);
+ }
+
+ public Object get(String key)
+ {
+ return _properties.get(key);
+ }
+
+
+ public void setNoLocal(boolean noLocal)
+ {
+ _noLocal = noLocal;
+ }
+
+ abstract boolean isBrowser();
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java
new file mode 100644
index 0000000000..5b3668ab64
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java
@@ -0,0 +1,663 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.subscription;
+
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.flow.FlowCreditManager;
+import org.apache.qpid.server.flow.CreditCreditManager;
+import org.apache.qpid.server.flow.WindowCreditManager;
+import org.apache.qpid.server.flow.FlowCreditManager_0_10;
+import org.apache.qpid.server.filter.FilterManager;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.SubscriptionActor;
+import org.apache.qpid.server.logging.subjects.SubscriptionLogSubject;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.logging.LogActor;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.message.MessageTransferMessage;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.transport.ServerSession;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ContentHeaderProperties;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.AMQTypedValue;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.transport.*;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+import java.nio.ByteBuffer;
+
+public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCreditManagerListener
+{
+
+ private static final AtomicLong idGenerator = new AtomicLong(0);
+ // Create a simple ID that increments for ever new Subscription
+ private final long _subscriptionID = idGenerator.getAndIncrement();
+
+ private final QueueEntry.SubscriptionAcquiredState _owningState = new QueueEntry.SubscriptionAcquiredState(this);
+ private final QueueEntry.SubscriptionAssignedState _assignedState = new QueueEntry.SubscriptionAssignedState(this);
+
+ private final Lock _stateChangeLock = new ReentrantLock();
+
+ private final AtomicReference<State> _state = new AtomicReference<State>(State.ACTIVE);
+ private AMQQueue.Context _queueContext;
+ private final AtomicBoolean _deleted = new AtomicBoolean(false);
+
+
+ private FlowCreditManager_0_10 _creditManager;
+
+
+ private StateListener _stateListener = new StateListener()
+ {
+
+ public void stateChange(Subscription sub, State oldState, State newState)
+ {
+
+ }
+ };
+ private AMQQueue _queue;
+ private final String _destination;
+ private boolean _noLocal;
+ private final FilterManager _filters;
+ private final MessageAcceptMode _acceptMode;
+ private final MessageAcquireMode _acquireMode;
+ private MessageFlowMode _flowMode;
+ private final ServerSession _session;
+ private AtomicBoolean _stopped = new AtomicBoolean(true);
+ private ConcurrentHashMap<Integer, QueueEntry> _sentMap = new ConcurrentHashMap<Integer, QueueEntry>();
+ private static final Struct[] EMPTY_STRUCT_ARRAY = new Struct[0];
+
+ private LogSubject _logSubject;
+ private LogActor _logActor;
+ private Map<String, Object> _properties = new ConcurrentHashMap<String, Object>();
+
+
+ public Subscription_0_10(ServerSession session, String destination, MessageAcceptMode acceptMode,
+ MessageAcquireMode acquireMode,
+ MessageFlowMode flowMode,
+ FlowCreditManager_0_10 creditManager,
+ FilterManager filters)
+ {
+ _session = session;
+ _destination = destination;
+ _acceptMode = acceptMode;
+ _acquireMode = acquireMode;
+ _creditManager = creditManager;
+ _flowMode = flowMode;
+ _filters = filters;
+ _creditManager.addStateListener(this);
+ _state.set(_creditManager.hasCredit() ? State.ACTIVE : State.SUSPENDED);
+
+
+ }
+
+ public void setNoLocal(boolean noLocal)
+ {
+ _noLocal = noLocal;
+ }
+
+ public AMQQueue getQueue()
+ {
+ return _queue;
+ }
+
+ public QueueEntry.SubscriptionAcquiredState getOwningState()
+ {
+ return _owningState;
+ }
+
+ public QueueEntry.SubscriptionAssignedState getAssignedState()
+ {
+ return _assignedState;
+ }
+
+ public void setQueue(AMQQueue queue, boolean exclusive)
+ {
+ if(getQueue() != null)
+ {
+ throw new IllegalStateException("Attempt to set queue for subscription " + this + " to " + queue + "when already set to " + getQueue());
+ }
+ _queue = queue;
+ _logSubject = new SubscriptionLogSubject(this);
+ _logActor = new SubscriptionActor(CurrentActor.get().getRootMessageLogger(), this);
+
+ }
+
+ public AMQShortString getConsumerTag()
+ {
+ return new AMQShortString(_destination);
+ }
+
+ public boolean isSuspended()
+ {
+ return !isActive() || _deleted.get(); // TODO check for Session suspension
+ }
+
+ public boolean hasInterest(QueueEntry entry)
+ {
+
+
+
+ //check that the message hasn't been rejected
+ if (entry.isRejectedBy(this))
+ {
+
+ return false;
+ }
+
+
+
+ if (_noLocal
+ && (entry.getMessage() instanceof MessageTransferMessage)
+ && ((MessageTransferMessage)entry.getMessage()).getSession() == _session)
+ {
+ return false;
+ }
+
+
+ return checkFilters(entry);
+
+
+ }
+
+ private boolean checkFilters(QueueEntry entry)
+ {
+ return (_filters == null) || _filters.allAllow(entry);
+ }
+
+ public boolean isAutoClose()
+ {
+ // no such thing in 0-10
+ return false;
+ }
+
+ public boolean isClosed()
+ {
+ return getState() == State.CLOSED;
+ }
+
+ public boolean isBrowser()
+ {
+ return _acquireMode == MessageAcquireMode.NOT_ACQUIRED;
+ }
+
+ public boolean seesRequeues()
+ {
+ return _acquireMode != MessageAcquireMode.NOT_ACQUIRED || _acceptMode == MessageAcceptMode.EXPLICIT;
+ }
+
+ public void close()
+ {
+ boolean closed = false;
+ State state = getState();
+
+ _stateChangeLock.lock();
+ try
+ {
+ while(!closed && state != State.CLOSED)
+ {
+ closed = _state.compareAndSet(state, State.CLOSED);
+ if(!closed)
+ {
+ state = getState();
+ }
+ else
+ {
+ _stateListener.stateChange(this,state, State.CLOSED);
+ }
+ }
+ _creditManager.removeListener(this);
+ }
+ finally
+ {
+ _stateChangeLock.unlock();
+ }
+
+
+
+ }
+
+ public void creditStateChanged(boolean hasCredit)
+ {
+
+ if(hasCredit)
+ {
+ if(_state.compareAndSet(State.SUSPENDED, State.ACTIVE))
+ {
+ _stateListener.stateChange(this, State.SUSPENDED, State.ACTIVE);
+ }
+ else
+ {
+ // this is a hack to get round the issue of increasing bytes credit
+ _stateListener.stateChange(this, State.ACTIVE, State.ACTIVE);
+ }
+ }
+ else
+ {
+ if(_state.compareAndSet(State.ACTIVE, State.SUSPENDED))
+ {
+ _stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED);
+ }
+ }
+ }
+
+
+ private class AddMessageDispositionListnerAction implements Runnable
+ {
+ public MessageTransfer _xfr;
+ public ServerSession.MessageDispositionChangeListener _action;
+
+ public void run()
+ {
+ _session.onMessageDispositionChange(_xfr, _action);
+ }
+ }
+
+ private final AddMessageDispositionListnerAction _postIdSettingAction = new AddMessageDispositionListnerAction();
+
+ public void send(final QueueEntry entry) throws AMQException
+ {
+ ServerMessage serverMsg = entry.getMessage();
+
+
+ MessageTransfer xfr;
+
+ if(serverMsg instanceof MessageTransferMessage)
+ {
+
+ MessageTransferMessage msg = (MessageTransferMessage) serverMsg;
+
+
+ Struct[] headers;
+ if(msg.getHeader() == null)
+ {
+ headers = EMPTY_STRUCT_ARRAY;
+ }
+ else
+ {
+ headers = msg.getHeader().getStructs();
+ }
+
+ ArrayList<Struct> newHeaders = new ArrayList<Struct>(headers.length);
+ DeliveryProperties origDeliveryProps = null;
+ for(Struct header : headers)
+ {
+ if(header instanceof DeliveryProperties)
+ {
+ origDeliveryProps = (DeliveryProperties) header;
+ }
+ else
+ {
+ newHeaders.add(header);
+ }
+ }
+
+ DeliveryProperties deliveryProps = new DeliveryProperties();
+ if(origDeliveryProps != null)
+ {
+ if(origDeliveryProps.hasDeliveryMode())
+ {
+ deliveryProps.setDeliveryMode(origDeliveryProps.getDeliveryMode());
+ }
+ if(origDeliveryProps.hasExchange())
+ {
+ deliveryProps.setExchange(origDeliveryProps.getExchange());
+ }
+ if(origDeliveryProps.hasExpiration())
+ {
+ deliveryProps.setExpiration(origDeliveryProps.getExpiration());
+ }
+ if(origDeliveryProps.hasPriority())
+ {
+ deliveryProps.setPriority(origDeliveryProps.getPriority());
+ }
+ if(origDeliveryProps.hasRoutingKey())
+ {
+ deliveryProps.setRoutingKey(origDeliveryProps.getRoutingKey());
+ }
+
+ }
+
+ deliveryProps.setRedelivered(entry.isRedelivered());
+
+ newHeaders.add(deliveryProps);
+ Header header = new Header(newHeaders);
+
+ xfr = new MessageTransfer(_destination,_acceptMode,_acquireMode,header,msg.getBody());
+ }
+ else
+ {
+ AMQMessage message_0_8 = (AMQMessage) serverMsg;
+ DeliveryProperties deliveryProps = new DeliveryProperties();
+ MessageProperties messageProps = new MessageProperties();
+
+ int size = (int) message_0_8.getSize();
+ ByteBuffer body = ByteBuffer.allocate(size);
+ message_0_8.getContent(body, 0);
+ body.flip();
+
+ Struct[] headers = new Struct[] { deliveryProps, messageProps };
+
+ BasicContentHeaderProperties properties =
+ (BasicContentHeaderProperties) message_0_8.getContentHeaderBody().properties;
+ final AMQShortString exchange = message_0_8.getMessagePublishInfo().getExchange();
+ if(exchange != null)
+ {
+ deliveryProps.setExchange(exchange.toString());
+ }
+ deliveryProps.setExpiration(message_0_8.getExpiration());
+ deliveryProps.setImmediate(message_0_8.isImmediate());
+ deliveryProps.setPriority(MessageDeliveryPriority.get(properties.getPriority()));
+ deliveryProps.setRedelivered(entry.isRedelivered());
+ deliveryProps.setRoutingKey(message_0_8.getRoutingKey());
+ deliveryProps.setTimestamp(properties.getTimestamp());
+
+ messageProps.setContentEncoding(properties.getEncodingAsString());
+ messageProps.setContentLength(size);
+ if(properties.getAppId() != null)
+ {
+ messageProps.setAppId(properties.getAppId().getBytes());
+ }
+ messageProps.setContentType(properties.getContentTypeAsString());
+ if(properties.getCorrelationId() != null)
+ {
+ messageProps.setCorrelationId(properties.getCorrelationId().getBytes());
+ }
+
+ // TODO - ReplyTo
+
+ if(properties.getUserId() != null)
+ {
+ messageProps.setUserId(properties.getUserId().getBytes());
+ }
+
+ final Map<String, Object> appHeaders = new HashMap<String, Object>();
+
+ properties.getHeaders().processOverElements(
+ new FieldTable.FieldTableElementProcessor()
+ {
+
+ public boolean processElement(String propertyName, AMQTypedValue value)
+ {
+ Object val = value.getValue();
+ if(val instanceof AMQShortString)
+ {
+ val = val.toString();
+ }
+ appHeaders.put(propertyName, val);
+ return true;
+ }
+
+ public Object getResult()
+ {
+ return appHeaders;
+ }
+ });
+
+
+ messageProps.setApplicationHeaders(appHeaders);
+
+ Header header = new Header(headers);
+ xfr = new MessageTransfer(_destination,_acceptMode,_acquireMode,header, body);
+ }
+
+ if(_acceptMode == MessageAcceptMode.NONE)
+ {
+ xfr.setCompletionListener(new MessageAcceptCompletionListener(this, _session, entry, _flowMode == MessageFlowMode.WINDOW));
+ }
+ else if(_flowMode == MessageFlowMode.WINDOW)
+ {
+ xfr.setCompletionListener(new Method.CompletionListener()
+ {
+ public void onComplete(Method method)
+ {
+ restoreCredit(entry);
+ }
+ });
+ }
+
+
+ _postIdSettingAction._xfr = xfr;
+ if(_acceptMode == MessageAcceptMode.EXPLICIT)
+ {
+ _postIdSettingAction._action = new ExplicitAcceptDispositionChangeListener(entry, this);
+ }
+ else
+ {
+ _postIdSettingAction._action = new ImplicitAcceptDispositionChangeListener(entry, this);
+ }
+
+ _session.sendMessage(xfr, _postIdSettingAction);
+
+ }
+
+ void reject(QueueEntry entry)
+ {
+ entry.setRedelivered();
+ entry.routeToAlternate();
+
+ }
+
+ void release(QueueEntry entry)
+ {
+ entry.setRedelivered();
+ entry.release();
+ }
+
+ public void queueDeleted(AMQQueue queue)
+ {
+ _deleted.set(true);
+ }
+
+ public boolean wouldSuspend(QueueEntry msg)
+ {
+ return !_creditManager.useCreditForMessage(msg.getMessage());
+ }
+
+ public void getSendLock()
+ {
+ _stateChangeLock.lock();
+ }
+
+ public void releaseSendLock()
+ {
+ _stateChangeLock.unlock();
+ }
+
+ public void restoreCredit(QueueEntry queueEntry)
+ {
+ _creditManager.restoreCredit(1, queueEntry.getSize());
+ }
+
+ public void onDequeue(QueueEntry queueEntry)
+ {
+
+ }
+
+ public void setStateListener(StateListener listener)
+ {
+ _stateListener = listener;
+ }
+
+ public State getState()
+ {
+ return _state.get();
+ }
+
+ public AMQQueue.Context getQueueContext()
+ {
+ return _queueContext;
+ }
+
+ public void setQueueContext(AMQQueue.Context queueContext)
+ {
+ _queueContext = queueContext;
+ }
+
+ public boolean isActive()
+ {
+ return getState() == State.ACTIVE;
+ }
+
+ public void confirmAutoClose()
+ {
+ //No such thing in 0-10
+ }
+
+ public void set(String key, Object value)
+ {
+ _properties.put(key, value);
+ }
+
+ public Object get(String key)
+ {
+ return _properties.get(key);
+ }
+
+
+ public FlowCreditManager_0_10 getCreditManager()
+ {
+ return _creditManager;
+ }
+
+
+ public void stop()
+ {
+ if(_state.compareAndSet(State.ACTIVE, State.SUSPENDED))
+ {
+ _stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED);
+ }
+ _stopped.set(true);
+ FlowCreditManager_0_10 creditManager = getCreditManager();
+ creditManager.clearCredit();
+ }
+
+ public void addCredit(MessageCreditUnit unit, long value)
+ {
+ FlowCreditManager_0_10 creditManager = getCreditManager();
+
+ switch (unit)
+ {
+ case MESSAGE:
+
+ creditManager.addCredit(value, 0L);
+ break;
+ case BYTE:
+ creditManager.addCredit(0l, value);
+ break;
+ }
+
+ _stopped.set(false);
+
+ if(creditManager.hasCredit())
+ {
+ if(_state.compareAndSet(State.SUSPENDED, State.ACTIVE))
+ {
+ _stateListener.stateChange(this, State.SUSPENDED, State.ACTIVE);
+ }
+ }
+
+ }
+
+ public void setFlowMode(MessageFlowMode flowMode)
+ {
+
+
+ _creditManager.removeListener(this);
+
+ switch(flowMode)
+ {
+ case CREDIT:
+ _creditManager = new CreditCreditManager(0l,0l);
+ break;
+ case WINDOW:
+ _creditManager = new WindowCreditManager(0l,0l);
+ break;
+ default:
+ throw new RuntimeException("Unknown message flow mode: " + flowMode);
+ }
+ _flowMode = flowMode;
+ if(_state.compareAndSet(State.ACTIVE, State.SUSPENDED))
+ {
+ _stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED);
+ }
+
+ _creditManager.addStateListener(this);
+
+ }
+
+ public boolean isStopped()
+ {
+ return _stopped.get();
+ }
+
+ public boolean acquires()
+ {
+ return _acquireMode == MessageAcquireMode.PRE_ACQUIRED;
+ }
+
+ public void acknowledge(QueueEntry entry)
+ {
+ // TODO Fix Store Context / cleanup
+ if(entry.isAcquiredBy(this))
+ {
+ entry.discard();
+ }
+ }
+
+ public void flush() throws AMQException
+ {
+ _queue.flushSubscription(this);
+ stop();
+ }
+
+ public long getSubscriptionID()
+ {
+ return _subscriptionID;
+ }
+
+ public LogActor getLogActor()
+ {
+ return _logActor;
+ }
+
+ public boolean isTransient()
+ {
+ return false;
+ }
+
+ ServerSession getSession()
+ {
+ return _session;
+ }
+
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java b/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java
deleted file mode 100644
index b67bb98e28..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java
+++ /dev/null
@@ -1,118 +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.
- *
- */
-package org.apache.qpid.server.transport;
-
-import org.apache.mina.common.IoAcceptor;
-import org.apache.mina.util.NewThreadExecutor;
-import org.apache.qpid.configuration.Configured;
-import org.apache.log4j.Logger;
-
-public class ConnectorConfiguration
-{
- private static final Logger _logger = Logger.getLogger(ConnectorConfiguration.class);
-
- public static final String DEFAULT_PORT = "5672";
-
- public static final String SSL_PORT = "8672";
-
- @Configured(path = "connector.processors",
- defaultValue = "4")
- public int processors;
-
- @Configured(path = "connector.port",
- defaultValue = DEFAULT_PORT)
- public int port;
-
- @Configured(path = "connector.bind",
- defaultValue = "wildcard")
- public String bindAddress;
-
- @Configured(path = "connector.socketReceiveBuffer",
- defaultValue = "32767")
- public int socketReceiveBufferSize;
-
- @Configured(path = "connector.socketWriteBuffer",
- defaultValue = "32767")
- public int socketWriteBuferSize;
-
- @Configured(path = "connector.tcpNoDelay",
- defaultValue = "true")
- public boolean tcpNoDelay;
-
- @Configured(path = "advanced.filterchain[@enableExecutorPool]",
- defaultValue = "false")
- public boolean enableExecutorPool;
-
- @Configured(path = "advanced.enablePooledAllocator",
- defaultValue = "false")
- public boolean enablePooledAllocator;
-
- @Configured(path = "advanced.enableDirectBuffers",
- defaultValue = "false")
- public boolean enableDirectBuffers;
-
- @Configured(path = "connector.ssl.enabled",
- defaultValue = "false")
- public boolean enableSSL;
-
- @Configured(path = "connector.ssl.sslOnly",
- defaultValue = "true")
- public boolean sslOnly;
-
- @Configured(path = "connector.ssl.port",
- defaultValue = SSL_PORT)
- public int sslPort;
-
- @Configured(path = "connector.ssl.keystorePath",
- defaultValue = "none")
- public String keystorePath;
-
- @Configured(path = "connector.ssl.keystorePassword",
- defaultValue = "none")
- public String keystorePassword;
-
- @Configured(path = "connector.ssl.certType",
- defaultValue = "SunX509")
- public String certType;
-
- @Configured(path = "connector.qpidnio",
- defaultValue = "false")
- public boolean _multiThreadNIO;
-
- @Configured(path = "advanced.useWriteBiasedPool",
- defaultValue = "false")
- public boolean useBiasedWrites;
-
-
- public IoAcceptor createAcceptor()
- {
- if (_multiThreadNIO)
- {
- _logger.warn("Using Qpid Multithreaded IO Processing");
- return new org.apache.mina.transport.socket.nio.MultiThreadSocketAcceptor(processors, new NewThreadExecutor());
- }
- else
- {
- _logger.warn("Using Mina IO Processing");
- return new org.apache.mina.transport.socket.nio.SocketAcceptor(processors, new NewThreadExecutor());
- }
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/transport/QpidAcceptor.java b/java/broker/src/main/java/org/apache/qpid/server/transport/QpidAcceptor.java
new file mode 100644
index 0000000000..3ca22b60c8
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/transport/QpidAcceptor.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.transport;
+
+import org.apache.qpid.transport.NetworkDriver;
+
+public class QpidAcceptor
+{
+ NetworkDriver _driver;
+ String _protocol;
+ public QpidAcceptor(NetworkDriver driver, String protocol)
+ {
+ _driver = driver;
+ _protocol = protocol;
+ }
+
+ public NetworkDriver getNetworkDriver()
+ {
+ return _driver;
+ }
+
+ public String toString()
+ {
+ return _protocol;
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java
new file mode 100644
index 0000000000..2a8b99ddac
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java
@@ -0,0 +1,64 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.transport;
+
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.Method;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+public class ServerConnection extends Connection
+{
+ @Override
+ protected void invoke(Method method)
+ {
+ super.invoke(method);
+ }
+
+ @Override
+ protected void setState(State state)
+ {
+ super.setState(state);
+ }
+
+ @Override
+ public ServerConnectionDelegate getConnectionDelegate()
+ {
+ return (ServerConnectionDelegate) super.getConnectionDelegate();
+ }
+
+ public void setConnectionDelegate(ServerConnectionDelegate delegate)
+ {
+ super.setConnectionDelegate(delegate);
+ }
+
+ private VirtualHost _virtualHost;
+
+
+ public VirtualHost getVirtualHost()
+ {
+ return _virtualHost;
+ }
+
+ public void setVirtualHost(VirtualHost virtualHost)
+ {
+ _virtualHost = virtualHost;
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java b/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java
new file mode 100644
index 0000000000..cfc5bb3a72
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java
@@ -0,0 +1,120 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.transport;
+
+import org.apache.qpid.transport.*;
+
+import org.apache.qpid.server.registry.IApplicationRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+import javax.security.sasl.SaslServer;
+import javax.security.sasl.SaslException;
+import java.util.*;
+
+
+public class ServerConnectionDelegate extends ServerDelegate
+{
+
+ private String _localFQDN;
+ private final IApplicationRegistry _appRegistry;
+
+
+ public ServerConnectionDelegate(IApplicationRegistry appRegistry,
+ String localFQDN)
+ {
+ this(Collections.EMPTY_MAP, Collections.singletonList((Object)"en_US"), appRegistry, localFQDN);
+ }
+
+
+ public ServerConnectionDelegate(Map<String, Object> properties,
+ List<Object> locales,
+ IApplicationRegistry appRegistry,
+ String localFQDN)
+ {
+ super(properties, parseToList(appRegistry.getAuthenticationManager().getMechanisms()), locales);
+ _appRegistry = appRegistry;
+ _localFQDN = localFQDN;
+ }
+
+ private static List<Object> parseToList(String mechanisms)
+ {
+ List<Object> list = new ArrayList<Object>();
+ StringTokenizer tokenizer = new StringTokenizer(mechanisms, " ");
+ while(tokenizer.hasMoreTokens())
+ {
+ list.add(tokenizer.nextToken());
+ }
+ return list;
+ }
+
+ @Override public ServerSession getSession(Connection conn, SessionAttach atc)
+ {
+
+ SessionDelegate serverSessionDelegate = new ServerSessionDelegate(_appRegistry);
+
+ ServerSession ssn = new ServerSession(conn, serverSessionDelegate, new Binary(atc.getName()), 0);
+ //ssn.setSessionListener(new Echo());
+ return ssn;
+ }
+
+
+
+
+ @Override
+ protected SaslServer createSaslServer(String mechanism) throws SaslException
+ {
+ return _appRegistry.getAuthenticationManager().createSaslServer(mechanism, _localFQDN);
+
+ }
+
+
+ @Override public void connectionOpen(Connection conn, ConnectionOpen open)
+ {
+ ServerConnection sconn = (ServerConnection) conn;
+
+ VirtualHost vhost;
+ String vhostName;
+ if(open.hasVirtualHost())
+ {
+ vhostName = open.getVirtualHost();
+ }
+ else
+ {
+ vhostName = "";
+ }
+ vhost = _appRegistry.getVirtualHostRegistry().getVirtualHost(vhostName);
+
+ if(vhost != null)
+ {
+ sconn.setVirtualHost(vhost);
+
+ sconn.invoke(new ConnectionOpenOk(Collections.EMPTY_LIST));
+
+ sconn.setState(Connection.State.OPEN);
+ }
+ else
+ {
+ sconn.invoke(new ConnectionClose(ConnectionCloseCode.INVALID_PATH, "Unknown vistrulhost '"+vhostName+"'"));
+ sconn.setState(Connection.State.CLOSING);
+ }
+
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java
new file mode 100644
index 0000000000..77dfbc0376
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java
@@ -0,0 +1,398 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.transport;
+
+import org.apache.qpid.transport.*;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.subscription.Subscription_0_10;
+import org.apache.qpid.server.txn.ServerTransaction;
+import org.apache.qpid.server.txn.AutoCommitTransaction;
+import org.apache.qpid.server.txn.LocalTransaction;
+import org.apache.qpid.server.security.PrincipalHolder;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.AMQException;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ConcurrentHashMap;
+import java.security.Principal;
+import java.lang.ref.WeakReference;
+
+import static org.apache.qpid.util.Serial.*;
+import com.sun.security.auth.UserPrincipal;
+
+public class ServerSession extends Session implements PrincipalHolder
+{
+ private static final String NULL_DESTINTATION = UUID.randomUUID().toString();
+
+ public static interface MessageDispositionChangeListener
+ {
+ public void onAccept();
+
+ public void onRelease();
+
+ public void onReject();
+
+ public boolean acquire();
+
+
+ }
+
+ public static interface Task
+ {
+ public void doTask(ServerSession session);
+ }
+
+
+ private final SortedMap<Integer, MessageDispositionChangeListener> _messageDispositionListenerMap =
+ new ConcurrentSkipListMap<Integer, MessageDispositionChangeListener>();
+
+ private ServerTransaction _transaction;
+
+ private Principal _principal;
+
+ private Map<String, Subscription_0_10> _subscriptions = new ConcurrentHashMap<String, Subscription_0_10>();
+
+ private final List<Task> _taskList = new CopyOnWriteArrayList<Task>();
+
+ private final WeakReference<Session> _reference;
+
+
+ ServerSession(Connection connection, Binary name, long expiry)
+ {
+ super(connection, name, expiry);
+
+ _transaction = new AutoCommitTransaction(this.getMessageStore());
+ _principal = new UserPrincipal(connection.getAuthorizationID());
+ _reference = new WeakReference(this);
+ }
+
+ ServerSession(Connection connection, SessionDelegate delegate, Binary name, long expiry)
+ {
+ super(connection, delegate, name, expiry);
+ _transaction = new AutoCommitTransaction(this.getMessageStore());
+ _principal = new UserPrincipal(connection.getAuthorizationID());
+ _reference = new WeakReference(this);
+ }
+
+ @Override
+ protected boolean isFull(int id)
+ {
+ return isCommandsFull(id);
+ }
+
+ public void enqueue(final ServerMessage message, final ArrayList<AMQQueue> queues)
+ {
+
+ _transaction.enqueue(queues,message, new ServerTransaction.Action()
+ {
+
+ AMQQueue[] _queues = queues.toArray(new AMQQueue[queues.size()]);
+
+ public void postCommit()
+ {
+ for(int i = 0; i < _queues.length; i++)
+ {
+ try
+ {
+ _queues[i].enqueue(message);
+ }
+ catch (AMQException e)
+ {
+ // TODO
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ public void onRollback()
+ {
+ // NO-OP
+ }
+ });
+
+
+ }
+
+
+ public void sendMessage(MessageTransfer xfr,
+ Runnable postIdSettingAction)
+ {
+ invoke(xfr, postIdSettingAction);
+ }
+
+ public void onMessageDispositionChange(MessageTransfer xfr, MessageDispositionChangeListener acceptListener)
+ {
+ _messageDispositionListenerMap.put(xfr.getId(), acceptListener);
+ }
+
+
+ private static interface MessageDispositionAction
+ {
+ void performAction(MessageDispositionChangeListener listener);
+ }
+
+ public void accept(RangeSet ranges)
+ {
+ dispositionChange(ranges, new MessageDispositionAction()
+ {
+ public void performAction(MessageDispositionChangeListener listener)
+ {
+ listener.onAccept();
+ }
+ });
+ }
+
+
+ public void release(RangeSet ranges)
+ {
+ dispositionChange(ranges, new MessageDispositionAction()
+ {
+ public void performAction(MessageDispositionChangeListener listener)
+ {
+ listener.onRelease();
+ }
+ });
+ }
+
+ public void reject(RangeSet ranges)
+ {
+ dispositionChange(ranges, new MessageDispositionAction()
+ {
+ public void performAction(MessageDispositionChangeListener listener)
+ {
+ listener.onReject();
+ }
+ });
+ }
+
+ public RangeSet acquire(RangeSet transfers)
+ {
+ RangeSet acquired = new RangeSet();
+
+ if(!_messageDispositionListenerMap.isEmpty())
+ {
+ Iterator<Integer> unacceptedMessages = _messageDispositionListenerMap.keySet().iterator();
+ Iterator<Range> rangeIter = transfers.iterator();
+
+ if(rangeIter.hasNext())
+ {
+ Range range = rangeIter.next();
+
+ while(range != null && unacceptedMessages.hasNext())
+ {
+ int next = unacceptedMessages.next();
+ while(gt(next, range.getUpper()))
+ {
+ if(rangeIter.hasNext())
+ {
+ range = rangeIter.next();
+ }
+ else
+ {
+ range = null;
+ break;
+ }
+ }
+ if(range != null && range.includes(next))
+ {
+ MessageDispositionChangeListener changeListener = _messageDispositionListenerMap.get(next);
+ if(changeListener.acquire())
+ {
+ acquired.add(next);
+ }
+ }
+
+
+ }
+
+ }
+
+
+ }
+
+ return acquired;
+ }
+
+ public void dispositionChange(RangeSet ranges, MessageDispositionAction action)
+ {
+ if(ranges != null && !_messageDispositionListenerMap.isEmpty())
+ {
+ Iterator<Integer> unacceptedMessages = _messageDispositionListenerMap.keySet().iterator();
+ Iterator<Range> rangeIter = ranges.iterator();
+
+ if(rangeIter.hasNext())
+ {
+ Range range = rangeIter.next();
+
+ while(range != null && unacceptedMessages.hasNext())
+ {
+ int next = unacceptedMessages.next();
+ while(gt(next, range.getUpper()))
+ {
+ if(rangeIter.hasNext())
+ {
+ range = rangeIter.next();
+ }
+ else
+ {
+ range = null;
+ break;
+ }
+ }
+ if(range != null && range.includes(next))
+ {
+ MessageDispositionChangeListener changeListener = _messageDispositionListenerMap.remove(next);
+ action.performAction(changeListener);
+ }
+
+
+ }
+
+ }
+
+ }
+ }
+
+ public void removeDispositionListener(Method method)
+ {
+ _messageDispositionListenerMap.remove(method.getId());
+ }
+
+ public void onClose()
+ {
+ _transaction.rollback();
+ for(MessageDispositionChangeListener listener : _messageDispositionListenerMap.values())
+ {
+ listener.onRelease();
+ }
+ _messageDispositionListenerMap.clear();
+
+ for (Task task : _taskList)
+ {
+ task.doTask(this);
+ }
+
+ }
+
+ public void acknowledge(final Subscription_0_10 sub, final QueueEntry entry)
+ {
+ _transaction.dequeue(entry.getQueue(), entry.getMessage(),
+ new ServerTransaction.Action()
+ {
+
+ public void postCommit()
+ {
+ sub.acknowledge(entry);
+ }
+
+ public void onRollback()
+ {
+ entry.release();
+ }
+ });
+ }
+
+ public Collection<Subscription_0_10> getSubscriptions()
+ {
+ return _subscriptions.values();
+ }
+
+ public void register(String destination, Subscription_0_10 sub)
+ {
+ _subscriptions.put(destination == null ? NULL_DESTINTATION : destination, sub);
+ }
+
+ public Subscription_0_10 getSubscription(String destination)
+ {
+ return _subscriptions.get(destination == null ? NULL_DESTINTATION : destination);
+ }
+
+ public void unregister(Subscription_0_10 sub)
+ {
+ _subscriptions.remove(sub.getConsumerTag().toString());
+ try
+ {
+ sub.getSendLock();
+ AMQQueue queue = sub.getQueue();
+ if(queue != null)
+ {
+ queue.unregisterSubscription(sub);
+ }
+
+ }
+ catch (AMQException e)
+ {
+ // TODO
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ }
+ finally
+ {
+ sub.releaseSendLock();
+ }
+ }
+
+ public void selectTx()
+ {
+ _transaction = new LocalTransaction(this.getMessageStore());
+ }
+
+ public void commit()
+ {
+ _transaction.commit();
+ }
+
+ public void rollback()
+ {
+ _transaction.rollback();
+ }
+
+ public Principal getPrincipal()
+ {
+ return _principal;
+ }
+
+ public void addSessionCloseTask(Task task)
+ {
+ _taskList.add(task);
+ }
+
+ public void removeSessionCloseTask(Task task)
+ {
+ _taskList.remove(task);
+ }
+
+ public WeakReference<Session> getReference()
+ {
+ return _reference;
+ }
+
+ public MessageStore getMessageStore()
+ {
+ return ((ServerConnection)getConnection()).getVirtualHost().getMessageStore();
+ }
+
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java
new file mode 100644
index 0000000000..36ed8e24ce
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java
@@ -0,0 +1,1198 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.transport;
+
+import org.apache.qpid.transport.*;
+import org.apache.qpid.server.registry.IApplicationRegistry;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.exchange.*;
+import org.apache.qpid.server.queue.QueueRegistry;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.AMQQueueFactory;
+import org.apache.qpid.server.message.MessageTransferMessage;
+import org.apache.qpid.server.message.MessageMetaData_0_10;
+import org.apache.qpid.server.subscription.Subscription_0_10;
+import org.apache.qpid.server.flow.*;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.StoredMessage;
+import org.apache.qpid.server.store.DurableConfigurationStore;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQUnknownExchangeType;
+import org.apache.qpid.framing.*;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+public class ServerSessionDelegate extends SessionDelegate
+{
+ private final IApplicationRegistry _appRegistry;
+
+ public ServerSessionDelegate(IApplicationRegistry appRegistry)
+ {
+ _appRegistry = appRegistry;
+ }
+
+ @Override
+ public void command(Session session, Method method)
+ {
+ super.command(session, method);
+ if (method.isSync())
+ {
+ session.flushProcessed();
+ }
+ }
+
+ @Override
+ public void messageAccept(Session session, MessageAccept method)
+ {
+ ((ServerSession)session).accept(method.getTransfers());
+ }
+
+
+
+ @Override
+ public void messageReject(Session session, MessageReject method)
+ {
+ ((ServerSession)session).reject(method.getTransfers());
+ }
+
+ @Override
+ public void messageRelease(Session session, MessageRelease method)
+ {
+ ((ServerSession)session).release(method.getTransfers());
+ }
+
+ @Override
+ public void messageAcquire(Session session, MessageAcquire method)
+ {
+ RangeSet acquiredRanges = ((ServerSession)session).acquire(method.getTransfers());
+
+ Acquired result = new Acquired(acquiredRanges);
+
+
+ session.executionResult((int) method.getId(), result);
+
+
+ }
+
+ @Override
+ public void messageResume(Session session, MessageResume method)
+ {
+ super.messageResume(session, method);
+ }
+
+ @Override
+ public void messageSubscribe(Session session, MessageSubscribe method)
+ {
+
+ //TODO - work around broken Python tests
+ if(!method.hasAcceptMode())
+ {
+ method.setAcceptMode(MessageAcceptMode.EXPLICIT);
+ }
+ if(!method.hasAcquireMode())
+ {
+ method.setAcquireMode(MessageAcquireMode.PRE_ACQUIRED);
+
+ }
+
+ /* if(!method.hasAcceptMode())
+ {
+ exception(session,method,ExecutionErrorCode.ILLEGAL_ARGUMENT, "Accept-mode not supplied");
+ }
+ else if(!method.hasAcquireMode())
+ {
+ exception(session,method,ExecutionErrorCode.ILLEGAL_ARGUMENT, "Acquire-mode not supplied");
+ }
+ else */if(!method.hasQueue())
+ {
+ exception(session,method,ExecutionErrorCode.ILLEGAL_ARGUMENT, "queue not supplied");
+ }
+ else
+ {
+ String destination = method.getDestination();
+
+ if(((ServerSession)session).getSubscription(destination)!=null)
+ {
+ exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Subscription already exists with destaination: '"+destination+"'");
+ }
+ else
+ {
+ String queueName = method.getQueue();
+ QueueRegistry queueRegistry = getQueueRegistry(session);
+
+
+ AMQQueue queue = queueRegistry.getQueue(queueName);
+
+ if(queue == null)
+ {
+ exception(session,method,ExecutionErrorCode.NOT_FOUND, "Queue: " + queueName + " not found");
+ }
+ else if(queue.getPrincipalHolder() != null && queue.getPrincipalHolder() != session)
+ {
+ exception(session,method,ExecutionErrorCode.RESOURCE_LOCKED, "Exclusive Queue: " + queueName + " owned exclusively by another session");
+ }
+ else
+ {
+
+ FlowCreditManager_0_10 creditManager = new WindowCreditManager(0L,0L);
+
+ // TODO filters
+
+ Subscription_0_10 sub = new Subscription_0_10((ServerSession)session,
+ destination,
+ method.getAcceptMode(),
+ method.getAcquireMode(),
+ MessageFlowMode.WINDOW,
+ creditManager, null);
+
+ ((ServerSession)session).register(destination, sub);
+ try
+ {
+ queue.registerSubscription(sub, method.getExclusive());
+ }
+ catch (AMQQueue.ExistingExclusiveSubscription existing)
+ {
+ exception(session, method, ExecutionErrorCode.RESOURCE_LOCKED, "Queue has an exclusive consumer");
+ }
+ catch (AMQQueue.ExistingSubscriptionPreventsExclusive exclusive)
+ {
+ exception(session, method, ExecutionErrorCode.RESOURCE_LOCKED, "Queue has an existing consumer - can't subscribe exclusively");
+ }
+ catch (AMQException e)
+ {
+ // TODO
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ }
+ }
+
+
+ @Override
+ public void messageTransfer(Session ssn, MessageTransfer xfr)
+ {
+ ExchangeRegistry exchangeRegistry = getExchangeRegistry(ssn);
+ Exchange exchange;
+ if(xfr.hasDestination())
+ {
+ exchange = exchangeRegistry.getExchange(xfr.getDestination());
+ if(exchange == null)
+ {
+ exchange = exchangeRegistry.getDefaultExchange();
+ }
+ }
+ else
+ {
+ exchange = exchangeRegistry.getDefaultExchange();
+ }
+
+
+ DeliveryProperties delvProps = null;
+ if(xfr.getHeader() != null && (delvProps = xfr.getHeader().get(DeliveryProperties.class)) != null && delvProps.hasTtl() && !delvProps.hasExpiration())
+ {
+ delvProps.setExpiration(System.currentTimeMillis() + delvProps.getTtl());
+ }
+
+ MessageMetaData_0_10 messageMetaData = new MessageMetaData_0_10(xfr);
+ final MessageStore store = getVirtualHost(ssn).getMessageStore();
+ StoredMessage<MessageMetaData_0_10> storeMessage = store.addMessage(messageMetaData);
+ storeMessage.addContent(0,xfr.getBody());
+ storeMessage.flushToStore();
+ MessageTransferMessage message = new MessageTransferMessage(storeMessage, ((ServerSession)ssn).getReference());
+
+ ArrayList<AMQQueue> queues = exchange.route(message);
+
+
+
+ if(queues != null && queues.size() != 0)
+ {
+ ((ServerSession) ssn).enqueue(message, queues);
+ }
+ else
+ {
+ if(delvProps == null || !delvProps.hasDiscardUnroutable() || !delvProps.getDiscardUnroutable())
+ {
+ if(xfr.getAcceptMode() == MessageAcceptMode.EXPLICIT)
+ {
+ RangeSet rejects = new RangeSet();
+ rejects.add(xfr.getId());
+ MessageReject reject = new MessageReject(rejects, MessageRejectCode.UNROUTABLE, "Unroutable");
+ ssn.invoke(reject);
+ }
+ else
+ {
+ Exchange alternate = exchange.getAlternateExchange();
+ if(alternate != null)
+ {
+ queues = alternate.route(message);
+ if(queues != null && queues.size() != 0)
+ {
+ ((ServerSession) ssn).enqueue(message, queues);
+ }
+ else
+ {
+ //TODO - log the message discard
+ }
+ }
+ else
+ {
+ //TODO - log the message discard
+ }
+
+
+ }
+ }
+
+
+ }
+
+ ssn.processed(xfr);
+
+ }
+
+ @Override
+ public void messageCancel(Session session, MessageCancel method)
+ {
+ String destination = method.getDestination();
+
+ Subscription_0_10 sub = ((ServerSession)session).getSubscription(destination);
+
+ if(sub == null)
+ {
+ exception(session, method, ExecutionErrorCode.NOT_FOUND, "not-found: destination '"+destination+"'");
+ }
+ else
+ {
+ ((ServerSession)session).unregister(sub);
+ }
+ }
+
+ @Override
+ public void messageFlush(Session session, MessageFlush method)
+ {
+ String destination = method.getDestination();
+
+ Subscription_0_10 sub = ((ServerSession)session).getSubscription(destination);
+
+ if(sub == null)
+ {
+ exception(session, method, ExecutionErrorCode.NOT_FOUND, "not-found: destination '"+destination+"'");
+ }
+ else
+ {
+
+ try
+ {
+ sub.flush();
+ }
+ catch (AMQException e)
+ {
+ //TODO
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ @Override
+ public void txSelect(Session session, TxSelect method)
+ {
+ // TODO - check current tx mode
+ ((ServerSession)session).selectTx();
+ }
+
+ @Override
+ public void txCommit(Session session, TxCommit method)
+ {
+ // TODO - check current tx mode
+ ((ServerSession)session).commit();
+ }
+
+ @Override
+ public void txRollback(Session session, TxRollback method)
+ {
+ // TODO - check current tx mode
+ ((ServerSession)session).rollback();
+ }
+
+
+ @Override
+ public void exchangeDeclare(Session session, ExchangeDeclare method)
+ {
+ String exchangeName = method.getExchange();
+ VirtualHost virtualHost = getVirtualHost(session);
+ Exchange exchange = getExchange(session, exchangeName);
+
+ if(method.getPassive())
+ {
+ if(exchange == null)
+ {
+ exception(session, method, ExecutionErrorCode.NOT_FOUND, "not-found: exchange-name '"+exchangeName+"'");
+
+ }
+ else
+ {
+ // TODO - check exchange has same properties
+ if(!exchange.getType().toString().equals(method.getType()))
+ {
+ exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Cannot redeclare with a different exchange type");
+ }
+ }
+
+ }
+ else
+ {
+ if (!virtualHost.getAccessManager().authoriseCreateExchange((ServerSession)session, method.getAutoDelete(),
+ method.getDurable(), new AMQShortString(method.getExchange()), false, false, method.getPassive(),
+ new AMQShortString(method.getType())))
+ {
+
+ ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_ALLOWED;
+ String description = "permission denied: exchange-name '" + exchangeName + "'";
+
+ exception(session, method, errorCode, description);
+
+
+ }
+ else if(exchange == null)
+ {
+ ExchangeRegistry exchangeRegistry = getExchangeRegistry(session);
+ ExchangeFactory exchangeFactory = virtualHost.getExchangeFactory();
+
+
+
+ try
+ {
+
+ exchange = exchangeFactory.createExchange(method.getExchange(),
+ method.getType(),
+ method.getDurable(),
+ method.getAutoDelete());
+
+ String alternateExchangeName = method.getAlternateExchange();
+ if(alternateExchangeName != null && alternateExchangeName.length() != 0)
+ {
+ Exchange alternate = getExchange(session, alternateExchangeName);
+ exchange.setAlternateExchange(alternate);
+ }
+
+ if (exchange.isDurable() && !exchange.isAutoDelete())
+ {
+ DurableConfigurationStore store = virtualHost.getDurableConfigurationStore();
+ store.createExchange(exchange);
+ }
+
+ exchangeRegistry.registerExchange(exchange);
+ }
+ catch(AMQUnknownExchangeType e)
+ {
+ exception(session, method, ExecutionErrorCode.NOT_FOUND, "Unknown Exchange Type: " + method.getType());
+ }
+ catch (AMQException e)
+ {
+ //TODO
+ throw new RuntimeException(e);
+ }
+
+ }
+ else
+ {
+ if(!exchange.getType().toString().equals(method.getType()))
+ {
+ exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Cannot redeclare with a different exchange type");
+ }
+ }
+
+ }
+ }
+
+ private void exception(Session session, Method method, ExecutionErrorCode errorCode, String description)
+ {
+ ExecutionException ex = new ExecutionException();
+ ex.setErrorCode(errorCode);
+ ex.setCommandId(method.getId());
+ ex.setDescription(description);
+
+ session.invoke(ex);
+
+ }
+
+ private Exchange getExchange(Session session, String exchangeName)
+ {
+ ExchangeRegistry exchangeRegistry = getExchangeRegistry(session);
+ return exchangeRegistry.getExchange(exchangeName);
+ }
+
+ private ExchangeRegistry getExchangeRegistry(Session session)
+ {
+ VirtualHost virtualHost = getVirtualHost(session);
+ return virtualHost.getExchangeRegistry();
+
+ }
+
+ private VirtualHost getVirtualHost(Session session)
+ {
+ ServerConnection conn = getServerConnection(session);
+ VirtualHost vhost = conn.getVirtualHost();
+ return vhost;
+ }
+
+ private ServerConnection getServerConnection(Session session)
+ {
+ ServerConnection conn = (ServerConnection) session.getConnection();
+ return conn;
+ }
+
+ @Override
+ public void exchangeDelete(Session session, ExchangeDelete method)
+ {
+ VirtualHost virtualHost = getVirtualHost(session);
+ ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry();
+
+ //Perform ACLs
+ if (!virtualHost.getAccessManager().authoriseDelete((ServerSession)session,
+ exchangeRegistry.getExchange(method.getExchange())))
+ {
+ exception(session,method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied");
+
+ }
+ else
+ {
+
+ try
+ {
+ Exchange exchange = getExchange(session, method.getExchange());
+
+ if(exchange != null && exchange.hasReferrers())
+ {
+ exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Exchange in use as an alternate exchange");
+ }
+ else
+ {
+ exchangeRegistry.unregisterExchange(method.getExchange(), method.getIfUnused());
+
+ if (exchange.isDurable() && !exchange.isAutoDelete())
+ {
+ DurableConfigurationStore store = virtualHost.getDurableConfigurationStore();
+ store.removeExchange(exchange);
+ }
+
+ }
+ }
+ catch (ExchangeInUseException e)
+ {
+ exception(session, method, ExecutionErrorCode.PRECONDITION_FAILED, "Exchange in use");
+ }
+ catch (AMQException e)
+ {
+ // TODO
+ throw new RuntimeException(e);
+ }
+ }
+
+ }
+
+ @Override
+ public void exchangeQuery(Session session, ExchangeQuery method)
+ {
+
+ ExchangeQueryResult result = new ExchangeQueryResult();
+
+ Exchange exchange = getExchange(session, method.getName());
+
+ if(exchange != null)
+ {
+ result.setDurable(exchange.isDurable());
+ result.setType(exchange.getType().toString());
+ result.setNotFound(false);
+ }
+ else
+ {
+ result.setNotFound(true);
+ }
+
+ session.executionResult((int) method.getId(), result);
+ }
+
+ @Override
+ public void exchangeBind(Session session, ExchangeBind method)
+ {
+
+ VirtualHost virtualHost = getVirtualHost(session);
+ ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry();
+ QueueRegistry queueRegistry = virtualHost.getQueueRegistry();
+
+ if (!method.hasQueue())
+ {
+ exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "queue not set");
+ }
+ else if (!method.hasExchange())
+ {
+ exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "exchange not set");
+ }
+/*
+ else if (!method.hasBindingKey())
+ {
+ exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "binding-key not set");
+ }
+*/
+ else
+ {
+ //TODO - here because of non-compiant python tests
+ if (!method.hasBindingKey())
+ {
+ method.setBindingKey(method.getQueue());
+ }
+ AMQQueue queue = queueRegistry.getQueue(method.getQueue());
+ Exchange exchange = exchangeRegistry.getExchange(method.getExchange());
+ if(queue == null)
+ {
+ exception(session, method, ExecutionErrorCode.NOT_FOUND, "Queue: '" + method.getQueue() + "' not found");
+ }
+ else if(exchange == null)
+ {
+ exception(session, method, ExecutionErrorCode.NOT_FOUND, "Exchange: '" + method.getExchange() + "' not found");
+ }
+ else if (!virtualHost.getAccessManager().authoriseBind((ServerSession)session, exchange,
+ queue, new AMQShortString(method.getBindingKey())))
+ {
+ exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Bind Exchange: '" + method.getExchange()
+ + "' to Queue: '" + method.getQueue()
+ + "' not allowed");
+ }
+ else if(exchange.getType().equals(HeadersExchange.TYPE.getName()) && (!method.hasArguments() || method.getArguments() == null || !method.getArguments().containsKey("x-match")))
+ {
+ exception(session, method, ExecutionErrorCode.INTERNAL_ERROR, "Bindings to an exchange of type " + HeadersExchange.TYPE.getName() + " require an x-match header");
+ }
+ else
+ {
+ try
+ {
+ AMQShortString routingKey = new AMQShortString(method.getBindingKey());
+ FieldTable fieldTable = FieldTable.convertToFieldTable(method.getArguments());
+
+ if (!exchange.isBound(routingKey, fieldTable, queue))
+ {
+ queue.bind(exchange, routingKey, fieldTable);
+
+ }
+ else
+ {
+ // todo
+ }
+ }
+ catch (AMQException e)
+ {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ }
+ }
+
+
+ }
+
+
+
+ }
+
+ @Override
+ public void exchangeUnbind(Session session, ExchangeUnbind method)
+ {
+ VirtualHost virtualHost = getVirtualHost(session);
+ ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry();
+ QueueRegistry queueRegistry = virtualHost.getQueueRegistry();
+
+ if (!method.hasQueue())
+ {
+ exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "queue not set");
+ }
+ else if (!method.hasExchange())
+ {
+ exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "exchange not set");
+ }
+ else if (!method.hasBindingKey())
+ {
+ exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "binding-key not set");
+ }
+ else
+ {
+ AMQQueue queue = queueRegistry.getQueue(method.getQueue());
+ Exchange exchange = exchangeRegistry.getExchange(method.getExchange());
+ if(queue == null)
+ {
+ exception(session, method, ExecutionErrorCode.NOT_FOUND, "Queue: '" + method.getQueue() + "' not found");
+ }
+ else if(exchange == null)
+ {
+ exception(session, method, ExecutionErrorCode.NOT_FOUND, "Exchange: '" + method.getExchange() + "' not found");
+ }
+ else
+ {
+ try
+ {
+ queue.unBind(exchange, new AMQShortString(method.getBindingKey()), null);
+ }
+ catch (AMQException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+
+ super.exchangeUnbind(session, method);
+ }
+
+ @Override
+ public void exchangeBound(Session session, ExchangeBound method)
+ {
+
+ ExchangeBoundResult result = new ExchangeBoundResult();
+ Exchange exchange;
+ AMQQueue queue;
+ if(method.hasExchange())
+ {
+ exchange = getExchange(session, method.getExchange());
+
+ if(exchange == null)
+ {
+ result.setExchangeNotFound(true);
+ }
+ }
+ else
+ {
+ exchange = getExchangeRegistry(session).getDefaultExchange();
+ }
+
+
+ if(method.hasQueue())
+ {
+
+ queue = getQueue(session, method.getQueue());
+ if(queue == null)
+ {
+ result.setQueueNotFound(true);
+ }
+
+
+ if(exchange != null && queue != null)
+ {
+
+ boolean queueMatched = exchange.isBound(queue);
+
+ result.setQueueNotMatched(!queueMatched);
+
+
+ if(method.hasBindingKey())
+ {
+
+ if(method.hasArguments())
+ {
+ // TODO
+ }
+ if(queueMatched)
+ {
+ result.setKeyNotMatched(!exchange.isBound(method.getBindingKey(), queue));
+ }
+ else
+ {
+ result.setKeyNotMatched(!exchange.isBound(method.getBindingKey()));
+ }
+ }
+ else if (method.hasArguments())
+ {
+ // TODO
+
+ }
+
+ result.setQueueNotMatched(!exchange.isBound(queue));
+
+ }
+ else if(exchange != null && method.hasBindingKey())
+ {
+ if(method.hasArguments())
+ {
+ // TODO
+ }
+ result.setKeyNotMatched(!exchange.isBound(method.getBindingKey()));
+
+ }
+
+ }
+ else if(exchange != null && method.hasBindingKey())
+ {
+ if(method.hasArguments())
+ {
+ // TODO
+ }
+ result.setKeyNotMatched(!exchange.isBound(method.getBindingKey()));
+
+ }
+
+
+ session.executionResult((int) method.getId(), result);
+
+
+ }
+
+ private AMQQueue getQueue(Session session, String queue)
+ {
+ QueueRegistry queueRegistry = getQueueRegistry(session);
+ return queueRegistry.getQueue(queue);
+ }
+
+ private QueueRegistry getQueueRegistry(Session session)
+ {
+ return getVirtualHost(session).getQueueRegistry();
+ }
+
+ @Override
+ public void queueDeclare(Session session, QueueDeclare method)
+ {
+
+ VirtualHost virtualHost = getVirtualHost(session);
+ DurableConfigurationStore store = virtualHost.getDurableConfigurationStore();
+
+ String queueName = method.getQueue();
+
+ if (!method.getPassive())
+ {
+ // Perform ACL if request is not passive
+
+ if (!virtualHost.getAccessManager().authoriseCreateQueue(((ServerSession)session), method.getAutoDelete(), method.getDurable(),
+ method.getExclusive(), false, method.getPassive(), new AMQShortString(queueName)))
+ {
+ ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_ALLOWED;
+ String description = "permission denied: queue-name '" + queueName + "'";
+
+ exception(session, method, errorCode, description);
+
+ // TODO control flow
+ return;
+ }
+ }
+
+
+ AMQQueue queue;
+ QueueRegistry queueRegistry = getQueueRegistry(session);
+ //TODO: do we need to check that the queue already exists with exactly the same "configuration"?
+
+ synchronized (queueRegistry)
+ {
+
+ if (((queue = queueRegistry.getQueue(queueName)) == null))
+ {
+
+ if (method.getPassive())
+ {
+ String description = "Queue: " + queueName + " not found on VirtualHost(" + virtualHost + ").";
+ ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_FOUND;
+
+ exception(session, method, errorCode, description);
+
+ return;
+ }
+ else
+ {
+ try
+ {
+ queue = createQueue(queueName, method, virtualHost, (ServerSession)session);
+ if(method.getExclusive())
+ {
+ queue.setPrincipalHolder((ServerSession)session);
+ queue.setExclusiveOwner(session);
+ }
+ else if(method.getAutoDelete())
+ {
+ queue.setDeleteOnNoConsumers(true);
+ }
+
+ final String alternateExchangeName = method.getAlternateExchange();
+ if(alternateExchangeName != null && alternateExchangeName.length() != 0)
+ {
+ Exchange alternate = getExchange(session, alternateExchangeName);
+ queue.setAlternateExchange(alternate);
+ }
+
+ if(method.hasArguments() && method.getArguments() != null)
+ {
+ if(method.getArguments().containsKey("no-local"))
+ {
+ Object no_local = method.getArguments().get("no-local");
+ if(no_local instanceof Boolean && ((Boolean)no_local))
+ {
+ queue.setNoLocal(true);
+ }
+ }
+ }
+
+
+ if (queue.isDurable() && !queue.isAutoDelete())
+ {
+ if(method.hasArguments() && method.getArguments() != null)
+ {
+ Map<String,Object> args = method.getArguments();
+ FieldTable ftArgs = new FieldTable();
+ for(Map.Entry<String, Object> entry : args.entrySet())
+ {
+ ftArgs.put(new AMQShortString(entry.getKey()), entry.getValue());
+ }
+ store.createQueue(queue, ftArgs);
+ }
+ else
+ {
+ store.createQueue(queue);
+ }
+ }
+ queueRegistry.registerQueue(queue);
+ boolean autoRegister = ApplicationRegistry.getInstance().getConfiguration().getQueueAutoRegister();
+
+ if (autoRegister)
+ {
+ ExchangeRegistry exchangeRegistry = getExchangeRegistry(session);
+
+ Exchange defaultExchange = exchangeRegistry.getDefaultExchange();
+
+ queue.bind(defaultExchange, new AMQShortString(queueName), null);
+
+ }
+
+ if(method.hasAutoDelete()
+ && method.getAutoDelete()
+ && method.hasExclusive()
+ && method.getExclusive())
+ {
+ final AMQQueue q = queue;
+ final ServerSession.Task deleteQueueTask = new ServerSession.Task()
+ {
+
+ public void doTask(ServerSession session)
+ {
+ try
+ {
+ q.delete();
+ }
+ catch (AMQException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ };
+ final ServerSession s = (ServerSession) session;
+ s.addSessionCloseTask(deleteQueueTask);
+ queue.addQueueDeleteTask(new AMQQueue.Task()
+ {
+
+ public void doTask(AMQQueue queue) throws AMQException
+ {
+ s.removeSessionCloseTask(deleteQueueTask);
+ }
+ });
+ }
+ else if(method.getExclusive())
+ {
+ {
+ final AMQQueue q = queue;
+ final ServerSession.Task removeExclusive = new ServerSession.Task()
+ {
+
+ public void doTask(ServerSession session)
+ {
+ q.setPrincipalHolder(null);
+ }
+ };
+ final ServerSession s = (ServerSession) session;
+ s.addSessionCloseTask(removeExclusive);
+ queue.addQueueDeleteTask(new AMQQueue.Task()
+ {
+
+ public void doTask(AMQQueue queue) throws AMQException
+ {
+ s.removeSessionCloseTask(removeExclusive);
+ }
+ });
+ }
+ }
+ }
+ catch (AMQException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ else if (method.getExclusive() && (queue.getPrincipalHolder() != null && !queue.getPrincipalHolder().equals(session)))
+ {
+
+ String description = "Cannot declare queue('" + queueName + "'),"
+ + " as exclusive queue with same name "
+ + "declared on another session";
+ ExecutionErrorCode errorCode = ExecutionErrorCode.RESOURCE_LOCKED;
+
+ exception(session, method, errorCode, description);
+
+ return;
+ }
+
+ }
+ }
+
+
+ protected AMQQueue createQueue(final String queueName,
+ QueueDeclare body,
+ VirtualHost virtualHost,
+ final ServerSession session)
+ throws AMQException
+ {
+ final QueueRegistry registry = virtualHost.getQueueRegistry();
+
+ String owner = body.getExclusive() ? session.getPrincipal().getName() : null;
+
+ final AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, body.getDurable(), owner, body.getAutoDelete(), virtualHost,
+ body.getArguments());
+
+
+ if (body.getExclusive() && !body.getDurable())
+ {
+ final ServerSession.Task deleteQueueTask =
+ new ServerSession.Task()
+ {
+ public void doTask(ServerSession session)
+ {
+ if (registry.getQueue(queueName) == queue)
+ {
+ try
+ {
+ queue.delete();
+ }
+ catch (AMQException e)
+ {
+ //TODO
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ };
+
+ session.addSessionCloseTask(deleteQueueTask);
+
+ queue.addQueueDeleteTask(new AMQQueue.Task()
+ {
+ public void doTask(AMQQueue queue)
+ {
+ session.removeSessionCloseTask(deleteQueueTask);
+ }
+ });
+ }// if exclusive and not durable
+
+ return queue;
+ }
+
+ @Override
+ public void queueDelete(Session session, QueueDelete method)
+ {
+
+ String queueName = method.getQueue();
+ if(queueName == null || queueName.length()==0)
+ {
+ exception(session, method, ExecutionErrorCode.INVALID_ARGUMENT, "No queue name supplied");
+
+ }
+ else
+ {
+ AMQQueue queue = getQueue(session, queueName);
+
+
+ if (queue == null)
+ {
+ exception(session, method, ExecutionErrorCode.NOT_FOUND, "No queue " + queueName + " found");
+ }
+ else
+ {
+ if(queue.getPrincipalHolder() != null && queue.getPrincipalHolder() != session)
+ {
+ exception(session,method,ExecutionErrorCode.RESOURCE_LOCKED, "Exclusive Queue: " + queueName + " owned exclusively by another session");
+ }
+ else if (method.getIfEmpty() && !queue.isEmpty())
+ {
+ exception(session, method, ExecutionErrorCode.PRECONDITION_FAILED, "Queue " + queueName + " not empty");
+ }
+ else if (method.getIfUnused() && !queue.isUnused())
+ {
+ // TODO - Error code
+ exception(session, method, ExecutionErrorCode.PRECONDITION_FAILED, "Queue " + queueName + " in use");
+
+ }
+ else
+ {
+ VirtualHost virtualHost = getVirtualHost(session);
+
+ //Perform ACLs
+ if (!virtualHost.getAccessManager().authoriseDelete(((ServerSession)session), queue))
+ {
+ exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Cannot delete queue " + queueName);
+ }
+ else
+ {
+ try
+ {
+ int purged = queue.delete();
+ if (queue.isDurable() && !queue.isAutoDelete())
+ {
+ DurableConfigurationStore store = virtualHost.getDurableConfigurationStore();
+ store.removeQueue(queue);
+ }
+
+ }
+ catch (AMQException e)
+ {
+ //TODO
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ }
+ }
+ }
+
+ }
+
+ @Override
+ public void queuePurge(Session session, QueuePurge method)
+ {
+ String queueName = method.getQueue();
+ if(queueName == null || queueName.length()==0)
+ {
+ exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "No queue name supplied");
+
+ }
+ else
+ {
+ AMQQueue queue = getQueue(session, queueName);
+
+
+ if (queue == null)
+ {
+ exception(session, method, ExecutionErrorCode.NOT_FOUND, "No queue " + queueName + " found");
+ }
+ else
+ {
+ //TODO
+ queue.clearQueue();
+ }
+ }
+
+ }
+
+ @Override
+ public void queueQuery(Session session, QueueQuery method)
+ {
+ QueueQueryResult result = new QueueQueryResult();
+
+ AMQQueue queue = getQueue(session, method.getQueue());
+
+ if(queue != null)
+ {
+ result.setQueue(queue.getName().toString());
+ result.setDurable(queue.isDurable());
+ result.setExclusive(queue.isExclusive());
+ result.setAutoDelete(queue.isAutoDelete());
+ result.setArguments(queue.getArguments());
+ result.setMessageCount(queue.getMessageCount());
+ result.setSubscriberCount(queue.getConsumerCount());
+
+ }
+
+
+ session.executionResult((int) method.getId(), result);
+
+ }
+
+ @Override
+ public void messageSetFlowMode(Session session, MessageSetFlowMode sfm)
+ {
+ String destination = sfm.getDestination();
+
+ Subscription_0_10 sub = ((ServerSession)session).getSubscription(destination);
+
+ if(sub == null)
+ {
+ exception(session, sfm, ExecutionErrorCode.NOT_FOUND, "not-found: destination '"+destination+"'");
+ }
+
+ if(sub.isStopped())
+ {
+ sub.setFlowMode(sfm.getFlowMode());
+ }
+ }
+
+ @Override
+ public void messageStop(Session session, MessageStop stop)
+ {
+ String destination = stop.getDestination();
+
+ Subscription_0_10 sub = ((ServerSession)session).getSubscription(destination);
+
+ if(sub == null)
+ {
+ exception(session, stop, ExecutionErrorCode.NOT_FOUND, "not-found: destination '"+destination+"'");
+ }
+
+ sub.stop();
+
+ }
+
+ @Override
+ public void messageFlow(Session session, MessageFlow flow)
+ {
+ String destination = flow.getDestination();
+
+ Subscription_0_10 sub = ((ServerSession)session).getSubscription(destination);
+
+ if(sub == null)
+ {
+ exception(session, flow, ExecutionErrorCode.NOT_FOUND, "not-found: destination '"+destination+"'");
+ }
+
+ sub.addCredit(flow.getUnit(), flow.getValue());
+
+ }
+
+ @Override
+ public void closed(Session session)
+ {
+ super.closed(session);
+ for(Subscription_0_10 sub : getSubscriptions(session))
+ {
+ ((ServerSession)session).unregister(sub);
+ }
+ ((ServerSession)session).onClose();
+ }
+
+ public Collection<Subscription_0_10> getSubscriptions(Session session)
+ {
+ return ((ServerSession)session).getSubscriptions();
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java b/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java
new file mode 100755
index 0000000000..7b29106ba6
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java
@@ -0,0 +1,170 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.txn;
+
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.message.EnqueableMessage;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.store.TransactionLog;
+import org.apache.qpid.AMQException;
+
+import java.util.List;
+import java.util.Collection;
+
+public class AutoCommitTransaction implements ServerTransaction
+{
+
+ private final TransactionLog _transactionLog;
+
+ public AutoCommitTransaction(TransactionLog transactionLog)
+ {
+ _transactionLog = transactionLog;
+ }
+
+
+ public void addPostCommitAction(Action postCommitAction)
+ {
+ postCommitAction.postCommit();
+ }
+
+ public void dequeue(AMQQueue queue, EnqueableMessage message, Action postCommitAction)
+ {
+
+ try
+ {
+ if(message.isPersistent() && queue.isDurable())
+ {
+
+ TransactionLog.Transaction txn = _transactionLog.newTransaction();
+ txn.dequeueMessage(queue, message.getMessageNumber());
+ // store.remove enqueue
+ // store.commit
+ txn.commitTran();
+ }
+ postCommitAction.postCommit();
+ }
+ catch (AMQException e)
+ {
+ //TODO
+ postCommitAction.onRollback();
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void dequeue(Collection<QueueEntry> ackedMessages, Action postCommitAction)
+ {
+ try
+ {
+ TransactionLog.Transaction txn = null;
+ for(QueueEntry entry : ackedMessages)
+ {
+ ServerMessage message = entry.getMessage();
+ AMQQueue queue = entry.getQueue();
+
+ if(message.isPersistent() && queue.isDurable())
+ {
+ if(txn == null)
+ {
+ txn = _transactionLog.newTransaction();
+ }
+ txn.dequeueMessage(queue, message.getMessageNumber());
+ }
+
+ }
+ if(txn != null)
+ {
+ txn.commitTran();
+ }
+ postCommitAction.postCommit();
+ }
+ catch (AMQException e)
+ {
+ //TODO
+ postCommitAction.onRollback();
+ throw new RuntimeException(e);
+ }
+ }
+
+
+ public void enqueue(AMQQueue queue, EnqueableMessage message, Action postCommitAction)
+ {
+ try
+ {
+ if(message.isPersistent() && queue.isDurable())
+ {
+
+ TransactionLog.Transaction txn = _transactionLog.newTransaction();
+ txn.enqueueMessage(queue, message.getMessageNumber());
+ txn.commitTran();
+ }
+ postCommitAction.postCommit();
+ }
+ catch (AMQException e)
+ {
+ //TODO
+ e.printStackTrace();
+ postCommitAction.onRollback();
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public void enqueue(List<AMQQueue> queues, EnqueableMessage message, Action postCommitAction)
+ {
+ try
+ {
+
+ if(message.isPersistent())
+ {
+ TransactionLog.Transaction txn = _transactionLog.newTransaction();
+ Long id = message.getMessageNumber();
+ for(AMQQueue q : queues)
+ {
+ if(q.isDurable())
+ {
+ txn.enqueueMessage(q, id);
+ }
+ }
+ txn.commitTran();
+
+ }
+ postCommitAction.postCommit();
+ }
+ catch (AMQException e)
+ {
+ //TODO
+ postCommitAction.onRollback();
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public void commit()
+ {
+
+ }
+
+ public void rollback()
+ {
+
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java b/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java
new file mode 100755
index 0000000000..9997fbe767
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java
@@ -0,0 +1,243 @@
+package org.apache.qpid.server.txn;
+
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.message.EnqueableMessage;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.store.TransactionLog;
+import org.apache.qpid.AMQException;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class LocalTransaction implements ServerTransaction
+{
+ private final List<Action> _postCommitActions = new ArrayList<Action>();
+
+ private volatile TransactionLog.Transaction _transaction;
+ private TransactionLog _transactionLog;
+
+ public LocalTransaction(TransactionLog transactionLog)
+ {
+ _transactionLog = transactionLog;
+ }
+
+ public void addPostCommitAction(Action postCommitAction)
+ {
+ _postCommitActions.add(postCommitAction);
+ }
+
+ public void dequeue(AMQQueue queue, EnqueableMessage message, Action postCommitAction)
+ {
+ if(message.isPersistent() && queue.isDurable())
+ {
+ try
+ {
+
+ beginTranIfNecessary();
+ _transaction.dequeueMessage(queue, message.getMessageNumber());
+
+ }
+ catch(AMQException e)
+ {
+ tidyUpOnError(e);
+ }
+ }
+ _postCommitActions.add(postCommitAction);
+ }
+
+ public void dequeue(Collection<QueueEntry> queueEntries, Action postCommitAction)
+ {
+ try
+ {
+
+ for(QueueEntry entry : queueEntries)
+ {
+ ServerMessage message = entry.getMessage();
+ AMQQueue queue = entry.getQueue();
+ if(message.isPersistent() && queue.isDurable())
+ {
+ beginTranIfNecessary();
+ _transaction.dequeueMessage(queue, message.getMessageNumber());
+ }
+
+ }
+ }
+ catch(AMQException e)
+ {
+ tidyUpOnError(e);
+ }
+ _postCommitActions.add(postCommitAction);
+
+ }
+
+ private void tidyUpOnError(Exception e)
+ {
+ try
+ {
+ for(Action action : _postCommitActions)
+ {
+ action.onRollback();
+ }
+ }
+ finally
+ {
+ try
+ {
+ _transaction.abortTran();
+ }
+ catch (Exception e1)
+ {
+ // TODO could try to chain the information to the original error
+ }
+ _transaction = null;
+ _postCommitActions.clear();
+ }
+
+ throw new RuntimeException(e);
+ }
+
+ private void beginTranIfNecessary()
+ {
+ if(_transaction == null)
+ {
+ try
+ {
+ _transaction = _transactionLog.newTransaction();
+ }
+ catch (Exception e)
+ {
+ tidyUpOnError(e);
+ }
+ }
+ }
+
+ public void enqueue(AMQQueue queue, EnqueableMessage message, Action postCommitAction)
+ {
+ if(message.isPersistent() && queue.isDurable())
+ {
+ beginTranIfNecessary();
+ try
+ {
+ _transaction.enqueueMessage(queue, message.getMessageNumber());
+ }
+ catch (Exception e)
+ {
+ tidyUpOnError(e);
+ }
+ }
+ _postCommitActions.add(postCommitAction);
+
+
+ }
+
+ public void enqueue(List<AMQQueue> queues, EnqueableMessage message, Action postCommitAction)
+ {
+
+
+ if(message.isPersistent())
+ {
+ if(_transaction == null)
+ {
+ for(AMQQueue queue : queues)
+ {
+ if(queue.isDurable())
+ {
+ beginTranIfNecessary();
+ break;
+ }
+ }
+
+
+ }
+
+
+ try
+ {
+ for(AMQQueue queue : queues)
+ {
+ if(queue.isDurable())
+ {
+ _transaction.enqueueMessage(queue, message.getMessageNumber());
+ }
+ }
+
+ }
+ catch (Exception e)
+ {
+ tidyUpOnError(e);
+ }
+ }
+ _postCommitActions.add(postCommitAction);
+
+
+ }
+
+ public void commit()
+ {
+ try
+ {
+ if(_transaction != null)
+ {
+
+ _transaction.commitTran();
+ }
+
+ for(Action action : _postCommitActions)
+ {
+ action.postCommit();
+ }
+ }
+ catch (Exception e)
+ {
+ for(Action action : _postCommitActions)
+ {
+ action.onRollback();
+ }
+ //TODO
+ throw new RuntimeException(e);
+ }
+ finally
+ {
+ _transaction = null;
+ _postCommitActions.clear();
+ }
+
+ }
+
+ public void rollback()
+ {
+
+ try
+ {
+
+ if(_transaction != null)
+ {
+
+ _transaction.abortTran();
+ }
+ }
+ catch (AMQException e)
+ {
+ //TODO
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ }
+ finally
+ {
+ try
+ {
+ for(Action action : _postCommitActions)
+ {
+ action.onRollback();
+ }
+ }
+ finally
+ {
+ _transaction = null;
+ _postCommitActions.clear();
+ }
+ }
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java
deleted file mode 100644
index 3c71282c57..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java
+++ /dev/null
@@ -1,293 +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.
- *
- */
-package org.apache.qpid.server.txn;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.server.RequiredDeliveryException;
-import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.ack.TxAck;
-import org.apache.qpid.server.ack.UnacknowledgedMessageMap;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.queue.*;
-import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.StoreContext;
-
-import java.util.List;
-import java.util.ArrayList;
-
-/** A transactional context that only supports local transactions. */
-public class LocalTransactionalContext implements TransactionalContext
-{
- private static final Logger _log = Logger.getLogger(LocalTransactionalContext.class);
-
- private final TxnBuffer _txnBuffer = new TxnBuffer();
-
- private final List<DeliveryAction> _postCommitDeliveryList = new ArrayList<DeliveryAction>();
-
- /**
- * We keep hold of the ack operation so that we can consolidate acks, i.e. multiple acks within a txn are
- * consolidated into a single operation
- */
- private TxAck _ackOp;
-
- private boolean _inTran = false;
-
- /** Are there messages to deliver. NOT Has the message been delivered */
- private boolean _messageDelivered = false;
- private final AMQChannel _channel;
-
-
- private abstract class DeliveryAction
- {
-
- abstract public void process() throws AMQException;
-
- }
-
- private class RequeueAction extends DeliveryAction
- {
- public QueueEntry entry;
-
- public RequeueAction(QueueEntry entry)
- {
- this.entry = entry;
- }
-
- public void process() throws AMQException
- {
- entry.requeue(getStoreContext());
- }
- }
-
- private class PublishAction extends DeliveryAction
- {
- private final AMQQueue _queue;
- private final AMQMessage _message;
-
- public PublishAction(final AMQQueue queue, final AMQMessage message)
- {
- _queue = queue;
- _message = message;
- }
-
- public void process() throws AMQException
- {
-
- _message.incrementReference();
- try
- {
- QueueEntry entry = _queue.enqueue(getStoreContext(),_message);
-
- if(entry.immediateAndNotDelivered())
- {
- getReturnMessages().add(new NoConsumersException(_message));
- }
- }
- finally
- {
- _message.decrementReference(getStoreContext());
- }
- }
- }
-
- public LocalTransactionalContext(final AMQChannel channel)
- {
- _channel = channel;
- }
-
- public StoreContext getStoreContext()
- {
- return _channel.getStoreContext();
- }
-
- public List<RequiredDeliveryException> getReturnMessages()
- {
- return _channel.getReturnMessages();
- }
-
- public MessageStore getMessageStore()
- {
- return _channel.getMessageStore();
- }
-
-
- public void rollback() throws AMQException
- {
- _txnBuffer.rollback(getStoreContext());
- // Hack to deal with uncommitted non-transactional writes
- if (getMessageStore().inTran(getStoreContext()))
- {
- getMessageStore().abortTran(getStoreContext());
- _inTran = false;
- }
-
- _postCommitDeliveryList.clear();
- }
-
- public void deliver(final AMQQueue queue, AMQMessage message) throws AMQException
- {
- // A publication will result in the enlisting of several
- // TxnOps. The first is an op that will store the message.
- // Following that (and ordering is important), an op will
- // be added for every queue onto which the message is
- // enqueued.
- _postCommitDeliveryList.add(new PublishAction(queue, message));
- _messageDelivered = true;
-
- }
-
- public void requeue(QueueEntry entry) throws AMQException
- {
- _postCommitDeliveryList.add(new RequeueAction(entry));
- _messageDelivered = true;
-
- }
-
-
- private void checkAck(long deliveryTag, UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException
- {
- if (!unacknowledgedMessageMap.contains(deliveryTag))
- {
- throw new AMQException("Ack with delivery tag " + deliveryTag + " not known for channel");
- }
- }
-
- public void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple,
- UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException
- {
- // check that the tag exists to give early failure
- if (!multiple || (deliveryTag > 0))
- {
- checkAck(deliveryTag, unacknowledgedMessageMap);
- }
- // we use a single txn op for all acks and update this op
- // as new acks come in. If this is the first ack in the txn
- // we will need to create and enlist the op.
- if (_ackOp == null)
- {
- _ackOp = new TxAck(unacknowledgedMessageMap);
- _txnBuffer.enlist(_ackOp);
- }
- // update the op to include this ack request
- if (multiple && (deliveryTag == 0))
- {
- // if have signalled to ack all, that refers only
- // to all at this time
- _ackOp.update(lastDeliveryTag, multiple);
- }
- else
- {
- _ackOp.update(deliveryTag, multiple);
- }
- if(!_inTran && _ackOp.checkPersistent())
- {
- beginTranIfNecessary();
- }
- }
-
- public void messageFullyReceived(boolean persistent) throws AMQException
- {
- // Not required in this transactional context
- }
-
- public void messageProcessed(AMQProtocolSession protocolSession) throws AMQException
- {
- // Not required in this transactional context
- }
-
- public void beginTranIfNecessary() throws AMQException
- {
- if (!_inTran)
- {
- if (_log.isDebugEnabled())
- {
- _log.debug("Starting transaction on message store: " + this);
- }
-
- getMessageStore().beginTran(getStoreContext());
- _inTran = true;
- }
- }
-
- public void commit() throws AMQException
- {
- if (_log.isDebugEnabled())
- {
- _log.debug("Committing transactional context: " + this);
- }
-
- if (_ackOp != null)
- {
-
- _messageDelivered = true;
- _ackOp.consolidate();
- // already enlisted, after commit will reset regardless of outcome
- _ackOp = null;
- }
-
- if (_messageDelivered && _inTran)
- {
- _txnBuffer.enlist(new StoreMessageOperation(getMessageStore()));
- }
- // fixme fail commit here ... QPID-440
- try
- {
- _txnBuffer.commit(getStoreContext());
- }
- finally
- {
- _messageDelivered = false;
- _inTran = getMessageStore().inTran(getStoreContext());
- }
-
- try
- {
- postCommitDelivery();
- }
- catch (AMQException e)
- {
- // OK so what do we do now...?
- _log.error("Failed to deliver messages following txn commit: " + e, e);
- }
- }
-
- private void postCommitDelivery() throws AMQException
- {
- if (_log.isDebugEnabled())
- {
- _log.debug("Performing post commit delivery");
- }
-
- try
- {
- for (DeliveryAction dd : _postCommitDeliveryList)
- {
- dd.process();
- }
- }
- finally
- {
- _postCommitDeliveryList.clear();
- }
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java
deleted file mode 100644
index 28af36e3db..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java
+++ /dev/null
@@ -1,213 +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.
- *
- */
-package org.apache.qpid.server.txn;
-
-import java.util.LinkedList;
-import java.util.List;
-
-import org.apache.log4j.Logger;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.RequiredDeliveryException;
-import org.apache.qpid.server.ack.UnacknowledgedMessageMap;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.queue.*;
-import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.StoreContext;
-
-/** @author Apache Software Foundation */
-public class NonTransactionalContext implements TransactionalContext
-{
- private static final Logger _log = Logger.getLogger(NonTransactionalContext.class);
-
- /** Channel is useful for logging */
- private final AMQChannel _channel;
-
- /** Where to put undeliverable messages */
- private final List<RequiredDeliveryException> _returnMessages;
-
-
-
- private final MessageStore _messageStore;
-
- private final StoreContext _storeContext;
-
- /** Whether we are in a transaction */
- private boolean _inTran;
-
- public NonTransactionalContext(MessageStore messageStore, StoreContext storeContext, AMQChannel channel,
- List<RequiredDeliveryException> returnMessages)
- {
- _channel = channel;
- _storeContext = storeContext;
- _returnMessages = returnMessages;
- _messageStore = messageStore;
-
- }
-
-
- public StoreContext getStoreContext()
- {
- return _storeContext;
- }
-
- public void beginTranIfNecessary() throws AMQException
- {
- if (!_inTran)
- {
- _messageStore.beginTran(_storeContext);
- _inTran = true;
- }
- }
-
- public void commit() throws AMQException
- {
- // Does not apply to this context
- }
-
- public void rollback() throws AMQException
- {
- // Does not apply to this context
- }
-
- public void deliver(final AMQQueue queue, AMQMessage message) throws AMQException
- {
- QueueEntry entry = queue.enqueue(_storeContext, message);
-
- //following check implements the functionality
- //required by the 'immediate' flag:
- if(entry.immediateAndNotDelivered())
- {
- _returnMessages.add(new NoConsumersException(entry.getMessage()));
- }
-
- }
-
- public void requeue(QueueEntry entry) throws AMQException
- {
- entry.requeue(_storeContext);
- }
-
- public void acknowledgeMessage(final long deliveryTag, long lastDeliveryTag,
- boolean multiple, final UnacknowledgedMessageMap unacknowledgedMessageMap)
- throws AMQException
- {
-
- final boolean debug = _log.isDebugEnabled();
- ;
- if (multiple)
- {
- if (deliveryTag == 0)
- {
-
- //Spec 2.1.6.11 ... If the multiple field is 1, and the delivery tag is zero,
- // tells the server to acknowledge all outstanding mesages.
- _log.info("Multiple ack on delivery tag 0. ACKing all messages. Current count:" +
- unacknowledgedMessageMap.size());
- unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor()
- {
- public boolean callback(final long deliveryTag, QueueEntry message) throws AMQException
- {
- if (debug)
- {
- _log.debug("Discarding message: " + message.getMessage().getMessageId());
- }
- if(message.getMessage().isPersistent())
- {
- beginTranIfNecessary();
- }
- //Message has been ack so discard it. This will dequeue and decrement the reference.
- message.discard(_storeContext);
-
- return false;
- }
-
- public void visitComplete()
- {
- unacknowledgedMessageMap.clear();
- }
- });
- }
- else
- {
- if (!unacknowledgedMessageMap.contains(deliveryTag))
- {
- throw new AMQException("Multiple ack on delivery tag " + deliveryTag + " not known for channel");
- }
-
- unacknowledgedMessageMap.drainTo(deliveryTag, _storeContext);
- }
- }
- else
- {
- QueueEntry msg;
- msg = unacknowledgedMessageMap.get(deliveryTag);
-
- if (msg == null)
- {
- _log.info("Single ack on delivery tag " + deliveryTag + " not known for channel:" +
- _channel.getChannelId());
- throw new AMQException("Single ack on delivery tag " + deliveryTag + " not known for channel:" +
- _channel.getChannelId());
- }
-
- if (debug)
- {
- _log.debug("Discarding message: " + msg.getMessage().getMessageId());
- }
- if(msg.getMessage().isPersistent())
- {
- beginTranIfNecessary();
- }
-
- //Message has been ack so discard it. This will dequeue and decrement the reference.
- msg.discard(_storeContext);
-
- unacknowledgedMessageMap.remove(deliveryTag);
-
-
- if (debug)
- {
- _log.debug("Received non-multiple ack for messaging with delivery tag " + deliveryTag + " msg id " +
- msg.getMessage().getMessageId());
- }
- }
- if(_inTran)
- {
- _messageStore.commitTran(_storeContext);
- _inTran = false;
- }
- }
-
- public void messageFullyReceived(boolean persistent) throws AMQException
- {
- if (persistent)
- {
- _messageStore.commitTran(_storeContext);
- _inTran = false;
- }
- }
-
- public void messageProcessed(AMQProtocolSession protocolSession) throws AMQException
- {
- _channel.processReturns();
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java b/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java
new file mode 100755
index 0000000000..88bdc363c4
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java
@@ -0,0 +1,60 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.txn;
+
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.message.EnqueableMessage;
+import org.apache.qpid.server.AMQChannel;
+
+import java.util.List;
+import java.util.SortedSet;
+import java.util.Collection;
+
+public interface ServerTransaction
+{
+
+ void addPostCommitAction(Action postCommitAction);
+
+
+
+
+ public static interface Action
+ {
+ public void postCommit();
+
+ public void onRollback();
+ }
+
+ void dequeue(AMQQueue queue, EnqueableMessage message, Action postCommitAction);
+
+ void dequeue(Collection<QueueEntry> ackedMessages, Action postCommitAction);
+
+ void enqueue(AMQQueue queue, EnqueableMessage message, Action postCommitAction);
+
+ void enqueue(List<AMQQueue> queues, EnqueableMessage message, Action postCommitAction);
+
+
+ void commit();
+
+ void rollback();
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java b/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java
deleted file mode 100644
index 0e4d6c2030..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java
+++ /dev/null
@@ -1,58 +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.
- *
- */
-package org.apache.qpid.server.txn;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.StoreContext;
-
-/**
- * A transactional operation to store messages in an underlying persistent store. When this operation
- * commits it will do everything to ensure that all messages are safely committed to persistent
- * storage.
- */
-public class StoreMessageOperation implements TxnOp
-{
- private final MessageStore _messsageStore;
-
- public StoreMessageOperation(MessageStore messageStore)
- {
- _messsageStore = messageStore;
- }
-
- public void prepare(StoreContext context) throws AMQException
- {
- }
-
- public void undoPrepare()
- {
- }
-
- public void commit(StoreContext context) throws AMQException
- {
- _messsageStore.commitTran(context);
- }
-
- public void rollback(StoreContext context) throws AMQException
- {
- _messsageStore.abortTran(context);
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java b/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java
deleted file mode 100644
index 647ba66fb4..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java
+++ /dev/null
@@ -1,179 +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.
- *
- */
-package org.apache.qpid.server.txn;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.server.ack.UnacknowledgedMessageMap;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.store.StoreContext;
-
-/**
- * TransactionalContext provides a context in which transactional operations on {@link AMQMessage}s are performed.
- * Different levels of transactional support for the delivery of messages may be provided by different implementations
- * of this interface.
- *
- * <p/>The fundamental transactional operations that can be performed on a message queue are 'enqueue' and 'dequeue'.
- * In this interface, these have been recast as the {@link #messageFullyReceived} and {@link #acknowledgeMessage}
- * operations. This interface essentially provides a way to make enqueueing and dequeuing transactional.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities
- * <tr><td> Explicitly accept a transaction start notification.
- * <tr><td> Commit all pending operations in a transaction.
- * <tr><td> Rollback all pending operations in a transaction.
- * <tr><td> Deliver a message to a queue as part of a transaction.
- * <tr><td> Redeliver a message to a queue as part of a transaction.
- * <tr><td> Mark a message as acknowledged as part of a transaction.
- * <tr><td> Accept notification that a message has been completely received as part of a transaction.
- * <tr><td> Accept notification that a message has been fully processed as part of a transaction.
- * <tr><td> Associate a message store context with this transaction context.
- * </table>
- *
- * @todo The 'fullyReceived' and 'messageProcessed' events sit uncomfortably in the responsibilities of a transactional
- * context. They are non-transactional operations, used to trigger other side-effects. Consider moving them
- * somewhere else, a seperate interface for example.
- *
- * @todo This transactional context could be written as a wrapper extension to a Queue implementation, that provides
- * transactional management of the enqueue and dequeue operations, with added commit/rollback methods. Any
- * queue implementation could be made transactional by wrapping it as a transactional queue. This would mean
- * that the enqueue/dequeue operations do not need to be recast as deliver/acknowledge operations, which may be
- * conceptually neater.
- *
- * For example:
- * <pre>
- * public interface Transactional
- * {
- * public void commit();
- * public void rollback();
- * }
- *
- * public interface TransactionalQueue<E> extends Transactional, SizeableQueue<E>
- * {}
- *
- * public class Queues
- * {
- * ...
- * // For transactional messaging, take a transactional view onto the queue.
- * public static <E> TransactionalQueue<E> getTransactionalQueue(SizeableQueue<E> queue) { ... }
- *
- * // For non-transactional messaging, take a non-transactional view onto the queue.
- * public static <E> TransactionalQueue<E> getNonTransactionalQueue(SizeableQueue<E> queue) { ... }
- * }
- * </pre>
- */
-public interface TransactionalContext
-{
- /**
- * Explicitly begins the transaction, if it has not already been started. {@link #commit} or {@link #rollback}
- * should automatically begin the next transaction in the chain.
- *
- * @throws AMQException If the transaction cannot be started for any reason.
- */
- void beginTranIfNecessary() throws AMQException;
-
- /**
- * Makes all pending operations on the transaction permanent and visible.
- *
- * @throws AMQException If the transaction cannot be committed for any reason.
- */
- void commit() throws AMQException;
-
- /**
- * Erases all pending operations on the transaction.
- *
- * @throws AMQException If the transaction cannot be committed for any reason.
- */
- void rollback() throws AMQException;
-
- /**
- * Delivers the specified message to the specified queue.
- *
- * <p/>This is an 'enqueue' operation.
- *
- * @param queue
- * @param message The message to deliver
- * @throws AMQException If the message cannot be delivered for any reason.
- */
- void deliver(final AMQQueue queue, AMQMessage message) throws AMQException;
-
- /**
- * Requeues the specified message entry (message queue pair)
- *
- *
- * @param queueEntry The message,queue pair
- *
- * @throws AMQException If the message cannot be delivered for any reason.
- */
- void requeue(QueueEntry queueEntry) throws AMQException;
-
-
- /**
- * Acknowledges a message or many messages as delivered. All messages up to a specified one, may be acknowledged by
- * setting the 'multiple' flag. It is also possible for the acknowledged message id to be zero, when the 'multiple'
- * flag is set, in which case an acknowledgement up to the latest delivered message should be done.
- *
- * <p/>This is a 'dequeue' operation.
- *
- * @param deliveryTag The id of the message to acknowledge, or zero, if using multiple acknowledgement
- * up to the latest message.
- * @param lastDeliveryTag The latest message delivered.
- * @param multiple <tt>true</tt> if all message ids up the acknowledged one or latest delivered, are
- * to be acknowledged, <tt>false</tt> otherwise.
- * @param unacknowledgedMessageMap The unacknowledged messages in the transaction, to remove the acknowledged message
- * from.
- *
- * @throws AMQException If the message cannot be acknowledged for any reason.
- */
- void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple,
- UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException;
-
- /**
- * Notifies the transactional context that a message has been fully received. The actual message that was received
- * is not specified. This event may be used to trigger a process related to the receipt of the message, for example,
- * flushing its data to disk.
- *
- * @param persistent <tt>true</tt> if the received message is persistent, <tt>false</tt> otherwise.
- *
- * @throws AMQException If the fully received event cannot be processed for any reason.
- */
- void messageFullyReceived(boolean persistent) throws AMQException;
-
- /**
- * Notifies the transactional context that a message has been delivered, succesfully or otherwise. The actual
- * message that was delivered is not specified. This event may be used to trigger a process related to the
- * outcome of the delivery of the message, for example, cleaning up failed deliveries.
- *
- * @param protocolSession The protocol session of the deliverable message.
- *
- * @throws AMQException If the message processed event cannot be handled for any reason.
- */
- void messageProcessed(AMQProtocolSession protocolSession) throws AMQException;
-
- /**
- * Gets the message store context associated with this transactional context.
- *
- * @return The message store context associated with this transactional context.
- */
- StoreContext getStoreContext();
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java b/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java
deleted file mode 100644
index 46a68b6a23..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java
+++ /dev/null
@@ -1,109 +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.
- *
- */
-package org.apache.qpid.server.txn;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.log4j.Logger;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.server.store.StoreContext;
-
-/** Holds a list of TxnOp instance representing transactional operations. */
-public class TxnBuffer
-{
- private final List<TxnOp> _ops = new ArrayList<TxnOp>();
- private static final Logger _log = Logger.getLogger(TxnBuffer.class);
-
- public TxnBuffer()
- {
- }
-
- public void commit(StoreContext context) throws AMQException
- {
- if (_log.isDebugEnabled())
- {
- _log.debug("Committing " + _ops.size() + " ops to commit.:" + _ops);
- }
-
- if (prepare(context))
- {
- for (TxnOp op : _ops)
- {
- op.commit(context);
- }
- }
- _ops.clear();
- }
-
- private boolean prepare(StoreContext context) throws AMQException
- {
- for (int i = 0; i < _ops.size(); i++)
- {
- TxnOp op = _ops.get(i);
- try
- {
- op.prepare(context);
- }
- catch (AMQException e)
- {
- undoPrepare(i);
- throw e;
- }
- catch (RuntimeException e)
- {
- undoPrepare(i);
- throw e;
- }
- }
- return true;
- }
-
- private void undoPrepare(int lastPrepared)
- {
- //compensate previously prepared ops
- for (int j = 0; j < lastPrepared; j++)
- {
- _ops.get(j).undoPrepare();
- }
- }
-
-
-
- public void rollback(StoreContext context) throws AMQException
- {
- for (TxnOp op : _ops)
- {
- op.rollback(context);
- }
- _ops.clear();
- }
-
- public void enlist(TxnOp op)
- {
- _ops.add(op);
- }
-
- public void cancel(TxnOp op)
- {
- _ops.remove(op);
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java b/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java
deleted file mode 100644
index 919c078cf0..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java
+++ /dev/null
@@ -1,55 +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.
- *
- */
-package org.apache.qpid.server.txn;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.server.store.StoreContext;
-
-/**
- * This provides the abstraction of an individual operation within a
- * transaction. It is used by the TxnBuffer class.
- */
-public interface TxnOp
-{
- /**
- * Do the part of the operation that updates persistent state
- */
- public void prepare(StoreContext context) throws AMQException;
- /**
- * Complete the operation started by prepare. Can now update in
- * memory state or make netork transfers.
- */
- public void commit(StoreContext context) throws AMQException;
- /**
- * This is not the same as rollback. Unfortunately the use of an
- * in memory reference count as a locking mechanism and a test for
- * whether a message should be deleted means that as things are,
- * handling an acknowledgement unavoidably alters both memory and
- * persistent state on prepare. This is needed to 'compensate' or
- * undo the in-memory change if the peristent update of later ops
- * fails.
- */
- public void undoPrepare();
- /**
- * Rolls back the operation.
- */
- public void rollback(StoreContext context) throws AMQException;
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java b/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java
deleted file mode 100644
index cf5e71a6e2..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java
+++ /dev/null
@@ -1,38 +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.
- *
- */
-package org.apache.qpid.server.util;
-
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-public class ConcurrentLinkedQueueNoSize<E> extends ConcurrentLinkedQueue<E>
-{
- public int size()
- {
- if (isEmpty())
- {
- return 0;
- }
- else
- {
- return 1;
- }
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java
deleted file mode 100644
index ee5f9d5e88..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java
+++ /dev/null
@@ -1,84 +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.
- *
- */
-package org.apache.qpid.server.util;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Properties;
-
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.MapConfiguration;
-import org.apache.qpid.server.management.ManagedObjectRegistry;
-import org.apache.qpid.server.management.NoopManagedObjectRegistry;
-import org.apache.qpid.server.plugins.PluginManager;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
-import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager;
-import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager;
-import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabaseManager;
-import org.apache.qpid.server.security.access.ACLPlugin;
-import org.apache.qpid.server.security.access.plugins.AllowAll;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
-
-public class NullApplicationRegistry extends ApplicationRegistry
-{
- public NullApplicationRegistry()
- {
- super(new MapConfiguration(new HashMap()));
- }
-
- public void initialise() throws Exception
- {
- _logger.info("Initialising NullApplicationRegistry");
-
- _configuration.addProperty("store.class", "org.apache.qpid.server.store.MemoryMessageStore");
-
- Properties users = new Properties();
-
- users.put("guest", "guest");
-
- _databaseManager = new PropertiesPrincipalDatabaseManager("default", users);
-
- _accessManager = new AllowAll();
-
- _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null);
-
- _managedObjectRegistry = new NoopManagedObjectRegistry();
- _virtualHostRegistry = new VirtualHostRegistry();
- VirtualHost dummyHost = new VirtualHost("test", getConfiguration());
- _virtualHostRegistry.registerVirtualHost(dummyHost);
- _virtualHostRegistry.setDefaultVirtualHostName("test");
- _pluginManager = new PluginManager("");
- _configuration.addProperty("heartbeat.delay", 10 * 60); // 10 minutes
-
- }
-
- public Collection<String> getVirtualHostNames()
- {
- String[] hosts = {"test"};
- return Arrays.asList(hosts);
- }
-}
-
-
-
diff --git a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java
index 85d804457e..2f0c56cc86 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/ManagedVirtualHost.java
@@ -22,7 +22,7 @@ package org.apache.qpid.server.virtualhost;
import java.io.IOException;
-import org.apache.qpid.server.management.MBeanAttribute;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanAttribute;
/**
* The management interface exposed to allow management of an Exchange.
@@ -31,6 +31,7 @@ import org.apache.qpid.server.management.MBeanAttribute;
public interface ManagedVirtualHost
{
static final String TYPE = "VirtualHost";
+ static final int VERSION = 1;
/**
* Returns the name of the managed virtualHost.
diff --git a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java
index b25a56344e..e4a382d275 100644..100755
--- a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java
@@ -1,329 +1,62 @@
/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
package org.apache.qpid.server.virtualhost;
-import javax.management.NotCompliantMBeanException;
-
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.PropertiesConfiguration;
-import org.apache.log4j.Logger;
-import org.apache.qpid.server.AMQBrokerManagerMBean;
-import org.apache.qpid.server.connection.ConnectionRegistry;
import org.apache.qpid.server.connection.IConnectionRegistry;
-import org.apache.qpid.server.security.access.ACLPlugin;
-import org.apache.qpid.server.security.access.ACLManager;
-import org.apache.qpid.server.security.access.Accessable;
-import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager;
-import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
-import org.apache.qpid.server.configuration.Configurator;
-import org.apache.qpid.server.exchange.DefaultExchangeFactory;
-import org.apache.qpid.server.exchange.DefaultExchangeRegistry;
-import org.apache.qpid.server.exchange.ExchangeFactory;
-import org.apache.qpid.server.exchange.ExchangeRegistry;
-import org.apache.qpid.server.management.AMQManagedObject;
-import org.apache.qpid.server.management.ManagedObject;
-import org.apache.qpid.server.queue.DefaultQueueRegistry;
+import org.apache.qpid.server.configuration.VirtualHostConfiguration;
import org.apache.qpid.server.queue.QueueRegistry;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.exchange.ExchangeRegistry;
+import org.apache.qpid.server.exchange.ExchangeFactory;
import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.AMQException;
-
-import java.util.Timer;
-import java.util.TimerTask;
+import org.apache.qpid.server.store.TransactionLog;
+import org.apache.qpid.server.store.DurableConfigurationStore;
+import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
+import org.apache.qpid.server.security.access.ACLManager;
+import org.apache.qpid.server.management.ManagedObject;
-public class VirtualHost implements Accessable
+public interface VirtualHost
{
- private static final Logger _logger = Logger.getLogger(VirtualHost.class);
-
-
- private final String _name;
-
- private ConnectionRegistry _connectionRegistry;
-
- private QueueRegistry _queueRegistry;
-
- private ExchangeRegistry _exchangeRegistry;
-
- private ExchangeFactory _exchangeFactory;
-
- private MessageStore _messageStore;
-
- protected VirtualHostMBean _virtualHostMBean;
-
- private AMQBrokerManagerMBean _brokerMBean;
-
- private AuthenticationManager _authenticationManager;
-
- private ACLPlugin _accessManager;
-
- private final Timer _houseKeepingTimer;
-
- private static final long DEFAULT_HOUSEKEEPING_PERIOD = 30000L;
-
-
- public void setAccessableName(String name)
- {
- _logger.warn("Setting Accessable Name for VirualHost is not allowed. ("
- + name + ") ignored remains :" + getAccessableName());
- }
-
- public String getAccessableName()
- {
- return _name;
- }
-
- public IConnectionRegistry getConnectionRegistry()
- {
- return _connectionRegistry;
- }
-
- /**
- * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any
- * implementaion of an Exchange MBean should extend this class.
- */
- public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost
- {
- public VirtualHostMBean() throws NotCompliantMBeanException
- {
- super(ManagedVirtualHost.class, "VirtualHost");
- }
-
- public String getObjectInstanceName()
- {
- return _name.toString();
- }
-
- public String getName()
- {
- return _name.toString();
- }
-
- public VirtualHost getVirtualHost()
- {
- return VirtualHost.this;
- }
-
-
- } // End of MBean class
-
- /**
- * Used for testing only
- * @param name
- * @param store
- * @throws Exception
- */
- public VirtualHost(String name, MessageStore store) throws Exception
- {
- this(name, new PropertiesConfiguration(), store);
- }
-
- /**
- * Normal Constructor
- * @param name
- * @param hostConfig
- * @throws Exception
- */
- public VirtualHost(String name, Configuration hostConfig) throws Exception
- {
- this(name, hostConfig, null);
- }
-
- public VirtualHost(String name, Configuration hostConfig, MessageStore store) throws Exception
- {
- if (name == null || name.length() == 0)
- {
- throw new IllegalArgumentException("Illegal name (" + name + ") for virtualhost.");
- }
-
- _name = name;
-
- _virtualHostMBean = new VirtualHostMBean();
-
- _connectionRegistry = new ConnectionRegistry(this);
-
- _houseKeepingTimer = new Timer("Queue-housekeeping-"+name, true);
- _queueRegistry = new DefaultQueueRegistry(this);
- _exchangeFactory = new DefaultExchangeFactory(this);
- _exchangeFactory.initialise(hostConfig);
- _exchangeRegistry = new DefaultExchangeRegistry(this);
-
- if (store != null)
- {
- _messageStore = store;
- }
- else
- {
- if (hostConfig == null)
- {
- throw new IllegalAccessException("HostConfig and MessageStore cannot be null");
- }
- initialiseMessageStore(hostConfig);
- }
-
- _exchangeRegistry.initialise();
-
- _authenticationManager = new PrincipalDatabaseAuthenticationManager(name, hostConfig);
-
- _accessManager = ACLManager.loadACLManager(name, hostConfig);
-
- _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean);
- _brokerMBean.register();
- initialiseHouseKeeping(hostConfig);
- }
-
- private void initialiseHouseKeeping(final Configuration hostConfig)
- {
-
- long period = hostConfig.getLong("housekeeping.expiredMessageCheckPeriod", DEFAULT_HOUSEKEEPING_PERIOD);
-
- /* add a timer task to iterate over queues, cleaning expired messages from queues with no consumers */
- if(period != 0L)
- {
- class RemoveExpiredMessagesTask extends TimerTask
- {
- public void run()
- {
- for(AMQQueue q : _queueRegistry.getQueues())
- {
-
- try
- {
- q.removeExpiredIfNoSubscribers();
- }
- catch (AMQException e)
- {
- _logger.error("Exception in housekeeping for queue: " + q.getName().toString(),e);
- throw new RuntimeException(e);
- }
- }
- }
- }
-
- _houseKeepingTimer.scheduleAtFixedRate(new RemoveExpiredMessagesTask(),
- period/2,
- period);
- }
- }
-
- private void initialiseMessageStore(Configuration config) throws Exception
- {
- String messageStoreClass = config.getString("store.class");
-
- Class clazz = Class.forName(messageStoreClass);
- Object o = clazz.newInstance();
-
- if (!(o instanceof MessageStore))
- {
- throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz +
- " does not.");
- }
- _messageStore = (MessageStore) o;
- _messageStore.configure(this, "store", config);
- }
-
-
- public <T> T getConfiguredObject(Class<T> instanceType, Configuration config)
- {
- T instance;
- try
- {
- instance = instanceType.newInstance();
- }
- catch (Exception e)
- {
- _logger.error("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor");
- throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor", e);
- }
- Configurator.configure(instance);
-
- return instance;
- }
-
-
- public String getName()
- {
- return _name;
- }
+ IConnectionRegistry getConnectionRegistry();
- public QueueRegistry getQueueRegistry()
- {
- return _queueRegistry;
- }
+ VirtualHostConfiguration getConfiguration();
- public ExchangeRegistry getExchangeRegistry()
- {
- return _exchangeRegistry;
- }
+ String getName();
- public ExchangeFactory getExchangeFactory()
- {
- return _exchangeFactory;
- }
+ QueueRegistry getQueueRegistry();
- public ApplicationRegistry getApplicationRegistry()
- {
- throw new UnsupportedOperationException();
- }
+ ExchangeRegistry getExchangeRegistry();
- public MessageStore getMessageStore()
- {
- return _messageStore;
- }
+ ExchangeFactory getExchangeFactory();
- public AuthenticationManager getAuthenticationManager()
- {
- return _authenticationManager;
- }
+ MessageStore getMessageStore();
- public ACLPlugin getAccessManager()
- {
- return _accessManager;
- }
+ TransactionLog getTransactionLog();
- public void close() throws Exception
- {
- //Stop Housekeeping
- if (_houseKeepingTimer != null)
- {
- _houseKeepingTimer.cancel();
- }
+ DurableConfigurationStore getDurableConfigurationStore();
- //Stop Connections
- _connectionRegistry.close();
+ AuthenticationManager getAuthenticationManager();
- //Close MessageStore
- if (_messageStore != null)
- {
- _messageStore.close();
- }
- }
+ ACLManager getAccessManager();
- public ManagedObject getBrokerMBean()
- {
- return _brokerMBean;
- }
+ void close() throws Exception;
- public ManagedObject getManagedObject()
- {
- return _virtualHostMBean;
- }
+ ManagedObject getManagedObject();
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java
new file mode 100755
index 0000000000..c543531210
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java
@@ -0,0 +1,341 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+package org.apache.qpid.server.virtualhost;
+
+import org.apache.qpid.server.store.ConfigurationRecoveryHandler;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.MessageStoreRecoveryHandler;
+import org.apache.qpid.server.store.StoredMessage;
+import org.apache.qpid.server.store.TransactionLogRecoveryHandler;
+import org.apache.qpid.server.store.TransactionLog;
+import org.apache.qpid.server.store.TransactionLogResource;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.AMQQueueFactory;
+import org.apache.qpid.server.queue.QueueRegistry;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.messages.TransactionLogMessages;
+import org.apache.qpid.server.logging.messages.MessageStoreMessages;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.message.MessageTransferMessage;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.AMQException;
+
+import org.apache.log4j.Logger;
+
+import java.nio.ByteBuffer;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.TreeMap;
+
+public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHandler,
+ ConfigurationRecoveryHandler.QueueRecoveryHandler,
+ ConfigurationRecoveryHandler.ExchangeRecoveryHandler,
+ ConfigurationRecoveryHandler.BindingRecoveryHandler,
+ MessageStoreRecoveryHandler,
+ MessageStoreRecoveryHandler.StoredMessageRecoveryHandler,
+ TransactionLogRecoveryHandler,
+ TransactionLogRecoveryHandler.QueueEntryRecoveryHandler
+{
+ private static final Logger _logger = Logger.getLogger(VirtualHostConfigRecoveryHandler.class);
+
+
+ private final VirtualHost _virtualHost;
+
+ private MessageStoreLogSubject _logSubject;
+ private List<ProcessAction> _actions;
+
+ private MessageStore _store;
+ private TransactionLog _transactionLog;
+
+ private final Map<String, Integer> _queueRecoveries = new TreeMap<String, Integer>();
+ private Map<Long, ServerMessage> _recoveredMessages = new HashMap<Long, ServerMessage>();
+ private Map<Long, StoredMessage> _unusedMessages = new HashMap<Long, StoredMessage>();
+
+
+
+ public VirtualHostConfigRecoveryHandler(VirtualHost virtualHost)
+ {
+ _virtualHost = virtualHost;
+ }
+
+ public QueueRecoveryHandler begin(MessageStore store)
+ {
+ _logSubject = new MessageStoreLogSubject(_virtualHost,store);
+ _store = store;
+ CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1004(null, false));
+
+ return this;
+ }
+
+ public void queue(String queueName, String owner, FieldTable arguments)
+ {
+ AMQShortString queueNameShortString = new AMQShortString(queueName);
+
+ AMQQueue q = _virtualHost.getQueueRegistry().getQueue(queueNameShortString);
+
+ if (q == null)
+ {
+ q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, _virtualHost,
+ arguments);
+ _virtualHost.getQueueRegistry().registerQueue(q);
+ }
+
+ CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1004(queueName, true));
+
+ //Record that we have a queue for recovery
+ _queueRecoveries.put(queueName, 0);
+ }
+
+ public ExchangeRecoveryHandler completeQueueRecovery()
+ {
+ return this;
+ }
+
+ public void exchange(String exchangeName, String type, boolean autoDelete)
+ {
+ try
+ {
+ Exchange exchange;
+ AMQShortString exchangeNameSS = new AMQShortString(exchangeName);
+ exchange = _virtualHost.getExchangeRegistry().getExchange(exchangeNameSS);
+ if (exchange == null)
+ {
+ exchange = _virtualHost.getExchangeFactory().createExchange(exchangeNameSS, new AMQShortString(type), true, autoDelete, 0);
+ _virtualHost.getExchangeRegistry().registerExchange(exchange);
+ }
+ }
+ catch (AMQException e)
+ {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public BindingRecoveryHandler completeExchangeRecovery()
+ {
+ return this;
+ }
+
+ public StoredMessageRecoveryHandler begin()
+ {
+ // TODO - log begin
+ return this;
+ }
+
+ public void message(StoredMessage message)
+ {
+ ServerMessage serverMessage;
+ switch(message.getMetaData().getType())
+ {
+ case META_DATA_0_8:
+ serverMessage = new AMQMessage(message);
+ break;
+ case META_DATA_0_10:
+ serverMessage = new MessageTransferMessage(message, null);
+ break;
+ default:
+ throw new RuntimeException("Unknown message type retreived from store " + message.getMetaData().getClass());
+ }
+
+
+ _recoveredMessages.put(message.getMessageNumber(), serverMessage);
+ _unusedMessages.put(message.getMessageNumber(), message);
+ }
+
+ public void completeMessageRecovery()
+ {
+ //TODO - log end
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public TransactionLogRecoveryHandler.QueueEntryRecoveryHandler begin(TransactionLog log)
+ {
+ _transactionLog = log;
+ return this;
+ }
+
+ private static final class ProcessAction
+ {
+ private final AMQQueue _queue;
+ private final AMQMessage _message;
+
+ public ProcessAction(AMQQueue queue, AMQMessage message)
+ {
+ _queue = queue;
+ _message = message;
+ }
+
+ public void process()
+ {
+ try
+ {
+ _queue.enqueue(_message);
+ }
+ catch(AMQException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ }
+
+ public void binding(String exchangeName, String queueName, String bindingKey, ByteBuffer buf)
+ {
+ _actions = new ArrayList<ProcessAction>();
+ try
+ {
+ QueueRegistry queueRegistry = _virtualHost.getQueueRegistry();
+ Exchange exchange = _virtualHost.getExchangeRegistry().getExchange(exchangeName);
+ AMQQueue queue = queueRegistry.getQueue(new AMQShortString(queueName));
+ if (queue == null)
+ {
+ _logger.error("Unkown queue: " + queueName + " cannot be bound to exchange: "
+ + exchange.getName());
+ }
+ else
+ {
+
+
+ FieldTable argumentsFT = null;
+ if(buf != null)
+ {
+ argumentsFT = new FieldTable(org.apache.mina.common.ByteBuffer.wrap(buf),buf.limit());
+ }
+
+ _logger.info("Restoring binding: (Exchange: " + exchange.getName() + ", Queue: " + queueName
+ + ", Routing Key: " + bindingKey + ", Arguments: " + argumentsFT + ")");
+
+ queue.bind(exchange, bindingKey == null ? null : new AMQShortString(bindingKey), argumentsFT);
+
+ }
+ }
+ catch (AMQException e)
+ {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public void completeBindingRecovery()
+ {
+ //return this;
+ }
+
+ public void complete()
+ {
+
+
+ }
+
+ public void queueEntry(final String queueName, long messageId)
+ {
+ AMQShortString queueNameShortString = new AMQShortString(queueName);
+
+ AMQQueue queue = _virtualHost.getQueueRegistry().getQueue(queueNameShortString);
+
+ try
+ {
+ if(queue != null)
+ {
+ ServerMessage message = _recoveredMessages.get(messageId);
+ _unusedMessages.remove(messageId);
+
+ if(message != null)
+ {
+
+
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("On recovery, delivering " + message.getMessageNumber() + " to " + queue.getName());
+ }
+
+ Integer count = _queueRecoveries.get(queueName);
+ if (count == null)
+ {
+ count = 0;
+ }
+
+ queue.enqueue(message);
+
+ _queueRecoveries.put(queueName, ++count);
+ }
+ else
+ {
+ _logger.warn("Message id " + messageId + " referenced in log as enqueue in queue " + queue.getName() + " is unknwon, entry will be discarded");
+ TransactionLog.Transaction txn = _transactionLog.newTransaction();
+ txn.dequeueMessage(queue, messageId);
+ txn.commitTranAsync();
+ }
+ }
+ else
+ {
+ _logger.warn("Message id " + messageId + " in log references queue " + queueName + " which is not in the configuration, entry will be discarded");
+ TransactionLog.Transaction txn = _transactionLog.newTransaction();
+ TransactionLogResource mockQueue =
+ new TransactionLogResource()
+ {
+
+ public String getResourceName()
+ {
+ return queueName;
+ }
+ };
+ txn.dequeueMessage(mockQueue, messageId);
+ txn.commitTranAsync();
+ }
+
+ }
+ catch(AMQException e)
+ {
+ throw new RuntimeException(e);
+ }
+
+
+
+ }
+
+ public void completeQueueEntryRecovery()
+ {
+
+ for(StoredMessage m : _unusedMessages.values())
+ {
+ _logger.warn("Message id " + m.getMessageNumber() + " in store, but not in any queue - removing....");
+ m.remove();
+ }
+
+ for(Map.Entry<String,Integer> entry : _queueRecoveries.entrySet())
+ {
+ CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1005(entry.getValue(), entry.getKey()));
+
+ CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1006(entry.getKey(), true));
+ }
+
+ CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1006(null, false));
+ }
+
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java
new file mode 100644
index 0000000000..78deeeb164
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java
@@ -0,0 +1,609 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.virtualhost;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.Configuration;
+import org.apache.log4j.Logger;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.server.AMQBrokerManagerMBean;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.messages.VirtualHostMessages;
+import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.configuration.ExchangeConfiguration;
+import org.apache.qpid.server.configuration.QueueConfiguration;
+import org.apache.qpid.server.configuration.VirtualHostConfiguration;
+import org.apache.qpid.server.connection.ConnectionRegistry;
+import org.apache.qpid.server.connection.IConnectionRegistry;
+import org.apache.qpid.server.exchange.DefaultExchangeFactory;
+import org.apache.qpid.server.exchange.DefaultExchangeRegistry;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.exchange.ExchangeFactory;
+import org.apache.qpid.server.exchange.ExchangeRegistry;
+import org.apache.qpid.server.management.AMQManagedObject;
+import org.apache.qpid.server.management.ManagedObject;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.AMQQueueFactory;
+import org.apache.qpid.server.queue.DefaultQueueRegistry;
+import org.apache.qpid.server.queue.QueueRegistry;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.security.access.ACLManager;
+import org.apache.qpid.server.security.access.Accessable;
+import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
+import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.DurableConfigurationStore;
+import org.apache.qpid.server.store.TransactionLog;
+import org.apache.qpid.server.store.ConfigurationRecoveryHandler;
+
+import javax.management.NotCompliantMBeanException;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class VirtualHostImpl implements Accessable, VirtualHost
+{
+ private static final Logger _logger = Logger.getLogger(VirtualHostImpl.class);
+
+ private final String _name;
+
+ private ConnectionRegistry _connectionRegistry;
+
+ private QueueRegistry _queueRegistry;
+
+ private ExchangeRegistry _exchangeRegistry;
+
+ private ExchangeFactory _exchangeFactory;
+
+ private MessageStore _messageStore;
+
+ protected VirtualHostMBean _virtualHostMBean;
+
+ private AMQBrokerManagerMBean _brokerMBean;
+
+ private AuthenticationManager _authenticationManager;
+
+ private ACLManager _accessManager;
+
+ private final Timer _houseKeepingTimer;
+ private VirtualHostConfiguration _configuration;
+ private DurableConfigurationStore _durableConfigurationStore;
+
+ public void setAccessableName(String name)
+ {
+ _logger.warn("Setting Accessable Name for VirualHost is not allowed. ("
+ + name + ") ignored remains :" + getAccessableName());
+ }
+
+ public String getAccessableName()
+ {
+ return _name;
+ }
+
+ public IConnectionRegistry getConnectionRegistry()
+ {
+ return _connectionRegistry;
+ }
+
+ public VirtualHostConfiguration getConfiguration()
+ {
+ return _configuration;
+ }
+
+ /**
+ * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any
+ * implementaion of an Exchange MBean should extend this class.
+ */
+ public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost
+ {
+ public VirtualHostMBean() throws NotCompliantMBeanException
+ {
+ super(ManagedVirtualHost.class, ManagedVirtualHost.TYPE, ManagedVirtualHost.VERSION);
+ }
+
+ public String getObjectInstanceName()
+ {
+ return _name.toString();
+ }
+
+ public String getName()
+ {
+ return _name.toString();
+ }
+
+ public VirtualHostImpl getVirtualHost()
+ {
+ return VirtualHostImpl.this;
+ }
+
+ } // End of MBean class
+
+ /**
+ * Normal Constructor
+ *
+ * @param hostConfig
+ *
+ * @throws Exception
+ */
+ public VirtualHostImpl(VirtualHostConfiguration hostConfig) throws Exception
+ {
+ this(hostConfig, null);
+ }
+
+ public VirtualHostImpl(VirtualHostConfiguration hostConfig, MessageStore store) throws Exception
+ {
+ _configuration = hostConfig;
+ _name = hostConfig.getName();
+
+ CurrentActor.get().message(VirtualHostMessages.VHT_CREATED(_name));
+
+ if (_name == null || _name.length() == 0)
+ {
+ throw new IllegalArgumentException("Illegal name (" + _name + ") for virtualhost.");
+ }
+
+ _virtualHostMBean = new VirtualHostMBean();
+
+ _connectionRegistry = new ConnectionRegistry(this);
+
+ _houseKeepingTimer = new Timer("Queue-housekeeping-" + _name, true);
+
+ _queueRegistry = new DefaultQueueRegistry(this);
+
+ _exchangeFactory = new DefaultExchangeFactory(this);
+ _exchangeFactory.initialise(hostConfig);
+
+ _exchangeRegistry = new DefaultExchangeRegistry(this);
+
+ //Create a temporary RT to store the durable entries from the config file
+ // so we can replay them in to the real _RT after it has been loaded.
+ /// This should be removed after the _RT has been fully split from the the TL
+
+ StartupRoutingTable configFileRT = new StartupRoutingTable();
+
+ _durableConfigurationStore = configFileRT;
+
+ // This needs to be after the RT has been defined as it creates the default durable exchanges.
+ _exchangeRegistry.initialise();
+
+ // We don't need to store the Default queues in the store as we always
+ // create them first on start up so don't clear them from the startup
+ // configuration here. This also ensures that we don't attempt to
+ // perform a createExchange twice with the same details in the
+ // MessageStore(RoutingTable) as some instances may not like that.
+ // Derby being one.
+ // todo this can be removed with the resolution fo QPID-2096
+ configFileRT.exchange.clear();
+
+ initialiseModel(hostConfig);
+
+ //todo REMOVE Work Around for QPID-2096
+ // This means that all durable exchanges declared in the configuration
+ // will not be stored in the MessageStore.
+ // They will still be created/registered/available on startup for as
+ // long as they are contained in the configuration. However, when they
+ // are removed from the configuration they will no longer exist.
+ // This differs from durable queues as they will be writen to to the
+ // store. After QPID-2096 has been resolved exchanges will mirror that
+ // functionality.
+ configFileRT.exchange.clear();
+
+ if (store != null)
+ {
+ _messageStore = store;
+ _durableConfigurationStore = store;
+ }
+ else
+ {
+ if (hostConfig == null)
+ {
+ throw new IllegalAccessException("HostConfig and MessageStore cannot be null");
+ }
+ initialiseMessageStore(hostConfig);
+ }
+
+ //Now that the RT has been initialised loop through the persistent queues/exchanges created from the config
+ // file and write them in to the new routing Table.
+ for (StartupRoutingTable.CreateQueueTuple cqt : configFileRT.queue)
+ {
+ getDurableConfigurationStore().createQueue(cqt.queue, cqt.arguments);
+ }
+
+ for (Exchange exchange : configFileRT.exchange)
+ {
+ getDurableConfigurationStore().createExchange(exchange);
+ }
+
+ for (StartupRoutingTable.CreateBindingTuple cbt : configFileRT.bindings)
+ {
+ getDurableConfigurationStore().bindQueue(cbt.exchange, cbt.routingKey, cbt.queue, cbt.arguments);
+ }
+
+ _authenticationManager = new PrincipalDatabaseAuthenticationManager(_name, hostConfig);
+
+ _accessManager = ApplicationRegistry.getInstance().getAccessManager();
+ _accessManager.configureHostPlugins(hostConfig.getSecurityConfiguration());
+
+ _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean);
+ _brokerMBean.register();
+ initialiseHouseKeeping(hostConfig.getHousekeepingExpiredMessageCheckPeriod());
+ }
+
+ private void initialiseHouseKeeping(long period)
+ {
+ /* add a timer task to iterate over queues, cleaning expired messages from queues with no consumers */
+ if (period != 0L)
+ {
+ class RemoveExpiredMessagesTask extends TimerTask
+ {
+ public void run()
+ {
+ for (AMQQueue q : _queueRegistry.getQueues())
+ {
+
+ try
+ {
+ q.checkMessageStatus();
+ }
+ catch (Exception e)
+ {
+ _logger.error("Exception in housekeeping for queue: " + q.getName().toString(), e);
+ //Don't throw exceptions as this will stop the
+ // house keeping task from running.
+ }
+ }
+ }
+ }
+
+ _houseKeepingTimer.scheduleAtFixedRate(new RemoveExpiredMessagesTask(),
+ period / 2,
+ period);
+
+ class ForceChannelClosuresTask extends TimerTask
+ {
+ public void run()
+ {
+ _connectionRegistry.expireClosedChannels();
+ }
+ }
+ }
+ }
+
+ private void initialiseMessageStore(VirtualHostConfiguration hostConfig) throws Exception
+ {
+ String messageStoreClass = hostConfig.getMessageStoreClass();
+
+ Class clazz = Class.forName(messageStoreClass);
+ Object o = clazz.newInstance();
+
+ if (!(o instanceof MessageStore))
+ {
+ throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz +
+ " does not.");
+ }
+ MessageStore messageStore = (MessageStore) o;
+ VirtualHostConfigRecoveryHandler recoveryHandler = new VirtualHostConfigRecoveryHandler(this);
+
+ MessageStoreLogSubject storeLogSubject = new MessageStoreLogSubject(this, messageStore);
+
+ messageStore.configureConfigStore(this.getName(),
+ recoveryHandler,
+ hostConfig.getStoreConfiguration(),
+ storeLogSubject);
+
+ messageStore.configureMessageStore(this.getName(),
+ recoveryHandler,
+ hostConfig.getStoreConfiguration(),
+ storeLogSubject);
+ messageStore.configureTransactionLog(this.getName(),
+ recoveryHandler,
+ hostConfig.getStoreConfiguration(),
+ storeLogSubject);
+
+ _messageStore = messageStore;
+ _durableConfigurationStore = messageStore;
+ }
+
+ private void initialiseModel(VirtualHostConfiguration config) throws ConfigurationException, AMQException
+ {
+ _logger.debug("Loading configuration for virtualhost: " + config.getName());
+
+ List exchangeNames = config.getExchanges();
+
+ for (Object exchangeNameObj : exchangeNames)
+ {
+ String exchangeName = String.valueOf(exchangeNameObj);
+ configureExchange(config.getExchangeConfiguration(exchangeName));
+ }
+
+ String[] queueNames = config.getQueueNames();
+
+ for (Object queueNameObj : queueNames)
+ {
+ String queueName = String.valueOf(queueNameObj);
+ configureQueue(config.getQueueConfiguration(queueName));
+ }
+ }
+
+ private void configureExchange(ExchangeConfiguration exchangeConfiguration) throws AMQException
+ {
+ AMQShortString exchangeName = new AMQShortString(exchangeConfiguration.getName());
+
+ Exchange exchange;
+ exchange = _exchangeRegistry.getExchange(exchangeName);
+ if (exchange == null)
+ {
+
+ AMQShortString type = new AMQShortString(exchangeConfiguration.getType());
+ boolean durable = exchangeConfiguration.getDurable();
+ boolean autodelete = exchangeConfiguration.getAutoDelete();
+
+ Exchange newExchange = _exchangeFactory.createExchange(exchangeName, type, durable, autodelete, 0);
+ _exchangeRegistry.registerExchange(newExchange);
+ }
+ }
+
+ private void configureQueue(QueueConfiguration queueConfiguration) throws AMQException, ConfigurationException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueConfiguration, this);
+
+ if (queue.isDurable())
+ {
+ getDurableConfigurationStore().createQueue(queue);
+ }
+
+ String exchangeName = queueConfiguration.getExchange();
+
+ Exchange exchange = _exchangeRegistry.getExchange(exchangeName == null ? null : new AMQShortString(exchangeName));
+
+ if (exchange == null)
+ {
+ exchange = _exchangeRegistry.getDefaultExchange();
+ }
+
+ if (exchange == null)
+ {
+ throw new ConfigurationException("Attempt to bind queue to unknown exchange:" + exchangeName);
+ }
+
+ List routingKeys = queueConfiguration.getRoutingKeys();
+ if (routingKeys == null || routingKeys.isEmpty())
+ {
+ routingKeys = Collections.singletonList(queue.getName());
+ }
+
+ for (Object routingKeyNameObj : routingKeys)
+ {
+ AMQShortString routingKey = new AMQShortString(String.valueOf(routingKeyNameObj));
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Binding queue:" + queue + " with routing key '" + routingKey + "' to exchange:" + this);
+ }
+ queue.bind(exchange, routingKey, null);
+ }
+
+ if (exchange != _exchangeRegistry.getDefaultExchange())
+ {
+ queue.bind(_exchangeRegistry.getDefaultExchange(), queue.getName(), null);
+ }
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public QueueRegistry getQueueRegistry()
+ {
+ return _queueRegistry;
+ }
+
+ public ExchangeRegistry getExchangeRegistry()
+ {
+ return _exchangeRegistry;
+ }
+
+ public ExchangeFactory getExchangeFactory()
+ {
+ return _exchangeFactory;
+ }
+
+ public MessageStore getMessageStore()
+ {
+ return _messageStore;
+ }
+
+ public TransactionLog getTransactionLog()
+ {
+ return _messageStore;
+ }
+
+ public DurableConfigurationStore getDurableConfigurationStore()
+ {
+ return _durableConfigurationStore;
+ }
+
+ public AuthenticationManager getAuthenticationManager()
+ {
+ return _authenticationManager;
+ }
+
+ public ACLManager getAccessManager()
+ {
+ return _accessManager;
+ }
+
+ public void close() throws Exception
+ {
+
+ //Stop Connections
+ _connectionRegistry.close();
+
+ //Stop the Queues processing
+ if (_queueRegistry != null)
+ {
+ for (AMQQueue queue : _queueRegistry.getQueues())
+ {
+ queue.stop();
+ }
+ }
+
+ //Stop Housekeeping
+ if (_houseKeepingTimer != null)
+ {
+ _houseKeepingTimer.cancel();
+ }
+
+ //Close MessageStore
+ if (_messageStore != null)
+ {
+ _messageStore.close();
+ }
+
+ CurrentActor.get().message(VirtualHostMessages.VHT_CLOSED());
+ }
+
+ public ManagedObject getBrokerMBean()
+ {
+ return _brokerMBean;
+ }
+
+ public ManagedObject getManagedObject()
+ {
+ return _virtualHostMBean;
+ }
+
+ /**
+ * Temporary Startup RT class to record the creation of persistent queues / exchanges.
+ *
+ *
+ * This is so we can replay the creation of queues/exchanges in to the real _RT after it has been loaded.
+ * This should be removed after the _RT has been fully split from the the TL
+ */
+ private class StartupRoutingTable implements DurableConfigurationStore
+ {
+ public List<Exchange> exchange = new LinkedList<Exchange>();
+ public List<CreateQueueTuple> queue = new LinkedList<CreateQueueTuple>();
+ public List<CreateBindingTuple> bindings = new LinkedList<CreateBindingTuple>();
+
+ public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception
+ {
+ }
+
+ public void close() throws Exception
+ {
+ }
+
+ public void removeMessage(Long messageId) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void configureConfigStore(String name,
+ ConfigurationRecoveryHandler recoveryHandler,
+ Configuration config,
+ LogSubject logSubject) throws Exception
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void createExchange(Exchange exchange) throws AMQException
+ {
+ if (exchange.isDurable())
+ {
+ this.exchange.add(exchange);
+ }
+ }
+
+ public void removeExchange(Exchange exchange) throws AMQException
+ {
+ }
+
+ public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException
+ {
+ if (exchange.isDurable() && queue.isDurable())
+ {
+ bindings.add(new CreateBindingTuple(exchange, routingKey, queue, args));
+ }
+ }
+
+ public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException
+ {
+ }
+
+ public void createQueue(AMQQueue queue) throws AMQException
+ {
+ createQueue(queue, null);
+ }
+
+ public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException
+ {
+ if (queue.isDurable())
+ {
+ this.queue.add(new CreateQueueTuple(queue, arguments));
+ }
+ }
+
+ public void removeQueue(AMQQueue queue) throws AMQException
+ {
+ }
+
+
+ private class CreateQueueTuple
+ {
+ public AMQQueue queue;
+ public FieldTable arguments;
+
+ public CreateQueueTuple(AMQQueue queue, FieldTable arguments)
+ {
+ this.queue = queue;
+ this.arguments = arguments;
+ }
+ }
+
+ private class CreateBindingTuple
+ {
+ public AMQQueue queue;
+ public FieldTable arguments;
+ public Exchange exchange;
+ public AMQShortString routingKey;
+
+ public CreateBindingTuple(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args)
+ {
+ this.exchange = exchange;
+ this.routingKey = routingKey;
+ this.queue = queue;
+ arguments = args;
+ }
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return _name;
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java
index 27917fac8a..b86e0d0baf 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java
@@ -20,6 +20,8 @@
*/
package org.apache.qpid.server.virtualhost;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
@@ -28,10 +30,16 @@ import java.util.concurrent.ConcurrentHashMap;
public class VirtualHostRegistry
{
- private final Map<String, VirtualHost> _registry = new ConcurrentHashMap<String,VirtualHost>();
+ private final Map<String, VirtualHost> _registry = new ConcurrentHashMap<String, VirtualHost>();
private String _defaultVirtualHostName;
+ private ApplicationRegistry _applicationRegistry;
+
+ public VirtualHostRegistry(ApplicationRegistry applicationRegistry)
+ {
+ _applicationRegistry = applicationRegistry;
+ }
public synchronized void registerVirtualHost(VirtualHost host) throws Exception
{
@@ -67,4 +75,9 @@ public class VirtualHostRegistry
{
return new ArrayList<VirtualHost>(_registry.values());
}
+
+ public ApplicationRegistry getApplicationRegistry()
+ {
+ return _applicationRegistry;
+ }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java
index 0869d9a497..ef3599bdc8 100644
--- a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java
+++ b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java
@@ -14,14 +14,16 @@
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
- * under the License.
+ * under the License.
+ *
*
- *
*/
package org.apache.qpid.tools.messagestore.commands;
import org.apache.qpid.tools.messagestore.MessageStoreTool;
import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.txn.ServerTransaction;
+import org.apache.qpid.server.txn.LocalTransaction;
public class Copy extends Move
{
@@ -49,7 +51,9 @@ public class Copy extends Move
protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue)
{
- fromQueue.copyMessagesToAnotherQueue(start, end, toQueue.getName().toString(), _storeContext);
+ ServerTransaction txn = new LocalTransaction(fromQueue.getVirtualHost().getTransactionLog());
+ fromQueue.copyMessagesToAnotherQueue(start, end, toQueue.getName().toString(), txn);
+ txn.commit();
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java
index 731f6140f9..a7d58dc6dd 100644
--- a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java
+++ b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java
@@ -21,16 +21,13 @@
package org.apache.qpid.tools.messagestore.commands;
import org.apache.commons.codec.binary.Hex;
-import org.apache.mina.common.ByteBuffer;
-import org.apache.qpid.framing.abstraction.ContentChunk;
-import org.apache.qpid.server.queue.AMQMessage;
import org.apache.qpid.server.queue.QueueEntryImpl;
import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.message.ServerMessage;
import org.apache.qpid.tools.messagestore.MessageStoreTool;
import org.apache.qpid.tools.utils.Console;
import java.io.UnsupportedEncodingException;
-import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -100,7 +97,7 @@ public class Dump extends Show
for (QueueEntry entry : messages)
{
- AMQMessage msg = entry.getMessage();
+ ServerMessage msg = entry.getMessage();
if (!includeMsg(msg, msgids))
{
continue;
@@ -112,7 +109,7 @@ public class Dump extends Show
// Show general message information
hex.add(Show.Columns.ID.name());
- ascii.add(msg.getMessageId().toString());
+ ascii.add(msg.getMessageNumber().toString());
hex.add(Console.ROW_DIVIDER);
ascii.add(Console.ROW_DIVIDER);
@@ -136,10 +133,10 @@ public class Dump extends Show
hex.add(Console.ROW_DIVIDER);
ascii.add(Console.ROW_DIVIDER);
- Iterator bodies = msg.getContentBodyIterator();
- if (bodies.hasNext())
- {
+ final int messageSize = (int) msg.getSize();
+ if (messageSize != 0)
+ {
hex.add("Hex");
hex.add(Console.ROW_DIVIDER);
@@ -147,14 +144,19 @@ public class Dump extends Show
ascii.add("ASCII");
ascii.add(Console.ROW_DIVIDER);
- while (bodies.hasNext())
+ java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocate(64 * 1024);
+
+ int position = 0;
+
+ while(position < messageSize)
{
- ContentChunk chunk = (ContentChunk) bodies.next();
+ position += msg.getContent(buf, position);
+ buf.flip();
//Duplicate so we don't destroy original data :)
- ByteBuffer hexBuffer = chunk.getData().duplicate();
+ java.nio.ByteBuffer hexBuffer = buf;
- ByteBuffer charBuffer = hexBuffer.duplicate();
+ java.nio.ByteBuffer charBuffer = hexBuffer.duplicate();
Hex hexencoder = new Hex();
@@ -232,6 +234,7 @@ public class Dump extends Show
ascii.add(asciiLine);
}
+ buf.clear();
}
}
else
@@ -252,7 +255,7 @@ public class Dump extends Show
return display;
}
- private void addShowInformation(List<String> column1, List<String> column2, AMQMessage msg,
+ private void addShowInformation(List<String> column1, List<String> column2, ServerMessage msg,
String title, boolean routing, boolean headers, boolean messageHeaders)
{
List<QueueEntry> single = new LinkedList<QueueEntry>();
diff --git a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java
index df8b59ec19..ab8e781df5 100644
--- a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java
+++ b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java
@@ -14,9 +14,9 @@
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
- * under the License.
+ * under the License.
+ *
*
- *
*/
package org.apache.qpid.tools.messagestore.commands;
diff --git a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java
index a8dd58ca83..6a5e2a6025 100644
--- a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java
+++ b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java
@@ -14,17 +14,17 @@
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
- * under the License.
+ * under the License.
+ *
*
- *
*/
package org.apache.qpid.tools.messagestore.commands;
import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.queue.QueueEntryImpl;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.txn.ServerTransaction;
+import org.apache.qpid.server.txn.LocalTransaction;
import org.apache.qpid.tools.messagestore.MessageStoreTool;
import java.util.LinkedList;
@@ -33,12 +33,6 @@ import java.util.List;
public class Move extends AbstractCommand
{
- /**
- * Since the Coopy command is not associated with a real channel we can safely create our own store context
- * for use in the few methods that require one.
- */
- protected StoreContext _storeContext = new StoreContext();
-
public Move(MessageStoreTool tool)
{
super(tool);
@@ -172,7 +166,7 @@ public class Move extends AbstractCommand
{
for (QueueEntry msg : messages)
{
- ids.add(msg.getMessage().getMessageId());
+ ids.add(msg.getMessage().getMessageNumber());
}
}
}
@@ -201,6 +195,8 @@ public class Move extends AbstractCommand
protected void doCommand(AMQQueue fromQueue, long start, long id, AMQQueue toQueue)
{
- fromQueue.moveMessagesToAnotherQueue(start, id, toQueue.getName().toString(), _storeContext);
+ ServerTransaction txn = new LocalTransaction(fromQueue.getVirtualHost().getTransactionLog());
+ fromQueue.moveMessagesToAnotherQueue(start, id, toQueue.getName().toString(), txn);
+ txn.commit();
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java
index 5e99997863..8df4afa2db 100644
--- a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java
+++ b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java
@@ -62,6 +62,6 @@ public class Purge extends Move
protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue)
{
- fromQueue.removeMessagesFromQueue(start, end, _storeContext);
+ fromQueue.removeMessagesFromQueue(start, end);
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java
index 2fa017fc64..4fd4999b19 100644
--- a/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java
+++ b/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java
@@ -25,10 +25,10 @@ import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.BasicContentHeaderProperties;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.queue.QueueEntryImpl;
+import org.apache.qpid.server.message.AMQMessage;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.message.ServerMessage;
import org.apache.qpid.tools.messagestore.MessageStoreTool;
import org.apache.qpid.tools.utils.Console;
@@ -171,7 +171,7 @@ public class Show extends AbstractCommand
// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getEncoding();
// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getExpiration();
// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getMessageId();
+// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getMessageNumber();
// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPriority();
// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPropertyFlags();
// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getReplyTo();
@@ -182,14 +182,14 @@ public class Show extends AbstractCommand
// //Print out all the property names
// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders().getPropertyNames();
//
-// msg.getMessageId();
+// msg.getMessageNumber();
// msg.getSize();
// msg.getArrivalTime();
// msg.getDeliveredSubscription();
// msg.getDeliveredToConsumer();
// msg.getMessageHandle();
-// msg.getMessageId();
+// msg.getMessageNumber();
// msg.getMessagePublishInfo();
// msg.getPublisher();
@@ -337,30 +337,24 @@ public class Show extends AbstractCommand
//Add create the table of data
for (QueueEntry entry : messages)
{
- AMQMessage msg = entry.getMessage();
+ ServerMessage msg = entry.getMessage();
if (!includeMsg(msg, msgids))
{
continue;
}
- id.add(msg.getMessageId().toString());
+ id.add(msg.getMessageNumber().toString());
size.add("" + msg.getSize());
arrival.add("" + msg.getArrivalTime());
- try
- {
- ispersitent.add(msg.isPersistent() ? "true" : "false");
- }
- catch (AMQException e)
- {
- ispersitent.add("n/a");
- }
+ ispersitent.add(msg.isPersistent() ? "true" : "false");
+
- isredelivered.add(msg.isRedelivered() ? "true" : "false");
+ isredelivered.add(entry.isRedelivered() ? "true" : "false");
- isdelivered.add(msg.getDeliveredToConsumer() ? "true" : "false");
+ isdelivered.add(entry.getDeliveredToConsumer() ? "true" : "false");
// msg.getMessageHandle();
@@ -368,7 +362,10 @@ public class Show extends AbstractCommand
try
{
- headers = ((BasicContentHeaderProperties) msg.getContentHeaderBody().properties);
+ if(msg instanceof AMQMessage)
+ {
+ headers = ((BasicContentHeaderProperties) ((AMQMessage)msg).getContentHeaderBody().properties);
+ }
}
catch (AMQException e)
{
@@ -417,7 +414,11 @@ public class Show extends AbstractCommand
MessagePublishInfo info = null;
try
{
- info = msg.getMessagePublishInfo();
+ if(msg instanceof AMQMessage)
+ {
+ info = ((AMQMessage)msg).getMessagePublishInfo();
+ }
+
}
catch (AMQException e)
{
@@ -457,14 +458,14 @@ public class Show extends AbstractCommand
return data;
}
- protected boolean includeMsg(AMQMessage msg, List<Long> msgids)
+ protected boolean includeMsg(ServerMessage msg, List<Long> msgids)
{
if (msgids == null)
{
return true;
}
- Long msgid = msg.getMessageId();
+ Long msgid = msg.getMessageNumber();
boolean found = false;
diff --git a/java/broker/src/test/java/org/apache/log4j/xml/QpidLog4JConfiguratorTest.java b/java/broker/src/test/java/org/apache/log4j/xml/QpidLog4JConfiguratorTest.java
new file mode 100644
index 0000000000..445c7d57f2
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/log4j/xml/QpidLog4JConfiguratorTest.java
@@ -0,0 +1,396 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.log4j.xml;
+
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import org.apache.log4j.xml.QpidLog4JConfigurator.IllegalLoggerLevelException;
+
+import junit.framework.TestCase;
+
+public class QpidLog4JConfiguratorTest extends TestCase
+{
+ private static final String NEWLINE = System.getProperty("line.separator");
+
+ private File _testConfigFile;
+
+ private File createTempTestLog4JConfig(String loggerLevel,String rootLoggerLevel, boolean missingTagClose, boolean incorrectAttribute)
+ {
+ File tmpFile = null;
+ try
+ {
+ tmpFile = File.createTempFile("QpidLog4JConfiguratorTestLog4jConfig", ".tmp");
+ tmpFile.deleteOnExit();
+
+ FileWriter fstream = new FileWriter(tmpFile);
+ BufferedWriter writer = new BufferedWriter(fstream);
+
+ writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+NEWLINE);
+ writer.write("<!DOCTYPE log4j:configuration SYSTEM \"log4j.dtd\">"+NEWLINE);
+
+ writer.write("<log4j:configuration xmlns:log4j=\"http://jakarta.apache.org/log4j/\" debug=\"null\" " +
+ "threshold=\"null\">"+NEWLINE);
+
+ writer.write(" <appender class=\"org.apache.log4j.ConsoleAppender\" name=\"STDOUT\">"+NEWLINE);
+ writer.write(" <layout class=\"org.apache.log4j.PatternLayout\">"+NEWLINE);
+ writer.write(" <param name=\"ConversionPattern\" value=\"%d %-5p [%t] %C{2} (%F:%L) - %m%n\"/>"+NEWLINE);
+ writer.write(" </layout>"+NEWLINE);
+ writer.write(" </appender>"+NEWLINE);
+
+ String closeTag="/";
+ if(missingTagClose)
+ {
+ closeTag="";
+ }
+
+ //Example of a 'category' with a 'priority'
+ writer.write(" <category additivity=\"true\" name=\"logger1\">"+NEWLINE);
+ writer.write(" <priority value=\"" + loggerLevel+ "\"" + closeTag + ">"+NEWLINE);
+ writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE);
+ writer.write(" </category>"+NEWLINE);
+
+ String attributeName="value";
+ if(incorrectAttribute)
+ {
+ attributeName="values";
+ }
+
+ //Example of a 'category' with a 'level'
+ writer.write(" <category additivity=\"true\" name=\"logger2\">"+NEWLINE);
+ writer.write(" <level " + attributeName + "=\"" + loggerLevel+ "\"/>"+NEWLINE);
+ writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE);
+ writer.write(" </category>"+NEWLINE);
+
+ //Example of a 'logger' with a 'level'
+ writer.write(" <logger additivity=\"true\" name=\"logger3\">"+NEWLINE);
+ writer.write(" <level value=\"" + loggerLevel+ "\"/>"+NEWLINE);
+ writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE);
+ writer.write(" </logger>"+NEWLINE);
+
+ //'root' logger
+ writer.write(" <root>"+NEWLINE);
+ writer.write(" <priority value=\"" + rootLoggerLevel+ "\"/>"+NEWLINE);
+ writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE);
+ writer.write(" </root>"+NEWLINE);
+
+ writer.write("</log4j:configuration>"+NEWLINE);
+
+ writer.flush();
+ writer.close();
+ }
+ catch (IOException e)
+ {
+ fail("Unable to create temporary test log4j configuration");
+ }
+
+ return tmpFile;
+ }
+
+
+
+ //******* Test Methods ******* //
+
+ public void testCheckLevelsAndStrictParser()
+ {
+ //try the valid logger levels
+ _testConfigFile = createTempTestLog4JConfig("all", "info", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ }
+ catch (Exception e)
+ {
+ fail("No exception expected, valid levels and xml were used");
+ }
+
+ _testConfigFile = createTempTestLog4JConfig("trace", "info", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ }
+ catch (Exception e)
+ {
+ fail("No exception expected, valid levels and xml were used");
+ }
+
+ _testConfigFile = createTempTestLog4JConfig("debug", "info", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ }
+ catch (Exception e)
+ {
+ fail("No exception expected, valid levels and xml were used");
+ }
+
+ _testConfigFile = createTempTestLog4JConfig("info", "info", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ }
+ catch (Exception e)
+ {
+ fail("No exception expected, valid levels and xml were used");
+ }
+
+ _testConfigFile = createTempTestLog4JConfig("warn", "info", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ }
+ catch (Exception e)
+ {
+ fail("No exception expected, valid levels and xml were used");
+ }
+
+ _testConfigFile = createTempTestLog4JConfig("error", "info", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ }
+ catch (Exception e)
+ {
+ fail("No exception expected, valid levels and xml were used");
+ }
+
+ _testConfigFile = createTempTestLog4JConfig("fatal", "info", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ }
+ catch (Exception e)
+ {
+ fail("No exception expected, valid levels and xml were used");
+ }
+
+ _testConfigFile = createTempTestLog4JConfig("off", "info", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ }
+ catch (Exception e)
+ {
+ fail("No exception expected, valid levels and xml were used");
+ }
+
+ _testConfigFile = createTempTestLog4JConfig("null", "info", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ }
+ catch (Exception e)
+ {
+ fail("No exception expected, valid levels and xml were used");
+ }
+
+ _testConfigFile = createTempTestLog4JConfig("inherited", "info", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ }
+ catch (Exception e)
+ {
+ fail("No exception expected, valid levels and xml were used");
+ }
+
+ //now try an invalid logger level
+ _testConfigFile = createTempTestLog4JConfig("madeup", "info", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ fail("IllegalLoggerLevelException expected, invalid levels used");
+ }
+ catch (IllegalLoggerLevelException e)
+ {
+ //expected, ignore
+ }
+ catch (IOException e)
+ {
+ fail("Incorrect Exception, expected an IllegalLoggerLevelException");
+ }
+
+
+
+ //now try the valid rootLogger levels
+ _testConfigFile = createTempTestLog4JConfig("info", "all", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ }
+ catch (Exception e)
+ {
+ fail("No exception expected, valid levels and xml were used");
+ }
+
+ _testConfigFile = createTempTestLog4JConfig("info", "trace", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ }
+ catch (Exception e)
+ {
+ fail("No exception expected, valid levels and xml were used");
+ }
+
+ _testConfigFile = createTempTestLog4JConfig("info", "debug", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ }
+ catch (Exception e)
+ {
+ fail("No exception expected, valid levels and xml were used");
+ }
+
+ _testConfigFile = createTempTestLog4JConfig("info", "info", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ }
+ catch (Exception e)
+ {
+ fail("No exception expected, valid levels and xml were used");
+ }
+
+ _testConfigFile = createTempTestLog4JConfig("info", "warn", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ }
+ catch (Exception e)
+ {
+ fail("No exception expected, valid levels and xml were used");
+ }
+
+ _testConfigFile = createTempTestLog4JConfig("info", "error", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ }
+ catch (Exception e)
+ {
+ fail("No exception expected, valid levels and xml were used");
+ }
+
+ _testConfigFile = createTempTestLog4JConfig("info", "fatal", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ }
+ catch (Exception e)
+ {
+ fail("No exception expected, valid levels and xml were used");
+ }
+
+ _testConfigFile = createTempTestLog4JConfig("info", "off", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ }
+ catch (Exception e)
+ {
+ fail("No exception expected, valid levels and xml were used");
+ }
+
+ _testConfigFile = createTempTestLog4JConfig("info", "null", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ }
+ catch (Exception e)
+ {
+ fail("No exception expected, valid levels and xml were used");
+ }
+
+ _testConfigFile = createTempTestLog4JConfig("info", "inherited", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ }
+ catch (Exception e)
+ {
+ fail("No exception expected, valid levels and xml were used");
+ }
+
+ _testConfigFile = createTempTestLog4JConfig("info", "debug", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ }
+ catch (Exception e)
+ {
+ fail("No exception expected, valid levels and xml were used");
+ }
+
+ //now try an invalid logger level
+ _testConfigFile = createTempTestLog4JConfig("info", "madeup", false, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ fail("IllegalLoggerLevelException expected, invalid levels used");
+ }
+ catch (IllegalLoggerLevelException e)
+ {
+ //expected, ignore
+ }
+ catch (IOException e)
+ {
+ fail("Incorrect Exception, expected an IllegalLoggerLevelException");
+ }
+
+
+
+ //now try invalid xml
+ _testConfigFile = createTempTestLog4JConfig("info", "info", true, false);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ fail("IOException expected, malformed XML used");
+ }
+ catch (IllegalLoggerLevelException e)
+ {
+ fail("Incorrect Exception, expected an IOException");
+ }
+ catch (IOException e)
+ {
+ //expected, ignore
+ }
+
+ _testConfigFile = createTempTestLog4JConfig("info", "info", false, true);
+ try
+ {
+ QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath());
+ fail("IOException expected, malformed XML used");
+ }
+ catch (IllegalLoggerLevelException e)
+ {
+ //expected, ignore
+ }
+ catch (IOException e)
+ {
+ fail("Incorrect Exception, expected an IllegalLoggerLevelException");
+ }
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java b/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java
new file mode 100644
index 0000000000..3cdb9c0c2d
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java
@@ -0,0 +1,99 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server;
+
+import junit.framework.TestCase;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.server.exchange.ExchangeRegistry;
+import org.apache.qpid.server.queue.QueueRegistry;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.registry.IApplicationRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHostImpl;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+public class AMQBrokerManagerMBeanTest extends TestCase
+{
+ private QueueRegistry _queueRegistry;
+ private ExchangeRegistry _exchangeRegistry;
+ private VirtualHost _vHost;
+
+ public void testExchangeOperations() throws Exception
+ {
+ String exchange1 = "testExchange1_" + System.currentTimeMillis();
+ String exchange2 = "testExchange2_" + System.currentTimeMillis();
+ String exchange3 = "testExchange3_" + System.currentTimeMillis();
+
+ assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange1)) == null);
+ assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange2)) == null);
+ assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange3)) == null);
+
+
+ ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHostImpl.VirtualHostMBean) _vHost.getManagedObject());
+ mbean.createNewExchange(exchange1, "direct", false);
+ mbean.createNewExchange(exchange2, "topic", false);
+ mbean.createNewExchange(exchange3, "headers", false);
+
+ assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange1)) != null);
+ assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange2)) != null);
+ assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange3)) != null);
+
+ mbean.unregisterExchange(exchange1);
+ mbean.unregisterExchange(exchange2);
+ mbean.unregisterExchange(exchange3);
+
+ assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange1)) == null);
+ assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange2)) == null);
+ assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange3)) == null);
+ }
+
+ public void testQueueOperations() throws Exception
+ {
+ String queueName = "testQueue_" + System.currentTimeMillis();
+
+ ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHostImpl.VirtualHostMBean) _vHost.getManagedObject());
+
+ assertTrue(_queueRegistry.getQueue(new AMQShortString(queueName)) == null);
+
+ mbean.createNewQueue(queueName, "test", false);
+ assertTrue(_queueRegistry.getQueue(new AMQShortString(queueName)) != null);
+
+ mbean.deleteQueue(queueName);
+ assertTrue(_queueRegistry.getQueue(new AMQShortString(queueName)) == null);
+ }
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ IApplicationRegistry appRegistry = ApplicationRegistry.getInstance();
+ _vHost = appRegistry.getVirtualHostRegistry().getVirtualHost("test");
+ _queueRegistry = _vHost.getQueueRegistry();
+ _exchangeRegistry = _vHost.getExchangeRegistry();
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ //Ensure we close the opened Registry
+ ApplicationRegistry.remove();
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/ExtractResendAndRequeueTest.java b/java/broker/src/test/java/org/apache/qpid/server/ExtractResendAndRequeueTest.java
new file mode 100644
index 0000000000..d2408ba21f
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/ExtractResendAndRequeueTest.java
@@ -0,0 +1,255 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server;
+
+import junit.framework.TestCase;
+import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.queue.SimpleQueueEntryList;
+import org.apache.qpid.server.queue.MockAMQMessage;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.MockAMQQueue;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.queue.QueueEntryIterator;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.subscription.MockSubscription;
+import org.apache.qpid.server.store.MemoryMessageStore;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.AMQException;
+
+import java.util.Map;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+
+/**
+ * QPID-1385 : Race condition between added to unacked map and resending due to a rollback.
+ *
+ * In AMQChannel _unackedMap.clear() was done after the visit. This meant that the clear was not in the same
+ * synchronized block as as the preparation to resend.
+ *
+ * This clearing/prep for resend was done as a result of the rollback call. HOWEVER, the delivery thread was still
+ * in the process of sending messages to the client. It is therefore possible that a message could block on the
+ * _unackedMap lock waiting for the visit to compelete so that it can add the new message to the unackedMap....
+ * which is then cleared by the resend/rollback thread.
+ *
+ * This problem was encountered by the testSend2ThenRollback test.
+ *
+ * To try and increase the chance of the race condition occuring this test will send multiple messages so that the
+ * delivery thread will be in progress while the rollback method is called. Hopefully this will cause the
+ * deliveryTag to be lost
+ */
+public class ExtractResendAndRequeueTest extends TestCase
+{
+
+ UnacknowledgedMessageMapImpl _unacknowledgedMessageMap;
+ private static final int INITIAL_MSG_COUNT = 10;
+ private AMQQueue _queue = new MockAMQQueue(getName());
+ private MessageStore _messageStore = new MemoryMessageStore();
+ private LinkedList<QueueEntry> _referenceList = new LinkedList<QueueEntry>();
+
+ @Override
+ public void setUp() throws AMQException
+ {
+ _unacknowledgedMessageMap = new UnacknowledgedMessageMapImpl(100);
+
+ long id = 0;
+ SimpleQueueEntryList list = new SimpleQueueEntryList(_queue);
+
+ // Add initial messages to QueueEntryList
+ for (int count = 0; count < INITIAL_MSG_COUNT; count++)
+ {
+ AMQMessage msg = new MockAMQMessage(id);
+
+ list.add(msg);
+
+ //Increment ID;
+ id++;
+ }
+
+ // Iterate through the QueueEntryList and add entries to unacknowledgeMessageMap and referecenList
+ QueueEntryIterator queueEntries = list.iterator();
+ while(queueEntries.advance())
+ {
+ QueueEntry entry = queueEntries.getNode();
+ _unacknowledgedMessageMap.add(entry.getMessage().getMessageNumber(), entry);
+
+ // Store the entry for future inspection
+ _referenceList.add(entry);
+ }
+
+ assertEquals("Map does not contain correct setup data", INITIAL_MSG_COUNT, _unacknowledgedMessageMap.size());
+ }
+
+ /**
+ * Helper method to create a new subscription and aquire the given messages.
+ *
+ * @param messageList The messages to aquire
+ *
+ * @return Subscription that performed the aquire
+ */
+ private Subscription createSubscriptionAndAquireMessages(LinkedList<QueueEntry> messageList)
+ {
+ Subscription subscription = new MockSubscription();
+
+ // Aquire messages in subscription
+ for (QueueEntry entry : messageList)
+ {
+ entry.acquire(subscription);
+ }
+
+ return subscription;
+ }
+
+ /**
+ * This is the normal consumer rollback method.
+ *
+ * An active consumer that has aquired messages expects those messasges to be reset when rollback is requested.
+ *
+ * This test validates that the msgToResend map includes all the messages and none are left behind.
+ *
+ * @throws AMQException the visit interface throws this
+ */
+ public void testResend() throws AMQException
+ {
+ //We don't need the subscription object here.
+ createSubscriptionAndAquireMessages(_referenceList);
+
+ final Map<Long, QueueEntry> msgToRequeue = new LinkedHashMap<Long, QueueEntry>();
+ final Map<Long, QueueEntry> msgToResend = new LinkedHashMap<Long, QueueEntry>();
+
+ // requeueIfUnabletoResend doesn't matter here.
+ _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, msgToRequeue,
+ msgToResend, true, _messageStore));
+
+ assertEquals("Message count for resend not correct.", INITIAL_MSG_COUNT, msgToResend.size());
+ assertEquals("Message count for requeue not correct.", 0, msgToRequeue.size());
+ assertEquals("Map was not emptied", 0, _unacknowledgedMessageMap.size());
+ }
+
+ /**
+ * This is the normal consumer close method.
+ *
+ * When a consumer that has aquired messages expects closes the messages that it has aquired should be removed from
+ * the unacknowledgeMap and placed in msgToRequeue
+ *
+ * This test validates that the msgToRequeue map includes all the messages and none are left behind.
+ *
+ * @throws AMQException the visit interface throws this
+ */
+ public void testRequeueDueToSubscriptionClosure() throws AMQException
+ {
+ Subscription subscription = createSubscriptionAndAquireMessages(_referenceList);
+
+ // Close subscription
+ subscription.close();
+
+ final Map<Long, QueueEntry> msgToRequeue = new LinkedHashMap<Long, QueueEntry>();
+ final Map<Long, QueueEntry> msgToResend = new LinkedHashMap<Long, QueueEntry>();
+
+ // requeueIfUnabletoResend doesn't matter here.
+ _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, msgToRequeue,
+ msgToResend, true, _messageStore));
+
+ assertEquals("Message count for resend not correct.", 0, msgToResend.size());
+ assertEquals("Message count for requeue not correct.", INITIAL_MSG_COUNT, msgToRequeue.size());
+ assertEquals("Map was not emptied", 0, _unacknowledgedMessageMap.size());
+ }
+
+ /**
+ * If the subscription is null, due to message being retrieved via a GET, And we request that messages are requeued
+ * requeueIfUnabletoResend(set to true) then all messages should be sent to the msgToRequeue map.
+ *
+ * @throws AMQException the visit interface throws this
+ */
+
+ public void testRequeueDueToMessageHavingNoConsumerTag() throws AMQException
+ {
+ final Map<Long, QueueEntry> msgToRequeue = new LinkedHashMap<Long, QueueEntry>();
+ final Map<Long, QueueEntry> msgToResend = new LinkedHashMap<Long, QueueEntry>();
+
+ // requeueIfUnabletoResend = true so all messages should go to msgToRequeue
+ _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, msgToRequeue,
+ msgToResend, true, _messageStore));
+
+ assertEquals("Message count for resend not correct.", 0, msgToResend.size());
+ assertEquals("Message count for requeue not correct.", INITIAL_MSG_COUNT, msgToRequeue.size());
+ assertEquals("Map was not emptied", 0, _unacknowledgedMessageMap.size());
+ }
+
+ /**
+ * If the subscription is null, due to message being retrieved via a GET, And we request that we don't
+ * requeueIfUnabletoResend(set to false) then all messages should be dropped as we do not have a dead letter queue.
+ *
+ * @throws AMQException the visit interface throws this
+ */
+
+ public void testDrop() throws AMQException
+ {
+ final Map<Long, QueueEntry> msgToRequeue = new LinkedHashMap<Long, QueueEntry>();
+ final Map<Long, QueueEntry> msgToResend = new LinkedHashMap<Long, QueueEntry>();
+
+ // requeueIfUnabletoResend = false so all messages should be dropped all maps should be empty
+ _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, msgToRequeue,
+ msgToResend, false, _messageStore));
+
+ assertEquals("Message count for resend not correct.", 0, msgToResend.size());
+ assertEquals("Message count for requeue not correct.", 0, msgToRequeue.size());
+ assertEquals("Map was not emptied", 0, _unacknowledgedMessageMap.size());
+
+
+ for (QueueEntry entry : _referenceList)
+ {
+ assertTrue("Message was not discarded", entry.isDeleted());
+ }
+
+ }
+
+ /**
+ * If the subscription is null, due to message being retrieved via a GET, AND the queue upon which the message was
+ * delivered has been deleted then it is not possible to requeue. Currently we simply discar the message but in the
+ * future we may wish to dead letter the message.
+ *
+ * Validate that at the end of the visit all Maps are empty and all messages are marked as deleted
+ *
+ * @throws AMQException the visit interface throws this
+ */
+ public void testDiscard() throws AMQException
+ {
+ final Map<Long, QueueEntry> msgToRequeue = new LinkedHashMap<Long, QueueEntry>();
+ final Map<Long, QueueEntry> msgToResend = new LinkedHashMap<Long, QueueEntry>();
+
+ _queue.delete();
+
+ // requeueIfUnabletoResend : value doesn't matter here as queue has been deleted
+ _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, msgToRequeue,
+ msgToResend, false, _messageStore));
+
+ assertEquals("Message count for resend not correct.", 0, msgToResend.size());
+ assertEquals("Message count for requeue not correct.", 0, msgToRequeue.size());
+ assertEquals("Map was not emptied", 0, _unacknowledgedMessageMap.size());
+
+ for (QueueEntry entry : _referenceList)
+ {
+ assertTrue("Message was not discarded", entry.isDeleted());
+ }
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/RunBrokerWithCommand.java b/java/broker/src/test/java/org/apache/qpid/server/RunBrokerWithCommand.java
index d8b5f5f7e6..59543874b4 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/RunBrokerWithCommand.java
+++ b/java/broker/src/test/java/org/apache/qpid/server/RunBrokerWithCommand.java
@@ -32,7 +32,7 @@ public class RunBrokerWithCommand
{
public static void main(String[] args)
{
- //Start broker
+ //Start the broker
try
{
String[] fudge = args.clone();
diff --git a/java/broker/src/test/java/org/apache/qpid/server/configuration/QueueConfigurationTest.java b/java/broker/src/test/java/org/apache/qpid/server/configuration/QueueConfigurationTest.java
new file mode 100644
index 0000000000..9692cf2727
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/configuration/QueueConfigurationTest.java
@@ -0,0 +1,136 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.configuration;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.configuration.PropertiesConfiguration;
+
+public class QueueConfigurationTest extends TestCase
+{
+
+ private VirtualHostConfiguration _emptyConf;
+ private PropertiesConfiguration _env;
+ private ServerConfiguration _fullServerConf;
+ private VirtualHostConfiguration _fullHostConf;
+
+ public void setUp() throws Exception
+ {
+ _env = new PropertiesConfiguration();
+ _emptyConf = new VirtualHostConfiguration("test", _env);
+
+ PropertiesConfiguration fullEnv = new PropertiesConfiguration();
+ fullEnv.setProperty("queues.maximumMessageAge", 1);
+ fullEnv.setProperty("queues.maximumQueueDepth", 1);
+ fullEnv.setProperty("queues.maximumMessageSize", 1);
+ fullEnv.setProperty("queues.maximumMessageCount", 1);
+ fullEnv.setProperty("queues.minimumAlertRepeatGap", 1);
+
+ _fullHostConf = new VirtualHostConfiguration("test", fullEnv);
+
+ }
+
+ public void testGetMaximumMessageAge()
+ {
+ // Check default value
+ QueueConfiguration qConf = new QueueConfiguration("test", _env, _emptyConf);
+ assertEquals(0, qConf.getMaximumMessageAge());
+
+ // Check explicit value
+ PropertiesConfiguration fullEnv = new PropertiesConfiguration();
+ fullEnv.setProperty("maximumMessageAge", 2);
+ qConf = new QueueConfiguration("test", fullEnv, _fullHostConf);
+ assertEquals(2, qConf.getMaximumMessageAge());
+
+ // Check inherited value
+ qConf = new QueueConfiguration("test", _env, _fullHostConf);
+ assertEquals(1, qConf.getMaximumMessageAge());
+ }
+
+ public void testGetMaximumQueueDepth()
+ {
+ // Check default value
+ QueueConfiguration qConf = new QueueConfiguration("test", _env, _emptyConf);
+ assertEquals(0, qConf.getMaximumQueueDepth());
+
+ // Check explicit value
+ PropertiesConfiguration fullEnv = new PropertiesConfiguration();
+ fullEnv.setProperty("maximumQueueDepth", 2);
+ qConf = new QueueConfiguration("test", fullEnv, _fullHostConf);
+ assertEquals(2, qConf.getMaximumQueueDepth());
+
+ // Check inherited value
+ qConf = new QueueConfiguration("test", _env, _fullHostConf);
+ assertEquals(1, qConf.getMaximumQueueDepth());
+ }
+
+ public void testGetMaximumMessageSize()
+ {
+ // Check default value
+ QueueConfiguration qConf = new QueueConfiguration("test", _env, _emptyConf);
+ assertEquals(0, qConf.getMaximumMessageSize());
+
+ // Check explicit value
+ PropertiesConfiguration fullEnv = new PropertiesConfiguration();
+ fullEnv.setProperty("maximumMessageSize", 2);
+ qConf = new QueueConfiguration("test", fullEnv, _fullHostConf);
+ assertEquals(2, qConf.getMaximumMessageSize());
+
+ // Check inherited value
+ qConf = new QueueConfiguration("test", _env, _fullHostConf);
+ assertEquals(1, qConf.getMaximumMessageSize());
+ }
+
+ public void testGetMaximumMessageCount()
+ {
+ // Check default value
+ QueueConfiguration qConf = new QueueConfiguration("test", _env, _emptyConf);
+ assertEquals(0, qConf.getMaximumMessageCount());
+
+ // Check explicit value
+ PropertiesConfiguration fullEnv = new PropertiesConfiguration();
+ fullEnv.setProperty("maximumMessageCount", 2);
+ qConf = new QueueConfiguration("test", fullEnv, _fullHostConf);
+ assertEquals(2, qConf.getMaximumMessageCount());
+
+ // Check inherited value
+ qConf = new QueueConfiguration("test", _env, _fullHostConf);
+ assertEquals(1, qConf.getMaximumMessageCount());
+ }
+
+ public void testGetMinimumAlertRepeatGap()
+ {
+ // Check default value
+ QueueConfiguration qConf = new QueueConfiguration("test", _env, _emptyConf);
+ assertEquals(0, qConf.getMinimumAlertRepeatGap());
+
+ // Check explicit value
+ PropertiesConfiguration fullEnv = new PropertiesConfiguration();
+ fullEnv.setProperty("minimumAlertRepeatGap", 2);
+ qConf = new QueueConfiguration("test", fullEnv, _fullHostConf);
+ assertEquals(2, qConf.getMinimumAlertRepeatGap());
+
+ // Check inherited value
+ qConf = new QueueConfiguration("test", _env, _fullHostConf);
+ assertEquals(1, qConf.getMinimumAlertRepeatGap());
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java b/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java
new file mode 100644
index 0000000000..89b825b270
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java
@@ -0,0 +1,1049 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.configuration;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Collections;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.qpid.server.protocol.AMQProtocolEngine;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
+import org.apache.qpid.transport.TestNetworkDriver;
+
+public class ServerConfigurationTest extends TestCase
+{
+
+ private XMLConfiguration _config;
+
+ @Override
+ public void setUp()
+ {
+ //Highlight that this test will cause a new AR to be created
+ ApplicationRegistry.getInstance();
+
+ _config = new XMLConfiguration();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ //Correctly Close the AR we created
+ ApplicationRegistry.remove();
+ }
+
+ public void testSetJMXManagementPort() throws ConfigurationException
+ {
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ serverConfig.setJMXManagementPort(23);
+ assertEquals(23, serverConfig.getJMXManagementPort());
+ }
+
+ public void testGetJMXManagementPort() throws ConfigurationException
+ {
+ _config.setProperty("management.jmxport", 42);
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(42, serverConfig.getJMXManagementPort());
+ }
+
+ public void testGetPlatformMbeanserver() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getPlatformMbeanserver());
+
+ // Check value we set
+ _config.setProperty("management.platform-mbeanserver", false);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getPlatformMbeanserver());
+ }
+
+ public void testGetPluginDirectory() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(null, serverConfig.getPluginDirectory());
+
+ // Check value we set
+ _config.setProperty("plugin-directory", "/path/to/plugins");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals("/path/to/plugins", serverConfig.getPluginDirectory());
+ }
+
+ public void testGetPrincipalDatabaseNames() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(0, serverConfig.getPrincipalDatabaseNames().size());
+
+ // Check value we set
+ _config.setProperty("security.principal-databases.principal-database(0).name", "a");
+ _config.setProperty("security.principal-databases.principal-database(1).name", "b");
+ serverConfig = new ServerConfiguration(_config);
+ List<String> dbs = serverConfig.getPrincipalDatabaseNames();
+ assertEquals(2, dbs.size());
+ assertEquals("a", dbs.get(0));
+ assertEquals("b", dbs.get(1));
+ }
+
+ public void testGetPrincipalDatabaseClass() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(0, serverConfig.getPrincipalDatabaseClass().size());
+
+ // Check value we set
+ _config.setProperty("security.principal-databases.principal-database(0).class", "a");
+ _config.setProperty("security.principal-databases.principal-database(1).class", "b");
+ serverConfig = new ServerConfiguration(_config);
+ List<String> dbs = serverConfig.getPrincipalDatabaseClass();
+ assertEquals(2, dbs.size());
+ assertEquals("a", dbs.get(0));
+ assertEquals("b", dbs.get(1));
+ }
+
+ public void testGetPrincipalDatabaseAttributeNames() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(0, serverConfig.getPrincipalDatabaseAttributeNames(1).size());
+
+ // Check value we set
+ _config.setProperty("security.principal-databases.principal-database(0).attributes(0).attribute.name", "a");
+ _config.setProperty("security.principal-databases.principal-database(0).attributes(1).attribute.name", "b");
+ serverConfig = new ServerConfiguration(_config);
+ List<String> dbs = serverConfig.getPrincipalDatabaseAttributeNames(0);
+ assertEquals(2, dbs.size());
+ assertEquals("a", dbs.get(0));
+ assertEquals("b", dbs.get(1));
+ }
+
+ public void testGetPrincipalDatabaseAttributeValues() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(0, serverConfig.getPrincipalDatabaseAttributeValues(1).size());
+
+ // Check value we set
+ _config.setProperty("security.principal-databases.principal-database(0).attributes(0).attribute.value", "a");
+ _config.setProperty("security.principal-databases.principal-database(0).attributes(1).attribute.value", "b");
+ serverConfig = new ServerConfiguration(_config);
+ List<String> dbs = serverConfig.getPrincipalDatabaseAttributeValues(0);
+ assertEquals(2, dbs.size());
+ assertEquals("a", dbs.get(0));
+ assertEquals("b", dbs.get(1));
+ }
+
+ public void testGetManagementAccessList() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(0, serverConfig.getManagementAccessList().size());
+
+ // Check value we set
+ _config.setProperty("security.jmx.access(0)", "a");
+ _config.setProperty("security.jmx.access(1)", "b");
+ serverConfig = new ServerConfiguration(_config);
+ List<String> dbs = serverConfig.getManagementAccessList();
+ assertEquals(2, dbs.size());
+ assertEquals("a", dbs.get(0));
+ assertEquals("b", dbs.get(1));
+ }
+
+ public void testGetFrameSize() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(65536, serverConfig.getFrameSize());
+
+ // Check value we set
+ _config.setProperty("advanced.framesize", "23");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(23, serverConfig.getFrameSize());
+ }
+
+ public void testGetProtectIOEnabled() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getProtectIOEnabled());
+
+ // Check value we set
+ _config.setProperty(ServerConfiguration.CONNECTOR_PROTECTIO_ENABLED, true);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getProtectIOEnabled());
+ }
+
+ public void testGetBufferReadLimit() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(262144, serverConfig.getBufferReadLimit());
+
+ // Check value we set
+ _config.setProperty(ServerConfiguration.CONNECTOR_PROTECTIO_READ_BUFFER_LIMIT_SIZE, 23);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(23, serverConfig.getBufferReadLimit());
+ }
+
+ public void testGetBufferWriteLimit() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(262144, serverConfig.getBufferWriteLimit());
+
+ // Check value we set
+ _config.setProperty(ServerConfiguration.CONNECTOR_PROTECTIO_WRITE_BUFFER_LIMIT_SIZE, 23);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(23, serverConfig.getBufferWriteLimit());
+ }
+
+
+ public void testGetStatusEnabled() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(ServerConfiguration.DEFAULT_STATUS_UPDATES.equalsIgnoreCase("on"),
+ serverConfig.getStatusUpdatesEnabled());
+
+ // Check disabling we set
+ _config.setProperty(ServerConfiguration.STATUS_UPDATES, "off");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getStatusUpdatesEnabled());
+
+ // Check invalid values don't cause error but result in disabled
+ _config.setProperty(ServerConfiguration.STATUS_UPDATES, "Yes Please");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getStatusUpdatesEnabled());
+
+ }
+ public void testGetSynchedClocks() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getSynchedClocks());
+
+ // Check value we set
+ _config.setProperty("advanced.synced-clocks", true);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getSynchedClocks());
+ }
+
+ public void testGetLocale() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+
+ // The Default is what ever the VMs default is
+ Locale defaultLocale = Locale.getDefault();
+
+ assertEquals(defaultLocale, serverConfig.getLocale());
+
+
+ //Test Language only
+ Locale update = new Locale("es");
+ _config.setProperty(ServerConfiguration.ADVANCED_LOCALE, "es");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(update, serverConfig.getLocale());
+
+ //Test Language and Country
+ update = new Locale("es","ES");
+ _config.setProperty(ServerConfiguration.ADVANCED_LOCALE, "es_ES");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(update, serverConfig.getLocale());
+
+ //Test Language and Country and Variant
+ update = new Locale("es","ES", "Traditional_WIN");
+ _config.setProperty(ServerConfiguration.ADVANCED_LOCALE, "es_ES_Traditional_WIN");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(update, serverConfig.getLocale());
+ }
+
+
+ public void testGetMsgAuth() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getMsgAuth());
+
+ // Check value we set
+ _config.setProperty("security.msg-auth", true);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getMsgAuth());
+ }
+
+ public void testGetJMXPrincipalDatabase() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(null, serverConfig.getJMXPrincipalDatabase());
+
+ // Check value we set
+ _config.setProperty("security.jmx.principal-database", "a");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals("a", serverConfig.getJMXPrincipalDatabase());
+ }
+
+ public void testGetManagementKeyStorePath() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(null, serverConfig.getManagementKeyStorePath());
+
+ // Check value we set
+ _config.setProperty("management.ssl.keyStorePath", "a");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals("a", serverConfig.getManagementKeyStorePath());
+ }
+
+ public void testGetManagementSSLEnabled() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getManagementSSLEnabled());
+
+ // Check value we set
+ _config.setProperty("management.ssl.enabled", false);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getManagementSSLEnabled());
+ }
+
+ public void testGetManagementKeyStorePassword() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(null, serverConfig.getManagementKeyStorePassword());
+
+ // Check value we set
+ _config.setProperty("management.ssl.keyStorePassword", "a");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals("a", serverConfig.getManagementKeyStorePassword());
+ }
+
+ public void testGetQueueAutoRegister() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getQueueAutoRegister());
+
+ // Check value we set
+ _config.setProperty("queue.auto_register", false);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getQueueAutoRegister());
+ }
+
+ public void testGetManagementEnabled() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getManagementEnabled());
+
+ // Check value we set
+ _config.setProperty("management.enabled", false);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getManagementEnabled());
+ }
+
+ public void testSetManagementEnabled() throws ConfigurationException
+ {
+ // Check value we set
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ serverConfig.setManagementEnabled(false);
+ assertEquals(false, serverConfig.getManagementEnabled());
+ }
+
+ public void testGetHeartBeatDelay() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(5, serverConfig.getHeartBeatDelay());
+
+ // Check value we set
+ _config.setProperty("heartbeat.delay", 23);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(23, serverConfig.getHeartBeatDelay());
+ }
+
+ public void testGetHeartBeatTimeout() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(2.0, serverConfig.getHeartBeatTimeout());
+
+ // Check value we set
+ _config.setProperty("heartbeat.timeoutFactor", 2.3);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(2.3, serverConfig.getHeartBeatTimeout());
+ }
+
+ public void testGetMaximumMessageAge() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(0, serverConfig.getMaximumMessageAge());
+
+ // Check value we set
+ _config.setProperty("maximumMessageAge", 10L);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(10, serverConfig.getMaximumMessageAge());
+ }
+
+ public void testGetMaximumMessageCount() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(0, serverConfig.getMaximumMessageCount());
+
+ // Check value we set
+ _config.setProperty("maximumMessageCount", 10L);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(10, serverConfig.getMaximumMessageCount());
+ }
+
+ public void testGetMaximumQueueDepth() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(0, serverConfig.getMaximumQueueDepth());
+
+ // Check value we set
+ _config.setProperty("maximumQueueDepth", 10L);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(10, serverConfig.getMaximumQueueDepth());
+ }
+
+ public void testGetMaximumMessageSize() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(0, serverConfig.getMaximumMessageSize());
+
+ // Check value we set
+ _config.setProperty("maximumMessageSize", 10L);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(10, serverConfig.getMaximumMessageSize());
+ }
+
+ public void testGetMinimumAlertRepeatGap() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(0, serverConfig.getMinimumAlertRepeatGap());
+
+ // Check value we set
+ _config.setProperty("minimumAlertRepeatGap", 10L);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(10, serverConfig.getMinimumAlertRepeatGap());
+ }
+
+ public void testGetProcessors() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(4, serverConfig.getProcessors());
+
+ // Check value we set
+ _config.setProperty("connector.processors", 10);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(10, serverConfig.getProcessors());
+ }
+
+ public void testGetPort() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertNotNull(serverConfig.getPorts());
+ assertEquals(1, serverConfig.getPorts().size());
+ assertEquals(5672, serverConfig.getPorts().get(0));
+
+
+ // Check value we set
+ _config.setProperty("connector.port", "10");
+ serverConfig = new ServerConfiguration(_config);
+ assertNotNull(serverConfig.getPorts());
+ assertEquals(1, serverConfig.getPorts().size());
+ assertEquals("10", serverConfig.getPorts().get(0));
+ }
+
+ public void testGetBind() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals("wildcard", serverConfig.getBind());
+
+ // Check value we set
+ _config.setProperty("connector.bind", "a");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals("a", serverConfig.getBind());
+ }
+
+ public void testGetReceiveBufferSize() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(32767, serverConfig.getReceiveBufferSize());
+
+ // Check value we set
+ _config.setProperty("connector.socketReceiveBuffer", "23");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(23, serverConfig.getReceiveBufferSize());
+ }
+
+ public void testGetWriteBufferSize() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(32767, serverConfig.getWriteBufferSize());
+
+ // Check value we set
+ _config.setProperty("connector.socketWriteBuffer", "23");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(23, serverConfig.getWriteBufferSize());
+ }
+
+ public void testGetTcpNoDelay() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getTcpNoDelay());
+
+ // Check value we set
+ _config.setProperty("connector.tcpNoDelay", false);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getTcpNoDelay());
+ }
+
+ public void testGetEnableExecutorPool() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getEnableExecutorPool());
+
+ // Check value we set
+ _config.setProperty("advanced.filterchain[@enableExecutorPool]", true);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getEnableExecutorPool());
+ }
+
+ public void testGetEnablePooledAllocator() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getEnablePooledAllocator());
+
+ // Check value we set
+ _config.setProperty("advanced.enablePooledAllocator", true);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getEnablePooledAllocator());
+ }
+
+ public void testGetEnableDirectBuffers() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getEnableDirectBuffers());
+
+ // Check value we set
+ _config.setProperty("advanced.enableDirectBuffers", true);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getEnableDirectBuffers());
+ }
+
+ public void testGetEnableSSL() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getEnableSSL());
+
+ // Check value we set
+ _config.setProperty("connector.ssl.enabled", true);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getEnableSSL());
+ }
+
+ public void testGetSSLOnly() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getSSLOnly());
+
+ // Check value we set
+ _config.setProperty("connector.ssl.sslOnly", true);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getSSLOnly());
+ }
+
+ public void testGetSSLPort() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(8672, serverConfig.getSSLPort());
+
+ // Check value we set
+ _config.setProperty("connector.ssl.port", 23);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(23, serverConfig.getSSLPort());
+ }
+
+ public void testGetKeystorePath() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals("none", serverConfig.getKeystorePath());
+
+ // Check value we set
+ _config.setProperty("connector.ssl.keystorePath", "a");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals("a", serverConfig.getKeystorePath());
+ }
+
+ public void testGetKeystorePassword() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals("none", serverConfig.getKeystorePassword());
+
+ // Check value we set
+ _config.setProperty("connector.ssl.keystorePassword", "a");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals("a", serverConfig.getKeystorePassword());
+ }
+
+ public void testGetCertType() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals("SunX509", serverConfig.getCertType());
+
+ // Check value we set
+ _config.setProperty("connector.ssl.certType", "a");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals("a", serverConfig.getCertType());
+ }
+
+ public void testGetQpidNIO() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getQpidNIO());
+
+ // Check value we set
+ _config.setProperty("connector.qpidnio", true);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getQpidNIO());
+ }
+
+ public void testGetUseBiasedWrites() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getUseBiasedWrites());
+
+ // Check value we set
+ _config.setProperty("advanced.useWriteBiasedPool", true);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getUseBiasedWrites());
+ }
+
+ public void testGetHousekeepingExpiredMessageCheckPeriod() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(30000, serverConfig.getHousekeepingCheckPeriod());
+
+ // Check value we set
+ _config.setProperty("housekeeping.expiredMessageCheckPeriod", 23L);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(23, serverConfig.getHousekeepingCheckPeriod());
+ serverConfig.setHousekeepingExpiredMessageCheckPeriod(42L);
+ assertEquals(42, serverConfig.getHousekeepingCheckPeriod());
+ }
+
+ public void testSingleConfiguration() throws IOException, ConfigurationException
+ {
+ File fileA = File.createTempFile(getClass().getName(), null);
+ fileA.deleteOnExit();
+ FileWriter out = new FileWriter(fileA);
+ out.write("<broker><connector><port>2342</port><ssl><port>4235</port></ssl></connector></broker>");
+ out.close();
+ ServerConfiguration conf = new ServerConfiguration(fileA);
+ assertEquals(4235, conf.getSSLPort());
+ }
+
+ public void testCombinedConfiguration() throws IOException, ConfigurationException
+ {
+ File mainFile = File.createTempFile(getClass().getName(), null);
+ File fileA = File.createTempFile(getClass().getName(), null);
+ File fileB = File.createTempFile(getClass().getName(), null);
+
+ mainFile.deleteOnExit();
+ fileA.deleteOnExit();
+ fileB.deleteOnExit();
+
+ FileWriter out = new FileWriter(mainFile);
+ out.write("<configuration><system/>");
+ out.write("<xml fileName=\"" + fileA.getAbsolutePath() + "\"/>");
+ out.write("<xml fileName=\"" + fileB.getAbsolutePath() + "\"/>");
+ out.write("</configuration>");
+ out.close();
+
+ out = new FileWriter(fileA);
+ out.write("<broker><connector><port>2342</port><ssl><port>4235</port></ssl></connector></broker>");
+ out.close();
+
+ out = new FileWriter(fileB);
+ out.write("<broker><connector><ssl><port>2345</port></ssl><qpidnio>true</qpidnio></connector></broker>");
+ out.close();
+
+ ServerConfiguration config = new ServerConfiguration(mainFile.getAbsoluteFile());
+ assertEquals(4235, config.getSSLPort()); // From first file, not
+ // overriden by second
+ assertNotNull(config.getPorts());
+ assertEquals(1, config.getPorts().size());
+ assertEquals("2342", config.getPorts().get(0)); // From the first file, not
+ // present in the second
+ assertEquals(true, config.getQpidNIO()); // From the second file, not
+ // present in the first
+ }
+
+ public void testVariableInterpolation() throws Exception
+ {
+ File mainFile = File.createTempFile(getClass().getName(), null);
+
+ mainFile.deleteOnExit();
+
+ FileWriter out = new FileWriter(mainFile);
+ out.write("<broker>\n");
+ out.write("\t<work>foo</work>\n");
+ out.write("\t<management><ssl><keyStorePath>${work}</keyStorePath></ssl></management>\n");
+ out.write("</broker>\n");
+ out.close();
+
+ ServerConfiguration config = new ServerConfiguration(mainFile.getAbsoluteFile());
+ assertEquals("Did not get correct interpolated value",
+ "foo", config.getManagementKeyStorePath());
+ }
+
+ public void testFirewallConfiguration() throws Exception
+ {
+ // Write out config
+ File mainFile = File.createTempFile(getClass().getName(), null);
+ mainFile.deleteOnExit();
+ FileWriter out;
+ writeConfigFile(mainFile, false);
+
+ // Load config
+ ApplicationRegistry reg = new ConfigurationFileApplicationRegistry(mainFile);
+ ApplicationRegistry.initialise(reg, 1);
+
+ // Test config
+ VirtualHostRegistry virtualHostRegistry = reg.getVirtualHostRegistry();
+ VirtualHost virtualHost = virtualHostRegistry.getVirtualHost("test");
+
+ TestNetworkDriver testDriver = new TestNetworkDriver();
+ testDriver.setRemoteAddress("127.0.0.1");
+
+ AMQProtocolEngine session = new AMQProtocolEngine(virtualHostRegistry, testDriver);
+ assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost));
+
+ testDriver.setRemoteAddress("127.1.2.3");
+ session = new AMQProtocolEngine(virtualHostRegistry, testDriver);
+ assertTrue(reg.getAccessManager().authoriseConnect(session, virtualHost));
+ }
+
+ public void testCombinedConfigurationFirewall() throws Exception
+ {
+ // Write out config
+ File mainFile = File.createTempFile(getClass().getName(), null);
+ File fileA = File.createTempFile(getClass().getName(), null);
+ File fileB = File.createTempFile(getClass().getName(), null);
+
+ mainFile.deleteOnExit();
+ fileA.deleteOnExit();
+ fileB.deleteOnExit();
+
+ FileWriter out = new FileWriter(mainFile);
+ out.write("<configuration><system/>");
+ out.write("<xml fileName=\"" + fileA.getAbsolutePath() + "\"/>");
+ out.write("</configuration>");
+ out.close();
+
+ out = new FileWriter(fileA);
+ out.write("<broker>\n");
+ out.write("\t<management><enabled>false</enabled></management>\n");
+ out.write("\t<security>\n");
+ out.write("\t\t<principal-databases>\n");
+ out.write("\t\t\t<principal-database>\n");
+ out.write("\t\t\t\t<name>passwordfile</name>\n");
+ out.write("\t\t\t\t<class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>\n");
+ out.write("\t\t\t\t<attributes>\n");
+ out.write("\t\t\t\t\t<attribute>\n");
+ out.write("\t\t\t\t\t\t<name>passwordFile</name>\n");
+ out.write("\t\t\t\t\t\t<value>/dev/null</value>\n");
+ out.write("\t\t\t\t\t</attribute>\n");
+ out.write("\t\t\t\t</attributes>\n");
+ out.write("\t\t\t</principal-database>\n");
+ out.write("\t\t</principal-databases>\n");
+ out.write("\t\t<jmx>\n");
+ out.write("\t\t\t<access>/dev/null</access>\n");
+ out.write("\t\t\t<principal-database>passwordfile</principal-database>\n");
+ out.write("\t\t</jmx>\n");
+ out.write("\t\t<firewall>\n");
+ out.write("\t\t\t<xml fileName=\"" + fileB.getAbsolutePath() + "\"/>");
+ out.write("\t\t</firewall>\n");
+ out.write("\t</security>\n");
+ out.write("\t<virtualhosts>\n");
+ out.write("\t\t<virtualhost>\n");
+ out.write("\t\t\t<name>test</name>\n");
+ out.write("\t\t</virtualhost>\n");
+ out.write("\t</virtualhosts>\n");
+ out.write("</broker>\n");
+ out.close();
+
+ out = new FileWriter(fileB);
+ out.write("<firewall>\n");
+ out.write("\t<rule access=\"deny\" network=\"127.0.0.1\"/>");
+ out.write("</firewall>\n");
+ out.close();
+
+ // Load config
+ ApplicationRegistry reg = new ConfigurationFileApplicationRegistry(mainFile);
+ ApplicationRegistry.initialise(reg, 1);
+
+ // Test config
+ VirtualHostRegistry virtualHostRegistry = reg.getVirtualHostRegistry();
+ VirtualHost virtualHost = virtualHostRegistry.getVirtualHost("test");
+
+ TestNetworkDriver testDriver = new TestNetworkDriver();
+ testDriver.setRemoteAddress("127.0.0.1");
+
+ AMQProtocolEngine session = new AMQProtocolEngine(virtualHostRegistry, testDriver);
+ session.setNetworkDriver(testDriver);
+ assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost));
+ }
+
+ public void testConfigurationFirewallReload() throws Exception
+ {
+ // Write out config
+ File mainFile = File.createTempFile(getClass().getName(), null);
+
+ mainFile.deleteOnExit();
+ writeConfigFile(mainFile, false);
+
+ // Load config
+ ApplicationRegistry reg = new ConfigurationFileApplicationRegistry(mainFile);
+ ApplicationRegistry.initialise(reg, 1);
+
+ // Test config
+ TestNetworkDriver testDriver = new TestNetworkDriver();
+ testDriver.setRemoteAddress("127.0.0.1");
+ VirtualHostRegistry virtualHostRegistry = reg.getVirtualHostRegistry();
+ VirtualHost virtualHost = virtualHostRegistry.getVirtualHost("test");
+ AMQProtocolSession session = new AMQProtocolEngine(virtualHostRegistry, testDriver);
+
+ assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost));
+
+ // Switch to deny the connection
+ writeConfigFile(mainFile, true);
+
+ reg.getConfiguration().reparseConfigFileSecuritySections();
+
+ assertTrue(reg.getAccessManager().authoriseConnect(session, virtualHost));
+
+ }
+
+ private void writeConfigFile(File mainFile, boolean allow) throws IOException {
+ FileWriter out = new FileWriter(mainFile);
+ out.write("<broker>\n");
+ out.write("\t<management><enabled>false</enabled></management>\n");
+ out.write("\t<security>\n");
+ out.write("\t\t<principal-databases>\n");
+ out.write("\t\t\t<principal-database>\n");
+ out.write("\t\t\t\t<name>passwordfile</name>\n");
+ out.write("\t\t\t\t<class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>\n");
+ out.write("\t\t\t\t<attributes>\n");
+ out.write("\t\t\t\t\t<attribute>\n");
+ out.write("\t\t\t\t\t\t<name>passwordFile</name>\n");
+ out.write("\t\t\t\t\t\t<value>/dev/null</value>\n");
+ out.write("\t\t\t\t\t</attribute>\n");
+ out.write("\t\t\t\t</attributes>\n");
+ out.write("\t\t\t</principal-database>\n");
+ out.write("\t\t</principal-databases>\n");
+ out.write("\t\t<jmx>\n");
+ out.write("\t\t\t<access>/dev/null</access>\n");
+ out.write("\t\t\t<principal-database>passwordfile</principal-database>\n");
+ out.write("\t\t</jmx>\n");
+ out.write("\t\t<firewall>\n");
+ out.write("\t\t\t<rule access=\""+ ((allow) ? "allow" : "deny") +"\" network=\"127.0.0.1\"/>");
+ out.write("\t\t</firewall>\n");
+ out.write("\t</security>\n");
+ out.write("\t<virtualhosts>\n");
+ out.write("\t\t<virtualhost>\n");
+ out.write("\t\t\t<name>test</name>\n");
+ out.write("\t\t</virtualhost>\n");
+ out.write("\t</virtualhosts>\n");
+ out.write("</broker>\n");
+ out.close();
+ }
+
+ public void testCombinedConfigurationFirewallReload() throws Exception
+ {
+ // Write out config
+ File mainFile = File.createTempFile(getClass().getName(), null);
+ File fileA = File.createTempFile(getClass().getName(), null);
+ File fileB = File.createTempFile(getClass().getName(), null);
+
+ mainFile.deleteOnExit();
+ fileA.deleteOnExit();
+ fileB.deleteOnExit();
+
+ FileWriter out = new FileWriter(mainFile);
+ out.write("<configuration><system/>");
+ out.write("<xml fileName=\"" + fileA.getAbsolutePath() + "\"/>");
+ out.write("</configuration>");
+ out.close();
+
+ out = new FileWriter(fileA);
+ out.write("<broker>\n");
+ out.write("\t<management><enabled>false</enabled></management>\n");
+ out.write("\t<security>\n");
+ out.write("\t\t<principal-databases>\n");
+ out.write("\t\t\t<principal-database>\n");
+ out.write("\t\t\t\t<name>passwordfile</name>\n");
+ out.write("\t\t\t\t<class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>\n");
+ out.write("\t\t\t\t<attributes>\n");
+ out.write("\t\t\t\t\t<attribute>\n");
+ out.write("\t\t\t\t\t\t<name>passwordFile</name>\n");
+ out.write("\t\t\t\t\t\t<value>/dev/null</value>\n");
+ out.write("\t\t\t\t\t</attribute>\n");
+ out.write("\t\t\t\t</attributes>\n");
+ out.write("\t\t\t</principal-database>\n");
+ out.write("\t\t</principal-databases>\n");
+ out.write("\t\t<jmx>\n");
+ out.write("\t\t\t<access>/dev/null</access>\n");
+ out.write("\t\t\t<principal-database>passwordfile</principal-database>\n");
+ out.write("\t\t</jmx>\n");
+ out.write("\t\t<firewall>\n");
+ out.write("\t\t\t<xml fileName=\"" + fileB.getAbsolutePath() + "\"/>");
+ out.write("\t\t</firewall>\n");
+ out.write("\t</security>\n");
+ out.write("\t<virtualhosts>\n");
+ out.write("\t\t<virtualhost>\n");
+ out.write("\t\t\t<name>test</name>\n");
+ out.write("\t\t</virtualhost>\n");
+ out.write("\t</virtualhosts>\n");
+ out.write("</broker>\n");
+ out.close();
+
+ out = new FileWriter(fileB);
+ out.write("<firewall>\n");
+ out.write("\t<rule access=\"deny\" network=\"127.0.0.1\"/>");
+ out.write("</firewall>\n");
+ out.close();
+
+ // Load config
+ ApplicationRegistry reg = new ConfigurationFileApplicationRegistry(mainFile);
+ ApplicationRegistry.initialise(reg, 1);
+
+ // Test config
+ TestNetworkDriver testDriver = new TestNetworkDriver();
+ testDriver.setRemoteAddress("127.0.0.1");
+ VirtualHostRegistry virtualHostRegistry = reg.getVirtualHostRegistry();
+ VirtualHost virtualHost = virtualHostRegistry.getVirtualHost("test");
+ AMQProtocolSession session = new AMQProtocolEngine(virtualHostRegistry, testDriver);
+ assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost));
+
+ RandomAccessFile fileBRandom = new RandomAccessFile(fileB, "rw");
+ fileBRandom.setLength(0);
+ fileBRandom.seek(0);
+ fileBRandom.close();
+
+ out = new FileWriter(fileB);
+ out.write("<firewall>\n");
+ out.write("\t<rule access=\"allow\" network=\"127.0.0.1\"/>");
+ out.write("</firewall>\n");
+ out.close();
+
+ reg.getConfiguration().reparseConfigFileSecuritySections();
+
+ assertTrue(reg.getAccessManager().authoriseConnect(session, virtualHost));
+
+ fileBRandom = new RandomAccessFile(fileB, "rw");
+ fileBRandom.setLength(0);
+ fileBRandom.seek(0);
+ fileBRandom.close();
+
+ out = new FileWriter(fileB);
+ out.write("<firewall>\n");
+ out.write("\t<rule access=\"deny\" network=\"127.0.0.1\"/>");
+ out.write("</firewall>\n");
+ out.close();
+
+ reg.getConfiguration().reparseConfigFileSecuritySections();
+
+ assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost));
+ }
+
+ public void testnewParserOutputVsOldParserOutput() throws ConfigurationException
+ {
+ String configDir = System.getProperty("QPID_HOME")+"/etc";
+
+ XMLConfiguration oldConfig = new XMLConfiguration(configDir +"/config-systests-ServerConfigurationTest-Old.xml");
+ Configuration newConfig = new ServerConfiguration(new File(configDir+"/config-systests-ServerConfigurationTest-New.xml")).getConfig();
+
+ Iterator xmlKeys = oldConfig.getKeys();
+ while (xmlKeys.hasNext())
+ {
+ String key = (String) xmlKeys.next();
+ assertEquals("Incorrect value for "+key, oldConfig.getProperty(key), newConfig.getProperty(key));
+ }
+ }
+
+
+ public void testNoVirtualhostXMLFile() throws Exception
+ {
+ int REGISTRY=1;
+
+ File configFile = new File(System.getProperty("QPID_HOME")+"/etc/config.xml");
+ assertTrue(configFile.exists());
+
+ ApplicationRegistry.initialise(new ConfigurationFileApplicationRegistry(configFile), REGISTRY);
+
+ VirtualHostRegistry virtualHostRegistry = ApplicationRegistry.getInstance(REGISTRY).getVirtualHostRegistry();
+
+ assertEquals("Incorrect virtualhost count", 3 , virtualHostRegistry.getVirtualHosts().size());
+ }
+
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java b/java/broker/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java
new file mode 100644
index 0000000000..b65020395c
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.configuration;
+
+
+import junit.framework.TestCase;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.queue.AMQPriorityQueue;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.virtualhost.VirtualHostImpl;
+
+public class VirtualHostConfigurationTest extends TestCase
+{
+
+ private VirtualHostConfiguration vhostConfig;
+ private XMLConfiguration configXml;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ //Highlight that this test will cause a new AR to be created
+ ApplicationRegistry.getInstance();
+ // Fill config file with stuff
+ configXml = new XMLConfiguration();
+ configXml.setRootElementName("virtualhosts");
+ configXml.addProperty("virtualhost(-1).name", "test");
+ }
+
+ public void tearDown() throws Exception
+ {
+ //Correctly close the AR we created
+ ApplicationRegistry.remove();
+
+ super.tearDown();
+ }
+
+ public void testQueuePriority() throws Exception
+ {
+ // Set up queue with 5 priorities
+ configXml.addProperty("virtualhost.test.queues(-1).queue(-1).name(-1)",
+ "atest");
+ configXml.addProperty("virtualhost.test.queues.queue.atest(-1).exchange",
+ "amq.direct");
+ configXml.addProperty("virtualhost.test.queues.queue.atest.priorities",
+ "5");
+
+ // Set up queue with JMS style priorities
+ configXml.addProperty("virtualhost.test.queues(-1).queue(-1).name(-1)",
+ "ptest");
+ configXml.addProperty("virtualhost.test.queues.queue.ptest(-1).exchange",
+ "amq.direct");
+ configXml.addProperty("virtualhost.test.queues.queue.ptest.priority",
+ "true");
+
+ // Set up queue with no priorities
+ configXml.addProperty("virtualhost.test.queues(-1).queue(-1).name(-1)",
+ "ntest");
+ configXml.addProperty("virtualhost.test.queues.queue.ntest(-1).exchange",
+ "amq.direct");
+ configXml.addProperty("virtualhost.test.queues.queue.ntest.priority",
+ "false");
+
+ VirtualHost vhost = new VirtualHostImpl(new VirtualHostConfiguration("test", configXml.subset("virtualhost.test")));
+
+ // Check that atest was a priority queue with 5 priorities
+ AMQQueue atest = vhost.getQueueRegistry().getQueue(new AMQShortString("atest"));
+ assertTrue(atest instanceof AMQPriorityQueue);
+ assertEquals(5, ((AMQPriorityQueue) atest).getPriorities());
+
+ // Check that ptest was a priority queue with 10 priorities
+ AMQQueue ptest = vhost.getQueueRegistry().getQueue(new AMQShortString("ptest"));
+ assertTrue(ptest instanceof AMQPriorityQueue);
+ assertEquals(10, ((AMQPriorityQueue) ptest).getPriorities());
+
+ // Check that ntest wasn't a priority queue
+ AMQQueue ntest = vhost.getQueueRegistry().getQueue(new AMQShortString("ntest"));
+ assertFalse(ntest instanceof AMQPriorityQueue);
+ }
+
+ public void testQueueAlerts() throws Exception
+ {
+ // Set up queue with 5 priorities
+ configXml.addProperty("virtualhost.test.queues.exchange", "amq.topic");
+ configXml.addProperty("virtualhost.test.queues.maximumQueueDepth", "1");
+ configXml.addProperty("virtualhost.test.queues.maximumMessageSize", "2");
+ configXml.addProperty("virtualhost.test.queues.maximumMessageAge", "3");
+
+ configXml.addProperty("virtualhost.test.queues(-1).queue(1).name(1)", "atest");
+ configXml.addProperty("virtualhost.test.queues.queue.atest(-1).exchange", "amq.direct");
+ configXml.addProperty("virtualhost.test.queues.queue.atest(-1).maximumQueueDepth", "4");
+ configXml.addProperty("virtualhost.test.queues.queue.atest(-1).maximumMessageSize", "5");
+ configXml.addProperty("virtualhost.test.queues.queue.atest(-1).maximumMessageAge", "6");
+
+ configXml.addProperty("virtualhost.test.queues(-1).queue(-1).name(-1)", "btest");
+
+ VirtualHost vhost = new VirtualHostImpl(new VirtualHostConfiguration("test", configXml.subset("virtualhost.test")));
+
+ // Check specifically configured values
+ AMQQueue aTest = vhost.getQueueRegistry().getQueue(new AMQShortString("atest"));
+ assertEquals(4, aTest.getMaximumQueueDepth());
+ assertEquals(5, aTest.getMaximumMessageSize());
+ assertEquals(6, aTest.getMaximumMessageAge());
+
+ // Check default values
+ AMQQueue bTest = vhost.getQueueRegistry().getQueue(new AMQShortString("btest"));
+ assertEquals(1, bTest.getMaximumQueueDepth());
+ assertEquals(2, bTest.getMaximumMessageSize());
+ assertEquals(3, bTest.getMaximumMessageAge());
+
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java b/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java
new file mode 100644
index 0000000000..e26b5b048c
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java
@@ -0,0 +1,575 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.exchange;
+
+import junit.framework.TestCase;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.*;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.server.queue.*;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.MemoryMessageStore;
+import org.apache.qpid.server.store.StoredMessage;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.message.AMQMessageHeader;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.message.MessageMetaData;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.log4j.Logger;
+
+import java.util.*;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class AbstractHeadersExchangeTestBase extends TestCase
+{
+ private static final Logger _log = Logger.getLogger(AbstractHeadersExchangeTestBase.class);
+
+ private final HeadersExchange exchange = new HeadersExchange();
+ protected final Set<TestQueue> queues = new HashSet<TestQueue>();
+
+ /**
+ * Not used in this test, just there to stub out the routing calls
+ */
+ private MessageStore _store = new MemoryMessageStore();
+
+ private int count;
+
+ public void testDoNothing()
+ {
+ // this is here only to make junit under Eclipse happy
+ }
+
+ protected TestQueue bindDefault(String... bindings) throws AMQException
+ {
+ return bind("Queue" + (++count), bindings);
+ }
+
+ protected TestQueue bind(String queueName, String... bindings) throws AMQException
+ {
+ return bind(queueName, getHeaders(bindings));
+ }
+
+ protected TestQueue bind(String queue, FieldTable bindings) throws AMQException
+ {
+ return bind(new TestQueue(new AMQShortString(queue)), bindings);
+ }
+
+ protected TestQueue bind(TestQueue queue, String... bindings) throws AMQException
+ {
+ return bind(queue, getHeaders(bindings));
+ }
+
+ protected TestQueue bind(TestQueue queue, FieldTable bindings) throws AMQException
+ {
+ queues.add(queue);
+ exchange.registerQueue(null, queue, bindings);
+ return queue;
+ }
+
+
+ protected int route(Message m) throws AMQException
+ {
+ m.getIncomingMessage().headersReceived();
+ m.route(exchange);
+ if(m.getIncomingMessage().allContentReceived())
+ {
+ for(AMQQueue q : m.getIncomingMessage().getDestinationQueues())
+ {
+ q.enqueue(m);
+ }
+ }
+ return m.getIncomingMessage().getDestinationQueues().size();
+ }
+
+ protected void routeAndTest(Message m, TestQueue... expected) throws AMQException
+ {
+ routeAndTest(m, false, Arrays.asList(expected));
+ }
+
+ protected void routeAndTest(Message m, boolean expectReturn, TestQueue... expected) throws AMQException
+ {
+ routeAndTest(m, expectReturn, Arrays.asList(expected));
+ }
+
+ protected void routeAndTest(Message m, List<TestQueue> expected) throws AMQException
+ {
+ routeAndTest(m, false, expected);
+ }
+
+ protected void routeAndTest(Message m, boolean expectReturn, List<TestQueue> expected) throws AMQException
+ {
+ int queueCount = route(m);
+
+ for (TestQueue q : queues)
+ {
+ if (expected.contains(q))
+ {
+ assertTrue("Expected " + m + " to be delivered to " + q, q.isInQueue(m));
+ //assert m.isInQueue(q) : "Expected " + m + " to be delivered to " + q;
+ }
+ else
+ {
+ assertFalse("Did not expect " + m + " to be delivered to " + q, q.isInQueue(m));
+ //assert !m.isInQueue(q) : "Did not expect " + m + " to be delivered to " + q;
+ }
+ }
+
+ if(expectReturn)
+ {
+ assertEquals("Expected "+m+" to be returned due to manadatory flag, and lack of routing",0, queueCount);
+ }
+
+ }
+
+ static FieldTable getHeaders(String... entries)
+ {
+ FieldTable headers = FieldTableFactory.newFieldTable();
+ for (String s : entries)
+ {
+ String[] parts = s.split("=", 2);
+ headers.setObject(parts[0], parts.length > 1 ? parts[1] : "");
+ }
+ return headers;
+ }
+
+
+ static final class MessagePublishInfoImpl implements MessagePublishInfo
+ {
+ private AMQShortString _exchange;
+ private boolean _immediate;
+ private boolean _mandatory;
+ private AMQShortString _routingKey;
+
+ public MessagePublishInfoImpl(AMQShortString routingKey)
+ {
+ _routingKey = routingKey;
+ }
+
+ public MessagePublishInfoImpl(AMQShortString exchange, boolean immediate, boolean mandatory, AMQShortString routingKey)
+ {
+ _exchange = exchange;
+ _immediate = immediate;
+ _mandatory = mandatory;
+ _routingKey = routingKey;
+ }
+
+ public AMQShortString getExchange()
+ {
+ return _exchange;
+ }
+
+ public boolean isImmediate()
+ {
+ return _immediate;
+
+ }
+
+ public boolean isMandatory()
+ {
+ return _mandatory;
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return _routingKey;
+ }
+
+
+ public void setExchange(AMQShortString exchange)
+ {
+ _exchange = exchange;
+ }
+
+ public void setImmediate(boolean immediate)
+ {
+ _immediate = immediate;
+ }
+
+ public void setMandatory(boolean mandatory)
+ {
+ _mandatory = mandatory;
+ }
+
+ public void setRoutingKey(AMQShortString routingKey)
+ {
+ _routingKey = routingKey;
+ }
+ }
+
+ static MessagePublishInfo getPublishRequest(final String id)
+ {
+ return new MessagePublishInfoImpl(null, false, false, new AMQShortString(id));
+ }
+
+ static ContentHeaderBody getContentHeader(FieldTable headers)
+ {
+ ContentHeaderBody header = new ContentHeaderBody();
+ header.properties = getProperties(headers);
+ return header;
+ }
+
+ static BasicContentHeaderProperties getProperties(FieldTable headers)
+ {
+ BasicContentHeaderProperties properties = new BasicContentHeaderProperties();
+ properties.setHeaders(headers);
+ return properties;
+ }
+
+ static class TestQueue extends SimpleAMQQueue
+ {
+ final List<HeadersExchangeTest.Message> messages = new ArrayList<HeadersExchangeTest.Message>();
+
+ public String toString()
+ {
+ return getName().toString();
+ }
+
+ public TestQueue(AMQShortString name) throws AMQException
+ {
+ super(name, false, new AMQShortString("test"), true, ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test"));
+ ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test").getQueueRegistry().registerQueue(this);
+ }
+
+ /**
+ * We override this method so that the default behaviour, which attempts to use a delivery manager, is
+ * not invoked. It is unnecessary since for this test we only care to know whether the message was
+ * sent to the queue; the queue processing logic is not being tested.
+ * @param msg
+ * @throws AMQException
+ */
+ @Override
+ public QueueEntry enqueue(ServerMessage msg) throws AMQException
+ {
+ messages.add( new HeadersExchangeTest.Message((AMQMessage) msg));
+ return new QueueEntry()
+ {
+
+ public AMQQueue getQueue()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public AMQMessage getMessage()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getSize()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean getDeliveredToConsumer()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean expired() throws AMQException
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isAcquired()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean acquire()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean acquire(Subscription sub)
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean delete()
+ {
+ return false;
+ }
+
+ public boolean isDeleted()
+ {
+ return false;
+ }
+
+ public boolean acquiredBySubscription()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isAcquiredBy(Subscription subscription)
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setDeliveredToSubscription()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void release()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean releaseButRetain()
+ {
+ return false;
+ }
+
+ public boolean immediateAndNotDelivered()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setRedelivered()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public AMQMessageHeader getMessageHeader()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isPersistent()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isRedelivered()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public Subscription getDeliveredSubscription()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void reject()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void reject(Subscription subscription)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isRejectedBy(Subscription subscription)
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void requeue()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void requeue(Subscription subscription)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void dequeue()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void dispose()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void restoreCredit()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void discard()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void routeToAlternate()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isQueueDeleted()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void addStateChangeListener(StateChangeListener listener)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean removeStateChangeListener(StateChangeListener listener)
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int compareTo(final QueueEntry o)
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+ };
+ }
+
+ boolean isInQueue(Message msg)
+ {
+ return messages.contains(msg);
+ }
+
+ }
+
+ /**
+ * Just add some extra utility methods to AMQMessage to aid testing.
+ */
+ static class Message extends AMQMessage
+ {
+ private static AtomicLong _messageId = new AtomicLong();
+
+ private class TestIncomingMessage extends IncomingMessage
+ {
+
+ public TestIncomingMessage(final long messageId,
+ final MessagePublishInfo info,
+ final AMQProtocolSession publisher)
+ {
+ super(info);
+ }
+
+
+ public AMQMessage getUnderlyingMessage()
+ {
+ return Message.this;
+ }
+
+
+ public ContentHeaderBody getContentHeader()
+ {
+ try
+ {
+ return Message.this.getContentHeaderBody();
+ }
+ catch (AMQException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private IncomingMessage _incoming;
+
+
+ Message(AMQProtocolSession protocolSession, String id, String... headers) throws AMQException
+ {
+ this(protocolSession, id, getHeaders(headers));
+ }
+
+ Message(AMQProtocolSession protocolSession, String id, FieldTable headers) throws AMQException
+ {
+ this(protocolSession, _messageId.incrementAndGet(),getPublishRequest(id), getContentHeader(headers), Collections.EMPTY_LIST);
+ }
+
+ public IncomingMessage getIncomingMessage()
+ {
+ return _incoming;
+ }
+
+ private Message(AMQProtocolSession protocolsession, long messageId,
+ MessagePublishInfo publish,
+ ContentHeaderBody header,
+ List<ContentBody> bodies) throws AMQException
+ {
+ super(new MockStoredMessage(messageId, publish, header));
+
+ StoredMessage<MessageMetaData> storedMessage = getStoredMessage();
+
+ int pos = 0;
+ for(ContentBody body : bodies)
+ {
+ storedMessage.addContent(pos, body.payload.duplicate().buf());
+ pos += body.payload.limit();
+ }
+
+ _incoming = new TestIncomingMessage(getMessageId(),publish, protocolsession);
+ _incoming.setContentHeaderBody(header);
+
+
+ }
+
+
+ private Message(AMQMessage msg) throws AMQException
+ {
+ super(msg.getStoredMessage());
+ }
+
+
+
+ void route(Exchange exchange) throws AMQException
+ {
+ _incoming.enqueue(exchange.route(_incoming));
+ }
+
+
+ public int hashCode()
+ {
+ return getKey().hashCode();
+ }
+
+ public boolean equals(Object o)
+ {
+ return o instanceof HeadersExchangeTest.Message && equals((HeadersExchangeTest.Message) o);
+ }
+
+ private boolean equals(HeadersExchangeTest.Message m)
+ {
+ return getKey().equals(m.getKey());
+ }
+
+ public String toString()
+ {
+ return getKey().toString();
+ }
+
+ private Object getKey()
+ {
+ try
+ {
+ return getMessagePublishInfo().getRoutingKey();
+ }
+ catch (AMQException e)
+ {
+ _log.error("Error getting routing key: " + e, e);
+ return null;
+ }
+ }
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/exchange/DestWildExchangeTest.java b/java/broker/src/test/java/org/apache/qpid/server/exchange/DestWildExchangeTest.java
deleted file mode 100644
index a592c9353a..0000000000
--- a/java/broker/src/test/java/org/apache/qpid/server/exchange/DestWildExchangeTest.java
+++ /dev/null
@@ -1,590 +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.
- *
- *
- */
-package org.apache.qpid.server.exchange;
-
-import junit.framework.TestCase;
-import junit.framework.Assert;
-import org.apache.qpid.server.queue.*;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.txn.NonTransactionalContext;
-import org.apache.qpid.server.txn.TransactionalContext;
-import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.MemoryMessageStore;
-import org.apache.qpid.server.store.StoreContext;
-import org.apache.qpid.server.RequiredDeliveryException;
-import org.apache.qpid.server.protocol.InternalTestProtocolSession;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.ContentHeaderBody;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-
-import java.util.LinkedList;
-
-public class DestWildExchangeTest extends TestCase
-{
-
- TopicExchange _exchange;
-
- VirtualHost _vhost;
- MessageStore _store;
- StoreContext _context;
-
- InternalTestProtocolSession _protocolSession;
-
-
- public void setUp() throws AMQException
- {
- _exchange = new TopicExchange();
- _vhost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHosts().iterator().next();
- _store = new MemoryMessageStore();
- _context = new StoreContext();
- _protocolSession = new InternalTestProtocolSession();
- }
-
-
- public void testNoRoute() throws AMQException
- {
- AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a*#b"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.*.#.b"), queue, null);
-
-
- MessagePublishInfo info = new PublishInfo(new AMQShortString("a.b"));
-
- IncomingMessage message = new IncomingMessage(0L, info, null, _protocolSession);
-
- _exchange.route(message);
-
- Assert.assertEquals(0, queue.getMessageCount());
- }
-
- public void testDirectMatch() throws AMQException
- {
- AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("ab"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.b"), queue, null);
-
-
- IncomingMessage message = createMessage("a.b");
-
- try
- {
- routeMessage(message);
- }
- catch (AMQException nre)
- {
- fail("Message has route and should be routed");
- }
-
- Assert.assertEquals(1, queue.getMessageCount());
-
- Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
-
- queue.deleteMessageFromTop(_context);
- Assert.assertEquals(0, queue.getMessageCount());
-
-
- message = createMessage("a.c");
-
- try
- {
- routeMessage(message);
- fail("Message has no route and should fail to be routed");
- }
- catch (AMQException nre)
- {
- }
-
- Assert.assertEquals(0, queue.getMessageCount());
- }
-
-
- public void testStarMatch() throws AMQException
- {
- AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a*"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.*"), queue, null);
-
-
- IncomingMessage message = createMessage("a.b");
-
- try
- {
- routeMessage(message);
- }
- catch (AMQException nre)
- {
- fail("Message has route and should be routed");
- }
-
- Assert.assertEquals(1, queue.getMessageCount());
-
- Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
-
- queue.deleteMessageFromTop(_context);
- Assert.assertEquals(0, queue.getMessageCount());
-
-
- message = createMessage("a.c");
-
- try
- {
- routeMessage(message);
- }
- catch (AMQException nre)
- {
- fail("Message has route and should be routed");
- }
-
- Assert.assertEquals(1, queue.getMessageCount());
-
- Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
-
- queue.deleteMessageFromTop(_context);
- Assert.assertEquals(0, queue.getMessageCount());
-
-
- message = createMessage("a");
-
- try
- {
- routeMessage(message);
- fail("Message has no route and should fail to be routed");
- }
- catch (AMQException nre)
- {
- }
-
- Assert.assertEquals(0, queue.getMessageCount());
- }
-
- public void testHashMatch() throws AMQException
- {
- AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a#"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.#"), queue, null);
-
-
- IncomingMessage message = createMessage("a.b.c");
-
- try
- {
- routeMessage(message);
- }
- catch (AMQException nre)
- {
- fail("Message has route and should be routed");
- }
-
- Assert.assertEquals(1, queue.getMessageCount());
-
- Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
-
- queue.deleteMessageFromTop(_context);
- Assert.assertEquals(0, queue.getMessageCount());
-
-
- message = createMessage("a.b");
-
- try
- {
- routeMessage(message);
- }
- catch (AMQException nre)
- {
- fail("Message has route and should be routed");
- }
-
- Assert.assertEquals(1, queue.getMessageCount());
-
- Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
-
- queue.deleteMessageFromTop(_context);
- Assert.assertEquals(0, queue.getMessageCount());
-
-
- message = createMessage("a.c");
-
- try
- {
- routeMessage(message);
- }
- catch (AMQException nre)
- {
- fail("Message has route and should be routed");
- }
-
- Assert.assertEquals(1, queue.getMessageCount());
-
- Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
-
- queue.deleteMessageFromTop(_context);
- Assert.assertEquals(0, queue.getMessageCount());
-
- message = createMessage("a");
-
- try
- {
- routeMessage(message);
- }
- catch (AMQException nre)
- {
- fail("Message has route and should be routed");
- }
-
- Assert.assertEquals(1, queue.getMessageCount());
-
- Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
-
- queue.deleteMessageFromTop(_context);
- Assert.assertEquals(0, queue.getMessageCount());
-
-
- message = createMessage("b");
-
- try
- {
- routeMessage(message);
- fail("Message has no route and should fail to be routed");
- }
- catch (AMQException nre)
- {
- }
-
- Assert.assertEquals(0, queue.getMessageCount());
- }
-
-
- public void testMidHash() throws AMQException
- {
- AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.*.#.b"), queue, null);
-
-
- IncomingMessage message = createMessage("a.c.d.b");
-
- try
- {
- routeMessage(message);
- }
- catch (AMQException nre)
- {
- fail("Message has no route and should be routed");
- }
-
- Assert.assertEquals(1, queue.getMessageCount());
-
- Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
-
- queue.deleteMessageFromTop(_context);
- Assert.assertEquals(0, queue.getMessageCount());
-
- message = createMessage("a.c.b");
-
- try
- {
- routeMessage(message);
- }
- catch (AMQException nre)
- {
- fail("Message has no route and should be routed");
- }
-
- Assert.assertEquals(1, queue.getMessageCount());
-
- Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
-
- queue.deleteMessageFromTop(_context);
- Assert.assertEquals(0, queue.getMessageCount());
-
- }
-
- public void testMatchafterHash() throws AMQException
- {
- AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a#"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.*.#.b.c"), queue, null);
-
-
- IncomingMessage message = createMessage("a.c.b.b");
-
- try
- {
- routeMessage(message);
- fail("Message has route and should not be routed");
- }
- catch (AMQException nre)
- {
- }
-
- Assert.assertEquals(0, queue.getMessageCount());
-
-
- message = createMessage("a.a.b.c");
-
- try
- {
- routeMessage(message);
- }
- catch (AMQException nre)
- {
- fail("Message has no route and should be routed");
- }
-
- Assert.assertEquals(1, queue.getMessageCount());
-
- Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
-
- queue.deleteMessageFromTop(_context);
- Assert.assertEquals(0, queue.getMessageCount());
-
- message = createMessage("a.b.c.b");
-
- try
- {
- routeMessage(message);
- fail("Message has route and should not be routed");
- }
- catch (AMQException nre)
- {
- }
-
- Assert.assertEquals(0, queue.getMessageCount());
-
- message = createMessage("a.b.c.b.c");
-
- try
- {
- routeMessage(message);
- }
- catch (AMQException nre)
- {
- fail("Message has no route and should be routed");
-
- }
-
- Assert.assertEquals(1, queue.getMessageCount());
-
- Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
-
- queue.deleteMessageFromTop(_context);
- Assert.assertEquals(0, queue.getMessageCount());
-
- }
-
-
- public void testHashAfterHash() throws AMQException
- {
- AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a#"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.*.#.b.c.#.d"), queue, null);
-
-
- IncomingMessage message = createMessage("a.c.b.b.c");
-
- try
- {
- routeMessage(message);
- fail("Message has route and should not be routed");
- }
- catch (AMQException nre)
- {
- }
-
- Assert.assertEquals(0, queue.getMessageCount());
-
-
- message = createMessage("a.a.b.c.d");
-
- try
- {
- routeMessage(message);
- }
- catch (AMQException nre)
- {
- fail("Message has no route and should be routed");
- }
-
- Assert.assertEquals(1, queue.getMessageCount());
-
- Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
-
- queue.deleteMessageFromTop(_context);
- Assert.assertEquals(0, queue.getMessageCount());
-
- }
-
- public void testHashHash() throws AMQException
- {
- AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a#"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.#.*.#.d"), queue, null);
-
-
- IncomingMessage message = createMessage("a.c.b.b.c");
-
- try
- {
- routeMessage(message);
- fail("Message has route and should not be routed");
- }
- catch (AMQException nre)
- {
- }
-
- Assert.assertEquals(0, queue.getMessageCount());
-
- message = createMessage("a.a.b.c.d");
-
- try
- {
- routeMessage(message);
- }
- catch (AMQException nre)
- {
- fail("Message has no route and should be routed");
- }
-
- Assert.assertEquals(1, queue.getMessageCount());
-
- Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
-
- queue.deleteMessageFromTop(_context);
- Assert.assertEquals(0, queue.getMessageCount());
-
- }
-
- public void testSubMatchFails() throws AMQException
- {
- AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.b.c.d"), queue, null);
-
-
- IncomingMessage message = createMessage("a.b.c");
-
- try
- {
- routeMessage(message);
- fail("Message has route and should not be routed");
- }
- catch (AMQException nre)
- {
- }
-
- Assert.assertEquals(0, queue.getMessageCount());
-
- }
-
- private void routeMessage(final IncomingMessage message)
- throws AMQException
- {
- _exchange.route(message);
- message.routingComplete(_store, new MessageHandleFactory());
- message.deliverToQueues();
- }
-
- public void testMoreRouting() throws AMQException
- {
- AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.b"), queue, null);
-
-
- IncomingMessage message = createMessage("a.b.c");
-
- try
- {
- routeMessage(message);
- fail("Message has route and should not be routed");
- }
- catch (AMQException nre)
- {
- }
-
- Assert.assertEquals(0, queue.getMessageCount());
-
- }
-
- public void testMoreQueue() throws AMQException
- {
- AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a"), false, null, false, _vhost, null);
- _exchange.registerQueue(new AMQShortString("a.b"), queue, null);
-
-
- IncomingMessage message = createMessage("a");
-
- try
- {
- routeMessage(message);
- fail("Message has route and should not be routed");
- }
- catch (AMQException nre)
- {
- }
-
- Assert.assertEquals(0, queue.getMessageCount());
-
- }
-
- private IncomingMessage createMessage(String s) throws AMQException
- {
- MessagePublishInfo info = new PublishInfo(new AMQShortString(s));
-
- TransactionalContext trancontext = new NonTransactionalContext(_store, _context, null,
- new LinkedList<RequiredDeliveryException>()
- );
-
- IncomingMessage message = new IncomingMessage(0L, info, trancontext,_protocolSession);
- message.setContentHeaderBody( new ContentHeaderBody());
-
-
- return message;
- }
-
-
- class PublishInfo implements MessagePublishInfo
- {
- AMQShortString _routingkey;
-
- PublishInfo(AMQShortString routingkey)
- {
- _routingkey = routingkey;
- }
-
- public AMQShortString getExchange()
- {
- return null;
- }
-
- public void setExchange(AMQShortString exchange)
- {
-
- }
-
- public boolean isImmediate()
- {
- return false;
- }
-
- public boolean isMandatory()
- {
- return true;
- }
-
- public AMQShortString getRoutingKey()
- {
- return _routingkey;
- }
- }
-}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java b/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java
index 8ce7b4c0e1..016f7eacbe 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java
+++ b/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java
@@ -21,12 +21,15 @@
package org.apache.qpid.server.exchange;
import junit.framework.TestCase;
+
+import org.apache.qpid.management.common.mbeans.ManagedExchange;
import org.apache.qpid.server.queue.QueueRegistry;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.AMQQueueFactory;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.registry.IApplicationRegistry;
import org.apache.qpid.server.management.ManagedObject;
+import org.apache.qpid.server.virtualhost.VirtualHostImpl;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.framing.AMQShortString;
@@ -129,7 +132,7 @@ public class ExchangeMBeanTest extends TestCase
{
super.setUp();
- IApplicationRegistry applicationRegistry = ApplicationRegistry.getInstance(1);
+ IApplicationRegistry applicationRegistry = ApplicationRegistry.getInstance();
_virtualHost = applicationRegistry.getVirtualHostRegistry().getVirtualHost("test");
_queueRegistry = _virtualHost.getQueueRegistry();
_queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue"), false, new AMQShortString("ExchangeMBeanTest"), false, _virtualHost,
@@ -139,7 +142,8 @@ public class ExchangeMBeanTest extends TestCase
protected void tearDown()
{
- ApplicationRegistry.remove(1);
+ // Correctly Close the AR that we created above
+ ApplicationRegistry.remove();
}
}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java b/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java
index 86ba96bf5d..dc47951548 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java
+++ b/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java
@@ -22,16 +22,95 @@ package org.apache.qpid.server.exchange;
import java.util.Map;
import java.util.HashMap;
+import java.util.Set;
import junit.framework.TestCase;
import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.server.message.AMQMessageHeader;
/**
*/
public class HeadersBindingTest extends TestCase
{
+
+ private class MockHeader implements AMQMessageHeader
+ {
+
+ private final Map<String, Object> _headers = new HashMap<String, Object>();
+
+ public String getCorrelationId()
+ {
+ return null;
+ }
+
+ public long getExpiration()
+ {
+ return 0;
+ }
+
+ public String getMessageId()
+ {
+ return null;
+ }
+
+ public String getMimeType()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public String getEncoding()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public byte getPriority()
+ {
+ return 0;
+ }
+
+ public long getTimestamp()
+ {
+ return 0;
+ }
+
+ public String getType()
+ {
+ return null;
+ }
+
+ public String getReplyTo()
+ {
+ return null;
+ }
+
+ public Object getHeader(String name)
+ {
+ return _headers.get(name);
+ }
+
+ public boolean containsHeaders(Set<String> names)
+ {
+ return _headers.keySet().containsAll(names);
+ }
+
+ public boolean containsHeader(String name)
+ {
+ return _headers.containsKey(name);
+ }
+
+ public void setString(String key, String value)
+ {
+ setObject(key,value);
+ }
+
+ public void setObject(String key, Object value)
+ {
+ _headers.put(key,value);
+ }
+ }
+
private FieldTable bindHeaders = new FieldTable();
- private FieldTable matchHeaders = new FieldTable();
+ private MockHeader matchHeaders = new MockHeader();
public void testDefault_1()
{
diff --git a/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersExchangeTest.java b/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersExchangeTest.java
new file mode 100644
index 0000000000..580bc78b8d
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersExchangeTest.java
@@ -0,0 +1,114 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.exchange;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.protocol.InternalTestProtocolSession;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+
+public class HeadersExchangeTest extends AbstractHeadersExchangeTestBase
+{
+ AMQProtocolSession _protocolSession;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ // AR will use the NullAR by default
+ // Just use the first vhost.
+ VirtualHost
+ virtualHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHosts().iterator().next();
+ _protocolSession = new InternalTestProtocolSession(virtualHost);
+ }
+
+ protected void tearDown()
+ {
+ // Correctly Close the AR that we created above
+ ApplicationRegistry.remove();
+ }
+
+ public void testSimple() throws AMQException
+ {
+ TestQueue q1 = bindDefault("F0000");
+ TestQueue q2 = bindDefault("F0000=Aardvark");
+ TestQueue q3 = bindDefault("F0001");
+ TestQueue q4 = bindDefault("F0001=Bear");
+ TestQueue q5 = bindDefault("F0000", "F0001");
+ TestQueue q6 = bindDefault("F0000=Aardvark", "F0001=Bear");
+ TestQueue q7 = bindDefault("F0000", "F0001=Bear");
+ TestQueue q8 = bindDefault("F0000=Aardvark", "F0001");
+
+ routeAndTest(new Message(_protocolSession, "Message1", "F0000"), q1);
+ routeAndTest(new Message(_protocolSession, "Message2", "F0000=Aardvark"), q1, q2);
+ routeAndTest(new Message(_protocolSession, "Message3", "F0000=Aardvark", "F0001"), q1, q2, q3, q5, q8);
+ routeAndTest(new Message(_protocolSession, "Message4", "F0000", "F0001=Bear"), q1, q3, q4, q5, q7);
+ routeAndTest(new Message(_protocolSession, "Message5", "F0000=Aardvark", "F0001=Bear"),
+ q1, q2, q3, q4, q5, q6, q7, q8);
+ routeAndTest(new Message(_protocolSession, "Message6", "F0002"));
+
+ Message m7 = new Message(_protocolSession, "Message7", "XXXXX");
+
+ MessagePublishInfoImpl pb7 = (MessagePublishInfoImpl) (m7.getMessagePublishInfo());
+ pb7.setMandatory(true);
+ routeAndTest(m7,true);
+
+ Message m8 = new Message(_protocolSession, "Message8", "F0000");
+ MessagePublishInfoImpl pb8 = (MessagePublishInfoImpl)(m8.getMessagePublishInfo());
+ pb8.setMandatory(true);
+ routeAndTest(m8,false,q1);
+
+
+ }
+
+ public void testAny() throws AMQException
+ {
+ TestQueue q1 = bindDefault("F0000", "F0001", "X-match=any");
+ TestQueue q2 = bindDefault("F0000=Aardvark", "F0001=Bear", "X-match=any");
+ TestQueue q3 = bindDefault("F0000", "F0001=Bear", "X-match=any");
+ TestQueue q4 = bindDefault("F0000=Aardvark", "F0001", "X-match=any");
+ TestQueue q6 = bindDefault("F0000=Apple", "F0001", "X-match=any");
+
+ routeAndTest(new Message(_protocolSession, "Message1", "F0000"), q1, q3);
+ routeAndTest(new Message(_protocolSession, "Message2", "F0000=Aardvark"), q1, q2, q3, q4);
+ routeAndTest(new Message(_protocolSession, "Message3", "F0000=Aardvark", "F0001"), q1, q2, q3, q4, q6);
+ routeAndTest(new Message(_protocolSession, "Message4", "F0000", "F0001=Bear"), q1, q2, q3, q4, q6);
+ routeAndTest(new Message(_protocolSession, "Message5", "F0000=Aardvark", "F0001=Bear"), q1, q2, q3, q4, q6);
+ routeAndTest(new Message(_protocolSession, "Message6", "F0002"));
+ }
+
+ public void testMandatory() throws AMQException
+ {
+ bindDefault("F0000");
+ Message m1 = new Message(_protocolSession, "Message1", "XXXXX");
+ Message m2 = new Message(_protocolSession, "Message2", "F0000");
+ MessagePublishInfoImpl pb1 = (MessagePublishInfoImpl) (m1.getMessagePublishInfo());
+ pb1.setMandatory(true);
+ MessagePublishInfoImpl pb2 = (MessagePublishInfoImpl) (m2.getMessagePublishInfo());
+ pb2.setMandatory(true);
+ routeAndTest(m1,true);
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(HeadersExchangeTest.class);
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/exchange/TopicExchangeTest.java b/java/broker/src/test/java/org/apache/qpid/server/exchange/TopicExchangeTest.java
new file mode 100644
index 0000000000..9d7a323b6d
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/exchange/TopicExchangeTest.java
@@ -0,0 +1,446 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.exchange;
+
+import junit.framework.TestCase;
+import junit.framework.Assert;
+import org.apache.qpid.server.queue.*;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.MemoryMessageStore;
+import org.apache.qpid.server.protocol.InternalTestProtocolSession;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.message.MessageMetaData;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+
+public class TopicExchangeTest extends TestCase
+{
+
+ TopicExchange _exchange;
+
+ VirtualHost _vhost;
+ MessageStore _store;
+
+ InternalTestProtocolSession _protocolSession;
+
+
+ public void setUp() throws AMQException
+ {
+ _exchange = new TopicExchange();
+ _vhost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHosts().iterator().next();
+ _store = new MemoryMessageStore();
+ _protocolSession = new InternalTestProtocolSession(_vhost);
+ }
+
+ public void tearDown()
+ {
+ ApplicationRegistry.remove();
+ }
+
+
+ public void testNoRoute() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a*#b"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.*.#.b"), queue, null);
+
+
+ MessagePublishInfo info = new PublishInfo(new AMQShortString("a.b"));
+
+ IncomingMessage message = new IncomingMessage(info);
+
+ message.enqueue(_exchange.route(message));
+
+ Assert.assertEquals(0, queue.getMessageCount());
+ }
+
+ public void testDirectMatch() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("ab"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.b"), queue, null);
+
+
+ IncomingMessage message = createMessage("a.b");
+
+ routeMessage(message);
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber());
+
+ queue.deleteMessageFromTop();
+ Assert.assertEquals(0, queue.getMessageCount());
+
+
+ message = createMessage("a.c");
+
+ int queueCount = routeMessage(message);
+ Assert.assertEquals("Message should not route to any queues", 0, queueCount);
+
+ Assert.assertEquals(0, queue.getMessageCount());
+ }
+
+
+ public void testStarMatch() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a*"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.*"), queue, null);
+
+
+ IncomingMessage message = createMessage("a.b");
+
+ routeMessage(message);
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber());
+
+ queue.deleteMessageFromTop();
+ Assert.assertEquals(0, queue.getMessageCount());
+
+
+ message = createMessage("a.c");
+
+ int queueCount = routeMessage(message);
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber());
+
+ queue.deleteMessageFromTop();
+ Assert.assertEquals(0, queue.getMessageCount());
+
+
+ message = createMessage("a");
+
+
+ queueCount = routeMessage(message);
+ Assert.assertEquals("Message should not route to any queues", 0, queueCount);
+
+ Assert.assertEquals(0, queue.getMessageCount());
+ }
+
+ public void testHashMatch() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a#"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.#"), queue, null);
+
+
+ IncomingMessage message = createMessage("a.b.c");
+
+ int queueCount = routeMessage(message);
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber());
+
+ queue.deleteMessageFromTop();
+ Assert.assertEquals(0, queue.getMessageCount());
+
+
+ message = createMessage("a.b");
+
+ queueCount = routeMessage(message);
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber());
+
+ queue.deleteMessageFromTop();
+ Assert.assertEquals(0, queue.getMessageCount());
+
+
+ message = createMessage("a.c");
+
+ queueCount = routeMessage(message);
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber());
+
+ queue.deleteMessageFromTop();
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ message = createMessage("a");
+
+ queueCount = routeMessage(message);
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber());
+
+ queue.deleteMessageFromTop();
+ Assert.assertEquals(0, queue.getMessageCount());
+
+
+ message = createMessage("b");
+
+
+ queueCount = routeMessage(message);
+ Assert.assertEquals("Message should not route to any queues", 0, queueCount);
+
+ Assert.assertEquals(0, queue.getMessageCount());
+ }
+
+
+ public void testMidHash() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.*.#.b"), queue, null);
+
+
+ IncomingMessage message = createMessage("a.c.d.b");
+
+ routeMessage(message);
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber());
+
+ queue.deleteMessageFromTop();
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ message = createMessage("a.c.b");
+
+ routeMessage(message);
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber());
+
+ queue.deleteMessageFromTop();
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ }
+
+ public void testMatchafterHash() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a#"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.*.#.b.c"), queue, null);
+
+
+ IncomingMessage message = createMessage("a.c.b.b");
+
+ int queueCount = routeMessage(message);
+ Assert.assertEquals("Message should not route to any queues", 0, queueCount);
+
+ Assert.assertEquals(0, queue.getMessageCount());
+
+
+ message = createMessage("a.a.b.c");
+
+ routeMessage(message);
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber());
+
+ queue.deleteMessageFromTop();
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ message = createMessage("a.b.c.b");
+
+ queueCount = routeMessage(message);
+ Assert.assertEquals("Message should not route to any queues", 0, queueCount);
+
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ message = createMessage("a.b.c.b.c");
+
+ routeMessage(message);
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber());
+
+ queue.deleteMessageFromTop();
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ }
+
+
+ public void testHashAfterHash() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a#"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.*.#.b.c.#.d"), queue, null);
+
+
+ IncomingMessage message = createMessage("a.c.b.b.c");
+
+ int queueCount = routeMessage(message);
+ Assert.assertEquals("Message should not route to any queues", 0, queueCount);
+
+ Assert.assertEquals(0, queue.getMessageCount());
+
+
+ message = createMessage("a.a.b.c.d");
+
+ routeMessage(message);
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber());
+
+ queue.deleteMessageFromTop();
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ }
+
+ public void testHashHash() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a#"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.#.*.#.d"), queue, null);
+
+
+ IncomingMessage message = createMessage("a.c.b.b.c");
+
+ int queueCount = routeMessage(message);
+ Assert.assertEquals("Message should not route to any queues", 0, queueCount);
+
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ message = createMessage("a.a.b.c.d");
+
+ routeMessage(message);
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber());
+
+ queue.deleteMessageFromTop();
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ }
+
+ public void testSubMatchFails() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.b.c.d"), queue, null);
+
+
+ IncomingMessage message = createMessage("a.b.c");
+
+ int queueCount = routeMessage(message);
+ Assert.assertEquals("Message should not route to any queues", 0, queueCount);
+
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ }
+
+ private int routeMessage(final IncomingMessage message)
+ throws AMQException
+ {
+ MessageMetaData mmd = message.headersReceived();
+ message.setStoredMessage(_store.addMessage(mmd));
+
+ message.enqueue(_exchange.route(message));
+ AMQMessage msg = new AMQMessage(message.getStoredMessage());
+ for(AMQQueue q : message.getDestinationQueues())
+ {
+ q.enqueue(msg);
+ }
+ return message.getDestinationQueues().size();
+ }
+
+ public void testMoreRouting() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.b"), queue, null);
+
+
+ IncomingMessage message = createMessage("a.b.c");
+
+ int queueCount = routeMessage(message);
+ Assert.assertEquals("Message should not route to any queues", 0, queueCount);
+
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ }
+
+ public void testMoreQueue() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.b"), queue, null);
+
+
+ IncomingMessage message = createMessage("a");
+
+ int queueCount = routeMessage(message);
+ Assert.assertEquals("Message should not route to any queues", 0, queueCount);
+
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ }
+
+ private IncomingMessage createMessage(String s) throws AMQException
+ {
+ MessagePublishInfo info = new PublishInfo(new AMQShortString(s));
+
+ IncomingMessage message = new IncomingMessage(info);
+ final ContentHeaderBody chb = new ContentHeaderBody();
+ BasicContentHeaderProperties props = new BasicContentHeaderProperties();
+ chb.properties = props;
+ message.setContentHeaderBody(chb);
+
+
+ return message;
+ }
+
+
+ class PublishInfo implements MessagePublishInfo
+ {
+ AMQShortString _routingkey;
+
+ PublishInfo(AMQShortString routingkey)
+ {
+ _routingkey = routingkey;
+ }
+
+ public AMQShortString getExchange()
+ {
+ return null;
+ }
+
+ public void setExchange(AMQShortString exchange)
+ {
+
+ }
+
+ public boolean isImmediate()
+ {
+ return false;
+ }
+
+ public boolean isMandatory()
+ {
+ return true;
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return _routingkey;
+ }
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/LogMessageTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/LogMessageTest.java
new file mode 100644
index 0000000000..2044627be7
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/LogMessageTest.java
@@ -0,0 +1,71 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging;
+
+import junit.framework.TestCase;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+public class LogMessageTest extends TestCase
+{
+
+ /**
+ * Test that the US local has a loadable bundle.
+ * No longer have a specific en_US bundle so cannot verify that that version
+ * is loaded.
+ */
+ public void testBundle()
+ {
+ Locale usLocal = Locale.US;
+ Locale.setDefault(usLocal);
+ ResourceBundle _messages = ResourceBundle.getBundle("org.apache.qpid.server.logging.messages.LogMessages",
+ usLocal);
+
+ assertNotNull("Unable to load ResourceBundle", _messages);
+ }
+
+ /**
+ * Test that loading an undefined locale will result in loadig of the
+ * default US locale.
+ */
+ public void testUndefinedLocale()
+ {
+ Locale japanese = Locale.JAPANESE;
+
+ Locale.setDefault(japanese);
+ try
+ {
+ ResourceBundle _messages = ResourceBundle.getBundle("org.apache.qpid.server.logging.messages.LogMessages",
+ japanese);
+
+ assertNotNull("Unable to load ResourceBundle", _messages);
+
+ // If we attempt to load an undefined locale it should default to the Root locale.
+ assertEquals("Loaded bundle has incorrect locale.", Locale.ROOT, _messages.getLocale());
+ }
+ catch (Throwable t)
+ {
+ fail(t.getMessage());
+ }
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/RootMessageLoggerImplTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/RootMessageLoggerImplTest.java
new file mode 100644
index 0000000000..012a590687
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/RootMessageLoggerImplTest.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.logging;
+
+import junit.framework.TestCase;
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.logging.rawloggers.UnitTestMessageLogger;
+
+import java.util.List;
+
+public class RootMessageLoggerImplTest extends TestCase
+{
+
+ RootMessageLogger _rootLogger;
+ UnitTestMessageLogger _rawLogger;
+
+ public void setUp() throws ConfigurationException
+ {
+ Configuration config = new PropertiesConfiguration();
+ ServerConfiguration serverConfig = new ServerConfiguration(config);
+
+ _rawLogger = new UnitTestMessageLogger();
+
+ _rootLogger = new RootMessageLoggerImpl(serverConfig, _rawLogger);
+ }
+
+ public void tearDown()
+ {
+ _rawLogger.clearLogMessages();
+ }
+
+ public void testLog()
+ {
+ String message = "test logging";
+
+ _rootLogger.rawMessage(message);
+
+ List<Object> logs = _rawLogger.getLogMessages();
+
+ assertEquals("Message log size not as expected.", 1, logs.size());
+
+ assertTrue(logs.get(0).toString().contains(message));
+ }
+
+ public void testLogWithThrowable()
+ {
+ String message = "test logging";
+ Exception exception = new Exception("Test");
+
+ _rootLogger.rawMessage(message, exception);
+
+ List<Object> logs = _rawLogger.getLogMessages();
+
+ assertEquals("Message log size not as expected.", 2, logs.size());
+
+ String loggedMessage = (String) logs.get(0);
+ assertTrue("Message not found in log:" + loggedMessage,
+ loggedMessage.contains(message));
+
+ Exception fromLog = (Exception) logs.get(1);
+ assertEquals(exception.getMessage(), fromLog.getMessage());
+ }
+
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/actors/AMQPChannelActorTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/actors/AMQPChannelActorTest.java
new file mode 100644
index 0000000000..ad8b25a4ac
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/actors/AMQPChannelActorTest.java
@@ -0,0 +1,269 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.actors;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.logging.rawloggers.UnitTestMessageLogger;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.logging.LogMessage;
+import org.apache.qpid.server.AMQChannel;
+
+import java.util.List;
+
+/**
+ * Test : AMQPChannelActorTest
+ * Validate the AMQPChannelActor class.
+ *
+ * The test creates a new AMQPActor and then logs a message using it.
+ *
+ * The test then verifies that the logged message was the only one created and
+ * that the message contains the required message.
+ */
+public class AMQPChannelActorTest extends BaseConnectionActorTestCase
+{
+
+ AMQChannel _channel;
+
+ @Override
+ protected void setUpWithConfig(ServerConfiguration serverConfig) throws AMQException
+ {
+ super.setUpWithConfig(serverConfig);
+
+ _channel = new AMQChannel(_session, 1, _session.getVirtualHost().getMessageStore());
+
+ _amqpActor = new AMQPChannelActor(_channel, _rootLogger);
+ }
+
+ /**
+ * Test that when logging on behalf of the channel
+ * The test sends a message then verifies that it entered the logs.
+ *
+ * The log message should be fully repalaced (no '{n}' values) and should
+ * contain the channel id ('/ch:1') identification.
+ */
+ public void testChannel()
+ {
+ final String message = sendTestMessage();
+
+ List<Object> logs = _rawLogger.getLogMessages();
+
+ assertEquals("Message log size not as expected.", 1, logs.size());
+
+ // Verify that the logged message is present in the output
+ assertTrue("Message was not found in log message:" + logs.get(0),
+ logs.get(0).toString().contains(message));
+
+ // Verify that the message has the correct type
+ assertTrue("Message contains the [con: prefix",
+ logs.get(0).toString().contains("[con:"));
+
+
+ // Verify that all the values were presented to the MessageFormatter
+ // so we will not end up with '{n}' entries in the log.
+ assertFalse("Verify that the string does not contain any '{'." + logs.get(0),
+ logs.get(0).toString().contains("{"));
+
+ // Verify that the logged message contains the 'ch:1' marker
+ assertTrue("Message was not logged as part of channel 1" + logs.get(0),
+ logs.get(0).toString().contains("/ch:1"));
+
+ }
+
+ /**
+ * Log a message using the test Actor
+ * @return the logged message
+ */
+ private String sendTestMessage()
+ {
+ final String message = "test logging";
+
+ _amqpActor.message(new LogSubject()
+ {
+ public String toString()
+ {
+ return "[AMQPActorTest]";
+ }
+
+ }, new LogMessage()
+ {
+ public String toString()
+ {
+ return message;
+ }
+ });
+ return message;
+ }
+
+ /**
+ * Test that if logging is configured to be off in the configuration that
+ * no logging is presented
+ * @throws ConfigurationException
+ * @throws AMQException
+ */
+ public void testChannelLoggingOFF() throws ConfigurationException, AMQException
+ {
+ Configuration config = new PropertiesConfiguration();
+ config.addProperty("status-updates", "OFF");
+
+ ServerConfiguration serverConfig = new ServerConfiguration(config);
+
+ _rawLogger = new UnitTestMessageLogger();
+
+ setUpWithConfig(serverConfig);
+
+ sendTestMessage();
+
+ List<Object> logs = _rawLogger.getLogMessages();
+
+ assertEquals("Message log size not as expected.", 0, logs.size());
+
+ }
+
+ /**
+ * Test that if logging is configured to be off in the configuration that
+ * no logging is presented
+ * @throws ConfigurationException
+ * @throws AMQException
+ */
+ public void testChannelLoggingOfF() throws ConfigurationException, AMQException
+ {
+ Configuration config = new PropertiesConfiguration();
+ config.addProperty("status-updates", "OfF");
+
+ ServerConfiguration serverConfig = new ServerConfiguration(config);
+
+ _rawLogger = new UnitTestMessageLogger();
+
+ setUpWithConfig(serverConfig);
+
+ sendTestMessage();
+
+ List<Object> logs = _rawLogger.getLogMessages();
+
+ assertEquals("Message log size not as expected.", 0, logs.size());
+
+ }
+
+ /**
+ * Test that if logging is configured to be off in the configuration that
+ * no logging is presented
+ * @throws ConfigurationException
+ * @throws AMQException
+ */
+ public void testChannelLoggingOff() throws ConfigurationException, AMQException
+ {
+ Configuration config = new PropertiesConfiguration();
+ config.addProperty("status-updates", "Off");
+
+ ServerConfiguration serverConfig = new ServerConfiguration(config);
+
+ _rawLogger = new UnitTestMessageLogger();
+
+ setUpWithConfig(serverConfig);
+
+ sendTestMessage();
+
+ List<Object> logs = _rawLogger.getLogMessages();
+
+ assertEquals("Message log size not as expected.", 0, logs.size());
+
+ }
+
+ /**
+ * Test that if logging is configured to be off in the configuration that
+ * no logging is presented
+ * @throws ConfigurationException
+ * @throws AMQException
+ */
+ public void testChannelLoggingofF() throws ConfigurationException, AMQException
+ {
+ Configuration config = new PropertiesConfiguration();
+ config.addProperty("status-updates", "ofF");
+
+ ServerConfiguration serverConfig = new ServerConfiguration(config);
+
+ _rawLogger = new UnitTestMessageLogger();
+
+ setUpWithConfig(serverConfig);
+
+ sendTestMessage();
+
+ List<Object> logs = _rawLogger.getLogMessages();
+
+ assertEquals("Message log size not as expected.", 0, logs.size());
+
+ }
+
+ /**
+ * Test that if logging is configured to be off in the configuration that
+ * no logging is presented
+ * @throws ConfigurationException
+ * @throws AMQException
+ */
+ public void testChannelLoggingoff() throws ConfigurationException, AMQException
+ {
+ Configuration config = new PropertiesConfiguration();
+ config.addProperty("status-updates", "off");
+
+ ServerConfiguration serverConfig = new ServerConfiguration(config);
+
+ _rawLogger = new UnitTestMessageLogger();
+
+ setUpWithConfig(serverConfig);
+
+ sendTestMessage();
+
+ List<Object> logs = _rawLogger.getLogMessages();
+
+ assertEquals("Message log size not as expected.", 0, logs.size());
+
+ }
+
+ /**
+ * Test that if logging is configured to be off in the configuration that
+ * no logging is presented
+ * @throws ConfigurationException
+ * @throws AMQException
+ */
+ public void testChannelLoggingoFf() throws ConfigurationException, AMQException
+ {
+ Configuration config = new PropertiesConfiguration();
+ config.addProperty("status-updates", "oFf");
+
+ ServerConfiguration serverConfig = new ServerConfiguration(config);
+
+ _rawLogger = new UnitTestMessageLogger();
+
+ setUpWithConfig(serverConfig);
+
+ sendTestMessage();
+
+ List<Object> logs = _rawLogger.getLogMessages();
+
+ assertEquals("Message log size not as expected.", 0, logs.size());
+
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/actors/AMQPConnectionActorTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/actors/AMQPConnectionActorTest.java
new file mode 100644
index 0000000000..013677461b
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/actors/AMQPConnectionActorTest.java
@@ -0,0 +1,116 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.actors;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.logging.LogMessage;
+import org.apache.qpid.server.logging.LogSubject;
+
+import java.util.List;
+
+/**
+ * Test : AMQPConnectionActorTest
+ * Validate the AMQPConnectionActor class.
+ *
+ * The test creates a new AMQPActor and then logs a message using it.
+ *
+ * The test then verifies that the logged message was the only one created and
+ * that the message contains the required message.
+ */
+public class AMQPConnectionActorTest extends BaseConnectionActorTestCase
+{
+ /**
+ * Test the AMQPActor logging as a Connection level.
+ *
+ * The test sends a message then verifies that it entered the logs.
+ *
+ * The log message should be fully repalaced (no '{n}' values) and should
+ * not contain any channel identification.
+ */
+ public void testConnection()
+ {
+ final String message = sendLogMessage();
+
+ List<Object> logs = _rawLogger.getLogMessages();
+
+ assertEquals("Message log size not as expected.", 1, logs.size());
+
+ // Verify that the logged message is present in the output
+ assertTrue("Message was not found in log message",
+ logs.get(0).toString().contains(message));
+
+ // Verify that the message has the correct type
+ assertTrue("Message does not contain the [con: prefix",
+ logs.get(0).toString().contains("[con:"));
+
+ // Verify that all the values were presented to the MessageFormatter
+ // so we will not end up with '{n}' entries in the log.
+ assertFalse("Verify that the string does not contain any '{'.",
+ logs.get(0).toString().contains("{"));
+
+ // Verify that the logged message does not contains the 'ch:' marker
+ assertFalse("Message was logged with a channel identifier." + logs.get(0),
+ logs.get(0).toString().contains("/ch:"));
+ }
+
+ public void testConnectionLoggingOff() throws ConfigurationException, AMQException
+ {
+ Configuration config = new PropertiesConfiguration();
+ config.addProperty("status-updates", "OFF");
+
+ ServerConfiguration serverConfig = new ServerConfiguration(config);
+
+ setUpWithConfig(serverConfig);
+
+ sendLogMessage();
+
+ List<Object> logs = _rawLogger.getLogMessages();
+
+ assertEquals("Message log size not as expected.", 0, logs.size());
+
+ }
+
+ private String sendLogMessage()
+ {
+ final String message = "test logging";
+
+ _amqpActor.message(new LogSubject()
+ {
+ public String toString()
+ {
+ return "[AMQPActorTest]";
+ }
+
+ }, new LogMessage()
+ {
+ public String toString()
+ {
+ return message;
+ }
+ });
+ return message;
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/actors/BaseActorTestCase.java b/java/broker/src/test/java/org/apache/qpid/server/logging/actors/BaseActorTestCase.java
new file mode 100644
index 0000000000..dd5632f2b0
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/actors/BaseActorTestCase.java
@@ -0,0 +1,74 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.actors;
+
+import junit.framework.TestCase;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.logging.rawloggers.UnitTestMessageLogger;
+import org.apache.qpid.server.logging.RootMessageLogger;
+import org.apache.qpid.server.logging.RootMessageLoggerImpl;
+import org.apache.qpid.server.logging.LogActor;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.PropertiesConfiguration;
+
+public class BaseActorTestCase extends TestCase
+{
+ protected LogActor _amqpActor;
+ protected UnitTestMessageLogger _rawLogger;
+ protected RootMessageLogger _rootLogger;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ //Highlight that this test will cause a new AR to be created
+ ApplicationRegistry.getInstance();
+
+ Configuration config = new PropertiesConfiguration();
+ ServerConfiguration serverConfig = new ServerConfiguration(config);
+
+ serverConfig.getConfig().setProperty(ServerConfiguration.STATUS_UPDATES, "on");
+
+ setUpWithConfig(serverConfig);
+ }
+
+ public void tearDown() throws Exception
+ {
+ _rawLogger.clearLogMessages();
+
+ // Correctly Close the AR we created
+ ApplicationRegistry.remove();
+
+ super.tearDown();
+ }
+
+ protected void setUpWithConfig(ServerConfiguration serverConfig) throws AMQException
+ {
+ _rawLogger = new UnitTestMessageLogger();
+
+ _rootLogger =
+ new RootMessageLoggerImpl(serverConfig, _rawLogger);
+ }
+
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/actors/BaseConnectionActorTestCase.java b/java/broker/src/test/java/org/apache/qpid/server/logging/actors/BaseConnectionActorTestCase.java
new file mode 100644
index 0000000000..6e8ecc1313
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/actors/BaseConnectionActorTestCase.java
@@ -0,0 +1,50 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.actors;
+
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.protocol.InternalTestProtocolSession;
+import org.apache.qpid.AMQException;
+
+public class BaseConnectionActorTestCase extends BaseActorTestCase
+{
+
+ protected AMQProtocolSession _session;
+
+ @Override
+ protected void setUpWithConfig(ServerConfiguration serverConfig) throws AMQException
+ {
+ super.setUpWithConfig(serverConfig);
+
+ VirtualHost virtualHost = ApplicationRegistry.getInstance().
+ getVirtualHostRegistry().getVirtualHosts().iterator().next();
+
+ // Create a single session for this test.
+ _session = new InternalTestProtocolSession(virtualHost);
+
+ _amqpActor = new AMQPConnectionActor(_session, _rootLogger);
+ }
+
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/actors/CurrentActorTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/actors/CurrentActorTest.java
new file mode 100644
index 0000000000..0d7d0c3dba
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/actors/CurrentActorTest.java
@@ -0,0 +1,294 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.actors;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.logging.LogMessage;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+
+/**
+ * Test : CurrentActorTest
+ * Summary:
+ * Validate ThreadLocal operation.
+ *
+ * Test creates THREADS number of threads which all then execute the same test
+ * together ( as close as looping Thread.start() will allow).
+ *
+ * Test:
+ * Test sets the CurrentActor then proceeds to retrieve the value and use it.
+ *
+ * The test also validates that it is the same LogActor that this thread set.
+ *
+ * Finally the LogActor is removed and tested to make sure that it was
+ * successfully removed.
+ *
+ * By having a higher number of threads than would normally be used in the
+ * Poolling filter we aim to catch the race condition where a ThreadLocal remove
+ * is called before one or more threads call get(). This way we can ensure that
+ * the remove does not affect more than the Thread it was called in.
+ */
+public class CurrentActorTest extends BaseConnectionActorTestCase
+{
+ //Set this to be a reasonably large number
+ int THREADS = 10;
+
+ // Record any exceptions that are thrown by the threads
+ Exception[] _errors = new Exception[THREADS];
+
+ /**
+ * Test that CurrentActor behaves as LIFO queue.
+ *
+ * Test creates two Actors Connection and Channel and then sets the
+ * CurrentActor.
+ *
+ * The test validates that CurrentActor remembers the Connection actor
+ * after the Channel actor has been removed.
+ *
+ * And then finally validates that removing the Connection actor results
+ * in there being no actors set.
+ *
+ * @throws AMQException
+ */
+ public void testLIFO() throws AMQException
+ {
+ // Create a new actor using retrieving the rootMessageLogger from
+ // the default ApplicationRegistry.
+ //fixme reminder that we need a better approach for broker testing.
+ AMQPConnectionActor connectionActor = new AMQPConnectionActor(_session,
+ ApplicationRegistry.getInstance().
+ getRootMessageLogger());
+
+ /*
+ * Push the actor on to the stack:
+ *
+ * CurrentActor -> Connection
+ * Stack -> null
+ */
+ CurrentActor.set(connectionActor);
+
+ //Use the Actor to send a simple message
+ CurrentActor.get().message(new LogSubject()
+ {
+ public String toString()
+ {
+ return "[CurrentActorTest] ";
+ }
+
+ }, new LogMessage()
+ {
+ public String toString()
+ {
+ return "Connection Log Msg";
+ }
+ });
+
+ // Verify it was the same actor as we set earlier
+ assertEquals("Retrieved actor is not as expected ",
+ connectionActor, CurrentActor.get());
+
+ /**
+ * Set the actor to now be the Channel actor so testing the ability
+ * to push the actor on to the stack:
+ *
+ * CurrentActor -> Channel
+ * Stack -> Connection, null
+ *
+ */
+
+ AMQChannel channel = new AMQChannel(_session, 1, _session.getVirtualHost().getMessageStore());
+
+ AMQPChannelActor channelActor = new AMQPChannelActor(channel,
+ ApplicationRegistry.getInstance().
+ getRootMessageLogger());
+
+ CurrentActor.set(channelActor);
+
+ //Use the Actor to send a simple message
+ CurrentActor.get().message(new LogSubject()
+ {
+ public String toString()
+ {
+ return "[CurrentActorTest] ";
+ }
+
+ }, new LogMessage()
+ {
+ public String toString()
+ {
+ return "Channel Log Msg";
+ }
+ });
+
+ // Verify it was the same actor as we set earlier
+ assertEquals("Retrieved actor is not as expected ",
+ channelActor, CurrentActor.get());
+
+ // Remove the ChannelActor from the stack
+ CurrentActor.remove();
+ /*
+ * Pop the actor on to the stack:
+ *
+ * CurrentActor -> Connection
+ * Stack -> null
+ */
+
+
+ // Verify we now have the same connection actor as we set earlier
+ assertEquals("Retrieved actor is not as expected ",
+ connectionActor, CurrentActor.get());
+
+ // Verify that removing the our last actor it returns us to the test
+ // default that the ApplicationRegistry sets.
+ CurrentActor.remove();
+ /*
+ * Pop the actor on to the stack:
+ *
+ * CurrentActor -> null
+ */
+
+
+ assertEquals("CurrentActor not the Test default", TestLogActor.class ,CurrentActor.get().getClass());
+ }
+
+ /**
+ * Test the setting CurrentActor is done correctly as a ThreadLocal.
+ *
+ * The test starts 'THREADS' threads that all set the CurrentActor log
+ * a message then remove the actor.
+ *
+ * Checks are done to ensure that there is no set actor after the remove.
+ *
+ * If the ThreadLoacl was not working then having concurrent actor sets
+ * would result in more than one actor and so the remove will not result
+ * in the clearing of the CurrentActor
+ *
+ */
+ public void testThreadLocal()
+ {
+
+ new Runnable(){
+ public void run()
+ {
+ System.out.println(_errors[0]);
+ }
+ };
+
+ // Setup the threads
+ Thread[] threads = new Thread[THREADS];
+ for (int count = 0; count < THREADS; count++)
+ {
+ Runnable test = new LogMessagesWithAConnectionActor(count);
+ threads[count] = new Thread(test);
+ }
+
+ //Run the threads
+ for (int count = 0; count < THREADS; count++)
+ {
+ threads[count].start();
+ }
+
+ // Wait for them to finish
+ for (int count = 0; count < THREADS; count++)
+ {
+ try
+ {
+ threads[count].join();
+ }
+ catch (InterruptedException e)
+ {
+ //if we are interrupted then we will exit shortly.
+ }
+ }
+
+ // Verify that none of the tests threw an exception
+ for (int count = 0; count < THREADS; count++)
+ {
+ if (_errors[count] != null)
+ {
+ _errors[count].printStackTrace();
+ fail("Error occured in thread:" + count);
+ }
+ }
+ }
+
+ /**
+ * Creates a new ConnectionActor and logs the given number of messages
+ * before removing the actor and validating that there is no set actor.
+ */
+ public class LogMessagesWithAConnectionActor implements Runnable
+ {
+ int count;
+
+ LogMessagesWithAConnectionActor(int count)
+ {
+ this.count = count;
+ }
+
+ public void run()
+ {
+
+ // Create a new actor using retrieving the rootMessageLogger from
+ // the default ApplicationRegistry.
+ //fixme reminder that we need a better approach for broker testing.
+ AMQPConnectionActor actor = new AMQPConnectionActor(_session,
+ ApplicationRegistry.getInstance().
+ getRootMessageLogger());
+
+ CurrentActor.set(actor);
+
+ try
+ {
+ //Use the Actor to send a simple message
+ CurrentActor.get().message(new LogSubject()
+ {
+ public String toString()
+ {
+ return "[CurrentActorTest] ";
+ }
+
+ }, new LogMessage()
+ {
+ public String toString()
+ {
+ return "Running Thread:" + count;
+ }
+ });
+
+ // Verify it was the same actor as we set earlier
+ assertEquals("Retrieved actor is not as expected ",
+ actor, CurrentActor.get());
+
+ // Verify that removing the actor works for this thread
+ CurrentActor.remove();
+
+ assertNull("CurrentActor should be null", CurrentActor.get());
+ }
+ catch (Exception e)
+ {
+ _errors[count] = e;
+ }
+
+ }
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/actors/ManagementActorTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/actors/ManagementActorTest.java
new file mode 100644
index 0000000000..caee84da09
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/actors/ManagementActorTest.java
@@ -0,0 +1,118 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.actors;
+
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.logging.LogMessage;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.AMQException;
+
+import java.util.List;
+
+/**
+ * Test : AMQPManagementActorTest
+ * Validate the AMQPManagementActor class.
+ *
+ * The test creates a new AMQPActor and then logs a message using it.
+ *
+ * The test then verifies that the logged message was the only one created and
+ * that the message contains the required message.
+ */
+public class ManagementActorTest extends BaseActorTestCase
+{
+
+ private static final String IP = "127.0.0.1";
+ private static final String CONNECTION_ID = "1";
+ private String _threadName;
+
+ @Override
+ protected void setUpWithConfig(ServerConfiguration serverConfig) throws AMQException
+ {
+ super.setUpWithConfig(serverConfig);
+ _amqpActor = new ManagementActor(_rootLogger);
+
+ // Set the thread name to be the same as a RMI JMX Connection would use
+ _threadName = Thread.currentThread().getName();
+ Thread.currentThread().setName("RMI TCP Connection(" + CONNECTION_ID + ")-" + IP);
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ Thread.currentThread().setName(_threadName);
+ super.tearDown();
+ }
+
+ /**
+ * Test the AMQPActor logging as a Connection level.
+ *
+ * The test sends a message then verifies that it entered the logs.
+ *
+ * The log message should be fully repalaced (no '{n}' values) and should
+ * not contain any channel identification.
+ */
+ public void testConnection()
+ {
+ final String message = "test logging";
+
+ _amqpActor.message(new LogSubject()
+ {
+ public String toString()
+ {
+ return "[AMQPActorTest]";
+ }
+
+ }, new LogMessage()
+ {
+ public String toString()
+ {
+ return message;
+ }
+ });
+
+ List<Object> logs = _rawLogger.getLogMessages();
+
+ assertEquals("Message log size not as expected.", 1, logs.size());
+
+ // Verify that the logged message is present in the output
+ assertTrue("Message was not found in log message",
+ logs.get(0).toString().contains(message));
+
+ // Verify that all the values were presented to the MessageFormatter
+ // so we will not end up with '{n}' entries in the log.
+ assertFalse("Verify that the string does not contain any '{'.",
+ logs.get(0).toString().contains("{"));
+
+ // Verify that the message has the correct type
+ assertTrue("Message does not contain the [mng: prefix",
+ logs.get(0).toString().contains("[mng:"));
+
+ // Verify that the logged message does not contains the 'ch:' marker
+ assertFalse("Message was logged with a channel identifier." + logs.get(0),
+ logs.get(0).toString().contains("/ch:"));
+
+ // Verify that the message has the right values
+ assertTrue("Message contains the [mng: prefix",
+ logs.get(0).toString().contains("[mng:" + CONNECTION_ID + "(" + IP + ")"));
+
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/actors/QueueActorTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/actors/QueueActorTest.java
new file mode 100644
index 0000000000..bf8fd86f85
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/actors/QueueActorTest.java
@@ -0,0 +1,99 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.actors;
+
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.logging.LogMessage;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.queue.MockAMQQueue;
+import org.apache.qpid.AMQException;
+
+import java.util.List;
+
+public class QueueActorTest extends BaseConnectionActorTestCase
+{
+
+ @Override
+ protected void setUpWithConfig(ServerConfiguration serverConfig) throws AMQException
+ {
+ super.setUpWithConfig(serverConfig);
+
+ MockAMQQueue queue = new MockAMQQueue(getName());
+
+ queue.setVirtualHost(_session.getVirtualHost());
+
+ _amqpActor = new QueueActor(queue, _rootLogger);
+ }
+
+ /**
+ * Test the QueueActor as a logger.
+ *
+ * The test logs a message then verifies that it entered the logs correctly
+ *
+ * The log message should be fully repalaced (no '{n}' values) and should
+ * contain the correct queue identification.
+ */
+ public void testQueueActor()
+ {
+ final String message = "test logging";
+
+ _amqpActor.message(new LogSubject()
+ {
+ public String toString()
+ {
+ return "[AMQPActorTest]";
+ }
+
+ }, new LogMessage()
+ {
+ public String toString()
+ {
+ return message;
+ }
+ });
+
+ List<Object> logs = _rawLogger.getLogMessages();
+
+ assertEquals("Message log size not as expected.", 1, logs.size());
+
+ String log = logs.get(0).toString();
+
+ // Verify that the logged message is present in the output
+ assertTrue("Message was not found in log message",
+ log.contains(message));
+
+ // Verify that all the values were presented to the MessageFormatter
+ // so we will not end up with '{n}' entries in the log.
+ assertFalse("Verify that the string does not contain any '{':" + log,
+ log.contains("{"));
+
+ // Verify that the message has the correct type
+ assertTrue("Message contains the [vh: prefix:" + log,
+ log.contains("[vh("));
+
+ // Verify that the logged message contains the 'qu(' marker
+ String expected = "qu(" + getName() + ")";
+ assertTrue("Message was not logged with a queue identifer '"+expected+"' actual:" + log,
+ log.contains(expected));
+ }
+
+}
+
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/actors/SubscriptionActorTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/actors/SubscriptionActorTest.java
new file mode 100644
index 0000000000..c86ffd4872
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/actors/SubscriptionActorTest.java
@@ -0,0 +1,110 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.actors;
+
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.logging.LogMessage;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.subscription.MockSubscription;
+import org.apache.qpid.server.queue.MockAMQQueue;
+import org.apache.qpid.AMQException;
+
+import java.util.List;
+
+/**
+ * Test : AMQPConnectionActorTest
+ * Validate the AMQPConnectionActor class.
+ *
+ * The test creates a new AMQPActor and then logs a message using it.
+ *
+ * The test then verifies that the logged message was the only one created and
+ * that the message contains the required message.
+ */
+public class SubscriptionActorTest extends BaseConnectionActorTestCase
+{
+
+ @Override
+ protected void setUpWithConfig(ServerConfiguration serverConfig) throws AMQException
+ {
+ super.setUpWithConfig(serverConfig);
+
+
+ MockSubscription mockSubscription = new MockSubscription();
+
+ MockAMQQueue queue = new MockAMQQueue(getName());
+
+ queue.setVirtualHost(_session.getVirtualHost());
+
+ mockSubscription.setQueue(queue,false);
+
+ _amqpActor = new SubscriptionActor(_rootLogger, mockSubscription);
+ }
+
+ /**
+ * Test the AMQPActor logging as a Subscription logger.
+ *
+ * The test sends a message then verifies that it entered the logs.
+ *
+ * The log message should be fully repalaced (no '{n}' values) and should
+ * contain subscription identification.
+ */
+ public void testSubscription()
+ {
+ final String message = "test logging";
+
+ _amqpActor.message(new LogSubject()
+ {
+ public String toString()
+ {
+ return "[AMQPActorTest]";
+ }
+
+ }, new LogMessage()
+ {
+ public String toString()
+ {
+ return message;
+ }
+ });
+
+ List<Object> logs = _rawLogger.getLogMessages();
+
+ assertEquals("Message log size not as expected.", 1, logs.size());
+
+ // Verify that the logged message is present in the output
+ assertTrue("Message was not found in log message",
+ logs.get(0).toString().contains(message));
+
+ // Verify that all the values were presented to the MessageFormatter
+ // so we will not end up with '{n}' entries in the log.
+ assertFalse("Verify that the string does not contain any '{'.",
+ logs.get(0).toString().contains("{"));
+
+ // Verify that the message has the correct type
+ assertTrue("Message contains the [sub: prefix",
+ logs.get(0).toString().contains("[sub:"));
+
+ // Verify that the logged message does not contains the 'ch:' marker
+ assertFalse("Message was logged with a channel identifier." + logs.get(0),
+ logs.get(0).toString().contains("/ch:"));
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/actors/TestLogActor.java b/java/broker/src/test/java/org/apache/qpid/server/logging/actors/TestLogActor.java
new file mode 100644
index 0000000000..30f4e16e42
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/actors/TestLogActor.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.actors;
+
+import org.apache.qpid.server.logging.RootMessageLogger;
+
+public class TestLogActor extends AbstractActor
+{
+ public TestLogActor(RootMessageLogger rootLogger)
+ {
+ super(rootLogger);
+ }
+
+ public String getLogMessage()
+ {
+ return "[Test Actor] ";
+ }
+}
+ \ No newline at end of file
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/management/LoggingManagementMBeanTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/management/LoggingManagementMBeanTest.java
new file mode 100644
index 0000000000..eff6a6f59f
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/management/LoggingManagementMBeanTest.java
@@ -0,0 +1,425 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.logging.management;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.management.JMException;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularDataSupport;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.qpid.management.common.mbeans.LoggingManagement;
+
+import junit.framework.TestCase;
+
+public class LoggingManagementMBeanTest extends TestCase
+{
+ private static final String TEST_LOGGER = "LoggingManagementMBeanTestLogger";
+ private static final String TEST_LOGGER_CHILD1 = "LoggingManagementMBeanTestLogger.child1";
+ private static final String TEST_LOGGER_CHILD2 = "LoggingManagementMBeanTestLogger.child2";
+
+ private static final String CATEGORY_PRIORITY = "LogManMBeanTest.category.priority";
+ private static final String CATEGORY_LEVEL = "LogManMBeanTest.category.level";
+ private static final String LOGGER_LEVEL = "LogManMBeanTest.logger.level";
+
+ private static final String NAME_INDEX = LoggingManagement.COMPOSITE_ITEM_NAMES[0];
+ private static final String LEVEL_INDEX = LoggingManagement.COMPOSITE_ITEM_NAMES[1];
+
+ private static final String NEWLINE = System.getProperty("line.separator");
+
+ private File _testConfigFile;
+
+ protected void setUp() throws Exception
+ {
+ _testConfigFile = createTempTestLog4JConfig();
+ }
+
+ protected void tearDown() throws Exception
+ {
+ File oldTestConfigFile = new File(_testConfigFile.getAbsolutePath() + ".old");
+ if(oldTestConfigFile.exists())
+ {
+ oldTestConfigFile.delete();
+ }
+
+ _testConfigFile.delete();
+ }
+
+ private File createTempTestLog4JConfig()
+ {
+ File tmpFile = null;
+ try
+ {
+ tmpFile = File.createTempFile("LogManMBeanTestLog4jConfig", ".tmp");
+ tmpFile.deleteOnExit();
+
+ FileWriter fstream = new FileWriter(tmpFile);
+ BufferedWriter writer = new BufferedWriter(fstream);
+
+ writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+NEWLINE);
+ writer.write("<!DOCTYPE log4j:configuration SYSTEM \"log4j.dtd\">"+NEWLINE);
+
+ writer.write("<log4j:configuration xmlns:log4j=\"http://jakarta.apache.org/log4j/\" debug=\"null\" " +
+ "threshold=\"null\">"+NEWLINE);
+
+ writer.write(" <appender class=\"org.apache.log4j.ConsoleAppender\" name=\"STDOUT\">"+NEWLINE);
+ writer.write(" <layout class=\"org.apache.log4j.PatternLayout\">"+NEWLINE);
+ writer.write(" <param name=\"ConversionPattern\" value=\"%d %-5p [%t] %C{2} (%F:%L) - %m%n\"/>"+NEWLINE);
+ writer.write(" </layout>"+NEWLINE);
+ writer.write(" </appender>"+NEWLINE);
+
+ //Example of a 'category' with a 'priority'
+ writer.write(" <category additivity=\"true\" name=\"" + CATEGORY_PRIORITY +"\">"+NEWLINE);
+ writer.write(" <priority value=\"info\"/>"+NEWLINE);
+ writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE);
+ writer.write(" </category>"+NEWLINE);
+
+ //Example of a 'category' with a 'level'
+ writer.write(" <category additivity=\"true\" name=\"" + CATEGORY_LEVEL +"\">"+NEWLINE);
+ writer.write(" <level value=\"warn\"/>"+NEWLINE);
+ writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE);
+ writer.write(" </category>"+NEWLINE);
+
+ //Example of a 'logger' with a 'level'
+ writer.write(" <logger additivity=\"true\" name=\"" + LOGGER_LEVEL + "\">"+NEWLINE);
+ writer.write(" <level value=\"error\"/>"+NEWLINE);
+ writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE);
+ writer.write(" </logger>"+NEWLINE);
+
+ //'root' logger
+ writer.write(" <root>"+NEWLINE);
+ writer.write(" <priority value=\"info\"/>"+NEWLINE);
+ writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE);
+ writer.write(" </root>"+NEWLINE);
+
+ writer.write("</log4j:configuration>"+NEWLINE);
+
+ writer.flush();
+ writer.close();
+ }
+ catch (IOException e)
+ {
+ fail("Unable to create temporary test log4j configuration");
+ }
+
+ return tmpFile;
+ }
+
+
+
+ //******* Test Methods ******* //
+
+ public void testSetRuntimeLoggerLevel()
+ {
+ LoggingManagementMBean lm = null;
+ try
+ {
+ lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0);
+ }
+ catch (JMException e)
+ {
+ fail("Could not create test LoggingManagementMBean");
+ }
+
+ //create a parent test logger, set its level explicitly
+ Logger log = Logger.getLogger(TEST_LOGGER);
+ log.setLevel(Level.toLevel("info"));
+
+ //create child1 test logger, check its *effective* level is the same as the parent, "info"
+ Logger log1 = Logger.getLogger(TEST_LOGGER_CHILD1);
+ assertTrue("Test logger's level was not the expected value",
+ log1.getEffectiveLevel().toString().equalsIgnoreCase("info"));
+
+ //now change its level to "warn"
+ assertTrue("Failed to set logger level", lm.setRuntimeLoggerLevel(TEST_LOGGER_CHILD1, "warn"));
+
+ //check the change, see its actual level is "warn
+ assertTrue("Test logger's level was not the expected value",
+ log1.getLevel().toString().equalsIgnoreCase("warn"));
+
+ //try an invalid level
+ assertFalse("Trying to set an invalid level succeded", lm.setRuntimeLoggerLevel(TEST_LOGGER_CHILD1, "made.up.level"));
+ }
+
+ public void testSetRuntimeRootLoggerLevel()
+ {
+ LoggingManagementMBean lm = null;
+ try
+ {
+ lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0);
+ }
+ catch (JMException e)
+ {
+ fail("Could not create test LoggingManagementMBean");
+ }
+
+ Logger log = Logger.getRootLogger();
+
+ //get current root logger level
+ Level origLevel = log.getLevel();
+
+ //change level twice to ensure a new level is actually selected
+
+ //set root loggers level to info
+ assertTrue("Failed to set root logger level", lm.setRuntimeRootLoggerLevel("debug"));
+ //check it is now actually info
+ Level currentLevel = log.getLevel();
+ assertTrue("Logger level was not expected value", currentLevel.equals(Level.toLevel("debug")));
+
+ //try an invalid level
+ assertFalse("Trying to set an invalid level succeded", lm.setRuntimeRootLoggerLevel("made.up.level"));
+
+ //set root loggers level to warn
+ assertTrue("Failed to set logger level", lm.setRuntimeRootLoggerLevel("info"));
+ //check it is now actually warn
+ currentLevel = log.getLevel();
+ assertTrue("Logger level was not expected value", currentLevel.equals(Level.toLevel("info")));
+
+ //restore original level
+ log.setLevel(origLevel);
+ }
+
+ public void testGetRuntimeRootLoggerLevel()
+ {
+ LoggingManagementMBean lm = null;
+ try
+ {
+ lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0);
+ }
+ catch (JMException e)
+ {
+ fail("Could not create test LoggingManagementMBean");
+ }
+
+ Logger log = Logger.getRootLogger();
+
+ //get current root logger level
+ Level origLevel = log.getLevel();
+
+ //change level twice to ensure a new level is actually selected
+
+ //set root loggers level to debug
+ log.setLevel(Level.toLevel("debug"));
+ //check it is now actually debug
+ assertTrue("Logger level was not expected value", lm.getRuntimeRootLoggerLevel().equalsIgnoreCase("debug"));
+
+
+ //set root loggers level to warn
+ log.setLevel(Level.toLevel("info"));
+ //check it is now actually warn
+ assertTrue("Logger level was not expected value", lm.getRuntimeRootLoggerLevel().equalsIgnoreCase("info"));
+
+ //restore original level
+ log.setLevel(origLevel);
+ }
+
+ public void testViewEffectiveRuntimeLoggerLevels()
+ {
+ LoggingManagementMBean lm = null;
+ try
+ {
+ lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0);
+ }
+ catch (JMException e)
+ {
+ fail("Could not create test LoggingManagementMBean");
+ }
+
+ //(re)create a parent test logger, set its level explicitly
+ Logger log = Logger.getLogger(TEST_LOGGER);
+ log.setLevel(Level.toLevel("info"));
+
+ //retrieve the current effective runtime logger level values
+ TabularDataSupport levels = (TabularDataSupport) lm.viewEffectiveRuntimeLoggerLevels();
+ Collection<Object> records = levels.values();
+ Map<String,String> list = new HashMap<String,String>();
+ for (Object o : records)
+ {
+ CompositeData data = (CompositeData) o;
+ list.put(data.get(NAME_INDEX).toString(), data.get(LEVEL_INDEX).toString());
+ }
+
+ //check child2 does not exist already
+ assertFalse("Did not expect this logger to exist already", list.containsKey(TEST_LOGGER_CHILD2));
+
+ //create child2 test logger
+ Logger log2 = Logger.getLogger(TEST_LOGGER_CHILD2);
+
+ //retrieve the current effective runtime logger level values
+ levels = (TabularDataSupport) lm.viewEffectiveRuntimeLoggerLevels();
+ records = levels.values();
+ list = new HashMap<String,String>();
+ for (Object o : records)
+ {
+ CompositeData data = (CompositeData) o;
+ list.put(data.get(NAME_INDEX).toString(), data.get(LEVEL_INDEX).toString());
+ }
+
+ //verify the parent and child2 loggers are present in returned values
+ assertTrue(TEST_LOGGER + " logger was not in the returned list", list.containsKey(TEST_LOGGER));
+ assertTrue(TEST_LOGGER_CHILD2 + " logger was not in the returned list", list.containsKey(TEST_LOGGER_CHILD2));
+
+ //check child2's effective level is the same as the parent, "info"
+ assertTrue("Test logger's level was not the expected value",
+ list.get(TEST_LOGGER_CHILD2).equalsIgnoreCase("info"));
+
+ //now change its level explicitly to "warn"
+ log2.setLevel(Level.toLevel("warn"));
+
+ //retrieve the current effective runtime logger level values
+ levels = (TabularDataSupport) lm.viewEffectiveRuntimeLoggerLevels();
+ records = levels.values();
+ list = new HashMap<String,String>();
+ for (Object o : records)
+ {
+ CompositeData data = (CompositeData) o;
+ list.put(data.get(NAME_INDEX).toString(), data.get(LEVEL_INDEX).toString());
+ }
+
+ //check child2's effective level is now "warn"
+ assertTrue("Test logger's level was not the expected value",
+ list.get(TEST_LOGGER_CHILD2).equalsIgnoreCase("warn"));
+ }
+
+ public void testViewAndSetConfigFileLoggerLevel() throws Exception
+ {
+ LoggingManagementMBean lm =null;
+ try
+ {
+ lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0);
+ }
+ catch (JMException e)
+ {
+ fail("Could not create test LoggingManagementMBean");
+ }
+
+ //retrieve the current values
+ TabularDataSupport levels = (TabularDataSupport) lm.viewConfigFileLoggerLevels();
+ Collection<Object> records = levels.values();
+ Map<String,String> list = new HashMap<String,String>();
+ for (Object o : records)
+ {
+ CompositeData data = (CompositeData) o;
+ list.put(data.get(NAME_INDEX).toString(), data.get(LEVEL_INDEX).toString());
+ }
+
+ //check the 3 different types of logger definition are successfully retrieved before update
+ assertTrue("Wrong number of items in returned list", list.size() == 3);
+ assertTrue(CATEGORY_PRIORITY + " logger was not in the returned list", list.containsKey(CATEGORY_PRIORITY));
+ assertTrue(CATEGORY_LEVEL + " logger was not in the returned list", list.containsKey(CATEGORY_LEVEL));
+ assertTrue(LOGGER_LEVEL + " logger was not in the returned list", list.containsKey(LOGGER_LEVEL));
+
+ //check that their level is as expected
+ assertTrue(CATEGORY_PRIORITY + " logger's level was incorrect", list.get(CATEGORY_PRIORITY).equalsIgnoreCase("info"));
+ assertTrue(CATEGORY_LEVEL + " logger's level was incorrect", list.get(CATEGORY_LEVEL).equalsIgnoreCase("warn"));
+ assertTrue(LOGGER_LEVEL + " logger's level was incorrect", list.get(LOGGER_LEVEL).equalsIgnoreCase("error"));
+
+ //increase their levels a notch to test the 3 different types of logger definition are successfully updated
+ //change the category+priority to warn
+ assertTrue("failed to set new level", lm.setConfigFileLoggerLevel(CATEGORY_PRIORITY, "warn"));
+ //change the category+level to error
+ assertTrue("failed to set new level", lm.setConfigFileLoggerLevel(CATEGORY_LEVEL, "error"));
+ //change the logger+level to trace
+ assertTrue("failed to set new level", lm.setConfigFileLoggerLevel(LOGGER_LEVEL, "trace"));
+
+ //try an invalid level
+ assertFalse("Use of an invalid logger level was successfull", lm.setConfigFileLoggerLevel(LOGGER_LEVEL, "made.up.level"));
+
+ //try an invalid logger name
+ assertFalse("Use of an invalid logger name was successfull", lm.setConfigFileLoggerLevel("made.up.logger.name", "info"));
+
+ //retrieve the new values from the file and check them
+ levels = (TabularDataSupport) lm.viewConfigFileLoggerLevels();
+ records = levels.values();
+ list = new HashMap<String,String>();
+ for (Object o : records)
+ {
+ CompositeData data = (CompositeData) o;
+ list.put(data.get(NAME_INDEX).toString(), data.get(LEVEL_INDEX).toString());
+ }
+
+ //check the 3 different types of logger definition are successfully retrieved after update
+ assertTrue("Wrong number of items in returned list", list.size() == 3);
+ assertTrue(CATEGORY_PRIORITY + " logger was not in the returned list", list.containsKey(CATEGORY_PRIORITY));
+ assertTrue(CATEGORY_LEVEL + " logger was not in the returned list", list.containsKey(CATEGORY_LEVEL));
+ assertTrue(LOGGER_LEVEL + " logger was not in the returned list", list.containsKey(LOGGER_LEVEL));
+
+ //check that their level is as expected after the changes
+ assertTrue(CATEGORY_PRIORITY + " logger's level was incorrect", list.get(CATEGORY_PRIORITY).equalsIgnoreCase("warn"));
+ assertTrue(CATEGORY_LEVEL + " logger's level was incorrect", list.get(CATEGORY_LEVEL).equalsIgnoreCase("error"));
+ assertTrue(LOGGER_LEVEL + " logger's level was incorrect", list.get(LOGGER_LEVEL).equalsIgnoreCase("trace"));
+ }
+
+ public void testGetAndSetConfigFileRootLoggerLevel() throws Exception
+ {
+ LoggingManagementMBean lm =null;
+ try
+ {
+ lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0);
+ }
+ catch (JMException e)
+ {
+ fail("Could not create test LoggingManagementMBean");
+ }
+
+ //retrieve the current value
+ String level = lm.getConfigFileRootLoggerLevel();
+
+ //check the value was successfully retrieved before update
+ assertTrue("Retrieved RootLogger level was incorrect", level.equalsIgnoreCase("info"));
+
+ //try an invalid level
+ assertFalse("Use of an invalid RootLogger level was successfull", lm.setConfigFileRootLoggerLevel("made.up.level"));
+
+ //change the level to warn
+ assertTrue("Failed to set new RootLogger level", lm.setConfigFileRootLoggerLevel("warn"));
+
+ //retrieve the current value
+ level = lm.getConfigFileRootLoggerLevel();
+
+ //check the value was successfully retrieved after update
+ assertTrue("Retrieved RootLogger level was incorrect", level.equalsIgnoreCase("warn"));
+ }
+
+ public void testGetLog4jLogWatchInterval()
+ {
+ LoggingManagementMBean lm =null;
+ try
+ {
+ lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 5000);
+ }
+ catch (JMException e)
+ {
+ fail("Could not create test LoggingManagementMBean");
+ }
+
+ assertTrue("Wrong value returned for logWatch period", lm.getLog4jLogWatchInterval() == 5000);
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/messages/AbstractTestMessages.java b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/AbstractTestMessages.java
new file mode 100644
index 0000000000..25760a6d65
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/AbstractTestMessages.java
@@ -0,0 +1,127 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.messages;
+
+import junit.framework.TestCase;
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.logging.LogActor;
+import org.apache.qpid.server.logging.LogMessage;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.logging.RootMessageLogger;
+import org.apache.qpid.server.logging.RootMessageLoggerImpl;
+import org.apache.qpid.server.logging.actors.TestLogActor;
+import org.apache.qpid.server.logging.rawloggers.UnitTestMessageLogger;
+import org.apache.qpid.server.logging.subjects.TestBlankSubject;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+
+import java.util.List;
+
+public abstract class AbstractTestMessages extends TestCase
+{
+ protected Configuration _config = new PropertiesConfiguration();
+ protected LogMessage _logMessage = null;
+ protected LogActor _actor;
+ protected UnitTestMessageLogger _logger;
+ protected LogSubject _logSubject = new TestBlankSubject();
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ // Highlight that we create a new AR here
+ ApplicationRegistry.getInstance();
+
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+
+ serverConfig.getConfig().setProperty(ServerConfiguration.STATUS_UPDATES, "on");
+
+ _logger = new UnitTestMessageLogger();
+ RootMessageLogger rootLogger =
+ new RootMessageLoggerImpl(serverConfig, _logger);
+
+ _actor = new TestLogActor(rootLogger);
+ }
+
+ public void tearDown() throws Exception
+ {
+ // Correctly Close the AR that we created above
+ ApplicationRegistry.remove();
+ super.tearDown();
+ }
+
+ protected List<Object> performLog()
+ {
+ if (_logMessage == null)
+ {
+ throw new NullPointerException("LogMessage has not been set");
+ }
+
+ _actor.message(_logSubject, _logMessage);
+
+ return _logger.getLogMessages();
+ }
+
+ /**
+ * Validate that only a single log messasge occured and that the message
+ * section starts with the specified tag
+ *
+ * @param logs the logs generated during test run
+ * @param tag the tag to check for
+ * @param expected the expected log messages
+ *
+ */
+ protected void validateLogMessage(List<Object> logs, String tag, String[] expected)
+ {
+ assertEquals("Log has incorrect message count", 1, logs.size());
+
+ //We trim() here as we don't care about extra white space at the end of the log message
+ // but we do care about the ability to easily check we don't have unexpected text at
+ // the end.
+ String log = String.valueOf(logs.get(0)).trim();
+
+ // Simple switch to print out all the logged messages
+ //System.err.println(log);
+
+ int msgIndex = log.indexOf(_logSubject.toString())+_logSubject.toString().length();
+
+ assertTrue("Unable to locate Subject:" + log, msgIndex != -1);
+
+ String message = log.substring(msgIndex);
+
+ assertTrue("Message does not start with tag:" + tag + ":" + message,
+ message.startsWith(tag));
+
+ // Test that the expected items occur in order.
+ int index = 0;
+ for (String text : expected)
+ {
+ index = message.indexOf(text, index);
+ assertTrue("Message does not contain expected (" + text + ") text :" + message, index != -1);
+ index = index + text.length();
+ }
+
+ //Check there is nothing left on the log message
+ assertEquals("Message has more text. '" + log.substring(msgIndex + index) + "'",
+ log.length(), msgIndex + index);
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/messages/BindingMessagesTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/BindingMessagesTest.java
new file mode 100644
index 0000000000..7a750baf06
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/BindingMessagesTest.java
@@ -0,0 +1,64 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.messages;
+
+import java.util.List;
+
+/**
+ * Test BND Log Messages
+ */
+public class BindingMessagesTest extends AbstractTestMessages
+{
+
+ public void testBindCreate_NoArgs()
+ {
+ _logMessage = BindingMessages.BND_CREATED(null, false);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create"};
+
+ validateLogMessage(log, "BND-1001", expected);
+ }
+
+ public void testBindCreate_Args()
+ {
+ String arguments = "arguments";
+
+ _logMessage = BindingMessages.BND_CREATED(arguments, true);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create", ": Arguments :", arguments};
+
+ validateLogMessage(log, "BND-1001", expected);
+ }
+
+ public void testBindDelete()
+ {
+ _logMessage = BindingMessages.BND_DELETED();
+
+ List<Object> log = performLog();
+
+ String[] expected = {"Deleted"};
+
+ validateLogMessage(log, "BND-1002", expected);
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/messages/BrokerMessagesTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/BrokerMessagesTest.java
new file mode 100644
index 0000000000..17306b2e2a
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/BrokerMessagesTest.java
@@ -0,0 +1,116 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.messages;
+
+import java.util.List;
+
+/**
+ * Test BRK log Messages
+ */
+public class BrokerMessagesTest extends AbstractTestMessages
+{
+ public void testBrokerStartup()
+ {
+ String version = "Qpid 0.6";
+ String build = "796936M";
+
+ _logMessage = BrokerMessages.BRK_STARTUP(version, build);
+ List<Object> log = performLog();
+
+ String[] expected = {"Startup :", "Version:", version, "Build:", build};
+
+ validateLogMessage(log, "BRK-1001", expected);
+ }
+
+ public void testBrokerListening()
+ {
+ String transport = "TCP";
+ Integer port = 2765;
+
+ _logMessage = BrokerMessages.BRK_LISTENING(transport, port);
+
+ List<Object> log = performLog();
+
+ String[] expected = {"Starting", "Listening on ",
+ transport, "port ", String.valueOf(port)};
+
+ validateLogMessage(log, "BRK-1002", expected);
+ }
+
+ public void testBrokerShuttingDown()
+ {
+ String transport = "TCP";
+ Integer port = 2765;
+
+ _logMessage = BrokerMessages.BRK_SHUTTING_DOWN(transport, port);
+
+ List<Object> log = performLog();
+
+ String[] expected = {"Shuting down", transport, "port ", String.valueOf(port)};
+
+ validateLogMessage(log, "BRK-1003", expected);
+ }
+
+ public void testBrokerReady()
+ {
+ _logMessage = BrokerMessages.BRK_READY();
+ List<Object> log = performLog();
+
+ String[] expected = {"Ready"};
+
+ validateLogMessage(log, "BRK-1004", expected);
+ }
+
+ public void testBrokerStopped()
+ {
+ _logMessage = BrokerMessages.BRK_STOPPED();
+ List<Object> log = performLog();
+
+ String[] expected = {"Stopped"};
+
+ validateLogMessage(log, "BRK-1005", expected);
+ }
+
+ public void testBrokerConfig()
+ {
+ String path = "/file/path/to/configuration.xml";
+
+ _logMessage = BrokerMessages.BRK_CONFIG(path);
+ List<Object> log = performLog();
+
+ String[] expected = {"Using configuration :", path};
+
+ validateLogMessage(log, "BRK-1006", expected);
+ }
+
+ public void testBrokerLogConfig()
+ {
+ String path = "/file/path/to/configuration.xml";
+
+ _logMessage = BrokerMessages.BRK_LOG_CONFIG(path);
+ List<Object> log = performLog();
+
+ String[] expected = {"Using logging configuration :", path};
+
+ validateLogMessage(log, "BRK-1007", expected);
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/messages/ChannelMessagesTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/ChannelMessagesTest.java
new file mode 100644
index 0000000000..2d414e9e95
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/ChannelMessagesTest.java
@@ -0,0 +1,64 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.messages;
+
+import java.util.List;
+
+/**
+ * Test CHN Log Messges
+ */
+public class ChannelMessagesTest extends AbstractTestMessages
+{
+ public void testChannelCreate()
+ {
+ _logMessage = ChannelMessages.CHN_CREATE();
+ List<Object> log = performLog();
+
+ // We use the MessageFormat here as that is what the ChannelMessage
+ // will do, this makes the resulting value 12,345
+ String[] expected = {"Create"};
+
+ validateLogMessage(log, "CHN-1001", expected);
+ }
+
+ public void testChannelFlow()
+ {
+ String flow = "ON";
+
+ _logMessage = ChannelMessages.CHN_FLOW(flow);
+ List<Object> log = performLog();
+
+ String[] expected = {"Flow", flow};
+
+ validateLogMessage(log, "CHN-1002", expected);
+ }
+
+ public void testChannelClose()
+ {
+ _logMessage = ChannelMessages.CHN_CLOSE();
+ List<Object> log = performLog();
+
+ String[] expected = {"Close"};
+
+ validateLogMessage(log, "CHN-1003", expected);
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/messages/ConnectionMessagesTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/ConnectionMessagesTest.java
new file mode 100644
index 0000000000..6003cafc95
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/ConnectionMessagesTest.java
@@ -0,0 +1,90 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.messages;
+
+import java.util.List;
+
+/**
+ * Test CON Log Messages
+ */
+public class ConnectionMessagesTest extends AbstractTestMessages
+{
+ public void testConnectionOpen_WithClientIDProtocolVersion()
+ {
+ String clientID = "client";
+ String protocolVersion = "8-0";
+
+ _logMessage = ConnectionMessages.CON_OPEN(clientID, protocolVersion, true , true);
+ List<Object> log = performLog();
+
+ String[] expected = {"Open :", "Client ID", clientID,
+ ": Protocol Version :", protocolVersion};
+
+ validateLogMessage(log, "CON-1001", expected);
+ }
+
+ public void testConnectionOpen_WithClientIDNoProtocolVersion()
+ {
+ String clientID = "client";
+
+ _logMessage = ConnectionMessages.CON_OPEN(clientID, null,true, false);
+ List<Object> log = performLog();
+
+ String[] expected = {"Open :", "Client ID", clientID};
+
+ validateLogMessage(log, "CON-1001", expected);
+ }
+
+ public void testConnectionOpen_WithNOClientIDProtocolVersion()
+ {
+ String protocolVersion = "8-0";
+
+ _logMessage = ConnectionMessages.CON_OPEN(null, protocolVersion, false , true);
+ List<Object> log = performLog();
+
+ String[] expected = {"Open", ": Protocol Version :", protocolVersion};
+
+ validateLogMessage(log, "CON-1001", expected);
+ }
+
+ public void testConnectionOpen_WithNoClientIDNoProtocolVersion()
+ {
+ _logMessage = ConnectionMessages.CON_OPEN(null, null,false, false);
+ List<Object> log = performLog();
+
+ String[] expected = {"Open"};
+
+ validateLogMessage(log, "CON-1001", expected);
+ }
+
+
+
+ public void testConnectionClose()
+ {
+ _logMessage = ConnectionMessages.CON_CLOSE();
+ List<Object> log = performLog();
+
+ String[] expected = {"Close"};
+
+ validateLogMessage(log, "CON-1002", expected);
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/messages/ExchangeMessagesTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/ExchangeMessagesTest.java
new file mode 100644
index 0000000000..072f671fec
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/ExchangeMessagesTest.java
@@ -0,0 +1,80 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.messages;
+
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+
+import java.util.List;
+
+/**
+ * Test EXH Log Messages
+ */
+public class ExchangeMessagesTest extends AbstractTestMessages
+{
+ public void testExchangeCreated_Transient()
+ {
+ // Get the Default Exchange on the Test Vhost for testing
+ Exchange exchange = ApplicationRegistry.getInstance().
+ getVirtualHostRegistry().getVirtualHost("test").
+ getExchangeRegistry().getDefaultExchange();
+
+ String type = exchange.getType().toString();
+ String name = exchange.getName().toString();
+
+ _logMessage = ExchangeMessages.EXH_CREATED(type, name, false);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create :", "Type:", type, "Name:", name};
+
+ validateLogMessage(log, "EXH-1001", expected);
+ }
+
+ public void testExchangeCreated_Persistent()
+ {
+ // Get the Default Exchange on the Test Vhost for testing
+ Exchange exchange = ApplicationRegistry.getInstance().
+ getVirtualHostRegistry().getVirtualHost("test").
+ getExchangeRegistry().getDefaultExchange();
+
+ String type = exchange.getType().toString();
+ String name = exchange.getName().toString();
+
+ _logMessage = ExchangeMessages.EXH_CREATED(type, name, true);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create :", "Durable", "Type:", type, "Name:", name};
+
+ validateLogMessage(log, "EXH-1001", expected);
+ }
+
+
+ public void testExchangeDeleted()
+ {
+ _logMessage = ExchangeMessages.EXH_DELETED();
+ List<Object> log = performLog();
+
+ String[] expected = {"Deleted"};
+
+ validateLogMessage(log, "EXH-1002", expected);
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/messages/ManagementConsoleMessagesTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/ManagementConsoleMessagesTest.java
new file mode 100644
index 0000000000..9b1ab2c14d
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/ManagementConsoleMessagesTest.java
@@ -0,0 +1,98 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.messages;
+
+import java.util.List;
+
+/**
+ * Test MNG Log Messages
+ */
+public class ManagementConsoleMessagesTest extends AbstractTestMessages
+{
+ public void testManagementStartup()
+ {
+ _logMessage = ManagementConsoleMessages.MNG_STARTUP();
+ List<Object> log = performLog();
+
+ String[] expected = {"Startup"};
+
+ validateLogMessage(log, "MNG-1001", expected);
+ }
+
+ public void testManagementListening()
+ {
+ String transport = "JMX";
+ Integer port = 8889;
+
+ _logMessage = ManagementConsoleMessages.MNG_LISTENING(transport, port);
+ List<Object> log = performLog();
+
+ String[] expected = {"Starting :", transport, ": Listening on port", String.valueOf(port)};
+
+ validateLogMessage(log, "MNG-1002", expected);
+ }
+
+ public void testManagementShuttingDown()
+ {
+ String transport = "JMX";
+ Integer port = 8889;
+
+ _logMessage = ManagementConsoleMessages.MNG_SHUTTING_DOWN(transport, port);
+ List<Object> log = performLog();
+
+ String[] expected = {"Shuting down :", transport, ": port", String.valueOf(port)};
+
+ validateLogMessage(log, "MNG-1003", expected);
+ }
+
+ public void testManagementReady()
+ {
+ _logMessage = ManagementConsoleMessages.MNG_READY();
+ List<Object> log = performLog();
+
+ String[] expected = {"Ready"};
+
+ validateLogMessage(log, "MNG-1004", expected);
+ }
+
+ public void testManagementStopped()
+ {
+ _logMessage = ManagementConsoleMessages.MNG_STOPPED();
+ List<Object> log = performLog();
+
+ String[] expected = {"Stopped"};
+
+ validateLogMessage(log, "MNG-1005", expected);
+ }
+
+ public void testManagementSSLKeyStore()
+ {
+ String path = "/path/to/the/keystore/files.jks";
+
+ _logMessage = ManagementConsoleMessages.MNG_SSL_KEYSTORE(path);
+ List<Object> log = performLog();
+
+ String[] expected = {"Using SSL Keystore :", path};
+
+ validateLogMessage(log, "MNG-1006", expected);
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/messages/MessageStoreMessagesTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/MessageStoreMessagesTest.java
new file mode 100644
index 0000000000..21041fc611
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/MessageStoreMessagesTest.java
@@ -0,0 +1,126 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.messages;
+
+import java.text.MessageFormat;
+import java.util.List;
+
+/**
+ * Test MST Log Messages
+ */
+public class MessageStoreMessagesTest extends AbstractTestMessages
+{
+ public void testMessageStoreCreated()
+ {
+ String name = "DerbyMessageStore";
+
+ _logMessage = MessageStoreMessages.MST_CREATED(name);
+ List<Object> log = performLog();
+
+ String[] expected = {"Created :", name};
+
+ validateLogMessage(log, "MST-1001", expected);
+ }
+
+ public void testMessageStoreStoreLocation()
+ {
+ String location = "/path/to/the/message/store.files";
+
+ _logMessage = MessageStoreMessages.MST_STORE_LOCATION(location);
+ List<Object> log = performLog();
+
+ String[] expected = {"Store location :", location};
+
+ validateLogMessage(log, "MST-1002", expected);
+ }
+
+ public void testMessageStoreClosed()
+ {
+ _logMessage = MessageStoreMessages.MST_CLOSED();
+ List<Object> log = performLog();
+
+ String[] expected = {"Closed"};
+
+ validateLogMessage(log, "MST-1003", expected);
+ }
+
+ public void testMessageStoreRecoveryStart()
+ {
+ _logMessage = MessageStoreMessages.MST_RECOVERY_START();
+ List<Object> log = performLog();
+
+ String[] expected = {"Recovery Start"};
+
+ validateLogMessage(log, "MST-1004", expected);
+ }
+/*
+ public void testMessageStoreRecoveryStart_withQueue()
+ {
+ String queueName = "testQueue";
+
+ _logMessage = MessageStoreMessages.MST_RECOVERY_START(queueName, true);
+ List<Object> log = performLog();
+
+ String[] expected = {"Recovery Start :", queueName};
+
+ validateLogMessage(log, "MST-1004", expected);
+ }
+
+ public void testMessageStoreRecovered()
+ {
+ String queueName = "testQueue";
+ Integer messasgeCount = 2000;
+
+ _logMessage = MessageStoreMessages.MST_RECOVERED(messasgeCount, queueName);
+ List<Object> log = performLog();
+
+ // Here we use MessageFormat to ensure the messasgeCount of 2000 is
+ // reformated for display as '2,000'
+ String[] expected = {"Recovered ",
+ MessageFormat.format("{0,number}", messasgeCount),
+ "messages for queue", queueName};
+
+ validateLogMessage(log, "MST-1005", expected);
+ }
+
+ public void testMessageStoreRecoveryComplete()
+ {
+ _logMessage = MessageStoreMessages.MST_RECOVERY_COMPLETE(null,false);
+ List<Object> log = performLog();
+
+ String[] expected = {"Recovery Complete"};
+
+ validateLogMessage(log, "MST-1006", expected);
+ }
+
+ public void testMessageStoreRecoveryComplete_withQueue()
+ {
+ String queueName = "testQueue";
+
+ _logMessage = MessageStoreMessages.MST_RECOVERY_COMPLETE(queueName, true);
+ List<Object> log = performLog();
+
+ String[] expected = {"Recovery Complete :", queueName};
+
+ validateLogMessage(log, "MST-1006", expected);
+ }
+ */
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/messages/QueueMessagesTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/QueueMessagesTest.java
new file mode 100644
index 0000000000..417ae31d13
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/QueueMessagesTest.java
@@ -0,0 +1,239 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.messages;
+
+import java.util.List;
+
+/**
+ * Test QUE Log Messages
+ */
+public class QueueMessagesTest extends AbstractTestMessages
+{
+ public void testQueueCreatedALL()
+ {
+ String owner = "guest";
+ Integer priority = 3;
+
+ _logMessage = QueueMessages.QUE_CREATED(owner, priority, true, true, true, true, true);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create :", "Owner:", owner, "AutoDelete",
+ "Durable", "Transient", "Priority:",
+ String.valueOf(priority)};
+
+ validateLogMessage(log, "QUE-1001", expected);
+ }
+
+ public void testQueueCreatedOwnerAutoDelete()
+ {
+ String owner = "guest";
+
+ _logMessage = QueueMessages.QUE_CREATED(owner, null, true, true, false, false, false);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create :", "Owner:", owner, "AutoDelete"};
+
+ validateLogMessage(log, "QUE-1001", expected);
+ }
+
+ public void testQueueCreatedOwnerPriority()
+ {
+ String owner = "guest";
+ Integer priority = 3;
+
+ _logMessage = QueueMessages.QUE_CREATED(owner, priority, true, false, false, false, true);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create :", "Owner:", owner, "Priority:",
+ String.valueOf(priority)};
+
+ validateLogMessage(log, "QUE-1001", expected);
+ }
+
+ public void testQueueCreatedOwnerAutoDeletePriority()
+ {
+ String owner = "guest";
+ Integer priority = 3;
+
+ _logMessage = QueueMessages.QUE_CREATED(owner, priority, true, true, false, false, true);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create :", "Owner:", owner, "AutoDelete",
+ "Priority:",
+ String.valueOf(priority)};
+
+ validateLogMessage(log, "QUE-1001", expected);
+ }
+
+ public void testQueueCreatedOwnerAutoDeleteTransient()
+ {
+ String owner = "guest";
+
+ _logMessage = QueueMessages.QUE_CREATED(owner, null, true, true, false, true, false);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create :", "Owner:", owner, "AutoDelete",
+ "Transient"};
+
+ validateLogMessage(log, "QUE-1001", expected);
+ }
+
+ public void testQueueCreatedOwnerAutoDeleteTransientPriority()
+ {
+ String owner = "guest";
+ Integer priority = 3;
+
+ _logMessage = QueueMessages.QUE_CREATED(owner, priority, true, true, false, true, true);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create :", "Owner:", owner, "AutoDelete",
+ "Transient", "Priority:",
+ String.valueOf(priority)};
+
+ validateLogMessage(log, "QUE-1001", expected);
+ }
+
+ public void testQueueCreatedOwnerAutoDeleteDurable()
+ {
+ String owner = "guest";
+
+ _logMessage = QueueMessages.QUE_CREATED(owner, null, true, true, true, false, false);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create :", "Owner:", owner, "AutoDelete",
+ "Durable"};
+
+ validateLogMessage(log, "QUE-1001", expected);
+ }
+
+ public void testQueueCreatedOwnerAutoDeleteDurablePriority()
+ {
+ String owner = "guest";
+ Integer priority = 3;
+
+ _logMessage = QueueMessages.QUE_CREATED(owner, priority, true, true, true, false, true);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create :", "Owner:", owner, "AutoDelete",
+ "Durable", "Priority:",
+ String.valueOf(priority)};
+
+ validateLogMessage(log, "QUE-1001", expected);
+ }
+
+ public void testQueueCreatedAutoDelete()
+ {
+ _logMessage = QueueMessages.QUE_CREATED(null, null, false, true, false, false, false);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create :", "AutoDelete"};
+
+ validateLogMessage(log, "QUE-1001", expected);
+ }
+
+ public void testQueueCreatedPriority()
+ {
+ Integer priority = 3;
+
+ _logMessage = QueueMessages.QUE_CREATED(null, priority, false, false, false, false, true);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create :", "Priority:",
+ String.valueOf(priority)};
+
+ validateLogMessage(log, "QUE-1001", expected);
+ }
+
+ public void testQueueCreatedAutoDeletePriority()
+ {
+ Integer priority = 3;
+
+ _logMessage = QueueMessages.QUE_CREATED(null, priority, false, true, false, false, true);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create :", "AutoDelete",
+ "Priority:",
+ String.valueOf(priority)};
+
+ validateLogMessage(log, "QUE-1001", expected);
+ }
+
+ public void testQueueCreatedAutoDeleteTransient()
+ {
+ _logMessage = QueueMessages.QUE_CREATED(null, null, false, true, false, true, false);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create :", "AutoDelete",
+ "Transient"};
+
+ validateLogMessage(log, "QUE-1001", expected);
+ }
+
+ public void testQueueCreatedAutoDeleteTransientPriority()
+ {
+ Integer priority = 3;
+
+ _logMessage = QueueMessages.QUE_CREATED(null, priority, false, true, false, true, true);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create :", "AutoDelete",
+ "Transient", "Priority:",
+ String.valueOf(priority)};
+
+ validateLogMessage(log, "QUE-1001", expected);
+ }
+
+ public void testQueueCreatedAutoDeleteDurable()
+ {
+ _logMessage = QueueMessages.QUE_CREATED(null, null, false, true, true, false, false);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create :", "AutoDelete",
+ "Durable"};
+
+ validateLogMessage(log, "QUE-1001", expected);
+ }
+
+ public void testQueueCreatedAutoDeleteDurablePriority()
+ {
+ Integer priority = 3;
+
+ _logMessage = QueueMessages.QUE_CREATED(null, priority, false, true, true, false, true);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create :", "AutoDelete",
+ "Durable", "Priority:",
+ String.valueOf(priority)};
+
+ validateLogMessage(log, "QUE-1001", expected);
+ }
+
+ public void testQueueDeleted()
+ {
+ _logMessage = QueueMessages.QUE_DELETED();
+ List<Object> log = performLog();
+
+ String[] expected = {"Deleted"};
+
+ validateLogMessage(log, "QUE-1002", expected);
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/messages/SubscriptionMessagesTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/SubscriptionMessagesTest.java
new file mode 100644
index 0000000000..b22f2e0b85
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/SubscriptionMessagesTest.java
@@ -0,0 +1,86 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.messages;
+
+import java.util.List;
+
+/**
+ * Test SUB Log Messages
+ */
+public class SubscriptionMessagesTest extends AbstractTestMessages
+{
+ public void testSubscriptionCreateALL()
+ {
+ String arguments = "arguments";
+
+ _logMessage = SubscriptionMessages.SUB_CREATE(arguments, true, true);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create :", "Durable", "Arguments :", arguments};
+
+ validateLogMessage(log, "SUB-1001", expected);
+ }
+
+ public void testSubscriptionCreateDurable()
+ {
+ _logMessage = SubscriptionMessages.SUB_CREATE(null, true, false);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create :", "Durable"};
+
+ validateLogMessage(log, "SUB-1001", expected);
+ }
+
+ public void testSubscriptionCreateArguments()
+ {
+ String arguments = "arguments";
+
+ _logMessage = SubscriptionMessages.SUB_CREATE(arguments, false, true);
+ List<Object> log = performLog();
+
+ String[] expected = {"Create :","Arguments :", arguments};
+
+ validateLogMessage(log, "SUB-1001", expected);
+ }
+
+
+ public void testSubscriptionClose()
+ {
+ _logMessage = SubscriptionMessages.SUB_CLOSE();
+ List<Object> log = performLog();
+
+ String[] expected = {"Close"};
+
+ validateLogMessage(log, "SUB-1002", expected);
+ }
+
+ public void testSubscriptionState()
+ {
+ String state = "ACTIVE";
+
+ _logMessage = SubscriptionMessages.SUB_STATE(state);
+ List<Object> log = performLog();
+
+ String[] expected = {"State :", state};
+
+ validateLogMessage(log, "SUB-1003", expected);
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/messages/VirtualHostMessagesTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/VirtualHostMessagesTest.java
new file mode 100644
index 0000000000..06a8acac29
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/messages/VirtualHostMessagesTest.java
@@ -0,0 +1,51 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.messages;
+
+import java.util.List;
+
+/**
+ * Test VHT Log Messages
+ */
+public class VirtualHostMessagesTest extends AbstractTestMessages
+{
+ public void testVirtualhostCreated()
+ {
+ String name = "test";
+ _logMessage = VirtualHostMessages.VHT_CREATED(name);
+ List<Object> log = performLog();
+
+ String[] expected = {"Created :", name};
+
+ validateLogMessage(log, "VHT-1001", expected);
+ }
+
+ public void testSubscriptionClosed()
+ {
+ _logMessage = VirtualHostMessages.VHT_CLOSED();
+ List<Object> log = performLog();
+
+ String[] expected = {"Closed"};
+
+ validateLogMessage(log, "VHT-1002", expected);
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLoggerTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLoggerTest.java
new file mode 100644
index 0000000000..4b69a46793
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/rawloggers/Log4jMessageLoggerTest.java
@@ -0,0 +1,238 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.logging.rawloggers;
+
+import junit.framework.TestCase;
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.log4j.spi.LoggingEvent;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+
+/** Test that the Log4jMessageLogger defaults behave as expected */
+public class Log4jMessageLoggerTest extends TestCase
+{
+ private File _lodgfile;
+
+ Level _rootLevel;
+ Log4jTestAppender _appender;
+
+ @Override
+ public void setUp() throws IOException
+ {
+ // Setup a file for logging
+ _appender = new Log4jTestAppender();
+
+ Logger root = Logger.getRootLogger();
+ root.addAppender(_appender);
+
+ _rootLevel = Logger.getRootLogger().getLevel();
+ if (_rootLevel != Level.INFO)
+ {
+ root.setLevel(Level.INFO);
+ root.warn("Root Logger set to:" + _rootLevel + " Resetting to INFO for test.");
+ }
+ root.warn("Adding Test Appender:" + _appender);
+ }
+
+ @Override
+ public void tearDown()
+ {
+ Logger root = Logger.getRootLogger();
+ root.warn("Removing Test Appender:" + _appender);
+ root.warn("Resetting Root Level to : " + _rootLevel);
+
+ Logger.getRootLogger().setLevel(_rootLevel);
+
+ Logger.getRootLogger().removeAppender(_appender);
+
+ //Call close on our appender. This will clear the log messages
+ // from Memory
+ _appender.close();
+ }
+
+ /**
+ * Verify that the default configuraion of Log4jMessageLogger will
+ * log a message.
+ *
+ */
+ public void testDefaultLogsMessage()
+ {
+ // Create a logger to test
+ Log4jMessageLogger logger = new Log4jMessageLogger();
+
+ //Create Message for test
+ String message = "testDefaults";
+
+ // Log the message
+ logger.rawMessage(message);
+
+ verifyLogPresent(message);
+ }
+
+ /**
+ * This test verifies that the Log4jMessageLogger does not inherit a logging
+ * level from the RootLogger. The Log4jMessageLogger default of INFO
+ * will result in logging being presented.
+ *
+ */
+ public void testLoggerDoesNotInheritRootLevel()
+ {
+ //Set default logger level to off
+ Logger.getRootLogger().setLevel(Level.OFF);
+
+ testDefaultLogsMessage();
+ }
+
+ /**
+ * Test that changing the logger works.
+ * <p/>
+ * Test this by setting the default logger level to off which has been
+ * verified to work by test 'testDefaultsLevelObeyed'
+ *
+ */
+ public void testDefaultLoggerAdjustment()
+ {
+ String loggerName = "TestLogger";
+ // Create a logger to test
+ Log4jMessageLogger logger = new Log4jMessageLogger(Log4jMessageLogger.DEFAULT_LEVEL, loggerName);
+
+ //Create Message for test
+ String message = "testDefaults";
+
+ //Disable the default Log4jMessageLogger logger
+ Level originalLevel = Logger.getLogger(Log4jMessageLogger.DEFAULT_LOGGER).getLevel();
+ Logger.getLogger(Log4jMessageLogger.DEFAULT_LOGGER).setLevel(Level.OFF);
+
+ // Log the message
+ logger.rawMessage(message);
+
+ verifyLogPresent(message);
+
+ // Restore the logging level
+ Logger.getLogger(Log4jMessageLogger.DEFAULT_LOGGER).setLevel(originalLevel);
+ }
+
+
+ /**
+ * Check that the Log Message reached log4j
+ * @param message the message to search for
+ */
+ private void verifyLogPresent(String message)
+ {
+ List<String> results = findMessageInLog(message);
+
+ //Validate we only got one message
+ assertEquals("The result set was not as expected.", 1, results.size());
+
+ // Validate message
+ String line = results.get(0);
+
+ assertNotNull("No Message retrieved from log file", line);
+ assertTrue("Message not contained in log.:" + line,
+ line.contains(message));
+ }
+
+ /**
+ * Check that the given Message is not present in the log4j records.
+ * @param message the message to search for
+ */
+ private void verifyNoLog(String message)
+ {
+ List<String> results = findMessageInLog(message);
+
+ //Validate we only got one message
+ if (results.size() > 0)
+ {
+ System.err.println("Unexpected Log messages");
+
+ for (String msg : results)
+ {
+ System.err.println(msg);
+ }
+ }
+
+ assertEquals("No messages expected.", 0, results.size());
+ }
+
+ /**
+ * Get the appenders list of events and return a list of all the messages
+ * that contain the given message
+ *
+ * @param message the search string
+ * @return The list of all logged messages that contain the search string.
+ */
+ private List<String> findMessageInLog(String message)
+ {
+ List<LoggingEvent> log = _appender.getLog();
+
+ // Search Results for requested message
+ List<String> result = new LinkedList<String>();
+
+ for (LoggingEvent event : log)
+ {
+ if (String.valueOf(event.getMessage()).contains(message))
+ {
+ result.add(String.valueOf(event.getMessage()));
+ }
+ }
+
+ return result;
+ }
+
+
+ /**
+ * Log4j Appender that simply records all the Logging Events so we can
+ * verify that the above logging will make it to log4j in a unit test.
+ */
+ private class Log4jTestAppender extends AppenderSkeleton
+ {
+ List<LoggingEvent> _log = new LinkedList<LoggingEvent>();
+
+ protected void append(LoggingEvent loggingEvent)
+ {
+ _log.add(loggingEvent);
+ }
+
+ public void close()
+ {
+ _log.clear();
+ }
+
+ /**
+ * @return the list of LoggingEvents that have occured in this Appender
+ */
+ public List<LoggingEvent> getLog()
+ {
+ return _log;
+ }
+
+ public boolean requiresLayout()
+ {
+ return false;
+ }
+ }
+}
+
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/rawloggers/UnitTestMessageLogger.java b/java/broker/src/test/java/org/apache/qpid/server/logging/rawloggers/UnitTestMessageLogger.java
new file mode 100644
index 0000000000..df50cfb57a
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/rawloggers/UnitTestMessageLogger.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.logging.rawloggers;
+
+import org.apache.qpid.server.logging.RawMessageLogger;
+
+import java.util.List;
+import java.util.LinkedList;
+
+public class UnitTestMessageLogger implements RawMessageLogger
+{
+ List<Object> _log;
+
+ public UnitTestMessageLogger()
+ {
+ _log = new LinkedList<Object>();
+ }
+
+
+ public void rawMessage(String message)
+ {
+ _log.add(message);
+ }
+
+ public void rawMessage(String message, Throwable throwable)
+ {
+ _log.add(message);
+ _log.add(throwable);
+ }
+
+
+ public List<Object> getLogMessages()
+ {
+ return _log;
+ }
+
+ public void clearLogMessages()
+ {
+ _log.clear();
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/rawloggers/UnitTestMessageLoggerTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/rawloggers/UnitTestMessageLoggerTest.java
new file mode 100644
index 0000000000..e10de48432
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/rawloggers/UnitTestMessageLoggerTest.java
@@ -0,0 +1,102 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.rawloggers;
+
+import junit.framework.TestCase;
+
+import java.util.List;
+
+/**
+ * Test: UnitTestMessageLoggerTest
+ *
+ * This test verifies that UnitTestMessageLogger adhears to its interface.
+ *
+ * Messages are logged, and Throwables recorded in an array that can be
+ * retreived and cleared.
+ *
+ */
+public class UnitTestMessageLoggerTest extends TestCase
+{
+ private static final String TEST_MESSAGE = "Test";
+ private static final String TEST_THROWABLE = "Test Throwable";
+
+ public void testRawMessage()
+ {
+ UnitTestMessageLogger logger = new UnitTestMessageLogger();
+
+ assertEquals("Messages logged before test start", 0,
+ logger.getLogMessages().size());
+
+ // Log a message
+ logger.rawMessage(TEST_MESSAGE);
+
+ List<Object> messages = logger.getLogMessages();
+
+ assertEquals("Expected to have 1 messages logged", 1, messages.size());
+
+ assertEquals("First message not what was logged",
+ TEST_MESSAGE, messages.get(0));
+ }
+
+ public void testRawMessageWithThrowable()
+ {
+ UnitTestMessageLogger logger = new UnitTestMessageLogger();
+
+ assertEquals("Messages logged before test start", 0,
+ logger.getLogMessages().size());
+
+ // Log a message
+ Throwable throwable = new Throwable(TEST_THROWABLE);
+
+ logger.rawMessage(TEST_MESSAGE, throwable);
+
+ List<Object> messages = logger.getLogMessages();
+
+ assertEquals("Expected to have 2 entries", 2, messages.size());
+
+ assertEquals("Message text not what was logged",
+ TEST_MESSAGE, messages.get(0));
+
+ assertEquals("Message throwable not what was logged",
+ TEST_THROWABLE, ((Throwable) messages.get(1)).getMessage());
+
+ }
+
+ public void testClear()
+ {
+ UnitTestMessageLogger logger = new UnitTestMessageLogger();
+
+ assertEquals("Messages logged before test start", 0,
+ logger.getLogMessages().size());
+
+ // Log a message
+ logger.rawMessage(TEST_MESSAGE);
+
+ assertEquals("Expected to have 1 messages logged",
+ 1, logger.getLogMessages().size());
+
+ logger.clearLogMessages();
+
+ assertEquals("Expected to have no messagse after a clear",
+ 0, logger.getLogMessages().size());
+
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/AbstractTestLogSubject.java b/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/AbstractTestLogSubject.java
new file mode 100644
index 0000000000..905d63ea09
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/AbstractTestLogSubject.java
@@ -0,0 +1,299 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.subjects;
+
+import junit.framework.TestCase;
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.logging.LogActor;
+import org.apache.qpid.server.logging.LogMessage;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.logging.RootMessageLogger;
+import org.apache.qpid.server.logging.RootMessageLoggerImpl;
+import org.apache.qpid.server.logging.actors.TestLogActor;
+import org.apache.qpid.server.logging.rawloggers.UnitTestMessageLogger;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.protocol.InternalTestProtocolSession;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+
+import java.util.List;
+
+/**
+ * Abstract Test for LogSubject testing
+ * Includes common validation code and two common tests.
+ *
+ * Each test class sets up the LogSubject and contains details of how to
+ * validate this class then performs a log statement with logging enabled and
+ * logging disabled.
+ *
+ * The resulting log file is then validated.
+ *
+ */
+public abstract class AbstractTestLogSubject extends TestCase
+{
+ protected Configuration _config = new PropertiesConfiguration();
+ protected LogSubject _subject = null;
+
+ AMQProtocolSession _session;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+
+ _config.setProperty(ServerConfiguration.STATUS_UPDATES, "ON");
+
+ VirtualHost virtualHost = ApplicationRegistry.getInstance().
+ getVirtualHostRegistry().getVirtualHosts().iterator().next();
+
+ // Create a single session for this test.
+ _session = new InternalTestProtocolSession(virtualHost);
+ }
+
+ public void tearDown() throws Exception
+ {
+ // Correctly Close the AR that we created above
+ ApplicationRegistry.remove();
+
+ super.tearDown();
+ }
+
+ protected List<Object> performLog() throws ConfigurationException
+ {
+ if (_subject == null)
+ {
+ throw new NullPointerException("LogSubject has not been set");
+ }
+
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+
+ UnitTestMessageLogger logger = new UnitTestMessageLogger();
+ RootMessageLogger rootLogger =
+ new RootMessageLoggerImpl(serverConfig, logger);
+
+ LogActor actor = new TestLogActor(rootLogger);
+
+ actor.message(_subject, new LogMessage()
+ {
+ public String toString()
+ {
+ return "<Log Message>";
+ }
+ });
+
+ return logger.getLogMessages();
+ }
+
+ /**
+ * Verify that the connection section has the expected items
+ *
+ * @param connectionID - The connection id (int) to check for
+ * @param user - the Connected username
+ * @param ipString - the ipString/hostname
+ * @param vhost - the virtualhost that the user connected to.
+ * @param message - the message these values should appear in.
+ */
+ protected void verifyConnection(long connectionID, String user, String ipString, String vhost, String message)
+ {
+ // This should return us MockProtocolSessionUser@null/test
+ String connectionSlice = getSlice("con:" + connectionID, message);
+
+ assertNotNull("Unable to find connection 'con:" + connectionID + "'",
+ connectionSlice);
+
+ // Exract the userName
+ String[] userNameParts = connectionSlice.split("@");
+
+ assertEquals("Unable to split Username from rest of Connection:"
+ + connectionSlice, 2, userNameParts.length);
+
+ assertEquals("Username not as expected", userNameParts[0], user);
+
+ // Extract IP.
+ // The connection will be of the format - guest@/127.0.0.1:1/test
+ // and so our userNamePart will be '/127.0.0.1:1/test'
+ String[] ipParts = userNameParts[1].split("/");
+
+ // We will have three sections
+ assertEquals("Unable to split IP from rest of Connection:"
+ + userNameParts[1], 3, ipParts.length);
+
+ // We need to skip the first '/' split will be empty so validate 1 as IP
+ assertEquals("IP not as expected", ipString, ipParts[1]);
+
+ //Finally check vhost which is section 2
+ assertEquals("Virtualhost name not as expected.", vhost, ipParts[2]);
+ }
+
+ /**
+ * Verify that the RoutingKey is present in the provided message.
+ *
+ * @param message The message to check
+ * @param routingKey The routing key to check against
+ */
+ protected void verifyRoutingKey(String message, AMQShortString routingKey)
+ {
+ String routingKeySlice = getSlice("rk", message);
+
+ assertNotNull("Routing Key not found:" + message, routingKey);
+
+ assertEquals("Routing key not correct",
+ routingKey.toString(), routingKeySlice);
+ }
+
+ /**
+ * Verify that the given Queue's name exists in the provided message
+ *
+ * @param message The message to check
+ * @param queue The queue to check against
+ */
+ protected void verifyQueue(String message, AMQQueue queue)
+ {
+ String queueSlice = getSlice("qu", message);
+
+ assertNotNull("Queue not found:" + message, queueSlice);
+
+ assertEquals("Queue name not correct",
+ queue.getName().toString(), queueSlice);
+ }
+
+ /**
+ * Verify that the given exchange (name and type) are present in the
+ * provided message.
+ *
+ * @param message The message to check
+ * @param exchange the exchange to check against
+ */
+ protected void verifyExchange(String message, Exchange exchange)
+ {
+ String exchangeSilce = getSlice("ex", message);
+
+ assertNotNull("Exchange not found:" + message, exchangeSilce);
+
+ String[] exchangeParts = exchangeSilce.split("/");
+
+ assertEquals("Exchange should be in two parts ex(type/name)", 2,
+ exchangeParts.length);
+
+ assertEquals("Exchange type not correct",
+ exchange.getType().toString(), exchangeParts[0]);
+
+ assertEquals("Exchange name not correct",
+ exchange.getName().toString(), exchangeParts[1]);
+
+ }
+
+ /**
+ * Verify that a VirtualHost with the given name appears in the given
+ * message.
+ *
+ * @param message the message to search
+ * @param vhost the vhostName to check against
+ */
+ static public void verifyVirtualHost(String message, VirtualHost vhost)
+ {
+ String vhostSlice = getSlice("vh", message);
+
+ assertNotNull("Virtualhost not found:" + message, vhostSlice);
+
+ assertEquals("Virtualhost not correct", "/" + vhost.getName(), vhostSlice);
+ }
+
+ /**
+ * Parse the log message and return the slice according to the following:
+ * Given Example:
+ * con:1(guest@127.0.0.1/test)/ch:2/ex(amq.direct)/qu(myQueue)/rk(myQueue)
+ *
+ * Each item (except channel) is of the format <key>(<values>)
+ *
+ * So Given an ID to slice on:
+ * con:1 - Connection 1
+ * ex - exchange
+ * qu - queue
+ * rk - routing key
+ *
+ * @param sliceID the slice to locate
+ * @param message the message to search in
+ *
+ * @return the slice if found otherwise null is returned
+ */
+ static public String getSlice(String sliceID, String message)
+ {
+ int indexOfSlice = message.indexOf(sliceID + "(");
+
+ if (indexOfSlice == -1)
+ {
+ return null;
+ }
+
+ int endIndex = message.indexOf(')', indexOfSlice);
+
+ if (endIndex == -1)
+ {
+ return null;
+ }
+
+ return message.substring(indexOfSlice + 1 + sliceID.length(),
+ endIndex);
+ }
+
+ /**
+ * Test that when Logging occurs a single log statement is provided
+ *
+ * @throws ConfigurationException
+ */
+ public void testEnabled() throws ConfigurationException
+ {
+ List<Object> logs = performLog();
+
+ assertEquals("Log has incorrect message count", 1, logs.size());
+
+ validateLogStatement(String.valueOf(logs.get(0)));
+ }
+
+ /**
+ * Call to the individiual tests to validate the message is formatted as
+ * expected
+ *
+ * @param message the message whos format needs validation
+ */
+ protected abstract void validateLogStatement(String message);
+
+ /**
+ * Ensure that when status-updates are off this does not perform logging
+ *
+ * @throws ConfigurationException
+ */
+ public void testDisabled() throws ConfigurationException
+ {
+ _config.setProperty(ServerConfiguration.STATUS_UPDATES, "OFF");
+
+ List<Object> logs = performLog();
+
+ assertEquals("Log has incorrect message count", 0, logs.size());
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/BindingLogSubjectTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/BindingLogSubjectTest.java
new file mode 100644
index 0000000000..6319238841
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/BindingLogSubjectTest.java
@@ -0,0 +1,71 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.subjects;
+
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.MockAMQQueue;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+/**
+ * Validate BindingLogSubjects are logged as expected
+ */
+public class BindingLogSubjectTest extends AbstractTestLogSubject
+{
+
+ AMQQueue _queue;
+ AMQShortString _routingKey;
+ Exchange _exchange;
+ VirtualHost _testVhost;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+
+ _testVhost = ApplicationRegistry.getInstance().getVirtualHostRegistry().
+ getVirtualHost("test");
+ // Configure items for subjectCreation
+ _routingKey = new AMQShortString("RoutingKey");
+ _exchange = _testVhost.getExchangeRegistry().getDefaultExchange();
+ _queue = new MockAMQQueue("BindingLogSubjectTest");
+ ((MockAMQQueue) _queue).setVirtualHost(_testVhost);
+
+ _subject = new BindingLogSubject(_routingKey, _exchange, _queue);
+ }
+
+ /**
+ * Validate that the logged Subject message is as expected:
+ * MESSAGE [Blank][vh(/test)/ex(direct/<<default>>)/qu(BindingLogSubjectTest)/rk(RoutingKey)] <Log Message>
+ * @param message the message whos format needs validation
+ */
+ @Override
+ protected void validateLogStatement(String message)
+ {
+ verifyVirtualHost(message, _testVhost);
+ verifyExchange(message, _exchange);
+ verifyQueue(message, _queue);
+ verifyRoutingKey(message, _routingKey);
+ }
+
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/ChannelLogSubjectTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/ChannelLogSubjectTest.java
new file mode 100644
index 0000000000..41760e1b05
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/ChannelLogSubjectTest.java
@@ -0,0 +1,58 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.subjects;
+
+import org.apache.qpid.server.AMQChannel;
+
+/**
+ * Validate ChannelLogSubjects are logged as expected
+ */
+public class ChannelLogSubjectTest extends ConnectionLogSubjectTest
+{
+ private final int _channelID = 1;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+
+ AMQChannel channel = new AMQChannel(_session, _channelID, _session.getVirtualHost().getMessageStore());
+
+ _subject = new ChannelLogSubject(channel);
+ }
+
+ /**
+ * MESSAGE [Blank][con:0(MockProtocolSessionUser@null/test)/ch:1] <Log Message>
+ *
+ * @param message the message whos format needs validation
+ */
+ protected void validateLogStatement(String message)
+ {
+ // Use the ConnectionLogSubjectTest to vaildate that the connection
+ // section is ok
+ super.validateLogStatement(message);
+
+ // Finally check that the channel identifier is correctly added
+ assertTrue("Channel 1 identifier not found as part of Subject",
+ message.contains(")/ch:1]"));
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubjectTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubjectTest.java
new file mode 100644
index 0000000000..92234e9241
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubjectTest.java
@@ -0,0 +1,46 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.subjects;
+
+/**
+ * Validate ConnectionLogSubjects are logged as expected
+ */
+public class ConnectionLogSubjectTest extends AbstractTestLogSubject
+{
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+
+ _subject = new ConnectionLogSubject(_session);
+ }
+
+ /**
+ * MESSAGE [Blank][con:0(MockProtocolSessionUser@null/test)] <Log Message>
+ *
+ * @param message the message whos format needs validation
+ */
+ protected void validateLogStatement(String message)
+ {
+ verifyConnection(_session.getSessionID(), "InternalTestProtocolSession", "127.0.0.1:1", "test", message);
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubjectTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubjectTest.java
new file mode 100644
index 0000000000..7e16516fc6
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubjectTest.java
@@ -0,0 +1,58 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.subjects;
+
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+
+/**
+ * Validate ExchangeLogSubjects are logged as expected
+ */
+public class ExchangeLogSubjectTest extends AbstractTestLogSubject
+{
+ Exchange _exchange;
+ VirtualHost _testVhost;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+
+ _testVhost = ApplicationRegistry.getInstance().getVirtualHostRegistry().
+ getVirtualHost("test");
+
+ _exchange = _testVhost.getExchangeRegistry().getDefaultExchange();
+ _subject = new ExchangeLogSubject(_exchange,_testVhost);
+ }
+
+ /**
+ * Validate that the logged Subject message is as expected:
+ * MESSAGE [Blank][vh(/test)/ex(direct/<<default>>)] <Log Message>
+ * @param message the message whos format needs validation
+ */
+ @Override
+ protected void validateLogStatement(String message)
+ {
+ verifyVirtualHost(message, _testVhost);
+ verifyExchange(message, _exchange);
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/MessageStoreLogSubjectTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/MessageStoreLogSubjectTest.java
new file mode 100644
index 0000000000..9c868ea651
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/MessageStoreLogSubjectTest.java
@@ -0,0 +1,62 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.subjects;
+
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+
+/**
+ * Validate MessageStoreLogSubjects are logged as expected
+ */
+public class MessageStoreLogSubjectTest extends AbstractTestLogSubject
+{
+ VirtualHost _testVhost;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+
+ _testVhost = ApplicationRegistry.getInstance().getVirtualHostRegistry().
+ getVirtualHost("test");
+
+ _subject = new MessageStoreLogSubject(_testVhost, _testVhost.getMessageStore());
+ }
+
+ /**
+ * Validate that the logged Subject message is as expected:
+ * MESSAGE [Blank][vh(/test)/ms(MemoryMessageStore)] <Log Message>
+ * @param message the message whos format needs validation
+ */
+ @Override
+ protected void validateLogStatement(String message)
+ {
+ verifyVirtualHost(message, _testVhost);
+
+ String msSlice = getSlice("ms", message);
+
+ assertNotNull("MessageStore not found:" + message, msSlice);
+
+ assertEquals("MessageStore not correct",
+ _testVhost.getMessageStore().getClass().getSimpleName(),
+ msSlice);
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/QueueLogSubjectTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/QueueLogSubjectTest.java
new file mode 100644
index 0000000000..d46e1ee11b
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/QueueLogSubjectTest.java
@@ -0,0 +1,62 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.subjects;
+
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.MockAMQQueue;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+/**
+ * Validate QueueLogSubjects are logged as expected
+ */
+public class QueueLogSubjectTest extends AbstractTestLogSubject
+{
+
+ AMQQueue _queue;
+ VirtualHost _testVhost;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+
+ _testVhost = ApplicationRegistry.getInstance().getVirtualHostRegistry().
+ getVirtualHost("test");
+
+ _queue = new MockAMQQueue("QueueLogSubjectTest");
+ ((MockAMQQueue) _queue).setVirtualHost(_testVhost);
+
+ _subject = new QueueLogSubject(_queue);
+ }
+
+ /**
+ * Validate that the logged Subject message is as expected:
+ * MESSAGE [Blank][vh(/test)/qu(QueueLogSubjectTest)] <Log Message>
+ *
+ * @param message the message whos format needs validation
+ */
+ @Override
+ protected void validateLogStatement(String message)
+ {
+ verifyVirtualHost(message, _testVhost);
+ verifyQueue(message, _queue);
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubjectTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubjectTest.java
new file mode 100644
index 0000000000..e96dc47367
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/SubscriptionLogSubjectTest.java
@@ -0,0 +1,105 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.subjects;
+
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.flow.LimitlessCreditManager;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.MockAMQQueue;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.subscription.SubscriptionFactory;
+import org.apache.qpid.server.subscription.SubscriptionFactoryImpl;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+/**
+ * Validate SubscriptionLogSubjects are logged as expected
+ */
+public class SubscriptionLogSubjectTest extends AbstractTestLogSubject
+{
+
+ AMQQueue _queue;
+ VirtualHost _testVhost;
+ private int _channelID = 1;
+ Subscription _subscription;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+
+ _testVhost = ApplicationRegistry.getInstance().getVirtualHostRegistry().
+ getVirtualHost("test");
+
+ _queue = new MockAMQQueue("SubscriptionLogSubjectTest");
+ ((MockAMQQueue) _queue).setVirtualHost(_testVhost);
+
+ AMQChannel channel = new AMQChannel(_session, _channelID, _session.getVirtualHost().getMessageStore());
+
+ _session.addChannel(channel);
+
+ SubscriptionFactory factory = new SubscriptionFactoryImpl();
+
+ _subscription = factory.createSubscription(_channelID, _session, new AMQShortString("cTag"),
+ false, null, false,
+ new LimitlessCreditManager());
+
+ _subscription.setQueue(_queue, false);
+
+ _subject = new SubscriptionLogSubject(_subscription);
+ }
+
+ /**
+ * Validate that the logged Subject message is as expected:
+ * MESSAGE [Blank][sub:0(vh(/test)/qu(SubscriptionLogSubjectTest))] <Log Message>
+ *
+ * @param message the message whos format needs validation
+ */
+ @Override
+ protected void validateLogStatement(String message)
+ {
+ String subscriptionSlice = getSlice("sub:"
+ + _subscription.getSubscriptionID(),
+ message);
+
+ assertNotNull("Unable to locate subscription 'sub:" +
+ _subscription.getSubscriptionID() + "'");
+
+
+
+ // Pull out the qu(..) section from the subscription message
+ // Split it into three parts
+ // MESSAGE [Blank][sub:0(vh(/
+ // test)/
+ // qu(SubscriptionLogSubjectTest))]
+ // Take the last bit and drop off the extra )]
+ String[] parts = message.split("/");
+ assertEquals("Message part count wrong", 3, parts.length);
+ String subscription = parts[2].substring(0, parts[2].indexOf(")") + 1);
+
+ // Adding the ')' is a bit ugly but SubscriptionLogSubject is the only
+ // Subject that nests () and so the simple parser of checking for the
+ // next ')' falls down.
+ verifyVirtualHost(subscriptionSlice+ ")", _queue.getVirtualHost());
+
+ verifyQueue(subscription, _queue);
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/TestBlankSubject.java b/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/TestBlankSubject.java
new file mode 100644
index 0000000000..89688e13b3
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/TestBlankSubject.java
@@ -0,0 +1,33 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging.subjects;
+
+/**
+ * Blank Subject for testing
+ */
+public class TestBlankSubject extends AbstractLogSubject
+{
+ public TestBlankSubject()
+ {
+ _logString = "[TestBlankSubject]";
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/plugins/MockPluginManager.java b/java/broker/src/test/java/org/apache/qpid/server/plugins/MockPluginManager.java
new file mode 100644
index 0000000000..9599848dde
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/plugins/MockPluginManager.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.server.plugins;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.qpid.server.exchange.ExchangeType;
+import org.apache.qpid.server.security.access.ACLPlugin;
+import org.apache.qpid.server.security.access.ACLPluginFactory;
+import org.apache.qpid.server.security.access.QueueDenier;
+
+public class MockPluginManager extends PluginManager
+{
+
+ private Map<String, ACLPluginFactory> _securityPlugins = new HashMap<String, ACLPluginFactory>();
+
+ public MockPluginManager(String plugindir) throws Exception
+ {
+ super(plugindir);
+ _securityPlugins.put("org.apache.qpid.server.security.access.QueueDenier", QueueDenier.FACTORY);
+ }
+
+ @Override
+ public Map<String, ExchangeType<?>> getExchanges()
+ {
+ return null;
+ }
+
+ @Override
+ public Map<String, ACLPluginFactory> getSecurityPlugins()
+ {
+ return _securityPlugins;
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/plugins/PluginTest.java b/java/broker/src/test/java/org/apache/qpid/server/plugins/PluginTest.java
new file mode 100644
index 0000000000..11d6105704
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/plugins/PluginTest.java
@@ -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 org.apache.qpid.server.plugins;
+
+import java.util.Map;
+
+import org.apache.qpid.server.exchange.ExchangeType;
+
+import junit.framework.TestCase;
+
+public class PluginTest extends TestCase
+{
+
+ private static final String TEST_EXCHANGE_CLASS = "org.apache.qpid.extras.exchanges.example.TestExchangeType";
+ private static final String PLUGIN_DIRECTORY = System.getProperty("example.plugin.target");
+
+ public void testLoadExchanges() throws Exception
+ {
+ PluginManager manager = new PluginManager(PLUGIN_DIRECTORY);
+ Map<String, ExchangeType<?>> exchanges = manager.getExchanges();
+ assertNotNull("No exchanges found in "+PLUGIN_DIRECTORY, exchanges);
+ assertEquals("Wrong number of exchanges found in "+PLUGIN_DIRECTORY,
+ 2, exchanges.size());
+ assertNotNull("Wrong exchange found in "+PLUGIN_DIRECTORY,
+ exchanges.get(TEST_EXCHANGE_CLASS));
+ }
+
+ public void testNoExchanges() throws Exception
+ {
+ PluginManager manager = new PluginManager("/path/to/nowhere");
+ Map<String, ExchangeType<?>> exchanges = manager.getExchanges();
+ assertEquals("Exchanges found", 0, exchanges.size());
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java b/java/broker/src/test/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java
new file mode 100644
index 0000000000..9152e68ee0
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java
@@ -0,0 +1,150 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.protocol;
+
+import junit.framework.TestCase;
+import org.apache.log4j.Logger;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.management.common.mbeans.ManagedConnection;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.AMQQueueFactory;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.SkeletonMessageStore;
+
+import javax.management.JMException;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+
+
+/** Test class to test MBean operations for AMQMinaProtocolSession. */
+public class AMQProtocolSessionMBeanTest extends TestCase
+{
+ /** Used for debugging. */
+ private static final Logger log = Logger.getLogger(AMQProtocolSessionMBeanTest.class);
+
+ private MessageStore _messageStore = new SkeletonMessageStore();
+ private AMQProtocolEngine _protocolSession;
+ private AMQChannel _channel;
+ private AMQProtocolSessionMBean _mbean;
+
+ public void testChannels() throws Exception
+ {
+ // check the channel count is correct
+ int channelCount = _mbean.channels().size();
+ assertTrue(channelCount == 1);
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue_" + System.currentTimeMillis()),
+ false,
+ new AMQShortString("test"),
+ true,
+ _protocolSession.getVirtualHost(), null);
+ AMQChannel channel = new AMQChannel(_protocolSession, 2, _messageStore);
+ channel.setDefaultQueue(queue);
+ _protocolSession.addChannel(channel);
+ channelCount = _mbean.channels().size();
+ assertTrue(channelCount == 2);
+
+ // general properties test
+ _mbean.setMaximumNumberOfChannels(1000L);
+ assertTrue(_mbean.getMaximumNumberOfChannels() == 1000L);
+
+ // check APIs
+ AMQChannel channel3 = new AMQChannel(_protocolSession, 3, _messageStore);
+ channel3.setLocalTransactional();
+ _protocolSession.addChannel(channel3);
+ _mbean.rollbackTransactions(2);
+ _mbean.rollbackTransactions(3);
+ _mbean.commitTransactions(2);
+ _mbean.commitTransactions(3);
+
+ // This should throw exception, because the channel does't exist
+ try
+ {
+ _mbean.commitTransactions(4);
+ fail();
+ }
+ catch (JMException ex)
+ {
+ log.debug("expected exception is thrown :" + ex.getMessage());
+ }
+
+ // check channels() return type conveys flow control blocking status correctly
+ AMQChannel channel4 = new AMQChannel(_protocolSession, 4, _messageStore);
+ _protocolSession.addChannel(channel4);
+ channel4.setDefaultQueue(queue);
+
+ final String blocking = ManagedConnection.COMPOSITE_ITEM_NAMES[4];
+ TabularData channels = _mbean.channels();
+ CompositeData chan4result = channels.get(new Integer[]{4});
+ assertNotNull(chan4result);
+ assertEquals("Flow should not have been blocked", false, chan4result.get(blocking));
+
+ channel4.block(queue);
+ channels = _mbean.channels();
+ chan4result = channels.get(new Integer[]{4});
+ assertNotNull(chan4result);
+ assertEquals("Flow should have been blocked", true, chan4result.get(blocking));
+
+ channel4.unblock(queue);
+ channels = _mbean.channels();
+ chan4result = channels.get(new Integer[]{4});
+ assertNotNull(chan4result);
+ assertEquals("Flow should have been unblocked", false, chan4result.get(blocking));
+
+ // check if closing of session works
+ _protocolSession.addChannel(new AMQChannel(_protocolSession, 5, _messageStore));
+ _mbean.closeConnection();
+ try
+ {
+ channelCount = _mbean.channels().size();
+ assertTrue(channelCount == 0);
+ // session is now closed so adding another channel should throw an exception
+ _protocolSession.addChannel(new AMQChannel(_protocolSession, 6, _messageStore));
+ fail();
+ }
+ catch (AMQException ex)
+ {
+ log.debug("expected exception is thrown :" + ex.getMessage());
+ }
+ }
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ VirtualHost vhost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test");
+ _protocolSession = new InternalTestProtocolSession(vhost);
+
+ _channel = new AMQChannel(_protocolSession, 1, _messageStore);
+ _protocolSession.addChannel(_channel);
+ _mbean = (AMQProtocolSessionMBean) _protocolSession.getManagedObject();
+ }
+
+ @Override
+ protected void tearDown()
+ {
+ ApplicationRegistry.remove();
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java b/java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java
index 51012bc776..681e513ecb 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java
+++ b/java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java
@@ -20,35 +20,44 @@
*/
package org.apache.qpid.server.protocol;
+import java.security.Principal;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+
import org.apache.qpid.AMQException;
-import org.apache.qpid.codec.AMQCodecFactory;
import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.server.output.ProtocolOutputConverter;
-import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.AMQChannel;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.message.MessageContentSource;
+import org.apache.qpid.transport.TestNetworkDriver;
-public class InternalTestProtocolSession extends AMQMinaProtocolSession implements ProtocolOutputConverter
+public class InternalTestProtocolSession extends AMQProtocolEngine implements ProtocolOutputConverter
{
// ChannelID(LIST) -> LinkedList<Pair>
final Map<Integer, Map<AMQShortString, LinkedList<DeliveryPair>>> _channelDelivers;
private AtomicInteger _deliveryCount = new AtomicInteger(0);
- public InternalTestProtocolSession() throws AMQException
+ public InternalTestProtocolSession(VirtualHost virtualHost) throws AMQException
{
- super(new TestIoSession(),
- ApplicationRegistry.getInstance().getVirtualHostRegistry(),
- new AMQCodecFactory(true));
+ super(ApplicationRegistry.getInstance().getVirtualHostRegistry(), new TestNetworkDriver());
_channelDelivers = new HashMap<Integer, Map<AMQShortString, LinkedList<DeliveryPair>>>();
+ // Need to authenticate session for it to be representative testing.
+ setAuthorizedID(new Principal()
+ {
+ public String getName()
+ {
+ return "InternalTestProtocolSession";
+ }
+ });
+
+ setVirtualHost(virtualHost);
}
public ProtocolOutputConverter getProtocolOutputConverter()
@@ -61,6 +70,16 @@ public class InternalTestProtocolSession extends AMQMinaProtocolSession implemen
return (byte) 8;
}
+ public void writeReturn(MessagePublishInfo messagePublishInfo,
+ ContentHeaderBody header,
+ MessageContentSource msgContent,
+ int channelId,
+ int replyCode,
+ AMQShortString replyText) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
public byte getProtocolMinorVersion()
{
return (byte) 0;
@@ -72,7 +91,14 @@ public class InternalTestProtocolSession extends AMQMinaProtocolSession implemen
{
synchronized (_channelDelivers)
{
- List<DeliveryPair> msgs = _channelDelivers.get(channelId).get(consumerTag).subList(0, count);
+ List<DeliveryPair> all =_channelDelivers.get(channelId).get(consumerTag);
+
+ if (all == null)
+ {
+ return new ArrayList<DeliveryPair>(0);
+ }
+
+ List<DeliveryPair> msgs = all.subList(0, count);
List<DeliveryPair> response = new ArrayList<DeliveryPair>(msgs);
@@ -92,7 +118,7 @@ public class InternalTestProtocolSession extends AMQMinaProtocolSession implemen
{
}
- public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) throws AMQException
+ public void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag) throws AMQException
{
_deliveryCount.incrementAndGet();
@@ -114,11 +140,11 @@ public class InternalTestProtocolSession extends AMQMinaProtocolSession implemen
consumers.put(consumerTag, consumerDelivers);
}
- consumerDelivers.add(new DeliveryPair(deliveryTag, message));
+ consumerDelivers.add(new DeliveryPair(deliveryTag, (AMQMessage)entry.getMessage()));
}
}
- public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException
+ public void writeGetOk(QueueEntry message, int channelId, long deliveryTag, int queueSize) throws AMQException
{
}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/protocol/MaxChannelsTest.java b/java/broker/src/test/java/org/apache/qpid/server/protocol/MaxChannelsTest.java
new file mode 100644
index 0000000000..13e712dbac
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/protocol/MaxChannelsTest.java
@@ -0,0 +1,86 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.protocol;
+
+import junit.framework.TestCase;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+
+/** Test class to test MBean operations for AMQMinaProtocolSession. */
+public class MaxChannelsTest extends TestCase
+{
+ private AMQProtocolEngine _session;
+
+ public void testChannels() throws Exception
+ {
+ VirtualHost vhost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test");
+ _session = new InternalTestProtocolSession(vhost);
+
+ // check the channel count is correct
+ int channelCount = _session.getChannels().size();
+ assertEquals("Initial channel count wrong", 0, channelCount);
+
+ long maxChannels = 10L;
+ _session.setMaximumNumberOfChannels(maxChannels);
+ assertEquals("Number of channels not correctly set.", new Long(maxChannels), _session.getMaximumNumberOfChannels());
+
+
+ try
+ {
+ for (long currentChannel = 0L; currentChannel < maxChannels; currentChannel++)
+ {
+ _session.addChannel(new AMQChannel(_session, (int) currentChannel, null));
+ }
+ }
+ catch (AMQException e)
+ {
+ assertEquals("Wrong exception recevied.", e.getErrorCode(), AMQConstant.NOT_ALLOWED);
+ }
+ assertEquals("Maximum number of channels not set.", new Long(maxChannels), new Long(_session.getChannels().size()));
+ }
+
+ @Override
+ public void setUp()
+ {
+ //Highlight that this test will cause a new AR to be created
+ ApplicationRegistry.getInstance();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ try {
+ _session.closeSession();
+ } catch (AMQException e) {
+ // Yikes
+ fail(e.getMessage());
+ }
+ finally
+ {
+ // Correctly Close the AR we created
+ ApplicationRegistry.remove();
+ }
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/protocol/TestIoSession.java b/java/broker/src/test/java/org/apache/qpid/server/protocol/TestIoSession.java
deleted file mode 100644
index ff4d3ed9fb..0000000000
--- a/java/broker/src/test/java/org/apache/qpid/server/protocol/TestIoSession.java
+++ /dev/null
@@ -1,295 +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.
- *
- */
-package org.apache.qpid.server.protocol;
-
-import org.apache.mina.common.*;
-import org.apache.mina.transport.socket.nio.SocketAcceptorConfig;
-import org.apache.qpid.pool.ReadWriteThreadModel;
-
-import java.net.SocketAddress;
-import java.net.InetSocketAddress;
-import java.util.Set;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Test implementation of IoSession, which is required for some tests. Methods not being used are not implemented,
- * so if this class is being used and some methods are to be used, then please update those.
- */
-public class TestIoSession implements IoSession
-{
- private final ConcurrentMap attributes = new ConcurrentHashMap();
-
- public TestIoSession()
- {
- }
-
- public IoService getService()
- {
- return null;
- }
-
- public IoServiceConfig getServiceConfig()
- {
- return new TestIoConfig();
- }
-
- public IoHandler getHandler()
- {
- return null;
- }
-
- public IoSessionConfig getConfig()
- {
- return null;
- }
-
- public IoFilterChain getFilterChain()
- {
- return null;
- }
-
- public WriteFuture write(Object message)
- {
- return null;
- }
-
- public CloseFuture close()
- {
- return null;
- }
-
- public Object getAttachment()
- {
- return getAttribute("");
- }
-
- public Object setAttachment(Object attachment)
- {
- return setAttribute("",attachment);
- }
-
- public Object getAttribute(String key)
- {
- return attributes.get(key);
- }
-
- public Object setAttribute(String key, Object value)
- {
- return attributes.put(key,value);
- }
-
- public Object setAttribute(String key)
- {
- return attributes.put(key, Boolean.TRUE);
- }
-
- public Object removeAttribute(String key)
- {
- return attributes.remove(key);
- }
-
- public boolean containsAttribute(String key)
- {
- return attributes.containsKey(key);
- }
-
- public Set getAttributeKeys()
- {
- return attributes.keySet();
- }
-
- public TransportType getTransportType()
- {
- return null;
- }
-
- public boolean isConnected()
- {
- return false;
- }
-
- public boolean isClosing()
- {
- return false;
- }
-
- public CloseFuture getCloseFuture()
- {
- return null;
- }
-
- public SocketAddress getRemoteAddress()
- {
- return new InetSocketAddress("127.0.0.1", 1234);
- }
-
- public SocketAddress getLocalAddress()
- {
- return null;
- }
-
- public SocketAddress getServiceAddress()
- {
- return null;
- }
-
- public int getIdleTime(IdleStatus status)
- {
- return 0;
- }
-
- public long getIdleTimeInMillis(IdleStatus status)
- {
- return 0;
- }
-
- public void setIdleTime(IdleStatus status, int idleTime)
- {
-
- }
-
- public int getWriteTimeout()
- {
- return 0;
- }
-
- public long getWriteTimeoutInMillis()
- {
- return 0;
- }
-
- public void setWriteTimeout(int writeTimeout)
- {
-
- }
-
- public TrafficMask getTrafficMask()
- {
- return null;
- }
-
- public void setTrafficMask(TrafficMask trafficMask)
- {
-
- }
-
- public void suspendRead()
- {
-
- }
-
- public void suspendWrite()
- {
-
- }
-
- public void resumeRead()
- {
-
- }
-
- public void resumeWrite()
- {
-
- }
-
- public long getReadBytes()
- {
- return 0;
- }
-
- public long getWrittenBytes()
- {
- return 0;
- }
-
- public long getReadMessages()
- {
- return 0;
- }
-
- public long getWrittenMessages()
- {
- return 0;
- }
-
- public long getWrittenWriteRequests()
- {
- return 0;
- }
-
- public int getScheduledWriteRequests()
- {
- return 0;
- }
-
- public int getScheduledWriteBytes()
- {
- return 0;
- }
-
- public long getCreationTime()
- {
- return 0;
- }
-
- public long getLastIoTime()
- {
- return 0;
- }
-
- public long getLastReadTime()
- {
- return 0;
- }
-
- public long getLastWriteTime()
- {
- return 0;
- }
-
- public boolean isIdle(IdleStatus status)
- {
- return false;
- }
-
- public int getIdleCount(IdleStatus status)
- {
- return 0;
- }
-
- public long getLastIdleTime(IdleStatus status)
- {
- return 0;
- }
-
- /**
- * Test implementation of IoServiceConfig
- */
- private class TestIoConfig extends SocketAcceptorConfig
- {
- public ThreadModel getThreadModel()
- {
- return ReadWriteThreadModel.getInstance();
- }
- }
-}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java
new file mode 100644
index 0000000000..dd013e6ad5
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java
@@ -0,0 +1,108 @@
+package org.apache.qpid.server.queue;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+import java.util.ArrayList;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.FieldTable;
+import junit.framework.AssertionFailedError;
+
+public class AMQPriorityQueueTest extends SimpleAMQQueueTest
+{
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ _arguments = new FieldTable();
+ _arguments.put(AMQQueueFactory.X_QPID_PRIORITIES, 3);
+ super.setUp();
+ }
+
+ public void testPriorityOrdering() throws AMQException, InterruptedException
+ {
+
+ // Enqueue messages in order
+ _queue.enqueue(createMessage(1L, (byte) 10));
+ _queue.enqueue(createMessage(2L, (byte) 4));
+ _queue.enqueue(createMessage(3L, (byte) 0));
+
+ // Enqueue messages in reverse order
+ _queue.enqueue(createMessage(4L, (byte) 0));
+ _queue.enqueue(createMessage(5L, (byte) 4));
+ _queue.enqueue(createMessage(6L, (byte) 10));
+
+ // Enqueue messages out of order
+ _queue.enqueue(createMessage(7L, (byte) 4));
+ _queue.enqueue(createMessage(8L, (byte) 10));
+ _queue.enqueue(createMessage(9L, (byte) 0));
+
+ // Register subscriber
+ _queue.registerSubscription(_subscription, false);
+ Thread.sleep(150);
+
+ ArrayList<QueueEntry> msgs = _subscription.getMessages();
+ try
+ {
+ assertEquals(new Long(1L), msgs.get(0).getMessage().getMessageNumber());
+ assertEquals(new Long(6L), msgs.get(1).getMessage().getMessageNumber());
+ assertEquals(new Long(8L), msgs.get(2).getMessage().getMessageNumber());
+
+ assertEquals(new Long(2L), msgs.get(3).getMessage().getMessageNumber());
+ assertEquals(new Long(5L), msgs.get(4).getMessage().getMessageNumber());
+ assertEquals(new Long(7L), msgs.get(5).getMessage().getMessageNumber());
+
+ assertEquals(new Long(3L), msgs.get(6).getMessage().getMessageNumber());
+ assertEquals(new Long(4L), msgs.get(7).getMessage().getMessageNumber());
+ assertEquals(new Long(9L), msgs.get(8).getMessage().getMessageNumber());
+ }
+ catch (AssertionFailedError afe)
+ {
+ // Show message order on failure.
+ int index = 1;
+ for (QueueEntry qe : msgs)
+ {
+ System.err.println(index + ":" + qe.getMessage().getMessageNumber());
+ index++;
+ }
+
+ throw afe;
+ }
+
+ }
+
+ protected AMQMessage createMessage(Long id, byte i) throws AMQException
+ {
+ AMQMessage msg = super.createMessage(id);
+ BasicContentHeaderProperties props = new BasicContentHeaderProperties();
+ props.setPriority(i);
+ msg.getContentHeaderBody().properties = props;
+ return msg;
+ }
+
+ protected AMQMessage createMessage(Long id) throws AMQException
+ {
+ return createMessage(id, (byte) 0);
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java
index 5eafc18378..5f0d77afea 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java
@@ -21,36 +21,33 @@
package org.apache.qpid.server.queue;
import junit.framework.TestCase;
+import org.apache.mina.common.ByteBuffer;
import org.apache.qpid.AMQException;
-import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.MemoryMessageStore;
-import org.apache.qpid.server.store.StoreContext;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.registry.IApplicationRegistry;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.txn.TransactionalContext;
-import org.apache.qpid.server.txn.NonTransactionalContext;
-import org.apache.qpid.server.RequiredDeliveryException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.abstraction.ContentChunk;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.message.MessageMetaData;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.protocol.AMQProtocolEngine;
+import org.apache.qpid.server.protocol.InternalTestProtocolSession;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.registry.IApplicationRegistry;
+import org.apache.qpid.server.store.MemoryMessageStore;
+import org.apache.qpid.server.store.MessageStore;
import org.apache.qpid.server.subscription.Subscription;
import org.apache.qpid.server.subscription.SubscriptionFactoryImpl;
-import org.apache.qpid.server.protocol.AMQMinaProtocolSession;
-import org.apache.qpid.server.protocol.InternalTestProtocolSession;
-import org.apache.qpid.framing.ContentHeaderBody;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.framing.abstraction.ContentChunk;
-import org.apache.mina.common.ByteBuffer;
+import org.apache.qpid.server.virtualhost.VirtualHost;
import javax.management.Notification;
-
import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.Collections;
/** This class tests all the alerts an AMQQueue can throw based on threshold values of different parameters */
public class AMQQueueAlertTest extends TestCase
-{
+{
private final static long MAX_MESSAGE_COUNT = 50;
private final static long MAX_MESSAGE_AGE = 250; // 0.25 sec
private final static long MAX_MESSAGE_SIZE = 2000; // 2 KB
@@ -58,13 +55,8 @@ public class AMQQueueAlertTest extends TestCase
private AMQQueue _queue;
private AMQQueueMBean _queueMBean;
private VirtualHost _virtualHost;
- private AMQMinaProtocolSession _protocolSession;
+ private AMQProtocolEngine _protocolSession;
private MessageStore _messageStore = new MemoryMessageStore();
- private StoreContext _storeContext = new StoreContext();
- private TransactionalContext _transactionalContext = new NonTransactionalContext(_messageStore, _storeContext,
- null,
- new LinkedList<RequiredDeliveryException>()
- );
private static final SubscriptionFactoryImpl SUBSCRIPTION_FACTORY = SubscriptionFactoryImpl.INSTANCE;
/**
@@ -74,6 +66,10 @@ public class AMQQueueAlertTest extends TestCase
*/
public void testMessageCountAlert() throws Exception
{
+ _protocolSession = new InternalTestProtocolSession(_virtualHost);
+ AMQChannel channel = new AMQChannel(_protocolSession, 2, _messageStore);
+ _protocolSession.addChannel(channel);
+
_queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue1"), false, new AMQShortString("AMQueueAlertTest"),
false, _virtualHost,
null);
@@ -81,7 +77,7 @@ public class AMQQueueAlertTest extends TestCase
_queueMBean.setMaximumMessageCount(MAX_MESSAGE_COUNT);
- sendMessages(MAX_MESSAGE_COUNT, 256l);
+ sendMessages(channel, MAX_MESSAGE_COUNT, 256l);
assertTrue(_queueMBean.getMessageCount() == MAX_MESSAGE_COUNT);
Notification lastNotification = _queueMBean.getLastNotification();
@@ -98,6 +94,10 @@ public class AMQQueueAlertTest extends TestCase
*/
public void testMessageSizeAlert() throws Exception
{
+ _protocolSession = new InternalTestProtocolSession(_virtualHost);
+ AMQChannel channel = new AMQChannel(_protocolSession, 2, _messageStore);
+ _protocolSession.addChannel(channel);
+
_queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue2"), false, new AMQShortString("AMQueueAlertTest"),
false, _virtualHost,
null);
@@ -105,7 +105,7 @@ public class AMQQueueAlertTest extends TestCase
_queueMBean.setMaximumMessageCount(MAX_MESSAGE_COUNT);
_queueMBean.setMaximumMessageSize(MAX_MESSAGE_SIZE);
- sendMessages(1, MAX_MESSAGE_SIZE * 2);
+ sendMessages(channel, 1, MAX_MESSAGE_SIZE * 2);
assertTrue(_queueMBean.getMessageCount() == 1);
Notification lastNotification = _queueMBean.getLastNotification();
@@ -124,6 +124,10 @@ public class AMQQueueAlertTest extends TestCase
*/
public void testQueueDepthAlertNoSubscriber() throws Exception
{
+ _protocolSession = new InternalTestProtocolSession(_virtualHost);
+ AMQChannel channel = new AMQChannel(_protocolSession, 2, _messageStore);
+ _protocolSession.addChannel(channel);
+
_queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue3"), false, new AMQShortString("AMQueueAlertTest"),
false, _virtualHost,
null);
@@ -133,7 +137,7 @@ public class AMQQueueAlertTest extends TestCase
while (_queue.getQueueDepth() < MAX_QUEUE_DEPTH)
{
- sendMessages(1, MAX_MESSAGE_SIZE);
+ sendMessages(channel, 1, MAX_MESSAGE_SIZE);
}
Notification lastNotification = _queueMBean.getLastNotification();
@@ -153,6 +157,10 @@ public class AMQQueueAlertTest extends TestCase
*/
public void testMessageAgeAlert() throws Exception
{
+ _protocolSession = new InternalTestProtocolSession(_virtualHost);
+ AMQChannel channel = new AMQChannel(_protocolSession, 2, _messageStore);
+ _protocolSession.addChannel(channel);
+
_queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue4"), false, new AMQShortString("AMQueueAlertTest"),
false, _virtualHost,
null);
@@ -160,14 +168,11 @@ public class AMQQueueAlertTest extends TestCase
_queueMBean.setMaximumMessageCount(MAX_MESSAGE_COUNT);
_queueMBean.setMaximumMessageAge(MAX_MESSAGE_AGE);
- sendMessages(1, MAX_MESSAGE_SIZE);
+ sendMessages(channel, 1, MAX_MESSAGE_SIZE);
// Ensure message sits on queue long enough to age.
Thread.sleep(MAX_MESSAGE_AGE * 2);
- sendMessages(1, MAX_MESSAGE_SIZE);
- assertTrue(_queueMBean.getMessageCount() == 2);
-
Notification lastNotification = _queueMBean.getLastNotification();
assertNotNull(lastNotification);
@@ -185,7 +190,6 @@ public class AMQQueueAlertTest extends TestCase
*/
public void testQueueDepthAlertWithSubscribers() throws Exception
{
- _protocolSession = new InternalTestProtocolSession();
AMQChannel channel = new AMQChannel(_protocolSession, 2, _messageStore);
_protocolSession.addChannel(channel);
@@ -203,8 +207,8 @@ public class AMQQueueAlertTest extends TestCase
// Send messages(no of message to be little more than what can cause a Queue_Depth alert)
int messageCount = Math.round(MAX_QUEUE_DEPTH / MAX_MESSAGE_SIZE) + 10;
- long totalSize = (messageCount * MAX_MESSAGE_SIZE) >> 10;
- sendMessages(messageCount, MAX_MESSAGE_SIZE);
+ long totalSize = (messageCount * MAX_MESSAGE_SIZE);
+ sendMessages(channel, messageCount, MAX_MESSAGE_SIZE);
// Check queueDepth. There should be no messages on the queue and as the subscriber is listening
// so there should be no Queue_Deoth alert raised
@@ -231,7 +235,7 @@ public class AMQQueueAlertTest extends TestCase
_queue.registerSubscription(
subscription2, false);
-
+
while (_queue.getUndeliveredMessageCount()!= 0)
{
Thread.sleep(100);
@@ -283,8 +287,10 @@ public class AMQQueueAlertTest extends TestCase
};
ContentHeaderBody contentHeaderBody = new ContentHeaderBody();
+ BasicContentHeaderProperties props = new BasicContentHeaderProperties();
+ contentHeaderBody.properties = props;
contentHeaderBody.bodySize = size; // in bytes
- IncomingMessage message = new IncomingMessage(_messageStore.getNewMessageId(), publish, _transactionalContext, _protocolSession);
+ IncomingMessage message = new IncomingMessage(publish);
message.setContentHeaderBody(contentHeaderBody);
return message;
@@ -294,28 +300,33 @@ public class AMQQueueAlertTest extends TestCase
protected void setUp() throws Exception
{
super.setUp();
- IApplicationRegistry applicationRegistry = ApplicationRegistry.getInstance(1);
+ IApplicationRegistry applicationRegistry = ApplicationRegistry.getInstance();
_virtualHost = applicationRegistry.getVirtualHostRegistry().getVirtualHost("test");
- _protocolSession = new InternalTestProtocolSession();
-
+ _protocolSession = new InternalTestProtocolSession(_virtualHost);
+ CurrentActor.set(_protocolSession.getLogActor());
}
protected void tearDown()
{
- ApplicationRegistry.remove(1);
+ // Remove the Protocol Session Actor set above
+ CurrentActor.remove();
+ ApplicationRegistry.remove();
}
- private void sendMessages(long messageCount, final long size) throws AMQException
+ private void sendMessages(AMQChannel channel, long messageCount, final long size) throws AMQException
{
IncomingMessage[] messages = new IncomingMessage[(int) messageCount];
+ MessageMetaData[] metaData = new MessageMetaData[(int) messageCount];
for (int i = 0; i < messages.length; i++)
{
messages[i] = message(false, size);
ArrayList<AMQQueue> qs = new ArrayList<AMQQueue>();
qs.add(_queue);
+ metaData[i] = messages[i].headersReceived();
+ messages[i].setStoredMessage(_messageStore.addMessage(metaData[i]));
+
messages[i].enqueue(qs);
- messages[i].routingComplete(_messageStore, new MessageHandleFactory());
}
@@ -325,6 +336,10 @@ public class AMQQueueAlertTest extends TestCase
ByteBuffer _data = ByteBuffer.allocate((int)size);
+ {
+ _data.limit((int)size);
+ }
+
public int getSize()
{
return (int) size;
@@ -337,10 +352,12 @@ public class AMQQueueAlertTest extends TestCase
public void reduceToFit()
{
-
+
}
});
- messages[i].deliverToQueues();
+
+ _queue.enqueue(new AMQMessage(messages[i].getStoredMessage()));
+
}
}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java
new file mode 100644
index 0000000000..97f061fdd1
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java
@@ -0,0 +1,71 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import junit.framework.TestCase;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+
+public class AMQQueueFactoryTest extends TestCase
+{
+ QueueRegistry _queueRegistry;
+ VirtualHost _virtualHost;
+
+ public void setUp()
+ {
+ ApplicationRegistry registry = (ApplicationRegistry) ApplicationRegistry.getInstance();
+
+ _virtualHost = registry.getVirtualHostRegistry().getVirtualHost("test");
+
+ _queueRegistry = _virtualHost.getQueueRegistry();
+
+ assertEquals("Queues registered on an empty virtualhost", 0, _queueRegistry.getQueues().size());
+ }
+
+ public void tearDown()
+ {
+ assertEquals("Queue was not registered in virtualhost", 1, _queueRegistry.getQueues().size());
+ ApplicationRegistry.remove();
+ }
+
+
+ public void testPriorityQueueRegistration()
+ {
+ FieldTable fieldTable = new FieldTable();
+ fieldTable.put(new AMQShortString(AMQQueueFactory.X_QPID_PRIORITIES), 5);
+
+
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testPriorityQueue"), false, new AMQShortString("owner"), false,
+ _virtualHost, fieldTable);
+
+ assertEquals("Queue not a priorty queue", AMQPriorityQueue.class, queue.getClass());
+ }
+
+
+ public void testSimpleQueueRegistration()
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue"), false, new AMQShortString("owner"), false,
+ _virtualHost, null);
+ assertEquals("Queue not a simple queue", SimpleAMQQueue.class, queue.getClass());
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java
index eab8ad3e2e..4e5ba0213a 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java
@@ -29,7 +29,10 @@ import org.apache.qpid.framing.ContentBody;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.framing.abstraction.ContentChunk;
import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.RequiredDeliveryException;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.util.TestApplicationRegistry;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.message.MessageMetaData;
import org.apache.qpid.server.subscription.Subscription;
import org.apache.qpid.server.subscription.SubscriptionFactory;
import org.apache.qpid.server.subscription.SubscriptionFactoryImpl;
@@ -38,19 +41,15 @@ import org.apache.qpid.server.protocol.InternalTestProtocolSession;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.registry.IApplicationRegistry;
import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.txn.TransactionalContext;
-import org.apache.qpid.server.txn.NonTransactionalContext;
import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.StoreContext;
import org.apache.qpid.server.store.MemoryMessageStore;
import org.apache.qpid.server.store.TestableMemoryMessageStore;
import org.apache.mina.common.ByteBuffer;
+import org.apache.commons.configuration.PropertiesConfiguration;
import javax.management.JMException;
import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.Collections;
/**
* Test class to test AMQQueueMBean attribtues and operations
@@ -61,8 +60,6 @@ public class AMQQueueMBeanTest extends TestCase
private AMQQueue _queue;
private AMQQueueMBean _queueMBean;
private MessageStore _messageStore;
- private StoreContext _storeContext = new StoreContext();
- private TransactionalContext _transactionalContext;
private VirtualHost _virtualHost;
private AMQProtocolSession _protocolSession;
private static final SubscriptionFactoryImpl SUBSCRIPTION_FACTORY = SubscriptionFactoryImpl.INSTANCE;
@@ -73,7 +70,7 @@ public class AMQQueueMBeanTest extends TestCase
sendMessages(messageCount, false);
assertTrue(_queueMBean.getMessageCount() == messageCount);
assertTrue(_queueMBean.getReceivedMessageCount() == messageCount);
- long queueDepth = (messageCount * MESSAGE_SIZE) >> 10;
+ long queueDepth = (messageCount * MESSAGE_SIZE);
assertTrue(_queueMBean.getQueueDepth() == queueDepth);
_queueMBean.deleteMessageFromTop();
@@ -94,7 +91,7 @@ public class AMQQueueMBeanTest extends TestCase
sendMessages(messageCount, true);
assertEquals("", messageCount, _queueMBean.getMessageCount().intValue());
assertTrue(_queueMBean.getReceivedMessageCount() == messageCount);
- long queueDepth = (messageCount * MESSAGE_SIZE) >> 10;
+ long queueDepth = (messageCount * MESSAGE_SIZE);
assertTrue(_queueMBean.getQueueDepth() == queueDepth);
_queueMBean.deleteMessageFromTop();
@@ -109,33 +106,78 @@ public class AMQQueueMBeanTest extends TestCase
verifyBrokerState();
}
+ public void testDeleteMessages() throws Exception
+ {
+ int messageCount = 10;
+ sendMessages(messageCount, true);
+ assertEquals("", messageCount, _queueMBean.getMessageCount().intValue());
+ assertTrue(_queueMBean.getReceivedMessageCount() == messageCount);
+ long queueDepth = (messageCount * MESSAGE_SIZE);
+ assertTrue(_queueMBean.getQueueDepth() == queueDepth);
+
+ //delete first message
+ _queueMBean.deleteMessages(1L,1L);
+ assertTrue(_queueMBean.getMessageCount() == (messageCount - 1));
+ assertTrue(_queueMBean.getReceivedMessageCount() == messageCount);
+ try
+ {
+ _queueMBean.viewMessageContent(1L);
+ fail("Message should no longer be on the queue");
+ }
+ catch(Exception e)
+ {
+
+ }
+
+ //delete last message, leaving 2nd to 9th
+ _queueMBean.deleteMessages(10L,10L);
+ assertTrue(_queueMBean.getMessageCount() == (messageCount - 2));
+ assertTrue(_queueMBean.getReceivedMessageCount() == messageCount);
+ try
+ {
+ _queueMBean.viewMessageContent(10L);
+ fail("Message should no longer be on the queue");
+ }
+ catch(Exception e)
+ {
+
+ }
+
+ //delete remaining messages, leaving none
+ _queueMBean.deleteMessages(2L,9L);
+ assertTrue(_queueMBean.getMessageCount() == (0));
+ assertTrue(_queueMBean.getReceivedMessageCount() == messageCount);
+
+ //Ensure that the data has been removed from the Store
+ verifyBrokerState();
+ }
+
// todo: collect to a general testing class -duplicated from Systest/MessageReturntest
private void verifyBrokerState()
{
- TestableMemoryMessageStore store = new TestableMemoryMessageStore((MemoryMessageStore) _virtualHost.getMessageStore());
+ TestableMemoryMessageStore store = (TestableMemoryMessageStore)_virtualHost.getMessageStore();
// Unlike MessageReturnTest there is no need for a delay as there this thread does the clean up.
- assertNotNull("ContentBodyMap should not be null", store.getContentBodyMap());
- assertEquals("Expected the store to have no content:" + store.getContentBodyMap(), 0, store.getContentBodyMap().size());
- assertNotNull("MessageMetaDataMap should not be null", store.getMessageMetaDataMap());
- assertEquals("Expected the store to have no metadata:" + store.getMessageMetaDataMap(), 0, store.getMessageMetaDataMap().size());
+
+ assertEquals("Store should have no messages:" + store.getMessageCount(), 0, store.getMessageCount());
}
public void testConsumerCount() throws AMQException
{
-
+
assertTrue(_queue.getActiveConsumerCount() == 0);
assertTrue(_queueMBean.getActiveConsumerCount() == 0);
- InternalTestProtocolSession protocolSession = new InternalTestProtocolSession();
+ InternalTestProtocolSession protocolSession = new InternalTestProtocolSession(_virtualHost);
+
AMQChannel channel = new AMQChannel(protocolSession, 1, _messageStore);
protocolSession.addChannel(channel);
Subscription subscription =
SUBSCRIPTION_FACTORY.createSubscription(channel.getChannelId(), protocolSession, new AMQShortString("test"), false, null, false, channel.getCreditManager());
-
+
_queue.registerSubscription(subscription, false);
assertEquals(1,(int)_queueMBean.getActiveConsumerCount());
@@ -175,10 +217,9 @@ public class AMQQueueMBeanTest extends TestCase
assertTrue(_queueMBean.getMaximumMessageCount() == 50000);
assertTrue(_queueMBean.getMaximumMessageSize() == 2000);
- assertTrue(_queueMBean.getMaximumQueueDepth() == (maxQueueDepth >> 10));
+ assertTrue(_queueMBean.getMaximumQueueDepth() == (maxQueueDepth));
assertTrue(_queueMBean.getName().equals("testQueue"));
- assertTrue(_queueMBean.getOwner().equals("AMQueueMBeanTest"));
assertFalse(_queueMBean.isAutoDelete());
assertFalse(_queueMBean.isDurable());
}
@@ -187,7 +228,7 @@ public class AMQQueueMBeanTest extends TestCase
{
try
{
- _queueMBean.viewMessages(0, 3);
+ _queueMBean.viewMessages(0L, 3L);
fail();
}
catch (JMException ex)
@@ -197,7 +238,7 @@ public class AMQQueueMBeanTest extends TestCase
try
{
- _queueMBean.viewMessages(2, 1);
+ _queueMBean.viewMessages(2L, 1L);
fail();
}
catch (JMException ex)
@@ -207,7 +248,7 @@ public class AMQQueueMBeanTest extends TestCase
try
{
- _queueMBean.viewMessages(-1, 1);
+ _queueMBean.viewMessages(-1L, 1L);
fail();
}
catch (JMException ex)
@@ -215,18 +256,35 @@ public class AMQQueueMBeanTest extends TestCase
}
+ try
+ {
+ long end = Integer.MAX_VALUE;
+ end+=2;
+ _queueMBean.viewMessages(1L, end);
+ fail("Expected Exception due to oversized(> 2^31) message range");
+ }
+ catch (JMException ex)
+ {
+
+ }
+
IncomingMessage msg = message(false, false);
- long id = msg.getMessageId();
- _queue.clearQueue(_storeContext);
+ _queue.clearQueue();
ArrayList<AMQQueue> qs = new ArrayList<AMQQueue>();
qs.add(_queue);
msg.enqueue(qs);
- msg.routingComplete(_messageStore, new MessageHandleFactory());
+ MessageMetaData mmd = msg.headersReceived();
+ msg.setStoredMessage(_messageStore.addMessage(mmd));
+ long id = msg.getMessageNumber();
msg.addContentBodyFrame(new ContentChunk()
{
ByteBuffer _data = ByteBuffer.allocate((int)MESSAGE_SIZE);
+ {
+ _data.limit((int)MESSAGE_SIZE);
+ }
+
public int getSize()
{
return (int) MESSAGE_SIZE;
@@ -242,7 +300,12 @@ public class AMQQueueMBeanTest extends TestCase
}
});
- msg.deliverToQueues();
+
+ AMQMessage m = new AMQMessage(msg.getStoredMessage());
+ for(AMQQueue q : msg.getDestinationQueues())
+ {
+ q.enqueue(m);
+ }
// _queue.process(_storeContext, new QueueEntry(_queue, msg), false);
_queueMBean.viewMessageContent(id);
try
@@ -255,6 +318,60 @@ public class AMQQueueMBeanTest extends TestCase
}
}
+
+ public void testFlowControlProperties() throws Exception
+ {
+ assertTrue(_queueMBean.getCapacity() == 0);
+ assertTrue(_queueMBean.getFlowResumeCapacity() == 0);
+ assertFalse(_queueMBean.isFlowOverfull());
+
+ //capacity currently 0, try setting FlowResumeCapacity above this
+ try
+ {
+ _queueMBean.setFlowResumeCapacity(1L);
+ fail("Should have failed to allow setting FlowResumeCapacity above Capacity");
+ }
+ catch (IllegalArgumentException ex)
+ {
+ //expected exception
+ assertTrue(_queueMBean.getFlowResumeCapacity() == 0);
+ }
+
+ //add a message to the queue
+ sendMessages(1, true);
+
+ //(FlowResume)Capacity currently 0, set both to 2
+ _queueMBean.setCapacity(2L);
+ assertTrue(_queueMBean.getCapacity() == 2L);
+ _queueMBean.setFlowResumeCapacity(2L);
+ assertTrue(_queueMBean.getFlowResumeCapacity() == 2L);
+
+ //Try setting Capacity below FlowResumeCapacity
+ try
+ {
+ _queueMBean.setCapacity(1L);
+ fail("Should have failed to allow setting Capacity below FlowResumeCapacity");
+ }
+ catch (IllegalArgumentException ex)
+ {
+ //expected exception
+ assertTrue(_queueMBean.getCapacity() == 2);
+ }
+
+ //create a channel and use it to exercise the capacity check mechanism
+ AMQChannel channel = new AMQChannel(_protocolSession, 1, _messageStore);
+ _queue.checkCapacity(channel);
+
+ assertTrue(_queueMBean.isFlowOverfull());
+ assertTrue(channel.getBlocking());
+
+ //set FlowResumeCapacity to MESSAGE_SIZE and check queue is now underfull and channel unblocked
+ _queueMBean.setCapacity(MESSAGE_SIZE);//must increase capacity too
+ _queueMBean.setFlowResumeCapacity(MESSAGE_SIZE);
+
+ assertFalse(_queueMBean.isFlowOverfull());
+ assertFalse(channel.getBlocking());
+ }
private IncomingMessage message(final boolean immediate, boolean persistent) throws AMQException
{
@@ -291,7 +408,7 @@ public class AMQQueueMBeanTest extends TestCase
contentHeaderBody.bodySize = MESSAGE_SIZE; // in bytes
contentHeaderBody.properties = new BasicContentHeaderProperties();
((BasicContentHeaderProperties) contentHeaderBody.properties).setDeliveryMode((byte) (persistent ? 2 : 1));
- IncomingMessage msg = new IncomingMessage(_messageStore.getNewMessageId(), publish, _transactionalContext, _protocolSession);
+ IncomingMessage msg = new IncomingMessage(publish);
msg.setContentHeaderBody(contentHeaderBody);
return msg;
@@ -301,25 +418,27 @@ public class AMQQueueMBeanTest extends TestCase
protected void setUp() throws Exception
{
super.setUp();
- IApplicationRegistry applicationRegistry = ApplicationRegistry.getInstance(1);
+
+ PropertiesConfiguration configuration = new PropertiesConfiguration();
+ configuration.setProperty("virtualhosts.virtualhost.test.store.class", TestableMemoryMessageStore.class.getName());
+ IApplicationRegistry applicationRegistry = new TestApplicationRegistry(new ServerConfiguration(configuration));
+ ApplicationRegistry.initialise(applicationRegistry );
+
+ configuration.setProperty("virtualhosts.virtualhost.test.store.class", TestableMemoryMessageStore.class.getName());
+
_virtualHost = applicationRegistry.getVirtualHostRegistry().getVirtualHost("test");
_messageStore = _virtualHost.getMessageStore();
- _transactionalContext = new NonTransactionalContext(_messageStore, _storeContext,
- null,
- new LinkedList<RequiredDeliveryException>()
- );
-
_queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue"), false, new AMQShortString("AMQueueMBeanTest"), false, _virtualHost,
null);
_queueMBean = new AMQQueueMBean(_queue);
- _protocolSession = new InternalTestProtocolSession();
+ _protocolSession = new InternalTestProtocolSession(_virtualHost);
}
public void tearDown()
{
- ApplicationRegistry.remove(1);
+ ApplicationRegistry.remove();
}
private void sendMessages(int messageCount, boolean persistent) throws AMQException
@@ -332,7 +451,8 @@ public class AMQQueueMBeanTest extends TestCase
currentMessage.enqueue(qs);
// route header
- currentMessage.routingComplete(_messageStore, new MessageHandleFactory());
+ MessageMetaData mmd = currentMessage.headersReceived();
+ currentMessage.setStoredMessage(_messageStore.addMessage(mmd));
// Add the body so we have somthing to test later
currentMessage.addContentBodyFrame(
@@ -341,7 +461,12 @@ public class AMQQueueMBeanTest extends TestCase
.convertToContentChunk(
new ContentBody(ByteBuffer.allocate((int) MESSAGE_SIZE),
MESSAGE_SIZE)));
- currentMessage.deliverToQueues();
+
+ AMQMessage m = new AMQMessage(currentMessage.getStoredMessage());
+ for(AMQQueue q : currentMessage.getDestinationQueues())
+ {
+ q.enqueue(m);
+ }
}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/AckTest.java b/java/broker/src/test/java/org/apache/qpid/server/queue/AckTest.java
new file mode 100644
index 0000000000..d64e533f72
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/AckTest.java
@@ -0,0 +1,432 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import junit.framework.TestCase;
+import org.apache.log4j.Logger;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.message.MessageMetaData;
+import org.apache.qpid.server.txn.ServerTransaction;
+import org.apache.qpid.server.txn.AutoCommitTransaction;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.protocol.InternalTestProtocolSession;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.subscription.SubscriptionFactoryImpl;
+import org.apache.qpid.server.flow.LimitlessCreditManager;
+import org.apache.qpid.server.flow.Pre0_10CreditManager;
+import org.apache.qpid.server.ack.UnacknowledgedMessageMap;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.store.TestMemoryMessageStore;
+
+import java.util.ArrayList;
+import java.util.Set;
+
+/**
+ * Tests that acknowledgements are handled correctly.
+ */
+public class AckTest extends TestCase
+{
+ private static final Logger _log = Logger.getLogger(AckTest.class);
+
+ private Subscription _subscription;
+
+ private AMQProtocolSession _protocolSession;
+
+ private TestMemoryMessageStore _messageStore;
+
+ private AMQChannel _channel;
+
+ private AMQQueue _queue;
+
+ private static final AMQShortString DEFAULT_CONSUMER_TAG = new AMQShortString("conTag");
+ private VirtualHost _virtualHost;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ // The NullApplicationRegistry will be created by default when
+ // calling AR.getInstance
+ _virtualHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test");
+ _messageStore = new TestMemoryMessageStore();
+ _protocolSession = new InternalTestProtocolSession(_virtualHost);
+ _channel = new AMQChannel(_protocolSession,5, _messageStore /*dont need exchange registry*/);
+
+ _protocolSession.addChannel(_channel);
+
+ _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("myQ"), false, new AMQShortString("guest"), true, _virtualHost,
+ null);
+ }
+
+ protected void tearDown()
+ {
+ ApplicationRegistry.remove();
+ }
+
+ private void publishMessages(int count) throws AMQException
+ {
+ publishMessages(count, false);
+ }
+
+ private void publishMessages(int count, boolean persistent) throws AMQException
+ {
+ _queue.registerSubscription(_subscription,false);
+ for (int i = 1; i <= count; i++)
+ {
+ // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0)
+ // TODO: Establish some way to determine the version for the test.
+ MessagePublishInfo publishBody = new MessagePublishInfo()
+ {
+
+ public AMQShortString getExchange()
+ {
+ return new AMQShortString("someExchange");
+ }
+
+ public void setExchange(AMQShortString exchange)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isImmediate()
+ {
+ return false;
+ }
+
+ public boolean isMandatory()
+ {
+ return false;
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return new AMQShortString("rk");
+ }
+ };
+ final IncomingMessage msg = new IncomingMessage(publishBody);
+ //IncomingMessage msg2 = null;
+ BasicContentHeaderProperties b = new BasicContentHeaderProperties();
+ ContentHeaderBody cb = new ContentHeaderBody();
+ cb.properties = b;
+
+ if (persistent)
+ {
+ //This is DeliveryMode.PERSISTENT
+ b.setDeliveryMode((byte) 2);
+ }
+
+ msg.setContentHeaderBody(cb);
+
+ // we increment the reference here since we are not delivering the messaging to any queues, which is where
+ // the reference is normally incremented. The test is easier to construct if we have direct access to the
+ // subscription
+ ArrayList<AMQQueue> qs = new ArrayList<AMQQueue>();
+ qs.add(_queue);
+ msg.enqueue(qs);
+ MessageMetaData mmd = msg.headersReceived();
+ msg.setStoredMessage(_messageStore.addMessage(mmd));
+ if(msg.allContentReceived())
+ {
+ ServerTransaction txn = new AutoCommitTransaction(_messageStore);
+ txn.enqueue(_queue, msg, new ServerTransaction.Action() {
+ public void postCommit()
+ {
+ try
+ {
+ _queue.enqueue(new AMQMessage(msg.getStoredMessage()));
+ }
+ catch (AMQException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void onRollback()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+ });
+
+ }
+ // we manually send the message to the subscription
+ //_subscription.send(new QueueEntry(_queue,msg), _queue);
+ }
+ }
+
+ /**
+ * Tests that the acknowledgements are correctly associated with a channel and
+ * order is preserved when acks are enabled
+ */
+ public void testAckChannelAssociationTest() throws AMQException
+ {
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true, null, false, new LimitlessCreditManager());
+ final int msgCount = 10;
+ publishMessages(msgCount, true);
+
+ UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
+ assertEquals("",msgCount,map.size());
+
+ Set<Long> deliveryTagSet = map.getDeliveryTags();
+ int i = 1;
+ for (long deliveryTag : deliveryTagSet)
+ {
+ assertTrue(deliveryTag == i);
+ i++;
+ QueueEntry unackedMsg = map.get(deliveryTag);
+ assertTrue(unackedMsg.getQueue() == _queue);
+ }
+
+ }
+
+ /**
+ * Tests that in no-ack mode no messages are retained
+ */
+ public void testNoAckMode() throws AMQException
+ {
+ // false arg means no acks expected
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, false, null, false, new LimitlessCreditManager());
+ final int msgCount = 10;
+ publishMessages(msgCount);
+
+ UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
+ assertTrue(map.size() == 0);
+ assertTrue(_messageStore.getMessageCount() == 0);
+
+
+ }
+
+ /**
+ * Tests that in no-ack mode no messages are retained
+ */
+ public void testPersistentNoAckMode() throws AMQException
+ {
+ // false arg means no acks expected
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, false,null,false, new LimitlessCreditManager());
+ final int msgCount = 10;
+ publishMessages(msgCount, true);
+
+ UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
+ assertTrue(map.size() == 0);
+ assertTrue(_messageStore.getMessageCount() == 0);
+
+
+ }
+
+ /**
+ * Tests that a single acknowledgement is handled correctly (i.e multiple flag not
+ * set case)
+ */
+ public void testSingleAckReceivedTest() throws AMQException
+ {
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true,null,false, new LimitlessCreditManager());
+ final int msgCount = 10;
+ publishMessages(msgCount);
+
+ _channel.acknowledgeMessage(5, false);
+ UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
+ assertTrue(map.size() == msgCount - 1);
+
+ Set<Long> deliveryTagSet = map.getDeliveryTags();
+ int i = 1;
+ for (long deliveryTag : deliveryTagSet)
+ {
+ assertTrue(deliveryTag == i);
+ QueueEntry unackedMsg = map.get(deliveryTag);
+ assertTrue(unackedMsg.getQueue() == _queue);
+ // 5 is the delivery tag of the message that *should* be removed
+ if (++i == 5)
+ {
+ ++i;
+ }
+ }
+ }
+
+ /**
+ * Tests that a single acknowledgement is handled correctly (i.e multiple flag not
+ * set case)
+ */
+ public void testMultiAckReceivedTest() throws AMQException
+ {
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true,null,false, new LimitlessCreditManager());
+ final int msgCount = 10;
+ publishMessages(msgCount);
+
+ _channel.acknowledgeMessage(5, true);
+ UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
+ assertTrue(map.size() == 5);
+
+ Set<Long> deliveryTagSet = map.getDeliveryTags();
+ int i = 1;
+ for (long deliveryTag : deliveryTagSet)
+ {
+ assertTrue(deliveryTag == i + 5);
+ QueueEntry unackedMsg = map.get(deliveryTag);
+ assertTrue(unackedMsg.getQueue() == _queue);
+ ++i;
+ }
+ }
+
+ /**
+ * Tests that a multiple acknowledgement is handled correctly. When ack'ing all pending msgs.
+ */
+ public void testMultiAckAllReceivedTest() throws AMQException
+ {
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true,null,false, new LimitlessCreditManager());
+ final int msgCount = 10;
+ publishMessages(msgCount);
+
+ _channel.acknowledgeMessage(0, true);
+ UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
+ assertTrue(map.size() == 0);
+
+ Set<Long> deliveryTagSet = map.getDeliveryTags();
+ int i = 1;
+ for (long deliveryTag : deliveryTagSet)
+ {
+ assertTrue(deliveryTag == i + 5);
+ QueueEntry unackedMsg = map.get(deliveryTag);
+ assertTrue(unackedMsg.getQueue() == _queue);
+ ++i;
+ }
+ }
+
+ /**
+ * A regression fixing QPID-1136 showed this up
+ *
+ * @throws Exception
+ */
+ public void testMessageDequeueRestoresCreditTest() throws Exception
+ {
+ // Send 10 messages
+ Pre0_10CreditManager creditManager = new Pre0_10CreditManager(0l, 1);
+
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession,
+ DEFAULT_CONSUMER_TAG, true, null, false, creditManager);
+ final int msgCount = 1;
+ publishMessages(msgCount);
+
+ _queue.deliverAsync(_subscription);
+
+ _channel.acknowledgeMessage(1, false);
+
+ // Check credit available
+ assertTrue("No credit available", creditManager.hasCredit());
+
+ }
+
+
+/*
+ public void testPrefetchHighLow() throws AMQException
+ {
+ int lowMark = 5;
+ int highMark = 10;
+
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true,null,false, new LimitlessCreditManager());
+ _channel.setPrefetchLowMarkCount(lowMark);
+ _channel.setPrefetchHighMarkCount(highMark);
+
+ assertTrue(_channel.getPrefetchLowMarkCount() == lowMark);
+ assertTrue(_channel.getPrefetchHighMarkCount() == highMark);
+
+ publishMessages(highMark);
+
+ // at this point we should have sent out only highMark messages
+ // which have not bee received so will be queued up in the channel
+ // which should be suspended
+ assertTrue(_subscription.isSuspended());
+ UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
+ assertTrue(map.size() == highMark);
+
+ //acknowledge messages so we are just above lowMark
+ _channel.acknowledgeMessage(lowMark - 1, true);
+
+ //we should still be suspended
+ assertTrue(_subscription.isSuspended());
+ assertTrue(map.size() == lowMark + 1);
+
+ //acknowledge one more message
+ _channel.acknowledgeMessage(lowMark, true);
+
+ //and suspension should be lifted
+ assertTrue(!_subscription.isSuspended());
+
+ //pubilsh more msgs so we are just below the limit
+ publishMessages(lowMark - 1);
+
+ //we should not be suspended
+ assertTrue(!_subscription.isSuspended());
+
+ //acknowledge all messages
+ _channel.acknowledgeMessage(0, true);
+ try
+ {
+ Thread.sleep(3000);
+ }
+ catch (InterruptedException e)
+ {
+ _log.error("Error: " + e, e);
+ }
+ //map will be empty
+ assertTrue(map.size() == 0);
+ }
+
+*/
+/*
+ public void testPrefetch() throws AMQException
+ {
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true,null,false, new LimitlessCreditManager());
+ _channel.setMessageCredit(5);
+
+ assertTrue(_channel.getPrefetchCount() == 5);
+
+ final int msgCount = 5;
+ publishMessages(msgCount);
+
+ // at this point we should have sent out only 5 messages with a further 5 queued
+ // up in the channel which should now be suspended
+ assertTrue(_subscription.isSuspended());
+ UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
+ assertTrue(map.size() == 5);
+ _channel.acknowledgeMessage(5, true);
+ assertTrue(!_subscription.isSuspended());
+ try
+ {
+ Thread.sleep(3000);
+ }
+ catch (InterruptedException e)
+ {
+ _log.error("Error: " + e, e);
+ }
+ assertTrue(map.size() == 0);
+ }
+
+*/
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(AckTest.class);
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessage.java b/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessage.java
new file mode 100644
index 0000000000..7000df157e
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessage.java
@@ -0,0 +1,43 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.message.AMQMessage;
+
+public class MockAMQMessage extends AMQMessage
+{
+ public MockAMQMessage(long messageId)
+ throws AMQException
+ {
+ super(new MockStoredMessage(messageId));
+ }
+
+
+
+
+ @Override
+ public long getSize()
+ {
+ return 0l;
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java b/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java
new file mode 100644
index 0000000000..a487b160e1
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java
@@ -0,0 +1,443 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.server.configuration.QueueConfiguration;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.management.ManagedObject;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.security.PrincipalHolder;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.txn.ServerTransaction;
+import org.apache.qpid.AMQException;
+
+import java.util.List;
+import java.util.Set;
+import java.util.Map;
+
+public class MockAMQQueue implements AMQQueue
+{
+ private boolean _deleted = false;
+ private AMQShortString _name;
+ private VirtualHost _virtualhost;
+
+ private PrincipalHolder _principalHolder;
+
+ private Object _exclusiveOwner;
+
+ public MockAMQQueue(String name)
+ {
+ _name = new AMQShortString(name);
+ }
+
+ public boolean getDeleteOnNoConsumers()
+ {
+ return false;
+ }
+
+ public void setDeleteOnNoConsumers(boolean b)
+ {
+ }
+
+ public AMQShortString getName()
+ {
+ return _name;
+ }
+
+ public void setNoLocal(boolean b)
+ {
+
+ }
+
+ public boolean isDurable()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isAutoDelete()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public AMQShortString getOwner()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setVirtualHost(VirtualHost virtualhost)
+ {
+ _virtualhost = virtualhost;
+ }
+
+ public VirtualHost getVirtualHost()
+ {
+ return _virtualhost;
+ }
+
+ public void bind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void unBind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public List<ExchangeBinding> getExchangeBindings()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void registerSubscription(Subscription subscription, boolean exclusive) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void unregisterSubscription(Subscription subscription) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int getConsumerCount()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int getActiveConsumerCount()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isUnused()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isEmpty()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int getMessageCount()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int getUndeliveredMessageCount()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getQueueDepth()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getReceivedMessageCount()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getOldestMessageArrivalTime()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isDeleted()
+ {
+ return _deleted;
+ }
+
+ public int delete() throws AMQException
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public QueueEntry enqueue(ServerMessage message) throws AMQException
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void requeue(QueueEntry entry)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void requeue(QueueEntryImpl storeContext, Subscription subscription)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void dequeue(QueueEntry entry)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean resend(QueueEntry entry, Subscription subscription) throws AMQException
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void addQueueDeleteTask(Task task)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public List<QueueEntry> getMessagesOnTheQueue()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public List<QueueEntry> getMessagesOnTheQueue(long fromMessageId, long toMessageId)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public List<Long> getMessagesOnTheQueue(int num)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public List<Long> getMessagesOnTheQueue(int num, int offest)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public QueueEntry getMessageOnTheQueue(long messageId)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public List<QueueEntry> getMessagesRangeOnTheQueue(long fromPosition, long toPosition)
+ {
+ return null;
+ }
+
+ public void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, ServerTransaction storeContext)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, ServerTransaction storeContext)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void removeMessagesFromQueue(long fromMessageId, long toMessageId)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getMaximumMessageSize()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setMaximumMessageSize(long value)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getMaximumMessageCount()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setMaximumMessageCount(long value)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getMaximumQueueDepth()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setMaximumQueueDepth(long value)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getMaximumMessageAge()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setMaximumMessageAge(long maximumMessageAge)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean getBlockOnQueueFull()
+ {
+ return false;
+ }
+
+ public void setBlockOnQueueFull(boolean block)
+ {
+ }
+
+ public long getMinimumAlertRepeatGap()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void deleteMessageFromTop()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long clearQueue()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+
+ public void checkMessageStatus() throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public Set<NotificationCheck> getNotificationChecks()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void flushSubscription(Subscription sub) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void deliverAsync(Subscription sub)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void deliverAsync()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void stop()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isExclusive()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public Exchange getAlternateExchange()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setAlternateExchange(Exchange exchange)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public Map<String, Object> getArguments()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void checkCapacity(AMQChannel channel)
+ {
+ }
+
+ public ManagedObject getManagedObject()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int compareTo(AMQQueue o)
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setMinimumAlertRepeatGap(long value)
+ {
+
+ }
+
+ public long getCapacity()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setCapacity(long capacity)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getFlowResumeCapacity()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setFlowResumeCapacity(long flowResumeCapacity)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void configure(QueueConfiguration config)
+ {
+
+ }
+
+ public PrincipalHolder getPrincipalHolder()
+ {
+ return _principalHolder;
+ }
+
+ public void setPrincipalHolder(PrincipalHolder principalHolder)
+ {
+ _principalHolder = principalHolder;
+ }
+
+ public Object getExclusiveOwner()
+ {
+ return _exclusiveOwner;
+ }
+
+ public void setExclusiveOwner(Object exclusiveOwner)
+ {
+ _exclusiveOwner = exclusiveOwner;
+ }
+
+
+ public String getResourceName()
+ {
+ return _name.toString();
+ }
+
+ public boolean isOverfull()
+ {
+ return false;
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/MockMessagePublishInfo.java b/java/broker/src/test/java/org/apache/qpid/server/queue/MockMessagePublishInfo.java
new file mode 100644
index 0000000000..5a5ffaa14d
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/MockMessagePublishInfo.java
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.framing.AMQShortString;
+
+public class MockMessagePublishInfo implements MessagePublishInfo
+{
+ public AMQShortString getExchange()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setExchange(AMQShortString exchange)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isImmediate()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isMandatory()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java b/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java
new file mode 100644
index 0000000000..3f74cb973b
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java
@@ -0,0 +1,228 @@
+/*
+*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.message.AMQMessageHeader;
+import org.apache.qpid.server.message.AMQMessage;
+
+public class MockQueueEntry implements QueueEntry
+{
+
+ private AMQMessage _message;
+
+ public boolean acquire()
+ {
+ return false;
+ }
+
+ public boolean acquire(Subscription sub)
+ {
+ return false;
+ }
+
+ public boolean acquiredBySubscription()
+ {
+ return false;
+ }
+
+ public boolean isAcquiredBy(Subscription subscription)
+ {
+ return false;
+ }
+
+ public void addStateChangeListener(StateChangeListener listener)
+ {
+
+ }
+
+ public boolean delete()
+ {
+ return false;
+ }
+
+ public void dequeue()
+ {
+
+ }
+
+ public void discard()
+ {
+
+ }
+
+ public void routeToAlternate()
+ {
+
+ }
+
+ public void dispose()
+ {
+
+ }
+
+ public boolean expired() throws AMQException
+ {
+ return false;
+ }
+
+ public Subscription getDeliveredSubscription()
+ {
+ return null;
+ }
+
+ public boolean getDeliveredToConsumer()
+ {
+ return false;
+ }
+
+ public AMQMessage getMessage()
+ {
+ return _message;
+ }
+
+ public AMQQueue getQueue()
+ {
+ return null;
+ }
+
+ public long getSize()
+ {
+ return 0;
+ }
+
+ public boolean immediateAndNotDelivered()
+ {
+ return false;
+ }
+
+ public boolean isAcquired()
+ {
+ return false;
+ }
+
+ public boolean isDeleted()
+ {
+ return false;
+ }
+
+
+ public boolean isQueueDeleted()
+ {
+
+ return false;
+ }
+
+
+ public boolean isRejectedBy(Subscription subscription)
+ {
+
+ return false;
+ }
+
+
+ public void reject()
+ {
+
+
+ }
+
+
+ public void reject(Subscription subscription)
+ {
+
+
+ }
+
+
+ public void release()
+ {
+
+
+ }
+
+ public boolean releaseButRetain()
+ {
+ return false;
+ }
+
+
+ public boolean removeStateChangeListener(StateChangeListener listener)
+ {
+
+ return false;
+ }
+
+
+ public void requeue()
+ {
+
+
+ }
+
+ public void requeue(Subscription subscription)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+
+ public void setDeliveredToSubscription()
+ {
+
+
+ }
+
+
+ public void setRedelivered()
+ {
+
+
+ }
+
+ public AMQMessageHeader getMessageHeader()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isPersistent()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isRedelivered()
+ {
+ return false;
+ }
+
+
+ public int compareTo(QueueEntry o)
+ {
+
+ return 0;
+ }
+
+ public void setMessage(AMQMessage msg)
+ {
+ _message = msg;
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/MockStoredMessage.java b/java/broker/src/test/java/org/apache/qpid/server/queue/MockStoredMessage.java
new file mode 100755
index 0000000000..7dc491de4d
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/MockStoredMessage.java
@@ -0,0 +1,92 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.TransactionLog;
+import org.apache.qpid.server.store.StoredMessage;
+import org.apache.qpid.server.message.MessageMetaData;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+
+import java.nio.ByteBuffer;
+
+public class MockStoredMessage implements StoredMessage<MessageMetaData>
+{
+ private long _messageId;
+ private MessageMetaData _metaData;
+ private final ByteBuffer _content;
+
+
+ public MockStoredMessage(long messageId)
+ {
+ this(messageId, new MockMessagePublishInfo(), new ContentHeaderBody(new BasicContentHeaderProperties(), 60));
+ }
+
+ public MockStoredMessage(long messageId, MessagePublishInfo info, ContentHeaderBody chb)
+ {
+ _messageId = messageId;
+ _metaData = new MessageMetaData(info, chb, 0);
+ _content = ByteBuffer.allocate(_metaData.getContentSize());
+
+ }
+
+ public MessageMetaData getMetaData()
+ {
+ return _metaData;
+ }
+
+ public long getMessageNumber()
+ {
+ return _messageId;
+ }
+
+ public void addContent(int offsetInMessage, ByteBuffer src)
+ {
+ src = src.duplicate();
+ ByteBuffer dst = _content.duplicate();
+ dst.position(offsetInMessage);
+ dst.put(src);
+ }
+
+ public int getContent(int offset, ByteBuffer dst)
+ {
+ ByteBuffer src = _content.duplicate();
+ src.position(offset);
+ src = src.slice();
+ if(dst.remaining() < src.limit())
+ {
+ src.limit(dst.remaining());
+ }
+ dst.put(src);
+ return src.limit();
+ }
+
+ public TransactionLog.StoreFuture flushToStore()
+ {
+ return MessageStore.IMMEDIATE_FUTURE;
+ }
+
+ public void remove()
+ {
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java b/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java
index aa6ee6ff12..408893870b 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java
@@ -1,28 +1,64 @@
package org.apache.qpid.server.queue;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+import java.util.ArrayList;
import java.util.List;
+import junit.framework.TestCase;
+
+import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.configuration.VirtualHostConfiguration;
+import org.apache.qpid.server.exchange.DirectExchange;
+import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.store.TestableMemoryMessageStore;
-import org.apache.qpid.server.txn.NonTransactionalContext;
-import org.apache.qpid.server.txn.TransactionalContext;
+import org.apache.qpid.server.store.StoredMessage;
+import org.apache.qpid.server.subscription.MockSubscription;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.virtualhost.VirtualHostImpl;
import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-
-import junit.framework.TestCase;
+import org.apache.qpid.server.txn.AutoCommitTransaction;
+import org.apache.qpid.server.txn.ServerTransaction;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.message.MessageMetaData;
public class SimpleAMQQueueTest extends TestCase
{
- private SimpleAMQQueue _queue;
- private MessageStore store = new TestableMemoryMessageStore();
- private TransactionalContext ctx = new NonTransactionalContext(store, new StoreContext(), null, null);
- private MessageHandleFactory factory = new MessageHandleFactory();
+ protected SimpleAMQQueue _queue;
+ protected VirtualHost _virtualHost;
+ protected TestableMemoryMessageStore _store = new TestableMemoryMessageStore();
+ protected AMQShortString _qname = new AMQShortString("qname");
+ protected AMQShortString _owner = new AMQShortString("owner");
+ protected AMQShortString _routingKey = new AMQShortString("routing key");
+ protected DirectExchange _exchange = new DirectExchange();
+ protected MockSubscription _subscription = new MockSubscription();
+ protected FieldTable _arguments = null;
MessagePublishInfo info = new MessagePublishInfo()
{
@@ -58,27 +94,200 @@ public class SimpleAMQQueueTest extends TestCase
{
super.setUp();
//Create Application Registry for test
- ApplicationRegistry.getInstance(1);
+ ApplicationRegistry applicationRegistry = (ApplicationRegistry)ApplicationRegistry.getInstance();
- AMQShortString qname = new AMQShortString("qname");
- AMQShortString owner = new AMQShortString("owner");
- _queue = new SimpleAMQQueue(qname, false, owner, false, new VirtualHost("vhost", store));
+ PropertiesConfiguration env = new PropertiesConfiguration();
+ _virtualHost = new VirtualHostImpl(new VirtualHostConfiguration(getClass().getName(), env), _store);
+ applicationRegistry.getVirtualHostRegistry().registerVirtualHost(_virtualHost);
+
+ _queue = (SimpleAMQQueue) AMQQueueFactory.createAMQQueueImpl(_qname, false, _owner, false, _virtualHost, _arguments);
}
@Override
protected void tearDown()
{
- ApplicationRegistry.remove(1);
+ _queue.stop();
+ ApplicationRegistry.remove();
+ }
+
+ public void testCreateQueue() throws AMQException
+ {
+ _queue.stop();
+ try {
+ _queue = (SimpleAMQQueue) AMQQueueFactory.createAMQQueueImpl(null, false, _owner, false, _virtualHost, _arguments );
+ assertNull("Queue was created", _queue);
+ }
+ catch (IllegalArgumentException e)
+ {
+ assertTrue("Exception was not about missing name",
+ e.getMessage().contains("name"));
+ }
+
+ try {
+ _queue = new SimpleAMQQueue(_qname, false, _owner, false, null);
+ assertNull("Queue was created", _queue);
+ }
+ catch (IllegalArgumentException e)
+ {
+ assertTrue("Exception was not about missing vhost",
+ e.getMessage().contains("Host"));
+ }
+
+ _queue = (SimpleAMQQueue) AMQQueueFactory.createAMQQueueImpl(_qname, false, _owner, false,
+ _virtualHost, _arguments);
+ assertNotNull("Queue was not created", _queue);
+ }
+
+ public void testGetVirtualHost()
+ {
+ assertEquals("Virtual host was wrong", _virtualHost, _queue.getVirtualHost());
+ }
+
+ public void testBinding()
+ {
+ try
+ {
+ _queue.bind(_exchange, _routingKey, null);
+ assertTrue("Routing key was not bound",
+ _exchange.getBindings().containsKey(_routingKey));
+ assertEquals("Queue was not bound to key",
+ _exchange.getBindings().get(_routingKey).get(0),
+ _queue);
+ assertEquals("Exchange binding count", 1,
+ _queue.getExchangeBindings().size());
+ assertEquals("Wrong exchange bound", _routingKey,
+ _queue.getExchangeBindings().get(0).getRoutingKey());
+ assertEquals("Wrong exchange bound", _exchange,
+ _queue.getExchangeBindings().get(0).getExchange());
+
+ _queue.unBind(_exchange, _routingKey, null);
+ assertFalse("Routing key was still bound",
+ _exchange.getBindings().containsKey(_routingKey));
+ assertNull("Routing key was not empty",
+ _exchange.getBindings().get(_routingKey));
+ }
+ catch (AMQException e)
+ {
+ assertNull("Unexpected exception", e);
+ }
+ }
+
+ public void testSubscription() throws AMQException
+ {
+ // Check adding a subscription adds it to the queue
+ _queue.registerSubscription(_subscription, false);
+ assertEquals("Subscription did not get queue", _queue,
+ _subscription.getQueue());
+ assertEquals("Queue does not have consumer", 1,
+ _queue.getConsumerCount());
+ assertEquals("Queue does not have active consumer", 1,
+ _queue.getActiveConsumerCount());
+
+ // Check sending a message ends up with the subscriber
+ AMQMessage messageA = createMessage(new Long(24));
+ _queue.enqueue(messageA);
+ assertEquals(messageA, _subscription.getQueueContext().getLastSeenEntry().getMessage());
+
+ // Check removing the subscription removes it's information from the queue
+ _queue.unregisterSubscription(_subscription);
+ assertTrue("Subscription still had queue", _subscription.isClosed());
+ assertFalse("Queue still has consumer", 1 == _queue.getConsumerCount());
+ assertFalse("Queue still has active consumer",
+ 1 == _queue.getActiveConsumerCount());
+
+ AMQMessage messageB = createMessage(new Long (25));
+ _queue.enqueue(messageB);
+ assertNull(_subscription.getQueueContext());
+
+ }
+
+ public void testQueueNoSubscriber() throws AMQException, InterruptedException
+ {
+ AMQMessage messageA = createMessage(new Long(24));
+ _queue.enqueue(messageA);
+ _queue.registerSubscription(_subscription, false);
+ Thread.sleep(150);
+ assertEquals(messageA, _subscription.getQueueContext().getLastSeenEntry().getMessage());
+ }
+
+ public void testExclusiveConsumer() throws AMQException
+ {
+ // Check adding an exclusive subscription adds it to the queue
+ _queue.registerSubscription(_subscription, true);
+ assertEquals("Subscription did not get queue", _queue,
+ _subscription.getQueue());
+ assertEquals("Queue does not have consumer", 1,
+ _queue.getConsumerCount());
+ assertEquals("Queue does not have active consumer", 1,
+ _queue.getActiveConsumerCount());
+
+ // Check sending a message ends up with the subscriber
+ AMQMessage messageA = createMessage(new Long(24));
+ _queue.enqueue(messageA);
+ assertEquals(messageA, _subscription.getQueueContext().getLastSeenEntry().getMessage());
+
+ // Check we cannot add a second subscriber to the queue
+ Subscription subB = new MockSubscription();
+ Exception ex = null;
+ try
+ {
+ _queue.registerSubscription(subB, false);
+ }
+ catch (AMQException e)
+ {
+ ex = e;
+ }
+ assertNotNull(ex);
+ assertTrue(ex instanceof AMQException);
+
+ // Check we cannot add an exclusive subscriber to a queue with an
+ // existing subscription
+ _queue.unregisterSubscription(_subscription);
+ _queue.registerSubscription(_subscription, false);
+ try
+ {
+ _queue.registerSubscription(subB, true);
+ }
+ catch (AMQException e)
+ {
+ ex = e;
+ }
+ assertNotNull(ex);
+ }
+
+ public void testAutoDeleteQueue() throws Exception
+ {
+ _queue.stop();
+ _queue = new SimpleAMQQueue(_qname, false, null, true, _virtualHost);
+ _queue.setDeleteOnNoConsumers(true);
+ _queue.registerSubscription(_subscription, false);
+ AMQMessage message = createMessage(new Long(25));
+ _queue.enqueue(message);
+ _queue.unregisterSubscription(_subscription);
+ assertTrue("Queue was not deleted when subscription was removed",
+ _queue.isDeleted());
+ }
+
+ public void testResend() throws Exception
+ {
+ _queue.registerSubscription(_subscription, false);
+ Long id = new Long(26);
+ AMQMessage message = createMessage(id);
+ _queue.enqueue(message);
+ QueueEntry entry = _subscription.getQueueContext().getLastSeenEntry();
+ entry.setRedelivered();
+ _queue.resend(entry, _subscription);
+
}
public void testGetFirstMessageId() throws Exception
{
// Create message
Long messageId = new Long(23);
- AMQMessage message = new TestMessage(messageId, messageId, info, new StoreContext());
+ AMQMessage message = createMessage(messageId);
// Put message on queue
- _queue.enqueue(null, message);
+ _queue.enqueue(message);
// Get message id
Long testmsgid = _queue.getMessagesOnTheQueue(1).get(0);
@@ -92,9 +301,9 @@ public class SimpleAMQQueueTest extends TestCase
{
// Create message
Long messageId = new Long(i);
- AMQMessage message = new TestMessage(messageId, messageId, info, new StoreContext());
+ AMQMessage message = createMessage(messageId);
// Put message on queue
- _queue.enqueue(null, message);
+ _queue.enqueue(message);
}
// Get message ids
List<Long> msgids = _queue.getMessagesOnTheQueue(5);
@@ -113,9 +322,9 @@ public class SimpleAMQQueueTest extends TestCase
{
// Create message
Long messageId = new Long(i);
- AMQMessage message = new TestMessage(messageId, messageId, info, new StoreContext());
+ AMQMessage message = createMessage(messageId);
// Put message on queue
- _queue.enqueue(null, message);
+ _queue.enqueue(message);
}
// Get message ids
List<Long> msgids = _queue.getMessagesOnTheQueue(5, 5);
@@ -128,54 +337,146 @@ public class SimpleAMQQueueTest extends TestCase
}
}
-
- // FIXME: move this to somewhere useful
- private static AMQMessageHandle createMessageHandle(final long messageId, final MessagePublishInfo publishBody)
+ public void testGetMessagesRangeOnTheQueue() throws Exception
{
- final AMQMessageHandle amqMessageHandle = (new MessageHandleFactory()).createMessageHandle(messageId,
- null,
- false);
- try
+ for (int i = 1 ; i <= 10; i++)
{
- amqMessageHandle.setPublishAndContentHeaderBody(new StoreContext(),
- publishBody,
- new ContentHeaderBody()
- {
- public int getSize()
- {
- return 1;
- }
- });
- }
- catch (AMQException e)
- {
- // won't happen
+ // Create message
+ Long messageId = new Long(i);
+ AMQMessage message = createMessage(messageId);
+ // Put message on queue
+ _queue.enqueue(message);
}
+ // Get non-existent 0th QueueEntry & check returned list was empty
+ // (the position parameters in this method are indexed from 1)
+ List<QueueEntry> entries = _queue.getMessagesRangeOnTheQueue(0, 0);
+ assertTrue(entries.size() == 0);
+
+ // Check that when 'from' is 0 it is ignored and the range continues from 1
+ entries = _queue.getMessagesRangeOnTheQueue(0, 2);
+ assertTrue(entries.size() == 2);
+ long msgID = entries.get(0).getMessage().getMessageNumber();
+ assertEquals("Message ID was wrong", msgID, 1L);
+ msgID = entries.get(1).getMessage().getMessageNumber();
+ assertEquals("Message ID was wrong", msgID, 2L);
+
+ // Check that when 'from' is greater than 'to' the returned list is empty
+ entries = _queue.getMessagesRangeOnTheQueue(5, 4);
+ assertTrue(entries.size() == 0);
+
+ // Get first QueueEntry & check id
+ entries = _queue.getMessagesRangeOnTheQueue(1, 1);
+ assertTrue(entries.size() == 1);
+ msgID = entries.get(0).getMessage().getMessageNumber();
+ assertEquals("Message ID was wrong", msgID, 1L);
+
+ // Get 5th,6th,7th entries and check id's
+ entries = _queue.getMessagesRangeOnTheQueue(5, 7);
+ assertTrue(entries.size() == 3);
+ msgID = entries.get(0).getMessage().getMessageNumber();
+ assertEquals("Message ID was wrong", msgID, 5L);
+ msgID = entries.get(1).getMessage().getMessageNumber();
+ assertEquals("Message ID was wrong", msgID, 6L);
+ msgID = entries.get(2).getMessage().getMessageNumber();
+ assertEquals("Message ID was wrong", msgID, 7L);
+
+ // Get 10th QueueEntry & check id
+ entries = _queue.getMessagesRangeOnTheQueue(10, 10);
+ assertTrue(entries.size() == 1);
+ msgID = entries.get(0).getMessage().getMessageNumber();
+ assertEquals("Message ID was wrong", msgID, 10L);
- return amqMessageHandle;
+ // Get non-existent 11th QueueEntry & check returned set was empty
+ entries = _queue.getMessagesRangeOnTheQueue(11, 11);
+ assertTrue(entries.size() == 0);
+
+ // Get 9th,10th, and non-existent 11th entries & check result is of size 2 with correct IDs
+ entries = _queue.getMessagesRangeOnTheQueue(9, 11);
+ assertTrue(entries.size() == 2);
+ msgID = entries.get(0).getMessage().getMessageNumber();
+ assertEquals("Message ID was wrong", msgID, 9L);
+ msgID = entries.get(1).getMessage().getMessageNumber();
+ assertEquals("Message ID was wrong", msgID, 10L);
+ }
+
+ public void testEnqueueDequeueOfPersistentMessageToNonDurableQueue() throws AMQException
+ {
+ // Create IncomingMessage and nondurable queue
+ final IncomingMessage msg = new IncomingMessage(info);
+ ContentHeaderBody contentHeaderBody = new ContentHeaderBody();
+ contentHeaderBody.properties = new BasicContentHeaderProperties();
+ ((BasicContentHeaderProperties) contentHeaderBody.properties).setDeliveryMode((byte) 2);
+ msg.setContentHeaderBody(contentHeaderBody);
+
+ final ArrayList<AMQQueue> qs = new ArrayList<AMQQueue>();
+
+ // Send persistent message
+
+ qs.add(_queue);
+ MessageMetaData metaData = msg.headersReceived();
+ StoredMessage handle = _store.addMessage(metaData);
+ msg.setStoredMessage(handle);
+
+
+ ServerTransaction txn = new AutoCommitTransaction(_store);
+
+ txn.enqueue(qs, msg, new ServerTransaction.Action()
+ {
+ public void postCommit()
+ {
+ msg.enqueue(qs);
+ }
+
+ public void onRollback()
+ {
+ }
+ });
+
+
+
+ // Check that it is enqueued
+ AMQQueue data = _store.getMessages().get(1L);
+ assertNull(data);
+
+ // Dequeue message
+ MockQueueEntry entry = new MockQueueEntry();
+ AMQMessage amqmsg = new AMQMessage(handle);
+
+ entry.setMessage(amqmsg);
+ _queue.dequeue(entry);
+
+ // Check that it is dequeued
+ data = _store.getMessages().get(1L);
+ assertNull(data);
}
+
public class TestMessage extends AMQMessage
{
private final long _tag;
private int _count;
- TestMessage(long tag, long messageId, MessagePublishInfo publishBody, StoreContext storeContext)
+ TestMessage(long tag, long messageId, MessagePublishInfo publishBody)
throws AMQException
{
- super(createMessageHandle(messageId, publishBody), storeContext, publishBody);
+ this(tag, messageId, publishBody, new ContentHeaderBody(1, 1, new BasicContentHeaderProperties(), 0));
+
+ }
+ TestMessage(long tag, long messageId, MessagePublishInfo publishBody, ContentHeaderBody chb)
+ throws AMQException
+ {
+ super(new MockStoredMessage(messageId, publishBody, chb));
_tag = tag;
}
-
public boolean incrementReference()
{
_count++;
return true;
}
- public void decrementReference(StoreContext context)
+ public void decrementReference()
{
_count--;
}
@@ -185,4 +486,10 @@ public class SimpleAMQQueueTest extends TestCase
assertEquals("Wrong count for message with tag " + _tag, expected, _count);
}
}
+
+ protected AMQMessage createMessage(Long id) throws AMQException
+ {
+ AMQMessage messageA = new TestMessage(id, id, info);
+ return messageA;
+ }
}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueThreadPoolTest.java b/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueThreadPoolTest.java
new file mode 100644
index 0000000000..ba94af5936
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueThreadPoolTest.java
@@ -0,0 +1,58 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import junit.framework.TestCase;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.pool.ReferenceCountingExecutorService;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.AMQException;
+
+public class SimpleAMQQueueThreadPoolTest extends TestCase
+{
+
+ public void test() throws AMQException
+ {
+ int initialCount = ReferenceCountingExecutorService.getInstance().getReferenceCount();
+ VirtualHost test = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test");
+
+ try
+ {
+ SimpleAMQQueue queue = (SimpleAMQQueue) AMQQueueFactory.createAMQQueueImpl(new AMQShortString("test"), false,
+ new AMQShortString("owner"),
+ false, test, null);
+
+ assertFalse("Creation did not start Pool.", ReferenceCountingExecutorService.getInstance().getPool().isShutdown());
+
+ assertEquals("References not increased", initialCount + 1, ReferenceCountingExecutorService.getInstance().getReferenceCount());
+
+ queue.stop();
+
+ assertEquals("References not decreased", initialCount , ReferenceCountingExecutorService.getInstance().getReferenceCount());
+ }
+ finally
+ {
+ ApplicationRegistry.remove();
+ }
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/registry/ApplicationRegistryShutdownTest.java b/java/broker/src/test/java/org/apache/qpid/server/registry/ApplicationRegistryShutdownTest.java
new file mode 100644
index 0000000000..4c8ff01be0
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/registry/ApplicationRegistryShutdownTest.java
@@ -0,0 +1,131 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.registry;
+
+import junit.framework.TestCase;
+import org.apache.qpid.server.util.TestApplicationRegistry;
+
+import java.security.Security;
+import java.security.Provider;
+import java.util.List;
+import java.util.LinkedList;
+
+/**
+ * QPID-1390 : Test to validate that the AuthenticationManger succesfully unregisters any new SASL providers when
+ * The ApplicationRegistry is closed.
+ *
+ * This should be expanded as QPID-1399 is implemented.
+ */
+public class ApplicationRegistryShutdownTest extends TestCase
+{
+
+ IApplicationRegistry _registry;
+
+ public void setUp() throws Exception
+ {
+ //Highlight that this test will cause a new AR to be created
+ // This must used TestAppRegistry but during the test getInstance()
+ // will be called so we must ensure to do the remove()
+ _registry = new TestApplicationRegistry();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ // Correctly Close the AR we created
+ ApplicationRegistry.remove();
+ }
+
+
+ /**
+ * QPID-1399 : Ensure that the Authentiction manager unregisters any SASL providers created during
+ * ApplicationRegistry initialisation.
+ *
+ */
+ public void testAuthenticationMangerCleansUp()
+ {
+ // Get default providers
+ Provider[] defaultProviders = Security.getProviders();
+
+ // Register new providers
+ try
+ {
+ _registry.initialise(ApplicationRegistry.DEFAULT_INSTANCE);
+ }
+ catch (Exception e)
+ {
+ fail(e.getMessage());
+ }
+
+ // Get the providers after initialisation
+ Provider[] providersAfterInitialisation = Security.getProviders();
+
+ // Find the additions
+ List additions = new LinkedList();
+ for (Provider afterInit : providersAfterInitialisation)
+ {
+ boolean found = false;
+ for (Provider defaultProvider : defaultProviders)
+ {
+ if (defaultProvider == afterInit)
+ {
+ found=true;
+ break;
+ }
+ }
+
+ // Record added registies
+ if (!found)
+ {
+ additions.add(afterInit);
+ }
+ }
+
+ // Not using isEmpty as that is not in Java 5
+ assertTrue("No new SASL mechanisms added by initialisation.", additions.size() != 0 );
+
+ //Close the registry which will perform the close the AuthenticationManager
+ try
+ {
+ _registry.close();
+ }
+ catch (Exception e)
+ {
+ fail(e.getMessage());
+ }
+
+ //Validate that the SASL plugins have been removed.
+ Provider[] providersAfterClose = Security.getProviders();
+
+ assertTrue("No providers unregistered", providersAfterInitialisation.length > providersAfterClose.length);
+
+ //Ensure that the additions are not still present after close().
+ for (Provider afterClose : providersAfterClose)
+ {
+ assertFalse("Added provider not unregistered", additions.contains(afterClose));
+ }
+ }
+
+
+
+
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/securiity/auth/sasl/CRAMMD5HexInitialiserTest.java b/java/broker/src/test/java/org/apache/qpid/server/securiity/auth/sasl/CRAMMD5HexInitialiserTest.java
new file mode 100644
index 0000000000..0d92b21d74
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/securiity/auth/sasl/CRAMMD5HexInitialiserTest.java
@@ -0,0 +1,143 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.securiity.auth.sasl;
+
+import junit.framework.TestCase;
+import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabase;
+import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HexInitialiser;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Properties;
+
+/**
+ * These tests ensure that the Hex wrapping that the initialiser performs does actually operate when the handle method is called.
+ */
+public class CRAMMD5HexInitialiserTest extends TestCase
+{
+
+ public void testHex()
+ {
+
+ //Create User details for testing
+ String user = "testUser";
+ String password = "testPassword";
+
+ perform(user, password);
+ }
+
+ public void testHashedHex()
+ {
+
+ //Create User details for testing
+ String user = "testUser";
+ String password = "testPassword";
+
+ //Create a hashed password that we then attempt to put through the call back mechanism.
+ try
+ {
+ password = new String(MessageDigest.getInstance("MD5").digest(password.getBytes()));
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ fail(e.getMessage());
+ }
+
+ perform(user, password);
+ }
+
+ public void perform(String user, String password)
+ {
+ CRAMMD5HexInitialiser initialiser = new CRAMMD5HexInitialiser();
+
+ //Use properties to create a PrincipalDatabase
+ Properties users = new Properties();
+ users.put(user, password);
+
+ PropertiesPrincipalDatabase db = new PropertiesPrincipalDatabase(users);
+
+ initialiser.initialise(db);
+
+ //setup the callbacks
+ PasswordCallback passwordCallback = new PasswordCallback("password:", false);
+ NameCallback usernameCallback = new NameCallback("user:", user);
+
+ Callback[] callbacks = new Callback[]{usernameCallback, passwordCallback};
+
+ //Check the
+ try
+ {
+ assertNull("The password was not null before the handle call.", passwordCallback.getPassword());
+ initialiser.getCallbackHandler().handle(callbacks);
+ }
+ catch (IOException e)
+ {
+ fail(e.getMessage());
+ }
+ catch (UnsupportedCallbackException e)
+ {
+ fail(e.getMessage());
+ }
+
+ //Hex the password we initialised with and compare it with the passwordCallback
+ assertArrayEquals(toHex(password.toCharArray()), passwordCallback.getPassword());
+
+ }
+
+ private void assertArrayEquals(char[] expected, char[] actual)
+ {
+ assertEquals("Arrays are not the same length", expected.length, actual.length);
+
+ for (int index = 0; index < expected.length; index++)
+ {
+ assertEquals("Characters are not equal", expected[index], actual[index]);
+ }
+ }
+
+ private char[] toHex(char[] password)
+ {
+ StringBuilder sb = new StringBuilder();
+ for (char c : password)
+ {
+ //toHexString does not prepend 0 so we have to
+ if (((byte) c > -1) && (byte) c < 10)
+ {
+ sb.append(0);
+ }
+
+ sb.append(Integer.toHexString(c & 0xFF));
+ }
+
+ //Extract the hex string as char[]
+ char[] hex = new char[sb.length()];
+
+ sb.getChars(0, sb.length(), hex, 0);
+
+ return hex;
+ }
+
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/access/ACLManagerTest.java b/java/broker/src/test/java/org/apache/qpid/server/security/access/ACLManagerTest.java
new file mode 100644
index 0000000000..44f9861e8d
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/access/ACLManagerTest.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.security.access;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.qpid.server.configuration.SecurityConfiguration;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.plugins.MockPluginManager;
+import org.apache.qpid.server.plugins.PluginManager;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.protocol.InternalTestProtocolSession;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.MockAMQQueue;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+
+public class ACLManagerTest extends TestCase
+{
+
+ private ACLManager _authzManager;
+ private AMQProtocolSession _session;
+ private SecurityConfiguration _conf;
+ private PluginManager _pluginManager;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ File tmpFile = File.createTempFile(getClass().getName(), "testconfig");
+ tmpFile.deleteOnExit();
+ BufferedWriter out = new BufferedWriter(new FileWriter(tmpFile));
+ out.write("<security><queueDenier>notyet</queueDenier><exchangeDenier>yes</exchangeDenier></security>");
+ out.close();
+
+ _conf = new SecurityConfiguration(new XMLConfiguration(tmpFile));
+
+ // Create ACLManager
+
+ _pluginManager = new MockPluginManager("");
+ _authzManager = new ACLManager(_conf, _pluginManager);
+
+
+ VirtualHost virtualHost = ApplicationRegistry.getInstance().
+ getVirtualHostRegistry().getVirtualHosts().iterator().next();
+
+ // Create a single session for this test.
+ _session = new InternalTestProtocolSession(virtualHost);
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ // Correctly Close the AR we created
+ ApplicationRegistry.remove();
+ super.tearDown();
+ }
+
+ public void testACLManagerConfigurationPluginManager() throws Exception
+ {
+ AMQQueue queue = new MockAMQQueue("notyet");
+ AMQQueue otherQueue = new MockAMQQueue("other");
+
+ assertFalse(_authzManager.authoriseDelete(_session, queue));
+
+ // This should only be denied if the config hasn't been correctly passed in
+ assertTrue(_authzManager.authoriseDelete(_session, otherQueue));
+ assertTrue(_authzManager.authorisePurge(_session, queue));
+ }
+
+ public void testACLManagerConfigurationPluginManagerACLPlugin() throws ConfigurationException
+ {
+ _authzManager = new ACLManager(_conf, _pluginManager, ExchangeDenier.FACTORY);
+
+ Exchange exchange = null;
+ assertFalse(_authzManager.authoriseDelete(_session, exchange));
+ }
+
+ public void testConfigurePlugins() throws ConfigurationException
+ {
+ Configuration hostConfig = new PropertiesConfiguration();
+ hostConfig.setProperty("queueDenier", "thisoneneither");
+ _authzManager.configureHostPlugins(new SecurityConfiguration(hostConfig));
+ AMQQueue queue = new MockAMQQueue("thisoneneither");
+ assertFalse(_authzManager.authoriseDelete(_session, queue));
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java b/java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java
new file mode 100644
index 0000000000..37a0fd7fc3
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.security.access;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.security.access.plugins.AllowAll;
+import org.apache.qpid.server.security.PrincipalHolder;
+
+public class ExchangeDenier extends AllowAll
+{
+
+ public static final ACLPluginFactory FACTORY = new ACLPluginFactory()
+ {
+ public boolean supportsTag(String name)
+ {
+ return name.startsWith("exchangeDenier");
+ }
+
+ public ACLPlugin newInstance(Configuration config)
+ {
+ return new ExchangeDenier();
+ }
+ };
+
+ @Override
+ public AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange)
+ {
+ return AuthzResult.DENIED;
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java b/java/broker/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java
new file mode 100644
index 0000000000..73e9dac775
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java
@@ -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.
+ *
+ */
+
+package org.apache.qpid.server.security.access;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.amqp_0_9.ExchangeDeclareBodyImpl;
+import org.apache.qpid.framing.amqp_8_0.QueueBindBodyImpl;
+import org.apache.qpid.server.configuration.VirtualHostConfiguration;
+import org.apache.qpid.server.exchange.DirectExchange;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.AMQQueueFactory;
+import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult;
+import org.apache.qpid.server.virtualhost.VirtualHostImpl;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+
+public class PrincipalPermissionsTest extends TestCase
+{
+
+ private String _user = "user";
+ private PrincipalPermissions _perms;
+
+ // Common things that are passed to frame constructors
+ private AMQShortString _queueName = new AMQShortString(this.getClass().getName()+"queue");
+ private AMQShortString _tempQueueName = new AMQShortString(this.getClass().getName()+"tempqueue");
+ private AMQShortString _exchangeName = new AMQShortString("amq.direct");
+ private AMQShortString _routingKey = new AMQShortString(this.getClass().getName()+"route");
+ private int _ticket = 1;
+ private FieldTable _arguments = null;
+ private boolean _nowait = false;
+ private boolean _passive = false;
+ private boolean _durable = false;
+ private boolean _autoDelete = false;
+ private AMQShortString _exchangeType = new AMQShortString("direct");
+ private boolean _internal = false;
+
+ private DirectExchange _exchange;
+ private VirtualHost _virtualHost;
+ private AMQShortString _owner = new AMQShortString(this.getClass().getName()+"owner");
+ private AMQQueue _queue;
+ private AMQQueue _temporaryQueue;
+ private Boolean _temporary = false;
+ private Boolean _ownQueue = false;
+
+ @Override
+ public void setUp()
+ {
+ //Highlight that this test will cause a new AR to be created
+ ApplicationRegistry.getInstance();
+
+ _perms = new PrincipalPermissions(_user);
+ try
+ {
+ PropertiesConfiguration env = new PropertiesConfiguration();
+ _virtualHost = new VirtualHostImpl(new VirtualHostConfiguration("test", env));
+ _exchange = DirectExchange.TYPE.newInstance(_virtualHost, _exchangeName, _durable, _ticket, _autoDelete);
+ _queue = AMQQueueFactory.createAMQQueueImpl(_queueName, false, _owner , false, _virtualHost, _arguments);
+ _temporaryQueue = AMQQueueFactory.createAMQQueueImpl(_tempQueueName, false, _owner , true, _virtualHost, _arguments);
+ }
+ catch (Exception e)
+ {
+ fail(e.getMessage());
+ }
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ //Ensure we close the opened Registry
+ ApplicationRegistry.remove();
+ }
+
+
+ public void testPrincipalPermissions()
+ {
+ assertNotNull(_perms);
+ assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.ACCESS, (Object[]) null));
+ }
+
+ // FIXME: test has been disabled since the permissions assume that the user has tried to create
+ // the queue first. QPID-1597
+ public void disableTestBind() throws Exception
+ {
+ QueueBindBodyImpl bind = new QueueBindBodyImpl(_ticket, _queueName, _exchangeName, _routingKey, _nowait, _arguments);
+ Object[] args = new Object[]{bind, _exchange, _queue, _routingKey};
+
+ assertEquals(AuthzResult.DENIED, _perms.authorise(Permission.BIND, args));
+ _perms.grant(Permission.BIND, (Object[]) null);
+ assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.BIND, args));
+ }
+
+ public void testQueueCreate()
+ {
+ Object[] grantArgs = new Object[]{_temporary , _queueName, _exchangeName, _routingKey};
+ Object[] authArgs = new Object[]{_autoDelete, _queueName};
+
+ assertEquals(AuthzResult.DENIED, _perms.authorise(Permission.CREATEQUEUE, authArgs));
+ _perms.grant(Permission.CREATEQUEUE, grantArgs);
+ assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.CREATEQUEUE, authArgs));
+ }
+
+ public void testQueueCreateWithNullRoutingKey()
+ {
+ Object[] grantArgs = new Object[]{_temporary , _queueName, _exchangeName, null};
+ Object[] authArgs = new Object[]{_autoDelete, _queueName};
+
+ assertEquals(AuthzResult.DENIED, _perms.authorise(Permission.CREATEQUEUE, authArgs));
+ _perms.grant(Permission.CREATEQUEUE, grantArgs);
+ assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.CREATEQUEUE, authArgs));
+ }
+
+ // FIXME disabled, this fails due to grant putting the grant into the wrong map QPID-1598
+ public void disableTestExchangeCreate()
+ {
+ ExchangeDeclareBodyImpl exchangeDeclare =
+ new ExchangeDeclareBodyImpl(_ticket, _exchangeName, _exchangeType, _passive, _durable,
+ _autoDelete, _internal, _nowait, _arguments);
+ Object[] authArgs = new Object[]{exchangeDeclare};
+ Object[] grantArgs = new Object[]{_exchangeName, _exchangeType};
+
+ assertEquals(AuthzResult.DENIED, _perms.authorise(Permission.CREATEEXCHANGE, authArgs));
+ _perms.grant(Permission.CREATEEXCHANGE, grantArgs);
+ assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.CREATEEXCHANGE, authArgs));
+ }
+
+ public void testConsume()
+ {
+ Object[] authArgs = new Object[]{_queue};
+ Object[] grantArgs = new Object[]{_queueName, _ownQueue};
+
+ /* FIXME: This throws a null pointer exception QPID-1599
+ * assertFalse(_perms.authorise(Permission.CONSUME, authArgs));
+ */
+ _perms.grant(Permission.CONSUME, grantArgs);
+ assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.CONSUME, authArgs));
+ }
+
+ public void testPublish()
+ {
+ Object[] authArgs = new Object[]{_exchange, _routingKey};
+ Object[] grantArgs = new Object[]{_exchange.getName(), _routingKey};
+
+ assertEquals(AuthzResult.DENIED, _perms.authorise(Permission.PUBLISH, authArgs));
+ _perms.grant(Permission.PUBLISH, grantArgs);
+ assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.PUBLISH, authArgs));
+ }
+
+ public void testVhostAccess()
+ {
+ //Tests that granting a user Virtualhost level access allows all authorisation requests
+ //where previously they would be denied
+
+ //QPID-2133 createExchange rights currently allow all exchange creation unless rights for creating some
+ //specific exchanges are granted. Grant a specific exchange creation to cause all others to be denied.
+ Object[] createArgsCreateExchange = new Object[]{new AMQShortString("madeup"), _exchangeType};
+ Object[] authArgsCreateExchange = new Object[]{_exchangeName,_exchangeType};
+ assertEquals("Exchange creation was not allowed", AuthzResult.ALLOWED, _perms.authorise(Permission.CREATEEXCHANGE, authArgsCreateExchange));
+ _perms.grant(Permission.CREATEEXCHANGE, createArgsCreateExchange);
+
+ Object[] authArgsPublish = new Object[]{_exchange, _routingKey};
+ Object[] authArgsConsume = new Object[]{_queue};
+ Object[] authArgsCreateQueue = new Object[]{_autoDelete, _queueName};
+ QueueBindBodyImpl bind = new QueueBindBodyImpl(_ticket, _queueName, _exchangeName, _routingKey, _nowait, _arguments);
+ Object[] authArgsBind = new Object[]{bind, _exchange, _queue, _routingKey};
+
+ assertEquals("Exchange creation was not denied", AuthzResult.DENIED, _perms.authorise(Permission.CREATEEXCHANGE, authArgsCreateExchange));
+ assertEquals("Publish was not denied", AuthzResult.DENIED, _perms.authorise(Permission.PUBLISH, authArgsPublish));
+ assertEquals("Consume creation was not denied", AuthzResult.DENIED, _perms.authorise(Permission.CONSUME, authArgsConsume));
+ assertEquals("Queue creation was not denied", AuthzResult.DENIED, _perms.authorise(Permission.CREATEQUEUE, authArgsCreateQueue));
+ //BIND pre-grant authorise check disabled due to QPID-1597
+ //assertEquals("Binding creation was not denied", AuthzResult.DENIED, _perms.authorise(Permission.BIND, authArgsBind));
+
+ _perms.grant(Permission.ACCESS);
+
+ assertEquals("Exchange creation was not allowed", AuthzResult.ALLOWED, _perms.authorise(Permission.CREATEEXCHANGE, authArgsCreateExchange));
+ assertEquals("Publish was not allowed", AuthzResult.ALLOWED, _perms.authorise(Permission.PUBLISH, authArgsPublish));
+ assertEquals("Consume creation was not allowed", AuthzResult.ALLOWED, _perms.authorise(Permission.CONSUME, authArgsConsume));
+ assertEquals("Queue creation was not allowed", AuthzResult.ALLOWED, _perms.authorise(Permission.CREATEQUEUE, authArgsCreateQueue));
+ assertEquals("Binding creation was not allowed", AuthzResult.ALLOWED, _perms.authorise(Permission.BIND, authArgsBind));
+ }
+
+ /**
+ * If the consume permission for temporary queues is for an unnamed queue then is should
+ * be global for any temporary queue but not for any non-temporary queue
+ */
+ public void testTemporaryUnnamedQueueConsume()
+ {
+ Object[] authNonTempQArgs = new Object[]{_queue};
+ Object[] authTempQArgs = new Object[]{_temporaryQueue};
+ Object[] grantArgs = new Object[]{true};
+
+ _perms.grant(Permission.CONSUME, grantArgs);
+
+ //Next line shows up bug - non temp queue should be denied
+ assertEquals(AuthzResult.DENIED, _perms.authorise(Permission.CONSUME, authNonTempQArgs));
+ assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.CONSUME, authTempQArgs));
+ }
+
+ /**
+ * Test that temporary queue permissions before queue perms in the ACL config work correctly
+ */
+ public void testTemporaryQueueFirstConsume()
+ {
+ Object[] authNonTempQArgs = new Object[]{_queue};
+ Object[] authTempQArgs = new Object[]{_temporaryQueue};
+ Object[] grantArgs = new Object[]{true};
+ Object[] grantNonTempQArgs = new Object[]{_queueName, _ownQueue};
+
+ //should not matter if the temporary permission is processed first or last
+ _perms.grant(Permission.CONSUME, grantNonTempQArgs);
+ _perms.grant(Permission.CONSUME, grantArgs);
+
+ assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.CONSUME, authNonTempQArgs));
+ assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.CONSUME, authTempQArgs));
+ }
+
+ /**
+ * Test that temporary queue permissions after queue perms in the ACL config work correctly
+ */
+ public void testTemporaryQueueLastConsume()
+ {
+ Object[] authNonTempQArgs = new Object[]{_queue};
+ Object[] authTempQArgs = new Object[]{_temporaryQueue};
+ Object[] grantArgs = new Object[]{true};
+ Object[] grantNonTempQArgs = new Object[]{_queueName, _ownQueue};
+
+ //should not matter if the temporary permission is processed first or last
+ _perms.grant(Permission.CONSUME, grantArgs);
+ _perms.grant(Permission.CONSUME, grantNonTempQArgs);
+
+ assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.CONSUME, authNonTempQArgs));
+ assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.CONSUME, authTempQArgs));
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/access/QueueDenier.java b/java/broker/src/test/java/org/apache/qpid/server/security/access/QueueDenier.java
new file mode 100644
index 0000000000..5b76bf7532
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/access/QueueDenier.java
@@ -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.
+ *
+ *
+ */
+package org.apache.qpid.server.security.access;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.security.access.plugins.AllowAll;
+import org.apache.qpid.server.security.PrincipalHolder;
+
+public class QueueDenier extends AllowAll
+{
+
+ public static final ACLPluginFactory FACTORY = new ACLPluginFactory()
+ {
+ public boolean supportsTag(String name)
+ {
+ return name.equals("queueDenier");
+ }
+
+ public ACLPlugin newInstance(Configuration config)
+ {
+ QueueDenier plugin = new QueueDenier();
+ plugin.setConfiguration(config);
+ return plugin;
+ }
+ };
+
+ private String _queueName = "";
+
+
+ @Override
+ public AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue)
+ {
+ if (!(queue.getName().toString().equals(_queueName)))
+ {
+ return AuthzResult.ALLOWED;
+ }
+ else
+ {
+ return AuthzResult.DENIED;
+ }
+ }
+
+ @Override
+ public void setConfiguration(Configuration config)
+ {
+ _queueName = config.getString("queueDenier");
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBeanTest.java b/java/broker/src/test/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBeanTest.java
new file mode 100644
index 0000000000..dab98095c9
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBeanTest.java
@@ -0,0 +1,276 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.security.access.management;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.server.management.MBeanInvocationHandlerImpl;
+import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase;
+
+import junit.framework.TestCase;
+
+/* Note: The main purpose is to test the jmx access rights file manipulation
+ * within AMQUserManagementMBean. The Principal Databases are tested by their own tests,
+ * this test just exercises their usage in AMQUserManagementMBean.
+ */
+public class AMQUserManagementMBeanTest extends TestCase
+{
+ private PlainPasswordFilePrincipalDatabase _database;
+ private AMQUserManagementMBean _amqumMBean;
+
+ private File _passwordFile;
+ private File _accessFile;
+
+ private static final String TEST_USERNAME = "testuser";
+ private static final String TEST_PASSWORD = "password";
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ _database = new PlainPasswordFilePrincipalDatabase();
+ _amqumMBean = new AMQUserManagementMBean();
+ loadFreshTestPasswordFile();
+ loadFreshTestAccessFile();
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ //clean up test password/access files
+ File _oldPasswordFile = new File(_passwordFile.getAbsolutePath() + ".old");
+ File _oldAccessFile = new File(_accessFile.getAbsolutePath() + ".old");
+ _oldPasswordFile.delete();
+ _oldAccessFile.delete();
+ _passwordFile.delete();
+ _accessFile.delete();
+ }
+
+ public void testDeleteUser()
+ {
+ loadFreshTestPasswordFile();
+ loadFreshTestAccessFile();
+
+ //try deleting a non existant user
+ assertFalse(_amqumMBean.deleteUser("made.up.username"));
+
+ assertTrue(_amqumMBean.deleteUser(TEST_USERNAME));
+ }
+
+ public void testDeleteUserIsSavedToAccessFile()
+ {
+ loadFreshTestPasswordFile();
+ loadFreshTestAccessFile();
+
+ assertTrue(_amqumMBean.deleteUser(TEST_USERNAME));
+
+ //check the access rights were actually deleted from the file
+ try{
+ BufferedReader reader = new BufferedReader(new FileReader(_accessFile));
+
+ //check the 'generated by' comment line is present
+ assertTrue("File has no content", reader.ready());
+ assertTrue("'Generated by' comment line was missing",reader.readLine().contains("Generated by " +
+ "AMQUserManagementMBean Console : Last edited by user:"));
+
+ //there should also be a modified date/time comment line
+ assertTrue("File has no modified date/time comment line", reader.ready());
+ assertTrue("Modification date/time comment line was missing",reader.readLine().startsWith("#"));
+
+ //the access file should not contain any further data now as we just deleted the only user
+ assertFalse("User access data was present when it should have been deleted", reader.ready());
+ }
+ catch (IOException e)
+ {
+ fail("Unable to valdate file contents due to:" + e.getMessage());
+ }
+
+ }
+
+ public void testSetRights()
+ {
+ loadFreshTestPasswordFile();
+ loadFreshTestAccessFile();
+
+ assertFalse(_amqumMBean.setRights("made.up.username", true, false, false));
+
+ assertTrue(_amqumMBean.setRights(TEST_USERNAME, true, false, false));
+ assertTrue(_amqumMBean.setRights(TEST_USERNAME, false, true, false));
+ assertTrue(_amqumMBean.setRights(TEST_USERNAME, false, false, true));
+ }
+
+ public void testSetRightsIsSavedToAccessFile()
+ {
+ loadFreshTestPasswordFile();
+ loadFreshTestAccessFile();
+
+ assertTrue(_amqumMBean.setRights(TEST_USERNAME, false, false, true));
+
+ //check the access rights were actually updated in the file
+ try{
+ BufferedReader reader = new BufferedReader(new FileReader(_accessFile));
+
+ //check the 'generated by' comment line is present
+ assertTrue("File has no content", reader.ready());
+ assertTrue("'Generated by' comment line was missing",reader.readLine().contains("Generated by " +
+ "AMQUserManagementMBean Console : Last edited by user:"));
+
+ //there should also be a modified date/time comment line
+ assertTrue("File has no modified date/time comment line", reader.ready());
+ assertTrue("Modification date/time comment line was missing",reader.readLine().startsWith("#"));
+
+ //the access file should not contain any further data now as we just deleted the only user
+ assertTrue("User access data was not updated in the access file",
+ reader.readLine().equals(TEST_USERNAME + "=" + MBeanInvocationHandlerImpl.ADMIN));
+
+ //the access file should not contain any further data now as we just deleted the only user
+ assertFalse("Additional user access data was present when there should be no more", reader.ready());
+ }
+ catch (IOException e)
+ {
+ fail("Unable to valdate file contents due to:" + e.getMessage());
+ }
+ }
+
+ public void testMBeanVersion()
+ {
+ try
+ {
+ ObjectName name = _amqumMBean.getObjectName();
+ assertEquals(AMQUserManagementMBean.VERSION, Integer.parseInt(name.getKeyProperty("version")));
+ }
+ catch (MalformedObjectNameException e)
+ {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testSetAccessFileWithMissingFile()
+ {
+ try
+ {
+ _amqumMBean.setAccessFile("made.up.filename");
+ }
+ catch (IOException e)
+ {
+ fail("Should not have been an IOE." + e.getMessage());
+ }
+ catch (ConfigurationException e)
+ {
+ assertTrue(e.getMessage(), e.getMessage().endsWith("does not exist"));
+ }
+ }
+
+ public void testSetAccessFileWithReadOnlyFile()
+ {
+ File testFile = null;
+ try
+ {
+ testFile = File.createTempFile(this.getClass().getName(),".access.readonly");
+ BufferedWriter passwordWriter = new BufferedWriter(new FileWriter(testFile, false));
+ passwordWriter.write(TEST_USERNAME + ":" + TEST_PASSWORD);
+ passwordWriter.newLine();
+ passwordWriter.flush();
+ passwordWriter.close();
+
+ testFile.setReadOnly();
+ _amqumMBean.setAccessFile(testFile.getPath());
+ }
+ catch (IOException e)
+ {
+ fail("Access file was not created." + e.getMessage());
+ }
+ catch (ConfigurationException e)
+ {
+ fail("There should not have been a configuration exception." + e.getMessage());
+ }
+
+ testFile.delete();
+ }
+
+ // ============================ Utility methods =========================
+
+ private void loadFreshTestPasswordFile()
+ {
+ try
+ {
+ if(_passwordFile == null)
+ {
+ _passwordFile = File.createTempFile(this.getClass().getName(),".password");
+ }
+
+ BufferedWriter passwordWriter = new BufferedWriter(new FileWriter(_passwordFile, false));
+ passwordWriter.write(TEST_USERNAME + ":" + TEST_PASSWORD);
+ passwordWriter.newLine();
+ passwordWriter.flush();
+ passwordWriter.close();
+ _database.setPasswordFile(_passwordFile.toString());
+ _amqumMBean.setPrincipalDatabase(_database);
+ }
+ catch (IOException e)
+ {
+ fail("Unable to create test password file: " + e.getMessage());
+ }
+ }
+
+ private void loadFreshTestAccessFile()
+ {
+ try
+ {
+ if(_accessFile == null)
+ {
+ _accessFile = File.createTempFile(this.getClass().getName(),".access");
+ }
+
+ BufferedWriter accessWriter = new BufferedWriter(new FileWriter(_accessFile,false));
+ accessWriter.write("#Last Updated By comment");
+ accessWriter.newLine();
+ accessWriter.write("#Date/time comment");
+ accessWriter.newLine();
+ accessWriter.write(TEST_USERNAME + "=" + MBeanInvocationHandlerImpl.READONLY);
+ accessWriter.newLine();
+ accessWriter.flush();
+ accessWriter.close();
+ }
+ catch (IOException e)
+ {
+ fail("Unable to create test access file: " + e.getMessage());
+ }
+
+ try{
+ _amqumMBean.setAccessFile(_accessFile.toString());
+ }
+ catch (Exception e)
+ {
+ fail("Unable to set access file: " + e.getMessage());
+ }
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/access/plugins/network/FirewallPluginTest.java b/java/broker/src/test/java/org/apache/qpid/server/security/access/plugins/network/FirewallPluginTest.java
new file mode 100644
index 0000000000..5d3335c001
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/access/plugins/network/FirewallPluginTest.java
@@ -0,0 +1,303 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.security.access.plugins.network;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.qpid.server.protocol.AMQProtocolEngine;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult;
+import org.apache.qpid.server.store.TestableMemoryMessageStore;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
+import org.apache.qpid.transport.TestNetworkDriver;
+
+public class FirewallPluginTest extends TestCase
+{
+
+ public class RuleInfo
+ {
+ private String _access;
+ private String _network;
+ private String _hostname;
+
+ public void setAccess(String _access)
+ {
+ this._access = _access;
+ }
+
+ public String getAccess()
+ {
+ return _access;
+ }
+
+ public void setNetwork(String _network)
+ {
+ this._network = _network;
+ }
+
+ public String getNetwork()
+ {
+ return _network;
+ }
+
+ public void setHostname(String _hostname)
+ {
+ this._hostname = _hostname;
+ }
+
+ public String getHostname()
+ {
+ return _hostname;
+ }
+ }
+
+ private TestableMemoryMessageStore _store;
+ private VirtualHost _virtualHost;
+ private AMQProtocolEngine _session;
+ private TestNetworkDriver _testDriver;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _store = new TestableMemoryMessageStore();
+ _testDriver = new TestNetworkDriver();
+ _testDriver.setRemoteAddress("127.0.0.1");
+
+ // Retreive VirtualHost from the Registry
+ VirtualHostRegistry virtualHostRegistry = ApplicationRegistry.getInstance().getVirtualHostRegistry();
+ _virtualHost = virtualHostRegistry.getVirtualHost("test");
+
+ _session = new AMQProtocolEngine(virtualHostRegistry, _testDriver);
+ }
+
+ public void tearDown() throws Exception
+ {
+ // Correctly Close the AR that we created above
+ ApplicationRegistry.remove();
+ super.tearDown();
+ }
+
+ private FirewallPlugin initialisePlugin(String defaultAction, RuleInfo[] rules) throws IOException, ConfigurationException
+ {
+ // Create sample config file
+ File confFile = File.createTempFile(getClass().getSimpleName()+"conffile", null);
+ confFile.deleteOnExit();
+ BufferedWriter buf = new BufferedWriter(new FileWriter(confFile));
+ buf.write("<firewall default-action=\""+defaultAction+"\">\n");
+ if (rules != null)
+ {
+ for (RuleInfo rule : rules)
+ {
+ buf.write("<rule");
+ buf.write(" access=\""+rule.getAccess()+"\"");
+ if (rule.getHostname() != null)
+ {
+ buf.write(" hostname=\""+rule.getHostname()+"\"");
+ }
+ if (rule.getNetwork() != null)
+ {
+ buf.write(" network=\""+rule.getNetwork()+"\"");
+ }
+ buf.write("/>\n");
+ }
+ }
+ buf.write("</firewall>");
+ buf.close();
+
+ // Configure plugin
+ FirewallPlugin plugin = new FirewallPlugin();
+ plugin.setConfiguration(new XMLConfiguration(confFile));
+ return plugin;
+ }
+
+ private FirewallPlugin initialisePlugin(String string) throws ConfigurationException, IOException
+ {
+ return initialisePlugin(string, null);
+ }
+
+ public void testDefaultAction() throws Exception
+ {
+ // Test simple deny
+ FirewallPlugin plugin = initialisePlugin("deny");
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Test simple allow
+ plugin = initialisePlugin("allow");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+
+ public void testSingleIPRule() throws Exception
+ {
+ RuleInfo rule = new RuleInfo();
+ rule.setAccess("allow");
+ rule.setNetwork("192.168.23.23");
+
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{rule});
+
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Set session IP so that we're connected from the right address
+ _testDriver.setRemoteAddress("192.168.23.23");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testSingleNetworkRule() throws Exception
+ {
+ RuleInfo rule = new RuleInfo();
+ rule.setAccess("allow");
+ rule.setNetwork("192.168.23.0/24");
+
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{rule});
+
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Set session IP so that we're connected from the right address
+ _testDriver.setRemoteAddress("192.168.23.23");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testSingleHostRule() throws Exception
+ {
+ RuleInfo rule = new RuleInfo();
+ rule.setAccess("allow");
+ rule.setHostname(new InetSocketAddress("127.0.0.1", 5672).getHostName());
+
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{rule});
+
+ // Set session IP so that we're connected from the right address
+ _testDriver.setRemoteAddress("127.0.0.1");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testSingleHostWilcardRule() throws Exception
+ {
+ RuleInfo rule = new RuleInfo();
+ rule.setAccess("allow");
+ String hostname = new InetSocketAddress("127.0.0.1", 0).getHostName();
+ rule.setHostname(".*"+hostname.subSequence(hostname.length() - 1, hostname.length())+"*");
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{rule});
+
+ // Set session IP so that we're connected from the right address
+ _testDriver.setRemoteAddress("127.0.0.1");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testSeveralFirstAllowsAccess() throws Exception
+ {
+ RuleInfo firstRule = new RuleInfo();
+ firstRule.setAccess("allow");
+ firstRule.setNetwork("192.168.23.23");
+
+ RuleInfo secondRule = new RuleInfo();
+ secondRule.setAccess("deny");
+ secondRule.setNetwork("192.168.42.42");
+
+ RuleInfo thirdRule = new RuleInfo();
+ thirdRule.setAccess("deny");
+ thirdRule.setHostname("localhost");
+
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{firstRule, secondRule, thirdRule});
+
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Set session IP so that we're connected from the right address
+ _testDriver.setRemoteAddress("192.168.23.23");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testSeveralLastAllowsAccess() throws Exception
+ {
+ RuleInfo firstRule = new RuleInfo();
+ firstRule.setAccess("deny");
+ firstRule.setHostname("localhost");
+
+ RuleInfo secondRule = new RuleInfo();
+ secondRule.setAccess("deny");
+ secondRule.setNetwork("192.168.42.42");
+
+ RuleInfo thirdRule = new RuleInfo();
+ thirdRule.setAccess("allow");
+ thirdRule.setNetwork("192.168.23.23");
+
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{firstRule, secondRule, thirdRule});
+
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Set session IP so that we're connected from the right address
+ _testDriver.setRemoteAddress("192.168.23.23");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testNetmask() throws Exception
+ {
+ RuleInfo firstRule = new RuleInfo();
+ firstRule.setAccess("allow");
+ firstRule.setNetwork("192.168.23.0/24");
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{firstRule});
+
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Set session IP so that we're connected from the right address
+ _testDriver.setRemoteAddress("192.168.23.23");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testCommaSeperatedNetmask() throws Exception
+ {
+ RuleInfo firstRule = new RuleInfo();
+ firstRule.setAccess("allow");
+ firstRule.setNetwork("10.1.1.1/8, 192.168.23.0/24");
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{firstRule});
+
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Set session IP so that we're connected from the right address
+ _testDriver.setRemoteAddress("192.168.23.23");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testCommaSeperatedHostnames() throws Exception
+ {
+ RuleInfo firstRule = new RuleInfo();
+ firstRule.setAccess("allow");
+ firstRule.setHostname("foo, bar, "+new InetSocketAddress("127.0.0.1", 5672).getHostName());
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{firstRule});
+ _testDriver.setRemoteAddress("10.0.0.1");
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Set session IP so that we're connected from the right address
+ _testDriver.setRemoteAddress("127.0.0.1");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabaseTest.java b/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabaseTest.java
new file mode 100644
index 0000000000..2ab15d4872
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabaseTest.java
@@ -0,0 +1,466 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.auth.database;
+
+import junit.framework.TestCase;
+
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.login.AccountNotFoundException;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+
+public class Base64MD5PasswordFilePrincipalDatabaseTest extends TestCase
+{
+
+ private static final String TEST_COMMENT = "# Test Comment";
+
+ private static final String USERNAME = "testUser";
+ private static final String PASSWORD = "guest";
+ private static final String PASSWORD_B64MD5HASHED = "CE4DQ6BIb/BVMN9scFyLtA==";
+ private static char[] PASSWORD_MD5_CHARS;
+ private static final String PRINCIPAL_USERNAME = "testUserPrincipal";
+ private static final Principal PRINCIPAL = new UsernamePrincipal(PRINCIPAL_USERNAME);
+ private Base64MD5PasswordFilePrincipalDatabase _database;
+ private File _pwdFile;
+ private List<File> _testPwdFiles = new ArrayList<File>();
+
+ static
+ {
+ try
+ {
+ Base64 b64 = new Base64();
+ byte[] md5passBytes = PASSWORD_B64MD5HASHED.getBytes(Base64MD5PasswordFilePrincipalDatabase.DEFAULT_ENCODING);
+ byte[] decoded = b64.decode(md5passBytes);
+
+ PASSWORD_MD5_CHARS = new char[decoded.length];
+
+ int index = 0;
+ for (byte c : decoded)
+ {
+ PASSWORD_MD5_CHARS[index++] = (char) c;
+ }
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ fail("Unable to perform B64 decode to get the md5 char[] password");
+ }
+ }
+
+
+ public void setUp() throws Exception
+ {
+ _database = new Base64MD5PasswordFilePrincipalDatabase();
+ _pwdFile = File.createTempFile(this.getClass().getName(), "pwd");
+ _pwdFile.deleteOnExit();
+ _database.setPasswordFile(_pwdFile.getAbsolutePath());
+ _testPwdFiles.clear();
+ }
+
+ public void tearDown() throws Exception
+ {
+ //clean up the created default password file and any backup
+ File oldPwdFile = new File(_pwdFile.getAbsolutePath() + ".old");
+ if(oldPwdFile.exists())
+ {
+ oldPwdFile.delete();
+ }
+
+ _pwdFile.delete();
+
+ //clean up any additional files and their backups
+ for(File f : _testPwdFiles)
+ {
+ oldPwdFile = new File(f.getAbsolutePath() + ".old");
+ if(oldPwdFile.exists())
+ {
+ oldPwdFile.delete();
+ }
+
+ f.delete();
+ }
+ }
+
+ private File createPasswordFile(int commentLines, int users)
+ {
+ try
+ {
+ File testFile = File.createTempFile("Base64MD5PDPDTest","tmp");
+ testFile.deleteOnExit();
+
+ BufferedWriter writer = new BufferedWriter(new FileWriter(testFile));
+
+ for (int i = 0; i < commentLines; i++)
+ {
+ writer.write(TEST_COMMENT);
+ writer.newLine();
+ }
+
+ for (int i = 0; i < users; i++)
+ {
+ writer.write(USERNAME + i + ":Password");
+ writer.newLine();
+ }
+
+ writer.flush();
+ writer.close();
+
+ _testPwdFiles.add(testFile);
+
+ return testFile;
+
+ }
+ catch (IOException e)
+ {
+ fail("Unable to create test password file." + e.getMessage());
+ }
+
+ return null;
+ }
+
+ private void loadPasswordFile(File file)
+ {
+ try
+ {
+ _database.setPasswordFile(file.toString());
+ }
+ catch (IOException e)
+ {
+ fail("Password File was not created." + e.getMessage());
+ }
+ }
+
+ /** **** Test Methods ************** */
+
+ public void testCreatePrincipal()
+ {
+ File testFile = createPasswordFile(1, 0);
+
+ loadPasswordFile(testFile);
+
+
+ Principal principal = new Principal()
+ {
+ public String getName()
+ {
+ return USERNAME;
+ }
+ };
+
+ assertTrue("New user not created.", _database.createPrincipal(principal, PASSWORD.toCharArray()));
+
+ PasswordCallback callback = new PasswordCallback("prompt",false);
+ try
+ {
+ _database.setPassword(principal, callback);
+ }
+ catch (AccountNotFoundException e)
+ {
+ fail("user account did not exist");
+ }
+ assertTrue("Password returned was incorrect.", Arrays.equals(PASSWORD_MD5_CHARS, callback.getPassword()));
+
+ loadPasswordFile(testFile);
+
+ try
+ {
+ _database.setPassword(principal, callback);
+ }
+ catch (AccountNotFoundException e)
+ {
+ fail("user account did not exist");
+ }
+ assertTrue("Password returned was incorrect.", Arrays.equals(PASSWORD_MD5_CHARS, callback.getPassword()));
+
+ assertNotNull("Created User was not saved", _database.getUser(USERNAME));
+
+ assertFalse("Duplicate user created.", _database.createPrincipal(principal, PASSWORD.toCharArray()));
+ }
+
+ public void testCreatePrincipalIsSavedToFile()
+ {
+
+ File testFile = createPasswordFile(1, 0);
+
+ loadPasswordFile(testFile);
+
+ final String CREATED_PASSWORD = "guest";
+ final String CREATED_B64MD5HASHED_PASSWORD = "CE4DQ6BIb/BVMN9scFyLtA==";
+ final String CREATED_USERNAME = "createdUser";
+
+ Principal principal = new Principal()
+ {
+ public String getName()
+ {
+ return CREATED_USERNAME;
+ }
+ };
+
+ _database.createPrincipal(principal, CREATED_PASSWORD.toCharArray());
+
+ try
+ {
+ BufferedReader reader = new BufferedReader(new FileReader(testFile));
+
+ assertTrue("File has no content", reader.ready());
+
+ assertEquals("Comment line has been corrupted.", TEST_COMMENT, reader.readLine());
+
+ assertTrue("File is missing user data.", reader.ready());
+
+ String userLine = reader.readLine();
+
+ String[] result = Pattern.compile(":").split(userLine);
+
+ assertEquals("User line not complete '" + userLine + "'", 2, result.length);
+
+ assertEquals("Username not correct,", CREATED_USERNAME, result[0]);
+ assertEquals("Password not correct,", CREATED_B64MD5HASHED_PASSWORD, result[1]);
+
+ assertFalse("File has more content", reader.ready());
+
+ }
+ catch (IOException e)
+ {
+ fail("Unable to valdate file contents due to:" + e.getMessage());
+ }
+ }
+
+
+ public void testDeletePrincipal()
+ {
+ File testFile = createPasswordFile(1, 1);
+
+ loadPasswordFile(testFile);
+
+ Principal user = _database.getUser(USERNAME + "0");
+ assertNotNull("Generated user not present.", user);
+
+ try
+ {
+ _database.deletePrincipal(user);
+ }
+ catch (AccountNotFoundException e)
+ {
+ fail("User should be present" + e.getMessage());
+ }
+
+ try
+ {
+ _database.deletePrincipal(user);
+ fail("User should not be present");
+ }
+ catch (AccountNotFoundException e)
+ {
+ //pass
+ }
+
+ loadPasswordFile(testFile);
+
+ try
+ {
+ _database.deletePrincipal(user);
+ fail("User should not be present");
+ }
+ catch (AccountNotFoundException e)
+ {
+ //pass
+ }
+
+ assertNull("Deleted user still present.", _database.getUser(USERNAME + "0"));
+ }
+
+ public void testGetUsers()
+ {
+ int USER_COUNT = 10;
+ File testFile = createPasswordFile(1, USER_COUNT);
+
+ loadPasswordFile(testFile);
+
+ Principal user = _database.getUser("MISSING_USERNAME");
+ assertNull("Missing user present.", user);
+
+ List<Principal> users = _database.getUsers();
+
+ assertNotNull("Users list is null.", users);
+
+ assertEquals(USER_COUNT, users.size());
+
+ boolean[] verify = new boolean[USER_COUNT];
+ for (int i = 0; i < USER_COUNT; i++)
+ {
+ Principal principal = users.get(i);
+
+ assertNotNull("Generated user not present.", principal);
+
+ String name = principal.getName();
+
+ int id = Integer.parseInt(name.substring(USERNAME.length()));
+
+ assertFalse("Duplicated username retrieve", verify[id]);
+ verify[id] = true;
+ }
+
+ for (int i = 0; i < USER_COUNT; i++)
+ {
+ assertTrue("User " + i + " missing", verify[i]);
+ }
+ }
+
+ public void testUpdatePasswordIsSavedToFile()
+ {
+
+ File testFile = createPasswordFile(1, 1);
+
+ loadPasswordFile(testFile);
+
+ Principal testUser = _database.getUser(USERNAME + "0");
+
+ assertNotNull(testUser);
+
+ String NEW_PASSWORD = "guest";
+ String NEW_PASSWORD_HASH = "CE4DQ6BIb/BVMN9scFyLtA==";
+ try
+ {
+ _database.updatePassword(testUser, NEW_PASSWORD.toCharArray());
+ }
+ catch (AccountNotFoundException e)
+ {
+ fail(e.toString());
+ }
+
+ try
+ {
+ BufferedReader reader = new BufferedReader(new FileReader(testFile));
+
+ assertTrue("File has no content", reader.ready());
+
+ assertEquals("Comment line has been corrupted.", TEST_COMMENT, reader.readLine());
+
+ assertTrue("File is missing user data.", reader.ready());
+
+ String userLine = reader.readLine();
+
+ String[] result = Pattern.compile(":").split(userLine);
+
+ assertEquals("User line not complete '" + userLine + "'", 2, result.length);
+
+ assertEquals("Username not correct,", USERNAME + "0", result[0]);
+ assertEquals("New Password not correct,", NEW_PASSWORD_HASH, result[1]);
+
+ assertFalse("File has more content", reader.ready());
+
+ }
+ catch (IOException e)
+ {
+ fail("Unable to valdate file contents due to:" + e.getMessage());
+ }
+ }
+
+ public void testSetPasswordFileWithMissingFile()
+ {
+ try
+ {
+ _database.setPasswordFile("DoesntExist");
+ }
+ catch (FileNotFoundException fnfe)
+ {
+ assertTrue(fnfe.getMessage(), fnfe.getMessage().startsWith("Cannot find password file"));
+ }
+ catch (IOException e)
+ {
+ fail("Password File was not created." + e.getMessage());
+ }
+
+ }
+
+ public void testSetPasswordFileWithReadOnlyFile()
+ {
+
+ File testFile = createPasswordFile(0, 0);
+
+ testFile.setReadOnly();
+
+ try
+ {
+ _database.setPasswordFile(testFile.toString());
+ }
+ catch (FileNotFoundException fnfe)
+ {
+ assertTrue(fnfe.getMessage().startsWith("Cannot read password file "));
+ }
+ catch (IOException e)
+ {
+ fail("Password File was not created." + e.getMessage());
+ }
+ }
+
+ public void testCreateUserPrincipal() throws IOException
+ {
+ _database.createPrincipal(PRINCIPAL, PASSWORD.toCharArray());
+ Principal newPrincipal = _database.getUser(PRINCIPAL_USERNAME);
+ assertNotNull(newPrincipal);
+ assertEquals(PRINCIPAL.getName(), newPrincipal.getName());
+ }
+
+ public void testVerifyPassword() throws IOException, AccountNotFoundException
+ {
+ testCreateUserPrincipal();
+ //assertFalse(_pwdDB.verifyPassword(_username, null));
+ assertFalse(_database.verifyPassword(PRINCIPAL_USERNAME, new char[]{}));
+ assertFalse(_database.verifyPassword(PRINCIPAL_USERNAME, (PASSWORD+"z").toCharArray()));
+ assertTrue(_database.verifyPassword(PRINCIPAL_USERNAME, PASSWORD.toCharArray()));
+
+ try
+ {
+ _database.verifyPassword("made.up.username", PASSWORD.toCharArray());
+ fail("Should not have been able to verify this non-existant users password.");
+ }
+ catch (AccountNotFoundException e)
+ {
+ // pass
+ }
+ }
+
+ public void testUpdatePassword() throws IOException, AccountNotFoundException
+ {
+ testCreateUserPrincipal();
+ char[] newPwd = "newpassword".toCharArray();
+ _database.updatePassword(PRINCIPAL, newPwd);
+ assertFalse(_database.verifyPassword(PRINCIPAL_USERNAME, PASSWORD.toCharArray()));
+ assertTrue(_database.verifyPassword(PRINCIPAL_USERNAME, newPwd));
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/HashedUserTest.java b/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/HashedUserTest.java
new file mode 100644
index 0000000000..aa85cac758
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/HashedUserTest.java
@@ -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.
+ *
+ */
+package org.apache.qpid.server.security.auth.database;
+
+import junit.framework.TestCase;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+
+import java.io.UnsupportedEncodingException;
+
+/*
+ Note User is mainly tested by Base64MD5PFPDTest this is just to catch the extra methods
+ */
+public class HashedUserTest extends TestCase
+{
+
+ String USERNAME = "username";
+ String PASSWORD = "password";
+ String B64_ENCODED_PASSWORD = "cGFzc3dvcmQ=";
+
+ public void testToLongArrayConstructor()
+ {
+ try
+ {
+ HashedUser user = new HashedUser(new String[]{USERNAME, PASSWORD, USERNAME});
+ fail("Error expected");
+ }
+ catch (IllegalArgumentException e)
+ {
+ assertEquals("User Data should be length 2, username, password", e.getMessage());
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testArrayConstructor()
+ {
+ try
+ {
+ HashedUser user = new HashedUser(new String[]{USERNAME, B64_ENCODED_PASSWORD});
+ assertEquals("Username incorrect", USERNAME, user.getName());
+ int index = 0;
+
+ char[] hash = B64_ENCODED_PASSWORD.toCharArray();
+
+ try
+ {
+ for (byte c : user.getEncodedPassword())
+ {
+ assertEquals("Password incorrect", hash[index], (char) c);
+ index++;
+ }
+ }
+ catch (Exception e)
+ {
+ fail(e.getMessage());
+ }
+
+ hash = PASSWORD.toCharArray();
+
+ index=0;
+ for (char c : user.getPassword())
+ {
+ assertEquals("Password incorrect", hash[index], c);
+ index++;
+ }
+
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ fail(e.getMessage());
+ }
+ }
+}
+
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabaseTest.java b/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabaseTest.java
new file mode 100644
index 0000000000..a3dad19bb4
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabaseTest.java
@@ -0,0 +1,416 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.auth.database;
+
+import junit.framework.TestCase;
+
+import javax.security.auth.login.AccountNotFoundException;
+
+import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+public class PlainPasswordFilePrincipalDatabaseTest extends TestCase
+{
+
+ private static final String TEST_COMMENT = "# Test Comment";
+ private static final String TEST_PASSWORD = "testPassword";
+ private static final char[] TEST_PASSWORD_CHARS = TEST_PASSWORD.toCharArray();
+ private static final String TEST_USERNAME = "testUser";
+
+ private Principal _principal = new UsernamePrincipal(TEST_USERNAME);
+ private PlainPasswordFilePrincipalDatabase _database;
+ private List<File> _testPwdFiles = new ArrayList<File>();
+
+ public void setUp() throws Exception
+ {
+ _database = new PlainPasswordFilePrincipalDatabase();
+ _testPwdFiles.clear();
+ }
+
+ public void tearDown() throws Exception
+ {
+ //clean up any additional files and their backups
+ for(File f : _testPwdFiles)
+ {
+ File oldPwdFile = new File(f.getAbsolutePath() + ".old");
+ if(oldPwdFile.exists())
+ {
+ oldPwdFile.delete();
+ }
+
+ f.delete();
+ }
+ }
+
+ // ******* Test Methods ********** //
+
+ public void testCreatePrincipal()
+ {
+ File testFile = createPasswordFile(1, 0);
+
+ loadPasswordFile(testFile);
+
+ final String CREATED_PASSWORD = "guest";
+ final String CREATED_USERNAME = "createdUser";
+
+ Principal principal = new Principal()
+ {
+ public String getName()
+ {
+ return CREATED_USERNAME;
+ }
+ };
+
+ assertTrue("New user not created.", _database.createPrincipal(principal, CREATED_PASSWORD.toCharArray()));
+
+ loadPasswordFile(testFile);
+
+ assertNotNull("Created User was not saved", _database.getUser(CREATED_USERNAME));
+
+ assertFalse("Duplicate user created.", _database.createPrincipal(principal, CREATED_PASSWORD.toCharArray()));
+
+ testFile.delete();
+ }
+
+ public void testCreatePrincipalIsSavedToFile()
+ {
+
+ File testFile = createPasswordFile(1, 0);
+
+ loadPasswordFile(testFile);
+
+ Principal principal = new Principal()
+ {
+ public String getName()
+ {
+ return TEST_USERNAME;
+ }
+ };
+
+ _database.createPrincipal(principal, TEST_PASSWORD_CHARS);
+
+ try
+ {
+ BufferedReader reader = new BufferedReader(new FileReader(testFile));
+
+ assertTrue("File has no content", reader.ready());
+
+ assertEquals("Comment line has been corrupted.", TEST_COMMENT, reader.readLine());
+
+ assertTrue("File is missing user data.", reader.ready());
+
+ String userLine = reader.readLine();
+
+ String[] result = Pattern.compile(":").split(userLine);
+
+ assertEquals("User line not complete '" + userLine + "'", 2, result.length);
+
+ assertEquals("Username not correct,", TEST_USERNAME, result[0]);
+ assertEquals("Password not correct,", TEST_PASSWORD, result[1]);
+
+ assertFalse("File has more content", reader.ready());
+
+ }
+ catch (IOException e)
+ {
+ fail("Unable to valdate file contents due to:" + e.getMessage());
+ }
+ testFile.delete();
+ }
+
+ public void testDeletePrincipal()
+ {
+ File testFile = createPasswordFile(1, 1);
+
+ loadPasswordFile(testFile);
+
+ Principal user = _database.getUser(TEST_USERNAME + "0");
+ assertNotNull("Generated user not present.", user);
+
+ try
+ {
+ _database.deletePrincipal(user);
+ }
+ catch (AccountNotFoundException e)
+ {
+ fail("User should be present" + e.getMessage());
+ }
+
+ try
+ {
+ _database.deletePrincipal(user);
+ fail("User should not be present");
+ }
+ catch (AccountNotFoundException e)
+ {
+ //pass
+ }
+
+ loadPasswordFile(testFile);
+
+ try
+ {
+ _database.deletePrincipal(user);
+ fail("User should not be present");
+ }
+ catch (AccountNotFoundException e)
+ {
+ //pass
+ }
+
+ assertNull("Deleted user still present.", _database.getUser(TEST_USERNAME + "0"));
+
+ testFile.delete();
+ }
+
+ public void testGetUsers()
+ {
+ int USER_COUNT = 10;
+ File testFile = createPasswordFile(1, USER_COUNT);
+
+ loadPasswordFile(testFile);
+
+ Principal user = _database.getUser("MISSING_USERNAME");
+ assertNull("Missing user present.", user);
+
+ List<Principal> users = _database.getUsers();
+
+ assertNotNull("Users list is null.", users);
+
+ assertEquals(USER_COUNT, users.size());
+
+ boolean[] verify = new boolean[USER_COUNT];
+ for (int i = 0; i < USER_COUNT; i++)
+ {
+ Principal principal = users.get(i);
+
+ assertNotNull("Generated user not present.", principal);
+
+ String name = principal.getName();
+
+ int id = Integer.parseInt(name.substring(TEST_USERNAME.length()));
+
+ assertFalse("Duplicated username retrieve", verify[id]);
+ verify[id] = true;
+ }
+
+ for (int i = 0; i < USER_COUNT; i++)
+ {
+ assertTrue("User " + i + " missing", verify[i]);
+ }
+
+ testFile.delete();
+ }
+
+ public void testUpdatePasswordIsSavedToFile()
+ {
+
+ File testFile = createPasswordFile(1, 1);
+
+ loadPasswordFile(testFile);
+
+ Principal testUser = _database.getUser(TEST_USERNAME + "0");
+
+ assertNotNull(testUser);
+
+ String NEW_PASSWORD = "NewPassword";
+ try
+ {
+ _database.updatePassword(testUser, NEW_PASSWORD.toCharArray());
+ }
+ catch (AccountNotFoundException e)
+ {
+ fail(e.toString());
+ }
+
+ try
+ {
+ BufferedReader reader = new BufferedReader(new FileReader(testFile));
+
+ assertTrue("File has no content", reader.ready());
+
+ assertEquals("Comment line has been corrupted.", TEST_COMMENT, reader.readLine());
+
+ assertTrue("File is missing user data.", reader.ready());
+
+ String userLine = reader.readLine();
+
+ String[] result = Pattern.compile(":").split(userLine);
+
+ assertEquals("User line not complete '" + userLine + "'", 2, result.length);
+
+ assertEquals("Username not correct,", TEST_USERNAME + "0", result[0]);
+ assertEquals("New Password not correct,", NEW_PASSWORD, result[1]);
+
+ assertFalse("File has more content", reader.ready());
+
+ }
+ catch (IOException e)
+ {
+ fail("Unable to valdate file contents due to:" + e.getMessage());
+ }
+ testFile.delete();
+ }
+
+ public void testSetPasswordFileWithMissingFile()
+ {
+ try
+ {
+ _database.setPasswordFile("DoesntExist");
+ }
+ catch (FileNotFoundException fnfe)
+ {
+ assertTrue(fnfe.getMessage(), fnfe.getMessage().startsWith("Cannot find password file"));
+ }
+ catch (IOException e)
+ {
+ fail("Password File was not created." + e.getMessage());
+ }
+
+ }
+
+ public void testSetPasswordFileWithReadOnlyFile()
+ {
+
+ File testFile = createPasswordFile(0, 0);
+
+ testFile.setReadOnly();
+
+ try
+ {
+ _database.setPasswordFile(testFile.toString());
+ }
+ catch (FileNotFoundException fnfe)
+ {
+ assertTrue(fnfe.getMessage().startsWith("Cannot read password file "));
+ }
+ catch (IOException e)
+ {
+ fail("Password File was not created." + e.getMessage());
+ }
+
+ testFile.delete();
+ }
+
+ private void createUserPrincipal() throws IOException
+ {
+ File testFile = createPasswordFile(0, 0);
+ loadPasswordFile(testFile);
+
+ _database.createPrincipal(_principal, TEST_PASSWORD_CHARS);
+ Principal newPrincipal = _database.getUser(TEST_USERNAME);
+ assertNotNull(newPrincipal);
+ assertEquals(_principal.getName(), newPrincipal.getName());
+ }
+
+ public void testVerifyPassword() throws IOException, AccountNotFoundException
+ {
+ createUserPrincipal();
+ assertFalse(_database.verifyPassword(TEST_USERNAME, new char[]{}));
+ assertFalse(_database.verifyPassword(TEST_USERNAME, "massword".toCharArray()));
+ assertTrue(_database.verifyPassword(TEST_USERNAME, TEST_PASSWORD_CHARS));
+
+ try
+ {
+ _database.verifyPassword("made.up.username", TEST_PASSWORD_CHARS);
+ fail("Should not have been able to verify this non-existant users password.");
+ }
+ catch (AccountNotFoundException e)
+ {
+ // pass
+ }
+ }
+
+ public void testUpdatePassword() throws IOException, AccountNotFoundException
+ {
+ createUserPrincipal();
+ char[] newPwd = "newpassword".toCharArray();
+ _database.updatePassword(_principal, newPwd);
+ assertFalse(_database.verifyPassword(TEST_USERNAME, TEST_PASSWORD_CHARS));
+ assertTrue(_database.verifyPassword(TEST_USERNAME, newPwd));
+ }
+
+
+
+ // *********** Utility Methods ******** //
+
+ private File createPasswordFile(int commentLines, int users)
+ {
+ try
+ {
+ File testFile = File.createTempFile(this.getClass().getName(),"tmp");
+ testFile.deleteOnExit();
+
+ BufferedWriter writer = new BufferedWriter(new FileWriter(testFile));
+
+ for (int i = 0; i < commentLines; i++)
+ {
+ writer.write(TEST_COMMENT);
+ writer.newLine();
+ }
+
+ for (int i = 0; i < users; i++)
+ {
+ writer.write(TEST_USERNAME + i + ":" + TEST_PASSWORD);
+ writer.newLine();
+ }
+
+ writer.flush();
+ writer.close();
+
+ _testPwdFiles.add(testFile);
+
+ return testFile;
+
+ }
+ catch (IOException e)
+ {
+ fail("Unable to create test password file." + e.getMessage());
+ }
+
+ return null;
+ }
+
+ private void loadPasswordFile(File file)
+ {
+ try
+ {
+ _database.setPasswordFile(file.toString());
+ }
+ catch (IOException e)
+ {
+ fail("Password File was not created." + e.getMessage());
+ }
+ }
+
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainUserTest.java b/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainUserTest.java
new file mode 100644
index 0000000000..7f0843d46e
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainUserTest.java
@@ -0,0 +1,78 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.auth.database;
+
+import junit.framework.TestCase;
+
+/*
+ Note PlainUser is mainly tested by PlainPFPDTest, this is just to catch the extra methods
+ */
+public class PlainUserTest extends TestCase
+{
+
+ String USERNAME = "username";
+ String PASSWORD = "password";
+
+ public void testTooLongArrayConstructor()
+ {
+ try
+ {
+ PlainUser user = new PlainUser(new String[]{USERNAME, PASSWORD, USERNAME});
+ fail("Error expected");
+ }
+ catch (IllegalArgumentException e)
+ {
+ assertEquals("User Data should be length 2, username, password", e.getMessage());
+ }
+ }
+
+ public void testStringArrayConstructor()
+ {
+ PlainUser user = new PlainUser(new String[]{USERNAME, PASSWORD});
+ assertEquals("Username incorrect", USERNAME, user.getName());
+ int index = 0;
+
+ char[] password = PASSWORD.toCharArray();
+
+ try
+ {
+ for (byte c : user.getPasswordBytes())
+ {
+ assertEquals("Password incorrect", password[index], (char) c);
+ index++;
+ }
+ }
+ catch (Exception e)
+ {
+ fail(e.getMessage());
+ }
+
+ password = PASSWORD.toCharArray();
+
+ index=0;
+ for (char c : user.getPassword())
+ {
+ assertEquals("Password incorrect", password[index], c);
+ index++;
+ }
+ }
+}
+
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java b/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java
new file mode 100644
index 0000000000..e8c24da68d
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java
@@ -0,0 +1,267 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.auth.rmi;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Collections;
+
+import javax.management.remote.JMXPrincipal;
+import javax.security.auth.Subject;
+
+import org.apache.qpid.server.security.auth.database.Base64MD5PasswordFilePrincipalDatabase;
+import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase;
+
+import junit.framework.TestCase;
+
+public class RMIPasswordAuthenticatorTest extends TestCase
+{
+ private final String USERNAME = "guest";
+ private final String PASSWORD = "guest";
+ private final String B64_MD5HASHED_PASSWORD = "CE4DQ6BIb/BVMN9scFyLtA==";
+ private RMIPasswordAuthenticator _rmipa;
+
+ private Base64MD5PasswordFilePrincipalDatabase _md5Pd;
+ private File _md5PwdFile;
+
+ private PlainPasswordFilePrincipalDatabase _plainPd;
+ private File _plainPwdFile;
+
+ private Subject testSubject;
+
+ protected void setUp() throws Exception
+ {
+ _rmipa = new RMIPasswordAuthenticator();
+
+ _md5Pd = new Base64MD5PasswordFilePrincipalDatabase();
+ _md5PwdFile = createTempPasswordFile(this.getClass().getName()+"md5pwd", USERNAME, B64_MD5HASHED_PASSWORD);
+ _md5Pd.setPasswordFile(_md5PwdFile.getAbsolutePath());
+
+ _plainPd = new PlainPasswordFilePrincipalDatabase();
+ _plainPwdFile = createTempPasswordFile(this.getClass().getName()+"plainpwd", USERNAME, PASSWORD);
+ _plainPd.setPasswordFile(_plainPwdFile.getAbsolutePath());
+
+ testSubject = new Subject(true,
+ Collections.singleton(new JMXPrincipal(USERNAME)),
+ Collections.EMPTY_SET,
+ Collections.EMPTY_SET);
+ }
+
+ private File createTempPasswordFile(String filenamePrefix, String user, String password)
+ {
+ try
+ {
+ File testFile = File.createTempFile(filenamePrefix,"tmp");
+ testFile.deleteOnExit();
+
+ BufferedWriter writer = new BufferedWriter(new FileWriter(testFile));
+
+ writer.write(user + ":" + password);
+ writer.newLine();
+
+ writer.flush();
+ writer.close();
+
+ return testFile;
+ }
+ catch (IOException e)
+ {
+ fail("Unable to create temporary test password file." + e.getMessage());
+ }
+
+ return null;
+ }
+
+
+ //********** Test Methods *********//
+
+
+ public void testAuthenticate()
+ {
+ String[] credentials;
+ Subject newSubject;
+
+ // Test when no PD has been set
+ try
+ {
+ credentials = new String[]{USERNAME, PASSWORD};
+ newSubject = _rmipa.authenticate(credentials);
+ fail("SecurityException expected due to lack of principal database");
+ }
+ catch (SecurityException se)
+ {
+ assertEquals("Unexpected exception message",
+ RMIPasswordAuthenticator.UNABLE_TO_LOOKUP, se.getMessage());
+ }
+
+ //The PrincipalDatabase's are tested primarily by their own tests, but
+ //minimal tests are done here to exercise their usage in this area.
+
+ // Test correct passwords are verified with an MD5 PD
+ try
+ {
+ _rmipa.setPrincipalDatabase(_md5Pd);
+ credentials = new String[]{USERNAME, PASSWORD};
+ newSubject = _rmipa.authenticate(credentials);
+ assertTrue("Returned subject does not equal expected value",
+ newSubject.equals(testSubject));
+ }
+ catch (Exception e)
+ {
+ fail("Unexpected Exception:" + e.getMessage());
+ }
+
+ // Test incorrect passwords are not verified with an MD5 PD
+ try
+ {
+ credentials = new String[]{USERNAME, PASSWORD+"incorrect"};
+ newSubject = _rmipa.authenticate(credentials);
+ fail("SecurityException expected due to incorrect password");
+ }
+ catch (SecurityException se)
+ {
+ assertEquals("Unexpected exception message",
+ RMIPasswordAuthenticator.INVALID_CREDENTIALS, se.getMessage());
+ }
+
+ // Test non-existent accounts are not verified with an MD5 PD
+ try
+ {
+ credentials = new String[]{USERNAME+"invalid", PASSWORD};
+ newSubject = _rmipa.authenticate(credentials);
+ fail("SecurityException expected due to non-existant account");
+ }
+ catch (SecurityException se)
+ {
+ assertEquals("Unexpected exception message",
+ RMIPasswordAuthenticator.INVALID_CREDENTIALS, se.getMessage());
+ }
+
+ // Test correct passwords are verified with a Plain PD
+ try
+ {
+ _rmipa.setPrincipalDatabase(_plainPd);
+ credentials = new String[]{USERNAME, PASSWORD};
+ newSubject = _rmipa.authenticate(credentials);
+ assertTrue("Returned subject does not equal expected value",
+ newSubject.equals(testSubject));
+ }
+ catch (Exception e)
+ {
+ fail("Unexpected Exception");
+ }
+
+ // Test incorrect passwords are not verified with a Plain PD
+ try
+ {
+ credentials = new String[]{USERNAME, PASSWORD+"incorrect"};
+ newSubject = _rmipa.authenticate(credentials);
+ fail("SecurityException expected due to incorrect password");
+ }
+ catch (SecurityException se)
+ {
+ assertEquals("Unexpected exception message",
+ RMIPasswordAuthenticator.INVALID_CREDENTIALS, se.getMessage());
+ }
+
+ // Test non-existent accounts are not verified with an Plain PD
+ try
+ {
+ credentials = new String[]{USERNAME+"invalid", PASSWORD};
+ newSubject = _rmipa.authenticate(credentials);
+ fail("SecurityException expected due to non existant account");
+ }
+ catch (SecurityException se)
+ {
+ assertEquals("Unexpected exception message",
+ RMIPasswordAuthenticator.INVALID_CREDENTIALS, se.getMessage());
+ }
+
+ // Test handling of non-string credential's
+ try
+ {
+ Object[] objCredentials = new Object[]{USERNAME, PASSWORD};
+ newSubject = _rmipa.authenticate(objCredentials);
+ fail("SecurityException expected due to non string[] credentials");
+ }
+ catch (SecurityException se)
+ {
+ assertEquals("Unexpected exception message",
+ RMIPasswordAuthenticator.SHOULD_BE_STRING_ARRAY, se.getMessage());
+ }
+
+ // Test handling of incorrect number of credential's
+ try
+ {
+ credentials = new String[]{USERNAME, PASSWORD, PASSWORD};
+ newSubject = _rmipa.authenticate(credentials);
+ fail("SecurityException expected due to supplying wrong number of credentials");
+ }
+ catch (SecurityException se)
+ {
+ assertEquals("Unexpected exception message",
+ RMIPasswordAuthenticator.SHOULD_HAVE_2_ELEMENTS, se.getMessage());
+ }
+
+ // Test handling of null credential's
+ try
+ {
+ //send a null array
+ credentials = null;
+ newSubject = _rmipa.authenticate(credentials);
+ fail("SecurityException expected due to not supplying an array of credentials");
+ }
+ catch (SecurityException se)
+ {
+ assertEquals("Unexpected exception message",
+ RMIPasswordAuthenticator.CREDENTIALS_REQUIRED, se.getMessage());
+ }
+
+ try
+ {
+ //send a null password
+ credentials = new String[]{USERNAME, null};
+ newSubject = _rmipa.authenticate(credentials);
+ fail("SecurityException expected due to sending a null password");
+ }
+ catch (SecurityException se)
+ {
+ assertEquals("Unexpected exception message",
+ RMIPasswordAuthenticator.SHOULD_BE_NON_NULL, se.getMessage());
+ }
+
+ try
+ {
+ //send a null username
+ credentials = new String[]{null, PASSWORD};
+ newSubject = _rmipa.authenticate(credentials);
+ fail("SecurityException expected due to sending a null username");
+ }
+ catch (SecurityException se)
+ {
+ assertEquals("Unexpected exception message",
+ RMIPasswordAuthenticator.SHOULD_BE_NON_NULL, se.getMessage());
+ }
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/TestPrincipalDatabase.java b/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/TestPrincipalDatabase.java
index a87c727a9a..8507e49e17 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/TestPrincipalDatabase.java
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/TestPrincipalDatabase.java
@@ -83,4 +83,9 @@ public class TestPrincipalDatabase implements PrincipalDatabase
return false;
}
+ public void reload() throws IOException
+ {
+ // TODO Auto-generated method stub
+ }
+
}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java b/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java
index 0524494bfd..5169676dae 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java
+++ b/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java
@@ -21,23 +21,21 @@
package org.apache.qpid.server.store;
import junit.framework.TestCase;
+
+import org.apache.qpid.server.configuration.VirtualHostConfiguration;
import org.apache.qpid.server.exchange.DirectExchange;
import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.server.exchange.ExchangeType;
import org.apache.qpid.server.exchange.TopicExchange;
import org.apache.qpid.server.exchange.ExchangeRegistry;
import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.AMQQueueFactory;
-import org.apache.qpid.server.queue.IncomingMessage;
-import org.apache.qpid.server.queue.MessageHandleFactory;
-import org.apache.qpid.server.queue.QueueRegistry;
-import org.apache.qpid.server.queue.AMQPriorityQueue;
-import org.apache.qpid.server.queue.SimpleAMQQueue;
-import org.apache.qpid.server.queue.ExchangeBinding;
-import org.apache.qpid.server.txn.NonTransactionalContext;
-import org.apache.qpid.server.protocol.InternalTestProtocolSession;
+import org.apache.qpid.server.virtualhost.VirtualHostImpl;
+import org.apache.qpid.server.queue.*;
+import org.apache.qpid.server.txn.ServerTransaction;
+import org.apache.qpid.server.txn.AutoCommitTransaction;
import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.message.MessageMetaData;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.framing.ContentHeaderBody;
@@ -101,7 +99,8 @@ public class MessageStoreTest extends TestCase
try
{
- _virtualHost = new VirtualHost(virtualHostName, configuration, null);
+ _virtualHost = new VirtualHostImpl(new VirtualHostConfiguration(getClass().getName(), configuration));
+ ApplicationRegistry.getInstance().getVirtualHostRegistry().registerVirtualHost(_virtualHost);
}
catch (Exception e)
{
@@ -133,12 +132,12 @@ public class MessageStoreTest extends TestCase
protected void setUp()
{
- ApplicationRegistry.getInstance(1);
+ ApplicationRegistry.getInstance();
}
protected void tearDown()
{
- ApplicationRegistry.remove(1);
+ ApplicationRegistry.remove();
}
protected void runTestWithStore(Configuration configuration)
@@ -166,7 +165,7 @@ public class MessageStoreTest extends TestCase
Exchange topicExchange = createExchange(TopicExchange.TYPE, topicExchangeName, true);
bindAllTopicQueuesToExchange(topicExchange, topicRouting);
- //Send Message To NonDurable direct Exchange = persistent
+ //Send Message To NonDurable direct Exchange = persistent
sendMessageOnExchange(nonDurableExchange, directRouting, true);
// and non-persistent
sendMessageOnExchange(nonDurableExchange, directRouting, false);
@@ -341,22 +340,11 @@ public class MessageStoreTest extends TestCase
MessagePublishInfo messageInfo = new TestMessagePublishInfo(directExchange, false, false, routingKey);
- IncomingMessage currentMessage = null;
+ final IncomingMessage currentMessage;
- try
- {
- currentMessage = new IncomingMessage(_virtualHost.getMessageStore().getNewMessageId(),
- messageInfo,
- new NonTransactionalContext(_virtualHost.getMessageStore(),
- new StoreContext(), null, null),
- new InternalTestProtocolSession());
- }
- catch (AMQException e)
- {
- fail(e.getMessage());
- }
- currentMessage.setMessageStore(_virtualHost.getMessageStore());
+ currentMessage = new IncomingMessage(messageInfo);
+
currentMessage.setExchange(directExchange);
ContentHeaderBody headerBody = new ContentHeaderBody();
@@ -376,35 +364,42 @@ public class MessageStoreTest extends TestCase
currentMessage.setExpiration();
- try
- {
- currentMessage.route();
- }
- catch (AMQException e)
- {
- fail(e.getMessage());
- }
+ MessageMetaData mmd = currentMessage.headersReceived();
+ currentMessage.setStoredMessage(_virtualHost.getMessageStore().addMessage(mmd));
+
+ currentMessage.route();
+
- try
- {
- currentMessage.routingComplete(_virtualHost.getMessageStore(), new MessageHandleFactory());
- }
- catch (AMQException e)
- {
- fail(e.getMessage());
- }
// check and deliver if header says body length is zero
if (currentMessage.allContentReceived())
{
- try
- {
- currentMessage.deliverToQueues();
- }
- catch (AMQException e)
- {
- fail(e.getMessage());
- }
+ // TODO Deliver to queues
+ ServerTransaction trans = new AutoCommitTransaction(_virtualHost.getMessageStore());
+ final List<AMQQueue> destinationQueues = currentMessage.getDestinationQueues();
+ trans.enqueue(currentMessage.getDestinationQueues(), currentMessage, new ServerTransaction.Action() {
+ public void postCommit()
+ {
+ try
+ {
+ AMQMessage message = new AMQMessage(currentMessage.getStoredMessage());
+
+ for(AMQQueue queue : destinationQueues)
+ {
+ QueueEntry entry = queue.enqueue(message);
+ }
+ }
+ catch (AMQException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public void onRollback()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+ });
}
}
@@ -493,14 +488,7 @@ public class MessageStoreTest extends TestCase
fail(e.getMessage());
}
- try
- {
- _virtualHost.getQueueRegistry().registerQueue(queue);
- }
- catch (AMQException e)
- {
- fail(e.getMessage());
- }
+ _virtualHost.getQueueRegistry().registerQueue(queue);
}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/store/SkeletonMessageStore.java b/java/broker/src/test/java/org/apache/qpid/server/store/SkeletonMessageStore.java
new file mode 100644
index 0000000000..9c12242a07
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/store/SkeletonMessageStore.java
@@ -0,0 +1,220 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.store;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.abstraction.ContentChunk;
+import org.apache.qpid.server.message.MessageMetaData;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.logging.LogSubject;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+import java.nio.ByteBuffer;
+
+/**
+ * A message store that does nothing. Designed to be used in tests that do not want to use any message store
+ * functionality.
+ */
+public class SkeletonMessageStore implements MessageStore
+{
+ private final AtomicLong _messageId = new AtomicLong(1);
+
+ public void configure(String base, Configuration config) throws Exception
+ {
+ }
+
+ public void configureConfigStore(String name,
+ ConfigurationRecoveryHandler recoveryHandler,
+ Configuration config,
+ LogSubject logSubject) throws Exception
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void configureMessageStore(String name,
+ MessageStoreRecoveryHandler recoveryHandler,
+ Configuration config,
+ LogSubject logSubject) throws Exception
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void close() throws Exception
+ {
+ }
+
+ public <M extends StorableMessageMetaData> StoredMessage<M> addMessage(M metaData)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void removeMessage(Long messageId)
+ {
+ }
+
+ public void createExchange(Exchange exchange) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void removeExchange(Exchange exchange) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void createQueue(AMQQueue queue) throws AMQException
+ {
+ }
+
+ public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException
+ {
+ }
+
+
+
+
+ public List<AMQQueue> createQueues() throws AMQException
+ {
+ return null;
+ }
+
+ public Long getNewMessageId()
+ {
+ return _messageId.getAndIncrement();
+ }
+
+ public void storeContentBodyChunk(
+ Long messageId,
+ int index,
+ ContentChunk contentBody,
+ boolean lastContentBody) throws AMQException
+ {
+
+ }
+
+ public void storeMessageMetaData(Long messageId, MessageMetaData messageMetaData) throws AMQException
+ {
+
+ }
+
+ public MessageMetaData getMessageMetaData(Long messageId) throws AMQException
+ {
+ return null;
+ }
+
+ public ContentChunk getContentBodyChunk(Long messageId, int index) throws AMQException
+ {
+ return null;
+ }
+
+ public boolean isPersistent()
+ {
+ return false;
+ }
+
+ public void storeMessageHeader(Long messageNumber, ServerMessage message)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void storeContent(Long messageNumber, long offset, ByteBuffer body)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public ServerMessage getMessage(Long messageNumber)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void removeQueue(final AMQQueue queue) throws AMQException
+ {
+
+ }
+
+ public void configureTransactionLog(String name,
+ TransactionLogRecoveryHandler recoveryHandler,
+ Configuration storeConfiguration,
+ LogSubject logSubject) throws Exception
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public Transaction newTransaction()
+ {
+ return new Transaction()
+ {
+
+ public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void commitTran() throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public StoreFuture commitTranAsync() throws AMQException
+ {
+ return new StoreFuture()
+ {
+ public boolean isComplete()
+ {
+ return true;
+ }
+
+ public void waitForCompletion()
+ {
+
+ }
+ };
+ }
+
+ public void abortTran() throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+ };
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/store/TestMemoryMessageStore.java b/java/broker/src/test/java/org/apache/qpid/server/store/TestMemoryMessageStore.java
new file mode 100644
index 0000000000..4dea13d391
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/store/TestMemoryMessageStore.java
@@ -0,0 +1,98 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.store;
+
+import org.apache.qpid.server.message.MessageMetaData;
+import org.apache.qpid.framing.abstraction.ContentChunk;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.List;
+import java.nio.ByteBuffer;
+
+/**
+ * Adds some extra methods to the memory message store for testing purposes.
+ */
+public class TestMemoryMessageStore extends MemoryMessageStore
+{
+ private AtomicInteger _messageCount = new AtomicInteger(0);
+
+
+ public TestMemoryMessageStore()
+ {
+ }
+
+ @Override
+ public StoredMessage addMessage(StorableMessageMetaData metaData)
+ {
+ return new TestableStoredMessage(super.addMessage(metaData));
+ }
+
+ public int getMessageCount()
+ {
+ return _messageCount.get();
+ }
+
+ private class TestableStoredMessage implements StoredMessage
+ {
+ private final StoredMessage _storedMessage;
+
+ public TestableStoredMessage(StoredMessage storedMessage)
+ {
+ _messageCount.incrementAndGet();
+ _storedMessage = storedMessage;
+ }
+
+ public StorableMessageMetaData getMetaData()
+ {
+ return _storedMessage.getMetaData();
+ }
+
+ public long getMessageNumber()
+ {
+ return _storedMessage.getMessageNumber();
+ }
+
+ public void addContent(int offsetInMessage, ByteBuffer src)
+ {
+ _storedMessage.addContent(offsetInMessage, src);
+ }
+
+ public int getContent(int offsetInMessage, ByteBuffer dst)
+ {
+ return _storedMessage.getContent(offsetInMessage, dst);
+ }
+
+ public StoreFuture flushToStore()
+ {
+ return _storedMessage.flushToStore();
+ }
+
+ public void remove()
+ {
+ _storedMessage.remove();
+ _messageCount.decrementAndGet();
+ }
+
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/store/TestReferenceCounting.java b/java/broker/src/test/java/org/apache/qpid/server/store/TestReferenceCounting.java
new file mode 100644
index 0000000000..c5b1ba7868
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/store/TestReferenceCounting.java
@@ -0,0 +1,167 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.store;
+
+import junit.framework.TestCase;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.message.MessageMetaData;
+
+/**
+ * Tests that reference counting works correctly with AMQMessage and the message store
+ */
+public class TestReferenceCounting extends TestCase
+{
+ private TestMemoryMessageStore _store;
+
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ _store = new TestMemoryMessageStore();
+
+ }
+
+ /**
+ * Check that when the reference count is decremented the message removes itself from the store
+ */
+ public void testMessageGetsRemoved() throws AMQException
+ {
+ ContentHeaderBody chb = createPersistentContentHeader();
+
+ MessagePublishInfo info = new MessagePublishInfo()
+ {
+
+ public AMQShortString getExchange()
+ {
+ return null;
+ }
+
+ public void setExchange(AMQShortString exchange)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isImmediate()
+ {
+ return false;
+ }
+
+ public boolean isMandatory()
+ {
+ return false;
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return null;
+ }
+ };
+
+
+
+ MessageMetaData mmd = new MessageMetaData(info, chb, 0);
+ StoredMessage storedMessage = _store.addMessage(mmd);
+
+
+ AMQMessage message = new AMQMessage(storedMessage);
+
+ message = message.takeReference();
+
+ // we call routing complete to set up the handle
+ // message.routingComplete(_store, _storeContext, new MessageHandleFactory());
+
+
+ assertEquals(1, _store.getMessageCount());
+ message.decrementReference();
+ assertEquals(1, _store.getMessageCount());
+ }
+
+ private ContentHeaderBody createPersistentContentHeader()
+ {
+ ContentHeaderBody chb = new ContentHeaderBody();
+ BasicContentHeaderProperties bchp = new BasicContentHeaderProperties();
+ bchp.setDeliveryMode((byte)2);
+ chb.properties = bchp;
+ return chb;
+ }
+
+ public void testMessageRemains() throws AMQException
+ {
+
+ MessagePublishInfo info = new MessagePublishInfo()
+ {
+
+ public AMQShortString getExchange()
+ {
+ return null;
+ }
+
+ public void setExchange(AMQShortString exchange)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isImmediate()
+ {
+ return false;
+ }
+
+ public boolean isMandatory()
+ {
+ return false;
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return null;
+ }
+ };
+
+ final ContentHeaderBody chb = createPersistentContentHeader();
+
+ MessageMetaData mmd = new MessageMetaData(info, chb, 0);
+ StoredMessage storedMessage = _store.addMessage(mmd);
+
+ AMQMessage message = new AMQMessage(storedMessage);
+
+
+ message = message.takeReference();
+ // we call routing complete to set up the handle
+ // message.routingComplete(_store, _storeContext, new MessageHandleFactory());
+
+
+
+ assertEquals(1, _store.getMessageCount());
+ message = message.takeReference();
+ message.decrementReference();
+ assertEquals(1, _store.getMessageCount());
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(TestReferenceCounting.class);
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java b/java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java
index 48d808142c..ab8c1e7c9c 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java
+++ b/java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java
@@ -20,13 +20,17 @@
*/
package org.apache.qpid.server.store;
-import org.apache.qpid.server.queue.MessageMetaData;
-import org.apache.qpid.framing.ContentBody;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.message.MessageMetaData;
import org.apache.qpid.framing.abstraction.ContentChunk;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.HashMap;
import java.util.List;
+import java.nio.ByteBuffer;
/**
* Adds some extra methods to the memory message store for testing purposes.
@@ -35,6 +39,8 @@ public class TestableMemoryMessageStore extends MemoryMessageStore
{
MemoryMessageStore _mms = null;
+ private HashMap<Long, AMQQueue> _messages = new HashMap<Long, AMQQueue>();
+ private AtomicInteger _messageCount = new AtomicInteger(0);
public TestableMemoryMessageStore(MemoryMessageStore mms)
{
@@ -43,31 +49,111 @@ public class TestableMemoryMessageStore extends MemoryMessageStore
public TestableMemoryMessageStore()
{
- _metaDataMap = new ConcurrentHashMap<Long, MessageMetaData>();
- _contentBodyMap = new ConcurrentHashMap<Long, List<ContentChunk>>();
+
+ }
+
+
+
+
+ @Override
+ public StoredMessage addMessage(StorableMessageMetaData metaData)
+ {
+ return new TestableStoredMessage(super.addMessage(metaData));
+ }
+
+ public int getMessageCount()
+ {
+ return _messageCount.get();
}
- public ConcurrentMap<Long, MessageMetaData> getMessageMetaDataMap()
+ private class TestableTransaction implements Transaction
{
- if (_mms != null)
+ public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQException
{
- return _mms._metaDataMap;
+ getMessages().put(messageId, (AMQQueue)queue);
}
- else
+
+ public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQException
{
- return _metaDataMap;
+ getMessages().remove(messageId);
}
+
+ public void commitTran() throws AMQException
+ {
+ }
+
+ public StoreFuture commitTranAsync() throws AMQException
+ {
+ return new StoreFuture()
+ {
+ public boolean isComplete()
+ {
+ return true;
+ }
+
+ public void waitForCompletion()
+ {
+
+ }
+ };
+ }
+
+ public void abortTran() throws AMQException
+ {
+ }
+ }
+
+
+ @Override
+ public Transaction newTransaction()
+ {
+ return new TestableTransaction();
+ }
+
+ public HashMap<Long, AMQQueue> getMessages()
+ {
+ return _messages;
}
- public ConcurrentMap<Long, List<ContentChunk>> getContentBodyMap()
+ private class TestableStoredMessage implements StoredMessage
{
- if (_mms != null)
+ private final StoredMessage _storedMessage;
+
+ public TestableStoredMessage(StoredMessage storedMessage)
+ {
+ _messageCount.incrementAndGet();
+ _storedMessage = storedMessage;
+ }
+
+ public StorableMessageMetaData getMetaData()
{
- return _mms._contentBodyMap;
+ return _storedMessage.getMetaData();
}
- else
+
+ public long getMessageNumber()
+ {
+ return _storedMessage.getMessageNumber();
+ }
+
+ public void addContent(int offsetInMessage, ByteBuffer src)
+ {
+ _storedMessage.addContent(offsetInMessage, src);
+ }
+
+ public int getContent(int offsetInMessage, ByteBuffer dst)
+ {
+ return _storedMessage.getContent(offsetInMessage, dst);
+ }
+
+ public StoreFuture flushToStore()
+ {
+ return _storedMessage.flushToStore();
+ }
+
+ public void remove()
{
- return _contentBodyMap;
+ _storedMessage.remove();
+ _messageCount.decrementAndGet();
}
}
}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java b/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java
new file mode 100644
index 0000000000..e6fd2172f0
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java
@@ -0,0 +1,238 @@
+package org.apache.qpid.server.subscription;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.logging.LogActor;
+import org.apache.qpid.server.filter.FilterManager;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.queue.QueueEntry.SubscriptionAcquiredState;
+
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class MockSubscription implements Subscription
+{
+
+ private boolean _closed = false;
+ private AMQShortString tag = new AMQShortString("mocktag");
+ private AMQQueue queue = null;
+ private StateListener _listener = null;
+ private AMQQueue.Context _queueContext = null;
+ private State _state = State.ACTIVE;
+ private ArrayList<QueueEntry> messages = new ArrayList<QueueEntry>();
+ private final Lock _stateChangeLock = new ReentrantLock();
+
+ private final QueueEntry.SubscriptionAcquiredState _owningState = new QueueEntry.SubscriptionAcquiredState(this);
+ private final QueueEntry.SubscriptionAssignedState _assignedState = new QueueEntry.SubscriptionAssignedState(this);
+
+
+ private static final AtomicLong idGenerator = new AtomicLong(0);
+ // Create a simple ID that increments for ever new Subscription
+ private final long _subscriptionID = idGenerator.getAndIncrement();
+
+ public void close()
+ {
+ _closed = true;
+ if (_listener != null)
+ {
+ _listener.stateChange(this, _state, State.CLOSED);
+ }
+ _state = State.CLOSED;
+ }
+
+ public boolean filtersMessages()
+ {
+ return false;
+ }
+
+ public AMQChannel getChannel()
+ {
+ return null;
+ }
+
+ public AMQShortString getConsumerTag()
+ {
+ return tag;
+ }
+
+ public long getSubscriptionID()
+ {
+ return _subscriptionID;
+ }
+
+ public AMQQueue.Context getQueueContext()
+ {
+ return _queueContext;
+ }
+
+ public SubscriptionAcquiredState getOwningState()
+ {
+ return _owningState;
+ }
+
+ public QueueEntry.SubscriptionAssignedState getAssignedState()
+ {
+ return _assignedState;
+ }
+
+ public LogActor getLogActor()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isTransient()
+ {
+ return false;
+ }
+
+ public AMQQueue getQueue()
+ {
+ return queue;
+ }
+
+ public void getSendLock()
+ {
+ _stateChangeLock.lock();
+ }
+
+ public boolean hasInterest(QueueEntry msg)
+ {
+ return true;
+ }
+
+ public boolean isActive()
+ {
+ return true;
+ }
+
+ public void confirmAutoClose()
+ {
+
+ }
+
+ public void set(String key, Object value)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public Object get(String key)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isAutoClose()
+ {
+ return false;
+ }
+
+ public boolean isBrowser()
+ {
+ return false;
+ }
+
+ public boolean isClosed()
+ {
+ return _closed;
+ }
+
+ public boolean acquires()
+ {
+ return true;
+ }
+
+ public boolean seesRequeues()
+ {
+ return true;
+ }
+
+ public boolean isSuspended()
+ {
+ return false;
+ }
+
+ public void queueDeleted(AMQQueue queue)
+ {
+ }
+
+ public void releaseSendLock()
+ {
+ _stateChangeLock.unlock();
+ }
+
+ public void resend(QueueEntry entry) throws AMQException
+ {
+ }
+
+ public void onDequeue(QueueEntry queueEntry)
+ {
+ }
+
+ public void restoreCredit(QueueEntry queueEntry)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void send(QueueEntry msg) throws AMQException
+ {
+ messages.add(msg);
+ }
+
+ public void setQueueContext(AMQQueue.Context queueContext)
+ {
+ _queueContext = queueContext;
+ }
+
+ public void setQueue(AMQQueue queue, boolean exclusive)
+ {
+ this.queue = queue;
+ }
+
+ public void setNoLocal(boolean noLocal)
+ {
+ }
+
+ public void setStateListener(StateListener listener)
+ {
+ this._listener = listener;
+ }
+
+ public State getState()
+ {
+ return _state;
+ }
+
+ public boolean wouldSuspend(QueueEntry msg)
+ {
+ return false;
+ }
+
+ public ArrayList<QueueEntry> getMessages()
+ {
+ return messages;
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/subscription/QueueBrowserUsesNoAckTest.java b/java/broker/src/test/java/org/apache/qpid/server/subscription/QueueBrowserUsesNoAckTest.java
new file mode 100644
index 0000000000..d0db4ebd38
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/subscription/QueueBrowserUsesNoAckTest.java
@@ -0,0 +1,77 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.subscription;
+
+import org.apache.qpid.server.util.InternalBrokerBaseCase;
+import org.apache.qpid.server.protocol.InternalTestProtocolSession;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.AMQException;
+
+import java.util.List;
+
+public class QueueBrowserUsesNoAckTest extends InternalBrokerBaseCase
+{
+
+ public void testQueueBrowserUsesNoAck() throws AMQException
+ {
+ int sendMessageCount = 2;
+ int prefetch = 1;
+
+ //Check store is empty
+ checkStoreContents(0);
+
+ //Send required messsages to the queue
+ publishMessages(_session, _channel, sendMessageCount);
+
+ //Ensure they are stored
+ checkStoreContents(sendMessageCount);
+
+ //Check that there are no unacked messages
+ assertEquals("Channel should have no unacked msgs ", 0,
+ _channel.getUnacknowledgedMessageMap().size());
+
+ //Set the prefetch on the session to be less than the sent messages
+ _channel.setCredit(0, prefetch);
+
+ //browse the queue
+ AMQShortString browser = browse(_channel, _queue);
+
+ _queue.deliverAsync();
+
+ //Wait for messages to fill the prefetch
+ _session.awaitDelivery(prefetch);
+
+ //Get those messages
+ List<InternalTestProtocolSession.DeliveryPair> messages =
+ _session.getDelivers(_channel.getChannelId(), browser,
+ prefetch);
+
+ //Ensure we recevied the prefetched messages
+ assertEquals(prefetch, messages.size());
+
+ //Check the process didn't suspend the subscription as this would
+ // indicate we are using the prefetch credit. i.e. using acks not No-Ack
+ assertTrue("The subscription has been suspended",
+ !_channel.getSubscription(browser).getState()
+ .equals(Subscription.State.SUSPENDED));
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/util/InternalBrokerBaseCase.java b/java/broker/src/test/java/org/apache/qpid/server/util/InternalBrokerBaseCase.java
index 67eb180dbf..906c769f9c 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/util/InternalBrokerBaseCase.java
+++ b/java/broker/src/test/java/org/apache/qpid/server/util/InternalBrokerBaseCase.java
@@ -21,42 +21,49 @@
package org.apache.qpid.server.util;
import junit.framework.TestCase;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.registry.IApplicationRegistry;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.AMQQueueFactory;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.common.AMQPFilterTypes;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.configuration.ServerConfiguration;
import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.server.protocol.InternalTestProtocolSession;
-import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.ConsumerTagNotUniqueException;
-import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.AMQQueueFactory;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.registry.IApplicationRegistry;
import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.StoreContext;
import org.apache.qpid.server.store.TestableMemoryMessageStore;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.ContentHeaderBody;
-import org.apache.qpid.framing.BasicContentHeaderProperties;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.util.MockChannel;
+
public class InternalBrokerBaseCase extends TestCase
{
protected IApplicationRegistry _registry;
protected MessageStore _messageStore;
- protected AMQChannel _channel;
+ protected MockChannel _channel;
protected InternalTestProtocolSession _session;
protected VirtualHost _virtualHost;
- protected StoreContext _storeContext = new StoreContext();
protected AMQQueue _queue;
protected AMQShortString QUEUE_NAME;
public void setUp() throws Exception
{
super.setUp();
- _registry = new TestApplicationRegistry();
+ PropertiesConfiguration configuration = new PropertiesConfiguration();
+ configuration.setProperty("virtualhosts.virtualhost.test.store.class", TestableMemoryMessageStore.class.getName());
+ _registry = new TestApplicationRegistry(new ServerConfiguration(configuration));
ApplicationRegistry.initialise(_registry);
_virtualHost = _registry.getVirtualHostRegistry().getVirtualHost("test");
+
_messageStore = _virtualHost.getMessageStore();
QUEUE_NAME = new AMQShortString("test");
@@ -69,24 +76,24 @@ public class InternalBrokerBaseCase extends TestCase
_queue.bind(defaultExchange, QUEUE_NAME, null);
- _session = new InternalTestProtocolSession();
-
- _session.setVirtualHost(_virtualHost);
+ _session = new InternalTestProtocolSession(_virtualHost);
+ CurrentActor.set(_session.getLogActor());
- _channel = new AMQChannel(_session, 1, _messageStore);
+ _channel = new MockChannel(_session, 1, _messageStore);
_session.addChannel(_channel);
}
public void tearDown() throws Exception
{
- ApplicationRegistry.removeAll();
+ CurrentActor.remove();
+ ApplicationRegistry.remove();
super.tearDown();
}
protected void checkStoreContents(int messageCount)
{
- assertEquals("Message header count incorrect in the MetaDataMap", messageCount, ((TestableMemoryMessageStore) _messageStore).getMessageMetaDataMap().size());
+ assertEquals("Message header count incorrect in the MetaDataMap", messageCount, ((TestableMemoryMessageStore) _messageStore).getMessageCount());
//The above publish message is sufficiently small not to fit in the header so no Body is required.
//assertEquals("Message body count incorrect in the ContentBodyMap", messageCount, ((TestableMemoryMessageStore) _messageStore).getContentBodyMap().size());
@@ -103,11 +110,26 @@ public class InternalBrokerBaseCase extends TestCase
e.printStackTrace();
fail(e.getMessage());
}
- catch (ConsumerTagNotUniqueException e)
+
+ //Keep the compiler happy
+ return null;
+ }
+
+ protected AMQShortString browse(AMQChannel channel, AMQQueue queue)
+ {
+ try
+ {
+ FieldTable filters = new FieldTable();
+ filters.put(AMQPFilterTypes.NO_CONSUME.getValue(), true);
+
+ return channel.subscribeToQueue(null, queue, true, filters, false, true);
+ }
+ catch (AMQException e)
{
e.printStackTrace();
fail(e.getMessage());
}
+
//Keep the compiler happy
return null;
}
@@ -144,7 +166,7 @@ public class InternalBrokerBaseCase extends TestCase
for (int count = 0; count < messages; count++)
{
- channel.setPublishFrame(info, _virtualHost.getExchangeRegistry().getExchange(info.getExchange()));
+ channel.setPublishFrame(info, _virtualHost.getExchangeRegistry().getExchange(info.getExchange()));
//Set the body size
ContentHeaderBody _headerBody = new ContentHeaderBody();
diff --git a/java/broker/src/test/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/java/broker/src/test/java/org/apache/qpid/server/util/NullApplicationRegistry.java
new file mode 100644
index 0000000000..3d37412376
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/util/NullApplicationRegistry.java
@@ -0,0 +1,120 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.util;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.configuration.VirtualHostConfiguration;
+import org.apache.qpid.server.logging.RootMessageLoggerImpl;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.TestLogActor;
+import org.apache.qpid.server.logging.actors.BrokerActor;
+import org.apache.qpid.server.logging.rawloggers.Log4jMessageLogger;
+import org.apache.qpid.server.management.NoopManagedObjectRegistry;
+import org.apache.qpid.server.plugins.PluginManager;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.security.access.ACLManager;
+import org.apache.qpid.server.security.access.plugins.AllowAll;
+import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabaseManager;
+import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager;
+import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHostImpl;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Properties;
+import java.util.NoSuchElementException;
+
+public class NullApplicationRegistry extends ApplicationRegistry
+{
+ public NullApplicationRegistry() throws ConfigurationException
+ {
+ super(new ServerConfiguration(new PropertiesConfiguration()));
+ }
+
+ public void initialise(int instanceID) throws Exception
+ {
+ _logger.info("Initialising NullApplicationRegistry");
+
+ _rootMessageLogger = new RootMessageLoggerImpl(_configuration, new Log4jMessageLogger());
+
+ //We should use a Test Actor Here not the Broker Actor
+ CurrentActor.set(new TestLogActor(_rootMessageLogger));
+
+ _configuration.setHousekeepingExpiredMessageCheckPeriod(200);
+
+ Properties users = new Properties();
+
+ users.put("guest", "guest");
+
+ _databaseManager = new PropertiesPrincipalDatabaseManager("default", users);
+
+ _accessManager = new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager, AllowAll.FACTORY);
+
+ _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null);
+
+ _managedObjectRegistry = new NoopManagedObjectRegistry();
+ _virtualHostRegistry = new VirtualHostRegistry(this);
+ PropertiesConfiguration vhostProps = new PropertiesConfiguration();
+ VirtualHostConfiguration hostConfig = new VirtualHostConfiguration("test", vhostProps);
+ VirtualHost dummyHost = new VirtualHostImpl(hostConfig);
+ _virtualHostRegistry.registerVirtualHost(dummyHost);
+ _virtualHostRegistry.setDefaultVirtualHostName("test");
+ _pluginManager = new PluginManager("");
+ _startup = new Exception("NAR");
+
+ }
+ private Exception _startup;
+ public Collection<String> getVirtualHostNames()
+ {
+ String[] hosts = {"test"};
+ return Arrays.asList(hosts);
+ }
+
+ @Override
+ public void close() throws Exception
+ {
+ CurrentActor.set(new BrokerActor(_rootMessageLogger));
+
+ try
+ {
+ super.close();
+ }
+ finally
+ {
+ try
+ {
+ CurrentActor.remove();
+ }
+ catch (NoSuchElementException npe)
+ {
+ _startup.printStackTrace();
+ _startup.printStackTrace(System.err);
+ }
+
+ }
+ }
+}
+
+
+
diff --git a/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java b/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java
index 15449dc613..bb338458f1 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java
+++ b/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -20,23 +20,30 @@
*/
package org.apache.qpid.server.util;
-import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.configuration.VirtualHostConfiguration;
import org.apache.qpid.server.exchange.ExchangeFactory;
import org.apache.qpid.server.exchange.ExchangeRegistry;
import org.apache.qpid.server.management.NoopManagedObjectRegistry;
import org.apache.qpid.server.queue.QueueRegistry;
import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.security.access.ACLPlugin;
+import org.apache.qpid.server.security.access.ACLManager;
import org.apache.qpid.server.security.access.plugins.AllowAll;
import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabaseManager;
import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager;
import org.apache.qpid.server.store.MessageStore;
import org.apache.qpid.server.store.TestableMemoryMessageStore;
-import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHostImpl;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.logging.RootMessageLoggerImpl;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.TestLogActor;
+import org.apache.qpid.server.logging.rawloggers.Log4jMessageLogger;
import java.util.Collection;
-import java.util.HashMap;
import java.util.Properties;
import java.util.Arrays;
@@ -53,20 +60,35 @@ public class TestApplicationRegistry extends ApplicationRegistry
private VirtualHost _vHost;
- public TestApplicationRegistry()
+ private ServerConfiguration _config;
+
+ public TestApplicationRegistry() throws ConfigurationException
{
- super(new MapConfiguration(new HashMap()));
+ super(new ServerConfiguration(new PropertiesConfiguration()));
}
- public void initialise() throws Exception
+ public TestApplicationRegistry(ServerConfiguration config) throws ConfigurationException
{
+ super(config);
+ _config = config;
+ }
+
+ public void initialise(int instanceID) throws Exception
+ {
+ _rootMessageLogger = new RootMessageLoggerImpl(_configuration,
+ new Log4jMessageLogger());
+
+ //Add a Test Actor as a lot of our System Tests reach in to the broker
+ // and manipulate it so the CurrentActor is not set.
+ CurrentActor.set(new TestLogActor(_rootMessageLogger));
+
Properties users = new Properties();
users.put("guest", "guest");
_databaseManager = new PropertiesPrincipalDatabaseManager("default", users);
- _accessManager = new AllowAll();
+ _accessManager = new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager, AllowAll.FACTORY);
_authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null);
@@ -74,9 +96,11 @@ public class TestApplicationRegistry extends ApplicationRegistry
_messageStore = new TestableMemoryMessageStore();
- _virtualHostRegistry = new VirtualHostRegistry();
+ _virtualHostRegistry = new VirtualHostRegistry(this);
- _vHost = new VirtualHost("test", _messageStore);
+ PropertiesConfiguration vhostProps = new PropertiesConfiguration();
+ VirtualHostConfiguration hostConfig = new VirtualHostConfiguration("test", vhostProps);
+ _vHost = new VirtualHostImpl(hostConfig, _messageStore);
_virtualHostRegistry.registerVirtualHost(_vHost);
@@ -84,7 +108,6 @@ public class TestApplicationRegistry extends ApplicationRegistry
_exchangeFactory = _vHost.getExchangeFactory();
_exchangeRegistry = _vHost.getExchangeRegistry();
- _configuration.addProperty("heartbeat.delay", 10 * 60); // 10 minutes
}
public QueueRegistry getQueueRegistry()
@@ -108,7 +131,7 @@ public class TestApplicationRegistry extends ApplicationRegistry
return Arrays.asList(hosts);
}
- public void setAccessManager(ACLPlugin newManager)
+ public void setAccessManager(ACLManager newManager)
{
_accessManager = newManager;
}
@@ -118,6 +141,19 @@ public class TestApplicationRegistry extends ApplicationRegistry
return _messageStore;
}
+ @Override
+ public void close() throws Exception
+ {
+ try
+ {
+ super.close();
+ }
+ finally
+ {
+ CurrentActor.remove();
+ }
+ }
+
}
diff --git a/java/broker/src/test/java/org/apache/qpid/util/MockChannel.java b/java/broker/src/test/java/org/apache/qpid/util/MockChannel.java
new file mode 100644
index 0000000000..9bd1e7c5e1
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/util/MockChannel.java
@@ -0,0 +1,40 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.util;
+
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+
+public class MockChannel extends AMQChannel
+{
+ public MockChannel(AMQProtocolSession session, int channelId, MessageStore messageStore)
+ throws AMQException
+ {
+ super(session, channelId, messageStore);
+ }
+
+
+
+}
diff --git a/java/broker/src/velocity/java/org/apache/qpid/server/logging/GenerateLogMessages.java b/java/broker/src/velocity/java/org/apache/qpid/server/logging/GenerateLogMessages.java
new file mode 100644
index 0000000000..738d54f8f4
--- /dev/null
+++ b/java/broker/src/velocity/java/org/apache/qpid/server/logging/GenerateLogMessages.java
@@ -0,0 +1,470 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+
+package org.apache.qpid.server.logging;
+
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.ResourceBundle;
+
+public class GenerateLogMessages
+{
+ private static String _tmplDir;
+ private String _outputDir;
+
+ public static void main(String[] args)
+ {
+ GenerateLogMessages generator = null;
+ try
+ {
+ generator = new GenerateLogMessages(args);
+ }
+ catch (IllegalAccessException iae)
+ {
+ // This occurs when args does not contain Template and output dirs.
+ System.exit(-1);
+ }
+ catch (Exception e)
+ {
+ //This is thrown by the Velocity Engine initialisation
+ e.printStackTrace();
+ System.exit(-1);
+ }
+
+ try
+ {
+ generator.run();
+ }
+ catch (InvalidTypeException e)
+ {
+ // This occurs when a type other than 'number' appears in the
+ // paramater config {0, number...}
+ System.err.println(e.getMessage());
+ System.exit(-1);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ System.exit(-1);
+ }
+ }
+
+ GenerateLogMessages(String[] args) throws Exception
+ {
+ processArgs(args);
+
+ // We need the template and output dirs set to run.
+ if (_tmplDir == null || _outputDir == null)
+ {
+ showUsage();
+ throw new IllegalAccessException();
+ }
+
+ // Initialise the Velocity Engine, Telling it where our macro lives
+ Properties props = new Properties();
+ props.setProperty("file.resource.loader.path", _tmplDir);
+ Velocity.init(props);
+ }
+
+ private void showUsage()
+ {
+ System.out.println("Broker LogMessageGenerator v.0.0");
+ System.out.println("Usage: GenerateLogMessages: -t tmplDir");
+ System.out.println(" where -t tmplDir: Find templates in tmplDir.");
+ System.out.println(" -o outDir: Use outDir as the output dir.");
+ }
+
+ public void run() throws InvalidTypeException, Exception
+ {
+ /* lets make a Context and put data into it */
+ createMessageClass("Broker", "BRK");
+ createMessageClass("ManagementConsole", "MNG");
+ createMessageClass("VirtualHost", "VHT");
+ createMessageClass("MessageStore", "MST");
+ createMessageClass("ConfigStore", "CFG");
+ createMessageClass("TransactionLog", "TXN");
+ createMessageClass("Connection", "CON");
+ createMessageClass("Channel", "CHN");
+ createMessageClass("Queue", "QUE");
+ createMessageClass("Exchange", "EXH");
+ createMessageClass("Binding", "BND");
+ createMessageClass("Subscription", "SUB");
+ }
+
+ /**
+ * Process the args for:
+ * -t|T value for the template location
+ * -o|O value for the output directory
+ *
+ * @param args the commandline arguments
+ */
+ private void processArgs(String[] args)
+ {
+ // Crude but simple...
+ for (int i = 0; i < args.length; i++)
+ {
+ String arg = args[i];
+ if (arg.charAt(0) == '-')
+ {
+ switch (arg.charAt(1))
+ {
+ case 'o':
+ case 'O':
+ if (++i < args.length)
+ {
+ _outputDir = args[i];
+ }
+ break;
+ case 't':
+ case 'T':
+ if (++i < args.length)
+ {
+ _tmplDir = args[i];
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * This is the main method that generates the _Messages.java file.
+ * The class is generated by extracting the list of messges from the
+ * available LogMessages Resource.
+ *
+ * The extraction is done based on typeIdentifier which is a 3-digit prefix
+ * on the messages e.g. BRK for Broker.
+ *
+ * @param className The name for the file '_className_Messages.java'
+ * @param typeIdentifier The 3 digit identifier
+ * @throws InvalidTypeException when an unknown parameter type is used in the properties file
+ * @throws Exception thrown by velocity if there is an error
+ */
+ private void createMessageClass(String className, String typeIdentifier)
+ throws InvalidTypeException, Exception
+ {
+ VelocityContext context = new VelocityContext();
+
+ // Get the Data for this class and typeIdentifier
+ HashMap<String, Object> typeData = prepareType(className, typeIdentifier);
+
+ // Store this data in the context for the macro to access
+ context.put("type", typeData);
+
+ // Create the file writer to put the finished file in
+ FileWriter output = new FileWriter(_outputDir + File.separator + className + "Messages.java");
+
+ // Run Velocity to create the output file.
+ // Fix the default file encoding to 'ISO-8859-1' rather than let
+ // Velocity fix it. This is the encoding format for the macro.
+ Velocity.mergeTemplate("LogMessages.vm", "ISO-8859-1", context, output);
+
+ //Close our file.
+ output.flush();
+ output.close();
+ }
+
+ /**
+ * This method does the processing and preparation of the data to be added
+ * to the Velocity context so that the macro can access and process the data
+ *
+ * The given messageKey (e.g. 'BRK') uses a 3-digit code used to match
+ * the property key from the loaded 'LogMessages' ResourceBundle.
+ *
+ * This gives a list of messages which are to be associated with the given
+ * messageName (e.g. 'Broker')
+ *
+ * Each of the messages in the list are then processed to identify how many
+ * parameters the MessageFormat call is expecting. These parameters are
+ * identified by braces ('{}') so a quick count of these can then be used
+ * to create a defined parameter list.
+ *
+ * Rather than defaulting all parameters to String a check is performed to
+ * see if a 'number' value has been requested. e.g. {0. number}
+ * {@see MessageFormat}. If a parameter has a 'number' type then the
+ * parameter will be defined as an Number value. This allows for better
+ * type checking during compilation whilst allowing the log message to
+ * maintain formatting controls.
+ *
+ * OPTIONS
+ *
+ * The returned hashMap contains the following structured data:
+ *
+ * - name - ClassName ('Broker')
+ * - list[logEntryData] - methodName ('BRK_1001')
+ * - name ('BRK-1001')
+ * - format ('Startup : Version: {0} Build: {1}')
+ * - parameters (list)
+ * - type ('String'|'Number')
+ * - name ('param1')
+ * - options (list)
+ * - name ('opt1')
+ * - value ('AutoDelete')
+ *
+ * @param messsageName the name to give the Class e.g. 'Broker'
+ * @param messageKey the 3-digit key to extract the messages e.g. 'BRK'
+ * @return A HashMap with data for the macro
+ * @throws InvalidTypeException when an unknown parameter type is used in the properties file
+ */
+ private HashMap<String, Object> prepareType(String messsageName, String messageKey) throws InvalidTypeException
+ {
+ // Load the LogMessages Resource Bundle
+ ResourceBundle _messages = ResourceBundle.getBundle("org.apache.qpid.server.logging.messages.LogMessages", Locale.US);
+
+ Enumeration<String> messageKeys = _messages.getKeys();
+
+ //Create the return map
+ HashMap<String, Object> messageTypeData = new HashMap<String, Object>();
+ // Store the name to give to this Class <name>Messages.java
+ messageTypeData.put("name", messsageName);
+
+ // Prepare the list of log messages
+ List<HashMap> logMessageList = new LinkedList<HashMap>();
+ messageTypeData.put("list", logMessageList);
+
+ //Process each of the properties
+ while (messageKeys.hasMoreElements())
+ {
+ HashMap<String, Object> logEntryData = new HashMap<String, Object>();
+
+ //Add MessageName to amp
+ String message = messageKeys.nextElement();
+
+ // Process the log message if it matches the specified key e.g.'BRK'
+ if (message.startsWith(messageKey))
+ {
+ // Method names can't have a '-' in them so lets make it '_'
+ // e.g. BRK-STARTUP -> BRK_STARTUP
+ logEntryData.put("methodName", message.replace('-', '_'));
+ // Store the real name so we can use that in the actual log.
+ logEntryData.put("name", message);
+
+ //Retrieve the actual log message string.
+ String logMessage = _messages.getString(message);
+
+ // Store the value of the property so we can add it to the
+ // Javadoc of the method.
+ logEntryData.put("format", logMessage);
+
+ // Add the parameters for this message
+ logEntryData.put("parameters", extractParameters(logMessage));
+
+ //Add the options for this messagse
+ logEntryData.put("options", extractOptions(logMessage));
+
+ //Add this entry to the list for this class
+ logMessageList.add(logEntryData);
+ }
+ }
+
+ return messageTypeData;
+ }
+
+ /**
+ * This method is responsible for extracting the options form the given log
+ * message and providing a HashMap with the expected data:
+ * - options (list)
+ * - name ('opt1')
+ * - value ('AutoDelete')
+ *
+ * The options list that this method provides must contain HashMaps that
+ * have two entries. A 'name' and a 'value' these strings are important as
+ * they are used in LogMessage.vm to extract the stored String during
+ * processing of the template.
+ *
+ * The 'name' is a unique string that is used to name the boolean parameter
+ * and refer to it later in the method body.
+ *
+ * The 'value' is used to provide documentation in the generated class to
+ * aid readability.
+ *
+ * @param logMessage the message from the properties file
+ * @return list of option data
+ */
+ private List<HashMap<String, String>> extractOptions(String logMessage)
+ {
+ // Split the string on the start brace '{' this will give us the
+ // details for each parameter that this message contains.
+ // NOTE: Simply splitting on '[' prevents the use of nested options.
+ // Currently there is no demand for nested options
+ String[] optionString = logMessage.split("\\[");
+ // Taking an example of:
+ // 'Text {n,type,format} [option] text {m} [option with param{p}] more'
+ // This would give us:
+ // 0 - Text {n,type,format}
+ // 1 - option] text {m}
+ // 2 - option with param{p}] more
+
+ // Create the parameter list for this item
+ List<HashMap<String, String>> options = new LinkedList<HashMap<String, String>>();
+
+ // Check that we have some parameters to process
+ // Skip 0 as that will not be the first entry
+ // Text {n,type,format} [option] text {m} [option with param{p}] more
+ if (optionString.length > 1)
+ {
+ for (int index = 1; index < optionString.length; index++)
+ {
+ // Use a HashMap to store the type,name of the parameter
+ // for easy retrieval in the macro template
+ HashMap<String, String> option = new HashMap<String, String>();
+
+ // Locate the end of the Option
+ // NOTE: it is this simple matching on the first ']' that
+ // prevents the nesting of options.
+ // Currently there is no demand for nested options
+ int end = optionString[index].indexOf("]");
+
+ // The parameter type
+ String value = optionString[index].substring(0, end);
+
+ // Simply name the parameters by index.
+ option.put("name", "opt" + index);
+
+ //Store the value e.g. AutoDelete
+ // We trim as we don't need to include any whitespace that is
+ // used for formating. This is only used to aid readability of
+ // of the generated code.
+ option.put("value", value.trim());
+
+ options.add(option);
+ }
+ }
+
+ return options;
+ }
+
+ /**
+ * This method is responsible for extract the parameters that are requried
+ * for this log message. The data is returned in a HashMap that has the
+ * following structure:
+ * - parameters (list)
+ * - type ('String'|'Number')
+ * - name ('param1')
+ *
+ * The parameters list that is provided must contain HashMaps that have the
+ * two named entries. A 'type' and a 'name' these strings are importans as
+ * they are used in LogMessage.vm to extract and the stored String during
+ * processing of the template
+ *
+ * The 'type' and 'name' values are used to populate the method signature.
+ * This is what gives us the compile time validation of log messages.
+ *
+ * The 'name' must be unique as there may be many parameters. The value is
+ * also used in the method body to pass the values through to the
+ * MessageFormat class for formating the log message.
+ *
+ * @param logMessage the message from the properties file
+ * @return list of option data
+ * @throws InvalidTypeException if the FormatType is specified and is not 'number'
+ */
+ private List<HashMap<String, String>> extractParameters(String logMessage)
+ throws InvalidTypeException
+ {
+ // Split the string on the start brace '{' this will give us the
+ // details for each parameter that this message contains.
+ String[] parametersString = logMessage.split("\\{");
+ // Taking an example of 'Text {n[,type]} text {m} more text {p}'
+ // This would give us:
+ // 0 - Text
+ // 1 - n[,type]} text
+ // 2 - m} more text
+ // 3 - p}
+
+ // Create the parameter list for this item
+ List<HashMap<String, String>> parameters = new LinkedList<HashMap<String, String>>();
+
+ // Check that we have some parameters to process
+ // Skip 0 as that will not be the first entry
+ // Text {n[,type]} text {m} more text {p}
+ if (parametersString.length > 1)
+ {
+ for (int index = 1; index < parametersString.length; index++)
+ {
+ // Use a HashMap to store the type,name of the parameter
+ // for easy retrieval in the macro template
+ HashMap<String, String> parameter = new HashMap<String, String>();
+
+ // Check for any properties of the parameter :
+ // e.g. {0} vs {0,number} vs {0,number,xxxx}
+ int typeIndex = parametersString[index].indexOf(",");
+
+
+ // The parameter type
+ String type;
+
+ //Be default all types are Strings
+ if (typeIndex == -1)
+ {
+ type = "String";
+ }
+ else
+ {
+ //Check string ',....}' for existence of number
+ // to identify this parameter as an integer
+ // This allows for a style value to be present
+ // Only check the text inside the braces '{}'
+ int typeIndexEnd = parametersString[index].indexOf("}", typeIndex);
+ String typeString = parametersString[index].substring(typeIndex, typeIndexEnd);
+ if (typeString.contains("number"))
+ {
+ type = "Number";
+ }
+ else
+ {
+ throw new InvalidTypeException("Invalid type(" + typeString + ") index (" + parameter.size() + ") in message:" + logMessage);
+ }
+
+ }
+
+ //Store the data
+ parameter.put("type", type);
+ // Simply name the parameters by index.
+ parameter.put("name", "param" + index);
+
+ parameters.add(parameter);
+ }
+ }
+
+ return parameters;
+ }
+
+ /**
+ * Just a inner exception to be able to identify when a type that is not
+ * 'number' occurs in the message parameter text.
+ */
+ private class InvalidTypeException extends Throwable
+ {
+ public InvalidTypeException(String message)
+ {
+ super(message);
+ }
+ }
+}
diff --git a/java/broker/src/velocity/templates/org/apache/qpid/server/logging/messages/LogMessages.vm b/java/broker/src/velocity/templates/org/apache/qpid/server/logging/messages/LogMessages.vm
new file mode 100644
index 0000000000..4eda0ffb19
--- /dev/null
+++ b/java/broker/src/velocity/templates/org/apache/qpid/server/logging/messages/LogMessages.vm
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.logging.messages;
+
+import org.apache.qpid.server.logging.LogMessage;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+/**
+ * Generated Using GeneratedLogMessages and LogMessages.vm
+ *
+ * This file is based on the content of LogMessages.properties
+ *
+ * It is generated so that we can provide compile time validation of the
+ * message parameters.
+ *
+ * DO NOT EDIT DIRECTLY THIS FILE IS GENERATED.
+ *
+ */
+public class ${type.name}Messages
+{
+ static ResourceBundle _messages;
+ static MessageFormat _formatter;
+
+ static
+ {
+ reload();
+ }
+
+ public static void reload()
+ {
+ Locale currentLocale;
+
+ if (ApplicationRegistry.isConfigured())
+ {
+ currentLocale = ApplicationRegistry.getInstance().getConfiguration().getLocale();
+ }
+ else
+ {
+ currentLocale = Locale.getDefault();
+ }
+
+ _messages = ResourceBundle.getBundle("org.apache.qpid.server.logging.messages.LogMessages",
+ currentLocale);
+
+ _formatter = new MessageFormat("");
+ _formatter.setLocale(currentLocale);
+ }
+
+
+##
+## The list stored under key 'list' in the 'type' HashMap contains all the
+## log messages that this class should contain. So for each entry in the list
+## this template will create a new log method.
+##
+#foreach( $message in ${type.list} )
+ /**
+ * Log a ${type.name} message of the Format:
+ * <pre>${message.format}</pre>
+ * Optional values are contained in [square brackets] and are numbered
+ * sequentially in the method call.
+ *
+ */
+## There is a lot in the method header here. To make it more readable/understandable
+## This is the same text laid out to be easier to read:
+## public static LogMessage ${message.methodName} (
+## #foreach($parameter in ${message.parameters})
+## ${parameter.type} ${parameter.name}
+## #if (${velocityCount} != ${message.parameters.size()} )
+## ,
+## #end
+## #end
+## #if(${message.parameters.size()} > 0 && ${message.options.size()} > 0)
+## ,
+## #end
+## #foreach($option in ${message.options})
+## boolean ${option.name}
+## #if (${velocityCount} != ${message.options.size()} )
+## ,
+## #end
+## #end
+## )
+##
+## What is going on is that we set the method name based on the HashMap lookup
+## for 'methodName' Then for each entry(another HashMap) in the list stored
+## in the HashMap under 'parameters' build the argument list of from the 'type'
+## and 'name' values. Ensuring that we add a ', ' between each entry.
+##
+## However, check that we are not at the last entry of the list as we don't
+## want to add ', ' at then end.
+##
+## Before we go on to the options we perform a check to see if we had any
+## parameters. If we did and we have options to add then we add ', ' to keep
+## the syntax correct.
+##
+## We then go on to the options that are again retrieved from the top HashMap
+## with key 'options'. For each option a boolean argument is created and the
+## name is retrieved from the option HashMap with key 'name'
+##
+ public static LogMessage ${message.methodName}(#foreach($parameter in ${message.parameters})${parameter.type} ${parameter.name}#if (${velocityCount} != ${message.parameters.size()} ), #end
+#end#if(${message.parameters.size()} > 0 && ${message.options.size()} > 0), #end#foreach($option in ${message.options})boolean ${option.name}#if (${velocityCount} != ${message.options.size()} ), #end#end)
+ {
+ String rawMessage = _messages.getString("${message.name}");
+## If we have some options then we need to build the message based
+## on those values so only provide that logic if we need it.
+#if(${message.options.size()} > 0)
+ StringBuffer msg = new StringBuffer();
+
+ // Split the formatted message up on the option values so we can
+ // rebuild the message based on the configured options.
+ String[] parts = rawMessage.split("\\[");
+ msg.append(parts[0]);
+
+ int end;
+ if (parts.length > 1)
+ {
+## For Each Optional value check if it has been enabled and then
+## append it to the log.
+#foreach($option in ${message.options})
+
+ // Add Option : ${option.value}
+ end = parts[${velocityCount}].indexOf(']');
+ if (${option.name})
+ {
+ msg.append(parts[${velocityCount}].substring(0, end));
+ }
+
+ // Use 'end + 1' to remove the ']' from the output
+ msg.append(parts[${velocityCount}].substring(end + 1));
+#end
+ }
+
+ rawMessage = msg.toString();
+#end
+
+##
+## If we don't have any parameters then we don't need the overhead of using the
+## message formatter so we can just set our return message to the retreived
+## fixed string.
+## So we don't need to update the _formatter with the new pattern.
+##
+## Here we setup rawMessage to be the formatted message ready for direct return
+## with the message.name or further processing to remove options.
+##
+#if(${message.parameters.size()} > 0)
+ final Object[] messageArguments = {#foreach($parameter in ${message.parameters})${parameter.name}#if (${velocityCount} != ${message.parameters.size()} ), #end#end};
+ _formatter.applyPattern(rawMessage);
+
+ final String message = _formatter.format(messageArguments);
+#else
+## If we have no parameters then we can skip the formatter and set the log
+ final String message = rawMessage;
+#end
+
+ return new LogMessage()
+ {
+ public String toString()
+ {
+ return message;
+ }
+ };
+ }
+
+#end
+
+}
diff --git a/java/build.deps b/java/build.deps
index 5ba09dc468..2c24d9ea17 100644
--- a/java/build.deps
+++ b/java/build.deps
@@ -1,15 +1,23 @@
backport-util-concurrent=lib/backport-util-concurrent-2.2.jar
+commons-beanutils-core=lib/commons-beanutils-core-1.8.0.jar
commons-cli=lib/commons-cli-1.0.jar
commons-codec=lib/commons-codec-1.3.jar
commons-collections=lib/commons-collections-3.2.jar
-commons-configuration=lib/commons-configuration-1.2.jar
+commons-configuration=lib/commons-configuration-1.6.jar
+commons-digester=lib/commons-digester-1.8.1.jar
commons-lang=lib/commons-lang-2.2.jar
commons-logging=lib/commons-logging-1.0.4.jar
+commons-pool=lib/commons-pool-1.4.jar
+
+derby-db=lib/derby-10.3.2.1.jar
geronimo-jms=lib/geronimo-jms_1.1_spec-1.0.jar
junit=lib/junit-3.8.1.jar
+junit4=lib/junit-4.4.jar
+
+jline=lib/jline-0.9.94.jar
log4j=lib/log4j-1.2.12.jar
@@ -21,20 +29,64 @@ slf4j-log4j=lib/slf4j-log4j12-1.4.0.jar
xalan=lib/xalan-2.7.0.jar
+muse-core=lib/muse-core-2.2.0.jar
+muse-platform-mini=lib/muse-platform-mini-2.2.0.jar
+muse-util=lib/muse-util-2.2.0.jar
+muse-util-qname=lib/muse-util-qname-2.2.0.jar
+muse-util-xml=lib/muse-util-xml-2.2.0.jar
+muse-wsa-soap=lib/muse-wsa-soap-2.2.0.jar
+muse-wsdm-muws-adv-api=lib/muse-wsdm-muws-adv-api-2.2.0.jar
+muse-wsdm-muws-adv-impl=lib/muse-wsdm-muws-adv-impl-2.2.0.jar
+muse-wsdm-muws-api=lib/muse-wsdm-muws-api-2.2.0.jar
+muse-wsdm-muws-impl=lib/muse-wsdm-muws-impl-2.2.0.jar
+muse-wsdm-wef-api=lib/muse-wsdm-wef-api-2.2.0.jar
+muse-wsdm-wef-impl=lib/muse-wsdm-wef-impl-2.2.0.jar
+muse-wsn-api=lib/muse-wsn-api-2.2.0.jar
+muse-wsn-impl=lib/muse-wsn-impl-2.2.0.jar
+muse-wsrf-api=lib/muse-wsrf-api-2.2.0.jar
+muse-wsrf-impl=lib/muse-wsrf-impl-2.2.0.jar
+muse-wsrf-rmd=lib/muse-wsrf-rmd-2.2.0.jar
+muse-wsx-api=lib/muse-wsx-api-2.2.0.jar
+muse-wsx-impl=lib/muse-wsx-impl-2.2.0.jar
+wsdl4j=lib/wsdl4j-1.6.1.jar
+xercesImpl=lib/xercesImpl-2.8.1.jar
+xml-apis=lib/xml-apis-1.3.03.jar
+javassist=lib/javassist.jar
+jetty=lib/jetty-6.1.14.jar
+jetty-util=lib/jetty-util-6.1.14.jar
+jetty-bootstrap=lib/start.jar
+jms=lib/jms-1.1.jar
+jsp-api=lib/jsp-api-2.1.jar
+jsp-impl=lib/jsp-2.1.jar
+core-lib=lib/core-3.1.1.jar
+
+muse.libs = ${muse-core} ${muse-platform-mini} ${muse-util} ${muse-util-qname} \
+${muse-util-xml} ${muse-wsa-soap} ${muse-wsdm-muws-adv-api} ${muse-wsdm-muws-adv-impl} \
+${muse-wsdm-muws-api} ${muse-wsdm-muws-impl} ${muse-wsdm-wef-api} ${muse-wsdm-wef-impl} \
+${muse-wsn-api} ${muse-wsn-impl} ${muse-wsrf-api} ${muse-wsrf-impl} ${muse-wsrf-rmd} \
+${muse-wsx-api} ${muse-wsx-impl} ${wsdl4j} ${xercesImpl} ${xml-apis} ${jetty} ${jetty-util} ${jetty-bootstrap}
+
+jsp.libs = ${jsp-api} ${jsp-impl} ${core-lib}
+
osgi-core=lib/org.osgi.core-1.0.0.jar
felix-framework=lib/org.apache.felix.framework-1.0.0.jar
+geronimo-servlet=lib/geronimo-servlet_2.5_spec-1.2.jar
felix.libs=${osgi-core} ${felix-framework}
common.libs=${slf4j-api} ${backport-util-concurrent} ${mina-core} \
- ${mina-filter-ssl} ${commons-codec} ${commons-lang} ${commons-collections} \
+ ${mina-filter-ssl} ${commons-beanutils-core} ${commons-digester} ${commons-codec} ${commons-lang} ${commons-collections} \
${commons-configuration}
-client.libs=${common.libs} ${geronimo-jms} ${junit}
+client.libs=${common.libs} ${geronimo-jms}
tools.libs=${client.libs}
broker.libs=${common.libs} ${commons-cli} ${commons-logging} ${log4j} \
- ${slf4j-log4j} ${xalan} ${felix.libs}
+ ${slf4j-log4j} ${xalan} ${felix.libs} ${derby-db}
+
+broker-plugins.libs=${common.libs} ${felix.libs} ${log4j}
+management-client.libs=${jsp.libs} ${log4j} ${slf4j-log4j} ${slf4j-api} ${commons-pool} ${geronimo-servlet} ${muse.libs} ${javassist} ${xalan} ${mina-core} ${mina-filter-ssl}
-broker-plugins.libs=${common.libs} ${felix.libs}
+management-agent.libs=${client.libs} ${commons-logging} ${geronimo-jms}
+management-console.libs=${client.libs} ${commons-logging} ${geronimo-jms}
junit-toolkit.libs=${log4j} ${junit} ${slf4j-api}
test.libs=${slf4j-log4j} ${junit-toolkit.libs}
@@ -43,37 +95,82 @@ perftests.libs=${systests.libs}
integrationtests.libs=${systests.libs}
client-example.libs=${client.libs}
-testkit.libs=${client.libs}
-
-ibm-icu=lib/com.ibm.icu-3.4.4.jar
-ecl-core-jface=lib/org.eclipse.jface-3.2.0.jar
-ecl-core-commands=lib/org.eclipse.core.commands-3.2.0.jar
-ecl-core-contenttype=lib/org.eclipse.core.contenttype-3.2.0.jar
-ecl-core-expressions=lib/org.eclipse.core.expressions-3.2.0.jar
-ecl-core-jobs=lib/org.eclipse.core.jobs-3.2.0.jar
-ecl-core-runtime=lib/org.eclipse.core.runtime-3.2.0.jar
-ecl-core-runtime-compat-auth=lib/org.eclipse.core.runtime.compatibility.auth-3.2.0.jar
-ecl-core-runtime-compat-registry=lib/org.eclipse.core.runtime.compatibility.registry-3.2.0.jar
-ecl-equinox-common=lib/org.eclipse.equinox.common-3.2.0.jar
-ecl-equinox-prefs=lib/org.eclipse.equinox.preferences-3.2.0.jar
-ecl-equinox-registry=lib/org.eclipse.equinox.registry-3.2.0.jar
-ecl-help=lib/org.eclipse.help-3.2.0.jar
-ecl-osgi=lib/org.eclipse.osgi-3.2.0.jar
-ecl-swt=lib/org.eclipse.swt-3.2.0.jar
-ecl-swt-win32=lib/org.eclipse.swt.win32.win32.x86-3.2.0.jar
-ecl-ui=lib/org.eclipse.ui-3.2.0.jar
-ecl-ui-forms=lib/org.eclipse.ui.forms-3.2.0.jar
-ecl-ui-workbench=lib/org.eclipse.ui.workbench-3.2.1.jar
-
-management-eclipse-plugin.libs=${commons-codec} ${ibm-icu} ${ecl-core-jface} \
- ${ecl-core-commands} ${ecl-core-contenttype} ${ecl-core-expressions} \
- ${ecl-core-jobs} ${ecl-core-runtime} ${ecl-core-runtime-compat-auth} \
- ${ecl-core-runtime-compat-registry} ${ecl-equinox-common} \
- ${ecl-equinox-prefs} ${ecl-equinox-registry} ${ecl-help} ${ecl-osgi} \
- ${ecl-swt} ${ecl-swt-win32} ${ecl-ui} ${ecl-ui-forms} ${ecl-ui-workbench}
+testkit.libs=${client.libs} ${log4j}
+
+ibm-icu=lib/com.ibm.icu_3.8.1.v20080530.jar
+ecl-core-jface=lib/org.eclipse.jface_3.4.1.M20080827-2000.jar
+ecl-core-jface-databinding=lib/org.eclipse.jface.databinding_1.2.1.M20080827-0800a.jar
+ecl-core-commands=lib/org.eclipse.core.commands_3.4.0.I20080509-2000.jar
+ecl-core-contenttype=lib/org.eclipse.core.contenttype_3.3.0.v20080604-1400.jar
+ecl-core-databinding=lib/org.eclipse.core.databinding_1.1.1.M20080827-0800b.jar
+ecl-core-expressions=lib/org.eclipse.core.expressions_3.4.0.v20080603-2000.jar
+ecl-core-jobs=lib/org.eclipse.core.jobs_3.4.0.v20080512.jar
+ecl-core-runtime=lib/org.eclipse.core.runtime_3.4.0.v20080512.jar
+ecl-core-runtime-compat-registry=lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/**
+ecl-equinox-app=lib/org.eclipse.equinox.app_1.1.0.v20080421-2006.jar
+ecl-equinox-common=lib/org.eclipse.equinox.common_3.4.0.v20080421-2006.jar
+ecl-equinox-launcher=lib/org.eclipse.equinox.launcher_1.0.101.R34x_v20080819.jar
+ecl-equinox-prefs=lib/org.eclipse.equinox.preferences_3.2.201.R34x_v20080709.jar
+ecl-equinox-registry=lib/org.eclipse.equinox.registry_3.4.0.v20080516-0950.jar
+ecl-help=lib/org.eclipse.help_3.3.101.v20080702_34x.jar
+ecl-osgi=lib/org.eclipse.osgi_3.4.2.R34x_v20080826-1230.jar
+ecl-swt=lib/org.eclipse.swt_3.4.1.v3449c.jar
+ecl-ui=lib/org.eclipse.ui_3.4.1.M20080910-0800.jar
+ecl-ui-forms=lib/org.eclipse.ui.forms_3.3.101.v20080708_34x.jar
+ecl-ui-workbench=lib/org.eclipse.ui.workbench_3.4.1.M20080827-0800a.jar
+apache-commons-codec=lib/org.apache.commons.codec_1.3.0.v20080530-1600.jar
+
+ecl-swt-win32-win32-x86=lib/org.eclipse.swt.win32.win32.x86_3.4.1.v3449c.jar
+ecl-equinox-launcher-win32-win32-x86=lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/**
+ecl-swt-linux-gtk-x86=lib/org.eclipse.swt.gtk.linux.x86_3.4.1.v3449c.jar
+ecl-equinox-launcher-linux-gtk-x86=lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/**
+ecl-swt-linux-gtk-x86_64=lib/org.eclipse.swt.gtk.linux.x86_64_3.4.1.v3449c.jar
+ecl-equinox-launcher-linux-gtk-x86_64=lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/**
+ecl-swt-macosx-carbon=lib/org.eclipse.swt.carbon.macosx_3.4.1.v3449c.jar
+ecl-equinox-launcher-macosx-carbon=lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/**
+ecl-swt-solaris-gtk-sparc=lib/org.eclipse.swt.gtk.solaris.sparc_3.4.1.v3449c.jar
+ecl-equinox-launcher-solaris-gtk-sparc=lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/**
+
+management-common.libs=
+
+management-eclipse-plugin-win32-win32-x86.libs=${management-eclipse-plugin.core-libs} \
+ ${ecl-swt-win32-win32-x86} ${ecl-equinox-launcher-win32-win32-x86}
+management-eclipse-plugin-linux-gtk-x86.libs=${management-eclipse-plugin.core-libs} \
+ ${ecl-swt-linux-gtk-x86} ${ecl-equinox-launcher-linux-gtk-x86}
+management-eclipse-plugin-linux-gtk-x86_64.libs=${management-eclipse-plugin.core-libs} \
+ ${ecl-swt-linux-gtk-x86_64} ${ecl-equinox-launcher-linux-gtk-x86_64}
+management-eclipse-plugin-macosx.libs=${management-eclipse-plugin.core-libs} \
+ ${ecl-swt-macosx-carbon} ${ecl-equinox-launcher-macosx-carbon}
+management-eclipse-plugin-solaris-gtk-sparc.libs=${management-eclipse-plugin.core-libs} \
+ ${ecl-swt-solaris-gtk-sparc} ${ecl-equinox-launcher-solaris-gtk-sparc}
+
+management-eclipse-plugin.core-libs=${ibm-icu} ${ecl-core-jface} ${ecl-core-jface-databinding} \
+ ${ecl-core-commands} ${ecl-core-contenttype} ${ecl-core-databinding} ${ecl-core-expressions} \
+ ${ecl-core-jobs} ${ecl-core-runtime} ${ecl-core-runtime-compat-registry} ${ecl-equinox-app} \
+ ${ecl-equinox-common} ${ecl-equinox-launcher} ${ecl-equinox-prefs} ${ecl-equinox-registry} \
+ ${ecl-help} ${ecl-osgi} ${ecl-swt} ${ecl-ui} ${ecl-ui-forms} ${ecl-ui-workbench} ${apache-commons-codec}
+
+management-eclipse-plugin.platform-libs=${ecl-equinox-launcher-win32-win32-x86} \
+ ${ecl-equinox-launcher-linux-gtk-x86} ${ecl-equinox-launcher-macosx-carbon} \
+ ${ecl-swt-win32-win32-x86} ${ecl-swt-linux-gtk-x86} ${ecl-swt-macosx-carbon} \
+ ${ecl-swt-linux-gtk-x86_64} ${ecl-equinox-launcher-linux-gtk-x86_64} \
+ ${ecl-swt-solaris-gtk-sparc} ${ecl-equinox-launcher-solaris-gtk-sparc}
+
+management-eclipse-plugin.libs=${management-eclipse-plugin.core-libs} ${management-eclipse-plugin.platform-libs}
+
+
+management-tools-qpid-cli.libs=${common.libs} ${jline}
common.test.libs=${test.libs}
broker.test.libs=${test.libs}
client.test.libs=${broker.libs} ${test.libs}
+client-example.test.libs=${test.libs}
tools.test.libs=${client.test.libs}
+testkit.test.libs=${test.libs}
+management-client.test.libs=${muse.libs} ${test.libs} ${log4j} ${javassist} ${geronimo-servlet} ${commons-pool}
+management-console.test.libs=${junit4} ${slf4j-log4j} ${log4j} ${client.libs}
+management-agent.test.libs=${junit}
management-eclipse-plugin.test.libs=${systests.libs}
+broker-plugins.test.libs=${test.libs}
+management-tools-qpid-cli.test.libs=${junit4} ${slf4j-log4j} ${log4j} ${client.libs}
+management-common.test.libs=${test.libs}
diff --git a/java/build.xml b/java/build.xml
index 375fbbac94..440cdf21a3 100644
--- a/java/build.xml
+++ b/java/build.xml
@@ -22,25 +22,29 @@
<import file="common.xml"/>
- <property name="modules.core" value="junit-toolkit common broker client tools"/>
+ <property name="modules.core" value="junit-toolkit common management/common broker client tools"/>
<property name="modules.examples" value="client/example"/>
<property name="modules.tests" value="systests perftests integrationtests testkit"/>
- <property name="modules.management" value="management/eclipse-plugin"/>
+ <property name="modules.management" value="management/client management/eclipse-plugin management/agent management/console"/>
<property name="modules.plugin" value="broker-plugins"/>
+ <property name="modules.management.tools" value="management/tools/qpid-cli"/>
+ <property name="modules" value="${modules.core}
+ ${modules.plugin} ${modules.examples}
+ ${modules.management} ${modules.management.tools} ${modules.tests}"/>
- <property name="modules" value="${modules.core} ${modules.plugin} ${modules.examples} ${modules.tests} ${modules.management}"/>
-
- <property name="qpid.jar" location="${build.lib}/qpid-incubating.jar"/>
+ <property name="qpid.jar" location="${build.lib}/qpid-all.jar"/>
<basename property="qpid.jar.name" file="${qpid.jar}"/>
+ <property name="resources" value="${project.root}/resources"/>
+
<map property="release.excludes" value="${modules}">
<globmapper from="*" to="*/\*\*"/>
</map>
- <property name="release.zip" location="${release}/${project.namever}.zip"/>
- <property name="release.tar" location="${release}/${project.namever}.tar"/>
- <property name="release.tgz" location="${release}/${project.namever}.tar.gz"/>
- <property name="release.bz2" location="${release}/${project.namever}.tar.bz2"/>
+ <property name="release.zip" location="${release}/${project.namever}-java.zip"/>
+ <property name="release.tar" location="${release}/${project.namever}-java.tar"/>
+ <property name="release.tgz" location="${release}/${project.namever}-java.tar.gz"/>
+ <property name="release.bz2" location="${release}/${project.namever}-java.tar.bz2"/>
<macrodef name="iterate">
<attribute name="target"/>
@@ -54,6 +58,10 @@
</sequential>
</macrodef>
+ <target name="pom" description="generate poms">
+ <iterate target="pom"/>
+ </target>
+
<target name="compile" description="compile sources">
<iterate target="compile"/>
</target>
@@ -94,6 +102,15 @@
<iterate target="doc"/>
</target>
+ <target name="bundle" description="create OSGi bundles">
+ <iterate target="bundle"/>
+ </target>
+
+ <target name="release-bin" description="build a binary release artifact" depends="build,bundle">
+ <iterate target="release-bin"/>
+ </target>
+
+
<target name="check-manifest">
<uptodate property="manifest.done" targetfile="${qpid.jar}">
<srcfiles dir="${build.lib}" includes="**/*.jar" excludes="**/${qpid.jar.name}"/>
@@ -116,6 +133,7 @@
<manifest>
<attribute name="Class-Path" value="${qpid.jar.classpath}"/>
</manifest>
+ <metainf dir="${project.root}/resources/"/>
</jar>
<touch file="${qpid.jar}"/>
@@ -143,8 +161,10 @@
<zipfileset dir="${build}" prefix="${project.namever}" excludes="${release.excludes}" filemode="644" dirmode="755">
<exclude name="bin/**"/>
- <exclude name="**/*.class"/>
+ <exclude name="scratch/**"/>
</zipfileset>
+
+ <zipfileset dir="${resources}" prefix="${project.namever}" filemode="644"/>
</zip>
</target>
@@ -166,6 +186,7 @@
<target name="release-all" depends="zip,gzip,bzip2" description="build all release archives"/>
+
<target name="clean" description="remove build and release artifacts">
<iterate target="clean"/>
<delete dir="${build}"/>
@@ -173,4 +194,52 @@
<delete dir="${tasks.classes}"/>
</target>
+ <target name="coverage-report" description="generate coverage report" depends="cobertura-init">
+ <cobertura-merge datafile="${build.coveragereport}/cobertura.ser">
+ <!-- merge all module coverage reports -->
+ <fileset dir="${build}">
+ <include name="**/*.ser"/>
+ </fileset>
+ </cobertura-merge>
+ <cobertura-report format="html"
+ destdir="${build.coveragereport}"
+ datafile="${build.coveragereport}/cobertura.ser"
+ >
+ <fileset dir="${project.root}/common/src/main/java" includes="**/*.java" />
+ <fileset dir="${project.root}/build/scratch/common/src" includes="**/*.java" />
+ <fileset dir="${project.root}/broker/src/main/java" includes="**/*.java" />
+ <fileset dir="${project.root}/build/scratch/broker/src" includes="**/*.java" />
+ <fileset dir="${project.root}/client/src/main/java" includes="**/*.java" />
+ <fileset dir="${project.root}/build/scratch/client/src" includes="**/*.java" />
+ </cobertura-report>
+ </target>
+
+ <target name="instrument" description="instrument for artifacts">
+ <iterate target="instrument"/>
+ </target>
+
+ <target name="cover-test" description="run tests and generate coverage information" depends="build">
+ <iterate target="cover-test" modules="broker client common"/>
+ </target>
+
+ <target name="test-interop" depends="build,compile-tests"
+ description="run JMS examples against the corresponding c++ and python examples">
+ <property name="qpid.src.home" location=".."/>
+ <echo-prop name="qpid.src.home"/>
+ <exec executable="/bin/sh" failonerror="true">
+ <env key="QPID_SRC_HOME" value="${qpid.src.home}"/>
+ <arg value="-c"/>
+ <arg value="${project.root}/client/example/bin/verify_all"/>
+ </exec>
+ </target>
+
+ <target name="testkit" depends="build,compile-tests">
+ <jython path="${mllib.dir}">
+ <args>
+ <arg value="${mllib.dir}/qpid-python-test"/>
+ <arg value="-m ${basedir}/testkit/testkit"/>
+ </args>
+ </jython>
+ </target>
+
</project>
diff --git a/java/clean-dir b/java/clean-dir
deleted file mode 100755
index 52800c5151..0000000000
--- a/java/clean-dir
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-rm -rf $@; mkdir $@
diff --git a/java/client-java14/README.txt b/java/client-java14/README.txt
deleted file mode 100644
index 66621c7eb2..0000000000
--- a/java/client-java14/README.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-An implementation of SASL is provided here, for the PLAIN and CRAM-MD5 mechanisms as well as maven assembly
-instructions for producing a backported Java client for Java 1.4. In order to use the custom SASL implementation
-on JRE 1.4 the following steps must be taken:
-
- * Install the SASL JSR-28 API jar.
- * Install the qpid-client-java14 jar or set it up as a dynamically registered SASL provider.
- * Set up java.security to add the SASL provider to the list of security providers if hte SASL implemenation jar was installed as an extension.
-
-Installing the SASL JSR-28 API jar.
-
- Download, http://www.worldspot.com/jsr28/v1.1/download/sasl.jar, and copy it to the JAVA_HOME\lib\ext directory.
-
-Install or set up the qpid-client-java14 jar.
-
- Copy the output jar for this project, qpid-client-java14-1.0-incubating-M2-SNAPSHOT.jar, to JAVA_HOME\lib\ext.
-
- OR
-
- Create a properties file and register the SASL implementations in the jar so that Qpids dynamic SASL registry can find them. In a properties file
- add the lines:
-
- PLAIN=org.apache.qpid.sasl.ClientFactoryImpl
- CRAM-MD5=org.apache.qpid.sasl.ClientFactoryImpl
-
- Place this somewhere on the classpath and put the qpid-client-java14-1.0-incubating-M2-SNAPSHOT.jar on the classpath too. When starting your application
- pass in the system property amq.dynamicsaslregistrar.properties and set it to point to the location of the properties file.
-
-Set up the SASL provider.
-
- You only need to do this if the custom SASL jar, qpid-client-java14-1.0-incubating-M2-SNAPSHOT.jar, was copied to JAVA_HOME\lib\ext.
- Add the following line to JAVA_HOME\lib\security\java.security file (where n is the providers preference order):
-
- security.provider.n=org.apache.qpid.sasl.Provider \ No newline at end of file
diff --git a/java/client-java14/etc/sasl.properties b/java/client-java14/etc/sasl.properties
deleted file mode 100644
index 04519e2a30..0000000000
--- a/java/client-java14/etc/sasl.properties
+++ /dev/null
@@ -1,20 +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.
-#
-PLAIN=org.apache.qpid.sasl.ClientFactoryImpl
-CRAM-MD5=org.apache.qpid.sasl.ClientFactoryImpl
diff --git a/java/client-java14/pom.xml b/java/client-java14/pom.xml
deleted file mode 100644
index 1e49cb0c1c..0000000000
--- a/java/client-java14/pom.xml
+++ /dev/null
@@ -1,224 +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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-client-java14</artifactId>
- <packaging>jar</packaging>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <name>Qpid Client for Java 1.4</name>
- <url>http://cwiki.apache.org/confluence/display/qpid</url>
-
- <parent>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid</artifactId>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <relativePath>../pom.xml</relativePath>
- </parent>
-
- <properties>
- <topDirectoryLocation>..</topDirectoryLocation>
- <java.source.version>1.4</java.source.version>
- <qpid.version>${pom.version}</qpid.version>
- <qpid.targetDir>${project.build.directory}</qpid.targetDir>
- <!--<qpid.root>${basedir}/..</qpid.root>-->
- <sasl.properties>${basedir}/etc/sasl.properties</sasl.properties>
-
- <!-- This is a dummy value to ensure this property exists, override in your settings.xml to your real 1.4 jdk location to run tests. -->
- <jvm.1.4.bin>path/to/java1.4</jvm.1.4.bin>
- </properties>
-
- <dependencies>
-
- <!-- These dependencies have to be re-declared here, because exluding the normal (non 1.4) client and common from the distribution takes out
- these transitive dependencies too. -->
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-simple</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.apache.mina</groupId>
- <artifactId>mina-core</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-jms_1.1_spec</artifactId>
- </dependency>
-
- <dependency>
- <groupId>commons-collections</groupId>
- <artifactId>commons-collections</artifactId>
- </dependency>
-
- <dependency>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- </dependency>
-
- <!-- Use the java 1.4 retrotranslated client. -->
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-client</artifactId>
- <type>jar</type>
- <version>${pom.version}</version>
- <classifier>java14</classifier>
- </dependency>
-
- <!-- Use the java 1.4 retrotranslated common library. -->
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-common</artifactId>
- <type>jar</type>
- <version>${pom.version}</version>
- <classifier>java14</classifier>
- </dependency>
-
- <!-- Use the java 1.4 retrotranslated integration tests. -->
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-integrationtests</artifactId>
- <type>jar</type>
- <version>${pom.version}</version>
- <classifier>java14</classifier>
- <!--<scope>test</scope>-->
- </dependency>
-
- <dependency>
- <groupId>net.sf.retrotranslator</groupId>
- <artifactId>retrotranslator-runtime</artifactId>
- <scope>package</scope>
- </dependency>
-
- <!-- Test dependencies. -->
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>test</scope>
- </dependency>
-
- </dependencies>
-
- <build>
- <plugins>
-
- <!-- Sets up the compiler plugin to compile on 1.4 -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>${java.source.version}</source>
- <target>${java.source.version}</target>
- </configuration>
- </plugin>
-
- <!-- Sets up the assembly plugin to use the assembly directions to build a 1.4 compatable client. -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-assembly-plugin</artifactId>
- <version>${assembly.version}</version>
-
- <executions>
-
- <!-- Produces the distribution. -->
- <execution>
- <id>assembly-dist</id>
- <phase>package</phase>
- <goals>
- <goal>attached</goal>
- </goals>
- <configuration>
- <descriptors>
- <descriptor>src/main/assembly/client-java14-bin.xml</descriptor>
- </descriptors>
- <finalName>qpid-${pom.version}</finalName>
- <outputDirectory>${qpid.targetDir}</outputDirectory>
- <tarLongFileMode>gnu</tarLongFileMode>
- </configuration>
- </execution>
-
- <!-- Produces a jar with all test dependencies in it. For convenience in running tests from command line. -->
- <!-- Todo: Replace this with a manifest only jar, its much quicker to build that. -->
- <execution>
- <id>assembly-alltestdeps</id>
- <phase>package</phase>
- <goals>
- <goal>attached</goal>
- </goals>
- <configuration>
- <descriptors>
- <descriptor>src/main/assembly/jar-with-dependencies.xml</descriptor>
- </descriptors>
- <outputDirectory>target</outputDirectory>
- <workDirectory>target/assembly/work</workDirectory>
- </configuration>
- </execution>
-
- </executions>
- </plugin>
-
- <!-- Sets up surefire to run during the integration-test phase instead of the test phase. -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <skip>true</skip>
- </configuration>
- <executions>
- <execution>
- <id>surefire-it</id>
- <phase>integration-test</phase>
- <goals>
- <goal>test</goal>
- </goals>
- <configuration>
- <skip>true</skip>
- <forkMode>once</forkMode>
- <jvm>${jvm.1.4.bin}</jvm>
- <systemProperties>
- <property>
- <name>amqj.logging.level</name>
- <value>${amqj.logging.level}</value>
- </property>
- <property>
- <name>log4j.configuration</name>
- <value>${log4j.configuration}</value>
- </property>
- <property>
- <name>amq.dynamicsaslregistrar.properties</name>
- <value>${sasl.properties}</value>
- </property>
- </systemProperties>
- </configuration>
- </execution>
- </executions>
- </plugin>
-
- </plugins>
- </build>
-</project>
diff --git a/java/client-java14/src/main/assembly/client-java14-bin.xml b/java/client-java14/src/main/assembly/client-java14-bin.xml
deleted file mode 100644
index 91e1f23975..0000000000
--- a/java/client-java14/src/main/assembly/client-java14-bin.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
--->
-<!-- Assembly instructions for a client that runs on Java 1.4 -->
-<assembly>
- <id>java-client-java14-bin</id>
- <includeBaseDirectory>false</includeBaseDirectory>
- <formats>
- <format>tar.gz</format>
- <format>zip</format>
- </formats>
-
- <fileSets>
- <fileSet>
- <!-- Apache license files -->
- <directory>../resources</directory>
- <outputDirectory>qpid-${qpid.version}</outputDirectory>
- <includes>
- <include>DISCLAIMER</include>
- <include>LICENSE.txt</include>
- <include>NOTICE.txt</include>
- <include>README.txt</include>
- </includes>
- </fileSet>
-
- <fileSet>
- <directory>../release-docs</directory>
- <outputDirectory>qpid-${qpid.version}/docs</outputDirectory>
- <includes>
- <include>RELEASE_NOTES.txt</include>
- </includes>
- </fileSet>
-
- </fileSets>
-
- <dependencySets>
- <dependencySet>
- <outputDirectory>qpid-${qpid.version}/lib</outputDirectory>
- <unpack>false</unpack>
-
- <excludes>
- <!-- Exclude the Java 5 built client and common. The java 1.4 retrotranslated versions are used instead. -->
- <exclude>org.apache.qpid:qpid-client:jar</exclude>
- <exclude>org.apache.qpid:qpid-common:jar</exclude>
-
- <!-- Exclude the retrotranslated integration tests from the distriubtion. -->
- <exclude>org.apache.qpid:qpid-integrationtests:jar:java14</exclude>
-
- <!-- Mina SSL support only available in Java 5. No SSL on 1.4. -->
- <exclude>org.apache.mina:mina-java5</exclude>
- <exclude>org.apache.mina:mina-filter-ssl</exclude>
-
- </excludes>
- </dependencySet>
- </dependencySets>
-</assembly>
-
-
diff --git a/java/client-java14/src/main/assembly/jar-with-dependencies.xml b/java/client-java14/src/main/assembly/jar-with-dependencies.xml
deleted file mode 100644
index 091fd46427..0000000000
--- a/java/client-java14/src/main/assembly/jar-with-dependencies.xml
+++ /dev/null
@@ -1,104 +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.
--->
-<!-- This is an assembly descriptor that produces a jar file that contains all the
- test dependencies, fully expanded into a single jar, required to run the tests
- of a maven project.
--->
-<!--
-<assembly>
- <id>all-test-deps</id>
- <includeBaseDirectory>false</includeBaseDirectory>
-
- <formats>
- <format>jar</format>
- </formats>
-
- <dependencySets>
- <!## Include all test dependencies. ##>
- <dependencySet>
- <outputDirectory></outputDirectory>
- <outputFileNameMapping></outputFileNameMapping>
- <unpack>true</unpack>
- <!##<scope>runtime</scope>##>
-
- <!##
- <includes>
- <include>org.apache.qpid:qpid-client:jar:java14</include>
- <include>org.apache.qpid:qpid-common:jar:java14</include>
- </includes>
- ##>
-
- <excludes>
- <!## Exclude the Java 5 built client and common. The java 1.4 retrotranslated versions are used instead. ##>
- <exclude>org.apache.qpid:qpid-client:jar</exclude>
- <exclude>org.apache.qpid:qpid-common:jar</exclude>
-
- <!## Mina SSL support only available in Java 5. No SSL on 1.4. ##>
- <exclude>org.apache.mina:mina-java5</exclude>
- <exclude>org.apache.mina:mina-filter-ssl</exclude>
- </excludes>
-
- </dependencySet>
-
- </dependencySets>
-
- <fileSets>
- <!## Include all project classes. ##>
- <fileSet>
- <directory>target/classes</directory>
- <outputDirectory></outputDirectory>
- </fileSet>
-
- <!## Include all project test classes. ##>
- <fileSet>
- <directory>target/test-classes</directory>
- <outputDirectory></outputDirectory>
- </fileSet>
- </fileSets>
-</assembly>
--->
-
-<assembly>
- <id>all-test-deps</id>
- <includeBaseDirectory>false</includeBaseDirectory>
- <formats>
- <format>jar</format>
- </formats>
-
- <fileSets>
- </fileSets>
-
- <dependencySets>
- <dependencySet>
- <outputDirectory></outputDirectory>
- <unpack>true</unpack>
-
- <excludes>
- <!-- Exclude the Java 5 built client and common. The java 1.4 retrotranslated versions are used instead. -->
- <exclude>org.apache.qpid:qpid-client:jar</exclude>
- <exclude>org.apache.qpid:qpid-common:jar</exclude>
-
- <!-- Mina SSL support only available in Java 5. No SSL on 1.4. -->
- <exclude>org.apache.mina:mina-java5</exclude>
- <exclude>org.apache.mina:mina-filter-ssl</exclude>
-
- </excludes>
- </dependencySet>
- </dependencySets>
-</assembly> \ No newline at end of file
diff --git a/java/client-java14/src/main/java/org/apache/qpid/sasl/ClientFactoryImpl.java b/java/client-java14/src/main/java/org/apache/qpid/sasl/ClientFactoryImpl.java
deleted file mode 100644
index ed8e4ad80f..0000000000
--- a/java/client-java14/src/main/java/org/apache/qpid/sasl/ClientFactoryImpl.java
+++ /dev/null
@@ -1,343 +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.
- *
- */
-package org.apache.qpid.sasl;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-import javax.security.auth.callback.*;
-import javax.security.sasl.Sasl;
-import javax.security.sasl.SaslClient;
-import javax.security.sasl.SaslClientFactory;
-import javax.security.sasl.SaslException;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.util.PrettyPrintingUtils;
-
-/**
- * Implements a factory for generating Sasl client implementations.
- *
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Provide a list of supported encryption mechansims that meet a defined set of Sasl properties.
- * <tr><td> Provide the best matching supported Sasl mechanism to a preference ordered list of mechanisms and Sasl
- * properties.
- * <tr><td> Perform username and password request call backs. <td> CallBackHandler
- * </table>
- */
-public class ClientFactoryImpl implements SaslClientFactory
-{
- //private static final Logger log = Logger.getLogger(ClientFactoryImpl.class);
-
- /** Holds the names of the supported encryption mechanisms. */
- private static final String[] SUPPORTED_MECHANISMS = { "CRAM-MD5", "PLAIN" };
-
- /** Defines index of the CRAM-MD5 mechanism within the supported mechanisms. */
- private static final int CRAM_MD5 = 0;
-
- /** Defines index of the PLAIN mechanism within the supported mechanisms. */
- private static final int PLAIN = 1;
-
- /** Bit mapping of the no plain text policy. */
- private static final int NOPLAINTEXT = 0x0001;
-
- /** Bit mapping of the no susceptible active attacks policy. */
- private static final int NOACTIVE = 0x0002;
-
- /** Bit mapping of the no susceptible to dictionary attacks policy. */
- private static final int NODICTIONARY = 0x0004;
-
- /** Bit mapping of the must use forward secrecy between sessions policy. */
- private static final int FORWARD_SECRECY = 0x0008;
-
- /** Bit mapping of the no anonymous logins policy. */
- private static final int NOANONYMOUS = 0x0010;
-
- /** Bit mapping of the must pass credentials policy. */
- private static final int PASS_CREDENTIALS = 0x0020;
-
- /** Defines a mapping from supported mechanisms to supported policy flags. */
- private static final int[] SUPPPORTED_MECHANISMS_POLICIES =
- {
- NOPLAINTEXT | NOANONYMOUS, // CRAM-MD5
- NOANONYMOUS // PLAIN
- };
-
- /**
- * Creates a SaslClient using the parameters supplied.
- *
- * @param mechanisms The non-null list of mechanism names to try. Each is the IANA-registered name of a SASL
- * mechanism. (e.g. "GSSAPI", "CRAM-MD5").
- * @param authorizationId The possibly null protocol-dependent identification to be used for authorization.
- * If null or empty, the server derives an authorization ID from the client's authentication
- * credentials. When the SASL authentication completes successfully, the specified entity is
- * granted access.
- * @param protocol The non-null string name of the protocol for which the authentication is being performed
- * (e.g., "ldap").
- * @param serverName The non-null fully qualified host name of the server to authenticate to.
- * @param props The possibly null set of properties used to select the SASL mechanism and to configure the
- * authentication exchange of the selected mechanism. See the <tt>Sasl</tt> class for a list
- * of standard properties. Other, possibly mechanism-specific, properties can be included.
- * Properties not relevant to the selected mechanism are ignored.
- * @param cbh The possibly null callback handler to used by the SASL mechanisms to get further
- * information from the application/library to complete the authentication. For example, a
- * SASL mechanism might require the authentication ID, password and realm from the caller.
- * The authentication ID is requested by using a <tt>NameCallback</tt>.
- * The password is requested by using a <tt>PasswordCallback</tt>.
- * The realm is requested by using a <tt>RealmChoiceCallback</tt> if there is a list
- * of realms to choose from, and by using a <tt>RealmCallback</tt> if
- * the realm must be entered.
- *
- * @return A possibly null <tt>SaslClient</tt> created using the parameters supplied. If null, this factory cannot
- * produce a <tt>SaslClient</tt> using the parameters supplied.
- *
- * @throws javax.security.sasl.SaslException If cannot create a <tt>SaslClient</tt> because of an error.
- */
- public SaslClient createSaslClient(String[] mechanisms, String authorizationId, String protocol, String serverName,
- Map props, CallbackHandler cbh) throws SaslException
- {
- /*log.debug("public SaslClient createSaslClient(String[] mechanisms = " + PrettyPrintingUtils.printArray(mechanisms)
- + ", String authorizationId = " + authorizationId + ", String protocol = " + protocol
- + ", String serverName = " + serverName + ", Map props = " + props + ", CallbackHandler cbh): called");*/
-
- // Get a list of all supported mechanisms that matched the required properties.
- String[] matchingMechanisms = getMechanismNames(props);
- //log.debug("matchingMechanisms = " + PrettyPrintingUtils.printArray(matchingMechanisms));
-
- // Scan down the list of mechanisms until the first one that matches one of the matching supported mechanisms
- // is found.
- String chosenMechanism = null;
-
- for (int i = 0; i < mechanisms.length; i++)
- {
- String mechanism = mechanisms[i];
-
- for (int j = 0; j < matchingMechanisms.length; j++)
- {
- String matchingMechanism = matchingMechanisms[j];
-
- if (mechanism.equals(matchingMechanism))
- {
- chosenMechanism = mechanism;
-
- break;
- }
- }
-
- // Stop scanning if a match has been found.
- if (chosenMechanism != null)
- {
- break;
- }
- }
-
- // Check that a matching mechanism was found or return null otherwise.
- if (chosenMechanism == null)
- {
- //log.debug("No matching mechanism could be found.");
-
- return null;
- }
-
- // Instantiate an appropriate client type for the chosen mechanism.
- if (chosenMechanism.equals(SUPPORTED_MECHANISMS[CRAM_MD5]))
- {
- Object[] uinfo = getUserInfo("CRAM-MD5", authorizationId, cbh);
-
- //log.debug("Using CRAM-MD5 mechanism.");
-
- return new CramMD5Client((String) uinfo[0], (byte[]) uinfo[1]);
- }
- else
- {
- Object[] uinfo = getUserInfo("PLAIN", authorizationId, cbh);
-
- //log.debug("Using PLAIN mechanism.");
-
- return new PlainClient(authorizationId, (String) uinfo[0], (byte[]) uinfo[1]);
- }
- }
-
- /**
- * Returns an array of names of mechanisms that match the specified
- * mechanism selection policies.
- *
- * @param props The possibly null set of properties used to specify the
- * security policy of the SASL mechanisms. For example, if <tt>props</tt>
- * contains the <tt>Sasl.POLICY_NOPLAINTEXT</tt> property with the value
- * <tt>"true"</tt>, then the factory must not return any SASL mechanisms
- * that are susceptible to simple plain passive attacks.
- * See the <tt>Sasl</tt> class for a complete list of policy properties.
- * Non-policy related properties, if present in <tt>props</tt>, are ignored.
- *
- * @return A non-null array containing a IANA-registered SASL mechanism names.
- */
- public String[] getMechanismNames(Map props)
- {
- //log.debug("public String[] getMechanismNames(Map props = " + props + "): called");
-
- // Used to build up the valid mechanisms in.
- List validMechanisms = new ArrayList();
-
- // Transform the Sasl properties into a set of bit mapped flags indicating the required properties of the
- // encryption mechanism employed.
- int requiredFlags = bitMapSaslProperties(props);
- //log.debug("requiredFlags = " + requiredFlags);
-
- // Scan down the list of supported mechanisms filtering in only those that satisfy all of the desired
- // encryption properties.
- for (int i = 0; i < SUPPORTED_MECHANISMS.length; i++)
- {
- int mechanismFlags = SUPPPORTED_MECHANISMS_POLICIES[i];
- //log.debug("mechanismFlags = " + mechanismFlags);
-
- // Check if the current mechanism contains all of the required flags.
- if ((requiredFlags & ~mechanismFlags) == 0)
- {
- //log.debug("Mechanism " + SUPPORTED_MECHANISMS[i] + " meets the required properties.");
- validMechanisms.add(SUPPORTED_MECHANISMS[i]);
- }
- }
-
- String[] result = (String[]) validMechanisms.toArray(new String[validMechanisms.size()]);
-
- //log.debug("result = " + PrettyPrintingUtils.printArray(result));
-
- return result;
- }
-
- /**
- * Transforms a set of Sasl properties, defined using the property names in javax.security.sasl.Sasl, into
- * a bit mapped set of property flags encoded using the bit mapping constants defined in this class.
- *
- * @param properties The Sasl properties to bit map.
- *
- * @return A set of bit mapped properties encoded in an integer.
- */
- private int bitMapSaslProperties(Map properties)
- {
- //log.debug("private int bitMapSaslProperties(Map properties = " + properties + "): called");
-
- int result = 0;
-
- // No flags set if no properties are set.
- if (properties == null)
- {
- return result;
- }
-
- if ("true".equalsIgnoreCase((String) properties.get(Sasl.POLICY_NOPLAINTEXT)))
- {
- result |= NOPLAINTEXT;
- }
-
- if ("true".equalsIgnoreCase((String) properties.get(Sasl.POLICY_NOACTIVE)))
- {
- result |= NOACTIVE;
- }
-
- if ("true".equalsIgnoreCase((String) properties.get(Sasl.POLICY_NODICTIONARY)))
- {
- result |= NODICTIONARY;
- }
-
- if ("true".equalsIgnoreCase((String) properties.get(Sasl.POLICY_NOANONYMOUS)))
- {
- result |= NOANONYMOUS;
- }
-
- if ("true".equalsIgnoreCase((String) properties.get(Sasl.POLICY_FORWARD_SECRECY)))
- {
- result |= FORWARD_SECRECY;
- }
-
- if ("true".equalsIgnoreCase((String) properties.get(Sasl.POLICY_PASS_CREDENTIALS)))
- {
- result |= PASS_CREDENTIALS;
- }
-
- return result;
- }
-
- /**
- * Uses the specified call back handler to query for the users log in name and password.
- *
- * @param prefix A prefix to prepend onto the username and password queries.
- * @param authorizationId The default autorhization name.
- * @param cbh The call back handler.
- *
- * @return The username and password from the callback.
- *
- * @throws SaslException If the callback fails for any reason.
- */
- private Object[] getUserInfo(String prefix, String authorizationId, CallbackHandler cbh) throws SaslException
- {
- // Check that the callback handler is defined.
- if (cbh == null)
- {
- throw new SaslException("Callback handler to get username/password required.");
- }
-
- try
- {
- String userPrompt = prefix + " authentication id: ";
- String passwdPrompt = prefix + " password: ";
-
- NameCallback ncb =
- (authorizationId == null) ? new NameCallback(userPrompt) : new NameCallback(userPrompt, authorizationId);
- PasswordCallback pcb = new PasswordCallback(passwdPrompt, false);
-
- // Ask the call back handler to get the users name and password.
- cbh.handle(new Callback[] { ncb, pcb });
-
- char[] pw = pcb.getPassword();
-
- byte[] bytepw;
- String authId;
-
- if (pw != null)
- {
- bytepw = new String(pw).getBytes("UTF8");
- pcb.clearPassword();
- }
- else
- {
- bytepw = null;
- }
-
- authId = ncb.getName();
-
- return new Object[] { authId, bytepw };
- }
- catch (IOException e)
- {
- throw new SaslException("Cannot get password.", e);
- }
- catch (UnsupportedCallbackException e)
- {
- throw new SaslException("Cannot get userid/password.", e);
- }
- }
-}
diff --git a/java/client-java14/src/main/java/org/apache/qpid/sasl/CramMD5Client.java b/java/client-java14/src/main/java/org/apache/qpid/sasl/CramMD5Client.java
deleted file mode 100644
index 4f890ffed5..0000000000
--- a/java/client-java14/src/main/java/org/apache/qpid/sasl/CramMD5Client.java
+++ /dev/null
@@ -1,347 +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.
- *
- */
-package org.apache.qpid.sasl;
-
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-
-import javax.security.sasl.Sasl;
-import javax.security.sasl.SaslClient;
-import javax.security.sasl.SaslException;
-
-/**
- * Implements the CRAM-MD5 SASL mechanism.
- *
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Concatenate the user id and password hashed by a challenge string as the challenge response.
- * <tr><td> Ensure password is wiped once a challenge has been processed.
- * </table>
- */
-public class CramMD5Client implements SaslClient
-{
- /** Defines the HMAC block size. */
- private static final int MD5_BLOCKSIZE = 64;
-
- /** Flag used to indicate that the authentication has completed. */
- private boolean completed = false;
-
- private String authenticationId;
- private byte[] password;
-
- /**
- * Creates a PLAIN SASL client for an authorization id, authentication id and password.
- *
- * @param authenticationId The authentication id.
- * @param password The password.
- *
- * @throws SaslException If the authentication id or password is null.
- */
- CramMD5Client(String authenticationId, byte[] password) throws SaslException
- {
- // Check that a username and password are specified.
- if ((authenticationId == null) || (password == null))
- {
- throw new SaslException("CRAM: authentication id and password must be specified");
- }
-
- // Keep the log in credentials.
- this.authenticationId = authenticationId;
- this.password = password;
- }
-
- /**
- * Returns the IANA-registered mechanism name of this SASL client. (e.g. "CRAM-MD5", "GSSAPI").
- *
- * @return A non-null string representing the IANA-registered mechanism name.
- */
- public String getMechanismName()
- {
- return "CRAM-MD5";
- }
-
- /**
- * Determines whether this mechanism has an optional initial response. If true, caller should call
- * <tt>evaluateChallenge()</tt> with an empty array to get the initial response.
- *
- * <p/>CRAM-MD5 has no intial response.
- *
- * @return true if this mechanism has an initial response.
- */
- public boolean hasInitialResponse()
- {
- return false;
- }
-
- /**
- * Evaluates the challenge data and generates a response. If a challenge is received from the server during the
- * authentication process, this method is called to prepare an appropriate next response to submit to the server.
- *
- * <p/>The initial response for the SASL command, for the CRAM-MD5 mechanism is the concatenation of authentication
- * ID and password HMAC-MD5 hashed by the server challenge.
- *
- * @param challenge The non-null challenge sent from the server. The challenge array may have zero length.
- *
- * @return The possibly null reponse to send to the server. It is null if the challenge accompanied a "SUCCESS"
- * status and the challenge only contains data for the client to update its state and no response
- * needs to be sent to the server. The response is a zero-length byte array if the client is to send a
- * response with no data.
- *
- * @throws javax.security.sasl.SaslException If an error occurred while processing the challenge or generating a
- * response.
- */
- public byte[] evaluateChallenge(byte[] challenge) throws SaslException
- {
- // Check that the authentication has not already been performed.
- if (completed)
- {
- throw new IllegalStateException("CRAM-MD5 authentication already completed.");
- }
-
- // Check if the password is null, this will be the case if a previous attempt to authenticated failed.
- if (password == null)
- {
- throw new IllegalStateException("CRAM-MD5 authentication previously aborted due to error.");
- }
-
- // Generate a keyed-MD5 digest from the user's password keyed by the challenge bytes.
- try
- {
- String digest = hmac_md5(password, challenge);
- String result = authenticationId + " " + digest;
-
- completed = true;
-
- return result.getBytes("UTF8");
- }
- catch (java.security.NoSuchAlgorithmException e)
- {
- throw new SaslException("MD5 algorithm not available on platform", e);
- }
- catch (java.io.UnsupportedEncodingException e)
- {
- throw new SaslException("UTF8 not available on platform", e);
- }
- finally
- {
- clearPassword();
- }
- }
-
- /**
- * Determines whether the authentication exchange has completed. This method may be called at any time, but
- * typically, it will not be called until the caller has received indication from the server (in a protocol-specific
- * manner) that the exchange has completed.
- *
- * @return true if the authentication exchange has completed; false otherwise.
- */
- public boolean isComplete()
- {
- return completed;
- }
-
- /**
- * Unwraps a byte array received from the server. This method can be called only after the authentication exchange
- * has completed (i.e., when <tt>isComplete()</tt> returns true) and only if the authentication exchange has
- * negotiated integrity and/or privacy as the quality of protection; otherwise, an <tt>IllegalStateException</tt> is
- * thrown.
- *
- * <p/><tt>incoming</tt> is the contents of the SASL buffer as defined in RFC 2222 without the leading four octet
- * field that represents the length. <tt>offset</tt> and <tt>len</tt> specify the portion of <tt>incoming</tt>
- * to use.
- *
- * @param incoming A non-null byte array containing the encoded bytes from the server.
- * @param offset The starting position at <tt>incoming</tt> of the bytes to use.
- * @param len The number of bytes from <tt>incoming</tt> to use.
- *
- * @return A non-null byte array containing the decoded bytes.
- *
- * @throws javax.security.sasl.SaslException If <tt>incoming</tt> cannot be successfully unwrapped.
- * @throws IllegalStateException If the authentication exchange has not completed, or if the negotiated quality of
- * protection has neither integrity nor privacy.
- */
- public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException
- {
- throw new SaslException("CRAM-MD5 does not support quality of protection.");
- }
-
- /**
- * Wraps a byte array to be sent to the server. This method can be called only after the authentication exchange has
- * completed (i.e., when <tt>isComplete()</tt> returns true) and only if the authentication exchange has negotiated
- * integrity and/or privacy as the quality of protection; otherwise, an <tt>IllegalStateException</tt> is thrown.
- *
- * <p/>The result of this method will make up the contents of the SASL buffer as defined in RFC 2222 without the
- * leading four octet field that represents the length. <tt>offset</tt> and <tt>len</tt> specify the portion of
- * <tt>outgoing</tt> to use.
- *
- * @param outgoing A non-null byte array containing the bytes to encode.
- * @param offset The starting position at <tt>outgoing</tt> of the bytes to use.
- * @param len The number of bytes from <tt>outgoing</tt> to use.
- *
- * @return A non-null byte array containing the encoded bytes.
- *
- * @throws javax.security.sasl.SaslException If <tt>outgoing</tt> cannot be successfully wrapped.
- * @throws IllegalStateException If the authentication exchange has not completed, or if the negotiated quality of
- * protection has neither integrity nor privacy.
- */
- public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException
- {
- throw new SaslException("CRAM-MD5 does not support quality of protection.");
- }
-
- /**
- * Retrieves the negotiated property. This method can be called only after the authentication exchange has
- * completed (i.e., when <tt>isComplete()</tt> returns true); otherwise, an <tt>IllegalStateException</tt> is thrown.
- *
- * @param propName The non-null property name.
- *
- * @return The value of the negotiated property. If null, the property was not negotiated or is not applicable to
- * this mechanism.
- *
- * @throws IllegalStateException If this authentication exchange has not completed.
- */
- public Object getNegotiatedProperty(String propName)
- {
- if (completed)
- {
- if (propName.equals(Sasl.QOP))
- {
- return "auth";
- }
- else
- {
- return null;
- }
- }
- else
- {
- throw new IllegalStateException("CRAM-MD5 authentication not completed");
- }
- }
-
- /**
- * Disposes of any system resources or security-sensitive information the SaslClient might be using. Invoking this
- * method invalidates the SaslClient instance. This method is idempotent.
- *
- * @throws javax.security.sasl.SaslException If a problem was encountered while disposing the resources.
- */
- public void dispose() throws SaslException
- { }
-
- /*
- * Hashes its input arguments according to HMAC-MD5 (RFC 2104) and returns the resulting digest in its ASCII
- * representation.
- *
- * <p/> The HMAC-MD5 function is described as follows:
- * <p/><pre>
- * MD5(key XOR opad, MD5(key XOR ipad, text))
- * </pre>
- *
- * <p/>Where key is an n byte key, ipad is the byte 0x36 repeated 64 times, opad is the byte 0x5c repeated 64 times
- * and text is the data to be protected.
- *
- * @param key The key to hash by.
- * @param text The plain text to hash.
- *
- * @return The hashed text.
- *
- * @throws NoSuchAlgorithmException If the Java platform does not supply an MD5 implementation.
- */
- private static final String hmac_md5(byte[] key, byte[] text) throws NoSuchAlgorithmException
- {
- MessageDigest md5 = MessageDigest.getInstance("MD5");
-
- /* digest the key if longer than 64 bytes */
- if (key.length > 64)
- {
- key = md5.digest(key);
- }
-
- byte[] ipad = new byte[MD5_BLOCKSIZE]; /* inner padding */
- byte[] opad = new byte[MD5_BLOCKSIZE]; /* outer padding */
- byte[] digest;
- int i;
-
- /* store key in pads */
- for (i = 0; i < MD5_BLOCKSIZE; i++)
- {
- for (; i < key.length; i++)
- {
- ipad[i] = key[i];
- opad[i] = key[i];
- }
-
- ipad[i] = 0x00;
- opad[i] = 0x00;
- }
-
- /* XOR key with pads */
- for (i = 0; i < MD5_BLOCKSIZE; i++)
- {
- ipad[i] ^= 0x36;
- opad[i] ^= 0x5c;
- }
-
- /* inner MD5 */
- md5.update(ipad);
- md5.update(text);
- digest = md5.digest();
-
- /* outer MD5 */
- md5.update(opad);
- md5.update(digest);
- digest = md5.digest();
-
- // Get character representation of digest
- StringBuffer digestString = new StringBuffer();
-
- for (i = 0; i < digest.length; i++)
- {
- if ((digest[i] & 0x000000ff) < 0x10)
- {
- digestString.append("0" + Integer.toHexString(digest[i] & 0x000000ff));
- }
- else
- {
- digestString.append(Integer.toHexString(digest[i] & 0x000000ff));
- }
- }
-
- return (digestString.toString());
- }
-
- /**
- * Overwrites the password with zeros.
- */
- private void clearPassword()
- {
- if (password != null)
- {
- // Zero out password.
- for (int i = 0; i < password.length; i++)
- {
- password[i] = (byte) 0;
- }
-
- password = null;
- }
- }
-}
diff --git a/java/client-java14/src/main/java/org/apache/qpid/sasl/PlainClient.java b/java/client-java14/src/main/java/org/apache/qpid/sasl/PlainClient.java
deleted file mode 100644
index f5a9f150bb..0000000000
--- a/java/client-java14/src/main/java/org/apache/qpid/sasl/PlainClient.java
+++ /dev/null
@@ -1,275 +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.
- *
- */
-package org.apache.qpid.sasl;
-
-import javax.security.sasl.Sasl;
-import javax.security.sasl.SaslClient;
-import javax.security.sasl.SaslException;
-
-/**
- * Implements the PLAIN SASL mechanism.
- *
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Concatenate the user id and password in plain text as the challenge respose.
- * <tr><td> Ensure password is wiped once a challenge has been processed.
- * </table>
- */
-public class PlainClient implements SaslClient
-{
- /** Flag used to indicate that the authentication has completed. */
- private boolean completed = false;
-
- private String authorizationId;
- private String authenticationId;
- private byte[] password;
-
- private static byte SEPERATOR = 0; // US-ASCII <NUL>
-
- /**
- * Creates a PLAIN SASL client for an authorization id, authentication id and password.
- *
- * @param authorizationId The authorization id. May be null.
- * @param authenticationId The authentication id.
- * @param password The password.
- *
- * @throws SaslException If the authentication id or password is null.
- */
- PlainClient(String authorizationId, String authenticationId, byte[] password) throws SaslException
- {
- // Check that a username and password are specified.
- if ((authenticationId == null) || (password == null))
- {
- throw new SaslException("PLAIN: authentication ID and password must be specified");
- }
-
- // Keep the log in credentials.
- this.authorizationId = authorizationId;
- this.authenticationId = authenticationId;
- this.password = password;
- }
-
- /**
- * Returns the IANA-registered mechanism name of this SASL client. (e.g. "CRAM-MD5", "GSSAPI").
- *
- * @return A non-null string representing the IANA-registered mechanism name.
- */
- public String getMechanismName()
- {
- return "PLAIN";
- }
-
- /**
- * Determines whether this mechanism has an optional initial response. If true, caller should call
- * <tt>evaluateChallenge()</tt> with an empty array to get the initial response.
- *
- * @return true if this mechanism has an initial response.
- */
- public boolean hasInitialResponse()
- {
- return true;
- }
-
- /**
- * Evaluates the challenge data and generates a response. If a challenge is received from the server during the
- * authentication process, this method is called to prepare an appropriate next response to submit to the server.
- *
- * <p/>The initial response for the SASL command, for the PLAIN mechanism is the concatenation of authorization ID,
- * authentication ID and password, with each component separated by the US-ASCII <NUL> byte.
- *
- * @param challenge The non-null challenge sent from the server. The challenge array may have zero length.
- *
- * @return The possibly null reponse to send to the server. It is null if the challenge accompanied a "SUCCESS"
- * status and the challenge only contains data for the client to update its state and no response
- * needs to be sent to the server. The response is a zero-length byte array if the client is to send a
- * response with no data.
- *
- * @throws javax.security.sasl.SaslException If an error occurred while processing the challenge or generating a
- * response.
- */
- public byte[] evaluateChallenge(byte[] challenge) throws SaslException
- {
- // Check that the authentication has not already been performed.
- if (completed)
- {
- throw new IllegalStateException("PLAIN authentication already completed");
- }
-
- try
- {
- // Get the authorization and authentication ids in bytes.
- byte[] authorizationBytes = (authorizationId != null) ? authorizationId.getBytes("UTF8") : null;
- byte[] authenticationBytes = authenticationId.getBytes("UTF8");
-
- // Create an array big enough to hold the results.
- byte[] result =
- new byte[password.length + authenticationBytes.length + 2
- + ((authorizationBytes == null) ? 0 : authorizationBytes.length)];
-
- // Copy the authorization id, authentication id and password into the results.
- int pos = 0;
- if (authorizationBytes != null)
- {
- System.arraycopy(authorizationBytes, 0, result, 0, authorizationBytes.length);
- pos = authorizationBytes.length;
- }
-
- result[pos++] = SEPERATOR;
- System.arraycopy(authenticationBytes, 0, result, pos, authenticationBytes.length);
-
- pos += authenticationBytes.length;
- result[pos++] = SEPERATOR;
-
- System.arraycopy(password, 0, result, pos, password.length);
-
- completed = true;
-
- return result;
- }
- catch (java.io.UnsupportedEncodingException e)
- {
- throw new SaslException("Cannot get UTF-8 encoding of ids", e);
- }
- finally
- {
- clearPassword();
- }
- }
-
- /**
- * Determines whether the authentication exchange has completed. This method may be called at any time, but
- * typically, it will not be called until the caller has received indication from the server (in a protocol-specific
- * manner) that the exchange has completed.
- *
- * @return true if the authentication exchange has completed; false otherwise.
- */
- public boolean isComplete()
- {
- return completed;
- }
-
- /**
- * Unwraps a byte array received from the server. This method can be called only after the authentication exchange has
- * completed (i.e., when <tt>isComplete()</tt> returns true) and only if the authentication exchange has negotiated
- * integrity and/or privacy as the quality of protection; otherwise, an <tt>IllegalStateException</tt> is thrown.
- *
- * <p/><tt>incoming</tt> is the contents of the SASL buffer as defined in RFC 2222 without the leading four octet
- * field that represents the length. <tt>offset</tt> and <tt>len</tt> specify the portion of <tt>incoming</tt>
- * to use.
- *
- * @param incoming A non-null byte array containing the encoded bytes
- * from the server.
- * @param offset The starting position at <tt>incoming</tt> of the bytes to use.
- * @param len The number of bytes from <tt>incoming</tt> to use.
- *
- * @return A non-null byte array containing the decoded bytes.
- *
- * @throws javax.security.sasl.SaslException If <tt>incoming</tt> cannot be successfully unwrapped.
- * @throws IllegalStateException If the authentication exchange has not completed, or if the negotiated quality of
- * protection has neither integrity nor privacy.
- */
- public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException
- {
- throw new SaslException("PLAIN does not support quality of protection.");
- }
-
- /**
- * Wraps a byte array to be sent to the server. This method can be called only after the authentication exchange has
- * completed (i.e., when <tt>isComplete()</tt> returns true) and only if the authentication exchange has negotiated
- * integrity and/or privacy as the quality of protection; otherwise, an <tt>IllegalStateException</tt> is thrown.
- *
- * <p/>The result of this method will make up the contents of the SASL buffer as defined in RFC 2222 without the
- * leading four octet field that represents the length. <tt>offset</tt> and <tt>len</tt> specify the portion of
- * <tt>outgoing</tt> to use.
- *
- * @param outgoing A non-null byte array containing the bytes to encode.
- * @param offset The starting position at <tt>outgoing</tt> of the bytes to use.
- * @param len The number of bytes from <tt>outgoing</tt> to use.
- *
- * @return A non-null byte array containing the encoded bytes.
- *
- * @throws javax.security.sasl.SaslException If <tt>outgoing</tt> cannot be successfully wrapped.
- * @throws IllegalStateException If the authentication exchange has not completed, or if the negotiated quality of
- * protection has neither integrity nor privacy.
- */
- public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException
- {
- throw new SaslException("PLAIN does not support quality of protection.");
- }
-
- /**
- * Retrieves the negotiated property. This method can be called only after the authentication exchange has
- * completed (i.e., when <tt>isComplete()</tt> returns true); otherwise, an <tt>IllegalStateException</tt> is thrown.
- *
- * @param propName The non-null property name.
- *
- * @return The value of the negotiated property. If null, the property was not negotiated or is not applicable to
- * this mechanism.
- *
- * @throws IllegalStateException If this authentication exchange has not completed.
- */
- public Object getNegotiatedProperty(String propName)
- {
- if (completed)
- {
- if (propName.equals(Sasl.QOP))
- {
- return "auth";
- }
- else
- {
- return null;
- }
- }
- else
- {
- throw new IllegalStateException("PLAIN authentication not completed");
- }
- }
-
- /**
- * Disposes of any system resources or security-sensitive information the SaslClient might be using. Invoking this
- * method invalidates the SaslClient instance. This method is idempotent.
- *
- * @throws javax.security.sasl.SaslException If a problem was encountered while disposing the resources.
- */
- public void dispose() throws SaslException
- {
- clearPassword();
- }
-
- /**
- * Overwrites the password with zeros.
- */
- private void clearPassword()
- {
- if (password != null)
- {
- // Zero out password.
- for (int i = 0; i < password.length; i++)
- {
- password[i] = (byte) 0;
- }
-
- password = null;
- }
- }
-}
diff --git a/java/client-java14/src/main/java/org/apache/qpid/sasl/Provider.java b/java/client-java14/src/main/java/org/apache/qpid/sasl/Provider.java
deleted file mode 100644
index ef075a0cad..0000000000
--- a/java/client-java14/src/main/java/org/apache/qpid/sasl/Provider.java
+++ /dev/null
@@ -1,61 +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.
- *
- */
-package org.apache.qpid.sasl;
-
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-
-import org.apache.log4j.Logger;
-
-/**
- * A SASL provider for Java 1.4. Declares the capabilities of this implementation, which supports PLAIN and CRAM-MD5
- * client implementations only.
- *
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Declare PLAIN SASL support.
- * <tr><td> Declare CRAM-MD5 SASL support.
- * </table>
- */
-public class Provider extends java.security.Provider
-{
- //Logger log = Logger.getLogger(Provider.class);
-
- private static final String info = "Qpid SASL provider" + "(implements client mechanisms for: PLAIN, CRAM-MD5)";
-
- public Provider()
- {
- super("QpidSASL", 1.4, info);
-
- //log.debug("public Provider(): called");
-
- AccessController.doPrivileged(new PrivilegedAction()
- {
- public Object run()
- {
- put("SaslClientFactory.PLAIN", "org.apache.qpid.sasl.ClientFactoryImpl");
- put("SaslClientFactory.CRAM-MD5", "org.apache.qpid.sasl.ClientFactoryImpl");
-
- return null;
- }
- });
- }
-}
diff --git a/java/client-java14/src/test/java/org/apache/qpid/test/integration/client/ConnectionTest.java b/java/client-java14/src/test/java/org/apache/qpid/test/integration/client/ConnectionTest.java
deleted file mode 100644
index 77cc79bc49..0000000000
--- a/java/client-java14/src/test/java/org/apache/qpid/test/integration/client/ConnectionTest.java
+++ /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.
- *
- */
-package org.apache.qpid.test.integration.client;
-
-import junit.framework.Assert;
-import junit.framework.TestCase;
-
-import org.apache.log4j.Logger;
-import org.apache.log4j.NDC;
-
-import org.apache.qpid.client.AMQConnection;
-
-/**
- * Implements a trivial broker connection test, to a broker on the default port on localhost, to check that SASL
- * authentication works.
- *
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Check that a connection to a broker can be established.
- * </table>
- */
-public class ConnectionTest extends TestCase
-{
- private String BROKER_URL = "tcp://localhost:5672";
-
- public ConnectionTest(String name)
- {
- super(name);
- }
-
- /** Check that a connection to a broker can be established. */
- public void testConnection() throws Exception
- {
- // Open a connection to the broker and close it again.
- AMQConnection conn = new AMQConnection(BROKER_URL, "guest", "guest", "clientid", "test");
- conn.close();
- }
-
- protected void setUp()
- {
- NDC.push(getName());
- }
-
- protected void tearDown()
- {
- NDC.pop();
- }
-}
diff --git a/java/client/build.xml b/java/client/build.xml
index abeb3ec903..3c6132dc5b 100644
--- a/java/client/build.xml
+++ b/java/client/build.xml
@@ -21,6 +21,9 @@
<project name="AMQ Client" default="build">
<property name="module.depends" value="common"/>
+ <property name="module.test.depends" value="common/test" />
+ <property name="module.genpom" value="true"/>
+ <property name="module.genpom.args" value="-Sgeronimo-jms_1.1_spec=provided"/>
<import file="../module.xml"/>
@@ -33,4 +36,17 @@
javacchome="${project.root}/lib"/>
</target>
+
+ <uptodate property="doc-release.done" targetfile="${module.release}/api/index.html">
+ <srcfiles dir="${module.src}" includes="**/*.java"/>
+ </uptodate>
+
+ <target name="doc-release" depends="build" unless="doc-release.done">
+ <javadoc destdir="${module.release}/api" sourcepathref="module.src.path"
+ classpathref="module.class.path" packagenames="org.apache.qpid.jms"/>
+ </target>
+
+ <target name="release-bin" depends="release-bin-tasks"/>
+
+ <target name="bundle" depends="bundle-tasks"/>
</project>
diff --git a/java/client/distribution/pom.xml b/java/client/distribution/pom.xml
deleted file mode 100644
index 03f3656501..0000000000
--- a/java/client/distribution/pom.xml
+++ /dev/null
@@ -1,156 +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.
- -->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-client-distribution</artifactId>
- <packaging>jar</packaging>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <name>Qpid Client Distributions</name>
- <url>http://cwiki.apache.org/confluence/display/qpid</url>
-
- <parent>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid</artifactId>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- </parent>
-
- <properties>
- <topDirectoryLocation>..</topDirectoryLocation>
- <java.source.version>1.5</java.source.version>
- <qpid.version>${pom.version}</qpid.version>
- <qpid.targetDir>${project.build.directory}</qpid.targetDir>
- <qpid.root>${basedir}/..</qpid.root>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-client</artifactId>
- <type>jar</type>
- <version>${pom.version}</version>
- </dependency>
- </dependencies>
-
- <build>
- <pluginManagement>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>${java.source.version}</source>
- <target>${java.source.version}</target>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-assembly-plugin</artifactId>
- <version>${assembly.version}</version>
- <configuration>
- <descriptors>
- <descriptor>src/main/assembly/client-bin.xml</descriptor>
- </descriptors>
- <finalName>qpid-${pom.version}</finalName>
- <outputDirectory>${qpid.targetDir}</outputDirectory>
- <tarLongFileMode>gnu</tarLongFileMode>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <configuration>
- <finalName>qpid-incubating</finalName>
- <archive>
- <manifest>
- <addClasspath>true</addClasspath>
- </manifest>
- </archive>
- </configuration>
- </plugin>
-
- </plugins>
- </pluginManagement>
-
- <plugins>
- <plugin>
- <artifactId>maven-assembly-plugin</artifactId>
- <executions>
- <execution>
- <id>distribution-package</id>
- <phase>package</phase>
- <goals>
- <goal>single</goal>
- </goals>
- <configuration>
- <descriptors>
- <descriptor>src/main/assembly/client-bin.xml</descriptor>
- <descriptor>src/main/assembly/client-src.xml</descriptor>
- </descriptors>
- <finalName>qpid-${pom.version}</finalName>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
-
- </build>
-
-<profiles>
- <profile>
- <id>tests</id>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-client</artifactId>
- <type>test-jar</type>
- <version>${project.version}</version>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <artifactId>maven-assembly-plugin</artifactId>
- <executions>
- <execution>
- <id>distribution-package</id>
- <phase>package</phase>
- <goals>
- <goal>single</goal>
- </goals>
- <configuration>
- <descriptors>
- <descriptor>src/main/assembly/client-bin-tests.xml</descriptor>
- </descriptors>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
- </profile>
-</profiles>
-
-</project>
diff --git a/java/client/distribution/src/main/assembly/client-bin-tests.xml b/java/client/distribution/src/main/assembly/client-bin-tests.xml
deleted file mode 100644
index ec4df1c9a7..0000000000
--- a/java/client/distribution/src/main/assembly/client-bin-tests.xml
+++ /dev/null
@@ -1,107 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
--->
-<assembly>
- <id>java-client-bin-with-tests</id>
- <includeBaseDirectory>false</includeBaseDirectory>
- <formats>
- <format>tar.gz</format>
- <format>zip</format>
- </formats>
-
- <fileSets>
- <fileSet>
- <!-- Apache license files -->
- <directory>../../resources</directory>
- <outputDirectory>qpid-${qpid.version}</outputDirectory>
- <includes>
- <include>DISCLAIMER</include>
- <include>LICENSE.txt</include>
- <include>NOTICE.txt</include>
- <include>README.txt</include>
- </includes>
- </fileSet>
-
- <fileSet>
- <directory>../../release-docs</directory>
- <outputDirectory>qpid-${qpid.version}/docs</outputDirectory>
- <includes>
- <include>RELEASE_NOTES.txt</include>
- </includes>
- </fileSet>
-
- <!-- Include easy access to test source-->
- <fileSet>
- <directory>../src/test</directory>
- <outputDirectory>qpid-${qpid.version}/src</outputDirectory>
- <includes>
- <include>**/*.java</include>
- </includes>
- </fileSet>
-
- <!-- fileSet> Client contains a readme.txt as does qpid root.
- Which will cause problems on windows as the zip will
- contain: readme.txt and README.txt
- < Client local documentation>
- <directory>..</directory>
- <outputDirectory>qpid-${qpid.version}</outputDirectory>
- <includes>
- <include>*.txt</include>
- </includes>
- </fileSet-->
-
- <!-- Configuration -->
- <fileSet>
- <directory>../test/etc</directory>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <includes>
- <include>**/*</include>
- </includes>
- </fileSet>
-
- <!-- Execution Scripts -->
- <fileSet>
- <directory>../test/bin</directory>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <includes>
- <include>**/*</include>
- </includes>
- <fileMode>777</fileMode> <!-- RWX -->
- </fileSet>
-
- <!-- Metadata Jar -->
- <fileSet>
- <directory>target</directory>
- <outputDirectory>qpid-${qpid.version}/lib</outputDirectory>
- <includes>
- <include>qpid-incubating.jar</include>
- </includes>
- </fileSet>
- </fileSets>
-
- <dependencySets>
- <dependencySet>
- <outputDirectory>qpid-${qpid.version}/lib</outputDirectory>
- <unpack>false</unpack>
- <excludes>
- <exclude>org.apache.qpid:qpid-client-distribution</exclude>
- </excludes>
- </dependencySet>
- </dependencySets>
-</assembly>
diff --git a/java/client/distribution/src/main/assembly/client-bin.xml b/java/client/distribution/src/main/assembly/client-bin.xml
deleted file mode 100644
index 70874b09a4..0000000000
--- a/java/client/distribution/src/main/assembly/client-bin.xml
+++ /dev/null
@@ -1,78 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
--->
-<assembly>
- <id>java-client-bin</id>
- <includeBaseDirectory>false</includeBaseDirectory>
- <formats>
- <format>tar.gz</format>
- <format>zip</format>
- </formats>
-
- <fileSets>
- <fileSet>
- <!-- Apache license files -->
- <directory>../../resources</directory>
- <outputDirectory>qpid-${qpid.version}</outputDirectory>
- <includes>
- <include>DISCLAIMER</include>
- <include>LICENSE.txt</include>
- <include>NOTICE.txt</include>
- <include>README.txt</include>
- </includes>
- </fileSet>
-
- <!--fileSet>
- < Client local documentation>
- <directory>..</directory>
- <outputDirectory>qpid-${qpid.version}</outputDirectory>
- <includes>
- <include>*.txt</include>
- </includes>
- </fileSet-->
-
- <fileSet>
- <directory>../../release-docs</directory>
- <outputDirectory>qpid-${qpid.version}/docs</outputDirectory>
- <includes>
- <include>RELEASE_NOTES.txt</include>
- </includes>
- </fileSet>
-
- <fileSet>
- <directory>target</directory>
- <outputDirectory>qpid-${qpid.version}/lib</outputDirectory>
- <includes>
- <include>qpid-incubating.jar</include>
- </includes>
- </fileSet>
- </fileSets>
-
- <dependencySets>
- <dependencySet>
- <outputDirectory>qpid-${qpid.version}/lib</outputDirectory>
- <unpack>false</unpack>
- <excludes>
- <exclude>org.apache.qpid:qpid-client:jar:java14</exclude>
- <exclude>org.apache.qpid:qpid-common:jar:java14</exclude>
- <exclude>org.apache.qpid:qpid-client-distribution</exclude>
- </excludes>
- </dependencySet>
- </dependencySets>
-</assembly>
diff --git a/java/client/distribution/src/main/assembly/client-java1.4-bin.xml b/java/client/distribution/src/main/assembly/client-java1.4-bin.xml
deleted file mode 100644
index 6a2dd17c5c..0000000000
--- a/java/client/distribution/src/main/assembly/client-java1.4-bin.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
--->
-<!-- Assembly instructions for a client that runs on Java 1.4 -->
-<assembly>
- <id>java-client-java1.4-bin</id>
- <includeBaseDirectory>false</includeBaseDirectory>
- <formats>
- <format>tar.gz</format>
- <format>zip</format>
- </formats>
-
- <fileSets>
- <fileSet>
- <!-- Apache license files -->
- <directory>../../resources</directory>
- <outputDirectory>qpid-${qpid.version}</outputDirectory>
- <includes>
- <include>DISCLAIMER</include>
- <include>LICENSE.txt</include>
- <include>NOTICE.txt</include>
- <include>README.txt</include>
- </includes>
- </fileSet>
-
- <fileSet>
- <directory>../../release-docs</directory>
- <outputDirectory>qpid-${qpid.version}/docs</outputDirectory>
- <includes>
- <include>RELEASE_NOTES.txt</include>
- </includes>
- </fileSet>
-
- <fileSet>
- <directory>target</directory>
- <outputDirectory>qpid-${qpid.version}/lib</outputDirectory>
- <includes>
- <include>qpid-incubating.jar</include>
- </includes>
- </fileSet>
- </fileSets>
-
- <dependencySets>
- <dependencySet>
- <outputDirectory>qpid-${qpid.version}/lib</outputDirectory>
- <unpack>false</unpack>
- <excludes>
- <exclude>org.apache.qpid:qpid-client:jar</exclude>
- <exclude>org.apache.qpid:qpid-common:jar</exclude>
- <exclude>org.apache.qpid:qpid-client-distribution</exclude>
- <exclude>org.apache.mina:mina-java5</exclude>
- <exclude>org.apache.mina:mina-filter-ssl</exclude>
- </excludes>
- </dependencySet>
- </dependencySets>
-</assembly>
-
-
diff --git a/java/client/distribution/src/main/assembly/client-src.xml b/java/client/distribution/src/main/assembly/client-src.xml
deleted file mode 100644
index b5055f05d7..0000000000
--- a/java/client/distribution/src/main/assembly/client-src.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
--->
-<assembly>
- <!-- id typically identifies the "type" (src vs bin etc) of the assembly -->
- <id>java-client-src</id>
- <includeBaseDirectory>false</includeBaseDirectory>
- <formats>
- <format>tar.gz</format>
- <format>zip</format>
- </formats>
-
- <fileSets>
-
- <fileSet>
- <!-- Apache license files -->
- <directory>../../resources</directory>
- <outputDirectory>qpid-${qpid.version}-src</outputDirectory>
- <includes>
- <include>DISCLAIMER</include>
- <include>LICENSE.txt</include>
- <include>NOTICE.txt</include>
- <include>README.txt</include>
- </includes>
- </fileSet>
-
- <fileSet>
- <directory>..</directory>
- <outputDirectory>qpid-${qpid.version}-src</outputDirectory>
- <includes>
- <include>src/main/**</include>
- <include>src/test/**</include>
- <include>test/main/**</include>
- <include>test/test/**</include>
- <include>pom.xml</include>
- <include>distribution/**</include>
- </includes>
- <excludes>
- <exclude>**/target</exclude>
- <exclude>**/target/**/*</exclude>
- <exclude>**/build</exclude>
- <exclude>**/build/**/*</exclude>
- </excludes>
- </fileSet>
- </fileSets>
-</assembly>
diff --git a/java/client/example/bin/verify_all b/java/client/example/bin/verify_all
index 0191ebd80e..e9a9e988c9 100644..100755
--- a/java/client/example/bin/verify_all
+++ b/java/client/example/bin/verify_all
@@ -1,12 +1,36 @@
#!/bin/sh
-export QPID_SRC_HOME=$(cd "$(dirname $0)/../../../.."; pwd)
-export CPP=$QPID_SRC_HOME/cpp/examples/examples
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+echo $QPID_SRC_HOME
+
+if test "'x$QPID_SRC_HOME'" == "'x'"
+then
+ export QPID_SRC_HOME=$(cd "$(dirname $0)/../../../.."; pwd)
+fi
+export CPP=$QPID_SRC_HOME/cpp/examples
export PYTHON=$QPID_SRC_HOME/python/examples
export JAVA=$QPID_SRC_HOME/java/client/example/src/main/java/org/apache/qpid/example/jmsexample
-export AMQP_SPEC=$QPID_SRC_HOME/specs/amqp.0-10.xml
+export AMQP_SPEC=$QPID_SRC_HOME/specs/amqp.0-10-qpid-errata.xml
export PYTHONPATH=$QPID_SRC_HOME/python/
+export LOG4J=file://$QPID_SRC_HOME/java/client/example/src/main/java/log4j.xml
trap cleanup EXIT
@@ -38,4 +62,3 @@ do
$verify $script
stop_broker
done
-
diff --git a/java/client/example/pom.xml b/java/client/example/pom.xml
deleted file mode 100644
index db9aa94ca2..0000000000
--- a/java/client/example/pom.xml
+++ /dev/null
@@ -1,152 +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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-example</artifactId>
- <packaging>jar</packaging>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <name>Qpid Example</name>
- <url>http://cwiki.apache.org/confluence/display/qpid</url>
-
- <parent>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid</artifactId>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <relativePath>../pom.xml</relativePath>
- </parent>
-
- <properties>
- <topDirectoryLocation>../..</topDirectoryLocation>
- <amqj.logging.level>warn</amqj.logging.level>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-common</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-client</artifactId>
- </dependency>
-
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-jms_1.1_spec</artifactId>
- </dependency>
-
- <dependency>
- <groupId>jmscts</groupId>
- <artifactId>jmscts</artifactId>
- <version>0.5-b2</version>
- <scope>test</scope>
- <exclusions>
- <exclusion>
- <groupId>jms</groupId>
- <artifactId>jms</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <systemProperties>
- <property>
- <name>amqj.noAutoCreateVMBroker</name>
- <value>true</value>
- </property>
- <property>
- <name>amqj.logging.level</name>
- <value>${amqj.logging.level}</value>
- </property>
- <property>
- <name>log4j.configuration</name>
- <value>file:///${basedir}/src/main/java/log4j.properties</value>
- </property>
- </systemProperties>
- </configuration>
- </plugin>
-
- <!-- Build a zip file with the source in it, this had to be done with the assembly plugin as the source plugin did not provide a way
- to exclude the .svn directories. -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-assembly-plugin</artifactId>
- <version>2.2-SNAPSHOT</version>
- <configuration>
- <descriptors>
- <descriptor>source-jar.xml</descriptor>
- </descriptors>
- <outputDirectory>target</outputDirectory>
- <workDirectory>target/assembly/work</workDirectory>
- </configuration>
- <executions>
- <execution>
- <id>attach-artifacts</id>
- <phase>package</phase>
- <goals>
- <goal>attached</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
-
- <!-- Publish the source as a build artifact. -->
- <!--
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <executions>
- <execution>
- <id>attach-artifacts</id>
- <phase>package</phase>
- <goals>
- <goal>attach-artifact</goal>
- </goals>
- <configuration>
- <artifacts>
- <artifact>
- <file>target/${project.build.finalName}-source.jar</file>
- <type>jar</type>
- <classifier>source</classifier>
- </artifact>
- </artifacts>
- </configuration>
- </execution>
- </executions>
- </plugin>
- -->
-
- </plugins>
- </build>
-</project>
diff --git a/java/client/example/src/main/java/README.txt b/java/client/example/src/main/java/README.txt
index c8fe6a76ad..c99c3fddec 100644
--- a/java/client/example/src/main/java/README.txt
+++ b/java/client/example/src/main/java/README.txt
@@ -3,15 +3,16 @@ variables, QPID_HOME and QPID_SAMPLE. If not the default values will be used.
QPID_HOME
---------
-This is the distribution directory. You would have set the QPID_HOME when you
-started the Qpid Java broker.
+This is the directory that contains the QPID distribution. If you are running the Qpid
+Java broker on the same machine as the examples, you have already set QPID_HOME to this
+directory.
default: /usr/share/java/
QPID_SAMPLE
-----------
-This is the parent directory of the directory in which you find the runSample.sh
+This is the parent directory of the 'java' directory in which you find 'runSample.sh'
(Ex:- $QPID_SRC_HOME/java/client/example/src/main)
-default: /usr/share/doc/rhm-0.2
+default: $PWD
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/direct/DeclareQueue.java b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/direct/DeclareQueue.java
index b16a7fa7c3..38073cb7f2 100755
--- a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/direct/DeclareQueue.java
+++ b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/direct/DeclareQueue.java
@@ -1,8 +1,28 @@
package org.apache.qpid.example.amqpexample.direct;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
-import org.apache.qpid.nclient.Client;
-import org.apache.qpid.nclient.Connection;
-import org.apache.qpid.nclient.Session;
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.Session;
/**
* This creates a queue a queue and binds it to the
@@ -15,16 +35,8 @@ public class DeclareQueue
public static void main(String[] args)
{
// Create connection
- Connection con = Client.createConnection();
- try
- {
- con.connect("localhost", 5672, "test", "guest", "guest");
- }
- catch(Exception e)
- {
- System.out.print("Error connecting to broker");
- e.printStackTrace();
- }
+ Connection con = new Connection();
+ con.connect("localhost", 5672, "test", "guest", "guest",false);
// Create session
Session session = con.createSession(0);
@@ -37,15 +49,7 @@ public class DeclareQueue
session.sync();
//cleanup
- session.sessionDetach(session.getName());
- try
- {
- con.close();
- }
- catch(Exception e)
- {
- System.out.print("Error closing broker connection");
- e.printStackTrace();
- }
+ session.close();
+ con.close();
}
}
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/direct/DirectProducer.java b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/direct/DirectProducer.java
index 2793e567ea..2234eb22da 100755
--- a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/direct/DirectProducer.java
+++ b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/direct/DirectProducer.java
@@ -1,65 +1,44 @@
package org.apache.qpid.example.amqpexample.direct;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import java.nio.ByteBuffer;
import org.apache.qpid.api.Message;
-import org.apache.qpid.nclient.Client;
-import org.apache.qpid.nclient.Connection;
-import org.apache.qpid.nclient.Session;
-import org.apache.qpid.nclient.util.MessageListener;
+import org.apache.qpid.transport.Connection;
import org.apache.qpid.transport.DeliveryProperties;
import org.apache.qpid.transport.Header;
import org.apache.qpid.transport.MessageAcceptMode;
import org.apache.qpid.transport.MessageAcquireMode;
+import org.apache.qpid.transport.Session;
-public class DirectProducer implements MessageListener
+public class DirectProducer
{
- boolean finish = false;
-
- public void onMessage(Message m)
- {
- String data = null;
-
- try
- {
- ByteBuffer buf = m.readData();
- byte[] b = new byte[buf.remaining()];
- buf.get(b);
- data = new String(b);
- }
- catch(Exception e)
- {
- System.out.print("Error reading message");
- e.printStackTrace();
- }
-
- System.out.println("Message: " + data);
-
-
- if (data != null && data.equals("That's all, folks!"))
- {
- finish = true;
- }
- }
-
- public boolean isFinished()
- {
- return finish;
- }
public static void main(String[] args)
{
// Create connection
- Connection con = Client.createConnection();
- try
- {
- con.connect("localhost", 5672, "test", "guest", "guest");
- }
- catch(Exception e)
- {
- System.out.print("Error connecting to broker");
- e.printStackTrace();
- }
+ Connection con = new Connection();
+ con.connect("localhost", 5672, "test", "guest", "guest",false);
// Create session
Session session = con.createSession(0);
@@ -81,16 +60,8 @@ public class DirectProducer implements MessageListener
session.sync();
//cleanup
- session.sessionDetach(session.getName());
- try
- {
- con.close();
- }
- catch(Exception e)
- {
- System.out.print("Error closing broker connection");
- e.printStackTrace();
- }
+ session.close();
+ con.close();
}
}
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/direct/Listener.java b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/direct/Listener.java
index 081fbf2521..1ac3e85f7a 100755
--- a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/direct/Listener.java
+++ b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/direct/Listener.java
@@ -1,115 +1,105 @@
package org.apache.qpid.example.amqpexample.direct;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
-import java.nio.ByteBuffer;
-import org.apache.qpid.api.Message;
-import org.apache.qpid.nclient.Client;
-import org.apache.qpid.nclient.Connection;
-import org.apache.qpid.nclient.Session;
-import org.apache.qpid.nclient.util.MessageListener;
-import org.apache.qpid.nclient.util.MessagePartListenerAdapter;
+import java.nio.ByteBuffer;
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.MessageAcceptMode;
+import org.apache.qpid.transport.MessageAcquireMode;
import org.apache.qpid.transport.MessageCreditUnit;
+import org.apache.qpid.transport.MessageTransfer;
+import org.apache.qpid.transport.Session;
+import org.apache.qpid.transport.SessionException;
+import org.apache.qpid.transport.SessionListener;
/**
* This listens to messages on a queue and terminates
* when it sees the final message
*
*/
-public class Listener implements MessageListener
+public class Listener implements SessionListener
{
- boolean finish = false;
- public void onMessage(Message m)
+ public void opened(Session ssn) {}
+
+ public void resumed(Session ssn) {}
+
+ public void message(Session ssn, MessageTransfer xfr)
{
- String data = null;
-
- try
- {
- ByteBuffer buf = m.readData();
- byte[] b = new byte[buf.remaining()];
- buf.get(b);
- data = new String(b);
- }
- catch(Exception e)
- {
- System.out.print("Error reading message");
- e.printStackTrace();
- }
-
- System.out.println("Message: " + data);
-
-
- if (data != null && data.equals("That's all, folks!"))
- {
- finish = true;
- }
+ System.out.println("Message: " + xfr);
}
- public boolean isFinished()
+ public void exception(Session ssn, SessionException exc)
{
- return finish;
+ exc.printStackTrace();
}
+ public void closed(Session ssn) {}
+
/**
* This sends 10 messages to the
* amq.direct exchange using the
* routing key as "routing_key"
*
*/
- public static void main(String[] args)
+ public static void main(String[] args) throws InterruptedException
{
// Create connection
- Connection con = Client.createConnection();
- try
- {
- con.connect("localhost", 5672, "test", "guest", "guest");
- }
- catch(Exception e)
- {
- System.out.print("Error connecting to broker");
- e.printStackTrace();
- }
+ Connection con = new Connection();
+ con.connect("localhost", 5672, "test", "guest", "guest",false);
// Create session
Session session = con.createSession(0);
// Create an instance of the listener
Listener listener = new Listener();
+ session.setSessionListener(listener);
// create a subscription
session.messageSubscribe("message_queue",
"listener_destination",
- Session.TRANSFER_CONFIRM_MODE_NOT_REQUIRED,
- Session.TRANSFER_ACQUIRE_MODE_PRE_ACQUIRE,
- new MessagePartListenerAdapter(listener), null);
+ MessageAcceptMode.NONE,
+ MessageAcquireMode.PRE_ACQUIRED,
+ null, 0, null);
// issue credits
// XXX
- session.messageFlow("listener_destination", MessageCreditUnit.BYTE, Session.MESSAGE_FLOW_MAX_BYTES);
+ session.messageFlow("listener_destination", MessageCreditUnit.BYTE, Session.UNLIMITED_CREDIT);
session.messageFlow("listener_destination", MessageCreditUnit.MESSAGE, 11);
// confirm completion
session.sync();
- // check to see if we have received all the messages
- while (!listener.isFinished()){}
+ // wait to receive all the messages
+ System.out.println("Waiting 100 seconds for messages from listener_destination");
+ Thread.sleep(100*1000);
System.out.println("Shutting down listener for listener_destination");
session.messageCancel("listener_destination");
//cleanup
- session.sessionDetach(session.getName());
-
- try
- {
- con.close();
- }
- catch(Exception e)
- {
- System.out.print("Error closing broker connection");
- e.printStackTrace();
- }
+ session.close();
+ con.close();
}
}
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/fanout/DeclareQueue.java b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/fanout/DeclareQueue.java
index 9af5f21e66..9c3ec2fb3b 100755
--- a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/fanout/DeclareQueue.java
+++ b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/fanout/DeclareQueue.java
@@ -1,8 +1,28 @@
package org.apache.qpid.example.amqpexample.fanout;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
-import org.apache.qpid.nclient.Client;
-import org.apache.qpid.nclient.Connection;
-import org.apache.qpid.nclient.Session;
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.Session;
/**
* This creates a queue a queue and binds it to the
@@ -15,16 +35,8 @@ public class DeclareQueue
public static void main(String[] args)
{
// Create connection
- Connection con = Client.createConnection();
- try
- {
- con.connect("localhost", 5672, "test", "guest", "guest");
- }
- catch(Exception e)
- {
- System.out.print("Error connecting to broker");
- e.printStackTrace();
- }
+ Connection con = new Connection();
+ con.connect("localhost", 5672, "test", "guest", "guest",false);
// Create session
Session session = con.createSession(0);
@@ -37,15 +49,7 @@ public class DeclareQueue
session.sync();
//cleanup
- session.sessionDetach(session.getName());
- try
- {
- con.close();
- }
- catch(Exception e)
- {
- System.out.print("Error closing broker connection");
- e.printStackTrace();
- }
+ session.close();
+ con.close();
}
}
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/fanout/FannoutProducer.java b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/fanout/FannoutProducer.java
index 41038d3e53..39d34713c6 100755
--- a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/fanout/FannoutProducer.java
+++ b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/fanout/FannoutProducer.java
@@ -1,12 +1,32 @@
package org.apache.qpid.example.amqpexample.fanout;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
-import org.apache.qpid.nclient.Client;
-import org.apache.qpid.nclient.Connection;
-import org.apache.qpid.nclient.Session;
+
+import org.apache.qpid.transport.Connection;
import org.apache.qpid.transport.DeliveryProperties;
import org.apache.qpid.transport.Header;
import org.apache.qpid.transport.MessageAcceptMode;
import org.apache.qpid.transport.MessageAcquireMode;
+import org.apache.qpid.transport.Session;
public class FannoutProducer
{
@@ -17,16 +37,8 @@ public class FannoutProducer
public static void main(String[] args)
{
// Create connection
- Connection con = Client.createConnection();
- try
- {
- con.connect("localhost", 5672, "test", "guest", "guest");
- }
- catch(Exception e)
- {
- System.out.print("Error connecting to broker");
- e.printStackTrace();
- }
+ Connection con = new Connection();
+ con.connect("localhost", 5672, "test", "guest", "guest",false);
// Create session
Session session = con.createSession(0);
@@ -47,16 +59,8 @@ public class FannoutProducer
session.sync();
//cleanup
- session.sessionDetach(session.getName());
- try
- {
- con.close();
- }
- catch(Exception e)
- {
- System.out.print("Error closing broker connection");
- e.printStackTrace();
- }
+ session.close();
+ con.close();
}
}
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/fanout/Listener.java b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/fanout/Listener.java
index 7942ce5ca3..21f9c43cd2 100755
--- a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/fanout/Listener.java
+++ b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/fanout/Listener.java
@@ -1,115 +1,105 @@
package org.apache.qpid.example.amqpexample.fanout;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
-import java.nio.ByteBuffer;
-import org.apache.qpid.api.Message;
-import org.apache.qpid.nclient.Client;
-import org.apache.qpid.nclient.Connection;
-import org.apache.qpid.nclient.Session;
-import org.apache.qpid.nclient.util.MessageListener;
-import org.apache.qpid.nclient.util.MessagePartListenerAdapter;
+import java.nio.ByteBuffer;
+import org.apache.qpid.transport.Connection;
import org.apache.qpid.transport.MessageAcceptMode;
import org.apache.qpid.transport.MessageAcquireMode;
import org.apache.qpid.transport.MessageCreditUnit;
+import org.apache.qpid.transport.MessageTransfer;
+import org.apache.qpid.transport.Session;
+import org.apache.qpid.transport.SessionException;
+import org.apache.qpid.transport.SessionListener;
/**
* This listens to messages on a queue and terminates
* when it sees the final message
*
*/
-public class Listener implements MessageListener
+public class Listener implements SessionListener
{
- boolean finish = false;
- public void onMessage(Message m)
+ public void opened(Session ssn) {}
+
+ public void resumed(Session ssn) {}
+
+ public void message(Session ssn, MessageTransfer xfr)
{
- String data = null;
-
- try
- {
- ByteBuffer buf = m.readData();
- byte[] b = new byte[buf.remaining()];
- buf.get(b);
- data = new String(b);
- }
- catch(Exception e)
- {
- System.out.print("Error reading message");
- e.printStackTrace();
- }
-
- System.out.println("Message: " + data);
-
- if (data != null && data.equals("That's all, folks!"))
- {
- finish = true;
- }
+ System.out.println("Message: " + xfr);
}
- public boolean isFinished()
+ public void exception(Session ssn, SessionException exc)
{
- return finish;
+ exc.printStackTrace();
}
+ public void closed(Session ssn) {}
+
/**
* This sends 10 messages to the
* amq.direct exchange using the
* routing key as "routing_key"
*
*/
- public static void main(String[] args)
+ public static void main(String[] args) throws InterruptedException
{
// Create connection
- Connection con = Client.createConnection();
- try
- {
- con.connect("localhost", 5672, "test", "guest", "guest");
- }
- catch(Exception e)
- {
- System.out.print("Error connecting to broker");
- e.printStackTrace();
- }
+ Connection con = new Connection();
+ con.connect("localhost", 5672, "test", "guest", "guest",false);
// Create session
Session session = con.createSession(0);
// Create an instance of the listener
Listener listener = new Listener();
+ session.setSessionListener(listener);
// create a subscription
session.messageSubscribe("message_queue",
"listener_destination",
- Session.TRANSFER_CONFIRM_MODE_NOT_REQUIRED,
- Session.TRANSFER_ACQUIRE_MODE_PRE_ACQUIRE,
- new MessagePartListenerAdapter(listener), null);
+ MessageAcceptMode.NONE,
+ MessageAcquireMode.PRE_ACQUIRED,
+ null, 0, null);
// issue credits
// XXX
- session.messageFlow("listener_destination", MessageCreditUnit.BYTE, Session.MESSAGE_FLOW_MAX_BYTES);
+ session.messageFlow("listener_destination", MessageCreditUnit.BYTE, Session.UNLIMITED_CREDIT);
session.messageFlow("listener_destination", MessageCreditUnit.MESSAGE, 11);
// confirm completion
session.sync();
// check to see if we have received all the messages
- while (!listener.isFinished()){}
+ System.out.println("Waiting 100 seconds for messages from listener_destination");
+ Thread.sleep(100*1000);
System.out.println("Shutting down listener for listener_destination");
session.messageCancel("listener_destination");
//cleanup
- session.sessionDetach(session.getName());
- try
- {
- con.close();
- }
- catch(Exception e)
- {
- System.out.print("Error closing broker connection");
- e.printStackTrace();
- }
+ session.close();
+ con.close();
}
}
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/headers/DeclareQueue.java b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/headers/DeclareQueue.java
new file mode 100644
index 0000000000..6fd73a59c4
--- /dev/null
+++ b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/headers/DeclareQueue.java
@@ -0,0 +1,74 @@
+package org.apache.qpid.example.amqpexample.headers;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.Session;
+
+import java.util.Map;
+import java.util.HashMap;
+
+
+public class DeclareQueue
+{
+
+ /**
+ * Creates 2 queues and bind them to an headers exchange. One queue receives messages with both
+ * properties H1 and H2 and the other queue receives messages with either one of those properties.
+ */
+ public static void main(String[] args)
+ {
+ // Create connection
+ Connection con = new Connection();
+ con.connect("localhost", 5672, "test", "guest", "guest",false);
+
+ // Create session
+ Session session = con.createSession(0);
+
+ // declare and bind queues
+ session.queueDeclare("headers_queue_any", null, null);
+ session.queueDeclare("headers_queue_all", null, null);
+ // we need to declare the header: name, type, alternate exchange
+ session.exchangeDeclare("test.headers", "headers", "amq.direct", null);
+ // The matching algorithm is controlled by 'x-match' property
+ // 'x-match' can take one of two values,
+ // (i) 'all' implies that all the other pairs must match the headers
+ // property of a message for that message to be routed (i.e. an AND match)
+ // (ii) 'any' implies that the message should be routed if any of the
+ // fields in the headers property match one of the fields in the arguments table (i.e. an OR match)
+ Map<String, Object> arguments = new HashMap<String, Object>();
+ arguments.put("x-match", "any");
+ arguments.put("h1", "v1");
+ arguments.put("h2", "v2");
+ session.exchangeBind("headers_queue_any", "test.headers", "useless", arguments);
+ arguments = new HashMap<String, Object>();
+ arguments.put("x-match", "all");
+ arguments.put("h1", "v1");
+ arguments.put("h2", "v2");
+ session.exchangeBind("headers_queue_all", "test.headers", "useless", arguments);
+ // confirm completion
+ session.sync();
+ //cleanup
+ session.close();
+ con.close();
+ }
+}
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/headers/Listener.java b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/headers/Listener.java
new file mode 100644
index 0000000000..dff49228a1
--- /dev/null
+++ b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/headers/Listener.java
@@ -0,0 +1,107 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.example.amqpexample.headers;
+
+
+import org.apache.qpid.transport.*;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class Listener implements SessionListener
+{
+ private static CountDownLatch _countDownLatch = new CountDownLatch(1);
+
+ public void opened(Session ssn) {}
+
+ public void resumed(Session ssn) {}
+
+ public void message(Session ssn, MessageTransfer xfr)
+ {
+ String body = xfr.getBodyString();
+ System.out.println("Message: " + body);
+ if ( body.equals("That's all, folks!"))
+ {
+ System.out.println("Received final message");
+ _countDownLatch.countDown();
+ }
+ }
+
+ public void exception(Session ssn, SessionException exc)
+ {
+ exc.printStackTrace();
+ }
+
+ public void closed(Session ssn) {}
+
+ /**
+ * Receives messages from queue ANY and then ALL
+ */
+ public static void main(String[] args) throws InterruptedException
+ {
+ // Create connection
+ Connection con = new Connection();
+ con.connect("localhost", 5672, "test", "guest", "guest",false);
+
+ // Create session
+ Session session = con.createSession(0);
+ // we expect to receive all the messages
+ Consume(session, "headers_queue_any");
+ // we expect to receive only messages that have both properties set.
+ Consume(session, "headers_queue_all");
+
+ //cleanup
+ session.close();
+ con.close();
+ }
+
+ private static void Consume(Session session, String queueName) throws InterruptedException
+ {
+ System.out.println("Consuming messages for queue " + queueName);
+ _countDownLatch = new CountDownLatch(1);
+ // Create an instance of the listener
+ Listener listener = new Listener();
+ session.setSessionListener(listener);
+
+ // create a subscription
+ session.messageSubscribe(queueName,
+ "listener_destination",
+ MessageAcceptMode.NONE,
+ MessageAcquireMode.PRE_ACQUIRED,
+ null, 0, null);
+
+
+ // issue credits
+ session.messageFlow("listener_destination", MessageCreditUnit.BYTE, Session.UNLIMITED_CREDIT);
+ session.messageFlow("listener_destination", MessageCreditUnit.MESSAGE, 100);
+ // confirm completion
+ session.sync();
+
+ // wait to receive all the messages
+ System.out.println("Waiting 100 seconds for messages from queue " + queueName);
+
+ _countDownLatch.await(30, TimeUnit.SECONDS);
+ System.out.println("Shutting down listener for " + queueName);
+ System.out.println("=========================================");
+ session.messageCancel("listener_destination");
+ }
+
+}
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/headers/Producer.java b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/headers/Producer.java
new file mode 100644
index 0000000000..a54069889a
--- /dev/null
+++ b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/headers/Producer.java
@@ -0,0 +1,88 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.example.amqpexample.headers;
+
+import org.apache.qpid.transport.*;
+import java.util.Map;
+import java.util.HashMap;
+
+
+public class Producer
+{
+ /**
+ * Sends 10 messages with a single property and 10 messages
+ * with 2 properties to a headers exchange.
+ */
+ public static void main(String[] args)
+ {
+ // Create connection
+ org.apache.qpid.transport.Connection con = new org.apache.qpid.transport.Connection();
+ con.connect("localhost", 5672, "test", "guest", "guest",false);
+
+ // Create session
+ org.apache.qpid.transport.Session session = con.createSession(0);
+ DeliveryProperties deliveryProps = new DeliveryProperties();
+
+ // set message headers
+ MessageProperties messageProperties = new MessageProperties();
+ Map<String, Object> messageHeaders = new HashMap<String, Object>();
+ // set the message property
+ messageHeaders.put("h1", "v1");
+ messageProperties.setApplicationHeaders(messageHeaders);
+ Header header = new Header(deliveryProps, messageProperties);
+
+ for (int i=0; i<10; i++)
+ {
+ session.messageTransfer("test.headers", MessageAcceptMode.EXPLICIT,MessageAcquireMode.PRE_ACQUIRED,
+ header,
+ "Message H1: " + i);
+ }
+
+ // set message headers
+ messageProperties = new MessageProperties();
+ messageHeaders = new HashMap<String, Object>();
+ // set the message properties
+ messageHeaders.put("h1", "v1");
+ messageHeaders.put("h2", "v2");
+ messageProperties.setApplicationHeaders(messageHeaders);
+ header = new Header(deliveryProps, messageProperties);
+
+ for (int i=0; i<10; i++)
+ {
+ session.messageTransfer("test.headers", MessageAcceptMode.EXPLICIT,MessageAcquireMode.PRE_ACQUIRED,
+ header,
+ "Message H1 and H2: " + i);
+ }
+
+
+ session.messageTransfer("test.headers", MessageAcceptMode.EXPLICIT,MessageAcquireMode.PRE_ACQUIRED,
+ header,
+ "That's all, folks!" );
+
+ // confirm completion
+ session.sync();
+
+ //cleanup
+ session.close();
+ con.close();
+ }
+
+}
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/lvq/DeclareLVQueue.java b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/lvq/DeclareLVQueue.java
new file mode 100644
index 0000000000..86a0f362ad
--- /dev/null
+++ b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/lvq/DeclareLVQueue.java
@@ -0,0 +1,64 @@
+package org.apache.qpid.example.amqpexample.lvq;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.Session;
+
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * This creates a queue a LVQueue with key test and binds it to the
+ * amq.direct exchange
+ *
+ */
+public class DeclareLVQueue
+{
+
+ public static void main(String[] args)
+ {
+ // Create connection
+ Connection con = new Connection();
+ con.connect("localhost", 5672, "test", "guest", "guest",false);
+
+ // Create session
+ Session session = con.createSession(0);
+
+ // declare and bind queue
+ Map<String, Object> arguments = new HashMap<String, Object>();
+ // We use a lvq
+ arguments.put("qpid.last_value_queue", true);
+ // We want this queue to use the key test
+ arguments.put("qpid.LVQ_key", "test");
+ session.queueDeclare("message_queue", null, arguments);
+ session.exchangeBind("message_queue", "amq.direct", "routing_key", null);
+
+ // confirm completion
+ session.sync();
+
+ //cleanup
+ session.close();
+ con.close();
+ }
+}
+
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/lvq/Listener.java b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/lvq/Listener.java
new file mode 100644
index 0000000000..e17d3eef9f
--- /dev/null
+++ b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/lvq/Listener.java
@@ -0,0 +1,115 @@
+package org.apache.qpid.example.amqpexample.lvq;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.MessageAcceptMode;
+import org.apache.qpid.transport.MessageAcquireMode;
+import org.apache.qpid.transport.MessageCreditUnit;
+import org.apache.qpid.transport.MessageTransfer;
+import org.apache.qpid.transport.Session;
+import org.apache.qpid.transport.SessionException;
+import org.apache.qpid.transport.SessionListener;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * This listens to messages on a queue and terminates
+ * when it sees the final message
+ *
+ */
+public class Listener implements SessionListener
+{
+ private static CountDownLatch _countDownLatch = new CountDownLatch(1);
+
+ public void opened(Session ssn) {}
+
+ public void resumed(Session ssn) {}
+
+ public void message(Session ssn, MessageTransfer xfr)
+ {
+ String body = xfr.getBodyString();
+ System.out.println("Message: " + body);
+ if ( body.equals("That's all, folks!"))
+ {
+ System.out.println("Received final message");
+ _countDownLatch.countDown();
+ }
+ }
+
+ public void exception(Session ssn, SessionException exc)
+ {
+ exc.printStackTrace();
+ }
+
+ public void closed(Session ssn) {}
+
+ /**
+ * This sends 10 messages to the
+ * amq.direct exchange using the
+ * routing key as "routing_key"
+ *
+ * @param args
+ */
+ public static void main(String[] args) throws InterruptedException
+ {
+ // Create connection
+ Connection con = new Connection();
+ con.connect("localhost", 5672, "test", "guest", "guest",false);
+
+ // Create session
+ Session session = con.createSession(0);
+
+ // Create an instance of the listener
+ Listener listener = new Listener();
+ session.setSessionListener(listener);
+
+ // create a subscription
+ session.messageSubscribe("message_queue",
+ "listener_destination",
+ MessageAcceptMode.NONE,
+ MessageAcquireMode.PRE_ACQUIRED,
+ null, 0, null);
+
+
+ // issue credits
+ // XXX
+ session.messageFlow("listener_destination", MessageCreditUnit.BYTE, Session.UNLIMITED_CREDIT);
+ session.messageFlow("listener_destination", MessageCreditUnit.MESSAGE, 11);
+
+ // confirm completion
+ session.sync();
+
+ // wait to receive all the messages
+ System.out.println("Waiting 100 seconds for messages from listener_destination");
+
+ _countDownLatch.await(30, TimeUnit.SECONDS);
+ System.out.println("Shutting down listener for listener_destination");
+ session.messageCancel("listener_destination");
+
+ //cleanup
+ session.close();
+ con.close();
+ }
+
+}
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/lvq/Producer.java b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/lvq/Producer.java
new file mode 100644
index 0000000000..482e6a6b11
--- /dev/null
+++ b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/lvq/Producer.java
@@ -0,0 +1,69 @@
+package org.apache.qpid.example.amqpexample.lvq;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+import java.util.Map;
+import java.util.HashMap;
+import org.apache.qpid.transport.*;
+
+public class Producer
+{
+
+ public static void main(String[] args)
+ {
+ // Create connection
+ Connection con = new Connection();
+ con.connect("localhost", 5672, "test", "guest", "guest",false);
+
+ // Create session
+ Session session = con.createSession(0);
+ DeliveryProperties deliveryProps = new DeliveryProperties();
+ deliveryProps.setRoutingKey("routing_key");
+
+ // set message headers
+ MessageProperties messageProperties = new MessageProperties();
+ Map<String, Object> messageHeaders = new HashMap<String, Object>();
+ // set the message key
+ messageHeaders.put("qpid.LVQ_key", "test");
+ messageProperties.setApplicationHeaders(messageHeaders);
+
+ Header header = new Header(deliveryProps, messageProperties);
+
+ for (int i=0; i<10; i++)
+ {
+ session.messageTransfer("amq.direct", MessageAcceptMode.EXPLICIT,MessageAcquireMode.PRE_ACQUIRED,
+ header,
+ "Message " + i);
+ }
+
+ session.messageTransfer("amq.direct", MessageAcceptMode.EXPLICIT,MessageAcquireMode.PRE_ACQUIRED,
+ header,
+ "That's all, folks!");
+
+ // confirm completion
+ session.sync();
+
+ //cleanup
+ session.close();
+ con.close();
+ }
+
+}
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/pubsub/TopicListener.java b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/pubsub/TopicListener.java
index 2e4edfbe6f..dd9307ca84 100755
--- a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/pubsub/TopicListener.java
+++ b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/pubsub/TopicListener.java
@@ -1,64 +1,73 @@
package org.apache.qpid.example.amqpexample.pubsub;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import java.nio.ByteBuffer;
-import org.apache.qpid.api.Message;
-import org.apache.qpid.nclient.Client;
-import org.apache.qpid.nclient.Connection;
-import org.apache.qpid.nclient.Session;
-import org.apache.qpid.nclient.util.MessageListener;
-import org.apache.qpid.nclient.util.MessagePartListenerAdapter;
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.DeliveryProperties;
+import org.apache.qpid.transport.MessageAcceptMode;
+import org.apache.qpid.transport.MessageAcquireMode;
import org.apache.qpid.transport.MessageCreditUnit;
+import org.apache.qpid.transport.MessageTransfer;
import org.apache.qpid.transport.Option;
+import org.apache.qpid.transport.Session;
+import org.apache.qpid.transport.SessionException;
+import org.apache.qpid.transport.SessionListener;
-public class TopicListener implements MessageListener
+public class TopicListener implements SessionListener
{
- boolean finish = false;
- int count = 0;
- public void onMessage(Message m)
+ public void opened(Session ssn) {}
+
+ public void resumed(Session ssn) {}
+
+ public void message(Session ssn, MessageTransfer xfr)
+ {
+ DeliveryProperties dp = xfr.getHeader().get(DeliveryProperties.class);
+ System.out.println("Message: " + xfr + " with routing_key " + dp.getRoutingKey());
+ }
+
+ public void exception(Session ssn, SessionException exc)
{
- String data = null;
-
- try
- {
- ByteBuffer buf = m.readData();
- byte[] b = new byte[buf.remaining()];
- buf.get(b);
- data = new String(b);
- }
- catch(Exception e)
- {
- System.out.print("Error reading message");
- e.printStackTrace();
- }
-
- System.out.println("Message: " + data + " with routing_key " + m.getDeliveryProperties().getRoutingKey());
-
- if (data != null && data.equals("That's all, folks!"))
- {
- count++;
- if (count == 4){
- finish = true;
- }
- }
+ exc.printStackTrace();
}
+ public void closed(Session ssn) {}
+
public void prepareQueue(Session session,String queueName,String bindingKey)
{
session.queueDeclare(queueName, null, null, Option.EXCLUSIVE, Option.AUTO_DELETE);
session.exchangeBind(queueName, "amq.topic", bindingKey, null);
session.exchangeBind(queueName, "amq.topic", "control", null);
- session.messageSubscribe(queueName,queueName,
- Session.TRANSFER_CONFIRM_MODE_NOT_REQUIRED,
- Session.TRANSFER_ACQUIRE_MODE_PRE_ACQUIRE,
- new MessagePartListenerAdapter(this),
- null, Option.NONE);
+ session.messageSubscribe(queueName, queueName,
+ MessageAcceptMode.NONE,
+ MessageAcquireMode.PRE_ACQUIRED,
+ null, 0, null);
// issue credits
// XXX: need to be able to set to null
- session.messageFlow(queueName, MessageCreditUnit.BYTE, Session.MESSAGE_FLOW_MAX_BYTES);
+ session.messageFlow(queueName, MessageCreditUnit.BYTE, Session.UNLIMITED_CREDIT);
session.messageFlow(queueName, MessageCreditUnit.MESSAGE, 24);
}
@@ -67,30 +76,18 @@ public class TopicListener implements MessageListener
session.messageCancel(dest);
}
- public boolean isFinished()
- {
- return finish;
- }
-
- public static void main(String[] args)
+ public static void main(String[] args) throws InterruptedException
{
// Create connection
- Connection con = Client.createConnection();
- try
- {
- con.connect("localhost", 5672, "test", "guest", "guest");
- }
- catch(Exception e)
- {
- System.out.print("Error connecting to broker");
- e.printStackTrace();
- }
+ Connection con = new Connection();
+ con.connect("localhost", 5672, "test", "guest", "guest",false);
// Create session
Session session = con.createSession(0);
// Create an instance of the listener
TopicListener listener = new TopicListener();
+ session.setSessionListener(listener);
listener.prepareQueue(session,"usa", "usa.#");
listener.prepareQueue(session,"europe", "europe.#");
@@ -99,25 +96,19 @@ public class TopicListener implements MessageListener
// confirm completion
session.sync();
- // check to see if we have received all the messages
- while (!listener.isFinished()){}
- System.out.println("Shutting down listener for listener_destination");
+
+ System.out.println("Waiting 100 seconds for messages");
+ Thread.sleep(100*1000);
+
+ System.out.println("Shutting down listeners");
listener.cancelSubscription(session,"usa");
listener.cancelSubscription(session,"europe");
listener.cancelSubscription(session,"news");
listener.cancelSubscription(session,"weather");
//cleanup
- session.sessionDetach(session.getName());
- try
- {
- con.close();
- }
- catch(Exception e)
- {
- System.out.print("Error closing broker connection");
- e.printStackTrace();
- }
+ session.close();
+ con.close();
}
}
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/pubsub/TopicPublisher.java b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/pubsub/TopicPublisher.java
index caec886642..facf08eeca 100755
--- a/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/pubsub/TopicPublisher.java
+++ b/java/client/example/src/main/java/org/apache/qpid/example/amqpexample/pubsub/TopicPublisher.java
@@ -1,15 +1,36 @@
package org.apache.qpid.example.amqpexample.pubsub;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
-import org.apache.qpid.nclient.Client;
-import org.apache.qpid.nclient.Connection;
-import org.apache.qpid.nclient.Session;
+
+import org.apache.qpid.transport.Connection;
import org.apache.qpid.transport.DeliveryProperties;
import org.apache.qpid.transport.Header;
import org.apache.qpid.transport.MessageAcceptMode;
import org.apache.qpid.transport.MessageAcquireMode;
+import org.apache.qpid.transport.Session;
public class TopicPublisher
{
+
public void publishMessages(Session session, String routing_key)
{
// Set the routing key once, we'll use the same routing key for all
@@ -35,16 +56,8 @@ public class TopicPublisher
public static void main(String[] args)
{
// Create connection
- Connection con = Client.createConnection();
- try
- {
- con.connect("localhost", 5672, "test", "guest", "guest");
- }
- catch(Exception e)
- {
- System.out.print("Error connecting to broker");
- e.printStackTrace();
- }
+ Connection con = new Connection();
+ con.connect("localhost", 5672, "test", "guest", "guest",false);
// Create session
Session session = con.createSession(0);
@@ -61,15 +74,7 @@ public class TopicPublisher
session.sync();
//cleanup
- session.sessionDetach(session.getName());
- try
- {
- con.close();
- }
- catch(Exception e)
- {
- System.out.print("Error closing broker connection");
- e.printStackTrace();
- }
+ session.close();
+ con.close();
}
}
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify
index 0541e490b6..7f81a3a57b 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify
+++ b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify
@@ -1,14 +1,33 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
# The JMS producer doesn't create qeueues so utilising the c++ declare_queues
cpp=$CPP/direct
direct_consumer_java()
{
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.direct.Consumer
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.direct.Consumer
}
direct_producer_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.direct.Producer
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.direct.Producer
}
clients $cpp/declare_queues direct_producer_java direct_consumer_java
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify_cpp_java b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify_cpp_java
index d581c4c1aa..a22162e075 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify_cpp_java
+++ b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify_cpp_java
@@ -2,7 +2,7 @@
cpp=$CPP/direct
direct_consumer_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.direct.Consumer
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.direct.Consumer
}
clients $cpp/declare_queues $cpp/direct_producer direct_consumer_java
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify_java_cpp b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify_java_cpp
index 573cac6986..dc4b349808 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify_java_cpp
+++ b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify_java_cpp
@@ -2,7 +2,7 @@
cpp=$CPP/direct
direct_producer_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.direct.Producer
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.direct.Producer
}
clients $cpp/declare_queues direct_producer_java $cpp/listener
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify_java_python b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify_java_python
index 61c033e969..befa34d650 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify_java_python
+++ b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify_java_python
@@ -1,8 +1,8 @@
# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
-py=$PYTHON_EXAMPLES/direct
+py=$PYTHON/direct
direct_producer_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.direct.Producer
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.direct.Producer
}
clients $py/declare_queues.py direct_producer_java $py/direct_consumer.py
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify_python_java b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify_python_java
index 4182331f3f..b22b44b9a6 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify_python_java
+++ b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/direct/verify_python_java
@@ -1,8 +1,8 @@
# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
-py=$PYTHON_EXAMPLES/direct
+py=$PYTHON/direct
direct_consumer_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.direct.Consumer
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.direct.Consumer
}
clients $py/declare_queues.py $py/direct_producer.py direct_consumer_java
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify
index 2edc1ced02..98c866da99 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify
+++ b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify
@@ -1,13 +1,32 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
# The JMS producer doesn't create qeueues so utilising the c++ declare_queues
cpp=$CPP/fanout
fanout_listener_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.fanout.Listener $1
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.fanout.Listener $1
}
fanout_producer_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.fanout.Producer
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.fanout.Producer
}
background "can receive messages" fanout_listener_java fanoutQueue1
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify_cpp_java b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify_cpp_java
index de057ea3b1..ab8d37a0d8 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify_cpp_java
+++ b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify_cpp_java
@@ -3,7 +3,7 @@
cpp=$CPP/fanout
fanout_listener_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.fanout.Listener $1
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.fanout.Listener $1
}
background "can receive messages" fanout_listener_java fanoutQueue1
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify_java_cpp b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify_java_cpp
index dab6114572..df923e6354 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify_java_cpp
+++ b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify_java_cpp
@@ -3,7 +3,7 @@
cpp=$CPP/fanout
fanout_producer_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.fanout.Producer
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.fanout.Producer
}
background "Listening" $cpp/listener
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify_java_python b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify_java_python
index 1641d88354..5f8701882d 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify_java_python
+++ b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify_java_python
@@ -1,9 +1,9 @@
# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
# The JMS producer doesn't create qeueues so utilising the c++ declare_queues
-py=$PYTHON_EXAMPLES/fanout
+py=$PYTHON/fanout
fanout_producer_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.fanout.Producer
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.fanout.Producer
}
background "Subscribed" $py/fanout_consumer.py
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify_python_java b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify_python_java
index 0f05663985..72f263fd3d 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify_python_java
+++ b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/fanout/verify_python_java
@@ -1,9 +1,9 @@
# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
# The JMS producer doesn't create qeueues so utilising the c++ declare_queues
-py=$PYTHON_EXAMPLES/fanout
+py=$PYTHON/fanout
fanout_listener_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.fanout.Listener $1
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.fanout.Listener $1
}
background "can receive messages" fanout_listener_java fanoutQueue1
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify
index cceb565dfc..363af252ad 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify
+++ b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify
@@ -1,12 +1,31 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
cpp=$CPP/pub-sub
topic_listener_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.pubsub.Listener
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.pubsub.Listener
}
topic_publisher_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.pubsub.Publisher
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.pubsub.Publisher
}
background "can receive messages" topic_listener_java
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify_cpp_java b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify_cpp_java
index 9276b3e21b..e73c164b77 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify_cpp_java
+++ b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify_cpp_java
@@ -2,7 +2,7 @@
cpp=$CPP/pub-sub
topic_listener_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.pubsub.Listener
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.pubsub.Listener
}
background "can receive messages" topic_listener_java
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify_java_cpp b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify_java_cpp
index af22b3b82c..0b877566d3 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify_java_cpp
+++ b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify_java_cpp
@@ -2,7 +2,7 @@
cpp=$CPP/pub-sub
topic_publisher_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.pubsub.Publisher
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.pubsub.Publisher
}
background "Listening" $cpp/topic_listener
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify_java_python b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify_java_python
index 3758e0f014..1340fe79eb 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify_java_python
+++ b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify_java_python
@@ -1,8 +1,8 @@
# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
-py=$PYTHON_EXAMPLES/pubsub
+py=$PYTHON/pubsub
topic_publisher_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.pubsub.Publisher
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.pubsub.Publisher
}
background "Queues created" $py/topic_subscriber.py
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify_python_java b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify_python_java
index c2b516f376..b7fba2b3e0 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify_python_java
+++ b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/pubsub/verify_python_java
@@ -1,8 +1,8 @@
# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
-py=$PYTHON_EXAMPLES/pubsub
+py=$PYTHON/pubsub
topic_listener_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.pubsub.Listener
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.pubsub.Listener
}
background "can receive messages" topic_listener_java
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify
index daf84c8ff9..c6caa7239e 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify
+++ b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify
@@ -1,12 +1,31 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
cpp=$CPP/pub-sub
client_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.requestResponse.Client
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.requestResponse.Client
}
server_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.requestResponse.Server
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.requestResponse.Server
}
background "can receive messages" server_java
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify_cpp_java b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify_cpp_java
index 6ef1b3b7e3..c0e788e373 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify_cpp_java
+++ b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify_cpp_java
@@ -3,7 +3,7 @@ cpp=$CPP/request-response
client_java()
{
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.requestResponse.Client
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.requestResponse.Client
}
background "Waiting" $cpp/server
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify_java_cpp b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify_java_cpp
index 2513eb691b..14a8c28000 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify_java_cpp
+++ b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify_java_cpp
@@ -2,11 +2,11 @@
cpp=$CPP/request-response
server_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.requestResponse.Server
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.requestResponse.Server
}
background "can receive messages" server_java
clients $cpp/client
-#ps -ao pid,cmd | awk '/qpid-client-incubating-M3.jar/{ print $1 }' | xargs -r kill
+#ps -ao pid,cmd | awk '/qpid-client-<version>.jar/{ print $1 }' | xargs -r kill
kill %%
outputs "$cpp/client.out | remove_uuid" "server_java.out | remove_uuid"
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify_java_python b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify_java_python
index 0760952527..2d2ec2fc04 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify_java_python
+++ b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify_java_python
@@ -1,8 +1,8 @@
# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
-py=$PYTHON_EXAMPLES/request-response
+py=$PYTHON/request-response
server_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.requestResponse.Server
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.requestResponse.Server
}
background "can receive messages" server_java
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify_python_java b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify_python_java
index 6ea526e914..bcedf168e3 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify_python_java
+++ b/java/client/example/src/main/java/org/apache/qpid/example/jmsexample/requestResponse/verify_python_java
@@ -1,8 +1,8 @@
# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
-py=$PYTHON_EXAMPLES/request-response
+py=$PYTHON/request-response
client_java(){
-java -Dlog4j.configuration=file://"$JAVA"/log4j.xml -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.requestResponse.Client
+java -Dlog4j.configuration=$LOG4J -cp "$CLASSPATH" org.apache.qpid.example.jmsexample.requestResponse.Client
}
background "Request server running" $py/server.py
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/publisher/FileMessageFactory.java b/java/client/example/src/main/java/org/apache/qpid/example/publisher/FileMessageFactory.java
index 1240284a56..04339b2498 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/publisher/FileMessageFactory.java
+++ b/java/client/example/src/main/java/org/apache/qpid/example/publisher/FileMessageFactory.java
@@ -19,7 +19,7 @@
package org.apache.qpid.example.publisher;
-import org.apache.qpid.example.shared.FileUtils;
+import org.apache.qpid.util.FileUtils;
import org.apache.qpid.example.shared.Statics;
import java.io.*;
@@ -42,10 +42,10 @@ public class FileMessageFactory
try
{
_filename = filename;
- _payload = FileUtils.getFileContent(filename);
+ _payload = FileUtils.readFileAsString(filename);
_session = session;
}
- catch (IOException e)
+ catch (Exception e)
{
MessageFactoryException mfe = new MessageFactoryException(e.toString(), e);
throw mfe;
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/publisher/MultiMessageDispatcher.java b/java/client/example/src/main/java/org/apache/qpid/example/publisher/MultiMessageDispatcher.java
new file mode 100644
index 0000000000..a92efe99ac
--- /dev/null
+++ b/java/client/example/src/main/java/org/apache/qpid/example/publisher/MultiMessageDispatcher.java
@@ -0,0 +1,141 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.example.publisher;
+
+import java.io.File;
+
+import javax.jms.JMSException;
+import javax.jms.TextMessage;
+
+
+import org.apache.qpid.example.shared.FileUtils;
+import org.apache.qpid.example.shared.Statics;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+/**
+ * Class that sends parameterised number of message files to the Publisher
+ * Must set properties for host in properties file or uses in vm broker
+ */
+public class MultiMessageDispatcher
+{
+
+ protected static final Logger _logger = LoggerFactory.getLogger(FileMessageDispatcher.class);
+
+ protected static Publisher _publisher = null;
+
+ /**
+ * To use this main method you need to specify a path or file to use for input
+ * This class then uses file contents from the dir/file specified to generate
+ * messages to publish
+ * Intended to be a very simple way to get going with publishing using the broker
+ * @param args - must specify one value, the path to file(s) for publisher
+ */
+ public static void main(String[] args)
+ {
+
+ // Check command line args ok - must provide a path or file for us to dispatch
+ if (args.length < 2)
+ {
+ System.out.println("Usage: MultiMessageDispatcher <numberOfMessagesToSend> <topic(true|false)>" + "");
+ }
+ else
+ {
+ boolean topicPublisher = true;
+
+ try
+ {
+ // publish message(s)
+ topicPublisher = new Boolean(args[1]).booleanValue();
+ publish(new Integer(args[0]).intValue(),topicPublisher);
+
+ // Move payload file(s) to archive location as no error
+ FileUtils.moveFileToNewDir(args[0], System.getProperties().getProperty(Statics.ARCHIVE_PATH));
+ }
+ catch (Exception e)
+ {
+ // log error and exit
+ _logger.error("Error trying to dispatch message: " + e);
+ System.exit(1);
+ }
+ finally
+ {
+
+ cleanup(topicPublisher);
+ }
+ }
+
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Finished dispatching message");
+ }
+
+ System.exit(0);
+ }
+
+ /**
+ * Publish the content of a file or files from a directory as messages
+ * @param numMessages - from main args
+ * @throws javax.jms.JMSException
+ * @throws org.apache.qpid.example.publisher.MessageFactoryException - if cannot create message from file content
+ */
+ public static void publish(int numMessages, boolean topicPublisher) throws JMSException, MessageFactoryException
+ {
+ {
+ // Send the message generated from the payload using the _publisher
+ getPublisher(topicPublisher).sendMessage(numMessages);
+ }
+ }
+
+ /**
+ * Cleanup before exit
+ */
+ public static void cleanup(boolean topicPublisher)
+ {
+ if (getPublisher(topicPublisher) != null)
+ {
+ getPublisher(topicPublisher).cleanup();
+ }
+ }
+
+ /**
+ * @return A Publisher instance
+ */
+ private static Publisher getPublisher(boolean topic)
+ {
+ if (_publisher != null)
+ {
+ return _publisher;
+ }
+
+ if (!topic)
+ {
+ // Create a _publisher
+ _publisher = new Publisher();
+ }
+ else
+ {
+ _publisher = new TopicPublisher();
+ }
+ return _publisher;
+ }
+
+} \ No newline at end of file
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/publisher/Publisher.java b/java/client/example/src/main/java/org/apache/qpid/example/publisher/Publisher.java
index 87fc543dbe..b5f44557a4 100644
--- a/java/client/example/src/main/java/org/apache/qpid/example/publisher/Publisher.java
+++ b/java/client/example/src/main/java/org/apache/qpid/example/publisher/Publisher.java
@@ -20,13 +20,7 @@ package org.apache.qpid.example.publisher;
import org.apache.qpid.client.AMQConnectionFactory;
-import javax.jms.JMSException;
-import javax.jms.Message;
-import javax.jms.DeliveryMode;
-import javax.jms.Queue;
-import javax.jms.MessageProducer;
-import javax.jms.Connection;
-import javax.jms.Session;
+import javax.jms.*;
import javax.naming.InitialContext;
@@ -50,7 +44,7 @@ public class Publisher
protected String _name = "Publisher";
- protected Queue _destination;
+ protected Destination _destination;
protected static final String _defaultDestinationDir = "/tmp";
@@ -70,6 +64,17 @@ public class Publisher
AMQConnectionFactory cf = (AMQConnectionFactory) ctx.lookup("local");
_connection = cf.createConnection();
+ _connection.setExceptionListener(new ExceptionListener()
+ {
+ public void onException(JMSException jmse)
+ {
+ // The connection may have broken invoke reconnect code if available.
+ // The connection may have broken invoke reconnect code if available.
+ System.err.println("ExceptionListener caught: " + jmse);
+ //System.exit(0);
+ }
+ });
+
//create a transactional session
_session = _connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
@@ -93,6 +98,28 @@ public class Publisher
}
/**
+ * Creates and sends the number of messages specified in the param
+ */
+ public void sendMessage(int numMessages)
+ {
+ try
+ {
+ TextMessage txtMessage = _session.createTextMessage("msg");
+ for (int i=0;i<numMessages;i++)
+ {
+ sendMessage(txtMessage);
+ _log.info("Sent: " + i);
+ }
+ }
+ catch (JMSException j)
+ {
+ _log.error("Exception in sendMessage" + j);
+ }
+
+
+ }
+
+ /**
* Publishes a non-persistent message using transacted session
* Note that persistent is the default mode for send - so need to specify for transient
*/
@@ -101,7 +128,7 @@ public class Publisher
try
{
//Send message via our producer which is not persistent
- _producer.send(message, DeliveryMode.NON_PERSISTENT, _producer.getPriority(), _producer.getTimeToLive());
+ _producer.send(message, DeliveryMode.PERSISTENT, _producer.getPriority(), _producer.getTimeToLive());
//commit the message send and close the transaction
_session.commit();
@@ -124,7 +151,7 @@ public class Publisher
}
}
- _log.info(_name + " finished sending message: " + message);
+ //_log.info(_name + " finished sending message: " + message);
return true;
}
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/publisher/TopicPublisher.java b/java/client/example/src/main/java/org/apache/qpid/example/publisher/TopicPublisher.java
new file mode 100644
index 0000000000..8645e41101
--- /dev/null
+++ b/java/client/example/src/main/java/org/apache/qpid/example/publisher/TopicPublisher.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.example.publisher;
+
+import org.apache.qpid.client.BasicMessageProducer;
+import org.apache.qpid.example.shared.InitialContextHelper;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+import javax.jms.*;
+import javax.naming.InitialContext;
+
+/**
+ * Subclass of Publisher which sends messages to a topic destination defined in example.properties
+ */
+public class TopicPublisher extends Publisher
+{
+
+ private static final Logger _log = LoggerFactory.getLogger(Publisher.class);
+
+ public TopicPublisher()
+ {
+ super();
+
+ try
+ {
+ _contextHelper = new InitialContextHelper(null);
+ InitialContext ctx = _contextHelper.getInitialContext();
+
+ //lookup the example topic and use it
+ _destination = (Topic) ctx.lookup("MyTopic");
+
+ //create a message producer
+ _producer = _session.createProducer(_destination);
+ }
+ catch (Exception e)
+ {
+ //argh
+ _log.error("Exception trying to construct TopicPublisher" + e);
+ }
+
+ }
+} \ No newline at end of file
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/simple/reqresp/Client.java b/java/client/example/src/main/java/org/apache/qpid/example/simple/reqresp/Client.java
new file mode 100644
index 0000000000..8a0ff88448
--- /dev/null
+++ b/java/client/example/src/main/java/org/apache/qpid/example/simple/reqresp/Client.java
@@ -0,0 +1,263 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.example.simple.reqresp;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import java.util.Properties;
+import java.util.concurrent.CountDownLatch;
+
+public class Client implements MessageListener
+{
+ final String BROKER = "localhost";
+
+ final String INITIAL_CONTEXT_FACTORY = "org.apache.qpid.jndi.PropertiesFileInitialContextFactory";
+
+ final String CONNECTION_JNDI_NAME = "local";
+ final String CONNECTION_NAME = "amqp://guest:guest@clientid/test?brokerlist='" + BROKER + "'";
+
+ final String QUEUE_JNDI_NAME = "queue";
+ final String QUEUE_NAME = "example.RequestQueue";
+
+
+ private InitialContext _ctx;
+
+ private CountDownLatch _shutdownHook = new CountDownLatch(1);
+
+ public Client()
+ {
+ setupJNDI();
+
+ Connection connection;
+ Session session;
+ Destination responseQueue;
+
+ //Setup the connection. Create producer to sent message and consumer to receive the repsonse.
+ MessageProducer _producer;
+ try
+ {
+ connection = ((ConnectionFactory) lookupJNDI(CONNECTION_JNDI_NAME)).createConnection();
+
+ session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ Destination requestQueue = (Queue) lookupJNDI(QUEUE_JNDI_NAME);
+
+ closeJNDI();
+
+ //Setup a message _producer to send message to the queue the server is consuming from
+ _producer = session.createProducer(requestQueue);
+
+ //Create a temporary queue that this client will listen for responses on then create a consumer
+ //that consumes message from this temporary queue.
+ responseQueue = session.createTemporaryQueue();
+
+ MessageConsumer responseConsumer = session.createConsumer(responseQueue);
+
+ //Set a listener to asynchronously deal with responses.
+ responseConsumer.setMessageListener(this);
+
+ // Now the connection is setup up start it.
+ connection.start();
+ }
+ catch (JMSException e)
+ {
+ System.err.println("Unable to setup connection, client and producer on broker");
+ return;
+ }
+
+ // Setup the message to send
+ TextMessage txtMessage;
+ try
+ {
+ //Now create the actual message you want to send
+ txtMessage = session.createTextMessage("Request Process");
+
+ //Set the reply to field to the temp queue you created above, this is the queue the server will respond to
+ txtMessage.setJMSReplyTo(responseQueue);
+
+ //Set a correlation ID so when you get a response you know which sent message the response is for
+ //If there is never more than one outstanding message to the server then the
+ //same correlation ID can be used for all the messages...if there is more than one outstanding
+ //message to the server you would presumably want to associate the correlation ID with this message
+
+ txtMessage.setJMSCorrelationID(txtMessage.getJMSMessageID());
+ }
+ catch (JMSException e)
+ {
+ System.err.println("Unable to create message");
+ return;
+
+ }
+
+ try
+ {
+ _producer.send(txtMessage);
+ }
+ catch (JMSException e)
+ {
+ //Handle the exception appropriately
+ }
+
+ try
+ {
+ System.out.println("Sent Request Message ID :" + txtMessage.getJMSMessageID());
+ }
+ catch (JMSException e)
+ {
+ //Handle exception more appropriately.
+ }
+
+ //Wait for the return message to arrive
+ try
+ {
+ _shutdownHook.await();
+ }
+ catch (InterruptedException e)
+ {
+ // Ignore this as we are quitting anyway.
+ }
+
+ //Close the connection
+ try
+ {
+ connection.close();
+ }
+ catch (JMSException e)
+ {
+ System.err.println("A problem occured while shutting down the connection : " + e);
+ }
+ }
+
+
+ /**
+ * Implementation of the Message Listener interface.
+ * This is where message will be asynchronously delivered.
+ *
+ * @param message
+ */
+ public void onMessage(Message message)
+ {
+ String messageText;
+ try
+ {
+ if (message instanceof TextMessage)
+ {
+ TextMessage textMessage = (TextMessage) message;
+ messageText = textMessage.getText();
+ System.out.println("messageText = " + messageText);
+ System.out.println("Correlation ID " + message.getJMSCorrelationID());
+
+ _shutdownHook.countDown();
+ }
+ else
+ {
+ System.err.println("Unexpected message delivered");
+ }
+ }
+ catch (JMSException e)
+ {
+ //Handle the exception appropriately
+ }
+ }
+
+ /**
+ * Lookup the specified name in the JNDI Context.
+ *
+ * @param name The string name of the object to lookup
+ *
+ * @return The object or null if nothing exists for specified name
+ */
+ private Object lookupJNDI(String name)
+ {
+ try
+ {
+ return _ctx.lookup(name);
+ }
+ catch (NamingException e)
+ {
+ System.err.println("Error looking up '" + name + "' in JNDI Context:" + e);
+ }
+
+ return null;
+ }
+
+ /**
+ * Setup the JNDI context.
+ *
+ * In this case we are simply using a Properties object to store the pairing information.
+ *
+ * Further details can be found on the wiki site here:
+ *
+ * @see : http://cwiki.apache.org/qpid/how-to-use-jndi.html
+ */
+ private void setupJNDI()
+ {
+ // Set the properties ...
+ Properties properties = new Properties();
+ properties.put(Context.INITIAL_CONTEXT_FACTORY, INITIAL_CONTEXT_FACTORY);
+ properties.put("connectionfactory." + CONNECTION_JNDI_NAME, CONNECTION_NAME);
+ properties.put("queue." + QUEUE_JNDI_NAME, QUEUE_NAME);
+
+ // Create the initial context
+ Context ctx = null;
+ try
+ {
+ _ctx = new InitialContext(properties);
+ }
+ catch (NamingException e)
+ {
+ System.err.println("Error Setting up JNDI Context:" + e);
+ }
+ }
+
+ /** Close the JNDI Context to keep everything happy. */
+ private void closeJNDI()
+ {
+ try
+ {
+ _ctx.close();
+ }
+ catch (NamingException e)
+ {
+ System.err.println("Unable to close JNDI Context : " + e);
+ }
+ }
+
+
+ public static void main(String[] args)
+ {
+ new Client();
+ }
+}
+
diff --git a/java/client/example/src/main/java/org/apache/qpid/example/simple/reqresp/Server.java b/java/client/example/src/main/java/org/apache/qpid/example/simple/reqresp/Server.java
new file mode 100644
index 0000000000..9c284eee97
--- /dev/null
+++ b/java/client/example/src/main/java/org/apache/qpid/example/simple/reqresp/Server.java
@@ -0,0 +1,236 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.example.simple.reqresp;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import java.util.Properties;
+import java.util.concurrent.CountDownLatch;
+import java.io.BufferedReader;
+import java.io.BufferedInputStream;
+import java.io.Reader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+
+public class Server implements MessageListener
+{
+ final String BROKER = "localhost";
+
+ final String INITIAL_CONTEXT_FACTORY = "org.apache.qpid.jndi.PropertiesFileInitialContextFactory";
+
+ final String CONNECTION_JNDI_NAME = "local";
+ final String CONNECTION_NAME = "amqp://guest:guest@clientid/test?brokerlist='" + BROKER + "'";
+
+ final String QUEUE_JNDI_NAME = "queue";
+ final String QUEUE_NAME = "example.RequestQueue";
+
+
+ private InitialContext _ctx;
+ private Session _session;
+ private MessageProducer _replyProducer;
+ private CountDownLatch _shutdownHook = new CountDownLatch(1);
+
+ public Server()
+ {
+ setupJNDI();
+
+ Connection connection;
+ try
+ {
+ connection = ((ConnectionFactory) lookupJNDI(CONNECTION_JNDI_NAME)).createConnection();
+
+ _session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ Destination requestQueue = (Queue) lookupJNDI(QUEUE_JNDI_NAME);
+
+ closeJNDI();
+
+ //Setup a message producer to respond to messages from clients, we will get the destination
+ //to send to from the JMSReplyTo header field from a Message so we MUST set the destination here to null.
+ this._replyProducer = _session.createProducer(null);
+
+ //Set up a consumer to consume messages off of the request queue
+ MessageConsumer consumer = _session.createConsumer(requestQueue);
+ consumer.setMessageListener(this);
+
+ //Now start the connection
+ connection.start();
+ }
+ catch (JMSException e)
+ {
+ //Handle the exception appropriately
+ System.err.println("JMSException occured setting up server :" + e);
+ return;
+ }
+
+ System.out.println("Server process started and waiting for messages.");
+
+ //Wait to process an single message then quit.
+ while (_shutdownHook.getCount() != 0)
+ {
+ try
+ {
+ _shutdownHook.await();
+ }
+ catch (InterruptedException e)
+ {
+ // Ignore this as we are quitting anyway.
+ }
+ }
+
+ //Close the connection
+ try
+ {
+ connection.close();
+ }
+ catch (JMSException e)
+ {
+ System.err.println("A problem occured while shutting down the connection : " + e);
+ }
+ }
+
+ public void onMessage(Message message)
+ {
+ try
+ {
+ TextMessage response = this._session.createTextMessage();
+
+ //Check we have the right message type.
+ if (message instanceof TextMessage)
+ {
+ TextMessage txtMsg = (TextMessage) message;
+ String messageText = txtMsg.getText();
+
+ //Perform the request
+ System.out.println("Received request:" + messageText + " for message :" + message.getJMSMessageID());
+
+ //Set the response back to the client
+ response.setText("Response to Request:" + messageText);
+ }
+
+ //Set the correlation ID from the received message to be the correlation id of the response message
+ //this lets the client identify which message this is a response to if it has more than
+ //one outstanding message to the server
+ response.setJMSCorrelationID(message.getJMSMessageID());
+
+ try
+ {
+ System.out.println("Received message press enter to send response....");
+ new BufferedReader(new InputStreamReader(System.in)).readLine();
+ }
+ catch (IOException e)
+ {
+ //Error attemptying to pause
+ }
+
+ //Send the response to the Destination specified by the JMSReplyTo field of the received message.
+ _replyProducer.send(message.getJMSReplyTo(), response);
+ }
+ catch (JMSException e)
+ {
+ //Handle the exception appropriately
+ }
+
+ _shutdownHook.countDown();
+ }
+
+ /**
+ * Lookup the specified name in the JNDI Context.
+ *
+ * @param name The string name of the object to lookup
+ *
+ * @return The object or null if nothing exists for specified name
+ */
+ private Object lookupJNDI(String name)
+ {
+ try
+ {
+ return _ctx.lookup(name);
+ }
+ catch (NamingException e)
+ {
+ System.err.println("Error looking up '" + name + "' in JNDI Context:" + e);
+ }
+
+ return null;
+ }
+
+ /**
+ * Setup the JNDI context.
+ *
+ * In this case we are simply using a Properties object to store the pairing information.
+ *
+ * Further details can be found on the wiki site here:
+ *
+ * @see : http://cwiki.apache.org/qpid/how-to-use-jndi.html
+ */
+ private void setupJNDI()
+ {
+ // Set the properties ...
+ Properties properties = new Properties();
+ properties.put(Context.INITIAL_CONTEXT_FACTORY, INITIAL_CONTEXT_FACTORY);
+ properties.put("connectionfactory." + CONNECTION_JNDI_NAME, CONNECTION_NAME);
+ properties.put("queue." + QUEUE_JNDI_NAME, QUEUE_NAME);
+
+ // Create the initial context
+ Context ctx = null;
+ try
+ {
+ _ctx = new InitialContext(properties);
+ }
+ catch (NamingException e)
+ {
+ System.err.println("Error Setting up JNDI Context:" + e);
+ }
+ }
+
+ /** Close the JNDI Context to keep everything happy. */
+ private void closeJNDI()
+ {
+ try
+ {
+ _ctx.close();
+ }
+ catch (NamingException e)
+ {
+ System.err.println("Unable to close JNDI Context : " + e);
+ }
+ }
+
+
+ public static void main(String[] args)
+ {
+ new Server();
+ }
+}
diff --git a/java/client/example/src/main/java/runSample.sh b/java/client/example/src/main/java/runSample.sh
index af0dd3ba6c..66338556a5 100755
--- a/java/client/example/src/main/java/runSample.sh
+++ b/java/client/example/src/main/java/runSample.sh
@@ -1,5 +1,25 @@
#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+
# Work out the CLASSPATH divider
UNAME=`uname -s`
case $UNAME in
@@ -23,7 +43,7 @@ if test "'x$QPID_SAMPLE'" != "'x'"
then
QPID_SAMPLE=$QPID_SAMPLE
else
- QPID_SAMPLE="/usr/share/doc/rhm-0.2"
+ QPID_SAMPLE=$PWD
fi
echo "Using QPID_SAMPLE: $QPID_SAMPLE"
diff --git a/java/client/pom.xml b/java/client/pom.xml
deleted file mode 100644
index 2ad41d96cd..0000000000
--- a/java/client/pom.xml
+++ /dev/null
@@ -1,290 +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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-client</artifactId>
- <packaging>jar</packaging>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <name>Qpid Client</name>
- <url>http://cwiki.apache.org/confluence/display/qpid</url>
-
- <parent>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid</artifactId>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <relativePath>../pom.xml</relativePath>
- </parent>
-
- <properties>
- <topDirectoryLocation>..</topDirectoryLocation>
- <java.source.version>1.5</java.source.version>
- <qpid.version>${pom.version}</qpid.version>
- <qpid.targetDir>${project.build.directory}</qpid.targetDir>
- </properties>
-
- <dependencies>
-
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-common</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <version>1.4.0</version>
- </dependency>
-
- <dependency>
- <groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-jms_1.1_spec</artifactId>
- </dependency>
-
- <dependency>
- <groupId>commons-collections</groupId>
- <artifactId>commons-collections</artifactId>
- </dependency>
-
- <dependency>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- </dependency>
-
-
- <!-- Test Dependencies -->
-
- <dependency> <!-- for inVm Broker -->
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-broker</artifactId>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>junit-toolkit</artifactId>
- <scope>test</scope>
- </dependency>
-
- <!-- These need to be included at compile time only, for the retrotranslator verification to find them. -->
- <dependency>
- <groupId>net.sf.retrotranslator</groupId>
- <artifactId>retrotranslator-runtime</artifactId>
- <scope>provided</scope>
- </dependency>
-
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>provided</scope>
- </dependency>
-
- </dependencies>
-
- <build>
- <plugins>
-
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>javacc-maven-plugin</artifactId>
- <version>2.0</version>
- <executions>
- <execution>
- <phase>generate-sources</phase>
- <configuration>
- <sourceDirectory>${basedir}/src/main/grammar</sourceDirectory>
- <outputDirectory>${basedir}/target/generated-sources</outputDirectory>
- <packageName>org.apache.qpid.filter.selector</packageName>
- </configuration>
- <goals>
- <goal>javacc</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
-
- <plugin>
- <artifactId>minijar-maven-plugin</artifactId>
- <groupId>org.codehaus.mojo</groupId>
- <executions>
- <execution>
- <phase>package</phase>
- <goals>
- <goal>ueberjar</goal>
- </goals>
- <configuration>
- <stripUnusedClasses>false</stripUnusedClasses>
- <name>[artifactId]-[version]-single.jar</name>
- <classifier>single</classifier>
- <attach>true</attach>
- </configuration>
- </execution>
- </executions>
- </plugin>
-
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <executions>
- <execution>
- <id>attach-artifacts</id>
- <phase>package</phase>
- <goals>
- <goal>attach-artifact</goal>
- </goals>
- <configuration>
- <artifacts>
- <artifact>
- <file>target/${artifactId}-${version}-single.jar</file>
- <type>jar</type>
- <classifier>single</classifier>
- </artifact>
- </artifacts>
- </configuration>
- </execution>
- </executions>
- </plugin>
-
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-antrun-plugin</artifactId>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <excludes>
- <exclude>**/QpidTestCase.java</exclude>
- </excludes>
- <systemProperties>
- <property>
- <name>amqj.logging.level</name>
- <value>${amqj.logging.level}</value>
- </property>
- <property>
- <name>log4j.configuration</name>
- <value>${log4j.configuration}</value>
- </property>
- <property>
- <name>amqj.noAutoCreateVMBroker</name>
- <value>true</value>
- </property>
- </systemProperties>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <executions>
- <execution>
- <phase>package</phase>
- <goals>
- <goal>test-jar</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
-
- <!-- Backports the module to Java 1.4. This is done during the packaging phase as a transformation of the Jar. -->
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>retrotranslator-maven-plugin</artifactId>
- <executions>
- <execution>
- <id>retro-client</id>
- <goals>
- <goal>translate-project</goal>
- </goals>
- <configuration>
- <destjar>${project.build.directory}/${project.build.finalName}-java14.jar</destjar>
- <verify>${retrotranslator.verify}</verify>
- <verifyClasspath>
- <element>${retrotranslator.1.4-rt-path}</element>
- <element>${retrotranslator.1.4-jce-path}</element>
- <element>${retrotranslator.1.4-jsse-path}</element>
- <element>${retrotranslator.1.4-sasl-path}</element>
- </verifyClasspath>
- <failonwarning>false</failonwarning>
- <classifier>java14</classifier>
- <attach>true</attach>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-javadoc-plugin</artifactId>
- <configuration>
- <excludePackageNames>
- org.apache.qpid.*:org.apache.qpid.njms:org.apache.qpid.njms.*:org.apache.qpid.nclient.impl
- </excludePackageNames>
- <groups>
- <group>
- <title>API</title>
- <packages>org.apache.qpid.nclient</packages>
- </group>
- <group>
- <title>Utility Package</title>
- <packages>org.apache.qpid.nclient.util</packages>
- </group>
- </groups>
- </configuration>
- </plugin>
-
- </plugins>
-
- <testResources>
- <testResource>
- <targetPath>META-INF/</targetPath>
- <filtering>false</filtering>
- <directory>../resources/META-INF</directory>
- <includes>
- <include>**</include>
- </includes>
- </testResource>
-
- <!--
- <testResource>
- <targetPath>src/</targetPath>
- <filtering>false</filtering>
- <directory>src/test/java</directory>
- <includes>
- <include>**/*.java</include>
- </includes>
- </testResource>
- -->
-
- <testResource>
- <targetPath></targetPath>
- <filtering>false</filtering>
- <directory>src/main/java</directory>
- <includes>
- <include>client.log4j</include>
- </includes>
- </testResource>
- </testResources>
-
- </build>
-
-</project>
diff --git a/java/client/src/main/java/client.bnd b/java/client/src/main/java/client.bnd
new file mode 100755
index 0000000000..a8a33532fb
--- /dev/null
+++ b/java/client/src/main/java/client.bnd
@@ -0,0 +1,7 @@
+ver: 0.6.0
+
+Bundle-SymbolicName: qpid-client
+Bundle-Version: ${ver}
+Export-Package: *;version=${ver}
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+
diff --git a/java/client/src/main/java/log4j.xml b/java/client/src/main/java/log4j.xml
new file mode 100644
index 0000000000..c27acba818
--- /dev/null
+++ b/java/client/src/main/java/log4j.xml
@@ -0,0 +1,36 @@
+<!--
+
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+-->
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+ <appender name="console" class="org.apache.log4j.ConsoleAppender">
+ <param name="Target" value="System.out"/>
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%-5p %c{1} - %m%n"/>
+ </layout>
+ </appender>
+
+ <logger name="org.apache.qpid">
+ <level value="warn"/>
+ <appender-ref ref="console" />
+ </logger>
+
+</log4j:configuration>
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQAnyDestination.java b/java/client/src/main/java/org/apache/qpid/client/AMQAnyDestination.java
new file mode 100644
index 0000000000..4bb2c12cc8
--- /dev/null
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQAnyDestination.java
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.client;
+
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.url.BindingURL;
+
+/**
+ * In order to support JMS 1.0 the Qpid implementation maps the
+ * direct exchange to JMS Queue and topic exchange to JMS Topic.
+ *
+ * The JMS 1.1 spec provides a javax.Destination as an abstraction
+ * to represent any type of destination.
+ * The abstract class AMQDestination has most of the functionality
+ * to support any destination defined in AMQP 0-10 spec.
+ */
+public class AMQAnyDestination extends AMQDestination
+{
+ public AMQAnyDestination(BindingURL binding)
+ {
+ super(binding);
+ }
+
+ public AMQAnyDestination(AMQShortString exchangeName,AMQShortString exchangeClass,
+ AMQShortString routingKey,boolean isExclusive,
+ boolean isAutoDelete, AMQShortString queueName,
+ boolean isDurable, AMQShortString[] bindingKeys)
+ {
+ super(exchangeName, exchangeClass, routingKey, isExclusive, isAutoDelete, queueName, isDurable, bindingKeys);
+ }
+
+ @Override
+ public boolean isNameRequired()
+ {
+ return getAMQQueueName() == null;
+ }
+
+}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQAuthenticationException.java b/java/client/src/main/java/org/apache/qpid/client/AMQAuthenticationException.java
index 05ac3dca9e..6bae0166d1 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQAuthenticationException.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQAuthenticationException.java
@@ -39,9 +39,4 @@ public class AMQAuthenticationException extends AMQException
{
super(error, msg, cause);
}
- public boolean isHardError()
- {
- return true;
- }
-
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java b/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java
index f051450260..414638dea4 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java
@@ -26,6 +26,7 @@ import java.util.HashMap;
import java.util.Map;
import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.jms.ConnectionURL;
import org.apache.qpid.url.URLHelper;
import org.apache.qpid.url.URLSyntaxException;
@@ -35,18 +36,15 @@ public class AMQBrokerDetails implements BrokerDetails
private int _port;
private String _transport;
- private Map<String, String> _options;
+ private Map<String, String> _options = new HashMap<String, String>();
private SSLConfiguration _sslConfiguration;
- public AMQBrokerDetails()
- {
- _options = new HashMap<String, String>();
- }
-
+ public AMQBrokerDetails(){}
+
public AMQBrokerDetails(String url) throws URLSyntaxException
- {
- this();
+ {
+
// URL should be of format tcp://host:port?option='value',option='value'
try
{
@@ -81,6 +79,10 @@ public class AMQBrokerDetails implements BrokerDetails
}
}
}
+ else if (url.indexOf("//") == -1)
+ {
+ throw new URLSyntaxException(url, "Missing '//' after the transport In broker URL",transport.length()+1,1);
+ }
}
else
{
@@ -252,6 +254,16 @@ public class AMQBrokerDetails implements BrokerDetails
return BrokerDetails.DEFAULT_CONNECT_TIMEOUT;
}
+
+ public boolean useSSL()
+ {
+ if (_options.containsKey(ConnectionURL.OPTIONS_SSL))
+ {
+ return Boolean.parseBoolean(_options.get(ConnectionURL.OPTIONS_SSL));
+ }
+
+ return false;
+ }
public void setTimeout(long timeout)
{
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java b/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java
index 27294562e5..0b9be5951f 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java
@@ -20,24 +20,21 @@
*/
package org.apache.qpid.client;
-import org.apache.qpid.AMQConnectionFailureException;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.AMQProtocolException;
-import org.apache.qpid.AMQUnresolvedAddressException;
-import org.apache.qpid.client.failover.FailoverException;
-import org.apache.qpid.client.protocol.AMQProtocolHandler;
-import org.apache.qpid.client.configuration.ClientProperties;
-import org.apache.qpid.exchange.ExchangeDefaults;
-import org.apache.qpid.framing.*;
-import org.apache.qpid.jms.BrokerDetails;
-import org.apache.qpid.jms.Connection;
-import org.apache.qpid.jms.ConnectionListener;
-import org.apache.qpid.jms.ConnectionURL;
-import org.apache.qpid.jms.FailoverPolicy;
-import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.url.URLSyntaxException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.net.ConnectException;
+import java.net.UnknownHostException;
+import java.nio.channels.UnresolvedAddressException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import javax.jms.ConnectionConsumer;
import javax.jms.ConnectionMetaData;
@@ -56,17 +53,34 @@ import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.naming.StringRefAddr;
-import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-import java.net.ConnectException;
-import java.net.UnknownHostException;
-import java.nio.channels.UnresolvedAddressException;
-import java.text.MessageFormat;
-import java.util.*;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.qpid.AMQConnectionFailureException;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQProtocolException;
+import org.apache.qpid.AMQUnresolvedAddressException;
+import org.apache.qpid.AMQDisconnectedException;
+import org.apache.qpid.client.configuration.ClientProperties;
+import org.apache.qpid.client.failover.FailoverException;
+import org.apache.qpid.client.failover.FailoverProtectedOperation;
+import org.apache.qpid.client.protocol.AMQProtocolHandler;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.BasicQosBody;
+import org.apache.qpid.framing.BasicQosOkBody;
+import org.apache.qpid.framing.ChannelOpenBody;
+import org.apache.qpid.framing.ChannelOpenOkBody;
+import org.apache.qpid.framing.ProtocolVersion;
+import org.apache.qpid.framing.TxSelectBody;
+import org.apache.qpid.framing.TxSelectOkBody;
+import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.jms.Connection;
+import org.apache.qpid.jms.ConnectionListener;
+import org.apache.qpid.jms.ConnectionURL;
+import org.apache.qpid.jms.FailoverPolicy;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.url.URLSyntaxException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class AMQConnection extends Closeable implements Connection, QueueConnection, TopicConnection, Referenceable
{
@@ -76,6 +90,9 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
private final LinkedHashMap<Integer, AMQSession> _slowAccessSessions = new LinkedHashMap<Integer, AMQSession>();
private int _size = 0;
private static final int FAST_CHANNEL_ACCESS_MASK = 0xFFFFFFF0;
+ private AtomicInteger _idFactory = new AtomicInteger(0);
+ private int _maxChannelID;
+ private boolean _cycledIds;
public AMQSession get(int channelId)
{
@@ -165,11 +182,57 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
_fastAccessSessions[i] = null;
}
}
+
+ /*
+ * Synchronized on whole method so that we don't need to consider the
+ * increment-then-reset path in too much detail
+ */
+ public synchronized int getNextChannelId()
+ {
+ int id = 0;
+ if (!_cycledIds)
+ {
+ id = _idFactory.incrementAndGet();
+ if (id == _maxChannelID)
+ {
+ _cycledIds = true;
+ _idFactory.set(0); // Go back to the start
+ }
+ }
+ else
+ {
+ boolean done = false;
+ while (!done)
+ {
+ // Needs to work second time through
+ id = _idFactory.incrementAndGet();
+ if (id > _maxChannelID)
+ {
+ _idFactory.set(0);
+ id = _idFactory.incrementAndGet();
+ }
+ if ((id & FAST_CHANNEL_ACCESS_MASK) == 0)
+ {
+ done = (_fastAccessSessions[id] == null);
+ }
+ else
+ {
+ done = (!_slowAccessSessions.keySet().contains(id));
+ }
+ }
+ }
+
+ return id;
+ }
+
+ public void setMaxChannelID(int maxChannelID)
+ {
+ _maxChannelID = maxChannelID;
+ }
}
private static final Logger _logger = LoggerFactory.getLogger(AMQConnection.class);
- protected AtomicInteger _idFactory = new AtomicInteger(0);
/**
* This is the "root" mutex that must be held when doing anything that could be impacted by failover. This must be
@@ -245,16 +308,22 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
/** Thread Pool for executing connection level processes. Such as returning bounced messages. */
private final ExecutorService _taskPool = Executors.newCachedThreadPool();
private static final long DEFAULT_TIMEOUT = 1000 * 30;
- private ProtocolVersion _protocolVersion = ProtocolVersion.v0_9; // FIXME TGM, shouldn't need this
protected AMQConnectionDelegate _delegate;
// this connection maximum number of prefetched messages
- private long _maxPrefetch;
+ private int _maxPrefetch;
//Indicates whether persistent messages are synchronized
private boolean _syncPersistence;
+ //Indicates whether we need to sync on every message ack
+ private boolean _syncAck;
+
+ //Indicates the sync publish options (persistent|all)
+ //By default it's async publish
+ private String _syncPublish = "";
+
/**
* @param broker brokerdetails
* @param username username
@@ -335,37 +404,76 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
public AMQConnection(ConnectionURL connectionURL, SSLConfiguration sslConfig) throws AMQException
{
// set this connection maxPrefetch
- if (connectionURL.getOption(ConnectionURL.AMQ_MAXPREFETCH) != null)
+ if (connectionURL.getOption(ConnectionURL.OPTIONS_MAXPREFETCH) != null)
{
- _maxPrefetch = Long.parseLong(connectionURL.getOption(ConnectionURL.AMQ_MAXPREFETCH));
+ _maxPrefetch = Integer.parseInt(connectionURL.getOption(ConnectionURL.OPTIONS_MAXPREFETCH));
}
else
{
// use the defaul value set for all connections
- _maxPrefetch = Long.valueOf(System.getProperties().getProperty(ClientProperties.MAX_PREFETCH_PROP_NAME,
- ClientProperties.MAX_PREFETCH_DEFAULT));
+ _maxPrefetch = Integer.parseInt(System.getProperties().getProperty(ClientProperties.MAX_PREFETCH_PROP_NAME,
+ ClientProperties.MAX_PREFETCH_DEFAULT));
}
- if (connectionURL.getOption(ConnectionURL.AMQ_SYNC_PERSISTENCE) != null)
+ if (connectionURL.getOption(ConnectionURL.OPTIONS_SYNC_PERSISTENCE) != null)
{
- _syncPersistence = Boolean.parseBoolean(connectionURL.getOption(ConnectionURL.AMQ_SYNC_PERSISTENCE));
+ _syncPersistence =
+ Boolean.parseBoolean(connectionURL.getOption(ConnectionURL.OPTIONS_SYNC_PERSISTENCE));
+ _logger.warn("sync_persistence is a deprecated property, " +
+ "please use sync_publish={persistent|all} instead");
}
else
{
// use the defaul value set for all connections
_syncPersistence = Boolean.getBoolean(ClientProperties.SYNC_PERSISTENT_PROP_NAME);
+ if (_syncPersistence)
+ {
+ _logger.warn("sync_persistence is a deprecated property, " +
+ "please use sync_publish={persistent|all} instead");
+ }
}
- _failoverPolicy = new FailoverPolicy(connectionURL);
- BrokerDetails brokerDetails = _failoverPolicy.getNextBrokerDetails();
- if (brokerDetails.getTransport().equals(BrokerDetails.VM))
+ if (connectionURL.getOption(ConnectionURL.OPTIONS_SYNC_ACK) != null)
+ {
+ _syncAck = Boolean.parseBoolean(connectionURL.getOption(ConnectionURL.OPTIONS_SYNC_ACK));
+ }
+ else
+ {
+ // use the defaul value set for all connections
+ _syncAck = Boolean.getBoolean(ClientProperties.SYNC_ACK_PROP_NAME);
+ }
+
+ if (connectionURL.getOption(ConnectionURL.OPTIONS_SYNC_PUBLISH) != null)
+ {
+ _syncPublish = connectionURL.getOption(ConnectionURL.OPTIONS_SYNC_PUBLISH);
+ }
+ else
+ {
+ // use the default value set for all connections
+ _syncPublish = System.getProperty((ClientProperties.SYNC_ACK_PROP_NAME),_syncPublish);
+ }
+
+ String amqpVersion = System.getProperty((ClientProperties.AMQP_VERSION), "0-10");
+
+ _failoverPolicy = new FailoverPolicy(connectionURL, this);
+ BrokerDetails brokerDetails = _failoverPolicy.getCurrentBrokerDetails();
+ if (brokerDetails.getTransport().equals(BrokerDetails.VM) || "0-8".equals(amqpVersion))
{
_delegate = new AMQConnectionDelegate_8_0(this);
+ }
+ else if ("0-9".equals(amqpVersion))
+ {
+ _delegate = new AMQConnectionDelegate_0_9(this);
+ }
+ else if ("0-91".equals(amqpVersion) || "0-9-1".equals(amqpVersion))
+ {
+ _delegate = new AMQConnectionDelegate_9_1(this);
}
else
{
_delegate = new AMQConnectionDelegate_0_10(this);
}
+ _sessions.setMaxChannelID(_delegate.getMaxChannelID());
if (_logger.isInfoEnabled())
{
@@ -413,7 +521,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
boolean retryAllowed = true;
Exception connectionException = null;
- while (!_connected && retryAllowed)
+ while (!_connected && retryAllowed && brokerDetails != null)
{
ProtocolVersion pe = null;
try
@@ -439,7 +547,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
}
else if (!_connected)
{
- retryAllowed = _failoverPolicy.failoverAllowed();
+ retryAllowed = _failoverPolicy.failoverAllowed();
brokerDetails = _failoverPolicy.getNextBrokerDetails();
}
}
@@ -458,7 +566,6 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
if (connectionException.getCause() != null)
{
message = connectionException.getCause().getMessage();
- connectionException.getCause().printStackTrace();
}
else
{
@@ -518,6 +625,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
Class partypes[] = new Class[1];
partypes[0] = AMQConnection.class;
_delegate = (AMQConnectionDelegate) c.getConstructor(partypes).newInstance(this);
+ _sessions.setMaxChannelID(_delegate.getMaxChannelID());
}
catch (ClassNotFoundException e)
{
@@ -591,12 +699,12 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
public boolean attemptReconnection()
{
- while (_failoverPolicy.failoverAllowed())
+ BrokerDetails broker = null;
+ while (_failoverPolicy.failoverAllowed() && (broker = _failoverPolicy.getNextBrokerDetails()) != null)
{
try
{
- makeBrokerConnection(_failoverPolicy.getNextBrokerDetails());
-
+ makeBrokerConnection(broker);
return true;
}
catch (Exception e)
@@ -628,6 +736,11 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
return _delegate.makeBrokerConnection(brokerDetail);
}
+ public <T, E extends Exception> T executeRetrySupport(FailoverProtectedOperation<T,E> operation) throws E
+ {
+ return _delegate.executeRetrySupport(operation);
+ }
+
/**
* Get the details of the currently active broker
*
@@ -653,7 +766,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
public org.apache.qpid.jms.Session createSession(final boolean transacted, final int acknowledgeMode) throws JMSException
{
- return createSession(transacted, acknowledgeMode, AMQSession.DEFAULT_PREFETCH_HIGH_MARK);
+ return createSession(transacted, acknowledgeMode, _maxPrefetch);
}
public org.apache.qpid.jms.Session createSession(final boolean transacted, final int acknowledgeMode, final int prefetch)
@@ -871,7 +984,12 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
{
if (!_closed.getAndSet(true))
{
- doClose(sessions, timeout);
+ _closing.set(true);
+ try{
+ doClose(sessions, timeout);
+ }finally{
+ _closing.set(false);
+ }
}
}
@@ -917,7 +1035,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
// adjust timeout
timeout = adjustTimeout(timeout, startCloseTime);
- _delegate.closeConneciton(timeout);
+ _delegate.closeConnection(timeout);
//If the taskpool hasn't shutdown by now then give it shutdownNow.
// This will interupt any running tasks.
@@ -932,6 +1050,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
}
catch (AMQException e)
{
+ _logger.error("error:", e);
JMSException jmse = new JMSException("Error closing connection: " + e);
jmse.setLinkedException(e);
throw jmse;
@@ -1191,6 +1310,11 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
return _failoverMutex;
}
+ public void failoverPrep()
+ {
+ _delegate.failoverPrep();
+ }
+
public void resubscribeSessions() throws JMSException, AMQException, FailoverException
{
_delegate.resubscribeSessions();
@@ -1245,6 +1369,17 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
else
{
//Should never get here as all AMQEs are required to have an ErrorCode!
+ // Other than AMQDisconnectedEx!
+
+ if (cause instanceof AMQDisconnectedException)
+ {
+ Exception last = _protocolHandler.getStateManager().getLastException();
+ if (last != null)
+ {
+ _logger.info("StateManager had an exception for us to use a cause of our Disconnected Exception");
+ cause = last;
+ }
+ }
je = new JMSException("Exception thrown against " + toString() + ": " + cause);
}
@@ -1259,8 +1394,10 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
// in the case of an IOException, MINA has closed the protocol session so we set _closed to true
// so that any generic client code that tries to close the connection will not mess up this error
// handling sequence
- if (cause instanceof IOException)
+ if (cause instanceof IOException || cause instanceof AMQDisconnectedException)
{
+ // If we have an IOE/AMQDisconnect there is no connection to close on.
+ _closing.set(false);
closer = !_closed.getAndSet(true);
_protocolHandler.getProtocolSession().notifyError(je);
@@ -1317,7 +1454,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
_sessions.put(channelId, session);
}
- void deregisterSession(int channelId)
+ public void deregisterSession(int channelId)
{
_sessions.remove(channelId);
}
@@ -1411,13 +1548,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
public ProtocolVersion getProtocolVersion()
{
- return _protocolVersion;
- }
-
- public void setProtocolVersion(ProtocolVersion protocolVersion)
- {
- _protocolVersion = protocolVersion;
- _protocolHandler.getProtocolSession().setProtocolVersion(protocolVersion);
+ return _delegate.getProtocolVersion();
}
public boolean isFailingOver()
@@ -1444,4 +1575,27 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect
{
return _syncPersistence;
}
+
+ /**
+ * Indicates whether we need to sync on every message ack
+ */
+ public boolean getSyncAck()
+ {
+ return _syncAck;
+ }
+
+ public String getSyncPublish()
+ {
+ return _syncPublish;
+ }
+
+ public void setIdleTimeout(long l)
+ {
+ _delegate.setIdleTimeout(l);
+ }
+
+ public int getNextChannelID()
+ {
+ return _sessions.getNextChannelId();
+ }
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java
index 7f36ec6e99..23dc244dee 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java
@@ -27,20 +27,40 @@ import javax.jms.XASession;
import org.apache.qpid.AMQException;
import org.apache.qpid.client.failover.FailoverException;
+import org.apache.qpid.client.failover.FailoverProtectedOperation;
import org.apache.qpid.framing.ProtocolVersion;
import org.apache.qpid.jms.BrokerDetails;
import org.apache.qpid.jms.Session;
public interface AMQConnectionDelegate
{
- public ProtocolVersion makeBrokerConnection(BrokerDetails brokerDetail) throws IOException, AMQException;
+ ProtocolVersion makeBrokerConnection(BrokerDetails brokerDetail) throws IOException, AMQException;
- public Session createSession(final boolean transacted, final int acknowledgeMode,
- final int prefetchHigh, final int prefetchLow) throws JMSException;
+ Session createSession(final boolean transacted, final int acknowledgeMode,
+ final int prefetchHigh, final int prefetchLow) throws JMSException;
- public XASession createXASession(int prefetchHigh, int prefetchLow) throws JMSException;
+ /**
+ * Create an XASession with default prefetch values of:
+ * High = MaxPrefetch
+ * Low = MaxPrefetch / 2
+ * @return XASession
+ * @throws JMSException thrown if there is a problem creating the session.
+ */
+ XASession createXASession() throws JMSException;
- public void resubscribeSessions() throws JMSException, AMQException, FailoverException;
+ XASession createXASession(int prefetchHigh, int prefetchLow) throws JMSException;
- public void closeConneciton(long timeout) throws JMSException, AMQException;
+ void failoverPrep();
+
+ void resubscribeSessions() throws JMSException, AMQException, FailoverException;
+
+ void closeConnection(long timeout) throws JMSException, AMQException;
+
+ <T, E extends Exception> T executeRetrySupport(FailoverProtectedOperation<T,E> operation) throws E;
+
+ void setIdleTimeout(long l);
+
+ int getMaxChannelID();
+
+ ProtocolVersion getProtocolVersion();
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java
index a2df2f3cf2..af21eb7ed0 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java
@@ -1,26 +1,52 @@
package org.apache.qpid.client;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.XASession;
import org.apache.qpid.AMQException;
-import org.apache.qpid.AMQProtocolException;
-import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.client.configuration.ClientProperties;
import org.apache.qpid.client.failover.FailoverException;
+import org.apache.qpid.client.failover.FailoverProtectedOperation;
import org.apache.qpid.framing.ProtocolVersion;
import org.apache.qpid.jms.BrokerDetails;
import org.apache.qpid.jms.Session;
-import org.apache.qpid.nclient.Client;
-import org.apache.qpid.nclient.ClosedListener;
-import org.apache.qpid.ErrorCode;
-import org.apache.qpid.QpidException;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.ConnectionClose;
+import org.apache.qpid.transport.ConnectionException;
+import org.apache.qpid.transport.ConnectionListener;
import org.apache.qpid.transport.ProtocolVersionException;
+import org.apache.qpid.transport.TransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, ClosedListener
+public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, ConnectionListener
{
/**
* This class logger.
@@ -35,12 +61,15 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Closed
/**
* The QpidConeection instance that is mapped with thie JMS connection.
*/
- org.apache.qpid.nclient.Connection _qpidConnection;
+ org.apache.qpid.transport.Connection _qpidConnection;
+ private ConnectionException exception = null;
//--- constructor
public AMQConnectionDelegate_0_10(AMQConnection conn)
{
_conn = conn;
+ _qpidConnection = new Connection();
+ _qpidConnection.setConnectionListener(this);
}
/**
@@ -50,7 +79,7 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Closed
throws JMSException
{
_conn.checkNotClosed();
- int channelId = _conn._idFactory.incrementAndGet();
+ int channelId = _conn.getNextChannelID();
AMQSession session;
try
{
@@ -71,12 +100,24 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Closed
}
/**
+ * Create an XASession with default prefetch values of:
+ * High = MaxPrefetch
+ * Low = MaxPrefetch / 2
+ * @return XASession
+ * @throws JMSException
+ */
+ public XASession createXASession() throws JMSException
+ {
+ return createXASession((int) _conn.getMaxPrefetch(), (int) _conn.getMaxPrefetch() / 2);
+ }
+
+ /**
* create an XA Session and start it if required.
*/
public XASession createXASession(int prefetchHigh, int prefetchLow) throws JMSException
{
_conn.checkNotClosed();
- int channelId = _conn._idFactory.incrementAndGet();
+ int channelId = _conn.getNextChannelID();
XASessionImpl session;
try
{
@@ -104,70 +145,165 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Closed
*/
public ProtocolVersion makeBrokerConnection(BrokerDetails brokerDetail) throws IOException, AMQException
{
- _qpidConnection = Client.createConnection();
try
{
if (_logger.isDebugEnabled())
{
- _logger.debug("creating connection with broker " + " host: " + brokerDetail
- .getHost() + " port: " + brokerDetail.getPort() + " virtualhost: " + _conn
- .getVirtualHost() + "user name: " + _conn.getUsername() + "password: " + _conn.getPassword());
+ _logger.debug("connecting to host: " + brokerDetail.getHost() +
+ " port: " + brokerDetail.getPort() +
+ " vhost: " + _conn.getVirtualHost() +
+ " username: " + _conn.getUsername() +
+ " password: " + _conn.getPassword());
+ }
+
+ if (brokerDetail.getProperty(BrokerDetails.OPTIONS_IDLE_TIMEOUT) != null)
+ {
+ this.setIdleTimeout(Long.parseLong(brokerDetail.getProperty(BrokerDetails.OPTIONS_IDLE_TIMEOUT)));
}
+ else
+ {
+ // use the default value set for all connections
+ this.setIdleTimeout(Long.getLong(ClientProperties.IDLE_TIMEOUT_PROP_NAME,0));
+ }
+
+ String saslMechs = brokerDetail.getProperty("sasl_mechs")!= null?
+ brokerDetail.getProperty("sasl_mechs"):
+ System.getProperty("qpid.sasl_mechs","PLAIN");
+
_qpidConnection.connect(brokerDetail.getHost(), brokerDetail.getPort(), _conn.getVirtualHost(),
- _conn.getUsername(), _conn.getPassword());
- _qpidConnection.setClosedListener(this);
+ _conn.getUsername(), _conn.getPassword(), brokerDetail.useSSL(),saslMechs);
_conn._connected = true;
+ _conn._failoverPolicy.attainedConnection();
}
catch(ProtocolVersionException pe)
{
return new ProtocolVersion(pe.getMajor(), pe.getMinor());
}
- catch (QpidException e)
- {
+ catch (ConnectionException e)
+ {
throw new AMQException(AMQConstant.CHANNEL_ERROR, "cannot connect to broker", e);
}
return null;
}
- /**
- * Not supported at this level.
- */
+ public void failoverPrep()
+ {
+ List<AMQSession> sessions = new ArrayList<AMQSession>(_conn.getSessions().values());
+ for (AMQSession s : sessions)
+ {
+ s.failoverPrep();
+ }
+ }
+
public void resubscribeSessions() throws JMSException, AMQException, FailoverException
{
- //NOT implemented as railover is handled at a lower level
- throw new FailoverException("failing to reconnect during failover, operation not supported.");
+ List<AMQSession> sessions = new ArrayList<AMQSession>(_conn.getSessions().values());
+ _logger.info(String.format("Resubscribing sessions = %s sessions.size=%s", sessions, sessions.size()));
+ for (AMQSession s : sessions)
+ {
+ ((AMQSession_0_10) s)._qpidConnection = _qpidConnection;
+ s.resubscribe();
+ }
}
- public void closeConneciton(long timeout) throws JMSException, AMQException
+ public void closeConnection(long timeout) throws JMSException, AMQException
{
try
{
_qpidConnection.close();
}
- catch (QpidException e)
+ catch (TransportException e)
+ {
+ throw new AMQException(e.getMessage(), e);
+ }
+ }
+
+ public void opened(Connection conn) {}
+
+ public void exception(Connection conn, ConnectionException exc)
+ {
+ if (exception != null)
{
- throw new AMQException(AMQConstant.CHANNEL_ERROR, "cannot close connection", e);
+ _logger.error("previous exception", exception);
}
+ exception = exc;
}
- public void onClosed(ErrorCode errorCode, String reason, Throwable t)
+ public void closed(Connection conn)
{
- if (_logger.isDebugEnabled())
+ ConnectionException exc = exception;
+ exception = null;
+
+ if (exc == null)
+ {
+ return;
+ }
+
+ ConnectionClose close = exc.getClose();
+ if (close == null)
+ {
+ try
+ {
+ if (_conn.firePreFailover(false) && _conn.attemptReconnection())
+ {
+ _conn.failoverPrep();
+ _qpidConnection.resume();
+ _conn.fireFailoverComplete();
+ return;
+ }
+ }
+ catch (Exception e)
+ {
+ _logger.error("error during failover", e);
+ }
+ }
+
+ ExceptionListener listener = _conn._exceptionListener;
+ if (listener == null)
{
- _logger.debug("Received a connection close from the broker: Error code : " + errorCode.getCode(), t);
+ _logger.error("connection exception: " + conn, exc);
}
- if (_conn._exceptionListener != null)
+ else
{
- JMSException ex = new JMSException(reason,String.valueOf(errorCode.getCode()));
- if (t != null)
+ String code = null;
+ if (close != null)
{
- ex.initCause(t);
+ code = close.getReplyCode().toString();
}
- _conn._exceptionListener.onException(ex);
+ JMSException ex = new JMSException(exc.getMessage(), code);
+ ex.initCause(exc);
+ listener.onException(ex);
+ }
+ }
+
+ public <T, E extends Exception> T executeRetrySupport(FailoverProtectedOperation<T,E> operation) throws E
+ {
+ try
+ {
+ return operation.execute();
}
+ catch (FailoverException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void setIdleTimeout(long l)
+ {
+ _qpidConnection.setIdleTimeout(l);
+ }
+
+ public int getMaxChannelID()
+ {
+ return Integer.MAX_VALUE;
+ }
+
+ public ProtocolVersion getProtocolVersion()
+ {
+ return ProtocolVersion.v0_10;
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_9.java b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_9.java
index d95e2e3dff..70ecedfd8b 100755
--- a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_9.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_9.java
@@ -20,6 +20,8 @@
*/
package org.apache.qpid.client;
+import org.apache.qpid.framing.ProtocolVersion;
+
public class AMQConnectionDelegate_0_9 extends AMQConnectionDelegate_8_0
{
@@ -28,5 +30,11 @@ public class AMQConnectionDelegate_0_9 extends AMQConnectionDelegate_8_0
{
super(conn);
}
+
+ @Override
+ public ProtocolVersion getProtocolVersion()
+ {
+ return ProtocolVersion.v0_9;
+ }
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java
index 2ec8737d16..6f44f68b37 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java
@@ -48,7 +48,6 @@ import org.apache.qpid.framing.TxSelectBody;
import org.apache.qpid.framing.TxSelectOkBody;
import org.apache.qpid.jms.BrokerDetails;
import org.apache.qpid.jms.ChannelLimitReachedException;
-import org.apache.qpid.transport.network.io.IoTransport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -58,7 +57,7 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
private AMQConnection _conn;
- public void closeConneciton(long timeout) throws JMSException, AMQException
+ public void closeConnection(long timeout) throws JMSException, AMQException
{
_conn.getProtocolHandler().closeConnection(timeout);
@@ -90,15 +89,15 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
StateWaiter waiter = _conn._protocolHandler.createWaiter(openOrClosedStates);
// TODO: use system property thingy for this
- if (System.getProperty("UseTransportIo", "false").equals("false"))
+ if (System.getProperty("UseTransportIo", "false").equals("false"))
{
TransportConnection.getInstance(brokerDetail).connect(_conn._protocolHandler, brokerDetail);
- }
- else
+ }
+ else
{
_conn.getProtocolHandler().createIoTransportSession(brokerDetail);
}
-
+ _conn._protocolHandler.getProtocolSession().init();
// this blocks until the connection has been set up or when an error
// has prevented the connection being set up
@@ -108,9 +107,13 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
{
_conn._failoverPolicy.attainedConnection();
_conn._connected = true;
+ return null;
+ }
+ else
+ {
+ return _conn._protocolHandler.getSuggestedProtocolVersion();
}
- return null;
}
public org.apache.qpid.jms.Session createSession(final boolean transacted, final int acknowledgeMode, final int prefetch)
@@ -139,7 +142,7 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
{
public org.apache.qpid.jms.Session execute() throws JMSException, FailoverException
{
- int channelId = _conn._idFactory.incrementAndGet();
+ int channelId = _conn.getNextChannelID();
if (_logger.isDebugEnabled())
{
@@ -192,6 +195,18 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
}, _conn).execute();
}
+ /**
+ * Create an XASession with default prefetch values of:
+ * High = MaxPrefetch
+ * Low = MaxPrefetch / 2
+ * @return XASession
+ * @throws JMSException thrown if there is a problem creating the session.
+ */
+ public XASession createXASession() throws JMSException
+ {
+ return createXASession((int) _conn.getMaxPrefetch(), (int) _conn.getMaxPrefetch() / 2);
+ }
+
private void createChannelOverWire(int channelId, int prefetchHigh, int prefetchLow, boolean transacted)
throws AMQException, FailoverException
{
@@ -203,7 +218,7 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
// todo Be aware of possible changes to parameter order as versions change.
BasicQosBody basicQosBody = _conn.getProtocolHandler().getMethodRegistry().createBasicQosBody(0,prefetchHigh,false);
_conn._protocolHandler.syncWrite(basicQosBody.generateFrame(channelId),BasicQosOkBody.class);
-
+
if (transacted)
{
if (_logger.isDebugEnabled())
@@ -211,12 +226,17 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
_logger.debug("Issuing TxSelect for " + channelId);
}
TxSelectBody body = _conn.getProtocolHandler().getMethodRegistry().createTxSelectBody();
-
+
// TODO: Be aware of possible changes to parameter order as versions change.
_conn._protocolHandler.syncWrite(body.generateFrame(channelId), TxSelectOkBody.class);
}
}
+ public void failoverPrep()
+ {
+ // do nothing
+ }
+
/**
* For all sessions, and for all consumers in those sessions, resubscribe. This is called during failover handling.
* The caller must hold the failover mutex before calling this method.
@@ -247,4 +267,52 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate
throw new AMQException(null, "Error reopening channel " + channelId + " after failover: " + e, e);
}
}
+
+ public <T, E extends Exception> T executeRetrySupport(FailoverProtectedOperation<T,E> operation) throws E
+ {
+ while (true)
+ {
+ try
+ {
+ _conn.blockUntilNotFailingOver();
+ }
+ catch (InterruptedException e)
+ {
+ _logger.debug("Interrupted: " + e, e);
+
+ return null;
+ }
+
+ synchronized (_conn.getFailoverMutex())
+ {
+ try
+ {
+ return operation.execute();
+ }
+ catch (FailoverException e)
+ {
+ _logger.debug("Failover exception caught during operation: " + e, e);
+ }
+ catch (IllegalStateException e)
+ {
+ if (!(e.getMessage().startsWith("Fail-over interupted no-op failover support")))
+ {
+ throw e;
+ }
+ }
+ }
+ }
+ }
+
+ public void setIdleTimeout(long l){}
+
+ public int getMaxChannelID()
+ {
+ return (int) (Math.pow(2, 16)-1);
+ }
+
+ public ProtocolVersion getProtocolVersion()
+ {
+ return ProtocolVersion.v8_0;
+ }
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_9_1.java b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_9_1.java
new file mode 100755
index 0000000000..442dd7b286
--- /dev/null
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_9_1.java
@@ -0,0 +1,39 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.client;
+
+import org.apache.qpid.framing.ProtocolVersion;
+
+
+public class AMQConnectionDelegate_9_1 extends AMQConnectionDelegate_8_0
+{
+
+ public AMQConnectionDelegate_9_1(AMQConnection conn)
+ {
+ super(conn);
+ }
+
+ @Override
+ public ProtocolVersion getProtocolVersion()
+ {
+ return ProtocolVersion.v0_91;
+ }
+} \ No newline at end of file
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java
index 01a915f2cc..2d6f4434fe 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java
@@ -354,6 +354,17 @@ public class AMQConnectionFactory implements ConnectionFactory, QueueConnectionF
return _connectionDetails;
}
+ public String getConnectionURLString()
+ {
+ return _connectionDetails.toString();
+ }
+
+
+ public final void setConnectionURLString(String url) throws URLSyntaxException
+ {
+ _connectionDetails = new AMQConnectionURL(url);
+ }
+
/**
* JNDI interface to create objects from References.
*
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java
index 21b63c1fdb..60e4a5960a 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java
@@ -237,14 +237,7 @@ public class AMQConnectionURL implements ConnectionURL
if (_password != null)
{
sb.append(':');
- if (_logger.isDebugEnabled())
- {
- sb.append(_password);
- }
- else
- {
- sb.append("********");
- }
+ sb.append("********");
}
sb.append('@');
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java b/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java
index 6c78b754bb..3f2c1af5c2 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java
@@ -82,8 +82,8 @@ public abstract class AMQDestination implements Destination, Referenceable
_isExclusive = Boolean.parseBoolean(binding.getOption(BindingURL.OPTION_EXCLUSIVE));
_isAutoDelete = Boolean.parseBoolean(binding.getOption(BindingURL.OPTION_AUTODELETE));
_isDurable = Boolean.parseBoolean(binding.getOption(BindingURL.OPTION_DURABLE));
- _queueName = binding.getQueueName() == null ? null : new AMQShortString(binding.getQueueName());
- _routingKey = binding.getRoutingKey() == null ? null : new AMQShortString(binding.getRoutingKey());
+ _queueName = binding.getQueueName() == null ? null : binding.getQueueName();
+ _routingKey = binding.getRoutingKey() == null ? null : binding.getRoutingKey();
_bindingKeys = binding.getBindingKeys() == null || binding.getBindingKeys().length == 0 ? new AMQShortString[0] : binding.getBindingKeys();
}
@@ -122,10 +122,11 @@ public abstract class AMQDestination implements Destination, Referenceable
protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString routingKey, boolean isExclusive,
boolean isAutoDelete, AMQShortString queueName, boolean isDurable,AMQShortString[] bindingKeys)
{
- // If used with a fannout exchange, the routing key can be null
- if ( !ExchangeDefaults.FANOUT_EXCHANGE_CLASS.equals(exchangeClass) && routingKey == null)
+ if ( (ExchangeDefaults.DIRECT_EXCHANGE_CLASS.equals(exchangeClass) ||
+ ExchangeDefaults.TOPIC_EXCHANGE_CLASS.equals(exchangeClass))
+ && routingKey == null)
{
- throw new IllegalArgumentException("routingKey exchange must not be null");
+ throw new IllegalArgumentException("routing/binding key must not be null");
}
if (exchangeName == null)
{
@@ -270,7 +271,7 @@ public abstract class AMQDestination implements Destination, Referenceable
sb.append("://");
sb.append(_exchangeName);
- sb.append("//");
+ sb.append("/"+_routingKey+"/");
if (_queueName != null)
{
@@ -472,11 +473,12 @@ public abstract class AMQDestination implements Destination, Referenceable
}
else
{
- throw new IllegalArgumentException("Unknown Exchange Class:" + exchangeClass);
+ return new AMQAnyDestination(exchangeName,exchangeClass,
+ routingKey,isExclusive,
+ isAutoDelete,queueName,
+ isDurable, new AMQShortString[0]);
}
-
-
}
public static Destination createDestination(BindingURL binding)
@@ -495,13 +497,9 @@ public abstract class AMQDestination implements Destination, Referenceable
{
return new AMQHeadersExchange(binding);
}
- else if (type.equals(ExchangeDefaults.FANOUT_EXCHANGE_CLASS))
- {
- return new AMQQueue(binding);
- }
else
{
- throw new IllegalArgumentException("Unknown Exchange Class:" + type + " in binding:" + binding);
+ return new AMQAnyDestination(binding);
}
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQQueueBrowser.java b/java/client/src/main/java/org/apache/qpid/client/AMQQueueBrowser.java
index 08fd49286b..d96544adf8 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQQueueBrowser.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQQueueBrowser.java
@@ -22,14 +22,12 @@ package org.apache.qpid.client;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.apache.qpid.AMQException;
import javax.jms.IllegalStateException;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.QueueBrowser;
-
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -90,38 +88,11 @@ public class AMQQueueBrowser implements QueueBrowser
{
checkState();
final BasicMessageConsumer consumer =
- (BasicMessageConsumer) _session.createBrowserConsumer(_queue, _messageSelector, false);
+ (BasicMessageConsumer) _session.createBrowserConsumer(_queue, _messageSelector, false);
_consumers.add(consumer);
- return new Enumeration()
- {
-
- Message _nextMessage = consumer == null ? null : consumer.receive(1000);
-
- public boolean hasMoreElements()
- {
- _logger.info("QB:hasMoreElements:" + (_nextMessage != null));
- return (_nextMessage != null);
- }
-
- public Object nextElement()
- {
- Message msg = _nextMessage;
- try
- {
- _logger.info("QB:nextElement about to receive");
- _nextMessage = consumer.receive(1000);
- _logger.info("QB:nextElement received:" + _nextMessage);
- }
- catch (JMSException e)
- {
- _logger.warn("Exception caught while queue browsing", e);
- _nextMessage = null;
- }
- return msg;
- }
- };
+ return new QueueBrowserEnumeration(consumer);
}
public void close() throws JMSException
@@ -134,4 +105,39 @@ public class AMQQueueBrowser implements QueueBrowser
_consumers.clear();
}
+ private class QueueBrowserEnumeration implements Enumeration
+ {
+ Message _nextMessage;
+ private BasicMessageConsumer _consumer;
+
+ public QueueBrowserEnumeration(BasicMessageConsumer consumer) throws JMSException
+ {
+ _nextMessage = consumer == null ? null : consumer.receiveBrowse();
+ _logger.info("QB:created with first element:" + _nextMessage);
+ _consumer = consumer;
+ }
+
+ public boolean hasMoreElements()
+ {
+ _logger.info("QB:hasMoreElements:" + (_nextMessage != null));
+ return (_nextMessage != null);
+ }
+
+ public Object nextElement()
+ {
+ Message msg = _nextMessage;
+ try
+ {
+ _logger.info("QB:nextElement about to receive");
+ _nextMessage = _consumer.receiveBrowse();
+ _logger.info("QB:nextElement received:" + _nextMessage);
+ }
+ catch (JMSException e)
+ {
+ _logger.warn("Exception caught while queue browsing", e);
+ _nextMessage = null;
+ }
+ return msg;
+ }
+ }
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQSession.java b/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
index 5203a27f42..43f6fd8ad2 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
@@ -30,6 +30,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
@@ -58,25 +59,37 @@ import javax.jms.Topic;
import javax.jms.TopicPublisher;
import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;
+import javax.jms.TransactionRolledBackException;
import org.apache.qpid.AMQDisconnectedException;
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQInvalidArgumentException;
import org.apache.qpid.AMQInvalidRoutingKeyException;
+import org.apache.qpid.AMQChannelClosedException;
import org.apache.qpid.client.failover.FailoverException;
import org.apache.qpid.client.failover.FailoverNoopSupport;
import org.apache.qpid.client.failover.FailoverProtectedOperation;
import org.apache.qpid.client.failover.FailoverRetrySupport;
-import org.apache.qpid.client.message.*;
+import org.apache.qpid.client.message.AMQMessageDelegateFactory;
+import org.apache.qpid.client.message.AbstractJMSMessage;
+import org.apache.qpid.client.message.CloseConsumerMessage;
+import org.apache.qpid.client.message.JMSBytesMessage;
+import org.apache.qpid.client.message.JMSMapMessage;
+import org.apache.qpid.client.message.JMSObjectMessage;
+import org.apache.qpid.client.message.JMSStreamMessage;
+import org.apache.qpid.client.message.JMSTextMessage;
+import org.apache.qpid.client.message.MessageFactoryRegistry;
+import org.apache.qpid.client.message.UnprocessedMessage;
import org.apache.qpid.client.protocol.AMQProtocolHandler;
-import org.apache.qpid.client.util.FlowControllingBlockingQueue;
-import org.apache.qpid.client.state.AMQStateManager;
import org.apache.qpid.client.state.AMQState;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.util.FlowControllingBlockingQueue;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.framing.FieldTableFactory;
import org.apache.qpid.framing.MethodRegistry;
import org.apache.qpid.jms.Session;
+import org.apache.qpid.thread.Threading;
import org.apache.qpid.url.AMQBindingURL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -100,7 +113,6 @@ import org.slf4j.LoggerFactory;
public abstract class AMQSession<C extends BasicMessageConsumer, P extends BasicMessageProducer> extends Closeable implements Session, QueueSession, TopicSession
{
-
public static final class IdToConsumerMap<C extends BasicMessageConsumer>
{
private final BasicMessageConsumer[] _fastAccessConsumers = new BasicMessageConsumer[16];
@@ -181,24 +193,38 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
/** Used for debugging. */
private static final Logger _logger = LoggerFactory.getLogger(AMQSession.class);
-
- /** The default maximum number of prefetched message at which to suspend the channel. */
- public static final int DEFAULT_PREFETCH_HIGH_MARK = 5000;
-
- /** The default minimum number of prefetched messages at which to resume the channel. */
- public static final int DEFAULT_PREFETCH_LOW_MARK = 2500;
-
/**
* The default value for immediate flag used by producers created by this session is false. That is, a consumer does
* not need to be attached to a queue.
*/
- protected static final boolean DEFAULT_IMMEDIATE = false;
+ protected final boolean DEFAULT_IMMEDIATE = Boolean.parseBoolean(System.getProperty("qpid.default_immediate", "false"));
/**
* The default value for mandatory flag used by producers created by this session is true. That is, server will not
* silently drop messages where no queue is connected to the exchange for the message.
*/
- protected static final boolean DEFAULT_MANDATORY = true;
+ protected final boolean DEFAULT_MANDATORY = Boolean.parseBoolean(System.getProperty("qpid.default_mandatory", "true"));
+
+ protected final boolean DEFAULT_WAIT_ON_SEND = Boolean.parseBoolean(System.getProperty("qpid.default_wait_on_send", "false"));
+
+ /**
+ * The period to wait while flow controlled before sending a log message confirming that the session is still
+ * waiting on flow control being revoked
+ */
+ protected final long FLOW_CONTROL_WAIT_PERIOD = Long.getLong("qpid.flow_control_wait_notify_period",5000L);
+
+ /**
+ * The period to wait while flow controlled before declaring a failure
+ */
+ public static final long DEFAULT_FLOW_CONTROL_WAIT_FAILURE = 120000L;
+ protected final long FLOW_CONTROL_WAIT_FAILURE = Long.getLong("qpid.flow_control_wait_failure",
+ DEFAULT_FLOW_CONTROL_WAIT_FAILURE);
+
+ protected final boolean DECLARE_QUEUES =
+ Boolean.parseBoolean(System.getProperty("qpid.declare_queues", "true"));
+
+ protected final boolean DECLARE_EXCHANGES =
+ Boolean.parseBoolean(System.getProperty("qpid.declare_exchanges", "true"));
/** System property to enable strict AMQP compliance. */
public static final String STRICT_AMQP = "STRICT_AMQP";
@@ -233,10 +259,10 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
private int _ticket;
/** Holds the high mark for prefetched message, at which the session is suspended. */
- private int _defaultPrefetchHighMark = DEFAULT_PREFETCH_HIGH_MARK;
+ private int _prefetchHighMark;
/** Holds the low mark for prefetched messages, below which the session is resumed. */
- private int _defaultPrefetchLowMark = DEFAULT_PREFETCH_LOW_MARK;
+ private int _prefetchLowMark;
/** Holds the message listener, if any, which is attached to this session. */
private MessageListener _messageListener = null;
@@ -268,6 +294,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
/** Holds the highest received delivery tag. */
private final AtomicLong _highestDeliveryTag = new AtomicLong(-1);
+ private final AtomicLong _rollbackMark = new AtomicLong(-1);
/** All the not yet acknowledged message tags */
protected ConcurrentLinkedQueue<Long> _unacknowledgedMessageTags = new ConcurrentLinkedQueue<Long>();
@@ -278,6 +305,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
/** Holds the dispatcher thread for this session. */
protected Dispatcher _dispatcher;
+ protected Thread _dispatcherThread;
+
/** Holds the message factory factory for this session. */
protected MessageFactoryRegistry _messageFactoryRegistry;
@@ -414,13 +443,13 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
_channelId = channelId;
_messageFactoryRegistry = messageFactoryRegistry;
- _defaultPrefetchHighMark = defaultPrefetchHighMark;
- _defaultPrefetchLowMark = defaultPrefetchLowMark;
+ _prefetchHighMark = defaultPrefetchHighMark;
+ _prefetchLowMark = defaultPrefetchLowMark;
if (_acknowledgeMode == NO_ACKNOWLEDGE)
{
_queue =
- new FlowControllingBlockingQueue(_defaultPrefetchHighMark, _defaultPrefetchLowMark,
+ new FlowControllingBlockingQueue(_prefetchHighMark, _prefetchLowMark,
new FlowControllingBlockingQueue.ThresholdListener()
{
private final AtomicBoolean _suspendState = new AtomicBoolean();
@@ -428,7 +457,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
public void aboveThreshold(int currentValue)
{
_logger.debug(
- "Above threshold(" + _defaultPrefetchHighMark
+ "Above threshold(" + _prefetchHighMark
+ ") so suspending channel. Current value is " + currentValue);
_suspendState.set(true);
new Thread(new SuspenderRunner(_suspendState)).start();
@@ -438,7 +467,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
public void underThreshold(int currentValue)
{
_logger.debug(
- "Below threshold(" + _defaultPrefetchLowMark
+ "Below threshold(" + _prefetchLowMark
+ ") so unsuspending channel. Current value is " + currentValue);
_suspendState.set(false);
new Thread(new SuspenderRunner(_suspendState)).start();
@@ -448,7 +477,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
else
{
- _queue = new FlowControllingBlockingQueue(_defaultPrefetchHighMark, null);
+ _queue = new FlowControllingBlockingQueue(_prefetchHighMark, null);
}
}
@@ -568,12 +597,19 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
public void bindQueue(final AMQShortString queueName, final AMQShortString routingKey, final FieldTable arguments,
final AMQShortString exchangeName, final AMQDestination destination) throws AMQException
{
+ bindQueue(queueName, routingKey, arguments, exchangeName, destination, false);
+ }
+
+ public void bindQueue(final AMQShortString queueName, final AMQShortString routingKey, final FieldTable arguments,
+ final AMQShortString exchangeName, final AMQDestination destination,
+ final boolean nowait) throws AMQException
+ {
/*new FailoverRetrySupport<Object, AMQException>(new FailoverProtectedOperation<Object, AMQException>()*/
new FailoverNoopSupport<Object, AMQException>(new FailoverProtectedOperation<Object, AMQException>()
{
public Object execute() throws AMQException, FailoverException
{
- sendQueueBind(queueName, routingKey, arguments, exchangeName, destination);
+ sendQueueBind(queueName, routingKey, arguments, exchangeName, destination, nowait);
return null;
}
}, _connection).execute();
@@ -588,7 +624,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
public abstract void sendQueueBind(final AMQShortString queueName, final AMQShortString routingKey, final FieldTable arguments,
- final AMQShortString exchangeName, AMQDestination destination) throws AMQException, FailoverException;
+ final AMQShortString exchangeName, AMQDestination destination,
+ final boolean nowait) throws AMQException, FailoverException;
/**
* Closes the session.
@@ -608,6 +645,11 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
*/
public void close(long timeout) throws JMSException
{
+ close(timeout, true);
+ }
+
+ private void close(long timeout, boolean sendClose) throws JMSException
+ {
if (_logger.isInfoEnabled())
{
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
@@ -618,6 +660,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
// Ensure we only try and close an open session.
if (!_closed.getAndSet(true))
{
+ _closing.set(true);
synchronized (getFailoverMutex())
{
// We must close down all producers and consumers in an orderly fashion. This is the only method
@@ -629,7 +672,16 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
try
{
- sendClose(timeout);
+ // If the connection is open or we are in the process
+ // of closing the connection then send a cance
+ // no point otherwise as the connection will be gone
+ if (!_connection.isClosed() || _connection.isClosing())
+ {
+ if (sendClose)
+ {
+ sendClose(timeout);
+ }
+ }
}
catch (AMQException e)
{
@@ -674,31 +726,32 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
if (_dispatcher != null)
{
// Failover failed and ain't coming back. Knife the dispatcher.
- _dispatcher.interrupt();
+ _dispatcherThread.interrupt();
}
- }
+
+ }
+
+ //if we don't have an exception then we can perform closing operations
+ _closing.set(e == null);
if (!_closed.getAndSet(true))
{
- synchronized (getFailoverMutex())
+ synchronized (_messageDeliveryLock)
{
- synchronized (_messageDeliveryLock)
+ // An AMQException has an error code and message already and will be passed in when closure occurs as a
+ // result of a channel close request
+ AMQException amqe;
+ if (e instanceof AMQException)
{
- // An AMQException has an error code and message already and will be passed in when closure occurs as a
- // result of a channel close request
- AMQException amqe;
- if (e instanceof AMQException)
- {
- amqe = (AMQException) e;
- }
- else
- {
- amqe = new AMQException("Closing session forcibly", e);
- }
-
- _connection.deregisterSession(_channelId);
- closeProducersAndConsumers(amqe);
+ amqe = (AMQException) e;
}
+ else
+ {
+ amqe = new AMQException("Closing session forcibly", e);
+ }
+
+ _connection.deregisterSession(_channelId);
+ closeProducersAndConsumers(amqe);
}
}
}
@@ -721,8 +774,16 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
try
{
+ //Check that we are clean to commit.
+ if (_failedOverDirty)
+ {
+ rollback();
+
+ throw new TransactionRolledBackException("Connection failover has occured since last send. " +
+ "Forced rollback");
+ }
+
- // TGM FIXME: what about failover?
// Acknowledge all delivered messages
while (true)
{
@@ -740,7 +801,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
catch (AMQException e)
{
- throw new JMSAMQException("Failed to commit: " + e.getMessage(), e);
+ throw new JMSAMQException("Failed to commit: " + e.getMessage() + ":" + e.getCause(), e);
}
catch (FailoverException e)
{
@@ -832,7 +893,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
checkValidDestination(destination);
- return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, noLocal, false,
+ return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, noLocal, false,
messageSelector, null, true, true);
}
@@ -840,7 +901,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
checkValidDestination(destination);
- return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, false, (destination instanceof Topic), null, null,
+ return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, false, (destination instanceof Topic), null, null,
false, false);
}
@@ -848,7 +909,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
checkValidDestination(destination);
- return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, false, true, null, null,
+ return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, false, true, null, null,
false, false);
}
@@ -856,7 +917,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
checkValidDestination(destination);
- return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, false, (destination instanceof Topic),
+ return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, false, (destination instanceof Topic),
messageSelector, null, false, false);
}
@@ -865,7 +926,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
checkValidDestination(destination);
- return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, noLocal, (destination instanceof Topic),
+ return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, noLocal, (destination instanceof Topic),
messageSelector, null, false, false);
}
@@ -874,7 +935,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
checkValidDestination(destination);
- return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, noLocal, true,
+ return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, noLocal, true,
messageSelector, null, false, false);
}
@@ -917,7 +978,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
throws JMSException
{
checkNotClosed();
- checkValidTopic(topic);
+ checkValidTopic(topic, true);
if (_subscriptions.containsKey(name))
{
_subscriptions.get(name).close();
@@ -1000,6 +1061,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
catch (URISyntaxException urlse)
{
+ _logger.error("", urlse);
JMSException jmse = new JMSException(urlse.getReason());
jmse.setLinkedException(urlse);
@@ -1194,7 +1256,28 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
return new TopicSubscriberAdaptor(dest, (C) createExclusiveConsumer(dest, messageSelector, noLocal));
}
- public abstract TemporaryQueue createTemporaryQueue() throws JMSException;
+ public TemporaryQueue createTemporaryQueue() throws JMSException
+ {
+ checkNotClosed();
+ try
+ {
+ AMQTemporaryQueue result = new AMQTemporaryQueue(this);
+
+ // this is done so that we can produce to a temporary queue before we create a consumer
+ result.setQueueName(result.getRoutingKey());
+ createQueue(result.getAMQQueueName(), result.isAutoDelete(),
+ result.isDurable(), result.isExclusive());
+ bindQueue(result.getAMQQueueName(), result.getRoutingKey(),
+ new FieldTable(), result.getExchangeName(), result);
+ return result;
+ }
+ catch (Exception e)
+ {
+ JMSException ex = new JMSException("Cannot create temporary queue");
+ ex.setLinkedException(e);
+ throw ex;
+ }
+ }
public TemporaryTopic createTemporaryTopic() throws JMSException
{
@@ -1275,17 +1358,17 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
public int getDefaultPrefetch()
{
- return _defaultPrefetchHighMark;
+ return _prefetchHighMark;
}
public int getDefaultPrefetchHigh()
{
- return _defaultPrefetchHighMark;
+ return _prefetchHighMark;
}
public int getDefaultPrefetchLow()
{
- return _defaultPrefetchLowMark;
+ return _prefetchLowMark;
}
public AMQShortString getDefaultQueueExchangeName()
@@ -1430,6 +1513,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
sendRecover();
+ markClean();
+
if (!isSuspended)
{
suspendChannel(false);
@@ -1498,6 +1583,14 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
suspendChannel(true);
}
+ // Let the dispatcher know that all the incomming messages
+ // should be rolled back(reject/release)
+ _rollbackMark.set(_highestDeliveryTag.get());
+
+ syncDispatchQueue();
+
+ _dispatcher.rollback();
+
releaseForRollback();
sendRollback();
@@ -1645,11 +1738,11 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
// if (rawSelector != null)
// ft.put("headers", rawSelector.getDataAsBytes());
// rawSelector is used by HeadersExchange and is not a JMS Selector
- if (rawSelector != null)
+ if (rawSelector != null)
{
ft.addAll(rawSelector);
}
-
+
if (messageSelector != null)
{
ft.put(new AMQShortString("x-filter-jms-selector"), messageSelector);
@@ -1682,6 +1775,11 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
catch (AMQException e)
{
+ if (e instanceof AMQChannelClosedException)
+ {
+ close(-1, false);
+ }
+
JMSException ex = new JMSException("Error registering consumer: " + e);
ex.setLinkedException(e);
@@ -1783,6 +1881,63 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
+ void failoverPrep()
+ {
+ syncDispatchQueue();
+ }
+
+ void syncDispatchQueue()
+ {
+ if (Thread.currentThread() == _dispatcherThread)
+ {
+ while (!_closed.get() && !_queue.isEmpty())
+ {
+ Dispatchable disp;
+ try
+ {
+ disp = (Dispatchable) _queue.take();
+ }
+ catch (InterruptedException e)
+ {
+ throw new RuntimeException(e);
+ }
+
+ // Check just in case _queue becomes empty, it shouldn't but
+ // better than an NPE.
+ if (disp == null)
+ {
+ _logger.debug("_queue became empty during sync.");
+ break;
+ }
+
+ disp.dispatch(AMQSession.this);
+ }
+ }
+ else
+ {
+ startDispatcherIfNecessary();
+
+ final CountDownLatch signal = new CountDownLatch(1);
+
+ _queue.add(new Dispatchable()
+ {
+ public void dispatch(AMQSession ssn)
+ {
+ signal.countDown();
+ }
+ });
+
+ try
+ {
+ signal.await();
+ }
+ catch (InterruptedException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
/**
* Resubscribes all producers and consumers. This is called when performing failover.
*
@@ -1794,6 +1949,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
_failedOverDirty = true;
}
+
+ _rollbackMark.set(-1);
resubscribeProducers();
resubscribeConsumers();
}
@@ -1808,6 +1965,11 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
_inRecovery = inRecovery;
}
+ boolean isStarted()
+ {
+ return _startedAtLeastOnce.get();
+ }
+
/**
* Starts the session, which ensures that it is not suspended and that its event dispatcher is running.
*
@@ -1834,7 +1996,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
void startDispatcherIfNecessary()
{
//If we are the dispatcher then we don't need to check we are started
- if (Thread.currentThread() == _dispatcher)
+ if (Thread.currentThread() == _dispatcherThread)
{
return;
}
@@ -1865,9 +2027,23 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
if (_dispatcher == null)
{
_dispatcher = new Dispatcher();
- _dispatcher.setDaemon(true);
+ try
+ {
+ _dispatcherThread = Threading.getThreadFactory().createThread(_dispatcher);
+
+ }
+ catch(Exception e)
+ {
+ throw new Error("Error creating Dispatcher thread",e);
+ }
+ _dispatcherThread.setName("Dispatcher-Channel-" + _channelId);
+ _dispatcherThread.setDaemon(true);
_dispatcher.setConnectionStopped(initiallyStopped);
- _dispatcher.start();
+ _dispatcherThread.start();
+ if (_dispatcherLogger.isInfoEnabled())
+ {
+ _dispatcherLogger.info(_dispatcherThread.getName() + " created");
+ }
}
else
{
@@ -1967,7 +2143,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
/*
* I could have combined the last 3 methods, but this way it improves readability
*/
- protected AMQTopic checkValidTopic(Topic topic) throws JMSException
+ protected AMQTopic checkValidTopic(Topic topic, boolean durable) throws JMSException
{
if (topic == null)
{
@@ -1980,6 +2156,12 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
"Cannot create a subscription on a temporary topic created in another session");
}
+ if ((topic instanceof TemporaryDestination) && durable)
+ {
+ throw new javax.jms.InvalidDestinationException
+ ("Cannot create a durable subscription with a temporary topic: " + topic);
+ }
+
if (!(topic instanceof AMQTopic))
{
throw new javax.jms.InvalidDestinationException(
@@ -1990,6 +2172,11 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
return (AMQTopic) topic;
}
+ protected AMQTopic checkValidTopic(Topic topic) throws JMSException
+ {
+ return checkValidTopic(topic, false);
+ }
+
/**
* Called to close message consumers cleanly. This may or may <b>not</b> be as a result of an error.
*
@@ -2110,7 +2297,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
private P createProducerImpl(Destination destination, boolean mandatory, boolean immediate)
throws JMSException
{
- return createProducerImpl(destination, mandatory, immediate, false);
+ return createProducerImpl(destination, mandatory, immediate, DEFAULT_WAIT_ON_SEND);
}
private P createProducerImpl(final Destination destination, final boolean mandatory,
@@ -2216,7 +2403,13 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
* @todo Be aware of possible changes to parameter order as versions change.
*/
protected AMQShortString declareQueue(final AMQDestination amqd, final AMQProtocolHandler protocolHandler,
- final boolean noLocal)
+ final boolean noLocal) throws AMQException
+ {
+ return declareQueue(amqd, protocolHandler, noLocal, false);
+ }
+
+ protected AMQShortString declareQueue(final AMQDestination amqd, final AMQProtocolHandler protocolHandler,
+ final boolean noLocal, final boolean nowait)
throws AMQException
{
/*return new FailoverRetrySupport<AMQShortString, AMQException>(*/
@@ -2231,14 +2424,15 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
amqd.setQueueName(protocolHandler.generateQueueName());
}
- sendQueueDeclare(amqd, protocolHandler);
+ sendQueueDeclare(amqd, protocolHandler, nowait);
return amqd.getAMQQueueName();
}
}, _connection).execute();
}
- public abstract void sendQueueDeclare(final AMQDestination amqd, final AMQProtocolHandler protocolHandler) throws AMQException, FailoverException;
+ public abstract void sendQueueDeclare(final AMQDestination amqd, final AMQProtocolHandler protocolHandler,
+ final boolean nowait) throws AMQException, FailoverException;
/**
* Undeclares the specified queue.
@@ -2351,14 +2545,21 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
AMQProtocolHandler protocolHandler = getProtocolHandler();
- declareExchange(amqd, protocolHandler, false);
+ if (DECLARE_EXCHANGES)
+ {
+ declareExchange(amqd, protocolHandler, nowait);
+ }
- AMQShortString queueName = declareQueue(amqd, protocolHandler, consumer.isNoLocal());
+ if (DECLARE_QUEUES || amqd.isNameRequired())
+ {
+ declareQueue(amqd, protocolHandler, consumer.isNoLocal(), nowait);
+ }
+ AMQShortString queueName = amqd.getAMQQueueName();
// store the consumer queue name
consumer.setQueuename(queueName);
- bindQueue(queueName, amqd.getRoutingKey(), consumer.getArguments(), amqd.getExchangeName(), amqd);
+ bindQueue(queueName, amqd.getRoutingKey(), consumer.getArguments(), amqd.getExchangeName(), amqd, nowait);
// If IMMEDIATE_PREFETCH is not required then suspsend the channel to delay prefetch
if (!_immediatePrefetch)
@@ -2390,11 +2591,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
try
{
- consumeFromQueue(consumer, queueName, protocolHandler, nowait, consumer.getMessageSelector());
- }
- catch (JMSException e) // thrown by getMessageSelector
- {
- throw new AMQException(null, e.getMessage(), e);
+ consumeFromQueue(consumer, queueName, protocolHandler, nowait, consumer._messageSelector);
}
catch (FailoverException e)
{
@@ -2465,9 +2662,10 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
_consumers.clear();
for (C consumer : consumers)
- {
- consumer.failedOver();
+ {
+ consumer.failedOverPre();
registerConsumer(consumer, true);
+ consumer.failedOverPost();
}
}
@@ -2570,50 +2768,67 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
public void setFlowControl(final boolean active)
{
_flowControl.setFlowControl(active);
+ _logger.warn("Broker enforced flow control " + (active ? "no longer in effect" : "has been enforced"));
}
- public void checkFlowControl() throws InterruptedException
+ public void checkFlowControl() throws InterruptedException, JMSException
{
+ long expiryTime = 0L;
synchronized (_flowControl)
{
- while (!_flowControl.getFlowControl())
+ while (!_flowControl.getFlowControl() &&
+ (expiryTime == 0L ? (expiryTime = System.currentTimeMillis() + FLOW_CONTROL_WAIT_FAILURE)
+ : expiryTime) >= System.currentTimeMillis() )
{
- _flowControl.wait();
+
+ _flowControl.wait(FLOW_CONTROL_WAIT_PERIOD);
+ _logger.warn("Message send delayed by " + (System.currentTimeMillis() + FLOW_CONTROL_WAIT_FAILURE - expiryTime)/1000 + "s due to broker enforced flow control");
}
+ if(!_flowControl.getFlowControl())
+ {
+ _logger.error("Message send failed due to timeout waiting on broker enforced flow control");
+ throw new JMSException("Unable to send message for " + FLOW_CONTROL_WAIT_FAILURE/1000 + " seconds due to broker enforced flow control");
+ }
+ }
+
+ }
+
+ public interface Dispatchable
+ {
+ void dispatch(AMQSession ssn);
+ }
+
+ public void dispatch(UnprocessedMessage message)
+ {
+ if (_dispatcher == null)
+ {
+ throw new java.lang.IllegalStateException("dispatcher is not started");
}
+ _dispatcher.dispatchMessage(message);
}
/** Used for debugging in the dispatcher. */
private static final Logger _dispatcherLogger = LoggerFactory.getLogger("org.apache.qpid.client.AMQSession.Dispatcher");
-
/** Responsible for decoding a message fragment and passing it to the appropriate message consumer. */
- class Dispatcher extends Thread
+ class Dispatcher implements Runnable
{
/** Track the 'stopped' state of the dispatcher, a session starts in the stopped state. */
private final AtomicBoolean _closed = new AtomicBoolean(false);
private final Object _lock = new Object();
- private final AtomicLong _rollbackMark = new AtomicLong(-1);
private String dispatcherID = "" + System.identityHashCode(this);
-
-
public Dispatcher()
{
- super("Dispatcher-Channel-" + _channelId);
- if (_dispatcherLogger.isInfoEnabled())
- {
- _dispatcherLogger.info(getName() + " created");
- }
}
public void close()
{
_closed.set(true);
- interrupt();
+ _dispatcherThread.interrupt();
// fixme awaitTermination
@@ -2692,7 +2907,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
if (_dispatcherLogger.isInfoEnabled())
{
- _dispatcherLogger.info(getName() + " started");
+ _dispatcherLogger.info(_dispatcherThread.getName() + " started");
}
UnprocessedMessage message;
@@ -2715,37 +2930,10 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
try
{
- while (!_closed.get() && ((message = (UnprocessedMessage) _queue.take()) != null))
+ Dispatchable disp;
+ while (!_closed.get() && ((disp = (Dispatchable) _queue.take()) != null))
{
- long deliveryTag = message.getDeliveryTag();
-
- synchronized (_lock)
- {
-
- while (connectionStopped())
- {
- _lock.wait();
- }
-
- if (!(message instanceof CloseConsumerMessage)
- && tagLE(deliveryTag, _rollbackMark.get()))
- {
- rejectMessage(message, true);
- }
- else
- {
- synchronized (_messageDeliveryLock)
- {
- dispatchMessage(message);
- }
- }
- }
-
- long current = _rollbackMark.get();
- if (updateRollbackMark(current, deliveryTag))
- {
- _rollbackMark.compareAndSet(current, deliveryTag);
- }
+ disp.dispatch(AMQSession.this);
}
}
catch (InterruptedException e)
@@ -2755,7 +2943,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
if (_dispatcherLogger.isInfoEnabled())
{
- _dispatcherLogger.info(getName() + " thread terminating for channel " + _channelId);
+ _dispatcherLogger.info(_dispatcherThread.getName() + " thread terminating for channel " + _channelId);
}
}
@@ -2786,11 +2974,47 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
private void dispatchMessage(UnprocessedMessage message)
{
- //This if block is not needed anymore as bounce messages are handled separately
- //if (message.getDeliverBody() != null)
- //{
- final C consumer =
- _consumers.get(message.getConsumerTag());
+ long deliveryTag = message.getDeliveryTag();
+
+ synchronized (_lock)
+ {
+
+ try
+ {
+ while (connectionStopped())
+ {
+ _lock.wait();
+ }
+ }
+ catch (InterruptedException e)
+ {
+ // pass
+ }
+
+ if (!(message instanceof CloseConsumerMessage)
+ && tagLE(deliveryTag, _rollbackMark.get()))
+ {
+ rejectMessage(message, true);
+ }
+ else
+ {
+ synchronized (_messageDeliveryLock)
+ {
+ notifyConsumer(message);
+ }
+ }
+ }
+
+ long current = _rollbackMark.get();
+ if (updateRollbackMark(current, deliveryTag))
+ {
+ _rollbackMark.compareAndSet(current, deliveryTag);
+ }
+ }
+
+ private void notifyConsumer(UnprocessedMessage message)
+ {
+ final C consumer = _consumers.get(message.getConsumerTag());
if ((consumer == null) || consumer.isClosed())
{
@@ -2798,7 +3022,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
if (consumer == null)
{
- _dispatcherLogger.info("Dispatcher(" + dispatcherID + ")Received a message(" + System.identityHashCode(message) + ")" + "["
+ _dispatcherLogger.info("Dispatcher(" + dispatcherID + ")Received a message("
+ + System.identityHashCode(message) + ")" + "["
+ message.getDeliveryTag() + "] from queue "
+ message.getConsumerTag() + " )without a handler - rejecting(requeue)...");
}
@@ -2806,7 +3031,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
if (consumer.isNoConsume())
{
- _dispatcherLogger.info("Received a message(" + System.identityHashCode(message) + ")" + "["
+ _dispatcherLogger.info("Received a message("
+ + System.identityHashCode(message) + ")" + "["
+ message.getDeliveryTag() + "] from queue " + " consumer("
+ message.getConsumerTag() + ") is closed and a browser so dropping...");
//DROP MESSAGE
@@ -2815,7 +3041,8 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
else
{
- _dispatcherLogger.info("Received a message(" + System.identityHashCode(message) + ")" + "["
+ _dispatcherLogger.info("Received a message("
+ + System.identityHashCode(message) + ")" + "["
+ message.getDeliveryTag() + "] from queue " + " consumer("
+ message.getConsumerTag() + ") is closed rejecting(requeue)...");
}
@@ -2831,7 +3058,6 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
{
consumer.notifyMessage(message);
}
-
}
}
@@ -2889,4 +3115,27 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic
}
}
}
+
+ /**
+ * Checks if the Session and its parent connection are closed
+ *
+ * @return <tt>true</tt> if this is closed, <tt>false</tt> otherwise.
+ */
+ @Override
+ public boolean isClosed()
+ {
+ return _closed.get() || _connection.isClosed();
+ }
+
+ /**
+ * Checks if the Session and its parent connection are capable of performing
+ * closing operations
+ *
+ * @return <tt>true</tt> if we are closing, <tt>false</tt> otherwise.
+ */
+ @Override
+ public boolean isClosing()
+ {
+ return _closing.get()|| _connection.isClosing();
+ }
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java b/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java
index aa0ff66545..2324d441cc 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java
@@ -28,31 +28,44 @@ import org.apache.qpid.client.protocol.AMQProtocolHandler;
import org.apache.qpid.client.message.MessageFactoryRegistry;
import org.apache.qpid.client.message.FiledTableSupport;
import org.apache.qpid.client.message.AMQMessageDelegateFactory;
+import org.apache.qpid.client.message.UnprocessedMessage_0_10;
import org.apache.qpid.util.Serial;
-import org.apache.qpid.nclient.Session;
-import org.apache.qpid.nclient.util.MessagePartListenerAdapter;
-import org.apache.qpid.ErrorCode;
-import org.apache.qpid.QpidException;
+import org.apache.qpid.transport.ExecutionException;
+import org.apache.qpid.transport.MessageAcceptMode;
+import org.apache.qpid.transport.MessageAcquireMode;
import org.apache.qpid.transport.MessageCreditUnit;
import org.apache.qpid.transport.MessageFlowMode;
+import org.apache.qpid.transport.MessageTransfer;
import org.apache.qpid.transport.RangeSet;
import org.apache.qpid.transport.Option;
import org.apache.qpid.transport.ExchangeBoundResult;
import org.apache.qpid.transport.Future;
+import org.apache.qpid.transport.Range;
+import org.apache.qpid.transport.Session;
+import org.apache.qpid.transport.SessionException;
+import org.apache.qpid.transport.SessionListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static org.apache.qpid.transport.Option.*;
+
import javax.jms.*;
import javax.jms.IllegalStateException;
+import java.lang.ref.WeakReference;
+
+import java.util.Date;
import java.util.HashMap;
import java.util.UUID;
import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
/**
* This is a 0.10 Session
*/
public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, BasicMessageProducer_0_10>
+ implements SessionListener
{
/**
@@ -60,6 +73,36 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
*/
private static final Logger _logger = LoggerFactory.getLogger(AMQSession_0_10.class);
+ private static Timer timer = new Timer("ack-flusher", true);
+ private static class Flusher extends TimerTask
+ {
+
+ private WeakReference<AMQSession_0_10> session;
+ public Flusher(AMQSession_0_10 session)
+ {
+ this.session = new WeakReference<AMQSession_0_10>(session);
+ }
+
+ public void run() {
+ AMQSession_0_10 ssn = session.get();
+ if (ssn == null)
+ {
+ cancel();
+ }
+ else
+ {
+ try
+ {
+ ssn.flushAcknowledgments(true);
+ }
+ catch (Throwable t)
+ {
+ _logger.error("error flushing acks", t);
+ }
+ }
+ }
+ }
+
/**
* The underlying QpidSession
@@ -70,11 +113,13 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
* The latest qpid Exception that has been reaised.
*/
private Object _currentExceptionLock = new Object();
- private QpidException _currentException;
+ private SessionException _currentException;
// a ref on the qpid connection
- protected org.apache.qpid.nclient.Connection _qpidConnection;
+ protected org.apache.qpid.transport.Connection _qpidConnection;
+ private long maxAckDelay = Long.getLong("qpid.session.max_ack_delay", 1000);
+ private TimerTask flushTask = null;
private RangeSet unacked = new RangeSet();
private int unackedCount = 0;
@@ -97,7 +142,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
* @param defaultPrefetchLowMark The number of prefetched messages at which to resume the session.
* @param qpidConnection The qpid connection
*/
- AMQSession_0_10(org.apache.qpid.nclient.Connection qpidConnection, AMQConnection con, int channelId,
+ AMQSession_0_10(org.apache.qpid.transport.Connection qpidConnection, AMQConnection con, int channelId,
boolean transacted, int acknowledgeMode, MessageFactoryRegistry messageFactoryRegistry,
int defaultPrefetchHighMark, int defaultPrefetchLowMark)
{
@@ -105,15 +150,18 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
super(con, channelId, transacted, acknowledgeMode, messageFactoryRegistry, defaultPrefetchHighMark,
defaultPrefetchLowMark);
_qpidConnection = qpidConnection;
- // create the qpid session with an expiry <= 0 so that the session does not expire
- _qpidSession = qpidConnection.createSession(0);
- // set the exception listnere for this session
- _qpidSession.setClosedListener(new QpidSessionExceptionListener());
- // set transacted if required
+ _qpidSession = _qpidConnection.createSession(1);
+ _qpidSession.setSessionListener(this);
if (_transacted)
{
_qpidSession.txSelect();
}
+
+ if (maxAckDelay > 0)
+ {
+ flushTask = new Flusher(this);
+ timer.schedule(flushTask, new Date(), maxAckDelay);
+ }
}
/**
@@ -127,7 +175,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
* @param defaultPrefetchLow The number of prefetched messages at which to resume the session.
* @param qpidConnection The connection
*/
- AMQSession_0_10(org.apache.qpid.nclient.Connection qpidConnection, AMQConnection con, int channelId,
+ AMQSession_0_10(org.apache.qpid.transport.Connection qpidConnection, AMQConnection con, int channelId,
boolean transacted, int acknowledgeMode, int defaultPrefetchHigh, int defaultPrefetchLow)
{
@@ -137,18 +185,30 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
private void addUnacked(int id)
{
- unacked.add(id);
- unackedCount++;
+ synchronized (unacked)
+ {
+ unacked.add(id);
+ unackedCount++;
+ }
}
private void clearUnacked()
{
- unacked.clear();
- unackedCount = 0;
+ synchronized (unacked)
+ {
+ unacked.clear();
+ unackedCount = 0;
+ }
}
//------- overwritten methods of class AMQSession
+ void failoverPrep()
+ {
+ super.failoverPrep();
+ clearUnacked();
+ }
+
/**
* Acknowledge one or many messages.
*
@@ -185,7 +245,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
long prefetch = getAMQConnection().getMaxPrefetch();
- if (unackedCount >= prefetch/2)
+ if (unackedCount >= prefetch/2 || maxAckDelay <= 0)
{
flushAcknowledgments();
}
@@ -193,11 +253,38 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
void flushAcknowledgments()
{
- if (unackedCount > 0)
+ flushAcknowledgments(false);
+ }
+
+ void flushAcknowledgments(boolean setSyncBit)
+ {
+ synchronized (unacked)
+ {
+ if (unackedCount > 0)
+ {
+ messageAcknowledge
+ (unacked, _acknowledgeMode != org.apache.qpid.jms.Session.NO_ACKNOWLEDGE,setSyncBit);
+ clearUnacked();
+ }
+ }
+ }
+
+ void messageAcknowledge(RangeSet ranges, boolean accept)
+ {
+ messageAcknowledge(ranges,accept,false);
+ }
+
+ void messageAcknowledge(RangeSet ranges, boolean accept,boolean setSyncBit)
+ {
+ Session ssn = getQpidSession();
+ for (Range range : ranges)
+ {
+ ssn.processed(range);
+ }
+ ssn.flushProcessed(accept ? BATCH : NONE);
+ if (accept)
{
- getQpidSession().messageAcknowledge
- (unacked, _acknowledgeMode != org.apache.qpid.jms.Session.NO_ACKNOWLEDGE);
- clearUnacked();
+ ssn.messageAccept(ranges, UNRELIABLE,setSyncBit? SYNC : NONE);
}
}
@@ -212,7 +299,8 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
* @param arguments 0_8 specific
*/
public void sendQueueBind(final AMQShortString queueName, final AMQShortString routingKey,
- final FieldTable arguments, final AMQShortString exchangeName, final AMQDestination destination)
+ final FieldTable arguments, final AMQShortString exchangeName,
+ final AMQDestination destination, final boolean nowait)
throws AMQException, FailoverException
{
Map args = FiledTableSupport.convertToMap(arguments);
@@ -227,9 +315,12 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
_logger.debug("Binding queue : " + queueName.toString() + " exchange: " + exchangeName.toString() + " using binding key " + rk.asString());
getQpidSession().exchangeBind(queueName.toString(), exchangeName.toString(), rk.toString(), args);
}
- // We need to sync so that we get notify of an error.
- getQpidSession().sync();
- getCurrentException();
+ if (!nowait)
+ {
+ // We need to sync so that we get notify of an error.
+ getQpidSession().sync();
+ getCurrentException();
+ }
}
@@ -242,6 +333,11 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
*/
public void sendClose(long timeout) throws AMQException, FailoverException
{
+ if (flushTask != null)
+ {
+ flushTask.cancel();
+ flushTask = null;
+ }
flushAcknowledgments();
getQpidSession().sync();
getQpidSession().close();
@@ -318,10 +414,6 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
public void releaseForRollback()
{
- if (_dispatcher != null)
- {
- _dispatcher.rollback();
- }
getQpidSession().messageRelease(_txRangeSet, Option.SET_REDELIVERED);
_txRangeSet.clear();
_txSize = 0;
@@ -376,7 +468,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
public boolean isQueueBound(final AMQShortString exchangeName, final AMQShortString queueName, final AMQShortString routingKey,AMQShortString[] bindingKeys)
throws JMSException
{
- String rk = "";
+ String rk = null;
boolean res;
if (bindingKeys != null && bindingKeys.length>0)
{
@@ -416,11 +508,11 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
preAcquire = ( ! consumer.isNoConsume() &&
(consumer.getMessageSelector() == null || consumer.getMessageSelector().equals("")) )
|| !(consumer.getDestination() instanceof AMQQueue);
- getQpidSession().messageSubscribe(queueName.toString(), String.valueOf(tag),
- getAcknowledgeMode() == NO_ACKNOWLEDGE ? Session.TRANSFER_CONFIRM_MODE_NOT_REQUIRED:Session.TRANSFER_CONFIRM_MODE_REQUIRED,
- preAcquire ? Session.TRANSFER_ACQUIRE_MODE_PRE_ACQUIRE : Session.TRANSFER_ACQUIRE_MODE_NO_ACQUIRE,
- (BasicMessageConsumer_0_10) consumer, null,
- consumer.isExclusive() ? Option.EXCLUSIVE : Option.NONE);
+ getQpidSession().messageSubscribe
+ (queueName.toString(), String.valueOf(tag),
+ getAcknowledgeMode() == NO_ACKNOWLEDGE ? MessageAcceptMode.NONE : MessageAcceptMode.EXPLICIT,
+ preAcquire ? MessageAcquireMode.PRE_ACQUIRED : MessageAcquireMode.NOT_ACQUIRED, null, 0, null,
+ consumer.isExclusive() ? Option.EXCLUSIVE : Option.NONE);
}
catch (JMSException e)
{
@@ -437,18 +529,24 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
{
getQpidSession().messageSetFlowMode(consumerTag, MessageFlowMode.WINDOW);
}
- getQpidSession().messageFlow(consumerTag, MessageCreditUnit.BYTE, 0xFFFFFFFF);
+ getQpidSession().messageFlow(consumerTag, MessageCreditUnit.BYTE, 0xFFFFFFFF,
+ Option.UNRELIABLE);
// We need to sync so that we get notify of an error.
// only if not immediat prefetch
- if(prefetch() && (consumer.isStrated() || _immediatePrefetch))
+ if(prefetch() && (isStarted() || _immediatePrefetch))
{
// set the flow
getQpidSession().messageFlow(consumerTag,
MessageCreditUnit.MESSAGE,
- getAMQConnection().getMaxPrefetch());
+ getAMQConnection().getMaxPrefetch(),
+ Option.UNRELIABLE);
+ }
+
+ if (!nowait)
+ {
+ getQpidSession().sync();
+ getCurrentException();
}
- getQpidSession().sync();
- getCurrentException();
}
/**
@@ -470,19 +568,24 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
final AMQProtocolHandler protocolHandler, final boolean nowait)
throws AMQException, FailoverException
{
- getQpidSession().exchangeDeclare(name.toString(), type.toString(), null, null);
- // autoDelete --> false
- // durable --> false
- // passive -- false
+ getQpidSession().exchangeDeclare(name.toString(),
+ type.toString(),
+ null,
+ null,
+ name.toString().startsWith("amq.")? Option.PASSIVE:Option.NONE);
// We need to sync so that we get notify of an error.
- getQpidSession().sync();
- getCurrentException();
+ if (!nowait)
+ {
+ getQpidSession().sync();
+ getCurrentException();
+ }
}
/**
* Declare a queue with the given queueName
*/
- public void sendQueueDeclare(final AMQDestination amqd, final AMQProtocolHandler protocolHandler)
+ public void sendQueueDeclare(final AMQDestination amqd, final AMQProtocolHandler protocolHandler,
+ final boolean nowait)
throws AMQException, FailoverException
{
// do nothing this is only used by 0_8
@@ -492,7 +595,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
* Declare a queue with the given queueName
*/
public AMQShortString send0_10QueueDeclare(final AMQDestination amqd, final AMQProtocolHandler protocolHandler,
- final boolean noLocal)
+ final boolean noLocal, final boolean nowait)
throws AMQException, FailoverException
{
AMQShortString res;
@@ -516,9 +619,12 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
amqd.isDurable() ? Option.DURABLE : Option.NONE,
!amqd.isDurable() && amqd.isExclusive() ? Option.EXCLUSIVE : Option.NONE);
// passive --> false
- // We need to sync so that we get notify of an error.
- getQpidSession().sync();
- getCurrentException();
+ if (!nowait)
+ {
+ // We need to sync so that we get notify of an error.
+ getQpidSession().sync();
+ getCurrentException();
+ }
return res;
}
@@ -544,7 +650,8 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
{
for (BasicMessageConsumer consumer : _consumers.values())
{
- getQpidSession().messageStop(String.valueOf(consumer.getConsumerTag()));
+ getQpidSession().messageStop(String.valueOf(consumer.getConsumerTag()),
+ Option.UNRELIABLE);
}
}
else
@@ -560,17 +667,20 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
if (consumer.getMessageListener() != null)
{
getQpidSession().messageFlow(consumerTag,
- MessageCreditUnit.MESSAGE, 1);
+ MessageCreditUnit.MESSAGE, 1,
+ Option.UNRELIABLE);
}
}
else
{
getQpidSession()
.messageFlow(consumerTag, MessageCreditUnit.MESSAGE,
- getAMQConnection().getMaxPrefetch());
+ getAMQConnection().getMaxPrefetch(),
+ Option.UNRELIABLE);
}
getQpidSession()
- .messageFlow(consumerTag, MessageCreditUnit.BYTE, 0xFFFFFFFF);
+ .messageFlow(consumerTag, MessageCreditUnit.BYTE, 0xFFFFFFFF,
+ Option.UNRELIABLE);
}
catch (Exception e)
{
@@ -598,7 +708,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
*
* @return The associated Qpid Session.
*/
- protected org.apache.qpid.nclient.Session getQpidSession()
+ protected Session getQpidSession()
{
return _qpidSession;
}
@@ -615,55 +725,56 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
{
if (_currentException != null)
{
- QpidException toBeThrown = _currentException;
+ SessionException se = _currentException;
_currentException = null;
- throw new AMQException(AMQConstant.getConstant(toBeThrown.getErrorCode().getCode()),
- toBeThrown.getMessage(), toBeThrown);
+ ExecutionException ee = se.getException();
+ int code;
+ if (ee == null)
+ {
+ code = 0;
+ }
+ else
+ {
+ code = ee.getErrorCode().getValue();
+ }
+ throw new AMQException
+ (AMQConstant.getConstant(code), se.getMessage(), se);
}
}
}
+ public void opened(Session ssn) {}
- public TemporaryQueue createTemporaryQueue() throws JMSException
+ public void resumed(Session ssn)
{
- checkNotClosed();
- AMQTemporaryQueue result = new AMQTemporaryQueue(this);
+ _qpidConnection = ssn.getConnection();
try
{
- // this is done so that we can produce to a temporary queue beofre we create a consumer
- sendCreateQueue(result.getRoutingKey(), result.isAutoDelete(), result.isDurable(), result.isExclusive(),null);
- sendQueueBind(result.getRoutingKey(), result.getRoutingKey(), new FieldTable(), result.getExchangeName(),result);
- result.setQueueName(result.getRoutingKey());
+ resubscribe();
}
- catch (Exception e)
+ catch (AMQException e)
{
- throw new JMSException("Cannot create temporary queue" );
+ throw new RuntimeException(e);
}
- return result;
}
+ public void message(Session ssn, MessageTransfer xfr)
+ {
+ messageReceived(new UnprocessedMessage_0_10(xfr));
+ }
-
-
- //------ Inner classes
- /**
- * Lstener for qpid protocol exceptions
- */
- private class QpidSessionExceptionListener implements org.apache.qpid.nclient.ClosedListener
+ public void exception(Session ssn, SessionException exc)
{
- public void onClosed(ErrorCode errorCode, String reason, Throwable t)
+ synchronized (_currentExceptionLock)
{
- synchronized (_currentExceptionLock)
- {
- // todo check the error code for finding out if we need to notify the
- // JMS connection exception listener
- _currentException = new QpidException(reason, errorCode, t);
- }
+ _currentException = exc;
}
}
+ public void closed(Session ssn) {}
+
protected AMQShortString declareQueue(final AMQDestination amqd, final AMQProtocolHandler protocolHandler,
- final boolean noLocal)
+ final boolean noLocal, final boolean nowait)
throws AMQException
{
/*return new FailoverRetrySupport<AMQShortString, AMQException>(*/
@@ -678,44 +789,21 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
String binddingKey = "";
for(AMQShortString key : amqd.getBindingKeys())
{
- binddingKey = binddingKey + "_" + key.toString();
+ binddingKey = binddingKey + "_" + key.toString();
}
amqd.setQueueName(new AMQShortString( binddingKey + "@"
+ amqd.getExchangeName().toString() + "_" + UUID.randomUUID()));
}
- return send0_10QueueDeclare(amqd, protocolHandler, noLocal);
+ return send0_10QueueDeclare(amqd, protocolHandler, noLocal, nowait);
}
}, _connection).execute();
}
-
- void start() throws AMQException
- {
- super.start();
- for(BasicMessageConsumer c: _consumers.values())
- {
- c.start();
- }
- }
-
-
- void stop() throws AMQException
- {
- super.stop();
- for(BasicMessageConsumer c: _consumers.values())
- {
- c.stop();
- }
- }
-
-
-
-
public TopicSubscriber createDurableSubscriber(Topic topic, String name) throws JMSException
{
checkNotClosed();
- AMQTopic origTopic=checkValidTopic(topic);
+ AMQTopic origTopic=checkValidTopic(topic, true);
AMQTopic dest=AMQTopic.createDurable010Topic(origTopic, name, _connection);
TopicSubscriberAdaptor<BasicMessageConsumer_0_10> subscriber=_subscriptions.get(name);
@@ -786,19 +874,19 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
/**
* Store non committed messages for this session
* With 0.10 messages are consumed with window mode, we must send a completion
- * before the window size is reached so credits don't dry up.
+ * before the window size is reached so credits don't dry up.
* @param id
*/
@Override protected void addDeliveredMessage(long id)
{
_txRangeSet.add((int) id);
_txSize++;
- // this is a heuristic, we may want to have that configurable
+ // this is a heuristic, we may want to have that configurable
if (_connection.getMaxPrefetch() == 1 ||
_connection.getMaxPrefetch() != 0 && _txSize % (_connection.getMaxPrefetch() / 2) == 0)
{
// send completed so consumer credits don't dry up
- getQpidSession().messageAcknowledge(_txRangeSet, false);
+ messageAcknowledge(_txRangeSet, false);
}
}
@@ -809,7 +897,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic
{
if( _txSize > 0 )
{
- getQpidSession().messageAcknowledge(_txRangeSet, true);
+ messageAcknowledge(_txRangeSet, true);
_txRangeSet.clear();
_txSize = 0;
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java b/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
index 2442b157f1..862e23385a 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
@@ -33,8 +33,10 @@ import org.apache.qpid.client.message.*;
import org.apache.qpid.client.message.AMQMessageDelegateFactory;
import org.apache.qpid.client.protocol.AMQProtocolHandler;
import org.apache.qpid.client.state.listener.SpecificMethodFrameListener;
+import org.apache.qpid.client.state.AMQState;
import org.apache.qpid.common.AMQPFilterTypes;
import org.apache.qpid.framing.*;
+import org.apache.qpid.framing.amqp_0_91.MethodRegistry_0_91;
import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9;
import org.apache.qpid.jms.Session;
import org.apache.qpid.protocol.AMQConstant;
@@ -102,10 +104,12 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
}
getProtocolHandler().writeFrame(ackFrame);
+ _unacknowledgedMessageTags.remove(deliveryTag);
}
public void sendQueueBind(final AMQShortString queueName, final AMQShortString routingKey, final FieldTable arguments,
- final AMQShortString exchangeName, final AMQDestination dest) throws AMQException, FailoverException
+ final AMQShortString exchangeName, final AMQDestination dest,
+ final boolean nowait) throws AMQException, FailoverException
{
getProtocolHandler().syncWrite(getProtocolHandler().getMethodRegistry().createQueueBindBody
(getTicket(),queueName,exchangeName,routingKey,false,arguments).
@@ -114,12 +118,23 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
public void sendClose(long timeout) throws AMQException, FailoverException
{
- getProtocolHandler().closeSession(this);
- getProtocolHandler().syncWrite(getProtocolHandler().getMethodRegistry().createChannelCloseBody(AMQConstant.REPLY_SUCCESS.getCode(),
- new AMQShortString("JMS client closing channel"), 0, 0).generateFrame(_channelId),
- ChannelCloseOkBody.class, timeout);
- // When control resumes at this point, a reply will have been received that
- // indicates the broker has closed the channel successfully.
+ // we also need to check the state manager for 08/09 as the
+ // _connection variable may not be updated in time by the error receiving
+ // thread.
+ // We can't close the session if we are alreadying in the process of
+ // closing/closed the connection.
+
+ if (!(getProtocolHandler().getStateManager().getCurrentState().equals(AMQState.CONNECTION_CLOSED)
+ || getProtocolHandler().getStateManager().getCurrentState().equals(AMQState.CONNECTION_CLOSING)))
+ {
+
+ getProtocolHandler().closeSession(this);
+ getProtocolHandler().syncWrite(getProtocolHandler().getMethodRegistry().createChannelCloseBody(AMQConstant.REPLY_SUCCESS.getCode(),
+ new AMQShortString("JMS client closing channel"), 0, 0).generateFrame(_channelId),
+ ChannelCloseOkBody.class, timeout);
+ // When control resumes at this point, a reply will have been received that
+ // indicates the broker has closed the channel successfully.
+ }
}
public void sendCommit() throws AMQException, FailoverException
@@ -172,6 +187,11 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
BasicRecoverSyncBody body = ((MethodRegistry_0_9)getMethodRegistry()).createBasicRecoverSyncBody(false);
_connection.getProtocolHandler().syncWrite(body.generateFrame(_channelId), BasicRecoverSyncOkBody.class);
}
+ else if(getProtocolVersion().equals(ProtocolVersion.v0_91))
+ {
+ BasicRecoverSyncBody body = ((MethodRegistry_0_91)getMethodRegistry()).createBasicRecoverSyncBody(false);
+ _connection.getProtocolHandler().syncWrite(body.generateFrame(_channelId), BasicRecoverSyncOkBody.class);
+ }
else
{
throw new RuntimeException("Unsupported version of the AMQP Protocol: " + getProtocolVersion());
@@ -181,6 +201,12 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
public void releaseForRollback()
{
+ // Reject all the messages that have been received in this session and
+ // have not yet been acknowledged. Should look to remove
+ // _deliveredMessageTags and use _txRangeSet as used by 0-10.
+ // Otherwise messages will be able to arrive out of order to a second
+ // consumer on the queue. Whilst this is within the JMS spec it is not
+ // user friendly and avoidable.
while (true)
{
Long tag = _deliveredMessageTags.poll();
@@ -191,11 +217,6 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
rejectMessage(tag, true);
}
-
- if (_dispatcher != null)
- {
- _dispatcher.rollback();
- }
}
public void rejectMessage(long deliveryTag, boolean requeue)
@@ -297,13 +318,16 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
public void sendExchangeDeclare(final AMQShortString name, final AMQShortString type, final AMQProtocolHandler protocolHandler,
final boolean nowait) throws AMQException, FailoverException
{
- ExchangeDeclareBody body = getMethodRegistry().createExchangeDeclareBody(getTicket(),name,type,false,false,false,false,nowait,null);
+ ExchangeDeclareBody body = getMethodRegistry().createExchangeDeclareBody(getTicket(),name,type,
+ name.toString().startsWith("amq."),
+ false,false,false,false,null);
AMQFrame exchangeDeclare = body.generateFrame(_channelId);
protocolHandler.syncWrite(exchangeDeclare, ExchangeDeclareOkBody.class);
}
- public void sendQueueDeclare(final AMQDestination amqd, final AMQProtocolHandler protocolHandler) throws AMQException, FailoverException
+ public void sendQueueDeclare(final AMQDestination amqd, final AMQProtocolHandler protocolHandler,
+ final boolean nowait) throws AMQException, FailoverException
{
QueueDeclareBody body = getMethodRegistry().createQueueDeclareBody(getTicket(),amqd.getAMQQueueName(),false,amqd.isDurable(),amqd.isExclusive(),amqd.isAutoDelete(),false,null);
@@ -418,18 +442,11 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
getProtocolHandler().syncWrite(frame, TxRollbackOkBody.class);
}
- public TemporaryQueue createTemporaryQueue() throws JMSException
- {
- checkNotClosed();
-
- return new AMQTemporaryQueue(this);
- }
-
public TopicSubscriber createDurableSubscriber(Topic topic, String name) throws JMSException
{
checkNotClosed();
- AMQTopic origTopic = checkValidTopic(topic);
+ AMQTopic origTopic = checkValidTopic(topic, true);
AMQTopic dest = AMQTopic.createDurableTopic(origTopic, name, _connection);
TopicSubscriberAdaptor<BasicMessageConsumer_0_8> subscriber = _subscriptions.get(name);
if (subscriber != null)
@@ -493,7 +510,7 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B
- public void setPrefecthLimits(final int messagePrefetch, final long sizePrefetch) throws AMQException
+ public void setPrefetchLimits(final int messagePrefetch, final long sizePrefetch) throws AMQException
{
new FailoverRetrySupport<Object, AMQException>(
new FailoverProtectedOperation<Object, AMQException>()
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQTopicSessionAdaptor.java b/java/client/src/main/java/org/apache/qpid/client/AMQTopicSessionAdaptor.java
index f44f8414fa..ec482a8f79 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQTopicSessionAdaptor.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQTopicSessionAdaptor.java
@@ -115,7 +115,7 @@ public class AMQTopicSessionAdaptor implements TopicSession, AMQSessionAdapter
public ObjectMessage createObjectMessage(Serializable serializable) throws JMSException
{
- return _session.createObjectMessage();
+ return _session.createObjectMessage(serializable);
}
public StreamMessage createStreamMessage() throws JMSException
diff --git a/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java b/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java
index dfd228370c..bea43cc232 100644
--- a/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java
+++ b/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java
@@ -40,8 +40,9 @@ import java.util.SortedSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.TreeSet;
-import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
@@ -78,7 +79,7 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
* Used in the blocking receive methods to receive a message from the Session thread. <p/> Or to notify of errors
* <p/> Argument true indicates we want strict FIFO semantics
*/
- protected final ArrayBlockingQueue _synchronousQueue;
+ protected final BlockingQueue _synchronousQueue;
protected final MessageFactoryRegistry _messageFactory;
@@ -182,7 +183,7 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
_prefetchLow = prefetchLow;
_exclusive = exclusive;
- _synchronousQueue = new ArrayBlockingQueue(prefetchHigh, true);
+ _synchronousQueue = new LinkedBlockingQueue();
_autoClose = autoClose;
_noConsume = noConsume;
@@ -440,7 +441,9 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
o = _synchronousQueue.take();
}
return o;
- }
+ }
+
+ abstract Message receiveBrowse() throws JMSException;
public Message receiveNoWait() throws JMSException
{
@@ -540,6 +543,7 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
if (!_closed.getAndSet(true))
{
+ _closing.set(true);
if (_logger.isDebugEnabled())
{
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
@@ -560,7 +564,13 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
{
try
{
- sendCancel();
+ // If the session is open or we are in the process
+ // of closing the session then send a cance
+ // no point otherwise as the connection will be gone
+ if (!_session.isClosed() || _session.isClosing())
+ {
+ sendCancel();
+ }
}
catch (AMQException e)
{
@@ -769,15 +779,16 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
else
{
_session.addDeliveredMessage(msg.getDeliveryTag());
+ _session.markDirty();
}
break;
}
+
}
void postDeliver(AbstractJMSMessage msg) throws JMSException
{
- msg.setJMSDestination(_destination);
switch (_acknowledgeMode)
{
@@ -1036,23 +1047,6 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
_synchronousQueue.clear();
}
- public void start()
- {
- // do nothing as this is a 0_10 feature
- }
-
-
- public void stop()
- {
- // do nothing as this is a 0_10 feature
- }
-
- public boolean isStrated()
- {
- // do nothing as this is a 0_10 feature
- return false;
- }
-
public AMQShortString getQueuename()
{
return _queuename;
@@ -1069,10 +1063,13 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa
}
/** to be called when a failover has occured */
- public void failedOver()
+ public void failedOverPre()
{
clearReceiveQueue();
// TGM FIXME: think this should just be removed
// clearUnackedMessages();
}
+
+ public void failedOverPost() {}
+
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java b/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java
index 2a37298a43..1b2d6876bd 100644
--- a/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java
+++ b/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java
@@ -31,6 +31,7 @@ import org.apache.qpid.filter.JMSSelectorFilter;
import javax.jms.InvalidSelectorException;
import javax.jms.JMSException;
+import javax.jms.Message;
import javax.jms.MessageListener;
import java.util.Iterator;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -39,7 +40,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
* This is a 0.10 message consumer.
*/
public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedMessage_0_10>
- implements org.apache.qpid.nclient.MessagePartListener
{
/**
@@ -114,9 +114,6 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM
return _consumerTagString;
}
-
- // ----- Interface org.apache.qpid.client.util.MessageListener
-
/**
*
* This is invoked by the session thread when emptying the session message queue.
@@ -152,35 +149,14 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM
if (isMessageListenerSet() && ! getSession().prefetch())
{
_0_10session.getQpidSession().messageFlow(getConsumerTagString(),
- MessageCreditUnit.MESSAGE, 1);
+ MessageCreditUnit.MESSAGE, 1,
+ Option.UNRELIABLE);
}
_logger.debug("messageOk, trying to notify");
super.notifyMessage(jmsMessage);
}
}
-
-
- /**
- * This method is invoked by the transport layer when a message is delivered for this
- * consumer. The message is transformed and pass to the session.
- * @param xfr an 0.10 message transfer
- */
- public void messageTransfer(MessageTransfer xfr)
-
- //public void onMessage(Message message)
- {
- int channelId = getSession().getChannelId();
- int consumerTag = getConsumerTag();
-
- UnprocessedMessage_0_10 newMessage =
- new UnprocessedMessage_0_10(consumerTag, xfr);
-
-
- getSession().messageReceived(newMessage);
- // else ignore this message
- }
-
//----- overwritten methods
/**
@@ -272,7 +248,8 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM
if(! getSession().prefetch())
{
_0_10session.getQpidSession().messageFlow(getConsumerTagString(),
- MessageCreditUnit.MESSAGE, 1);
+ MessageCreditUnit.MESSAGE, 1,
+ Option.UNRELIABLE);
}
}
// now we need to acquire this message if needed
@@ -284,9 +261,7 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM
_logger.debug("filterMessage - trying to acquire message");
}
messageOk = acquireMessage(message);
- _logger.debug("filterMessage - *************************************");
_logger.debug("filterMessage - message acquire status : " + messageOk);
- _logger.debug("filterMessage - *************************************");
}
return messageOk;
}
@@ -304,8 +279,9 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM
{
RangeSet ranges = new RangeSet();
ranges.add((int) message.getDeliveryTag());
- _0_10session.getQpidSession().messageAcknowledge(ranges,
- _acknowledgeMode != org.apache.qpid.jms.Session.NO_ACKNOWLEDGE );
+ _0_10session.messageAcknowledge
+ (ranges,
+ _acknowledgeMode != org.apache.qpid.jms.Session.NO_ACKNOWLEDGE);
_0_10session.getCurrentException();
}
}
@@ -360,7 +336,8 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM
if (messageListener != null && ! getSession().prefetch())
{
_0_10session.getQpidSession().messageFlow(getConsumerTagString(),
- MessageCreditUnit.MESSAGE, 1);
+ MessageCreditUnit.MESSAGE, 1,
+ Option.UNRELIABLE);
}
if (messageListener != null && !_synchronousQueue.isEmpty())
{
@@ -374,26 +351,16 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM
}
}
- public boolean isStrated()
+ public void failedOverPost()
{
- return _isStarted;
- }
-
- public void start()
- {
- _isStarted = true;
- if (_syncReceive.get())
+ if (_0_10session.isStarted() && _syncReceive.get())
{
- _0_10session.getQpidSession().messageFlow(getConsumerTagString(),
- MessageCreditUnit.MESSAGE, 1);
+ _0_10session.getQpidSession().messageFlow
+ (getConsumerTagString(), MessageCreditUnit.MESSAGE, 1,
+ Option.UNRELIABLE);
}
}
- public void stop()
- {
- _isStarted = false;
- }
-
/**
* When messages are not prefetched we need to request a message from the
* broker.
@@ -405,16 +372,35 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM
*/
public Object getMessageFromQueue(long l) throws InterruptedException
{
- if (isStrated() && ! getSession().prefetch() && _synchronousQueue.isEmpty())
- {
- _0_10session.getQpidSession().messageFlow(getConsumerTagString(),
- MessageCreditUnit.MESSAGE, 1);
- }
if (! getSession().prefetch())
{
_syncReceive.set(true);
}
+ if (_0_10session.isStarted() && ! getSession().prefetch() && _synchronousQueue.isEmpty())
+ {
+ _0_10session.getQpidSession().messageFlow(getConsumerTagString(),
+ MessageCreditUnit.MESSAGE, 1,
+ Option.UNRELIABLE);
+ }
Object o = super.getMessageFromQueue(l);
+ if (o == null && _0_10session.isStarted())
+ {
+ _0_10session.getQpidSession().messageFlush
+ (getConsumerTagString(), Option.UNRELIABLE, Option.SYNC);
+ _0_10session.getQpidSession().sync();
+ _0_10session.getQpidSession().messageFlow
+ (getConsumerTagString(), MessageCreditUnit.BYTE,
+ 0xFFFFFFFF, Option.UNRELIABLE);
+ if (getSession().prefetch())
+ {
+ _0_10session.getQpidSession().messageFlow
+ (getConsumerTagString(), MessageCreditUnit.MESSAGE,
+ _0_10session.getAMQConnection().getMaxPrefetch(),
+ Option.UNRELIABLE);
+ }
+ _0_10session.syncDispatchQueue();
+ o = super.getMessageFromQueue(-1);
+ }
if (! getSession().prefetch())
{
_syncReceive.set(false);
@@ -425,10 +411,50 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM
void postDeliver(AbstractJMSMessage msg) throws JMSException
{
super.postDeliver(msg);
- if(_acknowledgeMode == org.apache.qpid.jms.Session.NO_ACKNOWLEDGE && !_session.isInRecovery())
+ if (_acknowledgeMode == org.apache.qpid.jms.Session.NO_ACKNOWLEDGE && !_session.isInRecovery())
+ {
+ _session.acknowledgeMessage(msg.getDeliveryTag(), false);
+ }
+
+ if (_acknowledgeMode == org.apache.qpid.jms.Session.AUTO_ACKNOWLEDGE &&
+ !_session.isInRecovery() &&
+ _session.getAMQConnection().getSyncAck())
{
- _session.acknowledgeMessage(msg.getDeliveryTag(), false);
- }
+ ((AMQSession_0_10) getSession()).flushAcknowledgments();
+ ((AMQSession_0_10) getSession()).getQpidSession().sync();
+ }
+ }
+
+ Message receiveBrowse() throws JMSException
+ {
+ return receiveNoWait();
}
+ @Override public void rollbackPendingMessages()
+ {
+ if (_synchronousQueue.size() > 0)
+ {
+ RangeSet ranges = new RangeSet();
+ Iterator iterator = _synchronousQueue.iterator();
+ while (iterator.hasNext())
+ {
+
+ Object o = iterator.next();
+ if (o instanceof AbstractJMSMessage)
+ {
+ ranges.add((int) ((AbstractJMSMessage) o).getDeliveryTag());
+ iterator.remove();
+ }
+ else
+ {
+ _logger.error("Queue contained a :" + o.getClass()
+ + " unable to reject as it is not an AbstractJMSMessage. Will be cleared");
+ iterator.remove();
+ }
+ }
+
+ _0_10session.getQpidSession().messageRelease(ranges, Option.SET_REDELIVERED);
+ clearReceiveQueue();
+ }
+ }
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java b/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java
index 494a8fb43d..308f04f082 100644
--- a/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java
+++ b/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java
@@ -22,6 +22,7 @@ package org.apache.qpid.client;
import javax.jms.InvalidSelectorException;
import javax.jms.JMSException;
+import javax.jms.Message;
import org.apache.qpid.AMQException;
import org.apache.qpid.QpidException;
@@ -38,9 +39,9 @@ public class BasicMessageConsumer_0_8 extends BasicMessageConsumer<UnprocessedMe
protected final Logger _logger = LoggerFactory.getLogger(getClass());
protected BasicMessageConsumer_0_8(int channelId, AMQConnection connection, AMQDestination destination,
- String messageSelector, boolean noLocal, MessageFactoryRegistry messageFactory, AMQSession session,
- AMQProtocolHandler protocolHandler, FieldTable arguments, int prefetchHigh, int prefetchLow,
- boolean exclusive, int acknowledgeMode, boolean noConsume, boolean autoClose) throws JMSException
+ String messageSelector, boolean noLocal, MessageFactoryRegistry messageFactory, AMQSession session,
+ AMQProtocolHandler protocolHandler, FieldTable arguments, int prefetchHigh, int prefetchLow,
+ boolean exclusive, int acknowledgeMode, boolean noConsume, boolean autoClose) throws JMSException
{
super(channelId, connection, destination,messageSelector,noLocal,messageFactory,session,
protocolHandler, arguments, prefetchHigh, prefetchLow, exclusive,
@@ -73,13 +74,18 @@ public class BasicMessageConsumer_0_8 extends BasicMessageConsumer<UnprocessedMe
}
}
- public AbstractJMSMessage createJMSMessageFromUnprocessedMessage(AMQMessageDelegateFactory delegateFactory, UnprocessedMessage_0_8 messageFrame)throws Exception
- {
+ public AbstractJMSMessage createJMSMessageFromUnprocessedMessage(AMQMessageDelegateFactory delegateFactory, UnprocessedMessage_0_8 messageFrame)throws Exception
+ {
return _messageFactory.createMessage(messageFrame.getDeliveryTag(),
- messageFrame.isRedelivered(), messageFrame.getExchange(),
- messageFrame.getRoutingKey(), messageFrame.getContentHeader(), messageFrame.getBodies());
+ messageFrame.isRedelivered(), messageFrame.getExchange(),
+ messageFrame.getRoutingKey(), messageFrame.getContentHeader(), messageFrame.getBodies());
+
+ }
+ Message receiveBrowse() throws JMSException
+ {
+ return receive();
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java b/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java
index beaa47ed1e..df59be25d0 100644
--- a/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java
+++ b/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java
@@ -46,19 +46,21 @@ import org.slf4j.LoggerFactory;
public abstract class BasicMessageProducer extends Closeable implements org.apache.qpid.jms.MessageProducer
{
+ enum PublishMode { ASYNC_PUBLISH_ALL, SYNC_PUBLISH_PERSISTENT, SYNC_PUBLISH_ALL };
+
protected final Logger _logger = LoggerFactory.getLogger(getClass());
private AMQConnection _connection;
/**
- * If true, messages will not get a timestamp.
+ * If true, messages will not get a timestamp.
*/
protected boolean _disableTimestamps;
/**
* Priority of messages created by this producer.
*/
- private int _messagePriority;
+ private int _messagePriority = Message.DEFAULT_PRIORITY;
/**
* Time to live of messages. Specified in milliseconds but AMQ has 1 second resolution.
@@ -103,7 +105,7 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac
private long _producerId;
/**
- * The session used to create this producer
+ * The session used to create this producer
*/
protected AMQSession _session;
@@ -117,8 +119,12 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac
private UUIDGen _messageIdGenerator = UUIDs.newGenerator();
+ protected String _userID; // ref user id used in the connection.
+
private static final ContentBody[] NO_CONTENT_BODIES = new ContentBody[0];
+ protected PublishMode publishMode = PublishMode.ASYNC_PUBLISH_ALL;
+
protected BasicMessageProducer(AMQConnection connection, AMQDestination destination, boolean transacted, int channelId,
AMQSession session, AMQProtocolHandler protocolHandler, long producerId, boolean immediate, boolean mandatory,
boolean waitUntilSent)
@@ -138,6 +144,27 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac
_immediate = immediate;
_mandatory = mandatory;
_waitUntilSent = waitUntilSent;
+ _userID = connection.getUsername();
+ setPublishMode();
+ }
+
+ void setPublishMode()
+ {
+ // Publish mode could be configured at destination level as well.
+ // Will add support for this when we provide a more robust binding URL
+
+ String syncPub = _connection.getSyncPublish();
+ // Support for deprecated option sync_persistence
+ if (syncPub.equals("persistent") || _connection.getSyncPersistence())
+ {
+ publishMode = PublishMode.SYNC_PUBLISH_PERSISTENT;
+ }
+ else if (syncPub.equals("all"))
+ {
+ publishMode = PublishMode.SYNC_PUBLISH_ALL;
+ }
+
+ _logger.info("MessageProducer " + toString() + " using publish mode : " + publishMode);
}
void resubscribe() throws AMQException
@@ -250,6 +277,7 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac
checkPreConditions();
checkInitialDestination();
+
synchronized (_connection.getFailoverMutex())
{
sendImpl(_destination, message, _deliveryMode, _messagePriority, _timeToLive, _mandatory, _immediate);
@@ -521,6 +549,10 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac
{
throw new javax.jms.IllegalStateException("Invalid Session");
}
+ if(_session.getAMQConnection().isClosed())
+ {
+ throw new javax.jms.IllegalStateException("Connection closed");
+ }
}
private void checkInitialDestination()
diff --git a/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java b/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java
index 02c5526e03..a1b5ce6f4c 100644
--- a/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java
+++ b/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java
@@ -35,7 +35,7 @@ import org.apache.qpid.client.protocol.AMQProtocolHandler;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.BasicContentHeaderProperties;
import org.apache.qpid.url.AMQBindingURL;
-import org.apache.qpid.nclient.util.ByteBufferMessage;
+import org.apache.qpid.util.Strings;
import org.apache.qpid.njms.ExceptionHelper;
import org.apache.qpid.transport.*;
import static org.apache.qpid.transport.Option.*;
@@ -45,6 +45,7 @@ import static org.apache.qpid.transport.Option.*;
*/
public class BasicMessageProducer_0_10 extends BasicMessageProducer
{
+ private byte[] userIDBytes;
BasicMessageProducer_0_10(AMQConnection connection, AMQDestination destination, boolean transacted, int channelId,
AMQSession session, AMQProtocolHandler protocolHandler, long producerId,
@@ -52,13 +53,18 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer
{
super(connection, destination, transacted, channelId, session, protocolHandler, producerId, immediate,
mandatory, waitUntilSent);
+
+ userIDBytes = Strings.toUTF8(_userID);
}
void declareDestination(AMQDestination destination)
{
- ((AMQSession_0_10) getSession()).getQpidSession().exchangeDeclare(destination.getExchangeName().toString(),
- destination.getExchangeClass().toString(),
- null, null);
+ String name = destination.getExchangeName().toString();
+ ((AMQSession_0_10) getSession()).getQpidSession().exchangeDeclare
+ (name,
+ destination.getExchangeClass().toString(),
+ null, null,
+ name.startsWith("amq.") ? Option.PASSIVE : Option.NONE);
}
//--- Overwritten methods
@@ -77,6 +83,9 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer
DeliveryProperties deliveryProp = delegate.getDeliveryProperties();
MessageProperties messageProps = delegate.getMessageProperties();
+ // On the receiving side, this will be read in to the JMSXUserID as well.
+ messageProps.setUserId(userIDBytes);
+
if (messageId != null)
{
messageProps.setMessageId(messageId);
@@ -86,20 +95,22 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer
messageProps.clearMessageId();
}
+ long currentTime = 0;
+ if (timeToLive > 0 || !_disableTimestamps)
+ {
+ currentTime = System.currentTimeMillis();
+ }
+
+ if (timeToLive > 0)
+ {
+ deliveryProp.setTtl(timeToLive);
+ message.setJMSExpiration(currentTime + timeToLive);
+ }
+
if (!_disableTimestamps)
{
- final long currentTime = System.currentTimeMillis();
- deliveryProp.setTimestamp(currentTime);
- if (timeToLive > 0)
- {
- deliveryProp.setExpiration(currentTime + timeToLive);
- message.setJMSExpiration(currentTime + timeToLive);
- }
- else
- {
- deliveryProp.setExpiration(0);
- message.setJMSExpiration(0);
- }
+
+ deliveryProp.setTimestamp(currentTime);
message.setJMSTimestamp(currentTime);
}
@@ -145,9 +156,13 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer
((AMQSession_0_10) getSession()).getQpidSession();
// if true, we need to sync the delivery of this message
- boolean sync = (deliveryMode == DeliveryMode.PERSISTENT &&
- getSession().getAMQConnection().getSyncPersistence());
+ boolean sync = false;
+ sync = ( (publishMode == PublishMode.SYNC_PUBLISH_ALL) ||
+ (publishMode == PublishMode.SYNC_PUBLISH_PERSISTENT &&
+ deliveryMode == DeliveryMode.PERSISTENT)
+ );
+
org.apache.mina.common.ByteBuffer data = message.getData();
ByteBuffer buffer = data == null ? ByteBuffer.allocate(0) : data.buf().slice();
@@ -159,11 +174,12 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer
{
ssn.sync();
}
+
+
}
catch (RuntimeException rte)
{
JMSException ex = new JMSException("Exception when sending message");
- rte.printStackTrace();
ex.setLinkedException(rte);
throw ex;
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java b/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java
index c547fcb488..f726cd02a2 100644
--- a/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java
+++ b/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java
@@ -24,6 +24,8 @@ import java.util.UUID;
import javax.jms.JMSException;
import javax.jms.Message;
+import javax.jms.Topic;
+import javax.jms.Queue;
import org.apache.mina.common.ByteBuffer;
import org.apache.qpid.client.message.AbstractJMSMessage;
@@ -86,6 +88,26 @@ public class BasicMessageProducer_0_8 extends BasicMessageProducer
AMQMessageDelegate_0_8 delegate = (AMQMessageDelegate_0_8) message.getDelegate();
BasicContentHeaderProperties contentHeaderProperties = delegate.getContentHeaderProperties();
+ contentHeaderProperties.setUserId(_userID);
+
+ //Set the JMS_QPID_DESTTYPE for 0-8/9 messages
+ int type;
+ if (destination instanceof Topic)
+ {
+ type = AMQDestination.TOPIC_TYPE;
+ }
+ else if (destination instanceof Queue)
+ {
+ type = AMQDestination.QUEUE_TYPE;
+ }
+ else
+ {
+ type = AMQDestination.UNKNOWN_TYPE;
+ }
+
+ //Set JMS_QPID_DESTTYPE
+ delegate.getContentHeaderProperties().getHeaders().setInteger(CustomJMSXProperty.JMS_QPID_DESTTYPE.getShortStringName(), type);
+
if (!_disableTimestamps)
{
final long currentTime = System.currentTimeMillis();
diff --git a/java/client/src/main/java/org/apache/qpid/client/Closeable.java b/java/client/src/main/java/org/apache/qpid/client/Closeable.java
index 7e119343a1..e6771e122c 100644
--- a/java/client/src/main/java/org/apache/qpid/client/Closeable.java
+++ b/java/client/src/main/java/org/apache/qpid/client/Closeable.java
@@ -52,6 +52,13 @@ public abstract class Closeable
protected final AtomicBoolean _closed = new AtomicBoolean(false);
/**
+ * Are we in the process of closing. We have this distinction so we can
+ * still signal we are in the process of closing so other objects can tell
+ * the difference and tidy up.
+ */
+ protected final AtomicBoolean _closing = new AtomicBoolean(false);
+
+ /**
* Checks if this is closed, and raises a JMSException if it is.
*
* @throws JMSException If this is closed.
@@ -75,6 +82,17 @@ public abstract class Closeable
}
/**
+ * Checks if this is closis.
+ *
+ * @return <tt>true</tt> if we are closing, <tt>false</tt> otherwise.
+ */
+ public boolean isClosing()
+ {
+ return _closing.get();
+ }
+
+
+ /**
* Closes this object.
*
* @throws JMSException If this cannot be closed for any reason.
diff --git a/java/client/src/main/java/org/apache/qpid/client/XAConnectionImpl.java b/java/client/src/main/java/org/apache/qpid/client/XAConnectionImpl.java
index 476536e42b..43025bd724 100644
--- a/java/client/src/main/java/org/apache/qpid/client/XAConnectionImpl.java
+++ b/java/client/src/main/java/org/apache/qpid/client/XAConnectionImpl.java
@@ -47,7 +47,7 @@ public class XAConnectionImpl extends AMQConnection implements XAConnection, XAQ
public synchronized XASession createXASession() throws JMSException
{
checkNotClosed();
- return _delegate.createXASession(AMQSession.DEFAULT_PREFETCH_HIGH_MARK, AMQSession.DEFAULT_PREFETCH_HIGH_MARK);
+ return _delegate.createXASession();
}
//-- Interface XAQueueConnection
diff --git a/java/client/src/main/java/org/apache/qpid/client/XAResourceImpl.java b/java/client/src/main/java/org/apache/qpid/client/XAResourceImpl.java
index 6763c72ecd..35adda9348 100644
--- a/java/client/src/main/java/org/apache/qpid/client/XAResourceImpl.java
+++ b/java/client/src/main/java/org/apache/qpid/client/XAResourceImpl.java
@@ -88,8 +88,7 @@ public class XAResourceImpl implements XAResource
{
// we need to restore the qpid session that has been closed
_xaSession.createSession();
- // we should get a single exception
- convertExecutionErrorToXAErr(e.getExceptions().get(0).getErrorCode());
+ convertExecutionErrorToXAErr(e.getException().getErrorCode());
}
checkStatus(result.getStatus());
}
@@ -142,8 +141,7 @@ public class XAResourceImpl implements XAResource
{
// we need to restore the qpid session that has been closed
_xaSession.createSession();
- // we should get a single exception
- convertExecutionErrorToXAErr(e.getExceptions().get(0).getErrorCode());
+ convertExecutionErrorToXAErr(e.getException().getErrorCode());
}
checkStatus(result.getStatus());
}
@@ -171,8 +169,7 @@ public class XAResourceImpl implements XAResource
{
// we need to restore the qpid session that has been closed
_xaSession.createSession();
- // we should get a single exception
- convertExecutionErrorToXAErr(e.getExceptions().get(0).getErrorCode());
+ convertExecutionErrorToXAErr(e.getException().getErrorCode());
}
}
@@ -201,8 +198,7 @@ public class XAResourceImpl implements XAResource
{
// we need to restore the qpid session that has been closed
_xaSession.createSession();
- // we should get a single exception
- convertExecutionErrorToXAErr(e.getExceptions().get(0).getErrorCode());
+ convertExecutionErrorToXAErr(e.getException().getErrorCode());
}
}
return result;
@@ -248,8 +244,7 @@ public class XAResourceImpl implements XAResource
{
// we need to restore the qpid session that has been closed
_xaSession.createSession();
- // we should get a single exception
- convertExecutionErrorToXAErr(e.getExceptions().get(0).getErrorCode());
+ convertExecutionErrorToXAErr(e.getException().getErrorCode());
}
DtxXaStatus status = result.getStatus();
int outcome = XAResource.XA_OK;
@@ -291,8 +286,7 @@ public class XAResourceImpl implements XAResource
{
// we need to restore the qpid session that has been closed
_xaSession.createSession();
- // we should get a single exception
- convertExecutionErrorToXAErr( e.getExceptions().get(0).getErrorCode());
+ convertExecutionErrorToXAErr( e.getException().getErrorCode());
}
Xid[] result = new Xid[res.getInDoubt().size()];
int i = 0;
@@ -329,8 +323,7 @@ public class XAResourceImpl implements XAResource
{
// we need to restore the qpid session that has been closed
_xaSession.createSession();
- // we should get a single exception
- convertExecutionErrorToXAErr( e.getExceptions().get(0).getErrorCode());
+ convertExecutionErrorToXAErr( e.getException().getErrorCode());
}
checkStatus(result.getStatus());
}
@@ -413,8 +406,7 @@ public class XAResourceImpl implements XAResource
{
// we need to restore the qpid session that has been closed
_xaSession.createSession();
- // we should get a single exception
- convertExecutionErrorToXAErr(e.getExceptions().get(0).getErrorCode());
+ convertExecutionErrorToXAErr(e.getException().getErrorCode());
// TODO: The amqp spec does not allow to make the difference
// between an already known XID and a wrong arguments (join and resume are set)
// TODO: make sure amqp addresses that
diff --git a/java/client/src/main/java/org/apache/qpid/client/XASessionImpl.java b/java/client/src/main/java/org/apache/qpid/client/XASessionImpl.java
index 51b4b7899f..354b67cd35 100644
--- a/java/client/src/main/java/org/apache/qpid/client/XASessionImpl.java
+++ b/java/client/src/main/java/org/apache/qpid/client/XASessionImpl.java
@@ -17,7 +17,6 @@
*/
package org.apache.qpid.client;
-import org.apache.qpid.nclient.DtxSession;
import org.apache.qpid.client.message.MessageFactoryRegistry;
import javax.jms.*;
@@ -36,7 +35,7 @@ public class XASessionImpl extends AMQSession_0_10 implements XASession, XATopic
/**
* This XASession Qpid DtxSession
*/
- private DtxSession _qpidDtxSession;
+ private org.apache.qpid.transport.Session _qpidDtxSession;
/**
* The standard session
@@ -48,7 +47,7 @@ public class XASessionImpl extends AMQSession_0_10 implements XASession, XATopic
/**
* Create a JMS XASession
*/
- public XASessionImpl(org.apache.qpid.nclient.Connection qpidConnection, AMQConnection con, int channelId,
+ public XASessionImpl(org.apache.qpid.transport.Connection qpidConnection, AMQConnection con, int channelId,
int defaultPrefetchHigh, int defaultPrefetchLow)
{
super(qpidConnection, con, channelId, false, // this is not a transacted session
@@ -65,7 +64,9 @@ public class XASessionImpl extends AMQSession_0_10 implements XASession, XATopic
*/
public void createSession()
{
- _qpidDtxSession = _qpidConnection.createDTXSession(0);
+ _qpidDtxSession = _qpidConnection.createSession(0);
+ _qpidDtxSession.setSessionListener(this);
+ _qpidDtxSession.dtxSelect();
}
@@ -126,7 +127,7 @@ public class XASessionImpl extends AMQSession_0_10 implements XASession, XATopic
*
* @return The associated Qpid Session.
*/
- protected org.apache.qpid.nclient.DtxSession getQpidSession()
+ protected org.apache.qpid.transport.Session getQpidSession()
{
return _qpidDtxSession;
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/configuration/ClientProperties.java b/java/client/src/main/java/org/apache/qpid/client/configuration/ClientProperties.java
index edda18c715..e5050b4fbd 100644
--- a/java/client/src/main/java/org/apache/qpid/client/configuration/ClientProperties.java
+++ b/java/client/src/main/java/org/apache/qpid/client/configuration/ClientProperties.java
@@ -33,13 +33,13 @@ public class ClientProperties
public static final String IGNORE_SET_CLIENTID_PROP_NAME = "ignore_setclientID";
/**
- * This property is currently used within the 0.10 code path only
+ * This property is currently used within the 0.10 code path only
* The maximum number of pre-fetched messages per destination
* This property is used for all the connection unless it is overwritten by the connectionURL
* type: long
*/
public static final String MAX_PREFETCH_PROP_NAME = "max_prefetch";
- public static final String MAX_PREFETCH_DEFAULT = "1000";
+ public static final String MAX_PREFETCH_DEFAULT = "500";
/**
* When true a sync command is sent after every persistent messages.
@@ -47,6 +47,31 @@ public class ClientProperties
*/
public static final String SYNC_PERSISTENT_PROP_NAME = "sync_persistence";
+ /**
+ * When true a sync command is sent after sending a message ack.
+ * type: boolean
+ */
+ public static final String SYNC_ACK_PROP_NAME = "sync_ack";
+
+ /**
+ * sync_publish property - {persistent|all}
+ * If set to 'persistent',then persistent messages will be publish synchronously
+ * If set to 'all', then all messages regardless of the delivery mode will be
+ * published synchronously.
+ */
+ public static final String SYNC_PUBLISH_PROP_NAME = "sync_publish";
+
+ /**
+ * This value will be used in the following settings
+ * To calculate the SO_TIMEOUT option of the socket (2*idle_timeout)
+ * If this values is between the max and min values specified for heartbeat
+ * by the broker in TuneOK it will be used as the heartbeat interval.
+ * If not a warning will be printed and the max value specified for
+ * heartbeat in TuneOK will be used
+ */
+ public static final String IDLE_TIMEOUT_PROP_NAME = "idle_timeout";
+
+
/**
* ==========================================================
* Those properties are used when the io size should be bounded
@@ -75,4 +100,6 @@ public class ClientProperties
*/
public static final String WRITE_BUFFER_LIMIT_PROP_NAME = "qpid.read.buffer.limit";
public static final String WRITE_BUFFER_LIMIT_DEFAULT = "262144";
+
+ public static final String AMQP_VERSION = "qpid.amqp.version";
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java b/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java
index 927f660932..f74dbba939 100644
--- a/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java
+++ b/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java
@@ -20,11 +20,10 @@
*/
package org.apache.qpid.client.failover;
-import org.apache.mina.common.IoSession;
-
import org.apache.qpid.AMQDisconnectedException;
import org.apache.qpid.client.protocol.AMQProtocolHandler;
import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.state.AMQState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -81,9 +80,6 @@ public class FailoverHandler implements Runnable
/** Used for debugging. */
private static final Logger _logger = LoggerFactory.getLogger(FailoverHandler.class);
- /** Holds the MINA session for the connection that has failed, not the connection that is being failed onto. */
- private final IoSession _session;
-
/** Holds the protocol handler for the failed connection, upon which the new connection is to be set up. */
private AMQProtocolHandler _amqProtocolHandler;
@@ -97,12 +93,10 @@ public class FailoverHandler implements Runnable
* Creates a failover handler on a protocol session, for a particular MINA session (network connection).
*
* @param amqProtocolHandler The protocol handler that spans the failover.
- * @param session The MINA session, for the failing connection.
*/
- public FailoverHandler(AMQProtocolHandler amqProtocolHandler, IoSession session)
+ public FailoverHandler(AMQProtocolHandler amqProtocolHandler)
{
_amqProtocolHandler = amqProtocolHandler;
- _session = session;
}
/**
@@ -140,6 +134,8 @@ public class FailoverHandler implements Runnable
// a slightly more complex state model therefore I felt it was worthwhile doing this.
AMQStateManager existingStateManager = _amqProtocolHandler.getStateManager();
+
+ // Use a fresh new StateManager for the reconnection attempts
_amqProtocolHandler.setStateManager(new AMQStateManager());
@@ -194,9 +190,25 @@ public class FailoverHandler implements Runnable
}
else
{
- // Set the new Protocol Session in the StateManager.
+ // Set the new Protocol Session in the StateManager.
existingStateManager.setProtocolSession(_amqProtocolHandler.getProtocolSession());
+ // Now that the ProtocolHandler has been reconnected clean up
+ // the state of the old state manager. As if we simply reinstate
+ // it any old exception that had occured prior to failover may
+ // prohibit reconnection.
+ // e.g. During testing when the broker is shutdown gracefully.
+ // The broker
+ // Clear any exceptions we gathered
+ if (existingStateManager.getCurrentState() != AMQState.CONNECTION_OPEN)
+ {
+ // Clear the state of the previous state manager as it may
+ // have received an exception
+ existingStateManager.clearLastException();
+ existingStateManager.changeState(AMQState.CONNECTION_OPEN);
+ }
+
+
//Restore Existing State Manager
_amqProtocolHandler.setStateManager(existingStateManager);
try
@@ -221,7 +233,7 @@ public class FailoverHandler implements Runnable
_amqProtocolHandler.setFailoverState(FailoverState.FAILED);
/*try
{*/
- _amqProtocolHandler.exceptionCaught(_session, e);
+ _amqProtocolHandler.exception(e);
/*}
catch (Exception ex)
{
diff --git a/java/client/src/main/java/org/apache/qpid/client/failover/FailoverRetrySupport.java b/java/client/src/main/java/org/apache/qpid/client/failover/FailoverRetrySupport.java
index cf7e978c03..e9e52cc97c 100644
--- a/java/client/src/main/java/org/apache/qpid/client/failover/FailoverRetrySupport.java
+++ b/java/client/src/main/java/org/apache/qpid/client/failover/FailoverRetrySupport.java
@@ -99,37 +99,6 @@ public class FailoverRetrySupport<T, E extends Exception> implements FailoverSup
*/
public T execute() throws E
{
- while (true)
- {
- try
- {
- connection.blockUntilNotFailingOver();
- }
- catch (InterruptedException e)
- {
- _log.debug("Interrupted: " + e, e);
-
- return null;
- }
-
- synchronized (connection.getFailoverMutex())
- {
- try
- {
- return operation.execute();
- }
- catch (FailoverException e)
- {
- _log.debug("Failover exception caught during operation: " + e, e);
- }
- catch (IllegalStateException e)
- {
- if (!(e.getMessage().startsWith("Fail-over interupted no-op failover support")))
- {
- throw e;
- }
- }
- }
- }
+ return connection.executeRetrySupport(operation);
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/handler/AccessRequestOkMethodHandler.java b/java/client/src/main/java/org/apache/qpid/client/handler/AccessRequestOkMethodHandler.java
index 365fed6aa5..af47673a43 100644
--- a/java/client/src/main/java/org/apache/qpid/client/handler/AccessRequestOkMethodHandler.java
+++ b/java/client/src/main/java/org/apache/qpid/client/handler/AccessRequestOkMethodHandler.java
@@ -1,4 +1,25 @@
package org.apache.qpid.client.handler;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java b/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java
index 2b6745ebe4..2cf19bf391 100644
--- a/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java
+++ b/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java
@@ -32,7 +32,6 @@ import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.ChannelCloseBody;
import org.apache.qpid.framing.ChannelCloseOkBody;
import org.apache.qpid.protocol.AMQConstant;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -48,7 +47,7 @@ public class ChannelCloseMethodHandler implements StateAwareMethodListener<Chann
}
public void methodReceived(AMQProtocolSession session, ChannelCloseBody method, int channelId)
- throws AMQException
+ throws AMQException
{
_logger.debug("ChannelClose method received");
@@ -59,52 +58,62 @@ public class ChannelCloseMethodHandler implements StateAwareMethodListener<Chann
_logger.debug("Channel close reply code: " + errorCode + ", reason: " + reason);
}
-
-
ChannelCloseOkBody body = session.getMethodRegistry().createChannelCloseOkBody();
AMQFrame frame = body.generateFrame(channelId);
session.writeFrame(frame);
-
- if (errorCode != AMQConstant.REPLY_SUCCESS)
+ try
{
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Channel close received with errorCode " + errorCode + ", and reason " + reason);
- }
-
- if (errorCode == AMQConstant.NO_CONSUMERS)
- {
- throw new AMQNoConsumersException("Error: " + reason, null, null);
- }
- else if (errorCode == AMQConstant.NO_ROUTE)
- {
- throw new AMQNoRouteException("Error: " + reason, null, null);
- }
- else if (errorCode == AMQConstant.INVALID_ARGUMENT)
+ if (errorCode != AMQConstant.REPLY_SUCCESS)
{
- _logger.debug("Broker responded with Invalid Argument.");
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Channel close received with errorCode " + errorCode + ", and reason " + reason);
+ }
+
+ if (errorCode == AMQConstant.NO_CONSUMERS)
+ {
+ throw new AMQNoConsumersException("Error: " + reason, null, null);
+ }
+ else if (errorCode == AMQConstant.NO_ROUTE)
+ {
+ throw new AMQNoRouteException("Error: " + reason, null, null);
+ }
+ else if (errorCode == AMQConstant.INVALID_ARGUMENT)
+ {
+ _logger.debug("Broker responded with Invalid Argument.");
+
+ throw new org.apache.qpid.AMQInvalidArgumentException(String.valueOf(reason), null);
+ }
+ else if (errorCode == AMQConstant.INVALID_ROUTING_KEY)
+ {
+ _logger.debug("Broker responded with Invalid Routing Key.");
+
+ throw new AMQInvalidRoutingKeyException(String.valueOf(reason), null);
+ }
+ else
+ {
+
+ throw new AMQChannelClosedException(errorCode, "Error: " + reason, null);
+ }
- throw new org.apache.qpid.AMQInvalidArgumentException(String.valueOf(reason), null);
- }
- else if (errorCode == AMQConstant.INVALID_ROUTING_KEY)
- {
- _logger.debug("Broker responded with Invalid Routing Key.");
-
- throw new AMQInvalidRoutingKeyException(String.valueOf(reason), null);
- }
- else
- {
- throw new AMQChannelClosedException(errorCode, "Error: " + reason, null);
}
-
}
- // fixme why is this only done when the close is expected...
- // should the above forced closes not also cause a close?
- // ----------
- // Closing the session only when it is expected allows the errors to be processed
- // Calling this here will prevent failover. So we should do this for all exceptions
- // that should never cause failover. Such as authentication errors.
-
- session.channelClosed(channelId, errorCode, String.valueOf(reason));
+ finally
+ {
+ // fixme why is this only done when the close is expected...
+ // should the above forced closes not also cause a close?
+ // ----------
+ // Closing the session only when it is expected allows the errors to be processed
+ // Calling this here will prevent failover. So we should do this for all exceptions
+ // that should never cause failover. Such as authentication errors.
+ // ----
+ // 2009-09-07 - ritchiem
+ // calling channelClosed will only close this session and will not
+ // prevent failover. If we don't close the session here then we will
+ // have problems during the session close as it will attempt to
+ // close the session that the broker has closed,
+
+ session.channelClosed(channelId, errorCode, String.valueOf(reason));
+ }
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl.java b/java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl.java
index 9c791730ca..909ac8aae8 100644
--- a/java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl.java
+++ b/java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl.java
@@ -39,6 +39,7 @@ public class ClientMethodDispatcherImpl implements MethodDispatcher
private static final BasicReturnMethodHandler _basicReturnMethodHandler = BasicReturnMethodHandler.getInstance();
private static final ChannelCloseMethodHandler _channelCloseMethodHandler = ChannelCloseMethodHandler.getInstance();
private static final ChannelFlowOkMethodHandler _channelFlowOkMethodHandler = ChannelFlowOkMethodHandler.getInstance();
+ private static final ChannelFlowMethodHandler _channelFlowMethodHandler = ChannelFlowMethodHandler.getInstance();
private static final ConnectionCloseMethodHandler _connectionCloseMethodHandler = ConnectionCloseMethodHandler.getInstance();
private static final ConnectionOpenOkMethodHandler _connectionOpenOkMethodHandler = ConnectionOpenOkMethodHandler.getInstance();
private static final ConnectionRedirectMethodHandler _connectionRedirectMethodHandler = ConnectionRedirectMethodHandler.getInstance();
@@ -78,6 +79,16 @@ public class ClientMethodDispatcherImpl implements MethodDispatcher
}
});
+
+ _dispatcherFactories.put(ProtocolVersion.v0_91,
+ new DispatcherFactory()
+ {
+ public ClientMethodDispatcherImpl createMethodDispatcher(AMQProtocolSession session)
+ {
+ return new ClientMethodDispatcherImpl_0_91(session);
+ }
+ });
+
}
public static ClientMethodDispatcherImpl newMethodDispatcher(ProtocolVersion version, AMQProtocolSession session)
@@ -159,7 +170,8 @@ public class ClientMethodDispatcherImpl implements MethodDispatcher
public boolean dispatchChannelFlow(ChannelFlowBody body, int channelId) throws AMQException
{
- return false;
+ _channelFlowMethodHandler.methodReceived(_session, body, channelId);
+ return true;
}
public boolean dispatchChannelFlowOk(ChannelFlowOkBody body, int channelId) throws AMQException
diff --git a/java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl_0_91.java b/java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl_0_91.java
new file mode 100644
index 0000000000..f15340ae00
--- /dev/null
+++ b/java/client/src/main/java/org/apache/qpid/client/handler/ClientMethodDispatcherImpl_0_91.java
@@ -0,0 +1,158 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.client.handler;
+
+import org.apache.qpid.framing.*;
+import org.apache.qpid.framing.amqp_0_91.MethodDispatcher_0_91;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.state.AMQMethodNotImplementedException;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+
+public class ClientMethodDispatcherImpl_0_91 extends ClientMethodDispatcherImpl implements MethodDispatcher_0_91
+{
+ public ClientMethodDispatcherImpl_0_91(AMQProtocolSession session)
+ {
+ super(session);
+ }
+
+ public boolean dispatchBasicRecoverSyncOk(BasicRecoverSyncOkBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchBasicRecoverSync(BasicRecoverSyncBody body, int channelId) throws AMQException
+ {
+ throw new AMQMethodNotImplementedException(body);
+ }
+
+ public boolean dispatchChannelOk(ChannelOkBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchChannelPing(ChannelPingBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchChannelPong(ChannelPongBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchChannelResume(ChannelResumeBody body, int channelId) throws AMQException
+ {
+ throw new AMQMethodNotImplementedException(body);
+ }
+
+ public boolean dispatchMessageAppend(MessageAppendBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageCancel(MessageCancelBody body, int channelId) throws AMQException
+ {
+ throw new AMQMethodNotImplementedException(body);
+ }
+
+ public boolean dispatchMessageCheckpoint(MessageCheckpointBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageClose(MessageCloseBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageConsume(MessageConsumeBody body, int channelId) throws AMQException
+ {
+ throw new AMQMethodNotImplementedException(body);
+ }
+
+ public boolean dispatchMessageEmpty(MessageEmptyBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageGet(MessageGetBody body, int channelId) throws AMQException
+ {
+ throw new AMQMethodNotImplementedException(body);
+ }
+
+ public boolean dispatchMessageOffset(MessageOffsetBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageOk(MessageOkBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageOpen(MessageOpenBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageQos(MessageQosBody body, int channelId) throws AMQException
+ {
+ throw new AMQMethodNotImplementedException(body);
+ }
+
+ public boolean dispatchMessageRecover(MessageRecoverBody body, int channelId) throws AMQException
+ {
+ throw new AMQMethodNotImplementedException(body);
+ }
+
+ public boolean dispatchMessageReject(MessageRejectBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageResume(MessageResumeBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchMessageTransfer(MessageTransferBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchQueueUnbind(QueueUnbindBody body, int channelId) throws AMQException
+ {
+ throw new AMQMethodNotImplementedException(body);
+ }
+
+ public boolean dispatchBasicRecoverOk(BasicRecoverOkBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+ public boolean dispatchQueueUnbindOk(QueueUnbindOkBody body, int channelId) throws AMQException
+ {
+ return false;
+ }
+
+} \ No newline at end of file
diff --git a/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionOpenOkMethodHandler.java b/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionOpenOkMethodHandler.java
index e639a33450..e40cafd72f 100644
--- a/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionOpenOkMethodHandler.java
+++ b/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionOpenOkMethodHandler.java
@@ -40,7 +40,6 @@ public class ConnectionOpenOkMethodHandler implements StateAwareMethodListener<C
}
public void methodReceived(AMQProtocolSession session, ConnectionOpenOkBody body, int channelId)
- throws AMQException
{
session.getStateManager().changeState(AMQState.CONNECTION_OPEN);
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java b/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java
index 8857f1115a..c9212a54c1 100644
--- a/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java
+++ b/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java
@@ -68,6 +68,14 @@ public class ConnectionStartMethodHandler implements StateAwareMethodListener<Co
ProtocolVersion pv = new ProtocolVersion((byte) body.getVersionMajor(), (byte) body.getVersionMinor());
+ // 0-9-1 is indistinguishable from 0-9 using only major and minor ... if we established the connection as 0-9-1
+ // and now get back major = 0 , minor = 9 then we can assume it means 0-9-1
+
+ if(pv.equals(ProtocolVersion.v0_9) && session.getProtocolVersion().equals(ProtocolVersion.v0_91))
+ {
+ pv = ProtocolVersion.v0_91;
+ }
+
// For the purposes of interop, we can make the client accept the broker's version string.
// If it does, it then internally records the version as being the latest one that it understands.
// It needs to do this since frame lookup is done by version.
diff --git a/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java b/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java
index e4e58c317d..287b5957a1 100644
--- a/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java
+++ b/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java
@@ -45,7 +45,6 @@ public class ConnectionTuneMethodHandler implements StateAwareMethodListener<Con
{ }
public void methodReceived(AMQProtocolSession session, ConnectionTuneBody frame, int channelId)
- throws AMQException
{
_logger.debug("ConnectionTune frame received");
final MethodRegistry methodRegistry = session.getMethodRegistry();
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate.java b/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate.java
index 7f43e4b4b2..314508805d 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate.java
@@ -22,7 +22,6 @@
package org.apache.qpid.client.message;
import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.framing.BasicContentHeaderProperties;
import javax.jms.Destination;
import javax.jms.JMSException;
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java b/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java
index 8b4488f1f9..1479f06632 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java
@@ -29,7 +29,6 @@ import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQPInvalidClassException;
-import org.apache.qpid.nclient.*;
import org.apache.qpid.jms.Message;
import org.apache.qpid.url.BindingURL;
import org.apache.qpid.url.AMQBindingURL;
@@ -42,12 +41,13 @@ import javax.jms.MessageNotWriteableException;
import javax.jms.MessageFormatException;
import javax.jms.DeliveryMode;
import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.net.URISyntaxException;
-import java.nio.charset.Charset;
-import org.apache.qpid.exchange.ExchangeDefaults;
-public class AMQMessageDelegate_0_10 implements AMQMessageDelegate
+/**
+ * This extends AbstractAMQMessageDelegate which contains common code between
+ * both the 0_8 and 0_10 Message types.
+ *
+ */
+public class AMQMessageDelegate_0_10 extends AbstractAMQMessageDelegate
{
private static final Map<ReplyTo, Destination> _destinationCache = Collections.synchronizedMap(new ReferenceMap());
@@ -65,27 +65,6 @@ public class AMQMessageDelegate_0_10 implements AMQMessageDelegate
private AMQSession _session;
private final long _deliveryTag;
- private static Map<AMQShortString,Integer> _exchangeTypeMap = new ConcurrentHashMap<AMQShortString, Integer>();
- private static Map<String,Integer> _exchangeTypeStringMap = new ConcurrentHashMap<String, Integer>();
- private static Map<String, Integer> _exchangeTypeToDestinationType = new ConcurrentHashMap<String, Integer>();;
-
- static
- {
- _exchangeTypeMap.put(ExchangeDefaults.DIRECT_EXCHANGE_NAME, AMQDestination.QUEUE_TYPE);
- _exchangeTypeMap.put(AMQShortString.EMPTY_STRING, AMQDestination.QUEUE_TYPE);
- _exchangeTypeMap.put(ExchangeDefaults.TOPIC_EXCHANGE_NAME, AMQDestination.TOPIC_TYPE);
- _exchangeTypeMap.put(ExchangeDefaults.FANOUT_EXCHANGE_NAME, AMQDestination.TOPIC_TYPE);
-
- _exchangeTypeStringMap.put(ExchangeDefaults.DIRECT_EXCHANGE_NAME.toString(), AMQDestination.QUEUE_TYPE);
- _exchangeTypeStringMap.put("", AMQDestination.QUEUE_TYPE);
- _exchangeTypeStringMap.put(ExchangeDefaults.TOPIC_EXCHANGE_NAME.toString(), AMQDestination.TOPIC_TYPE);
- _exchangeTypeStringMap.put(ExchangeDefaults.FANOUT_EXCHANGE_NAME.toString(), AMQDestination.TOPIC_TYPE);
-
-
- _exchangeTypeToDestinationType.put(ExchangeDefaults.DIRECT_EXCHANGE_CLASS.toString(), AMQDestination.QUEUE_TYPE);
- _exchangeTypeToDestinationType.put(ExchangeDefaults.TOPIC_EXCHANGE_NAME.toString(), AMQDestination.TOPIC_TYPE);
- _exchangeTypeToDestinationType.put(ExchangeDefaults.FANOUT_EXCHANGE_NAME.toString(), AMQDestination.TOPIC_TYPE);
- }
protected AMQMessageDelegate_0_10()
{
@@ -93,87 +72,49 @@ public class AMQMessageDelegate_0_10 implements AMQMessageDelegate
_readableProperties = false;
}
- protected AMQMessageDelegate_0_10(long deliveryTag, MessageProperties messageProps, DeliveryProperties deliveryProps, AMQShortString exchange,
- AMQShortString routingKey) throws AMQException
+ protected AMQMessageDelegate_0_10(MessageProperties messageProps, DeliveryProperties deliveryProps, long deliveryTag)
{
- this(messageProps, deliveryProps, deliveryTag);
-
-
- AMQDestination dest;
-
- dest = generateDestination(exchange, routingKey);
- setJMSDestination(dest);
- }
+ _messageProps = messageProps;
+ _deliveryProps = deliveryProps;
+ _deliveryTag = deliveryTag;
+ _readableProperties = (_messageProps != null);
- private AMQDestination generateDestination(AMQShortString exchange, AMQShortString routingKey)
- {
AMQDestination dest;
- switch(getExchangeType(exchange))
- {
- case AMQDestination.QUEUE_TYPE:
- dest = new AMQQueue(exchange, routingKey, routingKey);
- break;
- case AMQDestination.TOPIC_TYPE:
- dest = new AMQTopic(exchange, routingKey, null);
- break;
- default:
- dest = new AMQUndefinedDestination(exchange, routingKey, null);
-
- }
-
- return dest;
- }
-
- private int getExchangeType(AMQShortString exchange)
- {
- Integer type = _exchangeTypeMap.get(exchange == null ? AMQShortString.EMPTY_STRING : exchange);
-
- if(type == null)
- {
- return AMQDestination.UNKNOWN_TYPE;
- }
-
- return type;
+ dest = generateDestination(new AMQShortString(_deliveryProps.getExchange()),
+ new AMQShortString(_deliveryProps.getRoutingKey()));
+ setJMSDestination(dest);
}
-
- public static void updateExchangeTypeMapping(Header header, org.apache.qpid.nclient.Session session)
+ /**
+ * Use the 0-10 ExchangeQuery call to validate the exchange type.
+ *
+ * This is used primarily to provide the correct JMSDestination value.
+ *
+ * The query is performed synchronously iff the map exchange is not already
+ * present in the exchange Map.
+ *
+ * @param header The message headers, from which the exchange name can be extracted
+ * @param session The 0-10 session to use to call ExchangeQuery
+ */
+ public static void updateExchangeTypeMapping(Header header, org.apache.qpid.transport.Session session)
{
DeliveryProperties deliveryProps = header.get(DeliveryProperties.class);
- if(deliveryProps != null)
+ if (deliveryProps != null)
{
String exchange = deliveryProps.getExchange();
- if(exchange != null && !_exchangeTypeStringMap.containsKey(exchange))
+ if (exchange != null && !exchangeMapContains(exchange))
{
-
- AMQShortString exchangeShortString = new AMQShortString(exchange);
Future<ExchangeQueryResult> future =
- session.exchangeQuery(exchange.toString());
+ session.exchangeQuery(exchange.toString());
ExchangeQueryResult res = future.get();
- Integer type = _exchangeTypeToDestinationType.get(res.getType());
- if(type == null)
- {
- type = AMQDestination.UNKNOWN_TYPE;
- }
- _exchangeTypeStringMap.put(exchange, type);
- _exchangeTypeMap.put(exchangeShortString, type);
-
+ updateExchangeType(exchange, res.getType());
}
}
}
- protected AMQMessageDelegate_0_10(MessageProperties messageProps, DeliveryProperties deliveryProps, long deliveryTag)
- {
- _messageProps = messageProps;
- _deliveryProps = deliveryProps;
- _deliveryTag = deliveryTag;
- _readableProperties = (_messageProps != null);
-
- }
-
public String getJMSMessageID() throws JMSException
{
@@ -287,7 +228,8 @@ public class AMQMessageDelegate_0_10 implements AMQMessageDelegate
{
if (destination == null)
{
- throw new IllegalArgumentException("Null destination not allowed");
+ _messageProps.setReplyTo(null);
+ return;
}
if (!(destination instanceof AMQDestination))
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java b/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java
index 4c20a44849..5157632280 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java
@@ -46,7 +46,7 @@ import java.util.Enumeration;
import java.util.UUID;
import java.net.URISyntaxException;
-public class AMQMessageDelegate_0_8 implements AMQMessageDelegate
+public class AMQMessageDelegate_0_8 extends AbstractAMQMessageDelegate
{
private static final Map _destinationCache = Collections.synchronizedMap(new ReferenceMap());
@@ -65,6 +65,16 @@ public class AMQMessageDelegate_0_8 implements AMQMessageDelegate
private AMQSession _session;
private final long _deliveryTag;
+ // The base set of items that needs to be set.
+ private AMQMessageDelegate_0_8(BasicContentHeaderProperties properties, long deliveryTag)
+ {
+ _contentHeaderProperties = properties;
+ _deliveryTag = deliveryTag;
+ _readableProperties = (_contentHeaderProperties != null);
+ _headerAdapter = new JMSHeaderAdapter(((BasicContentHeaderProperties) _contentHeaderProperties).getHeaders());
+ }
+
+ // Used for the creation of new messages
protected AMQMessageDelegate_0_8()
{
this(new BasicContentHeaderProperties(), -1);
@@ -73,6 +83,7 @@ public class AMQMessageDelegate_0_8 implements AMQMessageDelegate
}
+ // Used when generating a received message object
protected AMQMessageDelegate_0_8(long deliveryTag, BasicContentHeaderProperties contentHeader, AMQShortString exchange,
AMQShortString routingKey)
{
@@ -80,41 +91,33 @@ public class AMQMessageDelegate_0_8 implements AMQMessageDelegate
Integer type = contentHeader.getHeaders().getInteger(CustomJMSXProperty.JMS_QPID_DESTTYPE.getShortStringName());
- if(type == null)
+ AMQDestination dest = null;
+
+ // If we have a type set the attempt to use that.
+ if (type != null)
{
- type = AMQDestination.UNKNOWN_TYPE;
+ switch (type.intValue())
+ {
+ case AMQDestination.QUEUE_TYPE:
+ dest = new AMQQueue(exchange, routingKey, routingKey);
+ break;
+ case AMQDestination.TOPIC_TYPE:
+ dest = new AMQTopic(exchange, routingKey, null);
+ break;
+ default:
+ // Use the generateDestination method
+ dest = null;
+ }
}
- AMQDestination dest;
-
- switch(type.intValue())
+ if (dest == null)
{
- case AMQDestination.QUEUE_TYPE:
- dest = new AMQQueue(exchange, routingKey, routingKey);
- break;
- case AMQDestination.TOPIC_TYPE:
- dest = new AMQTopic(exchange, routingKey, null);
- break;
- default:
- dest = new AMQUndefinedDestination(exchange, routingKey, null);
+ dest = generateDestination(exchange, routingKey);
}
-
-
- // Destination dest = AMQDestination.createDestination(url);
setJMSDestination(dest);
-
-
-
}
- protected AMQMessageDelegate_0_8(BasicContentHeaderProperties properties, long deliveryTag)
- {
- _contentHeaderProperties = properties;
- _deliveryTag = deliveryTag;
- _readableProperties = (_contentHeaderProperties != null);
- _headerAdapter = new JMSHeaderAdapter(((BasicContentHeaderProperties) _contentHeaderProperties).getHeaders());
- }
public String getJMSMessageID() throws JMSException
@@ -124,12 +127,18 @@ public class AMQMessageDelegate_0_8 implements AMQMessageDelegate
public void setJMSMessageID(String messageId) throws JMSException
{
- getContentHeaderProperties().setMessageId(messageId);
+ if (messageId != null)
+ {
+ getContentHeaderProperties().setMessageId(messageId);
+ }
}
public void setJMSMessageID(UUID messageId) throws JMSException
{
- getContentHeaderProperties().setMessageId("ID:" + messageId);
+ if (messageId != null)
+ {
+ getContentHeaderProperties().setMessageId("ID:" + messageId);
+ }
}
@@ -196,7 +205,8 @@ public class AMQMessageDelegate_0_8 implements AMQMessageDelegate
{
if (destination == null)
{
- throw new IllegalArgumentException("Null destination not allowed");
+ getContentHeaderProperties().setReplyTo((String) null);
+ return; // We're done here
}
if (!(destination instanceof AMQDestination))
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/AbstractAMQMessageDelegate.java b/java/client/src/main/java/org/apache/qpid/client/message/AbstractAMQMessageDelegate.java
new file mode 100644
index 0000000000..534fb19b76
--- /dev/null
+++ b/java/client/src/main/java/org/apache/qpid/client/message/AbstractAMQMessageDelegate.java
@@ -0,0 +1,151 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.client.message;
+
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.client.AMQUndefinedDestination;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.framing.AMQShortString;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * This abstract class provides exchange lookup functionality that is shared
+ * between all MessageDelegates. Update facilities are provided so that the 0-10
+ * code base can update the mappings. The 0-8 code base does not have the
+ * facility to update the exchange map so it can only use the default mappings.
+ *
+ * That said any updates that a 0-10 client performs will also benefit any 0-8
+ * connections in this VM.
+ *
+ */
+public abstract class AbstractAMQMessageDelegate implements AMQMessageDelegate
+{
+
+ private static Map<AMQShortString, Integer> _exchangeTypeMap = new ConcurrentHashMap<AMQShortString, Integer>();
+ private static Map<String, Integer> _exchangeTypeStringMap = new ConcurrentHashMap<String, Integer>();
+ private static Map<String, Integer> _exchangeTypeToDestinationType = new ConcurrentHashMap<String, Integer>();
+
+ /**
+ * Add default Mappings for the Direct, Default, Topic and Fanout exchanges.
+ */
+ static
+ {
+ _exchangeTypeMap.put(ExchangeDefaults.DIRECT_EXCHANGE_NAME, AMQDestination.QUEUE_TYPE);
+ _exchangeTypeMap.put(AMQShortString.EMPTY_STRING, AMQDestination.QUEUE_TYPE);
+ _exchangeTypeMap.put(ExchangeDefaults.TOPIC_EXCHANGE_NAME, AMQDestination.TOPIC_TYPE);
+ _exchangeTypeMap.put(ExchangeDefaults.FANOUT_EXCHANGE_NAME, AMQDestination.TOPIC_TYPE);
+
+ _exchangeTypeStringMap.put(ExchangeDefaults.DIRECT_EXCHANGE_NAME.toString(), AMQDestination.QUEUE_TYPE);
+ _exchangeTypeStringMap.put("", AMQDestination.QUEUE_TYPE);
+ _exchangeTypeStringMap.put(ExchangeDefaults.TOPIC_EXCHANGE_NAME.toString(), AMQDestination.TOPIC_TYPE);
+ _exchangeTypeStringMap.put(ExchangeDefaults.FANOUT_EXCHANGE_NAME.toString(), AMQDestination.TOPIC_TYPE);
+
+ _exchangeTypeToDestinationType.put(ExchangeDefaults.DIRECT_EXCHANGE_NAME.toString(), AMQDestination.QUEUE_TYPE);
+ _exchangeTypeToDestinationType.put(ExchangeDefaults.TOPIC_EXCHANGE_NAME.toString(), AMQDestination.TOPIC_TYPE);
+ _exchangeTypeToDestinationType.put(ExchangeDefaults.FANOUT_EXCHANGE_NAME.toString(), AMQDestination.TOPIC_TYPE);
+ }
+
+ /**
+ * Called when a Destination is requried.
+ *
+ * This will create the AMQDestination that is the correct type and value
+ * based on the incomming values.
+ * @param exchange The exchange name
+ * @param routingKey The routing key to be used for the Destination
+ * @return AMQDestination of the correct subtype
+ */
+ protected AMQDestination generateDestination(AMQShortString exchange, AMQShortString routingKey)
+ {
+ AMQDestination dest;
+ switch (getExchangeType(exchange))
+ {
+ case AMQDestination.QUEUE_TYPE:
+ dest = new AMQQueue(exchange, routingKey, routingKey);
+ break;
+ case AMQDestination.TOPIC_TYPE:
+ dest = new AMQTopic(exchange, routingKey, null);
+ break;
+ default:
+ dest = new AMQUndefinedDestination(exchange, routingKey, null);
+ }
+
+ return dest;
+ }
+
+ /**
+ * Update the exchange name to type mapping.
+ *
+ * If the newType is not known then an UNKNOWN_TYPE is created. Only if the
+ * exchange is of a known type: amq.direct, amq.topic, amq.fanout can we
+ * create a suitable AMQDestination representation
+ *
+ * @param exchange the name of the exchange
+ * @param newtype the AMQP exchange class name i.e. amq.direct
+ */
+ protected static void updateExchangeType(String exchange, String newtype)
+ {
+ Integer type = _exchangeTypeToDestinationType.get(newtype);
+ if (type == null)
+ {
+ type = AMQDestination.UNKNOWN_TYPE;
+ }
+ _exchangeTypeStringMap.put(exchange, type);
+ _exchangeTypeMap.put(new AMQShortString(exchange), type);
+ }
+
+ /**
+ * Accessor method to allow lookups of the given exchange name.
+ *
+ * This check allows the prevention of extra work required such as asking
+ * the broker for the exchange class name.
+ *
+ * @param exchange the exchange name to lookup
+ * @return true if there is a mapping for this exchange
+ */
+ protected static boolean exchangeMapContains(String exchange)
+ {
+ return _exchangeTypeStringMap.containsKey(exchange);
+ }
+
+ /**
+ * Returns an int representing the exchange type. This is used in the
+ * createDestination method to ensure the correct AMQDestiation is created.
+ *
+ * @param exchange the exchange name to lookup
+ * @return int representing the Exchange type
+ */
+ private int getExchangeType(AMQShortString exchange)
+ {
+ Integer type = _exchangeTypeMap.get(exchange == null ? AMQShortString.EMPTY_STRING : exchange);
+
+ if (type == null)
+ {
+ return AMQDestination.UNKNOWN_TYPE;
+ }
+
+ return type;
+ }
+
+}
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesMessage.java b/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesMessage.java
index c0d51fa726..535b55ced5 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesMessage.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesMessage.java
@@ -31,6 +31,7 @@ import org.apache.mina.common.ByteBuffer;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.transport.util.Functions;
/**
* @author Apache Software Foundation
@@ -84,53 +85,26 @@ public abstract class AbstractBytesMessage extends AbstractJMSMessage
}
public String toBodyString() throws JMSException
- {
- checkReadable();
+ {
try
{
- return getText();
+ if (_data != null)
+ {
+ return Functions.str(_data.buf(), 100,0);
+ }
+ else
+ {
+ return "";
+ }
+
}
- catch (IOException e)
+ catch (Exception e)
{
JMSException jmse = new JMSException(e.toString());
jmse.setLinkedException(e);
throw jmse;
}
- }
-
- /**
- * We reset the stream before and after reading the data. This means that toString() will always output
- * the entire message and also that the caller can then immediately start reading as if toString() had
- * never been called.
- *
- * @return
- * @throws IOException
- */
- private String getText() throws IOException
- {
- // this will use the default platform encoding
- if (_data == null)
- {
- return null;
- }
-
- int pos = _data.position();
- _data.rewind();
- // one byte left is for the end of frame marker
- if (_data.remaining() == 0)
- {
- // this is really redundant since pos must be zero
- _data.position(pos);
-
- return null;
- }
- else
- {
- String data = _data.getString(Charset.forName("UTF8").newDecoder());
- _data.position(pos);
-
- return data;
- }
+
}
/**
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessage.java b/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessage.java
index 0700ce5d23..288a4ea85c 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessage.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessage.java
@@ -367,13 +367,14 @@ public abstract class AbstractJMSMessage implements org.apache.qpid.jms.Message
try
{
StringBuffer buf = new StringBuffer("Body:\n");
+
buf.append(toBodyString());
buf.append("\nJMS Correlation ID: ").append(getJMSCorrelationID());
buf.append("\nJMS timestamp: ").append(getJMSTimestamp());
buf.append("\nJMS expiration: ").append(getJMSExpiration());
buf.append("\nJMS priority: ").append(getJMSPriority());
buf.append("\nJMS delivery mode: ").append(getJMSDeliveryMode());
- //buf.append("\nJMS reply to: ").append(String.valueOf(getJMSReplyTo()));
+ buf.append("\nJMS reply to: ").append(getReplyToString());
buf.append("\nJMS Redelivered: ").append(_redelivered);
buf.append("\nJMS Destination: ").append(getJMSDestination());
buf.append("\nJMS Type: ").append(getJMSType());
@@ -392,7 +393,7 @@ public abstract class AbstractJMSMessage implements org.apache.qpid.jms.Message
while(propertyNames.hasMoreElements())
{
String propertyName = (String) propertyNames.nextElement();
- buf.append(propertyName).append(":\t").append(getObjectProperty(propertyName));
+ buf.append("\t").append(propertyName).append(" = ").append(getObjectProperty(propertyName)).append("\n");
}
}
@@ -401,7 +402,7 @@ public abstract class AbstractJMSMessage implements org.apache.qpid.jms.Message
}
catch (JMSException e)
{
- return e.toString();
+ throw new RuntimeException(e);
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java b/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java
index 54a845ceef..e719c9a4b2 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java
@@ -27,7 +27,6 @@ import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.ContentBody;
import org.apache.qpid.framing.ContentHeaderBody;
import org.apache.qpid.framing.BasicContentHeaderProperties;
-import org.apache.qpid.transport.Struct;
import org.apache.qpid.transport.MessageProperties;
import org.apache.qpid.transport.DeliveryProperties;
@@ -109,7 +108,8 @@ public abstract class AbstractJMSMessageFactory implements MessageFactory
protected abstract AbstractJMSMessage createMessage(AMQMessageDelegate delegate, ByteBuffer data) throws AMQException;
- protected AbstractJMSMessage create010MessageWithBody(long messageNbr, Struct[] contentHeader,
+ protected AbstractJMSMessage create010MessageWithBody(long messageNbr, MessageProperties msgProps,
+ DeliveryProperties deliveryProps,
java.nio.ByteBuffer body) throws AMQException
{
ByteBuffer data;
@@ -130,11 +130,7 @@ public abstract class AbstractJMSMessageFactory implements MessageFactory
_logger.debug("Creating message from buffer with position=" + data.position() + " and remaining=" + data
.remaining());
}
- // set the properties of this message
- MessageProperties mprop = (MessageProperties) contentHeader[0];
- DeliveryProperties devprop = (DeliveryProperties) contentHeader[1];
-
- AMQMessageDelegate delegate = new AMQMessageDelegate_0_10(mprop, devprop, messageNbr);
+ AMQMessageDelegate delegate = new AMQMessageDelegate_0_10(msgProps, deliveryProps, messageNbr);
AbstractJMSMessage message = createMessage(delegate, data);
return message;
@@ -163,12 +159,12 @@ public abstract class AbstractJMSMessageFactory implements MessageFactory
return msg;
}
- public AbstractJMSMessage createMessage(long messageNbr, boolean redelivered, Struct[] contentHeader,
- java.nio.ByteBuffer body)
+ public AbstractJMSMessage createMessage(long messageNbr, boolean redelivered, MessageProperties msgProps,
+ DeliveryProperties deliveryProps, java.nio.ByteBuffer body)
throws JMSException, AMQException
{
final AbstractJMSMessage msg =
- create010MessageWithBody(messageNbr, contentHeader, body);
+ create010MessageWithBody(messageNbr,msgProps,deliveryProps, body);
msg.setJMSRedelivered(redelivered);
msg.receivedFromServer();
return msg;
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/FiledTableSupport.java b/java/client/src/main/java/org/apache/qpid/client/message/FiledTableSupport.java
index 3db628017f..5b8a4ce878 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/FiledTableSupport.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/FiledTableSupport.java
@@ -1,4 +1,25 @@
package org.apache.qpid.client.message;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import java.util.Enumeration;
import java.util.HashMap;
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessage.java b/java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessage.java
index cd9d7ccf8b..8681dae2bd 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessage.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessage.java
@@ -381,10 +381,4 @@ public class JMSBytesMessage extends AbstractBytesMessage implements BytesMessag
throw new MessageFormatException("Only primitives plus byte arrays and String are valid types");
}
}
-
- public String toString()
- {
- return String.valueOf(System.identityHashCode(this));
- }
-
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java b/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java
index 39b9597af1..56e9a5dc73 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java
@@ -25,8 +25,6 @@ import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
-import java.nio.charset.CharacterCodingException;
-import java.nio.charset.Charset;
import javax.jms.JMSException;
import javax.jms.MessageFormatException;
@@ -35,8 +33,6 @@ import javax.jms.ObjectMessage;
import org.apache.mina.common.ByteBuffer;
import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.BasicContentHeaderProperties;
public class JMSObjectMessage extends AbstractJMSMessage implements ObjectMessage
{
@@ -157,7 +153,7 @@ public class JMSObjectMessage extends AbstractJMSMessage implements ObjectMessag
}
finally
{
- _data.rewind();
+ // _data.rewind();
close(in);
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessage.java b/java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessage.java
index c290149cef..f83ae6ace0 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessage.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessage.java
@@ -100,6 +100,7 @@ public class JMSTextMessage extends AbstractJMSMessage implements javax.jms.Text
if (encoding == null || encoding.equalsIgnoreCase("UTF-8"))
{
_data = ByteBuffer.wrap(Strings.toUTF8(text));
+ setEncoding("UTF-8");
}
else
{
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.java b/java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.java
index e1275c37f7..f3d96cd855 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.java
@@ -27,7 +27,8 @@ import javax.jms.JMSException;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.ContentHeaderBody;
-import org.apache.qpid.transport.Struct;
+import org.apache.qpid.transport.DeliveryProperties;
+import org.apache.qpid.transport.MessageProperties;
public interface MessageFactory
@@ -39,7 +40,8 @@ public interface MessageFactory
throws JMSException, AMQException;
AbstractJMSMessage createMessage(long deliveryTag, boolean redelivered,
- Struct[] contentHeader,
+ MessageProperties msgProps,
+ DeliveryProperties deliveryProps,
java.nio.ByteBuffer body)
throws JMSException, AMQException;
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java b/java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java
index 948d6d0d7d..a7d41e2cde 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java
@@ -48,6 +48,7 @@ public class MessageFactoryRegistry
private final Map<String, MessageFactory> _mimeStringToFactoryMap = new HashMap<String, MessageFactory>();
private final Map<AMQShortString, MessageFactory> _mimeShortStringToFactoryMap =
new HashMap<AMQShortString, MessageFactory>();
+ private final MessageFactory _default = new JMSBytesMessageFactory();
/**
* Construct a new registry with the default message factories registered
@@ -63,7 +64,7 @@ public class MessageFactoryRegistry
mf.registerFactory(JMSBytesMessage.MIME_TYPE, new JMSBytesMessageFactory());
mf.registerFactory(JMSObjectMessage.MIME_TYPE, new JMSObjectMessageFactory());
mf.registerFactory(JMSStreamMessage.MIME_TYPE, new JMSStreamMessageFactory());
- mf.registerFactory(null, new JMSBytesMessageFactory());
+ mf.registerFactory(null, mf._default);
return mf;
}
@@ -113,39 +114,43 @@ public class MessageFactoryRegistry
MessageFactory mf = _mimeShortStringToFactoryMap.get(contentTypeShortString);
if (mf == null)
{
- throw new AMQException(null, "Unsupport MIME type of " + properties.getContentTypeAsString(), null);
- }
- else
- {
- return mf.createMessage(deliveryTag, redelivered, contentHeader, exchange, routingKey, bodies);
+ mf = _default;
}
+
+ return mf.createMessage(deliveryTag, redelivered, contentHeader, exchange, routingKey, bodies);
}
public AbstractJMSMessage createMessage(MessageTransfer transfer) throws AMQException, JMSException
{
MessageProperties mprop = transfer.getHeader().get(MessageProperties.class);
- String messageType = mprop.getContentType();
- if (messageType == null)
+ String messageType = "";
+ if ( mprop == null || mprop.getContentType() == null)
{
_logger.debug("no message type specified, building a byte message");
messageType = JMSBytesMessage.MIME_TYPE;
}
+ else
+ {
+ messageType = mprop.getContentType();
+ }
MessageFactory mf = _mimeStringToFactoryMap.get(messageType);
if (mf == null)
{
- throw new AMQException(null, "Unsupport MIME type of " + messageType, null);
+ mf = _default;
}
- else
+
+ boolean redelivered = false;
+ DeliveryProperties deliverProps;
+ if((deliverProps = transfer.getHeader().get(DeliveryProperties.class)) != null)
{
- boolean redelivered = false;
- DeliveryProperties deliverProps;
- if((deliverProps = transfer.getHeader().get(DeliveryProperties.class)) != null)
- {
- redelivered = deliverProps.getRedelivered();
- }
- return mf.createMessage(transfer.getId(), redelivered, transfer.getHeader().getStructs(), transfer.getBody());
+ redelivered = deliverProps.getRedelivered();
}
+ return mf.createMessage(transfer.getId(),
+ redelivered,
+ mprop == null? new MessageProperties():mprop,
+ deliverProps == null? new DeliveryProperties():deliverProps,
+ transfer.getBody());
}
@@ -159,11 +164,9 @@ public class MessageFactoryRegistry
MessageFactory mf = _mimeStringToFactoryMap.get(mimeType);
if (mf == null)
{
- throw new AMQException(null, "Unsupport MIME type of " + mimeType, null);
- }
- else
- {
- return mf.createMessage(delegateFactory);
+ mf = _default;
}
+
+ return mf.createMessage(delegateFactory);
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/ReturnMessage.java b/java/client/src/main/java/org/apache/qpid/client/message/ReturnMessage.java
index ed590772d9..6e5f33a65c 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/ReturnMessage.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/ReturnMessage.java
@@ -1,4 +1,25 @@
package org.apache.qpid.client.message;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import org.apache.qpid.framing.AMQShortString;
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage.java b/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage.java
index 713c87260c..e2cb36a030 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage.java
@@ -20,6 +20,7 @@
*/
package org.apache.qpid.client.message;
+import org.apache.qpid.client.AMQSession;
import org.apache.qpid.client.BasicMessageConsumer;
@@ -30,7 +31,7 @@ import org.apache.qpid.client.BasicMessageConsumer;
* Note that the actual work of creating a JMS message for the client code's use is done outside of the MINA dispatcher
* thread in order to minimise the amount of work done in the MINA dispatcher thread.
*/
-public abstract class UnprocessedMessage
+public abstract class UnprocessedMessage implements AMQSession.Dispatchable
{
private final int _consumerTag;
@@ -49,5 +50,9 @@ public abstract class UnprocessedMessage
return _consumerTag;
}
+ public void dispatch(AMQSession ssn)
+ {
+ ssn.dispatch(this);
+ }
} \ No newline at end of file
diff --git a/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage_0_10.java b/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage_0_10.java
index 6b1301a33f..f31bc88509 100644
--- a/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage_0_10.java
+++ b/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage_0_10.java
@@ -33,9 +33,9 @@ public class UnprocessedMessage_0_10 extends UnprocessedMessage
{
private MessageTransfer _transfer;
- public UnprocessedMessage_0_10(int consumerTag, MessageTransfer xfr)
+ public UnprocessedMessage_0_10(MessageTransfer xfr)
{
- super(consumerTag);
+ super(Integer.parseInt(xfr.getDestination()));
_transfer = xfr;
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/protocol/AMQIoTransportProtocolSession.java b/java/client/src/main/java/org/apache/qpid/client/protocol/AMQIoTransportProtocolSession.java
deleted file mode 100644
index 1de0e7bdfc..0000000000
--- a/java/client/src/main/java/org/apache/qpid/client/protocol/AMQIoTransportProtocolSession.java
+++ /dev/null
@@ -1,125 +0,0 @@
-package org.apache.qpid.client.protocol;
-
-import java.util.UUID;
-
-import javax.security.sasl.SaslClient;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.mina.common.IdleStatus;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.ConnectionTuneParameters;
-import org.apache.qpid.client.handler.ClientMethodDispatcherImpl;
-import org.apache.qpid.client.state.AMQState;
-import org.apache.qpid.framing.AMQDataBlock;
-import org.apache.qpid.framing.AMQMethodBody;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.ProtocolInitiation;
-import org.apache.qpid.framing.ProtocolVersion;
-import org.apache.qpid.transport.Sender;
-
-public class AMQIoTransportProtocolSession extends AMQProtocolSession
-{
-
- protected Sender<java.nio.ByteBuffer> _ioSender;
- private SaslClient _saslClient;
- private ConnectionTuneParameters _connectionTuneParameters;
-
- public AMQIoTransportProtocolSession(AMQProtocolHandler protocolHandler, AMQConnection connection)
- {
- super(protocolHandler, connection);
- }
-
- @Override
- public void closeProtocolSession(boolean waitLast) throws AMQException
- {
- _ioSender.close();
- _protocolHandler.getStateManager().changeState(AMQState.CONNECTION_CLOSED);
- }
-
- @Override
- public void init()
- {
- _ioSender.send(new ProtocolInitiation(_connection.getProtocolVersion()).toNioByteBuffer());
- _ioSender.flush();
- }
-
- @Override
- protected AMQShortString generateQueueName()
- {
- int id;
- synchronized (_queueIdLock)
- {
- id = _queueId++;
- }
- return new AMQShortString("tmp_" + UUID.randomUUID() + "_" + id);
- }
-
- @Override
- public AMQConnection getAMQConnection()
- {
- return _connection;
- }
-
- @Override
- public SaslClient getSaslClient()
- {
- return _saslClient;
- }
-
- @Override
- public void setSaslClient(SaslClient client)
- {
- _saslClient = client;
- }
-
- /** @param delay delay in seconds (not ms) */
- @Override
- void initHeartbeats(int delay)
- {
- if (delay > 0)
- {
- // FIXME: actually do something here
- HeartbeatDiagnostics.init(delay, HeartbeatConfig.CONFIG.getTimeout(delay));
- }
- }
-
- @Override
- public void methodFrameReceived(final int channel, final AMQMethodBody amqMethodBody) throws AMQException
- {
- // FIXME?
- _protocolHandler.methodBodyReceived(channel, amqMethodBody, null);
- }
-
- @Override
- public void writeFrame(AMQDataBlock frame, boolean wait)
- {
- _ioSender.send(frame.toNioByteBuffer());
- if (wait)
- {
- _ioSender.flush();
- }
- }
-
- @Override
- public void setSender(Sender<java.nio.ByteBuffer> sender)
- {
- _ioSender = sender;
- }
-
- @Override
- public ConnectionTuneParameters getConnectionTuneParameters()
- {
- return _connectionTuneParameters;
- }
-
- @Override
- public void setConnectionTuneParameters(ConnectionTuneParameters params)
- {
- _connectionTuneParameters = params;
- AMQConnection con = getAMQConnection();
- con.setMaximumChannelCount(params.getChannelMax());
- con.setMaximumFrameSize(params.getFrameMax());
- initHeartbeats((int) params.getHeartbeat());
- }
-}
diff --git a/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java b/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java
index e92817f713..a567c2c215 100644
--- a/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java
+++ b/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java
@@ -20,24 +20,23 @@
*/
package org.apache.qpid.client.protocol;
-import org.apache.mina.common.IdleStatus;
-import org.apache.mina.common.IoFilterChain;
-import org.apache.mina.common.IoHandlerAdapter;
-import org.apache.mina.common.IoSession;
-import org.apache.mina.filter.ReadThrottleFilterBuilder;
-import org.apache.mina.filter.SSLFilter;
-import org.apache.mina.filter.WriteBufferLimitFilterBuilder;
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
import org.apache.mina.filter.codec.ProtocolCodecException;
-import org.apache.mina.filter.codec.ProtocolCodecFilter;
-import org.apache.mina.filter.executor.ExecutorFilter;
import org.apache.qpid.AMQConnectionClosedException;
import org.apache.qpid.AMQDisconnectedException;
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQTimeoutException;
import org.apache.qpid.client.AMQConnection;
import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.client.SSLConfiguration;
-import org.apache.qpid.client.configuration.ClientProperties;
import org.apache.qpid.client.failover.FailoverException;
import org.apache.qpid.client.failover.FailoverHandler;
import org.apache.qpid.client.failover.FailoverState;
@@ -46,23 +45,29 @@ import org.apache.qpid.client.state.AMQStateManager;
import org.apache.qpid.client.state.StateWaiter;
import org.apache.qpid.client.state.listener.SpecificMethodFrameListener;
import org.apache.qpid.codec.AMQCodecFactory;
-import org.apache.qpid.framing.*;
+import org.apache.qpid.framing.AMQBody;
+import org.apache.qpid.framing.AMQDataBlock;
+import org.apache.qpid.framing.AMQFrame;
+import org.apache.qpid.framing.AMQMethodBody;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ConnectionCloseBody;
+import org.apache.qpid.framing.ConnectionCloseOkBody;
+import org.apache.qpid.framing.HeartbeatBody;
+import org.apache.qpid.framing.MethodRegistry;
+import org.apache.qpid.framing.ProtocolInitiation;
+import org.apache.qpid.framing.ProtocolVersion;
import org.apache.qpid.jms.BrokerDetails;
-import org.apache.qpid.pool.ReadWriteThreadModel;
+import org.apache.qpid.pool.Job;
+import org.apache.qpid.pool.ReferenceCountingExecutorService;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.protocol.AMQMethodEvent;
import org.apache.qpid.protocol.AMQMethodListener;
-import org.apache.qpid.ssl.SSLContextFactory;
+import org.apache.qpid.protocol.ProtocolEngine;
+import org.apache.qpid.transport.NetworkDriver;
import org.apache.qpid.transport.network.io.IoTransport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-import java.util.Iterator;
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.CountDownLatch;
-
/**
* AMQProtocolHandler is the client side protocol handler for AMQP, it handles all protocol events received from the
* network by MINA. The primary purpose of AMQProtocolHandler is to translate the generic event model of MINA into the
@@ -102,17 +107,10 @@ import java.util.concurrent.CountDownLatch;
*
* <p/><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Create the filter chain to filter this handlers events.
- * <td> {@link ProtocolCodecFilter}, {@link SSLContextFactory}, {@link SSLFilter}, {@link ReadWriteThreadModel}.
- *
* <tr><td> Maintain fail-over state.
* <tr><td>
* </table>
*
- * @todo Explain the system property: amqj.shared_read_write_pool. How does putting the protocol codec filter before the
- * async write filter make it a shared pool? The pooling filter uses the same thread pool for reading and writing
- * anyway, see {@link org.apache.qpid.pool.PoolingFilter}, docs for comments. Will putting the protocol codec
- * filter before it mean not doing the read/write asynchronously but in the main filter thread?
* @todo Use a single handler instance, by shifting everything to do with the 'protocol session' state, including
* failover state, into AMQProtocolSession, and tracking that from AMQConnection? The lifecycles of
* AMQProtocolSesssion and AMQConnection will be the same, so if there is high cohesion between them, they could
@@ -120,13 +118,15 @@ import java.util.concurrent.CountDownLatch;
* held per protocol handler, per protocol session, per network connection, per channel, in seperate classes, so
* that lifecycles of the fields match lifecycles of their containing objects.
*/
-public class AMQProtocolHandler extends IoHandlerAdapter
+public class AMQProtocolHandler implements ProtocolEngine
{
/** Used for debugging. */
private static final Logger _logger = LoggerFactory.getLogger(AMQProtocolHandler.class);
private static final Logger _protocolLogger = LoggerFactory.getLogger("qpid.protocol");
private static final boolean PROTOCOL_DEBUG = (System.getProperty("amqj.protocol.logging.level") != null);
+ private static final long MAXIMUM_STATE_WAIT_TIME = Long.parseLong(System.getProperty("amqj.MaximumStateWait", "30000"));
+
/**
* The connection that this protocol handler is associated with. There is a 1-1 mapping between connection
* instances and protocol handler instances.
@@ -137,7 +137,7 @@ public class AMQProtocolHandler extends IoHandlerAdapter
private volatile AMQProtocolSession _protocolSession;
/** Holds the state of the protocol session. */
- private AMQStateManager _stateManager = new AMQStateManager();
+ private AMQStateManager _stateManager;
/** Holds the method listeners, */
private final CopyOnWriteArraySet<AMQMethodListener> _frameListeners = new CopyOnWriteArraySet<AMQMethodListener>();
@@ -162,7 +162,19 @@ public class AMQProtocolHandler extends IoHandlerAdapter
private FailoverException _lastFailoverException;
/** Defines the default timeout to use for synchronous protocol commands. */
- private final long DEFAULT_SYNC_TIMEOUT = 1000 * 30;
+ private final long DEFAULT_SYNC_TIMEOUT = Long.getLong("amqj.default_syncwrite_timeout", 1000 * 30);
+
+ /** Object to lock on when changing the latch */
+ private Object _failoverLatchChange = new Object();
+ private AMQCodecFactory _codecFactory;
+ private Job _readJob;
+ private Job _writeJob;
+ private ReferenceCountingExecutorService _poolReference = ReferenceCountingExecutorService.getInstance();
+ private NetworkDriver _networkDriver;
+ private ProtocolVersion _suggestedProtocolVersion;
+
+ private long _writtenBytes;
+ private long _readBytes;
/**
* Creates a new protocol handler, associated with the specified client connection instance.
@@ -172,101 +184,30 @@ public class AMQProtocolHandler extends IoHandlerAdapter
public AMQProtocolHandler(AMQConnection con)
{
_connection = con;
- }
-
- /**
- * Invoked by MINA when a MINA session for a new connection is created. This method sets up the filter chain on the
- * session, which filters the events handled by this handler. The filter chain consists of, handing off events
- * to an asynchronous thread pool, optionally encoding/decoding ssl, encoding/decoding AMQP.
- *
- * @param session The MINA session.
- *
- * @throws Exception Any underlying exceptions are allowed to fall through to MINA.
- */
- public void sessionCreated(IoSession session) throws Exception
- {
- _logger.debug("Protocol session created for session " + System.identityHashCode(session));
- _failoverHandler = new FailoverHandler(this, session);
-
- final ProtocolCodecFilter pcf = new ProtocolCodecFilter(new AMQCodecFactory(false));
-
- if (Boolean.getBoolean("amqj.shared_read_write_pool"))
- {
- session.getFilterChain().addBefore("AsynchronousWriteFilter", "protocolFilter", pcf);
- }
- else
- {
- session.getFilterChain().addLast("protocolFilter", pcf);
- }
- // we only add the SSL filter where we have an SSL connection
- if (_connection.getSSLConfiguration() != null)
- {
- SSLConfiguration sslConfig = _connection.getSSLConfiguration();
- SSLContextFactory sslFactory =
- new SSLContextFactory(sslConfig.getKeystorePath(), sslConfig.getKeystorePassword(), sslConfig.getCertType());
- SSLFilter sslFilter = new SSLFilter(sslFactory.buildClientContext());
- sslFilter.setUseClientMode(true);
- session.getFilterChain().addBefore("protocolFilter", "ssl", sslFilter);
- }
-
- try
- {
- ReadWriteThreadModel threadModel = ReadWriteThreadModel.getInstance();
- threadModel.getAsynchronousReadFilter().createNewJobForSession(session);
- threadModel.getAsynchronousWriteFilter().createNewJobForSession(session);
- }
- catch (RuntimeException e)
- {
- _logger.error(e.getMessage(), e);
- }
-
- if (Boolean.getBoolean(ClientProperties.PROTECTIO_PROP_NAME))
- {
- try
- {
- //Add IO Protection Filters
- IoFilterChain chain = session.getFilterChain();
-
- session.getFilterChain().addLast("tempExecutorFilterForFilterBuilder", new ExecutorFilter());
-
- ReadThrottleFilterBuilder readfilter = new ReadThrottleFilterBuilder();
- readfilter.setMaximumConnectionBufferSize(Integer.parseInt(System.getProperty(
- ClientProperties.READ_BUFFER_LIMIT_PROP_NAME, ClientProperties.READ_BUFFER_LIMIT_DEFAULT)));
- readfilter.attach(chain);
-
- WriteBufferLimitFilterBuilder writefilter = new WriteBufferLimitFilterBuilder();
- writefilter.setMaximumConnectionBufferSize(Integer.parseInt(System.getProperty(
- ClientProperties.WRITE_BUFFER_LIMIT_PROP_NAME, ClientProperties.WRITE_BUFFER_LIMIT_DEFAULT)));
- writefilter.attach(chain);
- session.getFilterChain().remove("tempExecutorFilterForFilterBuilder");
-
- _logger.info("Using IO Read/Write Filter Protection");
- }
- catch (Exception e)
- {
- _logger.error("Unable to attach IO Read/Write Filter Protection :" + e.getMessage());
- }
- }
- _protocolSession = new AMQProtocolSession(this, session, _connection);
-
- _stateManager.setProtocolSession(_protocolSession);
-
- _protocolSession.init();
+ _protocolSession = new AMQProtocolSession(this, _connection);
+ _stateManager = new AMQStateManager(_protocolSession);
+ _codecFactory = new AMQCodecFactory(false, _protocolSession);
+ _readJob = new Job(_poolReference, Job.MAX_JOB_EVENTS, true);
+ _writeJob = new Job(_poolReference, Job.MAX_JOB_EVENTS, false);
+ _poolReference.acquireExecutorService();
+ _failoverHandler = new FailoverHandler(this);
}
/**
* Called when we want to create a new IoTransport session
- * @param brokerDetail
+ * @param brokerDetail
*/
public void createIoTransportSession(BrokerDetails brokerDetail)
{
_protocolSession = new AMQProtocolSession(this, _connection);
_stateManager.setProtocolSession(_protocolSession);
IoTransport.connect_0_9(getProtocolSession(),
- brokerDetail.getHost(), brokerDetail.getPort());
+ brokerDetail.getHost(),
+ brokerDetail.getPort(),
+ brokerDetail.useSSL());
_protocolSession.init();
}
-
+
/**
* Called when the network connection is closed. This can happen, either because the client explicitly requested
* that the connection be closed, in which case nothing is done, or because the connection died. In the case
@@ -274,16 +215,10 @@ public class AMQProtocolHandler extends IoHandlerAdapter
* process will be started, provided that it is the clients policy to allow failover, and provided that a failover
* has not already been started or failed.
*
- * <p/>It is important to note that when the connection dies this method may be called or {@link #exceptionCaught}
- * may be called first followed by this method. This depends on whether the client was trying to send data at the
- * time of the failure.
- *
- * @param session The MINA session.
- *
* @todo Clarify: presumably exceptionCaught is called when the client is sending during a connection failure and
* not otherwise? The above comment doesn't make that clear.
*/
- public void sessionClosed(IoSession session)
+ public void closed()
{
if (_connection.isClosed())
{
@@ -322,7 +257,8 @@ public class AMQProtocolHandler extends IoHandlerAdapter
{
_logger.debug("sessionClose() not allowed to failover");
_connection.exceptionReceived(new AMQDisconnectedException(
- "Server closed connection and reconnection " + "not permitted.", null));
+ "Server closed connection and reconnection " + "not permitted.",
+ _stateManager.getLastException()));
}
else
{
@@ -337,41 +273,37 @@ public class AMQProtocolHandler extends IoHandlerAdapter
/** See {@link FailoverHandler} to see rationale for separate thread. */
private void startFailoverThread()
{
- Thread failoverThread = new Thread(_failoverHandler);
- failoverThread.setName("Failover");
- // Do not inherit daemon-ness from current thread as this can be a daemon
- // thread such as a AnonymousIoService thread.
- failoverThread.setDaemon(false);
- failoverThread.start();
+ if(!_connection.isClosed())
+ {
+ Thread failoverThread = new Thread(_failoverHandler);
+ failoverThread.setName("Failover");
+ // Do not inherit daemon-ness from current thread as this can be a daemon
+ // thread such as a AnonymousIoService thread.
+ failoverThread.setDaemon(false);
+ failoverThread.start();
+ }
}
- public void sessionIdle(IoSession session, IdleStatus status) throws Exception
+ public void readerIdle()
{
- _logger.debug("Protocol Session [" + this + ":" + session + "] idle: " + status);
- if (IdleStatus.WRITER_IDLE.equals(status))
- {
- // write heartbeat frame:
- _logger.debug("Sent heartbeat");
- session.write(HeartbeatBody.FRAME);
- HeartbeatDiagnostics.sent();
- }
- else if (IdleStatus.READER_IDLE.equals(status))
- {
- // failover:
- HeartbeatDiagnostics.timeout();
- _logger.warn("Timed out while waiting for heartbeat from peer.");
- session.close();
- }
+ _logger.debug("Protocol Session [" + this + "] idle: reader");
+ // failover:
+ HeartbeatDiagnostics.timeout();
+ _logger.warn("Timed out while waiting for heartbeat from peer.");
+ _networkDriver.close();
+ }
+
+ public void writerIdle()
+ {
+ _logger.debug("Protocol Session [" + this + "] idle: reader");
+ writeFrame(HeartbeatBody.FRAME);
+ HeartbeatDiagnostics.sent();
}
/**
- * Invoked when any exception is thrown by a user IoHandler implementation or by MINA. If the cause is an
- * IOException, MINA will close the connection automatically.
- *
- * @param session The MINA session.
- * @param cause The exception that triggered this event.
+ * Invoked when any exception is thrown by the NetworkDriver
*/
- public void exceptionCaught(IoSession session, Throwable cause)
+ public void exception(Throwable cause)
{
if (_failoverState == FailoverState.NOT_STARTED)
{
@@ -379,9 +311,9 @@ public class AMQProtocolHandler extends IoHandlerAdapter
if ((cause instanceof AMQConnectionClosedException) || cause instanceof IOException)
{
_logger.info("Exception caught therefore going to attempt failover: " + cause, cause);
- // this will attemp failover
-
- sessionClosed(session);
+ // this will attempt failover
+ _networkDriver.close();
+ closed();
}
else
{
@@ -428,12 +360,12 @@ public class AMQProtocolHandler extends IoHandlerAdapter
* @param e the exception to propagate
*
* @see #propagateExceptionToFrameListeners
- * @see #propagateExceptionToStateWaiters
*/
public void propagateExceptionToAllWaiters(Exception e)
{
+ getStateManager().error(e);
+
propagateExceptionToFrameListeners(e);
- propagateExceptionToStateWaiters(e);
}
/**
@@ -450,33 +382,20 @@ public class AMQProtocolHandler extends IoHandlerAdapter
*/
public void propagateExceptionToFrameListeners(Exception e)
{
- if (!_frameListeners.isEmpty())
+ synchronized (_frameListeners)
{
- final Iterator it = _frameListeners.iterator();
- while (it.hasNext())
+ if (!_frameListeners.isEmpty())
{
- final AMQMethodListener ml = (AMQMethodListener) it.next();
- ml.error(e);
+ final Iterator it = _frameListeners.iterator();
+ while (it.hasNext())
+ {
+ final AMQMethodListener ml = (AMQMethodListener) it.next();
+ ml.error(e);
+ }
}
}
}
- /**
- * This caters for the case where we only need to propogate an exception to the the state manager to interupt any
- * thing waiting for a state change.
- *
- * Currently (2008-07-15) the state manager is only used during 0-8/0-9 Connection establishement.
- *
- * Normally the state manager would not need to be notified without notifiying the frame listeners so in normal
- * cases {@link #propagateExceptionToAllWaiters} would be the correct choice.
- *
- * @param e the exception to propagate
- */
- public void propagateExceptionToStateWaiters(Exception e)
- {
- getStateManager().error(e);
- }
-
public void notifyFailoverStarting()
{
// Set the last exception in the sync block to ensure the ordering with add.
@@ -499,48 +418,81 @@ public class AMQProtocolHandler extends IoHandlerAdapter
private static int _messageReceivedCount;
- public void messageReceived(IoSession session, Object message) throws Exception
- {
- if (PROTOCOL_DEBUG)
- {
- _protocolLogger.info(String.format("RECV: [%s] %s", this, message));
- }
- if(message instanceof AMQFrame)
+ public void received(ByteBuffer msg)
+ {
+ try
{
- final boolean debug = _logger.isDebugEnabled();
- final long msgNumber = ++_messageReceivedCount;
+ _readBytes += msg.remaining();
+ final ArrayList<AMQDataBlock> dataBlocks = _codecFactory.getDecoder().decodeBuffer(msg);
- if (debug && ((msgNumber % 1000) == 0))
+ Job.fireAsynchEvent(_poolReference.getPool(), _readJob, new Runnable()
{
- _logger.debug("Received " + _messageReceivedCount + " protocol messages");
- }
-
- AMQFrame frame = (AMQFrame) message;
-
- final AMQBody bodyFrame = frame.getBodyFrame();
- HeartbeatDiagnostics.received(bodyFrame instanceof HeartbeatBody);
-
- bodyFrame.handle(frame.getChannel(), _protocolSession);
-
- _connection.bytesReceived(_protocolSession.getIoSession().getReadBytes());
+ public void run()
+ {
+ // Decode buffer
+
+ for (AMQDataBlock message : dataBlocks)
+ {
+
+ try
+ {
+ if (PROTOCOL_DEBUG)
+ {
+ _protocolLogger.info(String.format("RECV: [%s] %s", this, message));
+ }
+
+ if(message instanceof AMQFrame)
+ {
+ final boolean debug = _logger.isDebugEnabled();
+ final long msgNumber = ++_messageReceivedCount;
+
+ if (debug && ((msgNumber % 1000) == 0))
+ {
+ _logger.debug("Received " + _messageReceivedCount + " protocol messages");
+ }
+
+ AMQFrame frame = (AMQFrame) message;
+
+ final AMQBody bodyFrame = frame.getBodyFrame();
+
+ HeartbeatDiagnostics.received(bodyFrame instanceof HeartbeatBody);
+
+ bodyFrame.handle(frame.getChannel(), _protocolSession);
+
+ _connection.bytesReceived(_readBytes);
+ }
+ else if (message instanceof ProtocolInitiation)
+ {
+ // We get here if the server sends a response to our initial protocol header
+ // suggesting an alternate ProtocolVersion; the server will then close the
+ // connection.
+ ProtocolInitiation protocolInit = (ProtocolInitiation) message;
+ _suggestedProtocolVersion = protocolInit.checkVersion();
+
+ // get round a bug in old versions of qpid whereby the connection is not closed
+ _stateManager.changeState(AMQState.CONNECTION_CLOSED);
+ }
+ }
+ catch (Exception e)
+ {
+ _logger.error("Exception processing frame", e);
+ propagateExceptionToFrameListeners(e);
+ exception(e);
+ }
+ }
+ }
+ });
}
- else if (message instanceof ProtocolInitiation)
+ catch (Exception e)
{
- // We get here if the server sends a response to our initial protocol header
- // suggesting an alternate ProtocolVersion; the server will then close the
- // connection.
- ProtocolInitiation protocolInit = (ProtocolInitiation) message;
- ProtocolVersion pv = protocolInit.checkVersion();
- getConnection().setProtocolVersion(pv);
-
- // get round a bug in old versions of qpid whereby the connection is not closed
- _stateManager.changeState(AMQState.CONNECTION_CLOSED);
+ propagateExceptionToFrameListeners(e);
+ exception(e);
}
}
- public void methodBodyReceived(final int channelId, final AMQBody bodyFrame, IoSession session)//, final IoSession session)
+ public void methodBodyReceived(final int channelId, final AMQBody bodyFrame)
throws AMQException
{
@@ -556,18 +508,20 @@ public class AMQProtocolHandler extends IoHandlerAdapter
{
boolean wasAnyoneInterested = getStateManager().methodReceived(evt);
- if (!_frameListeners.isEmpty())
+ synchronized (_frameListeners)
{
- //This iterator is safe from the error state as the frame listeners always add before they send so their
- // will be ready and waiting for this response.
- Iterator it = _frameListeners.iterator();
- while (it.hasNext())
+ if (!_frameListeners.isEmpty())
{
- final AMQMethodListener listener = (AMQMethodListener) it.next();
- wasAnyoneInterested = listener.methodReceived(evt) || wasAnyoneInterested;
+ //This iterator is safe from the error state as the frame listeners always add before they send so their
+ // will be ready and waiting for this response.
+ Iterator it = _frameListeners.iterator();
+ while (it.hasNext())
+ {
+ final AMQMethodListener listener = (AMQMethodListener) it.next();
+ wasAnyoneInterested = listener.methodReceived(evt) || wasAnyoneInterested;
+ }
}
}
-
if (!wasAnyoneInterested)
{
throw new AMQException(null, "AMQMethodEvent " + evt + " was not processed by any listener. Listeners:"
@@ -578,32 +532,13 @@ public class AMQProtocolHandler extends IoHandlerAdapter
{
propagateExceptionToFrameListeners(e);
- exceptionCaught(session, e);
+ exception(e);
}
}
private static int _messagesOut;
- public void messageSent(IoSession session, Object message) throws Exception
- {
- if (PROTOCOL_DEBUG)
- {
- _protocolLogger.debug(String.format("SEND: [%s] %s", this, message));
- }
-
- final long sentMessages = _messagesOut++;
-
- final boolean debug = _logger.isDebugEnabled();
-
- if (debug && ((sentMessages % 1000) == 0))
- {
- _logger.debug("Sent " + _messagesOut + " protocol messages");
- }
-
- _connection.bytesSent(session.getWrittenBytes());
- }
-
public StateWaiter createWaiter(Set<AMQState> states) throws AMQException
{
return getStateManager().createWaiter(states);
@@ -617,12 +552,40 @@ public class AMQProtocolHandler extends IoHandlerAdapter
*/
public void writeFrame(AMQDataBlock frame)
{
- _protocolSession.writeFrame(frame);
+ writeFrame(frame, false);
}
public void writeFrame(AMQDataBlock frame, boolean wait)
{
- _protocolSession.writeFrame(frame, wait);
+ final ByteBuffer buf = frame.toNioByteBuffer();
+ _writtenBytes += buf.remaining();
+ Job.fireAsynchEvent(_poolReference.getPool(), _writeJob, new Runnable()
+ {
+ public void run()
+ {
+ _networkDriver.send(buf);
+ }
+ });
+ if (PROTOCOL_DEBUG)
+ {
+ _protocolLogger.debug(String.format("SEND: [%s] %s", this, frame));
+ }
+
+ final long sentMessages = _messagesOut++;
+
+ final boolean debug = _logger.isDebugEnabled();
+
+ if (debug && ((sentMessages % 1000) == 0))
+ {
+ _logger.debug("Sent " + _messagesOut + " protocol messages");
+ }
+
+ _connection.bytesSent(_writtenBytes);
+
+ if (wait)
+ {
+ _networkDriver.flush();
+ }
}
/**
@@ -657,9 +620,30 @@ public class AMQProtocolHandler extends IoHandlerAdapter
throw _lastFailoverException;
}
+ if(_stateManager.getCurrentState() == AMQState.CONNECTION_CLOSED ||
+ _stateManager.getCurrentState() == AMQState.CONNECTION_CLOSING)
+ {
+ Exception e = _stateManager.getLastException();
+ if (e != null)
+ {
+ if (e instanceof AMQException)
+ {
+ AMQException amqe = (AMQException) e;
+
+ throw amqe.cloneForCurrentThread();
+ }
+ else
+ {
+ throw new AMQException(AMQConstant.INTERNAL_ERROR, e.getMessage(), e);
+ }
+ }
+ }
+
_frameListeners.add(listener);
+ //FIXME: At this point here we should check or before add we should check _stateManager is in an open
+ // state so as we don't check we are likely just to time out here as I believe is being seen in QPID-1255
}
- _protocolSession.writeFrame(frame);
+ writeFrame(frame);
return listener.blockForFrame(timeout);
// When control resumes before this line, a reply will have been received
@@ -703,38 +687,42 @@ public class AMQProtocolHandler extends IoHandlerAdapter
*/
public void closeConnection(long timeout) throws AMQException
{
- getStateManager().changeState(AMQState.CONNECTION_CLOSING);
-
ConnectionCloseBody body = _protocolSession.getMethodRegistry().createConnectionCloseBody(AMQConstant.REPLY_SUCCESS.getCode(), // replyCode
new AMQShortString("JMS client is closing the connection."), 0, 0);
final AMQFrame frame = body.generateFrame(0);
- try
- {
- syncWrite(frame, ConnectionCloseOkBody.class, timeout);
- _protocolSession.closeProtocolSession();
- }
- catch (AMQTimeoutException e)
- {
- _protocolSession.closeProtocolSession(false);
- }
- catch (FailoverException e)
+ //If the connection is already closed then don't do a syncWrite
+ if (!getStateManager().getCurrentState().equals(AMQState.CONNECTION_CLOSED))
{
- _logger.debug("FailoverException interrupted connection close, ignoring as connection close anyway.");
+ try
+ {
+ syncWrite(frame, ConnectionCloseOkBody.class, timeout);
+ _networkDriver.close();
+ closed();
+ }
+ catch (AMQTimeoutException e)
+ {
+ closed();
+ }
+ catch (FailoverException e)
+ {
+ _logger.debug("FailoverException interrupted connection close, ignoring as connection close anyway.");
+ }
}
+ _poolReference.releaseExecutorService();
}
/** @return the number of bytes read from this protocol session */
public long getReadBytes()
{
- return _protocolSession.getIoSession().getReadBytes();
+ return _readBytes;
}
/** @return the number of bytes written to this protocol session */
public long getWrittenBytes()
{
- return _protocolSession.getIoSession().getWrittenBytes();
+ return _writtenBytes;
}
public void failover(String host, int port)
@@ -747,9 +735,15 @@ public class AMQProtocolHandler extends IoHandlerAdapter
public void blockUntilNotFailingOver() throws InterruptedException
{
- if (_failoverLatch != null)
+ synchronized(_failoverLatchChange)
{
- _failoverLatch.await();
+ if (_failoverLatch != null)
+ {
+ if(!_failoverLatch.await(MAXIMUM_STATE_WAIT_TIME, TimeUnit.MILLISECONDS))
+ {
+
+ }
+ }
}
}
@@ -765,7 +759,10 @@ public class AMQProtocolHandler extends IoHandlerAdapter
public void setFailoverLatch(CountDownLatch failoverLatch)
{
- _failoverLatch = failoverLatch;
+ synchronized (_failoverLatchChange)
+ {
+ _failoverLatch = failoverLatch;
+ }
}
public AMQConnection getConnection()
@@ -781,6 +778,7 @@ public class AMQProtocolHandler extends IoHandlerAdapter
public void setStateManager(AMQStateManager stateManager)
{
_stateManager = stateManager;
+ _stateManager.setProtocolSession(_protocolSession);
}
public AMQProtocolSession getProtocolSession()
@@ -817,4 +815,41 @@ public class AMQProtocolHandler extends IoHandlerAdapter
{
return _protocolSession.getProtocolVersion();
}
+
+ public SocketAddress getRemoteAddress()
+ {
+ return _networkDriver.getRemoteAddress();
+ }
+
+ public SocketAddress getLocalAddress()
+ {
+ return _networkDriver.getLocalAddress();
+ }
+
+ public void setNetworkDriver(NetworkDriver driver)
+ {
+ _networkDriver = driver;
+ }
+
+ /** @param delay delay in seconds (not ms) */
+ void initHeartbeats(int delay)
+ {
+ if (delay > 0)
+ {
+ getNetworkDriver().setMaxWriteIdle(delay);
+ getNetworkDriver().setMaxReadIdle(HeartbeatConfig.CONFIG.getTimeout(delay));
+ HeartbeatDiagnostics.init(delay, HeartbeatConfig.CONFIG.getTimeout(delay));
+ }
+ }
+
+ public NetworkDriver getNetworkDriver()
+ {
+ return _networkDriver;
+ }
+
+ public ProtocolVersion getSuggestedProtocolVersion()
+ {
+ return _suggestedProtocolVersion;
+ }
+
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java b/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java
index 5e12a5e6f8..2d59146b43 100644
--- a/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java
+++ b/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java
@@ -20,11 +20,6 @@
*/
package org.apache.qpid.client.protocol;
-import org.apache.commons.lang.StringUtils;
-import org.apache.mina.common.CloseFuture;
-import org.apache.mina.common.IdleStatus;
-import org.apache.mina.common.IoSession;
-import org.apache.mina.common.WriteFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -33,6 +28,7 @@ import javax.security.sasl.SaslClient;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import org.apache.commons.lang.StringUtils;
import org.apache.qpid.AMQException;
import org.apache.qpid.client.AMQConnection;
import org.apache.qpid.client.AMQSession;
@@ -65,10 +61,6 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
protected static final String SASL_CLIENT = "SASLClient";
- protected final IoSession _minaProtocolSession;
-
- protected WriteFuture _lastWriteFuture;
-
/**
* The handler from which this session was created and which is used to handle protocol events. We send failover
* events to the handler.
@@ -102,28 +94,15 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
protected final AMQConnection _connection;
- private static final int FAST_CHANNEL_ACCESS_MASK = 0xFFFFFFF0;
+ private ConnectionTuneParameters _connectionTuneParameters;
- public AMQProtocolSession(AMQProtocolHandler protocolHandler, IoSession protocolSession, AMQConnection connection)
- {
- _protocolHandler = protocolHandler;
- _minaProtocolSession = protocolSession;
- _minaProtocolSession.setAttachment(this);
- // properties of the connection are made available to the event handlers
- _minaProtocolSession.setAttribute(AMQ_CONNECTION, connection);
- // fixme - real value needed
- _minaProtocolSession.setWriteTimeout(LAST_WRITE_FUTURE_JOIN_TIMEOUT);
- _protocolVersion = connection.getProtocolVersion();
- _methodDispatcher = ClientMethodDispatcherImpl.newMethodDispatcher(ProtocolVersion.getLatestSupportedVersion(),
- this);
- _connection = connection;
+ private SaslClient _saslClient;
- }
+ private static final int FAST_CHANNEL_ACCESS_MASK = 0xFFFFFFF0;
public AMQProtocolSession(AMQProtocolHandler protocolHandler, AMQConnection connection)
{
_protocolHandler = protocolHandler;
- _minaProtocolSession = null;
_protocolVersion = connection.getProtocolVersion();
_methodDispatcher = ClientMethodDispatcherImpl.newMethodDispatcher(ProtocolVersion.getLatestSupportedVersion(),
this);
@@ -134,7 +113,7 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
{
// start the process of setting up the connection. This is the first place that
// data is written to the server.
- _minaProtocolSession.write(new ProtocolInitiation(_connection.getProtocolVersion()));
+ _protocolHandler.writeFrame(new ProtocolInitiation(_connection.getProtocolVersion()));
}
public String getClientID()
@@ -175,14 +154,9 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
return getAMQConnection().getPassword();
}
- public IoSession getIoSession()
- {
- return _minaProtocolSession;
- }
-
public SaslClient getSaslClient()
{
- return (SaslClient) _minaProtocolSession.getAttribute(SASL_CLIENT);
+ return _saslClient;
}
/**
@@ -192,28 +166,21 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
*/
public void setSaslClient(SaslClient client)
{
- if (client == null)
- {
- _minaProtocolSession.removeAttribute(SASL_CLIENT);
- }
- else
- {
- _minaProtocolSession.setAttribute(SASL_CLIENT, client);
- }
+ _saslClient = client;
}
public ConnectionTuneParameters getConnectionTuneParameters()
{
- return (ConnectionTuneParameters) _minaProtocolSession.getAttribute(CONNECTION_TUNE_PARAMETERS);
+ return _connectionTuneParameters;
}
public void setConnectionTuneParameters(ConnectionTuneParameters params)
{
- _minaProtocolSession.setAttribute(CONNECTION_TUNE_PARAMETERS, params);
+ _connectionTuneParameters = params;
AMQConnection con = getAMQConnection();
con.setMaximumChannelCount(params.getChannelMax());
con.setMaximumFrameSize(params.getFrameMax());
- initHeartbeats((int) params.getHeartbeat());
+ _protocolHandler.initHeartbeats((int) params.getHeartbeat());
}
/**
@@ -225,7 +192,7 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
* @throws AMQException if this was not expected
*/
public void unprocessedMessageReceived(final int channelId, UnprocessedMessage message) throws AMQException
- {
+ {
if ((channelId & FAST_CHANNEL_ACCESS_MASK) == 0)
{
_channelId2UnprocessedMsgArray[channelId] = message;
@@ -335,21 +302,12 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
*/
public void writeFrame(AMQDataBlock frame)
{
- writeFrame(frame, false);
+ _protocolHandler.writeFrame(frame);
}
public void writeFrame(AMQDataBlock frame, boolean wait)
{
- WriteFuture f = _minaProtocolSession.write(frame);
- if (wait)
- {
- // fixme -- time out?
- f.join();
- }
- else
- {
- _lastWriteFuture = f;
- }
+ _protocolHandler.writeFrame(frame, wait);
}
/**
@@ -407,33 +365,12 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
public AMQConnection getAMQConnection()
{
- return (AMQConnection) _minaProtocolSession.getAttribute(AMQ_CONNECTION);
+ return _connection;
}
public void closeProtocolSession() throws AMQException
{
- closeProtocolSession(true);
- }
-
- public void closeProtocolSession(boolean waitLast) throws AMQException
- {
- _logger.debug("Waiting for last write to join.");
- if (waitLast && (_lastWriteFuture != null))
- {
- _lastWriteFuture.join(LAST_WRITE_FUTURE_JOIN_TIMEOUT);
- }
-
- _logger.debug("Closing protocol session");
-
- final CloseFuture future = _minaProtocolSession.close();
-
- // There is no recovery we can do if the join on the close failes so simply mark the connection CLOSED
- // then wait for the connection to close.
- // ritchiem: Could this release BlockingWaiters to early? The close has been done as much as possible so any
- // error now shouldn't matter.
-
- _protocolHandler.getStateManager().changeState(AMQState.CONNECTION_CLOSED);
- future.join(LAST_WRITE_FUTURE_JOIN_TIMEOUT);
+ _protocolHandler.closeConnection(0);
}
public void failover(String host, int port)
@@ -449,22 +386,11 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
id = _queueId++;
}
// get rid of / and : and ; from address for spec conformance
- String localAddress = StringUtils.replaceChars(_minaProtocolSession.getLocalAddress().toString(), "/;:", "");
+ String localAddress = StringUtils.replaceChars(_protocolHandler.getLocalAddress().toString(), "/;:", "");
return new AMQShortString("tmp_" + localAddress + "_" + id);
}
- /** @param delay delay in seconds (not ms) */
- void initHeartbeats(int delay)
- {
- if (delay > 0)
- {
- _minaProtocolSession.setIdleTime(IdleStatus.WRITER_IDLE, delay);
- _minaProtocolSession.setIdleTime(IdleStatus.READER_IDLE, HeartbeatConfig.CONFIG.getTimeout(delay));
- HeartbeatDiagnostics.init(delay, HeartbeatConfig.CONFIG.getTimeout(delay));
- }
- }
-
public void confirmConsumerCancelled(int channelId, AMQShortString consumerTag)
{
final AMQSession session = getSession(channelId);
@@ -477,9 +403,7 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
_protocolVersion = pv;
_methodRegistry = MethodRegistry.getMethodRegistry(pv);
_methodDispatcher = ClientMethodDispatcherImpl.newMethodDispatcher(pv, this);
-
- // _registry = MainRegistry.getVersionSpecificRegistry(versionMajor, versionMinor);
- }
+ }
public byte getProtocolMinorVersion()
{
@@ -496,11 +420,6 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
return _protocolVersion;
}
-// public VersionSpecificRegistry getRegistry()
-// {
-// return _registry;
-// }
-
public MethodRegistry getMethodRegistry()
{
return _methodRegistry;
@@ -530,7 +449,7 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
public void methodFrameReceived(final int channel, final AMQMethodBody amqMethodBody) throws AMQException
{
- _protocolHandler.methodBodyReceived(channel, amqMethodBody, _minaProtocolSession);
+ _protocolHandler.methodBodyReceived(channel, amqMethodBody);
}
public void notifyError(Exception error)
@@ -542,4 +461,11 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession
{
// No-op, interface munging
}
+
+
+ @Override
+ public String toString()
+ {
+ return "AMQProtocolSession[" + _connection + ']';
+ }
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties b/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties
index 89ee8337f8..1fcfde3579 100644
--- a/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties
+++ b/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties
@@ -18,4 +18,5 @@
#
CallbackHandler.CRAM-MD5-HASHED=org.apache.qpid.client.security.UsernameHashedPasswordCallbackHandler
CallbackHandler.CRAM-MD5=org.apache.qpid.client.security.UsernamePasswordCallbackHandler
+CallbackHandler.AMQPLAIN=org.apache.qpid.client.security.UsernamePasswordCallbackHandler
CallbackHandler.PLAIN=org.apache.qpid.client.security.UsernamePasswordCallbackHandler
diff --git a/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java b/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java
index 803b34b7fa..2b4261b4b7 100644
--- a/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java
+++ b/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java
@@ -85,8 +85,19 @@ public class DynamicSaslRegistrar
if (factories.size() > 0)
{
- Security.insertProviderAt(new JCAProvider(factories), 0);
- _logger.debug("Dynamic SASL provider added as a security provider");
+ // Ensure we are used before the defaults
+ if (Security.insertProviderAt(new JCAProvider(factories), 1) == -1)
+ {
+ _logger.error("Unable to load custom SASL providers.");
+ }
+ else
+ {
+ _logger.info("Additional SASL providers successfully registered.");
+ }
+ }
+ else
+ {
+ _logger.warn("No additional SASL providers registered.");
}
}
catch (IOException e)
@@ -185,6 +196,7 @@ public class DynamicSaslRegistrar
continue;
}
+ _logger.debug("Registering class "+ clazz.getName() +" for mechanism "+mechanism);
factoriesToRegister.put(mechanism, (Class<? extends SaslClientFactory>) clazz);
}
catch (Exception ex)
diff --git a/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java b/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java
index 5a2c5ac5c1..828d26ed0d 100644
--- a/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java
+++ b/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java
@@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory;
import javax.security.sasl.SaslClientFactory;
import java.security.Provider;
+import java.security.Security;
import java.util.Map;
/**
@@ -49,10 +50,10 @@ public class JCAProvider extends Provider
*/
public JCAProvider(Map<String, Class<? extends SaslClientFactory>> providerMap)
{
- super("AMQSASLProvider", 1.0, "A JCA provider that registers all "
+ super("AMQSASLProvider-Client", 1.0, "A JCA provider that registers all "
+ "AMQ SASL providers that want to be registered");
register(providerMap);
- // Security.addProvider(this);
+// Security.addProvider(this);
}
/**
@@ -64,7 +65,7 @@ public class JCAProvider extends Provider
{
for (Map.Entry<String, Class<? extends SaslClientFactory>> me : providerMap.entrySet())
{
- put("SaslClientFactory." + me.getKey(), me.getValue().getName());
+ put( "SaslClientFactory."+me.getKey(), me.getValue().getName());
log.debug("Registered SASL Client factory for " + me.getKey() + " as " + me.getValue().getName());
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java b/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java
index f8645139f2..9c7d62670c 100644
--- a/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java
+++ b/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java
@@ -31,6 +31,7 @@ import org.slf4j.LoggerFactory;
import java.util.Set;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.io.IOException;
/**
* The state manager is responsible for managing the state of the protocol session. <p/>
@@ -86,7 +87,7 @@ public class AMQStateManager implements AMQMethodListener
return _currentState;
}
- public void changeState(AMQState newState) throws AMQException
+ public void changeState(AMQState newState)
{
_logger.debug("State changing to " + newState + " from old state " + _currentState);
@@ -136,6 +137,22 @@ public class AMQStateManager implements AMQMethodListener
*/
public void error(Exception error)
{
+ if (error instanceof AMQException)
+ {
+ // AMQException should be being notified before closing the
+ // ProtocolSession. Which will change the State to CLOSED.
+ // if we have a hard error.
+ if (((AMQException)error).isHardError())
+ {
+ changeState(AMQState.CONNECTION_CLOSING);
+ }
+ }
+ else
+ {
+ // Be on the safe side here and mark the connection closed
+ changeState(AMQState.CONNECTION_CLOSED);
+ }
+
if (_waiters.size() == 0)
{
_logger.error("No Waiters for error saving as last error:" + error.getMessage());
@@ -196,4 +213,9 @@ public class AMQStateManager implements AMQMethodListener
{
return _lastException;
}
+
+ public void clearLastException()
+ {
+ _lastException = null;
+ }
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/state/StateWaiter.java b/java/client/src/main/java/org/apache/qpid/client/state/StateWaiter.java
index 4695b195d5..79f438d35d 100644
--- a/java/client/src/main/java/org/apache/qpid/client/state/StateWaiter.java
+++ b/java/client/src/main/java/org/apache/qpid/client/state/StateWaiter.java
@@ -113,7 +113,6 @@ public class StateWaiter extends BlockingWaiter<AMQState>
{
_logger.error("Failover occured whilst waiting for states:" + _awaitStates);
- e.printStackTrace();
return null;
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/transport/SocketTransportConnection.java b/java/client/src/main/java/org/apache/qpid/client/transport/SocketTransportConnection.java
index b2f7ae8395..1ac8f62e32 100644
--- a/java/client/src/main/java/org/apache/qpid/client/transport/SocketTransportConnection.java
+++ b/java/client/src/main/java/org/apache/qpid/client/transport/SocketTransportConnection.java
@@ -20,27 +20,20 @@
*/
package org.apache.qpid.client.transport;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
import org.apache.mina.common.ByteBuffer;
-import org.apache.mina.common.ConnectFuture;
import org.apache.mina.common.IoConnector;
import org.apache.mina.common.SimpleByteBufferAllocator;
-import org.apache.mina.transport.socket.nio.ExistingSocketConnector;
-import org.apache.mina.transport.socket.nio.SocketConnectorConfig;
-import org.apache.mina.transport.socket.nio.SocketSessionConfig;
-
+import org.apache.qpid.client.SSLConfiguration;
import org.apache.qpid.client.protocol.AMQProtocolHandler;
import org.apache.qpid.jms.BrokerDetails;
-import org.apache.qpid.pool.ReadWriteThreadModel;
-
+import org.apache.qpid.ssl.SSLContextFactory;
+import org.apache.qpid.transport.network.mina.MINANetworkDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
public class SocketTransportConnection implements ITransportConnection
{
private static final Logger _logger = LoggerFactory.getLogger(SocketTransportConnection.class);
@@ -71,61 +64,27 @@ public class SocketTransportConnection implements ITransportConnection
}
final IoConnector ioConnector = _socketConnectorFactory.newSocketConnector();
- SocketConnectorConfig cfg = (SocketConnectorConfig) ioConnector.getDefaultConfig();
-
- // if we do not use our own thread model we get the MINA default which is to use
- // its own leader-follower model
- boolean readWriteThreading = Boolean.getBoolean("amqj.shared_read_write_pool");
- if (readWriteThreading)
- {
- cfg.setThreadModel(ReadWriteThreadModel.getInstance());
- }
-
- SocketSessionConfig scfg = (SocketSessionConfig) cfg.getSessionConfig();
- scfg.setTcpNoDelay("true".equalsIgnoreCase(System.getProperty("amqj.tcpNoDelay", "true")));
- scfg.setSendBufferSize(Integer.getInteger("amqj.sendBufferSize", DEFAULT_BUFFER_SIZE));
- _logger.info("send-buffer-size = " + scfg.getSendBufferSize());
- scfg.setReceiveBufferSize(Integer.getInteger("amqj.receiveBufferSize", DEFAULT_BUFFER_SIZE));
- _logger.info("recv-buffer-size = " + scfg.getReceiveBufferSize());
-
final InetSocketAddress address;
if (brokerDetail.getTransport().equals(BrokerDetails.SOCKET))
{
address = null;
-
- Socket socket = TransportConnection.removeOpenSocket(brokerDetail.getHost());
-
- if (socket != null)
- {
- _logger.info("Using existing Socket:" + socket);
-
- ((ExistingSocketConnector) ioConnector).setOpenSocket(socket);
- }
- else
- {
- throw new IllegalArgumentException("Active Socket must be provided for broker " +
- "with 'socket://<SocketID>' transport:" + brokerDetail);
- }
}
else
{
address = new InetSocketAddress(brokerDetail.getHost(), brokerDetail.getPort());
_logger.info("Attempting connection to " + address);
}
-
-
- ConnectFuture future = ioConnector.connect(address, protocolHandler);
-
- // wait for connection to complete
- if (future.join(brokerDetail.getTimeout()))
- {
- // we call getSession which throws an IOException if there has been an error connecting
- future.getSession();
- }
- else
+
+ SSLConfiguration sslConfig = protocolHandler.getConnection().getSSLConfiguration();
+ SSLContextFactory sslFactory = null;
+ if (sslConfig != null)
{
- throw new IOException("Timeout waiting for connection.");
+ sslFactory = new SSLContextFactory(sslConfig.getKeystorePath(), sslConfig.getKeystorePassword(), sslConfig.getCertType());
}
+
+ MINANetworkDriver driver = new MINANetworkDriver(ioConnector);
+ driver.open(brokerDetail.getPort(), address.getAddress(), protocolHandler, null, sslFactory);
+ protocolHandler.setNetworkDriver(driver);
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/transport/TransportConnection.java b/java/client/src/main/java/org/apache/qpid/client/transport/TransportConnection.java
index 6c12821c74..a4f8bb0166 100644
--- a/java/client/src/main/java/org/apache/qpid/client/transport/TransportConnection.java
+++ b/java/client/src/main/java/org/apache/qpid/client/transport/TransportConnection.java
@@ -20,6 +20,12 @@
*/
package org.apache.qpid.client.transport;
+import java.io.IOException;
+import java.net.Socket;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
import org.apache.mina.common.IoConnector;
import org.apache.mina.common.IoHandlerAdapter;
import org.apache.mina.common.IoServiceConfig;
@@ -30,16 +36,12 @@ import org.apache.mina.transport.vmpipe.VmPipeAcceptor;
import org.apache.mina.transport.vmpipe.VmPipeAddress;
import org.apache.qpid.client.vmbroker.AMQVMBrokerCreationException;
import org.apache.qpid.jms.BrokerDetails;
-import org.apache.qpid.pool.ReadWriteThreadModel;
+import org.apache.qpid.protocol.ProtocolEngineFactory;
+import org.apache.qpid.thread.QpidThreadExecutor;
+import org.apache.qpid.transport.network.mina.MINANetworkDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.net.Socket;
-
/**
* The TransportConnection is a helper class responsible for connecting to an AMQ server. It sets up the underlying
* connector, which currently always uses TCP/IP sockets. It creates the "protocol handler" which deals with MINA
@@ -61,7 +63,7 @@ public class TransportConnection
private static Logger _logger = LoggerFactory.getLogger(TransportConnection.class);
- private static final String DEFAULT_QPID_SERVER = "org.apache.qpid.server.protocol.AMQPFastProtocolHandler";
+ private static final String DEFAULT_QPID_SERVER = "org.apache.qpid.server.protocol.AMQProtocolEngineFactory";
private static Map<String, Socket> _openSocketRegister = new ConcurrentHashMap<String, Socket>();
@@ -75,7 +77,7 @@ public class TransportConnection
return _openSocketRegister.remove(socketID);
}
- public static synchronized ITransportConnection getInstance(BrokerDetails details) throws AMQTransportConnectionException
+ public static synchronized ITransportConnection getInstance(final BrokerDetails details) throws AMQTransportConnectionException
{
int transport = getTransport(details.getTransport());
@@ -91,7 +93,22 @@ public class TransportConnection
{
public IoConnector newSocketConnector()
{
- return new ExistingSocketConnector();
+ ExistingSocketConnector connector = new ExistingSocketConnector(1,new QpidThreadExecutor());
+
+ Socket socket = TransportConnection.removeOpenSocket(details.getHost());
+
+ if (socket != null)
+ {
+ _logger.info("Using existing Socket:" + socket);
+
+ ((ExistingSocketConnector) connector).setOpenSocket(socket);
+ }
+ else
+ {
+ throw new IllegalArgumentException("Active Socket must be provided for broker " +
+ "with 'socket://<SocketID>' transport:" + details);
+ }
+ return connector;
}
});
case TCP:
@@ -106,12 +123,12 @@ public class TransportConnection
_logger.warn("Using Qpid MultiThreaded NIO - " + (System.getProperties().containsKey("qpidnio")
? "Qpid NIO is new default"
: "Sysproperty 'qpidnio' is set"));
- result = new MultiThreadSocketConnector();
+ result = new MultiThreadSocketConnector(1, new QpidThreadExecutor());
}
else
{
_logger.info("Using Mina NIO");
- result = new SocketConnector(); // non-blocking connector
+ result = new SocketConnector(1, new QpidThreadExecutor()); // non-blocking connector
}
// Don't have the connector's worker thread wait around for other connections (we only use
// one SocketConnector per connection at the moment anyway). This allows short-running
@@ -189,8 +206,6 @@ public class TransportConnection
_acceptor = new VmPipeAcceptor();
IoServiceConfig config = _acceptor.getDefaultConfig();
-
- config.setThreadModel(ReadWriteThreadModel.getInstance());
}
synchronized (_inVmPipeAddress)
{
@@ -275,7 +290,10 @@ public class TransportConnection
{
Class[] cnstr = {Integer.class};
Object[] params = {port};
- provider = (IoHandlerAdapter) Class.forName(protocolProviderClass).getConstructor(cnstr).newInstance(params);
+
+ provider = new MINANetworkDriver();
+ ProtocolEngineFactory engineFactory = (ProtocolEngineFactory) Class.forName(protocolProviderClass).getConstructor(cnstr).newInstance(params);
+ ((MINANetworkDriver) provider).setProtocolEngineFactory(engineFactory, true);
// Give the broker a second to create
_logger.info("Created VMBroker Instance:" + port);
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/transport/VmPipeTransportConnection.java b/java/client/src/main/java/org/apache/qpid/client/transport/VmPipeTransportConnection.java
index dca6efba67..504d475740 100644
--- a/java/client/src/main/java/org/apache/qpid/client/transport/VmPipeTransportConnection.java
+++ b/java/client/src/main/java/org/apache/qpid/client/transport/VmPipeTransportConnection.java
@@ -20,25 +20,26 @@
*/
package org.apache.qpid.client.transport;
+import java.io.IOException;
+
import org.apache.mina.common.ConnectFuture;
-import org.apache.mina.common.IoServiceConfig;
import org.apache.mina.transport.vmpipe.QpidVmPipeConnector;
import org.apache.mina.transport.vmpipe.VmPipeAddress;
import org.apache.mina.transport.vmpipe.VmPipeConnector;
import org.apache.qpid.client.protocol.AMQProtocolHandler;
import org.apache.qpid.jms.BrokerDetails;
-import org.apache.qpid.pool.ReadWriteThreadModel;
+import org.apache.qpid.transport.network.mina.MINANetworkDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-
public class VmPipeTransportConnection implements ITransportConnection
{
private static final Logger _logger = LoggerFactory.getLogger(VmPipeTransportConnection.class);
private static int _port;
+ private MINANetworkDriver _networkDriver;
+
public VmPipeTransportConnection(int port)
{
_port = port;
@@ -47,16 +48,16 @@ public class VmPipeTransportConnection implements ITransportConnection
public void connect(AMQProtocolHandler protocolHandler, BrokerDetails brokerDetail) throws IOException
{
final VmPipeConnector ioConnector = new QpidVmPipeConnector();
- final IoServiceConfig cfg = ioConnector.getDefaultConfig();
-
- cfg.setThreadModel(ReadWriteThreadModel.getInstance());
final VmPipeAddress address = new VmPipeAddress(_port);
_logger.info("Attempting connection to " + address);
- ConnectFuture future = ioConnector.connect(address, protocolHandler);
+ _networkDriver = new MINANetworkDriver(ioConnector, protocolHandler);
+ protocolHandler.setNetworkDriver(_networkDriver);
+ ConnectFuture future = ioConnector.connect(address, _networkDriver);
// wait for connection to complete
future.join();
// we call getSession which throws an IOException if there has been an error connecting
future.getSession();
+ _networkDriver.setProtocolEngine(protocolHandler);
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/url/URLParser.java b/java/client/src/main/java/org/apache/qpid/client/url/URLParser.java
index b975713ad7..f3f74dd332 100644
--- a/java/client/src/main/java/org/apache/qpid/client/url/URLParser.java
+++ b/java/client/src/main/java/org/apache/qpid/client/url/URLParser.java
@@ -1,4 +1,25 @@
package org.apache.qpid.client.url;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import java.net.URI;
import java.net.URISyntaxException;
@@ -37,22 +58,31 @@ public class URLParser
if ((connection.getHost() == null) || connection.getHost().equals(""))
{
- String uid = AMQConnectionFactory.getUniqueClientID();
- if (uid == null)
- {
- throw URLHelper.parseError(-1, "Client Name not specified", fullURL);
+ String tmp = connection.getAuthority();
+ // hack to read a clientid such as "my_clientID"
+ if (tmp != null && tmp.indexOf('@') < tmp.length()-1)
+ {
+ _url.setClientName(tmp.substring(tmp.indexOf('@')+1,tmp.length()));
}
else
{
- _url.setClientName(uid);
+ String uid = AMQConnectionFactory.getUniqueClientID();
+ if (uid == null)
+ {
+ throw URLHelper.parseError(-1, "Client Name not specified", fullURL);
+ }
+ else
+ {
+ _url.setClientName(uid);
+ }
}
- }
+ }
else
{
_url.setClientName(connection.getHost());
}
-
+
String userInfo = connection.getUserInfo();
if (userInfo == null)
diff --git a/java/client/src/main/java/org/apache/qpid/client/util/BlockingWaiter.java b/java/client/src/main/java/org/apache/qpid/client/util/BlockingWaiter.java
index 67cda957fb..a3d015eadc 100644
--- a/java/client/src/main/java/org/apache/qpid/client/util/BlockingWaiter.java
+++ b/java/client/src/main/java/org/apache/qpid/client/util/BlockingWaiter.java
@@ -253,7 +253,7 @@ public abstract class BlockingWaiter<T>
}
else
{
- System.err.println("WARNING: new error arrived while old one not yet processed");
+ System.err.println("WARNING: new error '" + e == null ? "null" : e.getMessage() + "' arrived while old one not yet processed:" + _error.getMessage());
}
try
diff --git a/java/client/src/main/java/org/apache/qpid/client/util/FlowControllingBlockingQueue.java b/java/client/src/main/java/org/apache/qpid/client/util/FlowControllingBlockingQueue.java
index bddbc329ab..ee7fc533a3 100644
--- a/java/client/src/main/java/org/apache/qpid/client/util/FlowControllingBlockingQueue.java
+++ b/java/client/src/main/java/org/apache/qpid/client/util/FlowControllingBlockingQueue.java
@@ -22,10 +22,11 @@ package org.apache.qpid.client.util;
import java.util.Iterator;
import java.util.Queue;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
/**
* A blocking queue that emits events above a user specified threshold allowing the caller to take action (e.g. flow
* control) to try to prevent the queue growing (much) further. The underlying queue itself is not bounded therefore the
@@ -36,6 +37,8 @@ import java.util.concurrent.ConcurrentLinkedQueue;
*/
public class FlowControllingBlockingQueue
{
+ private static final Logger _logger = LoggerFactory.getLogger(FlowControllingBlockingQueue.class);
+
/** This queue is bounded and is used to store messages before being dispatched to the consumer */
private final Queue _queue = new ConcurrentLinkedQueue();
@@ -46,6 +49,8 @@ public class FlowControllingBlockingQueue
/** We require a separate count so we can track whether we have reached the threshold */
private int _count;
+
+ private boolean disableFlowControl;
public boolean isEmpty()
{
@@ -69,6 +74,10 @@ public class FlowControllingBlockingQueue
_flowControlHighThreshold = highThreshold;
_flowControlLowThreshold = lowThreshold;
_listener = listener;
+ if (highThreshold == 0)
+ {
+ disableFlowControl = true;
+ }
}
public Object take() throws InterruptedException
@@ -84,7 +93,7 @@ public class FlowControllingBlockingQueue
}
}
}
- if (_listener != null)
+ if (!disableFlowControl && _listener != null)
{
synchronized (_listener)
{
@@ -93,6 +102,7 @@ public class FlowControllingBlockingQueue
_listener.underThreshold(_count);
}
}
+
}
return o;
@@ -106,7 +116,7 @@ public class FlowControllingBlockingQueue
notifyAll();
}
- if (_listener != null)
+ if (!disableFlowControl && _listener != null)
{
synchronized (_listener)
{
diff --git a/java/client/src/main/java/org/apache/qpid/filter/PropertyExpression.java b/java/client/src/main/java/org/apache/qpid/filter/PropertyExpression.java
index 2c05f5ce0f..09152f7f1b 100644
--- a/java/client/src/main/java/org/apache/qpid/filter/PropertyExpression.java
+++ b/java/client/src/main/java/org/apache/qpid/filter/PropertyExpression.java
@@ -204,6 +204,24 @@ public class PropertyExpression implements Expression
}
}
});
+
+ JMS_PROPERTY_EXPRESSIONS.put("JMSMessageID", new Expression()
+ {
+ public Object evaluate(AbstractJMSMessage message)
+ {
+ try
+ {
+ return message.getJMSMessageID();
+ }
+ catch (Exception e)
+ {
+ _logger.warn("Error evaluating property",e);
+
+ return null;
+ }
+
+ }
+ });
}
diff --git a/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java b/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java
index 0316255b2c..7227ab247c 100644
--- a/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java
+++ b/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java
@@ -34,6 +34,8 @@ public interface BrokerDetails
public static final String OPTIONS_RETRY = "retries";
public static final String OPTIONS_CONNECT_TIMEOUT = "connecttimeout";
public static final String OPTIONS_CONNECT_DELAY = "connectdelay";
+ public static final String OPTIONS_IDLE_TIMEOUT = "idle_timeout";
+ public static final String OPTIONS_SASL_MECHS = "sasl_mechs";
public static final int DEFAULT_PORT = 5672;
public static final String SOCKET = "socket";
@@ -55,7 +57,7 @@ public interface BrokerDetails
public static final String VIRTUAL_HOST = "virtualhost";
public static final String CLIENT_ID = "client_id";
public static final String USERNAME = "username";
- public static final String PASSWORD = "password";
+ public static final String PASSWORD = "password";
String getHost();
@@ -94,6 +96,8 @@ public interface BrokerDetails
SSLConfiguration getSSLConfiguration();
void setSSLConfiguration(SSLConfiguration sslConfiguration);
+
+ boolean useSSL();
String toString();
diff --git a/java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java b/java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java
index da8cd4f750..03ab967c36 100644
--- a/java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java
+++ b/java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java
@@ -33,9 +33,11 @@ import java.util.List;
*/
public interface ConnectionURL
{
- public static final String AMQ_SYNC_PERSISTENCE = "sync_persistence";
- public static final String AMQ_MAXPREFETCH = "maxprefetch";
public static final String AMQ_PROTOCOL = "amqp";
+ public static final String OPTIONS_SYNC_PERSISTENCE = "sync_persistence";
+ public static final String OPTIONS_MAXPREFETCH = "maxprefetch";
+ public static final String OPTIONS_SYNC_ACK = "sync_ack";
+ public static final String OPTIONS_SYNC_PUBLISH = "sync_publish";
public static final String OPTIONS_BROKERLIST = "brokerlist";
public static final String OPTIONS_FAILOVER = "failover";
public static final String OPTIONS_FAILOVER_CYCLE = "cyclecount";
diff --git a/java/client/src/main/java/org/apache/qpid/jms/FailoverPolicy.java b/java/client/src/main/java/org/apache/qpid/jms/FailoverPolicy.java
index 8e3ccc3b02..7cdcd32306 100644
--- a/java/client/src/main/java/org/apache/qpid/jms/FailoverPolicy.java
+++ b/java/client/src/main/java/org/apache/qpid/jms/FailoverPolicy.java
@@ -20,9 +20,12 @@
*/
package org.apache.qpid.jms;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.jms.failover.FailoverExchangeMethod;
import org.apache.qpid.jms.failover.FailoverMethod;
import org.apache.qpid.jms.failover.FailoverRoundRobinServers;
import org.apache.qpid.jms.failover.FailoverSingleServer;
+import org.apache.qpid.jms.failover.NoFailover;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -48,7 +51,7 @@ public class FailoverPolicy
private long _lastMethodTime;
private long _lastFailTime;
- public FailoverPolicy(ConnectionURL connectionDetails)
+ public FailoverPolicy(ConnectionURL connectionDetails, AMQConnection conn)
{
FailoverMethod method;
@@ -88,6 +91,14 @@ public class FailoverPolicy
{
method = new FailoverRoundRobinServers(connectionDetails);
}
+ else if (failoverMethod.equals(FailoverMethod.FAILOVER_EXCHANGE))
+ {
+ method = new FailoverExchangeMethod(connectionDetails, conn);
+ }
+ else if (failoverMethod.equals(FailoverMethod.NO_FAILOVER))
+ {
+ method = new NoFailover(connectionDetails);
+ }
else
{
try
@@ -272,7 +283,7 @@ public class FailoverPolicy
public FailoverMethod getCurrentMethod()
{
- if ((_currentMethod >= 0) && (_currentMethod < (_methods.length - 1)))
+ if ((_currentMethod >= 0) && (_currentMethod < (_methods.length)))
{
return _methods[_currentMethod];
}
diff --git a/java/client/src/main/java/org/apache/qpid/jms/TopicSubscriber.java b/java/client/src/main/java/org/apache/qpid/jms/TopicSubscriber.java
index 80cfa18ec1..1dbe464230 100644
--- a/java/client/src/main/java/org/apache/qpid/jms/TopicSubscriber.java
+++ b/java/client/src/main/java/org/apache/qpid/jms/TopicSubscriber.java
@@ -1,4 +1,25 @@
package org.apache.qpid.jms;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import org.apache.qpid.AMQException;
diff --git a/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverExchangeMethod.java b/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverExchangeMethod.java
new file mode 100644
index 0000000000..960661daea
--- /dev/null
+++ b/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverExchangeMethod.java
@@ -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.
+ *
+ */
+package org.apache.qpid.jms.failover;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.Session;
+
+import org.apache.qpid.client.AMQAnyDestination;
+import org.apache.qpid.client.AMQBrokerDetails;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.jms.ConnectionURL;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * When using the Failover exchange a single broker is supplied in the URL.
+ * The connection will then connect to the cluster using the above broker details.
+ * Once connected, the membership details of the cluster will be obtained via
+ * subscribing to a queue bound to the failover exchange.
+ *
+ * The failover exchange will provide a list of broker URLs in the format "transport:ip:port"
+ * Out of this list we only select brokers that match the transport of the original
+ * broker supplied in the connection URL.
+ *
+ * Also properties defined for the original broker will be applied to all the brokers selected
+ * from the list.
+ */
+
+public class FailoverExchangeMethod implements FailoverMethod, MessageListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(FailoverExchangeMethod.class);
+
+ /** This is not safe to use until attainConnection is called */
+ private AMQConnection _conn;
+
+ /** Protects the broker list when modifications happens */
+ private Object _brokerListLock = new Object();
+
+ /** The session used to subscribe to failover exchange */
+ private Session _ssn;
+
+ private BrokerDetails _originalBrokerDetail;
+
+ /** The index into the hostDetails array of the broker to which we are connected */
+ private int _currentBrokerIndex = 0;
+
+ /** The broker currently selected **/
+ private BrokerDetails _currentBrokerDetail;
+
+ /** Array of BrokerDetail used to make connections. */
+ private ConnectionURL _connectionDetails;
+
+ /** Denotes the number of failed attempts **/
+ private int _failedAttemps = 0;
+
+ public FailoverExchangeMethod(ConnectionURL connectionDetails, AMQConnection conn)
+ {
+ _connectionDetails = connectionDetails;
+ _originalBrokerDetail = _connectionDetails.getBrokerDetails(0);
+
+ // This is not safe to use until attainConnection is called, as this ref will not initialized fully.
+ // The reason being this constructor is called inside the AMWConnection constructor.
+ // It would be best if we find a way to pass this ref after AMQConnection is fully initialized.
+ _conn = conn;
+ }
+
+ private void subscribeForUpdates() throws JMSException
+ {
+ if (_ssn == null)
+ {
+ _ssn = _conn.createSession(false,Session.AUTO_ACKNOWLEDGE);
+ MessageConsumer cons = _ssn.createConsumer(
+ new AMQAnyDestination(new AMQShortString("amq.failover"),
+ new AMQShortString("amq.failover"),
+ new AMQShortString(""),
+ true,true,null,false,
+ new AMQShortString[0]));
+ cons.setMessageListener(this);
+ }
+ }
+
+ public void onMessage(Message m)
+ {
+ _logger.info("Failover exchange notified cluster membership change");
+
+ String currentBrokerIP = "";
+ try
+ {
+ currentBrokerIP = InetAddress.getByName(_currentBrokerDetail.getHost()).getHostAddress();
+ }
+ catch(Exception e)
+ {
+ _logger.warn("Unable to resolve current broker host name",e);
+ }
+
+ List<BrokerDetails> brokerList = new ArrayList<BrokerDetails>();
+ try
+ {
+ List<String> list = (List<String>)m.getObjectProperty("amq.failover");
+ for (String brokerEntry:list)
+ {
+ String[] urls = brokerEntry.substring(5) .split(",");
+ // Iterate until you find the correct transport
+ // Need to reconsider the logic when the C++ broker supports
+ // SSL URLs.
+ for (String url:urls)
+ {
+ String[] tokens = url.split(":");
+ if (tokens[0].equalsIgnoreCase(_originalBrokerDetail.getTransport()))
+ {
+ BrokerDetails broker = new AMQBrokerDetails();
+ broker.setTransport(tokens[0]);
+ broker.setHost(tokens[1]);
+ broker.setPort(Integer.parseInt(tokens[2]));
+ broker.setProperties(_originalBrokerDetail.getProperties());
+ broker.setSSLConfiguration(_originalBrokerDetail.getSSLConfiguration());
+ brokerList.add(broker);
+
+ if (currentBrokerIP.equals(broker.getHost()) &&
+ _currentBrokerDetail.getPort() == broker.getPort())
+ {
+ _currentBrokerIndex = brokerList.indexOf(broker);
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ catch(JMSException e)
+ {
+ _logger.error("Error parsing the message sent by failover exchange",e);
+ }
+
+ synchronized (_brokerListLock)
+ {
+ _connectionDetails.setBrokerDetails(brokerList);
+ }
+
+ _logger.info("============================================================");
+ _logger.info("Updated cluster membership details " + _connectionDetails);
+ _logger.info("============================================================");
+ }
+
+ public void attainedConnection()
+ {
+ try
+ {
+ _failedAttemps = 0;
+ _logger.info("============================================================");
+ _logger.info("Attained connection ");
+ _logger.info("============================================================");
+ subscribeForUpdates();
+ }
+ catch (JMSException e)
+ {
+ throw new RuntimeException("Unable to subscribe for cluster membership updates",e);
+ }
+ }
+
+ public BrokerDetails getCurrentBrokerDetails()
+ {
+ synchronized (_brokerListLock)
+ {
+ _currentBrokerDetail = _connectionDetails.getBrokerDetails(_currentBrokerIndex);
+ return _currentBrokerDetail;
+ }
+ }
+
+ public BrokerDetails getNextBrokerDetails()
+ {
+ synchronized(_brokerListLock)
+ {
+ if (_currentBrokerIndex == (_connectionDetails.getBrokerCount() - 1))
+ {
+ _currentBrokerIndex = 0;
+ }
+ else
+ {
+ _currentBrokerIndex++;
+ }
+
+ BrokerDetails broker = _connectionDetails.getBrokerDetails(_currentBrokerIndex);
+
+ // When the broker list is updated it will include the current broker as well
+ // There is no point trying it again, so trying the next one.
+ if (_currentBrokerDetail != null &&
+ broker.getHost().equals(_currentBrokerDetail.getHost()) &&
+ broker.getPort() == _currentBrokerDetail.getPort())
+ {
+ if (_connectionDetails.getBrokerCount() > 1)
+ {
+ return getNextBrokerDetails();
+ }
+ else
+ {
+ _failedAttemps ++;
+ return null;
+ }
+ }
+
+ String delayStr = broker.getProperty(BrokerDetails.OPTIONS_CONNECT_DELAY);
+ if (delayStr != null)
+ {
+ Long delay = Long.parseLong(delayStr);
+ _logger.info("Delay between connect retries:" + delay);
+ try
+ {
+ Thread.sleep(delay);
+ }
+ catch (InterruptedException ie)
+ {
+ return null;
+ }
+ }
+ else
+ {
+ _logger.info("No delay between connect retries, use tcp://host:port?connectdelay='value' to enable.");
+ }
+
+ _failedAttemps ++;
+ _currentBrokerDetail = broker;
+ return broker;
+ }
+ }
+
+ public boolean failoverAllowed()
+ {
+ // We allow to Failover provided
+ // our broker list is not empty and
+ // we haven't gone through all of them
+
+ boolean b = _connectionDetails.getBrokerCount() > 0 &&
+ _failedAttemps <= _connectionDetails.getBrokerCount();
+
+
+ _logger.info("============================================================");
+ _logger.info(toString());
+ _logger.info("FailoverAllowed " + b);
+ _logger.info("============================================================");
+
+ return b;
+ }
+
+ public void reset()
+ {
+ _failedAttemps = 0;
+ }
+
+ public void setBroker(BrokerDetails broker)
+ {
+ // not sure if this method is needed
+ }
+
+ public void setRetries(int maxRetries)
+ {
+ // no max retries we keep trying as long
+ // as we get updates
+ }
+
+ public String methodName()
+ {
+ return "Failover Exchange";
+ }
+
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append("FailoverExchange:\n");
+ sb.append("\n Current Broker Index:");
+ sb.append(_currentBrokerIndex);
+ sb.append("\n Failed Attempts:");
+ sb.append(_failedAttemps);
+ sb.append("\n Orignal broker details:");
+ sb.append(_originalBrokerDetail).append("\n");
+ sb.append("\n -------- Broker List -----------\n");
+ for (int i = 0; i < _connectionDetails.getBrokerCount(); i++)
+ {
+ if (i == _currentBrokerIndex)
+ {
+ sb.append(">");
+ }
+
+ sb.append(_connectionDetails.getBrokerDetails(i));
+ sb.append("\n");
+ }
+ sb.append("--------------------------------\n");
+ return sb.toString();
+ }
+}
diff --git a/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverMethod.java b/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverMethod.java
index d7ec46dea3..1cef067e5f 100644
--- a/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverMethod.java
+++ b/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverMethod.java
@@ -27,7 +27,10 @@ public interface FailoverMethod
{
public static final String SINGLE_BROKER = "singlebroker";
public static final String ROUND_ROBIN = "roundrobin";
+ public static final String FAILOVER_EXCHANGE= "failover_exchange";
public static final String RANDOM = "random";
+ public static final String NO_FAILOVER = "nofailover";
+
/**
* Reset the Failover to initial conditions
*/
diff --git a/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverRoundRobinServers.java b/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverRoundRobinServers.java
index 9c172da6a2..41ba4974ec 100644
--- a/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverRoundRobinServers.java
+++ b/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverRoundRobinServers.java
@@ -30,27 +30,27 @@ public class FailoverRoundRobinServers implements FailoverMethod
private static final Logger _logger = LoggerFactory.getLogger(FailoverRoundRobinServers.class);
/** The default number of times to cycle through all servers */
- public static final int DEFAULT_CYCLE_RETRIES = 0;
+ public static final int DEFAULT_CYCLE_RETRIES = 1;
/** The default number of times to retry each server */
public static final int DEFAULT_SERVER_RETRIES = 0;
/** The index into the hostDetails array of the broker to which we are connected */
- private int _currentBrokerIndex = -1;
+ private int _currentBrokerIndex = 0;
/** The number of times to retry connecting for each server */
private int _serverRetries;
/** The current number of retry attempts made */
- private int _currentServerRetry;
+ private int _currentServerRetry = 0;
/** The number of times to cycle through the servers */
private int _cycleRetries;
/** The current number of cycles performed. */
- private int _currentCycleRetries;
+ private int _currentCycleRetries = 0;
/** Array of BrokerDetail used to make connections. */
- private ConnectionURL _connectionDetails;
+ protected ConnectionURL _connectionDetails;
public FailoverRoundRobinServers(ConnectionURL connectionDetails)
{
@@ -62,10 +62,12 @@ public class FailoverRoundRobinServers implements FailoverMethod
_connectionDetails = connectionDetails;
// There is no current broker at startup so set it to -1.
- _currentBrokerIndex = -1;
+ _currentBrokerIndex = 0;
String cycleRetries = _connectionDetails.getFailoverOption(ConnectionURL.OPTIONS_FAILOVER_CYCLE);
+ _cycleRetries = DEFAULT_CYCLE_RETRIES;
+
if (cycleRetries != null)
{
try
@@ -74,42 +76,39 @@ public class FailoverRoundRobinServers implements FailoverMethod
}
catch (NumberFormatException nfe)
{
- _cycleRetries = DEFAULT_CYCLE_RETRIES;
+ _logger.warn("Cannot set cycle Retries, " + cycleRetries + " is not a number. Using default: " + DEFAULT_CYCLE_RETRIES);
}
}
_currentCycleRetries = 0;
_serverRetries = 0;
- _currentServerRetry = -1;
+ _currentServerRetry = 0;
}
public void reset()
{
_currentBrokerIndex = 0;
_currentCycleRetries = 0;
- _currentServerRetry = -1;
+ _currentServerRetry = 0;
}
public boolean failoverAllowed()
{
- return ((_currentCycleRetries < _cycleRetries) || (_currentServerRetry < _serverRetries)
- || (_currentBrokerIndex < (_connectionDetails.getBrokerCount() - 1)));
+ _logger.info("==== Checking failoverAllowed() ====");
+ _logger.info(toString());
+ _logger.info("====================================");
+ return ((_currentCycleRetries < _cycleRetries) || (_currentServerRetry < _serverRetries));
}
public void attainedConnection()
{
_currentCycleRetries = 0;
- _currentServerRetry = -1;
+ _currentServerRetry = 0;
}
public BrokerDetails getCurrentBrokerDetails()
{
- if (_currentBrokerIndex == -1)
- {
- return null;
- }
-
return _connectionDetails.getBrokerDetails(_currentBrokerIndex);
}
@@ -121,20 +120,8 @@ public class FailoverRoundRobinServers implements FailoverMethod
{
if (_currentServerRetry < _serverRetries)
{
- if (_currentBrokerIndex == -1)
- {
- _currentBrokerIndex = 0;
-
- setBroker(_connectionDetails.getBrokerDetails(_currentBrokerIndex));
-
- _logger.info("First run using " + _connectionDetails.getBrokerDetails(_currentBrokerIndex));
- }
- else
- {
- _logger.info("Retrying " + _connectionDetails.getBrokerDetails(_currentBrokerIndex));
- doDelay=true;
- }
-
+ _logger.info("Trying " + _connectionDetails.getBrokerDetails(_currentBrokerIndex));
+ doDelay= _currentBrokerIndex != 0;
_currentServerRetry++;
}
else
@@ -154,19 +141,8 @@ public class FailoverRoundRobinServers implements FailoverMethod
{
if (_currentServerRetry < _serverRetries)
{
- if (_currentBrokerIndex == -1)
- {
- _currentBrokerIndex = 0;
-
- setBroker(_connectionDetails.getBrokerDetails(_currentBrokerIndex));
-
- _logger.info("First run using " + _connectionDetails.getBrokerDetails(_currentBrokerIndex));
- }
- else
- {
- _logger.info("Retrying " + _connectionDetails.getBrokerDetails(_currentBrokerIndex));
- doDelay=true;
- }
+ _logger.info("Trying " + _connectionDetails.getBrokerDetails(_currentBrokerIndex));
+ doDelay= _currentBrokerIndex != 0;
_currentServerRetry++;
}
@@ -198,7 +174,11 @@ public class FailoverRoundRobinServers implements FailoverMethod
}
else
{
- _logger.info("No delay between connect retries, use tcp://host:port?connectdelay='value' to enable.");
+ // Only display if option not set. Not if deDelay==false.
+ if (delayStr == null)
+ {
+ _logger.info("No delay between connect retries, use tcp://host:port?connectdelay='value' to enable.");
+ }
}
return broker;
@@ -225,7 +205,7 @@ public class FailoverRoundRobinServers implements FailoverMethod
}
}
- _currentServerRetry = -1;
+ _currentServerRetry = 0;
_currentBrokerIndex = index;
}
diff --git a/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverSingleServer.java b/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverSingleServer.java
index 9fa006233b..d033a49f5c 100644
--- a/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverSingleServer.java
+++ b/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverSingleServer.java
@@ -30,16 +30,16 @@ public class FailoverSingleServer implements FailoverMethod
private static final Logger _logger = LoggerFactory.getLogger(FailoverSingleServer.class);
/** The default number of times to rety a conection to this server */
- public static final int DEFAULT_SERVER_RETRIES = 1;
+ public static final int DEFAULT_SERVER_RETRIES = 0;
/** The details of the Single Server */
private BrokerDetails _brokerDetail;
/** The number of times to retry connecting to the sever */
- private int _retries;
+ protected int _retries;
/** The current number of attempts made to the server */
- private int _currentRetries;
+ protected int _currentRetries = 0;
public FailoverSingleServer(ConnectionURL connectionDetails)
@@ -61,7 +61,7 @@ public class FailoverSingleServer implements FailoverMethod
public void reset()
{
- _currentRetries = -1;
+ _currentRetries = 0;
}
public boolean failoverAllowed()
@@ -157,7 +157,7 @@ public class FailoverSingleServer implements FailoverMethod
public String toString()
{
- return "SingleServer:\n" +
+ return methodName()+":\n" +
"Max Retries:" + _retries +
"\nCurrent Retry:" + _currentRetries +
"\n" + _brokerDetail + "\n";
diff --git a/java/client/src/main/java/org/apache/qpid/jms/failover/NoFailover.java b/java/client/src/main/java/org/apache/qpid/jms/failover/NoFailover.java
new file mode 100644
index 0000000000..1231324397
--- /dev/null
+++ b/java/client/src/main/java/org/apache/qpid/jms/failover/NoFailover.java
@@ -0,0 +1,62 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.jms.failover;
+
+import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.jms.ConnectionURL;
+
+/**
+ * Extend the Single Server Model to gain retry functionality but once connected do not attempt to failover.
+ */
+public class NoFailover extends FailoverSingleServer
+{
+ private boolean _connected = false;
+
+ public NoFailover(BrokerDetails brokerDetail)
+ {
+ super(brokerDetail);
+ }
+
+ public NoFailover(ConnectionURL connectionDetails)
+ {
+ super(connectionDetails);
+ }
+
+ @Override
+ public void attainedConnection()
+ {
+ _connected=true;
+ _currentRetries = _retries;
+ }
+
+ @Override
+ public String methodName()
+ {
+ return "NoFailover";
+ }
+
+ @Override
+ public String toString()
+ {
+ return super.toString() + (_connected ? "Connection attained." : "Never connected.") + "\n";
+ }
+
+}
diff --git a/java/client/src/main/java/org/apache/qpid/jndi/PropertiesFileInitialContextFactory.java b/java/client/src/main/java/org/apache/qpid/jndi/PropertiesFileInitialContextFactory.java
index 43ac56dee9..8b702c008f 100644
--- a/java/client/src/main/java/org/apache/qpid/jndi/PropertiesFileInitialContextFactory.java
+++ b/java/client/src/main/java/org/apache/qpid/jndi/PropertiesFileInitialContextFactory.java
@@ -48,6 +48,7 @@ import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.url.AMQBindingURL;
import org.apache.qpid.url.BindingURL;
import org.apache.qpid.url.URLSyntaxException;
+import org.apache.qpid.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -84,9 +85,20 @@ public class PropertiesFileInitialContextFactory implements InitialContextFactor
Properties p = new Properties();
p.load(new BufferedInputStream(new FileInputStream(file)));
+ Strings.Resolver resolver = new Strings.ChainedResolver
+ (Strings.SYSTEM_RESOLVER, new Strings.PropertiesResolver(p));
- environment.putAll(p);
- System.getProperties().putAll(p);
+ for (Map.Entry me : p.entrySet())
+ {
+ String key = (String) me.getKey();
+ String value = (String) me.getValue();
+ String expanded = Strings.expand(value, resolver);
+ environment.put(key, expanded);
+ if (System.getProperty(key) == null)
+ {
+ System.setProperty(key, expanded);
+ }
+ }
_logger.info("Loaded Context Properties:" + environment.toString());
}
else
@@ -96,7 +108,8 @@ public class PropertiesFileInitialContextFactory implements InitialContextFactor
}
catch (IOException ioe)
{
- _logger.warn("Unable to load property file specified in Provider_URL:" + environment.get(Context.PROVIDER_URL));
+ _logger.warn("Unable to load property file specified in Provider_URL:" + environment.get(Context.PROVIDER_URL) +"\n" +
+ "Due to:"+ioe.getMessage());
}
createConnectionFactories(data, environment);
@@ -126,7 +139,7 @@ public class PropertiesFileInitialContextFactory implements InitialContextFactor
if (key.startsWith(CONNECTION_FACTORY_PREFIX))
{
String jndiName = key.substring(CONNECTION_FACTORY_PREFIX.length());
- ConnectionFactory cf = createFactory(entry.getValue().toString());
+ ConnectionFactory cf = createFactory(entry.getValue().toString().trim());
if (cf != null)
{
data.put(jndiName, cf);
@@ -144,7 +157,7 @@ public class PropertiesFileInitialContextFactory implements InitialContextFactor
if (key.startsWith(DESTINATION_PREFIX))
{
String jndiName = key.substring(DESTINATION_PREFIX.length());
- Destination dest = createDestination(entry.getValue().toString());
+ Destination dest = createDestination(entry.getValue().toString().trim());
if (dest != null)
{
data.put(jndiName, dest);
@@ -162,7 +175,7 @@ public class PropertiesFileInitialContextFactory implements InitialContextFactor
if (key.startsWith(QUEUE_PREFIX))
{
String jndiName = key.substring(QUEUE_PREFIX.length());
- Queue q = createQueue(entry.getValue().toString());
+ Queue q = createQueue(entry.getValue().toString().trim());
if (q != null)
{
data.put(jndiName, q);
@@ -180,7 +193,7 @@ public class PropertiesFileInitialContextFactory implements InitialContextFactor
if (key.startsWith(TOPIC_PREFIX))
{
String jndiName = key.substring(TOPIC_PREFIX.length());
- Topic t = createTopic(entry.getValue().toString());
+ Topic t = createTopic(entry.getValue().toString().trim());
if (t != null)
{
if (_logger.isDebugEnabled())
@@ -283,7 +296,7 @@ public class PropertiesFileInitialContextFactory implements InitialContextFactor
int i = 0;
for (String key:keys)
{
- bindings[i] = new AMQShortString(key);
+ bindings[i] = new AMQShortString(key.trim());
i++;
}
// The Destination has a dual nature. If this was used for a producer the key is used
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/Client.java b/java/client/src/main/java/org/apache/qpid/nclient/Client.java
deleted file mode 100644
index af0e724e42..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/Client.java
+++ /dev/null
@@ -1,295 +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.
- */
-
-package org.apache.qpid.nclient;
-
-import java.util.List;
-import java.util.UUID;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-import org.apache.qpid.client.url.URLParser_0_10;
-import org.apache.qpid.jms.BrokerDetails;
-import org.apache.qpid.url.QpidURL;
-import org.apache.qpid.ErrorCode;
-import org.apache.qpid.QpidException;
-import org.apache.qpid.nclient.impl.ClientSession;
-import org.apache.qpid.nclient.impl.ClientSessionDelegate;
-import org.apache.qpid.transport.Channel;
-import org.apache.qpid.transport.ClientDelegate;
-import org.apache.qpid.transport.Connection;
-import org.apache.qpid.transport.ConnectionClose;
-import org.apache.qpid.transport.ConnectionCloseCode;
-import org.apache.qpid.transport.ConnectionCloseOk;
-import org.apache.qpid.transport.ProtocolHeader;
-import org.apache.qpid.transport.ProtocolVersionException;
-import org.apache.qpid.transport.SessionDelegate;
-import org.apache.qpid.transport.network.io.IoTransport;
-import org.apache.qpid.transport.network.mina.MinaHandler;
-import org.apache.qpid.transport.network.nio.NioHandler;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-
-public class Client implements org.apache.qpid.nclient.Connection
-{
- private Connection _conn;
- private ClosedListener _closedListner;
- private final Lock _lock = new ReentrantLock();
- private static Logger _logger = LoggerFactory.getLogger(Client.class);
- private Condition closeOk;
- private boolean closed = false;
- private long timeout = 60000;
-
- private ProtocolHeader header = null;
-
- /**
- *
- * @return returns a new connection to the broker.
- */
- public static org.apache.qpid.nclient.Connection createConnection()
- {
- return new Client();
- }
-
- public void connect(String host, int port,String virtualHost,String username, String password) throws QpidException
- {
-
- final Condition negotiationComplete = _lock.newCondition();
- closeOk = _lock.newCondition();
- _lock.lock();
-
- ClientDelegate connectionDelegate = new ClientDelegate()
- {
- private boolean receivedClose = false;
- public SessionDelegate getSessionDelegate()
- {
- return new ClientSessionDelegate();
- }
-
- public void exception(Throwable t)
- {
- if (_closedListner != null)
- {
- _closedListner.onClosed(ErrorCode.CONNECTION_ERROR,ErrorCode.CONNECTION_ERROR.getDesc(),t);
- }
- else
- {
- throw new RuntimeException("connection closed",t);
- }
- }
-
- public void closed()
- {
- if (_closedListner != null && !this.receivedClose)
- {
- _closedListner.onClosed(ErrorCode.CONNECTION_ERROR,ErrorCode.CONNECTION_ERROR.getDesc(),null);
- }
- }
-
- @Override public void connectionCloseOk(Channel context, ConnectionCloseOk struct)
- {
- _lock.lock();
- try
- {
- closed = true;
- this.receivedClose = true;
- closeOk.signalAll();
- }
- finally
- {
- _lock.unlock();
- }
- }
-
- @Override public void connectionClose(Channel context, ConnectionClose connectionClose)
- {
- super.connectionClose(context, connectionClose);
- ErrorCode errorCode = ErrorCode.get(connectionClose.getReplyCode().getValue());
- if (_closedListner == null && errorCode != ErrorCode.NO_ERROR)
- {
- throw new RuntimeException
- (new QpidException("Server closed the connection: Reason " +
- connectionClose.getReplyText(),
- errorCode,
- null));
- }
- else
- {
- _closedListner.onClosed(errorCode, connectionClose.getReplyText(),null);
- }
-
- this.receivedClose = true;
- }
- @Override public void init(Channel ch, ProtocolHeader hdr)
- {
- // TODO: once the merge is done we'll need to update this code
- // for handling 0.8 protocol version type i.e. major=8 and mino
- if (hdr.getMajor() != 0 || hdr.getMinor() != 10)
- {
- Client.this.header = hdr;
- _lock.lock();
- negotiationComplete.signalAll();
- _lock.unlock();
- }
- }
- };
-
- connectionDelegate.setCondition(_lock,negotiationComplete);
- connectionDelegate.setUsername(username);
- connectionDelegate.setPassword(password);
- connectionDelegate.setVirtualHost(virtualHost);
-
- String transport = System.getProperty("transport","io");
- if (transport.equalsIgnoreCase("nio"))
- {
- _logger.info("using NIO Transport");
- _conn = NioHandler.connect(host, port,connectionDelegate);
- }
- else if (transport.equalsIgnoreCase("io"))
- {
- _logger.info("using Plain IO Transport");
- _conn = IoTransport.connect(host, port,connectionDelegate);
- }
- else
- {
- _logger.info("using MINA Transport");
- _conn = MinaHandler.connect(host, port,connectionDelegate);
- // _conn = NativeHandler.connect(host, port,connectionDelegate);
- }
-
- // XXX: hardcoded version numbers
- _conn.send(new ProtocolHeader(1, 0, 10));
-
- try
- {
- negotiationComplete.await(timeout, TimeUnit.MILLISECONDS);
- if (header != null)
- {
- _conn.close();
- throw new ProtocolVersionException(header.getMajor(), header.getMinor());
- }
- }
- catch (InterruptedException e)
- {
- throw new RuntimeException(e);
- }
- finally
- {
- _lock.unlock();
- }
- }
-
- public void connect(String url)throws QpidException
- {
- URLParser_0_10 parser = null;
- try
- {
- parser = new URLParser_0_10(url);
- }
- catch(Exception e)
- {
- throw new QpidException("Error parsing the URL",ErrorCode.UNDEFINED,e);
- }
- List<BrokerDetails> brokers = parser.getAllBrokerDetails();
- BrokerDetails brokerDetail = brokers.get(0);
- connect(brokerDetail.getHost(), brokerDetail.getPort(), brokerDetail.getProperty("virtualhost"),
- brokerDetail.getProperty("username")== null? "guest":brokerDetail.getProperty("username"),
- brokerDetail.getProperty("password")== null? "guest":brokerDetail.getProperty("password"));
- }
-
- /*
- * Until the dust settles with the URL disucssion
- * I am not going to implement this.
- */
- public void connect(QpidURL url) throws QpidException
- {
- throw new UnsupportedOperationException("Not implemented");
- }
-
- /* {
- // temp impl to tests
- BrokerDetails details = url.getAllBrokerDetails().get(0);
- connect(details.getHost(),
- details.getPort(),
- details.getVirtualHost(),
- details.getUserName(),
- details.getPassword());
- }
-*/
-
- public void close() throws QpidException
- {
- Channel ch = _conn.getChannel(0);
- ch.connectionClose(ConnectionCloseCode.NORMAL, "client is closing");
- _lock.lock();
- try
- {
- try
- {
- long start = System.currentTimeMillis();
- long elapsed = 0;
- while (!closed && elapsed < timeout)
- {
- closeOk.await(timeout - elapsed, TimeUnit.MILLISECONDS);
- elapsed = System.currentTimeMillis() - start;
- }
- if(!closed)
- {
- throw new QpidException("Timed out when closing connection", ErrorCode.CONNECTION_ERROR, null);
- }
- }
- catch (InterruptedException e)
- {
- throw new QpidException("Interrupted when closing connection", ErrorCode.CONNECTION_ERROR, null);
- }
- }
- finally
- {
- _lock.unlock();
- }
- _conn.close();
- }
-
- public Session createSession(long expiryInSeconds)
- {
- Channel ch = _conn.getChannel();
- ClientSession ssn = new ClientSession(UUID.randomUUID().toString().getBytes());
- ssn.attach(ch);
- ssn.sessionAttach(ssn.getName());
- ssn.sessionRequestTimeout(expiryInSeconds);
- return ssn;
- }
-
- public DtxSession createDTXSession(int expiryInSeconds)
- {
- ClientSession clientSession = (ClientSession) createSession(expiryInSeconds);
- clientSession.dtxSelect();
- return (DtxSession) clientSession;
- }
-
- public void setClosedListener(ClosedListener closedListner)
- {
-
- _closedListner = closedListner;
- }
-
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/ClosedListener.java b/java/client/src/main/java/org/apache/qpid/nclient/ClosedListener.java
deleted file mode 100644
index 4cf0cab1ec..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/ClosedListener.java
+++ /dev/null
@@ -1,39 +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.
- */
-package org.apache.qpid.nclient;
-
-import org.apache.qpid.ErrorCode;
-
-
-/**
- * If the communication layer detects a serious problem with a <CODE>connection</CODE>, it
- * informs the connection's ExceptionListener
- */
-public interface ClosedListener
-{
- /**
- * If the communication layer detects a serious problem with a connection, it
- * informs the connection's ExceptionListener
- * @param errorCode TODO
- * @param reason TODO
- * @param t TODO
- * @see Connection
- */
- public void onClosed(ErrorCode errorCode, String reason, Throwable t);
-} \ No newline at end of file
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/Connection.java b/java/client/src/main/java/org/apache/qpid/nclient/Connection.java
deleted file mode 100644
index 2d5b50b33a..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/Connection.java
+++ /dev/null
@@ -1,86 +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.
- */
-package org.apache.qpid.nclient;
-
-import org.apache.qpid.QpidException;
-
-/**
- * This represents a physical connection to a broker.
- */
-public interface Connection
-{
- /**
- * Establish the connection using the given parameters
- *
- * @param host host name
- * @param port port number
- * @param virtualHost the virtual host name
- * @param username user name
- * @param password password
- * @throws QpidException If the communication layer fails to establish the connection.
- */
- public void connect(String host, int port,String virtualHost,String username, String password) throws QpidException;
-
- /**
- * Establish the connection with the broker identified by the URL.
- *
- * @param url Specifies the URL of the broker.
- * @throws QpidException If the communication layer fails to connect with the broker, an exception is thrown.
- */
- public void connect(String url) throws QpidException;
-
- /**
- * Close this connection.
- *
- * @throws QpidException if the communication layer fails to close the connection.
- */
- public void close() throws QpidException;
-
- /**
- * Create a session for this connection.
- * <p> The returned session is suspended
- * (i.e. this session is not attached to an underlying channel)
- *
- * @param expiryInSeconds Expiry time expressed in seconds, if the value is less than
- * or equal to 0 then the session does not expire.
- * @return A newly created (suspended) session.
- */
- public Session createSession(long expiryInSeconds);
-
- /**
- * Create a DtxSession for this connection.
- * <p> A Dtx Session must be used when resources have to be manipulated as
- * part of a global transaction.
- * <p> The retuned DtxSession is suspended
- * (i.e. this session is not attached with an underlying channel)
- *
- * @param expiryInSeconds Expiry time expressed in seconds, if the value is less than or equal
- * to 0 then the session does not expire.
- * @return A newly created (suspended) DtxSession.
- */
- public DtxSession createDTXSession(int expiryInSeconds);
-
- /**
- * If the communication layer detects a serious problem with a connection, it
- * informs the connection's ClosedListener
- *
- * @param exceptionListner The ClosedListener
- */
- public void setClosedListener(ClosedListener exceptionListner);
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/DtxSession.java b/java/client/src/main/java/org/apache/qpid/nclient/DtxSession.java
deleted file mode 100644
index 8a859f2d84..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/DtxSession.java
+++ /dev/null
@@ -1,137 +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.
- */
-package org.apache.qpid.nclient;
-
-import org.apache.qpid.transport.Future;
-import org.apache.qpid.transport.GetTimeoutResult;
-import org.apache.qpid.transport.Option;
-import org.apache.qpid.transport.RecoverResult;
-import org.apache.qpid.transport.XaResult;
-import org.apache.qpid.transport.Xid;
-
-/**
- * The resources for this session are controlled under the scope of a distributed transaction.
- */
-public interface DtxSession extends Session
-{
-
- /**
- * This method is called when messages should be produced and consumed on behalf a transaction
- * branch identified by xid.
- * possible options are:
- * <ul>
- * <li> {@link Option#JOIN}: Indicate that the start applies to joining a transaction previously seen.
- * <li> {@link Option#RESUME}: Indicate that the start applies to resuming a suspended transaction branch specified.
- * </ul>
- *
- * @param xid Specifies the xid of the transaction branch to be started.
- * @param options Possible options are: {@link Option#JOIN} and {@link Option#RESUME}.
- * @return Confirms to the client that the transaction branch is started or specify the error condition.
- */
- public Future<XaResult> dtxStart(Xid xid, Option... options);
-
- /**
- * This method is called when the work done on behalf of a transaction branch finishes or needs to
- * be suspended.
- * possible options are:
- * <ul>
- * <li> {@link Option#FAIL}: indicates that this portion of work has failed;
- * otherwise this portion of work has
- * completed successfully.
- * <li> {@link Option#SUSPEND}: Indicates that the transaction branch is
- * temporarily suspended in an incomplete state.
- * </ul>
- *
- * @param xid Specifies the xid of the transaction branch to be ended.
- * @param options Available options are: {@link Option#FAIL} and {@link Option#SUSPEND}.
- * @return Confirms to the client that the transaction branch is ended or specifies the error condition.
- */
- public Future<XaResult> dtxEnd(Xid xid, Option... options);
-
- /**
- * Commit the work done on behalf of a transaction branch. This method commits the work associated
- * with xid. Any produced messages are made available and any consumed messages are discarded.
- * The only possible option is:
- * <ul>
- * <li> {@link Option#ONE_PHASE}: When set, one-phase commit optimization is used.
- * </ul>
- *
- * @param xid Specifies the xid of the transaction branch to be committed.
- * @param options Available option is: {@link Option#ONE_PHASE}
- * @return Confirms to the client that the transaction branch is committed or specifies the error condition.
- */
- public Future<XaResult> dtxCommit(Xid xid, Option... options);
-
- /**
- * This method is called to forget about a heuristically completed transaction branch.
- *
- * @param xid Specifies the xid of the transaction branch to be forgotten.
- */
- public void dtxForget(Xid xid, Option ... options);
-
- /**
- * This method obtains the current transaction timeout value in seconds. If set-timeout was not
- * used prior to invoking this method, the return value is the default timeout value; otherwise, the
- * value used in the previous set-timeout call is returned.
- *
- * @param xid Specifies the xid of the transaction branch used for getting the timeout.
- * @return The current transaction timeout value in seconds.
- */
- public Future<GetTimeoutResult> dtxGetTimeout(Xid xid, Option ... options);
-
- /**
- * This method prepares any message produced or consumed on behalf of xid, ready for commitment.
- *
- * @param xid Specifies the xid of the transaction branch to be prepared.
- * @return The status of the prepare operation can be any one of:
- * xa-ok: Normal execution.
- * <p/>
- * xa-rdonly: The transaction branch was read-only and has been committed.
- * <p/>
- * xa-rbrollback: The broker marked the transaction branch rollback-only for an unspecified
- * reason.
- * <p/>
- * xa-rbtimeout: The work represented by this transaction branch took too long.
- */
- public Future<XaResult> dtxPrepare(Xid xid, Option ... options);
-
- /**
- * This method is called to obtain a list of transaction branches that are in a prepared or
- * heuristically completed state.
- * @return a array of xids to be recovered.
- */
- public Future<RecoverResult> dtxRecover(Option ... options);
-
- /**
- * This method rolls back the work associated with xid. Any produced messages are discarded and
- * any consumed messages are re-queued.
- *
- * @param xid Specifies the xid of the transaction branch to be rolled back.
- * @return Confirms to the client that the transaction branch is rolled back or specifies the error condition.
- */
- public Future<XaResult> dtxRollback(Xid xid, Option ... options);
-
- /**
- * Sets the specified transaction branch timeout value in seconds.
- *
- * @param xid Specifies the xid of the transaction branch for setting the timeout.
- * @param timeout The transaction timeout value in seconds.
- */
- public void dtxSetTimeout(Xid xid, long timeout, Option ... options);
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/JMSTestCase.java b/java/client/src/main/java/org/apache/qpid/nclient/JMSTestCase.java
deleted file mode 100644
index 4e1b9058e6..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/JMSTestCase.java
+++ /dev/null
@@ -1,115 +0,0 @@
- package org.apache.qpid.nclient;
-
-import java.util.Enumeration;
-
-import javax.jms.ExceptionListener;
-import javax.jms.JMSException;
-import javax.jms.Message;
-import javax.jms.MessageListener;
-import javax.jms.Queue;
-import javax.jms.QueueBrowser;
-
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQQueue;
-import org.apache.qpid.client.AMQTopic;
-import org.apache.qpid.framing.AMQShortString;
-
-public class JMSTestCase
-{
-
- public static void main(String[] args)
- {
-
- try
- {
- javax.jms.Connection con = new AMQConnection("qpid:password=pass;username=name@tcp:localhost:5672");
- con.start();
-
- javax.jms.Session ssn = con.createSession(false, 1);
-
- javax.jms.Destination dest = new AMQQueue(new AMQShortString("direct"),"test");
- javax.jms.MessageProducer prod = ssn.createProducer(dest);
- QueueBrowser browser = ssn.createBrowser((Queue)dest, "Test = 'test'");
-
- javax.jms.TextMessage msg = ssn.createTextMessage();
- msg.setStringProperty("TEST", "test");
- msg.setText("Should get this");
- prod.send(msg);
-
- javax.jms.TextMessage msg2 = ssn.createTextMessage();
- msg2.setStringProperty("TEST", "test2");
- msg2.setText("Shouldn't get this");
- prod.send(msg2);
-
-
- Enumeration enu = browser.getEnumeration();
- for (;enu.hasMoreElements();)
- {
- System.out.println(enu.nextElement());
- System.out.println("\n");
- }
-
- javax.jms.MessageConsumer cons = ssn.createConsumer(dest, "Test = 'test'");
- javax.jms.TextMessage m = null; // (javax.jms.TextMessage)cons.receive();
- cons.setMessageListener(new MessageListener()
- {
- public void onMessage(Message m)
- {
- javax.jms.TextMessage m2 = (javax.jms.TextMessage)m;
- try
- {
- System.out.println("headers : " + m2.toString());
- System.out.println("m : " + m2.getText());
- System.out.println("\n\n");
- }
- catch(Exception e)
- {
- e.printStackTrace();
- }
- }
-
- });
-
- con.setExceptionListener(new ExceptionListener()
- {
- public void onException(JMSException e)
- {
- e.printStackTrace();
- }
- });
-
- System.out.println("Waiting");
- while (m == null)
- {
-
- }
-
- System.out.println("Exiting");
-
- /*javax.jms.TextMessage msg = ssn.createTextMessage();
- msg.setText("This is a test message");
- msg.setBooleanProperty("targetMessage", false);
- prod.send(msg);
-
- msg.setBooleanProperty("targetMessage", true);
- prod.send(msg);
-
- javax.jms.TextMessage m = (javax.jms.TextMessage)cons.receiveNoWait();
-
- if (m == null)
- {
- System.out.println("message is null");
- }
- else
- {
- System.out.println("message is not null" + m);
- }*/
-
- }
- catch(Exception e)
- {
- e.printStackTrace();
- }
- }
-
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/Session.java b/java/client/src/main/java/org/apache/qpid/nclient/Session.java
deleted file mode 100644
index 0d84394c7c..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/Session.java
+++ /dev/null
@@ -1,544 +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.
- */
-package org.apache.qpid.nclient;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.Map;
-
-import org.apache.qpid.transport.*;
-import org.apache.qpid.api.Message;
-
-/**
- * <p>A session is associated with a connection.
- * When it is created, a session is not associated with an underlying channel.
- * The session is single threaded. </p>
- * <p/>
- * All the Session commands are asynchronous. Synchronous behavior is achieved through invoking the sync method.
- * For example, <code>command1</code> will be synchronously invoked by using the following sequence:
- * <ul>
- * <li> <code>session.command1()</code>
- * <li> <code>session.sync()</code>
- * </ul>
- */
-public interface Session
-{
- public static final short TRANSFER_ACQUIRE_MODE_NO_ACQUIRE = 1;
- public static final short TRANSFER_ACQUIRE_MODE_PRE_ACQUIRE = 0;
- public static final short TRANSFER_CONFIRM_MODE_REQUIRED = 0;
- public static final short TRANSFER_CONFIRM_MODE_NOT_REQUIRED = 1;
- public static final short MESSAGE_FLOW_MODE_CREDIT = 0;
- public static final short MESSAGE_FLOW_MODE_WINDOW = 1;
- public static final short MESSAGE_FLOW_UNIT_MESSAGE = 0;
- public static final short MESSAGE_FLOW_UNIT_BYTE = 1;
- public static final long MESSAGE_FLOW_MAX_BYTES = 0xFFFFFFFF;
- public static final short MESSAGE_REJECT_CODE_GENERIC = 0;
- public static final short MESSAGE_REJECT_CODE_IMMEDIATE_DELIVERY_FAILED = 1;
- public static final short MESSAGE_ACQUIRE_ANY_AVAILABLE_MESSAGE = 0;
- public static final short MESSAGE_ACQUIRE_MESSAGES_IF_ALL_ARE_AVAILABLE = 1;
-
- //------------------------------------------------------
- // Session housekeeping methods
- //------------------------------------------------------
-
- /**
- * Sync method will block the session until all outstanding commands
- * are executed.
- */
- public void sync();
-
- public void close();
-
- public void sessionDetach(byte[] name, Option ... options);
-
- public void sessionRequestTimeout(long expiry, Option ... options);
-
- public byte[] getName();
-
- public void setAutoSync(boolean value);
-
- //------------------------------------------------------
- // Messaging methods
- // Producer
- //------------------------------------------------------
- /**
- * Transfer a message to a specified exchange.
- * <p/>
- * <p>This transfer provides a complete message
- * using a single method. The method is internally mapped to messageTransfer() and headers() followed
- * by data() and endData().
- * <b><i>This method should only be used by small messages.</b></i></p>
- *
- * @param destination The exchange the message is being sent to.
- * @param msg The Message to be sent.
- * @param confirmMode <ul> </li>off ({@link Session#TRANSFER_CONFIRM_MODE_NOT_REQUIRED}): confirmation
- * is not required. Once a message has been transferred in pre-acquire
- * mode (or once acquire has been sent in no-acquire mode) the message is considered
- * transferred.
- * <p/>
- * <li> on ({@link Session#TRANSFER_CONFIRM_MODE_REQUIRED}): an acquired message
- * is not considered transferred until the original
- * transfer is complete. A complete transfer is signaled by execution.complete.
- * </ul>
- * @param acquireMode <ul>
- * <li> no-acquire ({@link Session#TRANSFER_ACQUIRE_MODE_NO_ACQUIRE}): the message
- * must be explicitly acquired.
- * <li> pre-acquire ({@link Session#TRANSFER_ACQUIRE_MODE_PRE_ACQUIRE}): the message is
- * acquired when the transfer starts.
- * </ul>
- * @throws java.io.IOException If transferring a message fails due to some internal communication error, an exception is thrown.
- */
- public void messageTransfer(String destination, Message msg, short confirmMode, short acquireMode)
- throws IOException;
-
-
- /**
- * This command transfers a message between two peers.
- *
- * @param destination Specifies the destination to which the message is to be transferred.
- * @param acceptMode Indicates whether message.accept, session.complete,
- * or nothing at all is required to indicate successful transfer of the message.
- *
- * @param acquireMode Indicates whether or not the transferred message has been acquired.
- */
- public void messageTransfer(String destination, MessageAcceptMode acceptMode, MessageAcquireMode acquireMode,
- Header header, ByteBuffer body, Option ... options);
-
- /**
- * This command transfers a message between two peers.
- *
- * @param destination Specifies the destination to which the message is to be transferred.
- * @param acceptMode Indicates whether message.accept, session.complete,
- * or nothing at all is required to indicate successful transfer of the message.
- *
- * @param acquireMode Indicates whether or not the transferred message has been acquired.
- */
- public void messageTransfer(String destination, MessageAcceptMode acceptMode, MessageAcquireMode acquireMode,
- Header header, byte[] body, Option ... options);
-
- /**
- * This command transfers a message between two peers.
- *
- * @param destination Specifies the destination to which the message is to be transferred.
- * @param acceptMode Indicates whether message.accept, session.complete,
- * or nothing at all is required to indicate successful transfer of the message.
- *
- * @param acquireMode Indicates whether or not the transferred message has been acquired.
- */
- public void messageTransfer(String destination, MessageAcceptMode acceptMode, MessageAcquireMode acquireMode,
- Header header, String body, Option ... options);
-
- //------------------------------------------------------
- // Messaging methods
- // Consumer
- //------------------------------------------------------
-
- /**
- * Associate a message listener with a destination.
- * <p> The destination is bound to a queue, and messages are filtered based
- * on the provider filter map (message filtering is specific to the provider and in some cases might not be handled).
- * <p> The valid options are:
- * <ul>
- * <li>{@link Option#EXCLUSIVE}: <p> Requests exclusive subscription access, so that only this
- * subscription can access the queue.
- * <li>{@link Option#NONE}: <p> This is an empty option, and has no effect.
- * </ul>
- *
- * @param queue The queue that the receiver is receiving messages from.
- * @param destination The destination, or delivery tag, for the subscriber.
- * @param confirmMode <ul> </li>off ({@link Session#TRANSFER_CONFIRM_MODE_NOT_REQUIRED}): confirmation
- * is not required. Once a message has been transferred in pre-acquire
- * mode (or once acquire has been sent in no-acquire mode) the message is considered
- * transferred.
- * <p/>
- * <li> on ({@link Session#TRANSFER_CONFIRM_MODE_REQUIRED}): an acquired message
- * is not considered transferred until the original
- * transfer is complete. A complete transfer is signaled by execution.complete.
- * </ul>
- * @param acquireMode <ul>
- * <li> no-acquire ({@link Session#TRANSFER_ACQUIRE_MODE_NO_ACQUIRE}): the message must
- * be explicitly acquired.
- * <li> pre-acquire ({@link Session#TRANSFER_ACQUIRE_MODE_PRE_ACQUIRE}): the message is
- * acquired when the transfer starts.
- * </ul>
- * @param listener The listener for this destination. To transfer large messages
- * use a {@link org.apache.qpid.nclient.MessagePartListener}.
- * @param options Set of options. Valid options are {{@link Option#EXCLUSIVE}
- * and {@link Option#NONE}.
- * @param filter A set of filters for the subscription. The syntax and semantics of these filters varies
- * according to the provider's implementation.
- */
- public void messageSubscribe(String queue, String destination, short confirmMode, short acquireMode,
- MessagePartListener listener, Map<String, Object> filter, Option... options);
-
- /**
- * This method cancels a consumer. The server will not send any more messages to the specified destination.
- * This does not affect already delivered messages.
- * The client may receive a
- * number of messages in between sending the cancel method and receiving
- * notification that the cancellation has been completed.
- *
- * @param destination The destination to be cancelled.
- */
- public void messageCancel(String destination, Option ... options);
-
- /**
- * Associate a message listener with a destination.
- * <p> Only one listener is permitted for each destination. When a new listener is created,
- * it replaces the previous message listener. To prevent message loss, this occurs only when the original listener
- * has completed processing a message.
- *
- * @param destination The destination the listener is associated with.
- * @param listener The new listener for this destination.
- */
- public void setMessageListener(String destination, MessagePartListener listener);
-
- /**
- * Sets the mode of flow control used for a given destination.
- * <p> With credit based flow control, the broker continually maintains its current
- * credit balance with the recipient. The credit balance consists of two values, a message
- * count, and a byte count. Whenever message data is sent, both counts must be decremented.
- * If either value reaches zero, the flow of message data must stop. Additional credit is
- * received via the {@link Session#messageFlow} method.
- * <p> Window based flow control is identical to credit based flow control, however message
- * acknowledgment implicitly grants a single unit of message credit, and the size of the
- * message in byte credits for each acknowledged message.
- *
- * @param destination The destination to set the flow mode on.
- * @param mode <ul> <li>credit ({@link Session#MESSAGE_FLOW_MODE_CREDIT}): choose credit based flow control
- * <li> window ({@link Session#MESSAGE_FLOW_MODE_WINDOW}): choose window based flow control</ul>
- */
- public void messageSetFlowMode(String destination, MessageFlowMode mode, Option ... options);
-
-
- /**
- * This method controls the flow of message data to a given destination. It is used by the
- * recipient of messages to dynamically match the incoming rate of message flow to its
- * processing or forwarding capacity. Upon receipt of this method, the sender must add "value"
- * number of the specified unit to the available credit balance for the specified destination.
- * A value of 0 indicates an infinite amount of credit. This disables any limit for
- * the given unit until the credit balance is zeroed with {@link Session#messageStop}
- * or {@link Session#messageFlush}.
- *
- * @param destination The destination to set the flow.
- * @param unit Specifies the unit of credit balance.
- * <p/>
- * One of: <ul>
- * <li> message ({@link Session#MESSAGE_FLOW_UNIT_MESSAGE})
- * <li> byte ({@link Session#MESSAGE_FLOW_UNIT_BYTE})
- * </ul>
- * @param value Number of credits, a value of 0 indicates an infinite amount of credit.
- */
- public void messageFlow(String destination, MessageCreditUnit unit, long value, Option ... options);
-
- /**
- * Forces the broker to exhaust its credit supply.
- * <p> The credit on the broker will remain at zero once
- * this method is completed.
- *
- * @param destination The destination on which the credit supply is to be exhausted.
- */
- public void messageFlush(String destination, Option ... options);
-
- /**
- * On receipt of this method, the brokers set credit to zero for a given
- * destination. When confirmation of this method
- * is issued credit is set to zero. No further messages will be sent until
- * further credit is received.
- *
- * @param destination The destination on which to reset credit.
- */
- public void messageStop(String destination, Option ... options);
-
- /**
- * Acknowledge the receipt of a range of messages.
- * <p>Messages must already be acquired, either by receiving them in
- * pre-acquire mode or by explicitly acquiring them.
- *
- * @param ranges Range of messages to be acknowledged.
- * @param accept pecify whether to send a message accept to the broker
- */
- public void messageAcknowledge(RangeSet ranges, boolean accept);
-
- /**
- * Reject a range of acquired messages.
- * <p>The broker will deliver rejected messages to the
- * alternate-exchange on the queue from which it came. If no alternate-exchange is
- * defined for that queue the broker will discard the message.
- *
- * @param ranges Range of messages to be rejected.
- * @param code The reject code must be one of {@link Session#MESSAGE_REJECT_CODE_GENERIC} or
- * {@link Session#MESSAGE_REJECT_CODE_IMMEDIATE_DELIVERY_FAILED} (immediate delivery was attempted but
- * failed).
- * @param text String describing the reason for a message transfer rejection.
- */
- public void messageReject(RangeSet ranges, MessageRejectCode code, String text, Option ... options);
-
- /**
- * As it is possible that the broker does not manage to reject some messages, after completion of
- * {@link Session#messageReject} this method will return the ranges of rejected messages.
- * <p> Note that {@link Session#messageReject} and this methods are asynchronous therefore for accessing to the
- * previously rejected messages this method must be invoked in conjunction with {@link Session#sync()}.
- * <p> A recommended invocation sequence would be:
- * <ul>
- * <li> {@link Session#messageReject}
- * <li> {@link Session#sync()}
- * <li> {@link Session#getRejectedMessages()}
- * </ul>
- *
- * @return The rejected message ranges
- */
- public RangeSet getRejectedMessages();
-
- /**
- * Try to acquire ranges of messages hence releasing them form the queue.
- * This means that once acknowledged, a message will not be delivered to any other receiver.
- * <p> As those messages may have been consumed by another receivers hence,
- * message acquisition can fail.
- * The outcome of the acquisition is returned as an array of ranges of qcquired messages.
- * <p> This method should only be called on non-acquired messages.
- *
- * @param ranges Ranges of messages to be acquired.
- * @return Indicates the acquired messages
- */
- public Future<Acquired> messageAcquire(RangeSet ranges, Option ... options);
-
- /**
- * Give up responsibility for processing ranges of messages.
- * <p> Released messages are re-enqueued.
- *
- * @param ranges Ranges of messages to be released.
- * @param options Valid option is: {@link Option#SET_REDELIVERED})
- */
- public void messageRelease(RangeSet ranges, Option ... options);
-
- // -----------------------------------------------
- // Local transaction methods
- // ----------------------------------------------
- /**
- * Selects the session for local transaction support.
- */
- public void txSelect(Option ... options);
-
- /**
- * Commit the receipt and delivery of all messages exchanged by this session's resources.
- *
- * @throws IllegalStateException If this session is not transacted, an exception will be thrown.
- */
- public void txCommit(Option ... options) throws IllegalStateException;
-
- /**
- * Roll back the receipt and delivery of all messages exchanged by this session's resources.
- *
- * @throws IllegalStateException If this session is not transacted, an exception will be thrown.
- */
- public void txRollback(Option ... options) throws IllegalStateException;
-
- //---------------------------------------------
- // Queue methods
- //---------------------------------------------
-
- /**
- * Declare a queue with the given queueName
- * <p> Following are the valid options:
- * <ul>
- * <li> {@link Option#AUTO_DELETE}: <p> If this field is set and the exclusive field is also set,
- * then the queue is deleted when the connection closes.
- * If this field is set and the exclusive field is not set the queue is deleted when all
- * the consumers have finished using it.
- * <li> {@link Option#DURABLE}: <p> If set when creating a new queue,
- * the queue will be marked as durable. Durable queues
- * remain active when a server restarts. Non-durable queues (transient queues) are purged
- * if/when a server restarts. Note that durable queues do not necessarily hold persistent
- * messages, although it does not make sense to send persistent messages to a transient
- * queue.
- * <li> {@link Option#EXCLUSIVE}: <p> Exclusive queues can only be used from one connection at a time.
- * Once a connection declares an exclusive queue, that queue cannot be used by any other connections until the
- * declaring connection closes.
- * <li> {@link Option#PASSIVE}: <p> If set, the server will not create the queue.
- * This field allows the client to assert the presence of a queue without modifying the server state.
- * <li>{@link Option#NONE}: <p> Has no effect as it represents an empty option.
- * </ul>
- * <p>In the absence of a particular option, the defaul value is false for each option
- *
- * @param queueName The name of the delcared queue.
- * @param alternateExchange If a message is rejected by a queue, then it is sent to the alternate-exchange. A message
- * may be rejected by a queue for the following reasons:
- * <oL> <li> The queue is deleted when it is not empty;
- * <li> Immediate delivery of a message is requested, but there are no consumers connected to
- * the queue. </ol>
- * @param arguments Used for backward compatibility
- * @param options Set of Options ( valide options are: {@link Option#AUTO_DELETE}, {@link Option#DURABLE},
- * {@link Option#EXCLUSIVE}, {@link Option#PASSIVE} and {@link Option#NONE})
- * @see Option
- */
- public void queueDeclare(String queueName, String alternateExchange, Map<String, Object> arguments,
- Option... options);
-
- /**
- * Bind a queue with an exchange.
- *
- * @param queueName Specifies the name of the queue to bind. If the queue name is empty, refers to the current
- * queue for the session, which is the last declared queue.
- * @param exchangeName The exchange name.
- * @param routingKey Specifies the routing key for the binding. The routing key is used for routing messages
- * depending on the exchange configuration. Not all exchanges use a routing key - refer to
- * the specific exchange documentation. If the queue name is empty, the server uses the last
- * queue declared on the session. If the routing key is also empty, the server uses this
- * queue name for the routing key as well. If the queue name is provided but the routing key
- * is empty, the server does the binding with that empty routing key. The meaning of empty
- * routing keys depends on the exchange implementation.
- * @param arguments Used for backward compatibility
- */
- public void exchangeBind(String queueName, String exchangeName, String routingKey, Map<String, Object> arguments,
- Option ... options);
-
- /**
- * Unbind a queue from an exchange.
- *
- * @param queueName Specifies the name of the queue to unbind.
- * @param exchangeName The name of the exchange to unbind from.
- * @param routingKey Specifies the routing key of the binding to unbind.
- */
- public void exchangeUnbind(String queueName, String exchangeName, String routingKey, Option ... options);
-
- /**
- * This method removes all messages from a queue. It does not cancel consumers. Purged messages
- * are deleted without any formal "undo" mechanism.
- *
- * @param queueName Specifies the name of the queue to purge. If the queue name is empty, refers to the
- * current queue for the session, which is the last declared queue.
- */
- public void queuePurge(String queueName, Option ... options);
-
- /**
- * This method deletes a queue. When a queue is deleted any pending messages are sent to a
- * dead-letter queue if this is defined in the server configuration, and all consumers on the
- * queue are cancelled.
- * <p> Following are the valid options:
- * <ul>
- * <li> {@link Option#IF_EMPTY}: <p> If set, the server will only delete the queue if it has no messages.
- * <li> {@link Option#IF_UNUSED}: <p> If set, the server will only delete the queue if it has no consumers.
- * If the queue has consumers the server does does not delete it but raises a channel exception instead.
- * <li>{@link Option#NONE}: <p> Has no effect as it represents an empty option.
- * </ul>
- * </p>
- * <p/>
- * <p>In the absence of a particular option, the defaul value is false for each option</p>
- *
- * @param queueName Specifies the name of the queue to delete. If the queue name is empty, refers to the
- * current queue for the session, which is the last declared queue.
- * @param options Set of options (Valid options are: {@link Option#IF_EMPTY}, {@link Option#IF_UNUSED}
- * and {@link Option#NONE})
- * @see Option
- */
- public void queueDelete(String queueName, Option... options);
-
-
- /**
- * This method is used to request information on a particular queue.
- *
- * @param queueName The name of the queue for which information is requested.
- * @return Information on the specified queue.
- */
- public Future<QueueQueryResult> queueQuery(String queueName, Option ... options);
-
-
- /**
- * This method is used to request information on a particular binding.
- *
- * @param exchange The exchange name.
- * @param queue The queue name.
- * @param routingKey The routing key
- * @param arguments bacward compatibilties params.
- * @return Information on the specified binding.
- */
- public Future<ExchangeBoundResult> exchangeBound(String exchange, String queue, String routingKey,
- Map<String, Object> arguments, Option ... options);
-
- // --------------------------------------
- // exhcange methods
- // --------------------------------------
-
- /**
- * This method creates an exchange. If the exchange already exists,
- * the method verifies the class and checks the details are correct.
- * <p>Valid options are:
- * <ul>
- * <li>{@link Option#AUTO_DELETE}: <p>If set, the exchange is deleted when all queues have finished using it.
- * <li>{@link Option#DURABLE}: <p>If set, the exchange will
- * be marked as durable. Durable exchanges remain active when a server restarts. Non-durable exchanges (transient
- * exchanges) are purged when a server restarts.
- * <li>{@link Option#PASSIVE}: <p>If set, the server will not create the exchange.
- * The client can use this to check whether an exchange exists without modifying the server state.
- * <li> {@link Option#NONE}: <p>This option is an empty option, and has no effect.
- * </ul>
- * <p>In the absence of a particular option, the defaul value is false for each option</p>
- *
- * @param exchangeName The exchange name.
- * @param type Each exchange belongs to one of a set of exchange types implemented by the server. The
- * exchange types define the functionality of the exchange - i.e. how messages are routed
- * through it. It is not valid or meaningful to attempt to change the type of an existing
- * exchange. Default exchange types are: direct, topic, headers and fanout.
- * @param alternateExchange In the event that a message cannot be routed, this is the name of the exchange to which
- * the message will be sent.
- * @param options Set of options (valid options are: {@link Option#AUTO_DELETE}, {@link Option#DURABLE},
- * {@link Option#PASSIVE}, {@link Option#NONE})
- * @param arguments Used for backward compatibility
- * @see Option
- */
- public void exchangeDeclare(String exchangeName, String type, String alternateExchange,
- Map<String, Object> arguments, Option... options);
-
- /**
- * This method deletes an exchange. When an exchange is deleted all queue bindings on the
- * exchange are cancelled.
- * <p> Following are the valid options:
- * <ul>
- * <li> {@link Option#IF_UNUSED}: <p> If set, the server will only delete the exchange if it has no queue bindings. If the
- * exchange has queue bindings the server does not delete it but raises a channel exception
- * instead.
- * <li> {@link Option#NONE}: <p> Has no effect as it represents an empty option.
- * </ul>
- * <p>Note that if an option is not set, it will default to false.
- *
- * @param exchangeName The name of exchange to be deleted.
- * @param options Set of options. Valid options are: {@link Option#IF_UNUSED}, {@link Option#NONE}.
- * @see Option
- */
- public void exchangeDelete(String exchangeName, Option... options);
-
-
- /**
- * This method is used to request information about a particular exchange.
- *
- * @param exchangeName The name of the exchange about which information is requested. If not set, the method will
- * return information about the default exchange.
- * @return Information on the specified exchange.
- */
- public Future<ExchangeQueryResult> exchangeQuery(String exchangeName, Option ... options);
-
- /**
- * If the session receives a sessionClosed with an error code it
- * informs the session's exceptionListener
- *
- * @param exceptionListner The exceptionListener
- */
- public void setClosedListener(ClosedListener exceptionListner);
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/impl/ClientSession.java b/java/client/src/main/java/org/apache/qpid/nclient/impl/ClientSession.java
deleted file mode 100644
index 27805a1f39..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/impl/ClientSession.java
+++ /dev/null
@@ -1,142 +0,0 @@
-package org.apache.qpid.nclient.impl;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.qpid.QpidException;
-import org.apache.qpid.api.Message;
-import org.apache.qpid.nclient.ClosedListener;
-import org.apache.qpid.nclient.MessagePartListener;
-import org.apache.qpid.transport.DeliveryProperties;
-import org.apache.qpid.transport.Header;
-import org.apache.qpid.transport.MessageAcceptMode;
-import org.apache.qpid.transport.MessageAcquireMode;
-import org.apache.qpid.transport.MessageProperties;
-import org.apache.qpid.transport.Option;
-import org.apache.qpid.transport.Range;
-import org.apache.qpid.transport.RangeSet;
-
-import static org.apache.qpid.transport.Option.*;
-
-/**
- * Implements a Qpid Sesion.
- */
-public class ClientSession extends org.apache.qpid.transport.Session implements org.apache.qpid.nclient.DtxSession
-{
- static
- {
- String max = "message_size_before_sync"; // KB's
- try
- {
- MAX_NOT_SYNC_DATA_LENGH = new Long(System.getProperties().getProperty(max, "200000000"));
- }
- catch (NumberFormatException e)
- {
- // use default size
- MAX_NOT_SYNC_DATA_LENGH = 200000000;
- }
- String flush = "message_size_before_flush";
- try
- {
- MAX_NOT_FLUSH_DATA_LENGH = new Long(System.getProperties().getProperty(flush, "2000000"));
- }
- catch (NumberFormatException e)
- {
- // use default size
- MAX_NOT_FLUSH_DATA_LENGH = 20000000;
- }
- }
-
- private static long MAX_NOT_SYNC_DATA_LENGH;
- private static long MAX_NOT_FLUSH_DATA_LENGH;
-
- private Map<String,MessagePartListener> _messageListeners = new ConcurrentHashMap<String,MessagePartListener>();
- private ClosedListener _exceptionListner;
- private RangeSet _rejectedMessages;
- private long _currentDataSizeNotSynced;
- private long _currentDataSizeNotFlushed;
-
- public ClientSession(byte[] name)
- {
- super(name);
- }
-
- public void messageAcknowledge(RangeSet ranges, boolean accept)
- {
- for (Range range : ranges)
- {
- super.processed(range);
- }
- super.flushProcessed(accept ? BATCH : NONE);
- if (accept)
- {
- messageAccept(ranges);
- }
- }
-
- public void messageSubscribe(String queue, String destination, short acceptMode, short acquireMode, MessagePartListener listener, Map<String, Object> filter, Option... options)
- {
- setMessageListener(destination,listener);
- super.messageSubscribe(queue, destination, MessageAcceptMode.get(acceptMode),
- MessageAcquireMode.get(acquireMode), null, 0, filter,
- options);
- }
-
- public void messageTransfer(String destination, Message msg, short acceptMode, short acquireMode) throws IOException
- {
- DeliveryProperties dp = msg.getDeliveryProperties();
- MessageProperties mp = msg.getMessageProperties();
- ByteBuffer body = msg.readData();
- int size = body.remaining();
- super.messageTransfer
- (destination, MessageAcceptMode.get(acceptMode),
- MessageAcquireMode.get(acquireMode),
- new Header(dp, mp), body);
- _currentDataSizeNotSynced += size;
- _currentDataSizeNotFlushed += size;
- }
-
- public void sync()
- {
- super.sync();
- _currentDataSizeNotSynced = 0;
- }
-
- public RangeSet getRejectedMessages()
- {
- return _rejectedMessages;
- }
-
- public void setMessageListener(String destination, MessagePartListener listener)
- {
- if (listener == null)
- {
- throw new IllegalArgumentException("Cannot set message listener to null");
- }
- _messageListeners.put(destination, listener);
- }
-
- public void setClosedListener(ClosedListener exceptionListner)
- {
- _exceptionListner = exceptionListner;
- }
-
- void setRejectedMessages(RangeSet rejectedMessages)
- {
- _rejectedMessages = rejectedMessages;
- }
-
- void notifyException(QpidException ex)
- {
- _exceptionListner.onClosed(null, null, null);
- }
-
- Map<String,MessagePartListener> getMessageListeners()
- {
- return _messageListeners;
- }
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/impl/ClientSessionDelegate.java b/java/client/src/main/java/org/apache/qpid/nclient/impl/ClientSessionDelegate.java
deleted file mode 100644
index 620cf14c33..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/impl/ClientSessionDelegate.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package org.apache.qpid.nclient.impl;
-
-import java.nio.ByteBuffer;
-
-import org.apache.qpid.ErrorCode;
-
-import org.apache.qpid.nclient.MessagePartListener;
-
-import org.apache.qpid.QpidException;
-import org.apache.qpid.transport.Header;
-import org.apache.qpid.transport.MessageReject;
-import org.apache.qpid.transport.MessageTransfer;
-import org.apache.qpid.transport.Range;
-import org.apache.qpid.transport.Session;
-import org.apache.qpid.transport.SessionDetached;
-import org.apache.qpid.transport.SessionDelegate;
-
-
-public class ClientSessionDelegate extends SessionDelegate
-{
-
- // --------------------------------------------
- // Message methods
- // --------------------------------------------
- @Override public void messageTransfer(Session session, MessageTransfer xfr)
- {
- MessagePartListener listener = ((ClientSession)session).getMessageListeners()
- .get(xfr.getDestination());
- listener.messageTransfer(xfr);
- }
-
- @Override public void messageReject(Session session, MessageReject struct)
- {
- for (Range range : struct.getTransfers())
- {
- for (long l = range.getLower(); l <= range.getUpper(); l++)
- {
- System.out.println("message rejected: " +
- session.getCommand((int) l));
- }
- }
- ((ClientSession)session).setRejectedMessages(struct.getTransfers());
- ((ClientSession)session).notifyException(new QpidException("Message Rejected",ErrorCode.MESSAGE_REJECTED,null));
- session.processed(struct);
- }
-
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/impl/Constants.java b/java/client/src/main/java/org/apache/qpid/nclient/impl/Constants.java
deleted file mode 100644
index f689e9abde..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/impl/Constants.java
+++ /dev/null
@@ -1,78 +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.
- *
- */
-
-package org.apache.qpid.nclient.impl;
-
-/**
- * This class holds all the 0.10 client constants which value can be set
- * through properties.
- */
-public class Constants
-{
- static
- {
-
- String max="message_size_before_sync";// KB's
- try
- {
- MAX_NOT_SYNC_DATA_LENGH=new Long(System.getProperties().getProperty(max, "200000000"));
- }
- catch (NumberFormatException e)
- {
- // use default size
- MAX_NOT_SYNC_DATA_LENGH=200000000;
- }
- String flush="message_size_before_flush";
- try
- {
- MAX_NOT_FLUSH_DATA_LENGH=new Long(System.getProperties().getProperty(flush, "2000000"));
- }
- catch (NumberFormatException e)
- {
- // use default size
- MAX_NOT_FLUSH_DATA_LENGH=20000000;
- }
- }
-
- /**
- * The total message size in KBs that can be transferted before
- * client and broker are synchronized.
- * A sync will result in the client library releasing the sent messages
- * from memory. (messages are kept
- * in memory so client can reconnect to a broker in the event of a failure)
- * <p>
- * Property name: message_size_before_sync
- * <p>
- * Default value: 200000000
- */
- public static long MAX_NOT_SYNC_DATA_LENGH;
- /**
- * The total message size in KBs that can be transferted before
- * messages are flushed.
- * When a flush returns all messages have reached the broker.
- * <p>
- * Property name: message_size_before_flush
- * <p>
- * Default value: 200000000
- */
- public static long MAX_NOT_FLUSH_DATA_LENGH;
-
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/impl/DemoClient.java b/java/client/src/main/java/org/apache/qpid/nclient/impl/DemoClient.java
deleted file mode 100644
index 88b5dc6392..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/impl/DemoClient.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package org.apache.qpid.nclient.impl;
-
-import org.apache.qpid.ErrorCode;
-import org.apache.qpid.api.Message;
-import org.apache.qpid.nclient.Client;
-import org.apache.qpid.nclient.Connection;
-import org.apache.qpid.nclient.ClosedListener;
-import org.apache.qpid.nclient.Session;
-import org.apache.qpid.nclient.util.MessageListener;
-import org.apache.qpid.nclient.util.MessagePartListenerAdapter;
-import org.apache.qpid.transport.DeliveryProperties;
-import org.apache.qpid.transport.Header;
-import org.apache.qpid.transport.MessageAcceptMode;
-import org.apache.qpid.transport.MessageAcquireMode;
-import org.apache.qpid.transport.MessageProperties;
-
-import java.nio.ByteBuffer;
-import java.util.UUID;
-
-public class DemoClient
-{
- public static MessagePartListenerAdapter createAdapter()
- {
- return new MessagePartListenerAdapter(new MessageListener()
- {
- public void onMessage(Message m)
- {
- System.out.println("\n================== Received Msg ==================");
- System.out.println("Message Id : " + m.getMessageProperties().getMessageId());
- System.out.println(m.toString());
- System.out.println("================== End Msg ==================\n");
- }
-
- });
- }
-
- public static final void main(String[] args)
- {
- Connection conn = Client.createConnection();
- try{
- conn.connect("0.0.0.0", 5672, "test", "guest", "guest");
- }catch(Exception e){
- e.printStackTrace();
- }
-
- Session ssn = conn.createSession(50000);
- ssn.setClosedListener(new ClosedListener()
- {
- public void onClosed(ErrorCode errorCode, String reason, Throwable t)
- {
- System.out.println("ErrorCode : " + errorCode + " reason : " + reason);
- }
- });
- ssn.queueDeclare("queue1", null, null);
- ssn.exchangeBind("queue1", "amq.direct", "queue1",null);
- ssn.sync();
-
- ssn.messageSubscribe("queue1", "myDest", (short)0, (short)0,createAdapter(), null);
-
- // queue
- ssn.messageTransfer("amq.direct", MessageAcceptMode.NONE, MessageAcquireMode.PRE_ACQUIRED,
- new Header(new DeliveryProperties().setRoutingKey("queue1"),
- new MessageProperties().setMessageId(UUID.randomUUID())),
- ByteBuffer.wrap("this is the data".getBytes()));
-
- //reject
- ssn.messageTransfer("amq.direct", MessageAcceptMode.NONE, MessageAcquireMode.PRE_ACQUIRED,
- new Header(new DeliveryProperties().setRoutingKey("stocks")),
- ByteBuffer.wrap("this should be rejected".getBytes()));
- ssn.sync();
-
- // topic subs
- ssn.messageSubscribe("topic1", "myDest2", (short)0, (short)0,createAdapter(), null);
- ssn.messageSubscribe("topic2", "myDest3", (short)0, (short)0,createAdapter(), null);
- ssn.messageSubscribe("topic3", "myDest4", (short)0, (short)0,createAdapter(), null);
- ssn.sync();
-
- ssn.queueDeclare("topic1", null, null);
- ssn.exchangeBind("topic1", "amq.topic", "stock.*",null);
- ssn.queueDeclare("topic2", null, null);
- ssn.exchangeBind("topic2", "amq.topic", "stock.us.*",null);
- ssn.queueDeclare("topic3", null, null);
- ssn.exchangeBind("topic3", "amq.topic", "stock.us.rh",null);
- ssn.sync();
-
- // topic
- ssn.messageTransfer("amq.topic", MessageAcceptMode.NONE, MessageAcquireMode.PRE_ACQUIRED,
- new Header(new DeliveryProperties().setRoutingKey("stock.us.ibm"),
- new MessageProperties().setMessageId(UUID.randomUUID())),
- ByteBuffer.wrap("Topic message".getBytes()));
- }
-
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/interop/BasicInteropTest.java b/java/client/src/main/java/org/apache/qpid/nclient/interop/BasicInteropTest.java
deleted file mode 100644
index 9ea9297e14..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/interop/BasicInteropTest.java
+++ /dev/null
@@ -1,155 +0,0 @@
-package org.apache.qpid.nclient.interop;
-
-import java.nio.ByteBuffer;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.qpid.ErrorCode;
-import org.apache.qpid.QpidException;
-import org.apache.qpid.api.Message;
-import org.apache.qpid.nclient.Client;
-import org.apache.qpid.nclient.Connection;
-import org.apache.qpid.nclient.ClosedListener;
-import org.apache.qpid.nclient.Session;
-import org.apache.qpid.nclient.util.MessageListener;
-import org.apache.qpid.nclient.util.MessagePartListenerAdapter;
-import org.apache.qpid.transport.DeliveryProperties;
-import org.apache.qpid.transport.Header;
-import org.apache.qpid.transport.MessageAcceptMode;
-import org.apache.qpid.transport.MessageAcquireMode;
-import org.apache.qpid.transport.MessageCreditUnit;
-import org.apache.qpid.transport.MessageFlowMode;
-import org.apache.qpid.transport.MessageProperties;
-import org.apache.qpid.transport.RangeSet;
-
-public class BasicInteropTest implements ClosedListener
-{
-
- private Session session;
- private Connection conn;
- private String host;
-
- public BasicInteropTest(String host)
- {
- this.host = host;
- }
-
- public void close() throws QpidException
- {
- conn.close();
- }
-
- public void testCreateConnection(){
- System.out.println("------- Creating connection--------");
- conn = Client.createConnection();
- try{
- conn.connect(host, 5672, "test", "guest", "guest");
- }catch(Exception e){
- System.out.println("------- Error Creating connection--------");
- e.printStackTrace();
- System.exit(1);
- }
- System.out.println("------- Connection created Suscessfully --------");
- }
-
- public void testCreateSession(){
- System.out.println("------- Creating session --------");
- session = conn.createSession(0);
- System.out.println("------- Session created sucessfully --------");
- }
-
- public void testExchange(){
- System.out.println("------- Creating an exchange --------");
- session.exchangeDeclare("test", "direct", "", null);
- session.sync();
- System.out.println("------- Exchange created --------");
- }
-
- public void testQueue(){
- System.out.println("------- Creating a queue --------");
- session.queueDeclare("testQueue", "", null);
- session.sync();
- System.out.println("------- Queue created --------");
-
- System.out.println("------- Binding a queue --------");
- session.exchangeBind("testQueue", "test", "testKey", null);
- session.sync();
- System.out.println("------- Queue bound --------");
- }
-
- public void testSendMessage(){
- System.out.println("------- Sending a message --------");
- Map<String,Object> props = new HashMap<String,Object>();
- props.put("name", "rajith");
- props.put("age", 10);
- props.put("spf", 8.5);
- session.messageTransfer("test", MessageAcceptMode.NONE, MessageAcquireMode.PRE_ACQUIRED,
- new Header(new DeliveryProperties().setRoutingKey("testKey"),
- new MessageProperties().setApplicationHeaders(props)),
- ByteBuffer.wrap("TestMessage".getBytes()));
-
- session.sync();
- System.out.println("------- Message sent --------");
- }
-
- public void testSubscribe()
- {
- System.out.println("------- Sending a subscribe --------");
- session.messageSubscribe("testQueue", "myDest",
- Session.TRANSFER_CONFIRM_MODE_REQUIRED,
- Session.TRANSFER_ACQUIRE_MODE_PRE_ACQUIRE,
- new MessagePartListenerAdapter(new MessageListener(){
-
- public void onMessage(Message message)
- {
- System.out.println("--------Message Received--------");
- System.out.println(message.toString());
- System.out.println("--------/Message Received--------");
- RangeSet ack = new RangeSet();
- ack.add(message.getMessageTransferId(),message.getMessageTransferId());
- session.messageAcknowledge(ack, true);
- }
-
- }),
- null);
-
- System.out.println("------- Setting Credit mode --------");
- session.messageSetFlowMode("myDest", MessageFlowMode.WINDOW);
- System.out.println("------- Setting Credit --------");
- session.messageFlow("myDest", MessageCreditUnit.MESSAGE, 1);
- session.messageFlow("myDest", MessageCreditUnit.BYTE, -1);
- }
-
- public void testMessageFlush()
- {
- session.messageFlush("myDest");
- session.sync();
- }
-
- public void onClosed(ErrorCode errorCode, String reason, Throwable t)
- {
- System.out.println("------- Broker Notified an error --------");
- System.out.println("------- " + errorCode + " --------");
- System.out.println("------- " + reason + " --------");
- System.out.println("------- /Broker Notified an error --------");
- }
-
- public static void main(String[] args) throws QpidException
- {
- String host = "0.0.0.0";
- if (args.length>0)
- {
- host = args[0];
- }
-
- BasicInteropTest t = new BasicInteropTest(host);
- t.testCreateConnection();
- t.testCreateSession();
- t.testExchange();
- t.testQueue();
- t.testSubscribe();
- t.testSendMessage();
- t.testMessageFlush();
- t.close();
- }
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/util/ByteBufferMessage.java b/java/client/src/main/java/org/apache/qpid/nclient/util/ByteBufferMessage.java
index 64c89c960c..14bfb4f95e 100644
--- a/java/client/src/main/java/org/apache/qpid/nclient/util/ByteBufferMessage.java
+++ b/java/client/src/main/java/org/apache/qpid/nclient/util/ByteBufferMessage.java
@@ -1,4 +1,25 @@
package org.apache.qpid.nclient.util;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import java.io.IOException;
import java.nio.ByteBuffer;
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/util/FileMessage.java b/java/client/src/main/java/org/apache/qpid/nclient/util/FileMessage.java
deleted file mode 100644
index 179c91c2e9..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/util/FileMessage.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package org.apache.qpid.nclient.util;
-
-import java.io.EOFException;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.MappedByteBuffer;
-import java.nio.channels.FileChannel;
-
-import org.apache.qpid.transport.DeliveryProperties;
-import org.apache.qpid.transport.MessageProperties;
-import org.apache.qpid.transport.Header;
-import org.apache.qpid.api.Message;
-
-/**
- * FileMessage provides pull style semantics for
- * larges messages backed by a disk.
- * Instead of loading all data into memeory it uses
- * FileChannel to map regions of the file into memeory
- * at a time.
- *
- * The write methods are not supported.
- *
- * From the standpoint of performance it is generally
- * only worth mapping relatively large files into memory.
- *
- * FileMessage msg = new FileMessage(in,delProps,msgProps);
- * session.messageTransfer(dest,msg,0,0);
- *
- * The messageTransfer method will read the file in chunks
- * and stream it.
- *
- */
-public class FileMessage extends ReadOnlyMessage implements Message
-{
- private FileChannel _fileChannel;
- private int _chunkSize;
- private long _fileSize;
- private long _pos = 0;
-
- public FileMessage(FileInputStream in,int chunkSize,DeliveryProperties deliveryProperties,MessageProperties messageProperties)throws IOException
- {
- _messageProperties = messageProperties;
- _deliveryProperties = deliveryProperties;
-
- _fileChannel = in.getChannel();
- _chunkSize = chunkSize;
- _fileSize = _fileChannel.size();
-
- if (_fileSize <= _chunkSize)
- {
- _chunkSize = (int)_fileSize;
- }
- }
-
- public void setHeader(Header header) {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public Header getHeader() {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void readData(byte[] target) throws IOException
- {
- throw new UnsupportedOperationException();
- }
-
- public ByteBuffer readData() throws IOException
- {
- if (_pos == _fileSize)
- {
- throw new EOFException();
- }
-
- if (_pos + _chunkSize > _fileSize)
- {
- _chunkSize = (int)(_fileSize - _pos);
- }
- MappedByteBuffer bb = _fileChannel.map(FileChannel.MapMode.READ_ONLY, _pos, _chunkSize);
- _pos += _chunkSize;
- return bb;
- }
-
- /**
- * This message is used by an application user to
- * provide data to the client library using pull style
- * semantics. Since the message is not transfered yet, it
- * does not have a transfer id. Hence this method is not
- * applicable to this implementation.
- */
- public int getMessageTransferId()
- {
- throw new UnsupportedOperationException();
- }
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/util/MessagePartListenerAdapter.java b/java/client/src/main/java/org/apache/qpid/nclient/util/MessagePartListenerAdapter.java
index 0e54e04a99..10fd8d2a80 100644
--- a/java/client/src/main/java/org/apache/qpid/nclient/util/MessagePartListenerAdapter.java
+++ b/java/client/src/main/java/org/apache/qpid/nclient/util/MessagePartListenerAdapter.java
@@ -1,4 +1,25 @@
package org.apache.qpid.nclient.util;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import java.io.IOException;
import java.nio.ByteBuffer;
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/util/ReadOnlyMessage.java b/java/client/src/main/java/org/apache/qpid/nclient/util/ReadOnlyMessage.java
deleted file mode 100644
index 6583a95c7e..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/util/ReadOnlyMessage.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.apache.qpid.nclient.util;
-
-import java.nio.ByteBuffer;
-
-import org.apache.qpid.transport.DeliveryProperties;
-import org.apache.qpid.transport.MessageProperties;
-import org.apache.qpid.api.Message;
-
-public abstract class ReadOnlyMessage implements Message
-{
- MessageProperties _messageProperties;
- DeliveryProperties _deliveryProperties;
-
- public void appendData(byte[] src)
- {
- throw new UnsupportedOperationException("This Message is read only after the initial source");
- }
-
- public void appendData(ByteBuffer src)
- {
- throw new UnsupportedOperationException("This Message is read only after the initial source");
- }
-
- public DeliveryProperties getDeliveryProperties()
- {
- return _deliveryProperties;
- }
-
- public MessageProperties getMessageProperties()
- {
- return _messageProperties;
- }
-
- public void clearData()
- {
- throw new UnsupportedOperationException("This Message is read only after the initial source, cannot clear data");
- }
-}
diff --git a/java/client/src/main/java/org/apache/qpid/nclient/util/StreamingMessage.java b/java/client/src/main/java/org/apache/qpid/nclient/util/StreamingMessage.java
deleted file mode 100644
index a4574438ac..0000000000
--- a/java/client/src/main/java/org/apache/qpid/nclient/util/StreamingMessage.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package org.apache.qpid.nclient.util;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.SocketChannel;
-
-import org.apache.qpid.transport.DeliveryProperties;
-import org.apache.qpid.transport.MessageProperties;
-import org.apache.qpid.transport.Header;
-import org.apache.qpid.api.Message;
-
-public class StreamingMessage extends ReadOnlyMessage implements Message
-{
- SocketChannel _socChannel;
- private int _chunkSize;
- private ByteBuffer _readBuf;
-
- public Header getHeader() {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void setHeader(Header header) {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public StreamingMessage(SocketChannel in,int chunkSize,DeliveryProperties deliveryProperties,MessageProperties messageProperties)throws IOException
- {
- _messageProperties = messageProperties;
- _deliveryProperties = deliveryProperties;
-
- _socChannel = in;
- _chunkSize = chunkSize;
- _readBuf = ByteBuffer.allocate(_chunkSize);
- }
-
- public void readData(byte[] target) throws IOException
- {
- throw new UnsupportedOperationException();
- }
-
- public ByteBuffer readData() throws IOException
- {
- if(_socChannel.isConnected() && _socChannel.isOpen())
- {
- _readBuf.clear();
- _socChannel.read(_readBuf);
- }
- else
- {
- throw new EOFException("The underlying socket/channel has closed");
- }
-
- return _readBuf.duplicate();
- }
-
- /**
- * This message is used by an application user to
- * provide data to the client library using pull style
- * semantics. Since the message is not transfered yet, it
- * does not have a transfer id. Hence this method is not
- * applicable to this implementation.
- */
- public int getMessageTransferId()
- {
- throw new UnsupportedOperationException();
- }
-}
diff --git a/java/client/src/test/java/org/apache/qpid/client/AMQQueueTest.java b/java/client/src/test/java/org/apache/qpid/client/AMQQueueTest.java
new file mode 100644
index 0000000000..7789f87ace
--- /dev/null
+++ b/java/client/src/test/java/org/apache/qpid/client/AMQQueueTest.java
@@ -0,0 +1,42 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.client;
+
+import org.apache.qpid.framing.AMQShortString;
+
+import junit.framework.TestCase;
+
+public class AMQQueueTest extends TestCase
+{
+ AMQShortString exchange = new AMQShortString("test.exchange");
+ AMQShortString routingkey = new AMQShortString("test-route");
+ AMQShortString qname = new AMQShortString("test-queue");
+ AMQShortString[] oneBinding = new AMQShortString[]{new AMQShortString("bindingA")};
+ AMQShortString[] bindings = new AMQShortString[]{new AMQShortString("bindingB"),
+ new AMQShortString("bindingC")};
+
+ public void testToURLNoBindings()
+ {
+ AMQQueue dest = new AMQQueue(exchange, routingkey, qname);
+ String url = dest.toURL();
+ assertEquals("direct://test.exchange/test-route/test-queue?routingkey='test-route'", url);
+ }
+}
diff --git a/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java b/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java
new file mode 100644
index 0000000000..da44822ec3
--- /dev/null
+++ b/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java
@@ -0,0 +1,94 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.client;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.state.AMQState;
+import org.apache.qpid.framing.ProtocolVersion;
+import org.apache.qpid.jms.ConnectionURL;
+import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.url.URLSyntaxException;
+
+import java.io.IOException;
+
+public class MockAMQConnection extends AMQConnection
+{
+ public MockAMQConnection(String broker, String username, String password, String clientName, String virtualHost)
+ throws AMQException, URLSyntaxException
+ {
+ super(broker, username, password, clientName, virtualHost);
+ }
+
+ public MockAMQConnection(String broker, String username, String password, String clientName, String virtualHost, SSLConfiguration sslConfig)
+ throws AMQException, URLSyntaxException
+ {
+ super(broker, username, password, clientName, virtualHost, sslConfig);
+ }
+
+ public MockAMQConnection(String host, int port, String username, String password, String clientName, String virtualHost)
+ throws AMQException, URLSyntaxException
+ {
+ super(host, port, username, password, clientName, virtualHost);
+ }
+
+ public MockAMQConnection(String host, int port, String username, String password, String clientName, String virtualHost, SSLConfiguration sslConfig)
+ throws AMQException, URLSyntaxException
+ {
+ super(host, port, username, password, clientName, virtualHost, sslConfig);
+ }
+
+ public MockAMQConnection(String host, int port, boolean useSSL, String username, String password, String clientName, String virtualHost, SSLConfiguration sslConfig)
+ throws AMQException, URLSyntaxException
+ {
+ super(host, port, useSSL, username, password, clientName, virtualHost, sslConfig);
+ }
+
+ public MockAMQConnection(String connection)
+ throws AMQException, URLSyntaxException
+ {
+ super(connection);
+ }
+
+ public MockAMQConnection(String connection, SSLConfiguration sslConfig)
+ throws AMQException, URLSyntaxException
+ {
+ super(connection, sslConfig);
+ }
+
+ public MockAMQConnection(ConnectionURL connectionURL, SSLConfiguration sslConfig)
+ throws AMQException
+ {
+ super(connectionURL, sslConfig);
+ }
+
+ protected MockAMQConnection(String username, String password, String clientName, String virtualHost)
+ {
+ super(username, password, clientName, virtualHost);
+ }
+
+ @Override
+ public ProtocolVersion makeBrokerConnection(BrokerDetails brokerDetail) throws IOException
+ {
+ _connected = true;
+ _protocolHandler.getStateManager().changeState(AMQState.CONNECTION_OPEN);
+ return null;
+ }
+}
diff --git a/java/client/src/test/java/org/apache/qpid/client/message/AbstractJMSMessageTest.java b/java/client/src/test/java/org/apache/qpid/client/message/AbstractJMSMessageTest.java
new file mode 100644
index 0000000000..b4774113be
--- /dev/null
+++ b/java/client/src/test/java/org/apache/qpid/client/message/AbstractJMSMessageTest.java
@@ -0,0 +1,36 @@
+package org.apache.qpid.client.message;
+
+import javax.jms.JMSException;
+
+import junit.framework.TestCase;
+
+public class AbstractJMSMessageTest extends TestCase
+{
+
+ public void testSetNullJMSReplyTo08() throws JMSException
+ {
+ JMSTextMessage message = new JMSTextMessage(AMQMessageDelegateFactory.FACTORY_0_8);
+ try
+ {
+ message.setJMSReplyTo(null);
+ }
+ catch (IllegalArgumentException e)
+ {
+ fail("Null destination should be allowed");
+ }
+ }
+
+ public void testSetNullJMSReplyTo10() throws JMSException
+ {
+ JMSTextMessage message = new JMSTextMessage(AMQMessageDelegateFactory.FACTORY_0_10);
+ try
+ {
+ message.setJMSReplyTo(null);
+ }
+ catch (IllegalArgumentException e)
+ {
+ fail("Null destination should be allowed");
+ }
+ }
+
+}
diff --git a/java/client/src/test/java/org/apache/qpid/client/protocol/AMQProtocolHandlerTest.java b/java/client/src/test/java/org/apache/qpid/client/protocol/AMQProtocolHandlerTest.java
new file mode 100644
index 0000000000..f520a21ba0
--- /dev/null
+++ b/java/client/src/test/java/org/apache/qpid/client/protocol/AMQProtocolHandlerTest.java
@@ -0,0 +1,289 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.client.protocol;
+
+import junit.framework.TestCase;
+import org.apache.qpid.framing.AMQFrame;
+import org.apache.qpid.framing.AMQBody;
+import org.apache.qpid.framing.AMQMethodBody;
+import org.apache.qpid.framing.amqp_8_0.BasicRecoverOkBodyImpl;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.transport.TestNetworkDriver;
+import org.apache.qpid.client.MockAMQConnection;
+import org.apache.qpid.client.AMQAuthenticationException;
+import org.apache.qpid.client.state.AMQState;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * This is a test address QPID-1431 where frame listeners would fail to be notified of an incomming exception.
+ *
+ * Currently we do checks at the Session level to ensure that the connection/session are open. However, it is possible
+ * for the connection to close AFTER this check has been performed.
+ *
+ * Performing a similar check at the frameListener level in AMQProtocolHandler makes most sence as this will prevent
+ * listening when there can be no returning frames.
+ *
+ * With the correction in place it also means that the new listener will either make it on to the list for notification
+ * or it will be notified of any existing exception due to the connection being closed.
+ *
+ * There may still be an issue in this space if the client utilises a second thread to close the session as there will
+ * be no exception set to throw and so the wait will occur. That said when the session is closed the framelisteners
+ * should be notified. Not sure this is tested.
+ */
+public class AMQProtocolHandlerTest extends TestCase
+{
+ private static final Logger _logger = LoggerFactory.getLogger(AMQProtocolHandlerTest.class);
+
+ // The handler to test
+ AMQProtocolHandler _handler;
+
+ // A frame to block upon whilst waiting the exception
+ AMQFrame _blockFrame;
+
+ // Latch to know when the listener receives an exception
+ private CountDownLatch _handleCountDown;
+ // The listener that will receive an exception
+ BlockToAccessFrameListener _listener;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ //Create a new ProtocolHandler with a fake connection.
+ _handler = new AMQProtocolHandler(new MockAMQConnection("amqp://guest:guest@client/test?brokerlist='vm://:1'"));
+ _handler.setNetworkDriver(new TestNetworkDriver());
+ AMQBody body = BasicRecoverOkBodyImpl.getFactory().newInstance(null, 1);
+ _blockFrame = new AMQFrame(0, body);
+
+ _handleCountDown = new CountDownLatch(1);
+
+ _logger.info("Creating _Listener that should also receive the thrown exception.");
+ _listener = new BlockToAccessFrameListener(1);
+ }
+
+ /**
+ * There are two paths based on the type of exception thrown.
+ *
+ * This tests that when an AMQException is thrown we get the same type of AMQException back with the real exception
+ * wrapped as the cause.
+ *
+ * @throws InterruptedException - if we are unable to wait for the test signals
+ */
+ public void testFrameListenerUpdateWithAMQException() throws InterruptedException
+ {
+ AMQException trigger = new AMQAuthenticationException(AMQConstant.ACCESS_REFUSED,
+ "AMQPHTest", new RuntimeException());
+
+ performWithException(trigger);
+
+
+ AMQException receivedException = (AMQException) _listener.getReceivedException();
+
+ assertEquals("Return exception was not the expected type",
+ AMQAuthenticationException.class, receivedException.getClass());
+
+ assertEquals("The _Listener did not receive the correct error code",
+ trigger.getErrorCode(), receivedException.getErrorCode());
+ }
+
+ /**
+ * There are two paths based on the type of exception thrown.
+ *
+ * This tests that when a generic Exception is thrown we get the exception back wrapped in a AMQException
+ * as the cause.
+ * @throws InterruptedException - if we are unable to wait for the test signals
+ */
+ public void testFrameListenerUpdateWithException() throws InterruptedException
+ {
+
+ Exception trigger = new Exception(new RuntimeException());
+
+ performWithException(trigger);
+
+ assertEquals("The _Listener did not receive the correct error code",
+ AMQConstant.INTERNAL_ERROR, ((AMQException)_listener.getReceivedException()).getErrorCode());
+ }
+
+ /**
+ * This is the main test method for both test cases.
+ *
+ * What occurs is that we create a new thread that will block (<30s[DEFAULT]) for a frame or exception to occur .
+ *
+ * We use a CountDownLatch to ensure that the new thread is running before we then yield and sleep to help ensure
+ * the new thread has entered the synchronized block in the writeCommandFrameAndWaitForReply.
+ *
+ * We can then ack like an the incomming exception handler in (ConnectionCloseMethodHandler).
+ *
+ * We fire the error to the stateManager, which in this case will recored the error as there are no state listeners.
+ *
+ * We then set the connection to be closed, as we would normally close the socket at this point.
+ *
+ * Then fire the exception in to any frameListeners.
+ *
+ * The blocked listener (created above) when receiving the error simulates the user by creating a new request to
+ * block for a frame.
+ *
+ * This request should fail. Prior to the fix this will fail with a NPE as we are attempting to use a null listener
+ * in the writeCommand.... call L:268.
+ *
+ * This highlights that the listener would be added dispite there being a pending error state that the listener will
+ * miss as it is not currently part of the _frameListeners set that is being notified by the iterator.
+ *
+ * The method waits to ensure that an exception is received before returning.
+ *
+ * The calling methods validate that exception that was received based on the one they sent in.
+ *
+ * @param trigger The exception to throw through the handler
+ */
+ private void performWithException(Exception trigger) throws InterruptedException
+ {
+
+ final CountDownLatch callingWriteCommand = new CountDownLatch(1);
+
+ //Set an initial listener that will allow us to create a new blocking method
+ new Thread(new Runnable()
+ {
+ public void run()
+ {
+
+ try
+ {
+
+ _logger.info("At initial block, signalling to fire new exception");
+ callingWriteCommand.countDown();
+
+ _handler.writeCommandFrameAndWaitForReply(_blockFrame, _listener);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+ }).start();
+
+ _logger.info("Waiting for 'initial block' to start ");
+ if (!callingWriteCommand.await(1000, TimeUnit.MILLISECONDS))
+ {
+ fail("Failed to start new thread to block for frame");
+ }
+
+ // Do what we can to ensure that this thread does not continue before the above thread has hit the synchronized
+ // block in the writeCommandFrameAndWaitForReply
+ Thread.yield();
+ Thread.sleep(1000);
+
+ _logger.info("Firing Erorr through state manager. There should be not state waiters here.");
+ _handler.getStateManager().error(trigger);
+
+ _logger.info("Setting state to be CONNECTION_CLOSED.");
+
+ _handler.getStateManager().changeState(AMQState.CONNECTION_CLOSED);
+
+ _logger.info("Firing exception");
+ _handler.propagateExceptionToFrameListeners(trigger);
+
+ _logger.info("Awaiting notifcation from handler that exception arrived.");
+
+ if (!_handleCountDown.await(2000, TimeUnit.MILLISECONDS))
+ {
+ fail("Failed to handle exception and timeout has not occured");
+ }
+
+
+ assertNotNull("The _Listener did not receive the exception", _listener.getReceivedException());
+
+ assertTrue("Received exception not an AMQException",
+ _listener.getReceivedException() instanceof AMQException);
+
+ AMQException receivedException = (AMQException) _listener.getReceivedException();
+
+ assertTrue("The _Listener did not receive the correct message",
+ receivedException.getMessage().startsWith(trigger.getMessage()));
+
+
+ assertEquals("The _Listener did not receive the correct cause",
+ trigger, receivedException.getCause());
+
+ assertEquals("The _Listener did not receive the correct sub cause",
+ trigger.getCause(), receivedException.getCause().getCause());
+
+ }
+
+ class BlockToAccessFrameListener extends BlockingMethodFrameListener
+ {
+ private Exception _receivedException = null;
+
+ /**
+ * Creates a new method listener, that filters incoming method to just those that match the specified channel id.
+ *
+ * @param channelId The channel id to filter incoming methods with.
+ */
+ public BlockToAccessFrameListener(int channelId)
+ {
+ super(channelId);
+ _logger.info("Creating a listener:" + this);
+ }
+
+ public boolean processMethod(int channelId, AMQMethodBody frame)
+ {
+ return true;
+ }
+
+ @Override
+ public void error(Exception e)
+ {
+ _logger.info("Exception(" + e + ") Received by:" + this);
+ // Create a new Thread to start the blocking registration.
+ new Thread(new Runnable()
+ {
+
+ public void run()
+ {
+ //Set an initial listener that will allow us to create a new blocking method
+ try
+ {
+ _handler.writeCommandFrameAndWaitForReply(_blockFrame, null, 2000L);
+ _logger.info("listener(" + this + ") Wait completed");
+ }
+ catch (Exception e)
+ {
+ _logger.info("listener(" + this + ") threw exception:" + e.getMessage());
+ _receivedException = e;
+ }
+
+ _logger.info("listener(" + this + ") completed");
+ _handleCountDown.countDown();
+ }
+ }).start();
+ }
+
+ public Exception getReceivedException()
+ {
+ return _receivedException;
+ }
+ }
+
+}
diff --git a/java/client/src/test/java/org/apache/qpid/client/protocol/MockIoSession.java b/java/client/src/test/java/org/apache/qpid/client/protocol/MockIoSession.java
new file mode 100644
index 0000000000..f0938a4bc0
--- /dev/null
+++ b/java/client/src/test/java/org/apache/qpid/client/protocol/MockIoSession.java
@@ -0,0 +1,312 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.client.protocol;
+
+import org.apache.mina.common.*;
+import org.apache.mina.common.support.DefaultCloseFuture;
+import org.apache.mina.common.support.DefaultWriteFuture;
+import org.apache.mina.common.support.AbstractIoFilterChain;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+
+import java.net.SocketAddress;
+import java.net.InetSocketAddress;
+import java.util.Set;
+
+public class MockIoSession implements IoSession
+{
+ private AMQProtocolSession _protocolSession;
+
+ /**
+ * Stores the last response written
+ */
+ private Object _lastWrittenObject;
+
+ private boolean _closing;
+ private IoFilterChain _filterChain;
+
+ public MockIoSession()
+ {
+ _filterChain = new AbstractIoFilterChain(this)
+ {
+ protected void doWrite(IoSession ioSession, IoFilter.WriteRequest writeRequest) throws Exception
+ {
+
+ }
+
+ protected void doClose(IoSession ioSession) throws Exception
+ {
+
+ }
+ };
+ }
+
+ public Object getLastWrittenObject()
+ {
+ return _lastWrittenObject;
+ }
+
+ public IoService getService()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public IoServiceConfig getServiceConfig()
+ {
+ return null;
+ }
+
+ public IoHandler getHandler()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public IoSessionConfig getConfig()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public IoFilterChain getFilterChain()
+ {
+ return _filterChain;
+ }
+
+ public WriteFuture write(Object message)
+ {
+ WriteFuture wf = new DefaultWriteFuture(null);
+ _lastWrittenObject = message;
+ return wf;
+ }
+
+ public CloseFuture close()
+ {
+ _closing = true;
+ CloseFuture cf = new DefaultCloseFuture(null);
+ cf.setClosed();
+ return cf;
+ }
+
+ public Object getAttachment()
+ {
+ return _protocolSession;
+ }
+
+ public Object setAttachment(Object attachment)
+ {
+ Object current = _protocolSession;
+ _protocolSession = (AMQProtocolSession) attachment;
+ return current;
+ }
+
+ public Object getAttribute(String key)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public Object setAttribute(String key, Object value)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public Object setAttribute(String key)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public Object removeAttribute(String key)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean containsAttribute(String key)
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public Set getAttributeKeys()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public TransportType getTransportType()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isConnected()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isClosing()
+ {
+ return _closing;
+ }
+
+ public CloseFuture getCloseFuture()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public SocketAddress getRemoteAddress()
+ {
+ return new InetSocketAddress("127.0.0.1", 1234); //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public SocketAddress getLocalAddress()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public SocketAddress getServiceAddress()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int getIdleTime(IdleStatus status)
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getIdleTimeInMillis(IdleStatus status)
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setIdleTime(IdleStatus status, int idleTime)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int getWriteTimeout()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getWriteTimeoutInMillis()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setWriteTimeout(int writeTimeout)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public TrafficMask getTrafficMask()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setTrafficMask(TrafficMask trafficMask)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void suspendRead()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void suspendWrite()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void resumeRead()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void resumeWrite()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getReadBytes()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getWrittenBytes()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getReadMessages()
+ {
+ return 0L;
+ }
+
+ public long getWrittenMessages()
+ {
+ return 0L;
+ }
+
+ public long getWrittenWriteRequests()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int getScheduledWriteRequests()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int getScheduledWriteBytes()
+ {
+ return 0; //TODO
+ }
+
+ public long getCreationTime()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getLastIoTime()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getLastReadTime()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getLastWriteTime()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isIdle(IdleStatus status)
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int getIdleCount(IdleStatus status)
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getLastIdleTime(IdleStatus status)
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java
index 7bf96b99c1..1b27ff6300 100644
--- a/java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java
+++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java
@@ -20,14 +20,19 @@
*/
package org.apache.qpid.test.unit.client.BrokerDetails;
+import java.util.HashMap;
+import java.util.Map;
+
import junit.framework.TestCase;
import org.apache.qpid.client.AMQBrokerDetails;
+import org.apache.qpid.client.AMQConnectionURL;
+import org.apache.qpid.jms.ConnectionURL;
+import org.apache.qpid.jms.BrokerDetails;
import org.apache.qpid.url.URLSyntaxException;
public class BrokerDetailsTest extends TestCase
{
-
public void testMultiParameters() throws URLSyntaxException
{
String url = "tcp://localhost:5672?timeout='200',immediatedelivery='true'";
diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java
index 6f4c26945c..7400b524fd 100644
--- a/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java
+++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java
@@ -375,6 +375,19 @@ public class ConnectionURLTest extends TestCase
assertTrue(connectionurl.getBrokerCount() == 1);
}
+ public void testClientIDWithUnderscore() throws URLSyntaxException
+ {
+ String url = "amqp://user:pass@client_id/test?brokerlist='tcp://localhost:5672'";
+
+ ConnectionURL connectionurl = new AMQConnectionURL(url);
+
+ assertTrue(connectionurl.getUsername().equals("user"));
+ assertTrue(connectionurl.getPassword().equals("pass"));
+ assertTrue(connectionurl.getVirtualHost().equals("/test"));
+ assertTrue(connectionurl.getClientName().equals("client_id"));
+
+ assertTrue(connectionurl.getBrokerCount() == 1);
+ }
public void testWrongOptionSeparatorInOptions()
{
@@ -486,7 +499,8 @@ public class ConnectionURLTest extends TestCase
assertNotNull(curl.getBrokerDetails(0));
assertEquals(BrokerDetails.SOCKET, curl.getBrokerDetails(0).getTransport());
assertEquals("VM-Unique-socketID", curl.getBrokerDetails(0).getHost());
- assertEquals("URL does not toString as expected", url, curl.toString());
+ assertEquals("URL does not toString as expected",
+ url.replace(":guest", ":********"), curl.toString());
}
catch (URLSyntaxException e)
{
diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/destinationurl/DestinationURLTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/destinationurl/DestinationURLTest.java
index 2a66b86985..22e432a44f 100644
--- a/java/client/src/test/java/org/apache/qpid/test/unit/client/destinationurl/DestinationURLTest.java
+++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/destinationurl/DestinationURLTest.java
@@ -177,6 +177,18 @@ public class DestinationURLTest extends TestCase
assertTrue("Failed to throw an URISyntaxException when both the bindingkey and routingkey is specified",exceptionThrown);
}
+
+ public void testDestinationWithDurableTopic() throws URISyntaxException
+ {
+
+ String url = "topic://amq.topic//testTopicD?durable='true'&autodelete='true'&clientid='test'&subscription='testQueueD'";
+
+ AMQBindingURL dest = new AMQBindingURL(url);
+
+ assertTrue(dest.getExchangeClass().equals("topic"));
+ assertTrue(dest.getExchangeName().equals("amq.topic"));
+ assertTrue(dest.getQueueName().equals("test:testQueueD"));
+ }
public static junit.framework.Test suite()
{
diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/message/BytesMessageTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/message/BytesMessageTest.java
index bbabf0b57d..65013e7e6d 100644
--- a/java/client/src/test/java/org/apache/qpid/test/unit/client/message/BytesMessageTest.java
+++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/message/BytesMessageTest.java
@@ -559,7 +559,7 @@ public class BytesMessageTest extends TestCase
JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
bm.reset();
String result = bm.toBodyString();
- assertNull(result);
+ assertEquals("\"\"", result);
}
public static junit.framework.Test suite()
diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/message/StreamMessageTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/message/StreamMessageTest.java
index 802f1e6c2e..085dd81079 100644
--- a/java/client/src/test/java/org/apache/qpid/test/unit/client/message/StreamMessageTest.java
+++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/message/StreamMessageTest.java
@@ -435,7 +435,7 @@ public class StreamMessageTest extends TestCase
JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
bm.reset();
String result = bm.toBodyString();
- assertNull(result);
+ assertEquals("\"\"", result);
}
private void checkConversionsFail(StreamMessage sm, int[] conversions) throws JMSException
diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/jndi/ConnectionFactoryTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/jndi/ConnectionFactoryTest.java
new file mode 100644
index 0000000000..9e76b0d468
--- /dev/null
+++ b/java/client/src/test/java/org/apache/qpid/test/unit/jndi/ConnectionFactoryTest.java
@@ -0,0 +1,75 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.jndi;
+
+import junit.framework.TestCase;
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.jms.ConnectionURL;
+import org.apache.qpid.url.URLSyntaxException;
+
+public class ConnectionFactoryTest extends TestCase
+{
+
+ //URL will be returned with the password field swapped for '********'
+ // so ensure that these two strings are kept in sync.
+ public static final String URL = "amqp://guest:guest@clientID/test?brokerlist='tcp://localhost:5672'";
+ public static final String URL_STAR_PWD = "amqp://guest:********@clientID/test?brokerlist='tcp://localhost:5672'";
+
+ public void testConnectionURLString()
+ {
+ AMQConnectionFactory factory = new AMQConnectionFactory();
+
+ assertNull("ConnectionURL should have no value at start",
+ factory.getConnectionURL());
+
+ try
+ {
+ factory.setConnectionURLString(URL);
+ }
+ catch (URLSyntaxException e)
+ {
+ fail(e.getMessage());
+ }
+
+ //URL will be returned with the password field swapped for '********'
+ assertEquals("Connection URL not correctly set", URL_STAR_PWD, factory.getConnectionURLString());
+
+ // Further test that the processed ConnectionURL is as expected after
+ // the set call
+ ConnectionURL connectionurl = factory.getConnectionURL();
+
+ assertNull("Failover is set.", connectionurl.getFailoverMethod());
+ assertEquals("guest", connectionurl.getUsername());
+ assertEquals("guest", connectionurl.getPassword());
+ assertEquals("clientID", connectionurl.getClientName());
+ assertEquals("/test", connectionurl.getVirtualHost());
+
+ assertEquals(1, connectionurl.getBrokerCount());
+
+ BrokerDetails service = connectionurl.getBrokerDetails(0);
+
+ assertEquals("tcp", service.getTransport());
+ assertEquals("localhost", service.getHost());
+ assertEquals(5672, service.getPort());
+
+ }
+}
diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/jndi/JNDIPropertyFileTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/jndi/JNDIPropertyFileTest.java
new file mode 100644
index 0000000000..a1b14d5723
--- /dev/null
+++ b/java/client/src/test/java/org/apache/qpid/test/unit/jndi/JNDIPropertyFileTest.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.test.unit.jndi;
+
+import java.util.Properties;
+
+import javax.jms.Queue;
+import javax.jms.Topic;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.framing.AMQShortString;
+
+import junit.framework.TestCase;
+
+public class JNDIPropertyFileTest extends TestCase
+{
+ Context ctx;
+
+ public JNDIPropertyFileTest() throws Exception
+ {
+ Properties properties = new Properties();
+ properties.load(this.getClass().getResourceAsStream("JNDITest.properties"));
+
+ //Create the initial context
+ ctx = new InitialContext(properties);
+ }
+
+ public void testQueueNamesWithTrailingSpaces() throws Exception
+ {
+ Queue queue = (Queue)ctx.lookup("QueueNameWithSpace");
+ assertEquals("QueueNameWithSpace",queue.getQueueName());
+ }
+
+ public void testTopicNamesWithTrailingSpaces() throws Exception
+ {
+ Topic topic = (Topic)ctx.lookup("TopicNameWithSpace");
+ assertEquals("TopicNameWithSpace",topic.getTopicName());
+ }
+
+ public void testMultipleTopicNamesWithTrailingSpaces() throws Exception
+ {
+ Topic topic = (Topic)ctx.lookup("MultipleTopicNamesWithSpace");
+ int i = 0;
+ for (AMQShortString bindingKey: ((AMQDestination)topic).getBindingKeys())
+ {
+ i++;
+ assertEquals("Topic" + i + "WithSpace",bindingKey.asString());
+ }
+ }
+}
diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/jndi/JNDITest.properties b/java/client/src/test/java/org/apache/qpid/test/unit/jndi/JNDITest.properties
new file mode 100644
index 0000000000..07017a05a6
--- /dev/null
+++ b/java/client/src/test/java/org/apache/qpid/test/unit/jndi/JNDITest.properties
@@ -0,0 +1,28 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+java.naming.factory.initial = org.apache.qpid.jndi.PropertiesFileInitialContextFactory
+
+# Queue name with spaces
+queue.QueueNameWithSpace = QueueNameWithSpace
+
+# Topic name with spaces
+topic.TopicNameWithSpace = TopicNameWithSpace
+
+# Multiple topic names with spaces
+topic.MultipleTopicNamesWithSpace = Topic1WithSpace , Topic2WithSpace , Topic3WithSpace
diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/message/TestAMQSession.java b/java/client/src/test/java/org/apache/qpid/test/unit/message/TestAMQSession.java
index a881f6a822..566a222897 100644
--- a/java/client/src/test/java/org/apache/qpid/test/unit/message/TestAMQSession.java
+++ b/java/client/src/test/java/org/apache/qpid/test/unit/message/TestAMQSession.java
@@ -44,7 +44,9 @@ public class TestAMQSession extends AMQSession<BasicMessageConsumer_0_8, BasicMe
}
- public void sendQueueBind(AMQShortString queueName, AMQShortString routingKey, FieldTable arguments, AMQShortString exchangeName, AMQDestination destination) throws AMQException, FailoverException
+ public void sendQueueBind(AMQShortString queueName, AMQShortString routingKey, FieldTable arguments,
+ AMQShortString exchangeName, AMQDestination destination,
+ boolean nowait) throws AMQException, FailoverException
{
}
@@ -129,7 +131,8 @@ public class TestAMQSession extends AMQSession<BasicMessageConsumer_0_8, BasicMe
}
- public void sendQueueDeclare(AMQDestination amqd, AMQProtocolHandler protocolHandler) throws AMQException, FailoverException
+ public void sendQueueDeclare(AMQDestination amqd, AMQProtocolHandler protocolHandler,
+ boolean nowait) throws AMQException, FailoverException
{
}
diff --git a/java/common.xml b/java/common.xml
index 8606a24edb..578daf359a 100644
--- a/java/common.xml
+++ b/java/common.xml
@@ -23,10 +23,13 @@
<dirname property="project.root" file="${ant.file.common}"/>
<property name="project.name" value="qpid"/>
- <property name="project.version" value="incubating-M3"/>
+ <property name="project.version" value="0.6"/>
<property name="project.namever" value="${project.name}-${project.version}"/>
+ <property name="resources" location="${project.root}/resources"/>
+ <property name="test.profiles" location="${project.root}/test-profiles"/>
<property name="build" location="${project.root}/build"/>
+ <property name="build.scratch" location="${build}/scratch"/>
<property name="build.bin" location="${build}/bin"/>
<property name="build.etc" location="${build}/etc"/>
<property name="build.lib" location="${build}/lib"/>
@@ -35,8 +38,9 @@
<property name="build.report" location="${build}/report"/>
<property name="build.release" location="${build}/release"/>
<property name="build.release.prepare" location="${build.release}/prepare"/>
- <property name="build.data" location="${build}/data"/>
+ <property name="build.data" location="${build.scratch}/data"/>
<property name="build.plugins" location="${build}/lib/plugins"/>
+ <property name="build.coveragereport" location="${build}/coverage"/>
<property name="java.target" value="1.5"/>
<property name="java.source" value="1.5"/>
@@ -47,8 +51,21 @@
<property name="tasks.classes" location="${tasks}/classes"/>
<property name="tasks.src" location="${tasks}/src"/>
+ <property name="qpid.home" location="${project.root}/build"/>
+ <property name="qpid.work" location="${qpid.home}/work"/>
+
<property name="javac.compiler.args" value=""/>
+ <property name="cobertura.dir" value="${project.root}/lib/cobertura" />
+ <property name="mllib.dir" value="${project.root}/../python" />
+
+ <path id="cobertura.classpath">
+ <fileset dir="${cobertura.dir}">
+ <include name="cobertura.jar" />
+ <include name="lib/**/*.jar" />
+ </fileset>
+ </path>
+
<macrodef name="indirect">
<attribute name="name"/>
<attribute name="variable"/>
@@ -76,6 +93,17 @@
</sequential>
</macrodef>
+ <macrodef name="jython">
+ <attribute name="path"/>
+ <element name="args"/>
+ <sequential>
+ <java jar="${project.root}/lib/jython-2.5.0.jar" fork="true" failonerror="true">
+ <arg value="-Dpython.path=@{path}"/>
+ <args/>
+ </java>
+ </sequential>
+ </macrodef>
+
<mkdir dir="${tasks.classes}"/>
<javac source="${java.source}" target="${java.target}" srcdir="${tasks.src}" destdir="${tasks.classes}" classpath="${java.class.path}">
<compilerarg line="${javac.compiler.args}"/>
@@ -86,6 +114,19 @@
<taskdef name="foreach" classname="org.apache.qpid.tasks.Foreach"
classpath="${tasks.classes}"/>
+ <macrodef name="copylist">
+ <attribute name="todir"/>
+ <attribute name="dir"/>
+ <attribute name="files"/>
+ <sequential>
+ <foreach property="file" list="@{files}">
+ <copy todir="@{todir}" flatten="true">
+ <fileset dir="@{dir}" includes="${file}"/>
+ </copy>
+ </foreach>
+ </sequential>
+ </macrodef>
+
<target name="clean-tasks">
<delete dir="${tasks.classes}"/>
</target>
@@ -105,6 +146,10 @@
</junitreport>
</target>
+ <target name="cobertura-init">
+ <taskdef classpathref="cobertura.classpath" resource="tasks.properties" />
+ </target>
+
<target name="help" description="display detailed build documentation">
<echo>
ant build
@@ -201,6 +246,15 @@
${release}
+ ant release-bin
+
+ The release-bin target generates binary distribution archives for
+ modules that have a specific binary package configured.
+ To enable for other modules create a target "release-bin" that
+ depends on target "release-bin-tasks". The output is placed in:
+
+ ${module.release}
+
ant clean
The clean target removes build artifacts. When invoked from the
@@ -210,6 +264,8 @@
${build}
and
${release}
+ and
+ ${module.release}
When invoked from a specific module, the clean target will delete
that modules build root from underneath the project build root:
diff --git a/java/common/Composite.tpl b/java/common/Composite.tpl
index 4aed9b0432..97b7d01f3c 100644
--- a/java/common/Composite.tpl
+++ b/java/common/Composite.tpl
@@ -1,4 +1,25 @@
-package $(pkg);
+package org.apache.qpid.transport;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import java.nio.ByteBuffer;
import java.util.ArrayList;
@@ -7,17 +28,15 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
-import org.apache.qpid.transport.Future;
-import org.apache.qpid.transport.Method;
-import org.apache.qpid.transport.RangeSet;
-import org.apache.qpid.transport.Struct;
-
import org.apache.qpid.transport.codec.Decoder;
import org.apache.qpid.transport.codec.Encodable;
import org.apache.qpid.transport.codec.Encoder;
import org.apache.qpid.transport.network.Frame;
+import org.apache.qpid.util.Strings;
+
+
${
from genutil import *
@@ -73,7 +92,7 @@ public final class $name extends $base {
return $pack;
}
- public final boolean hasPayloadSegment() {
+ public final boolean hasPayload() {
return $payload;
}
@@ -108,7 +127,12 @@ if fields:
${
for f in fields:
if f.option: continue
- out(" $(f.set)($(f.name));\n")
+ if f.ref_type != f.type:
+ out(" $(f.set)($(f.name));\n")
+ else:
+ out(" if($(f.name) != null) {\n")
+ out(" $(f.set)($(f.name));\n")
+ out(" }\n")
if segments:
out(" setHeader(header);\n")
@@ -126,6 +150,7 @@ if options or base == "Method":
if base == "Method":
out(""" case SYNC: this.setSync(true); break;
case BATCH: this.setBatch(true); break;
+ case UNRELIABLE: this.setUnreliable(true); break;
""")
out(""" case NONE: break;
default: throw new IllegalArgumentException("invalid option: " + _options[i]);
@@ -135,9 +160,13 @@ if options or base == "Method":
}
}
- public final <C> void dispatch(C context, MethodDelegate<C> delegate) {
+${
+
+if base == "Method":
+ out(""" public <C> void dispatch(C context, MethodDelegate<C> delegate) {
delegate.$(dromedary(name))(context, this);
- }
+ }""")
+}
${
for f in fields:
@@ -175,7 +204,13 @@ if not f.empty:
}
${
if pack > 0:
- out(" packing_flags |= $(f.flag_mask(pack));")
+ if f.empty:
+ out(" if (value)\\n")
+ out(" packing_flags |= $(f.flag_mask(pack));\\n")
+ out(" else\\n")
+ out(" packing_flags &= ~$(f.flag_mask(pack));")
+ else:
+ out(" packing_flags |= $(f.flag_mask(pack));")
}
this.dirty = true;
return this;
@@ -222,6 +257,26 @@ if segments:
setBody(body);
return this;
}
+
+ public final byte[] getBodyBytes() {
+ ByteBuffer buf = getBody();
+ byte[] bytes = new byte[buf.remaining()];
+ buf.get(bytes);
+ return bytes;
+ }
+
+ public final void setBody(byte[] body)
+ {
+ setBody(ByteBuffer.wrap(body));
+ }
+
+ public final String getBodyString() {
+ return Strings.fromUTF8(getBodyBytes());
+ }
+
+ public final void setBody(String body) {
+ setBody(Strings.toUTF8(body));
+ }
""")
}
diff --git a/java/common/Constant.tpl b/java/common/Constant.tpl
index 9f64cc657c..da4233c847 100644
--- a/java/common/Constant.tpl
+++ b/java/common/Constant.tpl
@@ -1,4 +1,25 @@
-package $(pkg);
+package org.apache.qpid.transport;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
${from genutil import *}
diff --git a/java/common/Enum.tpl b/java/common/Enum.tpl
index 7ff451997a..0835d34a20 100644
--- a/java/common/Enum.tpl
+++ b/java/common/Enum.tpl
@@ -1,4 +1,25 @@
-package $(pkg);
+package org.apache.qpid.transport;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
public enum $name {
${
diff --git a/java/common/Invoker.tpl b/java/common/Invoker.tpl
index 43aaced780..2eed43ad28 100644
--- a/java/common/Invoker.tpl
+++ b/java/common/Invoker.tpl
@@ -1,23 +1,37 @@
-package $(pkg);
+package org.apache.qpid.transport;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Map;
import java.util.UUID;
-import org.apache.qpid.transport.Future;
-import org.apache.qpid.transport.Method;
-import org.apache.qpid.transport.RangeSet;
-import org.apache.qpid.transport.Struct;
-
-public abstract class Invoker {
-
- protected abstract void invoke(Method method);
- protected abstract <T> Future<T> invoke(Method method, Class<T> resultClass);
-
+public abstract class $(invoker) {
${
from genutil import *
+results = False
+
for c in composites:
name = cname(c)
fields = get_fields(c)
@@ -25,6 +39,7 @@ for c in composites:
args = get_arguments(c, fields)
result = c["result"]
if result:
+ results = True
if not result["@type"]:
rname = cname(result["struct"])
else:
@@ -37,11 +52,22 @@ for c in composites:
jreturn = ""
jclass = ""
+ if c.name == "command":
+ access = "public "
+ else:
+ access = ""
+
out("""
- public final $jresult $(dromedary(name))($(", ".join(params))) {
+ $(access)final $jresult $(dromedary(name))($(", ".join(params))) {
$(jreturn)invoke(new $name($(", ".join(args)))$jclass);
}
""")
}
-
+ protected abstract void invoke(Method method);
+${
+if results:
+ out("""
+ protected abstract <T> Future<T> invoke(Method method, Class<T> resultClass);
+""")
+}
}
diff --git a/java/common/MethodDelegate.tpl b/java/common/MethodDelegate.tpl
index d2491dcf3a..27e20a7ef2 100644
--- a/java/common/MethodDelegate.tpl
+++ b/java/common/MethodDelegate.tpl
@@ -1,12 +1,37 @@
-package $(pkg);
+package org.apache.qpid.transport;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
public abstract class MethodDelegate<C> {
+ public abstract void handle(C context, Method method);
${
from genutil import *
for c in composites:
name = cname(c)
- out(" public void $(dromedary(name))(C context, $name struct) {}\n")
+ out("""
+ public void $(dromedary(name))(C context, $name method) {
+ handle(context, method);
+ }""")
}
}
diff --git a/java/common/Option.tpl b/java/common/Option.tpl
index c1e8dcbe22..c22b35b999 100644
--- a/java/common/Option.tpl
+++ b/java/common/Option.tpl
@@ -1,24 +1,42 @@
-package $(pkg);
+package org.apache.qpid.transport;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
public enum Option {
${
from genutil import *
-names = ["NONE", "SYNC", "BATCH"]
+options = {}
+
for c in composites:
for f in c.query["field"]:
t = resolve_type(f)
if t["@name"] == "bit":
- names.append(scream(f["@name"]))
-
-options = {}
-
-for option in names:
- if not options.has_key(option):
- if options:
- out(",\n ")
- options[option] = None
- out("$option")
-}
+ option = scream(f["@name"])
+ if not options.has_key(option):
+ options[option] = None
+ out(" $option,\n")}
+ BATCH,
+ UNRELIABLE,
+ NONE
}
diff --git a/java/common/StructFactory.tpl b/java/common/StructFactory.tpl
index 533005d561..09c669f74e 100644
--- a/java/common/StructFactory.tpl
+++ b/java/common/StructFactory.tpl
@@ -1,6 +1,25 @@
-package $(pkg);
+package org.apache.qpid.transport;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
-import org.apache.qpid.transport.Struct;
class StructFactory {
diff --git a/java/common/Type.tpl b/java/common/Type.tpl
index 818a53ffcf..7f9cfee268 100644
--- a/java/common/Type.tpl
+++ b/java/common/Type.tpl
@@ -1,4 +1,25 @@
-package $(pkg);
+package org.apache.qpid.transport;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
${from genutil import *}
diff --git a/java/common/bin/qpid-run b/java/common/bin/qpid-run
index 1de0048f48..63bb648fd8 100755
--- a/java/common/bin/qpid-run
+++ b/java/common/bin/qpid-run
@@ -56,6 +56,12 @@ if [ -z $AMQJ_LOGGING_LEVEL ]; then
export AMQJ_LOGGING_LEVEL=info
fi
+#Set to help us get round the manifold problems of ps/pgrep on various
+#platforms which gather up to prevent qpid_stop from working .....
+if [ -z "$QPID_PNAME" ]; then
+ export QPID_PNAME=" -DPNAME=QPBRKR"
+fi
+
if [ -z "$QPID_HOME" ]; then
export QPID_HOME=$(dirname $(dirname $(readlink -f $0)))
export PATH=${PATH}:${QPID_HOME}/bin
@@ -105,6 +111,7 @@ if [ -n "$QPID_LOG_SUFFIX" ]; then
fi
log $INFO System Properties set to $SYSTEM_PROPS
+log $INFO QPID_OPTS set to $QPID_OPTS
program=$(basename $0)
sourced=${BASH_SOURCE[0]}
@@ -253,6 +260,6 @@ if $cygwin; then
JAVA=$(cygpath -u $JAVA)
fi
-COMMAND=($JAVA $JAVA_VM $JAVA_GC $JAVA_MEM $SYSTEM_PROPS $JAVA_OPTS $QPID_OPTS "${JAVA_ARGS[@]}")
+COMMAND=($JAVA $JAVA_VM $QPID_PNAME $JAVA_GC $JAVA_MEM $SYSTEM_PROPS $JAVA_OPTS $QPID_OPTS "${JAVA_ARGS[@]}")
DISPATCH
diff --git a/java/common/build.xml b/java/common/build.xml
index 13c500b24e..44cc19aa07 100644
--- a/java/common/build.xml
+++ b/java/common/build.xml
@@ -20,18 +20,18 @@
-->
<project name="AMQ Common" default="build">
+ <property name="module.genpom" value="true"/>
+
<import file="../module.xml"/>
<property name="gentools.home" location="${project.root}/../gentools" />
<property name="generated.package" value="org/apache/qpid/framing" />
<property name="generated.dir" location="${module.precompiled}/${generated.package}" />
<property name="xml.spec.dir" location="${project.root}/../specs" />
- <property name="xml.spec.deps" value="amqp.0-8.xml amqp.0-9.xml" />
- <property name="xml.spec.list" value="${xml.spec.dir}/amqp.0-8.xml ${xml.spec.dir}/amqp.0-9.xml" />
- <property name="mllib.dir" value="${project.root}/../python" />
+ <property name="xml.spec.deps" value="amqp.0-8.xml amqp.0-9.xml amqp0-9-1.stripped.xml" />
+ <property name="xml.spec.list" value="${xml.spec.dir}/amqp.0-8.xml ${xml.spec.dir}/amqp.0-9.xml ${xml.spec.dir}/amqp0-9-1.stripped.xml" />
<property name="gentools.timestamp" location="${generated.dir}/gentools.timestamp" />
- <property name="jython.timestamp" location="${module.precompiled}/jython.timestamp" />
- <property name="jython_1_0.timestamp" location="${module.precompiled}/jython_1_0.timestamp" />
+ <property name="jython.timestamp" location="${generated.dir}/jython.timestamp" />
<target name="check_jython_deps">
<uptodate property="jython.notRequired" targetfile="${jython.timestamp}">
@@ -40,43 +40,17 @@
</target>
<target name="jython" depends="check_jython_deps" unless="jython.notRequired">
- <java classname="org.python.util.jython" fork="true" failonerror="true">
- <arg value="-Dpython.cachedir.skip=true"/>
- <arg value="-Dpython.path=${basedir}/jython-lib.jar/Lib${path.separator}${mllib.dir}"/>
- <arg value="${basedir}/codegen"/>
- <arg value="${module.precompiled}"/>
- <arg value="${xml.spec.dir}/amqp.0-10-qpid-errata.xml"/>
- <arg value="${basedir}"/>
- <arg value="org/apache/qpid/transport"/>
- <classpath>
- <pathelement location="jython-2.2-rc2.jar"/>
- </classpath>
- </java>
+ <jython path="${mllib.dir}">
+ <args>
+ <arg value="${basedir}/codegen"/>
+ <arg value="${module.precompiled}"/>
+ <arg value="${xml.spec.dir}/amqp.0-10-qpid-errata.xml"/>
+ <arg value="${basedir}"/>
+ </args>
+ </jython>
<touch file="${jython.timestamp}" />
</target>
- <target name="check_jython_deps_1_0">
- <uptodate property="jython.notRequired_1_0" targetfile="${jython_1_0.timestamp}">
- <srcfiles dir="${xml.spec.dir}" includes="amqp.1-0-draft.xml" />
- </uptodate>
- </target>
-
- <target name="jython_1_0" depends="check_jython_deps_1_0" unless="jython.notRequired_1_0">
- <java classname="org.python.util.jython" fork="true" failonerror="true">
- <arg value="-Dpython.cachedir.skip=true"/>
- <arg value="-Dpython.path=${basedir}/jython-lib.jar/Lib${path.separator}${mllib.dir}"/>
- <arg value="${basedir}/codegen"/>
- <arg value="${module.precompiled}"/>
- <arg value="${xml.spec.dir}/amqp.1-0-draft.xml"/>
- <arg value="${basedir}"/>
- <arg value="org/apache/qpid/transport/v1_0"/>
- <classpath>
- <pathelement location="jython-2.2-rc2.jar"/>
- </classpath>
- </java>
- <touch file="${jython_1_0.timestamp}" />
- </target>
-
<target name="compile_gentools">
<ant dir="${gentools.home}" />
</target>
@@ -103,30 +77,7 @@
<touch file="${gentools.timestamp}" />
</target>
- <property name="version.file" location="${module.classes}/qpidversion.properties"/>
- <property file="${version.file}" prefix="old."/>
-
- <target name="check-version">
- <exec executable="svnversion" spawn="false" failifexecutionfails="false"
- dir="${project.root}" outputproperty="qpid.svnversion">
- <arg line="."/>
- </exec>
- <condition property="version.stale">
- <not>
- <equals arg1="${qpid.svnversion}" arg2="${old.qpid.svnversion}"/>
- </not>
- </condition>
- </target>
-
- <target name="version" depends="check-version" if="version.stale">
- <!-- Write the version.properties out. -->
- <echo file="${version.file}" append="true">
- qpid.svnversion=${qpid.svnversion}
- qpid.name=${project.name}
- qpid.version=${project.version}
- </echo>
- </target>
-
- <target name="precompile" depends="gentools,jython,jython_1_0,version"/>
+ <target name="precompile" depends="gentools,jython,create-version"/>
+ <target name="bundle" depends="bundle-tasks"/>
</project>
diff --git a/java/common/codegen b/java/common/codegen
index 07c5e5c6fb..6a1effc07b 100755
--- a/java/common/codegen
+++ b/java/common/codegen
@@ -1,5 +1,24 @@
#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
import os, sys, mllib
from templating import Parser
from genutil import *
@@ -7,9 +26,7 @@ from genutil import *
out_dir = sys.argv[1]
spec_file = sys.argv[2]
tpl_dir = sys.argv[3]
-pkg_rel = sys.argv[4]
-pkg_dir = os.path.join(out_dir, pkg_rel)
-pkg = pkg_rel.replace("/", ".")
+pkg_dir = os.path.join(out_dir, "org/apache/qpid/transport")
if not os.path.exists(pkg_dir):
os.makedirs(pkg_dir)
@@ -35,8 +52,8 @@ def execute(output, template, **kwargs):
f.write(p.output)
f.close()
-execute("Type.java", "Type.tpl", spec = spec, pkg = pkg)
-execute("Constant.java", "Constant.tpl", spec = spec, pkg = pkg)
+execute("Type.java", "Type.tpl", spec = spec)
+execute("Constant.java", "Constant.tpl", spec = spec)
structs = spec.query["amqp/struct"] + \
spec.query["amqp/class/struct", excludes] + \
@@ -45,15 +62,21 @@ controls = spec.query["amqp/class/control", excludes]
commands = spec.query["amqp/class/command", excludes]
composites = structs + controls + commands
+actions = controls + commands
+connection = [c for c in actions if c.parent["@name"] == "connection"]
+session = [c for c in actions if c.parent["@name"] != "connection"]
for c in composites:
name = cname(c)
- execute("%s.java" % name, "Composite.tpl", type = c, name = name, pkg = pkg)
+ execute("%s.java" % name, "Composite.tpl", type = c, name = name)
-execute("MethodDelegate.java", "MethodDelegate.tpl", composites = composites, pkg = pkg)
-execute("Option.java", "Option.tpl", composites = composites, pkg = pkg)
-execute("Invoker.java", "Invoker.tpl", composites = controls + commands, pkg = pkg)
-execute("StructFactory.java", "StructFactory.tpl", composites = composites, pkg = pkg)
+execute("MethodDelegate.java", "MethodDelegate.tpl", composites = actions)
+execute("Option.java", "Option.tpl", composites = composites)
+execute("ConnectionInvoker.java", "Invoker.tpl", invoker = "ConnectionInvoker",
+ composites = connection)
+execute("SessionInvoker.java", "Invoker.tpl", invoker = "SessionInvoker",
+ composites = session)
+execute("StructFactory.java", "StructFactory.tpl", composites = composites)
def is_enum(nd):
return nd["enum"] is not None
@@ -63,4 +86,4 @@ enums = spec.query["amqp/domain", is_enum] + \
for e in enums:
name = cname(e)
- execute("%s.java" % name, "Enum.tpl", name = name, type = e, pkg = pkg)
+ execute("%s.java" % name, "Enum.tpl", name = name, type = e)
diff --git a/java/common/genutil.py b/java/common/genutil.py
index f8f234548c..57a461ed40 100644
--- a/java/common/genutil.py
+++ b/java/common/genutil.py
@@ -1,3 +1,21 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
def camel(offset, *args):
parts = []
@@ -180,6 +198,7 @@ class Field:
self.read = "dec.read%s()" % self.coder
self.write = "enc.write%s(check(struct).%s)" % (self.coder, self.name)
self.type = jtype(self.type_node)
+ self.ref_type = jref(self.type)
self.default = DEFAULTS.get(self.type, "null")
self.has = camel(1, "has", self.name)
self.get = camel(1, "get", self.name)
diff --git a/java/common/jython-2.2-rc2.jar b/java/common/jython-2.2-rc2.jar
deleted file mode 100644
index e25e2cb945..0000000000
--- a/java/common/jython-2.2-rc2.jar
+++ /dev/null
Binary files differ
diff --git a/java/common/jython-lib.jar b/java/common/jython-lib.jar
deleted file mode 100644
index bb3ba82db5..0000000000
--- a/java/common/jython-lib.jar
+++ /dev/null
Binary files differ
diff --git a/java/common/pom.xml b/java/common/pom.xml
deleted file mode 100644
index 894ca26710..0000000000
--- a/java/common/pom.xml
+++ /dev/null
@@ -1,187 +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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-common</artifactId>
- <packaging>jar</packaging>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <name>Qpid Common Utilities</name>
- <url>http://cwiki.apache.org/confluence/display/qpid</url>
-
- <parent>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid</artifactId>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <relativePath>../pom.xml</relativePath>
- </parent>
-
- <properties>
- <topDirectoryLocation>..</topDirectoryLocation>
- <gentools.home>${topDirectoryLocation}/../gentools</gentools.home>
- <generated.path>${project.build.directory}/generated-sources/gentools</generated.path>
- <generated.package>org/apache/qpid/framing</generated.package>
- <generated.dir>${generated.path}/${generated.package}</generated.dir>
- <generated.timestamp>${generated.dir}/timestamp</generated.timestamp>
- <specs.dir>${basedir}/../../specs</specs.dir>
- <mllib.dir>${basedir}/../../python</mllib.dir>
- </properties>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-antrun-plugin</artifactId>
- <executions>
- <execution>
- <id>protocol-version</id>
- <phase>generate-sources</phase>
- <configuration>
- <tasks>
- <echo>"${generated.path}"</echo>
- <ant antfile="protocol-version.xml" />
-<!-- <exec executable="python">
- <arg line="generate"/>
- <arg line="${generated.path}"/>
- <arg line="org.apache.qpid"/>
- <arg line="${specs.dir}/amqp-transitional.0-10.xml"/>
- </exec> -->
- </tasks>
- <sourceRoot>${generated.path}</sourceRoot>
- </configuration>
- <goals>
- <goal>run</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
-
- <plugin>
- <groupId>org.apache.qpid</groupId>
- <artifactId>jython-plugin</artifactId>
- <executions>
- <execution>
- <id>jython</id>
- <phase>generate-sources</phase>
- <configuration>
- <params>
- <param>-Dpython.cachedir.skip=true</param>
- <param>-Dpython.path=${basedir}/jython-lib.jar/Lib${path.separator}${mllib.dir}</param>
- <param>${basedir}/codegen</param>
- <param>${generated.path}</param>
- <param>${specs.dir}/amqp.0-10-qpid-errata.xml</param>
- <param>${basedir}</param>
- </params>
- <sources>
- <source>${specs.dir}/amqp.0-10-qpid-errata.xml</source>
- <source>${basedir}/codegen</source>
- </sources>
- <timestamp>${generated.path}/generated.timestamp</timestamp>
- </configuration>
- <goals>
- <goal>jython</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
-
-
-
- <!-- Backports the module to Java 1.4. This is done during the packaging phase as a transformation of the Jar. -->
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>retrotranslator-maven-plugin</artifactId>
- <executions>
- <execution>
- <id>retro-common</id>
- <goals>
- <goal>translate-project</goal>
- </goals>
- <configuration>
- <destjar>${project.build.directory}/${project.build.finalName}-java14.jar</destjar>
- <verify>${retrotranslator.verify}</verify>
- <verifyClasspath>
- <element>${retrotranslator.1.4-rt-path}</element>
- <element>${retrotranslator.1.4-jce-path}</element>
- <element>${retrotranslator.1.4-jsse-path}</element>
- <element>${retrotranslator.1.4-sasl-path}</element>
- </verifyClasspath>
- <failonwarning>false</failonwarning>
- <classifier>java14</classifier>
- <attach>true</attach>
- </configuration>
- </execution>
-
- </executions>
- </plugin>
-
- </plugins>
- </build>
-
- <dependencies>
-
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <version>1.4.0</version>
- </dependency>
-
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.4.0</version>
- <scope>test</scope>
- </dependency>
-<!--
- <dependency>
- <groupId>org.apache.mina</groupId>
- <artifactId>mina-java5</artifactId>
- </dependency>
--->
- <dependency>
- <groupId>org.apache.mina</groupId>
- <artifactId>mina-filter-ssl</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.apache.mina</groupId>
- <artifactId>mina-core</artifactId>
- </dependency>
-
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>test</scope>
- </dependency>
-
- <!-- This needs to be included at compile time, for the retrotranslator verification to find it. -->
- <dependency>
- <groupId>net.sf.retrotranslator</groupId>
- <artifactId>retrotranslator-runtime</artifactId>
- <scope>provided</scope>
- </dependency>
- <!--- This is used by filter -->
- <dependency>
- <groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-jms_1.1_spec</artifactId>
- </dependency>
- </dependencies>
-</project>
diff --git a/java/common/protocol-version.xml b/java/common/protocol-version.xml
index ee9db6049b..5435a0a582 100644
--- a/java/common/protocol-version.xml
+++ b/java/common/protocol-version.xml
@@ -27,8 +27,8 @@
<property name="generated.dir" location="${generated.path}/${generated.package}" />
<property name="generated.timestamp" location="${generated.dir}/timestamp" />
<property name="xml.spec.dir" location="${topDirectoryLocation}/../specs" />
- <property name="xml.spec.deps" value="amqp.0-8.xml amqp.0-9.xml" />
- <property name="xml.spec.list" value="${xml.spec.dir}/amqp.0-8.xml ${xml.spec.dir}/amqp.0-9.xml" />
+ <property name="xml.spec.deps" value="amqp.0-8.xml amqp.0-9.xml amqp0-9-1.stripped.xml" />
+ <property name="xml.spec.list" value="${xml.spec.dir}/amqp.0-8.xml ${xml.spec.dir}/amqp.0-9.xml ${xml.spec.dir}/amqp0-9-1.stripped.xml" />
<property name="template.dir" value="${topDirectoryLocation}/common/templates" />
diff --git a/java/common/src/main/java/common.bnd b/java/common/src/main/java/common.bnd
new file mode 100755
index 0000000000..120a2401d3
--- /dev/null
+++ b/java/common/src/main/java/common.bnd
@@ -0,0 +1,6 @@
+ver: 0.6.0
+
+Bundle-SymbolicName: qpid-common
+Bundle-Version: ${ver}
+Export-Package: *;version=${ver}
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
diff --git a/java/common/src/main/java/org/apache/qpid/AMQConnectionException.java b/java/common/src/main/java/org/apache/qpid/AMQConnectionException.java
index afd415b1eb..8ef6facef1 100644
--- a/java/common/src/main/java/org/apache/qpid/AMQConnectionException.java
+++ b/java/common/src/main/java/org/apache/qpid/AMQConnectionException.java
@@ -60,7 +60,7 @@ public class AMQConnectionException extends AMQException
public AMQFrame getCloseFrame(int channel)
{
MethodRegistry reg = MethodRegistry.getMethodRegistry(new ProtocolVersion(major,minor));
- return new AMQFrame(channel,
+ return new AMQFrame(0,
reg.createConnectionCloseBody(getErrorCode().getCode(),
new AMQShortString(getMessage()),
_classId,
diff --git a/java/common/src/main/java/org/apache/qpid/AMQException.java b/java/common/src/main/java/org/apache/qpid/AMQException.java
index eda532b64e..be335c5dba 100644
--- a/java/common/src/main/java/org/apache/qpid/AMQException.java
+++ b/java/common/src/main/java/org/apache/qpid/AMQException.java
@@ -90,4 +90,33 @@ public class AMQException extends Exception
{
return true;
}
+
+ /**
+ * Rethrown this exception as a new exception.
+ *
+ * Attempt to create a new exception of the same class if they hav the default constructor of:
+ * {AMQConstant.class, String.class, Throwable.class}
+ *
+ * Individual subclasses may override as requried to create a new instance.
+ *
+ */
+ public AMQException cloneForCurrentThread()
+ {
+ Class amqeClass = this.getClass();
+ Class<?>[] paramClasses = {AMQConstant.class, String.class, Throwable.class};
+ Object[] params = {getErrorCode(), getMessage(), this};
+
+ AMQException newAMQE;
+
+ try
+ {
+ newAMQE = (AMQException) amqeClass.getConstructor(paramClasses).newInstance(params);
+ }
+ catch (Exception creationException)
+ {
+ newAMQE = new AMQException(getErrorCode(), getMessage(), this);
+ }
+
+ return newAMQE;
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/BrokerDetails.java b/java/common/src/main/java/org/apache/qpid/BrokerDetails.java
deleted file mode 100644
index 63f67a7857..0000000000
--- a/java/common/src/main/java/org/apache/qpid/BrokerDetails.java
+++ /dev/null
@@ -1,138 +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.
- */
-package org.apache.qpid;
-
-import java.util.Map;
-
-/**
- * This interface represents a broker and provides the basic information
- * required for opening a connection with a broker.
- */
-public interface BrokerDetails
-{
- /**
- * Those are the supported protocols
- */
- public static final String PROTOCOL_TCP = "tcp";
- public static final String PROTOCOL_TLS = "tls";
-
- public static final String VIRTUAL_HOST = "virtualhost";
- public static final String CLIENT_ID = "client_id";
- public static final String USERNAME = "username";
- public static final String PASSWORD = "password";
-
- /**
- * Get the broker host name.
- *
- * @return The broker host name.
- */
- public String getHost();
-
- /**
- * Get the broker port number.
- *
- * @return The broker port number.
- */
- public int getPort();
-
- /**
- * Get the virtual host to connect to.
- *
- * @return The virtual host of this broker.
- */
- public String getVirtualHost();
-
- /**
- * Get the user name.
- *
- * @return The user name
- */
- public String getUserName();
-
- /**
- * Get the user password
- *
- * @return The user password
- */
- public String getPassword();
-
- /**
- * Get the protocol used to connect to hise broker.
- *
- * @return the protocol used to connect to the broker.
- */
- public String getProtocol();
-
- /**
- * Set the broker host name.
- *
- * @param host The broker host name.
- */
- public void setHost(String host);
-
- /**
- * Set the broker port number.
- *
- * @param port The broker port number.
- */
- public void setPort(int port);
-
- /**
- * Set the virtual host to connect to.
- *
- * @param virtualHost The virtual host of this broker.
- */
- public void setVirtualHost(String virtualHost);
-
- /**
- * Set the user name.
- *
- * @param userName The user name
- */
- public void setUserName(String userName);
-
- /**
- * Set the user password
- *
- * @param password The user password
- */
- public void setPassword(String password);
-
- /**
- * Set the protocol used to connect to hise broker.
- *
- * @param protocol the protocol used to connect to the broker.
- */
- public void setProtocol(String protocol);
-
- /**
- * Ex: keystore path
- *
- * @return the Properties associated with this connection.
- */
- public Map<String,String> getProperties();
-
- /**
- * Sets the properties associated with this connection
- *
- * @param props the new p[roperties.
- */
- public void setProperties(Map<String,String> props);
-
- public void setProperty(String key,String value);
-}
diff --git a/java/common/src/main/java/org/apache/qpid/BrokerDetailsImpl.java b/java/common/src/main/java/org/apache/qpid/BrokerDetailsImpl.java
deleted file mode 100644
index 201d43e21f..0000000000
--- a/java/common/src/main/java/org/apache/qpid/BrokerDetailsImpl.java
+++ /dev/null
@@ -1,264 +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.
- */
-package org.apache.qpid;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Implements the interface BrokerDetails
- */
-public class BrokerDetailsImpl implements BrokerDetails
-{
- //--- Those are the default values
- private final String DEFAULT_USERNAME = "guest";
- private final String DEFAULT_PASSWORD = "guest";
- private final String DEFAULT_VIRTUALHOST = "";
-
- //---- The brker details
- private String _host;
- private int _port = 0;
- private String _virtualHost;
- private String _userName = DEFAULT_USERNAME;
- private String _password = DEFAULT_PASSWORD;
- private String _protocol;
- private Map<String, String> _props = new HashMap<String, String>();
- ;
-
- //--- Constructors
-
- public BrokerDetailsImpl()
- {
- }
-
- /**
- * Create a new broker details given all the reuqired information
- *
- * @param protocol The protocol used for this broker connection
- * @param host The host name.
- * @param port The port number.
- * @param virtualHost The virtual host.
- * @param userName The user name.
- * @param password The user password.
- */
- public BrokerDetailsImpl(String protocol, String host, int port, String virtualHost, String userName,
- String password, Map<String, String> props)
- {
- _protocol = protocol;
- _host = host;
- _port = port;
- _virtualHost = virtualHost;
- _userName = userName;
- _password = password;
- _props = props;
- }
-
- /**
- * Create a new broker details given the host name and the procol type,
- * default values are used for the other details.
- *
- * @param protocol The protocol used for this broker connection
- * @param host The host name.
- */
- public BrokerDetailsImpl(String protocol, String host)
- {
- _protocol = protocol;
- _host = host;
- _virtualHost = DEFAULT_VIRTUALHOST;
- _userName = DEFAULT_USERNAME;
- _password = DEFAULT_PASSWORD;
- }
-
- //--- API BrokerDetails
- /**
- * Get the user password
- *
- * @return The user password
- */
- public String getPassword()
- {
- return _password;
- }
-
- /**
- * Get the broker host name.
- *
- * @return The broker host name.
- */
- public String getHost()
- {
- return _host;
- }
-
- /**
- * Get the broker port number.
- *
- * @return The broker port number.
- */
- public int getPort()
- {
- if (_port == 0)
- {
- if (getProtocol().equals(BrokerDetails.PROTOCOL_TCP))
- {
- _port = 5672;
- }
- else if (getProtocol().equals(BrokerDetails.PROTOCOL_TLS))
- {
- _port = 5555;
- }
- }
- return _port;
- }
-
- /**
- * Get the virtual host to connect to.
- *
- * @return The virtual host of this broker.
- */
- public String getVirtualHost()
- {
- return _virtualHost;
- }
-
- /**
- * Get the user name.
- *
- * @return The user name
- */
- public String getUserName()
- {
- return _userName;
- }
-
- /**
- * Get the protocol used to connect to hise broker.
- *
- * @return the protocol used to connect to the broker.
- */
- public String getProtocol()
- {
- return _protocol;
- }
-
- /**
- * Set the broker host name.
- *
- * @param host The broker host name.
- */
- public void setHost(String host)
- {
- _host = host;
- }
-
- /**
- * Set the broker port number.
- *
- * @param port The broker port number.
- */
- public void setPort(int port)
- {
- _port = port;
- }
-
- /**
- * Set the virtual host to connect to.
- *
- * @param virtualHost The virtual host of this broker.
- */
- public void setVirtualHost(String virtualHost)
- {
- _virtualHost = virtualHost;
- }
-
- /**
- * Set the user name.
- *
- * @param userName The user name
- */
- public void setUserName(String userName)
- {
- _userName = userName;
- }
-
- /**
- * Set the user password
- *
- * @param password The user password
- */
- public void setPassword(String password)
- {
- _password = password;
- }
-
- /**
- * Set the protocol used to connect to hise broker.
- *
- * @param protocol the protocol used to connect to the broker.
- */
- public void setProtocol(String protocol)
- {
- _protocol = protocol;
- }
-
- /**
- * Ex: keystore path
- *
- * @return the Properties associated with this connection.
- */
- public Map<String, String> getProperties()
- {
- return _props;
- }
-
- /**
- * Sets the properties associated with this connection
- *
- * @param props
- */
- public void setProperties(Map<String, String> props)
- {
- _props = props;
- }
-
- public void setProperty(String key, String value)
- {
- _props.put(key, value);
- }
-
- public String toString()
- {
- StringBuilder b = new StringBuilder();
- b.append("[username=" + _userName);
- b.append(",password=" + _password);
- b.append(",transport=" + _protocol);
- b.append(",host=" + _host);
- b.append(",port=" + getPort() + "]");
- b.append(" - Properties[");
- if (_props != null)
- {
- for (String k : _props.keySet())
- {
- b.append(k + "=" + _props.get(k) + ",");
- }
- }
- b.append("]");
-
- return b.toString();
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/ConsoleOutput.java b/java/common/src/main/java/org/apache/qpid/ConsoleOutput.java
index f17782ebf4..7d8a5b7b36 100644
--- a/java/common/src/main/java/org/apache/qpid/ConsoleOutput.java
+++ b/java/common/src/main/java/org/apache/qpid/ConsoleOutput.java
@@ -20,12 +20,12 @@
*/
package org.apache.qpid;
+import static org.apache.qpid.transport.util.Functions.str;
+
import java.nio.ByteBuffer;
import org.apache.qpid.transport.Sender;
-import static org.apache.qpid.transport.util.Functions.*;
-
/**
* ConsoleOutput
@@ -51,4 +51,12 @@ public class ConsoleOutput implements Sender<ByteBuffer>
System.out.println("CLOSED");
}
+ public void setIdleTimeout(long l)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/ErrorCode.java b/java/common/src/main/java/org/apache/qpid/ErrorCode.java
index be1ad16dd5..0549869e71 100644
--- a/java/common/src/main/java/org/apache/qpid/ErrorCode.java
+++ b/java/common/src/main/java/org/apache/qpid/ErrorCode.java
@@ -1,4 +1,25 @@
package org.apache.qpid;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
public enum ErrorCode
{
@@ -99,4 +120,4 @@ public enum ErrorCode
An invalid or illegal argument was passed to a method, and the operation could not proceed.
</doc>
</constant>
-*/ \ No newline at end of file
+*/
diff --git a/java/common/src/main/java/org/apache/qpid/QpidConfig.java b/java/common/src/main/java/org/apache/qpid/QpidConfig.java
index e8d42fdf83..9c8019f109 100644
--- a/java/common/src/main/java/org/apache/qpid/QpidConfig.java
+++ b/java/common/src/main/java/org/apache/qpid/QpidConfig.java
@@ -1,4 +1,25 @@
package org.apache.qpid;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
/**
* API to configure the Security parameters of the client.
diff --git a/java/common/src/main/java/org/apache/qpid/SecurityHelper.java b/java/common/src/main/java/org/apache/qpid/SecurityHelper.java
deleted file mode 100644
index dda5a6506d..0000000000
--- a/java/common/src/main/java/org/apache/qpid/SecurityHelper.java
+++ /dev/null
@@ -1,71 +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.
- *
- */
-package org.apache.qpid;
-
-import java.io.UnsupportedEncodingException;
-import java.util.HashSet;
-import java.util.List;
-import java.util.StringTokenizer;
-
-import org.apache.qpid.security.AMQPCallbackHandler;
-import org.apache.qpid.security.CallbackHandlerRegistry;
-
-public class SecurityHelper
-{
- public static String chooseMechanism(List<Object> mechanisms) throws UnsupportedEncodingException
- {
- HashSet mechanismSet = new HashSet();
- for (Object m : mechanisms)
- {
- mechanismSet.add(m);
- }
-
- String preferredMechanisms = CallbackHandlerRegistry.getInstance().getMechanisms();
- StringTokenizer prefTokenizer = new StringTokenizer(preferredMechanisms, " ");
- while (prefTokenizer.hasMoreTokens())
- {
- String mech = prefTokenizer.nextToken();
- if (mechanismSet.contains(mech))
- {
- return mech;
- }
- }
- return null;
- }
-
- public static AMQPCallbackHandler createCallbackHandler(String mechanism, String username,String password)
- throws QpidException
- {
- Class mechanismClass = CallbackHandlerRegistry.getInstance().getCallbackHandlerClass(mechanism);
- try
- {
- Object instance = mechanismClass.newInstance();
- AMQPCallbackHandler cbh = (AMQPCallbackHandler) instance;
- cbh.initialise(username,password);
- return cbh;
- }
- catch (Exception e)
- {
- throw new QpidException("Unable to create callback handler: " + e,ErrorCode.UNDEFINED, e.getCause());
- }
- }
-
-}
diff --git a/java/common/src/main/java/org/apache/qpid/SerialException.java b/java/common/src/main/java/org/apache/qpid/SerialException.java
index 4fc8458e45..c59a6af779 100644
--- a/java/common/src/main/java/org/apache/qpid/SerialException.java
+++ b/java/common/src/main/java/org/apache/qpid/SerialException.java
@@ -1,4 +1,25 @@
package org.apache.qpid;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
/**
* This exception is used by the serial class (imp RFC 1982)
diff --git a/java/common/src/main/java/org/apache/qpid/ToyBroker.java b/java/common/src/main/java/org/apache/qpid/ToyBroker.java
index 83d434b20a..db84b83adb 100644
--- a/java/common/src/main/java/org/apache/qpid/ToyBroker.java
+++ b/java/common/src/main/java/org/apache/qpid/ToyBroker.java
@@ -174,23 +174,14 @@ class ToyBroker extends SessionDelegate
public static final void main(String[] args) throws IOException
{
final ToyExchange exchange = new ToyExchange();
- ConnectionDelegate delegate = new ConnectionDelegate()
+ ConnectionDelegate delegate = new ServerDelegate()
{
public SessionDelegate getSessionDelegate()
{
return new ToyBroker(exchange);
}
- public void exception(Throwable t)
- {
- t.printStackTrace();
- }
- public void closed() {}
};
- //hack
- delegate.setUsername("guest");
- delegate.setPassword("guest");
-
MinaHandler.accept("0.0.0.0", 5672, delegate);
}
diff --git a/java/common/src/main/java/org/apache/qpid/ToyClient.java b/java/common/src/main/java/org/apache/qpid/ToyClient.java
index cb10859c9f..5b2db10613 100644
--- a/java/common/src/main/java/org/apache/qpid/ToyClient.java
+++ b/java/common/src/main/java/org/apache/qpid/ToyClient.java
@@ -33,48 +33,30 @@ import org.apache.qpid.transport.network.mina.MinaHandler;
* @author Rafael H. Schloming
*/
-class ToyClient extends SessionDelegate
+class ToyClient implements SessionListener
{
+ public void opened(Session ssn) {}
- @Override public void messageReject(Session ssn, MessageReject reject)
+ public void resumed(Session ssn) {}
+
+ public void exception(Session ssn, SessionException exc)
{
- for (Range range : reject.getTransfers())
- {
- for (long l = range.getLower(); l <= range.getUpper(); l++)
- {
- System.out.println("message rejected: " +
- ssn.getCommand((int) l));
- }
- }
+ exc.printStackTrace();
}
- @Override public void messageTransfer(Session ssn, MessageTransfer xfr)
+ public void message(Session ssn, MessageTransfer xfr)
{
System.out.println("msg: " + xfr);
}
+ public void closed(Session ssn) {}
+
public static final void main(String[] args)
{
- Connection conn = MinaHandler.connect("0.0.0.0", 5672,
- new ClientDelegate()
- {
- public SessionDelegate getSessionDelegate()
- {
- return new ToyClient();
- }
- public void exception(Throwable t)
- {
- t.printStackTrace();
- }
- public void closed() {}
- });
- conn.send(new ProtocolHeader
- (1, 0, 10));
-
- Channel ch = conn.getChannel(0);
- Session ssn = new Session("my-session".getBytes());
- ssn.attach(ch);
- ssn.sessionAttach(ssn.getName());
+ Connection conn = new Connection();
+ conn.connect("0.0.0.0", 5672, null, "guest", "guest", false);
+ Session ssn = conn.createSession();
+ ssn.setSessionListener(new ToyClient());
ssn.queueDeclare("asdf", null, null);
ssn.sync();
diff --git a/java/common/src/main/java/org/apache/qpid/ToyExchange.java b/java/common/src/main/java/org/apache/qpid/ToyExchange.java
index c638679596..da6aed9629 100644
--- a/java/common/src/main/java/org/apache/qpid/ToyExchange.java
+++ b/java/common/src/main/java/org/apache/qpid/ToyExchange.java
@@ -1,4 +1,25 @@
package org.apache.qpid;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import java.util.ArrayList;
import java.util.HashMap;
diff --git a/java/common/src/main/java/org/apache/qpid/codec/AMQCodecFactory.java b/java/common/src/main/java/org/apache/qpid/codec/AMQCodecFactory.java
index fa890d0ebb..591dbd085b 100644
--- a/java/common/src/main/java/org/apache/qpid/codec/AMQCodecFactory.java
+++ b/java/common/src/main/java/org/apache/qpid/codec/AMQCodecFactory.java
@@ -23,6 +23,7 @@ package org.apache.qpid.codec;
import org.apache.mina.filter.codec.ProtocolCodecFactory;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolEncoder;
+import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
/**
* AMQCodecFactory is a Mina codec factory. It supplies the encoders and decoders need to read and write the bytes to
@@ -50,9 +51,9 @@ public class AMQCodecFactory implements ProtocolCodecFactory
* @param expectProtocolInitiation <tt>true</tt> if the first frame received is going to be a protocol initiation
* frame, <tt>false</tt> if it is going to be a standard AMQ data block.
*/
- public AMQCodecFactory(boolean expectProtocolInitiation)
+ public AMQCodecFactory(boolean expectProtocolInitiation, AMQVersionAwareProtocolSession session)
{
- _frameDecoder = new AMQDecoder(expectProtocolInitiation);
+ _frameDecoder = new AMQDecoder(expectProtocolInitiation, session);
}
/**
@@ -70,7 +71,7 @@ public class AMQCodecFactory implements ProtocolCodecFactory
*
* @return The AMQP decoder.
*/
- public ProtocolDecoder getDecoder()
+ public AMQDecoder getDecoder()
{
return _frameDecoder;
}
diff --git a/java/common/src/main/java/org/apache/qpid/codec/AMQDecoder.java b/java/common/src/main/java/org/apache/qpid/codec/AMQDecoder.java
index 7eef73f337..281c0761d9 100644
--- a/java/common/src/main/java/org/apache/qpid/codec/AMQDecoder.java
+++ b/java/common/src/main/java/org/apache/qpid/codec/AMQDecoder.java
@@ -20,14 +20,21 @@
*/
package org.apache.qpid.codec;
+import java.util.ArrayList;
+
import org.apache.mina.common.ByteBuffer;
import org.apache.mina.common.IoSession;
import org.apache.mina.common.SimpleByteBufferAllocator;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
+import org.apache.qpid.framing.AMQDataBlock;
import org.apache.qpid.framing.AMQDataBlockDecoder;
+import org.apache.qpid.framing.AMQFrameDecodingException;
+import org.apache.qpid.framing.AMQMethodBodyFactory;
+import org.apache.qpid.framing.AMQProtocolVersionException;
import org.apache.qpid.framing.ProtocolInitiation;
+import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
/**
* AMQDecoder delegates the decoding of AMQP either to a data block decoder, or in the case of new connections, to a
@@ -62,14 +69,19 @@ public class AMQDecoder extends CumulativeProtocolDecoder
private boolean _expectProtocolInitiation;
private boolean firstDecode = true;
+ private AMQMethodBodyFactory _bodyFactory;
+
+ private ByteBuffer _remainingBuf;
+
/**
* Creates a new AMQP decoder.
*
* @param expectProtocolInitiation <tt>true</tt> if this decoder needs to handle protocol initiation.
*/
- public AMQDecoder(boolean expectProtocolInitiation)
+ public AMQDecoder(boolean expectProtocolInitiation, AMQVersionAwareProtocolSession session)
{
_expectProtocolInitiation = expectProtocolInitiation;
+ _bodyFactory = new AMQMethodBodyFactory(session);
}
/**
@@ -120,7 +132,7 @@ public class AMQDecoder extends CumulativeProtocolDecoder
protected boolean doDecodeDataBlock(IoSession session, ByteBuffer in, ProtocolDecoderOutput out) throws Exception
{
int pos = in.position();
- boolean enoughData = _dataBlockDecoder.decodable(session, in);
+ boolean enoughData = _dataBlockDecoder.decodable(in.buf());
in.position(pos);
if (!enoughData)
{
@@ -149,7 +161,7 @@ public class AMQDecoder extends CumulativeProtocolDecoder
*/
private boolean doDecodePI(IoSession session, ByteBuffer in, ProtocolDecoderOutput out) throws Exception
{
- boolean enoughData = _piDecoder.decodable(session, in);
+ boolean enoughData = _piDecoder.decodable(in.buf());
if (!enoughData)
{
// returning false means it will leave the contents in the buffer and
@@ -158,7 +170,8 @@ public class AMQDecoder extends CumulativeProtocolDecoder
}
else
{
- _piDecoder.decode(session, in, out);
+ ProtocolInitiation pi = new ProtocolInitiation(in.buf());
+ out.write(pi);
return true;
}
@@ -177,7 +190,7 @@ public class AMQDecoder extends CumulativeProtocolDecoder
}
- /**
+ /**
* Cumulates content of <tt>in</tt> into internal buffer and forwards
* decoding request to {@link #doDecode(IoSession, ByteBuffer, ProtocolDecoderOutput)}.
* <tt>doDecode()</tt> is invoked repeatedly until it returns <tt>false</tt>
@@ -268,4 +281,60 @@ public class AMQDecoder extends CumulativeProtocolDecoder
session.setAttribute( BUFFER, remainingBuf );
}
+ public ArrayList<AMQDataBlock> decodeBuffer(java.nio.ByteBuffer buf) throws AMQFrameDecodingException, AMQProtocolVersionException
+ {
+
+ // get prior remaining data from accumulator
+ ArrayList<AMQDataBlock> dataBlocks = new ArrayList<AMQDataBlock>();
+ ByteBuffer msg;
+ // if we have a session buffer, append data to that otherwise
+ // use the buffer read from the network directly
+ if( _remainingBuf != null )
+ {
+ _remainingBuf.put(buf);
+ _remainingBuf.flip();
+ msg = _remainingBuf;
+ }
+ else
+ {
+ msg = ByteBuffer.wrap(buf);
+ }
+
+ if (_expectProtocolInitiation
+ || (firstDecode
+ && (msg.remaining() > 0)
+ && (msg.get(msg.position()) == (byte)'A')))
+ {
+ if (_piDecoder.decodable(msg.buf()))
+ {
+ dataBlocks.add(new ProtocolInitiation(msg.buf()));
+ }
+ }
+ else
+ {
+ boolean enoughData = true;
+ while (enoughData)
+ {
+ int pos = msg.position();
+
+ enoughData = _dataBlockDecoder.decodable(msg);
+ msg.position(pos);
+ if (enoughData)
+ {
+ dataBlocks.add(_dataBlockDecoder.createAndPopulateFrame(_bodyFactory, msg));
+ }
+ else
+ {
+ _remainingBuf = SIMPLE_BYTE_BUFFER_ALLOCATOR.allocate(msg.remaining(), false);
+ _remainingBuf.setAutoExpand(true);
+ _remainingBuf.put(msg);
+ }
+ }
+ }
+ if(firstDecode && dataBlocks.size() > 0)
+ {
+ firstDecode = false;
+ }
+ return dataBlocks;
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java b/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java
index 82ffc60802..228867b2b0 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java
@@ -47,7 +47,7 @@ public class AMQDataBlockDecoder
public AMQDataBlockDecoder()
{ }
- public boolean decodable(IoSession session, ByteBuffer in) throws AMQFrameDecodingException
+ public boolean decodable(java.nio.ByteBuffer in) throws AMQFrameDecodingException
{
final int remainingAfterAttributes = in.remaining() - (1 + 2 + 4 + 1);
// type, channel, body length and end byte
@@ -56,14 +56,15 @@ public class AMQDataBlockDecoder
return false;
}
- in.skip(1 + 2);
- final long bodySize = in.getUnsignedInt();
+ in.position(in.position() + 1 + 2);
+ // Get an unsigned int, lifted from MINA ByteBuffer getUnsignedInt()
+ final long bodySize = in.getInt() & 0xffffffffL;
return (remainingAfterAttributes >= bodySize);
}
- protected Object createAndPopulateFrame(IoSession session, ByteBuffer in)
+ public AMQFrame createAndPopulateFrame(AMQMethodBodyFactory methodBodyFactory, ByteBuffer in)
throws AMQFrameDecodingException, AMQProtocolVersionException
{
final byte type = in.get();
@@ -71,15 +72,7 @@ public class AMQDataBlockDecoder
BodyFactory bodyFactory;
if (type == AMQMethodBody.TYPE)
{
- bodyFactory = (BodyFactory) session.getAttribute(SESSION_METHOD_BODY_FACTORY);
- if (bodyFactory == null)
- {
- AMQVersionAwareProtocolSession protocolSession = (AMQVersionAwareProtocolSession) session.getAttachment();
- bodyFactory = new AMQMethodBodyFactory(protocolSession);
- session.setAttribute(SESSION_METHOD_BODY_FACTORY, bodyFactory);
-
- }
-
+ bodyFactory = methodBodyFactory;
}
else
{
@@ -115,6 +108,24 @@ public class AMQDataBlockDecoder
public void decode(IoSession session, ByteBuffer in, ProtocolDecoderOutput out) throws Exception
{
- out.write(createAndPopulateFrame(session, in));
+ AMQMethodBodyFactory bodyFactory = (AMQMethodBodyFactory) session.getAttribute(SESSION_METHOD_BODY_FACTORY);
+ if (bodyFactory == null)
+ {
+ AMQVersionAwareProtocolSession protocolSession = (AMQVersionAwareProtocolSession) session.getAttachment();
+ bodyFactory = new AMQMethodBodyFactory(protocolSession);
+ session.setAttribute(SESSION_METHOD_BODY_FACTORY, bodyFactory);
+ }
+
+ out.write(createAndPopulateFrame(bodyFactory, in));
+ }
+
+ public boolean decodable(ByteBuffer msg) throws AMQFrameDecodingException
+ {
+ return decodable(msg.buf());
+ }
+
+ public AMQDataBlock createAndPopulateFrame(AMQMethodBodyFactory factory, java.nio.ByteBuffer msg) throws AMQProtocolVersionException, AMQFrameDecodingException
+ {
+ return createAndPopulateFrame(factory, ByteBuffer.wrap(msg));
}
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockEncoder.java b/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockEncoder.java
index 05fd2bb480..374644b4f2 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockEncoder.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockEncoder.java
@@ -50,7 +50,7 @@ public final class AMQDataBlockEncoder implements MessageEncoder
{
_logger.debug("Encoded frame byte-buffer is '" + EncodingUtils.convertToHexString(buffer) + "'");
}
-
+
out.write(buffer);
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyImpl.java b/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyImpl.java
index ad7f36f790..cd3d721065 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyImpl.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyImpl.java
@@ -93,4 +93,166 @@ public abstract class AMQMethodBodyImpl implements AMQMethodBody
session.methodFrameReceived(channelId, this);
}
+ public int getSize()
+ {
+ return 2 + 2 + getBodySize();
+ }
+
+ public void writePayload(ByteBuffer buffer)
+ {
+ EncodingUtils.writeUnsignedShort(buffer, getClazz());
+ EncodingUtils.writeUnsignedShort(buffer, getMethod());
+ writeMethodPayload(buffer);
+ }
+
+
+ protected byte readByte(ByteBuffer buffer)
+ {
+ return buffer.get();
+ }
+
+ protected AMQShortString readAMQShortString(ByteBuffer buffer)
+ {
+ return EncodingUtils.readAMQShortString(buffer);
+ }
+
+ protected int getSizeOf(AMQShortString string)
+ {
+ return EncodingUtils.encodedShortStringLength(string);
+ }
+
+ protected void writeByte(ByteBuffer buffer, byte b)
+ {
+ buffer.put(b);
+ }
+
+ protected void writeAMQShortString(ByteBuffer buffer, AMQShortString string)
+ {
+ EncodingUtils.writeShortStringBytes(buffer, string);
+ }
+
+ protected int readInt(ByteBuffer buffer)
+ {
+ return buffer.getInt();
+ }
+
+ protected void writeInt(ByteBuffer buffer, int i)
+ {
+ buffer.putInt(i);
+ }
+
+ protected FieldTable readFieldTable(ByteBuffer buffer) throws AMQFrameDecodingException
+ {
+ return EncodingUtils.readFieldTable(buffer);
+ }
+
+ protected int getSizeOf(FieldTable table)
+ {
+ return EncodingUtils.encodedFieldTableLength(table); //To change body of created methods use File | Settings | File Templates.
+ }
+
+ protected void writeFieldTable(ByteBuffer buffer, FieldTable table)
+ {
+ EncodingUtils.writeFieldTableBytes(buffer, table);
+ }
+
+ protected long readLong(ByteBuffer buffer)
+ {
+ return buffer.getLong();
+ }
+
+ protected void writeLong(ByteBuffer buffer, long l)
+ {
+ buffer.putLong(l);
+ }
+
+ protected int getSizeOf(byte[] response)
+ {
+ return (response == null) ? 4 : response.length + 4;
+ }
+
+ protected void writeBytes(ByteBuffer buffer, byte[] data)
+ {
+ EncodingUtils.writeBytes(buffer,data);
+ }
+
+ protected byte[] readBytes(ByteBuffer buffer)
+ {
+ return EncodingUtils.readBytes(buffer);
+ }
+
+ protected short readShort(ByteBuffer buffer)
+ {
+ return EncodingUtils.readShort(buffer);
+ }
+
+ protected void writeShort(ByteBuffer buffer, short s)
+ {
+ EncodingUtils.writeShort(buffer, s);
+ }
+
+ protected Content readContent(ByteBuffer buffer)
+ {
+ return null; //To change body of created methods use File | Settings | File Templates.
+ }
+
+ protected int getSizeOf(Content body)
+ {
+ return 0; //To change body of created methods use File | Settings | File Templates.
+ }
+
+ protected void writeContent(ByteBuffer buffer, Content body)
+ {
+ //To change body of created methods use File | Settings | File Templates.
+ }
+
+ protected byte readBitfield(ByteBuffer buffer)
+ {
+ return readByte(buffer); //To change body of created methods use File | Settings | File Templates.
+ }
+
+ protected int readUnsignedShort(ByteBuffer buffer)
+ {
+ return buffer.getUnsignedShort(); //To change body of created methods use File | Settings | File Templates.
+ }
+
+ protected void writeBitfield(ByteBuffer buffer, byte bitfield0)
+ {
+ buffer.put(bitfield0);
+ }
+
+ protected void writeUnsignedShort(ByteBuffer buffer, int s)
+ {
+ EncodingUtils.writeUnsignedShort(buffer, s);
+ }
+
+ protected long readUnsignedInteger(ByteBuffer buffer)
+ {
+ return buffer.getUnsignedInt();
+ }
+ protected void writeUnsignedInteger(ByteBuffer buffer, long i)
+ {
+ EncodingUtils.writeUnsignedInteger(buffer, i);
+ }
+
+
+ protected short readUnsignedByte(ByteBuffer buffer)
+ {
+ return buffer.getUnsigned();
+ }
+
+ protected void writeUnsignedByte(ByteBuffer buffer, short unsignedByte)
+ {
+ EncodingUtils.writeUnsignedByte(buffer, unsignedByte);
+ }
+
+ protected long readTimestamp(ByteBuffer buffer)
+ {
+ return EncodingUtils.readTimestamp(buffer);
+ }
+
+ protected void writeTimestamp(ByteBuffer buffer, long t)
+ {
+ EncodingUtils.writeTimestamp(buffer, t);
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java b/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java
index 1ff39ca790..647d531476 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java
@@ -22,6 +22,10 @@ package org.apache.qpid.framing;
import org.apache.mina.common.ByteBuffer;
+import java.util.Date;
+import java.util.Map;
+import java.math.BigDecimal;
+
/**
* AMQTypedValue combines together a native Java Object value, and an {@link AMQType}, as a fully typed AMQP parameter
* value. It provides the ability to read and write fully typed parameters to and from byte buffers. It also provides
@@ -113,4 +117,63 @@ public class AMQTypedValue
return _type.hashCode() ^ (_value == null ? 0 : _value.hashCode());
}
+
+ public static AMQTypedValue toTypedValue(Object val)
+ {
+ if(val == null)
+ {
+ return AMQType.VOID.asTypedValue(null);
+ }
+
+ Class klass = val.getClass();
+ if(klass == String.class)
+ {
+ return AMQType.ASCII_STRING.asTypedValue(val);
+ }
+ else if(klass == Character.class)
+ {
+ return AMQType.ASCII_CHARACTER.asTypedValue(val);
+ }
+ else if(klass == Integer.class)
+ {
+ return AMQType.INT.asTypedValue(val);
+ }
+ else if(klass == Long.class)
+ {
+ return AMQType.LONG.asTypedValue(val);
+ }
+ else if(klass == Float.class)
+ {
+ return AMQType.FLOAT.asTypedValue(val);
+ }
+ else if(klass == Double.class)
+ {
+ return AMQType.DOUBLE.asTypedValue(val);
+ }
+ else if(klass == Date.class)
+ {
+ return AMQType.TIMESTAMP.asTypedValue(val);
+ }
+ else if(klass == Byte.class)
+ {
+ return AMQType.BYTE.asTypedValue(val);
+ }
+ else if(klass == Boolean.class)
+ {
+ return AMQType.BOOLEAN.asTypedValue(val);
+ }
+ else if(klass == byte[].class)
+ {
+ return AMQType.BINARY.asTypedValue(val);
+ }
+ else if(klass == BigDecimal.class)
+ {
+ return AMQType.DECIMAL.asTypedValue(val);
+ }
+ else if(val instanceof Map)
+ {
+ return AMQType.FIELD_TABLE.asTypedValue(FieldTable.convertToFieldTable((Map)val));
+ }
+ return null;
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java b/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java
index 47b5c02beb..c7d89a9927 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java
@@ -27,6 +27,10 @@ import org.slf4j.LoggerFactory;
public class BasicContentHeaderProperties implements CommonContentHeaderProperties
{
+ //persistent & non-persistent constants, values as per JMS DeliveryMode
+ public static final int NON_PERSISTENT = 1;
+ public static final int PERSISTENT = 2;
+
private static final Logger _logger = LoggerFactory.getLogger(BasicContentHeaderProperties.class);
private static final AMQShortString ZERO_STRING = null;
diff --git a/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java b/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java
index ed01c91804..341238c667 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java
@@ -131,9 +131,10 @@ public class FieldTable
}
else if ((_encodedForm != null) && (val != null))
{
- EncodingUtils.writeShortStringBytes(_encodedForm, key);
- val.writeToBuffer(_encodedForm);
-
+ // We have updated data to store in the buffer
+ // So clear the _encodedForm to allow it to be rebuilt later
+ // this is safer than simply appending to any existing buffer.
+ _encodedForm = null;
}
else if (val == null)
{
@@ -828,6 +829,7 @@ public class FieldTable
recalculateEncodedSize();
}
+
public static interface FieldTableElementProcessor
{
public boolean processElement(String propertyName, AMQTypedValue value);
@@ -904,10 +906,13 @@ public class FieldTable
}
}
+ public Object get(String key)
+ {
+ return get(new AMQShortString(key));
+ }
public Object get(AMQShortString key)
{
-
return getObject(key);
}
@@ -1184,4 +1189,24 @@ public class FieldTable
return _properties.equals(f._properties);
}
+
+ public static FieldTable convertToFieldTable(Map<String, Object> map)
+ {
+ if (map != null)
+ {
+ FieldTable table = new FieldTable();
+ for(Map.Entry<String,Object> entry : map.entrySet())
+ {
+ table.put(new AMQShortString(entry.getKey()), entry.getValue());
+ }
+
+ return table;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/ProtocolInitiation.java b/java/common/src/main/java/org/apache/qpid/framing/ProtocolInitiation.java
index 3ac17e9204..ac21fe4243 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/ProtocolInitiation.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/ProtocolInitiation.java
@@ -20,12 +20,10 @@
*/
package org.apache.qpid.framing;
-import org.apache.mina.common.ByteBuffer;
-import org.apache.mina.common.IoSession;
-import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.qpid.AMQException;
import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
public class ProtocolInitiation extends AMQDataBlock implements EncodableAMQDataBlock
{
@@ -53,13 +51,16 @@ public class ProtocolInitiation extends AMQDataBlock implements EncodableAMQData
_protocolMajor = protocolMajor;
_protocolMinor = protocolMinor;
}
-
+
public ProtocolInitiation(ProtocolVersion pv)
{
- this(AMQP_HEADER, CURRENT_PROTOCOL_CLASS, TCP_PROTOCOL_INSTANCE, pv.getMajorVersion(), pv.getMinorVersion());
+ this(AMQP_HEADER,
+ pv.equals(ProtocolVersion.v0_91) ? 0 : CURRENT_PROTOCOL_CLASS,
+ pv.equals(ProtocolVersion.v0_91) ? 0 : TCP_PROTOCOL_INSTANCE,
+ pv.equals(ProtocolVersion.v0_91) ? 9 : pv.getMajorVersion(),
+ pv.equals(ProtocolVersion.v0_91) ? 1 : pv.getMinorVersion());
}
-
public ProtocolInitiation(ByteBuffer in)
{
_protocolHeader = new byte[4];
@@ -71,6 +72,11 @@ public class ProtocolInitiation extends AMQDataBlock implements EncodableAMQData
_protocolMinor = in.get();
}
+ public void writePayload(org.apache.mina.common.ByteBuffer buffer)
+ {
+ writePayload(buffer.buf());
+ }
+
public long getSize()
{
return 4 + 1 + 1 + 1 + 1;
@@ -122,21 +128,15 @@ public class ProtocolInitiation extends AMQDataBlock implements EncodableAMQData
{
/**
*
- * @param session the session
* @param in input buffer
* @return true if we have enough data to decode the PI frame fully, false if more
* data is required
*/
- public boolean decodable(IoSession session, ByteBuffer in)
+ public boolean decodable(ByteBuffer in)
{
return (in.remaining() >= 8);
}
- public void decode(IoSession session, ByteBuffer in, ProtocolDecoderOutput out)
- {
- ProtocolInitiation pi = new ProtocolInitiation(in);
- out.write(pi);
- }
}
public ProtocolVersion checkVersion() throws AMQException
@@ -160,18 +160,33 @@ public class ProtocolInitiation extends AMQDataBlock implements EncodableAMQData
}
}
}
- if (_protocolClass != CURRENT_PROTOCOL_CLASS)
+
+ ProtocolVersion pv;
+
+ // Hack for 0-9-1 which changed how the header was defined
+ if(_protocolInstance == 0 && _protocolMajor == 9 && _protocolMinor == 1)
+ {
+ pv = ProtocolVersion.v0_91;
+ if (_protocolClass != 0)
+ {
+ throw new AMQProtocolClassException("Protocol class " + 0 + " was expected; received " +
+ _protocolClass, null);
+ }
+ }
+ else if (_protocolClass != CURRENT_PROTOCOL_CLASS)
{
throw new AMQProtocolClassException("Protocol class " + CURRENT_PROTOCOL_CLASS + " was expected; received " +
_protocolClass, null);
}
- if (_protocolInstance != TCP_PROTOCOL_INSTANCE)
+ else if (_protocolInstance != TCP_PROTOCOL_INSTANCE)
{
throw new AMQProtocolInstanceException("Protocol instance " + TCP_PROTOCOL_INSTANCE + " was expected; received " +
_protocolInstance, null);
}
-
- ProtocolVersion pv = new ProtocolVersion(_protocolMajor, _protocolMinor);
+ else
+ {
+ pv = new ProtocolVersion(_protocolMajor, _protocolMinor);
+ }
if (!pv.isSupported())
@@ -192,4 +207,5 @@ public class ProtocolInitiation extends AMQDataBlock implements EncodableAMQData
buffer.append(Integer.toHexString(_protocolMinor));
return buffer.toString();
}
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/abstraction/MessagePublishInfoImpl.java b/java/common/src/main/java/org/apache/qpid/framing/abstraction/MessagePublishInfoImpl.java
new file mode 100644
index 0000000000..e3d5da73da
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/framing/abstraction/MessagePublishInfoImpl.java
@@ -0,0 +1,85 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.framing.abstraction;
+
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.framing.AMQShortString;
+
+public class MessagePublishInfoImpl implements MessagePublishInfo
+{
+ private AMQShortString _exchange;
+ private boolean _immediate;
+ private boolean _mandatory;
+ private AMQShortString _routingKey;
+
+ public MessagePublishInfoImpl()
+ {
+ }
+
+ public MessagePublishInfoImpl(AMQShortString exchange, boolean immediate, boolean mandatory,
+ AMQShortString routingKey)
+ {
+ _exchange = exchange;
+ _immediate = immediate;
+ _mandatory = mandatory;
+ _routingKey = routingKey;
+ }
+
+ public AMQShortString getExchange()
+ {
+ return _exchange;
+ }
+
+ public void setExchange(AMQShortString exchange)
+ {
+ _exchange = exchange;
+ }
+
+ public boolean isImmediate()
+ {
+ return _immediate;
+ }
+
+ public void setImmediate(boolean immedate)
+ {
+ _immediate = immedate;
+ }
+
+ public boolean isMandatory()
+ {
+ return _mandatory;
+ }
+
+ public void setMandatory(boolean mandatory)
+ {
+ _mandatory = mandatory;
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return _routingKey;
+ }
+
+ public void setRoutingKey(AMQShortString routingKey)
+ {
+ _routingKey = routingKey;
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/abstraction/ProtocolVersionMethodConverter.java b/java/common/src/main/java/org/apache/qpid/framing/abstraction/ProtocolVersionMethodConverter.java
index 0a1cedc4e6..7544d9b7e7 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/abstraction/ProtocolVersionMethodConverter.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/abstraction/ProtocolVersionMethodConverter.java
@@ -23,10 +23,14 @@ package org.apache.qpid.framing.abstraction;
import org.apache.qpid.framing.AMQBody;
+import java.nio.ByteBuffer;
+
public interface ProtocolVersionMethodConverter extends MessagePublishInfoConverter
{
AMQBody convertToBody(ContentChunk contentBody);
ContentChunk convertToContentChunk(AMQBody body);
void configure();
+
+ AMQBody convertToBody(ByteBuffer buf);
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/AMQMethodBody_0_9.java b/java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/AMQMethodBody_0_9.java
index 948f5baaf6..8d51343507 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/AMQMethodBody_0_9.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/AMQMethodBody_0_9.java
@@ -21,14 +21,6 @@
package org.apache.qpid.framing.amqp_0_9;
-import org.apache.qpid.framing.EncodingUtils;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.framing.AMQFrameDecodingException;
-import org.apache.qpid.framing.Content;
-
-import org.apache.mina.common.ByteBuffer;
-
public abstract class AMQMethodBody_0_9 extends org.apache.qpid.framing.AMQMethodBodyImpl
{
@@ -40,170 +32,6 @@ public abstract class AMQMethodBody_0_9 extends org.apache.qpid.framing.AMQMetho
public byte getMinor()
{
return 9;
- }
-
- public int getSize()
- {
- return 2 + 2 + getBodySize();
- }
-
- public void writePayload(ByteBuffer buffer)
- {
- EncodingUtils.writeUnsignedShort(buffer, getClazz());
- EncodingUtils.writeUnsignedShort(buffer, getMethod());
- writeMethodPayload(buffer);
- }
-
-
- protected byte readByte(ByteBuffer buffer)
- {
- return buffer.get();
- }
-
- protected AMQShortString readAMQShortString(ByteBuffer buffer)
- {
- return EncodingUtils.readAMQShortString(buffer);
- }
-
- protected int getSizeOf(AMQShortString string)
- {
- return EncodingUtils.encodedShortStringLength(string);
- }
-
- protected void writeByte(ByteBuffer buffer, byte b)
- {
- buffer.put(b);
- }
-
- protected void writeAMQShortString(ByteBuffer buffer, AMQShortString string)
- {
- EncodingUtils.writeShortStringBytes(buffer, string);
- }
-
- protected int readInt(ByteBuffer buffer)
- {
- return buffer.getInt();
- }
-
- protected void writeInt(ByteBuffer buffer, int i)
- {
- buffer.putInt(i);
- }
-
- protected FieldTable readFieldTable(ByteBuffer buffer) throws AMQFrameDecodingException
- {
- return EncodingUtils.readFieldTable(buffer);
- }
-
- protected int getSizeOf(FieldTable table)
- {
- return EncodingUtils.encodedFieldTableLength(table); //To change body of created methods use File | Settings | File Templates.
- }
-
- protected void writeFieldTable(ByteBuffer buffer, FieldTable table)
- {
- EncodingUtils.writeFieldTableBytes(buffer, table);
- }
-
- protected long readLong(ByteBuffer buffer)
- {
- return buffer.getLong();
- }
-
- protected void writeLong(ByteBuffer buffer, long l)
- {
- buffer.putLong(l);
- }
-
- protected int getSizeOf(byte[] response)
- {
- return (response == null) ? 4 :response.length + 4;
- }
-
- protected void writeBytes(ByteBuffer buffer, byte[] data)
- {
- EncodingUtils.writeBytes(buffer,data);
- }
-
- protected byte[] readBytes(ByteBuffer buffer)
- {
- return EncodingUtils.readBytes(buffer);
- }
-
- protected short readShort(ByteBuffer buffer)
- {
- return EncodingUtils.readShort(buffer);
- }
-
- protected void writeShort(ByteBuffer buffer, short s)
- {
- EncodingUtils.writeShort(buffer, s);
- }
-
- protected Content readContent(ByteBuffer buffer)
- {
- return null; //To change body of created methods use File | Settings | File Templates.
- }
-
- protected int getSizeOf(Content body)
- {
- return 0; //To change body of created methods use File | Settings | File Templates.
- }
-
- protected void writeContent(ByteBuffer buffer, Content body)
- {
- //To change body of created methods use File | Settings | File Templates.
- }
-
- protected byte readBitfield(ByteBuffer buffer)
- {
- return readByte(buffer); //To change body of created methods use File | Settings | File Templates.
- }
-
- protected int readUnsignedShort(ByteBuffer buffer)
- {
- return buffer.getUnsignedShort(); //To change body of created methods use File | Settings | File Templates.
- }
-
- protected void writeBitfield(ByteBuffer buffer, byte bitfield0)
- {
- buffer.put(bitfield0);
- }
-
- protected void writeUnsignedShort(ByteBuffer buffer, int s)
- {
- EncodingUtils.writeUnsignedShort(buffer, s);
- }
-
- protected long readUnsignedInteger(ByteBuffer buffer)
- {
- return buffer.getUnsignedInt();
- }
- protected void writeUnsignedInteger(ByteBuffer buffer, long i)
- {
- EncodingUtils.writeUnsignedInteger(buffer, i);
- }
-
-
- protected short readUnsignedByte(ByteBuffer buffer)
- {
- return buffer.getUnsigned();
- }
-
- protected void writeUnsignedByte(ByteBuffer buffer, short unsignedByte)
- {
- EncodingUtils.writeUnsignedByte(buffer, unsignedByte);
- }
-
- protected long readTimestamp(ByteBuffer buffer)
- {
- return EncodingUtils.readTimestamp(buffer);
- }
-
- protected void writeTimestamp(ByteBuffer buffer, long t)
- {
- EncodingUtils.writeTimestamp(buffer, t);
- }
-
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/MethodConverter_0_9.java b/java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/MethodConverter_0_9.java
index fd5195eb6b..1c4a29b106 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/MethodConverter_0_9.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/MethodConverter_0_9.java
@@ -27,6 +27,7 @@ import org.apache.qpid.framing.abstraction.AbstractMethodConverter;
import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;
import org.apache.qpid.framing.abstraction.ContentChunk;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.framing.abstraction.MessagePublishInfoImpl;
import org.apache.qpid.framing.*;
import org.apache.qpid.framing.amqp_0_9.*;
import org.apache.qpid.framing.amqp_0_9.BasicPublishBodyImpl;
@@ -71,6 +72,11 @@ public class MethodConverter_0_9 extends AbstractMethodConverter implements Prot
}
+ public AMQBody convertToBody(java.nio.ByteBuffer buf)
+ {
+ return new ContentBody(ByteBuffer.wrap(buf));
+ }
+
public MessagePublishInfo convertToInfo(AMQMethodBody methodBody)
{
final BasicPublishBody publishBody = ((BasicPublishBody) methodBody);
@@ -78,7 +84,7 @@ public class MethodConverter_0_9 extends AbstractMethodConverter implements Prot
final AMQShortString exchange = publishBody.getExchange();
final AMQShortString routingKey = publishBody.getRoutingKey();
- return new MethodConverter_0_9.MessagePublishInfoImpl(exchange,
+ return new MessagePublishInfoImpl(exchange,
publishBody.getImmediate(),
publishBody.getMandatory(),
routingKey);
@@ -96,50 +102,6 @@ public class MethodConverter_0_9 extends AbstractMethodConverter implements Prot
}
- private static class MessagePublishInfoImpl implements MessagePublishInfo
- {
- private AMQShortString _exchange;
- private final boolean _immediate;
- private final boolean _mandatory;
- private final AMQShortString _routingKey;
-
- public MessagePublishInfoImpl(final AMQShortString exchange,
- final boolean immediate,
- final boolean mandatory,
- final AMQShortString routingKey)
- {
- _exchange = exchange;
- _immediate = immediate;
- _mandatory = mandatory;
- _routingKey = routingKey;
- }
-
- public AMQShortString getExchange()
- {
- return _exchange;
- }
-
- public void setExchange(AMQShortString exchange)
- {
- _exchange = exchange;
- }
-
- public boolean isImmediate()
- {
- return _immediate;
- }
-
- public boolean isMandatory()
- {
- return _mandatory;
- }
-
- public AMQShortString getRoutingKey()
- {
- return _routingKey;
- }
- }
-
private static class ContentChunk_0_9 implements ContentChunk
{
private final ContentBody _contentBodyChunk;
diff --git a/java/common/src/main/java/org/apache/qpid/framing/amqp_0_91/AMQMethodBody_0_91.java b/java/common/src/main/java/org/apache/qpid/framing/amqp_0_91/AMQMethodBody_0_91.java
new file mode 100644
index 0000000000..60b8a7e1a6
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/framing/amqp_0_91/AMQMethodBody_0_91.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.framing.amqp_0_91;
+
+public abstract class AMQMethodBody_0_91 extends org.apache.qpid.framing.AMQMethodBodyImpl
+{
+
+ public byte getMajor()
+ {
+ return 0;
+ }
+
+ public byte getMinor()
+ {
+ return 91;
+ }
+
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/framing/amqp_0_91/MethodConverter_0_91.java b/java/common/src/main/java/org/apache/qpid/framing/amqp_0_91/MethodConverter_0_91.java
new file mode 100644
index 0000000000..6e330574bc
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/framing/amqp_0_91/MethodConverter_0_91.java
@@ -0,0 +1,132 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.framing.amqp_0_91;
+
+import org.apache.mina.common.ByteBuffer;
+
+import org.apache.qpid.framing.abstraction.AbstractMethodConverter;
+import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;
+import org.apache.qpid.framing.abstraction.ContentChunk;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.framing.abstraction.MessagePublishInfoImpl;
+import org.apache.qpid.framing.*;
+
+public class MethodConverter_0_91 extends AbstractMethodConverter implements ProtocolVersionMethodConverter
+{
+ private int _basicPublishClassId;
+ private int _basicPublishMethodId;
+
+ public MethodConverter_0_91()
+ {
+ super((byte)0,(byte)9);
+
+
+ }
+
+ public AMQBody convertToBody(ContentChunk contentChunk)
+ {
+ if(contentChunk instanceof ContentChunk_0_9)
+ {
+ return ((ContentChunk_0_9)contentChunk).toBody();
+ }
+ else
+ {
+ return new ContentBody(contentChunk.getData());
+ }
+ }
+
+ public ContentChunk convertToContentChunk(AMQBody body)
+ {
+ final ContentBody contentBodyChunk = (ContentBody) body;
+
+ return new ContentChunk_0_9(contentBodyChunk);
+
+ }
+
+ public void configure()
+ {
+
+ _basicPublishClassId = BasicPublishBodyImpl.CLASS_ID;
+ _basicPublishMethodId = BasicPublishBodyImpl.METHOD_ID;
+
+ }
+
+ public AMQBody convertToBody(java.nio.ByteBuffer buf)
+ {
+ return new ContentBody(ByteBuffer.wrap(buf));
+ }
+
+ public MessagePublishInfo convertToInfo(AMQMethodBody methodBody)
+ {
+ final BasicPublishBody publishBody = ((BasicPublishBody) methodBody);
+
+ final AMQShortString exchange = publishBody.getExchange();
+ final AMQShortString routingKey = publishBody.getRoutingKey();
+
+ return new MessagePublishInfoImpl(exchange,
+ publishBody.getImmediate(),
+ publishBody.getMandatory(),
+ routingKey);
+
+ }
+
+ public AMQMethodBody convertToBody(MessagePublishInfo info)
+ {
+
+ return new BasicPublishBodyImpl(0,
+ info.getExchange(),
+ info.getRoutingKey(),
+ info.isMandatory(),
+ info.isImmediate()) ;
+
+ }
+
+ private static class ContentChunk_0_9 implements ContentChunk
+ {
+ private final ContentBody _contentBodyChunk;
+
+ public ContentChunk_0_9(final ContentBody contentBodyChunk)
+ {
+ _contentBodyChunk = contentBodyChunk;
+ }
+
+ public int getSize()
+ {
+ return _contentBodyChunk.getSize();
+ }
+
+ public ByteBuffer getData()
+ {
+ return _contentBodyChunk.payload;
+ }
+
+ public void reduceToFit()
+ {
+ _contentBodyChunk.reduceBufferToFit();
+ }
+
+ public AMQBody toBody()
+ {
+ return _contentBodyChunk;
+ }
+ }
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/AMQMethodBody_8_0.java b/java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/AMQMethodBody_8_0.java
index e9b4447140..35645854c0 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/AMQMethodBody_8_0.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/AMQMethodBody_8_0.java
@@ -21,14 +21,6 @@
package org.apache.qpid.framing.amqp_8_0;
-import org.apache.qpid.framing.EncodingUtils;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.framing.AMQFrameDecodingException;
-import org.apache.qpid.framing.Content;
-
-import org.apache.mina.common.ByteBuffer;
-
public abstract class AMQMethodBody_8_0 extends org.apache.qpid.framing.AMQMethodBodyImpl
{
@@ -42,168 +34,7 @@ public abstract class AMQMethodBody_8_0 extends org.apache.qpid.framing.AMQMetho
return 0;
}
- public int getSize()
- {
- return 2 + 2 + getBodySize();
- }
-
- public void writePayload(ByteBuffer buffer)
- {
- EncodingUtils.writeUnsignedShort(buffer, getClazz());
- EncodingUtils.writeUnsignedShort(buffer, getMethod());
- writeMethodPayload(buffer);
- }
-
- protected byte readByte(ByteBuffer buffer)
- {
- return buffer.get();
- }
-
- protected AMQShortString readAMQShortString(ByteBuffer buffer)
- {
- return EncodingUtils.readAMQShortString(buffer);
- }
-
- protected int getSizeOf(AMQShortString string)
- {
- return EncodingUtils.encodedShortStringLength(string);
- }
-
- protected void writeByte(ByteBuffer buffer, byte b)
- {
- buffer.put(b);
- }
-
- protected void writeAMQShortString(ByteBuffer buffer, AMQShortString string)
- {
- EncodingUtils.writeShortStringBytes(buffer, string);
- }
-
- protected int readInt(ByteBuffer buffer)
- {
- return buffer.getInt();
- }
-
- protected void writeInt(ByteBuffer buffer, int i)
- {
- buffer.putInt(i);
- }
-
- protected FieldTable readFieldTable(ByteBuffer buffer) throws AMQFrameDecodingException
- {
- return EncodingUtils.readFieldTable(buffer);
- }
-
- protected int getSizeOf(FieldTable table)
- {
- return EncodingUtils.encodedFieldTableLength(table); //To change body of created methods use File | Settings | File Templates.
- }
-
- protected void writeFieldTable(ByteBuffer buffer, FieldTable table)
- {
- EncodingUtils.writeFieldTableBytes(buffer, table);
- }
-
- protected long readLong(ByteBuffer buffer)
- {
- return buffer.getLong();
- }
-
- protected void writeLong(ByteBuffer buffer, long l)
- {
- buffer.putLong(l);
- }
-
- protected int getSizeOf(byte[] response)
- {
- return (response == null) ? 4 : response.length + 4;
- }
-
- protected void writeBytes(ByteBuffer buffer, byte[] data)
- {
- EncodingUtils.writeBytes(buffer,data);
- }
-
- protected byte[] readBytes(ByteBuffer buffer)
- {
- return EncodingUtils.readBytes(buffer);
- }
-
- protected short readShort(ByteBuffer buffer)
- {
- return EncodingUtils.readShort(buffer);
- }
-
- protected void writeShort(ByteBuffer buffer, short s)
- {
- EncodingUtils.writeShort(buffer, s);
- }
-
- protected Content readContent(ByteBuffer buffer)
- {
- return null; //To change body of created methods use File | Settings | File Templates.
- }
-
- protected int getSizeOf(Content body)
- {
- return 0; //To change body of created methods use File | Settings | File Templates.
- }
-
- protected void writeContent(ByteBuffer buffer, Content body)
- {
- //To change body of created methods use File | Settings | File Templates.
- }
-
- protected byte readBitfield(ByteBuffer buffer)
- {
- return readByte(buffer); //To change body of created methods use File | Settings | File Templates.
- }
-
- protected int readUnsignedShort(ByteBuffer buffer)
- {
- return buffer.getUnsignedShort(); //To change body of created methods use File | Settings | File Templates.
- }
-
- protected void writeBitfield(ByteBuffer buffer, byte bitfield0)
- {
- buffer.put(bitfield0);
- }
-
- protected void writeUnsignedShort(ByteBuffer buffer, int s)
- {
- EncodingUtils.writeUnsignedShort(buffer, s);
- }
-
- protected long readUnsignedInteger(ByteBuffer buffer)
- {
- return buffer.getUnsignedInt();
- }
- protected void writeUnsignedInteger(ByteBuffer buffer, long i)
- {
- EncodingUtils.writeUnsignedInteger(buffer, i);
- }
-
-
- protected short readUnsignedByte(ByteBuffer buffer)
- {
- return buffer.getUnsigned();
- }
-
- protected void writeUnsignedByte(ByteBuffer buffer, short unsignedByte)
- {
- EncodingUtils.writeUnsignedByte(buffer, unsignedByte);
- }
-
- protected long readTimestamp(ByteBuffer buffer)
- {
- return EncodingUtils.readTimestamp(buffer);
- }
-
- protected void writeTimestamp(ByteBuffer buffer, long t)
- {
- EncodingUtils.writeTimestamp(buffer, t);
- }
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/MethodConverter_8_0.java b/java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/MethodConverter_8_0.java
index 299c655698..c87820b9b2 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/MethodConverter_8_0.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/MethodConverter_8_0.java
@@ -25,6 +25,7 @@ import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;
import org.apache.qpid.framing.abstraction.ContentChunk;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.framing.abstraction.AbstractMethodConverter;
+import org.apache.qpid.framing.abstraction.MessagePublishInfoImpl;
import org.apache.qpid.framing.amqp_8_0.BasicPublishBodyImpl;
import org.apache.qpid.framing.*;
@@ -79,6 +80,11 @@ public class MethodConverter_8_0 extends AbstractMethodConverter implements Prot
_basicPublishMethodId = BasicPublishBodyImpl.METHOD_ID;
}
+
+ public AMQBody convertToBody(java.nio.ByteBuffer buf)
+ {
+ return new ContentBody(ByteBuffer.wrap(buf));
+ }
public MessagePublishInfo convertToInfo(AMQMethodBody methodBody)
{
@@ -104,48 +110,4 @@ public class MethodConverter_8_0 extends AbstractMethodConverter implements Prot
info.isImmediate()) ;
}
-
- private static class MessagePublishInfoImpl implements MessagePublishInfo
- {
- private AMQShortString _exchange;
- private final boolean _immediate;
- private final boolean _mandatory;
- private final AMQShortString _routingKey;
-
- public MessagePublishInfoImpl(final AMQShortString exchange,
- final boolean immediate,
- final boolean mandatory,
- final AMQShortString routingKey)
- {
- _exchange = exchange;
- _immediate = immediate;
- _mandatory = mandatory;
- _routingKey = routingKey;
- }
-
- public AMQShortString getExchange()
- {
- return _exchange;
- }
-
- public void setExchange(AMQShortString exchange)
- {
- _exchange = exchange;
- }
-
- public boolean isImmediate()
- {
- return _immediate;
- }
-
- public boolean isMandatory()
- {
- return _mandatory;
- }
-
- public AMQShortString getRoutingKey()
- {
- return _routingKey;
- }
- }
}
diff --git a/java/common/src/main/java/org/apache/qpid/pool/Event.java b/java/common/src/main/java/org/apache/qpid/pool/Event.java
deleted file mode 100644
index 5996cbf89c..0000000000
--- a/java/common/src/main/java/org/apache/qpid/pool/Event.java
+++ /dev/null
@@ -1,155 +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.
- *
- */
-package org.apache.qpid.pool;
-
-import org.apache.mina.common.IoFilter;
-import org.apache.mina.common.IoSession;
-
-/**
- * An Event is a continuation, which is used to break a Mina filter chain and save the current point in the chain
- * for later processing. It is an abstract class, with different implementations for continuations of different kinds
- * of Mina events.
- *
- * <p/>These continuations are typically batched by {@link Job} for processing by a worker thread pool.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Process a continuation in the context of a Mina session.
- * </table>
- *
- * @todo Pull up _nextFilter and getNextFilter into Event, as all events use it. Inner classes need to be non-static
- * to use instance variables in the parent. Consequently they need to be non-inner to be instantiable outside of
- * the context of the outer Event class. The inner class construction used here is preventing common code re-use
- * (though not by a huge amount), but makes for an inelegent way of handling inheritance and doesn't seem like
- * a justifiable use of inner classes. Move the inner classes out into their own files.
- *
- * @todo Could make Event implement Runnable, FutureTask, or a custom Continuation interface, to clarify its status as
- * a continuation. Job is also a continuation, as is the job completion handler. Or, as Event is totally abstract,
- * it is really an interface, so could just drop it and use the continuation interface instead.
- */
-public abstract class Event
-{
- /**
- * Creates a continuation.
- */
- public Event()
- { }
-
- /**
- * Processes the continuation in the context of a Mina session.
- *
- * @param session The Mina session.
- */
- public abstract void process(IoSession session);
-
- /**
- * A continuation ({@link Event}) that takes a Mina messageReceived event, and passes it to a NextFilter.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Pass a Mina messageReceived event to a NextFilter. <td> {@link IoFilter.NextFilter}, {@link IoSession}
- * </table>
- */
- public static final class ReceivedEvent extends Event
- {
- private final Object _data;
-
- private final IoFilter.NextFilter _nextFilter;
-
- public ReceivedEvent(final IoFilter.NextFilter nextFilter, final Object data)
- {
- super();
- _nextFilter = nextFilter;
- _data = data;
- }
-
- public void process(IoSession session)
- {
- _nextFilter.messageReceived(session, _data);
- }
-
- public IoFilter.NextFilter getNextFilter()
- {
- return _nextFilter;
- }
- }
-
- /**
- * A continuation ({@link Event}) that takes a Mina filterWrite event, and passes it to a NextFilter.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Pass a Mina filterWrite event to a NextFilter.
- * <td> {@link IoFilter.NextFilter}, {@link IoFilter.WriteRequest}, {@link IoSession}
- * </table>
- */
- public static final class WriteEvent extends Event
- {
- private final IoFilter.WriteRequest _data;
- private final IoFilter.NextFilter _nextFilter;
-
- public WriteEvent(final IoFilter.NextFilter nextFilter, final IoFilter.WriteRequest data)
- {
- super();
- _nextFilter = nextFilter;
- _data = data;
- }
-
- public void process(IoSession session)
- {
- _nextFilter.filterWrite(session, _data);
- }
-
- public IoFilter.NextFilter getNextFilter()
- {
- return _nextFilter;
- }
- }
-
- /**
- * A continuation ({@link Event}) that takes a Mina sessionClosed event, and passes it to a NextFilter.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Pass a Mina sessionClosed event to a NextFilter. <td> {@link IoFilter.NextFilter}, {@link IoSession}
- * </table>
- */
- public static final class CloseEvent extends Event
- {
- private final IoFilter.NextFilter _nextFilter;
-
- public CloseEvent(final IoFilter.NextFilter nextFilter)
- {
- super();
- _nextFilter = nextFilter;
- }
-
- public void process(IoSession session)
- {
- _nextFilter.sessionClosed(session);
- }
-
- public IoFilter.NextFilter getNextFilter()
- {
- return _nextFilter;
- }
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/pool/Job.java b/java/common/src/main/java/org/apache/qpid/pool/Job.java
index 00da005515..82b600de88 100644
--- a/java/common/src/main/java/org/apache/qpid/pool/Job.java
+++ b/java/common/src/main/java/org/apache/qpid/pool/Job.java
@@ -21,9 +21,12 @@
package org.apache.qpid.pool;
import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
-import org.apache.mina.common.IoSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* A Job is a continuation that batches together other continuations, specifically {@link Event}s, into one continuation.
@@ -52,35 +55,28 @@ import org.apache.mina.common.IoSession;
*/
public class Job implements ReadWriteRunnable
{
+
+ /** Defines the maximum number of events that will be batched into a single job. */
+ public static final int MAX_JOB_EVENTS = Integer.getInteger("amqj.server.read_write_pool.max_events", 10);
+
/** The maximum number of events to process per run of the job. More events than this may be queued in the job. */
private final int _maxEvents;
- /** The Mina session. */
- private final IoSession _session;
-
/** Holds the queue of events that make up the job. */
- private final java.util.Queue<Event> _eventQueue = new ConcurrentLinkedQueue<Event>();
+ private final java.util.Queue<Runnable> _eventQueue = new ConcurrentLinkedQueue<Runnable>();
/** Holds a status flag, that indicates when the job is actively running. */
private final AtomicBoolean _active = new AtomicBoolean();
- /** Holds the completion continuation, called upon completion of a run of the job. */
- private final JobCompletionHandler _completionHandler;
-
private final boolean _readJob;
- /**
- * Creates a new job that aggregates many continuations together.
- *
- * @param session The Mina session.
- * @param completionHandler The per job run, terminal continuation.
- * @param maxEvents The maximum number of aggregated continuations to process per run of the job.
- * @param readJob
- */
- Job(IoSession session, JobCompletionHandler completionHandler, int maxEvents, final boolean readJob)
+ private ReferenceCountingExecutorService _poolReference;
+
+ private final static Logger _logger = LoggerFactory.getLogger(Job.class);
+
+ public Job(ReferenceCountingExecutorService poolReference, int maxEvents, boolean readJob)
{
- _session = session;
- _completionHandler = completionHandler;
+ _poolReference = poolReference;
_maxEvents = maxEvents;
_readJob = readJob;
}
@@ -90,7 +86,7 @@ public class Job implements ReadWriteRunnable
*
* @param evt The continuation to enqueue.
*/
- void add(Event evt)
+ public void add(Runnable evt)
{
_eventQueue.add(evt);
}
@@ -104,14 +100,14 @@ public class Job implements ReadWriteRunnable
int i = _maxEvents;
while( --i != 0 )
{
- Event e = _eventQueue.poll();
+ Runnable e = _eventQueue.poll();
if (e == null)
{
return true;
}
else
{
- e.process(_session);
+ e.run();
}
}
return false;
@@ -153,40 +149,105 @@ public class Job implements ReadWriteRunnable
if(processAll())
{
deactivate();
- _completionHandler.completed(_session, this);
+ completed();
}
else
{
- _completionHandler.notCompleted(_session, this);
+ notCompleted();
}
}
- public boolean isReadJob()
- {
- return _readJob;
- }
-
public boolean isRead()
{
return _readJob;
}
-
- public boolean isWrite()
+
+ /**
+ * Adds an {@link Event} to a {@link Job}, triggering the execution of the job if it is not already running.
+ *
+ * @param job The job.
+ * @param event The event to hand off asynchronously.
+ */
+ public static void fireAsynchEvent(ExecutorService pool, Job job, Runnable event)
{
- return !_readJob;
- }
+ job.add(event);
+
+
+ if(pool == null)
+ {
+ return;
+ }
+
+ // rather than perform additional checks on pool to check that it hasn't shutdown.
+ // catch the RejectedExecutionException that will result from executing on a shutdown pool
+ if (job.activate())
+ {
+ try
+ {
+ pool.execute(job);
+ }
+ catch(RejectedExecutionException e)
+ {
+ _logger.warn("Thread pool shutdown while tasks still outstanding");
+ }
+ }
+ }
+
/**
- * Another interface for a continuation.
+ * Implements a terminal continuation for the {@link Job} for this filter. Whenever the Job completes its processing
+ * of a batch of events this is called. This method simply re-activates the job, if it has more events to process.
*
- * @todo Get rid of this interface as there are other interfaces that could be used instead, such as FutureTask,
- * Runnable or a custom Continuation interface.
+ * @param session The Mina session to work in.
+ * @param job The job that completed.
*/
- static interface JobCompletionHandler
+ public void completed()
+ {
+ if (!isComplete())
+ {
+ final ExecutorService pool = _poolReference.getPool();
+
+ if(pool == null)
+ {
+ return;
+ }
+
+
+ // ritchiem : 2006-12-13 Do we need to perform the additional checks here?
+ // Can the pool be shutdown at this point?
+ if (activate())
+ {
+ try
+ {
+ pool.execute(this);
+ }
+ catch(RejectedExecutionException e)
+ {
+ _logger.warn("Thread pool shutdown while tasks still outstanding");
+ }
+
+ }
+ }
+ }
+
+ public void notCompleted()
{
- public void completed(IoSession session, Job job);
+ final ExecutorService pool = _poolReference.getPool();
+
+ if(pool == null)
+ {
+ return;
+ }
- public void notCompleted(final IoSession session, final Job job);
+ try
+ {
+ pool.execute(this);
+ }
+ catch(RejectedExecutionException e)
+ {
+ _logger.warn("Thread pool shutdown while tasks still outstanding");
+ }
}
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/pool/PoolingFilter.java b/java/common/src/main/java/org/apache/qpid/pool/PoolingFilter.java
deleted file mode 100644
index a080cc7e04..0000000000
--- a/java/common/src/main/java/org/apache/qpid/pool/PoolingFilter.java
+++ /dev/null
@@ -1,491 +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.
- *
- */
-package org.apache.qpid.pool;
-
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import org.apache.mina.common.IdleStatus;
-import org.apache.mina.common.IoFilterAdapter;
-import org.apache.mina.common.IoSession;
-import org.apache.qpid.pool.Event.CloseEvent;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.ExecutorService;
-
-/**
- * PoolingFilter, is a no-op pass through filter that hands all events down the Mina filter chain by default. As it
- * adds no behaviour by default to the filter chain, it is abstract.
- *
- * <p/>PoolingFilter provides a capability, available to sub-classes, to handle events in the chain asynchronously, by
- * adding them to a job. If a job is not active, adding an event to it activates it. If it is active, the event is
- * added to the job, which will run to completion and eventually process the event. The queue on the job itself acts as
- * a buffer between stages of the pipeline.
- *
- * <p/>There are two convenience methods, {@link #createAynschReadPoolingFilter} and
- * {@link #createAynschWritePoolingFilter}, for obtaining pooling filters that handle 'messageReceived' and
- * 'filterWrite' events, making it possible to process these event streams seperately.
- *
- * <p/>Pooling filters have a name, in order to distinguish different filter types. They set up a {@link Job} on the
- * Mina session they are working with, and store it in the session against their identifying name. This allows different
- * filters with different names to be set up on the same filter chain, on the same Mina session, that batch their
- * workloads in different jobs.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Implement default, pass through filter.
- * <tr><td> Create pooling filters and a specific thread pool. <td> {@link ReferenceCountingExecutorService}
- * <tr><td> Provide the ability to batch Mina events for asynchronous processing. <td> {@link Job}, {@link Event}
- * <tr><td> Provide a terminal continuation to keep jobs running till empty.
- * <td> {@link Job}, {@link Job.JobCompletionHandler}
- * </table>
- *
- * @todo The static helper methods are pointless. Could just call new.
- */
-public abstract class PoolingFilter extends IoFilterAdapter implements Job.JobCompletionHandler
-{
- /** Used for debugging purposes. */
- private static final Logger _logger = LoggerFactory.getLogger(PoolingFilter.class);
-
- /** Holds the managed reference to obtain the executor for the batched jobs. */
- private final ReferenceCountingExecutorService _poolReference;
-
- /** Used to hold a name for identifying differeny pooling filter types. */
- private final String _name;
-
- /** Defines the maximum number of events that will be batched into a single job. */
- static final int MAX_JOB_EVENTS = Integer.getInteger("amqj.server.read_write_pool.max_events", 10);
-
- private final int _maxEvents;
-
- private final boolean _readFilter;
-
- /**
- * Creates a named pooling filter, on the specified shared thread pool.
- *
- * @param refCountingPool The thread pool reference.
- * @param name The identifying name of the filter type.
- */
- public PoolingFilter(ReferenceCountingExecutorService refCountingPool, String name, int maxEvents, boolean readFilter)
- {
- _poolReference = refCountingPool;
- _name = name;
- _maxEvents = maxEvents;
- _readFilter = readFilter;
- }
-
- /**
- * Helper method to get an instance of a pooling filter that handles read events asynchronously.
- *
- * @param refCountingPool A managed reference to the thread pool.
- * @param name The filter types identifying name.
- *
- * @return A pooling filter for asynchronous read events.
- */
- public static PoolingFilter createAynschReadPoolingFilter(ReferenceCountingExecutorService refCountingPool, String name)
- {
- return new AsynchReadPoolingFilter(refCountingPool, name);
- }
-
- /**
- * Helper method to get an instance of a pooling filter that handles write events asynchronously.
- *
- * @param refCountingPool A managed reference to the thread pool.
- * @param name The filter types identifying name.
- *
- * @return A pooling filter for asynchronous write events.
- */
- public static PoolingFilter createAynschWritePoolingFilter(ReferenceCountingExecutorService refCountingPool, String name)
- {
- return new AsynchWritePoolingFilter(refCountingPool, name);
- }
-
- /**
- * Called by Mina to initialize this filter. Takes a reference to the thread pool.
- */
- public void init()
- {
- _logger.debug("Init called on PoolingFilter " + toString());
-
- // Called when the filter is initialised in the chain. If the reference count is
- // zero this acquire will initialise the pool.
- _poolReference.acquireExecutorService();
- }
-
- /**
- * Called by Mina to clean up this filter. Releases the reference to the thread pool.
- */
- public void destroy()
- {
- _logger.debug("Destroy called on PoolingFilter " + toString());
-
- // When the reference count gets to zero we release the executor service.
- _poolReference.releaseExecutorService();
- }
-
- /**
- * Adds an {@link Event} to a {@link Job}, triggering the execution of the job if it is not already running.
- *
- * @param job The job.
- * @param event The event to hand off asynchronously.
- */
- void fireAsynchEvent(Job job, Event event)
- {
-
- job.add(event);
-
- final ExecutorService pool = _poolReference.getPool();
-
- if(pool == null)
- {
- return;
- }
-
- // rather than perform additional checks on pool to check that it hasn't shutdown.
- // catch the RejectedExecutionException that will result from executing on a shutdown pool
- if (job.activate())
- {
- try
- {
- pool.execute(job);
- }
- catch(RejectedExecutionException e)
- {
- _logger.warn("Thread pool shutdown while tasks still outstanding");
- }
- }
-
- }
-
- /**
- * Creates a Job on the Mina session, identified by this filters name, in which this filter places asynchronously
- * handled events.
- *
- * @param session The Mina session.
- */
- public void createNewJobForSession(IoSession session)
- {
- Job job = new Job(session, this, MAX_JOB_EVENTS,_readFilter);
- session.setAttribute(_name, job);
- }
-
- /**
- * Retrieves this filters Job, by this filters name, from the Mina session.
- *
- * @param session The Mina session.
- *
- * @return The Job for this filter to place asynchronous events into.
- */
- public Job getJobForSession(IoSession session)
- {
- return (Job) session.getAttribute(_name);
- }
-
- /**
- * Implements a terminal continuation for the {@link Job} for this filter. Whenever the Job completes its processing
- * of a batch of events this is called. This method simply re-activates the job, if it has more events to process.
- *
- * @param session The Mina session to work in.
- * @param job The job that completed.
- */
- public void completed(IoSession session, Job job)
- {
-
-
- if (!job.isComplete())
- {
- final ExecutorService pool = _poolReference.getPool();
-
- if(pool == null)
- {
- return;
- }
-
-
- // ritchiem : 2006-12-13 Do we need to perform the additional checks here?
- // Can the pool be shutdown at this point?
- if (job.activate())
- {
- try
- {
- pool.execute(job);
- }
- catch(RejectedExecutionException e)
- {
- _logger.warn("Thread pool shutdown while tasks still outstanding");
- }
-
- }
- }
- }
-
- public void notCompleted(IoSession session, Job job)
- {
- final ExecutorService pool = _poolReference.getPool();
-
- if(pool == null)
- {
- return;
- }
-
- try
- {
- pool.execute(job);
- }
- catch(RejectedExecutionException e)
- {
- _logger.warn("Thread pool shutdown while tasks still outstanding");
- }
-
- }
-
-
-
- /**
- * No-op pass through filter to the next filter in the chain.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- *
- * @throws Exception This method does not throw any exceptions, but has Exception in its signature to allow
- * overriding sub-classes the ability to.
- */
- public void sessionOpened(final NextFilter nextFilter, final IoSession session) throws Exception
- {
- nextFilter.sessionOpened(session);
- }
-
- /**
- * No-op pass through filter to the next filter in the chain.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- *
- * @throws Exception This method does not throw any exceptions, but has Exception in its signature to allow
- * overriding sub-classes the ability to.
- */
- public void sessionClosed(final NextFilter nextFilter, final IoSession session) throws Exception
- {
- nextFilter.sessionClosed(session);
- }
-
- /**
- * No-op pass through filter to the next filter in the chain.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- * @param status The session idle status.
- *
- * @throws Exception This method does not throw any exceptions, but has Exception in its signature to allow
- * overriding sub-classes the ability to.
- */
- public void sessionIdle(final NextFilter nextFilter, final IoSession session, final IdleStatus status) throws Exception
- {
- nextFilter.sessionIdle(session, status);
- }
-
- /**
- * No-op pass through filter to the next filter in the chain.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- * @param cause The underlying exception.
- *
- * @throws Exception This method does not throw any exceptions, but has Exception in its signature to allow
- * overriding sub-classes the ability to.
- */
- public void exceptionCaught(final NextFilter nextFilter, final IoSession session, final Throwable cause) throws Exception
- {
- nextFilter.exceptionCaught(session, cause);
- }
-
- /**
- * No-op pass through filter to the next filter in the chain.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- * @param message The message received.
- *
- * @throws Exception This method does not throw any exceptions, but has Exception in its signature to allow
- * overriding sub-classes the ability to.
- */
- public void messageReceived(final NextFilter nextFilter, final IoSession session, final Object message) throws Exception
- {
- nextFilter.messageReceived(session, message);
- }
-
- /**
- * No-op pass through filter to the next filter in the chain.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- * @param message The message sent.
- *
- * @throws Exception This method does not throw any exceptions, but has Exception in its signature to allow
- * overriding sub-classes the ability to.
- */
- public void messageSent(final NextFilter nextFilter, final IoSession session, final Object message) throws Exception
- {
- nextFilter.messageSent(session, message);
- }
-
- /**
- * No-op pass through filter to the next filter in the chain.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- * @param writeRequest The write request event.
- *
- * @throws Exception This method does not throw any exceptions, but has Exception in its signature to allow
- * overriding sub-classes the ability to.
- */
- public void filterWrite(final NextFilter nextFilter, final IoSession session, final WriteRequest writeRequest)
- throws Exception
- {
- nextFilter.filterWrite(session, writeRequest);
- }
-
- /**
- * No-op pass through filter to the next filter in the chain.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- *
- * @throws Exception This method does not throw any exceptions, but has Exception in its signature to allow
- * overriding sub-classes the ability to.
- */
- public void filterClose(NextFilter nextFilter, IoSession session) throws Exception
- {
- nextFilter.filterClose(session);
- }
-
- /**
- * No-op pass through filter to the next filter in the chain.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- *
- * @throws Exception This method does not throw any exceptions, but has Exception in its signature to allow
- * overriding sub-classes the ability to.
- */
- public void sessionCreated(NextFilter nextFilter, IoSession session) throws Exception
- {
- nextFilter.sessionCreated(session);
- }
-
- /**
- * Prints the filter types identifying name to a string, mainly for debugging purposes.
- *
- * @return The filter types identifying name.
- */
- public String toString()
- {
- return _name;
- }
-
- /**
- * AsynchReadPoolingFilter is a pooling filter that handles 'messageReceived' and 'sessionClosed' events
- * asynchronously.
- */
- public static class AsynchReadPoolingFilter extends PoolingFilter
- {
- /**
- * Creates a pooling filter that handles read events asynchronously.
- *
- * @param refCountingPool A managed reference to the thread pool.
- * @param name The filter types identifying name.
- */
- public AsynchReadPoolingFilter(ReferenceCountingExecutorService refCountingPool, String name)
- {
- super(refCountingPool, name, Integer.getInteger("amqj.server.read_write_pool.max_read_events", MAX_JOB_EVENTS),true);
- }
-
- /**
- * Hands off this event for asynchronous execution.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- * @param message The message received.
- */
- public void messageReceived(NextFilter nextFilter, final IoSession session, Object message)
- {
- Job job = getJobForSession(session);
- fireAsynchEvent(job, new Event.ReceivedEvent(nextFilter, message));
- }
-
- /**
- * Hands off this event for asynchronous execution.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- */
- public void sessionClosed(final NextFilter nextFilter, final IoSession session)
- {
- Job job = getJobForSession(session);
- fireAsynchEvent(job, new CloseEvent(nextFilter));
- }
- }
-
- /**
- * AsynchWritePoolingFilter is a pooling filter that handles 'filterWrite' and 'sessionClosed' events
- * asynchronously.
- */
- public static class AsynchWritePoolingFilter extends PoolingFilter
- {
- /**
- * Creates a pooling filter that handles write events asynchronously.
- *
- * @param refCountingPool A managed reference to the thread pool.
- * @param name The filter types identifying name.
- */
- public AsynchWritePoolingFilter(ReferenceCountingExecutorService refCountingPool, String name)
- {
- super(refCountingPool, name, Integer.getInteger("amqj.server.read_write_pool.max_write_events", MAX_JOB_EVENTS),false);
- }
-
- /**
- * Hands off this event for asynchronous execution.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- * @param writeRequest The write request event.
- */
- public void filterWrite(final NextFilter nextFilter, final IoSession session, final WriteRequest writeRequest)
- {
- Job job = getJobForSession(session);
- fireAsynchEvent(job, new Event.WriteEvent(nextFilter, writeRequest));
- }
-
- /**
- * Hands off this event for asynchronous execution.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- */
- public void sessionClosed(final NextFilter nextFilter, final IoSession session)
- {
- Job job = getJobForSession(session);
- fireAsynchEvent(job, new CloseEvent(nextFilter));
- }
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/pool/ReadWriteRunnable.java b/java/common/src/main/java/org/apache/qpid/pool/ReadWriteRunnable.java
index ad04a923e1..140c93ca8d 100644
--- a/java/common/src/main/java/org/apache/qpid/pool/ReadWriteRunnable.java
+++ b/java/common/src/main/java/org/apache/qpid/pool/ReadWriteRunnable.java
@@ -23,5 +23,4 @@ package org.apache.qpid.pool;
public interface ReadWriteRunnable extends Runnable
{
boolean isRead();
- boolean isWrite();
}
diff --git a/java/common/src/main/java/org/apache/qpid/pool/ReadWriteThreadModel.java b/java/common/src/main/java/org/apache/qpid/pool/ReadWriteThreadModel.java
deleted file mode 100644
index 8cea70e597..0000000000
--- a/java/common/src/main/java/org/apache/qpid/pool/ReadWriteThreadModel.java
+++ /dev/null
@@ -1,102 +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.
- *
- */
-package org.apache.qpid.pool;
-
-import org.apache.mina.common.IoFilterChain;
-import org.apache.mina.common.ThreadModel;
-import org.apache.mina.filter.ReferenceCountingIoFilter;
-
-/**
- * ReadWriteThreadModel is a Mina i/o filter chain factory, which creates a filter chain with seperate filters to
- * handle read and write events. The seperate filters are {@link PoolingFilter}s, which have thread pools to handle
- * these events. The effect of this is that reading and writing may happen concurrently.
- *
- * <p/>Socket i/o will only happen with concurrent reads and writes if Mina has seperate selector threads for each.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Create a filter chain with seperate read and write thread pools for read/write Mina events.
- * <td> {@link PoolingFilter}
- * </table>
- */
-public class ReadWriteThreadModel implements ThreadModel
-{
- /** Holds the singleton instance of this factory. */
- private static final ReadWriteThreadModel _instance = new ReadWriteThreadModel();
-
- /** Holds the thread pooling filter for reads. */
- private final PoolingFilter _asynchronousReadFilter;
-
- /** Holds the thread pooloing filter for writes. */
- private final PoolingFilter _asynchronousWriteFilter;
-
- /**
- * Creates a new factory for concurrent i/o, thread pooling filter chain construction. This is private, so that
- * only a singleton instance of the factory is ever created.
- */
- private ReadWriteThreadModel()
- {
- final ReferenceCountingExecutorService executor = ReferenceCountingExecutorService.getInstance();
- _asynchronousReadFilter = PoolingFilter.createAynschReadPoolingFilter(executor, "AsynchronousReadFilter");
- _asynchronousWriteFilter = PoolingFilter.createAynschWritePoolingFilter(executor, "AsynchronousWriteFilter");
- }
-
- /**
- * Gets the singleton instance of this filter chain factory.
- *
- * @return The singleton instance of this filter chain factory.
- */
- public static ReadWriteThreadModel getInstance()
- {
- return _instance;
- }
-
- /**
- * Gets the read filter.
- *
- * @return The read filter.
- */
- public PoolingFilter getAsynchronousReadFilter()
- {
- return _asynchronousReadFilter;
- }
-
- /**
- * Gets the write filter.
- *
- * @return The write filter.
- */
- public PoolingFilter getAsynchronousWriteFilter()
- {
- return _asynchronousWriteFilter;
- }
-
- /**
- * Adds the concurrent read and write filters to a filter chain.
- *
- * @param chain The Mina filter chain to add to.
- */
- public void buildFilterChain(IoFilterChain chain)
- {
- chain.addFirst("AsynchronousReadFilter", new ReferenceCountingIoFilter(_asynchronousReadFilter));
- chain.addLast("AsynchronousWriteFilter", new ReferenceCountingIoFilter(_asynchronousWriteFilter));
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java b/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java
index ce9c6ae4cb..20a30b3ed3 100644
--- a/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java
+++ b/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java
@@ -160,4 +160,13 @@ public class ReferenceCountingExecutorService
{
return _pool;
}
+
+ /**
+ * Return the ReferenceCount to this ExecutorService
+ * @return reference count
+ */
+ public int getReferenceCount()
+ {
+ return _refCount;
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngine.java b/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngine.java
new file mode 100644
index 0000000000..31953ea6ab
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngine.java
@@ -0,0 +1,61 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.protocol;
+
+import java.net.SocketAddress;
+
+import org.apache.qpid.framing.AMQDataBlock;
+import org.apache.qpid.transport.NetworkDriver;
+import org.apache.qpid.transport.Receiver;
+
+/**
+ * A ProtocolEngine is a Receiver for java.nio.ByteBuffers. It takes the data passed to it in the received
+ * decodes it and then process the result.
+ */
+public interface ProtocolEngine extends Receiver<java.nio.ByteBuffer>
+{
+ // Sets the network driver providing data for this ProtocolEngine
+ void setNetworkDriver (NetworkDriver driver);
+
+ // Returns the remote address of the NetworkDriver
+ SocketAddress getRemoteAddress();
+
+ // Returns the local address of the NetworkDriver
+ SocketAddress getLocalAddress();
+
+ // Returns number of bytes written
+ long getWrittenBytes();
+
+ // Returns number of bytes read
+ long getReadBytes();
+
+ // Called by the NetworkDriver when the socket has been closed for reading
+ void closed();
+
+ // Called when the NetworkEngine has not written data for the specified period of time (will trigger a
+ // heartbeat)
+ void writerIdle();
+
+ // Called when the NetworkEngine has not read data for the specified period of time (will close the connection)
+ void readerIdle();
+
+
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngineFactory.java b/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngineFactory.java
new file mode 100644
index 0000000000..9df84eef90
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngineFactory.java
@@ -0,0 +1,31 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.protocol;
+
+import org.apache.qpid.transport.NetworkDriver;
+
+public interface ProtocolEngineFactory
+{
+
+ // Returns a new instance of a ProtocolEngine
+ ProtocolEngine newProtocolEngine(NetworkDriver networkDriver);
+
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/security/CallbackHandlerRegistry.java b/java/common/src/main/java/org/apache/qpid/security/CallbackHandlerRegistry.java
deleted file mode 100644
index 8c80a1b5b7..0000000000
--- a/java/common/src/main/java/org/apache/qpid/security/CallbackHandlerRegistry.java
+++ /dev/null
@@ -1,94 +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.
- *
- */
-package org.apache.qpid.security;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.qpid.QpidConfig;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class CallbackHandlerRegistry
-{
- private static final Logger _logger = LoggerFactory.getLogger(CallbackHandlerRegistry.class);
- private static CallbackHandlerRegistry _instance = new CallbackHandlerRegistry();
-
- private Map<String,Class> _mechanismToHandlerClassMap = new HashMap<String,Class>();
-
- private StringBuilder _mechanisms;
-
- public static CallbackHandlerRegistry getInstance()
- {
- return _instance;
- }
-
- public Class getCallbackHandlerClass(String mechanism)
- {
- return _mechanismToHandlerClassMap.get(mechanism);
- }
-
- public String getMechanisms()
- {
- return _mechanisms.toString();
- }
-
- private CallbackHandlerRegistry()
- {
- // first we register any Sasl client factories
- DynamicSaslRegistrar.registerSaslProviders();
- registerMechanisms();
- }
-
- private void registerMechanisms()
- {
- for (QpidConfig.SecurityMechanism securityMechanism: QpidConfig.get().getSecurityMechanisms() )
- {
- Class clazz = null;
- try
- {
- clazz = Class.forName(securityMechanism.getHandler());
- if (!AMQPCallbackHandler.class.isAssignableFrom(clazz))
- {
- _logger.debug("SASL provider " + clazz + " does not implement " + AMQPCallbackHandler.class +
- ". Skipping");
- continue;
- }
- _mechanismToHandlerClassMap.put(securityMechanism.getType(), clazz);
- if (_mechanisms == null)
- {
-
- _mechanisms = new StringBuilder();
- _mechanisms.append(securityMechanism.getType());
- }
- else
- {
- _mechanisms.append(" " + securityMechanism.getType());
- }
- }
- catch (ClassNotFoundException ex)
- {
- _logger.debug("Unable to load class " + securityMechanism.getHandler() + ". Skipping that SASL provider");
- continue;
- }
- }
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/security/DynamicSaslRegistrar.java b/java/common/src/main/java/org/apache/qpid/security/DynamicSaslRegistrar.java
deleted file mode 100644
index 9f48ac96a3..0000000000
--- a/java/common/src/main/java/org/apache/qpid/security/DynamicSaslRegistrar.java
+++ /dev/null
@@ -1,74 +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.
- *
- */
-package org.apache.qpid.security;
-
-import java.security.Security;
-import java.util.Map;
-import java.util.TreeMap;
-
-import javax.security.sasl.SaslClientFactory;
-
-import org.apache.qpid.QpidConfig;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class DynamicSaslRegistrar
-{
- private static final Logger _logger = LoggerFactory.getLogger(DynamicSaslRegistrar.class);
-
- public static void registerSaslProviders()
- {
- Map<String, Class> factories = registerSaslClientFactories();
- if (factories.size() > 0)
- {
- Security.addProvider(new JCAProvider(factories));
- _logger.debug("Dynamic SASL provider added as a security provider");
- }
- }
-
- private static Map<String, Class> registerSaslClientFactories()
- {
- TreeMap<String, Class> factoriesToRegister =
- new TreeMap<String, Class>();
-
- for (QpidConfig.SaslClientFactory factory: QpidConfig.get().getSaslClientFactories())
- {
- String className = factory.getFactoryClass();
- try
- {
- Class clazz = Class.forName(className);
- if (!(SaslClientFactory.class.isAssignableFrom(clazz)))
- {
- _logger.debug("Class " + clazz + " does not implement " + SaslClientFactory.class + " - skipping");
- continue;
- }
- factoriesToRegister.put(factory.getType(), clazz);
- }
- catch (Exception ex)
- {
- _logger.debug("Error instantiating SaslClientFactory calss " + className + " - skipping");
- }
- }
- return factoriesToRegister;
- }
-
-
-}
diff --git a/java/common/src/main/java/org/apache/qpid/security/JCAProvider.java b/java/common/src/main/java/org/apache/qpid/security/JCAProvider.java
deleted file mode 100644
index 033deb550c..0000000000
--- a/java/common/src/main/java/org/apache/qpid/security/JCAProvider.java
+++ /dev/null
@@ -1,44 +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.
- *
- */
-package org.apache.qpid.security;
-
-import java.security.Provider;
-import java.security.Security;
-import java.util.Map;
-
-public class JCAProvider extends Provider
-{
- public JCAProvider(Map<String, Class> providerMap)
- {
- super("AMQSASLProvider", 1.0, "A JCA provider that registers all " +
- "AMQ SASL providers that want to be registered");
- register(providerMap);
- Security.addProvider(this);
- }
-
- private void register(Map<String, Class> providerMap)
- {
- for (Map.Entry<String, Class> me :providerMap.entrySet())
- {
- put("SaslClientFactory." + me.getKey(), me.getValue().getName());
- }
- }
-} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/security/amqplain/AmqPlainSaslClient.java b/java/common/src/main/java/org/apache/qpid/security/amqplain/AmqPlainSaslClient.java
deleted file mode 100644
index 81acc66de4..0000000000
--- a/java/common/src/main/java/org/apache/qpid/security/amqplain/AmqPlainSaslClient.java
+++ /dev/null
@@ -1,105 +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.
- *
- */
-package org.apache.qpid.security.amqplain;
-
-import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.framing.FieldTableFactory;
-
-import javax.security.sasl.SaslClient;
-import javax.security.sasl.SaslException;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.Callback;
-
-/**
- * Implements the "AMQPlain" authentication protocol that uses FieldTables to send username and pwd.
- *
- */
-public class AmqPlainSaslClient implements SaslClient
-{
- /**
- * The name of this mechanism
- */
- public static final String MECHANISM = "AMQPLAIN";
-
- private CallbackHandler _cbh;
-
- public AmqPlainSaslClient(CallbackHandler cbh)
- {
- _cbh = cbh;
- }
-
- public String getMechanismName()
- {
- return "AMQPLAIN";
- }
-
- public boolean hasInitialResponse()
- {
- return true;
- }
-
- public byte[] evaluateChallenge(byte[] challenge) throws SaslException
- {
- // we do not care about the prompt or the default name
- NameCallback nameCallback = new NameCallback("prompt", "defaultName");
- PasswordCallback pwdCallback = new PasswordCallback("prompt", false);
- Callback[] callbacks = new Callback[]{nameCallback, pwdCallback};
- try
- {
- _cbh.handle(callbacks);
- }
- catch (Exception e)
- {
- throw new SaslException("Error handling SASL callbacks: " + e, e);
- }
- FieldTable table = FieldTableFactory.newFieldTable();
- table.setString("LOGIN", nameCallback.getName());
- table.setString("PASSWORD", new String(pwdCallback.getPassword()));
- return table.getDataAsBytes();
- }
-
- public boolean isComplete()
- {
- return true;
- }
-
- public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException
- {
- throw new SaslException("Not supported");
- }
-
- public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException
- {
- throw new SaslException("Not supported");
- }
-
- public Object getNegotiatedProperty(String propName)
- {
- return null;
- }
-
- public void dispose() throws SaslException
- {
- _cbh = null;
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/security/amqplain/AmqPlainSaslClientFactory.java b/java/common/src/main/java/org/apache/qpid/security/amqplain/AmqPlainSaslClientFactory.java
deleted file mode 100644
index 6c66c87f4c..0000000000
--- a/java/common/src/main/java/org/apache/qpid/security/amqplain/AmqPlainSaslClientFactory.java
+++ /dev/null
@@ -1,62 +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.
- *
- */
-package org.apache.qpid.security.amqplain;
-
-import javax.security.sasl.SaslClientFactory;
-import javax.security.sasl.SaslClient;
-import javax.security.sasl.SaslException;
-import javax.security.sasl.Sasl;
-import javax.security.auth.callback.CallbackHandler;
-import java.util.Map;
-
-public class AmqPlainSaslClientFactory implements SaslClientFactory
-{
- public SaslClient createSaslClient(String[] mechanisms, String authorizationId, String protocol, String serverName, Map props, CallbackHandler cbh) throws SaslException
- {
- for (int i = 0; i < mechanisms.length; i++)
- {
- if (mechanisms[i].equals(AmqPlainSaslClient.MECHANISM))
- {
- if (cbh == null)
- {
- throw new SaslException("CallbackHandler must not be null");
- }
- return new AmqPlainSaslClient(cbh);
- }
- }
- return null;
- }
-
- public String[] getMechanismNames(Map props)
- {
- if (props.containsKey(Sasl.POLICY_NOPLAINTEXT) ||
- props.containsKey(Sasl.POLICY_NODICTIONARY) ||
- props.containsKey(Sasl.POLICY_NOACTIVE))
- {
- // returned array must be non null according to interface documentation
- return new String[0];
- }
- else
- {
- return new String[]{AmqPlainSaslClient.MECHANISM};
- }
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java b/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java
index 950279fff1..e142d21e06 100644
--- a/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java
+++ b/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java
@@ -41,38 +41,74 @@ public class SSLContextFactory {
/**
* Path to the Java keystore file
*/
- private String _keystorePath;
+ private String _keyStorePath;
/**
* Password for the keystore
*/
- private String _keystorePassword;
+ private String _keyStorePassword;
/**
- * Cert type to use
+ * Cert type to use in keystore
*/
- private String _certType;
+ private String _keyStoreCertType;
/**
+ * Path to the Java truststore file
+ */
+ private String _trustStorePath;
+
+ /**
+ * Password for the truststore
+ */
+ private String _trustStorePassword;
+
+ /**
+ * Cert type to use in truststore
+ */
+ private String _trustStoreCertType;
+
+
+
+ public SSLContextFactory(String trustStorePath, String trustStorePassword,
+ String trustStoreCertType)
+ {
+ this(trustStorePath,trustStorePassword,trustStoreCertType,
+ trustStorePath,trustStorePassword,trustStoreCertType);
+ }
+
+ /**
* Create a factory instance
* @param keystorePath path to the Java keystore file
* @param keystorePassword password for the Java keystore
* @param certType certificate type
*/
- public SSLContextFactory(String keystorePath, String keystorePassword,
- String certType)
+ public SSLContextFactory(String trustStorePath, String trustStorePassword, String trustStoreCertType,
+ String keyStorePath, String keyStorePassword, String keyStoreCertType)
{
- _keystorePath = keystorePath;
- _keystorePassword = keystorePassword;
- if (_keystorePassword.equals("none"))
+
+ _trustStorePath = trustStorePath;
+ _trustStorePassword = trustStorePassword;
+
+ if (_trustStorePassword.equals("none"))
+ {
+ _trustStorePassword = null;
+ }
+ _trustStoreCertType = trustStoreCertType;
+
+ _keyStorePath = keyStorePath;
+ _keyStorePassword = keyStorePassword;
+
+ if (_keyStorePassword.equals("none"))
{
- _keystorePassword = null;
+ _keyStorePassword = null;
}
- _certType = certType;
- if (keystorePath == null) {
- throw new IllegalArgumentException("Keystore path must be specified");
+ _keyStoreCertType = keyStoreCertType;
+
+ if (_trustStorePath == null) {
+ throw new IllegalArgumentException("A TrustStore path or KeyStore path must be specified");
}
- if (certType == null) {
+ if (_trustStoreCertType == null) {
throw new IllegalArgumentException("Cert type must be specified");
}
}
@@ -86,16 +122,18 @@ public class SSLContextFactory {
public SSLContext buildServerContext() throws GeneralSecurityException, IOException
{
// Create keystore
- KeyStore ks = getInitializedKeyStore();
+ KeyStore ks = getInitializedKeyStore(_keyStorePath,_keyStorePassword);
// Set up key manager factory to use our key store
- KeyManagerFactory kmf = KeyManagerFactory.getInstance(_certType);
- kmf.init(ks, _keystorePassword.toCharArray());
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(_keyStoreCertType);
+ kmf.init(ks, _keyStorePassword.toCharArray());
+ KeyStore ts = getInitializedKeyStore(_trustStorePath,_trustStorePassword);
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(_trustStoreCertType);
+ tmf.init(ts);
+
// Initialize the SSLContext to work with our key managers.
- SSLContext sslContext = SSLContext.getInstance("TLS");
- TrustManagerFactory tmf = TrustManagerFactory.getInstance(_certType);
- tmf.init(ks);
+ SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return sslContext;
@@ -109,34 +147,34 @@ public class SSLContextFactory {
*/
public SSLContext buildClientContext() throws GeneralSecurityException, IOException
{
- KeyStore ks = getInitializedKeyStore();
- TrustManagerFactory tmf = TrustManagerFactory.getInstance(_certType);
+ KeyStore ks = getInitializedKeyStore(_trustStorePath,_trustStorePassword);
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(_trustStoreCertType);
tmf.init(ks);
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
return context;
}
- private KeyStore getInitializedKeyStore() throws GeneralSecurityException, IOException
+ private KeyStore getInitializedKeyStore(String storePath, String storePassword) throws GeneralSecurityException, IOException
{
KeyStore ks = KeyStore.getInstance("JKS");
InputStream in = null;
try
{
- File f = new File(_keystorePath);
+ File f = new File(storePath);
if (f.exists())
{
in = new FileInputStream(f);
}
else
{
- in = Thread.currentThread().getContextClassLoader().getResourceAsStream(_keystorePath);
+ in = Thread.currentThread().getContextClassLoader().getResourceAsStream(storePath);
}
if (in == null)
{
- throw new IOException("Unable to load keystore resource: " + _keystorePath);
+ throw new IOException("Unable to load keystore resource: " + storePath);
}
- ks.load(in, _keystorePassword.toCharArray());
+ ks.load(in, storePassword.toCharArray());
}
finally
{
diff --git a/java/common/src/main/java/org/apache/qpid/thread/DefaultThreadFactory.java b/java/common/src/main/java/org/apache/qpid/thread/DefaultThreadFactory.java
new file mode 100644
index 0000000000..94869ab205
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/thread/DefaultThreadFactory.java
@@ -0,0 +1,18 @@
+package org.apache.qpid.thread;
+
+public class DefaultThreadFactory implements ThreadFactory
+{
+
+ public Thread createThread(Runnable r)
+ {
+ return new Thread(r);
+ }
+
+ public Thread createThread(Runnable r, int priority)
+ {
+ Thread t = new Thread(r);
+ t.setPriority(priority);
+ return t;
+ }
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/thread/QpidThreadExecutor.java b/java/common/src/main/java/org/apache/qpid/thread/QpidThreadExecutor.java
new file mode 100644
index 0000000000..38f60c04fe
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/thread/QpidThreadExecutor.java
@@ -0,0 +1,42 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.thread;
+
+import org.apache.qpid.thread.Threading;
+
+import edu.emory.mathcs.backport.java.util.concurrent.Executor;
+
+public class QpidThreadExecutor implements Executor
+{
+ public void execute(Runnable command)
+ {
+ try
+ {
+ Threading.getThreadFactory().createThread(command).start();
+ }
+ catch(Exception e)
+ {
+ throw new RuntimeException("Error creating a thread using Qpid thread factory",e);
+ }
+ }
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/thread/RealtimeThreadFactory.java b/java/common/src/main/java/org/apache/qpid/thread/RealtimeThreadFactory.java
new file mode 100644
index 0000000000..b711f749f8
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/thread/RealtimeThreadFactory.java
@@ -0,0 +1,47 @@
+package org.apache.qpid.thread;
+
+import java.lang.reflect.Constructor;
+
+public class RealtimeThreadFactory implements ThreadFactory
+{
+ private Class threadClass;
+ private Constructor threadConstructor;
+ private Constructor priorityParameterConstructor;
+ private int defaultRTThreadPriority = 20;
+
+ public RealtimeThreadFactory() throws Exception
+ {
+ defaultRTThreadPriority = Integer.getInteger("qpid.rt_thread_priority",20);
+ threadClass = Class.forName("javax.realtime.RealtimeThread");
+
+ Class schedulingParametersClass = Class.forName("javax.realtime.SchedulingParameters");
+ Class releaseParametersClass = Class.forName("javax.realtime.ReleaseParameters");
+ Class memoryParametersClass = Class.forName("javax.realtime.MemoryParameters");
+ Class memoryAreaClass = Class.forName("javax.realtime.MemoryArea");
+ Class processingGroupParametersClass = Class.forName("javax.realtime.ProcessingGroupParameters");
+
+ Class[] paramTypes = new Class[]{schedulingParametersClass,
+ releaseParametersClass,
+ memoryParametersClass,
+ memoryAreaClass,
+ processingGroupParametersClass,
+ java.lang.Runnable.class};
+
+ threadConstructor = threadClass.getConstructor(paramTypes);
+
+ Class priorityParameterClass = Class.forName("javax.realtime.PriorityParameters");
+ priorityParameterConstructor = priorityParameterClass.getConstructor(new Class[]{int.class});
+ }
+
+ public Thread createThread(Runnable r) throws Exception
+ {
+ return createThread(r,defaultRTThreadPriority);
+ }
+
+ public Thread createThread(Runnable r, int priority) throws Exception
+ {
+ Object priorityParams = priorityParameterConstructor.newInstance(priority);
+ return (Thread)threadConstructor.newInstance(priorityParams,null,null,null,null,r);
+ }
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/thread/ThreadFactory.java b/java/common/src/main/java/org/apache/qpid/thread/ThreadFactory.java
new file mode 100644
index 0000000000..f9bcabfa3d
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/thread/ThreadFactory.java
@@ -0,0 +1,7 @@
+package org.apache.qpid.thread;
+
+public interface ThreadFactory
+{
+ public Thread createThread(Runnable r) throws Exception;
+ public Thread createThread(Runnable r, int priority) throws Exception;
+}
diff --git a/java/common/src/main/java/org/apache/qpid/thread/Threading.java b/java/common/src/main/java/org/apache/qpid/thread/Threading.java
new file mode 100644
index 0000000000..0fb113d22c
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/thread/Threading.java
@@ -0,0 +1,26 @@
+package org.apache.qpid.thread;
+
+public final class Threading
+{
+ private static ThreadFactory threadFactory;
+
+ static {
+ try
+ {
+ Class threadFactoryClass =
+ Class.forName(System.getProperty("qpid.thread_factory",
+ "org.apache.qpid.thread.DefaultThreadFactory"));
+
+ threadFactory = (ThreadFactory)threadFactoryClass.newInstance();
+ }
+ catch(Exception e)
+ {
+ throw new Error("Error occured while loading thread factory",e);
+ }
+ }
+
+ public static ThreadFactory getThreadFactory()
+ {
+ return threadFactory;
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/Binary.java b/java/common/src/main/java/org/apache/qpid/transport/Binary.java
index e6dedc536f..4e97855a6f 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/Binary.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/Binary.java
@@ -20,6 +20,10 @@
*/
package org.apache.qpid.transport;
+import java.nio.ByteBuffer;
+
+import static org.apache.qpid.transport.util.Functions.*;
+
/**
* Binary
@@ -51,6 +55,13 @@ public final class Binary
this(bytes, 0, bytes.length);
}
+ public final byte[] getBytes()
+ {
+ byte[] result = new byte[size];
+ System.arraycopy(bytes, offset, result, 0, size);
+ return result;
+ }
+
public final byte[] array()
{
return bytes;
@@ -126,4 +137,9 @@ public final class Binary
return true;
}
+ public String toString()
+ {
+ return str(ByteBuffer.wrap(bytes, offset, size));
+ }
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/Channel.java b/java/common/src/main/java/org/apache/qpid/transport/Channel.java
deleted file mode 100644
index d6b015930b..0000000000
--- a/java/common/src/main/java/org/apache/qpid/transport/Channel.java
+++ /dev/null
@@ -1,176 +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.
- *
- */
-package org.apache.qpid.transport;
-
-import org.apache.qpid.transport.network.Frame;
-import org.apache.qpid.transport.util.Logger;
-
-import java.nio.ByteBuffer;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-import static org.apache.qpid.transport.network.Frame.*;
-import static org.apache.qpid.transport.util.Functions.*;
-
-
-/**
- * Channel
- *
- * @author Rafael H. Schloming
- */
-
-public class Channel extends Invoker
- implements Receiver<ProtocolEvent>, ProtocolDelegate<Void>
-{
-
- private static final Logger log = Logger.get(Channel.class);
-
- final private Connection connection;
- final private int channel;
- final private MethodDelegate<Channel> delegate;
- final private SessionDelegate sessionDelegate;
- // session may be null
- private Session session;
-
- public Channel(Connection connection, int channel, SessionDelegate delegate)
- {
- this.connection = connection;
- this.channel = channel;
- this.delegate = new ChannelDelegate();
- this.sessionDelegate = delegate;
- }
-
- public Connection getConnection()
- {
- return connection;
- }
-
- public void received(ProtocolEvent event)
- {
- event.delegate(null, this);
- }
-
- public void init(Void v, ProtocolHeader hdr)
- {
- connection.getConnectionDelegate().init(this, hdr);
- }
-
- public void control(Void v, Method method)
- {
- switch (method.getEncodedTrack())
- {
- case L1:
- method.dispatch(this, connection.getConnectionDelegate());
- break;
- case L2:
- method.dispatch(this, delegate);
- break;
- case L3:
- method.delegate(session, sessionDelegate);
- break;
- default:
- throw new IllegalStateException
- ("unknown track: " + method.getEncodedTrack());
- }
- }
-
- public void command(Void v, Method method)
- {
- method.delegate(session, sessionDelegate);
- }
-
- public void error(Void v, ProtocolError error)
- {
- throw new RuntimeException(error.getMessage());
- }
-
- public void exception(Throwable t)
- {
- session.exception(t);
- }
-
- public void closed()
- {
- log.debug("channel closed: ", this);
- if (session != null)
- {
- session.closed();
- }
- connection.removeChannel(channel);
- }
-
- public int getEncodedChannel() {
- return channel;
- }
-
- public Session getSession()
- {
- return session;
- }
-
- void setSession(Session session)
- {
- this.session = session;
- }
-
- void closeCode(ConnectionClose close)
- {
- if (session != null)
- {
- session.closeCode(close);
- }
- }
-
- private void emit(ProtocolEvent event)
- {
- event.setChannel(channel);
- connection.send(event);
- }
-
- public void method(Method m)
- {
- emit(m);
-
- if (!m.isBatch())
- {
- connection.flush();
- }
- }
-
- protected void invoke(Method m)
- {
- method(m);
- }
-
- protected <T> Future<T> invoke(Method m, Class<T> cls)
- {
- throw new UnsupportedOperationException();
- }
-
- public String toString()
- {
- return String.format("%s:%s", connection, channel);
- }
-
-}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ChannelDelegate.java b/java/common/src/main/java/org/apache/qpid/transport/ChannelDelegate.java
deleted file mode 100644
index 8475fbf174..0000000000
--- a/java/common/src/main/java/org/apache/qpid/transport/ChannelDelegate.java
+++ /dev/null
@@ -1,54 +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.
- *
- */
-package org.apache.qpid.transport;
-
-import java.util.UUID;
-
-
-/**
- * ChannelDelegate
- *
- * @author Rafael H. Schloming
- */
-
-class ChannelDelegate extends MethodDelegate<Channel>
-{
-
- public @Override void sessionAttach(Channel channel, SessionAttach atch)
- {
- Session ssn = new Session(atch.getName());
- ssn.attach(channel);
- ssn.sessionAttached(ssn.getName());
- }
-
- public @Override void sessionDetached(Channel channel, SessionDetached closed)
- {
- channel.closed();
- }
-
- public @Override void sessionDetach(Channel channel, SessionDetach dtc)
- {
- channel.getSession().closed();
- channel.sessionDetached(dtc.getName(), SessionDetachCode.NORMAL);
- channel.closed();
- }
-
-}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java b/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java
index bbdadfadb9..bd03c3e242 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java
@@ -20,21 +20,152 @@
*/
package org.apache.qpid.transport;
+import static org.apache.qpid.transport.Connection.State.OPEN;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+
+import org.apache.qpid.security.UsernamePasswordCallbackHandler;
+import org.apache.qpid.transport.util.Logger;
+
/**
* ClientDelegate
*
*/
-public abstract class ClientDelegate extends ConnectionDelegate
+public class ClientDelegate extends ConnectionDelegate
{
+ private static final Logger log = Logger.get(ClientDelegate.class);
+
+ private String vhost;
+ private String username;
+ private String password;
+ private String[] saslMechs;
+ private String protocol;
+ private String serverName;
+
+ public ClientDelegate(String vhost, String username, String password,String saslMechs)
+ {
+ this.vhost = vhost;
+ this.username = username;
+ this.password = password;
+ this.saslMechs = saslMechs.split(" ");
+
+ // Looks kinda of silly but the Sun SASL Kerberos client uses the
+ // protocol + servername as the service key.
+ this.protocol = System.getProperty("qpid.sasl_protocol","AMQP");
+ this.serverName = System.getProperty("qpid.sasl_server_name","localhost");
+ }
- public void init(Channel ch, ProtocolHeader hdr)
+ public void init(Connection conn, ProtocolHeader hdr)
{
- if (hdr.getMajor() != 0 && hdr.getMinor() != 10)
+ if (!(hdr.getMajor() == 0 && hdr.getMinor() == 10))
{
- throw new ProtocolVersionException(hdr.getMajor(), hdr.getMinor());
+ conn.exception(new ProtocolVersionException(hdr.getMajor(), hdr.getMinor()));
}
}
+ @Override public void connectionStart(Connection conn, ConnectionStart start)
+ {
+ Map clientProperties = new HashMap();
+ clientProperties.put("qpid.session_flow", 1);
+
+ List<Object> mechanisms = start.getMechanisms();
+ if (mechanisms == null || mechanisms.isEmpty())
+ {
+ conn.connectionStartOk
+ (clientProperties, null, null, conn.getLocale());
+ return;
+ }
+
+ String[] mechs = new String[mechanisms.size()];
+ mechanisms.toArray(mechs);
+
+ try
+ {
+ UsernamePasswordCallbackHandler handler =
+ new UsernamePasswordCallbackHandler();
+ handler.initialise(username, password);
+ SaslClient sc = Sasl.createSaslClient
+ (saslMechs, null, protocol, serverName, null, handler);
+ conn.setSaslClient(sc);
+
+ byte[] response = sc.hasInitialResponse() ?
+ sc.evaluateChallenge(new byte[0]) : null;
+ conn.connectionStartOk
+ (clientProperties, sc.getMechanismName(), response,
+ conn.getLocale());
+ }
+ catch (SaslException e)
+ {
+ conn.exception(e);
+ }
+ }
+
+ @Override public void connectionSecure(Connection conn, ConnectionSecure secure)
+ {
+ SaslClient sc = conn.getSaslClient();
+ try
+ {
+ byte[] response = sc.evaluateChallenge(secure.getChallenge());
+ conn.connectionSecureOk(response);
+ }
+ catch (SaslException e)
+ {
+ conn.exception(e);
+ }
+ }
+
+ @Override public void connectionTune(Connection conn, ConnectionTune tune)
+ {
+ conn.setChannelMax(tune.getChannelMax());
+ int hb_interval = calculateHeartbeatInterval(conn,
+ tune.getHeartbeatMin(),
+ tune.getHeartbeatMax()
+ );
+ conn.connectionTuneOk(tune.getChannelMax(),
+ tune.getMaxFrameSize(),
+ hb_interval);
+ conn.setIdleTimeout(hb_interval*1000);
+ conn.connectionOpen(vhost, null, Option.INSIST);
+ }
+
+ @Override public void connectionOpenOk(Connection conn, ConnectionOpenOk ok)
+ {
+ conn.setState(OPEN);
+ }
+
+ @Override public void connectionRedirect(Connection conn, ConnectionRedirect redir)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public void connectionHeartbeat(Connection conn, ConnectionHeartbeat hearbeat)
+ {
+ conn.connectionHeartbeat();
+ }
+
+ /**
+ * Currently the spec specified the min and max for heartbeat using secs
+ */
+ private int calculateHeartbeatInterval(Connection conn,int min, int max)
+ {
+ long l = conn.getIdleTimeout()/1000;
+ if (l !=0 && l >= min && l <= max)
+ {
+ return (int)l;
+ }
+ else
+ {
+ log.warn("Ignoring the idle timeout %s set by the connection," +
+ " using the brokers max value %s", l,max);
+ return max;
+ }
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/Connection.java b/java/common/src/main/java/org/apache/qpid/transport/Connection.java
index 68b9b209bb..773746af79 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/Connection.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/Connection.java
@@ -20,14 +20,23 @@
*/
package org.apache.qpid.transport;
+import org.apache.qpid.transport.network.ConnectionBinding;
+import org.apache.qpid.transport.network.io.IoTransport;
import org.apache.qpid.transport.util.Logger;
+import org.apache.qpid.transport.util.Waiter;
+import org.apache.qpid.util.Strings;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.nio.ByteBuffer;
+import java.util.UUID;
+
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslServer;
+
+import static org.apache.qpid.transport.Connection.State.*;
/**
@@ -40,27 +49,222 @@ import java.nio.ByteBuffer;
* short instead of Short
*/
-public class Connection
+public class Connection extends ConnectionInvoker
implements Receiver<ProtocolEvent>, Sender<ProtocolEvent>
{
private static final Logger log = Logger.get(Connection.class);
- final private Sender<ProtocolEvent> sender;
- final private ConnectionDelegate delegate;
+ public enum State { NEW, CLOSED, OPENING, OPEN, CLOSING, CLOSE_RCVD }
+
+ class DefaultConnectionListener implements ConnectionListener
+ {
+ public void opened(Connection conn) {}
+ public void exception(Connection conn, ConnectionException exception)
+ {
+ log.error(exception, "connection exception");
+ }
+ public void closed(Connection conn) {}
+ }
+
+ private ConnectionDelegate delegate;
+ private Sender<ProtocolEvent> sender;
+
+ final private Map<Binary,Session> sessions = new HashMap<Binary,Session>();
+ final private Map<Integer,Session> channels = new HashMap<Integer,Session>();
+
+ private State state = NEW;
+ final private Object lock = new Object();
+ private long timeout = 60000;
+ private ConnectionListener listener = new DefaultConnectionListener();
+ private ConnectionException error = null;
+
private int channelMax = 1;
+ private String locale;
+ private SaslServer saslServer;
+ private SaslClient saslClient;
+ private long idleTimeout = 0;
+ private String _authorizationID;
+
// want to make this final
private int _connectionId;
- final private Map<Integer,Channel> channels = new HashMap<Integer,Channel>();
+ public Connection() {}
- public Connection(Sender<ProtocolEvent> sender,
- ConnectionDelegate delegate)
+ public void setConnectionDelegate(ConnectionDelegate delegate)
{
- this.sender = sender;
this.delegate = delegate;
}
+ public void setConnectionListener(ConnectionListener listener)
+ {
+ if (listener == null)
+ {
+ this.listener = new DefaultConnectionListener();
+ }
+ else
+ {
+ this.listener = listener;
+ }
+ }
+
+ public Sender<ProtocolEvent> getSender()
+ {
+ return sender;
+ }
+
+ public void setSender(Sender<ProtocolEvent> sender)
+ {
+ this.sender = sender;
+ sender.setIdleTimeout(idleTimeout);
+ }
+
+ protected void setState(State state)
+ {
+ synchronized (lock)
+ {
+ this.state = state;
+ lock.notifyAll();
+ }
+ }
+
+ void setLocale(String locale)
+ {
+ this.locale = locale;
+ }
+
+ String getLocale()
+ {
+ return locale;
+ }
+
+ void setSaslServer(SaslServer saslServer)
+ {
+ this.saslServer = saslServer;
+ }
+
+ SaslServer getSaslServer()
+ {
+ return saslServer;
+ }
+
+ void setSaslClient(SaslClient saslClient)
+ {
+ this.saslClient = saslClient;
+ }
+
+ SaslClient getSaslClient()
+ {
+ return saslClient;
+ }
+
+ public void connect(String host, int port, String vhost, String username, String password)
+ {
+ connect(host, port, vhost, username, password, false);
+ }
+
+ public void connect(String host, int port, String vhost, String username, String password, boolean ssl)
+ {
+ connect(host, port, vhost, username, password, ssl,"PLAIN");
+ }
+
+ public void connect(String host, int port, String vhost, String username, String password, boolean ssl,String saslMechs)
+ {
+ synchronized (lock)
+ {
+ state = OPENING;
+
+ delegate = new ClientDelegate(vhost, username, password,saslMechs);
+
+ IoTransport.connect(host, port, ConnectionBinding.get(this), ssl);
+ send(new ProtocolHeader(1, 0, 10));
+
+ Waiter w = new Waiter(lock, timeout);
+ while (w.hasTime() && state == OPENING && error == null)
+ {
+ w.await();
+ }
+
+ if (error != null)
+ {
+ ConnectionException t = error;
+ error = null;
+ try
+ {
+ close();
+ }
+ catch (ConnectionException ce)
+ {
+ if (!(t instanceof ProtocolVersionException))
+ {
+ throw ce;
+ }
+ }
+ t.rethrow();
+ }
+
+ switch (state)
+ {
+ case OPENING:
+ close();
+ throw new ConnectionException("connect() timed out");
+ case OPEN:
+ break;
+ case CLOSED:
+ throw new ConnectionException("connect() aborted");
+ default:
+ throw new IllegalStateException(String.valueOf(state));
+ }
+ }
+
+ listener.opened(this);
+ }
+
+ public Session createSession()
+ {
+ return createSession(0);
+ }
+
+ public Session createSession(long expiry)
+ {
+ return createSession(UUID.randomUUID().toString(), expiry);
+ }
+
+ public Session createSession(String name)
+ {
+ return createSession(name, 0);
+ }
+
+ public Session createSession(String name, long expiry)
+ {
+ return createSession(Strings.toUTF8(name), expiry);
+ }
+
+ public Session createSession(byte[] name, long expiry)
+ {
+ return createSession(new Binary(name), expiry);
+ }
+
+ public Session createSession(Binary name, long expiry)
+ {
+ synchronized (lock)
+ {
+ Session ssn = new Session(this, name, expiry);
+ sessions.put(name, ssn);
+ map(ssn);
+ ssn.attach();
+ return ssn;
+ }
+ }
+
+ void removeSession(Session ssn)
+ {
+ synchronized (lock)
+ {
+ sessions.remove(ssn.getName());
+ }
+ }
+
public void setConnectionId(int id)
{
_connectionId = id;
@@ -79,14 +283,18 @@ public class Connection
public void received(ProtocolEvent event)
{
log.debug("RECV: [%s] %s", this, event);
- Channel channel = getChannel(event.getChannel());
- channel.received(event);
+ event.delegate(this, delegate);
}
public void send(ProtocolEvent event)
{
log.debug("SEND: [%s] %s", this, event);
- sender.send(event);
+ Sender s = sender;
+ if (s == null)
+ {
+ throw new ConnectionException("connection closed");
+ }
+ s.send(event);
}
public void flush()
@@ -95,6 +303,30 @@ public class Connection
sender.flush();
}
+ protected void invoke(Method method)
+ {
+ method.setChannel(0);
+ send(method);
+ if (!method.isBatch())
+ {
+ flush();
+ }
+ }
+
+ public void dispatch(Method method)
+ {
+ Session ssn = getSession(method.getChannel());
+ if(ssn != null)
+ {
+ ssn.received(method);
+ }
+ else
+ {
+ throw new ProtocolViolationException(
+ "Received frames for an already dettached session", null);
+ }
+ }
+
public int getChannelMax()
{
return channelMax;
@@ -105,15 +337,16 @@ public class Connection
channelMax = max;
}
- public Channel getChannel()
+ private int map(Session ssn)
{
- synchronized (channels)
+ synchronized (lock)
{
for (int i = 0; i < getChannelMax(); i++)
{
if (!channels.containsKey(i))
{
- return getChannel(i);
+ map(ssn, i);
+ return i;
}
}
@@ -121,61 +354,195 @@ public class Connection
}
}
- public Channel getChannel(int number)
+ void map(Session ssn, int channel)
+ {
+ synchronized (lock)
+ {
+ channels.put(channel, ssn);
+ ssn.setChannel(channel);
+ }
+ }
+
+ void unmap(Session ssn)
+ {
+ synchronized (lock)
+ {
+ channels.remove(ssn.getChannel());
+ }
+ }
+
+ Session getSession(int channel)
+ {
+ synchronized (lock)
+ {
+ return channels.get(channel);
+ }
+ }
+
+ public void resume()
{
- synchronized (channels)
+ synchronized (lock)
{
- Channel channel = channels.get(number);
- if (channel == null)
+ for (Session ssn : sessions.values())
{
- channel = new Channel(this, number, delegate.getSessionDelegate());
- channels.put(number, channel);
+ map(ssn);
+ ssn.attach();
+ ssn.resume();
}
- return channel;
}
}
- void removeChannel(int number)
+ public void exception(ConnectionException e)
{
- synchronized (channels)
+ synchronized (lock)
{
- channels.remove(number);
+ switch (state)
+ {
+ case OPENING:
+ case CLOSING:
+ error = e;
+ lock.notifyAll();
+ return;
+ }
}
+
+ listener.exception(this, e);
}
public void exception(Throwable t)
{
- delegate.exception(t);
+ exception(new ConnectionException(t));
}
void closeCode(ConnectionClose close)
{
- synchronized (channels)
+ synchronized (lock)
{
- for (Channel ch : channels.values())
+ for (Session ssn : channels.values())
{
- ch.closeCode(close);
+ ssn.closeCode(close);
+ }
+ ConnectionCloseCode code = close.getReplyCode();
+ if (code != ConnectionCloseCode.NORMAL)
+ {
+ exception(new ConnectionException(close));
}
}
}
public void closed()
{
+ if (state == OPEN)
+ {
+ exception(new ConnectionException("connection aborted"));
+ }
+
log.debug("connection closed: %s", this);
- synchronized (channels)
+
+ synchronized (lock)
{
- List<Channel> values = new ArrayList<Channel>(channels.values());
- for (Channel ch : values)
+ List<Session> values = new ArrayList<Session>(channels.values());
+ for (Session ssn : values)
+ {
+ ssn.closed();
+ }
+
+ try
+ {
+ sender.close();
+ }
+ catch(Exception e)
{
- ch.closed();
+ // ignore.
}
+ sender = null;
+ setState(CLOSED);
}
- delegate.closed();
+
+ listener.closed(this);
}
public void close()
{
- sender.close();
+ synchronized (lock)
+ {
+ switch (state)
+ {
+ case OPEN:
+ state = CLOSING;
+ connectionClose(ConnectionCloseCode.NORMAL, null);
+ Waiter w = new Waiter(lock, timeout);
+ while (w.hasTime() && state == CLOSING && error == null)
+ {
+ w.await();
+ }
+
+ if (error != null)
+ {
+ close();
+ throw new ConnectionException(error);
+ }
+
+ switch (state)
+ {
+ case CLOSING:
+ close();
+ throw new ConnectionException("close() timed out");
+ case CLOSED:
+ break;
+ default:
+ throw new IllegalStateException(String.valueOf(state));
+ }
+ break;
+ case CLOSED:
+ break;
+ default:
+ if (sender != null)
+ {
+ sender.close();
+ w = new Waiter(lock, timeout);
+ while (w.hasTime() && sender != null && error == null)
+ {
+ w.await();
+ }
+
+ if (error != null)
+ {
+ throw new ConnectionException(error);
+ }
+
+ if (sender != null)
+ {
+ throw new ConnectionException("close() timed out");
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ public void setIdleTimeout(long l)
+ {
+ idleTimeout = l;
+ if (sender != null)
+ {
+ sender.setIdleTimeout(l);
+ }
+ }
+
+ public long getIdleTimeout()
+ {
+ return idleTimeout;
+ }
+
+ public void setAuthorizationID(String authorizationID)
+ {
+ _authorizationID = authorizationID;
+ }
+
+ public String getAuthorizationID()
+ {
+ return _authorizationID;
}
public String toString()
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ConnectionDelegate.java b/java/common/src/main/java/org/apache/qpid/transport/ConnectionDelegate.java
index 2aa1db7b28..9ef7a47e1b 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/ConnectionDelegate.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/ConnectionDelegate.java
@@ -22,22 +22,7 @@ package org.apache.qpid.transport;
import org.apache.qpid.transport.util.Logger;
-import org.apache.qpid.SecurityHelper;
-import org.apache.qpid.QpidException;
-
-import java.io.UnsupportedEncodingException;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-
-import javax.security.sasl.Sasl;
-import javax.security.sasl.SaslClient;
-import javax.security.sasl.SaslException;
-import javax.security.sasl.SaslServer;
+import static org.apache.qpid.transport.Connection.State.*;
/**
@@ -52,236 +37,67 @@ import javax.security.sasl.SaslServer;
*
* the connectionClose is kind of different for both sides
*/
-public abstract class ConnectionDelegate extends MethodDelegate<Channel>
+public abstract class ConnectionDelegate
+ extends MethodDelegate<Connection>
+ implements ProtocolDelegate<Connection>
{
private static final Logger log = Logger.get(ConnectionDelegate.class);
- private String _username = "guest";
- private String _password = "guest";;
- private String _mechanism;
- private String _virtualHost;
- private SaslClient saslClient;
- private SaslServer saslServer;
- private String _locale = "utf8";
- private int maxFrame = 64*1024;
- private Condition _negotiationComplete;
- private Lock _negotiationCompleteLock;
-
- public abstract SessionDelegate getSessionDelegate();
-
- public abstract void exception(Throwable t);
-
- public abstract void closed();
-
- public void setCondition(Lock negotiationCompleteLock,Condition negotiationComplete)
+ public void control(Connection conn, Method method)
{
- _negotiationComplete = negotiationComplete;
- _negotiationCompleteLock = negotiationCompleteLock;
+ method.dispatch(conn, this);
}
- public void init(Channel ch, ProtocolHeader hdr)
+ public void command(Connection conn, Method method)
{
- ch.getConnection().send(new ProtocolHeader (1, hdr.getMajor(), hdr.getMinor()));
- List<Object> plain = new ArrayList<Object>();
- plain.add("PLAIN");
- List<Object> utf8 = new ArrayList<Object>();
- utf8.add("utf8");
- ch.connectionStart(null, plain, utf8);
+ method.dispatch(conn, this);
}
- // ----------------------------------------------
- // Client side
- //-----------------------------------------------
- @Override public void connectionStart(Channel context, ConnectionStart struct)
+ public void error(Connection conn, ProtocolError error)
{
- String mechanism = null;
- byte[] response = null;
- try
- {
- mechanism = SecurityHelper.chooseMechanism(struct.getMechanisms());
- saslClient = Sasl.createSaslClient(new String[]{ mechanism },null, "AMQP", "localhost", null,
- SecurityHelper.createCallbackHandler(mechanism,_username,_password ));
- response = saslClient.evaluateChallenge(new byte[0]);
- }
- catch (UnsupportedEncodingException e)
- {
- // need error handling
- }
- catch (SaslException e)
- {
- // need error handling
- }
- catch (QpidException e)
- {
- // need error handling
- }
-
- Map<String,Object> props = new HashMap<String,Object>();
- context.connectionStartOk(props, mechanism, response, _locale);
+ conn.exception(new ConnectionException(error.getMessage()));
}
- @Override public void connectionSecure(Channel context, ConnectionSecure struct)
+ public void handle(Connection conn, Method method)
{
- try
- {
- byte[] response = saslClient.evaluateChallenge(struct.getChallenge());
- context.connectionSecureOk(response);
- }
- catch (SaslException e)
- {
- // need error handling
- }
+ conn.dispatch(method);
}
- @Override public void connectionTune(Channel context, ConnectionTune struct)
+ @Override public void connectionHeartbeat(Connection conn, ConnectionHeartbeat hearbeat)
{
- context.getConnection().setChannelMax(struct.getChannelMax());
- context.connectionTuneOk(struct.getChannelMax(), struct.getMaxFrameSize(), struct.getHeartbeatMax());
- context.connectionOpen(_virtualHost, null, Option.INSIST);
+ // do nothing
}
-
- @Override public void connectionOpenOk(Channel context, ConnectionOpenOk struct)
+ @Override public void connectionClose(Connection conn, ConnectionClose close)
{
- List<Object> knownHosts = struct.getKnownHosts();
- if(_negotiationCompleteLock != null)
- {
- _negotiationCompleteLock.lock();
- try
- {
- _negotiationComplete.signalAll();
- }
- finally
- {
- _negotiationCompleteLock.unlock();
- }
- }
+ conn.connectionCloseOk();
+ conn.getSender().close();
+ conn.closeCode(close);
+ conn.setState(CLOSE_RCVD);
}
- public void connectionRedirect(Channel context, ConnectionRedirect struct)
+ @Override public void connectionCloseOk(Connection conn, ConnectionCloseOk ok)
{
- // not going to bother at the moment
+ conn.getSender().close();
}
- // ----------------------------------------------
- // Server side
- //-----------------------------------------------
- @Override public void connectionStartOk(Channel context, ConnectionStartOk struct)
+ @Override public void sessionDetach(Connection conn, SessionDetach dtc)
{
- //set the client side locale on the server side
- _locale = struct.getLocale();
- _mechanism = struct.getMechanism();
-
- //try
- //{
- //saslServer = Sasl.createSaslServer(_mechanism, "AMQP", "ABC",null,SecurityHelper.createCallbackHandler(_mechanism,_username,_password));
- //byte[] challenge = saslServer.evaluateResponse(struct.getResponse().getBytes());
- byte[] challenge = null;
- if ( challenge == null)
- {
- context.connectionTune(Integer.MAX_VALUE, maxFrame, 0, Integer.MAX_VALUE);
- }
- else
- {
- try
- {
- context.connectionSecure(challenge);
- }
- catch(Exception e)
- {
-
- }
- }
-
-
- /*}
- catch (SaslException e)
- {
- // need error handling
- }
- catch (QpidException e)
- {
- // need error handling
- }*/
+ Session ssn = conn.getSession(dtc.getChannel());
+ conn.unmap(ssn);
+ ssn.sessionDetached(dtc.getName(), SessionDetachCode.NORMAL);
+ ssn.closed();
}
- @Override public void connectionSecureOk(Channel context, ConnectionSecureOk struct)
+ @Override public void sessionDetached(Connection conn, SessionDetached dtc)
{
- try
- {
- saslServer = Sasl.createSaslServer(_mechanism, "AMQP", "ABC",new HashMap(),SecurityHelper.createCallbackHandler(_mechanism,_username,_password));
- byte[] challenge = saslServer.evaluateResponse(struct.getResponse());
- if ( challenge == null)
- {
- context.connectionTune(Integer.MAX_VALUE, maxFrame, 0, Integer.MAX_VALUE);
- }
- else
- {
- try
- {
- context.connectionSecure(challenge);
- }
- catch(Exception e)
- {
-
- }
- }
-
-
- }
- catch (SaslException e)
+ Session ssn = conn.getSession(dtc.getChannel());
+ if (ssn != null)
{
- // need error handling
+ conn.unmap(ssn);
+ ssn.closed();
}
- catch (QpidException e)
- {
- // need error handling
- }
- }
-
-
- @Override public void connectionOpen(Channel context, ConnectionOpen struct)
- {
- List<Object> hosts = new ArrayList<Object>();
- hosts.add("amqp:1223243232325");
- context.connectionOpenOk(hosts);
- }
-
- @Override public void connectionClose(Channel ch, ConnectionClose close)
- {
- ch.getConnection().closeCode(close);
- ch.connectionCloseOk();
- }
-
- public String getPassword()
- {
- return _password;
- }
-
- public void setPassword(String password)
- {
- _password = password;
- }
-
- public String getUsername()
- {
- return _username;
- }
-
- public void setUsername(String username)
- {
- _username = username;
- }
-
- public String getVirtualHost()
- {
- return _virtualHost;
- }
-
- public void setVirtualHost(String host)
- {
- _virtualHost = host;
}
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ConnectionException.java b/java/common/src/main/java/org/apache/qpid/transport/ConnectionException.java
index c3239ef684..6d3972eb43 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/ConnectionException.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/ConnectionException.java
@@ -26,20 +26,45 @@ package org.apache.qpid.transport;
*
*/
-public class ConnectionException extends RuntimeException
+public class ConnectionException extends TransportException
{
private ConnectionClose close;
- public ConnectionException(ConnectionClose close)
+ public ConnectionException(String message, ConnectionClose close, Throwable cause)
{
- super(close.getReplyText());
+ super(message, cause);
this.close = close;
}
+ public ConnectionException(String message)
+ {
+ this(message, null, null);
+ }
+
+ public ConnectionException(String message, Throwable cause)
+ {
+ this(message, null, cause);
+ }
+
+ public ConnectionException(Throwable cause)
+ {
+ this(cause.getMessage(), null, cause);
+ }
+
+ public ConnectionException(ConnectionClose close)
+ {
+ this(close.getReplyText(), close, null);
+ }
+
public ConnectionClose getClose()
{
return close;
}
+ @Override public void rethrow()
+ {
+ throw new ConnectionException(getMessage(), close, this);
+ }
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ConnectionListener.java b/java/common/src/main/java/org/apache/qpid/transport/ConnectionListener.java
new file mode 100644
index 0000000000..616e76825a
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/ConnectionListener.java
@@ -0,0 +1,38 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.transport;
+
+
+/**
+ * ConnectionListener
+ *
+ */
+
+public interface ConnectionListener
+{
+
+ void opened(Connection connection);
+
+ void exception(Connection connection, ConnectionException exception);
+
+ void closed(Connection connection);
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/Echo.java b/java/common/src/main/java/org/apache/qpid/transport/Echo.java
index b2be32331a..0e969464ab 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/Echo.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/Echo.java
@@ -32,36 +32,41 @@ import org.apache.qpid.transport.network.io.IoAcceptor;
*
*/
-public class Echo extends SessionDelegate
+public class Echo implements SessionListener
{
- public void messageTransfer(Session ssn, MessageTransfer xfr)
+ public void opened(Session ssn) {}
+
+ public void resumed(Session ssn) {}
+
+ public void message(Session ssn, MessageTransfer xfr)
{
+ int id = xfr.getId();
ssn.invoke(xfr);
- ssn.processed(xfr);
+ ssn.processed(id);
+ }
+
+ public void exception(Session ssn, SessionException exc)
+ {
+ exc.printStackTrace();
}
+ public void closed(Session ssn) {}
+
public static final void main(String[] args) throws IOException
{
- ConnectionDelegate delegate = new ConnectionDelegate()
+ ConnectionDelegate delegate = new ServerDelegate()
{
- public SessionDelegate getSessionDelegate()
- {
- return new Echo();
- }
- public void exception(Throwable t)
+ @Override public Session getSession(Connection conn, SessionAttach atc)
{
- t.printStackTrace();
+ Session ssn = super.getSession(conn, atc);
+ ssn.setSessionListener(new Echo());
+ return ssn;
}
- public void closed() {}
};
- //hack
- delegate.setUsername("guest");
- delegate.setPassword("guest");
-
IoAcceptor ioa = new IoAcceptor
- ("0.0.0.0", 5672, new ConnectionBinding(delegate));
+ ("0.0.0.0", 5672, ConnectionBinding.get(delegate));
ioa.start();
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/Method.java b/java/common/src/main/java/org/apache/qpid/transport/Method.java
index 37c347db98..3c80180d0b 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/Method.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/Method.java
@@ -35,6 +35,7 @@ import static org.apache.qpid.transport.util.Functions.*;
public abstract class Method extends Struct implements ProtocolEvent
{
+
public static final Method create(int type)
{
// XXX: should generate separate factories for separate
@@ -43,11 +44,18 @@ public abstract class Method extends Struct implements ProtocolEvent
}
// XXX: command subclass?
+ public static interface CompletionListener
+ {
+ public void onComplete(Method method);
+ }
+
private int id;
private int channel;
private boolean idSet = false;
private boolean sync = false;
private boolean batch = false;
+ private boolean unreliable = false;
+ private CompletionListener completionListener;
public final int getId()
{
@@ -60,6 +68,11 @@ public abstract class Method extends Struct implements ProtocolEvent
this.idSet = true;
}
+ boolean idSet()
+ {
+ return idSet;
+ }
+
public final int getChannel()
{
return channel;
@@ -75,7 +88,7 @@ public abstract class Method extends Struct implements ProtocolEvent
return sync;
}
- protected final void setSync(boolean value)
+ public final void setSync(boolean value)
{
this.sync = value;
}
@@ -85,12 +98,22 @@ public abstract class Method extends Struct implements ProtocolEvent
return batch;
}
- protected final void setBatch(boolean value)
+ final void setBatch(boolean value)
{
this.batch = value;
}
- public abstract boolean hasPayloadSegment();
+ public final boolean isUnreliable()
+ {
+ return unreliable;
+ }
+
+ final void setUnreliable(boolean value)
+ {
+ this.unreliable = value;
+ }
+
+ public abstract boolean hasPayload();
public Header getHeader()
{
@@ -112,18 +135,22 @@ public abstract class Method extends Struct implements ProtocolEvent
throw new UnsupportedOperationException();
}
- public abstract byte getEncodedTrack();
-
- public <C> void dispatch(C context, MethodDelegate<C> delegate)
+ public int getBodySize()
{
- throw new UnsupportedOperationException();
+ ByteBuffer body = getBody();
+ if (body == null)
+ {
+ return 0;
+ }
+ else
+ {
+ return body.remaining();
+ }
}
- public <C> void dispatch
- (C context, org.apache.qpid.transport.v1_0.MethodDelegate<C> delegate)
- {
- throw new UnsupportedOperationException();
- }
+ public abstract byte getEncodedTrack();
+
+ public abstract <C> void dispatch(C context, MethodDelegate<C> delegate);
public <C> void delegate(C context, ProtocolDelegate<C> delegate)
{
@@ -137,6 +164,26 @@ public abstract class Method extends Struct implements ProtocolEvent
}
}
+
+ public void setCompletionListener(CompletionListener completionListener)
+ {
+ this.completionListener = completionListener;
+ }
+
+ public void complete()
+ {
+ if(completionListener!= null)
+ {
+ completionListener.onComplete(this);
+ completionListener = null;
+ }
+ }
+
+ public boolean hasCompletionListener()
+ {
+ return completionListener != null;
+ }
+
public String toString()
{
StringBuilder str = new StringBuilder();
diff --git a/java/common/src/main/java/org/apache/qpid/transport/NetworkDriver.java b/java/common/src/main/java/org/apache/qpid/transport/NetworkDriver.java
new file mode 100644
index 0000000000..86af97bf7e
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/NetworkDriver.java
@@ -0,0 +1,63 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.transport;
+
+import java.net.BindException;
+import java.net.InetAddress;
+import java.net.SocketAddress;
+
+import org.apache.qpid.protocol.ProtocolEngine;
+import org.apache.qpid.protocol.ProtocolEngineFactory;
+import org.apache.qpid.ssl.SSLContextFactory;
+
+public interface NetworkDriver extends Sender<java.nio.ByteBuffer>
+{
+ // Creates a NetworkDriver which attempts to connect to destination on port and attaches the ProtocolEngine to
+ // it using the SSLContextFactory if provided
+ void open(int port, InetAddress destination, ProtocolEngine engine,
+ NetworkDriverConfiguration config, SSLContextFactory sslFactory)
+ throws OpenException;
+
+ // listens for incoming connections on the specified ports and address and creates a new NetworkDriver which
+ // processes incoming connections with ProtocolEngines and SSLEngines created from the factories
+ // (in the case of an SSLContextFactory, if provided)
+ void bind (int port, InetAddress[] addresses, ProtocolEngineFactory protocolFactory,
+ NetworkDriverConfiguration config, SSLContextFactory sslFactory) throws BindException;
+
+ // Returns the remote address of the underlying socket
+ SocketAddress getRemoteAddress();
+
+ // Returns the local address of the underlying socket
+ SocketAddress getLocalAddress();
+
+ /**
+ * The length of time after which the ProtocolEngines readIdle() method should be called if no data has been
+ * read in seconds
+ */
+ void setMaxReadIdle(int idleTime);
+
+ /**
+ * The length of time after which the ProtocolEngines writeIdle() method should be called if no data has been
+ * written in seconds
+ */
+ void setMaxWriteIdle(int idleTime);
+
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/transport/NetworkDriverConfiguration.java b/java/common/src/main/java/org/apache/qpid/transport/NetworkDriverConfiguration.java
new file mode 100644
index 0000000000..c38afe5dd5
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/NetworkDriverConfiguration.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.transport;
+
+/**
+ * This interface provides a means for NetworkDrivers to configure TCP options such as incoming and outgoing
+ * buffer sizes and set particular options on the socket. NetworkDrivers should honour the values returned
+ * from here if the underlying implementation supports them.
+ */
+public interface NetworkDriverConfiguration
+{
+ // Taken from Socket
+ Boolean getKeepAlive();
+ Boolean getOOBInline();
+ Boolean getReuseAddress();
+ Integer getSoLinger(); // null means off
+ Integer getSoTimeout();
+ Boolean getTcpNoDelay();
+ Integer getTrafficClass();
+
+ // The amount of memory in bytes to allocate to the incoming buffer
+ Integer getReceiveBufferSize();
+
+ // The amount of memory in bytes to allocate to the outgoing buffer
+ Integer getSendBufferSize();
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/OpenException.java b/java/common/src/main/java/org/apache/qpid/transport/OpenException.java
new file mode 100644
index 0000000000..68fbb5e8ec
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/OpenException.java
@@ -0,0 +1,34 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.transport;
+
+import java.io.IOException;
+
+public class OpenException extends IOException
+{
+
+ public OpenException(String string, Throwable lastException)
+ {
+ super(string, lastException);
+ }
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ProtocolHeader.java b/java/common/src/main/java/org/apache/qpid/transport/ProtocolHeader.java
index fa0c1e9c63..00ea55ff96 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/ProtocolHeader.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/ProtocolHeader.java
@@ -39,13 +39,15 @@ public final class ProtocolHeader implements NetworkEvent, ProtocolEvent
private static final byte[] AMQP = {'A', 'M', 'Q', 'P' };
private static final byte CLASS = 1;
+ final private byte protoClass;
final private byte instance;
final private byte major;
final private byte minor;
private int channel;
- public ProtocolHeader(byte instance, byte major, byte minor)
+ public ProtocolHeader(byte protoClass, byte instance, byte major, byte minor)
{
+ this.protoClass = protoClass;
this.instance = instance;
this.major = major;
this.minor = minor;
@@ -53,7 +55,7 @@ public final class ProtocolHeader implements NetworkEvent, ProtocolEvent
public ProtocolHeader(int instance, int major, int minor)
{
- this((byte) instance, (byte) major, (byte) minor);
+ this(CLASS, (byte) instance, (byte) major, (byte) minor);
}
public byte getInstance()
@@ -90,7 +92,7 @@ public final class ProtocolHeader implements NetworkEvent, ProtocolEvent
{
ByteBuffer buf = ByteBuffer.allocate(8);
buf.put(AMQP);
- buf.put(CLASS);
+ buf.put(protoClass);
buf.put(instance);
buf.put(major);
buf.put(minor);
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ProtocolVersionException.java b/java/common/src/main/java/org/apache/qpid/transport/ProtocolVersionException.java
index 2de0c169a5..db8064268c 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/ProtocolVersionException.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/ProtocolVersionException.java
@@ -26,19 +26,24 @@ package org.apache.qpid.transport;
*
*/
-public final class ProtocolVersionException extends TransportException
+public final class ProtocolVersionException extends ConnectionException
{
private final byte major;
private final byte minor;
- public ProtocolVersionException(byte major, byte minor)
+ public ProtocolVersionException(byte major, byte minor, Throwable cause)
{
- super(String.format("version missmatch: %s-%s", major, minor));
+ super(String.format("version mismatch: %s-%s", major, minor), cause);
this.major = major;
this.minor = minor;
}
+ public ProtocolVersionException(byte major, byte minor)
+ {
+ this(major, minor, null);
+ }
+
public byte getMajor()
{
return this.major;
@@ -49,4 +54,9 @@ public final class ProtocolVersionException extends TransportException
return this.minor;
}
+ @Override public void rethrow()
+ {
+ throw new ProtocolVersionException(major, minor, this);
+ }
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ProtocolViolationException.java b/java/common/src/main/java/org/apache/qpid/transport/ProtocolViolationException.java
new file mode 100644
index 0000000000..6787157e8e
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/ProtocolViolationException.java
@@ -0,0 +1,35 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.transport;
+
+
+/**
+ * ProtocolViolationException
+ *
+ */
+
+public final class ProtocolViolationException extends ConnectionException
+{
+ public ProtocolViolationException(String msg,Throwable cause)
+ {
+ super(msg, cause);
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/RangeSet.java b/java/common/src/main/java/org/apache/qpid/transport/RangeSet.java
index 9b2744ee8b..3850dc162b 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/RangeSet.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/RangeSet.java
@@ -52,6 +52,11 @@ public final class RangeSet implements Iterable<Range>
return ranges.getFirst();
}
+ public Range getLast()
+ {
+ return ranges.getLast();
+ }
+
public boolean includes(Range range)
{
for (Range r : this)
diff --git a/java/common/src/main/java/org/apache/qpid/transport/Sender.java b/java/common/src/main/java/org/apache/qpid/transport/Sender.java
index 9a6f675d7f..475289c83f 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/Sender.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/Sender.java
@@ -28,6 +28,7 @@ package org.apache.qpid.transport;
public interface Sender<T>
{
+ void setIdleTimeout(long l);
void send(T msg);
diff --git a/java/common/src/main/java/org/apache/qpid/transport/SenderException.java b/java/common/src/main/java/org/apache/qpid/transport/SenderException.java
new file mode 100644
index 0000000000..a96079dc27
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/SenderException.java
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.transport;
+
+
+/**
+ * SenderException
+ *
+ */
+
+public class SenderException extends TransportException
+{
+
+ public SenderException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+
+ public SenderException(String message)
+ {
+ super(message);
+ }
+
+ public SenderException(Throwable cause)
+ {
+ super(cause);
+ }
+
+ public void rethrow()
+ {
+ throw new SenderException(getMessage(), this);
+ }
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java b/java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java
new file mode 100644
index 0000000000..453921ea2b
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java
@@ -0,0 +1,183 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.transport;
+
+import java.util.Collections;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+
+import java.io.UnsupportedEncodingException;
+
+import org.apache.qpid.QpidException;
+
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+
+
+import static org.apache.qpid.transport.Connection.State.*;
+
+
+/**
+ * ServerDelegate
+ *
+ */
+
+public class ServerDelegate extends ConnectionDelegate
+{
+
+ private SaslServer saslServer;
+ private List<Object> _locales;
+ private List<Object> _mechanisms;
+ private Map<String, Object> _clientProperties;
+
+
+ public ServerDelegate()
+ {
+ this(null, Collections.EMPTY_LIST, Collections.singletonList((Object)"utf8"));
+ }
+
+ protected ServerDelegate(Map<String, Object> clientProperties, List<Object> mechanisms, List<Object> locales)
+ {
+ _clientProperties = clientProperties;
+ _mechanisms = mechanisms;
+ _locales = locales;
+ }
+
+ public void init(Connection conn, ProtocolHeader hdr)
+ {
+ conn.send(new ProtocolHeader(1, 0, 10));
+
+ conn.connectionStart(_clientProperties, _mechanisms, _locales);
+ }
+
+ @Override public void connectionStartOk(Connection conn, ConnectionStartOk ok)
+ {
+ conn.setLocale(ok.getLocale());
+ String mechanism = ok.getMechanism();
+
+ if (mechanism == null || mechanism.length() == 0)
+ {
+ conn.connectionTune
+ (Integer.MAX_VALUE,
+ org.apache.qpid.transport.network.ConnectionBinding.MAX_FRAME_SIZE,
+ 0, Integer.MAX_VALUE);
+ return;
+ }
+
+ try
+ {
+
+ SaslServer ss = createSaslServer(mechanism);
+ if (ss == null)
+ {
+ conn.connectionClose
+ (ConnectionCloseCode.CONNECTION_FORCED,
+ "null SASL mechanism: " + mechanism);
+ return;
+ }
+ conn.setSaslServer(ss);
+ secure(conn, ok.getResponse());
+ }
+ catch (SaslException e)
+ {
+ conn.exception(e);
+ }
+ }
+
+ protected SaslServer createSaslServer(String mechanism)
+ throws SaslException
+ {
+ SaslServer ss = Sasl.createSaslServer
+ (mechanism, "AMQP", "localhost", null, null);
+ return ss;
+ }
+
+ private void secure(Connection conn, byte[] response)
+ {
+ SaslServer ss = conn.getSaslServer();
+ try
+ {
+ byte[] challenge = ss.evaluateResponse(response);
+ if (ss.isComplete())
+ {
+ ss.dispose();
+ conn.connectionTune
+ (Integer.MAX_VALUE,
+ org.apache.qpid.transport.network.ConnectionBinding.MAX_FRAME_SIZE,
+ 0, Integer.MAX_VALUE);
+ conn.setAuthorizationID(ss.getAuthorizationID());
+ }
+ else
+ {
+ conn.connectionSecure(challenge);
+ }
+ }
+ catch (SaslException e)
+ {
+ conn.exception(e);
+ }
+ }
+
+ @Override public void connectionSecureOk(Connection conn, ConnectionSecureOk ok)
+ {
+ secure(conn, ok.getResponse());
+ }
+
+ @Override public void connectionTuneOk(Connection conn, ConnectionTuneOk ok)
+ {
+
+ }
+
+ @Override public void connectionOpen(Connection conn, ConnectionOpen open)
+ {
+ conn.connectionOpenOk(Collections.EMPTY_LIST);
+
+ conn.setState(OPEN);
+ }
+
+ protected Session getSession(Connection conn, SessionDelegate delegate, SessionAttach atc)
+ {
+ return new Session(conn, delegate, new Binary(atc.getName()), 0);
+ }
+
+
+ public Session getSession(Connection conn, SessionAttach atc)
+ {
+ return new Session(conn, new Binary(atc.getName()), 0);
+ }
+
+ @Override public void sessionAttach(Connection conn, SessionAttach atc)
+ {
+ Session ssn = getSession(conn, atc);
+ conn.map(ssn, atc.getChannel());
+ ssn.sessionAttached(atc.getName());
+ ssn.setState(Session.State.OPEN);
+ }
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/Session.java b/java/common/src/main/java/org/apache/qpid/transport/Session.java
index 10ca6cfb0a..818bb19c08 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/Session.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/Session.java
@@ -24,6 +24,7 @@ package org.apache.qpid.transport;
import org.apache.qpid.transport.network.Frame;
import org.apache.qpid.transport.util.Logger;
+import org.apache.qpid.transport.util.Waiter;
import java.nio.ByteBuffer;
import java.util.ArrayList;
@@ -32,8 +33,11 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
import static org.apache.qpid.transport.Option.*;
+import static org.apache.qpid.transport.Session.State.*;
import static org.apache.qpid.transport.util.Functions.*;
import static org.apache.qpid.util.Serial.*;
import static org.apache.qpid.util.Strings.*;
@@ -44,59 +48,125 @@ import static org.apache.qpid.util.Strings.*;
* @author Rafael H. Schloming
*/
-public class Session extends Invoker
+public class Session extends SessionInvoker
{
private static final Logger log = Logger.get(Session.class);
- private static boolean ENABLE_REPLAY = false;
+ enum State { NEW, DETACHED, RESUMING, OPEN, CLOSING, CLOSED }
- static
+ class DefaultSessionListener implements SessionListener
{
- String enableReplay = "enable_command_replay";
- try
+
+ public void opened(Session ssn) {}
+
+ public void resumed(Session ssn) {}
+
+ public void message(Session ssn, MessageTransfer xfr)
{
- ENABLE_REPLAY = new Boolean(System.getProperties().getProperty(enableReplay, "false"));
+ log.info("message: %s", xfr);
}
- catch (Exception e)
+
+ public void exception(Session ssn, SessionException exc)
{
- ENABLE_REPLAY = false;
+ log.error(exc, "session exception");
}
+
+ public void closed(Session ssn) {}
}
- private byte[] name;
+ public static final int UNLIMITED_CREDIT = 0xFFFFFFFF;
+
+ private Connection connection;
+ private Binary name;
+ private long expiry;
+ private int channel;
+ private SessionDelegate delegate;
+ private SessionListener listener = new DefaultSessionListener();
private long timeout = 60000;
private boolean autoSync = false;
- // channel may be null
- Channel channel;
-
+ private boolean incomingInit;
// incoming command count
- int commandsIn = 0;
+ private int commandsIn;
// completed incoming commands
private final Object processedLock = new Object();
- private RangeSet processed = new RangeSet();
- private int maxProcessed = commandsIn - 1;
- private int syncPoint = maxProcessed;
+ private RangeSet processed;
+ private int maxProcessed;
+ private int syncPoint;
// outgoing command count
private int commandsOut = 0;
- private Map<Integer,Method> commands = new HashMap<Integer,Method>();
+ private Method[] commands = new Method[Integer.getInteger("qpid.session.command_limit", 64*1024)];
+ private int commandBytes = 0;
+ private int byteLimit = Integer.getInteger("qpid.session.byte_limit", 1024*1024);
private int maxComplete = commandsOut - 1;
private boolean needSync = false;
- private AtomicBoolean closed = new AtomicBoolean(false);
+ private State state = NEW;
+
+ // transfer flow control
+ private volatile boolean flowControl = false;
+ private Semaphore credit = new Semaphore(0);
+
+ private Thread resumer = null;
- public Session(byte[] name)
+ protected Session(Connection connection, Binary name, long expiry)
{
+ this(connection, new SessionDelegate(), name, expiry);
+ }
+
+ protected Session(Connection connection, SessionDelegate delegate, Binary name, long expiry)
+ {
+ this.connection = connection;
+ this.delegate = delegate;
this.name = name;
+ this.expiry = expiry;
+ initReceiver();
+ }
+
+ public Connection getConnection()
+ {
+ return connection;
}
- public byte[] getName()
+ public Binary getName()
{
return name;
}
+ void setExpiry(long expiry)
+ {
+ this.expiry = expiry;
+ }
+
+ int getChannel()
+ {
+ return channel;
+ }
+
+ void setChannel(int channel)
+ {
+ this.channel = channel;
+ }
+
+ public void setSessionListener(SessionListener listener)
+ {
+ if (listener == null)
+ {
+ this.listener = new DefaultSessionListener();
+ }
+ else
+ {
+ this.listener = listener;
+ }
+ }
+
+ public SessionListener getSessionListener()
+ {
+ return listener;
+ }
+
public void setAutoSync(boolean value)
{
synchronized (commands)
@@ -105,9 +175,119 @@ public class Session extends Invoker
}
}
- public Map<Integer,Method> getOutstandingCommands()
+ void setState(State state)
+ {
+ synchronized (commands)
+ {
+ this.state = state;
+ commands.notifyAll();
+ }
+ }
+
+ void setFlowControl(boolean value)
+ {
+ flowControl = value;
+ }
+
+ void addCredit(int value)
+ {
+ credit.release(value);
+ }
+
+ void drainCredit()
{
- return commands;
+ credit.drainPermits();
+ }
+
+ void acquireCredit()
+ {
+ if (flowControl)
+ {
+ try
+ {
+ if (!credit.tryAcquire(timeout, TimeUnit.MILLISECONDS))
+ {
+ throw new SessionException
+ ("timed out waiting for message credit");
+ }
+ }
+ catch (InterruptedException e)
+ {
+ throw new SessionException
+ ("interrupted while waiting for credit", null, e);
+ }
+ }
+ }
+
+ private void initReceiver()
+ {
+ synchronized (processedLock)
+ {
+ incomingInit = false;
+ processed = new RangeSet();
+ }
+ }
+
+ void attach()
+ {
+ initReceiver();
+ sessionAttach(name.getBytes());
+ // XXX: when the broker and client support full session
+ // recovery we should use expiry as the requested timeout
+ sessionRequestTimeout(0);
+ }
+
+ void resume()
+ {
+ synchronized (commands)
+ {
+ for (int i = maxComplete + 1; lt(i, commandsOut); i++)
+ {
+ Method m = commands[mod(i, commands.length)];
+ if (m == null)
+ {
+ m = new ExecutionSync();
+ m.setId(i);
+ }
+ sessionCommandPoint(m.getId(), 0);
+ send(m);
+ }
+
+ sessionCommandPoint(commandsOut, 0);
+ sessionFlush(COMPLETED);
+ resumer = Thread.currentThread();
+ state = RESUMING;
+ listener.resumed(this);
+ resumer = null;
+ }
+ }
+
+ void dump()
+ {
+ synchronized (commands)
+ {
+ for (Method m : commands)
+ {
+ if (m != null)
+ {
+ System.out.println(m);
+ }
+ }
+ }
+ }
+
+ final void commandPoint(int id)
+ {
+ synchronized (processedLock)
+ {
+ this.commandsIn = id;
+ if (!incomingInit)
+ {
+ incomingInit = true;
+ maxProcessed = commandsIn - 1;
+ syncPoint = maxProcessed;
+ }
+ }
}
public int getCommandsOut()
@@ -127,6 +307,11 @@ public class Session extends Invoker
final void identify(Method cmd)
{
+ if (!incomingInit)
+ {
+ throw new IllegalStateException();
+ }
+
int id = nextCommandId();
cmd.setId(id);
@@ -160,11 +345,19 @@ public class Session extends Invoker
public void processed(Range range)
{
- log.debug("%s processed(%s)", this, range);
+ log.debug("%s processed(%s) %s %s", this, range, syncPoint, maxProcessed);
boolean flush;
synchronized (processedLock)
{
+ log.debug("%s", processed);
+
+ if (ge(range.getUpper(), commandsIn))
+ {
+ throw new IllegalArgumentException
+ ("range exceeds max received command-id: " + range);
+ }
+
processed.add(range);
Range first = processed.getFirst();
int lower = first.getLower();
@@ -174,8 +367,12 @@ public class Session extends Invoker
{
maxProcessed = max(maxProcessed, upper);
}
- flush = lt(old, syncPoint) && ge(maxProcessed, syncPoint);
- syncPoint = maxProcessed;
+ boolean synced = ge(maxProcessed, syncPoint);
+ flush = lt(old, syncPoint) && synced;
+ if (synced)
+ {
+ syncPoint = maxProcessed;
+ }
}
if (flush)
{
@@ -183,6 +380,19 @@ public class Session extends Invoker
}
}
+ void flushExpected()
+ {
+ RangeSet rs = new RangeSet();
+ synchronized (processedLock)
+ {
+ if (incomingInit)
+ {
+ rs.add(commandsIn);
+ }
+ }
+ sessionExpected(rs, null);
+ }
+
public void flushProcessed(Option ... options)
{
RangeSet copy;
@@ -190,7 +400,15 @@ public class Session extends Invoker
{
copy = processed.copy();
}
- sessionCompleted(copy, options);
+
+ synchronized (commands)
+ {
+ if (state == DETACHED || state == CLOSING)
+ {
+ return;
+ }
+ sessionCompleted(copy, options);
+ }
}
void knownComplete(RangeSet kc)
@@ -228,21 +446,7 @@ public class Session extends Invoker
}
}
- public void attach(Channel channel)
- {
- this.channel = channel;
- channel.setSession(this);
- }
-
- public Method getCommand(int id)
- {
- synchronized (commands)
- {
- return commands.get(id);
- }
- }
-
- boolean complete(int lower, int upper)
+ protected boolean complete(int lower, int upper)
{
//avoid autoboxing
if(log.isDebugEnabled())
@@ -254,57 +458,210 @@ public class Session extends Invoker
int old = maxComplete;
for (int id = max(maxComplete, lower); le(id, upper); id++)
{
- commands.remove(id);
+ int idx = mod(id, commands.length);
+ Method m = commands[idx];
+ if (m != null)
+ {
+ commandBytes -= m.getBodySize();
+ m.complete();
+ commands[idx] = null;
+ }
}
if (le(lower, maxComplete + 1))
{
maxComplete = max(maxComplete, upper);
}
- log.debug("%s commands remaining: %s", this, commands);
+ log.debug("%s commands remaining: %s", this, commandsOut - maxComplete);
commands.notifyAll();
return gt(maxComplete, old);
}
}
- public void invoke(Method m)
+ void received(Method m)
{
- if (closed.get())
+ m.delegate(this, delegate);
+ }
+
+ private void send(Method m)
+ {
+ m.setChannel(channel);
+ connection.send(m);
+
+ if (!m.isBatch())
{
- List<ExecutionException> exc = getExceptions();
- if (!exc.isEmpty())
- {
- throw new SessionException(exc);
- }
- else if (close != null)
- {
- throw new ConnectionException(close);
- }
- else
- {
- throw new SessionClosedException();
- }
+ connection.flush();
}
+ }
+
+ protected boolean isFull(int id)
+ {
+ return isCommandsFull(id) || isBytesFull();
+ }
+
+ protected boolean isBytesFull()
+ {
+ return commandBytes >= byteLimit;
+ }
+
+ protected boolean isCommandsFull(int id)
+ {
+ return id - maxComplete >= commands.length;
+ }
+
+ public void invoke(Method m)
+ {
+ invoke(m,(Runnable)null);
+ }
+ public void invoke(Method m, Runnable postIdSettingAction)
+ {
if (m.getEncodedTrack() == Frame.L4)
{
+ if (m.hasPayload())
+ {
+ acquireCredit();
+ }
+
synchronized (commands)
{
- int next = commandsOut++;
+ if (state == DETACHED && m.isUnreliable())
+ {
+ Thread current = Thread.currentThread();
+ if (!current.equals(resumer))
+ {
+ return;
+ }
+ }
+
+ if (state != OPEN && state != CLOSED)
+ {
+ Thread current = Thread.currentThread();
+ if (!current.equals(resumer))
+ {
+ Waiter w = new Waiter(commands, timeout);
+ while (w.hasTime() && (state != OPEN && state != CLOSED))
+ {
+ w.await();
+ }
+ }
+ }
+
+ switch (state)
+ {
+ case OPEN:
+ break;
+ case RESUMING:
+ Thread current = Thread.currentThread();
+ if (!current.equals(resumer))
+ {
+ throw new SessionException
+ ("timed out waiting for resume to finish");
+ }
+ break;
+ case CLOSED:
+ ExecutionException exc = getException();
+ if (exc != null)
+ {
+ throw new SessionException(exc);
+ }
+ else
+ {
+ throw new SessionClosedException();
+ }
+ default:
+ throw new SessionException
+ (String.format
+ ("timed out waiting for session to become open " +
+ "(state=%s)", state));
+ }
+
+ int next;
+ next = commandsOut++;
m.setId(next);
+ if(postIdSettingAction != null)
+ {
+ postIdSettingAction.run();
+ }
+
+ if (isFull(next))
+ {
+ Waiter w = new Waiter(commands, timeout);
+ while (w.hasTime() && isFull(next) && state != CLOSED)
+ {
+ if (state == OPEN || state == RESUMING)
+ {
+ try
+ {
+ sessionFlush(COMPLETED);
+ }
+ catch (SenderException e)
+ {
+ if (expiry > 0)
+ {
+ // if expiry is > 0 then this will
+ // happen again on resume
+ log.error(e, "error sending flush (full replay buffer)");
+ }
+ else
+ {
+ e.rethrow();
+ }
+ }
+ }
+ w.await();
+ }
+ }
+
+ if (state == CLOSED)
+ {
+ ExecutionException exc = getException();
+ if (exc != null)
+ {
+ throw new SessionException(exc);
+ }
+ else
+ {
+ throw new SessionClosedException();
+ }
+ }
+
+ if (isFull(next))
+ {
+ throw new SessionException("timed out waiting for completion");
+ }
+
if (next == 0)
{
sessionCommandPoint(0, 0);
}
- if (ENABLE_REPLAY)
+ if ((expiry > 0 && !m.isUnreliable()) || m.hasCompletionListener())
{
- commands.put(next, m);
+ commands[mod(next, commands.length)] = m;
+ commandBytes += m.getBodySize();
}
if (autoSync)
{
m.setSync(true);
}
needSync = !m.isSync();
- channel.method(m);
+
+ try
+ {
+ send(m);
+ }
+ catch (SenderException e)
+ {
+ if (expiry > 0)
+ {
+ // if expiry is > 0 then this will happen
+ // again on resume
+ log.error(e, "error sending command");
+ }
+ else
+ {
+ e.rethrow();
+ }
+ }
if (autoSync)
{
sync();
@@ -312,18 +669,39 @@ public class Session extends Invoker
// flush every 64K commands to avoid ambiguity on
// wraparound
- if ((next % 65536) == 0)
+ if (shouldIssueFlush(next))
{
- sessionFlush(COMPLETED);
+ try
+ {
+ sessionFlush(COMPLETED);
+ }
+ catch (SenderException e)
+ {
+ if (expiry > 0)
+ {
+ // if expiry is > 0 then this will happen
+ // again on resume
+ log.error(e, "error sending flush (periodic)");
+ }
+ else
+ {
+ e.rethrow();
+ }
+ }
}
}
}
else
{
- channel.method(m);
+ send(m);
}
}
+ protected boolean shouldIssueFlush(int next)
+ {
+ return (next % 65536) == 0;
+ }
+
public void sync()
{
sync(timeout);
@@ -341,31 +719,23 @@ public class Session extends Invoker
executionSync(SYNC);
}
- long start = System.currentTimeMillis();
- long elapsed = 0;
- while (!closed.get() && elapsed < timeout && lt(maxComplete, point))
+ Waiter w = new Waiter(commands, timeout);
+ while (w.hasTime() && state != CLOSED && lt(maxComplete, point))
{
- try {
- log.debug("%s waiting for[%d]: %d, %s", this, point,
- maxComplete, commands);
- commands.wait(timeout - elapsed);
- elapsed = System.currentTimeMillis() - start;
- }
- catch (InterruptedException e)
- {
- throw new RuntimeException(e);
- }
+ log.debug("%s waiting for[%d]: %d, %s", this, point,
+ maxComplete, commands);
+ w.await();
}
if (lt(maxComplete, point))
{
- if (closed.get())
+ if (state == CLOSED)
{
- throw new SessionException(getExceptions());
+ throw new SessionException(getException());
}
else
{
- throw new RuntimeException
+ throw new SessionException
(String.format
("timed out waiting for sync: complete = %s, point = %s", maxComplete, point));
}
@@ -375,8 +745,7 @@ public class Session extends Invoker
private Map<Integer,ResultFuture<?>> results =
new HashMap<Integer,ResultFuture<?>>();
- private List<ExecutionException> exceptions =
- new ArrayList<ExecutionException>();
+ private ExecutionException exception = null;
void result(int command, Struct result)
{
@@ -388,11 +757,17 @@ public class Session extends Invoker
future.set(result);
}
- void addException(ExecutionException exc)
+ void setException(ExecutionException exc)
{
- synchronized (exceptions)
+ synchronized (results)
{
- exceptions.add(exc);
+ if (exception != null)
+ {
+ throw new IllegalStateException
+ (String.format
+ ("too many exceptions: %s, %s", exception, exc));
+ }
+ exception = exc;
}
}
@@ -403,11 +778,11 @@ public class Session extends Invoker
this.close = close;
}
- List<ExecutionException> getExceptions()
+ ExecutionException getException()
{
- synchronized (exceptions)
+ synchronized (results)
{
- return new ArrayList<ExecutionException>(exceptions);
+ return exception;
}
}
@@ -450,20 +825,11 @@ public class Session extends Invoker
{
synchronized (this)
{
- long start = System.currentTimeMillis();
- long elapsed = 0;
- while (!closed.get() && timeout - elapsed > 0 && !isDone())
+ Waiter w = new Waiter(this, timeout);
+ while (w.hasTime() && state != CLOSED && !isDone())
{
- try
- {
- log.debug("%s waiting for result: %s", Session.this, this);
- wait(timeout - elapsed);
- elapsed = System.currentTimeMillis() - start;
- }
- catch (InterruptedException e)
- {
- throw new RuntimeException(e);
- }
+ log.debug("%s waiting for result: %s", Session.this, this);
+ w.await();
}
}
@@ -471,13 +837,15 @@ public class Session extends Invoker
{
return result;
}
- else if (closed.get())
+ else if (state == CLOSED)
{
- throw new SessionException(getExceptions());
+ throw new SessionException(getException());
}
else
{
- return null;
+ throw new SessionException
+ (String.format("%s timed out waiting for result: %s",
+ Session.this, this));
}
}
@@ -520,25 +888,29 @@ public class Session extends Invoker
public void close()
{
- sessionRequestTimeout(0);
- sessionDetach(name);
synchronized (commands)
{
- long start = System.currentTimeMillis();
- long elapsed = 0;
- try
+ state = CLOSING;
+ // XXX: we manually set the expiry to zero here to
+ // simulate full session recovery in brokers that don't
+ // support it, we should remove this line when there is
+ // broker support for full session resume:
+ expiry = 0;
+ sessionRequestTimeout(0);
+ sessionDetach(name.getBytes());
+ Waiter w = new Waiter(commands, timeout);
+ while (w.hasTime() && state != CLOSED)
{
- while (!closed.get() && elapsed < timeout)
- {
- commands.wait(timeout - elapsed);
- elapsed = System.currentTimeMillis() - start;
- }
+ w.await();
}
- catch (InterruptedException e)
+
+ if (state != CLOSED)
{
- throw new RuntimeException(e);
+ throw new SessionException("close() timed out");
}
}
+
+ connection.removeSession(this);
}
public void exception(Throwable t)
@@ -548,28 +920,43 @@ public class Session extends Invoker
public void closed()
{
- closed.set(true);
synchronized (commands)
{
+ if (expiry == 0 || getException() != null)
+ {
+ state = CLOSED;
+ }
+ else
+ {
+ state = DETACHED;
+ }
+
commands.notifyAll();
- }
- synchronized (results)
- {
- for (ResultFuture<?> result : results.values())
+
+ synchronized (results)
{
- synchronized(result)
+ for (ResultFuture<?> result : results.values())
{
- result.notifyAll();
+ synchronized(result)
+ {
+ result.notifyAll();
+ }
}
}
+ if(state == CLOSED)
+ {
+ delegate.closed(this);
+ }
+ else
+ {
+ delegate.detached(this);
+ }
}
- channel.setSession(null);
- channel = null;
}
public String toString()
{
- return String.format("ssn:%s", str(name));
+ return String.format("ssn:%s", name);
}
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/SessionClosedException.java b/java/common/src/main/java/org/apache/qpid/transport/SessionClosedException.java
index d2c54cf339..64f9039484 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/SessionClosedException.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/SessionClosedException.java
@@ -33,7 +33,17 @@ public class SessionClosedException extends SessionException
public SessionClosedException()
{
- super(Collections.EMPTY_LIST);
+ this(null);
+ }
+
+ public SessionClosedException(Throwable cause)
+ {
+ super("session closed", null, cause);
+ }
+
+ @Override public void rethrow()
+ {
+ throw new SessionClosedException(this);
}
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/SessionDelegate.java b/java/common/src/main/java/org/apache/qpid/transport/SessionDelegate.java
index 5e4336f988..6146f029b2 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/SessionDelegate.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/SessionDelegate.java
@@ -20,7 +20,7 @@
*/
package org.apache.qpid.transport;
-import org.apache.qpid.transport.network.Frame;
+import org.apache.qpid.transport.util.Logger;
/**
@@ -29,10 +29,12 @@ import org.apache.qpid.transport.network.Frame;
* @author Rafael H. Schloming
*/
-public abstract class SessionDelegate
+public class SessionDelegate
extends MethodDelegate<Session>
implements ProtocolDelegate<Session>
{
+ private static final Logger log = Logger.get(SessionDelegate.class);
+
public void init(Session ssn, ProtocolHeader hdr) { }
public void control(Session ssn, Method method) {
@@ -42,7 +44,7 @@ public abstract class SessionDelegate
public void command(Session ssn, Method method) {
ssn.identify(method);
method.dispatch(ssn, this);
- if (!method.hasPayloadSegment())
+ if (!method.hasPayload())
{
ssn.processed(method);
}
@@ -50,14 +52,21 @@ public abstract class SessionDelegate
public void error(Session ssn, ProtocolError error) { }
- @Override public void executionResult(Session ssn, ExecutionResult result)
+ public void handle(Session ssn, Method method)
{
- ssn.result(result.getCommandId(), result.getValue());
+ log.warn("UNHANDLED: [%s] %s", ssn, method);
}
- @Override public void executionException(Session ssn, ExecutionException exc)
+ @Override public void sessionAttached(Session ssn, SessionAttached atc)
{
- ssn.addException(exc);
+ ssn.setState(Session.State.OPEN);
+ }
+
+ @Override public void sessionTimeout(Session ssn, SessionTimeout t)
+ {
+ // XXX: we ignore this right now, we should uncomment this
+ // when full session resume is supported:
+ // ssn.setExpiry(t.getTimeout());
}
@Override public void sessionCompleted(Session ssn, SessionCompleted cmp)
@@ -108,13 +117,13 @@ public abstract class SessionDelegate
}
if (flush.getExpected())
{
- throw new Error("not implemented");
+ ssn.flushExpected();
}
}
@Override public void sessionCommandPoint(Session ssn, SessionCommandPoint scp)
{
- ssn.commandsIn = scp.getCommandId();
+ ssn.commandPoint(scp.getCommandId());
}
@Override public void executionSync(Session ssn, ExecutionSync sync)
@@ -122,4 +131,64 @@ public abstract class SessionDelegate
ssn.syncPoint();
}
+ @Override public void executionResult(Session ssn, ExecutionResult result)
+ {
+ ssn.result(result.getCommandId(), result.getValue());
+ }
+
+ @Override public void executionException(Session ssn, ExecutionException exc)
+ {
+ ssn.setException(exc);
+ }
+
+ @Override public void messageTransfer(Session ssn, MessageTransfer xfr)
+ {
+ ssn.getSessionListener().message(ssn, xfr);
+ }
+
+ @Override public void messageSetFlowMode(Session ssn, MessageSetFlowMode sfm)
+ {
+ if ("".equals(sfm.getDestination()) &&
+ MessageFlowMode.CREDIT.equals(sfm.getFlowMode()))
+ {
+ ssn.setFlowControl(true);
+ }
+ else
+ {
+ super.messageSetFlowMode(ssn, sfm);
+ }
+ }
+
+ @Override public void messageFlow(Session ssn, MessageFlow flow)
+ {
+ if ("".equals(flow.getDestination()) &&
+ MessageCreditUnit.MESSAGE.equals(flow.getUnit()))
+ {
+ ssn.addCredit((int) flow.getValue());
+ }
+ else
+ {
+ super.messageFlow(ssn, flow);
+ }
+ }
+
+ @Override public void messageStop(Session ssn, MessageStop stop)
+ {
+ if ("".equals(stop.getDestination()))
+ {
+ ssn.drainCredit();
+ }
+ else
+ {
+ super.messageStop(ssn, stop);
+ }
+ }
+
+ public void closed(Session session)
+ {
+ }
+
+ public void detached(Session session)
+ {
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/SessionException.java b/java/common/src/main/java/org/apache/qpid/transport/SessionException.java
index dc294b2206..c4fc9558a1 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/SessionException.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/SessionException.java
@@ -27,20 +27,35 @@ import java.util.List;
*
*/
-public class SessionException extends RuntimeException
+public class SessionException extends TransportException
{
- private List<ExecutionException> exceptions;
+ private ExecutionException exception;
- public SessionException(List<ExecutionException> exceptions)
+ public SessionException(String message, ExecutionException exception, Throwable cause)
{
- super(exceptions.isEmpty() ? "" : exceptions.toString());
- this.exceptions = exceptions;
+ super(message, cause);
+ this.exception = exception;
}
- public List<ExecutionException> getExceptions()
+ public SessionException(ExecutionException exception)
{
- return exceptions;
+ this(String.valueOf(exception), exception, null);
+ }
+
+ public SessionException(String message)
+ {
+ this(message, null, null);
+ }
+
+ public ExecutionException getException()
+ {
+ return exception;
+ }
+
+ @Override public void rethrow()
+ {
+ throw new SessionException(getMessage(), exception, this);
}
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/SessionListener.java b/java/common/src/main/java/org/apache/qpid/transport/SessionListener.java
new file mode 100644
index 0000000000..eb650eb9ed
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/SessionListener.java
@@ -0,0 +1,42 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.transport;
+
+
+/**
+ * SessionListener
+ *
+ */
+
+public interface SessionListener
+{
+
+ void opened(Session session);
+
+ void resumed(Session session);
+
+ void message(Session ssn, MessageTransfer xfr);
+
+ void exception(Session session, SessionException exception);
+
+ void closed(Session session);
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/Sink.java b/java/common/src/main/java/org/apache/qpid/transport/Sink.java
index 8653acedbe..88870284f6 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/Sink.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/Sink.java
@@ -31,7 +31,7 @@ import org.apache.qpid.transport.network.io.IoAcceptor;
*
*/
-public class Sink extends SessionDelegate
+public class Sink implements SessionListener
{
private static final String FORMAT_HDR = "%-12s %-18s %-18s %-18s";
@@ -85,7 +85,11 @@ public class Sink extends SessionDelegate
return String.format("%d/%.2f", count, ((double) bytes)/(1024*1024));
}
- public void messageTransfer(Session ssn, MessageTransfer xfr)
+ public void opened(Session ssn) {}
+
+ public void resumed(Session ssn) {}
+
+ public void message(Session ssn, MessageTransfer xfr)
{
count++;
bytes += xfr.getBody().remaining();
@@ -101,30 +105,27 @@ public class Sink extends SessionDelegate
ssn.processed(xfr);
}
- public static final void main(String[] args) throws IOException
+ public void exception(Session ssn, SessionException exc)
{
- ConnectionDelegate delegate = new ConnectionDelegate()
- {
+ exc.printStackTrace();
+ }
- public SessionDelegate getSessionDelegate()
- {
- return new Sink();
- }
+ public void closed(Session ssn) {}
- public void exception(Throwable t)
+ public static final void main(String[] args) throws IOException
+ {
+ ConnectionDelegate delegate = new ServerDelegate()
+ {
+ @Override public Session getSession(Connection conn, SessionAttach atc)
{
- t.printStackTrace();
+ Session ssn = super.getSession(conn, atc);
+ ssn.setSessionListener(new Sink());
+ return ssn;
}
-
- public void closed() {}
};
- //hack
- delegate.setUsername("guest");
- delegate.setPassword("guest");
-
IoAcceptor ioa = new IoAcceptor
- ("0.0.0.0", 5672, new ConnectionBinding(delegate));
+ ("0.0.0.0", 5672, ConnectionBinding.get(delegate));
System.out.println
(String.format
(FORMAT_HDR, "Session", "Count/MBytes", "Cumulative Rate", "Interval Rate"));
diff --git a/java/common/src/main/java/org/apache/qpid/transport/Struct.java b/java/common/src/main/java/org/apache/qpid/transport/Struct.java
index 097a6de1b5..22bd9f34ad 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/Struct.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/Struct.java
@@ -42,7 +42,7 @@ public abstract class Struct implements Encodable
return StructFactory.create(type);
}
- protected boolean dirty = true;
+ boolean dirty = true;
public boolean isDirty()
{
diff --git a/java/common/src/main/java/org/apache/qpid/transport/TransportException.java b/java/common/src/main/java/org/apache/qpid/transport/TransportException.java
index 5ef15154fc..0de190dfad 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/TransportException.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/TransportException.java
@@ -43,4 +43,9 @@ public class TransportException extends RuntimeException
super(cause);
}
+ public void rethrow()
+ {
+ throw new TransportException(getMessage(), this);
+ }
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/codec/BBDecoder.java b/java/common/src/main/java/org/apache/qpid/transport/codec/BBDecoder.java
index dd634eb94a..6f7a2fa3b2 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/codec/BBDecoder.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/codec/BBDecoder.java
@@ -25,16 +25,14 @@ import java.nio.ByteOrder;
import org.apache.qpid.transport.Binary;
-
/**
- * BBDecoder
+ * Byte Buffer Decoder.
+ * Decoder concrete implementor using a backing byte buffer for decoding data.
*
* @author Rafael H. Schloming
*/
-
public final class BBDecoder extends AbstractDecoder
{
-
private ByteBuffer in;
public void init(ByteBuffer in)
@@ -93,4 +91,54 @@ public final class BBDecoder extends AbstractDecoder
return in.getLong();
}
-}
+ public byte[] readBin128()
+ {
+ byte[] result = new byte[16];
+ get(result);
+ return result;
+ }
+
+ public byte[] readBytes(int howManyBytes)
+ {
+ byte[] result = new byte[howManyBytes];
+ get(result);
+ return result;
+ }
+
+ public double readDouble()
+ {
+ return in.getDouble();
+ }
+
+ public float readFloat()
+ {
+ return in.getFloat();
+ }
+
+ public short readInt16()
+ {
+ return in.getShort();
+ }
+
+ public int readInt32()
+ {
+ return in.getInt();
+ }
+
+ public byte readInt8()
+ {
+ return in.get();
+ }
+
+ public byte[] readReaminingBytes()
+ {
+ byte[] result = new byte[in.limit() - in.position()];
+ get(result);
+ return result;
+ }
+
+ public long readInt64()
+ {
+ return in.getLong();
+ }
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java b/java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java
index 390de881ab..d18a0f64db 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java
@@ -26,14 +26,13 @@ import java.nio.ByteOrder;
/**
- * BBEncoder
- *
+ * Byte Buffer Encoder.
+ * Encoder concrete implementor using a backing byte buffer for encoding data.
+ *
* @author Rafael H. Schloming
*/
-
public final class BBEncoder extends AbstractEncoder
{
-
private ByteBuffer out;
private int segment;
@@ -60,12 +59,23 @@ public final class BBEncoder extends AbstractEncoder
return slice;
}
+ public ByteBuffer buffer()
+ {
+ int pos = out.position();
+ out.position(segment);
+ ByteBuffer slice = out.slice();
+ slice.limit(pos - segment);
+ out.position(pos);
+ return slice;
+ }
+
private void grow(int size)
{
ByteBuffer old = out;
int capacity = old.capacity();
out = ByteBuffer.allocate(Math.max(capacity + size, 2*capacity));
out.order(ByteOrder.BIG_ENDIAN);
+ old.flip();
out.put(old);
}
@@ -229,4 +239,96 @@ public final class BBEncoder extends AbstractEncoder
out.putInt(pos, (cur - pos - 4));
}
-}
+ public void writeDouble(double aDouble)
+ {
+ try
+ {
+ out.putDouble(aDouble);
+ } catch(BufferOverflowException exception)
+ {
+ grow(8);
+ out.putDouble(aDouble);
+ }
+ }
+
+ public void writeInt16(short aShort)
+ {
+ try
+ {
+ out.putShort(aShort);
+ } catch(BufferOverflowException exception)
+ {
+ grow(2);
+ out.putShort(aShort);
+ }
+ }
+
+ public void writeInt32(int anInt)
+ {
+ try
+ {
+ out.putInt(anInt);
+ } catch(BufferOverflowException exception)
+ {
+ grow(4);
+ out.putInt(anInt);
+ }
+ }
+
+ public void writeInt64(long aLong)
+ {
+ try
+ {
+ out.putLong(aLong);
+ } catch(BufferOverflowException exception)
+ {
+ grow(8);
+ out.putLong(aLong);
+ }
+ }
+
+ public void writeInt8(byte aByte)
+ {
+ try
+ {
+ out.put(aByte);
+ } catch(BufferOverflowException exception)
+ {
+ grow(1);
+ out.put(aByte);
+ }
+ }
+
+ public void writeBin128(byte[] byteArray)
+ {
+ byteArray = (byteArray != null) ? byteArray : new byte [16];
+
+ assert byteArray.length == 16;
+
+ try
+ {
+ out.put(byteArray);
+ } catch(BufferOverflowException exception)
+ {
+ grow(16);
+ out.put(byteArray);
+ }
+ }
+
+ public void writeFloat(float aFloat)
+ {
+ try
+ {
+ out.putFloat(aFloat);
+ } catch(BufferOverflowException exception)
+ {
+ grow(4);
+ out.putFloat(aFloat);
+ }
+ }
+
+ public void writeMagicNumber()
+ {
+ out.put("AM2".getBytes());
+ }
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/transport/codec/Decoder.java b/java/common/src/main/java/org/apache/qpid/transport/codec/Decoder.java
index 50e787ccb2..a4df5b5fcb 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/codec/Decoder.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/codec/Decoder.java
@@ -29,40 +29,255 @@ import org.apache.qpid.transport.Struct;
/**
- * Decoder
- *
+ * Decoder interface.
+ * Each concrete implementor must specify how to decode given values.
+ *
* @author Rafael H. Schloming
*/
-
public interface Decoder
{
-
+ /**
+ * Tells whether there are any remaining byte(s) to be read.
+ *
+ * @return true if there are remaining bytes, false otherwise.
+ */
boolean hasRemaining();
+ /**
+ * The uint8 type is an 8-bit unsigned integral value.
+ *
+ * @return an 8-bit unsigned integral value.
+ */
short readUint8();
+
+ /**
+ *The uint16 type is a 16-bit unsigned integral value encoded in network byte order.
+ *
+ * @return a 16-bit unsigned integral value encoded in network byte order.
+ */
int readUint16();
+
+ /**
+ *The uint32 type is a 32-bit unsigned integral value encoded in network byte order.
+ *
+ * @return a 32-bit unsigned integral value encoded in network byte order.
+ */
long readUint32();
+
+ /**
+ * The uint64 type is a 64-bit unsigned integral value encoded in network byte order.
+ *
+ * @return a 64-bit unsigned integral value encoded in network byte order.
+ */
long readUint64();
+ /**
+ * The datetime type encodes a date and time using the 64 bit POSIX time_t format.
+ *
+ * @return a date and time using the 64 bit POSIX time_t format.
+ */
long readDatetime();
+
+ /**
+ * The uuid type encodes a universally unique id as defined by RFC-4122.
+ * The format and operations for this type can be found in section 4.1.2 of RFC-4122.
+ *
+ * return a universally unique id as defined by RFC-4122.
+ */
UUID readUuid();
+ /**
+// *The sequence-no type encodes, in network byte order, a serial number as defined in RFC-1982.
+ *
+ * @return a serial number as defined in RFC-1982.
+ */
int readSequenceNo();
+
RangeSet readSequenceSet(); // XXX
RangeSet readByteRanges(); // XXX
+ /**
+ * The str8 type encodes up to 255 octets worth of UTF-8 unicode.
+ * The number of octets of unicode is first encoded as an 8-bit unsigned integral value.
+ * This is followed by the actual UTF-8 unicode.
+ * Note that the encoded size refers to the number of octets of unicode, not necessarily the number of characters since
+ * the UTF-8 unicode may include multi-byte character sequences.
+ *
+ * @return a string.
+ */
String readStr8();
+
+ /**
+ * The str16 type encodes up to 65535 octets worth of UTF-8 unicode.
+ * The number of octets is first encoded as a 16-bit unsigned integral value in network byte order.
+ * This is followed by the actual UTF-8 unicode.
+ * Note that the encoded size refers to the number of octets of unicode, not necessarily the number of unicode
+ * characters since the UTF-8 unicode may include multi-byte character sequences.
+ *
+ * return a string.
+ */
String readStr16();
+ /**
+ * The vbin8 type encodes up to 255 octets of opaque binary data.
+ *
+ * return a byte array.
+ */
byte[] readVbin8();
+
+ /**
+ * The vbin16 type encodes up to 65535 octets of opaque binary data.
+ *
+ * @return the corresponding byte array.
+ */
byte[] readVbin16();
+
+ /**
+ * The vbin32 type encodes up to 4294967295 octets of opaque binary data.
+ *
+ * @return the corresponding byte array.
+ */
byte[] readVbin32();
+ /**
+ * The struct32 type describes any coded struct with a 32-bit (4 octet) size.
+ * The type is restricted to be only coded structs with a 32-bit size, consequently the first six octets of any encoded
+ * value for this type MUST always contain the size, class-code, and struct-code in that order.
+ * The size is encoded as a 32-bit unsigned integral value in network byte order that is equal to the size of the
+ * encoded field-data, packing-flags, class-code, and struct-code. The class-code is a single octet that may be set to any
+ * valid class code.
+ * The struct-code is a single octet that may be set to any valid struct code within the given class-code.
+ * The first six octets are then followed by the packing flags and encoded field data.
+ * The presence and quantity of packingflags, as well as the specific fields are determined by the struct definition
+ * identified with the encoded class-code and struct-code.
+ *
+ * @return the decoded struct.
+ */
Struct readStruct32();
+
+ /**
+ * A map is a set of distinct keys where each key has an associated (type,value) pair.
+ * The triple of the key, type, and value, form an entry within a map. Each entry within a given map MUST have a
+ * distinct key.
+ * A map is encoded as a size in octets, a count of the number of entries, followed by the encoded entries themselves.
+ * An encoded map may contain up to (4294967295 - 4) octets worth of encoded entries.
+ * The size is encoded as a 32-bit unsigned integral value in network byte order equal to the number of octets worth of
+ * encoded entries plus 4. (The extra 4 octets is added for the entry count.)
+ * The size is then followed by the number of entries encoded as a 32-bit unsigned integral value in network byte order.
+ * Finally the entries are encoded sequentially.
+ * An entry is encoded as the key, followed by the type, and then the value. The key is always a string encoded as a str8.
+ * The type is a single octet that may contain any valid AMQP type code.
+ * The value is encoded according to the rules defined by the type code for that entry.
+ *
+ * @return the decoded map.
+ */
Map<String,Object> readMap();
+
+ /**
+ * A list is an ordered sequence of (type, value) pairs. The (type, value) pair forms an item within the list.
+ * The list may contain items of many distinct types. A list is encoded as a size in octets, followed by a count of the
+ * number of items, followed by the items themselves encoded in their defined order.
+ * An encoded list may contain up to (4294967295 - 4) octets worth of encoded items.
+ * The size is encoded as a 32-bit unsigned integral value in network byte order equal to the number of octets worth
+ * of encoded items plus 4. (The extra4 octets is added for the item count.)
+ * The size is then followed by the number of items encoded as a 32-bit unsigned integral value in network byte order.
+ * Finally the items are encoded sequentially in their defined order.
+ * An item is encoded as the type followed by the value. The type is a single octet that may contain any valid AMQP type
+ * code.
+ * The value is encoded according to the rules defined by the type code for that item.
+ *
+ * @return the decoded list.
+ */
List<Object> readList();
+
+ /**
+ * An array is an ordered sequence of values of the same type.
+ * The array is encoded in as a size in octets, followed by a type code, then a count of the number values in the array,
+ * and finally the values encoded in their defined order.
+ * An encoded array may contain up to (4294967295 - 5) octets worth of encoded values.
+ * The size is encoded as a 32-bit unsigned integral value in network byte order equal to the number of octets worth of
+ * encoded values plus 5. (The extra 5 octets consist of 4 octets for the count of the number of values, and one octet to
+ * hold the type code for the items inthe array.)
+ * The size is then followed by a single octet that may contain any valid AMQP type code.
+ * The type code is then followed by the number of values encoded as a 32-bit unsigned integral value in network byte
+ * order.
+ * Finally the values are encoded sequentially in their defined order according to the rules defined by the type code for
+ * the array.
+ *
+ * @return the decoded array.
+ */
List<Object> readArray();
+ /**
+ *
+ * @param type the type of the struct.
+ * @return the decoded struct.
+ */
Struct readStruct(int type);
-
-}
+
+ /**
+ * The float type encodes a single precision 32-bit floating point number.
+ * The format and operations are defined by the IEEE 754 standard for 32-bit single precision floating point numbers.
+ *
+ * @return the decoded float.
+ */
+ float readFloat();
+
+ /**
+ * The double type encodes a double precision 64-bit floating point number.
+ * The format and operations are defined by the IEEE 754 standard for 64-bit double precision floating point numbers.
+ *
+ * @return the decoded double
+ */
+ double readDouble();
+
+ /**
+ * The int8 type is a signed integral value encoded using an 8-bit two's complement representation.
+ *
+ * @return the decoded integer.
+ */
+ byte readInt8();
+
+ /**
+ * The int16 type is a signed integral value encoded using a 16-bit two's complement representation in network byte order.
+ *
+ * @return the decoded integer.
+ */
+ short readInt16();
+
+ /**
+ * The int32 type is a signed integral value encoded using a 32-bit two's complement representation in network byte order.
+ *
+ * @return the decoded integer.
+ */
+ int readInt32();
+
+ /**
+ * The int64 type is a signed integral value encoded using a 64-bit two's complement representation in network byte order.
+ *
+ * @return the decoded integer (as long).
+ */
+ long readInt64();
+
+ /**
+ * The bin128 type consists of 16 consecutive octets of opaque binary data.
+ *
+ * @return the decoded byte array.
+ */
+ byte [] readBin128();
+
+ /**
+ * Reads the remaining bytes on the underlying buffer.
+ *
+ * @return the remaining bytes on the underlying buffer.
+ */
+ byte[] readReaminingBytes ();
+
+ /**
+ * Reads the given number of bytes.
+ *
+ * @param howManyBytes how many bytes need to be read?
+ * @return a byte array containing the requested data.
+ */
+ byte[] readBytes (int howManyBytes);
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/transport/codec/Encodable.java b/java/common/src/main/java/org/apache/qpid/transport/codec/Encodable.java
index 2aefafd19c..37ce8a5cb7 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/codec/Encodable.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/codec/Encodable.java
@@ -26,12 +26,19 @@ package org.apache.qpid.transport.codec;
*
* @author Rafael H. Schloming
*/
-
public interface Encodable
{
+ /**
+ * Encodes this encodable using the given encoder.
+ *
+ * @param encoder the encoder.
+ */
+ void write(Encoder encoder);
- void write(Encoder enc);
-
- void read(Decoder dec);
-
-}
+ /**
+ * Decodes this encodable using the given decoder.
+ *
+ * @param decoder the decoder.
+ */
+ void read(Decoder decoder);
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/transport/codec/Encoder.java b/java/common/src/main/java/org/apache/qpid/transport/codec/Encoder.java
index 2d8d13e80a..7d4f02af31 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/codec/Encoder.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/codec/Encoder.java
@@ -29,38 +29,254 @@ import org.apache.qpid.transport.Struct;
/**
- * Encoder
+ * Encoder interface.
+ * Each concrete implementor must specify how to encode given values.
*
* @author Rafael H. Schloming
*/
-
public interface Encoder
{
-
+ /**
+ * The uint8 type is an 8-bit unsigned integral value.
+ *
+ * @param b the unsigned integer to be encoded.
+ */
void writeUint8(short b);
+
+ /**
+ *The uint16 type is a 16-bit unsigned integral value encoded in network byte order.
+ *
+ * @param s the unsigned integer to be encoded.
+ */
void writeUint16(int s);
+
+ /**
+ *The uint32 type is a 32-bit unsigned integral value encoded in network byte order.
+ *
+ * @param i the unsigned integer to be encoded.
+ */
void writeUint32(long i);
+
+ /**
+ * The uint64 type is a 64-bit unsigned integral value encoded in network byte order.
+ *
+ * @param b the unsigned integer to be encoded.
+ */
void writeUint64(long l);
+ /**
+ * The datetime type encodes a date and time using the 64 bit POSIX time_t format.
+ *
+ * @param l the datetime (as long) to be encoded.
+ */
void writeDatetime(long l);
+
+ /**
+ * The uuid type encodes a universally unique id as defined by RFC-4122.
+ * The format and operations for this type can be found in section 4.1.2 of RFC-4122.
+ *
+ * @param uuid the uuid to be encoded.
+ */
void writeUuid(UUID uuid);
+ /**
+ *The sequence-no type encodes, in network byte order, a serial number as defined in RFC-1982.
+ *
+ * @param s the sequence number to be encoded.
+ */
void writeSequenceNo(int s);
+
void writeSequenceSet(RangeSet ranges); // XXX
void writeByteRanges(RangeSet ranges); // XXX
+ /**
+ * The str8 type encodes up to 255 octets worth of UTF-8 unicode.
+ * The number of octets of unicode is first encoded as an 8-bit unsigned integral value.
+ * This is followed by the actual UTF-8 unicode.
+ * Note that the encoded size refers to the number of octets of unicode, not necessarily the number of characters since
+ * the UTF-8 unicode may include multi-byte character sequences.
+ *
+ * @param s the string to be encoded.
+ */
void writeStr8(String s);
+
+ /**
+ * The str16 type encodes up to 65535 octets worth of UTF-8 unicode.
+ * The number of octets is first encoded as a 16-bit unsigned integral value in network byte order.
+ * This is followed by the actual UTF-8 unicode.
+ * Note that the encoded size refers to the number of octets of unicode, not necessarily the number of unicode
+ * characters since the UTF-8 unicode may include multi-byte character sequences.
+ *
+ * @param s the string to be encoded.
+ */
void writeStr16(String s);
+ /**
+ * The vbin8 type encodes up to 255 octets of opaque binary data.
+ * The number of octets is first encoded as an 8-bit unsigned integral value.
+ * This is followed by the actual data.
+ *
+ * @param bytes the byte array to be encoded.
+ */
void writeVbin8(byte[] bytes);
+
+ /**
+ * The vbin16 type encodes up to 65535 octets of opaque binary data.
+ * The number of octets is first encoded as a 16-bit unsigned integral value in network byte order.
+ * This is followed by the actual data.
+ *
+ * @param bytes the byte array to be encoded.
+ */
void writeVbin16(byte[] bytes);
+
+ /**
+ * The vbin32 type encodes up to 4294967295 octets of opaque binary data.
+ * The number of octets is first encoded as a 32-bit unsigned integral value in network byte order.
+ * This is followed by the actual data.
+ *
+ * @param bytes the byte array to be encoded.
+ */
void writeVbin32(byte[] bytes);
- void writeStruct32(Struct s);
+ /**
+ * The struct32 type describes any coded struct with a 32-bit (4 octet) size.
+ * The type is restricted to be only coded structs with a 32-bit size, consequently the first six octets of any encoded
+ * value for this type MUST always contain the size, class-code, and struct-code in that order.
+ * The size is encoded as a 32-bit unsigned integral value in network byte order that is equal to the size of the
+ * encoded field-data, packing-flags, class-code, and struct-code. The class-code is a single octet that may be set to any
+ * valid class code.
+ * The struct-code is a single octet that may be set to any valid struct code within the given class-code.
+ * The first six octets are then followed by the packing flags and encoded field data.
+ * The presence and quantity of packingflags, as well as the specific fields are determined by the struct definition
+ * identified with the encoded class-code and struct-code.
+ *
+ * @param struct the struct to be encoded.
+ */
+ void writeStruct32(Struct struct);
+
+ /**
+ * A map is a set of distinct keys where each key has an associated (type,value) pair.
+ * The triple of the key, type, and value, form an entry within a map. Each entry within a given map MUST have a
+ * distinct key.
+ * A map is encoded as a size in octets, a count of the number of entries, followed by the encoded entries themselves.
+ * An encoded map may contain up to (4294967295 - 4) octets worth of encoded entries.
+ * The size is encoded as a 32-bit unsigned integral value in network byte order equal to the number of octets worth of
+ * encoded entries plus 4. (The extra 4 octets is added for the entry count.)
+ * The size is then followed by the number of entries encoded as a 32-bit unsigned integral value in network byte order.
+ * Finally the entries are encoded sequentially.
+ * An entry is encoded as the key, followed by the type, and then the value. The key is always a string encoded as a str8.
+ * The type is a single octet that may contain any valid AMQP type code.
+ * The value is encoded according to the rules defined by the type code for that entry.
+ *
+ * @param map the map to be encoded.
+ */
void writeMap(Map<String,Object> map);
+
+ /**
+ * A list is an ordered sequence of (type, value) pairs. The (type, value) pair forms an item within the list.
+ * The list may contain items of many distinct types. A list is encoded as a size in octets, followed by a count of the
+ * number of items, followed by the items themselves encoded in their defined order.
+ * An encoded list may contain up to (4294967295 - 4) octets worth of encoded items.
+ * The size is encoded as a 32-bit unsigned integral value in network byte order equal to the number of octets worth
+ * of encoded items plus 4. (The extra4 octets is added for the item count.)
+ * The size is then followed by the number of items encoded as a 32-bit unsigned integral value in network byte order.
+ * Finally the items are encoded sequentially in their defined order.
+ * An item is encoded as the type followed by the value. The type is a single octet that may contain any valid AMQP type
+ * code.
+ * The value is encoded according to the rules defined by the type code for that item.
+ *
+ * @param list the list to be encoded.
+ */
void writeList(List<Object> list);
+
+ /**
+ * An array is an ordered sequence of values of the same type.
+ * The array is encoded in as a size in octets, followed by a type code, then a count of the number values in the array,
+ * and finally the values encoded in their defined order.
+ * An encoded array may contain up to (4294967295 - 5) octets worth of encoded values.
+ * The size is encoded as a 32-bit unsigned integral value in network byte order equal to the number of octets worth of
+ * encoded values plus 5. (The extra 5 octets consist of 4 octets for the count of the number of values, and one octet to
+ * hold the type code for the items inthe array.)
+ * The size is then followed by a single octet that may contain any valid AMQP type code.
+ * The type code is then followed by the number of values encoded as a 32-bit unsigned integral value in network byte
+ * order.
+ * Finally the values are encoded sequentially in their defined order according to the rules defined by the type code for
+ * the array.
+ *
+ * @param array the array to be encoded.
+ */
void writeArray(List<Object> array);
- void writeStruct(int type, Struct s);
-
-}
+ /**
+ * The struct32 type describes any coded struct with a 32-bit (4 octet) size.
+ * The type is restricted to be only coded structs with a 32-bit size, consequently the first six octets of any encoded
+ * value for this type MUST always contain the size, class-code, and struct-code in that order.
+ * The size is encoded as a 32-bit unsigned integral value in network byte order that is equal to the size of the
+ * encoded field-data, packing-flags, class-code, and struct-code. The class-code is a single octet that may be set to any
+ * valid class code.
+ * The struct-code is a single octet that may be set to any valid struct code within the given class-code.
+ * The first six octets are then followed by the packing flags and encoded field data.
+ * The presence and quantity of packingflags, as well as the specific fields are determined by the struct definition
+ * identified with the encoded class-code and struct-code.
+ *
+ * @param type the type of the struct.
+ * @param struct the struct to be encoded.
+ */
+ void writeStruct(int type, Struct struct);
+
+ /**
+ * The float type encodes a single precision 32-bit floating point number.
+ * The format and operations are defined by the IEEE 754 standard for 32-bit single precision floating point numbers.
+ *
+ * @param aFloat the float to be encoded.
+ */
+ void writeFloat(float aFloat);
+
+ /**
+ * The double type encodes a double precision 64-bit floating point number.
+ * The format and operations are defined by the IEEE 754 standard for 64-bit double precision floating point numbers.
+ *
+ * @param aDouble the double to be encoded.
+ */
+ void writeDouble(double aDouble);
+
+ /**
+ * The int8 type is a signed integral value encoded using an 8-bit two's complement representation.
+ *
+ * @param aByte the integer to be encoded.
+ */
+ void writeInt8(byte aByte);
+
+ /**
+ * The int16 type is a signed integral value encoded using a 16-bit two's complement representation in network byte order.
+ *
+ * @param aShort the integer to be encoded.
+ */
+ void writeInt16(short aShort);
+
+ /**
+ * The int32 type is a signed integral value encoded using a 32-bit two's complement representation in network byte order.
+ *
+ * @param anInt the integer to be encoded.
+ */
+ void writeInt32(int anInt);
+
+ /**
+ * The int64 type is a signed integral value encoded using a 64-bit two's complement representation in network byte order.
+ *
+ * @param aLong the integer to be encoded.
+ */
+ void writeInt64(long aLong);
+
+ /**
+ * The bin128 type consists of 16 consecutive octets of opaque binary data.
+ *
+ * @param bytes the bytes array to be encoded.
+ */
+ void writeBin128(byte [] bytes);
+
+ /**
+ * Encodes the AMQP magic number.
+ */
+ void writeMagicNumber();
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java b/java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java
index 4ff8fec206..357caa26e1 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java
@@ -186,10 +186,11 @@ public class Assembler implements Receiver<NetworkEvent>, NetworkDelegate
case COMMAND:
int commandType = dec.readUint16();
// read in the session header, right now we don't use it
- dec.readUint16();
+ int hdr = dec.readUint16();
command = Method.create(commandType);
+ command.setSync((0x0001 & hdr) != 0);
command.read(dec);
- if (command.hasPayloadSegment())
+ if (command.hasPayload())
{
incomplete[channel] = command;
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/ConnectionBinding.java b/java/common/src/main/java/org/apache/qpid/transport/network/ConnectionBinding.java
index 6886cb3a5a..8a2aba2e6d 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/ConnectionBinding.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/ConnectionBinding.java
@@ -33,23 +33,46 @@ import org.apache.qpid.transport.Sender;
*
*/
-public class ConnectionBinding implements Binding<Connection,ByteBuffer>
+public abstract class ConnectionBinding
+ implements Binding<Connection,ByteBuffer>
{
- private static final int MAX_FRAME_SIZE = 64 * 1024 - 1;
-
- private final ConnectionDelegate delegate;
+ public static Binding<Connection,ByteBuffer> get(final Connection connection)
+ {
+ return new ConnectionBinding()
+ {
+ public Connection connection()
+ {
+ return connection;
+ }
+ };
+ }
- public ConnectionBinding(ConnectionDelegate delegate)
+ public static Binding<Connection,ByteBuffer> get(final ConnectionDelegate delegate)
{
- this.delegate = delegate;
+ return new ConnectionBinding()
+ {
+ public Connection connection()
+ {
+ Connection conn = new Connection();
+ conn.setConnectionDelegate(delegate);
+ return conn;
+ }
+ };
}
+ public static final int MAX_FRAME_SIZE = 64 * 1024 - 1;
+
+ public abstract Connection connection();
+
public Connection endpoint(Sender<ByteBuffer> sender)
{
+ Connection conn = connection();
+
// XXX: hardcoded max-frame
- return new Connection
- (new Disassembler(sender, MAX_FRAME_SIZE), delegate);
+ Disassembler dis = new Disassembler(sender, MAX_FRAME_SIZE);
+ conn.setSender(dis);
+ return conn;
}
public Receiver<ByteBuffer> receiver(Connection conn)
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java b/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java
index 09586b357a..d99ee72d14 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java
@@ -20,7 +20,15 @@
*/
package org.apache.qpid.transport.network;
-import org.apache.qpid.transport.codec.BBEncoder;
+import static java.lang.Math.min;
+import static org.apache.qpid.transport.network.Frame.FIRST_FRAME;
+import static org.apache.qpid.transport.network.Frame.FIRST_SEG;
+import static org.apache.qpid.transport.network.Frame.HEADER_SIZE;
+import static org.apache.qpid.transport.network.Frame.LAST_FRAME;
+import static org.apache.qpid.transport.network.Frame.LAST_SEG;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import org.apache.qpid.transport.Header;
import org.apache.qpid.transport.Method;
@@ -31,13 +39,7 @@ import org.apache.qpid.transport.ProtocolHeader;
import org.apache.qpid.transport.SegmentType;
import org.apache.qpid.transport.Sender;
import org.apache.qpid.transport.Struct;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-import static org.apache.qpid.transport.network.Frame.*;
-
-import static java.lang.Math.*;
+import org.apache.qpid.transport.codec.BBEncoder;
/**
@@ -198,7 +200,7 @@ public final class Disassembler implements Sender<ProtocolEvent>,
byte flags = FIRST_SEG;
- boolean payload = method.hasPayloadSegment();
+ boolean payload = method.hasPayload();
if (!payload)
{
flags |= LAST_SEG;
@@ -208,11 +210,14 @@ public final class Disassembler implements Sender<ProtocolEvent>,
if (payload)
{
final Header hdr = method.getHeader();
- final Struct[] structs = hdr.getStructs();
-
- for (Struct st : structs)
+ if (hdr != null)
{
- enc.writeStruct32(st);
+ final Struct[] structs = hdr.getStructs();
+
+ for (Struct st : structs)
+ {
+ enc.writeStruct32(st);
+ }
}
headerSeg = enc.segment();
}
@@ -232,5 +237,9 @@ public final class Disassembler implements Sender<ProtocolEvent>,
{
throw new IllegalArgumentException("" + error);
}
-
+
+ public void setIdleTimeout(long l)
+ {
+ sender.setIdleTimeout(l);
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/InputHandler.java b/java/common/src/main/java/org/apache/qpid/transport/network/InputHandler.java
index 408c95e075..a2885f97bc 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/InputHandler.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/InputHandler.java
@@ -39,7 +39,7 @@ import static org.apache.qpid.transport.network.InputHandler.State.*;
* @author Rafael H. Schloming
*/
-public final class InputHandler implements Receiver<ByteBuffer>
+public class InputHandler implements Receiver<ByteBuffer>
{
public enum State
@@ -144,10 +144,11 @@ public final class InputHandler implements Receiver<ByteBuffer>
return ERROR;
}
+ byte protoClass = input.get(pos + 4);
byte instance = input.get(pos + 5);
byte major = input.get(pos + 6);
byte minor = input.get(pos + 7);
- receiver.received(new ProtocolHeader(instance, major, minor));
+ receiver.received(new ProtocolHeader(protoClass, instance, major, minor));
needed = Frame.HEADER_SIZE;
return FRAME_HDR;
case FRAME_HDR:
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/io/InputHandler_0_9.java b/java/common/src/main/java/org/apache/qpid/transport/network/io/InputHandler_0_9.java
index b63020913b..ecc5f6d07c 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/io/InputHandler_0_9.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/io/InputHandler_0_9.java
@@ -1,4 +1,25 @@
package org.apache.qpid.transport.network.io;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import java.nio.ByteBuffer;
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoAcceptor.java b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoAcceptor.java
index c4559ae6b4..8530240dcc 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoAcceptor.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoAcceptor.java
@@ -56,6 +56,17 @@ public class IoAcceptor<E> extends Thread
setName(String.format("IoAcceptor - %s", socket.getInetAddress()));
}
+ /**
+ Close the underlying ServerSocket if it has not already been closed.
+ */
+ public void close() throws IOException
+ {
+ if (!socket.isClosed())
+ {
+ socket.close();
+ }
+ }
+
public IoAcceptor(String host, int port, Binding<E,ByteBuffer> binding)
throws IOException
{
@@ -69,7 +80,7 @@ public class IoAcceptor<E> extends Thread
try
{
Socket sock = socket.accept();
- IoTransport<E> transport = new IoTransport<E>(sock, binding);
+ IoTransport<E> transport = new IoTransport<E>(sock, binding,false);
}
catch (IOException e)
{
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java
index a1fb0371fd..6144edb947 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java
@@ -20,13 +20,15 @@
*/
package org.apache.qpid.transport.network.io;
+import org.apache.qpid.thread.Threading;
import org.apache.qpid.transport.Receiver;
import org.apache.qpid.transport.TransportException;
import org.apache.qpid.transport.util.Logger;
-import java.io.InputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.net.Socket;
+import java.net.SocketException;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -35,7 +37,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
*
*/
-final class IoReceiver extends Thread
+final class IoReceiver implements Runnable
{
private static final Logger log = Logger.get(IoReceiver.class);
@@ -46,6 +48,9 @@ final class IoReceiver extends Thread
private final Socket socket;
private final long timeout;
private final AtomicBoolean closed = new AtomicBoolean(false);
+ private final Thread receiverThread;
+ private final boolean shutdownBroken =
+ ((String) System.getProperties().get("os.name")).matches("(?i).*windows.*");
public IoReceiver(IoTransport transport, Receiver<ByteBuffer> receiver,
int bufferSize, long timeout)
@@ -55,19 +60,27 @@ final class IoReceiver extends Thread
this.bufferSize = bufferSize;
this.socket = transport.getSocket();
this.timeout = timeout;
-
- setDaemon(true);
- setName(String.format("IoReceiver - %s", socket.getRemoteSocketAddress()));
- start();
+
+ try
+ {
+ receiverThread = Threading.getThreadFactory().createThread(this);
+ }
+ catch(Exception e)
+ {
+ throw new Error("Error creating IOReceiver thread",e);
+ }
+ receiverThread.setDaemon(true);
+ receiverThread.setName(String.format("IoReceiver - %s", socket.getRemoteSocketAddress()));
+ receiverThread.start();
}
- void close()
+ void close(boolean block)
{
if (!closed.getAndSet(true))
{
try
{
- if (((String) System.getProperties().get("os.name")).matches("(?i).*windows.*"))
+ if (shutdownBroken)
{
socket.close();
}
@@ -75,10 +88,10 @@ final class IoReceiver extends Thread
{
socket.shutdownInput();
}
- if (Thread.currentThread() != this)
+ if (block && Thread.currentThread() != receiverThread)
{
- join(timeout);
- if (isAlive())
+ receiverThread.join(timeout);
+ if (receiverThread.isAlive())
{
throw new TransportException("join timed out");
}
@@ -124,12 +137,25 @@ final class IoReceiver extends Thread
}
catch (Throwable t)
{
- receiver.exception(t);
+ if (!(shutdownBroken &&
+ t instanceof SocketException &&
+ t.getMessage().equalsIgnoreCase("socket closed") &&
+ closed.get()))
+ {
+ receiver.exception(t);
+ }
}
finally
{
receiver.closed();
- transport.getSender().close();
+ try
+ {
+ socket.close();
+ }
+ catch(Exception e)
+ {
+ log.warn(e, "Error closing socket");
+ }
}
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoSender.java b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoSender.java
index ef892744ab..00652e2927 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoSender.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoSender.java
@@ -18,20 +18,22 @@
*/
package org.apache.qpid.transport.network.io;
+import static org.apache.qpid.transport.util.Functions.mod;
+
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.qpid.thread.Threading;
import org.apache.qpid.transport.Sender;
+import org.apache.qpid.transport.SenderException;
import org.apache.qpid.transport.TransportException;
import org.apache.qpid.transport.util.Logger;
-import static org.apache.qpid.transport.util.Functions.*;
-
-public final class IoSender extends Thread implements Sender<ByteBuffer>
+public final class IoSender implements Runnable, Sender<ByteBuffer>
{
private static final Logger log = Logger.get(IoSender.class);
@@ -53,7 +55,9 @@ public final class IoSender extends Thread implements Sender<ByteBuffer>
private final Object notFull = new Object();
private final Object notEmpty = new Object();
private final AtomicBoolean closed = new AtomicBoolean(false);
-
+ private final Thread senderThread;
+ private long idleTimeout;
+
private volatile Throwable exception = null;
@@ -73,9 +77,18 @@ public final class IoSender extends Thread implements Sender<ByteBuffer>
throw new TransportException("Error getting output stream for socket", e);
}
- setDaemon(true);
- setName(String.format("IoSender - %s", socket.getRemoteSocketAddress()));
- start();
+ try
+ {
+ senderThread = Threading.getThreadFactory().createThread(this);
+ }
+ catch(Exception e)
+ {
+ throw new Error("Error creating IOSender thread",e);
+ }
+
+ senderThread.setDaemon(true);
+ senderThread.setName(String.format("IoSender - %s", socket.getRemoteSocketAddress()));
+ senderThread.start();
}
private static final int pof2(int n)
@@ -88,17 +101,11 @@ public final class IoSender extends Thread implements Sender<ByteBuffer>
return result;
}
- private static final int mod(int n, int m)
- {
- int r = n % m;
- return r < 0 ? m + r : r;
- }
-
public void send(ByteBuffer buf)
{
if (closed.get())
{
- throw new TransportException("sender is closed", exception);
+ throw new SenderException("sender is closed", exception);
}
final int size = buffer.length;
@@ -131,12 +138,12 @@ public final class IoSender extends Thread implements Sender<ByteBuffer>
if (closed.get())
{
- throw new TransportException("sender is closed", exception);
+ throw new SenderException("sender is closed", exception);
}
if (head - tail >= size)
{
- throw new TransportException(String.format("write timed out: %s, %s", head, tail));
+ throw new SenderException(String.format("write timed out: %s, %s", head, tail));
}
}
continue;
@@ -181,6 +188,11 @@ public final class IoSender extends Thread implements Sender<ByteBuffer>
{
if (!closed.getAndSet(true))
{
+ synchronized (notFull)
+ {
+ notFull.notify();
+ }
+
synchronized (notEmpty)
{
notEmpty.notify();
@@ -188,37 +200,31 @@ public final class IoSender extends Thread implements Sender<ByteBuffer>
try
{
- if (Thread.currentThread() != this)
+ if (Thread.currentThread() != senderThread)
{
- join(timeout);
- if (isAlive())
+ senderThread.join(timeout);
+ if (senderThread.isAlive())
{
- throw new TransportException("join timed out");
+ throw new SenderException("join timed out");
}
}
- transport.getReceiver().close();
- socket.close();
+ transport.getReceiver().close(false);
}
catch (InterruptedException e)
{
- throw new TransportException(e);
- }
- catch (IOException e)
- {
- throw new TransportException(e);
+ throw new SenderException(e);
}
if (reportException && exception != null)
{
- throw new TransportException(exception);
+ throw new SenderException(exception);
}
}
}
public void run()
{
- final int size = buffer.length;
-
+ final int size = buffer.length;
while (true)
{
final int hd = head;
@@ -288,4 +294,16 @@ public final class IoSender extends Thread implements Sender<ByteBuffer>
}
}
+ public void setIdleTimeout(long l)
+ {
+ try
+ {
+ socket.setSoTimeout((int)l*2);
+ idleTimeout = l;
+ }
+ catch (Exception e)
+ {
+ throw new SenderException(e);
+ }
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoTransport.java b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoTransport.java
index 70fd8a3c06..3615461e9f 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoTransport.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoTransport.java
@@ -26,17 +26,20 @@ import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+
import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
+import org.apache.qpid.ssl.SSLContextFactory;
import org.apache.qpid.transport.Binding;
import org.apache.qpid.transport.Connection;
import org.apache.qpid.transport.ConnectionDelegate;
import org.apache.qpid.transport.Receiver;
import org.apache.qpid.transport.Sender;
import org.apache.qpid.transport.TransportException;
-import org.apache.qpid.transport.network.Assembler;
import org.apache.qpid.transport.network.ConnectionBinding;
-import org.apache.qpid.transport.network.Disassembler;
-import org.apache.qpid.transport.network.InputHandler;
+import org.apache.qpid.transport.network.ssl.SSLReceiver;
+import org.apache.qpid.transport.network.ssl.SSLSender;
import org.apache.qpid.transport.util.Logger;
/**
@@ -68,21 +71,53 @@ public final class IoTransport<E>
("amqj.sendBufferSize", DEFAULT_READ_WRITE_BUFFER_SIZE);
private Socket socket;
- private IoSender sender;
+ private Sender<ByteBuffer> sender;
private E endpoint;
private IoReceiver receiver;
private long timeout = 60000;
- IoTransport(Socket socket, Binding<E,ByteBuffer> binding)
+ IoTransport(Socket socket, Binding<E,ByteBuffer> binding, boolean ssl)
{
this.socket = socket;
- this.sender = new IoSender(this, 2*writeBufferSize, timeout);
- this.endpoint = binding.endpoint(sender);
- this.receiver = new IoReceiver(this, binding.receiver(endpoint),
- 2*readBufferSize, timeout);
+
+ if (ssl)
+ {
+ SSLEngine engine = null;
+ SSLContext sslCtx;
+ try
+ {
+ sslCtx = createSSLContext();
+ }
+ catch (Exception e)
+ {
+ throw new TransportException("Error creating SSL Context", e);
+ }
+
+ try
+ {
+ engine = sslCtx.createSSLEngine();
+ engine.setUseClientMode(true);
+ }
+ catch(Exception e)
+ {
+ throw new TransportException("Error creating SSL Engine", e);
+ }
+
+ this.sender = new SSLSender(engine,new IoSender(this, 2*writeBufferSize, timeout));
+ this.endpoint = binding.endpoint(sender);
+ this.receiver = new IoReceiver(this, new SSLReceiver(engine,binding.receiver(endpoint),(SSLSender)sender),
+ 2*readBufferSize, timeout);
+ }
+ else
+ {
+ this.sender = new IoSender(this, 2*writeBufferSize, timeout);
+ this.endpoint = binding.endpoint(sender);
+ this.receiver = new IoReceiver(this, binding.receiver(endpoint),
+ 2*readBufferSize, timeout);
+ }
}
- IoSender getSender()
+ Sender<ByteBuffer> getSender()
{
return sender;
}
@@ -98,22 +133,24 @@ public final class IoTransport<E>
}
public static final <E> E connect(String host, int port,
- Binding<E,ByteBuffer> binding)
+ Binding<E,ByteBuffer> binding,
+ boolean ssl)
{
Socket socket = createSocket(host, port);
- IoTransport<E> transport = new IoTransport<E>(socket, binding);
+ IoTransport<E> transport = new IoTransport<E>(socket, binding,ssl);
return transport.endpoint;
}
public static final Connection connect(String host, int port,
- ConnectionDelegate delegate)
+ ConnectionDelegate delegate,
+ boolean ssl)
{
- return connect(host, port, new ConnectionBinding(delegate));
+ return connect(host, port, ConnectionBinding.get(delegate),ssl);
}
- public static void connect_0_9(AMQVersionAwareProtocolSession session, String host, int port)
+ public static void connect_0_9(AMQVersionAwareProtocolSession session, String host, int port, boolean ssl)
{
- connect(host, port, new Binding_0_9(session));
+ connect(host, port, new Binding_0_9(session),ssl);
}
private static class Binding_0_9
@@ -170,5 +207,23 @@ public final class IoTransport<E>
throw new TransportException("Error connecting to broker", e);
}
}
+
+ private SSLContext createSSLContext() throws Exception
+ {
+ String trustStorePath = System.getProperty("javax.net.ssl.trustStore");
+ String trustStorePassword = System.getProperty("javax.net.ssl.trustStorePassword");
+ String trustStoreCertType = System.getProperty("qpid.ssl.trustStoreCertType","SunX509");
+
+ String keyStorePath = System.getProperty("javax.net.ssl.keyStore",trustStorePath);
+ String keyStorePassword = System.getProperty("javax.net.ssl.keyStorePassword",trustStorePassword);
+ String keyStoreCertType = System.getProperty("qpid.ssl.keyStoreCertType","SunX509");
+
+ SSLContextFactory sslContextFactory = new SSLContextFactory(trustStorePath,trustStorePassword,
+ trustStoreCertType,keyStorePath,
+ keyStorePassword,keyStoreCertType);
+
+ return sslContextFactory.buildServerContext();
+
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java b/java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java
new file mode 100644
index 0000000000..3838bf76be
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java
@@ -0,0 +1,421 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.transport.network.mina;
+
+import java.io.IOException;
+import java.net.BindException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+
+import org.apache.mina.common.ConnectFuture;
+import org.apache.mina.common.IdleStatus;
+import org.apache.mina.common.IoAcceptor;
+import org.apache.mina.common.IoConnector;
+import org.apache.mina.common.IoFilterChain;
+import org.apache.mina.common.IoHandlerAdapter;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.common.SimpleByteBufferAllocator;
+import org.apache.mina.common.WriteFuture;
+import org.apache.mina.filter.ReadThrottleFilterBuilder;
+import org.apache.mina.filter.SSLFilter;
+import org.apache.mina.filter.WriteBufferLimitFilterBuilder;
+import org.apache.mina.filter.executor.ExecutorFilter;
+import org.apache.mina.transport.socket.nio.MultiThreadSocketConnector;
+import org.apache.mina.transport.socket.nio.SocketAcceptorConfig;
+import org.apache.mina.transport.socket.nio.SocketConnector;
+import org.apache.mina.transport.socket.nio.SocketConnectorConfig;
+import org.apache.mina.transport.socket.nio.SocketSessionConfig;
+import org.apache.mina.util.NewThreadExecutor;
+import org.apache.mina.util.SessionUtil;
+import org.apache.qpid.protocol.ProtocolEngine;
+import org.apache.qpid.protocol.ProtocolEngineFactory;
+import org.apache.qpid.ssl.SSLContextFactory;
+import org.apache.qpid.thread.QpidThreadExecutor;
+import org.apache.qpid.transport.NetworkDriver;
+import org.apache.qpid.transport.NetworkDriverConfiguration;
+import org.apache.qpid.transport.OpenException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MINANetworkDriver extends IoHandlerAdapter implements NetworkDriver
+{
+
+ private static final int DEFAULT_BUFFER_SIZE = 32 * 1024;
+
+ ProtocolEngine _protocolEngine;
+ private boolean _useNIO = false;
+ private int _processors = 4;
+ private boolean _executorPool = false;
+ private SSLContextFactory _sslFactory = null;
+ private IoConnector _socketConnector;
+ private IoAcceptor _acceptor;
+ private IoSession _ioSession;
+ private ProtocolEngineFactory _factory;
+ private boolean _protectIO;
+ private NetworkDriverConfiguration _config;
+ private Throwable _lastException;
+ private boolean _acceptingConnections = false;
+
+ private WriteFuture _lastWriteFuture;
+
+ private static final Logger _logger = LoggerFactory.getLogger(MINANetworkDriver.class);
+
+ public MINANetworkDriver(boolean useNIO, int processors, boolean executorPool, boolean protectIO)
+ {
+ _useNIO = useNIO;
+ _processors = processors;
+ _executorPool = executorPool;
+ _protectIO = protectIO;
+ }
+
+ public MINANetworkDriver(boolean useNIO, int processors, boolean executorPool, boolean protectIO,
+ ProtocolEngine protocolEngine, IoSession session)
+ {
+ _useNIO = useNIO;
+ _processors = processors;
+ _executorPool = executorPool;
+ _protectIO = protectIO;
+ _protocolEngine = protocolEngine;
+ _ioSession = session;
+ _ioSession.setAttachment(_protocolEngine);
+ }
+
+ public MINANetworkDriver()
+ {
+
+ }
+
+ public MINANetworkDriver(IoConnector ioConnector)
+ {
+ _socketConnector = ioConnector;
+ }
+
+ public MINANetworkDriver(IoConnector ioConnector, ProtocolEngine engine)
+ {
+ _socketConnector = ioConnector;
+ _protocolEngine = engine;
+ }
+
+ public void bind(int port, InetAddress[] addresses, ProtocolEngineFactory factory,
+ NetworkDriverConfiguration config, SSLContextFactory sslFactory) throws BindException
+ {
+
+ _factory = factory;
+ _config = config;
+
+ if (_useNIO)
+ {
+ _acceptor = new org.apache.mina.transport.socket.nio.MultiThreadSocketAcceptor(_processors,
+ new NewThreadExecutor());
+ }
+ else
+ {
+ _acceptor = new org.apache.mina.transport.socket.nio.SocketAcceptor(_processors, new NewThreadExecutor());
+ }
+
+ SocketAcceptorConfig sconfig = (SocketAcceptorConfig) _acceptor.getDefaultConfig();
+ SocketSessionConfig sc = (SocketSessionConfig) sconfig.getSessionConfig();
+
+ if (config != null)
+ {
+ sc.setReceiveBufferSize(config.getReceiveBufferSize());
+ sc.setSendBufferSize(config.getSendBufferSize());
+ sc.setTcpNoDelay(config.getTcpNoDelay());
+ }
+
+ if (sslFactory != null)
+ {
+ _sslFactory = sslFactory;
+ }
+
+ if (addresses != null && addresses.length > 0)
+ {
+ for (InetAddress addr : addresses)
+ {
+ try
+ {
+ _acceptor.bind(new InetSocketAddress(addr, port), this, sconfig);
+ }
+ catch (IOException e)
+ {
+ throw new BindException(String.format("Could not bind to %1s:%2s", addr, port));
+ }
+ }
+ }
+ else
+ {
+ try
+ {
+ _acceptor.bind(new InetSocketAddress(port), this, sconfig);
+ }
+ catch (IOException e)
+ {
+ throw new BindException(String.format("Could not bind to *:%1s", port));
+ }
+ }
+ _acceptingConnections = true;
+ }
+
+ public SocketAddress getRemoteAddress()
+ {
+ return _ioSession.getRemoteAddress();
+ }
+
+ public SocketAddress getLocalAddress()
+ {
+ return _ioSession.getLocalAddress();
+ }
+
+
+ public void open(int port, InetAddress destination, ProtocolEngine engine, NetworkDriverConfiguration config,
+ SSLContextFactory sslFactory) throws OpenException
+ {
+ if (sslFactory != null)
+ {
+ _sslFactory = sslFactory;
+ }
+
+ if (_useNIO)
+ {
+ _socketConnector = new MultiThreadSocketConnector(1, new QpidThreadExecutor());
+ }
+ else
+ {
+ _socketConnector = new SocketConnector(1, new QpidThreadExecutor()); // non-blocking
+ // connector
+ }
+
+ org.apache.mina.common.ByteBuffer.setUseDirectBuffers(Boolean.getBoolean("amqj.enableDirectBuffers"));
+ // the MINA default is currently to use the pooled allocator although this may change in future
+ // once more testing of the performance of the simple allocator has been done
+ if (!Boolean.getBoolean("amqj.enablePooledAllocator"))
+ {
+ org.apache.mina.common.ByteBuffer.setAllocator(new SimpleByteBufferAllocator());
+ }
+
+ SocketConnectorConfig cfg = (SocketConnectorConfig) _socketConnector.getDefaultConfig();
+
+ SocketSessionConfig scfg = (SocketSessionConfig) cfg.getSessionConfig();
+ scfg.setTcpNoDelay((config != null) ? config.getTcpNoDelay() : true);
+ scfg.setSendBufferSize((config != null) ? config.getSendBufferSize() : DEFAULT_BUFFER_SIZE);
+ scfg.setReceiveBufferSize((config != null) ? config.getReceiveBufferSize() : DEFAULT_BUFFER_SIZE);
+
+ // Don't have the connector's worker thread wait around for other
+ // connections (we only use
+ // one SocketConnector per connection at the moment anyway). This allows
+ // short-running
+ // clients (like unit tests) to complete quickly.
+ if (_socketConnector instanceof SocketConnector)
+ {
+ ((SocketConnector) _socketConnector).setWorkerTimeout(0);
+ }
+
+ ConnectFuture future = _socketConnector.connect(new InetSocketAddress(destination, port), this, cfg);
+ future.join();
+ if (!future.isConnected())
+ {
+ throw new OpenException("Could not open connection", _lastException);
+ }
+ _ioSession = future.getSession();
+ _ioSession.setAttachment(engine);
+ engine.setNetworkDriver(this);
+ _protocolEngine = engine;
+ }
+
+ public void setMaxReadIdle(int idleTime)
+ {
+ _ioSession.setIdleTime(IdleStatus.READER_IDLE, idleTime);
+ }
+
+ public void setMaxWriteIdle(int idleTime)
+ {
+ _ioSession.setIdleTime(IdleStatus.WRITER_IDLE, idleTime);
+ }
+
+ public void close()
+ {
+ if (_lastWriteFuture != null)
+ {
+ _lastWriteFuture.join();
+ }
+ if (_acceptor != null)
+ {
+ _acceptor.unbindAll();
+ }
+ if (_ioSession != null)
+ {
+ _ioSession.close();
+ }
+ }
+
+ public void flush()
+ {
+ if (_lastWriteFuture != null)
+ {
+ _lastWriteFuture.join();
+ }
+ }
+
+ public void send(ByteBuffer msg)
+ {
+ org.apache.mina.common.ByteBuffer minaBuf = org.apache.mina.common.ByteBuffer.allocate(msg.capacity());
+ minaBuf.put(msg);
+ minaBuf.flip();
+ _lastWriteFuture = _ioSession.write(minaBuf);
+ }
+
+ public void setIdleTimeout(long l)
+ {
+ // MINA doesn't support setting SO_TIMEOUT
+ }
+
+ public void exceptionCaught(IoSession protocolSession, Throwable throwable) throws Exception
+ {
+ if (_protocolEngine != null)
+ {
+ _protocolEngine.exception(throwable);
+ }
+ else
+ {
+ _logger.error("Exception thrown and no ProtocolEngine to handle it", throwable);
+ }
+ _lastException = throwable;
+ }
+
+ /**
+ * Invoked when a message is received on a particular protocol session. Note
+ * that a protocol session is directly tied to a particular physical
+ * connection.
+ *
+ * @param protocolSession
+ * the protocol session that received the message
+ * @param message
+ * the message itself (i.e. a decoded frame)
+ *
+ * @throws Exception
+ * if the message cannot be processed
+ */
+ public void messageReceived(IoSession protocolSession, Object message) throws Exception
+ {
+ if (message instanceof org.apache.mina.common.ByteBuffer)
+ {
+ ((ProtocolEngine) protocolSession.getAttachment()).received(((org.apache.mina.common.ByteBuffer) message).buf());
+ }
+ else
+ {
+ throw new IllegalStateException("Handed unhandled message. message.class = " + message.getClass() + " message = " + message);
+ }
+ }
+
+ public void sessionClosed(IoSession protocolSession) throws Exception
+ {
+ ((ProtocolEngine) protocolSession.getAttachment()).closed();
+ }
+
+ public void sessionCreated(IoSession protocolSession) throws Exception
+ {
+ // Configure the session with SSL if necessary
+ SessionUtil.initialize(protocolSession);
+ if (_executorPool)
+ {
+ if (_sslFactory != null)
+ {
+ protocolSession.getFilterChain().addAfter("AsynchronousReadFilter", "sslFilter",
+ new SSLFilter(_sslFactory.buildServerContext()));
+ }
+ }
+ else
+ {
+ if (_sslFactory != null)
+ {
+ protocolSession.getFilterChain().addBefore("protocolFilter", "sslFilter",
+ new SSLFilter(_sslFactory.buildServerContext()));
+ }
+ }
+ // Do we want to have read/write buffer limits?
+ if (_protectIO)
+ {
+ //Add IO Protection Filters
+ IoFilterChain chain = protocolSession.getFilterChain();
+
+ protocolSession.getFilterChain().addLast("tempExecutorFilterForFilterBuilder", new ExecutorFilter());
+
+ ReadThrottleFilterBuilder readfilter = new ReadThrottleFilterBuilder();
+ readfilter.setMaximumConnectionBufferSize(_config.getReceiveBufferSize());
+ readfilter.attach(chain);
+
+ WriteBufferLimitFilterBuilder writefilter = new WriteBufferLimitFilterBuilder();
+ writefilter.setMaximumConnectionBufferSize(_config.getSendBufferSize());
+ writefilter.attach(chain);
+
+ protocolSession.getFilterChain().remove("tempExecutorFilterForFilterBuilder");
+ }
+
+ if (_ioSession == null)
+ {
+ _ioSession = protocolSession;
+ }
+
+ if (_acceptingConnections)
+ {
+ // Set up the protocol engine
+ ProtocolEngine protocolEngine = _factory.newProtocolEngine(this);
+ MINANetworkDriver newDriver = new MINANetworkDriver(_useNIO, _processors, _executorPool, _protectIO, protocolEngine, protocolSession);
+ protocolEngine.setNetworkDriver(newDriver);
+ }
+ }
+
+ public void sessionIdle(IoSession session, IdleStatus status) throws Exception
+ {
+ if (IdleStatus.WRITER_IDLE.equals(status))
+ {
+ ((ProtocolEngine) session.getAttachment()).writerIdle();
+ }
+ else if (IdleStatus.READER_IDLE.equals(status))
+ {
+ ((ProtocolEngine) session.getAttachment()).readerIdle();
+ }
+ }
+
+ private ProtocolEngine getProtocolEngine()
+ {
+ return _protocolEngine;
+ }
+
+ public void setProtocolEngineFactory(ProtocolEngineFactory engineFactory, boolean acceptingConnections)
+ {
+ _factory = engineFactory;
+ _acceptingConnections = acceptingConnections;
+ }
+
+ public void setProtocolEngine(ProtocolEngine protocolEngine)
+ {
+ _protocolEngine = protocolEngine;
+ if (_ioSession != null)
+ {
+ _ioSession.setAttachment(protocolEngine);
+ }
+ }
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaHandler.java b/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaHandler.java
index f8dbec3c3d..b89eed48b0 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaHandler.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaHandler.java
@@ -262,13 +262,13 @@ public class MinaHandler<E> implements IoHandler
ConnectionDelegate delegate)
throws IOException
{
- accept(host, port, new ConnectionBinding(delegate));
+ accept(host, port, ConnectionBinding.get(delegate));
}
public static final Connection connect(String host, int port,
ConnectionDelegate delegate)
{
- return connect(host, port, new ConnectionBinding(delegate));
+ return connect(host, port, ConnectionBinding.get(delegate));
}
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaSender.java b/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaSender.java
index 69d4061e0c..fbedf14312 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaSender.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaSender.java
@@ -24,7 +24,6 @@ import org.apache.mina.common.ByteBuffer;
import org.apache.mina.common.CloseFuture;
import org.apache.mina.common.IoSession;
import org.apache.mina.common.WriteFuture;
-
import org.apache.qpid.transport.Sender;
import org.apache.qpid.transport.TransportException;
@@ -77,5 +76,15 @@ public class MinaSender implements Sender<java.nio.ByteBuffer>
CloseFuture closed = session.close();
closed.join();
}
-
+
+ public void setIdleTimeout(long l)
+ {
+ //noop
+ }
+
+ public long getIdleTimeout()
+ {
+ return 0;
+ }
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/nio/NioHandler.java b/java/common/src/main/java/org/apache/qpid/transport/network/nio/NioHandler.java
index 51e41b26f7..3bc6730623 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/nio/NioHandler.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/nio/NioHandler.java
@@ -1,4 +1,25 @@
package org.apache.qpid.transport.network.nio;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import java.io.EOFException;
import java.io.IOException;
@@ -66,8 +87,9 @@ public class NioHandler implements Runnable
}
NioSender sender = new NioSender(_ch);
- Connection con = new Connection
- (new Disassembler(sender, 64*1024 - 1), delegate);
+ Connection con = new Connection();
+ con.setSender(new Disassembler(sender, 64*1024 - 1));
+ con.setConnectionDelegate(delegate);
con.setConnectionId(_count.incrementAndGet());
_handlers.put(con.getConnectionId(),sender);
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/nio/NioSender.java b/java/common/src/main/java/org/apache/qpid/transport/network/nio/NioSender.java
index 33e888cc56..5196505c2d 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/nio/NioSender.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/nio/NioSender.java
@@ -1,4 +1,25 @@
package org.apache.qpid.transport.network.nio;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
@@ -97,4 +118,9 @@ public class NioSender implements Sender<java.nio.ByteBuffer>
}
}
}
+
+ public void setIdleTimeout(long l)
+ {
+ //noop
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLReceiver.java b/java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLReceiver.java
new file mode 100644
index 0000000000..e6e6c5f791
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLReceiver.java
@@ -0,0 +1,184 @@
+/*
+*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.transport.network.ssl;
+
+import java.nio.ByteBuffer;
+
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLEngineResult.Status;
+
+import org.apache.qpid.transport.Receiver;
+import org.apache.qpid.transport.TransportException;
+import org.apache.qpid.transport.util.Logger;
+
+public class SSLReceiver implements Receiver<ByteBuffer>
+{
+ private Receiver<ByteBuffer> delegate;
+ private SSLEngine engine;
+ private SSLSender sender;
+ private int sslBufSize;
+ private ByteBuffer appData;
+ private ByteBuffer localBuffer;
+ private boolean dataCached = false;
+ private final Object notificationToken;
+
+ private static final Logger log = Logger.get(SSLReceiver.class);
+
+ public SSLReceiver(SSLEngine engine, Receiver<ByteBuffer> delegate,SSLSender sender)
+ {
+ this.engine = engine;
+ this.delegate = delegate;
+ this.sender = sender;
+ this.sslBufSize = engine.getSession().getApplicationBufferSize();
+ appData = ByteBuffer.allocate(sslBufSize);
+ localBuffer = ByteBuffer.allocate(sslBufSize);
+ notificationToken = sender.getNotificationToken();
+ }
+
+ public void closed()
+ {
+ delegate.closed();
+ }
+
+ public void exception(Throwable t)
+ {
+ delegate.exception(t);
+ }
+
+ private ByteBuffer addPreviouslyUnreadData(ByteBuffer buf)
+ {
+ if (dataCached)
+ {
+ ByteBuffer b = ByteBuffer.allocate(localBuffer.remaining() + buf.remaining());
+ b.put(localBuffer);
+ b.put(buf);
+ b.flip();
+ dataCached = false;
+ return b;
+ }
+ else
+ {
+ return buf;
+ }
+ }
+
+ public void received(ByteBuffer buf)
+ {
+ ByteBuffer netData = addPreviouslyUnreadData(buf);
+
+ HandshakeStatus handshakeStatus;
+ Status status;
+
+ while (netData.hasRemaining())
+ {
+ try
+ {
+ SSLEngineResult result = engine.unwrap(netData, appData);
+ synchronized (notificationToken)
+ {
+ notificationToken.notifyAll();
+ }
+
+ int read = result.bytesProduced();
+ status = result.getStatus();
+ handshakeStatus = result.getHandshakeStatus();
+
+ if (read > 0)
+ {
+ int limit = appData.limit();
+ appData.limit(appData.position());
+ appData.position(appData.position() - read);
+
+ ByteBuffer data = appData.slice();
+
+ appData.limit(limit);
+ appData.position(appData.position() + read);
+
+ delegate.received(data);
+ }
+
+
+ switch(status)
+ {
+ case CLOSED:
+ synchronized(notificationToken)
+ {
+ notificationToken.notifyAll();
+ }
+ return;
+
+ case BUFFER_OVERFLOW:
+ appData = ByteBuffer.allocate(sslBufSize);
+ continue;
+
+ case BUFFER_UNDERFLOW:
+ localBuffer.clear();
+ localBuffer.put(netData);
+ localBuffer.flip();
+ dataCached = true;
+ break;
+
+ case OK:
+ break; // do nothing
+
+ default:
+ throw new IllegalStateException("SSLReceiver: Invalid State " + status);
+ }
+
+ switch (handshakeStatus)
+ {
+ case NEED_UNWRAP:
+ if (netData.hasRemaining())
+ {
+ continue;
+ }
+ break;
+
+ case NEED_TASK:
+ sender.doTasks();
+ handshakeStatus = engine.getHandshakeStatus();
+
+ case NEED_WRAP:
+ case FINISHED:
+ case NOT_HANDSHAKING:
+ synchronized(notificationToken)
+ {
+ notificationToken.notifyAll();
+ }
+ break;
+
+ default:
+ throw new IllegalStateException("SSLReceiver: Invalid State " + status);
+ }
+
+
+ }
+ catch(SSLException e)
+ {
+ throw new TransportException("Error in SSLReceiver",e);
+ }
+
+ }
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLSender.java b/java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLSender.java
new file mode 100644
index 0000000000..0e785bb2ee
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLSender.java
@@ -0,0 +1,255 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.transport.network.ssl;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLEngineResult.Status;
+
+import org.apache.qpid.transport.Sender;
+import org.apache.qpid.transport.SenderException;
+import org.apache.qpid.transport.util.Logger;
+
+public class SSLSender implements Sender<ByteBuffer>
+{
+ private Sender<ByteBuffer> delegate;
+ private SSLEngine engine;
+ private int sslBufSize;
+ private ByteBuffer netData;
+ private long timeout = 30000;
+
+ private final Object engineState = new Object();
+ private final AtomicBoolean closed = new AtomicBoolean(false);
+
+ private static final Logger log = Logger.get(SSLSender.class);
+
+ public SSLSender(SSLEngine engine, Sender<ByteBuffer> delegate)
+ {
+ this.engine = engine;
+ this.delegate = delegate;
+ sslBufSize = engine.getSession().getPacketBufferSize();
+ netData = ByteBuffer.allocate(sslBufSize);
+ timeout = Long.getLong("qpid.ssl_timeout", 60000);
+ }
+
+ public void close()
+ {
+ if (!closed.getAndSet(true))
+ {
+ if (engine.isOutboundDone())
+ {
+ return;
+ }
+ log.debug("Closing SSL connection");
+ engine.closeOutbound();
+ try
+ {
+ tearDownSSLConnection();
+ }
+ catch(Exception e)
+ {
+ throw new SenderException("Error closing SSL connection",e);
+ }
+
+ while (!engine.isOutboundDone())
+ {
+ synchronized(engineState)
+ {
+ try
+ {
+ engineState.wait();
+ }
+ catch(InterruptedException e)
+ {
+ // pass
+ }
+ }
+ }
+ delegate.close();
+ }
+ }
+
+ private void tearDownSSLConnection() throws Exception
+ {
+ SSLEngineResult result = engine.wrap(ByteBuffer.allocate(0), netData);
+ Status status = result.getStatus();
+ int read = result.bytesProduced();
+ while (status != Status.CLOSED)
+ {
+ if (status == Status.BUFFER_OVERFLOW)
+ {
+ netData.clear();
+ }
+ if(read > 0)
+ {
+ int limit = netData.limit();
+ netData.limit(netData.position());
+ netData.position(netData.position() - read);
+
+ ByteBuffer data = netData.slice();
+
+ netData.limit(limit);
+ netData.position(netData.position() + read);
+
+ delegate.send(data);
+ flush();
+ }
+ result = engine.wrap(ByteBuffer.allocate(0), netData);
+ status = result.getStatus();
+ read = result.bytesProduced();
+ }
+ }
+
+ public void flush()
+ {
+ delegate.flush();
+ }
+
+ public void send(ByteBuffer appData)
+ {
+ if (closed.get())
+ {
+ throw new SenderException("SSL Sender is closed");
+ }
+
+ HandshakeStatus handshakeStatus;
+ Status status;
+
+ while(appData.hasRemaining())
+ {
+
+ int read = 0;
+ try
+ {
+ SSLEngineResult result = engine.wrap(appData, netData);
+ read = result.bytesProduced();
+ status = result.getStatus();
+ handshakeStatus = result.getHandshakeStatus();
+
+ }
+ catch(SSLException e)
+ {
+ throw new SenderException("SSL, Error occurred while encrypting data",e);
+ }
+
+ if(read > 0)
+ {
+ int limit = netData.limit();
+ netData.limit(netData.position());
+ netData.position(netData.position() - read);
+
+ ByteBuffer data = netData.slice();
+
+ netData.limit(limit);
+ netData.position(netData.position() + read);
+
+ delegate.send(data);
+ }
+
+ switch(status)
+ {
+ case CLOSED:
+ throw new SenderException("SSLEngine is closed");
+
+ case BUFFER_OVERFLOW:
+ netData.clear();
+ continue;
+
+ case OK:
+ break; // do nothing
+
+ default:
+ throw new IllegalStateException("SSLReceiver: Invalid State " + status);
+ }
+
+ switch (handshakeStatus)
+ {
+ case NEED_WRAP:
+ if (netData.hasRemaining())
+ {
+ continue;
+ }
+
+ case NEED_TASK:
+ doTasks();
+ break;
+
+ case NEED_UNWRAP:
+ flush();
+ synchronized(engineState)
+ {
+ switch (engine.getHandshakeStatus())
+ {
+ case NEED_UNWRAP:
+ long start = System.currentTimeMillis();
+ try
+ {
+ engineState.wait(timeout);
+ }
+ catch(InterruptedException e)
+ {
+ // pass
+ }
+
+ if (System.currentTimeMillis()- start >= timeout)
+ {
+ throw new SenderException(
+ "SSL Engine timed out waiting for a response." +
+ "To get more info,run with -Djavax.net.debug=ssl");
+ }
+ break;
+ }
+ }
+ break;
+
+ case FINISHED:
+ case NOT_HANDSHAKING:
+ break; //do nothing
+
+ default:
+ throw new IllegalStateException("SSLReceiver: Invalid State " + status);
+ }
+
+ }
+ }
+
+ public void doTasks()
+ {
+ Runnable runnable;
+ while ((runnable = engine.getDelegatedTask()) != null) {
+ runnable.run();
+ }
+ }
+
+ public Object getNotificationToken()
+ {
+ return engineState;
+ }
+
+ public void setIdleTimeout(long l)
+ {
+ delegate.setIdleTimeout(l);
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/util/Functions.java b/java/common/src/main/java/org/apache/qpid/transport/util/Functions.java
index 2c6984e302..9f1c0ca9eb 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/util/Functions.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/util/Functions.java
@@ -34,6 +34,12 @@ import static java.lang.Math.*;
public class Functions
{
+ public static final int mod(int n, int m)
+ {
+ int r = n % m;
+ return r < 0 ? m + r : r;
+ }
+
public static final byte lsb(int i)
{
return (byte) (0xFF & i);
@@ -51,12 +57,17 @@ public class Functions
public static final String str(ByteBuffer buf, int limit)
{
+ return str(buf, limit,buf.position());
+ }
+
+ public static final String str(ByteBuffer buf, int limit,int start)
+ {
StringBuilder str = new StringBuilder();
str.append('"');
for (int i = 0; i < min(buf.remaining(), limit); i++)
{
- byte c = buf.get(buf.position() + i);
+ byte c = buf.get(start + i);
if (c > 31 && c < 127 && c != '\\')
{
diff --git a/java/common/src/main/java/org/apache/qpid/transport/util/Waiter.java b/java/common/src/main/java/org/apache/qpid/transport/util/Waiter.java
new file mode 100644
index 0000000000..e034d779ca
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/util/Waiter.java
@@ -0,0 +1,63 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.transport.util;
+
+
+/**
+ * Waiter
+ *
+ */
+
+public final class Waiter
+{
+
+ private final Object lock;
+ private final long timeout;
+ private final long start;
+ private long elapsed;
+
+ public Waiter(Object lock, long timeout)
+ {
+ this.lock = lock;
+ this.timeout = timeout;
+ this.start = System.currentTimeMillis();
+ this.elapsed = 0;
+ }
+
+ public boolean hasTime()
+ {
+ return elapsed < timeout;
+ }
+
+ public void await()
+ {
+ try
+ {
+ lock.wait(timeout - elapsed);
+ }
+ catch (InterruptedException e)
+ {
+ // pass
+ }
+ elapsed = System.currentTimeMillis() - start;
+ }
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/url/BindingURLImpl.java b/java/common/src/main/java/org/apache/qpid/url/BindingURLImpl.java
deleted file mode 100644
index f12fb2cff2..0000000000
--- a/java/common/src/main/java/org/apache/qpid/url/BindingURLImpl.java
+++ /dev/null
@@ -1,261 +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.
- */
-package org.apache.qpid.url;
-
-import org.apache.qpid.exchange.ExchangeDefaults;
-import org.slf4j.LoggerFactory;
-import org.slf4j.Logger;
-
-import java.util.HashMap;
-import java.net.URI;
-import java.net.URISyntaxException;
-
-public class BindingURLImpl implements QpidBindingURL
-{
- private static final Logger _logger = LoggerFactory.getLogger(BindingURLImpl.class);
-
- String _url;
- String _exchangeClass;
- String _exchangeName;
- String _destinationName;
- String _queueName;
- private HashMap<String, String> _options;
-
- public BindingURLImpl(String url) throws URLSyntaxException
- {
- // format:
- // <exch_class>://<exch_name>/[<destination>]/[<queue>]?<option>='<value>'[,<option>='<value>']*
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Parsing URL: " + url);
- }
- _url = url;
- _options = new HashMap<String, String>();
- parseBindingURL();
- }
-
- private void parseBindingURL() throws URLSyntaxException
- {
- try
- {
- URI connection = new URI(_url);
- String exchangeClass = connection.getScheme();
- if (exchangeClass == null)
- {
- _url = ExchangeDefaults.DIRECT_EXCHANGE_CLASS + "://" + "" + "//" + _url;
- // URLHelper.parseError(-1, "Exchange Class not specified.", _url);
- parseBindingURL();
- return;
- }
- else
- {
- setExchangeClass(exchangeClass);
- }
- String exchangeName = connection.getHost();
- if (exchangeName == null)
- {
- if (getExchangeClass().equals(ExchangeDefaults.DIRECT_EXCHANGE_CLASS))
- {
- setExchangeName("");
- }
- else
- {
- throw URLHelper.parseError(-1, "Exchange Name not specified.", _url);
- }
- }
- else
- {
- setExchangeName(exchangeName);
- }
- String queueName;
- if ((connection.getPath() == null) || connection.getPath().equals(""))
- {
- throw URLHelper.parseError(_url.indexOf(_exchangeName) + _exchangeName.length(),
- "Destination or Queue requried", _url);
- }
- else
- {
- int slash = connection.getPath().indexOf("/", 1);
- if (slash == -1)
- {
- throw URLHelper.parseError(_url.indexOf(_exchangeName) + _exchangeName.length(),
- "Destination requried", _url);
- }
- else
- {
- String path = connection.getPath();
- setDestinationName(path.substring(1, slash));
-
- // We don't set queueName yet as the actual value we use depends on options set
- // when we are dealing with durable subscriptions
-
- queueName = path.substring(slash + 1);
-
- }
- }
-
- URLHelper.parseOptions(_options, connection.getQuery());
- processOptions();
- // We can now call setQueueName as the URL is full parsed.
- setQueueName(queueName);
- // Fragment is #string (not used)
- if (_logger.isDebugEnabled())
- {
- _logger.debug("URL Parsed: " + this);
- }
- }
- catch (URISyntaxException uris)
- {
- throw URLHelper.parseError(uris.getIndex(), uris.getReason(), uris.getInput());
- }
- }
-
-
- private void processOptions()
- {
- // this is where we would parse any options that needed more than just storage.
- }
-
- public String getURL()
- {
- return _url;
- }
-
- public String getExchangeClass()
- {
- return _exchangeClass;
- }
-
- private void setExchangeClass(String exchangeClass)
- {
-
- _exchangeClass = exchangeClass;
- if (exchangeClass.equals(ExchangeDefaults.TOPIC_EXCHANGE_CLASS))
- {
- setOption(BindingURL.OPTION_EXCLUSIVE, "true");
- }
-
- }
-
- public String getExchangeName()
- {
- return _exchangeName;
- }
-
- private void setExchangeName(String name)
- {
- _exchangeName = name;
- }
-
- public String getDestinationName()
- {
- return _destinationName;
- }
-
- private void setDestinationName(String name)
- {
- _destinationName = name;
- }
-
- public String getQueueName()
- {
- return _queueName;
- }
-
- public void setQueueName(String name) throws URLSyntaxException
- {
- if (_exchangeClass.equals(ExchangeDefaults.TOPIC_EXCHANGE_CLASS))
- {
- if (Boolean.parseBoolean(getOption(OPTION_DURABLE)))
- {
- if (containsOption(BindingURL.OPTION_CLIENTID) && containsOption(BindingURL.OPTION_SUBSCRIPTION))
- {
- _queueName = getOption(BindingURL.OPTION_CLIENTID + ":" + BindingURL.OPTION_SUBSCRIPTION);
- }
- else
- {
- throw URLHelper.parseError(-1,
- "Durable subscription must have values for " + BindingURL.OPTION_CLIENTID + " and " + BindingURL.OPTION_SUBSCRIPTION + ".",
- _url);
-
- }
- }
- else
- {
- _queueName = null;
- }
- }
- else
- {
- _queueName = name;
- }
-
- }
-
- public String getOption(String key)
- {
- return _options.get(key);
- }
-
- public void setOption(String key, String value)
- {
- _options.put(key, value);
- }
-
- public boolean containsOption(String key)
- {
- return _options.containsKey(key);
- }
-
- public String getRoutingKey()
- {
- if (_exchangeClass.equals(ExchangeDefaults.DIRECT_EXCHANGE_CLASS))
- {
- return getQueueName();
- }
-
- if (containsOption(BindingURL.OPTION_ROUTING_KEY))
- {
- return getOption(OPTION_ROUTING_KEY);
- }
-
- return getDestinationName();
- }
-
- public void setRoutingKey(String key)
- {
- setOption(OPTION_ROUTING_KEY, key);
- }
-
- public String toString()
- {
- StringBuffer sb = new StringBuffer();
-
- sb.append(_exchangeClass);
- sb.append("://");
- sb.append(_exchangeName);
- sb.append('/');
- sb.append(_destinationName);
- sb.append('/');
- sb.append(_queueName);
-
- sb.append(URLHelper.printOptions(_options));
-
- return sb.toString();
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/url/BindingURLParser.java b/java/common/src/main/java/org/apache/qpid/url/BindingURLParser.java
index 5d26e7e65b..7fe7d2e1da 100644
--- a/java/common/src/main/java/org/apache/qpid/url/BindingURLParser.java
+++ b/java/common/src/main/java/org/apache/qpid/url/BindingURLParser.java
@@ -1,4 +1,25 @@
package org.apache.qpid.url;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import java.net.URISyntaxException;
import java.util.ArrayList;
@@ -23,7 +44,7 @@ public class BindingURLParser
private static final char COLON_CHAR = ':';
private static final char END_OF_URL_MARKER_CHAR = '%';
- private static final Logger _logger = LoggerFactory.getLogger(BindingURLImpl.class);
+ private static final Logger _logger = LoggerFactory.getLogger(BindingURLParser.class);
private char[] _url;
private AMQBindingURL _bindingURL;
@@ -396,7 +417,7 @@ public class BindingURLParser
{
if (_bindingURL.containsOption(BindingURL.OPTION_CLIENTID) && _bindingURL.containsOption(BindingURL.OPTION_SUBSCRIPTION))
{
- queueName = _bindingURL.getOption(BindingURL.OPTION_CLIENTID + ":" + BindingURL.OPTION_SUBSCRIPTION);
+ queueName = _bindingURL.getOption(BindingURL.OPTION_CLIENTID) + ":" + _bindingURL.getOption(BindingURL.OPTION_SUBSCRIPTION);
}
else
{
diff --git a/java/common/src/main/java/org/apache/qpid/url/QpidBindingURL.java b/java/common/src/main/java/org/apache/qpid/url/QpidBindingURL.java
deleted file mode 100644
index 00edbf1bc3..0000000000
--- a/java/common/src/main/java/org/apache/qpid/url/QpidBindingURL.java
+++ /dev/null
@@ -1,53 +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.
- */
-package org.apache.qpid.url;
-
-import org.apache.qpid.framing.AMQShortString;
-
-/*
- Binding URL format:
- <exch_class>://<exch_name>/[<destination>]/[<queue>]?<option>='<value>'[,<option>='<value>']*
-*/
-public interface QpidBindingURL
-{
- public static final String OPTION_EXCLUSIVE = "exclusive";
- public static final String OPTION_AUTODELETE = "autodelete";
- public static final String OPTION_DURABLE = "durable";
- public static final String OPTION_CLIENTID = "clientid";
- public static final String OPTION_SUBSCRIPTION = "subscription";
- public static final String OPTION_ROUTING_KEY = "routingkey";
-
-
- String getURL();
-
- String getExchangeClass();
-
- String getExchangeName();
-
- String getDestinationName();
-
- String getQueueName();
-
- String getOption(String key);
-
- boolean containsOption(String key);
-
- String getRoutingKey();
-
- String toString();
-}
diff --git a/java/common/src/main/java/org/apache/qpid/url/QpidURL.java b/java/common/src/main/java/org/apache/qpid/url/QpidURL.java
deleted file mode 100644
index 5ab4425323..0000000000
--- a/java/common/src/main/java/org/apache/qpid/url/QpidURL.java
+++ /dev/null
@@ -1,57 +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.
- */
-package org.apache.qpid.url;
-
-import org.apache.qpid.BrokerDetails;
-
-import java.util.List;
-
-/**
- * The format of the Qpid URL is based on the AMQP one.
- * The grammar is as follows:
- * <p> qpid_url = "qpid:" [user_props] prot_addr_list ["/" future-parameters]
- * <p> prot_addr_list = [prot_addr ","]* prot_addr
- * <p> prot_addr = tcp_prot_addr | tls_prot_addr | future_prot_addr
- * <p> tcp_prot_addr = tcp_id tcp_addr
- * <p> tcp_id = "tcp:" | ""
- * <p> tcp_addr = [host [":" port] ]
- * <p> host = <as per [2]>
- * <p> port = number
- * <p> tls_prot_addr = tls_id tls_addr
- * <p> tls_id = "tls:" | ""
- * <p> tls_addr = [host [":" port] ]
- * <p> future_prot_addr = future_prot_id future_prot_addr
- * <p> future_prot_id = <placeholder, must end in ":". Example "sctp:">
- * <p> future_prot_addr = <placeholder, protocl-specific address>
- * <p> future_parameters = <placeholder, not used in failover addresses>
- */
-public interface QpidURL
-{
- /**
- * Get all the broker details
- *
- * @return A list of BrokerDetails.
- */
- public List<BrokerDetails> getAllBrokerDetails();
-
- /**
- * Get this URL string form
- * @return This URL string form.
- */
- public String getURL();
-}
diff --git a/java/common/src/main/java/org/apache/qpid/url/QpidURLImpl.java b/java/common/src/main/java/org/apache/qpid/url/QpidURLImpl.java
deleted file mode 100644
index f92934db7f..0000000000
--- a/java/common/src/main/java/org/apache/qpid/url/QpidURLImpl.java
+++ /dev/null
@@ -1,460 +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.
- */
-package org.apache.qpid.url;
-
-import org.apache.qpid.BrokerDetails;
-import org.apache.qpid.BrokerDetailsImpl;
-
-import java.net.MalformedURLException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * The format Qpid URL is based on the AMQP one.
- * The grammar is as follows:
- * <p> qpid_url = "qpid:" [client_props "@"] port_addr_list ["/" future-parameters]
- * <p> port_addr_list = [port_addr ","]* port_addr
- * <p> port_addr = tcp_port_addr | tls_prot_addr | future_prot_addr
- * <p> tcp_port_addr = tcp_id tcp_addr
- * <p> tcp_id = "tcp:" | ""
- * <p> tcp_addr = host [":" port]
- * <p> host = <as per http://www.apps.ietf.org/>
- * <p> port = number
- * <p> tls_prot_addr = tls_id tls_addr
- * <p> tls_id = "tls:" | ""
- * <p> tls_addr = host [":" port]
- * <p> future_prot_addr = future_prot_id future_prot_addr
- * <p> future_prot_id = <placeholder, must end in ":". Example "sctp:">
- * <p> future_prot_addr = <placeholder, protocl-specific address>
- * <p> future_parameters = <placeholder, not used in failover addresses>
- * <p> client_props = [client_prop ";"]* client_prop
- * <p> client_prop = prop "=" val
- * <p> prop = chars as per <as per http://www.apps.ietf.org/>
- * <p> val = valid as per <as per http://www.apps.ietf.org/>
- * <p/>
- * Ex: qpid:virtualhost=tcp:host-foo,test,client_id=foo@tcp:myhost.com:5672,virtualhost=prod;
- * keystore=/opt/keystore@client_id2@tls:mysecurehost.com:5672
- */
-public class QpidURLImpl implements QpidURL
-{
- private static final char[] URL_START_SEQ = new char[]{'q', 'p', 'i', 'd', ':'};
- private static final char PROPERTY_EQUALS_CHAR = '=';
- private static final char PROPERTY_SEPARATOR_CHAR = ';';
- private static final char ADDRESS_SEPERATOR_CHAR = ',';
-
- //private static final char CLIENT_ID_TRANSPORT_SEPARATOR_CHAR = ':';
- private static final char TRANSPORT_HOST_SEPARATOR_CHAR = ':';
- private static final char HOST_PORT_SEPARATOR_CHAR = ':';
- private static final char AT_CHAR = '@';
-
- enum URLParserState
- {
- QPID_URL_START,
- ADDRESS_START,
- PROPERTY_NAME,
- PROPERTY_EQUALS,
- PROPERTY_VALUE,
- PROPERTY_SEPARATOR,
- AT_CHAR,
- // CLIENT_ID,
- // CLIENT_ID_TRANSPORT_SEPARATOR,
- TRANSPORT,
- TRANSPORT_HOST_SEPARATOR,
- HOST,
- HOST_PORT_SEPARATOR,
- PORT,
- ADDRESS_END,
- ADDRESS_SEPERATOR,
- QPID_URL_END,
- ERROR
- }
-
- //-- Constructors
-
- private char[] _url;
- private List<BrokerDetails> _brokerDetailList = new ArrayList<BrokerDetails>();
- private String _error;
- private int _index = 0;
- private BrokerDetails _currentBroker;
- private String _currentPropName;
- private boolean _endOfURL = false;
- private URLParserState _currentParserState;
-
- public QpidURLImpl(String url) throws MalformedURLException
- {
- _url = url.toCharArray();
- _endOfURL = false;
- _currentParserState = URLParserState.QPID_URL_START;
- URLParserState prevState = _currentParserState; // for error handling
- try
- {
- while (_currentParserState != URLParserState.ERROR && _currentParserState != URLParserState.QPID_URL_END)
- {
- prevState = _currentParserState;
- _currentParserState = next();
- }
-
- if (_currentParserState == URLParserState.ERROR)
- {
- _error =
- "Invalid URL format [current_state = " + prevState + ", broker details parsed so far " + _currentBroker + " ] error at (" + _index + ") due to " + _error;
- MalformedURLException ex;
- ex = new MalformedURLException(_error);
- throw ex;
- }
- }
- catch (ArrayIndexOutOfBoundsException e)
- {
- e.printStackTrace();
- _error =
- "Invalid URL format [current_state = " + prevState + ", broker details parsed so far " + _currentBroker + " ] error at (" + _index + ")";
- MalformedURLException ex;
- ex = new MalformedURLException(_error);
- throw ex;
- }
- }
-
- //-- interface QpidURL
- public List<BrokerDetails> getAllBrokerDetails()
- {
- return _brokerDetailList;
- }
-
- public String getURL()
- {
- return new String(_url);
- }
-
- private URLParserState next()
- {
- switch (_currentParserState)
- {
- case QPID_URL_START:
- return checkSequence(URL_START_SEQ, URLParserState.ADDRESS_START);
- case ADDRESS_START:
- return startAddress();
- case PROPERTY_NAME:
- return extractPropertyName();
- case PROPERTY_EQUALS:
- _index++; // skip the equal sign
- return URLParserState.PROPERTY_VALUE;
- case PROPERTY_VALUE:
- return extractPropertyValue();
- case PROPERTY_SEPARATOR:
- _index++; // skip ","
- return URLParserState.PROPERTY_NAME;
- case AT_CHAR:
- _index++; // skip the @ sign
- return setProperties();
- // case CLIENT_ID:
- // return extractClientId();
- // case CLIENT_ID_TRANSPORT_SEPARATOR:
- // _index++; // skip ":"
- // return URLParserState.TRANSPORT;
- case TRANSPORT:
- return extractTransport();
- case TRANSPORT_HOST_SEPARATOR:
- _index++; // skip ":"
- return URLParserState.HOST;
- case HOST:
- return extractHost();
- case HOST_PORT_SEPARATOR:
- _index++; // skip ":"
- return URLParserState.PORT;
- case PORT:
- return extractPort();
- case ADDRESS_END:
- return endAddress();
- case ADDRESS_SEPERATOR:
- _index++; // skip ","
- return URLParserState.ADDRESS_START;
- default:
- return URLParserState.ERROR;
- }
- }
-
- private URLParserState checkSequence(char[] expected, URLParserState nextPart)
- {
- for (char anExpected : expected)
- {
- if (anExpected != _url[_index])
- {
- _error = "Excepted (" + anExpected + ") at position " + _index + ", got (" + _url[_index] + ")";
- return URLParserState.ERROR;
- }
- _index++;
- }
- return nextPart;
- }
-
- private URLParserState startAddress()
- {
- _currentBroker = new BrokerDetailsImpl();
- // check that there is a "@" before the nexte ","
- for (int j = _index; j < _url.length; j++)
- {
- if (_url[j] == AT_CHAR)
- {
- return URLParserState.PROPERTY_NAME;
- }
- else if (_url[j] == ADDRESS_SEPERATOR_CHAR)
- {
- return URLParserState.TRANSPORT;
- }
- }
- return URLParserState.TRANSPORT;
- }
-
- private URLParserState endAddress()
- {
- _brokerDetailList.add(_currentBroker);
- if (_endOfURL)
- {
- return URLParserState.QPID_URL_END;
- }
- else
- {
- return URLParserState.ADDRESS_SEPERATOR;
- }
- }
-
- private URLParserState extractPropertyName()
- {
- StringBuilder b = new StringBuilder();
- char next = _url[_index];
- while (next != PROPERTY_EQUALS_CHAR && next != AT_CHAR)
- {
- b.append(next);
- next = _url[++_index];
- }
- _currentPropName = b.toString();
- if (_currentPropName.trim().equals(""))
- {
- _error = "Property name cannot be empty";
- return URLParserState.ERROR;
- }
- else if (next == PROPERTY_EQUALS_CHAR)
- {
- return URLParserState.PROPERTY_EQUALS;
- }
- else
- {
- return URLParserState.AT_CHAR;
- }
- }
-
- private URLParserState extractPropertyValue()
- {
- StringBuilder b = new StringBuilder();
- char next = _url[_index];
- while (next != PROPERTY_SEPARATOR_CHAR && next != AT_CHAR)
- {
- b.append(next);
- next = _url[++_index];
- }
- String propValue = b.toString();
- if (propValue.trim().equals(""))
- {
- _error = "Property values cannot be empty";
- return URLParserState.ERROR;
- }
- else
- {
- _currentBroker.setProperty(_currentPropName, propValue);
- if (next == PROPERTY_SEPARATOR_CHAR)
- {
- return URLParserState.PROPERTY_SEPARATOR;
- }
- else
- {
- return URLParserState.AT_CHAR;
- }
- }
- }
-
- private URLParserState setProperties()
- {
- //Check if atleast virtualhost is there
- if (_currentBroker.getProperties().get(BrokerDetails.VIRTUAL_HOST) != null)
- {
- _currentBroker.setVirtualHost(_currentBroker.getProperties().get(BrokerDetails.VIRTUAL_HOST));
- _currentBroker.getProperties().remove(BrokerDetails.VIRTUAL_HOST);
- }
-
- if (_currentBroker.getProperties().get(BrokerDetails.USERNAME) != null)
- {
- String username = _currentBroker.getProperties().get(BrokerDetails.USERNAME);
- _currentBroker.setUserName(username);
- }
- if (_currentBroker.getProperties().get(BrokerDetails.PASSWORD) != null)
- {
- String password = _currentBroker.getProperties().get(BrokerDetails.PASSWORD);
- _currentBroker.setPassword(password);
- }
- if (_currentBroker.getProperties().get(BrokerDetails.CLIENT_ID) != null)
- {
- String clientID = _currentBroker.getProperties().get(BrokerDetails.CLIENT_ID);
- _currentBroker.setProperty(BrokerDetails.CLIENT_ID, clientID);
- }
- return URLParserState.TRANSPORT;
- }
-
- private URLParserState extractTransport()
- {
- String transport = buildUntil(TRANSPORT_HOST_SEPARATOR_CHAR);
- if (transport.trim().equals(""))
- {
- _error = "Transport cannot be empty";
- return URLParserState.ERROR;
- }
- else if (!(transport.trim().equals(BrokerDetails.PROTOCOL_TCP) || transport.trim()
- .equals(BrokerDetails.PROTOCOL_TLS)))
- {
- _error = "Transport cannot be " + transport + " value must be tcp or tls";
- return URLParserState.ERROR;
- }
- else
- {
- _currentBroker.setProtocol(transport);
- return URLParserState.TRANSPORT_HOST_SEPARATOR;
- }
- }
-
- private URLParserState extractHost()
- {
- char nextSep = 'c';
- String host;
- for (int i = _index; i < _url.length; i++)
- {
- if (_url[i] == HOST_PORT_SEPARATOR_CHAR)
- {
- nextSep = HOST_PORT_SEPARATOR_CHAR;
- break;
- }
- else if (_url[i] == ADDRESS_SEPERATOR_CHAR)
- {
- nextSep = ADDRESS_SEPERATOR_CHAR;
- break;
- }
- }
- if (nextSep == HOST_PORT_SEPARATOR_CHAR)
- {
- host = buildUntil(HOST_PORT_SEPARATOR_CHAR);
- if (host.trim().equals(""))
- {
- _error = "Host cannot be empty";
- return URLParserState.ERROR;
- }
- else
- {
- _currentBroker.setHost(host);
- return URLParserState.HOST_PORT_SEPARATOR;
- }
- }
- else if (nextSep == ADDRESS_SEPERATOR_CHAR)
- {
- host = buildUntil(ADDRESS_SEPERATOR_CHAR);
- if (host.trim().equals(""))
- {
- _error = "Host cannot be empty";
- return URLParserState.ERROR;
- }
- else
- {
- _currentBroker.setHost(host);
- return URLParserState.ADDRESS_END;
- }
- }
- else
- {
- host = String.copyValueOf(_url, _index, _url.length - _index);
- _currentBroker.setHost(host);
- _endOfURL = true;
- return URLParserState.ADDRESS_END;
- }
- }
-
-
- private URLParserState extractPort()
- {
-
- StringBuilder b = new StringBuilder();
- try
- {
- char next = _url[_index];
- while (next != ADDRESS_SEPERATOR_CHAR)
- {
- b.append(next);
- next = _url[++_index];
- }
- }
- catch (ArrayIndexOutOfBoundsException e)
- {
- _endOfURL = true;
- }
- String portStr = b.toString();
- if (portStr.trim().equals(""))
- {
- _error = "Host cannot be empty";
- return URLParserState.ERROR;
- }
- else
- {
- try
- {
- int port = Integer.parseInt(portStr);
- _currentBroker.setPort(port);
- return URLParserState.ADDRESS_END;
- }
- catch (NumberFormatException e)
- {
- _error = "Illegal number for port";
- return URLParserState.ERROR;
- }
- }
- }
-
- private String buildUntil(char c)
- {
- StringBuilder b = new StringBuilder();
- char next = _url[_index];
- while (next != c)
- {
- b.append(next);
- next = _url[++_index];
- }
- return b.toString();
- }
-
- public static void main(String[] args)
- {
- String testurl = "qpid:password=pass;username=name@tcp:test1,tcp:fooBroker,keystore=/usr/foo@tls:tlsBroker";
- try
- {
- QpidURLImpl impl = new QpidURLImpl(testurl);
- for (BrokerDetails d : impl.getAllBrokerDetails())
- {
- System.out.println(d);
- }
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/util/FileUtils.java b/java/common/src/main/java/org/apache/qpid/util/FileUtils.java
index 7494745457..7ba38f4743 100644
--- a/java/common/src/main/java/org/apache/qpid/util/FileUtils.java
+++ b/java/common/src/main/java/org/apache/qpid/util/FileUtils.java
@@ -20,7 +20,18 @@
*/
package org.apache.qpid.util;
-import java.io.*;
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.LinkedList;
+import java.util.List;
/**
* FileUtils provides some simple helper methods for working with files. It follows the convention of wrapping all
@@ -48,14 +59,31 @@ public class FileUtils
try
{
- is = new BufferedInputStream(new FileInputStream(filename));
+ try
+ {
+ is = new BufferedInputStream(new FileInputStream(filename));
+ }
+ catch (FileNotFoundException e)
+ {
+ throw new RuntimeException(e);
+ }
+
+ return readStreamAsString(is);
}
- catch (FileNotFoundException e)
+ finally
{
- throw new RuntimeException(e);
+ if (is != null)
+ {
+ try
+ {
+ is.close();
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
}
-
- return readStreamAsString(is);
}
/**
@@ -168,28 +196,182 @@ public class FileUtils
{
try
{
- InputStream in = new FileInputStream(src);
- if (!dst.exists())
+ copyCheckedEx(src, dst);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Copies the specified source file to the specified destination file. If the destination file does not exist,
+ * it is created.
+ *
+ * @param src The source file name.
+ * @param dst The destination file name.
+ * @throws IOException
+ */
+ public static void copyCheckedEx(File src, File dst) throws IOException
+ {
+ InputStream in = new FileInputStream(src);
+ if (!dst.exists())
+ {
+ dst.createNewFile();
+ }
+
+ OutputStream out = new FileOutputStream(dst);
+
+ // Transfer bytes from in to out
+ byte[] buf = new byte[1024];
+ int len;
+ while ((len = in.read(buf)) > 0)
+ {
+ out.write(buf, 0, len);
+ }
+
+ in.close();
+ out.close();
+ }
+
+ /*
+ * Deletes a given file
+ */
+ public static boolean deleteFile(String filePath)
+ {
+ return delete(new File(filePath), false);
+ }
+
+ /*
+ * Deletes a given empty directory
+ */
+ public static boolean deleteDirectory(String directoryPath)
+ {
+ File directory = new File(directoryPath);
+
+ if (directory.isDirectory())
+ {
+ if (directory.listFiles().length == 0)
{
- dst.createNewFile();
+ return delete(directory, true);
}
+ }
- OutputStream out = new FileOutputStream(dst);
+ return false;
+ }
- // Transfer bytes from in to out
- byte[] buf = new byte[1024];
- int len;
- while ((len = in.read(buf)) > 0)
+ /**
+ * Delete a given file/directory,
+ * A directory will always require the recursive flag to be set.
+ * if a directory is specified and recursive set then delete the whole tree
+ *
+ * @param file the File object to start at
+ * @param recursive boolean to recurse if a directory is specified.
+ *
+ * @return <code>true</code> if and only if the file or directory is
+ * successfully deleted; <code>false</code> otherwise
+ */
+ public static boolean delete(File file, boolean recursive)
+ {
+ boolean success = true;
+
+ if (file.isDirectory())
+ {
+ if (recursive)
{
- out.write(buf, 0, len);
+ File[] files = file.listFiles();
+
+ // This can occur if the file is deleted outside the JVM
+ if (files == null)
+ {
+ return false;
+ }
+
+ for (int i = 0; i < files.length; i++)
+ {
+ success = delete(files[i], true) && success;
+ }
+
+ return success && file.delete();
}
- in.close();
- out.close();
+ return false;
}
- catch (IOException e)
+
+ return file.delete();
+ }
+
+ public static class UnableToCopyException extends Exception
+ {
+ UnableToCopyException(String msg)
{
- throw new RuntimeException(e);
+ super(msg);
}
}
+
+ public static void copyRecursive(File source, File dst) throws FileNotFoundException, UnableToCopyException
+ {
+
+ if (!source.exists())
+ {
+ throw new FileNotFoundException("Unable to copy '" + source.toString() + "' as it does not exist.");
+ }
+
+ if (dst.exists() && !dst.isDirectory())
+ {
+ throw new IllegalArgumentException("Unable to copy '" + source.toString() + "' to '" + dst + "' a file with same name exists.");
+ }
+
+ if (source.isFile())
+ {
+ copy(source, dst);
+ }
+
+ //else we have a source directory
+ if (!dst.isDirectory() && !dst.mkdir())
+ {
+ throw new UnableToCopyException("Unable to create destination directory");
+ }
+
+ for (File file : source.listFiles())
+ {
+ if (file.isFile())
+ {
+ copy(file, new File(dst.toString() + File.separator + file.getName()));
+ }
+ else
+ {
+ copyRecursive(file, new File(dst + File.separator + file.getName()));
+ }
+ }
+
+ }
+
+ /**
+ * Checks the specified file for instances of the search string.
+ *
+ * @param file the file to search
+ * @param search the search String
+ *
+ * @throws java.io.IOException
+ * @return the list of matching entries
+ */
+ public static List<String> searchFile(File file, String search)
+ throws IOException
+ {
+
+ List<String> results = new LinkedList<String>();
+
+ BufferedReader reader = new BufferedReader(new FileReader(file));
+ while (reader.ready())
+ {
+ String line = reader.readLine();
+ if (line.contains(search))
+ {
+ results.add(line);
+ }
+ }
+
+ return results;
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/util/NetMatcher.java b/java/common/src/main/java/org/apache/qpid/util/NetMatcher.java
new file mode 100644
index 0000000000..4c653e6ca0
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/util/NetMatcher.java
@@ -0,0 +1,264 @@
+/***********************************************************************
+ * Copyright (c) 2000-2006 The Apache Software Foundation. *
+ * All rights reserved. *
+ * ------------------------------------------------------------------- *
+ * 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. *
+ ***********************************************************************/
+
+package org.apache.qpid.util;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+public class NetMatcher
+{
+ private ArrayList networks;
+
+ public void initInetNetworks(final Collection nets)
+ {
+ networks = new ArrayList();
+ for (Iterator iter = nets.iterator(); iter.hasNext(); ) try
+ {
+ InetNetwork net = InetNetwork.getFromString((String) iter.next());
+ if (!networks.contains(net)) networks.add(net);
+ }
+ catch (java.net.UnknownHostException uhe)
+ {
+ log("Cannot resolve address: " + uhe.getMessage());
+ }
+ networks.trimToSize();
+ }
+
+ public void initInetNetworks(final String[] nets)
+ {
+ networks = new ArrayList();
+ for (int i = 0; i < nets.length; i++) try
+ {
+ InetNetwork net = InetNetwork.getFromString(nets[i]);
+ if (!networks.contains(net)) networks.add(net);
+ }
+ catch (java.net.UnknownHostException uhe)
+ {
+ log("Cannot resolve address: " + uhe.getMessage());
+ }
+ networks.trimToSize();
+ }
+
+ public boolean matchInetNetwork(final String hostIP)
+ {
+ InetAddress ip = null;
+
+ try
+ {
+ ip = InetAddress.getByName(hostIP);
+ }
+ catch (java.net.UnknownHostException uhe)
+ {
+ log("Cannot resolve address for " + hostIP + ": " + uhe.getMessage());
+ }
+
+ boolean sameNet = false;
+
+ if (ip != null) for (Iterator iter = networks.iterator(); (!sameNet) && iter.hasNext(); )
+ {
+ InetNetwork network = (InetNetwork) iter.next();
+ sameNet = network.contains(ip);
+ }
+ return sameNet;
+ }
+
+ public boolean matchInetNetwork(final InetAddress ip)
+ {
+ boolean sameNet = false;
+
+ for (Iterator iter = networks.iterator(); (!sameNet) && iter.hasNext(); )
+ {
+ InetNetwork network = (InetNetwork) iter.next();
+ sameNet = network.contains(ip);
+ }
+ return sameNet;
+ }
+
+ public NetMatcher()
+ {
+ }
+
+ public NetMatcher(final String[] nets)
+ {
+ initInetNetworks(nets);
+ }
+
+ public NetMatcher(final Collection nets)
+ {
+ initInetNetworks(nets);
+ }
+
+ public String toString() {
+ return networks.toString();
+ }
+
+ protected void log(String s) { }
+}
+
+class InetNetwork
+{
+ /*
+ * Implements network masking, and is compatible with RFC 1518 and
+ * RFC 1519, which describe CIDR: Classless Inter-Domain Routing.
+ */
+
+ private InetAddress network;
+ private InetAddress netmask;
+
+ public InetNetwork(InetAddress ip, InetAddress netmask)
+ {
+ network = maskIP(ip, netmask);
+ this.netmask = netmask;
+ }
+
+ public boolean contains(final String name) throws java.net.UnknownHostException
+ {
+ return network.equals(maskIP(InetAddress.getByName(name), netmask));
+ }
+
+ public boolean contains(final InetAddress ip)
+ {
+ return network.equals(maskIP(ip, netmask));
+ }
+
+ public String toString()
+ {
+ return network.getHostAddress() + "/" + netmask.getHostAddress();
+ }
+
+ public int hashCode()
+ {
+ return maskIP(network, netmask).hashCode();
+ }
+
+ public boolean equals(Object obj)
+ {
+ return (obj != null) && (obj instanceof InetNetwork) &&
+ ((((InetNetwork)obj).network.equals(network)) && (((InetNetwork)obj).netmask.equals(netmask)));
+ }
+
+ public static InetNetwork getFromString(String netspec) throws java.net.UnknownHostException
+ {
+ if (netspec.endsWith("*")) netspec = normalizeFromAsterisk(netspec);
+ else
+ {
+ int iSlash = netspec.indexOf('/');
+ if (iSlash == -1) netspec += "/255.255.255.255";
+ else if (netspec.indexOf('.', iSlash) == -1) netspec = normalizeFromCIDR(netspec);
+ }
+
+ return new InetNetwork(InetAddress.getByName(netspec.substring(0, netspec.indexOf('/'))),
+ InetAddress.getByName(netspec.substring(netspec.indexOf('/') + 1)));
+ }
+
+ public static InetAddress maskIP(final byte[] ip, final byte[] mask)
+ {
+ try
+ {
+ return getByAddress(new byte[]
+ {
+ (byte) (mask[0] & ip[0]),
+ (byte) (mask[1] & ip[1]),
+ (byte) (mask[2] & ip[2]),
+ (byte) (mask[3] & ip[3])
+ });
+ }
+ catch(Exception _) {}
+ {
+ return null;
+ }
+ }
+
+ public static InetAddress maskIP(final InetAddress ip, final InetAddress mask)
+ {
+ return maskIP(ip.getAddress(), mask.getAddress());
+ }
+
+ /*
+ * This converts from an uncommon "wildcard" CIDR format
+ * to "address + mask" format:
+ *
+ * * => 000.000.000.0/000.000.000.0
+ * xxx.* => xxx.000.000.0/255.000.000.0
+ * xxx.xxx.* => xxx.xxx.000.0/255.255.000.0
+ * xxx.xxx.xxx.* => xxx.xxx.xxx.0/255.255.255.0
+ */
+ static private String normalizeFromAsterisk(final String netspec)
+ {
+ String[] masks = { "0.0.0.0/0.0.0.0", "0.0.0/255.0.0.0", "0.0/255.255.0.0", "0/255.255.255.0" };
+ char[] srcb = netspec.toCharArray();
+ int octets = 0;
+ for (int i = 1; i < netspec.length(); i++) {
+ if (srcb[i] == '.') octets++;
+ }
+ return (octets == 0) ? masks[0] : netspec.substring(0, netspec.length() -1 ).concat(masks[octets]);
+ }
+
+ /*
+ * RFC 1518, 1519 - Classless Inter-Domain Routing (CIDR)
+ * This converts from "prefix + prefix-length" format to
+ * "address + mask" format, e.g. from xxx.xxx.xxx.xxx/yy
+ * to xxx.xxx.xxx.xxx/yyy.yyy.yyy.yyy.
+ */
+ static private String normalizeFromCIDR(final String netspec)
+ {
+ final int bits = 32 - Integer.parseInt(netspec.substring(netspec.indexOf('/')+1));
+ final int mask = (bits == 32) ? 0 : 0xFFFFFFFF - ((1 << bits)-1);
+
+ return netspec.substring(0, netspec.indexOf('/') + 1) +
+ Integer.toString(mask >> 24 & 0xFF, 10) + "." +
+ Integer.toString(mask >> 16 & 0xFF, 10) + "." +
+ Integer.toString(mask >> 8 & 0xFF, 10) + "." +
+ Integer.toString(mask >> 0 & 0xFF, 10);
+ }
+
+ private static java.lang.reflect.Method getByAddress = null;
+
+ static {
+ try {
+ Class inetAddressClass = Class.forName("java.net.InetAddress");
+ Class[] parameterTypes = { byte[].class };
+ getByAddress = inetAddressClass.getMethod("getByAddress", parameterTypes);
+ } catch (Exception e) {
+ getByAddress = null;
+ }
+ }
+
+ private static InetAddress getByAddress(byte[] ip) throws java.net.UnknownHostException
+ {
+ InetAddress addr = null;
+ if (getByAddress != null) try {
+ addr = (InetAddress) getByAddress.invoke(null, new Object[] { ip });
+ } catch (IllegalAccessException e) {
+ } catch (java.lang.reflect.InvocationTargetException e) {
+ }
+
+ if (addr == null) {
+ addr = InetAddress.getByName
+ (
+ Integer.toString(ip[0] & 0xFF, 10) + "." +
+ Integer.toString(ip[1] & 0xFF, 10) + "." +
+ Integer.toString(ip[2] & 0xFF, 10) + "." +
+ Integer.toString(ip[3] & 0xFF, 10)
+ );
+ }
+ return addr;
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpid/util/PropertiesUtils.java b/java/common/src/main/java/org/apache/qpid/util/PropertiesUtils.java
deleted file mode 100644
index d90e3b1a17..0000000000
--- a/java/common/src/main/java/org/apache/qpid/util/PropertiesUtils.java
+++ /dev/null
@@ -1,200 +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.
- *
- */
-package org.apache.qpid.util;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.Iterator;
-import java.util.Properties;
-
-/**
- * PropertiesHelper defines some static methods which are useful when working with properties
- * files.
- *
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Read properties from an input stream
- * <tr><td> Read properties from a file
- * <tr><td> Read properties from a URL
- * <tr><td> Read properties given a path to a file
- * <tr><td> Trim any whitespace from property values
- * </table>
- */
-public class PropertiesUtils
-{
- /** Used for logging. */
- private static final Logger log = LoggerFactory.getLogger(PropertiesUtils.class);
-
- /**
- * Get properties from an input stream.
- *
- * @param is The input stream.
- *
- * @return The properties loaded from the input stream.
- *
- * @throws IOException If the is an I/O error reading from the stream.
- */
- public static Properties getProperties(InputStream is) throws IOException
- {
- log.debug("getProperties(InputStream): called");
-
- // Create properties object laoded from input stream
- Properties properties = new Properties();
-
- properties.load(is);
-
- return properties;
- }
-
- /**
- * Get properties from a file.
- *
- * @param file The file.
- *
- * @return The properties loaded from the file.
- *
- * @throws IOException If there is an I/O error reading from the file.
- */
- public static Properties getProperties(File file) throws IOException
- {
- log.debug("getProperties(File): called");
-
- // Open the file as an input stream
- InputStream is = new FileInputStream(file);
-
- // Create properties object loaded from the stream
- Properties properties = getProperties(is);
-
- // Close the file
- is.close();
-
- return properties;
- }
-
- /**
- * Get properties from a url.
- *
- * @param url The URL.
- *
- * @return The properties loaded from the url.
- *
- * @throws IOException If there is an I/O error reading from the URL.
- */
- public static Properties getProperties(URL url) throws IOException
- {
- log.debug("getProperties(URL): called");
-
- // Open the URL as an input stream
- InputStream is = url.openStream();
-
- // Create properties object loaded from the stream
- Properties properties = getProperties(is);
-
- // Close the url
- is.close();
-
- return properties;
- }
-
- /**
- * Get properties from a path name. The path name may refer to either a file or a URL.
- *
- * @param pathname The path name.
- *
- * @return The properties loaded from the file or URL.
- *
- * @throws IOException If there is an I/O error reading from the URL or file named by the path.
- */
- public static Properties getProperties(String pathname) throws IOException
- {
- log.debug("getProperties(String): called");
-
- // Check that the path is not null
- if (pathname == null)
- {
- return null;
- }
-
- // Check if the path is a URL
- if (isURL(pathname))
- {
- // The path is a URL
- return getProperties(new URL(pathname));
- }
- else
- {
- // Assume the path is a file name
- return getProperties(new File(pathname));
- }
- }
-
- /**
- * Trims whitespace from property values. This method returns a new set of properties
- * the same as the properties specified as an argument but with any white space removed by
- * the {@link java.lang.String#trim} method.
- *
- * @param properties The properties to trim whitespace from.
- *
- * @return The white space trimmed properties.
- */
- public static Properties trim(Properties properties)
- {
- Properties trimmedProperties = new Properties();
-
- // Loop over all the properties
- for (Iterator i = properties.keySet().iterator(); i.hasNext();)
- {
- String next = (String) i.next();
- String nextValue = properties.getProperty(next);
-
- // Trim the value if it is not null
- if (nextValue != null)
- {
- nextValue.trim();
- }
-
- // Store the trimmed value in the trimmed properties
- trimmedProperties.setProperty(next, nextValue);
- }
-
- return trimmedProperties;
- }
-
- /**
- * Helper method. Guesses whether a string is a URL or not. A String is considered to be a url if it begins with
- * http:, ftp:, or uucp:.
- *
- * @param name The string to test for being a URL.
- *
- * @return True if the string is a URL and false if not.
- */
- private static boolean isURL(String name)
- {
- return (name.toLowerCase().startsWith("http:") || name.toLowerCase().startsWith("ftp:")
- || name.toLowerCase().startsWith("uucp:"));
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/util/Serial.java b/java/common/src/main/java/org/apache/qpid/util/Serial.java
index 44712984c0..8ad9d00f54 100644
--- a/java/common/src/main/java/org/apache/qpid/util/Serial.java
+++ b/java/common/src/main/java/org/apache/qpid/util/Serial.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import java.util.Comparator;
diff --git a/java/common/src/main/java/org/apache/qpid/util/Strings.java b/java/common/src/main/java/org/apache/qpid/util/Strings.java
index 4b199bafe6..04bf174ff0 100644
--- a/java/common/src/main/java/org/apache/qpid/util/Strings.java
+++ b/java/common/src/main/java/org/apache/qpid/util/Strings.java
@@ -22,6 +22,12 @@ package org.apache.qpid.util;
import java.io.UnsupportedEncodingException;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Stack;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
/**
* Strings
@@ -79,4 +85,154 @@ public final class Strings
}
}
+ public static final String fromUTF8(byte[] bytes)
+ {
+ try
+ {
+ return new String(bytes, "UTF-8");
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static final Pattern VAR = Pattern.compile("(?:\\$\\{([^\\}]*)\\})|(?:\\$(\\$))");
+
+ public static interface Resolver
+ {
+ String resolve(String variable);
+ }
+
+ public static class MapResolver implements Resolver
+ {
+
+ private final Map<String,String> map;
+
+ public MapResolver(Map<String,String> map)
+ {
+ this.map = map;
+ }
+
+ public String resolve(String variable)
+ {
+ return map.get(variable);
+ }
+ }
+
+ public static class PropertiesResolver implements Resolver
+ {
+
+ private final Properties properties;
+
+ public PropertiesResolver(Properties properties)
+ {
+ this.properties = properties;
+ }
+
+ public String resolve(String variable)
+ {
+ return properties.getProperty(variable);
+ }
+ }
+
+ public static class ChainedResolver implements Resolver
+ {
+ private final Resolver primary;
+ private final Resolver secondary;
+
+ public ChainedResolver(Resolver primary, Resolver secondary)
+ {
+ this.primary = primary;
+ this.secondary = secondary;
+ }
+
+ public String resolve(String variable)
+ {
+ String result = primary.resolve(variable);
+ if (result == null)
+ {
+ result = secondary.resolve(variable);
+ }
+ return result;
+ }
+ }
+
+ public static final Resolver SYSTEM_RESOLVER = new Resolver()
+ {
+ public String resolve(String variable)
+ {
+ String result = System.getProperty(variable);
+ if (result == null)
+ {
+ result = System.getenv(variable);
+ }
+ return result;
+ }
+ };
+
+ public static final String expand(String input)
+ {
+ return expand(input, SYSTEM_RESOLVER);
+ }
+
+ public static final String expand(String input, Resolver resolver)
+ {
+ return expand(input, resolver, new Stack());
+ }
+
+ private static final String expand(String input, Resolver resolver, Stack<String> stack)
+ {
+ Matcher m = VAR.matcher(input);
+ StringBuffer result = new StringBuffer();
+ while (m.find())
+ {
+ String var = m.group(1);
+ if (var == null)
+ {
+ String esc = m.group(2);
+ if ("$".equals(esc))
+ {
+ m.appendReplacement(result, Matcher.quoteReplacement("$"));
+ }
+ else
+ {
+ throw new IllegalArgumentException(esc);
+ }
+ }
+ else
+ {
+ m.appendReplacement(result, Matcher.quoteReplacement(resolve(var, resolver, stack)));
+ }
+ }
+ m.appendTail(result);
+ return result.toString();
+ }
+
+ private static final String resolve(String var, Resolver resolver, Stack<String> stack)
+ {
+ if (stack.contains(var))
+ {
+ throw new IllegalArgumentException
+ (String.format("recursively defined variable: %s stack=%s", var,
+ stack));
+ }
+
+ String result = resolver.resolve(var);
+ if (result == null)
+ {
+ throw new IllegalArgumentException("no such variable: " + var);
+ }
+
+ stack.push(var);
+ try
+ {
+ return expand(result, resolver, stack);
+ }
+ finally
+ {
+ stack.pop();
+ }
+ }
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/util/concurrent/AlreadyUnblockedException.java b/java/common/src/main/java/org/apache/qpid/util/concurrent/AlreadyUnblockedException.java
index ef43d1c8a8..e0c0337898 100644
--- a/java/common/src/main/java/org/apache/qpid/util/concurrent/AlreadyUnblockedException.java
+++ b/java/common/src/main/java/org/apache/qpid/util/concurrent/AlreadyUnblockedException.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util.concurrent;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
/**
* Used to signal that a data element and its producer cannot be requeued or sent an error message when using a
diff --git a/java/common/src/main/java/org/apache/qpid/util/concurrent/BatchSynchQueue.java b/java/common/src/main/java/org/apache/qpid/util/concurrent/BatchSynchQueue.java
index 261eecb561..63d8f77edb 100644
--- a/java/common/src/main/java/org/apache/qpid/util/concurrent/BatchSynchQueue.java
+++ b/java/common/src/main/java/org/apache/qpid/util/concurrent/BatchSynchQueue.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util.concurrent;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import java.util.Collection;
import java.util.concurrent.BlockingQueue;
diff --git a/java/common/src/main/java/org/apache/qpid/util/concurrent/BatchSynchQueueBase.java b/java/common/src/main/java/org/apache/qpid/util/concurrent/BatchSynchQueueBase.java
index d1c1abd285..4564b1d686 100644
--- a/java/common/src/main/java/org/apache/qpid/util/concurrent/BatchSynchQueueBase.java
+++ b/java/common/src/main/java/org/apache/qpid/util/concurrent/BatchSynchQueueBase.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util.concurrent;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import java.util.*;
import java.util.concurrent.TimeUnit;
diff --git a/java/common/src/main/java/org/apache/qpid/util/concurrent/BooleanLatch.java b/java/common/src/main/java/org/apache/qpid/util/concurrent/BooleanLatch.java
index 391ca686c9..0e4a07594f 100644
--- a/java/common/src/main/java/org/apache/qpid/util/concurrent/BooleanLatch.java
+++ b/java/common/src/main/java/org/apache/qpid/util/concurrent/BooleanLatch.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util.concurrent;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
diff --git a/java/common/src/main/java/org/apache/qpid/util/concurrent/Capacity.java b/java/common/src/main/java/org/apache/qpid/util/concurrent/Capacity.java
index e317c84971..a97ce0e172 100644
--- a/java/common/src/main/java/org/apache/qpid/util/concurrent/Capacity.java
+++ b/java/common/src/main/java/org/apache/qpid/util/concurrent/Capacity.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util.concurrent;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
/**
* An interface exposed by data structures that have a maximum capacity.
diff --git a/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchBuffer.java b/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchBuffer.java
index 49020803d7..bc63eb0353 100644
--- a/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchBuffer.java
+++ b/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchBuffer.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util.concurrent;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import java.util.Queue;
diff --git a/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchException.java b/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchException.java
index 77b60f2b72..99a83f96cd 100644
--- a/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchException.java
+++ b/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchException.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util.concurrent;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
/**
* SynchException is used to encapsulate exceptions with the data elements that caused them in order to send exceptions
diff --git a/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchQueue.java b/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchQueue.java
index 9d15c211f6..95833f398a 100644
--- a/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchQueue.java
+++ b/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchQueue.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util.concurrent;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import java.util.LinkedList;
import java.util.Queue;
diff --git a/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchRecord.java b/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchRecord.java
index 5e002100c2..fd740c20cd 100644
--- a/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchRecord.java
+++ b/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchRecord.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util.concurrent;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
/**
* SynchRecord associates a data item from a {@link BatchSynchQueue} with its producer. This enables the data item data
diff --git a/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchRef.java b/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchRef.java
index a75f7b766d..efe2344c06 100644
--- a/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchRef.java
+++ b/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchRef.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util.concurrent;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
/**
* A SynchRef is an interface which is returned from the synchronous take and drain methods of {@link BatchSynchQueue},
diff --git a/java/common/src/test/java/org/apache/qpid/AMQExceptionTest.java b/java/common/src/test/java/org/apache/qpid/AMQExceptionTest.java
new file mode 100644
index 0000000000..ef6cd41492
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/AMQExceptionTest.java
@@ -0,0 +1,106 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid;
+
+import junit.framework.TestCase;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.framing.AMQFrameDecodingException;
+
+/**
+ * This test is to ensure that when an AMQException is rethrown that the specified exception is correctly wrapped up.
+ *
+ * There are three cases:
+ * Re-throwing an AMQException
+ * Re-throwing a Subclass of AMQException
+ * Re-throwing a Subclass of AMQException that does not have the default AMQException constructor which will force the
+ * creation of an AMQException.
+ */
+public class AMQExceptionTest extends TestCase
+{
+ /**
+ * Test that an AMQException will be correctly created and rethrown.
+ */
+ public void testRethrowGeneric()
+ {
+ AMQException test = new AMQException(AMQConstant.ACCESS_REFUSED, "refused", new RuntimeException());
+
+ AMQException e = reThrowException(test);
+
+ assertEquals("Exception not of correct class", AMQException.class, e.getClass());
+
+ }
+
+ /**
+ * Test that a subclass of AMQException that has the default constructor will be correctly created and rethrown.
+ */
+ public void testRethrowAMQESubclass()
+ {
+ AMQFrameDecodingException test = new AMQFrameDecodingException(AMQConstant.INTERNAL_ERROR,
+ "Error",
+ new Exception());
+ AMQException e = reThrowException(test);
+
+ assertEquals("Exception not of correct class", AMQFrameDecodingException.class, e.getClass());
+ }
+
+ /**
+ * Test that a subclass of AMQException that doesnot have the default constructor will be correctly rethrown as an
+ * AMQException
+ */
+ public void testRethrowAMQESubclassNoConstructor()
+ {
+ AMQExceptionSubclass test = new AMQExceptionSubclass("Invalid Argument Exception");
+
+ AMQException e = reThrowException(test);
+
+ assertEquals("Exception not of correct class", AMQException.class, e.getClass());
+ }
+
+ /**
+ * Private method to rethrown and validate the basic values of the rethrown
+ * @param test Exception to rethrow
+ * @throws AMQException the rethrown exception
+ */
+ private AMQException reThrowException(AMQException test)
+ {
+ AMQException amqe = test.cloneForCurrentThread();
+
+ assertEquals("Error code does not match.", test.getErrorCode(), amqe.getErrorCode());
+ assertTrue("Exception message does not start as expected.", amqe.getMessage().startsWith(test.getMessage()));
+ assertEquals("Test Exception is not set as the cause", test, amqe.getCause());
+ assertEquals("Cause is not correct", test.getCause(), amqe.getCause().getCause());
+
+ return amqe;
+ }
+
+ /**
+ * Private class that extends AMQException but does not have a default exception.
+ */
+ private class AMQExceptionSubclass extends AMQException
+ {
+
+ public AMQExceptionSubclass(String msg)
+ {
+ super(null, msg, null);
+ }
+ }
+}
+
diff --git a/java/common/src/test/java/org/apache/qpid/codec/AMQDecoderTest.java b/java/common/src/test/java/org/apache/qpid/codec/AMQDecoderTest.java
new file mode 100644
index 0000000000..46c812e265
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/codec/AMQDecoderTest.java
@@ -0,0 +1,130 @@
+package org.apache.qpid.codec;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.framing.AMQDataBlock;
+import org.apache.qpid.framing.AMQFrame;
+import org.apache.qpid.framing.AMQFrameDecodingException;
+import org.apache.qpid.framing.AMQProtocolVersionException;
+import org.apache.qpid.framing.HeartbeatBody;
+
+public class AMQDecoderTest extends TestCase
+{
+
+ private AMQCodecFactory _factory;
+ private AMQDecoder _decoder;
+
+
+ public void setUp()
+ {
+ _factory = new AMQCodecFactory(false, null);
+ _decoder = _factory.getDecoder();
+ }
+
+
+ public void testSingleFrameDecode() throws AMQProtocolVersionException, AMQFrameDecodingException
+ {
+ ByteBuffer msg = HeartbeatBody.FRAME.toNioByteBuffer();
+ ArrayList<AMQDataBlock> frames = _decoder.decodeBuffer(msg);
+ if (frames.get(0) instanceof AMQFrame)
+ {
+ assertEquals(HeartbeatBody.FRAME.getBodyFrame().getFrameType(), ((AMQFrame) frames.get(0)).getBodyFrame().getFrameType());
+ }
+ else
+ {
+ fail("decode was not a frame");
+ }
+ }
+
+ public void testPartialFrameDecode() throws AMQProtocolVersionException, AMQFrameDecodingException
+ {
+ ByteBuffer msg = HeartbeatBody.FRAME.toNioByteBuffer();
+ ByteBuffer msgA = msg.slice();
+ int msgbPos = msg.remaining() / 2;
+ int msgaLimit = msg.remaining() - msgbPos;
+ msgA.limit(msgaLimit);
+ msg.position(msgbPos);
+ ByteBuffer msgB = msg.slice();
+ ArrayList<AMQDataBlock> frames = _decoder.decodeBuffer(msgA);
+ assertEquals(0, frames.size());
+ frames = _decoder.decodeBuffer(msgB);
+ assertEquals(1, frames.size());
+ if (frames.get(0) instanceof AMQFrame)
+ {
+ assertEquals(HeartbeatBody.FRAME.getBodyFrame().getFrameType(), ((AMQFrame) frames.get(0)).getBodyFrame().getFrameType());
+ }
+ else
+ {
+ fail("decode was not a frame");
+ }
+ }
+
+ public void testMultipleFrameDecode() throws AMQProtocolVersionException, AMQFrameDecodingException
+ {
+ ByteBuffer msgA = HeartbeatBody.FRAME.toNioByteBuffer();
+ ByteBuffer msgB = HeartbeatBody.FRAME.toNioByteBuffer();
+ ByteBuffer msg = ByteBuffer.allocate(msgA.remaining() + msgB.remaining());
+ msg.put(msgA);
+ msg.put(msgB);
+ msg.flip();
+ ArrayList<AMQDataBlock> frames = _decoder.decodeBuffer(msg);
+ assertEquals(2, frames.size());
+ for (AMQDataBlock frame : frames)
+ {
+ if (frame instanceof AMQFrame)
+ {
+ assertEquals(HeartbeatBody.FRAME.getBodyFrame().getFrameType(), ((AMQFrame) frame).getBodyFrame().getFrameType());
+ }
+ else
+ {
+ fail("decode was not a frame");
+ }
+ }
+ }
+
+ public void testMultiplePartialFrameDecode() throws AMQProtocolVersionException, AMQFrameDecodingException
+ {
+ ByteBuffer msgA = HeartbeatBody.FRAME.toNioByteBuffer();
+ ByteBuffer msgB = HeartbeatBody.FRAME.toNioByteBuffer();
+ ByteBuffer msgC = HeartbeatBody.FRAME.toNioByteBuffer();
+
+ ByteBuffer sliceA = ByteBuffer.allocate(msgA.remaining() + msgB.remaining() / 2);
+ sliceA.put(msgA);
+ int limit = msgB.limit();
+ int pos = msgB.remaining() / 2;
+ msgB.limit(pos);
+ sliceA.put(msgB);
+ sliceA.flip();
+ msgB.limit(limit);
+ msgB.position(pos);
+
+ ByteBuffer sliceB = ByteBuffer.allocate(msgB.remaining() + pos);
+ sliceB.put(msgB);
+ msgC.limit(pos);
+ sliceB.put(msgC);
+ sliceB.flip();
+ msgC.limit(limit);
+
+ ArrayList<AMQDataBlock> frames = _decoder.decodeBuffer(sliceA);
+ assertEquals(1, frames.size());
+ frames = _decoder.decodeBuffer(sliceB);
+ assertEquals(1, frames.size());
+ frames = _decoder.decodeBuffer(msgC);
+ assertEquals(1, frames.size());
+ for (AMQDataBlock frame : frames)
+ {
+ if (frame instanceof AMQFrame)
+ {
+ assertEquals(HeartbeatBody.FRAME.getBodyFrame().getFrameType(), ((AMQFrame) frame).getBodyFrame().getFrameType());
+ }
+ else
+ {
+ fail("decode was not a frame");
+ }
+ }
+ }
+
+}
diff --git a/java/common/src/test/java/org/apache/qpid/codec/MockAMQVersionAwareProtocolSession.java b/java/common/src/test/java/org/apache/qpid/codec/MockAMQVersionAwareProtocolSession.java
new file mode 100644
index 0000000000..c3b91d5d18
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/codec/MockAMQVersionAwareProtocolSession.java
@@ -0,0 +1,84 @@
+package org.apache.qpid.codec;
+
+import java.nio.ByteBuffer;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQDataBlock;
+import org.apache.qpid.framing.AMQMethodBody;
+import org.apache.qpid.framing.ContentBody;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.HeartbeatBody;
+import org.apache.qpid.framing.MethodRegistry;
+import org.apache.qpid.framing.ProtocolVersion;
+import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
+import org.apache.qpid.transport.Sender;
+
+public class MockAMQVersionAwareProtocolSession implements AMQVersionAwareProtocolSession
+{
+
+ public void contentBodyReceived(int channelId, ContentBody body) throws AMQException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void contentHeaderReceived(int channelId, ContentHeaderBody body) throws AMQException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public MethodRegistry getMethodRegistry()
+ {
+ return MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9);
+ }
+
+ public void heartbeatBodyReceived(int channelId, HeartbeatBody body) throws AMQException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void init()
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void methodFrameReceived(int channelId, AMQMethodBody body) throws AMQException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setSender(Sender<ByteBuffer> sender)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void writeFrame(AMQDataBlock frame)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public byte getProtocolMajorVersion()
+ {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public byte getProtocolMinorVersion()
+ {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public ProtocolVersion getProtocolVersion()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/java/common/src/test/java/org/apache/qpid/framing/abstraction/MessagePublishInfoImplTest.java b/java/common/src/test/java/org/apache/qpid/framing/abstraction/MessagePublishInfoImplTest.java
new file mode 100644
index 0000000000..3243136287
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/framing/abstraction/MessagePublishInfoImplTest.java
@@ -0,0 +1,99 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.framing.abstraction;
+
+import junit.framework.TestCase;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.abstraction.MessagePublishInfoImpl;
+
+public class MessagePublishInfoImplTest extends TestCase
+{
+ MessagePublishInfoImpl _mpi;
+ final AMQShortString _exchange = new AMQShortString("exchange");
+ final AMQShortString _routingKey = new AMQShortString("routingKey");
+
+ public void setUp()
+ {
+ _mpi = new MessagePublishInfoImpl(_exchange, true, true, _routingKey);
+ }
+
+ /** Test that we can update the exchange value. */
+ public void testExchange()
+ {
+ assertEquals(_exchange, _mpi.getExchange());
+ AMQShortString newExchange = new AMQShortString("newExchange");
+ //Check we can update the exchange
+ _mpi.setExchange(newExchange);
+ assertEquals(newExchange, _mpi.getExchange());
+ //Ensure that the new exchange doesn't equal the old one
+ assertFalse(_exchange.equals(_mpi.getExchange()));
+ }
+
+ /**
+ * Check that the immedate value is set correctly and defaulted correctly
+ */
+ public void testIsImmediate()
+ {
+ //Check that the set value is correct
+ assertTrue("Set value for immediate not as expected", _mpi.isImmediate());
+
+ MessagePublishInfoImpl mpi = new MessagePublishInfoImpl();
+
+ assertFalse("Default value for immediate should be false", mpi.isImmediate());
+
+ mpi.setImmediate(true);
+
+ assertTrue("Updated value for immediate not as expected", mpi.isImmediate());
+
+ }
+
+ /**
+ * Check that the mandatory value is set correctly and defaulted correctly
+ */
+ public void testIsMandatory()
+ {
+ assertTrue("Set value for mandatory not as expected", _mpi.isMandatory());
+
+ MessagePublishInfoImpl mpi = new MessagePublishInfoImpl();
+
+ assertFalse("Default value for mandatory should be false", mpi.isMandatory());
+
+ mpi.setMandatory(true);
+
+ assertTrue("Updated value for mandatory not as expected", mpi.isMandatory());
+ }
+
+ /**
+ * Check that the routingKey value is perserved
+ */
+ public void testRoutingKey()
+ {
+ assertEquals(_routingKey, _mpi.getRoutingKey());
+ AMQShortString newRoutingKey = new AMQShortString("newRoutingKey");
+
+ //Check we can update the routingKey
+ _mpi.setRoutingKey(newRoutingKey);
+ assertEquals(newRoutingKey, _mpi.getRoutingKey());
+ //Ensure that the new routingKey doesn't equal the old one
+ assertFalse(_routingKey.equals(_mpi.getRoutingKey()));
+
+ }
+}
diff --git a/java/common/src/test/java/org/apache/qpid/pool/PoolingFilterTest.java b/java/common/src/test/java/org/apache/qpid/pool/PoolingFilterTest.java
deleted file mode 100644
index 6383d52298..0000000000
--- a/java/common/src/test/java/org/apache/qpid/pool/PoolingFilterTest.java
+++ /dev/null
@@ -1,111 +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.
- *
- *
- */
-package org.apache.qpid.pool;
-
-import junit.framework.TestCase;
-import junit.framework.Assert;
-import org.apache.qpid.session.TestSession;
-import org.apache.mina.common.IoFilter;
-import org.apache.mina.common.IoSession;
-import org.apache.mina.common.IdleStatus;
-
-import java.util.concurrent.RejectedExecutionException;
-
-public class PoolingFilterTest extends TestCase
-{
- private PoolingFilter _pool;
- ReferenceCountingExecutorService _executorService;
-
- public void setUp()
- {
-
- //Create Pool
- _executorService = ReferenceCountingExecutorService.getInstance();
- _executorService.acquireExecutorService();
- _pool = PoolingFilter.createAynschWritePoolingFilter(_executorService,
- "AsynchronousWriteFilter");
-
- }
-
- public void testRejectedExecution() throws Exception
- {
-
- TestSession testSession = new TestSession();
- _pool.createNewJobForSession(testSession);
- _pool.filterWrite(new NoOpFilter(), testSession, new IoFilter.WriteRequest("Message"));
-
- //Shutdown the pool
- _executorService.getPool().shutdownNow();
-
- try
- {
-
- testSession = new TestSession();
- _pool.createNewJobForSession(testSession);
- //prior to fix for QPID-172 this would throw RejectedExecutionException
- _pool.filterWrite(null, testSession, null);
- }
- catch (RejectedExecutionException rje)
- {
- Assert.fail("RejectedExecutionException should not occur after pool has shutdown:" + rje);
- }
- }
-
- private static class NoOpFilter implements IoFilter.NextFilter
- {
-
- public void sessionOpened(IoSession session)
- {
- }
-
- public void sessionClosed(IoSession session)
- {
- }
-
- public void sessionIdle(IoSession session, IdleStatus status)
- {
- }
-
- public void exceptionCaught(IoSession session, Throwable cause)
- {
- }
-
- public void messageReceived(IoSession session, Object message)
- {
- }
-
- public void messageSent(IoSession session, Object message)
- {
- }
-
- public void filterWrite(IoSession session, IoFilter.WriteRequest writeRequest)
- {
- }
-
- public void filterClose(IoSession session)
- {
- }
-
- public void sessionCreated(IoSession session)
- {
- }
- }
-}
diff --git a/java/common/src/test/java/org/apache/qpid/thread/ThreadFactoryTest.java b/java/common/src/test/java/org/apache/qpid/thread/ThreadFactoryTest.java
new file mode 100644
index 0000000000..9932633cb9
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/thread/ThreadFactoryTest.java
@@ -0,0 +1,46 @@
+package org.apache.qpid.thread;
+
+import junit.framework.TestCase;
+
+public class ThreadFactoryTest extends TestCase
+{
+ public void testThreadFactory()
+ {
+ Class threadFactoryClass = null;
+ try
+ {
+ threadFactoryClass = Class.forName(System.getProperty("qpid.thread_factory",
+ "org.apache.qpid.thread.DefaultThreadFactory"));
+ }
+ // If the thread factory class was wrong it will flagged way before it gets here.
+ catch(Exception e)
+ {
+ fail("Invalid thread factory class");
+ }
+
+ assertEquals(threadFactoryClass, Threading.getThreadFactory().getClass());
+ }
+
+ public void testThreadCreate()
+ {
+ Runnable r = new Runnable(){
+
+ public void run(){
+
+ }
+ };
+
+ Thread t = null;
+ try
+ {
+ t = Threading.getThreadFactory().createThread(r,5);
+ }
+ catch(Exception e)
+ {
+ fail("Error creating thread using Qpid thread factory");
+ }
+
+ assertNotNull(t);
+ assertEquals(5,t.getPriority());
+ }
+}
diff --git a/java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java b/java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java
index b9ca210483..8aa8c5f647 100644
--- a/java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java
+++ b/java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java
@@ -26,62 +26,148 @@ import org.apache.qpid.util.concurrent.Condition;
import org.apache.qpid.transport.network.ConnectionBinding;
import org.apache.qpid.transport.network.io.IoAcceptor;
-import org.apache.qpid.transport.network.io.IoTransport;
import org.apache.qpid.transport.util.Logger;
+import org.apache.qpid.transport.util.Waiter;
import junit.framework.TestCase;
-import java.util.Random;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Collections;
+import java.io.IOException;
+
+import static org.apache.qpid.transport.Option.*;
/**
* ConnectionTest
*/
-public class ConnectionTest extends TestCase
+public class ConnectionTest extends TestCase implements SessionListener
{
private static final Logger log = Logger.get(ConnectionTest.class);
private int port;
+ private volatile boolean queue = false;
+ private List<MessageTransfer> messages = new ArrayList<MessageTransfer>();
+ private List<MessageTransfer> incoming = new ArrayList<MessageTransfer>();
+
+ private IoAcceptor _ioa = null;
+
protected void setUp() throws Exception
{
super.setUp();
port = AvailablePortFinder.getNextAvailable(12000);
+ }
- ConnectionDelegate server = new ConnectionDelegate() {
- public void init(Channel ch, ProtocolHeader hdr) {
- ch.getConnection().close();
- }
+ protected void tearDown() throws Exception
+ {
+ if (_ioa != null)
+ {
+ _ioa.close();
+ }
- public SessionDelegate getSessionDelegate() {
- return new SessionDelegate() {};
- }
- public void exception(Throwable t) {
- log.error(t, "exception caught");
- }
- public void closed() {}
- };
+ super.tearDown();
+ }
+
+ public void opened(Session ssn) {}
+
+ public void resumed(Session ssn) {}
+
+ public void message(final Session ssn, MessageTransfer xfr)
+ {
+ if (queue)
+ {
+ messages.add(xfr);
+ ssn.processed(xfr);
+ return;
+ }
- IoAcceptor ioa = new IoAcceptor
- ("localhost", port, new ConnectionBinding(server));
- ioa.start();
+ String body = xfr.getBodyString();
+
+ if (body.startsWith("CLOSE"))
+ {
+ ssn.getConnection().close();
+ }
+ else if (body.startsWith("DELAYED_CLOSE"))
+ {
+ ssn.processed(xfr);
+ new Thread()
+ {
+ public void run()
+ {
+ try
+ {
+ sleep(3000);
+ }
+ catch (InterruptedException e)
+ {
+ throw new RuntimeException(e);
+ }
+ ssn.getConnection().close();
+ }
+ }.start();
+ }
+ else if (body.startsWith("ECHO"))
+ {
+ int id = xfr.getId();
+ ssn.invoke(xfr);
+ ssn.processed(id);
+ }
+ else if (body.startsWith("SINK"))
+ {
+ ssn.processed(xfr);
+ }
+ else if (body.startsWith("DROP"))
+ {
+ // do nothing
+ }
+ else if (body.startsWith("EXCP"))
+ {
+ ExecutionException exc = new ExecutionException();
+ exc.setDescription("intentional exception for testing");
+ ssn.invoke(exc);
+ ssn.close();
+ }
+ else
+ {
+ throw new IllegalArgumentException
+ ("unrecognized message: " + body);
+ }
+ }
+
+ public void exception(Session ssn, SessionException exc)
+ {
+ throw exc;
+ }
+
+ public void closed(Session ssn) {}
+
+ private void send(Session ssn, String msg)
+ {
+ send(ssn, msg, false);
+ }
+
+ private void send(Session ssn, String msg, boolean sync)
+ {
+ ssn.messageTransfer
+ ("xxx", MessageAcceptMode.NONE, MessageAcquireMode.PRE_ACQUIRED,
+ null, msg, sync ? SYNC : NONE);
}
private Connection connect(final Condition closed)
{
- Connection conn = IoTransport.connect("localhost", port, new ConnectionDelegate()
+ Connection conn = new Connection();
+ conn.setConnectionListener(new ConnectionListener()
{
- public SessionDelegate getSessionDelegate()
+ public void opened(Connection conn) {}
+ public void exception(Connection conn, ConnectionException exc)
{
- return new SessionDelegate() {};
+ exc.printStackTrace();
}
- public void exception(Throwable t)
- {
- t.printStackTrace();
- }
- public void closed()
+ public void closed(Connection conn)
{
if (closed != null)
{
@@ -89,27 +175,94 @@ public class ConnectionTest extends TestCase
}
}
});
-
- conn.send(new ProtocolHeader(1, 0, 10));
+ conn.connect("localhost", port, null, "guest", "guest", false);
return conn;
}
+ public void testProtocolNegotiationExceptionOverridesCloseException() throws Exception
+ {
+ // Force os.name to be windows to exercise code in IoReceiver
+ // that looks for the value of os.name
+ System.setProperty("os.name","windows");
+
+ // Start server as 0-9 to froce a ProtocolVersionException
+ startServer(new ProtocolHeader(1, 0, 9));
+
+ Condition closed = new Condition();
+
+ try
+ {
+ connect(closed);
+ fail("ProtocolVersionException expected");
+ }
+ catch (ProtocolVersionException pve)
+ {
+ //Expected code path
+ }
+ catch (Exception e)
+ {
+ fail("ProtocolVersionException expected. Got:" + e.getMessage());
+ }
+ }
+
+ private void startServer()
+ {
+ startServer(new ProtocolHeader(1, 0, 10));
+ }
+
+ private void startServer(final ProtocolHeader protocolHeader)
+ {
+ ConnectionDelegate server = new ServerDelegate()
+ {
+ @Override
+ public void init(Connection conn, ProtocolHeader hdr)
+ {
+ conn.send(protocolHeader);
+ List<Object> utf8 = new ArrayList<Object>();
+ utf8.add("utf8");
+ conn.connectionStart(null, Collections.EMPTY_LIST, utf8);
+ }
+
+ @Override
+ public Session getSession(Connection conn, SessionAttach atc)
+ {
+ Session ssn = super.getSession(conn, atc);
+ ssn.setSessionListener(ConnectionTest.this);
+ return ssn;
+ }
+ };
+
+ try
+ {
+ _ioa = new IoAcceptor("localhost", port, ConnectionBinding.get(server));
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ fail("Unable to start Server for test due to:" + e.getMessage());
+ }
+
+ _ioa.start();
+ }
+
public void testClosedNotificationAndWriteToClosed() throws Exception
{
+ startServer();
+
Condition closed = new Condition();
Connection conn = connect(closed);
+
+ Session ssn = conn.createSession(1);
+ send(ssn, "CLOSE");
+
if (!closed.get(3000))
{
fail("never got notified of connection close");
}
- Channel ch = conn.getChannel(0);
- Session ssn = new Session("test".getBytes());
- ssn.attach(ch);
-
try
{
- ssn.sessionAttach(ssn.getName());
+ conn.connectionCloseOk();
fail("writing to a closed socket succeeded");
}
catch (TransportException e)
@@ -118,4 +271,176 @@ public class ConnectionTest extends TestCase
}
}
+ class FailoverConnectionListener implements ConnectionListener
+ {
+ public void opened(Connection conn) {}
+
+ public void exception(Connection conn, ConnectionException e)
+ {
+ throw e;
+ }
+
+ public void closed(Connection conn)
+ {
+ queue = true;
+ conn.connect("localhost", port, null, "guest", "guest");
+ conn.resume();
+ }
+ }
+
+ class TestSessionListener implements SessionListener
+ {
+ public void opened(Session s) {}
+ public void resumed(Session s) {}
+ public void exception(Session s, SessionException e) {}
+ public void message(Session s, MessageTransfer xfr)
+ {
+ synchronized (incoming)
+ {
+ incoming.add(xfr);
+ incoming.notifyAll();
+ }
+
+ s.processed(xfr);
+ }
+ public void closed(Session s) {}
+ }
+
+ public void testResumeNonemptyReplayBuffer() throws Exception
+ {
+ startServer();
+
+ Connection conn = new Connection();
+ conn.setConnectionListener(new FailoverConnectionListener());
+ conn.connect("localhost", port, null, "guest", "guest");
+ Session ssn = conn.createSession(1);
+ ssn.setSessionListener(new TestSessionListener());
+
+ send(ssn, "SINK 0");
+ send(ssn, "ECHO 1");
+ send(ssn, "ECHO 2");
+
+ ssn.sync();
+
+ String[] msgs = { "DROP 3", "DROP 4", "DROP 5", "CLOSE 6", "SINK 7" };
+ for (String m : msgs)
+ {
+ send(ssn, m);
+ }
+
+ ssn.sync();
+
+ assertEquals(msgs.length, messages.size());
+ for (int i = 0; i < msgs.length; i++)
+ {
+ assertEquals(msgs[i], messages.get(i).getBodyString());
+ }
+
+ queue = false;
+
+ send(ssn, "ECHO 8");
+ send(ssn, "ECHO 9");
+
+ synchronized (incoming)
+ {
+ Waiter w = new Waiter(incoming, 30000);
+ while (w.hasTime() && incoming.size() < 4)
+ {
+ w.await();
+ }
+
+ assertEquals(4, incoming.size());
+ assertEquals("ECHO 1", incoming.get(0).getBodyString());
+ assertEquals(0, incoming.get(0).getId());
+ assertEquals("ECHO 2", incoming.get(1).getBodyString());
+ assertEquals(1, incoming.get(1).getId());
+ assertEquals("ECHO 8", incoming.get(2).getBodyString());
+ assertEquals(0, incoming.get(0).getId());
+ assertEquals("ECHO 9", incoming.get(3).getBodyString());
+ assertEquals(1, incoming.get(1).getId());
+ }
+ }
+
+ public void testResumeEmptyReplayBuffer() throws InterruptedException
+ {
+ startServer();
+
+ Connection conn = new Connection();
+ conn.setConnectionListener(new FailoverConnectionListener());
+ conn.connect("localhost", port, null, "guest", "guest");
+ Session ssn = conn.createSession(1);
+ ssn.setSessionListener(new TestSessionListener());
+
+ send(ssn, "SINK 0");
+ send(ssn, "SINK 1");
+ send(ssn, "DELAYED_CLOSE 2");
+ ssn.sync();
+ Thread.sleep(6000);
+ send(ssn, "SINK 3");
+ ssn.sync();
+ System.out.println(messages);
+ assertEquals(1, messages.size());
+ assertEquals("SINK 3", messages.get(0).getBodyString());
+ }
+
+ public void testFlushExpected() throws InterruptedException
+ {
+ startServer();
+
+ Connection conn = new Connection();
+ conn.connect("localhost", port, null, "guest", "guest");
+ Session ssn = conn.createSession();
+ ssn.sessionFlush(EXPECTED);
+ send(ssn, "SINK 0");
+ ssn.sessionFlush(EXPECTED);
+ send(ssn, "SINK 1");
+ ssn.sync();
+ }
+
+ public void testHeartbeat()
+ {
+ startServer();
+ Connection conn = new Connection();
+ conn.connect("localhost", port, null, "guest", "guest");
+ conn.connectionHeartbeat();
+ conn.close();
+ }
+
+ public void testExecutionExceptionInvoke() throws Exception
+ {
+ startServer();
+
+ Connection conn = new Connection();
+ conn.connect("localhost", port, null, "guest", "guest");
+ Session ssn = conn.createSession();
+ send(ssn, "EXCP 0");
+ Thread.sleep(3000);
+ try
+ {
+ send(ssn, "SINK 1");
+ }
+ catch (SessionException exc)
+ {
+ assertNotNull(exc.getException());
+ }
+ }
+
+ public void testExecutionExceptionSync() throws Exception
+ {
+ startServer();
+
+ Connection conn = new Connection();
+ conn.connect("localhost", port, null, "guest", "guest");
+ Session ssn = conn.createSession();
+ send(ssn, "EXCP 0", true);
+ try
+ {
+ ssn.sync();
+ }
+ catch (SessionException exc)
+ {
+ assertNotNull(exc.getException());
+ }
+ }
+
}
diff --git a/java/common/src/test/java/org/apache/qpid/transport/GenTest.java b/java/common/src/test/java/org/apache/qpid/transport/GenTest.java
new file mode 100644
index 0000000000..512a0a29a6
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/transport/GenTest.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.transport;
+
+import junit.framework.TestCase;
+
+/**
+ * GenTest
+ *
+ */
+
+public class GenTest extends TestCase
+{
+
+ public void testBooleans()
+ {
+ QueueDeclare qd = new QueueDeclare().queue("test-queue").durable(false);
+ assertEquals(qd.getQueue(), "test-queue");
+ assertFalse("durable should be false", qd.getDurable());
+ qd.setDurable(true);
+ assertTrue("durable should be true", qd.getDurable());
+ qd.setDurable(false);
+ assertFalse("durable should be false again", qd.getDurable());
+ }
+
+}
diff --git a/java/common/src/test/java/org/apache/qpid/transport/TestNetworkDriver.java b/java/common/src/test/java/org/apache/qpid/transport/TestNetworkDriver.java
new file mode 100644
index 0000000000..a4c4b59cdd
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/transport/TestNetworkDriver.java
@@ -0,0 +1,122 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.transport;
+
+import java.net.BindException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.qpid.protocol.ProtocolEngine;
+import org.apache.qpid.protocol.ProtocolEngineFactory;
+import org.apache.qpid.ssl.SSLContextFactory;
+
+/**
+ * Test implementation of IoSession, which is required for some tests. Methods not being used are not implemented,
+ * so if this class is being used and some methods are to be used, then please update those.
+ */
+public class TestNetworkDriver implements NetworkDriver
+{
+ private final ConcurrentMap attributes = new ConcurrentHashMap();
+ private String _remoteAddress = "127.0.0.1";
+ private String _localAddress = "127.0.0.1";
+ private int _port = 1;
+
+ public TestNetworkDriver()
+ {
+ }
+
+ public void setRemoteAddress(String string)
+ {
+ this._remoteAddress = string;
+ }
+
+ public void setPort(int _port)
+ {
+ this._port = _port;
+ }
+
+ public int getPort()
+ {
+ return _port;
+ }
+
+ public void bind(int port, InetAddress[] addresses, ProtocolEngineFactory protocolFactory,
+ NetworkDriverConfiguration config, SSLContextFactory sslFactory) throws BindException
+ {
+
+ }
+
+ public SocketAddress getLocalAddress()
+ {
+ return new InetSocketAddress(_localAddress, _port);
+ }
+
+ public SocketAddress getRemoteAddress()
+ {
+ return new InetSocketAddress(_remoteAddress, _port);
+ }
+
+ public void open(int port, InetAddress destination, ProtocolEngine engine, NetworkDriverConfiguration config,
+ SSLContextFactory sslFactory) throws OpenException
+ {
+
+ }
+
+ public void setMaxReadIdle(int idleTime)
+ {
+
+ }
+
+ public void setMaxWriteIdle(int idleTime)
+ {
+
+ }
+
+ public void close()
+ {
+
+ }
+
+ public void flush()
+ {
+
+ }
+
+ public void send(ByteBuffer msg)
+ {
+
+ }
+
+ public void setIdleTimeout(long l)
+ {
+
+ }
+
+ public void setLocalAddress(String localAddress)
+ {
+ _localAddress = localAddress;
+ }
+
+}
diff --git a/java/common/src/test/java/org/apache/qpid/transport/codec/BBEncoderTest.java b/java/common/src/test/java/org/apache/qpid/transport/codec/BBEncoderTest.java
new file mode 100644
index 0000000000..79bf184fe2
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/transport/codec/BBEncoderTest.java
@@ -0,0 +1,47 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.transport.codec;
+
+import junit.framework.TestCase;
+
+import java.nio.ByteBuffer;
+
+/**
+ * BBEncoderTest
+ *
+ */
+
+public class BBEncoderTest extends TestCase
+{
+
+ public void testGrow()
+ {
+ BBEncoder enc = new BBEncoder(4);
+ enc.writeInt32(0xDEADBEEF);
+ ByteBuffer buf = enc.buffer();
+ assertEquals(0xDEADBEEF, buf.getInt(0));
+ enc.writeInt32(0xBEEFDEAD);
+ buf = enc.buffer();
+ assertEquals(0xDEADBEEF, buf.getInt(0));
+ assertEquals(0xBEEFDEAD, buf.getInt(4));
+ }
+
+}
diff --git a/java/common/src/test/java/org/apache/qpid/transport/network/mina/MINANetworkDriverTest.java b/java/common/src/test/java/org/apache/qpid/transport/network/mina/MINANetworkDriverTest.java
new file mode 100644
index 0000000000..5af07d9735
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/transport/network/mina/MINANetworkDriverTest.java
@@ -0,0 +1,491 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.transport.network.mina;
+
+import java.net.BindException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.framing.AMQDataBlock;
+import org.apache.qpid.protocol.ProtocolEngine;
+import org.apache.qpid.protocol.ProtocolEngineFactory;
+import org.apache.qpid.transport.NetworkDriver;
+import org.apache.qpid.transport.OpenException;
+
+public class MINANetworkDriverTest extends TestCase
+{
+
+ private static final String TEST_DATA = "YHALOTHAR";
+ private static final int TEST_PORT = 2323;
+ private NetworkDriver _server;
+ private NetworkDriver _client;
+ private CountingProtocolEngine _countingEngine; // Keeps a count of how many bytes it's read
+ private Exception _thrownEx;
+
+ @Override
+ public void setUp()
+ {
+ _server = new MINANetworkDriver();
+ _client = new MINANetworkDriver();
+ _thrownEx = null;
+ _countingEngine = new CountingProtocolEngine();
+ }
+
+ @Override
+ public void tearDown()
+ {
+ if (_server != null)
+ {
+ _server.close();
+ }
+
+ if (_client != null)
+ {
+ _client.close();
+ }
+ }
+
+ /**
+ * Tests that a socket can't be opened if a driver hasn't been bound
+ * to the port and can be opened if a driver has been bound.
+ * @throws BindException
+ * @throws UnknownHostException
+ * @throws OpenException
+ */
+ public void testBindOpen() throws BindException, UnknownHostException, OpenException
+ {
+ try
+ {
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+ }
+ catch (OpenException e)
+ {
+ _thrownEx = e;
+ }
+
+ assertNotNull("Open should have failed since no engine bound", _thrownEx);
+
+ _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null);
+
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+ }
+
+ /**
+ * Tests that a socket can't be opened after a bound NetworkDriver has been closed
+ * @throws BindException
+ * @throws UnknownHostException
+ * @throws OpenException
+ */
+ public void testBindOpenCloseOpen() throws BindException, UnknownHostException, OpenException
+ {
+ _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null);
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+ _client.close();
+ _server.close();
+
+ try
+ {
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+ }
+ catch (OpenException e)
+ {
+ _thrownEx = e;
+ }
+ assertNotNull("Open should have failed", _thrownEx);
+ }
+
+ /**
+ * Checks that the right exception is thrown when binding a NetworkDriver to an already
+ * existing socket.
+ */
+ public void testBindPortInUse()
+ {
+ try
+ {
+ _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null);
+ }
+ catch (BindException e)
+ {
+ fail("First bind should not fail");
+ }
+
+ try
+ {
+ _client.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null);
+ }
+ catch (BindException e)
+ {
+ _thrownEx = e;
+ }
+ assertNotNull("Second bind should throw BindException", _thrownEx);
+ }
+
+ /**
+ * tests that bytes sent on a network driver are received at the other end
+ *
+ * @throws UnknownHostException
+ * @throws OpenException
+ * @throws InterruptedException
+ * @throws BindException
+ */
+ public void testSend() throws UnknownHostException, OpenException, InterruptedException, BindException
+ {
+ // Open a connection from a counting engine to an echo engine
+ _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null);
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+
+ // Tell the counting engine how much data we're sending
+ _countingEngine.setNewLatch(TEST_DATA.getBytes().length);
+
+ // Send the data and wait for up to 2 seconds to get it back
+ _client.send(ByteBuffer.wrap(TEST_DATA.getBytes()));
+ _countingEngine.getLatch().await(2, TimeUnit.SECONDS);
+
+ // Check what we got
+ assertEquals("Wrong amount of data recieved", TEST_DATA.getBytes().length, _countingEngine.getReadBytes());
+ }
+
+ /**
+ * Opens a connection with a low read idle and check that it gets triggered
+ * @throws BindException
+ * @throws OpenException
+ * @throws UnknownHostException
+ *
+ */
+ public void testSetReadIdle() throws BindException, UnknownHostException, OpenException
+ {
+ // Open a connection from a counting engine to an echo engine
+ _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null);
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+ assertFalse("Reader should not have been idle", _countingEngine.getReaderHasBeenIdle());
+ _client.setMaxReadIdle(1);
+ sleepForAtLeast(1500);
+ assertTrue("Reader should have been idle", _countingEngine.getReaderHasBeenIdle());
+ }
+
+ /**
+ * Opens a connection with a low write idle and check that it gets triggered
+ * @throws BindException
+ * @throws OpenException
+ * @throws UnknownHostException
+ *
+ */
+ public void testSetWriteIdle() throws BindException, UnknownHostException, OpenException
+ {
+ // Open a connection from a counting engine to an echo engine
+ _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null);
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+ assertFalse("Reader should not have been idle", _countingEngine.getWriterHasBeenIdle());
+ _client.setMaxWriteIdle(1);
+ sleepForAtLeast(1500);
+ assertTrue("Reader should have been idle", _countingEngine.getWriterHasBeenIdle());
+ }
+
+
+ /**
+ * Creates and then closes a connection from client to server and checks that the server
+ * has its closed() method called. Then creates a new client and closes the server to check
+ * that the client has its closed() method called.
+ * @throws BindException
+ * @throws UnknownHostException
+ * @throws OpenException
+ */
+ public void testClosed() throws BindException, UnknownHostException, OpenException
+ {
+ // Open a connection from a counting engine to an echo engine
+ EchoProtocolEngineSingletonFactory factory = new EchoProtocolEngineSingletonFactory();
+ _server.bind(TEST_PORT, null, factory, null, null);
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+ EchoProtocolEngine serverEngine = null;
+ while (serverEngine == null)
+ {
+ serverEngine = factory.getEngine();
+ if (serverEngine == null)
+ {
+ try
+ {
+ Thread.sleep(10);
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+ }
+ assertFalse("Server should not have been closed", serverEngine.getClosed());
+ serverEngine.setNewLatch(1);
+ _client.close();
+ try
+ {
+ serverEngine.getLatch().await(2, TimeUnit.SECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ }
+ assertTrue("Server should have been closed", serverEngine.getClosed());
+
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+ _countingEngine.setClosed(false);
+ assertFalse("Client should not have been closed", _countingEngine.getClosed());
+ _countingEngine.setNewLatch(1);
+ _server.close();
+ try
+ {
+ _countingEngine.getLatch().await(2, TimeUnit.SECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ }
+ assertTrue("Client should have been closed", _countingEngine.getClosed());
+ }
+
+ /**
+ * Create a connection and instruct the client to throw an exception when it gets some data
+ * and that the latch gets counted down.
+ * @throws BindException
+ * @throws UnknownHostException
+ * @throws OpenException
+ * @throws InterruptedException
+ */
+ public void testExceptionCaught() throws BindException, UnknownHostException, OpenException, InterruptedException
+ {
+ _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null);
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+
+
+ assertEquals("Exception should not have been thrown", 1,
+ _countingEngine.getExceptionLatch().getCount());
+ _countingEngine.setErrorOnNextRead(true);
+ _countingEngine.setNewLatch(TEST_DATA.getBytes().length);
+ _client.send(ByteBuffer.wrap(TEST_DATA.getBytes()));
+ _countingEngine.getExceptionLatch().await(2, TimeUnit.SECONDS);
+ assertEquals("Exception should have been thrown", 0,
+ _countingEngine.getExceptionLatch().getCount());
+ }
+
+ /**
+ * Opens a connection and checks that the remote address is the one that was asked for
+ * @throws BindException
+ * @throws UnknownHostException
+ * @throws OpenException
+ */
+ public void testGetRemoteAddress() throws BindException, UnknownHostException, OpenException
+ {
+ _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null);
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+ assertEquals(new InetSocketAddress(InetAddress.getLocalHost(), TEST_PORT),
+ _client.getRemoteAddress());
+ }
+
+ private class EchoProtocolEngineSingletonFactory implements ProtocolEngineFactory
+ {
+ EchoProtocolEngine _engine = null;
+
+ public ProtocolEngine newProtocolEngine(NetworkDriver driver)
+ {
+ if (_engine == null)
+ {
+ _engine = new EchoProtocolEngine();
+ _engine.setNetworkDriver(driver);
+ }
+ return getEngine();
+ }
+
+ public EchoProtocolEngine getEngine()
+ {
+ return _engine;
+ }
+ }
+
+ public class CountingProtocolEngine implements ProtocolEngine
+ {
+
+ protected NetworkDriver _driver;
+ public ArrayList<ByteBuffer> _receivedBytes = new ArrayList<ByteBuffer>();
+ private int _readBytes;
+ private CountDownLatch _latch = new CountDownLatch(0);
+ private boolean _readerHasBeenIdle;
+ private boolean _writerHasBeenIdle;
+ private boolean _closed = false;
+ private boolean _nextReadErrors = false;
+ private CountDownLatch _exceptionLatch = new CountDownLatch(1);
+
+ public void closed()
+ {
+ setClosed(true);
+ _latch.countDown();
+ }
+
+ public void setErrorOnNextRead(boolean b)
+ {
+ _nextReadErrors = b;
+ }
+
+ public void setNewLatch(int length)
+ {
+ _latch = new CountDownLatch(length);
+ }
+
+ public long getReadBytes()
+ {
+ return _readBytes;
+ }
+
+ public SocketAddress getRemoteAddress()
+ {
+ if (_driver != null)
+ {
+ return _driver.getRemoteAddress();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public SocketAddress getLocalAddress()
+ {
+ if (_driver != null)
+ {
+ return _driver.getLocalAddress();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public long getWrittenBytes()
+ {
+ return 0;
+ }
+
+ public void readerIdle()
+ {
+ _readerHasBeenIdle = true;
+ }
+
+ public void setNetworkDriver(NetworkDriver driver)
+ {
+ _driver = driver;
+ }
+
+ public void writeFrame(AMQDataBlock frame)
+ {
+
+ }
+
+ public void writerIdle()
+ {
+ _writerHasBeenIdle = true;
+ }
+
+ public void exception(Throwable t)
+ {
+ _exceptionLatch.countDown();
+ }
+
+ public CountDownLatch getExceptionLatch()
+ {
+ return _exceptionLatch;
+ }
+
+ public void received(ByteBuffer msg)
+ {
+ // increment read bytes and count down the latch for that many
+ int bytes = msg.remaining();
+ _readBytes += bytes;
+ for (int i = 0; i < bytes; i++)
+ {
+ _latch.countDown();
+ }
+
+ // Throw an error if we've been asked too, but we can still count
+ if (_nextReadErrors)
+ {
+ throw new RuntimeException("Was asked to error");
+ }
+ }
+
+ public CountDownLatch getLatch()
+ {
+ return _latch;
+ }
+
+ public boolean getWriterHasBeenIdle()
+ {
+ return _writerHasBeenIdle;
+ }
+
+ public boolean getReaderHasBeenIdle()
+ {
+ return _readerHasBeenIdle;
+ }
+
+ public void setClosed(boolean _closed)
+ {
+ this._closed = _closed;
+ }
+
+ public boolean getClosed()
+ {
+ return _closed;
+ }
+
+ }
+
+ private class EchoProtocolEngine extends CountingProtocolEngine
+ {
+
+ public void received(ByteBuffer msg)
+ {
+ super.received(msg);
+ msg.rewind();
+ _driver.send(msg);
+ }
+ }
+
+ public static void sleepForAtLeast(long period)
+ {
+ long start = System.currentTimeMillis();
+ long timeLeft = period;
+ while (timeLeft > 0)
+ {
+ try
+ {
+ Thread.sleep(timeLeft);
+ }
+ catch (InterruptedException e)
+ {
+ // Ignore it
+ }
+ timeLeft = period - (System.currentTimeMillis() - start);
+ }
+ }
+} \ No newline at end of file
diff --git a/java/common/src/test/java/org/apache/qpid/util/FileUtilsTest.java b/java/common/src/test/java/org/apache/qpid/util/FileUtilsTest.java
new file mode 100644
index 0000000000..7eba5f092e
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/util/FileUtilsTest.java
@@ -0,0 +1,612 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.util;
+
+import junit.framework.TestCase;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.List;
+
+public class FileUtilsTest extends TestCase
+{
+ private static final String COPY = "-Copy";
+ private static final String SUB = "-Sub";
+
+ /**
+ * Additional test for the copy method.
+ * Ensures that the directory count did increase by more than 1 after the copy.
+ */
+ public void testCopyFile()
+ {
+ final String TEST_DATA = "FileUtilsTest-testCopy-TestDataTestDataTestDataTestDataTestDataTestData";
+ String fileName = "FileUtilsTest-testCopy";
+ String fileNameCopy = fileName + COPY;
+
+ File[] beforeCopyFileList = null;
+
+ //Create initial file
+ File test = createTestFile(fileName, TEST_DATA);
+
+ try
+ {
+ //Check number of files before copy
+ beforeCopyFileList = test.getAbsoluteFile().getParentFile().listFiles();
+ int beforeCopy = beforeCopyFileList.length;
+
+ //Perform Copy
+ File destination = new File(fileNameCopy);
+ FileUtils.copy(test, destination);
+ //Ensure the JVM cleans up if cleanup failues
+ destination.deleteOnExit();
+
+ //Retrieve counts after copy
+ int afterCopy = test.getAbsoluteFile().getParentFile().listFiles().length;
+
+ int afterCopyFromCopy = new File(fileNameCopy).getAbsoluteFile().getParentFile().listFiles().length;
+
+ // Validate the copy counts
+ assertEquals("The file listing from the original and the copy differ in length.", afterCopy, afterCopyFromCopy);
+ assertEquals("The number of files did not increase.", beforeCopy + 1, afterCopy);
+ assertEquals("The number of files did not increase.", beforeCopy + 1, afterCopyFromCopy);
+
+ //Validate copy
+ // Load content
+ String copiedFileContent = FileUtils.readFileAsString(fileNameCopy);
+ assertEquals(TEST_DATA, copiedFileContent);
+ }
+ finally // Ensure clean
+ {
+ //Clean up
+ assertTrue("Unable to cleanup", FileUtils.deleteFile(fileNameCopy));
+
+ //Check file list after cleanup
+ File[] afterCleanup = new File(test.getAbsoluteFile().getParent()).listFiles();
+ checkFileLists(beforeCopyFileList, afterCleanup);
+
+ //Remove original file
+ assertTrue("Unable to cleanup", test.delete());
+ }
+ }
+
+ /**
+ * Create and Copy the following structure:
+ *
+ * testDirectory --+
+ * +-- testSubDirectory --+
+ * +-- testSubFile
+ * +-- File
+ *
+ * to testDirectory-Copy
+ *
+ * Validate that the file count in the copy is correct and contents of the copied files is correct.
+ */
+ public void testCopyRecursive()
+ {
+ final String TEST_DATA = "FileUtilsTest-testDirectoryCopy-TestDataTestDataTestDataTestDataTestDataTestData";
+ String fileName = "FileUtilsTest-testCopy";
+ String TEST_DIR = "testDirectoryCopy";
+
+ //Create Initial Structure
+ File testDir = new File(TEST_DIR);
+
+ //Check number of files before copy
+ File[] beforeCopyFileList = testDir.getAbsoluteFile().getParentFile().listFiles();
+
+ try
+ {
+ //Create Directories
+ assertTrue("Test directory already exists cannot test.", !testDir.exists());
+
+ if (!testDir.mkdir())
+ {
+ fail("Unable to make test Directory");
+ }
+
+ File testSubDir = new File(TEST_DIR + File.separator + TEST_DIR + SUB);
+ if (!testSubDir.mkdir())
+ {
+ fail("Unable to make test sub Directory");
+ }
+
+ //Create Files
+ createTestFile(testDir.toString() + File.separator + fileName, TEST_DATA);
+ createTestFile(testSubDir.toString() + File.separator + fileName + SUB, TEST_DATA);
+
+ //Ensure the JVM cleans up if cleanup failues
+ testSubDir.deleteOnExit();
+ testDir.deleteOnExit();
+
+ //Perform Copy
+ File copyDir = new File(testDir.toString() + COPY);
+ try
+ {
+ FileUtils.copyRecursive(testDir, copyDir);
+ }
+ catch (FileNotFoundException e)
+ {
+ fail(e.getMessage());
+ }
+ catch (FileUtils.UnableToCopyException e)
+ {
+ fail(e.getMessage());
+ }
+
+ //Validate Copy
+ assertEquals("Copied directory should only have one file and one directory in it.", 2, copyDir.listFiles().length);
+
+ //Validate Copy File Contents
+ String copiedFileContent = FileUtils.readFileAsString(copyDir.toString() + File.separator + fileName);
+ assertEquals(TEST_DATA, copiedFileContent);
+
+ //Validate Name of Sub Directory
+ assertTrue("Expected subdirectory is not a directory", new File(copyDir.toString() + File.separator + TEST_DIR + SUB).isDirectory());
+
+ //Assert that it contains only one item
+ assertEquals("Copied sub directory should only have one directory in it.", 1, new File(copyDir.toString() + File.separator + TEST_DIR + SUB).listFiles().length);
+
+ //Validate content of Sub file
+ copiedFileContent = FileUtils.readFileAsString(copyDir.toString() + File.separator + TEST_DIR + SUB + File.separator + fileName + SUB);
+ assertEquals(TEST_DATA, copiedFileContent);
+ }
+ finally
+ {
+ //Clean up source and copy directory.
+ assertTrue("Unable to cleanup", FileUtils.delete(testDir, true));
+ assertTrue("Unable to cleanup", FileUtils.delete(new File(TEST_DIR + COPY), true));
+
+ //Check file list after cleanup
+ File[] afterCleanup = testDir.getAbsoluteFile().getParentFile().listFiles();
+ checkFileLists(beforeCopyFileList, afterCleanup);
+ }
+ }
+
+ /**
+ * Helper method to create a test file with a string content
+ *
+ * @param fileName The fileName to use in the creation
+ * @param test_data The data to store in the file
+ *
+ * @return The File reference
+ */
+ private File createTestFile(String fileName, String test_data)
+ {
+ File test = new File(fileName);
+
+ try
+ {
+ test.createNewFile();
+ //Ensure the JVM cleans up if cleanup failues
+ test.deleteOnExit();
+ }
+ catch (IOException e)
+ {
+ fail(e.getMessage());
+ }
+
+ BufferedWriter writer = null;
+ try
+ {
+ writer = new BufferedWriter(new FileWriter(test));
+ try
+ {
+ writer.write(test_data);
+ }
+ catch (IOException e)
+ {
+ fail(e.getMessage());
+ }
+ }
+ catch (IOException e)
+ {
+ fail(e.getMessage());
+ }
+ finally
+ {
+ try
+ {
+ if (writer != null)
+ {
+ writer.close();
+ }
+ }
+ catch (IOException e)
+ {
+ fail(e.getMessage());
+ }
+ }
+
+ return test;
+ }
+
+ /** Test that deleteFile only deletes the specified file */
+ public void testDeleteFile()
+ {
+ File test = new File("FileUtilsTest-testDelete");
+ //Record file count in parent directory to check it is not changed by delete
+ String path = test.getAbsolutePath();
+ File[] filesBefore = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles();
+ int fileCountBefore = filesBefore.length;
+
+ try
+ {
+ test.createNewFile();
+ //Ensure the JVM cleans up if cleanup failues
+ test.deleteOnExit();
+ }
+ catch (IOException e)
+ {
+ fail(e.getMessage());
+ }
+
+ assertTrue("File does not exists", test.exists());
+ assertTrue("File is not a file", test.isFile());
+
+ //Check that file creation can be seen on disk
+ int fileCountCreated = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles().length;
+ assertEquals("File creation was no registered", fileCountBefore + 1, fileCountCreated);
+
+ //Perform Delete
+ assertTrue("Unable to cleanup", FileUtils.deleteFile("FileUtilsTest-testDelete"));
+
+ assertTrue("File exists after delete", !test.exists());
+
+ //Check that after deletion the file count is now accurate
+ File[] filesAfter = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles();
+ int fileCountAfter = filesAfter.length;
+ assertEquals("File creation was no registered", fileCountBefore, fileCountAfter);
+
+ checkFileLists(filesBefore, filesAfter);
+ }
+
+ public void testDeleteNonExistentFile()
+ {
+ File test = new File("FileUtilsTest-testDelete-" + System.currentTimeMillis());
+
+ assertTrue("File exists", !test.exists());
+ assertFalse("File is a directory", test.isDirectory());
+
+ assertTrue("Delete Succeeded ", !FileUtils.delete(test, true));
+ }
+
+ public void testDeleteNull()
+ {
+ try
+ {
+ FileUtils.delete(null, true);
+ fail("Delete with null value should throw NPE.");
+ }
+ catch (NullPointerException npe)
+ {
+ // expected path
+ }
+ }
+
+ /**
+ * Given two lists of File arrays ensure they are the same length and all entries in Before are in After
+ *
+ * @param filesBefore File[]
+ * @param filesAfter File[]
+ */
+ private void checkFileLists(File[] filesBefore, File[] filesAfter)
+ {
+ assertNotNull("Before file list cannot be null", filesBefore);
+ assertNotNull("After file list cannot be null", filesAfter);
+
+ assertEquals("File lists are unequal", filesBefore.length, filesAfter.length);
+
+ for (File fileBefore : filesBefore)
+ {
+ boolean found = false;
+
+ for (File fileAfter : filesAfter)
+ {
+ if (fileBefore.getAbsolutePath().equals(fileAfter.getAbsolutePath()))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ assertTrue("File'" + fileBefore.getName() + "' was not in directory afterwards", found);
+ }
+ }
+
+ public void testNonRecursiveNonEmptyDirectoryDeleteFails()
+ {
+ String directoryName = "FileUtilsTest-testRecursiveDelete";
+ File test = new File(directoryName);
+
+ //Record file count in parent directory to check it is not changed by delete
+ String path = test.getAbsolutePath();
+ File[] filesBefore = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles();
+ int fileCountBefore = filesBefore.length;
+
+ assertTrue("Directory exists", !test.exists());
+
+ test.mkdir();
+
+ //Create a file in the directory
+ String fileName = test.getAbsolutePath() + File.separatorChar + "testFile";
+ File subFile = new File(fileName);
+ try
+ {
+ subFile.createNewFile();
+ //Ensure the JVM cleans up if cleanup failues
+ subFile.deleteOnExit();
+ }
+ catch (IOException e)
+ {
+ fail(e.getMessage());
+ }
+ //Ensure the JVM cleans up if cleanup failues
+ // This must be after the subFile as the directory must be empty before
+ // the delete is performed
+ test.deleteOnExit();
+
+ //Try and delete the non-empty directory
+ assertFalse("Non Empty Directory was successfully deleted.", FileUtils.deleteDirectory(directoryName));
+
+ //Check directory is still there
+ assertTrue("Directory was deleted.", test.exists());
+
+ // Clean up
+ assertTrue("Unable to cleanup", FileUtils.delete(test, true));
+
+ //Check that after deletion the file count is now accurate
+ File[] filesAfter = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles();
+ int fileCountAfter = filesAfter.length;
+ assertEquals("File creation was no registered", fileCountBefore, fileCountAfter);
+
+ checkFileLists(filesBefore, filesAfter);
+ }
+
+ /** Test that an empty directory can be deleted with deleteDirectory */
+ public void testEmptyDirectoryDelete()
+ {
+ String directoryName = "FileUtilsTest-testRecursiveDelete";
+ File test = new File(directoryName);
+
+ //Record file count in parent directory to check it is not changed by delete
+ String path = test.getAbsolutePath();
+ File[] filesBefore = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles();
+ int fileCountBefore = filesBefore.length;
+
+ assertTrue("Directory exists", !test.exists());
+
+ test.mkdir();
+ //Ensure the JVM cleans up if cleanup failues
+ test.deleteOnExit();
+
+ //Try and delete the empty directory
+ assertTrue("Non Empty Directory was successfully deleted.", FileUtils.deleteDirectory(directoryName));
+
+ //Check directory is still there
+ assertTrue("Directory was deleted.", !test.exists());
+
+ //Check that after deletion the file count is now accurate
+ File[] filesAfter = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles();
+ int fileCountAfter = filesAfter.length;
+ assertEquals("File creation was no registered", fileCountBefore, fileCountAfter);
+
+ checkFileLists(filesBefore, filesAfter);
+
+ }
+
+ /** Test that deleteDirectory on a non empty directory to complete */
+ public void testNonEmptyDirectoryDelete()
+ {
+ String directoryName = "FileUtilsTest-testRecursiveDelete";
+ File test = new File(directoryName);
+
+ assertTrue("Directory exists", !test.exists());
+
+ //Record file count in parent directory to check it is not changed by delete
+ String path = test.getAbsolutePath();
+ File[] filesBefore = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles();
+ int fileCountBefore = filesBefore.length;
+
+ test.mkdir();
+
+ //Create a file in the directory
+ String fileName = test.getAbsolutePath() + File.separatorChar + "testFile";
+ File subFile = new File(fileName);
+ try
+ {
+ subFile.createNewFile();
+ //Ensure the JVM cleans up if cleanup failues
+ subFile.deleteOnExit();
+ }
+ catch (IOException e)
+ {
+ fail(e.getMessage());
+ }
+
+ // Ensure the JVM cleans up if cleanup failues
+ // This must be after the subFile as the directory must be empty before
+ // the delete is performed
+ test.deleteOnExit();
+
+ //Try and delete the non-empty directory non-recursively
+ assertFalse("Non Empty Directory was successfully deleted.", FileUtils.delete(test, false));
+
+ //Check directory is still there
+ assertTrue("Directory was deleted.", test.exists());
+
+ // Clean up
+ assertTrue("Unable to cleanup", FileUtils.delete(test, true));
+
+ //Check that after deletion the file count is now accurate
+ File[] filesAfter = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles();
+ int fileCountAfter = filesAfter.length;
+ assertEquals("File creation was no registered", fileCountBefore, fileCountAfter);
+
+ checkFileLists(filesBefore, filesAfter);
+
+ }
+
+ /** Test that a recursive delete successeds */
+ public void testRecursiveDelete()
+ {
+ String directoryName = "FileUtilsTest-testRecursiveDelete";
+ File test = new File(directoryName);
+
+ assertTrue("Directory exists", !test.exists());
+
+ //Record file count in parent directory to check it is not changed by delete
+ String path = test.getAbsolutePath();
+ File[] filesBefore = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles();
+ int fileCountBefore = filesBefore.length;
+
+ test.mkdir();
+
+ createSubDir(directoryName, 2, 4);
+
+ //Ensure the JVM cleans up if cleanup failues
+ // This must be after the sub dir creation as the delete order is
+ // recorded and the directory must be empty to be deleted.
+ test.deleteOnExit();
+
+ assertFalse("Non recursive delete was able to directory", FileUtils.delete(test, false));
+
+ assertTrue("File does not exist after non recursive delete", test.exists());
+
+ assertTrue("Unable to cleanup", FileUtils.delete(test, true));
+
+ assertTrue("File exist after recursive delete", !test.exists());
+
+ //Check that after deletion the file count is now accurate
+ File[] filesAfter = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles();
+ int fileCountAfter = filesAfter.length;
+ assertEquals("File creation was no registered", fileCountBefore, fileCountAfter);
+
+ checkFileLists(filesBefore, filesAfter);
+
+ }
+
+ private void createSubDir(String path, int directories, int files)
+ {
+ File directory = new File(path);
+
+ assertTrue("Directory" + path + " does not exists", directory.exists());
+
+ for (int dir = 0; dir < directories; dir++)
+ {
+ String subDirName = path + File.separatorChar + "sub" + dir;
+ File subDir = new File(subDirName);
+
+ subDir.mkdir();
+
+ createSubDir(subDirName, directories - 1, files);
+ //Ensure the JVM cleans up if cleanup failues
+ // This must be after the sub dir creation as the delete order is
+ // recorded and the directory must be empty to be deleted.
+ subDir.deleteOnExit();
+ }
+
+ for (int file = 0; file < files; file++)
+ {
+ String subDirName = path + File.separatorChar + "file" + file;
+ File subFile = new File(subDirName);
+ try
+ {
+ subFile.createNewFile();
+ //Ensure the JVM cleans up if cleanup failues
+ subFile.deleteOnExit();
+ }
+ catch (IOException e)
+ {
+ fail(e.getMessage());
+ }
+ }
+ }
+
+ public static final String SEARCH_STRING = "testSearch";
+
+ /**
+ * Test searchFile(File file, String search) will find a match when it
+ * exists.
+ *
+ * @throws java.io.IOException if unable to perform test setup
+ */
+ public void testSearchSucceed() throws IOException
+ {
+ File _logfile = File.createTempFile("FileUtilsTest-testSearchSucceed", ".out");
+
+ prepareFileForSearchTest(_logfile);
+
+ List<String> results = FileUtils.searchFile(_logfile, SEARCH_STRING);
+
+ assertNotNull("Null result set returned", results);
+
+ assertEquals("Results do not contain expected count", 1, results.size());
+ }
+
+ /**
+ * Test searchFile(File file, String search) will not find a match when the
+ * test string does not exist.
+ *
+ * @throws java.io.IOException if unable to perform test setup
+ */
+ public void testSearchFail() throws IOException
+ {
+ File _logfile = File.createTempFile("FileUtilsTest-testSearchFail", ".out");
+
+ prepareFileForSearchTest(_logfile);
+
+ List<String> results = FileUtils.searchFile(_logfile, "Hello");
+
+ assertNotNull("Null result set returned", results);
+
+ //Validate we only got one message
+ if (results.size() > 0)
+ {
+ System.err.println("Unexpected messages");
+
+ for (String msg : results)
+ {
+ System.err.println(msg);
+ }
+ }
+
+ assertEquals("Results contains data when it was not expected",
+ 0, results.size());
+ }
+
+ /**
+ * Write the SEARCH_STRING in to the given file.
+ *
+ * @param logfile The file to write the SEARCH_STRING into
+ *
+ * @throws IOException if an error occurs
+ */
+ private void prepareFileForSearchTest(File logfile) throws IOException
+ {
+ BufferedWriter writer = new BufferedWriter(new FileWriter(logfile));
+ writer.append(SEARCH_STRING);
+ writer.flush();
+ writer.close();
+ }
+
+}
diff --git a/java/common/src/test/java/org/apache/qpid/util/SerialTest.java b/java/common/src/test/java/org/apache/qpid/util/SerialTest.java
index d3ab817b5d..b2578563e0 100644
--- a/java/common/src/test/java/org/apache/qpid/util/SerialTest.java
+++ b/java/common/src/test/java/org/apache/qpid/util/SerialTest.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import junit.framework.TestCase;
diff --git a/java/common/templates/model/ProtocolVersionListClass.vm b/java/common/templates/model/ProtocolVersionListClass.vm
index 9ac6adfdf5..78605c70ff 100644
--- a/java/common/templates/model/ProtocolVersionListClass.vm
+++ b/java/common/templates/model/ProtocolVersionListClass.vm
@@ -41,12 +41,14 @@ public class ProtocolVersion implements Comparable
{
private final byte _majorVersion;
private final byte _minorVersion;
+ private final String _stringFormat;
public ProtocolVersion(byte majorVersion, byte minorVersion)
{
_majorVersion = majorVersion;
_minorVersion = minorVersion;
+ _stringFormat = _majorVersion+"-"+_minorVersion;
}
public byte getMajorVersion()
@@ -59,6 +61,22 @@ public class ProtocolVersion implements Comparable
return _minorVersion;
}
+ public byte getActualMinorVersion()
+ {
+ return _minorVersion > 90 ? (byte) (_minorVersion / 10) : _minorVersion;
+ }
+
+
+ public byte getRevisionVersion()
+ {
+ return _minorVersion > 90 ? (byte) (_minorVersion % 10) : (byte) 0;
+ }
+
+ public String toString()
+ {
+ return _stringFormat;
+ }
+
public int compareTo(Object o)
{
@@ -131,15 +149,20 @@ public class ProtocolVersion implements Comparable
private static final ProtocolVersion _defaultVersion;
+ public static final ProtocolVersion v0_10 = new ProtocolVersion((byte)0,(byte)10);
+
#foreach( $version in $model.getVersionSet() )
#set( $versionId = "v$version.getMajor()_$version.getMinor()" )
- public static final ProtocolVersion $versionId = new ProtocolVersion((byte)$version.getMajor(),(byte)$version.getMinor());
+ public static final ProtocolVersion $versionId = new ProtocolVersion((byte)$version.getMajor(),(byte)$version.getMinor());
#end
+
static
{
SortedSet<ProtocolVersion> versions = new TreeSet<ProtocolVersion>();
+ versions.add(v0_10);
+ _nameToVersionMap.put("0-10", v0_10);
#foreach( $version in $model.getVersionSet() )
#set( $versionId = "v$version.getMajor()_$version.getMinor()" )
versions.add($versionId);
diff --git a/java/common/templating.py b/java/common/templating.py
index 832b7ecb9c..732e96fa60 100644
--- a/java/common/templating.py
+++ b/java/common/templating.py
@@ -1,3 +1,21 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
class Parser:
diff --git a/java/cpp.async.testprofile b/java/cpp.async.testprofile
deleted file mode 100644
index c7554165f0..0000000000
--- a/java/cpp.async.testprofile
+++ /dev/null
@@ -1,3 +0,0 @@
-broker.version=0-10
-broker=${project.root}/../cpp/src/qpidd --data-dir ${build.data} -t --load-module ${project.root}/../../cppStore/cpp/lib/.libs/libbdbstore.so --auth no
-test.excludesfile=${project.root}/010ExcludeList-store
diff --git a/java/cpp.noprefetch.testprofile b/java/cpp.noprefetch.testprofile
deleted file mode 100644
index 1e4f62dd8c..0000000000
--- a/java/cpp.noprefetch.testprofile
+++ /dev/null
@@ -1,4 +0,0 @@
-broker.version=0-10
-broker=${project.root}/../cpp/src/qpidd --data-dir ${build.data} -t --load-module ${project.root}/../../cppStore/cpp/lib/.libs/libbdbstore.so --auth no
-test.excludesfile=${project.root}/010ExcludeList-noPrefetch
-max_prefetch=0 \ No newline at end of file
diff --git a/java/cpp.testprofile b/java/cpp.testprofile
deleted file mode 100644
index 68ac8b8be8..0000000000
--- a/java/cpp.testprofile
+++ /dev/null
@@ -1,3 +0,0 @@
-broker.version=0-10
-broker=${project.root}/../cpp/src/qpidd --data-dir ${build.data} -t --auth no
-test.excludesfile=${project.root}/010ExcludeList
diff --git a/java/default-longrunning.testprofile b/java/default-longrunning.testprofile
deleted file mode 100644
index 155e78ad0a..0000000000
--- a/java/default-longrunning.testprofile
+++ /dev/null
@@ -1 +0,0 @@
-test.includesfile=${project.root}/08LongRunningList
diff --git a/java/default.testprofile b/java/default.testprofile
deleted file mode 100644
index 7354cbda48..0000000000
--- a/java/default.testprofile
+++ /dev/null
@@ -1,23 +0,0 @@
-broker.version=0-8
-broker=vm
-broker.clean=${project.root}/clean-dir ${build.data}
-broker.ready=Listening on TCP port
-
-java.naming.provider.url=${project.root}/test-provider.properties
-max_prefetch=1000
-
-log=debug
-amqj.logging.level=${log}
-amqj.protocol.logging.level=${log}
-root.logging.level=${log}
-log4j.configuration=file:///${project.root}/log4j-test.xml
-log4j.debug=false
-
-test.excludes=true
-test.excludesfile=${project.root}/08ExcludeList
-test.fork=no
-test.mem=512M
-test=*Test
-haltonfailure=no
-haltonerror=no
-exclude.modules=none
diff --git a/java/distribution/pom.xml b/java/distribution/pom.xml
deleted file mode 100644
index 6acd8e9a85..0000000000
--- a/java/distribution/pom.xml
+++ /dev/null
@@ -1,210 +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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-distribution</artifactId>
- <packaging>jar</packaging>
- <name>Qpid Distribution</name>
- <version>1.0-incubating-M3-SNAPSHOT</version>
-
- <parent>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid</artifactId>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <relativePath>../pom.xml</relativePath>
- </parent>
-
- <properties>
- <topDirectoryLocation>..</topDirectoryLocation>
- <java.source.version>1.5</java.source.version>
- <qpid.version>${pom.version}</qpid.version>
- <qpid.targetDir>${project.build.directory}</qpid.targetDir>
-
- <!-- This is an assembly/distribution pom so no test code exists -->
- <maven.test.skip>true</maven.test.skip>
- </properties>
-
- <repositories>
- <repository>
- <id>repo1.maven.org</id>
- <name>Maven eclipse Repository</name>
- <url>http://repo1.maven.org/eclipse</url>
- </repository>
- </repositories>
-
- <dependencies>
- <dependency>
- <groupId>${pom.groupId}</groupId>
- <artifactId>qpid-broker</artifactId>
- <version>${pom.version}</version>
- <type>jar</type>
- </dependency>
- <dependency>
- <groupId>${pom.groupId}</groupId>
- <artifactId>qpid-client</artifactId>
- <version>${pom.version}</version>
- <type>jar</type>
- </dependency>
- <dependency>
- <groupId>${pom.groupId}.management</groupId>
- <artifactId>org.apache.qpid.management.ui</artifactId>
- <version>${pom.version}</version>
- </dependency>
- </dependencies>
-
- <build>
- <pluginManagement>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>${java.source.version}</source>
- <target>${java.source.version}</target>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-assembly-plugin</artifactId>
- <version>${assembly.version}</version>
- <configuration>
- <descriptors>
- <descriptor>src/main/assembly/bin.xml</descriptor>
- </descriptors>
- <finalName>qpid-${pom.version}</finalName>
- <outputDirectory>${qpid.targetDir}</outputDirectory>
- <tarLongFileMode>gnu</tarLongFileMode>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <configuration>
- <finalName>qpid-incubating</finalName>
- <archive>
- <manifest>
- <addClasspath>true</addClasspath>
- </manifest>
- </archive>
- </configuration>
- </plugin>
- </plugins>
- </pluginManagement>
-
- <plugins>
- <plugin>
- <artifactId>maven-assembly-plugin</artifactId>
- <executions>
- <execution>
- <id>distribution-package</id>
- <phase>package</phase>
- <goals>
- <goal>single</goal>
- </goals>
- <configuration>
- <descriptors>
- <descriptor>src/main/assembly/bin.xml</descriptor>
- <descriptor>src/main/assembly/src.xml</descriptor>
- <descriptor>src/main/assembly/management-eclipse-plugin.xml</descriptor>
- <descriptor>src/main/assembly/management-eclipse-plugin-unix.xml</descriptor>
- </descriptors>
- <finalName>qpid-${pom.version}</finalName>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
-
- <defaultGoal>assembly:assembly</defaultGoal>
- </build>
-
- <profiles>
- <profile>
- <id>tests</id>
-
- <dependencies>
- <dependency>
- <groupId>${pom.groupId}</groupId>
- <artifactId>qpid-broker</artifactId>
- <version>${pom.version}</version>
- <type>jar</type>
- </dependency>
- <dependency>
- <groupId>${pom.groupId}</groupId>
- <artifactId>qpid-broker</artifactId>
- <version>${pom.version}</version>
- <type>test-jar</type>
- </dependency>
- <dependency>
- <groupId>${pom.groupId}</groupId>
- <artifactId>qpid-client</artifactId>
- <version>${pom.version}</version>
- <type>jar</type>
- </dependency>
- <dependency>
- <groupId>${pom.groupId}</groupId>
- <artifactId>qpid-client</artifactId>
- <version>${pom.version}</version>
- <type>test-jar</type>
- </dependency>
- <dependency>
- <groupId>${pom.groupId}</groupId>
- <artifactId>qpid-perftests</artifactId>
- <version>${pom.version}</version>
- <type>test-jar</type>
- </dependency>
- <dependency>
- <groupId>${pom.groupId}</groupId>
- <artifactId>qpid-systests</artifactId>
- <version>${pom.version}</version>
- <type>test-jar</type>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <artifactId>maven-assembly-plugin</artifactId>
- <executions>
- <execution>
- <id>distribution-package</id>
- <phase>package</phase>
- <goals>
- <goal>single</goal>
- </goals>
- <configuration>
- <descriptors>
- <descriptor>src/main/assembly/bin-test.xml</descriptor>
- </descriptors>
- <finalName>qpid-${pom.version}</finalName>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
-
- </profile>
- </profiles>
-
-</project>
diff --git a/java/distribution/src/main/assembly/bin-test.xml b/java/distribution/src/main/assembly/bin-test.xml
deleted file mode 100644
index a9e769e312..0000000000
--- a/java/distribution/src/main/assembly/bin-test.xml
+++ /dev/null
@@ -1,193 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
--->
-<assembly>
- <!-- id typically identifies the "type" (src vs bin etc) of the assembly -->
- <id>java-bin-with-tests</id>
- <includeBaseDirectory>false</includeBaseDirectory>
- <formats>
- <format>tar.gz</format>
- <format>zip</format>
- </formats>
-
- <fileSets>
- <fileSet>
- <directory>src/main/release</directory>
- <outputDirectory>qpid-${qpid.version}</outputDirectory>
- <includes>
- <include>DISCLAIMER</include>
- <include>LICENSE.txt</include>
- <include>NOTICE.txt</include>
- <include>README.txt</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>..</directory>
- <outputDirectory>qpid-${qpid.version}</outputDirectory>
- <includes>
- <include>*.txt</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>src/main/release/etc</directory>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <includes>
- <include>logging.properties</include>
- <include>log4j.properties</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>src/main/release/docs</directory>
- <outputDirectory>qpid-${qpid.version}/docs</outputDirectory>
- <includes>
- <include>RELEASE_NOTES.txt</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>target</directory>
- <outputDirectory>qpid-${qpid.version}/lib</outputDirectory>
- <includes>
- <include>qpid-incubating.jar</include>
- </includes>
- </fileSet>
- </fileSets>
- <files>
- <!-- due to a bug in the assembly plugin (MASSEMBLY-153) you have
- to use decimal numbers to specify fileMode -->
- <file>
- <source>../common/etc/qpid-run.conf</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>qpid-run.conf</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../broker/etc/config.xml</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>config.xml</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../broker/etc/log4j.xml</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>log4j.xml</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../broker/etc/passwd</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>passwd</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../broker/etc/qpid-server.conf</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>qpid-server.conf</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../broker/etc/virtualhosts.xml</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>virtualhosts.xml</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../broker/bin/qpid.start</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>qpid.start</destName>
- <fileMode>493</fileMode>
- </file>
- <file>
- <source>../broker/bin/qpid.stop</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>qpid.stop</destName>
- <fileMode>493</fileMode>
- </file>
- <file>
- <source>../broker/bin/qpid.stopall</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>qpid.stopall</destName>
- <fileMode>493</fileMode>
- </file>
- <file>
- <source>../common/bin/qpid-run</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>qpid-run</destName>
- <fileMode>493</fileMode>
- </file>
- <file>
- <source>../broker/bin/qpid-server</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>qpid-server</destName>
- <fileMode>493</fileMode>
- </file>
- <file>
- <source>../broker/bin/qpid-server.bat</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>qpid-server.bat</destName>
- <fileMode>493</fileMode>
- </file>
- <file>
- <source>../broker/bin/run.bat</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>run.bat</destName>
- <fileMode>493</fileMode>
- </file>
- <file>
- <source>../broker/bin/run.sh</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>run.sh</destName>
- <fileMode>493</fileMode>
- </file>
- <file>
- <source>../broker/bin/runAll</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>runAll</destName>
- <fileMode>493</fileMode>
- </file>
- </files>
- <dependencySets>
- <dependencySet>
- <outputDirectory>qpid-${qpid.version}/lib</outputDirectory>
- <unpack>false</unpack>
- <excludes>
- <exclude>org.apache.qpid:qpid-distribution</exclude>
- <exclude>org.apache.qpid.management:org.apache.qpid.management.ui</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.commands</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.contenttype</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.expressions</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.jobs</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.runtime</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.runtime.compatibility.auth</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.runtime.compatibility.registry</exclude>
- <exclude>org.eclipse.equinox:org.eclipse.equinox.common</exclude>
- <exclude>org.eclipse.equinox:org.eclipse.equinox.preferences</exclude>
- <exclude>org.eclipse.equinox:org.eclipse.equinox.registry</exclude>
- <exclude>org.eclipse.help:org.eclipse.help</exclude>
- <exclude>org.eclipse.jface:org.eclipse.jface</exclude>
- <exclude>org.eclipse.osgi:org.eclipse.osgi</exclude>
- <exclude>org.eclipse.swt:org.eclipse.swt</exclude>
- <exclude>org.eclipse.swt:org.eclipse.swt.win32.win32.x86</exclude>
- <exclude>org.eclipse.ui:org.eclipse.ui</exclude>
- <exclude>org.eclipse.ui:org.eclipse.ui.forms</exclude>
- <exclude>org.eclipse.ui:org.eclipse.ui.workbench</exclude>
- </excludes>
- <scope>runtime</scope>
- </dependencySet>
- </dependencySets>
-</assembly>
diff --git a/java/distribution/src/main/assembly/bin.xml b/java/distribution/src/main/assembly/bin.xml
deleted file mode 100644
index 0461f0f643..0000000000
--- a/java/distribution/src/main/assembly/bin.xml
+++ /dev/null
@@ -1,217 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
--->
-<assembly>
- <!-- id typically identifies the "type" (src vs bin etc) of the assembly -->
- <id>java-bin</id>
- <includeBaseDirectory>false</includeBaseDirectory>
- <formats>
- <format>tar.gz</format>
- <format>zip</format>
- </formats>
-
- <fileSets>
- <fileSet>
- <directory>src/main/release</directory>
- <outputDirectory>qpid-${qpid.version}</outputDirectory>
- <includes>
- <include>DISCLAIMER</include>
- <include>LICENSE.txt</include>
- <include>NOTICE.txt</include>
- <include>README.txt</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>..</directory>
- <outputDirectory>qpid-${qpid.version}</outputDirectory>
- <includes>
- <include>*.txt</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>src/main/release/etc</directory>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <includes>
- <include>logging.properties</include>
- <include>log4j.properties</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>src/main/release/docs</directory>
- <outputDirectory>qpid-${qpid.version}/docs</outputDirectory>
- <includes>
- <include>RELEASE_NOTES.txt</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>target</directory>
- <outputDirectory>qpid-${qpid.version}/lib</outputDirectory>
- <includes>
- <include>qpid-incubating.jar</include>
- </includes>
- </fileSet>
- </fileSets>
- <files>
- <!-- due to a bug in the assembly 2.1 plugin (MASSEMBLY-153) you have
- to use octal numbers to specify fileMode note not valid in 2.2 assembly plugin -->
- <file>
- <source>../common/etc/qpid-run.conf</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>qpid-run.conf</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../broker/etc/config.xml</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>config.xml</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../broker/etc/jmxremote.access</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>jmxremote.access</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../broker/etc/transient_config.xml</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>transient_config.xml</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../broker/etc/persistent_config.xml</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>persistent_config.xml</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../broker/etc/log4j.xml</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>log4j.xml</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../broker/etc/passwd</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>passwd</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../broker/etc/passwdVhost</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>passwdVhost</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../broker/etc/qpid-server.conf</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>qpid-server.conf</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../broker/etc/virtualhosts.xml</source>
- <outputDirectory>qpid-${qpid.version}/etc</outputDirectory>
- <destName>virtualhosts.xml</destName>
- <fileMode>420</fileMode>
- </file>
- <file>
- <source>../broker/bin/qpid.start</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>qpid.start</destName>
- <fileMode>493</fileMode>
- </file>
- <file>
- <source>../broker/bin/qpid.stop</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>qpid.stop</destName>
- <fileMode>493</fileMode>
- </file>
- <file>
- <source>../broker/bin/qpid.stopall</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>qpid.stopall</destName>
- <fileMode>493</fileMode>
- </file>
- <file>
- <source>../common/bin/qpid-run</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>qpid-run</destName>
- <fileMode>493</fileMode>
- </file>
- <file>
- <source>../broker/bin/qpid-server</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>qpid-server</destName>
- <fileMode>493</fileMode>
- </file>
- <file>
- <source>../broker/bin/qpid-server.bat</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>qpid-server.bat</destName>
- <fileMode>493</fileMode>
- </file>
- <file>
- <source>../broker/bin/run.bat</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>run.bat</destName>
- <fileMode>493</fileMode>
- </file>
- <file>
- <source>../broker/bin/run.sh</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>run.sh</destName>
- <fileMode>493</fileMode>
- </file>
- <file>
- <source>../broker/bin/runAll</source>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <destName>runAll</destName>
- <fileMode>493</fileMode>
- </file>
- </files>
- <dependencySets>
- <dependencySet>
- <outputDirectory>qpid-${qpid.version}/lib</outputDirectory>
- <unpack>false</unpack>
- <excludes>
- <exclude>org.apache.qpid:qpid-distribution</exclude>
- <exclude>org.apache.qpid.management:org.apache.qpid.management.ui</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.commands</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.contenttype</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.expressions</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.jobs</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.runtime</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.runtime.compatibility.auth</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.runtime.compatibility.registry</exclude>
- <exclude>org.eclipse.equinox:org.eclipse.equinox.common</exclude>
- <exclude>org.eclipse.equinox:org.eclipse.equinox.preferences</exclude>
- <exclude>org.eclipse.equinox:org.eclipse.equinox.registry</exclude>
- <exclude>org.eclipse.help:org.eclipse.help</exclude>
- <exclude>org.eclipse.jface:org.eclipse.jface</exclude>
- <exclude>org.eclipse.osgi:org.eclipse.osgi</exclude>
- <exclude>org.eclipse.swt:org.eclipse.swt</exclude>
- <exclude>org.eclipse.swt:org.eclipse.swt.win32.win32.x86</exclude>
- <exclude>org.eclipse.ui:org.eclipse.ui</exclude>
- <exclude>org.eclipse.ui:org.eclipse.ui.forms</exclude>
- <exclude>org.eclipse.ui:org.eclipse.ui.workbench</exclude>
- </excludes>
- <scope>runtime</scope>
- </dependencySet>
- </dependencySets>
-</assembly>
diff --git a/java/distribution/src/main/assembly/management-eclipse-plugin-unix.xml b/java/distribution/src/main/assembly/management-eclipse-plugin-unix.xml
deleted file mode 100644
index 1318248b2a..0000000000
--- a/java/distribution/src/main/assembly/management-eclipse-plugin-unix.xml
+++ /dev/null
@@ -1,118 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
--->
-<assembly>
- <!-- id typically identifies the "type" (src vs bin etc) of the assembly -->
- <id>management-console-unix</id>
- <includeBaseDirectory>false</includeBaseDirectory>
- <formats>
- <format>tar.gz</format>
- </formats>
-<!--
- <moduleSets>
- <moduleSet>
- <includes>
- <include>org.apache.qpid.management:org.apache.qpid.management.ui</include>
- </includes>
- <binaries>
- <includeDependencies>true</includeDependencies>
- <unpack>false</unpack>
- </binaries>
- </moduleSet>
- </moduleSets>
- -->
- <fileSets>
- <fileSet>
- <directory>src/main/release</directory>
- <outputDirectory>qpidmc</outputDirectory>
- <includes>
- <include>DISCLAIMER</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>..</directory>
- <outputDirectory>qpidmc</outputDirectory>
- <includes>
- <include>*.txt</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>src/main/release/docs</directory>
- <outputDirectory>qpidmc/docs</outputDirectory>
- <includes>
- <include>RELEASE_NOTES.txt</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>../management/eclipse-plugin/src/main/resources/unix/configuration</directory>
- <outputDirectory>qpidmc/configuration</outputDirectory>
- <includes>
- <include>**</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>../management/eclipse-plugin/src/main/resources</directory>
- <outputDirectory>qpidmc</outputDirectory>
- <includes>
- <include>license.eclipse.txt</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>../management/eclipse-plugin</directory>
- <outputDirectory>qpidmc</outputDirectory>
- <includes>
- <include>README.txt</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>../management/eclipse-plugin/bin</directory>
- <outputDirectory>qpidmc/bin</outputDirectory>
- <includes>
- <include>qpidmc*.sh</include>
- </includes>
- <fileMode>777</fileMode>
- </fileSet>
- </fileSets>
-
- <dependencySets>
- <dependencySet>
- <outputDirectory>qpidmc/eclipse/plugins/org.eclipse.core.runtime.compatibility.registry_3.2.0</outputDirectory>
- <outputFileNameMapping>${artifactId}_${version}/</outputFileNameMapping>
- <unpack>true</unpack>
- <includes>
- <include>org.eclipse.core:org.eclipse.core.runtime.compatibility.registry</include>
- </includes>
- <scope>runtime</scope>
- </dependencySet>
-
- <dependencySet>
- <outputDirectory>qpidmc/eclipse/plugins</outputDirectory>
- <outputFileNameMapping>${artifactId}_${version}.${extension}</outputFileNameMapping>
- <unpack>false</unpack>
- <excludes>
- <exclude>org.apache.qpid:qpid-distribution</exclude>
- </excludes>
- <includes>
- <include>org.eclipse.ui:org.eclipse.ui.forms</include>
- <include>org.apache.qpid.management:org.apache.qpid.management.ui</include>
- </includes>
- <scope>runtime</scope>
- </dependencySet>
-</dependencySets>
-</assembly>
diff --git a/java/distribution/src/main/assembly/management-eclipse-plugin.xml b/java/distribution/src/main/assembly/management-eclipse-plugin.xml
deleted file mode 100644
index 5c109181ff..0000000000
--- a/java/distribution/src/main/assembly/management-eclipse-plugin.xml
+++ /dev/null
@@ -1,157 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
--->
-<assembly>
- <!-- id typically identifies the "type" (src vs bin etc) of the assembly -->
- <id>management-console-win32</id>
- <includeBaseDirectory>false</includeBaseDirectory>
- <formats>
- <format>zip</format>
- </formats>
-<!--
- <moduleSets>
- <moduleSet>
- <includes>
- <include>org.apache.qpid.management:org.apache.qpid.management.ui</include>
- </includes>
- <binaries>
- <includeDependencies>true</includeDependencies>
- <unpack>false</unpack>
- </binaries>
- </moduleSet>
- </moduleSets>
- -->
- <fileSets>
- <fileSet>
- <directory>src/main/release</directory>
- <outputDirectory>qpidmc</outputDirectory>
- <includes>
- <include>DISCLAIMER</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>..</directory>
- <outputDirectory>qpidmc</outputDirectory>
- <includes>
- <include>*.txt</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>src/main/release/docs</directory>
- <outputDirectory>qpidmc/docs</outputDirectory>
- <includes>
- <include>RELEASE_NOTES.txt</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>../management/eclipse-plugin/src/main/resources/win32/configuration</directory>
- <outputDirectory>qpidmc/configuration</outputDirectory>
- <includes>
- <include>**</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>../management/eclipse-plugin/src/main/resources</directory>
- <outputDirectory>qpidmc/eclipse</outputDirectory>
- <includes>
- <include>*.*</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>../management/eclipse-plugin</directory>
- <outputDirectory>qpidmc</outputDirectory>
- <includes>
- <include>README.txt</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>../management/eclipse-plugin/bin</directory>
- <outputDirectory>qpidmc/bin</outputDirectory>
- <fileMode>777</fileMode>
- </fileSet>
- <fileSet>
- <directory>../management/eclipse-plugin/src/main/resources/sasl</directory>
- <outputDirectory>qpidmc/eclipse/plugins/jmxremote.sasl_1.0.1/META-INF</outputDirectory>
- <includes>
- <include>MANIFEST.MF</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>../management/eclipse-plugin/src/main/resources/org.apache.commons.codec</directory>
- <outputDirectory>qpidmc/eclipse/plugins/</outputDirectory>
- </fileSet>
- </fileSets>
-
- <dependencySets>
- <dependencySet>
- <outputDirectory>qpidmc/eclipse/plugins</outputDirectory>
- <outputFileNameMapping>${artifactId}_${version}.${extension}</outputFileNameMapping>
- <unpack>false</unpack>
- <excludes>
- <exclude>org.apache.qpid:qpid-distribution</exclude>
- <exclude>org.apache.qpid:qpid-common</exclude>
- <exclude>org.apache.qpid:qpid-broker</exclude>
- <exclude>org.apache.qpid:qpid-client</exclude>
- <exclude>commons-cli:commons-cli</exclude>
- <exclude>commons-configuration:commons-configuration</exclude>
- <exclude>commons-lang:commons-lang</exclude>
- <exclude>org.apache.mina:mina-filter-ssl</exclude>
- <exclude>org.apache.mina:mina-java5</exclude>
- <exclude>backport-util-concurrent:backport-util-concurrent</exclude>
- <exclude>org.slf4j:slf4j-simple</exclude>
- <exclude>junit:junit</exclude>
- <exclude>org.easymock:easymockclassextension</exclude>
- <exclude>commons-codec:commons-codec</exclude>
- <exclude>org.apache.geronimo.specs:geronimo-jms_1.1_spec</exclude>
- <exclude>commons-collections:commons-collections</exclude>
- <exclude>commons-lang:commons-lang</exclude>
- <exclude>org.apache.mina:mina-core</exclude>
- <exclude>commons-beanutils:commons-beanutils</exclude>
- <exclude>commons-beanutils:commons-beanutils-core</exclude>
- <exclude>commons-digester:commons-digester</exclude>
- <exclude>commons-logging:commons-logging</exclude>
- <exclude>commons-logging:commons-logging-api</exclude>
- <exclude>dom4j:dom4j</exclude>
- <exclude>isorelax:isorelax</exclude>
- <exclude>jaxen:jaxen</exclude>
- <exclude>log4j:log4j</exclude>
- <exclude>msv:msv</exclude>
- <exclude>xalan:xalan</exclude>
- <exclude>xml-apis:xml-apis</exclude>
- <exclude>saxpath:saxpath</exclude>
- <exclude>servletapi:servletapi</exclude>
- <exclude>relaxngDatatype:relaxngDatatype</exclude>
- <exclude>xerces:xercesImpl</exclude>
- <exclude>javax.servlet:servlet-api</exclude>
- <exclude>org.eclipse.core:org.eclipse.core.runtime.compatibility.registry</exclude>
- </excludes>
- <scope>runtime</scope>
- </dependencySet>
- <dependencySet>
- <outputDirectory>qpidmc/eclipse/plugins/org.eclipse.core.runtime.compatibility.registry_3.2.0</outputDirectory>
- <outputFileNameMapping>${artifactId}_${version}/</outputFileNameMapping>
- <unpack>true</unpack>
- <includes>
- <include>org.eclipse.core:org.eclipse.core.runtime.compatibility.registry</include>
- </includes>
- <scope>runtime</scope>
- </dependencySet>
- </dependencySets>
-
-</assembly>
diff --git a/java/distribution/src/main/assembly/src.xml b/java/distribution/src/main/assembly/src.xml
deleted file mode 100644
index 8aa6183b4d..0000000000
--- a/java/distribution/src/main/assembly/src.xml
+++ /dev/null
@@ -1,94 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
--->
-<assembly>
- <!-- id typically identifies the "type" (src vs bin etc) of the assembly -->
- <id>java-src</id>
- <includeBaseDirectory>false</includeBaseDirectory>
- <formats>
- <format>tar.gz</format>
- <format>zip</format>
- </formats>
-
- <fileSets>
- <fileSet>
- <directory>src/main/release</directory>
- <outputDirectory>qpid-${qpid.version}-src</outputDirectory>
- <includes>
- <include>DISCLAIMER</include>
- <include>LICENSE.txt</include>
- <include>licenses/*.*</include>
- <include>NOTICE.txt</include>
- <include>README.txt</include>
- <include>BUILDING.txt</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>..</directory>
- <outputDirectory>qpid-${qpid.version}-src/java</outputDirectory>
- <includes>
- <include>**/*</include>
- </includes>
- <excludes>
- <exclude>build.xml</exclude>
- <exclude>distribution/build.xml</exclude>
- <exclude>benchmark</exclude>
- <exclude>benchmark/**/*</exclude>
- <exclude>**/target</exclude>
- <exclude>**/target/**/*</exclude>
- <exclude>**/build</exclude>
- <exclude>**/build/**/*</exclude>
- <exclude>**/.settings</exclude>
- <exclude>**/.classpath</exclude>
- <exclude>**/.project</exclude>
- <exclude>**/.wtpmodules</exclude>
- <exclude>**/surefire*</exclude>
- <exclude>**/cobertura.ser</exclude>
- <exclude>bin</exclude>
- <exclude>bin/*</exclude>
- <exclude>lib</exclude>
- <exclude>lib/**/*</exclude>
- <exclude>**/var/journal</exclude>
- <exclude>**/build.out*</exclude>
- <exclude>**/eclipse-plugin/bin/**</exclude>
- <exclude>**/eclipse-plugin/plugins/**</exclude>
- <exclude>**/eclipse-plugin/src/main/resources/**</exclude>
- </excludes>
- </fileSet>
- <fileSet>
- <directory>../../gentools</directory>
- <outputDirectory>qpid-${qpid.version}-src/gentools</outputDirectory>
- <includes>
- <include>**/*</include>
- </includes>
- <excludes>
- <exclude>**/build</exclude>
- <exclude>**/build/**/*</exclude>
- <exclude>**/*.class</exclude>
- </excludes>
- </fileSet>
- <fileSet>
- <directory>../../specs</directory>
- <outputDirectory>qpid-${qpid.version}-src/specs</outputDirectory>
- <includes>
- <include>**/*</include>
- </includes>
- </fileSet>
- </fileSets>
-</assembly>
diff --git a/java/distribution/src/main/release/DISCLAIMER b/java/distribution/src/main/release/DISCLAIMER
deleted file mode 100644
index c321113c9e..0000000000
--- a/java/distribution/src/main/release/DISCLAIMER
+++ /dev/null
@@ -1,5 +0,0 @@
-Apache Qpid is an effort undergoing incubation at the Apache Software Foundation (ASF), sponsored by the Apache Incubator PMC.
-
-Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects.
-
-While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF.
diff --git a/java/distribution/src/main/release/LICENSE.txt b/java/distribution/src/main/release/LICENSE.txt
deleted file mode 100755
index 6b0b1270ff..0000000000
--- a/java/distribution/src/main/release/LICENSE.txt
+++ /dev/null
@@ -1,203 +0,0 @@
-
- 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/java/distribution/src/main/release/NOTICE.txt b/java/distribution/src/main/release/NOTICE.txt
deleted file mode 100644
index 82d3dbc632..0000000000
--- a/java/distribution/src/main/release/NOTICE.txt
+++ /dev/null
@@ -1,36 +0,0 @@
-=========================================================================
-== NOTICE file corresponding to the section 4 d of ==
-== the Apache License, Version 2.0, ==
-== in this case for the Apache Qpid distribution. ==
-=========================================================================
-
-This product includes software developed by the Apache Software Foundation
-(http://www.apache.org/).
-
-Please read the LICENSE.txt file present in the root directory of this
-distribution.
-
-
-Aside from contributions to the Apache Qpid project, this software also
-includes (binary only):
-
- - The SAXON XSLT Processor from Michael Kay distributed under the
- Mozilla Public License v1.0, which is available for download at
- http://saxon.sourceforge.net/
-
- - The JUnit regression testing framework written by Erich Gamma
- and Kent Beck and distributed under the Common Public License v1.0.
- JUnit is available for download at
- http://sourceforge.net/projects/junit/
-
- - The Simple Logging Facade For Java (slf4j), Copyright (c)
- 2004-2005 SLF4J.ORG, Copyright (c) 2004-2005 QOS.ch. slf4j is
- licensed under identical terms to the MIT/X11 license and
- available for download at http://www.slf4j.org/
-
- - Software from the Eclipse project. The binaries from this project are
- distributed under the Eclipse Public License and can be donwloaded
- from http://www.eclipse.org/
-
-
-
diff --git a/java/distribution/src/main/release/README.txt b/java/distribution/src/main/release/README.txt
deleted file mode 100644
index 14706170bc..0000000000
--- a/java/distribution/src/main/release/README.txt
+++ /dev/null
@@ -1,104 +0,0 @@
-
-Documentation
---------------
-All of our user documentation for the Qpid Java components can be accessed on our wiki at:
-
-http://cwiki.apache.org/confluence/display/qpid/Qpid+Java+Documentation
-
-This includes a Getting Started Guide and FAQ as well as detailed developer documentation.
-However, here's a VERY quick guide to running the installed Qpid broker, once you have installed it somewhere !
-
-
-Running the Broker
-------------------
-
-To run the broker, set the QPID_HOME environment variable to
-distribution directory and add $QPID_HOME/bin to your PATH. Then run
-the qpid-server shell script or qpid-server.bat batch file to start
-the broker. By default, the broker will use $QPID_HOME/etc to find
-the configuration files. You can supply a custom configuration using
-the -c argument.
-
-For example:
-
-qpid-server -c ~/etc/config.xml
-
-You can get a list of all command line arguments by using the -h argument.
-
-
-Developing
-----------
-
-In order to build Qpid you need Ant 1.6.5. Use ant -p to list the
-available targets. The default ant target, build, creates a working
-development-mode distribution in the build directory. To run the
-scripts in build/bin set QPID_HOME to the build directory and put
-${QPID_HOME}/bin on your PATH. The scripts in that directory include
-the standard ones in the distribution and a number of testing scripts.
-
-
-Running Tests
--------------
-
-The simplest test to ensure everything is working is the "service
-request reply" test. This involves one client that is known as a
-"service provider" and it listens on a well-known queue for
-requests. Another client, known as the "service requester" creates a
-private (temporary) response queue, creates a message with the private
-response queue set as the "reply to" field and then publishes the
-message to the well known service queue. The test allows you to time
-how long it takes to send messages and receive the response back. It
-also allows varying of the message size.
-
-You must start the service provider first:
-
-serviceProvidingClient.sh nop host:port
-
-where host:port is the host and port you are running the broker
-on.
-
-To run the service requester:
-
-serviceRequestingClient.sh nop host:post <count> <bytes>
-
-This requests <count> messages, each of size <bytes>. After
-receiving all the messages the client outputs the rate it achieved.
-
-A more realistic test is the "headers test", which tests the
-performance of routing messages based on message headers to a
-configurable number of clients (e.g. 50). A publisher sends 10000
-messages to each client and waits to receive a message from each
-client when it has received all the messages.
-
-You run the listener processes first:
-
-run_many.sh 10 header "headersListener.sh -host 10.0.0.1 -port 5672"
-
-In this command, the first argument means start 10 processes, the
-second is just a name use in the log files generated and the third
-argument is the command to run. In this case it runs another shell
-script but it could be anything.
-
-Then run the publisher process:
-
-headersPublisher.sh -host 10.0.0.1 -port 5672 10000 10
-
-The last two arguments are: the number of messages to send to each
-client, and the number of clients.
-
-Note that before starting the publisher you should wait about 30
-seconds to ensure all the clients are registered with the broker (you
-can see this from the broker output). Otherwise the numbers will be
-slightly skewed.
-
-A third useful test, which can easily be ported to other JMS
-implementations is the "topic test". It does the same as the headers
-test but using a standard topic (e.g. pub sub).
-
-To run the listeners:
-
-run_many.sh 10 topic "topicListener.sh -host 10.0.0.1 -port 5672"
-
-and to run the publisher:
-
-topicPublisher.sh -host 10.0.0.1 -port 5672 -clients 10 -messages 10000
diff --git a/java/doc/Qpid-architecture.dia b/java/doc/Qpid-architecture.dia
new file mode 100644
index 0000000000..4bdfd2ee93
--- /dev/null
+++ b/java/doc/Qpid-architecture.dia
Binary files differ
diff --git a/java/doc/broker-0.5-network.dia b/java/doc/broker-0.5-network.dia
new file mode 100644
index 0000000000..f30decde4b
--- /dev/null
+++ b/java/doc/broker-0.5-network.dia
Binary files differ
diff --git a/java/doc/broker-0.N-network-phase-1.dia b/java/doc/broker-0.N-network-phase-1.dia
new file mode 100644
index 0000000000..4ac8213b23
--- /dev/null
+++ b/java/doc/broker-0.N-network-phase-1.dia
Binary files differ
diff --git a/java/doc/broker-0.N-state.dia b/java/doc/broker-0.N-state.dia
new file mode 100644
index 0000000000..5ef83a871b
--- /dev/null
+++ b/java/doc/broker-0.N-state.dia
Binary files differ
diff --git a/java/doc/broker-overview.dia b/java/doc/broker-overview.dia
new file mode 100644
index 0000000000..2d943beadf
--- /dev/null
+++ b/java/doc/broker-overview.dia
Binary files differ
diff --git a/java/doc/broker-priority-queue-subscription.dia b/java/doc/broker-priority-queue-subscription.dia
new file mode 100644
index 0000000000..2289899435
--- /dev/null
+++ b/java/doc/broker-priority-queue-subscription.dia
Binary files differ
diff --git a/java/doc/broker-queue-subscription.dia b/java/doc/broker-queue-subscription.dia
new file mode 100644
index 0000000000..d146ad136d
--- /dev/null
+++ b/java/doc/broker-queue-subscription.dia
Binary files differ
diff --git a/java/doc/client-0.5-connection-creation.dia b/java/doc/client-0.5-connection-creation.dia
new file mode 100644
index 0000000000..b7c6d185a1
--- /dev/null
+++ b/java/doc/client-0.5-connection-creation.dia
Binary files differ
diff --git a/java/doc/client-0.5-network-processing.dia b/java/doc/client-0.5-network-processing.dia
new file mode 100644
index 0000000000..acacc4f462
--- /dev/null
+++ b/java/doc/client-0.5-network-processing.dia
Binary files differ
diff --git a/java/doc/client-0.N-network-processing.dia b/java/doc/client-0.N-network-processing.dia
new file mode 100644
index 0000000000..ed2c340969
--- /dev/null
+++ b/java/doc/client-0.N-network-processing.dia
Binary files differ
diff --git a/java/doc/common-0.N-network.dia b/java/doc/common-0.N-network.dia
new file mode 100644
index 0000000000..826ac32e5b
--- /dev/null
+++ b/java/doc/common-0.N-network.dia
Binary files differ
diff --git a/java/doc/network-driver-protocol-engine-sequence.dia b/java/doc/network-driver-protocol-engine-sequence.dia
new file mode 100644
index 0000000000..16cdc7e1dc
--- /dev/null
+++ b/java/doc/network-driver-protocol-engine-sequence.dia
Binary files differ
diff --git a/java/doc/noddy-network-blocks.dia b/java/doc/noddy-network-blocks.dia
new file mode 100644
index 0000000000..06abc109b1
--- /dev/null
+++ b/java/doc/noddy-network-blocks.dia
Binary files differ
diff --git a/java/etc/code-style.xml b/java/etc/code-style.xml
new file mode 100644
index 0000000000..a52b2a0c74
--- /dev/null
+++ b/java/etc/code-style.xml
@@ -0,0 +1,251 @@
+<?xml version="1.0"?>
+<profiles version="10">
+ <profile name="mine" version="10">
+ <setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="1"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
+ <setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="next_line"/>
+ <setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="next_line"/>
+ <setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
+ <setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="next_line"/>
+ <setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="next_line"/>
+ <setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="next_line"/>
+ <setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="next_line"/>
+ <setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="next_line"/>
+ <setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="next_line"/>
+ <setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="next_line"/>
+ <setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="next_line"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines" value="false"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.format_comments" value="true"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
+ <setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
+ <setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
+ <setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
+ <setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
+ <setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
+ <setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
+ <setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
+ <setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
+ <setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
+ <setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
+ <setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
+ <setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
+ <setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
+ <setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
+ <setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
+ <setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
+ <setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
+ <setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
+ <setting id="org.eclipse.jdt.core.formatter.lineSplit" value="80"/>
+ <setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
+ <setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
+ <setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
+ <setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
+ <setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
+ <setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
+ </profile>
+</profiles> \ No newline at end of file
diff --git a/java/etc/coding_standards.xml b/java/etc/coding_standards.xml
index 00b1a9516a..fdb42c1b9c 100644
--- a/java/etc/coding_standards.xml
+++ b/java/etc/coding_standards.xml
@@ -1,117 +1,138 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.1//EN" "http://www.puppycrawl.com/dtds/configuration_1_1.dtd">
-<module name="Checker">
- <!-- Checks package.html defined for all packages. -->
- <module name="PackageHtml"/>
-
- <module name="TreeWalker">
-
- <!-- Whitespace conventions. -->
- <module name="TabCharacter"/>
-
- <!-- License conventions. Checks that the license is included in every file. -->
- <module name="Header">
- <property name="headerFile" value="${checkstyle.header.file}"/>
- </module>
-
- <!-- Coding style conventions. -->
- <module name="com.puppycrawl.tools.checkstyle.checks.coding.PackageDeclarationCheck">
- <property name="severity" value="error"/>
- </module>
-
- <!-- These rules ensure that everything is javadoc'ed. -->
- <!--
- <module name="RequiredRegexp">
- <property name="format" value="&lt;table id=&quot;crc&quot;&gt;&lt;caption&gt;CRC Card&lt;/caption&gt;"/>
- </module>
- -->
-
- <module name="com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocTypeCheck">
- <property name="excludeScope" value="nothing"/>
- <property name="scope" value="private"/>
- <property name="severity" value="error"/>
- <property name="tokens" value="CLASS_DEF, INTERFACE_DEF"/>
- <property name="allowMissingParamTags" value="true"/>
- </module>
-
- <module name="com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocVariableCheck">
- <property name="excludeScope" value="nothing"/>
- <property name="scope" value="private"/>
- <property name="severity" value="error"/>
- </module>
-
- <module name="com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocMethodCheck">
- <property name="allowMissingParamTags" value="false"/>
- <property name="allowMissingReturnTag" value="false"/>
- <property name="allowMissingThrowsTags" value="false"/>
- <property name="allowThrowsTagsForSubclasses" value="false"/>
- <property name="allowUndeclaredRTE" value="true"/>
- <property name="allowMissingJavadoc" value="false"/>
- <property name="allowMissingPropertyJavadoc" value="true"/>
- <property name="excludeScope" value="nothing"/>
- <property name="scope" value="private"/>
- <property name="severity" value="error"/>
- <property name="tokens" value="METHOD_DEF, CTOR_DEF"/>
- </module>
-
- <module name="JavadocStyle">
- <property name="scope" value="private"/>
- <property name="checkHtml" value="false"/>
- <property name="checkFirstSentence" value="true"/>
- <property name="checkEmptyJavadoc" value="true"/>
- </module>
-
- <!-- These rules enforce the conventions for the naming of variables. -->
- <!--
- <module name="com.puppycrawl.tools.checkstyle.checks.naming.ConstantNameCheck">
- <property name="format" value="^log$|^[A-Z](_?[A-Z0-9]+)*$"/>
- <property name="severity" value="error"/>
- </module>
-
- <module name="com.puppycrawl.tools.checkstyle.checks.naming.LocalFinalVariableNameCheck">
- <property name="format" value="^[a-z][a-zA-Z0-9_]*$"/>
- <property name="severity" value="error"/>
- </module>
-
- <module name="com.puppycrawl.tools.checkstyle.checks.naming.LocalVariableNameCheck">
- <property name="format" value="^[a-z][a-zA-Z0-9_]*$"/>
- <property name="severity" value="error"/>
- </module>
-
- <module name="com.puppycrawl.tools.checkstyle.checks.naming.MemberNameCheck">
- <property name="applyToPackage" value="true"/>
- <property name="applyToPrivate" value="true"/>
- <property name="applyToProtected" value="true"/>
- <property name="applyToPublic" value="true"/>
- <property name="format" value="^[a-z][a-zA-Z0-9_]*$"/>
- <property name="severity" value="error"/>
- </module>
-
- <module name="com.puppycrawl.tools.checkstyle.checks.naming.MethodNameCheck">
- <property name="format" value="^[a-z][a-zA-Z0-9_]*$"/>
- <property name="severity" value="error"/>
- </module>
-
- <module name="com.puppycrawl.tools.checkstyle.checks.naming.PackageNameCheck">
- <property name="format" value="^[a-z]+(\.[a-zA-Z_][a-zA-Z0-9_]*)*$"/>
- <property name="severity" value="error"/>
- </module>
-
- <module name="com.puppycrawl.tools.checkstyle.checks.naming.ParameterNameCheck">
- <property name="format" value="^[a-z][a-zA-Z0-9_]*$"/>
- <property name="severity" value="error"/>
- </module>
-
- <module name="com.puppycrawl.tools.checkstyle.checks.naming.StaticVariableNameCheck">
- <property name="format" value="^[a-z][a-zA-Z0-9_]*$"/>
- <property name="severity" value="error"/>
- </module>
-
- <module name="com.puppycrawl.tools.checkstyle.checks.naming.TypeNameCheck">
- <property name="format" value="^[A-Z][a-zA-Z0-9_]*$"/>
- <property name="severity" value="error"/>
- <property name="tokens" value="CLASS_DEF, INTERFACE_DEF"/>
- </module>
- -->
- </module>
-</module>
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.1//EN" "http://www.puppycrawl.com/dtds/configuration_1_1.dtd">
+<module name="Checker">
+ <!-- Checks package.html defined for all packages. -->
+ <module name="PackageHtml"/>
+
+ <module name="TreeWalker">
+
+ <!-- Whitespace conventions. -->
+ <module name="TabCharacter"/>
+
+ <!-- License conventions. Checks that the license is included in every file. -->
+ <module name="Header">
+ <property name="headerFile" value="${checkstyle.header.file}"/>
+ </module>
+
+ <!-- Coding style conventions. -->
+ <module name="com.puppycrawl.tools.checkstyle.checks.coding.PackageDeclarationCheck">
+ <property name="severity" value="error"/>
+ </module>
+
+ <!-- These rules ensure that everything is javadoc'ed. -->
+ <!--
+ <module name="RequiredRegexp">
+ <property name="format" value="&lt;table id=&quot;crc&quot;&gt;&lt;caption&gt;CRC Card&lt;/caption&gt;"/>
+ </module>
+ -->
+
+ <module name="com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocTypeCheck">
+ <property name="excludeScope" value="nothing"/>
+ <property name="scope" value="private"/>
+ <property name="severity" value="error"/>
+ <property name="tokens" value="CLASS_DEF, INTERFACE_DEF"/>
+ <property name="allowMissingParamTags" value="true"/>
+ </module>
+
+ <module name="com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocVariableCheck">
+ <property name="excludeScope" value="nothing"/>
+ <property name="scope" value="private"/>
+ <property name="severity" value="error"/>
+ </module>
+
+ <module name="com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocMethodCheck">
+ <property name="allowMissingParamTags" value="false"/>
+ <property name="allowMissingReturnTag" value="false"/>
+ <property name="allowMissingThrowsTags" value="false"/>
+ <property name="allowThrowsTagsForSubclasses" value="false"/>
+ <property name="allowUndeclaredRTE" value="true"/>
+ <property name="allowMissingJavadoc" value="false"/>
+ <property name="allowMissingPropertyJavadoc" value="true"/>
+ <property name="excludeScope" value="nothing"/>
+ <property name="scope" value="private"/>
+ <property name="severity" value="error"/>
+ <property name="tokens" value="METHOD_DEF, CTOR_DEF"/>
+ </module>
+
+ <module name="JavadocStyle">
+ <property name="scope" value="private"/>
+ <property name="checkHtml" value="false"/>
+ <property name="checkFirstSentence" value="true"/>
+ <property name="checkEmptyJavadoc" value="true"/>
+ </module>
+
+ <!-- These rules enforce the conventions for the naming of variables. -->
+ <!--
+ <module name="com.puppycrawl.tools.checkstyle.checks.naming.ConstantNameCheck">
+ <property name="format" value="^log$|^[A-Z](_?[A-Z0-9]+)*$"/>
+ <property name="severity" value="error"/>
+ </module>
+
+ <module name="com.puppycrawl.tools.checkstyle.checks.naming.LocalFinalVariableNameCheck">
+ <property name="format" value="^[a-z][a-zA-Z0-9_]*$"/>
+ <property name="severity" value="error"/>
+ </module>
+
+ <module name="com.puppycrawl.tools.checkstyle.checks.naming.LocalVariableNameCheck">
+ <property name="format" value="^[a-z][a-zA-Z0-9_]*$"/>
+ <property name="severity" value="error"/>
+ </module>
+
+ <module name="com.puppycrawl.tools.checkstyle.checks.naming.MemberNameCheck">
+ <property name="applyToPackage" value="true"/>
+ <property name="applyToPrivate" value="true"/>
+ <property name="applyToProtected" value="true"/>
+ <property name="applyToPublic" value="true"/>
+ <property name="format" value="^[a-z][a-zA-Z0-9_]*$"/>
+ <property name="severity" value="error"/>
+ </module>
+
+ <module name="com.puppycrawl.tools.checkstyle.checks.naming.MethodNameCheck">
+ <property name="format" value="^[a-z][a-zA-Z0-9_]*$"/>
+ <property name="severity" value="error"/>
+ </module>
+
+ <module name="com.puppycrawl.tools.checkstyle.checks.naming.PackageNameCheck">
+ <property name="format" value="^[a-z]+(\.[a-zA-Z_][a-zA-Z0-9_]*)*$"/>
+ <property name="severity" value="error"/>
+ </module>
+
+ <module name="com.puppycrawl.tools.checkstyle.checks.naming.ParameterNameCheck">
+ <property name="format" value="^[a-z][a-zA-Z0-9_]*$"/>
+ <property name="severity" value="error"/>
+ </module>
+
+ <module name="com.puppycrawl.tools.checkstyle.checks.naming.StaticVariableNameCheck">
+ <property name="format" value="^[a-z][a-zA-Z0-9_]*$"/>
+ <property name="severity" value="error"/>
+ </module>
+
+ <module name="com.puppycrawl.tools.checkstyle.checks.naming.TypeNameCheck">
+ <property name="format" value="^[A-Z][a-zA-Z0-9_]*$"/>
+ <property name="severity" value="error"/>
+ <property name="tokens" value="CLASS_DEF, INTERFACE_DEF"/>
+ </module>
+ -->
+ </module>
+</module>
diff --git a/java/genpom b/java/genpom
new file mode 100755
index 0000000000..e3b89d0568
--- /dev/null
+++ b/java/genpom
@@ -0,0 +1,150 @@
+#!/usr/bin/python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import sys, re, os, mllib, optparse
+
+def die(msg):
+ print >> sys.stderr, msg
+ sys.exit(1)
+
+parser = optparse.OptionParser(usage="usage: %prog [options] JARs ...",
+ description="Generates a pom.")
+parser.add_option("-n", "--name")
+parser.add_option("-g", "--group")
+parser.add_option("-a", "--artifact")
+parser.add_option("-v", "--version")
+parser.add_option("-d", "--description", default="")
+parser.add_option("-u", "--url", default="")
+parser.add_option("-i", "--ignore", action="store_true", help="ignore missing poms")
+parser.add_option("-s", "--search-path", action="append",
+ help="the path to search for poms")
+parser.add_option("-S", "--scope", metavar="ARTIFACT=SCOPE", action="append",
+ default=[],
+ help="specify scope for an artifact")
+parser.add_option("-o", "--output")
+
+opts, jars = parser.parse_args()
+
+if opts.search_path is None:
+ path=["%s/.m2" % os.environ["HOME"]]
+else:
+ path = []
+ for p in opts.search_path:
+ path.extend(p.split(":"))
+
+expanded_path = []
+for p in path:
+ os.path.walk(p, lambda a, d, fs: expanded_path.append(d), None)
+
+if opts.group is None:
+ die("the group option is required")
+
+if opts.version is None:
+ die("the version option is required")
+
+if opts.name is None and opts.artifact is None:
+ die("one of name or artifact must be supplied")
+
+if opts.name is None:
+ opts.name = opts.artifact
+
+if opts.artifact is None:
+ opts.artifact = opts.name
+
+def lookup(pom, attr):
+ nd = pom["project"][attr]
+ if nd is None:
+ nd = pom["project/parent"][attr]
+ if nd is None:
+ return None
+ return nd.text()
+
+def search(path, file):
+ for d in path:
+ f = os.path.join(d, file)
+ if os.path.exists(f):
+ return mllib.xml_parse(f)
+
+scopes = {}
+for s in opts.scope:
+ m = re.match(r"(.*)=(.*)", s)
+ if not m:
+ die("bad scope specifier: %s" % s)
+ scopes[m.group(1)] = m.group(2)
+
+deps = []
+for jar in jars:
+ base, ext = os.path.splitext(os.path.basename(jar))
+ pom = search(expanded_path, "%s.pom" % base)
+ if pom is None:
+ if opts.ignore:
+ continue
+ else:
+ die("unable to locate pom for %s" % jar)
+ group = lookup(pom, "groupId")
+ artifactId = lookup(pom, "artifactId")
+ version = lookup(pom, "version")
+ deps.append("""
+ <dependency>
+ <groupId>%s</groupId>
+ <artifactId>%s</artifactId>
+ <version>%s</version>
+ <scope>%s</scope>
+ </dependency>
+""" % (group, artifactId, version,
+ scopes.get(artifactId, "compile")))
+
+TEMPLATE = """<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd ">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>%(group)s</groupId>
+ <artifactId>%(artifact)s</artifactId>
+ <version>%(version)s</version>
+ <name>%(name)s</name>
+ <url>%(url)s</url>
+ <description>%(description)s</description>
+ <organization>
+ <name>The Apache Software Foundation</name>
+ <url>http://www.apache.org</url>
+ </organization>
+ <licenses>
+ <license>
+ <name>The Apache Software License, Version 2.0</name>
+ <url>/LICENSE.txt</url>
+ </license>
+ </licenses>
+ <dependencies>
+ %(dependencies)s
+ </dependencies>
+</project>
+"""
+
+vars = {}
+vars.update(opts.__dict__)
+vars["dependencies"] = "".join(deps)
+
+if opts.output is None:
+ out = sys.stdout
+else:
+ out = open(opts.output, "w")
+out.write(TEMPLATE % vars)
+out.close()
diff --git a/java/integrationtests/bin/interoptests.py b/java/integrationtests/bin/interoptests.py
index f5a50fc1eb..a883a22a5f 100755
--- a/java/integrationtests/bin/interoptests.py
+++ b/java/integrationtests/bin/interoptests.py
@@ -27,11 +27,11 @@ interop_cases = ["InteropTestCase1DummyRun", "InteropTestCase2BasicP2P", "Intero
interop_command = "java -cp %s org.apache.qpid.test.framework.distributedtesting.Coordinator --xml -e interop -o . -n interop org.apache.qpid.interop.testcases.%s"
# TODO: read this from the ant properties file
-clientlibs = ["qpid-integrationtests-incubating-M3.jar",
- "qpid-junit-toolkit-incubating-M3.jar",
+clientlibs = ["qpid-integrationtests-M4.jar",
+ "qpid-junit-toolkit-M4.jar",
"junit-3.8.1.jar",
- "qpid-systests-incubating-M3.jar",
- "qpid-junit-toolkit-incubating-M3.jar",
+ "qpid-systests-M4.jar",
+ "qpid-junit-toolkit-M4.jar",
"geronimo-jms_1.1_spec-1.0.jar",
"log4j-1.2.12.jar"]
@@ -111,10 +111,10 @@ def start_java(javapath):
for lib in clientlibs:
classpath = classpath + testlibdir+"/"+lib+";"
- classpath = classpath + javapath+"/lib/qpid-incubating.jar"
+ classpath = classpath + javapath+"/lib/qpid-all.jar"
# Add qpid common since the tests need that, classpath hatefulness
- classpath = classpath + ";"+testlibdir+"/qpid-common-incubating-M3.jar"
+ classpath = classpath + ";"+testlibdir+"/qpid-common-M4.jar"
return Popen(["java", "-cp","\""+classpath+"\"",
"org.apache.qpid.test.framework.distributedtesting.TestClient"],
diff --git a/java/integrationtests/pom.xml b/java/integrationtests/pom.xml
deleted file mode 100644
index bbc12d4d00..0000000000
--- a/java/integrationtests/pom.xml
+++ /dev/null
@@ -1,146 +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.
- -->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-integrationtests</artifactId>
- <packaging>jar</packaging>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <name>Qpid Integration Tests</name>
-
- <parent>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid</artifactId>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <relativePath>../pom.xml</relativePath>
- </parent>
-
- <properties>
- <topDirectoryLocation>..</topDirectoryLocation>
- </properties>
-
- <dependencies>
-
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-client</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-systests</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.4.0</version>
- </dependency>
-
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>junit-toolkit</artifactId>
- <scope>compile</scope>
- </dependency>
-
- <!-- JUnit is a compile and runtime dependancy for these tests, not just a test time dependency. -->
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>compile</scope>
- </dependency>
-
- <!-- These need to be included at compile time only, for the retrotranslator verification to find them. -->
- <dependency>
- <groupId>net.sf.retrotranslator</groupId>
- <artifactId>retrotranslator-runtime</artifactId>
- <scope>provided</scope>
- </dependency>
-
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- </plugin>
-
- <!-- Backports the module to Java 1.4. This is done during the packaging phase as a transformation of the Jar. -->
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>retrotranslator-maven-plugin</artifactId>
- <executions>
- <execution>
- <id>retro-intergration-tests</id>
- <phase>package</phase>
- <goals>
- <goal>translate-project</goal>
- </goals>
- <configuration>
- <!--<destdir>${project.build.directory}/retro-classes</destdir>-->
- <destjar>${project.build.directory}/${project.build.finalName}-java14.jar</destjar>
- <verify>${retrotranslator.verify}</verify>
- <verifyClasspath>
- <element>${retrotranslator.1.4-rt-path}</element>
- <element>${retrotranslator.1.4-jce-path}</element>
- <element>${retrotranslator.1.4-jsse-path}</element>
- <element>${retrotranslator.1.4-sasl-path}</element>
- </verifyClasspath>
- <failonwarning>false</failonwarning>
- <classifier>java14</classifier>
- <attach>true</attach>
- </configuration>
- </execution>
- </executions>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-assembly-plugin</artifactId>
- <version>2.2-SNAPSHOT</version>
- <configuration>
- <descriptors>
- <descriptor>jar-with-dependencies.xml</descriptor>
- </descriptors>
- <outputDirectory>target</outputDirectory>
- <workDirectory>target/assembly/work</workDirectory>
- </configuration>
- </plugin>
-
- </plugins>
-
- <resources>
- <!-- Ensure all resources defined in the resources directory are copied into the build jar. -->
- <resource>
- <targetPath></targetPath>
- <filtering>false</filtering>
- <directory>src/resources</directory>
- <includes>
- <include>**/*</include>
- </includes>
- </resource>
- </resources>
-
- </build>
-
-</project>
diff --git a/java/java.testprofile b/java/java.testprofile
deleted file mode 100644
index cef0a10661..0000000000
--- a/java/java.testprofile
+++ /dev/null
@@ -1,5 +0,0 @@
-broker=${project.root}/build/bin/qpid-server
-broker.clean=${project.root}/clean-dir ${build.data}
-broker.ready=Qpid Broker Ready
-
-test.excludesfile=${project.root}/08ExcludeList-nonvm
diff --git a/java/junit-toolkit-maven-plugin/pom.xml b/java/junit-toolkit-maven-plugin/pom.xml
deleted file mode 100644
index a6fe810b6f..0000000000
--- a/java/junit-toolkit-maven-plugin/pom.xml
+++ /dev/null
@@ -1,79 +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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-
- <modelVersion>4.0.0</modelVersion>
-
- <groupId>org.apache.qpid</groupId>
- <artifactId>junit-toolkit-maven-plugin</artifactId>
- <name>junit-toolkit-maven-plugin</name>
- <version>1.0-incubating-M3-SNAPSHOT</version>
-
- <packaging>maven-plugin</packaging>
-
- <parent>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid</artifactId>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <relativePath>../pom.xml</relativePath>
- </parent>
-
- <properties>
- </properties>
-
- <dependencyManagement>
- <dependencies>
-
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.8.1</version>
- </dependency>
-
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.12</version>
- </dependency>
-
- </dependencies>
- </dependencyManagement>
-
- <dependencies>
-
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>junit-toolkit</artifactId>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- </dependency>
-
- <dependency>
- <groupId>org.apache.maven</groupId>
- <artifactId>maven-plugin-api</artifactId>
- <version>2.0.4</version>
- </dependency>
-
- </dependencies>
-
- <build>
- <sourceDirectory>src/main</sourceDirectory>
- <testSourceDirectory>src/unittests</testSourceDirectory>
- </build>
-
-</project>
diff --git a/java/junit-toolkit-maven-plugin/src/main/org/apache/qpid/junit/maven/IsolatedClassLoader.java b/java/junit-toolkit-maven-plugin/src/main/org/apache/qpid/junit/maven/IsolatedClassLoader.java
deleted file mode 100644
index fdae005f00..0000000000
--- a/java/junit-toolkit-maven-plugin/src/main/org/apache/qpid/junit/maven/IsolatedClassLoader.java
+++ /dev/null
@@ -1,113 +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.
- *
- */
-package org.apache.qpid.junit.maven;
-
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * </table>
- *
- * @author Rupert Smith
- *
- * @noinspection CustomClassloader
- */
-public class IsolatedClassLoader extends URLClassLoader
-{
-
- private static final URL[] EMPTY_URL_ARRAY = new URL[0];
- private ClassLoader parent = ClassLoader.getSystemClassLoader();
-
- private Set urls = new HashSet();
-
- private boolean childDelegation = true;
-
- public IsolatedClassLoader()
- {
- super(EMPTY_URL_ARRAY, null);
- }
-
- public IsolatedClassLoader(ClassLoader parent, boolean childDelegation)
- {
- super(EMPTY_URL_ARRAY, parent);
-
- this.childDelegation = childDelegation;
- }
-
- public IsolatedClassLoader(ClassLoader parent)
- {
- super(EMPTY_URL_ARRAY, parent);
- }
-
- public void addURL(URL url)
- {
- // avoid duplicates
- if (!urls.contains(url))
- {
- super.addURL(url);
- urls.add(url);
- }
- }
-
- public synchronized Class loadClass(String name) throws ClassNotFoundException
- {
- Class c;
-
- if (childDelegation)
- {
- c = findLoadedClass(name);
-
- ClassNotFoundException ex = null;
-
- if (c == null)
- {
- try
- {
- c = findClass(name);
- }
- catch (ClassNotFoundException e)
- {
- ex = e;
-
- if (parent != null)
- {
- c = parent.loadClass(name);
- }
- }
- }
-
- if (c == null)
- {
- throw ex;
- }
- }
- else
- {
- c = super.loadClass(name);
- }
-
- return c;
- }
-}
diff --git a/java/junit-toolkit-maven-plugin/src/main/org/apache/qpid/junit/maven/TKTestRunnerMojo.java b/java/junit-toolkit-maven-plugin/src/main/org/apache/qpid/junit/maven/TKTestRunnerMojo.java
deleted file mode 100644
index 36e594d9dc..0000000000
--- a/java/junit-toolkit-maven-plugin/src/main/org/apache/qpid/junit/maven/TKTestRunnerMojo.java
+++ /dev/null
@@ -1,274 +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.
- *
- */
-package org.apache.qpid.junit.maven;
-
-import org.apache.maven.plugin.AbstractMojo;
-
-import java.io.File;
-import java.lang.reflect.Method;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.*;
-
-/**
- * TKTestRunnerMojo is a JUnit test runner plugin for Maven 2. It is intended to be compatible with the surefire
- * plugin (though not all features of that are yet implemented), with some extended capabilities.
- *
- * <p/>This plugin adds the ability to use different JUnit test runners, and to pass arbitrary options to them.
- *
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * </table>
- *
- * @author Rupert Smith
- *
- * @goal tktest
- * @phase test
- * @requiresDependencyResolution test
- */
-public class TKTestRunnerMojo extends AbstractMojo
-{
- private static final BitSet UNRESERVED = new BitSet(256);
-
- /**
- * Set this to 'true' to bypass unit tests entirely. Its use is NOT RECOMMENDED, but quite convenient on occasion.
- *
- * @parameter expression="${maven.test.skip}"
- */
- private boolean skip;
-
- /**
- * The TKTest runner command lines. There are passed directly to the TKTestRunner main method.
- *
- * @parameter
- */
- private Map<String, String> commands = new LinkedHashMap<String, String>();
-
- /**
- * The base directory of the project being tested. This can be obtained in your unit test by
- * System.getProperty("basedir").
- *
- * @parameter expression="${basedir}"
- * @required
- */
- private File basedir;
-
- /**
- * The directory containing generated classes of the project being tested.
- *
- * @parameter expression="${project.build.outputDirectory}"
- * @required
- */
- private File classesDirectory;
-
- /**
- * The directory containing generated test classes of the project being tested.
- *
- * @parameter expression="${project.build.testOutputDirectory}"
- * @required
- */
- private File testClassesDirectory;
-
- /**
- * The classpath elements of the project being tested.
- *
- * @parameter expression="${project.testClasspathElements}"
- * @required
- * @readonly
- */
- private List classpathElements;
-
- /**
- * List of System properties to pass to the tests.
- *
- * @parameter
- */
- private Properties systemProperties;
-
- /**
- * Map of of plugin artifacts.
- *
- * @parameter expression="${plugin.artifactMap}"
- * @required
- * @readonly
- */
- private Map pluginArtifactMap;
-
- /**
- * Map of of project artifacts.
- *
- * @parameter expression="${project.artifactMap}"
- * @required
- * @readonly
- */
- private Map projectArtifactMap;
-
- /**
- * Option to specify the forking mode. Can be "never" (default), "once" or "always".
- * "none" and "pertest" are also accepted for backwards compatibility.
- *
- * @parameter expression="${forkMode}" default-value="once"
- */
- private String forkMode;
-
- /**
- * Option to specify the jvm (or path to the java executable) to use with
- * the forking options. For the default we will assume that java is in the path.
- *
- * @parameter expression="${jvm}"
- * default-value="java"
- */
- private String jvm;
-
- /**
- * The test runner to use.
- *
- * @parameter
- */
- private String testrunner;
-
- /**
- * The additional properties to append to the test runner invocation command line.
- *
- * @parameter
- */
- private Properties testrunnerproperties;
-
- /**
- * The options to pass to all test runner invocation command lines.
- *
- * @parameter
- */
- private String[] testrunneroptions;
-
- /**
- * Implementation of the tktest goal.
- */
- public void execute()
- {
- // Skip these tests if test skipping is turned on.
- if (skip)
- {
- getLog().info("Skipping Tests.");
-
- return;
- }
-
- // Log out the classpath if debugging is on.
- if (getLog().isDebugEnabled())
- {
- getLog().info("Test Classpath :");
-
- for (Object classpathElement1 : classpathElements)
- {
- String classpathElement = (String) classpathElement1;
- getLog().info(" " + classpathElement);
- }
- }
-
- try
- {
- // Create a class loader to load the test runner with. This also gets set as the context loader for this
- // thread, so that all subsequent class loading activity by the test runner or the test code, has the
- // test classes available to it. The system loader is set up for the maven build, which is why a seperate
- // loader needs to be created; in order to inject the test dependencies into it.
- ClassLoader runnerClassLoader = createClassLoader(classpathElements, ClassLoader.getSystemClassLoader(), true);
- Thread.currentThread().setContextClassLoader(runnerClassLoader);
-
- // Load the test runner implementation that will be used to run the tests.
- if ((testrunner == null) || "".equals(testrunner))
- {
- testrunner = "org.apache.qpid.junit.extensions.TKTestRunner";
- }
-
- Class testRunnerClass = Class.forName(testrunner, false, runnerClassLoader);
- Method run = testRunnerClass.getMethod("main", String[].class);
-
- // Concatenate all of the options to pass on the command line to the test runner.
- String preOptions = "";
-
- for (String option : testrunneroptions)
- {
- preOptions += option + " ";
- }
-
- // Concatenate all of the additional properties as name=value pairs on the command line.
- String nvPairs = "";
-
- if (testrunnerproperties != null)
- {
- for (Object objKey : testrunnerproperties.keySet())
- {
- String key = (String) objKey;
- String value = testrunnerproperties.getProperty(key);
-
- nvPairs = key + "=" + value + " ";
- }
- }
-
- // Pass each of the test runner command lines in turn to the toolkit test runner.
- // The command line is made up of the options, the command specific command line, then the trailing
- // name=value pairs.
- for (String testName : commands.keySet())
- {
- String commandLine = preOptions + " " + commands.get(testName) + " " + nvPairs;
- getLog().info("commandLine = " + commandLine);
-
- // Tokenize the command line on white space, into an array of string components.
- String[] tokenizedCommandLine = commandLine.split("\\s+");
-
- // Run the tests.
- run.invoke(testRunnerClass, new Object[] { tokenizedCommandLine });
- }
- }
- catch (Exception e)
- {
- getLog().error("There was an exception: " + e.getMessage(), e);
- }
- }
-
- private static ClassLoader createClassLoader(List classPathUrls, ClassLoader parent, boolean childDelegation)
- throws MalformedURLException
- {
- List urls = new ArrayList();
-
- for (Iterator i = classPathUrls.iterator(); i.hasNext();)
- {
- String url = (String) i.next();
-
- if (url != null)
- {
- File f = new File(url);
- urls.add(f.toURL());
- }
- }
-
- IsolatedClassLoader classLoader = new IsolatedClassLoader(parent, childDelegation);
-
- for (Iterator iter = urls.iterator(); iter.hasNext();)
- {
- URL url = (URL) iter.next();
- classLoader.addURL(url);
- }
-
- return classLoader;
- }
-}
diff --git a/java/junit-toolkit-maven-plugin/src/main/org/apache/qpid/junit/maven/TKTestScriptGenMojo.java b/java/junit-toolkit-maven-plugin/src/main/org/apache/qpid/junit/maven/TKTestScriptGenMojo.java
deleted file mode 100644
index adbe527e5e..0000000000
--- a/java/junit-toolkit-maven-plugin/src/main/org/apache/qpid/junit/maven/TKTestScriptGenMojo.java
+++ /dev/null
@@ -1,148 +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.
- *
- */
-package org.apache.qpid.junit.maven;
-
-import org.apache.maven.plugin.AbstractMojo;
-import org.apache.maven.plugin.MojoExecutionException;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.Writer;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Properties;
-
-/**
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * </table>
- *
- * @author Rupert Smith
- * @goal tkscriptgen
- * @phase test
- * @execute phase="test"
- * @requiresDependencyResolution test
- */
-public class TKTestScriptGenMojo extends AbstractMojo
-{
- private static final String _scriptLanguage = "#!/bin/bash\n\n";
-
- private static final String _javaOptArgParser =
- "# Parse arguements taking all - prefixed args as JAVA_OPTS\n" + "for arg in \"$@\"; do\n"
- + " if [[ $arg == -java:* ]]; then\n" + " JAVA_OPTS=\"${JAVA_OPTS}-`echo $arg|cut -d ':' -f 2` \"\n"
- + " else\n" + " ARGS=\"${ARGS}$arg \"\n" + " fi\n" + "done\n\n";
-
- /**
- * Where to write out the scripts.
- *
- * @parameter
- */
- private String scriptOutDirectory;
-
- /**
- * The all-in-one test jar location.
- *
- * @parameter
- */
- private String testJar;
-
- /**
- * The system properties to pass to java runtime.
- *
- * @parameter
- */
- private Properties systemproperties;
-
- /**
- * The TKTest runner command lines. There are passed directly to the TKTestRunner main method.
- *
- * @parameter
- */
- private Map<String, String> commands = new LinkedHashMap<String, String>();
-
- /**
- * Implementation of the tkscriptgen goal.
- *
- * @throws MojoExecutionException
- */
- public void execute() throws MojoExecutionException
- {
- // Turn each of the test runner command lines into a script.
- for (String testName : commands.keySet())
- {
- String testOptions = commands.get(testName);
- String commandLine = "java ";
-
- String logdir = null;
-
- for (Object key : systemproperties.keySet())
- {
- String keyString = (String) key;
- String value = systemproperties.getProperty(keyString);
-
- if (keyString.equals("logdir"))
- {
- logdir = value;
- }
- else
- {
- if (keyString.startsWith("-X"))
- {
- commandLine += keyString + value + " ";
- }
- else
- {
- commandLine += "-D" + keyString + "=" + value + " ";
- }
- }
- }
-
- commandLine +=
- "${JAVA_OPTS} -cp " + testJar + " org.apache.qpid.junit.extensions.TKTestRunner " + testOptions + " ${ARGS}";
-
- getLog().info("Generating Script for test: " + testName);
- getLog().debug(commandLine);
-
- String fileName = scriptOutDirectory + "/" + testName + ".sh";
-
- try
- {
- File scriptFile = new File(fileName);
- Writer scriptWriter = new FileWriter(scriptFile);
- scriptWriter.write(_scriptLanguage);
- scriptWriter.write(_javaOptArgParser);
- if (logdir != null)
- {
- scriptWriter.write("mkdir -p " + logdir + "\n");
- }
-
- scriptWriter.write(commandLine);
- scriptWriter.flush();
- scriptWriter.close();
- }
- catch (IOException e)
- {
- getLog().error("Failed to write: " + fileName);
- }
- }
- }
-}
diff --git a/java/junit-toolkit/pom.xml b/java/junit-toolkit/pom.xml
deleted file mode 100644
index c5f0d75a74..0000000000
--- a/java/junit-toolkit/pom.xml
+++ /dev/null
@@ -1,100 +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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <groupId>org.apache.qpid</groupId>
- <artifactId>junit-toolkit</artifactId>
- <name>junit-toolkit</name>
- <version>1.0-incubating-M3-SNAPSHOT</version>
-
- <packaging>jar</packaging>
-
- <parent>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid</artifactId>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <relativePath>../pom.xml</relativePath>
- </parent>
-
- <properties>
- <topDirectoryLocation>..</topDirectoryLocation>
- </properties>
-
- <dependencyManagement>
- <dependencies>
-
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.8.1</version>
- </dependency>
-
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.12</version>
- </dependency>
-
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <version>1.4.0</version>
- </dependency>
-
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.4.0</version>
- </dependency>
-
- </dependencies>
- </dependencyManagement>
-
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- </dependency>
-
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <version>1.4.0</version>
- </dependency>
-
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.4.0</version>
- </dependency>
-
- </dependencies>
-
- <build>
- <sourceDirectory>src/main</sourceDirectory>
- <testSourceDirectory>src/unittests</testSourceDirectory>
- </build>
-
-</project>
diff --git a/java/junit-toolkit/src/main/org/apache/qpid/junit/concurrency/package.html b/java/junit-toolkit/src/main/org/apache/qpid/junit/concurrency/package.html
index 4264367690..904fd0fd05 100644
--- a/java/junit-toolkit/src/main/org/apache/qpid/junit/concurrency/package.html
+++ b/java/junit-toolkit/src/main/org/apache/qpid/junit/concurrency/package.html
@@ -1,7 +1,28 @@
-<html>
-<body>
-Contains code to assist in testing concurrency issues using coordinated threads to present code under test with
-oportunities to expose concurrency bugs. Some example concurrency bugs that may be tested using these techniques are
-race conditions, dead locks, live locks, dirty reads, phantom reads, non repeatable reads and so on.
-</body>
-</html> \ No newline at end of file
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<html>
+<body>
+Contains code to assist in testing concurrency issues using coordinated threads to present code under test with
+oportunities to expose concurrency bugs. Some example concurrency bugs that may be tested using these techniques are
+race conditions, dead locks, live locks, dirty reads, phantom reads, non repeatable reads and so on.
+</body>
+</html>
diff --git a/java/junit-toolkit/src/main/org/apache/qpid/junit/extensions/listeners/package.html b/java/junit-toolkit/src/main/org/apache/qpid/junit/extensions/listeners/package.html
index 326d6e176e..15acc02ab1 100644
--- a/java/junit-toolkit/src/main/org/apache/qpid/junit/extensions/listeners/package.html
+++ b/java/junit-toolkit/src/main/org/apache/qpid/junit/extensions/listeners/package.html
@@ -1,6 +1,27 @@
-<html>
-<body>
-Listners for test statistics are defined in this package. At the moment there is only one listener which writes all test
-statistics out to a CSV (comma seperated values) file which can be loaded by most spread sheets.
-</body>
-</html> \ No newline at end of file
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<html>
+<body>
+Listners for test statistics are defined in this package. At the moment there is only one listener which writes all test
+statistics out to a CSV (comma seperated values) file which can be loaded by most spread sheets.
+</body>
+</html>
diff --git a/java/junit-toolkit/src/main/org/apache/qpid/junit/extensions/package.html b/java/junit-toolkit/src/main/org/apache/qpid/junit/extensions/package.html
index 091dcce08e..4cab8d936a 100644
--- a/java/junit-toolkit/src/main/org/apache/qpid/junit/extensions/package.html
+++ b/java/junit-toolkit/src/main/org/apache/qpid/junit/extensions/package.html
@@ -1,12 +1,33 @@
-<html>
-<body>
-Basic JUnit is enahanced with test runners to run tests repeatedly, simultaneously in many threads and with increasing
-test sizes for asymptotic performance measurements. There are features to measure the time and amount of memory that
-tests use as well as to record the asymptotic test size parameters. There are some utilities to write these test
-statistics to various file formats too and these can be found in the listeners package.
-
-</p>The main test runner class is TKTestRunner which can be called with command line parameters to specify how tests
-should be run.
-
-</body>
-</html> \ No newline at end of file
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<html>
+<body>
+Basic JUnit is enahanced with test runners to run tests repeatedly, simultaneously in many threads and with increasing
+test sizes for asymptotic performance measurements. There are features to measure the time and amount of memory that
+tests use as well as to record the asymptotic test size parameters. There are some utilities to write these test
+statistics to various file formats too and these can be found in the listeners package.
+
+</p>The main test runner class is TKTestRunner which can be called with command line parameters to specify how tests
+should be run.
+
+</body>
+</html>
diff --git a/java/junit-toolkit/src/main/org/apache/qpid/junit/extensions/util/package.html b/java/junit-toolkit/src/main/org/apache/qpid/junit/extensions/util/package.html
index cbf45fe295..f39b892e2d 100644
--- a/java/junit-toolkit/src/main/org/apache/qpid/junit/extensions/util/package.html
+++ b/java/junit-toolkit/src/main/org/apache/qpid/junit/extensions/util/package.html
@@ -1,6 +1,27 @@
-<html>
-<body>
-Provides some helper classes. ContextualProperties allows a hierarchy of properties to be used in properties file with
-default overrides. SizeOf takes memeory measurements by stabilizing the garbage collector.
-</body>
-</html> \ No newline at end of file
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<html>
+<body>
+Provides some helper classes. ContextualProperties allows a hierarchy of properties to be used in properties file with
+default overrides. SizeOf takes memeory measurements by stabilizing the garbage collector.
+</body>
+</html>
diff --git a/java/lib/bnd-0.0.249.jar b/java/lib/bnd-0.0.249.jar
new file mode 100644
index 0000000000..7d216ea9e0
--- /dev/null
+++ b/java/lib/bnd-0.0.249.jar
Binary files differ
diff --git a/java/lib/cobertura/README.txt b/java/lib/cobertura/README.txt
new file mode 100644
index 0000000000..8e4cc09a80
--- /dev/null
+++ b/java/lib/cobertura/README.txt
@@ -0,0 +1,10 @@
+Download the cobertura binary from the following location:
+
+http://cobertura.sourceforge.net/download.html
+
+
+Unpack it into the cobertura (this) directory with tar --strip-path 1 -xf.
+This should leave you with cobertura.jar in qpid/java/lib/cobertura.
+
+Run "ant cover-test coverage-report" to generate coverage report.
+
diff --git a/java/lib/com.ibm.icu-3.4.4.jar b/java/lib/com.ibm.icu-3.4.4.jar
deleted file mode 100644
index 9df503a2a3..0000000000
--- a/java/lib/com.ibm.icu-3.4.4.jar
+++ /dev/null
Binary files differ
diff --git a/java/lib/com.ibm.icu_3.8.1.v20080530.jar b/java/lib/com.ibm.icu_3.8.1.v20080530.jar
new file mode 100644
index 0000000000..1d8a0a0997
--- /dev/null
+++ b/java/lib/com.ibm.icu_3.8.1.v20080530.jar
Binary files differ
diff --git a/java/lib/commons-beanutils-core-1.8.0.jar b/java/lib/commons-beanutils-core-1.8.0.jar
new file mode 100644
index 0000000000..87c15f4565
--- /dev/null
+++ b/java/lib/commons-beanutils-core-1.8.0.jar
Binary files differ
diff --git a/java/lib/commons-configuration-1.2.jar b/java/lib/commons-configuration-1.2.jar
deleted file mode 100644
index 574d0ac789..0000000000
--- a/java/lib/commons-configuration-1.2.jar
+++ /dev/null
Binary files differ
diff --git a/java/lib/commons-configuration-1.6.jar b/java/lib/commons-configuration-1.6.jar
new file mode 100644
index 0000000000..2d4689a1b8
--- /dev/null
+++ b/java/lib/commons-configuration-1.6.jar
Binary files differ
diff --git a/java/lib/commons-digester-1.8.1.jar b/java/lib/commons-digester-1.8.1.jar
new file mode 100644
index 0000000000..7abda9696a
--- /dev/null
+++ b/java/lib/commons-digester-1.8.1.jar
Binary files differ
diff --git a/java/lib/commons-pool-1.4.jar b/java/lib/commons-pool-1.4.jar
new file mode 100644
index 0000000000..d6bc185450
--- /dev/null
+++ b/java/lib/commons-pool-1.4.jar
Binary files differ
diff --git a/java/lib/core-3.1.1.jar b/java/lib/core-3.1.1.jar
new file mode 100644
index 0000000000..ae0b635867
--- /dev/null
+++ b/java/lib/core-3.1.1.jar
Binary files differ
diff --git a/java/lib/derby-10.3.2.1.jar b/java/lib/derby-10.3.2.1.jar
new file mode 100644
index 0000000000..76ada492fd
--- /dev/null
+++ b/java/lib/derby-10.3.2.1.jar
Binary files differ
diff --git a/java/lib/geronimo-servlet_2.5_spec-1.2.jar b/java/lib/geronimo-servlet_2.5_spec-1.2.jar
new file mode 100644
index 0000000000..00a2010036
--- /dev/null
+++ b/java/lib/geronimo-servlet_2.5_spec-1.2.jar
Binary files differ
diff --git a/java/lib/javassist.jar b/java/lib/javassist.jar
new file mode 100644
index 0000000000..a6bde77812
--- /dev/null
+++ b/java/lib/javassist.jar
Binary files differ
diff --git a/java/lib/jetty-6.1.14.jar b/java/lib/jetty-6.1.14.jar
new file mode 100644
index 0000000000..3e67d1e19e
--- /dev/null
+++ b/java/lib/jetty-6.1.14.jar
Binary files differ
diff --git a/java/lib/jetty-util-6.1.14.jar b/java/lib/jetty-util-6.1.14.jar
new file mode 100644
index 0000000000..7acc988655
--- /dev/null
+++ b/java/lib/jetty-util-6.1.14.jar
Binary files differ
diff --git a/java/lib/jline-0.9.94.jar b/java/lib/jline-0.9.94.jar
new file mode 100644
index 0000000000..dafca7c46e
--- /dev/null
+++ b/java/lib/jline-0.9.94.jar
Binary files differ
diff --git a/java/lib/jsp-2.1.jar b/java/lib/jsp-2.1.jar
new file mode 100644
index 0000000000..bfdb566c13
--- /dev/null
+++ b/java/lib/jsp-2.1.jar
Binary files differ
diff --git a/java/lib/jsp-api-2.1.jar b/java/lib/jsp-api-2.1.jar
new file mode 100644
index 0000000000..ac3a7a8f7e
--- /dev/null
+++ b/java/lib/jsp-api-2.1.jar
Binary files differ
diff --git a/java/lib/junit-4.4.jar b/java/lib/junit-4.4.jar
new file mode 100644
index 0000000000..649b0b327f
--- /dev/null
+++ b/java/lib/junit-4.4.jar
Binary files differ
diff --git a/java/lib/jython-2.5.0.jar b/java/lib/jython-2.5.0.jar
new file mode 100644
index 0000000000..f8fc553ae7
--- /dev/null
+++ b/java/lib/jython-2.5.0.jar
Binary files differ
diff --git a/java/lib/muse-core-2.2.0.jar b/java/lib/muse-core-2.2.0.jar
new file mode 100644
index 0000000000..674ec26f58
--- /dev/null
+++ b/java/lib/muse-core-2.2.0.jar
Binary files differ
diff --git a/java/lib/muse-platform-mini-2.2.0.jar b/java/lib/muse-platform-mini-2.2.0.jar
new file mode 100644
index 0000000000..1782083231
--- /dev/null
+++ b/java/lib/muse-platform-mini-2.2.0.jar
Binary files differ
diff --git a/java/lib/muse-util-2.2.0.jar b/java/lib/muse-util-2.2.0.jar
new file mode 100644
index 0000000000..8bb7348180
--- /dev/null
+++ b/java/lib/muse-util-2.2.0.jar
Binary files differ
diff --git a/java/lib/muse-util-qname-2.2.0.jar b/java/lib/muse-util-qname-2.2.0.jar
new file mode 100644
index 0000000000..af0c76ece4
--- /dev/null
+++ b/java/lib/muse-util-qname-2.2.0.jar
Binary files differ
diff --git a/java/lib/muse-util-xml-2.2.0.jar b/java/lib/muse-util-xml-2.2.0.jar
new file mode 100644
index 0000000000..016b303c62
--- /dev/null
+++ b/java/lib/muse-util-xml-2.2.0.jar
Binary files differ
diff --git a/java/lib/muse-wsa-soap-2.2.0.jar b/java/lib/muse-wsa-soap-2.2.0.jar
new file mode 100644
index 0000000000..f83322beac
--- /dev/null
+++ b/java/lib/muse-wsa-soap-2.2.0.jar
Binary files differ
diff --git a/java/lib/muse-wsdm-muws-adv-api-2.2.0.jar b/java/lib/muse-wsdm-muws-adv-api-2.2.0.jar
new file mode 100644
index 0000000000..ba3bf4aa40
--- /dev/null
+++ b/java/lib/muse-wsdm-muws-adv-api-2.2.0.jar
Binary files differ
diff --git a/java/lib/muse-wsdm-muws-adv-impl-2.2.0.jar b/java/lib/muse-wsdm-muws-adv-impl-2.2.0.jar
new file mode 100644
index 0000000000..780a20f474
--- /dev/null
+++ b/java/lib/muse-wsdm-muws-adv-impl-2.2.0.jar
Binary files differ
diff --git a/java/lib/muse-wsdm-muws-api-2.2.0.jar b/java/lib/muse-wsdm-muws-api-2.2.0.jar
new file mode 100644
index 0000000000..2a0cab200a
--- /dev/null
+++ b/java/lib/muse-wsdm-muws-api-2.2.0.jar
Binary files differ
diff --git a/java/lib/muse-wsdm-muws-impl-2.2.0.jar b/java/lib/muse-wsdm-muws-impl-2.2.0.jar
new file mode 100644
index 0000000000..a9954bb27e
--- /dev/null
+++ b/java/lib/muse-wsdm-muws-impl-2.2.0.jar
Binary files differ
diff --git a/java/lib/muse-wsdm-wef-api-2.2.0.jar b/java/lib/muse-wsdm-wef-api-2.2.0.jar
new file mode 100644
index 0000000000..e9206b2eb3
--- /dev/null
+++ b/java/lib/muse-wsdm-wef-api-2.2.0.jar
Binary files differ
diff --git a/java/lib/muse-wsdm-wef-impl-2.2.0.jar b/java/lib/muse-wsdm-wef-impl-2.2.0.jar
new file mode 100644
index 0000000000..12856123b1
--- /dev/null
+++ b/java/lib/muse-wsdm-wef-impl-2.2.0.jar
Binary files differ
diff --git a/java/lib/muse-wsn-api-2.2.0.jar b/java/lib/muse-wsn-api-2.2.0.jar
new file mode 100644
index 0000000000..72b70a043d
--- /dev/null
+++ b/java/lib/muse-wsn-api-2.2.0.jar
Binary files differ
diff --git a/java/lib/muse-wsn-impl-2.2.0.jar b/java/lib/muse-wsn-impl-2.2.0.jar
new file mode 100644
index 0000000000..615f2a5f62
--- /dev/null
+++ b/java/lib/muse-wsn-impl-2.2.0.jar
Binary files differ
diff --git a/java/lib/muse-wsrf-api-2.2.0.jar b/java/lib/muse-wsrf-api-2.2.0.jar
new file mode 100644
index 0000000000..efa36e9fbc
--- /dev/null
+++ b/java/lib/muse-wsrf-api-2.2.0.jar
Binary files differ
diff --git a/java/lib/muse-wsrf-impl-2.2.0.jar b/java/lib/muse-wsrf-impl-2.2.0.jar
new file mode 100644
index 0000000000..a19b1e7149
--- /dev/null
+++ b/java/lib/muse-wsrf-impl-2.2.0.jar
Binary files differ
diff --git a/java/lib/muse-wsrf-rmd-2.2.0.jar b/java/lib/muse-wsrf-rmd-2.2.0.jar
new file mode 100644
index 0000000000..e03676cad8
--- /dev/null
+++ b/java/lib/muse-wsrf-rmd-2.2.0.jar
Binary files differ
diff --git a/java/lib/muse-wsx-api-2.2.0.jar b/java/lib/muse-wsx-api-2.2.0.jar
new file mode 100644
index 0000000000..1533d8dc59
--- /dev/null
+++ b/java/lib/muse-wsx-api-2.2.0.jar
Binary files differ
diff --git a/java/lib/muse-wsx-impl-2.2.0.jar b/java/lib/muse-wsx-impl-2.2.0.jar
new file mode 100644
index 0000000000..9ce78ef0b7
--- /dev/null
+++ b/java/lib/muse-wsx-impl-2.2.0.jar
Binary files differ
diff --git a/java/lib/org.apache.commons.codec_1.3.0.v20080530-1600.jar b/java/lib/org.apache.commons.codec_1.3.0.v20080530-1600.jar
new file mode 100644
index 0000000000..d9b4c8ea1f
--- /dev/null
+++ b/java/lib/org.apache.commons.codec_1.3.0.v20080530-1600.jar
Binary files differ
diff --git a/java/lib/org.eclipse.core.commands-3.2.0.jar b/java/lib/org.eclipse.core.commands-3.2.0.jar
deleted file mode 100644
index c864864689..0000000000
--- a/java/lib/org.eclipse.core.commands-3.2.0.jar
+++ /dev/null
Binary files differ
diff --git a/java/lib/org.eclipse.core.commands_3.4.0.I20080509-2000.jar b/java/lib/org.eclipse.core.commands_3.4.0.I20080509-2000.jar
new file mode 100644
index 0000000000..6467d78d66
--- /dev/null
+++ b/java/lib/org.eclipse.core.commands_3.4.0.I20080509-2000.jar
Binary files differ
diff --git a/java/lib/org.eclipse.core.contenttype-3.2.0.jar b/java/lib/org.eclipse.core.contenttype-3.2.0.jar
deleted file mode 100644
index 816e3fc938..0000000000
--- a/java/lib/org.eclipse.core.contenttype-3.2.0.jar
+++ /dev/null
Binary files differ
diff --git a/java/lib/org.eclipse.core.contenttype_3.3.0.v20080604-1400.jar b/java/lib/org.eclipse.core.contenttype_3.3.0.v20080604-1400.jar
new file mode 100644
index 0000000000..0b6163cf1b
--- /dev/null
+++ b/java/lib/org.eclipse.core.contenttype_3.3.0.v20080604-1400.jar
Binary files differ
diff --git a/java/lib/org.eclipse.core.databinding_1.1.1.M20080827-0800b.jar b/java/lib/org.eclipse.core.databinding_1.1.1.M20080827-0800b.jar
new file mode 100644
index 0000000000..7f9d1b637e
--- /dev/null
+++ b/java/lib/org.eclipse.core.databinding_1.1.1.M20080827-0800b.jar
Binary files differ
diff --git a/java/lib/org.eclipse.core.expressions-3.2.0.jar b/java/lib/org.eclipse.core.expressions-3.2.0.jar
deleted file mode 100644
index 51d2a0204c..0000000000
--- a/java/lib/org.eclipse.core.expressions-3.2.0.jar
+++ /dev/null
Binary files differ
diff --git a/java/lib/org.eclipse.core.expressions_3.4.0.v20080603-2000.jar b/java/lib/org.eclipse.core.expressions_3.4.0.v20080603-2000.jar
new file mode 100644
index 0000000000..671e92aa4b
--- /dev/null
+++ b/java/lib/org.eclipse.core.expressions_3.4.0.v20080603-2000.jar
Binary files differ
diff --git a/java/lib/org.eclipse.core.jobs-3.2.0.jar b/java/lib/org.eclipse.core.jobs-3.2.0.jar
deleted file mode 100644
index 995bcd2e27..0000000000
--- a/java/lib/org.eclipse.core.jobs-3.2.0.jar
+++ /dev/null
Binary files differ
diff --git a/java/lib/org.eclipse.core.jobs_3.4.0.v20080512.jar b/java/lib/org.eclipse.core.jobs_3.4.0.v20080512.jar
new file mode 100644
index 0000000000..7bdbc00313
--- /dev/null
+++ b/java/lib/org.eclipse.core.jobs_3.4.0.v20080512.jar
Binary files differ
diff --git a/java/lib/org.eclipse.core.runtime-3.2.0.jar b/java/lib/org.eclipse.core.runtime-3.2.0.jar
deleted file mode 100644
index 85e61cca58..0000000000
--- a/java/lib/org.eclipse.core.runtime-3.2.0.jar
+++ /dev/null
Binary files differ
diff --git a/java/lib/org.eclipse.core.runtime.compatibility.auth-3.2.0.jar b/java/lib/org.eclipse.core.runtime.compatibility.auth-3.2.0.jar
deleted file mode 100644
index 26bb49fe12..0000000000
--- a/java/lib/org.eclipse.core.runtime.compatibility.auth-3.2.0.jar
+++ /dev/null
Binary files differ
diff --git a/java/lib/org.eclipse.core.runtime.compatibility.registry-3.2.0.jar b/java/lib/org.eclipse.core.runtime.compatibility.registry-3.2.0.jar
deleted file mode 100644
index 4ffbb0db56..0000000000
--- a/java/lib/org.eclipse.core.runtime.compatibility.registry-3.2.0.jar
+++ /dev/null
Binary files differ
diff --git a/java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/META-INF/ECLIPSE.RSA b/java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/META-INF/ECLIPSE.RSA
new file mode 100644
index 0000000000..d694a14d7f
--- /dev/null
+++ b/java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/META-INF/ECLIPSE.RSA
Binary files differ
diff --git a/java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/META-INF/ECLIPSE.SF b/java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/META-INF/ECLIPSE.SF
new file mode 100644
index 0000000000..6bf4f8d81a
--- /dev/null
+++ b/java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/META-INF/ECLIPSE.SF
@@ -0,0 +1,17 @@
+Signature-Version: 1.0
+SHA1-Digest-Manifest: lM34M2cYUookZFTsw+CIRRJzG/o=
+Created-By: 1.5.0 (IBM Corporation)
+SHA1-Digest-Manifest-Main-Attributes: XjH6FbEjs0cznPMbHs9K2V7KmP4=
+
+Name: runtime_registry_compatibility.jar
+SHA1-Digest: 3ZA+TQU6TxgVia+krDcqMAAYdpU=
+
+Name: about.html
+SHA1-Digest: M+fykt9heyWoEv1LNiIEeBhi/2Q=
+
+Name: META-INF/eclipse.inf
+SHA1-Digest: SAqY+5ITAL0mkdYeijlSRhyIaZk=
+
+Name: fragment.properties
+SHA1-Digest: Gi/SEQV8Vl9A/8928AtuhnVkrKQ=
+
diff --git a/java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/META-INF/MANIFEST.MF b/java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..d9a497e8f4
--- /dev/null
+++ b/java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/META-INF/MANIFEST.MF
@@ -0,0 +1,25 @@
+Manifest-Version: 1.0
+Bundle-RequiredExecutionEnvironment: CDC-1.0/Foundation-1.0,J2SE-1.3
+Bundle-SymbolicName: org.eclipse.core.runtime.compatibility.registry
+Bundle-ManifestVersion: 2
+Bundle-Localization: fragment
+Bundle-Name: %fragmentName
+Bundle-Version: 3.2.200.v20080610
+Bundle-ClassPath: runtime_registry_compatibility.jar
+Fragment-Host: org.eclipse.equinox.registry;bundle-version="[3.3.0,3.5
+ .0)"
+Eclipse-PatchFragment: true
+Bundle-Vendor: %providerName
+
+Name: runtime_registry_compatibility.jar
+SHA1-Digest: Oxij1RUWY4Q3SjHVBqQuVSFgLxs=
+
+Name: about.html
+SHA1-Digest: ejOZra0kypGLQQ2bJtGTX+LI8tU=
+
+Name: META-INF/eclipse.inf
+SHA1-Digest: KyT9FF7C7t86NoBoa2kZT3ZJBfw=
+
+Name: fragment.properties
+SHA1-Digest: 4yjHkU5Z/6ej6ZFYT+PE9sMOJPY=
+
diff --git a/java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/META-INF/eclipse.inf b/java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/META-INF/eclipse.inf
new file mode 100644
index 0000000000..7864d3c4c3
--- /dev/null
+++ b/java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/META-INF/eclipse.inf
@@ -0,0 +1,3 @@
+#Processed using Jarprocessor
+pack200.args = -E4
+pack200.conditioned = true
diff --git a/java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/about.html b/java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/about.html
new file mode 100644
index 0000000000..460233046e
--- /dev/null
+++ b/java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 2, 2006</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/fragment.properties b/java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/fragment.properties
new file mode 100644
index 0000000000..e60dbf5c67
--- /dev/null
+++ b/java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/fragment.properties
@@ -0,0 +1,12 @@
+###############################################################################
+# Copyright (c) 2006 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+providerName=Eclipse.org
+fragmentName=Eclipse Registry Compatibility Fragment
diff --git a/java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/runtime_registry_compatibility.jar b/java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/runtime_registry_compatibility.jar
new file mode 100644
index 0000000000..3103fb0ce7
--- /dev/null
+++ b/java/lib/org.eclipse.core.runtime.compatibility.registry_3.2.200.v20080610/runtime_registry_compatibility.jar
Binary files differ
diff --git a/java/lib/org.eclipse.core.runtime_3.4.0.v20080512.jar b/java/lib/org.eclipse.core.runtime_3.4.0.v20080512.jar
new file mode 100644
index 0000000000..366be26fe3
--- /dev/null
+++ b/java/lib/org.eclipse.core.runtime_3.4.0.v20080512.jar
Binary files differ
diff --git a/java/lib/org.eclipse.equinox.app_1.1.0.v20080421-2006.jar b/java/lib/org.eclipse.equinox.app_1.1.0.v20080421-2006.jar
new file mode 100644
index 0000000000..e46c099fe4
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.app_1.1.0.v20080421-2006.jar
Binary files differ
diff --git a/java/lib/org.eclipse.equinox.common-3.2.0.jar b/java/lib/org.eclipse.equinox.common-3.2.0.jar
deleted file mode 100644
index e28a631ebb..0000000000
--- a/java/lib/org.eclipse.equinox.common-3.2.0.jar
+++ /dev/null
Binary files differ
diff --git a/java/lib/org.eclipse.equinox.common_3.4.0.v20080421-2006.jar b/java/lib/org.eclipse.equinox.common_3.4.0.v20080421-2006.jar
new file mode 100644
index 0000000000..c73223995b
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.common_3.4.0.v20080421-2006.jar
Binary files differ
diff --git a/java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/META-INF/ECLIPSE.RSA b/java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/META-INF/ECLIPSE.RSA
new file mode 100644
index 0000000000..29e6f3e7a0
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/META-INF/ECLIPSE.RSA
Binary files differ
diff --git a/java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/META-INF/ECLIPSE.SF b/java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/META-INF/ECLIPSE.SF
new file mode 100644
index 0000000000..1d2eece149
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/META-INF/ECLIPSE.SF
@@ -0,0 +1,17 @@
+Signature-Version: 1.0
+SHA1-Digest-Manifest: FheFhPCFIe9e17dtN19PvFpfHzs=
+Created-By: 1.5.0 (IBM Corporation)
+SHA1-Digest-Manifest-Main-Attributes: X4gDjCpbD8vwxPcCNeLjJjIHBoU=
+
+Name: about.html
+SHA1-Digest: xGcp/Hbq/ywyvVWkPzD/2vkIzdY=
+
+Name: eclipse_1115.so
+SHA1-Digest: ItFKEUKn9bCxLiWwFj8ubKbopDg=
+
+Name: META-INF/eclipse.inf
+SHA1-Digest: SAqY+5ITAL0mkdYeijlSRhyIaZk=
+
+Name: launcher.carbon.macosx.properties
+SHA1-Digest: iJiwtqN46CqxjQPiFqskiJDS2hk=
+
diff --git a/java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/META-INF/MANIFEST.MF b/java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..f9ef43c43a
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/META-INF/MANIFEST.MF
@@ -0,0 +1,25 @@
+Manifest-Version: 1.0
+Bundle-SymbolicName: org.eclipse.equinox.launcher.carbon.macosx;single
+ ton:=true
+Bundle-ManifestVersion: 2
+Bundle-Localization: launcher.carbon.macosx
+Bundle-Name: %pluginName
+Eclipse-PlatformFilter: (& (osgi.ws=carbon) (osgi.os=macosx) (|(osgi.a
+ rch=x86)(osgi.arch=ppc)) )
+Bundle-Version: 1.0.101.R34x_v20080731
+Fragment-Host: org.eclipse.equinox.launcher;bundle-version="[1.0.0,1.1
+ .0)"
+Bundle-Vendor: %providerName
+
+Name: eclipse_1115.so
+SHA1-Digest: RRLhb5Prci79GCZFsylKadyPBvM=
+
+Name: about.html
+SHA1-Digest: a9lDHrGuLPkvHBUhsqWU+V2mhPw=
+
+Name: META-INF/eclipse.inf
+SHA1-Digest: KyT9FF7C7t86NoBoa2kZT3ZJBfw=
+
+Name: launcher.carbon.macosx.properties
+SHA1-Digest: L4VSSU2M0KAWyhCp8QBLMsnC6Jk=
+
diff --git a/java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/META-INF/eclipse.inf b/java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/META-INF/eclipse.inf
new file mode 100644
index 0000000000..7864d3c4c3
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/META-INF/eclipse.inf
@@ -0,0 +1,3 @@
+#Processed using Jarprocessor
+pack200.args = -E4
+pack200.conditioned = true
diff --git a/java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/about.html b/java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/about.html
new file mode 100644
index 0000000000..395df3ba90
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 5, 2006</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;).
+Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/org/documents/epl-v10.php">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor&rsquo;s license
+that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/eclipse_1115.so b/java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/eclipse_1115.so
new file mode 100644
index 0000000000..17e8230b19
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/eclipse_1115.so
Binary files differ
diff --git a/java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/launcher.carbon.macosx.properties b/java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/launcher.carbon.macosx.properties
new file mode 100644
index 0000000000..4373d35790
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731/launcher.carbon.macosx.properties
@@ -0,0 +1,12 @@
+###############################################################################
+# Copyright (c) 2007 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+pluginName = Equinox Launcher MacOSX Fragment
+providerName = Eclipse.org
diff --git a/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/META-INF/ECLIPSE.RSA b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/META-INF/ECLIPSE.RSA
new file mode 100644
index 0000000000..566c0abd11
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/META-INF/ECLIPSE.RSA
Binary files differ
diff --git a/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/META-INF/ECLIPSE.SF b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/META-INF/ECLIPSE.SF
new file mode 100644
index 0000000000..4122b4ea8f
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/META-INF/ECLIPSE.SF
@@ -0,0 +1,17 @@
+Signature-Version: 1.0
+SHA1-Digest-Manifest: tswsDz0e+s2SPhfY7LybTLEXoI4=
+Created-By: 1.5.0 (IBM Corporation)
+SHA1-Digest-Manifest-Main-Attributes: Ymnpf9HjgpR8t0MrPx1wLH4tJFQ=
+
+Name: launcher.gtk.linux.x86.properties
+SHA1-Digest: +CJXeQUkWFS+xYpRY6jNNT065mI=
+
+Name: about.html
+SHA1-Digest: xGcp/Hbq/ywyvVWkPzD/2vkIzdY=
+
+Name: eclipse_1115.so
+SHA1-Digest: gvha3rnYpdA1SDXsMMxPKyEB/Xg=
+
+Name: META-INF/eclipse.inf
+SHA1-Digest: SAqY+5ITAL0mkdYeijlSRhyIaZk=
+
diff --git a/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/META-INF/MANIFEST.MF b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..d699938858
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/META-INF/MANIFEST.MF
@@ -0,0 +1,25 @@
+Manifest-Version: 1.0
+Bundle-SymbolicName: org.eclipse.equinox.launcher.gtk.linux.x86;single
+ ton:=true
+Bundle-ManifestVersion: 2
+Bundle-Localization: launcher.gtk.linux.x86
+Bundle-Name: %pluginName
+Eclipse-PlatformFilter: (& (osgi.ws=gtk) (osgi.os=linux) (osgi.arch=x8
+ 6))
+Bundle-Version: 1.0.101.R34x_v20080805
+Fragment-Host: org.eclipse.equinox.launcher;bundle-version="[1.0.0,1.1
+ .0)"
+Bundle-Vendor: %providerName
+
+Name: launcher.gtk.linux.x86.properties
+SHA1-Digest: BSbhScorws9R/DVRUdKNmymMSIU=
+
+Name: eclipse_1115.so
+SHA1-Digest: n3UyHV1KgJ0YuFIDUxPBXj2dxw0=
+
+Name: about.html
+SHA1-Digest: a9lDHrGuLPkvHBUhsqWU+V2mhPw=
+
+Name: META-INF/eclipse.inf
+SHA1-Digest: KyT9FF7C7t86NoBoa2kZT3ZJBfw=
+
diff --git a/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/META-INF/eclipse.inf b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/META-INF/eclipse.inf
new file mode 100644
index 0000000000..7864d3c4c3
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/META-INF/eclipse.inf
@@ -0,0 +1,3 @@
+#Processed using Jarprocessor
+pack200.args = -E4
+pack200.conditioned = true
diff --git a/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/about.html b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/about.html
new file mode 100644
index 0000000000..395df3ba90
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 5, 2006</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;).
+Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/org/documents/epl-v10.php">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor&rsquo;s license
+that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/eclipse_1115.so b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/eclipse_1115.so
new file mode 100644
index 0000000000..3ec14a5e88
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/eclipse_1115.so
Binary files differ
diff --git a/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/launcher.gtk.linux.x86.properties b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/launcher.gtk.linux.x86.properties
new file mode 100644
index 0000000000..792485112e
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805/launcher.gtk.linux.x86.properties
@@ -0,0 +1,12 @@
+###############################################################################
+# Copyright (c) 2007 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+pluginName = Equinox Launcher Linux X86 Fragment
+providerName = Eclipse.org
diff --git a/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/META-INF/ECLIPSE.RSA b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/META-INF/ECLIPSE.RSA
new file mode 100644
index 0000000000..df6b24ad57
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/META-INF/ECLIPSE.RSA
Binary files differ
diff --git a/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/META-INF/ECLIPSE.SF b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/META-INF/ECLIPSE.SF
new file mode 100644
index 0000000000..4193e97338
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/META-INF/ECLIPSE.SF
@@ -0,0 +1,17 @@
+Signature-Version: 1.0
+SHA1-Digest-Manifest: gnfArgp6eM77c1JxQF9X3q9/Hd8=
+Created-By: 1.5.0 (IBM Corporation)
+SHA1-Digest-Manifest-Main-Attributes: hR6QNnvCGlzBxiyTmh4DMZ03Yyg=
+
+Name: about.html
+SHA1-Digest: xGcp/Hbq/ywyvVWkPzD/2vkIzdY=
+
+Name: eclipse_1115.so
+SHA1-Digest: 33jSy/p2jY6bvgg4W0xBlxjxMWA=
+
+Name: META-INF/eclipse.inf
+SHA1-Digest: SAqY+5ITAL0mkdYeijlSRhyIaZk=
+
+Name: launcher.gtk.linux.x86_64.properties
+SHA1-Digest: Q2rsj7VmfkLLH24miqu0v+2sZjE=
+
diff --git a/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/META-INF/MANIFEST.MF b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..b790c0af9a
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/META-INF/MANIFEST.MF
@@ -0,0 +1,25 @@
+Manifest-Version: 1.0
+Bundle-SymbolicName: org.eclipse.equinox.launcher.gtk.linux.x86_64;sin
+ gleton:=true
+Bundle-ManifestVersion: 2
+Bundle-Localization: launcher.gtk.linux.x86_64
+Bundle-Name: %pluginName
+Eclipse-PlatformFilter: (& (osgi.ws=gtk) (osgi.os=linux) (osgi.arch=x8
+ 6_64))
+Bundle-Version: 1.0.101.R34x_v20080731
+Fragment-Host: org.eclipse.equinox.launcher;bundle-version="[1.0.0,1.1
+ .0)"
+Bundle-Vendor: %providerName
+
+Name: eclipse_1115.so
+SHA1-Digest: l0VkVxLXANjcUEWTLRqXKUmIfn8=
+
+Name: about.html
+SHA1-Digest: a9lDHrGuLPkvHBUhsqWU+V2mhPw=
+
+Name: META-INF/eclipse.inf
+SHA1-Digest: KyT9FF7C7t86NoBoa2kZT3ZJBfw=
+
+Name: launcher.gtk.linux.x86_64.properties
+SHA1-Digest: thXaNI0tmsHrCOYNbQBW2zzAh+Q=
+
diff --git a/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/META-INF/eclipse.inf b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/META-INF/eclipse.inf
new file mode 100644
index 0000000000..7864d3c4c3
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/META-INF/eclipse.inf
@@ -0,0 +1,3 @@
+#Processed using Jarprocessor
+pack200.args = -E4
+pack200.conditioned = true
diff --git a/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/about.html b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/about.html
new file mode 100644
index 0000000000..395df3ba90
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 5, 2006</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;).
+Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/org/documents/epl-v10.php">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor&rsquo;s license
+that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/eclipse_1115.so b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/eclipse_1115.so
new file mode 100644
index 0000000000..8bf855533c
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/eclipse_1115.so
Binary files differ
diff --git a/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/launcher.gtk.linux.x86_64.properties b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/launcher.gtk.linux.x86_64.properties
new file mode 100644
index 0000000000..da448aadbb
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/launcher.gtk.linux.x86_64.properties
@@ -0,0 +1,12 @@
+###############################################################################
+# Copyright (c) 2007 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+pluginName = Equinox Launcher Linux X86_64 Fragment
+providerName = Eclipse.org
diff --git a/java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/META-INF/ECLIPSE.RSA b/java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/META-INF/ECLIPSE.RSA
new file mode 100644
index 0000000000..81599f2e21
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/META-INF/ECLIPSE.RSA
Binary files differ
diff --git a/java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/META-INF/ECLIPSE.SF b/java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/META-INF/ECLIPSE.SF
new file mode 100644
index 0000000000..20fe507cdf
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/META-INF/ECLIPSE.SF
@@ -0,0 +1,17 @@
+Signature-Version: 1.0
+SHA1-Digest-Manifest: kR1kAxZlcW3W0rm/xjIZED9LrAo=
+Created-By: 1.5.0 (IBM Corporation)
+SHA1-Digest-Manifest-Main-Attributes: pqNWWWTyBz8hsANASpU3hoVl9kc=
+
+Name: about.html
+SHA1-Digest: xGcp/Hbq/ywyvVWkPzD/2vkIzdY=
+
+Name: eclipse_1115.so
+SHA1-Digest: o5PGzpcLRdWF5shzEwmVFCwZrb0=
+
+Name: META-INF/eclipse.inf
+SHA1-Digest: SAqY+5ITAL0mkdYeijlSRhyIaZk=
+
+Name: launcher.gtk.solaris.sparc.properties
+SHA1-Digest: gu+HrnaK+kn508ppLY/iXys12yA=
+
diff --git a/java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/META-INF/MANIFEST.MF b/java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..f81e6141bb
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/META-INF/MANIFEST.MF
@@ -0,0 +1,25 @@
+Manifest-Version: 1.0
+Bundle-SymbolicName: org.eclipse.equinox.launcher.gtk.solaris.sparc;si
+ ngleton:=true
+Bundle-ManifestVersion: 2
+Bundle-Localization: launcher.gtk.solaris.sparc
+Bundle-Name: %pluginName
+Eclipse-PlatformFilter: (& (osgi.ws=gtk) (osgi.os=solaris) (osgi.arch=
+ sparc))
+Bundle-Version: 1.0.101.R34x_v20080731
+Fragment-Host: org.eclipse.equinox.launcher;bundle-version="[1.0.0,1.1
+ .0)"
+Bundle-Vendor: %providerName
+
+Name: eclipse_1115.so
+SHA1-Digest: 5km5rPngvbWH3aWIYrl+xMejhCE=
+
+Name: about.html
+SHA1-Digest: a9lDHrGuLPkvHBUhsqWU+V2mhPw=
+
+Name: META-INF/eclipse.inf
+SHA1-Digest: KyT9FF7C7t86NoBoa2kZT3ZJBfw=
+
+Name: launcher.gtk.solaris.sparc.properties
+SHA1-Digest: B/N7qN8v4Os5flFl4mE2UaqnMZs=
+
diff --git a/java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/META-INF/eclipse.inf b/java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/META-INF/eclipse.inf
new file mode 100644
index 0000000000..7864d3c4c3
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/META-INF/eclipse.inf
@@ -0,0 +1,3 @@
+#Processed using Jarprocessor
+pack200.args = -E4
+pack200.conditioned = true
diff --git a/java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/about.html b/java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/about.html
new file mode 100644
index 0000000000..395df3ba90
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 5, 2006</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;).
+Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/org/documents/epl-v10.php">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor&rsquo;s license
+that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/eclipse_1115.so b/java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/eclipse_1115.so
new file mode 100644
index 0000000000..3d8beb88dd
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/eclipse_1115.so
Binary files differ
diff --git a/java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/launcher.gtk.solaris.sparc.properties b/java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/launcher.gtk.solaris.sparc.properties
new file mode 100644
index 0000000000..c3f2ae186e
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731/launcher.gtk.solaris.sparc.properties
@@ -0,0 +1,12 @@
+###############################################################################
+# Copyright (c) 2007 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+pluginName = Equinox Launcher Sparc Fragment
+providerName = Eclipse.org
diff --git a/java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/META-INF/ECLIPSE.RSA b/java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/META-INF/ECLIPSE.RSA
new file mode 100644
index 0000000000..e2350f7b3d
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/META-INF/ECLIPSE.RSA
Binary files differ
diff --git a/java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/META-INF/ECLIPSE.SF b/java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/META-INF/ECLIPSE.SF
new file mode 100644
index 0000000000..a4cc0ac995
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/META-INF/ECLIPSE.SF
@@ -0,0 +1,17 @@
+Signature-Version: 1.0
+SHA1-Digest-Manifest: oXE8Y8m0B4hXXkniJ3e42s+zWZA=
+Created-By: 1.5.0 (IBM Corporation)
+SHA1-Digest-Manifest-Main-Attributes: D+OZA9EIs+7l5qfZkdxKrzNalvU=
+
+Name: about.html
+SHA1-Digest: xGcp/Hbq/ywyvVWkPzD/2vkIzdY=
+
+Name: launcher.win32.win32.x86.properties
+SHA1-Digest: TMYbn4sXlC4uxONCDt2S0kP1hTY=
+
+Name: META-INF/eclipse.inf
+SHA1-Digest: SAqY+5ITAL0mkdYeijlSRhyIaZk=
+
+Name: eclipse_1115.dll
+SHA1-Digest: ishZ405IXeNkJcKK6X6ZCmhtZOk=
+
diff --git a/java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/META-INF/MANIFEST.MF b/java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..6acfe13c74
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/META-INF/MANIFEST.MF
@@ -0,0 +1,25 @@
+Manifest-Version: 1.0
+Bundle-SymbolicName: org.eclipse.equinox.launcher.win32.win32.x86; sin
+ gleton:=true
+Bundle-ManifestVersion: 2
+Bundle-Localization: launcher.win32.win32.x86
+Bundle-Name: %pluginName
+Eclipse-PlatformFilter: (& (osgi.ws=win32) (osgi.os=win32) (osgi.arch=
+ x86))
+Bundle-Version: 1.0.101.R34x_v20080731
+Fragment-Host: org.eclipse.equinox.launcher;bundle-version="[1.0.0,1.1
+ .0)"
+Bundle-Vendor: %providerName
+
+Name: about.html
+SHA1-Digest: a9lDHrGuLPkvHBUhsqWU+V2mhPw=
+
+Name: META-INF/eclipse.inf
+SHA1-Digest: KyT9FF7C7t86NoBoa2kZT3ZJBfw=
+
+Name: launcher.win32.win32.x86.properties
+SHA1-Digest: rhstucCaFV5tj2GARC/9A5zdmB4=
+
+Name: eclipse_1115.dll
+SHA1-Digest: 6f1Zg9WvwnS5OsA5EB8tWKy1480=
+
diff --git a/java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/META-INF/eclipse.inf b/java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/META-INF/eclipse.inf
new file mode 100644
index 0000000000..7864d3c4c3
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/META-INF/eclipse.inf
@@ -0,0 +1,3 @@
+#Processed using Jarprocessor
+pack200.args = -E4
+pack200.conditioned = true
diff --git a/java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/about.html b/java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/about.html
new file mode 100644
index 0000000000..395df3ba90
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 5, 2006</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;).
+Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/org/documents/epl-v10.php">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor&rsquo;s license
+that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/eclipse_1115.dll b/java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/eclipse_1115.dll
new file mode 100644
index 0000000000..5e438cf505
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/eclipse_1115.dll
Binary files differ
diff --git a/java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/launcher.win32.win32.x86.properties b/java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/launcher.win32.win32.x86.properties
new file mode 100644
index 0000000000..e8f40bca50
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher.win32.win32.x86_1.0.101.R34x_v20080731/launcher.win32.win32.x86.properties
@@ -0,0 +1,12 @@
+###############################################################################
+# Copyright (c) 2007 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+pluginName = Equinox Launcher Win32 X86 Fragment
+providerName = Eclipse.org
diff --git a/java/lib/org.eclipse.equinox.launcher_1.0.101.R34x_v20080819.jar b/java/lib/org.eclipse.equinox.launcher_1.0.101.R34x_v20080819.jar
new file mode 100644
index 0000000000..21cc2a6a07
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.launcher_1.0.101.R34x_v20080819.jar
Binary files differ
diff --git a/java/lib/org.eclipse.equinox.preferences-3.2.0.jar b/java/lib/org.eclipse.equinox.preferences-3.2.0.jar
deleted file mode 100644
index 0ca4767ced..0000000000
--- a/java/lib/org.eclipse.equinox.preferences-3.2.0.jar
+++ /dev/null
Binary files differ
diff --git a/java/lib/org.eclipse.equinox.preferences_3.2.201.R34x_v20080709.jar b/java/lib/org.eclipse.equinox.preferences_3.2.201.R34x_v20080709.jar
new file mode 100644
index 0000000000..0efcea4022
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.preferences_3.2.201.R34x_v20080709.jar
Binary files differ
diff --git a/java/lib/org.eclipse.equinox.registry-3.2.0.jar b/java/lib/org.eclipse.equinox.registry-3.2.0.jar
deleted file mode 100644
index 750fab0e76..0000000000
--- a/java/lib/org.eclipse.equinox.registry-3.2.0.jar
+++ /dev/null
Binary files differ
diff --git a/java/lib/org.eclipse.equinox.registry_3.4.0.v20080516-0950.jar b/java/lib/org.eclipse.equinox.registry_3.4.0.v20080516-0950.jar
new file mode 100644
index 0000000000..ddc97ffe7c
--- /dev/null
+++ b/java/lib/org.eclipse.equinox.registry_3.4.0.v20080516-0950.jar
Binary files differ
diff --git a/java/lib/org.eclipse.help-3.2.0.jar b/java/lib/org.eclipse.help-3.2.0.jar
deleted file mode 100644
index 12ac13f918..0000000000
--- a/java/lib/org.eclipse.help-3.2.0.jar
+++ /dev/null
Binary files differ
diff --git a/java/lib/org.eclipse.help_3.3.101.v20080702_34x.jar b/java/lib/org.eclipse.help_3.3.101.v20080702_34x.jar
new file mode 100644
index 0000000000..8bb2b74a73
--- /dev/null
+++ b/java/lib/org.eclipse.help_3.3.101.v20080702_34x.jar
Binary files differ
diff --git a/java/lib/org.eclipse.jface-3.2.0.jar b/java/lib/org.eclipse.jface-3.2.0.jar
deleted file mode 100644
index 1d5035a859..0000000000
--- a/java/lib/org.eclipse.jface-3.2.0.jar
+++ /dev/null
Binary files differ
diff --git a/java/lib/org.eclipse.jface.databinding_1.2.1.M20080827-0800a.jar b/java/lib/org.eclipse.jface.databinding_1.2.1.M20080827-0800a.jar
new file mode 100644
index 0000000000..b61037ef9f
--- /dev/null
+++ b/java/lib/org.eclipse.jface.databinding_1.2.1.M20080827-0800a.jar
Binary files differ
diff --git a/java/lib/org.eclipse.jface_3.4.1.M20080827-2000.jar b/java/lib/org.eclipse.jface_3.4.1.M20080827-2000.jar
new file mode 100644
index 0000000000..ad1c58f0d0
--- /dev/null
+++ b/java/lib/org.eclipse.jface_3.4.1.M20080827-2000.jar
Binary files differ
diff --git a/java/lib/org.eclipse.osgi-3.2.0.jar b/java/lib/org.eclipse.osgi-3.2.0.jar
deleted file mode 100644
index 7ad4b9eff3..0000000000
--- a/java/lib/org.eclipse.osgi-3.2.0.jar
+++ /dev/null
Binary files differ
diff --git a/java/lib/org.eclipse.osgi_3.4.2.R34x_v20080826-1230.jar b/java/lib/org.eclipse.osgi_3.4.2.R34x_v20080826-1230.jar
new file mode 100644
index 0000000000..673f3f5932
--- /dev/null
+++ b/java/lib/org.eclipse.osgi_3.4.2.R34x_v20080826-1230.jar
Binary files differ
diff --git a/java/lib/org.eclipse.swt-3.2.0.jar b/java/lib/org.eclipse.swt-3.2.0.jar
deleted file mode 100644
index 0b2be574ed..0000000000
--- a/java/lib/org.eclipse.swt-3.2.0.jar
+++ /dev/null
Binary files differ
diff --git a/java/lib/org.eclipse.swt.carbon.macosx_3.4.1.v3449c.jar b/java/lib/org.eclipse.swt.carbon.macosx_3.4.1.v3449c.jar
new file mode 100644
index 0000000000..d64249df6a
--- /dev/null
+++ b/java/lib/org.eclipse.swt.carbon.macosx_3.4.1.v3449c.jar
Binary files differ
diff --git a/java/lib/org.eclipse.swt.gtk.linux.x86_3.4.1.v3449c.jar b/java/lib/org.eclipse.swt.gtk.linux.x86_3.4.1.v3449c.jar
new file mode 100644
index 0000000000..cda22da341
--- /dev/null
+++ b/java/lib/org.eclipse.swt.gtk.linux.x86_3.4.1.v3449c.jar
Binary files differ
diff --git a/java/lib/org.eclipse.swt.gtk.linux.x86_64_3.4.1.v3449c.jar b/java/lib/org.eclipse.swt.gtk.linux.x86_64_3.4.1.v3449c.jar
new file mode 100644
index 0000000000..95909028d4
--- /dev/null
+++ b/java/lib/org.eclipse.swt.gtk.linux.x86_64_3.4.1.v3449c.jar
Binary files differ
diff --git a/java/lib/org.eclipse.swt.gtk.solaris.sparc_3.4.1.v3449c.jar b/java/lib/org.eclipse.swt.gtk.solaris.sparc_3.4.1.v3449c.jar
new file mode 100644
index 0000000000..d7143505a4
--- /dev/null
+++ b/java/lib/org.eclipse.swt.gtk.solaris.sparc_3.4.1.v3449c.jar
Binary files differ
diff --git a/java/lib/org.eclipse.swt.win32.win32.x86-3.2.0.jar b/java/lib/org.eclipse.swt.win32.win32.x86-3.2.0.jar
deleted file mode 100644
index 8fbebc2401..0000000000
--- a/java/lib/org.eclipse.swt.win32.win32.x86-3.2.0.jar
+++ /dev/null
Binary files differ
diff --git a/java/lib/org.eclipse.swt.win32.win32.x86_3.4.1.v3449c.jar b/java/lib/org.eclipse.swt.win32.win32.x86_3.4.1.v3449c.jar
new file mode 100644
index 0000000000..5c261c8411
--- /dev/null
+++ b/java/lib/org.eclipse.swt.win32.win32.x86_3.4.1.v3449c.jar
Binary files differ
diff --git a/java/lib/org.eclipse.swt_3.4.1.v3449c.jar b/java/lib/org.eclipse.swt_3.4.1.v3449c.jar
new file mode 100644
index 0000000000..606abc5a3b
--- /dev/null
+++ b/java/lib/org.eclipse.swt_3.4.1.v3449c.jar
Binary files differ
diff --git a/java/lib/org.eclipse.ui-3.2.0.jar b/java/lib/org.eclipse.ui-3.2.0.jar
deleted file mode 100644
index b96dac530d..0000000000
--- a/java/lib/org.eclipse.ui-3.2.0.jar
+++ /dev/null
Binary files differ
diff --git a/java/lib/org.eclipse.ui.forms-3.2.0.jar b/java/lib/org.eclipse.ui.forms-3.2.0.jar
deleted file mode 100644
index 460585e68b..0000000000
--- a/java/lib/org.eclipse.ui.forms-3.2.0.jar
+++ /dev/null
Binary files differ
diff --git a/java/lib/org.eclipse.ui.forms_3.3.101.v20080708_34x.jar b/java/lib/org.eclipse.ui.forms_3.3.101.v20080708_34x.jar
new file mode 100644
index 0000000000..a458fcb058
--- /dev/null
+++ b/java/lib/org.eclipse.ui.forms_3.3.101.v20080708_34x.jar
Binary files differ
diff --git a/java/lib/org.eclipse.ui.workbench-3.2.1.jar b/java/lib/org.eclipse.ui.workbench-3.2.1.jar
deleted file mode 100644
index 4a10e210df..0000000000
--- a/java/lib/org.eclipse.ui.workbench-3.2.1.jar
+++ /dev/null
Binary files differ
diff --git a/java/lib/org.eclipse.ui.workbench_3.4.1.M20080827-0800a.jar b/java/lib/org.eclipse.ui.workbench_3.4.1.M20080827-0800a.jar
new file mode 100644
index 0000000000..3e151c8122
--- /dev/null
+++ b/java/lib/org.eclipse.ui.workbench_3.4.1.M20080827-0800a.jar
Binary files differ
diff --git a/java/lib/org.eclipse.ui_3.4.1.M20080910-0800.jar b/java/lib/org.eclipse.ui_3.4.1.M20080910-0800.jar
new file mode 100644
index 0000000000..c7a8cf4256
--- /dev/null
+++ b/java/lib/org.eclipse.ui_3.4.1.M20080910-0800.jar
Binary files differ
diff --git a/java/lib/org.osgi.core-1.0.0.jar b/java/lib/org.osgi.core_1.0.0.jar
index dcddc09bc0..dcddc09bc0 100755
--- a/java/lib/org.osgi.core-1.0.0.jar
+++ b/java/lib/org.osgi.core_1.0.0.jar
Binary files differ
diff --git a/java/lib/poms/backport-util-concurrent-2.2.pom b/java/lib/poms/backport-util-concurrent-2.2.pom
new file mode 100644
index 0000000000..ea281da344
--- /dev/null
+++ b/java/lib/poms/backport-util-concurrent-2.2.pom
@@ -0,0 +1,25 @@
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>backport-util-concurrent</groupId>
+ <artifactId>backport-util-concurrent</artifactId>
+ <version>2.2</version>
+ <packaging>jar</packaging>
+ <name>Backport of JSR 166</name>
+ <url>http://www.mathcs.emory.edu/dcl/util/backport-util-concurrent/</url>
+ <description>Dawid Kurzyniec's backport of JSR 166</description>
+ <licenses>
+ <license>
+ <name>Public Domain</name>
+ <url>http://creativecommons.org/licenses/publicdomain</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+ <scm>
+ <url>http://dcl.mathcs.emory.edu/cgi-bin/viewcvs.cgi/software/util/backport-util-concurrent/</url>
+ </scm>
+ <organization>
+ <name>Dawid Kurzyniec</name>
+ <url>http://www.mathcs.emory.edu/~dawidk/</url>
+ </organization>
+ <dependencies/>
+</project>
diff --git a/java/lib/poms/commons-beanutils-core-1.8.0.pom b/java/lib/poms/commons-beanutils-core-1.8.0.pom
new file mode 100644
index 0000000000..30d29c9048
--- /dev/null
+++ b/java/lib/poms/commons-beanutils-core-1.8.0.pom
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache</groupId>
+ <artifactId>apache</artifactId>
+ <version>4</version>
+ </parent>
+ <groupId>commons-beanutils</groupId>
+ <artifactId>commons-beanutils-core</artifactId>
+ <version>1.8.0</version>
+ <name>Commons BeanUtils Core</name>
+ <url>http://commons.apache.org/beanutils/</url>
+
+ <dependencies>
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <version>1.1.1</version>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/java/lib/poms/commons-cli-1.0.pom b/java/lib/poms/commons-cli-1.0.pom
new file mode 100644
index 0000000000..cfc5a04d78
--- /dev/null
+++ b/java/lib/poms/commons-cli-1.0.pom
@@ -0,0 +1,76 @@
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>commons-cli</groupId>
+ <artifactId>commons-cli</artifactId>
+ <name>CLI</name>
+ <version>1.0</version>
+ <description>Commons CLI provides a simple API for working with the command line arguments and options.</description>
+ <inceptionYear>2002</inceptionYear>
+ <developers>
+ <developer>
+ <id>jstrachan</id>
+ <name>James Strachan</name>
+ <email>jstrachan@apache.org</email>
+ <organization>SpiritSoft, Inc.</organization>
+ </developer>
+ <developer>
+ <id>bob</id>
+ <name>bob mcwhirter</name>
+ <email>bob@werken.com</email>
+ <organization>Werken</organization>
+ </developer>
+ <developer>
+ <id>jkeyes</id>
+ <name>John Keyes</name>
+ <email>jbjk@mac.com</email>
+ <organization>integral Source</organization>
+ </developer>
+ </developers>
+ <contributors>
+ <contributor>
+ <name>Berin Loritsch</name>
+ <email>bloritsch@apache.org</email>
+ <roles>
+ <role>helped in the Avalon CLI merge</role>
+ </roles>
+ </contributor>
+ <contributor>
+ <name>Peter Maddocks</name>
+ <email>peter_maddocks@hp.com</email>
+ <organization>Hewlett-Packard</organization>
+ <roles>
+ <role>supplied patch</role>
+ </roles>
+ </contributor>
+ </contributors>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>**/*Test*.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <version>1.0</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>1.0</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.7</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project> \ No newline at end of file
diff --git a/java/lib/poms/commons-codec-1.3.pom b/java/lib/poms/commons-codec-1.3.pom
new file mode 100644
index 0000000000..dab16e299b
--- /dev/null
+++ b/java/lib/poms/commons-codec-1.3.pom
@@ -0,0 +1,178 @@
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ <name>Codec</name>
+ <version>1.3</version>
+ <description>The codec package contains simple encoder and decoders for
+ various formats such as Base64 and Hexadecimal. In addition to these
+ widely used encoders and decoders, the codec package also maintains a
+ collection of phonetic encoding utilities.</description>
+ <url>http://jakarta.apache.org/commons/codec/</url>
+ <issueManagement>
+ <url>http://nagoya.apache.org/bugzilla/buglist.cgi?bug_status=NEW&amp;bug_status=ASSIGNED&amp;bug_status=REOPENED&amp;email1=&amp;emailtype1=substring&amp;emailassigned_to1=1&amp;email2=&amp;emailtype2=substring&amp;emailreporter2=1&amp;bugidtype=include&amp;bug_id=&amp;changedin=&amp;votes=&amp;chfieldfrom=&amp;chfieldto=Now&amp;chfieldvalue=&amp;product=Commons&amp;component=Codec&amp;short_desc=&amp;short_desc_type=allwordssubstr&amp;long_desc=&amp;long_desc_type=allwordssubstr&amp;bug_file_loc=&amp;bug_file_loc_type=allwordssubstr&amp;keywords=&amp;keywords_type=anywords&amp;field0-0-0=noop&amp;type0-0-0=noop&amp;value0-0-0=&amp;cmdtype=doit&amp;newqueryname=&amp;order=Reuse+same+sort+as+last+time</url>
+ </issueManagement>
+ <ciManagement>
+ <notifiers>
+ <notifier>
+ <address>commons-dev@jakarta.apache.org</address>
+ </notifier>
+ </notifiers>
+ </ciManagement>
+ <inceptionYear>2002</inceptionYear>
+ <mailingLists>
+ <mailingList>
+ <name>Commons Dev List</name>
+ <subscribe>commons-dev-subscribe@jakarta.apache.org</subscribe>
+ <unsubscribe>commons-dev-unsubscribe@jakarta.apache.org</unsubscribe>
+ <archive>http://nagoya.apache.org/eyebrowse/SummarizeList?listName=commons-dev@jakarta.apache.org</archive>
+ </mailingList>
+ <mailingList>
+ <name>Commons User List</name>
+ <subscribe>commons-user-subscribe@jakarta.apache.org</subscribe>
+ <unsubscribe>commons-user-unsubscribe@jakarta.apache.org</unsubscribe>
+ <archive>http://nagoya.apache.org/eyebrowse/SummarizeList?listName=commons-user@jakarta.apache.org</archive>
+ </mailingList>
+ </mailingLists>
+ <developers>
+ <developer>
+ <id>bayard</id>
+ <name>Henri Yandell</name>
+ <email>bayard@generationjava.com</email>
+ </developer>
+ <developer>
+ <id>tobrien</id>
+ <name>Tim OBrien</name>
+ <email>tobrien@apache.org</email>
+ <timezone>-6</timezone>
+ </developer>
+ <developer>
+ <id>sanders</id>
+ <name>Scott Sanders</name>
+ <email>sanders@totalsync.com</email>
+ </developer>
+ <developer>
+ <id>rwaldhoff</id>
+ <name>Rodney Waldhoff</name>
+ <email>rwaldhoff@apache.org</email>
+ </developer>
+ <developer>
+ <id>dlr</id>
+ <name>Daniel Rall</name>
+ <email>dlr@finemaltcoding.com</email>
+ </developer>
+ <developer>
+ <id>jon</id>
+ <name>Jon S. Stevens</name>
+ <email>jon@collab.net</email>
+ </developer>
+ <developer>
+ <id>ggregory</id>
+ <name>Gary D. Gregory</name>
+ <email>ggregory@seagullsw.com</email>
+ <organization>Seagull Software</organization>
+ <timezone>-8</timezone>
+ </developer>
+ <developer>
+ <id>dgraham</id>
+ <name>David Graham</name>
+ <email>dgraham@apache.org</email>
+ </developer>
+ </developers>
+ <contributors>
+ <contributor>
+ <name>Christopher O'Brien</name>
+ <email>siege@preoccupied.net</email>
+ </contributor>
+ <contributor>
+ <name>Martin Redington</name>
+ </contributor>
+ <contributor>
+ <name>Jeffery Dever</name>
+ </contributor>
+ <contributor>
+ <name>Steve Zimmermann</name>
+ <email>steve.zimmermann@heii.com</email>
+ </contributor>
+ <contributor>
+ <name>Benjamin Walstrum</name>
+ <email>ben@walstrum.com</email>
+ </contributor>
+ <contributor>
+ <name>Oleg Kalnichevski</name>
+ <email>oleg@ural.ru</email>
+ </contributor>
+ <contributor>
+ <name>Dave Dribin</name>
+ <email>apache@dave.dribin.org</email>
+ </contributor>
+ <contributor>
+ <name>Alex Karasulu</name>
+ <email>aok123 at bellsouth.net</email>
+ </contributor>
+ <contributor>
+ <name>Matthew Inger</name>
+ <email>mattinger at yahoo.com</email>
+ </contributor>
+ </contributors>
+ <licenses>
+ <license>
+ <name>The Apache Software License, Version 2.0</name>
+ <url>/LICENSE.txt</url>
+ </license>
+ </licenses>
+ <scm>
+ <connection>scm:cvs:pserver:anoncvs@cvs.apache.org:/home/cvspublic:jakarta-commons/codec</connection>
+ <url>http://cvs.apache.org/viewcvs/jakarta-commons/codec/</url>
+ </scm>
+ <organization>
+ <name>The Apache Software Foundation</name>
+ <url>http://jakarta.apache.org</url>
+ </organization>
+ <build>
+ <sourceDirectory>src/java</sourceDirectory>
+ <testSourceDirectory>src/test</testSourceDirectory>
+ <testResources>
+ <testResource>
+ <directory>src/test</directory>
+ <includes>
+ <include>**/*.xml</include>
+ </includes>
+ </testResource>
+ </testResources>
+ <plugins>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>**/Test*.java</include>
+ <include>**/*Test.java</include>
+ </includes>
+ <excludes>
+ <exclude>**/*AbstractTest.java</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <distributionManagement>
+ <repository>
+ <id>default</id>
+ <name>Default Repository</name>
+ <url>file:///www/jakarta.apache.org/builds/jakarta-commons/codec/</url>
+ </repository>
+ <site>
+ <id>default</id>
+ <name>Default Site</name>
+ <url>scp://jakarta.apache.org//www/jakarta.apache.org/commons/codec/</url>
+ </site>
+ </distributionManagement>
+</project> \ No newline at end of file
diff --git a/java/lib/poms/commons-collections-3.2.pom b/java/lib/poms/commons-collections-3.2.pom
new file mode 100644
index 0000000000..88e5860df3
--- /dev/null
+++ b/java/lib/poms/commons-collections-3.2.pom
@@ -0,0 +1,420 @@
+<?xml version="1.0" encoding="UTF-8"?><project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ <name>Collections</name>
+ <version>3.2</version>
+ <description>Types that extend and augment the Java Collections Framework.</description>
+ <url>http://jakarta.apache.org/commons/collections/</url>
+ <issueManagement>
+ <url>http://issues.apache.org/bugzilla/</url>
+ </issueManagement>
+ <ciManagement>
+ <notifiers>
+ <notifier>
+ <configuration>
+ <address>commons-dev@jakarta.apache.org</address>
+ </configuration>
+ </notifier>
+ </notifiers>
+ </ciManagement>
+ <inceptionYear>2001</inceptionYear>
+ <mailingLists>
+ <mailingList>
+ <name>Commons Dev List</name>
+ <subscribe>commons-dev-subscribe@jakarta.apache.org</subscribe>
+ <unsubscribe>commons-dev-unsubscribe@jakarta.apache.org</unsubscribe>
+ <archive>http://mail-archives.apache.org/eyebrowse/SummarizeList?listName=commons-dev@jakarta.apache.org</archive>
+ </mailingList>
+ <mailingList>
+ <name>Commons User List</name>
+ <subscribe>commons-user-subscribe@jakarta.apache.org</subscribe>
+ <unsubscribe>commons-user-unsubscribe@jakarta.apache.org</unsubscribe>
+ <archive>http://mail-archives.apache.org/eyebrowse/SummarizeList?listName=commons-user@jakarta.apache.org</archive>
+ </mailingList>
+ </mailingLists>
+ <developers>
+ <developer>
+ <id>scolebourne</id>
+ <name>Stephen Colebourne</name>
+ <email></email>
+ <organization></organization>
+ </developer>
+ <developer>
+ <id>morgand</id>
+ <name>Morgan Delagrange</name>
+ <email></email>
+ <organization></organization>
+ </developer>
+ <developer>
+ <id>matth</id>
+ <name>Matthew Hawthorne</name>
+ <email></email>
+ <organization></organization>
+ </developer>
+ <developer>
+ <id>geirm</id>
+ <name>Geir Magnusson</name>
+ <email></email>
+ <organization></organization>
+ </developer>
+ <developer>
+ <id>craigmcc</id>
+ <name>Craig McClanahan</name>
+ <email></email>
+ <organization></organization>
+ </developer>
+ <developer>
+ <id>psteitz</id>
+ <name>Phil Steitz</name>
+ <email></email>
+ <organization></organization>
+ </developer>
+ <developer>
+ <id>amamment</id>
+ <name>Arun M. Thomas</name>
+ <email></email>
+ <organization></organization>
+ </developer>
+ <developer>
+ <id>rwaldhoff</id>
+ <name>Rodney Waldhoff</name>
+ <email></email>
+ <organization></organization>
+ </developer>
+ <developer>
+ <id>bayard</id>
+ <name>Henri Yandell</name>
+ <email></email>
+ <organization></organization>
+ </developer>
+ <developer>
+ <id>jcarman</id>
+ <name>James Carman</name>
+ <email></email>
+ <organization></organization>
+ </developer>
+ <developer>
+ <id>rdonkin</id>
+ <name>Robert Burrell Donkin</name>
+ </developer>
+ </developers>
+ <contributors>
+ <contributor>
+ <name>Rafael U. C. Afonso</name>
+ </contributor>
+ <contributor>
+ <name>Max Rydahl Andersen</name>
+ </contributor>
+ <contributor>
+ <name>Federico Barbieri</name>
+ </contributor>
+ <contributor>
+ <name>Arron Bates</name>
+ </contributor>
+ <contributor>
+ <name>Nicola Ken Barozzi</name>
+ </contributor>
+ <contributor>
+ <name>Sebastian Bazley</name>
+ </contributor>
+ <contributor>
+ <name>Matt Benson</name>
+ </contributor>
+ <contributor>
+ <name>Ola Berg</name>
+ </contributor>
+ <contributor>
+ <name>Christopher Berry</name>
+ </contributor>
+ <contributor>
+ <name>Nathan Beyer</name>
+ </contributor>
+ <contributor>
+ <name>Janek Bogucki</name>
+ </contributor>
+ <contributor>
+ <name>Chuck Burdick</name>
+ </contributor>
+ <contributor>
+ <name>Dave Bryson</name>
+ </contributor>
+ <contributor>
+ <name>Julien Buret</name>
+ </contributor>
+ <contributor>
+ <name>Jonathan Carlson</name>
+ </contributor>
+ <contributor>
+ <name>Ram Chidambaram</name>
+ </contributor>
+ <contributor>
+ <name>Steve Clark</name>
+ </contributor>
+ <contributor>
+ <name>Eric Crampton</name>
+ </contributor>
+ <contributor>
+ <name>Dimiter Dimitrov</name>
+ </contributor>
+ <contributor>
+ <name>Peter Donald</name>
+ </contributor>
+ <contributor>
+ <name>Steve Downey</name>
+ </contributor>
+ <contributor>
+ <name>Rich Dougherty</name>
+ </contributor>
+ <contributor>
+ <name>Tom Dunham</name>
+ </contributor>
+ <contributor>
+ <name>Stefano Fornari</name>
+ </contributor>
+ <contributor>
+ <name>Andrew Freeman</name>
+ </contributor>
+ <contributor>
+ <name>Gerhard Froehlich</name>
+ </contributor>
+ <contributor>
+ <name>Paul Jack</name>
+ </contributor>
+ <contributor>
+ <name>Eric Johnson</name>
+ </contributor>
+ <contributor>
+ <name>Kent Johnson</name>
+ </contributor>
+ <contributor>
+ <name>Marc Johnson</name>
+ </contributor>
+ <contributor>
+ <name>Nissim Karpenstein</name>
+ </contributor>
+ <contributor>
+ <name>Shinobu Kawai</name>
+ </contributor>
+ <contributor>
+ <name>Mohan Kishore</name>
+ </contributor>
+ <contributor>
+ <name>Simon Kitching</name>
+ </contributor>
+ <contributor>
+ <name>Thomas Knych</name>
+ </contributor>
+ <contributor>
+ <name>Serge Knystautas</name>
+ </contributor>
+ <contributor>
+ <name>Peter KoBek</name>
+ </contributor>
+ <contributor>
+ <name>Jordan Krey</name>
+ </contributor>
+ <contributor>
+ <name>Olaf Krische</name>
+ </contributor>
+ <contributor>
+ <name>Guilhem Lavaux</name>
+ </contributor>
+ <contributor>
+ <name>Paul Legato</name>
+ </contributor>
+ <contributor>
+ <name>David Leppik</name>
+ </contributor>
+ <contributor>
+ <name>Berin Loritsch</name>
+ </contributor>
+ <contributor>
+ <name>Stefano Mazzocchi</name>
+ </contributor>
+ <contributor>
+ <name>Brian McCallister</name>
+ </contributor>
+ <contributor>
+ <name>Steven Melzer</name>
+ </contributor>
+ <contributor>
+ <name>Leon Messerschmidt</name>
+ </contributor>
+ <contributor>
+ <name>Mauricio S. Moura</name>
+ </contributor>
+ <contributor>
+ <name>Kasper Nielsen</name>
+ </contributor>
+ <contributor>
+ <name>Stanislaw Osinski</name>
+ </contributor>
+ <contributor>
+ <name>Alban Peignier</name>
+ </contributor>
+ <contributor>
+ <name>Mike Pettypiece</name>
+ </contributor>
+ <contributor>
+ <name>Steve Phelps</name>
+ </contributor>
+ <contributor>
+ <name>Ilkka Priha</name>
+ </contributor>
+ <contributor>
+ <name>Jonas Van Poucke</name>
+ </contributor>
+ <contributor>
+ <name>Will Pugh</name>
+ </contributor>
+ <contributor>
+ <name>Herve Quiroz</name>
+ </contributor>
+ <contributor>
+ <name>Daniel Rall</name>
+ </contributor>
+ <contributor>
+ <name>Robert Ribnitz</name>
+ </contributor>
+ <contributor>
+ <name>Huw Roberts</name>
+ </contributor>
+ <contributor>
+ <name>Henning P. Schmiedehausen</name>
+ </contributor>
+ <contributor>
+ <name>Howard Lewis Ship</name>
+ </contributor>
+ <contributor>
+ <name>Joe Raysa</name>
+ </contributor>
+ <contributor>
+ <name>Thomas Schapitz</name>
+ </contributor>
+ <contributor>
+ <name>Jon Schewe</name>
+ </contributor>
+ <contributor>
+ <name>Andreas Schlosser</name>
+ </contributor>
+ <contributor>
+ <name>Christian Siefkes</name>
+ </contributor>
+ <contributor>
+ <name>Michael Smith</name>
+ </contributor>
+ <contributor>
+ <name>Stephen Smith</name>
+ </contributor>
+ <contributor>
+ <name>Jan Sorensen</name>
+ </contributor>
+ <contributor>
+ <name>Jon S. Stevens</name>
+ </contributor>
+ <contributor>
+ <name>James Strachan</name>
+ </contributor>
+ <contributor>
+ <name>Leo Sutic</name>
+ </contributor>
+ <contributor>
+ <name>Chris Tilden</name>
+ </contributor>
+ <contributor>
+ <name>Neil O'Toole</name>
+ </contributor>
+ <contributor>
+ <name>Jeff Turner</name>
+ </contributor>
+ <contributor>
+ <name>Kazuya Ujihara</name>
+ </contributor>
+ <contributor>
+ <name>Jeff Varszegi</name>
+ </contributor>
+ <contributor>
+ <name>Ralph Wagner</name>
+ </contributor>
+ <contributor>
+ <name>David Weinrich</name>
+ </contributor>
+ <contributor>
+ <name>Dieter Wimberger</name>
+ </contributor>
+ <contributor>
+ <name>Serhiy Yevtushenko</name>
+ </contributor>
+ <contributor>
+ <name>Jason van Zyl</name>
+ </contributor>
+ </contributors>
+ <licenses>
+ <license>
+ <name>The Apache Software License, Version 2.0</name>
+ <url>/LICENSE.txt</url>
+ </license>
+ </licenses>
+ <scm>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/jakarta/commons/proper/collections/trunk</connection>
+ <url>http://svn.apache.org/repos/asf/jakarta/commons/proper/collections/trunk</url>
+ </scm>
+ <organization>
+ <name>The Apache Software Foundation</name>
+ <url>http://jakarta.apache.org</url>
+ </organization>
+ <build>
+ <sourceDirectory>src/java</sourceDirectory>
+ <testSourceDirectory>src/test</testSourceDirectory>
+ <resources>
+ <resource>
+ <targetPath>META-INF</targetPath>
+ <directory>.</directory>
+ <includes>
+ <include>NOTICE.txt</include>
+ </includes>
+ </resource>
+ </resources>
+ <plugins>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>org/apache/commons/collections/TestAllPackages.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>maven-plugins</groupId>
+ <artifactId>maven-cobertura-plugin</artifactId>
+ <version>1.1.1</version>
+ <configuration>
+ <scope>test</scope>
+ <comment>Required only for generating test coverage reports.</comment>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <distributionManagement>
+ <repository>
+ <id>default</id>
+ <name>Default Repository</name>
+ <url>file:///www/jakarta.apache.org/builds/jakarta-commons/collections/</url>
+ </repository>
+ <site>
+ <id>default</id>
+ <name>Default Site</name>
+ <url>scp://people.apache.org//www/jakarta.apache.org/commons/collections/</url>
+ </site>
+ <status>converted</status>
+ </distributionManagement>
+</project> \ No newline at end of file
diff --git a/java/lib/poms/commons-configuration-1.6.pom b/java/lib/poms/commons-configuration-1.6.pom
new file mode 100644
index 0000000000..1597869b3a
--- /dev/null
+++ b/java/lib/poms/commons-configuration-1.6.pom
@@ -0,0 +1,419 @@
+<?xml version="1.0" encoding="UTF-8"?><project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>commons-configuration</groupId>
+ <artifactId>commons-configuration</artifactId>
+ <name>Commons Configuration</name>
+ <version>1.6</version>
+ <description>Tools to assist in the reading of configuration/preferences files in
+ various formats</description>
+ <url>http://commons.apache.org/${pom.artifactId.substring(8)}/</url>
+ <issueManagement>
+ <url>http://issues.apache.org/jira/browse/CONFIGURATION</url>
+ </issueManagement>
+ <ciManagement>
+ <notifiers>
+ <notifier>
+ <configuration>
+ <address>dev@commons.apache.org</address>
+ </configuration>
+ </notifier>
+ </notifiers>
+ </ciManagement>
+ <inceptionYear>2001</inceptionYear>
+ <mailingLists>
+ <mailingList>
+ <name>Commons Dev List</name>
+ <subscribe>dev-subscribe@commons.apache.org</subscribe>
+ <unsubscribe>dev-unsubscribe@commons.apache.org</unsubscribe>
+ <archive>http://mail-archives.apache.org/mod_mbox/commons-dev/</archive>
+ </mailingList>
+ <mailingList>
+ <name>Commons User List</name>
+ <subscribe>user-subscribe@commons.apache.org</subscribe>
+ <unsubscribe>user-unsubscribe@commons.apache.org</unsubscribe>
+ <archive>http://mail-archives.apache.org/mod_mbox/commons-user/</archive>
+ </mailingList>
+ </mailingLists>
+ <developers>
+ <developer>
+ <id>dlr</id>
+ <name>Daniel Rall</name>
+ <email>dlr@finemaltcoding.com</email>
+ <organization>CollabNet, Inc.</organization>
+ </developer>
+ <developer>
+ <id>jvanzyl</id>
+ <name>Jason van Zyl</name>
+ <email>jason@zenplex.com</email>
+ <organization>Zenplex</organization>
+ </developer>
+ <developer>
+ <id>mpoeschl</id>
+ <name>Martin Poeschl</name>
+ <email>mpoeschl@marmot.at</email>
+ <organization>tucana.at</organization>
+ </developer>
+ <developer>
+ <id>dion</id>
+ <name>dIon Gillard</name>
+ <email>dion@multitask.com.au</email>
+ <organization>Multitask Consulting</organization>
+ </developer>
+ <developer>
+ <id>henning</id>
+ <name>Henning P. Schmiedehausen</name>
+ <email>hps@intermeta.de</email>
+ <organization>INTERMETA - Gesellschaft fuer Mehrwertdienste mbH</organization>
+ <timezone>2</timezone>
+ </developer>
+ <developer>
+ <id>epugh</id>
+ <name>Eric Pugh</name>
+ <email>epugh@upstate.com</email>
+ <organization>upstate.com</organization>
+ </developer>
+ <developer>
+ <id>bdunbar</id>
+ <name>Brian E. Dunbar</name>
+ <email>bdunbar@dunbarconsulting.org</email>
+ <organization>dunbarconsulting.org</organization>
+ </developer>
+ <developer>
+ <id>ebourg</id>
+ <name>Emmanuel Bourg</name>
+ <email>ebourg@apache.org</email>
+ <organization>Ariane Software</organization>
+ <timezone>+1</timezone>
+ </developer>
+ <developer>
+ <id>oheger</id>
+ <name>Oliver Heger</name>
+ <email>oheger@apache.org</email>
+ <organization>Agfa HealthCare</organization>
+ <timezone>+1</timezone>
+ </developer>
+ <developer>
+ <id>joehni</id>
+ <name>Jörg Schaible</name>
+ <email>joerg.schaible@gmx.de</email>
+ <timezone>+1</timezone>
+ </developer>
+ </developers>
+ <contributors>
+ <contributor>
+ <name>Konstantin Shaposhnikov</name>
+ <email>ksh@scand.com</email>
+ <organization>scand.com</organization>
+ </contributor>
+ <contributor>
+ <name>Jamie M. Guillemette</name>
+ <email>JMGuillemette@gmail.com</email>
+ <organization>TD Bank</organization>
+ </contributor>
+ <contributor>
+ <name>Jorge Ferrer</name>
+ <email>jorge.ferrer@gmail.com</email>
+ <organization></organization>
+ </contributor>
+ <contributor>
+ <name>Gabriele Garuglieri</name>
+ <email>gabriele.garuglieri@infoblu.it</email>
+ <organization>Infoblu S.p.A</organization>
+ </contributor>
+ <contributor>
+ <name>Nicolas De Loof</name>
+ <email>nicolas.deloof@gmail.com</email>
+ <organization>Cap Gemini</organization>
+ </contributor>
+ </contributors>
+ <licenses>
+ <license>
+ <name>The Apache Software License, Version 2.0</name>
+ <url>/LICENSE.txt</url>
+ </license>
+ </licenses>
+ <scm>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/${pom.artifactId.substring(8)}/trunk</connection>
+ <url>http://svn.apache.org/repos/asf/commons/proper/${pom.artifactId.substring(8)}/trunk</url>
+ </scm>
+ <organization>
+ <name>The Apache Software Foundation</name>
+ <url>http://commons.apache.org/</url>
+ </organization>
+ <build>
+ <sourceDirectory>src/java</sourceDirectory>
+ <testSourceDirectory>src/test</testSourceDirectory>
+ <resources>
+ <resource>
+ <directory>conf</directory>
+ <includes>
+ <include>digesterRules.xml</include>
+ <include>properties.dtd</include>
+ <include>PropertyList-1.0.dtd</include>
+ </includes>
+ </resource>
+ <resource>
+ <targetPath>META-INF</targetPath>
+ <directory>${basedir}</directory>
+ <includes>
+ <include>NOTICE.txt</include>
+ </includes>
+ </resource>
+ </resources>
+ <testResources>
+ <testResource>
+ <directory>conf</directory>
+ <includes>
+ <include>*.xml</include>
+ </includes>
+ </testResource>
+ <testResource>
+ <directory>conf</directory>
+ <includes>
+ <include>testClasspath.properties</include>
+ <include>testdb.script</include>
+ <include>*.properties</include>
+ <include>*.dtd</include>
+ </includes>
+ </testResource>
+ <testResource>
+ <targetPath>org/apache/commons/configuration</targetPath>
+ <directory>conf</directory>
+ <includes>
+ <include>test.properties</include>
+ <include>include.properties</include>
+ </includes>
+ </testResource>
+ <testResource>
+ <targetPath>config</targetPath>
+ <directory>conf/config</directory>
+ <includes>
+ <include>**/*.properties</include>
+ </includes>
+ </testResource>
+ </testResources>
+ <plugins>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>**/*Test*.java</include>
+ </includes>
+ <excludes>
+ <exclude>**/TestBasePropertiesConfiguration.java</exclude>
+ <exclude>**/NonStringTestHolder.java</exclude>
+ <exclude>**/TestAbstractConfiguration.java</exclude>
+ <exclude>**/AbstractXPathTest.java</exclude>
+ <exclude>**/AbstractCombinerTest.java</exclude>
+ <exclude>**/AbstractTestConfigurationEvents.java</exclude>
+ <exclude>**/AbstractTestFileConfigurationEvents.java</exclude>
+ <exclude>**/AbstractTestPListEvents.java</exclude>
+ <exclude>**/InterpolationTestHelper.java</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>maven-plugins</groupId>
+ <artifactId>maven-tasks-plugin</artifactId>
+ <version>1.1.0</version>
+ <configuration />
+ </plugin>
+ <plugin>
+ <groupId>maven-plugins</groupId>
+ <artifactId>maven-findbugs-plugin</artifactId>
+ <version>1.4</version>
+ <configuration />
+ </plugin>
+ <plugin>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>3.0.1</version>
+ <configuration />
+ </plugin>
+ <plugin>
+ <groupId>maven-plugins</groupId>
+ <artifactId>maven-cobertura-plugin</artifactId>
+ <version>1.2</version>
+ <configuration />
+ </plugin>
+ <plugin>
+ <artifactId>maven-changes-plugin</artifactId>
+ <version>1.6</version>
+ <configuration>
+ <comment>&lt;strong>Site Only&lt;/strong> - v1.6 (minimum)
+ required for building the site documentation.</comment>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-xdoc-plugin</artifactId>
+ <version>1.8</version>
+ <configuration>
+ <comment>&lt;strong>Site Only&lt;/strong> - v1.8 (minimum)
+ required for building the site documentation.</comment>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-scm-plugin</artifactId>
+ <version>1.5</version>
+ <configuration>
+ <comment>&lt;strong>Site Only&lt;/strong> - v1.5 (minimum)</comment>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-jdiff-plugin</artifactId>
+ <version>1.5</version>
+ <configuration>
+ <comment>&lt;strong>Site Only&lt;/strong> - v1.5 (minimum)</comment>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>1.8</version>
+ <configuration>
+ <comment>&lt;strong>Site Only&lt;/strong> - v1.8 (minimum)</comment>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ <version>3.2.1</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>2.4</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <version>1.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-digester</groupId>
+ <artifactId>commons-digester</artifactId>
+ <version>1.8</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-beanutils</groupId>
+ <artifactId>commons-beanutils-core</artifactId>
+ <version>1.8.0</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ <version>1.3</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>commons-jxpath</groupId>
+ <artifactId>commons-jxpath</artifactId>
+ <version>1.3</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>xerces</groupId>
+ <artifactId>xercesImpl</artifactId>
+ <version>2.3.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>xalan</groupId>
+ <artifactId>xalan</artifactId>
+ <version>2.7.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>xml-apis</groupId>
+ <artifactId>xml-apis</artifactId>
+ <version>1.0.b2</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.4</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>javax.mail</groupId>
+ <artifactId>mail</artifactId>
+ <version>1.4</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>ant</groupId>
+ <artifactId>ant</artifactId>
+ <version>1.6.5</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>commons-dbcp</groupId>
+ <artifactId>commons-dbcp</artifactId>
+ <version>1.2.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>commons-pool</groupId>
+ <artifactId>commons-pool</artifactId>
+ <version>1.4</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>hsqldb</groupId>
+ <artifactId>hsqldb</artifactId>
+ <version>1.7.2.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>dbunit</groupId>
+ <artifactId>dbunit</artifactId>
+ <version>2.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit-addons</groupId>
+ <artifactId>junit-addons</artifactId>
+ <version>1.4</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>mockobjects</groupId>
+ <artifactId>mockobjects-core</artifactId>
+ <version>0.09</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>mockobjects</groupId>
+ <artifactId>mockobjects-jdk1.4-j2ee1.3</artifactId>
+ <version>0.09</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.8</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <distributionManagement>
+ <repository>
+ <id>default</id>
+ <name>Default Repository</name>
+ <url>www.apache.org//www/www.apache.org/dist/java-repository/</url>
+ </repository>
+ <site>
+ <id>default</id>
+ <name>Default Site</name>
+ <url>scp://people.apache.org//www/commons.apache.org/${pom.artifactId.substring(8)}/</url>
+ </site>
+ <status>converted</status>
+ </distributionManagement>
+</project> \ No newline at end of file
diff --git a/java/lib/poms/commons-digester-1.8.1.pom b/java/lib/poms/commons-digester-1.8.1.pom
new file mode 100644
index 0000000000..5470526527
--- /dev/null
+++ b/java/lib/poms/commons-digester-1.8.1.pom
@@ -0,0 +1,316 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+<!-- TODO:
+* include dtds as resources
+* build src jars
+-->
+
+ <parent>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-parent</artifactId>
+ <version>11</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <name>Commons Digester</name>
+ <groupId>commons-digester</groupId>
+ <artifactId>commons-digester</artifactId>
+ <version>1.8.1</version>
+
+ <inceptionYear>2001</inceptionYear>
+ <description>
+ The Digester package lets you configure an XML to Java object mapping module
+ which triggers certain actions called rules whenever a particular
+ pattern of nested XML elements is recognized.
+ </description>
+
+ <url>http://commons.apache.org/digester/</url>
+
+ <issueManagement>
+ <system>jira</system>
+ <url>http://issues.apache.org/jira/browse/DIGESTER</url>
+ </issueManagement>
+
+ <scm>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/digester/tags/DIGESTER_1_8_1</connection>
+ <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/digester/tags/DIGESTER_1_8_1</developerConnection>
+ <url>http://svn.apache.org/viewvc/commons/proper/digester/tags/DIGESTER_1_8_1</url>
+ </scm>
+
+ <developers>
+ <developer>
+ <name>Craig McClanahan</name>
+ <id>craigmcc</id>
+ <email>craigmcc@apache.org</email>
+ </developer>
+ <developer>
+ <name>Robert Burrell Donkin</name>
+ <id>rdonkin</id>
+ <email>rdonkin@apache.org</email>
+ </developer>
+ <developer>
+ <name>Scott Sanders</name>
+ <id>sanders</id>
+ <email>sanders@totalsync.com</email>
+ </developer>
+ <developer>
+ <name>James Strachan</name>
+ <id>jstrachan</id>
+ <email>jstrachan@apache.org</email>
+ </developer>
+ <developer>
+ <name>Jason van Zyl</name>
+ <id>jvanzyl</id>
+ <email>jvanzyl@apache.org</email>
+ </developer>
+ <developer>
+ <name>Tim OBrien</name>
+ <id>tobrien</id>
+ <email>tobrien@apache.org</email>
+ </developer>
+ <developer>
+ <name>Jean-Francois Arcand</name>
+ <id>jfarcand</id>
+ <email>jfarcand@apache.org</email>
+ </developer>
+ <developer>
+ <name>Simon Kitching</name>
+ <id>skitching</id>
+ <email>skitching@apache.org</email>
+ </developer>
+ <developer>
+ <name>Rahul Akolkar</name>
+ <id>rahul</id>
+ <email>rahul AT apache DOT org</email>
+ </developer>
+ </developers>
+
+ <contributors>
+ <contributor>
+ <name>Bradley M. Handy</name>
+ <email>bhandy@users.sf.net</email>
+ </contributor>
+ <contributor>
+ <name>Christopher Lenz</name>
+ </contributor>
+ <contributor>
+ <name>Ted Husted</name>
+ </contributor>
+ <contributor>
+ <name>David H. Martin</name>
+ </contributor>
+ <contributor>
+ <name>Henri Chen</name>
+ </contributor>
+ <contributor>
+ <name>Janek Bogucki</name>
+ </contributor>
+ <contributor>
+ <name>Mark Huisman</name>
+ </contributor>
+ <contributor>
+ <name>Paul Jack</name>
+ </contributor>
+ <contributor>
+ <name>Anton Maslovsky</name>
+ </contributor>
+ <contributor>
+ <name>Matt Cleveland</name>
+ </contributor>
+ <contributor>
+ <name>Gabriele Carcassi</name>
+ </contributor>
+ <contributor>
+ <name>Wendy Smoak</name>
+ <email>java@wendysmoak.com</email>
+ </contributor>
+ <contributor>
+ <name>Kevin Ross</name>
+ <email>kevin.ross@iverticalleap.com</email>
+ </contributor>
+ </contributors>
+
+ <distributionManagement>
+ <!-- Cannot define in parent ATM, see COMMONSSITE-26 -->
+ <site>
+ <id>apache.website</id>
+ <name>Apache Commons Site</name>
+ <url>${commons.deployment.protocol}://people.apache.org/www/commons.apache.org/digester</url>
+ </site>
+ </distributionManagement>
+
+ <properties>
+ <maven.compile.source>1.2</maven.compile.source>
+ <maven.compile.target>1.2</maven.compile.target>
+ <commons.componentid>digester</commons.componentid>
+ <commons.release.version>1.8.1</commons.release.version>
+ <commons.rc.version>RC1</commons.rc.version>
+ <commons.jira.id>DIGESTER</commons.jira.id>
+ <commons.jira.pid>12310471</commons.jira.pid>
+ </properties>
+
+ <build>
+ <sourceDirectory>src/java</sourceDirectory>
+ <testSourceDirectory>src/test</testSourceDirectory>
+
+ <resources>
+ <resource>
+ <directory>.</directory>
+ <targetPath>META-INF</targetPath>
+ <includes>
+ <include>NOTICE.txt</include>
+ <include>LICENSE.txt</include>
+ </includes>
+ </resource>
+ <resource>
+ <directory>src/java</directory>
+ <filtering>false</filtering>
+ <includes>
+ <include>**/*.dtd</include>
+ </includes>
+ </resource>
+ </resources>
+
+ <testResources>
+ <testResource>
+ <directory>src/test</directory>
+ <filtering>false</filtering>
+ <includes>
+ <include>**/*.xml</include>
+ </includes>
+ </testResource>
+ </testResources>
+
+ <plugins>
+ <plugin>
+ <!--
+ - A number of the pre-maven test case "suport" classes have names starting with Test.
+ - This confuses the maven surefire "auto-detect test case" functionality, so we
+ - need to manually exclude them.
+ -->
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>**/TestBean.java</exclude>
+ <exclude>**/TestRule.java</exclude>
+ <exclude>**/TestRuleSet.java</exclude>
+ <exclude>**/Test*$*.java</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <configuration>
+ <descriptors>
+ <descriptor>src/assembly/bin.xml</descriptor>
+ <descriptor>src/assembly/src.xml</descriptor>
+ </descriptors>
+ <tarLongFileMode>gnu</tarLongFileMode>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>commons-beanutils</groupId>
+ <artifactId>commons-beanutils</artifactId>
+ <version>1.8.0</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <version>1.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>xml-apis</groupId>
+ <artifactId>xml-apis</artifactId>
+ <version>1.0.b2</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-changes-plugin</artifactId>
+ <version>2.0</version>
+ <configuration>
+ <issueLinkTemplate>%URL%/../%ISSUE%</issueLinkTemplate>
+ </configuration>
+ <reportSets>
+ <reportSet>
+ <reports>
+ <report>changes-report</report>
+ <report>jira-report</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>2.1</version>
+ <configuration>
+ <configLocation>${basedir}/checkstyle.xml</configLocation>
+ <enableRulesSummary>false</enableRulesSummary>
+ <headerFile>${basedir}/file-header.txt</headerFile>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-pmd-plugin</artifactId>
+ <version>2.3</version>
+ <!--Use default rules-->
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>clirr-maven-plugin</artifactId>
+ <version>2.2.1</version>
+ <configuration>
+ <comparisonVersion>1.8</comparisonVersion>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
+
+ <profiles>
+ <profile>
+ <id>rc</id>
+ <distributionManagement>
+ <!-- Cannot define in parent ATM, see COMMONSSITE-26 -->
+ <site>
+ <id>apache.website</id>
+ <name>Apache Commons Release Candidate Staging Site</name>
+ <url>${commons.deployment.protocol}://people.apache.org/www/people.apache.org/builds/commons/${commons.componentid}/${commons.release.version}/${commons.rc.version}/site</url>
+ </site>
+ </distributionManagement>
+ </profile>
+ </profiles>
+
+</project>
diff --git a/java/lib/poms/commons-lang-2.2.pom b/java/lib/poms/commons-lang-2.2.pom
new file mode 100644
index 0000000000..9337a4374b
--- /dev/null
+++ b/java/lib/poms/commons-lang-2.2.pom
@@ -0,0 +1,414 @@
+<?xml version="1.0" encoding="UTF-8"?><project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <name>Lang</name>
+ <version>2.2</version>
+ <description>Commons.Lang, a package of Java utility classes for the
+ classes that are in java.lang's hierarchy, or are considered to be so
+ standard as to justify existence in java.lang.</description>
+ <url>http://jakarta.apache.org/commons/lang/</url>
+ <issueManagement>
+ <url>http://issues.apache.org/jira/</url>
+ </issueManagement>
+ <ciManagement>
+ <notifiers>
+ <notifier>
+ <configuration>
+ <address>commons-dev@jakarta.apache.org</address>
+ </configuration>
+ </notifier>
+ </notifiers>
+ </ciManagement>
+ <inceptionYear>2001</inceptionYear>
+ <mailingLists>
+ <mailingList>
+ <name>Commons Dev List</name>
+ <subscribe>commons-dev-subscribe@jakarta.apache.org</subscribe>
+ <unsubscribe>commons-dev-unsubscribe@jakarta.apache.org</unsubscribe>
+ <archive>http://mail-archives.apache.org/eyebrowse/SummarizeList?listName=commons-dev@jakarta.apache.org</archive>
+ </mailingList>
+ <mailingList>
+ <name>Commons User List</name>
+ <subscribe>commons-user-subscribe@jakarta.apache.org</subscribe>
+ <unsubscribe>commons-user-unsubscribe@jakarta.apache.org</unsubscribe>
+ <archive>http://mail-archives.apache.org/eyebrowse/SummarizeList?listName=commons-user@jakarta.apache.org</archive>
+ </mailingList>
+ </mailingLists>
+ <developers>
+ <developer>
+ <id>dlr</id>
+ <name>Daniel Rall</name>
+ <email>dlr@finemaltcoding.com</email>
+ <organization>CollabNet, Inc.</organization>
+ <roles>
+ <role>Java Developer</role>
+ </roles>
+ </developer>
+ <developer>
+ <id>scolebourne</id>
+ <name>Stephen Colebourne</name>
+ <email>scolebourne@joda.org</email>
+ <organization>SITA ATS Ltd</organization>
+ <roles>
+ <role>Java Developer</role>
+ </roles>
+ <timezone>0</timezone>
+ </developer>
+ <developer>
+ <id>bayard</id>
+ <name>Henri Yandell</name>
+ <email>bayard@generationjava.com</email>
+ <organization></organization>
+ <roles>
+ <role>Java Developer</role>
+ </roles>
+ </developer>
+ <developer>
+ <id>scaswell</id>
+ <name>Steven Caswell</name>
+ <email>stevencaswell@apache.org</email>
+ <organization></organization>
+ <roles>
+ <role>Java Developer</role>
+ </roles>
+ <timezone>-5</timezone>
+ </developer>
+ <developer>
+ <id>rdonkin</id>
+ <name>Robert Burrell Donkin</name>
+ <email>rdonkin@apache.org</email>
+ <organization></organization>
+ <roles>
+ <role>Java Developer</role>
+ </roles>
+ </developer>
+ <developer>
+ <id>ggregory</id>
+ <name>Gary D. Gregory</name>
+ <email>ggregory@seagullsw.com</email>
+ <organization>Seagull Software</organization>
+ <roles>
+ <role>Java Developer</role>
+ </roles>
+ <timezone>-8</timezone>
+ </developer>
+ <developer>
+ <id>psteitz</id>
+ <name>Phil Steitz</name>
+ <email>phil@steitz.com</email>
+ <organization></organization>
+ <roles>
+ <role>Java Developer</role>
+ </roles>
+ </developer>
+ <developer>
+ <id>fredrik</id>
+ <name>Fredrik Westermarck</name>
+ <email></email>
+ <organization></organization>
+ <roles>
+ <role>Java Developer</role>
+ </roles>
+ </developer>
+ <developer>
+ <id>jcarman</id>
+ <name>James Carman</name>
+ <email>jcarman@apache.org</email>
+ <organization>Carman Consulting, Inc.</organization>
+ <roles>
+ <role>Java Developer</role>
+ </roles>
+ </developer>
+ </developers>
+ <contributors>
+ <contributor>
+ <name>C. Scott Ananian</name>
+ </contributor>
+ <contributor>
+ <name>Chris Audley</name>
+ </contributor>
+ <contributor>
+ <name>Stephane Bailliez</name>
+ </contributor>
+ <contributor>
+ <name>Michael Becke</name>
+ </contributor>
+ <contributor>
+ <name>Ola Berg</name>
+ </contributor>
+ <contributor>
+ <name>Nathan Beyer</name>
+ </contributor>
+ <contributor>
+ <name>Stefan Bodewig</name>
+ </contributor>
+ <contributor>
+ <name>Janek Bogucki</name>
+ </contributor>
+ <contributor>
+ <name>Mike Bowler</name>
+ </contributor>
+ <contributor>
+ <name>Sean Brown</name>
+ </contributor>
+ <contributor>
+ <name>Alexander Day Chaffee</name>
+ </contributor>
+ <contributor>
+ <name>Al Chou</name>
+ </contributor>
+ <contributor>
+ <name>Greg Coladonato</name>
+ </contributor>
+ <contributor>
+ <name>Maarten Coene</name>
+ </contributor>
+ <contributor>
+ <name>Justin Couch</name>
+ </contributor>
+ <contributor>
+ <name>Michael Davey</name>
+ </contributor>
+ <contributor>
+ <name>Norm Deane</name>
+ </contributor>
+ <contributor>
+ <name>Ringo De Smet</name>
+ </contributor>
+ <contributor>
+ <name>Russel Dittmar</name>
+ </contributor>
+ <contributor>
+ <name>Steve Downey</name>
+ </contributor>
+ <contributor>
+ <name>Matthias Eichel</name>
+ </contributor>
+ <contributor>
+ <name>Christopher Elkins</name>
+ </contributor>
+ <contributor>
+ <name>Chris Feldhacker</name>
+ </contributor>
+ <contributor>
+ <name>Pete Gieser</name>
+ </contributor>
+ <contributor>
+ <name>Jason Gritman</name>
+ </contributor>
+ <contributor>
+ <name>Matthew Hawthorne</name>
+ </contributor>
+ <contributor>
+ <name>Michael Heuer</name>
+ </contributor>
+ <contributor>
+ <name>Oliver Heger</name>
+ </contributor>
+ <contributor>
+ <name>Chris Hyzer</name>
+ </contributor>
+ <contributor>
+ <name>Marc Johnson</name>
+ </contributor>
+ <contributor>
+ <name>Shaun Kalley</name>
+ </contributor>
+ <contributor>
+ <name>Tetsuya Kaneuchi</name>
+ </contributor>
+ <contributor>
+ <name>Nissim Karpenstein</name>
+ </contributor>
+ <contributor>
+ <name>Ed Korthof</name>
+ </contributor>
+ <contributor>
+ <name>Holger Krauth</name>
+ </contributor>
+ <contributor>
+ <name>Rafal Krupinski</name>
+ </contributor>
+ <contributor>
+ <name>Rafal Krzewski</name>
+ </contributor>
+ <contributor>
+ <name>Craig R. McClanahan</name>
+ </contributor>
+ <contributor>
+ <name>Rand McNeely</name>
+ </contributor>
+ <contributor>
+ <name>Nikolay Metchev</name>
+ </contributor>
+ <contributor>
+ <name>Kasper Nielsen</name>
+ </contributor>
+ <contributor>
+ <name>Tim O'Brien</name>
+ </contributor>
+ <contributor>
+ <name>Brian S O'Neill</name>
+ </contributor>
+ <contributor>
+ <name>Andrew C. Oliver</name>
+ </contributor>
+ <contributor>
+ <name>Alban Peignier</name>
+ </contributor>
+ <contributor>
+ <name>Moritz Petersen</name>
+ </contributor>
+ <contributor>
+ <name>Dmitri Plotnikov</name>
+ </contributor>
+ <contributor>
+ <name>Neeme Praks</name>
+ </contributor>
+ <contributor>
+ <name>Eric Pugh</name>
+ </contributor>
+ <contributor>
+ <name>Stephen Putman</name>
+ </contributor>
+ <contributor>
+ <name>Travis Reeder</name>
+ </contributor>
+ <contributor>
+ <name>Antony Riley</name>
+ </contributor>
+ <contributor>
+ <name>Scott Sanders</name>
+ </contributor>
+ <contributor>
+ <name>Ralph Schaer</name>
+ </contributor>
+ <contributor>
+ <name>Henning P. Schmiedehausen</name>
+ </contributor>
+ <contributor>
+ <name>Sean Schofield</name>
+ </contributor>
+ <contributor>
+ <name>Reuben Sivan</name>
+ </contributor>
+ <contributor>
+ <name>Ville Skytta</name>
+ </contributor>
+ <contributor>
+ <name>Jan Sorensen</name>
+ </contributor>
+ <contributor>
+ <name>Glen Stampoultzis</name>
+ </contributor>
+ <contributor>
+ <name>Scott Stanchfield</name>
+ </contributor>
+ <contributor>
+ <name>Jon S. Stevens</name>
+ </contributor>
+ <contributor>
+ <name>Sean C. Sullivan</name>
+ </contributor>
+ <contributor>
+ <name>Ashwin Suresh</name>
+ </contributor>
+ <contributor>
+ <name>Helge Tesgaard</name>
+ </contributor>
+ <contributor>
+ <name>Arun Mammen Thomas</name>
+ </contributor>
+ <contributor>
+ <name>Masato Tezuka</name>
+ </contributor>
+ <contributor>
+ <name>Jeff Varszegi</name>
+ </contributor>
+ <contributor>
+ <name>Chris Webb</name>
+ </contributor>
+ <contributor>
+ <name>Mario Winterer</name>
+ </contributor>
+ </contributors>
+ <licenses>
+ <license>
+ <name>The Apache Software License, Version 2.0</name>
+ <url>/LICENSE.txt</url>
+ </license>
+ </licenses>
+ <scm>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk</connection>
+ <url>http://svn.apache.org/viewvc/jakarta/commons/proper/lang/trunk</url>
+ </scm>
+ <organization>
+ <name>The Apache Software Foundation</name>
+ <url>http://jakarta.apache.org</url>
+ </organization>
+ <build>
+ <sourceDirectory>src/java</sourceDirectory>
+ <testSourceDirectory>src/test</testSourceDirectory>
+ <resources>
+ <resource>
+ <targetPath>META-INF</targetPath>
+ <directory>.</directory>
+ <includes>
+ <include>NOTICE.txt</include>
+ </includes>
+ </resource>
+ </resources>
+ <testResources>
+ <testResource>
+ <directory>${pom.build.unitTestSourceDirectory}</directory>
+ <includes>
+ <include>**/*.xml</include>
+ </includes>
+ </testResource>
+ </testResources>
+ <plugins>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>**/*TestSuite.java</include>
+ </includes>
+ <excludes>
+ <exclude>**/AllLangTestSuite.java</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>maven-plugins</groupId>
+ <artifactId>maven-cobertura-plugin</artifactId>
+ <version>1.1.1</version>
+ <configuration>
+ <scope>test</scope>
+ <comment>Required only for generating test coverage reports.</comment>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <distributionManagement>
+ <repository>
+ <id>default</id>
+ <name>Default Repository</name>
+ <url>file:///www/jakarta.apache.org/builds/jakarta-commons/lang/</url>
+ </repository>
+ <site>
+ <id>default</id>
+ <name>Default Site</name>
+ <url>scp://people.apache.org//www/jakarta.apache.org/commons/lang/</url>
+ </site>
+ <status>converted</status>
+ </distributionManagement>
+</project> \ No newline at end of file
diff --git a/java/lib/poms/commons-logging-1.0.4.pom b/java/lib/poms/commons-logging-1.0.4.pom
new file mode 100644
index 0000000000..7c1017dc2a
--- /dev/null
+++ b/java/lib/poms/commons-logging-1.0.4.pom
@@ -0,0 +1,165 @@
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <name>Logging</name>
+ <version>1.0.4</version>
+ <description>Commons Logging is a thin adapter allowing configurable bridging to other,
+ well known logging systems.</description>
+ <url>http://jakarta.apache.org/commons/logging/</url>
+ <issueManagement>
+ <url>http://issues.apache.org/bugzilla/</url>
+ </issueManagement>
+ <ciManagement>
+ <notifiers>
+ <notifier>
+ <configuration>
+ <address>commons-dev@jakarta.apache.org</address>
+ </configuration>
+ </notifier>
+ </notifiers>
+ </ciManagement>
+ <inceptionYear>2001</inceptionYear>
+ <mailingLists>
+ <mailingList>
+ <name>Commons Dev List</name>
+ <subscribe>commons-dev-subscribe@jakarta.apache.org</subscribe>
+ <unsubscribe>commons-dev-unsubscribe@jakarta.apache.org</unsubscribe>
+ <archive>http://nagoya.apache.org/eyebrowse/SummarizeList?listName=commons-dev@jakarta.apache.org</archive>
+ </mailingList>
+ <mailingList>
+ <name>Commons User List</name>
+ <subscribe>commons-user-subscribe@jakarta.apache.org</subscribe>
+ <unsubscribe>commons-user-unsubscribe@jakarta.apache.org</unsubscribe>
+ <archive>http://nagoya.apache.org/eyebrowse/SummarizeList?listName=commons-user@jakarta.apache.org</archive>
+ </mailingList>
+ </mailingLists>
+ <developers>
+ <developer>
+ <id>morgand</id>
+ <name>Morgan Delagrange</name>
+ <email>morgand at apache dot org</email>
+ <organization>Apache</organization>
+ <roles>
+ <role>Java Developer</role>
+ </roles>
+ </developer>
+ <developer>
+ <id>rwaldhoff</id>
+ <name>Rodney Waldhoff</name>
+ <email>rwaldhoff at apache org</email>
+ <organization>Apache Software Foundation</organization>
+ </developer>
+ <developer>
+ <id>craigmcc</id>
+ <name>Craig McClanahan</name>
+ <email>craigmcc at apache org</email>
+ <organization>Apache Software Foundation</organization>
+ </developer>
+ <developer>
+ <id>sanders</id>
+ <name>Scott Sanders</name>
+ <email>sanders at apache dot org</email>
+ <organization>Apache Software Foundation</organization>
+ </developer>
+ <developer>
+ <id>rdonkin</id>
+ <name>Robert Burrell Donkin</name>
+ <email>rdonkin at apache dot org</email>
+ <organization>Apache Software Foundation</organization>
+ </developer>
+ <developer>
+ <id>donaldp</id>
+ <name>Peter Donald</name>
+ <email>donaldp at apache dot org</email>
+ <organization></organization>
+ </developer>
+ <developer>
+ <id>costin</id>
+ <name>Costin Manolache</name>
+ <email>costin at apache dot org</email>
+ <organization>Apache Software Foundation</organization>
+ </developer>
+ <developer>
+ <id>rsitze</id>
+ <name>Richard Sitze</name>
+ <email>rsitze at apache dot org</email>
+ <organization>Apache Software Foundation</organization>
+ </developer>
+ <developer>
+ <id>baliuka</id>
+ <name>Juozas Baliuka</name>
+ <email>baliuka@apache.org</email>
+ <organization></organization>
+ <roles>
+ <role>Java Developer</role>
+ </roles>
+ </developer>
+ </developers>
+ <licenses>
+ <license>
+ <name>The Apache Software License, Version 2.0</name>
+ <url>/LICENSE.txt</url>
+ </license>
+ </licenses>
+ <scm>
+ <connection>scm:cvs:pserver:anoncvs@cvs.apache.org:/home/cvspublic:jakarta-commons/logging</connection>
+ <url>http://cvs.apache.org/viewcvs/jakarta-commons/logging/</url>
+ </scm>
+ <organization>
+ <name>The Apache Software Foundation</name>
+ <url>http://jakarta.apache.org</url>
+ </organization>
+ <build>
+ <sourceDirectory>src/java</sourceDirectory>
+ <testSourceDirectory>src/test</testSourceDirectory>
+ <plugins>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>**/AvalonLoggerTest.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.6</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>logkit</groupId>
+ <artifactId>logkit</artifactId>
+ <version>1.0.1</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.7</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>avalon-framework</groupId>
+ <artifactId>avalon-framework</artifactId>
+ <version>4.1.3</version>
+ <optional>true</optional>
+ </dependency>
+ </dependencies>
+ <distributionManagement>
+ <repository>
+ <id>default</id>
+ <name>Default Repository</name>
+ <url>file:///www/jakarta.apache.org/builds/jakarta-commons/logging/</url>
+ </repository>
+ <site>
+ <id>default</id>
+ <name>Default Site</name>
+ <url>scp://jakarta.apache.org//www/jakarta.apache.org/commons/logging/</url>
+ </site>
+ </distributionManagement>
+</project>
diff --git a/java/lib/poms/commons-pool-1.4.pom b/java/lib/poms/commons-pool-1.4.pom
new file mode 100644
index 0000000000..3dd87ae576
--- /dev/null
+++ b/java/lib/poms/commons-pool-1.4.pom
@@ -0,0 +1,209 @@
+<?xml version="1.0" encoding="UTF-8"?><project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>commons-pool</groupId>
+ <artifactId>commons-pool</artifactId>
+ <name>Commons Pool</name>
+ <version>1.4</version>
+ <description>Commons Object Pooling Library</description>
+ <url>http://commons.apache.org/pool/</url>
+ <issueManagement>
+ <url>http://issues.apache.org/jira/</url>
+ </issueManagement>
+ <ciManagement>
+ <notifiers>
+ <notifier>
+ <configuration>
+ <address>dev@commons.apache.org</address>
+ </configuration>
+ </notifier>
+ </notifiers>
+ </ciManagement>
+ <inceptionYear>2001</inceptionYear>
+ <mailingLists>
+ <mailingList>
+ <name>Commons Dev List</name>
+ <subscribe>dev-subscribe@commons.apache.org</subscribe>
+ <unsubscribe>dev-unsubscribe@commons.apache.org</unsubscribe>
+ <archive>http://mail-archives.apache.org/mod_mbox/commons-dev/</archive>
+ </mailingList>
+ <mailingList>
+ <name>Commons User List</name>
+ <subscribe>user-subscribe@commons.apache.org</subscribe>
+ <unsubscribe>user-unsubscribe@commons.apache.org</unsubscribe>
+ <archive>http://mail-archives.apache.org/mod_mbox/commons-user/</archive>
+ </mailingList>
+ </mailingLists>
+ <developers>
+ <developer>
+ <id>morgand</id>
+ <name>Morgan Delagrange</name>
+ <email></email>
+ <organization></organization>
+ </developer>
+ <developer>
+ <id>geirm</id>
+ <name>Geir Magnusson</name>
+ <email></email>
+ <organization></organization>
+ </developer>
+ <developer>
+ <id>craigmcc</id>
+ <name>Craig McClanahan</name>
+ <email></email>
+ <organization></organization>
+ </developer>
+ <developer>
+ <id>rwaldhoff</id>
+ <name>Rodney Waldhoff</name>
+ <email></email>
+ <organization></organization>
+ </developer>
+ <developer>
+ <id>dweinr1</id>
+ <name>David Weinrich</name>
+ <email></email>
+ <organization></organization>
+ </developer>
+ <developer>
+ <id>dirkv</id>
+ <name>Dirk Verbeeck</name>
+ <email></email>
+ <organization></organization>
+ </developer>
+ <developer>
+ <id>rdonkin</id>
+ <name>Robert Burrell Donkin</name>
+ <email></email>
+ <organization>Apache Software Foundation</organization>
+ </developer>
+ <developer>
+ <id>sandymac</id>
+ <name>Sandy McArthur</name>
+ <email></email>
+ <organization>Apache Software Foundation</organization>
+ </developer>
+ <developer>
+ <id>psteitz</id>
+ <name>Phil Steitz</name>
+ <email></email>
+ <organization>Apache Software Foundation</organization>
+ </developer>
+ </developers>
+ <contributors>
+ <contributor>
+ <name>Todd Carmichael</name>
+ <email>toddc@concur.com</email>
+ </contributor>
+ </contributors>
+ <licenses>
+ <license>
+ <name>The Apache Software License, Version 2.0</name>
+ <url>/LICENSE.txt</url>
+ </license>
+ </licenses>
+ <scm>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/pool/trunk</connection>
+ <url>http://svn.apache.org/repos/asf/commons/proper/pool/trunk</url>
+ </scm>
+ <organization>
+ <name>The Apache Software Foundation</name>
+ <url>http://commons.apache.org/</url>
+ </organization>
+ <build>
+ <sourceDirectory>src/java</sourceDirectory>
+ <testSourceDirectory>src/test</testSourceDirectory>
+ <resources>
+ <resource>
+ <targetPath>META-INF</targetPath>
+ <directory>${basedir}</directory>
+ <includes>
+ <include>NOTICE.txt</include>
+ </includes>
+ </resource>
+ </resources>
+ <plugins>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>org/apache/commons/pool/TestBaseObjectPool.java</include>
+ <include>org/apache/commons/pool/TestBaseKeyedObjectPool.java</include>
+ <include>org/apache/commons/pool/TestBasePoolableObjectFactory.java</include>
+ <include>org/apache/commons/pool/TestBaseKeyedPoolableObjectFactory.java</include>
+ <include>org/apache/commons/pool/TestPoolUtils.java</include>
+ <include>org/apache/commons/pool/impl/TestStackObjectPool.java</include>
+ <include>org/apache/commons/pool/impl/TestStackKeyedObjectPool.java</include>
+ <include>org/apache/commons/pool/impl/TestGenericObjectPool.java</include>
+ <include>org/apache/commons/pool/impl/TestGenericKeyedObjectPool.java</include>
+ <include>org/apache/commons/pool/impl/TestSoftReferenceObjectPool.java</include>
+ <include>org/apache/commons/pool/impl/TestGenericObjectPoolFactory.java</include>
+ <include>org/apache/commons/pool/impl/TestStackObjectPoolFactory.java</include>
+ <include>org/apache/commons/pool/impl/TestGenericKeyedObjectPoolFactory.java</include>
+ <include>org/apache/commons/pool/impl/TestStackKeyedObjectPoolFactory.java</include>
+ <include>org/apache/commons/pool/composite/TestFifoLender.java</include>
+ <include>org/apache/commons/pool/composite/TestIdleEvictorLender.java</include>
+ <include>org/apache/commons/pool/composite/TestInvalidEvictorLender.java</include>
+ <include>org/apache/commons/pool/composite/TestLifoLender.java</include>
+ <include>org/apache/commons/pool/composite/TestNullLender.java</include>
+ <include>org/apache/commons/pool/composite/TestSoftLender.java</include>
+ <include>org/apache/commons/pool/composite/TestFailManager.java</include>
+ <include>org/apache/commons/pool/composite/TestGrowManager.java</include>
+ <include>org/apache/commons/pool/composite/TestIdleLimitManager.java</include>
+ <include>org/apache/commons/pool/composite/TestFailLimitManager.java</include>
+ <include>org/apache/commons/pool/composite/TestWaitLimitManager.java</include>
+ <include>org/apache/commons/pool/composite/TestNullTracker.java</include>
+ <include>org/apache/commons/pool/composite/TestReferenceTracker.java</include>
+ <include>org/apache/commons/pool/composite/TestDebugTracker.java</include>
+ <include>org/apache/commons/pool/composite/TestSimpleTracker.java</include>
+ <include>org/apache/commons/pool/composite/TestCompositeObjectPool.java</include>
+ <include>org/apache/commons/pool/composite/TestCompositeKeyedObjectPool.java</include>
+ <include>org/apache/commons/pool/composite/TestCompositeKeyedObjectPool2.java</include>
+ <include>org/apache/commons/pool/composite/TestCompositeKeyedObjectPoolFactory.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-jdiff-plugin</artifactId>
+ <version>1.5</version>
+ <configuration>
+ <comment>&lt;strong>Site Only&lt;/strong> - v1.5 (minimum)</comment>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-changes-plugin</artifactId>
+ <version>1.6</version>
+ <configuration>
+ <comment>&lt;strong>Site Only&lt;/strong> - v1.6 (minimum)</comment>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>1.8</version>
+ <configuration>
+ <comment>&lt;b>Site&lt;/b> only</comment>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.2</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <distributionManagement>
+ <repository>
+ <id>default</id>
+ <name>Default Repository</name>
+ <url>file:///www/people.apache.org/builds/commons/pool/</url>
+ </repository>
+ <site>
+ <id>default</id>
+ <name>Default Site</name>
+ <url>scp://people.apache.org//www/commons.apache.org/pool/</url>
+ </site>
+ <status>converted</status>
+ </distributionManagement>
+</project> \ No newline at end of file
diff --git a/java/lib/poms/derby-10.3.2.1.pom b/java/lib/poms/derby-10.3.2.1.pom
new file mode 100644
index 0000000000..175046203d
--- /dev/null
+++ b/java/lib/poms/derby-10.3.2.1.pom
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?><project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.apache.derby</groupId>
+ <artifactId>derby</artifactId>
+ <name>Derby Engine</name>
+ <version>10.3.2.1</version>
+ <description></description>
+ <url>http://db.apache.org/derby/</url>
+ <issueManagement>
+ <url>http://issues.apache.org/jira/browse/DERBY</url>
+ </issueManagement>
+ <inceptionYear>2004</inceptionYear>
+ <mailingLists>
+ <mailingList>
+ <name>Derby User List</name>
+ <subscribe>derby-user-subscribe@db.apache.org</subscribe>
+ <unsubscribe>derby-user-unsubscribe@db.apache.org</unsubscribe>
+ <archive>http://issues.apache.org/eyebrowse/SummarizeList?listName=derby-user@db.apache.org</archive>
+ </mailingList>
+ <mailingList>
+ <name>Derby Developer List</name>
+ <subscribe>derby-dev-subscribe@db.apache.org</subscribe>
+ <unsubscribe>derby-dev-unsubscribe@db.apache.org</unsubscribe>
+ <archive>http://issues.apache.org/eyebrowse/SummarizeList?listName=derby-dev@db.apache.org</archive>
+ </mailingList>
+ <mailingList>
+ <name>Derby Commit List</name>
+ <subscribe>derby-commits-subscribe@db.apache.org</subscribe>
+ <unsubscribe>derby-commits-unsubscribe@db.apache.org</unsubscribe>
+ <archive>http://issues.apache.org/eyebrowse/SummarizeList?listName=derby-commits@db.apache.org</archive>
+ </mailingList>
+ </mailingLists>
+ <scm>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/db/derby/code/trunk</connection>
+ <developerConnection>scm:svn:https://svn.apache.org/repos/asf/db/derby/code/trunk</developerConnection>
+ <url>http://svn.apache.org/viewcvs.cgi/db/derby/code/trunk/?root=Apache-SVN</url>
+ </scm>
+ <organization>
+ <name>Apache Software Foundation</name>
+ <url>http://db.apache.org/</url>
+ </organization>
+ <build />
+</project> \ No newline at end of file
diff --git a/java/lib/poms/geronimo-jms_1.1_spec-1.0.pom b/java/lib/poms/geronimo-jms_1.1_spec-1.0.pom
new file mode 100644
index 0000000000..bde503231e
--- /dev/null
+++ b/java/lib/poms/geronimo-jms_1.1_spec-1.0.pom
@@ -0,0 +1,6 @@
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-jms_1.1_spec</artifactId>
+ <version>1.0</version>
+</project> \ No newline at end of file
diff --git a/java/lib/poms/junit-3.8.1.pom b/java/lib/poms/junit-3.8.1.pom
new file mode 100644
index 0000000000..2169a65d76
--- /dev/null
+++ b/java/lib/poms/junit-3.8.1.pom
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd ">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <name>JUnit</name>
+ <url>http://junit.org</url>
+ <description>
+ JUnit is a regression testing framework written by Erich Gamma and Kent Beck. It is used by the developer who implements unit tests in Java.
+ </description>
+ <organization>
+ <name>JUnit</name>
+ <url>http://www.junit.org</url>
+ </organization>
+ <licenses>
+ <license>
+ <name>Common Public License Version 1.0</name>
+ <url>http://www.opensource.org/licenses/cpl1.0.txt</url>
+ </license>
+ </licenses>
+ <scm>
+ <url>http://junit.cvs.sourceforge.net/junit/</url>
+ </scm>
+ <dependencies>
+ </dependencies>
+</project>
diff --git a/java/lib/poms/log4j-1.2.12.pom b/java/lib/poms/log4j-1.2.12.pom
new file mode 100644
index 0000000000..8c10608604
--- /dev/null
+++ b/java/lib/poms/log4j-1.2.12.pom
@@ -0,0 +1,6 @@
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.12</version>
+</project> \ No newline at end of file
diff --git a/java/lib/poms/mina-core-1.0.1.pom b/java/lib/poms/mina-core-1.0.1.pom
new file mode 100644
index 0000000000..def70418c9
--- /dev/null
+++ b/java/lib/poms/mina-core-1.0.1.pom
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="ISO-8859-1"?><project>
+ <parent>
+ <artifactId>build</artifactId>
+ <groupId>org.apache.mina</groupId>
+ <version>1.0.1</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>mina-core</artifactId>
+ <name>Apache MINA Core API</name>
+ <version>1.0.1</version>
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>1.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>backport-util-concurrent</groupId>
+ <artifactId>backport-util-concurrent</artifactId>
+ <version>2.2</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>easymock</groupId>
+ <artifactId>easymock</artifactId>
+ <version>1.2_Java1.3</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <distributionManagement>
+ <status>deployed</status>
+ </distributionManagement>
+</project> \ No newline at end of file
diff --git a/java/lib/poms/mina-filter-ssl-1.0.1.pom b/java/lib/poms/mina-filter-ssl-1.0.1.pom
new file mode 100644
index 0000000000..1d5a1ec18c
--- /dev/null
+++ b/java/lib/poms/mina-filter-ssl-1.0.1.pom
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="ISO-8859-1"?><project>
+ <parent>
+ <artifactId>build</artifactId>
+ <groupId>org.apache.mina</groupId>
+ <version>1.0.1</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>mina-filter-ssl</artifactId>
+ <name>Apache MINA SSL Filter</name>
+ <version>1.0.1</version>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.mina</groupId>
+ <artifactId>mina-core</artifactId>
+ <version>1.0.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>1.0</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ <distributionManagement>
+ <status>deployed</status>
+ </distributionManagement>
+</project> \ No newline at end of file
diff --git a/java/lib/poms/org.apache.felix.framework-1.0.0.pom b/java/lib/poms/org.apache.felix.framework-1.0.0.pom
new file mode 100644
index 0000000000..c7e6cd489e
--- /dev/null
+++ b/java/lib/poms/org.apache.felix.framework-1.0.0.pom
@@ -0,0 +1,66 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<project>
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix</artifactId>
+ <version>1.0.0</version>
+ <relativePath>../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <name>Apache Felix Framework</name>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>1.0.0</version>
+ <dependencies>
+ <dependency>
+ <groupId>${pom.groupId}</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>1.0.0</version>
+ </dependency>
+ <!--dependency>
+ We include ServiceTracker source code directly to avoid some
+ packaging issues. Will need to edit main pom to exclude this
+ dependency once it is added back in.
+ <groupId>${pom.groupId}</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>0.9.0-SNAPSHOT</version>
+ </dependency-->
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>1.0.0</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>Apache Felix Framework</Bundle-Name>
+ <Bundle-Description>OSGi R4 framework implementation.</Bundle-Description>
+ <Export-Package>org.osgi.framework,org.osgi.service.packageadmin,org.osgi.service.url,org.osgi.service.startlevel,org.osgi.util.tracker</Export-Package>
+ <Private-Package>org.apache.felix.moduleloader.*,org.apache.felix.framework.*</Private-Package>
+ <Import-Package>!*</Import-Package>
+ <Include-Resource>{src/main/resources/},org/osgi/framework/=target/classes/org/osgi/framework/</Include-Resource>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/java/lib/poms/org.osgi.core-1.0.0.pom b/java/lib/poms/org.osgi.core-1.0.0.pom
new file mode 100644
index 0000000000..4e512c06a4
--- /dev/null
+++ b/java/lib/poms/org.osgi.core-1.0.0.pom
@@ -0,0 +1,56 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<project>
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix</artifactId>
+ <version>1.0.0</version>
+ <relativePath>../pom/pom.xml</relativePath>
+ </parent>
+ <organization>
+ <name>OSGi Alliance</name>
+ <url>http://www.osgi.org/</url>
+ </organization>
+ <modelVersion>4.0.0</modelVersion>
+ <name>OSGi R4 Core Bundle</name>
+ <description>OSGi Service Platform Release 4 Core Interfaces and Classes.</description>
+ <artifactId>org.osgi.core</artifactId>
+ <version>1.0.0</version>
+ <packaging>bundle</packaging>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>1.0.0</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>org.osgi.core</Bundle-SymbolicName>
+ <Export-Package>org.osgi.framework, org.osgi.service.condpermadmin, org.osgi.service.packageadmin, org.osgi.service.permissionadmin, org.osgi.service.startlevel, org.osgi.service.url</Export-Package>
+ <Import-Package>org.osgi.framework,org.osgi.service.packageadmin,org.osgi.service.startlevel,org.osgi.service.url,!org.osgi.*,*</Import-Package>
+ <Bundle-Version>4</Bundle-Version>
+ <Bundle-Copyright>Copyright (c) OSGi Alliance (2000, 2006). All Rights Reserved.</Bundle-Copyright>
+ <Bundle-Category>osgi</Bundle-Category>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/java/lib/poms/slf4j-api-1.4.0.pom b/java/lib/poms/slf4j-api-1.4.0.pom
new file mode 100644
index 0000000000..13e1418d2b
--- /dev/null
+++ b/java/lib/poms/slf4j-api-1.4.0.pom
@@ -0,0 +1,73 @@
+<?xml version="1.0"?><project>
+ <parent>
+ <artifactId>slf4j-parent</artifactId>
+ <groupId>org.slf4j</groupId>
+ <version>1.4.0</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <name>SLF4J API Module</name>
+ <version>1.4.0</version>
+ <description>The slf4j API</description>
+ <url>http://www.slf4j.org</url>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <forkMode>once</forkMode>
+ <reportFormat>plain</reportFormat>
+ <trimStackTrace>false</trimStackTrace>
+ <excludes>
+ <exclude>**/AllTest.java</exclude>
+ <exclude>**/PackageTest.java</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>bundle-test-jar</id>
+ <phase>package</phase>
+ <goals>
+ <goal>jar</goal>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <archive>
+ <manifestEntries>
+ <Bundle-Version>${pv4osgi}</Bundle-Version>
+ <Bundle-Description>${project.description}</Bundle-Description>
+ <Implementation-Version>1.4.0</Implementation-Version>
+ </manifestEntries>
+ <manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>process-classes</phase>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <tasks>
+ <echo>Removing slf4j-api's dummy StaticLoggerBinder and StaticMarkerBinder</echo>
+ <delete dir="target/classes/org/slf4j/impl"></delete>
+ </tasks>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <distributionManagement>
+ <status>deployed</status>
+ </distributionManagement>
+</project> \ No newline at end of file
diff --git a/java/lib/poms/slf4j-log4j12-1.4.0.pom b/java/lib/poms/slf4j-log4j12-1.4.0.pom
new file mode 100644
index 0000000000..29302557e6
--- /dev/null
+++ b/java/lib/poms/slf4j-log4j12-1.4.0.pom
@@ -0,0 +1,44 @@
+<?xml version="1.0"?><project>
+ <parent>
+ <artifactId>slf4j-parent</artifactId>
+ <groupId>org.slf4j</groupId>
+ <version>1.4.0</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <name>SLF4J LOG4J-12 Binding</name>
+ <version>1.4.0</version>
+ <description>The slf4j log4j-12 binding</description>
+ <url>http://www.slf4j.org</url>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestEntries>
+ <Bundle-Version>${pv4osgi}</Bundle-Version>
+ <Bundle-Description>${project.description}</Bundle-Description>
+ <Implementation-Version>1.4.0</Implementation-Version>
+ </manifestEntries>
+ <manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </dependency>
+ </dependencies>
+ <distributionManagement>
+ <status>deployed</status>
+ </distributionManagement>
+</project> \ No newline at end of file
diff --git a/java/lib/poms/xalan-2.7.0.pom b/java/lib/poms/xalan-2.7.0.pom
new file mode 100644
index 0000000000..f543d7e6e2
--- /dev/null
+++ b/java/lib/poms/xalan-2.7.0.pom
@@ -0,0 +1,19 @@
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>xalan</groupId>
+ <artifactId>xalan</artifactId>
+ <version>2.7.0</version>
+ <dependencies>
+ <dependency>
+ <groupId>xml-apis</groupId>
+ <artifactId>xml-apis</artifactId>
+ <version>2.0.2</version>
+ </dependency>
+ <dependency>
+ <groupId>xerces</groupId>
+ <artifactId>xercesImpl</artifactId>
+ <version>2.6.0</version>
+ <optional>true</optional>
+ </dependency>
+ </dependencies>
+</project> \ No newline at end of file
diff --git a/java/lib/start.jar b/java/lib/start.jar
new file mode 100644
index 0000000000..63685df7cc
--- /dev/null
+++ b/java/lib/start.jar
Binary files differ
diff --git a/java/lib/wsdl4j-1.6.1.jar b/java/lib/wsdl4j-1.6.1.jar
new file mode 100644
index 0000000000..67a35fcbaa
--- /dev/null
+++ b/java/lib/wsdl4j-1.6.1.jar
Binary files differ
diff --git a/java/lib/xercesImpl-2.8.1.jar b/java/lib/xercesImpl-2.8.1.jar
new file mode 100644
index 0000000000..3b351f6e2b
--- /dev/null
+++ b/java/lib/xercesImpl-2.8.1.jar
Binary files differ
diff --git a/java/lib/xml-apis-1.3.03.jar b/java/lib/xml-apis-1.3.03.jar
new file mode 100644
index 0000000000..b338fb6693
--- /dev/null
+++ b/java/lib/xml-apis-1.3.03.jar
Binary files differ
diff --git a/java/log4j-test.xml b/java/log4j-test.xml
deleted file mode 100644
index c242286b70..0000000000
--- a/java/log4j-test.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
--->
-
-<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
-
-<!-- ===================================================================== -->
-<!-- -->
-<!-- Log4j configuration for unit tests -->
-<!-- -->
-<!-- ===================================================================== -->
-
-<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
- <appender name="console" class="org.apache.log4j.ConsoleAppender">
- <param name="Target" value="System.out"/>
- <layout class="org.apache.log4j.PatternLayout">
- <param name="ConversionPattern" value="%t %d %p [%c{4}] %m%n"/>
- </layout>
- </appender>
-
- <logger name="org.apache.qpid">
- <level value="${amqj.logging.level}"/>
- </logger>
-
- <logger name="qpid.protocol">
- <level value="${amqj.protocol.logging.level}"/>
- </logger>
-
- <logger name="org.apache.qpid.test.utils.QpidTestCase">
- <level value="ALL"/>
- </logger>
-
- <root>
- <level value="${root.logging.level}"/>
- <appender-ref ref="console" />
- </root>
-</log4j:configuration>
diff --git a/java/management/agent/build.xml b/java/management/agent/build.xml
new file mode 100644
index 0000000000..a410c74c1f
--- /dev/null
+++ b/java/management/agent/build.xml
@@ -0,0 +1,27 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<project name="QMF Agent" default="build">
+
+ <property name="module.depends" value="common client"/>
+
+ <import file="../../module.xml"/>
+
+</project>
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/Agent.java b/java/management/agent/src/main/java/org/apache/qpid/agent/Agent.java
new file mode 100644
index 0000000000..f6ae6adbc3
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/Agent.java
@@ -0,0 +1,707 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import javax.jms.BytesMessage;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.agent.binding.BindingContext;
+import org.apache.qpid.agent.binding.BindingUtils;
+import org.apache.qpid.agent.binding.ClassBinding;
+import org.apache.qpid.agent.binding.BindingException;
+import org.apache.qpid.agent.binding.MethodBinding;
+import org.apache.qpid.agent.binding.ParameterBinding;
+import org.apache.qpid.agent.binding.PropertyBinding;
+import org.apache.qpid.agent.binding.TypeBinding;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.transport.codec.BBDecoder;
+import org.apache.qpid.transport.codec.BBEncoder;
+import org.apache.qpid.transport.codec.Decoder;
+
+/**
+ * The main class for interacting with the QMF bus. Objects which are to be
+ * managed can be registered with the agent, as can classes to be exposed via
+ * the schema.
+ */
+public class Agent implements MessageListener
+{
+ // The following are settings to configure the Agent
+ protected AMQConnection connection;
+ protected boolean sessionTransacted = false;
+ protected int acknowledgeMode = Session.AUTO_ACKNOWLEDGE;
+ protected String label;
+ protected UUID systemId;
+ // this list holds the objects until the agent is started
+ protected List managedObjects = new ArrayList();
+ protected List registeredClasses = new ArrayList();
+ // The following instance variables are not
+ // able to be set by the end user.
+ protected Session session;
+ protected MessageProducer prod;
+ protected MessageConsumer cons;
+ protected Queue reply;
+ protected BindingContext bctx = new BindingContext();
+ protected Map<Long, ManagedObject> objects = new Hashtable<Long, ManagedObject>();
+ protected long bbank;
+ protected long abank;
+ protected static Log log = LogFactory.getLog(Agent.class);
+ protected volatile boolean inside = false;
+ protected ClassLoader classLoader = null;
+
+ public Agent()
+ {
+ systemId = UUID.randomUUID();
+ log.debug(String.format("Agent with uid %s created", systemId
+ .toString()));
+ }
+
+ public Agent(String label, UUID systemId)
+ {
+ this.systemId = systemId;
+ this.label = label;
+ log.debug(String.format("Agent with name %s and uid %s created", label,
+ systemId.toString()));
+ }
+
+ public void register(ManagedObject managedObject)
+ {
+ Class managedClass = managedObject.getObjectClass();
+ long id = managedObject.getId();
+ ClassBinding cb = bctx.register(managedClass);
+ managedObject.setManagedClassName(cb.getName());
+ managedObject.setManagedPackageName(cb.getPackage());
+ log.debug(String.format(
+ "Added managed object id '%d' for package '%s' class '%s'", id,
+ managedObject.getManagedPackageName(), managedObject
+ .getManagedClassName()));
+ objects.put(id, managedObject);
+ managedObjects.add(managedObject);
+ }
+
+ public void registerClass(Class cls)
+ {
+ bctx.register(cls);
+ if (!registeredClasses.contains(cls))
+ {
+ registeredClasses.add(cls);
+ }
+ }
+
+ /**
+ * Stops the agents connection to the bus
+ */
+ public void stop()
+ {
+ try
+ {
+ cons.close();
+ prod.close();
+ connection.stop();
+ connection.close();
+ session.close();
+ } catch (JMSException e)
+ {
+ log.error("Exception:", e);
+ }
+ }
+
+ /**
+ * Starts up the agent. Many bean containers may call this by default which
+ * aids in deployment
+ */
+ public void start()
+ {
+ log.debug(String.format("Agent with uid %s and name %s starting",
+ systemId.toString(), label));
+ for (Object clsName : registeredClasses.toArray())
+ {
+ try
+ {
+ Class cls = null;
+ if (String.class.isAssignableFrom(clsName.getClass()))
+ {
+ cls = getClass(clsName.toString());
+ } else
+ {
+ cls = (Class) clsName;
+ }
+ this.registerClass(cls);
+ } catch (Exception e)
+ {
+ log.error("Could not register class " + clsName);
+ }
+ }
+ for (Object obj : managedObjects.toArray())
+ {
+ this.register((ManagedObject) obj);
+ }
+ try
+ {
+ session = connection.createSession(sessionTransacted,
+ acknowledgeMode);
+ reply = session
+ .createQueue(String
+ .format(
+ "direct://amq.direct//%s-%s?exclusive='True'&autodelete='True'",
+ label, systemId));
+ cons = session.createConsumer(reply);
+ cons.setMessageListener(this);
+ prod = session.createProducer(null);
+ } catch (JMSException e)
+ {
+ throw new AgentException(e);
+ }
+ attachRequest(label, systemId);
+ try
+ {
+ connection.start();
+ } catch (JMSException e)
+ {
+ throw new AgentException(e);
+ }
+ }
+
+ /**
+ * Send an event object to the bus
+ */
+ public void raiseEvent(Object value, EventSeverity sev)
+ {
+ log.debug(String.format("Sending event of class %s with Severity %s",
+ value.getClass(), sev.ordinal()));
+ BBEncoder enc = this.init('e');
+ ClassBinding cb = bctx.getClassBinding(value.getClass());
+ String pkg = cb.getPackage();
+ String cls = cb.getName();
+ enc.writeStr8(pkg);
+ enc.writeStr8(cls);
+ enc.writeBin128(cb.getSchemaHash());
+ long now = System.currentTimeMillis() * 1000000;
+ enc.writeInt64(now);
+ enc.writeUint8((short) sev.ordinal());
+ for (PropertyBinding p : cb.getProperties())
+ {
+ p.getType().encode(enc, BindingUtils.get(p, value));
+ }
+ send(
+ String.format("console.event.%d.%d.%s.%s", bbank, abank, pkg,
+ cls), enc);
+ }
+
+ public void onMessage(Message message)
+ {
+ if (inside)
+ {
+ new Throwable().printStackTrace();
+ }
+ inside = true;
+ Decoder dec = readBody(message);
+ Destination replyTo;
+ try
+ {
+ replyTo = message.getJMSReplyTo();
+ } catch (JMSException e)
+ {
+ throw new AgentException(e);
+ }
+ byte[] magic = dec.readBytes(3);
+ if (magic[0] != 'A' || magic[1] != 'M' || magic[2] != '2')
+ {
+ throw new AgentException("bad magic: " + new String(magic));
+ }
+ short op = dec.readUint8();
+ long seq = dec.readUint32();
+ log.debug("Message recieved: " + (char) op);
+ switch (op)
+ {
+ case 'a':
+ this.handleAgentAttach(seq, replyTo, dec);
+ break;
+ case 'G':
+ this.handleGetQuery(seq, replyTo, dec);
+ break;
+ case 'M':
+ this.handleMethodRequest(seq, replyTo, dec);
+ break;
+ case 'S':
+ this.handleSchemaRequest(seq, replyTo, dec);
+ break;
+ case 'x':
+ // TODO
+ break;
+ default:
+ throw new IllegalArgumentException("opcode: " + ((char) op));
+ }
+ inside = false;
+ }
+
+ protected ClassBinding getClassBinding(ManagedObject mobj)
+ {
+ return bctx.getClassBinding(mobj.getObjectClass());
+ }
+
+ private byte[] ensure(int capacity, byte[] body, int size)
+ {
+ if (capacity > body.length)
+ {
+ byte[] copy = new byte[capacity];
+ System.arraycopy(body, 0, copy, 0, size);
+ body = copy;
+ }
+ return body;
+ }
+
+ private Decoder readBody(Message message)
+ {
+ BytesMessage msg = (BytesMessage) message;
+ BBDecoder dec = new BBDecoder();
+ byte[] buf = new byte[1024];
+ byte[] body = new byte[1024];
+ int size = 0;
+ int n;
+ try
+ {
+ while ((n = msg.readBytes(buf)) > 0)
+ {
+ body = ensure(size + n, body, size);
+ System.arraycopy(buf, 0, body, size, n);
+ size += n;
+ }
+ } catch (JMSException e)
+ {
+ throw new AgentException(e);
+ }
+ dec.init(ByteBuffer.wrap(body, 0, size));
+ return dec;
+ }
+
+ protected void handleAgentAttach(long seq, Destination replyTo, Decoder dec)
+ {
+ log.debug("Agent Attach Message");
+ bbank = dec.readUint32();
+ abank = dec.readUint32();
+ try
+ {
+ MessageConsumer mc = session
+ .createConsumer(session
+ .createQueue(String
+ .format(
+ "management://qpid.management//%s-%s?routingkey='agent.%d.%d'&exclusive='True'&autodelete='True'",
+ label, systemId, bbank, abank)));
+ mc.setMessageListener(this);
+ } catch (JMSException e)
+ {
+ throw new AgentException(e);
+ }
+ for (String packageName : bctx.getPackages())
+ {
+ packageIndication(packageName);
+ }
+ for (ClassBinding cb : bctx.getAllBindings())
+ {
+ classIndication(cb);
+ }
+ for (ManagedObject mo : objects.values())
+ {
+ content('i', seq, null, mo);
+ }
+ }
+
+ protected void handleMethodRequest(long seq, Destination replyTo,
+ Decoder dec)
+ {
+ dec.readUint64(); // first part of object-id
+ long id = dec.readUint64();
+ ManagedObject mo = objects.get(id);
+ if (mo == null)
+ {
+ methodResponse(seq, replyTo, 1, String.format(
+ "no such object: 0x%x", id));
+ } else
+ {
+ dec.readStr8(); // pkg
+ dec.readStr8(); // cls
+ dec.readBin128(); // hash
+ String mname = dec.readStr8();
+ ClassBinding cls = getClassBinding(mo);
+ MethodBinding method = cls.getMethod(mname);
+ if (method == null)
+ {
+ methodResponse(seq, replyTo, 2, String.format(
+ "no such method: %s", mname));
+ } else
+ {
+ log.trace("Handle method: " + method.getName());
+ List<ParameterBinding> params = method.getInParameters();
+ Object[] args = new Object[params.size()];
+ int idx = 0;
+ for (ParameterBinding p : params)
+ {
+ TypeBinding typeBinding = p.getType();
+ log
+ .trace(String
+ .format(
+ "Decoding parameter with type %s ref package %s ref class %s ",
+ typeBinding.getCode(), typeBinding
+ .getRefPackage(),
+ typeBinding.getRefClass()));
+ args[idx++] = typeBinding.decode(dec);
+ log.trace("Done");
+ }
+ try
+ {
+ Object[] result = mo.invoke(method, args);
+ methodResponse(seq, replyTo, 0, null, method, result);
+ } catch (BindingException ex)
+ {
+ log
+ .error(
+ String
+ .format(
+ "An exception occured invoking method %s. Stack trace sent to console.",
+ method.getName()), ex);
+ StringWriter str = new StringWriter();
+ PrintWriter writer = new PrintWriter(str);
+ ex.printStackTrace(writer);
+ writer.flush();
+ methodResponse(seq, replyTo, 7, str.toString());
+ }
+ log.trace("Done with method: " + method.getName());
+ }
+ }
+ }
+
+ protected void handleGetQuery(long seq, Destination replyTo, Decoder dec)
+ {
+ Map<String, Object> data = dec.readMap();
+ if (data.containsKey("_objectid"))
+ {
+ long objId = (Long) data.get("_objectid");
+ log.debug("Get Request message for object id " + objId);
+ ManagedObject mo = objects.get(objId);
+ if (mo == null)
+ {
+ methodResponse(seq, replyTo, 1, String.format(
+ "no such object: 0x%x", objId));
+ } else
+ {
+ content('g', seq, replyTo, mo);
+ }
+ } else if (data.containsKey("_class"))
+ {
+ String className = (String) data.get("_class");
+ String packageName = (String) data.get("_package");
+ log.debug(String.format(
+ "Get Request message for package '%s' class '%s'",
+ packageName, className));
+ for (ManagedObject mo : objects.values())
+ {
+ if (mo.getManagedClassName().equals(className))
+ {
+ if ((packageName == null) || packageName.equals("")
+ || packageName.equals(mo.getManagedPackageName()))
+ {
+ content('g', seq, replyTo, mo);
+ }
+ }
+ }
+ } else
+ {
+ for (ManagedObject mo : objects.values())
+ {
+ content('g', seq, replyTo, mo);
+ }
+ }
+ complete(seq, replyTo);
+ }
+
+ protected void handleSchemaRequest(long seq, Destination replyTo,
+ Decoder dec)
+ {
+ String pkg = dec.readStr8();
+ String cls = dec.readStr8();
+ log.debug(String.format(
+ "SchemaRequest message for package '%s' class '%s'", pkg, cls));
+ ClassBinding cb = bctx.getClassBinding(pkg, cls);
+ if (cb == null)
+ {
+ throw new AgentException("no such class: " + pkg + ", " + cls);
+ }
+ schemaResponse(seq, cb);
+ }
+
+ protected BBEncoder init(char opcode)
+ {
+ return init(opcode, 0);
+ }
+
+ protected BBEncoder init(char opcode, long sequence)
+ {
+ BBEncoder enc = new BBEncoder(1024);
+ enc.init();
+ enc.writeUint8((short) 'A');
+ enc.writeUint8((short) 'M');
+ enc.writeUint8((short) '2');
+ enc.writeUint8((short) opcode);
+ enc.writeUint32(sequence);
+ return enc;
+ }
+
+ protected void send(BBEncoder enc)
+ {
+ send("broker", enc);
+ }
+
+ protected void send(Destination dest, BBEncoder enc)
+ {
+ try
+ {
+ byte[] buf = new byte[1024];
+ byte[] body = new byte[1024];
+ BytesMessage msg = session.createBytesMessage();
+ ByteBuffer slice = enc.segment();
+ while (slice.hasRemaining())
+ {
+ int n = Math.min(buf.length, slice.remaining());
+ slice.get(buf, 0, n);
+ msg.writeBytes(buf, 0, n);
+ }
+ msg.setJMSReplyTo(reply);
+ // ???: I assume this is thread safe.
+ prod.send(dest, msg);
+ } catch (JMSException e)
+ {
+ throw new AgentException(e);
+ }
+ }
+
+ protected void send(String routingKey, BBEncoder enc)
+ {
+ try
+ {
+ send(session
+ .createQueue("management://qpid.management//?routingkey='"
+ + routingKey + "'"), enc);
+ } catch (JMSException e)
+ {
+ throw new AgentException(e);
+ }
+ }
+
+ protected void attachRequest(String label, UUID systemId)
+ {
+ BBEncoder enc = init('A');
+ enc.writeStr8(label);
+ enc.writeUuid(systemId);
+ enc.writeUint32(0);
+ enc.writeUint32(0);
+ send(enc);
+ }
+
+ protected void packageIndication(String pkg)
+ {
+ BBEncoder enc = init('p');
+ enc.writeStr8(pkg);
+ send(enc);
+ }
+
+ protected void classIndication(ClassBinding cb)
+ {
+ BBEncoder enc = init('q');
+ enc.writeUint8(cb.getKind());
+ enc.writeStr8(cb.getPackage());
+ enc.writeStr8(cb.getName());
+ enc.writeBin128(cb.getSchemaHash()); // schema hash?
+ send(enc);
+ }
+
+ protected void schemaResponse(long seq, ClassBinding cb)
+ {
+ BBEncoder enc = init('s', seq);
+ cb.encode(enc);
+ send(enc);
+ }
+
+ protected void content(char c, long seq, Destination dest, ManagedObject mo)
+ {
+ BBEncoder enc = init(c, seq);
+ ClassBinding cb = getClassBinding(mo);
+ String pkg = cb.getPackage();
+ String cls = cb.getName();
+ enc.writeStr8(pkg);
+ enc.writeStr8(cls);
+ enc.writeBin128(cb.getSchemaHash());
+ long now = System.currentTimeMillis() * 1000000;
+ enc.writeUint64(now);
+ enc.writeUint64(now);
+ enc.writeUint64(0);
+ enc.writeUint64(0x0000FFFFFFFFFFFFL & ((bbank << 28) | abank));
+ enc.writeUint64(mo.getId());
+ for (PropertyBinding p : cb.getProperties())
+ {
+ p.getType().encode(enc, mo.get(p));
+ }
+ if (dest == null)
+ {
+ send(String.format("console.obj.%d.%d.%s.%s", bbank, abank, pkg,
+ cls), enc);
+ } else
+ {
+ send(dest, enc);
+ }
+ }
+
+ protected void complete(long seq, Destination dest)
+ {
+ BBEncoder enc = init('z', seq);
+ enc.writeUint32(0);
+ enc.writeStr8("");
+ send(dest, enc);
+ }
+
+ protected void methodResponse(long seq, Destination dest, int status,
+ String text)
+ {
+ methodResponse(seq, dest, status, text, null, null);
+ }
+
+ protected void methodResponse(long seq, Destination dest, int status,
+ String text, MethodBinding method, Object[] result)
+ {
+ BBEncoder enc = init('m', seq);
+ enc.writeUint32(status);
+ enc.writeStr16(text == null ? "" : text);
+ if (method != null)
+ {
+ int idx = 0;
+ for (ParameterBinding p : method.getOutParameters())
+ {
+ p.getType().encode(enc, result[idx++]);
+ }
+ }
+ send(dest, enc);
+ }
+
+ protected Class getClass(String className)
+ {
+ try
+ {
+ if (classLoader != null)
+ {
+ return classLoader.loadClass(className);
+ } else
+ {
+ return Class.forName(className);
+ }
+ } catch (ClassNotFoundException e)
+ {
+ throw new AgentException(String.format(
+ "No class named %s was found", className), e);
+ }
+ }
+
+ public String getLabel()
+ {
+ return label;
+ }
+
+ public void setLabel(String label)
+ {
+ this.label = label;
+ }
+
+ public AMQConnection getConnection()
+ {
+ return connection;
+ }
+
+ public void setConnection(AMQConnection connection)
+ {
+ this.connection = connection;
+ }
+
+ public boolean isSessionTransacted()
+ {
+ return sessionTransacted;
+ }
+
+ public void setSessionTransacted(boolean sessionTransacted)
+ {
+ this.sessionTransacted = sessionTransacted;
+ }
+
+ public void setManagedObjects(List objectList)
+ {
+ this.managedObjects = objectList;
+ }
+
+ public List getManagedObjects()
+ {
+ return managedObjects;
+ }
+
+ public void setRegisteredClasses(List objectList)
+ {
+ this.registeredClasses = objectList;
+ }
+
+ public List getRegisteredClasses()
+ {
+ return this.registeredClasses;
+ }
+
+ public static void main(String[] args) throws Exception
+ {
+ String broker = args[0];
+ String name = args[1];
+ String url = String.format(
+ "amqp://guest:guest@/?brokerlist='tcp://%s'", broker);
+ AMQConnection conn = new AMQConnection(url);
+ Agent agent = new Agent(name, UUID.randomUUID());
+ agent.setConnection(conn);
+ for (int i = 2; i < args.length; i++)
+ {
+ Class<?> cls = Class.forName(args[i]);
+ agent.register(new ManagedPOJO(cls.newInstance()));
+ }
+ agent.start();
+ while (true)
+ {
+ Thread.sleep(1000);
+ }
+ }
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/AgentException.java b/java/management/agent/src/main/java/org/apache/qpid/agent/AgentException.java
new file mode 100644
index 0000000000..410cad2d8c
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/AgentException.java
@@ -0,0 +1,45 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent;
+
+/**
+ * AgentException
+ *
+ */
+public class AgentException extends RuntimeException
+{
+ private static final long serialVersionUID = 1L;
+
+ public AgentException(String msg)
+ {
+ super(msg);
+ }
+
+ public AgentException(Throwable t)
+ {
+ super(t);
+ }
+
+ public AgentException(String msg, Throwable t)
+ {
+ super(msg, t);
+ }
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/EventSeverity.java b/java/management/agent/src/main/java/org/apache/qpid/agent/EventSeverity.java
new file mode 100644
index 0000000000..a3528d9804
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/EventSeverity.java
@@ -0,0 +1,6 @@
+package org.apache.qpid.agent;
+
+public enum EventSeverity
+{
+ EMERGENCY, ALERT, CRIT, ERROR, WARN, NOTICE, INFO, DEBUG
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedEJB.java b/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedEJB.java
new file mode 100644
index 0000000000..60efb1e284
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedEJB.java
@@ -0,0 +1,138 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.agent.binding.BindingUtils;
+import org.apache.qpid.agent.binding.MethodBinding;
+import org.apache.qpid.agent.binding.PropertyBinding;
+
+/**
+ * Wrapper classe for adding EJBS which are to be managed by the QMF Agent. The
+ * jndi location and the public interface to exposed are used to generate the
+ * schema.
+ */
+public class ManagedEJB extends ManagedObjectBase
+{
+ private Log log = LogFactory.getLog(ManagedEJB.class);
+ protected String className;
+ protected String jndiLocation;
+ protected ClassLoader classLoader;
+
+ protected Object getEJB()
+ {
+ ClassLoader previousCL = Thread.currentThread().getContextClassLoader();
+ try
+ {
+ if (classLoader != null)
+ {
+ Thread.currentThread().setContextClassLoader(classLoader);
+ }
+ InitialContext ctx = new InitialContext();
+ return ctx.lookup(jndiLocation);
+ } catch (NamingException e)
+ {
+ throw new AgentException("Error looking up EJB at " + jndiLocation,
+ e);
+ } finally
+ {
+ Thread.currentThread().setContextClassLoader(previousCL);
+ }
+ }
+
+ @Override
+ public Object get(PropertyBinding property)
+ {
+ return BindingUtils.get(property, this.getEJB());
+ }
+
+ @Override
+ public long getId()
+ {
+ return System.identityHashCode(this);
+ }
+
+ @Override
+ public Class getObjectClass()
+ {
+ try
+ {
+ if (classLoader != null)
+ {
+ log.debug("Using the classloader");
+ return classLoader.loadClass(className);
+ } else
+ {
+ return Class.forName(className);
+ }
+ } catch (ClassNotFoundException e)
+ {
+ throw new AgentException(String.format(
+ "No class named %s was found", className), e);
+ }
+ }
+
+ @Override
+ public Object[] invoke(MethodBinding method, Object... args)
+ {
+ return BindingUtils.invoke(method, this.getEJB(), args);
+ }
+
+ @Override
+ public void set(PropertyBinding property, Object value)
+ {
+ BindingUtils.set(property, value, this.getEJB());
+ }
+
+ public String getClassName()
+ {
+ return className;
+ }
+
+ public void setClassName(String className)
+ {
+ this.className = className;
+ }
+
+ public String getJndiLocation()
+ {
+ return jndiLocation;
+ }
+
+ public void setJndiLocation(String jndiLocation)
+ {
+ this.jndiLocation = jndiLocation;
+ }
+
+ public ClassLoader getClassLoader()
+ {
+ return classLoader;
+ }
+
+ public void setClassLoader(ClassLoader cloader)
+ {
+ this.classLoader = cloader;
+ }
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedObject.java b/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedObject.java
new file mode 100644
index 0000000000..aa3bbf3894
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedObject.java
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent;
+
+import org.apache.qpid.agent.binding.MethodBinding;
+import org.apache.qpid.agent.binding.PropertyBinding;
+
+/**
+ * Objects which are to be managed and controlled by the QMF Agent.
+ */
+public interface ManagedObject
+{
+ public abstract long getId();
+
+ public abstract Class getObjectClass();
+
+ public abstract Object get(PropertyBinding property);
+
+ public abstract void set(PropertyBinding property, Object value);
+
+ public abstract Object[] invoke(MethodBinding method, Object... args);
+
+ public abstract String getName();
+
+ public abstract void setName(String name);
+
+ public String getManagedClassName();
+
+ public String getManagedPackageName();
+
+ public void setManagedClassName(String aName);
+
+ public void setManagedPackageName(String aName);
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedObjectBase.java b/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedObjectBase.java
new file mode 100644
index 0000000000..51789ae11f
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedObjectBase.java
@@ -0,0 +1,72 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.agent.binding.MethodBinding;
+import org.apache.qpid.agent.binding.PropertyBinding;
+
+public abstract class ManagedObjectBase implements ManagedObject
+{
+ private static Log log = LogFactory.getLog(ManagedObjectBase.class);
+ protected String name;
+ protected String managedClassName;
+ protected String managedPackageName;
+
+ public abstract long getId();
+
+ public abstract Object get(PropertyBinding property);
+
+ public abstract void set(PropertyBinding property, Object value);
+
+ public abstract Object[] invoke(MethodBinding method, Object... args);
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public String getManagedClassName()
+ {
+ return managedClassName;
+ }
+
+ public void setManagedClassName(String managedClassName)
+ {
+ this.managedClassName = managedClassName;
+ }
+
+ public String getManagedPackageName()
+ {
+ return managedPackageName;
+ }
+
+ public void setManagedPackageName(String managedPackageName)
+ {
+ this.managedPackageName = managedPackageName;
+ }
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedPOJO.java b/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedPOJO.java
new file mode 100644
index 0000000000..94d9b9d0a8
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/ManagedPOJO.java
@@ -0,0 +1,90 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.agent.binding.BindingUtils;
+import org.apache.qpid.agent.binding.MethodBinding;
+import org.apache.qpid.agent.binding.PropertyBinding;
+
+/**
+ * Wrapper classe for adding POJOS which are to be managed by the QMF Agent.
+ */
+public class ManagedPOJO extends ManagedObjectBase implements ManagedObject
+{
+ private Log log = LogFactory.getLog(ManagedPOJO.class);
+ private Object managed;
+
+ public ManagedPOJO()
+ {
+ super();
+ }
+
+ public ManagedPOJO(Object managed)
+ {
+ super();
+ this.setManaged(managed);
+ }
+
+ @Override
+ public long getId()
+ {
+ if (managed == null)
+ {
+ throw new AgentException("The managed object is null");
+ }
+ return System.identityHashCode(managed);
+ }
+
+ public Class getObjectClass()
+ {
+ return managed.getClass();
+ }
+
+ public Object getManaged()
+ {
+ return managed;
+ }
+
+ public void setManaged(Object managed)
+ {
+ this.managed = managed;
+ }
+
+ @Override
+ public Object get(PropertyBinding property)
+ {
+ return BindingUtils.get(property, managed);
+ }
+
+ @Override
+ public Object[] invoke(MethodBinding method, Object... args)
+ {
+ return BindingUtils.invoke(method, managed, args);
+ }
+
+ @Override
+ public void set(PropertyBinding property, Object value)
+ {
+ BindingUtils.set(property, value, managed);
+ }
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFAgent.java b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFAgent.java
new file mode 100644
index 0000000000..b9fcf40fc1
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFAgent.java
@@ -0,0 +1,34 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent.annotations;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Target(ElementType.FIELD)
+@Retention(RUNTIME)
+@Documented
+public @interface QMFAgent
+{
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFEvent.java b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFEvent.java
new file mode 100644
index 0000000000..314f2a7e68
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFEvent.java
@@ -0,0 +1,42 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent.annotations;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Tells the QMF Agent that this object will be passed as a QMF event. This will
+ * cause only properties to be sent across the wire.
+ */
+@Target(TYPE)
+@Retention(RUNTIME)
+@Documented
+public @interface QMFEvent
+{
+ String eventName();
+
+ String packageName();
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFHide.java b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFHide.java
new file mode 100644
index 0000000000..db6cb0412f
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFHide.java
@@ -0,0 +1,39 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent.annotations;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Causes the property which is annotated to not be added to the QMF schema when
+ * it is built.
+ */
+@Target(ElementType.METHOD)
+@Retention(RUNTIME)
+@Documented
+public @interface QMFHide
+{
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFObject.java b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFObject.java
new file mode 100644
index 0000000000..7d1713cdbe
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFObject.java
@@ -0,0 +1,42 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent.annotations;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Tells the QMF Agent that this object will be a managed object. This will
+ * allow users to query for it, as well as invoke methods on it.
+ */
+@Target(TYPE)
+@Retention(RUNTIME)
+@Documented
+public @interface QMFObject
+{
+ String className();
+
+ String packageName();
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFProperty.java b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFProperty.java
new file mode 100644
index 0000000000..f309fa95b5
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFProperty.java
@@ -0,0 +1,39 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent.annotations;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Controls the QMF schema which is generated for this property.
+ */
+@Target(ElementType.FIELD)
+@Retention(RUNTIME)
+@Documented
+public @interface QMFProperty
+{
+ boolean optional() default false;
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFSeeAlso.java b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFSeeAlso.java
new file mode 100644
index 0000000000..bb9b87805d
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFSeeAlso.java
@@ -0,0 +1,40 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent.annotations;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Augements the schema generation process to look for known subclasses of a
+ * type. Modeled after the JAXB @XMLSeeAlso.
+ */
+@Target(TYPE)
+@Retention(RUNTIME)
+@Documented
+public @interface QMFSeeAlso
+{
+ Class[] value();
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFType.java b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFType.java
new file mode 100644
index 0000000000..8da1e15124
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/annotations/QMFType.java
@@ -0,0 +1,42 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent.annotations;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Tells the QMF Agent that this object will be a type only This will cause only
+ * properties to be sent across the wire.
+ */
+@Target(TYPE)
+@Retention(RUNTIME)
+@Documented
+public @interface QMFType
+{
+ String className();
+
+ String packageName();
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/binding/BindingContext.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/BindingContext.java
new file mode 100644
index 0000000000..835fed0ce1
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/BindingContext.java
@@ -0,0 +1,213 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.agent.annotations.QMFEvent;
+import org.apache.qpid.agent.annotations.QMFObject;
+import org.apache.qpid.agent.annotations.QMFSeeAlso;
+import org.apache.qpid.agent.annotations.QMFType;
+
+/**
+ * Contains the mappings from java classes to QMF schema and back. There is one
+ * context per agent, and it contains all the metadata.
+ */
+public class BindingContext
+{
+ private static Log log = LogFactory.getLog(BindingContext.class);
+ private Map<Key, ClassBinding> classes = new Hashtable<Key, ClassBinding>();
+ private ArrayList<String> packages = new ArrayList<String>();
+
+ static class Key
+ {
+ String packageName = "";
+ String className = "";
+ boolean object = false;
+
+ @Override
+ public int hashCode()
+ {
+ return (packageName + "." + className).hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ return ((obj.getClass() == Key.class)
+ && (((Key) obj).packageName.equals(packageName)) && (((Key) obj).className
+ .equals(className)));
+ }
+ }
+
+ public BindingContext()
+ {
+ Key key = new Key();
+ key.className = "Object";
+ key.packageName = "org.apache.qmf";
+ key.object = false;
+ ClassBinding cb = new ClassBinding("org.apache.qmf", "Object",
+ Object.class, false, this);
+ classes.put(key, cb);
+ packages.add("org.apache.qmf");
+ }
+
+ public ClassBinding getClassBinding(Class clazz)
+ {
+ return classes.get(getClassKey(clazz));
+ }
+
+ public ClassBinding getClassBinding(String packageName, String className)
+ {
+ Key key = new Key();
+ key.packageName = packageName;
+ key.className = className;
+ return classes.get(key);
+ }
+
+ public ClassBinding register(Class cls)
+ {
+ String name = cls.getName();
+ ClassBinding cb = getClassBinding(cls);
+ if (cb == null)
+ {
+ Key key = getClassKey(cls);
+ // Create and store the internal representations
+ if (cls.isEnum())
+ {
+ cb = new EnumBinding(key.packageName, key.className, cls,
+ key.object, this);
+ } else
+ {
+ cb = new ClassBinding(key.packageName, key.className, cls,
+ key.object, this);
+ }
+ log.debug(String.format(
+ "Added class binding '%s' in package %s for class %s'",
+ key.className, key.packageName, cls.getCanonicalName()));
+ classes.put(key, cb);
+ if (!packages.contains(key.packageName))
+ {
+ packages.add(key.packageName);
+ }
+ // Parse the methods after adding the class to avoid recursion
+ cb.parse();
+ // See if there are other classes which should be looked at
+ QMFSeeAlso seeAlso = (QMFSeeAlso) cls
+ .getAnnotation(QMFSeeAlso.class);
+ if (seeAlso != null)
+ {
+ for (Class seeAlsoCls : seeAlso.value())
+ {
+ this.register(seeAlsoCls);
+ }
+ }
+ }
+ return cb;
+ }
+
+ public TypeBinding getTypeBinding(Class cls)
+ {
+ // Look for a built in type
+ TypeBinding type = QMFTypeBinding.forClass(cls);
+ // Have we seen it before?
+ if (type == null)
+ {
+ type = this.getClassBinding(cls);
+ }
+ if ((type == null) && List.class.isAssignableFrom(cls))
+ {
+ type = new ListBinding(this, cls);
+ }
+ if ((type == null) && Map.class.isAssignableFrom(cls))
+ {
+ type = new MapBinding(this, cls);
+ }
+ // Add it, but since we have not seen it before do not expose methods
+ if (type == null)
+ {
+ type = this.register(cls);
+ }
+ return type;
+ }
+
+ // FIXME: Need to store these keys off so we dont create alot of objects
+ protected Key getClassKey(Class cls)
+ {
+ Key key = new Key();
+ QMFObject objAnnotation = (QMFObject) cls
+ .getAnnotation(QMFObject.class);
+ if (objAnnotation != null)
+ {
+ key.className = objAnnotation.className();
+ key.packageName = objAnnotation.packageName();
+ key.object = true;
+ } else
+ {
+ QMFType typeAnnotation = (QMFType) cls.getAnnotation(QMFType.class);
+ if (typeAnnotation != null)
+ {
+ key.className = typeAnnotation.className();
+ key.packageName = typeAnnotation.packageName();
+ } else
+ {
+ QMFEvent eventAnnotation = (QMFEvent) cls
+ .getAnnotation(QMFEvent.class);
+ if (eventAnnotation != null)
+ {
+ key.className = eventAnnotation.eventName();
+ key.packageName = eventAnnotation.packageName();
+ } else
+ {
+ // If this is Object, we return the fake
+ // object value
+ if (cls == Object.class)
+ {
+ key.className = "Object";
+ key.packageName = "org.apache.qmf";
+ } else
+ {
+ String name = cls.getName();
+ int lastDot = name.lastIndexOf('.');
+ key.className = name.substring(lastDot + 1);
+ key.packageName = name.substring(0, lastDot);
+ }
+ }
+ }
+ }
+ return key;
+ }
+
+ public ArrayList<String> getPackages()
+ {
+ return packages;
+ }
+
+ public Collection<ClassBinding> getAllBindings()
+ {
+ return classes.values();
+ }
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/binding/BindingException.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/BindingException.java
new file mode 100644
index 0000000000..f8e436290c
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/BindingException.java
@@ -0,0 +1,50 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+/**
+ * ManagedException
+ *
+ */
+public class BindingException extends RuntimeException
+{
+ private static final long serialVersionUID = -7350845525748113340L;
+
+ public BindingException(Throwable t)
+ {
+ super(t);
+ }
+
+ public BindingException()
+ {
+ super();
+ }
+
+ public BindingException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+
+ public BindingException(String message)
+ {
+ super(message);
+ }
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/binding/BindingUtils.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/BindingUtils.java
new file mode 100644
index 0000000000..14f3fda0f1
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/BindingUtils.java
@@ -0,0 +1,137 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import java.beans.BeanInfo;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class BindingUtils
+{
+ private static Log log = LogFactory.getLog(BindingUtils.class);
+
+ public static Object get(PropertyBinding property, Object managed)
+ {
+ String name = property.getName();
+ return get(name, managed);
+ }
+
+ public static void set(PropertyBinding property, Object value,
+ Object managed)
+ {
+ String name = property.getName();
+ TypeBinding type = property.getType();
+ try
+ {
+ Method meth = managed.getClass().getMethod(accessor("set", name),
+ type.getJavaClass());
+ meth.invoke(managed, value);
+ } catch (NoSuchMethodException e)
+ {
+ throw new BindingException(e);
+ } catch (IllegalAccessException e)
+ {
+ throw new BindingException(e);
+ } catch (InvocationTargetException e)
+ {
+ throw new BindingException(e.getTargetException());
+ }
+ }
+
+ public static Object[] invoke(MethodBinding method, Object managed,
+ Object... args)
+ {
+ log.debug(String.format("Invoking %s on %s", method.getName(), managed
+ .getClass()));
+ List<ParameterBinding> in = method.getInParameters();
+ List<ParameterBinding> out = method.getOutParameters();
+ Class<?>[] classes = new Class<?>[in.size()];
+ int idx = 0;
+ for (ParameterBinding p : in)
+ {
+ classes[idx++] = p.getType().getJavaClass();
+ }
+ Object result;
+ try
+ {
+ Method meth = managed.getClass().getMethod(method.getName(),
+ classes);
+ result = meth.invoke(managed, args);
+ } catch (NoSuchMethodException e)
+ {
+ throw new BindingException(e);
+ } catch (IllegalAccessException e)
+ {
+ throw new BindingException(e);
+ } catch (InvocationTargetException e)
+ {
+ throw new BindingException(e.getTargetException());
+ }
+ Object[] results = new Object[out.size()];
+ // XXX: need better way to distinguish this case
+ if (out.size() == 1 && out.get(0).getName().equals("result"))
+ {
+ results[0] = result;
+ } else
+ {
+ for (int i = 0; i < results.length; i++)
+ {
+ results[i] = get(out.get(i).getName(), result);
+ }
+ }
+ return results;
+ }
+
+ public static String accessor(String pfx, String property)
+ {
+ return pfx + Character.toUpperCase(property.charAt(0))
+ + property.substring(1);
+ }
+
+ public static Object get(String name, Object obj)
+ {
+ Object returnValue = null;
+ try
+ {
+ BeanInfo info = Introspector.getBeanInfo(obj.getClass());
+ PropertyDescriptor[] pds = info.getPropertyDescriptors();
+ for (PropertyDescriptor pd : pds)
+ {
+ if (pd.getName().equals(name))
+ {
+ Method getMethod = pd.getReadMethod();
+ returnValue = getMethod.invoke(obj);
+ break;
+ }
+ }
+ } catch (Exception e)
+ {
+ throw new BindingException(e);
+ }
+ return returnValue;
+ }
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/binding/ClassBinding.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/ClassBinding.java
new file mode 100644
index 0000000000..0a74958023
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/ClassBinding.java
@@ -0,0 +1,602 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.agent.annotations.QMFEvent;
+import org.apache.qpid.agent.annotations.QMFObject;
+import org.apache.qpid.agent.annotations.QMFProperty;
+import org.apache.qpid.agent.annotations.QMFSeeAlso;
+import org.apache.qpid.agent.annotations.QMFType;
+import org.apache.qpid.agent.annotations.QMFHide;
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+/**
+ * Binding information from a custom java class to a QMF schema
+ */
+public class ClassBinding implements TypeBinding
+{
+ private static Log log = LogFactory.getLog(ClassBinding.class);
+
+ private static enum MethodType
+ {
+ READ_ONLY, READ_WRITE, METHOD, IGNORE
+ }
+
+ protected boolean exposeBehaviour = true;
+ protected String pkg;
+ protected BindingContext bctx;
+ protected String name;
+ protected ArrayList<PropertyBinding> properties = new ArrayList<PropertyBinding>();
+ protected ArrayList<MethodBinding> methods = new ArrayList<MethodBinding>();
+ protected Map<String, MethodBinding> methodsByName = new HashMap<String, MethodBinding>();
+ protected Class javaClass;
+ protected short kind = 1;
+ protected byte hash[] = null;
+ protected ClassBinding superType = null;
+
+ public ClassBinding(String pkg, String name, Class cls,
+ boolean exposeBehaviour, BindingContext bctx)
+ {
+ this.pkg = pkg;
+ this.name = name;
+ this.bctx = bctx;
+ this.javaClass = cls;
+ this.exposeBehaviour = exposeBehaviour;
+ }
+
+ protected MethodType classify(Class<?> cls, Method m)
+ {
+ String name = m.getName();
+ MethodType returnValue = MethodType.METHOD;
+ String propPrefixes[] =
+ { "get", "is" };
+ for (String prefix : propPrefixes)
+ {
+ if (name.startsWith(prefix) && m.getParameterTypes().length == 0)
+ {
+ try
+ {
+ Class<?> type = m.getReturnType();
+ Method setter = cls.getMethod("set"
+ + name.substring(prefix.length()), type);
+ returnValue = MethodType.READ_WRITE;
+ } catch (NoSuchMethodException e)
+ {
+ returnValue = MethodType.READ_ONLY;
+ }
+ break;
+ }
+ }
+ return returnValue;
+ }
+
+ protected String property(Method m)
+ {
+ String name = m.getName();
+ String propPrefixes[] =
+ { "get", "is" };
+ for (String prefix : propPrefixes)
+ {
+ if (name.startsWith(prefix) && m.getParameterTypes().length == 0)
+ {
+ String sfx = name.substring(prefix.length());
+ return Character.toLowerCase(sfx.charAt(0)) + sfx.substring(1);
+ }
+ }
+ // If we got here, it is n invalid property
+ throw new IllegalArgumentException("" + m);
+ }
+
+ protected ArrayList<Method> getMethods(Class cls)
+ {
+ ArrayList returnValue = new ArrayList();
+ ArrayList nameList = new ArrayList();
+ if ((cls != null) && (!cls.equals(Object.class)))
+ {
+ for (Method m : cls.getDeclaredMethods())
+ {
+ if (m.getAnnotation(QMFHide.class) == null)
+ // && (!Modifier.isAbstract(m.getModifiers())))
+ {
+ returnValue.add(m);
+ nameList.add(m.getName());
+ }
+ }
+ // Look at the superclass, if it is also a
+ // QMF object then stop.
+ Class superType = cls.getSuperclass();
+ if (!this.hasQMFSupertype(cls))
+ {
+ for (Method m : this.getMethods(cls.getSuperclass()))
+ {
+ if (!nameList.contains(m.getName()))
+ {
+ returnValue.add(m);
+ nameList.add(m.getName());
+ }
+ }
+ }
+ }
+ return returnValue;
+ }
+
+ protected boolean hasQMFSupertype(Class cls)
+ {
+ boolean returnValue = false;
+ Class superType = cls.getSuperclass();
+ if (superType != null)
+ {
+ if ((superType.getAnnotation(QMFObject.class) != null)
+ || (superType.getAnnotation(QMFType.class) != null)
+ || (superType.getAnnotation(QMFSeeAlso.class) != null)
+ || (superType.getAnnotation(QMFEvent.class) != null))
+ {
+ returnValue = true;
+ }
+ }
+ return returnValue;
+ }
+
+ protected boolean isOptional(Method m, TypeBinding type)
+ {
+ boolean returnValue = false;
+ // Look for the annotaiton first
+ QMFProperty ann = m.getAnnotation(QMFProperty.class);
+ if (ann != null)
+ {
+ returnValue = ann.optional();
+ } else
+ {
+ returnValue = type.optionalDefault();
+ }
+ return returnValue;
+ }
+
+ public ClassBinding parse()
+ {
+ log.debug(String.format(
+ "Parsing class binding '%s' for package '%s' from class %s",
+ name, pkg, javaClass.getName()));
+ for (Method m : this.getMethods(javaClass))
+ {
+ String mname = m.getName();
+ Class<?> type = m.getReturnType();
+ switch (classify(javaClass, m))
+ {
+ case READ_ONLY:
+ TypeBinding tb = bctx.getTypeBinding(type);
+ boolean optional = isOptional(m, tb);
+ properties.add(new PropertyBinding(property(m), tb,
+ PropertyBinding.READ_ONLY, optional));
+ break;
+ case READ_WRITE:
+ TypeBinding tbnd = bctx.getTypeBinding(type);
+ boolean opt = isOptional(m, tbnd);
+ properties.add(new PropertyBinding(property(m), tbnd,
+ PropertyBinding.READ_WRITE, opt));
+ break;
+ case METHOD:
+ // Only expose methods if told to
+ if (exposeBehaviour)
+ {
+ List<ParameterBinding> params = new ArrayList<ParameterBinding>();
+ int arg = 0;
+ for (Class pcls : m.getParameterTypes())
+ {
+ params.add(new ParameterBinding("arg" + arg++, bctx
+ .getTypeBinding(pcls), true, false));
+ }
+ if (type != void.class)
+ {
+ params.add(new ParameterBinding("result", bctx
+ .getTypeBinding(type), false, true));
+ }
+ methods.add(new MethodBinding(mname, params));
+ }
+ break;
+ case IGNORE:
+ break;
+ }
+ }
+ for (MethodBinding m : methods)
+ {
+ methodsByName.put(m.getName(), m);
+ }
+ QMFEvent eventAnnotation = (QMFEvent) javaClass
+ .getAnnotation(QMFEvent.class);
+ if (eventAnnotation != null)
+ {
+ kind = 2; // Event Type
+ }
+ // if (this.hasQMFSupertype(javaClass)) {
+ if ((javaClass.getSuperclass() != Object.class)
+ && (javaClass.getSuperclass() != null))
+ {
+ superType = bctx.register(javaClass.getSuperclass());
+ }
+ return this;
+ }
+
+ public String getPackage()
+ {
+ return pkg;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public List<PropertyBinding> getProperties()
+ {
+ return properties;
+ }
+
+ public List<PropertyBinding> getAllProperties()
+ {
+ if (this.superType == null)
+ {
+ return properties;
+ } else
+ {
+ List<PropertyBinding> newList = new ArrayList<PropertyBinding>(
+ properties);
+ for (PropertyBinding p : superType.getAllProperties())
+ {
+ if (!newList.contains(p))
+ {
+ newList.add(p);
+ }
+ }
+ return newList;
+ }
+ }
+
+ public List<MethodBinding> getMethods()
+ {
+ return methods;
+ }
+
+ public MethodBinding getMethod(String name)
+ {
+ return methodsByName.get(name);
+ }
+
+ // Use this format
+ // bytes value
+ // 0-3 package name
+ // 4-7 class name
+ // 8-11 property signature hash
+ // 12-15 method signature hash
+ // FIXME: Hash codes seem to mess things up
+ public byte[] getSchemaHash()
+ {
+ if (null == hash)
+ {
+ hash = new byte[16];
+ StringBuilder blder = new StringBuilder();
+ int packageHash = pkg.hashCode();
+ int classHash = name.hashCode();
+ int propertyHash = 0;
+ int methodHash = 0;
+ for (PropertyBinding p : properties)
+ {
+ blder.append(p.getName()).append(":").append(
+ p.getType().getCode()).append(":")
+ .append(p.getAccess()).append(":").append(
+ p.isOptional());
+ }
+ propertyHash = blder.toString().hashCode();
+ blder = new StringBuilder();
+ for (MethodBinding m : methods)
+ {
+ blder.append(m.getName());
+ for (ParameterBinding p : m.getParameters())
+ {
+ String direction = p.isIn() ? "in" : "out";
+ blder.append(":").append(p.getName()).append(":").append(
+ direction).append(":")
+ .append(p.getType().getCode());
+ }
+ }
+ methodHash = blder.toString().hashCode();
+ hash[0] = (byte) (packageHash >> 24);
+ hash[1] = (byte) (packageHash >> 16);
+ hash[2] = (byte) (packageHash >> 8);
+ hash[3] = (byte) (packageHash);
+ hash[4] = (byte) (classHash >> 24);
+ hash[5] = (byte) (classHash >> 16);
+ hash[6] = (byte) (classHash >> 8);
+ hash[7] = (byte) (classHash);
+ hash[8] = (byte) (propertyHash >> 24);
+ hash[9] = (byte) (propertyHash >> 16);
+ hash[10] = (byte) (propertyHash >> 8);
+ hash[11] = (byte) (propertyHash);
+ hash[12] = (byte) (methodHash >> 24);
+ hash[13] = (byte) (methodHash >> 16);
+ hash[14] = (byte) (methodHash >> 8);
+ hash[15] = (byte) (methodHash);
+ }
+ return hash;
+ }
+
+ public void encode(Encoder enc)
+ {
+ log.debug(String.format("encoding %s %s with superclass %s", this
+ .getRefClass(), this.getRefPackage(), superType));
+ enc.writeUint8(kind); // kind
+ enc.writeStr8(pkg);
+ enc.writeStr8(name);
+ enc.writeBin128(this.getSchemaHash()); // schema hash
+ // Send true (1) if we have a super-type
+ //if (superType == null)
+ //{
+ // enc.writeUint8((short) 0);
+ //} else
+ //{
+ // enc.writeUint8((short) 1);
+ //}
+ enc.writeUint16(properties.size());
+ // Events do not have the method size sent
+ if (kind == 1)
+ {
+ enc.writeUint16(0);
+ enc.writeUint16(methods.size());
+ }
+ // Add the super type information if we have it
+ //if (superType != null)
+ //{
+ // enc.writeStr8(superType.pkg);
+ // enc.writeStr8(superType.name);
+ // enc.writeBin128(superType.getSchemaHash()); // schema hash
+ //}
+ for (PropertyBinding p : properties)
+ {
+ log.trace("encoding property " + p.getName());
+ p.encode(enc);
+ }
+ for (MethodBinding m : methods)
+ {
+ m.encode(enc);
+ }
+ }
+
+ // Type Binding functions
+ public short getCode()
+ {
+ return (short) 20;
+ }
+
+ public Class<?> getJavaClass()
+ {
+ return javaClass;
+ }
+
+ public Object decode(Decoder dec)
+ {
+ // FIXME This only works with POJOs
+ short typeCode = dec.readUint8();
+ log.trace("Type code: " + typeCode);
+ if (typeCode == 20)
+ {
+ String packageName = dec.readStr8();
+ String className = dec.readStr8();
+ log
+ .debug(String
+ .format(
+ "Decoding an object for package %s class %s with bindings for %s %s",
+ packageName, className, this.pkg, this.name));
+ byte schemaHash[] = dec.readBin128();
+ // Check to see that this is me, and not a subclass
+ if (packageName.equals(this.pkg) && className.equals(this.name))
+ {
+ return decodeWithNoHeaders(dec);
+ } else
+ {
+ ClassBinding mcls = bctx
+ .getClassBinding(packageName, className);
+ return mcls.decodeWithNoHeaders(dec);
+ }
+ } else
+ {
+ TypeBinding tb = QMFTypeBinding.getType(typeCode);
+ return tb.decode(dec);
+ }
+ }
+
+ protected Object decodeWithNoHeaders(Decoder dec)
+ {
+ Object instance = null;
+ try
+ {
+ log.trace("Creating a new instance of " + this.javaClass.getName());
+ instance = this.javaClass.newInstance();
+ } catch (Exception e)
+ {
+ log.error("Could not instantiate object of class"
+ + this.javaClass.getName());
+ throw new BindingException(e);
+ }
+ List<String> excludes = this.processPresenceMasks(dec);
+ for (PropertyBinding p : getAllProperties())
+ {
+ if (!excludes.contains(p.getName()))
+ {
+ Object value = p.getType().decode(dec);
+ BindingUtils.set(p, value, instance);
+ }
+ }
+ return instance;
+ }
+
+ protected List<String> processPresenceMasks(Decoder dec)
+ {
+ List<String> excludes = new ArrayList<String>();
+ short bit = 0;
+ short mask = 0;
+ for (PropertyBinding prop : properties)
+ {
+ if (prop.isOptional())
+ {
+ if (bit == 0)
+ {
+ mask = dec.readUint8();
+ bit = 1;
+ }
+ if ((mask & bit) == 0)
+ {
+ log.trace("Going in exclude " + prop.getName());
+ excludes.add(prop.getName());
+ }
+ bit *= 2;
+ if (bit == 256)
+ {
+ bit = 0;
+ }
+ }
+ }
+ return excludes;
+ }
+
+ public void encode(Encoder enc, Object value)
+ {
+ // if the object is null, assume this is the
+ // correct class
+ if (value == null || (value.getClass().equals(this.javaClass)))
+ {
+ String pkg = getPackage();
+ String cls = getName();
+ log.debug(String.format("Encoding class %s:%s", pkg, cls));
+ enc.writeUint8(this.getCode());
+ enc.writeStr8(pkg);
+ enc.writeStr8(cls);
+ enc.writeBin128(this.getSchemaHash());
+ short bit = 0;
+ short mask = 0;
+ if (value != null)
+ {
+ // Encode the property presence masks first.
+ // if this is not an event
+ if (!isEvent())
+ {
+ for (PropertyBinding p : getAllProperties())
+ {
+ if (p.isOptional())
+ {
+ Object pValue = BindingUtils.get(p, value);
+ if (bit == 0)
+ bit = 1;
+ if (pValue != null)
+ {
+ mask |= bit;
+ }
+ if (bit == 128)
+ {
+ enc.writeUint8(mask);
+ bit = 0;
+ mask = 0;
+ } else
+ {
+ bit = (short) (bit << 1);
+ }
+ }
+ }
+ if (bit != 0)
+ {
+ enc.writeUint8(mask);
+ }
+ }
+ // Now put the actual properties
+ for (PropertyBinding p : getAllProperties())
+ {
+ Object pValue = BindingUtils.get(p, value);
+ if (!p.isOptional() || !(pValue == null))
+ {
+ log.trace(String.format("Encoding property %s", p
+ .getName()));
+ p.getType().encode(enc, pValue);
+ }
+ }
+ }
+ log.debug(String.format("Done with %s:%s", pkg, cls));
+ } else
+ {
+ TypeBinding tb = bctx.getTypeBinding(value.getClass());
+ if (tb == null)
+ {
+ throw new BindingException(String.format(
+ "No class named %s defined for this context ", value
+ .getClass()));
+ } else
+ {
+ if (tb.isNative())
+ {
+ enc.writeUint8(tb.getCode());
+ }
+ tb.encode(enc, value);
+ }
+ }
+ }
+
+ public boolean isNative()
+ {
+ return false;
+ }
+
+ public boolean optionalDefault()
+ {
+ return true;
+ }
+
+ public String getRefClass()
+ {
+ return this.name;
+ }
+
+ public String getRefPackage()
+ {
+ return this.pkg;
+ }
+
+ public short getKind()
+ {
+ return kind;
+ }
+
+ public boolean isEvent()
+ {
+ return kind == 2;
+ }
+
+ public void setKind(short kind)
+ {
+ this.kind = kind;
+ }
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/binding/EnumBinding.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/EnumBinding.java
new file mode 100644
index 0000000000..dcb619b736
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/EnumBinding.java
@@ -0,0 +1,108 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+/**
+ * Binding information from a java enum to a QMF schema
+ */
+public class EnumBinding extends ClassBinding
+{
+ private static Log log = LogFactory.getLog(EnumBinding.class);
+
+ public EnumBinding(String pkg, String name, Class cls,
+ boolean exposeBehaviour, BindingContext bctx)
+ {
+ super(pkg, name, cls, exposeBehaviour, bctx);
+ }
+
+ @Override
+ public void encode(Encoder enc)
+ {
+ enc.writeUint8((short) 1); // kind
+ enc.writeStr8(pkg);
+ enc.writeStr8(name);
+ enc.writeBin128(new byte[16]); // schema hash
+ // FIXME Is there a way to send the valid types?
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ if (value != null)
+ {
+ enc.writeStr16(value.toString());
+ } else
+ {
+ enc.writeStr16("");
+ }
+ }
+
+ @Override
+ public Object decode(Decoder dec)
+ {
+ // FIXME This only works with POJOs
+ Object instance = null;
+ String value = null;
+ try
+ {
+ value = dec.readStr16();
+ if ((value != null) && (!value.isEmpty()))
+ {
+ instance = Enum.valueOf((Class<Enum>) this.getJavaClass(),
+ value);
+ }
+ } catch (Exception e)
+ {
+ log.error(String.format(
+ "Could not create an enum of type %s with value %s",
+ this.javaClass.getName(), value));
+ throw new BindingException(e);
+ }
+ return instance;
+ }
+
+ // Make this look like a String
+ @Override
+ public short getCode()
+ {
+ return (short) 7;
+ }
+
+ @Override
+ public EnumBinding parse()
+ {
+ log.debug(String.format(
+ "Parsing enum binding '%s' for package '%s' from class %s",
+ name, pkg, javaClass.getName()));
+ return this;
+ }
+
+ @Override
+ public boolean optionalDefault()
+ {
+ return false;
+ }
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/binding/ListBinding.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/ListBinding.java
new file mode 100644
index 0000000000..a3658a812c
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/ListBinding.java
@@ -0,0 +1,131 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.transport.codec.BBDecoder;
+import org.apache.qpid.transport.codec.BBEncoder;
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+/**
+ * Binding information from a java list to a QMF schema.
+ */
+public class ListBinding implements TypeBinding
+{
+ private static Log log = LogFactory.getLog(ListBinding.class);
+ protected BindingContext bctx;
+ protected Class javaClass;
+
+ public ListBinding(BindingContext bctx, Class javaClass)
+ {
+ this.bctx = bctx;
+ this.javaClass = javaClass;
+ }
+
+ public void encode(Encoder enc, Object value)
+ {
+ List list = (List) value;
+ BBEncoder newEncoder = new BBEncoder(10);
+ if (list != null)
+ {
+ newEncoder.writeUint32(list.size());
+ for (Object obj : list)
+ {
+ TypeBinding type = bctx.getTypeBinding(obj.getClass());
+ newEncoder.writeUint8(type.getCode());
+ type.encode(newEncoder, obj);
+ }
+ } else
+ {
+ newEncoder.writeUint32(0);
+ }
+ enc.writeVbin32(newEncoder.buffer().array());
+ }
+
+ public Object decode(Decoder dec)
+ {
+ List list = null;
+ try
+ {
+ list = (List) javaClass.newInstance();
+ } catch (Exception e)
+ {
+ throw new BindingException(
+ "Could not create a List implementation for "
+ + javaClass.getName(), e);
+ }
+ BBDecoder newDecoder = new BBDecoder();
+ newDecoder.init(ByteBuffer.wrap(dec.readVbin32()));
+ long count = newDecoder.readUint32();
+ while (count > 0)
+ {
+ short typeCode = newDecoder.readUint8();
+ TypeBinding type = QMFTypeBinding.getType(typeCode);
+ if (type == null)
+ {
+ type = bctx.getTypeBinding(Object.class);
+ }
+ list.add(type.decode(newDecoder));
+ count -= 1;
+ }
+ return list;
+ }
+
+ // QMF List Type
+ public short getCode()
+ {
+ return (short) 21;
+ }
+
+ @Override
+ public Class<?> getJavaClass()
+ {
+ return javaClass;
+ }
+
+ @Override
+ public String getRefClass()
+ {
+ return null;
+ }
+
+ @Override
+ public String getRefPackage()
+ {
+ return null;
+ }
+
+ @Override
+ public boolean isNative()
+ {
+ return true;
+ }
+
+ public boolean optionalDefault()
+ {
+ return false;
+ }
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/binding/MapBinding.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/MapBinding.java
new file mode 100644
index 0000000000..02d562a59a
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/MapBinding.java
@@ -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.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.transport.codec.BBDecoder;
+import org.apache.qpid.transport.codec.BBEncoder;
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+/**
+ * Binding information from a java Map to a QMF schema.
+ */
+public class MapBinding implements TypeBinding
+{
+ private static Log log = LogFactory.getLog(MapBinding.class);
+ protected BindingContext bctx;
+ protected Class javaClass;
+
+ public MapBinding(BindingContext bctx, Class javaClass)
+ {
+ this.bctx = bctx;
+ this.javaClass = javaClass;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void encode(Encoder enc, Object value)
+ {
+ Map map = (Map) value;
+ enc.writeMap(map);
+ }
+
+ public Object decode(Decoder dec)
+ {
+ Map map = dec.readMap();
+ return map;
+ }
+
+ // QMF List Type
+ public short getCode()
+ {
+ return (short) 15;
+ }
+
+ @Override
+ public Class<?> getJavaClass()
+ {
+ return javaClass;
+ }
+
+ @Override
+ public String getRefClass()
+ {
+ return null;
+ }
+
+ @Override
+ public String getRefPackage()
+ {
+ return null;
+ }
+
+ @Override
+ public boolean isNative()
+ {
+ return true;
+ }
+
+ public boolean optionalDefault()
+ {
+ return false;
+ }
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/binding/MethodBinding.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/MethodBinding.java
new file mode 100644
index 0000000000..fc05c7393a
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/MethodBinding.java
@@ -0,0 +1,91 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.transport.codec.Encoder;
+
+/**
+ * Metadata for mapping a method to a QMF schema
+ */
+public class MethodBinding
+{
+ private final String name;
+ private final List<ParameterBinding> parameters;
+ private final List<ParameterBinding> inParameters = new ArrayList<ParameterBinding>();
+ private final List<ParameterBinding> outParameters = new ArrayList<ParameterBinding>();
+ private Log log = LogFactory.getLog(MethodBinding.class);
+
+ public MethodBinding(String name, List<ParameterBinding> parameters)
+ {
+ this.name = name;
+ this.parameters = parameters;
+ for (ParameterBinding p : parameters)
+ {
+ if (p.isIn())
+ {
+ inParameters.add(p);
+ }
+ if (p.isOut())
+ {
+ outParameters.add(p);
+ }
+ }
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public List<ParameterBinding> getParameters()
+ {
+ return parameters;
+ }
+
+ public List<ParameterBinding> getInParameters()
+ {
+ return inParameters;
+ }
+
+ public List<ParameterBinding> getOutParameters()
+ {
+ return outParameters;
+ }
+
+ void encode(Encoder enc)
+ {
+ Map map = new HashMap();
+ map.put("name", name);
+ map.put("argCount", parameters.size());
+ enc.writeMap(map);
+ for (ParameterBinding p : parameters)
+ {
+ p.encode(enc);
+ }
+ }
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/binding/ParameterBinding.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/ParameterBinding.java
new file mode 100644
index 0000000000..7362976e0e
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/ParameterBinding.java
@@ -0,0 +1,121 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.qpid.transport.codec.Encoder;
+
+/**
+ * Metadata for mapping a method argument to a QMF schema
+ */
+public class ParameterBinding
+{
+ private final String name;
+ private final TypeBinding type;
+ private final boolean in;
+ private final boolean out;
+
+ public ParameterBinding(String name, TypeBinding type, boolean in,
+ boolean out)
+ {
+ this.name = name;
+ this.type = type;
+ this.in = in;
+ this.out = out;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public TypeBinding getType()
+ {
+ return type;
+ }
+
+ public boolean isIn()
+ {
+ return in;
+ }
+
+ public boolean isOut()
+ {
+ return out;
+ }
+
+ void encode(Encoder enc)
+ {
+ Map map = new HashMap();
+ map.put("name", name);
+ map.put("type", type.getCode());
+ map.put("dir", (in ? "I" : "") + (out ? "O" : ""));
+ if (!type.isNative())
+ {
+ map.put("refClass", type.getRefClass());
+ map.put("refPackage", type.getRefPackage());
+ }
+ enc.writeMap(map);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (in ? 1231 : 1237);
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + (out ? 1231 : 1237);
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ParameterBinding other = (ParameterBinding) obj;
+ if (in != other.in)
+ return false;
+ if (name == null)
+ {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ if (out != other.out)
+ return false;
+ if (type == null)
+ {
+ if (other.type != null)
+ return false;
+ } else if (!type.equals(other.type))
+ return false;
+ return true;
+ }
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/binding/PropertyBinding.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/PropertyBinding.java
new file mode 100644
index 0000000000..604d66c818
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/PropertyBinding.java
@@ -0,0 +1,131 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.transport.codec.Encoder;
+
+/**
+ * Metadata for mapping a java property (getter/setter) to a QMF schema
+ */
+public class PropertyBinding
+{
+ private static Log log = LogFactory.getLog(PropertyBinding.class);
+ public final static int READ_CREATE = 1;
+ public final static int READ_WRITE = 2;
+ public final static int READ_ONLY = 3;
+ private String name;
+ private TypeBinding type;
+ private int accessType;
+ private boolean optional;
+
+ public PropertyBinding(String name, TypeBinding type, int accessType,
+ boolean optional)
+ {
+ this.name = name;
+ this.type = type;
+ this.accessType = accessType;
+ this.optional = optional;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + accessType;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ PropertyBinding other = (PropertyBinding) obj;
+ if (accessType != other.accessType)
+ return false;
+ if (name == null)
+ {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ if (type == null)
+ {
+ if (other.type != null)
+ return false;
+ } else if (!type.equals(other.type))
+ return false;
+ return true;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public TypeBinding getType()
+ {
+ return type;
+ }
+
+ public int getAccess()
+ {
+ return accessType;
+ }
+
+ public boolean isIndex()
+ {
+ return false;
+ }
+
+ public boolean isOptional()
+ {
+ return optional;
+ }
+
+ void encode(Encoder enc)
+ {
+ Map map = new HashMap();
+ map.put("name", name);
+ map.put("type", type.getCode());
+ map.put("access", getAccess());
+ map.put("index", isIndex() ? 1 : 0);
+ map.put("optional", isOptional() ? 1 : 0);
+ if (!type.isNative())
+ {
+ map.put("refClass", type.getRefClass());
+ map.put("refPackage", type.getRefPackage());
+ }
+ enc.writeMap(map);
+ }
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/binding/QMFTypeBinding.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/QMFTypeBinding.java
new file mode 100644
index 0000000000..11ccf1b1a7
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/QMFTypeBinding.java
@@ -0,0 +1,465 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+/**
+ * Basic type mappings for QMF schema
+ */
+public abstract class QMFTypeBinding implements TypeBinding
+{
+ private static final Map<Class<?>, QMFTypeBinding> TYPES = new HashMap<Class<?>, QMFTypeBinding>();
+ private static final Map<Short, QMFTypeBinding> TYPES_BY_CODE = new HashMap<Short, QMFTypeBinding>();
+ static
+ {
+ new QMFTypeBinding(null, (short) 1)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return Short.valueOf(dec.readUint8());
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeUint8(((Number) value).shortValue());
+ }
+ };
+ new QMFTypeBinding(null, (short) 2)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return Integer.valueOf(dec.readUint16());
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeUint16(((Number) value).intValue());
+ }
+ };
+ new QMFTypeBinding(null, (short) 3)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return Long.valueOf(dec.readUint32());
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeUint32(((Number) value).longValue());
+ }
+ };
+ new QMFTypeBinding(null, (short) 4)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return Long.valueOf(dec.readUint64());
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeUint64(((Number) value).longValue());
+ }
+ };
+ new QMFTypeBinding(null, (short) 6) // short string
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return dec.readStr8();
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ if (null == value)
+ value = "";
+ enc.writeStr8((String) value);
+ }
+ };
+ new QMFTypeBinding(String.class, (short) 7) // long string
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return dec.readStr16();
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ if (null == value)
+ value = "";
+ enc.writeStr16((String) value);
+ }
+ };
+ new QMFTypeBinding(Date.class, (short) 8)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return new Date(dec.readDatetime());
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeDatetime(((Date) value).getTime());
+ }
+ };
+ new QMFTypeBinding(Boolean.class, (short) 11)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return Boolean.valueOf(dec.readUint8() != 0);
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ if (((Boolean) value).booleanValue())
+ {
+ enc.writeUint8((short) 1);
+ } else
+ {
+ enc.writeUint8((short) 0);
+ }
+ }
+
+ @Override
+ public short[] alternateTypes()
+ {
+ short[] types =
+ { 5 };
+ return types;
+ }
+ };
+ new QMFTypeBinding(boolean.class, (short) 11)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return dec.readUint8() != 0;
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ if (((Boolean) value).booleanValue())
+ {
+ enc.writeUint8((short) 1);
+ } else
+ {
+ enc.writeUint8((short) 0);
+ }
+ }
+ };
+ new QMFTypeBinding(Float.class, (short) 12)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return Float.valueOf(dec.readFloat());
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeFloat(((Number) value).floatValue());
+ }
+ };
+ new QMFTypeBinding(float.class, (short) 12)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return dec.readFloat();
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeFloat(((Number) value).floatValue());
+ }
+ };
+ new QMFTypeBinding(Double.class, (short) 13)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return Double.valueOf(dec.readDouble());
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeDouble(((Number) value).doubleValue());
+ }
+ };
+ new QMFTypeBinding(double.class, (short) 13)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return dec.readDouble();
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeDouble(((Number) value).doubleValue());
+ }
+ };
+ new QMFTypeBinding(UUID.class, (short) 14)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return dec.readUuid();
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeUuid((UUID) value);
+ }
+ };
+ new QMFTypeBinding(byte.class, (short) 16)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return dec.readInt8();
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeInt8(((Number) value).byteValue());
+ }
+ };
+ new QMFTypeBinding(Short.class, (short) 17)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return Short.valueOf(dec.readInt16());
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeInt16(((Number) value).shortValue());
+ }
+ };
+ new QMFTypeBinding(short.class, (short) 17)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return dec.readInt16();
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeInt16(((Number) value).shortValue());
+ }
+ };
+ new QMFTypeBinding(Integer.class, (short) 18)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return Integer.valueOf(dec.readInt32());
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeInt32(((Number) value).intValue());
+ }
+ };
+ new QMFTypeBinding(int.class, (short) 18)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return dec.readInt32();
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeInt32(((Number) value).intValue());
+ }
+ };
+ new QMFTypeBinding(Long.class, (short) 19)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return Long.valueOf(dec.readInt64());
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeInt64(((Number) value).longValue());
+ }
+ };
+ new QMFTypeBinding(long.class, (short) 19)
+ {
+ @Override
+ public Object decode(Decoder dec)
+ {
+ return dec.readInt64();
+ }
+
+ @Override
+ public void encode(Encoder enc, Object value)
+ {
+ enc.writeInt64(((Number) value).longValue());
+ }
+ };
+ }
+
+ public static final QMFTypeBinding forClass(Class<?> cls)
+ {
+ QMFTypeBinding t = TYPES.get(cls);
+ return t;
+ }
+
+ public static final boolean isBound(Class<?> cls)
+ {
+ return TYPES.containsKey(cls);
+ }
+
+ public static QMFTypeBinding getType(short code)
+ {
+ return TYPES_BY_CODE.get(code);
+ }
+
+ private final Class<?> cls;
+ private final short code;
+
+ private QMFTypeBinding(Class<?> cls, short code)
+ {
+ this.cls = cls;
+ this.code = code;
+ if (cls != null)
+ {
+ TYPES.put(cls, this);
+ }
+ TYPES_BY_CODE.put(code, this);
+ for (short type : this.alternateTypes())
+ {
+ TYPES_BY_CODE.put(type, this);
+ }
+ }
+
+ public Class<?> getJavaClass()
+ {
+ return cls;
+ }
+
+ public short getCode()
+ {
+ return code;
+ }
+
+ public boolean isNative()
+ {
+ return true;
+ }
+
+ public boolean optionalDefault()
+ {
+ return false;
+ }
+
+ public String getRefClass()
+ {
+ return null;
+ }
+
+ public String getRefPackage()
+ {
+ return null;
+ }
+
+ public abstract Object decode(Decoder dec);
+
+ public abstract void encode(Encoder enc, Object value);
+
+ public short[] alternateTypes()
+ {
+ short[] types =
+ {};
+ return types;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((cls == null) ? 0 : cls.hashCode());
+ result = prime * result + code;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ QMFTypeBinding other = (QMFTypeBinding) obj;
+ if (cls == null)
+ {
+ if (other.cls != null)
+ return false;
+ } else if (!cls.equals(other.cls))
+ return false;
+ if (code != other.code)
+ return false;
+ return true;
+ }
+}
diff --git a/java/management/agent/src/main/java/org/apache/qpid/agent/binding/TypeBinding.java b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/TypeBinding.java
new file mode 100644
index 0000000000..97ec943bfd
--- /dev/null
+++ b/java/management/agent/src/main/java/org/apache/qpid/agent/binding/TypeBinding.java
@@ -0,0 +1,46 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent.binding;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+/**
+ * Binding between Java Type and QMF type
+ */
+public interface TypeBinding
+{
+ public Object decode(Decoder dec);
+
+ public void encode(Encoder enc, Object value);
+
+ public Class<?> getJavaClass();
+
+ public short getCode();
+
+ public boolean isNative();
+
+ public String getRefClass();
+
+ public String getRefPackage();
+
+ public boolean optionalDefault();
+}
diff --git a/java/management/agent/src/test/java/org/apache/qpid/agent/Crumpet.java b/java/management/agent/src/test/java/org/apache/qpid/agent/Crumpet.java
new file mode 100644
index 0000000000..67095c809b
--- /dev/null
+++ b/java/management/agent/src/test/java/org/apache/qpid/agent/Crumpet.java
@@ -0,0 +1,70 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent;
+
+import java.util.ArrayList;
+
+import org.apache.qpid.agent.annotations.QMFSeeAlso;
+import org.apache.qpid.agent.annotations.QMFType;
+
+/**
+ * Crumpet
+ *
+ */
+@QMFType(className = "Crumpet", packageName = "org.apache.test")
+@QMFSeeAlso(
+{ Pikelet.class })
+public class Crumpet
+{
+ private String foo = "fooValue";
+ private String bar = "barValue";
+ private ArrayList<String> ingredients = new ArrayList<String>();
+
+ public String getFoo()
+ {
+ return foo;
+ }
+
+ public void setFoo(String foo)
+ {
+ this.foo = foo;
+ }
+
+ public String getBar()
+ {
+ return bar;
+ }
+
+ public void setBar(String bar)
+ {
+ this.bar = bar;
+ }
+
+ public ArrayList<String> getIngredients()
+ {
+ return ingredients;
+ }
+
+ public void setIngredients(ArrayList<String> ingredients)
+ {
+ this.ingredients = ingredients;
+ }
+}
diff --git a/java/management/agent/src/test/java/org/apache/qpid/agent/Muppet.java b/java/management/agent/src/test/java/org/apache/qpid/agent/Muppet.java
new file mode 100644
index 0000000000..f039ab9baa
--- /dev/null
+++ b/java/management/agent/src/test/java/org/apache/qpid/agent/Muppet.java
@@ -0,0 +1,113 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.qpid.agent.annotations.QMFObject;
+
+@QMFObject(className = "Muppet", packageName = "org.apache.test")
+public class Muppet extends Puppet
+{
+ private Log log = LogFactory.getLog(Muppet.class);
+
+ public String getSomething()
+ {
+ return "something";
+ }
+
+ public void doSomething(String str)
+ {
+ log.debug(String.format("doSomething: %s", str));
+ }
+
+ public String returnSomething()
+ {
+ log.debug("returning something");
+ return "asdf";
+ }
+
+ public Crumpet gimmieCrumpet(String asdf, int n, float f, Map foo)
+ {
+ log.debug(String
+ .format("mmm, crumpet: %s, %s, %s, %s", asdf, n, f, foo));
+ Crumpet crumpet = new Crumpet();
+ crumpet.getIngredients().add("Butter");
+ crumpet.getIngredients().add("Salt");
+ crumpet.getIngredients().add("Flour");
+ return crumpet;
+ }
+
+ public Crumpet gimmieCrumpet2()
+ {
+ Pikelet pik = new Pikelet();
+ pik.getIngredients().add("Butter");
+ pik.getIngredients().add("Salt");
+ pik.getIngredients().add("Eggs");
+ pik.getCrumpets().put("Crumpet1",
+ this.gimmieCrumpet("2121", 1, 1, null));
+ return pik;
+ }
+
+ public List gimmeLotsOfCrumpets()
+ {
+ log.debug("Asking for lots of Crumpets");
+ ArrayList<Crumpet> returnValue = new ArrayList<Crumpet>();
+ Crumpet crumpet = new Crumpet();
+ crumpet.getIngredients().add("Chocolate");
+ returnValue.add(crumpet);
+ crumpet = new Crumpet();
+ crumpet.getIngredients().add("Pecans");
+ returnValue.add(crumpet);
+ crumpet = new Pikelet();
+ crumpet.getIngredients().add("Poached Eggs");
+ returnValue.add(crumpet);
+ return returnValue;
+ }
+
+ public int divideByZero()
+ {
+ return 1 / 0;
+ }
+
+ public Crumpet takeCrumpet(Crumpet newCrumpet)
+ {
+ log.debug(String.format("I gots me a crumpet: foo: '%s' bar: '%s'",
+ newCrumpet.getFoo(), newCrumpet.getBar()));
+ log.debug("My crumpet's class is " + newCrumpet.getClass().getName());
+ for (String ingredient : newCrumpet.getIngredients())
+ {
+ log.debug("My crumpet is made of " + ingredient);
+ }
+ return newCrumpet;
+ }
+
+ public Object takeSomething(Object obj)
+ {
+ log.debug(String.format("I gots me a something: '%s'", obj.getClass()
+ .getName()));
+ return obj;
+ }
+}
diff --git a/java/management/agent/src/test/java/org/apache/qpid/agent/Pikelet.java b/java/management/agent/src/test/java/org/apache/qpid/agent/Pikelet.java
new file mode 100644
index 0000000000..f820fa6258
--- /dev/null
+++ b/java/management/agent/src/test/java/org/apache/qpid/agent/Pikelet.java
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent;
+
+import java.util.HashMap;
+
+import org.apache.qpid.agent.annotations.QMFType;
+
+@QMFType(className = "Pikelet", packageName = "org.apache.test")
+public class Pikelet extends Crumpet
+{
+ protected String shape;
+ HashMap<String, Crumpet> crumpets = new HashMap<String, Crumpet>();
+
+ public String getShape()
+ {
+ return shape;
+ }
+
+ public void setShape(String shape)
+ {
+ this.shape = shape;
+ }
+
+ public HashMap<String, Crumpet> getCrumpets()
+ {
+ return crumpets;
+ }
+
+ public void setCrumpets(HashMap<String, Crumpet> crumpets)
+ {
+ this.crumpets = crumpets;
+ }
+}
diff --git a/java/management/agent/src/test/java/org/apache/qpid/agent/Puppet.java b/java/management/agent/src/test/java/org/apache/qpid/agent/Puppet.java
new file mode 100644
index 0000000000..bfd34840f8
--- /dev/null
+++ b/java/management/agent/src/test/java/org/apache/qpid/agent/Puppet.java
@@ -0,0 +1,29 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.agent;
+
+public class Puppet
+{
+ public int countStrings()
+ {
+ return 4;
+ }
+}
diff --git a/java/management/client/README b/java/management/client/README
new file mode 100644
index 0000000000..34a48f1f50
--- /dev/null
+++ b/java/management/client/README
@@ -0,0 +1,42 @@
+QMan - Qpid JMX & WS-DM Management Bridge
+---------------------------------------------------------
+
+Documentation
+--------------
+All of our user documentation for QMan module can be accessed on our wiki at:
+
+http://cwiki.apache.org/qpid/qman-qpid-management-bridge.html
+
+This includes a Getting Started and User Guide as well as detailed developer documentation.
+However, here's a VERY quick guide to running QMan, once you have installed it somewhere !
+
+Running
+------------------
+
+Once you installed QMan, under the root folder you should have the following structure
+
+- bin (folder) : contains startup & shutdown scripts;
+- app (folder) : contains the web application module;
+- etc (folder) : contains configuration files;
+- examples (folder) : contains examples (and a nested README as well)
+- lib (folder) : contains dependency libraries;
+- log (folder) : this is the default log folder.
+
+To run QMan,
+
+1) edit the $QMAN_HOME/etc/qman-config.xml file and configure broker connection data (host,port, username, etc...)
+2) under the $QMAN_HOME/bin directory run :
+
+> ./qman-wsdm-start.sh
+
+now, under $QMAN_HOME/log directory you should see two files :
+
+1) server.log : contains web server log messages;
+2) qman.log : contains qman log messages;
+
+Administration
+-----------------------
+
+After QMan has been started successfully you can browse its administration console pointing your browser to :
+
+http://<host>:<port>/qman/admin.jsp \ No newline at end of file
diff --git a/java/management/client/bin/qman-jmx.cmd b/java/management/client/bin/qman-jmx.cmd
new file mode 100644
index 0000000000..c04241494d
--- /dev/null
+++ b/java/management/client/bin/qman-jmx.cmd
@@ -0,0 +1,78 @@
+@echo off
+
+@rem Licensed to the Apache Software Foundation (ASF) under one
+@rem or more contributor license agreements. See the NOTICE file
+@rem distributed with this work for additional information
+@rem regarding copyright ownership. The ASF licenses this file
+@rem to you under the Apache License, Version 2.0 (the
+@rem "License"); you may not use this file except in compliance
+@rem with the License. You may obtain a copy of the License at
+@rem
+@rem http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing,
+@rem software distributed under the License is distributed on an
+@rem "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@rem KIND, either express or implied. See the License for the
+@rem specific language governing permissions and limitations
+@rem under the License.
+
+@rem *************************************************************************
+@rem This script is used to initialize environment to start QMan JMX Adapter.
+@rem It uses several environment variables described below.
+@rem You can edit this file according to your environment or (reccommended) set their
+@rem values outside this script.
+@rem
+@rem It sets (or retrieve from the environment if defined) the following variables:
+@rem
+@rem QMAN_HOME - The home directory of your QMan installation.
+@rem JAVA_HOME - Location of the version of Java runtime used to start QMan.
+@rem QMAN_CONFIG_FILE - Location of the QMan configuration file.
+@rem **************************************************************************
+
+cls
+
+:CHECK JVM
+set JAVA=%JAVA_HOME%\bin\java
+set JAVA_OPTS=-Xms128m -Xmx512m
+
+if not "%JAVA_HOME%" == "" goto CONFIGURE AND START
+
+set JAVA=java
+
+echo.
+echo WARNING : JAVA_HOME is not set so unexpected results may occur.
+echo Please set JAVA_HOME to the directory of your local JDK / JRE to avoid this message.
+
+:CONFIGURE AND START
+
+if "%QMAN_HOME%" == "" SET QMAN_HOME=..
+if "%QMAN_CONFIG_FILE%" == "" SET QMAN_CONFIG_FILE=%QMAN_HOME%\etc\qman-config.xml
+
+SET QMAN_LIBS=%QMAN_HOME%\lib
+SET QMAN_CLASSPATH=%QMAN_HOME%\etc
+
+setlocal ENABLEDELAYEDEXPANSION
+
+FOR /R %QMAN_LIBS% %%G IN (*.jar) DO set QMAN_CLASSPATH=!QMAN_CLASSPATH!;%%G
+
+:START
+echo ===============================================================================
+echo.
+echo QMan JMX Bridge Bootstrap Environment
+echo --------------------------------------------------
+echo.
+echo QMan HOME : %QMAN_HOME%
+echo.
+echo Java executable : %JAVA%
+echo.
+echo Java Opts : %JAVA_OPTS%
+echo.
+echo Configuration file : %QMAN_CONFIG_FILE%
+echo.
+echo Bootstrap classpath : %QMAN_CLASSPATH%
+echo.
+echo ===============================================================================
+echo.
+
+"%JAVA%" %JAVA_OPTS% -Dcom.sun.management.jmxremote -Dqman-config=%QMAN_CONFIG_FILE% -classpath "%QMAN_CLASSPATH%" org.apache.qpid.management.domain.services.QMan \ No newline at end of file
diff --git a/java/management/client/bin/qman-jmx.sh b/java/management/client/bin/qman-jmx.sh
new file mode 100644
index 0000000000..1003117128
--- /dev/null
+++ b/java/management/client/bin/qman-jmx.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# *************************************************************************
+# This script is used to initialize environment to start QMan JMX Adapter.
+# It uses several environment variables described below.
+# You can edit this file according to your environment or (reccommended) set their
+# values outside this script.
+#
+# It sets (or retrieve from the environment if defined) the following variables:
+#
+# QMAN_HOME - The home directory of your QMan installation.
+# JAVA_HOME - Location of the version of Java runtime used to start QMan.
+# QMAN_CONFIG_FILE - Location of the QMan configuration file.
+# **************************************************************************
+
+clear
+
+JAVA=$JAVA_HOME/bin/java
+JAVA_OPTS="-Xms128m -Xmx512m"
+
+if [ "$JAVA_HOME" = "" ] ; then
+ echo "JAVA_HOME is not set. Unexpected results may occur."
+ echo "Set JAVA_HOME to the directory of your local JDK to avoid this message."
+ JAVA=java
+fi
+
+if [ "$QMAN_HOME" = "" ] ; then
+ QMAN_HOME=..
+fi
+
+if [ "$QMAN_CONFIG_FILE" = "" ] ; then
+ QMAN_CONFIG_FILE=$QMAN_HOME/etc/qman-config.xml
+fi
+
+if [ "$QMAN_LIBS" = "" ] ; then
+ QMAN_LIBS=$QMAN_HOME/lib
+fi
+QMAN_CLASSPATH=`find $QMAN_LIBS | tr '\n' ":"`
+QMAN_CLASSPATH=$QMAN_HOME/etc:$QMAN_CLASSPATH
+
+echo "==============================================================================="
+echo ""
+echo "QMan JMX Bridge Bootstrap Environment"
+echo "--------------------------------------------------"
+echo ""
+echo "QMan HOME : $QMAN_HOME"
+echo ""
+echo "Java executable : $JAVA"
+echo ""
+echo "Java Opts : $JAVA_OPTS"
+echo ""
+echo "Configuration file : $QMAN_CONFIG_FILE"
+echo ""
+echo "Bootstrap classpath : $QMAN_CLASSPATH"
+echo ""
+echo "==============================================================================="
+echo ""
+
+"$JAVA" $JAVA_OPTS -cp $QMAN_CLASSPATH -Dcom.sun.management.jmxremote -Dqman-config=$QMAN_CONFIG_FILE org.apache.qpid.management.domain.services.QMan
diff --git a/java/management/client/bin/qman-wsdm-start.cmd b/java/management/client/bin/qman-wsdm-start.cmd
new file mode 100644
index 0000000000..df30ce8617
--- /dev/null
+++ b/java/management/client/bin/qman-wsdm-start.cmd
@@ -0,0 +1,88 @@
+@echo off
+
+@rem Licensed to the Apache Software Foundation (ASF) under one
+@rem or more contributor license agreements. See the NOTICE file
+@rem distributed with this work for additional information
+@rem regarding copyright ownership. The ASF licenses this file
+@rem to you under the Apache License, Version 2.0 (the
+@rem "License"); you may not use this file except in compliance
+@rem with the License. You may obtain a copy of the License at
+@rem
+@rem http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing,
+@rem software distributed under the License is distributed on an
+@rem "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@rem KIND, either express or implied. See the License for the
+@rem specific language governing permissions and limitations
+@rem under the License.
+
+@rem *************************************************************************
+@rem This script is used to initialize environment to start QMan WS-DM Adapter.
+@rem It uses several environment variables described below.
+@rem You can edit this file according to your environment or (reccommended) set their
+@rem values outside this script.
+@rem
+@rem It sets (or retrieve from the environment if defined) the following variables:
+@rem
+@rem QMAN_HOME - The home directory of your QMan installation.
+@rem JAVA_HOME - Location of the version of Java runtime used to start QMan.
+@rem QMAN_WSDM_ADAPTER_PORT - The TCP port that QMan will use to listen for incoming connections.
+@rem QMAN_WSDM_ADAPTER_HOST - The IP address or DNS name QMan will use to listen for incoming connections
+@rem QMAN_CONFIG_FILE - Location of the QMan configuration file.
+@rem **************************************************************************
+
+set JAVA=%JAVA_HOME%\bin\java
+set JAVA_OPTS=-Xms128m -Xmx512m
+SET CLASSPATH=
+
+if not "%JAVA_HOME%" == "" goto CONFIGURE AND START
+set JAVA=java
+
+echo JAVA_HOME is not set. Unexpected results may occur.
+echo Set JAVA_HOME to the directory of your local JDK to avoid this message.
+
+:CONFIGURE AND START
+
+if "%QMAN_HOME%" == "" SET QMAN_HOME=..
+if "%QMAN_WSDM_ADAPTER_PORT%" == "" SET QMAN_WSDM_ADAPTER_PORT=8080
+if "%QMAN_WSDM_ADAPTER_HOST%" == "" SET QMAN_WSDM_ADAPTER_HOST=%COMPUTERNAME%
+if "%QMAN_CONFIG_FILE%" == "" SET QMAN_CONFIG_FILE=%QMAN_HOME%\etc\qman-config.xml
+
+SET ADMIN_PORT=8079
+SET ADMIN_KEY=gazzax
+SET QMAN_LIBS=%QMAN_HOME%\lib
+SET JETTY_CONFIG_FILE=%QMAN_HOME%\etc\jetty.xml
+
+SET CLASSPATH=%QMAN_HOME%\etc
+SET CLASSPATH=%CLASSPATH%;%QMAN_LIBS%\start.jar
+SET CLASSPATH=%CLASSPATH%;%QMAN_LIBS%\jetty-6.1.14.jar
+SET CLASSPATH=%CLASSPATH%;%QMAN_LIBS%\jetty-util-6.1.14.jar
+SET CLASSPATH=%CLASSPATH%;%QMAN_LIBS%\geronimo-servlet_2.5_spec-1.2.jar
+SET CLASSPATH=%CLASSPATH%;%QMAN_LIBS%\slf4j-api-1.4.0.jar
+SET CLASSPATH=%CLASSPATH%;%QMAN_LIBS%\slf4j-log4j12-1.4.0.jar
+SET CLASSPATH=%CLASSPATH%;%QMAN_LIBS%\log4j-1.2.12.jar
+
+echo ===============================================================================
+echo.
+echo QMan WS-DM Bridge Bootstrap Environment
+echo ------------------------------------------------------
+echo.
+echo QMan HOME: %QMAN_HOME%
+echo.
+echo Java executable : %JAVA%
+echo.
+echo QMan configuration file : %QMAN_CONFIG_FILE%
+echo.
+echo Web Server configuration file : %JETTY_CONFIG_FILE%
+echo.
+echo Web Server HTTP port : %QMAN_WSDM_ADAPTER_PORT%
+echo.
+echo Web Server Admin port : %ADMIN_PORT%
+echo.
+echo Bootstrap classpath : %CLASSPATH%
+echo.
+echo ===============================================================================
+echo.
+
+%JAVA% -cp %CLASSPATH% -DQMAN_HOME=%QMAN_HOME% -Djetty.home=%QMAN_HOME% -Dqman.host=%QMAN_WSDM_ADAPTER_HOST% -Dqman.port=%QMAN_WSDM_ADAPTER_PORT% -DSTOP.PORT=%ADMIN_PORT% -DSTOP.KEY=%ADMIN_KEY% -Dqman-config=%QMAN_CONFIG_FILE% org.mortbay.start.Main %JETTY_CONFIG_FILE% \ No newline at end of file
diff --git a/java/management/client/bin/qman-wsdm-start.sh b/java/management/client/bin/qman-wsdm-start.sh
new file mode 100644
index 0000000000..39a4cba66e
--- /dev/null
+++ b/java/management/client/bin/qman-wsdm-start.sh
@@ -0,0 +1,89 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# *************************************************************************
+# This script is used to initialize environment to start QMan WS-DM Adapter.
+# It uses several environment variables described below.
+# You can edit this file according to your environment or (reccommended) set their
+# values outside this script.
+#
+# It sets (or retrieve from the environment if defined) the following variables:
+#
+# QMAN_HOME - The home directory of your QMan installation.
+# JAVA_HOME - Location of the version of Java runtime used to start QMan.
+# QMAN_WSDM_ADAPTER_PORT - The TCP port that QMan will use to listen for incoming connections.
+# QMAN_WSDM_ADAPTER_HOST - The IP address or DNS name QMan will use to listen for incoming connections
+# QMAN_CONFIG_FILE - Location of the QMan configuration file.
+# **************************************************************************
+
+JAVA=$JAVA_HOME/bin/java
+JAVA_OPTS="-Xms128m -Xmx512m"
+
+if [ "$JAVA_HOME" = "" ] ; then
+ echo "JAVA_HOME is not set. Unexpected results may occur."
+ echo "Set JAVA_HOME to the directory of your local JDK to avoid this message."
+ JAVA=java
+fi
+if [ "$QMAN_HOME" = "" ] ; then
+ QMAN_HOME=..
+fi
+if [ "$QMAN_WSDM_ADAPTER_PORT" = "" ] ; then
+ QMAN_WSDM_ADAPTER_PORT=8080
+fi
+if [ "$QMAN_WSDM_ADAPTER_HOST" = "" ] ; then
+ QMAN_WSDM_ADAPTER_HOST=$HOSTNAME
+fi
+if [ "$QMAN_CONFIG_FILE" = "" ] ; then
+ QMAN_CONFIG_FILE=$QMAN_HOME/etc/qman-config.xml
+fi
+
+ADMIN_PORT=8079
+ADMIN_KEY=gazzax
+QMAN_LIBS=$QMAN_HOME/lib
+JETTY_CONFIG_FILE=$QMAN_HOME/etc/jetty.xml
+
+QMAN_CLASSPATH=$QMAN_HOME/etc:$QMAN_LIBS/start.jar:$QMAN_LIBS/jetty-6.1.14.jar:$QMAN_LIBS/jetty-util-6.1.14.jar:$QMAN_LIBS/geronimo-servlet_2.5_spec-1.2.jar:$QMAN_LIBS/slf4j-api-1.4.0.jar:$QMAN_LIBS/slf4j-log4j12-1.4.0.jar:$QMAN_LIBS/log4j-1.2.12.jar
+
+echo "==============================================================================="
+echo""
+echo "QMan WS-DM Bridge Bootstrap Environment"
+echo "------------------------------------------------------"
+echo""
+echo "QMan HOME: $QMAN_HOME"
+echo""
+echo "Java executable : $JAVA"
+echo""
+echo "Java Opts : $JAVA_OPTS"
+echo""
+echo "Configuration file : $QMAN_CONFIG_FILE"
+echo""
+echo "Web Server Configuration File : $JETTY_CONFIG_FILE"
+echo""
+echo "Web Server HTTP port : $QMAN_WSDM_ADAPTER_PORT"
+echo""
+echo "Web Server HTTP host : $QMAN_WSDM_ADAPTER_HOST"
+echo""
+echo "Web Server Admin port : $ADMIN_PORT"
+echo""
+echo "Bootstrap classpath : $QMAN_CLASSPATH"
+echo""
+echo "==============================================================================="
+echo""
+
+"$JAVA" $JAVA_OPTS -cp $QMAN_CLASSPATH -DQMAN_HOME=$QMAN_HOME -Djetty.home=$QMAN_HOME -Dqman.host=$QMAN_WSDM_ADAPTER_HOST -Dqman.port=$QMAN_WSDM_ADAPTER_PORT -DSTOP.PORT=$ADMIN_PORT -DSTOP.KEY=$ADMIN_KEY -Dqman-config=$QMAN_CONFIG_FILE org.mortbay.start.Main $JETTY_CONFIG_FILE \ No newline at end of file
diff --git a/java/management/client/bin/qman-wsdm-stop.cmd b/java/management/client/bin/qman-wsdm-stop.cmd
new file mode 100644
index 0000000000..6449c70227
--- /dev/null
+++ b/java/management/client/bin/qman-wsdm-stop.cmd
@@ -0,0 +1,37 @@
+@echo off
+
+rem Licensed to the Apache Software Foundation (ASF) under one
+rem or more contributor license agreements. See the NOTICE file
+rem distributed with this work for additional information
+rem regarding copyright ownership. The ASF licenses this file
+rem to you under the Apache License, Version 2.0 (the
+rem "License"); you may not use this file except in compliance
+rem with the License. You may obtain a copy of the License at
+rem
+rem http://www.apache.org/licenses/LICENSE-2.0
+rem
+rem Unless required by applicable law or agreed to in writing,
+rem software distributed under the License is distributed on an
+rem "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+rem KIND, either express or implied. See the License for the
+rem specific language governing permissions and limitations
+rem under the License.
+
+set JAVA=%JAVA_HOME%\bin\java
+
+if not "%JAVA_HOME%" == "" goto CONFIGURE AND START
+
+set JAVA=java
+
+echo JAVA_HOME is not set. Unexpected results may occur.
+echo Set JAVA_HOME to the directory of your local JDK to avoid this message.
+
+:CONFIGURE AND START
+
+if "%QMAN_HOME%" == "" SET QMAN_HOME=..
+SET ADMIN_PORT=8079
+SET ADMIN_KEY=gazzax
+
+"%JAVA%" -DSTOP.PORT=%ADMIN_PORT% -DSTOP.KEY=%ADMIN_KEY% -jar %QMAN_HOME%\lib\start.jar --stop
+
+echo QMan WS-DM Adapter shut down successfully. \ No newline at end of file
diff --git a/java/management/client/bin/qman-wsdm-stop.sh b/java/management/client/bin/qman-wsdm-stop.sh
new file mode 100644
index 0000000000..0de9a995ef
--- /dev/null
+++ b/java/management/client/bin/qman-wsdm-stop.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+JAVA=$JAVA_HOME/bin/java
+
+if [ "$JAVA_HOME" = "" ] ; then
+ echo "JAVA_HOME is not set. Unexpected results may occur."
+ echo "Set JAVA_HOME to the directory of your local JDK to avoid this message."
+ JAVA=java
+fi
+
+if [ "$QMAN_HOME" = "" ] ; then
+ QMAN_HOME=..
+fi
+
+ADMIN_PORT=8079
+ADMIN_KEY=gazzax
+
+"$JAVA" -DSTOP.PORT=$ADMIN_PORT -DSTOP.KEY=$ADMIN_KEY -jar $QMAN_HOME/lib/start.jar --stop
+
+echo "QMan WS-DM Adapter shut down successfully." \ No newline at end of file
diff --git a/java/management/client/build.xml b/java/management/client/build.xml
new file mode 100644
index 0000000000..f7fa5449ff
--- /dev/null
+++ b/java/management/client/build.xml
@@ -0,0 +1,213 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<project name="QMan - Qpid JMX / WS-DM Adapter" default="build">
+
+ <property name="module.depends" value="client common"/>
+ <property name="module.test.depends" value="client common"/>
+
+ <import file="../../module.xml"/>
+
+ <property name="build.root" value="${module.build}"/>
+ <property name="web.module" value="${module.build}${file.separator}wsdm-module"/>
+ <property name="web-inf.folder" value="${web.module}${file.separator}WEB-INF"/>
+ <property name="classes.folder" value="${web-inf.folder}${file.separator}classes"/>
+ <property name="examples.folder" value="${module.build}${file.separator}examples"/>
+
+ <target name="release-bin-other">
+ <mkdir dir="${module.release}${file.separator}log"/>
+ <mkdir dir="${module.release}${file.separator}examples"/>
+ <mkdir dir="${module.release}${file.separator}examples${file.separator}sample_messages"/>
+
+ </target>
+
+ <target name="release-bin" depends="release-bin-tasks"/>
+
+ <target name="resources-release" description="copy resources into module release">
+ <copy todir="${module.release}" failonerror="false" flatten="true">
+ <fileset dir="${resources}" excludes="META-INF">
+ <exclude name="META-INF"/>
+ <exclude name="README"/>
+ </fileset>
+ <fileset file="${module.build}${file.separator}README"/>
+ </copy>
+ </target>
+
+ <target name="libs-release" description="copy dependencies into module release">
+ <copy todir="${module.release}${file.separator}" failonerror="true" verbose="true">
+ <fileset dir="${build}" casesensitive="yes" includes="${module.libs}">
+ <not><filename name="**/*javassist*"/></not>
+ <not><filename name="**/*xml-api*"/></not>
+ <not><filename name="**/*xerces*"/></not>
+ <not><filename name="**/*xalan*"/></not>
+ <not><filename name="**/*wsdl*"/></not>
+ <not><filename name="**/*muse*"/></not>
+ <not><filename name="**/*jsp*"/></not>
+ <not><filename name="**/*core-3.1.1.jar*"/></not>
+ </fileset>
+ </copy>
+ <copy todir="${module.release}${file.separator}lib" failonerror="true">
+ <fileset file="${module.jar}"/>
+ <fileset dir="${build.lib}" includes="${module.depends.jars}"/>
+ </copy>
+ <mkdir dir="${module.release}${file.separator}app${file.separator}qman"/>
+ <copy todir="${module.release}${file.separator}app${file.separator}qman" failonerror="true">
+ <fileset dir="${web.module}" includes="*/**"/>
+ </copy>
+ <mkdir dir="${module.release}${file.separator}examples"/>
+ <copy todir="${module.release}${file.separator}examples">
+ <fileset dir="${examples.folder}"/>
+ </copy>
+ </target>
+
+ <target name="prepare-wsdm-module">
+ <mkdir dir="${web.module}"/>
+ <mkdir dir="${web-inf.folder}"/>
+ <mkdir dir="${classes.folder}"/>
+ <copy file=".${file.separator}web.xml" todir="${web-inf.folder}" verbose="false"/>
+ <copy todir="${classes.folder}" verbose="false">
+ <fileset dir="${module.classes}">
+ <include name="wsdl/**"/>
+ <include name="muse.xml"/>
+ <include name="router-entries/**"/>
+ </fileset>
+ </copy>
+ <copy todir="${web-inf.folder}">
+ <fileset dir="${build}" includes="${module.libs}">
+ <exclude name="lib/jetty*.jar"/>
+ <exclude name="lib/start*.jar"/>
+ </fileset>
+ </copy>
+ <copy todir="${web-inf.folder}${file.separator}lib">
+ <fileset dir="${build}/lib">
+ <include name="qpid-client-*.jar"/>
+ <include name="qpid-common-*.jar"/>
+ <include name="qpid-management-client-*.jar"/>
+ <exclude name="qpid-client-example*.jar"/>
+ <exclude name="qpid-client-tests*.jar"/>
+ <exclude name="qpid-common-tests*.jar"/>
+ <exclude name="qpid-management-client-tests*.jar"/>
+ </fileset>
+ </copy>
+ <copy todir="${web.module}">
+ <fileset dir="${module.src}${file.separator}..${file.separator}..${file.separator}..${file.separator}console">
+ <include name="*/**"/>
+ </fileset>
+ </copy>
+ </target>
+ <target name="jar.manifest" depends="compile" if="module.manifest">
+ <jar destfile="${module.jar}" manifest="${module.manifest}">
+ <fileset dir="${module.classes}" casesensitive="yes">
+ <include name="**/**"/>
+ <exclude name="wsdl/**"/>
+ <exclude name="muse.xml"/>
+ <exclude name="router-entries/**"/>
+ </fileset>
+ </jar>
+ </target>
+ <target name="jar.nomanifest" depends="compile" unless="module.manifest">
+ <jar destfile="${module.jar}">
+ <metainf dir="${project.root}${file.separator}resources/" />
+ <fileset dir="${module.classes}" casesensitive="yes">
+ <include name="**/**"/>
+ <exclude name="wsdl/**"/>
+ <exclude name="muse.xml"/>
+ <exclude name="router-entries/**"/>
+ </fileset>
+ </jar>
+ </target>
+ <target name="postbuild" depends="prepare-wsdm-module,copy-examples-to-build,copy-README-to-build" description="Build WS-DM module"/>
+
+ <path id="module.test.path">
+ <pathelement path="${module.test.classes}" />
+ <path refid="module.test.libs"/>
+ <fileset dir="${build}/lib">
+ <include name="qpid-client-*.jar"/>
+ <include name="qpid-common-*.jar"/>
+ <include name="qpid-management-client-*.jar"/>
+ <exclude name="qpid-client-example*.jar"/>
+ <exclude name="qpid-client-tests*.jar"/>
+ <exclude name="qpid-common-tests*.jar"/>
+ <exclude name="qpid-management-client-tests*.jar"/>
+ </fileset>
+ </path>
+
+ <target name="copy-README-to-build">
+ <copy todir="${module.build}">
+ <fileset dir="${module.src}${file.separator}..${file.separator}..${file.separator}..">
+ <include name="README"/>
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="copy-examples-to-build">
+ <mkdir dir="${examples.folder}${file.separator}src"/>
+ <mkdir dir="${examples.folder}${file.separator}sample_messages"/>
+ <copy todir="${examples.folder}">
+ <fileset dir="${module.src}${file.separator}..${file.separator}..${file.separator}example">
+ <include name="README"/>
+ </fileset>
+ </copy>
+ <copy todir="${examples.folder}${file.separator}src">
+ <fileset dir="${module.src}${file.separator}..${file.separator}..${file.separator}example">
+ <include name="**/*.java"/>
+ <exclude name="**/*.out.*"/>
+ </fileset>
+ </copy>
+ <copy todir="${examples.folder}${file.separator}sample_messages">
+ <fileset dir="${module.src}${file.separator}..${file.separator}..${file.separator}example" >
+ <exclude name="**/*.java"/>
+ <exclude name="**/README"/>
+ <include name="**/*.out.*"/>
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="test" depends="build,compile-tests" if="module.test.src.exists" unless="${dontruntest}" description="execute unit tests">
+ <delete file="${module.failed}"/>
+ <echo message="Using profile:${profile}" level="info"/>
+ <junit fork="${test.fork}" maxmemory="1024M" reloading="no"
+ haltonfailure="${haltonfailure}" haltonerror="${haltonerror}"
+ failureproperty="test.failures" printsummary="on" timeout="600000" >
+
+ <jvmarg value="${jvm.args}"/>
+ <sysproperty key="qman.war" value="${web.module}"/>
+
+ <formatter type="plain"/>
+ <formatter type="xml"/>
+
+ <classpath refid="module.test.path"/>
+
+ <batchtest fork="${test.fork}" todir="${module.results}">
+ <fileset dir="${module.test.src}" excludes="${module.test.excludes}">
+ <include name="**/${test}.java"/>
+ </fileset>
+ </batchtest>
+ </junit>
+ <antcall target="touch-failed"/>
+ <condition property="failed">
+ <and>
+ <isfalse value="${test.failures.ignore}"/>
+ <available file="${module.failed}"/>
+ </and>
+ </condition>
+ <fail if="failed" message="TEST SUITE FAILED"/>
+ </target>
+</project>
diff --git a/java/management/client/console/brokers_management.jsp b/java/management/client/console/brokers_management.jsp
new file mode 100644
index 0000000000..449eabfcc1
--- /dev/null
+++ b/java/management/client/console/brokers_management.jsp
@@ -0,0 +1,188 @@
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+<%@ taglib uri='http://java.sun.com/jsp/jstl/core' prefix='c'%>
+<%@page import="org.apache.qpid.management.web.action.BrokerModel"%>
+<%@page import="java.util.Set"%>
+<%@page import="javax.management.ObjectName"%>
+<%@page import="org.apache.qpid.management.Names"%>
+<%@page import="java.util.List"%>
+<%@page import="java.util.*"%>
+<%@page import="java.net.URI"%>
+<%@page import="javax.xml.namespace.QName"%>
+<%@page import="org.w3c.dom.Element"%>
+<html>
+ <head>
+ <link rel="stylesheet" href="<%=request.getContextPath()%>/images/style.css" type="text/css" />
+ <title>QMan Administration Console</title>
+ </head>
+ <body>
+ <div id="page" align="center">
+ <jsp:include page="/fragments/header.jsp">
+ <jsp:param name="title" value="Brokers Management"/>
+ </jsp:include>
+
+ <div id="content" align="center">
+ <jsp:include page="/fragments/menu.jsp"/>
+
+ <div id="contenttext">
+ <div class="panel" align="justify">
+ <span class="bodytext">
+ <table width="100%">
+ <tr>
+ <td valign="top">
+ <fieldset>
+ <legend>Connected Brokers</legend>
+ <table width="100%" cellspacing="1">
+ <tr>
+ <th nowrap="nowrap" align="center">Host</th>
+ <th nowrap="nowrap" align="center" >Port</th>
+ <th nowrap="nowrap" align="center">Virtual Host</th>
+ <th nowrap="nowrap" align="center">Username</th>
+ <th nowrap="nowrap" align="center">Initial Pool Capacity</th>
+ <th nowrap="nowrap" align="center">Max Pool Capacity</th>
+ <th nowrap="nowrap" align="center">Max Wait Timeout</th>
+ </tr>
+ <c:forEach var="broker" items="${model}" varStatus="rowCounter">
+ <c:choose>
+ <c:when test="${rowCounter.count % 2 == 0}">
+ <c:set var="bgcolor" scope="page" value="EAEAEA"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="bgcolor" scope="page" value="FFFFFF"/>
+ </c:otherwise>
+ </c:choose>
+ <tr>
+ <td nowrap style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}"><c:out value="${broker.host}"/></td>
+ <td nowrap style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}"><c:out value="${broker.port}"/></td>
+ <td style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}"><c:out value="${broker.virtualHost}"/></td>
+ <td style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}"><c:out value="${broker.username}"/></td>
+ <td style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}"><c:out value="${broker.initialPoolCapacity}"/></td>
+ <td style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}"><c:out value="${broker.maxPoolCapacity}"/></td>
+ <td style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}"><c:out value="${broker.maxWaitTimeout}"/></td>
+ </tr>
+ </c:forEach>
+ </table>
+ </fieldset>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <form name="form" action="<%=request.getContextPath()%>/brokers_management" method="post">
+ <fieldset>
+ <legend>New Broker Connection Data</legend>
+ <table>
+ <tr>
+ <td>
+ Host :
+ </td>
+ <td>
+ <input type="text" name="host"/>
+ </td>
+ <td style="font-size: x-small;">
+ The hostname where the broker is running.
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Port :
+ </td>
+ <td>
+ <input type="text" name="port"/>
+ </td>
+ <td style="font-size: x-small;">
+ The port number where the broker is running.
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Virtual Host :
+ </td>
+ <td>
+ <input type="text" name="virtualHost"/>
+ </td>
+ <td style="font-size: x-small;">
+ The virtual host name.
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Username :
+ </td>
+ <td>
+ <input type="text" name="username"/>
+ </td>
+ <td style="font-size: x-small;">
+ The username used for estabilish connection with broker.
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Password :
+ </td>
+ <td>
+ <input type="text" name="password"/>
+ </td>
+ <td style="font-size: x-small;">
+ The password used for estabilish connection with broker.
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Initial Pool Capacity :
+ </td>
+ <td>
+ <input type="text" name="initialCapacity"/>
+ </td>
+ <td style="font-size: x-small;">
+ The number of connections that must be immediately opened.
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Max Pool Capacity :
+ </td>
+ <td>
+ <input type="text" name="maxCapacity"/>
+ </td>
+ <td style="font-size: x-small;">
+ The maximum number of open connections.
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Max Wait Timeout :
+ </td>
+ <td>
+ <input type="text" name="maxWaitTimeout"/>
+ </td>
+ <td style="font-size: x-small;">
+ The maximum amount of time that a client will wait for obtaining a connection.
+ </td>
+ </tr>
+ <tr>
+ <td colspan="3" align="center">
+ <input type="submit" value="Connect"/>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+ </td>
+ </form>
+ </tr>
+ <tr>
+ <td nowrap style="font-size: x-small; font-weight: bold; color=red;">
+ <ul>
+ <c:forEach var="errorMessage" items="${errors}">
+ <li><span style="font-size: medium; font-weight: bold; color:red;">${errorMessage}</span></li>
+ </c:forEach>
+ </ul>
+ </td>
+ </tr>
+
+ </table>
+ </span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/java/management/client/console/console.jsp b/java/management/client/console/console.jsp
new file mode 100644
index 0000000000..cdb53fede9
--- /dev/null
+++ b/java/management/client/console/console.jsp
@@ -0,0 +1,101 @@
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+<%@ taglib uri='http://java.sun.com/jsp/jstl/core' prefix='c'%>
+<html>
+ <head>
+ <link rel="stylesheet" href="<%=request.getContextPath()%>/images/style.css" type="text/css" />
+ <title>QMan Administration Console</title>
+ </head>
+ <body>
+ <div id="page" align="center">
+ <jsp:include page="/fragments/header.jsp">
+ <jsp:param name="title" value="System Overview"/>
+ </jsp:include>
+
+ <div id="content" align="center">
+ <jsp:include page="/fragments/menu.jsp"/>
+
+ <div id="contenttext">
+ <div class="panel" align="justify" style="height:500px; overflow-y:auto;">
+ <span class="bodytext">
+ <table width="100%" border="0">
+ <tr>
+ <td valign="top" nowrap align="center">
+ <fieldset>
+ <legend>QMan</legend>
+ <table cellspacing="2">
+ <tr><td style="color: #006633; font-size: xx-small; font-weight:bold;" align="center">Version</td></tr>
+ <tr><td style="font-size: xx-small;" align="center">${requestScope.model.version}</td></tr>
+ <tr><td><br /></td></tr>
+ <tr><td style="color: #006633; font-size: xx-small; font-weight:bold" align="center">Version Name</td></tr>
+ <tr><td style="font-size: xx-small;" align="center">${requestScope.model.versionName}</td></tr>
+ <tr><td><br /></td></tr>
+ <tr><td style="color: #006633; font-size: xx-small; font-weight:bold" align="center">Start Date</td></tr>
+ <tr>
+ <td style="font-size: xx-small;" align="center">
+ <fmt:formatDate
+ value="${requestScope.model.startDate}"
+ pattern="MM/dd/yyyy hh:mm:ss"/>
+ </td>
+ </tr>
+ <tr><td><br /></td></tr>
+ <tr><td style="color: #006633; font-size: xx-small; font-weight:bold" align="center">Host</td></tr>
+ <tr><td style="font-size: xx-small;" align="center">${requestScope.model.host}</td></tr>
+ <tr><td><br /></td></tr>
+ <tr><td style="color: #006633; font-size: xx-small; font-weight:bold" align="center">Port</td></tr>
+ <tr><td style="font-size: xx-small;" align="center">${requestScope.model.port}</td></tr>
+ </table>
+ </fieldset>
+ <fieldset>
+ <legend>Operating System</legend>
+ <table cellspacing="2">
+ <tr><td style="color: #006633; font-size: xx-small; font-weight:bold;" align="center">Name</td></tr>
+ <tr><td style="font-size: xx-small;" align="center">${requestScope.model.osName}</td></tr>
+ <tr><td><br /></td></tr>
+ <tr><td style="color: #006633; font-size: xx-small; font-weight:bold" align="center">Version</td></tr>
+ <tr><td style="font-size: xx-small;" align="center">${requestScope.model.osVersion}</td></tr>
+ <tr><td><br /></td></tr>
+ <tr><td style="color: #006633; font-size: xx-small; font-weight:bold" align="center">Arch</td></tr>
+ <tr><td style="font-size: xx-small;" align="center">${requestScope.model.archName}</td></tr>
+ <tr><td><br /></td></tr>
+ <tr><td style="color: #006633; font-size: xx-small; font-weight:bold" align="center">Processors</td></tr>
+ <tr><td style="font-size: xx-small;" align="center">${requestScope.model.processors}</td></tr>
+ </table>
+ </fieldset>
+ </td>
+ <td valign="top">
+ <fieldset>
+ <legend>JVM Environment</legend>
+ <table cellspacing="5">
+ <tr>
+ <td valign="top">
+ <h4 style="color: #006633; font-size: xx-small">Boot Classpath :
+ <p/>
+ <c:forEach var="entry" items="${model.bootClasspath}">
+ <c:out value="${entry}"/>;
+ <br/>
+ </c:forEach>
+ </h4>
+ </td>
+ <td valign="top">
+ <h4 style="color: #006633; font-size: xx-small">
+ Input Arguments :
+ <p/>
+ <c:forEach var="argument" items="${model.inputArguments}">
+ <c:out value="${argument}"/>;
+ <br/>
+ </c:forEach>
+ </h4>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+ </td>
+ </tr>
+ </table>
+ </span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/java/management/client/console/error_page.jsp b/java/management/client/console/error_page.jsp
new file mode 100644
index 0000000000..a0fd1e3629
--- /dev/null
+++ b/java/management/client/console/error_page.jsp
@@ -0,0 +1,38 @@
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+<%@ taglib uri='http://java.sun.com/jsp/jstl/core' prefix='c'%>
+<html>
+ <head>
+ <link rel="stylesheet" href="<%=request.getContextPath()%>/images/style.css" type="text/css" />
+ <title>QMan Administration Console</title>
+ </head>
+ <body>
+ <div id="page" align="center">
+ <jsp:include page="/fragments/header.jsp">
+ <jsp:param name="title" value="Error Page"/>
+ </jsp:include>
+
+ <div id="content" align="center">
+ <jsp:include page="/fragments/menu.jsp"/>
+
+ <div id="contenttext">
+ <div class="panel" align="justify" style="height:500px; overflow-y:auto;">
+ <span class="bodytext">
+ <table width="100%">
+ <tr><td nowrap style="font-weight: bold;">
+ We are not able to satify your request because an error has happened.
+ <br>Message : ${errorMessage}
+ </td></tr>
+ <tr><td nowrap style="font-size: xx-small; font-weight: bold;">
+ <c:forEach var="stackTrace" items="${exception.stackTrace}">
+ ${stackTrace}
+ <br>
+ </c:forEach>
+ </td></tr>
+ </table>
+ </span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/java/management/client/console/fragments/header.jsp b/java/management/client/console/fragments/header.jsp
new file mode 100644
index 0000000000..c835dc1bef
--- /dev/null
+++ b/java/management/client/console/fragments/header.jsp
@@ -0,0 +1,15 @@
+<div id="header" align="center">
+ <div id="pagetitle">
+ <div id="asf-header" align="left">
+ <table width="100%">
+ <tr>
+ <td align="left"><img src="images/qpid-logo.png" height="100" width="200" /></td>
+ <td align="right"><img src="images/asf-logo.png" height="69" width="225" /></td>
+ </tr>
+ </table>
+ </div>
+ <div id="title" class="titletext" align="right">
+ <span class="bluetitle"><%=request.getParameter("title")%></span>
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/java/management/client/console/fragments/menu.jsp b/java/management/client/console/fragments/menu.jsp
new file mode 100644
index 0000000000..971123e996
--- /dev/null
+++ b/java/management/client/console/fragments/menu.jsp
@@ -0,0 +1,10 @@
+<div id="menu" align="center">
+ <div id="linksmenu" align="left">
+ <a href="<%=request.getContextPath()%>/console"> &nbsp; &gt; System Overview</a>
+ <a href="<%=request.getContextPath()%>/brokers_management">&nbsp; &gt; Brokers Management</a>
+ <a href="<%=request.getContextPath()%>/resources_management">&nbsp; &gt; Resources Management</a>
+ <a>&nbsp; &gt; Subscriptions Management</a>
+ <a>&nbsp; &gt; System Health</a>
+ <a href="<%=request.getContextPath()%>/logging_configuration">&nbsp; &gt; Logging Configuration</a>
+ </div>
+</div>
diff --git a/java/management/client/console/images/asf-logo.png b/java/management/client/console/images/asf-logo.png
new file mode 100644
index 0000000000..d824fab768
--- /dev/null
+++ b/java/management/client/console/images/asf-logo.png
Binary files differ
diff --git a/java/management/client/console/images/menu.gif b/java/management/client/console/images/menu.gif
new file mode 100644
index 0000000000..9946e8e231
--- /dev/null
+++ b/java/management/client/console/images/menu.gif
Binary files differ
diff --git a/java/management/client/console/images/menuleft.gif b/java/management/client/console/images/menuleft.gif
new file mode 100644
index 0000000000..f986ecfc27
--- /dev/null
+++ b/java/management/client/console/images/menuleft.gif
Binary files differ
diff --git a/java/management/client/console/images/menuright.gif b/java/management/client/console/images/menuright.gif
new file mode 100644
index 0000000000..afdd8bd04b
--- /dev/null
+++ b/java/management/client/console/images/menuright.gif
Binary files differ
diff --git a/java/management/client/console/images/qpid-logo.png b/java/management/client/console/images/qpid-logo.png
new file mode 100644
index 0000000000..5f4ccc3081
--- /dev/null
+++ b/java/management/client/console/images/qpid-logo.png
Binary files differ
diff --git a/java/management/client/console/images/style.css b/java/management/client/console/images/style.css
new file mode 100644
index 0000000000..f8dece6f32
--- /dev/null
+++ b/java/management/client/console/images/style.css
@@ -0,0 +1,181 @@
+body
+{
+ margin-left: 0px;
+ margin-top: 0px;
+ margin-right: 0px;
+ margin-bottom: 0px;
+}
+
+tr th {
+ padding: 4px 8px 4px 8px;
+ background: #5E7796;
+ border: 1px solid #CCC;
+ color:#b8ce83;
+ font-size: smaller;
+}
+
+fieldset
+{
+ font-size: xx-small;
+}
+
+#header
+{
+ width:1024px;
+}
+
+#content
+{
+ width:1024px;
+}
+
+#contenttext
+{
+ float:left; width:824px;
+ background-color:#FFFFFF;
+ border-left:solid 1px #999999; border-right:solid 1px #999999;
+ border-bottom:solid 1px #999999; border-top:dotted 1px #CCCCCC;
+ min-height:360px;
+}
+
+#asf-header
+{
+ float:left;
+ width:1007px;
+ height:110px;
+ background-color:#FFFFFF;
+ border-right:solid 1px #999999;
+ border-left:solid 1px #999999;
+}
+
+#pagetitle
+{
+ position:relative;
+ float:left;
+ width:1024px;
+ height:110px;
+ background-color:#FFFFFF;
+}
+
+#title
+{
+ position:absolute;
+ right:20px;
+ bottom:0px;
+ width:1008px;
+}
+
+#menu
+{
+ float:left; width: 190px; margin: 0 0 0 -7px;
+}
+
+.panel{
+ padding:12px;
+ margin: 5px;
+ padding:10px;
+}
+
+.bodytext {
+ font: 0.7em Tahoma, sans-serif;
+ color: #666666;
+}
+
+.titletext {
+ font: 0.7em Tahoma, sans-serif;
+ font-size:36px;
+ font-weight:bold;
+ color: #CCCCCC;
+}
+
+.orangelogotext {
+ font: 0.7em Tahoma, sans-serif;
+ font-size:36px;
+ font-weight:bold;
+ color:#FF9900;
+}
+.orangetitle {
+ font: 0.7em Tahoma, sans-serif;
+ font-size:24px;
+ font-weight:bold;
+ color:#FF9900;
+}
+
+.bluetitle {
+ font: 0.7em Tahoma, sans-serif;
+ font-size:24px;
+ font-weight:bold;
+ color:#369;
+}
+
+#linksmenu a{
+ float:right;
+ width:183px;
+ height:20px;
+ background-color:#5E7796;
+ border-left:solid 1px #FFFFFF;
+ border-bottom:solid 1px #FFFFFF;
+ font: 0.7em Tahoma, sans-serif;
+ font-size: 11px;
+ font-weight:bold;
+ color: #FFFFFF;
+ text-decoration:none;
+ padding-top:5px;
+}
+#linksmenu a:hover
+{
+ background-color:#336;
+}
+
+
+#wsdmmenu
+{
+ float:left;
+ position: relative;
+ width: 600px;
+ font-size:75%;
+ margin: 0 0 0px 5px;
+ line-height:normal;
+}
+
+#wsdmmenu ul
+{
+ margin:0;
+ padding:0px 0px 0 0px;
+ list-style: none;
+}
+
+#wsdmmenu li
+{
+ display:inline;
+ margin:0;
+ padding:0;
+}
+
+#wsdmmenu a {
+ float:left;
+ background: url(menuleft.gif) no-repeat left top;
+ margin:0;
+ padding:0 0 0 4px;
+ text-decoration:none;
+}
+
+#wsdmmenu a span {
+ float:left;
+ display:block;
+ background: url(menuright.gif) no-repeat right top;
+ padding:5px 15px 4px 6px;
+ color:#888;
+}
+
+#wsdmmenu a span {float:none;}
+
+#wsdmmenu a:hover
+{
+ background-position:0% -42px;
+}
+
+#wsdmmenu a:hover span
+{
+ background-position:100% -42px;
+} \ No newline at end of file
diff --git a/java/management/client/console/jmx_perspective.jsp b/java/management/client/console/jmx_perspective.jsp
new file mode 100644
index 0000000000..e1d421e701
--- /dev/null
+++ b/java/management/client/console/jmx_perspective.jsp
@@ -0,0 +1,136 @@
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+<%@ taglib uri='http://java.sun.com/jsp/jstl/core' prefix='c'%>
+<%@page import="org.apache.qpid.management.web.action.BrokerModel"%>
+<%@page import="java.util.Set"%>
+<%@page import="javax.management.ObjectName"%>
+<%@page import="org.apache.qpid.management.Names"%>
+<%@page import="java.util.List"%>
+<html>
+ <head>
+ <link rel="stylesheet" href="<%=request.getContextPath()%>/images/style.css" type="text/css" />
+ <title>QMan Administration Console</title>
+ </head>
+ <body>
+ <div id="page" align="center">
+ <jsp:include page="/fragments/header.jsp">
+ <jsp:param name="title" value="Resource Management - JMX Perspective"/>
+ </jsp:include>
+
+ <div id="content" align="center">
+ <jsp:include page="/fragments/menu.jsp"/>
+
+ <div id="contenttext">
+ <div id="wsdmmenu" align="left">
+ <ul>
+ <li><a href="<%=request.getContextPath()%>/jmx_perspective?resourceId=${resourceId}"><span>JMX</span></a></li>
+ <li><a href="<%=request.getContextPath()%>/wsdm_properties_perspective?resourceId=${resourceId}"><span>WS-DM</span></a></li>
+ </ul>
+ </div>
+ <br />
+ <div class="panel" align="justify">
+ <span class="bodytext">
+ <table width="100%">
+ <tr>
+ <td valign="top" colspan="2">
+ <fieldset>
+ <legend>ObjectName</legend>
+ <ul>
+ <c:forEach var="property" items="${nameAttributes}">
+ <li>
+ <c:out value="${property}"/>
+ </li>
+ </c:forEach>
+ </ul>
+ </fieldset>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">
+ <fieldset>
+ <legend>Attributes</legend>
+ <table width="100%" cellspacing="1">
+ <tr>
+ <th>Name</th>
+ <th>Type</th>
+ <th>Value</th>
+ <th>Access</th>
+ </tr>
+ <c:forEach var="attribute" items="${metadata.attributes}" varStatus="rowCounter">
+ <c:choose>
+ <c:when test="${rowCounter.count % 2 == 0}">
+ <c:set var="bgcolor" scope="page" value="EAEAEA"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="bgcolor" scope="page" value="FFFFFF"/>
+ </c:otherwise>
+ </c:choose>
+ <c:choose>
+ <c:when test="${attribute.writable}">
+ <c:set var="access" scope="page" value="RW"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="access" scope="page" value="RO"/>
+ </c:otherwise>
+ </c:choose>
+ <tr>
+ <td nowrap style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}"><c:out value="${attribute.name}"/></td>
+ <td nowrap style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}"><c:out value="${attribute.type}"/></td>
+ <td style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}"><c:out value="${attributes[attribute.name]}"/></td>
+ <td nowrap style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}"><c:out value="${access}"/></td>
+ </tr>
+ </c:forEach>
+ </table>
+ </fieldset>
+ </td>
+ <td valign="top">
+ <fieldset>
+ <legend>Operations</legend>
+ <table width="100%" cellspacing="0">
+ <tr>
+ <th>Name</th>
+ <th>Arguments</th>
+ </tr>
+
+ <c:forEach var="operation" items="${metadata.operations}" varStatus="rowCounter">
+ <c:choose>
+ <c:when test="${rowCounter.count % 2 == 0}">
+ <c:set var="bgcolor" scope="page" value="EAEAEA"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="bgcolor" scope="page" value="FFFFFF"/>
+ </c:otherwise>
+ </c:choose>
+ <tr>
+ <td nowrap style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}"><c:out value="${operation.name}"/></td>
+ <td nowrap style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}">
+ <ul>
+ <c:forEach var="argument" items="${operation.signature}">
+ <li>
+ <c:out value="${argument.name}"/> (<c:out value="${argument.type}"/>)
+ </li>
+ </c:forEach>
+ </ul>
+ </td>
+ </tr>
+ </c:forEach>
+ </fieldset>
+ </td>
+ </tr>
+ </table>
+ </span>
+ </div>
+ </div>
+
+
+
+
+
+
+
+
+
+
+ </div>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/java/management/client/console/logging_configuration.jsp b/java/management/client/console/logging_configuration.jsp
new file mode 100644
index 0000000000..764bc5a85c
--- /dev/null
+++ b/java/management/client/console/logging_configuration.jsp
@@ -0,0 +1,220 @@
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+<%@ taglib uri='http://java.sun.com/jsp/jstl/core' prefix='c'%>
+<html>
+ <head>
+ <link rel="stylesheet" href="<%=request.getContextPath()%>/images/style.css" type="text/css" />
+ <title>QMan Administration Console</title>
+ </head>
+ <body>
+ <div id="page" align="center">
+ <jsp:include page="/fragments/header.jsp">
+ <jsp:param name="title" value="Logging Configuration"/>
+ </jsp:include>
+
+ <div id="content" align="center">
+ <jsp:include page="/fragments/menu.jsp"/>
+
+ <div id="contenttext">
+ <div class="panel" align="justify" style="height:500px; overflow-y:auto;">
+ <span class="bodytext">
+ <form method="post" name="form" action="<%=request.getContextPath() %>/logging_configuration">
+ <table>
+ <tr>
+ <td>
+ <fieldset>
+ <legend>WSDL & RDM Debugger</legend>
+ <table>
+ <tr>
+ <td>
+ <c:choose>
+ <c:when test="${wsdlDebugEnabled}">
+ <c:set var="checked" scope="page" value="checked"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="checked" scope="page" value=""/>
+ </c:otherwise>
+ </c:choose>
+ <input type="checkbox" ${checked} name="wsdlDebugEnabled" />
+ </td>
+ <td nowrap style="font-size: x-small;">
+ When this flag is checked all WSDL and RMD messages are written on log file (or console depending on your configuration.)
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ <fieldset>
+ <legend>SOAP Messages Debugger</legend>
+ <table>
+
+ <tr>
+ <td>
+ <c:choose>
+ <c:when test="${soapDebugEnabled}">
+ <c:set var="checked" scope="page" value="checked"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="checked" scope="page" value=""/>
+ </c:otherwise>
+ </c:choose>
+ <input ${checked} type="checkbox" name="soapDebugEnabled"/>
+ </td>
+ <td nowrap style="font-size: x-small;">
+ When this flag is checked all SOAP messages (requests & responses) are written on log file (or console depending on your configuration.)
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ <fieldset>
+ <legend>QMan Logger Level</legend>
+ <table>
+ <tr>
+ <td>
+ <c:choose>
+ <c:when test="${qmanLogLevel == 'DEBUG'}">
+ <c:set var="qmanDebug" scope="page" value="selected='true'"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="qmanDebug" scope="page" value=""/>
+ </c:otherwise>
+ </c:choose>
+ <c:choose>
+ <c:when test="${qmanLogLevel == 'INFO'}">
+ <c:set var="qmanInfo" scope="page" value="selected='true'"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="qmanInfo" scope="page" value=""/>
+ </c:otherwise>
+ </c:choose>
+ <c:choose>
+ <c:when test="${qmanLogLevel == 'WARN'}">
+ <c:set var="qmanWarn" scope="page" value="selected='true'"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="qmanWarn" scope="page" value=""/>
+ </c:otherwise>
+ </c:choose>
+ <c:choose>
+ <c:when test="${qmanLogLevel == 'ERROR'}">
+ <c:set var="qmanError" scope="page" value="selected='true'"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="qmanError" scope="page" value=""/>
+ </c:otherwise>
+ </c:choose>
+ <c:choose>
+ <c:when test="${qmanLogLevel == 'FATAL'}">
+ <c:set var="qmanFatal" scope="page" value="selected='true'"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="qmanFatal" scope="page" value=""/>
+ </c:otherwise>
+ </c:choose>
+
+ <select name="qmanLogLevel">
+ <option ${qmanDebug} value="DEBUG">DEBUG</option>
+ <option ${qmanWarn} value="WARN">WARNING</option>
+ <option ${qmanInfo} value="INFO">INFO</option>
+ <option ${qmanError} value="ERROR">ERROR</option>
+ <option ${qmanFatal} value="FATAL">FATAL</option>
+ </select>
+ </td>
+ <td nowrap style="font-size: x-small;">
+ This is the current priority level set for QMan module (and sub-modules). Note that a WARNING level is recomended in production.
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ <fieldset>
+ <legend>Web Server Logger Level</legend>
+ <table>
+
+ <tr>
+ <td>
+ <c:choose>
+ <c:when test="${webServerLogLevel == 'DEBUG'}">
+ <c:set var="webServerDebug" scope="page" value="selected='true'"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="webServerDebug" scope="page" value=""/>
+ </c:otherwise>
+ </c:choose>
+ <c:choose>
+ <c:when test="${webServerLogLevel == 'INFO'}">
+ <c:set var="webServerInfo" scope="page" value="selected='true'"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="webServerInfo" scope="page" value=""/>
+ </c:otherwise>
+ </c:choose>
+ <c:choose>
+ <c:when test="${webServerLogLevel == 'WARN'}">
+ <c:set var="webServerWarn" scope="page" value="selected='true'"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="webServerWarn" scope="page" value=""/>
+ </c:otherwise>
+ </c:choose>
+ <c:choose>
+ <c:when test="${webServerLogLevel == 'ERROR'}">
+ <c:set var="webServerError" scope="page" value="selected='true'"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="webServerError" scope="page" value=""/>
+ </c:otherwise>
+ </c:choose>
+ <c:choose>
+ <c:when test="${webServerLogLevel == 'FATAL'}">
+ <c:set var="webServerFatal" scope="page" value="selected='true'"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="webServerFatal" scope="page" value=""/>
+ </c:otherwise>
+ </c:choose>
+
+ <select name="webServerLogLevel">
+ <option ${webServerDebug} value="DEBUG" >DEBUG</option>
+ <option ${webServerWarn} value="WARN">WARNING</option>
+ <option ${webServerInfo} value="INFO">INFO</option>
+ <option ${webServerError} value="ERROR">ERROR</option>
+ <option ${webServerFatak} value="FATAL">FATAL</option>
+ </select>
+ </td>
+ <td nowrap style="font-size: x-small; ">
+ This is the current priority level set for QMan module (and sub-modules). Note that a WARNING level is recomended in production.
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <input type="submit" value="Submit" title="Submit"/>
+ </td>
+ </tr>
+ </table>
+ <br/></br>
+ <span style="fony-size: medium; color: red; font-weight: bold">Note that in general a DEBUG level is not reccommended in production (especially for WSDL and SOAP debugger).</span>
+ </form>
+ </span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/java/management/client/console/resources_management.jsp b/java/management/client/console/resources_management.jsp
new file mode 100644
index 0000000000..1541f3a5bc
--- /dev/null
+++ b/java/management/client/console/resources_management.jsp
@@ -0,0 +1,84 @@
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+<%@ taglib uri='http://java.sun.com/jsp/jstl/core' prefix='c'%>
+<%@page import="org.apache.qpid.management.web.action.BrokerModel"%>
+<%@page import="java.util.Set"%>
+<%@page import="javax.management.ObjectName"%>
+<%@page import="org.apache.qpid.management.Names"%>
+<%@page import="java.util.List"%>
+
+<%
+ BrokerModel model = (BrokerModel) request.getAttribute("model");
+%>
+<html>
+ <head>
+ <link rel="stylesheet" href="<%=request.getContextPath()%>/images/style.css" type="text/css" />
+ <title>QMan Administration Console</title>
+ </head>
+ <body>
+ <div id="page" align="center">
+ <jsp:include page="/fragments/header.jsp">
+ <jsp:param name="title" value="Resources Management"/>
+ </jsp:include>
+
+ <div id="content" align="center">
+ <jsp:include page="/fragments/menu.jsp"/>
+
+
+ <div id="contenttext">
+ <div id="wsdmmenu" align="left">
+ <ul>
+ <% if (model != null) {%>
+ <li><a href="#"><span>${model.id}</span></a></li>
+ <%} %>
+ </ul>
+ </div>
+ <br />
+ <div class="panel" align="justify" style="height:500px; overflow-y:auto;">
+ <span class="bodytext">
+ <table width="100%" border="0" cellpadding="1" cellspacing="2">
+<%
+ if (model != null ){
+ Set<String> categoryNames = model.getCategoryNames();
+ for(String categoryName : categoryNames)
+ {
+ List<ObjectName> categoryObjects = model.getCategory(categoryName);
+%>
+ <tr>
+ <td valign="top" nowrap align="left">
+ <fieldset>
+ <legend><%=categoryName%></legend>
+ <h4 style="color: #006633; font-size: xx-small">
+ <ul>
+ <%
+ for (ObjectName objectName : categoryObjects)
+ {%>
+
+ <li>
+ <a href="<%=request.getContextPath()%>/jmx_perspective?resourceId=<%=objectName%>">
+ <%=objectName.getKeyProperty(Names.OBJECT_ID)%>
+ </a>
+ </li>
+ <%
+ }
+ %>
+ </ul>
+ </fieldset>
+ </td>
+ </tr>
+<%
+ }
+ } else {
+%>
+<table><tr>
+<td nowrap style="font-weight: bold;" >Sorry, but it seems that QMan is not connected with any broker...</td>
+</tr>
+</table>
+<%
+ }
+%>
+ </table>
+ </span>
+ </div>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/java/management/client/console/tbd.jsp b/java/management/client/console/tbd.jsp
new file mode 100644
index 0000000000..486a4cff86
--- /dev/null
+++ b/java/management/client/console/tbd.jsp
@@ -0,0 +1,27 @@
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+<%@ taglib uri='http://java.sun.com/jsp/jstl/core' prefix='c'%>
+<html>
+ <head>
+ <link rel="stylesheet" href="<%=request.getContextPath()%>/images/style.css" type="text/css" />
+ <title>QMan Administration Console</title>
+ </head>
+ <body>
+ <div id="page" align="center">
+ <jsp:include page="/fragments/header.jsp">
+ <jsp:param name="title" value="TBD"/>
+ </jsp:include>
+
+ <div id="content" align="center">
+ <jsp:include page="/fragments/menu.jsp"/>
+
+ <div id="contenttext">
+ <div class="panel" align="justify" style="height:500px; overflow-y:auto;">
+ <span class="bodytext">
+ Sorry, this feature is not yet available!
+ </span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/java/management/client/console/wsdm_operations_perspective.jsp b/java/management/client/console/wsdm_operations_perspective.jsp
new file mode 100644
index 0000000000..f4038b2e14
--- /dev/null
+++ b/java/management/client/console/wsdm_operations_perspective.jsp
@@ -0,0 +1,153 @@
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+<%@ taglib uri='http://java.sun.com/jsp/jstl/core' prefix='c'%>
+<%@page import="org.apache.qpid.management.web.action.BrokerModel"%>
+<%@page import="java.util.Set"%>
+<%@page import="javax.management.ObjectName"%>
+<%@page import="org.apache.qpid.management.Names"%>
+<%@page import="java.util.*"%>
+<%
+ Map<String,String> java2Xml = new HashMap<String,String>();
+java2Xml.put(UUID.class.getName(),"qman:uuid");
+java2Xml.put(Long.class.getName(),"xsd:long");
+java2Xml.put(long.class.getName(),"xsd:long");
+java2Xml.put(Boolean.class.getName(),"xsd:boolean");
+java2Xml.put(boolean.class.getName(),"xsd:boolean");
+java2Xml.put(Double.class.getName(),"xsd:double");
+java2Xml.put(double.class.getName(),"xsd:double");
+java2Xml.put(Float.class.getName(),"xsd:float");
+java2Xml.put(float.class.getName(),"xsd:float");
+java2Xml.put(Integer.class.getName(),"xsd:integer");
+java2Xml.put(int.class.getName(),"xsd:integer");
+java2Xml.put(Short.class.getName(),"xsd:short");
+java2Xml.put(short.class.getName(),"xsd:short");
+java2Xml.put(String.class.getName(),"xsd:string");
+java2Xml.put(URI.class.getName(),"xsd:anyURI");
+java2Xml.put(Date.class.getName(),"xsd:dateTime");
+java2Xml.put(QName.class.getName(),"xsd:QName");
+java2Xml.put(Element.class.getName(),"xsd:element");
+java2Xml.put(byte[].class.getName(),"xsd:base64Binary");
+java2Xml.put(Long[].class.getName(),"qman:arrayOfLong");
+java2Xml.put(long[].class.getName(),"qman:arrayOfLong");
+java2Xml.put(Boolean[].class.getName(),"qman:arrayOfBoolean");
+java2Xml.put(boolean[].class.getName(),"qman:arrayOfBoolean");
+java2Xml.put(Double[].class.getName(),"qman:arrayOfDouble");
+java2Xml.put(double[].class.getName(),"qman:arrayOfDouble");
+java2Xml.put(Float[].class.getName(),"qman:arrayOfFloat");
+java2Xml.put(float[].class.getName(),"qman:arrayOfFloat");
+java2Xml.put(Integer[].class.getName(),"qman:arrayOfInteger");
+java2Xml.put(int[].class.getName(),"qman:arrayOfInteger");
+java2Xml.put(Short[].class.getName(),"qman:arrayOfShort");
+java2Xml.put(short[].class.getName(),"qman:arrayOfShort");
+java2Xml.put(String[].class.getName(),"qman:arrayOfString");
+java2Xml.put(URI[].class.getName(),"qman:arrayOfURI");
+java2Xml.put(Date[].class.getName(),"qman:arrayOfDate");
+java2Xml.put(Map.class.getName(),"qman:map");
+java2Xml.put(HashMap.class.getName(),"qman:map");
+
+pageContext.setAttribute("types",java2Xml);
+%>
+<%@page import="java.net.URI"%>
+<%@page import="javax.xml.namespace.QName"%>
+<%@page import="org.w3c.dom.Element"%>
+<html>
+ <head>
+ <link rel="stylesheet" href="<%=request.getContextPath()%>/images/style.css" type="text/css" />
+ <title>QMan Administration Console</title>
+ </head>
+ <body>
+ <div id="page" align="center">
+ <jsp:include page="/fragments/header.jsp">
+ <jsp:param name="title" value="Resource Management - WS-DM Operations Perspective"/>
+ </jsp:include>
+
+ <div id="content" align="center">
+ <jsp:include page="/fragments/menu.jsp"/>
+
+ <div id="contenttext">
+ <div id="wsdmmenu" align="left">
+ <ul>
+ <li><a href="<%=request.getContextPath()%>/jmx_perspective?resourceId=${resourceId}"><span>JMX</span></a></li>
+ <li><a href="<%=request.getContextPath()%>/wsdm_properties_perspective?wsresourceId=${resourceId}"><span>WS-DM</span></a></li>
+ </ul>
+ </div>
+ <br />
+ <div class="panel" align="justify">
+ <span class="bodytext">
+ <table width="100%">
+ <tr>
+ <td valign="top" colspan="2">
+ <fieldset>
+ <legend>Resource ID</legend>
+ <ul>
+ <c:forEach var="property" items="${nameAttributes}">
+ <li>
+ <c:out value="${property}"/>
+ </li>
+ </c:forEach>
+ </ul>
+ </fieldset>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">
+ <div id="wsdmmenu" align="left" style="font-size: small;">
+ <ul>
+ <li><a href="<%=request.getContextPath()%>/wsdm_properties_perspective?resourceId=${resourceId}"><span>Properties</span></a></li>
+ <li><a href="<%=request.getContextPath()%>/wsdm_operations_perspective?resourceId=${resourceId}""><span>Operations</span></a></li>
+ <li><a href="<%=request.getContextPath()%>/wsdm_wsdl_perspective?resourceId=${resourceId}""><span>WSDL</span></a></li>
+ <li><a href="<%=request.getContextPath()%>/wsdm_rmd_perspective?resourceId=${resourceId}""><span>RDM</span></a></li>
+ </ul>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">
+ <fieldset>
+ <legend>Attributes</legend>
+ <table width="100%" cellspacing="1">
+ <tr>
+ <th nowrap="nowrap" align="center">Name</th>
+ <th nowrap="nowrap" align="center">Arguments</th>
+ <th nowrap="nowrap" align="center">Faults</th>
+ </tr>
+ <c:forEach var="operation" items="${metadata.operations}" varStatus="rowCounter">
+ <c:choose>
+ <c:when test="${rowCounter.count % 2 == 0}">
+ <c:set var="bgcolor" scope="page" value="EAEAEA"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="bgcolor" scope="page" value="FFFFFF"/>
+ </c:otherwise>
+ </c:choose>
+ <tr>
+ <td nowrap style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}"><c:out value="${operation.name}"/></td>
+ <td nowrap style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}">
+ <ul>
+ <c:forEach var="argument" items="${operation.signature}">
+ <li>
+ <c:out value="${argument.name}"/> (<c:out value="${types[argument.type]}"/>)
+ </li>
+ </c:forEach>
+ </ul>
+ </td>
+ <td nowrap style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}">
+ <ul>
+ <li>qman:EntityInstanceNotFoundFault</li>
+ <li>qman:OperationInvocationFault</li>
+ <li>qman:QManFault</li>
+ </ul>
+ </td>
+ </tr>
+ </c:forEach>
+ </table>
+ </fieldset>
+ </td>
+ </tr>
+ </table>
+ </span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/java/management/client/console/wsdm_properties_perspective.jsp b/java/management/client/console/wsdm_properties_perspective.jsp
new file mode 100644
index 0000000000..2e8699e309
--- /dev/null
+++ b/java/management/client/console/wsdm_properties_perspective.jsp
@@ -0,0 +1,197 @@
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+<%@ taglib uri='http://java.sun.com/jsp/jstl/core' prefix='c'%>
+<%@page import="org.apache.qpid.management.web.action.BrokerModel"%>
+<%@page import="java.util.Set"%>
+<%@page import="javax.management.ObjectName"%>
+<%@page import="org.apache.qpid.management.Names"%>
+<%@page import="java.util.List"%>
+<%@page import="java.util.*"%>
+
+<%
+ Map<String,String> java2Xml = new HashMap<String,String>();
+java2Xml.put(UUID.class.getName(),"qman:uuid");
+java2Xml.put(Long.class.getName(),"xsd:long");
+java2Xml.put(long.class.getName(),"xsd:long");
+java2Xml.put(Boolean.class.getName(),"xsd:boolean");
+java2Xml.put(boolean.class.getName(),"xsd:boolean");
+java2Xml.put(Double.class.getName(),"xsd:double");
+java2Xml.put(double.class.getName(),"xsd:double");
+java2Xml.put(Float.class.getName(),"xsd:float");
+java2Xml.put(float.class.getName(),"xsd:float");
+java2Xml.put(Integer.class.getName(),"xsd:integer");
+java2Xml.put(int.class.getName(),"xsd:integer");
+java2Xml.put(Short.class.getName(),"xsd:short");
+java2Xml.put(short.class.getName(),"xsd:short");
+java2Xml.put(String.class.getName(),"xsd:string");
+java2Xml.put(URI.class.getName(),"xsd:anyURI");
+java2Xml.put(Date.class.getName(),"xsd:dateTime");
+java2Xml.put(QName.class.getName(),"xsd:QName");
+java2Xml.put(Element.class.getName(),"xsd:element");
+java2Xml.put(byte[].class.getName(),"xsd:base64Binary");
+java2Xml.put(Long[].class.getName(),"qman:arrayOfLong");
+java2Xml.put(long[].class.getName(),"qman:arrayOfLong");
+java2Xml.put(Boolean[].class.getName(),"qman:arrayOfBoolean");
+java2Xml.put(boolean[].class.getName(),"qman:arrayOfBoolean");
+java2Xml.put(Double[].class.getName(),"qman:arrayOfDouble");
+java2Xml.put(double[].class.getName(),"qman:arrayOfDouble");
+java2Xml.put(Float[].class.getName(),"qman:arrayOfFloat");
+java2Xml.put(float[].class.getName(),"qman:arrayOfFloat");
+java2Xml.put(Integer[].class.getName(),"qman:arrayOfInteger");
+java2Xml.put(int[].class.getName(),"qman:arrayOfInteger");
+java2Xml.put(Short[].class.getName(),"qman:arrayOfShort");
+java2Xml.put(short[].class.getName(),"qman:arrayOfShort");
+java2Xml.put(String[].class.getName(),"qman:arrayOfString");
+java2Xml.put(URI[].class.getName(),"qman:arrayOfURI");
+java2Xml.put(Date[].class.getName(),"qman:arrayOfDate");
+java2Xml.put(Map.class.getName(),"qman:map");
+java2Xml.put(HashMap.class.getName(),"qman:map");
+
+pageContext.setAttribute("types",java2Xml);
+%>
+<%@page import="java.net.URI"%>
+<%@page import="javax.xml.namespace.QName"%>
+<%@page import="org.w3c.dom.Element"%>
+<html>
+ <head>
+ <link rel="stylesheet" href="<%=request.getContextPath()%>/images/style.css" type="text/css" />
+ <title>QMan Administration Console</title>
+ </head>
+ <body>
+ <div id="page" align="center">
+ <jsp:include page="/fragments/header.jsp">
+ <jsp:param name="title" value="Resource Management - WS-DM Properties Perspective"/>
+ </jsp:include>
+
+ <div id="content" align="center">
+ <jsp:include page="/fragments/menu.jsp"/>
+
+ <div id="contenttext">
+ <div id="wsdmmenu" align="left">
+ <ul>
+ <li><a href="<%=request.getContextPath()%>/jmx_perspective?resourceId=${resourceId}"><span>JMX</span></a></li>
+ <li><a href="<%=request.getContextPath()%>/wsdm_properties_perspective?resourceId=${resourceId}"><span>WS-DM</span></a></li>
+ </ul>
+ </div>
+ <br />
+ <div class="panel" align="justify">
+ <span class="bodytext">
+ <table width="100%">
+ <tr>
+ <td valign="top" colspan="2">
+ <fieldset>
+ <legend>Resource ID</legend>
+ <ul>
+ <c:forEach var="property" items="${nameAttributes}">
+ <li>
+ <c:out value="${property}"/>
+ </li>
+ </c:forEach>
+ </ul>
+ </fieldset>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">
+ <div id="wsdmmenu" align="left" style="font-size: small;">
+ <ul>
+ <li><a href="<%=request.getContextPath()%>/wsdm_properties_perspective?resourceId=${resourceId}"><span>Properties</span></a></li>
+ <li><a href="<%=request.getContextPath()%>/wsdm_operations_perspective?resourceId=${resourceId}""><span>Operations</span></a></li>
+ <li><a href="<%=request.getContextPath()%>/wsdm_wsdl_perspective?resourceId=${resourceId}""><span>WSDL</span></a></li>
+ <li><a href="<%=request.getContextPath()%>/wsdm_rmd_perspective?resourceId=${resourceId}""><span>RDM</span></a></li>
+ </ul>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">
+ <fieldset>
+ <legend>Attributes</legend>
+ <table width="100%" cellspacing="1">
+ <tr>
+ <th nowrap="nowrap" align="center">Name</th>
+ <th nowrap="nowrap" align="center" >Type</th>
+ <th nowrap="nowrap" align="center">Value</th>
+ <th nowrap="nowrap" align="center">Mutable</th>
+ <th nowrap="nowrap" align="center">Access</th>
+ <th nowrap="nowrap" align="center">Valid Values</th>
+ <th nowrap="nowrap" align="center">Static Values</th>
+ <th nowrap="nowrap" align="center">Initial Values</th>
+ </tr>
+ <c:forEach var="attribute" items="${metadata.attributes}" varStatus="rowCounter">
+ <c:choose>
+ <c:when test="${rowCounter.count % 2 == 0}">
+ <c:set var="bgcolor" scope="page" value="EAEAEA"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="bgcolor" scope="page" value="FFFFFF"/>
+ </c:otherwise>
+ </c:choose>
+ <c:choose>
+ <c:when test="${attribute.writable}">
+ <c:set var="access" scope="page" value="RW"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="access" scope="page" value="RO"/>
+ </c:otherwise>
+ </c:choose>
+ <tr>
+ <td nowrap style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}"><c:out value="${attribute.name}"/></td>
+ <td nowrap style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}"><c:out value="${types[attribute.type]}"/></td>
+ <td style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}"><c:out value="${attributes[attribute.name]}"/></td>
+ <td nowrap style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}">
+ &radic;
+ <%--
+ <c:out value="${attribute.mutable}"/>
+ --%>
+ </td>
+ <td nowrap style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}"><c:out value="${access}"/></td>
+ <td nowrap style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}">
+ N.A.
+<%--
+ <ul>
+ <c:forEach var="value" items="${attribute.validValues}">
+ <li>
+ <c:out value="${value}"/>
+ </li>
+ </c:forEach>
+ </ul>
+--%>
+ </td>
+ <td nowrap style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}">
+ N.A.
+<%--
+ <ul>
+ <c:forEach var="value" items="${attribute.staticValues}">
+ <li>
+ <c:out value="${value}"/>
+ </li>
+ </c:forEach>
+ </ul>
+--%>
+ </td>
+ <td nowrap style="font-size: xx-small; font-weight: bold;" bgcolor="${bgcolor}">
+ N.A.
+<%--
+ <ul>
+ <c:forEach var="value" items="${attribute.initialValues}">
+ <li>
+ <c:out value="${value}"/>
+ </li>
+ </c:forEach>
+ </ul>
+--%>
+ </td>
+ </tr>
+ </c:forEach>
+ </table>
+ </fieldset>
+ </td>
+ </tr>
+ </table>
+ </span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/java/management/client/console/wsdm_rmd_perspective.jsp b/java/management/client/console/wsdm_rmd_perspective.jsp
new file mode 100644
index 0000000000..fe70930627
--- /dev/null
+++ b/java/management/client/console/wsdm_rmd_perspective.jsp
@@ -0,0 +1,78 @@
+<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
+<%@ taglib uri='http://java.sun.com/jsp/jstl/core' prefix="c"%>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/xml" prefix="x"%>
+
+<%@page import="org.apache.qpid.management.web.action.BrokerModel"%>
+<%@page import="java.util.Set"%>
+<%@page import="javax.management.ObjectName"%>
+<%@page import="org.apache.qpid.management.Names"%>
+<%@page import="java.util.*"%>
+<%@page import="java.net.URI"%>
+<%@page import="javax.xml.namespace.QName"%>
+<%@page import="org.w3c.dom.Element"%>
+<html>
+ <head>
+ <link rel="stylesheet" href="<%=request.getContextPath()%>/images/style.css" type="text/css" />
+ <title>QMan Administration Console</title>
+ </head>
+ <body>
+ <div id="page" align="center">
+ <jsp:include page="/fragments/header.jsp">
+ <jsp:param name="title" value="Resource Management - WS-DM RMD Perspective"/>
+ </jsp:include>
+
+ <div id="content" align="center">
+ <jsp:include page="/fragments/menu.jsp"/>
+
+ <div id="contenttext">
+ <div id="wsdmmenu" align="left">
+ <ul>
+ <li><a href="<%=request.getContextPath()%>/jmx_perspective?resourceId=${resourceId}"><span>JMX</span></a></li>
+ <li><a href="<%=request.getContextPath()%>/wsdm_properties_perspective?wsresourceId=${resourceId}"><span>WS-DM</span></a></li>
+ </ul>
+ </div>
+ <br />
+ <div class="panel" align="justify">
+ <span class="bodytext">
+ <table width="100%">
+ <tr>
+ <td valign="top" colspan="2">
+ <fieldset>
+ <legend>Resource ID</legend>
+ <ul>
+ <c:forEach var="property" items="${nameAttributes}">
+ <li>
+ <c:out value="${property}"/>
+ </li>
+ </c:forEach>
+ </ul>
+ </fieldset>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">
+ <div id="wsdmmenu" align="left" style="font-size: small;">
+ <ul>
+ <li><a href="<%=request.getContextPath()%>/wsdm_properties_perspective?resourceId=${resourceId}"><span>Properties</span></a></li>
+ <li><a href="<%=request.getContextPath()%>/wsdm_operations_perspective?resourceId=${resourceId}""><span>Operations</span></a></li>
+ <li><a href="<%=request.getContextPath()%>/wsdm_wsdl_perspective?resourceId=${resourceId}""><span>WSDL</span></a></li>
+ <li><a href="<%=request.getContextPath()%>/wsdm_rmd_perspective?resourceId=${resourceId}""><span>RDM</span></a></li>
+ </ul>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">
+ <div class="panel" align="left" style="height:500px; width=200px; overflow-y:auto; font-size: smaller; font-weight:bold;">
+ <pre> <c:out value="${rmd}" /> </pre>
+ </div>
+ </td>
+ </tr>
+ </table>
+ </span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/java/management/client/console/wsdm_wsdl_perspective.jsp b/java/management/client/console/wsdm_wsdl_perspective.jsp
new file mode 100644
index 0000000000..3759459842
--- /dev/null
+++ b/java/management/client/console/wsdm_wsdl_perspective.jsp
@@ -0,0 +1,78 @@
+<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
+<%@ taglib uri='http://java.sun.com/jsp/jstl/core' prefix="c"%>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/xml" prefix="x"%>
+
+<%@page import="org.apache.qpid.management.web.action.BrokerModel"%>
+<%@page import="java.util.Set"%>
+<%@page import="javax.management.ObjectName"%>
+<%@page import="org.apache.qpid.management.Names"%>
+<%@page import="java.util.*"%>
+<%@page import="java.net.URI"%>
+<%@page import="javax.xml.namespace.QName"%>
+<%@page import="org.w3c.dom.Element"%>
+<html>
+ <head>
+ <link rel="stylesheet" href="<%=request.getContextPath()%>/images/style.css" type="text/css" />
+ <title>QMan Administration Console</title>
+ </head>
+ <body>
+ <div id="page" align="center">
+ <jsp:include page="/fragments/header.jsp">
+ <jsp:param name="title" value="Resource Management - WS-DM WSDL Perspective"/>
+ </jsp:include>
+
+ <div id="content" align="center">
+ <jsp:include page="/fragments/menu.jsp"/>
+
+ <div id="contenttext">
+ <div id="wsdmmenu" align="left">
+ <ul>
+ <li><a href="<%=request.getContextPath()%>/jmx_perspective?resourceId=${resourceId}"><span>JMX</span></a></li>
+ <li><a href="<%=request.getContextPath()%>/wsdm_properties_perspective?resourceId=${resourceId}"><span>WS-DM</span></a></li>
+ </ul>
+ </div>
+ <br />
+ <div class="panel" align="justify">
+ <span class="bodytext">
+ <table width="100%">
+ <tr>
+ <td valign="top" colspan="2">
+ <fieldset>
+ <legend>Resource ID</legend>
+ <ul>
+ <c:forEach var="property" items="${nameAttributes}">
+ <li style="color : black;">
+ <c:out value="${property}"/>
+ </li>
+ </c:forEach>
+ </ul>
+ </fieldset>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">
+ <div id="wsdmmenu" align="left" style="font-size: small;">
+ <ul>
+ <li><a href="<%=request.getContextPath()%>/wsdm_properties_perspective?resourceId=${resourceId}"><span>Properties</span></a></li>
+ <li><a href="<%=request.getContextPath()%>/wsdm_operations_perspective?resourceId=${resourceId}""><span>Operations</span></a></li>
+ <li><a href="<%=request.getContextPath()%>/wsdm_wsdl_perspective?resourceId=${resourceId}""><span>WSDL</span></a></li>
+ <li><a href="<%=request.getContextPath()%>/wsdm_rmd_perspective?resourceId=${resourceId}""><span>RDM</span></a></li>
+ </ul>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">
+ <div class="panel" align="left" style="height:500px; width=200px; overflow-y:auto; font-size: smaller; font-weight:bold;">
+ <pre> <c:out value="${wsdl}" /> </pre>
+ </div>
+ </td>
+ </tr>
+ </table>
+ </span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/java/management/client/doc/man/qman-jmx b/java/management/client/doc/man/qman-jmx
new file mode 100644
index 0000000000..064c00eae5
--- /dev/null
+++ b/java/management/client/doc/man/qman-jmx
@@ -0,0 +1,17 @@
+.TH qman-jmx
+.SH NAME
+qman-jmx is a Management bridge that exposes one (or several) Qpid broker domain model as MBeans that are accessible through the Java Management Extensions (JMX). Once you run qman you need to start a JMX Console such as JConsole to browse the MBeans exposed by Q-Man.
+.SH SYNOPSIS
+qman
+.SH DESCRIPTION
+For more information on customizing qman-jmx for your own environment please read http://cwiki.apache.org/confluence/display/qpid/Qman+Tool
+.SH Configuration
+.SS Classpath
+By default qman jars will be loaded from /usr/share/java. If you want to load from an alternative location you could specify it using QPID_LIB_PATH var.
+.SS Config file
+qman can be configured to connect to one or more brokers at startup by adding brokers in
+.I /etc/qman-config.xml
+If you want to load qman with qman-config.xml from a different location, you can specify it using QPID_CONFIG_FILE var.
+.SS log4j configuration
+qman expects qman.log4j file to be in the classpath. By default it will be put in
+.I /usr/share/java
diff --git a/java/management/client/etc/jetty.xml b/java/management/client/etc/jetty.xml
new file mode 100644
index 0000000000..38a4775641
--- /dev/null
+++ b/java/management/client/etc/jetty.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
+<Configure id="Server" class="org.mortbay.jetty.Server">
+ <Set name="StopAtShutdown">true</Set>
+ <Set name="Connectors">
+ <Array type="org.mortbay.jetty.Connector">
+ <Item>
+ <New
+ class="org.mortbay.jetty.nio.SelectChannelConnector">
+ <Set name="port">
+ <SystemProperty name="qman.port" default="8080" />
+ </Set>
+ <Set name="host">
+ <SystemProperty name="qman.host" default="localhost" />
+ </Set>
+ </New>
+ </Item>
+ </Array>
+ </Set>
+ <Set name="handler">
+ <New class="org.mortbay.jetty.webapp.WebAppContext">
+ <Set name="contextPath">/qman</Set>
+ <Set name="war"><SystemProperty name="QMAN_HOME" default=".." />/app/qman</Set>
+ </New>
+ </Set>
+</Configure> \ No newline at end of file
diff --git a/java/management/client/etc/log4j.xml b/java/management/client/etc/log4j.xml
new file mode 100644
index 0000000000..0b63512211
--- /dev/null
+++ b/java/management/client/etc/log4j.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
+
+ <!-- QMan Appender-->
+ <appender name="QMAN_LOG"
+ class="org.apache.log4j.DailyRollingFileAppender">
+ <param name="File" value="../log/qman.log" />
+ <param name="Append" value="true" />
+ <param name="DatePattern" value="'.'yyyy-MM-dd" />
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%d %-5p [%c{1}] %m%n" />
+ </layout>
+ </appender>
+
+ <!-- XML messages appender -->
+ <appender name="MESSAGES_LOG"
+ class="org.apache.log4j.DailyRollingFileAppender">
+<!-- <param name="File" value="../log/messages.log" /> -->
+ <param name="File" value="../log/messages.log"/>
+ <param name="Append" value="true" />
+ <param name="DatePattern" value="'.'yyyy-MM-dd" />
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%d%n %m%n" />
+ </layout>
+ </appender>
+
+ <!-- Web Server Appender-->
+ <appender name="SERVER_LOG"
+ class="org.apache.log4j.DailyRollingFileAppender">
+ <param name="File" value="../log/server.log" />
+ <param name="Append" value="true" />
+ <param name="DatePattern" value="'.'yyyy-MM-dd" />
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%d %-5p [%c{1}] %m%n" />
+ </layout>
+ </appender>
+
+ <!-- Write to stdout -->
+ <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+ <param name="Target" value="System.out" />
+ <param name="Threshold" value="DEBUG" />
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern"
+ value="%d{ABSOLUTE} %-5p [%c{1}] %m%n" />
+ </layout>
+ </appender>
+
+ <!-- Category for QMan module -->
+ <category name="org.apache.qpid.management">
+ <priority value="INFO" />
+ <appender-ref ref="QMAN_LOG" />
+ </category>
+
+ <!-- Category for Jetty module : if you are using the JMX distribution you don't need this category-->
+ <category name="org.mortbay">
+ <priority value="INFO" />
+ <appender-ref ref="SERVER_LOG" />
+ </category>
+
+ <category name="org.apache.qpid.qman.debug.XmlDebugger">
+ <priority value="INFO" />
+ <appender-ref ref="MESSAGES_LOG" />
+ </category>
+
+ <category name="org.apache.qpid.qman.debug.WsdlDebugger">
+ <priority value="INFO" />
+ <appender-ref ref="MESSAGES_LOG" />
+ </category>
+
+ <root>
+ <priority value="ERROR" />
+ </root>
+
+</log4j:configuration> \ No newline at end of file
diff --git a/java/management/client/etc/qman-config.xml b/java/management/client/etc/qman-config.xml
new file mode 100644
index 0000000000..cdc840e967
--- /dev/null
+++ b/java/management/client/etc/qman-config.xml
@@ -0,0 +1,68 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<configuration>
+
+<!--
+Default configuration for QMan has no broker settings;
+that is, there's no broker configured at startup.
+If you want to connect with a running broker when QMan starts up,
+you can do that uncommenting and editing the template reported below.
+-->
+<!-- <brokers>
+ <broker>
+ <host>localhost</host>
+ <port>5672</port>
+ <virtual-host>test</virtual-host>
+ <user>guest</user>
+ <password>guest</password>
+ <max-pool-capacity>4</max-pool-capacity>
+ <initial-pool-capacity>0</initial-pool-capacity>
+ <max-wait-timeout>-1</max-wait-timeout>
+ </broker>
+ <broker>
+ <host>localhost</host>
+ <port>5672</port>
+ <virtual-host>test</virtual-host>
+ <user>guest</user>
+ <password>guest</password>
+ <max-pool-capacity>4</max-pool-capacity>
+ <initial-pool-capacity>0</initial-pool-capacity>
+ <max-wait-timeout>-1</max-wait-timeout>
+ </broker>
+ </brokers>
+ -->
+ <!-- Internal worked manager configuration-->
+ <work-manager>
+ <!-- The size of the worker thread pool -->
+ <pool-capacity>5</pool-capacity>
+
+ <!-- Maximum size of the worker thread pool -->
+ <max-pool-capacity>15</max-pool-capacity>
+
+ <!--
+ when the current number of threads is greater than
+ the pool-capacity, this is the maximum time that excess threads
+ can be in an idle state (without any task assigned) before terminating.
+ The value is expressed is milliseconds.
+ -->
+ <keep-alive-time>5000</keep-alive-time>
+ </work-manager>
+</configuration>
diff --git a/java/management/client/etc/qman-config.xsd b/java/management/client/etc/qman-config.xsd
new file mode 100644
index 0000000000..38282c63d1
--- /dev/null
+++ b/java/management/client/etc/qman-config.xsd
@@ -0,0 +1,63 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+-->
+<?xml version="1.0" encoding="UTF-8"?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <xsd:element name="broker">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="host" minOccurs="1" maxOccurs="1"/>
+ <xsd:element ref="port" minOccurs="1" maxOccurs="1"/>
+ <xsd:element ref="virtual-host" minOccurs="1" maxOccurs="1"/>
+ <xsd:element ref="user" minOccurs="1" maxOccurs="1"/>
+ <xsd:element ref="password" minOccurs="1" maxOccurs="1"/>
+ <xsd:element ref="max-pool-capacity" minOccurs="1" maxOccurs="1"/>
+ <xsd:element ref="initial-pool-capacity" minOccurs="1" maxOccurs="1"/>
+ <xsd:element ref="max-wait-timeout" minOccurs="1" maxOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="brokers">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="broker" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="configuration">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="brokers" maxOccurs="1" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="host" type="xsd:string"/>
+ <xsd:element name="initial-pool-capacity" type="xsd:integer"/>
+ <xsd:element name="max-pool-capacity" type="xsd:integer"/>
+ <xsd:element name="max-wait-timeout" type="xsd:integer"/>
+ <xsd:element name="password" type="xsd:string"/>
+ <xsd:element name="port" type="xsd:integer"/>
+ <xsd:element name="user" type="xsd:string"/>
+ <xsd:element name="virtual-host"type="xsd:string"/>
+
+</schema> \ No newline at end of file
diff --git a/java/management/client/etc/qman.log4j b/java/management/client/etc/qman.log4j
new file mode 100644
index 0000000000..bf6f940a6c
--- /dev/null
+++ b/java/management/client/etc/qman.log4j
@@ -0,0 +1,29 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+log4j.rootLogger=${root.logging.level}
+
+log4j.logger.org.apache.qpid=ERROR, console
+log4j.additivity.org.apache.qpid=false
+
+log4j.logger.org.apache.qpid.management.client=DEBUG, console
+
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.Threshold=error
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n
diff --git a/java/management/client/src/example/ConnectWithBroker.out.ok b/java/management/client/src/example/ConnectWithBroker.out.ok
new file mode 100644
index 0000000000..33af477b98
--- /dev/null
+++ b/java/management/client/src/example/ConnectWithBroker.out.ok
@@ -0,0 +1,81 @@
+ ConnectWithBrokerExample
+-------------------------------------------------------------------
+
+This example shows how to connect QMan with a broker using
+the adapter interface.
+
+Type enter to proceed...
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://romagazzarini:8080/qman/services/adapter</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://amqp.apache.org/qpid/management/qman/Connect</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:48bf9a1b-f814-7391-b5cf-d163de4ac068</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <qman:Connect xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <qman:host>sofia.gazzax.com</qman:host>
+ <qman:port>5672</qman:port>
+ <qman:username>test</qman:username>
+ <qman:password>a.gazzarini</qman:password>
+ <qman:virtualHost>p1ssw9rd</qman:virtualHost>
+ <qman:initialPoolCapacity>1</qman:initialPoolCapacity>
+ <qman:maxPoolCapacity>4</qman:maxPoolCapacity>
+ <qman:maxWaitTimeout>2000</qman:maxWaitTimeout>
+ </qman:Connect>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/fault</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:220bfe54-d5f4-4a04-794c-0f5d99a64567</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:48bf9a1b-f814-7391-b5cf-d163de4ac068</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://romagazzarini:8080/qman/services/adapter</wsa:Address>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <soap:Fault>
+ <soap:Code xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <soap:Value>qman:QMan</soap:Value>
+ </soap:Code>
+ <soap:Reason>
+ <soap:Text>Unable to connect with the requested broker. Underlying exception message was null</soap:Text>
+ </soap:Reason>
+ <soap:Detail>
+ <qman:OperationInvocationFault xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrf-bf:Timestamp xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2">2009-02-17T10:37:08+01:00</wsrf-bf:Timestamp>
+ <wsrf-bf:OriginatorReference xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2">
+ <wsa:ReferenceParameters xmlns:wsa="http://www.w3.org/2005/08/addressing"/>
+ <wsa:Address xmlns:wsa="http://www.w3.org/2005/08/addressing">http://romagazzarini:8080/qman/services/adapter</wsa:Address>
+ </wsrf-bf:OriginatorReference>
+ <qman:host>sofia.gazzax.com</qman:host>
+ <qman:port>5672</qman:port>
+ <qman:username>test</qman:username>
+ <qman:virtualHost>p1ssw9rd</qman:virtualHost>
+ </qman:OperationInvocationFault>
+ </soap:Detail>
+ </soap:Fault>
+ </soap:Body>
+</soap:Envelope>
+
+-----------------------EXAMPLE FAILURE-----------
+Not well-defined exception was detected while
+running the example.
+org.apache.muse.ws.addressing.soap.SoapFault: Unable to connect with the requested broker. Underlying exception message was null
+ at org.apache.muse.core.AbstractResourceClient.invoke(AbstractResourceClient.java:298)
+ at org.apache.muse.core.AbstractResourceClient.invoke(AbstractResourceClient.java:232)
+ at org.apache.muse.core.AbstractResourceClient.invoke(AbstractResourceClient.java:211)
+ at org.apache.qpid.management.example.ConnectWithBrokerExample.executeExample(ConnectWithBrokerExample.java:146)
+ at org.apache.qpid.management.example.ConnectWithBrokerExample.execute(ConnectWithBrokerExample.java:97)
+ at org.apache.qpid.management.example.ConnectWithBrokerExample.main(ConnectWithBrokerExample.java:201)
+--------------------------------------------------------
diff --git a/java/management/client/src/example/GetMultipleResourceProperties.out.ok b/java/management/client/src/example/GetMultipleResourceProperties.out.ok
new file mode 100644
index 0000000000..005841488d
--- /dev/null
+++ b/java/management/client/src/example/GetMultipleResourceProperties.out.ok
@@ -0,0 +1,262 @@
+ GetMultipleResourcePropertiesExample
+-------------------------------------------------------------------
+
+This example shows how to get properties from a
+WS-Resource using one request.
+First of all a request is send to WS-DM in order to get
+all registered WS-Resources.
+If the returned list is not empty then a GetMetadataRequest
+to the first child.
+The result metadata descriptor contains all property names of
+the target WS-Resource.
+Those names are then used for retrieving the corresponding values
+using the GetMultipleResourceProperties request.
+
+-------------------------------------------------------------------
+
+Type enter to proceed...
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/adapter</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:1a72feb1-7d76-1014-66d7-cd03aeff3525</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourceProperty
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:wsrf-sg="http://docs.oasis-open.org/wsrf/sg-2">wsrf-sg:Entry</wsrf-rp:GetResourceProperty>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:783956b1-4de7-f4b6-5421-536f5f310b9a</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:1a72feb1-7d76-1014-66d7-cd03aeff3525</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/adapter</wsa:Address>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <wsrf-sg:Entry xmlns:wsrf-sg="http://docs.oasis-open.org/wsrf/sg-2">
+ <wsrf-sg:ServiceGroupEntryEPR>
+ <wsa:Address xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/ServiceGroupEntry</wsa:Address>
+ <wsa:ReferenceParameters xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <muse-wsa:ResourceId xmlns:muse-wsa="http://ws.apache.org/muse/addressing">uuid:b220e2bd-0370-da4e-fc71-5e283954d319</muse-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsrf-sg:ServiceGroupEntryEPR>
+ <wsrf-sg:MemberServiceEPR>
+ <wsa:Address xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <qman-wsa:ResourceId xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsrf-sg:MemberServiceEPR>
+ <wsrf-sg:Content/>
+ </wsrf-sg:Entry>
+ </wsrf-rp:GetResourcePropertyResponse>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:588288c9-8bb7-04e9-e7bf-7be1e2fe41fb</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <qman:GetMetadata xmlns:qman="http://schemas.xmlsoap.org/ws/2004/09/mex">
+ <qman:Dialect>http://docs.oasis-open.org/wsrf/rmd-1</qman:Dialect>
+ </qman:GetMetadata>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadataResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:77c5520b-d450-5a8a-7e2b-22a1079392f2</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:588288c9-8bb7-04e9-e7bf-7be1e2fe41fb</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsx:Metadata xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex">
+ <wsx:MetadataSection>
+ <wsrmd:MetadataDescriptor
+ interface="qman:QManWsResourcePortType"
+ name="QManWsResourceMetadata"
+ wsdlLocation="http://docs.oasis-open.org/wsrf/rmd-1 QManWsResource.wsdl"
+ xmlns:qman="http://amqp.apache.org/qpid/management/qman" xmlns:wsrmd="http://docs.oasis-open.org/wsrf/rmd-1">
+ <wsrmd:Property modifiability="read-write"
+ mutability="mutable" name="qman:MgmtPubInterval" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="qman:Name" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="wsrl:TerminationTime" xmlns:wsrl="http://docs.oasis-open.org/wsrf/rl-2">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable"
+ name="qman:MsgTotalEnqueues" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="qman:Arguments" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="qman:VhostRef" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="wsrl:CurrentTime" xmlns:wsrl="http://docs.oasis-open.org/wsrf/rl-2">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-write"
+ mutability="mutable" name="qman:ExpireTime" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="qman:Durable" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="qman:ConsumerCount" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-write"
+ mutability="mutable" name="qman:Type" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ </wsrmd:MetadataDescriptor>
+ </wsx:MetadataSection>
+ </wsx:Metadata>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetMultipleResourceProperties/GetMultipleResourcePropertiesRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:783fc044-58a9-e780-a2ba-5b2ac0454985</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetMultipleResourceProperties xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <wsrf-rp:ResourceProperty xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:MgmtPubInterval</wsrf-rp:ResourceProperty>
+ <wsrf-rp:ResourceProperty xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:Name</wsrf-rp:ResourceProperty>
+ <wsrf-rp:ResourceProperty xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:MsgTotalEnqueues</wsrf-rp:ResourceProperty>
+ <wsrf-rp:ResourceProperty xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:Arguments</wsrf-rp:ResourceProperty>
+ <wsrf-rp:ResourceProperty xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:VhostRef</wsrf-rp:ResourceProperty>
+ <wsrf-rp:ResourceProperty xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:ExpireTime</wsrf-rp:ResourceProperty>
+ <wsrf-rp:ResourceProperty xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:Durable</wsrf-rp:ResourceProperty>
+ <wsrf-rp:ResourceProperty xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:ConsumerCount</wsrf-rp:ResourceProperty>
+ <wsrf-rp:ResourceProperty xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:Type</wsrf-rp:ResourceProperty>
+ </wsrf-rp:GetMultipleResourceProperties>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetMultipleResourceProperties/GetMultipleResourcePropertiesResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:9a2d76dd-52ba-ac7c-74cf-4acd99708529</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:783fc044-58a9-e780-a2ba-5b2ac0454985</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetMultipleResourcePropertiesResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <qman:MgmtPubInterval xmlns:qman="http://amqp.apache.org/qpid/management/qman">32767</qman:MgmtPubInterval>
+ <qman:Name xmlns:qman="http://amqp.apache.org/qpid/management/qman">Initial Name</qman:Name>
+ <qman:MsgTotalEnqueues xmlns:qman="http://amqp.apache.org/qpid/management/qman">9223372036854775797</qman:MsgTotalEnqueues>
+ <qman:Arguments
+ xmlns:qman="http://amqp.apache.org/qpid/management/qman" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <qman:entry>
+ <qman:key>Key3</qman:key>
+ <qman:value xsi:type="xsd:integer">2147483647</qman:value>
+ </qman:entry>
+ <qman:entry>
+ <qman:key>Key4</qman:key>
+ <qman:value xsi:type="xsd:float">3.4028235E38</qman:value>
+ </qman:entry>
+ <qman:entry>
+ <qman:key>Key1</qman:key>
+ <qman:value xsi:type="xsd:string">aStringValue</qman:value>
+ </qman:entry>
+ <qman:entry>
+ <qman:key>Key2</qman:key>
+ <qman:value xsi:type="xsd:long">-9223372036854775808</qman:value>
+ </qman:entry>
+ </qman:Arguments>
+ <qman:VhostRef xmlns:qman="http://amqp.apache.org/qpid/management/qman">2deef1b3-d2c6-49f3-a8de-51f6a75a1a6b</qman:VhostRef>
+ <qman:ExpireTime xmlns:qman="http://amqp.apache.org/qpid/management/qman">9223372036854775807</qman:ExpireTime>
+ <qman:Durable xmlns:qman="http://amqp.apache.org/qpid/management/qman">true</qman:Durable>
+ <qman:ConsumerCount xmlns:qman="http://amqp.apache.org/qpid/management/qman">-2147483638</qman:ConsumerCount>
+ </wsrf-rp:GetMultipleResourcePropertiesResponse>
+ </soap:Body>
+</soap:Envelope> \ No newline at end of file
diff --git a/java/management/client/src/example/GetQManResourceMembers.out.ko b/java/management/client/src/example/GetQManResourceMembers.out.ko
new file mode 100644
index 0000000000..d6b733e430
--- /dev/null
+++ b/java/management/client/src/example/GetQManResourceMembers.out.ko
@@ -0,0 +1,54 @@
+ GetQManResourceMembersExample Example
+-------------------------------------------------------------------
+
+This example shows the usage of WS-DM
+GetResourcePropertyRequest / Response on a
+Group service.
+The target resource is the WS-DM Adapter itself
+and the requested property is "ws-rp:Entry".
+WS-DM Adapter is a special WS-Resource (is a Group)
+that acts as the main entry point for retrieving
+all other managed resources.
+So clients that want to deal with QMan WS-Resources
+must first get resource identifiers sending
+a GetResourcePropertyRequest to WS-DM Adapter
+with "ws-rp:Entry" as target target property.
+
+-------------------------------------------------------------------
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://192.38.73.2:8080/qman/services/adapter</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:796bab33-ed59-3432-4e2c-1fadde465a25</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourceProperty
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:wsrf-sg="http://docs.oasis-open.org/wsrf/sg-2">wsrf-sg:Entry</wsrf-rp:GetResourceProperty>
+ </soap:Body>
+</soap:Envelope>
+
+-----------------------EXAMPLE FAILURE----------------------
+org.apache.muse.ws.addressing.soap.SoapFault: No route to host: connect
+ at org.apache.muse.core.AbstractResourceClient.invoke(AbstractResourceClient.java:298)
+ at org.apache.muse.core.AbstractResourceClient.invoke(AbstractResourceClient.java:254)
+ at org.apache.muse.ws.resource.remote.WsResourceClient.getResourceProperty(WsResourceClient.java:138)
+ at org.apache.muse.ws.resource.sg.remote.ServiceGroupClient.getMembers(ServiceGroupClient.java:110)
+ at org.apache.qpid.management.example.GetQManResourceMembersExample.execute(GetQManResourceMembersExample.java:61)
+ at org.apache.qpid.management.example.GetQManResourceMembersExample.main(GetQManResourceMembersExample.java:133)
+
+
+#########################################################################################
+
+WARNING! Unable to run this sample : port number must be a number.
+-------------------------------------------------------------
+Expected command line args for this sample are :
+
+1) host : ip or host name where QMan is running.
+2) port : port number where QMan is running.
+------------------------------------------------------------ \ No newline at end of file
diff --git a/java/management/client/src/example/GetQManResourceMembers.out.ok b/java/management/client/src/example/GetQManResourceMembers.out.ok
new file mode 100644
index 0000000000..dd75e1e490
--- /dev/null
+++ b/java/management/client/src/example/GetQManResourceMembers.out.ok
@@ -0,0 +1,55 @@
+ GetQManResourceMembersExample Example
+-------------------------------------------------------------------
+
+This example shows the usage of WS-DM
+GetResourcePropertyRequest / Response on a
+Group service.
+The target resource is the WS-DM Adapter itself
+and the requested property is "ws-rp:Entry".
+WS-DM Adapter is a special WS-Resource (is a Group)
+that acts as the main entry point for retrieving
+all other managed resources.
+So clients that want to deal with QMan WS-Resources
+must first get resource identifiers sending
+a GetResourcePropertyRequest to WS-DM Adapter
+with "ws-rp:Entry" as target target property.
+
+-------------------------------------------------------------------
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://romagazzarini:8080/qman/services/adapter</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:024c678b-1fab-cb6a-0992-30027817fb92</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourceProperty
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:wsrf-sg="http://docs.oasis-open.org/wsrf/sg-2">wsrf-sg:Entry</wsrf-rp:GetResourceProperty>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:90b0e421-6467-a72e-a8f4-cdedb80460b6</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:024c678b-1fab-cb6a-0992-30027817fb92</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://romagazzarini:8080/qman/services/adapter</wsa:Address>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2"/>
+ </soap:Body>
+</soap:Envelope>
+
+--------------------------------------------------------------------------
+QMan has at the moment 0 registered resources.
+-------------------------------------------------------------------------- \ No newline at end of file
diff --git a/java/management/client/src/example/GetResourceMetadataDescriptor.out.ok b/java/management/client/src/example/GetResourceMetadataDescriptor.out.ok
new file mode 100644
index 0000000000..a259259228
--- /dev/null
+++ b/java/management/client/src/example/GetResourceMetadataDescriptor.out.ok
@@ -0,0 +1,188 @@
+ GetResourceMetadataDescriptorExample
+-------------------------------------------------------------------
+
+The example shows how to get metadata from a
+WS-Resource.
+A QMan WS-Resource has different kinds of metadata.
+(see below)
+User who wants to receive metadata of a WS-Resource
+must send a GetMetadataRequesta specifying the
+associated dialect.
+Supported metadata that could be requested are :
+
+- WSDL : in this case dialect is "http://schemas.xmlsoap.org/wsdl/";
+- RDM (Resource Metadata Descriptor) : in this case dialect is "http://docs.oasis-open.org/wsrf/rmd-1 ".
+
+Note that this examples focuses on RDM Metadata only;
+another one is dedicated to WSDL.
+-------------------------------------------------------------------
+
+Type enter to proceed...
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/adapter</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:cdcf747a-e5fc-3762-1748-87cc2eefb18b</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourceProperty
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:wsrf-sg="http://docs.oasis-open.org/wsrf/sg-2">wsrf-sg:Entry</wsrf-rp:GetResourceProperty>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:1d0d091b-8867-d765-7cc8-4898851cd783</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:cdcf747a-e5fc-3762-1748-87cc2eefb18b</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/adapter</wsa:Address>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <wsrf-sg:Entry xmlns:wsrf-sg="http://docs.oasis-open.org/wsrf/sg-2">
+ <wsrf-sg:ServiceGroupEntryEPR>
+ <wsa:Address xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/ServiceGroupEntry</wsa:Address>
+ <wsa:ReferenceParameters xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <muse-wsa:ResourceId xmlns:muse-wsa="http://ws.apache.org/muse/addressing">uuid:3a2ee31e-49ed-e30a-c985-0fe49c182a75</muse-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsrf-sg:ServiceGroupEntryEPR>
+ <wsrf-sg:MemberServiceEPR>
+ <wsa:Address xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <qman-wsa:ResourceId xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=cbe0cada-e8ee-424c-945b-f6c42df7b011,class=queue,name=1232952196269,objectId=e2857418-b873-47b7-ab30-441ae9376529,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsrf-sg:MemberServiceEPR>
+ <wsrf-sg:Content/>
+ </wsrf-sg:Entry>
+ </wsrf-rp:GetResourcePropertyResponse>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:ba2435fc-9172-69d8-f4be-34f7f45b26ff</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=cbe0cada-e8ee-424c-945b-f6c42df7b011,class=queue,name=1232952196269,objectId=e2857418-b873-47b7-ab30-441ae9376529,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <qman:GetMetadata xmlns:qman="http://schemas.xmlsoap.org/ws/2004/09/mex">
+ <qman:Dialect>http://docs.oasis-open.org/wsrf/rmd-1</qman:Dialect>
+ </qman:GetMetadata>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadataResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:ceb6eb90-4910-01a9-c138-6029e6bb0836</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:ba2435fc-9172-69d8-f4be-34f7f45b26ff</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=cbe0cada-e8ee-424c-945b-f6c42df7b011,class=queue,name=1232952196269,objectId=e2857418-b873-47b7-ab30-441ae9376529,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsx:Metadata xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex">
+ <wsx:MetadataSection>
+ <wsrmd:MetadataDescriptor
+ interface="qman:QManWsResourcePortType"
+ name="QManWsResourceMetadata"
+ wsdlLocation="http://docs.oasis-open.org/wsrf/rmd-1 QManWsResource.wsdl"
+ xmlns:qman="http://amqp.apache.org/qpid/management/qman" xmlns:wsrmd="http://docs.oasis-open.org/wsrf/rmd-1">
+ <wsrmd:Property modifiability="read-write"
+ mutability="mutable" name="qman:MgmtPubInterval" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="qman:Name" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="wsrl:TerminationTime" xmlns:wsrl="http://docs.oasis-open.org/wsrf/rl-2">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable"
+ name="qman:MsgTotalEnqueues" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="qman:Arguments" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="qman:VhostRef" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="wsrl:CurrentTime" xmlns:wsrl="http://docs.oasis-open.org/wsrf/rl-2">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-write"
+ mutability="mutable" name="qman:ExpireTime" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="qman:Durable" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="qman:ConsumerCount" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-write"
+ mutability="mutable" name="qman:Type" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ </wsrmd:MetadataDescriptor>
+ </wsx:MetadataSection>
+ </wsx:Metadata>
+ </soap:Body>
+</soap:Envelope> \ No newline at end of file
diff --git a/java/management/client/src/example/GetResourcePropertyDocument.out.ok b/java/management/client/src/example/GetResourcePropertyDocument.out.ok
new file mode 100644
index 0000000000..9d6312f2f3
--- /dev/null
+++ b/java/management/client/src/example/GetResourcePropertyDocument.out.ok
@@ -0,0 +1,138 @@
+ GetResourcePropertyDocument
+-------------------------------------------------------------------
+
+This example shows how to get the whole property
+document from a WS-Resource.
+Resource property document represents a particular
+composed structural view of the resource properties
+of the WS-Resource.
+First of all a request is send to WS-DM in order to get
+all registered WS-Resources.
+the target WS-Resource.
+If the returned list is not empty then a
+GetResourcePropertyDocumentRequest is sent to the first child.
+
+-------------------------------------------------------------------
+
+Type enter to proceed...
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/adapter</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:50aa09f5-44e7-8bd3-7f24-49b8f0b9bf0d</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourceProperty
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:wsrf-sg="http://docs.oasis-open.org/wsrf/sg-2">wsrf-sg:Entry</wsrf-rp:GetResourceProperty>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:f71342ad-2185-fdb3-393a-e9a98305effd</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:50aa09f5-44e7-8bd3-7f24-49b8f0b9bf0d</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/adapter</wsa:Address>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <wsrf-sg:Entry xmlns:wsrf-sg="http://docs.oasis-open.org/wsrf/sg-2">
+ <wsrf-sg:ServiceGroupEntryEPR>
+ <wsa:Address xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/ServiceGroupEntry</wsa:Address>
+ <wsa:ReferenceParameters xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <muse-wsa:ResourceId xmlns:muse-wsa="http://ws.apache.org/muse/addressing">uuid:b220e2bd-0370-da4e-fc71-5e283954d319</muse-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsrf-sg:ServiceGroupEntryEPR>
+ <wsrf-sg:MemberServiceEPR>
+ <wsa:Address xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <qman-wsa:ResourceId xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsrf-sg:MemberServiceEPR>
+ <wsrf-sg:Content/>
+ </wsrf-sg:Entry>
+ </wsrf-rp:GetResourcePropertyResponse>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourcePropertyDocument/GetResourcePropertyDocumentRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:e035946b-c3f5-1b24-e94a-61c674ce07b9</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyDocument xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2"/>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourcePropertyDocument/GetResourcePropertyDocumentResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:dafe12e4-c0a9-f872-cf1e-2a41bc291b2e</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:e035946b-c3f5-1b24-e94a-61c674ce07b9</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyDocumentResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <qman:QManWsResourceProperties xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <qman:MgmtPubInterval>32767</qman:MgmtPubInterval>
+ <wsrf-rp:QueryExpressionDialect>http://www.w3.org/TR/1999/REC-xpath-19991116</wsrf-rp:QueryExpressionDialect>
+ <qman:Name>Initial Name</qman:Name>
+ <wsrf-rl:TerminationTime xmlns:wsrf-rl="http://docs.oasis-open.org/wsrf/rl-2"/>
+ <qman:MsgTotalEnqueues>9223372036854775797</qman:MsgTotalEnqueues>
+ <qman:Arguments xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <qman:entry>
+ <qman:key>Key3</qman:key>
+ <qman:value xsi:type="xsd:integer">2147483647</qman:value>
+ </qman:entry>
+ <qman:entry>
+ <qman:key>Key4</qman:key>
+ <qman:value xsi:type="xsd:float">3.4028235E38</qman:value>
+ </qman:entry>
+ <qman:entry>
+ <qman:key>Key1</qman:key>
+ <qman:value xsi:type="xsd:string">aStringValue</qman:value>
+ </qman:entry>
+ <qman:entry>
+ <qman:key>Key2</qman:key>
+ <qman:value xsi:type="xsd:long">-9223372036854775808</qman:value>
+ </qman:entry>
+ </qman:Arguments>
+ <qman:VhostRef>2deef1b3-d2c6-49f3-a8de-51f6a75a1a6b</qman:VhostRef>
+ <wsrf-rl:CurrentTime xmlns:wsrf-rl="http://docs.oasis-open.org/wsrf/rl-2">1232956293823</wsrf-rl:CurrentTime>
+ <qman:ExpireTime>9223372036854775807</qman:ExpireTime>
+ <qman:Durable>true</qman:Durable>
+ <qman:ConsumerCount>-2147483638</qman:ConsumerCount>
+ </qman:QManWsResourceProperties>
+ </wsrf-rp:GetResourcePropertyDocumentResponse>
+ </soap:Body>
+</soap:Envelope> \ No newline at end of file
diff --git a/java/management/client/src/example/GetResourcePropertyRequest.out.ok b/java/management/client/src/example/GetResourcePropertyRequest.out.ok
new file mode 100644
index 0000000000..4fa0ab3b8d
--- /dev/null
+++ b/java/management/client/src/example/GetResourcePropertyRequest.out.ok
@@ -0,0 +1,588 @@
+ GetResourcePropertyExample
+-------------------------------------------------------------------
+
+This example shows how to get the property value
+from a WS-Resource.
+First of all a request is send to WS-DM in order to get
+all registered WS-Resources.
+If the returned list is not empty then a GetMetadataRequest
+to the first child.
+The result metadata descriptor contains all properties of
+the target WS-Resource.
+For each of them a GetResourcePropertyRequest is sent
+ in order to get its value.
+
+-------------------------------------------------------------------
+
+Type enter to proceed...
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/adapter</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:e581b9cb-04a9-a87f-7763-dcf227ed7f8b</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourceProperty
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:wsrf-sg="http://docs.oasis-open.org/wsrf/sg-2">wsrf-sg:Entry</wsrf-rp:GetResourceProperty>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:27bab9a7-89aa-16a1-966b-c0aa19d3b352</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:e581b9cb-04a9-a87f-7763-dcf227ed7f8b</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/adapter</wsa:Address>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <wsrf-sg:Entry xmlns:wsrf-sg="http://docs.oasis-open.org/wsrf/sg-2">
+ <wsrf-sg:ServiceGroupEntryEPR>
+ <wsa:Address xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/ServiceGroupEntry</wsa:Address>
+ <wsa:ReferenceParameters xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <muse-wsa:ResourceId xmlns:muse-wsa="http://ws.apache.org/muse/addressing">uuid:b220e2bd-0370-da4e-fc71-5e283954d319</muse-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsrf-sg:ServiceGroupEntryEPR>
+ <wsrf-sg:MemberServiceEPR>
+ <wsa:Address xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <qman-wsa:ResourceId xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsrf-sg:MemberServiceEPR>
+ <wsrf-sg:Content/>
+ </wsrf-sg:Entry>
+ </wsrf-rp:GetResourcePropertyResponse>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:c5efae22-bc2f-ccdd-477c-621d4e49cd77</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <qman:GetMetadata xmlns:qman="http://schemas.xmlsoap.org/ws/2004/09/mex">
+ <qman:Dialect>http://docs.oasis-open.org/wsrf/rmd-1</qman:Dialect>
+ </qman:GetMetadata>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadataResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:4d933676-fb60-3fae-d7b9-39324a8661fc</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:c5efae22-bc2f-ccdd-477c-621d4e49cd77</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsx:Metadata xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex">
+ <wsx:MetadataSection>
+ <wsrmd:MetadataDescriptor
+ interface="qman:QManWsResourcePortType"
+ name="QManWsResourceMetadata"
+ wsdlLocation="http://docs.oasis-open.org/wsrf/rmd-1 QManWsResource.wsdl"
+ xmlns:qman="http://amqp.apache.org/qpid/management/qman" xmlns:wsrmd="http://docs.oasis-open.org/wsrf/rmd-1">
+ <wsrmd:Property modifiability="read-write"
+ mutability="mutable" name="qman:MgmtPubInterval" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="qman:Name" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="wsrl:TerminationTime" xmlns:wsrl="http://docs.oasis-open.org/wsrf/rl-2">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable"
+ name="qman:MsgTotalEnqueues" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="qman:Arguments" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="qman:VhostRef" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="wsrl:CurrentTime" xmlns:wsrl="http://docs.oasis-open.org/wsrf/rl-2">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-write"
+ mutability="mutable" name="qman:ExpireTime" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="qman:Durable" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="qman:ConsumerCount" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-write"
+ mutability="mutable" name="qman:Type" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ </wsrmd:MetadataDescriptor>
+ </wsx:MetadataSection>
+ </wsx:Metadata>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:83c13239-3e37-853d-776d-3dac2729117b</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourceProperty
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:MgmtPubInterval</wsrf-rp:GetResourceProperty>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:0beb3927-6420-9877-f163-4288ea1560da</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:83c13239-3e37-853d-776d-3dac2729117b</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <qman:MgmtPubInterval xmlns:qman="http://amqp.apache.org/qpid/management/qman">32767</qman:MgmtPubInterval>
+ </wsrf-rp:GetResourcePropertyResponse>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:30b678da-f1fa-8120-7660-9eb86ebb76b7</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourceProperty
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:Name</wsrf-rp:GetResourceProperty>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:8343b104-1a82-212a-c84a-460cbc223327</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:30b678da-f1fa-8120-7660-9eb86ebb76b7</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <qman:Name xmlns:qman="http://amqp.apache.org/qpid/management/qman">Initial Name</qman:Name>
+ </wsrf-rp:GetResourcePropertyResponse>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:795eaebd-dd48-75b0-18b3-a7e3c1fd4d5a</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourceProperty
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:MsgTotalEnqueues</wsrf-rp:GetResourceProperty>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:b6b91fd1-762b-3ae4-76c3-fe206c93b76d</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:795eaebd-dd48-75b0-18b3-a7e3c1fd4d5a</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <qman:MsgTotalEnqueues xmlns:qman="http://amqp.apache.org/qpid/management/qman">9223372036854775797</qman:MsgTotalEnqueues>
+ </wsrf-rp:GetResourcePropertyResponse>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:f57f0179-a31b-8607-668b-c2602838c363</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourceProperty
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:Arguments</wsrf-rp:GetResourceProperty>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:fc07cbe4-a19a-6374-c985-49fa525d3e90</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:f57f0179-a31b-8607-668b-c2602838c363</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <qman:Arguments
+ xmlns:qman="http://amqp.apache.org/qpid/management/qman" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <qman:entry>
+ <qman:key>Key3</qman:key>
+ <qman:value xsi:type="xsd:integer">2147483647</qman:value>
+ </qman:entry>
+ <qman:entry>
+ <qman:key>Key4</qman:key>
+ <qman:value xsi:type="xsd:float">3.4028235E38</qman:value>
+ </qman:entry>
+ <qman:entry>
+ <qman:key>Key1</qman:key>
+ <qman:value xsi:type="xsd:string">aStringValue</qman:value>
+ </qman:entry>
+ <qman:entry>
+ <qman:key>Key2</qman:key>
+ <qman:value xsi:type="xsd:long">-9223372036854775808</qman:value>
+ </qman:entry>
+ </qman:Arguments>
+ </wsrf-rp:GetResourcePropertyResponse>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:5d735040-95d1-7c87-7ac9-b4a5700e0ab9</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourceProperty
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:VhostRef</wsrf-rp:GetResourceProperty>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:cdfe639c-357b-d55b-fe7d-4a203d46465c</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:5d735040-95d1-7c87-7ac9-b4a5700e0ab9</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <qman:VhostRef xmlns:qman="http://amqp.apache.org/qpid/management/qman">2deef1b3-d2c6-49f3-a8de-51f6a75a1a6b</qman:VhostRef>
+ </wsrf-rp:GetResourcePropertyResponse>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:e3fde856-57f5-a96f-a382-5e0f4206a6fe</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourceProperty
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:ExpireTime</wsrf-rp:GetResourceProperty>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:fa290c54-bac1-62d6-701e-3b8ec2eaf817</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:e3fde856-57f5-a96f-a382-5e0f4206a6fe</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <qman:ExpireTime xmlns:qman="http://amqp.apache.org/qpid/management/qman">9223372036854775807</qman:ExpireTime>
+ </wsrf-rp:GetResourcePropertyResponse>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:092dd5d9-c443-428c-813c-13428058b08c</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourceProperty
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:Durable</wsrf-rp:GetResourceProperty>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:1053800e-345c-abed-e352-f524c1d24afa</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:092dd5d9-c443-428c-813c-13428058b08c</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <qman:Durable xmlns:qman="http://amqp.apache.org/qpid/management/qman">true</qman:Durable>
+ </wsrf-rp:GetResourcePropertyResponse>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:bc291be9-b1d1-f668-f3c5-29647e78d6bf</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourceProperty
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:ConsumerCount</wsrf-rp:GetResourceProperty>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:7467dddf-033e-f540-241f-76ce81c0ebeb</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:bc291be9-b1d1-f668-f3c5-29647e78d6bf</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <qman:ConsumerCount xmlns:qman="http://amqp.apache.org/qpid/management/qman">-2147483638</qman:ConsumerCount>
+ </wsrf-rp:GetResourcePropertyResponse>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:92783239-777c-27fa-cec2-ee3afecf5c32</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourceProperty
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:Type</wsrf-rp:GetResourceProperty>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:af8168b4-6c13-c736-b521-f2b410541dd0</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:92783239-777c-27fa-cec2-ee3afecf5c32</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=8e069b14-40ba-4d48-a2cb-b9f2bef2d404,class=queue,name=1232953394537,objectId=781f4ad7-4c96-4caa-b69d-291461cdb1fc,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2"/>
+ </soap:Body>
+</soap:Envelope> \ No newline at end of file
diff --git a/java/management/client/src/example/GetWsdlMetadata.out.ko.no.resources b/java/management/client/src/example/GetWsdlMetadata.out.ko.no.resources
new file mode 100644
index 0000000000..6e727261f9
--- /dev/null
+++ b/java/management/client/src/example/GetWsdlMetadata.out.ko.no.resources
@@ -0,0 +1,58 @@
+ GetWSDLMetadataExample
+-------------------------------------------------------------------
+
+This example shows the usage of WS-DM
+GetResourcePropertyRequest / Response on a
+Group service.
+The target resource is the WS-DM Adapter itself
+and the requested property is "ws-rp:Entry".
+WS-DM Adapter is a special WS-Resource (is a Group)
+that acts as the main entry point for retrieving
+all other managed resources.
+So clients that want to deal with QMan WS-Resources
+must first get resource identifiers sending
+a GetResourcePropertyRequest to WS-DM Adapter
+with "ws-rp:Entry" as target target property.
+
+-------------------------------------------------------------------
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/adapter</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:7f801eff-c528-91e8-33eb-3d1dd164bce7</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourceProperty
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:wsrf-sg="http://docs.oasis-open.org/wsrf/sg-2">wsrf-sg:Entry</wsrf-rp:GetResourceProperty>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:86a34968-38aa-83e8-47dd-8e86ffd8ac06</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:7f801eff-c528-91e8-33eb-3d1dd164bce7</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/adapter</wsa:Address>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2"/>
+ </soap:Body>
+</soap:Envelope>
+
+----------------------------WARNING---------------------------
+Cannot proceed with the example... it seems
+that there are no managed WS-Resources on QMan.
+Please check QMan in order to see that it is really
+connected with a broker.
+-------------------------------------------------------------------
diff --git a/java/management/client/src/example/GetWsdlMetadata.out.ok b/java/management/client/src/example/GetWsdlMetadata.out.ok
new file mode 100644
index 0000000000..16a4c1e07e
--- /dev/null
+++ b/java/management/client/src/example/GetWsdlMetadata.out.ok
@@ -0,0 +1,1968 @@
+ GetWSDLMetadataExample
+-------------------------------------------------------------------
+
+This example shows the usage of WS-DM
+GetResourcePropertyRequest / Response on a
+Group service.
+The target resource is the WS-DM Adapter itself
+and the requested property is "ws-rp:Entry".
+WS-DM Adapter is a special WS-Resource (is a Group)
+that acts as the main entry point for retrieving
+all other managed resources.
+So clients that want to deal with QMan WS-Resources
+must first get resource identifiers sending
+a GetResourcePropertyRequest to WS-DM Adapter
+with "ws-rp:Entry" as target target property.
+
+-------------------------------------------------------------------
+
+Type enter to proceed.
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/adapter</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:ec4d0c03-3174-e39d-4a36-8f109056865b</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourceProperty
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:wsrf-sg="http://docs.oasis-open.org/wsrf/sg-2">wsrf-sg:Entry</wsrf-rp:GetResourceProperty>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:0f47d614-565e-5360-8dcc-ea8e4771e4dd</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:ec4d0c03-3174-e39d-4a36-8f109056865b</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/adapter</wsa:Address>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <wsrf-sg:Entry xmlns:wsrf-sg="http://docs.oasis-open.org/wsrf/sg-2">
+ <wsrf-sg:ServiceGroupEntryEPR>
+ <wsa:Address xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/ServiceGroupEntry</wsa:Address>
+ <wsa:ReferenceParameters xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <muse-wsa:ResourceId xmlns:muse-wsa="http://ws.apache.org/muse/addressing">uuid:1d01b4ee-7d23-3a30-342e-62fc49984fe6</muse-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsrf-sg:ServiceGroupEntryEPR>
+ <wsrf-sg:MemberServiceEPR>
+ <wsa:Address xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <qman-wsa:ResourceId xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=d5b32f44-5164-4e59-8f1d-a6f8c0a8a748,class=queue,name=1232872843214,objectId=a3759467-bede-476d-8dde-169f1a652191,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsrf-sg:MemberServiceEPR>
+ <wsrf-sg:Content/>
+ </wsrf-sg:Entry>
+ </wsrf-rp:GetResourcePropertyResponse>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:0cdb5112-09e0-ac39-06ba-393843f06e42</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=d5b32f44-5164-4e59-8f1d-a6f8c0a8a748,class=queue,name=1232872843214,objectId=a3759467-bede-476d-8dde-169f1a652191,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <qman:GetMetadata xmlns:qman="http://schemas.xmlsoap.org/ws/2004/09/mex">
+ <qman:Dialect>http://schemas.xmlsoap.org/wsdl/</qman:Dialect>
+ </qman:GetMetadata>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadataResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:980617c8-e3a0-ebf1-8f5a-2b43d3d6d416</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:0cdb5112-09e0-ac39-06ba-393843f06e42</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=d5b32f44-5164-4e59-8f1d-a6f8c0a8a748,class=queue,name=1232872843214,objectId=a3759467-bede-476d-8dde-169f1a652191,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsx:Metadata xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex">
+ <wsx:MetadataSection>
+ <wsdl:definitions name="QManWsResource"
+ targetNamespace="http://amqp.apache.org/qpid/management/qman"
+ xmlns="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:qman="http://amqp.apache.org/qpid/management/qman"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:wsdl-soap="http://schemas.xmlsoap.org/wsdl/soap/"
+ xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
+ xmlns:wsrf-r="http://docs.oasis-open.org/wsrf/r-2"
+ xmlns:wsrf-rl="http://docs.oasis-open.org/wsrf/rl-2"
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2"
+ xmlns:wsrmd="http://docs.oasis-open.org/wsrf/rmd-1"
+ xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <wsdl:types>
+ <xsd:schema attributeFormDefault="unqualified"
+ elementFormDefault="qualified"
+ targetNamespace="http://www.w3.org/2005/08/addressing"
+ xmlns:tns="http://www.w3.org/2005/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:element name="EndpointReference"
+ type="tns:EndpointReferenceType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:complexType mixed="false"
+ name="EndpointReferenceType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:sequence>
+ <xs:element name="Address" type="tns:AttributedURIType"/>
+ <xs:element minOccurs="0"
+ name="ReferenceParameters" type="tns:ReferenceParametersType"/>
+ <xs:element minOccurs="0" ref="tns:Metadata"/>
+ <xs:any maxOccurs="unbounded"
+ minOccurs="0"
+ namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+ <xs:complexType mixed="false"
+ name="ReferenceParametersType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:sequence>
+ <xs:any maxOccurs="unbounded"
+ minOccurs="0" namespace="##any" processContents="lax"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+ <xs:element name="Metadata"
+ type="tns:MetadataType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:complexType mixed="false"
+ name="MetadataType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:sequence>
+ <xs:any maxOccurs="unbounded"
+ minOccurs="0" namespace="##any" processContents="lax"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+ <xs:element name="MessageID"
+ type="tns:AttributedURIType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:element name="RelatesTo"
+ type="tns:RelatesToType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:complexType mixed="false"
+ name="RelatesToType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:simpleContent>
+ <xs:extension base="xs:anyURI">
+ <xs:attribute
+ default="http://www.w3.org/2005/08/addressing/reply"
+ name="RelationshipType"
+ type="tns:RelationshipTypeOpenEnum" use="optional"/>
+ <xs:anyAttribute
+ namespace="##other" processContents="lax"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:simpleType
+ name="RelationshipTypeOpenEnum" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:union memberTypes="tns:RelationshipType xs:anyURI"/>
+ </xs:simpleType>
+ <xs:simpleType name="RelationshipType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:restriction base="xs:anyURI">
+ <xs:enumeration value="http://www.w3.org/2005/08/addressing/reply"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:element name="ReplyTo"
+ type="tns:EndpointReferenceType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:element name="From"
+ type="tns:EndpointReferenceType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:element name="FaultTo"
+ type="tns:EndpointReferenceType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:element name="To"
+ type="tns:AttributedURIType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:element name="Action"
+ type="tns:AttributedURIType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:complexType mixed="false"
+ name="AttributedURIType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:simpleContent>
+ <xs:extension base="xs:anyURI">
+ <xs:anyAttribute
+ namespace="##other" processContents="lax"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:attribute name="IsReferenceParameter"
+ type="xs:boolean" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:simpleType name="FaultCodesOpenEnumType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:union memberTypes="tns:FaultCodesType xs:QName"/>
+ </xs:simpleType>
+ <xs:simpleType name="FaultCodesType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:restriction base="xs:QName">
+ <xs:enumeration value="tns:InvalidAddressingHeader"/>
+ <xs:enumeration value="tns:InvalidAddress"/>
+ <xs:enumeration value="tns:InvalidEPR"/>
+ <xs:enumeration value="tns:InvalidCardinality"/>
+ <xs:enumeration value="tns:MissingAddressInEPR"/>
+ <xs:enumeration value="tns:DuplicateMessageID"/>
+ <xs:enumeration value="tns:ActionMismatch"/>
+ <xs:enumeration value="tns:MessageAddressingHeaderRequired"/>
+ <xs:enumeration value="tns:DestinationUnreachable"/>
+ <xs:enumeration value="tns:ActionNotSupported"/>
+ <xs:enumeration value="tns:EndpointUnavailable"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:element name="RetryAfter"
+ type="tns:AttributedUnsignedLongType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:complexType mixed="false"
+ name="AttributedUnsignedLongType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:simpleContent>
+ <xs:extension base="xs:unsignedLong">
+ <xs:anyAttribute
+ namespace="##other" processContents="lax"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:element name="ProblemHeaderQName"
+ type="tns:AttributedQNameType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:complexType mixed="false"
+ name="AttributedQNameType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:simpleContent>
+ <xs:extension base="xs:QName">
+ <xs:anyAttribute
+ namespace="##other" processContents="lax"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:element name="ProblemHeader"
+ type="tns:AttributedAnyType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:complexType mixed="false"
+ name="AttributedAnyType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:sequence>
+ <xs:any maxOccurs="1" minOccurs="1"
+ namespace="##any" processContents="lax"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+ <xs:element name="ProblemIRI"
+ type="tns:AttributedURIType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:element name="ProblemAction"
+ type="tns:ProblemActionType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:complexType mixed="false"
+ name="ProblemActionType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:sequence>
+ <xs:element minOccurs="0" ref="tns:Action"/>
+ <xs:element minOccurs="0"
+ name="SoapAction" type="xs:anyURI"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+ </xsd:schema>
+ <xsd:schema elementFormDefault="qualified"
+ targetNamespace="http://schemas.xmlsoap.org/ws/2004/09/mex"
+ xmlns:tns="http://schemas.xmlsoap.org/ws/2004/09/mex"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:import
+ namespace="http://www.w3.org/2005/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:element name="GetMetadata" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element minOccurs="0" ref="tns:Dialect"/>
+ <xs:element minOccurs="0" ref="tns:Identifier"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="Dialect" type="xs:anyURI" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:element name="Identifier"
+ type="xs:anyURI" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:element name="Metadata" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element
+ maxOccurs="unbounded"
+ minOccurs="0" ref="tns:MetadataSection"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="MetadataSection" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:complexType>
+ <xs:choice>
+ <xs:any maxOccurs="unbounded"
+ minOccurs="0"
+ namespace="##other" processContents="lax"/>
+ <xs:element ref="tns:MetadataReference"/>
+ <xs:element ref="tns:Location"/>
+ </xs:choice>
+ <xs:attribute name="Dialect"
+ type="xs:anyURI" use="required"/>
+ <xs:attribute name="Identifier" type="xs:anyURI"/>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="MetadataReference"
+ type="wsa:EndpointReferenceType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:element name="Location" type="xs:anyURI" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:complexType name="AnyXmlType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:sequence>
+ <xs:any namespace="##any" processContents="lax"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##any" processContents="lax"/>
+ </xs:complexType>
+ </xsd:schema>
+ <xsd:schema attributeFormDefault="unqualified"
+ elementFormDefault="qualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/rl-2"
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
+ xmlns:wsrf-rl="http://docs.oasis-open.org/wsrf/rl-2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/bf-2"/>
+ <xsd:element name="CurrentTime">
+ <xsd:complexType>
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:dateTime">
+ <xsd:anyAttribute
+ namespace="##other" processContents="lax"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="TerminationTime" nillable="true">
+ <xsd:complexType>
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:dateTime">
+ <xsd:anyAttribute
+ namespace="##other" processContents="lax"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="ScheduledResourceTerminationRP">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element maxOccurs="1"
+ minOccurs="1" ref="wsrf-rl:CurrentTime"/>
+ <xsd:element maxOccurs="1"
+ minOccurs="1" ref="wsrf-rl:TerminationTime"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="Destroy">
+ <xsd:complexType/>
+ </xsd:element>
+ <xsd:element name="DestroyResponse">
+ <xsd:complexType/>
+ </xsd:element>
+ <xsd:complexType name="ResourceNotDestroyedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="ResourceNotDestroyedFault" type="wsrf-rl:ResourceNotDestroyedFaultType"/>
+ <xsd:element name="SetTerminationTime">
+ <xsd:complexType>
+ <xsd:choice>
+ <xsd:element
+ name="RequestedTerminationTime"
+ nillable="true" type="xsd:dateTime"/>
+ <xsd:element
+ name="RequestedLifetimeDuration" type="xsd:duration"/>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="SetTerminationTimeResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element
+ name="NewTerminationTime"
+ nillable="true" type="xsd:dateTime"/>
+ <xsd:element name="CurrentTime" type="xsd:dateTime"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:complexType name="UnableToSetTerminationTimeFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="UnableToSetTerminationTimeFault" type="wsrf-rl:UnableToSetTerminationTimeFaultType"/>
+ <xsd:complexType name="TerminationTimeChangeRejectedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="TerminationTimeChangeRejectedFault" type="wsrf-rl:TerminationTimeChangeRejectedFaultType"/>
+ <xsd:element name="TerminationNotification">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element maxOccurs="1"
+ minOccurs="1"
+ name="TerminationTime"
+ nillable="true" type="xsd:dateTime"/>
+ <xsd:element maxOccurs="1"
+ minOccurs="0"
+ name="TerminationReason" type="xsd:anyType"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <xsd:schema attributeFormDefault="unqualified"
+ elementFormDefault="qualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/rp-2"
+ xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2" xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/bf-2"/>
+ <xsd:element name="QueryExpressionDialect" type="xsd:anyURI"/>
+ <xsd:element name="QueryExpressionRPDocument">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element
+ maxOccurs="unbounded"
+ minOccurs="0" ref="wsrf-rp:QueryExpressionDialect"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:attribute name="ResourceProperties" type="xsd:QName"/>
+ <xsd:complexType name="ResourcePropertyValueChangeNotificationType">
+ <xsd:sequence>
+ <xsd:element maxOccurs="1"
+ minOccurs="0" name="OldValues" nillable="true">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any
+ maxOccurs="unbounded" minOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element maxOccurs="1"
+ minOccurs="1" name="NewValues" nillable="true">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any
+ maxOccurs="unbounded" minOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element
+ name="ResourcePropertyValueChangeNotification" type="wsrf-rp:ResourcePropertyValueChangeNotificationType"/>
+ <xsd:complexType mixed="true" name="QueryExpressionType">
+ <xsd:sequence>
+ <xsd:any maxOccurs="1" minOccurs="0" processContents="lax"/>
+ </xsd:sequence>
+ <xsd:attribute name="Dialect" type="xsd:anyURI"/>
+ </xsd:complexType>
+ <xsd:element name="QueryExpression" type="wsrf-rp:QueryExpressionType"/>
+ <xsd:element name="GetResourcePropertyDocument">
+ <xsd:complexType/>
+ </xsd:element>
+ <xsd:element name="GetResourcePropertyDocumentResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any maxOccurs="1" minOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="GetResourceProperty" type="xsd:QName"/>
+ <xsd:element name="GetResourcePropertyResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any maxOccurs="unbounded" minOccurs="0"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:complexType name="InvalidResourcePropertyQNameFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="InvalidResourcePropertyQNameFault" type="wsrf-rp:InvalidResourcePropertyQNameFaultType"/>
+ <xsd:element name="GetMultipleResourceProperties">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element
+ maxOccurs="unbounded"
+ minOccurs="1"
+ name="ResourceProperty" type="xsd:QName"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="GetMultipleResourcePropertiesResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any maxOccurs="unbounded" minOccurs="0"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="PutResourcePropertyDocument">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any maxOccurs="1" minOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="PutResourcePropertyDocumentResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any maxOccurs="1" minOccurs="0"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:complexType name="ResourcePropertyChangeFailureType">
+ <xsd:sequence>
+ <xsd:element maxOccurs="1"
+ minOccurs="0" name="CurrentValue">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any
+ maxOccurs="unbounded" minOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element maxOccurs="1"
+ minOccurs="0" name="RequestedValue">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any
+ maxOccurs="unbounded" minOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:attribute name="Restored" type="xsd:boolean"/>
+ </xsd:complexType>
+ <xsd:complexType name="UnableToPutResourcePropertyDocumentFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element
+ name="ResourcePropertyChangeFailure" type="wsrf-rp:ResourcePropertyChangeFailureType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="UnableToPutResourcePropertyDocumentFault" type="wsrf-rp:UnableToPutResourcePropertyDocumentFaultType"/>
+ <xsd:complexType name="InsertType">
+ <xsd:sequence>
+ <xsd:any maxOccurs="unbounded"
+ minOccurs="1" processContents="lax"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="Insert" type="wsrf-rp:InsertType"/>
+ <xsd:complexType name="UpdateType">
+ <xsd:sequence>
+ <xsd:any maxOccurs="unbounded"
+ minOccurs="1" processContents="lax"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="Update" type="wsrf-rp:UpdateType"/>
+ <xsd:complexType name="DeleteType">
+ <xsd:attribute name="ResourceProperty"
+ type="xsd:QName" use="required"/>
+ </xsd:complexType>
+ <xsd:element name="Delete" type="wsrf-rp:DeleteType"/>
+ <xsd:element name="SetResourceProperties">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded" minOccurs="1">
+ <xsd:element ref="wsrf-rp:Insert"/>
+ <xsd:element ref="wsrf-rp:Update"/>
+ <xsd:element ref="wsrf-rp:Delete"/>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="SetResourcePropertiesResponse">
+ <xsd:complexType/>
+ </xsd:element>
+ <xsd:complexType name="InvalidModificationFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element
+ name="ResourcePropertyChangeFailure" type="wsrf-rp:ResourcePropertyChangeFailureType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="InvalidModificationFault" type="wsrf-rp:InvalidModificationFaultType"/>
+ <xsd:complexType name="UnableToModifyResourcePropertyFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element
+ name="ResourcePropertyChangeFailure" type="wsrf-rp:ResourcePropertyChangeFailureType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="UnableToModifyResourcePropertyFault" type="wsrf-rp:UnableToModifyResourcePropertyFaultType"/>
+ <xsd:complexType name="SetResourcePropertyRequestFailedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element
+ name="ResourcePropertyChangeFailure" type="wsrf-rp:ResourcePropertyChangeFailureType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="SetResourcePropertyRequestFailedFault" type="wsrf-rp:SetResourcePropertyRequestFailedFaultType"/>
+ <xsd:complexType name="InsertResourcePropertiesRequestFailedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element
+ name="ResourcePropertyChangeFailure" type="wsrf-rp:ResourcePropertyChangeFailureType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="InsertResourcePropertiesRequestFailedFault" type="wsrf-rp:InsertResourcePropertiesRequestFailedFaultType"/>
+ <xsd:complexType name="UpdateResourcePropertiesRequestFailedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element
+ name="ResourcePropertyChangeFailure" type="wsrf-rp:ResourcePropertyChangeFailureType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="UpdateResourcePropertiesRequestFailedFault" type="wsrf-rp:UpdateResourcePropertiesRequestFailedFaultType"/>
+ <xsd:complexType name="DeleteResourcePropertiesRequestFailedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element
+ name="ResourcePropertyChangeFailure" type="wsrf-rp:ResourcePropertyChangeFailureType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="DeleteResourcePropertiesRequestFailedFault" type="wsrf-rp:DeleteResourcePropertiesRequestFailedFaultType"/>
+ <xsd:element name="InsertResourceProperties">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsrf-rp:Insert"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="InsertResourcePropertiesResponse">
+ <xsd:complexType/>
+ </xsd:element>
+ <xsd:element name="UpdateResourceProperties">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsrf-rp:Update"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="UpdateResourcePropertiesResponse">
+ <xsd:complexType/>
+ </xsd:element>
+ <xsd:element name="DeleteResourceProperties">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsrf-rp:Delete"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="DeleteResourcePropertiesResponse">
+ <xsd:complexType/>
+ </xsd:element>
+ <xsd:element name="QueryResourceProperties">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element maxOccurs="1"
+ minOccurs="1" ref="wsrf-rp:QueryExpression"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="QueryResourcePropertiesResponse">
+ <xsd:complexType>
+ <xsd:complexContent mixed="true">
+ <xsd:restriction base="xsd:anyType">
+ <xsd:sequence>
+ <xsd:any
+ maxOccurs="unbounded"
+ minOccurs="1" processContents="lax"/>
+ </xsd:sequence>
+ </xsd:restriction>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:complexType name="UnknownQueryExpressionDialectFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="UnknownQueryExpressionDialectFault" type="wsrf-rp:UnknownQueryExpressionDialectFaultType"/>
+ <xsd:complexType name="InvalidQueryExpressionFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="InvalidQueryExpressionFault" type="wsrf-rp:InvalidQueryExpressionFaultType"/>
+ <xsd:complexType name="QueryEvaluationErrorFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="QueryEvaluationErrorFault" type="wsrf-rp:QueryEvaluationErrorFaultType"/>
+ </xsd:schema>
+ <xsd:schema attributeFormDefault="unqualified"
+ elementFormDefault="qualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/r-2"
+ xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
+ xmlns:wsrf-r="http://docs.oasis-open.org/wsrf/r-2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/bf-2"/>
+ <xsd:complexType name="ResourceUnknownFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="ResourceUnknownFault" type="wsrf-r:ResourceUnknownFaultType"/>
+ <xsd:complexType name="ResourceUnavailableFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="ResourceUnavailableFault" type="wsrf-r:ResourceUnavailableFaultType"/>
+ </xsd:schema>
+ <xsd:schema elementFormDefault="qualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/rmd-1"
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:wsrmd="http://docs.oasis-open.org/wsrf/rmd-1">
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/rp-2"/>
+ <xsd:import namespace="http://www.w3.org/2005/08/addressing"/>
+ <xsd:simpleType name="PairsOfURIType">
+ <xsd:list itemType="xsd:anyURI"/>
+ </xsd:simpleType>
+ <xsd:attribute name="Descriptor" type="xsd:QName"/>
+ <xsd:attribute name="DescriptorLocation" type="xsd:anyURI"/>
+ <xsd:complexType mixed="true" name="DocumentationType">
+ <xsd:sequence>
+ <xsd:any maxOccurs="unbounded"
+ minOccurs="0" namespace="##any" processContents="lax"/>
+ </xsd:sequence>
+ <xsd:anyAttribute/>
+ </xsd:complexType>
+ <xsd:complexType name="DocumentedType">
+ <xsd:sequence>
+ <xsd:element maxOccurs="1"
+ minOccurs="0"
+ name="documentation" type="wsrmd:DocumentationType"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="DefinitionsType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrmd:DocumentedType">
+ <xsd:sequence>
+ <xsd:element
+ maxOccurs="unbounded"
+ minOccurs="0" ref="wsrmd:MetadataDescriptor"/>
+ <xsd:any
+ maxOccurs="unbounded"
+ minOccurs="0"
+ namespace="##other" processContents="lax"/>
+ </xsd:sequence>
+ <xsd:attribute
+ name="targetNamespace"
+ type="xsd:anyURI" use="required"/>
+ <xsd:anyAttribute
+ namespace="##other" processContents="lax"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="Definitions" type="wsrmd:DefinitionsType">
+ <xsd:key name="MetadataDescriptor">
+ <xsd:annotation>
+ <xsd:documentation>
+ To form a QName, the name of any MetadataDescriptor must be
+ unique within a Definitions element.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:selector xpath="wsrmd:MetadataDescriptor"/>
+ <xsd:field xpath="@name"/>
+ </xsd:key>
+ </xsd:element>
+ <xsd:complexType name="MetadataDescriptorType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrmd:DocumentedType">
+ <xsd:sequence>
+ <xsd:element
+ maxOccurs="unbounded"
+ minOccurs="0" ref="wsrmd:Property"/>
+ <xsd:any
+ maxOccurs="unbounded"
+ minOccurs="0"
+ namespace="##other" processContents="lax"/>
+ </xsd:sequence>
+ <xsd:attribute name="name"
+ type="xsd:NCName" use="required"/>
+ <xsd:attribute name="interface"
+ type="xsd:QName" use="required"/>
+ <xsd:attribute
+ name="wsdlLocation" type="wsrmd:PairsOfURIType"/>
+ <xsd:anyAttribute
+ namespace="##other" processContents="lax"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="MetadataDescriptor" type="wsrmd:MetadataDescriptorType"/>
+ <xsd:complexType name="PropertyType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrmd:DocumentedType">
+ <xsd:sequence>
+ <xsd:choice>
+ <xsd:element
+ maxOccurs="1"
+ minOccurs="0" ref="wsrmd:ValidValues"/>
+ <xsd:element
+ maxOccurs="1"
+ minOccurs="0" ref="wsrmd:ValidValueRange"/>
+ </xsd:choice>
+ <xsd:element maxOccurs="1"
+ minOccurs="0" ref="wsrmd:StaticValues"/>
+ <xsd:any
+ maxOccurs="unbounded"
+ minOccurs="0"
+ namespace="##other" processContents="lax"/>
+ </xsd:sequence>
+ <xsd:attribute name="name"
+ type="xsd:QName" use="required"/>
+ <xsd:attribute name="mutability" type="wsrmd:MutabilityType"/>
+ <xsd:attribute
+ name="modifiability" type="wsrmd:ModifiabilityType"/>
+ <xsd:attribute default="false"
+ name="subscribability" type="xsd:boolean"/>
+ <xsd:anyAttribute
+ namespace="##other" processContents="lax"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="Property" type="wsrmd:PropertyType"/>
+ <xsd:simpleType name="MutabilityType">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="constant"/>
+ <xsd:enumeration value="appendable"/>
+ <xsd:enumeration value="mutable"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+ <xsd:simpleType name="ModifiabilityType">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="read-only"/>
+ <xsd:enumeration value="read-write"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+ <xsd:complexType mixed="true" name="ValidValuesType">
+ <xsd:sequence>
+ <xsd:element maxOccurs="1"
+ minOccurs="0"
+ name="documentation" type="wsrmd:DocumentationType"/>
+ <xsd:any maxOccurs="unbounded"
+ minOccurs="0"
+ namespace="##other" processContents="lax"/>
+ </xsd:sequence>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+ <xsd:element name="ValidValues" type="wsrmd:ValidValuesType"/>
+ <xsd:complexType mixed="true" name="ValidValueRangeType">
+ <xsd:sequence>
+ <xsd:element maxOccurs="1"
+ minOccurs="0"
+ name="documentation" type="wsrmd:DocumentationType"/>
+ <xsd:any maxOccurs="unbounded"
+ minOccurs="0"
+ namespace="##other" processContents="lax"/>
+ </xsd:sequence>
+ <xsd:attribute name="lowerBound" type="xsd:anySimpleType"/>
+ <xsd:attribute name="upperBound" type="xsd:anySimpleType"/>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+ <xsd:element name="ValidValueRange" type="wsrmd:ValidValueRangeType"/>
+ <xsd:complexType mixed="true" name="StaticValuesType">
+ <xsd:sequence>
+ <xsd:element maxOccurs="1"
+ minOccurs="0"
+ name="documentation" type="wsrmd:DocumentationType"/>
+ <xsd:any maxOccurs="unbounded"
+ minOccurs="0"
+ namespace="##other" processContents="lax"/>
+ </xsd:sequence>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+ <xsd:element name="StaticValues" type="wsrmd:StaticValuesType"/>
+ <xsd:complexType mixed="true" name="InitialValuesType">
+ <xsd:sequence>
+ <xsd:element maxOccurs="1"
+ minOccurs="0"
+ name="documentation" type="wsrmd:DocumentationType"/>
+ <xsd:any maxOccurs="unbounded"
+ minOccurs="0"
+ namespace="##other" processContents="lax"/>
+ </xsd:sequence>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+ <xsd:element name="InitialValues" type="wsrmd:InitialValuesType"/>
+ <xsd:complexType name="MetadataDescriptorReferenceType">
+ <xsd:complexContent>
+ <xsd:extension base="wsa:EndpointReferenceType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="MetadataDescriptorReference" type="wsrmd:MetadataDescriptorReferenceType"/>
+ <xsd:element name="MetadataResourceRP" type="wsrmd:DefinitionsType"/>
+ </xsd:schema>
+ <xsd:schema elementFormDefault="qualified" targetNamespace="http://amqp.apache.org/qpid/management/qman">
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/rl-2"/>
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/rp-2"/>
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/bf-2"/>
+ <xsd:element name="QManWsResourceProperties">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsrf-rl:CurrentTime"/>
+ <xsd:element ref="wsrf-rl:TerminationTime"/>
+ <xsd:element
+ maxOccurs="unbounded"
+ minOccurs="0" ref="wsrf-rp:QueryExpressionDialect"/>
+ <xsd:element ref="qman:Name"/>
+ <xsd:element ref="qman:Type"/>
+ <xsd:element ref="qman:Arguments"/>
+ <xsd:element ref="qman:VhostRef"/>
+ <xsd:element ref="qman:Durable"/>
+ <xsd:element ref="qman:MsgTotalEnqueues"/>
+ <xsd:element ref="qman:ConsumerCount"/>
+ <xsd:element ref="qman:ExpireTime"/>
+ <xsd:element ref="qman:MgmtPubInterval"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="QManFault">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="MethodInvocationFault">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="EntityInstanceNotFoundFault">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="MalformedEntityNameFault">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="NoSuchAttributeFault">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:complexType name="result">
+ <xsd:sequence>
+ <xsd:element name="statusCode" type="xsd:long"/>
+ <xsd:element name="statusText" type="xsd:string"/>
+ <xsd:complexType name="outputParameters">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element
+ maxOccurs="unbounded"
+ minOccurs="0" name="entry">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:name
+ name="key" type="xsd:string"/>
+ <xsd:element
+ name="value" type="xsd:anyType"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:complexType>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="Name" type="xsd:string"/>
+ <xsd:element name="Type" type="xsd:string"/>
+ <xsd:complexType name="map">
+ <xsd:sequence>
+ <xsd:element maxOccurs="unbounded"
+ minOccurs="0" name="entry">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="key" type="xsd:string"/>
+ <xsd:element
+ name="value" type="xsd:anyType"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="Arguments" type="qman:map"/>
+ <xsd:complexType name="uuid">
+ <xsd:sequence>
+ <xsd:element name="uuid" type="xsd:string"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="VhostRef" type="qman:uuid"/>
+ <xsd:element name="Durable" type="xsd:boolean"/>
+ <xsd:element name="MsgTotalEnqueues" type="xsd:long"/>
+ <xsd:element name="ConsumerCount" type="xsd:integer"/>
+ <xsd:element name="ExpireTime" type="xsd:dateTime"/>
+ <xsd:element name="MgmtPubInterval" type="xsd:short"/>
+ <xsd:element
+ name="echoWithSimpleTypesRequest" type="qman:echoWithSimpleTypesRequest"/>
+ <xsd:element
+ name="echoWithSimpleTypesResponse" type="qman:echoWithSimpleTypesResponse"/>
+ <xsd:complexType name="echoWithSimpleTypesRequest">
+ <xsd:sequence>
+ <xsd:element name="p1" type="xsd:long"/>
+ <xsd:element name="p2" type="xsd:boolean"/>
+ <xsd:element name="p3" type="xsd:double"/>
+ <xsd:element name="p4" type="xsd:float"/>
+ <xsd:element name="p5" type="xsd:integer"/>
+ <xsd:element name="p6" type="xsd:short"/>
+ <xsd:element name="p7" type="xsd:string"/>
+ <xsd:element name="p8" type="xsd:anyURI"/>
+ <xsd:element name="p9" type="xsd:dateTime"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="echoWithSimpleTypesResponse">
+ <xsd:sequence>
+ <xsd:element name="result" type="qman:result"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="echoWithArraysRequest" type="qman:echoWithArraysRequest"/>
+ <xsd:element name="echoWithArraysResponse" type="qman:echoWithArraysResponse"/>
+ <xsd:complexType name="arrayOfLong">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:long"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfBoolean">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:boolean"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfDouble">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:double"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfFloat">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:float"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfInteger">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:integer"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfShort">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:short"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfString">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:string"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfURI">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:anyURI"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfDate">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:dateTime"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="echoWithArraysRequest">
+ <xsd:sequence>
+ <xsd:element name="p1" type="qman:arrayOfLong"/>
+ <xsd:element name="p2" type="qman:arrayOfBoolean"/>
+ <xsd:element name="p3" type="qman:arrayOfDouble"/>
+ <xsd:element name="p4" type="qman:arrayOfFloat"/>
+ <xsd:element name="p5" type="qman:arrayOfInteger"/>
+ <xsd:element name="p6" type="qman:arrayOfShort"/>
+ <xsd:element name="p7" type="qman:arrayOfString"/>
+ <xsd:element name="p8" type="qman:arrayOfURI"/>
+ <xsd:element name="p9" type="qman:arrayOfDate"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="echoWithArraysResponse">
+ <xsd:sequence>
+ <xsd:element name="result" type="qman:result"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element
+ name="echoWithSimpleTypeArraysRequest" type="qman:echoWithSimpleTypeArraysRequest"/>
+ <xsd:element
+ name="echoWithSimpleTypeArraysResponse" type="qman:echoWithSimpleTypeArraysResponse"/>
+ <xsd:complexType name="arrayOfLong">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:long"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfBoolean">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:boolean"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfDouble">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:double"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfFloat">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:float"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfInt">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:integer"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfShort">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:short"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="echoWithSimpleTypeArraysRequest">
+ <xsd:sequence>
+ <xsd:element name="p1" type="qman:arrayOfLong"/>
+ <xsd:element name="p2" type="qman:arrayOfBoolean"/>
+ <xsd:element name="p3" type="qman:arrayOfDouble"/>
+ <xsd:element name="p4" type="qman:arrayOfFloat"/>
+ <xsd:element name="p5" type="qman:arrayOfInt"/>
+ <xsd:element name="p6" type="qman:arrayOfShort"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="echoWithSimpleTypeArraysResponse">
+ <xsd:sequence>
+ <xsd:element name="result" type="qman:result"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="echoWithByteArrayRequest" type="qman:echoWithByteArrayRequest"/>
+ <xsd:element
+ name="echoWithByteArrayResponse" type="qman:echoWithByteArrayResponse"/>
+ <xsd:complexType name="arrayOfByte">
+ <xsd:sequence>
+ <xsd:element name="entry" type=""/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="echoWithByteArrayRequest">
+ <xsd:sequence>
+ <xsd:element name="p1" type="qman:arrayOfByte"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="echoWithByteArrayResponse">
+ <xsd:sequence>
+ <xsd:element name="result" type="qman:result"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element
+ name="voidWithoutArgumentsRequest" type="qman:voidWithoutArgumentsRequest"/>
+ <xsd:element
+ name="voidWithoutArgumentsResponse" type="qman:voidWithoutArgumentsResponse"/>
+ <xsd:complexType name="voidWithoutArgumentsRequest">
+ <xsd:sequence/>
+ </xsd:complexType>
+ <xsd:complexType name="voidWithoutArgumentsResponse">
+ <xsd:sequence>
+ <xsd:element name="result" type="qman:result"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="throwsExceptionRequest" type="qman:throwsExceptionRequest"/>
+ <xsd:element name="throwsExceptionResponse" type="qman:throwsExceptionResponse"/>
+ <xsd:complexType name="throwsExceptionRequest">
+ <xsd:sequence/>
+ </xsd:complexType>
+ <xsd:complexType name="throwsExceptionResponse">
+ <xsd:sequence>
+ <xsd:element name="result" type="qman:result"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="echoWithUUIDRequest" type="qman:echoWithUUIDRequest"/>
+ <xsd:element name="echoWithUUIDResponse" type="qman:echoWithUUIDResponse"/>
+ <xsd:complexType name="echoWithUUIDRequest">
+ <xsd:sequence>
+ <xsd:element name="p1" type="qman:uuid"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="echoWithUUIDResponse">
+ <xsd:sequence>
+ <xsd:element name="result" type="qman:result"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="echoWithMapRequest" type="qman:echoWithMapRequest"/>
+ <xsd:element name="echoWithMapResponse" type="qman:echoWithMapResponse"/>
+ <xsd:complexType name="echoWithMapRequest">
+ <xsd:sequence>
+ <xsd:element name="p1" type="qman:map"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="echoWithMapResponse">
+ <xsd:sequence>
+ <xsd:element name="result" type="qman:result"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:schema>
+ <xsd:schema attributeFormDefault="unqualified"
+ elementFormDefault="qualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/bf-2"
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <xsd:import namespace="http://www.w3.org/2005/08/addressing"/>
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace">
+ <xsd:annotation>
+ <xsd:documentation>
+ Get access to the xml: attribute groups for xml:lang as declared on 'schema'
+ and 'documentation' below
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:import>
+ <xsd:element name="BaseFault" type="wsrf-bf:BaseFaultType"/>
+ <xsd:complexType name="BaseFaultType">
+ <xsd:sequence>
+ <xsd:any maxOccurs="unbounded"
+ minOccurs="0"
+ namespace="##other" processContents="lax"/>
+ <xsd:element maxOccurs="1"
+ minOccurs="1" name="Timestamp" type="xsd:dateTime"/>
+ <xsd:element maxOccurs="1"
+ minOccurs="0" name="Originator" type="wsa:EndpointReferenceType"/>
+ <xsd:element maxOccurs="1"
+ minOccurs="0" name="ErrorCode">
+ <xsd:complexType>
+ <xsd:complexContent mixed="true">
+ <xsd:extension base="xsd:anyType">
+ <xsd:attribute
+ name="dialect"
+ type="xsd:anyURI" use="required"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element maxOccurs="unbounded"
+ minOccurs="0" name="Description">
+ <xsd:complexType>
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute
+ ref="xml:lang" use="optional"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element maxOccurs="1"
+ minOccurs="0" name="FaultCause">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any maxOccurs="1"
+ minOccurs="1"
+ namespace="##other" processContents="lax"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+ </xsd:schema>
+ <xs:schema
+ targetNamespace="http://www.w3.org/XML/1998/namespace"
+ xml:lang="en" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:attribute name="lang" type="xs:language"/>
+ <xs:attribute default="preserve" name="space">
+ <xs:simpleType>
+ <xs:restriction base="xs:NCName">
+ <xs:enumeration value="default"/>
+ <xs:enumeration value="preserve"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="base" type="xs:anyURI"/>
+ <xs:attributeGroup name="specialAttrs">
+ <xs:attribute ref="xml:base"/>
+ <xs:attribute ref="xml:lang"/>
+ <xs:attribute ref="xml:space"/>
+ </xs:attributeGroup>
+ </xs:schema>
+ </wsdl:types>
+ <wsdl:message name="GetMetadataMsg">
+ <wsdl:part element="wsx:GetMetadata" name="GetMetadataMsg"/>
+ </wsdl:message>
+ <wsdl:message name="GetMetadataResponseMsg">
+ <wsdl:part element="wsx:Metadata" name="GetMetadataResponseMsg"/>
+ </wsdl:message>
+ <wsdl:message name="DestroyRequest">
+ <wsdl:part element="wsrf-rl:Destroy" name="DestroyRequest"/>
+ </wsdl:message>
+ <wsdl:message name="DestroyResponse">
+ <wsdl:part element="wsrf-rl:DestroyResponse" name="DestroyResponse"/>
+ </wsdl:message>
+ <wsdl:message name="ResourceNotDestroyedFault">
+ <wsdl:part
+ element="wsrf-rl:ResourceNotDestroyedFault" name="ResourceNotDestroyedFault"/>
+ </wsdl:message>
+ <wsdl:message name="ResourceUnknownFault">
+ <wsdl:part element="wsrf-r:ResourceUnknownFault" name="ResourceUnknownFault"/>
+ </wsdl:message>
+ <wsdl:message name="ResourceUnavailableFault">
+ <wsdl:part
+ element="wsrf-r:ResourceUnavailableFault" name="ResourceUnavailableFault"/>
+ </wsdl:message>
+ <wsdl:message name="SetTerminationTimeRequest">
+ <wsdl:part element="wsrf-rl:SetTerminationTime" name="SetTerminationTimeRequest"/>
+ </wsdl:message>
+ <wsdl:message name="SetTerminationTimeResponse">
+ <wsdl:part
+ element="wsrf-rl:SetTerminationTimeResponse" name="SetTerminationTimeResponse"/>
+ </wsdl:message>
+ <wsdl:message name="UnableToSetTerminationTimeFault">
+ <wsdl:part
+ element="wsrf-rl:UnableToSetTerminationTimeFault" name="UnableToSetTerminationTimeFault"/>
+ </wsdl:message>
+ <wsdl:message name="TerminationTimeChangeRejectedFault">
+ <wsdl:part
+ element="wsrf-rl:TerminationTimeChangeRejectedFault" name="TerminationTimeChangeRejectedFault"/>
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyDocumentRequest">
+ <wsdl:part
+ element="wsrf-rp:GetResourcePropertyDocument" name="GetResourcePropertyDocumentRequest"/>
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyDocumentResponse">
+ <wsdl:part
+ element="wsrf-rp:GetResourcePropertyDocumentResponse" name="GetResourcePropertyDocumentResponse"/>
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyRequest">
+ <wsdl:part element="wsrf-rp:GetResourceProperty" name="GetResourcePropertyRequest"/>
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyResponse">
+ <wsdl:part
+ element="wsrf-rp:GetResourcePropertyResponse" name="GetResourcePropertyResponse"/>
+ </wsdl:message>
+ <wsdl:message name="InvalidResourcePropertyQNameFault">
+ <wsdl:part
+ element="wsrf-rp:InvalidResourcePropertyQNameFault" name="InvalidResourcePropertyQNameFault"/>
+ </wsdl:message>
+ <wsdl:message name="GetMultipleResourcePropertiesRequest">
+ <wsdl:part
+ element="wsrf-rp:GetMultipleResourceProperties" name="GetMultipleResourcePropertiesRequest"/>
+ </wsdl:message>
+ <wsdl:message name="GetMultipleResourcePropertiesResponse">
+ <wsdl:part
+ element="wsrf-rp:GetMultipleResourcePropertiesResponse" name="GetMultipleResourcePropertiesResponse"/>
+ </wsdl:message>
+ <wsdl:message name="QueryResourcePropertiesRequest">
+ <wsdl:part
+ element="wsrf-rp:QueryResourceProperties" name="QueryResourcePropertiesRequest"/>
+ </wsdl:message>
+ <wsdl:message name="QueryResourcePropertiesResponse">
+ <wsdl:part
+ element="wsrf-rp:QueryResourcePropertiesResponse" name="QueryResourcePropertiesResponse"/>
+ </wsdl:message>
+ <wsdl:message name="UnknownQueryExpressionDialectFault">
+ <wsdl:part
+ element="wsrf-rp:UnknownQueryExpressionDialectFault" name="UnknownQueryExpressionDialectFault"/>
+ </wsdl:message>
+ <wsdl:message name="InvalidQueryExpressionFault">
+ <wsdl:part
+ element="wsrf-rp:InvalidQueryExpressionFault" name="InvalidQueryExpressionFault"/>
+ </wsdl:message>
+ <wsdl:message name="QueryEvaluationErrorFault">
+ <wsdl:part
+ element="wsrf-rp:QueryEvaluationErrorFault" name="QueryEvaluationErrorFault"/>
+ </wsdl:message>
+ <wsdl:message name="SetResourcePropertiesRequest">
+ <wsdl:part
+ element="wsrf-rp:SetResourceProperties" name="SetResourcePropertiesRequest"/>
+ </wsdl:message>
+ <wsdl:message name="SetResourcePropertiesResponse">
+ <wsdl:part
+ element="wsrf-rp:SetResourcePropertiesResponse" name="SetResourcePropertiesResponse"/>
+ </wsdl:message>
+ <wsdl:message name="InvalidModificationFault">
+ <wsdl:part
+ element="wsrf-rp:InvalidModificationFault" name="InvalidModificationFault"/>
+ </wsdl:message>
+ <wsdl:message name="UnableToModifyResourcePropertyFault">
+ <wsdl:part
+ element="wsrf-rp:UnableToModifyResourcePropertyFault" name="UnableToModifyResourcePropertyFault"/>
+ </wsdl:message>
+ <wsdl:message name="SetResourcePropertyRequestFailedFault">
+ <wsdl:part
+ element="wsrf-rp:SetResourcePropertyRequestFailedFault" name="SetResourcePropertyRequestFailedFault"/>
+ </wsdl:message>
+ <wsdl:portType name="QManWsResourcePortType"
+ wsrf-rp:ResourceProperties="qman:QManWsResourceProperties"
+ wsrmd:Descriptor="QManWsResourceMetadata" wsrmd:DescriptorLocation="QManWsResource.rmd">
+ <wsdl:operation name="GetMetadata">
+ <wsdl:input message="qman:GetMetadataMsg"
+ name="GetMetadataMsg" wsa:Action="http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata"/>
+ <wsdl:output
+ message="qman:GetMetadataResponseMsg"
+ name="GetMetadataResponseMsg" wsa:Action="http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadataResponse"/>
+ </wsdl:operation>
+ <wsdl:operation name="Destroy">
+ <wsdl:input message="qman:DestroyRequest"
+ name="DestroyRequest" wsa:Action="http://docs.oasis-open.org/wsrf/rlw-2/ImmediateResourceTermination/DestroyRequest"/>
+ <wsdl:output message="qman:DestroyResponse"
+ name="DestroyResponse" wsa:Action="http://docs.oasis-open.org/wsrf/rlw-2/ImmediateResourceTermination/DestroyResponse"/>
+ <wsdl:fault
+ message="qman:ResourceNotDestroyedFault" name="ResourceNotDestroyedFault"/>
+ <wsdl:fault
+ message="qman:ResourceUnknownFault" name="ResourceUnknownFault"/>
+ <wsdl:fault
+ message="qman:ResourceUnavailableFault" name="ResourceUnavailableFault"/>
+ </wsdl:operation>
+ <wsdl:operation name="SetTerminationTime">
+ <wsdl:input
+ message="qman:SetTerminationTimeRequest"
+ name="SetTerminationTimeRequest" wsa:Action="http://docs.oasis-open.org/wsrf/rlw-2/ScheduledResourceTermination/SetTerminationTimeRequest"/>
+ <wsdl:output
+ message="qman:SetTerminationTimeResponse"
+ name="SetTerminationTimeResponse" wsa:Action="http://docs.oasis-open.org/wsrf/rlw-2/ScheduledResourceTermination/SetTerminationTimeResponse"/>
+ <wsdl:fault
+ message="qman:UnableToSetTerminationTimeFault" name="UnableToSetTerminationTimeFault"/>
+ <wsdl:fault
+ message="qman:ResourceUnknownFault" name="ResourceUnknownFault"/>
+ <wsdl:fault
+ message="qman:ResourceUnavailableFault" name="ResourceUnavailableFault"/>
+ <wsdl:fault
+ message="qman:TerminationTimeChangeRejectedFault" name="TerminationTimeChangeRejectedFault"/>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourcePropertyDocument">
+ <wsdl:input
+ message="qman:GetResourcePropertyDocumentRequest"
+ name="GetResourcePropertyDocumentRequest" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourcePropertyDocument/GetResourcePropertyDocumentRequest"/>
+ <wsdl:output
+ message="qman:GetResourcePropertyDocumentResponse"
+ name="GetResourcePropertyDocumentResponse" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourcePropertyDocument/GetResourcePropertyDocumentResponse"/>
+ <wsdl:fault
+ message="qman:ResourceUnknownFault" name="ResourceUnknownFault"/>
+ <wsdl:fault
+ message="qman:ResourceUnavailableFault" name="ResourceUnavailableFault"/>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourceProperty">
+ <wsdl:input
+ message="qman:GetResourcePropertyRequest"
+ name="GetResourcePropertyRequest" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest"/>
+ <wsdl:output
+ message="qman:GetResourcePropertyResponse"
+ name="GetResourcePropertyResponse" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse"/>
+ <wsdl:fault
+ message="qman:ResourceUnknownFault" name="ResourceUnknownFault"/>
+ <wsdl:fault
+ message="qman:ResourceUnavailableFault" name="ResourceUnavailableFault"/>
+ <wsdl:fault
+ message="qman:InvalidResourcePropertyQNameFault" name="InvalidResourcePropertyQNameFault"/>
+ </wsdl:operation>
+ <wsdl:operation name="GetMultipleResourceProperties">
+ <wsdl:input
+ message="qman:GetMultipleResourcePropertiesRequest"
+ name="GetMultipleResourcePropertiesRequest" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetMultipleResourceProperties/GetMultipleResourcePropertiesRequest"/>
+ <wsdl:output
+ message="qman:GetMultipleResourcePropertiesResponse"
+ name="GetMultipleResourcePropertiesResponse" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetMultipleResourceProperties/GetMultipleResourcePropertiesResponse"/>
+ <wsdl:fault
+ message="qman:ResourceUnknownFault" name="ResourceUnknownFault"/>
+ <wsdl:fault
+ message="qman:ResourceUnavailableFault" name="ResourceUnavailableFault"/>
+ <wsdl:fault
+ message="qman:InvalidResourcePropertyQNameFault" name="InvalidResourcePropertyQNameFault"/>
+ </wsdl:operation>
+ <wsdl:operation name="QueryResourceProperties">
+ <wsdl:input
+ message="qman:QueryResourcePropertiesRequest"
+ name="QueryResourcePropertiesRequest" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/QueryResourceProperties/QueryResourcePropertiesRequest"/>
+ <wsdl:output
+ message="qman:QueryResourcePropertiesResponse"
+ name="QueryResourcePropertiesResponse" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/QueryResourceProperties/QueryResourcePropertiesResponse"/>
+ <wsdl:fault
+ message="qman:ResourceUnknownFault" name="ResourceUnknownFault"/>
+ <wsdl:fault
+ message="qman:ResourceUnavailableFault" name="ResourceUnavailableFault"/>
+ <wsdl:fault
+ message="qman:UnknownQueryExpressionDialectFault" name="UnknownQueryExpressionDialectFault"/>
+ <wsdl:fault
+ message="qman:InvalidQueryExpressionFault" name="InvalidQueryExpressionFault"/>
+ <wsdl:fault
+ message="qman:QueryEvaluationErrorFault" name="QueryEvaluationErrorFault"/>
+ </wsdl:operation>
+ <wsdl:operation name="SetResourceProperties">
+ <wsdl:input
+ message="qman:SetResourcePropertiesRequest"
+ name="SetResourcePropertiesRequest" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/SetResourceProperties/SetResourcePropertiesRequest"/>
+ <wsdl:output
+ message="qman:SetResourcePropertiesResponse"
+ name="SetResourcePropertiesResponse" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/SetResourceProperties/SetResourcePropertiesResponse"/>
+ <wsdl:fault
+ message="qman:ResourceUnknownFault" name="ResourceUnknownFault"/>
+ <wsdl:fault
+ message="qman:ResourceUnavailableFault" name="ResourceUnavailableFault"/>
+ <wsdl:fault
+ message="qman:InvalidModificationFault" name="InvalidModificationFault"/>
+ <wsdl:fault
+ message="qman:UnableToModifyResourcePropertyFault" name="UnableToModifyResourcePropertyFault"/>
+ <wsdl:fault
+ message="qman:InvalidResourcePropertyQNameFault" name="InvalidResourcePropertyQNameFault"/>
+ <wsdl:fault
+ message="qman:SetResourcePropertyRequestFailedFault" name="SetResourcePropertyRequestFailedFault"/>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithSimpleTypes">
+ <wsdl:input
+ message="qman:echoWithSimpleTypesRequestMessage"
+ name="echoWithSimpleTypesRequest" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithSimpleTypes"/>
+ <wsdl:output
+ message="qman:echoWithSimpleTypesResponseMessage"
+ name="echoWithSimpleTypesResponse" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithSimpleTypesResponse"/>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithArrays">
+ <wsdl:input
+ message="qman:echoWithArraysRequestMessage"
+ name="echoWithArraysRequest" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithArrays"/>
+ <wsdl:output
+ message="qman:echoWithArraysResponseMessage"
+ name="echoWithArraysResponse" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithArraysResponse"/>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithSimpleTypeArrays">
+ <wsdl:input
+ message="qman:echoWithSimpleTypeArraysRequestMessage"
+ name="echoWithSimpleTypeArraysRequest" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithSimpleTypeArrays"/>
+ <wsdl:output
+ message="qman:echoWithSimpleTypeArraysResponseMessage"
+ name="echoWithSimpleTypeArraysResponse" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithSimpleTypeArraysResponse"/>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithByteArray">
+ <wsdl:input
+ message="qman:echoWithByteArrayRequestMessage"
+ name="echoWithByteArrayRequest" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithByteArray"/>
+ <wsdl:output
+ message="qman:echoWithByteArrayResponseMessage"
+ name="echoWithByteArrayResponse" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithByteArrayResponse"/>
+ </wsdl:operation>
+ <wsdl:operation name="voidWithoutArguments">
+ <wsdl:input
+ message="qman:voidWithoutArgumentsRequestMessage"
+ name="voidWithoutArgumentsRequest" wsa:action="http://amqp.apache.org/qpid/management/qman/voidWithoutArguments"/>
+ <wsdl:output
+ message="qman:voidWithoutArgumentsResponseMessage"
+ name="voidWithoutArgumentsResponse" wsa:action="http://amqp.apache.org/qpid/management/qman/voidWithoutArgumentsResponse"/>
+ </wsdl:operation>
+ <wsdl:operation name="throwsException">
+ <wsdl:input
+ message="qman:throwsExceptionRequestMessage"
+ name="throwsExceptionRequest" wsa:action="http://amqp.apache.org/qpid/management/qman/throwsException"/>
+ <wsdl:output
+ message="qman:throwsExceptionResponseMessage"
+ name="throwsExceptionResponse" wsa:action="http://amqp.apache.org/qpid/management/qman/throwsExceptionResponse"/>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithUUID">
+ <wsdl:input
+ message="qman:echoWithUUIDRequestMessage"
+ name="echoWithUUIDRequest" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithUUID"/>
+ <wsdl:output
+ message="qman:echoWithUUIDResponseMessage"
+ name="echoWithUUIDResponse" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithUUIDResponse"/>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithMap">
+ <wsdl:input
+ message="qman:echoWithMapRequestMessage"
+ name="echoWithMapRequest" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithMap"/>
+ <wsdl:output
+ message="qman:echoWithMapResponseMessage"
+ name="echoWithMapResponse" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithMapResponse"/>
+ </wsdl:operation>
+ </wsdl:portType>
+ <wsdl:binding name="QManWsResourceBinding" type="qman:QManWsResourcePortType">
+ <wsdl-soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
+ <wsdl:operation name="GetMetadata">
+ <wsdl-soap:operation soapAction="GetMetadata"/>
+ <wsdl:input>
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="Destroy">
+ <wsdl-soap:operation soapAction="Destroy"/>
+ <wsdl:input name="DestroyRequest">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:input>
+ <wsdl:output name="DestroyResponse">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceNotDestroyedFault">
+ <wsdl-soap:fault
+ name="ResourceNotDestroyedFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ name="ResourceUnknownFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ name="ResourceUnavailableFault" use="literal"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="SetTerminationTime">
+ <wsdl-soap:operation soapAction="SetTerminationTime"/>
+ <wsdl:input name="SetTerminationTimeRequest">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:input>
+ <wsdl:output name="SetTerminationTimeResponse">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:output>
+ <wsdl:fault name="UnableToSetTerminationTimeFault">
+ <wsdl-soap:fault
+ name="UnableToSetTerminationTimeFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ name="ResourceUnknownFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ name="ResourceUnavailableFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="TerminationTimeChangeRejectedFault">
+ <wsdl-soap:fault
+ name="TerminationTimeChangeRejectedFault" use="literal"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourcePropertyDocument">
+ <wsdl-soap:operation soapAction="GetResourcePropertyDocument"/>
+ <wsdl:input name="GetResourcePropertyDocumentRequest">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:input>
+ <wsdl:output name="GetResourcePropertyDocumentResponse">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ name="ResourceUnknownFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ name="ResourceUnavailableFault" use="literal"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourceProperty">
+ <wsdl-soap:operation soapAction="GetResourceProperty"/>
+ <wsdl:input name="GetResourcePropertyRequest">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:input>
+ <wsdl:output name="GetResourcePropertyResponse">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ name="ResourceUnknownFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ name="ResourceUnavailableFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault">
+ <wsdl-soap:fault
+ name="InvalidResourcePropertyQNameFault" use="literal"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="GetMultipleResourceProperties">
+ <wsdl-soap:operation soapAction="GetMultipleResourceProperties"/>
+ <wsdl:input name="GetMultipleResourcePropertiesRequest">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:input>
+ <wsdl:output name="GetMultipleResourcePropertiesResponse">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ name="ResourceUnknownFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ name="ResourceUnavailableFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault">
+ <wsdl-soap:fault
+ name="InvalidResourcePropertyQNameFault" use="literal"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="QueryResourceProperties">
+ <wsdl-soap:operation soapAction="QueryResourceProperties"/>
+ <wsdl:input name="QueryResourcePropertiesRequest">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:input>
+ <wsdl:output name="QueryResourcePropertiesResponse">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ name="ResourceUnknownFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ name="ResourceUnavailableFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="UnknownQueryExpressionDialectFault">
+ <wsdl-soap:fault
+ name="UnknownQueryExpressionDialectFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidQueryExpressionFault">
+ <wsdl-soap:fault
+ name="InvalidQueryExpressionFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="QueryEvaluationErrorFault">
+ <wsdl-soap:fault
+ name="QueryEvaluationErrorFault" use="literal"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="SetResourceProperties">
+ <wsdl-soap:operation soapAction="http://oasis.org/SetResourceProperties"/>
+ <wsdl:input name="SetResourcePropertiesRequest">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:input>
+ <wsdl:output name="SetResourcePropertiesResponse">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ name="ResourceUnknownFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ name="ResourceUnavailableFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidModificationFault">
+ <wsdl-soap:fault
+ name="InvalidModificationFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="UnableToModifyResourcePropertyFault">
+ <wsdl-soap:fault
+ name="UnableToModifyResourcePropertyFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault">
+ <wsdl-soap:fault
+ name="InvalidResourcePropertyQNameFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="SetResourcePropertyRequestFailedFault">
+ <wsdl-soap:fault
+ name="SetResourcePropertyRequestFailedFault" use="literal"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="GetMetadata">
+ <wsdl-soap:operation soapAction="http://ws.apache.org/muse/test/wsrf/GetMetadata"/>
+ <wsdl:input name="GetMetadataMsg">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:input>
+ <wsdl:output name="GetMetadataResponseMsg">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithSimpleTypes">
+ <wsdl-soap:operation soapAction="http://amqp.apache.org/qpid/management/qman/echoWithSimpleTypes"/>
+ <wsdl:input>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithArrays">
+ <wsdl-soap:operation soapAction="http://amqp.apache.org/qpid/management/qman/echoWithArrays"/>
+ <wsdl:input>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithSimpleTypeArrays">
+ <wsdl-soap:operation soapAction="http://amqp.apache.org/qpid/management/qman/echoWithSimpleTypeArrays"/>
+ <wsdl:input>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithByteArray">
+ <wsdl-soap:operation soapAction="http://amqp.apache.org/qpid/management/qman/echoWithByteArray"/>
+ <wsdl:input>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="voidWithoutArguments">
+ <wsdl-soap:operation soapAction="http://amqp.apache.org/qpid/management/qman/voidWithoutArguments"/>
+ <wsdl:input>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="throwsException">
+ <wsdl-soap:operation soapAction="http://amqp.apache.org/qpid/management/qman/throwsException"/>
+ <wsdl:input>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithUUID">
+ <wsdl-soap:operation soapAction="http://amqp.apache.org/qpid/management/qman/echoWithUUID"/>
+ <wsdl:input>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithMap">
+ <wsdl-soap:operation soapAction="http://amqp.apache.org/qpid/management/qman/echoWithMap"/>
+ <wsdl:input>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ </wsdl:binding>
+ <wsdl:service name="QManWsResourceService">
+ <wsdl:port binding="qman:QManWsResourceBinding" name="QManWsResourcePort">
+ <wsdl-soap:address location="http://romagazzarini:8080/qman/services/QManWsResource"/>
+ </wsdl:port>
+ </wsdl:service>
+ <message name="echoWithSimpleTypesRequestMessage">
+ <wsdl:part
+ element="qman:echoWithSimpleTypesRequest" name="echoWithSimpleTypesRequest"/>
+ </message>
+ <wsdl:message name="echoWithSimpleTypesResponseMessage">
+ <wsdl:part
+ element="qman:echoWithSimpleTypesResponse" name="echoWithSimpleTypesResponse"/>
+ </wsdl:message>
+ <message name="echoWithArraysRequestMessage">
+ <wsdl:part element="qman:echoWithArraysRequest" name="echoWithArraysRequest"/>
+ </message>
+ <wsdl:message name="echoWithArraysResponseMessage">
+ <wsdl:part element="qman:echoWithArraysResponse" name="echoWithArraysResponse"/>
+ </wsdl:message>
+ <message name="echoWithSimpleTypeArraysRequestMessage">
+ <wsdl:part
+ element="qman:echoWithSimpleTypeArraysRequest" name="echoWithSimpleTypeArraysRequest"/>
+ </message>
+ <wsdl:message name="echoWithSimpleTypeArraysResponseMessage">
+ <wsdl:part
+ element="qman:echoWithSimpleTypeArraysResponse" name="echoWithSimpleTypeArraysResponse"/>
+ </wsdl:message>
+ <message name="echoWithByteArrayRequestMessage">
+ <wsdl:part
+ element="qman:echoWithByteArrayRequest" name="echoWithByteArrayRequest"/>
+ </message>
+ <wsdl:message name="echoWithByteArrayResponseMessage">
+ <wsdl:part
+ element="qman:echoWithByteArrayResponse" name="echoWithByteArrayResponse"/>
+ </wsdl:message>
+ <message name="voidWithoutArgumentsRequestMessage">
+ <wsdl:part
+ element="qman:voidWithoutArgumentsRequest" name="voidWithoutArgumentsRequest"/>
+ </message>
+ <wsdl:message name="voidWithoutArgumentsResponseMessage">
+ <wsdl:part
+ element="qman:voidWithoutArgumentsResponse" name="voidWithoutArgumentsResponse"/>
+ </wsdl:message>
+ <message name="throwsExceptionRequestMessage">
+ <wsdl:part element="qman:throwsExceptionRequest" name="throwsExceptionRequest"/>
+ </message>
+ <wsdl:message name="throwsExceptionResponseMessage">
+ <wsdl:part
+ element="qman:throwsExceptionResponse" name="throwsExceptionResponse"/>
+ </wsdl:message>
+ <message name="echoWithUUIDRequestMessage">
+ <wsdl:part element="qman:echoWithUUIDRequest" name="echoWithUUIDRequest"/>
+ </message>
+ <wsdl:message name="echoWithUUIDResponseMessage">
+ <wsdl:part element="qman:echoWithUUIDResponse" name="echoWithUUIDResponse"/>
+ </wsdl:message>
+ <message name="echoWithMapRequestMessage">
+ <wsdl:part element="qman:echoWithMapRequest" name="echoWithMapRequest"/>
+ </message>
+ <wsdl:message name="echoWithMapResponseMessage">
+ <wsdl:part element="qman:echoWithMapResponse" name="echoWithMapResponse"/>
+ </wsdl:message>
+ </wsdl:definitions>
+ </wsx:MetadataSection>
+ </wsx:Metadata>
+ </soap:Body>
+</soap:Envelope> \ No newline at end of file
diff --git a/java/management/client/src/example/PauseAndResumeSubscription.out.ok b/java/management/client/src/example/PauseAndResumeSubscription.out.ok
new file mode 100644
index 0000000000..8a98e1d0b7
--- /dev/null
+++ b/java/management/client/src/example/PauseAndResumeSubscription.out.ok
@@ -0,0 +1,133 @@
+This example is demonstrating a WS-Notification scenario
+when (for simplicity) QMan is at the same time consumer
+and producer.
+
+Specifically the example shows how a requestor can create,
+pause and resume a subscription.
+Type enter to proceed...
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://romagazzarini:8080/qman/services/adapter</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsn/bw-2/NotificationProducer/SubscribeRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:485cc87c-660e-de43-e8fa-4ad5fffa95a6</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsnt:Subscribe xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2">
+ <wsnt:ConsumerReference>
+ <wsa:Address xmlns:wsa="http://www.w3.org/2005/08/addressing">http://romagazzarini:8080/qman/services/consumer</wsa:Address>
+ </wsnt:ConsumerReference>
+ </wsnt:Subscribe>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsn/bw-2/NotificationProducer/SubscribeResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:0ee610d1-e211-95c6-a498-e1084a610c44</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:485cc87c-660e-de43-e8fa-4ad5fffa95a6</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://romagazzarini:8080/qman/services/adapter</wsa:Address>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsnt:SubscribeResponse xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2">
+ <wsnt:SubscriptionReference>
+ <wsa:Address xmlns:wsa="http://www.w3.org/2005/08/addressing">http://romagazzarini:8080/qman/services/SubscriptionManager</wsa:Address>
+ <wsa:ReferenceParameters xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <qman-wsa:ResourceId xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">282f28e6-4396-4000-a19d-87a03978e8a0</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsnt:SubscriptionReference>
+ <wsnt:CurrentTime>2009-02-27T13:51:56+01:00</wsnt:CurrentTime>
+ </wsnt:SubscribeResponse>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://romagazzarini:8080/qman/services/SubscriptionManager</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsn/bw-2/SubscriptionManager/PauseSubscriptionRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:35cc80af-84ac-2456-3e1f-edc2a7f60970</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">282f28e6-4396-4000-a19d-87a03978e8a0</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <wsnt:PauseSubscription xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2"/>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsn/bw-2/SubscriptionManager/PauseSubscriptionResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:bb53d38a-428c-3d90-cc45-29d5cb27a8df</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:35cc80af-84ac-2456-3e1f-edc2a7f60970</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://romagazzarini:8080/qman/services/SubscriptionManager</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">282f28e6-4396-4000-a19d-87a03978e8a0</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <muse-op:PauseSubscriptionResponse xmlns:muse-op="http://docs.oasis-open.org/wsn/b-2"/>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://romagazzarini:8080/qman/services/SubscriptionManager</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsn/bw-2/SubscriptionManager/ResumeSubscriptionRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:bfb48615-905a-e472-a9ca-5483fa592f60</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">282f28e6-4396-4000-a19d-87a03978e8a0</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <wsnt:ResumeSubscription xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2"/>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsn/bw-2/SubscriptionManager/ResumeSubscriptionResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:aab4cf18-3cc0-30c4-7036-009e26bb3213</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:bfb48615-905a-e472-a9ca-5483fa592f60</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://romagazzarini:8080/qman/services/SubscriptionManager</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">282f28e6-4396-4000-a19d-87a03978e8a0</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <muse-op:ResumeSubscriptionResponse xmlns:muse-op="http://docs.oasis-open.org/wsn/b-2"/>
+ </soap:Body>
+</soap:Envelope>
+
diff --git a/java/management/client/src/example/README b/java/management/client/src/example/README
new file mode 100644
index 0000000000..5365a416e5
--- /dev/null
+++ b/java/management/client/src/example/README
@@ -0,0 +1,69 @@
+*** QMan WS-DM examples ***
+
+1) DESCRIPTION
+This set of examples shows QMan WS-DM interface capabilities.
+Each example is articulated in the following way.
+First the name of the example class with a brief description about that is printed out. For example :
+
+ GetWSDLMetadataExample
+-------------------------------------------------------------------
+
+This example shows the usage of WS-DM
+GetResourcePropertyRequest / Response on a
+Group service.
+The target resource is the WS-DM Adapter itself
+and the requested property is "ws-rp:Entry".
+WS-DM Adapter is a special WS-Resource (is a Group)
+that acts as the main entry point for retrieving
+all other managed resources.
+So clients that want to deal with QMan WS-Resources
+must first get resource identifiers sending
+a GetResourcePropertyRequest to WS-DM Adapter
+with "ws-rp:Entry" as target target property.
+
+-------------------------------------------------------------------
+
+Type enter to proceed.
+
+When you're ready type enter to proceed. Now the example runs and all the exchanged
+SOAP messages are printed out on the screen.
+If you want, we shipped (under sample_messages folder) several files containing those messages.
+
+A general note concerning examples...they are all written using java language so what you see is the
+"java" usage of WS-DM client API.
+The most important thing that you should keep in mind is that what is expected (on QMan side) is a SOAP WS-DM
+compliant message so on top of that you don't need to use those java API but feel free to produce those messages
+in your preferred way (by hand or using another programming language).
+
+Another thing : the examples contain a lot of code duplication because each of them is took as independent as possible.
+The general idea is that you open an example source file and in the executeExample(...) method you should have a quick
+idea of how things are working.
+Also, as mentioned before, we provided, under the sample_messages folder, the messages that are part of each example conversation.
+Remember : these messages are important, not the way / language you use to produce them.
+
+2) HOW TO RUN
+
+2.1) Java
+You need JDK 1.5 or higher in order to run and / or compile the examples.
+
+2.2) Dependencies
+You need to set / update the CLASSPATH environment variable with libraries found under $QMAN_HOME/app/qman/WEB-INF/lib.
+After that you should be able to run one the shipped examples:
+
+> java org.apache.qpid.management.example.GetMultipleResourcePropertiesExample <qman_host> <qman_port>
+> java org.apache.qpid.management.example.GetQManResourceMembersExample <qman_host> <qman_port>
+> java org.apache.qpid.management.example.GetResourceMetadataDescriptorExample <qman_host> <qman_port>
+> java org.apache.qpid.management.example.GetResourcePropertyDocumentExample <qman_host> <qman_port>
+> java org.apache.qpid.management.example.GetResourcePropertyExample <qman_host> <qman_port>
+> java org.apache.qpid.management.example.GetWSDLMetadataExample <qman_host> <qman_port>
+> java org.apache.qpid.management.example.SetResourcePropertyExample <qman_host> <qman_port>
+
+Where
+<qman_host> is the host (ip or hostname) where QMan is running;
+<qman_port> is the port number where QMan is running;
+
+2.3) Qpid
+You must have a running C++ broker with management enabled.
+
+2.4) QMan
+You must have QMan WS-DM up, running and connected with the broker above. \ No newline at end of file
diff --git a/java/management/client/src/example/SetResourcePropertiesRequest.out.ok b/java/management/client/src/example/SetResourcePropertiesRequest.out.ok
new file mode 100644
index 0000000000..1f346afa4e
--- /dev/null
+++ b/java/management/client/src/example/SetResourcePropertiesRequest.out.ok
@@ -0,0 +1,2316 @@
+ SetResourcePropertyExample
+-------------------------------------------------------------------
+
+This example shows how to change the state of a WS-Resource.
+That means a SetResourcePropertyRequest is sent to that
+WS-Resource.
+First of all a request is send to WS-DM in order to get all
+registered WS-Resources.
+If the returned list is not empty then two GetMetadataRequests
+(one for WSDL and one for RDM) are sent to the first child.
+The result metadata descriptors are used for determine :
+
+1) WS-Resource property names;
+2) Modifiability (read-only, read-write
+3) Datatype;
+-------------------------------------------------------------------
+
+So a SetResourcePropertyRequest can be sent in order
+to change the WS-Resource state.
+The example is looking for a property that has one of the
+following datatype :
+
+1) String (xsd:string)
+2) Long (xsd:long)
+3) Integer (xsd:integer or xsd:int)
+4) Double (xsd:double)
+5) Float (xsd:float)
+6) Short (xsd:short)
+
+After the update / insert request has been sent, a
+GetResourcePropertiesRequest is made again
+in order to see if the state has changed correctly.
+
+Type enter to proceed...
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:d026718c-2724-d3bf-fd5b-3c6bf4cd5a8c</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=0ef67394-e34a-4bff-b0bf-88cf359ba1a0,class=queue,name=1232966356552,objectId=894cddd3-b893-4e2f-94d2-2489f72cbdd6,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <qman:GetMetadata xmlns:qman="http://schemas.xmlsoap.org/ws/2004/09/mex">
+ <qman:Dialect>http://docs.oasis-open.org/wsrf/rmd-1</qman:Dialect>
+ </qman:GetMetadata>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadataResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:dba8d7ab-83a6-16e1-03cc-48edc672a325</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:d026718c-2724-d3bf-fd5b-3c6bf4cd5a8c</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=0ef67394-e34a-4bff-b0bf-88cf359ba1a0,class=queue,name=1232966356552,objectId=894cddd3-b893-4e2f-94d2-2489f72cbdd6,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsx:Metadata xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex">
+ <wsx:MetadataSection>
+ <wsrmd:MetadataDescriptor
+ interface="qman:QManWsResourcePortType"
+ name="QManWsResourceMetadata"
+ wsdlLocation="http://docs.oasis-open.org/wsrf/rmd-1 QManWsResource.wsdl"
+ xmlns:qman="http://amqp.apache.org/qpid/management/qman" xmlns:wsrmd="http://docs.oasis-open.org/wsrf/rmd-1">
+ <wsrmd:Property modifiability="read-write"
+ mutability="mutable" name="qman:MgmtPubInterval" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="qman:Name" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="wsrl:TerminationTime" xmlns:wsrl="http://docs.oasis-open.org/wsrf/rl-2">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable"
+ name="qman:MsgTotalEnqueues" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="qman:Arguments" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="qman:VhostRef" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="wsrl:CurrentTime" xmlns:wsrl="http://docs.oasis-open.org/wsrf/rl-2">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-write"
+ mutability="mutable" name="qman:ExpireTime" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="qman:Durable" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-only"
+ mutability="mutable" name="qman:ConsumerCount" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ <wsrmd:Property modifiability="read-write"
+ mutability="mutable" name="qman:Type" xmlns:qman="http://amqp.apache.org/qpid/management/qman">
+ <wsrmd:ValidValues/>
+ <wsrmd:StaticValues/>
+ <wsrmd:InitialValues/>
+ </wsrmd:Property>
+ </wsrmd:MetadataDescriptor>
+ </wsx:MetadataSection>
+ </wsx:Metadata>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:11581af1-04af-05cd-7215-103cad6a316c</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=0ef67394-e34a-4bff-b0bf-88cf359ba1a0,class=queue,name=1232966356552,objectId=894cddd3-b893-4e2f-94d2-2489f72cbdd6,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <qman:GetMetadata xmlns:qman="http://schemas.xmlsoap.org/ws/2004/09/mex">
+ <qman:Dialect>http://schemas.xmlsoap.org/wsdl/</qman:Dialect>
+ </qman:GetMetadata>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadataResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:785964d4-9a81-784f-d68a-60de63223094</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:11581af1-04af-05cd-7215-103cad6a316c</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=0ef67394-e34a-4bff-b0bf-88cf359ba1a0,class=queue,name=1232966356552,objectId=894cddd3-b893-4e2f-94d2-2489f72cbdd6,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsx:Metadata xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex">
+ <wsx:MetadataSection>
+ <wsdl:definitions name="QManWsResource"
+ targetNamespace="http://amqp.apache.org/qpid/management/qman"
+ xmlns="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:qman="http://amqp.apache.org/qpid/management/qman"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:wsdl-soap="http://schemas.xmlsoap.org/wsdl/soap/"
+ xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
+ xmlns:wsrf-r="http://docs.oasis-open.org/wsrf/r-2"
+ xmlns:wsrf-rl="http://docs.oasis-open.org/wsrf/rl-2"
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2"
+ xmlns:wsrmd="http://docs.oasis-open.org/wsrf/rmd-1"
+ xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <wsdl:types>
+ <xsd:schema attributeFormDefault="unqualified"
+ elementFormDefault="qualified"
+ targetNamespace="http://www.w3.org/2005/08/addressing"
+ xmlns:tns="http://www.w3.org/2005/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:element name="EndpointReference"
+ type="tns:EndpointReferenceType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:complexType mixed="false"
+ name="EndpointReferenceType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:sequence>
+ <xs:element name="Address" type="tns:AttributedURIType"/>
+ <xs:element minOccurs="0"
+ name="ReferenceParameters" type="tns:ReferenceParametersType"/>
+ <xs:element minOccurs="0" ref="tns:Metadata"/>
+ <xs:any maxOccurs="unbounded"
+ minOccurs="0"
+ namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+ <xs:complexType mixed="false"
+ name="ReferenceParametersType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:sequence>
+ <xs:any maxOccurs="unbounded"
+ minOccurs="0" namespace="##any" processContents="lax"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+ <xs:element name="Metadata"
+ type="tns:MetadataType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:complexType mixed="false"
+ name="MetadataType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:sequence>
+ <xs:any maxOccurs="unbounded"
+ minOccurs="0" namespace="##any" processContents="lax"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+ <xs:element name="MessageID"
+ type="tns:AttributedURIType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:element name="RelatesTo"
+ type="tns:RelatesToType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:complexType mixed="false"
+ name="RelatesToType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:simpleContent>
+ <xs:extension base="xs:anyURI">
+ <xs:attribute
+ default="http://www.w3.org/2005/08/addressing/reply"
+ name="RelationshipType"
+ type="tns:RelationshipTypeOpenEnum" use="optional"/>
+ <xs:anyAttribute
+ namespace="##other" processContents="lax"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:simpleType
+ name="RelationshipTypeOpenEnum" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:union memberTypes="tns:RelationshipType xs:anyURI"/>
+ </xs:simpleType>
+ <xs:simpleType name="RelationshipType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:restriction base="xs:anyURI">
+ <xs:enumeration value="http://www.w3.org/2005/08/addressing/reply"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:element name="ReplyTo"
+ type="tns:EndpointReferenceType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:element name="From"
+ type="tns:EndpointReferenceType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:element name="FaultTo"
+ type="tns:EndpointReferenceType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:element name="To"
+ type="tns:AttributedURIType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:element name="Action"
+ type="tns:AttributedURIType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:complexType mixed="false"
+ name="AttributedURIType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:simpleContent>
+ <xs:extension base="xs:anyURI">
+ <xs:anyAttribute
+ namespace="##other" processContents="lax"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:attribute name="IsReferenceParameter"
+ type="xs:boolean" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:simpleType name="FaultCodesOpenEnumType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:union memberTypes="tns:FaultCodesType xs:QName"/>
+ </xs:simpleType>
+ <xs:simpleType name="FaultCodesType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:restriction base="xs:QName">
+ <xs:enumeration value="tns:InvalidAddressingHeader"/>
+ <xs:enumeration value="tns:InvalidAddress"/>
+ <xs:enumeration value="tns:InvalidEPR"/>
+ <xs:enumeration value="tns:InvalidCardinality"/>
+ <xs:enumeration value="tns:MissingAddressInEPR"/>
+ <xs:enumeration value="tns:DuplicateMessageID"/>
+ <xs:enumeration value="tns:ActionMismatch"/>
+ <xs:enumeration value="tns:MessageAddressingHeaderRequired"/>
+ <xs:enumeration value="tns:DestinationUnreachable"/>
+ <xs:enumeration value="tns:ActionNotSupported"/>
+ <xs:enumeration value="tns:EndpointUnavailable"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:element name="RetryAfter"
+ type="tns:AttributedUnsignedLongType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:complexType mixed="false"
+ name="AttributedUnsignedLongType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:simpleContent>
+ <xs:extension base="xs:unsignedLong">
+ <xs:anyAttribute
+ namespace="##other" processContents="lax"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:element name="ProblemHeaderQName"
+ type="tns:AttributedQNameType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:complexType mixed="false"
+ name="AttributedQNameType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:simpleContent>
+ <xs:extension base="xs:QName">
+ <xs:anyAttribute
+ namespace="##other" processContents="lax"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:element name="ProblemHeader"
+ type="tns:AttributedAnyType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:complexType mixed="false"
+ name="AttributedAnyType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:sequence>
+ <xs:any maxOccurs="1" minOccurs="1"
+ namespace="##any" processContents="lax"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+ <xs:element name="ProblemIRI"
+ type="tns:AttributedURIType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:element name="ProblemAction"
+ type="tns:ProblemActionType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:complexType mixed="false"
+ name="ProblemActionType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:sequence>
+ <xs:element minOccurs="0" ref="tns:Action"/>
+ <xs:element minOccurs="0"
+ name="SoapAction" type="xs:anyURI"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+ </xsd:schema>
+ <xsd:schema elementFormDefault="qualified"
+ targetNamespace="http://schemas.xmlsoap.org/ws/2004/09/mex"
+ xmlns:tns="http://schemas.xmlsoap.org/ws/2004/09/mex"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:import
+ namespace="http://www.w3.org/2005/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:element name="GetMetadata" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element minOccurs="0" ref="tns:Dialect"/>
+ <xs:element minOccurs="0" ref="tns:Identifier"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="Dialect" type="xs:anyURI" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:element name="Identifier"
+ type="xs:anyURI" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:element name="Metadata" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element
+ maxOccurs="unbounded"
+ minOccurs="0" ref="tns:MetadataSection"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="MetadataSection" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:complexType>
+ <xs:choice>
+ <xs:any maxOccurs="unbounded"
+ minOccurs="0"
+ namespace="##other" processContents="lax"/>
+ <xs:element ref="tns:MetadataReference"/>
+ <xs:element ref="tns:Location"/>
+ </xs:choice>
+ <xs:attribute name="Dialect"
+ type="xs:anyURI" use="required"/>
+ <xs:attribute name="Identifier" type="xs:anyURI"/>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="MetadataReference"
+ type="wsa:EndpointReferenceType" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:element name="Location" type="xs:anyURI" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
+ <xs:complexType name="AnyXmlType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:sequence>
+ <xs:any namespace="##any" processContents="lax"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##any" processContents="lax"/>
+ </xs:complexType>
+ </xsd:schema>
+ <xsd:schema attributeFormDefault="unqualified"
+ elementFormDefault="qualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/rl-2"
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
+ xmlns:wsrf-rl="http://docs.oasis-open.org/wsrf/rl-2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/bf-2"/>
+ <xsd:element name="CurrentTime">
+ <xsd:complexType>
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:dateTime">
+ <xsd:anyAttribute
+ namespace="##other" processContents="lax"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="TerminationTime" nillable="true">
+ <xsd:complexType>
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:dateTime">
+ <xsd:anyAttribute
+ namespace="##other" processContents="lax"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="ScheduledResourceTerminationRP">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element maxOccurs="1"
+ minOccurs="1" ref="wsrf-rl:CurrentTime"/>
+ <xsd:element maxOccurs="1"
+ minOccurs="1" ref="wsrf-rl:TerminationTime"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="Destroy">
+ <xsd:complexType/>
+ </xsd:element>
+ <xsd:element name="DestroyResponse">
+ <xsd:complexType/>
+ </xsd:element>
+ <xsd:complexType name="ResourceNotDestroyedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="ResourceNotDestroyedFault" type="wsrf-rl:ResourceNotDestroyedFaultType"/>
+ <xsd:element name="SetTerminationTime">
+ <xsd:complexType>
+ <xsd:choice>
+ <xsd:element
+ name="RequestedTerminationTime"
+ nillable="true" type="xsd:dateTime"/>
+ <xsd:element
+ name="RequestedLifetimeDuration" type="xsd:duration"/>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="SetTerminationTimeResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element
+ name="NewTerminationTime"
+ nillable="true" type="xsd:dateTime"/>
+ <xsd:element name="CurrentTime" type="xsd:dateTime"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:complexType name="UnableToSetTerminationTimeFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="UnableToSetTerminationTimeFault" type="wsrf-rl:UnableToSetTerminationTimeFaultType"/>
+ <xsd:complexType name="TerminationTimeChangeRejectedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="TerminationTimeChangeRejectedFault" type="wsrf-rl:TerminationTimeChangeRejectedFaultType"/>
+ <xsd:element name="TerminationNotification">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element maxOccurs="1"
+ minOccurs="1"
+ name="TerminationTime"
+ nillable="true" type="xsd:dateTime"/>
+ <xsd:element maxOccurs="1"
+ minOccurs="0"
+ name="TerminationReason" type="xsd:anyType"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <xsd:schema attributeFormDefault="unqualified"
+ elementFormDefault="qualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/rp-2"
+ xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2" xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/bf-2"/>
+ <xsd:element name="QueryExpressionDialect" type="xsd:anyURI"/>
+ <xsd:element name="QueryExpressionRPDocument">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element
+ maxOccurs="unbounded"
+ minOccurs="0" ref="wsrf-rp:QueryExpressionDialect"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:attribute name="ResourceProperties" type="xsd:QName"/>
+ <xsd:complexType name="ResourcePropertyValueChangeNotificationType">
+ <xsd:sequence>
+ <xsd:element maxOccurs="1"
+ minOccurs="0" name="OldValues" nillable="true">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any
+ maxOccurs="unbounded" minOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element maxOccurs="1"
+ minOccurs="1" name="NewValues" nillable="true">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any
+ maxOccurs="unbounded" minOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element
+ name="ResourcePropertyValueChangeNotification" type="wsrf-rp:ResourcePropertyValueChangeNotificationType"/>
+ <xsd:complexType mixed="true" name="QueryExpressionType">
+ <xsd:sequence>
+ <xsd:any maxOccurs="1" minOccurs="0" processContents="lax"/>
+ </xsd:sequence>
+ <xsd:attribute name="Dialect" type="xsd:anyURI"/>
+ </xsd:complexType>
+ <xsd:element name="QueryExpression" type="wsrf-rp:QueryExpressionType"/>
+ <xsd:element name="GetResourcePropertyDocument">
+ <xsd:complexType/>
+ </xsd:element>
+ <xsd:element name="GetResourcePropertyDocumentResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any maxOccurs="1" minOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="GetResourceProperty" type="xsd:QName"/>
+ <xsd:element name="GetResourcePropertyResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any maxOccurs="unbounded" minOccurs="0"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:complexType name="InvalidResourcePropertyQNameFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="InvalidResourcePropertyQNameFault" type="wsrf-rp:InvalidResourcePropertyQNameFaultType"/>
+ <xsd:element name="GetMultipleResourceProperties">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element
+ maxOccurs="unbounded"
+ minOccurs="1"
+ name="ResourceProperty" type="xsd:QName"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="GetMultipleResourcePropertiesResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any maxOccurs="unbounded" minOccurs="0"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="PutResourcePropertyDocument">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any maxOccurs="1" minOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="PutResourcePropertyDocumentResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any maxOccurs="1" minOccurs="0"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:complexType name="ResourcePropertyChangeFailureType">
+ <xsd:sequence>
+ <xsd:element maxOccurs="1"
+ minOccurs="0" name="CurrentValue">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any
+ maxOccurs="unbounded" minOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element maxOccurs="1"
+ minOccurs="0" name="RequestedValue">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any
+ maxOccurs="unbounded" minOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:attribute name="Restored" type="xsd:boolean"/>
+ </xsd:complexType>
+ <xsd:complexType name="UnableToPutResourcePropertyDocumentFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element
+ name="ResourcePropertyChangeFailure" type="wsrf-rp:ResourcePropertyChangeFailureType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="UnableToPutResourcePropertyDocumentFault" type="wsrf-rp:UnableToPutResourcePropertyDocumentFaultType"/>
+ <xsd:complexType name="InsertType">
+ <xsd:sequence>
+ <xsd:any maxOccurs="unbounded"
+ minOccurs="1" processContents="lax"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="Insert" type="wsrf-rp:InsertType"/>
+ <xsd:complexType name="UpdateType">
+ <xsd:sequence>
+ <xsd:any maxOccurs="unbounded"
+ minOccurs="1" processContents="lax"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="Update" type="wsrf-rp:UpdateType"/>
+ <xsd:complexType name="DeleteType">
+ <xsd:attribute name="ResourceProperty"
+ type="xsd:QName" use="required"/>
+ </xsd:complexType>
+ <xsd:element name="Delete" type="wsrf-rp:DeleteType"/>
+ <xsd:element name="SetResourceProperties">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded" minOccurs="1">
+ <xsd:element ref="wsrf-rp:Insert"/>
+ <xsd:element ref="wsrf-rp:Update"/>
+ <xsd:element ref="wsrf-rp:Delete"/>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="SetResourcePropertiesResponse">
+ <xsd:complexType/>
+ </xsd:element>
+ <xsd:complexType name="InvalidModificationFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element
+ name="ResourcePropertyChangeFailure" type="wsrf-rp:ResourcePropertyChangeFailureType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="InvalidModificationFault" type="wsrf-rp:InvalidModificationFaultType"/>
+ <xsd:complexType name="UnableToModifyResourcePropertyFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element
+ name="ResourcePropertyChangeFailure" type="wsrf-rp:ResourcePropertyChangeFailureType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="UnableToModifyResourcePropertyFault" type="wsrf-rp:UnableToModifyResourcePropertyFaultType"/>
+ <xsd:complexType name="SetResourcePropertyRequestFailedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element
+ name="ResourcePropertyChangeFailure" type="wsrf-rp:ResourcePropertyChangeFailureType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="SetResourcePropertyRequestFailedFault" type="wsrf-rp:SetResourcePropertyRequestFailedFaultType"/>
+ <xsd:complexType name="InsertResourcePropertiesRequestFailedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element
+ name="ResourcePropertyChangeFailure" type="wsrf-rp:ResourcePropertyChangeFailureType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="InsertResourcePropertiesRequestFailedFault" type="wsrf-rp:InsertResourcePropertiesRequestFailedFaultType"/>
+ <xsd:complexType name="UpdateResourcePropertiesRequestFailedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element
+ name="ResourcePropertyChangeFailure" type="wsrf-rp:ResourcePropertyChangeFailureType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="UpdateResourcePropertiesRequestFailedFault" type="wsrf-rp:UpdateResourcePropertiesRequestFailedFaultType"/>
+ <xsd:complexType name="DeleteResourcePropertiesRequestFailedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element
+ name="ResourcePropertyChangeFailure" type="wsrf-rp:ResourcePropertyChangeFailureType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="DeleteResourcePropertiesRequestFailedFault" type="wsrf-rp:DeleteResourcePropertiesRequestFailedFaultType"/>
+ <xsd:element name="InsertResourceProperties">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsrf-rp:Insert"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="InsertResourcePropertiesResponse">
+ <xsd:complexType/>
+ </xsd:element>
+ <xsd:element name="UpdateResourceProperties">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsrf-rp:Update"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="UpdateResourcePropertiesResponse">
+ <xsd:complexType/>
+ </xsd:element>
+ <xsd:element name="DeleteResourceProperties">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsrf-rp:Delete"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="DeleteResourcePropertiesResponse">
+ <xsd:complexType/>
+ </xsd:element>
+ <xsd:element name="QueryResourceProperties">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element maxOccurs="1"
+ minOccurs="1" ref="wsrf-rp:QueryExpression"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="QueryResourcePropertiesResponse">
+ <xsd:complexType>
+ <xsd:complexContent mixed="true">
+ <xsd:restriction base="xsd:anyType">
+ <xsd:sequence>
+ <xsd:any
+ maxOccurs="unbounded"
+ minOccurs="1" processContents="lax"/>
+ </xsd:sequence>
+ </xsd:restriction>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:complexType name="UnknownQueryExpressionDialectFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="UnknownQueryExpressionDialectFault" type="wsrf-rp:UnknownQueryExpressionDialectFaultType"/>
+ <xsd:complexType name="InvalidQueryExpressionFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="InvalidQueryExpressionFault" type="wsrf-rp:InvalidQueryExpressionFaultType"/>
+ <xsd:complexType name="QueryEvaluationErrorFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="QueryEvaluationErrorFault" type="wsrf-rp:QueryEvaluationErrorFaultType"/>
+ </xsd:schema>
+ <xsd:schema attributeFormDefault="unqualified"
+ elementFormDefault="qualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/r-2"
+ xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
+ xmlns:wsrf-r="http://docs.oasis-open.org/wsrf/r-2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/bf-2"/>
+ <xsd:complexType name="ResourceUnknownFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="ResourceUnknownFault" type="wsrf-r:ResourceUnknownFaultType"/>
+ <xsd:complexType name="ResourceUnavailableFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="ResourceUnavailableFault" type="wsrf-r:ResourceUnavailableFaultType"/>
+ </xsd:schema>
+ <xsd:schema elementFormDefault="qualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/rmd-1"
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:wsrmd="http://docs.oasis-open.org/wsrf/rmd-1">
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/rp-2"/>
+ <xsd:import namespace="http://www.w3.org/2005/08/addressing"/>
+ <xsd:simpleType name="PairsOfURIType">
+ <xsd:list itemType="xsd:anyURI"/>
+ </xsd:simpleType>
+ <xsd:attribute name="Descriptor" type="xsd:QName"/>
+ <xsd:attribute name="DescriptorLocation" type="xsd:anyURI"/>
+ <xsd:complexType mixed="true" name="DocumentationType">
+ <xsd:sequence>
+ <xsd:any maxOccurs="unbounded"
+ minOccurs="0" namespace="##any" processContents="lax"/>
+ </xsd:sequence>
+ <xsd:anyAttribute/>
+ </xsd:complexType>
+ <xsd:complexType name="DocumentedType">
+ <xsd:sequence>
+ <xsd:element maxOccurs="1"
+ minOccurs="0"
+ name="documentation" type="wsrmd:DocumentationType"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="DefinitionsType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrmd:DocumentedType">
+ <xsd:sequence>
+ <xsd:element
+ maxOccurs="unbounded"
+ minOccurs="0" ref="wsrmd:MetadataDescriptor"/>
+ <xsd:any
+ maxOccurs="unbounded"
+ minOccurs="0"
+ namespace="##other" processContents="lax"/>
+ </xsd:sequence>
+ <xsd:attribute
+ name="targetNamespace"
+ type="xsd:anyURI" use="required"/>
+ <xsd:anyAttribute
+ namespace="##other" processContents="lax"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="Definitions" type="wsrmd:DefinitionsType">
+ <xsd:key name="MetadataDescriptor">
+ <xsd:annotation>
+ <xsd:documentation>
+ To form a QName, the name of any MetadataDescriptor must be
+ unique within a Definitions element.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:selector xpath="wsrmd:MetadataDescriptor"/>
+ <xsd:field xpath="@name"/>
+ </xsd:key>
+ </xsd:element>
+ <xsd:complexType name="MetadataDescriptorType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrmd:DocumentedType">
+ <xsd:sequence>
+ <xsd:element
+ maxOccurs="unbounded"
+ minOccurs="0" ref="wsrmd:Property"/>
+ <xsd:any
+ maxOccurs="unbounded"
+ minOccurs="0"
+ namespace="##other" processContents="lax"/>
+ </xsd:sequence>
+ <xsd:attribute name="name"
+ type="xsd:NCName" use="required"/>
+ <xsd:attribute name="interface"
+ type="xsd:QName" use="required"/>
+ <xsd:attribute
+ name="wsdlLocation" type="wsrmd:PairsOfURIType"/>
+ <xsd:anyAttribute
+ namespace="##other" processContents="lax"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="MetadataDescriptor" type="wsrmd:MetadataDescriptorType"/>
+ <xsd:complexType name="PropertyType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrmd:DocumentedType">
+ <xsd:sequence>
+ <xsd:choice>
+ <xsd:element
+ maxOccurs="1"
+ minOccurs="0" ref="wsrmd:ValidValues"/>
+ <xsd:element
+ maxOccurs="1"
+ minOccurs="0" ref="wsrmd:ValidValueRange"/>
+ </xsd:choice>
+ <xsd:element maxOccurs="1"
+ minOccurs="0" ref="wsrmd:StaticValues"/>
+ <xsd:any
+ maxOccurs="unbounded"
+ minOccurs="0"
+ namespace="##other" processContents="lax"/>
+ </xsd:sequence>
+ <xsd:attribute name="name"
+ type="xsd:QName" use="required"/>
+ <xsd:attribute name="mutability" type="wsrmd:MutabilityType"/>
+ <xsd:attribute
+ name="modifiability" type="wsrmd:ModifiabilityType"/>
+ <xsd:attribute default="false"
+ name="subscribability" type="xsd:boolean"/>
+ <xsd:anyAttribute
+ namespace="##other" processContents="lax"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="Property" type="wsrmd:PropertyType"/>
+ <xsd:simpleType name="MutabilityType">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="constant"/>
+ <xsd:enumeration value="appendable"/>
+ <xsd:enumeration value="mutable"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+ <xsd:simpleType name="ModifiabilityType">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="read-only"/>
+ <xsd:enumeration value="read-write"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+ <xsd:complexType mixed="true" name="ValidValuesType">
+ <xsd:sequence>
+ <xsd:element maxOccurs="1"
+ minOccurs="0"
+ name="documentation" type="wsrmd:DocumentationType"/>
+ <xsd:any maxOccurs="unbounded"
+ minOccurs="0"
+ namespace="##other" processContents="lax"/>
+ </xsd:sequence>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+ <xsd:element name="ValidValues" type="wsrmd:ValidValuesType"/>
+ <xsd:complexType mixed="true" name="ValidValueRangeType">
+ <xsd:sequence>
+ <xsd:element maxOccurs="1"
+ minOccurs="0"
+ name="documentation" type="wsrmd:DocumentationType"/>
+ <xsd:any maxOccurs="unbounded"
+ minOccurs="0"
+ namespace="##other" processContents="lax"/>
+ </xsd:sequence>
+ <xsd:attribute name="lowerBound" type="xsd:anySimpleType"/>
+ <xsd:attribute name="upperBound" type="xsd:anySimpleType"/>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+ <xsd:element name="ValidValueRange" type="wsrmd:ValidValueRangeType"/>
+ <xsd:complexType mixed="true" name="StaticValuesType">
+ <xsd:sequence>
+ <xsd:element maxOccurs="1"
+ minOccurs="0"
+ name="documentation" type="wsrmd:DocumentationType"/>
+ <xsd:any maxOccurs="unbounded"
+ minOccurs="0"
+ namespace="##other" processContents="lax"/>
+ </xsd:sequence>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+ <xsd:element name="StaticValues" type="wsrmd:StaticValuesType"/>
+ <xsd:complexType mixed="true" name="InitialValuesType">
+ <xsd:sequence>
+ <xsd:element maxOccurs="1"
+ minOccurs="0"
+ name="documentation" type="wsrmd:DocumentationType"/>
+ <xsd:any maxOccurs="unbounded"
+ minOccurs="0"
+ namespace="##other" processContents="lax"/>
+ </xsd:sequence>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+ <xsd:element name="InitialValues" type="wsrmd:InitialValuesType"/>
+ <xsd:complexType name="MetadataDescriptorReferenceType">
+ <xsd:complexContent>
+ <xsd:extension base="wsa:EndpointReferenceType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="MetadataDescriptorReference" type="wsrmd:MetadataDescriptorReferenceType"/>
+ <xsd:element name="MetadataResourceRP" type="wsrmd:DefinitionsType"/>
+ </xsd:schema>
+ <xsd:schema elementFormDefault="qualified" targetNamespace="http://amqp.apache.org/qpid/management/qman">
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/rl-2"/>
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/rp-2"/>
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/bf-2"/>
+ <xsd:element name="QManWsResourceProperties">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsrf-rl:CurrentTime"/>
+ <xsd:element ref="wsrf-rl:TerminationTime"/>
+ <xsd:element
+ maxOccurs="unbounded"
+ minOccurs="0" ref="wsrf-rp:QueryExpressionDialect"/>
+ <xsd:element ref="qman:Name"/>
+ <xsd:element ref="qman:Type"/>
+ <xsd:element ref="qman:Arguments"/>
+ <xsd:element ref="qman:VhostRef"/>
+ <xsd:element ref="qman:Durable"/>
+ <xsd:element ref="qman:MsgTotalEnqueues"/>
+ <xsd:element ref="qman:ConsumerCount"/>
+ <xsd:element ref="qman:ExpireTime"/>
+ <xsd:element ref="qman:MgmtPubInterval"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="QManFault">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="MethodInvocationFault">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="EntityInstanceNotFoundFault">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="MalformedEntityNameFault">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="NoSuchAttributeFault">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:complexType name="result">
+ <xsd:sequence>
+ <xsd:element name="statusCode" type="xsd:long"/>
+ <xsd:element name="statusText" type="xsd:string"/>
+ <xsd:complexType name="outputParameters">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element
+ maxOccurs="unbounded"
+ minOccurs="0" name="entry">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:name
+ name="key" type="xsd:string"/>
+ <xsd:element
+ name="value" type="xsd:anyType"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:complexType>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="Name" type="xsd:string"/>
+ <xsd:element name="Type" type="xsd:string"/>
+ <xsd:complexType name="map">
+ <xsd:sequence>
+ <xsd:element maxOccurs="unbounded"
+ minOccurs="0" name="entry">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="key" type="xsd:string"/>
+ <xsd:element
+ name="value" type="xsd:anyType"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="Arguments" type="qman:map"/>
+ <xsd:complexType name="uuid">
+ <xsd:sequence>
+ <xsd:element name="uuid" type="xsd:string"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="VhostRef" type="qman:uuid"/>
+ <xsd:element name="Durable" type="xsd:boolean"/>
+ <xsd:element name="MsgTotalEnqueues" type="xsd:long"/>
+ <xsd:element name="ConsumerCount" type="xsd:integer"/>
+ <xsd:element name="ExpireTime" type="xsd:dateTime"/>
+ <xsd:element name="MgmtPubInterval" type="xsd:short"/>
+ <xsd:element
+ name="echoWithSimpleTypesRequest" type="qman:echoWithSimpleTypesRequest"/>
+ <xsd:element
+ name="echoWithSimpleTypesResponse" type="qman:echoWithSimpleTypesResponse"/>
+ <xsd:complexType name="echoWithSimpleTypesRequest">
+ <xsd:sequence>
+ <xsd:element name="p1" type="xsd:long"/>
+ <xsd:element name="p2" type="xsd:boolean"/>
+ <xsd:element name="p3" type="xsd:double"/>
+ <xsd:element name="p4" type="xsd:float"/>
+ <xsd:element name="p5" type="xsd:integer"/>
+ <xsd:element name="p6" type="xsd:short"/>
+ <xsd:element name="p7" type="xsd:string"/>
+ <xsd:element name="p8" type="xsd:anyURI"/>
+ <xsd:element name="p9" type="xsd:dateTime"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="echoWithSimpleTypesResponse">
+ <xsd:sequence>
+ <xsd:element name="result" type="qman:result"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="echoWithArraysRequest" type="qman:echoWithArraysRequest"/>
+ <xsd:element name="echoWithArraysResponse" type="qman:echoWithArraysResponse"/>
+ <xsd:complexType name="arrayOfLong">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:long"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfBoolean">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:boolean"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfDouble">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:double"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfFloat">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:float"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfInteger">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:integer"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfShort">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:short"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfString">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:string"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfURI">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:anyURI"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfDate">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:dateTime"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="echoWithArraysRequest">
+ <xsd:sequence>
+ <xsd:element name="p1" type="qman:arrayOfLong"/>
+ <xsd:element name="p2" type="qman:arrayOfBoolean"/>
+ <xsd:element name="p3" type="qman:arrayOfDouble"/>
+ <xsd:element name="p4" type="qman:arrayOfFloat"/>
+ <xsd:element name="p5" type="qman:arrayOfInteger"/>
+ <xsd:element name="p6" type="qman:arrayOfShort"/>
+ <xsd:element name="p7" type="qman:arrayOfString"/>
+ <xsd:element name="p8" type="qman:arrayOfURI"/>
+ <xsd:element name="p9" type="qman:arrayOfDate"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="echoWithArraysResponse">
+ <xsd:sequence>
+ <xsd:element name="result" type="qman:result"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element
+ name="echoWithSimpleTypeArraysRequest" type="qman:echoWithSimpleTypeArraysRequest"/>
+ <xsd:element
+ name="echoWithSimpleTypeArraysResponse" type="qman:echoWithSimpleTypeArraysResponse"/>
+ <xsd:complexType name="arrayOfLong">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:long"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfBoolean">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:boolean"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfDouble">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:double"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfFloat">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:float"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfInt">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:integer"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="arrayOfShort">
+ <xsd:sequence>
+ <xsd:element name="entry" type="xsd:short"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="echoWithSimpleTypeArraysRequest">
+ <xsd:sequence>
+ <xsd:element name="p1" type="qman:arrayOfLong"/>
+ <xsd:element name="p2" type="qman:arrayOfBoolean"/>
+ <xsd:element name="p3" type="qman:arrayOfDouble"/>
+ <xsd:element name="p4" type="qman:arrayOfFloat"/>
+ <xsd:element name="p5" type="qman:arrayOfInt"/>
+ <xsd:element name="p6" type="qman:arrayOfShort"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="echoWithSimpleTypeArraysResponse">
+ <xsd:sequence>
+ <xsd:element name="result" type="qman:result"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="echoWithByteArrayRequest" type="qman:echoWithByteArrayRequest"/>
+ <xsd:element
+ name="echoWithByteArrayResponse" type="qman:echoWithByteArrayResponse"/>
+ <xsd:complexType name="arrayOfByte">
+ <xsd:sequence>
+ <xsd:element name="entry" type=""/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="echoWithByteArrayRequest">
+ <xsd:sequence>
+ <xsd:element name="p1" type="qman:arrayOfByte"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="echoWithByteArrayResponse">
+ <xsd:sequence>
+ <xsd:element name="result" type="qman:result"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element
+ name="voidWithoutArgumentsRequest" type="qman:voidWithoutArgumentsRequest"/>
+ <xsd:element
+ name="voidWithoutArgumentsResponse" type="qman:voidWithoutArgumentsResponse"/>
+ <xsd:complexType name="voidWithoutArgumentsRequest">
+ <xsd:sequence/>
+ </xsd:complexType>
+ <xsd:complexType name="voidWithoutArgumentsResponse">
+ <xsd:sequence>
+ <xsd:element name="result" type="qman:result"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="throwsExceptionRequest" type="qman:throwsExceptionRequest"/>
+ <xsd:element name="throwsExceptionResponse" type="qman:throwsExceptionResponse"/>
+ <xsd:complexType name="throwsExceptionRequest">
+ <xsd:sequence/>
+ </xsd:complexType>
+ <xsd:complexType name="throwsExceptionResponse">
+ <xsd:sequence>
+ <xsd:element name="result" type="qman:result"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="echoWithUUIDRequest" type="qman:echoWithUUIDRequest"/>
+ <xsd:element name="echoWithUUIDResponse" type="qman:echoWithUUIDResponse"/>
+ <xsd:complexType name="echoWithUUIDRequest">
+ <xsd:sequence>
+ <xsd:element name="p1" type="qman:uuid"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="echoWithUUIDResponse">
+ <xsd:sequence>
+ <xsd:element name="result" type="qman:result"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="echoWithMapRequest" type="qman:echoWithMapRequest"/>
+ <xsd:element name="echoWithMapResponse" type="qman:echoWithMapResponse"/>
+ <xsd:complexType name="echoWithMapRequest">
+ <xsd:sequence>
+ <xsd:element name="p1" type="qman:map"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="echoWithMapResponse">
+ <xsd:sequence>
+ <xsd:element name="result" type="qman:result"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:schema>
+ <xsd:schema attributeFormDefault="unqualified"
+ elementFormDefault="qualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/bf-2"
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <xsd:import namespace="http://www.w3.org/2005/08/addressing"/>
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace">
+ <xsd:annotation>
+ <xsd:documentation>
+ Get access to the xml: attribute groups for xml:lang as declared on 'schema'
+ and 'documentation' below
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:import>
+ <xsd:element name="BaseFault" type="wsrf-bf:BaseFaultType"/>
+ <xsd:complexType name="BaseFaultType">
+ <xsd:sequence>
+ <xsd:any maxOccurs="unbounded"
+ minOccurs="0"
+ namespace="##other" processContents="lax"/>
+ <xsd:element maxOccurs="1"
+ minOccurs="1" name="Timestamp" type="xsd:dateTime"/>
+ <xsd:element maxOccurs="1"
+ minOccurs="0" name="Originator" type="wsa:EndpointReferenceType"/>
+ <xsd:element maxOccurs="1"
+ minOccurs="0" name="ErrorCode">
+ <xsd:complexType>
+ <xsd:complexContent mixed="true">
+ <xsd:extension base="xsd:anyType">
+ <xsd:attribute
+ name="dialect"
+ type="xsd:anyURI" use="required"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element maxOccurs="unbounded"
+ minOccurs="0" name="Description">
+ <xsd:complexType>
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute
+ ref="xml:lang" use="optional"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element maxOccurs="1"
+ minOccurs="0" name="FaultCause">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any maxOccurs="1"
+ minOccurs="1"
+ namespace="##other" processContents="lax"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+ </xsd:schema>
+ <xs:schema
+ targetNamespace="http://www.w3.org/XML/1998/namespace"
+ xml:lang="en" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:attribute name="lang" type="xs:language"/>
+ <xs:attribute default="preserve" name="space">
+ <xs:simpleType>
+ <xs:restriction base="xs:NCName">
+ <xs:enumeration value="default"/>
+ <xs:enumeration value="preserve"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="base" type="xs:anyURI"/>
+ <xs:attributeGroup name="specialAttrs">
+ <xs:attribute ref="xml:base"/>
+ <xs:attribute ref="xml:lang"/>
+ <xs:attribute ref="xml:space"/>
+ </xs:attributeGroup>
+ </xs:schema>
+ </wsdl:types>
+ <wsdl:message name="GetMetadataMsg">
+ <wsdl:part element="wsx:GetMetadata" name="GetMetadataMsg"/>
+ </wsdl:message>
+ <wsdl:message name="GetMetadataResponseMsg">
+ <wsdl:part element="wsx:Metadata" name="GetMetadataResponseMsg"/>
+ </wsdl:message>
+ <wsdl:message name="DestroyRequest">
+ <wsdl:part element="wsrf-rl:Destroy" name="DestroyRequest"/>
+ </wsdl:message>
+ <wsdl:message name="DestroyResponse">
+ <wsdl:part element="wsrf-rl:DestroyResponse" name="DestroyResponse"/>
+ </wsdl:message>
+ <wsdl:message name="ResourceNotDestroyedFault">
+ <wsdl:part
+ element="wsrf-rl:ResourceNotDestroyedFault" name="ResourceNotDestroyedFault"/>
+ </wsdl:message>
+ <wsdl:message name="ResourceUnknownFault">
+ <wsdl:part element="wsrf-r:ResourceUnknownFault" name="ResourceUnknownFault"/>
+ </wsdl:message>
+ <wsdl:message name="ResourceUnavailableFault">
+ <wsdl:part
+ element="wsrf-r:ResourceUnavailableFault" name="ResourceUnavailableFault"/>
+ </wsdl:message>
+ <wsdl:message name="SetTerminationTimeRequest">
+ <wsdl:part element="wsrf-rl:SetTerminationTime" name="SetTerminationTimeRequest"/>
+ </wsdl:message>
+ <wsdl:message name="SetTerminationTimeResponse">
+ <wsdl:part
+ element="wsrf-rl:SetTerminationTimeResponse" name="SetTerminationTimeResponse"/>
+ </wsdl:message>
+ <wsdl:message name="UnableToSetTerminationTimeFault">
+ <wsdl:part
+ element="wsrf-rl:UnableToSetTerminationTimeFault" name="UnableToSetTerminationTimeFault"/>
+ </wsdl:message>
+ <wsdl:message name="TerminationTimeChangeRejectedFault">
+ <wsdl:part
+ element="wsrf-rl:TerminationTimeChangeRejectedFault" name="TerminationTimeChangeRejectedFault"/>
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyDocumentRequest">
+ <wsdl:part
+ element="wsrf-rp:GetResourcePropertyDocument" name="GetResourcePropertyDocumentRequest"/>
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyDocumentResponse">
+ <wsdl:part
+ element="wsrf-rp:GetResourcePropertyDocumentResponse" name="GetResourcePropertyDocumentResponse"/>
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyRequest">
+ <wsdl:part element="wsrf-rp:GetResourceProperty" name="GetResourcePropertyRequest"/>
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyResponse">
+ <wsdl:part
+ element="wsrf-rp:GetResourcePropertyResponse" name="GetResourcePropertyResponse"/>
+ </wsdl:message>
+ <wsdl:message name="InvalidResourcePropertyQNameFault">
+ <wsdl:part
+ element="wsrf-rp:InvalidResourcePropertyQNameFault" name="InvalidResourcePropertyQNameFault"/>
+ </wsdl:message>
+ <wsdl:message name="GetMultipleResourcePropertiesRequest">
+ <wsdl:part
+ element="wsrf-rp:GetMultipleResourceProperties" name="GetMultipleResourcePropertiesRequest"/>
+ </wsdl:message>
+ <wsdl:message name="GetMultipleResourcePropertiesResponse">
+ <wsdl:part
+ element="wsrf-rp:GetMultipleResourcePropertiesResponse" name="GetMultipleResourcePropertiesResponse"/>
+ </wsdl:message>
+ <wsdl:message name="QueryResourcePropertiesRequest">
+ <wsdl:part
+ element="wsrf-rp:QueryResourceProperties" name="QueryResourcePropertiesRequest"/>
+ </wsdl:message>
+ <wsdl:message name="QueryResourcePropertiesResponse">
+ <wsdl:part
+ element="wsrf-rp:QueryResourcePropertiesResponse" name="QueryResourcePropertiesResponse"/>
+ </wsdl:message>
+ <wsdl:message name="UnknownQueryExpressionDialectFault">
+ <wsdl:part
+ element="wsrf-rp:UnknownQueryExpressionDialectFault" name="UnknownQueryExpressionDialectFault"/>
+ </wsdl:message>
+ <wsdl:message name="InvalidQueryExpressionFault">
+ <wsdl:part
+ element="wsrf-rp:InvalidQueryExpressionFault" name="InvalidQueryExpressionFault"/>
+ </wsdl:message>
+ <wsdl:message name="QueryEvaluationErrorFault">
+ <wsdl:part
+ element="wsrf-rp:QueryEvaluationErrorFault" name="QueryEvaluationErrorFault"/>
+ </wsdl:message>
+ <wsdl:message name="SetResourcePropertiesRequest">
+ <wsdl:part
+ element="wsrf-rp:SetResourceProperties" name="SetResourcePropertiesRequest"/>
+ </wsdl:message>
+ <wsdl:message name="SetResourcePropertiesResponse">
+ <wsdl:part
+ element="wsrf-rp:SetResourcePropertiesResponse" name="SetResourcePropertiesResponse"/>
+ </wsdl:message>
+ <wsdl:message name="InvalidModificationFault">
+ <wsdl:part
+ element="wsrf-rp:InvalidModificationFault" name="InvalidModificationFault"/>
+ </wsdl:message>
+ <wsdl:message name="UnableToModifyResourcePropertyFault">
+ <wsdl:part
+ element="wsrf-rp:UnableToModifyResourcePropertyFault" name="UnableToModifyResourcePropertyFault"/>
+ </wsdl:message>
+ <wsdl:message name="SetResourcePropertyRequestFailedFault">
+ <wsdl:part
+ element="wsrf-rp:SetResourcePropertyRequestFailedFault" name="SetResourcePropertyRequestFailedFault"/>
+ </wsdl:message>
+ <wsdl:portType name="QManWsResourcePortType"
+ wsrf-rp:ResourceProperties="qman:QManWsResourceProperties"
+ wsrmd:Descriptor="QManWsResourceMetadata" wsrmd:DescriptorLocation="QManWsResource.rmd">
+ <wsdl:operation name="GetMetadata">
+ <wsdl:input message="qman:GetMetadataMsg"
+ name="GetMetadataMsg" wsa:Action="http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata"/>
+ <wsdl:output
+ message="qman:GetMetadataResponseMsg"
+ name="GetMetadataResponseMsg" wsa:Action="http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadataResponse"/>
+ </wsdl:operation>
+ <wsdl:operation name="Destroy">
+ <wsdl:input message="qman:DestroyRequest"
+ name="DestroyRequest" wsa:Action="http://docs.oasis-open.org/wsrf/rlw-2/ImmediateResourceTermination/DestroyRequest"/>
+ <wsdl:output message="qman:DestroyResponse"
+ name="DestroyResponse" wsa:Action="http://docs.oasis-open.org/wsrf/rlw-2/ImmediateResourceTermination/DestroyResponse"/>
+ <wsdl:fault
+ message="qman:ResourceNotDestroyedFault" name="ResourceNotDestroyedFault"/>
+ <wsdl:fault
+ message="qman:ResourceUnknownFault" name="ResourceUnknownFault"/>
+ <wsdl:fault
+ message="qman:ResourceUnavailableFault" name="ResourceUnavailableFault"/>
+ </wsdl:operation>
+ <wsdl:operation name="SetTerminationTime">
+ <wsdl:input
+ message="qman:SetTerminationTimeRequest"
+ name="SetTerminationTimeRequest" wsa:Action="http://docs.oasis-open.org/wsrf/rlw-2/ScheduledResourceTermination/SetTerminationTimeRequest"/>
+ <wsdl:output
+ message="qman:SetTerminationTimeResponse"
+ name="SetTerminationTimeResponse" wsa:Action="http://docs.oasis-open.org/wsrf/rlw-2/ScheduledResourceTermination/SetTerminationTimeResponse"/>
+ <wsdl:fault
+ message="qman:UnableToSetTerminationTimeFault" name="UnableToSetTerminationTimeFault"/>
+ <wsdl:fault
+ message="qman:ResourceUnknownFault" name="ResourceUnknownFault"/>
+ <wsdl:fault
+ message="qman:ResourceUnavailableFault" name="ResourceUnavailableFault"/>
+ <wsdl:fault
+ message="qman:TerminationTimeChangeRejectedFault" name="TerminationTimeChangeRejectedFault"/>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourcePropertyDocument">
+ <wsdl:input
+ message="qman:GetResourcePropertyDocumentRequest"
+ name="GetResourcePropertyDocumentRequest" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourcePropertyDocument/GetResourcePropertyDocumentRequest"/>
+ <wsdl:output
+ message="qman:GetResourcePropertyDocumentResponse"
+ name="GetResourcePropertyDocumentResponse" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourcePropertyDocument/GetResourcePropertyDocumentResponse"/>
+ <wsdl:fault
+ message="qman:ResourceUnknownFault" name="ResourceUnknownFault"/>
+ <wsdl:fault
+ message="qman:ResourceUnavailableFault" name="ResourceUnavailableFault"/>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourceProperty">
+ <wsdl:input
+ message="qman:GetResourcePropertyRequest"
+ name="GetResourcePropertyRequest" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest"/>
+ <wsdl:output
+ message="qman:GetResourcePropertyResponse"
+ name="GetResourcePropertyResponse" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse"/>
+ <wsdl:fault
+ message="qman:ResourceUnknownFault" name="ResourceUnknownFault"/>
+ <wsdl:fault
+ message="qman:ResourceUnavailableFault" name="ResourceUnavailableFault"/>
+ <wsdl:fault
+ message="qman:InvalidResourcePropertyQNameFault" name="InvalidResourcePropertyQNameFault"/>
+ </wsdl:operation>
+ <wsdl:operation name="GetMultipleResourceProperties">
+ <wsdl:input
+ message="qman:GetMultipleResourcePropertiesRequest"
+ name="GetMultipleResourcePropertiesRequest" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetMultipleResourceProperties/GetMultipleResourcePropertiesRequest"/>
+ <wsdl:output
+ message="qman:GetMultipleResourcePropertiesResponse"
+ name="GetMultipleResourcePropertiesResponse" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetMultipleResourceProperties/GetMultipleResourcePropertiesResponse"/>
+ <wsdl:fault
+ message="qman:ResourceUnknownFault" name="ResourceUnknownFault"/>
+ <wsdl:fault
+ message="qman:ResourceUnavailableFault" name="ResourceUnavailableFault"/>
+ <wsdl:fault
+ message="qman:InvalidResourcePropertyQNameFault" name="InvalidResourcePropertyQNameFault"/>
+ </wsdl:operation>
+ <wsdl:operation name="QueryResourceProperties">
+ <wsdl:input
+ message="qman:QueryResourcePropertiesRequest"
+ name="QueryResourcePropertiesRequest" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/QueryResourceProperties/QueryResourcePropertiesRequest"/>
+ <wsdl:output
+ message="qman:QueryResourcePropertiesResponse"
+ name="QueryResourcePropertiesResponse" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/QueryResourceProperties/QueryResourcePropertiesResponse"/>
+ <wsdl:fault
+ message="qman:ResourceUnknownFault" name="ResourceUnknownFault"/>
+ <wsdl:fault
+ message="qman:ResourceUnavailableFault" name="ResourceUnavailableFault"/>
+ <wsdl:fault
+ message="qman:UnknownQueryExpressionDialectFault" name="UnknownQueryExpressionDialectFault"/>
+ <wsdl:fault
+ message="qman:InvalidQueryExpressionFault" name="InvalidQueryExpressionFault"/>
+ <wsdl:fault
+ message="qman:QueryEvaluationErrorFault" name="QueryEvaluationErrorFault"/>
+ </wsdl:operation>
+ <wsdl:operation name="SetResourceProperties">
+ <wsdl:input
+ message="qman:SetResourcePropertiesRequest"
+ name="SetResourcePropertiesRequest" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/SetResourceProperties/SetResourcePropertiesRequest"/>
+ <wsdl:output
+ message="qman:SetResourcePropertiesResponse"
+ name="SetResourcePropertiesResponse" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/SetResourceProperties/SetResourcePropertiesResponse"/>
+ <wsdl:fault
+ message="qman:ResourceUnknownFault" name="ResourceUnknownFault"/>
+ <wsdl:fault
+ message="qman:ResourceUnavailableFault" name="ResourceUnavailableFault"/>
+ <wsdl:fault
+ message="qman:InvalidModificationFault" name="InvalidModificationFault"/>
+ <wsdl:fault
+ message="qman:UnableToModifyResourcePropertyFault" name="UnableToModifyResourcePropertyFault"/>
+ <wsdl:fault
+ message="qman:InvalidResourcePropertyQNameFault" name="InvalidResourcePropertyQNameFault"/>
+ <wsdl:fault
+ message="qman:SetResourcePropertyRequestFailedFault" name="SetResourcePropertyRequestFailedFault"/>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithSimpleTypes">
+ <wsdl:input
+ message="qman:echoWithSimpleTypesRequestMessage"
+ name="echoWithSimpleTypesRequest" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithSimpleTypes"/>
+ <wsdl:output
+ message="qman:echoWithSimpleTypesResponseMessage"
+ name="echoWithSimpleTypesResponse" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithSimpleTypesResponse"/>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithArrays">
+ <wsdl:input
+ message="qman:echoWithArraysRequestMessage"
+ name="echoWithArraysRequest" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithArrays"/>
+ <wsdl:output
+ message="qman:echoWithArraysResponseMessage"
+ name="echoWithArraysResponse" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithArraysResponse"/>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithSimpleTypeArrays">
+ <wsdl:input
+ message="qman:echoWithSimpleTypeArraysRequestMessage"
+ name="echoWithSimpleTypeArraysRequest" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithSimpleTypeArrays"/>
+ <wsdl:output
+ message="qman:echoWithSimpleTypeArraysResponseMessage"
+ name="echoWithSimpleTypeArraysResponse" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithSimpleTypeArraysResponse"/>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithByteArray">
+ <wsdl:input
+ message="qman:echoWithByteArrayRequestMessage"
+ name="echoWithByteArrayRequest" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithByteArray"/>
+ <wsdl:output
+ message="qman:echoWithByteArrayResponseMessage"
+ name="echoWithByteArrayResponse" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithByteArrayResponse"/>
+ </wsdl:operation>
+ <wsdl:operation name="voidWithoutArguments">
+ <wsdl:input
+ message="qman:voidWithoutArgumentsRequestMessage"
+ name="voidWithoutArgumentsRequest" wsa:action="http://amqp.apache.org/qpid/management/qman/voidWithoutArguments"/>
+ <wsdl:output
+ message="qman:voidWithoutArgumentsResponseMessage"
+ name="voidWithoutArgumentsResponse" wsa:action="http://amqp.apache.org/qpid/management/qman/voidWithoutArgumentsResponse"/>
+ </wsdl:operation>
+ <wsdl:operation name="throwsException">
+ <wsdl:input
+ message="qman:throwsExceptionRequestMessage"
+ name="throwsExceptionRequest" wsa:action="http://amqp.apache.org/qpid/management/qman/throwsException"/>
+ <wsdl:output
+ message="qman:throwsExceptionResponseMessage"
+ name="throwsExceptionResponse" wsa:action="http://amqp.apache.org/qpid/management/qman/throwsExceptionResponse"/>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithUUID">
+ <wsdl:input
+ message="qman:echoWithUUIDRequestMessage"
+ name="echoWithUUIDRequest" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithUUID"/>
+ <wsdl:output
+ message="qman:echoWithUUIDResponseMessage"
+ name="echoWithUUIDResponse" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithUUIDResponse"/>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithMap">
+ <wsdl:input
+ message="qman:echoWithMapRequestMessage"
+ name="echoWithMapRequest" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithMap"/>
+ <wsdl:output
+ message="qman:echoWithMapResponseMessage"
+ name="echoWithMapResponse" wsa:action="http://amqp.apache.org/qpid/management/qman/echoWithMapResponse"/>
+ </wsdl:operation>
+ </wsdl:portType>
+ <wsdl:binding name="QManWsResourceBinding" type="qman:QManWsResourcePortType">
+ <wsdl-soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
+ <wsdl:operation name="GetMetadata">
+ <wsdl-soap:operation soapAction="GetMetadata"/>
+ <wsdl:input>
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="Destroy">
+ <wsdl-soap:operation soapAction="Destroy"/>
+ <wsdl:input name="DestroyRequest">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:input>
+ <wsdl:output name="DestroyResponse">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceNotDestroyedFault">
+ <wsdl-soap:fault
+ name="ResourceNotDestroyedFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ name="ResourceUnknownFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ name="ResourceUnavailableFault" use="literal"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="SetTerminationTime">
+ <wsdl-soap:operation soapAction="SetTerminationTime"/>
+ <wsdl:input name="SetTerminationTimeRequest">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:input>
+ <wsdl:output name="SetTerminationTimeResponse">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:output>
+ <wsdl:fault name="UnableToSetTerminationTimeFault">
+ <wsdl-soap:fault
+ name="UnableToSetTerminationTimeFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ name="ResourceUnknownFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ name="ResourceUnavailableFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="TerminationTimeChangeRejectedFault">
+ <wsdl-soap:fault
+ name="TerminationTimeChangeRejectedFault" use="literal"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourcePropertyDocument">
+ <wsdl-soap:operation soapAction="GetResourcePropertyDocument"/>
+ <wsdl:input name="GetResourcePropertyDocumentRequest">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:input>
+ <wsdl:output name="GetResourcePropertyDocumentResponse">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ name="ResourceUnknownFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ name="ResourceUnavailableFault" use="literal"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourceProperty">
+ <wsdl-soap:operation soapAction="GetResourceProperty"/>
+ <wsdl:input name="GetResourcePropertyRequest">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:input>
+ <wsdl:output name="GetResourcePropertyResponse">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ name="ResourceUnknownFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ name="ResourceUnavailableFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault">
+ <wsdl-soap:fault
+ name="InvalidResourcePropertyQNameFault" use="literal"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="GetMultipleResourceProperties">
+ <wsdl-soap:operation soapAction="GetMultipleResourceProperties"/>
+ <wsdl:input name="GetMultipleResourcePropertiesRequest">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:input>
+ <wsdl:output name="GetMultipleResourcePropertiesResponse">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ name="ResourceUnknownFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ name="ResourceUnavailableFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault">
+ <wsdl-soap:fault
+ name="InvalidResourcePropertyQNameFault" use="literal"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="QueryResourceProperties">
+ <wsdl-soap:operation soapAction="QueryResourceProperties"/>
+ <wsdl:input name="QueryResourcePropertiesRequest">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:input>
+ <wsdl:output name="QueryResourcePropertiesResponse">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ name="ResourceUnknownFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ name="ResourceUnavailableFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="UnknownQueryExpressionDialectFault">
+ <wsdl-soap:fault
+ name="UnknownQueryExpressionDialectFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidQueryExpressionFault">
+ <wsdl-soap:fault
+ name="InvalidQueryExpressionFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="QueryEvaluationErrorFault">
+ <wsdl-soap:fault
+ name="QueryEvaluationErrorFault" use="literal"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="SetResourceProperties">
+ <wsdl-soap:operation soapAction="http://oasis.org/SetResourceProperties"/>
+ <wsdl:input name="SetResourcePropertiesRequest">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:input>
+ <wsdl:output name="SetResourcePropertiesResponse">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ name="ResourceUnknownFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ name="ResourceUnavailableFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidModificationFault">
+ <wsdl-soap:fault
+ name="InvalidModificationFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="UnableToModifyResourcePropertyFault">
+ <wsdl-soap:fault
+ name="UnableToModifyResourcePropertyFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault">
+ <wsdl-soap:fault
+ name="InvalidResourcePropertyQNameFault" use="literal"/>
+ </wsdl:fault>
+ <wsdl:fault name="SetResourcePropertyRequestFailedFault">
+ <wsdl-soap:fault
+ name="SetResourcePropertyRequestFailedFault" use="literal"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="GetMetadata">
+ <wsdl-soap:operation soapAction="http://ws.apache.org/muse/test/wsrf/GetMetadata"/>
+ <wsdl:input name="GetMetadataMsg">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:input>
+ <wsdl:output name="GetMetadataResponseMsg">
+ <wsdl-soap:body
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithSimpleTypes">
+ <wsdl-soap:operation soapAction="http://amqp.apache.org/qpid/management/qman/echoWithSimpleTypes"/>
+ <wsdl:input>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithArrays">
+ <wsdl-soap:operation soapAction="http://amqp.apache.org/qpid/management/qman/echoWithArrays"/>
+ <wsdl:input>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithSimpleTypeArrays">
+ <wsdl-soap:operation soapAction="http://amqp.apache.org/qpid/management/qman/echoWithSimpleTypeArrays"/>
+ <wsdl:input>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithByteArray">
+ <wsdl-soap:operation soapAction="http://amqp.apache.org/qpid/management/qman/echoWithByteArray"/>
+ <wsdl:input>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="voidWithoutArguments">
+ <wsdl-soap:operation soapAction="http://amqp.apache.org/qpid/management/qman/voidWithoutArguments"/>
+ <wsdl:input>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="throwsException">
+ <wsdl-soap:operation soapAction="http://amqp.apache.org/qpid/management/qman/throwsException"/>
+ <wsdl:input>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithUUID">
+ <wsdl-soap:operation soapAction="http://amqp.apache.org/qpid/management/qman/echoWithUUID"/>
+ <wsdl:input>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="echoWithMap">
+ <wsdl-soap:operation soapAction="http://amqp.apache.org/qpid/management/qman/echoWithMap"/>
+ <wsdl:input>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ </wsdl:binding>
+ <wsdl:service name="QManWsResourceService">
+ <wsdl:port binding="qman:QManWsResourceBinding" name="QManWsResourcePort">
+ <wsdl-soap:address location="http://romagazzarini:8080/qman/services/QManWsResource"/>
+ </wsdl:port>
+ </wsdl:service>
+ <message name="echoWithSimpleTypesRequestMessage">
+ <wsdl:part
+ element="qman:echoWithSimpleTypesRequest" name="echoWithSimpleTypesRequest"/>
+ </message>
+ <wsdl:message name="echoWithSimpleTypesResponseMessage">
+ <wsdl:part
+ element="qman:echoWithSimpleTypesResponse" name="echoWithSimpleTypesResponse"/>
+ </wsdl:message>
+ <message name="echoWithArraysRequestMessage">
+ <wsdl:part element="qman:echoWithArraysRequest" name="echoWithArraysRequest"/>
+ </message>
+ <wsdl:message name="echoWithArraysResponseMessage">
+ <wsdl:part element="qman:echoWithArraysResponse" name="echoWithArraysResponse"/>
+ </wsdl:message>
+ <message name="echoWithSimpleTypeArraysRequestMessage">
+ <wsdl:part
+ element="qman:echoWithSimpleTypeArraysRequest" name="echoWithSimpleTypeArraysRequest"/>
+ </message>
+ <wsdl:message name="echoWithSimpleTypeArraysResponseMessage">
+ <wsdl:part
+ element="qman:echoWithSimpleTypeArraysResponse" name="echoWithSimpleTypeArraysResponse"/>
+ </wsdl:message>
+ <message name="echoWithByteArrayRequestMessage">
+ <wsdl:part
+ element="qman:echoWithByteArrayRequest" name="echoWithByteArrayRequest"/>
+ </message>
+ <wsdl:message name="echoWithByteArrayResponseMessage">
+ <wsdl:part
+ element="qman:echoWithByteArrayResponse" name="echoWithByteArrayResponse"/>
+ </wsdl:message>
+ <message name="voidWithoutArgumentsRequestMessage">
+ <wsdl:part
+ element="qman:voidWithoutArgumentsRequest" name="voidWithoutArgumentsRequest"/>
+ </message>
+ <wsdl:message name="voidWithoutArgumentsResponseMessage">
+ <wsdl:part
+ element="qman:voidWithoutArgumentsResponse" name="voidWithoutArgumentsResponse"/>
+ </wsdl:message>
+ <message name="throwsExceptionRequestMessage">
+ <wsdl:part element="qman:throwsExceptionRequest" name="throwsExceptionRequest"/>
+ </message>
+ <wsdl:message name="throwsExceptionResponseMessage">
+ <wsdl:part
+ element="qman:throwsExceptionResponse" name="throwsExceptionResponse"/>
+ </wsdl:message>
+ <message name="echoWithUUIDRequestMessage">
+ <wsdl:part element="qman:echoWithUUIDRequest" name="echoWithUUIDRequest"/>
+ </message>
+ <wsdl:message name="echoWithUUIDResponseMessage">
+ <wsdl:part element="qman:echoWithUUIDResponse" name="echoWithUUIDResponse"/>
+ </wsdl:message>
+ <message name="echoWithMapRequestMessage">
+ <wsdl:part element="qman:echoWithMapRequest" name="echoWithMapRequest"/>
+ </message>
+ <wsdl:message name="echoWithMapResponseMessage">
+ <wsdl:part element="qman:echoWithMapResponse" name="echoWithMapResponse"/>
+ </wsdl:message>
+ </wsdl:definitions>
+ </wsx:MetadataSection>
+ </wsx:Metadata>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:103f564f-7008-8456-042f-095a092444f9</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=0ef67394-e34a-4bff-b0bf-88cf359ba1a0,class=queue,name=1232966356552,objectId=894cddd3-b893-4e2f-94d2-2489f72cbdd6,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourceProperty
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:MgmtPubInterval</wsrf-rp:GetResourceProperty>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:b78625a8-af2f-b542-8001-d7e81d3de1c9</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:103f564f-7008-8456-042f-095a092444f9</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=0ef67394-e34a-4bff-b0bf-88cf359ba1a0,class=queue,name=1232966356552,objectId=894cddd3-b893-4e2f-94d2-2489f72cbdd6,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <qman:MgmtPubInterval xmlns:qman="http://amqp.apache.org/qpid/management/qman">32767</qman:MgmtPubInterval>
+ </wsrf-rp:GetResourcePropertyResponse>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/SetResourceProperties/SetResourcePropertiesRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:0b80a9ca-9e02-1d6b-c0e0-8ceb8560ee6e</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=0ef67394-e34a-4bff-b0bf-88cf359ba1a0,class=queue,name=1232966356552,objectId=894cddd3-b893-4e2f-94d2-2489f72cbdd6,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:SetResourceProperties xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <wsrf-rp:Update>
+ <qman:MgmtPubInterval xmlns:qman="http://amqp.apache.org/qpid/management/qman">12</qman:MgmtPubInterval>
+ </wsrf-rp:Update>
+ </wsrf-rp:SetResourceProperties>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/SetResourceProperties/SetResourcePropertiesResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:ae67ff51-e1c1-f2c3-5243-d54905f3907b</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:0b80a9ca-9e02-1d6b-c0e0-8ceb8560ee6e</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=0ef67394-e34a-4bff-b0bf-88cf359ba1a0,class=queue,name=1232966356552,objectId=894cddd3-b893-4e2f-94d2-2489f72cbdd6,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:SetResourcePropertiesResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2"/>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:0dca61e4-072f-3091-0f38-9a967f14666a</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=0ef67394-e34a-4bff-b0bf-88cf359ba1a0,class=queue,name=1232966356552,objectId=894cddd3-b893-4e2f-94d2-2489f72cbdd6,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourceProperty
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:MgmtPubInterval</wsrf-rp:GetResourceProperty>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:84399474-c5b1-8738-f410-fd86face1599</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:0dca61e4-072f-3091-0f38-9a967f14666a</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=0ef67394-e34a-4bff-b0bf-88cf359ba1a0,class=queue,name=1232966356552,objectId=894cddd3-b893-4e2f-94d2-2489f72cbdd6,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <qman:MgmtPubInterval xmlns:qman="http://amqp.apache.org/qpid/management/qman">12</qman:MgmtPubInterval>
+ </wsrf-rp:GetResourcePropertyResponse>
+ </soap:Body>
+</soap:Envelope>
+
+----------------------------------------------------------------------------------
+Resource has been correctly updated.
+----------------------------------------------------------------------------------
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:8be37e48-b3a5-0e4a-aea3-eda3aad58418</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=0ef67394-e34a-4bff-b0bf-88cf359ba1a0,class=queue,name=1232966356552,objectId=894cddd3-b893-4e2f-94d2-2489f72cbdd6,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourceProperty
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:Type</wsrf-rp:GetResourceProperty>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:b92c8851-d071-204f-6506-3706694cf32e</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:8be37e48-b3a5-0e4a-aea3-eda3aad58418</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=0ef67394-e34a-4bff-b0bf-88cf359ba1a0,class=queue,name=1232966356552,objectId=894cddd3-b893-4e2f-94d2-2489f72cbdd6,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2"/>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/SetResourceProperties/SetResourcePropertiesRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:7917abf6-5c85-7e25-4515-b7f60cd32c39</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=0ef67394-e34a-4bff-b0bf-88cf359ba1a0,class=queue,name=1232966356552,objectId=894cddd3-b893-4e2f-94d2-2489f72cbdd6,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:SetResourceProperties xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <wsrf-rp:Insert>
+ <qman:Type xmlns:qman="http://amqp.apache.org/qpid/management/qman">This is a string.</qman:Type>
+ </wsrf-rp:Insert>
+ </wsrf-rp:SetResourceProperties>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/SetResourceProperties/SetResourcePropertiesResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:0b895a1f-39e5-8739-d9d7-390c5f2eb445</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:7917abf6-5c85-7e25-4515-b7f60cd32c39</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=0ef67394-e34a-4bff-b0bf-88cf359ba1a0,class=queue,name=1232966356552,objectId=894cddd3-b893-4e2f-94d2-2489f72cbdd6,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:SetResourcePropertiesResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2"/>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (outgoing):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://localhost:8080/qman/services/QManWsResource</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:930f39a4-0114-03bd-9921-105579fb4213</wsa:MessageID>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://www.w3.org/2005/08/addressing/role/anonymous</wsa:Address>
+ </wsa:From>
+ <qman-wsa:ResourceId
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ wsa:IsReferenceParameter="true" xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing">Q-MAN: brokerID=0ef67394-e34a-4bff-b0bf-88cf359ba1a0,class=queue,name=1232966356552,objectId=894cddd3-b893-4e2f-94d2-2489f72cbdd6,package=org.apache.qpid</qman-wsa:ResourceId>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourceProperty
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:Type</wsrf-rp:GetResourceProperty>
+ </soap:Body>
+</soap:Envelope>
+
+[CLIENT TRACE] SOAP envelope contents (incoming):
+
+<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
+ <soap:Header>
+ <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/role/anonymous</wsa:To>
+ <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse</wsa:Action>
+ <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:3d3f04ab-3171-da69-08b5-2e74927ee981</wsa:MessageID>
+ <wsa:RelatesTo RelationshipType="wsa:Reply" xmlns:wsa="http://www.w3.org/2005/08/addressing">uuid:930f39a4-0114-03bd-9921-105579fb4213</wsa:RelatesTo>
+ <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
+ <wsa:Address>http://localhost:8080/qman/services/QManWsResource</wsa:Address>
+ <wsa:ReferenceParameters>
+ <qman-wsa:ResourceId wsa:IsReferenceParameter="true"
+ xmlns:qman-wsa="http://amqp.apache.org/qpid/management/qman/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing">Q-MAN: brokerID=0ef67394-e34a-4bff-b0bf-88cf359ba1a0,class=queue,name=1232966356552,objectId=894cddd3-b893-4e2f-94d2-2489f72cbdd6,package=org.apache.qpid</qman-wsa:ResourceId>
+ </wsa:ReferenceParameters>
+ </wsa:From>
+ </soap:Header>
+ <soap:Body>
+ <wsrf-rp:GetResourcePropertyResponse xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2">
+ <qman:Type xmlns:qman="http://amqp.apache.org/qpid/management/qman">This is a string.</qman:Type>
+ </wsrf-rp:GetResourcePropertyResponse>
+ </soap:Body>
+</soap:Envelope>
+
+----------------------------------------------------------------------------------
+Resource has been correctly updated.
+----------------------------------------------------------------------------------
diff --git a/java/management/client/src/example/org/apache/qpid/management/example/AbstractQManExample.java b/java/management/client/src/example/org/apache/qpid/management/example/AbstractQManExample.java
new file mode 100644
index 0000000000..ffa96635a8
--- /dev/null
+++ b/java/management/client/src/example/org/apache/qpid/management/example/AbstractQManExample.java
@@ -0,0 +1,140 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.example;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.muse.ws.addressing.EndpointReference;
+
+/**
+ * Common interface for all QMan related examples.
+ *
+ * @author Andrea Gazzarini
+ */
+public abstract class AbstractQManExample
+{
+ final static String LINE_SEPARATOR = System.getProperty("line.separator","\n");
+ protected final static String PREFIX = "qman";
+
+ /**
+ * Prints out the expected command line of this sample and after that exits.
+ */
+ static void printUsageAndExit(String reason)
+ {
+ StringBuilder builder = new StringBuilder();
+ builder.append("WARNING! Unable to run this sample : ")
+ .append(reason)
+ .append(LINE_SEPARATOR)
+ .append("-------------------------------------------------------------")
+ .append(LINE_SEPARATOR)
+ .append("Expected command line args for this sample are :")
+ .append(LINE_SEPARATOR)
+ .append(LINE_SEPARATOR)
+ .append("1) host : ip or host name where QMan is running.")
+ .append(LINE_SEPARATOR)
+ .append("2) port : port number where QMan is running.")
+ .append(LINE_SEPARATOR)
+ .append("------------------------------------------------------------");
+ System.out.println(builder);
+ System.exit(1);
+ }
+
+ /**
+ * Prints out a description of this example.
+ */
+ abstract void printOutExampleDescription();
+
+ /**
+ * Executes this example.
+ * Note that this is just a template method used to avoid code duplication
+ * (printOutExampleDescription() line) so in order to see how the example
+ * works you should have a look at the concrete implementation of
+ * executeExample(String host, int port).
+ *
+ * @param host the host where QMan is running.
+ * @param port the port where QMan is running.
+ */
+ void execute(String [] arguments)
+ {
+ if (arguments.length != 2){
+ printUsageAndExit("invalid command line was given.");
+ }
+
+ try
+ {
+ // 1) Parses command line arguments...
+ String host = arguments[0];
+ int port = Integer.parseInt(arguments[1]);
+
+ printOutExampleDescription();
+
+ waitForUserInput("Type enter to proceed...");
+
+ executeExample(host, port);
+
+ } catch(NumberFormatException exception)
+ {
+ printUsageAndExit("port number must be a number.");
+ } catch(Exception exception)
+ {
+ System.out.println("-----------------------EXAMPLE FAILURE-----------");
+ System.out.println("Not well-defined exception was detected while");
+ System.out.println("running the example.");
+ exception.printStackTrace(System.out);
+ System.out.println("--------------------------------------------------------");
+ }
+ }
+
+ protected void waitForUserInput(String message) throws IOException {
+ System.out.println(message);
+ System.in.read();
+ }
+
+ /**
+ * Each concrete implementor must define here how the example works.
+ * So, on top of that, user who wants to see how to use a specific feature
+ * should have a look at the concrete implementation of this method..
+ *
+ * @param host the host where QMan is running.
+ * @param port the port where QMan is running.
+ * @throws Exception when the example fails (not at application level).
+ */
+ void executeExample(String host, int port) throws Exception{};
+
+ /**
+ * Returns the endpoint reference of the adapter service.
+ *
+ * @param host ip or host name where the service is running.
+ * @param port the port number of the server where the service is running.
+ * @return the endpoint reference of the adapter service.
+ */
+ EndpointReference getAdapterEndpointReference(String host, int port)
+ {
+ URI address = URI.create(
+ "http://"+
+ host+
+ ":"+
+ port+
+ "/qman/services/adapter");
+ return new EndpointReference(address);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/example/org/apache/qpid/management/example/ConnectWithBrokerExample.java b/java/management/client/src/example/org/apache/qpid/management/example/ConnectWithBrokerExample.java
new file mode 100644
index 0000000000..153f0f66d5
--- /dev/null
+++ b/java/management/client/src/example/org/apache/qpid/management/example/ConnectWithBrokerExample.java
@@ -0,0 +1,240 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.example;
+
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.proxy.ProxyHandler;
+import org.apache.muse.core.proxy.ReflectionProxyHandler;
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.muse.ws.resource.remote.WsResourceClient;
+
+/**
+ * This example shows how to connect QMan with a broker using the adapter interface.
+ * As you can see the interface is very simple and requests you the following parameters :
+ *
+ * <ul>
+ * <li>hostname : the host (hostname or ip) where the broker is running;</li>
+ * <li>port : the port number of the running broker;</li>
+ * <li>virtual host : the name of the virtual host;</li>
+ * <li>username : the username that will be used for estabilshing connection.</li>
+ * <li>password : the password that will be used for estabilshing connection.</li>
+ * <li>initial pool capacity : the initial size of broker connection pool. </li>
+ * <li>maximum pool capacity : the max allowed size of broker connection pool.</li>
+ * <li>maximum wait timeout : the max wait timeout for retrieving connections.</li>
+ * </ul>
+ *
+ * @author Andrea Gazzarini
+ */
+public class ConnectWithBrokerExample extends AbstractQManExample
+{
+
+ /**
+ * Executes the connect example.
+ * Although not specified explicitly, the input array MUST contains in the following order :
+ *
+ * <ul>
+ * <li>host : the hostname where QMan is running;</li>
+ * <li>port : the port number where QMan is running;</li>
+ * <li>qpid host : the host name where QPid is running;</li>
+ * <li>qpid port : the port number where Qpid is running;</li>
+ * <li>virtual host : the virtual host name;</li>
+ * <li>username : the username that will be used for estabilshing connection.</li>
+ * <li>password : the password that will be used for estabilshing connection.</li>
+ * <li>initial pool capacity : the initial size of broker connection pool. </li>
+ * <li>maximum pool capacity : the max allowed size of broker connection pool.</li>
+ * <li>maximum wait timeout : the max wait timeout for retrieving connections.</li>
+ * </ul>
+ *
+ * Note that this example differs from the others (and therefore is overriding the execute() method) because
+ * in this case we are not using the "standard" WSRF interface but instead an additional custom
+ * "operation" on a WS-Resource.
+ *
+ * @param arguments the commadn line arguments.
+ */
+ void execute(String [] arguments)
+ {
+ if (arguments.length != 10){
+ printUsageAndExit("invalid command line was given.");
+ }
+
+ try
+ {
+ // 1) Parses command line arguments...
+ String host = arguments[0];
+ int port = Integer.parseInt(arguments[1]);
+ String qpidHost = arguments[2];
+ int qpidPort = Integer.parseInt(arguments[3]);
+ String virtualHost = arguments[4];
+ String username = arguments[5];
+ String password = arguments[6];
+ int initPoolCapacity = Integer.parseInt(arguments[7]);
+ int maxPoolCapacity = Integer.parseInt(arguments[8]);
+ long maxWaitTimeout = Long.parseLong(arguments[9]);
+
+ printOutExampleDescription();
+
+ waitForUserInput("Type enter to proceed...");
+
+ executeExample(
+ host,
+ port,
+ qpidHost,
+ qpidPort,
+ virtualHost,
+ username,
+ password,
+ initPoolCapacity,
+ maxPoolCapacity,
+ maxWaitTimeout);
+
+ } catch(NumberFormatException exception)
+ {
+ printUsageAndExit("Unable to run the example. Please ensure that all numeric values are correctly supplied.");
+ } catch(Exception exception)
+ {
+ System.out.println("-----------------------EXAMPLE FAILURE-----------");
+ System.out.println("Not well-defined exception was detected while");
+ System.out.println("running the example.");
+ exception.printStackTrace(System.out);
+ System.out.println("--------------------------------------------------------");
+ }
+ }
+
+ /**
+ * Connects QMan with a broker.
+ *
+ *@param host the hostname where QMan is running;
+ *@param port the port number where QMan is running;
+ *@param qpidHost the host name where QPid is running;
+ *@param qpidPort the port number where Qpid is running;
+ *@param virtualHost the virtual host name;
+ *@param username the username that will be used for estabilshing connection.
+ *@param password the password that will be used for estabilshing connection.
+ *@param initPoolCapacity the initial size of broker connection pool.
+ *@param maxPoolCapacity the max allowed size of broker connection pool.
+ *@param maxWaitTimeout the max wait timeout for retrieving connections.
+ *
+ * @throws Exception when the example fails (not at application level).
+ */
+ void executeExample(String host, int port, String qpidHost, int qpidPort, String virtualHost, String username, String password, int initPoolCapacity, int maxPoolCapacity, long maxWaitTimeout) throws Exception
+ {
+ // 1) Creates an endpoint reference of the adapter service...
+ EndpointReference adapterEndpointReference = getAdapterEndpointReference(host, port);
+ WsResourceClient adapterClient = new WsResourceClient(adapterEndpointReference);
+ adapterClient.setTrace(true);
+
+ // 2) Creates the Adapter service client...
+ adapterClient.invoke(
+ getProxyHandler(),
+ new Object[]{
+ qpidHost,
+ qpidPort,
+ username,
+ password,
+ virtualHost,
+ initPoolCapacity,
+ maxPoolCapacity,
+ maxWaitTimeout});
+ }
+
+ /**
+ * Prints out a description of this example.
+ */
+ void printOutExampleDescription()
+ {
+ System.out.println(" "+getClass().getSimpleName()+" ");
+ System.out.println("-------------------------------------------------------------------");
+ System.out.println();
+ System.out.println("This example shows how to connect QMan with a broker using");
+ System.out.println("the adapter interface.");
+ System.out.println();
+ }
+
+ /**
+ * A proxy handler is a module needed in order to make a capability
+ * service invocation.
+ * It contains logic to serialize and deserialize request, response, input and
+ * output parameters during a web service invocation.
+ *
+ * @return a proxy handler.
+ */
+ private ProxyHandler getProxyHandler()
+ {
+ ProxyHandler handler = new ReflectionProxyHandler();
+ handler.setAction("http://amqp.apache.org/qpid/management/qman/Connect");
+ handler.setRequestName(new QName("http://amqp.apache.org/qpid/management/qman", "Connect", PREFIX));
+ handler.setRequestParameterNames(new QName[]{
+ new QName("http://amqp.apache.org/qpid/management/qman", "host", PREFIX),
+ new QName("http://amqp.apache.org/qpid/management/qman", "port", PREFIX),
+ new QName("http://amqp.apache.org/qpid/management/qman", "username", PREFIX),
+ new QName("http://amqp.apache.org/qpid/management/qman", "password", PREFIX),
+ new QName("http://amqp.apache.org/qpid/management/qman", "virtualHost", PREFIX),
+ new QName("http://amqp.apache.org/qpid/management/qman", "initialPoolCapacity", PREFIX),
+ new QName("http://amqp.apache.org/qpid/management/qman", "maxPoolCapacity", PREFIX),
+ new QName("http://amqp.apache.org/qpid/management/qman", "maxWaitTimeout", PREFIX)});
+ handler.setResponseName(new QName("http://amqp.apache.org/qpid/management/qman", "ConnectResponse", PREFIX));
+ handler.setReturnType(null);
+ return handler;
+ }
+
+ public static void main(String[] arguments)
+ {
+ new ConnectWithBrokerExample().execute(arguments);
+ }
+
+ static void printUsageAndExit(String reason)
+ {
+ StringBuilder builder = new StringBuilder();
+ builder.append("WARNING! Unable to run this sample : ")
+ .append(reason)
+ .append(LINE_SEPARATOR)
+ .append("-------------------------------------------------------------")
+ .append(LINE_SEPARATOR)
+ .append("Expected command line args for this sample are :")
+ .append(LINE_SEPARATOR)
+ .append(LINE_SEPARATOR)
+ .append("1) host : ip or host name where QMan is running.")
+ .append(LINE_SEPARATOR)
+ .append("2) port : port number where QMan is running.")
+ .append(LINE_SEPARATOR)
+ .append("3) qpid host : port number where Qpid is running.")
+ .append(LINE_SEPARATOR)
+ .append("4) qpid port : port number where Qpid is running.")
+ .append(LINE_SEPARATOR)
+ .append("5) virtual host : virtual host name.")
+ .append(LINE_SEPARATOR)
+ .append("6) username : port number where QMan is running.")
+ .append(LINE_SEPARATOR)
+ .append("7) password : port number where QMan is running.")
+ .append(LINE_SEPARATOR)
+ .append("8) initial pool capacity : port number where QMan is running.")
+ .append(LINE_SEPARATOR)
+ .append("9) max pool capacity : port number where QMan is running.")
+ .append(LINE_SEPARATOR)
+ .append("10) max wait timeout : port number where QMan is running.")
+ .append(LINE_SEPARATOR)
+
+ .append("------------------------------------------------------------");
+ System.out.println(builder);
+ System.exit(1);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/example/org/apache/qpid/management/example/ConsumerAndProducerExample.java b/java/management/client/src/example/org/apache/qpid/management/example/ConsumerAndProducerExample.java
new file mode 100644
index 0000000000..42587d78ff
--- /dev/null
+++ b/java/management/client/src/example/org/apache/qpid/management/example/ConsumerAndProducerExample.java
@@ -0,0 +1,293 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.example;
+
+import java.net.URI;
+import java.util.Date;
+
+import org.apache.muse.util.xml.XPathUtils;
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.muse.ws.addressing.soap.SoapFault;
+import org.apache.muse.ws.notification.impl.FilterCollection;
+import org.apache.muse.ws.notification.impl.MessagePatternFilter;
+import org.apache.muse.ws.notification.impl.ProducerPropertiesFilter;
+import org.apache.muse.ws.notification.impl.TopicFilter;
+import org.apache.muse.ws.notification.remote.NotificationProducerClient;
+import org.apache.qpid.management.Names;
+
+/**
+ * This example is demonstrating a WS-Notification scenario
+ * when (for simplicity) QMan is at the same time consumer
+ * and producer.
+ *
+ * Basically we have (on producer side) two topics : one for
+ * lifecycle events of object instance (objects created & removed)
+ * and another one for lifecycle of event (events created).
+ *
+ * On consumer side there are many options that you can use in
+ * order to made a sunscription :
+ *
+ * <ul>
+ * <li>you could be an observer of all messages (all topics);</li>
+ * <li>you could be an observer of one specific topic;</li>
+ * <li>
+ * you could be an observer of all messages that match
+ * a condition expressed in XPath;
+ * </li>
+ * </ul>
+ *
+ * All those options are provided with or withour a termination time.
+ * A subscription with a termination time will have a predefined expiry
+ * date while if there's no termination the subscription will never expire.
+ *
+ * @author Andrea Gazzarini
+ *
+ */
+public class ConsumerAndProducerExample extends AbstractQManExample
+{
+ @Override
+ void executeExample(String host, int port) throws Exception
+ {
+ // This is QMan...
+ URI producerURI = URI.create("http://"+host+":"+port+"/qman/services/adapter");
+
+ // ...and this is QMan too! Note that it has an hidden consumer capability that is used in
+ // order to run successfully this example...
+ URI consumerURI = URI.create("http://"+host+":"+port+"/qman/services/consumer");
+
+ EndpointReference producerEPR = new EndpointReference(producerURI);
+ EndpointReference consumerEPR = new EndpointReference(consumerURI);
+
+ // Example 1 : all messages on all topics without termination time.
+ subscribeAllMessagesWithoutTerminationTime(producerEPR,consumerEPR);
+
+ // Example 2 : all messages on all topics with termination time.
+ subscribeAllMessagesWithTerminationTime(producerEPR,consumerEPR);
+
+ // Example 3: Topic filter without termination time.
+ topicSubscriptionWithoutTerminationTime(producerEPR,consumerEPR);
+
+ // Example 4: Topic filter with termination time.
+ topicSubscriptionWithTerminationTime(producerEPR,consumerEPR);
+
+ // Example 5: a MessageFilter is installed in order to listen only for connection events
+ // (connections created or removed). The subscription never expire.
+ allMessagesWithMessageFilterWithoutTerminationTime(producerEPR,consumerEPR);
+
+ // Example 6: a MessageFilter is installed in order to listen only for connection events
+ // (connections created or removed). The subscription will expire in 10 seconds.
+ allMessagesWithMessageFilterAndTerminationTime(producerEPR,consumerEPR);
+
+ // Example 7 : a subscription with more than one filter.
+ complexSubscription(producerEPR, consumerEPR);
+ }
+
+ /**
+ * Makes a subscription on all topics / all messages without an expiry date.
+ *
+ * @param producer the producer endpoint reference.
+ * @param consumer the consumer endpoint reference .
+ * @throws SoapFault when the subscription cannot be made.
+ */
+ private void subscribeAllMessagesWithoutTerminationTime(EndpointReference producer, EndpointReference consumer) throws SoapFault
+ {
+ NotificationProducerClient producerClient = new NotificationProducerClient(producer);
+ producerClient.setTrace(true);
+
+ producerClient.subscribe(
+ consumer, // Consumer Endpoint reference
+ null, // Filter, if null that means "all messages"
+ null); // Termination Time : if null the subscription will never expire.
+ }
+
+ /**
+ * Makes a subscription on all topics / all messages with 10 seconds as termination time.
+ * The subscription will expire after 10 seconds.
+ *
+ * @param producer the producer endpoint reference.
+ * @param consumer the consumer endpoint reference .
+ * @throws SoapFault when the subscription cannot be made.
+ */
+ private void subscribeAllMessagesWithTerminationTime(EndpointReference producer, EndpointReference consumer) throws SoapFault
+ {
+ NotificationProducerClient producerClient = new NotificationProducerClient(producer);
+ producerClient.setTrace(true);
+
+ producerClient.subscribe(
+ consumer, // Consumer Endpoint reference
+ null, // Filter, if null that means "all messages"
+ new Date(System.currentTimeMillis() + 10000)); // Termination Time
+ }
+
+ /**
+ * Makes a subscription on a specifc topic without an expiry date.
+ * Only messages published on the given topic will be delivered to the given consumer.
+ *
+ * @param producer the producer endpoint reference.
+ * @param consumer the consumer endpoint reference .
+ * @throws SoapFault when the subscription cannot be made.
+ */
+ private void topicSubscriptionWithoutTerminationTime(EndpointReference producer, EndpointReference consumer) throws SoapFault
+ {
+ NotificationProducerClient producerClient = new NotificationProducerClient(producer);
+ producerClient.setTrace(true);
+
+ TopicFilter filter = new TopicFilter(Names.EVENTS_LIFECYLE_TOPIC_NAME);
+
+ producerClient.subscribe(
+ consumer, // Consumer Endpoint reference
+ filter, // Topic Filter
+ null); // Termination Time : if null the subscription will never expire.
+ }
+
+ /**
+ * Makes a subscription on a specifc topic with an expiry date.
+ * Only messages published on the given topic will be delivered to the given consumer.
+ * The subscription will end after 10 seconds
+ *
+ * @param producer the producer endpoint reference.
+ * @param consumer the consumer endpoint reference .
+ * @throws SoapFault when the subscription cannot be made.
+ */
+ private void topicSubscriptionWithTerminationTime(EndpointReference producer, EndpointReference consumer) throws SoapFault
+ {
+ NotificationProducerClient producerClient = new NotificationProducerClient(producer);
+ producerClient.setTrace(true);
+
+ TopicFilter filter = new TopicFilter(Names.EVENTS_LIFECYLE_TOPIC_NAME);
+
+ producerClient.subscribe(
+ consumer, // Consumer Endpoint reference
+ filter, // Topic Filter
+ new Date(System.currentTimeMillis() + 10000)); // Termination Time
+ }
+
+ /**
+ * Makes a subscription on all topics with a message filter without an expiry date.
+ *
+ * @param producer the producer endpoint reference.
+ * @param consumer the consumer endpoint reference .
+ * @throws SoapFault when the subscription cannot be made.
+ */
+ private void allMessagesWithMessageFilterWithoutTerminationTime(EndpointReference producer, EndpointReference consumer) throws SoapFault
+ {
+ NotificationProducerClient producerClient = new NotificationProducerClient(producer);
+ producerClient.setTrace(true);
+
+ // Applying this filter will result in a subscription that wll be notified only when a "connection"
+ // object is created or removed
+ MessagePatternFilter filter= new MessagePatternFilter(
+ "/wsnt:NotificationMessage/wsnt:Message/qman:LifeCycleEvent/qman:Resource/qman:Name/text()='connection'", // expression (XPath)
+ XPathUtils.NAMESPACE_URI); // Dialect : the only supported dialect is XPath 1.0
+
+ producerClient.subscribe(
+ consumer, // Consumer Endpoint reference
+ filter, // Message Filter
+ null); // Termination Time : if null the subscription will never expire.
+ }
+
+ /**
+ * Makes a subscription on all topics with a message filter and an expiry date.
+ *
+ * @param producer the producer endpoint reference.
+ * @param consumer the consumer endpoint reference .
+ * @throws SoapFault when the subscription cannot be made.
+ */
+ private void allMessagesWithMessageFilterAndTerminationTime(EndpointReference producer, EndpointReference consumer) throws SoapFault
+ {
+ NotificationProducerClient producerClient = new NotificationProducerClient(producer);
+ producerClient.setTrace(true);
+
+ // Applying this filter will result in a subscription that wll be notified only when a "connection"
+ // object is created or removed
+ MessagePatternFilter filter= new MessagePatternFilter(
+ "/wsnt:NotificationMessage/wsnt:Message/qman:LifeCycleEvent/qman:Resource/qman:Name/text()='connection'", // expression (XPath)
+ XPathUtils.NAMESPACE_URI); // Dialect : the only supported dialect is XPath 1.0
+
+ producerClient.subscribe(
+ consumer, // Consumer Endpoint reference
+ filter, // Message Filter
+ new Date(System.currentTimeMillis() + 10000)); // Termination Time
+ }
+
+ /**
+ * Makes a subscription on a specifc topic with an expiry date.
+ * Only messages published on the given topic will be delivered to the given consumer.
+ * The subscription will end after 10 seconds
+ *
+ * @param producer the producer endpoint reference.
+ * @param consumer the consumer endpoint reference .
+ * @throws SoapFault when the subscription cannot be made.
+ */
+ private void complexSubscription(EndpointReference producer, EndpointReference consumer) throws SoapFault
+ {
+ NotificationProducerClient producerClient = new NotificationProducerClient(producer);
+ producerClient.setTrace(true);
+
+ FilterCollection filter = new FilterCollection();
+
+ TopicFilter topicFilter = new TopicFilter(Names.EVENTS_LIFECYLE_TOPIC_NAME);
+ MessagePatternFilter messageFilter= new MessagePatternFilter(
+ "/wsnt:NotificationMessage/wsnt:Message/qman:LifeCycleEvent/qman:Resource/qman:Name/text()='connection'", // expression (XPath)
+ XPathUtils.NAMESPACE_URI); // Dialect : the only supported dialect is XPath 1.0
+
+ ProducerPropertiesFilter producerFilter = new ProducerPropertiesFilter(
+ "boolean(/*/MgtPubInterval > 100 and /*/MsgTotalEnqueues > 56272)",
+ XPathUtils.NAMESPACE_URI);
+
+ filter.addFilter(topicFilter);
+ filter.addFilter(messageFilter);
+ filter.addFilter(producerFilter);
+
+ producerClient.subscribe(
+ consumer, // Consumer Endpoint reference
+ filter, // Topic Filter
+ new Date(System.currentTimeMillis() + 10000)); // Termination Time
+ }
+
+ @Override
+ void printOutExampleDescription()
+ {
+ System.out.println("This example is demonstrating a WS-Notification scenario ");
+ System.out.println("when (for simplicity) QMan is at the same time consumer ");
+ System.out.println("and producer.");
+ System.out.println();
+ System.out.println("Basically we have (on producer side) two topics : one for");
+ System.out.println("lifecycle events of object instance (objects created & removed) ");
+ System.out.println("and another one for lifecycle of event (events created).");
+ System.out.println();
+ System.out.println("On consumer side there are many options that you can use in");
+ System.out.println("order to made a sunscription :");
+ System.out.println();
+ System.out.println("- you could be an observer of all messages (all topics);");
+ System.out.println("- you could be an observer of one specific topic;");
+ System.out.println("- you could be an observer of all messages that match a condition expressed in XPath;");
+ System.out.println();
+ System.out.println("All those options are provided with or withour a termination time.");
+ System.out.println("A subscription with a termination time will have a predefined expiry");
+ System.out.println("date while if there's no termination the subscription will never expire.");
+ }
+
+ public static void main(String[] args)
+ {
+ new ConsumerAndProducerExample().execute(new String[]{"localhost","8080"});
+ }
+}
diff --git a/java/management/client/src/example/org/apache/qpid/management/example/GetMultipleResourcePropertiesExample.java b/java/management/client/src/example/org/apache/qpid/management/example/GetMultipleResourcePropertiesExample.java
new file mode 100644
index 0000000000..413222a79d
--- /dev/null
+++ b/java/management/client/src/example/org/apache/qpid/management/example/GetMultipleResourcePropertiesExample.java
@@ -0,0 +1,179 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.example;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.proxy.ProxyHandler;
+import org.apache.muse.core.proxy.ReflectionProxyHandler;
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.muse.ws.resource.remote.WsResourceClient;
+import org.apache.muse.ws.resource.sg.remote.ServiceGroupClient;
+import org.w3c.dom.Element;
+
+/**
+ * This example shows how to get properties from a WS-Resource using one request.
+ * First of all a request is send to WS-DM in order to get all registered WS-Resources.
+ * If the returned list is not empty then a GetMetadataRequest is sent to the
+ * first child.
+ * The result metadata descriptor contains all properties names of the target WS-Resource.
+ * Those names are then used for retrieving the corresponding values.
+ *
+ * @author Andrea Gazzarini
+ */
+public class GetMultipleResourcePropertiesExample extends AbstractQManExample
+{
+
+ /**
+ * First of all a request is send to WS-DM in order to get all registered WS-Resources.
+ * If the returned list is not empty then a GetMetadataRequest is sent to the
+ * first child.
+ * The result metadata descriptor contains all properties names of the target WS-Resource.
+ * Those names are then used for retrieving the corresponding values.
+ *
+ * @param host the host where QMan is running.
+ * @param port the port where QMan is running.
+ * @throws Exception when the example fails (not at application level).
+ */
+ void executeExample(String host, int port) throws Exception
+ {
+
+ // 1) Creates an endpoint reference of the adapter service...
+ EndpointReference adapterEndpointReference = getAdapterEndpointReference(host, port);
+
+ // 2) Creates the Adapter service client...
+ ServiceGroupClient adapterClient = new ServiceGroupClient(adapterEndpointReference);
+ adapterClient.setTrace(true);
+
+ // 3) Retrieves the all registered members (QMan WS-Resources)
+ WsResourceClient [] resources = adapterClient.getMembers();
+
+ // Sanity check : we cannot proceed if there are no WS-Resources.
+ if (resources.length == 0)
+ {
+ System.out.println("----------------------------WARNING---------------------------");
+ System.out.println("Cannot proceed with the example... it seems");
+ System.out.println("that there are no managed WS-Resources on QMan.");
+ System.out.println("Please check QMan in order to see that it is really");
+ System.out.println("connected with a broker.");
+ System.out.println("-------------------------------------------------------------------");
+ System.exit(0);
+ }
+
+ // 4) Creates a proxy handler for service invocation.
+ ProxyHandler metadataProxyHandler = createProxyHandler();
+
+ // 5) ..and invokes the GetMetadata on the first member.
+ WsResourceClient wsResourceClient = resources[0];
+ wsResourceClient.setTrace(true);
+
+ // Dialect is RDM for this example
+ String dialect = "http://docs.oasis-open.org/wsrf/rmd-1";
+ Object [] inputParameters = {dialect};
+
+ // RDM is the first element of the returned array.
+ // The first element is a wsx:Metadata containing all resource properties.
+ Element [] metadata = (Element[]) wsResourceClient.invoke(metadataProxyHandler, inputParameters);
+ Element resourceMetadataDescriptor = metadata[0];
+
+ // 6) using XPath navigates xml in order to get the list of all properties.
+ Element [] properties = XmlUtils.findInSubTree(
+ resourceMetadataDescriptor,
+ new QName("http://docs.oasis-open.org/wsrf/rmd-1","Property","wsrmd"));
+ List<QName> names = new ArrayList<QName>();
+
+ for (Element property : properties)
+ {
+
+ String attributeName = property.getAttribute("name"); // = qman:<Attribute Name>
+
+ // For this example we are only interested on qman namespace related properties...
+ if (attributeName.startsWith("qman"))
+ {
+ String attributeNameWithoutPrefix = attributeName.replaceFirst("qman:", ""); // = <Attribute Name>
+
+ names.add(new QName(
+ "http://amqp.apache.org/qpid/management/qman",
+ attributeNameWithoutPrefix,
+ "qman"));
+ }
+ }
+
+ QName [] qnames = names.toArray(new QName[names.size()]);
+
+ // 7) Send a GetMultipleResourcePropertiesRequest.
+ // We do nothing with the returned value(s) because it / they
+ // has / have already printed out (wsResourceClient.setTrace(true))
+ @SuppressWarnings("unused")
+ Element [] values = wsResourceClient.getMultipleResourceProperties(qnames);
+ }
+
+ /**
+ * Prints out a description of this example.
+ */
+ void printOutExampleDescription()
+ {
+ System.out.println(" "+getClass().getSimpleName()+" ");
+ System.out.println("-------------------------------------------------------------------");
+ System.out.println();
+ System.out.println("This example shows how to get properties from a");
+ System.out.println("WS-Resource using one request. ");
+ System.out.println("First of all a request is send to WS-DM in order to get");
+ System.out.println("all registered WS-Resources.");
+ System.out.println("If the returned list is not empty then a GetMetadataRequest");
+ System.out.println("to the first child.");
+ System.out.println("The result metadata descriptor contains all property names of");
+ System.out.println("the target WS-Resource.");
+ System.out.println("Those names are then used for retrieving the corresponding values");
+ System.out.println("using the GetMultipleResourceProperties request.");
+ System.out.println();
+ System.out.println("-------------------------------------------------------------------");
+ System.out.println();
+ }
+
+ /**
+ * A proxy handler is a module needed in order to make a capability
+ * service invocation.
+ * It contains logic to serialize and deserialize request, response, input and
+ * output parameters during a web service invocation.
+ *
+ * @return a proxy handler.
+ */
+ private ProxyHandler createProxyHandler()
+ {
+ ProxyHandler handler = new ReflectionProxyHandler();
+ handler.setAction("http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata");
+ handler.setRequestName(new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "GetMetadata", PREFIX));
+ handler.setRequestParameterNames(new QName[]{new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "Dialect", PREFIX)});
+ handler.setResponseName(new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "Metadata", PREFIX));
+ handler.setReturnType(Element[].class);
+ return handler;
+ }
+
+ public static void main(String[] arguments)
+ {
+ new GetMultipleResourcePropertiesExample().execute(arguments);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/example/org/apache/qpid/management/example/GetQManResourceMembersExample.java b/java/management/client/src/example/org/apache/qpid/management/example/GetQManResourceMembersExample.java
new file mode 100644
index 0000000000..f74a44ab57
--- /dev/null
+++ b/java/management/client/src/example/org/apache/qpid/management/example/GetQManResourceMembersExample.java
@@ -0,0 +1,93 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.example;
+
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.muse.ws.resource.remote.WsResourceClient;
+import org.apache.muse.ws.resource.sg.remote.ServiceGroupClient;
+
+/**
+ * An example demonstrating the usage of GetResourcePropertyRequest/Response on
+ * the WS-DM Adapter.
+ *
+ * @author Andrea Gazzarini
+ */
+public class GetQManResourceMembersExample extends AbstractQManExample
+{
+ /**
+ * Looks for memebers of QMan group requesting ws-rp:Entry property to
+ * WS-DM Adapter resource service.
+ *
+ * @param host the host where QMan is running.
+ * @param port the port where QMan is running.
+ * @throws Exception when the example fails (not at application level).
+ */
+ void executeExample(String host, int port) throws Exception
+ {
+ // 1) Creates an endpoint reference of the adapter service...
+ EndpointReference serviceEndpointReference = getAdapterEndpointReference(host, port);
+
+ // 2) Creates the Service client...
+ ServiceGroupClient adapterClient = new ServiceGroupClient(serviceEndpointReference);
+ adapterClient.setTrace(true);
+
+ // 3) Invokes the service.
+ WsResourceClient [] resources = adapterClient.getMembers();
+
+ String result = (resources.length != 0)
+ ? ("QMan has at the moment "+resources.length+" registered resources.")
+ : "It seems that there are no managed resource on QMan side...";
+
+ System.out.println("--------------------------------------------------------------------------");
+ System.out.println(result);
+ System.out.println("--------------------------------------------------------------------------");
+ }
+
+ /**
+ * Prints out a description of this example.
+ */
+ void printOutExampleDescription()
+ {
+ System.out.println(" "+getClass().getSimpleName()+" ");
+ System.out.println("-------------------------------------------------------------------");
+ System.out.println();
+ System.out.println("This example shows the usage of WS-DM ");
+ System.out.println("GetResourcePropertyRequest / Response on a ");
+ System.out.println("Group service.");
+ System.out.println("The target resource is the WS-DM Adapter itself ");
+ System.out.println("and the requested property is \"wsrf-sg:Entry\".");
+ System.out.println("WS-DM Adapter is a special WS-Resource (is a Group)");
+ System.out.println("that acts as the main entry point for retrieving");
+ System.out.println("all other managed resources.");
+ System.out.println("So clients that want to deal with QMan WS-Resources");
+ System.out.println("must first get resource identifiers sending");
+ System.out.println("a GetResourcePropertyRequest to WS-DM Adapter ");
+ System.out.println("with \"wsrf-sg:Entry\" as target target property.");
+ System.out.println();
+ System.out.println("-------------------------------------------------------------------");
+ System.out.println();
+ }
+
+ public static void main(String[] arguments)
+ {
+ new GetQManResourceMembersExample().execute(arguments);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/example/org/apache/qpid/management/example/GetResourceMetadataDescriptorExample.java b/java/management/client/src/example/org/apache/qpid/management/example/GetResourceMetadataDescriptorExample.java
new file mode 100644
index 0000000000..84befc01e4
--- /dev/null
+++ b/java/management/client/src/example/org/apache/qpid/management/example/GetResourceMetadataDescriptorExample.java
@@ -0,0 +1,156 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.example;
+
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.proxy.ProxyHandler;
+import org.apache.muse.core.proxy.ReflectionProxyHandler;
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.muse.ws.resource.remote.WsResourceClient;
+import org.apache.muse.ws.resource.sg.remote.ServiceGroupClient;
+import org.w3c.dom.Element;
+
+/**
+ * This example shows how to get metadata from a WS-Resource.
+ * The service supports different kinds of metadata.
+ * User who wants to receive metadata of a WS-Resource must
+ * send a GetMetadataRequesta specifying the requested dialect.
+ *
+ * Supported metadata that could be requested are
+ *
+ * <ul>
+ * <li>
+ * WSDL : requested using "http://schemas.xmlsoap.org/wsdl/" as dialect..
+ * <li>
+ * <li>
+ * RDM (Resource Metadata Descriptor) : requested using "http://docs.oasis-open.org/wsrf/rmd-1 "as dialect.
+ * </li>
+ * </ul>
+ *
+ * Note that this example focuses on RDM Metadata only; another example is dedicated to WSDL.
+ *
+ * @author Andrea Gazzarini
+ */
+public class GetResourceMetadataDescriptorExample extends AbstractQManExample
+{
+
+ /**
+ * First, sends a request to WS-DM Adapter in order to get the list of managed resources.
+ * If the list is not empty, then takes the first member and sends it a GetMetadataRequest
+ * in order to get its RDM.
+ *
+ * @param host the host where QMan is running.
+ * @param port the port where QMan is running.
+ * @throws Exception when the example fails (not at application level).
+ */
+ void executeExample(String host, int port) throws Exception
+ {
+
+ // 1) Creates an endpoint reference of the adapter service...
+ EndpointReference adapterEndpointReference = getAdapterEndpointReference(host, port);
+
+ // 2) Creates the Adapter service client...
+ ServiceGroupClient adapterClient = new ServiceGroupClient(adapterEndpointReference);
+ adapterClient.setTrace(true);
+
+ // 3) Retrieves the all registered members (QMan WS-Resources)
+ WsResourceClient [] resources = adapterClient.getMembers();
+
+ // Sanity check : we cannot proceed if there are no WS-Resources.
+ if (resources.length == 0)
+ {
+ System.out.println("----------------------------WARNING---------------------------");
+ System.out.println("Cannot proceed with the example... it seems");
+ System.out.println("that there are no managed WS-Resources on QMan.");
+ System.out.println("Please check QMan in order to see that it is really");
+ System.out.println("connected with a broker.");
+ System.out.println("-------------------------------------------------------------------");
+ System.exit(0);
+ }
+
+ // 4) Creates a proxy handler for service invocation.
+ ProxyHandler metadataProxyHandler = createProxyHandler();
+
+ // 5) ..and invokes the GetMetadata on the first member.
+ WsResourceClient firstMember = resources[0];
+ firstMember.setTrace(true);
+
+ // Dialect is RDM for this example
+ String dialect = "http://docs.oasis-open.org/wsrf/rmd-1";
+ Object [] inputParameters = {dialect};
+
+ // WSDL is the first element of the returned array. We don't need to print out it here
+ // because at this point it should have been already printed out (line 96 : firstMember.setTrace(true))
+ @SuppressWarnings("unused")
+ Element [] metadata = (Element[]) firstMember.invoke(metadataProxyHandler, inputParameters);
+ }
+
+ /**
+ * Prints out a description of this example.
+ */
+ void printOutExampleDescription()
+ {
+ System.out.println(" "+getClass().getSimpleName()+" ");
+ System.out.println("-------------------------------------------------------------------");
+ System.out.println();
+ System.out.println("The example shows how to get metadata from a");
+ System.out.println("WS-Resource.");
+ System.out.println("A QMan WS-Resource has different kinds of metadata.");
+ System.out.println("(see below)");
+ System.out.println("User who wants to receive metadata of a WS-Resource");
+ System.out.println("must send a GetMetadataRequesta specifying the");
+ System.out.println("associated dialect.");
+ System.out.println("Supported metadata that could be requested are : ");
+ System.out.println();
+ System.out.println("- WSDL : in this case dialect is \"http://schemas.xmlsoap.org/wsdl/\";");
+ System.out.println("- RDM (Resource Metadata Descriptor) : in this case dialect is \"http://docs.oasis-open.org/wsrf/rmd-1 \".");
+ System.out.println();
+ System.out.println("Note that this examples focuses on RDM Metadata only;");
+ System.out.println("another one is dedicated to WSDL.");
+ System.out.println("-------------------------------------------------------------------");
+ System.out.println();
+ }
+
+ /**
+ * A proxy handler is a module needed in order to make a capability
+ * service invocation.
+ * It contains logic to serialize and deserialize request, response, input and
+ * output parameters during a web service invocation.
+ *
+ * @return a proxy handler.
+ */
+ private ProxyHandler createProxyHandler()
+ {
+ ProxyHandler handler = new ReflectionProxyHandler();
+ handler.setAction("http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata");
+ handler.setRequestName(new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "GetMetadata", PREFIX));
+ handler.setRequestParameterNames(new QName[]{new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "Dialect", PREFIX)});
+ handler.setResponseName(new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "Metadata", PREFIX));
+ handler.setReturnType(Element[].class);
+ return handler;
+ }
+
+ public static void main(String[] arguments)
+ {
+ new GetResourceMetadataDescriptorExample().execute(arguments);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/example/org/apache/qpid/management/example/GetResourcePropertyDocumentExample.java b/java/management/client/src/example/org/apache/qpid/management/example/GetResourcePropertyDocumentExample.java
new file mode 100644
index 0000000000..56ce81358d
--- /dev/null
+++ b/java/management/client/src/example/org/apache/qpid/management/example/GetResourcePropertyDocumentExample.java
@@ -0,0 +1,111 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.example;
+
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.muse.ws.resource.remote.WsResourceClient;
+import org.apache.muse.ws.resource.sg.remote.ServiceGroupClient;
+import org.w3c.dom.Element;
+
+/**
+ * This example shows how to get the whole property document from a WS-Resource.
+ * Resource property document represents a particular composed structural view of
+ * the resource properties of the WS-Resource.
+ * Let's say that It is a way to get all-in-once the state of the WS-Resource.
+ *
+ * First of all a request is send to WS-DM in order to get all registered WS-Resources.
+ * If the returned list is not empty then a GetResourcePropertyDocumentRequest is
+ * sent to the first child.
+ *
+ * @author Andrea Gazzarini
+ */
+public class GetResourcePropertyDocumentExample extends AbstractQManExample
+{
+
+ /**
+ * First of all a request is send to WS-DM in order to get all registered WS-Resources.
+ * If the returned list is not empty then a GetResourcePropertyDocumentRequest is
+ * sent to the first child.
+ *
+ * @param host the host where QMan is running.
+ * @param port the port where QMan is running.
+ * @throws Exception when the example fails (not at application level).
+ */
+ void executeExample(String host, int port) throws Exception
+ {
+
+ // 1) Creates an endpoint reference of the adapter service...
+ EndpointReference adapterEndpointReference = getAdapterEndpointReference(host, port);
+
+ // 2) Creates the Adapter service client...
+ ServiceGroupClient adapterClient = new ServiceGroupClient(adapterEndpointReference);
+ adapterClient.setTrace(true);
+
+ // 3) Retrieves the all registered members (QMan WS-Resources)
+ WsResourceClient [] resources = adapterClient.getMembers();
+
+ // Sanity check : we cannot proceed if there are no WS-Resources.
+ if (resources.length == 0)
+ {
+ System.out.println("----------------------------WARNING---------------------------");
+ System.out.println("Cannot proceed with the example... it seems");
+ System.out.println("that there are no managed WS-Resources on QMan.");
+ System.out.println("Please check QMan in order to see that it is really");
+ System.out.println("connected with a broker.");
+ System.out.println("-------------------------------------------------------------------");
+ System.exit(0);
+ }
+
+ // 4) ..and invokes the GetMetadata on the first member.
+ WsResourceClient wsResourceClient = resources[0];
+ wsResourceClient.setTrace(true);
+
+ @SuppressWarnings("unused")
+ Element resourcePropertyDocument = wsResourceClient.getResourcePropertyDocument();
+ }
+ /**
+ * Prints out a description of this example.
+ */
+ void printOutExampleDescription()
+ {
+ System.out.println(" "+getClass().getSimpleName()+" ");
+ System.out.println("-------------------------------------------------------------------");
+ System.out.println();
+ System.out.println("This example shows how to get the whole property");
+ System.out.println("document from a WS-Resource.");
+ System.out.println("Resource property document represents a particular ");
+ System.out.println("composed structural view of the resource properties");
+ System.out.println("of the WS-Resource.");
+ System.out.println("First of all a request is send to WS-DM in order to get");
+ System.out.println("all registered WS-Resources.");
+ System.out.println("the target WS-Resource.");
+ System.out.println("If the returned list is not empty then a");
+ System.out.println("GetResourcePropertyDocumentRequest is sent to the first child.");
+ System.out.println();
+ System.out.println("-------------------------------------------------------------------");
+ System.out.println();
+ }
+
+ public static void main(String[] arguments)
+ {
+ new GetResourcePropertyDocumentExample().execute(arguments);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/example/org/apache/qpid/management/example/GetResourcePropertyExample.java b/java/management/client/src/example/org/apache/qpid/management/example/GetResourcePropertyExample.java
new file mode 100644
index 0000000000..28ed1c7925
--- /dev/null
+++ b/java/management/client/src/example/org/apache/qpid/management/example/GetResourcePropertyExample.java
@@ -0,0 +1,172 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.example;
+
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.proxy.ProxyHandler;
+import org.apache.muse.core.proxy.ReflectionProxyHandler;
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.muse.ws.resource.remote.WsResourceClient;
+import org.apache.muse.ws.resource.sg.remote.ServiceGroupClient;
+import org.w3c.dom.Element;
+
+/**
+ * This example shows how to get the property value from a WS-Resource.
+ * First of all a request is send to WS-DM in order to get all registered WS-Resources.
+ * If the returned list is not empty then a GetMetadataRequest is sent to the
+ * first child.
+ * The result metadata descriptor contains all properties of the target WS-Resource.
+ * For each of them a GetResourcePropertyRequest is sent in order to get its value.
+ *
+ * @author Andrea Gazzarini
+ */
+public class GetResourcePropertyExample extends AbstractQManExample
+{
+
+ /**
+ * First, sends a request to WS-DM Adapter in order to get the list of managed resources.
+ * If the list is not empty, then takes the first member and sends it a GetMetadataRequest
+ * in order to get its WSDL.
+ * After that, for each property contained in ResourceMetadataDescriptorm (RDM) a
+ * GetResourcePropertyRequest is sent in order to get its value.
+ *
+ * @param host the host where QMan is running.
+ * @param port the port where QMan is running.
+ * @throws Exception when the example fails (not at application level).
+ */
+ void executeExample(String host, int port) throws Exception
+ {
+
+ // 1) Creates an endpoint reference of the adapter service...
+ EndpointReference adapterEndpointReference = getAdapterEndpointReference(host, port);
+
+ // 2) Creates the Adapter service client...
+ ServiceGroupClient adapterClient = new ServiceGroupClient(adapterEndpointReference);
+ adapterClient.setTrace(true);
+
+ // 3) Retrieves the all registered members (QMan WS-Resources)
+ WsResourceClient [] resources = adapterClient.getMembers();
+
+ // Sanity check : we cannot proceed if there are no WS-Resources.
+ if (resources.length == 0)
+ {
+ System.out.println("----------------------------WARNING---------------------------");
+ System.out.println("Cannot proceed with the example... it seems");
+ System.out.println("that there are no managed WS-Resources on QMan.");
+ System.out.println("Please check QMan in order to see that it is really");
+ System.out.println("connected with a broker.");
+ System.out.println("-------------------------------------------------------------------");
+ System.exit(0);
+ }
+
+ // 4) Creates a proxy handler for service invocation.
+ ProxyHandler metadataProxyHandler = createProxyHandler();
+
+ // 5) ..and invokes the GetMetadata on the first member.
+ WsResourceClient wsResourceClient = resources[0];
+ wsResourceClient.setTrace(true);
+
+ // Dialect is RDM for this example
+ String dialect = "http://docs.oasis-open.org/wsrf/rmd-1";
+ Object [] inputParameters = {dialect};
+
+ // RDM is the first element of the returned array.
+ // The first element is a wsx:Metadata containing all resource properties.
+ Element [] metadata = (Element[]) wsResourceClient.invoke(metadataProxyHandler, inputParameters);
+ Element resourceMetadataDescriptor = metadata[0];
+
+ // 6) using XPath navigates xml in order to get the list of all properties.
+ Element [] properties = XmlUtils.findInSubTree(
+ resourceMetadataDescriptor,
+ new QName("http://docs.oasis-open.org/wsrf/rmd-1","Property","wsrmd"));
+
+ for (Element property : properties)
+ {
+
+ String attributeName = property.getAttribute("name"); // = qman:<Attribute Name>
+
+ // For this example we are only interested on qman namespace related properties...
+ if (attributeName.startsWith("qman"))
+ {
+ String attributeNameWithoutPrefix = attributeName.replaceFirst("qman:", ""); // = <Attribute Name>
+
+ // 7) Send a GetResourcePropertyRequest for the given attribute.
+ // We do nothing with the returned value(s) because it / they
+ // has / have already printed out (wsResourceClient.setTrace(true))
+ @SuppressWarnings("unused")
+ Element [] values = wsResourceClient.getResourceProperty(
+ new QName(
+ "http://amqp.apache.org/qpid/management/qman",
+ attributeNameWithoutPrefix,
+ "qman"));
+ }
+ }
+ }
+
+ /**
+ * Prints out a description of this example.
+ */
+ void printOutExampleDescription()
+ {
+ System.out.println(" "+getClass().getSimpleName()+" ");
+ System.out.println("-------------------------------------------------------------------");
+ System.out.println();
+ System.out.println("This example shows how to get the property value");
+ System.out.println("from a WS-Resource.");
+ System.out.println("First of all a request is send to WS-DM in order to get");
+ System.out.println("all registered WS-Resources.");
+ System.out.println("If the returned list is not empty then a GetMetadataRequest");
+ System.out.println("to the first child.");
+ System.out.println("The result metadata descriptor contains all properties of");
+ System.out.println("the target WS-Resource.");
+ System.out.println("For each of them a GetResourcePropertyRequest is sent");
+ System.out.println(" in order to get its value.");
+ System.out.println();
+ System.out.println("-------------------------------------------------------------------");
+ System.out.println();
+ }
+
+ /**
+ * A proxy handler is a module needed in order to make a capability
+ * service invocation.
+ * It contains logic to serialize and deserialize request, response, input and
+ * output parameters during a web service invocation.
+ *
+ * @return a proxy handler.
+ */
+ private ProxyHandler createProxyHandler()
+ {
+ ProxyHandler handler = new ReflectionProxyHandler();
+ handler.setAction("http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata");
+ handler.setRequestName(new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "GetMetadata", PREFIX));
+ handler.setRequestParameterNames(new QName[]{new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "Dialect", PREFIX)});
+ handler.setResponseName(new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "Metadata", PREFIX));
+ handler.setReturnType(Element[].class);
+ return handler;
+ }
+
+ public static void main(String[] arguments)
+ {
+ new GetResourcePropertyExample().execute(arguments);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/example/org/apache/qpid/management/example/GetWSDLMetadataExample.java b/java/management/client/src/example/org/apache/qpid/management/example/GetWSDLMetadataExample.java
new file mode 100644
index 0000000000..ecda6e8fb1
--- /dev/null
+++ b/java/management/client/src/example/org/apache/qpid/management/example/GetWSDLMetadataExample.java
@@ -0,0 +1,156 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.example;
+
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.proxy.ProxyHandler;
+import org.apache.muse.core.proxy.ReflectionProxyHandler;
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.muse.ws.resource.remote.WsResourceClient;
+import org.apache.muse.ws.resource.sg.remote.ServiceGroupClient;
+import org.w3c.dom.Element;
+
+/**
+ * This example shows how to get metadata from a WS-Resource.
+ * The service supports different kinds of metadata.
+ * User who wants to receive metadata of a WS-Resource must
+ * send a GetMetadataRequesta specifying the requested dialect.
+ *
+ * Supported metadata that could be requested are
+ *
+ * <ul>
+ * <li>
+ * WSDL : requested using "http://schemas.xmlsoap.org/wsdl/" as dialect..
+ * <li>
+ * <li>
+ * RDM (Resource Metadata Descriptor) : requested using "http://docs.oasis-open.org/wsrf/rmd-1 "as dialect.
+ * </li>
+ * </ul>
+ *
+ * Note that this example focuses on WSDL Metadata only; another example is dedicated to RDM.
+ *
+ * @author Andrea Gazzarini
+ */
+public class GetWSDLMetadataExample extends AbstractQManExample
+{
+
+ /**
+ * First, sends a request to WS-DM Adapter in order to get the list of managed resources.
+ * If the list is not empty, then takes the first member and sends it a GetMetadataRequest
+ * in order to get its WSDL.
+ *
+ * @param host the host where QMan is running.
+ * @param port the port where QMan is running.
+ * @throws Exception when the example fails (not at application level).
+ */
+ void executeExample(String host, int port) throws Exception
+ {
+
+ // 1) Creates an endpoint reference of the adapter service...
+ EndpointReference adapterEndpointReference = getAdapterEndpointReference(host, port);
+
+ // 2) Creates the Adapter service client...
+ ServiceGroupClient adapterClient = new ServiceGroupClient(adapterEndpointReference);
+ adapterClient.setTrace(true);
+
+ // 3) Retrieves the all registered members (QMan WS-Resources)
+ WsResourceClient [] resources = adapterClient.getMembers();
+
+ // Sanity check : we cannot proceed if there are no WS-Resources.
+ if (resources.length == 0)
+ {
+ System.out.println("----------------------------WARNING---------------------------");
+ System.out.println("Cannot proceed with the example... it seems");
+ System.out.println("that there are no managed WS-Resources on QMan.");
+ System.out.println("Please check QMan in order to see that it is really");
+ System.out.println("connected with a broker.");
+ System.out.println("-------------------------------------------------------------------");
+ System.exit(0);
+ }
+
+ // 4) Creates a proxy handler for service invocation.
+ ProxyHandler metadataProxyHandler = createProxyHandler();
+
+ // 5) ..and invokes the GetMetadata on the first member.
+ WsResourceClient firstMember = resources[0];
+ firstMember.setTrace(true);
+
+ // Dialect is WSDL for this example
+ String dialect = "http://schemas.xmlsoap.org/wsdl/";
+ Object [] inputParameters = {dialect};
+
+ // WSDL is the first element of the returned array. We don't need to print out it here
+ // because at this point it should have been already printed out (line 96 : firstMember.setTrace(true))
+ @SuppressWarnings("unused")
+ Element [] metadata = (Element[]) firstMember.invoke(metadataProxyHandler, inputParameters);
+ }
+
+ /**
+ * Prints out a description of this example.
+ */
+ void printOutExampleDescription()
+ {
+ System.out.println(" "+getClass().getSimpleName()+" ");
+ System.out.println("-------------------------------------------------------------------");
+ System.out.println();
+ System.out.println("The example shows how to get metadata from a");
+ System.out.println("WS-Resource.");
+ System.out.println("A QMan WS-Resource has different kinds of metadata.");
+ System.out.println("(see below)");
+ System.out.println("User who wants to receive metadata of a WS-Resource");
+ System.out.println("must send a GetMetadataRequesta specifying the");
+ System.out.println("associated dialect.");
+ System.out.println("Supported metadata that could be requested are : ");
+ System.out.println();
+ System.out.println("- WSDL : in this case dialect is \"http://schemas.xmlsoap.org/wsdl/\";");
+ System.out.println("- RDM (Resource Metadata Descriptor) : in this case dialect is \"http://docs.oasis-open.org/wsrf/rmd-1 \".");
+ System.out.println();
+ System.out.println("Note that this examples focuses on WSDL Metadata only;");
+ System.out.println("another one is dedicated to RDM.");
+ System.out.println("-------------------------------------------------------------------");
+ System.out.println();
+ }
+
+ /**
+ * A proxy handler is a module needed in order to make a capability
+ * service invocation.
+ * It contains logic to serialize and deserialize request, response, input and
+ * output parameters during a web service invocation.
+ *
+ * @return a proxy handler.
+ */
+ private ProxyHandler createProxyHandler()
+ {
+ ProxyHandler handler = new ReflectionProxyHandler();
+ handler.setAction("http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata");
+ handler.setRequestName(new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "GetMetadata", PREFIX));
+ handler.setRequestParameterNames(new QName[]{new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "Dialect", PREFIX)});
+ handler.setResponseName(new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "Metadata", PREFIX));
+ handler.setReturnType(Element[].class);
+ return handler;
+ }
+
+ public static void main(String[] arguments)
+ {
+ new GetWSDLMetadataExample().execute(arguments);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/example/org/apache/qpid/management/example/PausableSubscriptionExample.java b/java/management/client/src/example/org/apache/qpid/management/example/PausableSubscriptionExample.java
new file mode 100644
index 0000000000..01a27a16f9
--- /dev/null
+++ b/java/management/client/src/example/org/apache/qpid/management/example/PausableSubscriptionExample.java
@@ -0,0 +1,88 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.example;
+
+import java.net.URI;
+
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.muse.ws.notification.remote.NotificationProducerClient;
+import org.apache.muse.ws.notification.remote.SubscriptionClient;
+
+/**
+ * This example is demonstrating a WS-Notification scenario
+ * when (for simplicity) QMan is at the same time consumer
+ * and producer.
+ *
+ * Specifically the example shows how a requestor can create, pause and resume
+ * a subscription.
+ *
+ * @author Andrea Gazzarini
+ *
+ */
+public class PausableSubscriptionExample extends AbstractQManExample
+{
+ @Override
+ void executeExample(String host, int port) throws Exception
+ {
+ // This is QMan...
+ URI producerURI = URI.create("http://"+host+":"+port+"/qman/services/adapter");
+
+ // ...and this is QMan too! Note that it has an hidden consumer capability that is used in
+ // order to run successfully this example...
+ URI consumerURI = URI.create("http://"+host+":"+port+"/qman/services/consumer");
+
+ EndpointReference producerEPR = new EndpointReference(producerURI);
+ EndpointReference consumerEPR = new EndpointReference(consumerURI);
+
+ NotificationProducerClient producerClient = new NotificationProducerClient(producerEPR);
+ producerClient.setTrace(true);
+
+ // 1) Creates a subscription and gets the corresponding reference.
+ SubscriptionClient subscriptionClient = producerClient.subscribe(
+ consumerEPR, // Consumer Endpoint reference
+ null, // Filter, if null that means "all messages"
+ null); // Termination Time : if null the subscription will never expire.
+ subscriptionClient.setTrace(true);
+
+
+ // 2) Pauses the subscription.
+ subscriptionClient.pauseSubscription();
+
+ // 3) Resumes the subscription.
+ subscriptionClient.resumeSubscription();
+ }
+
+ @Override
+ void printOutExampleDescription()
+ {
+ System.out.println("This example is demonstrating a WS-Notification scenario ");
+ System.out.println("when (for simplicity) QMan is at the same time consumer ");
+ System.out.println("and producer.");
+ System.out.println();
+ System.out.println("Specifically the example shows how a requestor can create,");
+ System.out.println("pause and resume a subscription.");
+ }
+
+ public static void main(String[] args)
+ {
+ new PausableSubscriptionExample().execute(new String[]{"romagazzarini","8080"});
+ }
+}
diff --git a/java/management/client/src/example/org/apache/qpid/management/example/SetResourcePropertyExample.java b/java/management/client/src/example/org/apache/qpid/management/example/SetResourcePropertyExample.java
new file mode 100644
index 0000000000..8aed3101ff
--- /dev/null
+++ b/java/management/client/src/example/org/apache/qpid/management/example/SetResourcePropertyExample.java
@@ -0,0 +1,306 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.example;
+
+import java.lang.reflect.Array;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.proxy.ProxyHandler;
+import org.apache.muse.core.proxy.ReflectionProxyHandler;
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.muse.ws.resource.remote.WsResourceClient;
+import org.apache.muse.ws.resource.sg.remote.ServiceGroupClient;
+import org.w3c.dom.Element;
+
+/**
+ * This example shows how to change the state of a WS-Resource. That means
+ * a SetResourcePropertyRequest is sent to that WS-Resource.
+ * First of all a request is send to WS-DM in order to get all registered WS-Resources.
+ * If the returned list is not empty then two GetMetadataRequests are sent to the
+ * first child (one for WSDL and one for RDM).
+ * The result metadata descriptors are the used to determine :
+ *
+ * <br> What are names of WS-Resouce properties
+ * <br> Their modifiability (read-only or read-write)
+ * <br> Their type
+ *
+ * So a SetResourcePropertyRequest can be sent in order to change the WS-Resource state.
+ * The example is looking for a property that has one of the following datatype :
+ *
+ * <ul>
+ * <li>String</li>
+ * <li>Long</li>
+ * <li>Integer</li>
+ * <li>Short</li>
+ * <li>Double</li>
+ * <li>Float</li>
+ * </ul>
+ *
+ * After the update / insert request has been sent, a GetResourcePropertiesRequest is made
+ * again in order to see if the state has changed correctly.
+ *
+ * @author Andrea Gazzarini
+ */
+public class SetResourcePropertyExample extends AbstractQManExample
+{
+ /**
+ * First of all a request is send to WS-DM in order to get all registered WS-Resources.
+ * If the returned list is not empty then two GetMetadataRequests are sent to the
+ * first child (one for WSDL and one for RDM).
+ * The result metadata descriptors are the used to determine :
+ *
+ * <br> What are names of WS-Resouce properties
+ * <br> Their modifiability (read-only or read-write)
+ * <br> Their type
+ *
+ * So a SetResourcePropertyRequest can be sent in order to change the WS-Resource state.
+ * The example is looking for a property that has one of the following datatype :
+ *
+ * <ul>
+ * <li>String</li>
+ * <li>Long</li>
+ * <li>Integer</li>
+ * <li>Short</li>
+ * <li>Double</li>
+ * <li>Float</li>
+ * </ul>
+ *
+ * After the update / insert request has been sent, a GetResourcePropertiesRequest is made
+ * again in order to see if the state has changed correctly.
+ *
+ * @param host the host where QMan is running.
+ * @param port the port where QMan is running.
+ * @throws Exception when the example fails (not at application level).
+ */
+ void executeExample(String host, int port) throws Exception
+ {
+ // 1) Creates an endpoint reference of the adapter service...
+ EndpointReference adapterEndpointReference = getAdapterEndpointReference(host, port);
+
+ // 2) Creates the Adapter service client...
+ ServiceGroupClient adapterClient = new ServiceGroupClient(adapterEndpointReference);
+ adapterClient.setTrace(false);
+
+ // 3) Retrieves the all registered members (QMan WS-Resources)
+ WsResourceClient [] resources = adapterClient.getMembers();
+
+ // Sanity check : we cannot proceed if there are no WS-Resources.
+ if (resources.length == 0)
+ {
+ System.out.println("----------------------------WARNING---------------------------");
+ System.out.println("Cannot proceed with the example... it seems");
+ System.out.println("that there are no managed WS-Resources on QMan.");
+ System.out.println("Please check QMan in order to see that it is really");
+ System.out.println("connected with a broker.");
+ System.out.println("-------------------------------------------------------------------");
+ System.exit(0);
+ }
+
+ // 4) Creates a proxy handler for service invocation.
+ ProxyHandler metadataProxyHandler = createProxyHandler();
+
+ // 5) ..and invokes the GetMetadata on the first member.
+ WsResourceClient wsResourceClient = resources[0];
+ wsResourceClient.setTrace(true);
+
+ // Resource Metadata Descriptor
+ String dialect = "http://docs.oasis-open.org/wsrf/rmd-1";
+ Object [] inputParameters = {dialect};
+
+ // RDM is the first element of the returned array.
+ // The first element is a wsx:Metadata containing all resource properties.
+ Element [] metadata = (Element[]) wsResourceClient.invoke(metadataProxyHandler, inputParameters);
+ Element resourceMetadataDescriptor = metadata[0];
+
+ // 6) Now we need WSDL in order to catch datatypes
+ dialect = "http://schemas.xmlsoap.org/wsdl/";
+ inputParameters = new Object[]{dialect};
+ metadata = (Element[]) wsResourceClient.invoke(metadataProxyHandler, inputParameters);
+ Element wsdl = metadata[0];
+
+ //7) Defines sample values used for update property.
+ Map<String, Object> sampleValues = new HashMap<String, Object>();
+ sampleValues.put("xsd:string","This is a string.");
+ sampleValues.put("xsd:integer",new Integer(12345));
+ sampleValues.put("xsd:int",new Integer(54321));
+ sampleValues.put("xsd:long",new Integer(12345));
+ sampleValues.put("xsd:double",new Double(12345.6d));
+ sampleValues.put("xsd:float",new Float(123.4f));
+ sampleValues.put("xsd:short",new Short((short)12));
+
+ // 8) using XPath navigates xml in order to get the list of all properties.
+ Element [] properties = XmlUtils.findInSubTree(
+ resourceMetadataDescriptor,
+ new QName("http://docs.oasis-open.org/wsrf/rmd-1","Property","wsrmd"));
+
+ Element [] wsdlElements = XmlUtils.findInSubTree(
+ wsdl,
+ new QName("http://www.w3.org/2001/XMLSchema","element","xsd"));
+
+ // Did we find at least one writable property?
+ boolean atLeastOnePropertyHasBeenFound = false;
+
+ for (Element property : properties)
+ {
+ // Sanity check : if the property is read-only then proceed with next
+ // property.
+ if (!"read-write".equals(property.getAttribute("modifiability")))
+ {
+ continue;
+ }
+
+ String attributeName = property.getAttribute("name"); // = qman:<Attribute Name>
+
+ // For this example we are only interested on qman namespace related properties...
+ if (attributeName.startsWith("qman"))
+ {
+ String attributeNameWithoutPrefix = attributeName.replaceFirst("qman:", ""); // = <Attribute Name>
+
+ for (Element wsdlElement : wsdlElements)
+ {
+ String name = wsdlElement.getAttribute("name");
+ String type = wsdlElement.getAttribute("type");
+ if ((name != null) && (attributeNameWithoutPrefix.equals(name)) && (type != null))
+ {
+ Object newValue = sampleValues.get(type);
+ if (newValue != null)
+ {
+ atLeastOnePropertyHasBeenFound = true;
+
+ inputParameters = new Object[] {newValue};
+
+ // 9) Makes a GetResourcePropertiesRequest in order to get the current value.
+ QName propertyQName = new QName(
+ "http://amqp.apache.org/qpid/management/qman",
+ name,
+ "qman");
+
+ // The returned value is really an array because property shoudl be a multi-value property.
+ // So in order to get its value we need to extract the first value.
+ Object currentValue = wsResourceClient.getPropertyAsObject(propertyQName,newValue.getClass());
+
+ // 10a) If the property is not set (value is null) then an "Insert" request must be sent.
+ if (currentValue == null || Array.getLength(currentValue) == 0)
+ {
+ wsResourceClient.insertResourceProperty(propertyQName,inputParameters);
+ }
+ // 10b) If the property is not null then an "Update" request must be sent.
+ else
+ {
+ wsResourceClient.updateResourceProperty(propertyQName,inputParameters);
+ }
+
+ // 11) Let's query again the resource using GetResourceProperties in order to ensure the
+ // previous property has been properly updated.
+ currentValue = wsResourceClient.getPropertyAsObject(propertyQName,newValue.getClass());
+
+ String resultMessage = (newValue.equals(Array.get(currentValue, 0)))
+ ? "Resource has been correctly updated."
+ : "Something was wrong : resource seems not to be properly updated.";
+
+ System.out.println("----------------------------------------------------------------------------------");
+ System.out.println(resultMessage);
+ System.out.println("----------------------------------------------------------------------------------");
+
+ // Let's stop...one property is enough for this example :)
+ break;
+ }
+ }
+ }
+ if (!atLeastOnePropertyHasBeenFound)
+ {
+ System.out.println("----------------------------------------------------------------------------------");
+ System.out.println("WARNING : This example wasn't able to run because no writable ");
+ System.out.println("property has been found on the target WS-Resource.");
+ System.out.println("----------------------------------------------------------------------------------");
+ }
+ }
+ }
+ }
+
+ /**
+ * Prints out a description of this example.
+ */
+ void printOutExampleDescription()
+ {
+ System.out.println(" "+getClass().getSimpleName()+" ");
+ System.out.println("-------------------------------------------------------------------");
+ System.out.println();
+ System.out.println("This example shows how to change the state of a WS-Resource.");
+ System.out.println("That means a SetResourcePropertyRequest is sent to that");
+ System.out.println("WS-Resource.");
+ System.out.println("First of all a request is send to WS-DM in order to get all");
+ System.out.println("registered WS-Resources.");
+ System.out.println("If the returned list is not empty then two GetMetadataRequests");
+ System.out.println("(one for WSDL and one for RDM) are sent to the first child.");
+ System.out.println("The result metadata descriptors are used for determine :");
+ System.out.println();
+ System.out.println("1) WS-Resource property names;");
+ System.out.println("2) Modifiability (read-only, read-write");
+ System.out.println("3) Datatype;");
+ System.out.println("-------------------------------------------------------------------");
+ System.out.println();
+ System.out.println("So a SetResourcePropertyRequest can be sent in order");
+ System.out.println("to change the WS-Resource state.");
+ System.out.println("The example is looking for a property that has one of the");
+ System.out.println("following datatype :");
+ System.out.println();
+ System.out.println("1) String (xsd:string)");
+ System.out.println("2) Long (xsd:long)");
+ System.out.println("3) Integer (xsd:integer or xsd:int)");
+ System.out.println("4) Double (xsd:double)");
+ System.out.println("5) Float (xsd:float)");
+ System.out.println("6) Short (xsd:short)");
+ System.out.println();
+ System.out.println("After the update / insert request has been sent, a ");
+ System.out.println("GetResourcePropertiesRequest is made again");
+ System.out.println("in order to see if the state has changed correctly.");
+ System.out.println();
+ }
+
+ /**
+ * A proxy handler is a module needed in order to make a capability
+ * service invocation.
+ * It contains logic to serialize and deserialize request, response, input and
+ * output parameters during a web service invocation.
+ *
+ * @return a proxy handler.
+ */
+ private ProxyHandler createProxyHandler()
+ {
+ ProxyHandler handler = new ReflectionProxyHandler();
+ handler.setAction("http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata");
+ handler.setRequestName(new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "GetMetadata", PREFIX));
+ handler.setRequestParameterNames(new QName[]{new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "Dialect", PREFIX)});
+ handler.setResponseName(new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "Metadata", PREFIX));
+ handler.setReturnType(Element[].class);
+ return handler;
+ }
+
+ public static void main(String[] arguments)
+ {
+ new SetResourcePropertyExample().execute(arguments);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/muse.xml b/java/management/client/src/main/java/muse.xml
new file mode 100644
index 0000000000..cf651c34ac
--- /dev/null
+++ b/java/management/client/src/main/java/muse.xml
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<muse xmlns="http://ws.apache.org/muse/descriptor"
+ xmlns:wsrf-sgw="http://docs.oasis-open.org/wsrf/sgw-2"
+ xmlns:qman="http://amqp.apache.org/qpid/management/qman"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://ws.apache.org/muse/descriptor muse-descriptor.xsd">
+ <custom-serializer>
+ <java-serializable-type>java.lang.Object</java-serializable-type>
+ <java-serializer-class>org.apache.qpid.management.wsdm.muse.serializer.ObjectSerializer</java-serializer-class>
+ </custom-serializer>
+ <custom-serializer>
+ <java-serializable-type>java.util.Map</java-serializable-type>
+ <java-serializer-class>org.apache.qpid.management.wsdm.muse.serializer.MapSerializer</java-serializer-class>
+ </custom-serializer>
+ <custom-serializer>
+ <java-serializable-type>java.util.HashMap</java-serializable-type>
+ <java-serializer-class>org.apache.qpid.management.wsdm.muse.serializer.MapSerializer</java-serializer-class>
+ </custom-serializer>
+ <custom-serializer>
+ <java-serializable-type>java.util.UUID</java-serializable-type>
+ <java-serializer-class>org.apache.qpid.management.wsdm.muse.serializer.UUIDSerializer</java-serializer-class>
+ </custom-serializer>
+ <custom-serializer>
+ <java-serializable-type>org.apache.qpid.management.wsdm.capabilities.Result</java-serializable-type>
+ <java-serializer-class>org.apache.qpid.management.wsdm.muse.serializer.InvocationResultSerializer</java-serializer-class>
+ </custom-serializer>
+ <custom-serializer>
+ <java-serializable-type>java.util.Date</java-serializable-type>
+ <java-serializer-class>org.apache.qpid.management.wsdm.muse.serializer.DateSerializer</java-serializer-class>
+ </custom-serializer>
+ <router>
+ <java-router-class>org.apache.muse.ws.resource.impl.WsResourceRouter</java-router-class>
+ <logging>
+ <log-file>log/muse.log</log-file>
+ <log-level>SEVERE</log-level>
+ </logging>
+ <persistence>
+ <java-persistence-class>org.apache.muse.core.routing.RouterFilePersistence</java-persistence-class>
+ <persistence-location>router-entries</persistence-location>
+ </persistence>
+ </router>
+ <resource-type use-router-persistence="true">
+ <context-path>consumer</context-path>
+ <wsdl>
+ <wsdl-file>wsdl/WS-BaseNotification-1_3.wsdl</wsdl-file>
+ <wsdl-port-type xmlns:wsntw="http://docs.oasis-open.org/wsn/bw-2">wsntw:NotificationConsumer</wsdl-port-type>
+ </wsdl>
+ <java-id-factory-class>org.apache.qpid.management.wsdm.common.QManResourceIdFactory</java-id-factory-class>
+ <java-resource-class>org.apache.muse.core.SimpleResource</java-resource-class>
+ <capability>
+ <capability-uri>http://docs.oasis-open.org/wsn/bw-2/NotificationConsumer</capability-uri>
+ <java-capability-class>org.apache.muse.ws.notification.impl.SimpleNotificationConsumer</java-capability-class>
+ </capability>
+ <capability>
+ <capability-uri>http://amqp.apache.org/qpid/management/qman/consumer</capability-uri>
+ <java-capability-class>org.apache.qpid.management.wsdm.capabilities.ConsumerCapability</java-capability-class>
+ </capability>
+ </resource-type>
+ <resource-type>
+ <context-path>SubscriptionManager</context-path>
+ <wsdl>
+ <wsdl-file>wsdl/WS-BaseNotification-1_3.wsdl</wsdl-file>
+ <wsdl-port-type xmlns:wsntw="http://docs.oasis-open.org/wsn/bw-2">wsntw:SubscriptionManager</wsdl-port-type>
+ </wsdl>
+ <java-id-factory-class>org.apache.qpid.management.wsdm.common.QManResourceIdFactory</java-id-factory-class>
+ <java-resource-class>org.apache.muse.ws.resource.impl.SimpleWsResource</java-resource-class>
+ <capability>
+ <capability-uri>http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata</capability-uri>
+ <java-capability-class>org.apache.muse.ws.metadata.impl.SimpleMetadataExchange</java-capability-class>
+ </capability>
+ <capability>
+ <capability-uri>http://docs.oasis-open.org/wsrf/rpw-2/Get</capability-uri>
+ <java-capability-class>org.apache.muse.ws.resource.properties.get.impl.SimpleGetCapability</java-capability-class>
+ </capability>
+ <capability>
+ <capability-uri>http://docs.oasis-open.org/wsn/bw-2/SubscriptionManager</capability-uri>
+ <java-capability-class>org.apache.muse.ws.notification.impl.SimpleSubscriptionManager</java-capability-class>
+ <init-param>
+ <param-name>trace-notifications</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ </capability>
+ <capability>
+ <capability-uri>http://docs.oasis-open.org/wsrf/rlw-2/ImmediateResourceTermination</capability-uri>
+ <java-capability-class>org.apache.muse.ws.resource.lifetime.impl.SimpleImmediateTermination</java-capability-class>
+ </capability>
+ <capability>
+ <capability-uri>http://docs.oasis-open.org/wsrf/rlw-2/ScheduledResourceTermination</capability-uri>
+ <java-capability-class>org.apache.muse.ws.resource.lifetime.impl.SimpleScheduledTermination</java-capability-class>
+ </capability>
+ <init-param>
+ <param-name>validate-wsrp-schema</param-name>
+ <param-value>false</param-value>
+ </init-param>
+ </resource-type>
+ <resource-type use-router-persistence="true">
+ <context-path>adapter</context-path>
+ <wsdl>
+ <wsdl-file>wsdl/QManAdapter.wsdl</wsdl-file>
+ <wsdl-port-type xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:QManAdapterPortType</wsdl-port-type>
+ </wsdl>
+ <java-id-factory-class>org.apache.qpid.management.wsdm.common.QManResourceIdFactory</java-id-factory-class>
+ <java-resource-class>org.apache.muse.ws.resource.impl.SimpleWsResource</java-resource-class>
+ <capability>
+ <capability-uri >http://amqp.apache.org/qpid/management/qman</capability-uri>
+ <java-capability-class>org.apache.qpid.management.wsdm.capabilities.QManAdapterCapability</java-capability-class>
+ </capability>
+ <capability>
+ <capability-uri>http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata</capability-uri>
+ <java-capability-class>org.apache.muse.ws.metadata.impl.SimpleMetadataExchange</java-capability-class>
+ </capability>
+ <capability>
+ <capability-uri>http://docs.oasis-open.org/wsrf/rpw-2/Get</capability-uri>
+ <java-capability-class>org.apache.muse.ws.resource.properties.get.impl.SimpleGetCapability</java-capability-class>
+ </capability>
+ <capability>
+ <capability-uri>http://docs.oasis-open.org/wsrf/rpw-2/Query</capability-uri>
+ <java-capability-class>org.apache.muse.ws.resource.properties.query.impl.SimpleQueryCapability</java-capability-class>
+ </capability>
+ <capability>
+ <capability-uri>http://docs.oasis-open.org/wsrf/sgw-2/ServiceGroup</capability-uri>
+ <java-capability-class>org.apache.muse.ws.resource.sg.impl.SimpleServiceGroup</java-capability-class>
+ </capability>
+ <capability>
+ <capability-uri>http://docs.oasis-open.org/wsn/bw-2/NotificationProducer</capability-uri>
+ <java-capability-class>org.apache.muse.ws.notification.impl.SimpleNotificationProducer</java-capability-class>
+ </capability>
+ <init-param>
+ <param-name>validate-wsrp-schema</param-name>
+ <param-value>false</param-value>
+ </init-param>
+ </resource-type>
+ <resource-type>
+ <context-path>QManWsResource</context-path>
+ <wsdl>
+ <!-- Note that this is not a complete WSDL. It is just a base template where resource specific capabilities wll be added. -->
+ <wsdl-file>wsdl/QManWsResource.wsdl</wsdl-file>
+ <wsdl-port-type xmlns:qman="http://amqp.apache.org/qpid/management/qman">qman:QManWsResourcePortType</wsdl-port-type>
+ </wsdl>
+ <java-id-factory-class>org.apache.qpid.management.wsdm.common.ObjectNameIdFactory</java-id-factory-class>
+ <java-resource-class>org.apache.qpid.management.wsdm.muse.resources.QManWsResource</java-resource-class>
+ <capability>
+ <capability-uri>http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata</capability-uri>
+ <java-capability-class>org.apache.qpid.management.wsdm.capabilities.QManMetadataExchangeCapability</java-capability-class>
+ </capability>
+ <capability>
+ <capability-uri>http://docs.oasis-open.org/wsrf/rpw-2/Get</capability-uri>
+ <java-capability-class>org.apache.muse.ws.resource.properties.get.impl.SimpleGetCapability</java-capability-class>
+ </capability>
+ <capability>
+ <capability-uri>http://docs.oasis-open.org/wsrf/rpw-2/Query</capability-uri>
+ <java-capability-class>org.apache.muse.ws.resource.properties.query.impl.SimpleQueryCapability</java-capability-class>
+ </capability>
+ <capability>
+ <capability-uri>http://docs.oasis-open.org/wsrf/rpw-2/Set</capability-uri>
+ <java-capability-class>org.apache.muse.ws.resource.properties.set.impl.SimpleSetCapability</java-capability-class>
+ </capability>
+ <capability>
+ <capability-uri>http://docs.oasis-open.org/wsrf/rpw-2/Put</capability-uri>
+ <java-capability-class>org.apache.muse.ws.resource.properties.set.impl.SimpleSetCapability</java-capability-class>
+ </capability>
+ </resource-type>
+ <resource-type>
+ <context-path>ServiceGroupEntry</context-path>
+ <wsdl>
+ <wsdl-file>/wsdl/WS-ServiceGroupEntry-1_2.wsdl</wsdl-file>
+ <wsdl-port-type>wsrf-sgw:ServiceGroupEntryPortType</wsdl-port-type>
+ </wsdl>
+ <java-id-factory-class>org.apache.qpid.management.wsdm.common.QManResourceIdFactory</java-id-factory-class>
+ <java-resource-class>org.apache.muse.ws.resource.impl.SimpleWsResource</java-resource-class>
+ <capability>
+ <capability-uri>http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata</capability-uri>
+ <java-capability-class>org.apache.muse.ws.metadata.impl.SimpleMetadataExchange</java-capability-class>
+ </capability>
+ <capability>
+ <capability-uri>http://docs.oasis-open.org/wsrf/rpw-2/Get</capability-uri>
+ <java-capability-class>org.apache.muse.ws.resource.properties.get.impl.SimpleGetCapability</java-capability-class>
+ </capability>
+ <capability>
+ <capability-uri>http://docs.oasis-open.org/wsrf/sgw-2/ServiceGroupEntry</capability-uri>
+ <java-capability-class>org.apache.muse.ws.resource.sg.impl.SimpleEntry</java-capability-class>
+ </capability>
+ <init-param>
+ <param-name>validate-wsrp-schema</param-name>
+ <param-value>false</param-value>
+ </init-param>
+ </resource-type>
+</muse> \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/Messages.java b/java/management/client/src/main/java/org/apache/qpid/management/Messages.java
new file mode 100644
index 0000000000..4f84128fb3
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/Messages.java
@@ -0,0 +1,175 @@
+/*
+*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.management;
+
+/**
+ * Enumerative interfaces containing all QMan messages.
+ *
+ * @author Andrea Gazzarini
+ */
+public interface Messages
+{
+ // MESSAGES
+ String EVENT_SEVERITY_ATTRIBUTE_DESCRIPTION = "Severity level for this event.";
+ String EVENT_TIMESTAMP_ATTRIBUTE_DESCRIPTION = "Current timestamp of this event.";
+ String ACTION_NOT_SUPPORTED="Action %s not supported by resource %s.";
+
+ // INFO
+ String QMAN_000001_STARTING_QMAN = "<QMAN-000001> : Starting Q-Man...";
+ String QMAN_000002_READING_CONFIGURATION = "<QMAN-000002> : Reading Q-Man configuration...";
+ String QMAN_000003_CREATING_MANAGEMENT_CLIENTS = "<QMAN-000003> : Creating management client(s)...";
+ String QMAN_000004_MANAGEMENT_CLIENT_CONNECTED = "<QMAN-000004> : Management client for broker %s successfully connected.";
+ String QMAN_000005_TYPE_MAPPING_CONFIGURED = "<QMAN-000005> : Type mapping : code = %s associated to %s (validator class is %s)";
+ String QMAN_000006_ACCESS_MODE_MAPPING_CONFIGURED = "<QMAN-000006> : Access Mode mapping : code = %s associated to %s";
+ String QMAN_000007_MANAGEMENT_HANDLER_MAPPING_CONFIGURED = "<QMAN-000007> : Management Queue Message Handler Mapping : opcode = %s associated with %s";
+ String QMAN_000008_METHOD_REPLY_HANDLER_MAPPING_CONFIGURED = "<QMAN-000008> : Method-Reply Queue Message Handler Mapping : opcode = %s associated with %s";
+ String QMAN_000009_BROKER_DATA_CONFIGURED = "<QMAN-000009> : Broker configuration %s: %s";
+ String QMAN_000010_INCOMING_SCHEMA = "<QMAN-000010> : Incoming schema for %s::%s.%s";
+ String QMAN_000011_SHUTDOWN_INITIATED = "<QMAN-000011> : The shutdown sequence has been initiated for management client connected with broker %s";
+ String QMAN_000012_MANAGEMENT_CLIENT_SHUT_DOWN = "<QMAN-000012> : Management client connected with broker %s shut down successfully.";
+ String QMAN_000013_METHOD_REPLY_CONSUMER_INSTALLED = "<QMAN-000013> : Method-reply queue consumer has been successfully installed and bound on broker %s.";
+ String QMAN_000014_MANAGEMENT_CONSUMER_INSTALLED ="<QMAN-000014> : Management queue consumer has been successfully installed and bound on broker %s.";
+ String QMAN_000015_MANAGEMENT_QUEUE_DECLARED = "<QMAN-000015> : Management queue with name %s has been successfully declared and bound on broker %s.";
+ String QMAN_000016_METHOD_REPLY_QUEUE_DECLARED = "<QMAN-000016> : Method-reply queue with name %s has been successfully declared and bound on broker %s.";
+ String QMAN_000017_CONSUMER_HAS_BEEN_REMOVED = "<QMAN-000017> : Consumer %s has been removed from broker %s.";
+ String QMAN_000018_QUEUE_UNDECLARED = "<QMAN-000018> : Queue %s has been removed from broker %s.";
+ String QMAN_000019_QMAN_STARTED = "<QMAN-000019> : Q-Man open for e-business.";
+ String QMAN_000020_SHUTTING_DOWN_QMAN = "<QMAN-000020> : Shutting down Q-Man...";
+ String QMAN_000021_SHUT_DOWN = "<QMAN-000021> : Q-Man shut down.";
+ String QMAN_000022_NO_BROKER_CONFIGURED = "<QMAN-000022> : Q-Man has no configured broker : in order to connect with a running one use Q-Man Administration interface.";
+ String QMAN_000023_QMAN_REGISTERED_AS_MBEAN = "<QMAN-000023> : Q-Man service is now available on MBeanServer.";
+
+ String QMAN_000026_WSDM_ADAPTER_STARTS = "<QMAN-000026> : Initializing WS-DM Adapter Environment...";
+ String QMAN_000027_WSDM_ADAPTER_STARTED = "<QMAN-000027> : WS-DM Adapter ready for incoming requests.";
+ String QMAN_000028_TEST_MODULE_NOT_FOUND = "<QMAN-000028> : Qpid emulator not found. Test notifications are disabled.";
+ String QMAN_000029_DEFAULT_URI = "<QMAN-000029> : Default URI will be set to %s";
+ String QMAN_000030_RESOURCE_HAS_BEEN_CREATED = "<QMAN-000030> : New resource instance has been created and registered. Resource id is %s";
+ String QMAN_000031_RESOURCE_HAS_BEEN_REMOVED = "<QMAN-000031> : WS-Resource %s has been removed";
+ String QMAN_000032_EVENTS_LIFECYCLE_TOPIC_HAS_BEEN_CREATED = "<QMAN-000032> : Events lifecycle topic has been created with name %s";
+ String QMAN_000033_OBJECTS_LIFECYCLE_TOPIC_HAS_BEEN_CREATED = "<QMAN-000033> : Objects lifecycle topic has been created with name %s";
+ String QMAN_000034_UNCLASSIFIED_LIFECYCLE_TOPIC_HAS_BEEN_CREATED = "<QMAN-000034> : Unclassified object types lifecycle topic has been created with name %s";
+ String QMAN_000035_WORK_MANAGER_POOL_SIZE = "<QMAN-000035> : Work Manager thread pool size : %s";
+ String QMAN_000036_WORK_MANAGER_MAX_POOL_SIZE = "<QMAN-000036> : Work Manager thread pool max size : %s";
+ String QMAN_000037_WORK_MANAGER_KEEP_ALIVE_TIME = "<QMAN-000035> : Work Manager keep alive time : %s";
+
+ // DEBUG
+ String QMAN_200001_INCOMING_MESSAGE_HAS_BEEN_RECEIVED = "<QMAN-200001> : New incoming message has been received. Message content is %s";
+ String QMAN_200002_OPCODE_HANDLER_ASSOCIATION = "<QMAN-200002> : \"%s\" opcode is associated to handler %s";
+ String QMAN_200003_MESSAGE_FORWARDING = "<QMAN-200003> : Incoming message with \"%s\" as opcode will be forwarded to %s for processing.";
+ String QMAN_200004_MANAGEMENT_QUEUE_NAME = "<QMAN-200004> : Management queue name : %s";
+ String QMAN_200005_METHOD_REPLY_QUEUE_NAME = "<QMAN-200005> : Method-reply queue name : %s";
+ String QMAN_200006_QPID_CONNECTION_RELEASED = "<QMAN-200006> : Connection %s returned to the pool.";
+ String QMAN_200007_TEST_CONNECTION_ON_RESERVE = "<QMAN-200007> : Test connection on reserve. Is valid? %s";
+ String QMAN_200008_CONNECTION_DESTROYED = "<QMAN-200008> : Connection has been destroyed.";
+ String QMAN_200009_CONNECTION_DESTROY_FAILURE = "<QMAN-200009> : Unable to destroy a connection object.";
+ String QMAN_200010_EVENT_MBEAN_REGISTERED = "<QMAN-200010> : Event instance %s::%s::%s successfully registered with MBean Server with name %s";
+ String QMAN_200011_OBJECT_MBEAN_REGISTERED = "<QMAN-200011> : Object instance %s::%s::%s:%s successfully registered with MBean Server with name %s";
+ String QMAN_200012_OBJECT_MBEAN_UNREGISTERED = "<QMAN-200012> : Object instance %s::%s::%s:%s successfully unregistered from MBean Server. Name was %s";
+ String QMAN_200013_ARGUMENT_VALUE_ENCODED = "<QMAN-200013> : Encoded value %S for argument %s. Type is %s";
+ String QMAN_200014_INCOMING_INSTRUMENTATION_DATA = "<QMAN-200014> : Incoming instrumentation data for %s::%s.%s.%s";
+ String QMAN_200015_INCOMING_CONFIGURATION_DATA = "<QMAN-200015> : Incoming configuration data for %s::%s.%s.%s";
+ String QMAN_200016_PROPERTY_DEFINITION_HAS_BEEN_BUILT = "<QMAN-200016> : Property definition for %s::%s.%s has been built.";
+ String QMAN_200017_STATISTIC_DEFINITION_HAS_BEEN_BUILT = "<QMAN-200017> : Statistic definition for %s::%s.%s has been built.";
+ String QMAN_200018_OPTIONAL_PROPERTIES_INFO = "<QMAN-200018> : Class %s::%s.%s has %s optional properties.";
+ String QMAN_200019_EVENT_ARGUMENT_DEFINITION_HAS_BEEN_BUILT = "<QMAN-200019> : Event argument definition for %s::%s.%s has been built.";
+ String QMAN_200020_ENTITY_DEFINITION_HAS_BEEN_BUILT = "<QMAN-200020> : Entity definition has been built (without schema) for %s::%s.%s";
+ String QMAN_200021_INCOMING_EVENT_DATA = "<QMAN-200021> : Incoming data for event %s::%s.%s";
+ String QMAN_200022_VALIDATOR_INSTALLED = "<QMAN-200022> : Validator %s for type %s successfully installed.";
+ String QMAN_200023_VALIDATOR_NOT_FOUND = "<QMAN-200023> : No validator was found for type %s. The default (empty) validator will be used.";
+ String QMAN_200024_MANAGEMENT_MESSAGE_HAS_BEEN_SENT = "<QMAN-200024> : Message has been sent to management exchange. Message content : %s";
+ String QMAN_200025_SUBSCRIPTION_DECLARED = "<QMAN-200025> : New subscription between queue %s and destination %s has been declared.";
+ String QMAN_200026_SUBSCRIPTION_REMOVED = "<QMAN-200026> : Subscription named %s has been removed from remote broker.";
+ String QMAN_200027_QUEUE_DECLARED = "<QMAN-200027> : New queue with name %s has been declared.";
+ String QMAN_200028_QUEUE_REMOVED= "<QMAN-200028> : New queue with name %s has been undeclared.";
+ String QMAN_200029_BINDING_DECLARED = "<QMAN-200029> : New binding with %s as routing key has been declared between queue %s and exchange %s.";
+ String QMAN_200030_BINDING_REMOVED = "<QMAN-200030> : Binding with %s as routing key has been removed between queue %s and exchange %s.";
+ String QMAN_200031_COMPOUND_MESSAGE_CONTAINS = "<QMAN-200031> : Incoming compound message contains %s message(s).";
+ String QMAN_200032_COMMAND_MESSAGE_ROUTING_KEY = "<QMAN-200032> : Command message routing key : %s";
+ String QMAN_200033_CAPABILITY_CLASS_HAS_BEEN_ADDED = "<QMAN-200033> : Capability has been added to this resource. Class is %s while URI is %s.";
+ String QMAN_200034_RMD_NAME = "<QMAN-200034> : Resource Metadata Descriptor name is %s.";
+ String QMAN_200035_RMD_PATH = "<QMAN-200035> : Resource Metadata Descriptor path is %s.";
+ String QMAN_200036_ADDITIONAL_RMD_PROPERTY = "<QMAN-200036> : Additional RMD property : %s";
+ String QMAN_200037_RMD = "<QMAN-200037> : Resource Metadata Descriptor : %s";
+ String QMAN_200038_WSRP = "<QMAN-200038> : WS Resource Properties fragment : %s";
+ String QMAN_200039_DEBUG_JMX_NOTIFICATION = "<QMAN-200039> : %s";
+ String QMAN_200040_WS_ARTIFACTS_CACHED = "<QMAN-200040> : WS Artifacts has been stored on cache with the following id : %s";
+ String QMAN_200041_INCOMING_OBJECT_NAME_AND_DERIVED_KEY = "<QMAN-200041> : Incoming object name : %s, derived search key : %s";
+ String QMAN_200042_REMOVING_RESOURCE = "<QMAN-200042> : WS-Resource %s is going to be removed";
+ String QMAN_200043_GENERATED_ACCESSOR_METHOD = "<QMAN-200043> : Generated accessor method for %s : %s";
+ String QMAN_200044_GENERATED_METHOD = "<QMAN-200044> : Generated method for %s : %s";
+
+ // WARNING
+ String QMAN_300001_MESSAGE_DISCARDED = "<QMAN-300001> : No handler has been configured for processing messages with \"%s\" as opcode. Message will be discarded.";
+ String QMAN_300002_UNKNOWN_SEQUENCE_NUMBER = "<QMAN-300002> : Unable to deal with incoming message because it contains a unknown sequence number (%s).";
+ String QMAN_300003_BROKER_ALREADY_CONNECTED = "<QMAN-300003> : Unable to enlist given broker connection data : QMan is already connected with broker %s";
+ String QMAN_300004_INVALID_CONFIGURATION_FILE = "<QMAN-300004> : The given configuration file (%s) is not valid (it doesn't exist or cannot be read)";
+ String QMAN_300005_QEMU_INITIALIZATION_FAILURE = "<QMAN-300005> : Unable to initialize QEmu module and therefore emulation won't be enabled...";
+
+ String QMAN_300006_OS_MBEAN_FAILURE = "<QMAN-300006> : Unable to retrieve Operating System properties. No values will be displayed for underlying Operation System.";
+ String QMAN_300007_RUNTIME_MBEAN_FAILURE = "<QMAN-300007> : Unable to retrieve Runtime Environment properties. No values will be displayed.";
+
+ // ERROR
+ String QMAN_100001_BAD_MAGIC_NUMBER_FAILURE = "<QMAN-100001> : Message processing failure : incoming message contains a bad magic number (%s) and therefore will be discaded.";
+ String QMAN_100002_MESSAGE_READ_FAILURE = "<QMAN-100002> : Message I/O failure : unable to read byte message content and therefore it will be discarded.";
+ String QMAN_100003_MESSAGE_PROCESS_FAILURE = "<QMAN-100003> : Message processing failure : unknown exception; see logs for more details.";
+ String QMAN_100004_HANDLER_INITIALIZATION_FAILURE = "<QMAN-100004> : Message handler configured for opcode %s thrown an exception in initialization and therefore will be discarded.";
+ String QMAN_100005_CLASS_SCHEMA_PROCESSING_FAILURE = "<QMAN-100005> : Q-Man was unable to process the schema response message.";
+ String QMAN_100006_EVENT_SCHEMA_PROCESSING_FAILURE = "<QMAN-100006> : Q-Man was unable to process the schema response message.";
+ String QMAN_100007_UNABLE_TO_CONNECT_WITH_BROKER = "<QMAN-100007> : Unable to connect with broker located on %s. This broker will be ignored.";
+
+
+ String QMAN_100010_METHOD_INVOCATION_RESULT_FAILURE = "<QMAN-100010> : an exception occurred while storing the result of a method invocation. Sequence number was %s";
+ String QMAN_100011_UNKNOWN_CLASS_KIND = "<QMAN-100011> : Unknwon class kind : %s).";
+ String QMAN_100012_SCHEMA_MESSAGE_PROCESSING_FAILURE = "<QMAN-100012> : Q-Man was unable to process the schema response message.";
+ String QMAN_100013_MBEAN_REGISTRATION_FAILURE = "<QMAN-100013> : Unable to unregister object instance %s.";
+ String QMAN_100014_ATTRIBUTE_DECODING_FAILURE = "<QMAN-100014> : Unable to decode value for attribute %s";
+ String QMAN_100015_UNABLE_TO_SEND_SCHEMA_REQUEST = "<QMAN-100015> : Unable to send a schema request schema for %s.%s";
+ String QMAN_100016_UNABLE_TO_DECODE_FEATURE_VALUE = "<QMAN-100016> : Unable to decode value for %s::%s::%s";
+ String QMAN_100017_UNABLE_TO_CONNECT = "<QMAN-100017>: Cannot connect to broker %s on %s";
+ String QMAN_100018_UNABLE_TO_STARTUP_CORRECTLY = "<QMAN-100018> : Q-Man was unable to startup correctly : see logs for further details.";
+ String QMAN_100019_REQ_OR_RES_MALFORMED = "<QMAN-100019> : Unexpected exception occurred on WSDM adapter layer : probably request or response was malformed.";
+ String QMAN_100020_ACTION_NOT_SUPPORTED = "<QMAN-100020> : "+ACTION_NOT_SUPPORTED;
+ String QMAN_100021_RMD_BUID_FAILURE = "<QMAN-100021> : Unable to build RDM for resource %s.";
+
+ String QMAN_100023_BUILD_WS_ARTIFACTS_FAILURE = "<QMAN-100023> : Unable to build WS artifacts.";
+ String QMAN_100024_CAPABILITY_INSTANTIATION_FAILURE = "<QMAN-100024> : Unable to instantiate generated capability class for %s.";
+ String QMAN_100025_WSRF_FAILURE = "<QMAN-100025> : Resource manager raised an exception while creating capability for %s.";
+ String QMAN_100026_SOAP_ADDRESS_REPLACEMENT_FAILURE = "<QMAN-100026> : Exception occurred while replacing the placeholder soap address with resource actual location.";
+ String QMAN_100027_RESOURCE_SHUTDOWN_FAILURE = "<QMAN-100027> : Shutdown failure while destroying resource %s.";
+ String QMAN_100029_MALFORMED_RESOURCE_URI_FAILURE = "<QMAN-100029> : Unable to define URI for QMan resources using \"%s\". It violates RFC 2396";
+ String QMAN_100030_JMX_CORE_STARTUP_FAILURE = "<QMAN-100030> : QMan JMX core Unexpected failure while starting up.";
+ String QMAN_100031_WS_RESOURCE_ALREADY_INITIALIZED = "<QMAN-100031> : Bad request has been received on this WS-Resource : Initialization is not possible because the resource has already been initialized.";
+ String QMAN_100032_WS_RESOURCE_NOT_YET_INITIALIZED = "<QMAN-100032> : Bad request has been received on this WS-Resource : Shutdown is not possible because the resource hasn't yet been initialized.";
+ String QMAN_100033_WS_RESOURCE_ALREADY_SHUTDOWN = "<QMAN-100033> : Bad request has been received on this WS-Resource : Shutdown is not possible because the resource has already been shutdown.";
+ String QMAN_100034_WSDL_SCHEMA_SECTION_NOT_FOUND = "<QMAN-100034> : Unable to get via XPath the schema section in WSDL.";
+ String QMAN_100035_RESOURCE_CAPABILITY_INVOCATION_FAILURE = "<QMAN-100035> : Resource thrown a failure while invoking a capability operation.";
+ String QMAN_100036_TOPIC_DECLARATION_FAILURE = "<QMAN-100036> : WS-DM Adapter was unable to declare events and / or objects lifecycle topic(s). As conseguence of that, QMan won't be able to correctly emit lifecycle notifications.";
+
+ // NEW
+ String QMAN_100035_GET_ATTRIBUTE_FAILURE = "<QMAN-100035> : Get Attribute invocation failure for attribute %s, resource %s.";
+ String QMAN_100036_SET_ATTRIBUTE_FAILURE = "<QMAN-100036> : Set Attribute invocation failure for attribute %s, resource %s.";
+ String QMAN_100037_INVOKE_OPERATION_FAILURE = "<QMAN-100037> : Operation Invocation failure for operation.";
+ String QMAN_100038_UNABLE_TO_SEND_WS_NOTIFICATION = "<QMAN-100038> : Unable to send notification.";
+ String QMAN_100039_UNABLE_TO_CONFIGURE_PROPERLY_WORKER_MANAGER = "<QMAN-100039> : Unable to properly configure WorkManager. A malformed property (NaN) was given as input parameter.";
+ String QMAN_100040_UNABLE_TO_LOCATE_WSRP_PROPERTIES = "<QMAN-100040> : Unable to evaluate the WSRP XPath expression on resource WSDL.";
+
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/Names.java b/java/management/client/src/main/java/org/apache/qpid/management/Names.java
new file mode 100644
index 0000000000..d3ce711d5d
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/Names.java
@@ -0,0 +1,216 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management;
+
+import javax.management.ObjectName;
+import javax.xml.namespace.QName;
+
+/**
+ * Enumeration of literal strings to avoid code duplication.
+ */
+public abstract class Names
+{
+ public static String MANAGEMENT_EXCHANGE = "qpid.management";
+ public static String MANAGEMENT_ROUTING_KEY = "console.#";
+
+ public static String MANAGEMENT_QUEUE_PREFIX = "management.";
+ public static String METHOD_REPLY_QUEUE_PREFIX = "reply.";
+
+ public static String AMQ_DIRECT_QUEUE = "amq.direct";
+ public static String AGENT_ROUTING_KEY_PREFIX = "agent.";
+ public static String AGENT_ROUTING_KEY = AGENT_ROUTING_KEY_PREFIX+"1.0";
+
+ public static String APPLICATION_NAME ="Q-Man";
+
+ // Attributes
+ public static String PACKAGE = "package";
+ public static String CLASS = "class";
+ public static String EVENT = "event";
+ public static String OBJECT_ID="objectId";
+ public static String BROKER_ID = "brokerId";
+ public static String DOMAIN_NAME = "Q-MAN";
+
+ public static String ARG_COUNT_PARAM_NAME = "argCount";
+ public static String DEFAULT_PARAM_NAME ="default";
+
+ public static String NUMBER_VALIDATOR = "org.apache.qpid.management.domain.model.QpidProperty$NumberValidator";
+ public static String STRING_VALIDATOR = "org.apache.qpid.management.domain.model.QpidProperty$StringValidator";
+
+ public static String QMAN_CONFIG_OPTION_NAME = "qman-config";
+
+ public static String ADD_BROKER_OPERATION_NAME = "addBroker";
+
+ public static String NOT_AVAILABLE = "N.A.";
+
+ public static ObjectName QPID_EMULATOR_OBJECT_NAME;
+ static
+ {
+ try
+ {
+ QPID_EMULATOR_OBJECT_NAME = new ObjectName(
+ new StringBuilder()
+ .append(DOMAIN_NAME)
+ .append(':')
+ .append("Name=Qpid,Type=Emulator")
+ .toString());
+ } catch(Exception exception)
+ {
+ throw new ExceptionInInitializerError(exception);
+ }
+ }
+
+ public static ObjectName QMAN_OBJECT_NAME;
+ static
+ {
+ try
+ {
+ QMAN_OBJECT_NAME = new ObjectName(
+ new StringBuilder()
+ .append(DOMAIN_NAME)
+ .append(':')
+ .append("Name=QMan,Type=Service")
+ .toString());
+ } catch(Exception exception)
+ {
+ throw new ExceptionInInitializerError(exception);
+ }
+ }
+
+ // WSDM Stuff
+ public static String NAMESPACE_URI = "http://amqp.apache.org/qpid/management/qman";
+ public final static String PREFIX = "qman";
+
+ public static String ADDRESSING_URI = "http://amqp.apache.org/qpid/management/qman/addressing";
+ public static String ADDRESSING_PREFIX = "qman-wsa";
+
+ public static final QName RESOURCE_ID_QNAME = new QName(
+ ADDRESSING_URI,
+ "ResourceId",
+ ADDRESSING_PREFIX);
+
+ public static final QName RES_ID_QNAME = new QName(
+ NAMESPACE_URI,
+ "ResourceId",
+ PREFIX);
+
+ public static final QName RESOURCE_QNAME = new QName(
+ NAMESPACE_URI,
+ "Resource",
+ PREFIX);
+
+ public static final QName LIFECYCLE_EVENT_QNAME = new QName(
+ NAMESPACE_URI,
+ "LifeCycleEvent",
+ PREFIX);
+
+ public static final QName PACKAGE_NAME_QNAME = new QName(
+ NAMESPACE_URI,
+ "PackageName",
+ PREFIX);
+
+ public static final QName ENTITY_NAME_QNAME = new QName(
+ NAMESPACE_URI,
+ "Name",
+ PREFIX);
+
+ public static final String TIMEMILLIS_ATTRIBUTE_NAME="TimeMillis";
+
+ public final static String QMAN_RESOURCE_NAME = "QManWsResource";
+
+ public final static String VALIDATE_WSRP_PARAM = "validate-wsrp-schema";
+
+ public static final String WEB_APP_CLASSES_FOLDER = "/WEB-INF/classes";
+
+
+ public final static QName QMAN_RESOURCE_PORT_TYPE_NAME = new QName(
+ Names.NAMESPACE_URI,
+ "QManWsResourcePortType",
+ Names.PREFIX);
+
+ public final static QName QMAN_STATUS_TEXT_NAME = new QName(
+ Names.NAMESPACE_URI,
+ "Message",
+ Names.PREFIX);
+
+ public final static QName QMAN_STATUS_CODE_NAME = new QName(
+ Names.NAMESPACE_URI,
+ "ReturnCode",
+ Names.PREFIX);
+
+ public final static QName QMAN_STATUS_ATTRIBUTE_NAME= new QName(
+ Names.NAMESPACE_URI,
+ "AttributeName",
+ Names.PREFIX);
+
+ public final static QName OBJECTS_LIFECYLE_TOPIC_NAME= new QName(
+ Names.NAMESPACE_URI,
+ "ObjectsLifeCycleTopic",
+ Names.PREFIX);
+
+ public final static QName EVENTS_LIFECYLE_TOPIC_NAME= new QName(
+ Names.NAMESPACE_URI,
+ "EventsLifeCycleTopic",
+ Names.PREFIX);
+
+ public final static QName HOST_QNAME = new QName(
+ Names.NAMESPACE_URI,
+ "host",
+ Names.PREFIX);
+
+ public final static QName PORT_QNAME = new QName(
+ Names.NAMESPACE_URI,
+ "port",
+ Names.PREFIX);
+
+ public final static QName USERNAME_QNAME= new QName(
+ Names.NAMESPACE_URI,
+ "username",
+ Names.PREFIX);
+
+ public final static QName VIRTUAL_HOST_QNAME= new QName(
+ Names.NAMESPACE_URI,
+ "virtualHost",
+ Names.PREFIX);
+
+ public final static QName UNKNOWN_OBJECT_TYPE_LIFECYLE_TOPIC_NAME= new QName(
+ Names.NAMESPACE_URI,
+ "UnclassifiedLifeCycleTopic",
+ Names.PREFIX);
+
+
+ public final static String NAME_ATTRIBUTE = "name";
+ public final static String MODIFIABILITY = "modifiability";
+ public final static String READ_WRITE = "read-write";
+ public final static String READ_ONLY = "read-only";
+ public final static String MUTABILITY = "mutability";
+ public final static String MUTABLE = "mutable";
+
+ public final static String ENTRY = "entry";
+ public final static String KEY = "key";
+ public final static String VALUE = "value";
+ public final static String TYPE = "type";
+ public final static String XSI_TYPE = "xsi:"+TYPE;
+
+ public final static String ADAPTER_HOST_PROPERTY_NAME = "qman.host";
+ public final static String ADAPTER_PORT_PROPERTY_NAME = "qman.port";
+
+
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/Protocol.java b/java/management/client/src/main/java/org/apache/qpid/management/Protocol.java
new file mode 100644
index 0000000000..c1b1ceb5b4
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/Protocol.java
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management;
+
+/**
+ * Protocol defined constants.
+ *
+ * @author Andrea Gazzarini
+ */
+public interface Protocol
+{
+ String MAGIC_NUMBER = "AM2";
+
+ char SCHEMA_REQUEST_OPCODE = 'S';
+ char SCHEMA_RESPONSE_OPCODE = Character.toLowerCase(SCHEMA_REQUEST_OPCODE);
+
+ char OPERATION_INVOCATION_REQUEST_OPCODE = 'M';
+ char OPERATION_INVOCATION_RESPONSE_OPCODE = Character.toLowerCase(OPERATION_INVOCATION_REQUEST_OPCODE);
+
+ char INSTRUMENTATION_CONTENT_RESPONSE_OPCODE = 'i';
+ char CONFIGURATION_CONTENT_RESPONSE_OPCDE = 'c';
+ char EVENT_CONTENT_RESPONSE_OPCDE = 'e';
+ char INSTR_AND_CONFIG_CONTENT_RESPONSE_OPCODE = 'g';
+
+ char HEARTBEAT_INDICATION_RESPONSE_OPCODE = 'h';
+
+ int CLASS = 1;
+ int EVENT = 2;
+
+ String DEFAULT_QMAN_HOSTNAME = "localhost";
+ int DEFAULT_QMAN_PORT_NUMBER = 8080;
+
+ String DEFAULT_ENDPOINT_URI = "http://localhost:8080/qman/services/adapter";
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerAlreadyConnectedException.java b/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerAlreadyConnectedException.java
new file mode 100644
index 0000000000..f23bf9d25e
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerAlreadyConnectedException.java
@@ -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 org.apache.qpid.management.configuration;
+
+/**
+ * Thrown when an attempt is made in order to connect QMan with an already connected broker.
+ *
+ * @author Andrea Gazzarini
+ */
+public class BrokerAlreadyConnectedException extends Exception {
+
+ private static final long serialVersionUID = -5082431738056504669L;
+
+ private BrokerConnectionData _connectionData;
+
+ /**
+ * Builds a new exception with the given data.
+ *
+ * @param connectionData the broker connection data.
+ */
+ public BrokerAlreadyConnectedException(BrokerConnectionData connectionData) {
+ this._connectionData = connectionData;
+ }
+
+ /**
+ * Returns the connection data of the connected broker.
+ *
+ * @return the connection data of the connected broker.
+ */
+ public BrokerConnectionData getBrokerConnectionData()
+ {
+ return _connectionData;
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerConnectionData.java b/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerConnectionData.java
new file mode 100644
index 0000000000..b796620747
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerConnectionData.java
@@ -0,0 +1,270 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.configuration;
+
+/**
+ * Value object which is holding connection data for a specific broker.
+ *
+ * @author Andrea Gazzarini
+ */
+public class BrokerConnectionData
+{
+ private String _host;
+ private int _port;
+ private String _virtualHost;
+ private String _username;
+ private String _password;
+ private int _maxPoolCapacity;
+ private int _initialPoolCapacity;
+ private long _maxWaitTimeout;
+
+ /**
+ * Builds a connection data with the given parameters.
+ *
+ * @param host the hostname where the broker is running.
+ * @param port the port where the broker is running.
+ * @param username the username for connecting with the broker.
+ * @param password the password for connecting with the broker.
+ * @param virtualHost the virtual host.
+ * @param initialPoolCapacity the number of connections that must be immediately opened.
+ * @param maxPoolCapacity the maximum number of opened connection.
+ * @param maxWaitTimeout the maximum amount of time that a client will wait for obtaining a connection.
+ */
+ public BrokerConnectionData(
+ String host,
+ int port,
+ String virtualHost,
+ String username,
+ String password,
+ int initialPoolCapacity,
+ int maxPoolCapacity,
+ long waitTimeout) {
+
+ this._host = host;
+ this._port = port;
+ this._virtualHost = virtualHost;
+ this._username = username;
+ this._password = password;
+ _maxPoolCapacity = maxPoolCapacity;
+ _initialPoolCapacity = initialPoolCapacity;
+ _maxWaitTimeout = waitTimeout;
+ }
+
+ /**
+ * Builds a new empty broker connection data object.
+ */
+ BrokerConnectionData()
+ {
+ }
+
+ /**
+ * Sets the value of host property for this connection data.
+ *
+ * @param host the host name.
+ */
+ void setHost (String host)
+ {
+ this._host = host;
+ }
+
+ /**
+ * Sets the value of port property for this connection data.
+ *
+ * @param port the port.
+ */
+ void setPort (String port)
+ {
+ this._port = Integer.parseInt(port);
+ }
+
+ /**
+ * Sets the value of virtual host property for this connection data.
+ *
+ * @param virtualHost the virtual host.
+ */
+ void setVirtualHost (String virtualHost)
+ {
+ this._virtualHost = virtualHost;
+ }
+
+ /**
+ * Sets the value of username property for this connection data.
+ *
+ * @param username the username.
+ */
+ void setUsername(String username)
+ {
+ this._username = username;
+ }
+
+ /**
+ * Sets the value of password property for this connection data.
+ *
+ * @param password the password.
+ */
+ void setPassword(String password)
+ {
+ this._password = password;
+ }
+
+ /**
+ * Returns the value of the host property.
+ *
+ * @return the value of the host property.
+ */
+ public String getHost ()
+ {
+ return _host;
+ }
+
+ /**
+ * Returns the value of the port property.
+ *
+ * @return the value of the port property.
+ */
+ public int getPort ()
+ {
+ return _port;
+ }
+
+ /**
+ * Returns the value of the virtual host property.
+ *
+ * @return the value of the virtual host property.
+ */
+ public String getVirtualHost ()
+ {
+ return _virtualHost;
+ }
+
+ /**
+ * Returns the value of the username property.
+ *
+ * @return the value of the username property.
+ */
+ public String getUsername ()
+ {
+ return _username;
+ }
+
+ /**
+ * Returns the value of the password property.
+ *
+ * @return the value of the password property.
+ */
+ public String getPassword ()
+ {
+ return _password;
+ }
+
+ // sofia:5663@pippo/sung1
+ @Override
+ public String toString ()
+ {
+ return new StringBuilder()
+ .append(_host)
+ .append(':')
+ .append(_port)
+ .append('@')
+ .append(_virtualHost)
+ .toString();
+ }
+
+ /**
+ * Sets the max number of allowed connections that can be opened.
+ *
+ * @param value the max number of allowed connections that can be opened.
+ * @throws NumberFormatException if the given value is not a valid integer.
+ */
+ public void setMaxPoolCapacity (String value)
+ {
+ _maxPoolCapacity = Integer.parseInt(value);
+ }
+
+ /**
+ * Sets the max wait timeout for retrieving an available connections from the pool.
+ *
+ * @param value the max wait timeout for retrieving an available connections from the pool..
+ * @throws NumberFormatException if the given value is not a valid long.
+ */
+ public void setMaxWaitTimeout (String value)
+ {
+ this._maxWaitTimeout = Long.parseLong(value);
+ }
+
+ /**
+ * Returns the max number of allowed connections that can be opened.
+ *
+ * @return the max number of allowed connections that can be opened.
+ */
+ public int getMaxPoolCapacity ()
+ {
+ return _maxPoolCapacity;
+ }
+
+ /**
+ * Returns the max wait timeout for retrieving an available connections from the pool.
+ *
+ * @return the max wait timeout for retrieving an available connections from the pool.
+ */
+ public long getMaxWaitTimeout ()
+ {
+ return _maxWaitTimeout;
+ }
+
+ /**
+ * Sets the initial connection pool capacity.
+ *
+ * @param capacity the initial connection pool capacity.
+ */
+ public void setInitialPoolCapacity (String capacity)
+ {
+ _initialPoolCapacity = Integer.parseInt(capacity);
+ }
+
+ /**
+ * Returns the initial connection pool capacity.
+ *
+ * @return the initial connection pool capacity.
+ */
+ public int getInitialPoolCapacity ()
+ {
+ return _initialPoolCapacity;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ try
+ {
+ BrokerConnectionData connectionData = (BrokerConnectionData) object;
+ return (_host.equals(connectionData._host) )
+ && (_port == connectionData._port)
+ && (_virtualHost.equals(connectionData._virtualHost));
+ } catch (Exception exception) {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return _host.hashCode()+_port+_virtualHost.hashCode();
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerConnectionDataParser.java b/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerConnectionDataParser.java
new file mode 100644
index 0000000000..39981dc7cb
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerConnectionDataParser.java
@@ -0,0 +1,136 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.configuration;
+
+import java.util.UUID;
+
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * Parser used for building broker connection data settings.
+ * The corresponding section on the configuration file is :
+ *
+ <broker>
+ <host>192.168.148.131</host>
+ <port>5672</port>
+ <virtual-host>test</virtual-host>
+ <user>guest</user>
+ <password>guest</password>
+ <max-pool-capacity>4</max-pool-capacity>
+ <initial-pool-capacity>4</initial-pool-capacity>
+ <max-wait-timeout>-1</max-wait-timeout>
+ </broker>
+ *
+ * @author Andrea Gazzarini
+ */
+class BrokerConnectionDataParser implements IParser
+{
+ private final static Logger LOGGER = Logger.get(Configuration.class);
+ private BrokerConnectionData _connectionData = new BrokerConnectionData();
+ private String _currentValue;
+
+ /**
+ * Callback : the given value is the text content of the current node.
+ */
+ public void setCurrrentAttributeValue (String value)
+ {
+ this._currentValue = value;
+ }
+
+ /**
+ * Callback: each time the end of an element is reached this method is called.
+ * It's here that the built mapping is injected into the configuration.
+ * <broker>
+ <host>192.168.61.130</host>
+ <port>5673</port>
+ <virtual-host>test</virtual-host>
+ <user>andrea</user>
+ <password>andrea</password>
+ </broker>
+ */
+ public void setCurrentAttributeName (String name)
+ {
+ switch (Tag.get(name))
+ {
+ case HOST:
+ {
+ _connectionData.setHost(_currentValue);
+ break;
+ }
+ case PORT :
+ {
+ _connectionData.setPort(_currentValue);
+ break;
+ }
+ case VIRTUAL_HOST:
+ {
+ _connectionData.setVirtualHost(_currentValue);
+ break;
+ }
+ case USER :
+ {
+ _connectionData.setUsername(_currentValue);
+ break;
+ }
+ case MAX_POOL_CAPACITY:
+ {
+ _connectionData.setMaxPoolCapacity (_currentValue);
+ break;
+ }
+ case INITIAL_POOL_CAPACITY:
+ {
+ _connectionData.setInitialPoolCapacity(_currentValue);
+ break;
+ }
+ case MAX_WAIT_TIMEOUT:
+ {
+ _connectionData.setMaxWaitTimeout(_currentValue);
+ break;
+ }
+ case PASSWORD:
+ {
+ _connectionData.setPassword(_currentValue);
+ break;
+ }
+ case BROKER:
+ {
+ try
+ {
+ Configuration.getInstance().addBrokerConnectionData(getUUId(),_connectionData);
+ } catch(Exception exception)
+ {
+ LOGGER.error(exception, Messages.QMAN_100007_UNABLE_TO_CONNECT_WITH_BROKER, _connectionData);
+ }
+ _connectionData = new BrokerConnectionData();
+ break;
+ }
+ }
+ }
+
+ /**
+ * Gets an uuid in order to associate current connection data with a broker.
+ * @return
+ */
+ UUID getUUId(){
+ return UUID.randomUUID();
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerConnectionException.java b/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerConnectionException.java
new file mode 100644
index 0000000000..9294cf740e
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerConnectionException.java
@@ -0,0 +1,42 @@
+/*
+*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.management.configuration;
+
+/**
+ * Thrown when a connection to a broker cannot be estabilished.
+ *
+ * @author Andrea Gazzarini
+ */
+public class BrokerConnectionException extends Exception
+{
+ private static final long serialVersionUID = 8170112238862494025L;
+
+ /**
+ * Builds a new exception with the given cause.
+ *
+ * @param cause the exception cause.
+ */
+ BrokerConnectionException(Throwable cause)
+ {
+ super(cause);
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/configuration/Configuration.java b/java/management/client/src/main/java/org/apache/qpid/management/configuration/Configuration.java
new file mode 100644
index 0000000000..51dc62f4fa
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/configuration/Configuration.java
@@ -0,0 +1,489 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.configuration;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.Map.Entry;
+
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.domain.handler.base.IMessageHandler;
+import org.apache.qpid.management.domain.model.AccessMode;
+import org.apache.qpid.management.domain.model.type.AbsTime;
+import org.apache.qpid.management.domain.model.type.DeltaTime;
+import org.apache.qpid.management.domain.model.type.ObjectReference;
+import org.apache.qpid.management.domain.model.type.Str16;
+import org.apache.qpid.management.domain.model.type.Str8;
+import org.apache.qpid.management.domain.model.type.Type;
+import org.apache.qpid.management.domain.model.type.Uint16;
+import org.apache.qpid.management.domain.model.type.Uint32;
+import org.apache.qpid.management.domain.model.type.Uint64;
+import org.apache.qpid.management.domain.model.type.Uint8;
+import org.apache.qpid.transport.DeliveryProperties;
+import org.apache.qpid.transport.Header;
+import org.apache.qpid.transport.MessageProperties;
+import org.apache.qpid.transport.ReplyTo;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * Qpid Management bridge configuration.
+ * Basically iy is a singleton that is holding all the configurtion data loaded at startup.
+ */
+public final class Configuration
+{
+ private final static Logger LOGGER = Logger.get(Configuration.class);
+ private static Configuration INSTANCE = new Configuration();
+
+ // Work Manager default settings
+ private int _poolSize = 5;
+ private int _maxPoolSize = 15;
+ private long _keepAliveTime = 5000;
+
+ Map<Integer, Type> _typeMappings = new HashMap<Integer,Type>();
+ Map<Integer,AccessMode> _accessModes = new HashMap<Integer, AccessMode>();
+ Map<Type,String> _validators = new HashMap<Type, String>();
+
+ Map<UUID,BrokerConnectionData> _brokerConnectionInfos = new HashMap<UUID, BrokerConnectionData>();
+
+ Map<Character, IMessageHandler> _managementQueueHandlers = new HashMap<Character, IMessageHandler>();
+ Map<Character, IMessageHandler> _methodReplyQueueHandlers = new HashMap<Character, IMessageHandler>();
+
+ private String _managementQueueName;
+ private String _methodReplyQueueName;
+
+ private Header _headerForCommandMessages;
+ private DeliveryProperties _deliveryProperties = new DeliveryProperties();
+ private MessageProperties _messageProperties = new MessageProperties();
+
+ // Private constructor.
+ private Configuration()
+ {
+ defineQueueNames();
+
+ createHeaderForCommandMessages();
+
+ addAccessModeMappings();
+
+ addTypeMappings();
+ }
+
+ void clean()
+ {
+ INSTANCE = new Configuration();
+ }
+
+ /**
+ * Returns the singleton instance.
+ *
+ * @return the singleton instance.
+ */
+ public static Configuration getInstance ()
+ {
+ return INSTANCE;
+ }
+
+ /**
+ * Returns true if this configuration has at least
+ * one broker configured.
+ *
+ * @return true if this configuration has at least one
+ * broker configured.
+ */
+ public boolean hasOneOrMoreBrokersDefined()
+ {
+ return !_brokerConnectionInfos.isEmpty();
+ }
+
+ /**
+ * Returns the type associated to the given code.
+ *
+ * @param code the code used as search criteria.
+ * @return the type associated to the given code.
+ * @throws UnknownTypeCodeException when the given code is not associated to any type.
+ */
+ public Type getType(int code) throws UnknownTypeCodeException
+ {
+ Type result = _typeMappings.get(code);
+ if (result == null)
+ {
+ throw new UnknownTypeCodeException(code);
+ }
+ return result;
+ }
+
+ /**
+ * Returns the access mode associated to the given code.
+ *
+ * @param code the code used as search criteria.
+ * @return the access mode associated to the given code.
+ * @throws UnknownAccessCodeException when the given code is not associated to any access mode.
+ */
+ public AccessMode getAccessMode(int code) throws UnknownAccessCodeException
+ {
+ AccessMode result = _accessModes.get(code);
+ if (result == null)
+ {
+ throw new UnknownAccessCodeException(code);
+ }
+ return result;
+ }
+
+ /**
+ * Returns the validator class name associated to the given type.
+ *
+ * @param type the type.
+ * @return the validator class name associated to the given type.
+ */
+ public String getValidatorClassName (Type type)
+ {
+ return _validators.get(type);
+ }
+
+ /**
+ * Gets from this configuration the list of known broker (I mean, only their connection data).
+ *
+ * @return the list of known broker
+ */
+ public Set<Entry<UUID, BrokerConnectionData>> getConnectionInfos(){
+ return _brokerConnectionInfos.entrySet();
+ }
+
+ /**
+ * Gets from this configuration the connection data of the broker associated with the given id.
+ *
+ * @param brokerId the broker identifier.
+ * @return the connection data of the broker associated with the given id.
+ * @throws UnknownBrokerException when the given id is not associated with any broker.
+ */
+ public BrokerConnectionData getBrokerConnectionData (UUID brokerId) throws UnknownBrokerException
+ {
+ BrokerConnectionData connectionData = _brokerConnectionInfos.get(brokerId);
+ if (connectionData == null)
+ {
+ throw new UnknownBrokerException(brokerId);
+ }
+ return _brokerConnectionInfos.get(brokerId);
+ }
+
+ /**
+ * Returns the name of the management queue.
+ *
+ * @return the name of the management queue.
+ */
+ public String getManagementQueueName() {
+ return _managementQueueName;
+ }
+
+ /**
+ * Returns the name of the method-reply queue.
+ *
+ * @return the name of the method-reply queue.
+ */
+ public String getMethodReplyQueueName() {
+ return _methodReplyQueueName;
+ }
+
+ /**
+ * Returns a map containing all the configured management message handlers.
+ * A management message handler it is a basically a processor for a management queue incoming message associated
+ * with a specific opcode.
+ *
+ * @return a map containing all the configured management message handlers.
+ */
+ public Map<Character, IMessageHandler> getManagementQueueHandlers()
+ {
+ return _managementQueueHandlers;
+ }
+
+ /**
+ * Returns a map containing all the configured method-reply message handlers.
+ * A management message handler it is a basically a processor for a method-reply queue incoming message associated
+ * with a specific opcode.
+ *
+ * @return a map containing all the configured method-reply message handlers.
+ */
+ public Map<Character, IMessageHandler> getMethodReplyQueueHandlers()
+ {
+ return _methodReplyQueueHandlers;
+ }
+
+ /**
+ * Returns the message header used for sending command message on management queue.
+ *
+ * @return the message header used for sending command message on management queue.
+ */
+ public Header getCommandMessageHeader ()
+ {
+ return _headerForCommandMessages;
+ }
+
+ /**
+ * Returns the command message properties.
+ *
+ * @return the command message properties.
+ */
+ public MessageProperties getCommandMessageProperties ()
+ {
+ return _messageProperties;
+ }
+
+ /**
+ * Returns the command message delivery properties.
+ *
+ * @return the command message delivery properties.
+ */
+ public DeliveryProperties getCommandDeliveryProperties ()
+ {
+ return _deliveryProperties;
+ }
+
+ /**
+ * Adds a new type mapping to this configuration.
+ *
+ * @param code the code that will be associated with the declared type.
+ * @param type the type.
+ * @param vailidatorClassName the FQN of the validator class that will be
+ * associated with the given type.
+ */
+ void addTypeMapping(int code, Type type, String validatorClassName) {
+ _typeMappings.put(code, type);
+ _validators.put(type, validatorClassName);
+
+ LOGGER.info(
+ Messages.QMAN_000005_TYPE_MAPPING_CONFIGURED,
+ code,
+ type,
+ validatorClassName);
+ }
+
+
+ /**
+ * Adds a new type mapping to this configuration.
+ *
+ * @param code the code that will be associated with the declared type.
+ * @param type the type.
+ */
+ void addTypeMapping(int code, Type type) {
+ _typeMappings.put(code, type);
+
+ LOGGER.info(
+ Messages.QMAN_000005_TYPE_MAPPING_CONFIGURED,
+ code,
+ type,
+ "not configured for this type.");
+ }
+
+ /**
+ * Adds a new access mode mapping to this configuration.
+ *
+ * @param code the code that will be associated with the access mode,
+ * @param accessMode the accessMode.
+ */
+ void addAccessModeMapping(int code, AccessMode accessMode){
+ _accessModes.put(code, accessMode);
+
+ LOGGER.info(Messages.QMAN_000006_ACCESS_MODE_MAPPING_CONFIGURED, code,accessMode);
+ }
+
+ /**
+ * Adds a new management message handler to this configuration.
+ * The incoming mapping object will contains an opcode and the class (as a string) of the message handler that will be used
+ * for processing incoming messages with that opcode.
+ *
+ * @param mapping the message handler mapping.
+ */
+ void addManagementMessageHandlerMapping (MessageHandlerMapping mapping)
+ {
+ Character opcode = mapping.getOpcode();
+ IMessageHandler handler = mapping.getMessageHandler();
+ _managementQueueHandlers.put(opcode, handler);
+
+ LOGGER.info(Messages.QMAN_000007_MANAGEMENT_HANDLER_MAPPING_CONFIGURED, opcode,handler.getClass().getName());
+ }
+
+ /**
+ * Adds a new method-reply message handler to this configuration.
+ * The incoming mapping object will contains an opcode and the class (as a string) of the message handler that will be used
+ * for processing incoming messages with that opcode.
+ *
+ * @param mapping the message handler mapping.
+ */
+ void addMethodReplyMessageHandlerMapping (MessageHandlerMapping mapping)
+ {
+ Character opcode = mapping.getOpcode();
+ IMessageHandler handler = mapping.getMessageHandler();
+ _methodReplyQueueHandlers.put(opcode, handler);
+
+ LOGGER.info(Messages.QMAN_000008_METHOD_REPLY_HANDLER_MAPPING_CONFIGURED, opcode,handler.getClass().getName());
+ }
+
+ /**
+ * Adds to this configuration a new broker connection data.
+ *
+ * @param brokerId the broker identifier.
+ * @param connectionData the connection data.
+ * @throws BrokerAlreadyConnectedException when the broker is already connected.
+ * @throws BrokerConnectionException when a connection cannot be estabilished.
+ */
+ void addBrokerConnectionData (UUID brokerId, BrokerConnectionData connectionData) throws BrokerAlreadyConnectedException, BrokerConnectionException
+ {
+ if (_brokerConnectionInfos.containsValue(connectionData))
+ {
+ throw new BrokerAlreadyConnectedException(connectionData);
+ }
+
+ try
+ {
+ QpidDatasource.getInstance().addConnectionPool(brokerId, connectionData);
+ _brokerConnectionInfos.put(brokerId,connectionData);
+
+ LOGGER.info(Messages.QMAN_000009_BROKER_DATA_CONFIGURED,brokerId,connectionData);
+ } catch(Exception exception)
+ {
+ throw new BrokerConnectionException(exception);
+ }
+
+ }
+
+ /**
+ * Header for command messages is created once because it only contains static values.
+ */
+ private void createHeaderForCommandMessages ()
+ {
+ ReplyTo replyTo=new ReplyTo();
+ replyTo.setRoutingKey(_methodReplyQueueName);
+ _messageProperties.setReplyTo(replyTo);
+ _deliveryProperties.setRoutingKey(Names.AGENT_ROUTING_KEY);
+ _headerForCommandMessages = new Header(_deliveryProperties, _messageProperties);
+ }
+
+ /**
+ * Creates the name of the queues used by this service.
+ * This is done because if a broker should be managed by one or more management client, then each of them
+ * must have its own channels to communicate with.
+ */
+ private void defineQueueNames()
+ {
+ UUID uuid = UUID.randomUUID();
+ _managementQueueName = Names.MANAGEMENT_QUEUE_PREFIX+uuid;
+ _methodReplyQueueName = Names.METHOD_REPLY_QUEUE_PREFIX+uuid;
+
+ LOGGER.debug(Messages.QMAN_200004_MANAGEMENT_QUEUE_NAME,_managementQueueName);
+ LOGGER.debug(Messages.QMAN_200005_METHOD_REPLY_QUEUE_NAME,_methodReplyQueueName);
+ }
+
+ /**
+ * Returns the worker manager thread pool size.
+ *
+ * @return the worker manager thread pool size.
+ */
+ public int getWorkerManagerPoolSize()
+ {
+ return _poolSize;
+ }
+
+ /**
+ * Sets the size of the worker manager thread pool.
+ *
+ * @param poolSize the size of the worker manager thread pool.
+ */
+ void setWorkerManagerPoolSize(int poolSize)
+ {
+ this._poolSize = poolSize;
+ }
+
+ /**
+ * Returns the maximum size of the worker manager
+ * thread pool size.
+ *
+ * @return the max size of the worker manager thread pool.
+ */
+ public int getWorkerManagerMaxPoolSize()
+ {
+ return _maxPoolSize;
+ }
+
+ /**
+ * Sets the maximum size of the worker manager
+ * thread pool size.
+ *
+ * @param maxPoolSize the max size of the worker manager thread pool.
+ */
+ void setWorkerManagerMaxPoolSize(int maxPoolSize)
+ {
+ this._maxPoolSize = maxPoolSize;
+ }
+
+ /**
+ * Returns the max amount of time that an excess thread
+ * can be idle before purging from the pool.
+ *
+ * @return the max keep alive time.
+ */
+ public long getWorkerManagerKeepAliveTime()
+ {
+ return _keepAliveTime;
+ }
+
+ /**
+ * Sets the max amount of time that an excess thread
+ * can be idle before purging from the pool.
+ *
+ * @param keepAliveTime the max keep alive time.
+ */
+ void setWorkerManagerKeepAliveTime(long keepAliveTime)
+ {
+ this._keepAliveTime = keepAliveTime;
+ }
+
+ /**
+ * Configures access mode mappings.
+ * An access mode mapping is an association between a code and an access mode.
+ */
+ private void addAccessModeMappings() {
+ addAccessModeMapping(1,AccessMode.RC);
+ addAccessModeMapping(2,AccessMode.RW);
+ addAccessModeMapping(3,AccessMode.RO);
+ }
+
+ /**
+ * Configures type mappings.
+ * A type mapping is an association between a code and a management type.
+ */
+ private void addTypeMappings()
+ {
+ addTypeMapping(1,new Uint8(),Names.NUMBER_VALIDATOR);
+ addTypeMapping(2,new Uint16(),Names.NUMBER_VALIDATOR);
+ addTypeMapping(3,new Uint32(),Names.NUMBER_VALIDATOR);
+ addTypeMapping(4,new Uint64(),Names.NUMBER_VALIDATOR);
+ addTypeMapping(6,new Str8(),Names.STRING_VALIDATOR);
+ addTypeMapping(7,new Str16(),Names.STRING_VALIDATOR);
+ addTypeMapping(8,new AbsTime());
+ addTypeMapping(9,new DeltaTime());
+ addTypeMapping(10,new ObjectReference());
+ addTypeMapping(11,new org.apache.qpid.management.domain.model.type.Boolean());
+ addTypeMapping(14,new org.apache.qpid.management.domain.model.type.Uuid());
+ addTypeMapping(15,new org.apache.qpid.management.domain.model.type.Map());
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/configuration/ConfigurationException.java b/java/management/client/src/main/java/org/apache/qpid/management/configuration/ConfigurationException.java
new file mode 100644
index 0000000000..6eed515e11
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/configuration/ConfigurationException.java
@@ -0,0 +1,51 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.configuration;
+
+/**
+ * Thrown when a problem is encountered during building the configuration.
+ *
+ * @author Andrea Gazzarini
+ */
+public class ConfigurationException extends Exception
+{
+ private static final long serialVersionUID = 8238481177714286259L;
+
+ public ConfigurationException(String msg)
+ {
+ super(msg);
+ }
+
+ /**
+ * Builds a new ConfigurationException with the given cause.
+ *
+ * @param exception the exception cause.
+ */
+ public ConfigurationException(Exception exception)
+ {
+ super(exception);
+ }
+
+ public ConfigurationException(String msg,Exception exception)
+ {
+ super(msg,exception);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/configuration/Configurator.java b/java/management/client/src/main/java/org/apache/qpid/management/configuration/Configurator.java
new file mode 100644
index 0000000000..fe44c6aff7
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/configuration/Configurator.java
@@ -0,0 +1,240 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.configuration;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.util.UUID;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.Protocol;
+import org.apache.qpid.management.domain.handler.impl.ConfigurationMessageHandler;
+import org.apache.qpid.management.domain.handler.impl.EventContentMessageHandler;
+import org.apache.qpid.management.domain.handler.impl.HeartBeatIndicationMessageHandler;
+import org.apache.qpid.management.domain.handler.impl.InstrumentationMessageHandler;
+import org.apache.qpid.management.domain.handler.impl.MethodResponseMessageHandler;
+import org.apache.qpid.management.domain.handler.impl.SchemaResponseMessageHandler;
+import org.apache.qpid.transport.util.Logger;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * Director used for coordinating the build process of configuration.
+ * This is the only component which has a read-write permission on Configuration object.
+ */
+public class Configurator extends DefaultHandler
+{
+ private final static Logger LOGGER = Logger.get(Configurator.class);
+
+ /**
+ * Default (empty) parser used when there's no need to process data (non relevant elements).
+ */
+ final static IParser DEFAULT_PARSER = new IParser() {
+
+ public void setCurrrentAttributeValue (String value)
+ {
+ }
+
+ public void setCurrentAttributeName (String name)
+ {
+ }
+ };
+
+ IParser _brokerConfigurationParser = new BrokerConnectionDataParser();
+ IParser _workerManagerConfigurationParser = new WorkerManagerConfigurationParser();
+ IParser _currentParser = DEFAULT_PARSER;
+
+ /**
+ * Delegates the processing to the current parser.
+ */
+ @Override
+ public void characters (char[] ch, int start, int length) throws SAXException
+ {
+ String value = new String(ch,start,length).trim();
+ if (value.length() != 0) {
+ _currentParser.setCurrrentAttributeValue(value);
+ }
+ }
+
+ /**
+ * Here is defined what parser needs to be used for processing the current data.
+ */
+ @Override
+ public void startElement (String uri, String localName, String name, Attributes attributes) throws SAXException
+ {
+ switch(Tag.get(name))
+ {
+ case BROKERS :
+ {
+ _currentParser = _brokerConfigurationParser;
+ break;
+ }
+ case WORK_MANAGER :
+ {
+ _currentParser = _workerManagerConfigurationParser;
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void endElement (String uri, String localName, String name) throws SAXException
+ {
+ _currentParser.setCurrentAttributeName(name);
+ }
+
+ /**
+ * Builds whole configuration.
+ *
+ * @throws ConfigurationException when the build fails.
+ */
+ public void configure() throws ConfigurationException
+ {
+ BufferedReader reader = null;
+ try
+ {
+ String initialConfigFileName = System.getProperty(Names.QMAN_CONFIG_OPTION_NAME);
+ if (initialConfigFileName != null && initialConfigFileName.trim().length() != 0)
+ {
+ File initialConfigurationFile = new File(initialConfigFileName);
+ if (initialConfigurationFile.canRead())
+ {
+ SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
+ reader = new BufferedReader(
+ new InputStreamReader(
+ new FileInputStream(initialConfigFileName)));
+ InputSource source = new InputSource(reader);
+ parser.parse(source, this);
+ } else {
+ LOGGER.warn(
+ Messages.QMAN_300004_INVALID_CONFIGURATION_FILE,
+ initialConfigFileName);
+ }
+ }
+
+ addMandatoryManagementMessageHandlers();
+ addMandatoryMethodReplyMessageHandlers();
+ } catch (Exception exception)
+ {
+ throw new ConfigurationException(exception);
+ } finally
+ {
+ try
+ {
+ reader.close();
+ } catch (Exception ignore)
+ {
+ }
+ }
+ }
+
+ /**
+ * Creates and return a value object (BrokerConnectionData) with the given parameters.
+ * Note that that object will be stored on configuration and it could be used to set a connection with the broker.
+ * This happens when the "initialPoolCapacity" is greater than 0 : in this case the caller is indicatinf that it wants to open
+ * one or more connections immediately at startup and therefore Q-Man will try to do that.
+ *
+ * @param host the hostname where the broker is running.
+ * @param port the port where the broker is running.
+ * @param username the username for connecting with the broker.
+ * @param password the password for connecting with the broker.
+ * @param virtualHost the virtual host.
+ * @param initialPoolCapacity the number of the connection that must be immediately opened.
+ * @param maxPoolCapacity the maximum number of opened connection.
+ * @param maxWaitTimeout the maximum amount of time that a client will wait for obtaining a connection.
+ * @return the value object containing the data above.
+ * @throws BrokerAlreadyConnectedException when the broker is already connected.
+ * @throws BrokerConnectionException when a connection cannot be estabilished.
+ */
+ public BrokerConnectionData createAndReturnBrokerConnectionData(
+ UUID brokerId,
+ String host,
+ int port,
+ String username,
+ String password,
+ String virtualHost,
+ int initialPoolCapacity,
+ int maxPoolCapacity,
+ long maxWaitTimeout) throws BrokerAlreadyConnectedException, BrokerConnectionException
+ {
+ BrokerConnectionData data = new BrokerConnectionData(
+ host,
+ port,
+ virtualHost,
+ username,
+ password,
+ initialPoolCapacity,
+ maxPoolCapacity,
+ maxWaitTimeout);
+ Configuration.getInstance().addBrokerConnectionData(brokerId, data);
+ return data;
+ }
+
+ /**
+ * Configures the mandatory management message handlers.
+ */
+ void addMandatoryMethodReplyMessageHandlers ()
+ {
+ Configuration.getInstance().addMethodReplyMessageHandlerMapping(
+ new MessageHandlerMapping(
+ Protocol.OPERATION_INVOCATION_RESPONSE_OPCODE,
+ new MethodResponseMessageHandler()));
+
+ Configuration.getInstance().addMethodReplyMessageHandlerMapping(
+ new MessageHandlerMapping(
+ Protocol.SCHEMA_RESPONSE_OPCODE,
+ new SchemaResponseMessageHandler()));
+ }
+
+ /**
+ * Configures the mandatory management message handlers.
+ */
+ void addMandatoryManagementMessageHandlers ()
+ {
+ Configuration.getInstance().addManagementMessageHandlerMapping(
+ new MessageHandlerMapping(
+ Protocol.INSTRUMENTATION_CONTENT_RESPONSE_OPCODE,
+ new InstrumentationMessageHandler()));
+
+ Configuration.getInstance().addManagementMessageHandlerMapping(
+ new MessageHandlerMapping(
+ Protocol.CONFIGURATION_CONTENT_RESPONSE_OPCDE,
+ new ConfigurationMessageHandler()));
+
+ Configuration.getInstance().addManagementMessageHandlerMapping(
+ new MessageHandlerMapping(
+ Protocol.EVENT_CONTENT_RESPONSE_OPCDE,
+ new EventContentMessageHandler()));
+
+ Configuration.getInstance().addManagementMessageHandlerMapping(
+ new MessageHandlerMapping(
+ Protocol.HEARTBEAT_INDICATION_RESPONSE_OPCODE,
+ new HeartBeatIndicationMessageHandler()));
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/configuration/IParser.java b/java/management/client/src/main/java/org/apache/qpid/management/configuration/IParser.java
new file mode 100644
index 0000000000..a221686765
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/configuration/IParser.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.configuration;
+
+/**
+ * Interface definition for configuration parser
+ * Concrete implementors are responsible for parsing a specific XML part of configuration data.
+ *
+ * @author Andrea Gazzarini
+ */
+interface IParser
+{
+ /**
+ * Main director callback : Sets the name of the current attribute.
+ *
+ * @param name the name of the current attribute.
+ */
+ void setCurrentAttributeName(String name);
+
+ /**
+ * Main director callback : sets the value of the current attribute.
+ *
+ * @param value the value of the current attribute.
+ */
+ void setCurrrentAttributeValue(String value);
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/configuration/MessageHandlerMapping.java b/java/management/client/src/main/java/org/apache/qpid/management/configuration/MessageHandlerMapping.java
new file mode 100644
index 0000000000..b02fb789cc
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/configuration/MessageHandlerMapping.java
@@ -0,0 +1,64 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.configuration;
+
+import org.apache.qpid.management.domain.handler.base.IMessageHandler;
+
+/**
+ * Message Handler mapping used for associating an opcode with a message handler.
+ */
+class MessageHandlerMapping
+{
+ private final Character _opcode;
+ private final IMessageHandler _handler;
+
+ /**
+ * Builds a new mapping with the given opcode and handler class.
+ *
+ * @param opcode the opcode.
+ * @param handlerClass the handler class.
+ */
+ MessageHandlerMapping(Character opcode, IMessageHandler handler)
+ {
+ this._opcode = opcode;
+ this._handler = handler;
+ }
+
+ /**
+ * Returns the opcode of this mapping.
+ *
+ * @return the code of this mapping.
+ */
+ Character getOpcode ()
+ {
+ return _opcode;
+ }
+
+ /**
+ * Returns the message handler for this mapping.
+ *
+ * @return the message handler for this mapping.
+ */
+ IMessageHandler getMessageHandler()
+ {
+ return _handler;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/configuration/QpidDatasource.java b/java/management/client/src/main/java/org/apache/qpid/management/configuration/QpidDatasource.java
new file mode 100644
index 0000000000..569a65a782
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/configuration/QpidDatasource.java
@@ -0,0 +1,249 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.configuration;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.commons.pool.BasePoolableObjectFactory;
+import org.apache.commons.pool.ObjectPool;
+import org.apache.commons.pool.impl.GenericObjectPool;
+import org.apache.commons.pool.impl.GenericObjectPoolFactory;
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.ConnectionException;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * Qpid datasource.
+ * Basically it is a connection pool manager used for optimizing broker connections usage.
+ *
+ * @author Andrea Gazzarini
+ */
+public final class QpidDatasource
+{
+ private final static Logger LOGGER = Logger.get(QpidDatasource.class);
+
+ /**
+ * A connection decorator used for adding pool interaction behaviour to an existing connection.
+ *
+ * @author Andrea Gazzarini
+ */
+ class PooledConnection extends Connection
+ {
+ private final UUID _brokerId;
+ private boolean _valid;
+
+ /**
+ * Builds a new decorator with the given connection.
+ *
+ * @param brokerId the broker identifier.
+ */
+ private PooledConnection(UUID brokerId)
+ {
+ this._brokerId = brokerId;
+ _valid = true;
+ }
+
+ /**
+ * Returns true if the underlying connection is still valid and can be used.
+ *
+ * @return true if the underlying connection is still valid and can be used.
+ */
+ boolean isValid()
+ {
+ return _valid;
+ }
+
+ void reallyClose()
+ {
+ super.close();
+ }
+
+ /**
+ * Returns the connection to the pool. That is, marks this connections as available.
+ * After that, this connection will be available for further operations.
+ */
+ public void close()
+ {
+ try
+ {
+ pools.get(_brokerId).returnObject(this);
+
+ LOGGER.debug(Messages.QMAN_200006_QPID_CONNECTION_RELEASED, this);
+ }
+ catch (Exception e)
+ {
+ throw new ConnectionException(e);
+ }
+ }
+
+ public void exception(Throwable t)
+ {
+ //super.exception(t);
+ _valid = false;
+ }
+ }
+
+ /**
+ * This is the connection factory, that is, the factory used to manage the lifecycle (create, validate & destroy) of
+ * the broker connection(s).
+ *
+ * @author Andrea Gazzarini
+ */
+ class QpidConnectionFactory extends BasePoolableObjectFactory
+ {
+ private final BrokerConnectionData _connectionData;
+ private final UUID _brokerId;
+
+ /**
+ * Builds a new connection factory with the given parameters.
+ *
+ * @param brokerId the broker identifier.
+ * @param connectionData the connecton data.
+ */
+ private QpidConnectionFactory(UUID brokerId, BrokerConnectionData connectionData)
+ {
+ this._connectionData = connectionData;
+ this._brokerId = brokerId;
+ }
+
+ /**
+ * Creates a new underlying connection.
+ */
+ @Override
+ public Connection makeObject () throws Exception
+ {
+ PooledConnection connection = new PooledConnection(_brokerId);
+ connection.connect(
+ _connectionData.getHost(),
+ _connectionData.getPort(),
+ _connectionData.getVirtualHost(),
+ _connectionData.getUsername(),
+ _connectionData.getPassword(),
+ false);
+ return connection;
+ }
+
+ /**
+ * Validates the underlying connection.
+ */
+ @Override
+ public boolean validateObject (Object obj)
+ {
+ PooledConnection connection = (PooledConnection) obj;
+ boolean isValid = connection.isValid();
+
+ LOGGER.debug(Messages.QMAN_200007_TEST_CONNECTION_ON_RESERVE,isValid);
+
+ return isValid;
+ }
+
+ /**
+ * Closes the underlying connection.
+ */
+ @Override
+ public void destroyObject (Object obj) throws Exception
+ {
+ try
+ {
+ PooledConnection connection = (PooledConnection) obj;
+ connection.reallyClose();
+
+ LOGGER.debug(Messages.QMAN_200008_CONNECTION_DESTROYED);
+ } catch (Exception exception)
+ {
+ LOGGER.debug(exception, Messages.QMAN_200009_CONNECTION_DESTROY_FAILURE);
+ }
+ }
+ }
+
+ // Singleton instance.
+ private static QpidDatasource instance = new QpidDatasource();
+
+ // Each entry contains a connection pool for a specific broker.
+ private Map<UUID, ObjectPool> pools = new HashMap<UUID, ObjectPool>();
+
+ // Private constructor.
+ private QpidDatasource()
+ {
+ }
+
+ /**
+ * Gets an available connection from the pool of the given broker.
+ *
+ * @param brokerId the broker identifier.
+ * @return a valid connection to the broker associated with the given identifier.
+ */
+ public Connection getConnection(UUID brokerId) throws Exception
+ {
+ return (Connection) pools.get(brokerId).borrowObject();
+ }
+
+ /**
+ * Entry point method for retrieving the singleton instance of this datasource.
+ *
+ * @return the qpid datasource singleton instance.
+ */
+ public static QpidDatasource getInstance()
+ {
+ return instance;
+ }
+
+ /**
+ * Adds a connection pool to this datasource.
+ *
+ * @param brokerId the broker identifier that will be associated with the new connection pool.
+ * @param connectionData the broker connection data.
+ * @throws Exception when the pool cannot be created.
+ */
+ void addConnectionPool(UUID brokerId,BrokerConnectionData connectionData) throws Exception
+ {
+ GenericObjectPoolFactory factory = new GenericObjectPoolFactory(
+ new QpidConnectionFactory(brokerId,connectionData),
+ connectionData.getMaxPoolCapacity(),
+ GenericObjectPool.WHEN_EXHAUSTED_BLOCK,
+ connectionData.getMaxWaitTimeout(),-1,
+ true,
+ false);
+
+ ObjectPool pool = factory.createPool();
+
+ // Open connections at startup according to initial capacity param value.
+ int howManyConnectionAtStartup = connectionData.getInitialPoolCapacity();
+ Object [] openStartupList = new Object[howManyConnectionAtStartup];
+
+ // Open...
+ for (int index = 0; index < howManyConnectionAtStartup; index++)
+ {
+ openStartupList[index] = pool.borrowObject();
+ }
+
+ // ...and immediately return them to pool. In this way the pooled connection has been opened.
+ for (int index = 0; index < howManyConnectionAtStartup; index++)
+ {
+ pool.returnObject(openStartupList[index]);
+ }
+
+ pools.put(brokerId,pool);
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/configuration/Tag.java b/java/management/client/src/main/java/org/apache/qpid/management/configuration/Tag.java
new file mode 100644
index 0000000000..c2b6e1e27d
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/configuration/Tag.java
@@ -0,0 +1,54 @@
+/*
+*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.management.configuration;
+
+/**
+ * Configuration Tag catalogue.
+ *
+ * @author Andrea Gazzarini
+ */
+public enum Tag {
+ CONFIGURATION { @Override public String toString() { return "configuration"; }},
+ BROKER { @Override public String toString() { return "broker"; }},
+ HOST { @Override public String toString() { return "host"; }},
+ PORT { @Override public String toString() { return "port"; }},
+ MAX_POOL_CAPACITY { @Override public String toString() { return "max-pool-capacity"; }},
+ MAX_WAIT_TIMEOUT { @Override public String toString() { return "max-wait-timeout"; }},
+ INITIAL_POOL_CAPACITY { @Override public String toString() { return "initial-pool-capacity"; }},
+ VIRTUAL_HOST { @Override public String toString() { return "virtual-host"; }},
+ USER { @Override public String toString() { return "user"; }},
+ PASSWORD { @Override public String toString() { return "password"; }},
+ BROKERS { @Override public String toString() { return "brokers"; }},
+ WORK_MANAGER { @Override public String toString() { return "work-manager"; }},
+ POOL_CAPACITY { @Override public String toString() { return "pool-capacity"; }},
+ KEEP_ALIVE_TIME { @Override public String toString() { return "keep-alive-time"; }};
+
+ /**
+ * Returns the enum entry associated to the given tag name.
+ *
+ * @param name the name of tag.
+ * @return the enum entry associated to the given tag name.
+ */
+ public static Tag get(String name) {
+ return valueOf(name.replaceAll("-", "_").toUpperCase());
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/configuration/UnknownAccessCodeException.java b/java/management/client/src/main/java/org/apache/qpid/management/configuration/UnknownAccessCodeException.java
new file mode 100644
index 0000000000..b7f1c0a7ec
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/configuration/UnknownAccessCodeException.java
@@ -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 org.apache.qpid.management.configuration;
+
+/**
+ * Thrown when no access mode is found in configuration associated to the given code.
+ *
+ * @author Andrea Gazzarini
+ */
+public class UnknownAccessCodeException extends Exception
+{
+ private static final long serialVersionUID = 2350963503092509119L;
+ private final int _code;
+
+ /**
+ * Builds a new UnknownAccessCodeException with the given code.
+ *
+ * @param code the access code.
+ */
+ UnknownAccessCodeException(int code)
+ {
+ super(String.valueOf(code));
+ this._code = code;
+ }
+
+ /**
+ * Returns the unknown code.
+ *
+ * @return the unknown code.
+ */
+ public int getCode ()
+ {
+ return _code;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/configuration/UnknownBrokerException.java b/java/management/client/src/main/java/org/apache/qpid/management/configuration/UnknownBrokerException.java
new file mode 100644
index 0000000000..5b08e09c24
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/configuration/UnknownBrokerException.java
@@ -0,0 +1,43 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.configuration;
+
+import java.util.UUID;
+
+/**
+ * Thrown when someone requests connection data for an unknown broker.
+ *
+ * @author Andrea Gazzarini
+ */
+public class UnknownBrokerException extends Exception
+{
+ private static final long serialVersionUID = 4965395428832158924L;
+
+ /**
+ * Builds a new UnknownBrokerException with the given broker id.
+ *
+ * @param brokerId the broker identifier.
+ */
+ UnknownBrokerException(UUID brokerId)
+ {
+ super(String.valueOf(brokerId));
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/configuration/UnknownTypeCodeException.java b/java/management/client/src/main/java/org/apache/qpid/management/configuration/UnknownTypeCodeException.java
new file mode 100644
index 0000000000..57005d21e5
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/configuration/UnknownTypeCodeException.java
@@ -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 org.apache.qpid.management.configuration;
+
+/**
+ * Thrown when no type is found in configuration associated to the given code.
+ *
+ * @author Andrea Gazzarini
+ */
+public class UnknownTypeCodeException extends Exception
+{
+ private static final long serialVersionUID = 5440934037645111591L;
+ private int _code;
+
+ /**
+ * Builds a new UnknownTypeCodeException with the given code.
+ *
+ * @param code the access code.
+ */
+ UnknownTypeCodeException(int code)
+ {
+ super(String.valueOf(code));
+ this._code = code;
+ }
+
+ /**
+ * Returns the unknown code.
+ *
+ * @return the unknown code.
+ */
+ public int getCode ()
+ {
+ return _code;
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/configuration/WorkerManagerConfigurationParser.java b/java/management/client/src/main/java/org/apache/qpid/management/configuration/WorkerManagerConfigurationParser.java
new file mode 100644
index 0000000000..b99f272053
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/configuration/WorkerManagerConfigurationParser.java
@@ -0,0 +1,108 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.configuration;
+
+import java.util.UUID;
+
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * Parser used for building worker manager settings.
+ * The corresponding section of the configuration file is :
+ *
+ <work-manager>
+ <pool-capacity>5</pool-capacity>
+ <max-pool-capacity>15</max-pool-capacity>
+ <keep-alive-time>5000</keep-alive-time>
+ </work-manager>
+
+ *
+ * @author Andrea Gazzarini
+ */
+class WorkerManagerConfigurationParser implements IParser
+{
+ private final static Logger LOGGER = Logger.get(Configuration.class);
+ private String _currentValue;
+
+ private String _poolSizeAsString;
+ private String _maxPoolSizeAsString;
+ private String _keepAliveTimeAsString;
+
+ /**
+ * Callback : the given value is the text content of the current node.
+ */
+ public void setCurrrentAttributeValue (String value)
+ {
+ this._currentValue = value;
+ }
+
+ /**
+ * Callback: each time the end of an element is reached
+ * this method is called.
+ */
+ public void setCurrentAttributeName (String name)
+ {
+ switch (Tag.get(name))
+ {
+ case POOL_CAPACITY:
+ {
+ _poolSizeAsString = _currentValue.trim();
+ break;
+ }
+ case MAX_POOL_CAPACITY :
+ {
+ _maxPoolSizeAsString = _currentValue;
+ }
+ case KEEP_ALIVE_TIME:
+ {
+ _keepAliveTimeAsString = _currentValue;
+ break;
+ }
+ case WORK_MANAGER:
+ {
+ Configuration configuration = Configuration.getInstance();
+ try
+ {
+ configuration.setWorkerManagerPoolSize(Integer.parseInt(_poolSizeAsString));
+ configuration.setWorkerManagerMaxPoolSize(Integer.parseInt(_maxPoolSizeAsString));
+ configuration.setWorkerManagerKeepAliveTime(Long.parseLong(_keepAliveTimeAsString));
+ } catch(Exception exception)
+ {
+ LOGGER.error(Messages.QMAN_100039_UNABLE_TO_CONFIGURE_PROPERLY_WORKER_MANAGER);
+ } finally {
+ LOGGER.info(Messages.QMAN_000035_WORK_MANAGER_POOL_SIZE,configuration.getWorkerManagerPoolSize());
+ LOGGER.info(Messages.QMAN_000036_WORK_MANAGER_MAX_POOL_SIZE,configuration.getWorkerManagerMaxPoolSize());
+ LOGGER.info(Messages.QMAN_000037_WORK_MANAGER_KEEP_ALIVE_TIME,configuration.getWorkerManagerKeepAliveTime());
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * Gets an uuid in order to associate current connection data with a broker.
+ * @return
+ */
+ UUID getUUId(){
+ return UUID.randomUUID();
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/base/BaseMessageHandler.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/base/BaseMessageHandler.java
new file mode 100644
index 0000000000..798e835ff4
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/base/BaseMessageHandler.java
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.handler.base;
+
+import org.apache.qpid.management.domain.model.DomainModel;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * Base class for all message handlers.
+ * A message handler is an handler for a specific type of message.
+ * Message type is defined by the opcode.
+ *
+ * @author Andrea Gazzarini
+ */
+public abstract class BaseMessageHandler implements IMessageHandler
+{
+ /**
+ * Logger used for logging.
+ */
+ protected final Logger _logger = Logger.get(getClass());
+
+ /**
+ * Managed broker domain model.
+ */
+ protected DomainModel _domainModel;
+
+ /**
+ * Sets the broker domain model.
+ *
+ * @param domainModel the broker domain model.
+ */
+ public void setDomainModel(DomainModel domainModel)
+ {
+ this._domainModel = domainModel;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/base/ContentIndicationMessageHandler.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/base/ContentIndicationMessageHandler.java
new file mode 100644
index 0000000000..be000e9a05
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/base/ContentIndicationMessageHandler.java
@@ -0,0 +1,114 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.handler.base;
+
+import org.apache.qpid.management.domain.model.type.Binary;
+import org.apache.qpid.transport.codec.Decoder;
+
+/**
+ * Base class for content indication message handlers.
+ *
+ * @author Andrea Gazzarini
+ */
+public abstract class ContentIndicationMessageHandler extends BaseMessageHandler
+{
+ /**
+ * Processes the income message.
+ *
+ * @param decoder the decoder used to parse the message.
+ * @param sequenceNumber the sequence number of the message.
+ */
+ public final void process (Decoder decoder, int sequenceNumber)
+ {
+ String packageName = decoder.readStr8();
+ String className = decoder.readStr8();
+ Binary classHash = new Binary(decoder.readBin128());
+
+ long timeStampOfCurrentSample = decoder.readDatetime();
+ long timeObjectWasCreated = decoder.readDatetime();
+ long timeObjectWasDeleted = decoder.readDatetime();
+
+ Binary objectId = new Binary(decoder.readBin128());
+
+ if (objectHasBeenRemoved(timeObjectWasDeleted, timeStampOfCurrentSample))
+ {
+ removeObjectInstance(packageName,className,classHash,objectId);
+ } else
+ {
+ updateDomainModel(
+ packageName,
+ className,
+ classHash,
+ objectId,
+ timeStampOfCurrentSample,
+ timeObjectWasCreated,
+ timeObjectWasDeleted,
+ decoder.readReaminingBytes());
+ }
+ }
+
+ /**
+ * Removes an object instance from the domain model.
+ *
+ * @param packageName the package name.
+ * @param className the class name.
+ * @param classHash the class hash.
+ * @param objectId the object identifier.
+ */
+ void removeObjectInstance(String packageName, String className,Binary classHash, Binary objectId)
+ {
+ _domainModel.removeObjectInstance(packageName,className,classHash,objectId);
+ }
+
+ /**
+ * Checks if the timestamps contained in the message indicate that the object has been removed.
+ *
+ * @param deletionTimestamp time object was deleted.
+ * @param now timestamp of the current message.
+ * @return true if the object has been removed, false otherwise.
+ */
+ boolean objectHasBeenRemoved(long deletionTimestamp, long now) {
+ return (deletionTimestamp != 0) && (now > deletionTimestamp);
+ }
+
+ /**
+ * Updates domain model with the incoming data.
+ * This is a template method that each concrete subclass must implement in order to update the domain model
+ * with the incoming data.
+ *
+ * @param packageName the name of the package.
+ * @param className the name of the class.
+ * @param objectId the object identifier.
+ * @param timeStampOfCurrentSample timestamp of current sample.
+ * @param timeObjectWasCreated time object was created.
+ * @param timeObjectWasDeleted time object was deleted.
+ * @param contentData object instance incoming data.
+ */
+ protected abstract void updateDomainModel(
+ String packageName,
+ String className,
+ Binary classHash,
+ Binary objectId,
+ long timeStampOfCurrentSample,
+ long timeObjectWasCreated,
+ long timeObjectWasDeleted,
+ byte []contentData );
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/base/IMessageHandler.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/base/IMessageHandler.java
new file mode 100644
index 0000000000..c120334d30
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/base/IMessageHandler.java
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.handler.base;
+
+import org.apache.qpid.management.domain.model.DomainModel;
+import org.apache.qpid.transport.codec.Decoder;
+
+/**
+ * Interface definition for a processor able to deal with a specific message.
+ * The concrete implementor must define what has to be done with the supplied (incoming) stream and the sequence
+ * number.
+ *
+ * @author Andrea Gazzarini.
+ */
+public interface IMessageHandler
+{
+ /**
+ * Processes the (incoming) stream message.
+ * Note that the main controller (the component that is controlling this handler) has already read the magic number and
+ * the sequence number so here concrete implementors must start from that point (that is, just after the sequence
+ * number).
+ *
+ * @param decoder the stream decoder.
+ * @param sequenceNumber the sequence number of the message.
+ */
+ void process (Decoder decoder, int sequenceNumber);
+
+ /**
+ * Injects the domain model into this handler.
+ *
+ * @param domainModel the domain model.
+ */
+ void setDomainModel(DomainModel domainModel);
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/ConfigurationMessageHandler.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/ConfigurationMessageHandler.java
new file mode 100644
index 0000000000..3158138172
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/ConfigurationMessageHandler.java
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.handler.impl;
+
+import org.apache.qpid.management.domain.handler.base.ContentIndicationMessageHandler;
+import org.apache.qpid.management.domain.model.type.Binary;
+
+/**
+ * Schema Response message handler.
+ * This handler is responsible to process 'c'(opcode) messages sent by the management broker.
+ *
+ * @author Andrea Gazzarini
+ */
+public class ConfigurationMessageHandler extends ContentIndicationMessageHandler
+{
+ /**
+ * Broker domain model is going to be updated with incoming configuration data.
+ *
+ * @param packageName the name of the package.
+ * @param className the name of the class.
+ * @param objectId the object identifier.
+ * @param timeStampOfCurrentSample the timestamp of incoming data.
+ * @param timeObjectWasCreated time object was created.
+ * @param timeObjectWasDeleted time object was deleted.
+ */
+ @Override
+ protected void updateDomainModel (
+ String packageName,
+ String className,
+ Binary classHash,
+ Binary objectId,
+ long timeStampOfCurrentSample,
+ long timeObjectWasCreated,
+ long timeObjectWasDeleted,
+ byte[] contentData)
+ {
+ _domainModel.addConfigurationRawData(packageName,className,classHash,objectId,contentData);
+ }
+ }
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/EventContentMessageHandler.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/EventContentMessageHandler.java
new file mode 100644
index 0000000000..0a590d2836
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/EventContentMessageHandler.java
@@ -0,0 +1,51 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.handler.impl;
+
+import org.apache.qpid.management.domain.handler.base.BaseMessageHandler;
+import org.apache.qpid.management.domain.model.type.Binary;
+import org.apache.qpid.transport.codec.Decoder;
+
+/**
+ * Base class for content indication message handlers.
+ *
+ * @author Andrea Gazzarini
+ */
+public class EventContentMessageHandler extends BaseMessageHandler
+{
+ /**
+ * Processes the income message.
+ *
+ * @param decoder the decoder used to parse the message.
+ * @param sequenceNumber the sequence number of the message.
+ */
+ public final void process (Decoder decoder, int sequenceNumber)
+ {
+ String packageName = decoder.readStr8();
+ String eventName = decoder.readStr8();
+ Binary eventHash = new Binary(decoder.readBin128());
+ long timeStampOfCurrentSample = decoder.readDatetime();
+ int severity = decoder.readUint8();
+ byte[] argumentsData = decoder.readReaminingBytes();
+
+ _domainModel.addEventRawData(packageName, eventName, eventHash, argumentsData,timeStampOfCurrentSample,severity);
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/HeartBeatIndicationMessageHandler.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/HeartBeatIndicationMessageHandler.java
new file mode 100644
index 0000000000..08c4f1bc5d
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/HeartBeatIndicationMessageHandler.java
@@ -0,0 +1,39 @@
+/*
+*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.management.domain.handler.impl;
+
+import org.apache.qpid.management.domain.handler.base.BaseMessageHandler;
+import org.apache.qpid.transport.codec.Decoder;
+
+/**
+ * This is the handler responsible for processing the heartbeat indication response messages.
+ * At the moment it simply updates the last refresh update timestamp of the domain model.
+ *
+ * @author Andrea Gazzarini.
+ */
+public class HeartBeatIndicationMessageHandler extends BaseMessageHandler
+{
+ public void process(Decoder decoder, int sequenceNumber)
+ {
+ _domainModel.updateLastRefreshDate();
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/IMethodInvocationListener.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/IMethodInvocationListener.java
new file mode 100644
index 0000000000..4ce64dd339
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/IMethodInvocationListener.java
@@ -0,0 +1,41 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.handler.impl;
+
+import java.util.EventListener;
+
+import org.apache.qpid.management.domain.model.InvocationEvent;
+
+/**
+ * Listener interface used to denote a component interested in method invocation events.
+ *
+ * @author Andrea Gazzarini
+ */
+public interface IMethodInvocationListener extends EventListener
+{
+ /**
+ * An operation is going to be invoked on a specific object instance.
+ * This lets this listener to be informed about the imminent invocation.
+ *
+ * @param event the invocation event.
+ */
+ void operationIsGoingToBeInvoked(InvocationEvent event);
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/InstrumentationMessageHandler.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/InstrumentationMessageHandler.java
new file mode 100644
index 0000000000..e86a44f829
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/InstrumentationMessageHandler.java
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.handler.impl;
+
+import org.apache.qpid.management.domain.handler.base.ContentIndicationMessageHandler;
+import org.apache.qpid.management.domain.model.type.Binary;
+
+/**
+ * Schema Response message handler.
+ * This handler is responsible to process 'i'(opcode) messages sent by the management broker.
+ *
+ * @author Andrea Gazzarini
+ */
+public class InstrumentationMessageHandler extends ContentIndicationMessageHandler
+{
+ /**
+ * Broker domain model is going to be updated with incoming instrumentation data.
+ *
+ * @param packageName the name of the package.
+ * @param className the name of the class.
+ * @param objectId the object identifier.
+ * @param timeStampOfCurrentSample the timestamp of incoming data.
+ * @param timeObjectWasCreated time object was created.
+ * @param timeObjectWasDeleted time object was deleted.
+ */
+ @Override
+ protected void updateDomainModel (
+ String packageName,
+ String className,
+ Binary classHash,
+ Binary objectId,
+ long timeStampOfCurrentSample,
+ long timeObjectWasCreated,
+ long timeObjectWasDeleted,
+ byte[] contentData)
+ {
+ _domainModel.addInstrumentationRawData(packageName,className,classHash,objectId,contentData);
+ }
+ }
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/InvocationResult.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/InvocationResult.java
new file mode 100644
index 0000000000..019fce5a50
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/InvocationResult.java
@@ -0,0 +1,157 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.handler.impl;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.qpid.management.domain.services.MethodInvocationException;
+
+/**
+ * Value object used for storing an invocation method result.
+ * This is done in order to accomplish multiple return value requirement.
+ * As we know, it's not possible to do that only with method signature and therefore this value object / struct is used.
+ *
+ * @author Andrea Gazzarini
+ */
+public class InvocationResult implements Serializable
+{
+ private static final long serialVersionUID = 2062662997326399693L;
+
+ private final long _returnCode;
+ private final String _statusText;
+ private final byte [] _outputAndBidirectionalArgumentValues;
+ private Map<String, Object> _outputSection;
+
+ /**
+ * Builds an invocation result with the given status code and status text.
+ *
+ * @param statusCode the status code.
+ * @param statusText the status text.
+ */
+ InvocationResult(long statusCode, String statusText,byte [] outputAndBidirectionalArgumentValues)
+ {
+ this._returnCode = statusCode;
+ this._statusText = statusText;
+ this._outputAndBidirectionalArgumentValues = outputAndBidirectionalArgumentValues;
+ }
+
+ /**
+ * Checks if this result contains an error return code.
+ *
+ * @return true if this result object contains an error return code.
+ */
+ public boolean isException ()
+ {
+ return _returnCode != 0;
+ }
+
+ /**
+ * Simply throws a new MethodInvocationException.
+ * Usually this method is called in conjunction with the isException() method in order to raise an exception if
+ * the wrapped return code means that there was an error.
+ *
+ * @throws MethodInvocationException always.
+ */
+ public void createAndThrowException() throws MethodInvocationException
+ {
+ throw new MethodInvocationException(_returnCode, _statusText);
+ }
+
+ @Override
+ public String toString ()
+ {
+ StringBuilder builder = new StringBuilder()
+ .append("Status code : ")
+ .append(_returnCode)
+ .append(",")
+ .append("Status Text : ")
+ .append(_statusText);
+ if (_outputSection != null && !_outputSection.isEmpty())
+ {
+ builder.append(". Parameters : ");
+ for (Entry<String, Object> outputEntry : _outputSection.entrySet())
+ {
+ builder.append(outputEntry.getKey()).append('=').append(outputEntry.getValue());
+ builder.append(',');
+ }
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Returns the return code of this invocation result.
+ *
+ * @return the return code of this invocation result.
+ */
+ public long getReturnCode ()
+ {
+ return _returnCode;
+ }
+
+ /**
+ * Contains the status text of this invocation result.
+ *
+ * @return the status text of this invocation result.
+ */
+ public String getStatusText ()
+ {
+ return _statusText;
+ }
+
+ /**
+ * Returns the output and bidirectional argument values in raw format (byte [])
+ *
+ * @return the output and bidirectional argument values in raw format (byte [])
+ */
+ public byte [] getOutputAndBidirectionalArgumentValues()
+ {
+ return _outputAndBidirectionalArgumentValues;
+ }
+
+ /**
+ * Sets the output section (decoded) of this invocation result.
+ * When an incoming message arrives, the output section (output and bidirectional argument values) are
+ * initially stored in raw format.
+ * After that, their values need to be converted.
+ * The final result is a map containing (for each Output or Input/Output parameter) the name of the argument as key
+ * and its value as value.
+ *
+ * @param output a map containing outptu and bidirectional values (not in schema order).
+ */
+ public void setOutputSection (Map<String, Object> outputSection)
+ {
+ this._outputSection = outputSection;
+ }
+
+ /**
+ * Returns the output section of this invocation result.
+ * The output section consists in output and bidirectional argument values.
+ * Note that the order of the arguments is not guaranteed.
+ *
+ * @param outputSection the output section of this invocation result;
+ */
+ public Map<String, Object> getOutputSection ()
+ {
+ return _outputSection;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/MethodOrEventDataTransferObject.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/MethodOrEventDataTransferObject.java
new file mode 100644
index 0000000000..bc6a77d804
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/MethodOrEventDataTransferObject.java
@@ -0,0 +1,68 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.handler.impl;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Simple transfer object used for holding method / event definition data.
+ *
+ * @author Andrea Gazzarini
+ */
+public class MethodOrEventDataTransferObject
+{
+ private final Map<String, Object> _definition;
+ private List<Map<String, Object>> _argumentDefinitions;
+
+ /**
+ * Builds a new trasfer object with the given parameters.
+ *
+ * @param definition the method definition.
+ * @param argumentDefinitions the arguments definitions.
+ */
+ public MethodOrEventDataTransferObject(
+ Map<String, Object> definition,
+ List<Map<String, Object>> argumentDefinitions)
+ {
+ this._definition = definition;
+ this._argumentDefinitions = argumentDefinitions;
+ }
+
+ /**
+ * Returns the method definition.
+ *
+ * @return the method definition.
+ */
+ public Map<String, Object> getDefinition() {
+ return _definition;
+ }
+
+ /**
+ * Returns the arguemnts definitions.
+ *
+ * @return the arguemnts definitions.
+ */
+ public List<Map<String, Object>> getArgumentsDefinitions()
+ {
+ return _argumentDefinitions;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/MethodResponseMessageHandler.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/MethodResponseMessageHandler.java
new file mode 100644
index 0000000000..9c99eb09aa
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/MethodResponseMessageHandler.java
@@ -0,0 +1,106 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.handler.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.domain.handler.base.BaseMessageHandler;
+import org.apache.qpid.management.domain.model.DomainModel;
+import org.apache.qpid.management.domain.model.InvocationEvent;
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * Message handler for method response messages.
+ * This handler is installed on domain model as a method invocation result listener.
+ * When a method is going to be invoked this listener is notified with the exchange channel that will be used between it and
+ * the event (method invocation) source object.
+ *
+ * @author Andrea Gazzarini
+ *
+ */
+public class MethodResponseMessageHandler extends BaseMessageHandler
+{
+ private final static Logger LOGGER = Logger.get(MethodResponseMessageHandler.class);
+
+ private Map<Integer, BlockingQueue<InvocationResult>> _exchangeChannels = new HashMap<Integer, BlockingQueue<InvocationResult>>();
+
+ /**
+ * This is the listener installed on domain model for method invocations.
+ */
+ private final IMethodInvocationListener methodInvocationListener = new IMethodInvocationListener()
+ {
+ /**
+ * Event source callback.
+ * A method is going to be invoked and this method lets this listener take the exchange channel that will be used
+ * with the event source for synchronous communication.
+ *
+ * @param event the operation invocation event.
+ */
+ public void operationIsGoingToBeInvoked (InvocationEvent event)
+ {
+ _exchangeChannels.put(event.getSequenceNumber(), event.getExchangeChannel());
+ }
+ };
+
+ /**
+ * Processes the incoming message.
+ *
+ * @param decoder the decoder used for parsing incoming data.
+ * @param sequenceNumber the sequence number of the incoming message.
+ */
+ public void process (Decoder decoder, int sequenceNumber)
+ {
+ InvocationResult result = new InvocationResult(decoder.readUint32(), decoder.readStr16(),decoder.readReaminingBytes());
+ BlockingQueue<InvocationResult> exchangeChannel = _exchangeChannels.remove(sequenceNumber);
+ if (exchangeChannel != null)
+ {
+ try
+ {
+ exchangeChannel.put(result);
+ } catch (InterruptedException exception)
+ {
+ LOGGER.error(exception,Messages.QMAN_100010_METHOD_INVOCATION_RESULT_FAILURE,sequenceNumber);
+ }
+ } else
+ {
+ LOGGER.warn(
+ "Unable to deal with incoming message because it contains a unknown sequence number (%s).",
+ sequenceNumber);
+ }
+ }
+
+ /**
+ * Sets the domain model on this handler.
+ * In addiction, this handler registers a method invocation listener on the domain model.
+ *
+ * @param domainModel the managed broker domain model.
+ */
+ @Override
+ public void setDomainModel (DomainModel domainModel)
+ {
+ super.setDomainModel(domainModel);
+ domainModel.setMethodInvocationListener(methodInvocationListener);
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/QpidDomainObject.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/QpidDomainObject.java
new file mode 100644
index 0000000000..8456b2f8ac
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/QpidDomainObject.java
@@ -0,0 +1,314 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.handler.impl;
+
+import java.net.URI;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.qpid.management.domain.services.MethodInvocationException;
+
+/**
+ * This is a sample entity used on QMan test case.
+ *
+ * @author Andrea Gazzarini
+ */
+public class QpidDomainObject implements QpidDomainObjectMBean
+{
+ private UUID _vhostRef;
+ private String _name;
+ private Boolean _durable;
+ private Map<String, Object> _arguments;
+ private Long _msgTotalEnqueues;
+ private Integer _consumerCount;
+ private Short _mgmtPubInterval;
+ private Date _expireTime;
+ private String _type;
+ private byte [] _byteArray;
+
+ /**
+ * Builds a new QpidDomainObject with default values for
+ * its properties.
+ */
+ public QpidDomainObject()
+ {
+ _vhostRef = UUID.randomUUID();
+ _name = "Initial Name";
+ _durable = Boolean.TRUE;
+ _arguments = new HashMap<String, Object>();
+ _arguments.put("Key1", "aStringValue");
+ _arguments.put("Key2", Long.MIN_VALUE);
+ _arguments.put("Key3", Integer.MAX_VALUE);
+ _arguments.put("Key4", Double.MIN_VALUE);
+ _arguments.put("Key4", Float.MAX_VALUE);
+
+ _msgTotalEnqueues = Long.MAX_VALUE-10;
+ _consumerCount = Integer.MIN_VALUE+10;
+ _mgmtPubInterval = Short.MAX_VALUE;
+ _expireTime = new Date(Long.MAX_VALUE);
+ _byteArray = new byte[]{1,2,3,5,6,7,8,7,56};
+ }
+
+ /**
+ * A method that is throwing an exception, everytime.
+ *
+ * @throws Exception each time the method is called.
+ */
+ public void throwsException() throws Exception
+ {
+ throw new MethodInvocationException(-1,"KO");
+ }
+
+ /**
+ * Sample echo method that return an empty result object.
+ * That is, an object with only status code / text valorized
+ * (no output parameters).
+ *
+ * @return an empty result object.
+ */
+ public InvocationResult voidWithoutArguments()
+ {
+ return new InvocationResult(0,"OK,null",null);
+ }
+
+ /**
+ * Echo method that accepts and returns primitive type arrays.
+ *
+ * @param longs an array of long.
+ * @param booleans an array of boolean.
+ * @param doubles an array of double.
+ * @param floats an array of float.
+ * @param integers an array of int.
+ * @param shorts an array of short.
+ * @return a result object with the same input parameters (as output parameters).
+ */
+ public InvocationResult echoWithSimpleTypeArrays(
+ long [] longs,
+ boolean [] booleans,
+ double [] doubles,
+ float [] floats,
+ int [] integers,
+ short [] shorts)
+ {
+ InvocationResult result = new InvocationResult(0,"OK",null);
+ Map<String, Object> outputParameters = new HashMap<String, Object>();
+ outputParameters.put(long.class.getName(), longs);
+ outputParameters.put(boolean.class.getName(), booleans);
+ outputParameters.put(double.class.getName(), doubles);
+ outputParameters.put(float.class.getName(), floats);
+ outputParameters.put(int.class.getName(), integers);
+ outputParameters.put(short.class.getName(), shorts);
+ result.setOutputSection(outputParameters);
+ return result;
+ }
+
+ /**
+ * Echo method that accepts and returns wrapper types.
+ *
+ * @param aLong a java.lang.Long
+ * @param aBoolean a java.lang.Boolean
+ * @param aDouble a java.lang.Double
+ * @param aFloat a java.lang.Float
+ * @param anInteger a java.lang.Integer
+ * @param aShort a java.lang.Short
+ * @param aString a java.lang.String
+ * @param anURI a java.net.URI
+ * @param aDate a java.util.Date
+ * @return a result object with the same given parameters (as output parameters)
+ */
+ public InvocationResult echoWithSimpleTypes(
+ Long aLong,
+ Boolean aBoolean,
+ Double aDouble,
+ Float aFloat,
+ Integer anInteger,
+ Short aShort,
+ String aString,
+ URI anURI,
+ Date aDate)
+ {
+ InvocationResult result = new InvocationResult(0,"OK",null);
+ Map<String, Object> outputParameters = new HashMap<String, Object>();
+ outputParameters.put("p1", aLong);
+ outputParameters.put("p2", aBoolean);
+ outputParameters.put("p3", aDouble);
+ outputParameters.put("p4", aFloat);
+ outputParameters.put("p5", anInteger);
+ outputParameters.put("p6", aShort);
+ outputParameters.put("p7", aString);
+ outputParameters.put("p8", anURI);
+ outputParameters.put("p9", aDate);
+ result.setOutputSection(outputParameters);
+ return result;
+ }
+
+ /**
+ * Echo method that accepts and returns wrapper type arrays .
+ *
+ * @param longs an array of java.lang.Long
+ * @param booleans an array of java.lang.Boolean
+ * @param doubles an array of java.lang.Double
+ * @param floats an array of java.lang.Float
+ * @param integers an array of java.lang.Integer
+ * @param shorts an array of java.lang.Short
+ * @param strings an array of java.lang.String
+ * @param uris an array of java.net.URI
+ * @param dates an array of java.util.Date
+ * @return a result object with the same input parameters (as output parameters).
+ */
+ public InvocationResult echoWithArrays(
+ Long [] longs,
+ Boolean [] booleans,
+ Double [] doubles,
+ Float [] floats,
+ Integer [] integers,
+ Short [] shorts,
+ String [] strings,
+ URI [] uris,
+ Date [] dates)
+ {
+ InvocationResult result = new InvocationResult(0,"OK",null);
+ Map<String, Object> outputParameters = new HashMap<String, Object>();
+ outputParameters.put(Long.class.getName(), longs);
+ outputParameters.put(Boolean.class.getName(), booleans);
+ outputParameters.put(Double.class.getName(), doubles);
+ outputParameters.put(Float.class.getName(), floats);
+ outputParameters.put(Integer.class.getName(), integers);
+ outputParameters.put(Short.class.getName(), shorts);
+ outputParameters.put(String.class.getName(), strings);
+ outputParameters.put(URI.class.getName(), uris);
+ outputParameters.put(Date.class.getName(), dates);
+ result.setOutputSection(outputParameters);
+ return result;
+ }
+
+ /**
+ * Echo method that accepts and returns a byte array.
+ *
+ * @param byteArray a byte array
+ * @return a result containing the input byte array (as output parameter)
+ */
+ public InvocationResult echoWithByteArray(byte [] byteArray)
+ {
+ InvocationResult result = new InvocationResult(0,"OK",null);
+ Map<String, Object> outputParameters = new HashMap<String, Object>();
+ outputParameters.put(byte[].class.getName(),byteArray);
+ result.setOutputSection(outputParameters);
+ return result;
+ }
+
+ /**
+ * Echo method that accepts and returns an UUID.
+ *
+ * @param uuid a java.util.UUID.
+ * @return a result containing the input UUID (as output parameter)
+ */
+ public InvocationResult echoWithUUID(UUID uuid)
+ {
+ InvocationResult result = new InvocationResult(0,"OK",null);
+ Map<String, Object> outputParameters = new HashMap<String, Object>();
+ outputParameters.put("uuid",uuid);
+ result.setOutputSection(outputParameters);
+ return result;
+ }
+
+ /**
+ * Echo method that accepts and returns a Map.
+ *
+ * @param map a java.util.Map.
+ * @return a result containing the input Map (as output parameter)
+ */
+ public InvocationResult echoWithMap(Map<String,Object> map)
+ {
+ InvocationResult result = new InvocationResult(0,"OK",null);
+ Map<String, Object> outputParameters = new HashMap<String, Object>();
+ outputParameters.put("map",map);
+ result.setOutputSection(outputParameters);
+ return result;
+ }
+
+ public UUID getVhostRef()
+ {
+ return _vhostRef;
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public Boolean getDurable()
+ {
+ return _durable;
+ }
+
+ public Map<String, Object> getArguments()
+ {
+ return _arguments;
+ }
+
+ public Long getMsgTotalEnqueues()
+ {
+ return _msgTotalEnqueues;
+ }
+
+ public Integer getConsumerCount()
+ {
+ return _consumerCount;
+ }
+
+ public Date getExpireTime()
+ {
+ return _expireTime;
+ }
+
+ public Short getMgmtPubInterval()
+ {
+ return _mgmtPubInterval;
+ }
+
+ public void setExpireTime(Date expireTime)
+ {
+ this._expireTime = expireTime;
+ }
+
+ public void setMgmtPubInterval(Short value)
+ {
+ this._mgmtPubInterval = value;
+ }
+
+ public void setType(String type)
+ {
+ this._type = type;
+ }
+
+ public String getType()
+ {
+ return _type;
+ }
+
+ public byte[] getByteArray()
+ {
+ return _byteArray;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/QpidDomainObjectMBean.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/QpidDomainObjectMBean.java
new file mode 100644
index 0000000000..da585a9f43
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/QpidDomainObjectMBean.java
@@ -0,0 +1,234 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.handler.impl;
+
+import java.net.URI;
+import java.util.Date;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * Management interface for Qpid domain object.
+ *
+ * @author Andrea Gazzarini
+ */
+public interface QpidDomainObjectMBean
+{
+ /**
+ * A method that is throwing an exception, everytime.
+ *
+ * @throws Exception each time the method is called.
+ */
+ void throwsException() throws Exception;
+
+ /**
+ * Sample echo method that return an empty result object.
+ * That is, an object with only status code / text valorized
+ * (no output parameters).
+ *
+ * @return an empty result object.
+ */
+ InvocationResult voidWithoutArguments();
+
+ /**
+ * Echo method that accepts and returns wrapper types.
+ *
+ * @param aLong a java.lang.Long
+ * @param aBoolean a java.lang.Boolean
+ * @param aDouble a java.lang.Double
+ * @param aFloat a java.lang.Float
+ * @param anInteger a java.lang.Integer
+ * @param aShort a java.lang.Short
+ * @param aString a java.lang.String
+ * @param anURI a java.net.URI
+ * @param aDate a java.util.Date
+ * @return a result object with the same given parameters (as output parameters)
+ */
+ InvocationResult echoWithSimpleTypes(
+ Long aLong,
+ Boolean aBoolean,
+ Double aDouble,
+ Float aFloat,
+ Integer anInteger,
+ Short aShort,
+ String aString,
+ URI anURI,
+ Date aDate);
+
+ /**
+ * Echo method that accepts and returns wrapper type arrays .
+ *
+ * @param longs an array of java.lang.Long
+ * @param booleans an array of java.lang.Boolean
+ * @param doubles an array of java.lang.Double
+ * @param floats an array of java.lang.Float
+ * @param integers an array of java.lang.Integer
+ * @param shorts an array of java.lang.Short
+ * @param strings an array of java.lang.String
+ * @param uris an array of java.net.URI
+ * @param dates an array of java.util.Date
+ * @return a result object with the same input parameters (as output parameters).
+ */
+ InvocationResult echoWithArrays(
+ Long [] longs,
+ Boolean [] booleans,
+ Double [] doubles,
+ Float [] floats,
+ Integer [] integers,
+ Short [] shorts,
+ String [] strings,
+ URI [] uris,
+ Date [] dates);
+
+ /**
+ * Echo method that accepts and returns primitive type arrays.
+ *
+ * @param longs an array of long.
+ * @param booleans an array of boolean.
+ * @param doubles an array of double.
+ * @param floats an array of float.
+ * @param integers an array of int.
+ * @param shorts an array of short.
+ * @return a result object with the same input parameters (as output parameters).
+ */
+ InvocationResult echoWithSimpleTypeArrays(
+ long [] longs,
+ boolean [] booleans,
+ double [] doubles,
+ float [] floats,
+ int [] integers,
+ short [] shorts);
+
+ /**
+ * Echo method that accepts and returns a byte array.
+ *
+ * @param byteArray a byte array
+ * @return a result containing the input byte array (as output parameter)
+ */
+ InvocationResult echoWithByteArray(byte [] byteArray);
+
+ /**
+ * Echo method that accepts and returns an UUID.
+ *
+ * @param uuid a java.util.UUID.
+ * @return a result containing the input UUID (as output parameter)
+ */
+ InvocationResult echoWithUUID(UUID uuid);
+
+ /**
+ * Echo method that accepts and returns a Map.
+ *
+ * @param map a java.util.Map.
+ * @return a result containing the input Map (as output parameter)
+ */
+ InvocationResult echoWithMap(Map<String,Object> map);
+
+ /**
+ * Returns the VHostRef property value.
+ *
+ * @return the VHostRef property value.
+ */
+ UUID getVhostRef();
+
+ /**
+ * Returns the name property value.
+ *
+ * @return the name property value.
+ */
+ String getName();
+
+ /**
+ * Returns the durable property value.
+ *
+ * @return the durable property value.
+ */
+ Boolean getDurable();
+
+ /**
+ * Returns the arguments property value.
+ *
+ * @return the arguments property value.
+ */
+ Map<String, Object> getArguments();
+
+ /**
+ * Returns the msgTotalEnqueues property value.
+ *
+ * @return the msgTotalEnqueues property value.
+ */
+ Long getMsgTotalEnqueues();
+
+ /**
+ * Returns the consumerCount property value.
+ *
+ * @return the consumerCount property value.
+ */
+ Integer getConsumerCount();
+
+ /**
+ * Returns the mgmtPubInterval property value.
+ *
+ * @return the mgmtPubInterval property value.
+ */
+ Short getMgmtPubInterval();
+
+ /**
+ * Sets the mgmtPubInterval property value.
+ *
+ * @param the mgmtPubInterval property value.
+ */
+ void setMgmtPubInterval(Short mgmtPubInterval);
+
+ /**
+ * Returns the expireTime property value.
+ *
+ * @return the expireTime property value.
+ */
+ Date getExpireTime();
+
+ /**
+ * Sets the expireTime property value.
+ *
+ * @return the expireTime property value.
+ */
+ void setExpireTime(Date expireTime);
+
+ /**
+ * Returns the type property value.
+ *
+ * @return the type property value.
+ */
+ void setType(String type);
+
+ /**
+ * Sets the type property value.
+ *
+ * @return the type property value.
+ */
+ String getType();
+
+// /**
+// * Returns the byteArray property value.
+// *
+// * @return the byteArray property value.
+// */
+// byte[] getByteArray();
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/SchemaResponseMessageHandler.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/SchemaResponseMessageHandler.java
new file mode 100644
index 0000000000..4564acc9d0
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/SchemaResponseMessageHandler.java
@@ -0,0 +1,217 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.handler.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.Protocol;
+import org.apache.qpid.management.domain.handler.base.BaseMessageHandler;
+import org.apache.qpid.management.domain.model.type.Binary;
+import org.apache.qpid.transport.codec.Decoder;
+
+/**
+ * Schema Response message handler.
+ * This handler is responsible to process 'S'(opcode) messages sent by the management broker containing the full
+ * schema details for a class.
+ *
+ * @author Andrea Gazzarini
+ */
+public class SchemaResponseMessageHandler extends BaseMessageHandler
+{
+ /**
+ * Behavioural interface for classes that are responsible to deal with schema messages.
+ *
+ * @author Andrea Gazzarini
+ */
+ interface IProcessor
+ {
+ /**
+ * Processes the incoming message using the given decoder.
+ *
+ * @param decoder the decoder used for dealing with incoming message.
+ */
+ void process(Decoder decoder);
+ }
+
+ /**
+ * Processor responsible to deal with class schema related messages.
+ */
+ final IProcessor _classSchemaProcessor = new IProcessor()
+ {
+ public void process(Decoder decoder)
+ {
+ try
+ {
+ String packageName = decoder.readStr8();
+ String className = decoder.readStr8();
+
+ Binary schemaHash = new Binary(decoder.readBin128());
+
+ int howManyProperties = decoder.readUint16();
+ int howManyStatistics = decoder.readUint16();
+ int howManyMethods = decoder.readUint16();
+
+ _domainModel.addSchema(
+ packageName,
+ className,
+ schemaHash,
+ getAttributes(decoder, howManyProperties),
+ getAttributes(decoder, howManyStatistics),
+ getMethods(decoder, howManyMethods));
+ } catch(Exception exception)
+ {
+ _logger.error(exception,Messages.QMAN_100005_CLASS_SCHEMA_PROCESSING_FAILURE);
+ }
+ }
+ };
+
+ /**
+ * Processor responsible to deal with class event related messages.
+ */
+ final IProcessor _eventSchemaProcessor = new IProcessor()
+ {
+ public void process(Decoder decoder)
+ {
+ try
+ {
+ String packageName = decoder.readStr8();
+ String className = decoder.readStr8();
+ Binary hash = new Binary(decoder.readBin128());
+ int howManyArguments = decoder.readUint16();
+
+ _domainModel.addEventSchema(
+ packageName,
+ className,
+ hash,
+ getAttributes(decoder, howManyArguments));
+ } catch(Exception exception)
+ {
+ _logger.error(exception,Messages.QMAN_100006_EVENT_SCHEMA_PROCESSING_FAILURE);
+ }
+ }
+ };
+
+ /**
+ * Processes an incoming schema response.
+ * This will be used for building the corresponding class definition.
+ *
+ * @param decoder the decoder used for parsing the incoming stream.
+ * @param sequenceNumber the sequence number of the incoming message.
+ */
+ public void process (Decoder decoder, int sequenceNumber)
+ {
+ try
+ {
+ int classKind = decoder.readUint8();
+ switch(classKind)
+ {
+ case Protocol.CLASS :
+ {
+ _classSchemaProcessor.process(decoder);
+ break;
+ }
+ case Protocol.EVENT :
+ {
+ _eventSchemaProcessor.process(decoder);
+ break;
+ }
+ default :
+ {
+ _logger.error(Messages.QMAN_100011_UNKNOWN_CLASS_KIND,classKind);
+ }
+ }
+ } catch(Exception exception)
+ {
+ _logger.error(exception,Messages.QMAN_100012_SCHEMA_MESSAGE_PROCESSING_FAILURE);
+ }
+ }
+
+ /**
+ * Reads from the incoming message stream the properties definitions.
+ *
+ * @param decoder the decoder used for decode incoming data.
+ * @param howManyProperties the number of properties to read.
+ * @return a list of maps. Each map contains a property definition.
+ */
+ List<Map<String, Object>> getAttributes(Decoder decoder,int howMany)
+ {
+ List<Map<String, Object>> result = new ArrayList<Map<String, Object>>(howMany);
+ for (int i = 0; i < howMany; i++ )
+ {
+ result.add(decoder.readMap());
+ }
+ return result;
+ }
+
+ /**
+ * Reads the methods definitions from the incoming message stream.
+ *
+ * @param decoder the decoder used for decode incoming data.
+ * @param howManyMethods the number of methods to read.
+ * @return a list method definitions.
+ */
+ List<MethodOrEventDataTransferObject> getMethods(Decoder decoder, int howManyMethods)
+ {
+ List<MethodOrEventDataTransferObject> result = new ArrayList<MethodOrEventDataTransferObject>(howManyMethods);
+ for (int i = 0; i < howManyMethods; i++)
+ {
+ Map<String,Object> method = decoder.readMap();
+ int howManyArguments = (Integer) method.get(Names.ARG_COUNT_PARAM_NAME);
+
+ List<Map<String,Object>> arguments = new ArrayList<Map<String,Object>>(howManyArguments);
+ for (int argIndex = 0; argIndex < howManyArguments; argIndex++)
+ {
+ arguments.add(decoder.readMap());
+ }
+ result.add(new MethodOrEventDataTransferObject(method,arguments));
+ }
+ return result;
+ }
+
+ /**
+ * Reads the events definitions from the incoming message stream.
+ *
+ * @param decoder the decoder used for decode incoming data.
+ * @param howManyEvents the number of events to read.
+ * @return a list event definitions.
+ */
+ List<MethodOrEventDataTransferObject> getEvents(Decoder decoder, int howManyEvents)
+ {
+ List<MethodOrEventDataTransferObject> result = new ArrayList<MethodOrEventDataTransferObject>(howManyEvents);
+ for (int i = 0; i < howManyEvents; i++)
+ {
+ Map<String,Object> method = decoder.readMap();
+ int howManyArguments = (Integer) method.get(Names.ARG_COUNT_PARAM_NAME);
+
+ List<Map<String,Object>> arguments = new ArrayList<Map<String,Object>>(howManyArguments);
+ for (int argIndex = 0; argIndex < howManyArguments; argIndex++)
+ {
+ arguments.add(decoder.readMap());
+ }
+ result.add(new MethodOrEventDataTransferObject(method,arguments));
+ }
+ return result;
+ }
+ }
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/AccessMode.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/AccessMode.java
new file mode 100644
index 0000000000..6d1426c122
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/AccessMode.java
@@ -0,0 +1,33 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+/**
+ * Enumeration for Access modes.
+ *
+ * @author Andrea Gazzarini
+ */
+public enum AccessMode
+{
+ RC { @Override public String toString() { return "Read-Create"; }},
+ RO { @Override public String toString() { return "Read-Only"; }},
+ RW { @Override public String toString() { return "Read-Write"; }}
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/Direction.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/Direction.java
new file mode 100644
index 0000000000..8166c35eb6
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/Direction.java
@@ -0,0 +1,33 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+/**
+ * Enumeration of allowed method argument direction codes.
+ *
+ * @author Andrea Gazzarini
+ */
+public enum Direction
+{
+ I{ @Override public String toString() { return "Input"; }},
+ O{ @Override public String toString() { return "Output"; }},
+ IO{ @Override public String toString() { return "Input-Output"; }};
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/DomainModel.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/DomainModel.java
new file mode 100644
index 0000000000..5a0ebaf1f7
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/DomainModel.java
@@ -0,0 +1,239 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.qpid.management.domain.handler.impl.IMethodInvocationListener;
+import org.apache.qpid.management.domain.handler.impl.MethodOrEventDataTransferObject;
+import org.apache.qpid.management.domain.model.type.Binary;
+
+/**
+ * Broker domain model.
+ * This is the local representation of a remote broker domain model.
+ *
+ * @author Andrea Gazzarini
+ */
+public class DomainModel
+{
+ private final UUID _id;
+
+ /** Here the known packages of the remote broker are stored. */
+ Map<String,QpidPackage> _packages = new HashMap<String, QpidPackage>();
+
+ private Date _lastRefreshDate = new Date();
+
+ private IMethodInvocationListener _methodInvocationListener;
+
+ /**
+ * Builds a new domain model with the given broker identifier.
+ *
+ * @param brokerId the broker identifier.
+ */
+ public DomainModel(UUID brokerId)
+ {
+ this._id = brokerId;
+ }
+
+ /**
+ * Returns the identifier of the broker associated with this domain model.
+ *
+ * @return the identifier of the broker associated with this domain model.
+ */
+ public UUID getBrokerId()
+ {
+ return _id;
+ }
+
+ /**
+ * Adds the specified schema to this domain model.
+ *
+ * @param packageName the package name.
+ * @param className the class name.
+ * @param classHash the class schema hash.
+ * @param properties the class properties.
+ * @param statistics the class statistics.
+ * @param methods the class methods.
+ * @throws UnableToBuildFeatureException
+ */
+ public void addSchema(
+ String packageName,
+ String className,
+ Binary classHash,
+ List<Map<String, Object>> properties,
+ List<Map<String, Object>> statistics,
+ List<MethodOrEventDataTransferObject> methods) throws UnableToBuildFeatureException
+ {
+ QpidPackage qpidPackage = getPackageByName(packageName);
+ qpidPackage.addClassDefinition(className,classHash,properties,statistics,methods);
+ }
+
+ /**
+ * Updates the last refresh date.
+ */
+ public void updateLastRefreshDate()
+ {
+ this._lastRefreshDate = new Date();
+ }
+
+ /**
+ * Returns the last refresh date.
+ *
+ * @return the last refresh date.
+ */
+ public Date getLastRefreshDate()
+ {
+ return _lastRefreshDate;
+ }
+
+ /**
+ * Adds the specified schema to this domain model.
+ *
+ * @param packageName the package name.
+ * @param className the class name.
+ * @param classHash the class schema hash.
+ * @param properties the class properties.
+ * @param statistics the class statistics.
+ * @param methods the class methods.
+ * @throws UnableToBuildFeatureException
+ */
+ public void addEventSchema(
+ String packageName,
+ String className,
+ Binary classHash,
+ List<Map<String, Object>> arguments) throws UnableToBuildFeatureException
+ {
+ QpidPackage qpidPackage = getPackageByName(packageName);
+ qpidPackage.addEventDefinition(className,classHash,arguments);
+ }
+
+ /**
+ * Gets the package with the specified name.
+ * Note that if the package doesn't exist a new one will be created and returned.
+ *
+ * @param packageName the name of the package.
+ * @return the package.
+ */
+ QpidPackage getPackageByName (String packageName)
+ {
+ QpidPackage qpidPackage = _packages.get(packageName);
+ if (qpidPackage == null)
+ {
+ qpidPackage = new QpidPackage(packageName,this);
+ _packages.put(packageName, qpidPackage);
+ }
+ return qpidPackage;
+ }
+
+ /**
+ * Returns true if a package with the specified name already exists on this domain model.
+ *
+ * @param packageName the name of the package.
+ * @return true if the package exists, false otherwise.
+ */
+ boolean containsPackage (String packageName)
+ {
+ return _packages.containsKey(packageName);
+ }
+
+ /**
+ * Adds the given instrumentation data (raw format) to this domain model.
+ * Note that this data is belonging to a specific object instance.
+ *
+ * @param packageName the name of the ower package.
+ * @param className the name of the owner class.
+ * @param classHash the schema hash for this class.
+ * @param objectId the object instance identifier.
+ * @param rawData the instrumentation data.
+ */
+ public void addInstrumentationRawData (String packageName, String className,Binary classHash, Binary objectId, byte[] rawData)
+ {
+ QpidPackage qpidPackage = getPackageByName(packageName);
+ qpidPackage.setObjectInstanceInstrumentationRawData(className,classHash,objectId,rawData);
+ }
+
+ public void addEventRawData (
+ String packageName,
+ String eventName,
+ Binary eventHash,
+ byte[] rawData,
+ long currentTimestamp,
+ int severity)
+ {
+ QpidPackage qpidPackage = getPackageByName(packageName);
+ qpidPackage.setEventInstanceRawData(eventName,eventHash,rawData,currentTimestamp,severity);
+ }
+
+ /**
+ * Adds the given configuration data (raw format) to this domain model.
+ * Note that this data is belonging to a specific object instance.
+ *
+ * @param packageName the name of the ower package.
+ * @param className the name of the owner class.
+ * @param classHash the schema hash for this class.
+ * @param objectId the object instance identifier.
+ * @param rawData the configuration data.
+ */
+ public void addConfigurationRawData (String packageName, String className, Binary classHash,Binary objectId, byte[] rawData)
+ {
+ QpidPackage qpidPackage = getPackageByName(packageName);
+ qpidPackage.setObjectInstanceConfigurationRawData(className,classHash,objectId,rawData);
+ }
+
+ /**
+ * Removes the object instance associated to the given parameters.
+ *
+ * @param packageName the owner package.
+ * @param className the class definition of the object instance.
+ * @param classHash the class hash
+ * @param objectId the object identifier.
+ */
+ public void removeObjectInstance (String packageName, String className, Binary classHash, Binary objectId)
+ {
+ QpidPackage qpidPackage = getPackageByName(packageName);
+ qpidPackage.removeObjectInstance(className, classHash, objectId);
+ }
+
+ /**
+ * Releases all the resources kept by domain model entitiies.
+ */
+ public void releaseResources()
+ {
+ for (QpidPackage qpidPackage : _packages.values())
+ {
+ qpidPackage.releaseResources();
+ }
+ }
+
+ public void setMethodInvocationListener(IMethodInvocationListener listener)
+ {
+ this._methodInvocationListener = listener;
+ }
+
+ IMethodInvocationListener getMethodInvocationListener ()
+ {
+ return _methodInvocationListener;
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/IValidator.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/IValidator.java
new file mode 100644
index 0000000000..1ede559145
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/IValidator.java
@@ -0,0 +1,38 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+/**
+ * Interface definition for attribute validators.
+ *
+ * @author Andrea Gazzarini
+ */
+interface IValidator
+{
+ /**
+ * Validates the given value according to the rules definied by this validator.
+ *
+ * @param value the value be checked.
+ *
+ * @throws ValidationException when the value is violating validator's rules.
+ */
+ void validate(Object value) throws ValidationException;
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/InvocationEvent.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/InvocationEvent.java
new file mode 100644
index 0000000000..d84a018346
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/InvocationEvent.java
@@ -0,0 +1,76 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import java.util.EventObject;
+import java.util.concurrent.BlockingQueue;
+
+import org.apache.qpid.management.domain.handler.impl.InvocationResult;
+
+/**
+ * Operation invocation event.
+ * This encapsulates all the information that a method invocation listener needs to know about an operation which is
+ * going to be invoked.
+ *
+ * @author Andrea Gazzarini
+ */
+public class InvocationEvent extends EventObject
+{
+ private static final long serialVersionUID = 240229490753008597L;
+
+ private final int _sequenceNumber;
+ private final BlockingQueue<InvocationResult> _exchangeChannel;
+
+ /**
+ * Builds a new invocation event with the given data.
+ *
+ * @param source the event source.
+ * @param sequenceNumber the sequence number of the method invocation.
+ * @param exchangeChannel the exchange channel for synchronous communication.
+ */
+ InvocationEvent(Object source, int sequenceNumber, BlockingQueue<InvocationResult> exchangeChannel)
+ {
+ super(source);
+ this._sequenceNumber = sequenceNumber;
+ this._exchangeChannel = exchangeChannel;
+ }
+
+ /**
+ * Returns the sequence number that will be / has been used for method invocation.
+ *
+ * @return the sequence number that will be / has been used for method invocation.
+ */
+ public int getSequenceNumber()
+ {
+ return _sequenceNumber;
+ }
+
+ /**
+ * Returns the exchange channel that will be used between event source and event listener for synchronous
+ * communication.
+ *
+ * @return the exchange channel that will be used for synchronous communication.
+ */
+ public BlockingQueue<InvocationResult> getExchangeChannel()
+ {
+ return _exchangeChannel;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/JmxService.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/JmxService.java
new file mode 100644
index 0000000000..657d7e6210
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/JmxService.java
@@ -0,0 +1,410 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import java.lang.management.ManagementFactory;
+import java.util.Set;
+import java.util.UUID;
+
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.domain.model.QpidClass.QManManagedObject;
+import org.apache.qpid.management.domain.model.QpidEvent.QManManagedEvent;
+import org.apache.qpid.management.domain.model.type.Binary;
+import org.apache.qpid.management.domain.services.QMan;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * A simple facade used to perform operations on Mbean server.
+ */
+public class JmxService
+{
+ private final static Logger LOGGER = Logger.get(JmxService.class);
+ MBeanServer _mxServer = ManagementFactory.getPlatformMBeanServer();
+
+ /**
+ * Registers QMan with the MBeanServer.
+ * After that QMan management interface will be JMX-exposed.
+ *
+ * @param qman QMan
+ * @throws MBeanException when some error occurs during registration.
+ */
+ public void registerQManService(QMan qman) throws MBeanException
+ {
+ if (!_mxServer.isRegistered(Names.QMAN_OBJECT_NAME))
+ {
+ try {
+ _mxServer.registerMBean(qman, Names.QMAN_OBJECT_NAME);
+ } catch (Exception exception) {
+ throw new MBeanException(exception);
+ }
+ }
+ }
+
+ /**
+ * Registers an event instance with MBean server.
+ *
+ * @param eventInstance the mben event instance
+ * @param brokerId the broker identifier.
+ * @param packageName the package name.
+ * @param eventClassName the event class name.
+ * @return the object name used for registration.
+ */
+ ObjectName registerEventInstance(
+ QManManagedEvent eventInstance,
+ UUID brokerId,
+ String packageName,
+ String eventClassName)
+ {
+ ObjectName name = createEventName(brokerId, packageName, eventClassName);
+ if (!_mxServer.isRegistered(name))
+ {
+ try
+ {
+ _mxServer.registerMBean(eventInstance, name);
+
+ LOGGER.debug(
+ Messages.QMAN_200010_EVENT_MBEAN_REGISTERED,
+ brokerId,
+ packageName,
+ eventClassName,
+ name);
+ } catch (Exception exception)
+ {
+ throw new RuntimeException(exception);
+ }
+ }
+ return name;
+}
+
+ /**
+ * Registers a pre-existing object instance as an MBean with the MBean
+ * server.
+ *
+ * @param instance the object instance.
+ * @param brokerId the broker identifier.
+ * @param packageName the name of the package containing this instance.
+ * @param className the name of the owner class of this instance.
+ * @param objectId the object instance identifier.
+ * @return the object name used for registration.
+ */
+ ObjectName registerObjectInstance(
+ QManManagedObject instance,
+ UUID brokerId,
+ String packageName,
+ String className,
+ Binary objectId)
+ {
+ ObjectName name = createObjectName(brokerId, packageName, className, objectId);
+ if (!_mxServer.isRegistered(name))
+ {
+ try
+ {
+ _mxServer.registerMBean(instance, name);
+
+ LOGGER.debug(
+ Messages.QMAN_200011_OBJECT_MBEAN_REGISTERED,
+ brokerId,
+ packageName,
+ className,
+ objectId,
+ name);
+ } catch (Exception exception)
+ {
+ throw new RuntimeException(exception);
+ }
+ }
+ return name;
+ }
+
+ /**
+ * Removes / unregisters a managed object instance from the MBean Server.
+ *
+ * @param brokerId the broker identifier.
+ * @param packageName the name of the package containing this instance.
+ * @param className the name of the owner class of this instance.
+ * @param objectId the object instance identifier.
+ * @return obejctName the obejct name used for deregistration.
+ */
+ ObjectName unregisterObjectInstance(
+ UUID brokerId,
+ String packageName,
+ String className,
+ Binary objectId)
+ {
+ ObjectName name = createObjectName(brokerId, packageName, className, objectId);
+ if (_mxServer.isRegistered(name))
+ {
+ try
+ {
+ _mxServer.unregisterMBean(name);
+
+ LOGGER.debug(
+ Messages.QMAN_200012_OBJECT_MBEAN_UNREGISTERED,
+ brokerId,
+ packageName,
+ className,
+ objectId,
+ name);
+ } catch (Exception exception)
+ {
+ LOGGER.error(exception,Messages.QMAN_100013_MBEAN_REGISTRATION_FAILURE,name);
+ }
+ }
+ return name;
+ }
+
+ /**
+ * Removes (unregister) all events from MBean Server.
+ */
+ void unregisterEvents()
+ {
+ for (ObjectName name : getEventMBeans())
+ {
+ try
+ {
+ _mxServer.unregisterMBean(name);
+ } catch(Exception ignore)
+ {
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ Set<ObjectName> getEventMBeans()
+ {
+ return _mxServer.queryNames(createEventSearchName(),null);
+ }
+
+ /**
+ * Removes (unregister) all object instances from MBean Server.
+ */
+ @SuppressWarnings("unchecked")
+ void unregisterObjectInstances()
+ {
+ Set<ObjectName> names = _mxServer.queryNames(createObjectInstanceSearchName(),null);
+ for (ObjectName name : names)
+ {
+ try
+ {
+ _mxServer.unregisterMBean(name);
+ } catch(Exception ignore)
+ {
+ }
+ }
+ }
+
+ /**
+ * Factory method for ObjectNames.
+ *
+ * @param brokerId the broker identifier.
+ * @param packageName the name of the package containing this instance.
+ * @param className the name of the owner class of this instance.
+ * @param objectId the object instance identifier.
+ * @return the object name built according to the given parameters.
+ */
+ private ObjectName createObjectName(UUID brokerId, String packageName, String className, Binary objectId)
+ {
+ String asString = new StringBuilder()
+ .append(Names.DOMAIN_NAME)
+ .append(':')
+ .append(Names.BROKER_ID)
+ .append('=')
+ .append(brokerId)
+ .append(",type=Object,")
+ .append(Names.PACKAGE)
+ .append('=')
+ .append(packageName)
+ .append(',')
+ .append(Names.CLASS)
+ .append('=')
+ .append(className)
+ .append(',')
+ .append(Names.OBJECT_ID)
+ .append('=')
+ .append(objectId)
+ .toString();
+ try
+ {
+ return new ObjectName(asString);
+ } catch (MalformedObjectNameException exception)
+ {
+ throw new RuntimeException(exception);
+ }
+ }
+
+ /**
+ * Creates an object name that will be used for searching all registered events.
+ *
+ * @return the object name that will be used for searching all registered events.
+ */
+ ObjectName createEventSearchName()
+ {
+ String asString = new StringBuilder()
+ .append(Names.DOMAIN_NAME)
+ .append(':')
+ .append('*')
+ .append(",type=Event")
+ .toString();
+ try
+ {
+ return new ObjectName(asString);
+ } catch (MalformedObjectNameException exception)
+ {
+ throw new RuntimeException(exception);
+ }
+ }
+
+ /**
+ * Creates an object name that will be used for searching all registered events.
+ *
+ * @return the object name that will be used for searching all registered events.
+ */
+ ObjectName createClassDefinitionSearchName()
+ {
+ String asString = new StringBuilder()
+ .append(Names.DOMAIN_NAME)
+ .append(":Category=Schema,*")
+ .toString();
+ try
+ {
+ return new ObjectName(asString);
+ } catch (MalformedObjectNameException exception)
+ {
+ throw new RuntimeException(exception);
+ }
+ }
+
+ /**
+ * Creates an object name that will be used for searching all registered object instances.
+ *
+ * @return the object name that will be used for searching all registered object instances.
+ */
+ private ObjectName createObjectInstanceSearchName()
+ {
+ String asString = new StringBuilder()
+ .append(Names.DOMAIN_NAME)
+ .append(':')
+ .append('*')
+ .append(",type=Object")
+ .toString();
+ try
+ {
+ return new ObjectName(asString);
+ } catch (MalformedObjectNameException exception)
+ {
+ throw new RuntimeException(exception);
+ }
+ }
+
+ /**
+ * Factory method for ObjectNames.
+ *
+ * @param brokerId the broker identifier.
+ * @param packageName the name of the package containing this instance.
+ * @param className the name of the owner class of this instance.
+ * @return the object name built according to the given parameters.
+ */
+ private ObjectName createEventName(UUID brokerId, String packageName, String className)
+ {
+ String asString = new StringBuilder()
+ .append(Names.DOMAIN_NAME)
+ .append(':')
+ .append(Names.BROKER_ID)
+ .append('=')
+ .append(brokerId)
+ .append(",type=Event,")
+ .append(Names.PACKAGE)
+ .append('=')
+ .append(packageName)
+ .append(',')
+ .append(Names.CLASS)
+ .append('=')
+ .append(className)
+ .append(',')
+ .append(Names.OBJECT_ID)
+ .append('=')
+ .append(UUID.randomUUID())
+ .toString();
+ try
+ {
+ return new ObjectName(asString);
+ } catch (MalformedObjectNameException exception)
+ {
+ throw new RuntimeException(exception);
+ }
+ }
+
+ ObjectName createEntityDefinitionName(String packageName, String className, String type)
+ {
+ String asString = new StringBuilder()
+ .append(Names.DOMAIN_NAME)
+ .append(':')
+ .append("Category=Schema,Type=")
+ .append(type)
+ .append(",package=")
+ .append(packageName)
+ .append(",name=")
+ .append(className)
+ .toString();
+ try
+ {
+ return new ObjectName(asString);
+ } catch (MalformedObjectNameException exception)
+ {
+ throw new RuntimeException(exception);
+ }
+ }
+
+ public void registerEntityDefinition(ObjectName name, QpidEntity entity,String packageName, String className)
+ {
+ try
+ {
+ if (!_mxServer.isRegistered(name))
+ _mxServer.registerMBean(entity, name);
+ _mxServer.addNotificationListener(name, Names.QMAN_OBJECT_NAME, null, null);
+ } catch(Exception exception)
+ {
+ throw new RuntimeException(exception);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void unregisterClassDefinitions()
+ {
+ Set<ObjectName> names = _mxServer.queryNames(createClassDefinitionSearchName(),null);
+ for (ObjectName name : names)
+ {
+ try
+ {
+ _mxServer.unregisterMBean(name);
+ } catch(Exception ignore)
+ {
+ }
+ }
+
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/MissingFeatureAttributesException.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/MissingFeatureAttributesException.java
new file mode 100644
index 0000000000..160054059b
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/MissingFeatureAttributesException.java
@@ -0,0 +1,35 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import java.util.List;
+
+import org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute;
+
+public class MissingFeatureAttributesException extends UnableToBuildFeatureException
+{
+ private static final long serialVersionUID = 671471705085787235L;
+
+ public MissingFeatureAttributesException(List<Attribute> missingAttributeList)
+ {
+ super(String.valueOf(missingAttributeList));
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidArgument.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidArgument.java
new file mode 100644
index 0000000000..e126fcb8f5
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidArgument.java
@@ -0,0 +1,123 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.transport.codec.Encoder;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * An argument is the formal definition of a parameter belonging to a specific method / operation.
+ */
+class QpidArgument extends QpidProperty
+{
+ private final static Logger LOGGER = Logger.get(QpidArgument.class);
+
+ private Object _defaultValue;
+
+ private Direction _direction;
+
+ /**
+ * Sets the direction of this argument.
+ *
+ * @param the direction of this argument.
+ */
+ public void setDirection(String code)
+ {
+ this._direction = Direction.valueOf(code);
+ }
+
+ /**
+ * Returns the direction of this argument.
+ *
+ * @return the direction of this argument.
+ */
+ public Direction getDirection()
+ {
+ return _direction;
+ }
+
+ /**
+ * Sets the default value of this argument.
+ *
+ * @param defaultValue the default value of this argument.
+ */
+ public void setDefaultValue(Object defaultValue)
+ {
+ this._defaultValue = defaultValue;
+ }
+
+ /**
+ * Returns the default value of this argument.
+ *
+ * @return the default value of this argument.
+ */
+ public Object getDefaultValue()
+ {
+ return _defaultValue;
+ }
+
+ /**
+ * Returns true if this is an Input argument.
+ *
+ * @return true if this is an Input argument.
+ */
+ public boolean isInput()
+ {
+ return _direction != Direction.O;
+ }
+
+ @Override
+ public String toString ()
+ {
+ return new StringBuilder()
+ .append(getJavaType().getName())
+ .append(' ')
+ .append(_name)
+ .append("(")
+ .append(_direction)
+ .append(")")
+ .toString();
+ }
+
+ /**
+ * Encodes the given value according to this argument type & definition.
+ *
+ * @param value the value to be encoded.
+ * @param encoder the encoder.
+ */
+ public void encode(Object value,Encoder encoder)
+ {
+ _type.encode(value, encoder);
+ LOGGER.debug(Messages.QMAN_200013_ARGUMENT_VALUE_ENCODED,value,_name,_type);
+ }
+
+ /**
+ * Decodes the value for this argument according to its type & definition.
+ *
+ * @param decoder the decoder
+ * @return the decoded value of this argument.
+ */
+ public Object decode(org.apache.qpid.transport.codec.Decoder decoder)
+ {
+ return _type.decode(decoder);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidAttribute.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidAttribute.java
new file mode 100644
index 0000000000..6712a14075
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidAttribute.java
@@ -0,0 +1,105 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.domain.model.type.Type;
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * Layer supertype for qpid properties and statistics.
+ *
+ * @author Andrea Gazzarini
+ */
+class QpidAttribute extends QpidFeature
+{
+ private final static Logger LOGGER = Logger.get(QpidAttribute.class);
+
+ /** feature type */
+ protected Type _type;
+
+ /** feature unit */
+ protected String _unit;
+
+ /**
+ * Returns the units used for numeric values (i.e. seconds, bytes, etc.)
+ *
+ * @return the units used for numeric values (i.e. seconds, bytes, etc.)
+ */
+ String getUnit ()
+ {
+ return _unit;
+ }
+
+ /**
+ * Sets the unit for this property.
+ *
+ * @param unit the unit of this property.
+ */
+ void setUnit (String unit)
+ {
+ this._unit = unit;
+ }
+
+ /**
+ * Returns the java type (class) of this feature.
+ *
+ * @return the java type (class) of this feature.
+ */
+ Class<?> getJavaType ()
+ {
+ return _type.getJavaType();
+ }
+
+ /**
+ * Sets the type of this feature.
+ *
+ * @param type the type of this feature.
+ */
+ void setType (Type type)
+ {
+ this._type = type;
+ }
+
+ /**
+ * Gets the value of this feature according to its type definition.
+ *
+ * @param decoder the decoder used to extract the value.
+ * @return the value of this feature according to its type definition
+ */
+ Object decodeValue(Decoder decoder)
+ {
+ try {
+ return _type.decode(decoder);
+ } catch(RuntimeException exception)
+ {
+ LOGGER.error(exception,Messages.QMAN_100014_ATTRIBUTE_DECODING_FAILURE,this);
+ throw exception;
+ }
+ }
+
+ @Override
+ public String toString ()
+ {
+ return super.toString()+",type="+_type;
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidClass.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidClass.java
new file mode 100644
index 0000000000..667e600668
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidClass.java
@@ -0,0 +1,833 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.Map.Entry;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.RuntimeOperationsException;
+
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.domain.handler.impl.IMethodInvocationListener;
+import org.apache.qpid.management.domain.handler.impl.InvocationResult;
+import org.apache.qpid.management.domain.handler.impl.MethodOrEventDataTransferObject;
+import org.apache.qpid.management.domain.model.type.Binary;
+import org.apache.qpid.management.domain.services.SequenceNumberGenerator;
+import org.apache.qpid.management.jmx.EntityLifecycleNotification;
+import org.apache.qpid.management.jmx.OperationHasBeenInvokedNotification;
+import org.apache.qpid.transport.codec.BBDecoder;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * Qpid Class definition.
+ * A type definition for a manageable object.
+ * This class is also responsible to manage incoming obejct instance data (configuration & instrumentation).
+ * How can we handle data before schema is injected into this class? simply we must retain that data in raw format.
+ * This class has 3 states :
+ * 1) first state is when schema is not yet injected. In this case the incoming object data is retained as is (in raw format)
+ * and a schema request is sent;
+ * 2) second state is when schema has been requested but not yet injected. The incoming object data is still retained as is
+ * (in raw format)
+ * 3) third state is when schema is injected. Each injection of data will result in an update / create / delete of
+ * the corresponding object instance. In addition, the first time the state change, the old retained raw data is cnverted in
+ * object instance(s).
+ */
+class QpidClass extends QpidEntity implements QpidClassMBean
+{
+ /**
+ * State interface for this class definition.
+ * Each state is responsible to handle the injection of the data and / or schema.
+ *
+ * @author Andrea Gazzarini
+ */
+ interface State
+ {
+ /**
+ * Adds configuration data for the object instance associated to the given object identifier.
+ *
+ * @param objectId the object identifier.
+ * @param rawData the raw configuration data.
+ */
+ void addInstrumentationData (Binary objectId, byte[] rawData);
+
+ /**
+ * Adds instrumentation data for the object instance associated to the given object identifier.
+ *
+ * @param objectId the object identifier.
+ * @param rawData the raw instrumentation data.
+ */
+ void addConfigurationData (Binary objectId, byte[] rawData);
+
+ /**
+ * Inject the schema into this class definition.
+ *
+ * @param propertyDefinitions
+ * @param statisticDefinitions
+ * @param methodDefinitions
+ * @throws UnableToBuildFeatureException when it's not possibile to parse schema and build the class definition.
+ */
+ public void setSchema (
+ List<Map<String, Object>> propertyDefinitions,
+ List<Map<String, Object>> statisticDefinitions,
+ List<MethodOrEventDataTransferObject> methodDefinitions) throws UnableToBuildFeatureException;
+ };
+
+ /**
+ * This is the initial state of every qpid class.
+ * The class definition instance is created but its schema has not been injected.
+ * Incoming configuration & instrumentation data will be stored in raw format because we don't know how to
+ * parse it until the schema arrives.
+ * In addition, this state is responsible (when data arrives) to request its schema.
+ */
+ final State _schemaNotRequested = new State() {
+
+ /**
+ * Stores the incoming data in raw format and request the schema for this class.
+ * After that a transition to the next state is made.
+ *
+ * @param objectId the object instance identifier.
+ * @param rawData incoming configuration data.
+ */
+ public synchronized void addConfigurationData (Binary objectId, byte[] rawData)
+ {
+ try
+ {
+ requestSchema();
+ _state = _schemaRequestedButNotYetInjected;
+ } catch (Exception exception)
+ {
+ _logger.error(
+ exception,
+ Messages.QMAN_100015_UNABLE_TO_SEND_SCHEMA_REQUEST,
+ _parent.getName(),
+ _name);
+ } finally {
+ QManManagedObject instance = getObjectInstance(objectId,false);
+ instance._rawConfigurationData.add(rawData);
+ }
+ }
+
+ /**
+ * Stores the incoming data in raw format and request the schema for this class.
+ * After that a transition to the next state is made.
+ *
+ * @param objectId the object instance identifier.
+ * @param rawData incoming instrumentation data.
+ */
+ public synchronized void addInstrumentationData (Binary objectId, byte[] rawData)
+ {
+ try
+ {
+ requestSchema();
+ _state = _schemaRequestedButNotYetInjected;
+ } catch (Exception e)
+ {
+ _logger.error(
+ Messages.QMAN_100015_UNABLE_TO_SEND_SCHEMA_REQUEST,
+ _parent.getName(),
+ _name);
+ } finally {
+ QManManagedObject instance = getObjectInstance(objectId,false);
+ instance._rawConfigurationData.add(rawData);
+ }
+ }
+
+ /**
+ * This method only throws an illegal state exception because when a schema arrives
+ * this state is no longer valid.
+ */
+ public void setSchema (
+ List<Map<String, Object>> propertyDefinitions,
+ List<Map<String, Object>> statisticDefinitions,
+ List<MethodOrEventDataTransferObject> methodDefinitions) throws UnableToBuildFeatureException
+ {
+ throw new IllegalStateException("When a schema arrives it's not possible for this class to be in this state.");
+ }
+ };
+
+ /**
+ * This is the first state of this class definition : the schema is not yet injected so each injection of object data will be
+ * retained in raw format.
+ */
+ final State _schemaRequestedButNotYetInjected = new State()
+ {
+ /**
+ * Stores the incoming data in raw format.
+ *
+ * @param objectId the object instance identifier.
+ * @param rawData incoming configuration data.
+ */
+ public void addConfigurationData (Binary objectId, byte[] rawData)
+ {
+ QManManagedObject instance = getObjectInstance(objectId,false);
+ instance._rawConfigurationData.add(rawData);
+ }
+
+ /**
+ * Stores the incoming data in raw format.
+ *
+ * @param objectId the object instance identifier.
+ * @param rawData incoming instrumentation data.
+ */
+ public void addInstrumentationData (Binary objectId, byte[] rawData)
+ {
+ QManManagedObject instance = getObjectInstance(objectId,false);
+ instance._rawInstrumentationData.add(rawData);
+ }
+
+ /**
+ * When a schema is injected into this defintiion the following should happen :
+ * 1) the incoming schema is parsed and the class definition is built;
+ * 2) the retained raw data is converted into object instance(s)
+ * 3) the internal state of this class changes;
+ *
+ * If someting is wrong during that process the schema is not built and the state don't change.
+ */
+ public synchronized void setSchema (
+ List<Map<String, Object>> propertyDefinitions,
+ List<Map<String, Object>> statisticDefinitions,
+ List<MethodOrEventDataTransferObject> methodDefinitions) throws UnableToBuildFeatureException
+ {
+
+ MBeanAttributeInfo [] attributesMetadata = new MBeanAttributeInfo[propertyDefinitions.size()+statisticDefinitions.size()];
+ MBeanOperationInfo [] operationsMetadata = new MBeanOperationInfo[methodDefinitions.size()];
+
+ buildAttributes(propertyDefinitions,statisticDefinitions,attributesMetadata);
+ buildMethods(methodDefinitions,operationsMetadata);
+
+ _metadata = new MBeanInfo(_name,_name,attributesMetadata,null,operationsMetadata,null);
+
+ EntityLifecycleNotification notification = new EntityLifecycleNotification(
+ EntityLifecycleNotification.SCHEMA_INJECTED_NOTIFICATION_TYPE,
+ _parent.getName(),
+ _name,
+ Names.CLASS,
+ _objectName);
+
+ sendNotification(notification);
+
+ // Converting stored object instances into JMX MBean and removing raw instance data.
+ for (Entry<Binary, QManManagedObject> instanceEntry : _objectInstances.entrySet())
+ {
+ Binary objectId = instanceEntry.getKey();
+ QManManagedObject instance = instanceEntry.getValue();
+
+ for (Iterator<byte[]> iterator = instance._rawInstrumentationData.iterator(); iterator.hasNext();)
+ {
+ updateInstanceWithInstrumentationData(instance,iterator.next());
+ iterator.remove();
+ }
+
+ for (Iterator<byte[]> iterator = instance._rawConfigurationData.iterator(); iterator.hasNext();)
+ {
+ updateInstanceWithConfigurationData(instance, iterator.next());
+ iterator.remove();
+ }
+
+ registerMBean(instance,_parent.getOwnerId(),_parent.getName(),_name,objectId);
+ }
+ _state = _schemaInjected;
+
+ }
+ };
+
+ /**
+ * After a schema is built into this definition this is the current state of the class.
+ */
+ final State _schemaInjected = new State()
+ {
+ /**
+ * Updates the configuration state of the object instance associates with the given object identifier.
+ *
+ * @param objectId the object identifier.
+ * @param rawData the configuration data (raw format).
+ */
+ public void addConfigurationData (Binary objectId, byte[] rawData)
+ {
+ QManManagedObject instance = getObjectInstance(objectId,true);
+ updateInstanceWithConfigurationData(instance, rawData);
+ }
+
+ /**
+ * Updates the instrumentation state of the object instance associates with the given object identifier.
+ *
+ * @param objectId the object identifier.
+ * @param rawData the instrumentation data (raw format).
+ */
+ public void addInstrumentationData (Binary objectId, byte[] rawData)
+ {
+ QManManagedObject instance = getObjectInstance(objectId,true);
+ updateInstanceWithInstrumentationData(instance, rawData);
+ }
+
+ /**
+ * Never called when the class definition has this state.
+ */
+ public void setSchema (
+ List<Map<String, Object>> propertyDefinitions,
+ List<Map<String, Object>> statisticDefinitions,
+ List<MethodOrEventDataTransferObject> methodDefinitions) throws UnableToBuildFeatureException
+ {
+ throw new IllegalStateException("When a schema arrives it's not possible for this class to be in this state.");
+ }
+ };
+
+ /**
+ * MBean used for representing remote broker object instances.
+ * This is the core component of the QMan domain model
+ */
+ class QManManagedObject extends QManManagedEntity implements MBeanRegistration
+ {
+ private Binary _objectId;
+
+ // Arrays used for storing raw data before this mbean is registered to mbean server.
+ List<byte[]> _rawInstrumentationData = new ArrayList<byte[]>();
+ List<byte[]> _rawConfigurationData = new ArrayList<byte[]>();
+
+ /**
+ * Builds a new managed object with the given object identifier.
+ *
+ * @param objectId the object identifier.
+ */
+ QManManagedObject(Binary objectId)
+ {
+ this._objectId = objectId;
+ }
+
+ /**
+ * Returns the value of the given attribute.s
+ *
+ * @throws AttributeNotFoundException when no attribute is found with the given name.
+ */
+ public Object getAttribute (String attributeName) throws AttributeNotFoundException, MBeanException, ReflectionException
+ {
+ if (attributeName == null)
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("attribute name must not be null"));
+ }
+
+ if (_properties.containsKey(attributeName) || _statistics.containsKey(attributeName))
+ {
+ return _attributes.get(attributeName);
+ } else
+ {
+ throw new AttributeNotFoundException(attributeName);
+ }
+ }
+
+ /**
+ * Executes an operation on this object instance.
+ *
+ * @param actionName the name of the method.
+ * @param params the method parameters
+ * @param signature the method signature.
+ */
+ public Object invoke (String actionName, Object[] params, String[] signature) throws MBeanException,ReflectionException
+ {
+ OperationHasBeenInvokedNotification notification = null;
+ try
+ {
+ QpidMethod method = _methods.get(actionName);
+ if (method != null)
+ {
+ try
+ {
+ method.validate(params);
+ InvocationResult result = invokeMethod(_objectId, method, params);
+ notification = new OperationHasBeenInvokedNotification(actionName,params,signature,result);
+ return result;
+ } catch (Exception ex)
+ {
+ MBeanException exception = new MBeanException(ex);
+ notification = new OperationHasBeenInvokedNotification(actionName,params,signature,exception);
+ throw exception;
+ }
+ } else
+ {
+ ReflectionException exception = new ReflectionException(new NoSuchMethodException(actionName));
+ notification = new OperationHasBeenInvokedNotification(actionName,params,signature,exception);
+ throw exception;
+ }
+ } finally
+ {
+ sendNotification(notification);
+ }
+ }
+
+ /**
+ * Sets the value of the given attribute on this object instance.
+ *
+ * @param attribute contains the new value of the attribute.
+ * @throws AttributeNotFoundException when the given attribute is not found on this object instance.
+ * @throws InvalidAttributeValueException when the given value is violating one attribute invariant.
+ */
+ public void setAttribute (Attribute attribute) throws AttributeNotFoundException,
+ InvalidAttributeValueException, MBeanException, ReflectionException
+ {
+ QpidProperty property = _properties.get(attribute.getName());
+ try
+ {
+ property.validate(attribute.getValue());
+ } catch(ValidationException exception)
+ {
+ throw new InvalidAttributeValueException(exception.getMessage());
+ }
+ throw new RuntimeException("Not yet implemented.");
+ }
+
+ /**
+ * Sets the values of several attributes of this MBean.
+ *
+ * @param attributes a list of attributes: The identification of the attributes to be set and the values they are to be set to.
+ * @return The list of attributes that were set, with their new values.
+ */
+ public AttributeList setAttributes (AttributeList attributes)
+ {
+ throw new RuntimeException("Not yet implemented.");
+ }
+
+ /**
+ * MBean server callback after deregistration.
+ */
+ public void postDeregister ()
+ {
+ }
+
+ /**
+ * After the object is registered the raw data is set to null.
+ * This is done because we no longer need this data : it has already been
+ * injected into this object instance.
+ *
+ * @param registrationDone a flag indicating if the instance has been registered to mbean server.
+ */
+ public void postRegister (Boolean registrationDone)
+ {
+ if (registrationDone)
+ {
+ _rawConfigurationData = null;
+ _rawInstrumentationData = null;
+ }
+ }
+
+ /**
+ * MBean server callback before deregistration.
+ */
+ public void preDeregister () throws Exception
+ {
+ }
+
+ /**
+ * MBean server callback before registration.
+ */
+ public ObjectName preRegister (MBeanServer server, ObjectName name) throws Exception
+ {
+ return name;
+ }
+ }
+
+ Map<String, QpidProperty> _properties = new HashMap<String, QpidProperty>();
+ Map<String, QpidStatistic> _statistics = new HashMap<String, QpidStatistic>();
+ private Map<String, QpidMethod> _methods = new HashMap<String, QpidMethod>();
+
+ private List<QpidProperty> _schemaOrderedProperties = new ArrayList<QpidProperty>();
+ private List<QpidStatistic> _schemaOrderedStatistics= new ArrayList<QpidStatistic>();
+
+ private int _howManyPresenceBitMasks;
+ private BlockingQueue<InvocationResult> _exchangeChannelForMethodInvocations;
+ private final IMethodInvocationListener _methodInvocationListener;
+
+ Map<Binary, QManManagedObject> _objectInstances = new HashMap<Binary, QManManagedObject>();
+ State _state = _schemaNotRequested;;
+
+ private final static class Log
+ {
+ private final static Logger LOGGER = Logger.get(QpidClass.class);
+ final static void logMethodInvocationResult(InvocationResult result)
+ {
+ if (LOGGER.isDebugEnabled())
+ {
+ LOGGER.debug(String.valueOf(result));
+ }
+ }
+ }
+
+ /**
+ * Builds a new class with the given name and package as parent.
+ *
+ * @param className the name of the class.
+ * @param hash the class schema hash.
+ * @param parentPackage the parent of this class.
+ */
+ QpidClass(String className, Binary hash, QpidPackage parentPackage)
+ {
+ super(className,hash, parentPackage,Names.CLASS);
+ this._methodInvocationListener = _parent.getMethodInvocationListener();
+ this._exchangeChannelForMethodInvocations = new SynchronousQueue<InvocationResult>();
+ }
+
+ /**
+ * Adds the configuration data for the object instance associated to the given object identifier.
+ *
+ * @param objectId the object identifier.
+ * @param rawData the raw configuration data.
+ */
+ void addInstrumentationData (Binary objectId, byte[] rawData)
+ {
+ _logger.debug(
+ Messages.QMAN_200014_INCOMING_INSTRUMENTATION_DATA,
+ _parent.getOwnerId(),
+ _parent.getName(),
+ _name,
+ objectId);
+ _state.addInstrumentationData(objectId, rawData);
+ }
+
+ /**
+ * Adds the instrumentation data for the object instance associated to the given object identifier.
+ *
+ * @param objectId the object identifier.
+ * @param rawData the raw instrumentation data.
+ */
+ void addConfigurationData (Binary objectId, byte[] rawData)
+ {
+ _logger.debug(
+ Messages.QMAN_200015_INCOMING_CONFIGURATION_DATA,
+ _parent.getOwnerId(),
+ _parent.getName(),
+ _name,
+ objectId);
+ _state.addConfigurationData(objectId, rawData);
+ }
+
+ /**
+ * Sets the schema for this class definition.
+ * A schema is basically a metadata description of all properties, statistics, methods and events of this class.
+ *
+ * @param propertyDefinitions properties metadata.
+ * @param statisticDefinitions statistics metadata.
+ * @param methodDefinitions methods metadata.
+ * @throws UnableToBuildFeatureException when some error occurs while parsing the incoming schema.
+ */
+ void setSchema (
+ List<Map<String, Object>> propertyDefinitions,
+ List<Map<String, Object>> statisticDefinitions,
+ List<MethodOrEventDataTransferObject> methodDefinitions) throws UnableToBuildFeatureException
+ {
+ _logger.info(Messages.QMAN_000010_INCOMING_SCHEMA,_parent.getOwnerId(),_parent.getName(),_name);
+ _state.setSchema(propertyDefinitions, statisticDefinitions, methodDefinitions);
+ }
+
+ /**
+ * Internal method used for building attributes definitions.
+ *
+ * @param props the map contained in the properties schema.
+ * @param stats the map contained in the statistics schema.
+ * @param attributes the management metadata for attributes.
+ * @throws UnableToBuildFeatureException when it's not possibile to build one attribute definition.
+ */
+ void buildAttributes (
+ List<Map<String, Object>> props,
+ List<Map<String, Object>> stats,
+ MBeanAttributeInfo[] attributes) throws UnableToBuildFeatureException
+ {
+ int index = 0;
+ int howManyOptionalProperties = 0;
+
+ for (Map<String, Object> propertyDefinition : props)
+ {
+ QpidFeatureBuilder builder = QpidFeatureBuilder.createPropertyBuilder(propertyDefinition);
+ builder.build();
+
+ QpidProperty property = (QpidProperty) builder.getQpidFeature();
+
+ howManyOptionalProperties += (property.isOptional()) ? 1 : 0;
+
+ _properties.put(property.getName(),property);
+ _schemaOrderedProperties.add(property);
+ attributes[index++]=(MBeanAttributeInfo) builder.getManagementFeature();
+
+ _logger.debug(
+ Messages.QMAN_200016_PROPERTY_DEFINITION_HAS_BEEN_BUILT,
+ _parent.getName(),
+ _name,
+ property);
+ }
+
+ _howManyPresenceBitMasks = (int)Math.ceil((double)howManyOptionalProperties / 8);
+
+ _logger.debug(
+ Messages.QMAN_200018_OPTIONAL_PROPERTIES_INFO,
+ _parent.getOwnerId(),
+ _parent.getName(),
+ _name,
+ _howManyPresenceBitMasks);
+
+ for (Map<String, Object> statisticDefinition : stats)
+ {
+ QpidFeatureBuilder builder = QpidFeatureBuilder.createStatisticBuilder(statisticDefinition);
+ builder.build();
+ QpidStatistic statistic = (QpidStatistic) builder.getQpidFeature();
+
+ _statistics.put(statistic.getName(),statistic);
+ _schemaOrderedStatistics.add(statistic);
+ attributes[index++]=(MBeanAttributeInfo) builder.getManagementFeature();
+
+ _logger.debug(
+ Messages.QMAN_200017_STATISTIC_DEFINITION_HAS_BEEN_BUILT,
+ _parent.getName(),
+ _name,
+ statistic);
+ }
+ }
+
+ /**
+ * Returns the object instance associated to the given identifier.
+ * Note that if the identifier is not associated to any obejct instance, a new one will be created.
+ *
+ * @param objectId the object identifier.
+ * @param registration a flag indicating whenever the (new ) instance must be registered with MBean server.
+ * @return the object instance associated to the given identifier.
+ */
+ QManManagedObject getObjectInstance(Binary objectId, boolean registration)
+ {
+ QManManagedObject objectInstance = _objectInstances.get(objectId);
+ if (objectInstance == null)
+ {
+ objectInstance = new QManManagedObject(objectId);
+ _objectInstances.put(objectId, objectInstance);
+ if (registration)
+ {
+ registerMBean(objectInstance,_parent.getOwnerId(),_parent.getName(),_name,objectId);
+ }
+ }
+ return objectInstance;
+ }
+
+ /**
+ * Internal method used for building method defintiions.
+ *
+ * @param definitions the properties map contained in the incoming schema.
+ * @param operationsMetadata
+ * @throws UnableToBuildFeatureException when it's not possibile to build one or more definitions.
+ */
+ void buildMethods (List<MethodOrEventDataTransferObject> definitions, MBeanOperationInfo[] operationsMetadata) throws UnableToBuildFeatureException
+ {
+ int index = 0;
+ for (MethodOrEventDataTransferObject definition: definitions)
+ {
+ QpidFeatureBuilder builder = QpidFeatureBuilder.createMethodBuilder(definition);
+ builder.build();
+ operationsMetadata [index++]= (MBeanOperationInfo) builder.getManagementFeature();
+ QpidMethod method = (QpidMethod) builder.getQpidFeature();
+ _methods.put(method.getName(),method);
+ }
+ }
+
+ /**
+ * Header (opcode='M')
+ * ObjectId of target object (128 bits)
+ * Package name (str8)
+ * Class name (str8)
+ * Class hash (bin128)
+ * Method name (str8) [as defined in the schema]
+ * Now encode all input ("I") and i/o (IO) arguments in the order in which they are defined in the schema.
+ * (i.e. make one pass over the argument list and encode arguments that are either input or inptu/output).
+
+ * @param objectId
+ * @param method
+ * @param parameters
+ * @throws Exception
+ */
+ private InvocationResult invokeMethod(Binary objectId,QpidMethod method,Object [] parameters) throws Exception
+ {
+ try
+ {
+ _service.connect();
+
+ int sequenceNumber = SequenceNumberGenerator.getNextSequenceNumber();
+ _methodInvocationListener.operationIsGoingToBeInvoked(new InvocationEvent(this,sequenceNumber,_exchangeChannelForMethodInvocations));
+ _service.invoke(_parent.getName(), _name, _hash,objectId,parameters, method,sequenceNumber,objectId.getBankId(),objectId.getBrokerId());
+
+ InvocationResult result = _exchangeChannelForMethodInvocations.poll(5000,TimeUnit.MILLISECONDS);
+
+ if (result == null)
+ {
+ throw new TimeoutException();
+ }
+
+ Map<String, Object> output = method.decodeParameters(result.getOutputAndBidirectionalArgumentValues());
+ result.setOutputSection(output);
+
+ Log.logMethodInvocationResult(result);
+
+ if (result.isException())
+ {
+ result.createAndThrowException();
+ }
+ return result;
+ } finally
+ {
+ _service.close();
+ }
+ }
+
+ /**
+ * Updates the given obejct instance with the given incoming configuration data.
+ *
+ * @param instance the managed object instance.
+ * @param rawData the incoming configuration data which contains new values for instance properties.
+ */
+ void updateInstanceWithConfigurationData(QManManagedObject instance,byte [] rawData)
+ {
+ BBDecoder decoder = new BBDecoder();
+ decoder.init(ByteBuffer.wrap(rawData));
+
+ byte [] presenceBitMasks = decoder.readBytes(_howManyPresenceBitMasks);
+ for (QpidProperty property : _schemaOrderedProperties)
+ {
+ try {
+ Object value = property.decodeValue(decoder,presenceBitMasks);
+ instance.createOrReplaceAttributeValue(property.getName(),value);
+ } catch(Exception ignore) {
+ _logger.error(Messages.QMAN_100016_UNABLE_TO_DECODE_FEATURE_VALUE, _parent.getName(),_name,property.getName());
+ }
+ }
+ }
+
+ /**
+ * Updates the given object instance with the given incoming instrumentation data.
+ *
+ * @param instance the managed object instance.
+ * @param rawData the incoming instrumentation data which contains new values for instance properties.
+ */
+ void updateInstanceWithInstrumentationData(QManManagedObject instance,byte [] rawData)
+ {
+ BBDecoder decoder = new BBDecoder();
+ decoder.init(ByteBuffer.wrap(rawData));
+
+ for (QpidStatistic statistic : _schemaOrderedStatistics)
+ {
+ try {
+ Object value = statistic.decodeValue(decoder);
+ instance.createOrReplaceAttributeValue(statistic.getName(),value);
+ } catch(Exception ignore) {
+ _logger.error(Messages.QMAN_100016_UNABLE_TO_DECODE_FEATURE_VALUE, _parent.getName(),_name,statistic.getName());
+ }
+ }
+ }
+
+ @Override
+ public String toString ()
+ {
+ return new StringBuilder()
+ .append(_parent.getOwnerId())
+ .append("::")
+ .append(_parent.getName())
+ .append('.')
+ .append(_name)
+ .toString();
+ }
+
+ /**
+ * Removes the object instance associated to the given identifier.
+ *
+ * @param objectId the object identifier.
+ */
+ void removeObjectInstance (Binary objectId)
+ {
+ QManManagedObject toBeRemoved = _objectInstances.remove(objectId);
+ if (toBeRemoved != null)
+ {
+ ObjectName objectName = JMX_SERVICE.unregisterObjectInstance(_parent.getOwnerId(),_parent.getName(),_name,toBeRemoved._objectId);
+
+ EntityLifecycleNotification notification = new EntityLifecycleNotification(
+ EntityLifecycleNotification.INSTANCE_REMOVED_NOTIFICATION_TYPE,
+ _parent.getName(),
+ _name,
+ Names.CLASS,
+ objectName);
+
+ sendNotification(notification);
+ }
+ }
+
+ /**
+ * Deregisters all the object instances and release all previously acquired resources.
+ */
+ void releaseResources ()
+ {
+ _objectInstances.clear();
+ JMX_SERVICE.unregisterObjectInstances();
+ JMX_SERVICE.unregisterClassDefinitions();
+ _service.close();
+ }
+
+ /**
+ * Compose method used for registering mbean instance.
+ *
+ * @param instance the mbean instance.
+ * @param brokerId the broker identifier.
+ * @param packageName the package name.
+ * @param className the class name.
+ * @param objectId the object identifier.
+ */
+ private void registerMBean(
+ QManManagedObject instance,
+ UUID brokerId,
+ String packageName,
+ String className,
+ Binary objectId)
+ {
+ ObjectName objectName = JMX_SERVICE.registerObjectInstance(instance,_parent.getOwnerId(),_parent.getName(),_name,objectId);
+
+ EntityLifecycleNotification notification = new EntityLifecycleNotification(
+ EntityLifecycleNotification.INSTANCE_ADDED_NOTIFICATION_TYPE,
+ packageName,
+ className,
+ Names.CLASS,
+ objectName);
+
+ sendNotification(notification);
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidClassMBean.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidClassMBean.java
new file mode 100644
index 0000000000..eeb4e0e2d8
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidClassMBean.java
@@ -0,0 +1,41 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+/**
+ * Management interface for Qpid entity class..
+ */
+public interface QpidClassMBean
+{
+ /**
+ * Retruns the name of the class.
+ *
+ * @return the name of the class.
+ */
+ String getName();
+
+ /**
+ * Returns the name of the package.
+ *
+ * @return the name of the package.
+ */
+ String getPackageName();
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidEntity.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidEntity.java
new file mode 100644
index 0000000000..a13da559fc
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidEntity.java
@@ -0,0 +1,163 @@
+package org.apache.qpid.management.domain.model;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.DynamicMBean;
+import javax.management.MBeanInfo;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.ObjectName;
+import javax.management.RuntimeOperationsException;
+
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.domain.model.type.Binary;
+import org.apache.qpid.management.domain.services.QpidService;
+import org.apache.qpid.management.jmx.EntityLifecycleNotification;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * Layer supertype for QMan entities.
+ */
+public abstract class QpidEntity extends NotificationBroadcasterSupport
+{
+ /**
+ * Layer supertype for QMan managed bean entities.
+ */
+ abstract class QManManagedEntity implements DynamicMBean
+ {
+ // After mbean is registered with the MBean server this collection holds the mbean attribute values.
+ Map<String,Object> _attributes = new HashMap<String, Object>();
+
+ /**
+ * Creates or replace the given attribute.
+ * Note that this is not part of the management interface of this object instance and therefore will be accessible only
+ * from within this class.
+ * It is used to update directly the object attributes bypassing jmx interface.
+ *
+ * @param attributeName the name of the attribute.
+ * @param property newValue the new value of the attribute.
+ */
+ void createOrReplaceAttributeValue(String attributeName, Object newValue)
+ {
+ _attributes.put(attributeName, newValue);
+ }
+
+ /**
+ * Get the values of several attributes of the Dynamic MBean.
+ *
+ * @param attributes A list of the attributes to be retrieved.
+ *
+ * @return The list of attributes retrieved.
+ */
+ public AttributeList getAttributes (String[] attributes)
+ {
+ if (attributes == null)
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("Attributes array must not be null"));
+ }
+
+ AttributeList result = new AttributeList(attributes.length);
+ for (int i = 0; i < attributes.length; i++)
+ {
+ String attributeName = attributes[i];
+ try
+ {
+ result.add(new Attribute(attributeName,getAttribute(attributeName)));
+ } catch(Exception exception)
+ {
+ // Already logged.
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns metadata for this object instance.
+ */
+ // Developer Note : note that this metadata is a member of the outer class definition : in that way we create
+ // that metadata only once and then it will be shared between all object instances (it's a readonly object)
+ public MBeanInfo getMBeanInfo ()
+ {
+ return _metadata;
+ }
+ };
+
+ final Logger _logger = Logger.get(getClass());
+ final static JmxService JMX_SERVICE = new JmxService();
+
+ final String _name;
+ final Binary _hash;
+
+ final QpidPackage _parent;
+ MBeanInfo _metadata;
+ final QpidService _service;
+
+ protected ObjectName _objectName;
+
+ private final String _type;
+
+ /**
+ * Builds a new class with the given name and package as parent.
+ *
+ * @param className the name of the class.
+ * @param hash the class schema hash.
+ * @param parentPackage the parent of this class.
+ */
+ QpidEntity(String className, Binary hash, QpidPackage parentPackage,String type)
+ {
+ this._name = className;
+ this._parent = parentPackage;
+ this._hash = hash;
+ this._type = type;
+ this._service = new QpidService(_parent.getOwnerId());
+
+ _logger.debug(
+ Messages.QMAN_200020_ENTITY_DEFINITION_HAS_BEEN_BUILT,
+ _parent.getOwnerId(),
+ _parent.getName(),
+ _name);
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public String getPackageName()
+ {
+ return _parent.getName();
+ }
+
+ /**
+ * Internal method used to send a schema request for this entity.
+ *
+ * @throws Exception when the request cannot be sent.
+ */
+ void requestSchema() throws Exception
+ {
+
+ _objectName = JMX_SERVICE.createEntityDefinitionName(_parent.getName(), _name,_type);
+ JMX_SERVICE.registerEntityDefinition(_objectName,this,_parent.getName(),_name);
+
+ try
+ {
+ _service.connect();
+ _service.requestSchema(_parent.getName(), _name, _hash);
+ _service.sync();
+ } finally
+ {
+ _service.close();
+ }
+
+ EntityLifecycleNotification notification = new EntityLifecycleNotification(
+ EntityLifecycleNotification.SCHEMA_REQUESTED_NOTIFICATION_TYPE,
+ _parent.getName(),
+ _name,
+ Names.CLASS,
+ _objectName);
+ sendNotification(notification);
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidEvent.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidEvent.java
new file mode 100644
index 0000000000..31d8d01fc9
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidEvent.java
@@ -0,0 +1,493 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.RuntimeOperationsException;
+
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.domain.model.type.Binary;
+import org.apache.qpid.management.jmx.EntityLifecycleNotification;
+import org.apache.qpid.transport.codec.BBDecoder;
+
+/**
+ * Qpid event definition.
+ */
+class QpidEvent extends QpidEntity implements QpidEventMBean
+{
+
+ /**
+ * State interface for this event definition.
+ * Each state is responsible to handle the injection of the data and / or schema.
+ */
+ interface State
+ {
+ /**
+ * Adds the given data for the object instance associated to the given object identifier.
+ *
+ * @param rawData the raw configuration data.
+ */
+ void addNewEventData (byte[] rawData, long currentTimestamp, int severity);
+
+ /**
+ * Inject the schema into this class definition.
+ *
+ * @param propertyDefinitions
+ * @param statisticDefinitions
+ * @param methodDefinitions
+ * @throws UnableToBuildFeatureException when it's not possibile to parse schema and build the class definition.
+ */
+ public void setSchema (List<Map<String, Object>> agumentDefinitions) throws UnableToBuildFeatureException;
+ };
+
+
+ /**
+ * This is the initial state of every qpid class.
+ * The class definition instance is created but its schema has not been injected.
+ * Incoming configuration & instrumentation data will be stored in raw format because we don't know how to
+ * parse it until the schema arrives.
+ * In addition, this state is responsible (when data arrives) to request its schema.
+ */
+ final State _schemaNotRequested = new State() {
+
+ /**
+ * Stores the incoming data in raw format and request the schema for this class.
+ * After that a transition to the next state is made.
+ *
+ * @param objectId the object instance identifier.
+ * @param rawData incoming configuration data.
+ */
+ public synchronized void addNewEventData (byte[] rawData, long currentTimestamp, int severity)
+ {
+ try
+ {
+ requestSchema();
+ _state = _schemaRequestedButNotYetInjected;
+ } catch (Exception exception)
+ {
+ _logger.error(
+ exception,
+ Messages.QMAN_100015_UNABLE_TO_SEND_SCHEMA_REQUEST,
+ _parent.getName(),
+ _name);
+ } finally {
+ createEventInstance(rawData,currentTimestamp,severity);
+ }
+ }
+
+ /**
+ * This method only throws an illegal state exception because when a schema arrives
+ * this state is no longer valid.
+ */
+ public void setSchema (List<Map<String, Object>> agumentDefinitions) throws UnableToBuildFeatureException
+ {
+ throw new IllegalStateException("When a schema arrives it's not possible for this event to be in this state.");
+ }
+ };
+
+ /**
+ * This is the first state of this class definition : the schema is not yet injected so each injection of object data will be
+ * retained in raw format.
+ */
+ final State _schemaRequestedButNotYetInjected = new State()
+ {
+ /**
+ * Stores the incoming data in raw format and request the schema for this class.
+ * After that a transition to the next state is made.
+ *
+ * @param objectId the object instance identifier.
+ * @param rawData incoming configuration data.
+ */
+ public synchronized void addNewEventData (byte[] rawData,long currentTimestamp, int severity)
+ {
+ createEventInstance(rawData,currentTimestamp, severity);
+ }
+
+ /**
+ * When a schema is injected into this defintiion the following should happen :
+ * 1) the incoming schema is parsed and the class definition is built;
+ * 2) the retained raw data is converted into object instance(s)
+ * 3) the internal state of this class changes;
+ *
+ * If someting is wrong during that process the schema is not built and the state don't change.
+ */
+ public synchronized void setSchema (List<Map<String, Object>> argumentDefinitions) throws UnableToBuildFeatureException
+ {
+ MBeanAttributeInfo [] attributesMetadata = new MBeanAttributeInfo[argumentDefinitions.size()+2];
+
+ buildArguments(argumentDefinitions, attributesMetadata);
+
+ _metadata = new MBeanInfo(_name,_name,attributesMetadata,null,null,null);
+
+ // Converting stored object instances into JMX MBean and removing raw instance data.
+ for (QManManagedEvent instance : _eventInstances)
+ {
+ updateEventInstanceWithData(instance);
+ registerEventInstance(instance,_parent.getOwnerId(),_parent.getName(),_name);
+ }
+ _state = _schemaInjected;
+
+ EntityLifecycleNotification notification = new EntityLifecycleNotification(
+ EntityLifecycleNotification.SCHEMA_INJECTED_NOTIFICATION_TYPE,
+ _parent.getName(),
+ _name,
+ Names.EVENT,
+ _objectName);
+
+ sendNotification(notification);
+ }
+ };
+
+ /**
+ * After a schema is built into this definition this is the current state of the class.
+ */
+ final State _schemaInjected = new State()
+ {
+ /**
+ * Updates the configuration state of the object instance associates with the given object identifier.
+ *
+ * @param objectId the object identifier.
+ * @param rawData the configuration data (raw format).
+ */
+ public void addNewEventData (byte[] rawData,long currentTimestamp, int severity)
+ {
+ QManManagedEvent instance = createEventInstance(rawData,currentTimestamp, severity);
+ updateEventInstanceWithData(instance);
+ registerEventInstance(instance,_parent.getOwnerId(),_parent.getName(),_name);
+ }
+
+ /**
+ * Never called when the class definition has this state.
+ */
+ public void setSchema (List<Map<String, Object>> agumentDefinitions) throws UnableToBuildFeatureException
+ {
+ // N.A. : Schema is already injected.
+ }
+ };
+
+ /**
+ * MBean used for representing remote broker object instances.
+ * This is the core component of the QMan domain model
+ *
+ * @author Andrea Gazzarini
+ */
+ class QManManagedEvent extends QManManagedEntity
+ {
+
+
+ // Arrays used for storing raw data before this mbean is registered to mbean server.
+ final byte[] _rawEventData;
+ final long _timestamp;
+ final int _severity;
+
+ /**
+ * Builds a new managed object with the given object identifier.
+ *
+ * @param objectId the object identifier.
+ */
+ private QManManagedEvent(byte [] data, long timestamp, int severity)
+ {
+ this._rawEventData = data;
+ this._timestamp = timestamp;
+ this._severity = severity;
+ _attributes.put(SEVERITY_ATTR_NAME, _severity);
+ _attributes.put(TIMESTAMP_ATTR_NAME, new Date(_timestamp));
+ }
+
+ /**
+ * Returns the value of the given attribute.s
+ *
+ * @throws AttributeNotFoundException when no attribute is found with the given name.
+ */
+ public Object getAttribute (String attributeName) throws AttributeNotFoundException, MBeanException, ReflectionException
+ {
+ if (attributeName == null)
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("Attribute name must not be null."));
+ }
+
+ if (_arguments.containsKey(attributeName) || SEVERITY_ATTR_NAME.equals(attributeName) || TIMESTAMP_ATTR_NAME.equals(attributeName))
+ {
+ return _attributes.get(attributeName);
+ } else
+ {
+ throw new AttributeNotFoundException(attributeName);
+ }
+ }
+
+ /**
+ * Executes an operation on this object instance.
+ *
+ * @param actionName the name of the method.
+ * @param params the method parameters
+ * @param signature the method signature.
+ */
+ public Object invoke (String actionName, Object[] params, String[] signature) throws MBeanException,ReflectionException
+ {
+ throw new ReflectionException(new NoSuchMethodException(actionName));
+ }
+
+ /**
+ * Sets the value of the given attribute on this object instance.
+ *
+ * @param attribute contains the new value of the attribute.
+ * @throws AttributeNotFoundException when the given attribute is not found on this object instance.
+ * @throws InvalidAttributeValueException when the given value is violating one attribute invariant.
+ */
+ public void setAttribute (Attribute attribute) throws AttributeNotFoundException,
+ InvalidAttributeValueException, MBeanException, ReflectionException
+ {
+ throw new ReflectionException(new NoSuchMethodException());
+ }
+
+ /**
+ * Sets the values of several attributes of this MBean.
+ *
+ * @param attributes a list of attributes: The identification of the attributes to be set and the values they are to be set to.
+ * @return The list of attributes that were set, with their new values.
+ */
+ public AttributeList setAttributes (AttributeList attributes)
+ {
+ throw new RuntimeException();
+ }
+ }
+
+ final static String SEVERITY_ATTR_NAME = "Severity";
+ final static String TIMESTAMP_ATTR_NAME = "Date";
+
+ private List<QpidProperty> _schemaOrderedArguments = new ArrayList<QpidProperty>();
+
+ Map<String, QpidProperty> _arguments = new HashMap<String, QpidProperty>();
+ List<QManManagedEvent> _eventInstances = new LinkedList<QManManagedEvent>();
+ State _state = _schemaNotRequested;;
+
+ /**
+ * Builds a new class with the given name and package as parent.
+ *
+ * @param className the name of the class.
+ * @param hash the class schema hash.
+ * @param parentPackage the parent of this class.
+ */
+ QpidEvent(String eventClassName, Binary hash, QpidPackage parentPackage)
+ {
+ super(eventClassName,hash,parentPackage,Names.EVENT);
+ }
+
+ /**
+ * Adds the configuration data for the object instance associated to the given object identifier.
+ *
+ * @param objectId the object identifier.
+ * @param rawData the raw configuration data.
+ */
+ void addEventData (byte[] rawData, long currentTimestamp, int severity)
+ {
+ _logger.debug(
+ Messages.QMAN_200021_INCOMING_EVENT_DATA,
+ _parent.getOwnerId(),
+ _parent.getName(),
+ _name);
+ _state.addNewEventData(rawData, currentTimestamp, severity);
+ }
+
+ /**
+ * Sets the schema for this class definition.
+ * A schema is basically a metadata description of all properties, statistics, methods and events of this class.
+ *
+ * @param propertyDefinitions properties metadata.
+ * @param statisticDefinitions statistics metadata.
+ * @param methodDefinitions methods metadata.
+ * @throws UnableToBuildFeatureException when some error occurs while parsing the incoming schema.
+ */
+ void setSchema (List<Map<String, Object>> argumentDefinitions) throws UnableToBuildFeatureException
+ {
+ _logger.info(Messages.QMAN_000010_INCOMING_SCHEMA,_parent.getOwnerId(),_parent.getName(),_name);
+ _state.setSchema(argumentDefinitions);
+ }
+
+ /**
+ * Internal method used for building attributes definitions.
+ *
+ * @param props the map contained in the properties schema.
+ * @param stats the map contained in the statistics schema.
+ * @param attributes the management metadata for attributes.
+ * @throws UnableToBuildFeatureException when it's not possibile to build one attribute definition.
+ */
+ void buildArguments (
+ List<Map<String, Object>> arguments,MBeanAttributeInfo[] attributes) throws UnableToBuildFeatureException
+ {
+ int index = 0;
+
+ for (Map<String, Object> argumentDefinition : arguments)
+ {
+ // Force metadata attributes. It is needed because arguments are "similar" to properties but they
+ // aren't properties and then they haven't optional, index and access metadata attributes
+ // (mandatory for build a property definition).
+ argumentDefinition.put(QpidFeatureBuilder.Attribute.optional.name(),0);
+ argumentDefinition.put(QpidFeatureBuilder.Attribute.index.name(),1);
+ argumentDefinition.put(QpidFeatureBuilder.Attribute.access.name(),3);
+
+ QpidFeatureBuilder builder = QpidFeatureBuilder.createPropertyBuilder(argumentDefinition);
+ builder.build();
+
+ QpidProperty argument = (QpidProperty) builder.getQpidFeature();
+
+ _arguments.put(argument.getName(),argument);
+ _schemaOrderedArguments.add(argument);
+ attributes[index++]=(MBeanAttributeInfo) builder.getManagementFeature();
+
+ _logger.debug(
+ Messages.QMAN_200019_EVENT_ARGUMENT_DEFINITION_HAS_BEEN_BUILT,
+ _parent.getName(),
+ _name,
+ argument);
+ }
+
+ attributes[index++] = new MBeanAttributeInfo(
+ SEVERITY_ATTR_NAME,
+ Integer.class.getName(),
+ Messages.EVENT_SEVERITY_ATTRIBUTE_DESCRIPTION,
+ true,
+ false,
+ false);
+
+ attributes[index++] = new MBeanAttributeInfo(
+ TIMESTAMP_ATTR_NAME,
+ Date.class.getName(),
+ Messages.EVENT_TIMESTAMP_ATTRIBUTE_DESCRIPTION,
+ true,
+ false,
+ false);
+ }
+
+ /**
+ * Returns the object instance associated to the given identifier.
+ * Note that if the identifier is not associated to any obejct instance, a new one will be created.
+ *
+ * @param objectId the object identifier.
+ * @param registration a flag indicating whenever the (new ) instance must be registered with MBean server.
+ * @return the object instance associated to the given identifier.
+ */
+ QManManagedEvent createEventInstance(byte [] data, long timestamp, int severity)
+ {
+ QManManagedEvent eventInstance = new QManManagedEvent(data, timestamp, severity);
+ _eventInstances.add(eventInstance);
+ return eventInstance;
+ }
+
+ /**
+ * Updates the given obejct instance with the given incoming configuration data.
+ *
+ * @param instance the managed object instance.
+ * @param rawData the incoming configuration data which contains new values for instance properties.
+ */
+ void updateEventInstanceWithData(QManManagedEvent instance)
+ {
+ BBDecoder decoder = new BBDecoder();
+ decoder.init(ByteBuffer.wrap(instance._rawEventData));
+
+ for (QpidProperty property : _schemaOrderedArguments)
+ {
+ try {
+ Object value = property.decodeValue(decoder);
+ instance.createOrReplaceAttributeValue(property.getName(),value);
+ } catch(Exception ignore) {
+ _logger.error(Messages.QMAN_100016_UNABLE_TO_DECODE_FEATURE_VALUE, _parent.getName(),_name,property.getName());
+ }
+ }
+ }
+
+ @Override
+ public String toString ()
+ {
+ return new StringBuilder()
+ .append(_parent.getOwnerId())
+ .append("::")
+ .append(_parent.getName())
+ .append(".")
+ .append(_name)
+ .toString();
+ }
+
+ /**
+ * Deregisters all the object instances and release all previously acquired resources.
+ */
+ void releaseResources ()
+ {
+ _eventInstances.clear();
+ JMX_SERVICE.unregisterEvents();
+ JMX_SERVICE.unregisterClassDefinitions();
+ _service.close();
+ }
+
+ /**
+ * Checks if this event definition contains event instance(s).
+ *
+ * @return true if there is one or more managed instances.
+ */
+ boolean hasNoInstances()
+ {
+ return _eventInstances.isEmpty();
+ }
+
+ /**
+ * Compose method used for registering an mbean (event) instance.
+ *
+ * @param instance the mbean event.
+ * @param brokerId the broker identifier.
+ * @param packageName the package name.
+ * @param eventClassName the event class name.
+ */
+ private void registerEventInstance(
+ QManManagedEvent instance,
+ UUID brokerId,
+ String packageName,
+ String eventClassName)
+ {
+ ObjectName objectName = JMX_SERVICE.registerEventInstance(instance,brokerId,packageName,eventClassName);
+
+ EntityLifecycleNotification notification = new EntityLifecycleNotification(
+ EntityLifecycleNotification.INSTANCE_ADDED_NOTIFICATION_TYPE,
+ packageName,
+ eventClassName,
+ Names.EVENT,
+ objectName);
+
+ sendNotification(notification);
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidEventMBean.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidEventMBean.java
new file mode 100644
index 0000000000..35ba62e02c
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidEventMBean.java
@@ -0,0 +1,41 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+/**
+ * Management interface for Qpid entity class..
+ */
+public interface QpidEventMBean
+{
+ /**
+ * Retruns the name of the event.
+ *
+ * @return the name of the event.
+ */
+ String getName();
+
+ /**
+ * Returns the name of the package.
+ *
+ * @return the name of the package.
+ */
+ String getPackageName();
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidFeature.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidFeature.java
new file mode 100644
index 0000000000..3262448bd4
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidFeature.java
@@ -0,0 +1,86 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+/**
+ * Layer Supertype for all qpid management features.
+ */
+abstract class QpidFeature
+{
+ /** The name of the feature. */
+ protected String _name;
+
+ /**
+ * The description of the feature.
+ */
+ protected String _description;
+
+ /**
+ * Returns the description of this feature.
+ *
+ * @return the description of this feature.
+ */
+ String getDescription ()
+ {
+ return _description;
+ }
+
+ /**
+ * Sets the description for this feature.
+ *
+ * @param description the description for this feature.
+ */
+ void setDescription (String description)
+ {
+ this._description = description;
+ }
+
+ /**
+ * Returns the name of the feature.
+ *
+ * @return the name of the feature.
+ */
+ public String getName ()
+ {
+ return _name;
+ }
+
+ /**
+ * Sets the name for this feature.
+ *
+ * @param name the name of this feature.
+ */
+ void setName (String name)
+ {
+ this._name = name;
+ }
+
+ /**
+ * Returns the name of the feature.
+ *
+ * @return the name of the feature.
+ */
+ @Override
+ public String toString ()
+ {
+ return _name;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidFeatureBuilder.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidFeatureBuilder.java
new file mode 100644
index 0000000000..d0862c15ca
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidFeatureBuilder.java
@@ -0,0 +1,454 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanFeatureInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+
+import org.apache.qpid.management.configuration.Configuration;
+import org.apache.qpid.management.configuration.UnknownTypeCodeException;
+import org.apache.qpid.management.domain.handler.impl.MethodOrEventDataTransferObject;
+import org.apache.qpid.management.Names;
+
+/**
+ * A builder used to parse incoming schema message and therefore to build a feature (property, statistic, method, event)
+ * definition.
+ * In order to set up the correct state for this builder, clients must create an instance of this class
+ * The product of the builder will be a QpidFeature and a JMX Managemtn feature used for describing that feature in a
+ * JMX environment. So, for example, for building a property definition client code should be :
+ *
+ * <br>- QpidFeatureBuilder builder = QpidFeature.createPropertyBuilder(...);
+ * <br>- builder.build();
+ * <br>- QpidProperty property = (QpidProperty) builder.getQpidFeature();
+ * <br>- MBeanAttributeInfo managementAttributeInfo = (MBeanAttributeInfo)builder.getManagementFeature();
+ *
+ * <br>N.B.: a builder instance is not supposed to be reused. One instance for one feature!
+ *
+ * @author Andrea Gazzarini
+ */
+class QpidFeatureBuilder
+{
+
+ static enum Attribute {
+ name,type,access,index,optional,unit,min,max,maxlen,desc,dir,argCount;
+ };
+
+ private List<Attribute> _mandatoryAttributes = new ArrayList<Attribute>();
+
+ /**
+ * Builder state for this class.
+ * Each concrete implementor is a builder for a specific feature.
+ * using the appropriate factory method.
+ *
+ * @author Andrea Gazzarini
+ */
+ interface State {
+ void build() throws UnableToBuildFeatureException;
+ }
+
+ /**
+ * Builder used for building property definition.
+ */
+ final State _propertyBuilder = new State() {
+
+ /**
+ * Builds a property definition as well a management attribute feature.
+ */
+ public void build () throws UnableToBuildFeatureException
+ {
+ QpidProperty property = new QpidProperty();
+ try {
+ int optionalIndex = 0;
+ for (Entry<String, Object> propertyAttribute : _featureDefinition.entrySet())
+ {
+ Attribute attribute = Attribute.valueOf(propertyAttribute.getKey());
+ switch(attribute)
+ {
+ case name :
+ {
+ property.setName(String.valueOf(propertyAttribute.getValue()));
+ break;
+ }
+ case access :
+ {
+ int code = (Integer)propertyAttribute.getValue();
+ property.setAccessMode(Configuration.getInstance().getAccessMode(code));
+ break;
+ }
+ case unit :
+ {
+ property.setUnit(String.valueOf(propertyAttribute.getValue()));
+ break;
+ }
+ case min :
+ {
+ property.setMinValue((Integer)propertyAttribute.getValue());
+ break;
+ }
+ case max :
+ {
+ property.setMaxValue((Integer)propertyAttribute.getValue());
+ break;
+ }
+ case maxlen :
+ {
+ property.setMaxLength((Integer)propertyAttribute.getValue());
+ break;
+ }
+ case desc :
+ {
+ property.setDescription(String.valueOf(propertyAttribute.getValue()));
+ break;
+ }
+ case type :
+ {
+ int code = (Integer) propertyAttribute.getValue();
+ property.setType(Configuration.getInstance().getType(code));
+ break;
+ }
+ case index :
+ {
+ break;
+ }
+ case optional :
+ {
+ int code = (Integer) propertyAttribute.getValue();
+ if (code == 1)
+ {
+ property.markAsOptional(optionalIndex);
+ optionalIndex++;
+ }
+ break;
+ }
+ }
+ _mandatoryAttributes.remove(attribute);
+ }
+ } catch(Exception exception)
+ {
+ throw new UnableToBuildFeatureException(exception,property.getName());
+ }
+
+ if (!_mandatoryAttributes.isEmpty())
+ {
+ throw new MissingFeatureAttributesException(_mandatoryAttributes);
+ }
+
+ _managementFeatureInfo = new MBeanAttributeInfo(
+ property.getName(),
+ property.getJavaType().getName(),
+ property.getDescription(),
+ true,
+ property.getAccessMode()==AccessMode.RW,
+ false);
+ _qpidFeature = property;
+ }
+ };
+
+ final State _statisticBuilder = new State()
+ {
+ public void build () throws UnableToBuildFeatureException
+ {
+ QpidStatistic statistic = new QpidStatistic();
+ try
+ {
+ for (Entry<String, Object> statisticAttribute : _featureDefinition.entrySet())
+ {
+ Attribute attribute = Attribute.valueOf(statisticAttribute.getKey());
+ switch(attribute)
+ {
+ case name :
+ {
+ statistic.setName(String.valueOf(statisticAttribute.getValue()));
+ break;
+ }
+ case unit :
+ {
+ statistic.setUnit(String.valueOf(statisticAttribute.getValue()));
+ break;
+ }
+ case desc :
+ {
+ statistic.setDescription(String.valueOf(statisticAttribute.getValue()));
+ break;
+ }
+ case type :
+ {
+ int code = (Integer) statisticAttribute.getValue();
+ statistic.setType(Configuration.getInstance().getType(code));
+ break;
+ }
+ }
+ _mandatoryAttributes.remove(attribute);
+ }
+ } catch(Exception exception)
+ {
+ throw new UnableToBuildFeatureException(exception,statistic.getName());
+ }
+
+ if (!_mandatoryAttributes.isEmpty())
+ {
+ throw new MissingFeatureAttributesException(_mandatoryAttributes);
+ }
+
+ _managementFeatureInfo = new MBeanAttributeInfo(
+ statistic.getName(),
+ statistic.getJavaType().getName(),
+ statistic.getDescription(),
+ true,
+ false,
+ false);
+ _qpidFeature = statistic;
+ }
+ };
+
+ /**
+ * Builder used for building a statistic definition.
+ */
+ final State _argumentBuilder = new State()
+ {
+ /**
+ * Builds a property definition as well a management attribute feature.
+ */
+ public void build () throws UnableToBuildFeatureException
+ {
+ QpidArgument argument = new QpidArgument();
+ for (Entry<String, Object> argumentAttribute : _featureDefinition.entrySet())
+ {
+ String key = argumentAttribute.getKey();
+ if (Names.DEFAULT_PARAM_NAME.equals(key))
+ {
+ argument.setDefaultValue(argumentAttribute.getValue());
+ } else {
+ Attribute attribute = Attribute.valueOf(key);
+ switch (attribute)
+ {
+ case name :
+ {
+ argument.setName((String)argumentAttribute.getValue());
+ break;
+ }
+ case desc :
+ {
+ argument.setDescription((String)argumentAttribute.getValue());
+ break;
+ }
+ case type :
+ {
+ try
+ {
+ argument.setType(Configuration.getInstance().getType((Integer)argumentAttribute.getValue()));
+ break;
+ } catch(UnknownTypeCodeException exception)
+ {
+ throw new UnableToBuildFeatureException(exception,argument.getName());
+ }
+ }
+ case dir :
+ {
+ argument.setDirection((String)argumentAttribute.getValue());
+ break;
+ }
+ case unit :
+ {
+ argument.setUnit((String)argumentAttribute.getValue());
+ break;
+
+ }
+ }
+ }
+ }
+
+ if (!_mandatoryAttributes.isEmpty())
+ {
+ throw new MissingFeatureAttributesException(_mandatoryAttributes);
+ }
+
+ _qpidFeature = argument;
+ _managementFeatureInfo = new MBeanParameterInfo(
+ argument.getName(),
+ argument.getJavaType().getName(),
+ argument.getDescription());
+ }
+ };
+
+ final State _methodBuilder = new State()
+ {
+ public void build () throws UnableToBuildFeatureException
+ {
+ Map<String,Object> definition = _methodOrEventDefinition.getDefinition();
+ String name = (String)definition.get(Attribute.name.name());
+ if (name == null)
+ {
+ throw new MissingFeatureAttributesException(_mandatoryAttributes);
+ }
+
+ QpidMethod method = new QpidMethod((String)definition.get(Attribute.name.name()),(String) definition.get(Attribute.desc.name()));
+
+ List<Map<String,Object>> args = _methodOrEventDefinition.getArgumentsDefinitions();
+
+ List<MBeanParameterInfo> signature = new LinkedList<MBeanParameterInfo>();
+
+ for (Map<String,Object> argumentDefinition : args)
+ {
+ QpidFeatureBuilder builder = QpidFeatureBuilder.createArgumentBuilder(argumentDefinition);
+ builder.build();
+
+ QpidArgument argument = (QpidArgument) builder.getQpidFeature();
+ method.addArgument(argument);
+ if (argument.isInput())
+ {
+ signature.add((MBeanParameterInfo) builder.getManagementFeature());
+ }
+ }
+
+ _qpidFeature = method;
+ _managementFeatureInfo = new MBeanOperationInfo(
+ method.getName(),
+ method.getDescription(),
+ (MBeanParameterInfo[])signature.toArray(new MBeanParameterInfo[signature.size()]),
+ void.class.getName(),
+ MBeanOperationInfo.ACTION);
+ }
+ };
+
+ final State _eventBuilder = new State()
+ {
+ public void build () throws UnableToBuildFeatureException
+ {
+ }
+ };
+
+ private MBeanFeatureInfo _managementFeatureInfo;
+ private QpidFeature _qpidFeature;
+ private final Map <String, Object> _featureDefinition;
+ private final MethodOrEventDataTransferObject _methodOrEventDefinition;
+ private State _state;
+
+ static QpidFeatureBuilder createPropertyBuilder(Map<String, Object> propertyDefinition)
+ {
+ QpidFeatureBuilder result = new QpidFeatureBuilder(propertyDefinition);
+ result._state = result._propertyBuilder;
+ result._mandatoryAttributes.add(Attribute.name);
+ result._mandatoryAttributes.add(Attribute.access);
+ result._mandatoryAttributes.add(Attribute.type);
+ result._mandatoryAttributes.add(Attribute.optional);
+ result._mandatoryAttributes.add(Attribute.index);
+ return result;
+ }
+
+ static QpidFeatureBuilder createStatisticBuilder(Map<String, Object> statisticDefinition)
+ {
+ QpidFeatureBuilder result = new QpidFeatureBuilder(statisticDefinition);
+ result._state = result._statisticBuilder;
+ result._mandatoryAttributes.add(Attribute.name);
+ result._mandatoryAttributes.add(Attribute.type);
+ return result;
+ }
+
+ static QpidFeatureBuilder createEventBuilder(Map<String, Object> eventDefinition)
+ {
+ QpidFeatureBuilder result = new QpidFeatureBuilder(eventDefinition);
+ result._state = result._eventBuilder;
+ return result;
+ }
+
+ static QpidFeatureBuilder createMethodBuilder(MethodOrEventDataTransferObject methodDefinition)
+ {
+ QpidFeatureBuilder result = new QpidFeatureBuilder(methodDefinition);
+ result._state = result._methodBuilder;
+ result._mandatoryAttributes.add(Attribute.name);
+ return result;
+ }
+
+ private static QpidFeatureBuilder createArgumentBuilder(Map<String, Object> argumentDefinition)
+ {
+ QpidFeatureBuilder result = new QpidFeatureBuilder(argumentDefinition);
+ result._state = result._argumentBuilder;
+ return result;
+ }
+
+
+ /**
+ * Builds new builder with the given data.
+ * This constructor is used for building properties, statistics and arguments.
+ *
+ * @param definition the feature definition data.
+ */
+ private QpidFeatureBuilder(Map<String, Object> definition)
+ {
+ this._featureDefinition = definition;
+ this._methodOrEventDefinition = null;
+ }
+
+ /**
+ * Builds new builder with the given data.
+ * This constructor is used for building properties, statistics and arguments.
+ *
+ * @param definition the feature definition data.
+ */
+ private QpidFeatureBuilder(MethodOrEventDataTransferObject definition)
+ {
+ this._featureDefinition = null;
+ this._methodOrEventDefinition = definition;
+ }
+
+ /**
+ * Returns the just built qpid feature.
+ *
+ * @return the qpid feature.
+ */
+ QpidFeature getQpidFeature()
+ {
+ return _qpidFeature;
+ }
+
+ /**
+ * Return the jmx metadata for the built feature.
+ *
+ * @return the jmx metadata for the built feature.
+ */
+ MBeanFeatureInfo getManagementFeature()
+ {
+ return _managementFeatureInfo;
+ }
+
+ void build() throws UnableToBuildFeatureException
+ {
+ try
+ {
+ _state.build();
+ } catch(UnableToBuildFeatureException exception)
+ {
+ throw exception;
+ } catch(Exception exception)
+ {
+ throw new UnableToBuildFeatureException(exception,"Feature name is not available for debugging.");
+ }
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidMethod.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidMethod.java
new file mode 100644
index 0000000000..7824ecc9a4
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidMethod.java
@@ -0,0 +1,147 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.transport.codec.BBDecoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+
+/**
+ * Qpid method definition.
+ * An entity describing an invocation that can be made on a managed object instance.
+ *
+ * @author Andrea Gazzarini
+ */
+public class QpidMethod extends QpidFeature
+{
+ /** Argument list */
+ List<QpidArgument> arguments = new LinkedList<QpidArgument>();
+
+ /**
+ * Builds a new qpid method definition with the given name and description.
+ *
+ * @param name the method name.
+ * @param description the method description.
+ */
+ QpidMethod(String name, String description)
+ {
+ this._name = name;
+ this._description = description;
+ }
+
+ /**
+ * Adds an argument to this method.
+ *
+ * @param argument the new argument to be added.
+ */
+ void addArgument(QpidArgument argument)
+ {
+ arguments.add(argument);
+ }
+
+ /**
+ * Returns a string representation of this method.
+ * The result format is <method name>(argType1 argName1 (Direction), argType2 argName2 (Direction), etc...)
+ *
+ * @return a string representation of this method.
+ */
+ @Override
+ public String toString ()
+ {
+ StringBuilder builder = new StringBuilder()
+ .append(_name)
+ .append('(');
+
+ for (QpidArgument argument : arguments)
+ {
+ builder.append(argument).append(',');
+ }
+
+ builder.append(')');
+ return builder.toString();
+ }
+
+ /**
+ * Encodes the given parameter values according to this method arguments definitions.
+ * Note that only Input/Output and Input parameters are encoded.
+ *
+ * @param parameters the parameters values.
+ * @param encoder the encoder used for encoding.
+ */
+ public void encodeParameters (Object[] parameters, Encoder encoder)
+ {
+ int index = 0;
+ for (QpidArgument argument : arguments)
+ {
+ if (argument.getDirection() != Direction.O)
+ {
+ argument.encode(parameters[index++],encoder);
+ }
+ }
+ }
+
+ /**
+ * Decodes the given input raw according to this method arguments definitions.
+ * Note that only Input/Output and Output parameters are encoded.
+ *
+ * @param parameters the parameters values.
+ * @param encoder the encoder used for encoding.
+ */
+ public Map<String, Object> decodeParameters (byte [] values)
+ {
+ BBDecoder decoder = new BBDecoder();
+ decoder.init(ByteBuffer.wrap(values));
+ Map<String, Object> result = new HashMap<String, Object>();
+
+ for (QpidArgument argument : arguments)
+ {
+ if (argument.getDirection() != Direction.I)
+ {
+ result.put(argument.getName(),argument.decode(decoder));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Validates the given array of parameters against the constraint defined on this method's arguments.
+ *
+ * @param parameters the parameters (values) to be validated.
+ * @throws ValidationException when one of the supplied values is violating some constraint.
+ */
+ public void validate (Object[] parameters) throws ValidationException
+ {
+ int index = 0;
+ for (QpidArgument argument : arguments)
+ {
+ if (argument.getDirection() != Direction.O)
+ {
+ argument.validate(parameters[index++]);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidPackage.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidPackage.java
new file mode 100644
index 0000000000..e9799cb147
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidPackage.java
@@ -0,0 +1,279 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.qpid.management.domain.handler.impl.IMethodInvocationListener;
+import org.apache.qpid.management.domain.handler.impl.MethodOrEventDataTransferObject;
+import org.apache.qpid.management.domain.model.type.Binary;
+
+/**
+ * Qpid package definition.
+ * A grouping of class definitions that are related to a single software component.
+ * The package concept is used to extend the management schema beyond just the QPID software components.
+ * The name is prefixed with "Qpid" for avoiding name conficts with java.lang.Package.
+ *
+ * @author Andrea Gazzarini
+ */
+final class QpidPackage
+{
+ /**
+ * Qpid class identity.
+ * Each qpid class is uniquely identifier by its name and schema-hash.
+ * The schema hash is an MD5 checksum of the schema for a class.
+ * It is there so we can support the case where two different versions of the same class are present at the same time.
+ *
+ * @author Andrea Gazzarini
+ */
+ class QpidClassIdentity {
+ final String name;
+ final Binary hash;
+
+ /**
+ * Builds a new class identity with the given name and hash.
+ *
+ * @param name the class name.
+ * @param hash is an MD5 checksum of the schema of this outer class.
+ */
+ QpidClassIdentity(String name,Binary hash) {
+ this.name = name;
+ this.hash = hash;
+ }
+
+ @Override
+ public int hashCode ()
+ {
+ return name.hashCode()+hash.hashCode();
+ }
+
+ @Override
+ public boolean equals (Object obj)
+ {
+ QpidClassIdentity identity = (QpidClassIdentity) obj;
+ return name.equals(identity.name) && hash.equals(identity.hash);
+ }
+ }
+
+ private String _name;
+ private DomainModel _parent;
+ private Map<QpidClassIdentity, QpidClass> _classes = new HashMap<QpidClassIdentity, QpidClass>();
+ private Map<QpidClassIdentity, QpidEvent> _events = new HashMap<QpidClassIdentity, QpidEvent>();
+
+ /**
+ * Builds a new package with the supplied name.
+ *
+ * @param name the name of the package.
+ */
+ QpidPackage(String name, DomainModel parent)
+ {
+ this._name = name;
+ this._parent = parent;
+ }
+
+ /**
+ * Returns the identifier of the broker which contains this package.
+ * @return
+ */
+ UUID getOwnerId()
+ {
+ return _parent.getBrokerId();
+ }
+
+ /**
+ * Returns the name of this package.
+ *
+ * @return the name of this package.
+ */
+ String getName ()
+ {
+ return _name;
+ }
+
+ /**
+ * Adds a class definition to this package.
+ * The class will be added only if its definition doesn't already exists.
+ *
+ * @param className the name of the class.
+ * @param classHash the class schema hash.
+ * @param properties the properties of the class.
+ * @param statistics the statistics of the class.
+ * @param methods the methods of the class.
+ * @param events the events of the class.
+ *
+ * @throws UnableToBuildFeatureException when the class definition cannot be built due to a feature build failure.
+ */
+ void addClassDefinition (
+ String className,
+ Binary classHash,
+ List<Map<String, Object>> properties,
+ List<Map<String, Object>> statistics,
+ List<MethodOrEventDataTransferObject> methods) throws UnableToBuildFeatureException
+ {
+ getQpidClass(className,classHash,true).setSchema(properties,statistics,methods);
+ }
+
+ void addEventDefinition (
+ String eventClassName,
+ Binary classHash,
+ List<Map<String, Object>> arguments) throws UnableToBuildFeatureException
+ {
+ getQpidEvent(eventClassName,classHash,true).setSchema(arguments);
+ }
+
+ /**
+ * Returns true if this package contains the given class definition.
+ *
+ * @param className the name of the class.
+ * @return true if this package contains the class definition, false otherwise.
+ */
+ boolean alreadyContainsClassDefinition (String className, Binary hash)
+ {
+ return _classes.containsKey(new QpidClassIdentity(className,hash));
+ }
+
+ /**
+ * Injects into a class the given object instance instrumentation data.
+ *
+ * @param className the of the class the injected object data belongs to.
+ * @param objectId the object identifier.
+ * @param rawData the instrumentation data (in raw format).
+ */
+ void setObjectInstanceInstrumentationRawData (String className, Binary classHash,Binary objectId, byte[] rawData)
+ {
+ getQpidClass(className, classHash,true).addInstrumentationData(objectId,rawData);
+ }
+
+ /**
+ * Injects into a class the given object instance configuration data.
+ *
+ * @param className the of the class the injected object data belongs to.
+ * @param objectId the object identifier.
+ * @param rawData the configuration data (in raw format).
+ */
+ void setObjectInstanceConfigurationRawData (String className,Binary classHash, Binary objectId, byte[] rawData)
+ {
+ getQpidClass(className,classHash,true).addConfigurationData(objectId,rawData);
+ }
+
+ void setEventInstanceRawData (String eventName,Binary eventHash, byte[] rawData,long currentTimestamp,int severity)
+ {
+ getQpidEvent(eventName,eventHash,true).addEventData(rawData, currentTimestamp, severity);
+ }
+
+ /**
+ * Returns the definition of the class with given name.
+ *
+ * @param className the name of the class.
+ * @param hash the class hash.
+ * @param store a flag indicating if a just created class must be stored or not.
+ * @return the definition of the class with given name.
+ */
+ QpidClass getQpidClass(String className, Binary hash, boolean store)
+ {
+ QpidClassIdentity identity = new QpidClassIdentity(className,hash);
+ QpidClass classDefinition = _classes.get(identity);
+ if (classDefinition == null)
+ {
+ classDefinition = new QpidClass(className, hash,this);
+ if (store)
+ {
+ _classes.put(identity,classDefinition);
+ }
+ }
+ return classDefinition;
+ }
+
+ /**
+ * Returns the definition of the class with given name.
+ *
+ * @param className the name of the class.
+ * @param hash the class hash.
+ * @param store a flag indicating if a just created class must be stored or not.
+ * @return the definition of the class with given name.
+ */
+ QpidEvent getQpidEvent(String className, Binary hash, boolean store)
+ {
+ QpidClassIdentity identity = new QpidClassIdentity(className,hash);
+ QpidEvent eventDefinition = _events.get(identity);
+ if (eventDefinition == null)
+ {
+ eventDefinition = new QpidEvent(className, hash,this);
+ if (store)
+ {
+ _events.put(identity,eventDefinition);
+ }
+ }
+ return eventDefinition;
+ }
+
+ /**
+ * Returns a string representation of this class.
+ * That is, this method returns the simple name (not FQN) of this class.
+ */
+ @Override
+ public String toString ()
+ {
+ return _name;
+ }
+
+ /**
+ * Removes the object instance associated to the given parameters.
+ *
+ * @param className the class definition of the object instance.
+ * @param classHash the class hash
+ * @param objectId the object identifier.
+ */
+ void removeObjectInstance (String className, Binary classHash, Binary objectId)
+ {
+ QpidClass qpidClass = getQpidClass(className,classHash,false);
+ qpidClass.removeObjectInstance(objectId);
+ }
+
+ /**
+ * Releases all previously acquired resources of this package.
+ */
+ void releaseResources ()
+ {
+ for (QpidClass qpidClass : _classes.values())
+ {
+ qpidClass.releaseResources();
+ }
+
+ for (QpidEvent qpidEvent: _events.values())
+ {
+ qpidEvent.releaseResources();
+ }
+ }
+
+ /**
+ * Returns the method invocation listener of the corresponing parent domain model.
+ *
+ * @return the method invocation listener of the corresponing parent domain model.
+ */
+ IMethodInvocationListener getMethodInvocationListener ()
+ {
+ return _parent.getMethodInvocationListener();
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidProperty.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidProperty.java
new file mode 100644
index 0000000000..089b00c71c
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidProperty.java
@@ -0,0 +1,295 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import java.lang.reflect.Constructor;
+
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.configuration.Configuration;
+import org.apache.qpid.management.domain.model.type.Type;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * Qpid property definition.
+ *
+ * @author Andrea Gazzarini
+ */
+class QpidProperty extends QpidAttribute
+{
+ private final static Logger LOGGER = Logger.get(QpidProperty.class);
+
+ private final static int [] MASKS = {1,2,4,8,16,32,64,128};
+
+ /**
+ * Decoder interface used for decoding incomng values for this property.
+ *
+ * @author Andrea Gazzarini
+ */
+ interface Decoder
+ {
+ Object decodeValue(org.apache.qpid.transport.codec.Decoder decoder,byte [] presenceBitMasks);
+ }
+
+ /**
+ * Decoder used for decoding incoming values for this optional property.
+ */
+ final Decoder _optionalPropertyDecoder = new Decoder() {
+
+ public Object decodeValue (org.apache.qpid.transport.codec.Decoder decoder, byte[] presenceBitMasks)
+ {
+ return ((presenceBitMasks[_optionalIndex/8] & MASKS[_maskIndex]) != 0)
+ ? QpidProperty.this.decodeValue(decoder)
+ : null;
+ }
+ };
+
+ /**
+ * Decoder used for decoding incoming values for this mandatory property.
+ */
+ final Decoder _mandatoryPropertyDecoder = new Decoder() {
+
+ public Object decodeValue (org.apache.qpid.transport.codec.Decoder decoder, byte[] presenceBitMasks)
+ {
+ return QpidProperty.this.decodeValue(decoder);
+ }
+ };
+
+
+ /**
+ * Null object used to perform a dummy validation.
+ * This is the default validator installed at creation time.
+ */
+ final static IValidator EMPTY_VALIDATOR = new IValidator()
+ {
+ public void validate (Object value) throws ValidationException
+ {
+ // Nothing to do here.
+ }
+ };
+
+ /**
+ * Validator responsible for validating strings.
+ * At the moment the only constraint that should be applied to a string feature is the "max length"
+ */
+ class StringValidator implements IValidator
+ {
+ public void validate (Object value) throws ValidationException
+ {
+ if ((_maxLength != Integer.MIN_VALUE) && (value != null)){
+ int length = value.toString().length();
+ if (length > _maxLength) {
+ throw new ValidationException(
+ ValidationException.MAX_LENGTH,
+ _maxLength,
+ _name,
+ length);
+ }
+ }
+ }
+ };
+
+ /**
+ * Validator responsible for validating numbers.
+ */
+ class NumberValidator implements IValidator
+ {
+ public void validate (Object value) throws ValidationException
+ {
+ if (value != null) {
+ double numericValue = ((Number)value).doubleValue();
+ if (_minValue != Integer.MIN_VALUE && numericValue < _minValue) {
+ throw new ValidationException(
+ ValidationException.MIN_VALUE,
+ _minValue,
+ _name,
+ numericValue);
+ }
+
+ if (_maxValue != Integer.MIN_VALUE && numericValue > _maxValue) {
+ throw new ValidationException(
+ ValidationException.MAX_VALUE,
+ _maxValue,
+ _name,
+ numericValue);
+ }
+ }
+ }
+ };
+
+ private AccessMode _accessMode;
+ private int _minValue = Integer.MIN_VALUE;
+ private int _maxValue = Integer.MIN_VALUE;
+ private int _maxLength = Integer.MIN_VALUE;
+
+ private int _optionalIndex;
+ private int _maskIndex;
+
+ Decoder _decoder = _mandatoryPropertyDecoder;
+
+ private IValidator _validator = EMPTY_VALIDATOR;
+
+ /**
+ * Validates the given value according to the current validator.
+ * It delegates the validation to the current installed validator.
+ *
+ * @param value the value of this qpid property.
+ * @throws ValidationException when the given value is violating the current validator constraints.
+ */
+ void validate(Object value) throws ValidationException {
+ _validator.validate(value);
+ }
+
+ /**
+ * Sets the type of this property.
+ * In addition this method tries to detect if a validator has been associated with the type.
+ * If no validator is found then the default validator will be used; that is : no validator will be performed on this
+ * property.
+ *
+ * @param type the type of this property.
+ */
+ void setType (Type type)
+ {
+ super.setType(type);
+ try {
+ Class<?> validatorClass = Class.forName(Configuration.getInstance().getValidatorClassName(type));
+ Constructor<?> validatorConstructor = validatorClass.getDeclaredConstructor(QpidProperty.class);
+ _validator = (IValidator) validatorConstructor.newInstance(this);
+ LOGGER.debug(Messages.QMAN_200022_VALIDATOR_INSTALLED ,validatorClass.getName(), type);
+ } catch(Exception exception) {
+ _validator = EMPTY_VALIDATOR;
+ LOGGER.debug(Messages.QMAN_200023_VALIDATOR_NOT_FOUND , type);
+ }
+ }
+
+ /**
+ * Gets the value of this property according to its type definition.
+ *
+ * @param decoder the decoder used to extract the value.
+ * @return the value of this feature according to its type definition
+ */
+ Object decodeValue(org.apache.qpid.transport.codec.Decoder decoder,byte [] presenceBitMasks)
+ {
+ return _decoder.decodeValue(decoder, presenceBitMasks);
+ }
+
+ /**
+ * Sets access mode for this property.
+ *
+ * @param accessMode the access mode for this property.
+ */
+ void setAccessMode (AccessMode accessMode)
+ {
+ this._accessMode = accessMode;
+ }
+
+ /**
+ * Gets the minimum allowed value for this property.
+ *
+ * @return the minimum allowed value for this property.
+ */
+ int getMinValue ()
+ {
+ return _minValue;
+ }
+
+ /**
+ * Sets the minimum allowed value for this property.
+ *
+ * @param minValue the minimum allowed value for this property.
+ */
+ void setMinValue (int minValue)
+ {
+ this._minValue = minValue;
+ }
+
+ /**
+ * Gets the maximum allowed value for this property.
+ *
+ * @return the maximum allowed value for this property.
+ */
+ int getMaxValue ()
+ {
+ return _maxValue;
+ }
+
+ /**
+ * Sets the masimum allowed value for this property.
+ *
+ * @param maxValue the maximum allowed value for this property.
+ */
+ void setMaxValue (int maxValue)
+ {
+ this._maxValue = maxValue;
+ }
+
+ /**
+ * Gets the max length value for this property.
+ *
+ * @return the max length value for this property.
+ */
+ int getMaxLength ()
+ {
+ return _maxLength;
+ }
+
+ /**
+ * Sets the max length value for this property.
+ *
+ * @param maxLength the max length value for this property.
+ */
+ void setMaxLength (int maxLength)
+ {
+ this._maxLength = maxLength;
+ }
+
+ /**
+ * Gets the description of this property.
+ *
+ * @return the description of this property.
+ */
+ AccessMode getAccessMode ()
+ {
+ return _accessMode;
+ }
+
+ /**
+ * Marks this property as optional.
+ *
+ * @param optional the optional attribute value for this property.
+ * @param index the index of this optional property
+ */
+ void markAsOptional (int index)
+ {
+ this._optionalIndex = index;
+ this._maskIndex = (_optionalIndex >= 8) ? _optionalIndex-8 : _optionalIndex;
+ _decoder = _optionalPropertyDecoder;
+ }
+
+ /**
+ * Returns true if this property is marked as optional.
+ *
+ * @return true if this property is marked as optional, false otherwise.
+ */
+ boolean isOptional ()
+ {
+ return _decoder == _optionalPropertyDecoder;
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidStatistic.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidStatistic.java
new file mode 100644
index 0000000000..37a652c098
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidStatistic.java
@@ -0,0 +1,34 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+/**
+ * Qpid statistic definition.
+ *
+ * A statistic is a typed member of a class which represents an instrumentation attribute of the class.
+ * Statistics are always read-only in nature and tend to change rapidly.
+ *
+ * @author Andrea Gazzarini
+ */
+class QpidStatistic extends QpidAttribute
+{
+ // EMPTY CLASS : Statistic metadata are all defined in superclasses.
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/UnableToBuildFeatureException.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/UnableToBuildFeatureException.java
new file mode 100644
index 0000000000..fc4506779b
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/UnableToBuildFeatureException.java
@@ -0,0 +1,51 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+/**
+ * Thrown when a feature (property, statistic, method or event) definition cannot be built due to schema parsing errors.
+ *
+ * @author Andrea Gazzarini
+ */
+public class UnableToBuildFeatureException extends Exception
+{
+ private static final long serialVersionUID = 5180111828887602836L;
+
+ /**
+ * Builds a new UnableToBuildFeatureException with the specified cause.
+ *
+ * @param exception the exception cause.
+ */
+ UnableToBuildFeatureException(Exception exception, String featureName)
+ {
+ super( (featureName != null) ? featureName : "Feature name is not available for debugging purposes." ,exception);
+ }
+
+ /**
+ * Builds a new UnableToBuildFeatureException with the specified message.
+ *
+ * @param message the detail message.
+ */
+ UnableToBuildFeatureException(String message)
+ {
+ super(message);
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/ValidationException.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/ValidationException.java
new file mode 100644
index 0000000000..3b117e5b9d
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/ValidationException.java
@@ -0,0 +1,105 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+/**
+ * Thrown when an attempt is made in order to update / change the state of an object and a constraint on that state
+ * is violated.
+ *
+ * @author Andrea Gazzarini
+ */
+public class ValidationException extends Exception
+{
+ private static final long serialVersionUID = -5218828669655586205L;
+
+ public final static String MAX_LENGTH = "Max Length";
+ public final static String MAX_VALUE = "Max Value";
+ public final static String MIN_VALUE = "Min Value";
+
+ private final String _featureName;
+ private final Object _featureValue;
+
+ private final Number _constraintValue;
+ private final String _constraintName;
+
+ /**
+ * Builds a new validation exception with the specified parameters.
+ *
+ * @param constraintName the name of the violated constraint.
+ * @param constraintValue the value of the violated constraint.
+ * @param featureName the name of the violating feature.
+ * @param featureValue the value of the violating feature.
+ */
+ ValidationException(String constraintName,Number constraintValue, String featureName,Object featureValue)
+ {
+ super(String.format(
+ "Property constraint violation : " +
+ "%s allowed for property %s is %s but received value was %s",
+ constraintName,
+ featureName,
+ constraintValue,
+ featureValue));
+ this._constraintName = constraintName;
+ this._constraintValue = constraintValue;
+ this._featureName = featureName;
+ this._featureValue = featureValue;
+ }
+
+ /**
+ * Returns the value of the violating feature.
+ *
+ * @return the value of the violating feature.
+ */
+ public Object getFeatureValue ()
+ {
+ return _featureValue;
+ }
+
+ /**
+ * Returns the name of the violating feature.
+ *
+ * @return the name of the violating feature.
+ */
+ public String getFeatureName()
+ {
+ return _featureName;
+ }
+
+ /**
+ * Returns the value of the violated constraint.
+ *
+ * @return the value of the violated constraint.
+ */
+ public Number getConstraintValue ()
+ {
+ return _constraintValue;
+ }
+
+ /**
+ * Returns the name of the violated constraint.
+ *
+ * @return the name of the violated constraint.
+ */
+ public String getConstraintName ()
+ {
+ return _constraintName;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/AbsTime.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/AbsTime.java
new file mode 100644
index 0000000000..28f5f70c04
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/AbsTime.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model.type;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class AbsTime extends Type
+{
+ public AbsTime()
+ {
+ super(Long.class);
+ }
+
+ @Override
+ public Object decode (Decoder decoder)
+ {
+ return decoder.readInt64();
+ }
+
+ @Override
+ public void encode (Object value, Encoder encoder)
+ {
+ encoder.writeInt64((Long)value);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Binary.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Binary.java
new file mode 100644
index 0000000000..343280ca4b
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Binary.java
@@ -0,0 +1,162 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model.type;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.UUID;
+
+import org.apache.qpid.transport.codec.Encoder;
+
+/**
+ * It is a simple wrapper for a byte array (for example a 128bin).
+ * It is used to let QMan deal with an object instead of an array.
+ *
+ * @author Andrea Gazzarini
+ */
+public final class Binary implements Serializable
+{
+ private static final long serialVersionUID = -6865585077320637567L;
+
+ // Marker internal (empty) interface
+ private interface State extends Serializable{}
+
+ /**
+ * Internal state of this object used to denote the situation when the hashcode() method has never been called.
+ * After the hashcode has been computed this class switches the state of the outer object to the next state.
+ */
+ State hashCodeNotYetComputed = new State()
+ {
+ private static final long serialVersionUID = 221632033761266959L;
+
+ @Override
+ public int hashCode ()
+ {
+ hashCode = Arrays.hashCode(_bytes);
+ state = hashCodeAlreadyComputed;
+ return hashCode;
+ }
+ };
+
+ /**
+ * Internal state of this object used to denote the situation where the hashcode() method has already been computed.
+ * Simply it returns the just computed value for the hashcode.
+ */
+ State hashCodeAlreadyComputed = new State()
+ {
+ private static final long serialVersionUID = 221632033761266959L;
+
+ @Override
+ public int hashCode ()
+ {
+ return hashCode;
+ }
+ };
+
+ private final UUID uuid;
+ private final byte [] _bytes;
+ private long _first;
+ private int hashCode;
+
+ /** Current state (hashcode computation). */
+ State state = hashCodeNotYetComputed;
+
+ /**
+ * Builds a new binary with the given byte array.
+ *
+ * @param bytes the wrapped data.
+ */
+ public Binary(byte [] bytes)
+ {
+ this._bytes = bytes;
+ byte [] array = new byte [8];
+ System.arraycopy(_bytes, 0, array, 0, 8);
+ _first = unpack64(array);
+ uuid = UUID.randomUUID();
+ }
+
+ @Override
+ public int hashCode ()
+ {
+ return state.hashCode();
+ }
+
+ @Override
+ public boolean equals (Object obj)
+ {
+ try
+ {
+ Binary binary = (Binary)obj;
+ return Arrays.equals(_bytes, binary._bytes);
+ } catch (Exception exception)
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Encodes the content (wrapped byte array) of this instance using the given encoder.
+ *
+ * @param encoder the encoder used to encode instance content.
+ */
+ public void encode(Encoder encoder)
+ {
+ encoder.writeBin128(_bytes);
+ }
+
+ @Override
+ public String toString ()
+ {
+ return uuid.toString();
+ }
+
+ /**
+ * Returns the bank identifier derived from this object identifier.
+ *
+ * @return the bank identifier derived from this object identifier.
+ */
+ public long getBankId()
+ {
+ return _first & 0x000000000FFFFFFF;
+ }
+
+ /**
+ * Returns the broker identifier derived from this object identifier.
+ *
+ * @return the broker identifier derived from this object identifier.
+ */
+ public long getBrokerId()
+ {
+ return (_first & 281474708275200L) >> 28;
+ }
+
+ public final long unpack64(byte data[]) {
+ return (
+ ((long) (data[0] & 0xff) << 56) |
+ ((long)(data[1] & 0xff) << 48) |
+ ((long)(data[2] & 0xff) << 40) |
+ ((long)(data[3] & 0xff) << 32) |
+ ((long)(data[4] & 0xff) << 24) |
+ ((long)(data[5] & 0xff) << 16) |
+ ((long)(data[6] & 0xff) << 8) |
+ (long) data[7] & 0xff);
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Boolean.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Boolean.java
new file mode 100644
index 0000000000..c339b870ac
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Boolean.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model.type;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class Boolean extends Type
+{
+ public Boolean()
+ {
+ super(java.lang.Boolean.class);
+ }
+
+ @Override
+ public Object decode (Decoder decoder)
+ {
+ return (decoder.readUint8() == 1);
+ }
+
+ @Override
+ public void encode (Object value, Encoder encoder)
+ {
+ encoder.writeUint8( ((java.lang.Boolean)value) ? (short)1 : 0 );
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/DeltaTime.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/DeltaTime.java
new file mode 100644
index 0000000000..a788e2f8e1
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/DeltaTime.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model.type;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class DeltaTime extends Type
+{
+ public DeltaTime()
+ {
+ super(Long.class);
+ }
+
+ @Override
+ public Object decode (Decoder decoder)
+ {
+ return decoder.readUint64();
+ }
+
+ @Override
+ public void encode (Object value, Encoder encoder)
+ {
+ encoder.writeUint64((Long)value);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Double.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Double.java
new file mode 100644
index 0000000000..d36af3d3df
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Double.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model.type;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class Double extends Type
+{
+ public Double()
+ {
+ super(java.lang.Double.class);
+ }
+
+ @Override
+ public Object decode(Decoder decoder)
+ {
+ return decoder.readDouble();
+ }
+
+ @Override
+ public void encode(Object value, Encoder encoder)
+ {
+ encoder.writeDouble((java.lang.Double)value);
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Float.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Float.java
new file mode 100644
index 0000000000..cb1f6e78a7
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Float.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model.type;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class Float extends Type
+{
+ public Float()
+ {
+ super(java.lang.Float.class);
+ }
+
+ @Override
+ public Object decode(Decoder decoder)
+ {
+ return decoder.readFloat();
+ }
+
+ @Override
+ public void encode(Object value, Encoder encoder)
+ {
+ encoder.writeFloat((java.lang.Float)value);
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int16.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int16.java
new file mode 100644
index 0000000000..f4685f0295
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int16.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model.type;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class Int16 extends Type
+{
+ public Int16()
+ {
+ super(Short.class);
+ }
+
+ @Override
+ public Object decode (Decoder decoder)
+ {
+ return decoder.readInt16();
+ }
+
+ @Override
+ public void encode (Object value, Encoder encoder)
+ {
+ encoder.writeInt16((Short)value);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int32.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int32.java
new file mode 100644
index 0000000000..ae5be90a2d
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int32.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model.type;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class Int32 extends Type
+{
+ public Int32()
+ {
+ super(Integer.class);
+ }
+
+ @Override
+ public Object decode (Decoder decoder)
+ {
+ return decoder.readInt32();
+ }
+
+ @Override
+ public void encode (Object value, Encoder encoder)
+ {
+ encoder.writeInt32((Integer)value);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int64.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int64.java
new file mode 100644
index 0000000000..f76818344e
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int64.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model.type;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class Int64 extends Type
+{
+ public Int64()
+ {
+ super(Long.class);
+ }
+
+ @Override
+ public Object decode (Decoder decoder)
+ {
+ return decoder.readInt64();
+ }
+
+ @Override
+ public void encode (Object value, Encoder encoder)
+ {
+ encoder.writeInt64((Long)value);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int8.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int8.java
new file mode 100644
index 0000000000..6f7c3b24d0
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int8.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model.type;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class Int8 extends Type
+{
+ public Int8()
+ {
+ super(Byte.class);
+ }
+
+ @Override
+ public Object decode (Decoder decoder)
+ {
+ return decoder.readInt8();
+ }
+
+ @Override
+ public void encode (Object value, Encoder encoder)
+ {
+ encoder.writeInt8((Byte)value);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Map.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Map.java
new file mode 100644
index 0000000000..ef5bc7a484
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Map.java
@@ -0,0 +1,45 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model.type;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class Map extends Type
+{
+ public Map()
+ {
+ super(java.util.Map.class);
+ }
+
+ @Override
+ public Object decode (Decoder decoder)
+ {
+ return decoder.readMap();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void encode (Object value, Encoder encoder)
+ {
+ encoder.writeMap((java.util.Map<String, Object>)value);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/ObjectReference.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/ObjectReference.java
new file mode 100644
index 0000000000..13e1b68d26
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/ObjectReference.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model.type;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class ObjectReference extends Type
+{
+ public ObjectReference()
+ {
+ super(byte[].class);
+ }
+
+ @Override
+ public Object decode (Decoder decoder)
+ {
+ return decoder.readBin128();
+ }
+
+ @Override
+ public void encode (Object value, Encoder encoder)
+ {
+ ((Binary)value).encode(encoder);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Str16.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Str16.java
new file mode 100644
index 0000000000..42829ce176
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Str16.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model.type;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class Str16 extends Type
+{
+ public Str16()
+ {
+ super(String.class);
+ }
+
+ @Override
+ public Object decode (Decoder decoder)
+ {
+ return decoder.readStr16();
+ }
+
+ @Override
+ public void encode (Object value, Encoder encoder)
+ {
+ encoder.writeStr16((String)value);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Str8.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Str8.java
new file mode 100644
index 0000000000..f9b747ce6d
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Str8.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model.type;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class Str8 extends Type
+{
+ public Str8()
+ {
+ super(String.class);
+ }
+
+ @Override
+ public Object decode (Decoder decoder)
+ {
+ return decoder.readStr8();
+ }
+
+ @Override
+ public void encode (Object value, Encoder encoder)
+ {
+ encoder.writeStr8((String)value);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Type.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Type.java
new file mode 100644
index 0000000000..c455faaf2c
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Type.java
@@ -0,0 +1,101 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model.type;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+/**
+ * Layer supertype for all management "types".
+ *
+ * @author Andrea Gazzarini
+ */
+public abstract class Type
+{
+ /** Java representation of this type. */
+ protected final Class<?> javaType;
+
+ /**
+ * Builds a new management type wiich wraps the given java type.
+ *
+ * @param javaType the java type.
+ */
+ Type(Class<?> javaType)
+ {
+ this.javaType = javaType;
+ }
+
+ /**
+ * Returns the wrapped java type.
+ *
+ * @return the wrapped java type.
+ */
+ public Class<?> getJavaType ()
+ {
+ return javaType;
+ }
+
+ /**
+ * Each concrete subclass must define here how to decode incoming data according.
+ *
+ * @param decoder the decoder used to extract data.
+ * @return the "typed" value.
+ *
+ */
+ public abstract Object decode(Decoder decoder);
+
+ /**
+ * Returns a string representation of this type.
+ *
+ * @return a string representation of this type.
+ */
+ @Override
+ public String toString ()
+ {
+ return new StringBuilder(getClass().getName())
+ .append(" (wraps ")
+ .append(javaType.getName())
+ .append(')').toString();
+ }
+
+ /**
+ * Identity for types is based on wrapped java type identity.
+ */
+ @Override
+ public boolean equals (Object obj)
+ {
+ return getClass() == obj.getClass();
+ }
+
+ @Override
+ public int hashCode ()
+ {
+ return getClass().hashCode();
+ }
+
+ /**
+ * Encodes the given values according to this type definition.
+ *
+ * @param value the value to be encoded.
+ * @param encoder the encoder.
+ */
+ public abstract void encode (Object value,Encoder encoder);
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint16.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint16.java
new file mode 100644
index 0000000000..2d3edd41ea
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint16.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model.type;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class Uint16 extends Type
+{
+ public Uint16()
+ {
+ super(Integer.class);
+ }
+
+ @Override
+ public Object decode (Decoder decoder)
+ {
+ return new Integer(decoder.readUint16());
+ }
+
+ @Override
+ public void encode (Object value, Encoder encoder)
+ {
+ encoder.writeUint16((Integer)value);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint32.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint32.java
new file mode 100644
index 0000000000..c5fb981bb0
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint32.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model.type;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class Uint32 extends Type
+{
+ public Uint32()
+ {
+ super(Long.class);
+ }
+
+ @Override
+ public Object decode (Decoder decoder)
+ {
+ return new Long(decoder.readUint32());
+ }
+
+ @Override
+ public void encode (Object value, Encoder encoder)
+ {
+ encoder.writeUint32((Long)value);
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint64.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint64.java
new file mode 100644
index 0000000000..9182f883bf
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint64.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model.type;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class Uint64 extends Type
+{
+ public Uint64()
+ {
+ super(Long.class);
+ }
+
+ @Override
+ public Object decode (Decoder decoder)
+ {
+ return new Long(decoder.readUint64());
+ }
+
+ @Override
+ public void encode (Object value, Encoder encoder)
+ {
+ encoder.writeUint64((Long)value);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint8.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint8.java
new file mode 100644
index 0000000000..ab7e78856c
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint8.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model.type;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class Uint8 extends Type
+{
+ public Uint8()
+ {
+ super(Short.class);
+ }
+
+ @Override
+ public Object decode (Decoder decoder)
+ {
+ return new Short(decoder.readUint8());
+ }
+
+ @Override
+ public void encode (Object value, Encoder encoder)
+ {
+ encoder.writeUint8((Short)value);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uuid.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uuid.java
new file mode 100644
index 0000000000..1b3be954d6
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uuid.java
@@ -0,0 +1,46 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model.type;
+
+import java.util.UUID;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class Uuid extends Type
+{
+ public Uuid()
+ {
+ super(UUID.class);
+ }
+
+ @Override
+ public Object decode (Decoder decoder)
+ {
+ return decoder.readUuid();
+ }
+
+ @Override
+ public void encode (Object value, Encoder encoder)
+ {
+ encoder.writeUuid((UUID)value);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/services/BrokerMessageListener.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/services/BrokerMessageListener.java
new file mode 100644
index 0000000000..fc9819fce4
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/services/BrokerMessageListener.java
@@ -0,0 +1,183 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.services;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.qpid.api.Message;
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Protocol;
+import org.apache.qpid.management.domain.handler.base.IMessageHandler;
+import org.apache.qpid.management.domain.model.DomainModel;
+import org.apache.qpid.nclient.util.MessageListener;
+import org.apache.qpid.transport.codec.BBDecoder;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * Message listener used for processing incoming messages.
+ * So it is installed as a consumer on a specific channel and when a new message arrives:
+ *
+ * 1) Performs a sanity check on the message (magic number, sequence number)
+ * 2) Extracts the opcode and looks for one message handler associated with that opcode.
+ * 3) If a message handler is found the delegates the message processing; otherwise a log message is written to indicate
+ * that the message will be skipped.
+ *
+ * @author Andrea Gazzarini
+ */
+class BrokerMessageListener implements MessageListener
+{
+ private final static Logger LOGGER = Logger.get(BrokerMessageListener.class);
+
+ private static class Log
+ {
+ // Debugs the content of the incoming message.
+ static void debugIncomingMessage(ByteBuffer message)
+ {
+ if (LOGGER.isDebugEnabled())
+ {
+ LOGGER.debug(Messages.QMAN_200001_INCOMING_MESSAGE_HAS_BEEN_RECEIVED, Arrays.toString(message.array()));
+ }
+ }
+
+ // Debugs all the configured handlers.
+ static void debugConfiguredHandlers (Map<Character, IMessageHandler> _handlers)
+ {
+ if (LOGGER.isDebugEnabled())
+ {
+ for (Entry<Character, IMessageHandler> entry : _handlers.entrySet())
+ {
+ LOGGER.debug(Messages.QMAN_200002_OPCODE_HANDLER_ASSOCIATION,entry.getKey(),entry.getValue());
+ }
+ }
+ }
+ }
+
+ Map<Character, IMessageHandler> _handlers = new HashMap<Character, IMessageHandler>();
+ private DomainModel _domainModel;
+
+ /**
+ * Builds a new message listener with the given broker domain model.
+ *
+ * @param model the managed broker domain model.
+ */
+ BrokerMessageListener(DomainModel model)
+ {
+ this._domainModel = model;
+ }
+
+ /**
+ * When a new message arrives this method is called.
+ * 1) Performs a sanity check on the message (magic number, sequence number)
+ * 2) Extracts the opcode and looks for one message handler associated with that opcode.
+ * 3) If a message handler is found the delegates the message processing; otherwise a log message is written to indicate
+ * that the message will be skipped.
+ *
+ * @param message the incoming message.
+ */
+ public void onMessage (Message compoundMessage)
+ {
+ try
+ {
+ MessageTokenizer tokenizer = new MessageTokenizer(compoundMessage);
+ while (tokenizer.hasMoreElements())
+ {
+ dispatch(tokenizer.nextElement());
+ }
+ } catch(IOException exception)
+ {
+ LOGGER.error(exception,Messages.QMAN_100002_MESSAGE_READ_FAILURE);
+ } catch(Exception exception)
+ {
+ LOGGER.error(exception,Messages.QMAN_100003_MESSAGE_PROCESS_FAILURE);
+ }
+ }
+
+ /**
+ * Configures a new handler with this listener.
+ * After that, each time a message arrives with the specified opcode, this handler will be responsible for
+ * processing.
+ * Note that calling this method will switch this listener to a WORKING state.
+ *
+ * @param opcode the operation code.
+ * @param handler the message handler.
+ */
+ void setHandlers(Map<Character, IMessageHandler> handlers)
+ {
+ for (Entry<Character, IMessageHandler> entry : handlers.entrySet())
+ {
+ char opcode = entry.getKey();
+ IMessageHandler handler = entry.getValue();
+ try
+ {
+ handler.setDomainModel(_domainModel);
+ _handlers.put(opcode, handler);
+ } catch (Exception exception) {
+ LOGGER.error(exception,
+ Messages.QMAN_100004_HANDLER_INITIALIZATION_FAILURE,
+ opcode);
+ }
+ }
+ }
+
+
+
+ /**
+ * Dispatches the given message to the appropriate handler.
+ *
+ * @param message
+ * the incoming message.
+ * @throws IOException
+ * when the message content cannot be read.
+ */
+ private void dispatch(Message message) throws IOException
+ {
+ ByteBuffer buffer = message.readData();
+
+ String magicNumber = new String(new byte[] {buffer.get(),buffer.get(),buffer.get()});
+ if (!Protocol.MAGIC_NUMBER.equals(magicNumber))
+ {
+ LOGGER.error(Messages.QMAN_100001_BAD_MAGIC_NUMBER_FAILURE,magicNumber);
+ return;
+ }
+
+ char opcode = (char)buffer.get();
+
+ IMessageHandler handler = _handlers.get(opcode);
+ if (handler != null)
+ {
+ BBDecoder decoder = new BBDecoder();
+ decoder.init(buffer);
+
+ LOGGER.debug(Messages.QMAN_200003_MESSAGE_FORWARDING,opcode,handler);
+
+ handler.process(decoder,decoder.readSequenceNo());
+ } else
+ {
+ LOGGER.warn(Messages.QMAN_300001_MESSAGE_DISCARDED,opcode);
+ Log.debugConfiguredHandlers(_handlers);
+ }
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/services/ManagementClient.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/services/ManagementClient.java
new file mode 100644
index 0000000000..ee610b1713
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/services/ManagementClient.java
@@ -0,0 +1,250 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.services;
+
+import java.util.UUID;
+
+import org.apache.qpid.QpidException;
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.configuration.BrokerConnectionData;
+import org.apache.qpid.management.configuration.Configuration;
+import org.apache.qpid.management.domain.model.DomainModel;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * This is the Object representation of a management client.
+ * According to specification : "A software component that is separate from the messaging broker, connected to the
+ * management broker via an AMQP connection, which allows any software component to be managed remotely by QPID."
+ *
+ * @author Andrea Gazzarini
+ */
+public final class ManagementClient
+{
+ private final static Logger LOGGER = Logger.get(ManagementClient.class);
+
+ private final String _managementQueueName;
+ private final String _methodReplyQueueName;
+
+ private DomainModel _domainModel;
+ private QpidService _service;
+
+ private final BrokerConnectionData _connectionData;
+
+ /**
+ * Builds a new <code>ManagementClient</code> with the given identifier and connection data.
+ *
+ * @param brokerId the broker identifier.
+ * @param connectionData the broker connection data (host, port, etc...)
+ */
+ ManagementClient(UUID brokerId,BrokerConnectionData connectionData)
+ {
+ _connectionData = connectionData;
+ _service = new QpidService(brokerId);
+ _domainModel = new DomainModel(brokerId);
+ _managementQueueName = Configuration.getInstance().getManagementQueueName();
+ _methodReplyQueueName = Configuration.getInstance().getMethodReplyQueueName();
+ }
+
+ @Override
+ public String toString()
+ {
+ return _connectionData.toString();
+ }
+
+ /**
+ * Returns the connection data associated with this management client.
+ *
+ * @return the connection data associated with this management client.
+ */
+ public BrokerConnectionData getBrokerConnectionData()
+ {
+ return _connectionData;
+ }
+
+ /**
+ * Establishing initial communication Between Client and Broker.
+ * According to specification :
+ * "Communication is established between the management client and management agent using normal AMQP procedures.
+ * The client creates a connection to the broker and then establishes a session with its corresponding channel.
+ * Two private queues are then declared.
+ * A management queue is declared and bound to the qpid.management exchange with "mgmt.#" as routing key; in that
+ * way all management-related messages sent to the exchange will be received by this client.
+ * When a client successfully binds to the qpid.management exchange, the management agent schedules a schema
+ * broadcast to be sent to the exchange.
+ * The agent will publish, via the exchange, a description of the schema for all manageable objects in its control. That
+ * schema is therefore received by this service and it will be part of service's domain model."
+ *
+ * @throws StartupFailureException when this management client cannot perform startup operations due to an error.
+ */
+ void estabilishFirstConnectionWithBroker() throws StartupFailureException{
+ try {
+ connectWithBroker();
+
+ createAndBindMethodReplyQueue();
+ createAndBindManagementQueue();
+
+ registerConsumerOnManagementQueue();
+ registerConsumerOnMethodReplyQueue();
+
+ synchronize();
+ } catch(Exception exception)
+ {
+ try {
+ _service.close();
+ } catch(Exception ignore)
+ {
+ }
+ throw new StartupFailureException(exception);
+ }
+ }
+
+ /**
+ * Shutdown procedure for this management client.
+ */
+ void shutdown ()
+ {
+ LOGGER.info(Messages.QMAN_000011_SHUTDOWN_INITIATED,_domainModel.getBrokerId());
+
+ removeMethodReplyConsumer();
+ destroyAndUnbingMethodReplyQueue();
+
+ removeManagementConsumer();
+ destroyAndUnbingManagementQueue();
+
+ _domainModel.releaseResources();
+
+ _service.close();
+
+ LOGGER.info(Messages.QMAN_000012_MANAGEMENT_CLIENT_SHUT_DOWN,_domainModel.getBrokerId());
+ }
+
+ /**
+ * Registers a consumer (that is, a listener) on the method-reply queue.
+ */
+ private void registerConsumerOnMethodReplyQueue ()
+ {
+ BrokerMessageListener methodReplyChannelListener = new BrokerMessageListener(_domainModel);
+ methodReplyChannelListener.setHandlers(Configuration.getInstance().getMethodReplyQueueHandlers());
+ _service.createSubscription(_methodReplyQueueName, _methodReplyQueueName, methodReplyChannelListener);
+
+ LOGGER.info(Messages.QMAN_000013_METHOD_REPLY_CONSUMER_INSTALLED, _domainModel.getBrokerId());
+ }
+
+ /**
+ * Registers a consumer (listener) on the management queue.
+ */
+ private void registerConsumerOnManagementQueue () throws QpidException
+ {
+ BrokerMessageListener managementChannelListener = new BrokerMessageListener(_domainModel);
+ managementChannelListener.setHandlers(Configuration.getInstance().getManagementQueueHandlers());
+ _service.createSubscription(_managementQueueName, _managementQueueName, managementChannelListener);
+
+ LOGGER.info(Messages.QMAN_000014_MANAGEMENT_CONSUMER_INSTALLED, _domainModel.getBrokerId());
+ }
+
+ /**
+ * Declares a management queue and bound it to the "qpid.management" exchange with "mgmt.#" as routing key;
+ */
+ private void createAndBindManagementQueue ()
+ {
+ _service.declareQueue(_managementQueueName);
+ _service.declareBinding(
+ _managementQueueName,
+ Names.MANAGEMENT_EXCHANGE,
+ Names.MANAGEMENT_ROUTING_KEY);
+
+ LOGGER.info(Messages.QMAN_000015_MANAGEMENT_QUEUE_DECLARED,_managementQueueName,_domainModel.getBrokerId());
+ }
+
+ /**
+ * Declares a private queue for receiving method replies (after method invocations).
+ * This queue is bound to the amq.direct exchange using a routing key equal to the name of the queue.
+ */
+ private void createAndBindMethodReplyQueue ()
+ {
+ _service.declareQueue(_methodReplyQueueName);
+ _service.declareBinding(_methodReplyQueueName, Names.AMQ_DIRECT_QUEUE, _methodReplyQueueName);
+
+ LOGGER.info(Messages.QMAN_000016_METHOD_REPLY_QUEUE_DECLARED,_methodReplyQueueName, _domainModel.getBrokerId());
+ }
+
+ /**
+ * Removes the method-reply queue consumer.
+ */
+ private void removeMethodReplyConsumer()
+ {
+ _service.removeSubscription(_methodReplyQueueName);
+
+ LOGGER.info(Messages.QMAN_000017_CONSUMER_HAS_BEEN_REMOVED,_methodReplyQueueName,_domainModel.getBrokerId());
+ }
+
+ /**
+ * Unbind the method reply queue and after that destroy it from remote broker.
+ */
+ private void destroyAndUnbingMethodReplyQueue()
+ {
+ _service.declareUnbinding(_methodReplyQueueName, Names.AMQ_DIRECT_QUEUE, _methodReplyQueueName);
+ _service.deleteQueue(_methodReplyQueueName);
+
+ LOGGER.info(Messages.QMAN_000018_QUEUE_UNDECLARED,_methodReplyQueueName,_domainModel.getBrokerId());
+ }
+
+ /**
+ * Removes the management queue consumer.
+ */
+ private void removeManagementConsumer()
+ {
+ _service.removeSubscription(_managementQueueName);
+
+ LOGGER.info(Messages.QMAN_000017_CONSUMER_HAS_BEEN_REMOVED,_managementQueueName,_domainModel.getBrokerId());
+ }
+
+ /**
+ * Unbind the management queue and after that destroy it from remote broker.
+ */
+ private void destroyAndUnbingManagementQueue()
+ {
+ _service.declareUnbinding(_managementQueueName, Names.MANAGEMENT_EXCHANGE, Names.MANAGEMENT_ROUTING_KEY);
+ _service.deleteQueue(_managementQueueName);
+
+ LOGGER.info(Messages.QMAN_000018_QUEUE_UNDECLARED, _managementQueueName,_domainModel.getBrokerId());
+ }
+
+ /**
+ * Connects this client with the broker.
+ *
+ * @throws QpidException when it's not possibile to connect with the broker.
+ */
+ private void connectWithBroker() throws Exception
+ {
+ _service.connect();
+ }
+
+ /**
+ * All the Management client commands are asynchronous.
+ * Synchronous behavior is achieved through invoking the sync method.
+ */
+ private void synchronize()
+ {
+ _service.sync();
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/services/MessageTokenizer.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/services/MessageTokenizer.java
new file mode 100644
index 0000000000..9275255517
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/services/MessageTokenizer.java
@@ -0,0 +1,152 @@
+/*
+*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.management.domain.services;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import org.apache.qpid.api.Message;
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Protocol;
+import org.apache.qpid.nclient.util.ByteBufferMessage;
+import org.apache.qpid.transport.codec.BBDecoder;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * The message tokenizer class allows a multi message listener to break a
+ * message into tokens where each token is itself a valid AMQP message.
+ *
+ * @author Andrea Gazzarini
+ * @see QPID-1368
+ */
+class MessageTokenizer implements Enumeration<Message>
+{
+ private final static Logger LOGGER = Logger.get(MessageTokenizer.class);
+
+ static byte [] MAGIC_NUMBER_BYTES;
+
+ private LinkedList<Message> _messages = new LinkedList<Message>();
+ private Iterator<Message> _iterator;
+
+ static
+ {
+ try
+ {
+ MAGIC_NUMBER_BYTES = Protocol.MAGIC_NUMBER.getBytes("UTF-8");
+ } catch(Exception exception)
+ {
+ throw new ExceptionInInitializerError(exception);
+ }
+ }
+
+ /**
+ * Builds a new Message tokenizer with the given message.
+ * Note that if the given message is not a "compound" message this tokenizer will producer only one token;
+ * That is, the token is a message equals to the given message.
+ *
+ * @param compoundMessage the compound message
+ * @throws IOException when it's not possible to read the given message content.
+ */
+ MessageTokenizer(Message compoundMessage) throws IOException
+ {
+ build(compoundMessage);
+ }
+
+ public boolean hasMoreElements()
+ {
+ return _iterator.hasNext();
+ }
+
+ public Message nextElement()
+ {
+ return _iterator.next();
+ }
+
+ /**
+ * Retruns the number of the tokens produced by this tokenizer.
+ *
+ * @return the number of the tokens produced by this tokenizer.
+ */
+ public int countTokens()
+ {
+ return _messages.size();
+ }
+
+ // Internal methods used for splitting the multi message byte array.
+ int indexOf(byte[] source, int startIndex)
+ {
+ int currentSourceIndex;
+ int currentExampleIndex;
+
+ if (startIndex + 3 > source.length)
+ return -1;
+
+ for (currentSourceIndex = startIndex; currentSourceIndex <= source.length - 3; currentSourceIndex++)
+ {
+ for (currentExampleIndex = 0; currentExampleIndex < 3; currentExampleIndex++)
+ {
+ if (source[currentSourceIndex + currentExampleIndex] != MAGIC_NUMBER_BYTES[currentExampleIndex])
+ break;
+ }
+
+ if (currentExampleIndex == 3)
+ return currentSourceIndex;
+ }
+ return -1;
+ }
+
+ // Internal method used for building the tokens.
+ private void build(Message compoundMessage) throws IOException
+ {
+ int startIndex = 0;
+ int indexOfMagicNumber = 0;
+
+ BBDecoder decoder = new BBDecoder();
+ decoder.init(compoundMessage.readData());
+ byte [] source = decoder.readReaminingBytes();
+
+ int howManyTokens = 1;
+
+ while ((indexOfMagicNumber = indexOf(source, startIndex+1)) != -1)
+ {
+ addMessageToken(source, startIndex, (indexOfMagicNumber-startIndex));
+ startIndex = indexOfMagicNumber;
+ howManyTokens++;
+ }
+ addMessageToken(source, startIndex, (source.length-startIndex));
+ _iterator = _messages.iterator();
+
+ LOGGER.debug(Messages.QMAN_200031_COMPOUND_MESSAGE_CONTAINS,howManyTokens);
+ };
+
+ // Builds & adds a new "message" token
+ private void addMessageToken(byte [] source,int startIndex,int length) throws IOException
+ {
+ byte [] messageData = new byte[length];
+ System.arraycopy(source, startIndex, messageData, 0, messageData.length);
+ Message message = new ByteBufferMessage();
+ message.appendData(messageData);
+ _messages.add(message);
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/services/MethodInvocationException.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/services/MethodInvocationException.java
new file mode 100644
index 0000000000..26fd8eee24
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/services/MethodInvocationException.java
@@ -0,0 +1,50 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.services;
+
+public class MethodInvocationException extends Exception
+{
+ private static final long serialVersionUID = -7772343434879470351L;
+ private final long _returnCode;
+ private final String _statusText;
+
+ public MethodInvocationException(long code, String text)
+ {
+ this._returnCode = code;
+ this._statusText = text;
+ }
+
+ @Override
+ public String getMessage ()
+ {
+ return String.format("Return code : \"%s, reason : \"%s\"",_returnCode,_statusText);
+ }
+
+ public long getReturnCode ()
+ {
+ return _returnCode;
+ }
+
+ public String getStatusText ()
+ {
+ return _statusText;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/services/QMan.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/services/QMan.java
new file mode 100644
index 0000000000..c4c0ce5e74
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/services/QMan.java
@@ -0,0 +1,412 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.services;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.DynamicMBean;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationListener;
+import javax.management.ReflectionException;
+
+import org.apache.log4j.xml.DOMConfigurator;
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.configuration.BrokerAlreadyConnectedException;
+import org.apache.qpid.management.configuration.BrokerConnectionData;
+import org.apache.qpid.management.configuration.BrokerConnectionException;
+import org.apache.qpid.management.configuration.Configuration;
+import org.apache.qpid.management.configuration.Configurator;
+import org.apache.qpid.management.domain.model.JmxService;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * Main entry point for starting Q-Man application.
+ */
+public class QMan extends NotificationBroadcasterSupport implements DynamicMBean, NotificationListener
+{
+ private final static Logger LOGGER = Logger.get(QMan.class);
+ private final List<ManagementClient> managementClients = new ArrayList<ManagementClient>();
+
+ private Configurator _configurator = new Configurator();
+ private ThreadPoolExecutor _workManager;
+
+ /**
+ * Starts QMan.
+ * @throws StartupFailureException when it's not possible to proceed with startup.
+ */
+ public void start() throws StartupFailureException
+ {
+ LOGGER.info(Messages.QMAN_000001_STARTING_QMAN);
+ LOGGER.info(Messages.QMAN_000002_READING_CONFIGURATION);
+
+ try
+ {
+ registerQManService();
+
+ _configurator.configure();
+
+ configureWorkManager();
+
+ LOGGER.info(Messages.QMAN_000019_QMAN_STARTED);
+ } catch(Exception exception) {
+ LOGGER.error(exception,Messages.QMAN_100018_UNABLE_TO_STARTUP_CORRECTLY );
+ throw new StartupFailureException(exception);
+ }
+ }
+
+ /**
+ * Connects Q-Man with a broker defined by the given parameter.
+ *
+ * @param host the hostname where the broker is running.
+ * @param port the port where the broker is running.
+ * @param username the username for connecting with the broker.
+ * @param password the password for connecting with the broker.
+ * @param virtualHost the virtual host.
+ * @param initialPoolCapacity the number of the connection that must be immediately opened.
+ * @param maxPoolCapacity the maximum number of opened connection.
+ * @param maxWaitTimeout the maximum amount of time that a client will wait for obtaining a connection.
+ * @throws MBeanException when it's not possible to connect with the broker.
+ */
+ public void addBroker(
+ String host,
+ int port,
+ String username,
+ String password,
+ String virtualHost,
+ int initialPoolCapacity,
+ int maxPoolCapacity,
+ long maxWaitTimeout) throws BrokerAlreadyConnectedException, BrokerConnectionException
+ {
+ Configurator configurator = new Configurator();
+ try {
+ UUID brokerId = UUID.randomUUID();
+ BrokerConnectionData data = configurator.createAndReturnBrokerConnectionData(
+ brokerId,
+ host,
+ port,
+ username,
+ password,
+ virtualHost,
+ initialPoolCapacity,
+ maxPoolCapacity,
+ maxWaitTimeout);
+ createManagementClient(brokerId, data);
+ } catch (BrokerAlreadyConnectedException exception)
+ {
+ LOGGER.warn(Messages.QMAN_300003_BROKER_ALREADY_CONNECTED, exception.getBrokerConnectionData());
+ throw exception;
+ }
+ }
+
+ /**
+ * Stop Qman
+ */
+ public void stop()
+ {
+ LOGGER.info(Messages.QMAN_000020_SHUTTING_DOWN_QMAN);
+ try
+ {
+ for (ManagementClient client : managementClients)
+ {
+ client.shutdown();
+ }
+ } catch(Exception exception)
+ {
+ }
+ LOGGER.info(Messages.QMAN_000021_SHUT_DOWN);
+ }
+
+ /**
+ * Creates a management client using the given data.
+ *
+ * @param brokerId the broker identifier.
+ * @param data the broker connection data.
+ */
+ public void createManagementClient(UUID brokerId, BrokerConnectionData data)
+ {
+ try
+ {
+ ManagementClient client = new ManagementClient(brokerId,data);
+ client.estabilishFirstConnectionWithBroker();
+ managementClients.add(client);
+
+ LOGGER.info(Messages.QMAN_000004_MANAGEMENT_CLIENT_CONNECTED,brokerId);
+ } catch(StartupFailureException exception) {
+ LOGGER.error(exception, Messages.QMAN_100017_UNABLE_TO_CONNECT,brokerId,data);
+ }
+ }
+
+ /**
+ * Returns the list of management clients currently handled by QMan.
+ *
+ * @return the list of management clients currently handled by QMan.
+ */
+ public List<ManagementClient> getManagementClients()
+ {
+ return managementClients;
+ }
+
+ /**
+ * Injects the configurator on this QMan instance.
+ * That configutator later will be responsible to manage the configuration.
+ *
+ * @param configurator the configurator to be injected.
+ */
+ public void setConfigurator(Configurator configurator){
+ this._configurator = configurator;
+ }
+
+ /**
+ * Main method used for starting Q-Man.
+ *
+ * @param args the command line arguments.
+ */
+ public static void main (String[] args)
+ {
+ if (args.length == 1)
+ {
+ String logFileName = args[0];
+ DOMConfigurator.configureAndWatch(logFileName,5000);
+ }
+
+ final QMan qman = new QMan();
+
+ Thread hook = new Thread()
+ {
+ @Override
+ public void run ()
+ {
+ qman.stop();
+ }
+ };
+
+ Runtime.getRuntime().addShutdownHook(hook);
+ try
+ {
+ qman.start();
+
+ System.out.println("Type \"q\" to quit.");
+ BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
+ while ( !"q".equals(reader.readLine()) )
+ {
+
+ }
+ Runtime.getRuntime().removeShutdownHook(hook);
+ qman.stop();
+ System.exit(-1);
+ } catch (StartupFailureException exception)
+ {
+ qman.stop();
+ System.exit(-1);
+ } catch (IOException exception)
+ {
+ System.exit(-1);
+ }
+ }
+
+ /**
+ * Not implemented for this MBean.
+ */
+ public Object getAttribute(String attribute)
+ {
+ return null;
+ }
+
+ /**
+ * Not implemented for this MBean.
+ */
+ public AttributeList getAttributes(String[] attributes)
+ {
+ return null;
+ }
+
+ /**
+ * Returns the metadata for this MBean
+ *
+ * @return the metadata for this MBean
+ */
+ public MBeanInfo getMBeanInfo()
+ {
+ MBeanParameterInfo parameters [] = new MBeanParameterInfo[8];
+
+ parameters[0] = new MBeanParameterInfo(
+ "host",
+ String.class.getName(),
+ "The IP address or DNS name that Qpid Broker uses to listen for incoming connections.");
+ parameters[1] = new MBeanParameterInfo(
+ "port",
+ int.class.getName(),
+ "The port number that Qpid Broker uses to listen for incoming connections.");
+ parameters[2] = new MBeanParameterInfo(
+ "username",
+ String.class.getName(),
+ "The Qpid account name used in the physical connection.");
+ parameters[3] = new MBeanParameterInfo(
+ "password",
+ String.class.getName(),
+ "The Qpid account password used in the physical connection.");
+ parameters[4]= new MBeanParameterInfo(
+ "virtualHost",
+ String.class.getName(),
+ "The virtualHost name.");
+ parameters[5]= new MBeanParameterInfo(
+ "initialPoolCapacity",
+ int.class.getName(),
+ "The number of physical connections (between 0 and a positive 32-bit integer) to create when creating the (Qpid) connection pool.");
+ parameters[6]= new MBeanParameterInfo(
+ "maxPoolCapacity",
+ int.class.getName(),
+ "The maximum number of physical database connections (between 0 and a positive 32-bit integer) that the (Qpid) connection pool can contain. ");
+ parameters[7]= new MBeanParameterInfo(
+ "maxWaitTimeout",
+ long.class.getName(),
+ "The maximum amount of time to wait for an idle connection.A value of -1 indicates an illimted amount of time (i.e. forever)");
+
+ MBeanOperationInfo operation = new MBeanOperationInfo(
+ "addBroker",
+ "Connects QMan with a broker.",
+ parameters,
+ void.class.getName(),
+ MBeanOperationInfo.ACTION);
+
+ MBeanInfo mbean = new MBeanInfo(
+ QMan.class.getName(),
+ "QMan Management & Administration interface.",
+ null,
+ null,
+ new MBeanOperationInfo[]{operation},
+ null);
+
+ return mbean;
+ }
+
+ /**
+ * Invokes an operation on QMan (MBean).
+ *
+ * @param actionName the operation name.
+ * @param params the operation parameters.
+ * @param signature the operation signature.
+ * @return the result of the invocation (if the operation is not void);
+ * @exception MBeanException Wraps a <CODE>java.lang.Exception</CODE> thrown by the MBean's invoked method.
+ * @exception ReflectionException Wraps a <CODE>java.lang.Exception</CODE> thrown while trying to invoke the method
+ */
+ public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException
+ {
+ if (Names.ADD_BROKER_OPERATION_NAME.equals(actionName))
+ {
+ try
+ {
+ addBroker(
+ (String)params[0],
+ (Integer)params[1],
+ (String)params[2],
+ (String)params[3],
+ (String)params[4],
+ (Integer)params[5],
+ (Integer)params[6],
+ (Long)params[7]);
+ } catch(Exception exception)
+ {
+ throw new MBeanException(exception);
+ }
+ } else
+ {
+ throw new ReflectionException(new NoSuchMethodException(actionName));
+ }
+ return null;
+ }
+
+ /**
+ * Not implemented for this MBean.
+ */
+ public void setAttribute(Attribute attribute)
+ {
+ }
+
+ /**
+ * Not implemented for this MBean.
+ */
+ public AttributeList setAttributes(AttributeList attributes)
+ {
+ return null;
+ }
+
+ /**
+ * Simply dispatches the incoming notification to registered listeners.
+ * Consider that the notification is sent asynchronously so the QMan current thread is not
+ * waiting for completion of receiver task.
+ *
+ * @param notification the incoming notification.
+ * @param handback the context associated to this notification.
+ */
+ public void handleNotification(final Notification notification, Object handback)
+ {
+ _workManager.execute(new Runnable(){
+ public void run()
+ {
+ sendNotification(notification);
+ }
+ });
+ }
+
+ /**
+ * Registers QMan as an MBean on MBeanServer.
+ *
+ * @throws MBeanException when it's not possible to proceeed with registration.
+ */
+ private void registerQManService() throws MBeanException
+ {
+ JmxService service = new JmxService();
+ service.registerQManService(this);
+
+ LOGGER.info(Messages.QMAN_000023_QMAN_REGISTERED_AS_MBEAN);
+ }
+
+ /**
+ * Configures work manager component.
+ */
+ private void configureWorkManager()
+ {
+ Configuration configuration = Configuration.getInstance();
+ _workManager = new ThreadPoolExecutor(
+ configuration.getWorkerManagerPoolSize(),
+ configuration.getWorkerManagerMaxPoolSize(),
+ configuration.getWorkerManagerKeepAliveTime(),
+ TimeUnit.MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(30));
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/services/QpidService.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/services/QpidService.java
new file mode 100644
index 0000000000..ee41beaf50
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/services/QpidService.java
@@ -0,0 +1,362 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.services;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.qpid.QpidException;
+import org.apache.qpid.api.Message;
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.configuration.QpidDatasource;
+import org.apache.qpid.management.domain.model.QpidMethod;
+import org.apache.qpid.management.domain.model.type.Binary;
+import org.apache.qpid.management.messages.MethodInvocationRequestMessage;
+import org.apache.qpid.management.messages.SchemaRequestMessage;
+import org.apache.qpid.nclient.util.MessageListener;
+import org.apache.qpid.nclient.util.MessagePartListenerAdapter;
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.MessageAcceptMode;
+import org.apache.qpid.transport.MessageAcquireMode;
+import org.apache.qpid.transport.MessageCreditUnit;
+import org.apache.qpid.transport.MessageTransfer;
+import org.apache.qpid.transport.Option;
+import org.apache.qpid.transport.Session;
+import org.apache.qpid.transport.SessionException;
+import org.apache.qpid.transport.SessionListener;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * Qpid Broker facade.
+ *
+ * @author Andrea Gazzarini
+ */
+public class QpidService implements SessionListener
+{
+ private final static Logger LOGGER = Logger.get(QpidService.class);
+
+ private UUID _brokerId;
+ private Connection _connection;
+ private Session _session;
+ private Map<String,MessagePartListenerAdapter> _listeners;
+
+ /**
+ * Builds a new service with the given connection data.
+ *
+ * @param connectionData the connection data of the broker.
+ */
+ public QpidService(UUID brokerId)
+ {
+ this._brokerId = brokerId;
+ }
+
+ /**
+ * Estabilishes a connection with the broker.
+ *
+ * @throws QpidException in case of connection failure.
+ */
+ public void connect() throws Exception
+ {
+ _connection = QpidDatasource.getInstance().getConnection(_brokerId);
+ _listeners = new ConcurrentHashMap<String,MessagePartListenerAdapter>();
+ _session = _connection.createSession(0);
+ _session.setSessionListener(this);
+ }
+
+ public void opened(Session ssn) {}
+
+ public void resumed(Session ssn) {}
+
+ public void message(Session ssn, MessageTransfer xfr)
+ {
+ MessagePartListenerAdapter l = _listeners.get(xfr.getDestination());
+ if (l == null)
+ {
+ LOGGER.error("unhandled message: %s", xfr);
+ }
+ else
+ {
+ l.messageTransfer(xfr);
+ }
+ }
+
+
+ public void exception(Session ssn, SessionException exc)
+ {
+
+ }
+
+ public void closed(Session ssn) {}
+
+ /**
+ * All the previously entered outstanding commands are asynchronous.
+ * Synchronous behavior is achieved through invoking this method.
+ */
+ public void sync()
+ {
+ _session.sync();
+ }
+
+ /**
+ * Closes communication with broker.
+ */
+ public void close()
+ {
+ try
+ {
+ _session.close();
+ _session = null;
+ _listeners = null;
+ } catch (Exception e)
+ {
+ }
+ try
+ {
+ _connection.close();
+ _connection = null;
+ } catch (Exception e)
+ {
+ }
+ }
+
+ /**
+ * Associate a message listener with a destination therefore creating a new subscription.
+ *
+ * @param queueName The name of the queue that the subscriber is receiving messages from.
+ * @param destinationName the name of the destination, or delivery tag, for the subscriber.
+ * @param listener the listener for this destination.
+ *
+ * @see Session#messageSubscribe(String, String, short, short, org.apache.qpid.nclient.MessagePartListener, java.util.Map, org.apache.qpid.transport.Option...)
+ */
+ public void createSubscription(String queueName, String destinationName, MessageListener listener)
+ {
+ _listeners.put(destinationName, new MessagePartListenerAdapter(listener));
+ _session.messageSubscribe
+ (queueName,
+ destinationName,
+ MessageAcceptMode.NONE,
+ MessageAcquireMode.PRE_ACQUIRED,
+ null, 0, null);
+
+ _session.messageFlow(destinationName, MessageCreditUnit.BYTE, Session.UNLIMITED_CREDIT);
+ _session.messageFlow(destinationName, MessageCreditUnit.MESSAGE, Session.UNLIMITED_CREDIT);
+
+ LOGGER.debug(Messages.QMAN_200025_SUBSCRIPTION_DECLARED,queueName,destinationName);
+ }
+
+ /**
+ * Removes a previously declared consumer from the broker.
+ *
+ * @param destinationName the name of the destination, or delivery tag, for the subscriber.
+ * @see Session#messageCancel(String, Option...)
+ */
+ public void removeSubscription(String destinationName)
+ {
+ _session.messageCancel(destinationName);
+ LOGGER.debug(Messages.QMAN_200026_SUBSCRIPTION_REMOVED,destinationName);
+ }
+
+ /**
+ * Declares a queue on the broker with the given name.
+ *
+ * @param queueName the name of the declared queue.
+ * @see Session#queueDeclare(String, String, java.util.Map, Option...)
+ */
+ public void declareQueue(String queueName)
+ {
+ _session.queueDeclare(queueName, null, null);
+ LOGGER.debug(Messages.QMAN_200027_QUEUE_DECLARED,queueName);
+ }
+
+ /**
+ * Removes the queue with the given name from the broker.
+ *
+ * @param queueName the name of the queue.
+ * @see Session#queueDelete(String, Option...)
+ */
+ public void deleteQueue(String queueName)
+ {
+ _session.queueDelete(queueName);
+ LOGGER.debug(Messages.QMAN_200028_QUEUE_REMOVED,queueName);
+ }
+
+ /**
+ * Binds (on the broker) a queue with an exchange.
+ *
+ * @param queueName the name of the queue to bind.
+ * @param exchangeName the exchange name.
+ * @param routingKey the routing key used for the binding.
+ * @see Session#exchangeBind(String, String, String, java.util.Map, Option...)
+ */
+ public void declareBinding(String queueName, String exchangeName, String routingKey)
+ {
+ _session.exchangeBind(queueName, exchangeName, routingKey, null);
+ LOGGER.debug(Messages.QMAN_200029_BINDING_DECLARED,routingKey,queueName,exchangeName);
+ }
+
+ /**
+ * Removes a previously declare binding between an exchange and a queue.
+ *
+ * @param queueName the name of the queue.
+ * @param exchangeName the name of the exchange.
+ * @param routingKey the routing key used for binding.
+ */
+ public void declareUnbinding(String queueName, String exchangeName, String routingKey)
+ {
+ _session.exchangeUnbind(queueName, exchangeName, routingKey);
+ LOGGER.debug(Messages.QMAN_200030_BINDING_REMOVED,routingKey,queueName,exchangeName);
+ }
+
+ /**
+ * Sends a command message with the given data on the management queue.
+ *
+ * @param messageData the command message content.
+ */
+
+ /**
+ * Requests a schema for the given package.class.hash.
+ *
+ * @param packageName the package name.
+ * @param className the class name.
+ * @param schemaHash the schema hash.
+ * @throws IOException when the schema request cannot be sent.
+ */
+ public void requestSchema(final String packageName, final String className, final Binary schemaHash) throws IOException
+ {
+ Message message = new SchemaRequestMessage()
+ {
+ @Override
+ protected String className ()
+ {
+ return className;
+ }
+
+ @Override
+ protected String packageName ()
+ {
+ return packageName;
+ }
+
+ @Override
+ protected Binary schemaHash ()
+ {
+ return schemaHash;
+ }
+ };
+
+ sendMessage(message);
+ }
+
+ /**
+ * Invokes an operation on a broker object instance.
+ *
+ * @param packageName the package name.
+ * @param className the class name.
+ * @param schemaHash the schema hash of the corresponding class.
+ * @param objectId the object instance identifier.
+ * @param parameters the parameters for this invocation.
+ * @param method the method (definition) invoked.
+ * @param bankId the object bank identifier.
+ * @param brokerId the broker identifier.
+ * @return the sequence number used for this message.
+ * @throws MethodInvocationException when the invoked method returns an error code.
+ * @throws UnableToComplyException when it wasn't possibile to invoke the requested operation.
+ */
+ public void invoke(
+ final String packageName,
+ final String className,
+ final Binary schemaHash,
+ final Binary objectId,
+ final Object[] parameters,
+ final QpidMethod method,
+ final int sequenceNumber,
+ final long bankId,
+ final long brokerId) throws MethodInvocationException, UnableToComplyException
+ {
+ Message message = new MethodInvocationRequestMessage(bankId, brokerId)
+ {
+
+ @Override
+ protected int sequenceNumber ()
+ {
+ return sequenceNumber;
+ }
+
+ protected Binary objectId() {
+ return objectId;
+ }
+
+ protected String packageName()
+ {
+ return packageName;
+ }
+
+ protected String className()
+ {
+ return className;
+ }
+
+ @Override
+ protected QpidMethod method ()
+ {
+ return method;
+ }
+
+ @Override
+ protected Object[] parameters ()
+ {
+ return parameters;
+ }
+
+ @Override
+ protected Binary schemaHash ()
+ {
+ return schemaHash;
+ }
+ };
+
+ try {
+ sendMessage(message);
+ sync();
+ } catch(Exception exception) {
+ throw new UnableToComplyException(exception);
+ }
+ }
+
+ /**
+ * Sends a command message.
+ *
+ * @param message the command message.
+ * @throws IOException when the message cannot be sent.
+ */
+ public void sendMessage(Message message) throws IOException
+ {
+ _session.messageTransfer(
+ Names.MANAGEMENT_EXCHANGE,
+ MessageAcceptMode.EXPLICIT,
+ MessageAcquireMode.PRE_ACQUIRED,
+ message.getHeader(),
+ message.readData());
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/services/SequenceNumberGenerator.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/services/SequenceNumberGenerator.java
new file mode 100644
index 0000000000..e6d99971cd
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/services/SequenceNumberGenerator.java
@@ -0,0 +1,41 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.services;
+
+/**
+ * Sequence number generator utility class.
+ *
+ * @author Andrea Gazzarini
+ */
+public class SequenceNumberGenerator
+{
+ private static int sequenceNumber;
+
+ /**
+ * Returns a valid sequence number.
+ *
+ * @return a sequence number.
+ */
+ public static synchronized int getNextSequenceNumber()
+ {
+ return sequenceNumber++;
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/services/StartupFailureException.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/services/StartupFailureException.java
new file mode 100644
index 0000000000..9da8832624
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/services/StartupFailureException.java
@@ -0,0 +1,42 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.services;
+
+/**
+ * Thrown in case of service startup failure.
+ * For example the configuration file couldn't be read because is not well-formed.
+ *
+ * @author Andrea Gazzarini.
+ */
+public class StartupFailureException extends Exception
+{
+ private static final long serialVersionUID = -4102037574602857703L;
+
+ /**
+ * Builds a new StartupFailureException with the given exception.
+ *
+ * @param exception the exception cause.
+ */
+ public StartupFailureException(Exception exception)
+ {
+ super(exception);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/domain/services/UnableToComplyException.java b/java/management/client/src/main/java/org/apache/qpid/management/domain/services/UnableToComplyException.java
new file mode 100644
index 0000000000..2ab9a41e75
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/domain/services/UnableToComplyException.java
@@ -0,0 +1,31 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.services;
+
+public class UnableToComplyException extends Exception
+{
+ public UnableToComplyException(Exception exception)
+ {
+ super(exception);
+ }
+
+ private static final long serialVersionUID = -3071434478559509435L;
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/jmx/EntityLifecycleNotification.java b/java/management/client/src/main/java/org/apache/qpid/management/jmx/EntityLifecycleNotification.java
new file mode 100644
index 0000000000..d7f9d8d6f0
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/jmx/EntityLifecycleNotification.java
@@ -0,0 +1,147 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.jmx;
+
+import javax.management.Notification;
+import javax.management.ObjectName;
+
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.domain.services.SequenceNumberGenerator;
+
+/**
+ * Q-Man JMX entity lifecycle notification.
+ * A notification is sent to interested listener by Q-Man on the following scenarios :
+ *
+ * <br> - A schema (class / event) has been requested (Schema request);
+ * <br> - A schema (class / event) has been injected (Schema response);
+ * <br> - A schema cannot be parsed (probably it is malformed);
+ * <br> - An object instance has been created (Instrumentation / Configuration response);
+ * <br> - An event instance has been created (Instrumentation / Configuration response);
+ * <br> - An object instance has been removed (Instrumentation / Configuration response);
+ *
+ * @author Andrea Gazzarini
+ */
+public class EntityLifecycleNotification extends Notification
+{
+ private static final long serialVersionUID = -7755773156742412161L;
+
+ public static final String SCHEMA_INJECTED_NOTIFICATION_TYPE = "org.apache.qpid.management.lifecycle.entity.schema.injected";
+ public static final String SCHEMA_REQUESTED_NOTIFICATION_TYPE = "org.apache.qpid.management.lifecycle.entity.schema.requested";
+ public static final String MALFORMED_SCHEMA_NOTIFICATION_TYPE = "org.apache.qpid.management.lifecycle.error.schema";
+
+ public static final String INSTANCE_ADDED_NOTIFICATION_TYPE = "qman.lifecycle.entity.instance.created";
+ public static final String INSTANCE_REMOVED_NOTIFICATION_TYPE = "qman.lifecycle.entity.instance.removed";
+
+ private String _packageName = Names.NOT_AVAILABLE;
+ private String _className = Names.NOT_AVAILABLE;
+ private String _classKind = Names.NOT_AVAILABLE;
+
+ private ObjectName _objectName;
+
+ /**
+ * Builds a new notification with the given parameters.
+ *
+ * @param type the notification type.
+ * @param sequenceNumber the sequence number.
+ * @param packageName the package name.
+ * @param className the class name.
+ * @param classKind the class kind (i.e. class or event)
+ * @param objectName the object name of the affected mbean.
+ */
+ public EntityLifecycleNotification(
+ String type,
+ String packageName,
+ String className,
+ String classKind,
+ ObjectName objectName)
+ {
+ super(
+ type,
+ Names.APPLICATION_NAME,
+ SequenceNumberGenerator.getNextSequenceNumber());
+
+ this._className = className;
+ this._packageName = packageName;
+ this._classKind = classKind;
+ this._objectName = objectName;
+ }
+
+ /**
+ * Returns the package name of object contained in this notification.
+ *
+ * @return the package name of object contained in this notification.
+ */
+ public String getPackageName()
+ {
+ return _packageName;
+ }
+
+ /**
+ * Returns the class name of object contained in this notification.
+ *
+ * @return the class name of object contained in this notification.
+ */
+ public String getClassName()
+ {
+ return _className;
+ }
+
+ /**
+ * Returns the class kind of object contained in this notification.
+ *
+ * @return the class kind of object contained in this notification.
+ * @see Names#CLASS
+ * @see Names#EVENT
+ */
+ public String getClassKind()
+ {
+ return _classKind;
+ }
+
+ /**
+ * Returns the object name of object contained in this notification.
+ *
+ * @return the object name of object contained in this notification.
+ */
+ public ObjectName getObjectName()
+ {
+ return _objectName;
+ }
+
+ /**
+ * Returns a string representation of this notification.
+ *
+ * @return a string representation of this notification.
+ */
+ @Override
+ public String toString()
+ {
+ return new StringBuilder()
+ .append(getType())
+ .append(':')
+ .append(_packageName)
+ .append('.')
+ .append(_className)
+ .append('@')
+ .append(_objectName)
+ .toString();
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/jmx/OperationHasBeenInvokedNotification.java b/java/management/client/src/main/java/org/apache/qpid/management/jmx/OperationHasBeenInvokedNotification.java
new file mode 100644
index 0000000000..dec29c1b93
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/jmx/OperationHasBeenInvokedNotification.java
@@ -0,0 +1,168 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.jmx;
+
+import javax.management.Notification;
+
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.domain.handler.impl.InvocationResult;
+import org.apache.qpid.management.domain.services.SequenceNumberGenerator;
+
+/**
+ * Q-Man JMX method invocation notification.
+ * This kind of notification is sent to interested listener by Q-Man when
+ * a method has been invoked (Method invocation request)
+ *
+ * @author Andrea Gazzarini
+ */
+public class OperationHasBeenInvokedNotification extends Notification
+{
+ private static final long serialVersionUID = -7755773156742412161L;
+ public static final String NOTIFICATION_TYPE = "org.apache.qpid.management.operation.invoked";
+
+ private final String _operationName;
+ private final Object [] _parameters;
+ private final String [] _signature;
+ private final Exception _exception;
+ private final InvocationResult _result;
+
+ /**
+ * Builds a new notification with the given parameters.
+ *
+ * @param type the notification type.
+ * @param operationName the operation name.
+ * @param params the operation parameters.
+ * @param signature the operation signature.
+ * @param exception the exception raised by the invocation.
+ */
+ public OperationHasBeenInvokedNotification(
+ String operationName,
+ Object[] parameters,
+ String [] signature,
+ Exception exception)
+ {
+ super(
+ NOTIFICATION_TYPE,
+ Names.APPLICATION_NAME,
+ SequenceNumberGenerator.getNextSequenceNumber());
+
+ this._operationName= operationName;
+ this._parameters = parameters;
+ this._signature = signature;
+ this._result = null;
+ this._exception = exception;
+ }
+
+ /**
+ * Builds a new notification with the given parameters.
+ *
+ * @param type the notification type.
+ * @param operationName the operation name.
+ * @param params the operation parameters.
+ * @param signature the operation signature.
+ * @param objectName the target mbean object name.
+ * @param result the invocation result.
+ */
+ public OperationHasBeenInvokedNotification(
+ String operationName,
+ Object[] parameters,
+ String [] signature,
+ InvocationResult result)
+ {
+ super(
+ NOTIFICATION_TYPE,
+ Names.APPLICATION_NAME,
+ SequenceNumberGenerator.getNextSequenceNumber());
+
+ this._operationName= operationName;
+ this._parameters = parameters;
+ this._signature = signature;
+ this._result = result;
+ this._exception = null;
+ }
+
+ /**
+ * Returns the exception raised by this notification
+ * referred operation.
+ *
+ * @return the exception raised by this notification referred operation.
+ */
+ public Exception getException()
+ {
+ return _exception;
+ }
+
+ /**
+ * Returns the exception raised by this notification
+ * referred operation.
+ *
+ * @return the exception raised by this notification referred operation.
+ */
+ public InvocationResult getResult()
+ {
+ return _result;
+ }
+
+ /**
+ * Returns the operation name.
+ *
+ * @return the operation name.
+ */
+ public String getOperationName()
+ {
+ return _operationName;
+ }
+
+ /**
+ * Returns the parameters used in method invocation.
+ *
+ * @return the parameters used in method invocation.
+ */
+ public Object [] getParameters()
+ {
+ return _parameters;
+ }
+
+ /**
+ * Returns the signature of the invoked operation.
+ *
+ * @return the signature of the invoked operation.
+ */
+ public String [] getSignature()
+ {
+ return _signature;
+ }
+
+ /**
+ * Returns a string representation of this notification.
+ *
+ * @return a string representation of this notification.
+ */
+ @Override
+ public String toString()
+ {
+ return new StringBuilder()
+ .append(getType())
+ .append(':')
+ .append(_operationName)
+ .toString();
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/messages/ManagementMessage.java b/java/management/client/src/main/java/org/apache/qpid/management/messages/ManagementMessage.java
new file mode 100644
index 0000000000..2fa20fb456
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/messages/ManagementMessage.java
@@ -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.
+ *
+ */
+package org.apache.qpid.management.messages;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import org.apache.qpid.api.Message;
+import org.apache.qpid.management.configuration.Configuration;
+import org.apache.qpid.management.domain.services.SequenceNumberGenerator;
+import org.apache.qpid.transport.DeliveryProperties;
+import org.apache.qpid.transport.Header;
+import org.apache.qpid.transport.MessageProperties;
+import org.apache.qpid.transport.codec.BBEncoder;
+
+/**
+ * Message implementation used for specific management purposes.
+ *
+ * @author Andrea Gazzarini
+ */
+public abstract class ManagementMessage implements Message
+{
+ /**
+ * Strategy interface for building / getting data.
+ *
+ * @author Andrea Gazzarini
+ */
+ private interface IDataBuilderStrategy
+ {
+ ByteBuffer getData();
+ };
+
+ /**
+ * Strategy used for retrieving raw data from this message when it has been already encoded.
+ */
+ IDataBuilderStrategy READING = new IDataBuilderStrategy()
+ {
+ public ByteBuffer getData() {
+ return _data;
+ };
+ };
+
+ /**
+ * Strategy used for retrieving raw data from this message when it hasn't been already encoded.
+ */
+ IDataBuilderStrategy ACCUMULATING = new IDataBuilderStrategy()
+ {
+ public ByteBuffer getData() {
+ _codec.writeInt8((byte)opcode());
+ _codec.writeSequenceNo(sequenceNumber());
+
+ specificMessageEncoding();
+
+ _data =_codec.segment();
+ _reader = READING;
+ return _data;
+ }
+ };
+
+ protected BBEncoder _codec;
+ protected ByteBuffer _data;
+ private int _messageTransferId;
+ private IDataBuilderStrategy _reader = ACCUMULATING;
+
+ /**
+ * Builds an empty management message.
+ */
+ ManagementMessage()
+ {
+ _codec = new BBEncoder(100);
+ _codec.writeMagicNumber();
+ }
+
+ /**
+ * Returns the sequence number that will be used for this message.
+ *
+ * @return the sequence number that will be used for this message.
+ */
+ protected int sequenceNumber ()
+ {
+ return SequenceNumberGenerator.getNextSequenceNumber();
+ }
+
+ /**
+ * Returns the opcode that will be used for this message.
+ *
+ * @return the opcode that will be used for this message.
+ */
+ abstract char opcode ();
+
+ /**
+ * Returns the delivery properties of this message.
+ *
+ * @return the delivery properties of this message.
+ */
+ public DeliveryProperties getDeliveryProperties ()
+ {
+ return Configuration.getInstance().getCommandDeliveryProperties();
+ }
+
+ /**
+ * Returns the header of this message.
+ *
+ * @return the header of this message.
+ */
+ public Header getHeader ()
+ {
+ return Configuration.getInstance().getCommandMessageHeader();
+ }
+
+ /**
+ * Returns the messages header properties of this message.
+ *
+ * @return the message header properties of this message.
+ */
+ public MessageProperties getMessageProperties ()
+ {
+ return Configuration.getInstance().getCommandMessageProperties();
+ }
+
+ /**
+ * Returns the transfer Id of this message.
+ *
+ * @return the transfer Id of this message.
+ */
+ public int getMessageTransferId ()
+ {
+ return _messageTransferId;
+ }
+
+ /**
+ * Returns the encoded data of this message.
+ *
+ * @return the encoded data of this message.
+ */
+ public ByteBuffer readData () throws IOException
+ {
+ return _reader.getData();
+ }
+
+ /**
+ * Sets the header for this message.
+ *
+ * @param header the new message header.
+ */
+ public void setHeader (Header header)
+ {
+ // N.A. at the moment.
+ }
+
+ public void appendData (byte[] src) throws IOException
+ {
+ }
+
+ public void appendData (ByteBuffer src) throws IOException
+ {
+ }
+
+ public void clearData ()
+ {
+ }
+
+ public void readData (byte[] target) throws IOException
+ {
+ }
+
+ /**
+ * Concrete subclasses (message implementations) must define here their specific data encoding.
+ */
+ abstract void specificMessageEncoding();
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/messages/MethodInvocationRequestMessage.java b/java/management/client/src/main/java/org/apache/qpid/management/messages/MethodInvocationRequestMessage.java
new file mode 100644
index 0000000000..99916085d6
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/messages/MethodInvocationRequestMessage.java
@@ -0,0 +1,161 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.messages;
+
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.Protocol;
+import org.apache.qpid.management.configuration.Configuration;
+import org.apache.qpid.management.domain.model.QpidMethod;
+import org.apache.qpid.management.domain.model.type.Binary;
+import org.apache.qpid.transport.DeliveryProperties;
+import org.apache.qpid.transport.Header;
+import org.apache.qpid.transport.MessageProperties;
+import org.apache.qpid.transport.ReplyTo;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * Abstract representation of a method invocation request message.
+ * Concrete subclasses must supply the values needed to build & encode the message.
+ *
+ * @author Andrea Gazzarini
+ */
+public abstract class MethodInvocationRequestMessage extends ManagementMessage
+{
+ private final static Logger LOGGER = Logger.get(MethodInvocationRequestMessage.class);
+
+ private DeliveryProperties _deliveryProperties;
+ private MessageProperties _messageProperties;
+ private Header _header;
+
+ /**
+ * Builds a new method invocation request message with the given target identifiers.
+ *
+ * @param bankId the bank identifier.
+ * @param brokerId the broker identifier.
+ */
+ public MethodInvocationRequestMessage(long bankId, long brokerId)
+ {
+ ReplyTo replyTo=new ReplyTo();
+ replyTo.setRoutingKey(Configuration.getInstance().getMethodReplyQueueName());
+ _messageProperties = new MessageProperties();
+ _messageProperties.setReplyTo(replyTo);
+
+ String routingKey = String.format(Names.AGENT_ROUTING_KEY_PREFIX+"%s.%s", brokerId,bankId);
+
+ LOGGER.debug(Messages.QMAN_200032_COMMAND_MESSAGE_ROUTING_KEY, routingKey);
+
+ _deliveryProperties = new DeliveryProperties();
+ _deliveryProperties.setRoutingKey(routingKey);
+ _header = new Header(_deliveryProperties, _messageProperties);
+ }
+
+ @Override
+ char opcode ()
+ {
+ return Protocol.OPERATION_INVOCATION_REQUEST_OPCODE;
+ }
+
+ /**
+ * Returns the package name.
+ *
+ * @return the package name.
+ */
+ protected abstract String packageName();
+
+ /**
+ * Returns the class name.
+ *
+ * @return the class name.
+ */
+ protected abstract String className();
+
+ /**
+ * Returns the schema hash.
+ *
+ * @return the schema hash.
+ */
+ protected abstract Binary schemaHash();
+
+ /**
+ * Returns the object identifier.
+ *
+ * @return the object identifier.
+ */
+ protected abstract Binary objectId();
+
+ /**
+ * Returns the method to be invoked.
+ *
+ * @return the method to be invoked.
+ */
+ protected abstract QpidMethod method();
+
+ /**
+ * Returns the parameters used for method invocation.
+ *
+ * @return the parameters used for method invocation.
+ */
+ protected abstract Object[] parameters();
+
+ /**
+ * Returns the delivery properties of this message.
+ *
+ * @return the delivery properties of this message.
+ */
+ public DeliveryProperties getDeliveryProperties ()
+ {
+ return _deliveryProperties;
+ }
+
+ /**
+ * Returns the header of this message.
+ *
+ * @return the header of this message.
+ */
+ public Header getHeader ()
+ {
+ return _header;
+ }
+
+ /**
+ * Returns the messages header properties of this message.
+ *
+ * @return the message header properties of this message.
+ */
+ public MessageProperties getMessageProperties ()
+ {
+ return _messageProperties;
+ }
+
+ @Override
+ void specificMessageEncoding ()
+ {
+ objectId().encode(_codec);
+ _codec.writeStr8(packageName());
+ _codec.writeStr8(className());
+ schemaHash().encode(_codec);
+
+ QpidMethod method = method();
+ _codec.writeStr8(method.getName());
+ method.encodeParameters(parameters(), _codec);
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/messages/SchemaRequestMessage.java b/java/management/client/src/main/java/org/apache/qpid/management/messages/SchemaRequestMessage.java
new file mode 100644
index 0000000000..9df1733649
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/messages/SchemaRequestMessage.java
@@ -0,0 +1,68 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.messages;
+
+import org.apache.qpid.management.Protocol;
+import org.apache.qpid.management.domain.model.type.Binary;
+
+/**
+ * Abstract representation of a schema request message.
+ * Concrete subclasses must supply the values needed to build & encode the message.
+ *
+ * @author Andrea Gazzarini
+ */
+public abstract class SchemaRequestMessage extends ManagementMessage
+{
+ @Override
+ char opcode ()
+ {
+ return Protocol.SCHEMA_REQUEST_OPCODE;
+ }
+
+ /**
+ * Returns the package name.
+ *
+ * @return the package name.
+ */
+ protected abstract String packageName();
+
+ /**
+ * Returns the class name.
+ *
+ * @return the class name.
+ */
+ protected abstract String className();
+
+ /**
+ * Returns the schema hash.
+ *
+ * @return the schema hash.
+ */
+ protected abstract Binary schemaHash();
+
+ @Override
+ final void specificMessageEncoding ()
+ {
+ _codec.writeStr8(packageName());
+ _codec.writeStr8(className());
+ schemaHash().encode(_codec);
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/servlet/ConnectQManToBroker.java b/java/management/client/src/main/java/org/apache/qpid/management/servlet/ConnectQManToBroker.java
new file mode 100644
index 0000000000..8f73098e20
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/servlet/ConnectQManToBroker.java
@@ -0,0 +1,89 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.servlet;
+
+import java.util.UUID;
+import java.util.Map.Entry;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.muse.core.platform.mini.MiniServlet;
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.configuration.BrokerConnectionData;
+import org.apache.qpid.management.configuration.Configuration;
+import org.apache.qpid.management.domain.services.QMan;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * When QMan is started and a configuration file is given
+ * (via system property) with initial broker connection data(s),
+ * this servlet simply sends connect command(s) to QMan in order
+ * to estabilish the connection(s) to the requested broker(s).
+ *
+ * @author Andrea Gazzarini
+ */
+public class ConnectQManToBroker extends MiniServlet
+{
+ private static final long serialVersionUID = 6149614872902682208L;
+ private final static Logger LOGGER = Logger.get(ConnectQManToBroker.class);
+
+ /**
+ * Send one or more initial "connect" command(s) to QMan in order
+ * to estabilish a connection with broker found on the configuration file..
+ * Note that this is done only if that configuration file is given (via system
+ * property) and it is valid.
+ */
+ public void init()
+ {
+ Configuration configuration = Configuration.getInstance();
+ if (configuration.hasOneOrMoreBrokersDefined())
+ {
+ QMan qman = (QMan)getServletContext().getAttribute(Names.APPLICATION_NAME);
+
+ LOGGER.info(Messages.QMAN_000003_CREATING_MANAGEMENT_CLIENTS);
+ for (Entry<UUID, BrokerConnectionData> entry : Configuration.getInstance().getConnectionInfos())
+ {
+ qman.createManagementClient(entry.getKey(), entry.getValue());
+ }
+ } else
+ {
+ LOGGER.info(Messages.QMAN_000022_NO_BROKER_CONFIGURED);
+ }
+ }
+
+ /**
+ * This is a startup module only so an override of the default servlet
+ * behaviour must be done in order to prevent incoming http
+ * requests processing.
+ *
+ * @param request the http request.
+ * @param response the http response.
+ * @throws ServletException each time this method is called.
+ */
+ @Override
+ public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException
+ {
+ throw new ServletException();
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/servlet/QManLifeCycleManager.java b/java/management/client/src/main/java/org/apache/qpid/management/servlet/QManLifeCycleManager.java
new file mode 100644
index 0000000000..edd6804e68
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/servlet/QManLifeCycleManager.java
@@ -0,0 +1,79 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.servlet;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.domain.services.QMan;
+import org.apache.qpid.management.domain.services.StartupFailureException;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * QMan JMX lifecycle manager.
+ * Provides lifecycle management of QMan JMX core including startup and shutdown.
+ *
+ * @author Andrea Gazzarini
+ */
+public class QManLifeCycleManager implements ServletContextListener
+{
+ private final static Logger LOGGER = Logger.get(QManLifeCycleManager.class);
+
+ /**
+ * Starts QMan JMX Core.
+ *
+ * @param event the application context event.
+ */
+ public void contextInitialized(ServletContextEvent event)
+ {
+ try
+ {
+ QMan qman = new QMan();
+ qman.start();
+ event.getServletContext().setAttribute(
+ Names.APPLICATION_NAME,
+ qman);
+ } catch (StartupFailureException exception)
+ {
+ LOGGER.error(
+ exception,
+ Messages.QMAN_100030_JMX_CORE_STARTUP_FAILURE);
+ }
+ }
+
+ /**
+ * Sutdown QMan JMX Core.
+ *
+ * @param event the application context event.
+ */
+ public void contextDestroyed(ServletContextEvent event)
+ {
+ ServletContext context = event.getServletContext();
+
+ QMan qman = (QMan) context.getAttribute(Names.APPLICATION_NAME);
+ qman.stop();
+
+ context.removeAttribute(Names.APPLICATION_NAME);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/servlet/WSDMAdapter.java b/java/management/client/src/main/java/org/apache/qpid/management/servlet/WSDMAdapter.java
new file mode 100644
index 0000000000..c6fcde08c4
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/servlet/WSDMAdapter.java
@@ -0,0 +1,109 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.servlet;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.wsdm.muse.engine.WSDMAdapterIsolationLayer;
+import org.apache.qpid.qman.debug.XmlDebugger;
+import org.apache.qpid.transport.util.Logger;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+/**
+ * QMan Adapter facade.
+ * This is the main requestor entry point of the WS-DM connector / adapter.
+ * All WSDM requests will be handled (at higher level) by this servlet.
+ *
+ * @author Andrea Gazzarini
+ */
+public class WSDMAdapter extends HttpServlet
+{
+ private static final long serialVersionUID = 6149614872902682208L;
+ private final static Logger LOGGER = Logger.get(WSDMAdapter.class);
+ private WSDMAdapterIsolationLayer _isolationLayer;
+
+ @Override
+ public void init() throws ServletException {
+ LOGGER.debug(Messages.QMAN_000026_WSDM_ADAPTER_STARTS);
+
+ _isolationLayer = new WSDMAdapterIsolationLayer(getServletContext());
+ _isolationLayer.initialize();
+
+ LOGGER.debug(Messages.QMAN_000027_WSDM_ADAPTER_STARTED);
+
+ }
+
+ /**
+ * Accepts http requests containing a soap envelope (request) and therefore
+ * acts as the main entry point of whole WS process.
+ *
+ * @param request the http request.
+ * @param response the http response.
+ * @throws ServletException in case of application failure.
+ * @throws IOException in case of generic I/O failure.
+ */
+ @Override
+ protected void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException
+ {
+ PrintWriter writer = response.getWriter();
+
+ Document soapEnvelopeRequest = null;
+ String soapEnvelopeResposeAsString = null;
+
+ try
+ {
+ soapEnvelopeRequest = XmlUtils.createDocument(request.getInputStream());
+
+ Document soapEnvelopeResponse = _isolationLayer.handleRequest(soapEnvelopeRequest);
+ soapEnvelopeResposeAsString = XmlUtils.toString(soapEnvelopeResponse,false,true);
+
+ response.setContentType("text/xml");
+
+ writer.write(soapEnvelopeResposeAsString);
+ } catch (SAXException exception)
+ {
+ LOGGER.error(
+ exception,
+ Messages.QMAN_100019_REQ_OR_RES_MALFORMED);
+ throw new ServletException(exception);
+ } finally {
+ writer.flush();
+
+ XmlDebugger.debug(soapEnvelopeRequest);
+ try {
+ XmlDebugger.debug(soapEnvelopeResposeAsString);
+ } catch(Exception exception) {
+ LOGGER.error(
+ exception,
+ Messages.QMAN_100019_REQ_OR_RES_MALFORMED);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/web/action/BrokerModel.java b/java/management/client/src/main/java/org/apache/qpid/management/web/action/BrokerModel.java
new file mode 100644
index 0000000000..09b7309b96
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/web/action/BrokerModel.java
@@ -0,0 +1,100 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.web.action;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.ObjectName;
+
+import org.apache.qpid.management.Names;
+
+/**
+ * Value Object encapsulating a broker management domain model.
+ *
+ * @author Andrea Gazzarini
+ */
+public class BrokerModel
+{
+ private Map<String, List<ObjectName>> _objectsByType = new HashMap<String, List<ObjectName>>();
+ private String _id;
+
+ /**
+ * Adds a new object to this domain model.
+ *
+ * @param name the object name of the JMX entity.
+ */
+ void addObject(ObjectName name)
+ {
+ String packageName = name.getKeyProperty(Names.PACKAGE);
+ String className = name.getKeyProperty(Names.CLASS);
+ if (className != null)
+ {
+ String fqn = packageName+"."+className;
+
+ List<ObjectName> objects = _objectsByType.get(fqn);
+ if (objects == null)
+ {
+ objects = new ArrayList<ObjectName>();
+ _objectsByType.put(fqn,objects);
+ }
+ objects.add(name);
+ }
+ }
+
+ /**
+ * Gets the identifier of the owner of this model.
+ *
+ * @return the identifier of the owner of this model.
+ */
+ public String getId()
+ {
+ return _id;
+ }
+
+ /**
+ * Sets the identifier of the owner of this model.
+ *
+ * @param id the identifier of the owner of this model.
+ */
+ public void setId(String id)
+ {
+ this._id = id;
+ }
+
+ public Set<String> getCategoryNames()
+ {
+ return _objectsByType.keySet();
+ }
+
+ public List<ObjectName> getCategory(String name)
+ {
+ return _objectsByType.get(name);
+ }
+
+ public int getCategoryCount()
+ {
+ return _objectsByType.keySet().size();
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/web/action/BrokersManagementAction.java b/java/management/client/src/main/java/org/apache/qpid/management/web/action/BrokersManagementAction.java
new file mode 100644
index 0000000000..509c86c08b
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/web/action/BrokersManagementAction.java
@@ -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.
+ *
+ */
+package org.apache.qpid.management.web.action;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.configuration.BrokerAlreadyConnectedException;
+import org.apache.qpid.management.configuration.BrokerConnectionData;
+import org.apache.qpid.management.configuration.BrokerConnectionException;
+import org.apache.qpid.management.domain.services.ManagementClient;
+import org.apache.qpid.management.domain.services.QMan;
+
+/**
+ * This controller is responsible to :
+ *
+ * <ul>
+ * <li> prepare data for the page that is showing all connected brokers.</li>.
+ * </li> connect QMan with a broker on demand.
+ * </ul>
+ *
+ * @author Andrea Gazzarini
+ */
+public class BrokersManagementAction extends HttpServlet
+{
+ private static final long serialVersionUID = -2411413147821629363L;
+
+ /**
+ * Retrieves all connected brokers (their connection data) and prepare the model that
+ * is then forwarded to the appropriate view page.
+ *
+ * @param request the http request.
+ * @param response the http response.
+ * @throws ServletException in case of failure while forwarding to the view component.
+ * @throws IOException in case of failure while forwarding to the view component.
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ try
+ {
+ QMan qman = (QMan)getServletContext().getAttribute(Names.APPLICATION_NAME);
+ List<ManagementClient> managementClients = qman.getManagementClients();
+
+ List<BrokerConnectionData> brokers = new ArrayList<BrokerConnectionData>(managementClients.size());
+
+ if (!managementClients.isEmpty())
+ {
+ for (ManagementClient managementClient : managementClients)
+ {
+ brokers.add(managementClient.getBrokerConnectionData());
+ }
+ request.setAttribute("model", brokers);
+ }
+
+ RequestDispatcher dispatcher = request.getRequestDispatcher("/brokers_management.jsp");
+ dispatcher.forward(request,response);
+ } catch(Exception exception)
+ {
+ request.setAttribute("errorMessage","Unable to detect the exact cause Please look at the reported stack trace below.");
+ request.setAttribute("exception",exception);
+ RequestDispatcher dispatcher = request.getRequestDispatcher("/error_page.jsp");
+ dispatcher.forward(request,response);
+ }
+ }
+
+ /**
+ * Connects QMan with a new broker and forwards to
+ * the brokers list view page.
+ *
+ * @param request the http request.
+ * @param response the http response.
+ * @throws ServletException in case of failure while forwarding to the view component.
+ * @throws IOException in case of failure while forwarding to the view component.
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ try
+ {
+ QMan qman = (QMan)getServletContext().getAttribute(Names.APPLICATION_NAME);
+
+ String host = request.getParameter("host");
+ String portString = request.getParameter("port");
+ String virtualHost = request.getParameter("virtualHost");
+ String username = request.getParameter("username");
+ String password = request.getParameter("password");
+
+ String initialCapacityString = request.getParameter("initialCapacity");
+ String maxCapacityString = request.getParameter("maxCapacity");
+ String maxWaitTimeoutString = request.getParameter("maxWaitTimeout");
+
+ List<String> errors = new LinkedList<String>();
+ int port = 0;
+ int initialPoolCapacity = 0;
+ int maxPoolCapacity = 0;
+ long maxWaitTimeout = 0;
+
+ if(host== null || host.trim().length()==0)
+ {
+ errors.add("Invalid value for \"host\" attribute. Must be not null.");
+ }
+
+ if(virtualHost == null || virtualHost.trim().length()==0)
+ {
+ errors.add("Invalid value for \"virtualHost\" attribute. Must be not null.");
+ }
+
+ try
+ {
+ port = Integer.parseInt(portString);
+ } catch(Exception exception)
+ {
+ errors.add("Invalid value for \"port\" attribute. Must be not null and must be a number.");
+ }
+
+ try
+ {
+ initialPoolCapacity = Integer.parseInt(initialCapacityString);
+ } catch(Exception exception)
+ {
+ errors.add("Invalid value for \"Initial Pool Capacity\" attribute. Must be not null and must be a number.");
+ }
+
+ try
+ {
+ maxPoolCapacity = Integer.parseInt(maxCapacityString);
+ } catch(Exception exception)
+ {
+ errors.add("Invalid value for \"Max Pool Capacity\" attribute. Must be not null and must be a number.");
+ }
+
+ try
+ {
+ maxWaitTimeout = Long.parseLong(maxWaitTimeoutString);
+ } catch(Exception exception)
+ {
+ errors.add("Invalid value for \"Max Wait Timeout\" attribute. Must be not null and must be a number.");
+ }
+
+ request.setAttribute("errors", errors);
+
+ if (errors.isEmpty())
+ {
+ qman.addBroker(
+ host,
+ port,
+ username,
+ password,
+ virtualHost,
+ initialPoolCapacity,
+ maxPoolCapacity,
+ maxWaitTimeout);
+ }
+ doGet(request, response);
+ }catch(BrokerAlreadyConnectedException exception)
+ {
+ request.setAttribute("errorMessage","Supplied data refers to an already connected broker...");
+ RequestDispatcher dispatcher = request.getRequestDispatcher("/brokers_management.jsp");
+ dispatcher.forward(request,response);
+ }
+ catch(BrokerConnectionException exception)
+ {
+ request.setAttribute("errorMessage","Unable to connect with the requested broker...");
+ RequestDispatcher dispatcher = request.getRequestDispatcher("/brokers_management.jsp");
+ dispatcher.forward(request,response);
+ } catch(Exception exception)
+ {
+ request.setAttribute("errorMessage","Unable to detect the exact cause Please look at the reported stack trace below.");
+ request.setAttribute("exception",exception);
+ RequestDispatcher dispatcher = request.getRequestDispatcher("/error_page.jsp");
+ dispatcher.forward(request,response);
+ }
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/web/action/ConsoleAction.java b/java/management/client/src/main/java/org/apache/qpid/management/web/action/ConsoleAction.java
new file mode 100644
index 0000000000..ee098882f1
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/web/action/ConsoleAction.java
@@ -0,0 +1,117 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.web.action;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.lang.management.OperatingSystemMXBean;
+import java.lang.management.RuntimeMXBean;
+import java.util.Date;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * This action is the controller responsible to prepare data for the home
+ * page (System Overview) of QMan admin console.
+ *
+ * @author Andrea Gazzarini
+ */
+public class ConsoleAction extends HttpServlet
+{
+ private static final long serialVersionUID = -2411413147821629363L;
+
+ private static final Logger LOGGER = Logger.get(ConsoleAction.class);
+
+ private Date _startDate;
+
+ /**
+ * Initializes this controller.
+ * Simply it computes the start date of the application.
+ */
+ @Override
+ public void init()
+ {
+ _startDate = new Date();
+ }
+
+ /**
+ * Prepares data for System Overview admin console page and forward that data to that page.
+ *
+ * @throws ServletException when this controller is not able to forward to the appropriate view page.
+ * @throws IOException when this controller is not able to forward to the appropriate view page.
+ */
+ @Override
+ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ ConsoleModel model = new ConsoleModel();
+ model.setVersion("1.0");
+ model.setVersionName("Sofia");
+ model.setStartDate(_startDate);
+ model.setHost(System.getProperty(Names.ADAPTER_HOST_PROPERTY_NAME, "localhost"));
+ model.setPort(Integer.parseInt(System.getProperty(Names.ADAPTER_PORT_PROPERTY_NAME, "8080")));
+
+ try
+ {
+ OperatingSystemMXBean operatingSystem = ManagementFactory.getOperatingSystemMXBean();
+ model.setOsName(operatingSystem.getName());
+ model.setProcessors(operatingSystem.getAvailableProcessors());
+ model.setOsVersion(operatingSystem.getVersion());
+ model.setArchName(operatingSystem.getArch());
+ } catch(Exception exception)
+ {
+ LOGGER.warn(exception,Messages.QMAN_300006_OS_MBEAN_FAILURE);
+ model.setOsName("N.A.");
+ model.setProcessors(null);
+ model.setOsVersion("N.A.");
+ model.setArchName("N.A.");
+ }
+
+ try
+ {
+ RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
+
+ String bootClasspath = runtime.getBootClassPath();
+ model.setBootClasspath(bootClasspath.split(File.pathSeparator));
+
+ String classpath = runtime.getClassPath();
+ model.setClasspath(classpath.split(File.pathSeparator));
+
+ model.setInputArguments(runtime.getInputArguments().toArray(new String[]{}));
+ } catch(Exception exception)
+ {
+ LOGGER.warn(exception,Messages.QMAN_300007_RUNTIME_MBEAN_FAILURE);
+ }
+
+ request.setAttribute("model", model);
+
+ RequestDispatcher dispatcher = request.getRequestDispatcher("/console.jsp");
+ dispatcher.forward(request,response);
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/web/action/ConsoleModel.java b/java/management/client/src/main/java/org/apache/qpid/management/web/action/ConsoleModel.java
new file mode 100644
index 0000000000..ac0e1d2bbd
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/web/action/ConsoleModel.java
@@ -0,0 +1,158 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.web.action;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Console Model.
+ * It is a simple Data Transfer Object encapsulating all information about QMan
+ * console (System Overview)
+ *
+ * @author Andrea Gazzarini
+ */
+public class ConsoleModel implements Serializable
+{
+ private static final long serialVersionUID = -7676132151242738376L;
+ private String _version;
+ private String _versionName;
+ private Date _startDate;
+ private String _host;
+ private int _port;
+
+ private String _osName;
+ private String _osVersion;
+ private String _archName;
+ private Integer _processors;
+
+ private String [] _bootClasspath;
+ private String [] _classpath;
+ private String [] _inputArguments;
+ private String [] _systemProperties;
+
+ public String getVersion()
+ {
+ return _version;
+ }
+ public void setVersion(String version)
+ {
+ this._version = version;
+ }
+ public String getVersionName()
+ {
+ return _versionName;
+ }
+ public void setVersionName(String versionName)
+ {
+ this._versionName = versionName;
+ }
+ public Date getStartDate()
+ {
+ return _startDate;
+ }
+ public void setStartDate(Date startDate)
+ {
+ this._startDate = startDate;
+ }
+ public String getHost()
+ {
+ return _host;
+ }
+ public void setHost(String host)
+ {
+ this._host = host;
+ }
+ public int getPort()
+ {
+ return _port;
+ }
+ public void setPort(int port)
+ {
+ this._port = port;
+ }
+ public String getOsName()
+ {
+ return _osName;
+ }
+ public void setOsName(String osName)
+ {
+ this._osName = osName;
+ }
+ public String getOsVersion()
+ {
+ return _osVersion;
+ }
+ public void setOsVersion(String osVersion)
+ {
+ this._osVersion = osVersion;
+ }
+ public String getArchName()
+ {
+ return _archName;
+ }
+ public void setArchName(String archName)
+ {
+ this._archName = archName;
+ }
+ public Integer getProcessors()
+ {
+ return _processors;
+ }
+ public void setProcessors(Integer processors)
+ {
+ this._processors = processors;
+ }
+ public List<String> getBootClasspath()
+ {
+ return Arrays.asList(_bootClasspath);
+ }
+ public void setBootClasspath(String [] bootClasspath)
+ {
+ this._bootClasspath = bootClasspath;
+ }
+ public String [] getClasspath()
+ {
+ return _classpath;
+ }
+ public void setClasspath(String [] classpath)
+ {
+ this._classpath = classpath;
+ }
+ public String [] getInputArguments()
+ {
+ return _inputArguments;
+ }
+ public void setInputArguments(String [] inputArguments)
+ {
+ this._inputArguments = inputArguments;
+ }
+ public String [] getSystemProperties()
+ {
+ return _systemProperties;
+ }
+ public void setSystemProperties(String [] systemProperties)
+ {
+ this._systemProperties = systemProperties;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/web/action/JmxPerspectiveAction.java b/java/management/client/src/main/java/org/apache/qpid/management/web/action/JmxPerspectiveAction.java
new file mode 100644
index 0000000000..59777cc9c8
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/web/action/JmxPerspectiveAction.java
@@ -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.
+ *
+ */
+package org.apache.qpid.management.web.action;
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Map.Entry;
+
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * This controller is responsible to provide a jmx perspective of a specific resource.
+ * That means that this controller is querying the Platform MBean server in order to
+ * get metadata for the requested mbean.
+ *
+ * After that metadata will be forwarded to the appropriate view page and therefore
+ * will be shown on the Admin console.
+ *
+ * @author Andrea Gazzarini
+ */
+public class JmxPerspectiveAction extends HttpServlet
+{
+ private static final long serialVersionUID = -2411413147821629363L;
+
+ /**
+ * Adapter interface for converting objects on html strings.
+ *
+ * @author Andrea Gazzarini.
+ */
+ interface JavaToHtmlAdapter
+ {
+ /**
+ * Returns an HTML string representation of the given object.
+ *
+ * @param javaObject the object that needs to be converted.
+ * @return an html string containing value of the given object.
+ */
+ String toHtml(Object javaObject);
+ }
+
+ /**
+ * Adapter implementation for Map (and subclasses).
+ */
+ private JavaToHtmlAdapter mapAdapter = new JavaToHtmlAdapter()
+ {
+ @SuppressWarnings("unchecked")
+ public String toHtml(Object javaObject)
+ {
+ Map<String,Object> value = (Map<String, Object>) javaObject;
+
+ // Sanity check : if the map is empty or null there's no need to
+ // do any convertion
+ if (value == null || value.isEmpty())
+ {
+ return "(empty)";
+ }
+
+ StringBuilder builder = new StringBuilder("<ul>");
+ for (Entry<String, Object> entry : value.entrySet())
+ {
+ builder
+ .append("<li>")
+ .append(entry.getKey())
+ .append(" = ")
+ .append(entry.getValue());
+ }
+ builder.append("</ul>");
+ return builder.toString();
+ }
+ };
+
+ private Map<String, JavaToHtmlAdapter> _adapters = new HashMap<String, JavaToHtmlAdapter>();
+
+ @Override
+ public void init() throws ServletException
+ {
+ _adapters.put(Map.class.getName(), mapAdapter);
+ _adapters.put(HashMap.class.getName(),mapAdapter);
+ _adapters.put(Properties.class.getName(),mapAdapter);
+ _adapters.put(Hashtable.class.getName(),mapAdapter);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ String resourceId = null;
+ try
+ {
+ resourceId = request.getParameter("resourceId");
+
+ ObjectName objectName = new ObjectName(resourceId);
+ String [] keyProperties = objectName.getKeyPropertyListString().split(",");
+
+ MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+
+ MBeanInfo metadata = server.getMBeanInfo(objectName);
+
+ Map<String, String> attributes = getAttributes(server, objectName,metadata.getAttributes());
+
+ request.setAttribute("resourceId", objectName);
+ request.setAttribute("metadata",metadata);
+ request.setAttribute("nameAttributes",keyProperties);
+ request.setAttribute("attributes",attributes);
+
+ RequestDispatcher dispatcher = request.getRequestDispatcher("/jmx_perspective.jsp");
+ dispatcher.forward(request,response);
+ } catch(MalformedObjectNameException exception)
+ {
+ request.setAttribute("errorMessage","Malformed Resource ID : supplied value is "+resourceId);
+ request.setAttribute("exception",exception);
+ RequestDispatcher dispatcher = request.getRequestDispatcher("/error_page.jsp");
+ dispatcher.forward(request,response);
+
+ }
+ catch(Exception exception)
+ {
+ request.setAttribute("errorMessage","Unable to detect the exact cause Please look at the reported stack trace below.");
+ request.setAttribute("exception",exception);
+ RequestDispatcher dispatcher = request.getRequestDispatcher("/error_page.jsp");
+ dispatcher.forward(request,response);
+ }
+ }
+
+ /**
+ * Starting from an mbean metadata, this method retrieves all the attributes
+ * from the corresponding MBean Server.
+ *
+ * @param server the mbean server where the target mbean is registered.
+ * @param name the name of the target mbean.
+ * @param metadata the metadata of mbean.
+ * @return a map containing all attributes of the given mbean.
+ * @throws Exception when it's not possible to retrieve attributes.
+ */
+ private Map<String, String> getAttributes(MBeanServer server, ObjectName name, MBeanAttributeInfo [] metadata) throws Exception
+ {
+ Map<String,String> result = new HashMap<String, String>(metadata.length);
+ for (MBeanAttributeInfo attribute : metadata)
+ {
+ Object value = server.getAttribute(name, attribute.getName());
+ result.put(attribute.getName(),getAdaptedValue(attribute.getType(), value));
+ }
+ return result;
+ }
+
+ /**
+ * Converts the given attribute value in a html string format.
+ *
+ * @param type the java type of the given attribute value.
+ * @param value the attribute value.
+ * @return a html string format of the given value.
+ */
+ private String getAdaptedValue(String type, Object value)
+ {
+ JavaToHtmlAdapter adapter = _adapters.get(type);
+ return (adapter != null) ? adapter.toHtml(value) : String.valueOf(value);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/web/action/LoggingConfigurationAction.java b/java/management/client/src/main/java/org/apache/qpid/management/web/action/LoggingConfigurationAction.java
new file mode 100644
index 0000000000..aefd4ca8dd
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/web/action/LoggingConfigurationAction.java
@@ -0,0 +1,114 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.web.action;
+
+import java.io.IOException;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.qpid.qman.debug.WsdlDebugger;
+import org.apache.qpid.qman.debug.XmlDebugger;
+
+/**
+ * Logging configuration controller.
+ * Accepts input parameters from admin console and configure the underlying
+ * logging subsystem at runtime.
+ *
+ * @author Andrea Gazzarini
+ */
+public class LoggingConfigurationAction extends HttpServlet
+{
+ private static final long serialVersionUID = 633352305870632824L;
+
+ private final static String WSDL_DEBUG_ENABLED_PARAM = "wsdlDebugEnabled";
+ private final static String SOAP_DEBUG_ENABLED_PARAM = "soapDebugEnabled";
+ private final static String WEB_SERVER_LOG_LEVEL_PARAM = "webServerLogLevel";
+ private final static String QMAN_LOG_LEVEL_PARAM = "qmanLogLevel";
+
+ private final static String WEB_SERVER_PACKAGE = "org.mortbay";
+ private final static String QMAN_PACKAGE = "org.qpid.apache.management";
+
+ /**
+ * Retrieves current logging configuration and forward those data to the logging configuration view page.
+ * In this way that page will be able to display the current logging settings.
+ *
+ * @param request the http request.
+ * @param response the http response.
+ * @throws ServletException when this controller is not able to forward to the appropriate view page.
+ * @throws IOException when this controller is not able to forward to the appropriate view page.
+ */
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ Level messageDebuggerLogLevel = Logger.getLogger(XmlDebugger.class).getEffectiveLevel();
+ Level wsdlDebuggerLogLevel = Logger.getLogger(WsdlDebugger.class).getEffectiveLevel();
+ Level webServerLogLevel = Logger.getLogger(WEB_SERVER_PACKAGE).getEffectiveLevel();
+ Level qmanLogLevel = Logger.getLogger(QMAN_PACKAGE).getEffectiveLevel();
+
+ request.setAttribute(WSDL_DEBUG_ENABLED_PARAM,wsdlDebuggerLogLevel.equals(Level.DEBUG));
+ request.setAttribute(SOAP_DEBUG_ENABLED_PARAM,messageDebuggerLogLevel.equals(Level.DEBUG));
+ request.setAttribute(WEB_SERVER_LOG_LEVEL_PARAM,webServerLogLevel);
+ request.setAttribute(QMAN_LOG_LEVEL_PARAM,qmanLogLevel);
+
+ RequestDispatcher dispatcher = request.getRequestDispatcher("/logging_configuration.jsp");
+ dispatcher.forward(request, response);
+ }
+
+ /**
+ * Accepts user data coming from admin console and use it for configure the underlying logging
+ * subsystem.
+ *
+ * @param request the http request.
+ * @param response the http response.
+ * @throws ServletException when this controller is not able to forward to the appropriate view page.
+ * @throws IOException when this controller is not able to forward to the appropriate view page.
+ */
+ @Override
+ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ String wsdlDebugEnabled = request.getParameter(WSDL_DEBUG_ENABLED_PARAM);
+ String soapDebugEnabled = request.getParameter(SOAP_DEBUG_ENABLED_PARAM);
+
+ String qmanLevel = request.getParameter(QMAN_LOG_LEVEL_PARAM);
+ String serverLevel = request.getParameter(WEB_SERVER_LOG_LEVEL_PARAM);
+
+ Logger.getLogger(WEB_SERVER_PACKAGE).setLevel(Level.toLevel(serverLevel));
+ Logger.getLogger(QMAN_PACKAGE).setLevel(Level.toLevel(qmanLevel));
+
+ Logger.getLogger(WsdlDebugger.class).setLevel(
+ "on".equals(wsdlDebugEnabled)
+ ? Level.DEBUG
+ : Level.INFO);
+
+ Logger.getLogger(XmlDebugger.class).setLevel(
+ "on".equals(soapDebugEnabled)
+ ? Level.DEBUG
+ : Level.INFO);
+
+ doGet(request, response);
+ }
+}
+ \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/web/action/ResourcesManagementAction.java b/java/management/client/src/main/java/org/apache/qpid/management/web/action/ResourcesManagementAction.java
new file mode 100644
index 0000000000..f1a55be6bf
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/web/action/ResourcesManagementAction.java
@@ -0,0 +1,91 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.web.action;
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.List;
+import java.util.Set;
+
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.domain.services.ManagementClient;
+import org.apache.qpid.management.domain.services.QMan;
+
+/**
+ * This controller retrieves from QMan all the registered resources and organize
+ * that data in a model that is then forwarded to the appropriate view page.
+ *
+ * TODO : In the corresponding view page only one broker is displayed.
+ * A query should be made on QMan mbean in order to retrieve all connected broker and therefore
+ * a model for each of them should be created.
+ * In the corresponding weg page there should be a "tab" for each broker. Each tab should show only
+ * the objects belonging to that broker.
+ *
+ * @author Andrea Gazzarini
+ */
+public class ResourcesManagementAction extends HttpServlet
+{
+ private static final long serialVersionUID = -2411413147821629363L;
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ try
+ {
+ QMan qman = (QMan)getServletContext().getAttribute(Names.APPLICATION_NAME);
+ List<ManagementClient> managementClient = qman.getManagementClients();
+
+ if (!managementClient.isEmpty())
+ {
+ BrokerModel model = new BrokerModel();
+ model.setId(managementClient.toString());
+
+ MBeanServer mxServer = ManagementFactory.getPlatformMBeanServer();
+ Set<ObjectName> objectNames = mxServer.queryNames(new ObjectName("Q-MAN:*"), null);
+ for (ObjectName objectName : objectNames)
+ {
+ model.addObject(objectName);
+ }
+
+ request.setAttribute("model", model);
+ }
+
+ RequestDispatcher dispatcher = request.getRequestDispatcher("/resources_management.jsp");
+ dispatcher.forward(request,response);
+ } catch(MalformedObjectNameException exception)
+ {
+ request.setAttribute("errorMessage","Unable to detect the exact cause Please look at the reported stack trace below.");
+ request.setAttribute("exception",exception);
+ RequestDispatcher dispatcher = request.getRequestDispatcher("/error_page.jsp");
+ dispatcher.forward(request,response);
+ }
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/web/action/WsdmOperationsPerspectiveAction.java b/java/management/client/src/main/java/org/apache/qpid/management/web/action/WsdmOperationsPerspectiveAction.java
new file mode 100644
index 0000000000..ca5b3285b0
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/web/action/WsdmOperationsPerspectiveAction.java
@@ -0,0 +1,191 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.web.action;
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Map.Entry;
+
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.proxy.ProxyHandler;
+import org.apache.muse.core.proxy.ReflectionProxyHandler;
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.qpid.management.Names;
+import org.w3c.dom.Element;
+
+/**
+ * This controller is responsible to retirve operations metadata from a WS-Resource.
+ * That metadat will be forwarded and used by the corresponding view page.
+ *
+ * TODO : This is not really showing WS metadata. Insted JMX metadata is used here.
+ *
+ * @author Andrea Gazzarini
+ *
+ */
+public class WsdmOperationsPerspectiveAction extends HttpServlet
+{
+ private static final long serialVersionUID = -2411413147821629363L;
+
+ private ProxyHandler proxyHandler;
+
+ interface JavaToHtmlAdapter
+ {
+ String toHtml(Object javaObject);
+ }
+
+ private URI resourceUri;
+
+ private JavaToHtmlAdapter mapAdapter = new JavaToHtmlAdapter()
+ {
+ @SuppressWarnings("unchecked")
+ public String toHtml(Object javaObject)
+ {
+ Map<String,Object> value = (Map<String, Object>) javaObject;
+
+ if (value == null || value.isEmpty())
+ {
+ return "(empty)";
+ }
+
+ StringBuilder builder = new StringBuilder();
+ builder.append("<ul>");
+ for (Entry<String, Object> entry : value.entrySet())
+ {
+ builder
+ .append("<li>")
+ .append(entry.getKey())
+ .append(" = ")
+ .append(entry.getValue());
+ }
+ builder.append("</ul>");
+ return builder.toString();
+ }
+ };
+
+ private Map<String, JavaToHtmlAdapter> adapters = new HashMap<String, JavaToHtmlAdapter>();
+
+ @Override
+ public void init() throws ServletException
+ {
+ adapters.put(Map.class.getName(), mapAdapter);
+ adapters.put(HashMap.class.getName(),mapAdapter);
+ adapters.put(Properties.class.getName(),mapAdapter);
+ adapters.put(Hashtable.class.getName(),mapAdapter);
+
+ proxyHandler = new ReflectionProxyHandler();
+ proxyHandler.setAction("http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata");
+ proxyHandler.setRequestName(new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "GetMetadata", Names.PREFIX));
+ proxyHandler.setRequestParameterNames(new QName[]{new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "Dialect", Names.PREFIX)});
+ proxyHandler.setResponseName(new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "Metadata", Names.PREFIX));
+ proxyHandler.setReturnType(Element[].class);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ try
+ {
+ String resourceId = request.getParameter("resourceId");
+ ObjectName objectName = new ObjectName(resourceId);
+ String wsdmResourceId = objectName.getKeyProperty(Names.OBJECT_ID);
+
+ EndpointReference resourceEndpointReference = new EndpointReference(getURI(request));
+ resourceEndpointReference.addParameter(
+ Names.RESOURCE_ID_QNAME,
+ wsdmResourceId);
+
+// WsResourceClient resourceClient = new WsResourceClient(resourceEndpointReference);
+// Element wsdl = ((Element[])resourceClient.invoke(proxyHandler,WSDL_DIALECT))[0];
+// Element rmd = ((Element[])resourceClient.invoke(proxyHandler,RMD_DIALECT))[0];
+
+ String [] keyProperties = objectName.getKeyPropertyListString().split(",");
+ MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+
+ MBeanInfo metadata = server.getMBeanInfo(objectName);
+
+ Map<String, String> attributes = getAttributes(server, objectName,metadata.getAttributes());
+
+ request.setAttribute("resourceId", resourceId);
+ request.setAttribute("metadata",metadata);
+ request.setAttribute("nameAttributes",keyProperties);
+ request.setAttribute("attributes",attributes);
+
+ RequestDispatcher dispatcher = request.getRequestDispatcher("/wsdm_operations_perspective.jsp");
+ dispatcher.forward(request,response);
+ } catch(Exception exception)
+ {
+ request.setAttribute("errorMessage","Unable to detect the exact cause Please look at the reported stack trace below.");
+ request.setAttribute("exception",exception);
+ RequestDispatcher dispatcher = request.getRequestDispatcher("/error_page.jsp");
+ dispatcher.forward(request,response);
+ }
+ }
+
+ private URI getURI(HttpServletRequest request)
+ {
+ if (resourceUri == null)
+ {
+ StringBuilder builder = new StringBuilder();
+ builder
+ .append(request.getProtocol())
+ .append("//")
+ .append(request.getServerName())
+ .append(":")
+ .append(request.getServerPort())
+ .append("/qman/services/QManWsResource");
+ resourceUri = URI.create(builder.toString());
+ }
+ return resourceUri;
+ }
+
+ private Map<String, String> getAttributes(MBeanServer server, ObjectName name, MBeanAttributeInfo [] metadata) throws Exception
+ {
+ Map<String,String> result = new HashMap<String, String>(metadata.length);
+ for (MBeanAttributeInfo attribute : metadata)
+ {
+ Object value = server.getAttribute(name, attribute.getName());
+ result.put(attribute.getName(),getAdaptedValue(attribute.getType(), value));
+ }
+ return result;
+ }
+
+ private String getAdaptedValue(String type, Object value)
+ {
+ JavaToHtmlAdapter adapter = adapters.get(type);
+ return (adapter != null) ? adapter.toHtml(value) : String.valueOf(value);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/web/action/WsdmPropertiesPerspectiveAction.java b/java/management/client/src/main/java/org/apache/qpid/management/web/action/WsdmPropertiesPerspectiveAction.java
new file mode 100644
index 0000000000..e3a8eb50d7
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/web/action/WsdmPropertiesPerspectiveAction.java
@@ -0,0 +1,185 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.web.action;
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Map.Entry;
+
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.proxy.ProxyHandler;
+import org.apache.muse.core.proxy.ReflectionProxyHandler;
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.qpid.management.Names;
+import org.w3c.dom.Element;
+
+public class WsdmPropertiesPerspectiveAction extends HttpServlet
+{
+ private static final long serialVersionUID = -2411413147821629363L;
+
+ private ProxyHandler proxyHandler;
+
+ interface JavaToHtmlAdapter
+ {
+ String toHtml(Object javaObject);
+ }
+
+ private URI resourceUri;
+
+ private JavaToHtmlAdapter mapAdapter = new JavaToHtmlAdapter()
+ {
+ @SuppressWarnings("unchecked")
+ public String toHtml(Object javaObject)
+ {
+ Map<String,Object> value = (Map<String, Object>) javaObject;
+
+ if (value == null || value.isEmpty())
+ {
+ return "(empty)";
+ }
+
+ StringBuilder builder = new StringBuilder();
+ builder.append("<ul>");
+ for (Entry<String, Object> entry : value.entrySet())
+ {
+ builder
+ .append("<li>")
+ .append(entry.getKey())
+ .append(" = ")
+ .append(entry.getValue());
+ }
+ builder.append("</ul>");
+ return builder.toString();
+ }
+ };
+
+ private Map<String, JavaToHtmlAdapter> adapters = new HashMap<String, JavaToHtmlAdapter>();
+
+ @Override
+ public void init() throws ServletException
+ {
+ adapters.put(Map.class.getName(), mapAdapter);
+ adapters.put(HashMap.class.getName(),mapAdapter);
+ adapters.put(Properties.class.getName(),mapAdapter);
+ adapters.put(Hashtable.class.getName(),mapAdapter);
+
+ proxyHandler = new ReflectionProxyHandler();
+ proxyHandler.setAction("http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata");
+ proxyHandler.setRequestName(new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "GetMetadata", Names.PREFIX));
+ proxyHandler.setRequestParameterNames(new QName[]{new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "Dialect", Names.PREFIX)});
+ proxyHandler.setResponseName(new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "Metadata", Names.PREFIX));
+ proxyHandler.setReturnType(Element[].class);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ try
+ {
+ String resourceId = request.getParameter("resourceId");
+ ObjectName objectName = new ObjectName(resourceId);
+
+ String wsresourceid = objectName.getKeyProperty(Names.OBJECT_ID);
+
+ EndpointReference resourceEndpointReference = new EndpointReference(getURI(request));
+ resourceEndpointReference.addParameter(
+ Names.RESOURCE_ID_QNAME,
+ wsresourceid);
+
+// WsResourceClient resourceClient = new WsResourceClient(resourceEndpointReference);
+// Element wsdl = ((Element[])resourceClient.invoke(proxyHandler,WSDL_DIALECT))[0];
+// Element rmd = ((Element[])resourceClient.invoke(proxyHandler,RMD_DIALECT))[0];
+
+ String [] keyProperties = objectName.getKeyPropertyListString().split(",");
+
+
+ MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+
+ MBeanInfo metadata = server.getMBeanInfo(objectName);
+
+ Map<String, String> attributes = getAttributes(server, objectName,metadata.getAttributes());
+
+ request.setAttribute("resourceId", resourceId);
+ request.setAttribute("metadata",metadata);
+ request.setAttribute("nameAttributes",keyProperties);
+ request.setAttribute("attributes",attributes);
+
+ RequestDispatcher dispatcher = request.getRequestDispatcher("/wsdm_properties_perspective.jsp");
+ dispatcher.forward(request,response);
+ } catch(Exception exception)
+ {
+ request.setAttribute("errorMessage","Unable to detect the exact cause Please look at the reported stack trace below.");
+ request.setAttribute("exception",exception);
+ RequestDispatcher dispatcher = request.getRequestDispatcher("/error_page.jsp");
+ dispatcher.forward(request,response);
+ }
+ }
+
+ private URI getURI(HttpServletRequest request)
+ {
+ if (resourceUri == null)
+ {
+ StringBuilder builder = new StringBuilder();
+ builder
+ .append(request.getProtocol())
+ .append("//")
+ .append(request.getServerName())
+ .append(":")
+ .append(request.getServerPort())
+ .append("/qman/services/QManWsResource");
+ resourceUri = URI.create(builder.toString());
+ }
+ return resourceUri;
+ }
+
+ private Map<String, String> getAttributes(MBeanServer server, ObjectName name, MBeanAttributeInfo [] metadata) throws Exception
+ {
+ Map<String,String> result = new HashMap<String, String>(metadata.length);
+ for (MBeanAttributeInfo attribute : metadata)
+ {
+ Object value = server.getAttribute(name, attribute.getName());
+ result.put(attribute.getName(),getAdaptedValue(attribute.getType(), value));
+ }
+ return result;
+ }
+
+ private String getAdaptedValue(String type, Object value)
+ {
+ JavaToHtmlAdapter adapter = adapters.get(type);
+ return (adapter != null) ? adapter.toHtml(value) : String.valueOf(value);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/web/action/WsdmRmdPerspectiveAction.java b/java/management/client/src/main/java/org/apache/qpid/management/web/action/WsdmRmdPerspectiveAction.java
new file mode 100644
index 0000000000..b4c488e97c
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/web/action/WsdmRmdPerspectiveAction.java
@@ -0,0 +1,139 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.web.action;
+
+import java.io.IOException;
+import java.net.URI;
+
+import javax.management.ObjectName;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.proxy.ProxyHandler;
+import org.apache.muse.core.proxy.ReflectionProxyHandler;
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.muse.ws.metadata.WsxConstants;
+import org.apache.muse.ws.resource.metadata.WsrmdConstants;
+import org.apache.muse.ws.resource.remote.WsResourceClient;
+import org.apache.qpid.management.Names;
+import org.w3c.dom.Element;
+
+public class WsdmRmdPerspectiveAction extends HttpServlet
+{
+ private static final long serialVersionUID = -2411413147821629363L;
+ private static final Object [] RMD_DIALECT = new Object[]{WsrmdConstants.NAMESPACE_URI};
+
+ private ProxyHandler proxyHandler;
+
+ private URI resourceUri;
+
+ @Override
+ public void init() throws ServletException
+ {
+ proxyHandler = new ReflectionProxyHandler();
+ proxyHandler.setAction(WsxConstants.GET_METADATA_URI);
+ proxyHandler.setRequestName(WsxConstants.GET_METADATA_QNAME);
+ proxyHandler.setRequestParameterNames(new QName[]{
+ new QName(
+ WsxConstants.NAMESPACE_URI,
+ WsxConstants.DIALECT,
+ WsxConstants.PREFIX)});
+ proxyHandler.setResponseName(WsxConstants.METADATA_QNAME);
+ proxyHandler.setReturnType(Element[].class);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ try
+ {
+ String resourceId = request.getParameter("resourceId");
+ ObjectName objectName = new ObjectName(resourceId);
+
+ String wsresourceid = objectName.getKeyProperty(Names.OBJECT_ID);
+ EndpointReference resourceEndpointReference = new EndpointReference(getURI(request));
+
+ resourceEndpointReference.addParameter(
+ Names.RESOURCE_ID_QNAME,
+ wsresourceid);
+
+ WsResourceClient resourceClient = new WsResourceClient(resourceEndpointReference);
+ Element rmd = ((Element[])resourceClient.invoke(proxyHandler,RMD_DIALECT))[0];
+
+// NodeList nodelist = wsdl.getChildNodes();
+// Element definitions = null;
+// for (int i = 0; i < nodelist.getLength(); i++)
+// {
+// Node node = nodelist.item(i);
+// switch (node.getNodeType())
+// {
+// case Node.ELEMENT_NODE:
+// {
+// Element element = (Element) node;
+// if (element.getNodeName().indexOf("definitions") != -1)
+// {
+// definitions = element;
+// break;
+// }
+// }
+// }
+// }
+
+ String output = XmlUtils.toString(rmd);
+
+ String [] keyProperties = objectName.getKeyPropertyListString().split(",");
+
+ request.setAttribute("resourceId", resourceId);
+ request.setAttribute("nameAttributes",keyProperties);
+ request.setAttribute("rmd",output);
+ RequestDispatcher dispatcher = request.getRequestDispatcher("/wsdm_rmd_perspective.jsp");
+ dispatcher.forward(request,response);
+ } catch(Exception exception)
+ {
+ request.setAttribute("errorMessage","Unable to detect the exact cause Please look at the reported stack trace below.");
+ request.setAttribute("exception",exception);
+ RequestDispatcher dispatcher = request.getRequestDispatcher("/error_page.jsp");
+ dispatcher.forward(request,response);
+ }
+ }
+
+ private URI getURI(HttpServletRequest request)
+ {
+ if (resourceUri == null)
+ {
+ StringBuilder builder = new StringBuilder();
+ builder
+ .append("http://")
+ .append(request.getServerName())
+ .append(":")
+ .append(request.getServerPort())
+ .append("/qman/services/QManWsResource");
+ resourceUri = URI.create(builder.toString());
+ }
+ return resourceUri;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/web/action/WsdmWsdlPerspectiveAction.java b/java/management/client/src/main/java/org/apache/qpid/management/web/action/WsdmWsdlPerspectiveAction.java
new file mode 100644
index 0000000000..77a5237037
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/web/action/WsdmWsdlPerspectiveAction.java
@@ -0,0 +1,140 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.web.action;
+
+import java.io.IOException;
+import java.net.URI;
+
+import javax.management.ObjectName;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.proxy.ProxyHandler;
+import org.apache.muse.core.proxy.ReflectionProxyHandler;
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.muse.ws.metadata.WsxConstants;
+import org.apache.muse.ws.resource.remote.WsResourceClient;
+import org.apache.qpid.management.Names;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public class WsdmWsdlPerspectiveAction extends HttpServlet
+{
+ private static final long serialVersionUID = -2411413147821629363L;
+ private static final Object [] WSDL_DIALECT = new Object[]{WsxConstants.WSDL_DIALECT};
+
+ private ProxyHandler proxyHandler;
+
+ private URI resourceUri;
+
+ @Override
+ public void init() throws ServletException
+ {
+ proxyHandler = new ReflectionProxyHandler();
+ proxyHandler.setAction(WsxConstants.GET_METADATA_URI);
+ proxyHandler.setRequestName(WsxConstants.GET_METADATA_QNAME);
+ proxyHandler.setRequestParameterNames(new QName[]{
+ new QName(
+ WsxConstants.NAMESPACE_URI,
+ WsxConstants.DIALECT,
+ WsxConstants.PREFIX)});
+ proxyHandler.setResponseName(WsxConstants.METADATA_QNAME);
+ proxyHandler.setReturnType(Element[].class);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ try
+ {
+ String resourceId = request.getParameter("resourceId");
+ ObjectName objectName = new ObjectName(resourceId);
+
+ String wsresourceid = objectName.getKeyProperty(Names.OBJECT_ID);
+ EndpointReference resourceEndpointReference = new EndpointReference(getURI(request));
+
+ resourceEndpointReference.addParameter(
+ Names.RESOURCE_ID_QNAME,
+ wsresourceid);
+
+ WsResourceClient resourceClient = new WsResourceClient(resourceEndpointReference);
+ Element wsdl = ((Element[])resourceClient.invoke(proxyHandler,WSDL_DIALECT))[0];
+
+ NodeList nodelist = wsdl.getChildNodes();
+ Element definitions = null;
+ for (int i = 0; i < nodelist.getLength(); i++)
+ {
+ Node node = nodelist.item(i);
+ switch (node.getNodeType())
+ {
+ case Node.ELEMENT_NODE:
+ {
+ Element element = (Element) node;
+ if (element.getNodeName().indexOf("definitions") != -1)
+ {
+ definitions = element;
+ break;
+ }
+ }
+ }
+ }
+
+ String output = XmlUtils.toString(definitions);
+
+ String [] keyProperties = objectName.getKeyPropertyListString().split(",");
+
+ request.setAttribute("resourceId", resourceId);
+ request.setAttribute("nameAttributes",keyProperties);
+ request.setAttribute("wsdl",output);
+ RequestDispatcher dispatcher = request.getRequestDispatcher("/wsdm_wsdl_perspective.jsp");
+ dispatcher.forward(request,response);
+ } catch(Exception exception)
+ {
+ request.setAttribute("errorMessage","Unable to detect the exact cause Please look at the reported stack trace below.");
+ request.setAttribute("exception",exception);
+ RequestDispatcher dispatcher = request.getRequestDispatcher("/error_page.jsp");
+ dispatcher.forward(request,response);
+ }
+ }
+
+ private URI getURI(HttpServletRequest request)
+ {
+ if (resourceUri == null)
+ {
+ StringBuilder builder = new StringBuilder();
+ builder
+ .append("http://")
+ .append(request.getServerName())
+ .append(":")
+ .append(request.getServerPort())
+ .append("/qman/services/QManWsResource");
+ resourceUri = URI.create(builder.toString());
+ }
+ return resourceUri;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmu.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmu.java
new file mode 100644
index 0000000000..79a387e80c
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmu.java
@@ -0,0 +1,130 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm;
+
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.ObjectName;
+
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.domain.handler.impl.QpidDomainObject;
+import org.apache.qpid.management.domain.handler.impl.QpidDomainObjectMBean;
+import org.apache.qpid.management.jmx.EntityLifecycleNotification;
+
+/**
+ * QEmu is basically an instance creator that is installed separately
+ * as part of QMan test cases & examples.
+ * Reason for that is to emulate object creation (queues, exchanges, etc...)
+ * without having Qpid broker connected and therefore controlling the
+ * total number of the instances that are created.
+ *
+ * @author Andrea Gazzarini
+ */
+public class QEmu extends NotificationBroadcasterSupport implements QEmuMBean, MBeanRegistration{
+
+ private MBeanServer _mxServer;
+ private final static String PACKAGE_NAME= "org.apache.qpid";
+ private final static String QUEUE = "queue";
+
+ /**
+ * Unregisters a Queue MBean with MBeanServer.
+ *
+ * @param objectName the name of the MBean that must unregistered.
+ * @throws Exception when the creation or the registration fails.
+ */
+ public void unregister(ObjectName objectName) throws Exception
+ {
+ _mxServer.unregisterMBean(objectName);
+
+ sendNotification(
+ EntityLifecycleNotification.INSTANCE_REMOVED_NOTIFICATION_TYPE,
+ objectName);
+ }
+
+ /**
+ * Creates and registers a Queue MBean with MBeanServer.
+ *
+ * @param objectName the name of the queue MBean.
+ * @throws Exception when the creation or the registration fails.
+ */
+ public void createQueue(ObjectName objectName) throws Exception
+ {
+ QpidDomainObjectMBean queue = new QpidDomainObject();
+ _mxServer.registerMBean(queue, objectName);
+
+ sendNotification(
+ EntityLifecycleNotification.INSTANCE_ADDED_NOTIFICATION_TYPE,
+ objectName);
+ }
+
+ /**
+ * Sends a notification about a lifecycle event of the mbean associated
+ * with the given object.
+ *
+ * @param type the event (notification) type.
+ * @param name the name of the event source.
+ */
+ private void sendNotification(String type,ObjectName name)
+ {
+ sendNotification(
+ new EntityLifecycleNotification(
+ type,
+ PACKAGE_NAME,
+ QUEUE,
+ Names.CLASS,
+ name));
+ }
+
+ /**
+ * Not implemented for this class.
+ */
+ public void postDeregister()
+ {
+ // N.A.
+ }
+
+ /**
+ * Not implemented for this class.
+ */
+ public void postRegister(Boolean registrationDone)
+ {
+ // N.A.
+ }
+
+ /**
+ * Not implemented for this class.
+ */
+ public void preDeregister()
+ {
+ // N.A.
+ }
+
+ /**
+ * MBean server callback.
+ * Stores the value of the owner MBeanServer.
+ */
+ public ObjectName preRegister(MBeanServer server, ObjectName name)
+ {
+ this._mxServer = server;
+ return name;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmuInitializer.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmuInitializer.java
new file mode 100644
index 0000000000..47aa4ea681
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmuInitializer.java
@@ -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.
+ *
+ */
+package org.apache.qpid.management.wsdm;
+
+import java.lang.management.ManagementFactory;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * QPid Emulator Initializer.
+ * This component is basically responsible to create and initialize
+ * an emulator module used for simulate object instances creation.
+ *
+ * @author Andrea Gazzarini
+ */
+public class QEmuInitializer extends HttpServlet
+{
+ private static final long serialVersionUID = 6149614872902682208L;
+ private final static Logger LOGGER = Logger.get(QEmuInitializer.class);
+
+ /**
+ * QEmu initialization method.
+ *
+ * @throws ServletException when the module cannot be initialized.
+ */
+ public void init() throws ServletException
+ {
+ try
+ {
+ ManagementFactory.getPlatformMBeanServer().registerMBean(
+ new QEmu(),
+ Names.QPID_EMULATOR_OBJECT_NAME);
+ } catch(Exception exception)
+ {
+ LOGGER.warn(
+ exception,
+ Messages.QMAN_300005_QEMU_INITIALIZATION_FAILURE);
+ throw new ServletException(exception);
+ }
+ }
+
+ /**
+ * This is a startup module only so an override of the
+ * default servlet behaviour must be done in order to
+ * prevent incoming http requests processing.
+ *
+ * @param request the http request.
+ * @param response the http response.
+ * @throws ServletException each time this method is called.
+ */
+ @Override
+ public void service(HttpServletRequest request,HttpServletResponse response) throws ServletException
+ {
+ throw new ServletException();
+ }
+
+ /**
+ * Unregister QPid emulator.
+ */
+ public void destroy()
+ {
+ try
+ {
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(
+ Names.QPID_EMULATOR_OBJECT_NAME);
+ } catch (Exception exception)
+ {
+ }
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmuMBean.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmuMBean.java
new file mode 100644
index 0000000000..f22e7ff12d
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/QEmuMBean.java
@@ -0,0 +1,48 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm;
+
+import javax.management.ObjectName;
+
+/**
+ * Management interface for QEmu.
+ *
+ * @author Andrea Gazzarini
+ * @see QEmu
+ */
+public interface QEmuMBean
+{
+ /**
+ * Creates and registers a Queue MBean with MBeanServer.
+ *
+ * @param objectName the name of the queue MBean.
+ * @throws Exception when the creation or the registration fails.
+ */
+ void createQueue(ObjectName name) throws Exception;
+
+ /**
+ * Unregisters a Queue MBean with MBeanServer.
+ *
+ * @param objectName the name of the MBean that must unregistered.
+ * @throws Exception when the creation or the registration fails.
+ */
+ void unregister(ObjectName name) throws Exception;
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/ArtifactsNotAvailableException.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/ArtifactsNotAvailableException.java
new file mode 100644
index 0000000000..eef70b5544
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/ArtifactsNotAvailableException.java
@@ -0,0 +1,76 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.capabilities;
+
+import javax.management.ObjectName;
+
+/**
+ * Thrown when the artifacts related to a specific resource cannot be built.
+ *
+ * @author Andrea Gazzarini
+ */
+public class ArtifactsNotAvailableException extends Exception
+{
+ private static final long serialVersionUID = -9010460152421791926L;
+
+ private final WsArtifacts _artifacts;
+ private final ObjectName _objectName;
+
+ /**
+ * Builds a new exception with the given arguments.
+ *
+ * @param artifacts the artifacts built.
+ * @param cause the exception cause.
+ * @param objectName the object name of the corresponding JMX entity.
+ */
+ public ArtifactsNotAvailableException(
+ WsArtifacts artifacts,
+ Throwable cause,
+ ObjectName objectName)
+ {
+ super(cause);
+ this._artifacts = artifacts;
+ this._objectName = objectName;
+ }
+
+ /**
+ * Returns a message that indicates which artifacts were built.
+ *
+ * @return a message that indicates which artifacts were built.
+ */
+ @Override
+ public String getMessage()
+ {
+ StringBuilder builder = new StringBuilder();
+ if (_artifacts == null)
+ {
+ return super.getMessage();
+ }
+
+ builder.append("Built artifacts for ")
+ .append(_objectName)
+ .append(" : ")
+ .append( (_artifacts.getWsdl() != null) ? "WSDL," : "")
+ .append( (_artifacts.getCapabilityClass() != null) ? "Capability Class," : "")
+ .append( (_artifacts.getResourceMetadataDescriptor() != null) ? "Resource Metadata Descriptor," : "");
+ return builder.toString();
+ }
+}
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/BuilderException.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/BuilderException.java
new file mode 100644
index 0000000000..f3c8077d46
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/BuilderException.java
@@ -0,0 +1,41 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.capabilities;
+
+/**
+ * Thrown when a WSRF artifact (either WSDL or capability) cannot be built.
+ *
+ * @author Andrea Gazzarini
+ */
+public class BuilderException extends Exception
+{
+ private static final long serialVersionUID = -8267818907567906262L;
+
+ /**
+ * Builds a new exception with the given cause.
+ *
+ * @param cause the exception cause.
+ */
+ public BuilderException(Exception cause)
+ {
+ super(cause);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/Constants.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/Constants.java
new file mode 100644
index 0000000000..59a5801505
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/Constants.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.capabilities;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+
+public interface Constants
+{
+ String WSRP_PROPERTIES_XPATH = "/wsdl:definitions/wsdl:types/xsd:schema[" +
+ "@targetNamespace='http://amqp.apache.org/qpid/management/qman']" +
+ "/xsd:element[@name='QManWsResourceProperties']/xsd:complexType/xsd:sequence";
+
+ String SERVICE_LOCATION_XPATH = "/wsdl:definitions/wsdl:service/wsdl:port/wsdl-soap:address/@location";
+ String QMAN_SCHEMA_XPATH = "/wsdl:definitions/wsdl:types/xsd:schema[@targetNamespace='http://amqp.apache.org/qpid/management/qman']";
+
+ String MIN_OCCURS = "minOccurs";
+ String REF_ATTRIBUTE = "ref";
+ String NAME_ATTRIBUTE = "name";
+ String TYPE_ATTRIBUTE ="type";
+
+ QName XSD_ELEMENT_QNAME = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI,"element","xsd");
+ QName XSD_COMPLEX_TYPE_QNAME = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI,"complexType","xsd");
+ QName XSD_SEQUENCE_QNAME = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI,"sequence","xsd");
+
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/ConsumerCapability.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/ConsumerCapability.java
new file mode 100644
index 0000000000..bde98092a0
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/ConsumerCapability.java
@@ -0,0 +1,68 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.capabilities;
+
+import org.apache.muse.core.AbstractCapability;
+import org.apache.muse.ws.addressing.soap.SoapFault;
+import org.apache.muse.ws.notification.NotificationConsumer;
+import org.apache.muse.ws.notification.NotificationMessage;
+import org.apache.muse.ws.notification.NotificationMessageListener;
+import org.apache.muse.ws.notification.WsnConstants;
+
+/**
+ * WS-Notifications consumer capability.
+ * At the moment QMan is not a consumer of itself so this capability is here only
+ * for test purposes.
+ *
+ * @author Andrea Gazzarini
+ */
+public class ConsumerCapability extends AbstractCapability implements NotificationMessageListener
+{
+ /**
+ * Initializes this capability and register itself as message listener.
+ *
+ * @throws SoapFault when the initialization fails.
+ */
+ public void initializeCompleted() throws SoapFault
+ {
+ super.initializeCompleted();
+
+ NotificationConsumer wsn = (NotificationConsumer)getResource().getCapability(WsnConstants.CONSUMER_URI);
+ wsn.addMessageListener(this);
+ }
+
+ /**
+ * Returns true if this consumer can accepts the message.
+ *
+ * @return true;
+ */
+ public boolean accepts(NotificationMessage message)
+ {
+ return true;
+ }
+
+ /**
+ * On Message callback.
+ */
+ public void process(NotificationMessage message)
+ {
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/DummyCapabilityBuilder.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/DummyCapabilityBuilder.java
new file mode 100644
index 0000000000..370cf3086d
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/DummyCapabilityBuilder.java
@@ -0,0 +1,86 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.capabilities;
+
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.ObjectName;
+
+import org.apache.muse.core.Environment;
+
+/**
+ * Dummy capability builder used for avoid duplicated builds for the
+ * same class.
+ * Basically it acts likes a Null Object when the target capability class has been
+ * already built.
+ *
+ * @author Andrea Gazzarini
+ */
+public class DummyCapabilityBuilder implements IArtifactBuilder
+{
+ /**
+ * Director callback.
+ * Do nothing here (see class comments above.)
+ */
+ public void begin(ObjectName objectName)
+ {
+ }
+
+ /**
+ * Director callback.
+ * Do nothing here (see class comments above.)
+ */
+ public void endAttributes()
+ {
+ }
+
+ /**
+ * Director callback.
+ * Do nothing here (see class comments above.)
+ */
+ public void endOperations()
+ {
+ }
+
+ /**
+ * Director callback.
+ * Do nothing here (see class comments above.)
+ */
+ public void onAttribute(MBeanAttributeInfo attributeMetadata)
+ {
+ }
+
+ /**
+ * Director callback.
+ * Do nothing here (see class comments above.)
+ */
+ public void onOperation(MBeanOperationInfo operationMetadata)
+ {
+ }
+
+ /**
+ * Director callback.
+ * Do nothing here (see class comments above.)
+ */
+ public void setEnvironment(Environment environment)
+ {
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/IArtifactBuilder.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/IArtifactBuilder.java
new file mode 100644
index 0000000000..70b9b0e009
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/IArtifactBuilder.java
@@ -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.
+ *
+ */
+package org.apache.qpid.management.wsdm.capabilities;
+
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.ObjectName;
+
+import org.apache.muse.core.Environment;
+
+/**
+ * Defines behaviour needed by WS-DM artifact builders.
+ * Each concrete implementor must provide its own parser
+ * implementation of the given JMX data.
+ *
+ * @author Andrea Gazzarini
+ */
+public interface IArtifactBuilder
+{
+ /**
+ * The build process begin and the given parameter is the
+ * object name of the corresponding JMX entity.
+ *
+ * @throws BuilderException when the initialization fails.
+ */
+ void begin(ObjectName objectName) throws BuilderException;
+
+ /**
+ * Processes an attribute (its metadata) of the current MBean.
+ *
+ * @param attributeMetadata the attribute metadata.
+ * @throws BuilderException when the builder cannot parse the given metadata.
+ */
+ void onAttribute(MBeanAttributeInfo attributeMetadata) throws BuilderException;
+
+ /**
+ * Processes an operation (its metadata) of the current MBean.
+ *
+ * @param operationMetadata the operation metadata.
+ * @throws BuilderException when the builder cannot parse the given metadata.
+ */
+ void onOperation(MBeanOperationInfo operationMetadata) throws BuilderException;
+
+ /**
+ * Ends of the attributes section.
+ *
+ * @throws BuilderException when the builder encounter a problem during this phase..
+ */
+ void endAttributes() throws BuilderException;
+
+ /**
+ * Ends of the operations section.
+ *
+ * @throws BuilderException when the builder encounter a problem during this phase..
+ */
+ void endOperations() throws BuilderException;
+
+ /**
+ * Injects the adapter enviroment on this builder.
+ *
+ * @param environment the adapter environment.
+ */
+ void setEnvironment(Environment environment);
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapability.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapability.java
new file mode 100644
index 0000000000..37ecc0c031
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapability.java
@@ -0,0 +1,219 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.capabilities;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.Attribute;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.muse.ws.resource.impl.AbstractWsResourceCapability;
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.domain.handler.impl.InvocationResult;
+import org.apache.qpid.management.domain.services.MethodInvocationException;
+import org.apache.qpid.management.wsdm.common.EntityInstanceNotFoundFault;
+import org.apache.qpid.management.wsdm.common.MethodInvocationFault;
+import org.apache.qpid.management.wsdm.common.NoSuchAttributeFault;
+import org.apache.qpid.management.wsdm.common.QManFault;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * Abstract capability used for centralize common
+ * behaviour of the QMan resource(s) related capabilities.
+ *
+ * @author Andrea Gazzarini
+ */
+public abstract class MBeanCapability extends AbstractWsResourceCapability
+{
+ private static final Logger LOGGER = Logger.get(MBeanCapability.class);
+
+ protected final MBeanServer _mxServer;
+ protected ObjectName _objectName;
+
+ /**
+ * Builds a new capability related to the given object name.
+ *
+ * @param objectName the name of the target object of this capability.
+ */
+ public MBeanCapability()
+ {
+ _mxServer = ManagementFactory.getPlatformMBeanServer();
+ }
+
+ /**
+ * Injects on this capability the object name of the target mbean.
+ *
+ * @param objectName the object name of the target mbean.
+ */
+ void setResourceObjectName(ObjectName objectName)
+ {
+ this._objectName = objectName;
+ }
+
+ /**
+ * Returns the attribute value of a QMan managed object instance.
+ *
+ * @param attributeName the name of the attribute to be requested.
+ * @return the value for the requested attribute.
+ * @throws NoSuchAttributeFault when the requested attribute cannot be found
+ * on the given entity instance.
+ * @throws EntityInstanceNotFoundFault when the requested entity instance cannot
+ * be found.
+ * @throws QManFault in case of internal system failure.
+ */
+ Object getAttribute(String attributeName) throws NoSuchAttributeFault, EntityInstanceNotFoundFault, QManFault
+ {
+ try
+ {
+ return _mxServer.getAttribute(_objectName, attributeName);
+ } catch (AttributeNotFoundException exception)
+ {
+ throw new NoSuchAttributeFault(
+ getWsResource().getEndpointReference(),
+ attributeName);
+ } catch (InstanceNotFoundException exception)
+ {
+ throw new EntityInstanceNotFoundFault(
+ getWsResource().getEndpointReference(),
+ _objectName);
+ } catch (Exception exception)
+ {
+ LOGGER.error(
+ Messages.QMAN_100035_GET_ATTRIBUTE_FAILURE,
+ attributeName,
+ _objectName);
+ throw new QManFault(
+ getWsResource().getEndpointReference(),
+ exception);
+ }
+ }
+
+ /**
+ * Sets the value for the given attribute on this MBean (proxy).
+ *
+ * @param objectName
+ * the object name of the target instance (excluding the domain
+ * name).
+ * @param attributeName
+ * the name of the attribute to be requested.
+ * @param value
+ * the value for the requested attribute.
+ * @throws NoSuchAttributeFault
+ * when the requested attribute cannot be found on the given
+ * entity instance.
+ * @throws EntityInstanceNotFoundFault
+ * when the requested entity instance cannot be found.
+ * @throws QManFault
+ * in case of internal system failure.
+ */
+ void setAttribute(String attributeName, Object value) throws NoSuchAttributeFault, EntityInstanceNotFoundFault, QManFault
+ {
+ try
+ {
+ _mxServer.setAttribute(_objectName, new Attribute(attributeName,value));
+ } catch (AttributeNotFoundException exception)
+ {
+ throw new NoSuchAttributeFault(
+ getWsResource().getEndpointReference(),
+ attributeName);
+ } catch (InstanceNotFoundException exception)
+ {
+ throw new EntityInstanceNotFoundFault(
+ getWsResource().getEndpointReference(),
+ _objectName);
+ } catch (Exception exception)
+ {
+ LOGGER.error(
+ Messages.QMAN_100036_SET_ATTRIBUTE_FAILURE,
+ attributeName,
+ _objectName);
+ throw new QManFault(
+ getWsResource().getEndpointReference(),
+ exception);
+ }
+ }
+
+ /**
+ * Invokes the requested operation on target JMX resource.
+ *
+ * @param operationName the name of the operation to be invoked.
+ * @param params parameters used for operation invocation.
+ * @param signature the operation / method signature.
+ * @throws EntityInstanceNotFoundFault
+ * when the target MBean doesn't exist on Management server.
+ * @throws MethodInvocationFault
+ * when the invocation of the requested operation raises an exception.
+ * @throws QManFault
+ * in case of not-well known failure.
+ */
+ Result invoke(String operationName, Object [] params, String [] signature) throws EntityInstanceNotFoundFault, MethodInvocationFault,QManFault
+ {
+ try
+ {
+ InvocationResult output = (InvocationResult) _mxServer
+ .invoke(
+ _objectName,
+ operationName,
+ params,
+ signature);
+
+ return new Result(output.getOutputSection());
+
+ } catch (InstanceNotFoundException exception)
+ {
+ throw new EntityInstanceNotFoundFault(
+ getWsResource().getEndpointReference(),
+ _objectName);
+ } catch (MBeanException exception)
+ {
+ if (exception.getTargetException() instanceof MethodInvocationException)
+ {
+ MethodInvocationException failure = (MethodInvocationException) exception.getTargetException();
+ throw new MethodInvocationFault(
+ getWsResource().getEndpointReference(),
+ operationName,
+ failure.getStatusText(),
+ failure.getReturnCode());
+ } else {
+ LOGGER.error(
+ Messages.QMAN_100037_INVOKE_OPERATION_FAILURE,
+ operationName,
+ _objectName);
+ throw new QManFault(
+ getWsResource().getEndpointReference(),
+ exception);
+ }
+ }catch(Exception exception)
+ {
+ LOGGER.error(
+ Messages.QMAN_100037_INVOKE_OPERATION_FAILURE,
+ operationName,
+ _objectName);
+ throw new QManFault(
+ getWsResource().getEndpointReference(),
+ exception);
+ }
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityBuilder.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityBuilder.java
new file mode 100644
index 0000000000..ea67bdf9e1
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityBuilder.java
@@ -0,0 +1,549 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.capabilities;
+
+import javassist.CannotCompileException;
+import javassist.ClassClassPath;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtField;
+import javassist.CtMethod;
+import javassist.CtNewMethod;
+
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+import javax.management.ObjectName;
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.Environment;
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.wsdm.common.EntityInstanceNotFoundFault;
+import org.apache.qpid.management.wsdm.common.MethodInvocationFault;
+import org.apache.qpid.management.wsdm.common.NoSuchAttributeFault;
+import org.apache.qpid.management.wsdm.common.QManFault;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * Builder for capability class that will implements the interface
+ * and the behaviour of the underlying JMX Entity.
+ * The product of this builder (capability class) will be used for create a new instance
+ * of the corresponding capability. It will be the "adapter" between WS-Resource and
+ * JMX MBean.
+ *
+ * @author Andrea Gazzarini
+ */
+public class MBeanCapabilityBuilder implements IArtifactBuilder{
+
+ private final static String GET_PROPERTY_NAMES_METHOD_COMMON_PART = "public QName[] getPropertyNames() { return ";
+ private final static String GET_PROPERTY_NAMES_METHOD_WITH_ARRAY = GET_PROPERTY_NAMES_METHOD_COMMON_PART+" PROPERTIES;}";
+ private final static String GET_PROPERTY_NAMES_METHOD_WITH_EMPTY_ARRAY = GET_PROPERTY_NAMES_METHOD_COMMON_PART+" new QName[0];}";
+ private final static Logger LOGGER = Logger.get(MBeanCapabilityBuilder.class);
+
+ /**
+ * Handler interface definining operation needed to be
+ * peformed (by a concrete implementor) when the "endAttributes"
+ * director callback happens.
+ *
+ * @author Andrea Gazzarini
+ */
+ interface EndAttributesHandler {
+
+ /**
+ * Concrete implementor must define in this method what
+ * needs to be done when the corresponding director callback
+ * happens (@see {@link MBeanCapabilityBuilder#endAttributes()}
+ *
+ * @throws BuilderException when a failure is raised inside the concrete implementation.
+ */
+ void endAttributes() throws BuilderException;
+ };
+
+ /**
+ * This is the concrete implementation of the internal interface EndAttributesHandler
+ * that is activated when this builder detects the presence of at least one property on the
+ * capability class.
+ */
+ final EndAttributesHandler _atLeastThereIsOneProperty = new EndAttributesHandler() {
+
+ /**
+ * Creates the QName array instance member and the corresponding
+ * accessor getPropertyNames().
+ *
+ * @throws BuilderException when the member above cannot be added to the capability class.
+ */
+ public void endAttributes() throws BuilderException
+ {
+ try
+ {
+ _properties.deleteCharAt(_properties.length()-1);
+ _properties.append("};");
+
+ CtField properties = CtField.make(_properties.toString(), _capabilityClassDefinition);
+
+ _capabilityClassDefinition.addField(properties);
+
+ CtMethod getPropertyNames = CtNewMethod.make(
+ GET_PROPERTY_NAMES_METHOD_WITH_ARRAY,
+ _capabilityClassDefinition);
+ _capabilityClassDefinition.addMethod(getPropertyNames);
+ } catch(Exception exception)
+ {
+ throw new BuilderException(exception);
+ }
+ }
+ };
+
+ /**
+ * This is the concrete implementation of the internal interface EndAttributesHandler
+ * that is activated when this builder detects that there are no properties defined for
+ * the capability class.
+ */
+ final EndAttributesHandler _noPropertyHasBeenDefined= new EndAttributesHandler()
+ {
+ /**
+ * Creates the getPropertyNames() that simply returns an empty QName array.
+ *
+ * @throws BuilderException when the member above cannot be added to the capability class.
+ */
+ public void endAttributes() throws BuilderException
+ {
+ try
+ {
+ CtMethod getPropertyNames = CtNewMethod.make(
+ GET_PROPERTY_NAMES_METHOD_WITH_EMPTY_ARRAY,
+ _capabilityClassDefinition);
+ _capabilityClassDefinition.addMethod(getPropertyNames);
+ } catch(Exception exception)
+ {
+ throw new BuilderException(exception);
+ }
+ }
+ };
+
+ /**
+ * This is the active state for this builder when the requested class has never been
+ * built.
+ */
+ IArtifactBuilder _classNotAvailable = new IArtifactBuilder()
+ {
+
+ /**
+ * Build process begins.
+ * The given object name is used to build a minimal definition of the product class.
+ *
+ * @param objectName the name of the JMX entity.
+ * @throws BuilderException when the initial definiton of the capability cannot be created.
+ */
+ public void begin(ObjectName objectName) throws BuilderException
+ {
+ String className = objectName.getKeyProperty(Names.CLASS);
+ ClassPool pool = ClassPool.getDefault();
+ pool.insertClassPath(new ClassClassPath(MBeanCapabilityBuilder.class));
+ pool.importPackage(QName.class.getPackage().getName());
+ pool.importPackage(ObjectName.class.getPackage().getName());
+ pool.importPackage(QManFault.class.getPackage().getName());
+ pool.importPackage(Names.class.getPackage().getName());
+ pool.importPackage(Result.class.getPackage().getName());
+ pool.importPackage(NoSuchAttributeFault.class.getPackage().getName());
+ pool.importPackage(EntityInstanceNotFoundFault.class.getPackage().getName());
+ pool.importPackage(MethodInvocationFault.class.getPackage().getName());
+
+ _capabilityClassDefinition = pool.makeClass("org.apache.qpid.management.wsdm.capabilities."+className);
+ try
+ {
+ _capabilityClassDefinition.setSuperclass(pool.get(MBeanCapability.class.getName()));
+ } catch(Exception exception)
+ {
+ throw new BuilderException(exception);
+ }
+ }
+
+ /**
+ * Director callback.
+ * All attributes have been notified.
+ *
+ * This builder is using this callback in order to create the initial
+ * properties QNames declaration.
+ *
+ */
+ public void endAttributes() throws BuilderException
+ {
+ _endAttributeHandler.endAttributes();
+ }
+
+ @SuppressWarnings("unchecked")
+ public void endOperations() throws BuilderException
+ {
+ try
+ {
+ _capabilityClass = _capabilityClassDefinition.toClass(
+ QManAdapterCapability.class.getClassLoader(),
+ QManAdapterCapability.class.getProtectionDomain());
+ } catch (Exception exception)
+ {
+ throw new BuilderException(exception);
+ }
+ }
+
+ /**
+ * Director callback.
+ * Attrbute metadata notification. With this callback the director informs this builder that the
+ * currently processed MBean has an attribute with the given metadata.
+ * This builder uses this information in order to add a property and the corresponding accessors
+ * to the capability class that is going to be built.
+ *
+ * @throws BuilderException bytecode manipulation / creation failure.
+ */
+ public void onAttribute(MBeanAttributeInfo attribute) throws BuilderException
+ {
+ String name = attribute.getName();
+ String type = attribute.getType();
+
+ try
+ {
+ type = Class.forName(type).getCanonicalName();
+
+ addPropertyMemberInstance(type, name);
+
+ String nameForAccessors = getNameForAccessors(name);
+
+ if (attribute.isReadable())
+ {
+ String accessor = generateGetter(type, nameForAccessors,name);
+ CtMethod getter = CtNewMethod.make(accessor,_capabilityClassDefinition);
+ _capabilityClassDefinition.addMethod(getter);
+ appendToPropertiesArray(name);
+
+ LOGGER.debug(
+ Messages.QMAN_200043_GENERATED_ACCESSOR_METHOD,
+ _objectName,
+ accessor);
+ }
+
+ if (attribute.isWritable())
+ {
+ String accessor = generateSetter(type, nameForAccessors,name);
+ CtMethod setter = CtNewMethod.make(accessor,_capabilityClassDefinition);
+ _capabilityClassDefinition.addMethod(setter);
+
+ LOGGER.debug(
+ Messages.QMAN_200043_GENERATED_ACCESSOR_METHOD,
+ _objectName,
+ accessor);
+ }
+ } catch(Exception exception)
+ {
+ throw new BuilderException(exception);
+ }
+ }
+
+ public void onOperation(MBeanOperationInfo operation) throws BuilderException
+ {
+ StringBuilder method = new StringBuilder();
+ try
+ {
+ method
+ .append("public Result ")
+ .append(operation.getName())
+ .append("( ");
+
+ for (MBeanParameterInfo parameter: operation.getSignature())
+ {
+ method
+ .append(Class.forName(parameter.getType()).getCanonicalName())
+ .append(' ')
+ .append(parameter.getName())
+ .append(',');
+ }
+
+ method.deleteCharAt(method.length()-1);
+ method.append(") throws EntityInstanceNotFoundFault, MethodInvocationFault,QManFault { return invoke(")
+ .append("\"").append(operation.getName()).append("\"")
+ .append(", new Object[]{ ");
+
+ for (MBeanParameterInfo parameter: operation.getSignature())
+ {
+ method.append(parameter.getName())
+ .append(',');
+ }
+
+ method.deleteCharAt(method.length()-1);
+ method.append("}, new String[]{ ");
+
+ for (MBeanParameterInfo parameter: operation.getSignature())
+ {
+ method
+ .append("\"")
+ .append(parameter.getType())
+ .append("\",");
+ }
+ method.deleteCharAt(method.length()-1);
+ method.append("}); }");
+
+ String methodAsString = method.toString();
+ methodAsString = methodAsString.replace("new Object[]{}","null");
+ methodAsString = methodAsString.replace("new String[]{}","null");
+
+ CtMethod definition = CtNewMethod.make(methodAsString,_capabilityClassDefinition);
+ _capabilityClassDefinition.addMethod(definition);
+ } catch(Exception exception)
+ {
+ throw new BuilderException(exception);
+ } finally {
+ if (LOGGER.isDebugEnabled())
+ {
+ LOGGER.debug(
+ Messages.QMAN_200044_GENERATED_METHOD,
+ _objectName,
+ method.toString());
+ }
+ }
+ }
+
+ public void setEnvironment(Environment environment)
+ {
+ // Nothing to do here...
+ }
+ };
+
+ StringBuilder _properties = new StringBuilder("private static final QName[] PROPERTIES = new QName[]{ ");
+ private Class<MBeanCapability> _capabilityClass;
+ CtClass _capabilityClassDefinition;
+ EndAttributesHandler _endAttributeHandler = _noPropertyHasBeenDefined;
+
+ private ObjectName _objectName;
+
+ IArtifactBuilder _state;
+
+ /**
+ * Director callback.
+ * Attrbute metadata notification. With this callback the director informs this builder that the
+ * currently processed MBean has an attribute with the given metadata.
+ * This builder uses this information in order to add a property and the corresponding accessors
+ * to the capability class that is going to be built.
+ *
+ * @throws BuilderException bytecode manipulation / creation failure.
+ */
+ public void onAttribute(MBeanAttributeInfo attribute) throws BuilderException
+ {
+ _state.onAttribute(attribute);
+ }
+
+ /**
+ * First callback : this method is called at the begin of the director process.
+ * Contains builder initialization code.
+ *
+ * @param objectName the name of the target JMX entity of this capability.
+ * @throws BuilderException when the initialization fails.
+ */
+ @SuppressWarnings("unchecked")
+ public void begin(ObjectName objectName) throws BuilderException
+ {
+ try
+ {
+ this._objectName = objectName;
+ String className = objectName.getKeyProperty(Names.CLASS);
+ _capabilityClass = (Class<MBeanCapability>) Class.forName("org.apache.qpid.management.wsdm.capabilities."+className);
+ _state = new DummyCapabilityBuilder();
+ } catch (ClassNotFoundException exception)
+ {
+ _state = _classNotAvailable;
+ }
+
+ _state.begin(objectName);
+ }
+
+ /**
+ * Director callback.
+ * Operation metadata notification. With this callback the director informs this builder that the
+ * currently processed MBean has an operation with the given metadata.
+ * This builder uses this information in order to add a method to the capability class that is
+ * going to be built.
+ *
+ * For example, let's suppose that an operation like that is detected on the MBean :
+ *
+ * public void purge(int request)
+ *
+ * then the capability will be enrichied with the following method :
+ *
+ * public void purge(int request) throws QManFault {
+ * invoke(
+ * "purge",
+ * new Object[]{request},
+ * new String[]{int.class.getName()});
+ * }
+ *
+ * @throws BuilderException bytecode manipulation / creation failure.
+ */
+ public void onOperation(MBeanOperationInfo operation) throws BuilderException
+ {
+ _state.onOperation(operation);
+ }
+
+ /**
+ * Returns the capability class (the product of this builder).
+ *
+ * @return the capability class (the product of this builder).
+ */
+ Class<MBeanCapability> getCapabilityClass()
+ {
+ return _capabilityClass;
+ }
+
+ /**
+ * Determines what needs to be done when all attributes
+ * metadata has been notified to this builder.
+ * Capability class must have an array member with all defined
+ * properties and a getter method that returns it.
+ * In this method those two members are declared (obviously only
+ * if this capability has at least one property).
+ *
+ * @throws BuilderException when something fails during this phase.
+ */
+ public void endAttributes() throws BuilderException
+ {
+ _state.endAttributes();
+ }
+
+ /**
+ * Director callback.
+ * This method is notified when all operations metadata has been
+ * notified to this builder.
+ * This is the place where the capability class is created, defined and loaded by the JVM.
+ *
+ * @throws BuilderException issues on this method are basically class loading related.
+ */
+ @SuppressWarnings("unchecked")
+ public void endOperations() throws BuilderException
+ {
+ _state.endOperations();
+ }
+
+ /**
+ * Injects the module environment on this builder.
+ *
+ * @param environment the module environment.
+ */
+ public void setEnvironment(Environment environment)
+ {
+ // Nothing to do here...
+ }
+
+ /**
+ * Generates the get accessor method for the given property.
+ *
+ * @param type the type of the property.
+ * @param name the name of the property with the first letter capitalized.
+ * @param plainName the plain name of the property.
+ * @return the getter method (as a string).
+ */
+ String generateGetter(String type, String name,String plainName)
+ {
+ return new StringBuilder()
+ .append("public ")
+ .append(type)
+ .append(' ')
+ .append("get")
+ .append(name)
+ .append("() throws NoSuchAttributeFault,EntityInstanceNotFoundFault,QManFault { return (")
+ .append(type)
+ .append(") getAttribute(\"")
+ .append(plainName)
+ .append("\"); }")
+ .toString();
+ }
+
+ /**
+ * Generates the set accessor method for the given property.
+ *
+ * @param type the type of the property.
+ * @param name the name of the property with the first letter capitalized.
+ * @param plainName the plain name of the property.
+ * @return the setter method (as a string).
+ */
+ String generateSetter(String type, String name, String plainName)
+ {
+ return new StringBuilder()
+ .append("public void ")
+ .append("set")
+ .append(name)
+ .append("(")
+ .append(type)
+ .append(" newValue) throws NoSuchAttributeFault,EntityInstanceNotFoundFault,QManFault {")
+ .append(" setAttribute(\"")
+ .append(plainName)
+ .append("\", newValue); }")
+ .toString();
+ }
+
+ /**
+ * Appends the given attribute name to the properties array declared as an
+ * instance member of the capability class.
+ *
+ * @param attributeName the name of the attribute.
+ */
+ private void appendToPropertiesArray(String attributeName)
+ {
+ _properties.append("new QName(Names.NAMESPACE_URI, \"")
+ .append(attributeName)
+ .append("\", Names.PREFIX),");
+
+ _endAttributeHandler = _atLeastThereIsOneProperty;
+ }
+
+ /**
+ * Adds a new property member instance to the capability class.
+ *
+ * @param type the type of the property.
+ * @param name the name of the property.
+ * @throws CannotCompileException when the property cannot be added.
+ */
+ private void addPropertyMemberInstance(String type, String name) throws CannotCompileException
+ {
+ StringBuilder buffer = new StringBuilder()
+ .append("private ")
+ .append(type)
+ .append(' ')
+ .append(name)
+ .append(';');
+
+ CtField field= CtField.make(buffer.toString(),_capabilityClassDefinition);
+ _capabilityClassDefinition.addField(field);
+ }
+
+ /**
+ * Returns a name that will be used in accessor methods.
+ * That name will differ from the given one because the first letter will be capitalized.
+ * For example, if the given name is "name" the return value will be "Name".
+ *
+ * @param name the plain name of the attribute.
+ * @return a capitalized version of the given name to be used in accessors.
+ */
+ String getNameForAccessors(String name)
+ {
+ return
+ Character.toUpperCase(name.charAt(0)) +
+ name.substring(1);
+ }
+
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/QManAdapterCapability.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/QManAdapterCapability.java
new file mode 100644
index 0000000000..414f37a746
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/QManAdapterCapability.java
@@ -0,0 +1,557 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.capabilities;
+
+import java.lang.management.ManagementFactory;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.Notification;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.AbstractCapability;
+import org.apache.muse.core.Resource;
+import org.apache.muse.core.ResourceManager;
+import org.apache.muse.core.routing.MessageHandler;
+import org.apache.muse.core.serializer.SerializerRegistry;
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.muse.ws.addressing.soap.SoapFault;
+import org.apache.muse.ws.notification.NotificationProducer;
+import org.apache.muse.ws.notification.WsnConstants;
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.configuration.Configuration;
+import org.apache.qpid.management.jmx.EntityLifecycleNotification;
+import org.apache.qpid.management.wsdm.common.ThreadSessionManager;
+import org.apache.qpid.management.wsdm.common.UnableToConnectWithBrokerFault;
+import org.apache.qpid.management.wsdm.muse.engine.WSDMAdapterEnvironment;
+import org.apache.qpid.management.wsdm.muse.serializer.ByteArraySerializer;
+import org.apache.qpid.management.wsdm.notifications.LifeCycleEvent;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * QMan Adapter capability.
+ * Basically it acts as a lifecycle manager of all ws resource that correspond to entities on JMX side.
+ *
+ * @author Andrea Gazzarini
+*/
+@SuppressWarnings("serial")
+public class QManAdapterCapability extends AbstractCapability
+{
+ private final static Logger LOGGER = Logger.get(QManAdapterCapability.class);
+
+ private MBeanServer _mxServer;
+ private WsArtifactsFactory _artifactsFactory;
+ private URI _resourceURI;
+ private NotificationProducer _publisherCapability;
+ private ThreadPoolExecutor _workManager;
+ private Map<String, QName> _lifeCycleTopics = new HashMap<String, QName>();
+
+ /**
+ * Runnable wrapper used for sending asynchronous
+ * notifications.
+ *
+ * @author Andrea Gazzarini
+ */
+ private final class AsynchNotificationTask implements Runnable
+ {
+ private final QName topicName;
+ private final LifeCycleEvent event;
+
+ AsynchNotificationTask(QName tName, LifeCycleEvent evt)
+ {
+ topicName = tName;
+ event = evt;
+ }
+
+ public void run()
+ {
+ try
+ {
+ _publisherCapability.publish(topicName,event);
+ } catch (SoapFault exception)
+ {
+ LOGGER.error(
+ exception,
+ Messages.QMAN_100038_UNABLE_TO_SEND_WS_NOTIFICATION);
+ }
+ }
+ };
+
+ /**
+ * NotificationFilter for "create" only events.
+ */
+ private final NotificationFilter _filterForNewInstances = new NotificationFilter(){
+
+ /**
+ * Returns true when the notification is related to a creation of a new instance.
+ *
+ * @return true when the notification is related to a creation of a new instance.
+ */
+ public boolean isNotificationEnabled(Notification notification)
+ {
+ return EntityLifecycleNotification.INSTANCE_ADDED_NOTIFICATION_TYPE.equals(notification.getType());
+ }
+
+ };
+
+ /**
+ * NotificationFilter for "remove" only events.
+ */
+ private final NotificationFilter _filterForRemovedInstances = new NotificationFilter(){
+
+ /**
+ * Returns true when the notification is related to a deletion of an existing instance.
+ *
+ * @return true when the notification is related to a deletion of an existing instance.
+ */
+ public boolean isNotificationEnabled(Notification notification)
+ {
+ return EntityLifecycleNotification.INSTANCE_REMOVED_NOTIFICATION_TYPE.equals(notification.getType());
+ }
+ };
+
+ /**
+ * This listener handles "create" mbean events and therefore provides procedure to create and initialize
+ * corresponding ws resources.
+ */
+ private final NotificationListener _listenerForNewInstances = new NotificationListener()
+ {
+ /**
+ * Handles JMX "create" notification type.
+ *
+ * @param notification the entity lifecycle notification.
+ * @param data user data associated with the incoming notifiication : it is not used at the moment.
+ */
+ public void handleNotification(Notification notification, Object data)
+ {
+ ObjectName eventSourceName = null;
+ try
+ {
+ EntityLifecycleNotification lifecycleNotification = (EntityLifecycleNotification) notification;
+ eventSourceName = lifecycleNotification.getObjectName();
+
+ ThreadSessionManager.getInstance().getSession().setObjectName(eventSourceName);
+
+ LOGGER.debug(Messages.QMAN_200039_DEBUG_JMX_NOTIFICATION, notification);
+
+ ResourceManager resourceManager = getResource().getResourceManager();
+ Resource resource = resourceManager.createResource(Names.QMAN_RESOURCE_NAME);
+
+ WsArtifacts artifacts = _artifactsFactory.getArtifactsFor(resource,eventSourceName);
+ MBeanCapability capability = _artifactsFactory.createCapability(
+ artifacts.getCapabilityClass(),
+ eventSourceName);
+
+ ThreadSessionManager.getInstance().getSession().setWsdlDocument(artifacts.getWsdl());
+ ThreadSessionManager.getInstance().getSession().setResourceMetadataDescriptor(artifacts.getResourceMetadataDescriptor());
+
+ resource.setWsdlPortType(Names.QMAN_RESOURCE_PORT_TYPE_NAME);
+ capability.setCapabilityURI(Names.NAMESPACE_URI+"/"+capability.getClass().getSimpleName());
+ capability.setMessageHandlers(createMessageHandlers(capability));
+
+ resource.addCapability(capability);
+ resource.initialize();
+ resourceManager.addResource(resource.getEndpointReference(), resource);
+
+ LOGGER.info(
+ Messages.QMAN_000030_RESOURCE_HAS_BEEN_CREATED,
+ eventSourceName);
+
+ AsynchNotificationTask asynchNotificationTask = new AsynchNotificationTask(
+ getTopicName(lifecycleNotification.getClassKind()),
+ LifeCycleEvent.newCreateEvent(
+ eventSourceName.getKeyProperty(Names.OBJECT_ID),
+ lifecycleNotification.getPackageName(),
+ lifecycleNotification.getClassName()));
+
+ _workManager.execute(asynchNotificationTask);
+
+ } catch (ArtifactsNotAvailableException exception)
+ {
+ LOGGER.error(
+ exception,
+ Messages.QMAN_100023_BUILD_WS_ARTIFACTS_FAILURE);
+ } catch (IllegalAccessException exception)
+ {
+ LOGGER.error(
+ exception,
+ Messages.QMAN_100024_CAPABILITY_INSTANTIATION_FAILURE,
+ eventSourceName);
+ } catch (InstantiationException exception)
+ {
+ LOGGER.error(
+ exception,
+ Messages.QMAN_100024_CAPABILITY_INSTANTIATION_FAILURE,
+ eventSourceName);
+ } catch (SoapFault exception)
+ {
+ LOGGER.error(
+ exception,Messages.QMAN_100025_WSRF_FAILURE,
+ eventSourceName);
+ } catch (Exception exception)
+ {
+ LOGGER.error(
+ exception,
+ Messages.QMAN_100025_WSRF_FAILURE,
+ eventSourceName);
+ }
+ }
+ };
+
+ /**
+ * This listener handles "remove" mbean events and therefore provides procedure to shutdown and remove
+ * corresponding ws resources.
+ */
+ private final NotificationListener _listenerForRemovedInstances = new NotificationListener()
+ {
+ /**
+ * Handles JMX "remove" notification type.
+ *
+ * @param notification the entity lifecycle notification.
+ * @param data user data associated with the incoming notifiication : it is not used at the moment.
+ */
+ public void handleNotification(Notification notification, Object data)
+ {
+ EntityLifecycleNotification lifecycleNotification = (EntityLifecycleNotification) notification;
+ ObjectName eventSourceName = lifecycleNotification.getObjectName();
+
+ LOGGER.debug(Messages.QMAN_200042_REMOVING_RESOURCE, eventSourceName);
+
+ EndpointReference endpointPointReference = new EndpointReference(_resourceURI);
+ endpointPointReference.addParameter(
+ Names.RESOURCE_ID_QNAME,
+ eventSourceName.getKeyProperty(Names.OBJECT_ID));
+
+ ResourceManager resourceManager = getResource().getResourceManager();
+ try
+ {
+ Resource resource = resourceManager.getResource(endpointPointReference);
+ resource.shutdown();
+
+ LOGGER.info(
+ Messages.QMAN_000031_RESOURCE_HAS_BEEN_REMOVED,
+ eventSourceName);
+
+ AsynchNotificationTask asynchNotificationTask = new AsynchNotificationTask(
+ getTopicName(lifecycleNotification.getClassKind()),
+ LifeCycleEvent.newRemoveEvent(
+ eventSourceName.getKeyProperty(Names.OBJECT_ID),
+ lifecycleNotification.getPackageName(),
+ lifecycleNotification.getClassName()));
+
+ _workManager.execute(asynchNotificationTask);
+
+ }
+ catch(Exception exception)
+ {
+ LOGGER.error(
+ exception,
+ Messages.QMAN_100027_RESOURCE_SHUTDOWN_FAILURE,
+ eventSourceName);
+ }
+ }
+ };
+
+ /**
+ * Initializes this capability.
+ *
+ * @throws SoapFault when the initialization fails..
+ */
+ @Override
+ public void initialize() throws SoapFault
+ {
+ super.initialize();
+
+ registerByteArraySerializer();
+
+ createLifeCycleTopics();
+
+ initializeWorkManager();
+
+ createQManResourceURI();
+
+ _mxServer = ManagementFactory.getPlatformMBeanServer();
+ _artifactsFactory = new WsArtifactsFactory(getEnvironment(),_mxServer);
+
+ registerQManLifecycleListeners();
+ }
+
+ /**
+ * Connects QMan with a broker with the given connection data.
+ *
+ * @param host the host where the broker is running.
+ * @param port the port number where the broker is running.
+ * @param username username for estabilshing connection.
+ * @param password password for estabilshing connection.
+ * @param virtualHost the virtualHost name.
+ * @param initialPoolCapacity the initial size of broker connection pool.
+ * @param maxPoolCapacity the max allowed size of broker connection pool.
+ * @param maxWaitTimeout the max wait timeout for retrieving connections.
+ * @throws SoapFault when the connection with broker cannot be estabilished.
+ */
+ @SuppressWarnings("unchecked")
+ public void connect(
+ String host,
+ int port,
+ String username,
+ String password,
+ String virtualHost,
+ int initialPoolCapacity,
+ int maxPoolCapacity,
+ long maxWaitTimeout) throws SoapFault
+ {
+ try
+ {
+ _mxServer.invoke(
+ Names.QMAN_OBJECT_NAME,
+ "addBroker",
+ new Object[]{host,port,username,password,virtualHost,initialPoolCapacity,maxPoolCapacity,maxWaitTimeout},
+ new String[]{
+ String.class.getName(),
+ int.class.getName(),
+ String.class.getName(),
+ String.class.getName(),
+ String.class.getName(),
+ int.class.getName(),
+ int.class.getName(),
+ long.class.getName()});
+ } catch(Exception exception)
+ {
+ LOGGER.error(Messages.QMAN_100017_UNABLE_TO_CONNECT,host,port);
+ throw new UnableToConnectWithBrokerFault(
+ getResource().getEndpointReference(),
+ host,
+ port,
+ username,
+ virtualHost,
+ exception.getMessage());
+ }
+ }
+
+ /**
+ * Creates the message handlers for the given capability.
+ *
+ * @param capability the QMan capability.
+ * @return a collection with message handlers for the given capability.
+ */
+ protected Collection<MessageHandler> createMessageHandlers(MBeanCapability capability)
+ {
+ Collection<MessageHandler> handlers = new ArrayList<MessageHandler>();
+
+ for (Method method : capability.getClass().getDeclaredMethods())
+ {
+ String name = method.getName();
+
+ QName requestName = new QName(
+ Names.NAMESPACE_URI,
+ name,
+ Names.PREFIX);
+
+ QName returnValueName = new QName(
+ Names.NAMESPACE_URI,
+ name+"Response",
+ Names.PREFIX);
+
+ String actionURI = Names.NAMESPACE_URI+"/"+name;
+
+ MessageHandler handler = new QManMessageHandler(
+ actionURI,
+ requestName,
+ returnValueName);
+
+ handler.setMethod(method);
+ handlers.add(handler);
+ }
+ return handlers;
+ }
+
+ /**
+ * Returns the publisher capability associated with the owner resource.
+ *
+ * @return the publisher capability associated with the owner resource.
+ */
+ NotificationProducer getPublisherCapability()
+ {
+ return (NotificationProducer) getResource().getCapability(WsnConstants.PRODUCER_URI);
+ }
+
+ /**
+ * Creates events & objects lifecycle topic that will be used to publish lifecycle event
+ * messages..
+ */
+ void createLifeCycleTopics()
+ {
+ try
+ {
+ _publisherCapability = getPublisherCapability();
+
+ _publisherCapability.addTopic(Names.EVENTS_LIFECYLE_TOPIC_NAME);
+ _lifeCycleTopics.put(Names.EVENT,Names.EVENTS_LIFECYLE_TOPIC_NAME);
+
+ LOGGER.info(
+ Messages.QMAN_000032_EVENTS_LIFECYCLE_TOPIC_HAS_BEEN_CREATED,
+ Names.OBJECTS_LIFECYLE_TOPIC_NAME);
+
+ _publisherCapability.addTopic(Names.OBJECTS_LIFECYLE_TOPIC_NAME);
+ _lifeCycleTopics.put(Names.CLASS,Names.OBJECTS_LIFECYLE_TOPIC_NAME);
+
+ LOGGER.info(
+ Messages.QMAN_000033_OBJECTS_LIFECYCLE_TOPIC_HAS_BEEN_CREATED,
+ Names.OBJECTS_LIFECYLE_TOPIC_NAME);
+
+ _publisherCapability.addTopic(Names.UNKNOWN_OBJECT_TYPE_LIFECYLE_TOPIC_NAME);
+ LOGGER.info(
+ Messages.QMAN_000034_UNCLASSIFIED_LIFECYCLE_TOPIC_HAS_BEEN_CREATED,
+ Names.OBJECTS_LIFECYLE_TOPIC_NAME);
+ } catch(Exception exception)
+ {
+ LOGGER.error(exception, Messages.QMAN_100036_TOPIC_DECLARATION_FAILURE);
+ }
+ }
+
+ /**
+ * Starting from an object type (i.e. event or class) returns the name of the
+ * corresponding topic where the lifecycle message must be published.
+ * Note that if the given object type is unknown then the "Unclassified Object Types" topic
+ * will be returned (and therefore the message will be published there).
+ *
+ * @param objectType the type of the object.
+ * @return the name of the topic associated with the given object type.
+ */
+ QName getTopicName(String objectType)
+ {
+ QName topicName = _lifeCycleTopics.get(objectType);
+ return (topicName != null)
+ ? topicName
+ : Names.UNKNOWN_OBJECT_TYPE_LIFECYLE_TOPIC_NAME;
+ }
+
+ /**
+ * Workaround : it seems that is not possibile to declare a serializer
+ * for a byte array using muse descriptor...
+ * What is the stringified name of the class?
+ * byte[].getClass().getName() is [B but is not working (ClassNotFound).
+ * So, at the end, this is hard-coded here!
+ */
+ private void registerByteArraySerializer()
+ {
+ SerializerRegistry.getInstance().registerSerializer(
+ byte[].class,
+ new ByteArraySerializer());
+ }
+
+ /**
+ * Creates the URI that will be later used to identify a QMan WS-Resource.
+ * Note that the resources that will be created are identified also with their resource id.
+ * Briefly we could say that this is the soap:address of the WS-Resource definition.
+ *
+ * @throws SoapFault when the URI cannot be built (probably it is malformed).
+ */
+ private void createQManResourceURI() throws SoapFault
+ {
+ WSDMAdapterEnvironment environment = (WSDMAdapterEnvironment) getEnvironment();
+ String resourceURI = environment.getDefaultURIPrefix()+Names.QMAN_RESOURCE_NAME;
+ try
+ {
+ _resourceURI = URI.create(resourceURI);
+
+ } catch(IllegalArgumentException exception)
+ {
+ LOGGER.info(
+ exception,
+ Messages.QMAN_100029_MALFORMED_RESOURCE_URI_FAILURE,
+ resourceURI);
+ throw new SoapFault(exception);
+ }
+ }
+
+ /**
+ * Initializes the work manager used for asynchronous notifications.
+ */
+ private void initializeWorkManager()
+ {
+ Configuration configuration = Configuration.getInstance();
+ _workManager = new ThreadPoolExecutor(
+ configuration.getWorkerManagerPoolSize(),
+ configuration.getWorkerManagerMaxPoolSize(),
+ configuration.getWorkerManagerKeepAliveTime(),
+ TimeUnit.MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(30));
+ }
+
+ /**
+ * This adapter capability needs to be an event listener of QMan JMX core
+ * in order to detect relevant lifecycle events and therefore create WS artifacts & notification(s).
+ *
+ * @throws SoapFault when it's not possible to register event listener : is QMan running?
+ */
+ @SuppressWarnings("serial")
+ private void registerQManLifecycleListeners() throws SoapFault
+ {
+ try
+ {
+ _mxServer.addNotificationListener(
+ Names.QMAN_OBJECT_NAME,
+ _listenerForNewInstances,
+ _filterForNewInstances,
+ null);
+
+ _mxServer.addNotificationListener(
+ Names.QMAN_OBJECT_NAME,
+ _listenerForRemovedInstances,
+ _filterForRemovedInstances,
+ null);
+
+ try
+ {
+ _mxServer.addNotificationListener(
+ Names.QPID_EMULATOR_OBJECT_NAME,
+ _listenerForNewInstances,
+ _filterForNewInstances, null);
+
+ _mxServer.addNotificationListener(
+ Names.QPID_EMULATOR_OBJECT_NAME,
+ _listenerForRemovedInstances,
+ _filterForRemovedInstances, null);
+
+ } catch (Exception exception)
+ {
+ LOGGER.info(Messages.QMAN_000028_TEST_MODULE_NOT_FOUND);
+ }
+ } catch(InstanceNotFoundException exception)
+ {
+ throw new SoapFault(exception);
+ }
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/QManMessageHandler.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/QManMessageHandler.java
new file mode 100644
index 0000000000..95f54ef5b5
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/QManMessageHandler.java
@@ -0,0 +1,104 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.capabilities;
+
+import java.lang.reflect.Method;
+
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.routing.ReflectionMessageHandler;
+import org.apache.muse.core.serializer.Serializer;
+import org.apache.muse.core.serializer.SerializerRegistry;
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.addressing.soap.SoapFault;
+import org.apache.qpid.management.wsdm.muse.serializer.ByteArraySerializer;
+import org.w3c.dom.Element;
+
+/**
+ * JMXConnectionListener_example custom implementation of Muse message handler to properly deal with
+ * byte arrays.
+ *
+ * @author Andrea Gazzarini
+ */
+public class QManMessageHandler extends ReflectionMessageHandler
+{
+
+ /**
+ * Builds a new message handler with the given arguments.
+ *
+ * @param actionURI the action URI.
+ * @param requestQName the qname of the incoming request.
+ * @param returnValueName the qname of the result value.
+ */
+ public QManMessageHandler(String actionURI, QName requestQName,
+ QName returnValueName)
+ {
+ super(actionURI, requestQName, returnValueName);
+ }
+
+ /**
+ * Transforms the given xml element in the corresponding
+ * object representation.
+ *
+ * @throws SoapFaul when unmarshal operation fails.
+ */
+ @SuppressWarnings("unchecked")
+ public Object[] fromXML(Element xml) throws SoapFault
+ {
+ Method method = getMethod();
+
+ if (xml == null )
+ {
+ return EMPTY_REQUEST;
+ }
+
+ Class[] parameters = method.getParameterTypes();
+ Object[] objects = new Object[parameters.length];
+
+ Element[] elements = XmlUtils.getAllElements(xml);
+
+ if (parameters.length == 1 && elements.length == 0)
+ {
+ elements = new Element[]{ xml };
+ }
+
+ if (elements.length != parameters.length)
+ {
+ throw new SoapFault("IncorrectParams");
+ }
+
+ SerializerRegistry registry = SerializerRegistry.getInstance();
+
+ for (int i = 0; i < elements.length; ++i)
+ {
+ Class clazz = parameters[i];
+ if (clazz == byte[].class)
+ {
+ objects[i] = new ByteArraySerializer().fromXML(elements[i]);
+ } else
+ {
+ Serializer ser = registry.getSerializer(parameters[i]);
+ objects[i] = ser.fromXML(elements[i]);
+ }
+ }
+ return objects;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/QManMetadataExchangeCapability.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/QManMetadataExchangeCapability.java
new file mode 100644
index 0000000000..d6255d0bed
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/QManMetadataExchangeCapability.java
@@ -0,0 +1,99 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.capabilities;
+
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.metadata.WsxConstants;
+import org.apache.muse.ws.resource.WsResource;
+import org.apache.muse.ws.resource.metadata.MetadataDescriptor;
+import org.apache.muse.ws.resource.metadata.WsrmdConstants;
+import org.apache.muse.ws.resource.metadata.ext.WsrfMetadataExchange;
+import org.apache.muse.ws.wsdl.WsdlUtils;
+import org.apache.qpid.management.wsdm.muse.resources.QManWsResource;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * QMan resource metadata exchange.
+ * We cannot resuse the preexisting classes directly because the wsdl of the service instance
+ * is retrieved using a file path.
+ * Since the owner resource (QManWsResource) is dynamic (I mean, its interface is dynamic), the corresponding
+ * WSDL cannot defined at compile time but needs some changes when the resource is created.
+ * As part of that, the WSDL template found under wsdl folder is modified with the additional properties of the given
+ * resource. The metadata exchange capability must include those properties too.
+ *
+ * Note that this capability is appliable only to a QManWsResource.
+ *
+ * @author Andrea Gazzarini
+ */
+public class QManMetadataExchangeCapability extends WsrfMetadataExchange
+{
+ /**
+ * Returns the WSDL associated with the owner of this capability.
+ *
+ * @return the WSDL associated with the owner of this capability.
+ */
+ @Override
+ protected Element getWSDL()
+ {
+ QManWsResource resource = (QManWsResource) getResource();
+
+ Document wsdlDoc = resource.getWsdl();
+ Element wsdl = XmlUtils.getFirstElement(wsdlDoc);
+
+ WsdlUtils.removeWsdlReferences(wsdl);
+ WsdlUtils.removeSchemaReferences(wsdl);
+
+ return wsdl;
+ }
+
+ /**
+ * Returns the resource metadata descriptor associated with the owenr
+ * resource of thi capability.
+ *
+ * @return the resource metadata descriptor.
+ */
+ protected Element getResourceMetadataDescriptor()
+ {
+ WsResource resource = (WsResource)getResource();
+ MetadataDescriptor metadataDescriptor = resource.getPropertyCollection().getMetadata();
+ return metadataDescriptor.toXML();
+ }
+
+ public Element[] getMetadata(String dialect)
+ {
+ if (dialect == null)
+ {
+ return new Element[]{
+ getResourceMetadataDescriptor(),
+ getWSDL()};
+ } else {
+ if (WsrmdConstants.NAMESPACE_URI.equals(dialect))
+ {
+ return new Element[]{getResourceMetadataDescriptor()};
+ } else if (WsxConstants.WSDL_DIALECT.equals(dialect))
+ {
+ return new Element[]{getWSDL()};
+ }
+ }
+ return super.getMetadata(dialect);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/Result.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/Result.java
new file mode 100644
index 0000000000..a00d2665ae
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/Result.java
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.capabilities;
+
+import java.util.*;
+
+/**
+ * Data Transfer Object that encapsulates the result of a method invocation.
+ * This is the object that will be marshalled in XML and will contain the result of a method
+ * invocation (status code & text).
+ *
+ * @author Andrea Gazzarini
+ */
+public final class Result
+{
+ private final Map<String,Object> _outputParameters;
+
+ /**
+ * Builds a new result DTO with the given parameters.
+ *
+ * @param statusCode the return code.
+ * @param statusText the status message.
+ * @param outputParameters the output parameters.
+ */
+ public Result(Map<String, Object> outputParameters)
+ {
+ this._outputParameters = outputParameters;
+ }
+
+ /**
+ * Returns the output parameterss.
+ *
+ * @return the output parameterss.
+ */
+ public Map<String, Object> getOutputParameters()
+ {
+ return _outputParameters;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/RmdBuilder.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/RmdBuilder.java
new file mode 100644
index 0000000000..c1678eb43f
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/RmdBuilder.java
@@ -0,0 +1,135 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.capabilities;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.ObjectName;
+
+import org.apache.muse.core.Environment;
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.resource.metadata.WsrmdConstants;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.qman.debug.WsdlDebugger;
+import org.w3c.dom.Element;
+
+/**
+ * Resource Metadata Descriptor Builder.
+ * It is used for build the metadata descriptor for properties of the
+ * incoming jmx object.
+ *
+ * @author Andrea Gazzarini
+ */
+class RmdBuilder implements IArtifactBuilder
+{
+ private List<Element> _metadataDescriptor = new ArrayList<Element>();
+
+ ObjectName _objectName;
+
+ /**
+ * Nothing to be done here on this builder.
+ * Simply logs a message indicating the target object name.
+ *
+ * @param objectName the jmx name of the object that is going to be processed.
+ */
+ public void begin(ObjectName objectName)
+ {
+ this._objectName = objectName;
+ }
+
+ /**
+ * Nothing to be done here on this builder.
+ *
+ * @throws BuilderException never.
+ */
+ public void endAttributes()
+ {
+ // N.A. for this builder.
+ }
+
+ /**
+ * Nothing to be done here on this builder.
+ *
+ * @throws BuilderException never.
+ */
+ public void endOperations()
+ {
+ // N.A. for this builder.
+ }
+
+ /**
+ * Process a single attribute metadata.
+ * An attribute (that is, a property) represented by the corresponding incoming
+ * attribute metadata will generate an wsrmd:Property xml element with the constraints
+ * (initial values, static values, allowed values) contained on the metadata.
+ *
+ * @param attributeMetadata the attribute (jmx) metadata.
+ */
+ public void onAttribute(MBeanAttributeInfo attributeMetadata)
+ {
+ Element property = XmlUtils.createElement(WsrmdConstants.PROPERTY_QNAME);
+ property.setAttribute(Names.NAME_ATTRIBUTE, Names.PREFIX+":"+attributeMetadata.getName());
+ property.setAttribute(Names.MODIFIABILITY,
+ attributeMetadata.isWritable()
+ ? Names.READ_WRITE
+ : Names.READ_ONLY);
+ property.setAttribute(Names.MUTABILITY,Names.MUTABLE);
+
+ WsdlDebugger.debug(_objectName, property);
+
+ _metadataDescriptor.add(property);
+ }
+
+ /**
+ * Nothing to be done here on this builder.
+ *
+ * @throws BuilderException never.
+ */
+ public void onOperation(MBeanOperationInfo operation)
+ {
+ // N.A. for this builder
+ }
+
+ /**
+ * Nothing to be done here on this builder.
+ *
+ * @throws BuilderException never.
+ */
+ public void setEnvironment(Environment environment)
+ {
+ // N.A. for this builder
+ }
+
+ /**
+ * Nothing to be done here on this builder.
+ *
+ * @throws BuilderException never.
+ */
+ public Element[] getResourceMetadataDescriptor()
+ {
+ Element [] properties = _metadataDescriptor.toArray(
+ new Element[_metadataDescriptor.size()]);
+ return properties;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WSDMArtifactsDirector.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WSDMArtifactsDirector.java
new file mode 100644
index 0000000000..35a919c295
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WSDMArtifactsDirector.java
@@ -0,0 +1,196 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.capabilities;
+
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.ObjectName;
+
+import org.apache.muse.core.Environment;
+import org.apache.muse.core.Resource;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Director used for coordinate the building process of WS-DM artifacts.
+ *
+ * @author Andrea Gazzarini
+ */
+final class WSDMArtifactsDirector
+{
+ private final ObjectName _eventSourceObjectName;
+ private final MBeanInfo _metadata;
+
+ private final MBeanCapabilityBuilder _capabilityBuilder;
+ private final WsdlBuilder _wsdlBuilder;
+ private final RmdBuilder _rmdBuilder;
+
+ /**
+ * Builds a new director with the given objectname and (jmx) metadata.
+ *
+ * @param eventSourceObjectName the object name of the event source mbean.
+ * @param metadata the jmx metadata of the corresponding mbean.
+ */
+ WSDMArtifactsDirector(ObjectName eventSourceObjectName, MBeanInfo metadata)
+ {
+ this._eventSourceObjectName = eventSourceObjectName;
+ this._metadata = metadata;
+
+ _wsdlBuilder = new WsdlBuilder();
+ _capabilityBuilder = new MBeanCapabilityBuilder();
+ _rmdBuilder = new RmdBuilder();
+ }
+
+ /**
+ * Starts the build process of this director.
+ * This method acts as a facade of the whole build process.
+ *
+ * @throws BuilderException when one step of the build process fails.
+ */
+ void direct() throws BuilderException
+ {
+ processObjectName();
+ processAttributes();
+ endAttributes();
+ processOperations();
+ endOperations();
+ }
+
+ /**
+ * Notifiies builder that all the operations metadata have been transmitted.
+ *
+ * @throws BuilderException when one builder raises an exception during this operation.
+ */
+ private void endOperations() throws BuilderException
+ {
+ _capabilityBuilder.endOperations();
+ _wsdlBuilder.endOperations();
+ _rmdBuilder.endOperations();
+ }
+
+ /**
+ * Notifiies builder that all the attributes metadata have been transmitted.
+ *
+ * @throws BuilderException when one builder raises an exception during this operation.
+ */
+ private void endAttributes() throws BuilderException
+ {
+ _capabilityBuilder.endAttributes();
+ _wsdlBuilder.endAttributes();
+ _rmdBuilder.endAttributes();
+ }
+
+ /**
+ * Injects event source object name on all builders.
+ *
+ * @throws BuilderException when one builder raises an exception during this operation.
+ */
+ void processObjectName() throws BuilderException
+ {
+ _capabilityBuilder.begin(_eventSourceObjectName);
+ _wsdlBuilder.begin(_eventSourceObjectName);
+ _rmdBuilder.begin(_eventSourceObjectName);
+ }
+
+ /**
+ * Injects attributes metadata on all builders.
+ *
+ * @throws BuilderException when one builder raises an exception during this operation.
+ */
+ void processAttributes() throws BuilderException
+ {
+ for (MBeanAttributeInfo attribute : _metadata.getAttributes())
+ {
+ _capabilityBuilder.onAttribute(attribute);
+ _wsdlBuilder.onAttribute(attribute);
+ _rmdBuilder.onAttribute(attribute);
+ }
+ }
+
+ /**
+ * Injects operations metadata on all builders.
+ *
+ * @throws BuilderException when one builder raises an exception during this operation.
+ */
+ void processOperations() throws BuilderException
+ {
+ for (MBeanOperationInfo operation : _metadata.getOperations())
+ {
+ _capabilityBuilder.onOperation(operation);
+ _wsdlBuilder.onOperation(operation);
+ }
+ }
+
+ /**
+ * Returns the capabilty class.
+ *
+ * @return the capability class.
+ */
+ Class<MBeanCapability> getCapabilityClass()
+ {
+ return _capabilityBuilder.getCapabilityClass();
+ }
+
+ /**
+ * Returns the wsdl.
+ *
+ * @return the wsdl.
+ */
+ Document getWsdl()
+ {
+ return _wsdlBuilder.getWsdl();
+ }
+
+ /**
+ * Returns the resource metadata descriptor containing metadata (rules, constraints, etc)
+ * for the current resource.
+ * The returned object is an array of Element and each of them maps a resource property.
+ *
+ * @return the resource metadata descriptor (as an array of Element).
+ */
+ Element [] getResourceMetadataDescriptor()
+ {
+ return _rmdBuilder.getResourceMetadataDescriptor();
+ }
+
+ /**
+ * Injects the environment on this director.
+ *
+ * @param environment the QMan environment.
+ */
+ void setEnvironment(Environment environment)
+ {
+ _wsdlBuilder.setEnvironment(environment);
+ _capabilityBuilder.setEnvironment(environment);
+ _rmdBuilder.setEnvironment(environment);
+ }
+
+ /**
+ * Injectcs the ws resource on this director.
+ *
+ * @param resource the ws resource.
+ */
+ public void setResource(Resource resource)
+ {
+ _wsdlBuilder.setWsdlPath(resource.getWsdlPath());
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsArtifacts.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsArtifacts.java
new file mode 100644
index 0000000000..ac4636b9c9
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsArtifacts.java
@@ -0,0 +1,93 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.capabilities;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Web Service Artifacts.
+ * Basically it acts as a container for all artifacts built when a new WS-Resource is created.
+ * With WS artifacts we mean :
+ *
+ * <ul>
+ * <li>Capability class (which encapsulate the WS-DM capability concern)</li>
+ * <li>WS Resource Metadata Descriptor (RMD)</li>
+ * <li>Web Service Description (WSDL)</li>
+ * </ul>
+ *
+ * @author Andrea Gazzarini
+ */
+class WsArtifacts {
+
+ private final Class<MBeanCapability>_capabilityClass;
+ private final Element[] _resourceMetadataDescriptor;
+ private final Document _wsdl;
+
+ /**
+ * Builds a new artifacts container with the given artifacts.
+ *
+ * @param capabilityClass the capability class.
+ * @param resourceMetadataDescriptor the resource metadata descriptor.
+ * @param wsdl the wsdl.
+ */
+ public WsArtifacts(
+ Class<MBeanCapability> capabilityClass,
+ Element[] resourceMetadataDescriptor,
+ Document wsdl)
+ {
+ this._capabilityClass = capabilityClass;
+ this._resourceMetadataDescriptor = resourceMetadataDescriptor;
+ this._wsdl = wsdl;
+ }
+
+ /**
+ * Returns the capability class.
+ *
+ * @return the capability class.
+ */
+ Class<MBeanCapability> getCapabilityClass()
+ {
+ return _capabilityClass;
+ }
+
+ /**
+ * Returns the resource metadata descriptor.
+ * It is not a whole document but each property metadata is described in a
+ * separated element so the returned object is an array of elements.
+ *
+ * @return the resource metadata descriptor.
+ */
+ Element[] getResourceMetadataDescriptor()
+ {
+ return _resourceMetadataDescriptor;
+ }
+
+ /**
+ * Returns the web service description.
+ *
+ * @return the web service description (WSDL).
+ */
+ Document getWsdl()
+ {
+ return _wsdl;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsArtifactsFactory.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsArtifactsFactory.java
new file mode 100644
index 0000000000..94505d28f7
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsArtifactsFactory.java
@@ -0,0 +1,140 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.capabilities;
+
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import javax.management.MBeanInfo;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.muse.core.Environment;
+import org.apache.muse.core.Resource;
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * Manager for all WS-* related artifacts.
+ * Basically it is a factory ehnanced with a _cache mechanism so each created resource
+ * (WSDL, capability class, descriptor) is created and its reference is returned when requested
+ * again.
+ *
+ * @author Andrea Gazzarini
+ */
+class WsArtifactsFactory
+{
+ private final static Logger LOGGER = Logger.get(WsArtifactsFactory.class);
+
+ private final MBeanServer _mxServer;
+ private final Environment _environment;
+ private Map<ObjectName, WsArtifacts> _cache;
+
+ /**
+ * Builds a new factory with the given environment and mbean server.
+ *
+ * @param environment the builder environment.
+ * @param mxServer the management server.
+ */
+ public WsArtifactsFactory(Environment environment, MBeanServer mxServer)
+ {
+ this._environment = environment;
+ this._mxServer = mxServer;
+ this._cache = new HashMap<ObjectName, WsArtifacts>();
+ }
+
+ /**
+ * Returns the WS artifacts corresponding with the given resource.
+ *
+ * @param resource the WS resource.
+ * @param objectName the resource identifier (name).
+ * @return the WS artifacts corresponding with the given resource.
+ * @throws ArtifactsNotAvailableException when some problem occurs during artifacts generation.
+ */
+ @SuppressWarnings("unchecked")
+ WsArtifacts getArtifactsFor(Resource resource, ObjectName objectName) throws ArtifactsNotAvailableException
+ {
+ WsArtifacts result = null;
+ try
+ {
+ Hashtable<String, String> keyProperties = objectName.getKeyPropertyList();
+ keyProperties.remove(Names.NAME_ATTRIBUTE);
+ keyProperties.remove(Names.OBJECT_ID);
+
+ ObjectName searchKey = ObjectName.getInstance(objectName.getDomain(),keyProperties);
+
+ LOGGER.debug(
+ Messages.QMAN_200041_INCOMING_OBJECT_NAME_AND_DERIVED_KEY,
+ objectName,
+ searchKey);
+
+ result = _cache.get(searchKey);
+ if (result == null)
+ {
+ MBeanInfo metadata = _mxServer.getMBeanInfo(objectName);
+
+ WSDMArtifactsDirector director = new WSDMArtifactsDirector(objectName,metadata);
+ director.setEnvironment(_environment);
+ director.setResource(resource);
+ director.direct();
+
+ result = new WsArtifacts(
+ director.getCapabilityClass(),
+ director.getResourceMetadataDescriptor(),
+ director.getWsdl());
+
+ _cache.put(searchKey, result);
+
+ LOGGER.debug(
+ Messages.QMAN_200040_WS_ARTIFACTS_CACHED,
+ searchKey);
+ }
+
+ return result;
+ } catch(Exception exception)
+ {
+ throw new ArtifactsNotAvailableException(
+ result,
+ exception,
+ objectName);
+ }
+ }
+
+ /**
+ * Utility method for create concrete instance of the given capability class.
+ *
+ * @param capabilityClass the capability class.
+ * @param objectName the object name that will act as the target for this capability invocations.
+ * @return an initialized instance of the given capability class.
+ * @throws InstantiationException when the class cannot be instantiated.
+ * @throws IllegalAccessException when this method does not have access to
+ * the definition of the capability class.
+ */
+ MBeanCapability createCapability(Class<MBeanCapability> capabilityClass, ObjectName objectName)
+ throws InstantiationException, IllegalAccessException
+ {
+ MBeanCapability capability = capabilityClass.newInstance();
+ capability.setResourceObjectName(objectName);
+ return capability;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsdlBuilder.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsdlBuilder.java
new file mode 100644
index 0000000000..6bfccda1ce
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/capabilities/WsdlBuilder.java
@@ -0,0 +1,460 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.capabilities;
+
+import java.net.InetAddress;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+import javax.management.ObjectName;
+import javax.xml.transform.TransformerException;
+
+import org.apache.muse.core.Environment;
+import org.apache.muse.core.serializer.SerializerRegistry;
+import org.apache.muse.util.ReflectUtils;
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.wsdl.WsdlUtils;
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.wsdm.muse.engine.WSDMAdapterEnvironment;
+import org.apache.qpid.management.wsdm.muse.serializer.ObjectSerializer;
+import org.apache.qpid.qman.debug.WsdlDebugger;
+import org.apache.qpid.transport.util.Logger;
+import org.apache.xpath.XPathAPI;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+/**
+ * TO BE IMPROVED USING JAXB!!
+ *
+ * @author Andrea Gazzarini
+ */
+class WsdlBuilder implements IArtifactBuilder,Constants {
+
+ private final static Logger LOGGER = Logger.get(WsdlBuilder.class);
+
+ private WSDMAdapterEnvironment _environment;
+ private Document _document;
+ private Element schema;
+ private Element _wsrpProperties;
+ private ObjectSerializer _serializer;
+ private ObjectName _objectName;
+ private Map<String, String> arrayTypesAlreadyDeclared = new HashMap<String, String>();
+
+ private Element _arrayComplexType;
+ private Element _nestedArrayType;
+
+ /**
+ * For each attibute the corresponding xml type definition must be inserted on the QMan
+ * schema related section.
+ * After that, a reference to that definition must be declared on the wsrp element .
+ *
+ * @param attributeMetadata the attribute metadata.
+ * @throws BuilderException only if this builder wasn't able to get a reference (via XPath)
+ * to QMan schema section.
+ */
+ public void onAttribute(MBeanAttributeInfo attributeMetadata) throws BuilderException
+ {
+ try
+ {
+ String attributeName = attributeMetadata.getName();
+ schema.appendChild(defineSchemaFor(attributeMetadata.getType(), attributeName));
+
+ Element propertyRef= XmlUtils.createElement(_document, XSD_ELEMENT_QNAME);
+ propertyRef.setAttribute(MIN_OCCURS, "0");
+ propertyRef.setAttribute(
+ REF_ATTRIBUTE,
+ Names.PREFIX+":"+attributeName);
+
+ _wsrpProperties.appendChild(propertyRef);
+ } catch(Exception exception)
+ {
+ throw new BuilderException(exception);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private Element defineSchemaFor(String type, String attributeName) throws Exception
+ {
+ Element propertyDeclaration = XmlUtils.createElement(_document, XSD_ELEMENT_QNAME);
+ String xmlType = null;
+ if (type.equals(Map.class.getName()))
+ {
+ xmlType="qman:map";
+ } else if (UUID.class.getName().equals(type))
+ {
+ xmlType = "qman:uuid";
+ } else if (type.startsWith("["))
+ {
+ Class arrayClass = Class.forName(type);
+ Class clazz = ReflectUtils.getClassFromArrayClass(arrayClass);
+ String arrayType = arrayClass.getSimpleName().replace("[]", "").trim();
+ arrayType = Character.toUpperCase(arrayType.charAt(0))+arrayType.substring(1);
+ if (!arrayTypesAlreadyDeclared.containsKey(type))
+ {
+ _arrayComplexType.setAttribute(NAME_ATTRIBUTE, "arrayOf"+arrayType);
+ _nestedArrayType.setAttribute(TYPE_ATTRIBUTE, _serializer.getXmlType(clazz));
+ schema.appendChild(_arrayComplexType);
+ arrayTypesAlreadyDeclared.put(type, arrayType);
+ }
+ xmlType = "qman:arrayOf"+arrayTypesAlreadyDeclared.get(type);
+ }
+ else
+ {
+ xmlType = _serializer.getXmlType(Class.forName(type));
+ }
+ propertyDeclaration.setAttribute(NAME_ATTRIBUTE,attributeName);
+ propertyDeclaration.setAttribute(TYPE_ATTRIBUTE, xmlType);
+ return propertyDeclaration;
+ }
+
+ /**
+ * Initializes this builder.
+ *
+ * @param objectName the name of the current JMX entity.
+ * @throws BuilderException when it's not possible to proceed with the initialization.
+ */
+ public void begin(ObjectName objectName) throws BuilderException
+ {
+ this._objectName = objectName;
+ this._serializer = (ObjectSerializer) SerializerRegistry.getInstance().getSerializer(Object.class);
+
+ createWsrpPropertiesElement();
+
+ createReusableArrayComplextType();
+
+ replaceDummyServiceLocationOnWsdl();
+
+ createSchemaElement();
+ }
+
+ public void onOperation(MBeanOperationInfo operationMetadata) throws BuilderException
+ {
+ // SCHEMA SECTION
+ /*
+ <xs:element name='purgeRequest' type='qman:purgeRequest' />
+
+ <xs:element name='purgeResponse' type='qman:purgeResponse' />
+
+ <xs:complexType name='purgeRequest'>
+ <xs:sequence>
+ <xs:element name='arg0' type='xs:int' />
+ <xs:element minOccurs='0' name='arg1' type='qman:hashMap' />
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:element name='hashMap'>
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element maxOccurs='unbounded' minOccurs='0' name='entry'>
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element minOccurs='0' name='key' type='xs:string'/>
+ <xs:element minOccurs='0' name='value' type='xs:anyType'/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:complexType name='purgeResponse'>
+ <xs:sequence />
+ </xs:complexType>
+ */
+
+ try
+ {
+ // <xsd:element xmlns="" name="purgeRequest" type="qman:purgeRequest"/>
+
+ Element methodRequestElement= _document.createElement("xsd:element");
+ String methodNameRequest = operationMetadata.getName()+"Request";
+ methodRequestElement.setAttribute("name", methodNameRequest);
+ methodRequestElement.setAttribute("type", "qman:"+methodNameRequest);
+
+ // <xs:element name='purgeResponse' type='qman:purgeResponse' />
+// Element methodResponseElement= _document.createElement("xsd:element");
+ String methodNameResponse= operationMetadata.getName()+"Response";
+// methodResponseElement.setAttribute("name", methodNameResponse);
+// methodResponseElement.setAttribute("type", "qman:result");//+methodNameResponse);
+
+ schema.appendChild(methodRequestElement);
+// schema.appendChild(methodResponseElement);
+
+ /*
+ <xs:complexType name='purgeRequest'>
+ <xs:sequence>
+ <xs:element name='arg0' type='xs:int' />
+ <xs:element minOccurs='0' name='arg1' type='qman:hashMap' />
+ </xs:sequence>
+ </xs:complexType>
+
+ */
+
+ Element methodNameRequestComplexType = _document.createElement("xsd:complexType");
+ methodNameRequestComplexType.setAttribute("name", methodNameRequest);
+ Element methodNameRequestComplexTypeSequence = _document.createElement("xsd:sequence");
+
+ for(MBeanParameterInfo parameter : operationMetadata.getSignature())
+ {
+ methodNameRequestComplexTypeSequence.appendChild(defineSchemaFor(parameter.getType(), parameter.getName()));
+ }
+
+ methodNameRequestComplexType.appendChild(methodNameRequestComplexTypeSequence);
+ schema.appendChild(methodNameRequestComplexType);
+
+ /*
+ <message name="purgeResponseMessage">
+ <part element='qman:purgeResponse' name='purgeResponse'></part>
+ </message>
+
+ <message name='purgeRequestMessage'>
+ <part element="qman:purgeRequest" name='purgeRequest'></part>
+ </message>
+ */
+ Element definitions = (Element) XPathAPI.selectSingleNode(_document, "/wsdl:definitions");
+
+ String requestMessageName = methodNameRequest+"Message";
+ String responseMessageName = methodNameResponse+"Message";
+
+ Element requestMessage = _document.createElement("message");
+ requestMessage.setAttribute("name", requestMessageName);
+ Element requestPart = _document.createElement("wsdl:part");
+ requestPart.setAttribute("element", "qman:"+methodNameRequest);
+ requestPart.setAttribute("name", methodNameRequest);
+ requestMessage.appendChild(requestPart);
+
+ Element responseMessage = _document.createElement("wsdl:message");
+ responseMessage.setAttribute("name", responseMessageName);
+ Element responsePart = _document.createElement("wsdl:part");
+ responsePart.setAttribute("element", "qman:result");//+methodNameResponse);
+ responsePart.setAttribute("name", methodNameResponse);
+ responseMessage.appendChild(responsePart);
+
+ definitions.appendChild(requestMessage);
+ definitions.appendChild(responseMessage);
+
+
+ /*
+ <operation name='purge'>
+ <input message="qman:purgeRequestMessage">
+ </input>
+ <output message='qman:purgeResponseMessage'>
+ </output>
+ </operation>
+ */
+ Element portType = (Element) XPathAPI.selectSingleNode(_document, "/wsdl:definitions/wsdl:portType");
+ Element operation = _document.createElement("wsdl:operation");
+ operation.setAttribute("name", operationMetadata.getName());
+
+ Element input = _document.createElement("wsdl:input");
+ input.setAttribute("message", "qman:"+requestMessageName);
+ input.setAttribute("name", methodNameRequest);
+ input.setAttribute("wsa:action", Names.NAMESPACE_URI+"/"+operationMetadata.getName());
+
+ //name="SetResourcePropertiesRequest" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/SetResourceProperties/SetResourcePropertiesRequest"/>
+
+ operation.appendChild(input);
+
+ Element output = _document.createElement("wsdl:output");
+ output.setAttribute("message", "qman:"+responseMessageName);
+ output.setAttribute("name", methodNameResponse);
+ output.setAttribute("wsa:action", Names.NAMESPACE_URI+"/"+methodNameResponse);
+
+ operation.appendChild(output);
+
+ portType.appendChild(operation);
+
+ /*
+ <operation name='purge'>
+ <soap:operation soapAction='purge' />
+ <input>
+ <soap:body use='literal' />
+ </input>
+ <output>
+ <soap:body use='literal' />
+ </output>
+ </operation>
+ */
+ Element binding = (Element) XPathAPI.selectSingleNode(_document, "/wsdl:definitions/wsdl:binding");
+ Element bindingOperation = _document.createElement("wsdl:operation");
+ bindingOperation.setAttribute("name", operationMetadata.getName());
+
+ Element soapOperation = _document.createElement("wsdl-soap:operation");
+ soapOperation.setAttribute("soapAction", Names.NAMESPACE_URI+"/"+operationMetadata.getName());
+
+ Element bindingInput = _document.createElement("wsdl:input");
+ Element bodyIn = _document.createElement("wsdl-soap:body");
+ bodyIn.setAttribute("use", "literal");
+
+ Element bindingOutput = _document.createElement("wsdl:output");
+ Element bodyOut = _document.createElement("wsdl-soap:body");
+ bodyOut.setAttribute("use", "literal");
+
+ bindingOutput.appendChild(bodyOut);
+ bindingInput.appendChild(bodyIn);
+
+ bindingOperation.appendChild(soapOperation);
+ bindingOperation.appendChild(bindingInput);
+ bindingOperation.appendChild(bindingOutput);
+
+ binding.appendChild(bindingOperation);
+ } catch(Exception exception)
+ {
+ throw new BuilderException(exception);
+ }
+ }
+
+ /**
+ * Director callback : all attributes have been notified.
+ * Nothing to do here.
+ */
+ public void endAttributes()
+ {
+ // N.A.
+ }
+
+ /**
+ * Director callback : all operations have been notified.
+ * Nothing to do here.
+ */
+ public void endOperations()
+ {
+ // N.A.
+ }
+
+ /**
+ * Returns the WSDL built by this builder.
+ *
+ * @return the WSDL built by this builder.
+ */
+ public Document getWsdl()
+ {
+ WsdlDebugger.debug(_objectName,_document);
+ return _document;
+ }
+
+ /**
+ * Injects the application context environment
+ * on this builder.
+ *
+ * @param environment the application context environment.
+ */
+ public void setEnvironment(Environment environment)
+ {
+ this._environment = (WSDMAdapterEnvironment)environment;
+ }
+
+ /**
+ * Injects the path of the wsdl document.
+ *
+ * @param wsdlPath the path of the wsdl document.
+ */
+ public void setWsdlPath(String wsdlPath)
+ {
+ _document = WsdlUtils.createWSDL(_environment, wsdlPath, true);
+ }
+
+ /**
+ * Create a reference to the WSRP properties element.
+ *
+ * @throws BuilderException in case of XPath evaluation problem.
+ */
+ private void createWsrpPropertiesElement() throws BuilderException
+ {
+ try
+ {
+ _wsrpProperties = (Element) XPathAPI.selectSingleNode(
+ _document,
+ WSRP_PROPERTIES_XPATH);
+ } catch (TransformerException exception)
+ {
+ LOGGER.error(Messages.QMAN_100040_UNABLE_TO_LOCATE_WSRP_PROPERTIES);
+ throw new BuilderException(exception);
+ }
+ }
+
+ /**
+ * Creates a template element that will be used for array
+ * type schema declaration(s).
+ */
+ private void createReusableArrayComplextType()
+ {
+ _arrayComplexType = XmlUtils.createElement(_document, XSD_COMPLEX_TYPE_QNAME);
+ Element sequence = XmlUtils.createElement(_document, XSD_SEQUENCE_QNAME);
+ _nestedArrayType = XmlUtils.createElement(_document, XSD_ELEMENT_QNAME);
+ _nestedArrayType.setAttribute(NAME_ATTRIBUTE, "entry");
+ sequence.appendChild(_nestedArrayType);
+ _arrayComplexType.appendChild(sequence);
+ }
+
+ private void createSchemaElement() throws BuilderException
+ {
+ try
+ {
+ schema = (Element) XPathAPI.selectSingleNode(
+ _document.getDocumentElement(),
+ QMAN_SCHEMA_XPATH);
+ } catch(Exception exception)
+ {
+ LOGGER.error(
+ exception,
+ Messages.QMAN_100034_WSDL_SCHEMA_SECTION_NOT_FOUND);
+ throw new BuilderException(exception);
+ }
+ }
+
+ /**
+ * The template WSDL contains a dummy URL as service location that
+ * needs to be replaced with the real service address.
+ *
+ * @throws BuilderException when replacement fails (XPath problem).
+ */
+ private void replaceDummyServiceLocationOnWsdl() throws BuilderException
+ {
+ try
+ {
+ Attr location = (Attr) XPathAPI.selectSingleNode(
+ _document,
+ SERVICE_LOCATION_XPATH);
+
+ StringBuilder builder = new StringBuilder("http://")
+ .append(InetAddress.getLocalHost().getHostName())
+ .append(':')
+ .append(System.getProperty(Names.ADAPTER_PORT_PROPERTY_NAME,"8080"))
+ .append('/')
+ .append(_environment.getContextPath())
+ .append('/')
+ .append("services/QManWsResource");
+ location.setValue(builder.toString());
+ } catch(Exception exception)
+ {
+ LOGGER.error(
+ exception,
+ Messages.QMAN_100026_SOAP_ADDRESS_REPLACEMENT_FAILURE);
+ throw new BuilderException(exception);
+ }
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/EntityInstanceNotFoundFault.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/EntityInstanceNotFoundFault.java
new file mode 100644
index 0000000000..116d74727a
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/EntityInstanceNotFoundFault.java
@@ -0,0 +1,58 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.common;
+
+import javax.management.ObjectName;
+import javax.xml.namespace.QName;
+
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.qpid.management.Names;
+
+/**
+ * Thrown when some operation has been requested on an entity and the entity hasn't been found
+ * on the managed domain.
+ *
+ * @author Andrea Gazzarini
+ */
+public class EntityInstanceNotFoundFault extends QManFault
+{
+ private static final long serialVersionUID = -3772811863214553615L;
+
+ private final static QName EXCEPTION_QNAME = new QName(
+ Names.NAMESPACE_URI,
+ "EntityInstanceNotFoundFault",
+ Names.PREFIX);
+
+ /**
+ * Builds a new exception with the given endpoint reference and the object name of the entity
+ * that wasn't found.
+ *
+ * @param endpointReference the origin endpoint reference of this exception.
+ * @param targetEntityName the object name of the not found entity.
+ */
+ public EntityInstanceNotFoundFault(EndpointReference endpointReference, ObjectName targetEntityName)
+ {
+ super(
+ endpointReference,
+ EXCEPTION_QNAME,
+ targetEntityName.getCanonicalName());
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/MethodInvocationFault.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/MethodInvocationFault.java
new file mode 100644
index 0000000000..f24c2bfd46
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/MethodInvocationFault.java
@@ -0,0 +1,79 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.common;
+
+import javax.xml.namespace.QName;
+
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.qpid.management.Names;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * This is the exception encapsulating the fault that will be thrown in case of
+ * method invocation failure.
+ *
+ * @author Andrea Gazzarini
+ */
+public class MethodInvocationFault extends QManFault
+{
+ private static final long serialVersionUID = 5977379710882983474L;
+
+ private String _message;
+ private long _returnCode;
+
+ /**
+ * Builds a new exception with the given endpoint reference and method invocation exception.
+ * This constructor will be used when the invocation thrown the MethodInvocationException.
+ *
+ * @param endpointReference the endpoint reference.
+ * @param methodName the name of the method.
+ * @param message the explanatio message.
+ * @param returnCode the a mnemonic code associated with the failure.
+ */
+ public MethodInvocationFault(
+ EndpointReference endpointReference,
+ String methodName,
+ String message,
+ long returnCode)
+ {
+ super(
+ endpointReference,
+ new QName(
+ Names.NAMESPACE_URI,
+ "OperationInvocationFault",
+ Names.PREFIX),
+ String.format("OPERATION \"%s\" FAILURE. See detail section for further details.",methodName));
+ this._message = message;
+ this._returnCode = returnCode;
+ }
+
+ @Override
+ public Element getDetail()
+ {
+ Element detail = super.getDetail();
+ Document owner = detail.getOwnerDocument();
+ detail.appendChild(XmlUtils.createElement(owner, Names.QMAN_STATUS_TEXT_NAME,_message));
+ detail.appendChild(XmlUtils.createElement(owner, Names.QMAN_STATUS_CODE_NAME,_returnCode));
+ return detail;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/NoSuchAttributeFault.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/NoSuchAttributeFault.java
new file mode 100644
index 0000000000..e9f37f8afb
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/NoSuchAttributeFault.java
@@ -0,0 +1,70 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.common;
+
+import javax.xml.namespace.QName;
+
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.qpid.management.Names;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * This is the exception encapsulating the fault that will be thrown when a requested
+ * attribute is not found on the target ws resource.
+ *
+ * @author Andrea Gazzarini
+ */
+public class NoSuchAttributeFault extends QManFault
+{
+ private static final long serialVersionUID = 5977379710882983474L;
+
+ private String _attributeName;
+
+ /**
+ * Builds a new exception with the given endpoint reference, JMX object name
+ * and attribute that hasn't been found.
+ *
+ * @param endpointReference the endpoint reference.
+ * @param attributeName the name of the attribute that hasn't been found.
+ */
+ public NoSuchAttributeFault(EndpointReference endpointReference, String attributeName)
+ {
+ super(
+ endpointReference,
+ new QName(
+ Names.NAMESPACE_URI,
+ "NoSuchAttributeFault",
+ Names.PREFIX),
+ "Attribute not found on this WS-Resource.");
+ _attributeName = attributeName;
+ }
+
+ @Override
+ public Element getDetail()
+ {
+ Element detail = super.getDetail();
+ Document owner = detail.getOwnerDocument();
+ detail.appendChild(XmlUtils.createElement(owner, Names.QMAN_STATUS_ATTRIBUTE_NAME,_attributeName));
+ return detail;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/ObjectNameIdFactory.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/ObjectNameIdFactory.java
new file mode 100644
index 0000000000..eb7eee9547
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/ObjectNameIdFactory.java
@@ -0,0 +1,61 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.common;
+
+import javax.management.ObjectName;
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.routing.ResourceIdFactory;
+import org.apache.qpid.management.Names;
+
+/**
+ * ResourceIdFactory implementation that is using an objectName as
+ * resource identifier.
+ * This is done in order to make a relationship between an MBean (which is part of the
+ * JMX core domain model) and a WS-Resource (the same entity as is represented on WS-DM adapter side).
+ *
+ * @author Andrea Gazzarini
+ */
+public class ObjectNameIdFactory implements ResourceIdFactory
+{
+ /**
+ * Returns the name of the identifier element.
+ *
+ * @return the name of the identifier element.
+ */
+ public QName getIdentifierName()
+ {
+ return Names.RESOURCE_ID_QNAME;
+ }
+
+ /**
+ * Returns the object name used as a resource identifier.
+ * Developer note : this factory is highly coupled with ThreadSessionManager stuff because
+ * the object name that will be used as identifier is supposed to be in the thread session.
+ *
+ * @return the object name used as a resource identifier.
+ */
+ public String getNextIdentifier()
+ {
+ ObjectName objectName = ThreadSessionManager.getInstance().getSession().getObjectName();
+ return objectName.getKeyProperty(Names.OBJECT_ID);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/QManFault.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/QManFault.java
new file mode 100644
index 0000000000..0a52c2ba65
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/QManFault.java
@@ -0,0 +1,72 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.common;
+
+import javax.xml.namespace.QName;
+
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.muse.ws.resource.basefaults.BaseFault;
+import org.apache.qpid.management.Names;
+
+/**
+ * Base class for QMan thrown faults.
+ * This should be thrown to denote a situation where a not-well cause could be determined.
+ */
+public class QManFault extends BaseFault
+{
+ private static final long serialVersionUID = 5977379710882983474L;
+ private final static QName SERVICE = new QName(
+ Names.NAMESPACE_URI,
+ "QMan",
+ Names.PREFIX);
+
+ private final static QName EXCEPTION_QNAME = new QName(
+ Names.NAMESPACE_URI,
+ "QManFault",
+ Names.PREFIX);
+
+ /**
+ * Builds a new exception with the given endpoint reference and the exception cause.
+ *
+ * @param endpointReference the endpoint reference.
+ * @param cause the exception cause.
+ */
+ public QManFault(EndpointReference endpointReference, Exception cause)
+ {
+ super(EXCEPTION_QNAME,cause.getMessage());
+ setCode(SERVICE);
+ setOriginReference(endpointReference);
+ }
+
+ /**
+ * Builds a new exception with the given endpoint reference, qname and detail message.
+ *
+ * @param endpointReference the endpoint reference.
+ * @param qname the qname of this exception.
+ * @param message the detail message of this exception.
+ */
+ public QManFault(EndpointReference endpointReference, QName qname, String message)
+ {
+ super(qname,message);
+ setOriginReference(endpointReference);
+ setCode(SERVICE);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/QManResourceIdFactory.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/QManResourceIdFactory.java
new file mode 100644
index 0000000000..1a34971c6a
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/QManResourceIdFactory.java
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.common;
+
+import java.util.UUID;
+
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.routing.ResourceIdFactory;
+import org.apache.qpid.management.Names;
+
+/**
+ * A simple implementation of resource id factory that uses a UUID as resource
+ * identifier.
+ *
+ * @author Andrea Gazzarini
+ */
+public class QManResourceIdFactory implements ResourceIdFactory
+{
+ /**
+ * Returns the identifier name for id element.
+ *
+ * @return the identifier name for id element.
+ */
+ public QName getIdentifierName()
+ {
+ return Names.RESOURCE_ID_QNAME;
+ }
+
+ /**
+ * Returns the next valid identifier.
+ *
+ * @return the next valid identifier.
+ */
+ public String getNextIdentifier()
+ {
+ return UUID.randomUUID().toString();
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/ThreadSession.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/ThreadSession.java
new file mode 100644
index 0000000000..588879b951
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/ThreadSession.java
@@ -0,0 +1,105 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.common;
+
+import javax.management.ObjectName;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Thread-scoped session.
+ *
+ * @author Andrea Gazzarini
+ */
+public class ThreadSession
+{
+ private ObjectName _objectName;
+ private Document _wsdl;
+ private Element [] _wsrmdProperties;
+
+ /**
+ * Empty constructor.
+ */
+ ThreadSession()
+ {
+ }
+
+ /**
+ * Gets the object name associated with this thread session.
+ *
+ * @return the object name associated with this thread session.
+ */
+ public ObjectName getObjectName()
+ {
+ return _objectName;
+ }
+
+ /**
+ * Sets the object name on this thread session.
+ *
+ * @param the object name of this thread session..
+ */
+ public void setObjectName(ObjectName objectName)
+ {
+ this._objectName = objectName;
+ }
+
+ /**
+ * Sets the WSDL document on this thread session.
+ *
+ * @param the WSDL document of this thread session..
+ */
+ public void setWsdlDocument(Document wsdlDoc)
+ {
+ this._wsdl = wsdlDoc;
+ }
+
+ /**
+ * Gets the WSDL document associated with this thread session.
+ *
+ * @return the WSDL document associated with this thread session.
+ */
+ public Document getWsdlDocument()
+ {
+ return _wsdl;
+ }
+
+ /**
+ * Gets the RDM elements associated with this thread session.
+ *
+ * @return the RDM elements associated with this thread session.
+ */
+ public Element[] getResourceMetadataDescriptor()
+ {
+ return _wsrmdProperties;
+ }
+
+ /**
+ * Sets the WSDL elements on this thread session.
+ *
+ * @param the WSDL elements of this thread session..
+ */
+ public void setResourceMetadataDescriptor(Element[] rmd)
+ {
+ this._wsrmdProperties = rmd;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/ThreadSessionManager.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/ThreadSessionManager.java
new file mode 100644
index 0000000000..6a081bfec4
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/ThreadSessionManager.java
@@ -0,0 +1,68 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.common;
+
+/**
+ * Thread session manager used to handle thread-scoped sessions.
+ *
+ * @author Andrea Gazzarini
+ */
+public final class ThreadSessionManager
+{
+ private static ThreadSessionManager instance = new ThreadSessionManager();
+
+ private ThreadLocal<ThreadSession> sessions;
+
+ /**
+ * Builds and initializes a new manager.
+ */
+ private ThreadSessionManager()
+ {
+ this.sessions = new ThreadLocal<ThreadSession>();
+ }
+
+ /**
+ * Returns the singleton instance of this manager.
+ *
+ * @return the singleton instance of this manager.
+ */
+ public static ThreadSessionManager getInstance()
+ {
+ return instance;
+ }
+
+ /**
+ * Returns (or create and returns) the session associated with the
+ * current thread.
+ *
+ * @return the thread session.
+ */
+ public ThreadSession getSession()
+ {
+ ThreadSession session = (ThreadSession) sessions.get();
+ if (session == null)
+ {
+ session = new ThreadSession();
+ sessions.set(session);
+ }
+ return session;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/UnableToConnectWithBrokerFault.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/UnableToConnectWithBrokerFault.java
new file mode 100644
index 0000000000..55365b4051
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/common/UnableToConnectWithBrokerFault.java
@@ -0,0 +1,86 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.common;
+
+import javax.xml.namespace.QName;
+
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.qpid.management.Names;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * This is the exception encapsulating the fault that will be thrown in case of
+ * broker connection failure.
+ *
+ * @author Andrea Gazzarini
+ */
+public class UnableToConnectWithBrokerFault extends QManFault
+{
+ private static final long serialVersionUID = 5977379710882983474L;
+
+ private String _host;
+ private int _port;
+ private String _username;
+ private String _virtualHostName;
+
+ /**
+ * Builds a new exception with the given endpoint reference and connection data.
+ *
+ * @param host the requested qpid host.
+ * @param port the requested qpid port.
+ * @param username the username used for estabilishing connection.
+ * @param virtualHostName the name of the target virtual host..
+ */
+ public UnableToConnectWithBrokerFault(
+ EndpointReference endpointReference,
+ String host,
+ int port,
+ String username,
+ String virtualHostName,
+ String message)
+ {
+ super(
+ endpointReference,
+ new QName(
+ Names.NAMESPACE_URI,
+ "UnableToConnectFault",
+ Names.PREFIX),
+ String.format("Unable to connect with the requested broker. Underlying exception message was %s",message));
+ this._host = host;
+ this._port = port;
+ this._username = username;
+ this._virtualHostName = virtualHostName;
+ }
+
+ @Override
+ public Element getDetail()
+ {
+ Element detail = super.getDetail();
+ Document owner = detail.getOwnerDocument();
+ detail.appendChild(XmlUtils.createElement(owner, Names.HOST_QNAME,_host));
+ detail.appendChild(XmlUtils.createElement(owner, Names.PORT_QNAME,_port));
+ detail.appendChild(XmlUtils.createElement(owner, Names.USERNAME_QNAME,_username));
+ detail.appendChild(XmlUtils.createElement(owner, Names.VIRTUAL_HOST_QNAME,_virtualHostName));
+ return detail;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/engine/WSDMAdapterEnvironment.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/engine/WSDMAdapterEnvironment.java
new file mode 100644
index 0000000000..b5d978e0e5
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/engine/WSDMAdapterEnvironment.java
@@ -0,0 +1,97 @@
+package org.apache.qpid.management.wsdm.muse.engine;
+
+import java.io.File;
+import java.net.URI;
+
+import javax.servlet.ServletContext;
+
+import org.apache.muse.core.AbstractEnvironment;
+import org.apache.muse.util.FileUtils;
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.Protocol;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * QMan Adapter enviroment implementation.
+ *
+ * @author Andrea Gazzarini
+ */
+public class WSDMAdapterEnvironment extends AbstractEnvironment
+{
+ private final static Logger LOGGER = Logger.get(WSDMAdapterEnvironment.class);
+ private final File _realDirectory;
+ private final ServletContext _servletContext;
+
+ /**
+ * Builds a new qman environment with the given application context.
+ *
+ * @param servletContext the application context.
+ */
+ public WSDMAdapterEnvironment(ServletContext servletContext)
+ {
+ this._servletContext = servletContext;
+ String realDirectoryPath = servletContext.getRealPath(Names.WEB_APP_CLASSES_FOLDER);
+
+ _realDirectory = (realDirectoryPath != null)
+ ? new File(realDirectoryPath)
+ : FileUtils.CURRENT_DIR;
+
+ String defaultURI = getDefaultURIPrefix()+"adapter";
+ setDefaultURI(defaultURI);
+
+ LOGGER.info(Messages.QMAN_000029_DEFAULT_URI, defaultURI);
+ }
+
+ /**
+ * Returns the endpoint created starting by this application default URI.
+ *
+ * @return the endpoint created starting by this application default URI.
+ */
+ public EndpointReference getDeploymentEPR()
+ {
+ return new EndpointReference(URI.create(getDefaultURI()));
+ }
+
+ /**
+ * Returns the application classes folder.
+ *
+ * @return the application classes folder.
+ */
+ public File getRealDirectory()
+ {
+ return _realDirectory;
+ }
+
+ /**
+ * Returns the default endpoint reference URI.
+ *
+ * @return the default endpoint reference URI.
+ */
+ public String getDefaultURIPrefix()
+ {
+ return new StringBuilder()
+ .append("http://")
+ .append(System.getProperty(
+ Names.ADAPTER_HOST_PROPERTY_NAME,
+ Protocol.DEFAULT_QMAN_HOSTNAME))
+ .append(":")
+ .append(System.getProperty(
+ Names.ADAPTER_PORT_PROPERTY_NAME,
+ String.valueOf(Protocol.DEFAULT_QMAN_PORT_NUMBER)))
+ .append(_servletContext.getContextPath())
+ .append("/services/")
+ .toString();
+ }
+
+ /**
+ * Returns the context path name of QMan application.
+ *
+ * @return the context path name of QMan application.
+ */
+ public String getContextPath()
+ {
+ return _servletContext.getContextPath();
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/engine/WSDMAdapterIsolationLayer.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/engine/WSDMAdapterIsolationLayer.java
new file mode 100644
index 0000000000..0ca19bc727
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/engine/WSDMAdapterIsolationLayer.java
@@ -0,0 +1,36 @@
+package org.apache.qpid.management.wsdm.muse.engine;
+
+import javax.servlet.ServletContext;
+
+import org.apache.muse.core.Environment;
+import org.apache.muse.core.platform.mini.MiniIsolationLayer;
+
+/**
+ * QMan specific implementation of the Apache Muse isolation layer.
+ * If you are a Muse expert you were wondering why don't we use the muse default implementation...
+ * well,
+ *
+ * @author Andrea Gazzarini
+ */
+public class WSDMAdapterIsolationLayer extends MiniIsolationLayer
+{
+ /**
+ * Builds a new isolation layer with the given application context.
+ *
+ * @param initialContext the application context.
+ */
+ public WSDMAdapterIsolationLayer(ServletContext initialContext)
+ {
+ super(null, initialContext);
+ }
+
+ /**
+ * WSDMAdapterEnvironment factory method.
+ *
+ * @return the environment.
+ */
+ protected Environment createEnvironment()
+ {
+ return new WSDMAdapterEnvironment(getInitialContext());
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/resources/QManWsResource.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/resources/QManWsResource.java
new file mode 100644
index 0000000000..c16c156b73
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/resources/QManWsResource.java
@@ -0,0 +1,762 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.muse.resources;
+
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.Capability;
+import org.apache.muse.core.Environment;
+import org.apache.muse.core.ResourceManager;
+import org.apache.muse.core.routing.MessageHandler;
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.muse.ws.addressing.WsaConstants;
+import org.apache.muse.ws.addressing.soap.SoapConstants;
+import org.apache.muse.ws.addressing.soap.SoapFault;
+import org.apache.muse.ws.addressing.soap.SoapUtils;
+import org.apache.muse.ws.resource.WsResource;
+import org.apache.muse.ws.resource.metadata.MetadataDescriptor;
+import org.apache.muse.ws.resource.metadata.WsrmdConstants;
+import org.apache.muse.ws.resource.metadata.impl.SimpleMetadataDescriptor;
+import org.apache.muse.ws.resource.metadata.impl.WsrmdUtils;
+import org.apache.muse.ws.resource.properties.ResourcePropertyCollection;
+import org.apache.muse.ws.resource.properties.impl.SimpleResourcePropertyCollection;
+import org.apache.muse.ws.resource.properties.impl.WsrpUtils;
+import org.apache.muse.ws.resource.properties.schema.ResourcePropertiesSchema;
+import org.apache.muse.ws.resource.properties.schema.impl.SimpleResourcePropertiesSchema;
+import org.apache.muse.ws.wsdl.WsdlUtils;
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.wsdm.common.ThreadSessionManager;
+import org.apache.qpid.transport.util.Logger;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * QMan WS resource.
+ * We could say that this is a QMan manageable entity under the
+ * WS-DM perspective.
+ *
+ * @author Andrea Gazzarini
+ */
+@SuppressWarnings("unchecked")
+public class QManWsResource implements WsResource
+{
+ private final static Logger LOGGER = Logger.get(QManWsResource.class);
+
+ /**
+ * Internal state of this resource.
+ *
+ * @author Andrea Gazzarini
+ */
+ interface State
+ {
+ /**
+ * Provides initialization of this resource.
+ *
+ * @throws SoapFault when the initialization fails.
+ */
+ void initialize() throws SoapFault;
+
+ /**
+ * Returns true if this resource has been initialized.
+ *
+ * @return true if this resource has been initialized.
+ */
+ boolean hasBeenInitialized();
+
+ /**
+ * Returns true if this resource has been shutdown.
+ *
+ * @return true if this resource has been shutdown.
+ */
+ boolean hasBeenShutdown();
+
+ /**
+ * Shuts down this resource.
+ *
+ * @throws SoapFault when the shutdown procedure fails.
+ */
+ void shutdown() throws SoapFault;
+ }
+
+ private final State _hasBeenShutdown = new State()
+ {
+ /**
+ * Return false because this resource has been shutdown so therefore
+ * initialization occurred.
+ *
+ * @return true;
+ */
+ public boolean hasBeenInitialized()
+ {
+ return true;
+ }
+
+ /**
+ * Returns true because this state indicates that resource has been shutdown.
+ *
+ * @return true.
+ */
+ public boolean hasBeenShutdown()
+ {
+ return true;
+ }
+
+ /**
+ * Since this resource has been shutdown the initialization
+ * cannot be performed again.
+ * As conseguence of that this method throws an exception.
+ *
+ * @throws SoapFault each time this method is called.
+ */
+ public void initialize() throws SoapFault
+ {
+ LOGGER.error(Messages.QMAN_100031_WS_RESOURCE_ALREADY_INITIALIZED);
+ throw new SoapFault(Messages.QMAN_100031_WS_RESOURCE_ALREADY_INITIALIZED);
+ }
+
+ public void shutdown() throws SoapFault
+ {
+ LOGGER.error(Messages.QMAN_100033_WS_RESOURCE_ALREADY_SHUTDOWN);
+ throw new SoapFault(Messages.QMAN_100033_WS_RESOURCE_ALREADY_SHUTDOWN);
+ }
+ };
+
+ private final State _hasBeenInitialized = new State()
+ {
+ /**
+ * Returns true because this is the state where a resource is when it
+ * has been initialized.
+ *
+ * @return true.
+ */
+ public boolean hasBeenInitialized()
+ {
+ return true;
+ }
+
+ /**
+ * Returns false because this resource has been initialized but no shutdown request
+ * has been received.
+ *
+ * @return false.
+ */
+ public boolean hasBeenShutdown()
+ {
+ return false;
+ }
+
+ /**
+ * A resource in this state cannot be initialized again so if this method is called an
+ * exception is thrown.
+ *
+ * @throws SoapFault each time this method is called.
+ */
+ public void initialize() throws SoapFault
+ {
+ LOGGER.error(Messages.QMAN_100031_WS_RESOURCE_ALREADY_INITIALIZED);
+ throw new SoapFault(Messages.QMAN_100031_WS_RESOURCE_ALREADY_INITIALIZED);
+ }
+
+ /**
+ * Shuts down this resource.
+ *
+ * @throws SoapFault when the shutdown procedure fails.
+ */
+ public void shutdown() throws SoapFault
+ {
+ shutdownCapabilities();
+
+ ResourceManager manager = getResourceManager();
+
+ if (manager.getResource(_enpointReference) != null)
+ {
+ manager.removeResource(_enpointReference);
+ }
+
+ _currentState = _hasBeenShutdown;
+ }
+ };
+
+ /**
+ * The initial state of this resource.
+ * As the name suggests, it is not yet initialized.
+ */
+ private final State _notYetInitialized = new State()
+ {
+ /**
+ * Provides initialization of this resource.
+ *
+ * @throws SoapFault when the initialization fails.
+ */
+ public void initialize() throws SoapFault
+ {
+ _properties = new SimpleResourcePropertyCollection();
+ _wsdl = ThreadSessionManager.getInstance().getSession().getWsdlDocument();
+
+ ResourcePropertiesSchema schema = createPropertiesSchema(_wsdl);
+ _properties.setSchema(schema);
+
+ MetadataDescriptor metadata = createMetadataDescriptor(_wsdl);
+ _properties.setMetadata(metadata);
+
+ initializeCapabilities();
+
+ _properties.applyMetadata();
+
+ // Resource intialization completed : Let's make a state change.
+ _currentState = _hasBeenInitialized;
+ }
+
+ /**
+ * Shuts down this resource.
+ *
+ * @throws SoapFault when the shutdown procedure fails. */
+ public void shutdown() throws SoapFault
+ {
+ LOGGER.error(Messages.QMAN_100032_WS_RESOURCE_NOT_YET_INITIALIZED);
+ throw new SoapFault(Messages.QMAN_100032_WS_RESOURCE_NOT_YET_INITIALIZED);
+ }
+
+ /**
+ * Returns false because this state indicates that
+ * the resource has not yet been initialized.
+ *
+ * @return false;
+ */
+ public boolean hasBeenInitialized()
+ {
+ return false;
+ }
+
+ /**
+ * Returns false because the resource, when is in this state
+ * hasn't been initialized and as conseguence of that hasn't
+ * been shutdonm.
+ *
+ * @return false;
+ */
+ public boolean hasBeenShutdown()
+ {
+ return false;
+ }
+ };
+
+ private Map<String,Capability> _capabilitiesByAction = new HashMap<String, Capability>();
+ private Map<String, Capability> _capabilitiesByURI = new LinkedHashMap<String, Capability>();
+
+ private String _contextPath;
+ private Environment _environment;
+ private EndpointReference _enpointReference;
+
+ private State _currentState = _notYetInitialized;
+
+ private ResourceManager _resourceManager;
+ private ResourcePropertyCollection _properties;
+
+ private Map<String,String> _initParameters = Collections.EMPTY_MAP;
+
+ // Workaround : muse is using and hardcoded java.util.logging.Logger but we should use
+ // SLF4j so this is the original implementatation that won't never be used (on QMan classes)
+ private java.util.logging.Logger _logger;
+
+ private Document _wsdl;
+ private String _wsdlPath;
+ private QName _wsdlPortType;
+
+ /**
+ * Adds the given capability to this resource.
+ *
+ * @param capability the capability to be added.
+ */
+ public void addCapability(Capability capability)
+ {
+ capability.setResource(this);
+ capability.setLog(getLog());
+ capability.setEnvironment(getEnvironment());
+
+ String uri = capability.getCapabilityURI();
+ _capabilitiesByURI.put(uri, capability);
+
+ LOGGER.debug(
+ Messages.QMAN_200033_CAPABILITY_CLASS_HAS_BEEN_ADDED,
+ capability.getClass(),
+ uri);
+ }
+
+ /**
+ * Returns the capability associated with the given URI.
+ *
+ * @return the capability associated with the given URI.
+ */
+ public Capability getCapability(String capabilityURI)
+ {
+ return _capabilitiesByURI.get(capabilityURI);
+ }
+
+ /**
+ * Returns a collection with all registered capability URIs.
+ *
+ * @return a collection with all registered capability URIs.
+ */
+ public final Collection getCapabilityURIs()
+ {
+ return Collections.unmodifiableSet(_capabilitiesByURI.keySet());
+ }
+
+ /**
+ * Returns the context path of this resource.
+ *
+ * @return the context path of this resource.
+ */
+ public final String getContextPath()
+ {
+ return _contextPath;
+ }
+
+ /**
+ * Returns the endpoint reference of this resource.
+ *
+ * @return the endpoint reference of this resource.
+ */
+ public EndpointReference getEndpointReference()
+ {
+ return _enpointReference;
+ }
+
+ /**
+ * Returns the enviroment associated with this resource.
+ *
+ * @return the enviroment associated with this resource.
+ */
+ public final Environment getEnvironment()
+ {
+ return _environment;
+ }
+
+ /**
+ * Returns the initialization parameter of this resource associated with
+ * the given name.
+ *
+ * @param name the init parameter name.
+ * @return the initialization parameter associated with the given name.
+ */
+ public final String getInitializationParameter(String name)
+ {
+ return (String)getInitializationParameters().get(name);
+ }
+
+ /**
+ * Returns the map containing all init parameters of this resource.
+ *
+ * @return the map containing all init parameters of this resource.
+ */
+ public final Map<String,String> getInitializationParameters()
+ {
+ return _initParameters;
+ }
+
+ /**
+ * N.A. This resource uses QMan logging instead of plain java.util.logger
+ * implementation.
+ */
+ public final java.util.logging.Logger getLog()
+ {
+ return _logger;
+ }
+
+ /**
+ * Returns the resource manager associated with this resource.
+ *
+ * @return the resource manager associated with this resource.
+ */
+ public ResourceManager getResourceManager()
+ {
+ return _resourceManager;
+ }
+
+ /**
+ * Returns the wsdl (relative) path of this resource.
+ *
+ * @return the wsdl (relative) path of this resource.
+ */
+ public String getWsdlPath()
+ {
+ return _wsdlPath;
+ }
+
+ /**
+ * Returns the port type of this resource.
+ *
+ * @return the port type of this resource.
+ */
+ public final QName getWsdlPortType()
+ {
+ return _wsdlPortType;
+ }
+
+ /**
+ * Returns true if this resource has been initialized, false otherwise.
+ *
+ * @return true if this resource has been initialized, false otherwise.
+ */
+ public final boolean hasBeenInitialized()
+ {
+ return _currentState.hasBeenInitialized();
+ }
+
+ /**
+ * Returns true if this resource has been shutdown, false otherwise.
+ *
+ * @return true if this resource has been shutdown, false otherwise.
+ */
+ public final boolean hasBeenShutdown()
+ {
+ return _currentState.hasBeenShutdown();
+ }
+
+ /**
+ * Checks if a capability with the given URI is available for this resource.
+ *
+ * @return true if a capability with the given URI is available for this resource, false otherwise.
+ */
+ public final boolean hasCapability(String capabilityURI)
+ {
+ return getCapability(capabilityURI) != null;
+ }
+
+ /**
+ * Returns the collection containing all properties of this resource.
+ *
+ * @return the collection containing all properties of this resource.
+ */
+ public final ResourcePropertyCollection getPropertyCollection()
+ {
+ return _properties;
+ }
+
+ /**
+ * Return the WSDL document of this resource.
+ *
+ * @return the WSDL document of this resource.
+ */
+ public Document getWsdl()
+ {
+ return _wsdl;
+ }
+
+ /**
+ * Initializes this resources.
+ * Note that the what needs to be done depends on the current state of this
+ * resource.
+ *
+ * @throws SoapFault when the initialization fails.
+ */
+ public void initialize() throws SoapFault
+ {
+ _currentState.initialize();
+ }
+
+ /**
+ * Invokes the action specified in the given soap request on this resource.
+ *
+ * @param requestBody the SOAP body.
+ * @return the result of the invocation as org.w3c.dom.Element
+ */
+ public Element invoke(Element requestBody)
+ {
+ String action = _environment.getAddressingContext().getAction();
+ Capability capability = getCapabilityForAction(action);
+
+ // Sanity check : is there a capability for the given action?
+ if (capability == null)
+ {
+ SoapFault wsaFault = new SoapFault(
+ String.format(
+ Messages.ACTION_NOT_SUPPORTED,
+ action,getContextPath()));
+
+ wsaFault.setCode(SoapConstants.SENDER_QNAME);
+ wsaFault.setSubCode(WsaConstants.ACTION_NOT_SUPPORTED_FAULT_QNAME);
+
+ Element detail = XmlUtils.createElement(WsaConstants.PROBLEM_ACTION_QNAME);
+ XmlUtils.setElement(detail, WsaConstants.ACTION_QNAME, action);
+ wsaFault.setDetail(detail);
+
+ LOGGER.error(
+ Messages.QMAN_100020_ACTION_NOT_SUPPORTED,
+ action,
+ getContextPath());
+
+ return wsaFault.toXML();
+ }
+
+ MessageHandler handler = capability.getMessageHandler(action);
+ Method method = handler.getMethod();
+
+ try
+ {
+ Object[]parameters = handler.fromXML(requestBody);
+ Object result = method.invoke(capability, parameters);
+ return handler.toXML(result);
+ }
+ catch (Throwable throwable)
+ {
+ LOGGER.error(
+ throwable,
+ Messages.QMAN_100037_INVOKE_OPERATION_FAILURE);
+
+ SoapFault response = SoapUtils.convertToFault(
+ (throwable.getCause()!= null)
+ ? throwable.getCause()
+ : throwable);
+ return response.toXML();
+ }
+ }
+
+ /**
+ * Sets the context path of this resource.
+ *
+ * @param contextPath the context path of this resource.
+ */
+ public final void setContextPath(String contextPath)
+ {
+ _contextPath = contextPath;
+ }
+
+ /**
+ * Sets the endpoint reference of this resource.
+ *
+ * @param endpointReference the endpoint reference of this resource.
+ */
+ public final void setEndpointReference(EndpointReference endpointReference)
+ {
+ if (_enpointReference != null && hasBeenInitialized())
+ throw new RuntimeException(("ExistingResourceEPR"));
+
+ _enpointReference = endpointReference;
+ }
+
+ /**
+ * Sets the context environment of this resource.
+ *
+ * @param environment the context environment of this resource.
+ */
+ public final void setEnvironment(Environment environment)
+ {
+ _environment = environment;
+ }
+
+ /**
+ * Sets the initialization parameters of this resource.
+ *
+ * @param parameters the init parameters of this resource.
+ */
+ public final void setInitializationParameters(Map parameters)
+ {
+ _initParameters = (parameters != null)
+ ? parameters
+ : Collections.EMPTY_MAP;
+ }
+
+ /**
+ * N.A. for this resource. QMan logging mechanism is used for that.
+ */
+ public final void setLog(java.util.logging.Logger log)
+ {
+ _logger = log;
+ }
+
+ /**
+ * Sets the resource manager owner of this resource.
+ *
+ * @param manager the resource manager of this resource.
+ */
+ public void setResourceManager(ResourceManager manager)
+ {
+ _resourceManager = manager;
+ }
+
+ /**
+ * Sets the WSDL (relative) path of this resource.
+ *
+ * @param wsdlPath the WSDL (relative) path of this resource.
+ */
+ public final void setWsdlPath(String wsdlPath)
+ {
+ this._wsdlPath = wsdlPath;
+ }
+
+ /**
+ * Sets the port type of this resource.
+ *
+ * @param wsdlPortType the port type of this resource.
+ */
+ public final void setWsdlPortType(QName wsdlPortType)
+ {
+ _wsdlPortType = wsdlPortType;
+ }
+
+ /**
+ * Shutdown procedure for this resource.
+ *
+ * @throws SoapFault when the shutdown procedure fails.
+ */
+ public synchronized void shutdown() throws SoapFault
+ {
+ _currentState.shutdown();
+ }
+
+ /**
+ * Returns a string representation of this resource.
+ * Basically the resource endpoint reference (as a string) is returned.
+ *
+ * @return the resource endpoint reference (as a string) is returned.
+ */
+ public String toString()
+ {
+ return getEndpointReference().toString();
+ }
+
+ /**
+ * Initializes capabilities of this resource.
+ *
+ * @throws SoapFault when at least one capability fails to initialize.
+ */
+ private void initializeCapabilities() throws SoapFault
+ {
+ for (Entry<String, Capability> entry : _capabilitiesByURI.entrySet())
+ {
+ Capability capability = entry.getValue();
+ capability.initialize();
+
+ for (Object action : capability.getActions())
+ {
+ _capabilitiesByAction.put((String)action, capability);
+ }
+
+ capability.initializeCompleted();
+ }
+ }
+
+ /**
+ * Shutdown procedure for all registered capabilities of this resource.
+ *
+ * @throws SoapFault when at least one capability shutdown fails.
+ */
+ private void shutdownCapabilities() throws SoapFault
+ {
+ for (Entry<String,Capability> entry : _capabilitiesByURI.entrySet())
+ {
+ Capability capabilty = entry.getValue();
+ capabilty.prepareShutdown();
+ capabilty.shutdown();
+ }
+ }
+
+ /**
+ * Creates a metadata descriptor for this resource.
+ *
+ * @param wsdl the WSDL document.
+ * @return a metadata descriptor for this resource.
+ * @throws SoapFault when it's not possible build the descriptor.
+ */
+ private MetadataDescriptor createMetadataDescriptor(Document wsdl) throws SoapFault
+ {
+ try
+ {
+ Element portTypeXML = WsdlUtils.getPortType(wsdl, getWsdlPortType());
+
+ String rmdName = XmlUtils.getAttribute(
+ portTypeXML,
+ WsrmdConstants.DESCRIPTOR_ATTR_QNAME);
+
+ String rmdPath = XmlUtils.getAttribute(
+ portTypeXML,
+ WsrmdConstants.DESCRIPTOR_LOCATION_ATTR_QNAME);
+
+ LOGGER.debug(Messages.QMAN_200034_RMD_NAME, rmdName);
+ LOGGER.debug(Messages.QMAN_200035_RMD_PATH, rmdPath);
+
+ Environment env = getEnvironment();
+ String path = env.createRelativePath(getWsdlPath(), rmdPath);
+ Document rmdDoc = env.getDocument(path);
+
+ Element[] additionalProperties =
+ ThreadSessionManager
+ .getInstance()
+ .getSession()
+ .getResourceMetadataDescriptor();
+
+ Element metadataDescriptor = WsrmdUtils.getMetadataDescriptor(rmdDoc, rmdName);
+
+ for (Element element : additionalProperties)
+ {
+
+// rmdDoc.importNode(element, true);
+ Element adopted = (Element) rmdDoc.importNode(element,false);
+ metadataDescriptor.appendChild(adopted);
+ }
+
+ return new SimpleMetadataDescriptor(metadataDescriptor);
+ }
+ catch(Exception exception)
+ {
+ LOGGER.error(
+ exception,
+ Messages.QMAN_100021_RMD_BUID_FAILURE,
+ getContextPath());
+ throw new SoapFault(exception);
+ }
+ }
+
+ /**
+ * Returns the capability associated with the given action.
+ *
+ * @param action the wsa:action of the requested capability.
+ * @return the capability associated with the given action.
+ */
+ private Capability getCapabilityForAction(String action)
+ {
+ return (Capability)_capabilitiesByAction.get(action);
+ }
+
+ /**
+ * Creates a WSRP document representing schema properties for this resource.
+ *
+ * @param wsdl the DOM document holding the resource's WSDL.
+ * @return the WSRP document schema.
+ */
+ private ResourcePropertiesSchema createPropertiesSchema(Document wsdl)
+ {
+ QName wsrpName = WsrpUtils.getPropertiesName(wsdl, getWsdlPortType());
+ Element wsrpDoc = WsdlUtils.getElementDeclaration(wsdl, wsrpName);
+ return new SimpleResourcePropertiesSchema(wsrpName, wsrpDoc);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/ByteArraySerializer.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/ByteArraySerializer.java
new file mode 100644
index 0000000000..a064542658
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/ByteArraySerializer.java
@@ -0,0 +1,83 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.muse.serializer;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.serializer.Serializer;
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.addressing.soap.SoapFault;
+import org.apache.xerces.impl.dv.util.Base64;
+import org.w3c.dom.Element;
+
+/**
+ * Implementation of Muse Serializer for byte array type.
+ *
+ * @author Andrea Gazzarini
+ */
+public class ByteArraySerializer implements Serializer {
+
+ /**
+ * Return a byte array representation of the given xml element.
+ *
+ * @param xml the element to unmarshal.
+ * @throws SoapFault when the unmarshalling fails.
+ */
+ public Object fromXML(Element xml) throws SoapFault
+ {
+ try
+ {
+ return Base64.decode(xml.getTextContent());
+ } catch (Exception exception)
+ {
+ throw new SoapFault(exception);
+ }
+ }
+
+ /**
+ * Returns the java type associated to this class.
+ *
+ * @return the java type associated to this class.
+ */
+ public Class<?> getSerializableType()
+ {
+ return byte[].class;
+ }
+
+ /**
+ * Return an xml representation of the given byte array with the given name.
+ *
+ * @param object the byte array to marshal.
+ * @param qname the qualified (xml) name of the object to use in xml representation.
+ * @return the xml representation of the byte array.
+ * @throws SoapFault when the marshalling fails.
+ */
+ public Element toXML(Object object, QName qname) throws SoapFault
+ {
+ Element element = XmlUtils.createElement(
+ qname,
+ Base64.encode((byte[]) object));
+ element.setAttribute("xmlns:xsi", XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);
+ element.setAttribute("xsi:type","xsd:base64Binary");
+ return element;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/DateSerializer.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/DateSerializer.java
new file mode 100644
index 0000000000..60350ccc31
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/DateSerializer.java
@@ -0,0 +1,75 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.muse.serializer;
+
+import java.util.Date;
+
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.serializer.Serializer;
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.addressing.soap.SoapFault;
+import org.w3c.dom.Element;
+
+/**
+ * Implementation of Muse Serializer for Date type.
+ * Note that Muse already ships a serializer but the formatter used on that class
+ * is losing precision betweem marshal / unmarshal operations.
+ *
+ * @author Andrea Gazzarini
+ */
+public class DateSerializer implements Serializer
+{
+ /**
+ * Return a Date representation of the given xml element.
+ *
+ * @param xml the element to unmarshal.
+ * @throws SoapFault when the unmarshalling fails.
+ */
+ public Object fromXML(Element elementData) throws SoapFault
+ {
+ return new Date(Long.parseLong(elementData.getTextContent()));
+ }
+
+ /**
+ * Returns the java type associated to this class.
+ *
+ * @return the java type associated to this class.
+ */
+ public Class<?> getSerializableType()
+ {
+ return Date.class;
+ }
+
+ /**
+ * Return an xml representation of the given UUID with the given name.
+ *
+ * @param object the UUID to marshal.
+ * @param qname the qualified (xml) name of the object to use in xml representation.
+ * @return the xml representation of the UUID.
+ * @throws SoapFault when the marshalling fails.
+ */
+ public Element toXML(Object obj, QName qname) throws SoapFault
+ {
+ Date date = (Date) obj;
+ return XmlUtils.createElement(qname, String.valueOf(date.getTime()));
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/InvocationResultSerializer.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/InvocationResultSerializer.java
new file mode 100644
index 0000000000..b819d52ad1
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/InvocationResultSerializer.java
@@ -0,0 +1,85 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.muse.serializer;
+
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.serializer.Serializer;
+import org.apache.muse.core.serializer.SerializerRegistry;
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.addressing.soap.SoapFault;
+import org.apache.qpid.management.wsdm.capabilities.Result;
+import org.w3c.dom.Element;
+
+/**
+ * Implementation of Muse Serializer for Result type.
+ *
+ * @author Andrea Gazzarini
+ */
+public class InvocationResultSerializer implements Serializer
+{
+ private Serializer _mapSerializer = SerializerRegistry.getInstance().getSerializer(Map.class);
+
+ /**
+ * Return a UUID representation of the given xml element.
+ *
+ * @param xml the element to unmarshal.
+ * @throws SoapFault when the unmarshalling fails.
+ */
+ @SuppressWarnings("unchecked")
+ public Object fromXML(Element elementData) throws SoapFault
+ {
+ Element outputParameters = XmlUtils.getFirstElement(elementData);
+ return new Result((Map<String, Object>) _mapSerializer.fromXML(outputParameters));
+ }
+
+ /**
+ * Returns the java type associated to this class.
+ *
+ * @return the java type associated to this class.
+ */
+ public Class<?> getSerializableType()
+ {
+ return Result.class;
+ }
+
+ /**
+ * Return an xml representation of the given UUID with the given name.
+ *
+ * @param object the UUID to marshal.
+ * @param qname the qualified (xml) name of the object to use in xml representation.
+ * @return the xml representation of the UUID.
+ * @throws SoapFault when the marshalling fails.
+ */
+ public Element toXML(Object obj, QName qname) throws SoapFault
+ {
+ Result result = (Result) obj;
+ Element root = XmlUtils.createElement(qname);
+ if (result.getOutputParameters() != null)
+ {
+ Element outputSection = SerializerRegistry.getInstance().getSerializer(Map.class).toXML(result.getOutputParameters(), new QName("outputParameters"));
+ root.appendChild(outputSection);
+ }
+ return root;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/MapSerializer.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/MapSerializer.java
new file mode 100644
index 0000000000..07e1dfdc56
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/MapSerializer.java
@@ -0,0 +1,134 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.muse.serializer;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.serializer.Serializer;
+import org.apache.muse.core.serializer.SerializerRegistry;
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.addressing.soap.SoapFault;
+import org.apache.qpid.management.Names;
+import org.w3c.dom.Element;
+
+/**
+ * Implementation of Muse Serializer for Map type.
+ *
+ * <amspam>
+ * <entry>
+ * <key>
+ * <value>
+ * </entry>
+ * </amsasm>
+ *
+ * @author Andrea Gazzarini
+ */
+public class MapSerializer implements Serializer
+{
+
+ ByteArraySerializer _byteArraySerializer = new ByteArraySerializer();
+ Serializer _objectSerializer = SerializerRegistry.getInstance().getSerializer(Object.class);
+ Serializer _stringSerializer = SerializerRegistry.getInstance().getSerializer(String.class);
+
+ /**
+ * Return a map representation of the given xml element.
+ *
+ * @param xml the element to unmarshal.
+ * @throws SoapFault when the unmarshalling fails.
+ */
+ public Object fromXML(Element xml) throws SoapFault
+ {
+ Map<Object,Object> result = new HashMap<Object,Object>();
+
+ if (xml != null)
+ {
+ Element[] children = XmlUtils.getAllElements(xml);
+ Serializer objectDeserializer = SerializerRegistry.getInstance().getSerializer(Object.class);
+
+ for (Element entry : children)
+ {
+ Element[] keysAndValues = XmlUtils.getAllElements(entry);
+ Object key = null;
+ Object value = null;
+ for (Element element : keysAndValues)
+ {
+ if (Names.KEY.equals(element.getLocalName()))
+ {
+ key = _stringSerializer.fromXML(element);
+ } else if (Names.VALUE.equals(element.getLocalName()))
+ {
+ value = objectDeserializer.fromXML(element);
+ }
+ }
+ result.put(key, value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the java type associated to this class.
+ *
+ * @return the java type associated to this class.
+ */
+ public Class<?> getSerializableType()
+ {
+ return Map.class;
+ }
+
+ /**
+ * Return an xml representation of the given Map with the given name.
+ *
+ * @param object the Map to marshal.
+ * @param qname the qualified (xml) name of the object to use in xml representation.
+ * @return the xml representation of the given Map.
+ * @throws SoapFault when the marshalling fails.
+ */
+ public Element toXML(Object obj, QName qname) throws SoapFault
+ {
+
+ Map<?, ?> data = (Map<?, ?>) obj;
+
+ QName entryQName = new QName(qname.getNamespaceURI(),Names.ENTRY,qname.getPrefix());
+ QName keyQName = new QName(qname.getNamespaceURI(),Names.KEY,qname.getPrefix());
+ QName valueQName = new QName(qname.getNamespaceURI(),Names.VALUE,qname.getPrefix());
+
+ Element root = XmlUtils.createElement(qname);
+ root.setAttribute("xmlns:xsi", XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);
+ for (Entry<?, ?> mapEntry: data.entrySet())
+ {
+ Element entry = XmlUtils.createElement(entryQName);
+ entry.appendChild(_stringSerializer.toXML(mapEntry.getKey(), keyQName));
+ if (mapEntry.getValue().getClass() == byte[].class) {
+ entry.appendChild(_byteArraySerializer.toXML(mapEntry.getValue(), valueQName));
+ } else {
+ entry.appendChild(_objectSerializer.toXML(mapEntry.getValue(), valueQName));
+ }
+ root.appendChild(entry);
+ }
+ return root;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/ObjectSerializer.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/ObjectSerializer.java
new file mode 100644
index 0000000000..ff0c69cdda
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/ObjectSerializer.java
@@ -0,0 +1,202 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.muse.serializer;
+
+import java.net.URI;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.serializer.Serializer;
+import org.apache.muse.core.serializer.SerializerRegistry;
+import org.apache.muse.ws.addressing.soap.SoapFault;
+import org.apache.qpid.management.Names;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+
+/**
+ * Generic Serializer for objects.
+ * It is a general-purpose serializer used for encoding Object values.
+ */
+public class ObjectSerializer implements Serializer
+{
+ /**
+ * Mapping between xsd and java types.
+ */
+ private Map<String, Class<?>> xml2Java = new HashMap<String, Class<?>>();
+ {
+ xml2Java.put("xsd:long", Long.class);
+ xml2Java.put("xsd:boolean",Boolean.class);
+ xml2Java.put("xsd:double",Double.class);
+ xml2Java.put("xsd:float",Float.class);
+ xml2Java.put("xsd:integer",Integer.class);
+ xml2Java.put("xsd:int",Integer.class);
+ xml2Java.put("xsd:short",Short.class);
+ xml2Java.put("xsd:string",String.class);
+ xml2Java.put("xsd:anyURI",URI.class);
+ xml2Java.put("xsd:dateTime",Date.class);
+ xml2Java.put("xsd:QName",QName.class);
+ xml2Java.put("xsd:element",Element.class);
+ xml2Java.put("xsd:base64Binary",byte[].class);
+ xml2Java.put("qman:arrayOfLong",Long[].class);
+ xml2Java.put("qman:arrayOfBoolean",Boolean[].class);
+ xml2Java.put("qman:arrayOfDouble",Double[].class);
+ xml2Java.put("qman:arrayOfFloat",Float[].class);
+ xml2Java.put("qman:arrayOfInteger",Integer[].class);
+ xml2Java.put("qman:arrayOfShort",Short[].class);
+ xml2Java.put("qman:arrayOfString",String[].class);
+ xml2Java.put("qman:arrayOfURI",URI[].class);
+ xml2Java.put("qman:arrayOfDate",Date[].class);
+ xml2Java.put("qman:uuid",UUID.class);
+ xml2Java.put("qman:map",Map.class);
+ xml2Java.put("qman:map",HashMap.class);
+ }
+
+ private Map<Class<?>, String> java2Xml = new HashMap<Class<?>, String>();
+ {
+ java2Xml.put(UUID.class,"qman:uuid");
+ java2Xml.put(Long.class,"xsd:long");
+ java2Xml.put(long.class,"xsd:long");
+ java2Xml.put(Boolean.class,"xsd:boolean");
+ java2Xml.put(boolean.class,"xsd:boolean");
+ java2Xml.put(Double.class,"xsd:double");
+ java2Xml.put(double.class,"xsd:double");
+ java2Xml.put(Float.class,"xsd:float");
+ java2Xml.put(float.class,"xsd:float");
+ java2Xml.put(Integer.class,"xsd:integer");
+ java2Xml.put(int.class,"xsd:integer");
+ java2Xml.put(Short.class,"xsd:short");
+ java2Xml.put(short.class,"xsd:short");
+ java2Xml.put(String.class,"xsd:string");
+ java2Xml.put(URI.class,"xsd:anyURI");
+ java2Xml.put(Date.class,"xsd:dateTime");
+ java2Xml.put(QName.class,"xsd:QName");
+ java2Xml.put(Element.class,"xsd:element");
+ java2Xml.put(byte[].class,"xsd:base64Binary");
+ java2Xml.put(Long[].class,"qman:arrayOfLong");
+ java2Xml.put(long[].class,"qman:arrayOfLong");
+ java2Xml.put(Boolean[].class,"qman:arrayOfBoolean");
+ java2Xml.put(boolean[].class,"qman:arrayOfBoolean");
+ java2Xml.put(Double[].class,"qman:arrayOfDouble");
+ java2Xml.put(double[].class,"qman:arrayOfDouble");
+ java2Xml.put(Float[].class,"qman:arrayOfFloat");
+ java2Xml.put(float[].class,"qman:arrayOfFloat");
+ java2Xml.put(Integer[].class,"qman:arrayOfInteger");
+ java2Xml.put(int[].class,"qman:arrayOfInteger");
+ java2Xml.put(Short[].class,"qman:arrayOfShort");
+ java2Xml.put(short[].class,"qman:arrayOfShort");
+ java2Xml.put(String[].class,"qman:arrayOfString");
+ java2Xml.put(URI[].class,"qman:arrayOfURI");
+ java2Xml.put(Date[].class,"qman:arrayOfDate");
+ java2Xml.put(Map.class,"qman:map");
+ java2Xml.put(HashMap.class,"qman:map");
+ }
+
+ /**
+ * Converts the incoming element into the appropriate Java type.
+ * The method will fail if :
+ *
+ * <br>1) The element has no xsi:type attribute;
+ * <br>2) The xsi:type attribute has no corresponding java type on this serializer mappings.
+ *
+ * @param elementData the xml element containing data to be unmarshalled.l
+ * @return the java object as result of xml element unmarshalling.
+ * @throws SoapFault when the marshalling fails.
+ */
+ public Object fromXML(Element elementData) throws SoapFault
+ {
+ Attr typeAttribute = elementData.getAttributeNodeNS(
+ XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI,
+ Names.TYPE);
+
+ if (typeAttribute == null)
+ {
+ throw new SoapFault(
+ "No type attribute was found for the current element. " +
+ "If you are using this serializer, in order to unmarshal the" +
+ " opportune type the xsi:type must be specified.");
+ }
+
+ Class<?> clazz = xml2Java.get(typeAttribute.getValue());
+
+ if (clazz == null)
+ {
+ throw new SoapFault(
+ String.format(
+ "No corresponding class was found on this serializer mappings for xsi:type %s.",
+ typeAttribute));
+ }
+
+ if (clazz == byte[].class) {
+ return new ByteArraySerializer().fromXML(elementData);
+ }
+
+ return SerializerRegistry.getInstance().getSerializer(clazz).fromXML(elementData);
+ }
+
+ /**
+ * As this serializer is supposed to deal with generic object types, this method returns Object.class.
+ *
+ * @return Object.class
+ */
+ public Class<?> getSerializableType()
+ {
+ return Object.class;
+ }
+
+ /**
+ * Converts the given object (with the given qname) in XML format.
+ * This method fails if there's no corresponding xml type for the given runtime type of the input object.
+ *
+ * @param obj the object to be marshalled.
+ * @param qname the qualified name that will be used in encoding.
+ */
+ public Element toXML(Object obj, QName qname) throws SoapFault
+ {
+ Class<?> clazz = obj.getClass();
+
+ Element result = null;
+
+ if (clazz == byte[].class) {
+ result = new ByteArraySerializer().toXML(obj,qname);
+ }
+ else {
+ result = SerializerRegistry.getInstance().getSerializer(clazz).toXML(obj,qname);
+ }
+ result.setAttribute(Names.XSI_TYPE, java2Xml.get(clazz));
+ return result;
+ }
+
+ /**
+ * Returns the xml type associated with the given class.
+ *
+ * @param clazz the class.
+ * @return the xml type associated with the given class.
+ */
+ public String getXmlType(Class<?> clazz)
+ {
+ return java2Xml.get(clazz);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/UUIDSerializer.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/UUIDSerializer.java
new file mode 100644
index 0000000000..408a8de6cf
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/muse/serializer/UUIDSerializer.java
@@ -0,0 +1,72 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.muse.serializer;
+
+import java.util.UUID;
+
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.serializer.Serializer;
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.addressing.soap.SoapFault;
+import org.w3c.dom.Element;
+
+/**
+ * Implementation of Muse Serializer for UUID type.
+ *
+ * @author Andrea Gazzarini
+ */
+public class UUIDSerializer implements Serializer
+{
+ /**
+ * Return a UUID representation of the given xml element.
+ *
+ * @param xml the element to unmarshal.
+ * @throws SoapFault when the unmarshalling fails.
+ */
+ public Object fromXML(Element elementData) throws SoapFault
+ {
+ return UUID.fromString(elementData.getTextContent());
+ }
+
+ /**
+ * Returns the java type associated to this class.
+ *
+ * @return the java type associated to this class.
+ */
+ public Class<?> getSerializableType()
+ {
+ return UUID.class;
+ }
+
+ /**
+ * Return an xml representation of the given UUID with the given name.
+ *
+ * @param object the UUID to marshal.
+ * @param qname the qualified (xml) name of the object to use in xml representation.
+ * @return the xml representation of the UUID.
+ * @throws SoapFault when the marshalling fails.
+ */
+ public Element toXML(Object obj, QName qname) throws SoapFault
+ {
+ return XmlUtils.createElement(qname, String.valueOf(obj));
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/notifications/LifeCycleEvent.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/notifications/LifeCycleEvent.java
new file mode 100644
index 0000000000..9284a62461
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/notifications/LifeCycleEvent.java
@@ -0,0 +1,149 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.notifications;
+
+import org.apache.muse.util.xml.XmlSerializable;
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.qpid.management.Names;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Object representation of a QMan entity lifecycle event notification.
+ * Note that with entity we mean both object(s) and event(s).
+ *
+ * At the moment there are only two types of lifecycle events : CREATE and REMOVE.
+ * The first one if fired when a new instance (event or object) is created, while the second
+ * one is fired when an object instance (events are transient objects so they are not destroyed)
+ * is removed.
+ *
+ * Developer Note : The marshal & unmarshal ops could be handled using JAXB but
+ * we are not sure about the running environment (JAXB libs were included only
+ * starting from 1.6)
+ *
+ * This is the event XML representation :
+ *
+ * <LifecycleEvent Type="created" timemillis="">
+ <Resource>
+ <ResourceId>16038bd5-b62b-4e86-9833-7560ed57b474</id>
+ <Package>org.qpid.apache.broker</package>
+ <Name>session</name>
+ </Resource>
+ </lifecycle-event>
+
+ * @author Andrea Gazzarini
+ */
+public class LifeCycleEvent implements XmlSerializable
+{
+ private final String _resourceId;
+ private final String _packageName;
+ private final String _name;
+
+ private final LifeCycleEventType _type;
+
+ /**
+ * Builds a new event with the given data.
+ *
+ * @param resourceId resource identifier.
+ * @param packageName resource package name.
+ * @param name resource name.
+ * @param type event type.
+ */
+ private LifeCycleEvent(String resourceId, String packageName, String name, LifeCycleEventType type)
+ {
+ this._resourceId = resourceId;
+ this._packageName = packageName;
+ this._name = name;
+ this._type = type;
+ }
+
+ /**
+ * Factory method for a new "CREATE" event.
+ * Builds a new "CREATE" event with the given data.
+ *
+ * @param resourceId resource identifier.
+ * @param packageName resource package name.
+ * @param name resource name.
+ */
+ public static LifeCycleEvent newCreateEvent(String resourceId, String packageName, String name)
+ {
+ return new LifeCycleEvent(resourceId, packageName, name, LifeCycleEventType.CREATED);
+ }
+
+ /**
+ * Factory method for a new "REMOVE" event.
+ * Builds a new "REMOVE" event with the given data.
+ *
+ * @param resourceId resource identifier.
+ * @param packageName resource package name.
+ * @param name resource name.
+ */
+ public static LifeCycleEvent newRemoveEvent(String resourceId, String packageName, String name)
+ {
+ return new LifeCycleEvent(resourceId, packageName, name, LifeCycleEventType.REMOVED);
+ }
+
+ /**
+ * Returns an XML representation of this event.
+ *
+ * @return an XML representation of this event.
+ */
+ public Element toXML()
+ {
+ return toXML(XmlUtils.EMPTY_DOC);
+ }
+
+ /**
+ * Returns an XML representation of this event using the given
+ * input document as owner.
+ *
+ * @return an XML representation of this event.
+ */
+ public Element toXML(Document factory)
+ {
+ Element lifeCycleEvent = XmlUtils.createElement(factory, Names.LIFECYCLE_EVENT_QNAME);
+
+ lifeCycleEvent.setAttribute(
+ "Type",
+ _type.toString());
+
+ lifeCycleEvent.setAttribute(
+ Names.TIMEMILLIS_ATTRIBUTE_NAME,
+ String.valueOf(System.currentTimeMillis()));
+
+ Element resource = XmlUtils.createElement(factory, Names.RESOURCE_QNAME);
+ lifeCycleEvent.appendChild(resource);
+
+ Element id = XmlUtils.createElement(factory, Names.RES_ID_QNAME);
+ id.setTextContent(_resourceId);
+ resource.appendChild(id);
+
+ Element packageName = XmlUtils.createElement(factory, Names.PACKAGE_NAME_QNAME);
+ packageName.setTextContent(_packageName);
+ resource.appendChild(packageName);
+
+ Element name = XmlUtils.createElement(factory, Names.ENTITY_NAME_QNAME);
+ name.setTextContent(_name);
+ resource.appendChild(name);
+
+ return lifeCycleEvent;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/management/wsdm/notifications/LifeCycleEventType.java b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/notifications/LifeCycleEventType.java
new file mode 100644
index 0000000000..9ce7bfc743
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/management/wsdm/notifications/LifeCycleEventType.java
@@ -0,0 +1,34 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.notifications;
+
+/**
+ * Event type enumeration.
+ * Event type are used as part of event WS-Notifications in order to inform
+ * the interested listeners about the lifecycle of a QMan managed entity (object or event instance).
+ *
+ * @author Andrea Gazzarini
+ */
+public enum LifeCycleEventType
+{
+ CREATED,
+ REMOVED;
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/qman/debug/WsdlDebugger.java b/java/management/client/src/main/java/org/apache/qpid/qman/debug/WsdlDebugger.java
new file mode 100644
index 0000000000..398a69817b
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/qman/debug/WsdlDebugger.java
@@ -0,0 +1,49 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.qman.debug;
+
+import javax.management.ObjectName;
+
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.qpid.transport.util.Logger;
+import org.w3c.dom.Node;
+
+/**
+ * Utility class used for debbugging WSDL documents
+ *
+ * @author Andrea Gazzarini
+ */
+public class WsdlDebugger {
+ public final static Logger LOGGER = Logger.get(WsdlDebugger.class);
+
+ /**
+ * Prints out to log the given node.
+ *
+ * @param node the xml node to be printed out.
+ */
+ public static void debug(ObjectName resourceId, Node node)
+ {
+ if (LOGGER.isDebugEnabled())
+ {
+ LOGGER.debug(resourceId+" : "+XmlUtils.toString(node, false,true));
+ }
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/org/apache/qpid/qman/debug/XmlDebugger.java b/java/management/client/src/main/java/org/apache/qpid/qman/debug/XmlDebugger.java
new file mode 100644
index 0000000000..600bb51858
--- /dev/null
+++ b/java/management/client/src/main/java/org/apache/qpid/qman/debug/XmlDebugger.java
@@ -0,0 +1,92 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.qman.debug;
+
+import javax.management.ObjectName;
+
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.qpid.transport.util.Logger;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Utility class used for debbugging XML messages
+ *
+ * @author Andrea Gazzarini
+ */
+public class XmlDebugger {
+ public final static Logger LOGGER = Logger.get(XmlDebugger.class);
+
+ /**
+ * Prints out to log the given node.
+ *
+ * @param node the xml node to be printed out.
+ */
+ public static void debug(Node node)
+ {
+ if (LOGGER.isDebugEnabled())
+ {
+ LOGGER.debug(XmlUtils.toString(node, false,true));
+ }
+ }
+
+ /**
+ * Prints out to log the given node.
+ *
+ * @param node the xml node to be printed out.
+ */
+ public static void debug(ObjectName resourceId, Node node)
+ {
+ if (LOGGER.isDebugEnabled())
+ {
+ LOGGER.debug(resourceId+" : "+XmlUtils.toString(node, false,true));
+ }
+ }
+
+
+ /**
+ * Prints out to log the given element array.
+ *
+ * @param elements the element array to be printed out.
+ */
+ public static void debug(Element [] elements)
+ {
+ if (LOGGER.isDebugEnabled())
+ {
+ StringBuilder builder = new StringBuilder();
+ for (Element element : elements) {
+ builder.append(XmlUtils.toString(element,false,true));
+ builder.append(System.getProperty("line.separator"));
+ }
+ LOGGER.debug(builder.toString());
+ }
+ }
+
+ /**
+ * Prints out to log the given node.
+ *
+ * @param node the xml node to be printed out.
+ */
+ public static void debug(String node)
+ {
+ LOGGER.debug(node);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/main/java/router-entries/adapter/resource-instance-1.xml b/java/management/client/src/main/java/router-entries/adapter/resource-instance-1.xml
new file mode 100644
index 0000000000..f7d72c2903
--- /dev/null
+++ b/java/management/client/src/main/java/router-entries/adapter/resource-instance-1.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<wsa:ReferenceParameters xmlns:wsa="http://www.w3.org/2005/08/addressing"/>
diff --git a/java/management/client/src/main/java/router-entries/consumer/resource-instance-1.xml b/java/management/client/src/main/java/router-entries/consumer/resource-instance-1.xml
new file mode 100644
index 0000000000..599ac87a57
--- /dev/null
+++ b/java/management/client/src/main/java/router-entries/consumer/resource-instance-1.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<wsa:ReferenceParameters xmlns:wsa="http://www.w3.org/2005/08/addressing"/> \ No newline at end of file
diff --git a/java/management/client/src/main/java/wsdl/QManAdapter.rmd b/java/management/client/src/main/java/wsdl/QManAdapter.rmd
new file mode 100644
index 0000000000..31e921a06b
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/QManAdapter.rmd
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<Definitions xmlns="http://docs.oasis-open.org/wsrf/rmd-1">
+ <MetadataDescriptor
+ xmlns:wsrf-sg="http://docs.oasis-open.org/wsrf/sg-2"
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2"
+ xmlns:wsrl="http://docs.oasis-open.org/wsrf/rl-2"
+ xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2"
+ xmlns:wst="http://docs.oasis-open.org/wsn/t-1"
+ xmlns:muws1="http://docs.oasis-open.org/wsdm/muws1-2.xsd"
+ xmlns:muws2="http://docs.oasis-open.org/wsdm/muws2-2.xsd"
+ xmlns:qman="http://amqp.apache.org/qpid/management/qman"
+ name="WsDmAdapterMetadata"
+ interface="qman:QManAdapterPortType"
+ wsdlLocation="http://amqp.apache.org/qpid/management/qman QManAdapter.wsdl">
+ <Property name="wsrf-sg:MembershipContentRule" modifiability="read-only" mutability="mutable">
+ <StaticValues>
+ <wsrf-sg:MembershipContentRule MemberInterface="qman:QManWsResourcePortType"/>
+ </StaticValues>
+ </Property>
+ <Property name="wsrf-sg:Entry" modifiability="read-only" mutability="mutable" />
+ <Property name="wsrf-rp:QueryExpressionDialect" modifiability="read-only" mutability="constant" />
+ <Property name="wsnt:FixedTopicSet" modifiability="read-only" mutability="constant" />
+ <Property name="wst:TopicSet" modifiability="read-only" mutability="mutable" />
+ <Property name="wsnt:TopicExpression" modifiability="read-only" mutability="mutable" />
+ <Property name="wsnt:TopicExpressionDialect" modifiability="read-only" mutability="mutable" />
+ </MetadataDescriptor>
+</Definitions>
diff --git a/java/management/client/src/main/java/wsdl/QManAdapter.wsdl b/java/management/client/src/main/java/wsdl/QManAdapter.wsdl
new file mode 100644
index 0000000000..4b26862604
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/QManAdapter.wsdl
@@ -0,0 +1,694 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<wsdl:definitions
+ targetNamespace="http://amqp.apache.org/qpid/management/qman"
+ xmlns:qman="http://amqp.apache.org/qpid/management/qman"
+ xmlns="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:wsdl-soap="http://schemas.xmlsoap.org/wsdl/soap/"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex"
+ xmlns:wsrf-r="http://docs.oasis-open.org/wsrf/r-2"
+ xmlns:wsrf-rl="http://docs.oasis-open.org/wsrf/rl-2"
+ xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2"
+ xmlns:wsrf-sg="http://docs.oasis-open.org/wsrf/sg-2"
+ xmlns:wsrf-sgw="http://docs.oasis-open.org/wsrf/sgw-2"
+ xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2"
+ xmlns:wsntw="http://docs.oasis-open.org/wsn/bw-2"
+ xmlns:wst="http://docs.oasis-open.org/wsn/t-1"
+ xmlns:wsrmd="http://docs.oasis-open.org/wsrf/rmd-1"
+ xmlns:muws1="http://docs.oasis-open.org/wsdm/muws1-2.xsd"
+ xmlns:muws2="http://docs.oasis-open.org/wsdm/muws2-2.xsd"
+ name="QManAdapter" >
+ <wsdl:types>
+ <xsd:schema elementFormDefault="qualified" targetNamespace="http://docs.oasis-open.org/wsrf/bf-2">
+ <xsd:include schemaLocation="WS-BaseFaults-1_2.xsd" />
+ </xsd:schema>
+ <xsd:schema elementFormDefault="qualified" targetNamespace="http://docs.oasis-open.org/wsrf/rp-2">
+ <xsd:include schemaLocation="WS-ResourceProperties-1_2.xsd" />
+ </xsd:schema>
+ <xsd:schema elementFormDefault="qualified" targetNamespace="http://docs.oasis-open.org/wsrf/r-2">
+ <xsd:include schemaLocation="WS-Resource-1_2.xsd" />
+ </xsd:schema>
+ <xsd:schema elementFormDefault="qualified" targetNamespace="http://www.w3.org/2005/08/addressing">
+ <xsd:include schemaLocation="WS-Addressing-2005_08.xsd"/>
+ </xsd:schema>
+ <xsd:schema elementFormDefault="qualified" targetNamespace="http://schemas.xmlsoap.org/ws/2004/09/mex">
+ <xsd:include schemaLocation="WS-MetadataExchange-2004_09.xsd"/>
+ </xsd:schema>
+ <xsd:schema elementFormDefault="qualified" targetNamespace="http://docs.oasis-open.org/wsrf/sg-2">
+ <xsd:include schemaLocation="WS-ServiceGroup-1_2.xsd" />
+ </xsd:schema>
+ <xsd:schema elementFormDefault="qualified" targetNamespace="http://docs.oasis-open.org/wsdm/muws1-2.xsd">
+ <xsd:include schemaLocation="WSDM-MUWS-Part1-1_1.xsd" />
+ </xsd:schema>
+ <xsd:schema elementFormDefault="qualified" targetNamespace="http://docs.oasis-open.org/wsdm/muws2-2.xsd">
+ <xsd:include schemaLocation="WSDM-MUWS-Part2-1_1.xsd" />
+ </xsd:schema>
+ <xsd:schema elementFormDefault="qualified" targetNamespace="http://docs.oasis-open.org/wsn/b-2">
+ <xsd:include schemaLocation="WS-BaseNotification-1_3.xsd" />
+ </xsd:schema>
+ <xsd:schema elementFormDefault="qualified" targetNamespace="http://docs.oasis-open.org/wsn/t-1">
+ <xsd:include schemaLocation="WS-Topics-1_3.xsd" />
+ </xsd:schema>
+ <xsd:schema targetNamespace="http://amqp.apache.org/qpid/management/qman">
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/bf-2" schemaLocation="WS-BaseFaults-1_2.xsd"/>
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/sg-2" schemaLocation="WS-ServiceGroup-1_2.xsd"/>
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/rp-2" schemaLocation="WS-ResourceProperties-1_2.xsd"/>
+ <xsd:import namespace="http://docs.oasis-open.org/wsn/b-2" schemaLocation="WS-BaseNotification-1_3.xsd"/>
+ <xsd:import namespace="http://docs.oasis-open.org/wsn/t-1" schemaLocation="WS-Topics-1_3.xsd"/>
+ <xsd:element name="WsDmAdapterResourceProperties">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsrf-sg:Entry"/>
+ <xsd:element ref="wsrf-sg:MembershipContentRule"/>
+ <xsd:element ref="wsrf-rp:QueryExpressionDialect" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element ref="wsnt:FixedTopicSet" />
+ <xsd:element ref="wst:TopicSet" minOccurs="0" />
+ <xsd:element ref="wsnt:TopicExpression" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element ref="wsnt:TopicExpressionDialect" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="OperationInvocationFault">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="EntityInstanceNotFoundFault">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="MalformedEntityNameFault">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="NoSuchAttributeFault">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="Connect">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="host" type="xsd:string" minOccurs="1" nillable="false"/>
+ <xsd:element name="port" type="xsd:integer" minOccurs="1" nillable="false"/>
+ <xsd:element name="username" type="xsd:string" minOccurs="1" nillable="false"/>
+ <xsd:element name="password" type="xsd:string" minOccurs="1" nillable="false"/>
+ <xsd:element name="virtualHost" type="xsd:string" minOccurs="1" nillable="false"/>
+ <xsd:element name="initialPoolCapacity" type="xsd:integer" minOccurs="1" nillable="false"/>
+ <xsd:element name="maxPoolCapacity" type="xsd:integer" minOccurs="1" nillable="false"/>
+ <xsd:element name="maxWaitTimeout" type="xsd:long" minOccurs="1" nillable="false"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="ConnectResponse"/>
+ </xsd:schema>
+ </wsdl:types>
+
+ <wsdl:message name="SubscribeRequest">
+ <wsdl:part name="SubscribeRequest" element="wsnt:Subscribe" />
+ </wsdl:message>
+
+ <wsdl:message name="SubscribeResponse">
+ <wsdl:part name="SubscribeResponse"
+ element="wsnt:SubscribeResponse" />
+ </wsdl:message>
+
+ <wsdl:message name="SubscribeCreationFailedFault">
+ <wsdl:part name="SubscribeCreationFailedFault"
+ element="wsnt:SubscribeCreationFailedFault" />
+ </wsdl:message>
+
+ <wsdl:message name="TopicExpressionDialectUnknownFault">
+ <wsdl:part name="TopicExpressionDialectUnknownFault"
+ element="wsnt:TopicExpressionDialectUnknownFault" />
+ </wsdl:message>
+
+ <wsdl:message name="InvalidFilterFault">
+ <wsdl:part name="InvalidFilterFault"
+ element="wsnt:InvalidFilterFault" />
+ </wsdl:message>
+
+ <wsdl:message name="InvalidProducerPropertiesExpressionFault">
+ <wsdl:part name="InvalidProducerPropertiesExpressionFault"
+ element="wsnt:InvalidProducerPropertiesExpressionFault" />
+ </wsdl:message>
+
+ <wsdl:message name="InvalidMessageContentExpressionFault">
+ <wsdl:part name="InvalidMessageContentExpressionFault"
+ element="wsnt:InvalidMessageContentExpressionFault" />
+ </wsdl:message>
+
+ <wsdl:message name="UnrecognizedPolicyRequestFault">
+ <wsdl:part name="UnrecognizedPolicyRequestFault"
+ element="wsnt:UnrecognizedPolicyRequestFault" />
+ </wsdl:message>
+
+ <wsdl:message name="UnsupportedPolicyRequestFault">
+ <wsdl:part name="UnsupportedPolicyRequestFault"
+ element="wsnt:UnsupportedPolicyRequestFault" />
+ </wsdl:message>
+
+ <wsdl:message name="NotifyMessageNotSupportedFault">
+ <wsdl:part name="NotifyMessageNotSupportedFault"
+ element="wsnt:NotifyMessageNotSupportedFault" />
+ </wsdl:message>
+
+ <wsdl:message name="UnacceptableInitialTerminationTimeFault">
+ <wsdl:part name="UnacceptableInitialTerminationTimeFault"
+ element="wsnt:UnacceptableInitialTerminationTimeFault" />
+ </wsdl:message>
+
+ <!-- ========== NotificationProducer::GetCurrentMessage ===========
+ GetCurrentMessage(topicExpression)
+ returns: a NotificationMessage (xsd:any)
+ -->
+ <wsdl:message name="GetCurrentMessageRequest">
+ <wsdl:part name="GetCurrentMessageRequest"
+ element="wsnt:GetCurrentMessage" />
+ </wsdl:message>
+
+ <wsdl:message name="GetCurrentMessageResponse">
+ <wsdl:part name="GetCurrentMessageResponse"
+ element="wsnt:GetCurrentMessageResponse" />
+ </wsdl:message>
+
+ <wsdl:message name="InvalidTopicExpressionFault">
+ <wsdl:part name="InvalidTopicExpressionFault"
+ element="wsnt:InvalidTopicExpressionFault" />
+ </wsdl:message>
+
+ <wsdl:message name="TopicNotSupportedFault">
+ <wsdl:part name="TopicNotSupportedFault"
+ element="wsnt:TopicNotSupportedFault" />
+ </wsdl:message>
+
+ <wsdl:message name="MultipleTopicsSpecifiedFault">
+ <wsdl:part name="MultipleTopicsSpecifiedFault"
+ element="wsnt:MultipleTopicsSpecifiedFault" />
+ </wsdl:message>
+
+ <wsdl:message name="NoCurrentMessageOnTopicFault">
+ <wsdl:part name="NoCurrentMessageOnTopicFault"
+ element="wsnt:NoCurrentMessageOnTopicFault" />
+ </wsdl:message>
+
+
+
+ <wsdl:message name="OperationInvocationFaultMessage">
+ <wsdl:part name="OperationInvocationFault" element="qman:OperationInvocationFault" />
+ </wsdl:message>
+ <wsdl:message name="EntityInstanceNotFoundFaultMessage">
+ <wsdl:part name="EntityInstanceNotFound" element="qman:EntityInstanceNotFoundFault" />
+ </wsdl:message>
+ <wsdl:message name="MalformedEntityNameFaultMessage">
+ <wsdl:part name="MalformedEntityName" element="qman:MalformedEntityNameFault" />
+ </wsdl:message>
+ <wsdl:message name="NoSuchAttributeFaultMessage">
+ <wsdl:part name="NoSuchAttributeFault" element="qman:NoSuchAttributeFault" />
+ </wsdl:message>
+ <wsdl:message name="ConnectRequestMessage">
+ <wsdl:part name="ConnectRequest" element="qman:Connect" />
+ </wsdl:message>
+ <wsdl:message name="ConnectResponseMessage">
+ <wsdl:part name="ConnectResponse" element="qman:ConnectResponse" />
+ </wsdl:message>
+ <wsdl:message name="InvalidResourcePropertyQNameFault">
+ <wsdl:part name="InvalidResourcePropertyQNameFault" element="wsrf-rp:InvalidResourcePropertyQNameFault" />
+ </wsdl:message>
+ <wsdl:message name="ResourceUnknownFault">
+ <wsdl:part name="ResourceUnknownFault" element="wsrf-r:ResourceUnknownFault" />
+ </wsdl:message>
+ <wsdl:message name="ResourceUnavailableFault">
+ <wsdl:part name="ResourceUnavailableFault" element="wsrf-r:ResourceUnavailableFault" />
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyDocumentRequest">
+ <wsdl:part name="GetResourcePropertyDocumentRequest" element="wsrf-rp:GetResourcePropertyDocument"/>
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyDocumentResponse">
+ <wsdl:part name="GetResourcePropertyDocumentResponse" element="wsrf-rp:GetResourcePropertyDocumentResponse"/>
+ </wsdl:message>
+ <wsdl:message name="GetMultipleResourcePropertiesRequest">
+ <wsdl:part name="GetMultipleResourcePropertiesRequest" element="wsrf-rp:GetMultipleResourceProperties" />
+ </wsdl:message>
+ <wsdl:message name="GetMultipleResourcePropertiesResponse">
+ <wsdl:part name="GetMultipleResourcePropertiesResponse" element="wsrf-rp:GetMultipleResourcePropertiesResponse" />
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyRequest">
+ <wsdl:part name="GetResourcePropertyRequest" element="wsrf-rp:GetResourceProperty" />
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyResponse">
+ <wsdl:part name="GetResourcePropertyResponse" element="wsrf-rp:GetResourcePropertyResponse" />
+ </wsdl:message>
+ <wsdl:message name="GetMetadataRequestMessage">
+ <wsdl:part name="GetMetadataMsg" element="wsx:GetMetadata" />
+ </wsdl:message>
+ <wsdl:message name="GetMetadataResponseMessage">
+ <wsdl:part name="GetMetadataResponseMsg" element="wsx:Metadata" />
+ </wsdl:message>
+ <wsdl:message name="QueryResourcePropertiesRequest">
+ <wsdl:part name="QueryResourcePropertiesRequest" element="wsrf-rp:QueryResourceProperties" />
+ </wsdl:message>
+ <wsdl:message name="QueryResourcePropertiesResponse">
+ <wsdl:part name="QueryResourcePropertiesResponse" element="wsrf-rp:QueryResourcePropertiesResponse" />
+ </wsdl:message>
+ <wsdl:message name="UnknownQueryExpressionDialectFault">
+ <wsdl:part name="UnknownQueryExpressionDialectFault" element="wsrf-rp:UnknownQueryExpressionDialectFault" />
+ </wsdl:message>
+ <wsdl:message name="InvalidQueryExpressionFault">
+ <wsdl:part name="InvalidQueryExpressionFault" element="wsrf-rp:InvalidQueryExpressionFault" />
+ </wsdl:message>
+ <wsdl:message name="QueryEvaluationErrorFault">
+ <wsdl:part name="QueryEvaluationErrorFault" element="wsrf-rp:QueryEvaluationErrorFault" />
+ </wsdl:message>
+ <wsdl:portType
+ name="QManAdapterPortType"
+ wsrf-rp:ResourceProperties="qman:WsDmAdapterResourceProperties"
+ wsrmd:Descriptor="WsDmAdapterMetadata" wsrmd:DescriptorLocation="QManAdapter.rmd">
+
+ <wsdl:operation name="Subscribe">
+ <wsdl:input
+ wsa:Action="http://docs.oasis-open.org/wsn/bw-2/NotificationProducer/SubscribeRequest"
+ message="qman:SubscribeRequest" />
+ <wsdl:output
+ wsa:Action="http://docs.oasis-open.org/wsn/bw-2/NotificationProducer/SubscribeResponse"
+ message="qman:SubscribeResponse" />
+ <wsdl:fault name="ResourceUnknownFault"
+ message="qman:ResourceUnknownFault" />
+ <wsdl:fault name="InvalidFilterFault"
+ message="qman:InvalidFilterFault" />
+ <wsdl:fault name="TopicExpressionDialectUnknownFault"
+ message="qman:TopicExpressionDialectUnknownFault" />
+ <wsdl:fault name="InvalidTopicExpressionFault"
+ message="qman:InvalidTopicExpressionFault" />
+ <wsdl:fault name="TopicNotSupportedFault"
+ message="qman:TopicNotSupportedFault" />
+ <wsdl:fault name="InvalidProducerPropertiesExpressionFault"
+ message="qman:InvalidProducerPropertiesExpressionFault" />
+ <wsdl:fault name="InvalidMessageContentExpressionFault"
+ message="qman:InvalidMessageContentExpressionFault" />
+ <wsdl:fault name="UnacceptableInitialTerminationTimeFault"
+ message="qman:UnacceptableInitialTerminationTimeFault" />
+ <wsdl:fault name="UnrecognizedPolicyRequestFault"
+ message="qman:UnrecognizedPolicyRequestFault" />
+ <wsdl:fault name="UnsupportedPolicyRequestFault"
+ message="qman:UnsupportedPolicyRequestFault" />
+ <wsdl:fault name="NotifyMessageNotSupportedFault"
+ message="qman:NotifyMessageNotSupportedFault" />
+ <wsdl:fault name="SubscribeCreationFailedFault"
+ message="qman:SubscribeCreationFailedFault" />
+ </wsdl:operation>
+ <wsdl:operation name="GetCurrentMessage">
+ <wsdl:input
+ wsa:Action="http://docs.oasis-open.org/wsn/bw-2/NotificationProducer/GetCurrentMessageRequest"
+ message="qman:GetCurrentMessageRequest" />
+ <wsdl:output
+ wsa:Action="http://docs.oasis-open.org/wsn/bw-2/NotificationProducer/GetCurrentMessageResponse"
+ message="qman:GetCurrentMessageResponse" />
+ <wsdl:fault name="ResourceUnknownFault"
+ message="qman:ResourceUnknownFault" />
+ <wsdl:fault name="TopicExpressionDialectUnknownFault"
+ message="qman:TopicExpressionDialectUnknownFault" />
+ <wsdl:fault name="InvalidTopicExpressionFault"
+ message="qman:InvalidTopicExpressionFault" />
+ <wsdl:fault name="TopicNotSupportedFault"
+ message="qman:TopicNotSupportedFault" />
+ <wsdl:fault name="NoCurrentMessageOnTopicFault"
+ message="qman:NoCurrentMessageOnTopicFault" />
+ <wsdl:fault name="MultipleTopicsSpecifiedFault"
+ message="qman:MultipleTopicsSpecifiedFault" />
+ </wsdl:operation>
+
+ <wsdl:operation name="QueryResourceProperties">
+ <wsdl:input
+ wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/QueryResourceProperties/QueryResourcePropertiesRequest"
+ name="QueryResourcePropertiesRequest"
+ message="qman:QueryResourcePropertiesRequest" />
+ <wsdl:output
+ wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/QueryResourceProperties/QueryResourcePropertiesResponse"
+ name="QueryResourcePropertiesResponse"
+ message="qman:QueryResourcePropertiesResponse" />
+ <wsdl:fault name="ResourceUnknownFault" message="qman:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault" message="qman:ResourceUnavailableFault"/>
+ <wsdl:fault name="UnknownQueryExpressionDialectFault" message="qman:UnknownQueryExpressionDialectFault"/>
+ <wsdl:fault name="InvalidQueryExpressionFault" message="qman:InvalidQueryExpressionFault"/>
+ <wsdl:fault name="QueryEvaluationErrorFault" message="qman:QueryEvaluationErrorFault" />
+ </wsdl:operation>
+ <wsdl:operation name="Connect">
+ <wsdl:documentation>
+ Connects QMan with a new broker.
+ </wsdl:documentation>
+ <wsdl:input
+ wsa:Action="http://amqp.apache.org/qpid/management/qman/Connect"
+ name="ConnectRequestInput"
+ message="qman:ConnectRequestMessage" />
+ <wsdl:output
+ wsa:Action="http://amqp.apache.org/qpid/management/qman/ConnectResponse"
+ name="ConnectResponseOutput"
+ message="qman:ConnectResponseMessage" />
+ </wsdl:operation>
+ <wsdl:operation name="GetMultipleResourceProperties">
+ <wsdl:documentation>
+ Returns an array containing values for the requested properties.
+ Note that using this method it's possibile to retrieve only the value of the QManService properties.
+ That is : this method is not supposed to be used for retrieve attributes of the QMan managed entities. For that, the GetManagedEntityAttributeValue must be used.</wsdl:documentation>
+ <wsdl:input
+ wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetMultipleResourceProperties/GetMultipleResourcePropertiesRequest"
+ name="GetMultipleResourcePropertiesRequest"
+ message="qman:GetMultipleResourcePropertiesRequest" />
+ <wsdl:output
+ wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetMultipleResourceProperties/GetMultipleResourcePropertiesResponse"
+ name="GetMultipleResourcePropertiesResponse"
+ message="qman:GetMultipleResourcePropertiesResponse" />
+ <wsdl:fault name="ResourceUnknownFault" message="qman:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault" message="qman:ResourceUnavailableFault"/>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault" message="qman:InvalidResourcePropertyQNameFault" />
+ </wsdl:operation>
+ <wsdl:operation name="GetResourcePropertyDocument">
+ <wsdl:documentation>
+ Returns resource's entire WS-RP document, with the most up-to-date values of all properties. Note that using this method it's possibile to retrieve only the value of the QManService properties.
+ That is : this method is not supposed to be used for retrieve attributes of the QMan managed entities. For that, the GetManagedEntityAttributeValue must be used.</wsdl:documentation>
+ <wsdl:input
+ wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourcePropertyDocument/GetResourcePropertyDocumentRequest"
+ name="GetResourcePropertyDocumentRequest"
+ message="qman:GetResourcePropertyDocumentRequest"/>
+ <wsdl:output
+ wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourcePropertyDocument/GetResourcePropertyDocumentResponse"
+ name="GetResourcePropertyDocumentResponse"
+ message="qman:GetResourcePropertyDocumentResponse"/>
+ <wsdl:fault name="ResourceUnknownFault" message="qman:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault" message="qman:ResourceUnavailableFault"/>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourceProperty">
+ <wsdl:documentation>
+ Returns the value of the given property. Note that using this method it's possibile to retrieve only the value of the QManService properties.
+ That is : this method is not supposed to be used for retrieve attributes of the QMan managed entities. For that, the GetManagedEntityAttributeValue must be used.
+ </wsdl:documentation>
+ <wsdl:input
+ wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest"
+ name="GetResourcePropertyRequest"
+ message="qman:GetResourcePropertyRequest" />
+ <wsdl:output
+ wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse"
+ name="GetResourcePropertyResponse"
+ message="qman:GetResourcePropertyResponse" />
+ <wsdl:fault name="ResourceUnknownFault" message="qman:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault" message="qman:ResourceUnavailableFault"/>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault" message="qman:InvalidResourcePropertyQNameFault" />
+ </wsdl:operation>
+ <wsdl:operation name="GetMetadata">
+ <wsdl:documentation>
+ Implementation of the WS-MetadataExchange GetMetadata port type. Note that the only supported metadata type (dialect) is WSDL.
+ </wsdl:documentation>
+ <wsdl:input
+ wsa:Action="http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata"
+ name="GetMetadataMsg"
+ message="qman:GetMetadataRequestMessage"/>
+ <wsdl:output
+ wsa:Action="http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadataResponse"
+ name="GetMetadataResponseMsg"
+ message="qman:GetMetadataResponseMessage"/>
+ </wsdl:operation>
+ </wsdl:portType>
+ <wsdl:binding name="QManAdapterBinding" type="qman:QManAdapterPortType">
+ <wsdl-soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
+ <wsdl:operation name="Subscribe">
+ <wsdl-soap:operation
+ soapAction="http://ws.apache.org/muse/test/wsrf/Subscribe" />
+ <wsdl:input>
+ <wsdl-soap:body use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ namespace="http://ws.apache.org/muse/test/wsrf" use="encoded"
+ name="ResourceUnknownFault" />
+ </wsdl:fault>
+ <wsdl:fault name="InvalidFilterFault">
+ <wsdl-soap:fault
+ namespace="http://ws.apache.org/muse/test/wsrf" use="encoded"
+ name="InvalidFilterFault" />
+ </wsdl:fault>
+ <wsdl:fault name="TopicExpressionDialectUnknownFault">
+ <wsdl-soap:fault
+ namespace="http://ws.apache.org/muse/test/wsrf" use="encoded"
+ name="TopicExpressionDialectUnknownFault" />
+ </wsdl:fault>
+ <wsdl:fault name="InvalidTopicExpressionFault">
+ <wsdl-soap:fault
+ namespace="http://ws.apache.org/muse/test/wsrf" use="encoded"
+ name="InvalidTopicExpressionFault" />
+ </wsdl:fault>
+ <wsdl:fault name="TopicNotSupportedFault">
+ <wsdl-soap:fault
+ namespace="http://ws.apache.org/muse/test/wsrf" use="encoded"
+ name="TopicNotSupportedFault" />
+ </wsdl:fault>
+ <wsdl:fault
+ name="InvalidProducerPropertiesExpressionFault">
+ <wsdl-soap:fault
+ namespace="http://ws.apache.org/muse/test/wsrf" use="encoded"
+ name="InvalidProducerPropertiesExpressionFault" />
+ </wsdl:fault>
+ <wsdl:fault name="InvalidMessageContentExpressionFault">
+ <wsdl-soap:fault
+ namespace="http://ws.apache.org/muse/test/wsrf" use="encoded"
+ name="InvalidMessageContentExpressionFault" />
+ </wsdl:fault>
+ <wsdl:fault
+ name="UnacceptableInitialTerminationTimeFault">
+ <wsdl-soap:fault
+ namespace="http://ws.apache.org/muse/test/wsrf" use="encoded"
+ name="UnacceptableInitialTerminationTimeFault" />
+ </wsdl:fault>
+ <wsdl:fault name="UnrecognizedPolicyRequestFault">
+ <wsdl-soap:fault
+ namespace="http://ws.apache.org/muse/test/wsrf" use="encoded"
+ name="UnrecognizedPolicyRequestFault" />
+ </wsdl:fault>
+ <wsdl:fault name="UnsupportedPolicyRequestFault">
+ <wsdl-soap:fault
+ namespace="http://ws.apache.org/muse/test/wsrf" use="encoded"
+ name="UnsupportedPolicyRequestFault" />
+ </wsdl:fault>
+ <wsdl:fault name="NotifyMessageNotSupportedFault">
+ <wsdl-soap:fault
+ namespace="http://ws.apache.org/muse/test/wsrf" use="encoded"
+ name="NotifyMessageNotSupportedFault" />
+ </wsdl:fault>
+ <wsdl:fault name="SubscribeCreationFailedFault">
+ <wsdl-soap:fault
+ namespace="http://ws.apache.org/muse/test/wsrf" use="encoded"
+ name="SubscribeCreationFailedFault" />
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="GetCurrentMessage">
+ <wsdl-soap:operation
+ soapAction="http://ws.apache.org/muse/test/wsrf/GetCurrentMessage" />
+ <wsdl:input>
+ <wsdl-soap:body use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ namespace="http://ws.apache.org/muse/test/wsrf" use="encoded"
+ name="ResourceUnknownFault" />
+ </wsdl:fault>
+ <wsdl:fault name="TopicExpressionDialectUnknownFault">
+ <wsdl-soap:fault
+ namespace="http://ws.apache.org/muse/test/wsrf" use="encoded"
+ name="TopicExpressionDialectUnknownFault" />
+ </wsdl:fault>
+ <wsdl:fault name="InvalidTopicExpressionFault">
+ <wsdl-soap:fault
+ namespace="http://ws.apache.org/muse/test/wsrf" use="encoded"
+ name="InvalidTopicExpressionFault" />
+ </wsdl:fault>
+ <wsdl:fault name="TopicNotSupportedFault">
+ <wsdl-soap:fault
+ namespace="http://ws.apache.org/muse/test/wsrf" use="encoded"
+ name="TopicNotSupportedFault" />
+ </wsdl:fault>
+ <wsdl:fault name="NoCurrentMessageOnTopicFault">
+ <wsdl-soap:fault
+ namespace="http://ws.apache.org/muse/test/wsrf" use="encoded"
+ name="NoCurrentMessageOnTopicFault" />
+ </wsdl:fault>
+ <wsdl:fault name="MultipleTopicsSpecifiedFault">
+ <wsdl-soap:fault
+ namespace="http://ws.apache.org/muse/test/wsrf" use="encoded"
+ name="MultipleTopicsSpecifiedFault" />
+ </wsdl:fault>
+ </wsdl:operation>
+
+ <wsdl:operation name="QueryResourceProperties">
+ <wsdl-soap:operation soapAction="QueryResourceProperties"/>
+ <wsdl:input name="QueryResourcePropertiesRequest">
+ <wsdl-soap:body
+ use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:input>
+ <wsdl:output name="QueryResourcePropertiesResponse">
+ <wsdl-soap:body
+ use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="ResourceUnknownFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="ResourceUnavailableFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="UnknownQueryExpressionDialectFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="UnknownQueryExpressionDialectFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidQueryExpressionFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="InvalidQueryExpressionFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="QueryEvaluationErrorFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="QueryEvaluationErrorFault"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="Connect">
+ <wsdl-soap:operation soapAction="Connect" />
+ <wsdl:input>
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="GetMultipleResourceProperties">
+ <wsdl-soap:operation soapAction="GetMultipleResourceProperties"/>
+ <wsdl:input name="GetMultipleResourcePropertiesRequest">
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:input>
+ <wsdl:output name="GetMultipleResourcePropertiesResponse">
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="ResourceUnknownFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="ResourceUnavailableFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="InvalidResourcePropertyQNameFault"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourcePropertyDocument">
+ <wsdl-soap:operation soapAction="GetResourcePropertyDocument"/>
+ <wsdl:input name="GetResourcePropertyDocumentRequest">
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:input>
+ <wsdl:output name="GetResourcePropertyDocumentResponse">
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="ResourceUnknownFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="ResourceUnavailableFault"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourceProperty">
+ <wsdl-soap:operation soapAction="GetResourceProperty"/>
+ <wsdl:input name="GetResourcePropertyRequest">
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:input>
+ <wsdl:output name="GetResourcePropertyResponse">
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="ResourceUnknownFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="ResourceUnavailableFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="InvalidResourcePropertyQNameFault"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="GetMetadata">
+ <wsdl-soap:operation soapAction="GetMetadata" />
+ <wsdl:input>
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
+ </wsdl:output>
+ </wsdl:operation>
+ </wsdl:binding>
+ <wsdl:service name="QManAdapterService">
+ <wsdl:port name="QManAdapterPort" binding="qman:QManAdapterBinding">
+ <wsdl-soap:address location="http://romagazzarini:8080/qman/services/adapter"/>
+ </wsdl:port>
+ </wsdl:service>
+</wsdl:definitions> \ No newline at end of file
diff --git a/java/management/client/src/main/java/wsdl/QManWsResource.rmd b/java/management/client/src/main/java/wsdl/QManWsResource.rmd
new file mode 100644
index 0000000000..c4944440e0
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/QManWsResource.rmd
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<Definitions xmlns="http://docs.oasis-open.org/wsrf/rmd-1" >
+ <MetadataDescriptor
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2"
+ xmlns:wsrl="http://docs.oasis-open.org/wsrf/rl-2"
+ xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2"
+ xmlns:wst="http://docs.oasis-open.org/wsn/t-1"
+ xmlns:muws1="http://docs.oasis-open.org/wsdm/muws1-2.xsd"
+ xmlns:muws2="http://docs.oasis-open.org/wsdm/muws2-2.xsd"
+ xmlns:qman="http://amqp.apache.org/qpid/management/qman"
+ name="QManWsResourceMetadata"
+ interface="qman:QManWsResourcePortType"
+ wsdlLocation="http://ws.apache.org/muse/test/wsrf QManWsResource.wsdl" >
+ <Property name="wsrf-rp:QueryExpressionDialect" modifiability="read-only" mutability="constant" />
+ </MetadataDescriptor>
+
+</Definitions> \ No newline at end of file
diff --git a/java/management/client/src/main/java/wsdl/QManWsResource.wsdl b/java/management/client/src/main/java/wsdl/QManWsResource.wsdl
new file mode 100644
index 0000000000..16169c9b78
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/QManWsResource.wsdl
@@ -0,0 +1,507 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<wsdl:definitions
+ targetNamespace="http://amqp.apache.org/qpid/management/qman"
+ xmlns:qman="http://amqp.apache.org/qpid/management/qman"
+ xmlns="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:wsrmd="http://docs.oasis-open.org/wsrf/rmd-1"
+ xmlns:wsrf-r="http://docs.oasis-open.org/wsrf/r-2"
+ xmlns:wsrf-rl="http://docs.oasis-open.org/wsrf/rl-2"
+ xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2"
+ xmlns:wsdl-soap="http://schemas.xmlsoap.org/wsdl/soap/"
+ name="QManWsResource">
+ <wsdl:types>
+ <xsd:schema
+ elementFormDefault="qualified"
+ targetNamespace="http://www.w3.org/2005/08/addressing">
+ <xsd:include schemaLocation="WS-Addressing-2005_08.xsd"/>
+ </xsd:schema>
+ <xsd:schema
+ elementFormDefault="qualified"
+ targetNamespace="http://schemas.xmlsoap.org/ws/2004/09/mex">
+ <xsd:include schemaLocation="WS-MetadataExchange-2004_09.xsd"/>
+ </xsd:schema>
+ <xsd:schema
+ elementFormDefault="qualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/rl-2">
+ <xsd:include schemaLocation="WS-ResourceLifetime-1_2.xsd" />
+ </xsd:schema>
+ <xsd:schema
+ elementFormDefault="qualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/rp-2">
+ <xsd:include schemaLocation="WS-ResourceProperties-1_2.xsd" />
+ </xsd:schema>
+ <xsd:schema
+ elementFormDefault="qualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/r-2">
+ <xsd:include schemaLocation="WS-Resource-1_2.xsd" />
+ </xsd:schema>
+ <xsd:schema
+ elementFormDefault="qualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/rmd-1">
+ <xsd:include schemaLocation="WS-ResourceMetadataDescriptor-CD-01.xsd" />
+ </xsd:schema>
+ <xsd:schema
+ elementFormDefault="qualified"
+ targetNamespace="http://amqp.apache.org/qpid/management/qman">
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/rl-2" schemaLocation="WS-ResourceLifetime-1_2.xsd"/>
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/rp-2" schemaLocation="WS-ResourceProperties-1_2.xsd"/>
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/bf-2" schemaLocation="WS-BaseFaults-1_2.xsd"/>
+ <xsd:element name="QManWsResourceProperties">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsrf-rp:QueryExpressionDialect" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="QManFault">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="MethodInvocationFault">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="EntityInstanceNotFoundFault">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="MalformedEntityNameFault">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="NoSuchAttributeFault">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:complexType name="uuid">
+ <xsd:sequence>
+ <xsd:element name="uuid" type="xsd:string"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="map">
+ <xsd:sequence>
+ <xsd:element name="entry" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="key" type="xsd:string"/>
+ <xsd:element name="value" type="xsd:anyType"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="result">
+ <xsd:sequence>
+ <xsd:element name="outputParameters" type="qman:map"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ </xsd:schema>
+ </wsdl:types>
+ <wsdl:message name="GetMetadataMsg">
+ <wsdl:part name="GetMetadataMsg" element="wsx:GetMetadata" />
+ </wsdl:message>
+ <wsdl:message name="GetMetadataResponseMsg">
+ <wsdl:part name="GetMetadataResponseMsg" element="wsx:Metadata" />
+ </wsdl:message>
+ <wsdl:message name="DestroyRequest">
+ <wsdl:part name="DestroyRequest" element="wsrf-rl:Destroy" />
+ </wsdl:message>
+ <wsdl:message name="DestroyResponse">
+ <wsdl:part name="DestroyResponse" element="wsrf-rl:DestroyResponse" />
+ </wsdl:message>
+ <wsdl:message name="ResourceNotDestroyedFault">
+ <wsdl:part name="ResourceNotDestroyedFault" element="wsrf-rl:ResourceNotDestroyedFault" />
+ </wsdl:message>
+ <wsdl:message name="ResourceUnknownFault">
+ <wsdl:part name="ResourceUnknownFault" element="wsrf-r:ResourceUnknownFault" />
+ </wsdl:message>
+ <wsdl:message name="ResourceUnavailableFault">
+ <wsdl:part name="ResourceUnavailableFault" element="wsrf-r:ResourceUnavailableFault" />
+ </wsdl:message>
+ <wsdl:message name="UnableToPutResourcePropertyDocumentFault">
+ <wsdl:part name="UnableToPutResourcePropertyDocumentFault" element="wsrf-rp:UnableToPutResourcePropertyDocumentFault" />
+ </wsdl:message>
+ <wsdl:message name="PutResourcePropertyDocumentRequest">
+ <wsdl:part name="PutResourcePropertyDocumentRequest" element="wsrf-rp:PutResourcePropertyDocument"/>
+ </wsdl:message>
+ <wsdl:message name="PutResourcePropertyDocumentResponse">
+ <wsdl:part name="PutResourcePropertyDocumentResponse" element="wsrf-rp:PutResourcePropertyDocumentResponse"/>
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyDocumentRequest">
+ <wsdl:part name="GetResourcePropertyDocumentRequest" element="wsrf-rp:GetResourcePropertyDocument"/>
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyDocumentResponse">
+ <wsdl:part name="GetResourcePropertyDocumentResponse" element="wsrf-rp:GetResourcePropertyDocumentResponse"/>
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyRequest">
+ <wsdl:part name="GetResourcePropertyRequest" element="wsrf-rp:GetResourceProperty" />
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyResponse">
+ <wsdl:part name="GetResourcePropertyResponse" element="wsrf-rp:GetResourcePropertyResponse" />
+ </wsdl:message>
+ <wsdl:message name="InvalidResourcePropertyQNameFault">
+ <wsdl:part name="InvalidResourcePropertyQNameFault" element="wsrf-rp:InvalidResourcePropertyQNameFault" />
+ </wsdl:message>
+ <wsdl:message name="GetMultipleResourcePropertiesRequest">
+ <wsdl:part name="GetMultipleResourcePropertiesRequest" element="wsrf-rp:GetMultipleResourceProperties" />
+ </wsdl:message>
+ <wsdl:message name="GetMultipleResourcePropertiesResponse">
+ <wsdl:part name="GetMultipleResourcePropertiesResponse" element="wsrf-rp:GetMultipleResourcePropertiesResponse" />
+ </wsdl:message>
+ <wsdl:message name="QueryResourcePropertiesRequest">
+ <wsdl:part name="QueryResourcePropertiesRequest" element="wsrf-rp:QueryResourceProperties" />
+ </wsdl:message>
+ <wsdl:message name="QueryResourcePropertiesResponse">
+ <wsdl:part name="QueryResourcePropertiesResponse" element="wsrf-rp:QueryResourcePropertiesResponse" />
+ </wsdl:message>
+ <wsdl:message name="UnknownQueryExpressionDialectFault">
+ <wsdl:part name="UnknownQueryExpressionDialectFault" element="wsrf-rp:UnknownQueryExpressionDialectFault" />
+ </wsdl:message>
+ <wsdl:message name="InvalidQueryExpressionFault">
+ <wsdl:part name="InvalidQueryExpressionFault" element="wsrf-rp:InvalidQueryExpressionFault" />
+ </wsdl:message>
+ <wsdl:message name="QueryEvaluationErrorFault">
+ <wsdl:part name="QueryEvaluationErrorFault" element="wsrf-rp:QueryEvaluationErrorFault" />
+ </wsdl:message>
+ <wsdl:message name="SetResourcePropertiesRequest">
+ <wsdl:part name="SetResourcePropertiesRequest" element="wsrf-rp:SetResourceProperties" />
+ </wsdl:message>
+ <wsdl:message name="SetResourcePropertiesResponse">
+ <wsdl:part name="SetResourcePropertiesResponse" element="wsrf-rp:SetResourcePropertiesResponse" />
+ </wsdl:message>
+ <wsdl:message name="InvalidModificationFault">
+ <wsdl:part name="InvalidModificationFault" element="wsrf-rp:InvalidModificationFault" />
+ </wsdl:message>
+ <wsdl:message name="UnableToModifyResourcePropertyFault">
+ <wsdl:part name="UnableToModifyResourcePropertyFault" element="wsrf-rp:UnableToModifyResourcePropertyFault" />
+ </wsdl:message>
+ <wsdl:message name="SetResourcePropertyRequestFailedFault">
+ <wsdl:part name="SetResourcePropertyRequestFailedFault" element="wsrf-rp:SetResourcePropertyRequestFailedFault" />
+ </wsdl:message>
+ <wsdl:portType
+ name="QManWsResourcePortType"
+ wsrf-rp:ResourceProperties="qman:QManWsResourceProperties"
+ wsrmd:Descriptor="QManWsResourceMetadata"
+ wsrmd:DescriptorLocation="QManWsResource.rmd">
+ <wsdl:operation name="GetMetadata">
+ <wsdl:input
+ wsa:Action="http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata"
+ name="GetMetadataMsg"
+ message="qman:GetMetadataMsg"/>
+ <wsdl:output
+ wsa:Action="http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadataResponse"
+ name="GetMetadataResponseMsg"
+ message="qman:GetMetadataResponseMsg"/>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourcePropertyDocument">
+ <wsdl:input
+ wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourcePropertyDocument/GetResourcePropertyDocumentRequest"
+ name="GetResourcePropertyDocumentRequest"
+ message="qman:GetResourcePropertyDocumentRequest"/>
+ <wsdl:output
+ wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourcePropertyDocument/GetResourcePropertyDocumentResponse"
+ name="GetResourcePropertyDocumentResponse"
+ message="qman:GetResourcePropertyDocumentResponse"/>
+ <wsdl:fault name="ResourceUnknownFault" message="qman:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault" message="qman:ResourceUnavailableFault"/>
+ </wsdl:operation>
+ <wsdl:operation name="PutResourcePropertyDocument">
+ <wsdl:input
+ wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/PutResourcePropertyDocument/PutResourcePropertyDocumentRequest"
+ name="PutResourcePropertyDocumentRequest"
+ message="qman:PutResourcePropertyDocumentRequest"/>
+ <wsdl:output
+ wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/PutResourcePropertyDocument/PutResourcePropertyDocumentResponse"
+ name="PutResourcePropertyDocumentResponse"
+ message="qman:PutResourcePropertyDocumentResponse"/>
+ <wsdl:fault name="ResourceUnknownFault" message="qman:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault" message="qman:ResourceUnavailableFault"/>
+ <wsdl:fault name="UnableToPutResourcePropertyDocumentFault" message="qman:UnableToPutResourcePropertyDocumentFault"/>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourceProperty">
+ <wsdl:input
+ wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest"
+ name="GetResourcePropertyRequest"
+ message="qman:GetResourcePropertyRequest" />
+ <wsdl:output
+ wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse"
+ name="GetResourcePropertyResponse"
+ message="qman:GetResourcePropertyResponse" />
+ <wsdl:fault name="ResourceUnknownFault" message="qman:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault" message="qman:ResourceUnavailableFault"/>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault" message="qman:InvalidResourcePropertyQNameFault" />
+ </wsdl:operation>
+ <wsdl:operation name="GetMultipleResourceProperties">
+ <wsdl:input
+ wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetMultipleResourceProperties/GetMultipleResourcePropertiesRequest"
+ name="GetMultipleResourcePropertiesRequest"
+ message="qman:GetMultipleResourcePropertiesRequest" />
+ <wsdl:output
+ wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetMultipleResourceProperties/GetMultipleResourcePropertiesResponse"
+ name="GetMultipleResourcePropertiesResponse"
+ message="qman:GetMultipleResourcePropertiesResponse" />
+ <wsdl:fault name="ResourceUnknownFault" message="qman:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault" message="qman:ResourceUnavailableFault"/>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault" message="qman:InvalidResourcePropertyQNameFault" />
+ </wsdl:operation>
+ <wsdl:operation name="QueryResourceProperties">
+ <wsdl:input
+ wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/QueryResourceProperties/QueryResourcePropertiesRequest"
+ name="QueryResourcePropertiesRequest"
+ message="qman:QueryResourcePropertiesRequest" />
+ <wsdl:output
+ wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/QueryResourceProperties/QueryResourcePropertiesResponse"
+ name="QueryResourcePropertiesResponse"
+ message="qman:QueryResourcePropertiesResponse" />
+ <wsdl:fault name="ResourceUnknownFault" message="qman:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault" message="qman:ResourceUnavailableFault"/>
+ <wsdl:fault name="UnknownQueryExpressionDialectFault" message="qman:UnknownQueryExpressionDialectFault"/>
+ <wsdl:fault name="InvalidQueryExpressionFault" message="qman:InvalidQueryExpressionFault"/>
+ <wsdl:fault name="QueryEvaluationErrorFault" message="qman:QueryEvaluationErrorFault" />
+ </wsdl:operation>
+ <wsdl:operation name="SetResourceProperties">
+ <wsdl:input
+ wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/SetResourceProperties/SetResourcePropertiesRequest"
+ name="SetResourcePropertiesRequest"
+ message="qman:SetResourcePropertiesRequest" />
+ <wsdl:output
+ wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/SetResourceProperties/SetResourcePropertiesResponse"
+ name="SetResourcePropertiesResponse"
+ message="qman:SetResourcePropertiesResponse" />
+ <wsdl:fault name="ResourceUnknownFault" message="qman:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault" message="qman:ResourceUnavailableFault"/>
+ <wsdl:fault name="InvalidModificationFault" message="qman:InvalidModificationFault" />
+ <wsdl:fault name="UnableToModifyResourcePropertyFault" message="qman:UnableToModifyResourcePropertyFault" />
+ <wsdl:fault name="InvalidResourcePropertyQNameFault" message="qman:InvalidResourcePropertyQNameFault" />
+ <wsdl:fault name="SetResourcePropertyRequestFailedFault" message="qman:SetResourcePropertyRequestFailedFault" />
+ </wsdl:operation>
+ </wsdl:portType>
+ <wsdl:binding name="QManWsResourceBinding" type="qman:QManWsResourcePortType">
+ <wsdl-soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
+ <wsdl:operation name="GetMetadata">
+ <wsdl-soap:operation soapAction="GetMetadata" />
+ <wsdl:input>
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="PutResourcePropertyDocument">
+ <wsdl-soap:operation soapAction="PutResourcePropertyDocument"/>
+ <wsdl:input name="PutResourcePropertyDocumentRequest">
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:input>
+ <wsdl:output name="PutResourcePropertyDocumentResponse">
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="ResourceUnknownFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="ResourceUnavailableFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="UnableToPutResourcePropertyDocumentFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="UnableToPutResourcePropertyDocumentFault"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourcePropertyDocument">
+ <wsdl-soap:operation soapAction="GetResourcePropertyDocument"/>
+ <wsdl:input name="GetResourcePropertyDocumentRequest">
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:input><wsdl:output name="GetResourcePropertyDocumentResponse">
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="ResourceUnknownFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="ResourceUnavailableFault"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourceProperty">
+ <wsdl-soap:operation soapAction="GetResourceProperty"/>
+ <wsdl:input name="GetResourcePropertyRequest">
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:input><wsdl:output name="GetResourcePropertyResponse">
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="ResourceUnknownFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="ResourceUnavailableFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="InvalidResourcePropertyQNameFault"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="GetMultipleResourceProperties">
+ <wsdl-soap:operation soapAction="GetMultipleResourceProperties"/>
+ <wsdl:input name="GetMultipleResourcePropertiesRequest">
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:input><wsdl:output name="GetMultipleResourcePropertiesResponse">
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="ResourceUnknownFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="ResourceUnavailableFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="InvalidResourcePropertyQNameFault"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="QueryResourceProperties">
+ <wsdl-soap:operation soapAction="QueryResourceProperties"/>
+ <wsdl:input name="QueryResourcePropertiesRequest">
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:input><wsdl:output name="QueryResourcePropertiesResponse">
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="ResourceUnknownFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="ResourceUnavailableFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="UnknownQueryExpressionDialectFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="UnknownQueryExpressionDialectFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidQueryExpressionFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="InvalidQueryExpressionFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="QueryEvaluationErrorFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="QueryEvaluationErrorFault"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="SetResourceProperties">
+ <wsdl-soap:operation soapAction="http://oasis.org/SetResourceProperties"/>
+ <wsdl:input name="SetResourcePropertiesRequest">
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:input><wsdl:output name="SetResourcePropertiesResponse">
+ <wsdl-soap:body
+ use="literal"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="ResourceUnknownFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="ResourceUnavailableFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidModificationFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="InvalidModificationFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="UnableToModifyResourcePropertyFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="UnableToModifyResourcePropertyFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="InvalidResourcePropertyQNameFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="SetResourcePropertyRequestFailedFault">
+ <wsdl-soap:fault
+ use="literal"
+ name="SetResourcePropertyRequestFailedFault"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ </wsdl:binding>
+ <wsdl:service name="QManWsResourceService">
+ <wsdl:port name="QManWsResourcePort" binding="qman:QManWsResourceBinding">
+ <wsdl-soap:address location="http://localhost:8080/qman/services/QManWsResource"/>
+ </wsdl:port>
+ </wsdl:service>
+</wsdl:definitions> \ No newline at end of file
diff --git a/java/management/client/src/main/java/wsdl/SOAP-Envelope-1_2.xsd b/java/management/client/src/main/java/wsdl/SOAP-Envelope-1_2.xsd
new file mode 100644
index 0000000000..5aba6591fe
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/SOAP-Envelope-1_2.xsd
@@ -0,0 +1,160 @@
+<?xml version="1.0"?>
+
+<!-- Schema defined in the SOAP Version 1.2 Part 1 specification
+ Proposed Recommendation:
+ http://www.w3.org/TR/2003/PR-soap12-part1-20030507/
+ $Id: SOAP-Envelope-1_2.xsd,v 1.1 2006/05/07 19:09:15 danjemiolo Exp $
+
+ Copyright (C)2003 W3C(R) (MIT, ERCIM, Keio), All Rights Reserved.
+ W3C viability, trademark, document use and software licensing rules
+ apply.
+ http://www.w3.org/Consortium/Legal/
+
+ This document is governed by the W3C Software License [1] as
+ described in the FAQ [2].
+
+ [1] http://www.w3.org/Consortium/Legal/copyright-software-19980720
+ [2] http://www.w3.org/Consortium/Legal/IPR-FAQ-20000620.html#DTD
+-->
+
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:tns="http://www.w3.org/2003/05/soap-envelope"
+ targetNamespace="http://www.w3.org/2003/05/soap-envelope"
+ elementFormDefault="qualified">
+
+ <xs:import namespace="http://www.w3.org/XML/1998/namespace"
+ schemaLocation="XML-Namespace-1998.xsd"/>
+
+ <!-- Envelope, header and body -->
+ <xs:element name="Envelope" type="tns:Envelope"/>
+ <xs:complexType name="Envelope">
+ <xs:sequence>
+ <xs:element ref="tns:Header" minOccurs="0"/>
+ <xs:element ref="tns:Body" minOccurs="1"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+
+ <xs:element name="Header" type="tns:Header"/>
+ <xs:complexType name="Header">
+ <xs:annotation>
+ <xs:documentation>
+ Elements replacing the wildcard MUST be namespace qualified, but can be in the targetNamespace
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+
+ <xs:element name="Body" type="tns:Body"/>
+ <xs:complexType name="Body">
+ <xs:sequence>
+ <xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+
+ <!-- Global Attributes. The following attributes are intended to be
+ usable via qualified attribute names on any complex type referencing
+ them. -->
+ <xs:attribute name="mustUnderstand" type="xs:boolean" default="0"/>
+ <xs:attribute name="relay" type="xs:boolean" default="0"/>
+ <xs:attribute name="role" type="xs:anyURI"/>
+
+ <!-- 'encodingStyle' indicates any canonicalization conventions
+ followed in the contents of the containing element. For example, the
+ value 'http://www.w3.org/2003/05/soap-encoding' indicates the pattern
+ described in the last call working draft of SOAP Version 1.2 Part 2:
+ Adjuncts -->
+
+ <xs:attribute name="encodingStyle" type="xs:anyURI"/>
+
+ <xs:element name="Fault" type="tns:Fault"/>
+ <xs:complexType name="Fault" final="extension">
+ <xs:annotation>
+ <xs:documentation>
+ Fault reporting structure
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="Code" type="tns:faultcode"/>
+ <xs:element name="Reason" type="tns:faultreason"/>
+ <xs:element name="Node" type="xs:anyURI" minOccurs="0"/>
+ <xs:element name="Role" type="xs:anyURI" minOccurs="0"/>
+ <xs:element name="Detail" type="tns:detail" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="faultreason">
+ <xs:sequence>
+ <xs:element name="Text" type="tns:reasontext"
+ minOccurs="1" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="reasontext">
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute ref="xml:lang" use="required"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+
+ <xs:complexType name="faultcode">
+ <xs:sequence>
+ <xs:element name="Value"
+ type="tns:faultcodeEnum"/>
+ <xs:element name="Subcode"
+ type="tns:subcode"
+ minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:simpleType name="faultcodeEnum">
+ <xs:restriction base="xs:QName">
+ <xs:enumeration value="tns:DataEncodingUnknown"/>
+ <xs:enumeration value="tns:MustUnderstand"/>
+ <xs:enumeration value="tns:Receiver"/>
+ <xs:enumeration value="tns:Sender"/>
+ <xs:enumeration value="tns:VersionMismatch"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:complexType name="subcode">
+ <xs:sequence>
+ <xs:element name="Value"
+ type="xs:QName"/>
+ <xs:element name="Subcode"
+ type="tns:subcode"
+ minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="detail">
+ <xs:sequence>
+ <xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+
+ <!-- Global element declaration and complex type definition for header entry returned due to a mustUnderstand fault -->
+ <xs:element name="NotUnderstood" type="tns:NotUnderstoodType"/>
+ <xs:complexType name="NotUnderstoodType">
+ <xs:attribute name="qname" type="xs:QName" use="required"/>
+ </xs:complexType>
+
+ <!-- Global element and associated types for managing version transition as described in Appendix A of the SOAP Version 1.2 Part 1 Last Call Working Draft -->
+ <xs:complexType name="SupportedEnvType">
+ <xs:attribute name="qname" type="xs:QName" use="required"/>
+ </xs:complexType>
+
+ <xs:element name="Upgrade" type="tns:UpgradeType"/>
+ <xs:complexType name="UpgradeType">
+ <xs:sequence>
+ <xs:element name="SupportedEnvelope" type="tns:SupportedEnvType" minOccurs="1" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+</xs:schema>
diff --git a/java/management/client/src/main/java/wsdl/WS-Addressing-2005_08.xsd b/java/management/client/src/main/java/wsdl/WS-Addressing-2005_08.xsd
new file mode 100644
index 0000000000..9bf9b10b7f
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/WS-Addressing-2005_08.xsd
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xs:schema
+ targetNamespace="http://www.w3.org/2005/08/addressing"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:tns="http://www.w3.org/2005/08/addressing"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified">
+
+ <!-- Constructs from the WS-Addressing Core -->
+
+ <xs:element name="EndpointReference"
+ type="tns:EndpointReferenceType" />
+ <xs:complexType name="EndpointReferenceType" mixed="false">
+ <xs:sequence>
+ <xs:element name="Address" type="tns:AttributedURIType" />
+ <xs:element name="ReferenceParameters"
+ type="tns:ReferenceParametersType" minOccurs="0" />
+ <xs:element ref="tns:Metadata" minOccurs="0" />
+ <xs:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded" />
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax" />
+ </xs:complexType>
+
+ <xs:complexType name="ReferenceParametersType" mixed="false">
+ <xs:sequence>
+ <xs:any namespace="##any" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded" />
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax" />
+ </xs:complexType>
+
+ <xs:element name="Metadata" type="tns:MetadataType" />
+ <xs:complexType name="MetadataType" mixed="false">
+ <xs:sequence>
+ <xs:any namespace="##any" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded" />
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax" />
+ </xs:complexType>
+
+ <xs:element name="MessageID" type="tns:AttributedURIType" />
+ <xs:element name="RelatesTo" type="tns:RelatesToType" />
+ <xs:complexType name="RelatesToType" mixed="false">
+ <xs:simpleContent>
+ <xs:extension base="xs:anyURI">
+ <xs:attribute name="RelationshipType"
+ type="tns:RelationshipTypeOpenEnum" use="optional"
+ default="http://www.w3.org/2005/08/addressing/reply" />
+ <xs:anyAttribute namespace="##other"
+ processContents="lax" />
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+
+ <xs:simpleType name="RelationshipTypeOpenEnum">
+ <xs:union memberTypes="tns:RelationshipType xs:anyURI" />
+ </xs:simpleType>
+
+ <xs:simpleType name="RelationshipType">
+ <xs:restriction base="xs:anyURI">
+ <xs:enumeration
+ value="http://www.w3.org/2005/08/addressing/reply" />
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:element name="ReplyTo" type="tns:EndpointReferenceType" />
+ <xs:element name="From" type="tns:EndpointReferenceType" />
+ <xs:element name="FaultTo" type="tns:EndpointReferenceType" />
+ <xs:element name="To" type="tns:AttributedURIType" />
+ <xs:element name="Action" type="tns:AttributedURIType" />
+
+ <xs:complexType name="AttributedURIType" mixed="false">
+ <xs:simpleContent>
+ <xs:extension base="xs:anyURI">
+ <xs:anyAttribute namespace="##other"
+ processContents="lax" />
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+
+ <!-- Constructs from the WS-Addressing SOAP binding -->
+
+ <xs:attribute name="IsReferenceParameter" type="xs:boolean" />
+
+ <xs:simpleType name="FaultCodesOpenEnumType">
+ <xs:union memberTypes="tns:FaultCodesType xs:QName" />
+ </xs:simpleType>
+
+ <xs:simpleType name="FaultCodesType">
+ <xs:restriction base="xs:QName">
+ <xs:enumeration value="tns:InvalidAddressingHeader" />
+ <xs:enumeration value="tns:InvalidAddress" />
+ <xs:enumeration value="tns:InvalidEPR" />
+ <xs:enumeration value="tns:InvalidCardinality" />
+ <xs:enumeration value="tns:MissingAddressInEPR" />
+ <xs:enumeration value="tns:DuplicateMessageID" />
+ <xs:enumeration value="tns:ActionMismatch" />
+ <xs:enumeration value="tns:MessageAddressingHeaderRequired" />
+ <xs:enumeration value="tns:DestinationUnreachable" />
+ <xs:enumeration value="tns:ActionNotSupported" />
+ <xs:enumeration value="tns:EndpointUnavailable" />
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:element name="RetryAfter" type="tns:AttributedUnsignedLongType" />
+ <xs:complexType name="AttributedUnsignedLongType" mixed="false">
+ <xs:simpleContent>
+ <xs:extension base="xs:unsignedLong">
+ <xs:anyAttribute namespace="##other"
+ processContents="lax" />
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+
+ <xs:element name="ProblemHeaderQName"
+ type="tns:AttributedQNameType" />
+ <xs:complexType name="AttributedQNameType" mixed="false">
+ <xs:simpleContent>
+ <xs:extension base="xs:QName">
+ <xs:anyAttribute namespace="##other"
+ processContents="lax" />
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+
+ <xs:element name="ProblemHeader" type="tns:AttributedAnyType" />
+ <xs:complexType name="AttributedAnyType" mixed="false">
+ <xs:sequence>
+ <xs:any namespace="##any" processContents="lax"
+ minOccurs="1" maxOccurs="1" />
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax" />
+ </xs:complexType>
+
+ <xs:element name="ProblemIRI" type="tns:AttributedURIType" />
+
+ <xs:element name="ProblemAction" type="tns:ProblemActionType" />
+ <xs:complexType name="ProblemActionType" mixed="false">
+ <xs:sequence>
+ <xs:element ref="tns:Action" minOccurs="0" />
+ <xs:element name="SoapAction" minOccurs="0"
+ type="xs:anyURI" />
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax" />
+ </xs:complexType>
+
+</xs:schema>
diff --git a/java/management/client/src/main/java/wsdl/WS-BaseFaults-1_2.xsd b/java/management/client/src/main/java/wsdl/WS-BaseFaults-1_2.xsd
new file mode 100644
index 0000000000..665797e486
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/WS-BaseFaults-1_2.xsd
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ OASIS takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any effort to identify any such rights. Information on OASIS's procedures with respect to rights in OASIS specifications can be found at the OASIS website. Copies of claims of rights made available for publication and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification, can be obtained from the OASIS Executive Director.
+
+OASIS invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may cover technology that may be required to implement this specification. Please address the information to the OASIS Executive Director.
+
+Copyright (C) OASIS Open (2005). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to OASIS, except as needed for the purpose of developing OASIS specifications, in which case the procedures for copyrights defined in the OASIS Intellectual Property Rights document must be followed, or as required to translate it into languages other than English.
+
+The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.
+
+This document and the information contained herein is provided on an "AS IS" basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+-->
+
+<xsd:schema
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ xmlns:wsrf-bf=
+ "http://docs.oasis-open.org/wsrf/bf-2"
+ elementFormDefault="qualified" attributeFormDefault="unqualified"
+ targetNamespace=
+ "http://docs.oasis-open.org/wsrf/bf-2">
+ <xsd:import
+ namespace="http://www.w3.org/2005/08/addressing"
+ schemaLocation="WS-Addressing-2005_08.xsd"/>
+
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace"
+ schemaLocation="XML-Namespace-1998.xsd">
+ <xsd:annotation>
+ <xsd:documentation>
+ Get access to the xml: attribute groups for xml:lang as declared on 'schema'
+ and 'documentation' below
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:import>
+<!-- ====================== BaseFault Types ======================= -->
+
+ <xsd:element name="BaseFault" type="wsrf-bf:BaseFaultType"/>
+
+ <xsd:complexType name="BaseFaultType">
+ <xsd:sequence>
+ <xsd:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="Timestamp" type="xsd:dateTime"
+ minOccurs="1" maxOccurs="1"/>
+ <xsd:element name="Originator" type="wsa:EndpointReferenceType"
+ minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="ErrorCode"
+ minOccurs="0" maxOccurs="1">
+ <xsd:complexType>
+ <xsd:complexContent mixed="true">
+ <xsd:extension base="xsd:anyType">
+ <xsd:attribute name="dialect" type="xsd:anyURI"
+ use="required"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="Description"
+ minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute ref="xml:lang" use="optional"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="FaultCause" minOccurs="0" maxOccurs="1">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any namespace="##other" processContents="lax"
+ minOccurs="1" maxOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+</xsd:schema>
diff --git a/java/management/client/src/main/java/wsdl/WS-BaseNotification-1_3.wsdl b/java/management/client/src/main/java/wsdl/WS-BaseNotification-1_3.wsdl
new file mode 100644
index 0000000000..d53bf60f3a
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/WS-BaseNotification-1_3.wsdl
@@ -0,0 +1,449 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+OASIS takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any effort to identify any such rights. Information on OASIS's procedures with respect to rights in OASIS specifications can be found at the OASIS website. Copies of claims of rights made available for publication and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementors or users of this specification, can be obtained from the OASIS Executive Director.
+
+OASIS invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may cover technology that may be required to implement this specification. Please address the information to the OASIS Executive Director.
+
+Copyright (C) OASIS Open (2004-2005). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to OASIS, except as needed for the purpose of developing OASIS specifications, in which case the procedures for copyrights defined in the OASIS Intellectual Property Rights document must be followed, or as required to translate it into languages other than English.
+
+The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.
+
+This document and the information contained herein is provided on an "AS IS" basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+-->
+<wsdl:definitions name="WS-BaseNotification"
+ targetNamespace="http://docs.oasis-open.org/wsn/bw-2"
+ xmlns:wsntw="http://docs.oasis-open.org/wsn/bw-2"
+ xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ xmlns:wsrf-rw="http://docs.oasis-open.org/wsrf/rw-2"
+ xmlns:wsrf-rlw="http://docs.oasis-open.org/wsrf/rlw-2"
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2"
+ xmlns:wsrf-rpw="http://docs.oasis-open.org/wsrf/rpw-2"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
+
+<!-- ========================== Imports =========================== -->
+ <wsdl:import
+ namespace="http://docs.oasis-open.org/wsrf/rw-2"
+ location="WS-Resource-1_2.wsdl"/>
+
+ <wsdl:import
+ namespace="http://docs.oasis-open.org/wsrf/rlw-2"
+ location="WS-ResourceLifetime-1_2.wsdl"/>
+
+ <wsdl:import
+ namespace="http://docs.oasis-open.org/wsrf/rpw-2"
+ location="WS-ResourceProperties-1_2.wsdl"/>
+
+<!-- ===================== Types Definitions ====================== -->
+ <wsdl:types>
+ <xsd:schema>
+ <xsd:import
+ namespace="http://docs.oasis-open.org/wsn/b-2"
+ schemaLocation="WS-BaseNotification-1_3.xsd"/>
+ <xsd:import
+ namespace="http://docs.oasis-open.org/wsrf/rp-2"
+ schemaLocation="WS-ResourceProperties-1_2.xsd"/>
+ </xsd:schema>
+ </wsdl:types>
+
+<!-- ================ NotificationConsumer::Notify ================
+ Notify(
+ NotificationMessage
+ (SubscriptionReference, TopicExpression, ProducerReference,
+ Message)*
+ returns: n/a (one way)
+-->
+ <wsdl:message name="Notify">
+ <wsdl:part name="Notify" element="wsnt:Notify"/>
+ </wsdl:message>
+
+<!-- ============== NotificationProducer::Subscribe ===============
+ Subscribe(
+ (ConsumerEndpointReference, [Filter], [SubscriptionPolicy],
+ [InitialTerminationTime])
+ returns: WS-Resource qualified EPR to a Subscription
+-->
+ <wsdl:message name="SubscribeRequest" >
+ <wsdl:part name="SubscribeRequest"
+ element="wsnt:Subscribe"/>
+ </wsdl:message>
+
+ <wsdl:message name="SubscribeResponse">
+ <wsdl:part name="SubscribeResponse"
+ element="wsnt:SubscribeResponse"/>
+ </wsdl:message>
+
+ <wsdl:message name="SubscribeCreationFailedFault">
+ <wsdl:part name="SubscribeCreationFailedFault"
+ element="wsnt:SubscribeCreationFailedFault" />
+ </wsdl:message>
+
+ <wsdl:message name="TopicExpressionDialectUnknownFault">
+ <wsdl:part name="TopicExpressionDialectUnknownFault"
+ element="wsnt:TopicExpressionDialectUnknownFault" />
+ </wsdl:message>
+
+ <wsdl:message name="InvalidFilterFault">
+ <wsdl:part name="InvalidFilterFault"
+ element="wsnt:InvalidFilterFault" />
+ </wsdl:message>
+
+ <wsdl:message name="InvalidProducerPropertiesExpressionFault">
+ <wsdl:part name="InvalidProducerPropertiesExpressionFault"
+ element="wsnt:InvalidProducerPropertiesExpressionFault" />
+ </wsdl:message>
+
+ <wsdl:message name="InvalidMessageContentExpressionFault">
+ <wsdl:part name="InvalidMessageContentExpressionFault"
+ element="wsnt:InvalidMessageContentExpressionFault" />
+ </wsdl:message>
+
+ <wsdl:message name="UnrecognizedPolicyRequestFault">
+ <wsdl:part name="UnrecognizedPolicyRequestFault"
+ element="wsnt:UnrecognizedPolicyRequestFault" />
+ </wsdl:message>
+
+ <wsdl:message name="UnsupportedPolicyRequestFault">
+ <wsdl:part name="UnsupportedPolicyRequestFault"
+ element="wsnt:UnsupportedPolicyRequestFault" />
+ </wsdl:message>
+
+ <wsdl:message name="NotifyMessageNotSupportedFault">
+ <wsdl:part name="NotifyMessageNotSupportedFault"
+ element="wsnt:NotifyMessageNotSupportedFault" />
+ </wsdl:message>
+
+ <wsdl:message name="UnacceptableInitialTerminationTimeFault">
+ <wsdl:part name="UnacceptableInitialTerminationTimeFault"
+ element="wsnt:UnacceptableInitialTerminationTimeFault"/>
+ </wsdl:message>
+
+<!-- ========== NotificationProducer::GetCurrentMessage ===========
+ GetCurrentMessage(topicExpression)
+ returns: a NotificationMessage (xsd:any)
+-->
+ <wsdl:message name="GetCurrentMessageRequest">
+ <wsdl:part name="GetCurrentMessageRequest"
+ element="wsnt:GetCurrentMessage"/>
+ </wsdl:message>
+
+ <wsdl:message name="GetCurrentMessageResponse">
+ <wsdl:part name="GetCurrentMessageResponse"
+ element="wsnt:GetCurrentMessageResponse"/>
+ </wsdl:message>
+
+ <wsdl:message name="InvalidTopicExpressionFault">
+ <wsdl:part name="InvalidTopicExpressionFault"
+ element="wsnt:InvalidTopicExpressionFault" />
+ </wsdl:message>
+
+ <wsdl:message name="TopicNotSupportedFault">
+ <wsdl:part name="TopicNotSupportedFault"
+ element="wsnt:TopicNotSupportedFault" />
+ </wsdl:message>
+
+ <wsdl:message name="MultipleTopicsSpecifiedFault">
+ <wsdl:part name="MultipleTopicsSpecifiedFault"
+ element="wsnt:MultipleTopicsSpecifiedFault" />
+ </wsdl:message>
+
+ <wsdl:message name="NoCurrentMessageOnTopicFault">
+ <wsdl:part name="NoCurrentMessageOnTopicFault"
+ element="wsnt:NoCurrentMessageOnTopicFault" />
+ </wsdl:message>
+
+<!-- ========== PullPoint::GetMessages ===========
+ GetMessages(MaximumNumber)
+ returns: NotificationMessage list
+-->
+ <wsdl:message name="GetMessagesRequest">
+ <wsdl:part name="GetMessagesRequest"
+ element="wsnt:GetMessages"/>
+ </wsdl:message>
+
+ <wsdl:message name="GetMessagesResponse">
+ <wsdl:part name="GetMessagesResponse"
+ element="wsnt:GetMessagesResponse"/>
+ </wsdl:message>
+
+<!-- ========== PullPoint::DestroyPullPoint ===========
+ DestroyPullPoint()
+ returns: void
+-->
+ <wsdl:message name="DestroyPullPointRequest">
+ <wsdl:part name="DestroyPullPointRequest"
+ element="wsnt:DestroyPullPoint"/>
+ </wsdl:message>
+
+ <wsdl:message name="DestroyPullPointResponse">
+ <wsdl:part name="DestroyPullPointResponse"
+ element="wsnt:DestroyPullPointResponse"/>
+ </wsdl:message>
+
+ <wsdl:message name="UnableToDestroyPullPointFault">
+ <wsdl:part name="UnableToDestroyPullPointFault"
+ element="wsnt:UnableToDestroyPullPointFault"/>
+ </wsdl:message>
+
+<!-- ========== PullPoint::CreatePullPoint ===========
+ CreatePullPoint()
+ returns: PullPoint (wsa:EndpointReference)
+-->
+ <wsdl:message name="CreatePullPointRequest">
+ <wsdl:part name="CreatePullPointRequest"
+ element="wsnt:CreatePullPoint"/>
+ </wsdl:message>
+
+ <wsdl:message name="CreatePullPointResponse">
+ <wsdl:part name="CreatePullPointResponse"
+ element="wsnt:CreatePullPointResponse"/>
+ </wsdl:message>
+
+ <wsdl:message name="UnableToCreatePullPointFault">
+ <wsdl:part name="UnableToCreatePullPointFault"
+ element="wsnt:UnableToCreatePullPointFault"/>
+ </wsdl:message>
+
+<!-- ================ SubscriptionManager::Renew ==================
+ Renew( Duration | AbsoluteTime)
+ returns: (New Termination Time [CurrentTime])
+-->
+ <wsdl:message name="RenewRequest">
+ <wsdl:part name="RenewRequest"
+ element="wsnt:Renew"/>
+ </wsdl:message>
+
+ <wsdl:message name="RenewResponse">
+ <wsdl:part name="RenewResponse"
+ element="wsnt:RenewResponse"/>
+ </wsdl:message>
+
+ <wsdl:message name="UnacceptableTerminationTimeFault">
+ <wsdl:part name="UnacceptableTerminationTimeFault"
+ element="wsnt:UnacceptableTerminationTimeFault" />
+ </wsdl:message>
+
+<!-- ============== SubscriptionManager::Unsubscribe ===============
+ Unsubscribe()
+ returns: empty
+-->
+ <wsdl:message name="UnsubscribeRequest">
+ <wsdl:part name="UnsubscribeRequest"
+ element="wsnt:Unsubscribe"/>
+ </wsdl:message>
+
+ <wsdl:message name="UnsubscribeResponse">
+ <wsdl:part name="UnsubscribeResponse"
+ element="wsnt:UnsubscribeResponse"/>
+ </wsdl:message>
+
+ <wsdl:message name="UnableToDestroySubscriptionFault">
+ <wsdl:part name="UnableToDestroySubscriptionFault"
+ element="wsnt:UnableToDestroySubscriptionFault" />
+ </wsdl:message>
+
+<!-- ========== SubscriptionManager::PauseSubscription ============
+ PauseSubscription()
+ returns: empty
+-->
+ <wsdl:message name="PauseSubscriptionRequest">
+ <wsdl:part name="PauseSubscriptionRequest"
+ element="wsnt:PauseSubscription"/>
+ </wsdl:message>
+
+ <wsdl:message name="PauseSubscriptionResponse">
+ <wsdl:part name="PauseSubscriptionResponse"
+ element="wsnt:PauseSubscriptionResponse"/>
+ </wsdl:message>
+
+ <wsdl:message name="PauseFailedFault">
+ <wsdl:part name="PauseFailedFault"
+ element="wsnt:PauseFailedFault" />
+ </wsdl:message>
+
+<!-- ========= SubscriptionManager::ResumeSubscription ============
+ ResumeSubscription()
+ returns: empty
+-->
+ <wsdl:message name="ResumeSubscriptionRequest">
+ <wsdl:part name="ResumeSubscriptionRequest"
+ element="wsnt:ResumeSubscription"/>
+ </wsdl:message>
+
+ <wsdl:message name="ResumeSubscriptionResponse">
+ <wsdl:part name="ResumeSubscriptionResponse"
+ element="wsnt:ResumeSubscriptionResponse"/>
+ </wsdl:message>
+
+ <wsdl:message name="ResumeFailedFault">
+ <wsdl:part name="ResumeFailedFault"
+ element="wsnt:ResumeFailedFault" />
+ </wsdl:message>
+
+<!-- =================== PortType Definitions ===================== -->
+<!-- ========= NotificationConsumer PortType Definition =========== -->
+ <wsdl:portType name="NotificationConsumer">
+ <wsdl:operation name="Notify">
+ <wsdl:input wsa:Action="http://docs.oasis-open.org/wsn/bw-2/NotificationConsumer/NotifyRequest" message="wsntw:Notify" />
+ </wsdl:operation>
+ </wsdl:portType>
+
+<!-- ========= NotificationProducer PortType Definition =========== -->
+ <wsdl:portType name="NotificationProducer">
+ <wsdl:operation name="Subscribe">
+ <wsdl:input wsa:Action="http://docs.oasis-open.org/wsn/bw-2/NotificationProducer/SubscribeRequest"
+ message="wsntw:SubscribeRequest" />
+ <wsdl:output wsa:Action="http://docs.oasis-open.org/wsn/bw-2/NotificationProducer/SubscribeResponse"
+ message="wsntw:SubscribeResponse" />
+ <wsdl:fault name="ResourceUnknownFault"
+ message="wsrf-rw:ResourceUnknownFault" />
+ <wsdl:fault name="InvalidFilterFault"
+ message="wsntw:InvalidFilterFault"/>
+ <wsdl:fault name="TopicExpressionDialectUnknownFault"
+ message="wsntw:TopicExpressionDialectUnknownFault"/>
+ <wsdl:fault name="InvalidTopicExpressionFault"
+ message="wsntw:InvalidTopicExpressionFault" />
+ <wsdl:fault name="TopicNotSupportedFault"
+ message="wsntw:TopicNotSupportedFault" />
+ <wsdl:fault name="InvalidProducerPropertiesExpressionFault"
+ message="wsntw:InvalidProducerPropertiesExpressionFault"/>
+ <wsdl:fault name="InvalidMessageContentExpressionFault"
+ message="wsntw:InvalidMessageContentExpressionFault"/>
+ <wsdl:fault name="UnacceptableInitialTerminationTimeFault"
+ message="wsntw:UnacceptableInitialTerminationTimeFault"/>
+ <wsdl:fault name="UnrecognizedPolicyRequestFault"
+ message="wsntw:UnrecognizedPolicyRequestFault"/>
+ <wsdl:fault name="UnsupportedPolicyRequestFault"
+ message="wsntw:UnsupportedPolicyRequestFault"/>
+ <wsdl:fault name="NotifyMessageNotSupportedFault"
+ message="wsntw:NotifyMessageNotSupportedFault"/>
+ <wsdl:fault name="SubscribeCreationFailedFault"
+ message="wsntw:SubscribeCreationFailedFault"/>
+ </wsdl:operation>
+
+ <wsdl:operation name="GetCurrentMessage">
+ <wsdl:input wsa:Action="http://docs.oasis-open.org/wsn/bw-2/NotificationProducer/GetCurrentMessageRequest"
+ message="wsntw:GetCurrentMessageRequest"/>
+ <wsdl:output wsa:Action="http://docs.oasis-open.org/wsn/bw-2/NotificationProducer/GetCurrentMessageResponse"
+ message="wsntw:GetCurrentMessageResponse"/>
+ <wsdl:fault name="ResourceUnknownFault"
+ message="wsrf-rw:ResourceUnknownFault" />
+ <wsdl:fault name="TopicExpressionDialectUnknownFault"
+ message="wsntw:TopicExpressionDialectUnknownFault"/>
+ <wsdl:fault name="InvalidTopicExpressionFault"
+ message="wsntw:InvalidTopicExpressionFault" />
+ <wsdl:fault name="TopicNotSupportedFault"
+ message="wsntw:TopicNotSupportedFault" />
+ <wsdl:fault name="NoCurrentMessageOnTopicFault"
+ message="wsntw:NoCurrentMessageOnTopicFault" />
+ <wsdl:fault name="MultipleTopicsSpecifiedFault"
+ message="wsntw:MultipleTopicsSpecifiedFault" />
+ </wsdl:operation>
+ </wsdl:portType>
+
+<!-- ========== PullPoint PortType Definition ===================== -->
+ <wsdl:portType name="PullPoint">
+ <wsdl:operation name="GetMessages">
+ <wsdl:input name="GetMessagesRequest"
+ message="wsntw:GetMessagesRequest" />
+ <wsdl:output name="GetMessagesResponse"
+ message="wsntw:GetMessagesResponse" />
+ <wsdl:fault name="ResourceUnknownFault"
+ message="wsrf-rw:ResourceUnknownFault" />
+ </wsdl:operation>
+
+ <wsdl:operation name="Notify">
+ <wsdl:input message="wsntw:Notify"/>
+ </wsdl:operation>
+ </wsdl:portType>
+
+<!-- ========== CreatePullPoint PortType Definition =============== -->
+ <wsdl:portType name="CreatePullPoint">
+ <wsdl:operation name="CreatePullPoint">
+ <wsdl:input name="CreatePullPointRequest"
+ message="wsntw:CreatePullPointRequest" />
+ <wsdl:output name="CreatePullPointResponse"
+ message="wsntw:CreatePullPointResponse" />
+ <wsdl:fault name="UnableToCreatePullPointFault"
+ message="wsntw:UnableToCreatePullPointFault" />
+ </wsdl:operation>
+ </wsdl:portType>
+
+<!-- ========== SubscriptionManager PortType Definition =========== -->
+ <wsdl:portType name="SubscriptionManager"
+ wsrf-rp:ResourceProperties="wsnt:SubscriptionManagerRP">
+
+ <wsdl:operation name="Destroy">
+ <wsdl:input wsa:Action="http://docs.oasis-open.org/wsrf/rlw-2/ImmediateResourceTermination/DestroyRequest"
+ name="DestroyRequest" message="wsrf-rlw:DestroyRequest" />
+ <wsdl:output wsa:Action="http://docs.oasis-open.org/wsrf/rlw-2/ImmediateResourceTermination/DestroyResponse"
+ name="DestroyResponse" message="wsrf-rlw:DestroyResponse" />
+ <wsdl:fault name="ResourceNotDestroyedFault" message="wsrf-rlw:ResourceNotDestroyedFault" />
+ <wsdl:fault name="ResourceUnknownFault" message="wsrf-rw:ResourceUnknownFault" />
+ <wsdl:fault name="ResourceUnavailableFault" message="wsrf-rw:ResourceUnavailableFault"/>
+ </wsdl:operation>
+ <wsdl:operation name="SetTerminationTime">
+ <wsdl:input wsa:Action="http://docs.oasis-open.org/wsrf/rlw-2/ScheduledResourceTermination/SetTerminationTimeRequest"
+ name="SetTerminationTimeRequest" message="wsrf-rlw:SetTerminationTimeRequest" />
+ <wsdl:output wsa:Action="http://docs.oasis-open.org/wsrf/rlw-2/ScheduledResourceTermination/SetTerminationTimeResponse"
+ name="SetTerminationTimeResponse" message="wsrf-rlw:SetTerminationTimeResponse" />
+ <wsdl:fault name="UnableToSetTerminationTimeFault" message="wsrf-rlw:UnableToSetTerminationTimeFault" />
+ <wsdl:fault name="ResourceUnknownFault" message="wsrf-rw:ResourceUnknownFault" />
+ <wsdl:fault name="ResourceUnavailableFault" message="wsrf-rw:ResourceUnavailableFault"/>
+ <wsdl:fault name="TerminationTimeChangeRejectedFault" message="wsrf-rlw:TerminationTimeChangeRejectedFault" />
+ </wsdl:operation>
+ <wsdl:operation name="GetResourcePropertyDocument">
+ <wsdl:input wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourcePropertyDocument/GetResourcePropertyDocumentRequest"
+ name="GetResourcePropertyDocumentRequest" message="wsrf-rpw:GetResourcePropertyDocumentRequest"/>
+ <wsdl:output wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourcePropertyDocument/GetResourcePropertyDocumentResponse"
+ name="GetResourcePropertyDocumentResponse" message="wsrf-rpw:GetResourcePropertyDocumentResponse"/>
+ <wsdl:fault name="ResourceUnknownFault" message="wsrf-rw:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault" message="wsrf-rw:ResourceUnavailableFault"/>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourceProperty">
+ <wsdl:input wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest"
+ name="GetResourcePropertyRequest" message="wsrf-rpw:GetResourcePropertyRequest" />
+ <wsdl:output wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse"
+ name="GetResourcePropertyResponse" message="wsrf-rpw:GetResourcePropertyResponse" />
+ <wsdl:fault name="ResourceUnknownFault" message="wsrf-rw:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault" message="wsrf-rw:ResourceUnavailableFault"/>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault" message="wsrf-rpw:InvalidResourcePropertyQNameFault" />
+ </wsdl:operation>
+ <wsdl:operation name="GetMultipleResourceProperties">
+ <wsdl:input wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetMultipleResourceProperties/GetMultipleResourcePropertiesRequest"
+ name="GetMultipleResourcePropertiesRequest" message="wsrf-rpw:GetMultipleResourcePropertiesRequest" />
+ <wsdl:output wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetMultipleResourceProperties/GetMultipleResourcePropertiesResponse"
+ name="GetMultipleResourcePropertiesResponse" message="wsrf-rpw:GetMultipleResourcePropertiesResponse" />
+ <wsdl:fault name="ResourceUnknownFault" message="wsrf-rw:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault" message="wsrf-rw:ResourceUnavailableFault"/>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault" message="wsrf-rpw:InvalidResourcePropertyQNameFault" />
+ </wsdl:operation>
+
+<!-- </wsdl:portType>
+
+ <wsdl:portType name="PausableSubscriptionManager">
+-->
+ <!-- === PausableSubscriptionManager specific operations === -->
+ <wsdl:operation name="PauseSubscription">
+ <wsdl:input message="wsntw:PauseSubscriptionRequest" wsa:Action="http://docs.oasis-open.org/wsn/bw-2/SubscriptionManager/PauseSubscriptionRequest"/>
+ <wsdl:output message="wsntw:PauseSubscriptionResponse" wsa:Action="http://docs.oasis-open.org/wsn/bw-2/SubscriptionManager/PauseSubscriptionResponse"/>
+ <wsdl:fault name="ResourceUnknownFault"
+ message="wsrf-rw:ResourceUnknownFault" />
+ <wsdl:fault name="PauseFailedFault"
+ message="wsntw:PauseFailedFault" />
+ </wsdl:operation>
+ <wsdl:operation name="ResumeSubscription">
+ <wsdl:input message="wsntw:ResumeSubscriptionRequest" wsa:Action="http://docs.oasis-open.org/wsn/bw-2/SubscriptionManager/ResumeSubscriptionRequest"/>
+ <wsdl:output message="wsntw:ResumeSubscriptionResponse" wsa:Action="http://docs.oasis-open.org/wsn/bw-2/SubscriptionManager/ResumeSubscriptionResponse"/>
+ <wsdl:fault name="ResourceUnknownFault"
+ message="wsrf-rw:ResourceUnknownFault" />
+ <wsdl:fault name="ResumeFailedFault"
+ message="wsntw:ResumeFailedFault" />
+ </wsdl:operation>
+ </wsdl:portType>
+</wsdl:definitions> \ No newline at end of file
diff --git a/java/management/client/src/main/java/wsdl/WS-BaseNotification-1_3.xsd b/java/management/client/src/main/java/wsdl/WS-BaseNotification-1_3.xsd
new file mode 100644
index 0000000000..9e10282759
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/WS-BaseNotification-1_3.xsd
@@ -0,0 +1,577 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+OASIS takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any effort to identify any such rights. Information on OASIS's procedures with respect to rights in OASIS specifications can be found at the OASIS website. Copies of claims of rights made available for publication and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementors or users of this specification, can be obtained from the OASIS Executive Director.
+
+OASIS invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may cover technology that may be required to implement this specification. Please address the information to the OASIS Executive Director.
+
+Copyright (C) OASIS Open (2004-2005). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to OASIS, except as needed for the purpose of developing OASIS specifications, in which case the procedures for copyrights defined in the OASIS Intellectual Property Rights document must be followed, or as required to translate it into languages other than English.
+
+The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.
+
+This document and the information contained herein is provided on an "AS IS" basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+-->
+
+<xsd:schema
+ targetNamespace="http://docs.oasis-open.org/wsn/b-2"
+ xmlns="http://docs.oasis-open.org/wsn/b-2"
+ xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
+ xmlns:wsrf-rl="http://docs.oasis-open.org/wsrf/rl-2"
+ xmlns:wstop="http://docs.oasis-open.org/wsn/t-1"
+xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified" attributeFormDefault="unqualified">
+
+<!-- ======================== Imports ============================ -->
+
+ <xsd:import namespace="http://www.w3.org/2005/08/addressing"
+ schemaLocation="WS-Addressing-2005_08.xsd"
+ />
+
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/bf-2"
+ schemaLocation="WS-BaseFaults-1_2.xsd"
+ />
+
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/rl-2"
+ schemaLocation="WS-ResourceLifetime-1_2.xsd"
+ />
+ <xsd:import namespace="http://docs.oasis-open.org/wsn/t-1"
+ schemaLocation="WS-Topics-1_3.xsd"
+ />
+
+<!-- ===================== Misc. Helper Types ===================== -->
+
+ <xsd:complexType name="QueryExpressionType" mixed="true">
+ <xsd:sequence>
+ <xsd:any minOccurs="0" maxOccurs="1" processContents="lax" />
+ </xsd:sequence>
+ <xsd:attribute name="Dialect" type="xsd:anyURI" use="required"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="TopicExpressionType" mixed="true">
+ <xsd:sequence>
+ <xsd:any minOccurs="0" maxOccurs="1" processContents="lax" />
+ </xsd:sequence>
+ <xsd:attribute name="Dialect" type="xsd:anyURI" use="required" />
+ <xsd:anyAttribute/>
+ </xsd:complexType>
+
+ <xsd:complexType name="FilterType">
+ <xsd:sequence>
+ <xsd:any minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="SubscriptionPolicyType">
+ <xsd:sequence>
+ <xsd:any minOccurs="0" maxOccurs="unbounded" processContents="lax"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+<!-- =============== Resource Property Related =================== -->
+<!-- ======== Resource Properties for NotificationProducer ======== -->
+ <xsd:element name="TopicExpression" type="wsnt:TopicExpressionType"/>
+ <xsd:element name="FixedTopicSet" type="xsd:boolean" default="true"/>
+ <xsd:element name="TopicExpressionDialect" type="xsd:anyURI"/>
+
+ <xsd:element name="NotificationProducerRP">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsnt:TopicExpression"
+ minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element ref="wsnt:FixedTopicSet"
+ minOccurs="0" maxOccurs="1" />
+ <xsd:element ref="wsnt:TopicExpressionDialect"
+ minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element ref="wstop:TopicSet"
+ minOccurs="0" maxOccurs="1" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+<!-- ======== Resource Properties for SubscriptionManager ========= -->
+ <xsd:element name="ConsumerReference"
+ type="wsa:EndpointReferenceType" />
+ <xsd:element name="Filter" type="wsnt:FilterType" />
+ <xsd:element name="SubscriptionPolicy" type="wsnt:SubscriptionPolicyType" />
+
+
+ <xsd:element name="CreationTime" type="xsd:dateTime" />
+
+ <xsd:element name="SubscriptionManagerRP" >
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsnt:ConsumerReference"
+ minOccurs="1" maxOccurs="1" />
+ <xsd:element ref="wsnt:Filter"
+ minOccurs="0" maxOccurs="1" />
+ <xsd:element ref="wsnt:SubscriptionPolicy"
+ minOccurs="0" maxOccurs="1" />
+ <xsd:element ref="wsnt:CreationTime"
+ minOccurs="0" maxOccurs="1" />
+ <xsd:element ref="wsrf-rl:CurrentTime"/>
+ <xsd:element ref="wsrf-rl:TerminationTime"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+<!-- ================= Notification Metadata ===================== -->
+ <xsd:element name="SubscriptionReference"
+ type="wsa:EndpointReferenceType" />
+ <xsd:element name="Topic"
+ type="wsnt:TopicExpressionType" />
+ <xsd:element name="ProducerReference"
+ type="wsa:EndpointReferenceType" />
+
+<!-- ================== Message Helper Types ===================== -->
+ <xsd:complexType name="NotificationMessageHolderType" >
+ <xsd:sequence>
+ <xsd:element ref="wsnt:SubscriptionReference"
+ minOccurs="0" maxOccurs="1" />
+ <xsd:element ref="wsnt:Topic"
+ minOccurs="0" maxOccurs="1" />
+ <xsd:element ref="wsnt:ProducerReference"
+ minOccurs="0" maxOccurs="1" />
+ <xsd:element name="Message">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any namespace="##any" processContents="lax"
+ minOccurs="1" maxOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="NotificationMessage"
+ type="wsnt:NotificationMessageHolderType"/>
+
+<!-- ========== Message Types for NotificationConsumer =========== -->
+ <xsd:element name="Notify" >
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsnt:NotificationMessage"
+ minOccurs="1" maxOccurs="unbounded" />
+ <xsd:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+<!-- ========== Message Types for NotificationProducer =========== -->
+
+ <xsd:simpleType name="AbsoluteOrRelativeTimeType">
+ <xsd:union memberTypes="xsd:dateTime xsd:duration" />
+ </xsd:simpleType>
+
+ <xsd:element name="CurrentTime" type="xsd:dateTime" />
+
+ <xsd:element name="TerminationTime"
+ nillable="true" type="xsd:dateTime" />
+
+ <xsd:element name="ProducerProperties"
+ type="wsnt:QueryExpressionType" />
+
+ <xsd:element name="MessageContent"
+ type="wsnt:QueryExpressionType" />
+
+ <xsd:element name="UseRaw"><xsd:complexType/></xsd:element>
+
+ <xsd:element name="Subscribe" >
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="ConsumerReference"
+ type="wsa:EndpointReferenceType"
+ minOccurs="1" maxOccurs="1" />
+ <xsd:element name="Filter"
+ type="wsnt:FilterType"
+ minOccurs="0" maxOccurs="1" />
+ <xsd:element name="InitialTerminationTime"
+ type="wsnt:AbsoluteOrRelativeTimeType"
+ nillable="true"
+ minOccurs="0" maxOccurs="1" />
+ <xsd:element name="SubscriptionPolicy"
+ minOccurs="0" maxOccurs="1">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any namespace="##any" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="SubscribeResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="SubscriptionReference"
+ type="wsa:EndpointReferenceType"
+ minOccurs="1" maxOccurs="1" />
+ <xsd:element ref="wsnt:CurrentTime"
+ minOccurs="0" maxOccurs="1" />
+ <xsd:element ref="wsnt:TerminationTime"
+ minOccurs="0" maxOccurs="1" />
+ <xsd:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="GetCurrentMessage">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="Topic"
+ type="wsnt:TopicExpressionType" />
+ <xsd:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="GetCurrentMessageResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:complexType name="SubscribeCreationFailedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="SubscribeCreationFailedFault"
+ type="wsnt:SubscribeCreationFailedFaultType"/>
+
+ <xsd:complexType name="InvalidFilterFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element name="UnknownFilter" type="xsd:QName"
+ minOccurs="1" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="InvalidFilterFault"
+ type="wsnt:InvalidFilterFaultType"/>
+
+ <xsd:complexType name="TopicExpressionDialectUnknownFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="TopicExpressionDialectUnknownFault"
+ type="wsnt:TopicExpressionDialectUnknownFaultType"/>
+
+ <xsd:complexType name="InvalidTopicExpressionFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="InvalidTopicExpressionFault"
+ type="wsnt:InvalidTopicExpressionFaultType"/>
+
+ <xsd:complexType name="TopicNotSupportedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="TopicNotSupportedFault"
+ type="wsnt:TopicNotSupportedFaultType"/>
+
+ <xsd:complexType name="MultipleTopicsSpecifiedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="MultipleTopicsSpecifiedFault"
+ type="wsnt:MultipleTopicsSpecifiedFaultType"/>
+
+ <xsd:complexType name="InvalidProducerPropertiesExpressionFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="InvalidProducerPropertiesExpressionFault"
+ type="wsnt:InvalidProducerPropertiesExpressionFaultType"/>
+
+ <xsd:complexType name="InvalidMessageContentExpressionFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="InvalidMessageContentExpressionFault"
+ type="wsnt:InvalidMessageContentExpressionFaultType"/>
+
+ <xsd:complexType name="UnrecognizedPolicyRequestFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element name="UnrecognizedPolicy" type="xsd:QName"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="UnrecognizedPolicyRequestFault"
+ type="wsnt:UnrecognizedPolicyRequestFaultType"/>
+
+ <xsd:complexType name="UnsupportedPolicyRequestFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element name="UnsupportedPolicy" type="xsd:QName"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="UnsupportedPolicyRequestFault"
+ type="wsnt:UnsupportedPolicyRequestFaultType"/>
+
+ <xsd:complexType name="NotifyMessageNotSupportedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="NotifyMessageNotSupportedFault"
+ type="wsnt:NotifyMessageNotSupportedFaultType"/>
+
+ <xsd:complexType name="UnacceptableInitialTerminationTimeFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element name="MinimumTime" type="xsd:dateTime"/>
+ <xsd:element name="MaximumTime" type="xsd:dateTime"
+ minOccurs="0"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="UnacceptableInitialTerminationTimeFault"
+ type="wsnt:UnacceptableInitialTerminationTimeFaultType"/>
+
+ <xsd:complexType name="NoCurrentMessageOnTopicFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="NoCurrentMessageOnTopicFault"
+ type="wsnt:NoCurrentMessageOnTopicFaultType"/>
+
+<!-- ======== Message Types for PullPoint ======================== -->
+ <xsd:element name="GetMessages">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="MaximumNumber"
+ type="xsd:nonNegativeInteger"/>
+ <xsd:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:anyAttribute/>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="GetMessagesResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsnt:NotificationMessage"
+ minOccurs="0" maxOccurs="unbounded" />
+ <xsd:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:anyAttribute/>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="DestroyPullPoint">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:anyAttribute/>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="DestroyPullPointResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:anyAttribute/>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:complexType name="UnableToDestroyPullPointFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="UnableToDestroyPullPointFault"
+ type="wsnt:UnableToDestroyPullPointFaultType"/>
+
+<!-- ======== Message Types for Create PullPoint ================= -->
+ <xsd:element name="CreatePullPoint">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:anyAttribute/>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="CreatePullPointResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="PullPoint"
+ type="wsa:EndpointReferenceType"/>
+ <xsd:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:anyAttribute/>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:complexType name="UnableToCreatePullPointFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="UnableToCreatePullPointFault"
+ type="wsnt:UnableToCreatePullPointFaultType"/>
+
+<!-- ======== Message Types for Base SubscriptionManager ========= -->
+ <xsd:element name="Renew">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="TerminationTime"
+ type="wsnt:AbsoluteOrRelativeTimeType"
+ nillable="true"
+ minOccurs="1" maxOccurs="1" />
+ <xsd:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="RenewResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsnt:TerminationTime"
+ minOccurs="1" maxOccurs="1" />
+ <xsd:element ref="wsnt:CurrentTime"
+ minOccurs="0" maxOccurs="1" />
+ <xsd:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:complexType name="UnacceptableTerminationTimeFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element name="MinimumTime" type="xsd:dateTime"/>
+ <xsd:element name="MaximumTime" type="xsd:dateTime"
+ minOccurs="0"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="UnacceptableTerminationTimeFault"
+ type="wsnt:UnacceptableTerminationTimeFaultType"/>
+
+ <xsd:element name="Unsubscribe">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="UnsubscribeResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:complexType name="UnableToDestroySubscriptionFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="UnableToDestroySubscriptionFault"
+ type="wsnt:UnableToDestroySubscriptionFaultType"/>
+
+<!-- ====== Message Types for Pausable SubscriptionManager ======= -->
+
+ <xsd:element name="PauseSubscription">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="PauseSubscriptionResponse" >
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="ResumeSubscription">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="ResumeSubscriptionResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:complexType name="PauseFailedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="PauseFailedFault"
+ type="wsnt:PauseFailedFaultType"/>
+
+ <xsd:complexType name="ResumeFailedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="ResumeFailedFault"
+ type="wsnt:ResumeFailedFaultType"/>
+
+</xsd:schema> \ No newline at end of file
diff --git a/java/management/client/src/main/java/wsdl/WS-MetadataExchange-2004_09.xsd b/java/management/client/src/main/java/wsdl/WS-MetadataExchange-2004_09.xsd
new file mode 100644
index 0000000000..771a801f57
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/WS-MetadataExchange-2004_09.xsd
@@ -0,0 +1,113 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<!--
+(c) 2004 BEA Systems Inc., Computer Associates International, Inc.,
+International Business Machines Corporation, Microsoft Corporation,
+Inc., SAP AG, Sun Microsystems, and webMethods. All rights reserved.
+
+Permission to copy and display the WS-MetadataExchange Specification
+(the "Specification"), in any medium without fee or royalty is hereby
+granted, provided that you include the following on ALL copies of the
+Specification that you make:
+
+1. A link or URL to the Specification at this location.
+2. The copyright notice as shown in the Specification.
+
+BEA Systems, Computer Associates, IBM, Microsoft, SAP, Sun, and
+webMethods (collectively, the "Authors") each agree to grant you a
+license, under royalty-free and otherwise reasonable,
+non-discriminatory terms and conditions, to their respective essential
+patent claims that they deem necessary to implement the
+WS-MetadataExchange Specification.
+
+THE SPECIFICATION IS PROVIDED "AS IS," AND THE AUTHORS MAKE NO
+REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE CONTENTS OF THE
+SPECIFICATION ARE SUITABLE FOR ANY PURPOSE; NOR THAT THE
+IMPLEMENTATION OF SUCH CONTENTS WILL NOT INFRINGE ANY THIRD PARTY
+PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
+
+THE AUTHORS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL,
+INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO ANY
+USE OR DISTRIBUTION OF THE SPECIFICATIONS.
+
+The name and trademarks of the Authors may NOT be used in any manner,
+including advertising or publicity pertaining to the Specifications or
+their contents without specific, written prior permission. Title to
+copyright in the Specifications will at all times remain with the
+Authors.
+
+No other rights are granted by implication, estoppel or otherwise.
+-->
+
+<xs:schema
+ targetNamespace="http://schemas.xmlsoap.org/ws/2004/09/mex"
+ xmlns:tns="http://schemas.xmlsoap.org/ws/2004/09/mex"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified" >
+
+ <xs:import
+ namespace="http://www.w3.org/2005/08/addressing"
+ schemaLocation="WS-Addressing-2005_08.xsd" />
+
+ <!-- Get Metadata request -->
+ <xs:element name='GetMetadata' >
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element ref='tns:Dialect' minOccurs='0' />
+ <xs:element ref='tns:Identifier' minOccurs='0' />
+ </xs:sequence>
+ <xs:anyAttribute namespace='##other' processContents='lax' />
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name='Dialect' type='xs:anyURI' />
+ <xs:element name='Identifier' type='xs:anyURI' />
+
+ <!-- Get Metadata response -->
+ <xs:element name='Metadata' >
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element ref='tns:MetadataSection'
+ minOccurs='0'
+ maxOccurs='unbounded' />
+ </xs:sequence>
+ <xs:anyAttribute namespace='##other' processContents='lax' />
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name='MetadataSection' >
+ <xs:complexType>
+ <xs:choice>
+ <xs:any namespace='##other'
+ processContents='lax'
+ minOccurs='0'
+ maxOccurs='unbounded' />
+ <xs:element ref='tns:MetadataReference' />
+ <xs:element ref='tns:Location' />
+ </xs:choice>
+ <xs:attribute name='Dialect' type='xs:anyURI' use='required' />
+ <xs:attribute name='Identifier' type='xs:anyURI' />
+ <xs:anyAttribute namespace='##other' processContents='lax' />
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name='MetadataReference'
+ type='wsa:EndpointReferenceType' />
+
+ <xs:element name='Location'
+ type='xs:anyURI' />
+
+ <!-- count(/s:Envelope/s:Body/*) = 0 for Get request -->
+
+ <!-- Get Response returns xs:any -->
+
+ <xs:complexType name='AnyXmlType' >
+ <xs:sequence>
+ <xs:any namespace='##any' processContents='lax' />
+ </xs:sequence>
+ <xs:anyAttribute namespace='##any' processContents='lax' />
+ </xs:complexType>
+
+</xs:schema>
diff --git a/java/management/client/src/main/java/wsdl/WS-Resource-1_2.wsdl b/java/management/client/src/main/java/wsdl/WS-Resource-1_2.wsdl
new file mode 100644
index 0000000000..ed1c309211
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/WS-Resource-1_2.wsdl
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+OASIS takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any effort to identify any such rights. Information on OASIS's procedures with respect to rights in OASIS specifications can be found at the OASIS website. Copies of claims of rights made available for publication and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementors or users of this specification, can be obtained from the OASIS Executive Director.
+
+OASIS invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may cover technology that may be required to implement this specification. Please address the information to the OASIS Executive Director.
+
+Copyright (C) OASIS Open (2005). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to OASIS, except as needed for the purpose of developing OASIS specifications, in which case the procedures for copyrights defined in the OASIS Intellectual Property Rights document must be followed, or as required to translate it into languages other than English.
+
+The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.
+
+This document and the information contained herein is provided on an "AS IS" basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+-->
+
+<wsdl:definitions name="WS-Resource"
+ xmlns="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:wsrf-r="http://docs.oasis-open.org/wsrf/r-2"
+ xmlns:wsrf-rw="http://docs.oasis-open.org/wsrf/rw-2"
+ targetNamespace="http://docs.oasis-open.org/wsrf/rw-2"
+>
+
+<!-- ===================== Types Definitions ====================== -->
+ <wsdl:types>
+ <xsd:schema
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://docs.oasis-open.org/wsrf/rw-2"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified">
+
+ <xsd:import
+ namespace="http://docs.oasis-open.org/wsrf/r-2"
+ schemaLocation="WS-Resource-1_2.xsd"
+ />
+
+ </xsd:schema>
+ </wsdl:types>
+
+<!-- ================= WS-Resource faults ========================= -->
+ <wsdl:message name="ResourceUnknownFault">
+ <part name="ResourceUnknownFault"
+ element="wsrf-r:ResourceUnknownFault" />
+ </wsdl:message>
+
+ <wsdl:message name="ResourceUnavailableFault">
+ <part name="ResourceUnavailableFault"
+ element="wsrf-r:ResourceUnavailableFault" />
+ </wsdl:message>
+
+</wsdl:definitions>
+
diff --git a/java/management/client/src/main/java/wsdl/WS-Resource-1_2.xsd b/java/management/client/src/main/java/wsdl/WS-Resource-1_2.xsd
new file mode 100644
index 0000000000..5d50284a33
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/WS-Resource-1_2.xsd
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+OASIS takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any effort to identify any such rights. Information on OASIS's procedures with respect to rights in OASIS specifications can be found at the OASIS website. Copies of claims of rights made available for publication and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementors or users of this specification, can be obtained from the OASIS Executive Director.
+
+OASIS invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may cover technology that may be required to implement this specification. Please address the information to the OASIS Executive Director.
+
+Copyright (C) OASIS Open (2005). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to OASIS, except as needed for the purpose of developing OASIS specifications, in which case the procedures for copyrights defined in the OASIS Intellectual Property Rights document must be followed, or as required to translate it into languages other than English.
+
+The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.
+
+This document and the information contained herein is provided on an "AS IS" basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+-->
+<xsd:schema
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:wsrf-r="http://docs.oasis-open.org/wsrf/r-2"
+ xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ elementFormDefault="qualified" attributeFormDefault="unqualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/r-2"
+>
+
+ <xsd:import
+ namespace="http://docs.oasis-open.org/wsrf/bf-2"
+ schemaLocation="WS-BaseFaults-1_2.xsd" />
+
+<!-- ====================== WS-Resource fault types ============= -->
+
+ <xsd:complexType name="ResourceUnknownFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="ResourceUnknownFault"
+ type="wsrf-r:ResourceUnknownFaultType"/>
+
+ <xsd:complexType name="ResourceUnavailableFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="ResourceUnavailableFault"
+ type="wsrf-r:ResourceUnavailableFaultType"/>
+</xsd:schema>
+
diff --git a/java/management/client/src/main/java/wsdl/WS-ResourceLifetime-1_2.wsdl b/java/management/client/src/main/java/wsdl/WS-ResourceLifetime-1_2.wsdl
new file mode 100644
index 0000000000..adea5800fc
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/WS-ResourceLifetime-1_2.wsdl
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ OASIS takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any effort to identify any such rights. Information on OASIS's procedures with respect to rights in OASIS specifications can be found at the OASIS website. Copies of claims of rights made available for publication and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementors or users of this specification, can be obtained from the OASIS Executive Director.
+
+ OASIS invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may cover technology that may be required to implement this specification. Please address the information to the OASIS Executive Director.
+
+ Copyright (C) OASIS Open (2005). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to OASIS, except as needed for the purpose of developing OASIS specifications, in which case the procedures for copyrights defined in the OASIS Intellectual Property Rights document must be followed, or as required to translate it into languages other than English.
+
+ The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.
+
+ This document and the information contained herein is provided on an "AS IS" basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+-->
+<wsdl:definitions name="WS-ResourceLifetime"
+targetNamespace="http://docs.oasis-open.org/wsrf/rlw-2"
+xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
+xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
+xmlns:wsrf-rl="http://docs.oasis-open.org/wsrf/rl-2"
+xmlns:wsrf-rlw="http://docs.oasis-open.org/wsrf/rlw-2"
+xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2"
+xmlns:wsrf-rw="http://docs.oasis-open.org/wsrf/rw-2"
+xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
+
+ <wsdl:import namespace="http://docs.oasis-open.org/wsrf/rw-2"
+ location="WS-Resource-1_2.wsdl"/>
+ <wsdl:types>
+ <xsd:schema attributeFormDefault="unqualified"
+ elementFormDefault="qualified"
+ xmlns="http://www.w3.org/2001/XMLSchema">
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/rl-2"
+ schemaLocation="WS-ResourceLifetime-1_2.xsd" />
+ </xsd:schema>
+ </wsdl:types>
+
+ <wsdl:message name="SetTerminationTimeRequest">
+ <wsdl:part element="wsrf-rl:SetTerminationTime" name="SetTerminationTimeRequest" />
+ </wsdl:message>
+ <wsdl:message name="SetTerminationTimeResponse">
+ <wsdl:part element="wsrf-rl:SetTerminationTimeResponse" name="SetTerminationTimeResponse" />
+ </wsdl:message>
+
+ <wsdl:message name="DestroyRequest">
+ <wsdl:part element="wsrf-rl:Destroy" name="DestroyRequest" />
+ </wsdl:message>
+ <wsdl:message name="DestroyResponse">
+ <wsdl:part element="wsrf-rl:DestroyResponse" name="DestroyResponse" />
+ </wsdl:message>
+ <wsdl:message name="ResourceNotDestroyedFault">
+ <wsdl:part element="wsrf-rl:ResourceNotDestroyedFault" name="ResourceNotDestroyedFault" />
+ </wsdl:message>
+
+ <wsdl:message name="UnableToSetTerminationTimeFault">
+ <wsdl:part element="wsrf-rl:UnableToSetTerminationTimeFault" name="UnableToSetTerminationTimeFault" />
+ </wsdl:message>
+ <wsdl:message name="TerminationTimeChangeRejectedFault">
+ <wsdl:part element="wsrf-rl:TerminationTimeChangeRejectedFault" name="TerminationTimeChangeRejectedFault" />
+ </wsdl:message>
+ <wsdl:portType name="ImmediateResourceTermination">
+ <wsdl:operation name="Destroy">
+ <wsdl:input name="DestroyRequest" message="wsrf-rlw:DestroyRequest" />
+
+ <wsdl:output name="DestroyResponse" message="wsrf-rlw:DestroyResponse" />
+ <wsdl:fault message="wsrf-rlw:ResourceNotDestroyedFault" name="ResourceNotDestroyedFault" />
+ <wsdl:fault name="ResourceUnknownFault" message="wsrf-rw:ResourceUnknownFault" />
+ <wsdl:fault name="ResourceUnavailableFault" message="wsrf-rw:ResourceUnavailableFault"/>
+ </wsdl:operation>
+ </wsdl:portType>
+ <wsdl:portType name="ScheduledResourceTermination"
+ wsrf-rp:ResourceProperties="wsrf-rl:ScheduledResourceTerminationRP">
+ <wsdl:operation name="SetTerminationTime">
+ <wsdl:input name="SetTerminationTimeRequest" message="wsrf-rlw:SetTerminationTimeRequest" />
+ <wsdl:output name="SetTerminationTimeResponse" message="wsrf-rlw:SetTerminationTimeResponse" />
+
+ <wsdl:fault message="wsrf-rlw:UnableToSetTerminationTimeFault" name="UnableToSetTerminationTimeFault" />
+ <wsdl:fault name="ResourceUnknownFault" message="wsrf-rw:ResourceUnknownFault" />
+ <wsdl:fault name="ResourceUnavailableFault" message="wsrf-rw:ResourceUnavailableFault"/>
+ <wsdl:fault message="wsrf-rlw:TerminationTimeChangeRejectedFault" name="TerminationTimeChangeRejectedFault" />
+ </wsdl:operation>
+ </wsdl:portType>
+</wsdl:definitions> \ No newline at end of file
diff --git a/java/management/client/src/main/java/wsdl/WS-ResourceLifetime-1_2.xsd b/java/management/client/src/main/java/wsdl/WS-ResourceLifetime-1_2.xsd
new file mode 100644
index 0000000000..3338faf191
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/WS-ResourceLifetime-1_2.xsd
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ OASIS takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any effort to identify any such rights. Information on OASIS's procedures with respect to rights in OASIS specifications can be found at the OASIS website. Copies of claims of rights made available for publication and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementors or users of this specification, can be obtained from the OASIS Executive Director.
+
+ OASIS invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may cover technology that may be required to implement this specification. Please address the information to the OASIS Executive Director.
+
+ Copyright (C) OASIS Open (2005). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to OASIS, except as needed for the purpose of developing OASIS specifications, in which case the procedures for copyrights defined in the OASIS Intellectual Property Rights document must be followed, or as required to translate it into languages other than English.
+
+ The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.
+
+ This document and the information contained herein is provided on an "AS IS" basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+-->
+
+
+<xsd:schema
+xmlns="http://www.w3.org/2001/XMLSchema"
+xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+xmlns:wsrf-rl="http://docs.oasis-open.org/wsrf/rl-2"
+xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
+elementFormDefault="qualified" attributeFormDefault="unqualified"
+targetNamespace="http://docs.oasis-open.org/wsrf/rl-2">
+
+ <xsd:import namespace="http://docs.oasis-open.org/wsrf/bf-2"
+ schemaLocation="WS-BaseFaults-1_2.xsd" />
+ <!--
+ =============== Resource Property Related ===================
+ -->
+ <!--
+ ==== Resource Properties for ScheduledResourceTermination ====
+ -->
+
+ <xsd:element name="CurrentTime" >
+ <xsd:complexType>
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:dateTime" >
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="TerminationTime" nillable="true">
+ <xsd:complexType>
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:dateTime" >
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ </xsd:element>
+
+
+ <!-- ==== Resource Properties for ScheduledResourceTermination ==== -->
+ <xsd:element name="ScheduledResourceTerminationRP">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element maxOccurs="1" minOccurs="1" ref="wsrf-rl:CurrentTime" />
+ <xsd:element maxOccurs="1" minOccurs="1" ref="wsrf-rl:TerminationTime" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <!-- ====== Message Types for ImmediateResourceTermination ======= -->
+ <xsd:element name="Destroy">
+ <xsd:complexType />
+ </xsd:element>
+
+ <xsd:element name="DestroyResponse">
+ <xsd:complexType />
+ </xsd:element>
+
+ <xsd:complexType name="ResourceNotDestroyedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType" />
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="ResourceNotDestroyedFault" type="wsrf-rl:ResourceNotDestroyedFaultType" />
+ <!-- ====== Message Types for ScheduledResourceTermination ======= -->
+ <xsd:element name="SetTerminationTime">
+ <xsd:complexType>
+ <xsd:choice>
+ <xsd:element name="RequestedTerminationTime" nillable="true" type="xsd:dateTime" />
+ <xsd:element name="RequestedLifetimeDuration" type="xsd:duration" />
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="SetTerminationTimeResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="NewTerminationTime" nillable="true" type="xsd:dateTime" />
+ <xsd:element name="CurrentTime" type="xsd:dateTime" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:complexType name="UnableToSetTerminationTimeFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType" />
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:element name="UnableToSetTerminationTimeFault" type="wsrf-rl:UnableToSetTerminationTimeFaultType" />
+ <xsd:complexType name="TerminationTimeChangeRejectedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType" />
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="TerminationTimeChangeRejectedFault" type="wsrf-rl:TerminationTimeChangeRejectedFaultType" />
+
+
+ <!--
+ ============= Notification Message Related ==================
+ -->
+ <xsd:element name="TerminationNotification">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="TerminationTime" type="xsd:dateTime" minOccurs="1" maxOccurs="1" nillable="true" />
+ <xsd:element name="TerminationReason" type="xsd:anyType" minOccurs="0" maxOccurs="1" />
+ </xsd:sequence>
+
+ </xsd:complexType>
+ </xsd:element>
+
+
+</xsd:schema> \ No newline at end of file
diff --git a/java/management/client/src/main/java/wsdl/WS-ResourceMetadataDescriptor-CD-01.xsd b/java/management/client/src/main/java/wsdl/WS-ResourceMetadataDescriptor-CD-01.xsd
new file mode 100644
index 0000000000..2c5952264b
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/WS-ResourceMetadataDescriptor-CD-01.xsd
@@ -0,0 +1,325 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+
+OASIS takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any effort to identify any such rights. Information on OASIS's procedures with respect to rights in OASIS specifications can be found at the OASIS website. Copies of claims of rights made available for publication and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementors or users of this specification, can be obtained from the OASIS Executive Director.
+
+OASIS invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may cover technology that may be required to implement this specification. Please address the information to the OASIS Executive Director.
+
+Copyright (C) OASIS Open (2005-2006). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to OASIS, except as needed for the purpose of developing OASIS specifications, in which case the procedures for copyrights defined in the OASIS Intellectual Property Rights document must be followed, or as required to translate it into languages other than English.
+
+The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.
+
+This document and the information contained herein is provided on an "AS IS" basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+-->
+
+<xsd:schema
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2"
+ targetNamespace="http://docs.oasis-open.org/wsrf/rmd-1"
+ xmlns:wsrmd="http://docs.oasis-open.org/wsrf/rmd-1"
+ elementFormDefault="qualified">
+
+ <xsd:import
+ namespace="http://docs.oasis-open.org/wsrf/rp-2"
+ schemaLocation="WS-ResourceProperties-1_2.xsd" />
+
+ <xsd:import
+ namespace="http://www.w3.org/2005/08/addressing"
+ schemaLocation="WS-Addressing-2005_08.xsd" />
+
+
+
+<!-- ======================== Utility Types ======================= -->
+ <xsd:simpleType name="PairsOfURIType">
+ <xsd:list itemType="xsd:anyURI" />
+ </xsd:simpleType>
+
+<!-- ================ PortType Attribute Extensions ================ -->
+ <xsd:attribute name="Descriptor" type="xsd:QName" />
+
+ <xsd:attribute name="DescriptorLocation" type="xsd:anyURI" />
+
+<!-- ================= Documentation Component ==================== -->
+ <xsd:complexType name="DocumentationType" mixed="true" >
+ <xsd:sequence>
+ <xsd:any namespace="##any"
+ minOccurs="0" maxOccurs="unbounded"
+ processContents="lax" />
+ </xsd:sequence>
+ <xsd:anyAttribute/>
+ </xsd:complexType>
+
+ <xsd:complexType name="DocumentedType">
+ <xsd:sequence>
+ <xsd:element name="documentation" type="wsrmd:DocumentationType"
+ minOccurs="0" maxOccurs="1" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+<!-- ================== Definitions Component ===================== -->
+<!--
+ <Definitions
+ targetNamespace="xsd:anyURI"
+ {anyAttribute}* >
+
+ <documentation />?
+ <MetadataDescriptor /> *
+ {any}*
+
+</Definitions>
+ -->
+
+ <xsd:complexType name= "DefinitionsType" >
+ <xsd:complexContent>
+ <xsd:extension base="wsrmd:DocumentedType">
+ <xsd:sequence>
+ <xsd:element ref="wsrmd:MetadataDescriptor"
+ minOccurs="0" maxOccurs="unbounded" />
+ <xsd:any namespace="##other"
+ minOccurs="0" maxOccurs="unbounded"
+ processContents="lax" />
+ </xsd:sequence>
+ <xsd:attribute name="targetNamespace"
+ type="xsd:anyURI" use="required"/>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:element name="Definitions" type="wsrmd:DefinitionsType" >
+ <xsd:key name="MetadataDescriptor">
+ <xsd:annotation>
+ <xsd:documentation>
+ To form a QName, the name of any MetadataDescriptor must be
+ unique within a Definitions element.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:selector xpath="wsrmd:MetadataDescriptor" />
+ <xsd:field xpath="@name" />
+ </xsd:key>
+ </xsd:element>
+
+<!-- =============== MetadataDescriptor Component =================== -->
+<!--
+<MetadataDescriptor
+ name="xsd:NCName"
+ interface="xsd:QName"
+ wsdlLocation="list of xsd:anyURI"?
+ {anyAttribute}* >
+
+ <documentation />?
+ <Property /> *
+ {any}*
+
+</MetadataDescriptor>
+-->
+
+ <xsd:complexType name= "MetadataDescriptorType" >
+ <xsd:complexContent>
+ <xsd:extension base="wsrmd:DocumentedType">
+ <xsd:sequence>
+ <xsd:element ref="wsrmd:Property"
+ minOccurs="0" maxOccurs="unbounded" />
+ <xsd:any namespace="##other"
+ minOccurs="0" maxOccurs="unbounded"
+ processContents="lax" />
+ </xsd:sequence>
+ <xsd:attribute name="name"
+ type="xsd:NCName" use="required"/>
+ <xsd:attribute name="interface"
+ type="xsd:QName" use="required"/>
+ <xsd:attribute name="wsdlLocation"
+ type="wsrmd:PairsOfURIType" />
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:element name="MetadataDescriptor"
+ type="wsrmd:MetadataDescriptorType" />
+
+<!-- ==================== Property Component ====================== -->
+<!--
+<Property
+ name="xsd:QName"
+ mutability="[constant|appendable|mutable]" ?
+ modifiability="[read-only|read-write]" ?
+ subscribability="xs:boolean" ?
+ {anyAttribute}* >
+
+ <documentation />?
+ [ <ValidValues> {any}* </ValidValues> |
+ <ValidValueRange lowerBound=’xsd:simpleType’
+ upperBound=’xsd:simpleType’>
+ </ValidValueRange> ] ?
+ <StaticValues> {any}* </StaticValues> ?
+
+ {any} *
+
+</Property>
+-->
+ <xsd:complexType name= "PropertyType" >
+ <xsd:complexContent>
+ <xsd:extension base="wsrmd:DocumentedType">
+ <xsd:sequence>
+ <xsd:choice>
+ <xsd:element ref="wsrmd:ValidValues"
+ minOccurs="0" maxOccurs="1" />
+ <xsd:element ref="wsrmd:ValidValueRange"
+ minOccurs="0" maxOccurs="1" />
+ </xsd:choice>
+ <xsd:element ref="wsrmd:StaticValues"
+ minOccurs="0" maxOccurs="1" />
+ <xsd:any namespace="##other"
+ minOccurs="0" maxOccurs="unbounded"
+ processContents="lax" />
+ </xsd:sequence>
+ <xsd:attribute name="name"
+ type="xsd:QName" use="required"/>
+ <xsd:attribute name="mutability"
+ type="wsrmd:MutabilityType" />
+ <xsd:attribute name="modifiability"
+ type="wsrmd:ModifiabilityType" />
+ <xsd:attribute name="subscribability" type="xsd:boolean" default="false" />
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:element name="Property" type="wsrmd:PropertyType" />
+
+ <xsd:simpleType name="MutabilityType">
+ <xsd:restriction base="xsd:string" >
+ <xsd:enumeration value="constant" />
+ <xsd:enumeration value="appendable" />
+ <xsd:enumeration value="mutable" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="ModifiabilityType">
+ <xsd:restriction base="xsd:string" >
+ <xsd:enumeration value="read-only" />
+ <xsd:enumeration value="read-write" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+<!-- ================= Valid Values Component ===================== -->
+<!--
+<ValidValues
+ {anyAttribute}* >
+ <documentation />?
+ {any}*
+</ValidValues>
+-->
+ <xsd:complexType name= "ValidValuesType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="documentation" type="wsrmd:DocumentationType"
+ minOccurs="0" maxOccurs="1" />
+
+ <xsd:any namespace="##other"
+ minOccurs="0" maxOccurs="unbounded"
+ processContents="lax" />
+ </xsd:sequence>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+
+ <xsd:element name="ValidValues" type="wsrmd:ValidValuesType" />
+
+<!-- ================= Valid Range Component ===================== -->
+<!--
+<ValidValueRange
+ lowerBound="xs:anySimpleType" ? upperBound="xs:anySimpleType" ?
+ {anyAttribute}* >
+ <documentation />?
+ {any}*
+</ValidValueRange>
+-->
+ <xsd:complexType name= "ValidValueRangeType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="documentation" type="wsrmd:DocumentationType"
+ minOccurs="0" maxOccurs="1" />
+
+ <xsd:any namespace="##other"
+ minOccurs="0" maxOccurs="unbounded"
+ processContents="lax" />
+ </xsd:sequence>
+ <xsd:attribute name="lowerBound" type="xsd:anySimpleType" />
+ <xsd:attribute name="upperBound" type="xsd:anySimpleType" />
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+
+ <xsd:element name="ValidValueRange" type="wsrmd:ValidValueRangeType" />
+
+<!-- ================ Static Values Component ===================== -->
+<!--
+<StaticValues
+ {anyAttribute}* >
+ <documentation />?
+ {any}*
+</StaticValues>
+-->
+ <xsd:complexType name= "StaticValuesType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="documentation" type="wsrmd:DocumentationType"
+ minOccurs="0" maxOccurs="1" />
+
+ <xsd:any namespace="##other"
+ minOccurs="0" maxOccurs="unbounded"
+ processContents="lax" />
+ </xsd:sequence>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+
+ <xsd:element name="StaticValues" type="wsrmd:StaticValuesType" />
+
+<!-- ================ Initial Values Component ==================== -->
+<!--
+<InitialValues
+ {anyAttribute}* >
+ <documentation />?
+ {any}*
+</InitialValues>
+-->
+ <xsd:complexType name= "InitialValuesType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="documentation" type="wsrmd:DocumentationType"
+ minOccurs="0" maxOccurs="1" />
+
+ <xsd:any namespace="##other"
+ minOccurs="0" maxOccurs="unbounded"
+ processContents="lax" />
+ </xsd:sequence>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+
+ <xsd:element name="InitialValues" type="wsrmd:InitialValuesType" />
+
+
+<!-- =========== MetadataDescriptorReference RP GED =============== -->
+ <xsd:complexType name="MetadataDescriptorReferenceType">
+ <xsd:complexContent>
+ <xsd:extension base="wsa:EndpointReferenceType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:element name="MetadataDescriptorReference"
+ type="wsrmd:MetadataDescriptorReferenceType" />
+
+<!--
+
+Metadata Resource RP Doc
+
+This defines one property - MetadataDescriptor - which must have a cardinality of one.
+
+-->
+
+ <xsd:element name="MetadataResourceRP" type="wsrmd:DefinitionsType"/>
+
+</xsd:schema>
diff --git a/java/management/client/src/main/java/wsdl/WS-ResourceProperties-1_2.wsdl b/java/management/client/src/main/java/wsdl/WS-ResourceProperties-1_2.wsdl
new file mode 100644
index 0000000000..5d9d7562f4
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/WS-ResourceProperties-1_2.wsdl
@@ -0,0 +1,395 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+OASIS takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any effort to identify any such rights. Information on OASIS's procedures with respect to rights in OASIS specifications can be found at the OASIS website. Copies of claims of rights made available for publication and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementors or users of this specification, can be obtained from the OASIS Executive Director.
+
+OASIS invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may cover technology that may be required to implement this specification. Please address the information to the OASIS Executive Director.
+
+Copyright (C) OASIS Open (2005). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to OASIS, except as needed for the purpose of developing OASIS specifications, in which case the procedures for copyrights defined in the OASIS Intellectual Property Rights document must be followed, or as required to translate it into languages other than English.
+
+The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.
+
+This document and the information contained herein is provided on an "AS IS" basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+-->
+
+<wsdl:definitions name="WS-ResourceProperties"
+ xmlns="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2"
+ xmlns:wsrf-rpw="http://docs.oasis-open.org/wsrf/rpw-2"
+ xmlns:wsrf-rw="http://docs.oasis-open.org/wsrf/rw-2"
+ targetNamespace="http://docs.oasis-open.org/wsrf/rpw-2"
+>
+
+<!-- ========================== Imports ========================== -->
+
+ <wsdl:import
+ namespace="http://docs.oasis-open.org/wsrf/rw-2"
+ location="WS-Resource-1_2.wsdl" />
+
+<!-- ===================== Types Definitions ====================== -->
+ <wsdl:types>
+ <xsd:schema>
+ <xsd:import
+ namespace="http://docs.oasis-open.org/wsrf/rp-2"
+ schemaLocation="WS-ResourceProperties-1_2.xsd" />
+ </xsd:schema>
+ </wsdl:types>
+
+<!-- ================== GetResourcePropertyDocument ===============
+ GetResourcePropertyDocument()
+ returns: any
+-->
+ <wsdl:message name="GetResourcePropertyDocumentRequest">
+ <wsdl:part name="GetResourcePropertyDocumentRequest"
+ element="wsrf-rp:GetResourcePropertyDocument"/>
+ </wsdl:message>
+
+ <wsdl:message name="GetResourcePropertyDocumentResponse">
+ <wsdl:part name="GetResourcePropertyDocumentResponse"
+ element="wsrf-rp:GetResourcePropertyDocumentResponse"/>
+ </wsdl:message>
+
+<!-- ===================== GetResourceProperty ====================
+ GetResourceProperty(QName)
+ returns: any
+-->
+ <wsdl:message name="GetResourcePropertyRequest">
+ <wsdl:part name="GetResourcePropertyRequest"
+ element="wsrf-rp:GetResourceProperty" />
+ </wsdl:message>
+
+ <wsdl:message name="GetResourcePropertyResponse">
+ <wsdl:part name="GetResourcePropertyResponse"
+ element="wsrf-rp:GetResourcePropertyResponse" />
+ </wsdl:message>
+
+ <wsdl:message name="InvalidResourcePropertyQNameFault">
+ <part name="InvalidResourcePropertyQNameFault"
+ element="wsrf-rp:InvalidResourcePropertyQNameFault" />
+ </wsdl:message>
+
+<!-- ==============GetMultipleResourceProperties ==================
+ GetMultipleResourceProperties(list of QName)
+ returns: sequence of any
+-->
+ <wsdl:message name="GetMultipleResourcePropertiesRequest">
+ <wsdl:part name="GetMultipleResourcePropertiesRequest"
+ element="wsrf-rp:GetMultipleResourceProperties" />
+ </wsdl:message>
+
+ <wsdl:message name="GetMultipleResourcePropertiesResponse">
+ <wsdl:part name="GetMultipleResourcePropertiesResponse"
+ element="wsrf-rp:GetMultipleResourcePropertiesResponse" />
+ </wsdl:message>
+<!-- ================== PutResourcePropertyDocument ===============
+ PutResourcePropertyDocument(any)
+ returns: any?
+-->
+ <wsdl:message name="PutResourcePropertyDocumentRequest">
+ <wsdl:part name="PutResourcePropertyDocumentRequest"
+ element="wsrf-rp:PutResourcePropertyDocument"/>
+ </wsdl:message>
+
+ <wsdl:message name="PutResourcePropertyDocumentResponse">
+ <wsdl:part name="PutResourcePropertyDocumentResponse"
+ element="wsrf-rp:PutResourcePropertyDocumentResponse"/>
+ </wsdl:message>
+
+ <wsdl:message name="UnableToPutResourcePropertyDocumentFault">
+ <part name="UnableToPutResourcePropertyDocumentFault"
+ element="wsrf-rp:UnableToPutResourcePropertyDocumentFault" />
+ </wsdl:message>
+
+<!-- ================= SetResourceProperties ======================
+ SetResourceProperties(
+ { insert (any)* |
+ update (any)* |
+ delete@QName } +
+ )
+ returns: empty
+-->
+ <wsdl:message name="SetResourcePropertiesRequest">
+ <wsdl:part name="SetResourcePropertiesRequest"
+ element="wsrf-rp:SetResourceProperties" />
+ </wsdl:message>
+
+ <wsdl:message name="SetResourcePropertiesResponse">
+ <wsdl:part name="SetResourcePropertiesResponse"
+ element="wsrf-rp:SetResourcePropertiesResponse" />
+ </wsdl:message>
+
+ <wsdl:message name="InvalidModificationFault">
+ <part name="InvalidModificationFault"
+ element="wsrf-rp:InvalidModificationFault" />
+ </wsdl:message>
+
+ <wsdl:message name="UnableToModifyResourcePropertyFault">
+ <part name="UnableToModifyResourcePropertyFault"
+ element="wsrf-rp:UnableToModifyResourcePropertyFault" />
+ </wsdl:message>
+
+ <wsdl:message name="SetResourcePropertyRequestFailedFault">
+ <part name="SetResourcePropertyRequestFailedFault"
+ element="wsrf-rp:SetResourcePropertyRequestFailedFault" />
+ </wsdl:message>
+
+<!-- =============== InsertResourceProperties =====================
+ InsertResourceProperties((any)* )
+ returns: empty
+-->
+ <wsdl:message name="InsertResourcePropertiesRequest">
+ <wsdl:part name="InsertResourcePropertiesRequest"
+ element="wsrf-rp:InsertResourceProperties" />
+ </wsdl:message>
+
+ <wsdl:message name="InsertResourcePropertiesResponse">
+ <wsdl:part name="InsertResourcePropertiesResponse"
+ element="wsrf-rp:InsertResourcePropertiesResponse" />
+ </wsdl:message>
+
+ <wsdl:message name="InsertResourcePropertiesRequestFailedFault">
+ <part name="InsertResourcePropertiesRequestFailedFault"
+ element="wsrf-rp:InsertResourcePropertiesRequestFailedFault" />
+ </wsdl:message>
+
+<!-- =============== UpdateResourceProperties =====================
+ UpdateResourceProperties((any)* )
+ returns: empty
+-->
+ <wsdl:message name="UpdateResourcePropertiesRequest">
+ <wsdl:part name="UpdateResourcePropertiesRequest"
+ element="wsrf-rp:UpdateResourceProperties" />
+ </wsdl:message>
+
+ <wsdl:message name="UpdateResourcePropertiesResponse">
+ <wsdl:part name="UpdateResourcePropertiesResponse"
+ element="wsrf-rp:UpdateResourcePropertiesResponse" />
+ </wsdl:message>
+
+ <wsdl:message name="UpdateResourcePropertiesRequestFailedFault">
+ <part name="UpdateResourcePropertiesRequestFailedFault"
+ element="wsrf-rp:UpdateResourcePropertiesRequestFailedFault" />
+ </wsdl:message>
+
+<!-- =============== DeleteResourceProperties =====================
+ DeleteResourceProperties( ResourceProperty )
+ returns: empty
+-->
+ <wsdl:message name="DeleteResourcePropertiesRequest">
+ <wsdl:part name="DeleteResourcePropertiesRequest"
+ element="wsrf-rp:DeleteResourceProperties" />
+ </wsdl:message>
+
+ <wsdl:message name="DeleteResourcePropertiesResponse">
+ <wsdl:part name="DeleteResourcePropertiesResponse"
+ element="wsrf-rp:DeleteResourcePropertiesResponse" />
+ </wsdl:message>
+
+ <wsdl:message name="DeleteResourcePropertiesRequestFailedFault">
+ <part name="DeleteResourcePropertiesRequestFailedFault"
+ element="wsrf-rp:DeleteResourcePropertiesRequestFailedFault" />
+ </wsdl:message>
+
+<!-- ================ QueryResourceProperties =====================
+ QueryResourceProperties(QueryExpression)
+ returns: any
+-->
+ <wsdl:message name="QueryResourcePropertiesRequest">
+ <wsdl:part name="QueryResourcePropertiesRequest"
+ element="wsrf-rp:QueryResourceProperties" />
+ </wsdl:message>
+
+ <wsdl:message name="QueryResourcePropertiesResponse">
+ <wsdl:part name="QueryResourcePropertiesResponse"
+ element="wsrf-rp:QueryResourcePropertiesResponse" />
+ </wsdl:message>
+
+ <wsdl:message name="UnknownQueryExpressionDialectFault">
+ <part name="UnknownQueryExpressionDialectFault"
+ element="wsrf-rp:UnknownQueryExpressionDialectFault" />
+ </wsdl:message>
+
+ <wsdl:message name="InvalidQueryExpressionFault">
+ <part name="InvalidQueryExpressionFault"
+ element="wsrf-rp:InvalidQueryExpressionFault" />
+ </wsdl:message>
+
+ <wsdl:message name="QueryEvaluationErrorFault">
+ <part name="QueryEvaluationErrorFault"
+ element="wsrf-rp:QueryEvaluationErrorFault" />
+ </wsdl:message>
+
+<!-- =================== PortType Definitions ===================== -->
+ <wsdl:portType name="GetResourcePropertyDocument">
+ <wsdl:operation name="GetResourcePropertyDocument">
+ <wsdl:input name="GetResourcePropertyDocumentRequest"
+ message="wsrf-rpw:GetResourcePropertyDocumentRequest"/>
+ <wsdl:output name="GetResourcePropertyDocumentResponse"
+ message="wsrf-rpw:GetResourcePropertyDocumentResponse"/>
+ <wsdl:fault name="ResourceUnknownFault"
+ message="wsrf-rw:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault"
+ message="wsrf-rw:ResourceUnavailableFault"/>
+ </wsdl:operation>
+ </wsdl:portType>
+
+ <wsdl:portType name="GetResourceProperty">
+ <wsdl:operation name="GetResourceProperty">
+ <wsdl:input name="GetResourcePropertyRequest"
+ message="wsrf-rpw:GetResourcePropertyRequest" />
+ <wsdl:output name="GetResourcePropertyResponse"
+ message="wsrf-rpw:GetResourcePropertyResponse" />
+ <wsdl:fault name="ResourceUnknownFault"
+ message="wsrf-rw:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault"
+ message="wsrf-rw:ResourceUnavailableFault"/>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault"
+ message="wsrf-rpw:InvalidResourcePropertyQNameFault" />
+ </wsdl:operation>
+ </wsdl:portType>
+
+ <wsdl:portType name="GetMultipleResourceProperties">
+ <wsdl:operation name="GetMultipleResourceProperties">
+ <wsdl:input name="GetMultipleResourcePropertiesRequest"
+ message="wsrf-rpw:GetMultipleResourcePropertiesRequest" />
+ <wsdl:output name="GetMultipleResourcePropertiesResponse"
+ message="wsrf-rpw:GetMultipleResourcePropertiesResponse" />
+ <wsdl:fault name="ResourceUnknownFault"
+ message="wsrf-rw:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault"
+ message="wsrf-rw:ResourceUnavailableFault"/>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault"
+ message="wsrf-rpw:InvalidResourcePropertyQNameFault" />
+ </wsdl:operation>
+ </wsdl:portType>
+
+ <wsdl:portType name="PutResourcePropertyDocument">
+ <wsdl:operation name="PutResourcePropertyDocument">
+ <wsdl:input name="PutResourcePropertyDocumentRequest"
+ message="wsrf-rpw:PutResourcePropertyDocumentRequest" />
+ <wsdl:output name="PutResourcePropertyDocumentResponse"
+ message="wsrf-rpw:PutResourcePropertyDocumentResponse" />
+ <wsdl:fault name="ResourceUnknownFault"
+ message="wsrf-rw:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault"
+ message="wsrf-rw:ResourceUnavailableFault"/>
+ <wsdl:fault name="UnableToPutResourcePropertyDocumentFault"
+ message="wsrf-rpw:UnableToPutResourcePropertyDocumentFault" />
+ </wsdl:operation>
+ </wsdl:portType>
+
+ <wsdl:portType name="SetResourceProperties">
+ <wsdl:operation name="SetResourceProperties">
+ <wsdl:input name="SetResourcePropertiesRequest"
+ message="wsrf-rpw:SetResourcePropertiesRequest" />
+ <wsdl:output name="SetResourcePropertiesResponse"
+ message="wsrf-rpw:SetResourcePropertiesResponse" />
+ <wsdl:fault name="ResourceUnknownFault"
+ message="wsrf-rw:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault"
+ message="wsrf-rw:ResourceUnavailableFault"/>
+ <wsdl:fault name="InvalidModificationFault"
+ message="wsrf-rpw:InvalidModificationFault" />
+ <wsdl:fault name="UnableToModifyResourcePropertyFault"
+ message="wsrf-rpw:UnableToModifyResourcePropertyFault" />
+ <wsdl:fault name="InvalidResourcePropertyQNameFault"
+ message="wsrf-rpw:InvalidResourcePropertyQNameFault" />
+ <wsdl:fault name="SetResourcePropertyRequestFailedFault"
+ message="wsrf-rpw:SetResourcePropertyRequestFailedFault" />
+ </wsdl:operation>
+ </wsdl:portType>
+
+ <wsdl:portType name="InsertResourceProperties">
+ <wsdl:operation name="InsertResourceProperties">
+ <wsdl:input name="InsertResourcePropertiesRequest"
+ message="wsrf-rpw:InsertResourcePropertiesRequest" />
+ <wsdl:output name="InsertResourcePropertiesResponse"
+ message="wsrf-rpw:InsertResourcePropertiesResponse" />
+ <wsdl:fault name="ResourceUnknownFault"
+ message="wsrf-rw:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault"
+ message="wsrf-rw:ResourceUnavailableFault"/>
+ <wsdl:fault name="InvalidModificationFault"
+ message="wsrf-rpw:InvalidModificationFault" />
+ <wsdl:fault name="UnableToModifyResourcePropertyFault"
+ message="wsrf-rpw:UnableToModifyResourcePropertyFault" />
+ <wsdl:fault name="InvalidResourcePropertyQNameFault"
+ message="wsrf-rpw:InvalidResourcePropertyQNameFault" />
+ <wsdl:fault name="InsertResourcePropertiesRequestFailedFault"
+ message="wsrf-rpw:InsertResourcePropertiesRequestFailedFault" />
+ </wsdl:operation>
+ </wsdl:portType>
+
+ <wsdl:portType name="UpdateResourceProperties">
+ <wsdl:operation name="UpdateResourceProperties">
+ <wsdl:input name="UpdateResourcePropertiesRequest"
+ message="wsrf-rpw:UpdateResourcePropertiesRequest" />
+ <wsdl:output name="UpdateResourcePropertiesResponse"
+ message="wsrf-rpw:UpdateResourcePropertiesResponse" />
+ <wsdl:fault name="ResourceUnknownFault"
+ message="wsrf-rw:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault"
+ message="wsrf-rw:ResourceUnavailableFault"/>
+ <wsdl:fault name="InvalidModificationFault"
+ message="wsrf-rpw:InvalidModificationFault" />
+ <wsdl:fault name="UnableToModifyResourcePropertyFault"
+ message="wsrf-rpw:UnableToModifyResourcePropertyFault" />
+ <wsdl:fault name="InvalidResourcePropertyQNameFault"
+ message="wsrf-rpw:InvalidResourcePropertyQNameFault" />
+ <wsdl:fault name="UpdateResourcePropertiesRequestFailedFault"
+ message="wsrf-rpw:UpdateResourcePropertiesRequestFailedFault" />
+ </wsdl:operation>
+ </wsdl:portType>
+
+ <wsdl:portType name="DeleteResourceProperties">
+ <wsdl:operation name="DeleteResourceProperties">
+ <wsdl:input name="DeleteResourcePropertiesRequest"
+ message="wsrf-rpw:DeleteResourcePropertiesRequest" />
+ <wsdl:output name="DeleteResourcePropertiesResponse"
+ message="wsrf-rpw:DeleteResourcePropertiesResponse" />
+ <wsdl:fault name="ResourceUnknownFault"
+ message="wsrf-rw:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault"
+ message="wsrf-rw:ResourceUnavailableFault"/>
+ <wsdl:fault name="InvalidModificationFault"
+ message="wsrf-rpw:InvalidModificationFault" />
+ <wsdl:fault name="UnableToModifyResourcePropertyFault"
+ message="wsrf-rpw:UnableToModifyResourcePropertyFault" />
+ <wsdl:fault name="InvalidResourcePropertyQNameFault"
+ message="wsrf-rpw:InvalidResourcePropertyQNameFault" />
+ <wsdl:fault name="DeleteResourcePropertiesRequestFailedFault"
+ message="wsrf-rpw:DeleteResourcePropertiesRequestFailedFault" />
+ </wsdl:operation>
+ </wsdl:portType>
+
+<wsdl:portType name="QueryResourceProperties"
+ wsrf-rp:ResourceProperties="wsrf-rp:QueryExpressionRPDocument">
+ <wsdl:operation name="QueryResourceProperties">
+ <wsdl:input name="QueryResourcePropertiesRequest"
+ message="wsrf-rpw:QueryResourcePropertiesRequest" />
+ <wsdl:output name="QueryResourcePropertiesResponse"
+ message="wsrf-rpw:QueryResourcePropertiesResponse" />
+ <wsdl:fault name="ResourceUnknownFault"
+ message="wsrf-rw:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault"
+ message="wsrf-rw:ResourceUnavailableFault"/>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault"
+ message="wsrf-rpw:InvalidResourcePropertyQNameFault" />
+ <wsdl:fault name="UnknownQueryExpressionDialectFault"
+ message="wsrf-rpw:UnknownQueryExpressionDialectFault" />
+ <wsdl:fault name="InvalidQueryExpressionFault"
+ message="wsrf-rpw:InvalidQueryExpressionFault" />
+ <wsdl:fault name="QueryEvaluationErrorFault"
+ message="wsrf-rpw:QueryEvaluationErrorFault" />
+ </wsdl:operation>
+
+ </wsdl:portType>
+
+</wsdl:definitions> \ No newline at end of file
diff --git a/java/management/client/src/main/java/wsdl/WS-ResourceProperties-1_2.xsd b/java/management/client/src/main/java/wsdl/WS-ResourceProperties-1_2.xsd
new file mode 100644
index 0000000000..c408b36db1
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/WS-ResourceProperties-1_2.xsd
@@ -0,0 +1,394 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+OASIS takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any effort to identify any such rights. Information on OASIS's procedures with respect to rights in OASIS specifications can be found at the OASIS website. Copies of claims of rights made available for publication and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementors or users of this specification, can be obtained from the OASIS Executive Director.
+
+OASIS invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may cover technology that may be required to implement this specification. Please address the information to the OASIS Executive Director.
+
+Copyright (C) OASIS Open (2005). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to OASIS, except as needed for the purpose of developing OASIS specifications, in which case the procedures for copyrights defined in the OASIS Intellectual Property Rights document must be followed, or as required to translate it into languages other than English.
+
+The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.
+
+This document and the information contained herein is provided on an "AS IS" basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+-->
+<xsd:schema
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2"
+ xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
+ elementFormDefault="qualified" attributeFormDefault="unqualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/rp-2"
+>
+ <xsd:import
+ namespace="http://docs.oasis-open.org/wsrf/bf-2"
+ schemaLocation="WS-BaseFaults-1_2.xsd"
+ />
+<!-- =============== Resource Property Related =================== -->
+<!-- ====== Resource Properties for QueryResourceProperties ======= -->
+ <xsd:element name="QueryExpressionDialect" type="xsd:anyURI"/>
+
+ <xsd:element name="QueryExpressionRPDocument">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsrf-rp:QueryExpressionDialect"
+ minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+<!-- ======= Global Attribute Declaration for WSDL 1.1 portType==== -->
+ <xsd:attribute name="ResourceProperties" type="xsd:QName" />
+
+<!-- = Notification Message for ResourceProperties value change === -->
+ <xsd:complexType name="ResourcePropertyValueChangeNotificationType">
+ <xsd:sequence>
+ <xsd:element name="OldValues" nillable="true"
+ minOccurs="0" maxOccurs="1" >
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any minOccurs="1" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="NewValues" nillable="true"
+ minOccurs="1" maxOccurs="1" >
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any minOccurs="1" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:element name="ResourcePropertyValueChangeNotification"
+ type="wsrf-rp:ResourcePropertyValueChangeNotificationType" />
+
+ <xsd:complexType name="QueryExpressionType" mixed="true">
+ <xsd:sequence>
+ <xsd:any minOccurs="0" maxOccurs="1" processContents="lax" />
+ </xsd:sequence>
+ <xsd:attribute name="Dialect" type="xsd:anyURI" />
+ </xsd:complexType>
+
+ <xsd:element name="QueryExpression" type="wsrf-rp:QueryExpressionType" />
+
+<!-- ======= Message Types for GetResourcePropertyDocument ======= -->
+
+ <xsd:element name="GetResourcePropertyDocument">
+ <xsd:complexType/>
+ </xsd:element>
+
+ <xsd:element name="GetResourcePropertyDocumentResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any minOccurs="1" maxOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+<!-- ========== Message Types for GetResourceProperty ============ -->
+
+ <xsd:element name="GetResourceProperty"
+ type="xsd:QName" />
+
+ <xsd:element name="GetResourcePropertyResponse" >
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:complexType name="InvalidResourcePropertyQNameFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="InvalidResourcePropertyQNameFault"
+ type="wsrf-rp:InvalidResourcePropertyQNameFaultType"/>
+
+<!-- ====== Message Types for GetMultipleResourceProperties ======= -->
+ <xsd:element name="GetMultipleResourceProperties">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="ResourceProperty" type="xsd:QName"
+ minOccurs="1" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="GetMultipleResourcePropertiesResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+<!-- ========== Message Types for PutResourceProperty ============ -->
+
+ <xsd:element name="PutResourcePropertyDocument">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any minOccurs="1" maxOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="PutResourcePropertyDocumentResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any minOccurs="0" maxOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:complexType name="ResourcePropertyChangeFailureType">
+ <xsd:sequence>
+ <xsd:element name="CurrentValue" minOccurs="0" maxOccurs="1">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any minOccurs="1" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="RequestedValue" minOccurs="0" maxOccurs="1">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any minOccurs="1" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:attribute name="Restored" type="xsd:boolean"/>
+ </xsd:complexType>
+
+ <xsd:complexType
+ name="UnableToPutResourcePropertyDocumentFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element name="ResourcePropertyChangeFailure" type=
+ "wsrf-rp:ResourcePropertyChangeFailureType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="UnableToPutResourcePropertyDocumentFault"
+ type=
+ "wsrf-rp:UnableToPutResourcePropertyDocumentFaultType"/>
+
+<!-- ========= Message Types for SetResourceProperties =========== -->
+
+ <xsd:complexType name="InsertType">
+ <xsd:sequence>
+ <xsd:any processContents="lax"
+ minOccurs="1" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="Insert" type="wsrf-rp:InsertType"/>
+
+ <xsd:complexType name="UpdateType">
+ <xsd:sequence>
+ <xsd:any processContents="lax"
+ minOccurs="1" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:element name="Update" type="wsrf-rp:UpdateType"/>
+
+ <xsd:complexType name="DeleteType">
+ <xsd:attribute name="ResourceProperty"
+ type="xsd:QName" use="required" />
+ </xsd:complexType>
+ <xsd:element name="Delete" type="wsrf-rp:DeleteType"/>
+
+ <xsd:element name="SetResourceProperties">
+ <xsd:complexType>
+ <xsd:choice minOccurs="1" maxOccurs="unbounded">
+ <xsd:element ref="wsrf-rp:Insert"/>
+ <xsd:element ref="wsrf-rp:Update"/>
+ <xsd:element ref="wsrf-rp:Delete"/>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="SetResourcePropertiesResponse" >
+ <xsd:complexType />
+ </xsd:element>
+
+ <xsd:complexType
+ name="InvalidModificationFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element name="ResourcePropertyChangeFailure" type=
+ "wsrf-rp:ResourcePropertyChangeFailureType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name=
+ "InvalidModificationFault"
+ type=
+ "wsrf-rp:InvalidModificationFaultType"/>
+
+ <xsd:complexType name="UnableToModifyResourcePropertyFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element name="ResourcePropertyChangeFailure" type=
+ "wsrf-rp:ResourcePropertyChangeFailureType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="UnableToModifyResourcePropertyFault"
+ type="wsrf-rp:UnableToModifyResourcePropertyFaultType"/>
+
+ <xsd:complexType name="SetResourcePropertyRequestFailedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element name="ResourcePropertyChangeFailure" type=
+ "wsrf-rp:ResourcePropertyChangeFailureType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="SetResourcePropertyRequestFailedFault"
+ type=
+ "wsrf-rp:SetResourcePropertyRequestFailedFaultType"/>
+
+ <xsd:complexType name="InsertResourcePropertiesRequestFailedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element name="ResourcePropertyChangeFailure" type=
+ "wsrf-rp:ResourcePropertyChangeFailureType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="InsertResourcePropertiesRequestFailedFault"
+ type=
+ "wsrf-rp:InsertResourcePropertiesRequestFailedFaultType"/>
+
+ <xsd:complexType name="UpdateResourcePropertiesRequestFailedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element name="ResourcePropertyChangeFailure" type=
+ "wsrf-rp:ResourcePropertyChangeFailureType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="UpdateResourcePropertiesRequestFailedFault"
+ type="wsrf-rp:UpdateResourcePropertiesRequestFailedFaultType"/>
+
+ <xsd:complexType name="DeleteResourcePropertiesRequestFailedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType">
+ <xsd:sequence>
+ <xsd:element name="ResourcePropertyChangeFailure" type=
+ "wsrf-rp:ResourcePropertyChangeFailureType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element
+ name="DeleteResourcePropertiesRequestFailedFault"
+ type="wsrf-rp:DeleteResourcePropertiesRequestFailedFaultType"/>
+
+<!-- ======== Message Types for InsertResourceProperties ========== -->
+ <xsd:element name="InsertResourceProperties">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsrf-rp:Insert"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="InsertResourcePropertiesResponse" >
+ <xsd:complexType />
+ </xsd:element>
+
+<!-- ======== Message Types for UpdateResourceProperties ========== -->
+ <xsd:element name="UpdateResourceProperties">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsrf-rp:Update"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="UpdateResourcePropertiesResponse" >
+ <xsd:complexType />
+ </xsd:element>
+
+<!-- ======== Message Types for DeleteResourceProperties ========== -->
+ <xsd:element name="DeleteResourceProperties">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsrf-rp:Delete"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="DeleteResourcePropertiesResponse" >
+ <xsd:complexType />
+ </xsd:element>
+
+<!-- ========= Message Types for QueryResourceProperties ========== -->
+
+ <xsd:element name="QueryResourceProperties" >
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsrf-rp:QueryExpression"
+ minOccurs="1" maxOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="QueryResourcePropertiesResponse" >
+ <xsd:complexType>
+ <xsd:complexContent mixed="true">
+ <xsd:restriction base="xsd:anyType">
+ <xsd:sequence>
+ <xsd:any processContents="lax"
+ minOccurs="1" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:restriction>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:complexType name="UnknownQueryExpressionDialectFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="UnknownQueryExpressionDialectFault"
+ type="wsrf-rp:UnknownQueryExpressionDialectFaultType"/>
+
+ <xsd:complexType name="InvalidQueryExpressionFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="InvalidQueryExpressionFault"
+ type="wsrf-rp:InvalidQueryExpressionFaultType"/>
+
+ <xsd:complexType name="QueryEvaluationErrorFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="QueryEvaluationErrorFault"
+ type="wsrf-rp:QueryEvaluationErrorFaultType"/>
+
+</xsd:schema> \ No newline at end of file
diff --git a/java/management/client/src/main/java/wsdl/WS-ServiceGroup-1_2.wsdl b/java/management/client/src/main/java/wsdl/WS-ServiceGroup-1_2.wsdl
new file mode 100644
index 0000000000..a75cd59728
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/WS-ServiceGroup-1_2.wsdl
@@ -0,0 +1,269 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<wsdl:definitions
+ targetNamespace="http://docs.oasis-open.org/wsrf/sgw-2"
+ xmlns:tns="http://docs.oasis-open.org/wsrf/sgw-2"
+ xmlns:wsrf-sg="http://docs.oasis-open.org/wsrf/sg-2"
+ xmlns:wsrf-sgw="http://docs.oasis-open.org/wsrf/sgw-2"
+ xmlns="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:wsdl-soap="http://schemas.xmlsoap.org/wsdl/soap/"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex"
+ xmlns:wsrf-r="http://docs.oasis-open.org/wsrf/r-2"
+ xmlns:wsrf-rl="http://docs.oasis-open.org/wsrf/rl-2"
+ xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2"
+ name="ServiceGroup">
+ <wsdl:types>
+ <xsd:schema
+ elementFormDefault="qualified"
+ targetNamespace="http://schemas.xmlsoap.org/ws/2004/09/mex">
+ <xsd:include schemaLocation="WS-MetadataExchange-2004_09.xsd"/>
+ </xsd:schema>
+ <xsd:schema
+ elementFormDefault="qualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/rp-2">
+ <xsd:include schemaLocation="WS-ResourceProperties-1_2.xsd" />
+ </xsd:schema>
+ <xsd:schema
+ elementFormDefault="qualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/r-2">
+ <xsd:include schemaLocation="WS-Resource-1_2.xsd" />
+ </xsd:schema>
+ <xsd:schema
+ elementFormDefault="qualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/sg-2">
+ <xsd:include schemaLocation="WS-ServiceGroup-1_2.xsd" />
+ </xsd:schema>
+ </wsdl:types>
+ <wsdl:message name="GetMetadataMsg">
+ <wsdl:part name="GetMetadataMsg" element="wsx:GetMetadata" />
+ </wsdl:message>
+ <wsdl:message name="GetMetadataResponseMsg">
+ <wsdl:part name="GetMetadataResponseMsg" element="wsx:Metadata" />
+ </wsdl:message>
+ <wsdl:message name="ResourceUnknownFault">
+ <wsdl:part name="ResourceUnknownFault" element="wsrf-r:ResourceUnknownFault" />
+ </wsdl:message>
+ <wsdl:message name="ResourceUnavailableFault">
+ <wsdl:part name="ResourceUnavailableFault" element="wsrf-r:ResourceUnavailableFault" />
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyDocumentRequest">
+ <wsdl:part name="GetResourcePropertyDocumentRequest" element="wsrf-rp:GetResourcePropertyDocument"/>
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyDocumentResponse">
+ <wsdl:part name="GetResourcePropertyDocumentResponse" element="wsrf-rp:GetResourcePropertyDocumentResponse"/>
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyRequest">
+ <wsdl:part name="GetResourcePropertyRequest" element="wsrf-rp:GetResourceProperty" />
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyResponse">
+ <wsdl:part name="GetResourcePropertyResponse" element="wsrf-rp:GetResourcePropertyResponse" />
+ </wsdl:message>
+ <wsdl:message name="InvalidResourcePropertyQNameFault">
+ <wsdl:part name="InvalidResourcePropertyQNameFault" element="wsrf-rp:InvalidResourcePropertyQNameFault" />
+ </wsdl:message>
+ <wsdl:message name="GetMultipleResourcePropertiesRequest">
+ <wsdl:part name="GetMultipleResourcePropertiesRequest" element="wsrf-rp:GetMultipleResourceProperties" />
+ </wsdl:message>
+ <wsdl:message name="GetMultipleResourcePropertiesResponse">
+ <wsdl:part name="GetMultipleResourcePropertiesResponse" element="wsrf-rp:GetMultipleResourcePropertiesResponse" />
+ </wsdl:message>
+ <wsdl:message name="QueryResourcePropertiesRequest">
+ <wsdl:part name="QueryResourcePropertiesRequest" element="wsrf-rp:QueryResourceProperties" />
+ </wsdl:message>
+ <wsdl:message name="QueryResourcePropertiesResponse">
+ <wsdl:part name="QueryResourcePropertiesResponse" element="wsrf-rp:QueryResourcePropertiesResponse" />
+ </wsdl:message>
+ <wsdl:message name="UnknownQueryExpressionDialectFault">
+ <wsdl:part name="UnknownQueryExpressionDialectFault" element="wsrf-rp:UnknownQueryExpressionDialectFault" />
+ </wsdl:message>
+ <wsdl:message name="InvalidQueryExpressionFault">
+ <wsdl:part name="InvalidQueryExpressionFault" element="wsrf-rp:InvalidQueryExpressionFault" />
+ </wsdl:message>
+ <wsdl:message name="QueryEvaluationErrorFault">
+ <wsdl:part name="QueryEvaluationErrorFault" element="wsrf-rp:QueryEvaluationErrorFault" />
+ </wsdl:message>
+ <wsdl:portType
+ name="ServiceGroupPortType"
+ wsrf-rp:ResourceProperties="wsrf-sg:ServiceGroupRP">
+ <wsdl:operation name="GetMetadata">
+ <wsdl:input wsa:Action="http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata"
+ name="GetMetadataMsg" message="tns:GetMetadataMsg"/>
+ <wsdl:output wsa:Action="http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadataResponse"
+ name="GetMetadataResponseMsg" message="tns:GetMetadataResponseMsg"/>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourcePropertyDocument">
+ <wsdl:input wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourcePropertyDocument/GetResourcePropertyDocumentRequest"
+ name="GetResourcePropertyDocumentRequest" message="tns:GetResourcePropertyDocumentRequest"/>
+ <wsdl:output wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourcePropertyDocument/GetResourcePropertyDocumentResponse"
+ name="GetResourcePropertyDocumentResponse" message="tns:GetResourcePropertyDocumentResponse"/>
+ <wsdl:fault name="ResourceUnknownFault" message="tns:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault" message="tns:ResourceUnavailableFault"/>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourceProperty">
+ <wsdl:input wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest"
+ name="GetResourcePropertyRequest" message="tns:GetResourcePropertyRequest" />
+ <wsdl:output wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse"
+ name="GetResourcePropertyResponse" message="tns:GetResourcePropertyResponse" />
+ <wsdl:fault name="ResourceUnknownFault" message="tns:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault" message="tns:ResourceUnavailableFault"/>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault" message="tns:InvalidResourcePropertyQNameFault" />
+ </wsdl:operation>
+ <wsdl:operation name="GetMultipleResourceProperties">
+ <wsdl:input wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetMultipleResourceProperties/GetMultipleResourcePropertiesRequest"
+ name="GetMultipleResourcePropertiesRequest" message="tns:GetMultipleResourcePropertiesRequest" />
+ <wsdl:output wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetMultipleResourceProperties/GetMultipleResourcePropertiesResponse"
+ name="GetMultipleResourcePropertiesResponse" message="tns:GetMultipleResourcePropertiesResponse" />
+ <wsdl:fault name="ResourceUnknownFault" message="tns:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault" message="tns:ResourceUnavailableFault"/>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault" message="tns:InvalidResourcePropertyQNameFault" />
+ </wsdl:operation>
+ <wsdl:operation name="QueryResourceProperties">
+ <wsdl:input wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/QueryResourceProperties/QueryResourcePropertiesRequest"
+ name="QueryResourcePropertiesRequest" message="tns:QueryResourcePropertiesRequest" />
+ <wsdl:output wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/QueryResourceProperties/QueryResourcePropertiesResponse"
+ name="QueryResourcePropertiesResponse" message="tns:QueryResourcePropertiesResponse" />
+ <wsdl:fault name="ResourceUnknownFault" message="tns:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault" message="tns:ResourceUnavailableFault"/>
+ <wsdl:fault name="UnknownQueryExpressionDialectFault" message="tns:UnknownQueryExpressionDialectFault"/>
+ <wsdl:fault name="InvalidQueryExpressionFault" message="tns:InvalidQueryExpressionFault"/>
+ <wsdl:fault name="QueryEvaluationErrorFault" message="tns:QueryEvaluationErrorFault" />
+ </wsdl:operation>
+ </wsdl:portType>
+ <wsdl:binding name="ServiceGroupBinding" type="tns:ServiceGroupPortType">
+ <wsdl-soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
+ <wsdl:operation name="GetMetadata">
+ <wsdl-soap:operation soapAction="GetMetadata" />
+ <wsdl:input>
+ <wsdl-soap:body
+ use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body
+ use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourcePropertyDocument">
+ <wsdl-soap:operation soapAction="GetResourcePropertyDocument"/>
+ <wsdl:input name="GetResourcePropertyDocumentRequest">
+ <wsdl-soap:body
+ use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:input><wsdl:output name="GetResourcePropertyDocumentResponse">
+ <wsdl-soap:body
+ use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="ResourceUnknownFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="ResourceUnavailableFault"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourceProperty">
+ <wsdl-soap:operation soapAction="GetResourceProperty"/>
+ <wsdl:input name="GetResourcePropertyRequest">
+ <wsdl-soap:body
+ use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:input><wsdl:output name="GetResourcePropertyResponse">
+ <wsdl-soap:body
+ use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="ResourceUnknownFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="ResourceUnavailableFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="InvalidResourcePropertyQNameFault"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="GetMultipleResourceProperties">
+ <wsdl-soap:operation soapAction="GetMultipleResourceProperties"/>
+ <wsdl:input name="GetMultipleResourcePropertiesRequest">
+ <wsdl-soap:body
+ use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:input><wsdl:output name="GetMultipleResourcePropertiesResponse">
+ <wsdl-soap:body
+ use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="ResourceUnknownFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="ResourceUnavailableFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="InvalidResourcePropertyQNameFault"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="QueryResourceProperties">
+ <wsdl-soap:operation soapAction="QueryResourceProperties"/>
+ <wsdl:input name="QueryResourcePropertiesRequest">
+ <wsdl-soap:body
+ use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:input><wsdl:output name="QueryResourcePropertiesResponse">
+ <wsdl-soap:body
+ use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="ResourceUnknownFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="ResourceUnavailableFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="UnknownQueryExpressionDialectFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="UnknownQueryExpressionDialectFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidQueryExpressionFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="InvalidQueryExpressionFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="QueryEvaluationErrorFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="QueryEvaluationErrorFault"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ </wsdl:binding>
+ <wsdl:service name="ServiceGroupService">
+ <wsdl:port name="ServiceGroupPort" binding="tns:ServiceGroupBinding">
+ <wsdl-soap:address location="http://localhost:8080/wsrf/services/ServiceGroup"/>
+ </wsdl:port>
+ </wsdl:service>
+</wsdl:definitions>
diff --git a/java/management/client/src/main/java/wsdl/WS-ServiceGroup-1_2.xsd b/java/management/client/src/main/java/wsdl/WS-ServiceGroup-1_2.xsd
new file mode 100644
index 0000000000..87238f90e5
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/WS-ServiceGroup-1_2.xsd
@@ -0,0 +1,233 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+OASIS takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any effort to identify any such rights. Information on OASIS's procedures with respect to rights in OASIS specifications can be found at the OASIS website. Copies of claims of rights made available for publication and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementors or users of this specification, can be obtained from the OASIS Executive Director.
+
+OASIS invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may cover technology that may be required to implement this specification. Please address the information to the OASIS Executive Director.
+
+Copyright (C) OASIS Open (2005). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to OASIS, except as needed for the purpose of developing OASIS specifications, in which case the procedures for copyrights defined in the OASIS Intellectual Property Rights document must be followed, or as required to translate it into languages other than English.
+
+The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.
+
+This document and the information contained herein is provided on an "AS IS" basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+-->
+<xsd:schema
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2"
+ xmlns:wsrf-sg="http://docs.oasis-open.org/wsrf/sg-2"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/sg-2" >
+<!-- ======================== Imports ============================ -->
+
+ <xsd:import
+ namespace="http://www.w3.org/2005/08/addressing"
+ schemaLocation="WS-Addressing-2005_08.xsd"/>
+ <xsd:import
+ namespace="http://docs.oasis-open.org/wsrf/bf-2"
+ schemaLocation="WS-BaseFaults-1_2.xsd" />
+ <xsd:import
+ namespace="http://docs.oasis-open.org/wsrf/rp-2"
+ schemaLocation="WS-ResourceProperties-1_2.xsd" />
+
+<!-- =============== Resource Property Related =================== -->
+<!-- ============ Resource Properties for ServiceGroup ============ -->
+ <xsd:simpleType name="AbsoluteOrRelativeTimeType">
+ <xsd:union memberTypes="xsd:dateTime xsd:duration"/>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="ContentElementsType">
+ <xsd:list itemType="xsd:QName"/>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="MemberInterfacesType">
+ <xsd:list itemType="xsd:QName"/>
+ </xsd:simpleType>
+
+ <xsd:element name="MembershipContentRule">
+ <xsd:complexType>
+ <xsd:attribute name="MemberInterfaces"
+ type="wsrf-sg:MemberInterfacesType"/>
+ <xsd:attribute name="ContentElements"
+ type="wsrf-sg:ContentElementsType"
+ use="required"/>
+ <xsd:anyAttribute namespace="##other"
+ processContents="lax"/>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:complexType name="RPDocType">
+ <xsd:sequence>
+ <xsd:any namespace="##any" processContents="lax"
+ minOccurs="1" maxOccurs="1" />
+ </xsd:sequence>
+ <xsd:anyAttribute namespace="##other"
+ processContents="lax"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="ContentType">
+ <xsd:sequence>
+ <xsd:element name="RPDoc"
+ type="wsrf-sg:RPDocType"
+ minOccurs="0" maxOccurs="1" />
+ </xsd:sequence>
+ <xsd:anyAttribute namespace="##other"
+ processContents="lax"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="EntryType">
+ <xsd:sequence>
+ <xsd:element name="ServiceGroupEntryEPR"
+ type="wsa:EndpointReferenceType"
+ minOccurs="1" maxOccurs="1"
+ nillable="true"/>
+ <xsd:element name="MemberServiceEPR"
+ type="wsa:EndpointReferenceType"
+ minOccurs="0" maxOccurs="1"/>
+ <xsd:element ref="wsrf-sg:Content"
+ minOccurs="0" maxOccurs="1"/>
+ </xsd:sequence>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+
+<!-- ========== Resource Properties for ServiceGroupEntry ========= -->
+
+ <xsd:element name="Entry"
+ type="wsrf-sg:EntryType"/>
+
+ <xsd:element name="Content"
+ type="wsrf-sg:ContentType"/>
+
+ <xsd:element name="MemberEPR"
+ type="wsa:EndpointReferenceType"/>
+
+ <xsd:element name="ServiceGroupEPR"
+ type="wsa:EndpointReferenceType"/>
+
+<!-- =============== Resource Property Related =================== -->
+<!-- ============ Resource Properties for ServiceGroup ============ -->
+ <xsd:element name="ServiceGroupRP">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsrf-rp:QueryExpressionDialect"
+ minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element ref="wsrf-sg:MembershipContentRule"
+ minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element ref="wsrf-sg:Entry"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+<!-- ========== Resource Properties for ServiceGroupEntry ========= -->
+ <xsd:element name="ServiceGroupEntryRP">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element ref="wsrf-sg:ServiceGroupEPR"
+ minOccurs="1" maxOccurs="1"/>
+ <xsd:element ref="wsrf-sg:MemberEPR"
+ minOccurs="0" maxOccurs="1"/>
+ <xsd:element ref="wsrf-sg:Content"
+ minOccurs="0" maxOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+<!-- ================= Message Specific Types ==================== -->
+<!-- ======== Message Types for ServiceGroupRegistration ========= -->
+ <xsd:element name="Add">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="MemberEPR"
+ type="wsa:EndpointReferenceType" />
+ <xsd:element ref="wsrf-sg:Content" />
+ <xsd:element name="InitialTerminationTime"
+ type="wsrf-sg:AbsoluteOrRelativeTimeType"
+ minOccurs="0" maxOccurs="1" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="AddResponse">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="ServiceGroupEntryReference"
+ type="wsa:EndpointReferenceType"
+ minOccurs="1" maxOccurs="1" />
+ <xsd:element name="TerminationTime"
+ nillable="true"
+ type="xsd:dateTime"
+ minOccurs="1" maxOccurs="1" />
+ <xsd:element name="CurrentTime"
+ type="xsd:dateTime"
+ minOccurs="1" maxOccurs="1" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:complexType name="ContentCreationFailedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="ContentCreationFailedFault"
+ type="wsrf-sg:ContentCreationFailedFaultType"/>
+
+ <xsd:complexType name="UnsupportedMemberInterfaceFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="UnsupportedMemberInterfaceFault"
+ type="wsrf-sg:UnsupportedMemberInterfaceFaultType"/>
+
+ <xsd:complexType name="AddRefusedFaultType">
+ <xsd:complexContent>
+ <xsd:extension base="wsrf-bf:BaseFaultType"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ <xsd:element name="AddRefusedFault"
+ type="wsrf-sg:AddRefusedFaultType"/>
+
+<!-- = Messages Related to ServiceGroup Change Notification ======= -->
+ <xsd:complexType name="ServiceGroupModificationNotificationType">
+ <xsd:sequence>
+ <xsd:element name="ServiceGroupEntryEPR"
+ type="wsa:EndpointReferenceType"
+ minOccurs="1" maxOccurs="1"
+ nillable="true"/>
+ <xsd:element name="MemberServiceEPR"
+ type="wsa:EndpointReferenceType"
+ minOccurs="0" maxOccurs="1"/>
+ <xsd:element ref="wsrf-sg:Content"
+ minOccurs="0" maxOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="ServiceGroupRemovalNotificationType">
+ <xsd:complexContent>
+ <xsd:extension
+ base="wsrf-sg:ServiceGroupModificationNotificationType">
+ <xsd:sequence>
+ <xsd:element name="Reason"
+ type="xsd:string"
+ minOccurs="0" maxOccurs="1"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:element name="EntryAdditionNotification"
+ type="wsrf-sg:ServiceGroupModificationNotificationType" />
+
+ <xsd:element name="EntryRemovalNotification"
+ type="wsrf-sg:ServiceGroupRemovalNotificationType" />
+
+</xsd:schema>
diff --git a/java/management/client/src/main/java/wsdl/WS-ServiceGroupEntry-1_2.wsdl b/java/management/client/src/main/java/wsdl/WS-ServiceGroupEntry-1_2.wsdl
new file mode 100644
index 0000000000..379382c18d
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/WS-ServiceGroupEntry-1_2.wsdl
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<wsdl:definitions
+ targetNamespace="http://docs.oasis-open.org/wsrf/sgw-2"
+ xmlns:tns="http://docs.oasis-open.org/wsrf/sgw-2"
+ xmlns:wsrf-sg="http://docs.oasis-open.org/wsrf/sg-2"
+ xmlns:wsrf-sgw="http://docs.oasis-open.org/wsrf/sgw-2"
+ xmlns="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:wsdl-soap="http://schemas.xmlsoap.org/wsdl/soap/"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex"
+ xmlns:wsrf-r="http://docs.oasis-open.org/wsrf/r-2"
+ xmlns:wsrf-rl="http://docs.oasis-open.org/wsrf/rl-2"
+ xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
+ xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2"
+ name="ServiceGroupEntry">
+ <wsdl:types>
+ <xsd:schema
+ elementFormDefault="qualified"
+ targetNamespace="http://schemas.xmlsoap.org/ws/2004/09/mex">
+ <xsd:include schemaLocation="WS-MetadataExchange-2004_09.xsd"/>
+ </xsd:schema>
+ <xsd:schema
+ elementFormDefault="qualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/rp-2">
+ <xsd:include schemaLocation="WS-ResourceProperties-1_2.xsd" />
+ </xsd:schema>
+ <xsd:schema
+ elementFormDefault="qualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/r-2">
+ <xsd:include schemaLocation="WS-Resource-1_2.xsd" />
+ </xsd:schema>
+ <xsd:schema
+ elementFormDefault="qualified"
+ targetNamespace="http://docs.oasis-open.org/wsrf/sg-2">
+ <xsd:include schemaLocation="WS-ServiceGroup-1_2.xsd" />
+ </xsd:schema>
+ </wsdl:types>
+ <wsdl:message name="GetMetadataMsg">
+ <wsdl:part name="GetMetadataMsg" element="wsx:GetMetadata" />
+ </wsdl:message>
+ <wsdl:message name="GetMetadataResponseMsg">
+ <wsdl:part name="GetMetadataResponseMsg" element="wsx:Metadata" />
+ </wsdl:message>
+ <wsdl:message name="ResourceUnknownFault">
+ <wsdl:part name="ResourceUnknownFault" element="wsrf-r:ResourceUnknownFault" />
+ </wsdl:message>
+ <wsdl:message name="ResourceUnavailableFault">
+ <wsdl:part name="ResourceUnavailableFault" element="wsrf-r:ResourceUnavailableFault" />
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyDocumentRequest">
+ <wsdl:part name="GetResourcePropertyDocumentRequest" element="wsrf-rp:GetResourcePropertyDocument"/>
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyDocumentResponse">
+ <wsdl:part name="GetResourcePropertyDocumentResponse" element="wsrf-rp:GetResourcePropertyDocumentResponse"/>
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyRequest">
+ <wsdl:part name="GetResourcePropertyRequest" element="wsrf-rp:GetResourceProperty" />
+ </wsdl:message>
+ <wsdl:message name="GetResourcePropertyResponse">
+ <wsdl:part name="GetResourcePropertyResponse" element="wsrf-rp:GetResourcePropertyResponse" />
+ </wsdl:message>
+ <wsdl:message name="InvalidResourcePropertyQNameFault">
+ <wsdl:part name="InvalidResourcePropertyQNameFault" element="wsrf-rp:InvalidResourcePropertyQNameFault" />
+ </wsdl:message>
+ <wsdl:message name="GetMultipleResourcePropertiesRequest">
+ <wsdl:part name="GetMultipleResourcePropertiesRequest" element="wsrf-rp:GetMultipleResourceProperties" />
+ </wsdl:message>
+ <wsdl:message name="GetMultipleResourcePropertiesResponse">
+ <wsdl:part name="GetMultipleResourcePropertiesResponse" element="wsrf-rp:GetMultipleResourcePropertiesResponse" />
+ </wsdl:message>
+ <wsdl:portType
+ name="ServiceGroupEntryPortType"
+ wsrf-rp:ResourceProperties="wsrf-sg:ServiceGroupEntryRP">
+ <wsdl:operation name="GetMetadata">
+ <wsdl:input wsa:Action="http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata"
+ name="GetMetadataMsg" message="tns:GetMetadataMsg"/>
+ <wsdl:output wsa:Action="http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadataResponse"
+ name="GetMetadataResponseMsg" message="tns:GetMetadataResponseMsg"/>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourcePropertyDocument">
+ <wsdl:input wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourcePropertyDocument/GetResourcePropertyDocumentRequest"
+ name="GetResourcePropertyDocumentRequest" message="tns:GetResourcePropertyDocumentRequest"/>
+ <wsdl:output wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourcePropertyDocument/GetResourcePropertyDocumentResponse"
+ name="GetResourcePropertyDocumentResponse" message="tns:GetResourcePropertyDocumentResponse"/>
+ <wsdl:fault name="ResourceUnknownFault" message="tns:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault" message="tns:ResourceUnavailableFault"/>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourceProperty">
+ <wsdl:input wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyRequest"
+ name="GetResourcePropertyRequest" message="tns:GetResourcePropertyRequest" />
+ <wsdl:output wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse"
+ name="GetResourcePropertyResponse" message="tns:GetResourcePropertyResponse" />
+ <wsdl:fault name="ResourceUnknownFault" message="tns:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault" message="tns:ResourceUnavailableFault"/>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault" message="tns:InvalidResourcePropertyQNameFault" />
+ </wsdl:operation>
+ <wsdl:operation name="GetMultipleResourceProperties">
+ <wsdl:input wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetMultipleResourceProperties/GetMultipleResourcePropertiesRequest"
+ name="GetMultipleResourcePropertiesRequest" message="tns:GetMultipleResourcePropertiesRequest" />
+ <wsdl:output wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/GetMultipleResourceProperties/GetMultipleResourcePropertiesResponse"
+ name="GetMultipleResourcePropertiesResponse" message="tns:GetMultipleResourcePropertiesResponse" />
+ <wsdl:fault name="ResourceUnknownFault" message="tns:ResourceUnknownFault"/>
+ <wsdl:fault name="ResourceUnavailableFault" message="tns:ResourceUnavailableFault"/>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault" message="tns:InvalidResourcePropertyQNameFault" />
+ </wsdl:operation>
+ </wsdl:portType>
+ <wsdl:binding name="ServiceGroupEntryBinding" type="tns:ServiceGroupEntryPortType">
+ <wsdl-soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
+ <wsdl:operation name="GetMetadata">
+ <wsdl-soap:operation soapAction="GetMetadata" />
+ <wsdl:input>
+ <wsdl-soap:body
+ use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
+ </wsdl:input>
+ <wsdl:output>
+ <wsdl-soap:body
+ use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourcePropertyDocument">
+ <wsdl-soap:operation soapAction="GetResourcePropertyDocument"/>
+ <wsdl:input name="GetResourcePropertyDocumentRequest">
+ <wsdl-soap:body
+ use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:input><wsdl:output name="GetResourcePropertyDocumentResponse">
+ <wsdl-soap:body
+ use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="ResourceUnknownFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="ResourceUnavailableFault"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="GetResourceProperty">
+ <wsdl-soap:operation soapAction="GetResourceProperty"/>
+ <wsdl:input name="GetResourcePropertyRequest">
+ <wsdl-soap:body
+ use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:input><wsdl:output name="GetResourcePropertyResponse">
+ <wsdl-soap:body
+ use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="ResourceUnknownFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="ResourceUnavailableFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="InvalidResourcePropertyQNameFault"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ <wsdl:operation name="GetMultipleResourceProperties">
+ <wsdl-soap:operation soapAction="GetMultipleResourceProperties"/>
+ <wsdl:input name="GetMultipleResourcePropertiesRequest">
+ <wsdl-soap:body
+ use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:input><wsdl:output name="GetMultipleResourcePropertiesResponse">
+ <wsdl-soap:body
+ use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </wsdl:output>
+ <wsdl:fault name="ResourceUnknownFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="ResourceUnknownFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="ResourceUnavailableFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="ResourceUnavailableFault"/>
+ </wsdl:fault>
+ <wsdl:fault name="InvalidResourcePropertyQNameFault">
+ <wsdl-soap:fault
+ use="encoded"
+ name="InvalidResourcePropertyQNameFault"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ </wsdl:binding>
+ <wsdl:service name="ServiceGroupEntryService">
+ <wsdl:port name="ServiceGroupEntryPort" binding="tns:ServiceGroupEntryBinding">
+ <wsdl-soap:address location="http://localhost:8080/wsrf/services/ServiceGroupEntry"/>
+ </wsdl:port>
+ </wsdl:service>
+</wsdl:definitions>
diff --git a/java/management/client/src/main/java/wsdl/WS-Topics-1_3.xsd b/java/management/client/src/main/java/wsdl/WS-Topics-1_3.xsd
new file mode 100644
index 0000000000..df98513131
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/WS-Topics-1_3.xsd
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+OASIS takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any effort to identify any such rights. Information on OASIS's procedures with respect to rights in OASIS specifications can be found at the OASIS website. Copies of claims of rights made available for publication and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementors or users of this specification, can be obtained from the OASIS Executive Director.
+
+OASIS invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may cover technology that may be required to implement this specification. Please address the information to the OASIS Executive Director.
+
+Copyright (C) OASIS Open (2004-2005). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to OASIS, except as needed for the purpose of developing OASIS specifications, in which case the procedures for copyrights defined in the OASIS Intellectual Property Rights document must be followed, or as required to translate it into languages other than English.
+
+The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.
+
+This document and the information contained herein is provided on an "AS IS" basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+-->
+
+
+<xsd:schema
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:wstop = "http://docs.oasis-open.org/wsn/t-1"
+ targetNamespace = "http://docs.oasis-open.org/wsn/t-1"
+ elementFormDefault="qualified" attributeFormDefault="unqualified">
+
+<!-- =============== utility type definitions ==================== -->
+ <xsd:complexType name="Documentation" mixed="true">
+ <xsd:sequence>
+ <xsd:any processContents="lax" minOccurs="0"
+ maxOccurs="unbounded" namespace="##any"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="ExtensibleDocumented" abstract="true"
+ mixed="false">
+ <xsd:sequence>
+ <xsd:element name="documentation" type="wstop:Documentation"
+ minOccurs="0" />
+ </xsd:sequence>
+ <xsd:anyAttribute namespace="##other" processContents="lax" />
+</xsd:complexType>
+
+<xsd:complexType name="QueryExpressionType" mixed="true">
+ <xsd:sequence>
+ <xsd:any minOccurs="0" maxOccurs="1" processContents="lax" />
+ </xsd:sequence>
+ <xsd:attribute name="Dialect" type="xsd:anyURI" use="required"/>
+</xsd:complexType>
+
+<!-- ================== Topic-Namespace Related ================ -->
+ <xsd:complexType name="TopicNamespaceType">
+ <xsd:complexContent>
+ <xsd:extension base="wstop:ExtensibleDocumented">
+ <xsd:sequence>
+ <xsd:element name="Topic"
+ minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="wstop:TopicType">
+ <xsd:attribute name="parent" type="wstop:ConcreteTopicExpression" />
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:any namespace="##other"
+ minOccurs="0" maxOccurs="unbounded"
+ processContents="lax"/>
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:NCName"/>
+ <xsd:attribute name="targetNamespace" type="xsd:anyURI"
+ use="required"/>
+ <xsd:attribute name="final" type="xsd:boolean"
+ default="false"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:element name="TopicNamespace" type="wstop:TopicNamespaceType">
+ <xsd:unique name="rootTopicUniqueness">
+ <xsd:selector xpath="wstop:Topic"/>
+ <xsd:field xpath="@name"/>
+ </xsd:unique>
+ </xsd:element>
+
+ <xsd:attribute name="topicNamespaceLocation" type="xsd:anyURI"/>
+
+
+
+<!-- ===================== Topic Related ========================= -->
+
+ <xsd:complexType name="TopicType">
+ <xsd:complexContent>
+ <xsd:extension base="wstop:ExtensibleDocumented">
+ <xsd:sequence>
+ <xsd:element name="MessagePattern"
+ type="wstop:QueryExpressionType"
+ minOccurs="0" maxOccurs="1" />
+ <xsd:element name="Topic" type="wstop:TopicType"
+ minOccurs="0" maxOccurs="unbounded">
+ <xsd:unique name="childTopicUniqueness">
+ <xsd:selector xpath="wstop:topic"/>
+ <xsd:field xpath="@name"/>
+ </xsd:unique>
+ </xsd:element>
+ <xsd:any namespace="##other" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:NCName"/>
+ <xsd:attribute name="messageTypes">
+ <xsd:simpleType>
+ <xsd:list itemType="xsd:QName"/>
+ </xsd:simpleType>
+ </xsd:attribute>
+ <xsd:attribute name="final" type="xsd:boolean"
+ default="false"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+<!-- ================ Topic Set Related =================== -->
+
+ <xsd:complexType name="TopicSetType">
+ <xsd:complexContent>
+ <xsd:extension base="wstop:ExtensibleDocumented">
+ <xsd:sequence>
+ <xsd:any namespace="##other"
+ minOccurs="0" maxOccurs="unbounded"
+ processContents="lax"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:element name="TopicSet" type="wstop:TopicSetType"/>
+<xsd:attribute name="topic" type="xsd:boolean" default="false"/>
+
+<!-- ================ Topic Expression Related =================== -->
+
+ <xsd:simpleType name="FullTopicExpression">
+ <xsd:restriction base="xsd:token">
+ <xsd:annotation>
+ <xsd:documentation>
+ TopicPathExpression ::= TopicPath ( '|' TopicPath )*
+ TopicPath ::= RootTopic ChildTopicExpression*
+ RootTopic ::= NamespacePrefix? ('//')? (NCName | '*')
+ NamespacePrefix ::= NCName ':'
+ ChildTopicExpression ::= '/' '/'? (QName | NCName | '*'| '.')
+
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:pattern value=
+ "([\i-[:]][\c-[:]]*:)?(//)?([\i-[:]][\c-[:]]*|\*)((/|//)(([\i-[:]][\c-[:]]*:)?[\i-[:]][\c-[:]]*|\*|[.]))*(\|([\i-[:]][\c-[:]]*:)?(//)?([\i-[:]][\c-[:]]*|\*)((/|//)(([\i-[:]][\c-[:]]*:)?[\i-[:]][\c-[:]]*|\*|[.]))*)*">
+ </xsd:pattern>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="ConcreteTopicExpression">
+ <xsd:restriction base="xsd:token">
+ <xsd:annotation>
+ <xsd:documentation>
+ The pattern allows strings matching the following EBNF:
+ ConcreteTopicPath ::= RootTopic ChildTopic*
+ RootTopic ::= QName
+ ChildTopic ::= '/' (QName | NCName)
+
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:pattern value=
+"(([\i-[:]][\c-[:]]*:)?[\i-[:]][\c-[:]]*)(/([\i-[:]][\c-[:]]*:)?[\i-[:]][\c-[:]]*)*" >
+ </xsd:pattern>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="SimpleTopicExpression">
+ <xsd:restriction base="xsd:QName">
+ <xsd:annotation>
+ <xsd:documentation>
+ The pattern allows strings matching the following EBNF:
+ RootTopic ::= QName
+
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+</xsd:schema> \ No newline at end of file
diff --git a/java/management/client/src/main/java/wsdl/WSDM-MUWS-Part1-1_1.xsd b/java/management/client/src/main/java/wsdl/WSDM-MUWS-Part1-1_1.xsd
new file mode 100644
index 0000000000..dd74c23681
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/WSDM-MUWS-Part1-1_1.xsd
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xs:schema
+ targetNamespace="http://docs.oasis-open.org/wsdm/muws1-2.xsd"
+ xmlns:muws1="http://docs.oasis-open.org/wsdm/muws1-2.xsd"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified" attributeFormDefault="unqualified">
+
+ <xs:import namespace="http://www.w3.org/2005/08/addressing"
+ schemaLocation="WS-Addressing-2005_08.xsd"/>
+
+
+ <xs:element name="ResourceId" type="xs:anyURI"/>
+ <xs:element name="ManageabilityCapability" type="xs:anyURI"/>
+
+
+ <xs:complexType name="CorrelatablePropertiesType">
+ <xs:sequence>
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ <xs:attribute name="Dialect" type="xs:anyURI"/>
+ <xs:attribute name="NegativeAssertionPossible" type="xs:boolean"/>
+ <xs:anyAttribute namespace="##other"/>
+ </xs:complexType>
+
+ <xs:element name="CorrelatableProperties"
+ type="muws1:CorrelatablePropertiesType"/>
+
+
+ <xs:complexType name="ComponentAddressType">
+ <xs:sequence>
+ <xs:any namespace="##any" processContents="lax"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="ComponentType">
+ <xs:sequence>
+ <xs:element name="ResourceId" type="xs:anyURI"
+ minOccurs="0"/>
+ <xs:element name="ComponentAddress"
+ type="muws1:ComponentAddressType"
+ minOccurs="0" maxOccurs="unbounded"/>
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other"/>
+ </xs:complexType>
+
+
+ <xs:complexType name="ManagementEventType">
+ <xs:sequence>
+ <xs:element name="EventId" type="xs:anyURI"/>
+ <xs:element name="SourceComponent" type="muws1:ComponentType"/>
+ <xs:element name="ReporterComponent" type="muws1:ComponentType"
+ minOccurs="0"/>
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ <xs:attribute name="ReportTime" type="xs:dateTime" use="optional"/>
+ <xs:anyAttribute namespace="##other"/>
+ </xs:complexType>
+
+ <xs:element name="ManagementEvent"
+ type="muws1:ManagementEventType"/>
+
+ <xs:element name="ManageabilityEndpointReference"
+ type="wsa:EndpointReferenceType"/>
+
+
+<!--
+ SCHEMA COPY Material
+Copy and paste element references below into the schema of a resource properties document.
+These references are provide to insure that the correct minOccurs/maxOccurs attributes are specified in a resource property document schema.
+
+NOTE: You must import the MUWS Part 1 schema namespace (MUWS1).
+
+ ** Identity Properties **
+ <xs:element ref="muws1:ResourceId"/>
+
+
+ ** ManageabilityCharacteristics Properties **
+ <xs:element ref="muws1:ManageabilityCapability"
+ minOccurs="0" maxOccurs="unbounded"/>
+
+ ** Correlatable Properties **
+ <xs:element ref="muws1:CorrelatableProperties"
+ minOccurs="0" maxOccurs="unbounded"/>
+
+-->
+
+</xs:schema>
+
diff --git a/java/management/client/src/main/java/wsdl/WSDM-MUWS-Part2-1_1.xsd b/java/management/client/src/main/java/wsdl/WSDM-MUWS-Part2-1_1.xsd
new file mode 100644
index 0000000000..51233a0989
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/WSDM-MUWS-Part2-1_1.xsd
@@ -0,0 +1,656 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<xs:schema targetNamespace="http://docs.oasis-open.org/wsdm/muws2-2.xsd"
+ xmlns:muws2="http://docs.oasis-open.org/wsdm/muws2-2.xsd"
+ xmlns:muws1="http://docs.oasis-open.org/wsdm/muws1-2.xsd"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified" attributeFormDefault="unqualified">
+ <xs:import namespace="http://docs.oasis-open.org/wsdm/muws1-2.xsd"
+ schemaLocation="WSDM-MUWS-Part1-1_1.xsd" />
+ <xs:import namespace="http://www.w3.org/2005/08/addressing"
+ schemaLocation="WS-Addressing-2005_08.xsd" />
+ <xs:import namespace="http://www.w3.org/XML/1998/namespace"
+ schemaLocation="XML-Namespace-1998.xsd" />
+ <xs:complexType name="LangString">
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute ref="xml:lang" use="required" />
+ <xs:anyAttribute namespace="##other" />
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!-- Begin properties for the Description capability -->
+ <xs:element name="Caption" type="muws2:LangString" />
+ <xs:element name="Description" type="muws2:LangString" />
+ <xs:element name="Version" type="xs:string" />
+ <!-- End properties for the Description capability -->
+ <xs:complexType name="CategoryType">
+ <xs:sequence>
+ <xs:any minOccurs="0" namespace="##any"
+ processContents="lax" />
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="StateType">
+ <xs:complexContent>
+ <xs:extension base="muws2:CategoryType" />
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:element name="State" type="muws2:StateType" />
+ <xs:element name="EnteredState" type="muws2:StateType" />
+ <xs:element name="PreviousState" type="muws2:StateType" />
+ <xs:complexType name="StateTransitionType">
+ <xs:sequence>
+ <xs:element ref="muws2:EnteredState" />
+ <xs:element ref="muws2:PreviousState" minOccurs="0" />
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax" />
+ </xs:sequence>
+ <xs:attribute name="TransitionIdentifier" type="xs:anyURI"
+ use="optional" />
+ <xs:attribute name="Time" type="xs:dateTime" use="required" />
+ <xs:anyAttribute namespace="##other" />
+ </xs:complexType>
+ <xs:element name="StateTransition" type="muws2:StateTransitionType" />
+ <!-- Begin properties for the OperationalStatus capability -->
+ <xs:element name="OperationalStatus">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="Available" />
+ <xs:enumeration value="PartiallyAvailable" />
+ <xs:enumeration value="Unavailable" />
+ <xs:enumeration value="Unknown" />
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <!-- End properties for the OperationalStatus capability -->
+ <xs:attributeGroup name="MetricAttributes">
+ <xs:attribute name="ResetAt" type="xs:dateTime" />
+ <xs:attribute name="LastUpdated" type="xs:dateTime" />
+ <xs:attribute name="Duration" type="xs:duration" />
+ </xs:attributeGroup>
+ <!-- Begin properties for the Metrics capability -->
+ <xs:element name="CurrentTime" type="xs:dateTime" />
+ <!-- End properties for the Metrics capability -->
+ <xs:complexType name="RelationshipTypeType">
+ <xs:complexContent>
+ <xs:extension base="muws2:CategoryType" />
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:element name="Self">
+ <xs:complexType />
+ </xs:element>
+ <xs:complexType name="RelationshipParticipantType">
+ <xs:sequence>
+ <xs:element ref="muws2:Self" minOccurs="0" />
+ <xs:element ref="muws1:ManageabilityEndpointReference"
+ minOccurs="0" maxOccurs="unbounded" />
+ <xs:element ref="wsa:EndpointReference" minOccurs="0"
+ maxOccurs="unbounded" />
+ <xs:element ref="muws1:ResourceId" minOccurs="0" />
+ <xs:element name="Role" type="xs:anyURI" />
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax" />
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" />
+ </xs:complexType>
+ <!-- Begin properties for the RelationshipResource capability -->
+ <xs:element name="Name" type="xs:string" />
+ <xs:element name="Type" type="muws2:RelationshipTypeType" />
+ <xs:element name="Participant"
+ type="muws2:RelationshipParticipantType" />
+ <!-- End properties for the RelationshipResource capability -->
+ <xs:complexType name="RelationshipType">
+ <xs:sequence>
+ <xs:element ref="muws2:Name" minOccurs="0" />
+ <xs:element ref="muws2:Type" />
+ <xs:element ref="muws2:Participant" minOccurs="2"
+ maxOccurs="unbounded" />
+ <xs:element name="AccessEndpointReference"
+ type="wsa:EndpointReferenceType" minOccurs="0" />
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax" />
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" />
+ </xs:complexType>
+ <!-- Begin properties for the Relationship capability -->
+ <xs:element name="Relationship" type="muws2:RelationshipType" />
+ <!-- End properties for the Relationship capability -->
+ <xs:element name="RelationshipCreatedNotification">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element ref="muws2:Relationship" />
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax" />
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" />
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="RelationshipDeletedNotification">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element ref="muws2:Relationship" />
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax" />
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" />
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="QueryRelationshipsByType">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="RequestedType" type="xs:QName" />
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="QueryRelationshipsByTypeResponse">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element ref="muws2:Relationship" minOccurs="0"
+ maxOccurs="unbounded" />
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="CreationNotification">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element ref="muws1:ManageabilityEndpointReference"
+ minOccurs="0" maxOccurs="unbounded" />
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" />
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="DestructionNotification">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element ref="muws1:ResourceId" minOccurs="0" />
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" />
+ </xs:complexType>
+ </xs:element>
+ <xs:complexType name="SituationCategoryType">
+ <xs:complexContent>
+ <xs:extension base="muws2:CategoryType" />
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="SubstitutableMsgType">
+ <xs:sequence>
+ <xs:element name="Value" type="xs:anySimpleType"
+ minOccurs="0" maxOccurs="unbounded" />
+ </xs:sequence>
+ <xs:attribute name="MsgId" type="xs:string" use="required" />
+ <xs:attribute name="MsgIdType" type="xs:anyURI" use="required" />
+ </xs:complexType>
+ <xs:complexType name="SituationType">
+ <xs:sequence>
+ <xs:element name="SituationCategory"
+ type="muws2:SituationCategoryType" />
+ <xs:element name="SuccessDisposition" minOccurs="0">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="Successful" />
+ <xs:enumeration value="Unsuccessful" />
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="SituationTime" type="xs:dateTime" />
+ <xs:element name="Priority" type="xs:short" minOccurs="0" />
+ <xs:element name="Severity" type="xs:short" minOccurs="0" />
+ <xs:element name="Message" type="muws2:LangString"
+ minOccurs="0" />
+ <xs:element name="SubstitutableMsg"
+ type="muws2:SubstitutableMsgType" minOccurs="0" />
+ </xs:sequence>
+ </xs:complexType>
+ <xs:element name="Situation" type="muws2:SituationType" />
+ <xs:complexType name="EventCorrelationPropertiesType">
+ <xs:sequence>
+ <xs:element name="repeatCount" minOccurs="0"
+ maxOccurs="1">
+ <xs:simpleType>
+ <xs:restriction base="xs:short">
+ <xs:minInclusive value="0" />
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="elapsedTime" minOccurs="0"
+ maxOccurs="1">
+ <xs:simpleType>
+ <xs:restriction base="xs:long">
+ <xs:minInclusive value="0" />
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="sequenceNumber" type="xs:unsignedLong" />
+ </xs:complexType>
+ <xs:element name="EventCorrelationProperties"
+ type="muws2:EventCorrelationPropertiesType" />
+ <xs:complexType name="MsgCatalogInformationType">
+ <xs:sequence>
+ <xs:element name="msgCatalog" type="xs:anyURI"
+ minOccurs="1" />
+ <xs:element name="msgCatalogType" type="xs:anyURI"
+ minOccurs="0" />
+ </xs:sequence>
+ </xs:complexType>
+ <xs:element name="MsgCatalogInformation"
+ type="muws2:MsgCatalogInformationType" />
+ <!-- ##### Metadata description elements ##### -->
+ <xs:element name="Capability" type="xs:anyURI" />
+ <xs:complexType name="DialectableExpressionType" mixed="true">
+ <xs:sequence>
+ <xs:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded" />
+ </xs:sequence>
+ <xs:attribute name="Dialect" type="xs:anyURI" use="required" />
+ <xs:anyAttribute namespace="##other" />
+ </xs:complexType>
+ <xs:element name="ValidWhile"
+ type="muws2:DialectableExpressionType" />
+ <xs:element name="Units" type="xs:string" />
+ <xs:element name="ChangeType">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="Counter" />
+ <xs:enumeration value="Gauge" />
+ <xs:enumeration value="Unknown" />
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="TimeScope">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="Interval" />
+ <xs:enumeration value="PointInTime" />
+ <xs:enumeration value="SinceReset" />
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="GatheringTime">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="OnChange" />
+ <xs:enumeration value="Periodic" />
+ <xs:enumeration value="OnDemand" />
+ <xs:enumeration value="Unknown" />
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="CalculationInterval" type="xs:duration" />
+ <xs:element name="MetricGroup" type="xs:anyURI" />
+ <xs:element name="PostCondition"
+ type="muws2:DialectableExpressionType" />
+ <!-- ========= StartSituation ============ -->
+ <xs:element name="StartSituation">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType" />
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="StartInitiated">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:StartSituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="RestartInitiated">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:StartSituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="StartCompleted">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:StartSituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <!-- ========= StopSituation ============ -->
+ <xs:element name="StopSituation">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType" />
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="StopInitiated">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:StopSituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="AbortInitiated">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:StopSituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="PauseInitiated">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:StopSituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="StopCompleted">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:StopSituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <!-- ========= RequestSituation ============ -->
+ <xs:element name="RequestSituation">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType" />
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="RequestInitiated">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:RequestSituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="RequestCompleted">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:RequestSituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <!-- ========= DestroySituation ============ -->
+ <xs:element name="DestroySituation">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType" />
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="DestroyInitiated">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:DestroySituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="DestroyCompleted">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:DestroySituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <!-- ========= CreateSituation ============ -->
+ <xs:element name="CreateSituation">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType" />
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="CreateInitiated">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:CreateSituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="CreateCompleted">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:CreateSituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <!-- ========= ConnectSituation ============ -->
+ <xs:element name="ConnectSituation">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType" />
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="ConnectInitiated">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:ConnectSituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="ReconnectInitiated">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:ConnectSituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="ConnectCompleted">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:ConnectSituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <!-- ========= ReportSituation ============ -->
+ <xs:element name="ReportSituation">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType" />
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="PerformanceReport">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:ReportSituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="SecurityReport">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:ReportSituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="HeartbeatReport">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:ReportSituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="StatusReport">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:ReportSituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="TraceReport">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:ReportSituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="DebugReport">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:ReportSituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="LogReport">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType">
+ <xs:sequence>
+ <xs:element ref="muws2:ReportSituation" />
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <!-- ========= AvailabilitySituation ============ -->
+ <xs:element name="AvailabilitySituation">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType" />
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <!-- ========= CapabilitySituation ============ -->
+ <xs:element name="CapabilitySituation">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType" />
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <!-- ========= ConfigureSituation ============ -->
+ <xs:element name="ConfigureSituation">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType" />
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <!-- ========= OtherSituation ============ -->
+ <xs:element name="OtherSituation">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="muws2:SituationCategoryType" />
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <!--
+ SCHEMA COPY Material
+ Copy and paste element references below into the schema of a resource properties document.
+ These references insure that the correct minOccurs/maxOccurs attributes are specified in a resource property document schema.
+
+ NOTE: You must import the MUWS Part 2 schema namespace (MUWS2).
+
+ ** Description Properties **
+ <xs:element ref="muws2:Caption"
+ minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element ref="muws2:Description"
+ minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element ref="muws2:Version"
+ minOccurs="0"/>
+
+ ** Operational Status **
+ <xs:element ref="muws2:OperationalStatus"/>
+
+ ** Metrics **
+ <xs:element ref="muws2:CurrentTime"/>
+
+ ** Relationship **
+ <xs:element ref="muws2:Relationship"
+ minOccurs="0" maxOccurs="unbounded"/>
+
+ ** Relationship Resource **
+ <xs:element ref="muws2:Name" minOccurs="0"/>
+ <xs:element ref="muws2:Type"/>
+ <xs:element ref="muws2:Participant"
+ minOccurs="2" maxOccurs="unbounded"/>
+
+ -->
+</xs:schema> \ No newline at end of file
diff --git a/java/management/client/src/main/java/wsdl/WsResource.rmd b/java/management/client/src/main/java/wsdl/WsResource.rmd
new file mode 100644
index 0000000000..b15f7eca1c
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/WsResource.rmd
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<Definitions xmlns="http://docs.oasis-open.org/wsrf/rmd-1" >
+
+ <MetadataDescriptor xmlns:wsrl="http://docs.oasis-open.org/wsrf/rl-2"
+ xmlns:qman="http://amqp.apache.org/qpid/management/qman" name="QManWsResourceMetadata"
+ interface="qman:QManWsResourcePortType"
+ wsdlLocation="http://ws.apache.org/muse/test/wsrf QManWsResource.wsdl" >
+
+ <Property name="wsrl:CurrentTime" modifiability="read-only" mutability="mutable" />
+
+ <Property name="wsrl:TerminationTime" modifiability="read-only" mutability="mutable" />
+ </MetadataDescriptor>
+
+</Definitions> \ No newline at end of file
diff --git a/java/management/client/src/main/java/wsdl/WsResourceFactory.wsdl b/java/management/client/src/main/java/wsdl/WsResourceFactory.wsdl
new file mode 100644
index 0000000000..83a7e5ad8c
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/WsResourceFactory.wsdl
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<wsdl:definitions
+ targetNamespace="http://ws.apache.org/muse/test/wsrf"
+ xmlns:tns="http://ws.apache.org/muse/test/wsrf"
+ xmlns="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:wsdl-soap="http://schemas.xmlsoap.org/wsdl/soap/"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ name="WsResourceFactory">
+ <wsdl:types>
+ </wsdl:types>
+ <wsdl:portType name="WsResourceFactoryPortType" >
+ </wsdl:portType>
+ <wsdl:binding name="WsResourceFactoryBinding" type="tns:WsResourceFactoryPortType">
+ <wsdl-soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
+ </wsdl:binding>
+ <wsdl:service name="WsResourceFactoryService">
+ <wsdl:port name="WsResourceFactoryPort" binding="tns:WsResourceFactoryBinding">
+ <wsdl-soap:address location="http://romagazzarini:8080/wsrf/services/WsResourceFactory"/>
+ </wsdl:port>
+ </wsdl:service>
+</wsdl:definitions>
diff --git a/java/management/client/src/main/java/wsdl/XML-Namespace-1998.xsd b/java/management/client/src/main/java/wsdl/XML-Namespace-1998.xsd
new file mode 100644
index 0000000000..998a8001de
--- /dev/null
+++ b/java/management/client/src/main/java/wsdl/XML-Namespace-1998.xsd
@@ -0,0 +1,25 @@
+<?xml version='1.0'?>
+<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace" xmlns:xs="http://www.w3.org/2001/XMLSchema" xml:lang="en">
+
+ <xs:attribute name="lang" type="xs:language">
+ </xs:attribute>
+
+ <xs:attribute name="space" default="preserve">
+ <xs:simpleType>
+ <xs:restriction base="xs:NCName">
+ <xs:enumeration value="default"/>
+ <xs:enumeration value="preserve"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+
+ <xs:attribute name="base" type="xs:anyURI">
+ </xs:attribute>
+
+ <xs:attributeGroup name="specialAttrs">
+ <xs:attribute ref="xml:base"/>
+ <xs:attribute ref="xml:lang"/>
+ <xs:attribute ref="xml:space"/>
+ </xs:attributeGroup>
+
+</xs:schema>
diff --git a/java/management/client/src/test/java/log4j.xml b/java/management/client/src/test/java/log4j.xml
new file mode 100644
index 0000000000..34634b7738
--- /dev/null
+++ b/java/management/client/src/test/java/log4j.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
+ <!-- Write to stdout -->
+ <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+ <param name="Target" value="System.out" />
+ <param name="Threshold" value="DEBUG" />
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern"
+ value="%d{ABSOLUTE} %-5p [%c{1}] %m%n" />
+ </layout>
+ </appender>
+ <category name="org.apache.qpid.management">
+ <priority value="INFO" />
+ <appender-ref ref="CONSOLE" />
+ </category>
+
+ <category name="org.mortbay">
+ <priority value="INFO" />
+ <appender-ref ref="CONSOLE" />
+ </category>
+
+ <category name="org.apache.qpid.qman.debug.XmlDebugger">
+ <priority value="DEBUG" />
+ <appender-ref ref="CONSOLE" />
+ </category>
+ <root>
+ <priority value="ERROR" />
+ </root>
+
+</log4j:configuration> \ No newline at end of file
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/TestConstants.java b/java/management/client/src/test/java/org/apache/qpid/management/TestConstants.java
new file mode 100644
index 0000000000..9abcd08eef
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/TestConstants.java
@@ -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.
+ *
+ */
+package org.apache.qpid.management;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.qpid.management.domain.handler.impl.MethodOrEventDataTransferObject;
+import org.apache.qpid.management.domain.model.DomainModel;
+import org.apache.qpid.management.domain.model.type.Binary;
+
+/**
+ * Collects all literal constants used in test cases.
+ */
+public interface TestConstants
+{
+ UUID BROKER_ID = UUID.randomUUID();
+ Binary OBJECT_ID = new Binary(new byte []{1,2,3,2,1,1,2,3});
+
+ DomainModel DOMAIN_MODEL = new DomainModel(BROKER_ID);
+
+ String AGE_ATTRIBUTE_NAME = "age";
+ String AGE_ATTRIBUTE_DESCRIPTION = "The age of a person.";
+ String SURNAME_ATTRIBUTE_NAME = "surname";
+ String SURNAME_ATTRIBUTE_DESCRIPTION = "The surname of a person.";
+ Integer _1 = new Integer(1);
+
+ byte [] TEST_RAW_DATA= new byte []{1,4,5,7,8,9,4,44};
+ long NOW = System.currentTimeMillis();
+ int SEVERITY = _1;
+
+ String QPID_PACKAGE_NAME = "qpid";
+ String EXCHANGE_CLASS_NAME = "exchange";
+ String BIND_EVENT_NAME = "bind";
+ Binary HASH = new Binary(new byte []{1,2,3,4,5,6,7,8,9});
+ int VALID_CODE = _1;
+
+ List<Map<String, Object>> EMPTY_PROPERTIES_SCHEMA = new LinkedList<Map<String,Object>>();
+ List<Map<String, Object>> EMPTY_STATISTICS_SCHEMA = new LinkedList<Map<String,Object>>();
+ List<MethodOrEventDataTransferObject> EMPTY_METHODS_SCHEMA = new LinkedList<MethodOrEventDataTransferObject>();
+ List<Map<String, Object>> EMPTY_ARGUMENTS_SCHEMA = new LinkedList<Map<String,Object>>();
+ int _0 = 0;
+ int SAMPLE_ACCESS_CODE = 1;
+ String YEARS = "years";
+ int SAMPLE_MIN_VALUE = 1;
+ int SAMPLE_MAX_VALUE = 120;
+} \ No newline at end of file
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/configuration/ConfigurationTest.java b/java/management/client/src/test/java/org/apache/qpid/management/configuration/ConfigurationTest.java
new file mode 100644
index 0000000000..72bd45f70f
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/configuration/ConfigurationTest.java
@@ -0,0 +1,181 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.configuration;
+
+import java.util.Map;
+import java.util.UUID;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.management.TestConstants;
+import org.apache.qpid.management.domain.handler.base.IMessageHandler;
+import org.apache.qpid.management.domain.handler.impl.ConfigurationMessageHandler;
+import org.apache.qpid.management.domain.handler.impl.InstrumentationMessageHandler;
+import org.apache.qpid.management.domain.handler.impl.SchemaResponseMessageHandler;
+
+/**
+ * Test case for Configuration singleton.
+ */
+public class ConfigurationTest extends TestCase
+{
+ /**
+ * Tests the singleton behaviour of the configuration object.
+ */
+ public void testSingleton()
+ {
+ assertSame(Configuration.getInstance(),Configuration.getInstance());
+ }
+
+ /**
+ * Tests the execution of getType() method when a unknown code is supplied.
+ *
+ * <br>precondition : the requested type doesn't exist on the configuration.
+ * <br>postcondition : an exception is thrown indicating the failure.
+ */
+ public void testGetTypeKO()
+ {
+ try
+ {
+ Configuration.getInstance().getType(TestConstants.VALID_CODE*10001);
+ fail("If an unknwon code is supplied an exception must be thrown.");
+ } catch (UnknownTypeCodeException expected)
+ {
+ assertEquals(TestConstants.VALID_CODE*10001,expected.getCode());
+ }
+ }
+
+ /**
+ * Tests the execution of getAccessMode() method when a unknown code is supplied.
+ *
+ * <br>precondition : the requested access mode doesn't exist on the configuration.
+ * <br>postcondition : an exception is thrown indicating the failure.
+ */
+ public void testGetAccessModeKO()
+ {
+ try
+ {
+ Configuration.getInstance().getAccessMode(TestConstants.VALID_CODE*1528);
+ fail("If an unknwon code is supplied an exception must be thrown.");
+ } catch (UnknownAccessCodeException expected)
+ {
+ assertEquals(TestConstants.VALID_CODE*1528,expected.getCode());
+ }
+ }
+
+ /**
+ * Tests the execution of the getBrokerConnectionData when a valid broker id is supplied.
+ *
+ * <br>precondition : on configuration a connection data is stored and associated with the supplied id.
+ * <br>postcondition : the requested connection data is returned and no exception is thrown.
+ */
+ public void testGetBrokerConnectionDataOK() throws Exception
+ {
+ BrokerConnectionData connectionData = new BrokerConnectionData();
+ connectionData.setHost("host");
+ connectionData.setPort("7001");
+ connectionData.setInitialPoolCapacity("0");
+ connectionData.setMaxPoolCapacity("10");
+ connectionData.setMaxWaitTimeout("1");
+ Configuration.getInstance().addBrokerConnectionData(TestConstants.BROKER_ID, connectionData);
+
+ BrokerConnectionData result = Configuration.getInstance().getBrokerConnectionData(TestConstants.BROKER_ID);
+ assertSame(connectionData, result);
+ }
+
+ /**
+ * Tests the execution of the getBrokerConnectionData when a unknown broker id is supplied.
+ *
+ * <br>precondition : on configuration there's no connection data associated with the supplied id.
+ * <br>postcondition : an exception is thrown indicating the failure.
+ */
+ public void testGetBrokerConnectionDataKO_withUnknownBrokerId()
+ {
+ UUID brokerId = UUID.randomUUID();
+ try
+ {
+ Configuration.getInstance().getBrokerConnectionData(brokerId);
+ fail("If an unknown broker id is supplied then an exception must be thrown.");
+ } catch(UnknownBrokerException expected)
+ {
+ assertEquals(brokerId.toString(),expected.getMessage());
+ }
+ }
+
+ /**
+ * Tests the execution of the getBrokerConnectionData when a null id is supplied.
+ *
+ * <br>precondition : a null broker is given.
+ * <br>postcondition : an exception is thrown indicating the failure.
+ */
+ public void testGetBrokerConnectionDataKO_withNullBrokerId()
+ {
+ try
+ {
+ Configuration.getInstance().getBrokerConnectionData(null);
+ fail("If a null broker id is supplied then an exception must be thrown.");
+ } catch(UnknownBrokerException expected)
+ {
+ }
+ }
+
+ /**
+ * Tests the behaviour of the getManagementQueueHandlers() method.
+ *
+ * <br>precondition: 2 management handlers are in stored configuration
+ * <br>postcondition : 2 management handlers are returned.
+ */
+ public void testGetManagementQueueHandlersOk()
+ {
+ IMessageHandler instrMessageHandler = new InstrumentationMessageHandler();
+ IMessageHandler configMessageHandler = new ConfigurationMessageHandler();
+
+ MessageHandlerMapping instrMapping = new MessageHandlerMapping('i',instrMessageHandler);
+ MessageHandlerMapping configMapping = new MessageHandlerMapping('c',configMessageHandler);
+
+ Configuration.getInstance().addManagementMessageHandlerMapping(instrMapping);
+ Configuration.getInstance().addManagementMessageHandlerMapping(configMapping);
+
+ Map<Character, IMessageHandler> handlerMappings = Configuration.getInstance().getManagementQueueHandlers();
+
+ assertEquals(2,handlerMappings.size());
+ assertEquals(instrMessageHandler,handlerMappings.get(instrMapping.getOpcode()));
+ assertEquals(configMessageHandler,handlerMappings.get(configMapping.getOpcode()));
+ }
+
+ /**
+ * Tests the behaviour of the getManagementQueueHandlers() method.
+ *
+ * <br>precondition: 2 management handlers are in stored configuration
+ * <br>postcondition : 2 management handlers are returned.
+ */
+ public void testGetMethodReplyQueueHandlersOk()
+ {
+ IMessageHandler schemaMessageHandler = new SchemaResponseMessageHandler();
+
+ MessageHandlerMapping schemaMapping = new MessageHandlerMapping('s',schemaMessageHandler);
+
+ Configuration.getInstance().addMethodReplyMessageHandlerMapping(schemaMapping);
+
+ Map<Character, IMessageHandler> handlerMappings = Configuration.getInstance().getMethodReplyQueueHandlers();
+
+ assertEquals(schemaMessageHandler,handlerMappings.get(schemaMapping.getOpcode()));
+ }
+}
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/configuration/ConfiguratorTest.java b/java/management/client/src/test/java/org/apache/qpid/management/configuration/ConfiguratorTest.java
new file mode 100644
index 0000000000..1e464bf6ae
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/configuration/ConfiguratorTest.java
@@ -0,0 +1,163 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.configuration;
+
+import java.util.Map;
+import java.util.UUID;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.management.Protocol;
+import org.apache.qpid.management.domain.handler.base.IMessageHandler;
+import org.apache.qpid.management.domain.handler.impl.ConfigurationMessageHandler;
+import org.apache.qpid.management.domain.handler.impl.EventContentMessageHandler;
+import org.apache.qpid.management.domain.handler.impl.HeartBeatIndicationMessageHandler;
+import org.apache.qpid.management.domain.handler.impl.InstrumentationMessageHandler;
+import org.apache.qpid.management.domain.handler.impl.MethodResponseMessageHandler;
+import org.apache.qpid.management.domain.handler.impl.SchemaResponseMessageHandler;
+import org.apache.qpid.management.domain.model.AccessMode;
+import org.apache.qpid.management.domain.model.type.AbsTime;
+import org.apache.qpid.management.domain.model.type.DeltaTime;
+import org.apache.qpid.management.domain.model.type.ObjectReference;
+import org.apache.qpid.management.domain.model.type.Str16;
+import org.apache.qpid.management.domain.model.type.Str8;
+import org.apache.qpid.management.domain.model.type.Uint16;
+import org.apache.qpid.management.domain.model.type.Uint32;
+import org.apache.qpid.management.domain.model.type.Uint64;
+import org.apache.qpid.management.domain.model.type.Uint8;
+import org.xml.sax.SAXException;
+
+/**
+ * Test case for configurator.
+ *
+ * @author Andrea Gazzarini
+ *
+ */
+public class ConfiguratorTest extends TestCase
+{
+ /**
+ * Tests the execution of the configure() method when no configuration file is given.
+ *
+ * <br>precondition : configuration file option is not set
+ * <br>postcondition : no exception is thrown, the configuration is holding no broker data and the predefined mappings are
+ * stored in configuration.
+ */
+ public void testConfigureOK_WithNoConfigurationFile() throws Exception
+ {
+ Configurator configurator = new Configurator();
+ configurator.configure();
+ Configuration configuration = Configuration.getInstance();
+
+ assertEquals(new Uint8(), configuration.getType(1));
+ assertEquals(new Uint16(), configuration.getType(2));
+ assertEquals(new Uint32(), configuration.getType(3));
+ assertEquals(new Uint64(), configuration.getType(4));
+ assertEquals(new Str8(), configuration.getType(6));
+ assertEquals(new Str16(), configuration.getType(7));
+ assertEquals(new AbsTime(), configuration.getType(8));
+ assertEquals(new DeltaTime(), configuration.getType(9));
+ assertEquals(new ObjectReference(), configuration.getType(10));
+ assertEquals(new org.apache.qpid.management.domain.model.type.Boolean(), configuration.getType(11));
+ assertEquals(new org.apache.qpid.management.domain.model.type.Uuid(), configuration.getType(14));
+ assertEquals(new org.apache.qpid.management.domain.model.type.Map(), configuration.getType(15));
+
+ assertEquals(AccessMode.RC,configuration.getAccessMode(1));
+ assertEquals(AccessMode.RW,configuration.getAccessMode(2));
+ assertEquals(AccessMode.RO,configuration.getAccessMode(3));
+
+ Map<Character, IMessageHandler> managementHandlers = configuration.getManagementQueueHandlers();
+ assertEquals(4,managementHandlers.size());
+ assertEquals(
+ InstrumentationMessageHandler.class,
+ managementHandlers.get(Protocol.INSTRUMENTATION_CONTENT_RESPONSE_OPCODE).getClass());
+
+ assertEquals(
+ ConfigurationMessageHandler.class,
+ managementHandlers.get(Protocol.CONFIGURATION_CONTENT_RESPONSE_OPCDE).getClass());
+
+ assertEquals(
+ EventContentMessageHandler.class,
+ managementHandlers.get(Protocol.EVENT_CONTENT_RESPONSE_OPCDE).getClass());
+
+ assertEquals(
+ HeartBeatIndicationMessageHandler.class,
+ managementHandlers.get(Protocol.HEARTBEAT_INDICATION_RESPONSE_OPCODE).getClass());
+
+ Map<Character, IMessageHandler> methodReplyHandlers = configuration.getMethodReplyQueueHandlers();
+ assertEquals(2, methodReplyHandlers.size());
+
+ assertEquals(
+ MethodResponseMessageHandler.class,
+ methodReplyHandlers.get(Protocol.OPERATION_INVOCATION_RESPONSE_OPCODE).getClass());
+
+ assertEquals(
+ SchemaResponseMessageHandler.class,
+ methodReplyHandlers.get(Protocol.SCHEMA_RESPONSE_OPCODE).getClass());
+ }
+
+ /**
+ * Tests the changes of the configurator internal state while configuration file is parsed.
+ *
+ * <br>precondition: N.A.
+ * <br>postcondition: N.A.
+ */
+ public void testDirectorParsing() throws SAXException{
+ Configurator configurator = new Configurator();
+
+ assertSame(Configurator.DEFAULT_PARSER,configurator._currentParser);
+
+ configurator.startElement(null, null, Tag.BROKERS.toString(), null);
+ assertSame(configurator._brokerConfigurationParser,configurator._currentParser);
+ }
+
+ /**
+ * It's not possibile to add twice the same broker connection data.
+ * Is so an exception must be thrown indicating that the given broker is already connected.
+ *
+ * <br>precondition : the given data identifies an already connected broker.
+ * <br>postcondition : an exception is thrown indicating the failure.
+ */
+ public void testAddTwoIdenticalBrokers() throws ConfigurationException, BrokerConnectionException
+ {
+ Configurator configurator = new Configurator();
+ configurator.configure();
+
+ BrokerConnectionData data = new BrokerConnectionData("sofia.gazzax.com",5672,"virtualHost","user","pwd",1,4,-1);
+
+ Configuration.getInstance()._brokerConnectionInfos.put(UUID.randomUUID(),data);
+
+ try {
+ configurator.createAndReturnBrokerConnectionData(
+ UUID.randomUUID(),
+ data.getHost(),
+ data.getPort(),
+ "anotherUser",
+ "anotherPassword",
+ data.getVirtualHost(),
+ 33,
+ 12,
+ 1000);
+ fail("If a broker is added twice an exception must be thrown.");
+ } catch (BrokerAlreadyConnectedException expected) {
+ assertEquals(data,expected.getBrokerConnectionData());
+ }
+ }
+}
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/configuration/MappingParsersTest.java b/java/management/client/src/test/java/org/apache/qpid/management/configuration/MappingParsersTest.java
new file mode 100644
index 0000000000..af261024bd
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/configuration/MappingParsersTest.java
@@ -0,0 +1,79 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.configuration;
+
+import java.util.UUID;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.management.TestConstants;
+
+/**
+ * Test case for mapping parsers.
+ *
+ * @author Andrea Gazzarini.
+ */
+public class MappingParsersTest extends TestCase
+{
+ /**
+ * Tests the execution of the broker connection data mapping parser.
+ *
+ * <br>precondition: A broker connection datamapping is built by the parser;
+ * <br>postcondition: the corresponding connection data is available on the configuration.
+ */
+ public void testBrokerConnectionDataParser() throws UnknownBrokerException
+ {
+ String host = "127.0.0.1";
+ String port = "7001";
+ String virtualHost = "test";
+ String username = "username_guest";
+ String password ="password_guest";
+
+ BrokerConnectionDataParser parser = new BrokerConnectionDataParser()
+ {
+ @Override
+ UUID getUUId ()
+ {
+ return TestConstants.BROKER_ID;
+ }
+ };
+
+ parser.setCurrrentAttributeValue(host);
+ parser.setCurrentAttributeName(Tag.HOST.toString());
+ parser.setCurrrentAttributeValue(port);
+ parser.setCurrentAttributeName(Tag.PORT.toString());
+ parser.setCurrrentAttributeValue(virtualHost);
+ parser.setCurrentAttributeName(Tag.VIRTUAL_HOST.toString());
+ parser.setCurrrentAttributeValue(username);
+ parser.setCurrentAttributeName(Tag.USER.toString());
+ parser.setCurrrentAttributeValue(password);
+ parser.setCurrentAttributeName(Tag.PASSWORD.toString());
+ parser.setCurrentAttributeName(Tag.BROKER.toString());
+
+ BrokerConnectionData result = Configuration.getInstance().getBrokerConnectionData(TestConstants.BROKER_ID);
+
+ assertEquals(host,result.getHost());
+ assertEquals(Integer.parseInt(port),result.getPort());
+ assertEquals(virtualHost,result.getVirtualHost());
+ assertEquals(username,result.getUsername());
+ assertEquals(password,result.getPassword());
+ }
+}
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/domain/handler/base/ContentIndicationMessageHandlerTest.java b/java/management/client/src/test/java/org/apache/qpid/management/domain/handler/base/ContentIndicationMessageHandlerTest.java
new file mode 100644
index 0000000000..d6b51b64fc
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/domain/handler/base/ContentIndicationMessageHandlerTest.java
@@ -0,0 +1,59 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.handler.base;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.management.domain.model.type.Binary;
+
+/**
+ * Test case for Content indication message handler (base class).
+ *
+ * @author Andrea Gazzarini
+ */
+public class ContentIndicationMessageHandlerTest extends TestCase
+{
+ /**
+ * Tests the behaviour of the objectHasBeenRemoved method().
+ */
+ public void testObjectHasBeenRemoved()
+ {
+ ContentIndicationMessageHandler mockHandler = new ContentIndicationMessageHandler()
+ {
+ @Override
+ protected void updateDomainModel (String packageName, String className, Binary classHash, Binary objectId,
+ long timeStampOfCurrentSample, long timeObjectWasCreated, long timeObjectWasDeleted, byte[] contentData)
+ {
+ }
+ };
+
+ long deletionTimestamp = 0;
+ long now = System.currentTimeMillis();
+
+ assertFalse(mockHandler.objectHasBeenRemoved(deletionTimestamp, now));
+
+ deletionTimestamp = now + 1000;
+ assertFalse(mockHandler.objectHasBeenRemoved(deletionTimestamp, now));
+
+ deletionTimestamp = now - 1000;
+ assertTrue(mockHandler.objectHasBeenRemoved(deletionTimestamp, now));
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/domain/model/BaseDomainModelTestCase.java b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/BaseDomainModelTestCase.java
new file mode 100644
index 0000000000..c528392a93
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/BaseDomainModelTestCase.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import org.apache.qpid.management.configuration.Configurator;
+
+import junit.framework.TestCase;
+
+/**
+ * Layer supertype for all domain model related test cases.
+ *
+ * @author Andrea Gazzarini
+ */
+public abstract class BaseDomainModelTestCase extends TestCase
+{
+ /**
+ * Set up fixture for this test case.
+ * In order to execute tests on domain model we need to build the configuration.
+ */
+ @Override
+ protected void setUp () throws Exception
+ {
+ Configurator configurator = new Configurator();
+ configurator.configure();
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/domain/model/BaseQpidFeatureBuilderTestCase.java b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/BaseQpidFeatureBuilderTestCase.java
new file mode 100644
index 0000000000..3d3783eb04
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/BaseQpidFeatureBuilderTestCase.java
@@ -0,0 +1,96 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.desc;
+import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.name;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.management.configuration.Configurator;
+import org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute;
+
+/**
+ * Layer supertype for feature builder test cases.
+ *
+ * @author Andrea Gazzarini
+ */
+public abstract class BaseQpidFeatureBuilderTestCase extends TestCase
+{
+ protected final static String NAME = "aName";
+
+ protected final static String DESCRIPTION = "A description.";
+
+ protected Map <String,Object> _featureDefinition;
+ protected QpidFeatureBuilder _builder;
+
+ /**
+ * Set up fixture for all concrete builder test cases.
+ */
+ @Override
+ protected void setUp () throws Exception
+ {
+ Configurator configurator = new Configurator();
+ configurator.configure();
+ _featureDefinition = new HashMap<String, Object>();
+ _featureDefinition.put(name.name(),NAME);
+ _featureDefinition.put(desc.name(), DESCRIPTION);
+ }
+
+ // Internal test used to avoid code duplication.
+ protected void internalTestForMissingMandatoryAttribute(Attribute ...toBeRemoved)
+ {
+ try
+ {
+ for (Attribute attribute : toBeRemoved)
+ {
+ _featureDefinition.remove(attribute.name());
+ }
+ _builder.build();
+ fail("If a mandatory attribute is missing an exception must be thrown!");
+ } catch (UnableToBuildFeatureException expected)
+ {
+ assertTrue(expected instanceof MissingFeatureAttributesException);
+ for (Attribute attribute : toBeRemoved)
+ {
+ assertTrue(expected.getMessage().contains(attribute.name()));
+ }
+ }
+ }
+
+ // Internal test used to avoid code duplication.
+ protected void internalTestForMissingOptionalAttribute(Attribute ...toBeRemoved) throws UnableToBuildFeatureException
+ {
+ for (Attribute attribute : toBeRemoved)
+ {
+ _featureDefinition.remove(attribute.name());
+ }
+ _builder.build();
+
+ assertNotNull(_builder.getQpidFeature());
+ assertNotNull(_builder.getManagementFeature());
+ }
+
+
+}
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/domain/model/DomainModelTest.java b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/DomainModelTest.java
new file mode 100644
index 0000000000..578fa36bc7
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/DomainModelTest.java
@@ -0,0 +1,55 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import java.util.UUID;
+
+import org.apache.qpid.management.TestConstants;
+
+/**
+ * Test case for domain model entity.
+ *
+ * @author Andrea Gazzarini
+ */
+public class DomainModelTest extends BaseDomainModelTestCase
+{
+ private DomainModel _model;
+
+ @Override
+ protected void setUp () throws Exception
+ {
+ _model = new DomainModel(UUID.randomUUID());
+ }
+
+ /**
+ * Tests the execution of the getPackage() method.
+ */
+ public void testGetPackage()
+ {
+ assertFalse(_model.containsPackage(TestConstants.QPID_PACKAGE_NAME));
+
+ QpidPackage qpidPackage = _model.getPackageByName(TestConstants.QPID_PACKAGE_NAME);
+ assertEquals(TestConstants.QPID_PACKAGE_NAME,qpidPackage.getName());
+
+ QpidPackage theSameAsPreviousOne = _model.getPackageByName(TestConstants.QPID_PACKAGE_NAME);
+ assertSame(qpidPackage, theSameAsPreviousOne);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/domain/model/OptionalPropertiesTest.java b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/OptionalPropertiesTest.java
new file mode 100644
index 0000000000..553c1c21de
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/OptionalPropertiesTest.java
@@ -0,0 +1,187 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.management.domain.model.type.Uint64;
+import org.apache.qpid.transport.codec.BBDecoder;
+
+public class OptionalPropertiesTest extends TestCase
+{
+ public void testDecoderStateChange()
+ {
+ QpidProperty property = new QpidProperty();
+ assertSame(
+ "Default decoder for properties is the one for mandatory properties.",
+ property._mandatoryPropertyDecoder,
+ property._decoder);
+
+ property.markAsOptional(1);
+ assertSame(
+ "After a property has been marked as optional the corresponding decoder must be installed.",
+ property._optionalPropertyDecoder,
+ property._decoder);
+ }
+
+ /**
+ * Tests the execution of the decode() method when the current property is optional but in the presence bitmask
+ * there's no the corresponding bit set.
+ *
+ * <br>precondition : property is optional and corresponding presence bit is not set.
+ * <br>postcondition : result must be null.
+ */
+ public void testDecodeValueWithOptionalPropertyAndMissingValue()
+ {
+ byte [] presenceBytes = {2};
+
+ QpidProperty property = new QpidProperty();
+
+ // We don't need a decoder so in order to be sure that it won't be invoked set it to null.
+ BBDecoder nullDecoder = null;
+
+ for (int i = 0; i < 8; i++)
+ {
+ // Property number 1 is declaring a value so skip it!
+ if (i != 1)
+ {
+ property.markAsOptional(i);
+ assertNull(property.decodeValue(nullDecoder, presenceBytes));
+ }
+ }
+ }
+
+ /**
+ * Tests the execution of the decode() method when the current property is optional but in the presence bitmask
+ * there's no the corresponding bit set.
+ *
+ * <br>precondition : property is optional and corresponding presence bit is not set.
+ * <br>postcondition : result must be null.
+ */
+ public void testDecodeValueWithOptionalPropertyAndDeclaredValue()
+ {
+ byte [] presenceBytes = {4};
+ Long _44 = new Long(44);
+
+ QpidProperty property = new QpidProperty();
+ property.setType(new Uint64());
+ property.markAsOptional(2);
+
+ ByteBuffer buffer = ByteBuffer.allocate(8);
+ buffer.putLong(_44);
+ buffer.rewind();
+ BBDecoder decoder = new BBDecoder();
+
+ decoder.init(buffer);
+ assertEquals(_44,property.decodeValue(decoder, presenceBytes));
+ }
+
+ /**
+ * Tests the execution of the decode() method with a real scenario where there are mandatory and optional
+ * properties.
+ */
+ public void testDecodeValueWithOptionalAndMandatoryProperties()
+ {
+ // With this bitset :
+ //
+ // 1th opt property is null;
+ // 2th opt property is null;
+ // 3th opt property is not null;
+ // 4th opt property is null;
+ // 5th opt propertyis null;
+ // 6th opt property is null;
+ // 7th opt property is null;
+ // 8th opt property is not null;
+ byte [] presenceBytes = {4,1};
+
+ List<QpidProperty> properties = new LinkedList<QpidProperty>();
+
+ properties.add(createProperty(false, -1));
+ properties.add(createProperty(false, -1));
+ properties.add(createProperty(true, 0));
+ properties.add(createProperty(false, -1));
+ properties.add(createProperty(false, -1));
+ properties.add(createProperty(true, 1));
+ properties.add(createProperty(false, -1));
+ properties.add(createProperty(false, -1));
+ properties.add(createProperty(true, 2));
+ properties.add(createProperty(true, 3));
+ properties.add(createProperty(true, 4));
+ properties.add(createProperty(true, 5));
+ properties.add(createProperty(true, 6));
+ properties.add(createProperty(true, 7));
+ properties.add(createProperty(false, -1));
+ properties.add(createProperty(true, 8));
+
+ Long expectedResults [] = {
+ 1L, // p1
+ 22L, // p2
+ null, // p3
+ 232L, // p4
+ 211L, // p5
+ null, // p6
+ 232L, // p7
+ 211L, // p8
+ 999L, // p9
+ null, // p10
+ null, // p11
+ null, // p12
+ null, // p13
+ null, // p14
+ 626L, // p15
+ 969L // p16
+ };
+
+
+ ByteBuffer buffer = ByteBuffer.allocate(expectedResults.length * 8);
+ for (Long expected : expectedResults)
+ {
+ if (expected != null)
+ {
+ buffer.putLong(expected);
+ }
+ }
+ buffer.rewind();
+ BBDecoder decoder = new BBDecoder();
+
+ decoder.init(buffer);
+ int index = 0;
+ for (QpidProperty property : properties)
+ {
+ assertEquals(expectedResults[index++],property.decodeValue(decoder, presenceBytes));
+ }
+ }
+
+ private QpidProperty createProperty(boolean isOptional, int optionalIndex)
+ {
+ QpidProperty property = new QpidProperty();
+ property.setType(new Uint64());
+ if (isOptional)
+ {
+ property.markAsOptional(optionalIndex);
+ }
+ return property;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidClassTest.java b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidClassTest.java
new file mode 100644
index 0000000000..9d6e176912
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidClassTest.java
@@ -0,0 +1,408 @@
+/*
+*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.management.domain.model;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanInfo;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.management.TestConstants;
+import org.apache.qpid.management.configuration.ConfigurationException;
+import org.apache.qpid.management.configuration.Configurator;
+import org.apache.qpid.management.domain.handler.impl.MethodOrEventDataTransferObject;
+import org.apache.qpid.management.domain.model.QpidClass.QManManagedObject;
+
+/**
+ * Test case for Qpid Class.
+ *
+ * @author Andrea Gazzarini
+ */
+public class QpidClassTest extends TestCase
+{
+ private QpidClass _class;
+ private QpidPackage _package;
+
+ @Override
+ protected void setUp () throws ConfigurationException
+ {
+ Configurator configurator = new Configurator();
+ configurator.configure();
+ _package = new QpidPackage(TestConstants.QPID_PACKAGE_NAME,TestConstants.DOMAIN_MODEL);
+ _class = new QpidClass(TestConstants.EXCHANGE_CLASS_NAME,TestConstants.HASH,_package);
+ }
+
+ /**
+ * Tests the execution of the getObjectInstance() method.
+ * Basically it tests the addition of a new object instance.
+ *
+ * <br>precondition: class has no object instances.
+ * <br>precondition : class contains the added object instance.
+ */
+ public void testGetObjectInstance()
+ {
+ assertFalse (
+ "Nobody set instance #"+TestConstants.OBJECT_ID+" into this class so why is it there?",
+ _class._objectInstances.containsKey(TestConstants.OBJECT_ID));
+
+ QManManagedObject instance = _class.getObjectInstance(TestConstants.OBJECT_ID, false);
+
+ assertTrue (
+ "Now the instance #"+TestConstants.OBJECT_ID+" should be there...",
+ _class._objectInstances.containsKey(TestConstants.OBJECT_ID));
+
+ assertEquals(instance,_class.getObjectInstance(TestConstants.OBJECT_ID, false));
+ }
+
+ /**
+ * Tests the injection of instrumentation and configuration data (related to a specific object instance) before the
+ * schema is installed.
+ *
+ * <br>precondition : the schema hasn't yet installed on this class.
+ * <br>postcondition : incoming configuration & instrumentation data is stored into the corresponding object instance.
+ */
+ public void testAddInstrumentationAndConfigurationDataBeforeSchemaInstallation()
+ {
+ _class._state = _class._schemaRequestedButNotYetInjected;
+ QManManagedObject objectInstance = _class.getObjectInstance(TestConstants.OBJECT_ID,false);
+
+ assertTrue(
+ "This object instance is a new one so how is it possible that it has already instrumentation data? ",
+ objectInstance._rawInstrumentationData.isEmpty());
+ assertTrue(
+ "This object instance is a new one so how is it possible that it has already configuration data? ",
+ objectInstance._rawConfigurationData.isEmpty());
+
+ byte [] dummyConfigurationData = {1,2,3,4,5,6,7,8};
+ byte [] dummyInstrumentationData = {11,21,31,41,51,61,71,81};
+
+ _class.addConfigurationData(TestConstants.OBJECT_ID, dummyConfigurationData);
+ _class.addInstrumentationData(TestConstants.OBJECT_ID, dummyInstrumentationData);
+
+ assertEquals("Now configuration data should be there...",1,objectInstance._rawConfigurationData.size());
+ assertEquals("Now instrumentation data should be there...",1,objectInstance._rawInstrumentationData.size());
+
+ assertTrue(
+ "Object instance configuration data should be the previously set...",
+ Arrays.equals(objectInstance._rawConfigurationData.get(0),
+ dummyConfigurationData));
+
+ assertTrue(
+ "Object instance instrumentation data should be the previously set...",
+ Arrays.equals(objectInstance._rawInstrumentationData.get(0),
+ dummyInstrumentationData));
+ }
+
+ /**
+ * Tests the internal state change of a class definition.
+ */
+ public void testStateChange() throws UnableToBuildFeatureException
+ {
+ _class = new QpidClass(TestConstants.EXCHANGE_CLASS_NAME,TestConstants.HASH,_package)
+ {
+ @Override
+ void requestSchema() throws Exception {
+ _state = _schemaRequestedButNotYetInjected;
+ }
+
+ @Override
+ void setSchema(List<Map<String, Object>> propertyDefinitions,
+ List<Map<String, Object>> statisticDefinitions,
+ List<MethodOrEventDataTransferObject> methodDefinitions) throws UnableToBuildFeatureException {
+ _state = _schemaInjected;
+ }
+ };
+
+ assertSame(
+ "Initial state doesn't match.",
+ _class._schemaNotRequested,
+ _class._state);
+
+ _class.addConfigurationData(TestConstants.OBJECT_ID, TestConstants.TEST_RAW_DATA);
+ _class.addInstrumentationData(TestConstants.OBJECT_ID, TestConstants.TEST_RAW_DATA);
+
+ assertSame(
+ "Request schema has been requested but not yet injected. The current state is not indicating that!",
+ _class._schemaRequestedButNotYetInjected,
+ _class._state);
+
+ _class.setSchema(
+ TestConstants.EMPTY_PROPERTIES_SCHEMA,
+ TestConstants.EMPTY_STATISTICS_SCHEMA,
+ new LinkedList<MethodOrEventDataTransferObject>());
+
+ assertSame(
+ "Request schema has been injected. The current state is not indicating that!",
+ _class._schemaInjected,
+ _class._state);
+ }
+
+ /**
+ * Tests the injection of a valid schema on a QpidClass.
+ *
+ * <br>precondition : a valid arguments is injected on the qpid class.
+ * <br>postcondition : class definition is built successfully.
+ */
+ public void testSchemaInjectionOk() throws UnableToBuildFeatureException
+ {
+ _class = new QpidClass(TestConstants.EXCHANGE_CLASS_NAME,TestConstants.HASH,_package)
+ {
+ @Override
+ void requestSchema() throws Exception
+ {
+ // DO NOTHING : QMan is not running and therefore the schema will be manually injected.
+ }
+
+ @Override
+ void updateInstanceWithConfigurationData(QManManagedObject instance, byte[] rawData)
+ {
+ // DO NOTHING Given raw data is not valid so it cannot be converted.
+ }
+ };
+
+ // Incoming configuration data : that will fire the schema request and a state change
+ // from schema-not-requested to schema-requested-but-not-injected
+ _class.addConfigurationData(TestConstants.OBJECT_ID, TestConstants.TEST_RAW_DATA);
+
+ // I must be sure that what is obvious for me it's obvious for QMan... :)
+ assertSame(
+ "Request schema has been requested but not yet injected. The current state is not indicating that!",
+ _class._schemaRequestedButNotYetInjected,
+ _class._state);
+
+ List<Map<String,Object>> propertyDefinitions = new ArrayList<Map<String,Object>>(2);
+ propertyDefinitions.add(
+ createProperty(
+ TestConstants.AGE_ATTRIBUTE_NAME,
+ 1,
+ TestConstants.YEARS,
+ TestConstants.SAMPLE_MIN_VALUE,
+ TestConstants.SAMPLE_MAX_VALUE,
+ null,
+ TestConstants.AGE_ATTRIBUTE_DESCRIPTION,
+ TestConstants._1,
+ false,
+ TestConstants._0));
+
+ propertyDefinitions.add(
+ createProperty(
+ TestConstants.SURNAME_ATTRIBUTE_NAME,
+ TestConstants.SAMPLE_ACCESS_CODE,
+ null,
+ null,
+ null,
+ TestConstants.SAMPLE_MAX_VALUE,
+ TestConstants.SURNAME_ATTRIBUTE_DESCRIPTION,
+ TestConstants._1,
+ true,
+ TestConstants._1));
+
+ _class.setSchema(propertyDefinitions, TestConstants.EMPTY_STATISTICS_SCHEMA, TestConstants.EMPTY_METHODS_SCHEMA);
+
+ assertEquals(2,_class._properties.size());
+
+ QpidProperty property = _class._properties.get(TestConstants.AGE_ATTRIBUTE_NAME);
+ assertEquals(TestConstants.AGE_ATTRIBUTE_NAME,property.getName());
+ assertEquals(AccessMode.RC,property.getAccessMode());
+ assertEquals(TestConstants.YEARS,property.getUnit());
+ assertEquals(TestConstants.SAMPLE_MIN_VALUE,property.getMinValue());
+ assertEquals(TestConstants.SAMPLE_MAX_VALUE,property.getMaxValue());
+ assertEquals(Integer.MIN_VALUE,property.getMaxLength());
+ assertEquals(TestConstants.AGE_ATTRIBUTE_DESCRIPTION,property.getDescription());
+ assertEquals(Short.class,property.getJavaType());
+ assertFalse(property.isOptional());
+
+ property = _class._properties.get(TestConstants.SURNAME_ATTRIBUTE_NAME);
+ assertEquals(TestConstants.SURNAME_ATTRIBUTE_NAME,property.getName());
+ assertEquals(AccessMode.RC,property.getAccessMode());
+ assertNull(property.getUnit());
+ assertEquals(Integer.MIN_VALUE,property.getMinValue());
+ assertEquals(Integer.MIN_VALUE,property.getMaxValue());
+ assertEquals(TestConstants.SAMPLE_MAX_VALUE,property.getMaxLength());
+ assertEquals(TestConstants.SURNAME_ATTRIBUTE_DESCRIPTION,property.getDescription());
+ assertEquals(Short.class,property.getJavaType());
+ assertTrue(property.isOptional());
+
+ MBeanInfo mbeanInfo = _class._metadata;
+ assertEquals(TestConstants.EXCHANGE_CLASS_NAME,mbeanInfo.getClassName());
+
+ MBeanAttributeInfo [] attributes = mbeanInfo.getAttributes();
+ assertEquals(2,attributes.length);
+
+ MBeanAttributeInfo attribute = attributes[0];
+ assertEquals(TestConstants.AGE_ATTRIBUTE_NAME,attribute.getName());
+ assertEquals(TestConstants.AGE_ATTRIBUTE_DESCRIPTION,attribute.getDescription());
+ assertFalse(attribute.isWritable());
+ assertTrue(attribute.isReadable());
+ assertEquals(Short.class.getName(),attribute.getType());
+
+ attribute = attributes[1];
+ assertEquals(TestConstants.SURNAME_ATTRIBUTE_NAME,attribute.getName());
+ assertEquals(TestConstants.SURNAME_ATTRIBUTE_DESCRIPTION,attribute.getDescription());
+ assertFalse(attribute.isWritable());
+ assertTrue(attribute.isReadable());
+ assertEquals(Short.class.getName(),attribute.getType());
+ }
+
+ /**
+ * Tests the behaviour of the class when a schema request can't be made.
+ *
+ * <br>precondition : class must be in "schema-not-requested" state when incoming data arrives.
+ * <br>postcondition : no exception is thrown and no state transition happens.
+ */
+ public void testStateChange_withRequestSchemaFailure()
+ {
+ _class= new QpidClass(TestConstants.EXCHANGE_CLASS_NAME,TestConstants.HASH,_package)
+ {
+ @Override
+ void requestSchema() throws Exception {
+ throw new Exception();
+ }
+
+ @Override
+ void setSchema(
+ List<Map<String, Object>> propertyDefinitions,
+ List<Map<String, Object>> statisticDefinitions,
+ List<MethodOrEventDataTransferObject> methodDefinitions) throws UnableToBuildFeatureException
+ {
+ }
+ };
+
+ assertSame(
+ "Initial state must be schema-not-requested.",
+ _class._schemaNotRequested,
+ _class._state);
+
+ _class.addInstrumentationData(TestConstants.OBJECT_ID, TestConstants.TEST_RAW_DATA);
+
+ assertSame(
+ "Current state must be still schema-not-requested.",
+ _class._schemaNotRequested,
+ _class._state);
+ }
+
+ /**
+ * Tests the behaviour of the class when a schema injection fails.
+ *
+ * <br>precondition : class must be in "schema-not-requested" state when incoming data arrives.
+ * <br>postcondition : an exception is thrown and no state transition happens.
+ */
+ public void testStateChange_withSchemaInjectionFailure()
+ {
+ _class = new QpidClass(TestConstants.EXCHANGE_CLASS_NAME,TestConstants.HASH,_package)
+ {
+ @Override
+ void requestSchema() throws Exception
+ {
+ // DO NOTHING.
+ }
+
+ @Override
+ void setSchema(List<Map<String, Object>> propertyDefinitions,
+ List<Map<String, Object>> statisticDefinitions,
+ List<MethodOrEventDataTransferObject> methodDefinitions)
+ throws UnableToBuildFeatureException
+ {
+ throw new UnableToBuildFeatureException("");
+ }
+ };
+
+ assertSame(
+ "Initial state must be schema-not-requested.",
+ _class._schemaNotRequested,
+ _class._state);
+
+ _class.addInstrumentationData(TestConstants.OBJECT_ID, TestConstants.TEST_RAW_DATA);
+
+ assertSame(
+ "Request schema has been requested but not yet injected. The current state is not indicating that!",
+ _class._schemaRequestedButNotYetInjected,
+ _class._state);
+
+ try {
+ _class.setSchema(
+ TestConstants.EMPTY_PROPERTIES_SCHEMA,
+ TestConstants.EMPTY_STATISTICS_SCHEMA,
+ TestConstants.EMPTY_METHODS_SCHEMA);
+ fail("If we are here something was wrong becuase the setSchema() of this event is throwing an exception...");
+ } catch (UnableToBuildFeatureException expected) {
+ assertSame(
+ "Request schema has been requested but not yet injected. The current state is not indicating that!",
+ _class._schemaRequestedButNotYetInjected,
+ _class._state);
+ }
+ }
+
+ private Map<String,Object> createProperty(
+ String name,
+ Integer accessCode,
+ String unit,
+ Integer min,
+ Integer max,
+ Integer maxLength,
+ String description,
+ Integer type,
+ boolean optional,
+ Integer index)
+ {
+ Map <String,Object> result = new HashMap<String, Object>();
+ result.put(QpidFeatureBuilder.Attribute.name.name(),name);
+ result.put(QpidFeatureBuilder.Attribute.access.name(), accessCode);
+
+ if (unit != null)
+ {
+ result.put(QpidFeatureBuilder.Attribute.unit.name(),unit);
+ }
+
+ if (min != null)
+ {
+ result.put(QpidFeatureBuilder.Attribute.min.name(), min);
+ }
+
+ if (max != null)
+ {
+ result.put(QpidFeatureBuilder.Attribute.max.name(),max);
+ }
+
+ if (maxLength != null)
+ {
+ result.put(QpidFeatureBuilder.Attribute.maxlen.name(),maxLength);
+ }
+
+ result.put(QpidFeatureBuilder.Attribute.desc.name(), description);
+ result.put(QpidFeatureBuilder.Attribute.type.name(), type);
+ result.put(QpidFeatureBuilder.Attribute.optional.name(),optional ? 1 : 0);
+
+ if (index != null)
+ {
+ result.put(QpidFeatureBuilder.Attribute.index.name(), index);
+ }
+ return result;
+ }
+}
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidEventTest.java b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidEventTest.java
new file mode 100644
index 0000000000..4b36d9e5cc
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidEventTest.java
@@ -0,0 +1,293 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.management.TestConstants;
+import org.apache.qpid.management.configuration.ConfigurationException;
+import org.apache.qpid.management.configuration.Configurator;
+import org.apache.qpid.management.domain.model.QpidEvent.QManManagedEvent;
+
+/**
+ * Test case for qpid class entity.
+ *
+ * @author Andrea Gazzarini
+ */
+public class QpidEventTest extends TestCase
+{
+ private QpidEvent _event;
+ private QpidPackage _qpidPackage;
+
+ @Override
+ protected void setUp () throws Exception
+ {
+ _qpidPackage = new QpidPackage(TestConstants.QPID_PACKAGE_NAME,TestConstants.DOMAIN_MODEL);
+ _event = new QpidEvent(TestConstants.BIND_EVENT_NAME,TestConstants.HASH,_qpidPackage);
+ }
+
+ /**
+ * Tests the execution of the createEventInstance() method.
+ * Basically it tests the addition of a new event instance.
+ *
+ * <br>precondition: event deifinition has no object instances.
+ * <br>precondition : event definition contains the new object instance.
+ */
+ public void testCreateEventInstance()
+ {
+ assertTrue(
+ "A just created event should be empty. I mean there shouldn't be event instances inside.",
+ _event.hasNoInstances());
+
+ QManManagedEvent instance = createEventInstance();
+
+ assertFalse (
+ "Now a new instance should be there...",
+ _event.hasNoInstances());
+
+ assertEquals(TestConstants.TEST_RAW_DATA,instance._rawEventData);
+ assertEquals(TestConstants.NOW,instance._timestamp);
+ assertEquals(TestConstants.SEVERITY, instance._severity);
+ }
+
+ /**
+ * Tests the internal state change of an event definition.
+ */
+ public void testStateChange() throws UnableToBuildFeatureException
+ {
+ // Let's override this class because this is not an online tests and therefore
+ // QMan is not supposed to be up.
+ _event = new QpidEvent(TestConstants.BIND_EVENT_NAME,TestConstants.HASH,_qpidPackage)
+ {
+ @Override
+ void requestSchema() throws Exception {
+ // Do Nothing.
+ }
+
+ @Override
+ void setSchema(List<Map<String, Object>> argumentDefinitions)throws UnableToBuildFeatureException {
+ _state = _schemaInjected;
+ }
+ };
+
+ assertSame(
+ "Initial state doesn't match.",
+ _event._schemaNotRequested,
+ _event._state);
+
+ _event.addEventData(TestConstants.TEST_RAW_DATA, TestConstants.NOW, TestConstants.SEVERITY);
+
+ assertSame(
+ "Request schema has been requested but not yet injected. The current state is not indicating that!",
+ _event._schemaRequestedButNotYetInjected,
+ _event._state);
+
+ _event.setSchema(TestConstants.EMPTY_ARGUMENTS_SCHEMA);
+
+ assertSame(
+ "Request schema has been injected. The current state is not indicating that!",
+ _event._schemaInjected,
+ _event._state);
+ }
+
+ /**
+ * Tests the injection of a valid schema on a QpidEvent.
+ *
+ * <br>precondition : a valid arguments is injected on the qpid event.
+ * <br>postcondition : event definition is built successfully.
+ */
+ public void testSchemaInjectionOK() throws UnableToBuildFeatureException, ConfigurationException, InstanceNotFoundException, MBeanException, ReflectionException
+ {
+ _event = new QpidEvent(TestConstants.BIND_EVENT_NAME,TestConstants.HASH,_qpidPackage)
+ {
+ @Override
+ void requestSchema() throws Exception
+ {
+ // DO NOTHING : QMan is not running and therefore the schema will be manually injected.
+ }
+
+ @Override
+ void updateEventInstanceWithData(QManManagedEvent instance)
+ {
+ // DO NOTHING : otherwise we should supply a valid raw data to be converted. ;-)
+ }
+ };
+
+ Configurator configurator = new Configurator();
+ configurator.configure();
+
+ List<Map<String,Object>> arguments = new ArrayList<Map<String, Object>>();
+ arguments.add(createArgument(TestConstants.AGE_ATTRIBUTE_NAME, TestConstants.AGE_ATTRIBUTE_DESCRIPTION));
+ arguments.add(createArgument(TestConstants.SURNAME_ATTRIBUTE_NAME, TestConstants.SURNAME_ATTRIBUTE_DESCRIPTION));
+
+ // Incoming data : that will fire the schema request and a state change from schema-not-requested to schema-requested-but-not-injected
+ _event.addEventData(TestConstants.TEST_RAW_DATA, TestConstants.NOW, TestConstants.SEVERITY);
+
+ // I must be sure that what is obvious for me it's obvious for QMan... :)
+ assertSame(
+ "Request schema has been requested but not yet injected. The current state is not indicating that!",
+ _event._schemaRequestedButNotYetInjected,
+ _event._state);
+
+ // Inject schema
+ _event.setSchema(arguments);
+
+ // Arguments must be 2 + 2 (severity)
+ assertEquals(2,_event._arguments.size());
+
+ QpidProperty argument = _event._arguments.get(TestConstants.AGE_ATTRIBUTE_NAME);
+ assertEquals(TestConstants.AGE_ATTRIBUTE_NAME,argument.getName());
+ assertEquals(AccessMode.RO,argument.getAccessMode());
+ assertEquals(TestConstants.AGE_ATTRIBUTE_DESCRIPTION,argument.getDescription());
+ assertEquals(Short.class,argument.getJavaType());
+ assertFalse(argument.isOptional());
+
+ argument = _event._arguments.get(TestConstants.SURNAME_ATTRIBUTE_NAME);
+ assertEquals(TestConstants.SURNAME_ATTRIBUTE_NAME,argument.getName());
+ assertEquals(AccessMode.RO,argument.getAccessMode());
+ assertEquals(TestConstants.SURNAME_ATTRIBUTE_DESCRIPTION,argument.getDescription());
+ assertEquals(Short.class,argument.getJavaType());
+ assertFalse(argument.isOptional());
+
+ assertEquals(1,_event._eventInstances.size());
+
+ JmxService service = new JmxService();
+ Set<ObjectName> objectNames = service.getEventMBeans();
+
+ assertEquals(1,objectNames.size());
+ }
+
+ /**
+ * Tests the behaviour of the event class when a schema request can't be made.
+ *
+ * <br>precondition : event must be in "schema-not-requested" state when incoming data arrives.
+ * <br>postcondition : no exception is thrown and no state transition happens.
+ */
+ public void testStateChange_withRequestSchemaFailure()
+ {
+ _event = new QpidEvent(TestConstants.BIND_EVENT_NAME,TestConstants.HASH,_qpidPackage)
+ {
+ @Override
+ void requestSchema() throws Exception {
+ throw new Exception();
+ }
+
+ @Override
+ void setSchema(List<Map<String, Object>> argumentDefinitions)throws UnableToBuildFeatureException {
+ _state = _schemaInjected;
+ }
+ };
+
+ assertSame(
+ "Initial state must be schema-not-requested.",
+ _event._schemaNotRequested,
+ _event._state);
+
+ _event.addEventData(TestConstants.TEST_RAW_DATA, TestConstants.NOW, TestConstants.SEVERITY);
+
+ assertSame(
+ "Current state must be still schema-not-requested.",
+ _event._schemaNotRequested,
+ _event._state);
+ }
+
+ /**
+ * Tests the behaviour of the event class when a schema injection fails.
+ *
+ * <br>precondition : event must be in "schema-not-requested" state when incoming data arrives.
+ * <br>postcondition : an exception is thrown and no state transition happens.
+ */
+ public void testStateChange_withSchemaInjectionFailure()
+ {
+ _event = new QpidEvent(TestConstants.BIND_EVENT_NAME,TestConstants.HASH,_qpidPackage)
+ {
+ @Override
+ void requestSchema() throws Exception {
+ // DO NOTHING.
+ }
+
+ @Override
+ void setSchema(List<Map<String, Object>> argumentDefinitions)throws UnableToBuildFeatureException {
+ throw new UnableToBuildFeatureException("");
+ }
+ };
+
+ assertSame(
+ "Initial state must be schema-not-requested.",
+ _event._schemaNotRequested,
+ _event._state);
+
+ _event.addEventData(TestConstants.TEST_RAW_DATA, TestConstants.NOW, TestConstants.SEVERITY);
+
+ assertSame(
+ "Request schema has been requested but not yet injected. The current state is not indicating that!",
+ _event._schemaRequestedButNotYetInjected,
+ _event._state);
+
+ try {
+ _event.setSchema(TestConstants.EMPTY_ARGUMENTS_SCHEMA);
+ fail("If we are here something was wrong becuase the setSchema() of this event is throwing an exception...");
+ } catch (UnableToBuildFeatureException expected) {
+ assertSame(
+ "Request schema has been requested but not yet injected. The current state is not indicating that!",
+ _event._schemaRequestedButNotYetInjected,
+ _event._state);
+ }
+ }
+
+ /**
+ * Factory method for qpid managed event instances.
+ *
+ * @return a new QpidManagedEvent with test data inside.
+ */
+ private QManManagedEvent createEventInstance()
+ {
+ return _event.createEventInstance(
+ TestConstants.TEST_RAW_DATA,
+ TestConstants.NOW,
+ TestConstants.SEVERITY);
+ }
+
+ /**
+ * Factory method for event argument.
+ *
+ * @return a new argument metadata.
+ */
+ private Map<String,Object> createArgument(String name,String desc)
+ {
+ Map <String,Object> argument = new HashMap<String, Object>();
+ argument.put(QpidFeatureBuilder.Attribute.name.name(),name);
+ argument.put(QpidFeatureBuilder.Attribute.desc.name(), desc);
+ argument.put(QpidFeatureBuilder.Attribute.type.name(), TestConstants._1);
+ return argument;
+ }
+}
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidMethodBuilderTest.java b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidMethodBuilderTest.java
new file mode 100644
index 0000000000..06dc35b0b1
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidMethodBuilderTest.java
@@ -0,0 +1,147 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.dir;
+import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.name;
+import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.type;
+import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.unit;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.MBeanOperationInfo;
+
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.domain.handler.impl.MethodOrEventDataTransferObject;
+import org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute;
+
+/**
+ * Test case for Qpid Statistic builder.
+ *
+ * @author Andrea Gazzarini
+ */
+public class QpidMethodBuilderTest extends BaseQpidFeatureBuilderTestCase
+{
+ private final static Integer ARG_COUNT = 3;
+ private MethodOrEventDataTransferObject _methodDefinition;
+
+ private List<Map<String,Object>> _argumentsDefinitons = new ArrayList<Map<String, Object>>();
+
+ @Override
+ protected void setUp () throws Exception
+ {
+ super.setUp();
+ _featureDefinition.put(Names.ARG_COUNT_PARAM_NAME, ARG_COUNT);
+
+ Map<String,Object> arg1 = new HashMap<String,Object>();
+ arg1.put(name.name(), "arg1");
+ arg1.put(type.name(),1);
+ arg1.put(dir.name(),Direction.I.name());
+ arg1.put(unit.name(), "bytes");
+
+ Map<String,Object> arg2 = new HashMap<String,Object>();
+ arg2.put(name.name(), "arg2");
+ arg2.put(type.name(),1);
+ arg2.put(dir.name(),Direction.O.name());
+ arg2.put(unit.name(), "bytes");
+
+ Map<String,Object> arg3 = new HashMap<String,Object>();
+ arg3.put(name.name(), "arg3");
+ arg3.put(type.name(),1);
+ arg3.put(dir.name(),Direction.IO.name());
+ arg3.put(unit.name(), "bytes");
+
+ /*
+ dir yes no yes Direction code for method arguments
+ unit yes yes yes Units for numeric values (i.e. seconds, bytes, etc.)
+ min yes no yes Minimum value for numerics
+ max yes no yes Maximum value for numerics
+ maxlen yes no yes Maximum length for strings
+ desc yes yes yes Description of the argument
+ default yes no yes Default value for the argument
+ */
+ _argumentsDefinitons.add(arg1);
+ _argumentsDefinitons.add(arg2);
+
+ _methodDefinition = new MethodOrEventDataTransferObject(_featureDefinition,_argumentsDefinitons);
+ _builder = QpidFeatureBuilder.createMethodBuilder(_methodDefinition);
+ }
+
+ /**
+ * Tests the build process for a statistic when the definition map doesn't contains type attribute.
+ *
+ * <br>precondition: definition map doesn't contains type attribute.
+ * <br>postcondition : an exception should be thrown indicating the failure. That exception must contain the name of the
+ * missing attribute.
+ */
+ public void testMethodBuilderKO_WithMissingName()
+ {
+ internalTestForMissingMandatoryAttribute(Attribute.name);
+ }
+
+ /**
+ * Tests the build process for a statistic when the definition map doesn't contain type, name, index & optional attributes.
+ *
+ * <br>precondition: definition map doesn't contain type, name, index & optional attributes.
+ * <br>postcondition : an exception should be thrown indicating the failure. That exception must contain the name of the
+ * missing attributes.
+ */
+ public void testMethodBuilderOK_WithMissingUnit() throws UnableToBuildFeatureException
+ {
+ internalTestForMissingOptionalAttribute(Attribute.unit);
+ }
+
+ /**
+ * Tests the build process for a statistic when the definition map doesn't unit attribute.
+ * Note that this attribute is optional and therefore the build must succeed.
+ *
+ * <br>precondition: definition map doesn't contain unit attribute.
+ * <br>postcondition : no exception is thrown and the statistic is built.
+ */
+ public void testMethodBuilderOK_WithMissingDescription() throws UnableToBuildFeatureException
+ {
+ internalTestForMissingOptionalAttribute(Attribute.desc);
+ }
+
+ /**
+ * Tests the build process for a statistic when the definition map contains valid values.
+ *
+ * <br>precondition : the statistic definiton map contains valid values.
+ * <br>postcondition : no exception is thrown and the statistisc is built as expected.
+ */
+ public void testMethodBuilderOK() throws UnableToBuildFeatureException
+ {
+ _builder.build();
+
+ QpidMethod method = (QpidMethod) _builder.getQpidFeature();
+ MBeanOperationInfo info = (MBeanOperationInfo) _builder.getManagementFeature();
+
+ assertEquals(NAME,method.getName());
+
+ assertEquals(DESCRIPTION,method.getDescription());
+
+ assertEquals(method.getDescription(),info.getDescription());
+ assertEquals(method.getName(),info.getName());
+ }
+}
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidNumberPropertyTest.java b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidNumberPropertyTest.java
new file mode 100644
index 0000000000..374011d150
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidNumberPropertyTest.java
@@ -0,0 +1,171 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.management.configuration.Configurator;
+import org.apache.qpid.management.domain.model.type.Uint8;
+
+public class QpidNumberPropertyTest extends TestCase
+{
+ private QpidProperty _property;
+ private Long _value = 55432L;
+
+ @Override
+ protected void setUp () throws Exception
+ {
+ Configurator configurator = new Configurator();
+ configurator.configure();
+ _property = new QpidProperty();
+ _property.setName("average");
+ _property.setAccessMode(AccessMode.RW);
+ _property.setType(new Uint8());
+ }
+
+ /**
+ * Tests the validation of a qpid property when the type is a number and no constraint has been set.
+ *
+ * <br>precondition : property type is a string, no constraint has been set.
+ * <br>postcondition : no exception is thrown and the validation succeeds.
+ */
+ public void testValidationWithoutConstraints() {
+ try
+ {
+ _property.validate(_value);
+ } catch (ValidationException notExpected)
+ {
+ fail("If no constraint has been set on this property why the validation is failing?");
+ }
+ }
+
+ /**
+ * Tests the validation of a qpid property when the type is a number and a max value constraint has been set.
+ *
+ * <br>precondition : property type is a number, max value has been set and property value is greater than max value.
+ * <br>postcondition : an exception is thrown indicating the validation failure.
+ */
+ public void testValidationKO_withMaxValue() {
+ int maxValue = (int)(_value-1);
+ _property.setMaxValue(maxValue);
+
+ try
+ {
+ _property.validate(_value);
+ fail("The given value is violating the installed constraint so an exception must be thrown.");
+ } catch (ValidationException expected)
+ {
+ assertEquals(ValidationException.MAX_VALUE,expected.getConstraintName());
+ assertEquals(maxValue,expected.getConstraintValue());
+ assertEquals((double)_value,expected.getFeatureValue());
+ assertEquals(_property.getName(),expected.getFeatureName());
+ }
+ }
+
+ /**
+ * Tests the validation of a qpid property when the type is a number and a min value constraint has been set.
+ *
+ * <br>precondition : property type is a number, min value has been set and property value is lesser than min value.
+ * <br>postcondition : an exception is thrown indicating the validation failure.
+ */
+ public void testValidationKO_withMinValue() {
+ int minValue = (int)(_value+1);
+ _property.setMinValue(minValue);
+
+ try
+ {
+ _property.validate(_value);
+ fail("The given value is violating the installed constraint so an exception must be thrown.");
+ } catch (ValidationException expected)
+ {
+ assertEquals(ValidationException.MIN_VALUE,expected.getConstraintName());
+ assertEquals(minValue,expected.getConstraintValue());
+ assertEquals((double)_value,expected.getFeatureValue());
+ assertEquals(_property.getName(),expected.getFeatureName());
+ }
+ }
+
+
+ /**
+ * Tests the validation of a qpid property when the number is a string and the property value is null.
+ *
+ * <br>precondition : property type is a number and property value is null..
+ * <br>postcondition : no exception is thrown. That is : the validation succeeds.
+ */
+ public void testValidationOK_withNullValue() {
+ try
+ {
+ _property.validate(null);
+ } catch (ValidationException notExpected)
+ {
+ fail("No constraint has been violated so validate() shouldn't raise an exception.");
+ }
+
+ _property.setMinValue(1);
+ _property.setMaxValue(10);
+
+ try
+ {
+ _property.validate(null);
+ } catch (ValidationException notExpected)
+ {
+ fail("No constraint has been violated so validate() shouldn't raise an exception.");
+ }
+ }
+
+ /**
+ * Tests the validation of a qpid property when the type is a number and a max / min constraints have been set.
+ *
+ * <br>precondition : property type is a number, max / min constraint have been set and property value is wrong.
+ * <br>postcondition : an exception is thrown indicating the validation failure.
+ */
+ public void testValidationOK_withMinAndMaxConstraint() {
+ int minValue = (int)(_value+1);
+ int maxValue = (int)(_value-1);
+ _property.setMinValue(minValue);
+ _property.setMaxValue(maxValue);
+
+ try
+ {
+ _property.validate(_value);
+ fail("The given value is violating the installed constraint so an exception must be thrown.");
+ } catch (ValidationException expected)
+ {
+ assertEquals(ValidationException.MIN_VALUE,expected.getConstraintName());
+ assertEquals(minValue,expected.getConstraintValue());
+ assertEquals((double)_value,expected.getFeatureValue());
+ assertEquals(_property.getName(),expected.getFeatureName());
+ }
+
+ _property.setMinValue(0);
+ try
+ {
+ _property.validate(_value);
+ fail("The given value is violating the installed constraint so an exception must be thrown.");
+ } catch (ValidationException expected)
+ {
+ assertEquals(ValidationException.MAX_VALUE,expected.getConstraintName());
+ assertEquals(maxValue,expected.getConstraintValue());
+ assertEquals((double)_value,expected.getFeatureValue());
+ assertEquals(_property.getName(),expected.getFeatureName());
+ }
+ }
+}
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidPackageTest.java b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidPackageTest.java
new file mode 100644
index 0000000000..b7eb9055ba
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidPackageTest.java
@@ -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 org.apache.qpid.management.domain.model;
+
+import org.apache.qpid.management.TestConstants;
+
+/**
+ * Test case for Qpid package entity.
+ *
+ * @author Andrea Gazzarini
+ */
+public class QpidPackageTest extends BaseDomainModelTestCase
+{
+ private QpidPackage _qpidPackage;
+
+ @Override
+ protected void setUp () throws Exception
+ {
+ _qpidPackage = new QpidPackage(TestConstants.QPID_PACKAGE_NAME, TestConstants.DOMAIN_MODEL);
+ }
+
+ /**
+ * Tests the association of a new class with a qpid package.
+ *
+ * <br>precondition : the package is not associated with any class.
+ * <br>postcondition : the package is now associated with the given class.
+ */
+ public void testAddClass() throws UnableToBuildFeatureException {
+ assertFalse(_qpidPackage.alreadyContainsClassDefinition(TestConstants.EXCHANGE_CLASS_NAME, TestConstants.HASH));
+
+ _qpidPackage.getQpidClass(TestConstants.EXCHANGE_CLASS_NAME, TestConstants.HASH, true);
+
+ assertTrue(_qpidPackage.alreadyContainsClassDefinition(TestConstants.EXCHANGE_CLASS_NAME, TestConstants.HASH));
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidPropertyBuilderTest.java b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidPropertyBuilderTest.java
new file mode 100644
index 0000000000..8ad177645c
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidPropertyBuilderTest.java
@@ -0,0 +1,269 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.access;
+import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.index;
+import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.max;
+import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.min;
+import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.optional;
+import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.type;
+import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.unit;
+
+import javax.management.MBeanAttributeInfo;
+
+import org.apache.qpid.management.configuration.UnknownTypeCodeException;
+import org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute;
+
+/**
+ * Test case for Qpid Property builder.
+ *
+ * @author Andrea Gazzarini
+ */
+public class QpidPropertyBuilderTest extends BaseQpidFeatureBuilderTestCase
+{
+ private final static Integer MIN = 0;
+ private final static Integer MAX = 120;
+ private final static String UNIT = "bytes";
+
+ private Integer _access;
+
+ @Override
+ protected void setUp () throws Exception
+ {
+ super.setUp();
+
+ _access = 1;
+ _featureDefinition.put(access.name(), _access);
+ _featureDefinition.put(unit.name(),UNIT);
+ _featureDefinition.put(min.name(), MIN);
+ _featureDefinition.put(max.name(),MAX);
+
+ _featureDefinition.put(type.name(), 1);
+ _featureDefinition.put(optional.name(),0);
+ _featureDefinition.put(index.name(), 0);
+
+ _builder = QpidFeatureBuilder.createPropertyBuilder(_featureDefinition);
+ }
+
+ /**
+ * Tests the build process for a statistic when the definition map contains an unknown type code.
+ *
+ * <br>precondition : the statistic definiton map contains an unknown type code.
+ * <br>postcondition : an exception is thrown indicating the failure.
+ */
+ public void testStatisticBuilderKO_WithUnknownType()
+ {
+ int unknownTypeCode =999;
+ try
+ {
+ _featureDefinition.put(type.name(), unknownTypeCode);
+ _builder.build();
+ fail("An unknown type code should raise an exception to indicate a failure.");
+ } catch (UnableToBuildFeatureException expected)
+ {
+ assertEquals(unknownTypeCode,((UnknownTypeCodeException)expected.getCause()).getCode());
+ }
+ }
+
+ /**
+ * Tests the build process for a statistic when the definition map contains a null value for a metadata attribute.
+ *
+ * <br>precondition : the statistic definiton map contains a null value for a metadata attribute.
+ * <br>postcondition : an exception is thrown indicating the failure.
+ */
+ public void testMethodBuilderKO_WithNullMetadataValue()
+ {
+ try
+ {
+ _featureDefinition.put(type.name(), null);
+ _builder.build();
+ fail("An null value for a metadata attribute should raise an exception to indicate a failure.");
+ } catch (UnableToBuildFeatureException expected)
+ {
+ assertTrue(expected.getCause() instanceof NullPointerException);
+ }
+ }
+
+ /**
+ * Tests the build process for a property when the definition map contains an invalid metadata type.
+ *
+ * <br>precondition : the property definiton map contains a wrong type for a metadata attribute.
+ * <br>postcondition : an exception is thrown indicating the failure.
+ */
+ public void testPropertyBuilderKO_WithClassCastException()
+ {
+ try
+ {
+ _featureDefinition.put(access.name(), new String("a"));
+ _builder.build();
+ fail("A wrong metadata attribute type should raise an exception to indicate a failure.");
+ } catch (UnableToBuildFeatureException expected)
+ {
+ assertTrue(expected.getCause() instanceof ClassCastException);
+ }
+ }
+
+ /**
+ * Tests the build process for a property when the definition map contains an unknown type code.
+ *
+ * <br>precondition : the property definiton map contains an unknown type code.
+ * <br>postcondition : an exception is thrown indicating the failure.
+ */
+ public void testPropertyBuilderKO_WithUnknownType()
+ {
+ int unknownTypeCode = 999;
+ try
+ {
+ _featureDefinition.put(type.name(), unknownTypeCode);
+ _builder.build();
+ fail("An unknown type code should raise an exception to indicate a failure.");
+ } catch (UnableToBuildFeatureException expected)
+ {
+ assertEquals(unknownTypeCode,((UnknownTypeCodeException)expected.getCause()).getCode());
+ }
+ }
+
+ /**
+ * Tests the build process for a property when the definition map doesn't contains type attribute.
+ *
+ * <br>precondition: definition map doesn't contains type attribute.
+ * <br>postcondition : an exception should be thrown indicating the failure. That exception must contain the name of the
+ * missing attribute.
+ */
+ public void testPropertyBuilderKO_WithMissingType()
+ {
+ internalTestForMissingMandatoryAttribute(Attribute.type);
+ }
+
+ /**
+ * Tests the build process for a property when the definition map doesn't contain type & name attributes.
+ *
+ * <br>precondition: definition map doesn't contain type & name attributes.
+ * <br>postcondition : an exception should be thrown indicating the failure. That exception must contain the name of the
+ * missing attributes.
+ */
+ public void testPropertyBuilderKO_WithMissingTypeAndName()
+ {
+ internalTestForMissingMandatoryAttribute(Attribute.type, Attribute.name);
+ }
+
+ /**
+ * Tests the build process for a property when the definition map doesn't contain type & name & index attributes.
+ *
+ * <br>precondition: definition map doesn't contain type & name & index attributes.
+ * <br>postcondition : an exception should be thrown indicating the failure. That exception must contain the name of the
+ * missing attributes.
+ */
+ public void testPropertyBuilderKO_WithMissingTypeAndNameAndIndex()
+ {
+ internalTestForMissingMandatoryAttribute(Attribute.type, Attribute.name,Attribute.index);
+ }
+
+ /**
+ * Tests the build process for a property when the definition map doesn't contain type, name, index & optional attributes.
+ *
+ * <br>precondition: definition map doesn't contain type, name, index & optional attributes.
+ * <br>postcondition : an exception should be thrown indicating the failure. That exception must contain the name of the
+ * missing attributes.
+ */
+ public void testPropertyBuilderKO_WithMissingTypeAndNameAndIndexAndOptional()
+ {
+ internalTestForMissingMandatoryAttribute(Attribute.type, Attribute.name,Attribute.index,Attribute.optional);
+ }
+
+ /**
+ * Tests the build process for a property when the definition map doesn't contain type, name, index, optional and access
+ * attributes.
+ *
+ * <br>precondition: definition map doesn't contain type, name, index, optional and access attributes.
+ * <br>postcondition : an exception should be thrown indicating the failure. That exception must contain the name of the
+ * missing attributes.
+ */
+ public void testPropertyBuilderKO_WithMissingTypeAndNameAndIndexAndOptionalAndAccess()
+ {
+ internalTestForMissingMandatoryAttribute(Attribute.type, Attribute.name,Attribute.index,Attribute.optional,Attribute.access);
+ }
+
+ /**
+ * Tests the build process for a property when the definition map doesn't unit attribute.
+ * Note that this attribute is optional and therefore the build must succeed.
+ *
+ * <br>precondition: definition map doesn't contain unit attribute.
+ * <br>postcondition : no exception is thrown and the property is built.
+ */
+ public void testBuilderOK_WithMissingUnit() throws UnableToBuildFeatureException
+ {
+ internalTestForMissingOptionalAttribute(Attribute.unit);
+ }
+
+ /**
+ * Tests the build process for a property when the definition map doesn't min and max attributes.
+ * Note that those attributes are optional and therefore the build must succeed.
+ *
+ * <br>precondition: definition map doesn't contain min and max attributes.
+ * <br>postcondition : no exception is thrown and the property is built.
+ */
+ public void testBuilderOK_WithMissingMinAndMax() throws UnableToBuildFeatureException
+ {
+ internalTestForMissingOptionalAttribute(Attribute.min,Attribute.max);
+ }
+
+ /**
+ * Tests the build process for a property when the definition map doesn't description attribute.
+ * Note that this attribute is optional and therefore the build must succeed.
+ *
+ * <br>precondition: definition map doesn't contain description attribute.
+ * <br>postcondition : no exception is thrown and the property is built.
+ */
+ public void testBuilderOK_WithMissingDescription() throws UnableToBuildFeatureException
+ {
+ internalTestForMissingOptionalAttribute(Attribute.desc);
+ }
+
+ /**
+ * Tests the build process for a property when the definition map contains valid values.
+ *
+ * <br>precondition : the property definiton map contains valid values.
+ * <br>postcondition : no exception is thrown and the property is built as expected.
+ */
+ public void testPropertyBuilderOK() throws UnableToBuildFeatureException
+ {
+ _builder.build();
+
+ QpidProperty property = (QpidProperty) _builder.getQpidFeature();
+ MBeanAttributeInfo info = (MBeanAttributeInfo) _builder.getManagementFeature();
+
+ assertEquals(NAME,property.getName());
+ assertEquals(AccessMode.RC,property.getAccessMode());
+ assertEquals(UNIT,property.getUnit());
+ assertEquals(MIN.intValue(),property.getMinValue());
+ assertEquals(MAX.intValue(),property.getMaxValue());
+ assertEquals(Integer.MIN_VALUE,property.getMaxLength());
+ assertEquals(DESCRIPTION,property.getDescription());
+ assertEquals(Short.class,property.getJavaType());
+ assertFalse(property.isOptional());
+
+ assertEquals(property.getDescription(),info.getDescription());
+ assertEquals(property.getName(),info.getName());
+ assertEquals(property.getJavaType().getName(),info.getType());
+ }
+}
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidStatisticBuilderTest.java b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidStatisticBuilderTest.java
new file mode 100644
index 0000000000..b7a8540b2d
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidStatisticBuilderTest.java
@@ -0,0 +1,159 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.type;
+import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.unit;
+
+import javax.management.MBeanAttributeInfo;
+
+import org.apache.qpid.management.configuration.UnknownTypeCodeException;
+import org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute;
+
+/**
+ * Test case for Qpid Statistic builder.
+ *
+ * @author Andrea Gazzarini
+ */
+public class QpidStatisticBuilderTest extends BaseQpidFeatureBuilderTestCase
+{
+ private final static String UNIT = "bytes";
+
+ @Override
+ protected void setUp () throws Exception
+ {
+ super.setUp();
+ _featureDefinition.put(unit.name(),UNIT);
+ _featureDefinition.put(type.name(), 1);
+
+ _builder = QpidFeatureBuilder.createStatisticBuilder(_featureDefinition);
+ }
+
+ /**
+ * Tests the build process for a statistic when the definition map contains an unknown type code.
+ *
+ * <br>precondition : the statistic definiton map contains an unknown type code.
+ * <br>postcondition : an exception is thrown indicating the failure.
+ */
+ public void testStatisticBuilderKO_WithUnknownType()
+ {
+ int unknownTypeCode = 999;
+ try
+ {
+ _featureDefinition.put(type.name(), unknownTypeCode);
+ _builder.build();
+ fail("An unknown type code should raise an exception to indicate a failure.");
+ } catch (UnableToBuildFeatureException expected)
+ {
+ assertEquals(unknownTypeCode,((UnknownTypeCodeException)expected.getCause()).getCode());
+ }
+ }
+
+ /**
+ * Tests the build process for a statistic when the definition map contains a null value for a metadata attribute.
+ *
+ * <br>precondition : the statistic definiton map contains a null value for a metadata attribute.
+ * <br>postcondition : an exception is thrown indicating the failure.
+ */
+ public void testMethodBuilderKO_WithNullMetadataValue()
+ {
+ try
+ {
+ _featureDefinition.put(type.name(), null);
+ _builder.build();
+ fail("An null value for a metadata attribute should raise an exception to indicate a failure.");
+ } catch (UnableToBuildFeatureException expected)
+ {
+ assertTrue(expected.getCause() instanceof NullPointerException);
+ }
+ }
+
+ /**
+ * Tests the build process for a statistic when the definition map doesn't contains type attribute.
+ *
+ * <br>precondition: definition map doesn't contains type attribute.
+ * <br>postcondition : an exception should be thrown indicating the failure. That exception must contain the name of the
+ * missing attribute.
+ */
+ public void testStatisticBuilderKO_WithMissingType()
+ {
+ internalTestForMissingMandatoryAttribute(Attribute.type);
+ }
+
+ /**
+ * Tests the build process for a statistic when the definition map doesn't contain type & name attributes.
+ *
+ * <br>precondition: definition map doesn't contain type & name attributes.
+ * <br>postcondition : an exception should be thrown indicating the failure. That exception must contain the name of the
+ * missing attributes.
+ */
+ public void testStatisticBuilderKO_WithMissingTypeAndName()
+ {
+ internalTestForMissingMandatoryAttribute(Attribute.type, Attribute.name);
+ }
+
+ /**
+ * Tests the build process for a statistic when the definition map doesn't contain type, name, index & optional attributes.
+ *
+ * <br>precondition: definition map doesn't contain type, name, index & optional attributes.
+ * <br>postcondition : an exception should be thrown indicating the failure. That exception must contain the name of the
+ * missing attributes.
+ */
+ public void testStatisticBuilderOK_WithMissingUnit() throws UnableToBuildFeatureException
+ {
+ internalTestForMissingOptionalAttribute(Attribute.unit);
+ }
+
+ /**
+ * Tests the build process for a statistic when the definition map doesn't unit attribute.
+ * Note that this attribute is optional and therefore the build must succeed.
+ *
+ * <br>precondition: definition map doesn't contain unit attribute.
+ * <br>postcondition : no exception is thrown and the statistic is built.
+ */
+ public void testBuilderOK_WithMissingDescription() throws UnableToBuildFeatureException
+ {
+ internalTestForMissingOptionalAttribute(Attribute.desc);
+ }
+
+ /**
+ * Tests the build process for a statistic when the definition map contains valid values.
+ *
+ * <br>precondition : the statistic definiton map contains valid values.
+ * <br>postcondition : no exception is thrown and the statistisc is built as expected.
+ */
+ public void testStatisticBuilderOK() throws UnableToBuildFeatureException
+ {
+ _builder.build();
+
+ QpidStatistic statistic= (QpidStatistic) _builder.getQpidFeature();
+ MBeanAttributeInfo info = (MBeanAttributeInfo) _builder.getManagementFeature();
+
+ assertEquals(NAME,statistic.getName());
+ assertEquals(UNIT,statistic.getUnit());
+ assertEquals(DESCRIPTION,statistic.getDescription());
+ assertEquals(Short.class,statistic.getJavaType());
+
+ assertEquals(statistic.getDescription(),info.getDescription());
+ assertEquals(statistic.getName(),info.getName());
+ assertEquals(statistic.getJavaType().getName(),info.getType());
+ }
+}
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidStringPropertyTest.java b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidStringPropertyTest.java
new file mode 100644
index 0000000000..8aeb7c8550
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidStringPropertyTest.java
@@ -0,0 +1,127 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.management.configuration.Configurator;
+import org.apache.qpid.management.domain.model.type.Str16;
+
+public class QpidStringPropertyTest extends TestCase
+{
+ private QpidProperty _property;
+ private final String _5LettersString = "12345";
+
+ @Override
+ protected void setUp () throws Exception
+ {
+ Configurator configurator = new Configurator();
+ configurator.configure();
+ _property = new QpidProperty();
+ _property.setName("name");
+ _property.setAccessMode(AccessMode.RW);
+ _property.setType(new Str16());
+ }
+
+ /**
+ * Tests the validation of a qpid property when the type is a string and a max length constraint hasn't been set.
+ *
+ * <br>precondition : property type is a string, max length hasn't been set.
+ * <br>postcondition : no exception is thrown. That is : the validation succeeds.
+ */
+ public void testValidationWithoutMaxLength() {
+ try
+ {
+ _property.validate(_5LettersString);
+ } catch (ValidationException notExpected)
+ {
+ fail("No max length has been set on property so validation must succeed.");
+ }
+ }
+
+ /**
+ * Tests the validation of a qpid property when the type is a string and a max length constraint has been set.
+ *
+ * <br>precondition : property type is a string, max length has been set and property value is longer than max length.
+ * <br>postcondition : an exception is thrown indicating the validation failure.
+ */
+ public void testValidationKO_withMaxLength() {
+ int maxLength = 2;
+ _property.setMaxLength(maxLength);
+
+ try
+ {
+ _property.validate(_5LettersString);
+ fail("No max length has been set on property so validation must proceed.");
+ } catch (ValidationException expected)
+ {
+ assertEquals(ValidationException.MAX_LENGTH,expected.getConstraintName());
+ assertEquals(maxLength,expected.getConstraintValue());
+ assertEquals(_5LettersString.length(),expected.getFeatureValue());
+ assertEquals(_property.getName(),expected.getFeatureName());
+ }
+ }
+
+ /**
+ * Tests the validation of a qpid property when the type is a string and the property value is null.
+ *
+ * <br>precondition : property type is a string and property value is null..
+ * <br>postcondition : no exception is thrown. That is : the validation succeeds.
+ */
+ public void testValidationOK_withNullValue() {
+ try
+ {
+ _property.validate(null);
+ } catch (ValidationException notExpected)
+ {
+ fail("No constraint has been violated so validate() shouldn't raise an exception.");
+ }
+
+ _property.setMaxLength(1);
+
+ try
+ {
+ _property.validate(null);
+ } catch (ValidationException notExpected)
+ {
+ fail("No constraint has been violated so validate() shouldn't raise an exception.");
+ }
+ }
+
+ /**
+ * Tests the validation of a qpid property when the type is a string and a max length constraint has been set.
+ *
+ * <br>precondition : property type is a string, max length has been set and property value is not violating that.
+ * <br>postcondition : no exception is thrown. That is : the validation succeeds.
+ */
+ public void testValidationOK_withMaxLength() {
+ int maxLength = (_5LettersString.length()+1);
+ _property.setMaxLength(maxLength);
+
+ try
+ {
+ _property.validate(_5LettersString);
+ } catch (ValidationException notExpected)
+ {
+ fail("No constraint has been violated so validate() shouldn't raise an exception.");
+ }
+ }
+}
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/domain/model/type/BinaryTest.java b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/type/BinaryTest.java
new file mode 100644
index 0000000000..6636c08710
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/domain/model/type/BinaryTest.java
@@ -0,0 +1,59 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model.type;
+
+import junit.framework.TestCase;
+
+/**
+ * Test case for "Binary" type.
+ *
+ * @author Andrea Gazzarini
+ */
+public class BinaryTest extends TestCase
+{
+ /**
+ * Tests the lazy & once hash code computation behaviour of the binary type.
+ */
+ public void testHashCodeComputation(){
+ Binary binary = new Binary(new byte[]{1,2,3,4,5,6,7,6,3,3});
+ assertSame(binary.state,binary.hashCodeNotYetComputed);
+
+ int firstResult = binary.hashCode();
+ assertSame(binary.state,binary.hashCodeAlreadyComputed);
+
+ int secondResult = binary.hashCode();
+ assertSame(binary.state,binary.hashCodeAlreadyComputed);
+ assertEquals(firstResult,secondResult);
+ }
+
+ /**
+ * Tests the equals() method of the binary class.
+ * Two binary must be equals only if they contain the same array (that is, two arrays with the same size & content)
+ */
+ public void testIdentity() {
+ Binary binary = new Binary(new byte[]{1,2,3,4,5,6,7,6,3,3});
+ Binary theSame= new Binary(new byte[]{1,2,3,4,5,6,7,6,3,3});
+ Binary aDifferentOne = new Binary(new byte[]{4,2,3,3,4,4,5,3,3,2});
+
+ assertTrue(binary.equals(theSame));
+ assertFalse(binary.equals(aDifferentOne));
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/domain/services/BrokerMessageListenerTest.java b/java/management/client/src/test/java/org/apache/qpid/management/domain/services/BrokerMessageListenerTest.java
new file mode 100644
index 0000000000..805c039a6f
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/domain/services/BrokerMessageListenerTest.java
@@ -0,0 +1,241 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.services;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.api.Message;
+import org.apache.qpid.management.TestConstants;
+import org.apache.qpid.management.domain.handler.base.IMessageHandler;
+import org.apache.qpid.management.domain.model.DomainModel;
+import org.apache.qpid.nclient.util.ByteBufferMessage;
+import org.apache.qpid.transport.codec.Decoder;
+
+/**
+ * Test case for Broker Message Listener.
+ *
+ * @author Andrea Gazzarini
+ */
+public class BrokerMessageListenerTest extends TestCase
+{
+ // An empty message handler user for test.
+ private IMessageHandler _emptyMessageHandler = new IMessageHandler()
+ {
+ public void process (Decoder decoder, int sequenceNumber)
+ {
+ }
+ public void setDomainModel (DomainModel domainModel)
+ {
+ }
+ };
+
+ // Another empty message handler user for test.
+ private IMessageHandler _anotherEmptyMessageHandler = new IMessageHandler()
+ {
+ public void process (Decoder decoder, int sequenceNumber)
+ {
+ }
+ public void setDomainModel (DomainModel domainModel)
+ {
+ }
+ };
+
+ private Map<Character,IMessageHandler> _handlers = new HashMap<Character, IMessageHandler>();
+ private BrokerMessageListener _listener;
+ private final char opcode1 = 'x';
+ private final char opcode2 = 'y';
+
+
+ @Override
+ protected void setUp () throws Exception
+ {
+ DomainModel domainModel = new DomainModel(TestConstants.BROKER_ID);
+ _listener = new BrokerMessageListener(domainModel);
+
+ _handlers.put(opcode1, _emptyMessageHandler);
+ _handlers.put(opcode2, _anotherEmptyMessageHandler);
+ }
+
+ /**
+ * Tests the installation of message handlers on a broker message listener.
+ *
+ * <br>precondition : no message handler has been installed on message listener.
+ * <br>postcondition : two message handlers are installed on message listener.
+ */
+ public void testSetHandlersOK()
+ {
+ assertTrue(
+ "No handler has yet been installed so how is it possible that the handlers map is not empty?",
+ _listener._handlers.isEmpty());
+
+ _listener.setHandlers(_handlers);
+
+ assertEquals("Now we should have two handlers configured.",2,_listener._handlers.size());
+ assertSame(_listener._handlers.get(opcode1),_emptyMessageHandler);
+ assertSame(_listener._handlers.get(opcode2),_anotherEmptyMessageHandler);
+ }
+
+ /**
+ * Tests the installation of message handlers on a broker message listener.
+ * Specifically it tries to install three message handlers and one of them is throwing an exception at installation time.
+ *
+ * <br>precondition : no message handler has been installed on message listener.
+ * <br>postcondition : two message handlers are installed on message listener. (the one that thrown exception has been
+ * discarded).
+ */
+ public void testSetHandlerOK()
+ {
+ IMessageHandler wrongMessageHandler = new IMessageHandler()
+ {
+
+ public void process (Decoder decoder, int sequenceNumber)
+ {
+ }
+
+ public void setDomainModel (DomainModel domainModel)
+ {
+ throw new RuntimeException();
+ }
+ };
+
+ char opcodeForWrongHandler = 'k';
+
+ assertTrue(
+ "No handler has yet been installed so how is it possible that the handlers map is not empty?",
+ _listener._handlers.isEmpty());
+
+ _handlers.put(opcodeForWrongHandler,wrongMessageHandler);
+
+ _listener.setHandlers(_handlers);
+
+ assertEquals("Now we should have two handlers configured.",2,_listener._handlers.size());
+ assertSame(_listener._handlers.get(opcode1),_emptyMessageHandler);
+ assertSame(_listener._handlers.get(opcode2),_anotherEmptyMessageHandler);
+ assertNull(_listener._handlers.get(opcodeForWrongHandler));
+ }
+
+ /**
+ * Tests the execution of the onMessage() method when a message with a bad magic number is received.
+ *
+ * <br>precondition : a message with a bad magic number is received.
+ * <br>postcondition : the processing of the incoming message is skipped and therefore no handler will be called.
+ */
+ public void testOnMessageKO_withBadMagicNumber() throws IOException
+ {
+ IMessageHandler neverCallMe = new IMessageHandler()
+ {
+
+ public void process (Decoder decoder, int sequenceNumber)
+ {
+ fail("This test shouldn't never arrive at this point...");
+ }
+
+ public void setDomainModel (DomainModel domainModel)
+ {
+ }
+ };
+
+ String opcodeForNeverCallMeHandler = "w";
+
+ _handlers.put('w',neverCallMe);
+ _listener.setHandlers(_handlers);
+
+ Message message = new ByteBufferMessage();
+ message.appendData( ("AMG"+opcodeForNeverCallMeHandler).getBytes());
+
+ _listener.onMessage(message);
+ }
+
+ /**
+ * Tests the execution of the onMessage() method when the incoming message is a compound message.
+ *
+ * <br>precondition : the incoming message is a compound message.
+ * <br>postcondition : each tokenized message is forwarded to the appropriate handler.
+ */
+ public void testOnMessageOK_WithCompoundMessage() throws Exception
+ {
+ final Map<Character,IMessageHandler> handlersMap = new HashMap<Character,IMessageHandler>();
+ char [] opcodes = {'a','b','c','d','e'};
+
+ class MockMessageHandler implements IMessageHandler
+ {
+ private final char _opcode;
+
+ public MockMessageHandler(char opcode)
+ {
+ this._opcode = opcode;
+ }
+
+ public void process (Decoder decoder, int sequenceNumber)
+ {
+ handlersMap.remove(_opcode);
+ }
+
+ public void setDomainModel (DomainModel domainModel)
+ {
+ // Do nothing here. It's just a mock handler.
+ }
+ };
+
+ for (char opcode : opcodes)
+ {
+ handlersMap.put(opcode, new MockMessageHandler(opcode));
+ }
+
+ // Removes previously injected handlers (i.e. x & y)
+ _listener._handlers.clear();
+ _listener.setHandlers(handlersMap);
+
+ Message compoundMessage = createCompoundMessage(opcodes);
+ _listener.onMessage(compoundMessage);
+
+ assertTrue(handlersMap.isEmpty());
+ }
+
+ // Creates a (non valid) compound message.
+ private Message createCompoundMessage(char[] opcodes) throws IOException {
+ byte [] compoundMessageData = new byte [12 * opcodes.length];
+ Random randomizer = new Random();
+ int position = 0;
+
+ for (char opcode : opcodes) {
+ System.arraycopy(MessageTokenizer.MAGIC_NUMBER_BYTES, 0, compoundMessageData, position, MessageTokenizer.MAGIC_NUMBER_BYTES.length);
+ position+=MessageTokenizer.MAGIC_NUMBER_BYTES.length;
+
+ compoundMessageData[position++] = (byte)opcode;
+
+ for (int c = 4; c < 12; c++)
+ {
+ byte aByte = (byte)randomizer.nextInt(127);
+ compoundMessageData[position++] = aByte;
+ }
+ }
+
+ Message compoundMessage = new ByteBufferMessage();
+ compoundMessage.appendData(compoundMessageData);
+ return compoundMessage;
+ }
+}
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/domain/services/MessageTokenizerTest.java b/java/management/client/src/test/java/org/apache/qpid/management/domain/services/MessageTokenizerTest.java
new file mode 100644
index 0000000000..55b8b17f9d
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/domain/services/MessageTokenizerTest.java
@@ -0,0 +1,140 @@
+/*
+*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.management.domain.services;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.*;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.api.Message;
+import org.apache.qpid.nclient.util.ByteBufferMessage;
+import org.apache.qpid.transport.codec.BBDecoder;
+
+/**
+ * Tests case for messaeg tokenizer.
+ *
+ * @author Andrea Gazzarini
+ */
+public class MessageTokenizerTest extends TestCase {
+
+ /**
+ * Tests the execution of the message tokenizer when the given message is not a valid AMQP message.
+ *
+ * <br>precondition : the incoming message is not a valid AMQP message.
+ * <br>postcondition : no exception is thrown and there will be exactly one token with the given message.
+ */
+ public void testOK_WithNoMessage() throws IOException{
+ byte [] noMessage = {2,10,120,23,23,23,4,10,11,12,2,1,3,-22};
+
+ Message multiMessage = new ByteBufferMessage();
+ multiMessage.appendData(noMessage);
+ MessageTokenizer tokenizer = new MessageTokenizer(multiMessage);
+
+ assertEquals(1, tokenizer.countTokens());
+ assertEquals(tokenizer.nextElement(),noMessage);
+ assertFalse(tokenizer.hasMoreElements());
+ }
+
+ /**
+ * Tests the execution of the message tokenizer when the given message contains only one message.
+ *
+ * <br>precondition : the incoming message contains only one message.
+ * <br>postcondition : no exception is thrown and there will be exactly one token with the given message.
+ */
+ public void testOK_WithOneMessage() throws IOException{
+ byte [] oneEncodedMessage = {'A','M','2',23,23,23,4,10,11,12,2,1,3,-22};
+
+ Message multiMessage = new ByteBufferMessage();
+ multiMessage.appendData(oneEncodedMessage);
+ MessageTokenizer tokenizer = new MessageTokenizer(multiMessage);
+
+ assertEquals(1, tokenizer.countTokens());
+ assertEquals(tokenizer.nextElement(),oneEncodedMessage);
+ assertFalse(tokenizer.hasMoreElements());
+ }
+
+ /**
+ * Tests the execution of the message tokenizer when the given message contains a random number of messages.
+ *
+ * <br>precondition : the incoming message contains a random number of messages.
+ * <br>postcondition : no exception is thrown and each built token is a valid message starting with right header.
+ */
+ public void testOK_WithRandomNUmberOfMessages() throws IOException{
+ Random randomizer = new Random();
+
+ int howManyLoops = randomizer.nextInt(10000);
+ howManyLoops = (howManyLoops == 0) ? 10 : howManyLoops;
+ byte [] compoundMessageData = new byte [12 * howManyLoops];
+
+ List<byte []> messages = new ArrayList<byte[]>(howManyLoops);
+
+ int position = 0;
+ for (int i = 0; i < howManyLoops; i++)
+ {
+ byte [] message = new byte[12];
+ System.arraycopy(MessageTokenizer.MAGIC_NUMBER_BYTES, 0, compoundMessageData, position, MessageTokenizer.MAGIC_NUMBER_BYTES.length);
+ System.arraycopy(MessageTokenizer.MAGIC_NUMBER_BYTES, 0, message, 0, MessageTokenizer.MAGIC_NUMBER_BYTES.length);
+ position+=MessageTokenizer.MAGIC_NUMBER_BYTES.length;
+
+ for (int c = 3; c < 12; c++)
+ {
+ byte aByte = (byte)randomizer.nextInt(127);
+ aByte = (aByte == 77) ? (byte)c : aByte;
+ compoundMessageData[position++] = aByte;
+ message[c] = aByte;
+ }
+ messages.add(message);
+ }
+
+ Message multiMessage = new ByteBufferMessage();
+ multiMessage.appendData(compoundMessageData);
+ MessageTokenizer tokenizer = new MessageTokenizer(multiMessage);
+
+ int howManyTokens = tokenizer.countTokens();
+ assertEquals(howManyLoops, howManyTokens);
+
+ int index = 0;
+ while (tokenizer.hasMoreElements())
+ {
+ assertEquals(tokenizer.nextElement(),messages.get(index++));
+ }
+
+ assertEquals((index),howManyTokens);
+ }
+
+ /**
+ * Internal method used for comparison of two messages.
+ *
+ * @param message the token message just built by the tokenizer.
+ * @param expected the expected result.
+ */
+ private void assertEquals(Message message, byte [] expected) throws IOException
+ {
+ ByteBuffer messageContent = message.readData();
+ BBDecoder decoder = new BBDecoder();
+ decoder.init(messageContent);
+ byte [] content = decoder.readReaminingBytes();
+ assertTrue(Arrays.equals(content, expected));
+ }
+}
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/BaseWsDmAdapterTestCase.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/BaseWsDmAdapterTestCase.java
new file mode 100644
index 0000000000..900d14c72e
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/BaseWsDmAdapterTestCase.java
@@ -0,0 +1,143 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm;
+
+import java.lang.management.ManagementFactory;
+import java.net.URI;
+import java.util.UUID;
+
+import javax.management.MBeanInfo;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import junit.framework.TestCase;
+
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.muse.ws.resource.remote.WsResourceClient;
+import org.apache.muse.ws.resource.sg.remote.ServiceGroupClient;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.Protocol;
+import org.apache.qpid.management.TestConstants;
+
+/**
+ * Test case for WS-Resource lifecycle management.
+ *
+ * @author Andrea Gazzarini
+ */
+public abstract class BaseWsDmAdapterTestCase extends TestCase implements TestConstants{
+
+ protected MBeanServer _managementServer;
+ protected ObjectName _resourceObjectName;
+
+ protected WsResourceClient _resourceClient;
+ protected MBeanInfo _mbeanInfo;
+
+ /**
+ * Set up fixture for this test case.
+ *
+ * @throws Exception when the test case intialization fails.
+ */
+ protected void setUp() throws Exception
+ {
+ _managementServer = ManagementFactory.getPlatformMBeanServer();
+
+ ServiceGroupClient serviceGroup = getServiceGroupClient();
+ WsResourceClient [] members = serviceGroup.getMembers();
+
+ assertEquals(
+ "No resource has been yet created so how is " +
+ "it possible that service group children list is not empty?",
+ 0,
+ members.length);
+
+ _managementServer.invoke(
+ Names.QPID_EMULATOR_OBJECT_NAME,
+ "createQueue",
+ new Object[]{_resourceObjectName = createResourceName()},
+ new String[]{ObjectName.class.getName()});
+
+ members = serviceGroup.getMembers();
+ assertEquals(
+ "One resource has just been created so " +
+ "I expect to find it on service group children list...",
+ 1,
+ members.length);
+
+ _resourceClient = members[0];
+ _mbeanInfo = _managementServer.getMBeanInfo(_resourceObjectName);
+ }
+
+ /**
+ * Shutdown procedure for this test case.
+ *
+ * @throws Exception when either the server or some resource fails to shutdown.
+ */
+ @Override
+ protected void tearDown() throws Exception
+ {
+ ServiceGroupClient serviceGroup = getServiceGroupClient();
+ WsResourceClient [] members = serviceGroup.getMembers();
+
+ _managementServer.invoke(
+ Names.QPID_EMULATOR_OBJECT_NAME,
+ "unregister",
+ new Object[]{_resourceObjectName},
+ new String[]{ObjectName.class.getName()});
+
+ members = serviceGroup.getMembers();
+
+ assertEquals(
+ "No resource has been yet created so how is it possible that service group children list is not empty?",
+ 0,
+ members.length);
+ }
+
+ /**
+ * Creates a service group client reference.
+ *
+ * @return a service group client reference.
+ */
+ private ServiceGroupClient getServiceGroupClient()
+ {
+ URI address = URI.create(
+ Protocol.DEFAULT_ENDPOINT_URI.replaceFirst("8080",System.getProperty(Names.ADAPTER_PORT_PROPERTY_NAME)));
+ return new ServiceGroupClient(new EndpointReference(address));
+ }
+
+ /**
+ * In order to test the behaviour of the WS-DM adapter, at
+ * least one resource must be created. This is the method that
+ * returns the name (ObjectName on JMX side, Resource-ID on WSDM side)
+ * of that resource
+ *
+ * @return the name of the MBean instance that will be created.
+ * @throws Exception when the name if malformed. Practically never.
+ */
+ private ObjectName createResourceName() throws Exception
+ {
+ return new ObjectName(
+ "Q-MAN:objectId="+UUID.randomUUID()+
+ ", brokerID="+UUID.randomUUID()+
+ ",class=queue"+
+ ",package=org.apache.qpid"+
+ ",name="+System.currentTimeMillis());
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/EnhancedReflectionProxyHandler.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/EnhancedReflectionProxyHandler.java
new file mode 100644
index 0000000000..615d744546
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/EnhancedReflectionProxyHandler.java
@@ -0,0 +1,72 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm;
+
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.proxy.ReflectionProxyHandler;
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.addressing.soap.SoapFault;
+import org.apache.qpid.management.wsdm.muse.serializer.ByteArraySerializer;
+import org.w3c.dom.Element;
+
+/**
+ * Custom implementation of Muse ReflectionProxyHandler
+ * that uses a base64 serializer for byte arrays.
+ * Note that this proxy handler is only needed for tests because it provides
+ * client side Base64 serializer capability.
+ * In a concrete scenario we don't mind what instrument the client is using in order to
+ * propertly serialize byte arrays.
+ *
+ * @author Andrea Gazzarini
+ */
+public class EnhancedReflectionProxyHandler extends ReflectionProxyHandler
+{
+ @Override
+ protected Element serialize(Object obj, QName qname) throws SoapFault
+ {
+ if (obj == null)
+ {
+ return XmlUtils.createElement(qname);
+ }
+
+ if (obj.getClass() == byte[].class)
+ {
+ return new ByteArraySerializer().toXML(obj, qname);
+ } else
+ {
+ return super.serialize(obj, qname);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected Object deserialize(Element xml, Class theClass) throws SoapFault
+ {
+ if (theClass == byte[].class)
+ {
+ return new ByteArraySerializer().fromXML(xml);
+ } else
+ {
+ return super.deserialize(xml, theClass);
+ }
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/GetMultipleResourcePropertiesTestCase.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/GetMultipleResourcePropertiesTestCase.java
new file mode 100644
index 0000000000..d59e7a39e5
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/GetMultipleResourcePropertiesTestCase.java
@@ -0,0 +1,125 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm;
+
+import java.util.Date;
+import java.util.UUID;
+
+import javax.management.MBeanAttributeInfo;
+import javax.xml.namespace.QName;
+
+import org.apache.muse.ws.addressing.soap.SoapFault;
+import org.apache.muse.ws.resource.WsrfConstants;
+import org.apache.qpid.management.Names;
+import org.w3c.dom.Element;
+
+/**
+ * Test case for Web Service Resource Properties interfaces.
+ * Those interfaces are defined on http://docs.oasis-open.org/wsrf/wsrf-ws_resource_properties-1.2-spec-os.pdf
+ * (Web Services Resource Properties 1.2 - (WS-ResourceProperties).
+ * For a better explanation see chapter 5 of the specification above.
+ *
+ * @author Andrea Gazzarini
+ */
+public class GetMultipleResourcePropertiesTestCase extends BaseWsDmAdapterTestCase
+{
+ /**
+ * Tests the GetMultipleResourceProperties interface when the request contains
+ * an unknwon target resource.
+ *
+ * <br>precondition : the GetMultipleResourceProperties request contains an unknwon resource.
+ * <br>postcondition : a SoapFault is thrown and the corresponding detail contains an
+ * UnknownResourceFault element.
+ */
+ public void testGetMultipleResourcePropertiesKO_WithUnknownResourceFault() throws Exception
+ {
+ try
+ {
+ _resourceClient.getEndpointReference().removeParameter(Names.RESOURCE_ID_QNAME);
+ _resourceClient.getEndpointReference().addParameter(Names.RESOURCE_ID_QNAME,"lablabalbal");
+
+ _resourceClient.getMultipleResourceProperties(new QName[]{});
+ } catch(SoapFault expected)
+ {
+ assertEquals(
+ WsrfConstants.RESOURCE_UNKNOWN_QNAME.getLocalPart(),
+ expected.getDetail().getLocalName());
+ }
+ }
+
+ /**
+ * Test the WS-RP GetResourceProperties interface of the WS-DM adapter.
+ *
+ * <br>precondition : a ws resource exists and is registered.
+ * <br>postcondition : Properties are correctly returned according to WSRP interface and they (their value)
+ * are matching with corresponding MBean properties.
+ */
+ public void testGetMultipleResourcePropertiesOK() throws Exception
+ {
+ MBeanAttributeInfo [] attributesMetadata = _mbeanInfo.getAttributes();
+ QName[] names = new QName[attributesMetadata.length];
+
+ int index = 0;
+ for (MBeanAttributeInfo attributeMetadata : _mbeanInfo.getAttributes())
+ {
+ QName qname = new QName(Names.NAMESPACE_URI,attributeMetadata.getName(),Names.PREFIX);
+ names[index++] = qname;
+ }
+
+ Element[] properties =_resourceClient.getMultipleResourceProperties(names);
+ for (Element element : properties)
+ {
+ String name = element.getLocalName();
+ Object value = _managementServer.getAttribute(_resourceObjectName, name);
+ if ("Name".equals(name))
+ {
+ assertEquals(
+ value,
+ element.getTextContent());
+ } else if ("Durable".equals(name))
+ {
+ assertEquals(
+ value,
+ Boolean.valueOf(element.getTextContent()));
+ } else if ("ExpireTime".equals(name))
+ {
+ assertEquals(
+ value,
+ new Date(Long.valueOf(element.getTextContent())));
+ } else if ("MsgTotalEnqueues".equals(name))
+ {
+ assertEquals(
+ value,
+ Long.valueOf(element.getTextContent()));
+ } else if ("ConsumerCount".equals(name))
+ {
+ assertEquals(
+ value,
+ Integer.valueOf(element.getTextContent()));
+ }else if ("VhostRef".equals(name))
+ {
+ assertEquals(
+ value,
+ UUID.fromString(element.getTextContent()));
+ }
+ }
+ }
+}
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/GetResourcePropertiesTestCase.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/GetResourcePropertiesTestCase.java
new file mode 100644
index 0000000000..e18e928cf4
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/GetResourcePropertiesTestCase.java
@@ -0,0 +1,105 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm;
+
+import java.lang.reflect.Array;
+
+import javax.management.MBeanAttributeInfo;
+import javax.xml.namespace.QName;
+
+import org.apache.muse.ws.addressing.soap.SoapFault;
+import org.apache.muse.ws.resource.WsrfConstants;
+import org.apache.qpid.management.Names;
+
+/**
+ * Test case for Web Service Resource Properties interfaces.
+ * Those interfaces are defined on http://docs.oasis-open.org/wsrf/wsrf-ws_resource_properties-1.2-spec-os.pdf
+ * (Web Services Resource Properties 1.2 - (WS-ResourceProperties).
+ * For a better explanation see chapter 5 of the specification above.
+ *
+ * @author Andrea Gazzarini
+ */
+public class GetResourcePropertiesTestCase extends BaseWsDmAdapterTestCase
+{
+
+ /**
+ * Test the WS-RP GetResourceProperty interface of the WS-DM adapter.
+ *
+ * <br>precondition : a ws resource exists and is registered.
+ * <br>postcondition : property values coming from WS-DM resource are the same of the JMX interface.
+ */
+ public void testGetResourcePropertiesOK() throws Exception
+ {
+ MBeanAttributeInfo [] attributesMetadata = _mbeanInfo.getAttributes();
+ for (MBeanAttributeInfo attributeMetadata : attributesMetadata)
+ {
+ String name = attributeMetadata.getName();
+ Object propertyValues = _resourceClient.getPropertyAsObject(
+ new QName(
+ Names.NAMESPACE_URI,
+ name,
+ Names.PREFIX),
+ Class.forName(attributeMetadata.getType()));
+
+ int length = Array.getLength(propertyValues);
+ if (length != 0)
+ {
+ Object propertyValue = Array.get(propertyValues, 0);
+
+ assertEquals(
+ "Comparison failed for property "+name,
+ _managementServer.getAttribute(_resourceObjectName,name),
+ propertyValue);
+ } else {
+ assertNull(
+ String.format(
+ "\"%s\" property value shouldn't be null. Its value is %s",
+ name,
+ _managementServer.getAttribute(_resourceObjectName,name)),
+ _managementServer.getAttribute(_resourceObjectName,name));
+ }
+ }
+ }
+
+ /**
+ * Tests the GetMultipleResourceProperties interface when the request contains
+ * an unknwon target resource.
+ *
+ * <br>precondition : the GetMultipleResourceProperties request contains an unknwon resource.
+ * <br>postcondition : a SoapFault is thrown and the corresponding detail contains an
+ * UnknownResourceFault element.
+ */
+ public void testGetResourcePropertiesKO_WithUnknownResourceFault() throws Exception
+ {
+ try
+ {
+ _resourceClient.getEndpointReference().removeParameter(Names.RESOURCE_ID_QNAME);
+ _resourceClient.getEndpointReference().addParameter(Names.RESOURCE_ID_QNAME,"lablabalbal");
+
+ _resourceClient.getResourceProperty(new QName("a","b","c"));
+ } catch(SoapFault expected)
+ {
+ assertEquals(
+ WsrfConstants.RESOURCE_UNKNOWN_QNAME.getLocalPart(),
+ expected.getDetail().getLocalName());
+ }
+ }
+}
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/GetResourcePropertyDocumentTestCase.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/GetResourcePropertyDocumentTestCase.java
new file mode 100644
index 0000000000..862115f841
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/GetResourcePropertyDocumentTestCase.java
@@ -0,0 +1,134 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm;
+
+import javax.xml.namespace.QName;
+
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.addressing.soap.SoapFault;
+import org.apache.muse.ws.resource.WsrfConstants;
+import org.apache.qpid.management.Names;
+import org.w3c.dom.Element;
+
+/**
+ * Test case for Web Service Resource Properties interfaces.
+ * Those interfaces are defined on http://docs.oasis-open.org/wsrf/wsrf-ws_resource_properties-1.2-spec-os.pdf
+ * (Web Services Resource Properties 1.2 - (WS-ResourceProperties).
+ * For a better explanation see chapter 5 of the specification above.
+ *
+ * @author Andrea Gazzarini
+ */
+public class GetResourcePropertyDocumentTestCase extends BaseWsDmAdapterTestCase
+{
+ /**
+ * Tests the GetResourcePropertyDocument interface when the request contains
+ * an unknwon target resource.
+ *
+ * <br>precondition : the GetResourcePropertyDocument contains an unknwon resource.
+ * <br>postcondition : a SoapFault is thrown and the corresponding detail contains an
+ * UnknownResourceFault element.
+ */
+ public void testGetResourcePropertyDocumentKO_WithUnknownResourceFault() throws Exception
+ {
+ try
+ {
+ _resourceClient.getEndpointReference().removeParameter(Names.RESOURCE_ID_QNAME);
+ _resourceClient.getEndpointReference().addParameter(Names.RESOURCE_ID_QNAME,"lablabalbal");
+ _resourceClient.setTrace(true);
+
+ _resourceClient.getResourcePropertyDocument();
+ } catch(SoapFault expected)
+ {
+ assertEquals(
+ WsrfConstants.RESOURCE_UNKNOWN_QNAME.getLocalPart(),
+ expected.getDetail().getLocalName());
+ }
+ }
+
+ /**
+ * Tests the WS-RP PutResourcePropertyDocument interface of the WS-DM adapter.
+ *
+ * <br>precondition : a ws resource exists and is registered.
+ * <br>postcondition : A read / write property is correctly set according to WSRP interface.
+ */
+ public void testGetAndPutResourcePropertyDocumentOK() throws Exception
+ {
+ String expectedMgmtPubIntervalValue = "4321";
+ String propertyName = "MgmtPubInterval";
+
+ Element propertiesDocument = _resourceClient.getResourcePropertyDocument();
+ Element [] properties = XmlUtils.getAllElements(propertiesDocument);
+
+ for (Element element : properties)
+ {
+ if (propertyName.equals(element.getLocalName())) {
+ element.setTextContent(expectedMgmtPubIntervalValue);
+ } else {
+ propertiesDocument.removeChild(element);
+ }
+ }
+
+ _resourceClient.putResourcePropertyDocument(propertiesDocument);
+
+ Element newProperties = _resourceClient.getResourcePropertyDocument();
+
+ Element mgmtPubInterval = XmlUtils.getElement(
+ newProperties, new QName(
+ Names.NAMESPACE_URI,
+ propertyName,
+ Names.PREFIX));
+
+ assertEquals(expectedMgmtPubIntervalValue,mgmtPubInterval.getTextContent());
+ }
+
+ /**
+ * Tests the WS-RP PutResourcePropertyDocument interface of the WS-DM adapter.
+ * Specifically it tries to update the value of a read-only property.
+ *
+ * <br>precondition : a ws resource exists, it is registered and has at least one read-only property.
+ * <br>postcondition : An exception is thrown indicating the failure.
+ */
+ public void testGetAndPutResourcePropertyDocumentKO_WithReadOnlyProperty() throws Exception
+ {
+ String propertyName = "Name";
+
+ Element propertiesDocument = _resourceClient.getResourcePropertyDocument();
+ Element [] properties = XmlUtils.getAllElements(propertiesDocument);
+
+ for (Element element : properties)
+ {
+ if (propertyName.equals(element.getLocalName())) {
+ element.setTextContent("ThisIsTheNewValueOfNameProperty");
+ } else {
+ propertiesDocument.removeChild(element);
+ }
+ }
+
+ try
+ {
+ _resourceClient.putResourcePropertyDocument(propertiesDocument);
+ fail("It's not possible to update the value of a read-only property.");
+ } catch (SoapFault expected)
+ {
+
+ }
+ }
+}
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/MetadataExchangeInterfaceTestCase.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/MetadataExchangeInterfaceTestCase.java
new file mode 100644
index 0000000000..046f2226e6
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/MetadataExchangeInterfaceTestCase.java
@@ -0,0 +1,169 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm;
+
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.proxy.ProxyHandler;
+import org.apache.muse.core.proxy.ReflectionProxyHandler;
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.addressing.soap.SoapFault;
+import org.apache.muse.ws.metadata.WsxConstants;
+import org.apache.muse.ws.resource.WsrfConstants;
+import org.apache.muse.ws.resource.metadata.WsrmdConstants;
+import org.apache.qpid.management.Names;
+import org.w3c.dom.Element;
+
+/**
+ * Test case for QMan metadata exchange interface.
+ *
+ * @author Andrea Gazzarini
+ */
+public class MetadataExchangeInterfaceTestCase extends BaseWsDmAdapterTestCase
+{
+ /**
+ * Test the MetadataExchange interface when the corresponding
+ * request doesn't contain a dialect. According to WS-MetadataExchange specs this should be
+ * intended as a "give-me-all-metadata" for that resource.
+ *
+ * <br>precondition : the GetMetadata request doesn't contain a dialect.
+ * <br>postcondition : the whole metadata document is returned with all metadata .
+ * It will contain both WSDL and RMD.
+ */
+ @SuppressWarnings("unchecked")
+ public void testGetMetadataOK_WithoutDialect() throws Exception
+ {
+ Element[] result = (Element[]) _resourceClient.invoke(
+ getProxyHandler(),
+ new Object[]{""});
+
+ assertEquals(2,result.length);
+
+ Element rmdMetadataSection = result[0];
+ Element wsdlMetadataSection = result[1];
+
+ Element rmd = XmlUtils.getFirstElement(rmdMetadataSection);
+ Element wsdl = XmlUtils.getFirstElement(wsdlMetadataSection);
+
+ assertEquals("MetadataDescriptor",rmd.getLocalName());
+ assertEquals("definitions",wsdl.getLocalName());
+ }
+
+ /**
+ * Test the MetadataExchange interface when the WSDL dialect is specified on the request.
+ *
+ * <br>precondition : the GetMetadata request contains WSDL dialect.
+ * <br>postcondition : the resource WSDL metadata document is returned.
+ */
+ @SuppressWarnings("unchecked")
+ public void testGetMetadataOK_WithWSDLDialect() throws Exception
+ {
+ Element[] result = (Element[]) _resourceClient.invoke(
+ getProxyHandler(),
+ new Object[]{WsxConstants.WSDL_DIALECT});
+
+ assertEquals(1,result.length);
+
+ Element wsdlMetadataSection = result[0];
+
+ Element wsdl = XmlUtils.getFirstElement(wsdlMetadataSection);
+
+ assertEquals("definitions",wsdl.getLocalName());
+ }
+
+ /**
+ * Test the MetadataExchange interface when the RMD dialect is specified on the request.
+ *
+ * <br>precondition : the GetMetadata request contains RMD dialect.
+ * <br>postcondition : the RMD metadata document is returned.
+ */
+ @SuppressWarnings("unchecked")
+ public void testGetMetadataOK_WithRMDDialect() throws Exception
+ {
+ Element[] result = (Element[]) _resourceClient.invoke(
+ getProxyHandler(),
+ new Object[]{WsrmdConstants.NAMESPACE_URI});
+
+ assertEquals(1,result.length);
+
+ Element rmdMetadataSection = result[0];
+
+ Element wsdl = XmlUtils.getFirstElement(rmdMetadataSection);
+
+ assertEquals("MetadataDescriptor",wsdl.getLocalName());
+ }
+
+ /**
+ * Test the MetadataExchange interface with an unknown metadata dialect.
+ *
+ * <br>precondition : the GetMetadata request contains an unknown dialect.
+ * <br>postcondition : the returned metadata section is empty.
+ */
+ @SuppressWarnings("unchecked")
+ public void testGetMetadataKO_WithoutUnknownDialect() throws Exception
+ {
+ Element [] metadata = (Element[]) _resourceClient.invoke(
+ getProxyHandler(),
+ new Object[]{"HopeThisIsAnUnknownDialect"});
+
+ assertEquals(0,metadata.length);
+ }
+
+ /**
+ * Test the MetadataExchange interface with an unknown metadata dialect.
+ *
+ * <br>precondition : the GetMetadata request contains an unknown dialect.
+ * <br>postcondition : the returned metadata section is empty.
+ */
+ @SuppressWarnings("unchecked")
+ public void testGetMetadataKO_WithoutUnknownResourceFault() throws Exception
+ {
+ try
+ {
+ _resourceClient.getEndpointReference().removeParameter(Names.RESOURCE_ID_QNAME);
+ _resourceClient.getEndpointReference().addParameter(Names.RESOURCE_ID_QNAME,"lablabalbal");
+
+ _resourceClient.invoke(getProxyHandler(), new Object[]{""});
+ } catch(SoapFault expected)
+ {
+ assertEquals(
+ WsrfConstants.RESOURCE_UNKNOWN_QNAME.getLocalPart(),
+ expected.getDetail().getLocalName());
+ }
+ }
+
+ /**
+ * Returns a proxy handler used for working with metadata exchange
+ * interface.
+ *
+ * @return a metadata proxy handler.
+ */
+ private ProxyHandler getProxyHandler()
+ {
+ ProxyHandler getMetadataHandler = new ReflectionProxyHandler();
+ getMetadataHandler.setAction("http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata");
+ getMetadataHandler.setRequestName(new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "GetMetadata", "wsx"));
+ getMetadataHandler.setRequestParameterNames(new QName[]{new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "Dialect", "wsx")});
+ getMetadataHandler.setResponseName(new QName("http://schemas.xmlsoap.org/ws/2004/09/mex", "Metadata", "wsx"));
+ getMetadataHandler.setReturnType(Element[].class);
+ return getMetadataHandler;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/OperationInvocationInterfaceTestCase.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/OperationInvocationInterfaceTestCase.java
new file mode 100644
index 0000000000..afc4a62085
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/OperationInvocationInterfaceTestCase.java
@@ -0,0 +1,580 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.xml.namespace.QName;
+
+import org.apache.muse.core.proxy.ProxyHandler;
+import org.apache.muse.core.proxy.ReflectionProxyHandler;
+import org.apache.muse.ws.addressing.soap.SoapFault;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.wsdm.capabilities.Result;
+
+/**
+ * Test case for QMan operation invocation interface.
+ *
+ * @author Andrea Gazzarini
+ */
+public class OperationInvocationInterfaceTestCase extends BaseWsDmAdapterTestCase
+{
+ private Map<String, ProxyHandler> _invocationHandlers = createInvocationHandlers();
+
+ /**
+ * Test operation invocation on WS-Resource.
+ * This method tests the exchange of a byte type array between requestor
+ * and service provider.
+ *
+ * <br>precondition : a WS-Resource exists and is registered and the requested
+ * operation is available on that.
+ * <br>postcondition : invocations are executed successfully, no exception is thrown
+ * and byte array are correctly returned.
+ */
+ @SuppressWarnings("unchecked")
+ public void testOperationInvocationOK_withByteArray() throws Exception
+ {
+ byte [] expectedByteResult = {1,3,4,2,2,44,22,3,3,55,66};
+
+ Object result = _resourceClient.invoke(
+ _invocationHandlers.get("echoWithByteArray"),
+ new Object[]{expectedByteResult});
+
+ Method getOutputParameters = result.getClass().getMethod("getOutputParameters");
+
+ Map<String,Object> out = (Map<String, Object>) getOutputParameters.invoke(result);
+
+ assertEquals("Output parameters must be 1.",1,out.size());
+ assertArrayEquals(expectedByteResult, out.get(byte[].class.getName()));
+ }
+
+ /**
+ * Test a simple operation invocation on a WS-Resource.
+ * This method tests a simple operation without any input and output parameters.
+ *
+ * <br>precondition : a ws resource exists and is registered and the requested operation
+ * is available on that.
+ * <br>postcondition : invocations are executed successfully an no exception is thrown.
+ */
+ @SuppressWarnings("unchecked")
+ public void testSimpleOperationInvocationOK() throws Exception
+ {
+ Object result = _resourceClient.invoke(
+ _invocationHandlers.get("voidWithoutArguments"),
+ null);
+
+ assertNotNull(result);
+ }
+
+ /**
+ * Test a the invocation on a WS-Resource with a method that throws an exception..
+ *
+ * <br>precondition : a ws resource exists and is registered and the requested
+ * operation is available on that.
+ * <br>postcondition : an exception is thrown by the requested method.
+ */
+ @SuppressWarnings("unchecked")
+ public void testInvocationException_OK() throws Exception
+ {
+ try
+ {
+ _resourceClient.invoke(
+ _invocationHandlers.get("throwsException"),
+ null);
+ fail("The requested operation has thrown an exception so a Soap Fault is expected...");
+ } catch(SoapFault expected)
+ {
+ }
+ }
+
+ /**
+ * Test operation invocation on WS-Resource.
+ * This method tests the exchange of UUID type between requestor and service provider.
+ *
+ * <br>precondition : a WS-Resource exists and is registered and the requested operation
+ * is available on that.
+ * <br>postcondition : invocations are executed successfully, no exception is thrown
+ * and parameters are correctly returned.
+ */
+ @SuppressWarnings("unchecked")
+ public void testOperationInvocationOK_withUUID() throws Exception
+ {
+ UUID expectedUuid = UUID.randomUUID();
+
+ Object result = _resourceClient.invoke(
+ _invocationHandlers.get("echoWithUUID"),
+ new Object[]{expectedUuid});
+
+ Method getOutputParameters = result.getClass().getMethod("getOutputParameters");
+
+ Map<String,Object> out = (Map<String, Object>) getOutputParameters.invoke(result);
+
+ assertEquals("Output parameters must be 1.",1,out.size());
+ assertEquals(expectedUuid, out.get("uuid"));
+ }
+
+ /**
+ * Test operation invocation on WS-Resource.
+ * This method tests the exchange of Map type between requestor and service provider.
+ * For this test exchanged arrays contain :
+ *
+ * <br>precondition : a ws resource exists and is registered and the requested
+ * operation is available on that.
+ * <br>postcondition : invocations are executed successfully, no exception is
+ * thrown and parameters are correctly returned.
+ */
+ @SuppressWarnings("unchecked")
+ public void testOperationInvocationOK_withMap() throws Exception
+ {
+ Map<String,Object> expectedMap = new HashMap<String, Object>();
+ expectedMap.put("p1", new Long(1));
+ expectedMap.put("p2", Boolean.TRUE);
+ expectedMap.put("p3", 1234d);
+ expectedMap.put("p4", 11.2f);
+ expectedMap.put("p5", 1272);
+ expectedMap.put("p6", (short)12);
+ expectedMap.put("p7", "aString");
+ expectedMap.put("p8", "http://qpid.apache.org");
+ expectedMap.put("p9", new Date(12383137128L));
+ expectedMap.put("p10", new byte[]{1,2,2,3,3,4});
+
+ Object result = _resourceClient.invoke(
+ _invocationHandlers.get("echoWithMap"),
+ new Object[]{expectedMap});
+
+ Method getOutputParameters = result.getClass().getMethod("getOutputParameters");
+
+ Map<String,Object> out = (Map<String, Object>) ((Map<String, Object>) getOutputParameters.invoke(result)).get("map");
+
+ assertEquals("Output parameters must be 10.",10,out.size());
+ assertEquals(expectedMap.get("p1"),out.get("p1"));
+ assertEquals(expectedMap.get("p2"),out.get("p2"));
+ assertEquals(expectedMap.get("p3"),out.get("p3"));
+ assertEquals(expectedMap.get("p4"),out.get("p4"));
+ assertEquals(expectedMap.get("p5"),out.get("p5"));
+ assertEquals(expectedMap.get("p6"),out.get("p6"));
+ assertEquals(expectedMap.get("p7"),out.get("p7"));
+ assertEquals(expectedMap.get("p8"),out.get("p8"));
+ assertEquals(expectedMap.get("p9"),out.get("p9"));
+ assertTrue( Arrays.equals((byte[])expectedMap.get("p10"),(byte[])out.get("p10")));
+ }
+
+ /**
+ * Test operation invocation on WS-Resource.
+ * This method tests the exchange of simple types between requestor and
+ * service provider.
+ *
+ * With simple types we mean :
+ *
+ * <ul>
+ * <li>java.lang.Long / long (xsd:long)
+ * <li>java.lang.Integer / int (xsd:int / xsd:integer)
+ * <li>java.lang.Double/ double (xsd:double)
+ * <li>java.lang.Float / float (xsd:float)
+ * <li>java.lang.Short / short (xsd:short)
+ * <li>java.lang.Boolean / boolean (xsd:boolean)
+ * <li>java.lang.String (xsd:string)
+ * <li>java.net.URI (xsd:anyURI)
+ * <li>java.util.Date(xsd:dateTime)
+ * </ul>
+ *
+ * <br>precondition : a ws resource exists and is registered and the requested operation is
+ * available on that.
+ * <br>postcondition : invocations are executed successfully, no exception is thrown and
+ * parameters are correctly returned.
+ */
+ @SuppressWarnings("unchecked")
+ public void testOperationInvocationOK_withSimpleTypes() throws Exception
+ {
+ Long expectedLongResult = new Long(1373);
+ Boolean expectedBooleanResult = Boolean.TRUE;
+ Double expectedDoubleResult = new Double(12763.44);
+ Float expectedFloatResult = new Float(2727.233f);
+ Integer expectedIntegerResult = new Integer(28292);
+ Short expectedShortResult = new Short((short)227);
+ String expectedStringResult = "expectedStringResult";
+ URI expectedUriResult = URI.create("http://qpid.apache.org/");
+ Date expectedDateResult = new Date();
+
+ Object result = _resourceClient.invoke(
+ _invocationHandlers.get("echoWithSimpleTypes"),
+ new Object[]{
+ expectedLongResult,
+ expectedBooleanResult,
+ expectedDoubleResult,
+ expectedFloatResult,
+ expectedIntegerResult,
+ expectedShortResult,
+ expectedStringResult,
+ expectedUriResult,
+ expectedDateResult});
+
+ Method getOutputParameters = result.getClass().getMethod("getOutputParameters");
+ Map<String,Object> out = (Map<String, Object>) getOutputParameters.invoke(result);
+
+ assertEquals("Output parameters must be 9.",9,out.size());
+ assertTrue("Long output parameter not found on result object.",out.containsValue(expectedLongResult));
+ assertTrue("Boolean output parameter not found on result object.",out.containsValue(expectedBooleanResult));
+ assertTrue("Double output parameter not found on result object.",out.containsValue(expectedDoubleResult));
+ assertTrue("Float output parameter not found on result object.",out.containsValue(expectedFloatResult));
+ assertTrue("Integer output parameter not found on result object.",out.containsValue(expectedIntegerResult));
+ assertTrue("Short output parameter not found on result object.",out.containsValue(expectedShortResult));
+ assertTrue("String output parameter not found on result object.",out.containsValue(expectedStringResult));
+ assertTrue("URI output parameter not found on result object.",out.containsValue(expectedUriResult));
+ assertTrue("Date output parameter not found on result object.",out.containsValue(expectedDateResult));
+ }
+
+ /**
+ * Test operation invocation on WS-Resource.
+ * This method tests the exchange of arrays between requestor and service provider.
+ * For this test exchanged arrays contain :
+ *
+ * <ul>
+ * <li>java.lang.Long (xsd:long)
+ * <li>java.lang.Integer (xsd:int / xsd:integer)
+ * <li>java.lang.Double (xsd:double)
+ * <li>java.lang.Float (xsd:float)
+ * <li>java.lang.Short (xsd:short)
+ * <li>java.lang.Boolean (xsd:boolean)
+ * <li>java.lang.String (xsd:string)
+ * <li>java.net.URI (xsd:anyURI)
+ * <li>java.util.Date(xsd:dateTime)
+ * </ul>
+ *
+ * <br>precondition : a ws resource exists and is registered and the requested operation is available on that.
+ * <br>postcondition : invocations are executed successfully, no exception is thrown and parameters are correctly returned.
+ */
+ @SuppressWarnings("unchecked")
+ public void testOperationInvocationOK_withWrapperArrays() throws Exception
+ {
+ Long [] expectedLongResult = {new Long(2),new Long(1),new Long(3),new Long(4)};
+ Boolean [] expectedBooleanResult = { Boolean.TRUE,Boolean.FALSE,Boolean.FALSE};
+ Double [] expectedDoubleResult = {12763.44d,2832.33d,2292.33d,22293.22d};
+ Float [] expectedFloatResult = {2727.233f,1f,2f,4f,5.4f,33.2f};
+ Integer [] expectedIntegerResult = {1,2,3,4,55,66,77,88,99};
+ Short [] expectedShortResult = {(short)227,(short)23,(short)9};
+ String [] expectedStringResult = {"s1","s2","s333","s4"};
+ URI [] expectedUriResult = {
+ URI.create("http://qpid.apache.org/"),
+ URI.create("http://www.apache.org"),
+ URI.create("http://projects.apache.org")};
+
+ Date [] expectedDateResult = {
+ new Date(),
+ new Date(38211897),
+ new Date(903820382)};
+
+ Object result = _resourceClient.invoke(
+ _invocationHandlers.get("echoWithArrays"),
+ new Object[]{
+ expectedLongResult,
+ expectedBooleanResult,
+ expectedDoubleResult,
+ expectedFloatResult,
+ expectedIntegerResult,
+ expectedShortResult,
+ expectedStringResult,
+ expectedUriResult,
+ expectedDateResult});
+
+ Method getOutputParameters = result.getClass().getMethod("getOutputParameters");
+ Map<String,Object> out = (Map<String, Object>) getOutputParameters.invoke(result);
+
+ assertEquals("Output parameters must be 9.",9,out.size());
+ assertTrue("Long array doesn't match.",Arrays.equals(expectedLongResult, (Long[])out.get(Long.class.getName())));
+ assertTrue("Boolean array doesn't match.",Arrays.equals(expectedBooleanResult, (Boolean[])out.get(Boolean.class.getName())));
+ assertTrue("Double array doesn't match.",Arrays.equals(expectedDoubleResult, (Double[])out.get(Double.class.getName())));
+ assertTrue("Float array doesn't match.",Arrays.equals(expectedFloatResult, (Float[])out.get(Float.class.getName())));
+ assertTrue("Integer array doesn't match.", Arrays.equals(expectedIntegerResult, (Integer[])out.get(Integer.class.getName())));
+ assertTrue("Short array doesn't match.",Arrays.equals(expectedShortResult, (Short[])out.get(Short.class.getName())));
+ assertTrue("String array doesn't match.",Arrays.equals(expectedStringResult, (String[])out.get(String.class.getName())));
+ assertTrue("URI array doesn't match.",Arrays.equals(expectedUriResult, (URI[])out.get(URI.class.getName())));
+ assertTrue("Date array doesn't match.",Arrays.equals(expectedDateResult, (Date[])out.get(Date.class.getName())));
+ }
+
+ /**
+ * Test operation invocation on WS-Resource.
+ * This method tests the exchange of primitive type arrays between requestor and service provider.
+ * NOte that even the sent array contain primtiive type QMan deals only with objects so in the result
+ * object you will find the corresponding wrapper types.
+ *
+ * For this test exchanged arrays contain :
+ *
+ * <ul>
+ * <li>java.lang.Long / long (xsd:long)
+ * <li>java.lang.Integer / int (xsd:int / xsd:integer)
+ * <li>java.lang.Double/ double (xsd:double)
+ * <li>java.lang.Float / float (xsd:float)
+ * <li>java.lang.Short / short (xsd:short)
+ * <li>java.lang.Boolean / boolean (xsd:boolean)
+ * </ul>
+ *
+ * <br>precondition : a ws resource exists and is registered and the requested operation is available on that.
+ * <br>postcondition : invocations are executed successfully, no exception is thrown and parameters are correctly returned.
+ */
+ @SuppressWarnings("unchecked")
+ public void testOperationInvocationOK_withPrimitiveArrays() throws Exception
+ {
+ long [] expectedLongResult = {1L,2L,3L,4L};
+ boolean [] expectedBooleanResult = { true,false,false};
+ double [] expectedDoubleResult = {12763.44d,2832.33d,2292.33d,22293.22d};
+ float [] expectedFloatResult = {2727.233f,1f,2f,4f,5.4f,33.2f};
+ int [] expectedIntegerResult = {1,2,3,4,55,66,77,88,99};
+ short [] expectedShortResult = {(short)227,(short)23,(short)9};
+
+ Object result = _resourceClient.invoke(
+ _invocationHandlers.get("echoWithSimpleTypeArrays"),
+ new Object[]{
+ expectedLongResult,
+ expectedBooleanResult,
+ expectedDoubleResult,
+ expectedFloatResult,
+ expectedIntegerResult,
+ expectedShortResult});
+
+ Method getOutputParameters = result.getClass().getMethod("getOutputParameters");
+ Map<String,Object> out = (Map<String, Object>) getOutputParameters.invoke(result);
+
+ assertEquals("Output parameters must be 6.",6,out.size());
+ assertArrayEquals(expectedLongResult, out.get(long.class.getName()));
+ assertArrayEquals(expectedBooleanResult, out.get(boolean.class.getName()));
+ assertArrayEquals(expectedDoubleResult, out.get(double.class.getName()));
+ assertArrayEquals(expectedFloatResult, out.get(float.class.getName()));
+ assertArrayEquals(expectedIntegerResult, out.get(int.class.getName()));
+ assertArrayEquals(expectedShortResult, out.get(short.class.getName()));
+ }
+
+ /**
+ * Internal method used for array comparison using reflection.
+ *
+ * @param expectedArray the expected array.
+ * @param resultArray the array that must match the expected one.
+ */
+ private void assertArrayEquals(Object expectedArray, Object resultArray)
+ {
+ int expectedArrayLength = Array.getLength(expectedArray);
+ int resultArrayLength = Array.getLength(resultArray);
+
+ assertEquals(expectedArrayLength,resultArrayLength);
+
+ for (int index = 0; index < expectedArrayLength; index++)
+ {
+ Object expected = Array.get(expectedArray, index);
+ Object result = Array.get(resultArray, index);
+
+ assertEquals(expected,result);
+ }
+ }
+
+ private Map<String,ProxyHandler> createInvocationHandlers()
+ {
+ Map<String, ProxyHandler> handlers = new HashMap<String, ProxyHandler>();
+
+ ProxyHandler handler = new ReflectionProxyHandler();
+ handler.setAction(Names.NAMESPACE_URI+"/"+"voidWithoutArguments");
+ handler.setRequestName(
+ new QName(
+ Names.NAMESPACE_URI,
+ "voidWithoutArgumentsRequest",
+ Names.PREFIX));
+ handler.setRequestParameterNames(new QName[]{});
+ handler.setResponseName(
+ new QName(
+ Names.NAMESPACE_URI,
+ "voidWithoutArgumentsResponse",
+ Names.PREFIX));
+ handler.setReturnType(Result.class);
+
+ ProxyHandler exceptionHandler = new ReflectionProxyHandler();
+ exceptionHandler.setAction(Names.NAMESPACE_URI+"/"+"throwsException");
+ exceptionHandler.setRequestName(
+ new QName(
+ Names.NAMESPACE_URI,
+ "throwsExceptionRequest",
+ Names.PREFIX));
+
+ exceptionHandler.setRequestParameterNames(new QName[]{});
+ exceptionHandler.setResponseName(
+ new QName(
+ Names.NAMESPACE_URI,
+ "throwsExceptionResponse",
+ Names.PREFIX));
+
+ exceptionHandler.setReturnType(Result.class);
+
+ ProxyHandler echoWithWrapperTypesHandler = new ReflectionProxyHandler();
+ echoWithWrapperTypesHandler.setAction(Names.NAMESPACE_URI+"/"+"echoWithSimpleTypes");
+ echoWithWrapperTypesHandler.setRequestName(
+ new QName(
+ Names.NAMESPACE_URI,
+ "echoWithSimpleTypesRequest",
+ Names.PREFIX));
+
+ echoWithWrapperTypesHandler.setRequestParameterNames(new QName[]{
+ new QName(Names.NAMESPACE_URI,"p1",Names.PREFIX),
+ new QName(Names.NAMESPACE_URI,"p2",Names.PREFIX),
+ new QName(Names.NAMESPACE_URI,"p3",Names.PREFIX),
+ new QName(Names.NAMESPACE_URI,"p4",Names.PREFIX),
+ new QName(Names.NAMESPACE_URI,"p5",Names.PREFIX),
+ new QName(Names.NAMESPACE_URI,"p6",Names.PREFIX),
+ new QName(Names.NAMESPACE_URI,"p7",Names.PREFIX),
+ new QName(Names.NAMESPACE_URI,"p8",Names.PREFIX),
+ new QName(Names.NAMESPACE_URI,"p9",Names.PREFIX),
+ });
+
+ echoWithWrapperTypesHandler.setResponseName(
+ new QName(
+ Names.NAMESPACE_URI,
+ "echoWithSimpleTypesResponse",
+ Names.PREFIX));
+
+ echoWithWrapperTypesHandler.setReturnType(Result.class);
+
+ ProxyHandler echoWithArrayOfWrapperTypes = new ReflectionProxyHandler();
+ echoWithArrayOfWrapperTypes.setAction(Names.NAMESPACE_URI+"/"+"echoWithArrays");
+ echoWithArrayOfWrapperTypes.setRequestName(
+ new QName(
+ Names.NAMESPACE_URI,
+ "echoWithArraysRequest",
+ Names.PREFIX));
+
+ echoWithArrayOfWrapperTypes.setRequestParameterNames(new QName[]{
+ new QName(Names.NAMESPACE_URI,"p1",Names.PREFIX),
+ new QName(Names.NAMESPACE_URI,"p2",Names.PREFIX),
+ new QName(Names.NAMESPACE_URI,"p3",Names.PREFIX),
+ new QName(Names.NAMESPACE_URI,"p4",Names.PREFIX),
+ new QName(Names.NAMESPACE_URI,"p5",Names.PREFIX),
+ new QName(Names.NAMESPACE_URI,"p6",Names.PREFIX),
+ new QName(Names.NAMESPACE_URI,"p7",Names.PREFIX),
+ new QName(Names.NAMESPACE_URI,"p8",Names.PREFIX),
+ new QName(Names.NAMESPACE_URI,"p9",Names.PREFIX),
+ });
+
+ echoWithArrayOfWrapperTypes.setResponseName(
+ new QName(
+ Names.NAMESPACE_URI,
+ "echoWithArraysResponse",
+ Names.PREFIX));
+
+ echoWithArrayOfWrapperTypes.setReturnType(Result.class);
+
+ ProxyHandler echoWithArrayOfPrimitiveTypes = new ReflectionProxyHandler();
+ echoWithArrayOfPrimitiveTypes.setAction(Names.NAMESPACE_URI+"/"+"echoWithSimpleTypeArrays");
+ echoWithArrayOfPrimitiveTypes.setRequestName(
+ new QName(
+ Names.NAMESPACE_URI,
+ "echoWithSimpleTypeArraysRequest",
+ Names.PREFIX));
+
+ echoWithArrayOfPrimitiveTypes.setRequestParameterNames(new QName[]{
+ new QName(Names.NAMESPACE_URI,"p1",Names.PREFIX),
+ new QName(Names.NAMESPACE_URI,"p2",Names.PREFIX),
+ new QName(Names.NAMESPACE_URI,"p3",Names.PREFIX),
+ new QName(Names.NAMESPACE_URI,"p4",Names.PREFIX),
+ new QName(Names.NAMESPACE_URI,"p5",Names.PREFIX),
+ new QName(Names.NAMESPACE_URI,"p6",Names.PREFIX)});
+
+ echoWithArrayOfPrimitiveTypes.setResponseName(
+ new QName(
+ Names.NAMESPACE_URI,
+ "echoWithSimpleTypeArraysResponse",
+ Names.PREFIX));
+
+ echoWithArrayOfPrimitiveTypes.setReturnType(Result.class);
+
+ ProxyHandler echoWithByteArray = new EnhancedReflectionProxyHandler();
+ echoWithByteArray.setAction(Names.NAMESPACE_URI+"/"+"echoWithByteArray");
+ echoWithByteArray.setRequestName(
+ new QName(
+ Names.NAMESPACE_URI,
+ "echoWithByteArrayRequest",
+ Names.PREFIX));
+
+ echoWithByteArray.setRequestParameterNames(
+ new QName[]{
+ new QName(Names.NAMESPACE_URI,"p1",Names.PREFIX)});
+
+ echoWithByteArray.setResponseName(
+ new QName(
+ Names.NAMESPACE_URI,
+ "echoWithByteArrayResponse",
+ Names.PREFIX));
+
+ echoWithByteArray.setReturnType(Result.class);
+
+ ProxyHandler echoWithUUID = new EnhancedReflectionProxyHandler();
+ echoWithUUID.setAction(Names.NAMESPACE_URI+"/"+"echoWithUUID");
+ echoWithUUID.setRequestName(
+ new QName(
+ Names.NAMESPACE_URI,
+ "echoWithUUIDRequest",
+ Names.PREFIX));
+
+ echoWithUUID.setRequestParameterNames(
+ new QName[]{
+ new QName(Names.NAMESPACE_URI,"p1",Names.PREFIX)});
+
+ echoWithUUID.setResponseName(
+ new QName(
+ Names.NAMESPACE_URI,
+ "echoWithUUIDResponse",
+ Names.PREFIX));
+
+ echoWithUUID.setReturnType(Result.class);
+
+ ProxyHandler echoWithMap = new EnhancedReflectionProxyHandler();
+ echoWithMap.setAction(Names.NAMESPACE_URI+"/"+"echoWithMap");
+ echoWithMap.setRequestName(
+ new QName(
+ Names.NAMESPACE_URI,
+ "echoWithMapRequest",
+ Names.PREFIX));
+
+ echoWithMap.setRequestParameterNames(
+ new QName[]{
+ new QName(Names.NAMESPACE_URI,"p1",Names.PREFIX)});
+
+ echoWithMap.setResponseName(
+ new QName(
+ Names.NAMESPACE_URI,
+ "echoWithMapResponse",
+ Names.PREFIX));
+
+ echoWithMap.setReturnType(Result.class);
+
+ handlers.put("voidWithoutArguments",handler);
+ handlers.put("echoWithSimpleTypes",echoWithWrapperTypesHandler);
+ handlers.put("echoWithArrays",echoWithArrayOfWrapperTypes);
+ handlers.put("echoWithSimpleTypeArrays", echoWithArrayOfPrimitiveTypes);
+ handlers.put("echoWithByteArray", echoWithByteArray);
+ handlers.put("echoWithUUID", echoWithUUID);
+ handlers.put("echoWithMap", echoWithMap);
+ handlers.put("throwsException",exceptionHandler);
+ return handlers;
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/ServerThread.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/ServerThread.java
new file mode 100644
index 0000000000..6574c278ff
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/ServerThread.java
@@ -0,0 +1,118 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm;
+
+import java.io.File;
+
+import org.apache.qpid.management.Names;
+import org.mortbay.component.LifeCycle.Listener;
+import org.mortbay.jetty.Connector;
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.nio.SelectChannelConnector;
+import org.mortbay.jetty.webapp.WebAppContext;
+import org.mortbay.start.Monitor;
+
+/**
+ * Web Server startup thread.
+ * It is used on adapter test case in order to start the embedded
+ * web server as a separated thread.
+ *
+ * @author Andrea Gazzarini
+ */
+class ServerThread extends Thread
+{
+ private final Listener _lifecycleListener;
+ private Server _server;
+
+ private SelectChannelConnector _connector;
+
+ /**
+ * Builds a new server thread with the given lifecycle listener.
+ *
+ * @param listener the lifecycle listener.
+ */
+ ServerThread(Listener listener)
+ {
+ this._lifecycleListener = listener;
+ }
+
+ /**
+ * Starts the server.
+ */
+ @Override
+ public void run()
+ {
+ try
+ {
+ Monitor.monitor();
+ _server = new Server();
+ _server.setStopAtShutdown(true);
+
+ _connector=new SelectChannelConnector();
+ _connector.setPort(Integer.parseInt(System.getProperty(Names.ADAPTER_PORT_PROPERTY_NAME)));
+ _connector.setHost(System.getProperty(Names.ADAPTER_HOST_PROPERTY_NAME));
+
+
+ _server.setConnectors(new Connector[]{_connector});
+
+ WebAppContext webapp = new WebAppContext();
+ webapp.setContextPath("/qman");
+
+ // Additional web application descriptor containing test components.
+ webapp.setDefaultsDescriptor("/org/apache/qpid/management/wsdm/web.xml");
+
+ String webApplicationPath = System.getProperty("qman.war");
+ File rootFolderPath = (webApplicationPath != null) ? new File(webApplicationPath) : new File(".");
+
+ webapp.setWar(rootFolderPath.toURI().toURL().toExternalForm());
+ webapp.addLifeCycleListener(_lifecycleListener);
+ _server.setHandler(webapp);
+ _server.start();
+ System.setProperty(Names.ADAPTER_PORT_PROPERTY_NAME,String.valueOf( _connector.getLocalPort()));
+ _server.join();
+
+ } catch(Exception exception)
+ {
+ throw new RuntimeException(exception);
+ }
+ }
+
+ /**
+ * Shutdown the server.
+ *
+ * @throws Exception when a problem is encountered during shutdown.
+ */
+ void shutdown() throws Exception
+ {
+ _server.stop();
+ }
+
+ /**
+ * Returns the port number where the server is running.
+ *
+ * @return the port number where the server is running.
+ */
+ int getPort()
+ {
+ return _connector.getLocalPort();
+ }
+
+}
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/SetResourcePropertiesTestCase.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/SetResourcePropertiesTestCase.java
new file mode 100644
index 0000000000..87f8905e01
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/SetResourcePropertiesTestCase.java
@@ -0,0 +1,219 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm;
+
+import java.lang.reflect.Array;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.management.MBeanAttributeInfo;
+import javax.xml.namespace.QName;
+
+import org.apache.muse.ws.addressing.soap.SoapFault;
+import org.apache.muse.ws.resource.WsrfConstants;
+import org.apache.qpid.management.Names;
+
+/**
+ * Test case for Set Resource Properties interfaces.
+ *
+ * @author Andrea Gazzarini
+ */
+public class SetResourcePropertiesTestCase extends BaseWsDmAdapterTestCase
+{
+ /**
+ * Test the WS-RP SetResourceProperty interface of the WS-DM adapter.
+ *
+ * <br>precondition : a WS-Resource exists and is registered.
+ * <br>postcondition : property values are correctly updated on the target WS-Resource..
+ */
+ public void testSetResourcePropertiesOK() throws Exception
+ {
+ Map<String, Object> sampleMap = new HashMap<String, Object>();
+ sampleMap.put("Key1", "BLABALABLABALBAL");
+ sampleMap.put("Key2", 182838484l);
+ sampleMap.put("Key3", -928376362);
+ sampleMap.put("Key4", 23762736276.33D);
+ sampleMap.put("Key4", 2327363.2F);
+
+ Map<String, Object> sampleValues = new HashMap<String, Object>();
+ sampleValues.put(String.class.getName(),"SAMPLE_STRING");
+ sampleValues.put(UUID.class.getName(),UUID.randomUUID());
+ sampleValues.put(Boolean.class.getName(),Boolean.FALSE);
+ sampleValues.put(Map.class.getName(),sampleMap);
+ sampleValues.put(Long.class.getName(),283781273L);
+ sampleValues.put(Integer.class.getName(),12727);
+ sampleValues.put(Short.class.getName(),new Short((short)22));
+ sampleValues.put(Date.class.getName(),new Date());
+
+ MBeanAttributeInfo [] attributesMetadata = _mbeanInfo.getAttributes();
+ boolean atLeastThereIsOneWritableProperty = false;
+
+ for (MBeanAttributeInfo attributeMetadata : attributesMetadata)
+ {
+ String name = attributeMetadata.getName();
+
+ if (attributeMetadata.isWritable())
+ {
+ atLeastThereIsOneWritableProperty = true;
+ Object sampleValue = sampleValues.get(attributeMetadata.getType());
+ Object []values = new Object[]{sampleValue};
+
+ Object result = _managementServer.getAttribute(_resourceObjectName, name);
+ if (result == null)
+ {
+ _resourceClient.insertResourceProperty(
+ new QName(
+ Names.NAMESPACE_URI,
+ name,
+ Names.PREFIX),
+ values);
+ } else
+ {
+ _resourceClient.updateResourceProperty(
+ new QName(
+ Names.NAMESPACE_URI,
+ name,
+ Names.PREFIX),
+ values);
+ }
+
+ Object propertyValues = _resourceClient.getPropertyAsObject(
+ new QName(
+ Names.NAMESPACE_URI,
+ name,
+ Names.PREFIX),
+ Class.forName(attributeMetadata.getType()));
+ int length = Array.getLength(propertyValues);
+ if (length != 0)
+ {
+ Object propertyValue = Array.get(propertyValues, 0);
+
+ assertEquals(
+ "Comparison failed for property "+name,
+ sampleValue,
+ propertyValue);
+ } else {
+ assertNull(
+ String.format(
+ "\"%s\" property value shouldn't be null. Its value is %s",
+ name,
+ _managementServer.getAttribute(_resourceObjectName,name)),
+ sampleValue);
+ }
+ }
+ }
+ assertTrue(
+ "It's not possibile to run successfully this test case if " +
+ "the target WS-Resource has no at least one writable property",
+ atLeastThereIsOneWritableProperty);
+ }
+
+ /**
+ * Test the WS-RP SetResourceProperty interface of the WS-DM adapter when the
+ * target property is null.
+ * According to WS-RP specs this operation is not allowed because in this case a SetResourceProperty with an "Insert"
+ * message should be sent in order to initialize the property.
+ *
+ * <br>precondition : a ws resource exists and is registered. The value of the target property is null.
+ * <br>postcondition : a Soap fault is received indicating the failuire.
+ */
+ public void testSetResourcePropertiesKO() throws Exception
+ {
+ Object typePropertyValue = _managementServer.getAttribute(_resourceObjectName, "Type");
+ assertNull(typePropertyValue);
+
+ try
+ {
+ _resourceClient.updateResourceProperty(
+ new QName(
+ Names.NAMESPACE_URI,
+ "Type",
+ Names.PREFIX),
+ new Object[]{"sampleValue"});
+ fail(
+ "If the property is null on the target ws resource, according " +
+ "to WS-RP specs, an update of its value is not possible.");
+ } catch(SoapFault expected)
+ {
+
+ }
+ }
+
+ /**
+ * Tests the SetResourceProperties (update) interface when the request contains
+ * an unknwon target resource.
+ *
+ * <br>precondition : the SetResourceProperties contains an unknwon resource.
+ * <br>postcondition : a SoapFault is thrown and the corresponding detail contains an
+ * UnknownResourceFault element.
+ */
+ public void testUpdateResourcePropertiesKO_WithUnknownResourceFault() throws Exception
+ {
+ try
+ {
+ _resourceClient.getEndpointReference().removeParameter(Names.RESOURCE_ID_QNAME);
+ _resourceClient.getEndpointReference().addParameter(Names.RESOURCE_ID_QNAME,"lablabalbal");
+
+ _resourceClient.updateResourceProperty(
+ new QName(
+ Names.NAMESPACE_URI,
+ "Type",
+ Names.PREFIX),
+ new Object[]{"sampleValue"});
+ } catch(SoapFault expected)
+ {
+ assertEquals(
+ WsrfConstants.RESOURCE_UNKNOWN_QNAME.getLocalPart(),
+ expected.getDetail().getLocalName());
+ }
+ }
+
+ /**
+ * Tests the SetResourceProperties (insert) interface when the request contains
+ * an unknwon target resource.
+ *
+ * <br>precondition : the SetResourceProperties contains an unknwon resource.
+ * <br>postcondition : a SoapFault is thrown and the corresponding detail contains an
+ * UnknownResourceFault element.
+ */
+ public void testInsertResourcePropertiesKO_WithUnknownResourceFault() throws Exception
+ {
+ try
+ {
+ _resourceClient.getEndpointReference().removeParameter(Names.RESOURCE_ID_QNAME);
+ _resourceClient.getEndpointReference().addParameter(Names.RESOURCE_ID_QNAME,"lablabalbal");
+
+ _resourceClient.insertResourceProperty(
+ new QName(
+ Names.NAMESPACE_URI,
+ "Type",
+ Names.PREFIX),
+ new Object[]{"sampleValue"});
+ } catch(SoapFault expected)
+ {
+ assertEquals(
+ WsrfConstants.RESOURCE_UNKNOWN_QNAME.getLocalPart(),
+ expected.getDetail().getLocalName());
+ }
+ }
+}
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/WebApplicationLifeCycleListener.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/WebApplicationLifeCycleListener.java
new file mode 100644
index 0000000000..91c646467e
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/WebApplicationLifeCycleListener.java
@@ -0,0 +1,61 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm;
+
+import org.mortbay.component.LifeCycle;
+import org.mortbay.component.LifeCycle.Listener;
+
+/**
+ * Adapter class used to provide an empty (base) implementation of
+ * Lifecycle listener interface.
+ *
+ * Adapter test case needs to be informed about the lifecycle of the
+ * deployed QMan application. Only when its deployment is completed the test
+ * case can run successfully.
+ *
+ * So, following the same logic of Swng event model, this is an adapter that provides
+ * empty implementation of the listener interface (see for example MouseAdapter
+ * for mouse events listener)
+ *
+ * @author Andrea Gazzarini
+ */
+public class WebApplicationLifeCycleListener implements Listener
+{
+ public void lifeCycleFailure(LifeCycle event, Throwable cause)
+ {
+ }
+
+ public void lifeCycleStarted(LifeCycle event)
+ {
+ }
+
+ public void lifeCycleStarting(LifeCycle event)
+ {
+ }
+
+ public void lifeCycleStopped(LifeCycle event)
+ {
+ }
+
+ public void lifeCycleStopping(LifeCycle event)
+ {
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/WsDmAdapterTest.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/WsDmAdapterTest.java
new file mode 100644
index 0000000000..07395b3be9
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/WsDmAdapterTest.java
@@ -0,0 +1,156 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.muse.core.serializer.SerializerRegistry;
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.Protocol;
+import org.apache.qpid.management.wsdm.capabilities.Result;
+import org.apache.qpid.management.wsdm.muse.serializer.DateSerializer;
+import org.apache.qpid.management.wsdm.muse.serializer.InvocationResultSerializer;
+import org.apache.qpid.management.wsdm.muse.serializer.MapSerializer;
+import org.apache.qpid.management.wsdm.muse.serializer.ObjectSerializer;
+import org.apache.qpid.management.wsdm.muse.serializer.UUIDSerializer;
+import org.mortbay.component.LifeCycle;
+import org.mortbay.component.LifeCycle.Listener;
+
+import junit.extensions.TestSetup;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class WsDmAdapterTest
+{
+
+ /**
+ * Test case wide set up.
+ * Provides Server startup & shutdown global procedure.
+ *
+ * @author Andrea Gazzarini
+ */
+ private static class WsDmAdapterTestSetup extends TestSetup
+ {
+ private Object _serverMonitor = new Object();
+
+ Listener listener = new WebApplicationLifeCycleListener()
+ {
+ public void lifeCycleStarted(LifeCycle event)
+ {
+ synchronized (_serverMonitor)
+ {
+ _serverMonitor.notify();
+ }
+ }
+ };
+
+ private ServerThread _server;
+
+ /**
+ * Builds a new test setup with for the given test.
+ *
+ * @param test the decorated test.
+ */
+ public WsDmAdapterTestSetup(Test test)
+ {
+ super(test);
+ }
+
+ /**
+ * Starts up Web server.
+ *
+ * @throws Exception when the server startup fails.
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ SerializerRegistry.getInstance().registerSerializer(Object.class, new ObjectSerializer());
+ SerializerRegistry.getInstance().registerSerializer(Date.class, new DateSerializer());
+ SerializerRegistry.getInstance().registerSerializer(Map.class, new MapSerializer());
+ SerializerRegistry.getInstance().registerSerializer(HashMap.class, new MapSerializer());
+ SerializerRegistry.getInstance().registerSerializer(UUID.class, new UUIDSerializer());
+ SerializerRegistry.getInstance().registerSerializer(Result.class, new InvocationResultSerializer());
+
+ System.setProperty(
+ Names.ADAPTER_HOST_PROPERTY_NAME,
+ Protocol.DEFAULT_QMAN_HOSTNAME);
+
+ System.setProperty(
+ Names.ADAPTER_PORT_PROPERTY_NAME,
+ String.valueOf(getFreePort()));
+
+ _server = new ServerThread(listener);
+ _server.start();
+
+ synchronized(_serverMonitor) {
+ _serverMonitor.wait();
+ Thread.sleep(2000);
+ }
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ _server.shutdown();
+ }
+ };
+
+ /**
+ * Gets the test suite composition.
+ *
+ * @return the test suite composition.
+ */
+ public static Test suite()
+ {
+ TestSuite suite = new TestSuite("Test suite for QMan WS-DM.");
+ suite.addTestSuite(MetadataExchangeInterfaceTestCase.class);
+ suite.addTestSuite(OperationInvocationInterfaceTestCase.class);
+ suite.addTestSuite(GetResourcePropertyDocumentTestCase.class);
+ suite.addTestSuite(SetResourcePropertiesTestCase.class);
+ suite.addTestSuite(GetMultipleResourcePropertiesTestCase.class);
+ suite.addTestSuite(GetResourcePropertiesTestCase.class);
+ return new WsDmAdapterTestSetup(suite);
+ }
+
+ /**
+ * Finds a free port that will be used to run the embedded
+ * web server.
+ *
+ * @return a free port that will be used to run the
+ * embedded web server.
+ */
+ private static int getFreePort() throws IOException {
+ ServerSocket server = null;
+ try
+ {
+ server = new ServerSocket(0);
+ return server.getLocalPort();
+ } finally
+ {
+ server.close();
+ }
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityBuilderTest.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityBuilderTest.java
new file mode 100644
index 0000000000..68c9930ecd
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityBuilderTest.java
@@ -0,0 +1,335 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.capabilities;
+
+import java.lang.management.ManagementFactory;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javassist.CtClass;
+import javassist.CtMethod;
+
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.xml.namespace.QName;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.management.domain.handler.impl.QpidDomainObject;
+import org.apache.qpid.management.wsdm.common.EntityInstanceNotFoundFault;
+import org.apache.qpid.management.wsdm.common.MethodInvocationFault;
+import org.apache.qpid.management.wsdm.common.NoSuchAttributeFault;
+import org.apache.qpid.management.wsdm.common.QManFault;
+
+/**
+ * Test case for MBean capability builder.
+ *
+ * @author Andrea Gazzarini
+ */
+public class MBeanCapabilityBuilderTest extends TestCase
+{
+
+ /**
+ * Management interface for an mbean that has no properties and no
+ * methods.
+ *
+ * @author Andrea Gazzarini
+ */
+ public interface NoPropertiesNoMethodsMBean
+ {
+ }
+
+ /**
+ * Implementation of the managenent interface described above.
+ *
+ * @author Andrea Gazzarini
+ */
+ public class NoPropertiesNoMethods implements NoPropertiesNoMethodsMBean
+ {
+ }
+
+ private MBeanCapabilityBuilder _builder;
+ private ObjectName _objectName;
+
+ /**
+ * Set up fixture for this test case.
+ */
+ protected void setUp() throws Exception
+ {
+ _builder = new MBeanCapabilityBuilder();
+ _objectName = new ObjectName("Test:Name=aName,class=DomainObject");
+ }
+
+ /**
+ * Tests that state change that occcurs on the begin() method when the requested
+ * class has not been defined.
+ */
+ public void testBegin_withClassNotYetDefined() throws Exception
+ {
+ _builder.begin(_objectName);
+ assertEquals(_builder._state,_builder._classNotAvailable);
+ }
+
+ /**
+ * Tests that state change that occcurs on the begin() method when the requested
+ * class has not been defined.
+ */
+ public void testBegin_withClassAlreadyDefined() throws Exception
+ {
+ _objectName = new ObjectName("Test:Name=aString,class=MBeanCapabilityBuilder");
+ _builder.begin(_objectName);
+
+ assertTrue(_builder._state instanceof DummyCapabilityBuilder);
+ assertSame(_builder._endAttributeHandler, _builder._noPropertyHasBeenDefined);
+ }
+
+ /**
+ * Tests the generateGetter method().
+ */
+ public void testGenerateGetter()
+ {
+ String name ="MyProperty";
+ String type = Long.class.getName();
+ String expected =
+ "public "+
+ type+
+ " get"+
+ name+
+ "() throws NoSuchAttributeFault,EntityInstanceNotFoundFault,QManFault { return ("+
+ type+
+ ") getAttribute(\""+
+ name+
+ "\"); }";
+
+ String result = _builder.generateGetter(type, name,name);
+ assertEquals(expected,result);
+ }
+
+ /**
+ * Tests the generateGetter method().
+ */
+ public void testGenerateSetter()
+ {
+ String name ="MyProperty";
+ String type = Long.class.getName();
+ String expected =
+ "public void setMyProperty("+
+ type+
+ " newValue) throws NoSuchAttributeFault,EntityInstanceNotFoundFault,QManFault { setAttribute(\""+
+ name+
+ "\", newValue); }";
+
+ String result = _builder.generateSetter(type, name,name);
+ assertEquals(expected,result);
+ }
+
+ /**
+ * Tests buils of a capability that has no properties and methods
+ *
+ * <br>precondition : the incoming entity definition is empty (no properties and no methods)
+ * <br>postcondition : the capability class is built successfully and has no props and methods.
+ * The getPropertyNames returns an empty QName array.
+ */
+ public void testOK_WithNoPropertiesNoMethods() throws Exception {
+
+ ObjectName name = new ObjectName("Test:Name=NoPropertiesNoMethods");
+
+ MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+ server.registerMBean(new NoPropertiesNoMethods(), name);
+
+ _builder.begin(name);
+ _builder.endAttributes();
+ _builder.endOperations();
+ Class<MBeanCapability> capabilityClass = _builder.getCapabilityClass();
+
+ Field[] fields = capabilityClass.getDeclaredFields();
+ Method [] methods = capabilityClass.getDeclaredMethods();
+
+ assertEquals(Arrays.toString(fields),0,fields.length);
+ assertEquals(Arrays.toString(methods),1,methods.length);
+
+ Method getPropertyNames = methods[0];
+ assertEquals("getPropertyNames",getPropertyNames.getName());
+
+
+ MBeanCapability capability = capabilityClass.newInstance();
+ QName [] properties = (QName[]) getPropertyNames.invoke(capability);
+ assertEquals(0,properties.length);
+ }
+
+ /**
+ * Tests the whole execution of the builder.
+ */
+ @SuppressWarnings("unchecked")
+ public void testBuildOK() throws Exception
+ {
+ MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+ QpidDomainObject mbean = new QpidDomainObject();
+ server.registerMBean(mbean, _objectName);
+
+ _builder.begin(_objectName);
+
+ CtClass definition = _builder._capabilityClassDefinition;
+ assertEquals(
+ MBeanCapability.class.getName(),
+ definition.getSuperclass().getName());
+
+ MBeanInfo metadata = server.getMBeanInfo(_objectName);
+
+ for (MBeanAttributeInfo attribute : metadata.getAttributes())
+ {
+ _builder.onAttribute(attribute);
+ checkAttribute(attribute, definition);
+
+ assertSame(
+ _builder._endAttributeHandler,
+ _builder._atLeastThereIsOneProperty);
+ }
+
+ for (MBeanOperationInfo operation : metadata.getOperations())
+ {
+ _builder.onOperation(operation);
+ checkOperation(operation,definition);
+ }
+
+ _builder.endAttributes();
+ _builder.endOperations();
+
+ assertNotNull(_builder.getCapabilityClass());
+ }
+
+ /**
+ * Checks an operation / method after that it has been declared on
+ * capability definition.
+ *
+ * @param operation the (JMX) operation metadata.
+ * @param definition the capability class definition.
+ * @throws Exception when something goes wrong during introspection.
+ */
+ private void checkOperation(MBeanOperationInfo operation, CtClass definition) throws Exception
+ {
+ CtMethod method = definition.getDeclaredMethod(operation.getName());
+ assertNotNull(method);
+
+ checkExceptionTypes(
+ method.getExceptionTypes(),
+ new String[]{
+ QManFault.class.getName(),
+ EntityInstanceNotFoundFault.class.getName(),
+ MethodInvocationFault.class.getName()});
+
+ assertEquals(Result.class.getName(),method.getReturnType().getName());
+
+ CtClass [] parameterTypes = method.getParameterTypes();
+ MBeanParameterInfo [] parameterMetadata = operation.getSignature();
+
+ assertEquals(parameterTypes.length, parameterMetadata.length);
+ for (int i = 0; i < parameterMetadata.length; i++)
+ {
+ assertEquals(
+ parameterTypes[i].getName(),
+ Class.forName(parameterMetadata[i].getType()).getCanonicalName());
+ }
+ }
+
+ /**
+ * Checks the exception types associated with a method.
+ *
+ * @param exceptionTypes the exception types actually thrown.
+ * @param expectedExceptionNames the expected exception types (as strings).
+ */
+ private void checkExceptionTypes(CtClass [] exceptionTypes, String [] expectedExceptionNames)
+ {
+ List<String> exceptionNames = new ArrayList<String>(exceptionTypes.length);
+ for (CtClass exception : exceptionTypes)
+ {
+ exceptionNames.add(exception.getName());
+ }
+
+ for (String expectedExceptionName : expectedExceptionNames)
+ {
+ exceptionNames.remove(expectedExceptionName);
+ }
+
+ assertTrue(exceptionNames.isEmpty());
+ }
+
+ /**
+ * Checks an attribute after that it has been declared on capability definition.
+ *
+ * @param attribute the (JMX) attribute metadata.
+ * @param definition the capability class definition.
+ * @throws Exception when something goes wrong during introspection.
+ */
+ private void checkAttribute(MBeanAttributeInfo attribute, CtClass definition) throws Exception
+ {
+ String name = _builder.getNameForAccessors(attribute.getName());
+
+ String newPropertyDeclaration =
+ new StringBuilder("new QName(Names.NAMESPACE_URI, \"")
+ .append(attribute.getName())
+ .append("\", Names.PREFIX),")
+ .toString();
+ assertTrue(_builder._properties.indexOf(newPropertyDeclaration) != -1);
+
+ if (attribute.isReadable())
+ {
+ CtMethod getter = definition.getDeclaredMethod("get"+name);
+ assertNotNull(getter);
+
+ checkExceptionTypes(
+ getter.getExceptionTypes(),
+ new String[]{
+ QManFault.class.getName(),
+ NoSuchAttributeFault.class.getName(),
+ EntityInstanceNotFoundFault.class.getName()});
+
+ assertEquals(0,getter.getParameterTypes().length);
+ assertEquals(attribute.getType(),getter.getReturnType().getName());
+ }
+
+ if (attribute.isWritable())
+ {
+ CtMethod setter = definition.getDeclaredMethod("set"+name);
+ assertNotNull(setter);
+
+ checkExceptionTypes(
+ setter.getExceptionTypes(),
+ new String[]{
+ QManFault.class.getName(),
+ NoSuchAttributeFault.class.getName(),
+ EntityInstanceNotFoundFault.class.getName()});
+
+ CtClass [] parameterTypes = setter.getParameterTypes();
+
+ assertEquals(1,parameterTypes.length);
+ assertEquals(attribute.getType(),parameterTypes[0].getName());
+ assertEquals(void.class.getName(),setter.getReturnType().getName());
+ }
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityTest.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityTest.java
new file mode 100644
index 0000000000..a9a6491209
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/MBeanCapabilityTest.java
@@ -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.
+ *
+ */
+package org.apache.qpid.management.wsdm.capabilities;
+
+import java.lang.management.ManagementFactory;
+import java.net.URI;
+
+import javax.management.ObjectName;
+
+import junit.framework.TestCase;
+
+import org.apache.muse.ws.addressing.EndpointReference;
+import org.apache.muse.ws.resource.WsResource;
+import org.apache.muse.ws.resource.impl.SimpleWsResource;
+import org.apache.qpid.management.domain.handler.impl.QpidDomainObject;
+import org.apache.qpid.management.wsdm.common.EntityInstanceNotFoundFault;
+import org.apache.qpid.management.wsdm.common.NoSuchAttributeFault;
+import org.apache.qpid.management.wsdm.common.QManFault;
+
+/**
+ * Test case for MBeanCapability supertype layer..
+ *
+ * @author Andrea Gazzarini
+ */
+public class MBeanCapabilityTest extends TestCase
+{
+ private final String _typeAttributeName = "Type";
+ private final String _newTypeValue = "DomainObject";
+
+ private ObjectName _objectName;
+ private ObjectName _unknownObjectName;
+
+ private MBeanCapability _capability;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ _objectName = new ObjectName("Test:Name=aName");
+ _unknownObjectName = new ObjectName("Test:Type=unknown");
+
+ _capability = new MBeanCapability(){
+ @Override
+ public WsResource getWsResource()
+ {
+ return new SimpleWsResource(){
+ @Override
+ public EndpointReference getEndpointReference()
+ {
+ return new EndpointReference(URI.create("http://qpid.apache.org/qman"));
+ }
+ };
+ }
+ };
+ _capability.setResourceObjectName(_objectName);
+ ManagementFactory.getPlatformMBeanServer().registerMBean(new QpidDomainObject(), _objectName);
+ }
+
+ /**
+ * Tests the execution of the getAttribute() and setAttribute() method.
+ *
+ * <br>precondition : the mbean is registered and a _capability is associated with it.
+ * <br>postcondition : the set value of the requested attribute is correctly returned.
+ */
+ public void testGetAndSetAttributeOK() throws Exception
+ {
+ Object name = _capability.getAttribute(_typeAttributeName);
+ assertNull("Name has an initial value of null so how is possibile that is not null?",name);
+
+ _capability.setAttribute(_typeAttributeName,_newTypeValue);
+
+ name = _capability.getAttribute(_typeAttributeName);
+ assertEquals("Now the name attribute must be set to \""+_newTypeValue+"\"",_newTypeValue,name);
+ }
+
+ /**
+ * Tests the execution of the getAttribute() and setAttribte() methods when an unknown attribute is given..
+ *
+ * <br>precondition : the mbean is registered, a _capability is associated with it and the requested attribute doesn't exist.
+ * <br>postcondition : an exception is thrown indicating the failure.
+ */
+ public void testNoSuchAttributeFault() throws Exception
+ {
+ // I suppose that we shouldn't have an attribute with this name...
+ String unknownAttribute = String.valueOf(System.currentTimeMillis());
+
+ try
+ {
+ _capability.getAttribute(unknownAttribute);
+ fail("An exception must be thrown here in order to indicate that the attribute is unknown.");
+ } catch(NoSuchAttributeFault expected)
+ {
+ }
+
+ try
+ {
+ _capability.setAttribute(unknownAttribute,null);
+ fail("An exception must be thrown here in order to indicate that the attribute is unknown.");
+ } catch(NoSuchAttributeFault expected)
+ {
+ }
+ }
+
+ /**
+ * Tests the execution of the setAttribute,getAttribute and invoke methods when the target mbean
+ * doesn't exists.
+ *
+ * <br>precondition : the object name associated with the capability is not pointing to an existent MBean.
+ * <br>postcondition : an exception is thrown indicating the failure.
+ */
+ public void testEntityInstanceNotFoundFault() throws Exception
+ {
+ _capability.setResourceObjectName(_unknownObjectName);
+
+ try
+ {
+ _capability.getAttribute(_typeAttributeName);
+ fail("An exception must be thrown here in order to indicate that the attribute is unknown.");
+ } catch(EntityInstanceNotFoundFault expected)
+ {
+ }
+
+ try
+ {
+ _capability.setAttribute(_typeAttributeName,_newTypeValue);
+ fail("An exception must be thrown here in order to indicate that the attribute is unknown.");
+ } catch(EntityInstanceNotFoundFault expected)
+ {
+ }
+
+ try
+ {
+ _capability.invoke("operationName", null,null);
+ fail("An exception must be thrown here in order to indicate that the attribute is unknown.");
+ } catch(EntityInstanceNotFoundFault expected)
+ {
+ }
+ }
+
+ /**
+ * Tests the execution of the setAttribute,getAttribute and invoke methods when an unknown / unexpected
+ * exception is thrown.
+ *
+ * <br>precondition : the mbean is registered and a capability is associated with it. Something
+ * unexpected happens during method invocation.
+ * <br>postcondition : an exception is thrown indicating the failure.
+ */
+ public void testQManFault() throws Exception
+ {
+ // Emulate a RuntimeException (which is the best example of uncaught exception... :) )
+ _capability.setResourceObjectName(null);
+
+ try
+ {
+ _capability.getAttribute(_typeAttributeName);
+ fail("An exception must be thrown here in order to indicate that the attribute is unknown.");
+ } catch(QManFault expected)
+ {
+ }
+
+ try
+ {
+ _capability.setAttribute(_typeAttributeName,_newTypeValue);
+ fail("An exception must be thrown here in order to indicate that the attribute is unknown.");
+ } catch(QManFault expected)
+ {
+ }
+
+ try
+ {
+ _capability.invoke("operationName", null,null);
+ fail("An exception must be thrown here in order to indicate that the attribute is unknown.");
+ } catch(QManFault expected)
+ {
+ }
+ }
+
+
+ /**
+ * Shutdown procedure for this test case.
+ */
+ @Override
+ protected void tearDown() throws Exception
+ {
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(_objectName);
+ }
+}
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/QManAdapterCapabilityTest.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/QManAdapterCapabilityTest.java
new file mode 100644
index 0000000000..648c7b2f60
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/QManAdapterCapabilityTest.java
@@ -0,0 +1,81 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.capabilities;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import org.apache.muse.ws.notification.NotificationProducer;
+import org.apache.qpid.management.Names;
+
+import junit.framework.TestCase;
+
+/**
+ * Test case for QMan adapter capability.
+ *
+ * @author Andrea Gazzarini
+ */
+public class QManAdapterCapabilityTest extends TestCase
+{
+ /**
+ * Tests the execution of the getTopicName() method.
+ *
+ * <br>precondition : an object type is given to the method (null is allowed).
+ * <br>postcondition : according to getTopicName() specs, the name of the
+ * topic associated with the given object type must be returned.
+ */
+ public void testGetTopicName()
+ {
+ final InvocationHandler invocationHandler = new InvocationHandler(){
+
+ public Object invoke(Object proxy, Method method, Object[] args)
+ {
+ return null;
+ }
+ };
+
+ QManAdapterCapability capability = new QManAdapterCapability(){
+ @Override
+ NotificationProducer getPublisherCapability()
+ {
+ return (NotificationProducer) Proxy.newProxyInstance(
+ getClass().getClassLoader(),
+ new Class[]{NotificationProducer.class},
+ invocationHandler);
+ }
+ };
+
+ capability.createLifeCycleTopics();
+
+ assertEquals(
+ Names.EVENTS_LIFECYLE_TOPIC_NAME,
+ capability.getTopicName(Names.EVENT));
+
+ assertEquals(
+ Names.OBJECTS_LIFECYLE_TOPIC_NAME,
+ capability.getTopicName(Names.CLASS));
+
+ assertEquals(
+ Names.UNKNOWN_OBJECT_TYPE_LIFECYLE_TOPIC_NAME,
+ capability.getTopicName("This is an unknown object Type @#!--!!@#"));
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/RmdBuilderTest.java b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/RmdBuilderTest.java
new file mode 100644
index 0000000000..77cda1c2c1
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/capabilities/RmdBuilderTest.java
@@ -0,0 +1,110 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.wsdm.capabilities;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.qpid.management.Names;
+import org.apache.qpid.management.domain.handler.impl.QpidDomainObject;
+import org.w3c.dom.Element;
+
+import junit.framework.TestCase;
+
+/**
+ * Test case for Resource Metadata Descriptor Builder.
+ *
+ * @author Andrea Gazzarini
+ */
+public class RmdBuilderTest extends TestCase
+{
+ private MBeanInfo _metadata;
+ private RmdBuilder _builder;
+ private ObjectName _objectName;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+ _objectName = new ObjectName("Test:Name=QpidDomainObject");
+
+ server.registerMBean(new QpidDomainObject(), _objectName);
+ _metadata = server.getMBeanInfo(_objectName);
+
+ _builder = new RmdBuilder();
+ _builder.begin(_objectName);
+
+ assertEquals(_objectName,_builder._objectName);
+ }
+
+ /**
+ * Tests the execution of the onOperation() method.
+ */
+ public void testOnOperation() throws Exception
+ {
+ MBeanAttributeInfo [] attributes = _metadata.getAttributes();
+ for (MBeanAttributeInfo attribute : attributes)
+ {
+ _builder.onAttribute(attribute);
+ }
+
+ Element [] rmd = _builder.getResourceMetadataDescriptor();
+
+ assertEquals(attributes.length,rmd.length);
+
+ for (MBeanAttributeInfo attribute: _metadata.getAttributes())
+ {
+ Element propertyMetadataDescriptor = getPropertyMetadatDescriptor(attribute.getName(), rmd);
+
+ String modifiability = propertyMetadataDescriptor.getAttribute(Names.MODIFIABILITY);
+ String expectedValue =
+ attribute.isWritable()
+ ? Names.READ_WRITE
+ : Names.READ_ONLY;
+ assertEquals(expectedValue,modifiability);
+ }
+ }
+
+ /**
+ * Returns the property metadata descriptor associated with the given attribute name.
+ *
+ * @param name the attribute name.
+ * @param rmd the resource metadata descriptor.
+ * @return the property metadata descriptor associated with the given attribute name.
+ * @throws RuntimeException if metadata for the given attribute is not found.
+ */
+ private Element getPropertyMetadatDescriptor(String name, Element [] rmd)
+ {
+ for (Element propertyMetadataDescriptor : rmd)
+ {
+ if ((Names.PREFIX+":"+name).equals(
+ propertyMetadataDescriptor.getAttribute(Names.NAME_ATTRIBUTE)))
+ {
+ return propertyMetadataDescriptor;
+ }
+ }
+ throw new RuntimeException("Property MetadataDescriptor not found for attribute "+name);
+ }
+} \ No newline at end of file
diff --git a/java/management/client/src/test/java/org/apache/qpid/management/wsdm/web.xml b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/web.xml
new file mode 100644
index 0000000000..d0a9eb20a4
--- /dev/null
+++ b/java/management/client/src/test/java/org/apache/qpid/management/wsdm/web.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+ <servlet>
+ <display-name>Qpid emulator startip</display-name>
+ <servlet-name>QEmu</servlet-name>
+ <servlet-class>org.apache.qpid.management.wsdm.QEmuInitializer</servlet-class>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+</web-app> \ No newline at end of file
diff --git a/java/management/client/web.xml b/java/management/client/web.xml
new file mode 100644
index 0000000000..29eb64a268
--- /dev/null
+++ b/java/management/client/web.xml
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app id="qman" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+ <description>
+ Q-Man is a Management bridge that exposes one (or several) Qpid
+ broker domain model as MBeans that are accessible through the
+ Java Management Extensions (JMX) and / or WS-DM.
+ </description>
+ <display-name>QManEE</display-name>
+ <listener>
+ <description>
+ Provides lifecycle management for QMan module.
+ </description>
+ <display-name>QMan Lifecycle manager</display-name>
+ <listener-class>org.apache.qpid.management.servlet.QManLifeCycleManager</listener-class>
+ </listener>
+ <servlet>
+ <display-name>QMan Proxy Servlet</display-name>
+ <servlet-name>Proxy</servlet-name>
+ <servlet-class>org.apache.qpid.management.servlet.WSDMAdapter</servlet-class>
+ <load-on-startup>2</load-on-startup>
+ </servlet>
+ <servlet>
+ <display-name>View Console (System Overview) Action</display-name>
+ <servlet-name>ViewConsole</servlet-name>
+ <servlet-class>org.apache.qpid.management.web.action.ConsoleAction</servlet-class>
+ <load-on-startup>5</load-on-startup>
+ </servlet>
+ <servlet>
+ <display-name>View Resources</display-name>
+ <servlet-name>ResourceManagement</servlet-name>
+ <servlet-class>org.apache.qpid.management.web.action.ResourcesManagementAction</servlet-class>
+ </servlet>
+ <servlet>
+ <display-name>JMX Perspective</display-name>
+ <servlet-name>JmxPerspective</servlet-name>
+ <servlet-class>org.apache.qpid.management.web.action.JmxPerspectiveAction</servlet-class>
+ </servlet>
+ <servlet>
+ <display-name>WSDM Properties Perspective</display-name>
+ <servlet-name>WsdmPropertiesPerspective</servlet-name>
+ <servlet-class>org.apache.qpid.management.web.action.WsdmPropertiesPerspectiveAction</servlet-class>
+ </servlet>
+ <servlet>
+ <display-name>WSDM Operations Perspective</display-name>
+ <servlet-name>WsdmOperationsPerspective</servlet-name>
+ <servlet-class>org.apache.qpid.management.web.action.WsdmOperationsPerspectiveAction</servlet-class>
+ </servlet>
+ <servlet>
+ <display-name>WSDM WSDL Perspective</display-name>
+ <servlet-name>WsdmWsdlPerspective</servlet-name>
+ <servlet-class>org.apache.qpid.management.web.action.WsdmWsdlPerspectiveAction</servlet-class>
+ </servlet>
+ <servlet>
+ <display-name>WSDM RMD Perspective</display-name>
+ <servlet-name>WsdmRmdPerspective</servlet-name>
+ <servlet-class>org.apache.qpid.management.web.action.WsdmRmdPerspectiveAction</servlet-class>
+ </servlet>
+ <servlet>
+ <display-name>Logging Configurator</display-name>
+ <servlet-name>LoggingConfiguration</servlet-name>
+ <servlet-class>org.apache.qpid.management.web.action.LoggingConfigurationAction</servlet-class>
+ </servlet>
+ <servlet>
+ <display-name>Brokers Management</display-name>
+ <servlet-name>BrokersManagement</servlet-name>
+ <servlet-class>org.apache.qpid.management.web.action.BrokersManagementAction</servlet-class>
+ </servlet>
+ <servlet>
+ <description>
+ Connects QMAn to one or more brokers depending from what is
+ specified on the given (via system property) configuration
+ file.
+ </description>
+ <display-name>Connect QMan to Broker</display-name>
+ <servlet-name>ConnectQManToBroker</servlet-name>
+ <servlet-class>org.apache.qpid.management.servlet.ConnectQManToBroker</servlet-class>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+ <servlet-mapping>
+ <servlet-name>ResourceManagement</servlet-name>
+ <url-pattern>/resources_management</url-pattern>
+ </servlet-mapping>
+ <servlet-mapping>
+ <servlet-name>WsdmWsdlPerspective</servlet-name>
+ <url-pattern>/wsdm_wsdl_perspective</url-pattern>
+ </servlet-mapping>
+ <servlet-mapping>
+ <servlet-name>WsdmRmdPerspective</servlet-name>
+ <url-pattern>/wsdm_rmd_perspective</url-pattern>
+ </servlet-mapping>
+ <servlet-mapping>
+ <servlet-name>WsdmOperationsPerspective</servlet-name>
+ <url-pattern>/wsdm_operations_perspective</url-pattern>
+ </servlet-mapping>
+ <servlet-mapping>
+ <servlet-name>WsdmPropertiesPerspective</servlet-name>
+ <url-pattern>/wsdm_properties_perspective</url-pattern>
+ </servlet-mapping>
+ <servlet-mapping>
+ <servlet-name>BrokersManagement</servlet-name>
+ <url-pattern>/brokers_management</url-pattern>
+ </servlet-mapping>
+ <servlet-mapping>
+ <servlet-name>JmxPerspective</servlet-name>
+ <url-pattern>/jmx_perspective</url-pattern>
+ </servlet-mapping>
+ <servlet-mapping>
+ <servlet-name>LoggingConfiguration</servlet-name>
+ <url-pattern>/logging_configuration</url-pattern>
+ </servlet-mapping>
+ <servlet-mapping>
+ <servlet-name>ViewConsole</servlet-name>
+ <url-pattern>/console</url-pattern>
+ </servlet-mapping>
+ <servlet-mapping>
+ <servlet-name>ConnectQManToBroker</servlet-name>
+ <url-pattern>/test/*</url-pattern>
+ </servlet-mapping>
+ <servlet-mapping>
+ <servlet-name>Proxy</servlet-name>
+ <url-pattern>/services/*</url-pattern>
+ </servlet-mapping>
+ <login-config>
+ <auth-method>BASIC</auth-method>
+ </login-config>
+</web-app> \ No newline at end of file
diff --git a/java/management/common/build.xml b/java/management/common/build.xml
new file mode 100644
index 0000000000..ce2ec3a106
--- /dev/null
+++ b/java/management/common/build.xml
@@ -0,0 +1,26 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<project name="Management Common" default="build">
+
+ <import file="../../module.xml"/>
+
+ <target name="bundle" depends="bundle-tasks"/>
+</project>
diff --git a/java/management/common/src/main/java/management-common.bnd b/java/management/common/src/main/java/management-common.bnd
new file mode 100644
index 0000000000..f9744b7cc3
--- /dev/null
+++ b/java/management/common/src/main/java/management-common.bnd
@@ -0,0 +1,8 @@
+ver: 0.6.0
+
+Bundle-SymbolicName: qpid-management-common
+Bundle-Version: ${ver}
+Export-Package: *;version=${ver}
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Require-Bundle: jmxremote.sasl;resolution:=optional
+
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/JMXConnnectionFactory.java b/java/management/common/src/main/java/org/apache/qpid/management/common/JMXConnnectionFactory.java
new file mode 100644
index 0000000000..c03b782987
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/JMXConnnectionFactory.java
@@ -0,0 +1,284 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.management.common;
+
+import java.io.IOException;
+import java.security.Security;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+import javax.net.ssl.SSLException;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.sasl.SaslClientFactory;
+
+import org.apache.qpid.management.common.sasl.CRAMMD5HashedSaslClientFactory;
+import org.apache.qpid.management.common.sasl.Constants;
+import org.apache.qpid.management.common.sasl.JCAProvider;
+import org.apache.qpid.management.common.sasl.SaslProvider;
+import org.apache.qpid.management.common.sasl.UserPasswordCallbackHandler;
+import org.apache.qpid.management.common.sasl.UsernameHashedPasswordCallbackHandler;
+
+public class JMXConnnectionFactory {
+
+ private static final String NON_JRMP_SERVER = "non-JRMP server at remote endpoint";
+ private static final String SERVER_SUPPORTED_PROFILES = "The server supported profiles";
+ private static final String CLIENT_REQUIRED_PROFILES = "do not match the client required profiles";
+
+ public static JMXConnector getJMXConnection(long timeout, String host, int port, String username, String password)
+ throws SSLException, IOException, Exception
+ {
+ //auto-negotiate an RMI or JMXMP (SASL/CRAM-MD5 or SASL/PLAIN) JMX connection to broker
+ try
+ {
+ return createJMXconnector("RMI", timeout, host, port, username, password);
+ }
+ catch (IOException rmiIOE)
+ {
+ // check if the ioe was raised because we tried connecting to a non RMI-JRMP based JMX server
+ boolean jrmpServer = !rmiIOE.getMessage().contains(NON_JRMP_SERVER);
+
+ if (jrmpServer)
+ {
+ //it was an RMI-JRMP based JMX server, so something else went wrong. Check for SSL issues.
+ Throwable rmiIOECause = rmiIOE.getCause();
+ boolean isSSLException = false;
+ if (rmiIOECause != null)
+ {
+ isSSLException = rmiIOECause instanceof SSLException;
+ }
+
+ //if it was an SSLException based cause, throw it
+ if (isSSLException)
+ {
+ throw (SSLException) rmiIOECause;
+ }
+ else
+ {
+ //can't determine cause, throw new IOE citing the original as cause
+ IOException nioe = new IOException();
+ nioe.initCause(rmiIOE);
+ throw nioe;
+ }
+ }
+ else
+ {
+ try
+ {
+ //It wasnt an RMI ConnectorServer at the broker end. Try to establish a JMXMP SASL/CRAM-MD5 connection instead.
+ return createJMXconnector("JMXMP_CRAM-MD5", timeout, host, port, username, password);
+ }
+ catch (IOException cramIOE)
+ {
+ // check if the IOE was raised because we tried connecting to a SASL/PLAIN server using SASL/CRAM-MD5
+ boolean plainProfileServer = cramIOE.getMessage().contains(SERVER_SUPPORTED_PROFILES +
+ " [" + Constants.SASL_PLAIN + "] " + CLIENT_REQUIRED_PROFILES + " [" + Constants.SASL_CRAMMD5 + "]");
+
+ if (!plainProfileServer)
+ {
+ IOException nioe = new IOException();
+ nioe.initCause(cramIOE);
+ throw nioe;
+ }
+ else
+ {
+ try
+ {
+ // Try to establish a JMXMP SASL/PLAIN connection instead.
+ return createJMXconnector("JMXMP_PLAIN", timeout, host, port, username, password);
+ }
+ catch (IOException plainIOE)
+ {
+ /* Out of options now. Check that the IOE was raised because we tried connecting to a server
+ * which didnt support SASL/PLAIN. If so, signal an unknown profile type. If not, raise the exception. */
+ boolean unknownProfile = plainIOE.getMessage().contains(CLIENT_REQUIRED_PROFILES + " [" + Constants.SASL_PLAIN + "]");
+
+ if (unknownProfile)
+ {
+ throw new Exception("Unknown JMXMP authentication mechanism, unable to connect.");
+ }
+ else
+ {
+ IOException nioe = new IOException();
+ nioe.initCause(plainIOE);
+ throw nioe;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private static JMXConnector createJMXconnector(String connectionType, long timeout, String host, int port,
+ String userName, String password) throws IOException, Exception
+ {
+ Map<String, Object> env = new HashMap<String, Object>();
+ JMXServiceURL jmxUrl = null;
+
+ if (connectionType == "RMI")
+ {
+ jmxUrl = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + host + ":" + port + "/jmxrmi");
+
+ //Add user credential's to environment map for RMIConnector startup.
+ //These will be used for authentication by the remote RMIConnectorServer if supported, or ignored otherwise.
+ env.put(JMXConnector.CREDENTIALS, new String[] {userName,password});
+ }
+ else if (connectionType.contains("JMXMP"))
+ {
+ // Check that the JMXMPConnector is available to provide SASL support
+ final String jmxmpcClass = "javax.management.remote.jmxmp.JMXMPConnector";
+
+ try
+ {
+ Class.forName(jmxmpcClass);
+ }
+ catch (ClassNotFoundException cnfe)
+ {
+ throw new Exception("JMXMPConnector class not found, unable to connect to specified server.\n\n"
+ + "Please add the jmxremote_optional.jar to the jmxremote.sasl plugin folder, or the classpath.");
+ }
+
+ jmxUrl = new JMXServiceURL("jmxmp", host, port);
+ env = new HashMap<String, Object>();
+
+ /* set the package in which to find the JMXMP ClientProvider.class file loaded by the
+ * jmxremote.sasl plugin (from the jmxremote_optional.jar) */
+ env.put("jmx.remote.protocol.provider.pkgs", "com.sun.jmx.remote.protocol");
+
+ if (connectionType == "JMXMP_CRAM-MD5")
+ {
+ Map<String, Class<? extends SaslClientFactory>> map = new HashMap<String, Class<? extends SaslClientFactory>>();
+ map.put("CRAM-MD5-HASHED", CRAMMD5HashedSaslClientFactory.class);
+ Security.addProvider(new JCAProvider(map));
+
+ CallbackHandler handler = new UsernameHashedPasswordCallbackHandler(
+ userName, password);
+ env.put("jmx.remote.profiles", Constants.SASL_CRAMMD5);
+ env.put("jmx.remote.sasl.callback.handler", handler);
+ }
+ else if (connectionType == "JMXMP_PLAIN")
+ {
+ Security.addProvider(new SaslProvider());
+ CallbackHandler handler = new UserPasswordCallbackHandler(userName, password);
+ env.put("jmx.remote.profiles", Constants.SASL_PLAIN);
+ env.put("jmx.remote.sasl.callback.handler", handler);
+ }
+ else
+ {
+ throw new Exception("Unknown JMXMP authentication mechanism");
+ }
+ }
+ else
+ {
+ throw new Exception("Unknown connection type");
+ }
+
+ ConnectWaiter connector = new ConnectWaiter(jmxUrl, env);
+ Thread connectorThread = new Thread(connector);
+ connectorThread.start();
+ connectorThread.join(timeout);
+
+ if(connector.getJmxc() == null)
+ {
+ if (connector.getConnectionException() != null)
+ {
+ throw connector.getConnectionException();
+ }
+ else
+ {
+ throw new IOException("Timed out connecting to " + host + ":" + port);
+ }
+ }
+
+ return connector.getJmxc();
+ }
+
+ private static class ConnectWaiter implements Runnable
+ {
+ private Exception _connectionException;
+ private JMXConnector _jmxc;
+ private JMXServiceURL _jmxUrl;
+ private Map<String, ?> _env;
+ private boolean _connectionRetrieved;
+
+ public ConnectWaiter(JMXServiceURL url, Map<String, ?> env)
+ {
+ _jmxUrl = url;
+ _env = env;
+ }
+
+ public void run()
+ {
+ try
+ {
+ _jmxc = null;
+ _connectionRetrieved = false;
+ _connectionException = null;
+
+ JMXConnector conn = JMXConnectorFactory.connect(_jmxUrl, _env);
+
+ synchronized (this)
+ {
+ if(_connectionRetrieved)
+ {
+ //The app thread already timed out the attempt and retrieved the
+ //null connection, so just close this orphaned connection
+ try
+ {
+ conn.close();
+ }
+ catch (IOException e)
+ {
+ //ignore
+ }
+ }
+ else
+ {
+ _jmxc = conn;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ _connectionException = ex;
+ }
+ }
+
+ public Exception getConnectionException()
+ {
+ return _connectionException;
+ }
+
+ public JMXConnector getJmxc()
+ {
+ synchronized (this)
+ {
+ _connectionRetrieved = true;
+
+ return _jmxc;
+ }
+ }
+ }
+}
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ConfigurationManagement.java b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ConfigurationManagement.java
new file mode 100644
index 0000000000..e3495a7df6
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ConfigurationManagement.java
@@ -0,0 +1,42 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.common.mbeans;
+
+import javax.management.MBeanOperationInfo;
+
+import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation;
+
+public interface ConfigurationManagement
+{
+
+ String TYPE = "ConfigurationManagement";
+ int VERSION = 1;
+
+ /**
+ * Reload the
+ * @throws ConfigurationException
+ */
+ @MBeanOperation(name="reloadSecurityConfiguration",
+ description = "Force a reload of the security configuration sections",
+ impact = MBeanOperationInfo.ACTION)
+ void reloadSecurityConfiguration() throws Exception;
+
+}
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/LoggingManagement.java b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/LoggingManagement.java
new file mode 100644
index 0000000000..cb3387c6d3
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/LoggingManagement.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.management.common.mbeans;
+
+import java.io.IOException;
+
+import org.apache.qpid.management.common.mbeans.annotations.MBeanAttribute;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanOperationParameter;
+
+import javax.management.MBeanOperationInfo;
+import javax.management.openmbean.TabularData;
+
+/**
+ * Interface for the LoggingManagement MBean
+ * @since Qpid JMX API 1.2
+ */
+public interface LoggingManagement
+{
+ String TYPE = "LoggingManagement";
+ int VERSION = 2;
+
+ //TabularType and contained CompositeType key/description information
+ //For compatibility reasons, DONT MODIFY the existing key values if expanding the set.
+ String[] COMPOSITE_ITEM_NAMES = {"LoggerName", "Level"};
+ String[] COMPOSITE_ITEM_DESCRIPTIONS = {"Name of the logger", "Level of the logger"};
+ String[] TABULAR_UNIQUE_INDEX = {COMPOSITE_ITEM_NAMES[0]};
+
+ /**
+ * Attribute to represent the log4j xml configuration file's LogWatch interval.
+ * @return The logwatch interval in seconds.
+ * @since Qpid JMX API 1.2
+ */
+ @MBeanAttribute(name="Log4jLogWatchInterval",
+ description = "The log4j xml configuration file LogWatch interval (in seconds). 0 indicates not being checked.")
+ Integer getLog4jLogWatchInterval();
+
+ /**
+ * Attribute to represent the available log4j logger output levels.
+ * @return The logging level names.
+ * @since Qpid JMX API 1.2
+ */
+ @MBeanAttribute(name="AvailableLoggerLevels", description = "The values to which log output level can be set.")
+ String[] getAvailableLoggerLevels();
+
+
+ //****** log4j runtime operations ****** //
+
+ /**
+ * Sets the level of an active Log4J logger
+ * @param logger The name of the logger
+ * @param level The level to set the logger to
+ * @return True if successful, false if unsuccessful (eg if an invalid level is specified)
+ * @since Qpid JMX API 1.2
+ */
+ @MBeanOperation(name = "setRuntimeLoggerLevel", description = "Set the runtime logging level for an active log4j logger.",
+ impact = MBeanOperationInfo.ACTION)
+ boolean setRuntimeLoggerLevel(@MBeanOperationParameter(name = "logger", description = "Logger name")String logger,
+ @MBeanOperationParameter(name = "level", description = "Logger level")String level);
+
+ /**
+ * Retrieves a TabularData set of the active log4j loggers and their levels
+ * @return TabularData set of CompositeData rows with logger name and level, or null if there is a problem with the TabularData type
+ * @since Qpid JMX API 1.2
+ */
+ @MBeanOperation(name = "viewEffectiveRuntimeLoggerLevels", description = "View the effective runtime logging level " +
+ "for active log4j logger's.", impact = MBeanOperationInfo.INFO)
+ TabularData viewEffectiveRuntimeLoggerLevels();
+
+ /**
+ * Sets the level of the active Log4J RootLogger
+ * @param level The level to set the RootLogger to
+ * @return True if successful, false if unsuccessful (eg if an invalid level is specified)
+ * @since Qpid JMX API 1.2
+ */
+ @MBeanOperation(name = "setRuntimeRootLoggerLevel", description = "Set the runtime logging level for the active log4j Root Logger.",
+ impact = MBeanOperationInfo.ACTION)
+ boolean setRuntimeRootLoggerLevel(@MBeanOperationParameter(name = "level", description = "Logger level")String level);
+
+ /**
+ * Attribute to represent the level of the active Log4J RootLogger
+ * @return The level of the RootLogger.
+ * @since Qpid JMX API 1.2
+ */
+ @MBeanAttribute(name = "getRuntimeRootLoggerLevel", description = "Get the runtime logging level for the active log4j Root Logger.")
+ String getRuntimeRootLoggerLevel();
+
+
+ //****** log4j XML configuration file operations ****** //
+
+ /**
+ * Reloads the log4j configuration file, applying any changes made.
+ *
+ * @throws IOException
+ * @since Qpid JMX API 1.4
+ */
+ @MBeanOperation(name = "reloadConfigFile", description = "Reload the log4j xml configuration file", impact = MBeanOperationInfo.ACTION)
+ void reloadConfigFile() throws IOException;
+
+ /**
+ * Updates the level of an existing Log4J logger within the xml configuration file
+ * @param logger The name of the logger
+ * @param level The level to set the logger to
+ * @return True if successful, false if unsuccessful (eg if an invalid logger or level is specified)
+ * @throws IOException if there is an error parsing the configuration file.
+ * @since Qpid JMX API 1.2
+ */
+ @MBeanOperation(name = "setConfigFileLoggerLevel", description = "Set the logging level for an existing logger " +
+ "in the log4j xml configuration file", impact = MBeanOperationInfo.ACTION)
+ boolean setConfigFileLoggerLevel(@MBeanOperationParameter(name = "logger", description = "logger name")String logger,
+ @MBeanOperationParameter(name = "level", description = "Logger level")String level) throws IOException;
+
+ /**
+ * Retrieves a TabularData set of the existing Log4J loggers within the xml configuration file
+ * @return TabularData set of CompositeData rows with logger name and level, or null if there is a problem with the TabularData type
+ * @throws IOException if there is an error parsing the configuration file.
+ * @since Qpid JMX API 1.2
+ */
+ @MBeanOperation(name = "viewConfigFileLoggerLevels", description = "Get the logging level defined for the logger's " +
+ "in the log4j xml configuration file.", impact = MBeanOperationInfo.INFO)
+ TabularData viewConfigFileLoggerLevels() throws IOException;
+
+ /**
+ * Updates the level of the Log4J RootLogger within the xml configuration file if it is present
+ * @param level The level to set the logger to
+ * @return True if successful, false if not (eg an invalid level is specified, or root logger level isnt already defined)
+ * @throws IOException if there is an error parsing the configuration file.
+ * @since Qpid JMX API 1.2
+ */
+ @MBeanOperation(name = "setConfigFileRootLoggerLevel", description = "Set the logging level for the Root Logger " +
+ "in the log4j xml configuration file.", impact = MBeanOperationInfo.ACTION)
+ boolean setConfigFileRootLoggerLevel(@MBeanOperationParameter(name = "level", description = "Logger level")String level) throws IOException;
+
+ /**
+ * Attribute to represent the level of the Log4J RootLogger within the xml configuration file
+ * @return The level of the RootLogger, or null if it is not present
+ * @since Qpid JMX API 1.2
+ */
+ @MBeanAttribute(name = "getConfigFileRootLoggerLevel", description = "Get the logging level for the Root Logger " +
+ "in the log4j xml configuration file.")
+ String getConfigFileRootLoggerLevel() throws IOException;
+}
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedBroker.java b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedBroker.java
new file mode 100644
index 0000000000..dcf77ca2ed
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedBroker.java
@@ -0,0 +1,127 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.management.common.mbeans;
+
+import java.io.IOException;
+import java.util.List;
+
+import javax.management.JMException;
+import javax.management.MBeanOperationInfo;
+
+import org.apache.qpid.management.common.mbeans.annotations.MBeanAttribute;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanOperationParameter;
+
+/**
+ * The ManagedBroker is the management interface to expose management
+ * features of the Broker.
+ *
+ * @author Bhupendra Bhardwaj
+ * @version 0.1
+ */
+public interface ManagedBroker
+{
+ static final String TYPE = "VirtualHostManager";
+
+ static final int VERSION = 1 ;
+
+ /**
+ * Returns an array of the exchange types available for creation.
+ * @since Qpid JMX API 1.3
+ * @throws IOException
+ */
+ @MBeanAttribute(name="ExchangeTypes", description = "The types of Exchange available for creation.")
+ String[] getExchangeTypes() throws IOException;
+
+ /**
+ * Returns a list containing the names of the attributes available for the Queue mbeans.
+ * @since Qpid JMX API 1.3
+ * @throws IOException
+ */
+ @MBeanOperation(name = "retrieveQueueAttributeNames", description = "Retrieve the attribute names for queues in this virtualhost",
+ impact = MBeanOperationInfo.INFO)
+ List<String> retrieveQueueAttributeNames() throws IOException;
+
+ /**
+ * Returns a List of Object Lists containing the requested attribute values (in the same sequence requested) for each queue in the virtualhost.
+ * If a particular attribute cant be found or raises an mbean/reflection exception whilst being gathered its value is substituted with the String "-".
+ * @since Qpid JMX API 1.3
+ * @throws IOException
+ */
+ @MBeanOperation(name = "retrieveQueueAttributeValues", description = "Retrieve the indicated attributes for queues in this virtualhost",
+ impact = MBeanOperationInfo.INFO)
+ List<List<Object>> retrieveQueueAttributeValues(@MBeanOperationParameter(name="attributes", description="Attributes to retrieve") String[] attributes) throws IOException;
+
+ /**
+ * Creates a new Exchange.
+ * @param name
+ * @param type
+ * @param durable
+ * @throws IOException
+ * @throws JMException
+ */
+ @MBeanOperation(name="createNewExchange", description="Creates a new Exchange", impact= MBeanOperationInfo.ACTION)
+ void createNewExchange(@MBeanOperationParameter(name="name", description="Name of the new exchange")String name,
+ @MBeanOperationParameter(name="ExchangeType", description="Type of the exchange")String type,
+ @MBeanOperationParameter(name="durable", description="true if the Exchang should be durable")boolean durable)
+ throws IOException, JMException;
+
+ /**
+ * unregisters all the channels, queuebindings etc and unregisters
+ * this exchange from managed objects.
+ * @param exchange
+ * @throws IOException
+ * @throws JMException
+ */
+ @MBeanOperation(name="unregisterExchange",
+ description="Unregisters all the related channels and queuebindings of this exchange",
+ impact= MBeanOperationInfo.ACTION)
+ void unregisterExchange(@MBeanOperationParameter(name= ManagedExchange.TYPE, description="Exchange Name")String exchange)
+ throws IOException, JMException;
+
+ /**
+ * Create a new Queue on the Broker server
+ * @param queueName
+ * @param durable
+ * @param owner
+ * @throws IOException
+ * @throws JMException
+ */
+ @MBeanOperation(name="createNewQueue", description="Create a new Queue on the Broker server", impact= MBeanOperationInfo.ACTION)
+ void createNewQueue(@MBeanOperationParameter(name="queue name", description="Name of the new queue")String queueName,
+ @MBeanOperationParameter(name="owner", description="Owner name")String owner,
+ @MBeanOperationParameter(name="durable", description="true if the queue should be durable")boolean durable)
+ throws IOException, JMException;
+
+ /**
+ * Unregisters the Queue bindings, removes the subscriptions and unregisters
+ * from the managed objects.
+ * @param queueName
+ * @throws IOException
+ * @throws JMException
+ */
+ @MBeanOperation(name="deleteQueue",
+ description="Unregisters the Queue bindings, removes the subscriptions and deletes the queue",
+ impact= MBeanOperationInfo.ACTION)
+ void deleteQueue(@MBeanOperationParameter(name= ManagedQueue.TYPE, description="Queue Name")String queueName)
+ throws IOException, JMException;
+}
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedConnection.java b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedConnection.java
new file mode 100644
index 0000000000..5b02c20b7f
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedConnection.java
@@ -0,0 +1,143 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.management.common.mbeans;
+
+import java.io.IOException;
+import java.util.Date;
+import java.security.Principal;
+
+import javax.management.JMException;
+import javax.management.MBeanOperationInfo;
+import javax.management.openmbean.TabularData;
+
+import org.apache.qpid.management.common.mbeans.annotations.MBeanAttribute;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanOperationParameter;
+
+/**
+ * The management interface exposed to allow management of Connections.
+ * @author Bhupendra Bhardwaj
+ * @version 0.1
+ */
+public interface ManagedConnection
+{
+ static final String TYPE = "Connection";
+ static final int VERSION = 2;
+
+ //TabularType and contained CompositeType key/description information
+ //For compatibility reasons, DONT MODIFY the existing key values if expanding the set.
+ //"Flow Blocked" added in Qpid JMX API 1.5
+ String[] COMPOSITE_ITEM_NAMES = {"Channel Id", "Transactional", "Default Queue", "Unacknowledged Message Count", "Flow Blocked"};
+ String[] COMPOSITE_ITEM_DESCRIPTIONS = {"Channel Id", "Transactional", "Default Queue", "Unacknowledged Message Count", "Flow Blocked"};
+ String[] TABULAR_UNIQUE_INDEX = {COMPOSITE_ITEM_NAMES[0]};
+
+ @MBeanAttribute(name = "ClientId", description = "Client Id")
+ String getClientId();
+
+ @MBeanAttribute(name = "AuthorizedId", description = "User Name")
+ String getAuthorizedId();
+
+ @MBeanAttribute(name = "Version", description = "Client Version")
+ String getVersion();
+
+ /**
+ * Tells the remote address of this connection.
+ * @return remote address
+ */
+ @MBeanAttribute(name="RemoteAddress", description=TYPE + " Address")
+ String getRemoteAddress();
+
+ /**
+ * Tells the last time, the IO operation was done.
+ * @return last IO time.
+ */
+ @MBeanAttribute(name="LastIOTime", description="The last time, the IO operation was done")
+ Date getLastIoTime();
+
+ /**
+ * Tells the total number of bytes written till now.
+ * @return number of bytes written.
+ *
+ @MBeanAttribute(name="WrittenBytes", description="The total number of bytes written till now")
+ Long getWrittenBytes();
+ */
+ /**
+ * Tells the total number of bytes read till now.
+ * @return number of bytes read.
+ *
+ @MBeanAttribute(name="ReadBytes", description="The total number of bytes read till now")
+ Long getReadBytes();
+ */
+
+ /**
+ * Threshold high value for no of channels. This is useful in setting notifications or
+ * taking required action is there are more channels being created.
+ * @return threshold limit for no of channels
+ */
+ Long getMaximumNumberOfChannels();
+
+ /**
+ * Sets the threshold high value for number of channels for a connection
+ * @param value
+ */
+ @MBeanAttribute(name="MaximumNumberOfChannels", description="The threshold high value for number of channels for this connection")
+ void setMaximumNumberOfChannels(Long value);
+
+ //********** Operations *****************//
+
+ /**
+ * channel details of all the channels opened for this connection.
+ * @return general channel details
+ * @throws IOException
+ * @throws JMException
+ */
+ @MBeanOperation(name="channels", description="Channel details for this connection")
+ TabularData channels() throws IOException, JMException;
+
+ /**
+ * Commits the transactions if the channel is transactional.
+ * @param channelId
+ * @throws JMException
+ */
+ @MBeanOperation(name="commitTransaction",
+ description="Commits the transactions for given channel Id, if the channel is transactional",
+ impact= MBeanOperationInfo.ACTION)
+ void commitTransactions(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) throws JMException;
+
+ /**
+ * Rollsback the transactions if the channel is transactional.
+ * @param channelId
+ * @throws JMException
+ */
+ @MBeanOperation(name="rollbackTransactions",
+ description="Rollsback the transactions for given channel Id, if the channel is transactional",
+ impact= MBeanOperationInfo.ACTION)
+ void rollbackTransactions(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) throws JMException;
+
+ /**
+ * Closes all the related channels and unregisters this connection from managed objects.
+ */
+ @MBeanOperation(name="closeConnection",
+ description="Closes this connection and all related channels",
+ impact= MBeanOperationInfo.ACTION)
+ void closeConnection() throws Exception;
+}
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedExchange.java b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedExchange.java
new file mode 100644
index 0000000000..c8df64549e
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedExchange.java
@@ -0,0 +1,110 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.common.mbeans;
+
+import java.io.IOException;
+
+import javax.management.JMException;
+import javax.management.MBeanOperationInfo;
+import javax.management.openmbean.TabularData;
+
+import org.apache.qpid.management.common.mbeans.annotations.MBeanAttribute;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanOperationParameter;
+
+/**
+ * The management interface exposed to allow management of an Exchange.
+ * @author Robert J. Greig
+ * @author Bhupendra Bhardwaj
+ * @version 0.1
+ */
+public interface ManagedExchange
+{
+ static final String TYPE = "Exchange";
+ static final int VERSION = 1;
+
+ //TabularType and contained CompositeType key/description info for DIRECT/TOPIC/FANOUT exchanges.
+ //For compatibility reasons, DONT MODIFY the existing key values if expanding the set.
+ String[] COMPOSITE_ITEM_NAMES = {"Binding Key", "Queue Names"};
+ String[] COMPOSITE_ITEM_DESCRIPTIONS = {"Binding Key", "Queue Names"};
+ String[] TABULAR_UNIQUE_INDEX = {COMPOSITE_ITEM_NAMES[0]};
+
+ //TabularType and contained CompositeType key/description info for HEADERS exchange only.
+ //For compatibility reasons, DONT MODIFY the existing key values if expanding the set.
+ String[] HEADERS_COMPOSITE_ITEM_NAMES = new String[]{"Binding No", "Queue Name", "Queue Bindings"};
+ String[] HEADERS_COMPOSITE_ITEM_DESC = new String[]{"Binding No", "Queue Name", "Queue Bindings"};
+ String[] HEADERS_TABULAR_UNIQUE_INDEX = new String[]{HEADERS_COMPOSITE_ITEM_NAMES[0]};
+
+ /**
+ * Returns the name of the managed exchange.
+ * @return the name of the exchange.
+ * @throws IOException
+ */
+ @MBeanAttribute(name="Name", description=TYPE + " Name")
+ String getName() throws IOException;
+
+ @MBeanAttribute(name="ExchangeType", description="Exchange Type")
+ String getExchangeType() throws IOException;
+
+ @MBeanAttribute(name="TicketNo", description="Exchange Ticket No")
+ Integer getTicketNo() throws IOException;
+
+ /**
+ * Tells if the exchange is durable or not.
+ * @return true if the exchange is durable.
+ * @throws IOException
+ */
+ @MBeanAttribute(name="Durable", description="true if Exchange is durable")
+ boolean isDurable() throws IOException;
+
+ /**
+ * Tells if the exchange is set for autodelete or not.
+ * @return true if the exchange is set as autodelete.
+ * @throws IOException
+ */
+ @MBeanAttribute(name="AutoDelete", description="true if Exchange is AutoDelete")
+ boolean isAutoDelete() throws IOException;
+
+ // Operations
+
+ /**
+ * Returns all the bindings this exchange has with the queues.
+ * @return the bindings with the exchange.
+ * @throws IOException
+ * @throws JMException
+ */
+ @MBeanOperation(name="bindings", description="view the queue bindings for this exchange")
+ TabularData bindings() throws IOException, JMException;
+
+ /**
+ * Creates new binding with the given queue and binding.
+ * @param queueName
+ * @param binding
+ * @throws JMException
+ */
+ @MBeanOperation(name="createNewBinding",
+ description="create a new binding with this exchange",
+ impact= MBeanOperationInfo.ACTION)
+ void createNewBinding(@MBeanOperationParameter(name= ManagedQueue.TYPE, description="Queue name") String queueName,
+ @MBeanOperationParameter(name="Binding", description="New binding")String binding)
+ throws JMException;
+
+}
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedQueue.java b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedQueue.java
new file mode 100644
index 0000000000..7838400cd1
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedQueue.java
@@ -0,0 +1,407 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.common.mbeans;
+
+import java.io.IOException;
+
+import javax.management.JMException;
+import javax.management.MBeanOperationInfo;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+
+import org.apache.qpid.management.common.mbeans.annotations.MBeanAttribute;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanOperationParameter;
+
+/**
+ * The management interface exposed to allow management of a queue.
+ * @author Robert J. Greig
+ * @author Bhupendra Bhardwaj
+ * @version 0.1
+ */
+public interface ManagedQueue
+{
+ static final String TYPE = "Queue";
+ static final int VERSION = 3;
+
+ //TabularType and contained CompositeType key/description information for message list
+ //For compatibility reasons, DONT MODIFY the existing key values if expanding the set.
+ //"Queue Position" added in Qpid JMX API 1.3
+ String[] VIEW_MSGS_COMPOSITE_ITEM_NAMES = {"AMQ MessageId", "Header", "Size(bytes)", "Redelivered", "Queue Position"};
+ String[] VIEW_MSGS_COMPOSITE_ITEM_DESCRIPTIONS = {"AMQ MessageId", "Header", "Size(bytes)", "Redelivered", "Queue Position"};
+ String[] VIEW_MSGS_TABULAR_UNIQUE_INDEX = {VIEW_MSGS_COMPOSITE_ITEM_NAMES[0]};
+
+ //CompositeType key/description information for message content
+ //For compatibility reasons, DONT MODIFY the existing key values if expanding the set.
+ String[] VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES = { "AMQ MessageId", "MimeType", "Encoding", "Content" };
+ String[] VIEW_MSG_CONTENT_COMPOSITE_ITEM_DESCRIPTIONS = { "AMQ MessageId", "MimeType", "Encoding", "Content" };
+
+ //Individual attribute name constants
+ String ATTR_NAME = "Name";
+ String ATTR_OWNER = "Owner";
+ String ATTR_MAX_MSG_AGE = "MaximumMessageAge";
+ String ATTR_MAX_MSG_COUNT = "MaximumMessageCount";
+ String ATTR_MAX_QUEUE_DEPTH = "MaximumQueueDepth";
+ String ATTR_MAX_MSG_SIZE = "MaximumMessageSize";
+ String ATTR_DURABLE = "Durable";
+ String ATTR_AUTODELETE = "AutoDelete";
+ String ATTR_CONSUMER_COUNT = "ConsumerCount";
+ String ATTR_ACTIVE_CONSUMER_COUNT = "ActiveConsumerCount";
+ String ATTR_MSG_COUNT = "MessageCount";
+ String ATTR_QUEUE_DEPTH = "QueueDepth";
+ String ATTR_RCVD_MSG_COUNT = "ReceivedMessageCount";
+ String ATTR_CAPACITY = "Capacity";
+ String ATTR_FLOW_OVERFULL = "FlowOverfull";
+ String ATTR_FLOW_RESUME_CAPACITY = "FlowResumeCapacity";
+
+ //All attribute names constant
+ String[] QUEUE_ATTRIBUTES = new String[]{
+ ATTR_NAME,
+ ATTR_OWNER,
+ ATTR_MAX_MSG_AGE,
+ ATTR_MAX_MSG_COUNT,
+ ATTR_MAX_QUEUE_DEPTH,
+ ATTR_MAX_MSG_SIZE,
+ ATTR_DURABLE,
+ ATTR_AUTODELETE,
+ ATTR_CONSUMER_COUNT,
+ ATTR_ACTIVE_CONSUMER_COUNT,
+ ATTR_MSG_COUNT,
+ ATTR_QUEUE_DEPTH,
+ ATTR_RCVD_MSG_COUNT,
+ ATTR_CAPACITY,
+ ATTR_FLOW_OVERFULL,
+ ATTR_FLOW_RESUME_CAPACITY
+ };
+
+ /**
+ * Returns the Name of the ManagedQueue.
+ * @return the name of the managedQueue.
+ * @throws IOException
+ */
+ @MBeanAttribute(name="Name", description = TYPE + " Name")
+ String getName() throws IOException;
+
+ /**
+ * Total number of messages on the queue, which are yet to be delivered to the consumer(s).
+ * @return number of undelivered message in the Queue.
+ * @throws IOException
+ */
+ @MBeanAttribute(name="MessageCount", description = "Total number of undelivered messages on the queue")
+ Integer getMessageCount() throws IOException;
+
+ /**
+ * Tells the total number of messages receieved by the queue since startup.
+ * @return total number of messages received.
+ * @throws IOException
+ */
+ @MBeanAttribute(name="ReceivedMessageCount", description="The total number of messages receieved by the queue since startup")
+ Long getReceivedMessageCount() throws IOException;
+
+ /**
+ * Size of messages in the queue
+ *
+ * Since Qpid JMX API 1.2 this operation returns in units of bytes. Prior to this, the result was in units of kilobytes.
+ * @return
+ * @throws IOException
+ */
+ @MBeanAttribute(name="QueueDepth", description="The total size(Bytes) of messages in the queue")
+ Long getQueueDepth() throws IOException, JMException;
+
+ /**
+ * Returns the total number of active subscribers to the queue.
+ * @return the number of active subscribers
+ * @throws IOException
+ */
+ @MBeanAttribute(name="ActiveConsumerCount", description="The total number of active subscribers to the queue")
+ Integer getActiveConsumerCount() throws IOException;
+
+ /**
+ * Returns the total number of subscribers to the queue.
+ * @return the number of subscribers.
+ * @throws IOException
+ */
+ @MBeanAttribute(name="ConsumerCount", description="The total number of subscribers to the queue")
+ Integer getConsumerCount() throws IOException;
+
+ /**
+ * Tells the Owner of the ManagedQueue.
+ * @return the owner's name.
+ * @throws IOException
+ */
+ @MBeanAttribute(name="Owner", description = "Owner")
+ String getOwner() throws IOException;
+
+ /**
+ * Tells whether this ManagedQueue is durable or not.
+ * @return true if this ManagedQueue is a durable queue.
+ * @throws IOException
+ */
+ @MBeanAttribute(name="Durable", description = "true if the AMQQueue is durable")
+ boolean isDurable() throws IOException;
+
+ /**
+ * Tells if the ManagedQueue is set to AutoDelete.
+ * @return true if the ManagedQueue is set to AutoDelete.
+ * @throws IOException
+ */
+ @MBeanAttribute(name="AutoDelete", description = "true if the AMQQueue is AutoDelete")
+ boolean isAutoDelete() throws IOException;
+
+ /**
+ * Returns the maximum age of a message (expiration time) in milliseconds
+ * @return the maximum age
+ * @throws IOException
+ */
+ Long getMaximumMessageAge() throws IOException;
+
+ /**
+ * Sets the maximum age of a message in milliseconds
+ * @param age maximum age of message.
+ * @throws IOException
+ */
+ @MBeanAttribute(name="MaximumMessageAge", description="Threshold high value(milliseconds) for message age")
+ void setMaximumMessageAge(Long age) throws IOException;
+
+ /**
+ * Returns the maximum size of a message (in Bytes) allowed to be accepted by the
+ * ManagedQueue. This is useful in setting notifications or taking
+ * appropriate action, if the size of the message received is more than
+ * the allowed size.
+ * @return the maximum size of a message allowed to be aceepted by the
+ * ManagedQueue.
+ * @throws IOException
+ */
+ Long getMaximumMessageSize() throws IOException;
+
+ /**
+ * Sets the maximum size of the message (in Bytes) that is allowed to be
+ * accepted by the Queue.
+ * @param size maximum size of message.
+ * @throws IOException
+ */
+ @MBeanAttribute(name="MaximumMessageSize", description="Threshold high value(Bytes) for a message size")
+ void setMaximumMessageSize(Long size) throws IOException;
+
+ /**
+ * Tells the maximum number of messages that can be stored in the queue.
+ * This is useful in setting the notifications or taking required
+ * action is the number of message increase this limit.
+ * @return maximum muber of message allowed to be stored in the queue.
+ * @throws IOException
+ */
+ Long getMaximumMessageCount() throws IOException;
+
+ /**
+ * Sets the maximum number of messages allowed to be stored in the queue.
+ * @param value the maximum number of messages allowed to be stored in the queue.
+ * @throws IOException
+ */
+ @MBeanAttribute(name="MaximumMessageCount", description="Threshold high value for number of undelivered messages in the queue")
+ void setMaximumMessageCount(Long value) throws IOException;
+
+ /**
+ * This is useful for setting notifications or taking required action if the size of messages
+ * stored in the queue increases over this limit.
+ *
+ * Since Qpid JMX API 1.2 this operation returns in units of bytes. Prior to this, the result was in units of kilobytes.
+ * @return threshold high value for Queue Depth
+ * @throws IOException
+ */
+ Long getMaximumQueueDepth() throws IOException;
+
+ /**
+ * Sets the maximum size of all the messages together, that can be stored
+ * in the queue.
+ * @param value
+ * @throws IOException
+ */
+ @MBeanAttribute(name="MaximumQueueDepth", description="The threshold high value(Bytes) for Queue Depth")
+ void setMaximumQueueDepth(Long value) throws IOException;
+
+
+ /**
+ * Returns the current flow control Capacity of the queue in bytes.
+ *
+ * @since Qpid JMX API 1.6
+ * @return Capacity at which flow control is enforced
+ * @throws IOException
+ */
+ Long getCapacity() throws IOException;
+
+ /**
+ * Sets the Capacity in bytes above which flow is blocked.
+ *
+ * @since Qpid JMX API 1.6
+ * @param value the capacity in bytes
+ * @throws IOException
+ * @throws IllegalArgumentException If the given value is less than the queue FloeResumeCapacity
+ */
+ @MBeanAttribute(name="Capacity", description="The flow control Capacity (Bytes) of the queue")
+ void setCapacity(Long value) throws IOException, IllegalArgumentException;
+
+ /**
+ * Returns the current flow control FlowResumeCapacity of the queue in bytes.
+ *
+ * @since Qpid JMX API 1.6
+ * @return Capacity below which flow resumes in bytes
+ * @throws IOException
+ */
+ Long getFlowResumeCapacity() throws IOException;
+
+ /**
+ * Sets the FlowResumeCapacity in bytes below which flow resumes.
+ *
+ * @since Qpid JMX API 1.6
+ * @param value of the resume capacity in bytes
+ * @throws IOException
+ * @throws IllegalArgumentException If the given value exceeds the queue Capacity
+ */
+ @MBeanAttribute(name="FlowResumeCapacity", description="The flow resume Capacity (Bytes) of the queue")
+ void setFlowResumeCapacity(Long value) throws IOException, IllegalArgumentException;
+
+ /**
+ * Indicates whether the Queue is currently considered overfull by the FlowControl system
+ *
+ * @since Qpid JMX API 1.6
+ * @throws IOException
+ */
+ @MBeanAttribute(name="FlowOverfull", description="true if the queue is considered overfull by the Flow Control system")
+ boolean isFlowOverfull() throws IOException;
+
+ //********** Operations *****************//
+
+
+ /**
+ * Returns a subset of all the messages stored in the queue. The messages
+ * are returned based on the given index numbers.
+ *
+ * Deprecated as of Qpid JMX API 1.3
+ * @param fromIndex
+ * @param toIndex
+ * @return
+ * @throws IOException
+ * @throws JMException
+ */
+ @Deprecated
+ @MBeanOperation(name="viewMessages",
+ description="Message headers for messages in this queue within given index range. eg. from index 1 - 100")
+ TabularData viewMessages(@MBeanOperationParameter(name="from index", description="from index")int fromIndex,
+ @MBeanOperationParameter(name="to index", description="to index")int toIndex)
+ throws IOException, JMException;
+
+ /**
+ * Returns a subset (up to 2^31 messages at a time) of all the messages stored on the queue.
+ * The messages are returned based on the given queue position range.
+ * @param startPosition
+ * @param endPosition
+ * @return
+ * @throws IOException
+ * @throws JMException
+ */
+ @MBeanOperation(name="viewMessages",
+ description="Message headers for messages in this queue within given queue positions range. eg. from index 1 - 100")
+ TabularData viewMessages(@MBeanOperationParameter(name="start position", description="start position")long startPosition,
+ @MBeanOperationParameter(name="end position", description="end position")long endPosition)
+ throws IOException, JMException;
+
+ /**
+ * Returns the content for the given AMQ Message ID.
+ *
+ * @throws IOException
+ * @throws JMException
+ */
+ @MBeanOperation(name="viewMessageContent", description="The message content for given Message Id")
+ CompositeData viewMessageContent(@MBeanOperationParameter(name="Message Id", description="Message Id")long messageId)
+ throws IOException, JMException;
+
+ /**
+ * Deletes the first message from top.
+ *
+ * Deprecated as of Qpid JMX API 1.3
+ * @throws IOException
+ * @throws JMException
+ */
+ @Deprecated
+ @MBeanOperation(name="deleteMessageFromTop", description="Deletes the first message from top",
+ impact= MBeanOperationInfo.ACTION)
+ void deleteMessageFromTop() throws IOException, JMException;
+
+ /**
+ * Clears the queue by deleting all the messages from the queue that have not been acquired by consumers"
+ *
+ * Since Qpid JMX API 1.3 this returns the number of messages deleted. Prior to this, the return type was void.
+ * @return the number of messages deleted
+ * @throws IOException
+ * @throws JMException
+ */
+ @MBeanOperation(name="clearQueue",
+ description="Clears the queue by deleting all the messages from the queue " +
+ "that have not been acquired by consumers",
+ impact= MBeanOperationInfo.ACTION)
+ Long clearQueue() throws IOException, JMException;
+
+ /**
+ * Moves the messages in given range of message Ids to given Queue. QPID-170
+ * @param fromMessageId first in the range of message ids
+ * @param toMessageId last in the range of message ids
+ * @param toQueue where the messages are to be moved
+ * @throws IOException
+ * @throws JMException
+ */
+ @MBeanOperation(name="moveMessages",
+ description="You can move messages to another queue from this queue ",
+ impact= MBeanOperationInfo.ACTION)
+ void moveMessages(@MBeanOperationParameter(name="from MessageId", description="from MessageId")long fromMessageId,
+ @MBeanOperationParameter(name="to MessageId", description="to MessageId")long toMessageId,
+ @MBeanOperationParameter(name= ManagedQueue.TYPE, description="to Queue Name")String toQueue)
+ throws IOException, JMException;
+
+ /**
+ * Deletes the messages in given range of AMQ message Ids in the given Queue.
+ * @param fromMessageId first in the range of message ids
+ * @param toMessageId last in the range of message ids
+ * @throws IOException
+ * @throws JMException
+ */
+ @MBeanOperation(name="deleteMessages",
+ description="Delete a range of messages from a specified queue",
+ impact= MBeanOperationInfo.ACTION)
+ void deleteMessages(@MBeanOperationParameter(name="from MessageId", description="from MessageId")long fromMessageId,
+ @MBeanOperationParameter(name="to MessageId", description="to MessageId")long toMessageId)
+ throws IOException, JMException;
+
+ /**
+ * Copies the messages in given range of AMQ message Ids to a given Queue.
+ * @param fromMessageId first in the range of message ids
+ * @param toMessageId last in the range of message ids
+ * @param toQueue where the messages are to be copied
+ * @throws IOException
+ * @throws JMException
+ */
+ @MBeanOperation(name="copyMessages",
+ description="Copies a range of messages to a specified queue",
+ impact= MBeanOperationInfo.ACTION)
+ void copyMessages(@MBeanOperationParameter(name="from MessageId", description="from MessageId")long fromMessageId,
+ @MBeanOperationParameter(name="to MessageId", description="to MessageId")long toMessageId,
+ @MBeanOperationParameter(name= ManagedQueue.TYPE, description="to Queue Name")String toQueue)
+ throws IOException, JMException;
+}
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ServerInformation.java b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ServerInformation.java
new file mode 100644
index 0000000000..9b75945d53
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ServerInformation.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.management.common.mbeans;
+
+import java.io.IOException;
+
+import org.apache.qpid.management.common.mbeans.annotations.MBeanAttribute;
+
+/**
+ * Interface for the ServerInformation MBean
+ * @since Qpid JMX API 1.3
+ */
+public interface ServerInformation
+{
+ String TYPE = "ServerInformation";
+ int VERSION = 1;
+
+ /* API version info for the brokers JMX management interface
+ *
+ * As the ServerInformation MBean was only introduced in Qpid JMX API 1.3 it is not possible to use it
+ * for identifying earlier broker JMX APIs for compatibility purposes. However, this can be accomplished
+ * by inspecting the 'version' property key of the UserManagement MBean JMX ObjectName. This was first
+ * introduced in Qpid JMX API 1.2 and so if present in the absence of the ServerInformation MBean
+ * indicates that version. If it is not present then a null value will be returned upon inspection and
+ * Qpid JMX API 1.1 can be assumed.
+ */
+ int QPID_JMX_API_MAJOR_VERSION = 1;
+ int QPID_JMX_API_MINOR_VERSION = 6;
+
+
+ /**
+ * Attribute to represent the major version number for the management API.
+ * @return The major management version number.
+ * @since Qpid JMX API 1.3
+ */
+ @MBeanAttribute(name="ManagementApiMajorVersion",
+ description = "The major version number for the broker management API")
+ Integer getManagementApiMajorVersion() throws IOException;
+
+ /**
+ * Attribute to represent the minor version number for the management API.
+ * @return The minor management version number.
+ * @since Qpid JMX API 1.3
+ */
+ @MBeanAttribute(name="ManagementApiMinorVersion",
+ description = "The minor version number for the broker management API")
+ Integer getManagementApiMinorVersion() throws IOException;
+
+ /**
+ * Attribute to represent the build version string.
+ * @return The build version string
+ * @since Qpid JMX API 1.3
+ */
+ @MBeanAttribute(name="BuildVersion",
+ description = "The repository build version string")
+ String getBuildVersion() throws IOException;
+
+ /**
+ * Attribute to represent the product version string.
+ * @return The product version string
+ * @since Qpid JMX API 1.3
+ */
+ @MBeanAttribute(name="ProductVersion",
+ description = "The product version string")
+ String getProductVersion() throws IOException;
+}
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/UserManagement.java b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/UserManagement.java
new file mode 100644
index 0000000000..6c973b438d
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/UserManagement.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.management.common.mbeans;
+
+import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanOperationParameter;
+
+import javax.management.openmbean.TabularData;
+import javax.management.MBeanOperationInfo;
+
+public interface UserManagement
+{
+
+ String TYPE = "UserManagement";
+ int VERSION = 2;
+
+ //TabularType and contained CompositeType key/description information.
+ //For compatibility reasons, DONT MODIFY the existing key values if expanding the set.
+ String[] COMPOSITE_ITEM_NAMES = {"Username", "read", "write", "admin"};
+ String[] COMPOSITE_ITEM_DESCRIPTIONS = {"Broker Login username",
+ "Management Console Read Permission",
+ "Management Console Write Permission",
+ "Management Console Admin Permission"};
+ String[] TABULAR_UNIQUE_INDEX = {COMPOSITE_ITEM_NAMES[0]};
+
+ //********** Operations *****************//
+ /**
+ * set password for user.
+ *
+ * Since Qpid JMX API 1.2 this operation expects plain text passwords to be provided. Prior to this, MD5 hashed passwords were supplied.
+ *
+ * @param username The username to create
+ * @param password The password for the user
+ *
+ * @return The result of the operation
+ */
+ @MBeanOperation(name = "setPassword", description = "Set password for user.",
+ impact = MBeanOperationInfo.ACTION)
+ boolean setPassword(@MBeanOperationParameter(name = "username", description = "Username")String username,
+ @MBeanOperationParameter(name = "password", description = "Password")char[] password);
+
+ /**
+ * set rights for users with given details
+ *
+ * @param username The username to create
+ * @param read The set of permission to give the new user
+ * @param write The set of permission to give the new user
+ * @param admin The set of permission to give the new user
+ *
+ * @return The result of the operation
+ */
+ @MBeanOperation(name = "setRights", description = "Set access rights for user.",
+ impact = MBeanOperationInfo.ACTION)
+ boolean setRights(@MBeanOperationParameter(name = "username", description = "Username")String username,
+ @MBeanOperationParameter(name = "read", description = "Administration read")boolean read,
+ @MBeanOperationParameter(name = "readAndWrite", description = "Administration write")boolean write,
+ @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin);
+
+ /**
+ * Create users with given details
+ *
+ * Since Qpid JMX API 1.2 this operation expects plain text passwords to be provided. Prior to this, MD5 hashed passwords were supplied.
+ *
+ * @param username The username to create
+ * @param password The password for the user
+ * @param read The set of permission to give the new user
+ * @param write The set of permission to give the new user
+ * @param admin The set of permission to give the new user
+ *
+ * @return The result of the operation
+ */
+ @MBeanOperation(name = "createUser", description = "Create new user from system.",
+ impact = MBeanOperationInfo.ACTION)
+ boolean createUser(@MBeanOperationParameter(name = "username", description = "Username")String username,
+ @MBeanOperationParameter(name = "password", description = "Password")char[] password,
+ @MBeanOperationParameter(name = "read", description = "Administration read")boolean read,
+ @MBeanOperationParameter(name = "readAndWrite", description = "Administration write")boolean write,
+ @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin);
+
+ /**
+ * View users returns all the users that are currently available to the system.
+ *
+ * @param username The user to delete
+ *
+ * @return The result of the operation
+ */
+ @MBeanOperation(name = "deleteUser", description = "Delete user from system.",
+ impact = MBeanOperationInfo.ACTION)
+ boolean deleteUser(@MBeanOperationParameter(name = "username", description = "Username")String username);
+
+
+ /**
+ * Reload the date from disk
+ *
+ * Since Qpid JMX API 1.2 this operation reloads the password and authorisation files. Prior to this, only the authorisation file was reloaded.
+ *
+ * @return The result of the operation
+ */
+ @MBeanOperation(name = "reloadData", description = "Reload the authentication and authorisation files from disk.",
+ impact = MBeanOperationInfo.ACTION)
+ boolean reloadData();
+
+ /**
+ * View users returns all the users that are currently available to the system.
+ *
+ * @return a table of users data (Username, read, write, admin)
+ */
+ @MBeanOperation(name = "viewUsers", description = "All users with access rights to the system.",
+ impact = MBeanOperationInfo.INFO)
+ TabularData viewUsers();
+
+
+}
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/annotations/MBeanAttribute.java b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/annotations/MBeanAttribute.java
new file mode 100644
index 0000000000..14e7211049
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/annotations/MBeanAttribute.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+
+package org.apache.qpid.management.common.mbeans.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for MBean attributes. This should be used with getter or setter
+ * methods of attributes.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@Inherited
+public @interface MBeanAttribute
+{
+ String name();
+ String description();
+}
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/annotations/MBeanConstructor.java b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/annotations/MBeanConstructor.java
new file mode 100644
index 0000000000..3131969813
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/annotations/MBeanConstructor.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+
+package org.apache.qpid.management.common.mbeans.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for MBean constructors.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.CONSTRUCTOR)
+@Inherited
+public @interface MBeanConstructor
+{
+ String value();
+}
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/annotations/MBeanDescription.java b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/annotations/MBeanDescription.java
new file mode 100644
index 0000000000..d70c7dd8f3
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/annotations/MBeanDescription.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+
+package org.apache.qpid.management.common.mbeans.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for MBean class.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Inherited
+public @interface MBeanDescription {
+ String value();
+}
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/annotations/MBeanOperation.java b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/annotations/MBeanOperation.java
new file mode 100644
index 0000000000..c608f64817
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/annotations/MBeanOperation.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+
+package org.apache.qpid.management.common.mbeans.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.management.MBeanOperationInfo;
+
+/**
+ * Annotation for MBean operations.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@Inherited
+public @interface MBeanOperation
+{
+ String name();
+ String description();
+ int impact() default MBeanOperationInfo.INFO;
+}
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/annotations/MBeanOperationParameter.java b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/annotations/MBeanOperationParameter.java
new file mode 100644
index 0000000000..25f2d09608
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/annotations/MBeanOperationParameter.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+
+package org.apache.qpid.management.common.mbeans.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for MBean operation parameters.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.PARAMETER)
+public @interface MBeanOperationParameter {
+ String name();
+ String description();
+}
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/CRAMMD5HashedSaslClientFactory.java b/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/CRAMMD5HashedSaslClientFactory.java
new file mode 100644
index 0000000000..be4897d6c4
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/CRAMMD5HashedSaslClientFactory.java
@@ -0,0 +1,60 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.common.sasl;
+
+import java.util.Map;
+
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslClientFactory;
+import javax.security.sasl.SaslException;
+
+public class CRAMMD5HashedSaslClientFactory implements SaslClientFactory
+{
+ /** The name of this mechanism */
+ public static final String MECHANISM = "CRAM-MD5-HASHED";
+
+ public SaslClient createSaslClient(String[] mechanisms, String authorizationId, String protocol,
+ String serverName, Map<String, ?> props, CallbackHandler cbh)
+ throws SaslException
+ {
+ for (int i = 0; i < mechanisms.length; i++)
+ {
+ if (mechanisms[i].equals(MECHANISM))
+ {
+ if (cbh == null)
+ {
+ throw new SaslException("CallbackHandler must not be null");
+ }
+
+ String[] mechs = {"CRAM-MD5"};
+ return Sasl.createSaslClient(mechs, authorizationId, protocol, serverName, props, cbh);
+ }
+ }
+ return null;
+ }
+
+ public String[] getMechanismNames(Map props)
+ {
+ return new String[]{MECHANISM};
+ }
+}
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/ClientSaslFactory.java b/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/ClientSaslFactory.java
new file mode 100644
index 0000000000..ee5803a220
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/ClientSaslFactory.java
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.common.sasl;
+
+import java.util.Map;
+
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslClientFactory;
+import javax.security.sasl.SaslException;
+
+public class ClientSaslFactory implements SaslClientFactory
+{
+ public SaslClient createSaslClient(String[] mechs, String authorizationId, String protocol,
+ String serverName, Map props, CallbackHandler cbh)
+ throws SaslException
+ {
+ for (int i = 0; i < mechs.length; i++)
+ {
+ if (mechs[i].equals("PLAIN"))
+ {
+ return new PlainSaslClient(authorizationId, cbh);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Simple-minded implementation that ignores props
+ */
+ public String[] getMechanismNames(Map props)
+ {
+ return new String[]{"PLAIN"};
+ }
+
+}
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/Constants.java b/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/Constants.java
new file mode 100644
index 0000000000..31010baf8b
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/Constants.java
@@ -0,0 +1,33 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.management.common.sasl;
+
+public class Constants
+{
+
+ public final static String MECH_CRAMMD5 = "CRAM-MD5";
+ public final static String MECH_PLAIN = "PLAIN";
+ public final static String SASL_CRAMMD5 = "SASL/CRAM-MD5";
+ public final static String SASL_PLAIN = "SASL/PLAIN";
+
+}
+
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/JCAProvider.java b/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/JCAProvider.java
new file mode 100644
index 0000000000..f5a3ca8ccc
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/JCAProvider.java
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.common.sasl;
+
+import java.security.Provider;
+import java.util.Map;
+
+import javax.security.sasl.SaslClientFactory;
+
+public class JCAProvider extends Provider
+{
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates the security provider with a map from SASL mechanisms to implementing factories.
+ *
+ * @param providerMap The map from SASL mechanims to implementing factory classes.
+ */
+ public JCAProvider(Map<String, Class<? extends SaslClientFactory>> providerMap)
+ {
+ super("AMQSASLProvider", 1.0, "A JCA provider that registers all "
+ + "AMQ SASL providers that want to be registered");
+ register(providerMap);
+ }
+
+ /**
+ * Registers client factory classes for a map of mechanism names to client factory classes.
+ *
+ * @param providerMap The map from SASL mechanims to implementing factory classes.
+ */
+ private void register(Map<String, Class<? extends SaslClientFactory>> providerMap)
+ {
+ for (Map.Entry<String, Class<? extends SaslClientFactory>> me : providerMap.entrySet())
+ {
+ put("SaslClientFactory." + me.getKey(), me.getValue().getName());
+ }
+ }
+}
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/PlainSaslClient.java b/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/PlainSaslClient.java
new file mode 100644
index 0000000000..806975c32f
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/PlainSaslClient.java
@@ -0,0 +1,203 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.common.sasl;
+
+import java.io.*;
+import javax.security.auth.callback.*;
+import javax.security.sasl.*;
+
+public class PlainSaslClient implements SaslClient
+{
+
+ private boolean completed;
+ private CallbackHandler cbh;
+ private String authorizationID;
+ private String authenticationID;
+ private byte password[];
+ private static byte SEPARATOR = 0;
+
+ public PlainSaslClient(String authorizationID, CallbackHandler cbh) throws SaslException
+ {
+ completed = false;
+ this.cbh = cbh;
+ Object[] userInfo = getUserInfo();
+ this.authorizationID = authorizationID;
+ this.authenticationID = (String) userInfo[0];
+ this.password = (byte[]) userInfo[1];
+ if (authenticationID == null || password == null)
+ {
+ throw new SaslException("PLAIN: authenticationID and password must be specified");
+ }
+ }
+
+ public byte[] evaluateChallenge(byte[] challenge) throws SaslException
+ {
+ if (completed)
+ {
+ throw new IllegalStateException("PLAIN: authentication already " +
+ "completed");
+ }
+ completed = true;
+ try
+ {
+ byte authzid[] =
+ authorizationID == null ? null : authorizationID.getBytes("UTF8");
+ byte authnid[] = authenticationID.getBytes("UTF8");
+ byte response[] =
+ new byte[
+ password.length +
+ authnid.length +
+ 2 + // SEPARATOR
+ (authzid != null ? authzid.length : 0)
+ ];
+ int size = 0;
+ if (authzid != null) {
+ System.arraycopy(authzid, 0, response, 0, authzid.length);
+ size = authzid.length;
+ }
+ response[size++] = SEPARATOR;
+ System.arraycopy(authnid, 0, response, size, authnid.length);
+ size += authnid.length;
+ response[size++] = SEPARATOR;
+ System.arraycopy(password, 0, response, size, password.length);
+ clearPassword();
+ return response;
+ } catch (UnsupportedEncodingException e) {
+ throw new SaslException("PLAIN: Cannot get UTF-8 encoding of ids",
+ e);
+ }
+ }
+
+ public String getMechanismName()
+ {
+ return "PLAIN";
+ }
+
+ public boolean hasInitialResponse()
+ {
+ return true;
+ }
+
+ public boolean isComplete()
+ {
+ return completed;
+ }
+
+ public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException
+ {
+ if (completed) {
+ throw new IllegalStateException("PLAIN: this mechanism supports " +
+ "neither integrity nor privacy");
+ } else {
+ throw new IllegalStateException("PLAIN: authentication not " +
+ "completed");
+ }
+ }
+
+ public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException
+ {
+ if (completed)
+ {
+ throw new IllegalStateException("PLAIN: this mechanism supports " +
+ "neither integrity nor privacy");
+ }
+ else
+ {
+ throw new IllegalStateException("PLAIN: authentication not " +
+ "completed");
+ }
+ }
+
+ public Object getNegotiatedProperty(String propName)
+ {
+ if (completed)
+ {
+ if (propName.equals(Sasl.QOP))
+ {
+ return "auth";
+ }
+ else
+ {
+ return null;
+ }
+ }
+ else
+ {
+ throw new IllegalStateException("PLAIN: authentication not " +
+ "completed");
+ }
+ }
+
+ private void clearPassword()
+ {
+ if (password != null)
+ {
+ for (int i = 0 ; i < password.length ; i++)
+ {
+ password[i] = 0;
+ }
+ password = null;
+ }
+ }
+
+ public void dispose() throws SaslException
+ {
+ clearPassword();
+ }
+
+ protected void finalize()
+ {
+ clearPassword();
+ }
+
+ private Object[] getUserInfo() throws SaslException
+ {
+ try
+ {
+ final String userPrompt = "PLAIN authentication id: ";
+ final String pwPrompt = "PLAIN password: ";
+ NameCallback nameCb = new NameCallback(userPrompt);
+ PasswordCallback passwordCb = new PasswordCallback(pwPrompt, false);
+ cbh.handle(new Callback[] { nameCb, passwordCb });
+ String userid = nameCb.getName();
+ char pwchars[] = passwordCb.getPassword();
+ byte pwbytes[];
+ if (pwchars != null)
+ {
+ pwbytes = (new String(pwchars)).getBytes("UTF8");
+ passwordCb.clearPassword();
+ }
+ else
+ {
+ pwbytes = null;
+ }
+ return (new Object[] { userid, pwbytes });
+ }
+ catch (IOException e)
+ {
+ throw new SaslException("Cannot get password", e);
+ }
+ catch (UnsupportedCallbackException e)
+ {
+ throw new SaslException("Cannot get userid/password", e);
+ }
+ }
+}
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/SaslProvider.java b/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/SaslProvider.java
new file mode 100644
index 0000000000..1eb44e35df
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/SaslProvider.java
@@ -0,0 +1,35 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.common.sasl;
+
+import java.security.Provider;
+
+public class SaslProvider extends Provider
+{
+ private static final long serialVersionUID = -6978096016899676466L;
+
+ public SaslProvider()
+ {
+ super("SaslClientFactory", 1.0, "SASL PLAIN CLIENT MECHANISM");
+ put("SaslClientFactory.PLAIN", "ClientSaslFactory");
+ }
+
+}
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/UserPasswordCallbackHandler.java b/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/UserPasswordCallbackHandler.java
new file mode 100644
index 0000000000..a1634f86d9
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/UserPasswordCallbackHandler.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.common.sasl;
+
+import java.io.*;
+import javax.security.auth.callback.*;
+
+public class UserPasswordCallbackHandler implements CallbackHandler
+{
+ private String user;
+ private char[] pwchars;
+
+ public UserPasswordCallbackHandler(String user, String password)
+ {
+ this.user = user;
+ this.pwchars = password.toCharArray();
+ }
+
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
+ {
+ for (int i = 0; i < callbacks.length; i++)
+ {
+ if (callbacks[i] instanceof NameCallback)
+ {
+ NameCallback ncb = (NameCallback) callbacks[i];
+ ncb.setName(user);
+ }
+ else if (callbacks[i] instanceof PasswordCallback)
+ {
+ PasswordCallback pcb = (PasswordCallback) callbacks[i];
+ pcb.setPassword(pwchars);
+ }
+ else
+ {
+ throw new UnsupportedCallbackException(callbacks[i]);
+ }
+ }
+ }
+
+ private void clearPassword()
+ {
+ if (pwchars != null)
+ {
+ for (int i = 0 ; i < pwchars.length ; i++)
+ {
+ pwchars[i] = 0;
+ }
+ pwchars = null;
+ }
+ }
+
+ protected void finalize()
+ {
+ clearPassword();
+ }
+}
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/UsernameHashedPasswordCallbackHandler.java b/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/UsernameHashedPasswordCallbackHandler.java
new file mode 100644
index 0000000000..09aba1f3e1
--- /dev/null
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/sasl/UsernameHashedPasswordCallbackHandler.java
@@ -0,0 +1,108 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.common.sasl;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+
+public class UsernameHashedPasswordCallbackHandler implements CallbackHandler
+{
+ private String user;
+ private char[] pwchars;
+
+ public UsernameHashedPasswordCallbackHandler(String user, String password) throws Exception
+ {
+ this.user = user;
+ this.pwchars = getHash(password);
+ }
+
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
+ {
+ for (int i = 0; i < callbacks.length; i++)
+ {
+ if (callbacks[i] instanceof NameCallback)
+ {
+ NameCallback ncb = (NameCallback) callbacks[i];
+ ncb.setName(user);
+ }
+ else if (callbacks[i] instanceof PasswordCallback)
+ {
+ PasswordCallback pcb = (PasswordCallback) callbacks[i];
+ pcb.setPassword(pwchars);
+ }
+ else
+ {
+ throw new UnsupportedCallbackException(callbacks[i]);
+ }
+ }
+ }
+
+
+ private void clearPassword()
+ {
+ if (pwchars != null)
+ {
+ for (int i = 0 ; i < pwchars.length ; i++)
+ {
+ pwchars[i] = 0;
+ }
+ pwchars = null;
+ }
+ }
+
+ protected void finalize()
+ {
+ clearPassword();
+ }
+
+ public static char[] getHash(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException
+ {
+ byte[] data = text.getBytes("utf-8");
+
+ MessageDigest md = MessageDigest.getInstance("MD5");
+
+ for (byte b : data)
+ {
+ md.update(b);
+ }
+
+ byte[] digest = md.digest();
+
+ char[] hash = new char[digest.length ];
+
+ int index = 0;
+ for (byte b : digest)
+ {
+ hash[index++] = (char) b;
+ }
+
+ return hash;
+ }
+}
diff --git a/java/management/common/src/test/java/org/apache/qpid/management/common/mbeans/ManagedQueueTest.java b/java/management/common/src/test/java/org/apache/qpid/management/common/mbeans/ManagedQueueTest.java
new file mode 100644
index 0000000000..f449ecb7e5
--- /dev/null
+++ b/java/management/common/src/test/java/org/apache/qpid/management/common/mbeans/ManagedQueueTest.java
@@ -0,0 +1,84 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.common.mbeans;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.management.MBeanAttributeInfo;
+import javax.management.NotCompliantMBeanException;
+import javax.management.StandardMBean;
+
+import junit.framework.TestCase;
+
+public class ManagedQueueTest extends TestCase
+{
+ public void testAttributesContants()
+ {
+ //Construct a test MBeanInfo that matches what we would get from a real
+ //MBean using the ManagedQueue management interface. Use this to test
+ //that all attributes have a listing in the attribute array constant.
+
+ StubInvocationHandler stubIH = new StubInvocationHandler();
+ Class<ManagedQueue> mq = ManagedQueue.class;
+
+ ManagedQueue impl = mq.cast(Proxy.newProxyInstance(mq.getClassLoader(), new Class<?>[] {mq}, stubIH));
+ try
+ {
+ StandardMBean mbean = new StandardMBean(impl, ManagedQueue.class);
+
+ List<String> attributeList = new ArrayList<String>();
+ for(String attr : ManagedQueue.QUEUE_ATTRIBUTES)
+ {
+ attributeList.add(attr);
+ }
+
+ //retrieve the attributes from the constructed MBeanInfo
+ MBeanAttributeInfo[] attributes = mbean.getMBeanInfo().getAttributes();
+
+ for(MBeanAttributeInfo info : attributes)
+ {
+ if(!attributeList.contains(info.getName()))
+ {
+ fail(mq.getSimpleName() + " attributes constant array does not include the attribute: " + info.getName());
+ }
+ }
+ }
+ catch (NotCompliantMBeanException e)
+ {
+ fail("Unable to create the test proxy mbean to generate the MBeanInfo");
+ }
+
+ }
+
+ private static class StubInvocationHandler implements InvocationHandler
+ {
+ //invocation handler used to present a stub implementation when generating the StandardMBean
+ public Object invoke(Object proxy, Method method, Object[] args)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/java/management/console/build.xml b/java/management/console/build.xml
new file mode 100644
index 0000000000..8f23030b44
--- /dev/null
+++ b/java/management/console/build.xml
@@ -0,0 +1,27 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<project name="QMF Console" default="build">
+
+ <property name="module.depends" value="common client"/>
+
+ <import file="../../module.xml"/>
+
+</project>
diff --git a/java/management/console/src/main/java/org/apache/qpid/console/AbstractConsole.java b/java/management/console/src/main/java/org/apache/qpid/console/AbstractConsole.java
new file mode 100644
index 0000000000..d95003b1cc
--- /dev/null
+++ b/java/management/console/src/main/java/org/apache/qpid/console/AbstractConsole.java
@@ -0,0 +1,81 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.console;
+
+public class AbstractConsole implements Console
+{
+ public AbstractConsole()
+ {
+ }
+
+ public void agentRemoved(Agent agent)
+ {
+ }
+
+ public void brokerConnected(Broker broker)
+ {
+ }
+
+ public void brokerDisconnected(Broker broker)
+ {
+ }
+
+ public void brokerInformation(Broker broker)
+ {
+ }
+
+ public void eventRecieved(Broker broker, QMFEvent anEvent)
+ {
+ }
+
+ public void hearbeatRecieved(Agent agent, long timestamp)
+ {
+ }
+
+ public void methodResponse(Broker broker, long seq, MethodResult response)
+ {
+ }
+
+ public void newAgent(Agent agent)
+ {
+ }
+
+ public void newClass(short kind, ClassKey key)
+ {
+ }
+
+ public void newPackage(String packageName)
+ {
+ }
+
+ public void objectProperties(Broker broker, QMFObject obj)
+ {
+ }
+
+ public void objectStatistics(Broker broker, QMFObject obj)
+ {
+ }
+
+ public Class typeMapping(ClassKey key)
+ {
+ return QMFObject.class;
+ }
+} \ No newline at end of file
diff --git a/java/management/console/src/main/java/org/apache/qpid/console/Agent.java b/java/management/console/src/main/java/org/apache/qpid/console/Agent.java
new file mode 100644
index 0000000000..e1887d82ea
--- /dev/null
+++ b/java/management/console/src/main/java/org/apache/qpid/console/Agent.java
@@ -0,0 +1,116 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.console;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Agent
+{
+ private static Logger log = LoggerFactory.getLogger(Agent.class);
+
+ public static String AgentKey(long AgentBank, long BrokerBank)
+ {
+ return String.format("%s:%s", AgentBank, BrokerBank);
+ }
+
+ public static long getAgentBank(String routingKey)
+ {
+ String delim = ".";
+ return Long.parseLong(routingKey.split(java.util.regex.Pattern
+ .quote(delim))[3]);
+ }
+
+ public static long getBrokerBank(String routingKey)
+ {
+ String delim = ".";
+ return Long.parseLong(routingKey.split(java.util.regex.Pattern
+ .quote(delim))[2]);
+ }
+
+ public static String routingCode(long AgentBank, long BrokerBank)
+ {
+ return String.format("agent.%s.%s", BrokerBank, AgentBank);
+ }
+
+ private long agentBank;
+ private Broker broker;
+ private long brokerBank;
+ private String label;
+
+ public Agent(Broker broker, long agentBank, String label)
+ {
+ this.setBroker(broker);
+ this.setBrokerBank(broker.brokerBank());
+ this.setAgentBank(agentBank);
+ this.setlabel(label);
+ }
+
+ public final String agentKey()
+ {
+ return Agent.AgentKey(getAgentBank(), getBrokerBank());
+ }
+
+ public final long getAgentBank()
+ {
+ return agentBank;
+ }
+
+ public final Broker getBroker()
+ {
+ return broker;
+ }
+
+ public final long getBrokerBank()
+ {
+ return brokerBank;
+ }
+
+ public final String getlabel()
+ {
+ return label;
+ }
+
+ public final String routingCode()
+ {
+ return Agent.routingCode(getAgentBank(), getBrokerBank());
+ }
+
+ public final void setAgentBank(long value)
+ {
+ agentBank = value;
+ }
+
+ public final void setBroker(Broker value)
+ {
+ broker = value;
+ }
+
+ public final void setBrokerBank(long value)
+ {
+ brokerBank = value;
+ }
+
+ public final void setlabel(String value)
+ {
+ label = value;
+ }
+} \ No newline at end of file
diff --git a/java/management/console/src/main/java/org/apache/qpid/console/Broker.java b/java/management/console/src/main/java/org/apache/qpid/console/Broker.java
new file mode 100644
index 0000000000..2ea2ab8a70
--- /dev/null
+++ b/java/management/console/src/main/java/org/apache/qpid/console/Broker.java
@@ -0,0 +1,505 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.console;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.UUID;
+
+import javax.jms.BytesMessage;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.transport.codec.BBDecoder;
+import org.apache.qpid.transport.codec.BBEncoder;
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class Broker implements MessageListener
+{
+ class HeaderInfo
+ {
+ boolean valid;
+ long sequence;
+ char opcode;
+
+ public String toString()
+ {
+ return String.format("%s Header with opcode %s and sequence %s",
+ (valid ? "Valid" : "Invalid"), opcode, sequence);
+ }
+ }
+
+ private static Logger log = LoggerFactory.getLogger(Broker.class);
+ public static int SYNC_TIME = 60000;
+ // JMS Stuff
+ private javax.jms.Session session;
+ boolean sessionTransacted = false;
+ private String replyName;
+ private String topicName;
+ private MessageProducer prod;
+ private ArrayList<MessageConsumer> consumers = new ArrayList<MessageConsumer>();
+ private Queue reply;
+ private Queue topic;
+ private int acknowledgeMode = javax.jms.Session.AUTO_ACKNOWLEDGE;
+ // QMF Stuff
+ AMQConnection connection;
+ public String url;
+ public java.util.HashMap<String, Agent> Agents = new java.util.HashMap<String, Agent>();
+ private Session consoleSession;
+ private boolean connected = false;
+ private boolean syncInFlight = false;
+ private boolean topicBound = false;
+ private int reqsOutstanding = 0;
+ private Object lockObject = new Object();
+ UUID brokerId = UUID.randomUUID();
+
+ public Broker(org.apache.qpid.console.Session session, String url)
+ {
+ log.debug("Creating a new Broker for url " + url);
+ this.url = url;
+ consoleSession = session;
+ this.tryToConnect();
+ }
+
+ public int brokerBank()
+ {
+ return 1;
+ }
+
+ protected HeaderInfo CheckHeader(Decoder decoder)
+ {
+ HeaderInfo returnValue = new HeaderInfo();
+ returnValue.opcode = 'x';
+ returnValue.sequence = -1;
+ returnValue.valid = false;
+ if (decoder.hasRemaining())
+ {
+ char character = (char) decoder.readUint8();
+ if (character != 'A')
+ {
+ return returnValue;
+ }
+ character = (char) decoder.readUint8();
+ if (character != 'M')
+ {
+ return returnValue;
+ }
+ character = (char) decoder.readUint8();
+ if (character != '2')
+ {
+ return returnValue;
+ }
+ returnValue.valid = true;
+ returnValue.opcode = (char) decoder.readUint8();
+ returnValue.sequence = decoder.readUint32();
+ }
+ return returnValue;
+ }
+
+ public Encoder createEncoder(char opcode, long sequence)
+ {
+ return setHeader(new BBEncoder(1024), opcode, sequence);
+ }
+
+ public Message createMessage(Encoder enc)
+ {
+ try
+ {
+ byte[] buf = new byte[1024];
+ byte[] body = new byte[1024];
+ BBEncoder bbenc = (BBEncoder) enc;
+ BytesMessage msg = session.createBytesMessage();
+ ByteBuffer slice = bbenc.buffer();
+ while (slice.hasRemaining())
+ {
+ int n = Math.min(buf.length, slice.remaining());
+ slice.get(buf, 0, n);
+ msg.writeBytes(buf, 0, n);
+ }
+ return msg;
+ } catch (JMSException e)
+ {
+ throw new ConsoleException(e);
+ }
+ }
+
+ public void decrementOutstanding()
+ {
+ synchronized (lockObject)
+ {
+ this.reqsOutstanding -= 1;
+ if ((reqsOutstanding == 0) & !topicBound)
+ {
+ for (String key : consoleSession.bindingKeys())
+ {
+ try
+ {
+ // this.clientSession.exchangeBind(topicName,
+ // "qpid.mannagement", key) ;
+ log.debug("Setting Topic Binding " + key);
+ // topicName = "management://qpid.management//" + key;
+ String rk = String.format("&routingkey='%s'", key);
+ Queue aQueue = session.createQueue(topicName + rk);
+ MessageConsumer cons = session.createConsumer(aQueue);
+ cons.setMessageListener(this);
+ consumers.add(cons);
+ } catch (JMSException e)
+ {
+ throw new ConsoleException(e);
+ }
+ }
+ topicBound = true;
+ }
+ if ((reqsOutstanding == 0) & syncInFlight)
+ {
+ syncInFlight = false;
+ lockObject.notifyAll();
+ }
+ }
+ }
+
+ private byte[] ensure(int capacity, byte[] body, int size)
+ {
+ if (capacity > body.length)
+ {
+ byte[] copy = new byte[capacity];
+ System.arraycopy(body, 0, copy, 0, size);
+ body = copy;
+ }
+ return body;
+ }
+
+ protected void finalize()
+ {
+ if (connected)
+ {
+ this.shutdown();
+ }
+ }
+
+ public boolean getSyncInFlight()
+ {
+ return syncInFlight;
+ }
+
+ public void incrementOutstanding()
+ {
+ synchronized (lockObject)
+ {
+ this.reqsOutstanding += 1;
+ }
+ }
+
+ public boolean isConnected()
+ {
+ return connected;
+ }
+
+ public void onMessage(Message msg)
+ {
+ Decoder decoder = readBody(msg);
+ HeaderInfo headerInfo = this.CheckHeader(decoder);
+ // log.debug(headerInfo.toString());
+ while (headerInfo.valid)
+ {
+ long seq = headerInfo.sequence;
+ switch (headerInfo.opcode)
+ {
+ case 'b':
+ consoleSession.handleBrokerResponse(this, decoder, seq);
+ break;
+ case 'p':
+ consoleSession.handlePackageIndicator(this, decoder, seq);
+ break;
+ case 'z':
+ consoleSession.handleCommandComplete(this, decoder, seq);
+ break;
+ case 'q':
+ consoleSession.handleClassIndicator(this, decoder, seq);
+ break;
+ case 'm':
+ consoleSession.handleMethodResponse(this, decoder, seq);
+ break;
+ case 'h':
+ consoleSession
+ .handleHeartbeatIndicator(this, decoder, seq, msg);
+ break;
+ case 'e':
+ consoleSession.handleEventIndicator(this, decoder, seq);
+ break;
+ case 's':
+ consoleSession.handleSchemaResponse(this, decoder, seq);
+ break;
+ case 'c':
+ consoleSession.handleContentIndicator(this, decoder, seq, true,
+ false);
+ break;
+ case 'i':
+ consoleSession.handleContentIndicator(this, decoder, seq,
+ false, true);
+ break;
+ case 'g':
+ consoleSession.handleContentIndicator(this, decoder, seq, true,
+ true);
+ break;
+ default:
+ log.error("Invalid message type recieved with opcode "
+ + headerInfo.opcode);
+ break;
+ }
+ headerInfo = this.CheckHeader(decoder);
+ }
+ }
+
+ private Decoder readBody(Message message)
+ {
+ BytesMessage msg = (BytesMessage) message;
+ BBDecoder dec = new BBDecoder();
+ byte[] buf = new byte[1024];
+ byte[] body = new byte[1024];
+ int size = 0;
+ int n;
+ try
+ {
+ while ((n = msg.readBytes(buf)) > 0)
+ {
+ body = ensure(size + n, body, size);
+ System.arraycopy(buf, 0, body, size, n);
+ size += n;
+ }
+ } catch (JMSException e)
+ {
+ throw new ConsoleException(e);
+ }
+ dec.init(ByteBuffer.wrap(body, 0, size));
+ return dec;
+ }
+
+ public void send(Encoder enc)
+ {
+ this.send(this.createMessage(enc), "broker");
+ }
+
+ public void send(Message msg)
+ {
+ this.send(msg, "broker", -1);
+ }
+
+ public void send(Message msg, String routingKey)
+ {
+ this.send(msg, routingKey, -1);
+ }
+
+ public void send(Message msg, String routingKey, int ttl)
+ {
+ synchronized (lockObject)
+ {
+ try
+ {
+ log.debug(String.format("Sending message to routing key '%s'",
+ routingKey));
+ String destName = String.format(
+ "management://qpid.management//?routingkey='%s'",
+ routingKey);
+ log.debug(destName);
+ Queue dest = session.createQueue(destName);
+ // Queue jmsReply = session
+ // createQueue("direct://amq.direct//?routingkey='reply-"
+ // + brokerId + "'");
+ if (ttl != -1)
+ {
+ msg.setJMSExpiration(ttl);
+ }
+ msg.setJMSReplyTo(reply);
+ prod.send(dest, msg);
+ } catch (Exception e)
+ {
+ throw new ConsoleException(e);
+ }
+ }
+ }
+
+ protected Encoder setHeader(Encoder enc, char opcode, long sequence)
+ {
+ enc.writeUint8((short) 'A');
+ enc.writeUint8((short) 'M');
+ enc.writeUint8((short) '2');
+ enc.writeUint8((short) opcode);
+ enc.writeUint32(sequence);
+ return enc;
+ }
+
+ public void setSyncInFlight(boolean inFlight)
+ {
+ synchronized (lockObject)
+ {
+ syncInFlight = inFlight;
+ lockObject.notifyAll();
+ }
+ }
+
+ public void shutdown()
+ {
+ if (connected)
+ {
+ this.waitForStable();
+ try
+ {
+ session.close();
+ for (MessageConsumer cons : consumers)
+ {
+ cons.close();
+ }
+ connection.close();
+ } catch (Exception e)
+ {
+ throw new ConsoleException(e);
+ } finally
+ {
+ this.connected = false;
+ }
+ }
+ }
+
+ protected void tryToConnect()
+ {
+ try
+ {
+ reqsOutstanding = 1;
+ Agent newAgent = new Agent(this, 0, "BrokerAgent");
+ Agents.put(newAgent.agentKey(), newAgent);
+ connection = new AMQConnection(url);
+ session = connection.createSession(sessionTransacted,
+ acknowledgeMode);
+ replyName = String
+ .format(
+ "direct://amq.direct//reply-%s?exclusive='True'&autodelete='True'",
+ brokerId);
+ topicName = String
+ .format(
+ "management://qpid.management//topic-%s?exclusive='True'&autodelete='True'",
+ brokerId);
+ reply = session.createQueue(replyName);
+ MessageConsumer cons = session.createConsumer(reply);
+ cons.setMessageListener(this);
+ consumers.add(cons);
+ prod = session.createProducer(null);
+ topic = session.createQueue(topicName);
+ cons = session.createConsumer(topic);
+ cons.setMessageListener(this);
+ consumers.add(cons);
+ connection.start();
+ // Rest of the topic is bound later. Start er up
+ } catch (Exception e)
+ {
+ throw new ConsoleException(e);
+ }
+ connected = true;
+ consoleSession.handleBrokerConnect(this);
+ Encoder Encoder = createEncoder('B', 0);
+ this.send(Encoder);
+ }
+
+ public void updateAgent(QMFObject obj)
+ {
+ long agentBank = (Long) obj.getProperty("agentBank");
+ long brokerBank = (Long) obj.getProperty("brokerBank");
+ String key = Agent.AgentKey(agentBank, brokerBank);
+ if (obj.isDeleted())
+ {
+ if (Agents.containsKey(key))
+ {
+ Agent agent = Agents.get(key);
+ Agents.remove(key);
+ consoleSession.handleAgentRemoved(agent);
+ }
+ } else
+ {
+ if (!Agents.containsKey(key))
+ {
+ Agent newAgent = new Agent(this, agentBank, (String) obj
+ .getProperty("label"));
+ Agents.put(key, newAgent);
+ consoleSession.handleNewAgent(newAgent);
+ }
+ }
+ }
+
+ public void waitForStable()
+ {
+ synchronized (lockObject)
+ {
+ if (connected)
+ {
+ long start = System.currentTimeMillis();
+ syncInFlight = true;
+ while (reqsOutstanding != 0)
+ {
+ log.debug("Waiting to recieve messages");
+ try
+ {
+ lockObject.wait(SYNC_TIME);
+ } catch (Exception e)
+ {
+ throw new ConsoleException(e);
+ }
+ long duration = System.currentTimeMillis() - start;
+ if (duration > SYNC_TIME)
+ {
+ throw new ConsoleException(
+ "Timeout waiting for Broker to Sync");
+ }
+ }
+ }
+ }
+ }
+
+ public void waitForSync(int timeout)
+ {
+ synchronized (lockObject)
+ {
+ long start = System.currentTimeMillis();
+ while (syncInFlight)
+ {
+ try
+ {
+ lockObject.wait(SYNC_TIME);
+ } catch (Exception e)
+ {
+ throw new ConsoleException(e);
+ }
+ }
+ long duration = System.currentTimeMillis() - start;
+ if (duration > timeout)
+ {
+ throw new ConsoleException("Timeout waiting for Broker to Sync");
+ }
+ }
+ }
+}
diff --git a/java/management/console/src/main/java/org/apache/qpid/console/ClassKey.java b/java/management/console/src/main/java/org/apache/qpid/console/ClassKey.java
new file mode 100644
index 0000000000..9eac8942cb
--- /dev/null
+++ b/java/management/console/src/main/java/org/apache/qpid/console/ClassKey.java
@@ -0,0 +1,146 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.console;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ClassKey
+{
+ private static Logger log = LoggerFactory.getLogger(ClassKey.class);
+ private String packageName;
+ private String className;
+ private long[] hash = new long[4];
+
+ public ClassKey(Decoder dec)
+ {
+ setPackageName(dec.readStr8());
+ setClassName(dec.readStr8());
+ hash[0] = dec.readUint32();
+ hash[1] = dec.readUint32();
+ hash[2] = dec.readUint32();
+ hash[3] = dec.readUint32();
+ }
+
+ public ClassKey(String keyString)
+ {
+ String delims = "[*:*(*)]";
+ String[] parts = keyString.split(delims);
+ if (parts.length < 3)
+ {
+ throw new ConsoleException(
+ "Invalid class key format. Format should be package:class(bytes)");
+ }
+ setPackageName(parts[0]);
+ setClassName(parts[1]);
+ delims = "-";
+ String[] bytes = parts[2].split(delims);
+ if (bytes.length != 4)
+ {
+ throw new ConsoleException(
+ "Invalid class key format. Bytes should be in the format HEX-HEX-HEX-HEX");
+ }
+ hash[0] = Long.parseLong(bytes[0], 16);
+ hash[1] = Long.parseLong(bytes[1], 16);
+ hash[2] = Long.parseLong(bytes[2], 16);
+ hash[3] = Long.parseLong(bytes[3], 16);
+ }
+
+ public void encode(Encoder enc)
+ {
+ enc.writeStr8(getPackageName());
+ enc.writeStr8(getClassName());
+ enc.writeUint32(hash[0]);
+ enc.writeUint32(hash[1]);
+ enc.writeUint32(hash[2]);
+ enc.writeUint32(hash[3]);
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj.getClass().equals(this.getClass()))
+ {
+ ClassKey other = (ClassKey) obj;
+ return (other.getKeyString().equals(this.getKeyString()));
+ } else
+ {
+ return false;
+ }
+ }
+
+ public final String getClassName()
+ {
+ return className;
+ }
+
+ public long[] getHash()
+ {
+ return hash;
+ }
+
+ public String getHashString()
+ {
+ return String.format("%08x-%08x-%08x-%08x", hash[0], hash[1], hash[2],
+ hash[3]);
+ }
+
+ public String getKeyString()
+ {
+ String hashString = this.getHashString();
+ return String.format("%s:%s(%s)", getPackageName(), getClassName(),
+ hashString);
+ }
+
+ public String getPackageName()
+ {
+ return packageName;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return getKeyString().hashCode();
+ }
+
+ public void setClassName(String value)
+ {
+ className = value;
+ }
+
+ public void setHash(long[] hash)
+ {
+ this.hash = hash;
+ }
+
+ public void setPackageName(String value)
+ {
+ packageName = value;
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("ClassKey: %s", getKeyString());
+ }
+} \ No newline at end of file
diff --git a/java/management/console/src/main/java/org/apache/qpid/console/Console.java b/java/management/console/src/main/java/org/apache/qpid/console/Console.java
new file mode 100644
index 0000000000..11b381032a
--- /dev/null
+++ b/java/management/console/src/main/java/org/apache/qpid/console/Console.java
@@ -0,0 +1,51 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.console;
+
+public interface Console
+{
+ void agentRemoved(Agent agent);
+
+ void brokerConnected(Broker broker);
+
+ void brokerDisconnected(Broker broker);
+
+ void brokerInformation(Broker broker);
+
+ void eventRecieved(Broker broker, QMFEvent anEvent);
+
+ void hearbeatRecieved(Agent agent, long timestamp);
+
+ void methodResponse(Broker broker, long seq, MethodResult response);
+
+ void newAgent(Agent agent);
+
+ void newClass(short kind, ClassKey key);
+
+ void newPackage(String packageName);
+
+ void objectProperties(Broker broker, QMFObject obj);
+
+ void objectStatistics(Broker broker, QMFObject obj);
+
+ @SuppressWarnings("unchecked")
+ Class typeMapping(ClassKey key);
+} \ No newline at end of file
diff --git a/java/management/console/src/main/java/org/apache/qpid/console/ConsoleException.java b/java/management/console/src/main/java/org/apache/qpid/console/ConsoleException.java
new file mode 100644
index 0000000000..3176da70a6
--- /dev/null
+++ b/java/management/console/src/main/java/org/apache/qpid/console/ConsoleException.java
@@ -0,0 +1,48 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.console;
+
+import java.lang.RuntimeException;
+
+public class ConsoleException extends RuntimeException
+{
+ private static final long serialVersionUID = 1L;
+
+ public ConsoleException()
+ {
+ super();
+ }
+
+ public ConsoleException(String message)
+ {
+ super(message);
+ }
+
+ public ConsoleException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+
+ public ConsoleException(Throwable cause)
+ {
+ super(cause);
+ }
+}
diff --git a/java/management/console/src/main/java/org/apache/qpid/console/EventSeverity.java b/java/management/console/src/main/java/org/apache/qpid/console/EventSeverity.java
new file mode 100644
index 0000000000..d40d41b196
--- /dev/null
+++ b/java/management/console/src/main/java/org/apache/qpid/console/EventSeverity.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.console;
+
+public enum EventSeverity
+{
+ EMER(0), ALERT(1), CRIT(2), ERROR(3), WARN(4), NOTIC(5), INFO(6), DEBUG(7);
+ private int intValue;
+
+ private EventSeverity(int value)
+ {
+ intValue = value;
+ }
+
+ public int getValue()
+ {
+ return intValue;
+ }
+} \ No newline at end of file
diff --git a/java/management/console/src/main/java/org/apache/qpid/console/MethodResult.java b/java/management/console/src/main/java/org/apache/qpid/console/MethodResult.java
new file mode 100644
index 0000000000..34980b50e1
--- /dev/null
+++ b/java/management/console/src/main/java/org/apache/qpid/console/MethodResult.java
@@ -0,0 +1,88 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.console;
+
+import java.util.HashMap;
+
+public class MethodResult
+{
+ private long returnCode;
+ private String text;
+ protected java.util.HashMap<String, Object> returnValues;
+
+ public MethodResult(long aCode, String aMsg,
+ java.util.HashMap<String, Object> args)
+ {
+ setReturnCode(aCode);
+ setText(aMsg);
+ returnValues = args;
+ }
+
+ public long getReturnCode()
+ {
+ return returnCode;
+ }
+
+ public Object getReturnValue(String name)
+ {
+ Object returnValue = null;
+ if (returnValues.containsKey(name))
+ {
+ returnValue = returnValues.get(name);
+ }
+ return returnValue;
+ }
+
+ public HashMap<String, Object> getReturnValues()
+ {
+ return returnValues;
+ }
+
+ public String getText()
+ {
+ return text;
+ }
+
+ public void setReturnCode(long value)
+ {
+ returnCode = value;
+ }
+
+ public void setText(String value)
+ {
+ text = value;
+ }
+
+ @Override
+ public String toString()
+ {
+ String returnString = "";
+ for (java.util.Map.Entry<String, Object> pair : returnValues.entrySet())
+ {
+ returnString = returnString
+ + String.format("(Key: '%s' Value: '%s')", pair.getKey(),
+ pair.getValue());
+ }
+ return String.format(
+ "MethodResult: ReturnCode=%s, Text=%s Values=[%s]",
+ getReturnCode(), getText(), returnString);
+ }
+} \ No newline at end of file
diff --git a/java/management/console/src/main/java/org/apache/qpid/console/ObjectID.java b/java/management/console/src/main/java/org/apache/qpid/console/ObjectID.java
new file mode 100644
index 0000000000..6cf5301de5
--- /dev/null
+++ b/java/management/console/src/main/java/org/apache/qpid/console/ObjectID.java
@@ -0,0 +1,93 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.console;
+
+import org.apache.qpid.transport.codec.*;
+
+public class ObjectID
+{
+ protected long first;
+ protected long second;
+
+ public ObjectID()
+ {
+ }
+
+ public ObjectID(Decoder dec)
+ {
+ first = dec.readUint64();
+ second = dec.readUint64();
+ }
+
+ public ObjectID(long first, long second)
+ {
+ this.first = first;
+ this.second = second;
+ }
+
+ public long agentBank()
+ {
+ return (this.first & 0x000000000FFFFFFF);
+ }
+
+ public long brokerBank()
+ {
+ return (this.first & 0x0000FFFFF0000000L) >> 28;
+ }
+
+ public void encode(Encoder enc)
+ {
+ enc.writeUint64(first);
+ enc.writeUint64(second);
+ }
+
+ public long flags()
+ {
+ return (this.first & 0xF000000000000000L) >> 60;
+ }
+
+ public boolean isDurable()
+ {
+ return sequence() == 0;
+ }
+
+ public long objectNum()
+ {
+ return second;
+ }
+
+ public String routingCode()
+ {
+ return Agent.routingCode(agentBank(), brokerBank());
+ }
+
+ public long sequence()
+ {
+ return (this.first & 0x0FFF000000000000L) >> 48;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "" + flags() + "-" + sequence() + "-" + brokerBank() + "-"
+ + agentBank() + "-" + objectNum();
+ }
+} \ No newline at end of file
diff --git a/java/management/console/src/main/java/org/apache/qpid/console/QMFEvent.java b/java/management/console/src/main/java/org/apache/qpid/console/QMFEvent.java
new file mode 100644
index 0000000000..116387acfc
--- /dev/null
+++ b/java/management/console/src/main/java/org/apache/qpid/console/QMFEvent.java
@@ -0,0 +1,108 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.console;
+
+import java.util.HashMap;
+
+import org.apache.qpid.transport.codec.*;
+
+public class QMFEvent
+{
+ private java.util.HashMap<String, Object> arguments;
+ private ClassKey classKey;
+ private Session session;
+ private EventSeverity severity;
+ // FIXME time?
+ private long timestamp;
+
+ public QMFEvent(Session session, Decoder dec)
+ {
+ setSession(session);
+ setClassKey(new ClassKey(dec));
+ setTimestamp(dec.readInt64());
+ setSeverity(EventSeverity.values()[dec.readUint8()]);
+ SchemaClass sClass = getSession().getSchema(getClassKey());
+ setArguments(new java.util.HashMap<String, Object>());
+ if (sClass != null)
+ {
+ for (SchemaArgument arg : sClass.arguments)
+ {
+ getArguments().put(arg.getName(),
+ getSession().decodeValue(dec, arg.getType()));
+ }
+ }
+ }
+
+ public final Object GetArgument(String argName)
+ {
+ return getArguments().get(argName);
+ }
+
+ public final HashMap<String, Object> getArguments()
+ {
+ return arguments;
+ }
+
+ public final ClassKey getClassKey()
+ {
+ return classKey;
+ }
+
+ public final Session getSession()
+ {
+ return session;
+ }
+
+ public final EventSeverity getSeverity()
+ {
+ return severity;
+ }
+
+ public final long getTimestamp()
+ {
+ return timestamp;
+ }
+
+ public final void setArguments(java.util.HashMap<String, Object> value)
+ {
+ arguments = value;
+ }
+
+ public final void setClassKey(ClassKey value)
+ {
+ classKey = value;
+ }
+
+ public final void setSession(Session value)
+ {
+ session = value;
+ }
+
+ public final void setSeverity(EventSeverity value)
+ {
+ severity = value;
+ }
+
+ public final void setTimestamp(long value)
+ {
+ timestamp = value;
+ }
+} \ No newline at end of file
diff --git a/java/management/console/src/main/java/org/apache/qpid/console/QMFObject.java b/java/management/console/src/main/java/org/apache/qpid/console/QMFObject.java
new file mode 100644
index 0000000000..1919bac411
--- /dev/null
+++ b/java/management/console/src/main/java/org/apache/qpid/console/QMFObject.java
@@ -0,0 +1,423 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.console;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import edu.emory.mathcs.backport.java.util.Arrays;
+
+public class QMFObject
+{
+ private static Logger log = LoggerFactory.getLogger(QMFObject.class);
+ protected SchemaClass schema;
+ private java.util.Date createTime;
+ private java.util.Date currentTime;
+ private java.util.Date deleteTime;
+ private ObjectID objectID;
+ private Session session;
+ private boolean managed;
+ public java.util.HashMap<String, Object> properties = new java.util.HashMap<String, Object>();
+ public java.util.HashMap<String, Object> statistics = new java.util.HashMap<String, Object>();
+
+ // This constructor is the "naked" constructor which creates
+ // an object without a session or a schema. It is used by
+ // subclasses which are auto generated
+ public QMFObject()
+ {
+ }
+
+ public QMFObject(QMFObject source)
+ {
+ this.setSession(source.getSession());
+ this.setSchema(source.getSchema());
+ this.managed = source.managed;
+ this.setCurrentTime(source.getCurrentTime());
+ this.setCreateTime(source.getCreateTime());
+ this.setDeleteTime(source.getDeleteTime());
+ this.setObjectID(source.getObjectID());
+ this.properties = source.properties;
+ this.statistics = source.statistics;
+ }
+
+ // This constructor is used by a session make object call to
+ // create a blank object from a schema.
+ public QMFObject(Session session, SchemaClass schema,
+ boolean hasProperties, boolean hasStats, boolean isManaged)
+ {
+ setSession(session);
+ setSchema(schema);
+ managed = isManaged;
+ if (hasProperties)
+ {
+ for (SchemaProperty prop : getSchema().getAllProperties())
+ {
+ Object propValue = null;
+ if (!prop.getOptional())
+ {
+ propValue = Util.defaultValue(prop.getType());
+ }
+ this.setProperty(prop.getName(), propValue);
+ }
+ }
+ if (hasStats)
+ {
+ for (SchemaStatistic stat : getSchema().statistics)
+ {
+ setStatistic(stat.getName(), Util.defaultValue(stat.getType()));
+ }
+ }
+ }
+
+ // This constructor is used by the session to create an object based on a
+ // data
+ // stream by the agent.
+ public QMFObject(Session session, SchemaClass schema, Decoder dec,
+ boolean hasProperties, boolean hasStats, boolean isManaged)
+ {
+ setSession(session);
+ setSchema(schema);
+ managed = isManaged;
+ if (managed)
+ {
+ // FIXME DateTime or Uint64??
+ setCurrentTime(new java.util.Date(dec.readDatetime()));
+ setCreateTime(new java.util.Date(dec.readDatetime()));
+ setDeleteTime(new java.util.Date(dec.readDatetime()));
+ setObjectID(new ObjectID(dec));
+ }
+ if (hasProperties)
+ {
+ java.util.ArrayList<String> excluded = processPresenceMasks(dec,
+ getSchema());
+ for (SchemaProperty prop : getSchema().getAllProperties())
+ {
+ if (excluded.contains(prop.getName()))
+ {
+ // log.Debug(String.Format("Setting Property Default {0}",
+ // prop.Name)) ;
+ safeAddProperty(prop.getName(), null);
+ } else
+ {
+ // log.Debug(String.Format("Setting Property {0}",
+ // prop.Name)) ;
+ safeAddProperty(prop.getName(), session.decodeValue(dec,
+ prop.getType()));
+ }
+ }
+ }
+ if (hasStats)
+ {
+ for (SchemaStatistic stat : getSchema().getAllStatistics())
+ {
+ // log.Debug(String.Format("Setting Statistic {0}", stat.Name))
+ // ;
+ statistics.put(stat.getName(), session.decodeValue(dec, stat
+ .getType()));
+ }
+ }
+ }
+
+ public final long agentBank()
+ {
+ return getObjectID().agentBank();
+ }
+
+ public final long brokerBank()
+ {
+ return getObjectID().brokerBank();
+ }
+
+ public final void encode(Encoder enc)
+ {
+ int mask = 0;
+ int bit = 0;
+ java.util.ArrayList<SchemaProperty> propsToEncode = new java.util.ArrayList<SchemaProperty>();
+ log.debug(String.format("Encoding class %s:%s", getSchema()
+ .getPackageName(), getSchema().getClassName()));
+ enc.writeUint8((short) 20);
+ getSchema().getKey().encode(enc);
+ for (SchemaProperty prop : getSchema().getAllProperties())
+ {
+ if (prop.getOptional())
+ {
+ if (bit == 0)
+ {
+ bit = 1;
+ }
+ if ((properties.containsKey(prop.getName()))
+ && (properties.get(prop.getName()) != null))
+ {
+ mask |= bit;
+ propsToEncode.add(prop);
+ } else
+ {
+ }
+ bit = bit << 1;
+ if (bit == 256)
+ {
+ bit = 0;
+ enc.writeUint8((short) mask);
+ mask = 0;
+ }
+ } else
+ {
+ propsToEncode.add(prop);
+ }
+ }
+ if (bit != 0)
+ {
+ enc.writeUint8((short) mask);
+ }
+ for (SchemaProperty prop : propsToEncode)
+ {
+ Object obj = properties.get(prop.getName());
+ // log.Debug(String.Format("Encoding property {0}", prop.Name)) ;
+ getSession().encodeValue(enc, prop.getType(), obj);
+ }
+ for (SchemaStatistic stat : getSchema().statistics)
+ {
+ Object obj = statistics.get(stat.getName());
+ getSession().encodeValue(enc, stat.getType(), obj);
+ }
+ log.debug("Done");
+ }
+
+ public final Date getCreateTime()
+ {
+ return createTime;
+ }
+
+ public final Date getCurrentTime()
+ {
+ return currentTime;
+ }
+
+ public final Date getDeleteTime()
+ {
+ return deleteTime;
+ }
+
+ protected final ArrayList<SchemaMethod> getMethods()
+ {
+ return getSchema().getAllMethods();
+ }
+
+ public final ObjectID getObjectID()
+ {
+ return objectID;
+ }
+
+ public final Object getProperty(String attributeName)
+ {
+ return properties.get(attributeName);
+ }
+
+ public SchemaClass getSchema()
+ {
+ return schema;
+ }
+
+ public final Session getSession()
+ {
+ return session;
+ }
+
+ protected final MethodResult internalInvokeMethod(String name,
+ List<Object> args, boolean synchronous, int timeToLive)
+ {
+ if (!managed)
+ {
+ throw new ConsoleException("Object is not Managed");
+ }
+ if (getSchema().getMethod(name) == null)
+ {
+ throw new ConsoleException(String.format(
+ "Method named '%s' does not exist", name));
+ }
+ return getSession().invokeMethod(this, name, args, synchronous,
+ timeToLive);
+ }
+
+ public final MethodResult invokeMethod(String name, boolean synchronous,
+ int timeToLive, Object... args)
+ {
+ return this.internalInvokeMethod(name, Arrays.asList(args),
+ synchronous, timeToLive);
+ }
+
+ public final MethodResult invokeMethod(String name, boolean synchronous,
+ Object... args)
+ {
+ return this.internalInvokeMethod(name, Arrays.asList(args),
+ synchronous, Broker.SYNC_TIME);
+ }
+
+ public final MethodResult invokeMethod(String name, int timeToLive,
+ Object... args)
+ {
+ return this.internalInvokeMethod(name, Arrays.asList(args), true,
+ timeToLive);
+ }
+
+ public final MethodResult invokeMethod(String name, Object... args)
+ {
+ return this.internalInvokeMethod(name, Arrays.asList(args), true,
+ Broker.SYNC_TIME);
+ }
+
+ public final boolean isDeleted()
+ {
+ return !getDeleteTime().equals(new java.util.Date(0));
+ }
+
+ protected final ArrayList<String> processPresenceMasks(Decoder dec,
+ SchemaClass schema)
+ {
+ java.util.ArrayList<String> excludes = new java.util.ArrayList<String>();
+ short bit = 0;
+ short mask = 0;
+ for (SchemaProperty prop : getSchema().getAllProperties())
+ {
+ if (prop.getOptional())
+ {
+ // log.Debug(String.Format("Property named {0} is optional",
+ // prop.Name)) ;
+ if (bit == 0)
+ {
+ mask = dec.readUint8();
+ bit = 1;
+ }
+ if ((mask & bit) == 0)
+ {
+ // log.Debug(String.Format("Property named {0} is not present",
+ // prop.Name)) ;
+ excludes.add(prop.getName());
+ }
+ bit *= 2;
+ if (bit == 256)
+ {
+ bit = 0;
+ }
+ }
+ }
+ return excludes;
+ }
+
+ public final String routingKey()
+ {
+ return getObjectID().routingCode();
+ }
+
+ protected final void safeAddProperty(String propName, Object value)
+ {
+ if (properties.containsKey(propName))
+ {
+ properties.put(propName, value);
+ } else
+ {
+ properties.put(propName, value);
+ }
+ }
+
+ public final void setCreateTime(java.util.Date value)
+ {
+ createTime = value;
+ }
+
+ public final void setCurrentTime(java.util.Date value)
+ {
+ currentTime = value;
+ }
+
+ public final void setDeleteTime(java.util.Date value)
+ {
+ deleteTime = value;
+ }
+
+ public final void setObjectID(ObjectID value)
+ {
+ objectID = value;
+ }
+
+ public final void setProperty(String attributeName, Object newValue)
+ {
+ properties.put(attributeName, newValue);
+ }
+
+ public void setSchema(SchemaClass value)
+ {
+ schema = value;
+ }
+
+ public final void setSession(Session value)
+ {
+ session = value;
+ }
+
+ protected final void setStatistic(String attributeName, Object newValue)
+ {
+ statistics.put(attributeName, newValue);
+ }
+
+ @Override
+ public String toString()
+ {
+ String propertyString = "";
+ for (Entry<String, Object> pair : properties.entrySet())
+ {
+ propertyString = propertyString
+ + String.format("(Name: '%0$s' Value: '%1$s')", pair
+ .getKey(), pair.getValue());
+ }
+ String statsString = "";
+ for (Entry<String, Object> sPair : statistics.entrySet())
+ {
+ statsString = statsString
+ + String.format("(Name: '%0$s' Value: '%1$s')", sPair
+ .getKey(), sPair.getValue());
+ }
+ if (managed)
+ {
+ return String
+ .format(
+ "Managed QMFObject %0$s:%1$s(%2$s) Properties: [%3$s] Statistics: [%4$s])",
+ getSchema().getPackageName(), getSchema()
+ .getClassName(), getObjectID(),
+ propertyString, statsString);
+ } else
+ {
+ return String
+ .format(
+ "QMFObject %0$s:%1$s Properties: [%2$s] Statistics: [%3$s]",
+ getSchema().getPackageName(), getSchema()
+ .getClassName(), propertyString,
+ statsString);
+ }
+ }
+} \ No newline at end of file
diff --git a/java/management/console/src/main/java/org/apache/qpid/console/SchemaArgument.java b/java/management/console/src/main/java/org/apache/qpid/console/SchemaArgument.java
new file mode 100644
index 0000000000..7e83b1b447
--- /dev/null
+++ b/java/management/console/src/main/java/org/apache/qpid/console/SchemaArgument.java
@@ -0,0 +1,65 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.console;
+
+import java.util.Map;
+
+import org.apache.qpid.transport.codec.Decoder;
+
+public class SchemaArgument extends SchemaVariable
+{
+ private String direction;
+
+ public SchemaArgument(Decoder dec, boolean methodArg)
+ {
+ Map<String, Object> map = dec.readMap();
+ super.populateData(map);
+ if (map.containsKey("dir"))
+ {
+ setDirection((String) map.get("dir"));
+ }
+ }
+
+ public String getDirection()
+ {
+ return direction;
+ }
+
+ public boolean isBidirectional()
+ {
+ return getDirection().equals("IO");
+ }
+
+ public boolean isInput()
+ {
+ return getDirection().equals("I") | getDirection().equals("IO");
+ }
+
+ public boolean isOutput()
+ {
+ return getDirection().equals("O") | getDirection().equals("IO");
+ }
+
+ public void setDirection(String value)
+ {
+ direction = value;
+ }
+} \ No newline at end of file
diff --git a/java/management/console/src/main/java/org/apache/qpid/console/SchemaClass.java b/java/management/console/src/main/java/org/apache/qpid/console/SchemaClass.java
new file mode 100644
index 0000000000..a0faa6c73d
--- /dev/null
+++ b/java/management/console/src/main/java/org/apache/qpid/console/SchemaClass.java
@@ -0,0 +1,251 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.console;//
+
+import java.util.ArrayList;
+
+import org.apache.qpid.transport.codec.*;
+
+public class SchemaClass
+{
+ public static int CLASS_KIND_EVENT = 2;
+ public static int CLASS_KIND_TABLE = 1;
+ public ArrayList<SchemaArgument> arguments = new ArrayList<SchemaArgument>();
+ private ClassKey classKey;
+ private int kind;
+ private Session session;
+ private ClassKey superType;
+ public ArrayList<SchemaMethod> methods = new ArrayList<SchemaMethod>();
+ public ArrayList<SchemaProperty> properties = new ArrayList<SchemaProperty>();
+ public ArrayList<SchemaStatistic> statistics = new ArrayList<SchemaStatistic>();
+
+ public SchemaClass(int kind, ClassKey key, Decoder dec, Session session)
+ {
+ // System.Console.WriteLine(key.ClassName) ;
+ setKind(kind);
+ setSession(session);
+ this.setKey(key);
+ boolean hasSupertype = false; //dec.readUint8() != 0;
+ if (kind == CLASS_KIND_TABLE)
+ {
+ int propCount = dec.readUint16();
+ int statCount = dec.readUint16();
+ int methodCount = dec.readUint16();
+ if (hasSupertype)
+ {
+ setSuperType(new ClassKey(dec));
+ }
+ for (int x = 0; x < propCount; x++)
+ {
+ properties.add(new SchemaProperty(dec));
+ }
+ for (int x = 0; x < statCount; x++)
+ {
+ statistics.add(new SchemaStatistic(dec));
+ }
+ for (int x = 0; x < methodCount; x++)
+ {
+ methods.add(new SchemaMethod(dec));
+ }
+ }
+ if (kind == CLASS_KIND_EVENT)
+ {
+ int argCount = dec.readUint16();
+ if (hasSupertype)
+ {
+ setSuperType(new ClassKey(dec));
+ }
+ for (int x = 0; x < argCount; x++)
+ {
+ arguments.add(new SchemaArgument(dec, false));
+ }
+ }
+ }
+
+ public ArrayList<SchemaMethod> getAllMethods()
+ {
+ if (getSuperType() == null)
+ {
+ return methods;
+ } else
+ {
+ ArrayList<SchemaMethod> allMethods = new ArrayList<SchemaMethod>(
+ methods);
+ allMethods.addAll(getSession().getSchema(getSuperType())
+ .getAllMethods());
+ return allMethods;
+ }
+ }
+
+ public ArrayList<SchemaProperty> getAllProperties()
+ {
+ if (getSuperType() == null)
+ {
+ return properties;
+ } else
+ {
+ ArrayList<SchemaProperty> allProperties = new ArrayList<SchemaProperty>(
+ properties);
+ allProperties.addAll(getSession().getSchema(getSuperType())
+ .getAllProperties());
+ return allProperties;
+ }
+ }
+
+ public ArrayList<SchemaStatistic> getAllStatistics()
+ {
+ if (getSuperType() == null)
+ {
+ return statistics;
+ } else
+ {
+ ArrayList<SchemaStatistic> allStats = new ArrayList<SchemaStatistic>(
+ statistics);
+ allStats.addAll(getSession().getSchema(getSuperType())
+ .getAllStatistics());
+ return allStats;
+ }
+ }
+
+ public String getClassKeyString()
+ {
+ return getKey().getKeyString();
+ }
+
+ public String getClassName()
+ {
+ return getKey().getClassName();
+ }
+
+ public ClassKey getKey()
+ {
+ return classKey;
+ }
+
+ public int getKind()
+ {
+ return kind;
+ }
+
+ public SchemaMethod getMethod(String name)
+ {
+ SchemaMethod returnValue = null;
+ for (SchemaMethod method : methods)
+ {
+ if (method.getName().equals(name))
+ {
+ returnValue = method;
+ break;
+ }
+ }
+ return returnValue;
+ }
+
+ public String getPackageName()
+ {
+ return getKey().getPackageName();
+ }
+
+ protected Session getSession()
+ {
+ return session;
+ }
+
+ public ClassKey getSuperType()
+ {
+ return superType;
+ }
+
+ public boolean hasSuperType()
+ {
+ return getSuperType() != null;
+ }
+
+ public void setKey(ClassKey value)
+ {
+ classKey = value;
+ }
+
+ public void setKind(int value)
+ {
+ kind = value;
+ }
+
+ protected void setSession(Session value)
+ {
+ session = value;
+ }
+
+ public void setSuperType(ClassKey value)
+ {
+ superType = value;
+ }
+
+ public ArrayList<SchemaProperty> getProperties()
+ {
+ return properties;
+ }
+
+ public void setProperties(ArrayList<SchemaProperty> properties)
+ {
+ this.properties = properties;
+ }
+
+ public ArrayList<SchemaMethod> getMethods()
+ {
+ return methods;
+ }
+
+ public void setMethods(ArrayList<SchemaMethod> methods)
+ {
+ this.methods = methods;
+ }
+
+ public ArrayList<SchemaStatistic> getStatistics()
+ {
+ return statistics;
+ }
+
+ public void setStatistics(ArrayList<SchemaStatistic> statistics)
+ {
+ this.statistics = statistics;
+ }
+
+ public ArrayList<SchemaArgument> getArguments()
+ {
+ return arguments;
+ }
+
+ public void setArguments(ArrayList<SchemaArgument> arguments)
+ {
+ this.arguments = arguments;
+ }
+
+ public ClassKey getClassKey()
+ {
+ return classKey;
+ }
+
+ public void setClassKey(ClassKey classKey)
+ {
+ this.classKey = classKey;
+ }
+}
diff --git a/java/management/console/src/main/java/org/apache/qpid/console/SchemaMethod.java b/java/management/console/src/main/java/org/apache/qpid/console/SchemaMethod.java
new file mode 100644
index 0000000000..1c20ae55bb
--- /dev/null
+++ b/java/management/console/src/main/java/org/apache/qpid/console/SchemaMethod.java
@@ -0,0 +1,125 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.console;//
+
+import java.util.ArrayList;
+import java.util.Map;
+
+import org.apache.qpid.transport.codec.*;
+
+public class SchemaMethod
+{
+ public ArrayList<SchemaArgument> Arguments = new ArrayList<SchemaArgument>();
+ private int m_ArgCount;
+ private int m_BidirectionalArgCount;
+ private String m_Description;
+ private int m_InputArgCount;
+ private String m_Name;
+ private int m_OutputArgCount;
+
+ public SchemaMethod(Decoder dec)
+ {
+ Map<String, Object> map = dec.readMap();
+ setName((String) map.get("name"));
+ setArgCount((Integer) map.get("argCount"));
+ if (map.containsKey("desc"))
+ {
+ setDescription((String) map.get("desc"));
+ }
+ for (int x = 0; x < getArgCount(); x++)
+ {
+ SchemaArgument arg = new SchemaArgument(dec, true);
+ Arguments.add(arg);
+ if (arg.isInput())
+ {
+ setInputArgCount(getInputArgCount() + 1);
+ }
+ if (arg.isOutput())
+ {
+ setOutputArgCount(getOutputArgCount() + 1);
+ }
+ if (arg.isBidirectional())
+ {
+ setBidirectionalArgCount(getBidirectionalArgCount() + 1);
+ }
+ }
+ }
+
+ public final int getArgCount()
+ {
+ return m_ArgCount;
+ }
+
+ public final int getBidirectionalArgCount()
+ {
+ return m_BidirectionalArgCount;
+ }
+
+ public final String getDescription()
+ {
+ return m_Description;
+ }
+
+ public final int getInputArgCount()
+ {
+ return m_InputArgCount;
+ }
+
+ public final String getName()
+ {
+ return m_Name;
+ }
+
+ public final int getOutputArgCount()
+ {
+ return m_OutputArgCount;
+ }
+
+ public final void setArgCount(int value)
+ {
+ m_ArgCount = value;
+ }
+
+ public final void setBidirectionalArgCount(int value)
+ {
+ m_BidirectionalArgCount = value;
+ }
+
+ public final void setDescription(String value)
+ {
+ m_Description = value;
+ }
+
+ public final void setInputArgCount(int value)
+ {
+ m_InputArgCount = value;
+ }
+
+ public final void setName(String value)
+ {
+ m_Name = value;
+ }
+
+ public final void setOutputArgCount(int value)
+ {
+ m_OutputArgCount = value;
+ }
+} \ No newline at end of file
diff --git a/java/management/console/src/main/java/org/apache/qpid/console/SchemaProperty.java b/java/management/console/src/main/java/org/apache/qpid/console/SchemaProperty.java
new file mode 100644
index 0000000000..8e278ff70d
--- /dev/null
+++ b/java/management/console/src/main/java/org/apache/qpid/console/SchemaProperty.java
@@ -0,0 +1,81 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.console;
+
+import java.util.Map;
+
+import org.apache.qpid.transport.codec.*;
+
+public class SchemaProperty extends SchemaVariable
+{
+ private int access;
+ private boolean index;
+ private boolean optional;
+
+ public SchemaProperty(Decoder dec)
+ {
+ Map<String, Object> map = dec.readMap();
+ super.populateData(map);
+ setName((String) map.get("name"));
+ if (map.containsKey("optional"))
+ {
+ setOptional((Integer) map.get("optional") != 0);
+ }
+ if (map.containsKey("index"))
+ {
+ setIndex((Integer) map.get("index") != 0);
+ }
+ if (map.containsKey("access"))
+ {
+ setAccess((Integer) map.get("access"));
+ }
+ }
+
+ public int getAccess()
+ {
+ return access;
+ }
+
+ public boolean getIndex()
+ {
+ return index;
+ }
+
+ public boolean getOptional()
+ {
+ return optional;
+ }
+
+ public void setAccess(int value)
+ {
+ access = value;
+ }
+
+ public void setIndex(boolean value)
+ {
+ index = value;
+ }
+
+ public void setOptional(boolean value)
+ {
+ optional = value;
+ }
+} \ No newline at end of file
diff --git a/java/management/console/src/main/java/org/apache/qpid/console/SchemaStatistic.java b/java/management/console/src/main/java/org/apache/qpid/console/SchemaStatistic.java
new file mode 100644
index 0000000000..18bce86423
--- /dev/null
+++ b/java/management/console/src/main/java/org/apache/qpid/console/SchemaStatistic.java
@@ -0,0 +1,88 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.console;//
+
+import java.util.Map;
+
+import org.apache.qpid.transport.codec.*;
+
+public class SchemaStatistic
+{
+ private String description;
+ private String name;
+ private short type;
+ private String unit;
+
+ public SchemaStatistic(Decoder dec)
+ {
+ Map<String, Object> map = dec.readMap();
+ setName((String) map.get("name"));
+ setType(Short.parseShort("" + map.get("type")));
+ if (map.containsKey("unit"))
+ {
+ setUnit((String) map.get("unit"));
+ }
+ if (map.containsKey("description"))
+ {
+ setDescription((String) map.get("description"));
+ }
+ }
+
+ public String getDescription()
+ {
+ return description;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public short getType()
+ {
+ return type;
+ }
+
+ public String getUnit()
+ {
+ return unit;
+ }
+
+ public void setDescription(String value)
+ {
+ description = value;
+ }
+
+ public void setName(String value)
+ {
+ name = value;
+ }
+
+ public void setType(short value)
+ {
+ type = value;
+ }
+
+ public void setUnit(String value)
+ {
+ unit = value;
+ }
+} \ No newline at end of file
diff --git a/java/management/console/src/main/java/org/apache/qpid/console/SchemaVariable.java b/java/management/console/src/main/java/org/apache/qpid/console/SchemaVariable.java
new file mode 100644
index 0000000000..483a17d0de
--- /dev/null
+++ b/java/management/console/src/main/java/org/apache/qpid/console/SchemaVariable.java
@@ -0,0 +1,185 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.console;
+
+import java.util.Map;
+
+public abstract class SchemaVariable
+{
+ private String defaultVariable;
+ private String description;
+ private Integer max;
+ private Integer maxLength;
+ private Integer min;
+ private String name;
+ private String refClass;
+ private String refPackage;
+ private short type;
+ private String unit;
+
+ public SchemaVariable()
+ {
+ }
+
+ public String getDefault()
+ {
+ return defaultVariable;
+ }
+
+ public String getDescription()
+ {
+ return description;
+ }
+
+ public Integer getMax()
+ {
+ return max;
+ }
+
+ public Integer getMaxLength()
+ {
+ return maxLength;
+ }
+
+ public Integer getMin()
+ {
+ return min;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public String getRefClass()
+ {
+ return refClass;
+ }
+
+ public String getRefPackage()
+ {
+ return refPackage;
+ }
+
+ public short getType()
+ {
+ return type;
+ }
+
+ public String getUnit()
+ {
+ return unit;
+ }
+
+ protected void populateData(Map<String, Object> map)
+ {
+ if (map.containsKey("name"))
+ {
+ setName((String) map.get("name"));
+ }
+ if (map.containsKey("type"))
+ {
+ setType(Short.parseShort(("" + map.get("type"))));
+ }
+ if (map.containsKey("unit"))
+ {
+ setUnit((String) map.get("unit"));
+ }
+ if (map.containsKey("min"))
+ {
+ setMin((Integer) map.get("min"));
+ }
+ if (map.containsKey("max"))
+ {
+ setMax((Integer) map.get("max"));
+ }
+ if (map.containsKey("maxlen"))
+ {
+ setMaxLength((Integer) map.get("maxlen"));
+ }
+ if (map.containsKey("description"))
+ {
+ setDescription((String) map.get("description"));
+ }
+ if (map.containsKey("refClass"))
+ {
+ setRefClass((String) map.get("refClass"));
+ }
+ if (map.containsKey("refPackage"))
+ {
+ setRefPackage((String) map.get("refPackage"));
+ }
+ if (map.containsKey("Default"))
+ {
+ setDefault((String) map.get("default"));
+ }
+ }
+
+ public void setDefault(String value)
+ {
+ defaultVariable = value;
+ }
+
+ public void setDescription(String value)
+ {
+ description = value;
+ }
+
+ public void setMax(Integer value)
+ {
+ max = value;
+ }
+
+ public void setMaxLength(Integer value)
+ {
+ maxLength = value;
+ }
+
+ public void setMin(Integer value)
+ {
+ min = value;
+ }
+
+ public void setName(String value)
+ {
+ name = value;
+ }
+
+ public void setRefClass(String value)
+ {
+ refClass = value;
+ }
+
+ public void setRefPackage(String value)
+ {
+ refPackage = value;
+ }
+
+ public void setType(short value)
+ {
+ type = value;
+ }
+
+ public void setUnit(String value)
+ {
+ unit = value;
+ }
+} \ No newline at end of file
diff --git a/java/management/console/src/main/java/org/apache/qpid/console/SequenceManager.java b/java/management/console/src/main/java/org/apache/qpid/console/SequenceManager.java
new file mode 100644
index 0000000000..4c5fcc7355
--- /dev/null
+++ b/java/management/console/src/main/java/org/apache/qpid/console/SequenceManager.java
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.console;
+
+import java.util.HashMap;
+
+public class SequenceManager
+{
+ private long sequence = 0;
+ private HashMap<Long, Object> pending = new HashMap<Long, Object>();
+ private Object lockObject = new Object();
+
+ public SequenceManager()
+ {
+ }
+
+ public Object release(long seq)
+ {
+ Object returnValue = null;
+ synchronized (lockObject)
+ {
+ returnValue = pending.get(seq);
+ pending.remove(seq);
+ }
+ return returnValue;
+ }
+
+ public long reserve(Object data)
+ {
+ long returnValue = 0;
+ synchronized (lockObject)
+ {
+ returnValue = sequence;
+ sequence += 1;
+ pending.put(returnValue, data);
+ }
+ return returnValue;
+ }
+} \ No newline at end of file
diff --git a/java/management/console/src/main/java/org/apache/qpid/console/Session.java b/java/management/console/src/main/java/org/apache/qpid/console/Session.java
new file mode 100644
index 0000000000..822f215f4d
--- /dev/null
+++ b/java/management/console/src/main/java/org/apache/qpid/console/Session.java
@@ -0,0 +1,980 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.console;//
+
+import java.lang.reflect.Constructor;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import javax.jms.Message;
+
+import org.apache.qpid.transport.codec.BBDecoder;
+import org.apache.qpid.transport.codec.BBEncoder;
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Session
+{
+ private static Logger log = LoggerFactory.getLogger(Session.class);
+ public static int CONTEXT_SYNC = 1;
+ public static int CONTEXT_STARTUP = 2;
+ public static int CONTEXT_MULTIGET = 3;
+ public static int DEFAULT_GET_WAIT_TIME = 60000;
+ public boolean recieveObjects = true;
+ public boolean recieveEvents = true;
+ public boolean recieveHeartbeat = true;
+ public boolean userBindings = false;
+ public Console console;
+ protected HashMap<String, HashMap<String, SchemaClass>> packages = new HashMap<String, HashMap<String, SchemaClass>>();
+ protected ArrayList<Broker> brokers = new ArrayList<Broker>();
+ protected SequenceManager sequenceManager = new SequenceManager();
+ protected Object lockObject = new Object();
+ protected ArrayList<Long> syncSequenceList = new ArrayList<Long>();
+ protected ArrayList<QMFObject> getResult;
+ protected Object syncResult;
+
+ public Session()
+ {
+ }
+
+ public Session(Console console)
+ {
+ this.console = console;
+ }
+
+ public void addBroker(String url)
+ {
+ Broker broker = new Broker(this, url);
+ brokers.add(broker);
+ java.util.HashMap<String, Object> args = new java.util.HashMap<String, Object>();
+ args.put("_class", "agent");
+ args.put("_broker", broker);
+ this.getObjects(args);
+ }
+
+ public ArrayList<String> bindingKeys()
+ {
+ ArrayList<String> bindings = new ArrayList<String>();
+ bindings.add("schema.#");
+ if (recieveObjects & recieveEvents & recieveHeartbeat & !userBindings)
+ {
+ bindings.add("console.#");
+ } else
+ {
+ if (recieveObjects & !userBindings)
+ {
+ bindings.add("console.obj.#");
+ } else
+ {
+ bindings.add("console.obj.*.*.org.apache.qpid.broker.agent");
+ }
+ if (recieveEvents)
+ {
+ bindings.add("console.event.#");
+ }
+ if (recieveHeartbeat)
+ {
+ bindings.add("console.heartbeat.#");
+ }
+ }
+ return bindings;
+ }
+
+ public void close()
+ {
+ for (Broker broker : brokers.toArray(new Broker[0]))
+ {
+ this.removeBroker(broker);
+ }
+ }
+
+ protected QMFObject createQMFObject(SchemaClass schema,
+ boolean hasProperties, boolean hasStats, boolean isManaged)
+ {
+ Class realClass = QMFObject.class;
+ if (console != null)
+ {
+ realClass = console.typeMapping(schema.getKey());
+ }
+ Class[] types = new Class[]
+ { Session.class, SchemaClass.class, boolean.class, boolean.class,
+ boolean.class };
+ Object[] args = new Object[]
+ { this, schema, hasProperties, hasStats, isManaged };
+ try
+ {
+ Constructor ci = realClass.getConstructor(types);
+ return (QMFObject) ci.newInstance(args);
+ } catch (Exception e)
+ {
+ throw new ConsoleException(e);
+ }
+ }
+
+ protected QMFObject createQMFObject(SchemaClass schema, Decoder dec,
+ boolean hasProperties, boolean hasStats, boolean isManaged)
+ {
+ Class realClass = QMFObject.class;
+ if (console != null)
+ {
+ realClass = console.typeMapping(schema.getKey());
+ }
+ Class[] types = new Class[]
+ { Session.class, SchemaClass.class, Decoder.class, boolean.class,
+ boolean.class, boolean.class };
+ Object[] args = new Object[]
+ { this, schema, dec, hasProperties, hasStats, isManaged };
+ try
+ {
+ log.debug("" + realClass);
+ Constructor ci = realClass.getConstructor(types);
+ return (QMFObject) ci.newInstance(args);
+ } catch (Exception e)
+ {
+ throw new ConsoleException(e);
+ }
+ }
+
+ public Object decodeValue(Decoder dec, short type)
+ {
+ switch (type)
+ {
+ case 1: // U8
+ return dec.readUint8();
+ case 2: // U16
+ return dec.readUint16();
+ case 3: // U32
+ return dec.readUint32();
+ case 4: // U64
+ return dec.readUint64();
+ case 6: // SSTR
+ return dec.readStr8();
+ case 7: // LSTR
+ return dec.readStr16();
+ case 8: // ABSTIME
+ return dec.readDatetime();
+ case 9: // DELTATIME
+ return dec.readUint32();
+ case 10: // ref
+ return new ObjectID(dec);
+ case 11: // bool
+ return dec.readUint8() != 0;
+ case 12: // float
+ return dec.readFloat();
+ case 13: // double
+ return dec.readDouble();
+ case 14: // UUID
+ return dec.readUuid();
+ case 15: // Ftable
+ return dec.readMap();
+ case 16: // int8
+ return dec.readInt8();
+ case 17: // int16
+ return dec.readInt16();
+ case 18: // int32
+ return dec.readInt32();
+ case 19: // int64
+ return dec.readInt64();
+ case 20: // Object
+ // Peek into the inner type code, make sure
+ // it is actually an object
+ Object returnValue = null;
+ short innerTypeCode = dec.readUint8();
+ if (innerTypeCode != 20)
+ {
+ returnValue = this.decodeValue(dec, innerTypeCode);
+ } else
+ {
+ ClassKey classKey = new ClassKey(dec);
+ synchronized (lockObject)
+ {
+ SchemaClass sClass = getSchema(classKey);
+ if (sClass != null)
+ {
+ returnValue = this.createQMFObject(sClass, dec, true,
+ true, false);
+ }
+ }
+ }
+ return returnValue;
+ case 21: // List
+ BBDecoder lDec = new BBDecoder();
+ lDec.init(ByteBuffer.wrap(dec.readVbin32()));
+ long count = lDec.readUint32();
+ ArrayList<Object> newList = new ArrayList<Object>();
+ while (count > 0)
+ {
+ short innerType = lDec.readUint8();
+ newList.add(this.decodeValue(lDec, innerType));
+ count -= 1;
+ }
+ return newList;
+ case 22: // Array
+ BBDecoder aDec = new BBDecoder();
+ aDec.init(ByteBuffer.wrap(dec.readVbin32()));
+ long cnt = aDec.readUint32();
+ short innerType = aDec.readUint8();
+ ArrayList<Object> aList = new ArrayList<Object>();
+ while (cnt > 0)
+ {
+ aList.add(this.decodeValue(aDec, innerType));
+ cnt -= 1;
+ }
+ return aList;
+ default:
+ throw new ConsoleException(String.format("Invalid Type Code: %s",
+ type));
+ }
+ }
+
+ public void encodeValue(Encoder enc, short type, Object val)
+ {
+ try
+ {
+ switch (type)
+ {
+ case 1: // U8
+ enc.writeUint8(((Short) val).shortValue());
+ break;
+ case 2: // U16
+ enc.writeUint16(((Integer) val).intValue());
+ break;
+ case 3: // U32
+ enc.writeUint32(((Integer) val).longValue());
+ break;
+ case 4: // U64
+ enc.writeUint64(((Long) val).longValue());
+ break;
+ case 6: // SSTR
+ enc.writeStr8((String) val);
+ break;
+ case 7: // LSTR
+ enc.writeStr16((String) val);
+ break;
+ case 8: // ABSTIME
+ enc.writeDatetime(((Long) val).longValue());
+ break;
+ case 9: // DELTATIME
+ enc.writeUint32(((Long) val).longValue());
+ break;
+ case 10: // ref
+ ((ObjectID) val).encode(enc);
+ break;
+ case 11:
+ if (((Boolean) val).booleanValue())
+ {
+ enc.writeUint8((short) 1);
+ } else
+ {
+ enc.writeUint8((short) 0);
+ }
+ break;
+ case 12: // FLOAT
+ enc.writeFloat(((Float) val).floatValue());
+ break;
+ case 13: // DOUBLE
+ enc.writeDouble(((Double) val).doubleValue());
+ break;
+ case 14: // UUID
+ enc.writeUuid((UUID) val);
+ break;
+ case 15: // Ftable
+ enc.writeMap((HashMap) val);
+ break;
+ case 16: // int8
+ enc.writeInt8((Byte) val);
+ break;
+ case 17: // int16
+ enc.writeInt16((Short) val);
+ break;
+ case 18: // int32
+ enc.writeInt32((Integer) val);
+ break;
+ case 19: // int64
+ enc.writeInt64((Long) val);
+ break;
+ case 20: // Object
+ // Check that the object has a session, if not
+ // take ownership of it
+ QMFObject qObj = (QMFObject) val;
+ if (qObj.getSession() == null)
+ {
+ qObj.setSession(this);
+ }
+ qObj.encode(enc);
+ break;
+ case 21: // List
+ ArrayList<Object> items = (ArrayList<Object>) val;
+ BBEncoder lEnc = new BBEncoder(1);
+ lEnc.init();
+ lEnc.writeUint32(items.size());
+ for (Object obj : items)
+ {
+ short innerType = Util.qmfType(obj);
+ lEnc.writeUint8(innerType);
+ this.encodeValue(lEnc, innerType, obj);
+ }
+ enc.writeVbin32(lEnc.segment().array());
+ break;
+ case 22: // Array
+ ArrayList<Object> aItems = (ArrayList<Object>) val;
+ BBEncoder aEnc = new BBEncoder(1);
+ aEnc.init();
+ long aCount = aItems.size();
+ aEnc.writeUint32(aCount);
+ if (aCount > 0)
+ {
+ Object anObj = aItems.get(0);
+ short innerType = Util.qmfType(anObj);
+ aEnc.writeUint8(innerType);
+ for (Object obj : aItems)
+ {
+ this.encodeValue(aEnc, innerType, obj);
+ }
+ }
+ enc.writeVbin32(aEnc.segment().array());
+ break;
+ default:
+ throw new ConsoleException(String.format(
+ "Invalid Type Code: %s", type));
+ }
+ } catch (ClassCastException e)
+ {
+ String msg = String.format(
+ "Class cast exception for typecode %s, type %s ", type, val
+ .getClass());
+ log.error(msg);
+ throw new ConsoleException(msg + type, e);
+ }
+ }
+
+ public Broker getBroker(long BrokerBank)
+ {
+ Broker returnValue = null;
+ for (Broker broker : brokers)
+ {
+ if (broker.brokerBank() == BrokerBank)
+ {
+ returnValue = broker;
+ break;
+ }
+ }
+ return returnValue;
+ }
+
+ public ArrayList<ClassKey> getClasses(String packageName)
+ {
+ ArrayList<ClassKey> returnValue = new ArrayList<ClassKey>();
+ this.waitForStable();
+ if (packages.containsKey(packageName))
+ {
+ for (SchemaClass sClass : packages.get(packageName).values())
+ {
+ returnValue.add(sClass.getKey());
+ }
+ }
+ return returnValue;
+ }
+
+ public ArrayList<QMFObject> getObjects(
+ java.util.HashMap<String, Object> args)
+ {
+ ArrayList<Broker> brokerList = null;
+ ArrayList<Agent> agentList = new ArrayList<Agent>();
+ if (args.containsKey("_broker"))
+ {
+ brokerList = new ArrayList<Broker>();
+ brokerList.add((Broker) args.get("_broker"));
+ } else
+ {
+ brokerList = this.brokers;
+ }
+ for (Broker broker : brokerList)
+ {
+ broker.waitForStable();
+ }
+ if (args.containsKey("_agent"))
+ {
+ Agent agent = (Agent) args.get("_agent");
+ if (brokerList.contains(agent.getBroker()))
+ {
+ agentList.add(agent);
+ } else
+ {
+ throw new ConsoleException(
+ "Agent is not managed by this console or the supplied broker");
+ }
+ } else
+ {
+ if (args.containsKey("_objectId"))
+ {
+ ObjectID oid = (ObjectID) args.get("_objectId");
+ for (Broker broker : brokers)
+ {
+ for (Agent agent : broker.Agents.values())
+ {
+ if ((agent.getAgentBank() == oid.agentBank())
+ && (agent.getBrokerBank() == oid.brokerBank()))
+ {
+ agentList.add(agent);
+ }
+ }
+ }
+ } else
+ {
+ for (Broker broker : brokerList)
+ {
+ for (Agent agent : broker.Agents.values())
+ {
+ if (agent.getBroker().isConnected())
+ {
+ agentList.add(agent);
+ }
+ }
+ }
+ }
+ }
+ getResult = new ArrayList<QMFObject>();
+ if (agentList.size() > 0)
+ {
+ // FIXME Add a bunch of other suff too
+ for (Agent agent : agentList)
+ {
+ HashMap<String, Object> getParameters = new HashMap<String, Object>();
+ Broker broker = agent.getBroker();
+ long seq = -1;
+ synchronized (lockObject)
+ {
+ seq = sequenceManager.reserve(Session.CONTEXT_MULTIGET);
+ syncSequenceList.add(seq);
+ }
+ String packageName = (String) args.get("_package");
+ String className = (String) args.get("_class");
+ ClassKey key = (ClassKey) args.get("_key");
+ Object sClass = args.get("_schema");
+ Object oid = args.get("_objectID");
+ long[] hash = (long[]) args.get("_hash");
+ if ((className == null) && (oid == null) && (oid == null))
+ {
+ throw new ConsoleException(
+ "No class supplied, use '_schema', '_key', '_class', or '_objectId' argument");
+ }
+ if (oid != null)
+ {
+ getParameters.put("_objectID", oid);
+ } else
+ {
+ if (sClass != null)
+ {
+ key = (key != null) ? key : ((SchemaClass) sClass)
+ .getKey();
+ }
+ if (key != null)
+ {
+ className = (className != null) ? className : key
+ .getClassName();
+ packageName = (packageName != null) ? packageName : key
+ .getPackageName();
+ hash = (hash != null) ? hash : key.getHash();
+ }
+ if (packageName != null)
+ {
+ getParameters.put("_package", packageName);
+ }
+ if (className != null)
+ {
+ getParameters.put("_class", className);
+ }
+ if (hash != null)
+ {
+ getParameters.put("_hash", hash);
+ }
+ for (java.util.Map.Entry<String, Object> pair : args
+ .entrySet())
+ {
+ if (!pair.getKey().startsWith("_"))
+ {
+ getParameters.put(pair.getKey(), pair.getValue());
+ }
+ }
+ }
+ Encoder enc = broker.createEncoder('G', seq);
+ enc.writeMap(getParameters);
+ String routingKey = agent.routingCode();
+ Message msg = broker.createMessage(enc);
+ log.debug("Get Object Keys: ");
+ for (String pKey : getParameters.keySet())
+ {
+ log.debug(String.format("\tKey: '%s' Value: '%s'", pKey,
+ getParameters.get(pKey)));
+ }
+ broker.send(msg, routingKey);
+ }
+ int waittime = DEFAULT_GET_WAIT_TIME;
+ boolean timeout = false;
+ if (args.containsKey("_timeout"))
+ {
+ waittime = (Integer) args.get("_timeout");
+ }
+ long start = System.currentTimeMillis();
+ synchronized (lockObject)
+ {
+ // FIXME ERROR
+ while (syncSequenceList.size() > 0)
+ {
+ try
+ {
+ lockObject.wait(waittime);
+ } catch (InterruptedException e)
+ {
+ throw new ConsoleException(e);
+ }
+ long duration = System.currentTimeMillis() - start;
+ if (duration > waittime)
+ {
+ for (long pendingSeq : syncSequenceList)
+ {
+ sequenceManager.release(pendingSeq);
+ }
+ syncSequenceList.clear();
+ timeout = true;
+ }
+ }
+ }
+ // FIXME Add the error logic
+ if ((getResult.isEmpty()) && timeout)
+ {
+ throw new ConsoleException("Get Request timed out");
+ }
+ }
+ return getResult;
+ }
+
+ public ArrayList<String> getPackages()
+ {
+ this.waitForStable();
+ ArrayList<String> returnValue = new ArrayList<String>();
+ for (String name : packages.keySet())
+ {
+ returnValue.add(name);
+ }
+ return returnValue;
+ }
+
+ public SchemaClass getSchema(ClassKey key)
+ {
+ return getSchema(key, true);
+ }
+
+ protected SchemaClass getSchema(ClassKey key, boolean waitForStable)
+ {
+ if (waitForStable)
+ {
+ this.waitForStable();
+ }
+ SchemaClass returnValue = null;
+ returnValue = packages.get(key.getPackageName())
+ .get(key.getKeyString());
+ return returnValue;
+ }
+
+ public void handleAgentRemoved(Agent agent)
+ {
+ if (console != null)
+ {
+ console.agentRemoved(agent);
+ }
+ }
+
+ public void handleBrokerConnect(Broker broker)
+ {
+ if (console != null)
+ {
+ console.brokerConnected(broker);
+ }
+ }
+
+ public void handleBrokerDisconnect(Broker broker)
+ {
+ if (console != null)
+ {
+ console.brokerDisconnected(broker);
+ }
+ }
+
+ public void handleBrokerResponse(Broker broker, Decoder decoder,
+ long sequence)
+ {
+ if (console != null)
+ {
+ console.brokerInformation(broker);
+ }
+ long seq = sequenceManager.reserve(CONTEXT_STARTUP);
+ Encoder encoder = broker.createEncoder('P', seq);
+ broker.send(encoder);
+ }
+
+ public void handleClassIndicator(Broker broker, Decoder decoder,
+ long sequence)
+ {
+ short kind = decoder.readUint8();
+ ClassKey classKey = new ClassKey(decoder);
+ boolean unknown = false;
+ synchronized (lockObject)
+ {
+ if (packages.containsKey(classKey.getPackageName()))
+ {
+ if (!packages.get(classKey.getPackageName()).containsKey(
+ classKey.getKeyString()))
+ {
+ unknown = true;
+ }
+ }
+ }
+ if (unknown)
+ {
+ broker.incrementOutstanding();
+ long seq = sequenceManager.reserve(Session.CONTEXT_STARTUP);
+ Encoder enc = broker.createEncoder('S', seq);
+ classKey.encode(enc);
+ broker.send(enc);
+ }
+ }
+
+ public void handleCommandComplete(Broker broker, Decoder decoder,
+ long sequence)
+ {
+ long code = decoder.readUint32();
+ String text = decoder.readStr8();
+ Object context = this.sequenceManager.release(sequence);
+ if (context.equals(CONTEXT_STARTUP))
+ {
+ broker.decrementOutstanding();
+ } else
+ {
+ if ((context.equals(CONTEXT_SYNC)) & broker.getSyncInFlight())
+ {
+ broker.setSyncInFlight(false);
+ } else
+ {
+ if (context.equals(CONTEXT_MULTIGET)
+ && syncSequenceList.contains(sequence))
+ {
+ synchronized (lockObject)
+ {
+ syncSequenceList.remove(sequence);
+ if (syncSequenceList.isEmpty())
+ {
+ lockObject.notifyAll();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void handleContentIndicator(Broker broker, Decoder decoder,
+ long sequence, boolean hasProperties, boolean hasStatistics)
+ {
+ ClassKey key = new ClassKey(decoder);
+ SchemaClass sClass = null;
+ ;
+ synchronized (lockObject)
+ {
+ sClass = getSchema(key, false);
+ }
+ if (sClass != null)
+ {
+ QMFObject obj = this.createQMFObject(sClass, decoder,
+ hasProperties, hasStatistics, true);
+ if (key.getPackageName().equals("org.apache.qpid.broker")
+ && key.getClassName().equals("agent") && hasProperties)
+ {
+ broker.updateAgent(obj);
+ }
+ synchronized (lockObject)
+ {
+ if (syncSequenceList.contains(sequence))
+ {
+ if (!obj.isDeleted() && this.selectMatch(obj))
+ {
+ getResult.add(obj);
+ }
+ }
+ }
+ if (console != null)
+ {
+ if (hasProperties)
+ {
+ console.objectProperties(broker, obj);
+ }
+ if (hasStatistics)
+ {
+ console.objectStatistics(broker, obj);
+ }
+ }
+ }
+ }
+
+ public void handleEventIndicator(Broker broker, Decoder decoder,
+ long sequence)
+ {
+ if (console != null)
+ {
+ QMFEvent newEvent = new QMFEvent(this, decoder);
+ console.eventRecieved(broker, newEvent);
+ }
+ }
+
+ public void handleHeartbeatIndicator(Broker broker, Decoder decoder,
+ long sequence, Message msg)
+ {
+ if (console != null)
+ {
+ long brokerBank = 1;
+ long agentBank = 0;
+ try
+ {
+ // FIXME HOW DO WE GET THE ROUTING KEY
+ // String routingKey = msg.DeliveryProperties.getRoutingKey();
+ String routingKey = null;
+ if (routingKey != null)
+ {
+ agentBank = Agent.getBrokerBank(routingKey);
+ brokerBank = Agent.getBrokerBank(routingKey);
+ }
+ } catch (Throwable e)
+ {
+ log.warn("Internal QPID error", e);
+ }
+ String agentKey = Agent.AgentKey(agentBank, brokerBank);
+ long timestamp = decoder.readUint64();
+ if (broker.Agents.containsKey(agentKey))
+ {
+ Agent agent = broker.Agents.get(agentKey);
+ console.hearbeatRecieved(agent, timestamp);
+ }
+ }
+ }
+
+ public void handleMethodResponse(Broker broker, Decoder decoder,
+ long sequence)
+ {
+ long code = decoder.readUint32();
+ String text = decoder.readStr16();
+ java.util.HashMap<String, Object> outArgs = new java.util.HashMap<String, Object>();
+ Object obj = sequenceManager.release(sequence);
+ if (obj == null)
+ {
+ return;
+ }
+ Object[] pair = (Object[]) obj;
+ if (code == 0)
+ {
+ for (SchemaArgument arg : ((SchemaMethod) pair[0]).Arguments)
+ {
+ if (arg.isOutput())
+ {
+ outArgs.put(arg.getName(), this.decodeValue(decoder, arg
+ .getType()));
+ }
+ }
+ }
+ MethodResult result = new MethodResult(code, text, outArgs);
+ if ((Boolean) pair[1])
+ {
+ this.syncResult = result;
+ broker.setSyncInFlight(false);
+ }
+ if (console != null)
+ {
+ console.methodResponse(broker, sequence, result);
+ }
+ }
+
+ // Callback Methods
+ public void handleNewAgent(Agent agent)
+ {
+ if (console != null)
+ {
+ console.newAgent(agent);
+ }
+ }
+
+ public void handlePackageIndicator(Broker broker, Decoder decoder,
+ long sequence)
+ {
+ String packageName = decoder.readStr8();
+ boolean notify = false;
+ if (!packages.containsKey(packageName))
+ {
+ synchronized (lockObject)
+ {
+ packages.put(packageName,
+ new java.util.HashMap<String, SchemaClass>());
+ notify = true;
+ }
+ }
+ if (notify && console != null)
+ {
+ console.newPackage(packageName);
+ }
+ broker.incrementOutstanding();
+ long seq = sequenceManager.reserve(Session.CONTEXT_STARTUP);
+ Encoder enc = broker.createEncoder('Q', seq);
+ enc.writeStr8(packageName);
+ broker.send(enc);
+ }
+
+ public void handleSchemaResponse(Broker broker, Decoder decoder,
+ long sequence)
+ {
+ short kind = decoder.readUint8();
+ ClassKey classKey = new ClassKey(decoder);
+ SchemaClass sClass = new SchemaClass(kind, classKey, decoder, this);
+ synchronized (lockObject)
+ {
+ java.util.HashMap<String, SchemaClass> classMappings = packages
+ .get(sClass.getPackageName());
+ classMappings.remove(sClass.getClassKeyString());
+ classMappings.put(sClass.getClassKeyString(), sClass);
+ log.debug(classKey.toString());
+ }
+ sequenceManager.release(sequence);
+ broker.decrementOutstanding();
+ if (console != null)
+ {
+ this.console.newClass(kind, classKey);
+ }
+ }
+
+ public MethodResult invokeMethod(QMFObject obj, String name,
+ List<Object> args, boolean synchronous, int timeToLive)
+ {
+ Broker aBroker = this.getBroker(obj.brokerBank());
+ long seq = this.sendMethodRequest(obj, aBroker, name, args,
+ synchronous, timeToLive);
+ if (seq != 0)
+ {
+ if (!synchronous)
+ {
+ return null;
+ }
+ try
+ {
+ aBroker.waitForSync(timeToLive);
+ } catch (Throwable e)
+ {
+ sequenceManager.release(seq);
+ throw new ConsoleException(e);
+ }
+ // FIXME missing error logic in the broker
+ return (MethodResult) syncResult;
+ }
+ return null;
+ }
+
+ public QMFObject makeObject(ClassKey key)
+ {
+ SchemaClass sClass = this.getSchema(key);
+ if (sClass == null)
+ {
+ throw new ConsoleException("No schema found for class "
+ + key.toString());
+ }
+ return this.createQMFObject(sClass, true, true, false);
+ }
+
+ public QMFObject makeObject(String keyString)
+ {
+ return this.makeObject(new ClassKey(keyString));
+ }
+
+ public void removeBroker(Broker broker)
+ {
+ if (brokers.contains(broker))
+ {
+ brokers.remove(broker);
+ }
+ broker.shutdown();
+ }
+
+ public boolean selectMatch(QMFObject obj)
+ {
+ return true;
+ }
+
+ protected long sendMethodRequest(QMFObject obj, Broker aBroker,
+ String name, List<Object> args, boolean synchronous, int timeToLive)
+ {
+ SchemaMethod method = obj.getSchema().getMethod(name);
+ if (args == null)
+ {
+ args = new ArrayList<Object>();
+ }
+ long seq = 0;
+ if (method != null)
+ {
+ Object[] pair =
+ { method, synchronous };
+ seq = sequenceManager.reserve(pair);
+ Encoder enc = aBroker.createEncoder('M', seq);
+ obj.getObjectID().encode(enc);
+ obj.getSchema().getKey().encode(enc);
+ enc.writeStr8(name);
+ if (args.size() < method.getInputArgCount())
+ {
+ throw new ConsoleException(String.format(
+ "Incorrect number of arguments: expected %s, got %s",
+ method.getInputArgCount(), args.size()));
+ }
+ int argIndex = 0;
+ for (SchemaArgument arg : method.Arguments)
+ {
+ if (arg.isInput())
+ {
+ this.encodeValue(enc, arg.getType(), args.get(argIndex));
+ argIndex += 1;
+ }
+ }
+ Message msg = aBroker.createMessage(enc);
+ if (synchronous)
+ {
+ aBroker.setSyncInFlight(true);
+ }
+ aBroker.send(msg, obj.routingKey(), timeToLive);
+ }
+ return seq;
+ }
+
+ protected void waitForStable()
+ {
+ for (Broker broker : brokers)
+ {
+ broker.waitForStable();
+ }
+ }
+}
diff --git a/java/management/console/src/main/java/org/apache/qpid/console/Util.java b/java/management/console/src/main/java/org/apache/qpid/console/Util.java
new file mode 100644
index 0000000000..a9e4d68601
--- /dev/null
+++ b/java/management/console/src/main/java/org/apache/qpid/console/Util.java
@@ -0,0 +1,184 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.console;
+
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.UUID;
+
+public class Util
+{
+ private static HashMap<Class, Short> ENCODINGS = new HashMap<Class, Short>();
+ static
+ {
+ ENCODINGS.put(String.class, (short) 7);
+ ENCODINGS.put(Short.class, (short) 1);
+ ENCODINGS.put(Float.class, (short) 13);
+ ENCODINGS.put(QMFObject.class, (short) 20);
+ ENCODINGS.put(Integer.class, (short) 17);
+ ENCODINGS.put(Long.class, (short) 18);
+ ENCODINGS.put(ArrayList.class, (short) 21);
+ }
+
+ public static String accessName(int type)
+ {
+ switch (type)
+ {
+ // case 0: return "UNKNOWN" ;
+ case 1:
+ return "RC";
+ case 2:
+ return "RW";
+ case 3:
+ return "RO";
+ }
+ throw new ConsoleException(String.format("Invalid Access Code: %s",
+ type));
+ }
+
+ public static String byteString(byte[] bytes)
+ {
+ return new String(bytes, Charset.forName("UTF-8"));
+ }
+
+ public static Object defaultValue(short type)
+ {
+ switch (type)
+ {
+ // case 0: return "UNKNOWN" ;
+ case 1:
+ return 0;
+ case 2:
+ return 0;
+ case 3:
+ return 0l;
+ case 4:
+ return 0l;
+ case 5:
+ return false;
+ case 6:
+ return "";
+ case 7:
+ return "";
+ case 8:
+ return 0l;
+ case 9:
+ return 0l;
+ case 10:
+ return new ObjectID();
+ case 11:
+ return false;
+ case 12:
+ return 0f;
+ case 13:
+ return 0d;
+ case 14:
+ return new UUID(0, 0);
+ case 15:
+ return new HashMap<String, Object>();
+ case 16:
+ return 0;
+ case 17:
+ return 0;
+ case 18:
+ return 0l;
+ case 19:
+ return 0l;
+ case 20:
+ return null;
+ case 21:
+ return new java.util.ArrayList<Object>();
+ case 22:
+ return new java.util.ArrayList<Object>();
+ }
+ throw new ConsoleException(String.format("Invalid Type Code: %s", type));
+ }
+
+ public static short qmfType(Object obj)
+ {
+ if (ENCODINGS.containsKey(obj.getClass()))
+ {
+ return ENCODINGS.get(obj.getClass());
+ } else
+ {
+ throw new ConsoleException(String.format("Unkown Type of %s", obj
+ .getClass()));
+ }
+ }
+
+ public static String typeName(short type)
+ {
+ switch (type)
+ {
+ // case 0: return "UNKNOWN" ;
+ case 1:
+ return "uint8";
+ case 2:
+ return "uint16";
+ case 3:
+ return "uint32";
+ case 4:
+ return "uint64";
+ case 5:
+ return "bool";
+ case 6:
+ return "short-string";
+ case 7:
+ return "long-string";
+ case 8:
+ return "abs-time";
+ case 9:
+ return "delta-time";
+ case 10:
+ return "reference";
+ case 11:
+ return "boolean";
+ case 12:
+ return "float";
+ case 13:
+ return "double";
+ case 14:
+ return "uuid";
+ case 15:
+ return "field-table";
+ case 16:
+ return "int8";
+ case 17:
+ return "int16";
+ case 18:
+ return "int32";
+ case 19:
+ return "int64";
+ case 20:
+ return "object";
+ case 21:
+ return "list";
+ case 22:
+ return "array";
+ }
+ throw new ConsoleException(String.format("Invalid Type Code: %s", type));
+ }
+
+ protected Util()
+ {
+ }
+} \ No newline at end of file
diff --git a/java/management/console/src/main/java/org/apache/qpid/console/XMLUtil.java b/java/management/console/src/main/java/org/apache/qpid/console/XMLUtil.java
new file mode 100644
index 0000000000..1ab93de6a2
--- /dev/null
+++ b/java/management/console/src/main/java/org/apache/qpid/console/XMLUtil.java
@@ -0,0 +1,134 @@
+package org.apache.qpid.console;
+
+public class XMLUtil
+{
+ public static String commonAttributes(SchemaVariable var)
+ {
+ String returnString = "";
+ if (var.getDescription() != null)
+ {
+ returnString = returnString
+ + String.format(" desc='%s'", var.getDescription());
+ }
+ if (var.getRefPackage() != null)
+ {
+ returnString = returnString
+ + String.format(" refPackage='%s'", var.getRefPackage());
+ }
+ if (var.getRefClass() != null)
+ {
+ returnString = returnString
+ + String.format(" refClass='%s'", var.getRefClass());
+ }
+ if (var.getUnit() != null)
+ {
+ returnString = returnString
+ + String.format(" unit='%s'", var.getUnit());
+ }
+ if (var.getMin() != null)
+ {
+ returnString = returnString
+ + String.format(" min='%s'", var.getMin());
+ }
+ if (var.getMax() != null)
+ {
+ returnString = returnString
+ + String.format(" max='%s'", var.getMax());
+ }
+ if (var.getMaxLength() != null)
+ {
+ returnString = returnString
+ + String.format(" maxLength='%s'", var.getMaxLength());
+ }
+ return returnString;
+ }
+
+ public static String schemaXML(Session sess, String packageName)
+ {
+ String returnValue = String.format("<schema package='%s'>\n",
+ packageName);
+ for (ClassKey key : sess.getClasses(packageName))
+ {
+ SchemaClass schema = sess.getSchema(key);
+ if (schema.getKind() == 1)
+ {
+ if (schema.getSuperType() == null)
+ {
+ returnValue += String.format(
+ "\t<class name='%s' hash='%s'>\n", key
+ .getClassName(), key.getHashString());
+ } else
+ {
+ returnValue += String.format(
+ "\t<class name='%s' hash='%s' extends='%s'>\n", key
+ .getClassName(), key.getHashString(),
+ schema.getSuperType().getKeyString());
+ }
+ for (SchemaProperty prop : schema.getProperties())
+ {
+ Object[] attributes = new Object[5];
+ attributes[0] = prop.getName();
+ attributes[1] = Util.typeName(prop.getType());
+ attributes[2] = Util.accessName(prop.getAccess());
+ attributes[3] = prop.getOptional() ? "True" : "False ";
+ attributes[4] = XMLUtil.commonAttributes(prop);
+ returnValue += String
+ .format(
+ "\t\t<property name='%s' type='%s' access='%s' optional='%s'%s/>\n",
+ attributes);
+ }
+ for (SchemaMethod meth : schema.getMethods())
+ {
+ returnValue += String.format("\t\t<method name='%s'/>\n",
+ meth.getName());
+ for (SchemaArgument arg : meth.Arguments)
+ {
+ Object[] attributes = new Object[4];
+ attributes[0] = arg.getName();
+ attributes[1] = arg.getDirection();
+ attributes[2] = Util.typeName(arg.getType());
+ attributes[3] = XMLUtil.commonAttributes(arg);
+ returnValue += String
+ .format(
+ "\t\t\t<arg name='%s' dir='%s' type='%s'%s/>\n",
+ attributes);
+ }
+ returnValue += String.format("\t\t</method>\n");
+ }
+ returnValue += String.format("\t</class>\n");
+ } else
+ {
+ returnValue += String.format("\t<event name='%s' hash='%s'>\n",
+ key.getClassName(), key.getHashString());
+ for (SchemaArgument arg : schema.getArguments())
+ {
+ Object[] attributes = new Object[4];
+ attributes[0] = arg.getName();
+ attributes[1] = Util.typeName(arg.getType());
+ attributes[2] = XMLUtil.commonAttributes(arg);
+ returnValue += String.format(
+ "\t\t\t<arg name='%s' type='%s'%s/>\n", attributes);
+ }
+ returnValue += String.format("\t</event>\n");
+ }
+ }
+ returnValue += String.format("</schema>\n");
+ return returnValue;
+ }
+
+ public static String schemaXML(Session sess, String[] packageNames)
+ {
+ String returnValue = "<schemas>\n";
+ for (String pack : packageNames)
+ {
+ returnValue += XMLUtil.schemaXML(sess, pack);
+ returnValue += "\n";
+ }
+ returnValue += "</schemas>\n";
+ return returnValue;
+ }
+
+ protected XMLUtil()
+ {
+ }
+}
diff --git a/java/management/console/src/test/java/org/apache/qpid/console/ClassKeyTest.java b/java/management/console/src/test/java/org/apache/qpid/console/ClassKeyTest.java
new file mode 100644
index 0000000000..dc16aaac5b
--- /dev/null
+++ b/java/management/console/src/test/java/org/apache/qpid/console/ClassKeyTest.java
@@ -0,0 +1,39 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.console;
+
+import junit.framework.TestCase;
+
+public class ClassKeyTest extends TestCase
+{
+ public void testCreation()
+ {
+ ClassKey key = new ClassKey(
+ "some.package:Class(00000001-00000002-00000003-00000004)");
+ assertEquals("some.package", key.getPackageName());
+ assertEquals("Class", key.getClassName());
+ assertEquals("00000001-00000002-00000003-00000004", key.getHashString());
+ assertEquals(1, key.getHash()[0]);
+ assertEquals(2, key.getHash()[1]);
+ assertEquals(3, key.getHash()[2]);
+ assertEquals(4, key.getHash()[3]);
+ }
+}
diff --git a/java/management/eclipse-plugin/META-INF/MANIFEST.MF b/java/management/eclipse-plugin/META-INF/MANIFEST.MF
index a03c35c457..39b329089d 100644
--- a/java/management/eclipse-plugin/META-INF/MANIFEST.MF
+++ b/java/management/eclipse-plugin/META-INF/MANIFEST.MF
@@ -1,13 +1,22 @@
Manifest-Version: 1.0
+Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
Bundle-ManifestVersion: 2
-Bundle-Name: Qpid Management Console Plug-in
+Bundle-Name: Qpid JMX Management Console Plug-in
Bundle-SymbolicName: org.apache.qpid.management.ui; singleton:=true
-Bundle-Version: 0.1.0
+Bundle-Version: 0.6.0
Bundle-Activator: org.apache.qpid.management.ui.Activator
+Bundle-Vendor: Apache Software Foundation
Bundle-Localization: plugin
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
org.eclipse.ui.forms,
- jmxremote.sasl
+ qpid-management-common,
+ org.apache.commons.codec;bundle-version="1.3.0"
Eclipse-LazyStart: true
-Bundle-Vendor: Apache Software Foundation
+Export-Package: org.apache.qpid.management.ui,
+ org.apache.qpid.management.ui.actions,
+ org.apache.qpid.management.ui.exceptions,
+ org.apache.qpid.management.ui.jmx,
+ org.apache.qpid.management.ui.model,
+ org.apache.qpid.management.ui.sasl,
+ org.apache.qpid.management.ui.views
diff --git a/java/management/eclipse-plugin/README.txt b/java/management/eclipse-plugin/README.txt
deleted file mode 100644
index 5325bf27ec..0000000000
--- a/java/management/eclipse-plugin/README.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-
-Running the Qpid Management Console (eclipse-plugin)
-----------------------------------------------------
-
-To run the management console, set the QPIDMC_HOME environment variable to
-qpid management console root directory (e.g. C:/qpidmc)and add $QPIDMC_HOME/bin to your PATH.
-Then run the script to launch the management console-
-For Windows:
-------------
-qpidmc.bat
-qpidmc.sh (using cygwin)
-
-Unix:
------
-qpidmc.sh <operating system> <windowing system> <platform achitecture>
-eg. qpidms.sh linux motif x86
-qpidmc_motif.sh
-qpidmc_gtk.sh
-
-Apache confluence page for latest information:
-http://cwiki.apache.org/confluence/display/qpid/Qpid+Management+Console
diff --git a/java/management/eclipse-plugin/bin/qpidmc.bat b/java/management/eclipse-plugin/bin/qpidmc.bat
deleted file mode 100644
index 1f3207f043..0000000000
--- a/java/management/eclipse-plugin/bin/qpidmc.bat
+++ /dev/null
@@ -1,55 +0,0 @@
-@REM
-@REM Licensed to the Apache Software Foundation (ASF) under one
-@REM or more contributor license agreements. See the NOTICE file
-@REM distributed with this work for additional information
-@REM regarding copyright ownership. The ASF licenses this file
-@REM to you under the Apache License, Version 2.0 (the
-@REM "License"); you may not use this file except in compliance
-@REM with the License. You may obtain a copy of the License at
-@REM
-@REM http://www.apache.org/licenses/LICENSE-2.0
-@REM
-@REM Unless required by applicable law or agreed to in writing,
-@REM software distributed under the License is distributed on an
-@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-@REM KIND, either express or implied. See the License for the
-@REM specific language governing permissions and limitations
-@REM under the License.
-@REM
-
-@echo off
-REM Script to run the Qpid Management Console
-
-rem Guess QPIDMC_HOME if not defined
-set CURRENT_DIR=%cd%
-if not "%QPIDMC_HOME%" == "" goto gotHome
-set QPIDMC_HOME=%CURRENT_DIR%
-echo %QPIDMC_HOME%
-if exist "%QPIDMC_HOME%\bin\qpidmc.bat" goto okHome
-cd ..
-set QPIDMC_HOME=%cd%
-cd %CURRENT_DIR%
-:gotHome
-if exist "%QPIDMC_HOME%\bin\qpidmc.bat" goto okHome
-echo The QPIDMC_HOME environment variable is not defined correctly
-echo This environment variable is needed to run this program
-goto end
-:okHome
-
-if not "%JAVA_HOME%" == "" goto gotJavaHome
-echo The JAVA_HOME environment variable is not defined
-echo This environment variable is needed to run this program
-goto exit
-:gotJavaHome
-if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
-goto okJavaHome
-:noJavaHome
-echo The JAVA_HOME environment variable is not defined correctly
-echo This environment variable is needed to run this program.
-goto exit
-:okJavaHome
-
-rem Slurp the command line arguments. This loop allows for an unlimited number
-rem of agruments (up to the command line limit, anyway).
-
-"%JAVA_HOME%\bin\java" -Xms40m -Xmx256m -Declipse.consoleLog=false -jar %QPIDMC_HOME%\eclipse\startup.jar org.eclipse.core.launcher.Main -launcher %QPIDMC_HOME%\eclipse\eclipse -name "Qpid Management Console" -showsplash 600 -configuration "file:%QPIDMC_HOME%\configuration" -os win32 -ws win32 -arch x86
diff --git a/java/management/eclipse-plugin/bin/qpidmc.sh b/java/management/eclipse-plugin/bin/qpidmc.sh
deleted file mode 100755
index 2472545a14..0000000000
--- a/java/management/eclipse-plugin/bin/qpidmc.sh
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-if [ "$JAVA_HOME" == "" ]; then
- echo "The JAVA_HOME environment variable is not defined";
- exit 0;
-fi
-
-if [ "$QPIDMC_HOME" == "" ]; then
- echo "The QPIDMC_HOME environment variable is not defined correctly";
- exit 0;
-fi
-
-# Test if we're running on cygwin.
-cygwin=false
-if [[ "$(uname -a | fgrep Cygwin)" != "" ]]; then
- cygwin=true
-fi
-
-if $cygwin; then
- QPIDMC_HOME=$(cygpath -w $QPIDMC_HOME)
-fi
-
-os=win32
-ws=win32
-arch=x86
-
-##echo $os
-##echo $ws
-##echo $arch
-
-## If this is to be run on different platform other than windows then following parameters should be passed
-## qpidmc.sh <operating system> <windowing system> <platform achitecture>
-## eg. qpidmc.sh linux motif x86
-if [ $# -eq 3 ]; then
- os=$1
- ws=$2
- arch=$3
-fi
-
-if [ $os = "SunOS" ]; then
- os="solaris"
-elif [ $os = "Linux" ]; then
- os="linux"
-fi
-
-"$JAVA_HOME/bin/java" -Xms40m -Xmx256m -Declipse.consoleLog=false -jar $QPIDMC_HOME/eclipse/startup.jar org.eclipse.core.launcher.Main -launcher $QPIDMC_HOME/eclipse/eclipse -name "Qpid Management Console" -showsplash 600 -configuration "file:$QPIDMC_HOME/configuration" -os $os -ws $ws -arch $arch
diff --git a/java/management/eclipse-plugin/bin/qpidmc_gtk.sh b/java/management/eclipse-plugin/bin/qpidmc_gtk.sh
deleted file mode 100755
index 10b463d63b..0000000000
--- a/java/management/eclipse-plugin/bin/qpidmc_gtk.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-os=`uname | tr A-Z a-z`
-arch=`uname -p`
-
-$QPIDMC_HOME/bin/qpidmc.sh $os gtk $arch
diff --git a/java/management/eclipse-plugin/bin/qpidmc_motif.sh b/java/management/eclipse-plugin/bin/qpidmc_motif.sh
deleted file mode 100755
index f53be75d87..0000000000
--- a/java/management/eclipse-plugin/bin/qpidmc_motif.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-os=`uname | tr A-Z a-z`
-arch=`uname -p`
-
-$QPIDMC_HOME/bin/qpidmc.sh $os motif $arch
diff --git a/java/management/eclipse-plugin/build-release-common.properties b/java/management/eclipse-plugin/build-release-common.properties
new file mode 100644
index 0000000000..7ccbd750cf
--- /dev/null
+++ b/java/management/eclipse-plugin/build-release-common.properties
@@ -0,0 +1,33 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
+app.namever=jmx-management-console-${project.version}
+
+artifact.id=org.apache.qpid.management.ui
+mcplugin.version=${project.version}.0
+mcplugin.filename=${artifact.id}_${mcplugin.version}
+
+mcplugin.contents.dir=${module.classes}
+
+mcplugin.manifest=${module.manifest}
+
+jmxremote.sasl.manifest=src/main/resources/jmxremote.sasl-plugin/MANIFEST.MF
+
diff --git a/java/management/eclipse-plugin/build-release-linux-gtk-x86.properties b/java/management/eclipse-plugin/build-release-linux-gtk-x86.properties
new file mode 100644
index 0000000000..51c4bfa8d0
--- /dev/null
+++ b/java/management/eclipse-plugin/build-release-linux-gtk-x86.properties
@@ -0,0 +1,36 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
+release.name=${project.name}-${app.namever}-linux-gtk-x86
+
+release.subdir=${module.release.base}/${release.name}
+
+release.tar.gz=${module.release.base}/${release.name}.tar.gz
+
+qpidmc.ini=src/main/resources/linux-gtk-x86/qpidmc.ini
+
+qpidmc.executable=src/main/resources/linux-gtk-x86/qpidmc
+
+qpidmc.companion.library=src/main/resources/linux-gtk-x86/libcairo-swt.so
+
+rcp.libs=${management-eclipse-plugin-linux-gtk-x86.libs}
+
+rcp.configuration.dir=src/main/resources/linux-gtk-x86/Configuration
diff --git a/java/management/eclipse-plugin/build-release-linux-gtk-x86_64.properties b/java/management/eclipse-plugin/build-release-linux-gtk-x86_64.properties
new file mode 100644
index 0000000000..bf58d9c08e
--- /dev/null
+++ b/java/management/eclipse-plugin/build-release-linux-gtk-x86_64.properties
@@ -0,0 +1,36 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
+release.name=${project.name}-${app.namever}-linux-gtk-x86_64
+
+release.subdir=${module.release.base}/${release.name}
+
+release.tar.gz=${module.release.base}/${release.name}.tar.gz
+
+qpidmc.ini=src/main/resources/linux-gtk-x86_64/qpidmc.ini
+
+qpidmc.executable=src/main/resources/linux-gtk-x86_64/qpidmc
+
+qpidmc.companion.library=src/main/resources/linux-gtk-x86_64/libcairo-swt.so
+
+rcp.libs=${management-eclipse-plugin-linux-gtk-x86_64.libs}
+
+rcp.configuration.dir=src/main/resources/linux-gtk-x86_64/Configuration
diff --git a/java/management/eclipse-plugin/build-release-macosx.properties b/java/management/eclipse-plugin/build-release-macosx.properties
new file mode 100644
index 0000000000..bdb2f0d7da
--- /dev/null
+++ b/java/management/eclipse-plugin/build-release-macosx.properties
@@ -0,0 +1,40 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
+application.name=Qpid JMX Management Console
+
+application.dir=${application.name}.app
+
+release.name=${project.name}-${app.namever}-macosx
+
+release.subdir=${module.release.base}/${release.name}
+
+release.zip=${module.release.base}/${release.name}.zip
+
+rcp.libs=${management-eclipse-plugin-macosx.libs}
+
+rcp.configuration.dir=src/main/resources/macosx/Configuration
+
+qpidmc.ini=src/main/resources/macosx/Contents/MacOS/qpidmc.ini
+qpidmc.executable=src/main/resources/macosx/Contents/MacOS/qpidmc
+
+eclipse.icns=src/main/resources/macosx/Contents/Resources/Console.icns
+macosx.plist=src/main/resources/macosx/Contents/Info.plist
diff --git a/java/management/eclipse-plugin/build-release-macosx.xml b/java/management/eclipse-plugin/build-release-macosx.xml
new file mode 100644
index 0000000000..2aa63d7f2f
--- /dev/null
+++ b/java/management/eclipse-plugin/build-release-macosx.xml
@@ -0,0 +1,101 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<project name="JMX Management Console MacOSX Binary Release" default="release-bin">
+
+ <import file="build-release.xml"/>
+
+ <property name="release.app" value="${release.subdir}/${application.dir}"/>
+
+ <target name="release-bin-qpid-mc-plugin">
+ <available file="${build.lib}/qpid-management-eclipse-plugin-${project.version}.jar" property="management-eclipse-plugin.jar.present"/>
+ <fail unless="management-eclipse-plugin.jar.present" message="Please run ant build for the management-eclipse-plugin module"/>
+
+ <!-- Copy the qpid management-eclipse-plugin module jar -->
+ <copy tofile="${release.app}/plugins/${mcplugin.filename}.jar" flatten="true" failonerror="true">
+ <fileset file="${build.lib}/qpid-management-eclipse-plugin-${project.version}.jar"/>
+ </copy>
+ </target>
+
+ <target name="release-bin-jmxremote-plugin">
+ <!-- Copy the jmxremote.sasl plugin's manifest, creating its plugin directory -->
+ <copy todir="${release.app}/plugins/jmxremote.sasl_1.0.1/META-INF" flatten="true" failonerror="true">
+ <fileset file="${jmxremote.sasl.manifest}"/>
+ </copy>
+ </target>
+
+ <target name="release-bin-qpid-management-common-plugin">
+ <available file="${build.lib}/qpid-management-common_${project.version}.0.osgi.jar" property="management-common.jar.present"/>
+ <fail unless="management-common.jar.present" message="Please run ant bundle for the management-common module"/>
+
+ <!-- Copy the qpid-management-common module osgi jar -->
+ <copy todir="${release.app}/plugins" flatten="true" failonerror="true">
+ <fileset file="${build.lib}/qpid-management-common_${project.version}.0.osgi.jar"/>
+ </copy>
+ </target>
+
+
+ <target name="release-bin-rcp-deps" description="copy eclipse-rcp dependencies into module release">
+
+ <!-- Copy Eclipse binary and start-up files -->
+ <copy todir="${release.app}/Contents/MacOS" flatten="true" failonerror="true">
+ <fileset file="${qpidmc.ini}"/>
+ <fileset file="${qpidmc.executable}"/>
+ </copy>
+
+ <chmod dir="${release.app}/Contents/MacOS" perm="u+rx" includes="**/*"/>
+
+ <!-- Copy MacOS plist file -->
+ <copy todir="${release.app}/Contents" flatten="true" failonerror="true">
+ <fileset file="${macosx.plist}"/>
+ </copy>
+
+ <!-- Copy Icns icon file -->
+ <copy todir="${release.app}/Contents/Resources" flatten="true" failonerror="true">
+ <fileset file="${eclipse.icns}"/>
+ </copy>
+
+ <!-- Copy the eclipse rcp module libs -->
+ <copy todir="${release.app}/plugins" failonerror="true">
+ <fileset dir="${project.root}" includes="${rcp.libs}"/>
+ <globmapper from="lib${file.separator}*" to="*"/>
+ </copy>
+
+ <!-- Copy the relevant configuration dir -->
+ <copy todir="${release.app}/Configuration" failonerror="true">
+ <fileset dir="${rcp.configuration.dir}"/>
+ </copy>
+ <chmod dir="${release.app}/Configuration" perm="ugo+r" includes="**/*"/>
+ </target>
+
+ <target name="release-bin-zip" if="release.zip" description="build mc zip archive">
+
+ <zip destfile="${release.zip}">
+ <zipfileset dir="${release.subdir}" filemode="755">
+ <include name="${application.dir}/Contents/MacOS/**"/>
+ </zipfileset>
+
+ <zipfileset dir="${release.subdir}" filemode="644" dirmode="755">
+ <exclude name="${application.dir}/Contents/MacOS/**"/>
+ </zipfileset>
+ </zip>
+ </target>
+
+</project>
diff --git a/java/management/eclipse-plugin/build-release-solaris-gtk-sparc.properties b/java/management/eclipse-plugin/build-release-solaris-gtk-sparc.properties
new file mode 100644
index 0000000000..d58d0c9ac0
--- /dev/null
+++ b/java/management/eclipse-plugin/build-release-solaris-gtk-sparc.properties
@@ -0,0 +1,39 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
+release.name=${project.name}-${app.namever}-solaris-gtk-sparc
+
+release.subdir=${module.release.base}/${release.name}
+
+release.tar.gz=${module.release.base}/${release.name}.tar.gz
+
+qpidmc.ini=src/main/resources/solaris-gtk-sparc/qpidmc.ini
+
+qpidmc.solaris.xpm.files=src/main/resources/solaris-gtk-sparc/Qpidmc.l.pm \
+ src/main/resources/solaris-gtk-sparc/Qpidmc.m.pm \
+ src/main/resources/solaris-gtk-sparc/Qpidmc.s.pm \
+ src/main/resources/solaris-gtk-sparc/Qpidmc.t.pm
+
+qpidmc.executable=src/main/resources/solaris-gtk-sparc/qpidmc
+
+rcp.libs=${management-eclipse-plugin-solaris-gtk-sparc.libs}
+
+rcp.configuration.dir=src/main/resources/solaris-gtk-sparc/Configuration
diff --git a/java/management/eclipse-plugin/build-release-win32-win32-x86.properties b/java/management/eclipse-plugin/build-release-win32-win32-x86.properties
new file mode 100644
index 0000000000..ee678a92c9
--- /dev/null
+++ b/java/management/eclipse-plugin/build-release-win32-win32-x86.properties
@@ -0,0 +1,34 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
+release.name=${project.name}-${app.namever}-win32-win32-x86
+
+release.subdir=${module.release.base}/${release.name}
+
+release.zip=${module.release.base}/${release.name}.zip
+
+qpidmc.executable=src/main/resources/win32-win32-x86/qpidmc.exe
+
+qpidmc.ini=src/main/resources/win32-win32-x86/qpidmc.ini
+
+rcp.libs=${management-eclipse-plugin-win32-win32-x86.libs}
+
+rcp.configuration.dir=src/main/resources/win32-win32-x86/Configuration
diff --git a/java/management/eclipse-plugin/build-release.xml b/java/management/eclipse-plugin/build-release.xml
new file mode 100644
index 0000000000..dec4cd5f32
--- /dev/null
+++ b/java/management/eclipse-plugin/build-release.xml
@@ -0,0 +1,172 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<project name="JMX Management Console Binary Release" default="release-bin">
+
+ <!-- check properties that must be set by caller -->
+ <target name="check" description="ensure all required properties are set">
+ <condition property="properties.set">
+ <and>
+ <!-- common properties -->
+ <isset property ="mcplugin.filename"/>
+ <isset property ="jmxremote.sasl.manifest"/>
+ <!-- platform specific properties -->
+ <isset property ="qpidmc.ini"/>
+ <isset property ="qpidmc.executable"/>
+ <isset property ="release.name"/>
+ <isset property ="release.subdir"/>
+ <isset property ="rcp.libs"/>
+ <isset property ="rcp.configuration.dir"/>
+ <or>
+ <isset property ="release.zip"/>
+ <isset property ="release.tar.gz"/>
+ </or>
+ </and>
+ <!-- Optional Properties:
+
+ For linux libcairo-swt.so file:
+ qpidmc.companion.library
+
+ For solaris .xpm files:
+ qpidmc.solaris.xpm.files
+
+ -->
+ </condition>
+
+ <fail unless="properties.set" message="some required properties were not set"/>
+ </target>
+
+ <target name="release-bin-prepare">
+ <mkdir dir="${release.subdir}"/>
+ </target>
+
+ <target name="release-bin-qpid-mc-plugin">
+ <available file="${build.lib}/qpid-management-eclipse-plugin-${project.version}.jar" property="management-eclipse-plugin.jar.present"/>
+ <fail unless="management-eclipse-plugin.jar.present" message="Please run ant build for the management-eclipse-plugin module"/>
+
+ <!-- Copy the qpid management-eclipse-plugin module jar -->
+ <copy tofile="${release.subdir}/plugins/${mcplugin.filename}.jar" flatten="true" failonerror="true">
+ <fileset file="${build.lib}/qpid-management-eclipse-plugin-${project.version}.jar"/>
+ </copy>
+ </target>
+
+ <target name="release-bin-jmxremote-plugin">
+ <!-- Copy the jmxremote.sasl plugin's manifest, creating its plugin directory -->
+ <copy todir="${release.subdir}/plugins/jmxremote.sasl_1.0.1/META-INF" flatten="true" failonerror="true">
+ <fileset file="${jmxremote.sasl.manifest}"/>
+ </copy>
+ </target>
+
+ <target name="release-bin-qpid-management-common-plugin">
+ <available file="${build.lib}/qpid-management-common_${project.version}.0.osgi.jar" property="management-common.jar.present"/>
+ <fail unless="management-common.jar.present" message="Please run ant bundle for the management-common module"/>
+
+ <!-- Copy the qpid-management-common module osgi jar -->
+ <copy todir="${release.subdir}/plugins" failonerror="true">
+ <fileset file="${build.lib}/qpid-management-common_${project.version}.0.osgi.jar"/>
+ </copy>
+ </target>
+
+ <target name="release-bin-executable-companion-library" if="qpidmc.companion.library">
+ <!-- Copy the rcp executable companion library file -->
+ <copy todir="${release.subdir}" flatten="true" failonerror="true">
+ <fileset file="${qpidmc.companion.library}"/>
+ </copy>
+ </target>
+
+ <target name="release-bin-executable-solaris-xpm-files" if="qpidmc.solaris.xpm.files">
+ <!-- Copy the solaris xpm files -->
+ <copy todir="${release.subdir}" flatten="true" failonerror="true">
+ <fileset dir="${basedir}" includes="${qpidmc.solaris.xpm.files}"/>
+ </copy>
+ </target>
+
+ <target name="release-bin-rcp-deps" description="copy eclipse-rcp dependencies into module release"
+ depends="release-bin-executable-companion-library, release-bin-executable-solaris-xpm-files">
+
+ <!-- Copy the rcp executable file -->
+ <copy todir="${release.subdir}" flatten="true" failonerror="true">
+ <fileset file="${qpidmc.executable}"/>
+ </copy>
+ <chmod dir="${release.subdir}" perm="u+rx" includes="qpidmc*"/>
+
+ <!-- Copy remaining startup & license files -->
+ <copy todir="${release.subdir}" flatten="true" failonerror="true">
+ <fileset file="${qpidmc.ini}"/>
+ </copy>
+
+ <!-- Copy the rcp module libs -->
+ <copy todir="${release.subdir}/plugins" failonerror="true">
+ <fileset dir="${project.root}" includes="${rcp.libs}"/>
+ <globmapper from="lib${file.separator}*" to="*"/>
+ </copy>
+
+ <!-- Copy the relevant configuration dir -->
+ <copy todir="${release.subdir}/configuration" failonerror="true">
+ <fileset dir="${rcp.configuration.dir}"/>
+ </copy>
+ <chmod dir="${release.subdir}/configuration" perm="ugo+r" includes="**/*"/>
+ </target>
+
+ <target name="release-bin-zip" if="release.zip" description="build mc zip archive">
+ <zip destfile="${release.zip}">
+ <zipfileset dir="${release.subdir}" prefix="${release.name}" filemode="755">
+ <include name="qpidmc*"/>
+ <exclude name="qpidmc.ini"/>
+ </zipfileset>
+
+ <zipfileset dir="${release.subdir}" prefix="${release.name}" filemode="644">
+ <include name="qpidmc.ini"/>
+ </zipfileset>
+
+ <zipfileset dir="${release.subdir}" prefix="${release.name}" filemode="644" dirmode="755">
+ <exclude name="qpidmc*"/>
+ </zipfileset>
+ </zip>
+ </target>
+
+ <target name="release-bin-gzip" if="release.tar.gz" description="build mc tar.gz archive">
+ <tar destfile="${release.tar.gz}" longfile="gnu" compression="gzip">
+ <tarfileset dir="${release.subdir}" prefix="${release.name}" filemode="755">
+ <include name="qpidmc*"/>
+ <exclude name="qpidmc.ini"/>
+ </tarfileset>
+
+ <tarfileset dir="${release.subdir}" prefix="${release.name}" filemode="644">
+ <include name="qpidmc.ini"/>
+ </tarfileset>
+
+ <tarfileset dir="${release.subdir}" prefix="${release.name}" filemode="644" dirmode="755">
+ <exclude name="qpidmc*"/>
+ </tarfileset>
+ </tar>
+ </target>
+
+ <target name="release-bin-resources" description="copy project resources into module release">
+ <copy todir="${release.subdir}" failonerror="false" flatten="true">
+ <fileset dir="${resources}" excludes="META-INF"/>
+ </copy>
+ </target>
+
+ <!-- override imported module.xml release-bin target -->
+ <target name="release-bin" depends="check,release-bin-prepare,release-bin-rcp-deps,release-bin-resources,
+ release-bin-qpid-mc-plugin,release-bin-qpid-management-common-plugin,release-bin-jmxremote-plugin,release-bin-zip,release-bin-gzip"/>
+
+</project>
diff --git a/java/management/eclipse-plugin/build.xml b/java/management/eclipse-plugin/build.xml
index 492783e574..3361ae362c 100644
--- a/java/management/eclipse-plugin/build.xml
+++ b/java/management/eclipse-plugin/build.xml
@@ -20,8 +20,69 @@
-->
<project name="Eclipse Plugin" default="build">
- <property name="module.depends" value="broker common"/>
+ <property name="module.depends" value="broker common management/common"/>
+ <property name="module.test.depends" value="broker/test" />
<import file="../../module.xml"/>
+ <!-- module.manifest property to invoke use of 'jar.manifest' jar target when building -->
+ <property name="module.manifest" value="${module.classes}/META-INF/MANIFEST.MF"/>
+
+ <!-- override module.xml 'libs' target, avoids cluttering the 'build/lib' dir as the
+ MC build/packaging process does not use the libs from there -->
+ <target name="libs"/>
+
+ <target name="copy-plugin-files" description="copy eclipse management plugin files into build tree">
+ <copy todir="${module.classes}/icons" failonerror="true">
+ <fileset dir="icons/"/>
+ </copy>
+ <copy todir="${module.classes}/META-INF/" failonerror="true">
+ <fileset dir="META-INF/"/>
+ </copy>
+ <copy todir="${module.classes}" failonerror="true">
+ <fileset file="icons/splash.bmp"/>
+ </copy>
+ <copy todir="${module.classes}" failonerror="true">
+ <fileset file="plugin.properties"/>
+ </copy>
+ <copy todir="${module.classes}" failonerror="true">
+ <fileset file="plugin.xml"/>
+ </copy>
+ </target>
+
+ <target name="precompile" depends="copy-plugin-files, create-version" />
+
+ <!-- Override imported module.xml release-bin target -->
+ <target name="release-bin" depends="build">
+ <!-- linux gtk x86 -->
+ <ant antfile="build-release.xml">
+ <property file="build-release-common.properties"/>
+ <property file="build-release-linux-gtk-x86.properties"/>
+ </ant>
+
+ <!-- linux gtk x86_64 -->
+ <ant antfile="build-release.xml">
+ <property file="build-release-common.properties"/>
+ <property file="build-release-linux-gtk-x86_64.properties"/>
+ </ant>
+
+ <!-- solaris gtk sparc -->
+ <ant antfile="build-release.xml">
+ <property file="build-release-common.properties"/>
+ <property file="build-release-solaris-gtk-sparc.properties"/>
+ </ant>
+
+ <!-- mac os x -->
+ <ant antfile="build-release-macosx.xml">
+ <property file="build-release-common.properties"/>
+ <property file="build-release-macosx.properties"/>
+ </ant>
+
+ <!-- win32 win32 x86 -->
+ <ant antfile="build-release.xml">
+ <property file="build-release-common.properties"/>
+ <property file="build-release-win32-win32-x86.properties"/>
+ </ant>
+ </target>
+
</project>
diff --git a/java/management/eclipse-plugin/icons/Thumbs.db b/java/management/eclipse-plugin/icons/Thumbs.db
deleted file mode 100644
index 306bfb2eda..0000000000
--- a/java/management/eclipse-plugin/icons/Thumbs.db
+++ /dev/null
Binary files differ
diff --git a/java/management/eclipse-plugin/icons/back.gif b/java/management/eclipse-plugin/icons/back.gif
new file mode 100644
index 0000000000..d3a10077a5
--- /dev/null
+++ b/java/management/eclipse-plugin/icons/back.gif
Binary files differ
diff --git a/java/management/eclipse-plugin/icons/configuration_management.gif b/java/management/eclipse-plugin/icons/configuration_management.gif
new file mode 100644
index 0000000000..d11c996e57
--- /dev/null
+++ b/java/management/eclipse-plugin/icons/configuration_management.gif
Binary files differ
diff --git a/java/management/eclipse-plugin/icons/failure.gif b/java/management/eclipse-plugin/icons/failure.gif
new file mode 100644
index 0000000000..9b048d6053
--- /dev/null
+++ b/java/management/eclipse-plugin/icons/failure.gif
Binary files differ
diff --git a/java/management/eclipse-plugin/icons/logging_management.gif b/java/management/eclipse-plugin/icons/logging_management.gif
new file mode 100644
index 0000000000..7f5fe98a73
--- /dev/null
+++ b/java/management/eclipse-plugin/icons/logging_management.gif
Binary files differ
diff --git a/java/management/eclipse-plugin/icons/qpidConnections.gif b/java/management/eclipse-plugin/icons/qpidConnections.gif
index 89489f11f2..17f927e9a4 100644
--- a/java/management/eclipse-plugin/icons/qpidConnections.gif
+++ b/java/management/eclipse-plugin/icons/qpidConnections.gif
Binary files differ
diff --git a/java/management/eclipse-plugin/icons/refresh.gif b/java/management/eclipse-plugin/icons/refresh.gif
index a063c230ac..1b724a6784 100644
--- a/java/management/eclipse-plugin/icons/refresh.gif
+++ b/java/management/eclipse-plugin/icons/refresh.gif
Binary files differ
diff --git a/java/management/eclipse-plugin/icons/server_information.gif b/java/management/eclipse-plugin/icons/server_information.gif
new file mode 100644
index 0000000000..716df436f9
--- /dev/null
+++ b/java/management/eclipse-plugin/icons/server_information.gif
Binary files differ
diff --git a/java/management/eclipse-plugin/icons/splash.bmp b/java/management/eclipse-plugin/icons/splash.bmp
index b528a508c5..cf3b93d523 100644
--- a/java/management/eclipse-plugin/icons/splash.bmp
+++ b/java/management/eclipse-plugin/icons/splash.bmp
Binary files differ
diff --git a/java/management/eclipse-plugin/icons/success.gif b/java/management/eclipse-plugin/icons/success.gif
new file mode 100644
index 0000000000..9cacb96dca
--- /dev/null
+++ b/java/management/eclipse-plugin/icons/success.gif
Binary files differ
diff --git a/java/management/eclipse-plugin/icons/user_management.gif b/java/management/eclipse-plugin/icons/user_management.gif
new file mode 100644
index 0000000000..d28c326dea
--- /dev/null
+++ b/java/management/eclipse-plugin/icons/user_management.gif
Binary files differ
diff --git a/java/management/eclipse-plugin/icons/virtualhost_manager.gif b/java/management/eclipse-plugin/icons/virtualhost_manager.gif
new file mode 100644
index 0000000000..e7ec2a1544
--- /dev/null
+++ b/java/management/eclipse-plugin/icons/virtualhost_manager.gif
Binary files differ
diff --git a/java/management/eclipse-plugin/plugin.xml b/java/management/eclipse-plugin/plugin.xml
index 5774859b47..e151456fa1 100644
--- a/java/management/eclipse-plugin/plugin.xml
+++ b/java/management/eclipse-plugin/plugin.xml
@@ -32,7 +32,8 @@
<extension
point="org.eclipse.ui.perspectives">
<perspective
- name="qpid.management.perspective"
+ name="Qpid Management"
+ icon="icons/mbean_view.png"
class="org.apache.qpid.management.ui.Perspective"
id="org.apache.qpid.management.ui.perspective">
</perspective>
@@ -93,11 +94,6 @@
name="Refresh"/>
<command
categoryId="org.apache.qpid.management.ui.category"
- description="pops up the window for editing selected attribute"
- id="org.apache.qpid.management.ui.actions.cmd_editAttribute"
- name="Edit Attribute"/>
- <command
- categoryId="org.apache.qpid.management.ui.category"
description="About Qpid Management Console"
id="qpidmc.about"
name="About"/>
@@ -127,10 +123,6 @@
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"
sequence="CTRL+Alt+F5"/>
<key
- commandId="org.apache.qpid.management.ui.actions.cmd_editAttribute"
- schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"
- sequence="CTRL+Alt+E"/>
- <key
commandId="org.eclipse.ui.file.exit"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"
sequence="CTRL+Alt+X">
@@ -152,6 +144,23 @@
value="Qpid Management Console"/>
</product>
</extension>
+
+ <extension point="org.eclipse.ui.menus">
+ <menuContribution locationURI="toolbar:org.eclipse.ui.main.toolbar?after=additions">
+ <toolbar id="qpidMC">
+ <separator name="qpidActionsGroup" visible="false"/>
+ <separator name="refresh" visible="true"/>
+ <separator name="refresh2" visible="false"/>
+ <separator name="additions" visible="false"/>
+ </toolbar>
+ </menuContribution>
+ <menuContribution locationURI="toolbar:qpidMC?after=refresh">
+ <control
+ class="org.apache.qpid.management.ui.RefreshIntervalComboPanel">
+ </control>
+ </menuContribution>
+ </extension>
+
<extension
point="org.eclipse.ui.actionSets">
<actionSet
@@ -164,14 +173,6 @@
<separator name="qpidActionsGroup"/>
</menu>
<action
- class="org.apache.qpid.management.ui.actions.EditAttribute"
- definitionId="org.apache.qpid.management.ui.actions.cmd_editAttribute"
- id="org.apache.qpid.management.ui.actions.editAttribute"
- label="Edit Attribute"
- menubarPath="qpidmanager/mbeanactions"
- style="push"
- tooltip="Edit Attribute"/>
- <action
class="org.apache.qpid.management.ui.actions.Refresh"
definitionId="org.apache.qpid.management.ui.actions.cmd_refresh"
icon="icons/refresh.gif"
@@ -179,8 +180,8 @@
label="Refresh"
menubarPath="qpidmanager/additions"
style="push"
- toolbarPath="qpidActionsGroup"
- tooltip="Refresh"/>
+ toolbarPath="qpidMC/refresh2"
+ tooltip="Refresh Now"/>
<action
class="org.apache.qpid.management.ui.actions.RemoveServer"
definitionId="org.apache.qpid.management.ui.actions.cmd_remove"
@@ -189,7 +190,8 @@
label="Remove Connection"
menubarPath="qpidmanager/additions"
style="push"
- toolbarPath="qpidActionsGroup"/>
+ toolbarPath="qpidMC/qpidActionsGroup"
+ tooltip="Remove Server"/>
<action
class="org.apache.qpid.management.ui.actions.CloseConnection"
definitionId="org.apache.qpid.management.ui.actions.cmd_disconnect"
@@ -197,7 +199,7 @@
id="org.apache.qpid.management.ui.disconnect"
label="Disconnect"
menubarPath="qpidmanager/additions"
- toolbarPath="qpidActionsGroup"
+ toolbarPath="qpidMC/qpidActionsGroup"
tooltip="Disconnect"/>
<action
class="org.apache.qpid.management.ui.actions.ReconnectServer"
@@ -206,7 +208,7 @@
id="org.apache.qpid.management.ui.reconnect"
label="Reconnect"
menubarPath="qpidmanager/additions"
- toolbarPath="qpidActionsGroup"
+ toolbarPath="qpidMC/qpidActionsGroup"
tooltip="Reconnect"/>
<action
class="org.apache.qpid.management.ui.actions.AddServer"
@@ -215,9 +217,9 @@
id="org.apache.qpid.management.ui.add"
label="New Connection"
menubarPath="qpidmanager/additions"
- toolbarPath="qpidActionsGroup"
- tooltip="New Connection"/>
+ toolbarPath="qpidMC/qpidActionsGroup"
+ tooltip="New Connection"/>
</actionSet>
</extension>
-
+
</plugin>
diff --git a/java/management/eclipse-plugin/pom.xml b/java/management/eclipse-plugin/pom.xml
deleted file mode 100644
index a3fff30598..0000000000
--- a/java/management/eclipse-plugin/pom.xml
+++ /dev/null
@@ -1,252 +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.
- -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.qpid.management</groupId>
- <artifactId>org.apache.qpid.management.ui</artifactId>
- <packaging>jar</packaging>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <name>Qpid Management</name>
-
- <parent>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid</artifactId>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <relativePath>../../pom.xml</relativePath>
- </parent>
-
- <properties>
- <topDirectoryLocation>../..</topDirectoryLocation>
- </properties>
-
- <repositories>
- <repository>
- <id>repo1.maven.org</id>
- <name>Maven eclipse Repository</name>
- <url>http://repo1.maven.org/eclipse</url>
- </repository>
- <repository>
- <id>apache.snapshots</id>
- <name>Apache SNAPSHOT Repository</name>
- <url>http://people.apache.org/repo/m2-snapshot-repository</url>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- </repository>
- </repositories>
-
- <dependencies>
- <dependency>
- <groupId>com.ibm.icu</groupId>
- <artifactId>com.ibm.icu</artifactId>
- <version>3.4.4</version>
- <scope>compile</scope>
- </dependency>
-
- <dependency>
- <groupId>org.eclipse.jface</groupId>
- <artifactId>org.eclipse.jface</artifactId>
- <version>3.2.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.eclipse.core</groupId>
- <artifactId>org.eclipse.core.commands</artifactId>
- <version>3.2.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.eclipse.core</groupId>
- <artifactId>org.eclipse.core.contenttype</artifactId>
- <version>3.2.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.eclipse.core</groupId>
- <artifactId>org.eclipse.core.expressions</artifactId>
- <version>3.2.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.eclipse.core</groupId>
- <artifactId>org.eclipse.core.jobs</artifactId>
- <version>3.2.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.eclipse.core</groupId>
- <artifactId>org.eclipse.core.runtime</artifactId>
- <version>3.2.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.eclipse.core</groupId>
- <artifactId>org.eclipse.core.runtime.compatibility.auth</artifactId>
- <version>3.2.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.eclipse.core</groupId>
- <artifactId>org.eclipse.core.runtime.compatibility.registry</artifactId>
- <version>3.2.0</version>
- <scope>runtime</scope>
- </dependency>
- <dependency>
- <groupId>org.eclipse.equinox</groupId>
- <artifactId>org.eclipse.equinox.common</artifactId>
- <version>3.2.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.eclipse.equinox</groupId>
- <artifactId>org.eclipse.equinox.preferences</artifactId>
- <version>3.2.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.eclipse.equinox</groupId>
- <artifactId>org.eclipse.equinox.registry</artifactId>
- <version>3.2.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.eclipse.help</groupId>
- <artifactId>org.eclipse.help</artifactId>
- <version>3.2.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.eclipse.osgi</groupId>
- <artifactId>org.eclipse.osgi</artifactId>
- <version>3.2.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.eclipse.swt</groupId>
- <artifactId>org.eclipse.swt.win32.win32.x86</artifactId>
- <version>3.2.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.eclipse.swt</groupId>
- <artifactId>org.eclipse.swt</artifactId>
- <version>3.2.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.eclipse.ui</groupId>
- <artifactId>org.eclipse.ui.forms</artifactId>
- <version>3.2.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.eclipse.ui</groupId>
- <artifactId>org.eclipse.ui.workbench</artifactId>
- <version>3.2.1</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.eclipse.ui</groupId>
- <artifactId>org.eclipse.ui</artifactId>
- <version>3.2.0</version>
- <scope>compile</scope>
- </dependency>
-
- <!-- Test Dependencies -->
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.4.0</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-broker</artifactId>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>test</scope>
- </dependency>
-
- </dependencies>
-
- <build>
- <resources>
- <resource>
- <directory>icons/</directory>
- <targetPath>icons/</targetPath>
- <includes>
- <include>**</include>
- </includes>
- </resource>
- <resource>
- <directory>icons/</directory>
- <targetPath>/</targetPath>
- <includes>
- <include>splash.bmp</include>
- </includes>
- </resource>
- <resource>
- <directory>${basedir}</directory>
- <targetPath>/</targetPath>
- <includes>
- <include>plugin.xml</include>
- <include>plugin.properties</include>
- </includes>
- </resource>
- </resources>
- <plugins>
- <!--
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-antrun-plugin</artifactId>
- </plugin>
- -->
-
- <!-- This is required to identify the JAR to eclipse as a plugin -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <configuration>
- <archive>
- <manifestFile>META-INF/MANIFEST.MF</manifestFile>
- </archive>
- <finalName>${artifactId}_${version}</finalName>
- </configuration>
- </plugin>
-
- <!--
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <skip>false</skip>
- </configuration>
- </plugin>
- -->
- </plugins>
- </build>
-
-</project>
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApiVersion.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApiVersion.java
new file mode 100644
index 0000000000..a8eda3f3d1
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApiVersion.java
@@ -0,0 +1,110 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui;
+
+public class ApiVersion
+{
+ private int major;
+ private int minor;
+
+ public ApiVersion(int major, int minor)
+ {
+ this.major = major;
+ this.minor = minor;
+ }
+
+ public int getMajor()
+ {
+ return major;
+ }
+
+ public int getMinor()
+ {
+ return minor;
+ }
+
+ public boolean greaterThanOrEqualTo(int major, int minor)
+ {
+ if((this.major == major) && (this.minor >= minor))
+ {
+ return true;
+ }
+ else if (this.major > major)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public boolean lessThanOrEqualTo(int major, int minor)
+ {
+ if((this.major == major) && (this.minor <= minor))
+ {
+ return true;
+ }
+ else if (this.major < major)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public boolean greaterThan(int major, int minor)
+ {
+ if(this.major > major)
+ {
+ return true;
+ }
+ else if ((this.major == major) && (this.minor > minor))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public boolean lessThan(int major, int minor)
+ {
+ if(this.major < major)
+ {
+ return true;
+ }
+ else if ((this.major == major) && (this.minor < minor))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public boolean equals(int major, int minor)
+ {
+ return (this.major == major) && (this.minor == minor);
+ }
+
+ public String toString()
+ {
+ return new String("major=" + major + ",minor=" + minor);
+ }
+
+}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java
index 0ad85dbf33..f3fc135efb 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java
@@ -20,8 +20,9 @@
*/
package org.apache.qpid.management.ui;
-import java.util.HashMap;
+import java.io.File;
import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.jface.resource.FontRegistry;
@@ -42,12 +43,20 @@ public abstract class ApplicationRegistry
private static ImageRegistry imageRegistry = new ImageRegistry();
private static FontRegistry fontRegistry = new FontRegistry();
public static final boolean debug = Boolean.getBoolean("eclipse.consoleLog");
- public static final String securityMechanism = System.getProperty("security", null);
- public static final String connectorClass = System.getProperty("jmxconnector");
- public static final long timeout = Long.parseLong(System.getProperty("timeout", "5000"));
+ public static final long timeout = Long.parseLong(System.getProperty("timeout", "15000"));
+
+ //max supported broker management interface supported by this release of the management console
+ public static final int SUPPORTED_QPID_JMX_API_MAJOR_VERSION = 1;
+ public static final int SUPPORTED_QPID_JMX_API_MINOR_VERSION = 6;
+
+ public static final String DATA_DIR = System.getProperty("user.home") + File.separator + ".qpidmc";
static
{
+ imageRegistry.put(Constants.SUCCESS_IMAGE,
+ org.apache.qpid.management.ui.Activator.getImageDescriptor("/icons/success.gif"));
+ imageRegistry.put(Constants.FAILURE_IMAGE,
+ org.apache.qpid.management.ui.Activator.getImageDescriptor("/icons/failure.gif"));
imageRegistry.put(Constants.CONSOLE_IMAGE,
org.apache.qpid.management.ui.Activator.getImageDescriptor("/icons/qpidmc.gif"));
imageRegistry.put(Constants.CLOSED_FOLDER_IMAGE,
@@ -58,6 +67,16 @@ public abstract class ApplicationRegistry
PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_ELEMENT));
imageRegistry.put(Constants.NOTIFICATION_IMAGE,
org.apache.qpid.management.ui.Activator.getImageDescriptor("/icons/notifications.gif"));
+ imageRegistry.put(Constants.LOGGING_MANAGEMENT_IMAGE,
+ org.apache.qpid.management.ui.Activator.getImageDescriptor("/icons/logging_management.gif"));
+ imageRegistry.put(Constants.USER_MANAGEMENT_IMAGE,
+ org.apache.qpid.management.ui.Activator.getImageDescriptor("/icons/user_management.gif"));
+ imageRegistry.put(Constants.CONFIGURATION_MANAGEMENT_IMAGE,
+ org.apache.qpid.management.ui.Activator.getImageDescriptor("/icons/configuration_management.gif"));
+ imageRegistry.put(Constants.SERVER_INFO_IMAGE,
+ org.apache.qpid.management.ui.Activator.getImageDescriptor("/icons/server_information.gif"));
+ imageRegistry.put(Constants.VHOST_MANAGER_IMAGE,
+ org.apache.qpid.management.ui.Activator.getImageDescriptor("/icons/virtualhost_manager.gif"));
}
static
@@ -71,9 +90,8 @@ public abstract class ApplicationRegistry
/*
* This maps all the managed servers to the respective server registry.
- * Server can be JMX MBeanServer or a C++ server
*/
- private static HashMap<ManagedServer, ServerRegistry> _serverRegistryMap = new HashMap<ManagedServer, ServerRegistry>();
+ private static ConcurrentHashMap<ManagedServer, ServerRegistry> _serverRegistryMap = new ConcurrentHashMap<ManagedServer, ServerRegistry>();
// This map gets updated when a server connection closes.
private static List<ManagedServer> _closedServerList = new CopyOnWriteArrayList<ManagedServer>();
@@ -111,7 +129,19 @@ public abstract class ApplicationRegistry
public static boolean isServerConnected(ManagedServer server)
{
- return _serverRegistryMap.containsKey(server);
+ if(server == null)
+ {
+ //checking for null is not permitted in a CHM
+ return false;
+ }
+
+ ServerRegistry reg = _serverRegistryMap.get(server);
+ if(reg !=null)
+ {
+ return !reg.isServerConnectionClosed();
+ }
+
+ return false;
}
// remove the server from the registry
@@ -121,6 +151,27 @@ public abstract class ApplicationRegistry
removeServer(server);
}
+ // remove the server from the registry
+ public static void serverConnectionClosedRemotely(ManagedServer server)
+ {
+ ServerRegistry reg = _serverRegistryMap.get(server);
+ if(reg !=null)
+ {
+ synchronized(server)
+ {
+ if(reg.isServerConnectionClosed())
+ {
+ //the connection closure was already processed
+ return;
+ }
+
+ reg.serverConnectionClosed();
+ }
+ }
+
+ serverConnectionClosed(server);
+ }
+
/*
* Returns the lis of closed servers. The Thread in GUI, which keeps checking for closed connection
* will check this and will remove the server links from the GUI.
@@ -134,14 +185,5 @@ public abstract class ApplicationRegistry
_closedServerList.clear();
return list;
}
-
- public static String getSecurityMechanism()
- {
- return securityMechanism;
- }
-
- public static String getJMXConnectorClass()
- {
- return connectorClass;
- }
+
}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationWorkbenchWindowAdvisor.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationWorkbenchWindowAdvisor.java
index e3aedef28e..00574440c5 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationWorkbenchWindowAdvisor.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationWorkbenchWindowAdvisor.java
@@ -51,7 +51,7 @@ public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor
int y = Display.getDefault().getBounds().height;
configurer.setInitialSize(new Point(9*x/10, 8*y/10));
configurer.setShowCoolBar(true);
- configurer.setShowStatusLine(false);
+ configurer.setShowStatusLine(true);
configurer.setTitle(Constants.APPLICATION_NAME);
}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Constants.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Constants.java
index d6f895b64a..cec9c8a83c 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Constants.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Constants.java
@@ -27,13 +27,14 @@ package org.apache.qpid.management.ui;
*/
public class Constants
{
- public final static String APPLICATION_NAME = "Qpid Management Console";
+ public final static String APPLICATION_NAME = "Qpid JMX Management Console";
+ public static final String DEFAULT_DOMAIN = "org.apache.qpid";
public final static String ACTION_REMOVE_MBEANNODE = "Remove from list";
public final static String VALUE = "value";
public final static String TYPE = "type";
+ public final static String VERSION = "version";
public final static String NODE_TYPE_SERVER = "server";
- public final static String NODE_TYPE_DOMAIN = "domain";
public final static String NODE_TYPE_MBEANTYPE = "mbeantype";
// currently used only for virtual host instances, but will work as general also
public final static String NODE_TYPE_TYPEINSTANCE = "mbeantype_instance";
@@ -77,11 +78,9 @@ public class Constants
public final static String CONNECTION ="Connection";
public final static String EXCHANGE = "Exchange";
public final static String EXCHANGE_TYPE = "ExchangeType";
- public final static String[] EXCHANGE_TYPE_VALUES = {"direct", "fanout", "headers", "topic"};
+ public final static String[] DEFAULT_EXCHANGE_TYPE_VALUES = {"direct", "fanout", "headers", "topic"};
public final static String[] BOOLEAN_TYPE_VALUES = {"false", "true"};
public final static String[] ATTRIBUTE_TABLE_TITLES = {"Attribute Name", "Value"};
- public static final String[] CONNECTION_PROTOCOLS ={"RMI"};
- public static final String DEFAULT_PROTOCOL = CONNECTION_PROTOCOLS[0];
public final static String ACTION_ADDSERVER = "New Connection";
public final static String ACTION_RECONNECT = "Reconnect";
@@ -97,11 +96,19 @@ public class Constants
public final static String SUBSCRIBE_BUTTON = "Subscribe";
public final static String UNSUBSCRIBE_BUTTON = "Unsubscribe";
- public final static String CONSOLE_IMAGE = "ConsoelImage";
+
+ public final static String SUCCESS_IMAGE = "SuccessImage";
+ public final static String FAILURE_IMAGE = "FailureImage";
+ public final static String CONSOLE_IMAGE = "ConsoleImage";
public final static String CLOSED_FOLDER_IMAGE = "ClosedFolderImage";
public final static String OPEN_FOLDER_IMAGE = "OpenFolderImage";
public final static String MBEAN_IMAGE = "MBeanImage";
public final static String NOTIFICATION_IMAGE = "NotificationImage";
+ public final static String LOGGING_MANAGEMENT_IMAGE = "LoggingManagementImage";
+ public final static String USER_MANAGEMENT_IMAGE = "UserManagementImage";
+ public final static String CONFIGURATION_MANAGEMENT_IMAGE = "ConfigurationManagementImage";
+ public final static String SERVER_INFO_IMAGE = "ServerInfoImage";
+ public final static String VHOST_MANAGER_IMAGE = "VhostManagerImage";
public final static String FONT_BUTTON = "ButtonFont";
public final static String FONT_BOLD = "BoldFont";
@@ -110,7 +117,7 @@ public class Constants
public final static String FONT_NORMAL = "Normal";
public final static String BUTTON_DETAILS = "Details";
- public final static String BUTTON_EDIT_ATTRIBUTE = "Edit Attribute";
+ public final static String BUTTON_EDIT_ATTRIBUTE = "Edit";
public final static String BUTTON_REFRESH = "Refresh";
public final static String BUTTON_GRAPH = "Graph";
public final static int TIMER_INTERVAL = 5000;
@@ -133,8 +140,4 @@ public class Constants
public final static String INFO_USERNAME = "Please enter the " + USERNAME;
public final static String INFO_PASSWORD = "Please enter the " + PASSWORD;
- public final static String MECH_CRAMMD5 = "CRAM-MD5";
- public final static String MECH_PLAIN = "PLAIN";
- public final static String SASL_CRAMMD5 = "SASL/CRAM-MD5";
- public final static String SASL_PLAIN = "SASL/PLAIN";
}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedBean.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedBean.java
index 31825e925d..8ded3f35c6 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedBean.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedBean.java
@@ -20,13 +20,19 @@
*/
package org.apache.qpid.management.ui;
-import static org.apache.qpid.management.ui.Constants.*;
+import static org.apache.qpid.management.ui.Constants.ADMIN_MBEAN_TYPE;
+import static org.apache.qpid.management.ui.Constants.CONNECTION;
+import static org.apache.qpid.management.ui.Constants.DEFAULT_VH;
+import static org.apache.qpid.management.ui.Constants.EXCHANGE;
+import static org.apache.qpid.management.ui.Constants.QUEUE;
+import static org.apache.qpid.management.ui.Constants.VIRTUAL_HOST;
+
import java.util.HashMap;
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+
/**
* Class representing a managed bean on the managed server
- * @author Bhupendra Bhardwaj
- *
*/
public abstract class ManagedBean extends ManagedObject
{
@@ -36,27 +42,50 @@ public abstract class ManagedBean extends ManagedObject
private String _virtualHostName = null;
private ManagedServer _server = null;
private HashMap _properties = null;
-
+ private int _version;
+
public String getProperty(String key)
{
- return (String)_properties.get(key);
+ return (String) _properties.get(key);
}
-
+
public HashMap getProperties()
{
return _properties;
}
+
public void setProperties(HashMap properties)
{
this._properties = properties;
setName(getProperty("name"));
setType(getProperty("type"));
+ setVersion(getProperty("version"));
_virtualHostName = getProperty(VIRTUAL_HOST);
}
+
+ public void setVersion(String version)
+ {
+ try
+ {
+ _version = Integer.parseInt(version);
+ }
+ catch (NumberFormatException nfe)
+ {
+ _version = 1;
+ }
+
+ }
+
+ public int getVersion()
+ {
+ return _version;
+ }
+
public String getDomain()
{
return _domain;
}
+
public void setDomain(String domain)
{
this._domain = domain;
@@ -66,65 +95,80 @@ public abstract class ManagedBean extends ManagedObject
{
return _server;
}
+
public void setServer(ManagedServer server)
{
this._server = server;
}
+
public String getType()
{
return _type;
}
+
public void setType(String type)
{
this._type = type;
}
+
public String getUniqueName()
{
return _uniqueName;
}
+
public void setUniqueName(String uniqueName)
{
this._uniqueName = uniqueName;
}
-
+
public String getVirtualHostName()
{
// To make it work with the broker with no virtual host implementation
return _virtualHostName == null ? DEFAULT_VH : _virtualHostName;
}
-
+
/**
* Returns mbean instance name. MBeans which have only one instance, the type attribute will be returned
+ *
* @return
*/
public String getInstanceName()
{
if (getName() != null)
+ {
return getName();
+ }
else
+ {
return getType();
+ }
}
-
+
public boolean isQueue()
{
return _type.endsWith(QUEUE);
}
-
+
public boolean isConnection()
{
return _type.endsWith(CONNECTION);
}
-
+
public boolean isExchange()
{
return _type.endsWith(EXCHANGE);
}
+
+ public boolean isVirtualHostManager()
+ {
+ return _type.endsWith(ManagedBroker.TYPE);
+ }
public boolean isTempQueue()
{
return (isQueue() && getName().startsWith("tmp_"));
}
-
+
public boolean isAdmin()
{
return _type.endsWith(ADMIN_MBEAN_TYPE);
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedServer.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedServer.java
index 480fdb429a..9ca8787bb5 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedServer.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedServer.java
@@ -20,20 +20,16 @@
*/
package org.apache.qpid.management.ui;
-import static org.apache.qpid.management.ui.Constants.DEFAULT_PROTOCOL;
/**
* Class representing a server being managed eg. MBeanServer
- * @author Bhupendra Bhardwaj
*/
public class ManagedServer extends ManagedObject
{
private String _host;
private int _port;
- private String _url;
private String _domain;
private String _user;
private String _password;
- private String _protocol = DEFAULT_PROTOCOL;
public ManagedServer(String host, int port, String domain)
{
@@ -46,7 +42,6 @@ public class ManagedServer extends ManagedObject
_host = host;
_port = port;
_domain = domain;
- _url = getRMIURL(host, port);
_user = user;
_password = password;
}
@@ -65,17 +60,7 @@ public class ManagedServer extends ManagedObject
{
return _port;
}
-
- public String getUrl()
- {
- return _url;
- }
- public String getProtocol()
- {
- return _protocol;
- }
-
public String getPassword()
{
return _password;
@@ -96,8 +81,4 @@ public class ManagedServer extends ManagedObject
_user = user;
}
- private String getRMIURL(String host, int port)
- {
- return "service:jmx:rmi:///jndi/rmi://" + host + ":" + port + "/jmxrmi";
- }
}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/RefreshIntervalComboPanel.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/RefreshIntervalComboPanel.java
new file mode 100644
index 0000000000..ae60467bf5
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/RefreshIntervalComboPanel.java
@@ -0,0 +1,131 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui;
+
+import org.apache.qpid.management.ui.jmx.MBeanUtility;
+import org.apache.qpid.management.ui.views.MBeanView;
+import org.apache.qpid.management.ui.views.NavigationView;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.menus.WorkbenchWindowControlContribution;
+
+public class RefreshIntervalComboPanel extends WorkbenchWindowControlContribution
+{
+ private Display _display = null;
+ private RefreshTask _refreshTask = null;
+
+ private static int DEFAULT_INDEX = 2; //15seconds
+ private static final int[] INTERVALS = new int[]{5,10,15,30,60,120,300,600};
+
+ public RefreshIntervalComboPanel()
+ {
+ super();
+ }
+
+ public RefreshIntervalComboPanel(String id)
+ {
+ super(id);
+ }
+
+ @Override
+ public Control createControl(Composite parent)
+ {
+ _display = parent.getDisplay();
+
+ Composite holder = new Composite(parent,SWT.NONE);
+ holder.setLayout(new GridLayout(2,false));
+ holder.setLayoutData(new GridData(SWT.LEFT,SWT.TOP,false,false));
+
+ Label refreshLabel = new Label(holder,SWT.NONE);
+ refreshLabel.setLayoutData(new GridData(SWT.LEFT,SWT.TOP,false,true));
+ refreshLabel.setText("Refresh Interval: ");
+
+ final Combo combo = new Combo(holder, SWT.NONE | SWT.DROP_DOWN | SWT.READ_ONLY);
+ combo.setLayoutData(new GridData(SWT.LEFT,SWT.TOP,false,false));
+ for(int i=0; i< INTERVALS.length ; i++)
+ {
+ combo.add(String.valueOf(INTERVALS[i]) + " seconds");
+ }
+ combo.select(DEFAULT_INDEX);
+
+ _refreshTask = new RefreshTask(INTERVALS[DEFAULT_INDEX]);
+ _display.timerExec(1000 * INTERVALS[DEFAULT_INDEX], _refreshTask);
+
+ combo.addModifyListener(
+ new ModifyListener()
+ {
+ public void modifyText(final ModifyEvent e)
+ {
+ _display.timerExec(-1, _refreshTask); //cancels existing refresh runnable
+ _refreshTask = new RefreshTask(INTERVALS[combo.getSelectionIndex()]);
+ _display.timerExec(0, _refreshTask); //immediately refresh and begin new schedule
+ }
+ });
+
+ return holder;
+ }
+
+
+ private class RefreshTask implements Runnable
+ {
+ private int seconds;
+
+ public RefreshTask(int secs)
+ {
+ this.seconds = secs;
+ }
+
+ @Override
+ public void run()
+ {
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if(window != null)
+ {
+ final MBeanView mbView = (MBeanView)window.getActivePage().findView(MBeanView.ID);
+
+ final NavigationView navView = (NavigationView)window.getActivePage().findView(NavigationView.ID);
+ try
+ {
+ mbView.refresh();
+ navView.refresh();
+ }
+ catch (Exception ex)
+ {
+ MBeanUtility.handleException(ex);
+ }
+
+ _display.timerExec(1000 * seconds, this);
+ }
+ }
+
+ }
+
+}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ServerRegistry.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ServerRegistry.java
index 313e143df5..027a555360 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ServerRegistry.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ServerRegistry.java
@@ -25,6 +25,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.qpid.management.ui.jmx.ClientListener;
import org.apache.qpid.management.ui.model.ManagedAttributeModel;
@@ -35,6 +36,9 @@ public abstract class ServerRegistry
{
private ManagedServer _managedServer = null;
+ // API version for the management interface on the broker
+ private ApiVersion _managementApiVersion = new ApiVersion(0,0);
+
// list of virtual hosts for this server
private List<String> _virtualHosts = new ArrayList<String>();
// map of all Connection mbeans
@@ -43,6 +47,10 @@ public abstract class ServerRegistry
private ConcurrentMap<String,List<ManagedBean>> _exchanges = new ConcurrentHashMap<String,List<ManagedBean>>();
// map of all queue mbenas
private ConcurrentMap<String,List<ManagedBean>> _queues = new ConcurrentHashMap<String,List<ManagedBean>>();
+ // map of all virtual host manager mbeans
+ private ConcurrentMap<String,ManagedBean> _vhostManagers = new ConcurrentHashMap<String,ManagedBean>();
+
+ private AtomicBoolean _serverConnectionClosed = new AtomicBoolean(false);
public ServerRegistry()
{
@@ -54,6 +62,26 @@ public abstract class ServerRegistry
_managedServer = server;
}
+ public void serverConnectionClosed()
+ {
+ _serverConnectionClosed.set(true);
+ }
+
+ public boolean isServerConnectionClosed()
+ {
+ return _serverConnectionClosed.get();
+ }
+
+ public void setManagementApiVersion(ApiVersion mgmtApiVersion)
+ {
+ _managementApiVersion = mgmtApiVersion;
+ }
+
+ public ApiVersion getManagementApiVersion()
+ {
+ return _managementApiVersion;
+ }
+
public ManagedServer getManagedServer()
{
return _managedServer;
@@ -85,6 +113,22 @@ public abstract class ServerRegistry
_queues.get(vHost).add(mbean);
}
+ protected void addVirtualHostManagerMBean(ManagedBean mbean)
+ {
+ String vHost = mbean.getVirtualHostName();
+ _vhostManagers.put(vHost, mbean);
+ }
+
+ protected void removeVirtualHostManagerMBean(ManagedBean mbean)
+ {
+ _vhostManagers.remove(mbean);
+ }
+
+ public ManagedBean getVirtualHostManagerMBean(String virtualHost)
+ {
+ return _vhostManagers.get(virtualHost);
+ }
+
protected void removeConnectionMBean(ManagedBean mbean)
{
_connections.get(mbean.getVirtualHostName()).remove(mbean);
@@ -115,6 +159,23 @@ public abstract class ServerRegistry
return _queues.get(virtualHost);
}
+ //returns the requested ManagedBean, or null if it cant be found
+ public ManagedBean getQueue(String queueName, String virtualHost)
+ {
+ ManagedBean requestedQueue = null;
+
+ for(ManagedBean queue : _queues.get(virtualHost))
+ {
+ if(queueName.equals(queue.getName()))
+ {
+ requestedQueue = queue;
+ break;
+ }
+ }
+
+ return requestedQueue;
+ }
+
public void addVirtualHost(String name)
{
if (!_virtualHosts.contains(name))
@@ -156,6 +217,8 @@ public abstract class ServerRegistry
public abstract List<NotificationObject> getNotifications(ManagedBean mbean);
+ public abstract List<NotificationObject> getNotifications(String virtualhost);
+
public abstract boolean hasSubscribedForNotifications(ManagedBean mbean, String name, String type);
public abstract void clearNotifications(ManagedBean mbean, List<NotificationObject> list);
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/AbstractAction.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/AbstractAction.java
index 53aa927299..5d892f5503 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/AbstractAction.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/AbstractAction.java
@@ -24,9 +24,15 @@ import static org.apache.qpid.management.ui.Constants.ERROR_SERVER_CONNECTION;
import java.io.IOException;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLKeyException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+
import org.apache.qpid.management.ui.ApplicationRegistry;
import org.apache.qpid.management.ui.ApplicationWorkbenchAdvisor;
import org.apache.qpid.management.ui.Constants;
+import org.apache.qpid.management.ui.exceptions.ManagementConsoleException;
import org.apache.qpid.management.ui.jmx.MBeanUtility;
import org.apache.qpid.management.ui.views.NavigationView;
import org.eclipse.core.runtime.IStatus;
@@ -43,10 +49,13 @@ public class AbstractAction
protected IWorkbenchWindow _window;
- public static final String RMI_SASL_ERROR = "non-JRMP server";
- public static final String SECURITY_FAILURE = "User authentication has failed";
- public static final String SERVER_UNAVAILABLE = "Qpid server is not running";
-
+ public static final String INVALID_PERSPECTIVE = "Invalid Perspective";
+ public static final String CHANGE_PERSPECTIVE = "Please use the Qpid Management Perspective";
+
+ private static final String SSL_EMPTY_TRUSTANCHORS = "the trustAnchors parameter must be non-empty";
+ private static final String SSL_UNABLE_TO_FIND_CERTPATH = "sun.security.provider.certpath.SunCertPathBuilderException: " +
+ "unable to find valid certification path to requested target";
+
/**
* We will cache window object in order to
* be able to provide parent shell for the message dialog.
@@ -71,52 +80,127 @@ public class AbstractAction
return _navigationView;
}
-
protected void handleException(Throwable ex, String title, String msg)
{
- MBeanUtility.printStackTrace(ex);
+ //ensure first that the exception is not due to running in the wrong eclipse perspective
+ NavigationView view = (NavigationView)_window.getActivePage().findView(NavigationView.ID);
+ if (view == null)
+ {
+ IStatus status = new Status(IStatus.WARNING, ApplicationWorkbenchAdvisor.PERSPECTIVE_ID,
+ IStatus.OK, CHANGE_PERSPECTIVE, null);
+ ErrorDialog.openError(_window.getShell(), "Warning", INVALID_PERSPECTIVE, status);
+ return;
+ }
+
+ //default title if none given
+ if (title == null)
+ {
+ title = ERROR_SERVER_CONNECTION;
+ }
+
+ //determine the error message to display
if (msg == null)
{
- if (ex instanceof IOException)
+ if (ex instanceof SSLException)
{
- if ((ex.getMessage() != null) && (ex.getMessage().indexOf(RMI_SASL_ERROR) != -1))
+ if (ex instanceof SSLKeyException)
{
- msg = SECURITY_FAILURE;
+ msg = "SSL key was invalid, please check the certificate configuration.";
+ //Display error dialogue and return
+ displayErrorDialogue(msg, title);
+ return;
+ }
+ else if (ex instanceof SSLPeerUnverifiedException)
+ {
+ msg = "SSL peer identity could not be verified, please ensure valid certificate configuration.";
+ //Display error dialogue and return
+ displayErrorDialogue(msg, title);
+ return;
+ }
+ else if (ex instanceof SSLHandshakeException)
+ {
+ if (ex.getMessage().contains(SSL_UNABLE_TO_FIND_CERTPATH))
+ {
+ msg = "Unable to certify the provided SSL certificate using the current SSL trust store.";
+ }
+ else
+ {
+ //cause unknown, provide a trace too
+ MBeanUtility.printStackTrace(ex);
+ msg = "SSL handhshake error.";
+ }
+ //Display error dialogue and return
+ displayErrorDialogue(msg, title);
+ return;
}
else
{
- msg = SERVER_UNAVAILABLE;
+ //general SSL Exception.
+ if (ex.getMessage().contains(SSL_EMPTY_TRUSTANCHORS))
+ {
+ msg = "Unable to locate the specified SSL certificate trust store, please check the configuration.";
+ }
+ else
+ {
+ //cause unknown, print stack trace
+ MBeanUtility.printStackTrace(ex);
+ msg = "SSL connection error.";
+ }
+ //Display error dialogue and return
+ displayErrorDialogue(msg, title);
+ return;
}
}
- else if (ex instanceof SecurityException)
+ else if (ex instanceof IOException || ex instanceof SecurityException )
{
- msg = SECURITY_FAILURE;
+ msg = ex.getMessage();
+
+ //if msg is still null, try reporting the cause.
+ if ((msg == null) && (ex.getCause() != null))
+ {
+ msg = ex.getCause().getMessage();
+ }
+
+ //Display error dialogue and return
+ displayErrorDialogue(msg, title);
+ return;
+ }
+ else if (ex instanceof ManagementConsoleException)
+ {
+ msg = ex.getMessage();
+ displayErrorDialogue(msg, title);
+ return;
}
else
{
+ //Unknown exception type/reason.
msg = ex.getMessage();
}
+
+ //if msg is still null, try reporting the cause.
+ if ((msg == null) && (ex.getCause() != null))
+ {
+ msg = ex.getCause().getMessage();
+ }
+
+ //failing all else, default non-descript error message.
+ if (msg == null)
+ {
+ msg = "An unknown error has occured.";
+ }
}
-
- if ((msg == null) && (ex.getCause() != null))
- {
- msg = ex.getCause().getMessage();
- }
-
- if (msg == null)
- {
- msg = ERROR_SERVER_CONNECTION;
- }
-
- if (title == null)
- {
- title = ERROR_SERVER_CONNECTION;
- }
- IStatus status = new Status(IStatus.ERROR, ApplicationWorkbenchAdvisor.PERSPECTIVE_ID,
- IStatus.OK, msg, null);
- ErrorDialog.openError(_window.getShell(), "Error", title, status);
+
+ //Display error dialogue and print the exception stack trace
+ MBeanUtility.printStackTrace(ex);
+ displayErrorDialogue(msg, title);
}
+ private void displayErrorDialogue(String msg, String title)
+ {
+ IStatus status = new Status(IStatus.ERROR, ApplicationWorkbenchAdvisor.PERSPECTIVE_ID,
+ IStatus.OK, msg, null);
+ ErrorDialog.openError(_window.getShell(), "Error", title, status);
+ }
/**
* Selection in the workbench has been changed. We can change the state of the 'real' action here
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/AddServer.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/AddServer.java
index 7a36ca6160..e487c02a67 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/AddServer.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/AddServer.java
@@ -28,13 +28,15 @@ import org.apache.qpid.management.ui.views.NumberVerifyListener;
import org.apache.qpid.management.ui.views.ViewUtility;
import org.eclipse.jface.action.IAction;
import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
@@ -43,12 +45,9 @@ import org.eclipse.ui.IWorkbenchWindowActionDelegate;
public class AddServer extends AbstractAction implements IWorkbenchWindowActionDelegate
{
- private static final String[] _domains ={"org.apache.qpid"};
-
- private String _transport = DEFAULT_PROTOCOL;
private String _host;
private String _port;
- private String _domain;
+ private String _domain = DEFAULT_DOMAIN;
private String _user;
private String _password;
@@ -70,7 +69,7 @@ public class AddServer extends AbstractAction implements IWorkbenchWindowActionD
{
if (_addServer)
{
- getNavigationView().addNewServer(_transport, _host, Integer.parseInt(_port), _domain, _user, _password);
+ getNavigationView().addNewServer(_host, Integer.parseInt(_port), _domain, _user, _password);
}
}
catch(InfoRequiredException ex)
@@ -88,7 +87,6 @@ public class AddServer extends AbstractAction implements IWorkbenchWindowActionD
_addServer = false;
_host = null;
_port = null;
- _domain = null;
_user = null;
_password = null;
}
@@ -100,17 +98,34 @@ public class AddServer extends AbstractAction implements IWorkbenchWindowActionD
*/
private void createAddServerPopup()
{
+ final Shell appShell = _window.getShell();
+
Display display = Display.getCurrent();
final Shell shell = new Shell(display, SWT.BORDER | SWT.CLOSE);
shell.setText(ACTION_ADDSERVER);
shell.setImage(ApplicationRegistry.getImage(CONSOLE_IMAGE));
shell.setLayout(new GridLayout());
- int x = display.getBounds().width;
- int y = display.getBounds().height;
- shell.setBounds(x/3, y/3, 425, 275);
-
createWidgets(shell);
+ shell.pack();
+
+ //get current size dialog, and application window size and location
+ int appWidth = appShell.getBounds().width;
+ int appHeight = appShell.getBounds().height;
+ int appLocX = appShell.getBounds().x;
+ int appLocY = appShell.getBounds().y;
+ int currentShellWidth = shell.getSize().x;
+ int currentShellHeight = shell.getSize().y;
+
+ //default sizes for the dialog
+ int minShellWidth = 425;
+ int minShellHeight= 265;
+ //ensure this is large enough, increase it if its not
+ int newShellWidth = currentShellWidth > minShellWidth ? currentShellWidth : minShellWidth;
+ int newShellHeight = currentShellHeight > minShellHeight ? currentShellHeight : minShellHeight;
+
+ //set the final size and centre the dialog within the app window
+ shell.setBounds((appWidth - newShellWidth)/2 + appLocX, (appHeight - newShellHeight)/2 + appLocY, newShellWidth, newShellHeight);
shell.open();
_window.getShell().setEnabled(false);
@@ -173,17 +188,6 @@ public class AddServer extends AbstractAction implements IWorkbenchWindowActionD
// Verify if the value entered is numeric
textPort.addVerifyListener(new NumberVerifyListener());
-
- Label domain = new Label(composite, SWT.NONE);
- domain.setText("Domain");
- domain.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, false, false));
-
- final Combo comboDomain = new Combo(composite, SWT.DROP_DOWN | SWT.READ_ONLY);
- comboDomain.setItems(_domains);
- comboDomain.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
- comboDomain.select(0);
-
-
Label user = new Label(composite, SWT.NONE);
user.setText(USERNAME);
user.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, false, false));
@@ -201,11 +205,27 @@ public class AddServer extends AbstractAction implements IWorkbenchWindowActionD
//textPwd.setEchoChar('*');
textPwd.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ //Get the text widgets
+ Control[] widgets = composite.getChildren();
+ for (int i=0; i < widgets.length; i++)
+ {
+ widgets[i].addKeyListener(new KeyAdapter()
+ {
+ public void keyPressed(KeyEvent event)
+ {
+ if (event.character == SWT.ESC)
+ {
+ //Escape key acts as cancel on all widgets
+ shell.dispose();
+ }
+ }
+ });
+ }
+
Composite buttonsComposite = new Composite(composite, SWT.NONE);
buttonsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
buttonsComposite.setLayout(new GridLayout(2, true));
-
final Button connectButton = new Button(buttonsComposite, SWT.PUSH | SWT.CENTER);
connectButton.setText(BUTTON_CONNECT);
GridData gridData = new GridData (SWT.TRAIL, SWT.BOTTOM, true, true);
@@ -251,7 +271,6 @@ public class AddServer extends AbstractAction implements IWorkbenchWindowActionD
return;
}
- _domain = comboDomain.getText();
_addServer = true;
shell.dispose();
}
@@ -263,12 +282,32 @@ public class AddServer extends AbstractAction implements IWorkbenchWindowActionD
gridData.widthHint = 100;
cancelButton.setLayoutData(gridData);
cancelButton.setFont(ApplicationRegistry.getFont(FONT_BUTTON));
- cancelButton.addSelectionListener(new SelectionAdapter(){
+ cancelButton.addSelectionListener(new SelectionAdapter()
+ {
public void widgetSelected(SelectionEvent event)
{
shell.dispose();
}
});
+
+ //Get the ok/cancel button widgets and add a new key listener
+ widgets = buttonsComposite.getChildren();
+ for (int i=0; i < widgets.length; i++)
+ {
+ widgets[i].addKeyListener(new KeyAdapter()
+ {
+ public void keyPressed(KeyEvent event)
+ {
+ if (event.character == SWT.ESC)
+ {
+ //Escape key acts as cancel on all widgets
+ shell.dispose();
+ }
+ }
+ });
+ }
+
+ shell.setDefaultButton(connectButton);
}
}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/BackAction.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/BackAction.java
new file mode 100644
index 0000000000..2998c5db53
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/BackAction.java
@@ -0,0 +1,59 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui.actions;
+
+import org.apache.qpid.management.ui.jmx.MBeanUtility;
+import org.apache.qpid.management.ui.views.MBeanView;
+import org.eclipse.jface.action.Action;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
+
+
+public class BackAction extends Action implements IWorkbenchAction
+{
+ private static final String ID = "org.apache.qpid.management.ui.actions.back";
+
+ public BackAction()
+ {
+ setText("Back");
+ setImageDescriptor(org.apache.qpid.management.ui.Activator.getImageDescriptor("/icons/back.gif"));
+ setId(ID);
+ }
+
+ public void run()
+ {
+ MBeanView mbeanview = (MBeanView)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().findView(MBeanView.ID);
+ try
+ {
+ mbeanview.back();
+ }
+ catch (Exception ex)
+ {
+ MBeanUtility.handleException(ex);
+ }
+
+ }
+
+ public void dispose()
+ {
+
+ }
+}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/EditAttribute.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/EditAttribute.java
deleted file mode 100644
index d3af3661b0..0000000000
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/EditAttribute.java
+++ /dev/null
@@ -1,51 +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.
- *
- */
-package org.apache.qpid.management.ui.actions;
-
-import static org.apache.qpid.management.ui.Constants.ACTION_EDITATTRIBUTE;
-import org.apache.qpid.management.ui.exceptions.InfoRequiredException;
-import org.apache.qpid.management.ui.views.MBeanView;
-import org.apache.qpid.management.ui.views.ViewUtility;
-import org.eclipse.jface.action.IAction;
-import org.eclipse.ui.IWorkbenchWindowActionDelegate;
-
-public class EditAttribute extends AbstractAction implements IWorkbenchWindowActionDelegate
-{
- public void run(IAction action)
- {
- if(_window != null)
- {
- MBeanView view = (MBeanView)_window.getActivePage().findView(MBeanView.ID);
- try
- {
- view.editAttribute();
- }
- catch(InfoRequiredException ex)
- {
- ViewUtility.popupInfoMessage(ACTION_EDITATTRIBUTE, ex.getMessage());
- }
- catch(Exception ex)
- {
- handleException(ex, "Attribute could not be edited", null);
- }
- }
- }
-}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/ReconnectServer.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/ReconnectServer.java
index dd9e792912..5eb9d9a168 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/ReconnectServer.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/ReconnectServer.java
@@ -34,12 +34,15 @@ import org.apache.qpid.management.ui.views.TreeObject;
import org.apache.qpid.management.ui.views.ViewUtility;
import org.eclipse.jface.action.IAction;
import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
@@ -96,17 +99,34 @@ public class ReconnectServer extends AbstractAction implements IWorkbenchWindowA
// Create the login popup fot th user to enter usernaem and password
private void createLoginPopup()
{
+ final Shell appShell = _window.getShell();
+
Display display = Display.getCurrent();
final Shell shell = new Shell(display, SWT.BORDER | SWT.CLOSE);
shell.setText(_title);
shell.setImage(ApplicationRegistry.getImage(CONSOLE_IMAGE));
shell.setLayout(new GridLayout());
- int x = display.getBounds().width;
- int y = display.getBounds().height;
- shell.setBounds(x/3, y/3, 350, 200);
-
- createWidgets(shell);
+ createWidgets(shell);
+ shell.pack();
+
+ //get current size dialog, and application window size and location
+ int appWidth = appShell.getBounds().width;
+ int appHeight = appShell.getBounds().height;
+ int appLocX = appShell.getBounds().x;
+ int appLocY = appShell.getBounds().y;
+ int currentShellWidth = shell.getSize().x;
+ int currentShellHeight = shell.getSize().y;
+
+ //default sizes for the dialog
+ int minShellWidth = 350;
+ int minShellHeight= 200;
+ //ensure this is large enough, increase it if its not
+ int newShellWidth = currentShellWidth > minShellWidth ? currentShellWidth : minShellWidth;
+ int newShellHeight = currentShellHeight > minShellHeight ? currentShellHeight : minShellHeight;
+
+ //set the final size and centre the dialog within the app window
+ shell.setBounds((appWidth - newShellWidth)/2 + appLocX, (appHeight - newShellHeight)/2 + appLocY, newShellWidth, newShellHeight);
shell.open();
_window.getShell().setEnabled(false);
@@ -155,11 +175,27 @@ public class ReconnectServer extends AbstractAction implements IWorkbenchWindowA
textPwd.setText("");
textPwd.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ //Get the text widgets
+ Control[] widgets = composite.getChildren();
+ for (int i=0; i < widgets.length; i++)
+ {
+ widgets[i].addKeyListener(new KeyAdapter()
+ {
+ public void keyPressed(KeyEvent event)
+ {
+ if (event.character == SWT.ESC)
+ {
+ //Escape key acts as cancel on all widgets
+ shell.dispose();
+ }
+ }
+ });
+ }
+
Composite buttonsComposite = new Composite(composite, SWT.NONE);
buttonsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
buttonsComposite.setLayout(new GridLayout(2, true));
-
final Button connectButton = new Button(buttonsComposite, SWT.PUSH | SWT.CENTER);
connectButton.setText(Constants.BUTTON_CONNECT);
GridData gridData = new GridData (SWT.TRAIL, SWT.BOTTOM, true, true);
@@ -203,7 +239,26 @@ public class ReconnectServer extends AbstractAction implements IWorkbenchWindowA
{
shell.dispose();
}
- });
+ });
+
+ //Get the ok/cancel button widgets and add a new key listener
+ widgets = buttonsComposite.getChildren();
+ for (int i=0; i < widgets.length; i++)
+ {
+ widgets[i].addKeyListener(new KeyAdapter()
+ {
+ public void keyPressed(KeyEvent event)
+ {
+ if (event.character == SWT.ESC)
+ {
+ //Escape key acts as cancel on all widgets
+ shell.dispose();
+ }
+ }
+ });
+ }
+
+ shell.setDefaultButton(connectButton);
}
}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/Refresh.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/Refresh.java
index 34251c12d7..dd4cbffd84 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/Refresh.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/Refresh.java
@@ -42,7 +42,7 @@ public class Refresh extends AbstractAction implements IWorkbenchWindowActionDel
MBeanView mbeanview = (MBeanView)_window.getActivePage().findView(MBeanView.ID);
try
{
- mbeanview.refreshMBeanView();
+ mbeanview.refresh();
}
catch (Exception ex)
{
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/VersionAction.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/VersionAction.java
index 11db02f5a2..be69fadbe8 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/VersionAction.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/VersionAction.java
@@ -57,6 +57,11 @@ public class VersionAction extends Action
_text = "Build Version : " + _buildVersion + "\n" +
"Release Version : " + _releaseVersion;
}
+ else
+ {
+ _text = "Build Version : \n" +
+ "Release Version : ";
+ }
}
catch (Exception ex)
{
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientListener.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientListener.java
index 2be0ddbebf..694f7ba86b 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientListener.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientListener.java
@@ -45,7 +45,6 @@ public class ClientListener implements NotificationListener
{
ObjectName objName = null;
String type = notification.getType();
- MBeanUtility.printOutput(type + ":" + objName);
if (MBeanServerNotification.REGISTRATION_NOTIFICATION.equals(type))
{
@@ -59,7 +58,13 @@ public class ClientListener implements NotificationListener
}
else if (JMXConnectionNotification.FAILED.equals(type))
{
- ApplicationRegistry.serverConnectionClosed(server);
+ ApplicationRegistry.serverConnectionClosedRemotely(server);
+ MBeanUtility.printOutput("JMX Connection to " + server.getName() + " failed.");
+ }
+ else if (JMXConnectionNotification.CLOSED.equals(type))
+ {
+ ApplicationRegistry.serverConnectionClosedRemotely(server);
+ MBeanUtility.printOutput("JMX Connection to " + server.getName() + " was closed.");
}
}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientNotificationListener.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientNotificationListener.java
index c6ecda4b4c..2af8e681ae 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientNotificationListener.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientNotificationListener.java
@@ -35,7 +35,6 @@ public class ClientNotificationListener extends ClientListener
public void handleNotification(Notification notification, Object handback)
{
ObjectName objName = (ObjectName)notification.getSource();
- //String type = notification.getType();
getServerRegistry().addNotification(objName, notification);
}
}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXServerRegistry.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXServerRegistry.java
index f671a1dc9a..717f781334 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXServerRegistry.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXServerRegistry.java
@@ -20,29 +20,23 @@
*/
package org.apache.qpid.management.ui.jmx;
-import static org.apache.qpid.management.ui.Constants.*;
+import static org.apache.qpid.management.ui.Constants.ALL;
-import java.lang.reflect.Constructor;
-import java.security.Security;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
-import javax.management.ListenerNotFoundException;
import javax.management.MBeanInfo;
import javax.management.MBeanServerConnection;
import javax.management.Notification;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
-import javax.management.remote.JMXConnectorFactory;
-import javax.management.remote.JMXServiceURL;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.sasl.SaslClientFactory;
+import org.apache.qpid.management.common.JMXConnnectionFactory;
import org.apache.qpid.management.ui.ApplicationRegistry;
import org.apache.qpid.management.ui.ManagedBean;
import org.apache.qpid.management.ui.ManagedServer;
@@ -51,21 +45,14 @@ import org.apache.qpid.management.ui.model.ManagedAttributeModel;
import org.apache.qpid.management.ui.model.NotificationInfoModel;
import org.apache.qpid.management.ui.model.NotificationObject;
import org.apache.qpid.management.ui.model.OperationDataModel;
-import org.apache.qpid.management.ui.sasl.JCAProvider;
-import org.apache.qpid.management.ui.sasl.SaslProvider;
-import org.apache.qpid.management.ui.sasl.UserPasswordCallbackHandler;
-import org.apache.qpid.management.ui.sasl.UsernameHashedPasswordCallbackHandler;
public class JMXServerRegistry extends ServerRegistry
{
- private boolean _connected = false;
private ObjectName _serverObjectName = null;
- private Map<String, Object> _env = null;
- private JMXServiceURL _jmxUrl = null;
private JMXConnector _jmxc = null;
private MBeanServerConnection _mbsc = null;
- private Exception _connectionException = null;
+ private String _securityMechanism = null;
private List<String> _usersList;
// When an mbean gets removed from mbean server, then the notification listener
@@ -98,140 +85,94 @@ public class JMXServerRegistry extends ServerRegistry
public JMXServerRegistry(ManagedServer server) throws Exception
{
super(server);
- String securityMechanism = ApplicationRegistry.getSecurityMechanism();
- String connectorClassName = ApplicationRegistry.getJMXConnectorClass();
-
- if ((securityMechanism != null) && (connectorClassName != null))
- {
- createSASLConnector(securityMechanism, connectorClassName);
- }
- else
- {
- _jmxUrl = new JMXServiceURL(server.getUrl());
- _jmxc = JMXConnectorFactory.connect(_jmxUrl, null);
- }
- _mbsc = _jmxc.getMBeanServerConnection();
+ _jmxc = JMXConnnectionFactory.getJMXConnection(
+ ApplicationRegistry.timeout, server.getHost(),
+ server.getPort(), server.getUser(), server.getPassword());
+ _mbsc = _jmxc.getMBeanServerConnection();
+
_clientListener = new ClientListener(server);
_notificationListener = new ClientNotificationListener(server);
-
- _jmxc.addConnectionNotificationListener(_clientListener, null, null);
+
+ _jmxc.addConnectionNotificationListener(_clientListener, null, null);
_serverObjectName = new ObjectName("JMImplementation:type=MBeanServerDelegate");
_mbsc.addNotificationListener(_serverObjectName, _clientListener, null, null);
+
}
-
+
public MBeanServerConnection getServerConnection()
{
return _mbsc;
}
-
- private void createSASLConnector(String mech, String className) throws Exception
- {
- String text = "Security mechanism " + mech + " is not supported.";
- // Check if the given connector, which supports SASL is available
- Class connectorClass = Class.forName(className);
-
- _jmxUrl = new JMXServiceURL("jmxmp", getManagedServer().getHost(), getManagedServer().getPort());
- _env = new HashMap<String, Object>();
- CallbackHandler handler;
- if (MECH_CRAMMD5.equals(mech))
- {
- // For SASL/CRAM-MD5
- Map<String, Class<? extends SaslClientFactory>> map = new HashMap<String, Class<? extends SaslClientFactory>>();
- Class<?> clazz = Class.forName("org.apache.qpid.management.ui.sasl.CRAMMD5HashedSaslClientFactory");
- map.put("CRAM-MD5-HASHED", (Class<? extends SaslClientFactory>) clazz);
-
- Security.addProvider(new JCAProvider(map));
- handler = new UsernameHashedPasswordCallbackHandler(getManagedServer().getUser(),
- getManagedServer().getPassword());
- _env.put("jmx.remote.profiles", SASL_CRAMMD5);
- _env.put("jmx.remote.sasl.callback.handler", handler);
-
- }
- else if (MECH_PLAIN.equals(mech))
- {
- // For SASL/PLAIN
- Security.addProvider(new SaslProvider());
- handler = new UserPasswordCallbackHandler(getManagedServer().getUser(), getManagedServer().getPassword());
- _env.put("jmx.remote.profiles", SASL_PLAIN);
- _env.put("jmx.remote.sasl.callback.handler", handler);
- }
- else
- {
- MBeanUtility.printOutput(text);
- throw new Exception(text);
- }
- // Now create the instance of JMXMPConnector
- Class[] paramTypes = {JMXServiceURL.class, Map.class};
- Constructor cons = connectorClass.getConstructor(paramTypes);
- Object[] args = {_jmxUrl, _env};
- Object theObject = cons.newInstance(args);
- _jmxc = (JMXConnector)theObject;
-
- Thread connectorThread = new Thread(new ConnectorThread());
- connectorThread.start();
- long timeNow = System.currentTimeMillis();
- connectorThread.join(ApplicationRegistry.timeout);
-
- if (_connectionException != null)
- {
- throw _connectionException;
- }
- if (!_connected)
- {
- if (System.currentTimeMillis() - timeNow >= ApplicationRegistry.timeout)
- throw new Exception("Qpid server connection timed out");
- else
- throw new Exception("Qpid server connection failed");
- }
- }
-
- private class ConnectorThread implements Runnable
+ public String getSecurityMechanism()
{
- public void run()
- {
- try
- {
- _connected = false;
- _connectionException = null;
-
- _jmxc.connect();
- _connected = true;
- }
- catch (Exception ex)
- {
- _connectionException = ex;
- MBeanUtility.printStackTrace(ex);
- }
- }
+ return _securityMechanism;
}
+
/**
* removes all listeners from the mbean server. This is required when user
* disconnects the Qpid server connection
*/
- public void closeServerConnection() throws Exception
+ public void closeServerConnection() throws IOException
{
+ if(isServerConnectionClosed())
+ {
+ //connection was already closed
+ return;
+ }
+
try
{
+ //remove the listener from the JMXConnector
if (_jmxc != null && _clientListener != null)
+ {
_jmxc.removeConnectionNotificationListener(_clientListener);
+ }
+ }
+ catch (Exception e)
+ {
+ //ignore
+ }
+ try
+ {
+ //remove the listener from the MBeanServerDelegate MBean
if (_mbsc != null && _clientListener != null)
+ {
_mbsc.removeNotificationListener(_serverObjectName, _clientListener);
+ }
+ }
+ catch (Exception e)
+ {
+ //ignore
+ }
- // remove mbean notification listeners
+ if (_mbsc != null && _clientListener != null)
+ {
+ //remove any listeners from the Qpid MBeans
for (String mbeanName : _subscribedNotificationMap.keySet())
{
- _mbsc.removeNotificationListener(new ObjectName(mbeanName), _notificationListener);
+ try
+ {
+ _mbsc.removeNotificationListener(new ObjectName(mbeanName), _notificationListener);
+ }
+ catch (Exception e)
+ {
+ //ignore
+ }
}
}
- catch (ListenerNotFoundException ex)
+
+ //close the JMXConnector
+ if (_jmxc != null)
{
- MBeanUtility.printOutput(ex.toString());
+ _jmxc.close();
}
+
+ serverConnectionClosed();
}
public ManagedBean getManagedObject(String uniqueName)
@@ -253,6 +194,10 @@ public class JMXServerRegistry extends ServerRegistry
{
addConnectionMBean(mbean);
}
+ else if (mbean.isVirtualHostManager())
+ {
+ addVirtualHostManagerMBean(mbean);
+ }
addVirtualHost(mbean.getVirtualHostName());
_mbeansMap.put(mbean.getUniqueName(), mbean);
@@ -260,7 +205,12 @@ public class JMXServerRegistry extends ServerRegistry
public void removeManagedObject(ManagedBean mbean)
{
- MBeanUtility.printOutput("Removing MBean:" + mbean.getUniqueName());
+ if (mbean == null)
+ {
+ return;
+ }
+
+ _mbeansMap.remove(mbean.getUniqueName());
if (mbean.isQueue())
{
@@ -274,8 +224,10 @@ public class JMXServerRegistry extends ServerRegistry
{
removeConnectionMBean(mbean);
}
-
- _mbeansMap.remove(mbean.getUniqueName());
+ else if (mbean.isVirtualHostManager())
+ {
+ removeVirtualHostManagerMBean(mbean);
+ }
}
public void putMBeanInfo(ManagedBean mbean, MBeanInfo mbeanInfo)
@@ -341,6 +293,38 @@ public class JMXServerRegistry extends ServerRegistry
}
}
+ public List<NotificationObject> getNotifications(String virtualhost)
+ {
+ List<NotificationObject> vhostNotificationsList = new ArrayList<NotificationObject>();
+
+ //iterate over all the notification lists for mbeans with subscribed notifications
+ for (List<NotificationObject> list : _notificationsMap.values())
+ {
+ if(list == null || list.isEmpty())
+ {
+ continue;
+ }
+
+ //Check the source vhost of the first notification
+ NotificationObject notification = list.get(0);
+
+ if (notification != null)
+ {
+ String sourceVhost = notification.getSourceVirtualHost();
+ if(sourceVhost != null)
+ {
+ if(sourceVhost.equalsIgnoreCase(virtualhost))
+ {
+ //If it matches, add the entire list as they are from the same vhost (same source mbean)
+ vhostNotificationsList.addAll(list);
+ }
+ }
+ }
+ }
+
+ return vhostNotificationsList;
+ }
+
public void clearNotifications(ManagedBean mbean, List<NotificationObject> list)
{
if (mbean == null)
@@ -520,11 +504,11 @@ public class JMXServerRegistry extends ServerRegistry
public void unregisterManagedObject(ObjectName objName)
{
ManagedBean mbean = _mbeansMap.get(objName.toString());
- removeManagedObject(mbean);
// Check if mbean was not available in the map. It can happen if mbean unregistration
// notification is received and the mbean is not added in the map.
if (mbean != null)
{
+ removeManagedObject(mbean);
_mbeansToBeRemoved.add(mbean);
}
}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/MBeanUtility.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/MBeanUtility.java
index 2d1883533b..2f5752db9b 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/MBeanUtility.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/MBeanUtility.java
@@ -20,9 +20,10 @@
*/
package org.apache.qpid.management.ui.jmx;
+import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -37,10 +38,14 @@ import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.MalformedObjectNameException;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.ReflectionException;
+import org.apache.qpid.management.common.mbeans.ServerInformation;
+import org.apache.qpid.management.ui.ApiVersion;
import org.apache.qpid.management.ui.ApplicationRegistry;
import org.apache.qpid.management.ui.ManagedBean;
import org.apache.qpid.management.ui.ManagedServer;
@@ -173,6 +178,10 @@ public class MBeanUtility
{
ViewUtility.popupErrorMessage(mbean.getInstanceName(), ex.getMessage());
}
+ else if (ex instanceof SecurityException)
+ {
+ ViewUtility.popupErrorMessage(mbean.getInstanceName(), ex.getMessage());
+ }
else
{
if (ex.getCause() != null)
@@ -267,6 +276,72 @@ public class MBeanUtility
return value;
}
+
+ /**
+ * Returns a List of Object arrays containing the requested attribute values (in the same sequence requested) for each queue in the virtualhost.
+ * If a particular attribute cant be found or raises an mbean/reflection exception whilst being gathered its value is substituted with the String "-".
+ */
+ public static List<List<Object>> getQueueAttributes(List<ManagedBean> mbeans, String[] attributes)
+ {
+ List<List<Object>> results = new ArrayList<List<Object>>();
+
+ MBeanServerConnection mbsc = null;
+ if(mbeans.isEmpty())
+ {
+ return results;
+ }
+ else
+ {
+ ManagedBean mbean = mbeans.get(0);
+ JMXServerRegistry serverRegistry = (JMXServerRegistry)ApplicationRegistry.getServerRegistry(mbean);
+ mbsc = serverRegistry.getServerConnection();
+ }
+
+ if(mbsc == null)
+ {
+ return results;
+ }
+
+ for(ManagedBean mbean : mbeans)
+ {
+ HashMap<String,Object> tempResults = new HashMap<String,Object>();
+
+ ObjectName objName = ((JMXManagedObject)mbean).getObjectName();
+ try
+ {
+ AttributeList list = mbsc.getAttributes(objName, attributes);
+
+ for (Attribute attr : list.toArray(new Attribute[0]))
+ {
+ tempResults.put(attr.getName(), attr.getValue());
+ }
+
+ List<Object> attributeValues = new ArrayList<Object>(attributes.length);
+
+ for(int i = 0; i <attributes.length; i++)
+ {
+ if(tempResults.containsKey(attributes[i]))
+ {
+ attributeValues.add(tempResults.get(attributes[i]));
+ }
+ else
+ {
+ attributeValues.add(new String("-"));
+ }
+ }
+
+ results.add(attributeValues);
+ }
+ catch (Exception ignore)
+ {
+ continue;
+ }
+ }
+
+ return results;
+ }
+
+
/**
* Retrieves the attribute values from MBeanSever and stores in the server registry.
* @param mbean
@@ -437,15 +512,70 @@ public class MBeanUtility
}
/**
- * Returns all the domains for the given server. This method can be removed as now this RCP is specific to
- * Qpid and domain is also fixed
+ * Classifies the management API version of the given server
+ * @return list of ManagedBeans
+ * @throws NullPointerException
+ * @throws ManagementConsoleException
+ * @throws MalformedObjectNameException
+ * @throws IOException
*/
- public static List<String> getAllDomains(ManagedServer server) throws Exception
+ public static void classifyManagementApiVersion(ManagedServer server, JMXServerRegistry serverRegistry)
+ throws MalformedObjectNameException, NullPointerException, IOException
{
- JMXServerRegistry serverRegistry = (JMXServerRegistry)ApplicationRegistry.getServerRegistry(server);
MBeanServerConnection mbsc = serverRegistry.getServerConnection();
- String[] domains = mbsc.getDomains();
- return Arrays.asList(domains);
+
+ //Detect if the ServerInformation MBean is present, and use it to retrieve the API version.
+ ObjectName objName = new ObjectName(server.getDomain() + ":type="+ ServerInformation.TYPE + ",*");
+ Set<ObjectName> objectInstances = mbsc.queryNames(objName, null);
+
+ if(objectInstances.size() != 0)
+ {
+ for (Iterator<ObjectName> itr = objectInstances.iterator(); itr.hasNext();)
+ {
+ ObjectName instance = (ObjectName)itr.next();
+ ServerInformation simb = (ServerInformation)
+ MBeanServerInvocationHandler.newProxyInstance(mbsc,
+ instance, ServerInformation.class, false);
+
+ int major = simb.getManagementApiMajorVersion();
+ int minor = simb.getManagementApiMinorVersion();
+
+ serverRegistry.setManagementApiVersion(new ApiVersion(major, minor));
+ }
+
+ return;
+ }
+
+ //ServerInformation mbean was not present, so this is a older pre-v1.3 API server.
+
+ //Detect the value of the 'version' key property on the UserManagement MBean ObjectName.
+ //If present, we have a v1.2 API server. If null, we have a v1.1 API server.
+ //Use an ObjectName pattern (the ?) to match the 'type' and allow this to work for non-admin users
+ objName = new ObjectName(server.getDomain() + ":type="+ "UserManagemen?" + ",*");
+ objectInstances = mbsc.queryNames(objName, null);
+
+ if(objectInstances.size() != 0)
+ {
+ for (Iterator<ObjectName> itr = objectInstances.iterator(); itr.hasNext();)
+ {
+ ObjectName instance = (ObjectName)itr.next();
+ String version = instance.getKeyProperty("version");
+
+ if(version != null)
+ {
+ serverRegistry.setManagementApiVersion(new ApiVersion(1, 2));
+ }
+ else
+ {
+ serverRegistry.setManagementApiVersion(new ApiVersion(1, 1));
+ }
+ }
+ }
+ else
+ {
+ //UserManagement MBean wasnt present, connected to an old server: classify as v1.0 API
+ serverRegistry.setManagementApiVersion(new ApiVersion(1, 0));
+ }
}
public static void printOutput(String statement)
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/NotificationObject.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/NotificationObject.java
index 926e5f0a24..e42b3c53b6 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/NotificationObject.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/NotificationObject.java
@@ -26,6 +26,8 @@ import java.util.TimeZone;
import javax.management.ObjectName;
+import static org.apache.qpid.management.ui.Constants.VIRTUAL_HOST;
+
public class NotificationObject
{
@@ -65,6 +67,16 @@ public class NotificationObject
return null;
}
+ public String getSourceVirtualHost()
+ {
+ if (_source instanceof ObjectName)
+ {
+ return ((ObjectName)_source).getKeyProperty(VIRTUAL_HOST);
+ }
+
+ return null;
+ }
+
public String getMessage()
{
return _message;
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/CRAMMD5HashedSaslClientFactory.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/CRAMMD5HashedSaslClientFactory.java
deleted file mode 100644
index 32a0c12344..0000000000
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/CRAMMD5HashedSaslClientFactory.java
+++ /dev/null
@@ -1,60 +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.
- *
- */
-package org.apache.qpid.management.ui.sasl;
-
-import java.util.Map;
-
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.sasl.Sasl;
-import javax.security.sasl.SaslClient;
-import javax.security.sasl.SaslClientFactory;
-import javax.security.sasl.SaslException;
-
-public class CRAMMD5HashedSaslClientFactory implements SaslClientFactory
-{
- /** The name of this mechanism */
- public static final String MECHANISM = "CRAM-MD5-HASHED";
-
- public SaslClient createSaslClient(String[] mechanisms, String authorizationId, String protocol,
- String serverName, Map<String, ?> props, CallbackHandler cbh)
- throws SaslException
- {
- for (int i = 0; i < mechanisms.length; i++)
- {
- if (mechanisms[i].equals(MECHANISM))
- {
- if (cbh == null)
- {
- throw new SaslException("CallbackHandler must not be null");
- }
-
- String[] mechs = {"CRAM-MD5"};
- return Sasl.createSaslClient(mechs, authorizationId, protocol, serverName, props, cbh);
- }
- }
- return null;
- }
-
- public String[] getMechanismNames(Map props)
- {
- return new String[]{MECHANISM};
- }
-}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/ClientSaslFactory.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/ClientSaslFactory.java
deleted file mode 100644
index ce9a273eaa..0000000000
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/ClientSaslFactory.java
+++ /dev/null
@@ -1,54 +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.
- *
- */
-package org.apache.qpid.management.ui.sasl;
-
-import java.util.Map;
-
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.sasl.SaslClient;
-import javax.security.sasl.SaslClientFactory;
-import javax.security.sasl.SaslException;
-
-public class ClientSaslFactory implements SaslClientFactory
-{
- public SaslClient createSaslClient(String[] mechs, String authorizationId, String protocol,
- String serverName, Map props, CallbackHandler cbh)
- throws SaslException
- {
- for (int i = 0; i < mechs.length; i++)
- {
- if (mechs[i].equals("PLAIN"))
- {
- return new PlainSaslClient(authorizationId, cbh);
- }
- }
- return null;
- }
-
- /**
- * Simple-minded implementation that ignores props
- */
- public String[] getMechanismNames(Map props)
- {
- return new String[]{"PLAIN"};
- }
-
-}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/JCAProvider.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/JCAProvider.java
deleted file mode 100644
index d8189f3ac3..0000000000
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/JCAProvider.java
+++ /dev/null
@@ -1,56 +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.
- *
- */
-package org.apache.qpid.management.ui.sasl;
-
-import java.security.Provider;
-import java.util.Map;
-
-import javax.security.sasl.SaslClientFactory;
-
-public class JCAProvider extends Provider
-{
- private static final long serialVersionUID = 1L;
-
- /**
- * Creates the security provider with a map from SASL mechanisms to implementing factories.
- *
- * @param providerMap The map from SASL mechanims to implementing factory classes.
- */
- public JCAProvider(Map<String, Class<? extends SaslClientFactory>> providerMap)
- {
- super("AMQSASLProvider", 1.0, "A JCA provider that registers all "
- + "AMQ SASL providers that want to be registered");
- register(providerMap);
- }
-
- /**
- * Registers client factory classes for a map of mechanism names to client factory classes.
- *
- * @param providerMap The map from SASL mechanims to implementing factory classes.
- */
- private void register(Map<String, Class<? extends SaslClientFactory>> providerMap)
- {
- for (Map.Entry<String, Class<? extends SaslClientFactory>> me : providerMap.entrySet())
- {
- put("SaslClientFactory." + me.getKey(), me.getValue().getName());
- }
- }
-}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/PlainSaslClient.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/PlainSaslClient.java
deleted file mode 100644
index 22190f29eb..0000000000
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/PlainSaslClient.java
+++ /dev/null
@@ -1,203 +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.
- *
- */
-package org.apache.qpid.management.ui.sasl;
-
-import java.io.*;
-import javax.security.auth.callback.*;
-import javax.security.sasl.*;
-
-public class PlainSaslClient implements SaslClient
-{
-
- private boolean completed;
- private CallbackHandler cbh;
- private String authorizationID;
- private String authenticationID;
- private byte password[];
- private static byte SEPARATOR = 0;
-
- public PlainSaslClient(String authorizationID, CallbackHandler cbh) throws SaslException
- {
- completed = false;
- this.cbh = cbh;
- Object[] userInfo = getUserInfo();
- this.authorizationID = authorizationID;
- this.authenticationID = (String) userInfo[0];
- this.password = (byte[]) userInfo[1];
- if (authenticationID == null || password == null)
- {
- throw new SaslException("PLAIN: authenticationID and password must be specified");
- }
- }
-
- public byte[] evaluateChallenge(byte[] challenge) throws SaslException
- {
- if (completed)
- {
- throw new IllegalStateException("PLAIN: authentication already " +
- "completed");
- }
- completed = true;
- try
- {
- byte authzid[] =
- authorizationID == null ? null : authorizationID.getBytes("UTF8");
- byte authnid[] = authenticationID.getBytes("UTF8");
- byte response[] =
- new byte[
- password.length +
- authnid.length +
- 2 + // SEPARATOR
- (authzid != null ? authzid.length : 0)
- ];
- int size = 0;
- if (authzid != null) {
- System.arraycopy(authzid, 0, response, 0, authzid.length);
- size = authzid.length;
- }
- response[size++] = SEPARATOR;
- System.arraycopy(authnid, 0, response, size, authnid.length);
- size += authnid.length;
- response[size++] = SEPARATOR;
- System.arraycopy(password, 0, response, size, password.length);
- clearPassword();
- return response;
- } catch (UnsupportedEncodingException e) {
- throw new SaslException("PLAIN: Cannot get UTF-8 encoding of ids",
- e);
- }
- }
-
- public String getMechanismName()
- {
- return "PLAIN";
- }
-
- public boolean hasInitialResponse()
- {
- return true;
- }
-
- public boolean isComplete()
- {
- return completed;
- }
-
- public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException
- {
- if (completed) {
- throw new IllegalStateException("PLAIN: this mechanism supports " +
- "neither integrity nor privacy");
- } else {
- throw new IllegalStateException("PLAIN: authentication not " +
- "completed");
- }
- }
-
- public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException
- {
- if (completed)
- {
- throw new IllegalStateException("PLAIN: this mechanism supports " +
- "neither integrity nor privacy");
- }
- else
- {
- throw new IllegalStateException("PLAIN: authentication not " +
- "completed");
- }
- }
-
- public Object getNegotiatedProperty(String propName)
- {
- if (completed)
- {
- if (propName.equals(Sasl.QOP))
- {
- return "auth";
- }
- else
- {
- return null;
- }
- }
- else
- {
- throw new IllegalStateException("PLAIN: authentication not " +
- "completed");
- }
- }
-
- private void clearPassword()
- {
- if (password != null)
- {
- for (int i = 0 ; i < password.length ; i++)
- {
- password[i] = 0;
- }
- password = null;
- }
- }
-
- public void dispose() throws SaslException
- {
- clearPassword();
- }
-
- protected void finalize()
- {
- clearPassword();
- }
-
- private Object[] getUserInfo() throws SaslException
- {
- try
- {
- final String userPrompt = "PLAIN authentication id: ";
- final String pwPrompt = "PLAIN password: ";
- NameCallback nameCb = new NameCallback(userPrompt);
- PasswordCallback passwordCb = new PasswordCallback(pwPrompt, false);
- cbh.handle(new Callback[] { nameCb, passwordCb });
- String userid = nameCb.getName();
- char pwchars[] = passwordCb.getPassword();
- byte pwbytes[];
- if (pwchars != null)
- {
- pwbytes = (new String(pwchars)).getBytes("UTF8");
- passwordCb.clearPassword();
- }
- else
- {
- pwbytes = null;
- }
- return (new Object[] { userid, pwbytes });
- }
- catch (IOException e)
- {
- throw new SaslException("Cannot get password", e);
- }
- catch (UnsupportedCallbackException e)
- {
- throw new SaslException("Cannot get userid/password", e);
- }
- }
-}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/SaslProvider.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/SaslProvider.java
deleted file mode 100644
index 2917de8740..0000000000
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/SaslProvider.java
+++ /dev/null
@@ -1,35 +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.
- *
- */
-package org.apache.qpid.management.ui.sasl;
-
-import java.security.Provider;
-
-public class SaslProvider extends Provider
-{
- private static final long serialVersionUID = -6978096016899676466L;
-
- public SaslProvider()
- {
- super("SaslClientFactory", 1.0, "SASL PLAIN CLIENT MECHANISM");
- put("SaslClientFactory.PLAIN", "ClientSaslFactory");
- }
-
-}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/UserPasswordCallbackHandler.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/UserPasswordCallbackHandler.java
deleted file mode 100644
index 1602229c85..0000000000
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/UserPasswordCallbackHandler.java
+++ /dev/null
@@ -1,73 +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.
- *
- */
-package org.apache.qpid.management.ui.sasl;
-
-import java.io.*;
-import javax.security.auth.callback.*;
-
-public class UserPasswordCallbackHandler implements CallbackHandler
-{
- private String user;
- private char[] pwchars;
-
- public UserPasswordCallbackHandler(String user, String password)
- {
- this.user = user;
- this.pwchars = password.toCharArray();
- }
-
- public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
- {
- for (int i = 0; i < callbacks.length; i++)
- {
- if (callbacks[i] instanceof NameCallback)
- {
- NameCallback ncb = (NameCallback) callbacks[i];
- ncb.setName(user);
- }
- else if (callbacks[i] instanceof PasswordCallback)
- {
- PasswordCallback pcb = (PasswordCallback) callbacks[i];
- pcb.setPassword(pwchars);
- }
- else
- {
- throw new UnsupportedCallbackException(callbacks[i]);
- }
- }
- }
-
- private void clearPassword()
- {
- if (pwchars != null)
- {
- for (int i = 0 ; i < pwchars.length ; i++)
- {
- pwchars[i] = 0;
- }
- pwchars = null;
- }
- }
-
- protected void finalize()
- {
- clearPassword();
- }
-}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/UsernameHashedPasswordCallbackHandler.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/UsernameHashedPasswordCallbackHandler.java
deleted file mode 100644
index f4e3d2661e..0000000000
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/UsernameHashedPasswordCallbackHandler.java
+++ /dev/null
@@ -1,82 +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.
- *
- */
-package org.apache.qpid.management.ui.sasl;
-
-import java.io.IOException;
-
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.UnsupportedCallbackException;
-
-import org.apache.qpid.management.ui.views.ViewUtility;
-
-public class UsernameHashedPasswordCallbackHandler implements CallbackHandler
-{
- private String user;
- private char[] pwchars;
-
- public UsernameHashedPasswordCallbackHandler(String user, String password) throws Exception
- {
- this.user = user;
- this.pwchars = ViewUtility.getHash(password);
- }
-
- public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
- {
- for (int i = 0; i < callbacks.length; i++)
- {
- if (callbacks[i] instanceof NameCallback)
- {
- NameCallback ncb = (NameCallback) callbacks[i];
- ncb.setName(user);
- }
- else if (callbacks[i] instanceof PasswordCallback)
- {
- PasswordCallback pcb = (PasswordCallback) callbacks[i];
- pcb.setPassword(pwchars);
- }
- else
- {
- throw new UnsupportedCallbackException(callbacks[i]);
- }
- }
- }
-
-
- private void clearPassword()
- {
- if (pwchars != null)
- {
- for (int i = 0 ; i < pwchars.length ; i++)
- {
- pwchars[i] = 0;
- }
- pwchars = null;
- }
- }
-
- protected void finalize()
- {
- clearPassword();
- }
-}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/AttributesTabControl.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/AttributesTabControl.java
index 3234503fb5..f21647b2d2 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/AttributesTabControl.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/AttributesTabControl.java
@@ -74,8 +74,8 @@ import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
-import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
/**
@@ -85,10 +85,10 @@ import org.eclipse.ui.forms.widgets.FormToolkit;
public class AttributesTabControl extends TabControl
{
private FormToolkit _toolkit;
- private Form _form;
+ private ScrolledForm _form;
private Table _table = null;
private TableViewer _tableViewer = null;
- private static final int[] tableWidths = new int[] {300, 300};
+ private int[] tableWidths = new int[] {275, 275};
private Composite _tableComposite = null;
private Composite _buttonsComposite = null;
@@ -98,7 +98,6 @@ public class AttributesTabControl extends TabControl
private Button _detailsButton = null;
private Button _editButton = null;
private Button _graphButton = null;
- private Button _refreshButton = null;
private boolean disableEditing = false;
private static final String MAX_VALUE = "MaxValue";
@@ -113,7 +112,7 @@ public class AttributesTabControl extends TabControl
{
super(tabFolder);
_toolkit = new FormToolkit(_tabFolder.getDisplay());
- _form = _toolkit.createForm(_tabFolder);
+ _form = _toolkit.createScrolledForm(_tabFolder);
GridLayout gridLayout = new GridLayout(2, false);
gridLayout.marginWidth = 0;
gridLayout.marginHeight = 0;
@@ -122,7 +121,7 @@ public class AttributesTabControl extends TabControl
_tableComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
_tableComposite.setLayout(new GridLayout());
_buttonsComposite = _toolkit.createComposite(_form.getBody());
- _buttonsComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, true));
+ _buttonsComposite.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, true));
_buttonsComposite.setLayout(new GridLayout());
image = Display.getCurrent().getSystemImage(SWT.ICON_INFORMATION);
@@ -162,7 +161,7 @@ public class AttributesTabControl extends TabControl
final TableColumn column = new TableColumn(_table, SWT.NONE);
column.setText(ATTRIBUTE_TABLE_TITLES[i]);
column.setWidth(tableWidths[i]);
- column.setResizable(false);
+ column.setResizable(true);
}
_table.setLinesVisible (true);
@@ -187,7 +186,6 @@ public class AttributesTabControl extends TabControl
addDetailsButton();
addEditButton();
addGraphButton();
- addRefreshButton();
}
private void addDetailsButton()
@@ -195,7 +193,7 @@ public class AttributesTabControl extends TabControl
// Create and configure the button for attribute details
_detailsButton = _toolkit.createButton(_buttonsComposite, BUTTON_DETAILS, SWT.PUSH | SWT.CENTER);
_detailsButton.setFont(ApplicationRegistry.getFont(FONT_BUTTON));
- GridData gridData = new GridData(SWT.CENTER, SWT.TOP, false, false);
+ GridData gridData = new GridData(SWT.FILL, SWT.TOP, false, false);
gridData.widthHint = 80;
_detailsButton.setLayoutData(gridData);
_detailsButton.addSelectionListener(new SelectionAdapter()
@@ -220,7 +218,7 @@ public class AttributesTabControl extends TabControl
// Create and configure the button for editing attribute
_editButton = _toolkit.createButton(_buttonsComposite, BUTTON_EDIT_ATTRIBUTE, SWT.PUSH | SWT.CENTER);
_editButton.setFont(ApplicationRegistry.getFont(FONT_BUTTON));
- GridData gridData = new GridData(SWT.CENTER, SWT.TOP, false, false);
+ GridData gridData = new GridData(SWT.FILL, SWT.TOP, false, false);
gridData.widthHint = 80;
_editButton.setLayoutData(gridData);
_editButton.addSelectionListener(new SelectionAdapter()
@@ -242,7 +240,7 @@ public class AttributesTabControl extends TabControl
{
_graphButton = _toolkit.createButton(_buttonsComposite, BUTTON_GRAPH, SWT.PUSH | SWT.CENTER);
_graphButton.setFont(ApplicationRegistry.getFont(FONT_BUTTON));
- GridData gridData = new GridData(SWT.CENTER, SWT.TOP, false, false);
+ GridData gridData = new GridData(SWT.FILL, SWT.TOP, false, false);
gridData.widthHint = 80;
_graphButton.setLayoutData(gridData);
_graphButton.addSelectionListener(new SelectionAdapter()
@@ -256,35 +254,6 @@ public class AttributesTabControl extends TabControl
}
});
}
-
- /**
- * Creates the "Refresh" button
- */
- private void addRefreshButton()
- {
- _refreshButton = _toolkit.createButton(_buttonsComposite, BUTTON_REFRESH, SWT.PUSH | SWT.CENTER);
-
- _refreshButton.setFont(ApplicationRegistry.getFont(FONT_BUTTON));
- GridData gridData = new GridData(SWT.CENTER, SWT.TOP, false, false);
- gridData.widthHint = 80;
- _refreshButton.setLayoutData(gridData);
- _refreshButton.addSelectionListener(new SelectionAdapter()
- {
- public void widgetSelected(SelectionEvent e)
- {
- try
- {
- // refresh the attributes list
- refresh(_mbean);
- }
- catch (Exception ex)
- {
- MBeanUtility.handleException(_mbean, ex);
- }
-
- }
- });
- }
private void addTableListeners()
{
@@ -509,10 +478,24 @@ public class AttributesTabControl extends TabControl
{
if (!isSimpleType(attribute.getValue()))
{
- Composite composite = new Composite(parent, SWT.BORDER);
- composite.setLayout(new GridLayout());
- composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
- ViewUtility.populateCompositeWithData(_toolkit, composite, attribute.getValue());
+ if (attribute.getValue() instanceof String[])
+ {
+ String result = new String("");
+ for(String val : (String[]) attribute.getValue()){
+ result = result.concat(val+ "; ");
+ }
+ value = _toolkit.createText(parent, "", textStyle);
+
+ value.setText(result);
+ value.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ }
+ else
+ {
+ Composite composite = new Composite(parent, SWT.BORDER);
+ composite.setLayout(new GridLayout());
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ ViewUtility.populateCompositeWithData(_toolkit, composite, attribute.getValue());
+ }
}
else
{
@@ -574,7 +557,7 @@ public class AttributesTabControl extends TabControl
AttributeData data = (AttributeData)button.getParent().getData();
MBeanUtility.updateAttribute(_mbean, data, text.getText());
button.getShell().close();
- refresh();
+ refresh(_mbean);
}
catch (Exception ex)
{
@@ -586,14 +569,6 @@ public class AttributesTabControl extends TabControl
return updateButton;
}
- // Refresh from the server registry
- public void refresh()
- {
- JMXServerRegistry serverRegistry = (JMXServerRegistry)ApplicationRegistry.getServerRegistry(_mbean);
- ManagedAttributeModel attributesList = serverRegistry.getAttributeModel(_mbean);
- _tableViewer.setInput(attributesList);
- }
-
/**
* Refreshes the attribute tab by querying the mbean server for latest values
*/
@@ -642,12 +617,10 @@ public class AttributesTabControl extends TabControl
_detailsButton.setEnabled(false);
_editButton.setEnabled(false);
_graphButton.setEnabled(false);
- _refreshButton.setEnabled(false);
return;
}
_detailsButton.setEnabled(true);
- _refreshButton.setEnabled(true);
if (attribute.isWritable())
{
_editButton.setEnabled(true);
@@ -877,7 +850,16 @@ public class AttributesTabControl extends TabControl
break;
case 1 : // attribute value column
if (attribute.getValue() != null)
- result = String.valueOf(attribute.getValue());
+ if (attribute.getValue() instanceof String[])
+ {
+ for(String val : (String[]) attribute.getValue()){
+ result = result.concat(val+ "; ");
+ }
+ }
+ else
+ {
+ result = String.valueOf(attribute.getValue());
+ }
break;
default :
result = "";
@@ -900,7 +882,7 @@ public class AttributesTabControl extends TabControl
{
attribute = (AttributeData) element;
if (attribute.isWritable())
- return Display.getCurrent().getSystemColor(SWT.COLOR_DARK_BLUE);
+ return Display.getCurrent().getSystemColor(SWT.COLOR_BLUE);
else
return Display.getCurrent().getSystemColor(SWT.COLOR_BLACK);
}
@@ -933,4 +915,4 @@ public class AttributesTabControl extends TabControl
return collator.compare(attribtue1.getName(), attribtue2.getName());
}
}
-} \ No newline at end of file
+}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/ConnectionTypeTabControl.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/ConnectionTypeTabControl.java
deleted file mode 100644
index d891a45210..0000000000
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/ConnectionTypeTabControl.java
+++ /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.
- *
- */
-
-package org.apache.qpid.management.ui.views;
-
-import org.apache.qpid.management.ui.ApplicationRegistry;
-import org.apache.qpid.management.ui.Constants;
-import org.apache.qpid.management.ui.ManagedBean;
-import org.apache.qpid.management.ui.ServerRegistry;
-import org.eclipse.swt.widgets.TabFolder;
-
-/**
- * Controller class, which takes care of displaying appropriate information and widgets for Connections.
- * This allows user to select Connections and add those to the navigation view
- */
-public class ConnectionTypeTabControl extends MBeanTypeTabControl
-{
-
- public ConnectionTypeTabControl(TabFolder tabFolder)
- {
- super(tabFolder, Constants.CONNECTION);
- createWidgets();
- }
-
- protected void createWidgets()
- {
- createHeaderComposite(getFormComposite());
- createButtonsComposite(getFormComposite());
- createListComposite(getFormComposite());
- }
-
- protected void populateList() throws Exception
- {
- // map should be cleared before populating it with new values
- getMBeansMap().clear();
-
- ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(MBeanView.getServer());
- java.util.List<ManagedBean> list = serverRegistry.getConnections(MBeanView.getVirtualHost());
- getListWidget().setItems(getItems(list));
- }
-}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/ExchangeTypeTabControl.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/ExchangeTypeTabControl.java
deleted file mode 100644
index ee55b251ee..0000000000
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/ExchangeTypeTabControl.java
+++ /dev/null
@@ -1,60 +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.
- *
- */
-
-package org.apache.qpid.management.ui.views;
-
-import org.apache.qpid.management.ui.ApplicationRegistry;
-import org.apache.qpid.management.ui.Constants;
-import org.apache.qpid.management.ui.ManagedBean;
-import org.apache.qpid.management.ui.ServerRegistry;
-import org.eclipse.swt.widgets.TabFolder;
-
-/**
- * Controller class, which takes care of displaying appropriate information and widgets for Exchanges.
- * This allows user to select Exchanges and add those to the navigation view
- * @author Bhupendra Bhardwaj
- */
-public class ExchangeTypeTabControl extends MBeanTypeTabControl
-{
-
- public ExchangeTypeTabControl(TabFolder tabFolder)
- {
- super(tabFolder, Constants.EXCHANGE);
- createWidgets();
- }
-
- protected void createWidgets()
- {
- createHeaderComposite(getFormComposite());
- createButtonsComposite(getFormComposite());
- createListComposite(getFormComposite());
- }
-
- protected void populateList() throws Exception
- {
- // map should be cleared before populating it with new values
- getMBeansMap().clear();
-
- ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(MBeanView.getServer());
- java.util.List<ManagedBean> list = serverRegistry.getExchanges(MBeanView.getVirtualHost());
- getListWidget().setItems(getItems(list));
- }
-}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanTabFolderFactory.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanTabFolderFactory.java
new file mode 100644
index 0000000000..1fef89d6b5
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanTabFolderFactory.java
@@ -0,0 +1,464 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui.views;
+
+import static org.apache.qpid.management.ui.Constants.ATTRIBUTES;
+import static org.apache.qpid.management.ui.Constants.CONNECTION;
+import static org.apache.qpid.management.ui.Constants.EXCHANGE;
+import static org.apache.qpid.management.ui.Constants.EXCHANGE_TYPE;
+import static org.apache.qpid.management.ui.Constants.NOTIFICATIONS;
+import static org.apache.qpid.management.ui.Constants.QUEUE;
+
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.management.MBeanServerConnection;
+
+import org.apache.qpid.management.ui.ApplicationRegistry;
+import org.apache.qpid.management.ui.ManagedServer;
+import org.apache.qpid.management.ui.ServerRegistry;
+import org.apache.qpid.management.ui.jmx.JMXManagedObject;
+import org.apache.qpid.management.ui.jmx.MBeanUtility;
+import org.apache.qpid.management.ui.model.NotificationInfoModel;
+import org.apache.qpid.management.ui.model.OperationData;
+import org.apache.qpid.management.ui.model.OperationDataModel;
+import org.apache.qpid.management.ui.views.queue.QueueOperationsTabControl;
+import org.apache.qpid.management.ui.views.type.ConnectionTypeTabControl;
+import org.apache.qpid.management.ui.views.type.ExchangeTypeTabControl;
+import org.apache.qpid.management.ui.views.type.QueueTypeTabControl;
+import org.apache.qpid.management.ui.views.users.UserManagementTabControl;
+import org.apache.qpid.management.ui.views.vhost.VHostTabControl;
+import org.apache.qpid.management.ui.views.connection.ConnectionOperationsTabControl;
+import org.apache.qpid.management.ui.views.exchange.ExchangeOperationsTabControl;
+import org.apache.qpid.management.ui.views.exchange.HeadersExchangeOperationsTabControl;
+import org.apache.qpid.management.ui.views.logging.ConfigurationFileTabControl;
+import org.apache.qpid.management.ui.views.logging.RuntimeTabControl;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.TabItem;
+
+public class MBeanTabFolderFactory
+{
+ private static final String MBEANTYPE_QUEUE = "VirtualHost.Queue";
+ private static final String MBEANTYPE_CONNECTION = "VirtualHost.Connection";
+ private static final String MBEANTYPE_EXCHANGE = "VirtualHost.Exchange";
+ private static final String MBEANTYPE_VHOST_MANAGER = "VirtualHost.VirtualHostManager";
+ private static final String MBEANTYPE_LOGGING_MANAGEMENT = "LoggingManagement";
+ private static final String MBEANTYPE_USER_MANAGEMENT = "UserManagement";
+ private static final String MBEANTYPE_CONFIGURATION_MANAGEMENT = "ConfigurationManagement";
+
+ private MBeanTabFolderFactory()
+ {
+ //no instances
+ }
+
+ public static TabFolder generateMBeanTabFolder(final Composite parent, final JMXManagedObject mbean, final MBeanServerConnection mbsc)
+ {
+ TabFolder tabFolder = new TabFolder(parent, SWT.NONE);
+ FormData layoutData = new FormData();
+ layoutData.left = new FormAttachment(0);
+ layoutData.top = new FormAttachment(0);
+ layoutData.right = new FormAttachment(100);
+ layoutData.bottom = new FormAttachment(100);
+ tabFolder.setLayoutData(layoutData);
+
+ TabItem tab;
+ TabControl controller;
+ QpidMBeanType mbeanType = QpidMBeanType.get(mbean.getType());
+
+ switch(mbeanType)
+ {
+ case QUEUE:
+ createAttributesTab(tabFolder, mbean);
+
+ tab = new TabItem(tabFolder, SWT.NONE);
+ tab.setText("Operations");
+ controller = new QueueOperationsTabControl(tabFolder, mbean, mbsc);
+ tab.setControl(controller.getControl());
+ tab.setData(TabControl.CONTROLLER, controller);
+ break;
+ case CONNECTION:
+ createAttributesTab(tabFolder, mbean);
+
+ tab = new TabItem(tabFolder, SWT.NONE);
+ tab.setText("Operations");
+ controller = new ConnectionOperationsTabControl(tabFolder, mbean, mbsc);
+ tab.setControl(controller.getControl());
+ tab.setData(TabControl.CONTROLLER, controller);
+ break;
+ case EXCHANGE:
+ createAttributesTab(tabFolder, mbean);
+
+ if (mbean.getProperty(EXCHANGE_TYPE).equalsIgnoreCase("headers"))
+ {
+ tab = new TabItem(tabFolder, SWT.NONE);
+ tab.setText("Operations");
+ controller = new HeadersExchangeOperationsTabControl(tabFolder, mbean, mbsc);
+ tab.setControl(controller.getControl());
+ tab.setData(TabControl.CONTROLLER, controller);
+ }
+ else
+ {
+ tab = new TabItem(tabFolder, SWT.NONE);
+ tab.setText("Operations");
+ controller = new ExchangeOperationsTabControl(tabFolder, mbean, mbsc);
+ tab.setControl(controller.getControl());
+ tab.setData(TabControl.CONTROLLER, controller);
+ }
+ break;
+ case VHOST_MANAGER:
+ tab = new TabItem(tabFolder, SWT.NONE);
+ tab.setText("Operations");
+ controller = new VHostTabControl(tabFolder, mbean, mbsc);
+ tab.setControl(controller.getControl());
+ tab.setData(TabControl.CONTROLLER, controller);
+ break;
+ case LOGGING_MANAGEMENT:
+ tab = new TabItem(tabFolder, SWT.NONE);
+ tab.setText("Runtime Options");
+ controller = new RuntimeTabControl(tabFolder, mbean, mbsc);
+ tab.setControl(controller.getControl());
+ tab.setData(TabControl.CONTROLLER, controller);
+
+ tab = new TabItem(tabFolder, SWT.NONE);
+ tab.setText("ConfigurationFile Options");
+ controller = new ConfigurationFileTabControl(tabFolder, mbean, mbsc);
+ tab.setControl(controller.getControl());
+ tab.setData(TabControl.CONTROLLER, controller);
+ break;
+ case USER_MANAGEMENT:
+ tab = new TabItem(tabFolder, SWT.NONE);
+ tab.setText("Operations");
+ controller = new UserManagementTabControl(tabFolder, mbean, mbsc);
+ tab.setControl(controller.getControl());
+ tab.setData(TabControl.CONTROLLER, controller);
+ break;
+ case CONFIGURATION_MANAGEMENT:
+ createGenericTabFolder(tabFolder, mbean);
+ break;
+ case UNKNOWN:
+ createGenericTabFolder(tabFolder, mbean);
+ break;
+ }
+
+ createNotificationsTabIfNecessary(tabFolder, mbean);
+
+ tabFolder.addListener(SWT.Selection, new Listener()
+ {
+ public void handleEvent(Event evt)
+ {
+ TabItem tab = (TabItem)evt.item;
+ TabControl controller = (TabControl)tab.getData(TabControl.CONTROLLER);
+ if(controller != null)
+ {
+ controller.refresh(mbean);
+ }
+ }
+ });
+
+ return tabFolder;
+ }
+
+ private static void createGenericTabFolder(TabFolder tabFolder, JMXManagedObject mbean)
+ {
+ createAttributesTab(tabFolder, mbean);
+ createOperationTabs(tabFolder, mbean);
+ }
+
+ private static void createAttributesTab(TabFolder tabFolder, JMXManagedObject mbean)
+ {
+ ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(mbean);
+ if(serverRegistry.getAttributeModel(mbean).getCount() == 0)
+ {
+ return;
+ }
+
+ TabItem tab = new TabItem(tabFolder, SWT.NONE);
+ tab.setText(ATTRIBUTES);
+ AttributesTabControl controller = new AttributesTabControl(tabFolder);
+ tab.setControl(controller.getControl());
+ tab.setData(TabControl.CONTROLLER, controller);
+ }
+
+ private static void createOperationTabs(TabFolder tabFolder, JMXManagedObject mbean)
+ {
+ ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(mbean);
+ int operationsCount = serverRegistry.getOperationModel(mbean).getCount();
+ if(operationsCount == 0)
+ {
+ return;
+ }
+
+ OperationDataModel operationModel = serverRegistry.getOperationModel(mbean);
+ for(OperationData operationData : operationModel.getOperations())
+ {
+ TabItem operationTab = new TabItem(tabFolder, SWT.NONE);
+ operationTab.setText(ViewUtility.getDisplayText(operationData.getName()));
+ operationTab.setData(operationData);
+ OperationTabControl control = new OperationTabControl(tabFolder, operationData);
+ operationTab.setData(TabControl.CONTROLLER, control);
+ operationTab.setControl(control.getControl());
+ }
+ }
+
+ private static void createNotificationsTabIfNecessary(TabFolder tabFolder, JMXManagedObject mbean)
+ {
+ NotificationInfoModel[] items = MBeanUtility.getNotificationInfo(mbean);
+ if(items == null || items.length == 0)
+ {
+ //the mbean has no notifications to subscribe for, do not create the tab.
+ return;
+ }
+
+ NotificationsTabControl controller = new NotificationsTabControl(tabFolder, mbean);
+
+ TabItem tab = new TabItem(tabFolder, SWT.NONE);
+ tab.setText(NOTIFICATIONS);
+ tab.setData(TabControl.CONTROLLER, controller);
+ tab.setControl(controller.getControl());
+ }
+
+ /**
+ * Creates TabFolder and tabs for all mbeantype (Connection, Queue, and Exchange)
+ */
+ public static TabFolder generateMBeanTypeTabFolder(final Composite parent, ManagedServer server, String virtualHost)
+ {
+ TabFolder tabFolder = new TabFolder(parent, SWT.NONE);
+ FormData layoutData = new FormData();
+ layoutData.left = new FormAttachment(0);
+ layoutData.top = new FormAttachment(0);
+ layoutData.right = new FormAttachment(100);
+ layoutData.bottom = new FormAttachment(100);
+ tabFolder.setLayoutData(layoutData);
+
+
+ TabItem tab;
+ TabControl controller;
+
+ tab = new TabItem(tabFolder, SWT.NONE);
+ tab.setText(CONNECTION);
+ controller = new ConnectionTypeTabControl(tabFolder,server,virtualHost);
+ tab.setData(TabControl.CONTROLLER, controller);
+ tab.setControl(controller.getControl());
+
+ tab = new TabItem(tabFolder, SWT.NONE);
+ tab.setText(EXCHANGE);
+ controller = new ExchangeTypeTabControl(tabFolder,server,virtualHost);
+ tab.setData(TabControl.CONTROLLER, controller);
+ tab.setControl(controller.getControl());
+
+ tab = new TabItem(tabFolder, SWT.NONE);
+ tab.setText(QUEUE);
+ controller = new QueueTypeTabControl(tabFolder,server,virtualHost);
+ tab.setData(TabControl.CONTROLLER, controller);
+ tab.setControl(controller.getControl());
+
+ tabFolder.addListener(SWT.Selection, new Listener()
+ {
+ public void handleEvent(Event evt)
+ {
+ TabItem tab = (TabItem)evt.item;
+ TabControl controller = (TabControl)tab.getData(TabControl.CONTROLLER);
+ if(controller != null)
+ {
+ controller.refresh(null);
+ }
+ }
+ });
+
+ return tabFolder;
+ }
+
+ /**
+ * Creates TabFolder and tab for the Connection selection view
+ */
+ public static TabFolder generateConnectionTypeTabFolder(final Composite parent, ManagedServer server, String virtualHost)
+ {
+ TabFolder tabFolder = new TabFolder(parent, SWT.NONE);
+ FormData layoutData = new FormData();
+ layoutData.left = new FormAttachment(0);
+ layoutData.top = new FormAttachment(0);
+ layoutData.right = new FormAttachment(100);
+ layoutData.bottom = new FormAttachment(100);
+ tabFolder.setLayoutData(layoutData);
+
+ TabItem tab;
+ TabControl controller;
+
+ tab = new TabItem(tabFolder, SWT.NONE);
+ tab.setText(CONNECTION);
+ controller = new ConnectionTypeTabControl(tabFolder,server,virtualHost);
+ tab.setData(TabControl.CONTROLLER, controller);
+ tab.setControl(controller.getControl());
+
+ tabFolder.addListener(SWT.Selection, new Listener()
+ {
+ public void handleEvent(Event evt)
+ {
+ TabItem tab = (TabItem)evt.item;
+ TabControl controller = (TabControl)tab.getData(TabControl.CONTROLLER);
+ if(controller != null)
+ {
+ controller.refresh(null);
+ }
+ }
+ });
+
+ return tabFolder;
+ }
+
+ /**
+ * Creates TabFolder and tab for the Exchange selection view
+ */
+ public static TabFolder generateExchangeTypeTabFolder(final Composite parent, ManagedServer server, String virtualHost)
+ {
+ TabFolder tabFolder = new TabFolder(parent, SWT.NONE);
+ FormData layoutData = new FormData();
+ layoutData.left = new FormAttachment(0);
+ layoutData.top = new FormAttachment(0);
+ layoutData.right = new FormAttachment(100);
+ layoutData.bottom = new FormAttachment(100);
+ tabFolder.setLayoutData(layoutData);
+
+ TabItem tab;
+ TabControl controller;
+
+ tab = new TabItem(tabFolder, SWT.NONE);
+ tab.setText(EXCHANGE);
+ controller = new ExchangeTypeTabControl(tabFolder,server,virtualHost);
+ tab.setData(TabControl.CONTROLLER, controller);
+ tab.setControl(controller.getControl());
+
+ tabFolder.addListener(SWT.Selection, new Listener()
+ {
+ public void handleEvent(Event evt)
+ {
+ TabItem tab = (TabItem)evt.item;
+ TabControl controller = (TabControl)tab.getData(TabControl.CONTROLLER);
+ if(controller != null)
+ {
+ controller.refresh(null);
+ }
+ }
+ });
+
+ return tabFolder;
+ }
+
+ /**
+ * Creates TabFolder and tab for the Queue selection view
+ */
+ public static TabFolder generateQueueTypeTabFolder(final Composite parent, ManagedServer server, String virtualHost)
+ {
+ TabFolder tabFolder = new TabFolder(parent, SWT.NONE);
+ FormData layoutData = new FormData();
+ layoutData.left = new FormAttachment(0);
+ layoutData.top = new FormAttachment(0);
+ layoutData.right = new FormAttachment(100);
+ layoutData.bottom = new FormAttachment(100);
+ tabFolder.setLayoutData(layoutData);
+
+ TabItem tab;
+ TabControl controller;
+
+ tab = new TabItem(tabFolder, SWT.NONE);
+ tab.setText(QUEUE);
+ controller = new QueueTypeTabControl(tabFolder,server,virtualHost);
+ tab.setData(TabControl.CONTROLLER, controller);
+ tab.setControl(controller.getControl());
+
+ tabFolder.addListener(SWT.Selection, new Listener()
+ {
+ public void handleEvent(Event evt)
+ {
+ TabItem tab = (TabItem)evt.item;
+ TabControl controller = (TabControl)tab.getData(TabControl.CONTROLLER);
+ if(controller != null)
+ {
+ controller.refresh(null);
+ }
+ }
+ });
+
+ return tabFolder;
+ }
+
+ private enum QpidMBeanType
+ {
+ QUEUE (MBEANTYPE_QUEUE),
+ CONNECTION (MBEANTYPE_CONNECTION),
+ EXCHANGE (MBEANTYPE_EXCHANGE),
+ VHOST_MANAGER (MBEANTYPE_VHOST_MANAGER),
+ LOGGING_MANAGEMENT (MBEANTYPE_LOGGING_MANAGEMENT),
+ USER_MANAGEMENT (MBEANTYPE_USER_MANAGEMENT),
+ CONFIGURATION_MANAGEMENT (MBEANTYPE_CONFIGURATION_MANAGEMENT),
+ UNKNOWN (null);
+
+ private static final Map<String,QpidMBeanType> lookup = new HashMap<String,QpidMBeanType>();
+
+ static
+ {
+ for(QpidMBeanType m : EnumSet.allOf(QpidMBeanType.class))
+ {
+ lookup.put(m.getType(), m);
+ }
+ }
+
+ private String type;
+
+ private QpidMBeanType()
+ {
+
+ }
+
+ private QpidMBeanType(String type)
+ {
+ this.type = type;
+ }
+
+ public String getType()
+ {
+ return type;
+ }
+
+ public static QpidMBeanType get(String type)
+ {
+ QpidMBeanType t= lookup.get(type);
+ if (t != null)
+ {
+ return t;
+ }
+ else
+ {
+ return UNKNOWN;
+ }
+
+ }
+ }
+
+
+}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanTypeTabControl.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanTypeTabControl.java
deleted file mode 100644
index 24dfb519fd..0000000000
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanTypeTabControl.java
+++ /dev/null
@@ -1,336 +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.
- *
- */
-
-package org.apache.qpid.management.ui.views;
-
-import static org.apache.qpid.management.ui.Constants.BUTTON_REFRESH;
-import static org.apache.qpid.management.ui.Constants.FONT_BOLD;
-import static org.apache.qpid.management.ui.Constants.FONT_ITALIC;
-import static org.apache.qpid.management.ui.Constants.FONT_NORMAL;
-
-import java.util.Collections;
-import java.util.HashMap;
-
-import org.apache.qpid.management.ui.ApplicationRegistry;
-import org.apache.qpid.management.ui.ManagedBean;
-import org.apache.qpid.management.ui.jmx.MBeanUtility;
-import org.apache.qpid.management.ui.model.AttributeData;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.List;
-import org.eclipse.swt.widgets.TabFolder;
-import org.eclipse.ui.IWorkbenchWindow;
-import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.forms.widgets.Form;
-import org.eclipse.ui.forms.widgets.FormToolkit;
-
-/**
- * Abstract class to be extended by the Controller classes for different MBean types (Connection, Queue, Exchange)
- */
-public abstract class MBeanTypeTabControl
-{
- private FormToolkit _toolkit = null;
- private Form _form = null;
- private TabFolder _tabFolder = null;
- private Composite _composite = null;
- private Composite _headerComposite = null;
- private Composite _listComposite = null;
- private Label _labelName = null;
- private Label _labelDesc = null;
- private Label _labelList = null;
-
- private org.eclipse.swt.widgets.List _list = null;
- private Button _refreshButton = null;
- private Button _addButton = null;
-
- private String _type = null;
-
- // maps an mbean name with the mbean object. Required to get mbean object when an mbean
- // is to be added to the navigation view.
- private HashMap<String, ManagedBean> _objectsMap = new HashMap<String, ManagedBean>();
- private Sorter _sorterByName = new Sorter();
-
- public MBeanTypeTabControl(TabFolder tabFolder, String type)
- {
- _type = type;
- _tabFolder = tabFolder;
- _toolkit = new FormToolkit(_tabFolder.getDisplay());
- _form = _toolkit.createForm(_tabFolder);
- createFormComposite();
- }
-
- public FormToolkit getToolkit()
- {
- return _toolkit;
- }
-
- public Control getControl()
- {
- return _form;
- }
-
- public String getType()
- {
- return _type;
- }
-
- protected List getListWidget()
- {
- return _list;
- }
-
- protected HashMap<String, ManagedBean> getMBeansMap()
- {
- return _objectsMap;
- }
-
- public Sorter getMBeanNameSorter()
- {
- return _sorterByName;
- }
-
- public Button getAddButton()
- {
- return _addButton;
- }
-
- public Button getRefreshButton()
- {
- return _refreshButton;
- }
-
- /**
- * Creates the main Composite, which will contain all other Composites and Widgets
- */
- protected void createFormComposite()
- {
- _form.getBody().setLayout(new GridLayout());
- _composite = _toolkit.createComposite(_form.getBody(), SWT.NONE);
- _composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- GridLayout layout = new GridLayout();
- layout.verticalSpacing = 10;
- layout.horizontalSpacing = 0;
- _composite.setLayout(layout);
- }
-
- protected Composite getFormComposite()
- {
- return _composite;
- }
-
- /**
- * Creates the header composite, which has MBean type name and description
- * @param parentComposite
- */
- protected void createHeaderComposite(Composite parentComposite)
- {
- _headerComposite = _toolkit.createComposite(parentComposite);
- _headerComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
- GridLayout layout = new GridLayout();
- layout.verticalSpacing = 10;
- layout.horizontalSpacing = 0;
- _headerComposite.setLayout(layout);
-
- _labelName = _toolkit.createLabel(_headerComposite, "Type:", SWT.NONE);
- GridData gridData = new GridData(SWT.CENTER, SWT.TOP, true, false);
- _labelName.setLayoutData(gridData);
- _labelName.setFont(ApplicationRegistry.getFont(FONT_BOLD));
-
- _labelDesc = _toolkit.createLabel(_headerComposite, " ", SWT.NONE);
- _labelDesc.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, true, false));
- _labelDesc.setFont(ApplicationRegistry.getFont(FONT_ITALIC));
-
- _headerComposite.layout();
- }
-
- /**
- * Creates Composite, which contains the common buttons - Add and Refresh.
- * @param parentComposite
- */
- protected void createButtonsComposite(Composite parentComposite)
- {
- Composite composite = _toolkit.createComposite(parentComposite);
- composite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
- GridLayout layout = new GridLayout(2, true);
- layout.verticalSpacing = 10;
- layout.horizontalSpacing = 20;
- composite.setLayout(layout);
-
- createAddButton(composite);
- createRefreshButton(composite);
- }
-
- /**
- * Creates the Add button, which adds the selected item to the navigation view
- * @param parentComposite
- */
- protected void createAddButton(Composite parentComposite)
- {
- Button _addButton = _toolkit.createButton(parentComposite, "<- Add to Navigation", SWT.PUSH);
- GridData gridData = new GridData(SWT.CENTER, SWT.CENTER, false, false);
- _addButton.setLayoutData(gridData);
- _addButton.addSelectionListener(new SelectionAdapter(){
- public void widgetSelected(SelectionEvent e)
- {
- if (_list.getSelectionCount() == 0)
- return;
-
- String[] selectedItems = _list.getSelection();
- for (int i = 0; i < selectedItems.length; i++)
- {
- String name = selectedItems[i];
- // pass the ManagedBean to the navigation view to be added
- ManagedBean mbean = _objectsMap.get(name);
- IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
- NavigationView view = (NavigationView)window.getActivePage().findView(NavigationView.ID);
- try
- {
- view.addManagedBean(mbean);
- }
- catch (Exception ex)
- {
- MBeanUtility.handleException(mbean, ex);
- }
- }
- }
- });
- }
-
- /**
- * Creates the Refresh button, which gets syncs the items with the broker server
- * @param parentComposite
- */
- protected void createRefreshButton(Composite parentComposite)
- {
- Button _refreshButton = _toolkit.createButton(parentComposite, BUTTON_REFRESH, SWT.PUSH);
- GridData gridData = new GridData(SWT.CENTER, SWT.CENTER, false, false);
- gridData.widthHint = 120;
- _refreshButton.setLayoutData(gridData);
- _refreshButton.addSelectionListener(new SelectionAdapter(){
- public void widgetSelected(SelectionEvent e)
- {
- try
- {
- // refresh the list from the broker server
- populateList();
- }
- catch (Exception ex)
- {
- MBeanUtility.handleException(ex);
- }
- }
- });
- }
-
- /**
- * Creates the Composite, which contains the items ( Connections, Exchanges or Queues)
- * @param parentComposite
- */
- protected void createListComposite(Composite parentComposite)
- {
- // Composite to contain the item list
- _listComposite = _toolkit.createComposite(parentComposite);
- GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
- _listComposite.setLayoutData(gridData);
- GridLayout layout = new GridLayout();
- layout.verticalSpacing = 0;
- _listComposite.setLayout(layout);
-
- // Label for item name
- _labelList = _toolkit.createLabel(_listComposite, " ", SWT.CENTER);
- gridData = new GridData(SWT.CENTER, SWT.TOP, true, false, 1, 1);
- _labelList.setLayoutData(gridData);
- _labelList.setFont(ApplicationRegistry.getFont(FONT_NORMAL));
-
- _list = new List(_listComposite, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
- gridData = new GridData(SWT.FILL, SWT.FILL, true, true,1, 1);
- _list.setLayoutData(gridData);
-
- }
-
- /**
- * This is called from MBean View to refresh the tab contents
- * @throws Exception
- */
- public void refresh() throws Exception
- {
- setLabelValues();
- populateList();
- layout();
- }
-
- protected void setLabelValues()
- {
- _labelName.setText("Type : " + _type);
- _labelDesc.setText("Select the " + _type + "(s) to add in the Navigation View");
- _labelList.setText("-- List of " + _type + "s --");
- }
-
- protected abstract void populateList() throws Exception;
-
- public void layout()
- {
- _form.layout(true);
- _form.getBody().layout(true, true);
- }
-
- // sets the map with appropriate mbean and name
- protected String[] getItems(java.util.List<ManagedBean> list)
- {
- if (list == null)
- return new String[0];
-
- Collections.sort(list, _sorterByName);
- String[] items = new String[list.size()];
- int i = 0;
- for (ManagedBean mbean : list)
- {
- items[i++] = mbean.getName();
- _objectsMap.put(mbean.getName(), mbean);
- }
- return items;
- }
-
- protected class ComparatorImpl implements java.util.Comparator<AttributeData>
- {
- public int compare(AttributeData data1, AttributeData data2)
- {
- Integer int1 = Integer.parseInt(data1.getValue().toString());
- Integer int2 = Integer.parseInt(data2.getValue().toString());
- return int1.compareTo(int2) * -1;
- }
- }
-
- protected class Sorter implements java.util.Comparator<ManagedBean>
- {
- public int compare(ManagedBean mbean1, ManagedBean mbean2)
- {
- return mbean1.getName().compareTo(mbean2.getName());
- }
- }
-}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanView.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanView.java
index 344c3c4e7f..9763c799d7 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanView.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanView.java
@@ -20,29 +20,32 @@
*/
package org.apache.qpid.management.ui.views;
-import java.util.HashMap;
+import java.util.LinkedList;
+
+import javax.management.MBeanServerConnection;
import static org.apache.qpid.management.ui.Constants.*;
+
+import org.apache.qpid.management.ui.ApiVersion;
import org.apache.qpid.management.ui.ApplicationRegistry;
import org.apache.qpid.management.ui.ManagedBean;
import org.apache.qpid.management.ui.ManagedServer;
import org.apache.qpid.management.ui.ServerRegistry;
-import org.apache.qpid.management.ui.exceptions.InfoRequiredException;
+import org.apache.qpid.management.ui.actions.BackAction;
+import org.apache.qpid.management.ui.jmx.JMXManagedObject;
+import org.apache.qpid.management.ui.jmx.JMXServerRegistry;
import org.apache.qpid.management.ui.jmx.MBeanUtility;
-import org.apache.qpid.management.ui.model.AttributeData;
-import org.apache.qpid.management.ui.model.OperationData;
-import org.apache.qpid.management.ui.model.OperationDataModel;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
+import org.eclipse.ui.IActionBars;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.forms.widgets.Form;
@@ -51,14 +54,10 @@ import org.eclipse.ui.part.ViewPart;
/**
* MBean View create appropriate view based on the user selection on the Navigation View.
- * Create TabFolder for all MBeans and displays the attribtues and method tabs.
- * @author Bhupendra Bhardwaj
- *
*/
public class MBeanView extends ViewPart
{
public static final String ID = "org.apache.qpid.management.ui.mbeanView";
- private static final String CONTROLLER = "CONTROLLER";
private FormToolkit _toolkit = null;
private Form _form = null;
@@ -67,15 +66,18 @@ public class MBeanView extends ViewPart
private TreeObject _selectedNode = null;
private ManagedBean _mbean = null;
private static String _virtualHostName = null;
- // This map contains a TabFolder for each kind of MBean.
- // TabFolder is mapped with mbeantype(Connection, Queue and Exchange)
- private HashMap<String, TabFolder> tabFolderMap = new HashMap<String, TabFolder>();
- private ISelectionListener selectionListener = new SelectionListenerImpl();
+ private static MBeanServerConnection _mbsc = null;
+ private TabFolder _tabFolder = null;
+ private ISelectionListener _selectionListener = new SelectionListenerImpl();
// TabFolder to list all the mbeans for a given mbeantype(eg Connection, Queue, Exchange)
- private TabFolder typeTabFolder = null;
+ private TabFolder _typeTabFolder = null;
+
+ private TabFolder _notificationTabFolder = null;
+
+ private LinkedList<Object> _backHistory;
+ private BackAction _backAction;
- private TabFolder notificationTabFolder = null;
/*
* Listener for the selection events in the navigation view
*/
@@ -93,16 +95,84 @@ public class MBeanView extends ViewPart
// mbean should be set to null. A selection done on the navigation view can be either an mbean or
// an mbeantype. For mbeantype selection(eg Connection, Queue, Exchange) _mbean will remain null.
_mbean = null;
- setInvisible();
+ clearView();
+
+ //clear the back history, it is only for use when opening subsequent mbeans not in the nav tree
+ _backHistory.clear();
+ _backAction.setEnabled(false);
// If a selected node(mbean) gets unregistered from mbean server, mbeanview should
// make the tabfolber for that mbean invisible
- if (_selectedNode == null)
+ if (_selectedNode == null)
+ {
return;
+ }
setServer();
- refreshMBeanView();
- setFormTitle();
+
+ if(!ApplicationRegistry.isServerConnected(_server))
+ {
+ return;
+ }
+
+ if (MBEAN.equals(_selectedNode.getType()))
+ {
+ _mbean = (ManagedBean)_selectedNode.getManagedObject();
+ }
+
+ setFormTitle();
+ showRelevantTabView();
+ }
+ }
+
+ public void openMBean(ManagedBean mbean)
+ {
+ openMBean(mbean, false);
+ }
+
+ private void openMBean(ManagedBean mbean, boolean undoing)
+ {
+ if(mbean == null)
+ {
+ return;
+ }
+
+ //if an mbean is about to be opened (but not returning to using back) from the mbean view,
+ //then record the current viewed area/object as a means of back history
+ if(!undoing)
+ {
+ if(_backHistory.isEmpty())
+ {
+ //ensure the button is enabled if this is to be the first history item
+ _backAction.setEnabled(true);
+ }
+
+ if(_mbean == null)
+ {
+ //queue etc selection area is open, record the tree object
+ _backHistory.addLast(_selectedNode);
+ }
+ else
+ {
+ _backHistory.addLast(_mbean);
+ }
+ }
+
+ _mbean = mbean;
+
+ try
+ {
+ clearView();
+
+ setFormTitle();
+ showMBean(mbean);
+
+ _form.layout(true);
+ _form.getBody().layout(true, true);
+ }
+ catch(Exception ex)
+ {
+ MBeanUtility.handleException(mbean, ex);
}
}
@@ -131,32 +201,58 @@ public class MBeanView extends ViewPart
_form.setText(_formText);
}
- public void refreshMBeanView()
+ public void showRelevantTabView()
{
try
{
- if (NODE_TYPE_SERVER.equals(_selectedNode.getType()) ||
- NODE_TYPE_DOMAIN.equals(_selectedNode.getType()) )
+ if (_selectedNode == null)
{
return;
}
- else if (NODE_TYPE_TYPEINSTANCE.equals(_selectedNode.getType()))
+
+ String mbeanType = _selectedNode.getType();
+
+ if (NODE_TYPE_TYPEINSTANCE.equals(mbeanType))
{
// An virtual host instance is selected
- refreshTypeTabFolder(typeTabFolder.getItem(0));
+ generateTypeTabFolder();
}
- else if (NODE_TYPE_MBEANTYPE.equals(_selectedNode.getType()))
+ else if (NODE_TYPE_MBEANTYPE.equals(mbeanType))
{
- refreshTypeTabFolder(_selectedNode.getName());
+ showTypeTabFolder(_selectedNode.getName());
}
- else if (NOTIFICATIONS.equals(_selectedNode.getType()))
+ else if (NOTIFICATIONS.equals(mbeanType))
{
refreshNotificationPage();
}
- else if (MBEAN.equals(_selectedNode.getType()))
+ else if (MBEAN.equals(mbeanType))
+ {
+ showMBean(_mbean);
+ }
+ else if(NODE_TYPE_SERVER.equals(mbeanType))
+ {
+ ServerRegistry serverReg = ApplicationRegistry.getServerRegistry(_server);
+
+ //check the server is connected
+ if(serverReg != null)
+ {
+ //post a message if the server supports a newer API version.
+ ApiVersion serverAPI = serverReg.getManagementApiVersion();
+ int supportedMajor = ApplicationRegistry.SUPPORTED_QPID_JMX_API_MAJOR_VERSION;
+ int supportedMinor = ApplicationRegistry.SUPPORTED_QPID_JMX_API_MINOR_VERSION;
+
+ if(serverAPI.greaterThan(supportedMajor, supportedMinor))
+ {
+ _form.setText("The server supports an updated management API and may offer " +
+ "functionality not available with this console. " +
+ "Please check for an updated console release.");
+ }
+
+ }
+ }
+ else
{
- _mbean = (ManagedBean)_selectedNode.getManagedObject();
- showSelectedMBean();
+ return;
}
_form.layout(true);
@@ -176,8 +272,7 @@ public class MBeanView extends ViewPart
*/
private void setServer()
{
- if (NODE_TYPE_SERVER.equals(_selectedNode.getType()) ||
- NODE_TYPE_DOMAIN.equals(_selectedNode.getType()) )
+ if (NODE_TYPE_SERVER.equals(_selectedNode.getType()))
{
_server = (ManagedServer)_selectedNode.getManagedObject();
_virtualHostName = null;
@@ -195,6 +290,11 @@ public class MBeanView extends ViewPart
_virtualHostName = _selectedNode.getVirtualHost();
}
+
+ JMXServerRegistry serverRegistry = (JMXServerRegistry)ApplicationRegistry.getServerRegistry(_server);
+ if(serverRegistry != null){
+ _mbsc = serverRegistry.getServerConnection();
+ }
}
public static ManagedServer getServer()
@@ -207,45 +307,36 @@ public class MBeanView extends ViewPart
return _virtualHostName;
}
- private void showSelectedMBean() throws Exception
+ private void showMBean(ManagedBean mbean) throws Exception
{
try
{
- MBeanUtility.getMBeanInfo(_mbean);
+ MBeanUtility.getMBeanInfo(mbean);
}
catch(Exception ex)
{
- MBeanUtility.handleException(_mbean, ex);
+ MBeanUtility.handleException(mbean, ex);
return;
}
- TabFolder tabFolder = tabFolderMap.get(_mbean.getType());
- /*
- * This solution can be used if there are many versions of Qpid running. Otherwise
- * there is no need to create a tabFolder everytime a bean is selected.
- if (tabFolder != null && !tabFolder.isDisposed())
- {
- tabFolder.dispose();
- }
- tabFolder = createTabFolder();
- */
- if (tabFolder == null)
+ if (_tabFolder != null && !_tabFolder.isDisposed())
{
- tabFolder = createMBeanTabFolder();
+ _tabFolder.dispose();
}
+ _tabFolder = MBeanTabFolderFactory.generateMBeanTabFolder(_form.getBody(),(JMXManagedObject)mbean,_mbsc);
+
int tabIndex = 0;
if (NOTIFICATIONS.equals(_selectedNode.getType()))
{
- tabIndex = tabFolder.getItemCount() -1;
+ tabIndex = _tabFolder.getItemCount() -1;
}
- TabItem tab = tabFolder.getItem(tabIndex);
+ TabItem tab = _tabFolder.getItem(tabIndex);
// If folder is being set as visible after tab refresh, then the tab
// doesn't have the focus.
- tabFolder.setSelection(tabIndex);
+ _tabFolder.setSelection(tabIndex);
refreshTab(tab);
- setVisible(tabFolder);
}
public void createPartControl(Composite parent)
@@ -257,57 +348,30 @@ public class MBeanView extends ViewPart
_form.setText(APPLICATION_NAME);
// Add selection listener for selection events in the Navigation view
- getSite().getPage().addSelectionListener(NavigationView.ID, selectionListener);
-
- // Add mbeantype TabFolder. This will list all the mbeans under a mbeantype (eg Queue, Exchange).
- // Using this list mbeans will be added in the navigation view
- createMBeanTypeTabFolder();
-
+ getSite().getPage().addSelectionListener(NavigationView.ID, _selectionListener);
+
createNotificationsTabFolder();
- }
-
- private TabFolder createMBeanTabFolder()
- {
- TabFolder tabFolder = new TabFolder(_form.getBody(), SWT.NONE);
- FormData layoutData = new FormData();
- layoutData.left = new FormAttachment(0);
- layoutData.top = new FormAttachment(0);
- layoutData.right = new FormAttachment(100);
- layoutData.bottom = new FormAttachment(100);
- tabFolder.setLayoutData(layoutData);
- tabFolder.setVisible(false);
-
- createAttributesTab(tabFolder);
- createOperationTabs(tabFolder);
- createNotificationsTab(tabFolder);
- tabFolder.addListener(SWT.Selection, new Listener()
- {
- public void handleEvent(Event evt)
- {
- TabItem tab = (TabItem)evt.item;
- refreshTab(tab);
- }
- });
+ ViewUtility.setMBeanView(this);
- tabFolderMap.put(_mbean.getType(), tabFolder);
- return tabFolder;
+ _backAction = new BackAction();
+ getViewSite().getActionBars().getToolBarManager().add(_backAction);
+ _backAction.setEnabled(false);
+ _backHistory = new LinkedList<Object>();
}
private void refreshTab(TabItem tab)
{
- // We can avoid refreshing the attributes tab because it's control
- // already contains the required values. But it is added for now and
- // will remove if there is any performance issue or any other issue.
- // The operations control should be refreshed because there is only one
- // controller for all operations tab.
- // The Notifications control needs to refresh with latest set of notifications
-
if (tab == null)
+ {
return;
+ }
- TabControl controller = (TabControl)tab.getData(CONTROLLER);
- controller.refresh(_mbean);
+ TabControl controller = (TabControl)tab.getData(TabControl.CONTROLLER);
+ if(controller != null)
+ {
+ controller.refresh(_mbean);
+ }
}
public void setFocus()
@@ -321,225 +385,216 @@ public class MBeanView extends ViewPart
super.dispose();
}
- private void createAttributesTab(TabFolder tabFolder)
- {
- ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(_mbean);
- if (serverRegistry.getAttributeModel(_mbean).getCount() == 0)
- {
- return;
- }
-
- TabItem tab = new TabItem(tabFolder, SWT.NONE);
- tab.setText(ATTRIBUTES);
- AttributesTabControl controller = new AttributesTabControl(tabFolder);
- tab.setControl(controller.getControl());
- tab.setData(CONTROLLER, controller);
- }
-
- private void createOperationTabs(TabFolder tabFolder)
- {
- ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(_mbean);
- int operationsCount = serverRegistry.getOperationModel(_mbean).getCount();
- if (operationsCount == 0)
- {
- return;
- }
-
- OperationDataModel operationModel = serverRegistry.getOperationModel(_mbean);
- for (OperationData operationData : operationModel.getOperations())
- {
- TabItem operationTab = new TabItem(tabFolder, SWT.NONE);
- operationTab.setText(ViewUtility.getDisplayText(operationData.getName()));
- operationTab.setData(operationData);
- OperationTabControl control = new OperationTabControl(tabFolder, operationData);
- operationTab.setData(CONTROLLER, control);
- operationTab.setControl(control.getControl());
- }
- }
-
- private void createNotificationsTab(TabFolder tabFolder)
- {
- NotificationsTabControl controller = new NotificationsTabControl(tabFolder);
-
- TabItem tab = new TabItem(tabFolder, SWT.NONE);
- tab.setText(NOTIFICATIONS);
- tab.setData(CONTROLLER, controller);
- tab.setControl(controller.getControl());
- }
-
- /**
- * For the EditAttribtue Action. Invoking this from action is same as clicking
- * "EditAttribute" button from Attribute tab.
- */
- public void editAttribute() throws Exception
- {
- if (_mbean == null)
- throw new InfoRequiredException("Please select the managed object and then attribute to be edited");
-
- String name = (_mbean.getName() != null) ? _mbean.getName() : _mbean.getType();
- ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(_mbean);
- if (serverRegistry.getAttributeModel(_mbean).getCount() == 0)
- {
- throw new InfoRequiredException("There are no attributes to be edited for " + name);
- }
-
- TabFolder tabFolder = tabFolderMap.get(_mbean.getType());
- int index = tabFolder.getSelectionIndex();
- if (index != 0)
- {
- tabFolder.setSelection(0);
- throw new InfoRequiredException("Please select the attribute to be edited");
- }
-
- TabItem tab = tabFolder.getItem(0);
- AttributesTabControl tabControl = (AttributesTabControl)tab.getData(CONTROLLER);
- AttributeData attribute = tabControl.getSelectionAttribute();
- if (attribute == null)
- throw new InfoRequiredException("Please select the attribute to be edited");
-
- tabControl.createDetailsPopup(attribute);
- }
-
- /**
- * Creates TabFolder and tabs for each mbeantype (eg Connection, Queue, Exchange)
- */
- private void createMBeanTypeTabFolder()
- {
- typeTabFolder = new TabFolder(_form.getBody(), SWT.NONE);
- FormData layoutData = new FormData();
- layoutData.left = new FormAttachment(0);
- layoutData.top = new FormAttachment(0);
- layoutData.right = new FormAttachment(100);
- layoutData.bottom = new FormAttachment(100);
- typeTabFolder.setLayoutData(layoutData);
- typeTabFolder.setVisible(false);
-
- TabItem tab = new TabItem(typeTabFolder, SWT.NONE);
- tab.setText(CONNECTION);
- MBeanTypeTabControl controller = new ConnectionTypeTabControl(typeTabFolder);
- tab.setData(CONTROLLER, controller);
- tab.setControl(controller.getControl());
-
- tab = new TabItem(typeTabFolder, SWT.NONE);
- tab.setText(EXCHANGE);
- controller = new ExchangeTypeTabControl(typeTabFolder);
- tab.setData(CONTROLLER, controller);
- tab.setControl(controller.getControl());
-
- tab = new TabItem(typeTabFolder, SWT.NONE);
- tab.setText(QUEUE);
- controller = new QueueTypeTabControl(typeTabFolder);
- tab.setData(CONTROLLER, controller);
- tab.setControl(controller.getControl());
-
- typeTabFolder.addListener(SWT.Selection, new Listener()
- {
- public void handleEvent(Event evt)
- {
- TabItem tab = (TabItem)evt.item;
- try
- {
- refreshTypeTabFolder(tab);
- }
- catch (Exception ex)
- {
- MBeanUtility.handleException(ex);
- }
- }
- });
- }
private void createNotificationsTabFolder()
{
- notificationTabFolder = new TabFolder(_form.getBody(), SWT.NONE);
+ _notificationTabFolder = new TabFolder(_form.getBody(), SWT.NONE);
FormData layoutData = new FormData();
layoutData.left = new FormAttachment(0);
layoutData.top = new FormAttachment(0);
layoutData.right = new FormAttachment(100);
layoutData.bottom = new FormAttachment(100);
- notificationTabFolder.setLayoutData(layoutData);
- notificationTabFolder.setVisible(false);
+ _notificationTabFolder.setLayoutData(layoutData);
+ _notificationTabFolder.setVisible(false);
- VHNotificationsTabControl controller = new VHNotificationsTabControl(notificationTabFolder);
- TabItem tab = new TabItem(notificationTabFolder, SWT.NONE);
+ VHNotificationsTabControl controller = new VHNotificationsTabControl(_notificationTabFolder);
+ TabItem tab = new TabItem(_notificationTabFolder, SWT.NONE);
tab.setText(NOTIFICATIONS);
- tab.setData(CONTROLLER, controller);
+ tab.setData(TabControl.CONTROLLER, controller);
tab.setControl(controller.getControl());
}
private void refreshNotificationPage()
{
- TabItem tab = notificationTabFolder.getItem(0);
- VHNotificationsTabControl controller = (VHNotificationsTabControl)tab.getData(CONTROLLER);
+ TabItem tab = _notificationTabFolder.getItem(0);
+ VHNotificationsTabControl controller = (VHNotificationsTabControl)tab.getData(TabControl.CONTROLLER);
controller.refresh();
- notificationTabFolder.setVisible(true);
+ _notificationTabFolder.setVisible(true);
}
- /**
- * Refreshes the Selected mbeantype tab. The control lists all the available mbeans
- * for an mbeantype(eg Queue, Exchange etc)
- * @param tab
- * @throws Exception
- */
- private void refreshTypeTabFolder(TabItem tab) throws Exception
+
+
+ private void generateTypeTabFolder() throws Exception
{
- if (tab == null)
+ if (_typeTabFolder != null && !_typeTabFolder.isDisposed())
{
- return;
+ _typeTabFolder.dispose();
}
- typeTabFolder.setSelection(tab);
- MBeanTypeTabControl controller = (MBeanTypeTabControl)tab.getData(CONTROLLER);
- controller.refresh();
- typeTabFolder.setVisible(true);
+
+ //Generates the full Queue/Connection/Exchange selection tab set
+ _typeTabFolder = MBeanTabFolderFactory.generateMBeanTypeTabFolder(
+ _form.getBody(), getServer(), getVirtualHost());
+ refreshTab(_typeTabFolder.getItem(0));
}
- private void refreshTypeTabFolder(String type) throws Exception
+ private void showTypeTabFolder(String type) throws Exception
{
+ if (_typeTabFolder != null && !_typeTabFolder.isDisposed())
+ {
+ _typeTabFolder.dispose();
+ }
+
if (CONNECTION.equals(type))
{
- refreshTypeTabFolder(typeTabFolder.getItem(0));
+ //Generates the Connection selection tab
+ _typeTabFolder = MBeanTabFolderFactory.generateConnectionTypeTabFolder(
+ _form.getBody(), getServer(), getVirtualHost());
+ refreshTab(_typeTabFolder.getItem(0));
}
else if (EXCHANGE.equals(type))
{
- refreshTypeTabFolder(typeTabFolder.getItem(1));
+ //Generates the Exchange selection tab
+ _typeTabFolder = MBeanTabFolderFactory.generateExchangeTypeTabFolder(
+ _form.getBody(), getServer(), getVirtualHost());
+ refreshTab(_typeTabFolder.getItem(0));
}
else if (QUEUE.equals(type))
{
- refreshTypeTabFolder(typeTabFolder.getItem(2));
+ //Generates the Queue selection tab
+ _typeTabFolder = MBeanTabFolderFactory.generateQueueTypeTabFolder(
+ _form.getBody(), getServer(), getVirtualHost());
+ refreshTab(_typeTabFolder.getItem(0));
+ }
+ }
+
+ private void clearView()
+ {
+ if (_tabFolder != null && !_tabFolder.isDisposed())
+ {
+ _tabFolder.setVisible(false);
+ }
+
+ if (_typeTabFolder != null && !_typeTabFolder.isDisposed())
+ {
+ _typeTabFolder.setVisible(false);
+ }
+
+ if (_notificationTabFolder != null && !_notificationTabFolder.isDisposed())
+ {
+ _notificationTabFolder.setVisible(false);
}
+
+ _form.setText(APPLICATION_NAME);
+ populateStatusBar("");
}
- /**
- * hides other folders and makes the given one visible.
- * @param tabFolder
- */
- private void setVisible(TabFolder tabFolder)
+ public void mbeanUnregistered(ManagedBean mbean)
{
- for (TabFolder folder : tabFolderMap.values())
+ //if the mbean is actually open, clear the view and empty the Back history
+ if(mbean == _mbean)
{
- if (folder == tabFolder)
- folder.setVisible(true);
- else
- folder.setVisible(false);
+ clearView();
+ _backHistory.clear();
+ _backAction.setEnabled(false);
+ ViewUtility.popupInfoMessage("MBean Unregistered",
+ "The open MBean was unregistered from the server.");
}
}
- private void setInvisible()
+ public void refresh()
{
- for (TabFolder folder : tabFolderMap.values())
+ if(!ApplicationRegistry.isServerConnected(_server))
{
- folder.setVisible(false);
+ return;
}
- if (typeTabFolder != null)
+ if (_tabFolder != null && !_tabFolder.isDisposed())
{
- typeTabFolder.setVisible(false);
+ if(_tabFolder.getVisible())
+ {
+ int selectedTab = _tabFolder.getSelectionIndex();
+ TabItem tab = _tabFolder.getItem(selectedTab);
+ TabControl controller = (TabControl) tab.getData(TabControl.CONTROLLER);
+ if(controller != null)
+ {
+ controller.refresh(_mbean);
+ }
+ return;
+ }
}
- if (notificationTabFolder != null)
+ if (_typeTabFolder != null && !_typeTabFolder.isDisposed())
{
- notificationTabFolder.setVisible(false);
+
+ if(_typeTabFolder.getVisible())
+ {
+ int selectedTab = _typeTabFolder.getSelectionIndex();
+ TabItem tab = _typeTabFolder.getItem(selectedTab);
+ TabControl controller = (TabControl) tab.getData(TabControl.CONTROLLER);
+ if(controller != null)
+ {
+ controller.refresh(_mbean);
+ }
+ return;
+ }
+ }
+
+ if (_notificationTabFolder != null && !_notificationTabFolder.isDisposed())
+ {
+ if(_notificationTabFolder.getVisible())
+ {
+ int selectedTab = _notificationTabFolder.getSelectionIndex();
+ TabItem tab = _notificationTabFolder.getItem(selectedTab);
+ TabControl controller = (TabControl) tab.getData(TabControl.CONTROLLER);
+ if(controller != null)
+ {
+ controller.refresh(_mbean);
+ }
+ return;
+ }
}
}
+ public void populateStatusBar(Image icon, String message)
+ {
+ IActionBars bars = getViewSite().getActionBars();
+ bars.getStatusLineManager().setMessage(icon, message);
+ }
+
+ public void populateStatusBar(String message)
+ {
+ IActionBars bars = getViewSite().getActionBars();
+ bars.getStatusLineManager().setMessage(message);
+ }
+
+ public void back() throws Exception
+ {
+ if(_backHistory.isEmpty())
+ {
+ return;
+ }
+
+ Object previous = _backHistory.removeLast();
+ if(_backHistory.isEmpty())
+ {
+ //if this is the last history item, disable the action button
+ _backAction.setEnabled(false);
+ }
+
+ if(previous instanceof ManagedBean)
+ {
+ openMBean((ManagedBean)previous, true);
+ }
+ else if (previous instanceof TreeObject)
+ {
+ _mbean = null;
+ clearView();
+ setFormTitle();
+
+ TreeObject node = (TreeObject) previous;
+ String mbeanType = node.getType();
+
+ if (NODE_TYPE_TYPEINSTANCE.equals(mbeanType))
+ {
+ generateTypeTabFolder();
+ }
+ else if (NODE_TYPE_MBEANTYPE.equals(mbeanType))
+ {
+ showTypeTabFolder(node.getName());
+ }
+ }
+
+ _form.layout(true);
+ _form.getBody().layout(true, true);
+ }
}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NavigationView.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NavigationView.java
index 1da13a9b56..1ca6c2b71d 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NavigationView.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NavigationView.java
@@ -21,18 +21,28 @@
package org.apache.qpid.management.ui.views;
import static org.apache.qpid.management.ui.Constants.*;
+import static org.apache.qpid.management.ui.ApplicationRegistry.DATA_DIR;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.qpid.management.common.mbeans.ConfigurationManagement;
+import org.apache.qpid.management.common.mbeans.LoggingManagement;
+import org.apache.qpid.management.common.mbeans.ServerInformation;
+import org.apache.qpid.management.common.mbeans.UserManagement;
+import org.apache.qpid.management.ui.ApiVersion;
import org.apache.qpid.management.ui.ApplicationRegistry;
import org.apache.qpid.management.ui.ManagedBean;
+import org.apache.qpid.management.ui.ManagedObject;
import org.apache.qpid.management.ui.ManagedServer;
import org.apache.qpid.management.ui.ServerRegistry;
import org.apache.qpid.management.ui.exceptions.InfoRequiredException;
+import org.apache.qpid.management.ui.exceptions.ManagementConsoleException;
import org.apache.qpid.management.ui.jmx.JMXServerRegistry;
import org.apache.qpid.management.ui.jmx.MBeanUtility;
import org.eclipse.jface.preference.PreferenceStore;
@@ -62,6 +72,8 @@ import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
/**
@@ -72,7 +84,7 @@ import org.eclipse.ui.part.ViewPart;
public class NavigationView extends ViewPart
{
public static final String ID = "org.apache.qpid.management.ui.navigationView";
- public static final String INI_FILENAME = System.getProperty("user.home") + File.separator + "qpidManagementConsole.ini";
+ public static final String INI_FILENAME = DATA_DIR + File.separator + "qpidmc_navigation.ini";
private static final String INI_SERVERS = "Servers";
private static final String INI_QUEUES = QUEUE + "s";
@@ -80,12 +92,19 @@ public class NavigationView extends ViewPart
private static final String INI_EXCHANGES = EXCHANGE + "s";
private TreeViewer _treeViewer = null;
- private TreeObject _rootNode = null;
private TreeObject _serversRootNode = null;
private PreferenceStore _preferences;
// Map of connected servers
- private HashMap<ManagedServer, TreeObject> _managedServerMap = new HashMap<ManagedServer, TreeObject>();
+ private ConcurrentHashMap<ManagedServer, TreeObject> _managedServerMap = new ConcurrentHashMap<ManagedServer, TreeObject>();
+
+ private static HashSet<String> _serverTopLevelMBeans = new HashSet<String>();
+ {
+ _serverTopLevelMBeans.add(UserManagement.TYPE);
+ _serverTopLevelMBeans.add(LoggingManagement.TYPE);
+ _serverTopLevelMBeans.add(ConfigurationManagement.TYPE);
+ _serverTopLevelMBeans.add(ServerInformation.TYPE);
+ }
private void createTreeViewer(Composite parent)
{
@@ -131,16 +150,26 @@ public class NavigationView extends ViewPart
{
public void treeExpanded(TreeExpansionEvent event)
{
- _treeViewer.setExpandedState(event.getElement(), true);
- // Following will cause the selection event to be sent, so commented
- // _treeViewer.setSelection(new StructuredSelection(event.getElement()));
- _treeViewer.refresh();
+ getSite().getShell().getDisplay().asyncExec(
+ new Runnable()
+ {
+ public void run()
+ {
+ _treeViewer.refresh();
+ }
+ });
}
public void treeCollapsed(TreeExpansionEvent event)
{
- _treeViewer.setExpandedState(event.getElement(), false);
- _treeViewer.refresh();
+ getSite().getShell().getDisplay().asyncExec(
+ new Runnable()
+ {
+ public void run()
+ {
+ _treeViewer.refresh();
+ }
+ });
}
});
@@ -180,7 +209,7 @@ public class NavigationView extends ViewPart
{
public void handleEvent(Event e)
{
- removeManagedObject(parentNode, (ManagedBean) selectedNode.getManagedObject());
+ removeManagedObject(parentNode, (ManagedBean) selectedNode.getManagedObject(), true);
_treeViewer.refresh();
// set the selection to the parent node
_treeViewer.setSelection(new StructuredSelection(parentNode));
@@ -202,14 +231,41 @@ public class NavigationView extends ViewPart
}
/**
- * Creates Qpid Server connection using JMX RMI protocol
+ * Creates Qpid Server connection
* @param server
* @throws Exception
*/
- private void createRMIServerConnection(ManagedServer server) throws Exception
+ private void createJMXServerConnection(ManagedServer server) throws Exception
{
// Currently Qpid Management Console only supports JMX MBeanServer
- ServerRegistry serverRegistry = new JMXServerRegistry(server);
+ JMXServerRegistry serverRegistry = new JMXServerRegistry(server);
+
+ try
+ {
+ //determine the management API version of the server just connected to
+ MBeanUtility.classifyManagementApiVersion(server, serverRegistry);
+ }
+ catch (Exception e)
+ {
+ //Exception classifying the server API, clean up the connection and rethrow
+ serverRegistry.closeServerConnection();
+ throw e;
+ }
+
+ //check that the console supports the API major version encountered, otherwise abort.
+ ApiVersion serverAPI = serverRegistry.getManagementApiVersion();
+
+ int serverMajor = serverAPI.getMajor();
+ int supportedMajor = ApplicationRegistry.SUPPORTED_QPID_JMX_API_MAJOR_VERSION;
+
+ if(serverMajor > supportedMajor)
+ {
+ serverRegistry.closeServerConnection();
+ throw new ManagementConsoleException("The server management API version encountered is not supported"
+ + " by this console release. Please check for an updated console release.");
+ }
+
+ //connection succeeded, add the ServerRegistry to the ApplicationRegistry
ApplicationRegistry.addServer(server, serverRegistry);
}
@@ -221,42 +277,32 @@ public class NavigationView extends ViewPart
* @param domain
* @throws Exception
*/
- public void addNewServer(String transportProtocol, String host, int port, String domain, String user, String pwd)
+ public void addNewServer(String host, int port, String domain, String user, String pwd)
throws Exception
{
- String serverAddress = host + ":" + port;
- String url = null;
ManagedServer managedServer = new ManagedServer(host, port, domain, user, pwd);
- if ("RMI".equals(transportProtocol))
+ String server = managedServer.getName();
+ List<TreeObject> list = _serversRootNode.getChildren();
+ for (TreeObject node : list)
{
- url = managedServer.getUrl();
- List<TreeObject> list = _serversRootNode.getChildren();
- for (TreeObject node : list)
+ ManagedServer nodeServer = (ManagedServer)node.getManagedObject();
+ if (server.equals(nodeServer.getName()))
{
- ManagedServer nodeServer = (ManagedServer)node.getManagedObject();
- if (url.equals(nodeServer.getUrl()))
- {
- // Server is already in the list of added servers, so now connect it.
- // Set the server node as selected and then connect it.
- _treeViewer.setSelection(new StructuredSelection(node));
- reconnect(user, pwd);
+ // Server is already in the list of added servers, so now connect it.
+ // Set the server node as selected and then connect it.
+ _treeViewer.setSelection(new StructuredSelection(node));
+ reconnect(user, pwd);
- return;
- }
+ return;
}
-
- // The server is not in the list of already added servers, so now connect and add it.
- managedServer.setName(serverAddress);
- createRMIServerConnection(managedServer);
- }
- else
- {
- throw new InfoRequiredException(transportProtocol + " transport is not supported");
}
+ // The server is not in the list of already added servers, so now connect and add it.
+ createJMXServerConnection(managedServer);
+
// Server connection is successful. Now add the server in the tree
- TreeObject serverNode = new TreeObject(serverAddress, NODE_TYPE_SERVER);
+ TreeObject serverNode = new TreeObject(server, NODE_TYPE_SERVER);
serverNode.setManagedObject(managedServer);
_serversRootNode.addChild(serverNode);
@@ -278,9 +324,15 @@ public class NavigationView extends ViewPart
addConfiguredItems(managedServer);
_treeViewer.refresh();
+
+ expandInitialMBeanView(serverNode);
+
+ //(re)select the server node now that it is connected to force a selectionEvent
+ _treeViewer.setSelection(new StructuredSelection(serverNode));
+ _treeViewer.refresh();
// save server address in file
- addServerInConfigFile(serverAddress);
+ addServerInConfigFile(server);
}
/**
@@ -289,6 +341,16 @@ public class NavigationView extends ViewPart
*/
private void createConfigFile()
{
+ File dir = new File(DATA_DIR);
+ if (!dir.exists())
+ {
+ if(!dir.mkdir())
+ {
+ System.out.println("Could not create application data directory " + DATA_DIR);
+ System.exit(1);
+ }
+ }
+
File file = new File(INI_FILENAME);
try
{
@@ -406,51 +468,33 @@ public class NavigationView extends ViewPart
}
}
- /**
- * Queries the qpid server for MBeans and populates the navigation view with all MBeans for
- * the given server node.
- * @param serverNode
- */
- private void populateServer(TreeObject serverNode) throws Exception
+ //check if the MBeanInfo can be retrieved.
+ private boolean haveAccessPermission(ManagedBean mbean)
{
- ManagedServer server = (ManagedServer) serverNode.getManagedObject();
- String domain = server.getDomain();
- if (!domain.equals(ALL))
- {
- TreeObject domainNode = new TreeObject(domain, NODE_TYPE_DOMAIN);
- domainNode.setParent(serverNode);
-
- populateDomain(domainNode);
+ try
+ {
+ MBeanUtility.getMBeanInfo(mbean);
}
- else
+ catch(Exception ex)
{
- List<TreeObject> domainList = new ArrayList<TreeObject>();
- List<String> domains = MBeanUtility.getAllDomains(server);
-
- for (String domainName : domains)
- {
- TreeObject domainNode = new TreeObject(domainName, NODE_TYPE_DOMAIN);
- domainNode.setParent(serverNode);
-
- domainList.add(domainNode);
- populateDomain(domainNode);
- }
+ return false;
}
+
+ return true;
}
-
+
/**
- * Queries the Qpid Server and populates the given domain node with all MBeans undser that domain.
- * @param domain
- * @throws IOException
+ * Queries the qpid server for MBeans and populates the navigation view with all MBeans for
+ * the given server node.
+ * @param serverNode
* @throws Exception
*/
- @SuppressWarnings("unchecked")
- private void populateDomain(TreeObject domain) throws IOException, Exception
+ private void populateServer(TreeObject serverNode) throws Exception
{
- ManagedServer server = (ManagedServer) domain.getParent().getManagedObject();
+ ManagedServer server = (ManagedServer) serverNode.getManagedObject();
+ String domain = server.getDomain();
- // Now populate the mbenas under those types
- List<ManagedBean> mbeans = MBeanUtility.getManagedObjectsForDomain(server, domain.getName());
+ List<ManagedBean> mbeans = MBeanUtility.getManagedObjectsForDomain(server, domain);
for (ManagedBean mbean : mbeans)
{
mbean.setServer(server);
@@ -461,19 +505,27 @@ public class NavigationView extends ViewPart
// manually by selecting from MBeanView
if (!(mbean.isConnection() || mbean.isExchange() || mbean.isQueue()))
{
- addManagedBean(domain, mbean);
+ //if we cant get the MBeanInfo then we cant display the mbean, so dont add it to the tree
+ if (haveAccessPermission(mbean))
+ {
+ addManagedBean(serverNode, mbean);
+ }
}
}
// To make it work with the broker without virtual host implementation.
// This will add the default nodes to the domain node
- for (TreeObject child : domain.getChildren())
+ boolean hasVirtualHost = false;
+ for (TreeObject child : serverNode.getChildren())
{
- if (!child.getName().startsWith(VIRTUAL_HOST))
+ if (child.getName().startsWith(VIRTUAL_HOST))
{
- addDefaultNodes(domain);
+ hasVirtualHost = true;
+ break;
}
-
- break;
+ }
+
+ if (!hasVirtualHost){
+ addDefaultNodes(serverNode);
}
}
@@ -538,15 +590,14 @@ public class NavigationView extends ViewPart
}
/**
- * Adds the given MBean to the given domain node. Creates Notification node for the MBean.
+ * Adds the given MBean to the given domain node.
* sample ObjectNames -
* org.apache.qpid:type=VirtualHost.VirtualHostManager,VirtualHost=localhost
* org.apache.qpid:type=VirtualHost.Queue,VirtualHost=test,name=ping_1
- * @param domain
- * @param mbean
- * @throws Exception
+ * @param parent parent tree node to add the mbean to
+ * @param mbean mbean to add
*/
- private void addManagedBean(TreeObject domain, ManagedBean mbean) // throws Exception
+ private void addManagedBean(TreeObject parent, ManagedBean mbean)
{
String name = mbean.getName();
// Split the mbean type into array of Strings, to create hierarchy
@@ -556,13 +607,21 @@ public class NavigationView extends ViewPart
// test->Queue->ping
String[] types = mbean.getType().split("\\.");
TreeObject typeNode = null;
- TreeObject parentNode = domain;
+ TreeObject parentNode = parent;
// Run this loop till all nodes(hierarchy) for this mbean are created. This loop only creates
// all the required parent nodes for the mbean
for (int i = 0; i < types.length; i++)
{
String type = types[i];
+
+ if(types.length == 1 && _serverTopLevelMBeans.contains(type))
+ {
+ //This mbean is not to be contained in a type hierarchy
+ //Just add it as a child of the server node.
+ break;
+ }
+
String valueOftype = mbean.getProperty(type);
// If value is not null, then there will be a parent node for this mbean
// eg. for type=VirtualHost the value is "test"
@@ -629,6 +688,7 @@ public class NavigationView extends ViewPart
// Add the mbean node now
TreeObject mbeanNode = new TreeObject(mbean);
+ mbeanNode.setVirtualHost(mbean.getVirtualHostName());
mbeanNode.setParent(typeNode);
// Add the mbean to the config file
@@ -636,11 +696,6 @@ public class NavigationView extends ViewPart
{
addItemInConfigFile(mbeanNode);
}
-
- // Add notification node
- // TODO: show this only if the mbean sends any notification
- //TreeObject notificationNode = new TreeObject(NOTIFICATION, NOTIFICATION);
- //notificationNode.setParent(mbeanNode);
}
private TreeObject createTypeNode(TreeObject parent, String name)
@@ -665,6 +720,11 @@ public class NavigationView extends ViewPart
*/
private void removeManagedObject(TreeObject parent)
{
+ if(parent == null)
+ {
+ return;
+ }
+
List<TreeObject> list = parent.getChildren();
for (TreeObject child : list)
{
@@ -679,7 +739,7 @@ public class NavigationView extends ViewPart
* @param parent
* @param mbean
*/
- private void removeManagedObject(TreeObject parent, ManagedBean mbean)
+ private void removeManagedObject(TreeObject parent, ManagedBean mbean, boolean removeFromConfigFile)
{
List<TreeObject> list = parent.getChildren();
TreeObject objectToRemove = null;
@@ -697,14 +757,17 @@ public class NavigationView extends ViewPart
}
else
{
- removeManagedObject(child, mbean);
+ removeManagedObject(child, mbean, removeFromConfigFile);
}
}
if (objectToRemove != null)
{
list.remove(objectToRemove);
- removeItemFromConfigFile(objectToRemove);
+ if(removeFromConfigFile)
+ {
+ removeItemFromConfigFile(objectToRemove);
+ }
}
}
@@ -733,9 +796,11 @@ public class NavigationView extends ViewPart
return;
}
- serverRegistry.closeServerConnection();
// Add server to the closed server list and the worker thread will remove the server from required places.
ApplicationRegistry.serverConnectionClosed(managedServer);
+
+ //close the connection
+ serverRegistry.closeServerConnection();
}
/**
@@ -753,8 +818,8 @@ public class NavigationView extends ViewPart
managedServer.setUser(user);
managedServer.setPassword(password);
- createRMIServerConnection(managedServer);
-
+ createJMXServerConnection(managedServer);
+
// put the server in the managed server map
_managedServerMap.put(managedServer, selectedNode);
@@ -773,8 +838,33 @@ public class NavigationView extends ViewPart
// Add the Queue/Exchanges/Connections from config file into the navigation tree
addConfiguredItems(managedServer);
+ expandInitialMBeanView(selectedNode);
+
+ //(re)select the server node now that it is connected to force a selectionEvent
+ _treeViewer.setSelection(new StructuredSelection(selectedNode));
_treeViewer.refresh();
}
+
+ private void expandInitialMBeanView(TreeObject serverNode)
+ {
+ if (serverNode.getChildren().size() == 0 )
+ {
+ return;
+ }
+ else
+ {
+ _treeViewer.setExpandedState(serverNode , true);
+ }
+
+ List<TreeObject> children = serverNode.getChildren();
+ for (TreeObject child : children)
+ {
+ if (child.getChildren().size() > 0)
+ {
+ _treeViewer.setExpandedState(child, true);
+ }
+ }
+ }
/**
* Adds the items(queues/exchanges/connectins) from config file to the server tree
@@ -954,11 +1044,9 @@ public class NavigationView extends ViewPart
composite.setLayout(gridLayout);
createTreeViewer(composite);
- _rootNode = new TreeObject("ROOT", "ROOT");
_serversRootNode = new TreeObject(NAVIGATION_ROOT, "ROOT");
- _serversRootNode.setParent(_rootNode);
- _treeViewer.setInput(_rootNode);
+ _treeViewer.setInput(_serversRootNode);
// set viewer as selection event provider for MBeanView
getSite().setSelectionProvider(_treeViewer);
@@ -1074,7 +1162,42 @@ public class NavigationView extends ViewPart
}
else
{
- return ApplicationRegistry.getImage(MBEAN_IMAGE);
+ ManagedObject obj = node.getManagedObject();
+ if(obj instanceof ManagedBean)
+ {
+ ManagedBean mbean = (ManagedBean) obj;
+ String mbeanType = mbean.getType();
+
+ if(mbeanType.equals(LoggingManagement.TYPE))
+ {
+ return ApplicationRegistry.getImage(LOGGING_MANAGEMENT_IMAGE);
+ }
+ else if(mbeanType.equals(UserManagement.TYPE))
+ {
+ return ApplicationRegistry.getImage(USER_MANAGEMENT_IMAGE);
+ }
+ else if(mbeanType.equals(ConfigurationManagement.TYPE))
+ {
+ return ApplicationRegistry.getImage(CONFIGURATION_MANAGEMENT_IMAGE);
+ }
+ else if(mbeanType.equals(ServerInformation.TYPE))
+ {
+ return ApplicationRegistry.getImage(SERVER_INFO_IMAGE);
+ }
+ else if(mbeanType.equals("VirtualHost.VirtualHostManager"))
+ {
+ return ApplicationRegistry.getImage(VHOST_MANAGER_IMAGE);
+ }
+ else
+ {
+ return ApplicationRegistry.getImage(MBEAN_IMAGE);
+ }
+
+ }
+ else
+ {
+ return ApplicationRegistry.getImage(MBEAN_IMAGE);
+ }
}
}
@@ -1146,7 +1269,7 @@ public class NavigationView extends ViewPart
try
{
- Thread.sleep(3000);
+ Thread.sleep(2000);
}
catch (Exception ex)
{ }
@@ -1157,25 +1280,12 @@ public class NavigationView extends ViewPart
/**
* Adds the mbean to the navigation tree
- * @param mbean
- * @throws Exception
+ * @param mbean mbean to add to the tree
*/
- public void addManagedBean(ManagedBean mbean) // throws Exception
+ public void addManagedBean(ManagedBean mbean)
{
TreeObject treeServerObject = _managedServerMap.get(mbean.getServer());
- List<TreeObject> domains = treeServerObject.getChildren();
- TreeObject domain = null;
- for (TreeObject child : domains)
- {
- if (child.getName().equals(mbean.getDomain()))
- {
- domain = child;
-
- break;
- }
- }
-
- addManagedBean(domain, mbean);
+ addManagedBean(treeServerObject, mbean);
_treeViewer.refresh();
}
@@ -1197,23 +1307,20 @@ public class NavigationView extends ViewPart
{
public void run()
{
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ final MBeanView view = (MBeanView)window.getActivePage().findView(MBeanView.ID);
+
for (ManagedBean mbean : removalList)
{
TreeObject treeServerObject = _managedServerMap.get(mbean.getServer());
- List<TreeObject> domains = treeServerObject.getChildren();
- TreeObject domain = null;
- for (TreeObject child : domains)
- {
- if (child.getName().equals(mbean.getDomain()))
- {
- domain = child;
- break;
- }
+ if(view != null)
+ {
+ //notify the MBeanView in case the unregistered mbean is being viewed
+ view.mbeanUnregistered(mbean);
}
-
- removeManagedObject(domain, mbean);
- // serverRegistry.removeManagedObject(mbean);
+
+ removeManagedObject(treeServerObject, mbean, false);
}
_treeViewer.refresh();
@@ -1239,7 +1346,18 @@ public class NavigationView extends ViewPart
{
for (ManagedServer server : closedServers)
{
- removeManagedObject(_managedServerMap.get(server));
+ if(server == null)
+ {
+ continue;
+ }
+
+ TreeObject node = _managedServerMap.get(server);
+ if(node ==null)
+ {
+ continue;
+ }
+
+ removeManagedObject(node);
_managedServerMap.remove(server);
ApplicationRegistry.removeServer(server);
}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NotificationsTabControl.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NotificationsTabControl.java
index 6894080859..ea49a5c006 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NotificationsTabControl.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NotificationsTabControl.java
@@ -21,7 +21,6 @@
package org.apache.qpid.management.ui.views;
import static org.apache.qpid.management.ui.Constants.BUTTON_CLEAR;
-import static org.apache.qpid.management.ui.Constants.BUTTON_REFRESH;
import static org.apache.qpid.management.ui.Constants.DESCRIPTION;
import static org.apache.qpid.management.ui.Constants.FONT_BOLD;
import static org.apache.qpid.management.ui.Constants.FONT_BUTTON;
@@ -29,6 +28,7 @@ import static org.apache.qpid.management.ui.Constants.FONT_ITALIC;
import static org.apache.qpid.management.ui.Constants.SUBSCRIBE_BUTTON;
import static org.apache.qpid.management.ui.Constants.UNSUBSCRIBE_BUTTON;
+import java.util.ArrayList;
import java.util.List;
import org.apache.qpid.management.ui.ApplicationRegistry;
@@ -50,7 +50,6 @@ import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.TabFolder;
@@ -65,23 +64,25 @@ public class NotificationsTabControl extends VHNotificationsTabControl
private SelectionListener selectionListener;
private SelectionListener comboListener;
- private Combo notificationNameCombo = null;
- private Combo typesCombo = null;
- private Label descriptionLabel = null;
- private Button _subscribeButton = null;
- private Button _unsubscribeButton = null;
+ private Combo _notificationNameCombo;
+ private Combo _typesCombo;
+ private Label _descriptionLabel;
+ private Button _subscribeButton;
+ private Button _unsubscribeButton;
- public NotificationsTabControl(TabFolder tabFolder)
+ public NotificationsTabControl(TabFolder tabFolder, ManagedBean mbean)
{
super(tabFolder);
+ _mbean = mbean;
+
+ populateNotificationInfo();
}
protected void createWidgets()
- {
+ {
selectionListener = new SelectionListenerImpl();
comboListener = new ComboSelectionListener();
createNotificationInfoComposite();
- //addFilterComposite();
addButtons();
createTableViewer();
}
@@ -103,21 +104,21 @@ public class NotificationsTabControl extends VHNotificationsTabControl
formData.left = new FormAttachment(0, 10);
label.setLayoutData(formData);
- notificationNameCombo = new Combo(composite, SWT.READ_ONLY | SWT.DROP_DOWN);
+ _notificationNameCombo = new Combo(composite, SWT.READ_ONLY | SWT.DROP_DOWN);
formData = new FormData();
formData.top = new FormAttachment(label, 10);
formData.left = new FormAttachment(0, 10);
formData.right = new FormAttachment(40);
- notificationNameCombo.setLayoutData(formData);
- notificationNameCombo.addSelectionListener(comboListener);
+ _notificationNameCombo.setLayoutData(formData);
+ _notificationNameCombo.addSelectionListener(comboListener);
- typesCombo = new Combo(composite, SWT.READ_ONLY | SWT.DROP_DOWN);
+ _typesCombo = new Combo(composite, SWT.READ_ONLY | SWT.DROP_DOWN);
formData = new FormData();
formData.top = new FormAttachment(label, 10);
- formData.left = new FormAttachment(notificationNameCombo, 5);
+ formData.left = new FormAttachment(_notificationNameCombo, 5);
formData.right = new FormAttachment(65);
- typesCombo.setLayoutData(formData);
- typesCombo.addSelectionListener(comboListener);
+ _typesCombo.setLayoutData(formData);
+ _typesCombo.addSelectionListener(comboListener);
_subscribeButton = new Button(composite, SWT.PUSH | SWT.CENTER);
_subscribeButton.setFont(ApplicationRegistry.getFont(FONT_BUTTON));
@@ -141,30 +142,30 @@ public class NotificationsTabControl extends VHNotificationsTabControl
Label fixedLabel = _toolkit.createLabel(composite, "");
formData = new FormData();
- formData.top = new FormAttachment(notificationNameCombo, 5);
+ formData.top = new FormAttachment(_notificationNameCombo, 5);
formData.left = new FormAttachment(0, 10);
fixedLabel.setLayoutData(formData);
fixedLabel.setText(DESCRIPTION + " : ");
fixedLabel.setFont(ApplicationRegistry.getFont(FONT_BOLD));
- descriptionLabel = _toolkit.createLabel(composite, "");
+ _descriptionLabel = _toolkit.createLabel(composite, "");
formData = new FormData();
- formData.top = new FormAttachment(notificationNameCombo, 5);
+ formData.top = new FormAttachment(_notificationNameCombo, 5);
formData.left = new FormAttachment(fixedLabel, 10);
formData.right = new FormAttachment(100);
- descriptionLabel.setLayoutData(formData);
- descriptionLabel.setText(" ");
- descriptionLabel.setFont(ApplicationRegistry.getFont(FONT_ITALIC));
+ _descriptionLabel.setLayoutData(formData);
+ _descriptionLabel.setText(" ");
+ _descriptionLabel.setFont(ApplicationRegistry.getFont(FONT_ITALIC));
}
/**
- * Creates clear buttin and refresh button
+ * Creates clear button
*/
protected void addButtons()
{
Composite composite = _toolkit.createComposite(_form.getBody(), SWT.NONE);
- composite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
- composite.setLayout(new GridLayout(2, true));
+ composite.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false));
+ composite.setLayout(new GridLayout(2,false));
// Add Clear Button
_clearButton = _toolkit.createButton(composite, BUTTON_CLEAR, SWT.PUSH | SWT.CENTER);
@@ -173,83 +174,53 @@ public class NotificationsTabControl extends VHNotificationsTabControl
gridData.widthHint = 80;
_clearButton.setLayoutData(gridData);
_clearButton.addSelectionListener(new SelectionAdapter()
- {
- public void widgetSelected(SelectionEvent e)
- {
- if (_mbean == null)
- return;
-
- IStructuredSelection ss = (IStructuredSelection)_tableViewer.getSelection();
- ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(_mbean);
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ if (_mbean == null)
+ {
+ return;
+ }
+
+ ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(MBeanView.getServer());
+ IStructuredSelection ss = (IStructuredSelection)_tableViewer.getSelection();
+ if(!ss.isEmpty())
+ {
+ //clear selected Notifications
serverRegistry.clearNotifications(_mbean, ss.toList());
- refresh();
}
- });
-
- // Add Refresh Button
- _refreshButton = _toolkit.createButton(composite, BUTTON_REFRESH, SWT.PUSH | SWT.CENTER);
- _refreshButton.setFont(ApplicationRegistry.getFont(FONT_BUTTON));
- gridData = new GridData(SWT.TRAIL, SWT.TOP, true, false);
- gridData.widthHint = 80;
- _refreshButton.setLayoutData(gridData);
- _refreshButton.addSelectionListener(new SelectionAdapter()
- {
- public void widgetSelected(SelectionEvent e)
- {
- if (_mbean == null)
+ else if(_notifications != null)
+ {
+ //clear all the notifications, if there are any
+
+ //check the user is certain of this clear-all operation
+ int response = ViewUtility.popupOkCancelConfirmationMessage(
+ "Clear Notifications", "Clear all Notifications for this MBean?");
+ if(response != SWT.OK)
+ {
return;
+ }
- refresh();
+ synchronized(this)
+ {
+ List<NotificationObject> newList = new ArrayList<NotificationObject>();
+ newList.addAll(_notifications);
+ serverRegistry.clearNotifications(_mbean, newList);
+ }
}
- });
+
+ refresh();
+ }
+ });
+ //add description
+ Label desc = _toolkit.createLabel(composite,"Clears the selected Notifications, or all if none are selected");
+ desc.setLayoutData(new GridData(SWT.LEFT,SWT.CENTER, false, false));
}
-
+
@Override
public void refresh(ManagedBean mbean)
{
- _mbean = mbean;
- _notifications = null;
- _table.deselectAll();
- _tableViewer.getTable().clearAll();
-
- if (_mbean == null)
- {
- _tableViewer.getTable().clearAll();
- _subscribeButton.setEnabled(false);
- _unsubscribeButton.setEnabled(false);
- return;
- }
-
- if (!doesMBeanSendsNotification())
- {
- Control[] children = _form.getBody().getChildren();
- for (int i = 0; i < children.length; i++)
- {
- children[i].setVisible(false);
- }
-
- String name = (_mbean.getName() != null) ? _mbean.getName() : _mbean.getType();
- _form.setText(name + " does not send any notification");
- return;
- }
-
- Control[] children = _form.getBody().getChildren();
- for (int i = 0; i < children.length; i++)
- {
- children[i].setVisible(true);
- }
-
- populateNotificationInfo();
- workerRunning = true;
- _form.layout(true);
- _form.getBody().layout(true, true);
- }
-
- public void refresh()
- {
- _notifications = null;
- _table.deselectAll();
- _tableViewer.getTable().clearAll();
+ refresh();
}
/**
@@ -257,26 +228,26 @@ public class NotificationsTabControl extends VHNotificationsTabControl
*/
private void populateNotificationInfo()
{
- notificationNameCombo.removeAll();
+ _notificationNameCombo.removeAll();
NotificationInfoModel[] items = MBeanUtility.getNotificationInfo(_mbean);
if (items.length > 1)
{
- notificationNameCombo.add(SELECT_NOTIFICATIONNAME);
+ _notificationNameCombo.add(SELECT_NOTIFICATIONNAME);
}
for (int i = 0; i < items.length; i++)
{
- notificationNameCombo.add(items[i].getName());
- notificationNameCombo.setData(items[i].getName(), items[i]);
+ _notificationNameCombo.add(items[i].getName());
+ _notificationNameCombo.setData(items[i].getName(), items[i]);
}
- notificationNameCombo.select(0);
+ _notificationNameCombo.select(0);
- typesCombo.removeAll();
- typesCombo.add("Select Type", 0);
- typesCombo.select(0);
- typesCombo.setEnabled(false);
+ _typesCombo.removeAll();
+ _typesCombo.add("Select Type", 0);
+ _typesCombo.select(0);
+ _typesCombo.setEnabled(false);
- populateNotificationType(notificationNameCombo.getItem(0));
+ populateNotificationType(_notificationNameCombo.getItem(0));
checkForEnablingButtons();
}
@@ -285,18 +256,18 @@ public class NotificationsTabControl extends VHNotificationsTabControl
*/
private void checkForEnablingButtons()
{
- int nameIndex = notificationNameCombo.getSelectionIndex();
- int itemCount = notificationNameCombo.getItems().length;
+ int nameIndex = _notificationNameCombo.getSelectionIndex();
+ int itemCount = _notificationNameCombo.getItems().length;
if ((itemCount > 1) && (nameIndex == 0))
{
_subscribeButton.setEnabled(false);
_unsubscribeButton.setEnabled(false);
- descriptionLabel.setText("");
+ _descriptionLabel.setText("");
return;
}
- int typeIndex = typesCombo.getSelectionIndex();
- itemCount = typesCombo.getItems().length;
+ int typeIndex = _typesCombo.getSelectionIndex();
+ itemCount = _typesCombo.getItems().length;
if ((itemCount > 1) && (typeIndex == 0))
{
_subscribeButton.setEnabled(false);
@@ -304,8 +275,8 @@ public class NotificationsTabControl extends VHNotificationsTabControl
return;
}
- String type = typesCombo.getItem(typeIndex);
- String name = notificationNameCombo.getItem(nameIndex);
+ String type = _typesCombo.getItem(typeIndex);
+ String name = _notificationNameCombo.getItem(nameIndex);
ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(_mbean);
if (serverRegistry.hasSubscribedForNotifications(_mbean, name, type))
@@ -320,15 +291,6 @@ public class NotificationsTabControl extends VHNotificationsTabControl
}
}
- private boolean doesMBeanSendsNotification()
- {
- NotificationInfoModel[] items = MBeanUtility.getNotificationInfo(_mbean);
- if (items == null || items.length == 0)
- return false;
- else
- return true;
- }
-
/**
* Selection listener for subscribing or unsubscribing the notifications
*/
@@ -340,8 +302,8 @@ public class NotificationsTabControl extends VHNotificationsTabControl
return;
Button source = (Button)e.getSource();
- String type = typesCombo.getItem(typesCombo.getSelectionIndex());
- String name = notificationNameCombo.getItem(notificationNameCombo.getSelectionIndex());
+ String type = _typesCombo.getItem(_typesCombo.getSelectionIndex());
+ String name = _notificationNameCombo.getItem(_notificationNameCombo.getSelectionIndex());
if (source == _unsubscribeButton)
{
try
@@ -380,7 +342,7 @@ public class NotificationsTabControl extends VHNotificationsTabControl
return;
Combo combo = (Combo)e.getSource();
- if (combo == notificationNameCombo)
+ if (combo == _notificationNameCombo)
{
String selectedItem = combo.getItem(combo.getSelectionIndex());
populateNotificationType(selectedItem);
@@ -391,23 +353,23 @@ public class NotificationsTabControl extends VHNotificationsTabControl
private void populateNotificationType(String notificationName)
{
- NotificationInfoModel data = (NotificationInfoModel)notificationNameCombo.getData(notificationName);
+ NotificationInfoModel data = (NotificationInfoModel)_notificationNameCombo.getData(notificationName);
if (data == null)
{
- descriptionLabel.setText("");
- typesCombo.select(0);
- typesCombo.setEnabled(false);
+ _descriptionLabel.setText("");
+ _typesCombo.select(0);
+ _typesCombo.setEnabled(false);
return;
}
- descriptionLabel.setText(data.getDescription());
- typesCombo.removeAll();
- typesCombo.setItems(data.getTypes());
- if (typesCombo.getItemCount() > 1)
+ _descriptionLabel.setText(data.getDescription());
+ _typesCombo.removeAll();
+ _typesCombo.setItems(data.getTypes());
+ if (_typesCombo.getItemCount() > 1)
{
- typesCombo.add(SELECT_NOTIFICATIONTYPE, 0);
+ _typesCombo.add(SELECT_NOTIFICATIONTYPE, 0);
}
- typesCombo.select(0);
- typesCombo.setEnabled(true);
+ _typesCombo.select(0);
+ _typesCombo.setEnabled(true);
}
/**
@@ -417,11 +379,10 @@ public class NotificationsTabControl extends VHNotificationsTabControl
{
ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(_mbean);
List<NotificationObject> newList = serverRegistry.getNotifications(_mbean);
- if (newList == null)
- return;
-
- _notifications = newList;
- _tableViewer.setInput(_notifications);
- _tableViewer.refresh();
+ synchronized(this)
+ {
+ _notifications = newList;
+ _tableViewer.setInput(_notifications);
+ }
}
}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/OperationTabControl.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/OperationTabControl.java
index f2cd594684..ff2005e4bb 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/OperationTabControl.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/OperationTabControl.java
@@ -22,7 +22,6 @@ package org.apache.qpid.management.ui.views;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
@@ -68,7 +67,6 @@ import org.eclipse.ui.forms.widgets.FormToolkit;
/**
* Control class for the MBean operations tab. It creates the required widgets
* for the selected MBean.
- * @author Bhupendra Bhardwaj
*/
public class OperationTabControl extends TabControl
{
@@ -223,7 +221,7 @@ public class OperationTabControl extends TabControl
// Customised parameter widgets
if (_mbean.isExchange() &&
- EXCHANGE_TYPE_VALUES[2].equals(_mbean.getProperty(EXCHANGE_TYPE)) &&
+ DEFAULT_EXCHANGE_TYPE_VALUES[2].equals(_mbean.getProperty(EXCHANGE_TYPE)) &&
_opData.getName().equalsIgnoreCase(OPERATION_CREATE_BINDING))
{
customCreateNewBinding();
@@ -276,7 +274,7 @@ public class OperationTabControl extends TabControl
}
else if (param.getName().equals(EXCHANGE_TYPE))
{
- items = EXCHANGE_TYPE_VALUES;
+ items = DEFAULT_EXCHANGE_TYPE_VALUES;
}
else if (isUserListParameter(param))
{
@@ -519,7 +517,7 @@ public class OperationTabControl extends TabControl
private void populateResults(Object result)
{
Display display = Display.getCurrent();
- int width = 600;
+ int width = 610;
int height = 400;
Shell shell = ViewUtility.createPopupShell(RESULT, width, height);
shell.setImage(ApplicationRegistry.getImage(CONSOLE_IMAGE));
@@ -603,21 +601,37 @@ public class OperationTabControl extends TabControl
return;
}
- // customized for passwords
- String securityMechanism = ApplicationRegistry.getSecurityMechanism();
- if ((MECH_CRAMMD5.equals(securityMechanism)) && PASSWORD.equalsIgnoreCase(param.getName()))
+ //Custom handling for the PASSWORD field
+ if (param.getName().equalsIgnoreCase(PASSWORD))
{
- try
+ //Convert the String value to a character array if that is what is required.
+ if (param.getType().equals("[C"))
{
- param.setValue(ViewUtility.getMD5HashedCharArray(param.getValue()));
- }
- catch (Exception ex)
- {
- MBeanUtility.handleException(_mbean, ex);
- return;
+ // Retreive the mBean type and version.
+ // If we have a version 1 UserManagement class mbean then it expects the password
+ // to be sent as the hashed version.
+ if (_mbean.getType().equals("UserManagement") && _mbean.getVersion() == 1)
+ {
+ try
+ {
+ param.setValue(ViewUtility.getHash((String) param.getValue()));
+ }
+ catch (Exception hashException)
+ {
+ ViewUtility.popupErrorMessage(_form.getText(),
+ "Unable to calculate hash for Password:"
+ + hashException.getMessage());
+ return;
+ }
+ }
+ else
+ {
+ param.setValue(((String) param.getValue()).toCharArray());
+ }
}
}
// end of customization
+
}
}
@@ -721,7 +735,14 @@ public class OperationTabControl extends TabControl
{
boolean success = Boolean.parseBoolean(result.toString());
String message = success ? OPERATION_SUCCESSFUL : OPERATION_UNSUCCESSFUL;
- ViewUtility.popupInfoMessage(title, message);
+ if(success)
+ {
+ ViewUtility.popupInfoMessage(title, message);
+ }
+ else
+ {
+ ViewUtility.popupErrorMessage(title, message);
+ }
}
else if (_opData.getParameters() != null && !_opData.getParameters().isEmpty())
{
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/QueueTypeTabControl.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/QueueTypeTabControl.java
deleted file mode 100644
index 31a0bc857b..0000000000
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/QueueTypeTabControl.java
+++ /dev/null
@@ -1,296 +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.
- *
- */
-
-package org.apache.qpid.management.ui.views;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import org.apache.qpid.management.ui.ApplicationRegistry;
-import org.apache.qpid.management.ui.Constants;
-import org.apache.qpid.management.ui.ManagedBean;
-import org.apache.qpid.management.ui.ServerRegistry;
-import org.apache.qpid.management.ui.jmx.MBeanUtility;
-import org.apache.qpid.management.ui.model.AttributeData;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Group;
-import org.eclipse.swt.widgets.TabFolder;
-
-/**
- * Controller class, which takes care of displaying appropriate information and widgets for Queues.
- * This allows user to select Queues and add those to the navigation view
- */
-public class QueueTypeTabControl extends MBeanTypeTabControl
-{
- private boolean _showTempQueues = false;
- private Button _sortBySizeButton = null;
- private Button _sortByConsumercountButton = null;
- private Button _sortByNameButton = null;
- private Button _showTempQueuesButton = null;
-
- private ComparatorImpl _sorterByAttribute = new ComparatorImpl();
-
- // Map required for sorting queues based on attribute values
- private Map<AttributeData, ManagedBean> _queueDepthMap = new LinkedHashMap<AttributeData, ManagedBean>();
- // Map used for sorting Queues based on consumer count
- private Map<AttributeData, ManagedBean> _queueConsumerCountMap = new LinkedHashMap<AttributeData, ManagedBean>();
-
-
- public QueueTypeTabControl(TabFolder tabFolder)
- {
- super(tabFolder, Constants.QUEUE);
- createWidgets();
- }
-
- protected void createWidgets()
- {
- createHeaderComposite(getFormComposite());
- createButtonsComposite(getFormComposite());
- createListComposite();
- }
-
- @Override
- public void refresh() throws Exception
- {
- setLabelValues();
- selectDefaultSortingButton();
- populateList();
- layout();
- }
-
- /**
- * populates the map with mbean name and the mbean object.
- * @throws Exception
- */
- protected void populateList() throws Exception
- {
- // map should be cleared before populating it with new values
- getMBeansMap().clear();
- _queueDepthMap.clear();
- _queueConsumerCountMap.clear();
-
- ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(MBeanView.getServer());
- String[] items = null;
- java.util.List<ManagedBean> list = null;
-
- // populate the map and list with appropriate mbeans
- list = serverRegistry.getQueues(MBeanView.getVirtualHost());
- items = getQueueItems(list);
- // sort the refreshed list in the selected order
- if (_sortBySizeButton.getSelection())
- {
- sortQueuesByQueueDepth();
- }
- else if (_sortByConsumercountButton.getSelection())
- {
- sortQueuesByConsumerCount();
- }
- else
- {
- getListWidget().setItems(items);
- }
- }
-
- private void selectDefaultSortingButton()
- {
- _sortByNameButton.setSelection(true);
- _sortBySizeButton.setSelection(false);
- _sortByConsumercountButton.setSelection(false);
-
- _showTempQueues = false;
- _showTempQueuesButton.setSelection(_showTempQueues);
- }
-
- protected void createListComposite()
- {
- // Composite to contain the item list
- Composite composite = getToolkit().createComposite(getFormComposite());
- GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
- composite.setLayoutData(gridData);
- GridLayout layout = new GridLayout(2, true);
- layout.verticalSpacing = 0;
- composite.setLayout(layout);
-
- createListComposite(composite);
-
- // Composite to contain buttons like - Sort by size
- Composite _sortingComposite = getToolkit().createComposite(composite);
- gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
- _sortingComposite.setLayoutData(gridData);
- GridLayout gridLayout = new GridLayout();
- gridLayout.verticalSpacing = 20;
- _sortingComposite.setLayout(gridLayout);
-
- Group sortingGroup = new Group(_sortingComposite, SWT.SHADOW_NONE);
- sortingGroup.setBackground(_sortingComposite.getBackground());
- sortingGroup.setText(" Sort List By ");
- sortingGroup.setFont(ApplicationRegistry.getFont(Constants.FONT_BOLD));
- gridData = new GridData(SWT.CENTER, SWT.TOP, true, false);
- sortingGroup.setLayoutData(gridData);
- sortingGroup.setLayout(new GridLayout());
-
- _sortByNameButton = getToolkit().createButton(sortingGroup, Constants.QUEUE_SORT_BY_NAME, SWT.RADIO);
- gridData = new GridData(SWT.LEAD, SWT.CENTER, true, false);
- _sortByNameButton.setLayoutData(gridData);
- _sortByNameButton.addSelectionListener(new SelectionAdapter(){
- public void widgetSelected(SelectionEvent e)
- {
- try
- {
- // sort the stored list of items
- java.util.List<String> list = new ArrayList<String>(getMBeansMap().keySet());
- Collections.sort(list);
- getListWidget().setItems(list.toArray(new String[0]));
- }
- catch (Exception ex)
- {
- MBeanUtility.handleException(ex);
- }
- }
- });
-
- _sortBySizeButton = getToolkit().createButton(sortingGroup, Constants.QUEUE_SORT_BY_DEPTH, SWT.RADIO);
- gridData = new GridData(SWT.LEAD, SWT.CENTER, true, false);
- _sortBySizeButton.setLayoutData(gridData);
- _sortBySizeButton.addSelectionListener(new SelectionAdapter(){
- public void widgetSelected(SelectionEvent e)
- {
- try
- {
- // sort the stored list of items
- sortQueuesByQueueDepth();
- }
- catch (Exception ex)
- {
- MBeanUtility.handleException(ex);
- }
- }
- });
-
- _sortByConsumercountButton = getToolkit().createButton(sortingGroup, Constants.QUEUE_SORT_BY_CONSUMERCOUNT, SWT.RADIO);
- gridData = new GridData(SWT.LEAD, SWT.CENTER, true, false);
- _sortByConsumercountButton.setLayoutData(gridData);
- _sortByConsumercountButton.addSelectionListener(new SelectionAdapter(){
- public void widgetSelected(SelectionEvent e)
- {
- try
- {
- sortQueuesByConsumerCount();
- }
- catch (Exception ex)
- {
- MBeanUtility.handleException(ex);
- }
- }
- });
-
- _showTempQueuesButton = getToolkit().createButton(_sortingComposite, Constants.QUEUE_SHOW_TEMP_QUEUES, SWT.CHECK);
- _showTempQueuesButton.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, true, false));
- _showTempQueuesButton.addSelectionListener(new SelectionAdapter(){
- public void widgetSelected(SelectionEvent e)
- {
- Button button = (Button)e.widget;
- _showTempQueues = button.getSelection();
- try
- {
- populateList();
- }
- catch (Exception ex)
- {
- MBeanUtility.handleException(ex);
- }
- }
- });
- }
-
-
- private String[] getQueueItems(java.util.List<ManagedBean> list) throws Exception
- {
- if (list == null)
- return new String[0];
-
- // Sort the list. It will keep the mbeans in sorted order in the _queueMap, which is required for
- // sorting the queue according to size etc
- Collections.sort(list, getMBeanNameSorter());
- java.util.List<String> items = new ArrayList<String>();;
- int i = 0;
- for (ManagedBean mbean : list)
- {
- if ((!_showTempQueues && mbean.isTempQueue()))
- {
- continue;
- }
- AttributeData data = MBeanUtility.getAttributeData(mbean, Constants.ATTRIBUTE_QUEUE_DEPTH);
- String value = mbean.getName() + " (" + data.getValue().toString() + " KB)";
- items.add(value);
- //items[i] = mbean.getName() + " (" + value + " KB)";
- getMBeansMap().put(value, mbean);
- _queueDepthMap.put(data, mbean);
- data = MBeanUtility.getAttributeData(mbean, Constants.ATTRIBUTE_QUEUE_CONSUMERCOUNT);
- _queueConsumerCountMap.put(data, mbean);
- i++;
- }
-
- return items.toArray(new String[0]);
- }
-
-
- private void sortQueuesByQueueDepth()
- {
- // Queues are already in the alphabetically sorted order in _queueMap, now sort for queueDepth
- java.util.List<AttributeData> list = new ArrayList<AttributeData>(_queueDepthMap.keySet());
- Collections.sort(list, _sorterByAttribute);
-
- String[] items = new String[list.size()];
- int i = 0;
- for (AttributeData data : list)
- {
- ManagedBean mbean = _queueDepthMap.get(data);
- String value = data.getValue().toString();
- items[i++] = mbean.getName() + " (" + value + " KB)";
- }
- getListWidget().setItems(items);
- }
-
- private void sortQueuesByConsumerCount()
- {
- java.util.List<AttributeData> list = new ArrayList<AttributeData>(_queueConsumerCountMap.keySet());
- Collections.sort(list, _sorterByAttribute);
-
- String[] items = new String[list.size()];
- int i = 0;
- for (AttributeData data : list)
- {
- ManagedBean mbean = _queueConsumerCountMap.get(data);
- String value = data.getValue().toString();
- items[i++] = mbean.getName() + " (" + value + " )";
- }
- getListWidget().setItems(items);
- }
-}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/TabControl.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/TabControl.java
index c13c92066c..156543d603 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/TabControl.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/TabControl.java
@@ -33,6 +33,7 @@ import org.eclipse.swt.widgets.TabFolder;
*/
public abstract class TabControl
{
+ public static final String CONTROLLER = "controller";
protected ManagedBean _mbean = null;
protected TabFolder _tabFolder = null;
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/VHNotificationsTabControl.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/VHNotificationsTabControl.java
index be25707bd3..4e21e9e865 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/VHNotificationsTabControl.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/VHNotificationsTabControl.java
@@ -22,7 +22,6 @@
package org.apache.qpid.management.ui.views;
import static org.apache.qpid.management.ui.Constants.BUTTON_CLEAR;
-import static org.apache.qpid.management.ui.Constants.BUTTON_REFRESH;
import static org.apache.qpid.management.ui.Constants.CONSOLE_IMAGE;
import static org.apache.qpid.management.ui.Constants.FONT_BUTTON;
@@ -35,7 +34,6 @@ import org.apache.qpid.management.ui.model.NotificationObject;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ILabelProviderListener;
-import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
@@ -68,7 +66,8 @@ public class VHNotificationsTabControl extends TabControl
protected Table _table = null;
protected TableViewer _tableViewer = null;
- protected Thread worker = null;
+ protected Thread _worker = null;
+ protected boolean _workerRunning = false;
protected List<NotificationObject> _notifications = null;
@@ -86,7 +85,6 @@ public class VHNotificationsTabControl extends TabControl
};
protected Button _clearButton = null;
- protected Button _refreshButton = null;
public VHNotificationsTabControl(TabFolder tabFolder)
{
@@ -98,8 +96,7 @@ public class VHNotificationsTabControl extends TabControl
gridLayout.marginHeight = 0;
_form.getBody().setLayout(gridLayout);
- worker = new Thread(new Worker());
- worker.start();
+ createWidgets();
}
protected void createWidgets()
@@ -113,10 +110,6 @@ public class VHNotificationsTabControl extends TabControl
*/
public Control getControl()
{
- if (_table == null)
- {
- createWidgets();
- }
return _form;
}
@@ -126,8 +119,8 @@ public class VHNotificationsTabControl extends TabControl
protected void addButtons()
{
Composite composite = _toolkit.createComposite(_form.getBody(), SWT.NONE);
- composite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
- composite.setLayout(new GridLayout(2, true));
+ composite.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false));
+ composite.setLayout(new GridLayout(2,false));
// Add Clear Button
_clearButton = _toolkit.createButton(composite, BUTTON_CLEAR, SWT.PUSH | SWT.CENTER);
@@ -136,30 +129,40 @@ public class VHNotificationsTabControl extends TabControl
gridData.widthHint = 80;
_clearButton.setLayoutData(gridData);
_clearButton.addSelectionListener(new SelectionAdapter()
- {
- public void widgetSelected(SelectionEvent e)
- {
- //TODO : Get selected rows and clear those
- IStructuredSelection ss = (IStructuredSelection)_tableViewer.getSelection();
- ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(MBeanView.getServer());
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(MBeanView.getServer());
+ IStructuredSelection ss = (IStructuredSelection)_tableViewer.getSelection();
+ if(!ss.isEmpty())
+ {
+ //clear selected Notifications
serverRegistry.clearNotifications(null, ss.toList());
- refresh();
}
- });
-
- // Add Refresh Button
- _refreshButton = _toolkit.createButton(composite, BUTTON_REFRESH, SWT.PUSH | SWT.CENTER);
- _refreshButton.setFont(ApplicationRegistry.getFont(FONT_BUTTON));
- gridData = new GridData(SWT.TRAIL, SWT.TOP, true, false);
- gridData.widthHint = 80;
- _refreshButton.setLayoutData(gridData);
- _refreshButton.addSelectionListener(new SelectionAdapter()
- {
- public void widgetSelected(SelectionEvent e)
- {
- refresh();
+ else if(_notifications != null)
+ {
+ //clear all the notifications, if there are any
+
+ //check the user is certain of this clear-all operation
+ int response = ViewUtility.popupOkCancelConfirmationMessage(
+ "Clear Notifications", "Clear all Notifications for this VirtualHost?");
+ if(response != SWT.OK)
+ {
+ return;
+ }
+
+ synchronized(this)
+ {
+ serverRegistry.clearNotifications(null, _notifications);
+ }
}
- });
+
+ refresh();
+ }
+ });
+ //add description
+ Label desc = _toolkit.createLabel(composite,"Clears the selected Notifications, or all if none are selected");
+ desc.setLayoutData(new GridData(SWT.LEFT,SWT.CENTER, false, false));
}
/**
@@ -201,36 +204,12 @@ public class VHNotificationsTabControl extends TabControl
{
createTable();
_tableViewer = new TableViewer(_table);
- //_tableViewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
_tableViewer.setUseHashlookup(true);
_tableViewer.setContentProvider(new ContentProviderImpl());
_tableViewer.setLabelProvider(new LabelProviderImpl());
_tableViewer.setColumnProperties(_tableTitles);
- /*
- CellEditor[] cellEditors = new CellEditor[_tableTitles.length];
- TextCellEditor textEditor = new TextCellEditor(table);
- cellEditors[0] = textEditor;
- textEditor = new TextCellEditor(table);
- cellEditors[1] = textEditor;
- textEditor = new TextCellEditor(table);
- cellEditors[2] = textEditor;
- textEditor = new TextCellEditor(table);
- cellEditors[3] = textEditor;
-
- // Assign the cell editors to the viewer
- _tableViewer.setCellEditors(cellEditors);
- _tableViewer.setCellModifier(new TableCellModifier());
- */
addTableListeners();
-
- //_tableViewer.addSelectionChangedListener(new );
-
- //_notificationDetails = new Composite(_tabControl, SWT.BORDER);
- //_notificationDetails.setLayoutData(new GridData(GridData.FILL_BOTH));
-
- //_tabControl.layout();
- //viewerComposite.layout();
}
/**
@@ -311,17 +290,19 @@ public class VHNotificationsTabControl extends TabControl
public void refresh()
{
- _notifications = null;
- _table.deselectAll();
- _tableViewer.getTable().clearAll();
-
- Control[] children = _form.getBody().getChildren();
- for (int i = 0; i < children.length; i++)
+ if(_workerRunning)
+ {
+ //perform an single immediate-update
+ updateTableViewer();
+ }
+ else
{
- children[i].setVisible(true);
+ //start a worker to do the update and keep going as required
+ _workerRunning = true;
+ _worker = new Thread(new Worker());
+ _worker.start();
}
-
- workerRunning = true;
+
_form.layout(true);
_form.getBody().layout(true, true);
}
@@ -413,10 +394,10 @@ public class VHNotificationsTabControl extends TabControl
}
} // end of LabelProviderImpl
- protected boolean workerRunning = false;
+
protected void setWorkerRunning(boolean running)
{
- workerRunning = running;
+ _workerRunning = running;
}
/**
@@ -424,15 +405,18 @@ public class VHNotificationsTabControl extends TabControl
*/
private class Worker implements Runnable
{
+ private boolean keepGoing = true;
+
public void run()
{
- Display display = _tabFolder.getDisplay();
- while(true)
+ final Display display = _tabFolder.getDisplay();
+
+ while(keepGoing)
{
- if (!workerRunning || display == null)
+ if (display == null || display.isDisposed())
{
- sleep();
- continue;
+ setWorkerRunning(false);
+ break; //stop the thread
}
display.syncExec(new Runnable()
@@ -440,15 +424,27 @@ public class VHNotificationsTabControl extends TabControl
public void run()
{
if (_form == null || _form.isDisposed())
- return;
- setWorkerRunning(_form.isVisible());
- if (!workerRunning) return;
-
- updateTableViewer();
+ {
+ setWorkerRunning(false);
+ keepGoing = false; //exit the loop and stop the thread
+ }
+ else
+ {
+ keepGoing = _form.isVisible();
+ setWorkerRunning(keepGoing);
+ }
+
+ if (keepGoing)
+ {
+ updateTableViewer();
+ }
}
- });
+ });
- sleep();
+ if (keepGoing)
+ {
+ sleep();
+ }
}
}
@@ -466,18 +462,20 @@ public class VHNotificationsTabControl extends TabControl
}
/**
- * Updates the table with new notifications received from mbean server for all mbeans
+ * Updates the table with new notifications received from mbean server for all mbeans in this virtual host
*/
protected void updateTableViewer()
{
+ String virtualhost = MBeanView.getVirtualHost();
+
ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(MBeanView.getServer());
- List<NotificationObject> newList = serverRegistry.getNotifications(null);
- if (newList == null)
- return;
+ List<NotificationObject> newList = serverRegistry.getNotifications(virtualhost);
- _notifications = newList;
- _tableViewer.setInput(_notifications);
- _tableViewer.refresh();
+ synchronized(this)
+ {
+ _notifications = newList;
+ _tableViewer.setInput(_notifications);
+ }
}
}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/ViewUtility.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/ViewUtility.java
index 4f2b70f869..eb34f6c51c 100644
--- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/ViewUtility.java
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/ViewUtility.java
@@ -39,29 +39,36 @@ import javax.management.openmbean.OpenType;
import javax.management.openmbean.TabularDataSupport;
import javax.management.openmbean.TabularType;
-import org.apache.qpid.management.ui.ApplicationWorkbenchAdvisor;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.jface.dialogs.ErrorDialog;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.qpid.management.ui.ApplicationRegistry;
+import static org.apache.qpid.management.ui.Constants.FAILURE_IMAGE;
+import static org.apache.qpid.management.ui.Constants.SUCCESS_IMAGE;
+
import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.widgets.FormToolkit;
/**
* Utility Class for displaying OpenMbean data types by creating required SWT widgets
- * @author Bhupendra Bhardwaj
*/
public class ViewUtility
{
@@ -77,6 +84,8 @@ public class ViewUtility
private static final Comparator tabularDataComparator = new TabularDataComparator();
+ private static MBeanView _mbeanView = null;
+
private static List<String> SUPPORTED_ARRAY_DATATYPES = new ArrayList<String>();
static
{
@@ -89,6 +98,10 @@ public class ViewUtility
SUPPORTED_ARRAY_DATATYPES.add("java.util.Date");
}
+ private static final int DEFAULT_CONTENT_SIZE = 198;
+ static Button _firstButton, _nextButton, _previousButton, _lastButton;
+ static Text _hexNumTextToEnd, _hexNumTextToStart;
+
/**
* Populates the composite with given openmbean data type (TabularType or CompositeType)
* @param toolkit
@@ -190,15 +203,15 @@ public class ViewUtility
layoutData.widthHint = 80;
firstRecordButton.setLayoutData(layoutData);
- final Button nextRecordButton = toolkit.createButton(dataHolder, NEXT, SWT.PUSH);
+ final Button previousRecordButton = toolkit.createButton(dataHolder, PREV, SWT.PUSH);
layoutData = new GridData (GridData.HORIZONTAL_ALIGN_END);
layoutData.widthHint = 80;
- nextRecordButton.setLayoutData(layoutData);
+ previousRecordButton.setLayoutData(layoutData);
- final Button previousRecordButton = toolkit.createButton(dataHolder, PREV, SWT.PUSH);
+ final Button nextRecordButton = toolkit.createButton(dataHolder, NEXT, SWT.PUSH);
layoutData = new GridData (GridData.HORIZONTAL_ALIGN_BEGINNING);
layoutData.widthHint = 80;
- previousRecordButton.setLayoutData(layoutData);
+ nextRecordButton.setLayoutData(layoutData);
final Button lastRecordButton = toolkit.createButton(dataHolder, LAST, SWT.PUSH);
layoutData = new GridData (GridData.HORIZONTAL_ALIGN_BEGINNING);
@@ -352,7 +365,7 @@ public class ViewUtility
}
else
{
- setNotSupportedDataType(toolkit, compositeHolder);
+ handleBinaryMessageContent(toolkit, compositeHolder, data, itemName, encoding);
}
}
// If array of any other supported type, show as a list of String array
@@ -411,86 +424,413 @@ public class ViewUtility
ex.printStackTrace();
}
}
-
- public static int popupInfoMessage(String title, String message)
+
+ private static Shell getShell()
{
- MessageBox messageBox = new MessageBox(Display.getCurrent().getActiveShell(), SWT.ICON_INFORMATION | SWT.OK);
- messageBox.setMessage(message);
- messageBox.setText(title);
- int response = messageBox.open();
-
- return response;
+ Shell shell = Display.getCurrent().getActiveShell();
+
+ // Under linux GTK getActiveShell returns null so we need to make a new shell for display.
+ // Under windows this is fine.
+ if (shell == null)
+ {
+ // This occurs under linux gtk
+ shell = new Shell(Display.getCurrent(), SWT.BORDER | SWT.CLOSE | SWT.MIN | SWT.MAX);
+ }
+
+ return shell;
}
-
- public static int popupErrorMessage(String title, String message)
+
+ private static int showBox(String title, String message, int icon)
{
- MessageBox messageBox = new MessageBox(Display.getCurrent().getActiveShell(), SWT.ICON_ERROR | SWT.OK);
+ MessageBox messageBox = new MessageBox(getShell(), icon);
messageBox.setMessage(message);
messageBox.setText(title);
- int response = messageBox.open();
-
- return response;
+
+ return messageBox.open();
+ }
+
+ /**
+ * Creates widgets for object messages and populates the content in hexadecimal format.
+ * @param toolkit
+ * @param compositeHolder
+ * @param data
+ * @param itemName
+ * @param encoding
+ */
+ private static void handleBinaryMessageContent(FormToolkit toolkit, Composite compositeHolder, CompositeData data, String itemName, String encoding)
+ {
+ final String thisEncoding = encoding;
+ final Byte[] arrayItems = (Byte[]) data.get(itemName);
+ final byte[] byteArray = new byte[arrayItems.length];
+
+ for (int i = 0; i < arrayItems.length; i++)
+ {
+ byteArray[i] = arrayItems[i];
+ }
+
+ try
+ {
+ //create a new composite to contain the widgets required to display object messages.
+ final Composite localComposite = toolkit.createComposite(compositeHolder, SWT.NONE);
+ localComposite.setData("currentBytePos", 0);
+ localComposite.setData("startingBytePos", 0);
+ GridLayout layout = new GridLayout(2, true);
+ layout.marginWidth = 0;
+ layout.marginHeight = 0;
+ localComposite.setLayout(layout);
+ localComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));
+
+ int startContentSize = DEFAULT_CONTENT_SIZE;
+
+ if (byteArray.length < DEFAULT_CONTENT_SIZE)
+ {
+ startContentSize = byteArray.length;
+ }
+
+ //create a text to display the hexadecimal views of object messages, it takes more space than ascii view as
+ //a hex uses 2 chars and 1 space, while ascii only uses 1 char and 1 space.
+ final Text hexText = toolkit.createText(localComposite,
+ new String(displayByteFormat(localComposite, byteArray, startContentSize * 2, thisEncoding, "<<", true)),
+ SWT.READ_ONLY | SWT.MULTI | SWT.WRAP | SWT.V_SCROLL | SWT.BORDER);
+ GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
+ gridData.widthHint = 144; //set to 222 if not using any fonts
+ gridData.heightHint = 200;
+ hexText.setLayoutData(gridData);
+
+ final Text asciiText = toolkit.createText(localComposite,
+ new String(displayByteFormat(localComposite, byteArray, startContentSize * 2, thisEncoding, "<<", false)),
+ SWT.READ_ONLY | SWT.MULTI | SWT.WRAP | SWT.V_SCROLL | SWT.BORDER);
+
+
+ gridData = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
+ gridData.widthHint = 52;//set to 98 if not using any fonts
+ gridData.heightHint = 200;
+ asciiText.setLayoutData(gridData);
+
+ //use a monospaced font for a better layout
+ Font font = new Font(compositeHolder.getDisplay(), "Courier", 10, SWT.NORMAL);
+ hexText.setFont(font);
+ asciiText.setFont(font);
+
+ final ScrollBar hexScrollBar = hexText.getVerticalBar();
+ final ScrollBar asciiScrollBar = asciiText.getVerticalBar();
+
+ //create a sub composite to contain all the buttons
+ final Composite buttonComposite = toolkit.createComposite(localComposite, SWT.NONE);
+ layout = new GridLayout(7, false);
+ layout.marginWidth = 0;
+ buttonComposite.setLayout(layout);
+ buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1));
+
+ _firstButton = toolkit.createButton(buttonComposite, "<<", SWT.PUSH);
+ GridData layoutData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ layoutData.widthHint = 40;
+ _firstButton.setLayoutData(layoutData);
+ _firstButton.setToolTipText("See the first n bytes");
+
+ _previousButton = toolkit.createButton(buttonComposite, "<", SWT.PUSH);
+ layoutData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ layoutData.widthHint = 40;
+ _previousButton.setLayoutData(layoutData);
+ _previousButton.setToolTipText("See the previous n bytes");
+ _previousButton.setEnabled(false);
+
+ _hexNumTextToStart = toolkit.createText(buttonComposite, "0");
+ layoutData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ layoutData.widthHint = 40;
+ _hexNumTextToStart.setLayoutData(layoutData);
+ _hexNumTextToStart.setEditable(false);
+
+ final Text hexNumText = toolkit.createText(buttonComposite, "" + startContentSize);
+ layoutData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ layoutData.widthHint = 40;
+ hexNumText.setLayoutData(layoutData);
+
+ _hexNumTextToEnd = toolkit.createText(buttonComposite, "" + (byteArray.length - startContentSize));
+ layoutData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ layoutData.widthHint = 40;
+ _hexNumTextToEnd.setLayoutData(layoutData);
+ _hexNumTextToEnd.setEditable(false);
+
+ _nextButton = toolkit.createButton(buttonComposite, ">", SWT.PUSH);
+ layoutData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ layoutData.widthHint = 40;
+ _nextButton.setLayoutData(layoutData);
+ _nextButton.setToolTipText("See the next n bytes");
+ _nextButton.setEnabled(true);
+
+ _lastButton = toolkit.createButton(buttonComposite, ">>", SWT.PUSH);
+ layoutData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ layoutData.widthHint = 40;
+ _lastButton.setToolTipText("See the last n bytes");
+ _lastButton.setLayoutData(layoutData);
+
+ SelectionListener listener = new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ if (e.widget instanceof Button)
+ {
+ String numOfBytes = hexNumText.getText();
+ try
+ {
+ int n = Integer.parseInt(numOfBytes);
+
+ //Reset range display if user requests a large value
+ if (n > byteArray.length)
+ {
+ n = (byteArray.length > DEFAULT_CONTENT_SIZE) ? DEFAULT_CONTENT_SIZE : byteArray.length;
+ hexNumText.setText("" + n);
+ }
+
+ //rest if the user requests 0
+ if (n < 1)
+ {
+ n = DEFAULT_CONTENT_SIZE;
+ hexNumText.setText("" + n);
+ }
+
+ Button button = (Button) e.widget;
+ hexText.setText(displayByteFormat(localComposite, byteArray, n * 2, thisEncoding,
+ button.getText(), true));
+ asciiText.setText(displayByteFormat(localComposite, byteArray, n * 2, thisEncoding,
+ button.getText(), false));
+ }
+ catch (NumberFormatException exp)
+ {
+ popupErrorMessage("Error", "Please input the number of bytes you wish to look at");
+ }
+ }
+ if (e.widget instanceof ScrollBar)
+ {
+ //synchronize the movements of the two scrollbars
+ ScrollBar sb = (ScrollBar) e.widget;
+ if (sb.getParent().equals(hexText))
+ {
+ asciiScrollBar.setIncrement(sb.getIncrement());
+ asciiScrollBar.setSelection(sb.getSelection());
+ }
+ else if (sb.getParent().equals(asciiText))
+ {
+ hexScrollBar.setSelection(sb.getSelection());
+ hexScrollBar.setIncrement(sb.getIncrement());
+ }
+ }
+ }
+ };
+ localComposite.addControlListener(new ControlAdapter()
+ {
+ public void controlResized(ControlEvent e)
+ {
+ //if the control is resized, set different parameters to make a single line displays the same contents.
+ if (((GridLayout) localComposite.getLayout()).makeColumnsEqualWidth)
+ {
+ ((GridLayout) localComposite.getLayout()).makeColumnsEqualWidth = false;
+ ((GridLayout) localComposite.getLayout()).numColumns = 2;
+ ((GridData) hexText.getLayoutData()).horizontalSpan = 1;
+ ((GridData) hexText.getLayoutData()).widthHint = 144;
+ ((GridData) asciiText.getLayoutData()).horizontalSpan = 1;
+ ((GridData) asciiText.getLayoutData()).widthHint = 52;
+ ((GridData) buttonComposite.getLayoutData()).horizontalSpan = 2;
+ }
+ else
+ {
+ ((GridLayout) localComposite.getLayout()).makeColumnsEqualWidth = true;
+ ((GridLayout) localComposite.getLayout()).numColumns = 42; //set to 47 if not using any fonts
+ ((GridData) hexText.getLayoutData()).horizontalSpan = 25; // set to 30 if not using any fonts
+ ((GridData) asciiText.getLayoutData()).horizontalSpan = 17; // set to 17 if not using any fonts
+ ((GridData) buttonComposite.getLayoutData()).horizontalSpan = 42;
+ }
+ }
+ });
+
+ _firstButton.addSelectionListener(listener);
+ _previousButton.addSelectionListener(listener);
+ _nextButton.addSelectionListener(listener);
+ _lastButton.addSelectionListener(listener);
+ hexScrollBar.addSelectionListener(listener);
+ asciiScrollBar.addSelectionListener(listener);
+ //f.dispose();
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
+ /**
+ * Format object messages to have a hexadecimal view and a ascii view.
+ * @param numOfBytes
+ * @param encoding
+ * @return
+ */
+ private static String displayByteFormat(Composite localComposite, byte[] byteArray, int numOfBytes,
+ String encoding, String direction, boolean isHex)
+ {
+ final Hex hexeconder = new Hex();
+ final byte[] encoded = hexeconder.encode(byteArray);
+
+ int hexLength = byteArray.length * 2;
+ StringBuilder sb = new StringBuilder();
+ int currentBytePos = (Integer) localComposite.getData("currentBytePos");
+ int startingBytePos = (Integer) localComposite.getData("startingBytePos");
+
+ int strLength = 0;
+ int offset = 0;
+ String encStr;
+ if (isHex)
+ {
+ if (direction.equals("<<"))
+ {
+ strLength = (numOfBytes > hexLength) ? hexLength : numOfBytes;
+ offset = 0;
+ }
+ else if (direction.equals("<"))
+ {
+ strLength = (startingBytePos - numOfBytes < 0) ? startingBytePos : numOfBytes;
+ offset = (startingBytePos - numOfBytes < 0) ? 0 : startingBytePos - numOfBytes;
+ }
+ else if (direction.equals(">"))
+ {
+ strLength = (numOfBytes > (hexLength - currentBytePos)) ? hexLength - currentBytePos : numOfBytes;
+ offset = currentBytePos;
+ }
+ else if (direction.equals(">>"))
+ {
+ strLength = (numOfBytes > hexLength) ? hexLength : numOfBytes;
+ offset = (hexLength - numOfBytes > 0) ? hexLength - numOfBytes : 0;
+ }
+ else
+ {
+ strLength = hexLength;
+ offset = 0;
+ }
+ localComposite.setData("strLength", strLength);
+ localComposite.setData("currentBytePos", offset + strLength);
+ localComposite.setData("startingBytePos", offset);
+
+ if (_lastButton != null && !_lastButton.isDisposed())
+ {
+ //Set button state
+ _previousButton.setEnabled(offset != 0);
+ _nextButton.setEnabled(offset + strLength != hexLength);
+
+ //set the text fields
+ _hexNumTextToStart.setText("" + offset / 2);
+ _hexNumTextToEnd.setText("" + (hexLength - (offset + strLength)) / 2);
+ }
+ }
+
+ try
+ {
+ if (isHex)
+ {
+ encStr = new String(encoded, offset, strLength, encoding);
+ for (int c = 0; c < strLength; c++)
+ {
+ sb.append(encStr.charAt(c));
+ if (c % 2 == 1)
+ {
+ sb.append(" ");
+ }
+ }
+ return sb.toString().toUpperCase();
+ }
+ else
+ {
+ strLength = (Integer) localComposite.getData("strLength");
+ sb = new StringBuilder();
+ encStr = new String(byteArray, startingBytePos / 2, strLength / 2, encoding);
+ for (int c = 0; c < encStr.length(); c++)
+ {
+ char ch = encStr.charAt(c);
+ if (ch > 31 && ch < 127)
+ {
+ sb.append(ch);
+ }
+ else
+ {
+ sb.append("?");
+ }
+
+ sb.append(" ");
+ }
+ }
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ e.printStackTrace();
+ }
+ return sb.toString();
}
- public static int popupConfirmationMessage(String title, String message)
+ public static int popupInfoMessage(String title, String message)
{
- MessageBox messageBox = new MessageBox(Display.getCurrent().getActiveShell(),
- SWT.ICON_QUESTION | SWT.YES | SWT.NO | SWT.CANCEL);
- messageBox.setMessage(message);
- messageBox.setText(title);
- int response = messageBox.open();
-
- return response;
+ return showBox(title, message, SWT.ICON_INFORMATION | SWT.OK);
}
- public static void popupError(String title, String message, Throwable ex)
+ public static int popupErrorMessage(String title, String message)
{
- IStatus status = new Status(IStatus.ERROR, ApplicationWorkbenchAdvisor.PERSPECTIVE_ID,
- IStatus.ERROR, ex.toString(), ex);
- ErrorDialog.openError(Display.getCurrent().getActiveShell(), title, message, status);
+ return showBox(title, message, SWT.ICON_ERROR | SWT.OK);
+ }
+ public static int popupConfirmationMessage(String title, String message)
+ {
+ return showBox(title, message,SWT.ICON_QUESTION | SWT.YES | SWT.NO);
}
- public static void popupError(String errorMsg)
+ public static int popupOkCancelConfirmationMessage(String title, String message)
{
- Display display = Display.getCurrent();
- Shell shell = new Shell(display, SWT.BORDER | SWT.CLOSE | SWT.MIN | SWT.MAX);
- shell.setText("Attribute");
- shell.setLayout(new GridLayout());
- int x = display.getBounds().width;
- int y = display.getBounds().height;
- int width = 500;
- int height = 250;
- shell.setBounds(x/4, y/4, width, height);
-
- Label label = new Label(shell, SWT.NONE);
- label.setText(errorMsg);
- label.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, false, false));
-
- shell.open();
- while (!shell.isDisposed())
- {
- if (!display.readAndDispatch())
- {
- display.sleep();
- }
- }
- shell.dispose();
+ return showBox(title, message,SWT.ICON_QUESTION | SWT.OK | SWT.CANCEL);
}
+
public static Shell createPopupShell(String title, int width, int height)
{
Display display = Display.getCurrent();
- Shell shell = new Shell(display, SWT.BORDER | SWT.CLOSE | SWT.MIN |SWT.MAX);
+ final Shell shell = new Shell(display, SWT.BORDER | SWT.CLOSE | SWT.MIN |SWT.MAX);
shell.setText(title);
shell.setLayout(new GridLayout());
int x = display.getBounds().width;
int y = display.getBounds().height;
shell.setBounds(x/4, y/4, width, height);
+ shell.addListener(SWT.Traverse, new Listener () {
+ public void handleEvent (Event event) {
+ switch (event.detail) {
+ case SWT.TRAVERSE_ESCAPE:
+ shell.close ();
+ event.detail = SWT.TRAVERSE_NONE;
+ event.doit = false;
+ break;
+ }
+ }
+ });
+
return shell;
}
+ public static Shell createModalDialogShell(Shell parent, String title)
+ {
+ final Shell shell = new Shell(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);
+ shell.setText(title);
+ shell.setLayout(new GridLayout());
+
+ shell.addListener(SWT.Traverse, new Listener () {
+ public void handleEvent (Event event) {
+ switch (event.detail) {
+ case SWT.TRAVERSE_ESCAPE:
+ shell.close ();
+ event.detail = SWT.TRAVERSE_NONE;
+ event.doit = false;
+ break;
+ }
+ }
+ });
+
+ return shell;
+ }
+
/**
* Creates a List widget for displaying array of strings
* @param compositeHolder
@@ -562,29 +902,7 @@ public class ViewUtility
{
oldControls[i].dispose();
}
- }
-
- public static char[] getMD5HashedCharArray(Object text) throws NoSuchAlgorithmException, UnsupportedEncodingException
- {
- byte[] data = ((String)text).getBytes("utf-8");
-
- MessageDigest md = MessageDigest.getInstance("MD5");
-
- for (byte b : data)
- {
- md.update(b);
- }
-
- byte[] digest = md.digest();
-
- char[] byteArray = new char[digest.length];
- int index = 0;
- for (byte b : digest)
- {
- byteArray[index++] = (char)b;
- }
- return byteArray;
- }
+ }
public static char[] getHash(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException
{
@@ -638,4 +956,69 @@ public class ViewUtility
return -1;
}
}
+
+ public static void setMBeanView(MBeanView mbeanView)
+ {
+ _mbeanView = mbeanView;
+ }
+
+ /**
+ * Report feedback for the operation
+ * @param result true if success, false if unsuccessful, null if invoked but void result type.
+ * @param successMessage
+ * @param failureMessage
+ */
+ public static void operationResultFeedback(Boolean result, String successMessage, String failureMessage)
+ {
+ Image icon;
+
+ if(_mbeanView != null)
+ {
+ if(result == null)
+ {
+ icon = ApplicationRegistry.getImage(SUCCESS_IMAGE);
+ _mbeanView.populateStatusBar(icon, successMessage);
+ }
+ else if(result)
+ {
+ icon = ApplicationRegistry.getImage(SUCCESS_IMAGE);
+ _mbeanView.populateStatusBar(icon, successMessage);
+ }
+ else
+ {
+ icon = ApplicationRegistry.getImage(FAILURE_IMAGE);
+ _mbeanView.populateStatusBar(icon, failureMessage);
+ popupErrorMessage("Operation Failed", failureMessage);
+ }
+ }
+ }
+
+ public static void operationFailedStatusBarMessage(String failureMessage)
+ {
+ Image icon = ApplicationRegistry.getImage(FAILURE_IMAGE);
+
+ if(_mbeanView != null)
+ {
+ _mbeanView.populateStatusBar(icon, failureMessage);
+ }
+ }
+
+ public static void centerChildInParentShell(Shell parent, Shell child)
+ {
+ //get current parent shell size and location
+ int parentLocX = parent.getBounds().x;
+ int parentLocY = parent.getBounds().y;
+ int parentWidth = parent.getBounds().width;
+ int parentHeight = parent.getBounds().height;
+
+ //get current child size
+ int childWidth = child.getSize().x;
+ int childHeight = child.getSize().y;
+
+ //centre the child within/over the parent
+ child.setBounds((parentWidth - childWidth)/2 + parentLocX,
+ (parentHeight - childHeight)/2 + parentLocY,
+ childWidth, childHeight);
+ }
+
}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/connection/ConnectionOperationsTabControl.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/connection/ConnectionOperationsTabControl.java
new file mode 100644
index 0000000000..3281757526
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/connection/ConnectionOperationsTabControl.java
@@ -0,0 +1,547 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui.views.connection;
+
+import java.util.Collection;
+
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.TabularDataSupport;
+
+import org.apache.qpid.management.ui.ApiVersion;
+import org.apache.qpid.management.ui.ApplicationRegistry;
+import org.apache.qpid.management.ui.ManagedBean;
+import org.apache.qpid.management.ui.ServerRegistry;
+import org.apache.qpid.management.common.mbeans.ManagedConnection;
+import org.apache.qpid.management.ui.jmx.JMXManagedObject;
+import org.apache.qpid.management.ui.jmx.MBeanUtility;
+import org.apache.qpid.management.ui.views.MBeanView;
+import org.apache.qpid.management.ui.views.TabControl;
+import org.apache.qpid.management.ui.views.ViewUtility;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.forms.widgets.Form;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+
+
+/**
+ * Control class for the Connection mbean Operations tab.
+ */
+public class ConnectionOperationsTabControl extends TabControl
+{
+ private FormToolkit _toolkit;
+ private Form _form;
+ private Table _table = null;
+ private TableViewer _tableViewer = null;
+ private Composite _paramsComposite = null;
+
+ private TabularDataSupport _channels = null;
+ private ManagedConnection _cmb;
+ private ApiVersion _ApiVersion;
+
+ static final String CHAN_ID = ManagedConnection.COMPOSITE_ITEM_NAMES[0];
+ static final String TRANSACTIONAL = ManagedConnection.COMPOSITE_ITEM_NAMES[1];
+ static final String DEFAULT_QUEUE = ManagedConnection.COMPOSITE_ITEM_NAMES[2];
+ static final String UNACKED_COUNT = ManagedConnection.COMPOSITE_ITEM_NAMES[3];
+ static final String FLOW_BLOCKED = ManagedConnection.COMPOSITE_ITEM_NAMES[4];
+
+ public ConnectionOperationsTabControl(TabFolder tabFolder, JMXManagedObject mbean, MBeanServerConnection mbsc)
+ {
+ super(tabFolder);
+ _mbean = mbean;
+ _ApiVersion = ApplicationRegistry.getServerRegistry(mbean).getManagementApiVersion();
+ _cmb = (ManagedConnection) MBeanServerInvocationHandler.newProxyInstance(mbsc,
+ mbean.getObjectName(), ManagedConnection.class, false);
+ _toolkit = new FormToolkit(_tabFolder.getDisplay());
+ _form = _toolkit.createForm(_tabFolder);
+ _form.getBody().setLayout(new GridLayout());
+ createComposites();
+ createWidgets();
+ }
+
+ private void createComposites()
+ {
+ _paramsComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE);
+ _paramsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ _paramsComposite.setLayout(new GridLayout());
+ }
+
+ /**
+ * @see TabControl#getControl()
+ */
+ public Control getControl()
+ {
+ return _form;
+ }
+
+ /**
+ * @see TabControl#setFocus()
+ */
+ public void setFocus()
+ {
+ _table.setFocus();
+ }
+
+ @Override
+ public void refresh(ManagedBean mbean)
+ {
+ _channels = null;
+ try
+ {
+ //gather a list of all channels on the connection for display and selection
+ _channels = (TabularDataSupport) _cmb.channels();
+ }
+ catch (Exception e)
+ {
+ MBeanUtility.handleException(mbean,e);
+ }
+
+ _tableViewer.setInput(_channels);
+
+ layout();
+ }
+
+ public void layout()
+ {
+ _form.layout(true);
+ _form.getBody().layout(true, true);
+ }
+
+ private void createWidgets()
+ {
+ Group viewChannelsGroup = new Group(_paramsComposite, SWT.SHADOW_NONE);
+ viewChannelsGroup.setBackground(_paramsComposite.getBackground());
+ viewChannelsGroup.setText("Channels");
+ viewChannelsGroup.setLayout(new GridLayout());
+ GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gridData.heightHint = 250;
+ gridData.minimumHeight = 250;
+
+ viewChannelsGroup.setLayoutData(gridData);
+
+ _table = new Table (viewChannelsGroup, SWT.SINGLE | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION);
+ _table.setLinesVisible (true);
+ _table.setHeaderVisible (true);
+ GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ _table.setLayoutData(data);
+
+ _tableViewer = new TableViewer(_table);
+ final TableSorter tableSorter = new TableSorter();
+
+ String[] titles;
+ if(_ApiVersion.greaterThanOrEqualTo(1, 5))
+ {
+ titles = new String[]{"Id", "Transactional", "Num Unacked Msg", "Default Queue", "Flow Blocked"};
+ }
+ else
+ {
+ titles = new String[]{"Id", "Transactional", "Num Unacked Msg", "Default Queue"};
+ }
+ int[] bounds = { 50, 110, 145, 200, 110 };
+ for (int i = 0; i < titles.length; i++)
+ {
+ final int index = i;
+ final TableColumn column = new TableColumn (_table, SWT.NONE);
+
+ column.setText(titles[i]);
+ column.setWidth(bounds[i]);
+ column.setResizable(true);
+
+ //Setting the right sorter
+ column.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ tableSorter.setColumn(index);
+ final TableViewer viewer = _tableViewer;
+ int dir = viewer .getTable().getSortDirection();
+ if (viewer.getTable().getSortColumn() == column)
+ {
+ dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
+ }
+ else
+ {
+ dir = SWT.UP;
+ }
+ viewer.getTable().setSortDirection(dir);
+ viewer.getTable().setSortColumn(column);
+ viewer.refresh();
+ }
+ });
+
+ }
+
+ _tableViewer.setContentProvider(new ContentProviderImpl());
+ _tableViewer.setLabelProvider(new LabelProviderImpl());
+ _tableViewer.setSorter(tableSorter);
+ _table.setSortColumn(_table.getColumn(0));
+ _table.setSortDirection(SWT.UP);
+
+ Composite buttonsComposite = _toolkit.createComposite(viewChannelsGroup);
+ gridData = new GridData(SWT.RIGHT, SWT.BOTTOM, false, false);
+ buttonsComposite.setLayoutData(gridData);
+ buttonsComposite.setLayout(new GridLayout(2,false));
+
+ final Button commitButton = _toolkit.createButton(buttonsComposite, "Commit Transactions", SWT.PUSH);
+ commitButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+ commitButton.setEnabled(false);
+ commitButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ int selectionIndex = _table.getSelectionIndex();
+
+ if (selectionIndex != -1)
+ {
+ final CompositeData selectedChannel = (CompositeData)_table.getItem(selectionIndex).getData();
+ Integer id = (Integer) selectedChannel.get(CHAN_ID);
+
+ int response = ViewUtility.popupOkCancelConfirmationMessage("Commit Transactions",
+ "Commit transactions for channel:" + id + " ?");
+
+ if (response == SWT.OK)
+ {
+ try
+ {
+ _cmb.commitTransactions(id);
+ ViewUtility.operationResultFeedback(null, "Commited transactions", null);
+ }
+ catch (Exception e1)
+ {
+ ViewUtility.operationFailedStatusBarMessage("Error commiting transactions");
+ MBeanUtility.handleException(_mbean, e1);
+ }
+
+ refresh(_mbean);;
+ }
+ }
+ }
+ });
+
+ final Button rollbackButton = _toolkit.createButton(buttonsComposite, "Rollback Transactions", SWT.PUSH);
+ rollbackButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+ rollbackButton.setEnabled(false);
+ rollbackButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ int selectionIndex = _table.getSelectionIndex();
+
+ if (selectionIndex != -1)
+ {
+ final CompositeData selectedChannel = (CompositeData)_table.getItem(selectionIndex).getData();
+ Integer id = (Integer) selectedChannel.get(CHAN_ID);
+
+ int response = ViewUtility.popupOkCancelConfirmationMessage("Rollback Transactions",
+ "Rollback transactions for channel:" + id + " ?");
+
+ if (response == SWT.OK)
+ {
+ try
+ {
+ _cmb.rollbackTransactions(id);
+ ViewUtility.operationResultFeedback(null, "Rolled back transactions", null);
+ }
+ catch (Exception e1)
+ {
+ ViewUtility.operationFailedStatusBarMessage("Error rolling back transactions");
+ MBeanUtility.handleException(_mbean, e1);
+ }
+
+ refresh(_mbean);;
+ }
+ }
+
+ }
+ });
+
+ //listener for double clicking to open the selection mbean
+ _table.addMouseListener(new MouseListener()
+ {
+ // MouseListener implementation
+ public void mouseDoubleClick(MouseEvent event)
+ {
+ openMBean(_table);
+ }
+
+ public void mouseDown(MouseEvent e){}
+ public void mouseUp(MouseEvent e){}
+ });
+
+ _tableViewer.addSelectionChangedListener(new ISelectionChangedListener(){
+ public void selectionChanged(SelectionChangedEvent evt)
+ {
+ int selectionIndex = _table.getSelectionIndex();
+
+ if (selectionIndex != -1)
+ {
+ final CompositeData selectedChannel = (CompositeData)_table.getItem(selectionIndex).getData();
+ Boolean transactional = (Boolean) selectedChannel.get(TRANSACTIONAL);
+
+ if(transactional)
+ {
+ rollbackButton.setEnabled(true);
+ commitButton.setEnabled(true);
+ }
+ else
+ {
+ rollbackButton.setEnabled(false);
+ commitButton.setEnabled(false);
+ }
+ }
+ else
+ {
+ rollbackButton.setEnabled(false);
+ commitButton.setEnabled(true);
+ }
+ }
+ });
+
+ Composite opsComposite = _toolkit.createComposite(_paramsComposite);
+ gridData = new GridData(SWT.LEFT, SWT.FILL, false, true);
+ opsComposite.setLayoutData(gridData);
+ opsComposite.setLayout(new GridLayout(3,false));
+
+ Group closeConnectionGroup = new Group(opsComposite, SWT.SHADOW_NONE);
+ closeConnectionGroup.setBackground(opsComposite.getBackground());
+ closeConnectionGroup.setText("Close Connection");
+ gridData = new GridData(SWT.LEFT, SWT.TOP, true, false);
+ closeConnectionGroup.setLayoutData(gridData);
+ closeConnectionGroup.setLayout(new GridLayout());
+
+ final Button closeConnectionButton = _toolkit.createButton(closeConnectionGroup, "Close Connection", SWT.PUSH);
+ closeConnectionButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ int response = ViewUtility.popupOkCancelConfirmationMessage("Close Connection",
+ "Are you sure you wish to close the Connection?");
+
+ if (response == SWT.OK)
+ {
+ try
+ {
+ _cmb.closeConnection();
+ }
+ catch (Exception e1)
+ {
+ MBeanUtility.handleException(_mbean, e1);
+ }
+ }
+ }
+ });
+ }
+
+
+ /**
+ * Content Provider class for the table viewer
+ */
+ private class ContentProviderImpl implements IStructuredContentProvider
+ {
+
+ public void inputChanged(Viewer v, Object oldInput, Object newInput)
+ {
+
+ }
+
+ public void dispose()
+ {
+
+ }
+
+ public Object[] getElements(Object parent)
+ {
+ Collection<Object> rowCollection = ((TabularDataSupport) parent).values();
+
+ return rowCollection.toArray();
+ }
+ }
+
+ /**
+ * Label Provider class for the table viewer
+ */
+ private class LabelProviderImpl extends LabelProvider implements ITableLabelProvider
+ {
+ @Override
+ public String getColumnText(Object element, int columnIndex)
+ {
+ switch (columnIndex)
+ {
+ case 0 : // id column
+ return String.valueOf(((CompositeDataSupport) element).get(CHAN_ID));
+ case 1 : // transactional column
+ return String.valueOf(((CompositeDataSupport) element).get(TRANSACTIONAL));
+ case 2 : // num unacked msgs column
+ return String.valueOf(((CompositeDataSupport) element).get(UNACKED_COUNT));
+ case 3 : // default queue column
+ return String.valueOf(((CompositeDataSupport) element).get(DEFAULT_QUEUE));
+ case 4 : // flow blocked column
+ return String.valueOf(((CompositeDataSupport) element).get(FLOW_BLOCKED));
+ default :
+ return "-";
+ }
+ }
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex)
+ {
+ return null;
+ }
+
+ }
+
+ /**
+ * Sorter class for the table viewer.
+ *
+ */
+ public class TableSorter extends ViewerSorter
+ {
+ private int column;
+ private static final int ASCENDING = 0;
+ private static final int DESCENDING = 1;
+
+ private int direction = DESCENDING;
+
+ public TableSorter()
+ {
+ this.column = 0;
+ direction = ASCENDING;
+ }
+
+ public void setColumn(int column)
+ {
+ if (column == this.column)
+ {
+ // Same column as last sort; toggle the direction
+ direction = 1 - direction;
+ }
+ else
+ {
+ // New column; do an ascending sort
+ this.column = column;
+ direction = ASCENDING;
+ }
+ }
+
+ @Override
+ public int compare(Viewer viewer, Object e1, Object e2)
+ {
+ CompositeData chan1 = (CompositeData) e1;
+ CompositeData chan2 = (CompositeData) e2;
+
+ int comparison = 0;
+ switch(column)
+ {
+ case 0:
+ comparison = ((Integer) chan1.get(CHAN_ID)).compareTo((Integer)chan2.get(CHAN_ID));
+ break;
+ case 1:
+ comparison = String.valueOf(chan1.get(TRANSACTIONAL)).compareTo(
+ String.valueOf(chan2.get(TRANSACTIONAL)));
+ break;
+ case 2:
+ comparison = ((Long) chan1.get(UNACKED_COUNT)).compareTo((Long)chan2.get(UNACKED_COUNT));
+ break;
+ case 3:
+ comparison = String.valueOf(chan1.get(DEFAULT_QUEUE)).compareTo(
+ String.valueOf(chan2.get(DEFAULT_QUEUE)));
+ break;
+ case 4:
+ comparison = String.valueOf(chan1.get(FLOW_BLOCKED)).compareTo(
+ String.valueOf(chan2.get(FLOW_BLOCKED)));
+ break;
+ default:
+ comparison = 0;
+ }
+ // If descending order, flip the direction
+ if(direction == DESCENDING)
+ {
+ comparison = -comparison;
+ }
+ return comparison;
+ }
+ }
+
+ private void openMBean(Table table)
+ {
+ int selectionIndex = table.getSelectionIndex();
+
+ if (selectionIndex == -1)
+ {
+ return;
+ }
+
+ CompositeData channelResult = (CompositeData) table.getItem(selectionIndex).getData();
+ String queueName = (String) channelResult.get(DEFAULT_QUEUE);
+
+ if(queueName == null)
+ {
+ return;
+ }
+
+ ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(_mbean);
+ ManagedBean selectedMBean = serverRegistry.getQueue(queueName, _mbean.getVirtualHostName());
+
+ if(selectedMBean == null)
+ {
+ ViewUtility.popupErrorMessage("Error", "Unable to retrieve the selected MBean to open it");
+ return;
+ }
+
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ MBeanView view = (MBeanView) window.getActivePage().findView(MBeanView.ID);
+ try
+ {
+ view.openMBean(selectedMBean);
+ }
+ catch (Exception ex)
+ {
+ MBeanUtility.handleException(selectedMBean, ex);
+ }
+ }
+
+}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/exchange/ExchangeOperationsTabControl.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/exchange/ExchangeOperationsTabControl.java
new file mode 100644
index 0000000000..e3dea6e96b
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/exchange/ExchangeOperationsTabControl.java
@@ -0,0 +1,641 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui.views.exchange;
+
+import static org.apache.qpid.management.ui.Constants.EXCHANGE_TYPE;
+import static org.apache.qpid.management.ui.Constants.DEFAULT_EXCHANGE_TYPE_VALUES;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.TabularDataSupport;
+
+import org.apache.qpid.management.ui.ApiVersion;
+import org.apache.qpid.management.ui.ApplicationRegistry;
+import org.apache.qpid.management.ui.ManagedBean;
+import org.apache.qpid.management.ui.ServerRegistry;
+import org.apache.qpid.management.common.mbeans.ManagedExchange;
+import org.apache.qpid.management.ui.jmx.JMXManagedObject;
+import org.apache.qpid.management.ui.jmx.MBeanUtility;
+import org.apache.qpid.management.ui.views.MBeanView;
+import org.apache.qpid.management.ui.views.TabControl;
+import org.apache.qpid.management.ui.views.ViewUtility;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+
+
+/**
+ * Control class for the Exchange mbean Operations tab.
+ */
+public class ExchangeOperationsTabControl extends TabControl
+{
+ private FormToolkit _toolkit;
+ private ScrolledForm _form;
+ private Table _keysTable = null;
+ private TableViewer _keysTableViewer = null;
+ private Table _queuesTable = null;
+ private TableViewer _queuesTableViewer = null;
+ private Composite _paramsComposite = null;
+
+ private TabularDataSupport _bindings = null;
+ private ManagedExchange _emb;
+ private ApiVersion _ApiVersion;
+
+ static final String BINDING_KEY = ManagedExchange.COMPOSITE_ITEM_NAMES[0];
+ static final String QUEUES = ManagedExchange.COMPOSITE_ITEM_NAMES[1];
+
+ public ExchangeOperationsTabControl(TabFolder tabFolder, JMXManagedObject mbean, MBeanServerConnection mbsc)
+ {
+ super(tabFolder);
+ _mbean = mbean;
+ _ApiVersion = ApplicationRegistry.getServerRegistry(mbean).getManagementApiVersion();
+ _emb = (ManagedExchange) MBeanServerInvocationHandler.newProxyInstance(mbsc,
+ mbean.getObjectName(), ManagedExchange.class, false);
+ _toolkit = new FormToolkit(_tabFolder.getDisplay());
+ _form = _toolkit.createScrolledForm(_tabFolder);
+ _form.getBody().setLayout(new GridLayout());
+ createComposites();
+ createWidgets();
+ }
+
+ private void createComposites()
+ {
+ _paramsComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE);
+ _paramsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ _paramsComposite.setLayout(new GridLayout());
+ }
+
+ /**
+ * @see TabControl#getControl()
+ */
+ public Control getControl()
+ {
+ return _form;
+ }
+
+ /**
+ * @see TabControl#setFocus()
+ */
+ public void setFocus()
+ {
+ _keysTable.setFocus();
+ }
+
+ @Override
+ public void refresh(ManagedBean mbean)
+ {
+ _bindings = null;
+ try
+ {
+ //gather a list of all keys and queues for display and selection
+ _bindings = (TabularDataSupport) _emb.bindings();
+ }
+ catch (Exception e)
+ {
+ MBeanUtility.handleException(_mbean,e);
+ }
+
+ _keysTableViewer.setInput(_bindings);
+
+ //if we have a Qpid JMX API 1.3+ server
+ if(_ApiVersion.greaterThanOrEqualTo(1, 3))
+ {
+ //if it is a fanout exchange
+ if(isFanoutExchange())
+ {
+ //if there are any queue bindings, there is a single wildcard binding key
+ //auto-select it to show all the queues bound to the exchange
+ if (_keysTable.getItemCount() == 1)
+ {
+ _keysTable.setSelection(0);
+ updateQueuesTable();
+ }
+ }
+ }
+
+ layout();
+ }
+
+ public void layout()
+ {
+ _form.layout(true);
+ _form.getBody().layout(true, true);
+ }
+
+ private void createWidgets()
+ {
+ Group bindingsGroup = new Group(_paramsComposite, SWT.SHADOW_NONE);
+ bindingsGroup.setBackground(_paramsComposite.getBackground());
+ bindingsGroup.setText("Bindings");
+ bindingsGroup.setLayout(new GridLayout(2,false));
+ GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ bindingsGroup.setLayoutData(gridData);
+
+ Composite tablesComposite = _toolkit.createComposite(bindingsGroup);
+ gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gridData.minimumHeight = 250;
+ gridData.heightHint = 250;
+ tablesComposite.setLayoutData(gridData);
+ tablesComposite.setLayout(new GridLayout(2,false));
+
+ _keysTable = new Table (tablesComposite, SWT.SINGLE | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION);
+ _keysTable.setLinesVisible(true);
+ _keysTable.setHeaderVisible(true);
+ GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ _keysTable.setLayoutData(data);
+
+ _keysTableViewer = new TableViewer(_keysTable);
+ final TableSorter tableSorter = new TableSorter(BINDING_KEY);
+
+ String[] titles = {"Binding Key"};
+ int[] bounds = {200};
+ for (int i = 0; i < titles.length; i++)
+ {
+ final int index = i;
+ final TableColumn column = new TableColumn (_keysTable, SWT.NONE);
+
+ column.setText(titles[i]);
+ column.setWidth(bounds[i]);
+ column.setResizable(true);
+
+ //Setting the right sorter
+ column.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ tableSorter.setColumn(index);
+ final TableViewer viewer = _keysTableViewer;
+ int dir = viewer .getTable().getSortDirection();
+ if (viewer.getTable().getSortColumn() == column)
+ {
+ dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
+ }
+ else
+ {
+ dir = SWT.UP;
+ }
+ viewer.getTable().setSortDirection(dir);
+ viewer.getTable().setSortColumn(column);
+ viewer.refresh();
+ }
+ });
+
+ }
+
+ _keysTableViewer.setContentProvider(new ContentProviderImpl(BINDING_KEY));
+ _keysTableViewer.setLabelProvider(new LabelProviderImpl(BINDING_KEY));
+ _keysTableViewer.setSorter(tableSorter);
+ _keysTable.setSortColumn(_keysTable.getColumn(0));
+ _keysTable.setSortDirection(SWT.UP);
+
+
+ _queuesTable = new Table (tablesComposite, SWT.SINGLE | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION);
+ _queuesTable.setLinesVisible (true);
+ _queuesTable.setHeaderVisible (true);
+ data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ _queuesTable.setLayoutData(data);
+
+ _queuesTableViewer = new TableViewer(_queuesTable);
+ final TableSorter queuesTableSorter = new TableSorter(QUEUES);
+
+ titles = new String[]{"Queue Names"};
+ bounds = new int[]{225};
+ for (int i = 0; i < titles.length; i++)
+ {
+ final int index = i;
+ final TableColumn column = new TableColumn (_queuesTable, SWT.NONE);
+
+ column.setText(titles[i]);
+ column.setWidth(bounds[i]);
+ column.setResizable(true);
+
+ //Setting the right sorter
+ column.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ queuesTableSorter.setColumn(index);
+ final TableViewer viewer = _queuesTableViewer;
+ int dir = viewer .getTable().getSortDirection();
+ if (viewer.getTable().getSortColumn() == column)
+ {
+ dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
+ }
+ else
+ {
+ dir = SWT.UP;
+ }
+ viewer.getTable().setSortDirection(dir);
+ viewer.getTable().setSortColumn(column);
+ viewer.refresh();
+ }
+ });
+
+ }
+
+ _queuesTableViewer.setContentProvider(new ContentProviderImpl(QUEUES));
+ _queuesTableViewer.setLabelProvider(new LabelProviderImpl(QUEUES));
+ _queuesTableViewer.setSorter(queuesTableSorter);
+ _queuesTable.setSortColumn(_queuesTable.getColumn(0));
+ _queuesTable.setSortDirection(SWT.UP);
+ _queuesTableViewer.setInput(new String[]{"Select a binding key to view queues"});
+
+ //listener for double clicking to open the selection mbean
+ _queuesTable.addMouseListener(new MouseListener()
+ {
+ // MouseListener implementation
+ public void mouseDoubleClick(MouseEvent event)
+ {
+ openMBean(_queuesTable);
+ }
+
+ public void mouseDown(MouseEvent e){}
+ public void mouseUp(MouseEvent e){}
+ });
+
+ _keysTableViewer.addSelectionChangedListener(new ISelectionChangedListener(){
+ public void selectionChanged(SelectionChangedEvent evt)
+ {
+ updateQueuesTable();
+ }
+ });
+
+ //Side Buttons
+ Composite buttonsComposite = _toolkit.createComposite(bindingsGroup);
+ gridData = new GridData(SWT.FILL, SWT.FILL, false, true);
+ buttonsComposite.setLayoutData(gridData);
+ buttonsComposite.setLayout(new GridLayout());
+
+ final Button createBindingButton = _toolkit.createButton(buttonsComposite, "Create ...", SWT.PUSH);
+ createBindingButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ createNewBinding(createBindingButton.getShell());
+ }
+ });
+
+ }
+
+ private void updateQueuesTable()
+ {
+ int selectionIndex = _keysTable.getSelectionIndex();
+
+ if (selectionIndex != -1)
+ {
+ final CompositeData selectedMsg = (CompositeData)_keysTable.getItem(selectionIndex).getData();
+
+ String[] queues = (String[]) selectedMsg.get(QUEUES);
+ _queuesTableViewer.setInput(queues);
+ }
+ else
+ {
+ _queuesTableViewer.setInput(new String[]{"Select a binding key to view queues"});
+ }
+ }
+
+ private boolean isFanoutExchange()
+ {
+ return _mbean.getProperty(EXCHANGE_TYPE).equalsIgnoreCase(DEFAULT_EXCHANGE_TYPE_VALUES[1]);
+
+ }
+
+ /**
+ * Content Provider class for the table viewer
+ */
+ private class ContentProviderImpl implements IStructuredContentProvider
+ {
+ String type;
+
+ public ContentProviderImpl(String type)
+ {
+ this.type = type;
+ }
+
+ public void inputChanged(Viewer v, Object oldInput, Object newInput)
+ {
+
+ }
+
+ public void dispose()
+ {
+
+ }
+
+ public Object[] getElements(Object parent)
+ {
+ if(type.equals(BINDING_KEY))
+ {
+ Collection<Object> rowCollection = ((TabularDataSupport) parent).values();
+
+ return rowCollection.toArray();
+ }
+ else
+ {
+ //we have the list of queues, return directly
+ return (String[]) parent;
+ }
+ }
+ }
+
+ /**
+ * Label Provider class for the routing key table viewer
+ */
+ private class LabelProviderImpl extends LabelProvider implements ITableLabelProvider
+ {
+ String type;
+
+ public LabelProviderImpl(String type)
+ {
+ this.type = type;
+ }
+
+ @Override
+ public String getColumnText(Object element, int columnIndex)
+ {
+ if(type.equals(BINDING_KEY)) //binding num and queue name table
+ {
+ switch (columnIndex)
+ {
+ case 0 : // key column
+ return String.valueOf(((CompositeDataSupport) element).get(BINDING_KEY));
+ default :
+ return "";
+ }
+ }
+ else //binding key-value pair table
+ {
+ switch (columnIndex)
+ {
+ case 0 : //queue name column
+ return String.valueOf(element);
+ default :
+ return "";
+ }
+ }
+ }
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex)
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Sorter class for the table viewer.
+ *
+ */
+ public class TableSorter extends ViewerSorter
+ {
+ private int column;
+ private static final int ASCENDING = 0;
+ private static final int DESCENDING = 1;
+
+ private int direction = DESCENDING;
+
+ private String type;
+
+ public TableSorter(String type)
+ {
+ this.type = type;
+ this.column = 0;
+ direction = ASCENDING;
+ }
+
+ public void setColumn(int column)
+ {
+ if (column == this.column)
+ {
+ // Same column as last sort; toggle the direction
+ direction = 1 - direction;
+ }
+ else
+ {
+ // New column; do an ascending sort
+ this.column = column;
+ direction = ASCENDING;
+ }
+ }
+
+ @Override
+ public int compare(Viewer viewer, Object e1, Object e2)
+ {
+ int comparison = 0;
+
+ if(type.equals(BINDING_KEY))//binding num and queue name table
+ {
+ CompositeData binding1 = (CompositeData) e1;
+ CompositeData binding2 = (CompositeData) e2;
+
+ switch(column)
+ {
+ case 0:
+ comparison = ((String) binding1.get(BINDING_KEY)).compareTo((String) binding2.get(BINDING_KEY));
+ break;
+ default:
+ comparison = 0;
+ }
+ }
+ else //binding key-value pair table
+ {
+ switch(column)
+ {
+ case 0:
+ comparison = ((String)e1).compareTo((String) e2);
+ break;
+ default:
+ comparison = 0;
+ }
+ }
+
+
+ // If descending order, flip the direction
+ if(direction == DESCENDING)
+ {
+ comparison = -comparison;
+ }
+ return comparison;
+ }
+ }
+
+ private void createNewBinding(Shell parent)
+ {
+ final Shell shell = ViewUtility.createModalDialogShell(parent, "Create New Binding");
+
+ Composite destinationComposite = _toolkit.createComposite(shell, SWT.NONE);
+ destinationComposite.setBackground(shell.getBackground());
+ destinationComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ destinationComposite.setLayout(new GridLayout(2,false));
+
+ _toolkit.createLabel(destinationComposite,"Queue:").setBackground(shell.getBackground());
+ final Combo destinationCombo = new Combo(destinationComposite,SWT.NONE | SWT.READ_ONLY);
+ destinationCombo.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+
+ Composite bindingComposite = _toolkit.createComposite(shell, SWT.NONE);
+ bindingComposite.setBackground(shell.getBackground());
+ bindingComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ bindingComposite.setLayout(new GridLayout(2,false));
+
+ _toolkit.createLabel(bindingComposite,"Binding:").setBackground(shell.getBackground());
+ final Text bindingText = new Text(bindingComposite, SWT.BORDER);
+ bindingText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ if(isFanoutExchange())
+ {
+ bindingText.setText("*");
+ }
+
+ Composite okCancelButtonsComp = _toolkit.createComposite(shell);
+ okCancelButtonsComp.setBackground(shell.getBackground());
+ okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true));
+ okCancelButtonsComp.setLayout(new GridLayout(2,false));
+
+ Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH);
+ okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+ Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH);
+ cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+
+ List<String> queueList = ApplicationRegistry.getServerRegistry(_mbean).getQueueNames(_mbean.getVirtualHostName());
+
+ if(queueList.size() == 0)
+ {
+ destinationCombo.setItems(new String[]{"No queues available"});
+ okButton.setEnabled(false);
+ }
+ else
+ {
+ Collections.sort(queueList);
+ destinationCombo.setItems(queueList.toArray(new String[0]));
+ }
+ destinationCombo.select(0);
+
+ okButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ String binding = bindingText.getText();
+
+ if (!isFanoutExchange() && (binding == null || binding.length() == 0))
+ {
+ ViewUtility.popupErrorMessage("Create New Binding", "Please enter a valid binding");
+ return;
+ }
+
+ String destQueue = destinationCombo.getItem(destinationCombo.getSelectionIndex()).toString();
+
+ shell.dispose();
+
+ try
+ {
+ _emb.createNewBinding(destQueue, binding);
+ ViewUtility.operationResultFeedback(null, "Created new Binding", null);
+ }
+ catch (Exception e4)
+ {
+ ViewUtility.operationFailedStatusBarMessage("Error creating new Binding");
+ MBeanUtility.handleException(_mbean, e4);
+ }
+
+ refresh(_mbean);
+ }
+ });
+
+ cancelButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ shell.dispose();
+ }
+ });
+
+ shell.setDefaultButton(okButton);
+ shell.pack();
+ ViewUtility.centerChildInParentShell(parent, shell);
+
+ shell.open();
+ }
+
+ private void openMBean(Table table)
+ {
+ int selectionIndex = table.getSelectionIndex();
+
+ if (selectionIndex == -1)
+ {
+ return;
+ }
+
+ String queueName = (String) table.getItem(selectionIndex).getData();
+ ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(_mbean);
+ ManagedBean selectedMBean = serverRegistry.getQueue(queueName, _mbean.getVirtualHostName());
+
+ if(selectedMBean == null)
+ {
+ ViewUtility.popupErrorMessage("Error", "Unable to retrieve the selected MBean to open it");
+ return;
+ }
+
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ MBeanView view = (MBeanView) window.getActivePage().findView(MBeanView.ID);
+ try
+ {
+ view.openMBean(selectedMBean);
+ }
+ catch (Exception ex)
+ {
+ MBeanUtility.handleException(selectedMBean, ex);
+ }
+ }
+}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/exchange/HeadersExchangeOperationsTabControl.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/exchange/HeadersExchangeOperationsTabControl.java
new file mode 100644
index 0000000000..fcce0e67b6
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/exchange/HeadersExchangeOperationsTabControl.java
@@ -0,0 +1,713 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui.views.exchange;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.TabularDataSupport;
+
+import org.apache.qpid.management.ui.ApplicationRegistry;
+import org.apache.qpid.management.ui.ManagedBean;
+import org.apache.qpid.management.ui.ServerRegistry;
+import org.apache.qpid.management.common.mbeans.ManagedExchange;
+import org.apache.qpid.management.ui.jmx.JMXManagedObject;
+import org.apache.qpid.management.ui.jmx.MBeanUtility;
+import org.apache.qpid.management.ui.views.MBeanView;
+import org.apache.qpid.management.ui.views.TabControl;
+import org.apache.qpid.management.ui.views.ViewUtility;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+
+
+/**
+ * Control class for the Headers Exchange mbean Operations tab.
+ */
+public class HeadersExchangeOperationsTabControl extends TabControl
+{
+ private FormToolkit _toolkit;
+ private ScrolledForm _form;
+ private Table _bindingNumberTable = null;
+ private TableViewer _bindingNumberTableViewer = null;
+ private Table _headersTable = null;
+ private TableViewer _headersTableViewer = null;
+ private Composite _paramsComposite = null;
+
+ private TabularDataSupport _bindings = null;
+ private ManagedExchange _emb;
+
+ static final String BINDING_NUM = ManagedExchange.HEADERS_COMPOSITE_ITEM_NAMES[0];
+ static final String QUEUE_NAME = ManagedExchange.HEADERS_COMPOSITE_ITEM_NAMES[1];
+ static final String HEADER_BINDINGS = ManagedExchange.HEADERS_COMPOSITE_ITEM_NAMES[2];
+
+ public HeadersExchangeOperationsTabControl(TabFolder tabFolder, JMXManagedObject mbean, MBeanServerConnection mbsc)
+ {
+ super(tabFolder);
+ _mbean = mbean;
+ _emb = (ManagedExchange) MBeanServerInvocationHandler.newProxyInstance(mbsc,
+ mbean.getObjectName(), ManagedExchange.class, false);
+ _toolkit = new FormToolkit(_tabFolder.getDisplay());
+ _form = _toolkit.createScrolledForm(_tabFolder);
+ _form.getBody().setLayout(new GridLayout());
+ createComposites();
+ createWidgets();
+ }
+
+ private void createComposites()
+ {
+ _paramsComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE);
+ _paramsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ _paramsComposite.setLayout(new GridLayout());
+ }
+
+ /**
+ * @see TabControl#getControl()
+ */
+ public Control getControl()
+ {
+ return _form;
+ }
+
+ /**
+ * @see TabControl#setFocus()
+ */
+ public void setFocus()
+ {
+ _bindingNumberTable.setFocus();
+ }
+
+ @Override
+ public void refresh(ManagedBean mbean)
+ {
+
+ _bindings = null;
+ try
+ {
+ //gather a list of all keys and queues for display and selection
+ _bindings = (TabularDataSupport) _emb.bindings();
+ }
+ catch (Exception e)
+ {
+ MBeanUtility.handleException(_mbean,e);
+ }
+
+ _bindingNumberTableViewer.setInput(_bindings);
+
+ layout();
+ }
+
+ public void layout()
+ {
+ _form.layout(true);
+ _form.getBody().layout(true, true);
+ }
+
+ private void createWidgets()
+ {
+ Group bindingsGroup = new Group(_paramsComposite, SWT.SHADOW_NONE);
+ bindingsGroup.setBackground(_paramsComposite.getBackground());
+ bindingsGroup.setText("Bindings");
+ bindingsGroup.setLayout(new GridLayout(2,false));
+ GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ bindingsGroup.setLayoutData(gridData);
+
+ Composite tablesComposite = _toolkit.createComposite(bindingsGroup);
+ gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gridData.minimumHeight = 250;
+ gridData.heightHint = 250;
+ tablesComposite.setLayoutData(gridData);
+ tablesComposite.setLayout(new GridLayout(2,false));
+
+ //table of bindings for the exchange
+ _bindingNumberTable = new Table (tablesComposite, SWT.SINGLE | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION);
+ _bindingNumberTable.setLinesVisible(true);
+ _bindingNumberTable.setHeaderVisible(true);
+ GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ data.minimumHeight = 300;
+ data.heightHint = 300;
+ _bindingNumberTable.setLayoutData(data);
+
+ _bindingNumberTableViewer = new TableViewer(_bindingNumberTable);
+ final TableSorter tableSorter = new TableSorter(BINDING_NUM);
+
+ String[] titles = {"Binding Number", "Queue Name"};
+ int[] bounds = {135, 175};
+ for (int i = 0; i < titles.length; i++)
+ {
+ final int index = i;
+ final TableColumn column = new TableColumn (_bindingNumberTable, SWT.NONE);
+
+ column.setText(titles[i]);
+ column.setWidth(bounds[i]);
+ column.setResizable(true);
+
+ //Setting the right sorter
+ column.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ tableSorter.setColumn(index);
+ final TableViewer viewer = _bindingNumberTableViewer;
+ int dir = viewer .getTable().getSortDirection();
+ if (viewer.getTable().getSortColumn() == column)
+ {
+ dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
+ }
+ else
+ {
+ dir = SWT.UP;
+ }
+ viewer.getTable().setSortDirection(dir);
+ viewer.getTable().setSortColumn(column);
+ viewer.refresh();
+ }
+ });
+
+ }
+
+ _bindingNumberTableViewer.setContentProvider(new ContentProviderImpl(BINDING_NUM));
+ _bindingNumberTableViewer.setLabelProvider(new LabelProviderImpl(BINDING_NUM));
+ _bindingNumberTableViewer.setSorter(tableSorter);
+ _bindingNumberTable.setSortColumn(_bindingNumberTable.getColumn(0));
+ _bindingNumberTable.setSortDirection(SWT.UP);
+
+ //table of header bindings
+ _headersTable = new Table (tablesComposite, SWT.SINGLE | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION);
+ _headersTable.setLinesVisible (true);
+ _headersTable.setHeaderVisible (true);
+ data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ data.minimumHeight = 300;
+ data.heightHint = 300;
+ _headersTable.setLayoutData(data);
+
+ _headersTableViewer = new TableViewer(_headersTable);
+ final TableSorter queuesTableSorter = new TableSorter(HEADER_BINDINGS);
+
+ titles = new String[]{"Header Bindings"};
+ bounds = new int[]{225};
+ for (int i = 0; i < titles.length; i++)
+ {
+ final int index = i;
+ final TableColumn column = new TableColumn (_headersTable, SWT.NONE);
+
+ column.setText(titles[i]);
+ column.setWidth(bounds[i]);
+ column.setResizable(true);
+
+ //Setting the right sorter
+ column.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ queuesTableSorter.setColumn(index);
+ final TableViewer viewer = _headersTableViewer;
+ int dir = viewer .getTable().getSortDirection();
+ if (viewer.getTable().getSortColumn() == column)
+ {
+ dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
+ }
+ else
+ {
+ dir = SWT.UP;
+ }
+ viewer.getTable().setSortDirection(dir);
+ viewer.getTable().setSortColumn(column);
+ viewer.refresh();
+ }
+ });
+
+ }
+
+ _headersTableViewer.setContentProvider(new ContentProviderImpl(HEADER_BINDINGS));
+ _headersTableViewer.setLabelProvider(new LabelProviderImpl(HEADER_BINDINGS));
+ _headersTableViewer.setSorter(queuesTableSorter);
+ _headersTable.setSortColumn(_headersTable.getColumn(0));
+ _headersTable.setSortDirection(SWT.UP);
+ _headersTableViewer.setInput(new String[]{"Select a binding to view key-value pairs"});
+
+ _bindingNumberTableViewer.addSelectionChangedListener(new ISelectionChangedListener(){
+ public void selectionChanged(SelectionChangedEvent evt)
+ {
+ int selectionIndex = _bindingNumberTable.getSelectionIndex();
+
+ if (selectionIndex != -1)
+ {
+ final CompositeData selectedMsg = (CompositeData)_bindingNumberTable.getItem(selectionIndex).getData();
+
+ String[] bindings = (String[]) selectedMsg.get(HEADER_BINDINGS);
+ _headersTableViewer.setInput(bindings);
+ }
+ else
+ {
+ _headersTableViewer.setInput(new String[]{"Select a binding to view key-value pairs"});
+ }
+ }
+ });
+
+ //listener for double clicking to open the selection mbean
+ _bindingNumberTable.addMouseListener(new MouseListener()
+ {
+ // MouseListener implementation
+ public void mouseDoubleClick(MouseEvent event)
+ {
+ openMBean(_bindingNumberTable);
+ }
+
+ public void mouseDown(MouseEvent e){}
+ public void mouseUp(MouseEvent e){}
+ });
+
+ //Side Buttons
+ Composite buttonsComposite = _toolkit.createComposite(bindingsGroup);
+ gridData = new GridData(SWT.FILL, SWT.FILL, false, true);
+ buttonsComposite.setLayoutData(gridData);
+ buttonsComposite.setLayout(new GridLayout());
+
+ final Button createBindingButton = _toolkit.createButton(buttonsComposite, "Create ...", SWT.PUSH);
+ createBindingButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ createNewBinding(createBindingButton.getShell());
+ }
+ });
+
+ }
+
+
+ /**
+ * Content Provider class for the table viewer
+ */
+ private class ContentProviderImpl implements IStructuredContentProvider
+ {
+ String type;
+
+ public ContentProviderImpl(String type)
+ {
+ this.type = type;
+ }
+
+ public void inputChanged(Viewer v, Object oldInput, Object newInput)
+ {
+
+ }
+
+ public void dispose()
+ {
+
+ }
+
+ public Object[] getElements(Object parent)
+ {
+ if(type.equals(BINDING_NUM))
+ {
+ Collection<Object> rowCollection = ((TabularDataSupport) parent).values();
+
+ return rowCollection.toArray();
+ }
+ else
+ {
+ //we have the list of bindings, return directly
+ return (String[]) parent;
+ }
+ }
+ }
+
+ /**
+ * Label Provider class for the routing key table viewer
+ */
+ private class LabelProviderImpl extends LabelProvider implements ITableLabelProvider
+ {
+ String type;
+
+ public LabelProviderImpl(String type)
+ {
+ this.type = type;
+ }
+
+ @Override
+ public String getColumnText(Object element, int columnIndex)
+ {
+ if(type.equals(BINDING_NUM)) //binding num and queue name table
+ {
+ switch (columnIndex)
+ {
+ case 0 : // binding number column
+ return String.valueOf(((CompositeDataSupport) element).get(BINDING_NUM));
+ case 1 : // queue name column
+ return (String) ((CompositeDataSupport) element).get(QUEUE_NAME);
+ default :
+ return "";
+ }
+ }
+ else //binding key-value pair table
+ {
+ switch (columnIndex)
+ {
+ case 0 : //header binding column
+ return String.valueOf(element);
+ default :
+ return "";
+ }
+ }
+ }
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex)
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Sorter class for the table viewer.
+ *
+ */
+ public class TableSorter extends ViewerSorter
+ {
+ private int column;
+ private static final int ASCENDING = 0;
+ private static final int DESCENDING = 1;
+
+ private int direction = DESCENDING;
+
+ private String type;
+
+ public TableSorter(String type)
+ {
+ this.type = type;
+ this.column = 0;
+ direction = ASCENDING;
+ }
+
+ public void setColumn(int column)
+ {
+ if (column == this.column)
+ {
+ // Same column as last sort; toggle the direction
+ direction = 1 - direction;
+ }
+ else
+ {
+ // New column; do an ascending sort
+ this.column = column;
+ direction = ASCENDING;
+ }
+ }
+
+ @Override
+ public int compare(Viewer viewer, Object e1, Object e2)
+ {
+ int comparison = 0;
+
+ if(type.equals(BINDING_NUM)) //binding num and queue name table
+ {
+ CompositeData binding1 = (CompositeData) e1;
+ CompositeData binding2 = (CompositeData) e2;
+
+ switch(column)
+ {
+ case 0: // binding number column
+ comparison = ((Integer) binding1.get(BINDING_NUM)).compareTo((Integer) binding2.get(BINDING_NUM));
+ break;
+ case 1: // queue name column
+ comparison = ((String) binding1.get(QUEUE_NAME)).compareTo((String) binding2.get(QUEUE_NAME));
+ break;
+ default:
+ comparison = 0;
+ }
+ }
+ else //binding key-value pair table
+ {
+ switch(column)
+ {
+ case 0: //header binding column
+ comparison = ((String)e1).compareTo((String) e2);
+ break;
+ default:
+ comparison = 0;
+ }
+ }
+
+ // If descending order, flip the direction
+ if(direction == DESCENDING)
+ {
+ comparison = -comparison;
+ }
+ return comparison;
+ }
+ }
+
+ private void createNewBinding(Shell parent)
+ {
+ final Shell shell = ViewUtility.createModalDialogShell(parent, "Create New Binding");
+
+ Composite queueNameComposite = _toolkit.createComposite(shell, SWT.NONE);
+ queueNameComposite.setBackground(shell.getBackground());
+ GridData layoutData = new GridData(SWT.CENTER, SWT.TOP, true, false);
+ layoutData.minimumWidth = 300;
+ queueNameComposite.setLayoutData(layoutData);
+ queueNameComposite.setLayout(new GridLayout(2,false));
+
+ _toolkit.createLabel(queueNameComposite,"Queue:").setBackground(shell.getBackground());
+ final Combo destinationCombo = new Combo(queueNameComposite,SWT.NONE | SWT.READ_ONLY);
+ destinationCombo.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+
+ final ScrolledComposite scrolledComposite = new ScrolledComposite(shell, SWT.V_SCROLL);
+ scrolledComposite.setExpandHorizontal(true);
+ scrolledComposite.setLayout(new GridLayout());
+ scrolledComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ scrolledComposite.setBackground(shell.getBackground());
+
+ final Composite bindingComposite = _toolkit.createComposite(scrolledComposite, SWT.NONE);
+ bindingComposite.setBackground(scrolledComposite.getBackground());
+ bindingComposite.setLayout(new GridLayout(2,true));
+ layoutData = new GridData(SWT.FILL, SWT.TOP, true, false);
+ bindingComposite.setLayoutData(layoutData);
+ scrolledComposite.setContent(bindingComposite);
+
+ Composite addMoreButtonComp = _toolkit.createComposite(shell);
+ addMoreButtonComp.setBackground(shell.getBackground());
+ addMoreButtonComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true));
+ addMoreButtonComp.setLayout(new GridLayout());
+
+ final Button addMoreButton = _toolkit.createButton(addMoreButtonComp, "Add additional field", SWT.PUSH);
+
+ Composite okCancelButtonsComp = _toolkit.createComposite(shell);
+ okCancelButtonsComp.setBackground(shell.getBackground());
+ okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true));
+ okCancelButtonsComp.setLayout(new GridLayout(2,false));
+
+ Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH);
+ okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+ Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH);
+ cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+
+ List<String> queueList = ApplicationRegistry.getServerRegistry(_mbean).getQueueNames(_mbean.getVirtualHostName());
+
+ if(queueList.size() == 0)
+ {
+ destinationCombo.setItems(new String[]{"No queues available"});
+ okButton.setEnabled(false);
+ }
+ else
+ {
+ Collections.sort(queueList);
+ destinationCombo.setItems(queueList.toArray(new String[0]));
+ }
+ destinationCombo.select(0);
+
+ final HashMap<Text, Text> headerBindingHashMap = new HashMap<Text, Text>();
+
+ //add headings
+ Label keyLabel = _toolkit.createLabel(bindingComposite,"Key:");
+ keyLabel.setBackground(bindingComposite.getBackground());
+ keyLabel.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, true, false));
+
+ Label valueLabel = _toolkit.createLabel(bindingComposite,"Value:");
+ valueLabel.setBackground(bindingComposite.getBackground());
+ valueLabel.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, true, false));
+
+ //add the x-match key by default and offer a comobo to select its value
+ final Text xmatchKeyText = new Text(bindingComposite, SWT.BORDER);
+ xmatchKeyText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ xmatchKeyText.setText("x-match");
+ xmatchKeyText.setEditable(false);
+
+ final Combo xmatchValueCombo = new Combo(bindingComposite,SWT.NONE | SWT.READ_ONLY);
+ xmatchValueCombo.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ xmatchValueCombo.setItems(new String[]{"any", "all"});
+ xmatchValueCombo.select(0);
+
+ //make some empty key-value fields
+ for(int i=0; i < 4; i++)
+ {
+ Text keyText = new Text(bindingComposite, SWT.BORDER);
+ Text valueText = new Text(bindingComposite, SWT.BORDER);
+ keyText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ valueText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+
+ headerBindingHashMap.put(keyText, valueText);
+ }
+ bindingComposite.setSize(bindingComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+
+ //allow adding more fields for additional key-value pairs
+ addMoreButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ Text keyText = new Text(bindingComposite, SWT.BORDER);
+ Text valueText = new Text(bindingComposite, SWT.BORDER);
+ keyText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ valueText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+
+ headerBindingHashMap.put(keyText, valueText);
+
+ bindingComposite.setSize(bindingComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ bindingComposite.layout(true);
+ scrolledComposite.layout(true);
+ }
+ });
+
+ okButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ String xMatchString = xmatchValueCombo.getText();
+
+ String destQueue = destinationCombo.getItem(destinationCombo.getSelectionIndex()).toString();
+
+ StringBuffer bindingValue = new StringBuffer();
+
+ //insert the x-match key-value pair
+ if (xMatchString.equalsIgnoreCase("any"))
+ {
+ bindingValue.append("x-match=any");
+ }
+ else
+ {
+ bindingValue.append("x-match=all");
+ }
+
+ //insert the other key-value pairs
+ for (Text keyText : headerBindingHashMap.keySet())
+ {
+
+ String key = keyText.getText();
+ if(key == null || key.length() == 0)
+ {
+ continue;
+ }
+
+ Text valueText = headerBindingHashMap.get(keyText);
+ String value = valueText.getText();
+
+ bindingValue.append(",");
+ bindingValue.append(key + "=");
+ //empty values are permitted, signalling only key-presence is required
+ if(value != null && value.length() > 0)
+ {
+ bindingValue.append(value);
+ }
+ }
+
+ shell.dispose();
+
+ try
+ {
+ _emb.createNewBinding(destQueue, bindingValue.toString());
+ ViewUtility.operationResultFeedback(null, "Created new Binding", null);
+ }
+ catch (Exception e4)
+ {
+ ViewUtility.operationFailedStatusBarMessage("Error creating new Binding");
+ MBeanUtility.handleException(_mbean, e4);
+ }
+
+ refresh(_mbean);
+ }
+ });
+
+ cancelButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ shell.dispose();
+ }
+ });
+
+ shell.setDefaultButton(okButton);
+ shell.pack();
+ ViewUtility.centerChildInParentShell(parent, shell);
+
+ shell.open();
+ }
+
+ private void openMBean(Table table)
+ {
+ int selectionIndex = table.getSelectionIndex();
+
+ if (selectionIndex == -1)
+ {
+ return;
+ }
+
+ CompositeData bindingResult = (CompositeData) table.getItem(selectionIndex).getData();
+ String queueName = (String) bindingResult.get(QUEUE_NAME);
+ ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(_mbean);
+ ManagedBean selectedMBean = serverRegistry.getQueue(queueName, _mbean.getVirtualHostName());
+
+ if(selectedMBean == null)
+ {
+ ViewUtility.popupErrorMessage("Error", "Unable to retrieve the selected MBean to open it");
+ return;
+ }
+
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ MBeanView view = (MBeanView) window.getActivePage().findView(MBeanView.ID);
+ try
+ {
+ view.openMBean(selectedMBean);
+ }
+ catch (Exception ex)
+ {
+ MBeanUtility.handleException(selectedMBean, ex);
+ }
+ }
+}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/ConfigurationFileTabControl.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/ConfigurationFileTabControl.java
new file mode 100644
index 0000000000..536033368f
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/ConfigurationFileTabControl.java
@@ -0,0 +1,591 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui.views.logging;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularDataSupport;
+
+import static org.apache.qpid.management.ui.Constants.FONT_BOLD;
+
+import org.apache.qpid.management.ui.ApiVersion;
+import org.apache.qpid.management.ui.ApplicationRegistry;
+import org.apache.qpid.management.ui.ManagedBean;
+import org.apache.qpid.management.common.mbeans.LoggingManagement;
+import org.apache.qpid.management.ui.jmx.JMXManagedObject;
+import org.apache.qpid.management.ui.jmx.MBeanUtility;
+import org.apache.qpid.management.ui.views.TabControl;
+import org.apache.qpid.management.ui.views.ViewUtility;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+
+
+/**
+ * Control class for the LoggingManagement mbean ConfigFile Options tab.
+ */
+public class ConfigurationFileTabControl extends TabControl
+{
+ private FormToolkit _toolkit;
+ private ScrolledForm _form;
+ private Table _table = null;
+ private TableViewer _tableViewer = null;
+ private Composite _headerComposite = null;
+ private Composite _paramsComposite = null;
+
+ private Label _configFileRootLoggerLevelLabel = null;
+ private Label _logWatchIntervalLabel = null;
+ private String[] _availableLoggerLevels;
+ private TabularDataSupport _configFileLoggerLevels = null;
+ private LoggingManagement _lmmb;
+ private ApiVersion _ApiVersion;
+
+ static final String LOGGER_NAME = LoggingManagement.COMPOSITE_ITEM_NAMES[0];
+ static final String LOGGER_LEVEL = LoggingManagement.COMPOSITE_ITEM_NAMES[1];
+
+ public ConfigurationFileTabControl(TabFolder tabFolder, JMXManagedObject mbean, MBeanServerConnection mbsc)
+ {
+ super(tabFolder);
+ _mbean = mbean;
+ _lmmb = (LoggingManagement)
+ MBeanServerInvocationHandler.newProxyInstance(mbsc, mbean.getObjectName(),
+ LoggingManagement.class, false);
+ _ApiVersion = ApplicationRegistry.getServerRegistry(mbean).getManagementApiVersion();
+ _toolkit = new FormToolkit(_tabFolder.getDisplay());
+ _form = _toolkit.createScrolledForm(_tabFolder);
+ _form.getBody().setLayout(new GridLayout());
+ createComposites();
+ createWidgets();
+ }
+
+ private void createComposites()
+ {
+
+ _headerComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE);
+ _headerComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ _headerComposite.setLayout(new GridLayout());
+
+ _paramsComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE);
+ _paramsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ _paramsComposite.setLayout(new GridLayout());
+ }
+
+ /**
+ * @see TabControl#getControl()
+ */
+ public Control getControl()
+ {
+ return _form;
+ }
+
+ /**
+ * @see TabControl#setFocus()
+ */
+ public void setFocus()
+ {
+ _table.setFocus();
+ }
+
+ @Override
+ public void refresh(ManagedBean mbean)
+ {
+ String configFileRootLoggerLevel = "-";
+ try
+ {
+ configFileRootLoggerLevel = _lmmb.getConfigFileRootLoggerLevel();
+ }
+ catch (Exception e1)
+ {
+ MBeanUtility.handleException(_mbean, e1);
+ }
+
+ int log4jLogWatchInterval = -1;
+ try
+ {
+ log4jLogWatchInterval = _lmmb.getLog4jLogWatchInterval();
+ }
+ catch (Exception e2)
+ {
+ MBeanUtility.handleException(_mbean, e2);
+ }
+
+ _configFileLoggerLevels = null;
+ try
+ {
+ _configFileLoggerLevels = (TabularDataSupport) _lmmb.viewConfigFileLoggerLevels();
+ }
+ catch (Exception e3)
+ {
+ MBeanUtility.handleException(_mbean, e3);
+ }
+
+ _configFileRootLoggerLevelLabel.setText(String.valueOf(configFileRootLoggerLevel));
+ if (log4jLogWatchInterval == 0)
+ {
+ _logWatchIntervalLabel.setText("Disabled (0 sec)");
+ }
+ else
+ {
+ _logWatchIntervalLabel.setText(String.valueOf(log4jLogWatchInterval) + " seconds");
+ }
+ _tableViewer.setInput(_configFileLoggerLevels);
+
+ layout();
+ }
+
+ public void layout()
+ {
+ _form.layout(true);
+ _form.getBody().layout(true, true);
+ }
+
+ private void createWidgets()
+ {
+ try
+ {
+ _availableLoggerLevels = _lmmb.getAvailableLoggerLevels();
+ }
+ catch(Exception e)
+ {
+ _availableLoggerLevels = new String[]{"ALL","TRACE","DEBUG","INFO","WARN","ERROR","FATAL","OFF"};
+ }
+
+ Label noteLabel = _toolkit.createLabel(_headerComposite,
+ "NOTE: These options modify the configuration file. " +
+ "Changes only take effect automatically if LogWatch is enabled.");
+ Label noteLabel2 = _toolkit.createLabel(_headerComposite,
+ "A child Logger set to a non-inherited Level in the Runtime tab " +
+ "will retain that value after the file is reloaded.");
+ GridData gridData = new GridData(SWT.FILL, SWT.FILL, false, true);
+ noteLabel.setLayoutData(gridData);
+ gridData = new GridData(SWT.FILL, SWT.FILL, false, true);
+ noteLabel2.setLayoutData(gridData);
+
+ Group configFileLoggerLevelsGroup = new Group(_paramsComposite, SWT.SHADOW_NONE);
+ configFileLoggerLevelsGroup.setBackground(_paramsComposite.getBackground());
+ configFileLoggerLevelsGroup.setText("Configuration File Logger Levels");
+ configFileLoggerLevelsGroup.setLayout(new GridLayout());
+ gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ configFileLoggerLevelsGroup.setLayoutData(gridData);
+
+ Composite tableComposite = _toolkit.createComposite(configFileLoggerLevelsGroup);
+ gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gridData.heightHint = 250;
+ gridData.minimumHeight = 250;
+ tableComposite.setLayoutData(gridData);
+ GridLayout gridLayout = new GridLayout();
+
+ tableComposite.setLayout(gridLayout);
+
+ _table = new Table (tableComposite, SWT.MULTI | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION);
+ _table.setLinesVisible (true);
+ _table.setHeaderVisible (true);
+ GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ _table.setLayoutData(data);
+
+ _tableViewer = new TableViewer(_table);
+ final LoggingTableSorter tableSorter = new LoggingTableSorter();
+
+ String[] titles = { LOGGER_NAME, LOGGER_LEVEL };
+ int[] bounds = { 600, 75 };
+ for (int i = 0; i < titles.length; i++)
+ {
+ final int index = i;
+ final TableViewerColumn viewerColumn = new TableViewerColumn(_tableViewer, SWT.NONE);
+ final TableColumn column = viewerColumn.getColumn();
+
+ column.setText(titles[i]);
+ column.setWidth(bounds[i]);
+ column.setResizable(true);
+
+ //Setting the right sorter
+ column.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ tableSorter.setColumn(index);
+ final TableViewer viewer = _tableViewer;
+ int dir = viewer .getTable().getSortDirection();
+ if (viewer.getTable().getSortColumn() == column)
+ {
+ dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
+ }
+ else
+ {
+ dir = SWT.UP;
+ }
+ viewer.getTable().setSortDirection(dir);
+ viewer.getTable().setSortColumn(column);
+ viewer.refresh();
+ }
+ });
+
+ }
+
+ _tableViewer.setContentProvider(new LoggingTableContentProvider());
+ _tableViewer.setLabelProvider(new LoggingTableLabelProvider());
+ _tableViewer.setSorter(tableSorter);
+ _table.setSortColumn(_table.getColumn(0));
+ _table.setSortDirection(SWT.UP);
+ _table.addMouseListener(new MouseListener()
+ {
+ public void mouseDoubleClick(MouseEvent event)
+ {
+ editLoggerLevel(_table.getShell());
+ }
+
+ public void mouseDown(MouseEvent e){}
+ public void mouseUp(MouseEvent e){}
+ });
+
+ final Button logLevelEditButton = _toolkit.createButton(configFileLoggerLevelsGroup, "Edit Selected Logger(s)...", SWT.PUSH);
+ logLevelEditButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+ logLevelEditButton.setEnabled(false);
+ logLevelEditButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ editLoggerLevel(logLevelEditButton.getShell());
+ }
+ });
+
+ _tableViewer.addSelectionChangedListener(new ISelectionChangedListener(){
+ public void selectionChanged(SelectionChangedEvent evt)
+ {
+ int selectionIndex = _table.getSelectionIndex();
+
+ if(selectionIndex != -1)
+ {
+ logLevelEditButton.setEnabled(true);
+ }
+ else
+ {
+ logLevelEditButton.setEnabled(false);
+ }
+ }
+ });
+
+
+ Composite attributesComposite = _toolkit.createComposite(_paramsComposite);
+ gridData = new GridData(SWT.LEFT, SWT.FILL, false, true);
+ attributesComposite.setLayoutData(gridData);
+ gridLayout = new GridLayout(3,false);
+ attributesComposite.setLayout(gridLayout);
+
+ Group configFileRootLoggerLevelGroup = new Group(attributesComposite, SWT.SHADOW_NONE);
+ configFileRootLoggerLevelGroup.setBackground(attributesComposite.getBackground());
+ configFileRootLoggerLevelGroup.setText("Config File RootLogger Level");
+ gridData = new GridData(SWT.LEFT, SWT.TOP, true, false);
+ configFileRootLoggerLevelGroup.setLayoutData(gridData);
+ configFileRootLoggerLevelGroup.setLayout(new GridLayout(2,false));
+
+ _configFileRootLoggerLevelLabel = _toolkit.createLabel(configFileRootLoggerLevelGroup, "-");
+ _configFileRootLoggerLevelLabel.setFont(ApplicationRegistry.getFont(FONT_BOLD));
+ _configFileRootLoggerLevelLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+
+ final Button configFileRootLoggerLevelButton = _toolkit.createButton(configFileRootLoggerLevelGroup, "Edit ...", SWT.PUSH);
+ configFileRootLoggerLevelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, false));
+ configFileRootLoggerLevelButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ editRootLoggerLevel(configFileRootLoggerLevelButton.getShell());
+ }
+ });
+
+
+ Group logWatchIntervalGroup = new Group(attributesComposite, SWT.SHADOW_NONE);
+ logWatchIntervalGroup.setBackground(attributesComposite.getBackground());
+ logWatchIntervalGroup.setText("LogWatch Interval");
+ gridData = new GridData(SWT.LEFT, SWT.FILL, true, false);
+ logWatchIntervalGroup.setLayoutData(gridData);
+ logWatchIntervalGroup.setLayout(new GridLayout());
+
+ _logWatchIntervalLabel = _toolkit.createLabel(logWatchIntervalGroup, "-");
+ _logWatchIntervalLabel.setFont(ApplicationRegistry.getFont(FONT_BOLD));
+ _logWatchIntervalLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, true));
+
+ if(_ApiVersion.greaterThanOrEqualTo(1, 4))
+ {
+ Group reloadConfigFileGroup = new Group(attributesComposite, SWT.SHADOW_NONE);
+ reloadConfigFileGroup.setBackground(attributesComposite.getBackground());
+ reloadConfigFileGroup.setText("Reload Configuration File");
+ gridData = new GridData(SWT.LEFT, SWT.TOP, true, false);
+ reloadConfigFileGroup.setLayoutData(gridData);
+ reloadConfigFileGroup.setLayout(new GridLayout());
+
+ final Button reloadConfigFileButton = _toolkit.createButton(reloadConfigFileGroup, "Reload Config File", SWT.PUSH);
+ reloadConfigFileButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));
+ reloadConfigFileButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ int response = ViewUtility.popupOkCancelConfirmationMessage("Reload",
+ "Reload Logging Configuration File?");
+ if (response == SWT.OK)
+ {
+ try
+ {
+ _lmmb.reloadConfigFile();
+ ViewUtility.operationResultFeedback(null, "Reloaded Logging Configuration File", null);
+
+ }
+ catch (Exception ex)
+ {
+ ViewUtility.operationFailedStatusBarMessage("Error Reloading Logging Configuration File");
+ MBeanUtility.handleException(_mbean, ex);
+ }
+
+ refresh(_mbean);;
+ }
+ }
+ });
+ }
+ }
+
+
+
+ private void editLoggerLevel(Shell parent)
+ {
+ int selectionIndex = _table.getSelectionIndex();
+
+ if (selectionIndex != -1)
+ {
+ int[] selectedIndices = _table.getSelectionIndices();
+
+ final ArrayList<String> selectedLoggers = new ArrayList<String>();
+
+ for(int index = 0; index < selectedIndices.length ; index++)
+ {
+ CompositeData selectedLogger = (CompositeData)_table.getItem(selectedIndices[index]).getData();
+ String user = (String) selectedLogger.get(LOGGER_NAME);
+ selectedLoggers.add(user);
+ }
+
+ final Shell shell = ViewUtility.createModalDialogShell(parent, "Set Config File Logger Level(s)");
+
+ _toolkit.createLabel(shell, "Logger(s): ").setBackground(shell.getBackground());
+
+ final Text headerText = new Text(shell, SWT.WRAP | SWT.V_SCROLL | SWT.BORDER );
+ headerText.setEditable(false);
+ GridData data = new GridData(SWT.FILL, SWT.FILL, false, false);
+ data.minimumHeight = 125;
+ data.heightHint = 125;
+ data.minimumWidth = 575;
+ data.widthHint = 575;
+ headerText.setLayoutData(data);
+
+ String lineSeperator = System.getProperty("line.separator");
+ for(String loggerName : selectedLoggers)
+ {
+ headerText.append(loggerName + lineSeperator);
+ }
+ headerText.setSelection(0);
+
+ Composite levelComp = _toolkit.createComposite(shell);
+ levelComp.setBackground(shell.getBackground());
+ levelComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ levelComp.setLayout(new GridLayout(2,false));
+
+ _toolkit.createLabel(levelComp,"Level: ").setBackground(levelComp.getBackground());
+ final Combo levelCombo = new Combo (levelComp, SWT.READ_ONLY );
+ levelCombo.setItems(_availableLoggerLevels);
+ levelCombo.select(0);
+
+ Composite okCancelButtonsComp = _toolkit.createComposite(shell);
+ okCancelButtonsComp.setBackground(shell.getBackground());
+ okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true));
+ okCancelButtonsComp.setLayout(new GridLayout(2,false));
+
+ Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH);
+ okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+ Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH);
+ cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+
+ okButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ String level = levelCombo.getItem(levelCombo.getSelectionIndex()).toString();
+
+ shell.close();
+
+ try
+ {
+ HashMap<String,Boolean> results = new HashMap<String,Boolean>();
+
+ //perform the updates, save the results.
+ for(String logger : selectedLoggers)
+ {
+ boolean result = _lmmb.setConfigFileLoggerLevel(logger, level);
+ results.put(logger, result);
+ }
+
+ //categorise the overall result
+ boolean overallResult = true;
+ for(boolean result : results.values())
+ {
+ if (!result)
+ {
+ overallResult = false;
+ }
+ }
+
+ //output the result to status bar if all succeed, and dialogue if not
+ if(overallResult)
+ {
+ ViewUtility.operationResultFeedback(overallResult, "Updated ConfigFile Logger Level(s)", null);
+ }
+ else
+ {
+ String failedToSetLevelOfLoggers = "";
+ for(String logger : results.keySet())
+ {
+ if(!results.get(logger))
+ {
+ failedToSetLevelOfLoggers = failedToSetLevelOfLoggers.concat(logger + ", ");
+ }
+ }
+
+ //cut off last ", "
+ int lastIndex = failedToSetLevelOfLoggers.lastIndexOf(',');
+ if (lastIndex != -1)
+ {
+ failedToSetLevelOfLoggers = failedToSetLevelOfLoggers.substring(0, lastIndex);
+ }
+
+ ViewUtility.operationResultFeedback(overallResult, null,
+ "Failed to update ConfigFile Logger Level(s): "
+ + failedToSetLevelOfLoggers);
+ }
+ }
+ catch(Exception e4)
+ {
+ ViewUtility.operationFailedStatusBarMessage("Error updating Config File Logger Level(s)");
+ MBeanUtility.handleException(_mbean, e4);
+ }
+
+ refresh(_mbean);
+ }
+ });
+
+ cancelButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ shell.dispose();
+ }
+ });
+
+ shell.setDefaultButton(okButton);
+ shell.pack();
+ ViewUtility.centerChildInParentShell(parent, shell);
+
+ shell.open();
+ }
+ }
+
+ private void editRootLoggerLevel(Shell parent)
+ {
+ final Shell shell = ViewUtility.createModalDialogShell(parent, "ConfigFile RootLogger Level");
+
+ Composite levelComp = _toolkit.createComposite(shell);
+ levelComp.setBackground(shell.getBackground());
+ levelComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ levelComp.setLayout(new GridLayout(2,false));
+
+ _toolkit.createLabel(levelComp,"RootLogger level: ").setBackground(levelComp.getBackground());
+ final Combo levelCombo = new Combo (levelComp, SWT.READ_ONLY );
+ levelCombo.setItems(_availableLoggerLevels);
+ levelCombo.select(0);
+
+ Composite okCancelButtonsComp = _toolkit.createComposite(shell);
+ okCancelButtonsComp.setBackground(shell.getBackground());
+ okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true));
+ okCancelButtonsComp.setLayout(new GridLayout(2,false));
+
+ Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH);
+ okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+ Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH);
+ cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+
+ okButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ String selection = levelCombo.getItem(levelCombo.getSelectionIndex()).toString();
+ shell.dispose();
+ try
+ {
+ boolean result = _lmmb.setConfigFileRootLoggerLevel(selection);
+ ViewUtility.operationResultFeedback(result,
+ "Updated ConfigFile RootLogger Level", "Failed to update ConfigFile RootLogger Level");
+ }
+ catch (Exception e5)
+ {
+ ViewUtility.operationFailedStatusBarMessage("Error updating ConfigFile RootLogger Level");
+ MBeanUtility.handleException(_mbean, e5);
+ }
+ refresh(_mbean);
+ }
+ });
+
+ cancelButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ shell.dispose();
+ }
+ });
+
+ shell.setDefaultButton(okButton);
+ shell.pack();
+ ViewUtility.centerChildInParentShell(parent, shell);
+
+ shell.open();
+ }
+}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/LoggingTableContentProvider.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/LoggingTableContentProvider.java
new file mode 100644
index 0000000000..6ef3ab70a7
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/LoggingTableContentProvider.java
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui.views.logging;
+
+import java.util.Collection;
+
+import javax.management.openmbean.TabularDataSupport;
+
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+/**
+ * Content Provider class for theLogging Management table viewers
+ */
+public class LoggingTableContentProvider implements IStructuredContentProvider
+{
+
+ public void inputChanged(Viewer v, Object oldInput, Object newInput)
+ {
+
+ }
+
+ public void dispose()
+ {
+
+ }
+
+ public Object[] getElements(Object parent)
+ {
+ Collection<Object> rowCollection = ((TabularDataSupport) parent).values();
+
+ return rowCollection.toArray();
+ }
+} \ No newline at end of file
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/LoggingTableLabelProvider.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/LoggingTableLabelProvider.java
new file mode 100644
index 0000000000..27f6040d7d
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/LoggingTableLabelProvider.java
@@ -0,0 +1,59 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui.views.logging;
+
+import javax.management.openmbean.CompositeDataSupport;
+
+import org.apache.qpid.management.common.mbeans.LoggingManagement;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * Label Provider class for the LoggingManagement table viewers
+ */
+public class LoggingTableLabelProvider extends LabelProvider implements ITableLabelProvider
+{
+ private static final String LOGGER_NAME = LoggingManagement.COMPOSITE_ITEM_NAMES[0];
+ private static final String LOGGER_LEVEL = LoggingManagement.COMPOSITE_ITEM_NAMES[1];
+
+ @Override
+ public String getColumnText(Object element, int columnIndex)
+ {
+ switch (columnIndex)
+ {
+ case 0 : // logger name column
+ return (String) ((CompositeDataSupport) element).get(LOGGER_NAME);
+ case 1 : // logger level column
+ return (String) ((CompositeDataSupport) element).get(LOGGER_LEVEL);
+ default :
+ return "-";
+ }
+ }
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex)
+ {
+ return null;
+ }
+
+
+}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/LoggingTableSorter.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/LoggingTableSorter.java
new file mode 100644
index 0000000000..c1833148d7
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/LoggingTableSorter.java
@@ -0,0 +1,90 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui.views.logging;
+
+import javax.management.openmbean.CompositeData;
+
+import org.apache.qpid.management.common.mbeans.LoggingManagement;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerSorter;
+
+/**
+ * Sorter class for the Logging Management table viewers.
+ */
+public class LoggingTableSorter extends ViewerSorter
+{
+ private static final String LOGGER_NAME = LoggingManagement.COMPOSITE_ITEM_NAMES[0];
+ private static final String LOGGER_LEVEL = LoggingManagement.COMPOSITE_ITEM_NAMES[1];
+ private static final int ASCENDING = 0;
+ private static final int DESCENDING = 1;
+
+ private int column;
+ private int direction;
+
+ public LoggingTableSorter()
+ {
+ this.column = 0;
+ direction = ASCENDING;
+ }
+
+ public void setColumn(int column)
+ {
+ if (column == this.column)
+ {
+ // Same column as last sort; toggle the direction
+ direction = 1 - direction;
+ }
+ else
+ {
+ // New column; do an ascending sort
+ this.column = column;
+ direction = ASCENDING;
+ }
+ }
+
+ @Override
+ public int compare(Viewer viewer, Object e1, Object e2)
+ {
+ CompositeData logger1 = (CompositeData) e1;
+ CompositeData logger2 = (CompositeData) e2;
+
+ int comparison = 0;
+ switch(column)
+ {
+ case 0:
+ comparison = String.valueOf(logger1.get(LOGGER_NAME)).compareTo(
+ String.valueOf(logger2.get(LOGGER_NAME)));
+ break;
+ case 1:
+ comparison = String.valueOf(logger1.get(LOGGER_LEVEL)).compareTo(
+ String.valueOf(logger2.get(LOGGER_LEVEL)));
+ break;
+ default:
+ comparison = 0;
+ }
+ // If descending order, flip the direction
+ if (direction == DESCENDING)
+ {
+ comparison = -comparison;
+ }
+ return comparison;
+ }
+}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/RuntimeTabControl.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/RuntimeTabControl.java
new file mode 100644
index 0000000000..9834cd729a
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/RuntimeTabControl.java
@@ -0,0 +1,595 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui.views.logging;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.TabularDataSupport;
+
+import static org.apache.qpid.management.ui.Constants.FONT_BOLD;
+
+import org.apache.qpid.management.ui.ApplicationRegistry;
+import org.apache.qpid.management.ui.ManagedBean;
+import org.apache.qpid.management.common.mbeans.LoggingManagement;
+import org.apache.qpid.management.ui.jmx.JMXManagedObject;
+import org.apache.qpid.management.ui.jmx.MBeanUtility;
+import org.apache.qpid.management.ui.views.TabControl;
+import org.apache.qpid.management.ui.views.ViewUtility;
+import org.eclipse.jface.viewers.IColorProvider;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+
+
+/**
+ * Control class for the LoggingManagement mbean Runtime Options tab.
+ */
+public class RuntimeTabControl extends TabControl
+{
+ private FormToolkit _toolkit;
+ private ScrolledForm _form;
+ private Table _table = null;
+ private TableViewer _tableViewer = null;
+ private Composite _headerComposite = null;
+ private Composite _paramsComposite = null;
+
+ private Label _runtimeRootLoggerLevelLabel = null;
+ private String[] _availableLoggerLevels;
+ private TabularDataSupport _runtimeLoggerLevels = null;
+ private ArrayList<String> _configFileLoggerNames = new ArrayList<String>();
+ private LoggingManagement _lmmb;
+
+ private static final String LOGGER_NAME = LoggingManagement.COMPOSITE_ITEM_NAMES[0];
+ private static final String LOGGER_LEVEL = LoggingManagement.COMPOSITE_ITEM_NAMES[1];
+
+ public RuntimeTabControl(TabFolder tabFolder, JMXManagedObject mbean, MBeanServerConnection mbsc)
+ {
+ super(tabFolder);
+ _mbean = mbean;
+ _lmmb = (LoggingManagement)
+ MBeanServerInvocationHandler.newProxyInstance(mbsc, mbean.getObjectName(),
+ LoggingManagement.class, false);
+ _toolkit = new FormToolkit(_tabFolder.getDisplay());
+ _form = _toolkit.createScrolledForm(_tabFolder);
+ _form.getBody().setLayout(new GridLayout());
+ createComposites();
+ createWidgets();
+ }
+
+ private void createComposites()
+ {
+
+ _headerComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE);
+ _headerComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ _headerComposite.setLayout(new GridLayout());
+
+ _paramsComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE);
+ _paramsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ _paramsComposite.setLayout(new GridLayout());
+ }
+
+ /**
+ * @see TabControl#getControl()
+ */
+ public Control getControl()
+ {
+ return _form;
+ }
+
+ /**
+ * @see TabControl#setFocus()
+ */
+ public void setFocus()
+ {
+ _table.setFocus();
+ }
+
+ @Override
+ public void refresh(ManagedBean mbean)
+ {
+ String runtimeRootLoggerLevel = "-";
+ try
+ {
+ runtimeRootLoggerLevel = _lmmb.getRuntimeRootLoggerLevel();
+ }
+ catch(Exception e1)
+ {
+ MBeanUtility.handleException(_mbean, e1);
+ }
+
+ _runtimeLoggerLevels = null;
+ try
+ {
+ _runtimeLoggerLevels = (TabularDataSupport) _lmmb.viewEffectiveRuntimeLoggerLevels();
+ }
+ catch(Exception e2)
+ {
+ MBeanUtility.handleException(_mbean, e2);
+ }
+
+
+ try
+ {
+ TabularDataSupport confLoggers = (TabularDataSupport) _lmmb.viewConfigFileLoggerLevels();
+ ArrayList<String> confLoggerNames = new ArrayList<String>();
+
+ for(Object obj : confLoggers.values())
+ {
+ CompositeData comp = (CompositeData) obj;
+ confLoggerNames.add((String) comp.get(LOGGER_NAME));
+ }
+
+ _configFileLoggerNames = confLoggerNames;
+ }
+ catch(Exception e2)
+ {
+ //dont signal the failure, just dont highlight the config file loggers, empty the existing list.
+ _configFileLoggerNames.clear();
+ }
+
+ _runtimeRootLoggerLevelLabel.setText(String.valueOf(runtimeRootLoggerLevel));
+ _tableViewer.setInput(_runtimeLoggerLevels);
+
+ layout();
+ }
+
+ public void layout()
+ {
+ _form.layout(true);
+ _form.getBody().layout(true, true);
+ }
+
+ private void createWidgets()
+ {
+ try
+ {
+ _availableLoggerLevels = _lmmb.getAvailableLoggerLevels();
+ }
+ catch(Exception e)
+ {
+ _availableLoggerLevels = new String[]{"ALL","TRACE","DEBUG","INFO","WARN","ERROR","FATAL","OFF"};
+ }
+
+ Label noteLabel = _toolkit.createLabel(_headerComposite,
+ "NOTE: These options modify only the live runtime settings. " +
+ "Non-default values will be lost following broker restart.");
+ Label noteLabel2 = _toolkit.createLabel(_headerComposite,
+ "Loggers currently defined in the configuration file are " +
+ "highlighted. The other Loggers inherit a Level by default.");
+ GridData gridData = new GridData(SWT.FILL, SWT.FILL, false, true);
+ noteLabel.setLayoutData(gridData);
+ gridData = new GridData(SWT.FILL, SWT.FILL, false, true);
+ noteLabel2.setLayoutData(gridData);
+
+ Group effectiveRuntimeLoggerLevelsGroup = new Group(_paramsComposite, SWT.SHADOW_NONE);
+ effectiveRuntimeLoggerLevelsGroup.setBackground(_paramsComposite.getBackground());
+ effectiveRuntimeLoggerLevelsGroup.setText("Effective Runtime Logger Levels");
+ effectiveRuntimeLoggerLevelsGroup.setLayout(new GridLayout());
+ gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ effectiveRuntimeLoggerLevelsGroup.setLayoutData(gridData);
+
+ Composite tableComposite = _toolkit.createComposite(effectiveRuntimeLoggerLevelsGroup);
+ gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gridData.heightHint = 250;
+ gridData.minimumHeight = 250;
+ tableComposite.setLayoutData(gridData);
+ GridLayout gridLayout = new GridLayout();
+ tableComposite.setLayout(gridLayout);
+
+ _table = new Table (tableComposite, SWT.MULTI | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION);
+ _table.setLinesVisible (true);
+ _table.setHeaderVisible (true);
+ GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ _table.setLayoutData(data);
+
+ _tableViewer = new TableViewer(_table);
+ final LoggingTableSorter tableSorter = new LoggingTableSorter();
+
+ String[] titles = { LOGGER_NAME, LOGGER_LEVEL };
+ int[] bounds = { 600, 75 };
+ for (int i = 0; i < titles.length; i++)
+ {
+ final int index = i;
+ final TableViewerColumn viewerColumn = new TableViewerColumn(_tableViewer, SWT.NONE);
+ final TableColumn column = viewerColumn.getColumn();
+
+ column.setText(titles[i]);
+ column.setWidth(bounds[i]);
+ column.setResizable(true);
+
+ //Setting the right sorter
+ column.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ tableSorter.setColumn(index);
+ final TableViewer viewer = _tableViewer;
+ int dir = viewer.getTable().getSortDirection();
+ if (viewer.getTable().getSortColumn() == column)
+ {
+ dir = (dir == SWT.UP ? SWT.DOWN : SWT.UP);
+ }
+ else
+ {
+ dir = SWT.UP;
+ }
+ viewer.getTable().setSortDirection(dir);
+ viewer.getTable().setSortColumn(column);
+ viewer.refresh();
+ }
+ });
+
+ }
+
+ _tableViewer.setContentProvider(new LoggingTableContentProvider());
+ _tableViewer.setLabelProvider(new RuntimeLoggingTableLabelProvider());
+ _tableViewer.setSorter(tableSorter);
+ _table.setSortColumn(_table.getColumn(0));
+ _table.setSortDirection(SWT.UP);
+ _table.addMouseListener(new MouseListener()
+ {
+ public void mouseDoubleClick(MouseEvent event)
+ {
+ editLoggerLevel(_table.getShell());
+ }
+
+ public void mouseDown(MouseEvent e){}
+ public void mouseUp(MouseEvent e){}
+ });
+
+ final Button logLevelEditButton = _toolkit.createButton(effectiveRuntimeLoggerLevelsGroup, "Edit Selected Logger(s)...", SWT.PUSH);
+ logLevelEditButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+ logLevelEditButton.setEnabled(false);
+ logLevelEditButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ editLoggerLevel(logLevelEditButton.getShell());
+ }
+ });
+
+ _tableViewer.addSelectionChangedListener(new ISelectionChangedListener(){
+ public void selectionChanged(SelectionChangedEvent evt)
+ {
+ int selectionIndex = _table.getSelectionIndex();
+
+ if (selectionIndex != -1)
+ {
+ logLevelEditButton.setEnabled(true);
+ }
+ else
+ {
+ logLevelEditButton.setEnabled(false);
+ }
+ }
+ });
+
+ Composite attributesComposite = _toolkit.createComposite(_paramsComposite);
+ gridData = new GridData(SWT.FILL, SWT.FILL, false, true);
+ attributesComposite.setLayoutData(gridData);
+ gridLayout = new GridLayout(3,false);
+ attributesComposite.setLayout(gridLayout);
+
+ Group runtimeRootLoggerGroup = new Group(attributesComposite, SWT.SHADOW_NONE);
+ runtimeRootLoggerGroup.setBackground(attributesComposite.getBackground());
+ runtimeRootLoggerGroup.setText("Runtime RootLogger Level");
+ gridData = new GridData(SWT.LEFT, SWT.TOP, true, false);
+ runtimeRootLoggerGroup.setLayoutData(gridData);
+ runtimeRootLoggerGroup.setLayout(new GridLayout(2,false));
+
+ _runtimeRootLoggerLevelLabel = _toolkit.createLabel(runtimeRootLoggerGroup, "-");
+ _runtimeRootLoggerLevelLabel.setFont(ApplicationRegistry.getFont(FONT_BOLD));
+ _runtimeRootLoggerLevelLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+
+ final Button runtimeRootLoggerLevelButton = _toolkit.createButton(runtimeRootLoggerGroup, "Edit ...", SWT.PUSH);
+ runtimeRootLoggerLevelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, false));
+ runtimeRootLoggerLevelButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ editRootLoggerLevel(runtimeRootLoggerLevelButton.getShell());
+ }
+ });
+ }
+
+ private void editLoggerLevel(Shell parent)
+ {
+ int selectionIndex = _table.getSelectionIndex();
+
+ if (selectionIndex != -1)
+ {
+ int[] selectedIndices = _table.getSelectionIndices();
+
+ final ArrayList<String> selectedLoggers = new ArrayList<String>();
+
+ for(int index = 0; index < selectedIndices.length ; index++)
+ {
+ CompositeData selectedLogger = (CompositeData)_table.getItem(selectedIndices[index]).getData();
+ String user = (String) selectedLogger.get(LOGGER_NAME);
+ selectedLoggers.add(user);
+ }
+
+ final Shell shell = ViewUtility.createModalDialogShell(parent, "Set Runtime Logger Level(s)");
+
+ _toolkit.createLabel(shell, "Logger(s): ").setBackground(shell.getBackground());
+
+ final Text headerText = new Text(shell, SWT.WRAP | SWT.V_SCROLL | SWT.BORDER );
+ headerText.setEditable(false);
+ GridData data = new GridData(SWT.FILL, SWT.FILL, false, false);
+ data.minimumHeight = 125;
+ data.heightHint = 125;
+ data.minimumWidth = 575;
+ data.widthHint = 575;
+ headerText.setLayoutData(data);
+
+ String lineSeperator = System.getProperty("line.separator");
+ for(String loggerName : selectedLoggers)
+ {
+ headerText.append(loggerName + lineSeperator);
+ }
+ headerText.setSelection(0);
+
+ Composite levelComp = _toolkit.createComposite(shell);
+ levelComp.setBackground(shell.getBackground());
+ levelComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ levelComp.setLayout(new GridLayout(2,false));
+
+ _toolkit.createLabel(levelComp,"Level: ").setBackground(levelComp.getBackground());
+ final Combo levelCombo = new Combo (levelComp, SWT.READ_ONLY );
+ levelCombo.setItems(_availableLoggerLevels);
+ levelCombo.select(0);
+
+ Composite okCancelButtonsComp = _toolkit.createComposite(shell);
+ okCancelButtonsComp.setBackground(shell.getBackground());
+ okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true));
+ okCancelButtonsComp.setLayout(new GridLayout(2,false));
+
+ Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH);
+ okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+ Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH);
+ cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+
+ okButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ String level = levelCombo.getItem(levelCombo.getSelectionIndex()).toString();
+
+ shell.close();
+
+ try
+ {
+ HashMap<String,Boolean> results = new HashMap<String,Boolean>();
+
+ //perform the updates, save the results.
+ for(String logger : selectedLoggers)
+ {
+ boolean result = _lmmb.setRuntimeLoggerLevel(logger, level);
+ results.put(logger, result);
+ }
+
+ //categorise the overall result
+ boolean overallResult = true;
+ for(boolean result : results.values())
+ {
+ if (!result)
+ {
+ overallResult = false;
+ }
+ }
+
+ //output the result to status bar if all succeed, and dialogue if not
+ if(overallResult)
+ {
+ ViewUtility.operationResultFeedback(overallResult, "Updated Runtime Logger Level(s)", null);
+ }
+ else
+ {
+ String failedToSetLevelOfLoggers = "";
+ for(String logger : results.keySet())
+ {
+ if(!results.get(logger))
+ {
+ failedToSetLevelOfLoggers = failedToSetLevelOfLoggers.concat(logger + ", ");
+ }
+ }
+
+ //cut off last ", "
+ int lastIndex = failedToSetLevelOfLoggers.lastIndexOf(',');
+ if (lastIndex != -1)
+ {
+ failedToSetLevelOfLoggers = failedToSetLevelOfLoggers.substring(0, lastIndex);
+ }
+
+ ViewUtility.operationResultFeedback(overallResult, null,
+ "Failed to update Runtime Logger Level(s): "
+ + failedToSetLevelOfLoggers);
+ }
+ }
+ catch(Exception e3)
+ {
+ ViewUtility.operationFailedStatusBarMessage("Error updating Runtime Logger Level(s)");
+ MBeanUtility.handleException(_mbean, e3);
+ }
+
+ refresh(_mbean);
+ }
+ });
+
+ cancelButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ shell.dispose();
+ }
+ });
+
+ shell.setDefaultButton(okButton);
+ shell.pack();
+ ViewUtility.centerChildInParentShell(parent, shell);
+
+ shell.open();
+ }
+ }
+
+ private void editRootLoggerLevel(Shell parent)
+ {
+ final Shell shell = ViewUtility.createModalDialogShell(parent, "Runtime RootLogger Level");
+
+ Composite levelComp = _toolkit.createComposite(shell);
+ levelComp.setBackground(shell.getBackground());
+ levelComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ levelComp.setLayout(new GridLayout(2,false));
+
+ _toolkit.createLabel(levelComp,"RootLogger level: ").setBackground(levelComp.getBackground());
+ final Combo levelCombo = new Combo (levelComp, SWT.READ_ONLY );
+ levelCombo.setItems(_availableLoggerLevels);
+ levelCombo.select(0);
+
+ Composite okCancelButtonsComp = _toolkit.createComposite(shell);
+ okCancelButtonsComp.setBackground(shell.getBackground());
+ okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true));
+ okCancelButtonsComp.setLayout(new GridLayout(2,false));
+
+ Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH);
+ okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+ Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH);
+ cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+
+ okButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ String selection = levelCombo.getItem(levelCombo.getSelectionIndex()).toString();
+ shell.dispose();
+
+ try
+ {
+ boolean result = _lmmb.setRuntimeRootLoggerLevel(selection);
+ ViewUtility.operationResultFeedback(result,
+ "Updated Runtime RootLogger Level", "Failed to update Runtime Logger Level");
+ }
+ catch(Exception e4)
+ {
+ ViewUtility.operationFailedStatusBarMessage("Error updating Runtime Logger Level");
+ MBeanUtility.handleException(_mbean, e4);
+ }
+
+ refresh(_mbean);
+ }
+ });
+
+ cancelButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ shell.dispose();
+ }
+ });
+
+ shell.setDefaultButton(okButton);
+ shell.pack();
+ ViewUtility.centerChildInParentShell(parent, shell);
+
+ shell.open();
+ }
+
+ /**
+ * Label Provider class for the RuntimeLoggers table viewer
+ */
+ public class RuntimeLoggingTableLabelProvider extends LabelProvider implements ITableLabelProvider, IColorProvider
+ {
+
+ @Override
+ public String getColumnText(Object element, int columnIndex)
+ {
+ switch (columnIndex)
+ {
+ case 0 : // logger name column
+ return (String) ((CompositeDataSupport) element).get(LOGGER_NAME);
+ case 1 : // logger level column
+ return (String) ((CompositeDataSupport) element).get(LOGGER_LEVEL);
+ default :
+ return "-";
+ }
+ }
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex)
+ {
+ return null;
+ }
+
+ @Override
+ public Color getBackground(Object element)
+ {
+ return null;
+ }
+
+ @Override
+ public Color getForeground(Object element)
+ {
+ String loggerName = (String) ((CompositeData) element).get(LOGGER_NAME);
+ if(_configFileLoggerNames.contains(loggerName))
+ {
+ return Display.getCurrent().getSystemColor(SWT.COLOR_BLUE);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+
+ }
+}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/queue/QueueOperationsTabControl.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/queue/QueueOperationsTabControl.java
new file mode 100644
index 0000000000..309b84f52b
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/queue/QueueOperationsTabControl.java
@@ -0,0 +1,1114 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui.views.queue;
+
+import static org.apache.qpid.management.ui.Constants.CONSOLE_IMAGE;
+import static org.apache.qpid.management.ui.Constants.RESULT;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.TabularDataSupport;
+
+import org.apache.qpid.management.ui.ApiVersion;
+import org.apache.qpid.management.ui.ApplicationRegistry;
+import org.apache.qpid.management.ui.ManagedBean;
+import org.apache.qpid.management.common.mbeans.ManagedQueue;
+import org.apache.qpid.management.ui.jmx.JMXManagedObject;
+import org.apache.qpid.management.ui.jmx.MBeanUtility;
+import org.apache.qpid.management.ui.views.NumberVerifyListener;
+import org.apache.qpid.management.ui.views.TabControl;
+import org.apache.qpid.management.ui.views.ViewUtility;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+
+
+/**
+ * Control class for the Queue mbean Operations tab.
+ */
+public class QueueOperationsTabControl extends TabControl
+{
+ private FormToolkit _toolkit;
+ private ScrolledForm _form;
+ private Table _table = null;
+ private TableViewer _tableViewer = null;
+ private Composite _paramsComposite = null;
+
+ private ApiVersion _ApiVersion;
+
+ private Text _fromMsgText;
+ private Text _toMsgText;
+ private static final String FROM_DEFAULT = "1";
+ private static final String TO_DEFAULT = "50";
+ private long _interval = 50; //(to-from)+1
+ private Long _fromMsg = new Long(FROM_DEFAULT);
+ private Long _toMsg = new Long(TO_DEFAULT);
+
+ private TabularDataSupport _messages = null;
+ private ManagedQueue _qmb;
+
+ private Button _previousButton;
+ private Button _nextButton;
+
+ private static final String MSG_AMQ_ID = ManagedQueue.VIEW_MSGS_COMPOSITE_ITEM_NAMES[0];
+ private static final String MSG_HEADER = ManagedQueue.VIEW_MSGS_COMPOSITE_ITEM_NAMES[1];
+ private static final String MSG_SIZE = ManagedQueue.VIEW_MSGS_COMPOSITE_ITEM_NAMES[2];
+ private static final String MSG_REDELIVERED = ManagedQueue.VIEW_MSGS_COMPOSITE_ITEM_NAMES[3];
+ private static final String MSG_QUEUE_POS = ManagedQueue.VIEW_MSGS_COMPOSITE_ITEM_NAMES[4];
+
+ public QueueOperationsTabControl(TabFolder tabFolder, JMXManagedObject mbean, MBeanServerConnection mbsc)
+ {
+ super(tabFolder);
+ _mbean = mbean;
+ _ApiVersion = ApplicationRegistry.getServerRegistry(mbean).getManagementApiVersion();
+ _qmb = (ManagedQueue) MBeanServerInvocationHandler.newProxyInstance(mbsc,
+ mbean.getObjectName(), ManagedQueue.class, false);
+ _toolkit = new FormToolkit(_tabFolder.getDisplay());
+ _form = _toolkit.createScrolledForm(_tabFolder);
+ _form.getBody().setLayout(new GridLayout());
+ createComposites();
+ createWidgets();
+ }
+
+ private void createComposites()
+ {
+ _paramsComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE);
+ _paramsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ _paramsComposite.setLayout(new GridLayout());
+ }
+
+ /**
+ * @see TabControl#getControl()
+ */
+ public Control getControl()
+ {
+ return _form;
+ }
+
+ /**
+ * @see TabControl#setFocus()
+ */
+ public void setFocus()
+ {
+ _table.setFocus();
+ }
+
+ @Override
+ public void refresh(ManagedBean mbean)
+ {
+ _messages = null;
+ try
+ {
+ if(_ApiVersion.greaterThanOrEqualTo(1, 3))
+ { //broker supports Qpid JMX API 1.3 and takes Long values
+
+ //gather a list of all messages on the queue for display and selection
+ _messages = (TabularDataSupport) _qmb.viewMessages(_fromMsg,_toMsg);
+ }
+ else
+ { //broker supports Qpid JMX API 1.2 or below and takes int values
+
+ if(_toMsg > Integer.MAX_VALUE || _toMsg > Integer.MAX_VALUE)
+ {
+ ViewUtility.popupErrorMessage("Error", "This broker only supports viewing up to message " + Integer.MAX_VALUE);
+ _tableViewer.setInput(null);
+ return;
+ }
+
+ //gather a list of all messages on the queue for display and selection
+ _messages = (TabularDataSupport) _qmb.viewMessages(_fromMsg.intValue(), _toMsg.intValue());
+ }
+ }
+ catch (Exception e)
+ {
+ MBeanUtility.handleException(mbean,e);
+ }
+
+ _tableViewer.setInput(_messages);
+
+ layout();
+ }
+
+ public void layout()
+ {
+ _form.layout(true);
+ _form.getBody().layout(true, true);
+ }
+
+ private void createWidgets()
+ {
+ Group messagesGroup = new Group(_paramsComposite, SWT.SHADOW_NONE | SWT.SCROLL_LINE);
+ messagesGroup.setBackground(_paramsComposite.getBackground());
+ messagesGroup.setText("Messages");
+ messagesGroup.setLayout(new GridLayout());
+ GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ messagesGroup.setLayoutData(gridData);
+
+ //from and to fields for selecting the viewing range
+ Composite viewMessageRangeComposite = _toolkit.createComposite(messagesGroup);
+ gridData = new GridData(SWT.LEFT, SWT.FILL, false, false);
+ viewMessageRangeComposite.setLayoutData(gridData);
+ viewMessageRangeComposite.setLayout(new GridLayout(8,false));
+
+ _toolkit.createLabel(viewMessageRangeComposite, "Queue pos: ");
+ _fromMsgText = new Text(viewMessageRangeComposite, SWT.BORDER);
+ _fromMsgText.setText(FROM_DEFAULT);
+ gridData = new GridData(SWT.LEFT, SWT.FILL, false, false);
+ gridData.widthHint = 75;
+ _fromMsgText.setLayoutData(gridData);
+ _fromMsgText.addVerifyListener(new NumberVerifyListener());
+ _fromMsgText.addKeyListener(new KeyAdapter()
+ {
+ public void keyPressed(KeyEvent event)
+ {
+ if (event.character == SWT.CR)
+ {
+ updateMessageInterval();
+ }
+ }
+ });
+
+ _toolkit.createLabel(viewMessageRangeComposite, "to");
+
+ _toMsgText = new Text(viewMessageRangeComposite, SWT.BORDER);
+ _toMsgText.setText(TO_DEFAULT);
+ gridData = new GridData(SWT.LEFT, SWT.FILL, false, false);
+ gridData.widthHint = 75;
+ _toMsgText.setLayoutData(gridData);
+ _toMsgText.addVerifyListener(new NumberVerifyListener());
+ _toMsgText.addKeyListener(new KeyAdapter()
+ {
+ public void keyPressed(KeyEvent event)
+ {
+ if (event.character == SWT.CR)
+ {
+ updateMessageInterval();
+ }
+ }
+ });
+
+ final Button setButton = _toolkit.createButton(viewMessageRangeComposite, "Set", SWT.PUSH);
+ setButton.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, false));
+ setButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ updateMessageInterval();
+ }
+ });
+
+ _toolkit.createLabel(viewMessageRangeComposite, " "); //spacer
+
+ _previousButton = _toolkit.createButton(viewMessageRangeComposite, "< Prev " + _interval, SWT.PUSH);
+ _previousButton.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, false));
+ _previousButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ //make 'to' be 'from - 1' unless from is 1 (ie there are no previous messages)
+ if(_fromMsg > 1)
+ {
+ _toMsg = _fromMsg - 1;
+ _toMsgText.setText(_toMsg.toString());
+ }
+
+ //make 'from' be 'from - INTERVAL', or make it 1 if that would make it 0 or less
+ _fromMsg = (_fromMsg - _interval < 1) ? 1 : _fromMsg - _interval;
+ _fromMsgText.setText(_fromMsg.toString());
+
+ refresh(_mbean);
+ }
+ });
+
+ _nextButton = _toolkit.createButton(viewMessageRangeComposite, "Next " + _interval + " >", SWT.PUSH);
+ _nextButton.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, false));
+ _nextButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ //make 'from' be 'to + 1' unless 'to' is already Long.MAX_VALUE
+ if(_toMsg != Long.MAX_VALUE)
+ {
+ _fromMsg = _toMsg + 1;
+ _fromMsgText.setText(_fromMsg.toString());
+ }
+
+ //make 'to' be 'to + INTERVAL', or make it Long.MAX_VALUE if that would too large
+ _toMsg = (Long.MAX_VALUE - _toMsg > _interval) ? _toMsg + _interval : Long.MAX_VALUE;
+ _toMsgText.setText(_toMsg.toString());
+
+ refresh(_mbean);
+ }
+ });
+
+ //message table
+ Composite tableAndButtonsComposite = _toolkit.createComposite(messagesGroup);
+ gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gridData.minimumHeight = 180;
+ gridData.heightHint = 180;
+ tableAndButtonsComposite.setLayoutData(gridData);
+ tableAndButtonsComposite.setLayout(new GridLayout(2,false));
+
+ _table = new Table (tableAndButtonsComposite, SWT.MULTI | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION);
+ _table.setLinesVisible (true);
+ _table.setHeaderVisible (true);
+ GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ _table.setLayoutData(data);
+
+ _tableViewer = new TableViewer(_table);
+ final TableSorter tableSorter = new TableSorter();
+
+ String[] titles = {"AMQ ID", "Size(bytes)"};
+ if(_ApiVersion.greaterThanOrEqualTo(1, 3))
+ {
+ //if server management API is >= 1.3, show message's queue position
+ titles = new String[]{"AMQ ID", "Size(bytes)", "Queue Position"};
+ }
+
+ int[] bounds = { 175, 175, 140 };
+ for (int i = 0; i < titles.length; i++)
+ {
+ final int index = i;
+ final TableColumn column = new TableColumn (_table, SWT.NONE);
+
+ column.setText(titles[i]);
+ column.setWidth(bounds[i]);
+ column.setResizable(true);
+
+ //Setting the right sorter
+ column.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ tableSorter.setColumn(index);
+ final TableViewer viewer = _tableViewer;
+ int dir = viewer .getTable().getSortDirection();
+ if (viewer.getTable().getSortColumn() == column)
+ {
+ dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
+ }
+ else
+ {
+ dir = SWT.UP;
+ }
+ viewer.getTable().setSortDirection(dir);
+ viewer.getTable().setSortColumn(column);
+ viewer.refresh();
+ }
+ });
+
+ }
+
+ _tableViewer.setContentProvider(new ContentProviderImpl());
+ _tableViewer.setLabelProvider(new LabelProviderImpl());
+ _tableViewer.setSorter(tableSorter);
+ _table.setSortColumn(_table.getColumn(0));
+ _table.setSortDirection(SWT.UP);
+
+ //Side Buttons
+ Composite buttonsComposite = _toolkit.createComposite(tableAndButtonsComposite);
+ gridData = new GridData(SWT.FILL, SWT.FILL, false, true);
+ buttonsComposite.setLayoutData(gridData);
+ buttonsComposite.setLayout(new GridLayout());
+
+ final Button viewSelectedMsgButton = _toolkit.createButton(buttonsComposite, "View Message Content ...", SWT.PUSH);
+ viewSelectedMsgButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+ viewSelectedMsgButton.setEnabled(false);
+ viewSelectedMsgButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ if (_table.getSelectionIndex() == -1)
+ {
+ return;
+ }
+
+ viewMessageContent();
+ }
+ });
+
+ if(_ApiVersion.lessThan(1, 3)) //if the server predates Qpid JMX API 1.3
+ {
+ final Button deleteFirstMessageButton = _toolkit.createButton(buttonsComposite, "Delete 1st Unacquired Msg", SWT.PUSH);
+ deleteFirstMessageButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+ deleteFirstMessageButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent se)
+ {
+ int response = ViewUtility.popupOkCancelConfirmationMessage("Delete 1st unacquired message",
+ "Delete 1st unacquired message on the queue?\n\n"
+ + "NOTE: Any ongoing consumer activity may mean this is "
+ + "not the first message listed in the table.");
+ if (response == SWT.OK)
+ {
+ try
+ {
+ _qmb.deleteMessageFromTop();
+ ViewUtility.operationResultFeedback(null, "Deleted 1st unacquired message on the queue", null);
+ }
+ catch (Exception e)
+ {
+ ViewUtility.operationFailedStatusBarMessage("Error deleting 1st unacquired message on queue");
+ MBeanUtility.handleException(_mbean, e);
+ }
+
+ refresh(_mbean);;
+ }
+ }
+ });
+ }
+
+ final Button moveMessagesButton;
+ if(_ApiVersion.greaterThanOrEqualTo(1, 3))
+ {
+ //If the server supports Qpid JMX API 1.3, show the move message button.
+ //This is being disabled for earlier brokers due to bugs affecting the result appearance
+ //and impacting on the ability of the source queues to deliver further messages.
+
+ moveMessagesButton = _toolkit.createButton(buttonsComposite, "Move Message(s) ...", SWT.PUSH);
+
+ moveMessagesButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+ moveMessagesButton.setEnabled(false);
+ moveMessagesButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ if (_table.getSelectionIndex() == -1)
+ {
+ return;
+ }
+
+ moveOrCopyMessages(moveMessagesButton.getShell(), QueueOperations.MOVE);
+ }
+ });
+ }
+ else
+ {
+ moveMessagesButton = null;
+ }
+
+ final Button copyMessagesButton;
+ if(_ApiVersion.greaterThanOrEqualTo(1, 3))//if the server supports Qpid JMX API 1.3
+ {
+ copyMessagesButton= _toolkit.createButton(buttonsComposite, "Copy Message(s) ...", SWT.PUSH);
+ copyMessagesButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+ copyMessagesButton.setEnabled(false);
+ copyMessagesButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ if (_table.getSelectionIndex() == -1)
+ {
+ return;
+ }
+
+ moveOrCopyMessages(copyMessagesButton.getShell(), QueueOperations.COPY);
+ }
+ });
+ }
+ else
+ {
+ copyMessagesButton = null;
+ }
+
+ final Button deleteMessagesButton;
+ if(_ApiVersion.greaterThanOrEqualTo(1, 3))//if the server supports Qpid JMX API 1.3
+ {
+ deleteMessagesButton = _toolkit.createButton(buttonsComposite, "Delete Message(s) ...", SWT.PUSH);
+ deleteMessagesButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+ deleteMessagesButton.setEnabled(false);
+ deleteMessagesButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ if (_table.getSelectionIndex() == -1)
+ {
+ return;
+ }
+
+ deleteMessages(deleteMessagesButton.getShell());
+ }
+ });
+ }
+ else
+ {
+ deleteMessagesButton = null;
+ }
+
+ final Button clearQueueButton = _toolkit.createButton(buttonsComposite, "Clear Queue", SWT.PUSH);
+ clearQueueButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+ clearQueueButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ int response = ViewUtility.popupOkCancelConfirmationMessage("Clear Queue",
+ "Clear queue ?");
+ if (response == SWT.OK)
+ {
+ try
+ {
+ if(_ApiVersion.greaterThanOrEqualTo(1, 3))
+ {
+ //Qpid JMX API 1.3+, returns the number of messages deleted
+ Long numDeleted = _qmb.clearQueue();
+ String message = "Queue cleared of " + numDeleted +
+ " non-acquired message" + (numDeleted == 1 ? "": "s");
+
+ ViewUtility.operationResultFeedback(null, message, null);
+ }
+ else
+ {
+ //Qpid JMX API 1.2 or below, void return
+ _qmb.clearQueue();
+ ViewUtility.operationResultFeedback(null, "Queue cleared of non-acquired messages", null);
+ }
+ }
+ catch (Exception e2)
+ {
+ ViewUtility.operationFailedStatusBarMessage("Error clearing Queue");
+ MBeanUtility.handleException(_mbean, e2);
+ }
+
+ refresh(_mbean);;
+ }
+ }
+ });
+
+ _toolkit.createLabel(messagesGroup, "Message Header: ");
+
+ //Redelivered status and header
+ Composite headerEtcComposite = _toolkit.createComposite(messagesGroup);
+ gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
+ headerEtcComposite.setLayoutData(gridData);
+ headerEtcComposite.setLayout(new GridLayout());
+
+ final Text headerText = new Text(headerEtcComposite, SWT.WRAP | SWT.BORDER | SWT.V_SCROLL);
+ headerText.setText("Select a message to view its header.");
+ headerText.setEditable(false);
+ data = new GridData(SWT.LEFT, SWT.TOP, false, false);
+ data.minimumHeight = 210;
+ data.heightHint = 210;
+ data.minimumWidth = 500;
+ data.widthHint = 500;
+ headerText.setLayoutData(data);
+
+ Composite redeliveryComposite = _toolkit.createComposite(headerEtcComposite);
+ redeliveryComposite.setLayout(new GridLayout(2,false));
+ data = new GridData(SWT.LEFT, SWT.FILL, false, false);
+ data.minimumWidth = 150;
+ data.widthHint = 150;
+ redeliveryComposite.setLayoutData(data);
+
+ _toolkit.createLabel(redeliveryComposite, "Redelivered: ");
+ final Text redeliveredText = new Text(redeliveryComposite, SWT.BORDER);
+ redeliveredText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ redeliveredText.setText("-");
+ redeliveredText.setEditable(false);
+
+ //listener for double clicking to view message content
+ _table.addMouseListener(new MouseListener()
+ {
+ // MouseListener implementation
+ public void mouseDoubleClick(MouseEvent event)
+ {
+ viewMessageContent();
+ }
+
+ public void mouseDown(MouseEvent e){}
+ public void mouseUp(MouseEvent e){}
+ });
+
+ //selection listener to enable and disable buttons, update header and redelivered info
+ _tableViewer.addSelectionChangedListener(new ISelectionChangedListener(){
+ public void selectionChanged(SelectionChangedEvent evt)
+ {
+ int selectionIndex = _table.getSelectionIndex();
+
+ if (selectionIndex == -1)
+ {
+ headerText.setText("Select a message to view its header.");
+ redeliveredText.setText("-");
+ viewSelectedMsgButton.setEnabled(false);
+ if(moveMessagesButton != null)
+ {
+ moveMessagesButton.setEnabled(false);
+ }
+ if(copyMessagesButton != null)
+ {
+ copyMessagesButton.setEnabled(false);
+ }
+ if(deleteMessagesButton != null)
+ {
+ deleteMessagesButton.setEnabled(false);
+ }
+
+ return;
+ }
+ else
+ {
+ if(moveMessagesButton != null)
+ {
+ moveMessagesButton.setEnabled(true);
+ }
+ if(copyMessagesButton != null)
+ {
+ copyMessagesButton.setEnabled(true);
+ }
+ if(deleteMessagesButton != null)
+ {
+ deleteMessagesButton.setEnabled(true);
+ }
+
+ final CompositeData selectedMsg = (CompositeData)_table.getItem(selectionIndex).getData();
+ Boolean redelivered = (Boolean) selectedMsg.get(MSG_REDELIVERED);
+ redeliveredText.setText(redelivered.toString());
+
+ String[] msgHeader = (String[]) selectedMsg.get(MSG_HEADER);
+ headerText.setText("");
+ String lineSeperator = System.getProperty("line.separator");
+ int size = msgHeader.length;
+ for(int i=0; i < size; i++)
+ {
+ headerText.append(msgHeader[i]);
+ if(!(i == size - 1))
+ {
+ headerText.append(lineSeperator);
+ }
+ }
+ headerText.setSelection(0);
+ }
+
+ if (_table.getSelectionCount() > 1)
+ {
+ viewSelectedMsgButton.setEnabled(false);
+ }
+ else
+ {
+ viewSelectedMsgButton.setEnabled(true);
+ }
+
+ }
+ });
+
+ }
+
+ /**
+ * Content Provider class for the table viewer
+ */
+ private class ContentProviderImpl implements IStructuredContentProvider
+ {
+
+ public void inputChanged(Viewer v, Object oldInput, Object newInput)
+ {
+
+ }
+
+ public void dispose()
+ {
+
+ }
+
+ public Object[] getElements(Object parent)
+ {
+ Collection<Object> rowCollection = ((TabularDataSupport) parent).values();
+
+ return rowCollection.toArray();
+ }
+ }
+
+ /**
+ * Label Provider class for the table viewer
+ */
+ private class LabelProviderImpl extends LabelProvider implements ITableLabelProvider
+ {
+ @Override
+ public String getColumnText(Object element, int columnIndex)
+ {
+ switch (columnIndex)
+ {
+ case 0 : // msg id column
+ return String.valueOf(((CompositeDataSupport) element).get(MSG_AMQ_ID));
+ case 1 : // msg size column
+ return String.valueOf(((CompositeDataSupport) element).get(MSG_SIZE));
+ case 2 : // msg position in queue
+ return String.valueOf(((CompositeDataSupport) element).get(MSG_QUEUE_POS));
+ default :
+ return "-";
+ }
+ }
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex)
+ {
+ return null;
+ }
+
+ }
+
+ /**
+ * Sorter class for the table viewer.
+ *
+ */
+ public class TableSorter extends ViewerSorter
+ {
+ private int column;
+ private static final int ASCENDING = 0;
+ private static final int DESCENDING = 1;
+
+ private int direction = DESCENDING;
+
+ public TableSorter()
+ {
+ this.column = 0;
+ direction = ASCENDING;
+ }
+
+ public void setColumn(int column)
+ {
+ if (column == this.column)
+ {
+ // Same column as last sort; toggle the direction
+ direction = 1 - direction;
+ }
+ else
+ {
+ // New column; do an ascending sort
+ this.column = column;
+ direction = ASCENDING;
+ }
+ }
+
+ @Override
+ public int compare(Viewer viewer, Object e1, Object e2)
+ {
+ CompositeData msg1 = (CompositeData) e1;
+ CompositeData msg2 = (CompositeData) e2;
+
+ int comparison = 0;
+ switch(column)
+ {
+ case 0:
+ comparison = ((Long) msg1.get(MSG_AMQ_ID)).compareTo((Long)msg2.get(MSG_AMQ_ID));
+ break;
+ case 1:
+ comparison = ((Long) msg1.get(MSG_SIZE)).compareTo((Long)msg2.get(MSG_SIZE));
+ break;
+ case 2:
+ comparison = ((Long) msg1.get(MSG_QUEUE_POS)).compareTo((Long)msg2.get(MSG_QUEUE_POS));
+ break;
+ default:
+ comparison = 0;
+ }
+ // If descending order, flip the direction
+ if(direction == DESCENDING)
+ {
+ comparison = -comparison;
+ }
+ return comparison;
+ }
+ }
+
+ private void updateMessageInterval()
+ {
+ Long from;
+ try
+ {
+ from = Long.valueOf(_fromMsgText.getText());
+ }
+ catch(Exception e1)
+ {
+ ViewUtility.popupErrorMessage("Invalid Value", "Please enter a valid 'from' number");
+ return;
+ }
+
+ Long to;
+ try
+ {
+ to = Long.valueOf(_toMsgText.getText());
+ }
+ catch(Exception e1)
+ {
+ ViewUtility.popupErrorMessage("Invalid Value", "Please enter a valid 'to' number");
+ return;
+ }
+
+ _fromMsg = from;
+ _toMsg = to;
+
+ _interval = (to - from) + 1;
+ _previousButton.setText("< Prev " + _interval);
+ _nextButton.setText("Next " + _interval + " >");
+
+ refresh(_mbean);
+ }
+
+ private void viewMessageContent()
+ {
+ int selectionIndex = _table.getSelectionIndex();
+
+ if (selectionIndex != -1)
+ {
+ try
+ {
+ final CompositeData selectedMsg = (CompositeData)_table.getItem(selectionIndex).getData();
+ Long msgId = (Long) selectedMsg.get(MSG_AMQ_ID);
+
+ Object result = _qmb.viewMessageContent(msgId);
+
+ populateResults(result);
+ }
+ catch (Exception e3)
+ {
+ MBeanUtility.handleException(_mbean, e3);
+ }
+ }
+ }
+
+ private void populateResults(Object result)
+ {
+ Display display = Display.getCurrent();
+ int width = 610;
+ int height = 400;
+ Shell shell = ViewUtility.createPopupShell(RESULT, width, height);
+ shell.setImage(ApplicationRegistry.getImage(CONSOLE_IMAGE));
+ ViewUtility.populateCompositeWithData(_toolkit, shell, result);
+
+ shell.open();
+ while (!shell.isDisposed())
+ {
+ if (!display.readAndDispatch())
+ {
+ display.sleep();
+ }
+ }
+ shell.dispose();
+ }
+
+ private void moveOrCopyMessages(final Shell parent, final QueueOperations op)
+ {
+ final ArrayList<Long> rangeStarts = new ArrayList<Long>();
+ final ArrayList<Long> rangeEnds = new ArrayList<Long>();
+
+ gatherSelectedAMQMsgIDRanges(rangeStarts,rangeEnds);
+ String rangeString = getRangesString(rangeStarts,rangeEnds);
+
+ String windowTitle;
+ String dialogueMessage;
+ final String feedBackMessage;
+ final String failureFeedBackMessage;
+
+ if(op.equals(QueueOperations.MOVE))
+ {
+ windowTitle = "Move Messages";
+ dialogueMessage = "Move message(s) with AMQ ID:";
+ feedBackMessage = "Messages moved";
+ failureFeedBackMessage = "Error moving messages";
+ }
+ else
+ {
+ windowTitle = "Copy Messages";
+ dialogueMessage = "Copy message(s) with AMQ ID:";
+ feedBackMessage = "Messages copied";
+ failureFeedBackMessage = "Error copying messages";
+ }
+
+ final Shell shell = ViewUtility.createModalDialogShell(parent, windowTitle);
+
+ Composite idComposite = _toolkit.createComposite(shell, SWT.NONE);
+ idComposite.setBackground(shell.getBackground());
+ idComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ idComposite.setLayout(new GridLayout());
+
+ _toolkit.createLabel(idComposite,dialogueMessage).setBackground(shell.getBackground());
+ _toolkit.createLabel(idComposite,rangeString).setBackground(shell.getBackground());
+
+ Composite destinationComposite = _toolkit.createComposite(shell, SWT.NONE);
+ destinationComposite.setBackground(shell.getBackground());
+ destinationComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ destinationComposite.setLayout(new GridLayout(2,false));
+
+ _toolkit.createLabel(destinationComposite,"To Queue:").setBackground(shell.getBackground());
+ final Combo destinationCombo = new Combo(destinationComposite,SWT.NONE | SWT.READ_ONLY);
+ destinationCombo.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+
+ Composite okCancelButtonsComp = _toolkit.createComposite(shell);
+ okCancelButtonsComp.setBackground(shell.getBackground());
+ okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true));
+ okCancelButtonsComp.setLayout(new GridLayout(2,false));
+
+ Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH);
+ okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+ Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH);
+ cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+
+ List<String> queueList = ApplicationRegistry.getServerRegistry(_mbean).getQueueNames(_mbean.getVirtualHostName());
+ queueList.remove(_mbean.getName());
+
+ if(queueList.size() == 0)
+ {
+ destinationCombo.setItems(new String[]{"No other queues available"});
+ okButton.setEnabled(false);
+ }
+ else
+ {
+ Collections.sort(queueList);
+ destinationCombo.setItems(queueList.toArray(new String[0]));
+ }
+ destinationCombo.select(0);
+
+ okButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ String destQueue = destinationCombo.getItem(destinationCombo.getSelectionIndex()).toString();
+ shell.dispose();
+
+ try
+ {
+ for(int i=0 ; i < rangeStarts.size() ; i++)
+ {
+ Long from = rangeStarts.get(i);
+ Long to = rangeEnds.get(i);
+
+ switch(op)
+ {
+ case COPY:
+ _qmb.copyMessages(Long.valueOf(from), Long.valueOf(to), destQueue);
+ break;
+ case MOVE:
+ _qmb.moveMessages(Long.valueOf(from), Long.valueOf(to), destQueue);
+ break;
+ }
+ }
+
+ ViewUtility.operationResultFeedback(null, feedBackMessage, null);
+ }
+ catch (Exception e4)
+ {
+ ViewUtility.operationFailedStatusBarMessage(failureFeedBackMessage);
+ MBeanUtility.handleException(_mbean, e4);
+ }
+
+ refresh(_mbean);
+ }
+ });
+
+ cancelButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ shell.dispose();
+ }
+ });
+
+ shell.setDefaultButton(okButton);
+ shell.pack();
+ ViewUtility.centerChildInParentShell(parent, shell);
+
+ shell.open();
+ }
+
+ private void deleteMessages(final Shell parent)
+ {
+ final ArrayList<Long> rangeStarts = new ArrayList<Long>();
+ final ArrayList<Long> rangeEnds = new ArrayList<Long>();
+
+ gatherSelectedAMQMsgIDRanges(rangeStarts,rangeEnds);
+ String rangeString = getRangesString(rangeStarts,rangeEnds);
+
+ final Shell shell = ViewUtility.createModalDialogShell(parent, "Delete Messages");
+
+ Composite idComposite = _toolkit.createComposite(shell, SWT.NONE);
+ idComposite.setBackground(shell.getBackground());
+ idComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ idComposite.setLayout(new GridLayout());
+
+ _toolkit.createLabel(idComposite,"Delete message(s) with AMQ ID:").setBackground(shell.getBackground());
+ _toolkit.createLabel(idComposite,rangeString).setBackground(shell.getBackground());
+
+ Composite okCancelButtonsComp = _toolkit.createComposite(shell);
+ okCancelButtonsComp.setBackground(shell.getBackground());
+ okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true));
+ okCancelButtonsComp.setLayout(new GridLayout(2,false));
+
+ Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH);
+ okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+ Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH);
+ cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+
+ okButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ shell.dispose();
+
+ try
+ {
+ for(int i=0 ; i < rangeStarts.size() ; i++)
+ {
+ Long from = rangeStarts.get(i);
+ Long to = rangeEnds.get(i);
+
+ _qmb.deleteMessages(Long.valueOf(from), Long.valueOf(to));
+ }
+
+ ViewUtility.operationResultFeedback(null, "Messages deleted", null);
+ }
+ catch (Exception e4)
+ {
+ ViewUtility.operationFailedStatusBarMessage("Error deleting messages");
+ MBeanUtility.handleException(_mbean, e4);
+ }
+
+ refresh(_mbean);
+ }
+ });
+
+ cancelButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ shell.dispose();
+ }
+ });
+
+ shell.setDefaultButton(okButton);
+ shell.pack();
+ ViewUtility.centerChildInParentShell(parent, shell);
+
+ shell.open();
+ }
+
+ private void gatherSelectedAMQMsgIDRanges(ArrayList<Long> starts, ArrayList<Long> ends)
+ {
+ SortedSet<Long> amqIDs = new TreeSet<Long>();
+
+ for(Integer i : _table.getSelectionIndices())
+ {
+ CompositeData selectedMsg = (CompositeData)_table.getItem(i).getData();
+ amqIDs.add((Long)selectedMsg.get(MSG_AMQ_ID));
+ }
+
+ //initialise the first range
+ Long start = amqIDs.first();
+ Long end = amqIDs.first();
+
+ for(Long id : amqIDs)
+ {
+ if(id == amqIDs.first())
+ {
+ //skip first check, already initialised range
+ continue;
+ }
+
+ if(id == end +1)
+ {
+ //part of previous range, append
+ end = id;
+ }
+ else
+ {
+ //not in previous range, record existing start and end msg id values
+ starts.add(start);
+ ends.add(end);
+
+ //begin new range with this msg id
+ start = id;
+ end = id;
+ }
+ }
+
+ //record the last range created
+ starts.add(start);
+ ends.add(end);
+ }
+
+ private String getRangesString(ArrayList<Long> starts, ArrayList<Long> ends)
+ {
+ String idRangesString = new String("");
+
+ for(int i=0 ; i < starts.size() ; i++)
+ {
+ long start = starts.get(i);
+ long end = ends.get(i);
+
+ if(i != 0)
+ {
+ idRangesString = idRangesString.concat(", ");
+ }
+
+ if(start == end)
+ {
+ idRangesString = idRangesString.concat(String.valueOf(starts.get(i)));
+ }
+ else
+ {
+ idRangesString = idRangesString.concat(starts.get(i) + "-" + ends.get(i));
+ }
+ }
+
+ return idRangesString.concat(".");
+ }
+
+ private enum QueueOperations
+ {
+ MOVE,
+ COPY;
+ }
+}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/ConnectionTypeTabControl.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/ConnectionTypeTabControl.java
new file mode 100644
index 0000000000..f1f7b07b6f
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/ConnectionTypeTabControl.java
@@ -0,0 +1,50 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui.views.type;
+
+import java.util.List;
+
+import static org.apache.qpid.management.ui.Constants.CONNECTION;
+
+import org.apache.qpid.management.ui.ManagedBean;
+import org.apache.qpid.management.ui.ManagedServer;
+import org.eclipse.swt.widgets.TabFolder;
+
+/**
+ * Controller class, which takes care of displaying appropriate information and widgets for Connections.
+ * This allows user to select Connections and add those to the navigation view
+ */
+
+public class ConnectionTypeTabControl extends MBeanTypeTabControl
+{
+
+ public ConnectionTypeTabControl(TabFolder tabFolder, ManagedServer server, String virtualHost)
+ {
+ super(tabFolder, server, virtualHost, CONNECTION);
+ }
+
+ @Override
+ protected List<ManagedBean> getMbeans()
+ {
+ return _serverRegistry.getConnections(_virtualHost);
+ }
+
+}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/ExchangeTypeTabControl.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/ExchangeTypeTabControl.java
new file mode 100644
index 0000000000..5d587c7158
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/ExchangeTypeTabControl.java
@@ -0,0 +1,45 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui.views.type;
+
+import java.util.List;
+
+import static org.apache.qpid.management.ui.Constants.EXCHANGE;
+
+import org.apache.qpid.management.ui.ManagedBean;
+import org.apache.qpid.management.ui.ManagedServer;
+import org.eclipse.swt.widgets.TabFolder;
+
+public class ExchangeTypeTabControl extends MBeanTypeTabControl
+{
+
+ public ExchangeTypeTabControl(TabFolder tabFolder, ManagedServer server, String virtualHost)
+ {
+ super(tabFolder, server, virtualHost, EXCHANGE);
+ }
+
+ @Override
+ protected List<ManagedBean> getMbeans()
+ {
+ return _serverRegistry.getExchanges(_virtualHost);
+ }
+
+}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/MBeanTypeTabControl.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/MBeanTypeTabControl.java
new file mode 100644
index 0000000000..cab9bc9f95
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/MBeanTypeTabControl.java
@@ -0,0 +1,458 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui.views.type;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.qpid.management.ui.ApiVersion;
+import org.apache.qpid.management.ui.ApplicationRegistry;
+import org.apache.qpid.management.ui.ManagedBean;
+import org.apache.qpid.management.ui.ManagedServer;
+import org.apache.qpid.management.ui.jmx.JMXManagedObject;
+import org.apache.qpid.management.ui.jmx.JMXServerRegistry;
+import org.apache.qpid.management.ui.jmx.MBeanUtility;
+import org.apache.qpid.management.ui.views.MBeanView;
+import org.apache.qpid.management.ui.views.NavigationView;
+import org.apache.qpid.management.ui.views.TabControl;
+
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.forms.widgets.Form;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+
+public abstract class MBeanTypeTabControl extends TabControl
+{
+ protected FormToolkit _toolkit;
+ protected Form _form;
+ protected Table _table = null;
+ protected TableViewer _tableViewer = null;
+
+ protected List<ManagedBean> _mbeans = null;
+ protected String _type;
+ protected ApiVersion _ApiVersion;
+ protected JMXManagedObject _vhostMbean;
+ protected String _virtualHost;
+ protected JMXServerRegistry _serverRegistry;
+ protected Composite _tableComposite;
+ protected Button _favouritesButton;
+ protected Button _openButton;
+
+ public MBeanTypeTabControl(TabFolder tabFolder, ManagedServer server, String virtualHost, String type)
+ {
+ super(tabFolder);
+ _virtualHost = virtualHost;
+ _serverRegistry = (JMXServerRegistry) ApplicationRegistry.getServerRegistry(server);
+ _ApiVersion = _serverRegistry.getManagementApiVersion();
+ _vhostMbean = (JMXManagedObject) _serverRegistry.getVirtualHostManagerMBean(_virtualHost);
+ _type = type;
+ _toolkit = new FormToolkit(_tabFolder.getDisplay());
+ _form = _toolkit.createForm(_tabFolder);
+ _form.getBody().setLayout(new GridLayout());
+ init();
+ createWidgets();
+ }
+
+ protected void init()
+ {
+
+ }
+
+ /**
+ * @see TabControl#getControl()
+ */
+ public Control getControl()
+ {
+ return _form;
+ }
+
+ /**
+ * @see TabControl#setFocus()
+ */
+ public void setFocus()
+ {
+ _table.setFocus();
+ }
+
+ public void refresh()
+ {
+ refresh(null);
+ }
+
+
+ @Override
+ public void refresh(ManagedBean mbean)
+ {
+ _mbeans = getMbeans();
+
+ _tableViewer.setInput(_mbeans);
+
+ layout();
+ }
+
+ public void layout()
+ {
+ _form.layout(true);
+ _form.getBody().layout(true, true);
+ }
+
+ protected abstract List<ManagedBean> getMbeans();
+
+ protected void createTable()
+ {
+ _table = new Table (_tableComposite, SWT.MULTI | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION);
+ _table.setLinesVisible (true);
+ _table.setHeaderVisible (true);
+ GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ _table.setLayoutData(data);
+
+ _tableViewer = new TableViewer(_table);
+ final TableSorter tableSorter = new TableSorter();
+
+ String[] titles = { "Name"};
+ int[] bounds = { 310};
+ for (int i = 0; i < titles.length; i++)
+ {
+ final int index = i;
+ final TableViewerColumn viewerColumn = new TableViewerColumn(_tableViewer, SWT.NONE);
+ final TableColumn column = viewerColumn.getColumn();
+
+ column.setText(titles[i]);
+ column.setWidth(bounds[i]);
+ column.setResizable(true);
+
+ //Setting the right sorter
+ column.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ tableSorter.setColumn(index);
+ final TableViewer viewer = _tableViewer;
+ int dir = viewer .getTable().getSortDirection();
+ if (viewer.getTable().getSortColumn() == column)
+ {
+ dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
+ }
+ else
+ {
+ dir = SWT.UP;
+ }
+ viewer.getTable().setSortDirection(dir);
+ viewer.getTable().setSortColumn(column);
+ viewer.refresh();
+ }
+ });
+
+ }
+
+ _tableViewer.setContentProvider(new ContentProviderImpl());
+ _tableViewer.setLabelProvider(new LabelProviderImpl());
+ _tableViewer.setSorter(tableSorter);
+ _table.setSortColumn(_table.getColumn(0));
+ _table.setSortDirection(SWT.UP);
+
+ addTableListeners();
+ }
+
+ protected void addTableListeners()
+ {
+ _favouritesButton.setEnabled(false);
+ _openButton.setEnabled(false);
+
+ _tableViewer.addSelectionChangedListener(new ISelectionChangedListener(){
+ public void selectionChanged(SelectionChangedEvent evt)
+ {
+ int selectionIndex = _table.getSelectionIndex();
+
+ if (selectionIndex == -1)
+ {
+ _favouritesButton.setEnabled(false);
+ _openButton.setEnabled(false);
+ return;
+ }
+ else
+ {
+ _favouritesButton.setEnabled(true);
+ }
+
+ if(_table.getSelectionCount() > 1)
+ {
+ _openButton.setEnabled(false);
+ }
+ else
+ {
+ _openButton.setEnabled(true);
+ }
+ }
+ });
+
+ _table.addMouseListener(new MouseListener()
+ {
+ // MouseListener implementation
+ public void mouseDoubleClick(MouseEvent event)
+ {
+ openMBean();
+ }
+
+ public void mouseDown(MouseEvent e){}
+ public void mouseUp(MouseEvent e){}
+ });
+ }
+
+
+ private void createWidgets()
+ {
+ Composite mainComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE);
+ mainComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ mainComposite.setLayout(new GridLayout());
+
+ Composite buttonComposite = _toolkit.createComposite(mainComposite, SWT.NONE);
+ GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
+ buttonComposite.setLayoutData(gridData);
+ buttonComposite.setLayout(new GridLayout(2,true));
+
+ _favouritesButton = _toolkit.createButton(buttonComposite,
+ "<-- Add " + _type + "(s) to favourites", SWT.PUSH);
+ gridData = new GridData(SWT.LEFT, SWT.CENTER, true, false);
+ _favouritesButton.setLayoutData(gridData);
+ _favouritesButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ addMBeanToFavourites();
+ }
+ });
+
+ _openButton = _toolkit.createButton(buttonComposite, "Open selected " + _type, SWT.PUSH);
+ gridData = new GridData(SWT.RIGHT, SWT.CENTER, true, false);
+ _openButton.setLayoutData(gridData);
+ _openButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ openMBean();
+ }
+ });
+
+ _tableComposite = _toolkit.createComposite(mainComposite);
+ gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ _tableComposite.setLayoutData(gridData);
+ _tableComposite.setLayout(new GridLayout(1,false));
+
+ createTable();
+
+ createLowerAreaButton(mainComposite);
+ }
+
+ protected void createLowerAreaButton(Composite parent)
+ {
+
+ }
+
+ /**
+ * Content Provider class for the table viewer
+ */
+ private class ContentProviderImpl implements IStructuredContentProvider
+ {
+
+ public void inputChanged(Viewer v, Object oldInput, Object newInput)
+ {
+
+ }
+
+ public void dispose()
+ {
+
+ }
+
+ @SuppressWarnings("unchecked")
+ public Object[] getElements(Object parent)
+ {
+ return ((List<ManagedBean>) parent).toArray();
+ }
+ }
+
+ /**
+ * Label Provider class for the table viewer
+ */
+ private class LabelProviderImpl extends LabelProvider implements ITableLabelProvider
+ {
+ @Override
+ public String getColumnText(Object element, int columnIndex)
+ {
+ switch (columnIndex)
+ {
+ case 0 : // name column
+ return ((ManagedBean) element).getName();
+ default:
+ return "-";
+ }
+ }
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex)
+ {
+ return null;
+ }
+
+ }
+
+ /**
+ * Sorter class for the table viewer.
+ *
+ */
+ private class TableSorter extends ViewerSorter
+ {
+ private int column;
+ private static final int ASCENDING = 0;
+ private static final int DESCENDING = 1;
+
+ private int direction;
+
+ public TableSorter()
+ {
+ this.column = 0;
+ direction = ASCENDING;
+ }
+
+ public void setColumn(int column)
+ {
+ if(column == this.column)
+ {
+ // Same column as last sort; toggle the direction
+ direction = 1 - direction;
+ }
+ else
+ {
+ // New column; do an ascending sort
+ this.column = column;
+ direction = ASCENDING;
+ }
+ }
+
+ @Override
+ public int compare(Viewer viewer, Object e1, Object e2)
+ {
+ ManagedBean mbean1 = (ManagedBean) e1;
+ ManagedBean mbean2 = (ManagedBean) e2;
+
+ int comparison = 0;
+ switch(column)
+ {
+ case 0:
+ comparison = mbean1.getName().compareTo(mbean2.getName());
+ break;
+ default:
+ comparison = 0;
+ }
+ // If descending order, flip the direction
+ if(direction == DESCENDING)
+ {
+ comparison = -comparison;
+ }
+ return comparison;
+ }
+ }
+
+ protected void addMBeanToFavourites()
+ {
+ int selectionIndex = _table.getSelectionIndex();
+
+ if (selectionIndex == -1)
+ {
+ return;
+ }
+
+ int[] selectedIndices = _table.getSelectionIndices();
+
+ ArrayList<ManagedBean> selectedMBeans = new ArrayList<ManagedBean>();
+
+ for(int index = 0; index < selectedIndices.length ; index++)
+ {
+ ManagedBean selectedMBean = (ManagedBean)_table.getItem(selectedIndices[index]).getData();
+ selectedMBeans.add(selectedMBean);
+ }
+
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ NavigationView view = (NavigationView)window.getActivePage().findView(NavigationView.ID);
+
+ ManagedBean bean = null;
+ try
+ {
+ for(ManagedBean mbean: selectedMBeans)
+ {
+ view.addManagedBean(mbean);
+ }
+ }
+ catch (Exception ex)
+ {
+ MBeanUtility.handleException(bean, ex);
+ }
+ }
+
+ protected void openMBean()
+ {
+ int selectionIndex = _table.getSelectionIndex();
+
+ if (selectionIndex == -1)
+ {
+ return;
+ }
+
+ final ManagedBean selectedMBean = (ManagedBean)_table.getItem(selectionIndex).getData();
+
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ MBeanView view = (MBeanView) window.getActivePage().findView(MBeanView.ID);
+ try
+ {
+ view.openMBean(selectedMBean);
+ }
+ catch (Exception ex)
+ {
+ MBeanUtility.handleException(selectedMBean, ex);
+ }
+ }
+}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/QueueTypeTabControl.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/QueueTypeTabControl.java
new file mode 100644
index 0000000000..df2a1eca59
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/QueueTypeTabControl.java
@@ -0,0 +1,764 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui.views.type;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Semaphore;
+
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerInvocationHandler;
+
+import static org.apache.qpid.management.ui.ApplicationRegistry.DATA_DIR;
+import static org.apache.qpid.management.ui.Constants.QUEUE;
+import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_NAME;
+import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_ACTIVE_CONSUMER_COUNT;
+import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_AUTODELETE;
+import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_CONSUMER_COUNT;
+import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_DURABLE;
+import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_MAX_MSG_AGE;
+import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_MAX_MSG_COUNT;
+import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_MAX_MSG_SIZE;
+import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_MAX_QUEUE_DEPTH;
+import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_MSG_COUNT;
+import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_OWNER;
+import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_QUEUE_DEPTH;
+import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_RCVD_MSG_COUNT;
+
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedQueue;
+import org.apache.qpid.management.ui.ApplicationRegistry;
+import org.apache.qpid.management.ui.ManagedBean;
+import org.apache.qpid.management.ui.ManagedServer;
+import org.apache.qpid.management.ui.jmx.MBeanUtility;
+import org.apache.qpid.management.ui.views.MBeanView;
+import org.apache.qpid.management.ui.views.NavigationView;
+import org.apache.qpid.management.ui.views.ViewUtility;
+import org.eclipse.jface.preference.PreferenceStore;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+public class QueueTypeTabControl extends MBeanTypeTabControl
+{
+ private MBeanServerConnection _mbsc;
+ private ManagedBroker _vhmb;
+
+ private List<String> _selectedAttributes;
+ private PreferenceStore _preferences;
+ private Semaphore _tableViewerSemaphore = new Semaphore(1);
+
+ private static final String APP_DIR = ApplicationRegistry.DATA_DIR;
+ private static final String INI_FILENAME = APP_DIR + File.separator + "qpidmc_queue_attributes.ini";
+ private static final String INI_QUEUE_ATTRIBUES = "QueueAttributesSelection";
+
+ private static final ArrayList<String> FALLBACK_ATTRIBUTES_LIST = new ArrayList<String>();
+ static
+ {
+ FALLBACK_ATTRIBUTES_LIST.add(ATTR_NAME);
+ FALLBACK_ATTRIBUTES_LIST.add(ATTR_ACTIVE_CONSUMER_COUNT);
+ FALLBACK_ATTRIBUTES_LIST.add(ATTR_AUTODELETE);
+ FALLBACK_ATTRIBUTES_LIST.add(ATTR_CONSUMER_COUNT);
+ FALLBACK_ATTRIBUTES_LIST.add(ATTR_DURABLE);
+ FALLBACK_ATTRIBUTES_LIST.add(ATTR_MAX_MSG_AGE);
+ FALLBACK_ATTRIBUTES_LIST.add(ATTR_MAX_MSG_COUNT);
+ FALLBACK_ATTRIBUTES_LIST.add(ATTR_MAX_MSG_SIZE);
+ FALLBACK_ATTRIBUTES_LIST.add(ATTR_MAX_QUEUE_DEPTH);
+ FALLBACK_ATTRIBUTES_LIST.add(ATTR_MSG_COUNT);
+ FALLBACK_ATTRIBUTES_LIST.add(ATTR_OWNER);
+ FALLBACK_ATTRIBUTES_LIST.add(ATTR_QUEUE_DEPTH);
+ FALLBACK_ATTRIBUTES_LIST.add(ATTR_RCVD_MSG_COUNT);
+ }
+
+ private static final Map<String, Integer> DEFAULT_COLUMN_WIDTHS = new HashMap<String,Integer>();
+ static
+ {
+ DEFAULT_COLUMN_WIDTHS.put(ATTR_NAME, 215);
+ DEFAULT_COLUMN_WIDTHS.put(ATTR_OWNER,125);
+ DEFAULT_COLUMN_WIDTHS.put(ATTR_QUEUE_DEPTH,125);
+ }
+
+ public QueueTypeTabControl(TabFolder tabFolder, ManagedServer server, String virtualHost)
+ {
+ super(tabFolder,server,virtualHost,QUEUE);
+ _mbsc = (MBeanServerConnection) _serverRegistry.getServerConnection();
+
+ //create a proxy for the VirtualHostManager mbean to use in retrieving the attribute names/values
+ _vhmb = MBeanServerInvocationHandler.newProxyInstance(_mbsc,
+ _vhostMbean.getObjectName(), ManagedBroker.class, false);
+
+ }
+
+ @Override
+ protected void init()
+ {
+ createIniFileIfNecessary();
+ loadAttributePreferences();
+ }
+
+ /**
+ * Create the ini file if it doesn't already exist.
+ */
+ public static void createIniFileIfNecessary()
+ {
+ File dir = new File(DATA_DIR);
+ if (!dir.exists())
+ {
+ if(!dir.mkdir())
+ {
+ System.err.println("Could not create application data directory " + DATA_DIR);
+ ViewUtility.popupErrorMessage("Error", "Fatal Error: Unable to create the application data directory: " + DATA_DIR);
+ System.exit(1);
+ }
+ }
+
+ File file = new File(INI_FILENAME);
+ try
+ {
+ if (!file.exists())
+ {
+ file.createNewFile();
+ }
+ }
+ catch (IOException ex)
+ {
+ System.err.println("Error creating the configuration file " + INI_FILENAME);
+ ViewUtility.popupErrorMessage("Error", "Fatal Error: Unable to create the configuration file: " + INI_FILENAME);
+ System.exit(1);
+ }
+ }
+
+ private void loadAttributePreferences()
+ {
+ _preferences = new PreferenceStore(INI_FILENAME);
+ List<String> attributesList = new ArrayList<String>();
+
+ //ensure the name is present, and first
+ attributesList.add(ManagedQueue.ATTR_NAME);
+
+ //add any others from the file
+ try
+ {
+ _preferences.load();
+
+ String selectedAttributes = _preferences.getString(INI_QUEUE_ATTRIBUES);
+ if (selectedAttributes.length() != 0)
+ {
+ String[] attributes = selectedAttributes.split(",");
+ for (String attr : attributes)
+ {
+ if(attr.equals(ManagedQueue.ATTR_NAME))
+ {
+ //the Name attribute is already present
+ continue;
+ }
+
+ attributesList.add(attr);
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ ViewUtility.popupErrorMessage("Error", "Unable to load previous attribute selections, defaulting to Name only");
+ System.err.println(e);
+ }
+
+ _selectedAttributes = attributesList;
+ }
+
+ private void saveAttributePreferences()
+ {
+ String chosenAttributes = new String();
+
+ for(String attr : _selectedAttributes)
+ {
+ chosenAttributes = chosenAttributes.concat(attr) + ",";
+ }
+ //cut off last ","
+ int lastIndex = chosenAttributes.lastIndexOf(',');
+ if (lastIndex != -1)
+ {
+ chosenAttributes = chosenAttributes.substring(0,lastIndex);
+ }
+
+ _preferences.putValue(INI_QUEUE_ATTRIBUES, chosenAttributes);
+
+ try
+ {
+ _preferences.save();
+ }
+ catch (IOException e)
+ {
+ ViewUtility.popupErrorMessage("Error", "Unable to save the attribute selection, choices will be lost at shutdown");
+ System.err.println(e);
+ }
+ }
+
+ @Override
+ public void refresh(ManagedBean mbean)
+ {
+ //Try locking. If we cant aquire the lock, dont bother getting new values.
+ //Either the attributes are being changed and these values would be out of date,
+ //or another thread is still in the process of refreshing
+ if(_tableViewerSemaphore.tryAcquire())
+ {
+ try
+ {
+ List<List<Object>> values = null;
+
+ if(_ApiVersion.greaterThanOrEqualTo(1, 3))
+ {
+ //Qpid JMX API 1.3+, use this virtualhosts VirtualHostManager MBean
+ //to retrieve the attributes values requested for all queues at once
+ try
+ {
+ values = _vhmb.retrieveQueueAttributeValues(_selectedAttributes.toArray(new String[0]));
+ }
+ catch(Exception e)
+ {
+ MBeanUtility.handleException(_vhostMbean, e);
+ }
+ }
+ else
+ {
+ //Qpid JMX API 1.2 or below, use the local ManagedBeans and look
+ //up the attribute values for each queue individually
+ _mbeans = getMbeans();
+ values = MBeanUtility.getQueueAttributes(_mbeans, _selectedAttributes.toArray(new String[0]));
+ }
+
+ _tableViewer.setInput(values);
+ layout();
+ }
+ finally
+ {
+ _tableViewerSemaphore.release();
+ }
+ }
+
+ }
+
+ @Override
+ protected List<ManagedBean> getMbeans()
+ {
+ return _serverRegistry.getQueues(_virtualHost);
+ }
+
+ private void clearTableComposite()
+ {
+ ViewUtility.disposeChildren(_tableComposite);
+ }
+
+ @Override
+ protected void createTable()
+ {
+ _table = new Table (_tableComposite, SWT.MULTI | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION);
+ _table.setLinesVisible (true);
+ _table.setHeaderVisible (true);
+ GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ _table.setLayoutData(data);
+
+ _tableViewer = new TableViewer(_table);
+
+ final QueueTableSorter tableSorter = new QueueTableSorter();
+
+ for (int i = 0; i < _selectedAttributes.size(); i++)
+ {
+ final int index = i;
+ final TableViewerColumn viewerColumn = new TableViewerColumn(_tableViewer, SWT.NONE);
+ final TableColumn column = viewerColumn.getColumn();
+
+ String attrName = _selectedAttributes.get(i);
+ column.setMoveable(true);
+ column.setText(attrName);
+ column.pack();
+ if(DEFAULT_COLUMN_WIDTHS.containsKey(attrName))
+ {
+ //retrieve the desired default width
+ column.setWidth(DEFAULT_COLUMN_WIDTHS.get(attrName));
+ }
+ else
+ {
+ //add padding for sort direction indicator
+ column.setWidth(column.getWidth() + 15);
+ }
+ column.setResizable(true);
+
+ //Setting the right sorter
+ column.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ tableSorter.setColumn(index);
+ final TableViewer viewer = _tableViewer;
+ int dir = viewer .getTable().getSortDirection();
+ if (viewer.getTable().getSortColumn() == column)
+ {
+ dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
+ }
+ else
+ {
+ dir = SWT.UP;
+ }
+ viewer.getTable().setSortDirection(dir);
+ viewer.getTable().setSortColumn(column);
+ viewer.refresh();
+ }
+ });
+
+ }
+
+ _tableViewer.setContentProvider(new QueueContentProviderImpl());
+ _tableViewer.setLabelProvider(new QueueLabelProviderImpl());
+
+ _tableViewer.setUseHashlookup(true);
+ _tableViewer.setSorter(tableSorter);
+ _table.setSortColumn(_table.getColumn(0));
+ _table.setSortDirection(SWT.UP);
+
+ addTableListeners();
+ }
+
+ protected void createLowerAreaButton(Composite parent)
+ {
+ Composite lowerButtonComposite = _toolkit.createComposite(parent, SWT.NONE);
+ GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
+ lowerButtonComposite.setLayoutData(gridData);
+ lowerButtonComposite.setLayout(new GridLayout());
+
+ final Button attributesButton = _toolkit.createButton(lowerButtonComposite, "Select Attributes ...", SWT.PUSH);
+ gridData = new GridData(SWT.RIGHT, SWT.CENTER, true, false);
+ attributesButton.setLayoutData(gridData);
+ attributesButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ chooseAttributes(attributesButton.getShell());
+ }
+ });
+ }
+
+ private void chooseAttributes(final Shell parent)
+ {
+
+ List<String> availableAttributes;
+ if(_ApiVersion.greaterThanOrEqualTo(1, 3))
+ {
+ //Qpid JMX API 1.3+, request the current queue attributes names from the broker
+ try
+ {
+ availableAttributes = _vhmb.retrieveQueueAttributeNames();
+ }
+ catch (IOException e)
+ {
+ availableAttributes = new ArrayList<String>(FALLBACK_ATTRIBUTES_LIST);
+ }
+ }
+ else
+ {
+ //Qpid JMX API 1.2 or below, use the falllback list of names.
+ availableAttributes = new ArrayList<String>(FALLBACK_ATTRIBUTES_LIST);
+ }
+
+
+ final List<String> chosenAttributes = new ArrayList<String>();
+
+ final Shell shell = ViewUtility.createModalDialogShell(parent, "Select Attributes");
+
+ Composite attributesComposite = _toolkit.createComposite(shell, SWT.NONE);
+ attributesComposite.setBackground(shell.getBackground());
+ attributesComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ attributesComposite.setLayout(new GridLayout(2,false));
+
+ //add a selected-but-disabled check box for the Name attribute (its a mandatory attribute)
+ final Button nameCheckbox = new Button(attributesComposite, SWT.CHECK);
+ nameCheckbox.setText(ManagedQueue.ATTR_NAME);
+ nameCheckbox.setSelection(true);
+ nameCheckbox.setEnabled(false);
+
+ for(String attr : availableAttributes)
+ {
+ if(attr.equals(ManagedQueue.ATTR_NAME))
+ {
+ //Name attribute is mandatory and gets added to the front of the list later
+ continue;
+ }
+
+ final Button attrButton = new Button(attributesComposite, SWT.CHECK);
+ attrButton.setText(attr);
+
+ //if it was checked before, select it again now
+ if(_selectedAttributes.contains(attr))
+ {
+ attrButton.setSelection(true);
+ chosenAttributes.add(attr);
+ }
+
+ //add a selection listener to update the selected attribute list
+ attrButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ if(attrButton.getSelection())
+ {
+ chosenAttributes.add(attrButton.getText());
+ }
+ else
+ {
+ chosenAttributes.remove(attrButton.getText());
+ }
+ }
+ });
+ }
+
+ Composite okCancelButtonsComp = _toolkit.createComposite(shell);
+ okCancelButtonsComp.setBackground(shell.getBackground());
+ okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true));
+ okCancelButtonsComp.setLayout(new GridLayout(2,false));
+
+ Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH);
+ okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+ Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH);
+ cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+
+ okButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ shell.dispose();
+
+ //The Name attribute is mandatory, add it now, also
+ //ensuring it is left-most by placing it first in the list
+ List<String> newSelection = new ArrayList<String>();
+ newSelection.add(ManagedQueue.ATTR_NAME);
+
+ //now add all remaining choices in alphabetical order
+ Collections.sort(chosenAttributes);
+ newSelection.addAll(chosenAttributes);
+
+ _tableViewerSemaphore.acquireUninterruptibly();
+ try
+ {
+ _selectedAttributes = newSelection;
+
+ clearTableComposite();
+ createTable();
+ saveAttributePreferences();
+ }
+ finally
+ {
+ _tableViewerSemaphore.release();
+ }
+
+ refresh(_mbean);
+ }
+ });
+
+ cancelButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ shell.dispose();
+ }
+ });
+
+ shell.setDefaultButton(okButton);
+ shell.pack();
+ ViewUtility.centerChildInParentShell(parent, shell);
+
+ shell.open();
+ }
+
+ private String getQueueDepthString(Long value)
+ {
+ if(value == null)
+ {
+ return "-";
+ }
+
+ if (_ApiVersion.greaterThanOrEqualTo(1,2))
+ {
+ //Qpid JMX API 1.2 or above, returns Bytes
+ return convertLongBytesToText(value);
+ }
+ else
+ {
+ //Qpid JMX API 1.1 or below, returns KB
+ double mb = 1024.0;
+
+ if(value > mb) //MB
+ {
+ return String.format("%.3f", (Double)(value / mb)) + " MB";
+ }
+ else //KB
+ {
+ return value + " KB";
+ }
+ }
+ }
+
+ private String convertLongBytesToText(Long value)
+ {
+ if(value == null)
+ {
+ return "-";
+ }
+
+ double mb = 1024.0 * 1024.0;
+ double kb = 1024.0;
+
+ if(value >= mb) //MB
+ {
+ return String.format("%.3f", (Double)((double)value / mb)) + " MB";
+ }
+ else if (value >= kb) //KB
+ {
+ return String.format("%.3f", (Double)((double)value / kb)) + " KB";
+ }
+ else //Bytes
+ {
+ return value + " Bytes";
+ }
+ }
+
+ /**
+ * sorter class for the table viewer.
+ *
+ */
+ private class QueueTableSorter extends ViewerSorter
+ {
+ protected int column;
+ protected static final int ASCENDING = 0;
+ protected static final int DESCENDING = 1;
+
+ protected int direction;
+
+ public QueueTableSorter()
+ {
+ this.column = 0;
+ direction = ASCENDING;
+ }
+
+ public void setColumn(int column)
+ {
+ if(column == this.column)
+ {
+ // Same column as last sort; toggle the direction
+ direction = 1 - direction;
+ }
+ else
+ {
+ // New column; do an ascending sort
+ this.column = column;
+ direction = ASCENDING;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public int compare(Viewer viewer, Object e1, Object e2)
+ {
+ List<Object> queue1 = (List<Object>) e1;
+ List<Object> queue2 = (List<Object>) e2;
+
+ int comparison = 0;
+ switch(column)
+ {
+ default:
+ if(queue1.get(column) instanceof Comparable)
+ {
+ comparison = ((Comparable)queue1.get(column)).compareTo((Comparable) queue2.get(column));
+ }
+ }
+ // If descending order, flip the direction
+ if(direction == DESCENDING)
+ {
+ comparison = -comparison;
+ }
+ return comparison;
+ }
+ }
+
+ /**
+ * Content Provider class for the table viewer for Qpid JMX API 1.3 and above.
+ */
+ private class QueueContentProviderImpl implements IStructuredContentProvider
+ {
+
+ public void inputChanged(Viewer v, Object oldInput, Object newInput)
+ {
+
+ }
+
+ public void dispose()
+ {
+
+ }
+
+ @SuppressWarnings("unchecked")
+ public Object[] getElements(Object parent)
+ {
+ return ((List<List<Object>>) parent).toArray();
+ }
+ }
+
+ /**
+ * Label Provider class for the table viewer for for Qpid JMX API 1.3 and above.
+ */
+ private class QueueLabelProviderImpl extends LabelProvider implements ITableLabelProvider
+ {
+ @SuppressWarnings("unchecked")
+ @Override
+ public String getColumnText(Object element, int columnIndex)
+ {
+ List<Object> attributes = (List<Object>) element;
+
+ switch (columnIndex)
+ {
+ default :
+ String attrName = _selectedAttributes.get(columnIndex);
+
+ if(ATTR_QUEUE_DEPTH.equals(attrName))
+ {
+ return getQueueDepthString((Long) attributes.get(columnIndex));
+ }
+ else if(ATTR_MAX_QUEUE_DEPTH.equals(attrName) || ATTR_MAX_MSG_SIZE.equals(attrName))
+ {
+ Number val = (Number)attributes.get(columnIndex);
+ return convertLongBytesToText(val.longValue());
+ }
+ else if(ATTR_MAX_MSG_AGE.equals(attrName))
+ {
+ return String.valueOf(attributes.get(columnIndex) + "ms");
+ }
+
+ return String.valueOf(attributes.get(columnIndex));
+ }
+ }
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex)
+ {
+ return null;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void addMBeanToFavourites()
+ {
+ int selectionIndex = _table.getSelectionIndex();
+
+ if (selectionIndex == -1)
+ {
+ return;
+ }
+
+ int[] selectedIndices = _table.getSelectionIndices();
+
+ ArrayList<ManagedBean> selectedMBeans = new ArrayList<ManagedBean>();
+
+ //the entries are created from an List<Object> with the attribute values (name first)
+ for(int index = 0; index < selectedIndices.length ; index++)
+ {
+ List<Object> queueEntry = (List<Object>) _table.getItem(selectedIndices[index]).getData();
+ String queueName = (String) queueEntry.get(0);
+ selectedMBeans.add(_serverRegistry.getQueue(queueName, _virtualHost));
+ }
+
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ NavigationView view = (NavigationView)window.getActivePage().findView(NavigationView.ID);
+
+ ManagedBean bean = null;
+ try
+ {
+ for(ManagedBean mbean: selectedMBeans)
+ {
+ bean = mbean;
+ view.addManagedBean(mbean);
+ }
+ }
+ catch (Exception ex)
+ {
+ MBeanUtility.handleException(bean, ex);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void openMBean()
+ {
+ int selectionIndex = _table.getSelectionIndex();
+
+ if (selectionIndex == -1)
+ {
+ return;
+ }
+
+ ManagedBean selectedMBean;
+
+ //the entries are created from an List<Object> with the attribute values (name first)
+ List<Object> queueEntry = (List<Object>) _table.getItem(selectionIndex).getData();
+ String queueName = (String) queueEntry.get(0);
+ selectedMBean = _serverRegistry.getQueue(queueName, _virtualHost);
+
+ if(selectedMBean == null)
+ {
+ ViewUtility.popupErrorMessage("Error", "Unable to retrieve the selected MBean to open it");
+ return;
+ }
+
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ MBeanView view = (MBeanView) window.getActivePage().findView(MBeanView.ID);
+ try
+ {
+ view.openMBean(selectedMBean);
+ }
+ catch (Exception ex)
+ {
+ MBeanUtility.handleException(selectedMBean, ex);
+ }
+ }
+}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/users/UserManagementTabControl.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/users/UserManagementTabControl.java
new file mode 100644
index 0000000000..2051beafac
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/users/UserManagementTabControl.java
@@ -0,0 +1,915 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui.views.users;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularDataSupport;
+
+import org.apache.qpid.management.ui.ApiVersion;
+import org.apache.qpid.management.ui.ApplicationRegistry;
+import org.apache.qpid.management.ui.ManagedBean;
+import org.apache.qpid.management.common.mbeans.UserManagement;
+import org.apache.qpid.management.ui.jmx.JMXManagedObject;
+import org.apache.qpid.management.ui.jmx.MBeanUtility;
+import org.apache.qpid.management.ui.views.TabControl;
+import org.apache.qpid.management.ui.views.ViewUtility;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+
+
+/**
+ * Control class for the UserManagement mbean.
+ */
+public class UserManagementTabControl extends TabControl
+{
+ private FormToolkit _toolkit;
+ private ScrolledForm _form;
+ private Table _table = null;
+ private TableViewer _tableViewer = null;
+
+ private TabularDataSupport _userDetails = null;
+ private UserManagement _ummb;
+ private ApiVersion _ApiVersion;
+
+ static final String USERNAME = UserManagement.COMPOSITE_ITEM_NAMES[0];
+ static final String RIGHTS_READ_ONLY = UserManagement.COMPOSITE_ITEM_NAMES[1];
+ static final String RIGHTS_READ_WRITE = UserManagement.COMPOSITE_ITEM_NAMES[2];
+ static final String RIGHTS_ADMIN = UserManagement.COMPOSITE_ITEM_NAMES[3];
+
+ public UserManagementTabControl(TabFolder tabFolder, JMXManagedObject mbean, MBeanServerConnection mbsc)
+ {
+ super(tabFolder);
+ _mbean = mbean;
+ _ApiVersion = ApplicationRegistry.getServerRegistry(mbean).getManagementApiVersion();
+ _ummb = (UserManagement)
+ MBeanServerInvocationHandler.newProxyInstance(mbsc, mbean.getObjectName(),
+ UserManagement.class, false);
+ _toolkit = new FormToolkit(_tabFolder.getDisplay());
+ _form = _toolkit.createScrolledForm(_tabFolder);
+ _form.getBody().setLayout(new GridLayout());
+ createWidgets();
+ }
+
+ /**
+ * @see TabControl#getControl()
+ */
+ public Control getControl()
+ {
+ return _form;
+ }
+
+ /**
+ * @see TabControl#setFocus()
+ */
+ public void setFocus()
+ {
+ _table.setFocus();
+ }
+
+ @Override
+ public void refresh(ManagedBean mbean)
+ {
+ _userDetails = null;
+ try
+ {
+ _userDetails = (TabularDataSupport) _ummb.viewUsers();
+ }
+ catch(Exception e)
+ {
+ MBeanUtility.handleException(_mbean, e);
+
+ }
+
+ _tableViewer.setInput(_userDetails);
+
+ layout();
+ }
+
+ public void layout()
+ {
+ _form.layout(true);
+ _form.getBody().layout(true, true);
+ }
+
+ private void createWidgets()
+ {
+ Composite paramsComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE);
+ paramsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ paramsComposite.setLayout(new GridLayout());
+
+ Group viewUsersGroup = new Group(paramsComposite, SWT.SHADOW_NONE);
+ viewUsersGroup.setBackground(paramsComposite.getBackground());
+ viewUsersGroup.setText("Users");
+ viewUsersGroup.setLayout(new GridLayout(2,false));
+ viewUsersGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ Composite tableComposite = _toolkit.createComposite(viewUsersGroup);
+ GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gridData.heightHint = 250;
+ gridData.minimumHeight = 250;
+ tableComposite.setLayoutData(gridData);
+ tableComposite.setLayout(new GridLayout(2,false));
+
+ _table = new Table (tableComposite, SWT.MULTI | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION);
+ _table.setLinesVisible (true);
+ _table.setHeaderVisible (true);
+ gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ _table.setLayoutData(gridData);
+
+ _tableViewer = new TableViewer(_table);
+ final TableSorter tableSorter = new TableSorter();
+
+ String[] titles = { "Username", "JMX Management Rights" };
+ int[] bounds = { 310, 200 };
+ for (int i = 0; i < titles.length; i++)
+ {
+ final int index = i;
+ final TableViewerColumn viewerColumn = new TableViewerColumn(_tableViewer, SWT.NONE);
+ final TableColumn column = viewerColumn.getColumn();
+
+ column.setText(titles[i]);
+ column.setWidth(bounds[i]);
+ column.setResizable(true);
+
+ //Setting the right sorter
+ column.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ tableSorter.setColumn(index);
+ final TableViewer viewer = _tableViewer;
+ int dir = viewer .getTable().getSortDirection();
+ if (viewer.getTable().getSortColumn() == column)
+ {
+ dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
+ }
+ else
+ {
+ dir = SWT.UP;
+ }
+ viewer.getTable().setSortDirection(dir);
+ viewer.getTable().setSortColumn(column);
+ viewer.refresh();
+ }
+ });
+
+ }
+
+ _tableViewer.setContentProvider(new ContentProviderImpl());
+ _tableViewer.setLabelProvider(new LabelProviderImpl());
+ _tableViewer.setSorter(tableSorter);
+ _table.setSortColumn(_table.getColumn(0));
+ _table.setSortDirection(SWT.UP);
+
+ Composite buttonsComposite = _toolkit.createComposite(tableComposite);
+ gridData = new GridData(SWT.FILL, SWT.TOP, false, false);
+ gridData.heightHint = 165;
+ buttonsComposite.setLayoutData(gridData);
+ buttonsComposite.setLayout(new GridLayout());
+
+ final Button addUserButton = _toolkit.createButton(buttonsComposite, "Add New User ...", SWT.PUSH);
+ gridData = new GridData(SWT.CENTER, SWT.TOP, false, true);
+ gridData.widthHint = 125;
+ addUserButton.setLayoutData(gridData);
+ addUserButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ addUser(addUserButton.getShell());
+ }
+ });
+
+ final Button deleteUsersButton = _toolkit.createButton(buttonsComposite, "Delete User(s)", SWT.PUSH);
+ gridData = new GridData(SWT.CENTER, SWT.BOTTOM, false, false);
+ gridData.widthHint = 125;
+ deleteUsersButton.setLayoutData(gridData);
+ deleteUsersButton.setEnabled(false);
+ deleteUsersButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ int selectionIndex = _table.getSelectionIndex();
+
+ if (selectionIndex != -1)
+ {
+ deleteUsers();
+ }
+ }
+ });
+
+ final Button setPasswordButton = _toolkit.createButton(buttonsComposite, "Set Password ...", SWT.PUSH);
+ gridData = new GridData(SWT.CENTER, SWT.BOTTOM, false, false);
+ gridData.widthHint = 125;
+ setPasswordButton.setLayoutData(gridData);
+ setPasswordButton.setEnabled(false);
+ setPasswordButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ int selectionIndex = _table.getSelectionIndex();
+
+ if (selectionIndex != -1)
+ {
+ final CompositeData selectedLogger = (CompositeData)_table.getItem(
+ selectionIndex).getData();
+ String user = selectedLogger.get(USERNAME).toString();
+ InputDialog id = new InputDialog(setPasswordButton.getShell(),"Set Password",
+ "Please enter the new password for '" + user + "':",null,null){
+ @Override
+ protected Control createDialogArea(Composite parent)
+ {
+ Control control = super.createDialogArea(parent);
+ //set the Text field echo char to '*' to mask the password
+ getText().setEchoChar('*');
+ //return the normal result
+ return control;
+ }
+ };
+
+ int returnValue;
+ while((returnValue = id.open()) == InputDialog.OK)
+ {
+ if (id.getValue() == null || id.getValue().toString().length() == 0)
+ {
+ ViewUtility.popupErrorMessage("Set Password", "Please enter a valid password");
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (returnValue == InputDialog.OK)
+ {
+ char[] password = id.getValue().toCharArray();
+
+ // Qpid JMX API 1.1 and below expects the password to be sent as a hashed value.
+ if (_ApiVersion.lessThanOrEqualTo(1,1))
+ {
+ try
+ {
+ password = ViewUtility.getHash(id.getValue());
+ }
+ catch (Exception hashException)
+ {
+ ViewUtility.popupErrorMessage("Set Password",
+ "Unable to calculate hash for Password:"
+ + hashException.getMessage());
+ return;
+ }
+ }
+
+ try
+ {
+ boolean result = _ummb.setPassword(user, password);
+ ViewUtility.operationResultFeedback(result, "Updated user password", "Failed to update user password");
+ }
+ catch(Exception e2)
+ {
+ ViewUtility.operationFailedStatusBarMessage("Error updating user password");
+ MBeanUtility.handleException(_mbean, e2);
+ }
+ }
+ }
+ }
+ });
+
+ final Button setRightsButton = _toolkit.createButton(buttonsComposite, "Set Rights ...", SWT.PUSH);
+ gridData = new GridData(SWT.CENTER, SWT.BOTTOM, false, false);
+ gridData.widthHint = 125;
+ setRightsButton.setLayoutData(gridData);
+ setRightsButton.setEnabled(false);
+ setRightsButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ int selectionIndex = _table.getSelectionIndex();
+
+ if (selectionIndex != -1)
+ {
+ setRights(setRightsButton.getShell());
+ }
+ }
+ });
+
+ _tableViewer.addSelectionChangedListener(new ISelectionChangedListener(){
+ public void selectionChanged(SelectionChangedEvent evt)
+ {
+ int selectionIndex = _table.getSelectionIndex();
+
+ if (selectionIndex == -1)
+ {
+ deleteUsersButton.setEnabled(false);
+ setRightsButton.setEnabled(false);
+ setPasswordButton.setEnabled(false);
+ return;
+ }
+ else
+ {
+ deleteUsersButton.setEnabled(true);
+ setRightsButton.setEnabled(true);
+ }
+
+ if (_table.getSelectionCount() > 1)
+ {
+ setPasswordButton.setEnabled(false);
+ }
+ else
+ {
+ setPasswordButton.setEnabled(true);
+ }
+ }
+ });
+
+ Group miscGroup = new Group(paramsComposite, SWT.SHADOW_NONE);
+ miscGroup.setBackground(paramsComposite.getBackground());
+ miscGroup.setText("Misc");
+ gridData = new GridData(SWT.LEFT, SWT.TOP, true, true);
+ miscGroup.setLayoutData(gridData);
+ miscGroup.setLayout(new GridLayout(2,false));
+
+ final Button reloadUserDetails = _toolkit.createButton(miscGroup,
+ "Reload User Details", SWT.PUSH);
+ if(_ApiVersion.lessThan(1, 2))
+ {
+ //this only reloaded the JMX rights file before Qpid JMX API 1.2
+ _toolkit.createLabel(miscGroup, " Loads the current management rights file from disk");
+ }
+ else
+ {
+ //since Qpid JMX API 1.2 it also reloads the password file
+ _toolkit.createLabel(miscGroup, " Loads the current password and management rights files from disk");
+ }
+ reloadUserDetails.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ int response = ViewUtility.popupOkCancelConfirmationMessage("Reload User Data",
+ "Do you want to reload user data ?");
+ if (response == SWT.OK)
+ {
+ try
+ {
+ boolean result = _ummb.reloadData();
+ ViewUtility.operationResultFeedback(result, "Reloaded user data", "Failed to reload user data");
+ }
+ catch(Exception e3)
+ {
+ ViewUtility.operationFailedStatusBarMessage("Error reloading user data");
+ MBeanUtility.handleException(_mbean, e3);
+ }
+ refresh(_mbean);
+ }
+ }
+ });
+
+ }
+
+
+ /**
+ * Content Provider class for the table viewer
+ */
+ private class ContentProviderImpl implements IStructuredContentProvider
+ {
+
+ public void inputChanged(Viewer v, Object oldInput, Object newInput)
+ {
+
+ }
+
+ public void dispose()
+ {
+
+ }
+
+ public Object[] getElements(Object parent)
+ {
+ Collection<Object> rowCollection = ((TabularDataSupport) parent).values();
+
+ return rowCollection.toArray();
+ }
+ }
+
+ /**
+ * Label Provider class for the table viewer
+ */
+ private class LabelProviderImpl extends LabelProvider implements ITableLabelProvider
+ {
+ @Override
+ public String getColumnText(Object element, int columnIndex)
+ {
+ switch (columnIndex)
+ {
+ case 0 : // username column
+ return (String) ((CompositeData) element).get(USERNAME);
+ case 1 : // rights column
+ return classifyUserRights((CompositeData) element);
+ default :
+ return "-";
+ }
+ }
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex)
+ {
+ return null;
+ }
+
+ }
+
+ /**
+ * Sorter class for the table viewer.
+ *
+ */
+ private class TableSorter extends ViewerSorter
+ {
+ private int column;
+ private static final int ASCENDING = 0;
+ private static final int DESCENDING = 1;
+
+ private int direction;
+
+ public TableSorter()
+ {
+ this.column = 0;
+ direction = ASCENDING;
+ }
+
+ public void setColumn(int column)
+ {
+ if(column == this.column)
+ {
+ // Same column as last sort; toggle the direction
+ direction = 1 - direction;
+ }
+ else
+ {
+ // New column; do an ascending sort
+ this.column = column;
+ direction = ASCENDING;
+ }
+ }
+
+ @Override
+ public int compare(Viewer viewer, Object e1, Object e2)
+ {
+ CompositeData user1 = (CompositeData) e1;
+ CompositeData user2 = (CompositeData) e2;
+
+ int comparison = 0;
+ switch(column)
+ {
+ case 0:
+ comparison = String.valueOf(user1.get(USERNAME)).compareTo(
+ String.valueOf(user2.get(USERNAME)));
+ break;
+ case 1:
+ comparison = classifyUserRights(user1).compareTo(classifyUserRights(user2));
+ break;
+ default:
+ comparison = 0;
+ }
+ // If descending order, flip the direction
+ if(direction == DESCENDING)
+ {
+ comparison = -comparison;
+ }
+ return comparison;
+ }
+ }
+
+ private String classifyUserRights(CompositeData user)
+ {
+ Boolean read = (Boolean)user.get(RIGHTS_READ_ONLY);
+ Boolean write = (Boolean)user.get(RIGHTS_READ_WRITE);
+ Boolean admin = (Boolean)user.get(RIGHTS_ADMIN);
+
+ if(admin)
+ {
+ return "Admin";
+ }
+ else if(write)
+ {
+ return "Read & Write";
+ }
+ else if(read)
+ {
+ return "Read Only";
+ }
+ else
+ {
+ return "No Access";
+ }
+ }
+
+ private void setRights(final Shell parent)
+ {
+
+ int selectionIndex = _table.getSelectionIndex();
+
+ if (selectionIndex == -1)
+ {
+ return;
+ }
+
+ int[] selectedIndices = _table.getSelectionIndices();
+
+ final ArrayList<String> selectedUsers = new ArrayList<String>();
+
+ for(int index = 0; index < selectedIndices.length ; index++)
+ {
+ CompositeData selectedUser = (CompositeData)_table.getItem(selectedIndices[index]).getData();
+ String user = selectedUser.get(USERNAME).toString();
+ selectedUsers.add(user);
+ }
+
+ String selectedUsersString = "";
+ for(String user : selectedUsers)
+ {
+ selectedUsersString = selectedUsersString.concat(user + ", ");
+ }
+ //cut off last ", "
+ int lastIndex = selectedUsersString.lastIndexOf(',');
+ if (lastIndex != -1)
+ {
+ selectedUsersString = selectedUsersString.substring(0,lastIndex);
+ }
+
+
+
+ final Shell shell = ViewUtility.createModalDialogShell(parent, "Set Rights");
+
+ Label overview = _toolkit.createLabel(shell,"Select rights for user(s): ");
+ overview.setBackground(shell.getBackground());
+ Label userNamesLabel= _toolkit.createLabel(shell,selectedUsersString);
+ userNamesLabel.setBackground(shell.getBackground());
+
+ Composite buttons = _toolkit.createComposite(shell, SWT.NONE);
+ buttons.setBackground(shell.getBackground());
+ buttons.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ buttons.setLayout(new GridLayout(4,false));
+
+ final Button noneButton = new Button(buttons, SWT.RADIO);
+ noneButton.setText("No Access");
+ noneButton.setSelection(true);
+ final Button readButton = new Button(buttons, SWT.RADIO);
+ readButton.setText("Read Only");
+ final Button writeButton = new Button(buttons, SWT.RADIO);
+ writeButton.setText("Read + Write");
+ final Button adminButton = new Button(buttons, SWT.RADIO);
+ adminButton.setText("Admin");
+
+ Composite okCancelButtonsComp = _toolkit.createComposite(shell);
+ okCancelButtonsComp.setBackground(shell.getBackground());
+ okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true));
+ okCancelButtonsComp.setLayout(new GridLayout(2,false));
+
+ Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH);
+ okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+ Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH);
+ cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+
+ okButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ boolean read = readButton.getSelection();
+ boolean write = writeButton.getSelection();
+ boolean admin = adminButton.getSelection();
+
+ shell.dispose();
+
+ HashMap<String,Boolean> results = new HashMap<String,Boolean>();
+ try
+ {
+ //perform the rights updates, save the results.
+ for(String user : selectedUsers)
+ {
+ boolean result = _ummb.setRights(user,read,write,admin);
+ results.put(user, result);
+ }
+
+ //categorise the overall result
+ boolean overallResult = true;
+ for(boolean result : results.values())
+ {
+ if (!result)
+ {
+ overallResult = false;
+ }
+ }
+
+ //output the result to status bar if all success, and dialogue if not
+ if(overallResult)
+ {
+ ViewUtility.operationResultFeedback(overallResult, "Updated user rights", null);
+ }
+ else
+ {
+ String failedToUpdateRightsUsers = "";
+ for(String user : results.keySet())
+ {
+ if(!results.get(user))
+ {
+ failedToUpdateRightsUsers = failedToUpdateRightsUsers.concat(user + ", ");
+ }
+ }
+
+ //cut off last ", "
+ int lastIndex2 = failedToUpdateRightsUsers.lastIndexOf(',');
+ if (lastIndex2 != -1)
+ {
+ failedToUpdateRightsUsers = failedToUpdateRightsUsers.substring(0, lastIndex2);
+ }
+
+ ViewUtility.operationResultFeedback(overallResult, null, "Failed to update user(s) rights: " + failedToUpdateRightsUsers);
+ }
+ }
+ catch(Exception e4)
+ {
+ ViewUtility.operationFailedStatusBarMessage("Error updating user rights");
+ MBeanUtility.handleException(_mbean, e4);
+ }
+ refresh(_mbean);
+ }
+ });
+
+ cancelButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ shell.dispose();
+ }
+ });
+
+ shell.setDefaultButton(okButton);
+ shell.pack();
+ ViewUtility.centerChildInParentShell(parent, shell);
+
+ shell.open();
+ }
+
+ private void addUser(final Shell parent)
+ {
+ final Shell shell = ViewUtility.createModalDialogShell(parent, "Add New User");
+
+ Composite usernameComposite = _toolkit.createComposite(shell, SWT.NONE);
+ usernameComposite.setBackground(shell.getBackground());
+ usernameComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ usernameComposite.setLayout(new GridLayout(2,false));
+
+ _toolkit.createLabel(usernameComposite,"Username:").setBackground(shell.getBackground());
+ final Text usernameText = new Text(usernameComposite, SWT.BORDER);
+ usernameText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+
+ Composite passwordComposite = _toolkit.createComposite(shell, SWT.NONE);
+ passwordComposite.setBackground(shell.getBackground());
+ passwordComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ passwordComposite.setLayout(new GridLayout(2,false));
+
+ _toolkit.createLabel(passwordComposite,"Password:").setBackground(shell.getBackground());
+ final Text passwordText = new Text(passwordComposite, SWT.BORDER | SWT.PASSWORD);
+ passwordText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+
+ Group buttonGroup = new Group(shell, SWT.NONE);
+ buttonGroup.setText("JMX Management Rights");
+ buttonGroup.setBackground(shell.getBackground());
+ buttonGroup.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ buttonGroup.setLayout(new GridLayout(4,false));
+
+ final Button noneButton = new Button(buttonGroup, SWT.RADIO);
+ noneButton.setText("No Access");
+ noneButton.setSelection(true);
+ final Button readButton = new Button(buttonGroup, SWT.RADIO);
+ readButton.setText("Read Only");
+ final Button writeButton = new Button(buttonGroup, SWT.RADIO);
+ writeButton.setText("Read + Write");
+ final Button adminButton = new Button(buttonGroup, SWT.RADIO);
+ adminButton.setText("Admin");
+
+ Composite okCancelButtonsComp = _toolkit.createComposite(shell);
+ okCancelButtonsComp.setBackground(shell.getBackground());
+ okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true));
+ okCancelButtonsComp.setLayout(new GridLayout(2,false));
+
+ Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH);
+ okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+ Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH);
+ cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+
+ okButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ String username = usernameText.getText();
+ String password = passwordText.getText();
+
+ if (username == null || username.length() == 0)
+ {
+ ViewUtility.popupErrorMessage("Add New User", "Please enter a valid username");
+ return;
+ }
+
+ if (password == null || password.length() == 0)
+ {
+ ViewUtility.popupErrorMessage("Add New User", "Please enter a valid password");
+ return;
+ }
+
+ char[] passwordChars = password.toCharArray();
+
+ // Qpid JMX API 1.1 and below expects the password to be sent as a hashed value.
+ if (_ApiVersion.lessThanOrEqualTo(1,1))
+ {
+ try
+ {
+ passwordChars = ViewUtility.getHash(password);
+ }
+ catch (Exception hashException)
+ {
+ ViewUtility.popupErrorMessage("Set Password",
+ "Unable to calculate hash for Password:"
+ + hashException.getMessage());
+ return;
+ }
+ }
+
+ boolean read = readButton.getSelection();
+ boolean write = writeButton.getSelection();
+ boolean admin = adminButton.getSelection();
+
+ shell.dispose();
+ try
+ {
+ boolean result = _ummb.createUser(username, passwordChars, read, write, admin);
+ ViewUtility.operationResultFeedback(result, "Created user", "Failed to create user");
+ }
+ catch(Exception e5)
+ {
+ ViewUtility.operationFailedStatusBarMessage("Error creating user");
+ MBeanUtility.handleException(_mbean, e5);
+ }
+
+ refresh(_mbean);
+ }
+ });
+
+ cancelButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ shell.dispose();
+ }
+ });
+
+ shell.setDefaultButton(okButton);
+ shell.pack();
+ ViewUtility.centerChildInParentShell(parent, shell);
+
+ shell.open();
+ }
+
+ private void deleteUsers()
+ {
+ int selectionIndex = _table.getSelectionIndex();
+ if (selectionIndex == -1)
+ {
+ return;
+ }
+
+ int[] selectedIndices = _table.getSelectionIndices();
+
+ ArrayList<String> selectedUsers = new ArrayList<String>();
+
+ for(int index = 0; index < selectedIndices.length ; index++)
+ {
+ CompositeData selectedUser = (CompositeData)_table.getItem(selectedIndices[index]).getData();
+ String user = selectedUser.get(USERNAME).toString();
+ selectedUsers.add(user);
+ }
+
+ String selectedUsersString = "";
+ for(String user : selectedUsers)
+ {
+ selectedUsersString = selectedUsersString.concat(user + ", ");
+ }
+ //cut off last ", "
+ int lastIndex = selectedUsersString.lastIndexOf(',');
+ if (lastIndex != -1)
+ {
+ selectedUsersString = selectedUsersString.substring(0,lastIndex);
+ }
+
+ int response = ViewUtility.popupOkCancelConfirmationMessage(
+ "User Management", "Delete user(s): " + selectedUsersString + " ?");
+
+ if (response == SWT.OK)
+ {
+ HashMap<String,Boolean> results = new HashMap<String,Boolean>();
+ try
+ {
+ //perform the deletes, save the results.
+ for(String user : selectedUsers)
+ {
+ boolean result = _ummb.deleteUser(user);
+ results.put(user, result);
+ }
+
+ //categorise the overall result
+ boolean overallResult = true;
+ for(boolean result : results.values())
+ {
+ if (!result)
+ {
+ overallResult = false;
+ }
+ }
+
+ //output the result to status bar if all success, and dialogue if not
+ if(overallResult)
+ {
+ ViewUtility.operationResultFeedback(overallResult, "Deleted user(s)", null);
+ }
+ else
+ {
+ String failedToDeleteUsers = "";
+ for(String user : results.keySet())
+ {
+ if(!results.get(user))
+ {
+ failedToDeleteUsers = failedToDeleteUsers.concat(user + ", ");
+ }
+ }
+
+ //cut off last ", "
+ lastIndex = failedToDeleteUsers.lastIndexOf(',');
+ if (lastIndex != -1)
+ {
+ failedToDeleteUsers = failedToDeleteUsers.substring(0, lastIndex);
+ }
+
+ ViewUtility.operationResultFeedback(overallResult, null, "Failed to delete user(s): " + failedToDeleteUsers);
+ }
+
+ }
+ catch(Exception e1)
+ {
+ ViewUtility.operationFailedStatusBarMessage("Error deleting user(s)");
+ MBeanUtility.handleException(_mbean, e1);
+ }
+
+ refresh(_mbean);;
+ }
+ }
+}
diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/vhost/VHostTabControl.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/vhost/VHostTabControl.java
new file mode 100644
index 0000000000..3b03aeaff1
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/vhost/VHostTabControl.java
@@ -0,0 +1,871 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui.views.vhost;
+
+import static org.apache.qpid.management.ui.Constants.DEFAULT_EXCHANGE_TYPE_VALUES;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerInvocationHandler;
+
+import org.apache.qpid.management.ui.ApiVersion;
+import org.apache.qpid.management.ui.ApplicationRegistry;
+import org.apache.qpid.management.ui.ManagedBean;
+import org.apache.qpid.management.ui.ServerRegistry;
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.ui.jmx.JMXManagedObject;
+import org.apache.qpid.management.ui.jmx.MBeanUtility;
+import org.apache.qpid.management.ui.views.MBeanView;
+import org.apache.qpid.management.ui.views.TabControl;
+import org.apache.qpid.management.ui.views.ViewUtility;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.forms.widgets.Form;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+
+
+/**
+ * Control class for the VirtualHostManager mbean operations tab.
+ */
+public class VHostTabControl extends TabControl
+{
+ private FormToolkit _toolkit;
+ private Form _form;
+ private Table _queueTable = null;
+ private TableViewer _queueTableViewer = null;
+ private Table _exchangeTable = null;
+ private TableViewer _exchangeTableViewer = null;
+
+ private Composite _paramsComposite = null;
+
+ private ManagedBroker _vhmb;
+ private ApiVersion _ApiVersion;
+ private List<ManagedBean> _queues;
+ private List<ManagedBean> _exchanges;
+ private ServerRegistry _serverRegistry;
+
+ public VHostTabControl(TabFolder tabFolder, JMXManagedObject mbean, MBeanServerConnection mbsc)
+ {
+ super(tabFolder);
+ _mbean = mbean;
+ _serverRegistry = ApplicationRegistry.getServerRegistry(mbean);
+ _ApiVersion = _serverRegistry.getManagementApiVersion();
+ _vhmb = (ManagedBroker) MBeanServerInvocationHandler.newProxyInstance(mbsc,
+ mbean.getObjectName(), ManagedBroker.class, false);
+ _toolkit = new FormToolkit(_tabFolder.getDisplay());
+ _form = _toolkit.createForm(_tabFolder);
+ _form.getBody().setLayout(new GridLayout());
+ createComposites();
+ createWidgets();
+ }
+
+ private void createComposites()
+ {
+ _paramsComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE);
+ _paramsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ _paramsComposite.setLayout(new GridLayout(2, true));
+ }
+
+ /**
+ * @see TabControl#getControl()
+ */
+ public Control getControl()
+ {
+ return _form;
+ }
+
+ /**
+ * @see TabControl#setFocus()
+ */
+ public void setFocus()
+ {
+
+ }
+
+ @Override
+ public void refresh(ManagedBean mbean)
+ {
+ ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(MBeanView.getServer());
+ _queues = serverRegistry.getQueues(MBeanView.getVirtualHost());
+ _exchanges = serverRegistry.getExchanges(MBeanView.getVirtualHost());
+
+ _queueTableViewer.setInput(_queues);
+ _exchangeTableViewer.setInput(_exchanges);
+
+ layout();
+ }
+
+ public void layout()
+ {
+ _form.layout(true);
+ _form.getBody().layout(true, true);
+ }
+
+ private void createWidgets()
+ {
+ Group queuesGroup = new Group(_paramsComposite, SWT.SHADOW_NONE);
+ queuesGroup.setBackground(_paramsComposite.getBackground());
+ queuesGroup.setText("Queues");
+ queuesGroup.setLayout(new GridLayout(2,false));
+ GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ queuesGroup.setLayoutData(gridData);
+
+ _queueTable = new Table (queuesGroup, SWT.MULTI | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION);
+ _queueTable.setLinesVisible (true);
+ _queueTable.setHeaderVisible (true);
+ GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ _queueTable.setLayoutData(data);
+
+ _queueTableViewer = new TableViewer(_queueTable);
+ final TableSorter tableSorter = new TableSorter();
+
+ String[] titles = {"Name"};
+ int[] bounds = { 250 };
+ for (int i = 0; i < titles.length; i++)
+ {
+ final int index = i;
+ final TableColumn column = new TableColumn (_queueTable, SWT.NONE);
+
+ column.setText(titles[i]);
+ column.setWidth(bounds[i]);
+ column.setResizable(true);
+
+ //Setting the right sorter
+ column.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ tableSorter.setColumn(index);
+ final TableViewer viewer = _queueTableViewer;
+ int dir = viewer .getTable().getSortDirection();
+ if (viewer.getTable().getSortColumn() == column)
+ {
+ dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
+ }
+ else
+ {
+ dir = SWT.UP;
+ }
+ viewer.getTable().setSortDirection(dir);
+ viewer.getTable().setSortColumn(column);
+ viewer.refresh();
+ }
+ });
+
+ }
+
+ _queueTableViewer.setContentProvider(new ContentProviderImpl());
+ _queueTableViewer.setLabelProvider(new LabelProviderImpl());
+ _queueTableViewer.setSorter(tableSorter);
+ _queueTable.setSortColumn(_queueTable.getColumn(0));
+ _queueTable.setSortDirection(SWT.UP);
+
+ Composite queuesRightComposite = _toolkit.createComposite(queuesGroup);
+ gridData = new GridData(SWT.FILL, SWT.FILL, false, true);
+ queuesRightComposite.setLayoutData(gridData);
+ queuesRightComposite.setLayout(new GridLayout());
+
+ final Button createQueueButton = _toolkit.createButton(queuesRightComposite, "Create ...", SWT.PUSH);
+ createQueueButton.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
+ createQueueButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ createQueue(createQueueButton.getShell());
+ }
+ });
+
+ final Button deleteQueueButton = _toolkit.createButton(queuesRightComposite, "Delete", SWT.PUSH);
+ deleteQueueButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ deleteQueueButton.setEnabled(false);
+ deleteQueueButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ deleteQueuesOrExchanges(deleteQueueButton.getShell(), VhostOperations.DELETE_QUEUE);
+ }
+ });
+
+ _queueTableViewer.addSelectionChangedListener(new ISelectionChangedListener(){
+ public void selectionChanged(SelectionChangedEvent evt)
+ {
+ int selectionIndex = _queueTable.getSelectionIndex();
+
+ if (selectionIndex != -1)
+ {
+ deleteQueueButton.setEnabled(true);
+ }
+ else
+ {
+ deleteQueueButton.setEnabled(false);
+ }
+ }
+ });
+
+ //listener for double clicking to open the selection mbean
+ _queueTable.addMouseListener(new MouseListener()
+ {
+ // MouseListener implementation
+ public void mouseDoubleClick(MouseEvent event)
+ {
+ openMBean(_queueTable);
+ }
+
+ public void mouseDown(MouseEvent e){}
+ public void mouseUp(MouseEvent e){}
+ });
+
+ Group exchangesGroup = new Group(_paramsComposite, SWT.SHADOW_NONE);
+ exchangesGroup.setBackground(_paramsComposite.getBackground());
+ exchangesGroup.setText("Exchanges");
+ exchangesGroup.setLayout(new GridLayout(2,false));
+ gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ exchangesGroup.setLayoutData(gridData);
+
+ _exchangeTable = new Table (exchangesGroup, SWT.MULTI | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION);
+ _exchangeTable.setLinesVisible (true);
+ _exchangeTable.setHeaderVisible (true);
+ data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ _exchangeTable.setLayoutData(data);
+
+ _exchangeTableViewer = new TableViewer(_exchangeTable);
+ final TableSorter exchangeTableSorter = new TableSorter();
+
+ for (int i = 0; i < titles.length; i++)
+ {
+ final int index = i;
+ final TableColumn column = new TableColumn (_exchangeTable, SWT.NONE);
+
+ column.setText(titles[i]);
+ column.setWidth(bounds[i]);
+ column.setResizable(true);
+
+ //Setting the right sorter
+ column.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ exchangeTableSorter.setColumn(index);
+ final TableViewer viewer = _exchangeTableViewer;
+ int dir = viewer .getTable().getSortDirection();
+ if (viewer.getTable().getSortColumn() == column)
+ {
+ dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
+ }
+ else
+ {
+ dir = SWT.UP;
+ }
+ viewer.getTable().setSortDirection(dir);
+ viewer.getTable().setSortColumn(column);
+ viewer.refresh();
+ }
+ });
+
+ }
+
+ _exchangeTableViewer.setContentProvider(new ContentProviderImpl());
+ _exchangeTableViewer.setLabelProvider(new LabelProviderImpl());
+ _exchangeTableViewer.setSorter(exchangeTableSorter);
+ _exchangeTable.setSortColumn(_exchangeTable.getColumn(0));
+ _exchangeTable.setSortDirection(SWT.UP);
+
+ Composite exchangesRightComposite = _toolkit.createComposite(exchangesGroup);
+ gridData = new GridData(SWT.FILL, SWT.FILL, false, true);
+ exchangesRightComposite.setLayoutData(gridData);
+ exchangesRightComposite.setLayout(new GridLayout());
+
+ final Button createExchangeButton = _toolkit.createButton(exchangesRightComposite, "Create ...", SWT.PUSH);
+ createExchangeButton.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
+ createExchangeButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ createExchange(createQueueButton.getShell());
+ }
+ });
+
+ final Button deleteExchangeButton = _toolkit.createButton(exchangesRightComposite, "Delete", SWT.PUSH);
+ deleteExchangeButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ deleteExchangeButton.setEnabled(false);
+ deleteExchangeButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ deleteQueuesOrExchanges(deleteExchangeButton.getShell(), VhostOperations.DELETE_EXCHANGE);
+ }
+ });
+
+ _exchangeTableViewer.addSelectionChangedListener(new ISelectionChangedListener(){
+ public void selectionChanged(SelectionChangedEvent evt)
+ {
+ int selectionIndex = _exchangeTable.getSelectionIndex();
+
+ if (selectionIndex != -1)
+ {
+ deleteExchangeButton.setEnabled(true);
+ }
+ else
+ {
+ deleteExchangeButton.setEnabled(false);
+ }
+ }
+ });
+
+ //listener for double clicking to open the selection mbean
+ _exchangeTable.addMouseListener(new MouseListener()
+ {
+ // MouseListener implementation
+ public void mouseDoubleClick(MouseEvent event)
+ {
+ openMBean(_exchangeTable);
+ }
+
+ public void mouseDown(MouseEvent e){}
+ public void mouseUp(MouseEvent e){}
+ });
+ }
+
+
+ /**
+ * Content Provider class for the table viewer
+ */
+ private class ContentProviderImpl implements IStructuredContentProvider
+ {
+
+ public void inputChanged(Viewer v, Object oldInput, Object newInput)
+ {
+
+ }
+
+ public void dispose()
+ {
+
+ }
+
+ @SuppressWarnings("unchecked")
+ public Object[] getElements(Object parent)
+ {
+ return ((List<ManagedBean>) parent).toArray();
+ }
+ }
+
+ /**
+ * Label Provider class for the table viewer
+ */
+ private class LabelProviderImpl extends LabelProvider implements ITableLabelProvider
+ {
+ @Override
+ public String getColumnText(Object element, int columnIndex)
+ {
+ switch (columnIndex)
+ {
+ case 0 : // name column
+ return ((ManagedBean) element).getName();
+ default :
+ return "-";
+ }
+ }
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex)
+ {
+ return null;
+ }
+
+ }
+
+ /**
+ * Sorter class for the table viewer.
+ *
+ */
+ public class TableSorter extends ViewerSorter
+ {
+ private int column;
+ private static final int ASCENDING = 0;
+ private static final int DESCENDING = 1;
+
+ private int direction = DESCENDING;
+
+ public TableSorter()
+ {
+ this.column = 0;
+ direction = ASCENDING;
+ }
+
+ public void setColumn(int column)
+ {
+ if (column == this.column)
+ {
+ // Same column as last sort; toggle the direction
+ direction = 1 - direction;
+ }
+ else
+ {
+ // New column; do an ascending sort
+ this.column = column;
+ direction = ASCENDING;
+ }
+ }
+
+ @Override
+ public int compare(Viewer viewer, Object e1, Object e2)
+ {
+ ManagedBean mbean1 = (ManagedBean ) e1;
+ ManagedBean mbean2 = (ManagedBean ) e2;
+
+ int comparison = 0;
+ switch(column)
+ {
+ case 0:
+ comparison = mbean1.getName().compareTo(mbean2.getName());
+ break;
+ default:
+ comparison = 0;
+ }
+ // If descending order, flip the direction
+ if(direction == DESCENDING)
+ {
+ comparison = -comparison;
+ }
+ return comparison;
+ }
+ }
+
+ private void createQueue(final Shell parent)
+ {
+ final Shell shell = ViewUtility.createModalDialogShell(parent, "Create Queue");
+
+ Composite nameComposite = _toolkit.createComposite(shell, SWT.NONE);
+ nameComposite.setBackground(shell.getBackground());
+ nameComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ nameComposite.setLayout(new GridLayout(2,false));
+
+ _toolkit.createLabel(nameComposite,"Name:").setBackground(shell.getBackground());
+ final Text nameText = new Text(nameComposite, SWT.BORDER);
+ nameText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+
+ Composite ownerComposite = _toolkit.createComposite(shell, SWT.NONE);
+ ownerComposite.setBackground(shell.getBackground());
+ ownerComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ ownerComposite.setLayout(new GridLayout(2,false));
+
+ _toolkit.createLabel(ownerComposite,"Owner (optional):").setBackground(shell.getBackground());
+ final Text ownerText = new Text(ownerComposite, SWT.BORDER);
+ ownerText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+
+ Composite durableComposite = _toolkit.createComposite(shell, SWT.NONE);
+ durableComposite.setBackground(shell.getBackground());
+ GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
+ gridData.minimumWidth = 220;
+ durableComposite.setLayoutData(gridData);
+ durableComposite.setLayout(new GridLayout(2,false));
+
+ _toolkit.createLabel(durableComposite,"Durable:").setBackground(shell.getBackground());
+ final Button durableButton = new Button(durableComposite, SWT.CHECK);
+ durableButton.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false));
+
+ Composite okCancelButtonsComp = _toolkit.createComposite(shell);
+ okCancelButtonsComp.setBackground(shell.getBackground());
+ okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true));
+ okCancelButtonsComp.setLayout(new GridLayout(2,false));
+
+ Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH);
+ okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+ Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH);
+ cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+
+ okButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ String name = nameText.getText();
+
+ if (name == null || name.length() == 0)
+ {
+ ViewUtility.popupErrorMessage("Create Queue", "Please enter a valid name");
+ return;
+ }
+
+ String owner = ownerText.getText();
+
+ if (owner != null && owner.length() == 0)
+ {
+ owner = null;
+ }
+
+ boolean durable = durableButton.getSelection();
+
+ shell.dispose();
+
+ try
+ {
+ _vhmb.createNewQueue(name, owner, durable);
+
+ ViewUtility.operationResultFeedback(null, "Created Queue", null);
+ try
+ {
+ //delay to allow mbean registration notification processing
+ Thread.sleep(250);
+ }
+ catch(InterruptedException ie)
+ {
+ //ignore
+ }
+ }
+ catch(Exception e5)
+ {
+ ViewUtility.operationFailedStatusBarMessage("Error creating Queue");
+ MBeanUtility.handleException(_mbean, e5);
+ }
+
+ refresh(_mbean);
+ }
+ });
+
+ cancelButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ shell.dispose();
+ }
+ });
+
+ shell.setDefaultButton(okButton);
+ shell.pack();
+ ViewUtility.centerChildInParentShell(parent, shell);
+
+ shell.open();
+ }
+
+ private void createExchange(final Shell parent)
+ {
+ final Shell shell = ViewUtility.createModalDialogShell(parent, "Create Exchange");
+
+ Composite nameComposite = _toolkit.createComposite(shell, SWT.NONE);
+ nameComposite.setBackground(shell.getBackground());
+ nameComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ nameComposite.setLayout(new GridLayout(2,false));
+
+ _toolkit.createLabel(nameComposite,"Name:").setBackground(shell.getBackground());
+ final Text nameText = new Text(nameComposite, SWT.BORDER);
+ nameText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+
+ Composite typeComposite = _toolkit.createComposite(shell, SWT.NONE);
+ typeComposite.setBackground(shell.getBackground());
+ typeComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ typeComposite.setLayout(new GridLayout(2,false));
+
+ String[] exchangeTypes;
+ if(_ApiVersion.greaterThanOrEqualTo(1, 3))//if the server supports Qpid JMX API 1.3
+ {//request the current exchange types from the broker
+ try
+ {
+ exchangeTypes = _vhmb.getExchangeTypes();
+ }
+ catch (IOException e1)
+ {
+ exchangeTypes = DEFAULT_EXCHANGE_TYPE_VALUES;
+ }
+ }
+ else //use the fallback defaults.
+ {
+ exchangeTypes = DEFAULT_EXCHANGE_TYPE_VALUES;
+ }
+
+ _toolkit.createLabel(typeComposite,"Type:").setBackground(shell.getBackground());
+ final org.eclipse.swt.widgets.List typeList = new org.eclipse.swt.widgets.List(typeComposite, SWT.SINGLE | SWT.BORDER);
+ typeList.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ typeList.setItems(exchangeTypes);
+
+ Composite durableComposite = _toolkit.createComposite(shell, SWT.NONE);
+ durableComposite.setBackground(shell.getBackground());
+ GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
+ gridData.minimumWidth = 220;
+ durableComposite.setLayoutData(gridData);
+ durableComposite.setLayout(new GridLayout(2,false));
+
+ _toolkit.createLabel(durableComposite,"Durable:").setBackground(shell.getBackground());
+ final Button durableButton = new Button(durableComposite, SWT.CHECK);
+ durableButton.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false));
+
+
+ Composite okCancelButtonsComp = _toolkit.createComposite(shell);
+ okCancelButtonsComp.setBackground(shell.getBackground());
+ okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true));
+ okCancelButtonsComp.setLayout(new GridLayout(2,false));
+
+ Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH);
+ okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+ Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH);
+ cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+
+ okButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ String name = nameText.getText();
+
+ if (name == null || name.length() == 0)
+ {
+ ViewUtility.popupErrorMessage("Create Exchange", "Please enter a valid name");
+ return;
+ }
+
+ int selectedTypeIndex = typeList.getSelectionIndex();
+
+ if (selectedTypeIndex == -1)
+ {
+ ViewUtility.popupErrorMessage("Create Exchange", "Please select an Exchange type");
+ return;
+ }
+
+ String type = typeList.getItem(selectedTypeIndex);
+
+ boolean durable = durableButton.getSelection();
+
+ shell.dispose();
+
+ try
+ {
+ _vhmb.createNewExchange(name, type, durable);
+
+ ViewUtility.operationResultFeedback(null, "Created Exchange", null);
+ try
+ {
+ //delay to allow mbean registration notification processing
+ Thread.sleep(250);
+ }
+ catch(InterruptedException ie)
+ {
+ //ignore
+ }
+ }
+ catch(Exception e5)
+ {
+ ViewUtility.operationFailedStatusBarMessage("Error creating Exchange");
+ MBeanUtility.handleException(_mbean, e5);
+ }
+
+ refresh(_mbean);
+ }
+ });
+
+ cancelButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ shell.dispose();
+ }
+ });
+
+ shell.setDefaultButton(okButton);
+ shell.pack();
+ ViewUtility.centerChildInParentShell(parent, shell);
+
+ shell.open();
+ }
+
+ private void deleteQueuesOrExchanges(Shell parent, final VhostOperations op)
+ {
+ Table table;
+ String windowTitle;
+ String dialogueMessage;
+ final String feedBackMessage;
+ final String failureFeedBackMessage;
+
+ if(op.equals(VhostOperations.DELETE_QUEUE))
+ {
+ table = _queueTable;
+ windowTitle = "Delete Queue(s)";
+ dialogueMessage = "Delete Queue(s): ";
+ feedBackMessage = "Queue(s) deleted";
+ failureFeedBackMessage = "Error deleting Queue(s)";
+ }
+ else
+ {
+ table = _exchangeTable;
+ windowTitle = "Delete Exchange(s)";
+ dialogueMessage = "Delete Exchange(s): ";
+ feedBackMessage = "Exchange(s) deleted";
+ failureFeedBackMessage = "Error deleting Exchange(s)";
+ }
+
+ int selectionIndex = table.getSelectionIndex();
+ if (selectionIndex == -1)
+ {
+ return;
+ }
+
+ int[] selectedIndices = table.getSelectionIndices();
+
+ final ArrayList<ManagedBean> selectedMBeans = new ArrayList<ManagedBean>();
+
+ for(int index = 0; index < selectedIndices.length ; index++)
+ {
+ ManagedBean selectedMBean = (ManagedBean)table.getItem(selectedIndices[index]).getData();
+ selectedMBeans.add(selectedMBean);
+ }
+
+
+ final Shell shell = ViewUtility.createModalDialogShell(parent, windowTitle);
+
+ _toolkit.createLabel(shell, dialogueMessage).setBackground(shell.getBackground());
+
+ final Text headerText = new Text(shell, SWT.WRAP | SWT.V_SCROLL | SWT.BORDER );
+ headerText.setEditable(false);
+ GridData data = new GridData(SWT.FILL, SWT.FILL, false, false);
+ data.minimumHeight = 150;
+ data.heightHint = 150;
+ data.minimumWidth = 400;
+ data.widthHint = 400;
+ headerText.setLayoutData(data);
+
+ String lineSeperator = System.getProperty("line.separator");
+ for(ManagedBean mbean : selectedMBeans)
+ {
+ headerText.append(mbean.getName() + lineSeperator);
+ }
+ headerText.setSelection(0);
+
+ Composite okCancelButtonsComp = _toolkit.createComposite(shell);
+ okCancelButtonsComp.setBackground(shell.getBackground());
+ okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true));
+ okCancelButtonsComp.setLayout(new GridLayout(2,false));
+
+ Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH);
+ okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+ Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH);
+ cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+
+ okButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ shell.dispose();
+
+ try
+ {
+ //perform the deletes
+ for(ManagedBean mbean : selectedMBeans)
+ {
+ switch(op)
+ {
+ case DELETE_QUEUE:
+ _vhmb.deleteQueue(mbean.getName());
+ _serverRegistry.removeManagedObject(mbean);
+ break;
+ case DELETE_EXCHANGE:
+ _vhmb.unregisterExchange(mbean.getName());
+ break;
+ }
+ //remove the mbean from the server registry now instead of
+ //waiting for an mbean Unregistration Notification to do it
+ _serverRegistry.removeManagedObject(mbean);
+ }
+
+ ViewUtility.operationResultFeedback(null, feedBackMessage, null);
+ }
+ catch(Exception e1)
+ {
+ ViewUtility.operationFailedStatusBarMessage(failureFeedBackMessage);
+ MBeanUtility.handleException(_mbean, e1);
+ }
+
+ refresh(_mbean);;
+ }
+ });
+
+ cancelButton.addSelectionListener(new SelectionAdapter()
+ {
+ public void widgetSelected(SelectionEvent e)
+ {
+ shell.dispose();
+ }
+ });
+
+ shell.setDefaultButton(okButton);
+ shell.pack();
+ ViewUtility.centerChildInParentShell(parent, shell);
+
+ shell.open();
+ }
+
+ private enum VhostOperations
+ {
+ DELETE_QUEUE,
+ DELETE_EXCHANGE;
+ }
+
+ private void openMBean(Table table)
+ {
+ int selectionIndex = table.getSelectionIndex();
+
+ if (selectionIndex == -1)
+ {
+ return;
+ }
+
+ ManagedBean selectedMBean = (ManagedBean) table.getItem(selectionIndex).getData();
+
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ MBeanView view = (MBeanView) window.getActivePage().findView(MBeanView.ID);
+ try
+ {
+ view.openMBean(selectedMBean);
+ }
+ catch (Exception ex)
+ {
+ MBeanUtility.handleException(selectedMBean, ex);
+ }
+ }
+}
diff --git a/java/management/eclipse-plugin/src/main/resources/eclipse.exe b/java/management/eclipse-plugin/src/main/resources/eclipse.exe
deleted file mode 100644
index 7826d1ed80..0000000000
--- a/java/management/eclipse-plugin/src/main/resources/eclipse.exe
+++ /dev/null
Binary files differ
diff --git a/java/management/eclipse-plugin/src/main/resources/eclipse.ini b/java/management/eclipse-plugin/src/main/resources/eclipse.ini
deleted file mode 100644
index f56524580d..0000000000
--- a/java/management/eclipse-plugin/src/main/resources/eclipse.ini
+++ /dev/null
@@ -1,23 +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.
-###############################################################################
-
--vmargs
--Xms40m
--Xmx256m
--Declipse.consoleLog=true
diff --git a/java/management/eclipse-plugin/src/main/resources/jmxremote.sasl-plugin/MANIFEST.MF b/java/management/eclipse-plugin/src/main/resources/jmxremote.sasl-plugin/MANIFEST.MF
new file mode 100644
index 0000000000..fa11bac2ea
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/jmxremote.sasl-plugin/MANIFEST.MF
@@ -0,0 +1,19 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: jmx sasl Plug-in
+Bundle-SymbolicName: jmxremote.sasl
+Bundle-Version: 1.0.1
+Bundle-ClassPath: jmxremote_optional.jar
+Export-Package: com.sun.jmx.remote.generic,
+ com.sun.jmx.remote.opt.internal,
+ com.sun.jmx.remote.opt.security,
+ com.sun.jmx.remote.opt.util,
+ com.sun.jmx.remote.profile.sasl,
+ com.sun.jmx.remote.profile.tls,
+ com.sun.jmx.remote.protocol.jmxmp,
+ com.sun.jmx.remote.socket,
+ javax.management.remote.generic,
+ javax.management.remote.jmxmp,
+ javax.management.remote.message
+Bundle-Vendor:
+Bundle-Localization: plugin
diff --git a/java/management/eclipse-plugin/src/main/resources/license.eclipse.txt b/java/management/eclipse-plugin/src/main/resources/license.eclipse.txt
deleted file mode 100644
index da433e89f9..0000000000
--- a/java/management/eclipse-plugin/src/main/resources/license.eclipse.txt
+++ /dev/null
@@ -1,88 +0,0 @@
-Eclipse Public License - v 1.0
-
-THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
-
-1. DEFINITIONS
-
-"Contribution" means:
-
-a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
-b) in the case of each subsequent Contributor:
-
-i) changes to the Program, and
-
-ii) additions to the Program;
-
-where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.
-
-"Contributor" means any person or entity that distributes the Program.
-
-"Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.
-
-"Program" means the Contributions distributed in accordance with this Agreement.
-
-"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.
-
-2. GRANT OF RIGHTS
-
-a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.
-
-b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
-
-c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
-
-d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
-
-3. REQUIREMENTS
-
-A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:
-
-a) it complies with the terms and conditions of this Agreement; and
-
-b) its license agreement:
-
-i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
-
-ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
-
-iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and
-
-iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.
-
-When the Program is made available in source code form:
-
-a) it must be made available under this Agreement; and
-
-b) a copy of this Agreement must be included with each copy of the Program.
-
-Contributors may not remove or alter any copyright notices contained within the Program.
-
-Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.
-
-4. COMMERCIAL DISTRIBUTION
-
-Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.
-
-For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.
-
-5. NO WARRANTY
-
-EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED 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. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.
-
-6. DISCLAIMER OF LIABILITY
-
-EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
-
-7. GENERAL
-
-If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
-
-If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.
-
-All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.
-
-Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved.
-
-This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.
-
-
diff --git a/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/Configuration/config.ini b/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/Configuration/config.ini
new file mode 100644
index 0000000000..dc15366740
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/Configuration/config.ini
@@ -0,0 +1,49 @@
+###############################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+###############################################################################
+
+#Product Runtime Configuration File
+
+osgi.splashPath=platform:/base/plugins/org.apache.qpid.management.ui
+eclipse.product=org.apache.qpid.management.ui.product
+osgi.bundles.defaultStartLevel=4
+osgi.bundles=jmxremote.sasl, \
+qpid-management-common, \
+org.apache.qpid.management.ui, \
+com.ibm.icu, \
+org.eclipse.core.commands, \
+org.eclipse.core.contenttype, \
+org.eclipse.core.databinding, \
+org.eclipse.core.expressions, \
+org.eclipse.core.jobs, \
+org.eclipse.core.runtime@start, \
+org.eclipse.core.runtime.compatibility.registry, \
+org.eclipse.equinox.app,org.eclipse.equinox.common, \
+org.eclipse.equinox.preferences, \
+org.eclipse.equinox.registry, \
+org.eclipse.help, \
+org.eclipse.jface, \
+org.eclipse.jface.databinding, \
+org.eclipse.swt, \
+org.eclipse.swt.gtk.linux.x86, \
+org.eclipse.ui, \
+org.eclipse.ui.forms, \
+org.eclipse.ui.workbench, \
+org.eclipse.equinox.launcher, \
+org.eclipse.equinox.launcher.gtk.linux.x86, \
+org.apache.commons.codec
diff --git a/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/libcairo-swt.so b/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/libcairo-swt.so
new file mode 100644
index 0000000000..b66f95814e
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/libcairo-swt.so
Binary files differ
diff --git a/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/qpidmc b/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/qpidmc
new file mode 100644
index 0000000000..0cc5c65455
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/qpidmc
Binary files differ
diff --git a/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/qpidmc.ini b/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/qpidmc.ini
new file mode 100644
index 0000000000..19ceb6f717
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/qpidmc.ini
@@ -0,0 +1,37 @@
+###############################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+###############################################################################
+
+-vmargs
+-Xms40m
+-Xmx256m
+-XX:MaxPermSize=256m
+-Dosgi.requiredJavaVersion=1.5
+-Declipse.consoleLog=true
+
+#===============================================
+# SSL trust store configuration options.
+#===============================================
+
+# Uncomment lines below to specify custom truststore for server SSL
+# certificate verification, eg when using self-signed server certs.
+#
+#-Djavax.net.ssl.trustStore=<path.to.truststore>
+#-Djavax.net.ssl.trustStorePassword=<truststore.password>
+
+
diff --git a/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/Configuration/config.ini b/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/Configuration/config.ini
new file mode 100644
index 0000000000..f437e830b5
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/Configuration/config.ini
@@ -0,0 +1,49 @@
+###############################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+###############################################################################
+
+#Product Runtime Configuration File
+
+osgi.splashPath=platform:/base/plugins/org.apache.qpid.management.ui
+eclipse.product=org.apache.qpid.management.ui.product
+osgi.bundles.defaultStartLevel=4
+osgi.bundles=jmxremote.sasl, \
+qpid-management-common, \
+org.apache.qpid.management.ui, \
+com.ibm.icu, \
+org.eclipse.core.commands, \
+org.eclipse.core.contenttype, \
+org.eclipse.core.databinding, \
+org.eclipse.core.expressions, \
+org.eclipse.core.jobs, \
+org.eclipse.core.runtime@start, \
+org.eclipse.core.runtime.compatibility.registry, \
+org.eclipse.equinox.app,org.eclipse.equinox.common, \
+org.eclipse.equinox.preferences, \
+org.eclipse.equinox.registry, \
+org.eclipse.help, \
+org.eclipse.jface, \
+org.eclipse.jface.databinding, \
+org.eclipse.swt, \
+org.eclipse.swt.gtk.linux.x86_64, \
+org.eclipse.ui, \
+org.eclipse.ui.forms, \
+org.eclipse.ui.workbench, \
+org.eclipse.equinox.launcher, \
+org.eclipse.equinox.launcher.gtk.linux.x86_64, \
+org.apache.commons.codec
diff --git a/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/libcairo-swt.so b/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/libcairo-swt.so
new file mode 100644
index 0000000000..5734427fb8
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/libcairo-swt.so
Binary files differ
diff --git a/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/qpidmc b/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/qpidmc
new file mode 100644
index 0000000000..ff1f3a7507
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/qpidmc
Binary files differ
diff --git a/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/qpidmc.ini b/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/qpidmc.ini
new file mode 100644
index 0000000000..19ceb6f717
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/qpidmc.ini
@@ -0,0 +1,37 @@
+###############################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+###############################################################################
+
+-vmargs
+-Xms40m
+-Xmx256m
+-XX:MaxPermSize=256m
+-Dosgi.requiredJavaVersion=1.5
+-Declipse.consoleLog=true
+
+#===============================================
+# SSL trust store configuration options.
+#===============================================
+
+# Uncomment lines below to specify custom truststore for server SSL
+# certificate verification, eg when using self-signed server certs.
+#
+#-Djavax.net.ssl.trustStore=<path.to.truststore>
+#-Djavax.net.ssl.trustStorePassword=<truststore.password>
+
+
diff --git a/java/management/eclipse-plugin/src/main/resources/macosx/Configuration/config.ini b/java/management/eclipse-plugin/src/main/resources/macosx/Configuration/config.ini
new file mode 100644
index 0000000000..3ac3aa20f3
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/macosx/Configuration/config.ini
@@ -0,0 +1,49 @@
+###############################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+###############################################################################
+
+#Product Runtime Configuration File
+
+osgi.splashPath=platform:/base/plugins/org.apache.qpid.management.ui
+eclipse.product=org.apache.qpid.management.ui.product
+osgi.bundles.defaultStartLevel=4
+osgi.bundles=jmxremote.sasl, \
+qpid-management-common, \
+org.apache.qpid.management.ui, \
+com.ibm.icu, \
+org.eclipse.core.commands, \
+org.eclipse.core.contenttype, \
+org.eclipse.core.databinding, \
+org.eclipse.core.expressions, \
+org.eclipse.core.jobs, \
+org.eclipse.core.runtime@start, \
+org.eclipse.core.runtime.compatibility.registry, \
+org.eclipse.equinox.app,org.eclipse.equinox.common, \
+org.eclipse.equinox.preferences, \
+org.eclipse.equinox.registry, \
+org.eclipse.help, \
+org.eclipse.jface, \
+org.eclipse.jface.databinding, \
+org.eclipse.swt, \
+org.eclipse.swt.carbon.macosx, \
+org.eclipse.ui, \
+org.eclipse.ui.forms, \
+org.eclipse.ui.workbench, \
+org.eclipse.equinox.launcher, \
+org.eclipse.equinox.launcher.carbon.macosx, \
+org.apache.commons.codec
diff --git a/java/management/eclipse-plugin/src/main/resources/macosx/Contents/Info.plist b/java/management/eclipse-plugin/src/main/resources/macosx/Contents/Info.plist
new file mode 100644
index 0000000000..e06c8a6e60
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/macosx/Contents/Info.plist
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleExecutable</key>
+ <string>qpidmc</string>
+ <key>CFBundleGetInfoString</key>
+ <string>Apache Qpid Management Console for Mac OS X</string>
+ <key>CFBundleIconFile</key>
+ <string>Console.icns</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.apache.qpid.management.ui</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>Qpid Management Console</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>3.4</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>3.4</string>
+ <key>Qpid Management Console</key>
+ <array>
+ <string>-consoleLog</string>
+ <string>-showlocation</string>
+ <!-- WARNING:
+ If you try to add a single VM argument (-vmargs) here,
+ *all* vmargs specified in qpidmc.ini will be ignored.
+ We recommend to add all arguments in MacOS/qpidmc.ini -->
+ </array>
+</dict>
+</plist>
diff --git a/java/management/eclipse-plugin/src/main/resources/macosx/Contents/MacOS/qpidmc b/java/management/eclipse-plugin/src/main/resources/macosx/Contents/MacOS/qpidmc
new file mode 100755
index 0000000000..36247a08e4
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/macosx/Contents/MacOS/qpidmc
Binary files differ
diff --git a/java/management/eclipse-plugin/src/main/resources/macosx/Contents/MacOS/qpidmc.ini b/java/management/eclipse-plugin/src/main/resources/macosx/Contents/MacOS/qpidmc.ini
new file mode 100644
index 0000000000..2a31b9b2c7
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/macosx/Contents/MacOS/qpidmc.ini
@@ -0,0 +1,42 @@
+###############################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+###############################################################################
+
+-startup
+../../plugins/org.eclipse.equinox.launcher_1.0.101.R34x_v20080819.jar
+--launcher.library
+../../plugins/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731
+-vmargs
+-XstartOnFirstThread
+-Xms40m
+-Xmx512m
+-XX:MaxPermSize=256m
+-Dosgi.requiredJavaVersion=1.5
+-Declipse.consoleLog=true
+-Dorg.eclipse.swt.internal.carbon.smallFonts
+
+#===============================================
+# SSL trust store configuration options.
+#===============================================
+
+# Uncomment lines below to specify custom truststore for server SSL
+# certificate verification, eg when using self-signed server certs.
+#
+#-Djavax.net.ssl.trustStore=<path.to.truststore>
+#-Djavax.net.ssl.trustStorePassword=<truststore.password>
+
diff --git a/java/management/eclipse-plugin/src/main/resources/macosx/Contents/Resources/Console.icns b/java/management/eclipse-plugin/src/main/resources/macosx/Contents/Resources/Console.icns
new file mode 100644
index 0000000000..610976efab
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/macosx/Contents/Resources/Console.icns
Binary files differ
diff --git a/java/management/eclipse-plugin/src/main/resources/sasl/MANIFEST.MF b/java/management/eclipse-plugin/src/main/resources/sasl/MANIFEST.MF
deleted file mode 100644
index d18b1a073d..0000000000
--- a/java/management/eclipse-plugin/src/main/resources/sasl/MANIFEST.MF
+++ /dev/null
@@ -1,8 +0,0 @@
-Manifest-Version: 1.0
-Bundle-ManifestVersion: 2
-Bundle-Name: jmx sasl Plug-in
-Bundle-SymbolicName: jmxremote.sasl
-Bundle-Version: 1.0.1
-Bundle-ClassPath: .
-Bundle-Vendor:
-Bundle-Localization: plugin
diff --git a/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Configuration/config.ini b/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Configuration/config.ini
new file mode 100644
index 0000000000..a99a8b3f7d
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Configuration/config.ini
@@ -0,0 +1,49 @@
+###############################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+###############################################################################
+
+#Product Runtime Configuration File
+
+osgi.splashPath=platform:/base/plugins/org.apache.qpid.management.ui
+eclipse.product=org.apache.qpid.management.ui.product
+osgi.bundles.defaultStartLevel=4
+osgi.bundles=jmxremote.sasl, \
+qpid-management-common, \
+org.apache.qpid.management.ui, \
+com.ibm.icu, \
+org.eclipse.core.commands, \
+org.eclipse.core.contenttype, \
+org.eclipse.core.databinding, \
+org.eclipse.core.expressions, \
+org.eclipse.core.jobs, \
+org.eclipse.core.runtime@start, \
+org.eclipse.core.runtime.compatibility.registry, \
+org.eclipse.equinox.app,org.eclipse.equinox.common, \
+org.eclipse.equinox.preferences, \
+org.eclipse.equinox.registry, \
+org.eclipse.help, \
+org.eclipse.jface, \
+org.eclipse.jface.databinding, \
+org.eclipse.swt, \
+org.eclipse.swt.gtk.solaris.sparc, \
+org.eclipse.ui, \
+org.eclipse.ui.forms, \
+org.eclipse.ui.workbench, \
+org.eclipse.equinox.launcher, \
+org.eclipse.equinox.launcher.gtk.solaris.sparc, \
+org.apache.commons.codec
diff --git a/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.l.pm b/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.l.pm
new file mode 100644
index 0000000000..995d7c9bb0
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.l.pm
@@ -0,0 +1,311 @@
+/* XPM */
+static char *ProductIcon48[] = {
+/* columns rows colors chars-per-pixel */
+"48 48 257 2",
+" c black",
+". c gray100",
+"X c #69695A5AE8E8",
+"o c #494949499191",
+"O c #CECE9292BFBF",
+"+ c #E7E7CACAE0E0",
+"@ c #C8C88C8CBBBB",
+"# c #C2C28A8ABABA",
+"$ c #EAEAD7D7E8E8",
+"% c #CFCFA9A9CCCC",
+"& c #D9D9BCBCD8D8",
+"* c #B6B68787B9B9",
+"= c #C3C39999C7C7",
+"- c #A7A77D7DB5B5",
+"; c #BDBDA3A3CDCD",
+": c #D8D8CACAE3E3",
+"> c #A8A88D8DC4C4",
+", c #92927575B2B2",
+"< c #87876C6CAAAA",
+"1 c #9A9A8383BABA",
+"2 c #7B7B6363A3A3",
+"3 c #666654549595",
+"4 c #73735F5FADAD",
+"5 c #626251519292",
+"6 c #7F7F7272A7A7",
+"7 c #6D6D5E5E9E9E",
+"8 c #64645454A9A9",
+"9 c #77776969B1B1",
+"0 c #49493E3E8282",
+"q c #7D7D7373B6B6",
+"w c #5B5B4E4EADAD",
+"e c #55554949BABA",
+"r c #56564949BABA",
+"t c #56564A4ABABA",
+"y c #56564949B9B9",
+"u c #55554949B8B8",
+"i c #4F4F4444ACAC",
+"p c #53534848B4B4",
+"a c #53534848B3B3",
+"s c #54544949B5B5",
+"d c #52524747B0B0",
+"f c #52524747AFAF",
+"g c #54544949B3B3",
+"h c #DEDEDCDCEEEE",
+"j c #3E3E36369898",
+"k c #43433B3B9F9F",
+"l c #33332C2C7777",
+"z c #42423A3A9C9C",
+"x c #4A4A4040A8A8",
+"c c #55554A4ABABA",
+"v c #55554A4AB9B9",
+"b c #54544949B7B7",
+"n c #52524848B1B1",
+"m c #51514747AEAE",
+"M c #4E4E4545A9A9",
+"N c #49494141A0A0",
+"B c #52524848AFAF",
+"V c #51514848AEAE",
+"C c #50504747ACAC",
+"Z c #4F4F4646AAAA",
+"A c #51514848ADAD",
+"S c #50504747ABAB",
+"D c #50504848ACAC",
+"F c #50504747A9A9",
+"G c #4E4E4646A7A7",
+"H c #4E4E4545A4A4",
+"J c #4D4D4545A4A4",
+"K c #4F4F4747A8A8",
+"L c #4E4E4646A5A5",
+"P c #4D4D4545A3A3",
+"I c #3B3B35357D7D",
+"U c #4E4E4646A3A3",
+"Y c #55554D4D9F9F",
+"T c #4A4A43438989",
+"R c #51514B4B9090",
+"E c #67676060A5A5",
+"W c #1D1D18186A6A",
+"Q c #272722227D7D",
+"! c #282823237D7D",
+"~ c #2B2B26268181",
+"^ c #33332C2C8989",
+"/ c #3B3B36368E8E",
+"( c #454540409797",
+") c #4D4D4646A4A4",
+"_ c #4C4C4545A1A1",
+"` c #4D4D4646A2A2",
+"' c #4B4B4545A0A0",
+"] c #4D4D4646A1A1",
+"[ c #4C4C45459F9F",
+"{ c #4B4B45459E9E",
+"} c #4A4A44449C9C",
+"| c #494944449898",
+" . c #484843439696",
+".. c #4A4A45459999",
+"X. c #4F4F4A4AA0A0",
+"o. c #68686363AAAA",
+"O. c #21211D1D7676",
+"+. c #242420207575",
+"@. c #2D2D2A2A7F7F",
+"#. c #2D2D2A2A7B7B",
+"$. c #3D3D39398F8F",
+"%. c #484844449696",
+"&. c #474743439393",
+"*. c #464643439191",
+"=. c #454542428E8E",
+"-. c #4D4D4A4A9C9C",
+";. c #57575454A3A3",
+":. c #5A5A58589797",
+">. c #5F5F5D5D9999",
+",. c #85858282C1C1",
+"<. c #95959292C9C9",
+"1. c #B8B8B6B6DCDC",
+"2. c #070705055353",
+"3. c #080807075555",
+"4. c #0A0A09095757",
+"5. c #0C0C0B0B5858",
+"6. c #0F0F0D0D5C5C",
+"7. c #10100F0F5C5C",
+"8. c #131311116464",
+"9. c #141413136060",
+"0. c #141413135F5F",
+"q. c #171715156767",
+"w. c #161615156262",
+"e. c #161615156161",
+"r. c #181817176464",
+"t. c #1A1A19196666",
+"y. c #1C1C1A1A6464",
+"u. c #1D1D1C1C6868",
+"i. c #1F1F1E1E6A6A",
+"p. c #222221216C6C",
+"a. c #242423236F6F",
+"s. c #272725257171",
+"d. c #272726267272",
+"f. c #272726267171",
+"g. c #292928287474",
+"h. c #2A2A29297474",
+"j. c #2C2C2B2B7777",
+"k. c #2F2F2E2E7C7C",
+"l. c #2E2E2D2D7979",
+"z. c #343433337E7E",
+"x. c #393937378686",
+"c. c #373736368181",
+"v. c #3A3A39398484",
+"b. c #3A3A39398383",
+"n. c #3D3D3B3B8686",
+"m. c #424241418C8C",
+"M. c #424241418B8B",
+"N. c #444442428B8B",
+"B. c #434341418989",
+"V. c #454544448E8E",
+"C. c #454544448D8D",
+"Z. c #424241418787",
+"A. c #434342428888",
+"S. c #444442428787",
+"D. c #424241418585",
+"F. c #414140408383",
+"G. c #484847479090",
+"H. c #434342428686",
+"J. c #4A4A49499393",
+"K. c #464645458A8A",
+"L. c #4D4D4C4C9595",
+"P. c #54545252A0A0",
+"I. c #50504F4F9898",
+"U. c #58585757A0A0",
+"Y. c #525250509393",
+"T. c #5B5B5959A2A2",
+"R. c #585857579F9F",
+"E. c #62626161A9A9",
+"W. c #64646363ACAC",
+"Q. c #6B6B6A6AB2B2",
+"!. c #6B6B6A6AB1B1",
+"~. c #75757474B8B8",
+"^. c #7F7F7D7DBDBD",
+"/. c #9C9C9B9BCFCF",
+"(. c #0B0B0B0B5858",
+"). c #0D0D0D0D5A5A",
+"_. c #111111115E5E",
+"`. c #131313136060",
+"'. c #212121216D6D",
+"]. c #242424246F6F",
+"[. c #2B2B2C2C7777",
+"{. c #2B2B2B2B7777",
+"}. c #2C2C2C2C7777",
+"|. c #2E2E2E2E7979",
+" X c #313131317C7C",
+".X c #313131317B7B",
+"XX c #343434347E7E",
+"oX c #3C3C3C3C8686",
+"OX c #3F3F3F3F8989",
+"+X c #414142428B8B",
+"@X c #424242428B8B",
+"#X c #474747479090",
+"$X c #414141418484",
+"%X c #404040408181",
+"&X c #4A4A4A4A9494",
+"*X c #4A4A4A4A9393",
+"=X c #4D4D4D4D9696",
+"-X c #4F4F4F4F9898",
+";X c #505050509898",
+":X c #525252529B9B",
+">X c #555555559E9E",
+",X c #555555559D9D",
+"<X c #57575858A0A0",
+"1X c #58585858A0A0",
+"2X c #575758589F9F",
+"3X c #575757579F9F",
+"4X c #5A5A5A5AA2A2",
+"5X c #5D5D5D5DA5A5",
+"6X c #5F5F5F5FA7A7",
+"7X c #61616262AAAA",
+"8X c #61616161A9A9",
+"9X c #61616262A9A9",
+"0X c #62626262AAAA",
+"qX c #64646464ACAC",
+"wX c #62626262A9A9",
+"eX c #64646464ABAB",
+"rX c #66666666AEAE",
+"tX c #66666666ADAD",
+"yX c #68686868B0B0",
+"uX c #69696969AFAF",
+"iX c #6D6D6D6DB4B4",
+"pX c #6F6F6F6FB5B5",
+"aX c #73737373BABA",
+"sX c #71717171B7B7",
+"dX c #76767676BCBC",
+"fX c #79797979BFBF",
+"gX c #77777777B9B9",
+"hX c #80808080C1C1",
+"jX c #8C8C8C8CC5C5",
+"kX c #90909090C9C9",
+"lX c #98989898CBCB",
+"zX c #A0A0A0A0CFCF",
+"xX c #A5A5A5A5D3D3",
+"cX c #ABABABABD6D6",
+"vX c #C4C4C4C4E3E3",
+"bX c #D1D1D1D1E9E9",
+"nX c #E5E5E5E5F3F3",
+"mX c #9F9FA0A0D1D1",
+"MX c #B6B6C5C5E5E5",
+"NX c #8E8EA6A6D6D6",
+"BX c #9090A7A7D7D7",
+"VX c #9191A9A9D7D7",
+"CX c #9595ABABD8D8",
+"ZX c #9999AFAFDADA",
+"AX c #9D9DB2B2DCDC",
+"SX c #A1A1B5B5DDDD",
+"DX c #A5A5B8B8DEDE",
+"FX c #A9A9BBBBE0E0",
+"GX c #ACACBDBDE1E1",
+"HX c #B0B0C1C1E3E3",
+"JX c #B4B4C4C4E4E4",
+"KX c #B8B8C7C7E5E5",
+"LX c #BBBBC9C9E6E6",
+"PX c #AEAEC0C0E2E2",
+"IX c #B2B2C3C3E3E3",
+"UX c gray100",
+"YX c None",
+/* pixels */
+"YXX X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X YX",
+"X %X%X%XF.F.F.F.$XD.Z.Z.Z.B.B.B.N.N.=.=.=.*.*.*.&.&. . .| ....} } { { _ _ P P H G G G K S S C o ",
+"X %X%X%X%XF.F.$XD.D.Z.Z.B.A.B.N.N.N.=.=.=.*.*.&.&.%.%.%.| | ..} { { [ _ _ ` U J L G K F Z S C o ",
+"X %X%X%X%XF.F.F.D.D.H.Z.Z.A.B.N.N.N.C.=.=.*.*.&.&. . .%.| | ..} } { [ [ _ P P H G G K F S S C o ",
+"X %XF.%XF.F.$XF.$XZ.Z.Z.B.A.K.Y.7 , - - 1 1 ^.^.~.aX~.q 9 6XY { } { ' _ ] P P H L G K F Z S C o ",
+"X %XF.F.F.F.F.D.D.Z.Z.Z.K.:.1 ; % ; <.hXfXfXdXaXaXsXpXiX!.yXrXo.;.X.[ _ _ ` H H G K K F S S C o ",
+"X F.F.F.F.F.D.D.D.Z.H.Y.1 & & 1.cXmX/.kXfXdXaXaXsXpXiXQ.yXtXeXE.6X5XP.X._ ` J L G G K F Z S C o ",
+"X D.$XF.$XD.D.Z.Z.S.>.% + : vX1.1.cXmX/.dXaXaXsXpXiXQ.uXrXqX8X6X5XT.R.P.X.P ) H G K K S S S m o ",
+"X D.$XD.D.D.D.D.S.6 & $ h bXvXvX1.xX/.kXfXaXsXpXiXQ.yXrXW.E.6X5X4XU.,X:XI.-.` L G G K F Z C C o ",
+"X D.D.D.D.D.Z.H.6 & $ h h h bXvX1.cXmXkX,.dXpXiXQ.yXtXqXwX6X5XT.U.,X:XI.=X*X..` G K K Z S S m o ",
+"X Z.D.Z.H.Z.Z.7 & $ h h nXh bXvX1.cXmXkX,.gXiXQ.uXrXW.E.6X5X4XU.,X:X-XL.J.#XV. .P G F S S C m o ",
+"X Z.Z.Z.H.Z.R % + : bXh h h bXvX1.cX/.kXhX~.Q.yXrXqX9X6X5X4X2X,X:X;X=X*X#XV.M.OX( K Z S S C m o ",
+"X Z.Z.Z.A.A.* & & vXvXbXbXbXvXvX1.xXlXjX^.pXuXrXeXwX6X5X4XU.,X:X-XL.*XG.V.@XOXoXb.( Z S C C V o ",
+"X B.B.B.A.2 % % 1.1.vXvXvXvXvX1.cXzX<.,.gXiXrXW.E.6X5X4XU.,X:XI.=X*X#XV.@XOXn.b.c.x.N S S C m o ",
+"X B.B.B.S.* % ; xX1.1.1.1.1.cXcXzXlXjX^.pXrXeX7X6X5X4XR.,X:X-XL.J.#XV.@XOXn.b.c.XX X$.S C C m o ",
+"X N.N.N.2 O = /.mXxXcXcXcXcXxXzXlXjXhX~.uXeXE.6X5X4XU.,X:X-XL.J.#XV.M.OXn.v.c.z. X|.k.N D V f o ",
+"X N.N.N.- @ > kX<././.mXzXzXlX<.jXhXgXuXeXE.6X5X4X1X,X:XI.L.*X#XV.m.OXn.b.c.z. Xl.j.g./ C m V o ",
+"X N.N.R @ # ,.,.jXkXkX<.kXkXjX,.^.~.uXwXE.6X5X4X1X,X:XI.=XJ.#XC.M.OXn.v.c.z..X|.j.g.d.#.M m B o ",
+"X =.M.< @ * fXfXhXhX,.,.,.hX^.gXpXuXqX9X6X5X4XU.,X:XI.L.*XG.V.+XOXn.b.c.z..X|.[.g.d.a.p.z V B o ",
+"X =.N.- @ NXNXBXBXBXVXCXCXCXCXZXZXZXZXAXAXSXSXSXDXDXDXFXFXFXGXPXPXHXHXIXJXMXMXMXKXKXLXLXLXB d o ",
+"X =.=.* @ 1 dXdXaXaXsXpXiX!.yXrXeXwX6X5X4X<X,X:XI.=X*XG.V.M.OXn.v.c.XX.X|.j.g.d.a.p.i.u.@.f d o ",
+"X *.=.# @ ^.dXaXaXsXpXiXQ.yXrXeXwX6X5XT.U.,X:X-XL.&XG.C.m.OXoXv.c.z..X|.j.g.f.a.p.i.u.t.+.d d o ",
+"X *.*.@ @ NXNXNXBXVXVXCXCXCXCXZXZXZXZXAXAXAXSXSXDXDXDXFXFXGXGXPXPXHXHXJXJXJXMXKXKXKXLXLXLXd n o ",
+"X &.*.@ @ dXaXsXpXiXQ.yXtXeXE.6X5X4XU.>X:XI.L.*XG.V.m.OXoXv.c.z. X|.j.g.d.a.'.i.u.t.r.w.9.d n o ",
+"X &.&.@ @ ~.sXpXiXQ.yXtXW.E.6X5X4X1X,X:XI.=X*X#XC.m.OXn.b.c.z. X|.[.g.f.a.p.i.u.t.r.w.9.0.n a o ",
+"X &.&.@ @ NXNXBXBXVXVXVXCXCXCXZXZXZXZXAXAXSXSXSXDXDXDXFXFXGXGXPXPXHXIXIXJXMXMXKXKXKXLXLXLXn n o ",
+"X %. .# @ q iXQ.yXrXW.0X6X5X4XU.>X:XI.L.*X#XV.@XOXn.b.c.XX.X|.{.g.f.].'.i.u.t.r.w.0._.7.W n a o ",
+"X %. .* # , Q.yXtXeX7X6X5X4XU.,X:X-XL.*X#XV.@XOXn.b.c.XX Xl.{.g.d.a.p.i.u.t.r.e.0._.7.).+.a a o ",
+"X | | - # NXNXNXBXVXVXCXCXCXCXZXZXZXAXAXAXAXSXSXDXDXDXFXFXGXGXPXPXHXHXIXJXMXMXMXKXKXLXLXLXa a o ",
+"X | | < # - rXeX9X6X5X4XU.,X:X-XL.*X#XC.@XOXoXb.c.z. X|.j.h.s.a.'.i.u.t.r.w.9._.7.).5.4.j a p o ",
+"X | } Y # * 9 8X6X5X4X3X,X:XI.=X*XG.V.@XOXn.v.c.XX X|.j.g.f.a.p.i.u.t.r.e.0._.7.).5.4.q.i g p o ",
+"X } } | - # , 6X5X4XR.,X:XI.=X*XG.V.m.OXoXb.c.XX X|.j.g.f.a.p.i.u.t.r.e.9._.7.).5.4.3.~ a s s o ",
+"X } } } 4 # - E 4XU.>X:X-X=XJ.#XV.M.OXoXb.c.XX X|.{.h.d.a.'.i.u.t.r.e.9._.7.).5.4.3.6.z p s s o ",
+"X { { } } - # < U.,X:XI.=X*XG.V.+XOXoXb.c.z. X|.}.g.d.a.'.i.u.t.r.w.0._.7.).5.4.3.2.! g p s s o ",
+"X [ { ' [ 4 * - E :X;XL.J.#XV.m.OXoXb.c.z..X|.j.h.f.a.'.i.u.t.r.w.9._.6.).(.4.3.2.8.k p s s s o ",
+"X [ [ ' _ [ , * , ;XL.J.#XV.@XOXoXv.c.z..X|.{.g.f.a.p.i.u.t.r.w.`._.7.).(.4.3.2.2.^ s p s s s o ",
+"X _ _ _ _ P ] - * 2 *X#XV.m.OXn.v.c.XX X|.j.h.f.a.p.i.u.t.r.w.`._.7.).(.4.3.2.2.Q p s s s b u o ",
+"X ` ` ` ` ` ` 8 - - 7 V.@XOXoXv.c.XX.X|.j.g.d.a.'.i.u.t.r.w.0._.7.).5.4.3.2.2.O.x p s s s u u o ",
+"X P P ) P U U ) 8 - - 7 OXn.v.c.XX X|.j.h.f.a.p.i.u.t.r.w.0._.7.).5.4.3.2.2.O.x s s s s b u u o ",
+"X L L ) H ) L L L 8 1 - 7 b.c.z. X|.j.h.f.a.'.i.u.t.r.w.0._.7.).5.4.3.2.2.Q x p s s s b b u e o ",
+"X L G L G G G G G G G , * 2 T .Xl.j.h.f.a.p.i.u.t.r.e.0._.7.).5.4.3.2.8.^ p p s s s s u u e e o ",
+"X G G G G G G G K K M M 4 , , 3 I g.d.a.p.i.u.t.r.e.`._.7.).5.4.3.7.! k p s p s s s u u u e v o ",
+"X K G K K K K K K Z Z M F F 4 , < 3 I p.i.u.t.r.w.9._.7.).5.4.W ~ z a p p s s b s u u u e e e o ",
+"X F Z F F F F Z Z F F S S S S S w 9 < 2 5 0 l p.e.9.y.a.l ^ j i a p p p s s b b b u e v y r e o ",
+"X S Z Z S Z S Z S S S S S C C C A m d V f m B m B d d n d a a a p s p s s b u u u u e v e r t o ",
+"X S S S S S S S S S S C C C m m A V V B B B d d d n n a a a p p s p s s b u u u e e e c t r t o ",
+"X C C C C C C C C m C A m A m f V f f B d d d n n n a a a a s s s s s u b u u u u v t t r t t o ",
+"YXo o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o YX"
+};
diff --git a/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.m.pm b/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.m.pm
new file mode 100644
index 0000000000..e64aa0cc06
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.m.pm
@@ -0,0 +1,295 @@
+/* XPM */
+static char *ProductIcon32[] = {
+/* columns rows colors chars-per-pixel */
+"32 32 257 2",
+" c black",
+". c gray100",
+"X c #69695A5AE8E8",
+"o c #494949499191",
+"O c #E8E8CBCBE0E0",
+"+ c #DDDDB3B3D2D2",
+"@ c #F0F0DDDDEBEB",
+"# c #CDCD9191BEBE",
+"$ c #C8C88B8BBBBB",
+"% c #CACA9898C2C2",
+"& c #C3C38A8ABBBB",
+"* c #BABA8787B9B9",
+"= c #DCDCC4C4DEDE",
+"- c #C5C5A3A3CACA",
+"; c #ADAD8181B8B8",
+": c #A3A37A7AB5B5",
+"> c #E2E2D6D6E9E9",
+", c #B3B39A9AC4C4",
+"< c #EBEBE3E3F0F0",
+"1 c #C9C9B6B6D6D6",
+"2 c #96967676B8B8",
+"3 c #8C8C7171ABAB",
+"4 c #A4A49292BEBE",
+"5 c #7D7D6565A6A6",
+"6 c #83836D6DABAB",
+"7 c #9A9A8787C2C2",
+"8 c #7B7B6464B7B7",
+"9 c #5E5E50509191",
+"0 c #646457579A9A",
+"q c #85857B7BBEBE",
+"w c #7C7C7373B6B6",
+"e c #62625353D5D5",
+"r c #61615353D4D4",
+"t c #60605252D1D1",
+"y c #5F5F5252D0D0",
+"u c #5F5F5151CFCF",
+"i c #60605353D2D2",
+"p c #5F5F5252CFCF",
+"a c #5E5E5151CDCD",
+"s c #5C5C4F4FC7C7",
+"d c #5F5F5252CDCD",
+"f c #5E5E5151CBCB",
+"g c #5B5B4F4FC4C4",
+"h c #5A5A4E4EC1C1",
+"j c #71716969B0B0",
+"k c #48483E3EADAD",
+"l c #5D5D5151CDCD",
+"z c #5C5C5050C9C9",
+"x c #5D5D5151CBCB",
+"c c #5C5C5050C7C7",
+"v c #5B5B4F4FC6C6",
+"b c #5B5B5050C6C6",
+"n c #59594E4EC1C1",
+"m c #58584D4DBFBF",
+"M c #59594F4FC2C2",
+"N c #5A5A4F4FC2C2",
+"B c #58584D4DBCBC",
+"V c #57574D4DBCBC",
+"C c #59594E4EBEBE",
+"Z c #58584E4EBDBD",
+"A c #58584D4DBBBB",
+"S c #57574D4DBABA",
+"D c #56564D4DB9B9",
+"F c #56564C4CB6B6",
+"G c #55554C4CB6B6",
+"H c #54544B4BB4B4",
+"J c #54544B4BB1B1",
+"K c #53534B4BB1B1",
+"L c #52524A4AAEAE",
+"P c #51514949ACAC",
+"I c #51514949ABAB",
+"U c #474741418787",
+"Y c #32322C2C8F8F",
+"T c #2B2B25257777",
+"R c #36362F2F9696",
+"E c #2B2B26266E6E",
+"W c #4D4D4545ACAC",
+"Q c #55554D4DB8B8",
+"! c #54544C4CB4B4",
+"~ c #54544C4CB3B3",
+"^ c #51514A4AACAC",
+"/ c #51514A4AABAB",
+"( c #50504949A9A9",
+") c #4F4F4949A6A6",
+"_ c #4C4C4747A1A1",
+"` c #4E4E4848A3A3",
+"' c #4D4D4848A1A1",
+"] c #4B4B46469C9C",
+"[ c #4C4C47479E9E",
+"{ c #51514C4CA6A6",
+"} c #A9A9A6A6D5D5",
+"| c #1E1E1A1A6666",
+" . c #292925258181",
+".. c #3D3D39399292",
+"X. c #4A4A46469B9B",
+"o. c #53534E4EABAB",
+"O. c #494945459797",
+"+. c #4A4A46469999",
+"@. c #474744449494",
+"#. c #484845459494",
+"$. c #474744449292",
+"%. c #464643439090",
+"&. c #464642428D8D",
+"*. c #54545050A9A9",
+"=. c #474744448F8F",
+"-. c #4C4C49499999",
+";. c #57575454A6A6",
+":. c #5B5B5757AAAA",
+">. c #545451519B9B",
+",. c #5A5A57579C9C",
+"<. c #65656262A7A7",
+"1. c #68686666A2A2",
+"2. c #CACAC9C9E5E5",
+"3. c #050504045151",
+"4. c #080807075454",
+"5. c #0A0A09095858",
+"6. c #0C0C0A0A5858",
+"7. c #10100E0E6262",
+"8. c #0E0E0D0D5A5A",
+"9. c #121211115D5D",
+"0. c #131312125D5D",
+"q. c #161615156161",
+"w. c #171716166161",
+"e. c #1A1A19196565",
+"r. c #20201E1E7070",
+"t. c #1E1E1D1D6969",
+"y. c #2A2A29297676",
+"u. c #2F2F2D2D7676",
+"i. c #3A3A39398787",
+"p. c #3A3A39398383",
+"a. c #3F3F3E3E8888",
+"s. c #414140408989",
+"d. c #454543438D8D",
+"f. c #444442428B8B",
+"g. c #444443438C8C",
+"h. c #434342428A8A",
+"j. c #434341418888",
+"k. c #434342428989",
+"l. c #424241418787",
+"z. c #434342428787",
+"x. c #424241418585",
+"c. c #41413F3F8181",
+"v. c #414140408282",
+"b. c #484846468D8D",
+"n. c #494948489090",
+"m. c #4B4B4A4A9191",
+"M. c #4B4B49498E8E",
+"N. c #525251519A9A",
+"B. c #525251519999",
+"V. c #565654549A9A",
+"C. c #545453539494",
+"Z. c #60605F5FA7A7",
+"A. c #64646363ABAB",
+"S. c #5A5A59599797",
+"D. c #68686767ADAD",
+"F. c #6C6C6B6BB2B2",
+"G. c #5E5E5D5D9A9A",
+"H. c #76767575BABA",
+"J. c #78787777BBBB",
+"K. c #76767474B5B5",
+"L. c #7E7E7D7DBABA",
+"P. c #A5A5A4A4D2D2",
+"I. c #040404045252",
+"U. c #070707075454",
+"Y. c #070708085353",
+"T. c #080808085454",
+"R. c #0A0A0B0B5757",
+"E. c #0E0E0E0E5A5A",
+"W. c #111112125E5E",
+"Q. c #111111115E5E",
+"!. c #111111115D5D",
+"~. c #111112125D5D",
+"^. c #161616166868",
+"/. c #151516166161",
+"(. c #151515156161",
+"). c #19191A1A6565",
+"_. c #191919196565",
+"`. c #1A1A1A1A6464",
+"'. c #1D1D1E1E6969",
+"]. c #1E1E1E1E6969",
+"[. c #222222226D6D",
+"{. c #272727277171",
+"}. c #2B2B2C2C7676",
+"|. c #2B2B2B2B7676",
+" X c #2B2B2B2B7575",
+".X c #303030307A7A",
+"XX c #303030307979",
+"oX c #353535357F7F",
+"OX c #393939398383",
+"+X c #3A3A3A3A8383",
+"@X c #3F3F3F3F8787",
+"#X c #434343438C8C",
+"$X c #434344448C8C",
+"%X c #424242428686",
+"&X c #414141418484",
+"*X c #484848489191",
+"=X c #484849499090",
+"-X c #4D4D4D4D9696",
+";X c #515151519D9D",
+":X c #4D4D4D4D9595",
+">X c #515152529A9A",
+",X c #515152529999",
+"<X c #525252529A9A",
+"1X c #525252529999",
+"2X c #565657579E9E",
+"3X c #575757579D9D",
+"4X c #5B5B5B5BA2A2",
+"5X c #5F5F6060A6A6",
+"6X c #5F5F5F5FA6A6",
+"7X c #63636464AAAA",
+"8X c #64646464AAAA",
+"9X c #67676767AEAE",
+"0X c #67676868AEAE",
+"qX c #68686868AEAE",
+"wX c #6F6F6F6FB5B5",
+"eX c #6C6C6C6CB1B1",
+"rX c #73737373B8B8",
+"tX c #82828282BEBE",
+"yX c #86868686C2C2",
+"uX c #89898989C4C4",
+"iX c #98989898CBCB",
+"pX c #A0A0A0A0CFCF",
+"aX c #A9A9A9A9D5D5",
+"sX c #B0B0B0B0D8D8",
+"dX c #B8B8B8B8DDDD",
+"fX c #BDBDBDBDE0E0",
+"gX c #D9D9D9D9EDED",
+"hX c #90909191C6C6",
+"jX c #71718989BCBC",
+"kX c #73738B8BBFBF",
+"lX c #72728989BCBC",
+"zX c #79799090C3C3",
+"xX c #7E7E9595C7C7",
+"cX c #81819898CACA",
+"vX c #84849B9BCCCC",
+"bX c #8C8CA3A3D4D4",
+"nX c #71718A8ABCBC",
+"mX c #73738B8BBDBD",
+"MX c #75758D8DBFBF",
+"NX c #74748C8CBEBE",
+"BX c #76768E8EC0C0",
+"VX c #7C7C9494C6C6",
+"CX c #7B7B9393C4C4",
+"ZX c #7F7F9797C9C9",
+"AX c #82829A9ACBCB",
+"SX c #85859E9ECECE",
+"DX c #8888A0A0D1D1",
+"FX c #87879F9FD0D0",
+"GX c #8B8BA4A4D4D4",
+"HX c #8B8BA3A3D4D4",
+"JX c #8989A1A1D2D2",
+"KX c #8D8DA5A5D6D6",
+"LX c #8B8BA3A3D3D3",
+"PX c #8E8EA6A6D6D6",
+"IX c #8D8DA5A5D5D5",
+"UX c gray100",
+"YX c None",
+/* pixels */
+"YXX X X X X X X X X X X X X X X X X X X X X X X X X X X X X X YX",
+"X v.v.v.v.&Xl.z.k.&.d.%.$.@.O.+.] [ _ ` ) ( ^ L K ! G D V m m o ",
+"X c.c.c.v.&Xx.z.f.f.d.%.$.#.O.+.X.[ _ ` ) ( / L K H F D V C n o ",
+"X v.c.v.v.x.x.z.k.f.n.V.,.>.-.+.] [ _ ` ) ( ^ L K H G D V C h o ",
+"X &Xv.&Xx.x.l.j.M.1.4 - - , 7 q J.H.K.j :.*.P L K H F S B C n o ",
+"X x.&Xx.x.z.j.S., = = 1 } iXuXH.rXwXF.qX7XZ.;.o.J ! F S B m n o ",
+"X x.l.z.%Xz.G.1 @ > 2.dXaXiXuXrXwXF.qX8X5X4X2X;X{ H F S V C n o ",
+"X z.j.j.j.C.1 @ < gX2.fXaXpXuXwXeX9X7X5X4X2XN.:X*X_ D S Z m h o ",
+"X k.k.h.b., O > gXgX2.dXaXiXyXF.D.A.Z.4X3X1X:Xn.g.a._ V B m N o ",
+"X f.f.f.3 + = 2.2.2.fXsXpXhXtXD.8XZ.4X2X1X:X*X$X@Xp.i.W C n N o ",
+"X d.&.%.% + 1 dXdXdXsXP.iXyXK.8X5X4X2X>X:X*Xg.a.+XoX.X..m n N o ",
+"X %.=.5 % - P.} aXP.pXiXyXK.D.Z.4X3X1X-Xn.$X@X+XoX.X Xy.W h g o ",
+"X $.$.: # PXIXGXGXLXJXFXFXSXvXAXcXZXxXVXCXzXzXBXMXkXmXnXjXh g o ",
+"X #.@.* $ 7 yXuXyXtXL.K.D.6X4X2X1X:Xo g.a.OXoX.X|.{.[.t. .g v o ",
+"X O.#.$ $ q H.rXwXF.0XA.6X4X2X1X:Xo $Xa.p.oX.X|.{.[.'.`.r.g b o ",
+"X X.+.$ $ PXKXbXbXLXJXDXFXSXvXAXcXZXxXCXCXzXBXBXMXNXmXlXjXb c o ",
+"X ] ] $ $ H.wXF.0X7X6X4X2X<X:Xo #Xa.+XoX.X|.{.[.].)./.~.Q.c z o ",
+"X [ [ & & w F.qX7XZ.4X2X,X:Xo #Xa.+XoX.X}.{.[.'.e./.9.E.^.c z o ",
+"X ' _ * & PXKXbXHXLXJXDXSXSXvXAXcXZXxXVXCXzXzXBXMXNXkXjXjXz x o ",
+"X ` ` : & 2 8XZ.4X2XB.:X*Xg.@Xp.oX.X|.{.[.].).q.!.E.R.U.Y z f o ",
+"X ) ) 5 & ; <.4X2X>X:Xo #Xa.+XoXXX|.{.[.t._.q.~.E.R.4.5.k x a o ",
+"X ( ( I ; * 6 2X>X:X=X$X@X+XoX.X|.{.[.t.e./.W.E.R.Y.3. .z a a o ",
+"X I ^ / 8 * : 0 :X*X#X@X+XoX.X|.{.[.'._.(.~.E.R.T.3.7.k x a p o ",
+"X L L L ^ 2 * 3 m.$Xa.p.oX.X}.{.[.t.).(.~.E.6.T.3.I.R x a a y o ",
+"X J K K K K 2 * 5 s.OXoX.X}.{.[.'._.(.9.8.R.4.3.I.Y x l a p t o ",
+"X ~ H H ! ! ! 2 ; 5 U XX}.{.[.].e.(.W.E.R.U.3.7.R x l u u y t o ",
+"X G F G G G Q Q 8 : 3 9 u.[.]._./.Q.E.R.T.6. .k x a a u t t t o ",
+"X D S D S D S S S V 8 2 6 9 c.E w.0.| T Y k z z a a p t t i r o ",
+"X A V B V V V B B m m n n h h g g g c z z z l l d p y t i r r o ",
+"X m C C C C C C C n n n M N g g b c z z x a a a u y t t r r e o ",
+"X n n n n n h h h N N g g v b s z z z x a p p u t t r r r e e o ",
+"YXo o o o o o o o o o o o o o o o o o o o o o o o o o o o o o YX"
+};
diff --git a/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.s.pm b/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.s.pm
new file mode 100644
index 0000000000..e2b9379f3a
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.s.pm
@@ -0,0 +1,287 @@
+/* XPM */
+static char *ProductIcon24[] = {
+/* columns rows colors chars-per-pixel */
+"24 24 257 2",
+" c black",
+". c gray100",
+"X c #69695A5AE8E8",
+"o c #494949499191",
+"O c #F1F1DFDFECEC",
+"+ c #D7D7ACACCDCD",
+"@ c #DFDFBBBBD6D6",
+"# c #E2E2C4C4DBDB",
+"$ c #CECE9C9CC4C4",
+"% c #C4C48B8BBABA",
+"& c #C2C28A8ABABA",
+"* c #C4C48E8EBCBC",
+"= c #BFBF8A8AB9B9",
+"- c #EBEBD9D9E9E9",
+"; c #BFBF8888B9B9",
+": c #D8D8B9B9D6D6",
+"> c #B9B98686B9B9",
+", c #B8B88989B9B9",
+"< c #BBBB9393BFBF",
+"1 c #A9A97B7BB2B2",
+"2 c #E4E4D4D4E7E7",
+"3 c #C6C6AFAFCECE",
+"4 c #A6A68080B6B6",
+"5 c #A2A27E7EB4B4",
+"6 c #9E9E7E7EB1B1",
+"7 c #ABAB9090BBBB",
+"8 c #B7B7A0A0C5C5",
+"9 c #9D9D7C7CB2B2",
+"0 c #AAAA8B8BBEBE",
+"q c #AAAA9090BCBC",
+"w c #8C8C6B6BABAB",
+"e c #90907070B1B1",
+"r c #C4C4B3B3D7D7",
+"t c #CDCDBFBFDDDD",
+"y c #EAEAE4E4F1F1",
+"u c #88886A6AADAD",
+"i c #9E9E8585C1C1",
+"p c #84846A6AAFAF",
+"a c #81816B6BAAAA",
+"s c #D7D7CFCFE6E6",
+"d c #81816969B1B1",
+"f c #78786363A5A5",
+"g c #6E6E5D5D9C9C",
+"h c #717160609D9D",
+"j c #83837474AAAA",
+"k c #6A6A5757A3A3",
+"l c #6E6E5E5EA0A0",
+"z c #5E5E50509292",
+"x c #88887B7BBCBC",
+"c c #68685858ABAB",
+"v c #5A5A4D4DA2A2",
+"b c #7D7D7373B4B4",
+"n c #5A5A4E4EA6A6",
+"m c #5F5F56569595",
+"M c #56564A4ABBBB",
+"N c #56564949B9B9",
+"B c #55554949B8B8",
+"V c #53534848B3B3",
+"C c #54544949B4B4",
+"Z c #52524747B0B0",
+"A c #52524747AFAF",
+"S c #5B5B53539393",
+"D c #3E3E36369797",
+"F c #49494040A6A6",
+"G c #48484040A5A5",
+"H c #55554A4ABABA",
+"J c #54544949B7B7",
+"K c #53534949B4B4",
+"L c #51514747AFAF",
+"P c #52524848B1B1",
+"I c #51514848B0B0",
+"U c #51514848AEAE",
+"Y c #51514747ADAD",
+"T c #51514848ADAD",
+"R c #4F4F4747ABAB",
+"E c #50504747ABAB",
+"W c #50504646A9A9",
+"Q c #4F4F4646A8A8",
+"! c #4E4E4646A7A7",
+"~ c #4E4E4545A4A4",
+"^ c #4D4D4545A4A4",
+"/ c #4E4E4646A5A5",
+"( c #4D4D4545A1A1",
+") c #3D3D36367E7E",
+"_ c #4B4B44449C9C",
+"` c #2A2A25257F7F",
+"' c #3E3E37379898",
+"] c #474740409C9C",
+"[ c #4D4D4646A4A4",
+"{ c #4C4C4545A2A2",
+"} c #4D4D4646A2A2",
+"| c #4D4D4646A1A1",
+" . c #4B4B45459F9F",
+".. c #4C4C45459F9F",
+"X. c #4C4C46469F9F",
+"o. c #4B4B45459D9D",
+"O. c #494943439898",
+"+. c #494944449A9A",
+"@. c #4A4A45459A9A",
+"#. c #494944449898",
+"$. c #484843439696",
+"%. c #494944449797",
+"&. c #484843439595",
+"*. c #51514C4CA1A1",
+"=. c #6B6B6767AEAE",
+"-. c #95959191C9C9",
+";. c #23231F1F7676",
+":. c #21211E1E7070",
+">. c #292925257F7F",
+",. c #252521217070",
+"<. c #242421216D6D",
+"1. c #2B2B27278080",
+"2. c #393935358C8C",
+"3. c #444440409494",
+"4. c #3B3B38388282",
+"5. c #474743439494",
+"6. c #484844449595",
+"7. c #474743439393",
+"8. c #474744449393",
+"9. c #464643439191",
+"0. c #454542428F8F",
+"q. c #4A4A47479898",
+"w. c #464643438F8F",
+"e. c #454542428D8D",
+"r. c #444441418B8B",
+"t. c #484844449191",
+"y. c #444441418989",
+"u. c #494946469090",
+"i. c #4C4C48489393",
+"p. c #51514E4E9E9E",
+"a. c #73737070B6B6",
+"s. c #77777474BBBB",
+"d. c #A0A09E9ED1D1",
+"f. c #D6D6D5D5EBEB",
+"g. c #0E0E0D0D5A5A",
+"h. c #11110F0F5E5E",
+"j. c #121211115E5E",
+"k. c #131312125F5F",
+"l. c #171716166363",
+"z. c #1D1D1B1B6868",
+"x. c #1D1D1C1C6868",
+"c. c #222221216E6E",
+"v. c #222221216D6D",
+"b. c #282827277474",
+"n. c #282827277373",
+"m. c #292928287373",
+"M. c #2F2F2E2E7979",
+"N. c #353534347F7F",
+"B. c #363635358181",
+"V. c #3C3C3B3B8585",
+"C. c #424241418C8C",
+"Z. c #424241418B8B",
+"A. c #444442428B8B",
+"S. c #434341418989",
+"D. c #434342428989",
+"F. c #424241418787",
+"G. c #414140408484",
+"H. c #474745458D8D",
+"J. c #434342428787",
+"K. c #424241418585",
+"L. c #414140408282",
+"P. c #494948489191",
+"I. c #4F4F4E4E9797",
+"U. c #59595757A6A6",
+"Y. c #5F5F5D5DA4A4",
+"T. c #6C6C6B6BB3B3",
+"R. c #7C7C7B7BB9B9",
+"E. c #A8A8A7A7D3D3",
+"W. c #0D0D0D0D5A5A",
+"Q. c #1F1F1F1F6C6C",
+"!. c #222222226E6E",
+"~. c #3B3B3B3B8585",
+"^. c #414141418C8C",
+"/. c #414141418B8B",
+"(. c #424242428B8B",
+"). c #484848489292",
+"_. c #404040408181",
+"`. c #4E4E4E4E9898",
+"'. c #555555559E9E",
+"]. c #555555559D9D",
+"[. c #5B5B5B5BA3A3",
+"{. c #5C5C5C5CA3A3",
+"}. c #61616161A9A9",
+"|. c #66666666AEAE",
+" X c #66666666ADAD",
+".X c #6B6B6B6BB2B2",
+"XX c #70707070B7B7",
+"oX c #6A6A6A6AADAD",
+"OX c #74747474BBBB",
+"+X c #89898989C2C2",
+"@X c #90909090C8C8",
+"#X c #8F8F8F8FC6C6",
+"$X c #92929292C6C6",
+"%X c #9F9F9F9FCFCF",
+"&X c #A5A5A5A5D2D2",
+"*X c #B5B5B5B5DBDB",
+"=X c #B8B8B8B8DEDE",
+"-X c #B7B7B7B7DCDC",
+";X c #BBBBBBBBDEDE",
+":X c #BDBDBDBDDFDF",
+">X c #C9C9C9C9E5E5",
+",X c #D1D1D1D1EAEA",
+"<X c #7C7C7D7DBABA",
+"1X c #89898A8AC7C7",
+"2X c #8F8F9090C7C7",
+"3X c #A3A3A4A4D3D3",
+"4X c #A2A2B5B5DEDE",
+"5X c #ADADBDBDE1E1",
+"6X c #B9B9C7C7E5E5",
+"7X c #BABAC8C8E6E6",
+"8X c #8E8EA6A6D6D6",
+"9X c #9090A7A7D7D7",
+"0X c #9191A9A9D7D7",
+"qX c #9292A9A9D8D8",
+"wX c #9494ABABD8D8",
+"eX c #9898AEAED9D9",
+"rX c #9B9BB0B0DADA",
+"tX c #9E9EB3B3DCDC",
+"yX c #A1A1B5B5DDDD",
+"uX c #A5A5B8B8DEDE",
+"iX c #A8A8BBBBE0E0",
+"pX c #ACACBEBEE1E1",
+"aX c #AFAFC0C0E3E3",
+"sX c #B3B3C3C3E4E4",
+"dX c #B2B2C2C2E3E3",
+"fX c #B5B5C5C5E5E5",
+"gX c #B8B8C7C7E6E6",
+"hX c #B6B6C5C5E4E4",
+"jX c #9797AEAED9D9",
+"kX c #A1A1B6B6DDDD",
+"lX c #A8A8BBBBDFDF",
+"zX c gray100",
+"xX c black",
+"cX c black",
+"vX c black",
+"bX c black",
+"nX c black",
+"mX c black",
+"MX c black",
+"NX c black",
+"BX c black",
+"VX c black",
+"CX c black",
+"ZX c black",
+"AX c black",
+"SX c black",
+"DX c black",
+"FX c black",
+"GX c black",
+"HX c black",
+"JX c black",
+"KX c black",
+"LX c black",
+"PX c black",
+"IX c black",
+"UX c black",
+"YX c None",
+/* pixels */
+"YXX X X X X X X X X X X X X X X X X X X X X X YX",
+"X _._.L.G.K.F.D.A.e.0.9.&.$.%.+._ ..{ ^ ! W E o ",
+"X L.L.L.G.F.F.D.r.e.0.9.7.&.O.@.o. .{ ~ ! Q E o ",
+"X L.G.G.K.F.S.y.r.e.w.9.5.$.+.@.o...( ~ ! W E o ",
+"X G.K.K.F.J.D.h 6 0 i x s.a.=.U.*...} ~ ! W E o ",
+"X K.F.F.F.S 7 : r d.1XOXXX.X|.}.[.p.| / ! W E o ",
+"X F.F.F.m 3 - s =X3X@XXXT. X}.[.].I.q.{ Q E T o ",
+"X S.D.H.8 O y ,X;X&X2X.X|.}.[.].I.P.C.3.Q E Y o ",
+"X A.r.j # 2 f.>X*X%X+X|.}.[.].I.P.^.~.B.] E Y o ",
+"X e.u.q @ t :X-XE.$X<X}.[.].`.P.Z.V.N.M.2.Y L o ",
+"X 0.i.< + 8X8XqXwXeXrXtX4XuXlXpXaXsXfXgX7XY A o ",
+"X 9.t.* $ -.#X+XR.oX{.'.`.P.(.~.N.M.m.c.Q.T Z o ",
+"X 8.7.; % 8X9X0XwXeXrXtXyXuXiXpXaXdXfXgX7XL Z o ",
+"X 6.&.1 & b X}.[.'.I.P./.~.N.M.n.!.x.l.:.I P o ",
+"X #.#.w = 8X9XqXwXjXrXtXkXuXiX5XaXsXhX6X7XP V o ",
+"X +.+.k > 5 Y.].I.)./.~.N.M.b.v.x.l.k.h.' V C o ",
+"X o.o.o.u , a I.).Z.V.N.M.n.c.z.l.j.W.` P V C o ",
+"X .. .X.v e 4 l ^.V.N.M.m.!.x.l.j.g.;.F V C J o ",
+"X ( | ( ( n p 9 g 4.M.n.c.x.l.j.h.>.G V K C J o ",
+"X ~ [ [ ^ / / c d f z ) <.z.,.1.D P V C C B B o ",
+"X ! Q ! Q Q Q Q W E E Y T A Z P V V K C J B B o ",
+"X Q W Q W R W E E T T T L Z P V V K J J J B N o ",
+"X R E E E E E Y Y U L Z P P P C V J J B B H M o ",
+"YXo o o o o o o o o o o o o o o o o o o o o o YX"
+};
diff --git a/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.t.pm b/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.t.pm
new file mode 100644
index 0000000000..3f6b21f428
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.t.pm
@@ -0,0 +1,279 @@
+/* XPM */
+static char *ProductIcon16[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 257 2",
+" c black",
+". c gray100",
+"X c #E2E2C0C0D9D9",
+"o c #EDEDD9D9E8E8",
+"O c #D5D5ABABCDCD",
+"+ c #E2E2C3C3DCDC",
+"@ c #C5C58E8EBCBC",
+"# c #D4D4ABABCDCD",
+"$ c #CACA9F9FC6C6",
+"% c #D6D6B4B4D3D3",
+"& c #CACAA0A0C8C8",
+"* c #C6C69D9DC6C6",
+"= c #C5C59F9FC8C8",
+"- c #CCCCACACCECE",
+"; c #CCCCB0B0D3D3",
+": c #A6A68383B3B3",
+"> c #BABA9A9AC6C6",
+", c #B7B79A9AC2C2",
+"< c #E3E3D5D5E9E9",
+"1 c #B0B08E8EC0C0",
+"2 c #9F9F8080B8B8",
+"3 c #AFAF9898C1C1",
+"4 c #DBDBCFCFE5E5",
+"5 c #96967878B2B2",
+"6 c #9A9A7E7EBABA",
+"7 c #8E8E7878AFAF",
+"8 c #91917F7FBDBD",
+"9 c #D3D3CCCCE4E4",
+"0 c #535348488B8B",
+"q c #69695A5AE8E8",
+"w c #55554949B9B9",
+"e c #55554949B8B8",
+"r c #54544848B6B6",
+"t c #53534848B4B4",
+"y c #54544848B4B4",
+"u c #53534848B3B3",
+"i c #53534848B2B2",
+"p c #52524747AFAF",
+"a c #53534848B1B1",
+"s c #54544949B8B8",
+"d c #54544949B6B6",
+"f c #52524848B3B3",
+"g c #52524848B2B2",
+"h c #53534949B3B3",
+"j c #52524848B1B1",
+"k c #52524848B0B0",
+"l c #51514747AEAE",
+"z c #52524848AFAF",
+"x c #51514848AEAE",
+"c c #51514747ADAD",
+"v c #51514747ACAC",
+"b c #4F4F4646AAAA",
+"n c #51514848ADAD",
+"m c #50504747ABAB",
+"M c #50504747AAAA",
+"N c #4F4F4646A8A8",
+"B c #50504747A9A9",
+"V c #4E4E4646A7A7",
+"C c #4E4E4646A6A6",
+"Z c #4F4F4646A6A6",
+"A c #4F4F4747A7A7",
+"S c #4D4D4545A3A3",
+"D c #4D4D4545A2A2",
+"F c #4C4C45459E9E",
+"G c #74746E6EB3B3",
+"H c #2E2E29298383",
+"J c #383832329090",
+"K c #464640409999",
+"L c #4D4D4646A2A2",
+"P c #4E4E4747A3A3",
+"I c #4B4B45459F9F",
+"U c #4B4B45459E9E",
+"Y c #4C4C46469F9F",
+"T c #4A4A44449B9B",
+"R c #4A4A44449A9A",
+"E c #494943439797",
+"W c #494944449797",
+"Q c #484843439494",
+"! c #78787474B8B8",
+"~ c #272724247878",
+"^ c #2D2D2A2A7575",
+"/ c #484844449797",
+"( c #474743439393",
+") c #454542429090",
+"_ c #4B4B48489A9A",
+"` c #464643438F8F",
+"' c #464643438E8E",
+"] c #454542428C8C",
+"[ c #51514D4DA0A0",
+"{ c #5C5C5959A5A5",
+"} c #535350509090",
+"| c #C8C8C7C7E3E3",
+" . c #121211115D5D",
+".. c #1A1A19196565",
+"X. c #242422226D6D",
+"o. c #3F3F3E3E8888",
+"O. c #444442428D8D",
+"+. c #444442428989",
+"@. c #424241418787",
+"#. c #454543438A8A",
+"$. c #434342428888",
+"%. c #424241418686",
+"&. c #414140408484",
+"*. c #414140408383",
+"=. c #424240408383",
+"-. c #414140408282",
+";. c #474746468D8D",
+":. c #464644448989",
+">. c #525251519999",
+",. c #64646363AAAA",
+"<. c #61615F5FA2A2",
+"1. c #6E6E6C6CB2B2",
+"2. c #A5A5A4A4D3D3",
+"3. c #B0B0AFAFD6D6",
+"4. c #111112125D5D",
+"5. c #19191A1A6565",
+"6. c #1E1E1E1E6C6C",
+"7. c #222222226D6D",
+"8. c #2B2B2B2B7676",
+"9. c #2B2B2B2B7575",
+"0. c #2B2B2C2C7575",
+"q. c #343435357F7F",
+"w. c #343435357E7E",
+"e. c #353535357F7F",
+"r. c #3E3E3E3E8888",
+"t. c #3E3E3E3E8787",
+"y. c #414141418484",
+"u. c #404040408282",
+"i. c #484849499191",
+"p. c #494949499191",
+"a. c #484848489090",
+"s. c #484849499090",
+"d. c #404040408080",
+"f. c #525252529A9A",
+"g. c #525252529999",
+"h. c #5B5B5B5BA3A3",
+"j. c #5B5B5B5BA2A2",
+"k. c #64646464ABAB",
+"l. c #63636464AAAA",
+"z. c #6B6B6C6CB2B2",
+"x. c #72727373B9B9",
+"c. c #71717171A4A4",
+"v. c #78787878ABAB",
+"b. c #7F7F7F7FB1B1",
+"n. c #8C8C8C8CBEBE",
+"m. c #A5A5A5A5D2D2",
+"M. c #C9C9C9C9E5E5",
+"N. c #85858686B7B7",
+"B. c #91919292C4C4",
+"V. c #71718989BCBC",
+"C. c #73738B8BBEBE",
+"Z. c #75758D8DC0C0",
+"A. c #78789090C3C3",
+"S. c #7A7A9292C5C5",
+"D. c #71718A8ABDBD",
+"F. c #76768E8EC0C0",
+"G. c #78789090C2C2",
+"H. c #7B7B9393C5C5",
+"J. c #7D7D9595C7C7",
+"K. c #80809999CACA",
+"L. c #7E7E9696C7C7",
+"P. c #83839B9BCDCD",
+"I. c #83839B9BCCCC",
+"U. c #86869E9ECFCF",
+"Y. c #8888A1A1D1D1",
+"T. c #8A8AA2A2D3D3",
+"R. c #8989A1A1D1D1",
+"E. c #8B8BA3A3D3D3",
+"W. c gray100",
+"Q. c black",
+"!. c black",
+"~. c black",
+"^. c black",
+"/. c black",
+"(. c black",
+"). c black",
+"_. c black",
+"`. c black",
+"'. c black",
+"]. c black",
+"[. c black",
+"{. c black",
+"}. c black",
+"|. c black",
+" X c black",
+".X c black",
+"XX c black",
+"oX c black",
+"OX c black",
+"+X c black",
+"@X c black",
+"#X c black",
+"$X c black",
+"%X c black",
+"&X c black",
+"*X c black",
+"=X c black",
+"-X c black",
+";X c black",
+":X c black",
+">X c black",
+",X c black",
+"<X c black",
+"1X c black",
+"2X c black",
+"3X c black",
+"4X c black",
+"5X c black",
+"6X c black",
+"7X c black",
+"8X c black",
+"9X c black",
+"0X c black",
+"qX c black",
+"wX c black",
+"eX c black",
+"rX c black",
+"tX c black",
+"yX c black",
+"uX c black",
+"iX c black",
+"pX c black",
+"aX c black",
+"sX c black",
+"dX c black",
+"fX c black",
+"gX c black",
+"hX c black",
+"jX c black",
+"kX c black",
+"lX c black",
+"zX c black",
+"xX c black",
+"cX c black",
+"vX c black",
+"bX c black",
+"nX c black",
+"mX c black",
+"MX c black",
+"NX c black",
+"BX c black",
+"VX c black",
+"CX c black",
+"ZX c black",
+"AX c black",
+"SX c black",
+"DX c black",
+"FX c black",
+"GX c black",
+"HX c black",
+"JX c black",
+"KX c black",
+"LX c black",
+"PX c black",
+"IX c black",
+"UX c black",
+"YX c None",
+/* pixels */
+"YXq q q q q q q q q q q q q q YX",
+"q d.-.y.%.+.O.` ( E R U D C B p.",
+"q u.*.&.$.#.] ) Q W T F L V M p.",
+"q =.y.} , % ; 8 ! 1.{ [ S Z b p.",
+"q @.:.- o 4 2.x.z.,.j.>._ A m p.",
+"q +.: X < M.m.z.l.j.g.s.r.K v p.",
+"q ' $ + 9 | 3.B.n.N.b.v.c.<.n p.",
+"q ` O T.Y.U.P.K.L.S.G.F.C.D.l p.",
+"q ( # @ G k.h.g.i.t.e.9.7.6.z p.",
+"q / * E.R.U.I.K.J.H.A.Z.C.V.a p.",
+"q T 2 & 5 f.a.o.q.8.7...4.J u p.",
+"q I Y 1 = 7 ;.w.0.7.5. .H f y p.",
+"q L D P 6 > 3 0 ^ X.~ J i t d p.",
+"q C C V A N M m n p k g y r e p.",
+"q M b M m m c x p j h y d s w p.",
+"YXp.p.p.p.p.p.p.p.p.p.p.p.p.p.YX"
+};
diff --git a/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/qpidmc b/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/qpidmc
new file mode 100755
index 0000000000..b88ff49e8e
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/qpidmc
Binary files differ
diff --git a/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/qpidmc.ini b/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/qpidmc.ini
new file mode 100644
index 0000000000..cfa715e5a8
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/qpidmc.ini
@@ -0,0 +1,40 @@
+###############################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+###############################################################################
+-startup
+plugins/org.eclipse.equinox.launcher_1.0.101.R34x_v20080819.jar
+--launcher.library
+plugins/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731
+-vmargs
+-Xms40m
+-Xmx256m
+-XX:MaxPermSize=256m
+-Dosgi.requiredJavaVersion=1.5
+-Declipse.consoleLog=true
+
+#===============================================
+# SSL trust store configuration options.
+#===============================================
+
+# Uncomment lines below to specify custom truststore for server SSL
+# certificate verification, eg when using self-signed server certs.
+#
+#-Djavax.net.ssl.trustStore=<path.to.truststore>
+#-Djavax.net.ssl.trustStorePassword=<truststore.password>
+
+
diff --git a/java/management/eclipse-plugin/src/main/resources/startup.jar b/java/management/eclipse-plugin/src/main/resources/startup.jar
deleted file mode 100644
index 2f26eceece..0000000000
--- a/java/management/eclipse-plugin/src/main/resources/startup.jar
+++ /dev/null
Binary files differ
diff --git a/java/management/eclipse-plugin/src/main/resources/unix/configuration/config.ini b/java/management/eclipse-plugin/src/main/resources/unix/configuration/config.ini
deleted file mode 100644
index aa2d21fd48..0000000000
--- a/java/management/eclipse-plugin/src/main/resources/unix/configuration/config.ini
+++ /dev/null
@@ -1,27 +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.
-###############################################################################
-
-#Product Runtime Configuration File
-
-osgi.splashPath=platform:/base/plugins/org.apache.qpid.management.ui
-eclipse.product=org.apache.qpid.management.ui.product
-eclipse.application=org.apache.qpid.management.ui.application
-osgi.bundles=org.eclipse.equinox.common@2:start,org.eclipse.core.runtime@start,com.ibm.icu,org.apache.qpid.management.ui,org.eclipse.core.commands,org.eclipse.core.contenttype,org.eclipse.core.expressions,org.eclipse.core.jobs,org.eclipse.core.runtime.compatibility.auth,org.eclipse.core.runtime.compatibility.registry,org.eclipse.equinox.preferences,org.eclipse.equinox.registry,org.eclipse.help,org.eclipse.jface,org.eclipse.swt,org.eclipse.swt.motif.linux.x86,org.eclipse.swt.gtk.linux.x86_64,org.eclipse.swt.gtk.linux.x86,org.eclipse.swt.gtk.linux.ppc,org.eclipse.swt.motif.hpux.PA_RISC,org.eclipse.swt.gtk.solaris.sparc,org.eclipse.swt.motif.solaris.sparc,org.eclipse.swt.carbon.macocx,org.eclipse.ui,org.eclipse.ui.forms,org.eclipse.ui.workbench
-osgi.bundles.defaultStartLevel=4
-eof=eof \ No newline at end of file
diff --git a/java/management/eclipse-plugin/src/main/resources/win32-win32-x86/Configuration/config.ini b/java/management/eclipse-plugin/src/main/resources/win32-win32-x86/Configuration/config.ini
new file mode 100644
index 0000000000..a61bea2fa8
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/win32-win32-x86/Configuration/config.ini
@@ -0,0 +1,49 @@
+###############################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+###############################################################################
+
+#Product Runtime Configuration File
+
+osgi.splashPath=platform:/base/plugins/org.apache.qpid.management.ui
+eclipse.product=org.apache.qpid.management.ui.product
+osgi.bundles.defaultStartLevel=4
+osgi.bundles=jmxremote.sasl, \
+qpid-management-common, \
+org.apache.qpid.management.ui, \
+com.ibm.icu, \
+org.eclipse.core.commands, \
+org.eclipse.core.contenttype, \
+org.eclipse.core.databinding, \
+org.eclipse.core.expressions, \
+org.eclipse.core.jobs, \
+org.eclipse.core.runtime@start, \
+org.eclipse.core.runtime.compatibility.registry, \
+org.eclipse.equinox.app,org.eclipse.equinox.common, \
+org.eclipse.equinox.preferences, \
+org.eclipse.equinox.registry, \
+org.eclipse.help, \
+org.eclipse.jface, \
+org.eclipse.jface.databinding, \
+org.eclipse.swt, \
+org.eclipse.swt.win32.win32.x86, \
+org.eclipse.ui, \
+org.eclipse.ui.forms, \
+org.eclipse.ui.workbench, \
+org.eclipse.equinox.launcher, \
+org.eclipse.equinox.launcher.win32.win32.x86, \
+org.apache.commons.codec
diff --git a/java/management/eclipse-plugin/src/main/resources/win32-win32-x86/qpidmc.exe b/java/management/eclipse-plugin/src/main/resources/win32-win32-x86/qpidmc.exe
new file mode 100644
index 0000000000..3999884bfb
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/win32-win32-x86/qpidmc.exe
Binary files differ
diff --git a/java/management/eclipse-plugin/src/main/resources/win32-win32-x86/qpidmc.ini b/java/management/eclipse-plugin/src/main/resources/win32-win32-x86/qpidmc.ini
new file mode 100644
index 0000000000..312580769e
--- /dev/null
+++ b/java/management/eclipse-plugin/src/main/resources/win32-win32-x86/qpidmc.ini
@@ -0,0 +1,36 @@
+###############################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+###############################################################################
+
+-vmargs
+-Xms40m
+-Xmx256m
+-XX:MaxPermSize=256m
+-Dosgi.requiredJavaVersion=1.5
+-Declipse.consoleLog=true
+
+#===============================================
+# SSL trust store configuration options.
+#===============================================
+
+# Uncomment lines below to specify custom truststore for server SSL
+# certificate verification, eg when using self-signed server certs.
+#
+#-Djavax.net.ssl.trustStore=<path.to.truststore>
+#-Djavax.net.ssl.trustStorePassword=<truststore.password>
+
diff --git a/java/management/eclipse-plugin/src/main/resources/win32/configuration/config.ini b/java/management/eclipse-plugin/src/main/resources/win32/configuration/config.ini
deleted file mode 100644
index e83321e650..0000000000
--- a/java/management/eclipse-plugin/src/main/resources/win32/configuration/config.ini
+++ /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.
-###############################################################################
-
-#Product Runtime Configuration File
-
-osgi.splashPath=platform:/base/plugins/org.apache.qpid.management.ui
-eclipse.product=org.apache.qpid.management.ui.product
-eclipse.application=org.apache.qpid.management.ui.application
-osgi.bundles=org.eclipse.equinox.common@2:start,org.eclipse.core.runtime@start,com.ibm.icu,org.apache.qpid.management.ui,org.eclipse.core.commands,org.eclipse.core.contenttype,org.eclipse.core.expressions,org.eclipse.core.jobs,org.eclipse.core.runtime.compatibility.auth,org.eclipse.core.runtime.compatibility.registry,org.eclipse.equinox.preferences,org.eclipse.equinox.registry,org.eclipse.help,org.eclipse.jface,org.eclipse.swt,org.eclipse.swt.win32.win32.x86,org.eclipse.ui,org.eclipse.ui.forms,jmxremote.sasl,org.eclipse.ui.workbench
-osgi.bundles.defaultStartLevel=4
diff --git a/java/management/eclipse-plugin/src/test/java/org/apache/qpid/management/ui/ApiVersionTest.java b/java/management/eclipse-plugin/src/test/java/org/apache/qpid/management/ui/ApiVersionTest.java
new file mode 100644
index 0000000000..b4f6aea57b
--- /dev/null
+++ b/java/management/eclipse-plugin/src/test/java/org/apache/qpid/management/ui/ApiVersionTest.java
@@ -0,0 +1,177 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui;
+
+import junit.framework.TestCase;
+
+public class ApiVersionTest extends TestCase
+{
+
+ public void testGetMajor()
+ {
+ ApiVersion ver = new ApiVersion(1,3);
+ assertEquals(1, ver.getMajor());
+ }
+
+ public void testGetMinor()
+ {
+ ApiVersion ver = new ApiVersion(1,3);
+ assertEquals(3, ver.getMinor());
+ }
+
+ public void testGreaterThanOrEqualTo()
+ {
+ ApiVersion ver = new ApiVersion(1,3);
+
+ //equal
+ assertTrue(ver.greaterThanOrEqualTo(1, 3));
+ //same major, higher minor
+ assertFalse(ver.greaterThanOrEqualTo(1, 4));
+ //same major, lower minor
+ assertTrue(ver.greaterThanOrEqualTo(1, 2));
+
+ //higher major, lower minor
+ assertFalse(ver.greaterThanOrEqualTo(2, 0));
+ //higher major, same minor
+ assertFalse(ver.greaterThanOrEqualTo(2, 3));
+ //higher major, higher minor
+ assertFalse(ver.greaterThanOrEqualTo(2, 4));
+
+ //lower major, higher minor
+ assertTrue(ver.greaterThanOrEqualTo(0, 9));
+ //lower major, lower minor
+ assertTrue(ver.greaterThanOrEqualTo(0, 2));
+ //lower major, same minor
+ assertTrue(ver.greaterThanOrEqualTo(0, 3));
+ }
+
+ public void testLessThanOrEqualTo()
+ {
+ ApiVersion ver = new ApiVersion(1,3);
+
+ //equal
+ assertTrue(ver.lessThanOrEqualTo(1, 3));
+ //same major, higher minor
+ assertTrue(ver.lessThanOrEqualTo(1, 4));
+ //same major, lower minor
+ assertFalse(ver.lessThanOrEqualTo(1, 2));
+
+ //higher major, lower minor
+ assertTrue(ver.lessThanOrEqualTo(2, 0));
+ //higher major, same minor
+ assertTrue(ver.lessThanOrEqualTo(2, 3));
+ //higher major, higher minor
+ assertTrue(ver.lessThanOrEqualTo(2, 4));
+
+ //lower major, higher minor
+ assertFalse(ver.lessThanOrEqualTo(0, 9));
+ //lower major, lower minor
+ assertFalse(ver.lessThanOrEqualTo(0, 2));
+ //lower major, same minor
+ assertFalse(ver.lessThanOrEqualTo(0, 3));
+ }
+
+ public void testGreaterThan()
+ {
+ ApiVersion ver = new ApiVersion(1,3);
+
+ //equal
+ assertFalse(ver.greaterThan(1, 3));
+ //same major, higher minor
+ assertFalse(ver.greaterThan(1, 4));
+ //same major, lower minor
+ assertTrue(ver.greaterThan(1, 2));
+
+ //higher major, lower minor
+ assertFalse(ver.greaterThan(2, 0));
+ //higher major, same minor
+ assertFalse(ver.greaterThan(2, 3));
+ //higher major, higher minor
+ assertFalse(ver.greaterThan(2, 4));
+
+ //lower major, higher minor
+ assertTrue(ver.greaterThan(0, 9));
+ //lower major, lower minor
+ assertTrue(ver.greaterThan(0, 2));
+ //lower major, same minor
+ assertTrue(ver.greaterThan(0, 3));
+ }
+
+ public void testLessThan()
+ {
+ ApiVersion ver = new ApiVersion(1,3);
+
+ //equal
+ assertFalse(ver.lessThan(1, 3));
+ //same major, higher minor
+ assertTrue(ver.lessThan(1, 4));
+ //same major, lower minor
+ assertFalse(ver.lessThan(1, 2));
+
+ //higher major, lower minor
+ assertTrue(ver.lessThan(2, 0));
+ //higher major, same minor
+ assertTrue(ver.lessThan(2, 3));
+ //higher major, higher minor
+ assertTrue(ver.lessThan(2, 4));
+
+ //lower major, higher minor
+ assertFalse(ver.lessThan(0, 9));
+ //lower major, lower minor
+ assertFalse(ver.lessThan(0, 2));
+ //lower major, same minor
+ assertFalse(ver.lessThan(0, 3));
+ }
+
+ public void testEqualsIntInt()
+ {
+ ApiVersion ver = new ApiVersion(1,3);
+
+ //equal
+ assertTrue(ver.equals(1, 3));
+ //same major, higher minor
+ assertFalse(ver.equals(1, 4));
+ //same major, lower minor
+ assertFalse(ver.equals(1, 2));
+
+ //higher major, lower minor
+ assertFalse(ver.equals(2, 0));
+ //higher major, same minor
+ assertFalse(ver.equals(2, 3));
+ //higher major, higher minor
+ assertFalse(ver.equals(2, 4));
+
+ //lower major, higher minor
+ assertFalse(ver.equals(0, 9));
+ //lower major, lower minor
+ assertFalse(ver.equals(0, 2));
+ //lower major, same minor
+ assertFalse(ver.equals(0, 3));
+ }
+
+ public void testToString()
+ {
+ ApiVersion ver = new ApiVersion(1,3);
+
+ assertEquals("major=1,minor=3", ver.toString());
+ }
+
+}
diff --git a/java/management/eclipse-plugin/src/test/java/org/apache/qpid/management/ui/ApplicationRegistryTest.java b/java/management/eclipse-plugin/src/test/java/org/apache/qpid/management/ui/ApplicationRegistryTest.java
new file mode 100644
index 0000000000..1a56ab69b6
--- /dev/null
+++ b/java/management/eclipse-plugin/src/test/java/org/apache/qpid/management/ui/ApplicationRegistryTest.java
@@ -0,0 +1,43 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui;
+
+import org.apache.qpid.management.common.mbeans.ServerInformation;
+
+import junit.framework.TestCase;
+
+public class ApplicationRegistryTest extends TestCase
+{
+ public void testSupportedManagementApiVersion()
+ {
+ //ensure that the console supported API version is kept in sync with the broker
+
+ assertEquals("The management console does not support the same major version of management API as the broker. " +
+ "Make any required changes and update the supported value.",
+ ServerInformation.QPID_JMX_API_MAJOR_VERSION,
+ ApplicationRegistry.SUPPORTED_QPID_JMX_API_MAJOR_VERSION);
+
+ assertEquals("The management console does not support the same minor version of management API as the broker. " +
+ "Make any required changes and update the supported value.",
+ ServerInformation.QPID_JMX_API_MINOR_VERSION,
+ ApplicationRegistry.SUPPORTED_QPID_JMX_API_MINOR_VERSION);
+ }
+}
diff --git a/java/management/eclipse-plugin/src/test/java/org/apache/qpid/management/ui/ManagementConsoleTest.java b/java/management/eclipse-plugin/src/test/java/org/apache/qpid/management/ui/ManagementConsoleTest.java
index 11ab6af064..5469bfad5f 100644
--- a/java/management/eclipse-plugin/src/test/java/org/apache/qpid/management/ui/ManagementConsoleTest.java
+++ b/java/management/eclipse-plugin/src/test/java/org/apache/qpid/management/ui/ManagementConsoleTest.java
@@ -58,7 +58,8 @@ public class ManagementConsoleTest extends TestCase
@Override
protected void tearDown() throws Exception
{
- ApplicationRegistry.removeAll();
+ // Correctly Close the AR that we created above
+ ApplicationRegistry.remove();
}
/**
diff --git a/java/management/tools/qpid-cli/Guide.txt b/java/management/tools/qpid-cli/Guide.txt
new file mode 100644
index 0000000000..db841ebaa1
--- /dev/null
+++ b/java/management/tools/qpid-cli/Guide.txt
@@ -0,0 +1,143 @@
+
+ * How to connect with the Broker *
+ ---------------------------------
+
+Before you come in to this state you have to build the source or you
+can get the binary and extract then set the QPID_CLI environment
+variable to the main directory of the source or binary,then only you
+are in a position to start working with management console. First
+check whether the broker is up and running. In order to simply connect
+with the broker you can run the qpid-cli script which required
+arguments.
+
+${QPID_CLI}/bin/qpid-cli -h [HostName of IP of the broker ] -p [Port
+of the broker]
+
+Default values for arguments -h [localhost] -p [8999]
+
+ * One Shot mode *
+ -----------------
+
+With one shot mode you can run interactive mode commands for one time
+and disconnect with the broker.This feature is useful when you want to
+run particular command in the management console using a script which
+is running in the normal console.What you have to do is you have to
+give the command you want to run with the qpid-cli script running
+command.
+
+Ex 1: $QPID_CLI/bin/qpid-cli queue list -- This will list the queue
+objects and disconnect.
+
+Ex 2: $QPID_CLI/bin/qpid-cli queue view -n ping - This will display
+information about all the message in the queue with the name of ping
+
+Likewise you can run any command in one shot mode and get the output
+for one time.
+
+ * Report Generation Mode *
+ -------------------------
+
+If you want to generate reports you can do it by defining your
+required information using a property file. There's a sample property
+file in the parent directory and you can have a look and get an idea
+about that.You can generate reports by giving a time interval in the
+property file. In order to start the daemon mode you have to run the
+qpid-cli script with the option : -r by giving the path for your
+property file.
+
+Ex: $QPID_CLI/bin/qpid-cli -r ../report.property
+
+You should specify a property file in order to run the daemon mode and
+get information repeatedly.
+
+ * Interactive mode with number of command *
+ -------------------------------------------
+
+This is the mode you get when you run the qpid-cli script without the
+one shot mode and without the daemon mode with [-r] option.Once you
+connect with the broker it display you a prompt [qpid-admin-$], then
+you can run several commands to can perform following tasks.
+
+For all the commands object type is command and most important command
+so you can use this option value without giving the option letter by
+giving that option value at the beginning of the command.
+
+Ex: [list -o queue ] can use this command like this dropping -o option
+[queue list]
+Ex: [list -o queue -n ping] = [queue list -n ping]
+
+ * Data displaying commands *
+ ----------------------------
+
+This is the set of commands which display the information about
+broker.
+
+list :
+------
+list information about the given object type with limited
+number of attributes and you can use number of command options to get
+different useful behaviors with the list command.You can get the
+complete description about the command by running the command like
+this.[list -h].
+
+info :
+------
+list all the attributes of a given object type. This command
+works very similar way to list command. You can use -h option for help
+and get complete description of the info command.
+
+view :
+------
+view information about the content of the message in the queue
+object. In order to run this command you have to specify the object
+type at the beginning.You can give how many message informations you
+want to view from the top of the queue by using -t option.
+
+Ex : queue view -n message_queue -t 5
+[list the message info for top 5 messages in queue message_queue]
+
+viewcontent :
+-------------
+view the content of the a given message in the
+queue. You have to give the messageId as a parameter with -id option
+letters.
+
+Ex: queue viewcontent -n message_queue -id 12
+[list the content encoding and Mimetype of the message with the
+messageId for the give message which is in the queue message_queue]
+
+ * Data modification commands *
+ ------------------------------
+
+This is a set of commands which allow users to deal with messages in
+queues.Users can delete messages from a give queue and user's can move
+one message from one queue to another queue.
+
+delete :
+--------
+Using this command user can delete a give message from a given
+queue you can specify how many messages you want to delete from the
+queue from the top of the queue by using -t option.If user does not
+give how many messages to delete from the top of the queue program is
+going to delete all the messages from the queue after giving a prompt
+to confirm the deletion.
+
+Ex: queue delete -n message_queue -t 3
+[Delete top three messages in the queue message_queue ]
+
+move :
+------
+This command allow user to move number of messages from one
+queue to another queue. First you have to specify from which queue you
+want to move messages by using -n1 and -v1 option letters(-n1 queue
+name/ -v1 virtual host).Then you have to use -n2 option to give the
+target queue name and then you have to give From messageId and To
+messageId using -fmid and -tmid option letters to specify the messages
+range you want to do the move operation.
+
+Ex: queue move -n1 message_queue -n2 ping -fmid 13 -tmid 15
+[This will move messages with the messageId range of 13-15 from queue
+message_queue to queue ping.
+
+
+
diff --git a/java/management/tools/qpid-cli/LICENSE b/java/management/tools/qpid-cli/LICENSE
new file mode 100644
index 0000000000..c6432e459f
--- /dev/null
+++ b/java/management/tools/qpid-cli/LICENSE
@@ -0,0 +1,225 @@
+=========================================================================
+== 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.
+
+
+=============================================================================
+== JLine (BSD) License
+=============================================================================
+Copyright (c) 2008, Apache Software Foundation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ * Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+
+
+
diff --git a/java/management/tools/qpid-cli/NOTICE b/java/management/tools/qpid-cli/NOTICE
new file mode 100644
index 0000000000..f1d9e54095
--- /dev/null
+++ b/java/management/tools/qpid-cli/NOTICE
@@ -0,0 +1,12 @@
+Apache Qpid
+Copyright 2006-2008 Apache Software Foundation
+This product includes software developed at
+Apache Software Foundation (http://www.apache.org/)
+
+Handling console input is provided bye the Jline library package,
+JLine is a Java library for handling console input. It is similar
+in functionality to BSD editline and GNU readline.Original software is
+available from
+
+http://jline.sourceforge.net/index.html
+
diff --git a/java/management/tools/qpid-cli/README b/java/management/tools/qpid-cli/README
new file mode 100644
index 0000000000..6db439aad0
--- /dev/null
+++ b/java/management/tools/qpid-cli/README
@@ -0,0 +1,64 @@
+README
+n======
+
+INSTALL
+=======
+ source
+ ======
+ 1.Set the environment variable QPID_HOME to the root directory of the repository or the release.
+
+ 2.Run these command to build the source
+
+ ant compile OR run the ant build in the parent directory(main ant script)
+
+ 3.To launch the CLI run the script in bin folder with appropriate parameters.
+
+ ex:
+
+ Linux $QPID_HOME/bin/qpid-cli -h 10.8.100.122 -p 8334
+ Windows %QPID_HOME%/bin/qpid-cli.bat -h 10.8.100.122 -p 8334
+
+ -h hostname (default localhost)
+ -p broker port (default 8999)
+
+ binary
+ ======
+ 1.Set the environment variable QPID_HOME to the root directory of the repository or the release.
+
+ 2.To launch the CLI run the script in bin folder with appropriate parameters.
+
+ ex:
+
+ Linux $QPID_HOME/bin/qpid-cli -h 10.8.100.122 -p 8334
+ Windows %QPID_HOME%/bin/qpid-cli.bat -h 10.8.100.122 -p 8334
+
+ -h hostname (default localhost)
+ -p broker port (default 8999)
+
+ 3. No test cases are included in the binary version.
+
+TESTING
+=======
+
+1.Test source is located in the test directory.If you want to run the tests please start the
+Qpid java broker and run following ant targets.
+
+ ant compile-tests This compile all the test sources
+ ant test This runs all the test cases
+2.If you want to test with a remote broker please use the source release and change the constants in ConnectionConstants.java
+class.(Default values are BROKER_HOSTNAME="localhost" BROKER_PORT="8999")
+
+For more informations please visit the project home page.
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/java/management/tools/qpid-cli/bin/qpid-cli b/java/management/tools/qpid-cli/bin/qpid-cli
new file mode 100755
index 0000000000..0efb49dddd
--- /dev/null
+++ b/java/management/tools/qpid-cli/bin/qpid-cli
@@ -0,0 +1,35 @@
+#!/bin/bash
+#
+# License to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+if [ -z "$QPID_HOME" ]; then
+ export QPID_HOME=$(dirname $(dirname $(readlink -f $0)))
+ export PATH=${PATH}:${QPID_HOME}/bin
+fi
+
+# Set classpath to include Qpid jar with all required jars in manifest
+QPID_LIBS=$QPID_HOME/lib/qpid-all.jar
+
+# Set other variables used by the qpid-run script before calling
+export JAVA=java \
+ JAVA_VM=-server \
+ JAVA_MEM=-Xmx1024m \
+ QPID_CLASSPATH=$QPID_LIBS
+
+. qpid-run org.apache.qpid.CommandLineInterpreter "$@"
diff --git a/java/management/tools/qpid-cli/bin/qpid-cli.bat b/java/management/tools/qpid-cli/bin/qpid-cli.bat
new file mode 100755
index 0000000000..452ddb65ee
--- /dev/null
+++ b/java/management/tools/qpid-cli/bin/qpid-cli.bat
@@ -0,0 +1,28 @@
+@REM
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM
+set CLASSPATH=%CLASSPATH%;%QPID_HOME%/lib/jline-0.9.94.jar
+set CLASSPATH=%CLASSPATH%;%QPID_HOME%/lib/junit-4.4.jar
+set CLASSPATH=%CLASSPATH%;%QPID_HOME%/lib/qpid-cli-1.0.jar
+set CLASSPATH=%CLASSPATH%;%QPID_HOME%/lib/qpid-management-common-M4.jar
+set CLASSPATH=%CLASSPATH%;%QPID_HOME%/management/tools/qpid-cli/main/classes/
+java -classpath %CLASSPATH% org.apache.qpid.CommandLineInterpreter %1
+
+
+
+
diff --git a/java/management/tools/qpid-cli/build.xml b/java/management/tools/qpid-cli/build.xml
new file mode 100644
index 0000000000..7026cd2fd2
--- /dev/null
+++ b/java/management/tools/qpid-cli/build.xml
@@ -0,0 +1,31 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<project name="qpid-cli">
+
+ <property name="module.depends" value="common management/common" />
+ <property name="module.test.depends" value="common client" />
+ <property name="module.src" value="src" />
+ <!-- Disable tests as per QPID-1342 -->
+ <!--property name="module.test.src" value="test" /-->
+
+ <import file="../../../module.xml"/>
+
+</project>
diff --git a/java/management/tools/qpid-cli/report.property b/java/management/tools/qpid-cli/report.property
new file mode 100644
index 0000000000..46734d52a8
--- /dev/null
+++ b/java/management/tools/qpid-cli/report.property
@@ -0,0 +1,26 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+object=queue
+column=Name,MessageCount,ActiveConsumerCount,Durable
+filter.name=ping
+filter.virtualhost=test
+output=csv
+seperator=|
+interval=1
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/Command.java b/java/management/tools/qpid-cli/src/org/apache/qpid/Command.java
new file mode 100644
index 0000000000..eadc87186f
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/Command.java
@@ -0,0 +1,33 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid;
+
+public interface Command
+{
+ public void execute();
+
+ public void printusage();
+
+ public String optionchecker(String string);
+
+ public boolean checkoptionsetting(String string);
+
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/CommandExecutionEngine.java b/java/management/tools/qpid-cli/src/org/apache/qpid/CommandExecutionEngine.java
new file mode 100644
index 0000000000..69f261b4ba
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/CommandExecutionEngine.java
@@ -0,0 +1,76 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.qpid.utils.JMXinfo;
+
+public class CommandExecutionEngine
+{
+ private static Map<String, Class<? extends Command>> _commands = new HashMap<String, Class<? extends Command>>();
+ private Command currentcommand = null;
+ private String commandname = null;
+ private JMXinfo info = null;
+
+ public CommandExecutionEngine(JMXinfo info)
+ {
+ this.info = info;
+ this.commandname = info.getCommandLineOptionParser().getcommandname();
+ }
+
+ public boolean CommandSelector() throws Exception
+ {
+ Class<? extends Command> commandClass = _commands.get(this.commandname);
+ if (commandClass != null)
+ {
+ Class<?> parameterTypes = JMXinfo.class;
+ currentcommand = (Command) commandClass.getConstructor(parameterTypes).newInstance(info);
+ }
+ else
+ {
+ usage();
+ return false;
+ }
+ return true;
+ }
+
+ public static void addCommand(String name, Class<? extends Command> newCommand)
+ {
+ _commands.put(name, newCommand);
+ }
+
+ public static Map<String, Class<? extends Command>> getCommands()
+ {
+ return _commands;
+ }
+
+ public void runcommand()
+ {
+ currentcommand.execute();
+ }
+
+ public void usage()
+ {
+ System.out.println(commandname + ":Command not found");
+ }
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/CommandLineInterpreter.java b/java/management/tools/qpid-cli/src/org/apache/qpid/CommandLineInterpreter.java
new file mode 100644
index 0000000000..d8e76172bc
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/CommandLineInterpreter.java
@@ -0,0 +1,263 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid;
+
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import javax.management.MBeanServerConnection;
+import javax.management.remote.JMXConnector;
+
+import jline.ArgumentCompletor;
+import jline.ConsoleReader;
+import jline.SimpleCompletor;
+
+import org.apache.qpid.commands.Commanddelete;
+import org.apache.qpid.commands.Commandget;
+import org.apache.qpid.commands.Commandhelp;
+import org.apache.qpid.commands.Commandinfo;
+import org.apache.qpid.commands.Commandlist;
+import org.apache.qpid.commands.Commandmove;
+import org.apache.qpid.commands.Commandset;
+import org.apache.qpid.commands.Commandview;
+import org.apache.qpid.commands.Commandviewcontent;
+import org.apache.qpid.utils.CommandLineOptionParser;
+import org.apache.qpid.utils.JMXConfiguration;
+import org.apache.qpid.utils.JMXinfo;
+
+public class CommandLineInterpreter
+{
+ private static final String OBJECT_VIRTUALHOST = "virtualhost";
+ private static final String OBJECT_USERMANAGEMENT = "usermanagement";
+ private static final String OBJECT_CONNECTION = "connection";
+ private static final String OBJECT_EXCHANGE = "exchange";
+ private static final String OBJECT_QUEUE = "queue";
+ private static final String COMMAND_QUIT = "quit";
+ private static final String COMMAND_EXIT = "exit";
+
+ public static void main(String[] args)
+ {
+ Connector conn = null;
+ try
+ {
+ // Create an RMI connector client and
+ // connect it to the RMI connector server
+
+ /*
+ * checking the commandline options and parse them in to config
+ * method
+ */
+ JMXConnector jmxc = null;
+ MBeanServerConnection mbsc = null;
+ ConsoleReader reader = new ConsoleReader();
+ reader.setBellEnabled(false);
+ CommandLineOptionParser commandlineoptionparser = null;
+
+ if ((args == null) || (args.length) == 0)
+ {
+ Usage();
+ }
+ /*
+ * here special constructor is calling, when parsing options,in here
+ * first option value is starting from minus sign so this is handle
+ * by a special constructor
+ */
+ else
+ {
+ if (args[0].startsWith("-"))
+ {
+ commandlineoptionparser = new CommandLineOptionParser(args, args[0]); // if
+ // user
+ // specify
+ // any
+ // argument
+ // with
+ // the
+ // qpid-cli
+ // script
+ }
+ }
+
+ registerCommands();
+
+ /* Connecting with the broker */
+ try
+ {
+ if (commandlineoptionparser == null)
+ commandlineoptionparser = new CommandLineOptionParser(args);
+
+ JMXConfiguration config = new JMXConfiguration(commandlineoptionparser.getAlloptions());
+ conn = ConnectorFactory.getConnector(config.gethostname(), config.getport(), config.getUsername(),
+ config.getPassword());
+ jmxc = conn.getConnector();
+ mbsc = conn.getMBeanServerConnection();
+ if (config.checkoptionsetting("r", commandlineoptionparser.getAlloptions()))
+ {
+ JMXinfo info = new JMXinfo(jmxc, commandlineoptionparser, mbsc);
+ ReportGenerator reportgen = new ReportGenerator(config.optionchecker("r", commandlineoptionparser
+ .getAlloptions()), info);
+ reportgen.loadproperties();
+ reportgen.run();
+ }
+ /*
+ * This implementation is for the people who are using the
+ * interactive mode for one shot this run the user given command
+ * and exit
+ */
+ for (int i = 0; i < args.length; i++)
+ {
+ if (CommandExecutionEngine.getCommands().keySet().contains(args[i]))
+ {
+ oneshotmode(args, commandlineoptionparser, jmxc, mbsc);
+ return;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ connectionrefuse(ex);
+ return;
+ }
+ /* In this point connection has been established */
+ String line;
+ String[] command;
+
+ /* prividing GNU readline features using Jline library */
+ PrintWriter out = new PrintWriter(System.out);
+ SimpleCompletor completer = new SimpleCompletor(new String[] {
+ COMMAND_EXIT, COMMAND_QUIT, OBJECT_QUEUE, OBJECT_EXCHANGE, OBJECT_CONNECTION,
+ OBJECT_USERMANAGEMENT, OBJECT_VIRTUALHOST});
+ for (String commandName : CommandExecutionEngine.getCommands().keySet())
+ {
+ completer.addCandidateString(commandName);
+ }
+ reader.addCompletor(new ArgumentCompletor(completer));
+ while ((line = reader.readLine("qpid-admin-$ ")) != null)
+ {
+ out.flush();
+ if (removeSpaces(line).equalsIgnoreCase(COMMAND_QUIT) || removeSpaces(line).equalsIgnoreCase(COMMAND_EXIT))
+ break;
+ else if (line.length() == 0)
+ continue;
+ else
+ {
+ command = line.split("\\s+");
+ commandlineoptionparser = new CommandLineOptionParser(command);
+ JMXinfo info = new JMXinfo(jmxc, commandlineoptionparser, mbsc);
+ CommandExecutionEngine engine = new CommandExecutionEngine(info);
+ if (engine.CommandSelector())
+ engine.runcommand();
+ }
+ }
+
+ conn.getConnector().close();
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
+ private static void registerCommands()
+ {
+ CommandExecutionEngine.addCommand(Commanddelete.COMMAND_NAME, Commanddelete.class);
+ CommandExecutionEngine.addCommand(Commandget.COMMAND_NAME, Commandget.class);
+ CommandExecutionEngine.addCommand(Commandhelp.COMMAND_NAME, Commandhelp.class);
+ CommandExecutionEngine.addCommand(Commandinfo.COMMAND_NAME, Commandinfo.class);
+ CommandExecutionEngine.addCommand(Commandlist.COMMAND_NAME, Commandlist.class);
+ CommandExecutionEngine.addCommand(Commandmove.COMMAND_NAME, Commandmove.class);
+ CommandExecutionEngine.addCommand(Commandset.COMMAND_NAME, Commandset.class);
+ CommandExecutionEngine.addCommand(Commandview.COMMAND_NAME, Commandview.class);
+ CommandExecutionEngine.addCommand(Commandviewcontent.COMMAND_NAME, Commandviewcontent.class);
+ }
+
+ private static void Usage()
+ {
+ System.out.println("Connecting to localhost Qpid java broker...");
+ }
+
+ private static String removeSpaces(String s)
+ {
+ StringTokenizer st = new StringTokenizer(s, " ", false);
+ String t = "";
+ while (st.hasMoreElements())
+ t += st.nextElement();
+ return t;
+ }
+
+ private static void connectionrefuse(Exception e)
+ {
+ String message = e.getLocalizedMessage();
+ if (e instanceof SecurityException)
+ {
+ message = " authentication failed, please check username and password";
+ }
+ else
+ {
+ Throwable cause = e.getCause();
+ while (cause != null)
+ {
+ message = cause.getMessage();
+ cause = cause.getCause();
+ }
+ }
+
+ System.out.println("Cannot connect with the broker: " + message);
+ }
+
+ public static String[] oneshotmode(String[] args, CommandLineOptionParser commandlineoptionparser,
+ JMXConnector jmxc, MBeanServerConnection mbsc) throws Exception
+ {
+ int check = 0;
+ String[] temp;
+ for (int i = 0; i < args.length; i++)
+ {
+
+ if (args[i].compareTo("-h") == 0)
+ check++;
+ else if (args[i].compareTo("-p") == 0)
+ check++;
+ }
+ for (int i = 0; i < (args.length - 2 * check); i++)
+ { // mulitply by 2 because have to remove the option letter with the
+ // option value//
+ args[i] = args[i + check * 2];
+ }
+
+ commandlineoptionparser = new CommandLineOptionParser(args); // change
+ // the args
+ // string
+ // array
+ // which
+ // works as
+ // interactive
+ // mode//
+ JMXinfo info = new JMXinfo(jmxc, commandlineoptionparser, mbsc);
+ CommandExecutionEngine engine = new CommandExecutionEngine(info);
+ if (engine.CommandSelector())
+ engine.runcommand();
+ return args;
+
+ }
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/Connector.java b/java/management/tools/qpid-cli/src/org/apache/qpid/Connector.java
new file mode 100644
index 0000000000..2b887077c3
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/Connector.java
@@ -0,0 +1,49 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid;
+
+import javax.management.MBeanServerConnection;
+import javax.management.remote.JMXConnector;
+
+public class Connector
+{
+ private JMXConnector jmxc = null;
+ private MBeanServerConnection mbsc = null;
+
+ public Connector(JMXConnector jmxc, MBeanServerConnection mbsc)
+ {
+
+ this.jmxc = jmxc;
+ this.mbsc = mbsc;
+
+ }
+
+ public JMXConnector getConnector()
+ {
+ return jmxc;
+ }
+
+ public MBeanServerConnection getMBeanServerConnection()
+ {
+ return mbsc;
+ }
+
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/ConnectorFactory.java b/java/management/tools/qpid-cli/src/org/apache/qpid/ConnectorFactory.java
new file mode 100644
index 0000000000..84ba94c5c4
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/ConnectorFactory.java
@@ -0,0 +1,50 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid;
+
+import javax.management.MBeanServerConnection;
+import javax.management.remote.JMXConnector;
+
+import org.apache.qpid.management.common.JMXConnnectionFactory;
+
+public class ConnectorFactory
+{
+
+ private static final long TIMEOUT = 30 * 1000;
+
+ public static Connector getConnector(String host, String port, String username, String password) throws Exception
+ {
+
+ JMXConnector jmxc = null;
+ MBeanServerConnection mbsc = null;
+ try
+ {
+ jmxc = JMXConnnectionFactory.getJMXConnection(TIMEOUT, host, Integer.parseInt(port), username, password);
+ mbsc = jmxc.getMBeanServerConnection();
+ }
+ catch (NumberFormatException e)
+ {
+ System.out.println("Illegal port entered:" + port);
+ System.exit(1);
+ }
+ return new Connector(jmxc, mbsc);
+ }
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/ReportGenerator.java b/java/management/tools/qpid-cli/src/org/apache/qpid/ReportGenerator.java
new file mode 100644
index 0000000000..cc8c16f8b0
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/ReportGenerator.java
@@ -0,0 +1,195 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid;
+
+import org.apache.qpid.commands.objects.*;
+import org.apache.qpid.utils.JMXinfo;
+
+import javax.management.MBeanServerConnection;
+import java.util.*;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+public class ReportGenerator implements Runnable
+{
+
+ String[] propertyname = { "object", "column", "filter.name", "filter.virtualhost", "output", "seperator",
+ "interval" };
+ String[] propertyvalue = null;
+ String propertyfilepath = null;
+ String[] columnvalue = null;
+ List<String> columns = null;
+ Properties props = null;
+ JMXinfo info = null;
+ int interval = 10;
+
+ public void run()
+ {
+ for (;;) // creating infinite loop
+ {
+ generatereport();
+ try
+ {
+ Thread.sleep(this.interval * 60000);
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+ public ReportGenerator(String propfile, JMXinfo info)
+ {
+ this.propertyfilepath = propfile;
+ props = new Properties();
+ propertyvalue = new String[propertyname.length];
+ this.info = info;
+ columns = new ArrayList<String>();
+ }
+
+ public void loadproperties() // get all the property file values and set the
+ // columen values//
+ {
+ try
+ {
+
+ props.load(new FileInputStream(this.propertyfilepath));
+ for (int i = 0; i < propertyname.length; i++)
+ {
+ propertyvalue[i] = props.getProperty(propertyname[i]);
+ }
+ this.setcolumnvalues();
+ this.setinterval();
+ }
+
+ // catch exception in case properties file does not exist
+
+ catch (IOException e)
+ {
+ System.out.println("Oooops Give property file is not exist");
+ }
+ }
+
+ public void generatereport()
+ {
+ this.listobjects(propertyvalue[0]);
+ }
+
+ private void setcolumnvalues()
+ {
+ columnvalue = propertyvalue[1].split(",");
+ for (int i = 0; i < columnvalue.length; i++)
+ {
+ columns.add(columnvalue[i]);
+ }
+ }
+
+ private void setinterval()
+ {
+ this.interval = (new Integer(propertyvalue[6])).intValue();
+ }
+
+ private void listobjects(String option_value)
+ {
+ /*
+ * pring usage if use is not give the correct option letter or no
+ * options
+ */
+ if (option_value == null)
+ {
+ // System.out.println("testing");
+ return;
+ }
+ MBeanServerConnection mbsc = info.getmbserverconnector();
+ Set set = null;
+ ObjectNames objname = null;
+
+ try
+ {
+ if (option_value.compareToIgnoreCase("queue") == 0 || option_value.compareToIgnoreCase("queues") == 0)
+ {
+ objname = new QueueObject(mbsc);
+
+ }
+ else if (option_value.compareToIgnoreCase("Virtualhosts") == 0
+ || option_value.compareToIgnoreCase("Virtualhost") == 0)
+ {
+ objname = new VirtualHostObject(mbsc);
+ // this.name = option_value;
+ }
+ else if (option_value.compareToIgnoreCase("Exchange") == 0
+ || option_value.compareToIgnoreCase("Exchanges") == 0)
+ {
+ objname = new ExchangeObject(mbsc);
+ // this.name = option_value;
+ }
+ else if (option_value.compareToIgnoreCase("Connection") == 0
+ || option_value.compareToIgnoreCase("Connections") == 0)
+ {
+ objname = new ConnectionObject(mbsc);
+ // this.name = option_value;
+ }
+ else if (option_value.compareToIgnoreCase("all") == 0)
+ {
+ objname = new AllObjects(mbsc);
+ // this.name = option_value;
+ }
+ else if (option_value.compareToIgnoreCase("Usermanagement") == 0
+ || option_value.compareToIgnoreCase("Usermanagmenets") == 0)
+ {
+ objname = new UserManagementObject(mbsc);
+ // this.name = option_value;
+ }
+ else
+ {
+ printusage();
+ echo("Wrong objectName");
+ return;
+ }
+ objname.setQueryString(this.propertyvalue[0], this.propertyvalue[2], this.propertyvalue[3]);
+ objname.returnObjects();
+ if (objname.getSet().size() != 0)
+ {
+ objname.reportgenerator(this.propertyvalue[4], this.propertyvalue[5], columns);
+ }
+ else
+ {
+ printusage();
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+
+ }
+
+ public void echo(String str)
+ {
+ System.out.println(str);
+ }
+
+ public void printusage()
+ {
+ System.out.println("Wrong option or wrong option value");
+ }
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/commands/CommandImpl.java b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/CommandImpl.java
new file mode 100644
index 0000000000..6fdae4c0a6
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/CommandImpl.java
@@ -0,0 +1,153 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.commands;
+
+import java.util.Map;
+
+import org.apache.qpid.Command;
+import org.apache.qpid.utils.CommandLineOption;
+import org.apache.qpid.utils.JMXinfo;
+
+public abstract class CommandImpl implements Command
+{
+ protected JMXinfo info = null;
+
+ private String name;
+ private String virtualhost = null;
+ private String object = null;
+
+ private String outputformat = null;
+ private String seperator = ",";
+
+ public CommandImpl(JMXinfo info)
+ {
+ this.info = info;
+ }
+
+ public CommandImpl()
+ {
+
+ }
+
+ protected void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public String getName()
+ {
+ return this.name;
+ }
+
+ protected boolean hasName()
+ {
+ if (this.name == null)
+ return false;
+
+ else
+ return true;
+ }
+
+ protected void setObject(String object)
+ {
+ this.object = object;
+ }
+
+ public String getObject()
+ {
+ return this.object;
+ }
+
+ protected void setOutputFormat(String outputformat)
+ {
+ this.outputformat = outputformat;
+ }
+
+ protected String getOutputFormat()
+ {
+ return outputformat;
+ }
+
+ protected void setSeperator(String seperator)
+ {
+ this.seperator = seperator;
+ }
+
+ protected String getSeperator()
+ {
+ return seperator;
+ }
+
+ protected void setVirtualhost(String virtualhost)
+ {
+ this.virtualhost = virtualhost;
+ }
+
+ public String getVirtualhost()
+ {
+ return this.virtualhost;
+ }
+
+ public String optionchecker(String option_letter)
+ {
+ Map map = info.getCommandLineOptionParser().getAlloptions();
+ if (map == null)
+ return null;
+ CommandLineOption option = (CommandLineOption) map.get(option_letter);
+ if (option == null)
+ return null;
+ String value = option.getOptionValue();
+ return value;
+ }
+
+ public boolean checkoptionsetting(String option_letter)
+ {
+ Map map = info.getCommandLineOptionParser().getAlloptions();
+ if (map == null)
+ return false;
+ CommandLineOption option = (CommandLineOption) map.get(option_letter);
+ if (option == null)
+ return false;
+ String value = option.getOptionType();
+
+ if (value != null)
+ return true;
+ else
+ return false;
+ }
+
+ public void echo(String str)
+ {
+ System.out.println(str);
+ }
+
+ public void unrecognizeoption()
+ {
+ echo("list: Unrecognized option");
+ echo("Try --help for more information");
+ }
+
+ public abstract void execute();
+
+ public abstract void printusage();
+
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commanddelete.java b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commanddelete.java
new file mode 100644
index 0000000000..cdbb8f1d4f
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commanddelete.java
@@ -0,0 +1,199 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.commands;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+
+import org.apache.qpid.commands.objects.QueueObject;
+import org.apache.qpid.utils.JMXinfo;
+
+public class Commanddelete extends CommandImpl
+{
+ private int number = 0;
+ private QueueObject objname;
+ private MBeanServerConnection mbsc;
+ private String method1, method2;
+ private ObjectName queue;
+ public static final String COMMAND_NAME = "delete";
+
+ public Commanddelete(JMXinfo info)
+ {
+ super(info);
+ this.mbsc = info.getmbserverconnector();
+ this.objname = new QueueObject(mbsc);
+ this.method1 = "deleteMessageFromTop";
+ this.method2 = "clearQueue";
+
+ }
+
+ public void deletemessages()
+ {
+ Set set = null;
+ objname.setQueryString(this.getObject(), this.getName(), this.getVirtualhost());
+ set = objname.returnObjects();
+
+ if (objname.getSet().size() != 0)
+ {
+ Iterator it = set.iterator();
+ this.queue = (ObjectName) it.next();
+ try
+ {
+ if (this.number == 0)
+ {
+ echo("");
+ System.out.print("Do you want to delete all the messages from the Queue [Y/N] :");
+ InputStreamReader isr = new InputStreamReader(System.in);
+ BufferedReader br = new BufferedReader(isr);
+ String s = br.readLine();
+ echo(s);
+ if (s.compareToIgnoreCase("y") == 0)
+ this.mbsc.invoke(queue, this.method2, null, null);
+ else
+ return;
+ }
+ else if (objname.getmessagecount(this.queue) < this.number)
+ {
+ echo("Given number is Greater than the Queue Depth");
+ return;
+ }
+ else
+ {
+ for (int i = 0; i < this.number; i++)
+ {
+ this.mbsc.invoke(queue, this.method1, null, null);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+
+ }
+ else
+ {
+ if (hasName())
+ {
+
+ echo("The Queue you have specified is not in the current broker");
+ echo("");
+ }
+ else
+ {
+ printusage();
+ }
+ }
+ }
+
+ public void execute()
+ {
+ /*
+ * In here you it's easy to handle any number of otpions which are going
+ * to add with the list command which works with main option object or o
+ */
+
+ if (checkoptionsetting("object") || checkoptionsetting("o"))
+ {
+ String object = optionchecker("object");
+ if (object == null)
+ {
+ object = optionchecker("o");
+ }
+ if (object.compareToIgnoreCase("queue") == 0)
+ setObject(object);
+ else
+ {
+ unrecognizeoption();
+ echo("This command is only applicable for delete command so please start with queue");
+ }
+ if (checkoptionsetting("name") || checkoptionsetting("n"))
+ {
+ String name = optionchecker("name");
+ if (name == null)
+ name = optionchecker("n");
+
+ setName(name);
+ }
+ if (checkoptionsetting("virtualhost") || checkoptionsetting("v"))
+ {
+ String vhost = optionchecker("virtualhost");
+ if (vhost == null)
+ vhost = optionchecker("v");
+ setVirtualhost(vhost);
+ }
+ if (checkoptionsetting("top") || checkoptionsetting("t"))
+ {
+ String number = optionchecker("top");
+ if (number == null)
+ number = optionchecker("t");
+
+ setnumber(removeSpaces(number));
+ }
+ this.deletemessages();
+ }
+ else if (checkoptionsetting("h") || checkoptionsetting("help"))
+ printusage();
+ else
+ unrecognizeoption();
+ }
+
+ public void printusage()
+ {
+ echo("");
+ echo("Usage:delete [OPTION] ... [OBJECT TYPE]...\n");
+ echo("Delete the top most messages from the given queue object\n");
+ echo("To specify the desired queue you have to give the virtualhost name and the queue name with following commands\n");
+ echo("Where possible options include:\n");
+ echo(" -v --virtualhost Give the virtuallhost name of the desired queue");
+ echo(" -n --name Give the queue name of the desired queue you want to do the delete operation");
+ echo(" -t --top Give how many number of messages you want to delete from the top (Default = all the messages will be deleted");
+ echo(" -h --help Display the help and back to the qpid-cli prompt\n");
+
+ }
+
+ private void setnumber(String number)
+ {
+ Integer i = new Integer(number);
+ this.number = i.intValue();
+ }
+
+ public int getnumber()
+ {
+ return this.number;
+ }
+
+ private static String removeSpaces(String s)
+ {
+ StringTokenizer st = new StringTokenizer(s, " ", false);
+ String t = "";
+ while (st.hasMoreElements())
+ t += st.nextElement();
+ return t;
+ }
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandget.java b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandget.java
new file mode 100644
index 0000000000..8d690ac7f7
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandget.java
@@ -0,0 +1,211 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.commands;
+
+import org.apache.qpid.commands.objects.ObjectNames;
+import org.apache.qpid.commands.objects.QueueObject;
+import org.apache.qpid.utils.JMXinfo;
+
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+import java.util.Set;
+
+public class Commandget extends CommandImpl
+{
+
+ private String _attributeName;
+ private String _value;
+ public static String COMMAND_NAME = "get";
+
+ public Commandget(JMXinfo info)
+ {
+ super(info);
+ }
+
+ private void getAttribute(String option_value)
+ {
+ if (option_value == null)
+ {
+ printusage();
+ return;
+ }
+ MBeanServerConnection mbsc = info.getmbserverconnector();
+ Set set = null;
+ ObjectNames objname = null;
+
+ try
+ {
+ if (option_value.compareToIgnoreCase("queue") == 0 || option_value.compareToIgnoreCase("queues") == 0)
+ {
+ objname = new QueueObject(mbsc);
+ }
+ else
+ {
+ printusage();
+ echo("Wrong objectName");
+ return;
+ }
+
+ if (_attributeName == null)
+ {
+ echo("attribute name not specified. See --help for details");
+ return;
+ }
+
+ objname.setQueryString(this.getObject(), this.getName(), this.getVirtualhost());
+ objname.returnObjects();
+
+ if (objname.getSet().size() != 1)
+ {
+ echo("Your query returned more than one object to set was this intended?\n" + objname.getQueryString());
+ }
+ else if (objname.getSet().size() == 1)
+ {
+ ObjectName object = (ObjectName) objname.getSet().iterator().next();
+
+ Object value = objname.getAttribute(object, _attributeName);
+
+ echo(value.toString());
+ }
+ else
+ {
+ if (hasName())
+ {
+
+ echo("You might be querying wrong " + this.getObject() + " name with --name or -n option ");
+ echo("");
+ echo("No " + this.getObject() + "Type Objects might not in the broker currently");
+ echo("");
+ }
+ else
+ {
+ printusage();
+ }
+ }
+
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+
+ }
+
+ public void execute()
+ {
+ /*
+ * In here you it's easy to handle any number of otpions which are going
+ * to add with the list command which works with main option object or o
+ */
+ if (checkoptionsetting("output"))
+ {
+ setOutputFormat(optionchecker("output"));
+ if (checkoptionsetting("separator"))
+ {
+ setSeperator(optionchecker("separator"));
+ }
+ }
+ if (checkoptionsetting("object") || checkoptionsetting("o"))
+ {
+ String object = optionchecker("object");
+ if (object == null)
+ {
+ object = optionchecker("o");
+ }
+ setObject(object);
+
+ if (checkoptionsetting("name") || checkoptionsetting("n"))
+ {
+ String name = optionchecker("name");
+ if (name == null)
+ {
+ name = optionchecker("n");
+ }
+
+ setName(name);
+ }
+
+ if (checkoptionsetting("attribute") || checkoptionsetting("a"))
+ {
+ String name = optionchecker("attribute");
+ if (name == null)
+ {
+ name = optionchecker("a");
+ }
+
+ setAttributeName(name);
+ }
+ if (checkoptionsetting("virtualhost") || checkoptionsetting("v"))
+ {
+ String vhost = optionchecker("virtualhost");
+ if (vhost == null)
+ {
+ vhost = optionchecker("v");
+ }
+ setVirtualhost(vhost);
+ }
+ getAttribute(this.getObject());
+ }
+ else if (checkoptionsetting("h") || checkoptionsetting("help"))
+ {
+ printusage();
+ }
+ else
+ {
+ unrecognizeoption();
+ }
+ }
+
+ private void setAttributeName(String name)
+ {
+ this._attributeName = name;
+ }
+
+ public void printusage()
+ {
+ echo("");
+ echo("Usage:set [OPTION] ... [OBJECT TYPE]...\n");
+ echo("List the information about the given object\n");
+ echo("Where possible options include:\n");
+ echo(" -o --object type of objects which you want to list\n");
+ echo(" ex: < list -o queue > : lists all the queues created in the java broker\n");
+ echo(" For now list command is supporting following object typse \n");
+ echo(" Queue Connection VirtualHost UserMangement Exchange");
+ echo(" Or You can specify object type by giving it at the beginning");
+ echo(" rather giving it as a argument");
+ echo(" Ex:< queue list > this command is equal to list -o queue \n");
+ echo(" -v --virtualhost After specifying the object type you can filter output with this option");
+ echo(" list objects with the given virtualhost which will help to find ");
+ echo(" identical queue objects with -n option");
+ echo(" ex: queue list -v develop ment");
+ echo(" -n --name After specifying what type of objects you want to monitor you can filter");
+ echo(" the output using -n option by specifying the name of the object you want ");
+ echo(" to monitor exactly");
+ echo(" ex: <list -o queue -n ping> : list all the queue objects having queue name");
+ echo(" of ping");
+ echo(" ex: <queue list -n ping -v development> list all the queue objects with name ");
+ echo(" of ping and virtualhost of developement \n");
+ echo(" -a --attribute ");
+ echo(" -h --help Display the help and back to the qpid-cli prompt\n");
+
+ }
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandhelp.java b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandhelp.java
new file mode 100644
index 0000000000..502ac89f74
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandhelp.java
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.commands;
+
+import org.apache.qpid.utils.JMXinfo;
+
+public class Commandhelp extends CommandImpl
+{
+
+ public static final String COMMAND_NAME = "help";
+
+ public Commandhelp(JMXinfo info)
+ {
+ }
+
+ public void execute()
+ {
+ printusage();
+ }
+
+ public void printusage()
+ {
+ echo("");
+ echo("Current version of qpid CLI is supporting following commands");
+ echo("");
+ echo("[list] This command is listing limited information about a given type of object");
+ echo(" For more information about list command run `list --help`");
+ echo("[info] This command is listing All the information about a given type of object");
+ echo(" For more information about list command run `info --help`");
+
+ echo("");
+ echo("[exit] This command is disconnect the connection with the Qpid Java broker and go back to normal propmt");
+ echo("[quit] This command is disconnect the connection with the Qpid Java broker and go back to normal propmt");
+ echo("");
+ }
+
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandinfo.java b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandinfo.java
new file mode 100644
index 0000000000..7094a8fc7f
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandinfo.java
@@ -0,0 +1,206 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.commands;
+
+import java.util.Set;
+
+import javax.management.MBeanServerConnection;
+
+import org.apache.qpid.commands.objects.AllObjects;
+import org.apache.qpid.commands.objects.ConnectionObject;
+import org.apache.qpid.commands.objects.ExchangeObject;
+import org.apache.qpid.commands.objects.ObjectNames;
+import org.apache.qpid.commands.objects.QueueObject;
+import org.apache.qpid.commands.objects.UserManagementObject;
+import org.apache.qpid.commands.objects.VirtualHostObject;
+import org.apache.qpid.utils.JMXinfo;
+
+public class Commandinfo extends CommandImpl
+{
+
+ public static final String COMMAND_NAME = "info";
+
+ public Commandinfo(JMXinfo info)
+ {
+ super(info);
+ }
+
+ private void listobjects(String option_value)
+ {
+ /*
+ * pring usage if use is not give the correct option letter or no
+ * options
+ */
+ if (option_value == null)
+ {
+ // System.out.println("testing");
+ printusage();
+ return;
+ }
+ MBeanServerConnection mbsc = info.getmbserverconnector();
+ Set set = null;
+ ObjectNames objname = null;
+
+ try
+ {
+ if (option_value.compareToIgnoreCase("queue") == 0 || option_value.compareToIgnoreCase("queues") == 0)
+ {
+ objname = new QueueObject(mbsc);
+
+ }
+ else if (option_value.compareToIgnoreCase("Virtualhosts") == 0
+ || option_value.compareToIgnoreCase("Virtualhost") == 0)
+ {
+ objname = new VirtualHostObject(mbsc);
+ // this.name = option_value;
+ }
+ else if (option_value.compareToIgnoreCase("Exchange") == 0
+ || option_value.compareToIgnoreCase("Exchanges") == 0)
+ {
+ objname = new ExchangeObject(mbsc);
+ // this.name = option_value;
+ }
+ else if (option_value.compareToIgnoreCase("Connection") == 0
+ || option_value.compareToIgnoreCase("Connections") == 0)
+ {
+ objname = new ConnectionObject(mbsc);
+ // this.name = option_value;
+ }
+ else if (option_value.compareToIgnoreCase("all") == 0)
+ {
+ objname = new AllObjects(mbsc);
+ // this.name = option_value;
+ }
+ else if (option_value.compareToIgnoreCase("Usermanagement") == 0
+ || option_value.compareToIgnoreCase("Usermanagmenets") == 0)
+ {
+ objname = new UserManagementObject(mbsc);
+ // this.name = option_value;
+ }
+ else
+ {
+ printusage();
+ echo("Wrong objectName");
+ return;
+ }
+ objname.setQueryString(this.getObject(), this.getName(), this.getVirtualhost());
+ objname.returnObjects();
+ if (objname.getSet().size() != 0)
+ {
+ objname.displayinfo(this.getOutputFormat(), this.getSeperator());
+
+ }
+ else
+ {
+ if (hasName())
+ {
+
+ echo("You might querying wrong " + this.getObject() + " name with --name or -n option ");
+ echo("");
+ echo("No "+this.getObject() + "Type Objects might not be in the broker currently");
+ echo("");
+ }
+ else
+ {
+ printusage();
+ }
+ }
+
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+
+ }
+
+ public void execute()
+ {
+ /*
+ * In here you it's easy to handle any number of otpions which are going
+ * to add with the list command which works with main option object or o
+ */
+ if (checkoptionsetting("output"))
+ {
+ setOutputFormat(optionchecker("output"));
+ if (checkoptionsetting("separator"))
+ setSeperator(optionchecker("separator"));
+ }
+ if (checkoptionsetting("object") || checkoptionsetting("o"))
+ {
+ String object = optionchecker("object");
+ if (object == null)
+ {
+ object = optionchecker("o");
+ }
+ setObject(object);
+ if (checkoptionsetting("name") || checkoptionsetting("n"))
+ {
+ String name = optionchecker("name");
+ if (name == null)
+ name = optionchecker("n");
+
+ setName(name);
+ }
+ if (checkoptionsetting("virtualhost") || checkoptionsetting("v"))
+ {
+ String vhost = optionchecker("virtualhost");
+ if (vhost == null)
+ vhost = optionchecker("v");
+ setVirtualhost(vhost);
+ }
+ listobjects(this.getObject());
+ }
+ else if (checkoptionsetting("h") || checkoptionsetting("help"))
+ printusage();
+ else
+ unrecognizeoption();
+ }
+
+ public void printusage()
+ {
+ echo("");
+ echo("Usage:info [OPTION] ... [OBJECT TYPE]...\n");
+ echo("Give ALL the information about the given object\n");
+ echo("Where possible options include:\n");
+ echo(" -o --object type of objects which you want to list\n");
+ echo(" ex: < list -o queue > : lists all the queues created in the java broker\n");
+ echo(" For now list command is supporting following object typse \n");
+ echo(" Queue Connection VirtualHost UserMangement Exchange");
+ echo(" Or You can specify object type by giving it at the beginning rather giving ");
+ echo(" it as a argument");
+ echo(" Ex:< queue info > this command is equal to <info -o queue> command \n");
+ echo(" -v --virtualhost After specifying the object type you can filter output with this option");
+ echo(" list objects with the given virtualhost which will help to find identical");
+ echo(" queue objects with -n option");
+ echo(" ex: queue info -v developement");
+ echo(" -output Specify which output format you want to get the ouput");
+ echo(" Although the option is there current version supports only for CSV output format");
+ echo(" -separator This option use with output option to specify which separator you want to get the CSV output (default seperator is comma");
+ echo(" -h --help Display the help and back to the qpid-cli prompt\n");
+ echo(" -n --name After specifying what type of objects you want to monitor you can filter");
+ echo(" the output using -n option by specifying the name of the object you want");
+ echo(" to monitor exactly");
+ echo(" ex: <queue info -n ping> : Give all the information about queue objects ");
+ echo(" having queue name of ping\n");
+ }
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandlist.java b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandlist.java
new file mode 100644
index 0000000000..68ee593ba0
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandlist.java
@@ -0,0 +1,232 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.commands;
+
+import java.util.Set;
+
+import javax.management.MBeanServerConnection;
+
+import org.apache.qpid.commands.objects.AllObjects;
+import org.apache.qpid.commands.objects.ConnectionObject;
+import org.apache.qpid.commands.objects.ExchangeObject;
+import org.apache.qpid.commands.objects.ObjectNames;
+import org.apache.qpid.commands.objects.QueueObject;
+import org.apache.qpid.commands.objects.UserManagementObject;
+import org.apache.qpid.commands.objects.VirtualHostObject;
+import org.apache.qpid.utils.JMXinfo;
+
+public class Commandlist extends CommandImpl
+{
+
+ public static final String COMMAND_NAME = "list";
+
+ public Commandlist(JMXinfo info)
+ {
+ super(info);
+ }
+
+ private void listobjects(String option_value)
+ {
+ /*
+ * pring usage if use is not give the correct option letter or no
+ * options
+ */
+ if (option_value == null)
+ {
+ // System.out.println("testing");
+ printusage();
+ return;
+ }
+ MBeanServerConnection mbsc = info.getmbserverconnector();
+ Set set = null;
+ ObjectNames objname = null;
+
+ try
+ {
+ if (option_value.compareToIgnoreCase("queue") == 0 || option_value.compareToIgnoreCase("queues") == 0)
+ {
+ objname = new QueueObject(mbsc);
+
+ }
+ else if (option_value.compareToIgnoreCase("Virtualhosts") == 0
+ || option_value.compareToIgnoreCase("Virtualhost") == 0)
+ {
+ objname = new VirtualHostObject(mbsc);
+ // this.name = option_value;
+ }
+ else if (option_value.compareToIgnoreCase("Exchange") == 0
+ || option_value.compareToIgnoreCase("Exchanges") == 0)
+ {
+ objname = new ExchangeObject(mbsc);
+ // this.name = option_value;
+ }
+ else if (option_value.compareToIgnoreCase("Connection") == 0
+ || option_value.compareToIgnoreCase("Connections") == 0)
+ {
+ objname = new ConnectionObject(mbsc);
+ // this.name = option_value;
+ }
+ else if (option_value.compareToIgnoreCase("all") == 0)
+ {
+ objname = new AllObjects(mbsc);
+ // this.name = option_value;
+ }
+ else if (option_value.compareToIgnoreCase("Usermanagement") == 0
+ || option_value.compareToIgnoreCase("Usermanagmenets") == 0)
+ {
+ objname = new UserManagementObject(mbsc);
+ // this.name = option_value;
+ }
+ else
+ {
+ printusage();
+ echo("Wrong objectName");
+ return;
+ }
+ objname.setQueryString(this.getObject(), this.getName(), this.getVirtualhost());
+ objname.returnObjects();
+ if (objname.getSet().size() != 0)
+ {
+ if (this.getObject().compareToIgnoreCase("queue") == 0
+ || this.getObject().compareToIgnoreCase("queues") == 0)
+ objname.displayqueues(this.getOutputFormat(), this.getSeperator());
+ else
+ objname.displayobjects(this.getOutputFormat(), this.getSeperator());
+ }
+ else
+ {
+ if (hasName())
+ {
+
+ echo("You might quering wrong " + this.getObject() + " name with --name or -n option ");
+ echo("");
+ echo(this.getObject() + "Type Objects might not in the broker currently");
+ echo("");
+ }
+ else
+ {
+ printusage();
+ }
+ }
+
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+
+ }
+
+ public void listdomains()
+ {
+ MBeanServerConnection mbsc = info.getmbserverconnector();
+ try
+ {
+ String[] domains = mbsc.getDomains();
+ echo("DOMAINS");
+ for (int i = 0; i < domains.length; i++)
+ echo("\tDomain[" + i + "] = " + domains[i]);
+
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
+ public void execute()
+ {
+ /*
+ * In here you it's easy to handle any number of otpions which are going
+ * to add with the list command which works with main option object or o
+ */
+ if (checkoptionsetting("output"))
+ {
+ setOutputFormat(optionchecker("output"));
+ if (checkoptionsetting("separator"))
+ setSeperator(optionchecker("separator"));
+ }
+ if (checkoptionsetting("object") || checkoptionsetting("o"))
+ {
+ String object = optionchecker("object");
+ if (object == null)
+ {
+ object = optionchecker("o");
+ }
+ setObject(object);
+ if (checkoptionsetting("name") || checkoptionsetting("n"))
+ {
+ String name = optionchecker("name");
+ if (name == null)
+ name = optionchecker("n");
+
+ setName(name);
+ }
+ if (checkoptionsetting("virtualhost") || checkoptionsetting("v"))
+ {
+ String vhost = optionchecker("virtualhost");
+ if (vhost == null)
+ vhost = optionchecker("v");
+ setVirtualhost(vhost);
+ }
+ listobjects(this.getObject());
+ }
+ else if (checkoptionsetting("domain") || checkoptionsetting("d"))
+ listdomains();
+ else if (checkoptionsetting("h") || checkoptionsetting("help"))
+ printusage();
+ else
+ unrecognizeoption();
+ }
+
+ public void printusage()
+ {
+ echo("");
+ echo("Usage:list [OPTION] ... [OBJECT TYPE]...\n");
+ echo("List the information about the given object\n");
+ echo("Where possible options include:\n");
+ echo(" -o --object type of objects which you want to list\n");
+ echo(" ex: < list -o queue > : lists all the queues created in the java broker\n");
+ echo(" For now list command is supporting following object typse \n");
+ echo(" Queue Connection VirtualHost UserMangement Exchange");
+ echo(" Or You can specify object type by giving it at the beginning");
+ echo(" rather giving it as a argument");
+ echo(" Ex:< queue list > this command is equal to list -o queue \n");
+ echo(" -d --domain list all the domains of objects available for remote monitoring\n");
+ echo(" -v --virtualhost After specifying the object type you can filter output with this option");
+ echo(" list objects with the given virtualhost which will help to find ");
+ echo(" identical queue objects with -n option");
+ echo(" ex: queue list -v develop ment");
+ echo(" -output Specify which output format you want to get the ouput");
+ echo(" Although the option is there current version supports only for CSV output format");
+ echo(" -separator This option use with output option to specify which separator you want to get the CSV output (default seperator is comma");
+ echo(" -h --help Display the help and back to the qpid-cli prompt\n");
+ echo(" -n --name After specifying what type of objects you want to monitor you can filter");
+ echo(" the output using -n option by specifying the name of the object you want ");
+ echo(" to monitor exactly");
+ echo(" ex: <list -o queue -n ping> : list all the queue objects having queue name");
+ echo(" of ping");
+ echo(" ex: <queue list -n ping -v development> list all the queue objects with name ");
+ echo(" of ping and virtualhost of developement \n");
+
+ }
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandmove.java b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandmove.java
new file mode 100644
index 0000000000..6d1803409b
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandmove.java
@@ -0,0 +1,259 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.commands;
+
+import java.util.Iterator;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+
+import org.apache.qpid.commands.objects.QueueObject;
+import org.apache.qpid.utils.JMXinfo;
+
+public class Commandmove extends CommandImpl
+{
+
+ public static final String COMMAND_NAME = "move";
+
+ private String name1 = null, name2 = null, vhost1 = null, vhost2 = null, method1 = null, method2 = null; // target
+ // and
+ // starting
+ // queue
+ // specifications
+ // happen
+ // with
+ // these
+ // options
+ private QueueObject queue1;
+ private MBeanServerConnection mbsc;
+ private ObjectName queue;
+ private int fmid = 0, tmid = 0;
+
+ public Commandmove(JMXinfo info)
+ {
+ super(info);
+
+ this.mbsc = info.getmbserverconnector();
+ this.queue1 = new QueueObject(mbsc);
+ this.method1 = "moveMessages";
+ this.method2 = "getMessagesOnTheQueue";
+
+ }
+
+ public void movemessages()
+ {
+ Set set = null;
+ queue1.setQueryString(this.getObject(), this.name1, this.vhost1);
+ set = queue1.returnObjects();
+ if (queue1.getSet().size() != 0)
+ { // find the queue
+ Iterator it = set.iterator();
+ this.queue = (ObjectName) it.next();
+ }
+ else
+ {
+ if (isname1() || isname2())
+ { // if the specified queue is not there in the broker
+
+ echo("The Queue you have specified is not in the current broker");
+ echo("");
+ }
+ else
+ {
+ printusage();
+ }
+ }
+ try
+ {
+ Object[] params1 = { getfmid(), gettmid(), this.name2 };
+ String[] signature1 = { new String("long"), new String("long"), new String("java.lang.String") };
+ this.mbsc.invoke(this.queue, this.method1, params1, signature1);
+
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ echo("Given messageId's might be wrong please run the view command and check messageId's you have given\n");
+ echo("From MessageId should be greater than 0 and should less than To messageId");
+ }
+
+ }
+
+ public void execute()
+ {
+ /*
+ * In here you it's easy to handle any number of otpions which are going
+ * to add with the list command which works with main option object or o
+ */
+
+ if (checkoptionsetting("object") || checkoptionsetting("o"))
+ {
+ String object = optionchecker("object");
+ if (object == null)
+ {
+ object = optionchecker("o");
+ }
+ if (object.compareToIgnoreCase("queue") == 0)
+ setObject(object);
+ else
+ {
+ unrecognizeoption();
+ echo("This command is only applicable for queue command so please start with queue");
+ }
+ if (checkoptionsetting("n2") && checkoptionsetting("n1"))
+ {
+ setname1(optionchecker("n1"));
+ setname2(optionchecker("n2"));
+ }
+ else
+ {
+ echo("You have to specify both n1 and n2 option value to move a message"); /*
+ * when
+ * user
+ * forget
+ * to
+ * specify
+ * target
+ * or
+ * starting
+ * queue
+ * name
+ */
+ return;
+ }
+
+ if (checkoptionsetting("v1"))
+ {
+
+ setvhost1(optionchecker("v1"));
+ }
+ if (checkoptionsetting("tmid") && checkoptionsetting("fmid"))
+ {
+ String tmid = optionchecker("tmid");
+ String fmid = optionchecker("fmid");
+
+ settomessageIdandfrommessageId(removeSpaces(tmid), removeSpaces(fmid));
+ }
+ else
+ {
+ echo("You have to set from MessageId and to MessageId in order to move messages between queues");
+ echo("To view MessageId's use <view> command with -n and -v options");
+ return;
+ }
+ this.movemessages();
+
+ }
+ else if (checkoptionsetting("h") || checkoptionsetting("help"))
+ printusage();
+ else
+ unrecognizeoption();
+ }
+
+ public void printusage()
+ {
+ echo("");
+ echo("Usage:move [OPTION] ... [OBJECT TYPE]...\n");
+ echo("Move the top most messages from the given queue object to the given destination object\n");
+ echo("To specify the desired queues you have to give the virtualhost name and the queue name with following commands\n");
+ echo("Where possible options include:\n");
+ echo(" -v1 Give the virtuallhost name from which queue you want to move messages");
+ echo(" -n1 Give the queue name which you want to move messages from");
+ echo(" -n2 Give the queue name of the destination queue");
+ echo(" -tmid Give From MessageId you want to move from the Queue");
+ echo(" -fmid Give To MessageId you want to move from the Queue");
+ echo(" -h --help Display the help and back to the qpid-cli prompt\n");
+
+ }
+
+ private void setname1(String name)
+ {
+ this.name1 = name;
+ }
+
+ private void setname2(String name)
+ {
+ this.name2 = name;
+ }
+
+ private boolean isname1()
+ {
+ if (this.name1 == null)
+ return false;
+
+ else
+ return true;
+ }
+
+ private boolean isname2()
+ {
+ if (this.name2 == null)
+ return false;
+
+ else
+ return true;
+ }
+
+ private void setvhost1(String vhost)
+ {
+ this.vhost1 = vhost;
+ }
+
+ private static String removeSpaces(String s)
+ {
+ StringTokenizer st = new StringTokenizer(s, " ", false);
+ String t = "";
+ while (st.hasMoreElements())
+ t += st.nextElement();
+ return t;
+ }
+
+ private void settomessageIdandfrommessageId(String tmid, String fmid)
+ {
+ Integer i = new Integer(tmid);
+ Integer j = new Integer(fmid);
+ this.tmid = i.intValue();
+ this.fmid = j.intValue();
+ }
+
+ public int gettmid()
+ {
+ return this.tmid;
+ }
+
+ public int getfmid()
+ {
+ return this.fmid;
+ }
+
+ public String getname1()
+ {
+ return this.name1;
+ }
+
+ public String getname2()
+ {
+ return this.name2;
+ }
+
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandset.java b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandset.java
new file mode 100644
index 0000000000..b5cc9e6090
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandset.java
@@ -0,0 +1,260 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.commands;
+
+import org.apache.qpid.commands.objects.ObjectNames;
+import org.apache.qpid.commands.objects.QueueObject;
+import org.apache.qpid.utils.JMXinfo;
+
+import javax.management.Attribute;
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+import java.util.Set;
+
+public class Commandset extends CommandImpl
+{
+ private String _attributeName;
+ private String _value;
+ public static String COMMAND_NAME = "set";
+
+ public Commandset(JMXinfo info)
+ {
+ super(info);
+ }
+
+ private void setAttribute(String option_value)
+ {
+ /*
+ * print usage if use is not give the correct option letter or no
+ * options
+ */
+ if (option_value == null)
+ {
+ printusage();
+ return;
+ }
+ MBeanServerConnection mbsc = info.getmbserverconnector();
+ Set set = null;
+ ObjectNames objname = null;
+
+ try
+ {
+ if (option_value.compareToIgnoreCase("queue") == 0 || option_value.compareToIgnoreCase("queues") == 0)
+ {
+ objname = new QueueObject(mbsc);
+ }
+ else
+ {
+ printusage();
+ echo("Wrong objectName");
+ return;
+ }
+
+ if (_attributeName == null)
+ {
+ echo("attribute name not specified. See --help for details");
+ return;
+ }
+
+ if (_value == null)
+ {
+ echo("new value not specified. See --help for details");
+ return;
+ }
+
+ objname.setQueryString(this.getObject(), this.getName(), this.getVirtualhost());
+ objname.returnObjects();
+
+ if (objname.getSet().size() != 1)
+ {
+ echo("Your query returned more than one object to set was this intended?" + objname.getQueryString());
+ }
+ else if (objname.getSet().size() == 1)
+ {
+ ObjectName object = (ObjectName) objname.getSet().iterator().next();
+
+ Object value = objname.getAttribute(object, _attributeName);
+
+ Object attributeValue = _value;
+
+ try
+ {
+ if (value instanceof Integer)
+ {
+ attributeValue = Integer.valueOf(_value);
+ }
+ else if (value instanceof Long)
+ {
+ attributeValue = Long.valueOf(_value);
+ }
+ }
+ catch (NumberFormatException nfe)
+ {
+ echo("Value(" + _attributeName + ") should be of type " + value.getClass().getName());
+ return;
+ }
+
+ Attribute attribute = new Attribute(_attributeName, attributeValue);
+
+ objname.setAttribute(object, attribute);
+ }
+ else
+ {
+ if (hasName())
+ {
+
+ echo("You might be querying wrong " + this.getObject() + " name with --name or -n option ");
+ echo("");
+ echo("No " + this.getObject() + "Type Objects might not in the broker currently");
+ echo("");
+ }
+ else
+ {
+ printusage();
+ }
+ }
+
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+
+ }
+
+ public void execute()
+ {
+ /*
+ * In here you it's easy to handle any number of otpions which are going
+ * to add with the list command which works with main option object or o
+ */
+ if (checkoptionsetting("output"))
+ {
+ setOutputFormat(optionchecker("output"));
+ if (checkoptionsetting("separator"))
+ {
+ setSeperator(optionchecker("separator"));
+ }
+ }
+ if (checkoptionsetting("object") || checkoptionsetting("o"))
+ {
+ String object = optionchecker("object");
+ if (object == null)
+ {
+ object = optionchecker("o");
+ }
+ setObject(object);
+
+ if (checkoptionsetting("name") || checkoptionsetting("n"))
+ {
+ String name = optionchecker("name");
+ if (name == null)
+ {
+ name = optionchecker("n");
+ }
+
+ setName(name);
+ }
+
+ if (checkoptionsetting("attribute") || checkoptionsetting("a"))
+ {
+ String name = optionchecker("attribute");
+ if (name == null)
+ {
+ name = optionchecker("a");
+ }
+
+ setAttributeName(name);
+ }
+
+ if (checkoptionsetting("set") || checkoptionsetting("s"))
+ {
+ String value = optionchecker("set");
+ if (value == null)
+ {
+ value = optionchecker("s");
+ }
+
+ setAttributeValue(value);
+ }
+
+ if (checkoptionsetting("virtualhost") || checkoptionsetting("v"))
+ {
+ String vhost = optionchecker("virtualhost");
+ if (vhost == null)
+ {
+ vhost = optionchecker("v");
+ }
+ setVirtualhost(vhost);
+ }
+ setAttribute(this.getObject());
+ }
+ else if (checkoptionsetting("h") || checkoptionsetting("help"))
+ {
+ printusage();
+ }
+ else
+ {
+ unrecognizeoption();
+ }
+ }
+
+ private void setAttributeValue(String value)
+ {
+ _value = value;
+ }
+
+ private void setAttributeName(String name)
+ {
+ this._attributeName = name;
+ }
+
+ public void printusage()
+ {
+ echo("");
+ echo("Usage:set [OPTION] ... [OBJECT TYPE]...\n");
+ echo("List the information about the given object\n");
+ echo("Where possible options include:\n");
+ echo(" -o --object type of objects which you want to list\n");
+ echo(" ex: < list -o queue > : lists all the queues created in the java broker\n");
+ echo(" For now list command is supporting following object typse \n");
+ echo(" Queue Connection VirtualHost UserMangement Exchange");
+ echo(" Or You can specify object type by giving it at the beginning");
+ echo(" rather giving it as a argument");
+ echo(" Ex:< queue list > this command is equal to list -o queue \n");
+ echo(" -v --virtualhost After specifying the object type you can filter output with this option");
+ echo(" list objects with the given virtualhost which will help to find ");
+ echo(" identical queue objects with -n option");
+ echo(" ex: queue list -v develop ment");
+ echo(" -n --name After specifying what type of objects you want to monitor you can filter");
+ echo(" the output using -n option by specifying the name of the object you want ");
+ echo(" to monitor exactly");
+ echo(" ex: <list -o queue -n ping> : list all the queue objects having queue name");
+ echo(" of ping");
+ echo(" ex: <queue list -n ping -v development> list all the queue objects with name ");
+ echo(" of ping and virtualhost of developement \n");
+ echo(" -a --attribute ");
+ echo(" -h --help Display the help and back to the qpid-cli prompt\n");
+
+ }
+
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandview.java b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandview.java
new file mode 100644
index 0000000000..e98cb336d8
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandview.java
@@ -0,0 +1,257 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.commands;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularDataSupport;
+
+import org.apache.qpid.commands.objects.QueueObject;
+import org.apache.qpid.utils.JMXinfo;
+
+public class Commandview extends CommandImpl
+{
+
+ public static final String COMMAND_NAME = "view";
+
+ private int number = 0;
+ private QueueObject objname;
+ private MBeanServerConnection mbsc;
+ private String method1;
+ private ObjectName queue;
+
+ public Commandview(JMXinfo info)
+ {
+ super(info);
+ this.mbsc = info.getmbserverconnector();
+ this.objname = new QueueObject(mbsc);
+ this.method1 = "viewMessages";
+
+ }
+
+ public void viewmessages()
+ {
+ Set set = null;
+ Object temp[] = { null };
+ objname.setQueryString(this.getObject(), this.getName(), this.getVirtualhost());
+ set = objname.returnObjects();
+ String header = "", temp_header = "", message_data = "", outline = "";
+
+ if (objname.getSet().size() != 0)
+ {
+ Iterator it = set.iterator();
+ this.queue = (ObjectName) it.next();
+ try
+ {
+ if (objname.getmessagecount(this.queue) == 0)
+ {
+ echo("Selected Queue doesn't contain any messages");
+ return;
+ }
+ if (this.number == 0)
+ this.number = objname.getmessagecount(this.queue);
+
+ if (objname.getmessagecount(this.queue) < this.number)
+ {
+ echo("Given number is Greater than the Queue Depth");
+ return;
+ }
+ else
+ {
+ Object[] params = { 1, this.number };
+ String[] signature = { new String("int"), new String("int") };
+ TabularDataSupport data = (TabularDataSupport) this.mbsc.invoke(queue, this.method1, params,
+ signature);
+
+ Set entrySet = data.entrySet();
+ ArrayList<Map.Entry> list = new ArrayList<Map.Entry>(entrySet);
+ if (list.size() != 0)
+ {// no data}
+ for (int i = 0; i < list.size(); i++)
+ {
+ CompositeData compositedata = (CompositeData) (list.get(i)).getValue();
+ List<String> itemNames = new ArrayList<String>(compositedata.getCompositeType().keySet());
+ if (i == 0) // display the table headers
+ {
+ for (int j = 0; j < itemNames.size(); j++)
+ {
+ temp_header = "";
+ if (j != 1) // skipping header information
+ {
+ temp_header = itemNames.get(j);
+ while (temp_header.length() < 15)
+ temp_header = " " + temp_header;
+
+ header = header + temp_header + "|";
+ }
+ else
+ continue;
+ }
+ echo(header);
+ while (outline.length() < header.length())
+ outline = outline + "-";
+ echo(outline);
+ }
+
+ for (int j = 0; j < itemNames.size(); j++)
+ {
+ temp_header = "";
+ if (j != 1)
+ {
+ temp_header = String.valueOf(compositedata.get(itemNames.get(j)));
+ while (temp_header.length() < 15)
+ temp_header = " " + temp_header;
+ message_data = message_data + temp_header + "|";
+ }
+ else
+ // header information is not displaying
+ // unless user specify header information is
+ // needed
+ continue;
+
+ }
+ echo(message_data);
+ header = "";
+ message_data = "";
+ }
+ }
+ else
+ {
+ System.out.println("No Data to Display");
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+
+ }
+ else
+ {
+ if (hasName())
+ {
+
+ echo("The Queue you have specified is not in the current broker");
+ echo("");
+ }
+ else
+ {
+ printusage();
+ }
+ }
+ }
+
+ public void execute()
+ {
+ /*
+ * In here you it's easy to handle any number of otpions which are going
+ * to add with the list command which works with main option object or o
+ */
+
+ if (checkoptionsetting("object") || checkoptionsetting("o"))
+ {
+ String object = optionchecker("object");
+ if (object == null)
+ {
+ object = optionchecker("o");
+ }
+ if (object.compareToIgnoreCase("queue") == 0)
+ setObject(object);
+ else
+ {
+ unrecognizeoption();
+ echo("This command is only applicable for delete command so please start with queue");
+ }
+ if (checkoptionsetting("name") || checkoptionsetting("n"))
+ {
+ String name = optionchecker("name");
+ if (name == null)
+ name = optionchecker("n");
+
+ setName(name);
+ }
+ if (checkoptionsetting("virtualhost") || checkoptionsetting("v"))
+ {
+ String vhost = optionchecker("virtualhost");
+ if (vhost == null)
+ vhost = optionchecker("v");
+ setVirtualhost(vhost);
+ }
+ if (checkoptionsetting("top") || checkoptionsetting("t"))
+ {
+ String number = optionchecker("top");
+ if (number == null)
+ number = optionchecker("t");
+
+ setnumber(removeSpaces(number));
+ }
+ this.viewmessages();
+ }
+ else if (checkoptionsetting("h") || checkoptionsetting("help"))
+ printusage();
+ else
+ unrecognizeoption();
+ }
+
+ public void printusage()
+ {
+ echo("");
+ echo("Usage:view [OPTION] ... [OBJECT TYPE]...\n");
+ echo("view the information about given number of messages from the given queue object\n");
+ echo("To specify the desired queue you have to give the virtualhost name and the queue name with following commands\n");
+ echo("Where possible options include:\n");
+ echo(" -v --virtualhost Give the virtuallhost name of the desired queue");
+ echo(" -n --name Give the queue name of the desired queue you want to view messages");
+ echo(" -t --top Give how many number of messages you want to delete from the top (Default = all the messages will be deleted");
+ echo(" -h --help Display the help and back to the qpid-cli prompt\n");
+
+ }
+
+ private void setnumber(String number)
+ {
+ Integer i = new Integer(number);
+ this.number = i.intValue();
+ }
+
+ private static String removeSpaces(String s)
+ {
+ StringTokenizer st = new StringTokenizer(s, " ", false);
+ String t = "";
+ while (st.hasMoreElements())
+ t += st.nextElement();
+ return t;
+ }
+
+ public int getnumber()
+ {
+ return number;
+ }
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandviewcontent.java b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandviewcontent.java
new file mode 100644
index 0000000000..0c8a4b62b4
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/Commandviewcontent.java
@@ -0,0 +1,250 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.commands;
+
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+import javax.management.openmbean.CompositeData;
+
+import org.apache.qpid.commands.objects.QueueObject;
+import org.apache.qpid.utils.JMXinfo;
+
+public class Commandviewcontent extends CommandImpl
+{
+
+ public static final String COMMAND_NAME = "viewcontent";
+
+ private long number = 0;
+ private QueueObject objname;
+ private MBeanServerConnection mbsc;
+ private String method1;
+ private ObjectName queue;
+
+ public Commandviewcontent(JMXinfo info)
+ {
+ super(info);
+ this.mbsc = info.getmbserverconnector();
+ this.objname = new QueueObject(mbsc);
+ this.method1 = "viewMessageContent";
+
+ }
+
+ public void viewcontent()
+ {
+ Set set = null;
+ Object temp[] = { null };
+ objname.setQueryString(getObject(), getName(), getVirtualhost());
+ set = objname.returnObjects();
+ String temp_header = "", header = "", message_data = "", encoding = null;
+
+ if (objname.getSet().size() != 0)
+ {
+ Iterator it = set.iterator();
+ this.queue = (ObjectName) it.next();
+ try
+ {
+ if (objname.getmessagecount(this.queue) == 0)
+ {
+ echo("Selected Queue doesn't contain any messages");
+ return;
+ }
+ if (this.number == 0)
+ {
+ echo("You haven't selected a MessageId Please use -id and give a message id");
+ echo("Or run view command with same arguemnts to view messageId list for the queue");
+ }
+ else
+ {
+ Object[] params = { this.number };
+ String[] signature = { new String("long") };
+ CompositeData data = (CompositeData) this.mbsc.invoke(queue, this.method1, params, signature);
+ List<String> itemNames = new ArrayList<String>(data.getCompositeType().keySet());
+ for (int j = 0; j < itemNames.size(); j++)
+ {
+ temp_header = "";
+ temp_header = itemNames.get(j);
+ while (temp_header.length() < 15)
+ temp_header = " " + temp_header;
+
+ header = header + temp_header + "|";
+ }
+ echo(header);
+ encoding = String.valueOf(data.get(itemNames.get(2))); // set
+ // the
+ // encoding
+ // at
+ // the
+ // beginning
+ // because
+ // encoding
+ // comes
+ // later
+ // in
+ // the
+ // loop
+ if (encoding == null || encoding.length() == 0)
+ {
+ encoding = Charset.defaultCharset().name();
+
+ }
+ for (int j = 0; j < itemNames.size(); j++)
+ {
+ temp_header = "";
+ if (j != 1)
+ {
+ temp_header = String.valueOf(data.get(itemNames.get(j)));
+ while (temp_header.length() < 15)
+ temp_header = " " + temp_header;
+ }
+ else
+ {
+ Byte[] arrayItems = (Byte[]) data.get(itemNames.get(j));
+ byte[] byteArray = new byte[arrayItems.length];
+ for (int i = 0; i < arrayItems.length; i++)
+ {
+ byteArray[i] = arrayItems[i];
+ temp_header = new String(byteArray, encoding);
+ while (temp_header.length() < 15)
+ temp_header = " " + temp_header;
+ }
+ }
+ message_data = message_data + temp_header + "|";
+
+ }
+ echo(message_data);
+ }
+ }
+ catch (Exception ex)
+ {
+ echo("Given MessageId is invalid, There's no message with the given messageId");
+ ex.printStackTrace();
+ return;
+ }
+
+ }
+ else
+ {
+ if (hasName())
+ {
+
+ echo("The Queue you have specified is not in the current broker");
+ echo("");
+ }
+ else
+ {
+ printusage();
+ }
+ }
+ }
+
+ public void execute()
+ {
+ /*
+ * In here you it's easy to handle any number of otpions which are going
+ * to add with the list command which works with main option object or o
+ */
+
+ if (checkoptionsetting("object") || checkoptionsetting("o"))
+ {
+ String object = optionchecker("object");
+ if (object == null)
+ {
+ object = optionchecker("o");
+ }
+ if (object.compareToIgnoreCase("queue") == 0)
+ setObject(object);
+ else
+ {
+ unrecognizeoption();
+ echo("This command is only applicable for delete command so please start with queue");
+ }
+ if (checkoptionsetting("name") || checkoptionsetting("n"))
+ {
+ String name = optionchecker("name");
+ if (name == null)
+ name = optionchecker("n");
+
+ setName(name);
+ }
+ if (checkoptionsetting("virtualhost") || checkoptionsetting("v"))
+ {
+ String vhost = optionchecker("virtualhost");
+ if (vhost == null)
+ vhost = optionchecker("v");
+ setVirtualhost(vhost);
+ }
+ if (checkoptionsetting("messageid") || checkoptionsetting("id"))
+ {
+ String number = optionchecker("id");
+ if (number == null)
+ number = optionchecker("id");
+
+ setnumber(removeSpaces(number));
+ }
+ this.viewcontent();
+ }
+ else if (checkoptionsetting("h") || checkoptionsetting("help"))
+ printusage();
+ else
+ unrecognizeoption();
+ }
+
+ public void printusage()
+ {
+ echo("");
+ echo("Usage:viewcontent [OPTION] ... [OBJECT TYPE]...\n");
+ echo("view the information about given number of messages from the given queue object\n");
+ echo("To specify the desired queue you have to give the virtualhost name and the queue name with following commands\n");
+ echo("Where possible options include:\n");
+ echo(" -v --virtualhost Give the virtuallhost name of the desired queue");
+ echo(" -n --name Give the queue name of the desired queue you want to view messages");
+ echo(" -id Give the messageId of the required message you want to view the content");
+ echo(" -h --help Display the help and back to the qpid-cli prompt\n");
+
+ }
+
+ private void setnumber(String number)
+ {
+ this.number = Long.valueOf(number);
+ }
+
+ private static String removeSpaces(String s)
+ {
+ StringTokenizer st = new StringTokenizer(s, " ", false);
+ String t = "";
+ while (st.hasMoreElements())
+ t += st.nextElement();
+ return t;
+ }
+
+ public long getnumber()
+ {
+ return this.number;
+ }
+
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/AllObjects.java b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/AllObjects.java
new file mode 100644
index 0000000000..8b2099f3e0
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/AllObjects.java
@@ -0,0 +1,38 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.commands.objects;
+
+import javax.management.MBeanServerConnection;
+
+public class AllObjects extends ObjectNames
+{
+
+ public AllObjects(MBeanServerConnection mbsc)
+ {
+ super(mbsc);
+ }
+
+ public void setQueryString(String object, String name)
+ {
+ querystring = "org.apache.qpid:*";
+ }
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/ConnectionObject.java b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/ConnectionObject.java
new file mode 100644
index 0000000000..2746b2016f
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/ConnectionObject.java
@@ -0,0 +1,46 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.commands.objects;
+
+import javax.management.MBeanServerConnection;
+
+public class ConnectionObject extends ObjectNames
+{
+ public ConnectionObject(MBeanServerConnection mbsc)
+ {
+ /* calling parent classes constructor */
+ super(mbsc);
+ }
+
+ public void setQueryString(String object, String name, String vhost)
+ {
+ if (name != null && vhost == null)
+ querystring = "org.apache.qpid:type=Connection,name=" + name + ",*";
+ else if (name != null && vhost != null)
+ querystring = "org.apache.qpid:type=Connection,VirtualHost=" + vhost + ",name=" + name + ",*";
+ else if (name == null && vhost != null)
+ querystring = "org.apache.qpid:type=Connection,VirtualHost=" + vhost + ",*";
+ else
+ querystring = "org.apache.qpid:type=Connection,*";
+
+ }
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/ExchangeObject.java b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/ExchangeObject.java
new file mode 100644
index 0000000000..96d7e6e5dc
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/ExchangeObject.java
@@ -0,0 +1,45 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.commands.objects;
+
+import javax.management.MBeanServerConnection;
+
+public class ExchangeObject extends ObjectNames
+{
+ public ExchangeObject(MBeanServerConnection mbsc)
+ {
+ super(mbsc);
+ }
+
+ public void setQueryString(String object, String name, String vhost)
+ {
+ if (name != null && vhost == null)
+ querystring = "org.apache.qpid:type=VirtualHost.Exchange,name=" + name + ",*";
+ else if (name != null && vhost != null)
+ querystring = "org.apache.qpid:type=VirtualHost.Exchange,VirtualHost=" + vhost + ",name=" + name + ",*";
+ else if (name == null && vhost != null)
+ querystring = "org.apache.qpid:type=VirtualHost.Exchange,VirtualHost=" + vhost + ",*";
+ else
+ querystring = "org.apache.qpid:type=VirtualHost.Exchange,*";
+
+ }
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/ObjectNames.java b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/ObjectNames.java
new file mode 100644
index 0000000000..1432f18018
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/ObjectNames.java
@@ -0,0 +1,591 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.commands.objects;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.Attribute;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+
+import org.apache.qpid.management.common.mbeans.ManagedQueue;
+
+public class ObjectNames
+{
+ public String querystring = null;
+ public MBeanServerConnection mbsc;
+ public Set<ObjectName> set = null;
+ public String attributes = "";
+ public String attributevalues = "";// = null;
+
+ private static final Map<String,Integer> QUEUE_ATTRIBUTES = new HashMap<String,Integer>();
+ static
+ {
+ QUEUE_ATTRIBUTES.put(ManagedQueue.ATTR_NAME, 1);
+ QUEUE_ATTRIBUTES.put(ManagedQueue.ATTR_DURABLE, 2);
+ QUEUE_ATTRIBUTES.put(ManagedQueue.ATTR_ACTIVE_CONSUMER_COUNT, 3);
+ QUEUE_ATTRIBUTES.put(ManagedQueue.ATTR_MSG_COUNT, 4);
+ QUEUE_ATTRIBUTES.put(ManagedQueue.ATTR_RCVD_MSG_COUNT, 5);
+ }
+
+ public ObjectNames(MBeanServerConnection mbsc)
+ {
+ this.mbsc = mbsc;
+ }
+
+ public Set<ObjectName> returnObjects()
+ {
+ try
+ {
+ set = mbsc.queryNames(new ObjectName(querystring), null);
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ return set;
+ }
+
+ public void echo(String str)
+ {
+ System.out.println(str);
+ }
+
+ /* display appropriate objects according to the ojbect type */
+
+ public void displayobjects(String output, String seperator)
+ {
+ Iterator it = set.iterator();
+ String line = "";
+ String temp2 = "";
+ int iterator = 0;
+ try
+ {
+ do
+ {
+ ObjectName temp_object = null;
+ if (it.hasNext())
+ {
+ temp_object = (ObjectName) it.next();
+ if (temp_object == null)
+ System.out.println("null test");
+ }
+ // echo(temp_object.getCanonicalKeyPropertyListString());
+ MBeanInfo bean_info = mbsc.getMBeanInfo(temp_object);
+ MBeanAttributeInfo[] attr_info = bean_info.getAttributes();
+ if (attr_info == null)
+ {
+ echo(temp_object.toString());
+ String temp = "";
+ while (temp_object.toString().length() > temp.length())
+ temp = "=" + temp;
+ if (output == null)
+ echo(temp);
+
+ }
+ else
+ {
+ for (MBeanAttributeInfo attr : attr_info)
+ {
+ Object toWrite = null;
+
+ try
+ {
+ String temp1 = attr.getName();
+ if (output == null)
+ {
+ while (temp1.length() < 15)
+ temp1 = " " + temp1;
+ attributes = attributes + temp1 + "|";
+ }
+ else if (output.compareToIgnoreCase("csv") == 0)
+ attributes = attributes + temp1 + seperator;
+ else
+ {
+ echo("Wrong output format current version is supporting only for CSV");
+ return;
+ }
+ }
+ catch (Exception x)
+ {
+ x.printStackTrace();
+ }
+ }
+ if (attributes.equalsIgnoreCase(""))
+ {
+ echo(temp_object.toString());
+ String temp = "";
+ while (temp_object.toString().length() > temp.length())
+ temp = "=" + temp;
+ echo(temp);
+ echo("There are no attributes for this object Type");
+ continue;
+ }
+ for (MBeanAttributeInfo attr : attr_info)
+ {
+ Object toWrite = null;
+ temp2 = null;
+ try
+ {
+ toWrite = mbsc.getAttribute(temp_object, attr.getName());
+ }
+ catch (Exception x)
+ {
+ temp2 = "-";
+ }
+ if (toWrite != null)
+ temp2 = toWrite.toString();
+ else
+ temp2 = "-";
+ if (output == null)
+ {
+
+ while (temp2.length() < 15)
+ temp2 = " " + temp2;
+
+ attributevalues = attributevalues + temp2 + "|";
+ }
+ else if (output.compareToIgnoreCase("csv") == 0)
+ attributevalues = attributevalues + temp2 + seperator;
+
+ // echo(temp1 + " " + temp2 + " " + temp3);
+
+ }
+ }
+ iterator++;
+ if (iterator == 1)
+ {
+ echo(attributes);
+ for (int i = 0; i < attributes.length(); i++)
+ line = line + "-";
+ if (output == null)
+ echo(line);
+ }
+ echo(attributevalues);
+ line = "";
+ attributes = "";
+ attributevalues = "";
+ } while (it.hasNext());
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+
+ }
+
+ public void reportgenerator(String output, String seperator, List<String> column)
+ {
+ Iterator it = set.iterator();
+ String line = "";
+ String temp2 = "";
+ int iterator = 0;
+ try
+ {
+ do
+ {
+ ObjectName temp_object = null;
+ if (it.hasNext())
+ {
+ temp_object = (ObjectName) it.next();
+ if (temp_object == null)
+ System.out.println("null test");
+ }
+ // echo(temp_object.getCanonicalKeyPropertyListString());
+ MBeanInfo bean_info = mbsc.getMBeanInfo(temp_object);
+ MBeanAttributeInfo[] attr_info = bean_info.getAttributes();
+ if (attr_info == null)
+ {
+ echo(temp_object.toString());
+ String temp = "";
+ while (temp_object.toString().length() > temp.length())
+ temp = "=" + temp;
+ if (output == null)
+ echo(temp);
+
+ }
+ else
+ {
+ for (MBeanAttributeInfo attr : attr_info)
+ {
+ Object toWrite = null;
+
+ try
+ {
+ String temp1 = attr.getName();
+ if (column.contains(temp1))
+ {
+ if (output == null)
+ {
+ while (temp1.length() < 15)
+ temp1 = " " + temp1;
+ attributes = attributes + temp1 + "|";
+ }
+ else if (output.compareToIgnoreCase("csv") == 0)
+ attributes = attributes + temp1 + seperator;
+ else
+ {
+ echo("Wrong output format current version is supporting only for CSV");
+ return;
+ }
+ }
+ }
+ catch (Exception x)
+ {
+ x.printStackTrace();
+ }
+ }
+ if (attributes.equalsIgnoreCase(""))
+ {
+ echo(temp_object.toString());
+ String temp = "";
+ while (temp_object.toString().length() > temp.length())
+ temp = "=" + temp;
+ echo(temp);
+ echo("There are no attributes for this object Type");
+ return;
+ }
+ for (MBeanAttributeInfo attr : attr_info)
+ {
+ Object toWrite = null;
+ temp2 = null;
+ if (column.contains(attr.getName()))
+ {
+ try
+ {
+ toWrite = mbsc.getAttribute(temp_object, attr.getName());
+ }
+ catch (Exception x)
+ {
+ temp2 = "-";
+ }
+ if (toWrite != null)
+ temp2 = toWrite.toString();
+ else
+ temp2 = "-";
+ if (output == null)
+ {
+
+ while (temp2.length() < 15)
+ temp2 = " " + temp2;
+
+ attributevalues = attributevalues + temp2 + "|";
+ }
+ else if (output.compareToIgnoreCase("csv") == 0)
+ attributevalues = attributevalues + temp2 + seperator;
+
+ // echo(temp1 + " " + temp2 + " " + temp3);
+
+ }
+
+ }
+ }
+ iterator++;
+ if (iterator == 1)
+ {
+ echo(attributes);
+ for (int i = 0; i < attributes.length(); i++)
+ line = line + "-";
+ if (output == null)
+ echo(line);
+ }
+ echo(attributevalues);
+ line = "";
+ attributes = "";
+ attributevalues = "";
+ } while (it.hasNext());
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+
+ }
+
+ public void displayqueues(String output, String seperator)
+ {
+ Iterator it = set.iterator();
+ String line = "";
+ int iterator = 0;
+ String temp1 = "";
+ String temp2 = "";
+ try
+ {
+ do
+ {
+ ObjectName temp_object = null;
+ if (it.hasNext())
+ {
+ temp_object = (ObjectName) it.next();
+ }
+ // echo(temp_object.getCanonicalKeyPropertyListString());
+ MBeanInfo bean_info = mbsc.getMBeanInfo(temp_object);
+ MBeanAttributeInfo[] attr_info = bean_info.getAttributes();
+ if (attr_info == null)
+ {
+ echo(temp_object.toString());
+ String temp = "";
+ while (temp_object.toString().length() > temp.length())
+ temp = "=" + temp;
+ if (output == null)
+ echo(temp);
+
+ }
+ else
+ {
+ for (MBeanAttributeInfo attr : attr_info)
+ {
+ Object toWrite = null;
+ Integer attr_count = QUEUE_ATTRIBUTES.get(attr.getName());
+
+ if(attr_count == null)
+ {
+ continue;
+ }
+
+ try
+ {
+ toWrite = mbsc.getAttribute(temp_object, attr.getName());
+ if (output == null)
+ {
+ switch (attr_count)
+ {
+ case 1:
+ case 2:
+ temp1 = attr.getName();
+ while (temp1.length() < 10)
+ temp1 = " " + temp1;
+ attributes = attributes + temp1 + "|";
+ temp2 = toWrite.toString();
+ while (temp2.length() < 10)
+ temp2 = " " + temp2;
+ attributevalues = attributevalues + temp2 + "|";
+ break;
+ case 3:
+ temp1 = attr.getName();
+ while (temp1.length() < 20)
+ temp1 = " " + temp1;
+ attributes = attributes + temp1 + "|";
+ temp2 = toWrite.toString();
+ while (temp2.length() < 20)
+ temp2 = " " + temp2;
+ attributevalues = attributevalues + temp2 + "|";
+ break;
+ case 4:
+ temp1 = attr.getName();
+ while (temp1.length() < 13)
+ temp1 = " " + temp1;
+ attributes = attributes + temp1 + "|";
+ temp2 = toWrite.toString();
+ while (temp2.length() < 13)
+ temp2 = " " + temp2;
+ attributevalues = attributevalues + temp2 + "|";
+ break;
+ case 5:
+ temp1 = attr.getName();
+ while (temp1.length() < 20)
+ temp1 = " " + temp1;
+ attributes = attributes + temp1 + "|";
+ temp2 = toWrite.toString();
+ while (temp2.length() < 20)
+ temp2 = " " + temp2;
+ attributevalues = attributevalues + temp2 + "|";
+ break;
+ }
+ }
+ else if (output.compareToIgnoreCase("csv") == 0)
+ {
+ temp1 = attr.getName();
+ attributes = attributes + temp1 + seperator;
+ temp2 = toWrite.toString();
+ attributevalues = attributevalues + temp2 + seperator;
+ }
+ else
+ {
+ echo("Wrong output format specified currently CLI supports only csv output format");
+ return;
+ }
+
+ }
+ catch (Exception x)
+ {
+ x.printStackTrace();
+ }
+
+ }
+ }
+ iterator++;
+ if (iterator == 1)
+ {
+ for (int i = 0; i < attributes.length(); i++)
+ line = line + "-";
+ if (output == null)
+ echo(line);
+ echo(attributes);
+ if (output == null)
+ echo(line);
+ }
+ echo(attributevalues);
+ line = "";
+ attributes = "";
+ attributevalues = "";
+ } while (it.hasNext());
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
+ public void displayinfo(String output, String seperator)
+ {
+ Iterator it = set.iterator();
+ String temp1, temp2 = "";
+ try
+ {
+ do
+ {
+
+ ObjectName temp_object = null;
+ if (it.hasNext())
+ {
+ temp_object = (ObjectName) it.next();
+ }
+ // echo(temp_object.getCanonicalKeyPropertyListString());
+ MBeanInfo bean_info = mbsc.getMBeanInfo(temp_object);
+ MBeanAttributeInfo[] attr_info = bean_info.getAttributes();
+ if (attr_info == null)
+ {
+ echo(temp_object.toString());
+ String temp = "";
+ while (temp_object.toString().length() > temp.length())
+ temp = "=" + temp;
+ echo(temp);
+
+ }
+ else
+ {
+ echo(temp_object.toString());
+ String temp = "";
+ while (temp_object.toString().length() > temp.length())
+ temp = "=" + temp;
+ echo(temp);
+
+ for (MBeanAttributeInfo attr : attr_info)
+ {
+ Object toWrite = null;
+
+ try
+ {
+ toWrite = mbsc.getAttribute(temp_object, attr.getName());
+ }
+ catch (Exception x)
+ {
+ temp2 = "-";
+ }
+ temp1 = attr.getName();
+ if (toWrite != null)
+ temp2 = toWrite.toString();
+
+ if (output == null)
+ {
+ while (temp1.length() < 35)
+ temp1 = " " + temp1;
+
+ while (temp2.length() < 35)
+ temp2 = " " + temp2;
+ echo(temp1 + " " + temp2);
+ }
+ else if (output.compareToIgnoreCase("csv") == 0)
+ echo(temp1 + seperator + temp2);
+ else
+ {
+ echo("Wrong output format specified currently CLI supports only csv output format");
+ return;
+ }
+ }
+ echo("");
+ echo("");
+
+ }
+ } while (it.hasNext());
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+
+ }
+
+ public void setQueryString(String object, String name, String vhost)
+ {
+
+ }
+
+ public void setQueryStringforinfo(String object, String name, String virtualhost)
+ {
+
+ }
+
+ public String getQueryString()
+ {
+ return querystring;
+ }
+
+ public Set getSet()
+ {
+ return set;
+ }
+
+ public Object getAttribute(ObjectName object, String attribute)
+ {
+ try
+ {
+ return mbsc.getAttribute(object, attribute);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+
+ public void setAttribute(ObjectName object, Attribute attribute)
+ {
+ try
+ {
+ mbsc.setAttribute(object, attribute);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/QueueObject.java b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/QueueObject.java
new file mode 100644
index 0000000000..fcf0464ced
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/QueueObject.java
@@ -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.
+ *
+ */
+
+package org.apache.qpid.commands.objects;
+
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+
+import org.apache.qpid.management.common.mbeans.ManagedQueue;
+
+public class QueueObject extends ObjectNames
+{
+ public QueueObject(MBeanServerConnection mbsc)
+ {
+ super(mbsc);
+ }
+
+ public void setQueryString(String object, String name, String vhost)
+ {
+ if (name != null && vhost == null)
+ querystring = "org.apache.qpid:type=VirtualHost.Queue,name=" + name + ",*";
+ else if (name != null && vhost != null)
+ querystring = "org.apache.qpid:type=VirtualHost.Queue,VirtualHost=" + vhost + ",name=" + name + ",*";
+ else if (name == null && vhost != null)
+ querystring = "org.apache.qpid:type=VirtualHost.Queue,VirtualHost=" + vhost + ",*";
+ else
+ querystring = "org.apache.qpid:type=VirtualHost.Queue,*";
+ }
+
+ public int getmessagecount(ObjectName queue)
+ {
+ Number depth = null;
+
+ try
+ {
+ depth = (Number) mbsc.getAttribute(queue, ManagedQueue.ATTR_MSG_COUNT);
+
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ if (depth != null)
+ return depth.intValue();
+ else
+ return -1;
+ }
+
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/UserManagementObject.java b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/UserManagementObject.java
new file mode 100644
index 0000000000..fd5bc0ca72
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/UserManagementObject.java
@@ -0,0 +1,38 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.commands.objects;
+
+import javax.management.MBeanServerConnection;
+
+public class UserManagementObject extends ObjectNames
+{
+ public UserManagementObject(MBeanServerConnection mbsc)
+ {
+ super(mbsc);
+ }
+
+ public void setQueryString(String object, String name, String vhost)
+ {
+ querystring = "org.apache.qpid:type=UserManagement,*";
+ }
+
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/VirtualHostObject.java b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/VirtualHostObject.java
new file mode 100644
index 0000000000..77f8b66ac0
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/commands/objects/VirtualHostObject.java
@@ -0,0 +1,47 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.commands.objects;
+
+import javax.management.MBeanServerConnection;
+
+public class VirtualHostObject extends ObjectNames
+{
+
+ public VirtualHostObject(MBeanServerConnection mbsc)
+ {
+ super(mbsc);
+ }
+
+ public void setQueryString(String object, String name, String vhost)
+ {
+ if (name != null && vhost == null)
+ querystring = "org.apache.qpid:type=VirtualHost.VirtualHostManager,name=" + name + ",*";
+ else if (name != null && vhost != null)
+ querystring = "org.apache.qpid:type=VirtualHost.VirtualHostManager,VirtualHost=" + vhost + ",name=" + name
+ + ",*";
+ else if (name == null && vhost != null)
+ querystring = "org.apache.qpid:type=VirtualHost.VirtualHostManager,VirtualHost=" + vhost + ",*";
+ else
+ querystring = "org.apache.qpid:type=VirtualHost.VirtualHostManager,*";
+
+ }
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/utils/CommandLineOption.java b/java/management/tools/qpid-cli/src/org/apache/qpid/utils/CommandLineOption.java
new file mode 100644
index 0000000000..a443d6f789
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/utils/CommandLineOption.java
@@ -0,0 +1,104 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.utils;
+
+import java.util.ArrayList;
+
+public class CommandLineOption implements CommandLineOptionConstants
+{
+ private String type;
+ private ArrayList optionValues;
+
+ public CommandLineOption(String type, String[] values)
+ {
+ setOptionType(type);
+ ArrayList arrayList = new ArrayList(values.length);
+ for (int i = 0; i < values.length; i++)
+ {
+ arrayList.add(values[i]);
+ }
+ this.optionValues = arrayList;
+ }
+
+ private void setOptionType(String type)
+ {
+ // cater for the long options first
+ if (type.startsWith("--"))
+ {
+ type = type.replaceFirst("--", "");
+ }
+ if (type.startsWith("-"))
+ {
+ type = type.replaceFirst("-", "");
+ }
+
+ // we do not change the case of the option!
+
+ this.type = type;
+ }
+
+ /**
+ * @param type
+ */
+ public CommandLineOption(String type, ArrayList values)
+ {
+ setOptionType(type);
+
+ if (null != values)
+ {
+ this.optionValues = values;
+ }
+ }
+
+ /**
+ * @return Returns the type.
+ * @see CommandLineOptionConstants
+ */
+ public String getOptionType()
+ {
+ return type;
+ }
+
+ /**
+ * @return Returns the optionValues.
+ */
+ public String getOptionValue()
+ {
+ if ((optionValues != null) && (optionValues.size() > 0))
+ {
+ return (String) optionValues.get(0);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * @return Returns the optionValues.
+ */
+ public ArrayList getOptionValues()
+ {
+ return optionValues;
+ }
+
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/utils/CommandLineOptionConstants.java b/java/management/tools/qpid-cli/src/org/apache/qpid/utils/CommandLineOptionConstants.java
new file mode 100644
index 0000000000..be82dbfcaa
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/utils/CommandLineOptionConstants.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.utils;
+
+public interface CommandLineOptionConstants
+{
+ static interface JMXCommandLineOptionConstants
+ {
+ String HOST_OPTION = "h";
+ String PORT_OPTION = "p";
+ String INTERVAL_OPTION = "i";
+ String REPORT_OPTION = "r";
+ String USER_OPTION = "u";
+ String PASSWORD_OPTION = "w";
+
+ }
+
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/utils/CommandLineOptionParser.java b/java/management/tools/qpid-cli/src/org/apache/qpid/utils/CommandLineOptionParser.java
new file mode 100644
index 0000000000..fbf87bac01
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/utils/CommandLineOptionParser.java
@@ -0,0 +1,231 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.utils;
+
+import java.util.Map;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.StringTokenizer;
+
+public class CommandLineOptionParser
+{
+ private static int STARTED = 0;
+ private static int NEW_OPTION = 1;
+ private static int SUB_PARAM_OF_OPTION = 2;
+
+ private Map commandlineoption;
+ private String commandname;
+
+ public CommandLineOptionParser(Map commandlineoptions)
+ {
+ this.commandlineoption = commandlineoptions;
+ }
+
+ public CommandLineOptionParser(String[] args)
+ {
+ /* check whether user just type the enter key */
+ this.commandlineoption = this.parse(args);
+
+ }
+
+ public CommandLineOptionParser(String[] args, String first)
+ {
+ this.commandname = first;
+ this.commandlineoption = this.parsefirst(args);
+ }
+
+ public Map parse(String[] args)
+ {
+ Map commandLineOptions = new HashMap();
+
+ if (0 == args.length)
+ {
+ return commandLineOptions;
+ }
+ else if (1 == args.length)
+ {
+ commandname = args[0];
+ return commandLineOptions;
+ }
+ /* when user is not giving the command line option with a "=" */
+ // if (!args[2].startsWith("-"))
+ // return commandLineOptions;
+ // State 0 means started
+ // State 1 means earlier one was a new -option
+ // State 2 means earlier one was a sub param of a -option
+ int state = STARTED;
+ ArrayList optionBundle = null;
+ String optionType = null;
+ CommandLineOption commandLineOption;
+ String newcommand = "";
+ String[] newargs;
+ int j;
+ if (args[1].compareTo("list") == 0 || args[1].compareTo("info") == 0 || args[1].compareTo("delete") == 0
+ || args[1].compareTo("move") == 0 || args[1].compareTo("view") == 0
+ || args[1].compareTo("viewcontent") == 0)
+ {
+ String object = args[0];
+ for (j = 0; j < (args.length - 1); j++)
+ {
+ newcommand = newcommand + args[j + 1] + " ";
+ }
+ newcommand = newcommand + "-o " + object;
+ newargs = newcommand.split(" ");
+ args = newargs;
+ }
+ else if (!args[1].startsWith("-")) // if user give command like list
+ // queue or something without minus
+ // argument
+ return commandLineOptions; // for the second wordxi
+
+ commandname = args[0];
+ for (int i = 0; i < args.length; i++)
+ {
+ if (args[i].startsWith("-"))
+ {
+ if (STARTED == state)
+ {
+ // fresh one
+ state = NEW_OPTION;
+ optionType = args[i];
+ }
+ else if (SUB_PARAM_OF_OPTION == state || NEW_OPTION == state)
+ {
+ // new one but old one should be saved
+ commandLineOption = new CommandLineOption(optionType, optionBundle);
+ commandLineOptions.put(commandLineOption.getOptionType(), commandLineOption);
+ state = NEW_OPTION;
+ optionType = args[i];
+ optionBundle = null;
+
+ }
+ }
+ else
+ {
+ if (NEW_OPTION == state)
+ {
+ optionBundle = new ArrayList();
+ optionBundle.add(args[i]);
+ state = SUB_PARAM_OF_OPTION;
+
+ }
+ else if (SUB_PARAM_OF_OPTION == state)
+ {
+ optionBundle.add(args[i]);
+ }
+
+ }
+ }
+ commandLineOption = new CommandLineOption(optionType, optionBundle);
+ commandLineOptions.put(commandLineOption.getOptionType(), commandLineOption);
+ return commandLineOptions;
+
+ }
+
+ public Map parsefirst(String[] args)
+ {
+ Map commandLineOptions = new HashMap();
+ if (0 == args.length)
+ {
+ return commandLineOptions;
+ }
+ else if (1 == args.length)
+ {
+ return commandLineOptions;
+ }
+ /* when user is not giving the command line option with a "=" */
+ // if (!args[2].startsWith("-"))
+ // return commandLineOptions;
+ // State 0 means started
+ // State 1 means earlier one was a new -option
+ // State 2 means earlier one was a sub param of a -option
+ int state = STARTED;
+ ArrayList optionBundle = null;
+ String optionType = null;
+ CommandLineOption commandLineOption;
+ String newcommand = "";
+ String[] newargs;
+ int j;
+
+ for (int i = 0; i < args.length; i++)
+ {
+ if (args[i].startsWith("-"))
+ {
+ if (STARTED == state)
+ {
+ // fresh one
+ state = NEW_OPTION;
+ optionType = args[i];
+ }
+ else if (SUB_PARAM_OF_OPTION == state || NEW_OPTION == state)
+ {
+ // new one but old one should be saved
+ commandLineOption = new CommandLineOption(optionType, optionBundle);
+ commandLineOptions.put(commandLineOption.getOptionType(), commandLineOption);
+ state = NEW_OPTION;
+ optionType = args[i];
+ optionBundle = null;
+
+ }
+ }
+ else
+ {
+ if (NEW_OPTION == state)
+ {
+ optionBundle = new ArrayList();
+ optionBundle.add(args[i]);
+ state = SUB_PARAM_OF_OPTION;
+
+ }
+ else if (SUB_PARAM_OF_OPTION == state)
+ {
+ optionBundle.add(args[i]);
+ }
+
+ }
+ }
+ commandLineOption = new CommandLineOption(optionType, optionBundle);
+ commandLineOptions.put(commandLineOption.getOptionType(), commandLineOption);
+ return commandLineOptions;
+
+ }
+
+ public Map getAlloptions()
+ {
+ return this.commandlineoption;
+ }
+
+ public String getcommandname()
+ {
+ return this.commandname;
+ }
+
+ private static String removeSpaces(String s)
+ {
+ StringTokenizer st = new StringTokenizer(s, " ", false);
+ String t = "";
+ while (st.hasMoreElements())
+ t += st.nextElement();
+ return t;
+ }
+
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/utils/JMXConfigProperty.java b/java/management/tools/qpid-cli/src/org/apache/qpid/utils/JMXConfigProperty.java
new file mode 100644
index 0000000000..55240054a9
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/utils/JMXConfigProperty.java
@@ -0,0 +1,29 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.utils;
+
+public class JMXConfigProperty
+{
+
+ private static final String DEFAULT_HOST_NAME = "localhost";
+ private static final String DEFAULT_PORT = "8999";
+ private static final String DEFAULT_INTERVAL = "4000";
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/utils/JMXConfiguration.java b/java/management/tools/qpid-cli/src/org/apache/qpid/utils/JMXConfiguration.java
new file mode 100644
index 0000000000..76aab11e25
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/utils/JMXConfiguration.java
@@ -0,0 +1,182 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.utils;
+
+import java.util.Map;
+
+public class JMXConfiguration
+{
+ private String hostname = "localhost";
+ private String port = "8999";
+ private String interval = "40000";
+ private String outputpath = ".";
+ private String report_file = "report.output";
+ private boolean isreport_mode = false;
+ private String username = null;
+ private String password = null;
+
+ public JMXConfiguration(Map map)
+ {
+ if (checkoptionsetting(CommandLineOptionConstants.JMXCommandLineOptionConstants.HOST_OPTION, map))
+ {
+ this.hostname = optionchecker(CommandLineOptionConstants.JMXCommandLineOptionConstants.HOST_OPTION, map);
+ }
+ if (checkoptionsetting(CommandLineOptionConstants.JMXCommandLineOptionConstants.PORT_OPTION, map))
+ {
+ this.port = optionchecker(CommandLineOptionConstants.JMXCommandLineOptionConstants.PORT_OPTION, map);
+ }
+ if (checkoptionsetting(CommandLineOptionConstants.JMXCommandLineOptionConstants.REPORT_OPTION, map))
+ {
+
+ this.report_file = optionchecker(CommandLineOptionConstants.JMXCommandLineOptionConstants.REPORT_OPTION,
+ map);
+ }
+ if (checkoptionsetting(CommandLineOptionConstants.JMXCommandLineOptionConstants.USER_OPTION, map))
+ {
+
+ this.setUsername(optionchecker(CommandLineOptionConstants.JMXCommandLineOptionConstants.USER_OPTION, map));
+ }
+
+ if (checkoptionsetting(CommandLineOptionConstants.JMXCommandLineOptionConstants.PASSWORD_OPTION, map))
+ {
+ this.setPassword(optionchecker(CommandLineOptionConstants.JMXCommandLineOptionConstants.PASSWORD_OPTION,
+ map));
+ }
+
+ }
+
+ public void sethostname(String hostname)
+ {
+ this.hostname = hostname;
+ }
+
+ public void setport(String port)
+ {
+ this.port = port;
+ }
+
+ public void setinterval(String interval)
+ {
+ this.interval = interval;
+ }
+
+ public void setoutputpath(String output)
+ {
+ this.outputpath = output;
+ }
+
+ public String gethostname()
+ {
+ return this.hostname;
+ }
+
+ public String getport()
+ {
+ return this.port;
+ }
+
+ public String getinterval()
+ {
+ return this.interval;
+ }
+
+ public String getoutputpath()
+ {
+ return this.outputpath;
+ }
+
+ public CommandLineOption loadoption(String option, Map options)
+ {
+ CommandLineOption op = null;
+ if (option != null)
+ {
+ op = (CommandLineOption) options.get(option);
+
+ }
+ return op;
+
+ }
+
+ public void setreportfile(String reportfile)
+ {
+ this.report_file = reportfile;
+ this.isreport_mode = true;
+
+ }
+
+ public boolean isreportmode()
+ {
+ return this.isreport_mode;
+ }
+
+ public String getreportfile()
+ {
+ return this.report_file;
+ }
+
+ public String optionchecker(String option_letter, Map map)
+ {
+
+ if (map == null)
+ return null;
+ CommandLineOption option = (CommandLineOption) map.get(option_letter);
+ if (option == null)
+ return null;
+ String value = option.getOptionValue();
+ return value;
+ }
+
+ public boolean checkoptionsetting(String option_letter, Map map)
+ {
+ if (map == null)
+ return false;
+ CommandLineOption option = (CommandLineOption) map.get(option_letter);
+ if (option == null)
+ return false;
+ String value = option.getOptionType();
+
+ if (value != null)
+ return true;
+ else
+ return false;
+ }
+
+ public void setUsername(String username)
+ {
+ this.username = username;
+ }
+
+ public String getUsername()
+ {
+ return username;
+ }
+
+ public void setPassword(String password)
+ {
+ this.password = password;
+ }
+
+ public String getPassword()
+ {
+ return password;
+ }
+
+}
diff --git a/java/management/tools/qpid-cli/src/org/apache/qpid/utils/JMXinfo.java b/java/management/tools/qpid-cli/src/org/apache/qpid/utils/JMXinfo.java
new file mode 100644
index 0000000000..09de4a248f
--- /dev/null
+++ b/java/management/tools/qpid-cli/src/org/apache/qpid/utils/JMXinfo.java
@@ -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 org.apache.qpid.utils;
+
+import javax.management.remote.JMXConnector;
+import javax.management.MBeanServerConnection;
+
+public class JMXinfo
+{
+ private JMXConnector jmxconnector;
+ private CommandLineOptionParser input;
+ private MBeanServerConnection mbserverconnector;
+
+ public JMXinfo(JMXConnector jmxc, CommandLineOptionParser input, MBeanServerConnection mbsc)
+ {
+ this.jmxconnector = jmxc;
+ this.input = input;
+ this.mbserverconnector = mbsc;
+ }
+
+ public JMXConnector getjmxconnectot()
+ {
+ return jmxconnector;
+ }
+
+ public CommandLineOptionParser getCommandLineOptionParser()
+ {
+ return input;
+ }
+
+ public MBeanServerConnection getmbserverconnector()
+ {
+ return mbserverconnector;
+ }
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/AllTest.java b/java/management/tools/qpid-cli/test/org/apache/qpid/AllTest.java
new file mode 100644
index 0000000000..d9758245cd
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/AllTest.java
@@ -0,0 +1,41 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.apache.qpid.commands.*;
+import org.apache.qpid.commands.objects.*;
+import org.apache.qpid.utils.TestCommandLineOption;
+import org.apache.qpid.utils.TestCommandLineOptionParser;
+import org.apache.qpid.utils.TestJMXConfiguration;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses( { TestCommand.class, TestCommandExecutionEngine.class, TestCommandLineOption.class,
+ TestCommandLineOptionParser.class, TestConnector.class, TestJMXConfiguration.class, TestAllObject.class,
+ TestConnectionObject.class, TestExchangeObject.class, TestQueueObject.class, TestVirtualHostObject.class,
+ TestUserManagementObject.class, TestCommanddelete.class, TestCommandlist.class, TestCommandinfo.class,
+ TestCommandmove.class, TestCommandview.class, TestCommandviewcontent.class, TestCommandLineInterpreter.class
+
+})
+public class AllTest
+{
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/ConnectionConstants.java b/java/management/tools/qpid-cli/test/org/apache/qpid/ConnectionConstants.java
new file mode 100644
index 0000000000..90163460ce
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/ConnectionConstants.java
@@ -0,0 +1,30 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid;
+
+public interface ConnectionConstants
+{
+ String BROKER_HOSTNAME = "localhost";
+ String BROKER_PORT = "8999";
+ String USERNAME = "guest";
+ String PASSWORD = "guest";
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/TestCommandExecutionEngine.java b/java/management/tools/qpid-cli/test/org/apache/qpid/TestCommandExecutionEngine.java
new file mode 100644
index 0000000000..6889e8faad
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/TestCommandExecutionEngine.java
@@ -0,0 +1,73 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid;
+
+import java.io.IOException;
+
+import org.apache.qpid.utils.CommandLineOptionParser;
+import org.apache.qpid.utils.JMXinfo;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestCommandExecutionEngine
+{
+ String line;
+ String[] command;
+ CommandLineOptionParser commandlineoptionparser;
+ JMXinfo info;
+ CommandExecutionEngine engine;
+ Connector connector;
+
+ @Before
+ public void setup() throws Exception
+ {
+
+ connector = ConnectorFactory.getConnector(ConnectionConstants.BROKER_HOSTNAME, ConnectionConstants.BROKER_PORT,
+ ConnectionConstants.USERNAME, ConnectionConstants.PASSWORD);
+
+ }
+
+ @Test
+ public void TestCommandSelector() throws Exception
+ {
+ line = "list -o queue";
+ command = line.split(" ");
+ commandlineoptionparser = new CommandLineOptionParser(command);
+ info = new JMXinfo(connector.getConnector(), commandlineoptionparser, connector.getMBeanServerConnection());
+ engine = new CommandExecutionEngine(info);
+ Assert.assertEquals(engine.CommandSelector(), true);
+ }
+
+ @After
+ public void cleanup()
+ {
+ try
+ {
+ connector.getConnector().close();
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/TestCommandLineInterpreter.java b/java/management/tools/qpid-cli/test/org/apache/qpid/TestCommandLineInterpreter.java
new file mode 100644
index 0000000000..07344598bf
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/TestCommandLineInterpreter.java
@@ -0,0 +1,80 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid;
+
+import javax.management.MBeanServerConnection;
+import javax.management.remote.JMXConnector;
+
+import org.apache.qpid.utils.CommandLineOptionParser;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestCommandLineInterpreter
+{
+
+ // CommandLineInterpreter test = new CommandLineInterpreter();
+ /*
+ * In this class there are only methodes which are displaying data on
+ * console so no test can be written
+ */
+ String command = "-h " + ConnectionConstants.BROKER_HOSTNAME + " -p " + ConnectionConstants.BROKER_PORT
+ + " info -o queue -n ping -v test";
+ Connector conn = null;
+ JMXConnector jmxc = null;
+ MBeanServerConnection mbsc = null;
+ CommandLineOptionParser parser = null;
+
+ String[] args = null;
+
+ @Before
+ public void startup() throws Exception
+ {
+ args = command.split(" ");
+ // System.out.println(args[0]);
+ conn = ConnectorFactory.getConnector(ConnectionConstants.BROKER_HOSTNAME, ConnectionConstants.BROKER_PORT,
+ ConnectionConstants.USERNAME, ConnectionConstants.PASSWORD);
+ jmxc = conn.getConnector();
+ mbsc = conn.getMBeanServerConnection();
+ parser = new CommandLineOptionParser(args, args[0]);
+
+ }
+
+ @Test
+ public void TestSetQueryString() throws Exception
+ {
+ CommandLineInterpreter.oneshotmode(args, parser, jmxc, mbsc);
+ Assert.assertEquals(args[0], "info");
+ Assert.assertEquals(args[1], "-o");
+ Assert.assertEquals(args[2], "queue");
+ Assert.assertEquals(args[3], "-n");
+ Assert.assertEquals(args[4], "ping");
+ Assert.assertEquals(args[5], "-v");
+ Assert.assertEquals(args[6], "test");
+ }
+
+ @After
+ public void cleanup()
+ {
+
+ }
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/TestConnector.java b/java/management/tools/qpid-cli/test/org/apache/qpid/TestConnector.java
new file mode 100644
index 0000000000..ea450b5caa
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/TestConnector.java
@@ -0,0 +1,79 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid;
+
+import java.io.IOException;
+
+import javax.management.MBeanServerConnection;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXServiceURL;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestConnector
+{
+ Connector test;
+ JMXServiceURL svc_url;
+ JMXConnector connector;
+ MBeanServerConnection mbsc;
+
+ @Before
+ public void setup() throws Exception
+ {
+ test = ConnectorFactory.getConnector(ConnectionConstants.BROKER_HOSTNAME, ConnectionConstants.BROKER_PORT,
+ ConnectionConstants.USERNAME, ConnectionConstants.PASSWORD);
+ String url = "service:jmx:rmi:///jndi/rmi://localhost:8999/jmxrmi";
+
+ }
+
+ @Test
+ public void testGetConnector()
+ {
+ Assert.assertEquals(test.getConnector(), test.getConnector());
+ }
+
+ @Test
+ public void testGetMBeanServerConnection()
+ {
+ Assert.assertEquals(test.getMBeanServerConnection(), test.getMBeanServerConnection());
+ }
+
+ @After
+ public void cleanup()
+ {
+ try
+ {
+
+ test.getConnector().close();
+ test = null;
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace(); // To change body of catch statement use File |
+ // Settings | File Templates.
+ }
+ test = null;
+ }
+
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/TestReportGenerator.java b/java/management/tools/qpid-cli/test/org/apache/qpid/TestReportGenerator.java
new file mode 100644
index 0000000000..c14f4bb1bb
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/TestReportGenerator.java
@@ -0,0 +1,26 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid;
+
+public class TestReportGenerator
+{
+
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommand.java b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommand.java
new file mode 100644
index 0000000000..085d7220e9
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommand.java
@@ -0,0 +1,79 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.commands;
+
+import javax.management.MBeanServerConnection;
+
+import org.apache.qpid.Command;
+import org.apache.qpid.ConnectionConstants;
+import org.apache.qpid.Connector;
+import org.apache.qpid.ConnectorFactory;
+import org.apache.qpid.utils.CommandLineOptionParser;
+import org.apache.qpid.utils.JMXinfo;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestCommand
+{
+ String command = "list -o queue";
+ String[] list;
+ Connector test;
+ MBeanServerConnection mbsc;
+ JMXinfo info;
+ CommandLineOptionParser parser;
+ Command cmd;
+
+ @Before
+ public void setup() throws Exception
+ {
+ list = command.split(" ");
+ parser = new CommandLineOptionParser(list);
+ test = ConnectorFactory.getConnector(ConnectionConstants.BROKER_HOSTNAME, ConnectionConstants.BROKER_PORT,
+ ConnectionConstants.USERNAME, ConnectionConstants.PASSWORD);
+ info = new JMXinfo(test.getConnector(), parser, test.getMBeanServerConnection());
+ cmd = new Commandinfo(info);
+
+ }
+
+ @Test
+ public void TestOptionChecker()
+ {
+ Assert.assertEquals(cmd.optionchecker("o"), "queue");
+ }
+
+ @Test
+ public void TestCheckOptionSetting()
+ {
+ Assert.assertEquals(cmd.checkoptionsetting("o"), true);
+ Assert.assertEquals(cmd.checkoptionsetting("p"), false);
+ }
+
+ @After
+ public void cleanup()
+ {
+ parser = null;
+ test = null;
+ info = null;
+ cmd = null;
+ }
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommanddelete.java b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommanddelete.java
new file mode 100644
index 0000000000..60249c6940
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommanddelete.java
@@ -0,0 +1,79 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.commands;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.Before;
+import org.junit.Assert;
+import org.apache.qpid.ConnectorFactory;
+import org.apache.qpid.Connector;
+import org.apache.qpid.ConnectionConstants;
+import org.apache.qpid.utils.JMXinfo;
+import org.apache.qpid.utils.CommandLineOptionParser;
+
+import javax.management.remote.JMXConnector;
+import javax.management.MBeanServerConnection;
+
+public class TestCommanddelete
+{
+ JMXinfo info = null;
+ String command = "delete -o queue -n ping -v test -t 1";
+ Commanddelete delete = null;
+ Connector conn;
+
+ @Before
+ public void startup() throws Exception
+ {
+ conn = ConnectorFactory.getConnector(ConnectionConstants.BROKER_HOSTNAME, ConnectionConstants.BROKER_PORT,
+ ConnectionConstants.USERNAME, ConnectionConstants.PASSWORD);
+ JMXConnector jmxc = conn.getConnector();
+ MBeanServerConnection mbsc = conn.getMBeanServerConnection();
+ CommandLineOptionParser parser = new CommandLineOptionParser(command.split(" "));
+ info = new JMXinfo(jmxc, parser, mbsc);
+ delete = new Commanddelete(info);
+
+ }
+
+ @Test
+ public void TestSetQueryString()
+ {
+ delete.execute();
+ Assert.assertEquals(delete.getObject(), "queue");
+ Assert.assertEquals(delete.getVirtualhost(), "test");
+ Assert.assertEquals(delete.getName(), "ping");
+ Assert.assertEquals(delete.getnumber(), 1);
+
+ }
+
+ @After
+ public void cleanup()
+ {
+ try
+ {
+ conn.getConnector().close();
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommandinfo.java b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommandinfo.java
new file mode 100644
index 0000000000..24263eea73
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommandinfo.java
@@ -0,0 +1,77 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.commands;
+
+import org.apache.qpid.utils.JMXinfo;
+import org.apache.qpid.utils.CommandLineOptionParser;
+import org.apache.qpid.Connector;
+import org.apache.qpid.ConnectorFactory;
+import org.apache.qpid.ConnectionConstants;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.Assert;
+import org.junit.After;
+
+import javax.management.remote.JMXConnector;
+import javax.management.MBeanServerConnection;
+
+public class TestCommandinfo
+{
+ JMXinfo info = null;
+ String command = "info -o queue -n ping -v test";
+ CommandImpl infocommand = null;
+ Connector conn = null;
+
+ @Before
+ public void startup() throws Exception
+ {
+ conn = ConnectorFactory.getConnector(ConnectionConstants.BROKER_HOSTNAME, ConnectionConstants.BROKER_PORT,
+ ConnectionConstants.USERNAME, ConnectionConstants.PASSWORD);
+ JMXConnector jmxc = conn.getConnector();
+ MBeanServerConnection mbsc = conn.getMBeanServerConnection();
+ CommandLineOptionParser parser = new CommandLineOptionParser(command.split(" "));
+ info = new JMXinfo(jmxc, parser, mbsc);
+ infocommand = new Commandinfo(info);
+
+ }
+
+ @Test
+ public void TestSetQueryString()
+ {
+ infocommand.execute();
+ Assert.assertEquals(infocommand.getObject(), "queue");
+ Assert.assertEquals(infocommand.getVirtualhost(), "test");
+ Assert.assertEquals(infocommand.getName(), "ping");
+ }
+
+ @After
+ public void cleanup()
+ {
+ try
+ {
+ conn.getConnector().close();
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommandlist.java b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommandlist.java
new file mode 100644
index 0000000000..ac759889fd
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommandlist.java
@@ -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.
+ *
+ */
+package org.apache.qpid.commands;
+
+import javax.management.MBeanServerConnection;
+import javax.management.remote.JMXConnector;
+
+import org.apache.qpid.ConnectionConstants;
+import org.apache.qpid.Connector;
+import org.apache.qpid.ConnectorFactory;
+import org.apache.qpid.utils.CommandLineOptionParser;
+import org.apache.qpid.utils.JMXinfo;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestCommandlist
+{
+ /*
+ * All the methods in Commandlist doesn't have any arguments and no return
+ * type.
+ */
+ JMXinfo info = null;
+ String command = "list -o queue -n ping -v test";
+ Commandlist list = null;
+ Connector conn = null;
+
+ @Before
+ public void startup() throws Exception
+ {
+ conn = ConnectorFactory.getConnector(ConnectionConstants.BROKER_HOSTNAME, ConnectionConstants.BROKER_PORT,
+ ConnectionConstants.USERNAME, ConnectionConstants.PASSWORD);
+ JMXConnector jmxc = conn.getConnector();
+ MBeanServerConnection mbsc = conn.getMBeanServerConnection();
+ CommandLineOptionParser parser = new CommandLineOptionParser(command.split(" "));
+ info = new JMXinfo(jmxc, parser, mbsc);
+ list = new Commandlist(info);
+
+ }
+
+ @Test
+ public void TestSetQueryString()
+ {
+ list.execute();
+ Assert.assertEquals(list.getObject(), "queue");
+ Assert.assertEquals(list.getVirtualhost(), "test");
+ Assert.assertEquals(list.getName(), "ping");
+ }
+
+ @After
+ public void cleanup()
+ {
+ try
+ {
+ conn.getConnector().close();
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommandmove.java b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommandmove.java
new file mode 100644
index 0000000000..3ff7890662
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommandmove.java
@@ -0,0 +1,80 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.commands;
+
+import org.apache.qpid.ConnectionConstants;
+import org.apache.qpid.Connector;
+import org.apache.qpid.ConnectorFactory;
+import org.apache.qpid.utils.CommandLineOptionParser;
+import org.apache.qpid.utils.JMXinfo;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.After;
+import org.junit.Assert;
+
+import javax.management.remote.JMXConnector;
+import javax.management.MBeanServerConnection;
+
+public class TestCommandmove
+{
+ JMXinfo info = null;
+ String command = "move -o queue -n1 ping -v1 test -n2 message_queue -fmid 10 -tmid 12";
+ Commandmove move = null;
+ Connector conn = null;
+
+ @Before
+ public void startup() throws Exception
+ {
+ conn = ConnectorFactory.getConnector(ConnectionConstants.BROKER_HOSTNAME, ConnectionConstants.BROKER_PORT,
+ ConnectionConstants.USERNAME, ConnectionConstants.PASSWORD);
+ JMXConnector jmxc = conn.getConnector();
+ MBeanServerConnection mbsc = conn.getMBeanServerConnection();
+ CommandLineOptionParser parser = new CommandLineOptionParser(command.split(" "));
+ info = new JMXinfo(jmxc, parser, mbsc);
+ move = new Commandmove(info);
+
+ }
+
+ @Test
+ public void TestSetQueryString()
+ {
+ move.execute();
+ Assert.assertEquals(move.getObject(), "queue");
+ Assert.assertEquals(move.getVirtualhost(), "test");
+ Assert.assertEquals(move.getname1(), "ping");
+ Assert.assertEquals(move.getname2(), "message_queue");
+ Assert.assertEquals(move.getfmid(), 10);
+ Assert.assertEquals(move.gettmid(), 12);
+ }
+
+ @After
+ public void cleanup()
+ {
+ try
+ {
+ conn.getConnector().close();
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommandview.java b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommandview.java
new file mode 100644
index 0000000000..f46b8626b8
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommandview.java
@@ -0,0 +1,78 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.commands;
+
+import org.apache.qpid.ConnectionConstants;
+import org.apache.qpid.ConnectorFactory;
+import org.apache.qpid.Connector;
+import org.apache.qpid.utils.CommandLineOptionParser;
+import org.apache.qpid.utils.JMXinfo;
+import org.junit.Test;
+import org.junit.Before;
+import org.junit.After;
+import org.junit.Assert;
+
+import javax.management.MBeanServerConnection;
+import javax.management.remote.JMXConnector;
+
+public class TestCommandview
+{
+ JMXinfo info = null;
+ String command = "view -o queue -n ping -v test -t 10";
+ Commandview view = null;
+ Connector conn = null;
+
+ @Before
+ public void startup() throws Exception
+ {
+ conn = ConnectorFactory.getConnector(ConnectionConstants.BROKER_HOSTNAME, ConnectionConstants.BROKER_PORT,
+ ConnectionConstants.USERNAME, ConnectionConstants.PASSWORD);
+ JMXConnector jmxc = conn.getConnector();
+ MBeanServerConnection mbsc = conn.getMBeanServerConnection();
+ CommandLineOptionParser parser = new CommandLineOptionParser(command.split(" "));
+ info = new JMXinfo(jmxc, parser, mbsc);
+ view = new Commandview(info);
+ }
+
+ @Test
+ public void TestSetQueryString()
+ {
+ view.execute();
+ Assert.assertEquals(view.getObject(), "queue");
+ Assert.assertEquals(view.getVirtualhost(), "test");
+ Assert.assertEquals(view.getName(), "ping");
+ Assert.assertEquals(view.getnumber(), 10);
+
+ }
+
+ @After
+ public void cleanup()
+ {
+ try
+ {
+ conn.getConnector().close();
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommandviewcontent.java b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommandviewcontent.java
new file mode 100644
index 0000000000..f4a8f22aff
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/TestCommandviewcontent.java
@@ -0,0 +1,78 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.commands;
+
+import org.apache.qpid.utils.JMXinfo;
+import org.apache.qpid.utils.CommandLineOptionParser;
+import org.apache.qpid.Connector;
+import org.apache.qpid.ConnectorFactory;
+import org.apache.qpid.ConnectionConstants;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.After;
+import org.junit.Assert;
+
+import javax.management.remote.JMXConnector;
+import javax.management.MBeanServerConnection;
+
+public class TestCommandviewcontent
+{
+ JMXinfo info = null;
+ String command = "viewcontent -o queue -n ping -v test -id 10";
+ Commandviewcontent viewcontent = null;
+ Connector conn = null;
+
+ @Before
+ public void startup() throws Exception
+ {
+ conn = ConnectorFactory.getConnector(ConnectionConstants.BROKER_HOSTNAME, ConnectionConstants.BROKER_PORT,
+ ConnectionConstants.USERNAME, ConnectionConstants.PASSWORD);
+ JMXConnector jmxc = conn.getConnector();
+ MBeanServerConnection mbsc = conn.getMBeanServerConnection();
+ CommandLineOptionParser parser = new CommandLineOptionParser(command.split(" "));
+ info = new JMXinfo(jmxc, parser, mbsc);
+ viewcontent = new Commandviewcontent(info);
+
+ }
+
+ @Test
+ public void TestSetQueryString()
+ {
+ viewcontent.execute();
+ Assert.assertEquals(viewcontent.getObject(), "queue");
+ Assert.assertEquals(viewcontent.getnumber(), 10);
+ Assert.assertEquals(viewcontent.getName(), "ping");
+ Assert.assertEquals(viewcontent.getVirtualhost(), "test");
+ }
+
+ @After
+ public void cleanup()
+ {
+ try
+ {
+ conn.getConnector().close();
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestAllObject.java b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestAllObject.java
new file mode 100644
index 0000000000..af993e9205
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestAllObject.java
@@ -0,0 +1,69 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.commands.objects;
+
+import javax.management.MBeanServerConnection;
+
+import org.apache.qpid.ConnectionConstants;
+import org.apache.qpid.Connector;
+import org.apache.qpid.ConnectorFactory;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestAllObject {
+ Connector conn;
+ MBeanServerConnection mbsc;
+ AllObjects test;
+ String test1,test2;
+
+ @Before
+ public void startup() throws Exception
+ {
+ conn = ConnectorFactory.getConnector(ConnectionConstants.BROKER_HOSTNAME,ConnectionConstants.BROKER_PORT, ConnectionConstants.USERNAME, ConnectionConstants.PASSWORD);
+ mbsc = conn.getMBeanServerConnection();
+ test = new AllObjects(mbsc);
+ test1 = "empty input1";
+ test2 = "empty input2";
+
+
+ }
+ @Test
+ public void TestSetQueryString()
+ {
+ test.setQueryString(test1,test2);
+ Assert.assertEquals(test.querystring,"org.apache.qpid:*");
+
+ }
+
+ @After
+ public void cleanup()
+ {
+ try{
+ conn.getConnector().close();
+ }catch(Exception ex)
+ {
+ ex.printStackTrace();
+ }
+
+ }
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestConnectionObject.java b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestConnectionObject.java
new file mode 100644
index 0000000000..f91a519108
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestConnectionObject.java
@@ -0,0 +1,83 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.commands.objects;
+
+import javax.management.MBeanServerConnection;
+
+import org.apache.qpid.ConnectionConstants;
+import org.apache.qpid.Connector;
+import org.apache.qpid.ConnectorFactory;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestConnectionObject
+{
+ Connector conn;
+ MBeanServerConnection mbsc;
+ ConnectionObject test;
+ String test1, test2, test3;
+
+ @Before
+ public void startup() throws Exception
+ {
+ conn = ConnectorFactory.getConnector(ConnectionConstants.BROKER_HOSTNAME, ConnectionConstants.BROKER_PORT,
+ ConnectionConstants.USERNAME, ConnectionConstants.PASSWORD);
+ mbsc = conn.getMBeanServerConnection();
+ test = new ConnectionObject(mbsc);
+ test1 = "ping";
+ test2 = "test";
+ test3 = "object";
+
+ }
+
+ @Test
+ public void TestSetQueryString()
+ {
+ test.setQueryString(test3, test1, null);
+ Assert.assertEquals(test.querystring, "org.apache.qpid:type=Connection,name=ping,*");
+ test.querystring = null;
+ test.setQueryString(test3, null, test2);
+ Assert.assertEquals(test.querystring, "org.apache.qpid:type=Connection,VirtualHost=test,*");
+ test.querystring = null;
+ test.setQueryString(test3, test1, test2);
+ Assert.assertEquals(test.querystring, "org.apache.qpid:type=Connection,VirtualHost=test,name=ping,*");
+ test.querystring = null;
+ test.setQueryString(test3, null, null);
+ Assert.assertEquals(test.querystring, "org.apache.qpid:type=Connection,*");
+
+ }
+
+ @After
+ public void cleanup()
+ {
+ try
+ {
+ conn.getConnector().close();
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+
+ }
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestExchangeObject.java b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestExchangeObject.java
new file mode 100644
index 0000000000..5ffbe9854f
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestExchangeObject.java
@@ -0,0 +1,83 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.commands.objects;
+
+import javax.management.MBeanServerConnection;
+
+import org.apache.qpid.ConnectionConstants;
+import org.apache.qpid.Connector;
+import org.apache.qpid.ConnectorFactory;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestExchangeObject
+{
+ Connector conn;
+ MBeanServerConnection mbsc;
+ ExchangeObject test;
+ String test1, test2, test3;
+
+ @Before
+ public void startup() throws Exception
+ {
+ conn = ConnectorFactory.getConnector(ConnectionConstants.BROKER_HOSTNAME, ConnectionConstants.BROKER_PORT,
+ ConnectionConstants.USERNAME, ConnectionConstants.PASSWORD);
+ mbsc = conn.getMBeanServerConnection();
+ test = new ExchangeObject(mbsc);
+ test1 = "ping";
+ test2 = "test";
+ test3 = "object";
+
+ }
+
+ @Test
+ public void TestSetQueryString()
+ {
+ test.setQueryString(test3, test1, null);
+ // System.out.println(test.querystring);
+ // System.out.println("org.apache.qpid:type=VitualHost.Exchange,name=ping,*");
+ Assert.assertEquals(test.querystring, "org.apache.qpid:type=VirtualHost.Exchange,name=ping,*");
+ test.querystring = null;
+ test.setQueryString(test3, null, test2);
+ Assert.assertEquals(test.querystring, "org.apache.qpid:type=VirtualHost.Exchange,VirtualHost=test,*");
+ test.querystring = null;
+ test.setQueryString(test3, test1, test2);
+ Assert.assertEquals(test.querystring, "org.apache.qpid:type=VirtualHost.Exchange,VirtualHost=test,name=ping,*");
+ test.querystring = null;
+ test.setQueryString(test3, null, null);
+ }
+
+ @After
+ public void cleanup()
+ {
+ try
+ {
+ conn.getConnector().close();
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+
+ }
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestObjectNames.java b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestObjectNames.java
new file mode 100644
index 0000000000..600c567368
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestObjectNames.java
@@ -0,0 +1,26 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.commands.objects;
+
+public class TestObjectNames
+{
+
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestQueueObject.java b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestQueueObject.java
new file mode 100644
index 0000000000..fb7f42e1ae
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestQueueObject.java
@@ -0,0 +1,83 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.commands.objects;
+
+import javax.management.MBeanServerConnection;
+
+import org.apache.qpid.ConnectionConstants;
+import org.apache.qpid.Connector;
+import org.apache.qpid.ConnectorFactory;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestQueueObject
+{
+ Connector conn;
+ MBeanServerConnection mbsc;
+ QueueObject test;
+ String test1, test2, test3;
+
+ @Before
+ public void startup() throws Exception
+ {
+ conn = ConnectorFactory.getConnector(ConnectionConstants.BROKER_HOSTNAME, ConnectionConstants.BROKER_PORT,
+ ConnectionConstants.USERNAME, ConnectionConstants.PASSWORD);
+ mbsc = conn.getMBeanServerConnection();
+ test = new QueueObject(mbsc);
+ test1 = "ping";
+ test2 = "test";
+ test3 = "object";
+
+ }
+
+ @Test
+ public void TestSetQueryString()
+ {
+ test.setQueryString(test3, test1, null);
+ Assert.assertEquals(test.querystring, "org.apache.qpid:type=VirtualHost.Queue,name=ping,*");
+ test.querystring = null;
+ test.setQueryString(test3, null, test2);
+ Assert.assertEquals(test.querystring, "org.apache.qpid:type=VirtualHost.Queue,VirtualHost=test,*");
+ test.querystring = null;
+ test.setQueryString(test3, test1, test2);
+ Assert.assertEquals(test.querystring, "org.apache.qpid:type=VirtualHost.Queue,VirtualHost=test,name=ping,*");
+ test.querystring = null;
+ test.setQueryString(test3, null, null);
+ Assert.assertEquals(test.querystring, "org.apache.qpid:type=VirtualHost.Queue,*");
+
+ }
+
+ @After
+ public void cleanup()
+ {
+ try
+ {
+ conn.getConnector().close();
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+
+ }
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestUserManagementObject.java b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestUserManagementObject.java
new file mode 100644
index 0000000000..863bf62311
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestUserManagementObject.java
@@ -0,0 +1,74 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.commands.objects;
+
+import javax.management.MBeanServerConnection;
+
+import org.apache.qpid.ConnectionConstants;
+import org.apache.qpid.Connector;
+import org.apache.qpid.ConnectorFactory;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestUserManagementObject
+{
+ Connector conn;
+ MBeanServerConnection mbsc;
+ UserManagementObject test;
+ String test1, test2, test3;
+
+ @Before
+ public void startup() throws Exception
+ {
+ conn = ConnectorFactory.getConnector(ConnectionConstants.BROKER_HOSTNAME, ConnectionConstants.BROKER_PORT,
+ ConnectionConstants.USERNAME, ConnectionConstants.PASSWORD);
+ mbsc = conn.getMBeanServerConnection();
+ test = new UserManagementObject(mbsc);
+ test1 = "ping";
+ test2 = "test";
+ test3 = "object";
+
+ }
+
+ @Test
+ public void TestSetQueryString()
+ {
+ test.setQueryString(test3, test1, test2);
+ Assert.assertEquals(test.querystring, "org.apache.qpid:type=UserManagement,*");
+
+ }
+
+ @After
+ public void cleanup()
+ {
+ try
+ {
+ conn.getConnector().close();
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+
+ }
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestVirtualHostObject.java b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestVirtualHostObject.java
new file mode 100644
index 0000000000..29c4db30a5
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/commands/objects/TestVirtualHostObject.java
@@ -0,0 +1,84 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.commands.objects;
+
+import javax.management.MBeanServerConnection;
+
+import org.apache.qpid.ConnectionConstants;
+import org.apache.qpid.Connector;
+import org.apache.qpid.ConnectorFactory;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestVirtualHostObject
+{
+ Connector conn;
+ MBeanServerConnection mbsc;
+ VirtualHostObject test;
+ String test1, test2, test3;
+
+ @Before
+ public void startup() throws Exception
+ {
+ conn = ConnectorFactory.getConnector(ConnectionConstants.BROKER_HOSTNAME, ConnectionConstants.BROKER_PORT,
+ ConnectionConstants.USERNAME, ConnectionConstants.PASSWORD);
+ mbsc = conn.getMBeanServerConnection();
+ test = new VirtualHostObject(mbsc);
+ test1 = "ping";
+ test2 = "test";
+ test3 = "object";
+
+ }
+
+ @Test
+ public void TestSetQueryString()
+ {
+ test.setQueryString(test3, test1, null);
+ Assert.assertEquals(test.querystring, "org.apache.qpid:type=VirtualHost.VirtualHostManager,name=ping,*");
+ test.querystring = null;
+ test.setQueryString(test3, null, test2);
+ Assert.assertEquals(test.querystring, "org.apache.qpid:type=VirtualHost.VirtualHostManager,VirtualHost=test,*");
+ test.querystring = null;
+ test.setQueryString(test3, test1, test2);
+ Assert.assertEquals(test.querystring,
+ "org.apache.qpid:type=VirtualHost.VirtualHostManager,VirtualHost=test,name=ping,*");
+ test.querystring = null;
+ test.setQueryString(test3, null, null);
+ Assert.assertEquals(test.querystring, "org.apache.qpid:type=VirtualHost.VirtualHostManager,*");
+
+ }
+
+ @After
+ public void cleanup()
+ {
+ try
+ {
+ conn.getConnector().close();
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+
+ }
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/utils/TestCommandLineOption.java b/java/management/tools/qpid-cli/test/org/apache/qpid/utils/TestCommandLineOption.java
new file mode 100644
index 0000000000..e2a03f52ad
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/utils/TestCommandLineOption.java
@@ -0,0 +1,64 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.utils;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestCommandLineOption
+{
+ String input1;
+ String input2;
+ String options;
+ String[] list;
+ CommandLineOption option;
+
+ @Before
+ public void setup()
+ {
+ input1 = "-h";
+ input2 = "--help";
+ options = "localhost testing";
+ list = options.split(" ");
+ option = new CommandLineOption(input1, list);
+
+ }
+
+ @Test
+ public void TestGetOptinValue()
+ {
+ Assert.assertEquals(option.getOptionValue(), "localhost");
+ }
+
+ @Test
+ public void TestGetOptionType()
+ {
+ Assert.assertEquals(option.getOptionType(), "h");
+ }
+
+ @After
+ public void cleanup()
+ {
+ option = null;
+ }
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/utils/TestCommandLineOptionParser.java b/java/management/tools/qpid-cli/test/org/apache/qpid/utils/TestCommandLineOptionParser.java
new file mode 100644
index 0000000000..964c350fc5
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/utils/TestCommandLineOptionParser.java
@@ -0,0 +1,79 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.utils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestCommandLineOptionParser
+{
+ CommandLineOptionParser parser;
+ String[] input;
+ CommandLineOption option1;
+ CommandLineOption option2;
+ ArrayList list1;
+ ArrayList list2;
+
+ @Before
+ public void setup()
+ {
+ String temp = "run -h localhost -p 23232";
+ input = temp.split(" ");
+ parser = new CommandLineOptionParser(input);
+ list1 = new ArrayList();
+ list2 = new ArrayList();
+ }
+
+ @Test
+ public void TestParse()
+ {
+ Map hash = new HashMap();
+
+ list1.add("localhost");
+ list2.add("23232");
+ option1 = new CommandLineOption("h", list1);
+ option2 = new CommandLineOption("p", list2);
+ hash.put("h", option1);
+ hash.put("p", option2);
+ option1 = (CommandLineOption) parser.parse(input).get("h");
+ Assert.assertEquals(option1.getOptionType(), "h");
+ Assert.assertEquals(option1.getOptionValue(), "localhost");
+ option1 = (CommandLineOption) parser.parse(input).get("p");
+ Assert.assertEquals(option1.getOptionType(), "p");
+ Assert.assertEquals(option1.getOptionValue(), "23232");
+ Assert.assertEquals(parser.parse(input).size(), hash.size());
+ }
+
+ @After
+ public void cleanup()
+ {
+ parser = null;
+ option1 = null;
+ option2 = null;
+
+ }
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/utils/TestJMXConfigProperty.java b/java/management/tools/qpid-cli/test/org/apache/qpid/utils/TestJMXConfigProperty.java
new file mode 100644
index 0000000000..20234d1153
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/utils/TestJMXConfigProperty.java
@@ -0,0 +1,26 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.utils;
+
+public class TestJMXConfigProperty
+{
+
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/utils/TestJMXConfiguration.java b/java/management/tools/qpid-cli/test/org/apache/qpid/utils/TestJMXConfiguration.java
new file mode 100644
index 0000000000..40cde00953
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/utils/TestJMXConfiguration.java
@@ -0,0 +1,64 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.utils;
+
+import java.util.ArrayList;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestJMXConfiguration
+{
+ CommandLineOptionParser clop;
+ JMXConfiguration jmc;
+ CommandLineOption option;
+ String[] input;
+
+ @Before
+ public void setup()
+ {
+ String temp = "command -h 127.0.0.1 -p 1234";
+ input = temp.split(" ");
+ clop = new CommandLineOptionParser(input);
+ jmc = new JMXConfiguration(clop.getAlloptions());
+ }
+
+ @Test
+ public void TestLoadOption()
+ {
+ ArrayList list = new ArrayList();
+ list.add("127.0.0.1");
+ option = new CommandLineOption("-h", list);
+ CommandLineOption expect = jmc.loadoption("h", clop.getAlloptions());
+ Assert.assertEquals(expect.getOptionType(), option.getOptionType());
+ Assert.assertEquals(expect.getOptionValue(), option.getOptionValue());
+ }
+
+ @After
+ public void cleanup()
+ {
+ clop = null;
+ jmc = null;
+ option = null;
+ }
+}
diff --git a/java/management/tools/qpid-cli/test/org/apache/qpid/utils/TestJMXinfo.java b/java/management/tools/qpid-cli/test/org/apache/qpid/utils/TestJMXinfo.java
new file mode 100644
index 0000000000..aae39bcb37
--- /dev/null
+++ b/java/management/tools/qpid-cli/test/org/apache/qpid/utils/TestJMXinfo.java
@@ -0,0 +1,30 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.utils;
+
+public class TestJMXinfo
+{
+ /*
+ * this class is having only three simple getter methods. Therefore no
+ * testcases
+ */
+}
diff --git a/java/module.xml b/java/module.xml
index 50b68ee633..568359f7ea 100644
--- a/java/module.xml
+++ b/java/module.xml
@@ -26,12 +26,19 @@
<globmapper from="${project.root}${file.separator}*" to="*"/>
</map>
+ <map property="module.name" value="${module}">
+ <filtermapper>
+ <replacestring from="${file.separator}" to="-"/>
+ </filtermapper>
+ </map>
+
<echo message="Running ant for module : ${module}" level="info"/>
<property file="${project.root}/build.deps"/>
- <property name="module.build" location="${build}/${module}"/>
+ <property name="module.build" location="${build.scratch}/${module}"/>
<property name="module.classes" location="${module.build}/classes"/>
+ <property name="module.instrumented" location="${module.build}/classes-instrumented"/>
<property name="module.precompiled" location="${module.build}/src"/>
<property name="module.api" location="${module.build}/api"/>
<property name="module.test.classes" location="${module.build}/test/classes"/>
@@ -41,26 +48,46 @@
<property name="module.test.src" location="src/test/java"/>
<property name="module.bin" location="bin"/>
<property name="module.etc" location="etc"/>
+
+ <property name="module.namever" value="${project.name}-${module.name}-${project.version}"/>
+ <property name="module.namever.osgi" value="${project.name}-${module.name}_${project.version}.0.osgi"/>
+ <property name="module.release.base" value="${basedir}/release"/>
+ <property name="module.release" value="${module.release.base}/${module.namever}"/>
+ <property name="module.release.lib" value="${module.release}/lib"/>
+ <property name="module.release.zip" location="${module.release.base}/${module.namever}.zip"/>
+ <property name="module.release.tar" location="${module.release.base}/${module.namever}.tar"/>
+ <property name="module.release.tgz" location="${module.release.base}/${module.namever}.tar.gz"/>
+ <property name="module.release.bz2" location="${module.release}/${module.namever}.tar.bz2"/>
+
+ <property name="module.genpom.args" value=""/>
+ <property name="broker.log.prefix" value="BROKER: "/>
+ <property name="broker.log.interleave" value="true"/>
+
+ <property name="module.qpid.jar" location="${module.release.lib}/qpid-all.jar"/>
+ <basename property="qpid.jar.name" file="${module.qpid.jar}"/>
+
+ <property name="module.coverage" location="${module.build}/coverage"/>
+ <property name="cobertura.datafile" location="${module.instrumented}/cobetura.ser"/>
<available property="module.test.src.exists" file="${module.test.src}"/>
<available property="module.etc.exists" file="${module.etc}"/>
<available property="module.bin.exists" file="${module.bin}"/>
- <map property="module.name" value="${module}">
- <filtermapper>
- <replacestring from="${file.separator}" to="-"/>
- </filtermapper>
- </map>
-
<indirect name="module.libs" variable="${module.name}.libs"/>
+ <condition property="module.libs.includes" value="__EMPTY__" else="${module.libs}">
+ <equals trim="true" arg1="${module.libs}" arg2=""/>
+ </condition>
<indirect name="module.test.libs" variable="${module.name}.test.libs"/>
+ <condition property="module.test.libs.includes" value="__EMPTY__" else="${module.test.libs}">
+ <equals trim="true" arg1="${module.test.libs}" arg2=""/>
+ </condition>
<path id="module.libs">
- <filelist dir="${project.root}" files="${module.libs}"/>
+ <fileset dir="${project.root}" includes="${module.libs.includes}"/>
</path>
<path id="module.test.libs">
- <filelist dir="${project.root}" files="${module.test.libs}"/>
+ <fileset dir="${project.root}" includes="${module.test.libs.includes}"/>
</path>
<path id="module.src.path">
@@ -86,11 +113,11 @@
<property name="module.test.excludes" value=""/>
<map property="module.depends.path" value="${module.depends}" join="${path.separator}">
- <globmapper from="*" to="${build}/*/classes"/>
+ <globmapper from="*" to="${build.scratch}/*/classes"/>
</map>
<map property="module.test.depends.path" value="${module.test.depends}" join="${path.separator}">
- <globmapper from="*" to="${build}/*/classes"/>
+ <globmapper from="*" to="${build.scratch}/*/classes"/>
</map>
<path id="module.class.path">
@@ -139,6 +166,21 @@
<mkdir dir="${module.results}"/>
</target>
+ <target name="pom" depends="prepare" if="module.genpom">
+ <jython path="${mllib.dir}">
+ <args>
+ <arg line="${project.root}/genpom"/>
+ <arg line="-s ${project.root}/lib/poms"/>
+ <arg line="-o ${build}/${module.name}.pom"/>
+ <arg line="-g org.apache.qpid"/>
+ <arg line="-a ${module.name}"/>
+ <arg line="-v ${project.version}"/>
+ <arg line="${module.genpom.args}"/>
+ <arg line="${module.libs}"/>
+ </args>
+ </jython>
+ </target>
+
<target name="precompile"/>
<target name="compile" depends="prepare,precompile" description="compile sources">
@@ -182,18 +224,27 @@
</copy>
</target>
- <property name="java.naming.factory.initial" value="org.apache.qpid.jndi.PropertiesFileInitialContextFactory"/>
- <condition property="config" value="${profile}.testprofile" else="default.testprofile">
- <and>
- <isset property="profile"/>
- <available file="${project.root}/${profile}.testprofile" type="file"/>
- </and>
+ <property name="profile" value="default"/>
+ <property file="${test.profiles}/${profile}.testprofile" prefix="preload"/>
+ <property name="preload.include" value=""/>
+ <condition property="profiles"
+ value="${preload.include} ${profile}"
+ else="default ${preload.include} ${profile}">
+ <equals arg1="${profile}" arg2="default"/>
</condition>
+ <map property="_profile_files" value="${profiles}" join=" ">
+ <globmapper from="*" to="*.testprofile"/>
+ </map>
+ <concat destfile="${build.scratch}/test-${profile}.properties" force="no" fixlastline="yes">
+ <filelist dir="${test.profiles}" files="${_profile_files}"/>
+ </concat>
+ <property file="${build.scratch}/test-${profile}.properties"/>
+ <map property="test.excludefiles" value="${test.excludes}">
+ <globmapper from="*" to="${test.profiles}/*"/>
+ </map>
- <property file="${project.root}/${config}"/>
- <property file="${project.root}/default.testprofile"/>
<condition property="dontruntest" value="dontruntest" else="runtest">
<contains substring="${module.name}" string="${exclude.modules}" />
@@ -204,7 +255,7 @@
<delete file="${module.failed}"/>
- <echo message="Using config:${config}" level="info"/>
+ <echo message="Using profile:${profile}" level="info"/>
<junit fork="${test.fork}" maxmemory="${test.mem}" reloading="no"
haltonfailure="${haltonfailure}" haltonerror="${haltonerror}"
failureproperty="test.failures" printsummary="on" timeout="600000" >
@@ -212,6 +263,7 @@
<jvmarg value="${jvm.args}"/>
<sysproperty key="amqj.logging.level" value="${amqj.logging.level}"/>
+ <sysproperty key="amqj.server.logging.level" value="${amqj.server.logging.level}"/>
<sysproperty key="amqj.protocol.logging.level" value="${amqj.protocol.logging.level}"/>
<sysproperty key="log4j.debug" value="${log4j.debug}"/>
<sysproperty key="root.logging.level" value="${root.logging.level}"/>
@@ -220,15 +272,31 @@
<sysproperty key="java.naming.provider.url" value="${java.naming.provider.url}"/>
<sysproperty key="broker" value="${broker}"/>
<sysproperty key="broker.clean" value="${broker.clean}"/>
+ <sysproperty key="broker.clean.between.tests" value="${broker.clean.between.tests}"/>
<sysproperty key="broker.version" value="${broker.version}"/>
<sysproperty key="broker.ready" value="${broker.ready}" />
- <sysproperty key="test.excludes" value="${test.excludes}"/>
- <sysproperty key="test.excludesfile" value="${test.excludesfile}"/>
+ <sysproperty key="broker.stopped" value="${broker.stopped}" />
+ <sysproperty key="broker.config" value="${broker.config}" />
<sysproperty key="test.output" value="${module.results}"/>
+
+ <syspropertyset>
+ <propertyref prefix="test"/>
+ </syspropertyset>
+ <syspropertyset>
+ <propertyref prefix="profile"/>
+ </syspropertyset>
+ <syspropertyset>
+ <propertyref prefix="javax.net.ssl"/>
+ </syspropertyset>
+ <syspropertyset>
+ <propertyref prefix="broker"/>
+ </syspropertyset>
+
<sysproperty key="max_prefetch" value ="${max_prefetch}"/>
<sysproperty key="example.plugin.target" value="${project.root}/build/lib/plugins"/>
- <sysproperty key="QPID_EXAMPLE_HOME" value="${project.root}/build"/>
- <sysproperty key="QPID_HOME" value="${project.root}/build"/>
+ <sysproperty key="QPID_EXAMPLE_HOME" value="${qpid.home}"/>
+ <sysproperty key="QPID_HOME" value="${qpid.home}"/>
+ <sysproperty key="QPID_WORK" value="${qpid.work}"/>
<formatter type="plain"/>
<formatter type="xml"/>
@@ -267,19 +335,36 @@
<chmod dir="${build.bin}" perm="ugo+rx" includes="**/*"/>
</target>
+ <target name="copy-bin-release" if="module.bin.exists" description="copy dependencies into module release">
+ <copy todir="${module.release}/bin" failonerror="true">
+ <fileset dir="${module.bin}" />
+ </copy>
+ <chmod dir="${module.release}/bin" perm="ugo+rx" includes="**/*"/>
+ </target>
+
<target name="copy-etc" if="module.etc.exists" description="copy etc directory if it exists to build tree">
<copy todir="${build.etc}" failonerror="false">
<fileset dir="${module.etc}"/>
</copy>
</target>
- <target name="build" depends="jar,jar-tests,libs,copy-bin,copy-etc" description="compile and copy resources into build tree"/>
+ <target name="copy-etc-release" if="module.etc.exists" description="copy etc directory if it exists to build tree">
+ <copy todir="${module.release}/etc" failonerror="false" flatten="true">
+ <fileset dir="${module.etc}"/>
+ </copy>
+ </target>
+
+ <target name="postbuild" description="run after a build"/>
+
+ <target name="build" depends="jar,jar-tests,libs,copy-bin,copy-etc,postbuild" description="compile and copy resources into build tree"/>
<target name="jar.manifest" depends="compile" if="module.manifest">
<jar destfile="${module.jar}" basedir="${module.classes}" manifest="${module.manifest}"/>
</target>
<target name="jar.nomanifest" depends="compile" unless="module.manifest">
- <jar destfile="${module.jar}" basedir="${module.classes}"/>
+ <jar destfile="${module.jar}" basedir="${module.classes}">
+ <metainf dir="${project.root}/resources/" />
+ </jar>
</target>
<target name="jar" depends="jar.manifest,jar.nomanifest" description="create jar"/>
@@ -289,8 +374,36 @@
</target>
<target name="libs" description="copy dependencies into build tree">
- <copy todir="${build.lib}" failonerror="false" flatten="true">
- <fileset dir="${basedir}${file.separator}.." includes="${module.libs}"/>
+ <copylist todir="${build.lib}" dir="${project.root}" files="${module.libs}"/>
+ </target>
+
+ <map property="module.depends.jars" value="${module.depends}" join=",">
+ <globmapper from="*" to="${project.name}-*-${project.version}.jar"/>
+ <filtermapper>
+ <replacestring from="/" to="-"/>
+ </filtermapper>
+ </map>
+
+
+ <target name="libs-release" description="copy dependencies into module release">
+ <!-- Copy the module dependencies -->
+ <copylist todir="${module.release}/lib" dir="${project.root}" files="${module.libs}"/>
+ <!-- Copy the jar for this module -->
+ <copy todir="${module.release}/lib" failonerror="true">
+ <fileset file="${module.jar}"/>
+ <fileset dir="${build.lib}" includes="${module.depends.jars}"/>
+ </copy>
+ </target>
+
+ <target name="resources" description="copy resources into build tree">
+ <copy todir="${build}" failonerror="false" flatten="true">
+ <fileset dir="${basedir}${file.separator}.." includes="${resources}"/>
+ </copy>
+ </target>
+
+ <target name="resources-release" description="copy resources into module release">
+ <copy todir="${module.release}" failonerror="false" flatten="true">
+ <fileset dir="${resources}" excludes="META-INF"/>
</copy>
</target>
@@ -302,10 +415,209 @@
<javadoc destdir="${module.api}" sourcepathref="module.src.path"
classpathref="module.class.path" packagenames="*"/>
</target>
+
+ <target name="release-bin-prepare">
+ <mkdir dir="${module.release}"/>
+ <available property="module.release.exists" file="${module.release}"/>
+ </target>
+
+ <target name="check-module-manifest">
+ <uptodate property="module-manifest.done" targetfile="${qpid.jar}">
+ <srcfiles dir="${build.lib}" includes="**/*.jar" excludes="**/${qpid.jar.name}"/>
+ </uptodate>
+ </target>
+
+ <target name="module-manifest" depends="check-module-manifest" unless="module-manifest.done">
+ <path id="class.path">
+ <fileset dir="${module.release.lib}" >
+ <include name="*.jar"/>
+ <exclude name="${qpid.jar.name}"/>
+ </fileset>
+ </path>
+ <pathconvert property="qpid.jar.classpath" pathsep=" " dirsep="/">
+ <path refid="class.path"/>
+ <globmapper from="${module.release.lib}${file.separator}*" to="*"/>
+ </pathconvert>
+
+ <jar destfile="${module.qpid.jar}">
+ <manifest>
+ <attribute name="Class-Path" value="${qpid.jar.classpath}"/>
+ </manifest>
+ <metainf dir="${project.root}/resources/"/>
+ </jar>
+
+ <touch file="${module.qpid.jar}"/>
+ </target>
+
+
+ <target name="zip-release" depends="build-release-bin" description="build module release archive">
+ <zip destfile="${module.release.zip}">
+ <zipfileset dir="${module.release}" prefix="${module.namever}" filemode="755">
+ <include name="bin/*"/>
+ <exclude name="bin/*.txt"/>
+ </zipfileset>
+
+ <zipfileset dir="${module.release}" prefix="${module.namever}" filemode="644">
+ <include name="bin/*.txt"/>
+ </zipfileset>
+
+ <zipfileset dir="${module.release}" prefix="${module.namever}" excludes="${module.release.excludes}" filemode="644" dirmode="755">
+ <exclude name="bin/**"/>
+ <exclude name="**/*.class"/>
+ </zipfileset>
+ </zip>
+ </target>
+
+ <target name="bundle" description="Build module osgi artifact. Override and depend on bundle-tasks to use"/>
+
+ <target name="bundle-tasks" depends="jar">
+ <taskdef resource="aQute/bnd/ant/taskdef.properties" classpath="${project.root}/lib/bnd-0.0.249.jar"/>
+ <echo message="Bundling ${build}/lib/${module.namever}.jar with ${module.src}/${module.name}.bnd"/>
+ <bnd
+ classpath="${build}/lib/${module.namever}.jar"
+ eclipse="false"
+ failok="false"
+ exceptions="true"
+ output="${build}/lib/${module.namever.osgi}.jar"
+ files="${module.src}/${module.name}.bnd"/>
+ </target>
+
+ <target name="tar-release" depends="zip-release" description="build release archive">
+ <tar destfile="${module.release.tar}" longfile="gnu" >
+ <zipfileset src="${module.release.zip}"/>
+ </tar>
+ </target>
+
+ <target name="gzip-release" depends="tar-release" description="build release archive">
+ <gzip src="${module.release.tar}" destfile="${module.release.tgz}"/>
+ </target>
+
+ <target name="bzip2-release" depends="tar-release" description="build release archive">
+ <bzip2 src="${module.release.tar}" destfile="${module.release.bz2}"/>
+ </target>
+
+ <target name="doc-release" description="no-op override if a doc step is requried "/>
+
+
+ <target name="build-release-bin" depends="release-bin-prepare,libs-release,copy-bin-release,
+ copy-etc-release,doc-release,resources-release,release-bin-other,module-manifest"
+ description="Task that includes all tasks required to create a module binary release"/>
+
+ <!-- ,zip-release,gzip-release -->
+ <target name="release-bin-tasks" depends="gzip-release" description="build all release archives except .bz2"/>
+
+ <target name="release-bin-all-tasks" depends="bzip2-release" description="build all release archives"/>
+
+ <!-- Dummy targets to no-op for most modules. Override if a module package is required -->
+ <target name="release-bin-other" description="Override if there is tasks required for the module bin release to occur last"/>
+ <target name="release-bin" description="Override and depend on release-bin-tasks to generate"/>
+ <target name="release-bin-all" description="Override and depend on release-bin-tasks to generate"/>
<target name="clean" description="remove build artifacts">
<delete dir="${module.build}"/>
<delete dir="${module.results}"/>
+ <delete dir="${module.release.base}"/>
+ <delete dir="${module.instrumented}"/>
+ </target>
+
+ <target name="instrument" depends="cobertura-init">
+ <cobertura-instrument todir="${module.instrumented}"
+ datafile="${cobertura.datafile}">
+ <fileset dir="${module.classes}">
+ <include name="**/*.class"/>
+ </fileset>
+ <fileset dir="${module.test.classes}">
+ <include name="**/*.class"/>
+ </fileset>
+ </cobertura-instrument>
+ </target>
+
+ <target name="cover-test" depends="instrument">
+
+ <mkdir dir="${build.coveragereport}" />
+ <junit fork="yes" forkmode="once" maxmemory="${test.mem}" reloading="no"
+ haltonfailure="${haltonfailure}" haltonerror="${haltonerror}"
+ failureproperty="test.failures" printsummary="on" timeout="600000" >
+
+ <sysproperty key="amqj.logging.level" value="${amqj.logging.level}"/>
+ <sysproperty key="amqj.protocol.logging.level" value="${amqj.protocol.logging.level}"/>
+ <sysproperty key="log4j.debug" value="${log4j.debug}"/>
+ <sysproperty key="root.logging.level" value="${root.logging.level}"/>
+ <sysproperty key="log4j.configuration" value="${log4j.configuration}"/>
+ <sysproperty key="java.naming.factory.initial" value="${java.naming.factory.initial}"/>
+ <sysproperty key="java.naming.provider.url" value="${java.naming.provider.url}"/>
+ <sysproperty key="broker" value="${broker}"/>
+ <sysproperty key="broker.clean" value="${broker.clean}"/>
+ <sysproperty key="broker.version" value="${broker.version}"/>
+ <sysproperty key="broker.ready" value="${broker.ready}" />
+ <sysproperty key="test.output" value="${module.results}"/>
+
+ <syspropertyset>
+ <propertyref prefix="test"/>
+ </syspropertyset>
+ <syspropertyset>
+ <propertyref prefix="broker"/>
+ </syspropertyset>
+
+ <sysproperty key="max_prefetch" value ="${max_prefetch}"/>
+ <sysproperty key="example.plugin.target" value="${project.root}/build/lib/plugins"/>
+ <sysproperty key="QPID_EXAMPLE_HOME" value="${project.root}/build"/>
+ <sysproperty key="QPID_HOME" value="${project.root}/build"/>
+
+ <sysproperty key="net.sourceforge.cobertura.datafile"
+ file="${cobertura.datafile}" />
+
+ <formatter type="plain"/>
+ <formatter type="xml"/>
+
+ <classpath path="${module.instrumented}"/>
+ <classpath>
+ <fileset dir="${build}">
+ <include name="**/classes-instrumented/*.class"/>
+ </fileset>
+ </classpath>
+ <classpath refid="module.test.path"/>
+ <classpath refid="cobertura.classpath"/>
+
+ <batchtest todir="${module.results}">
+ <fileset dir="${module.test.src}" excludes="${module.test.excludes}">
+ <include name="**/${test}.java"/>
+ </fileset>
+ </batchtest>
+ </junit>
+ </target>
+
+ <target name="coverage-report" depends="cobertura-init">
+ <echo message="${cobertura.datafile}"/>
+ <cobertura-report format="html"
+ destdir="${module.coverage}"
+ datafile="${cobertura.datafile}">
+ <fileset dir="${module.src}" includes="**/*.java" />
+ </cobertura-report>
+ </target>
+
+ <property name="version.file" location="${module.classes}/qpidversion.properties"/>
+ <property file="${version.file}" prefix="old."/>
+
+ <target name="check-version">
+ <exec executable="svnversion" spawn="false" failifexecutionfails="false"
+ dir="${project.root}" outputproperty="svnversion.output">
+ <arg line="."/>
+ </exec>
+ <condition property="version.stale">
+ <not>
+ <equals arg1="${svnversion.output}" arg2="${old.qpid.svnversion}"/>
+ </not>
+ </condition>
+ </target>
+
+ <target name="create-version" depends="check-version" if="version.stale">
+ <!-- Write the version.properties out.-->
+ <!-- Echos exactly as shown, so leave no spaces before/after lines -->
+ <echo file="${version.file}" append="false">qpid.version=${project.version}
+qpid.svnversion=${svnversion.output}
+qpid.name=${project.name}
+</echo>
</target>
</project>
diff --git a/java/perftests/bin/monitoring/monitor-broker.sh b/java/perftests/bin/monitoring/monitor-broker.sh
new file mode 100755
index 0000000000..39f4760114
--- /dev/null
+++ b/java/perftests/bin/monitoring/monitor-broker.sh
@@ -0,0 +1,200 @@
+#!/bin/bash
+#
+# This script starts a broker and then starts additional logging as required.
+# *.pid files are generated in the LOG_DIR for later use by the stop-monitored-broker
+# script.
+#
+# Currently this process starts:
+# - The broker with additional QPID_OPTS for gc logging
+# - Top to monitoring the CPU usage
+#
+# Additional processes can be started and as long as they write a PID into LOG_DIR/*.pid
+# it will be shutdown with the stop script
+#
+
+#
+# Output the broker log file to aid problem diagnosis
+# then exit.
+#
+brokerFailExit()
+{
+ echo "Broker failed to start up."
+ cat $BROKER_LOG
+ exit 1
+}
+
+showUsageExit()
+{
+ echo "Usage $0 <Path to Test Broker> <LOG DIR> <CPU Monitor Rate (s)> [Additional options to
+ pass to Qpid broker startup]"
+ exit 1
+}
+
+#
+# Perform 3 attempts to get the broker PID via ps and grep
+# if unable the output broker log and exit
+#
+getBrokerPID()
+{
+ attempts=3
+ ready=0
+ while [ $ready == 0 ] ; do
+
+ PID=`ps auxwww| grep java | grep Xloggc | awk '{print $2}'`
+
+ if [ ! $PID == 0 ] ; then
+ ready=1
+ else
+ attempts=$[ $attempts - 1 ]
+
+ if [ $attempts == 0 ] ; then
+ brokerFailExit
+ fi
+
+ sleep 1
+ fi
+ done
+
+}
+
+
+#
+# Additional Check to ensure that the broker process
+# has correctly written 'Ready' to the log file.
+#
+checkBrokerStarted()
+{
+ attempts=3
+ ready=0
+ while [ $ready == 0 ] ; do
+
+ grep Ready $BROKER_LOG > /dev/null
+
+ if [ $? == 0 ] ; then
+ ready=1
+ else
+ attempts=$[ $attempts - 1 ]
+
+ if [ $attempts == 0 ] ; then
+ brokerFailExit
+ fi
+
+ echo "Broker not ready sleeping 1s"
+ sleep 1
+ fi
+ done
+}
+
+#
+# Command Line setup
+#
+
+# Ensure we have minimum of three arguments
+if [[ $# > 2 ]] ; then
+ BROKER_VERSION=$1
+ LOG_DIR=$2
+ CPU_MONITOR_RATE=$3
+ # Remove these arguments from the $@ variable
+ shift
+ shift
+ shift
+else
+ # If we have no arguments then use these as the default
+ CPU_MONITOR_RATE=0.5
+ LOG_DIR=$QPID_WORK/logging
+ BROKER_VERSION=qpid-0.5
+fi
+
+
+#
+# Check the specified broker is reachable
+# it it is not the log and show usage
+#
+if [ ! -d $BROKER_VERSION ] ; then
+ echo "Broker not available at: $BROKER_VERSION"
+ showUsageExit
+fi
+
+#
+# Check to see if we have an absolute path for logging
+#
+logStart=`echo $LOG_DIR|cut -c 1`
+
+
+#
+# If we don't have an absolute path then add the current
+# directory path to the start.
+#
+if [[ $logStart != '/' ]] ; then
+ echo -n "$LOG_DIR is not absolute, using "
+ LOG_DIR=`pwd`/$LOG_DIR
+ echo $LOG_DIR
+fi
+
+#
+# Validate that the directory does not exist
+# - this is so we can guarrantee a clean run.
+# If it does exit then log and show usage
+#
+if [ -d $LOG_DIR ] ; then
+ echo "Log directory already exists : $LOG_DIR"
+ showUsageExit
+fi
+
+#
+# Create the logging directory
+#
+mkdir -p $LOG_DIR
+
+#
+# Variable for broker log
+#
+BROKER_LOG=$LOG_DIR/broker.log
+
+# Variable to hold broker PID
+PID=0
+
+export QPID_OPTS="-Xloggc:$LOG_DIR/gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps"
+
+#
+# Start Qpid Broker
+#
+echo "Starting Broker : $BROKER_VERSION"
+pushd $BROKER_VERSION/bin > /dev/null
+./qpid-server $@ 2> $BROKER_LOG >&2 &
+popd > /dev/null
+
+# Wait and check startup was ok
+echo "Waiting for broker startup"
+getBrokerPID
+
+checkBrokerStarted
+
+echo $PID > $LOG_DIR/broker.pid
+
+#
+# Start CPU Monitoring via TOP
+#
+echo "Starting CPU Monitor at RATE:$CPU_MONITOR_RATE on $SERVER1"
+pushd $LOG_DIR > /dev/null
+
+echo $CPU_MONITOR_RATE > top.rate
+
+top -d $CPU_MONITOR_RATE -S -c -p $PID -b > broker_cpu.log &
+
+#
+# Get top pid using $!
+#
+echo $! > $LOG_DIR/top.pid
+
+popd > /dev/null
+
+
+#
+# Generate Stat files
+#
+echo "Generating Stat data"
+stat $BROKER_LOG > $BROKER_LOG.stat
+stat $LOG_DIR/broker_cpu.log > $LOG_DIR/broker_cpu.log.stat
+stat $LOG_DIR/gc.log > $LOG_DIR/gc.log.stat
+
diff --git a/java/perftests/bin/monitoring/runTests.sh b/java/perftests/bin/monitoring/runTests.sh
new file mode 100755
index 0000000000..4ba5040ccc
--- /dev/null
+++ b/java/perftests/bin/monitoring/runTests.sh
@@ -0,0 +1,127 @@
+#!/bin/bash
+#
+# Run specified performance tests and
+# gather details about the test run
+#
+
+
+runTest()
+{
+ echo "$@"
+ echo "$@ --csv -o $LOG_DIR" >> $LOG_DIR/TestRun.log 2>&1
+ ./$@ --csv -o $LOG_DIR >> $LOG_DIR/TestRun.log 2>&1
+}
+
+showUsageExit()
+{
+ echo "Usage $0 <Path to Test Pack> <LOG DIR> <TEST LIST FILE>"
+ exit 1
+}
+
+# Ensure we have minimum of three arguments
+if [[ $# > 2 ]] ; then
+ TEST_VERSION=$1
+ LOG_DIR=$2
+ TEST_LIST=$3
+ # Remove these arguments from the $@ variable
+ shift
+ shift
+ shift
+else
+ showUsageExit
+fi
+
+#
+# Check the specified broker is reachable
+# it it is not the log and show usage
+#
+if [ ! -d $TEST_VERSION ] ; then
+ echo "Tests not available at: $TEST_VERSION"
+ showUsageExit
+fi
+
+
+#
+# Check to see if we have an absolute path for logging
+#
+logStart=`echo $LOG_DIR|cut -c 1`
+
+#
+# If we don't have an absolute path then add the current
+# directory path to the start.
+#
+if [[ $logStart != '/' ]] ; then
+ echo -n "$LOG_DIR is not absolute, using "
+ LOG_DIR=`pwd`/$LOG_DIR
+ echo $LOG_DIR
+fi
+
+#
+# Validate that the directory does not exist
+# - this is so we can guarrantee a clean run.
+# If it does exit then log and show usage
+#
+if [ -d $LOG_DIR ] ; then
+ echo "Log directory already exists : $LOG_DIR"
+ showUsageExit
+fi
+
+#
+# Check to see if we have an absolute path for test list
+#
+testListStart=`echo $TEST_LIST|cut -c 1`
+
+#
+# If we don't have an absolute path then add the current
+# directory path to the start.
+#
+if [[ $testListStart != '/' ]] ; then
+ echo -n "$TEST_LIST is not absolute, using "
+ TEST_LIST=`pwd`/$TEST_LIST
+ echo $TEST_LIST
+fi
+
+#
+# Validate that the directory does not exist
+# - this is so we can guarrantee a clean run.
+# If it does exit then log and show usage
+#
+# -r Check file exists and is readable
+if [ ! -r $TEST_LIST ] ; then
+ echo "Test file is not readable : $TEST_LIST"
+ showUsageExit
+fi
+
+
+
+#
+# Create the logging directory
+#
+mkdir -p $LOG_DIR
+
+
+
+echo "Starting Test Run in : $TEST_VERSION"
+pushd $TEST_VERSION/bin > /dev/null
+
+#
+# Run tests
+#
+
+
+while read testCommand
+do
+ runTest $testCommand
+done < "$TEST_LIST"
+
+
+popd > /dev/null
+
+
+#
+# Generate Stat files
+#
+echo "Generating Stat data"
+for file in `find $LOG_DIR -name "*.csv"` ; do
+ stat $file > $file.stat
+done
diff --git a/java/perftests/bin/monitoring/stop-monitored-broker.sh b/java/perftests/bin/monitoring/stop-monitored-broker.sh
new file mode 100755
index 0000000000..2bd1d1771a
--- /dev/null
+++ b/java/perftests/bin/monitoring/stop-monitored-broker.sh
@@ -0,0 +1,103 @@
+#!/bin/bash
+#
+# Script to stop the running of a monitored broker
+# and the associated monitoring processes.
+#
+# Looks in the specifed directory for pid files and
+# stops those proceses
+#
+
+
+usage()
+{
+ echo "Usage: $0 <LOG_DIR>"
+}
+
+#
+# Attempt to gracefully kill processs
+#
+stopRun()
+{
+ kill $PIDS
+}
+
+
+#
+# Forcibly stop processes
+#
+forceStopRun()
+{
+ kill -9 $PIDS
+}
+
+#
+# Show usage if we are not started correctly
+#
+if [ $# != 1 ] ; then
+ usage
+ exit 1
+fi
+
+LOG_DIR=$1
+
+
+PIDS=`cat $LOG_DIR/*.pid`
+
+echo "Preparing to stop:"
+#
+# Escape the path so we can use sed to remove it.
+#
+path=`echo $LOG_DIR|sed -e s/\\\//\\\\\\\\\\\//g`
+
+for i in `ls $LOG_DIR/*.pid` ; do
+ # Remove path from pid item then remove any final '/'
+ echo $i|cut -d '.' -f 1| sed -e s/$path// |tr '/' ' '
+done
+
+status=`ps $PIDS |wc -l`
+
+if [ $status == 1 ] ; then
+ echo "Processes do not appear to be running."
+ echo "Have they already been stopped?"
+ exit 0
+fi
+
+attempts=3
+
+while [ ! $status == 1 ] ; do
+ stopRun
+ sleep 1
+ status=`ps $PIDS |wc -l`
+
+ if [ $status == 1 ] ; then
+ echo "Done"
+ exit 0
+ else
+ attempts=$[ $attempts - 1 ]
+
+ if [ $attempts == 0 ] ; then
+ break
+ fi
+
+ echo "Sleeping as processes not stopped"
+ sleep 2
+
+ fi
+done
+
+# If we haven't been able to kill the processes then
+# forcibly do it
+if [ ! $status == 1 ] ; then
+ forceStopRun
+ sleep 1
+ status=`ps $PIDS |wc -l`
+
+ if [ $status == 1 ] ; then
+ echo "Done"
+ else
+ echo "Stop failed"
+ exit 1
+ fi
+else
+ echo "Done"
+fi
diff --git a/java/perftests/bin/processing/process.sh b/java/perftests/bin/processing/process.sh
new file mode 100755
index 0000000000..84d6467f87
--- /dev/null
+++ b/java/perftests/bin/processing/process.sh
@@ -0,0 +1,264 @@
+#!/bin/bash
+
+usage()
+{
+ echo "usage: process.sh <Qpid Version> <Test Type Queue/Topic/Latency..> <Volume of data %age> <broker details>"
+ echo "These parameters are used to title and name the graphs:"
+ echo 'Title = $<Qpid Version> $<Test Type> : $<Volume>% volume'
+ echo 'File = $<Qpid Version>-$<Broker Details>-$<Test Type>-$<Volume>'
+ exit 1
+}
+
+processCMSGCFile()
+{
+ # Extract all the ParNew timings: Ignore any lines corrupted by concurrent CMS logging.
+ grep -v CMS gc.log|grep ParNew > $work/parnew.gc.log
+
+ # Calculate Full GC Data
+ grep failure -B 1 gc.log | sed -e :a -e '$!N;s/\n.(concurrent/ /;ta' -e 'P;D' |grep -v ^\- > $work/full.gc.log
+ cut -d ':' -f 1 $work/full.gc.log > $work/full.time.log
+ sed -e 's/failure)/\#/g' $work/full.gc.log |cut -d '#' -f 2- |awk '{print $3}' > $work/full.dur.log
+
+ # Move to the working directory to further process the gathered data.
+ pushd $work &> /dev/null
+
+ # Extract the Heap and timing data.
+ #8 is the full gc data
+ #5 is the paranew gc data
+ cat parnew.gc.log | awk '{print $8}' | cut -d '(' -f 2 | cut -d 'K' -f 1 > HEAP_MAX.log
+ cat parnew.gc.log | awk '{print $8}' | cut -d 'K' -f 1 > HEAP_PRE_GC.log
+ cat parnew.gc.log | awk '{print $8}' | cut -d 'K' -f 2 | cut -d '>' -f 2 > HEAP_POST_GC.log
+ cat parnew.gc.log | awk '{print $1}' | cut -d ':' -f 1 > GC_TIME.log
+
+
+ # Calculate ParNew GC Cumulative total
+ cat parnew.gc.log |awk '{sum=sum+$6; print $6, sum}' > GC_DUR.log
+ # Give a count of GC occurances
+ parNewGCCount=`wc -l GC_DUR.log| awk '{print $1}'`
+
+ # Create the Heap data file
+ paste GC_TIME.log HEAP_POST_GC.log HEAP_PRE_GC.log HEAP_MAX.log > GC.Heap.data
+ # Create ParNew GC Duration data file for graphing
+ paste GC_TIME.log GC_DUR.log > GC.Dur.data
+ # Create Full GC occurance log file for plotting
+ paste full.time.log full.dur.log > GC.Full.data
+
+ # Calculate All GC Timing and give a count of their occurance
+ awk '{print $1}' GC_DUR.log > gc_dur.log
+ paste GC_TIME.log gc_dur.log > gc_all.log
+ cat GC.Full.data >> gc_all.log
+ sort -n gc_all.log | awk '{sum=sum+$2;print $1 , sum}' > GC.Dur.All.data
+ fullGCCount=`wc -l GC.Full.data| awk '{print $1}'`
+}
+
+processG1GCFile()
+{
+ cat gc.log | grep -e \^[0-9]*.[0-9]*\: -e \^.*[0-9]*.\-\> > $work/g1.gc.log
+
+ # Move to the working directory to further process the gathered data.
+ pushd $work &> /dev/null
+
+ # Calculate Full GC Data
+ cat g1.gc.log | sed -e :a -e '$!N;s/\n.\ *\[/ \[/;ta' -e 'P;D' > full.gc.log
+ grep Full full.gc.log |awk '{print $1}'| tr ':' ' ' > full.time.log
+ grep Full full.gc.log |awk '{print $5}' > full.dur.log
+ fullGCCount=`wc -l GC.Full.data| awk '{print $1}'`
+
+ # Create Full GC occurance log file for plotting
+ paste full.time.log full.dur.log > GC.Full.data
+
+ # Extract the Heap and timing data.
+ # Create G1 Young Duration data file for graphing
+ grep "(young)," full.gc.log |awk '{print $1}' | tr ':' ' ' > GC_TIME.log
+ grep "(young)," full.gc.log |awk '{print $5}' > young.gc.time.log
+ # Calculate G1 young Cumulative total
+ cat young.gc.time.log |awk '{sum=sum+$1; print $1, sum}' > GC_DUR.log
+ # Create G1 Young Duration data file for graphing
+ paste GC_TIME.log GC_DUR.log > GC.Dur.data
+
+ # Give a count of GC occurances
+ youngGCCount=`wc -l GC_DUR.log| awk '{print $1}'`
+
+ #
+ # If we have no GCs then something is wrong
+ if [ $youngGCCount == 0 ] ; then
+ echo "Error no YoungGC log entries to proceses"
+ return
+ fi
+
+ # Gather the Heap Size data
+
+ grep "(young)," full.gc.log | awk '{print $8}' | cut -d '(' -f 2 | cut -d ')' -f 1 > HEAP_MAX.Sized.log
+ grep "(young)," full.gc.log | awk '{print $8}' | cut -d '-' -f 1 > HEAP_PRE_GC.Sized.log
+ grep "(young)," full.gc.log | awk '{print $8}' | cut -d '>' -f 2| cut -d '(' -f 1 > HEAP_POST_GC.Sized.log
+
+ normaliseSizeMemFile HEAP_MAX.Sized.log HEAP_MAX.log
+ normaliseSizeMemFile HEAP_PRE_GC.Sized.log HEAP_PRE_GC.log
+ normaliseSizeMemFile HEAP_POST_GC.Sized.log HEAP_POST_GC.log
+
+
+ # Create the Heap data file
+ paste GC_TIME.log HEAP_POST_GC.log HEAP_PRE_GC.log HEAP_MAX.log > GC.Heap.data
+
+ # Calculate All GC Timing and give a count of their occurance
+ awk '{print $1}' GC_DUR.log > gc_dur.log
+ paste GC_TIME.log gc_dur.log > gc_all.log
+ cat GC.Full.data >> gc_all.log
+ sort -n gc_all.log | awk '{sum=sum+$2;print $1 , sum}' > GC.Dur.All.data
+
+}
+
+#
+# Take an input file ($1) of lines
+# <value><K|M>
+# and output file $2 of <value> in whole M
+#
+normaliseSizeMemFile()
+{
+rm -f $2
+for i in `cat $1` ; do
+ if [[ `echo $i | grep -c "K" ` == 1 ]] ; then
+ kb=`echo $i|cut -d 'K' -f 1`
+ echo $[ $kb / 1024 ] >> $2
+ else
+ echo $i|cut -d 'M' -f 1 >> $2
+ fi
+done
+
+
+}
+
+
+# Parse command line
+# TODO more advanced processing
+# Check we have enough parameters
+if [ $# != 4 ] ; then
+ # Take one arg to be a graph data file.
+ if [ $# == 1 ] ; then
+ textArray[0]="" # hold text
+ length=0
+ # read whole file in loop
+ while read line
+ do
+ textArray[$length]=$line # store line
+ length=$(expr $length + 1) # increase length by 1
+ done < $1
+
+ if [ $length != 2 ] ; then
+ usage
+ fi
+
+ #Get Title and file name
+ title=${textArray[0]}
+ file=${textArray[1]}
+
+ pushd `dirname $1`
+
+ else
+ usage
+ fi
+else
+ version=$1
+ type=$2
+ volume=$3
+ brokerState=$4
+
+
+ # Configure Graph Title and image file names
+ title="$version $type : $volume% volume"
+ file="$version-$brokerState-$type-$volume"
+fi
+
+work=work
+
+mkdir -p $work
+
+echo -n "Processing GC Usage Data : "
+ParNew=`grep -c ParNew gc.log`
+
+if [ $ParNew != 0 ] ; then
+ echo "CMS log file"
+ processCMSGCFile
+ PLOT="\"GC.Dur.data\" with lines axis x1y1 ti \"ParNew GC Time ($parNewGCCount)\", "
+else
+ echo "G1 log file"
+ processG1GCFile
+ PLOT="\"GC.Dur.data\" with lines axis x1y1 ti \"G1 Young Time ($youngGCCount)\", "
+fi
+
+
+
+# Prepare the plot command
+# If a Full GC occured during this test then plot those
+if [[ $fullGCCount > 0 ]] ; then
+PLOT=$PLOT"\"GC.Dur.data\" using 1:3 with lines axis x1y2 ti \"Cumulative Total Time(ParNew)\", \
+ \"GC.Dur.All.data\" with lines axis x1y2 ti \"Cumulative Total Time(All)\", \
+ \"GC.Full.data\" with points ti \"Full GCs Time ($fullGCCount)\" "
+else
+PLOT=$PLOT"\"GC.Dur.data\" using 1:3 with lines axis x1y2 ti \"Cumulative Total Time(ParNew)\", \
+ \"GC.Dur.All.data\" with lines axis x1y2 ti \"Cumulative Total Time(All)\" "
+fi
+
+if [ $ParNew != 0 ] ; then
+ gcs=$parNewGCCount
+else
+ gcs=$youngGCCount
+fi
+
+# Call out to gnuplot to generate graphs
+# Only do this if we have data
+if [ $gcs != 0 ] ; then
+ # Generate the Heap Graph and the GC Duration Graph
+ gnuplot << EOGNUPLOT
+set xlabel "Run Time(s)"
+
+set title "$title : Heap Size"
+set term png
+set output "$file-Heap.png"
+set ylabel "MB" +0.5,0
+plot "GC.Heap.data" using 1:2 with lines axis x1y1 ti "GC Size Post",\
+ "GC.Heap.data" using 1:4 with lines axis x1y1 ti "GC Size Max ", \
+ "GC.Heap.data" using 1:3 with lines axis x1y1 ti "GC Size Pre "
+
+set y2tics nomirror
+set ytics nomirror
+set key top left
+set title "$title GC Time"
+set ylabel "Time(s)" +0.5,0
+set y2label "Total Time(s)"
+set output "$file-GCDuration.png"
+plot $PLOT
+EOGNUPLOT
+
+else
+ echo "Warning: No GC Data to graph"
+fi
+
+# pop back to further process for CPU usage
+popd &> /dev/null
+
+echo "Processing CPU Usage Data"
+
+# CPU.data is just TimeStamp + %age
+cat broker_cpu.log |awk '{print $1 "T" $2 " " $3}' > $work/CPU.data
+
+# Move to work directory to run gnuplot
+pushd $work &> /dev/null
+
+# Call out to gnuplot to generate graphs
+# Generate the Heap Graph and the GC Duration Graph
+gnuplot << EOGNUPLOT
+set term png
+set title "$title : CPU"
+set output "$file-CPU.png"
+unset key
+set xlabel "Real Time(h:m)"
+set ylabel "Usage(%)"
+
+set xdata time
+set timefmt "%Y-%m-%dT%H:%M:%S"
+set format x "%H:%M"
+plot "CPU.data" using 1:2 with lines
+EOGNUPLOT
+
+popd &> /dev/null
diff --git a/java/perftests/bin/processing/processAll.sh b/java/perftests/bin/processing/processAll.sh
new file mode 100755
index 0000000000..7fce0abb60
--- /dev/null
+++ b/java/perftests/bin/processing/processAll.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+usage()
+{
+ echo "processResults.sh <search dir>"
+ exit 1
+}
+
+root=`pwd`
+echo $root
+graphFile=graph.data
+
+if [ $# != 1 ] ; then
+ usage
+fi
+
+mkdir -p results
+
+for file in `find $1 -name $graphFile` ; do
+
+ dir=`dirname $file`
+
+ echo Processing : $dir
+ pushd $dir &> /dev/null
+
+ $root/process.sh $graphFile
+
+ echo Copying Images
+ cp work/*png $root/results/
+
+ popd &> /dev/null
+ echo Done
+done
diff --git a/java/perftests/bin/processing/processTests.py b/java/perftests/bin/processing/processTests.py
new file mode 100755
index 0000000000..7142692d14
--- /dev/null
+++ b/java/perftests/bin/processing/processTests.py
@@ -0,0 +1,567 @@
+#!/usr/bin/env python
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import os
+import re
+import datetime
+import sys
+import string
+from optparse import OptionParser
+from datetime import datetime, timedelta
+import shutil
+
+
+def showUsage():
+ log("./pT.py [-b|--broker-log-dir] <dir> [-t|--test-dir] <dir>")
+
+
+ACCESS="Access"
+MODIFY="Modify"
+
+BROKER_LOG="broker.log"
+BROKER_PID="broker.pid"
+BROKER_CPU="broker_cpu.log"
+BROKER_CPU_DATED="broker_cpu.log.dated"
+BROKER_GC="gc.log"
+
+GRAPH_DATA="graph.data"
+
+_verbose = False
+_debug = False
+_brokerLogs = ""
+
+def exitError(message):
+ log(message)
+ sys.exit(1)
+
+def main():
+ global _log, _verbose, _debug, _brokerLogs
+
+ # Load the
+ parser = OptionParser()
+
+ parser.add_option("-v", "--verbose", dest="verbose",
+ action="store_true", default=False, help="enable verbose output")
+
+ parser.add_option("-d", "--debug", dest="debug",
+ action="store_true", default=False, help="enable debug output")
+
+ parser.add_option("-b", "--broker-log-dir", dest="brokerLogs",
+ action="store", default=True, help="Broker Logs")
+
+ parser.add_option("-t", "--test-dir", dest="testDir",
+ action="store", default="", help="Test Results")
+
+
+ (options, args) = parser.parse_args()
+
+ _verbose = options.verbose
+ _debug = options.debug
+ testDir = options.testDir
+ _brokerLogs = options.brokerLogs
+
+ if testDir == "" or _brokerLogs == "" :
+ log("Broker Log Dir and Test Dir are both requried.")
+ showUsage()
+
+ if not os.path.exists(testDir):
+ exitError("Test directory does not exist:" + testDir)
+
+ if not os.path.exists(_brokerLogs):
+ exitError("Broker log directory does not exist:" + _brokerLogs)
+
+
+ # Standardize the format of the broker logs
+ preProcessBrokerLogs(_brokerLogs)
+
+ # Get list of test results from test_dir
+ processTestResults(testDir)
+
+#
+# Process the log files we know of
+#
+def preProcessBrokerLogs(resultDir):
+ # Pre-Process GC - no pre processing required
+
+ # Process Log4j - no processing required as file is already time stamped.
+
+ # Pre-Process broker_cpu
+ processCPUUsage(resultDir)
+
+#
+# Process the broker CPU log file and create an output file of format
+# <Date Time> <CPU Usage>
+#
+#
+def processCPUUsage(resultDir):
+ logfile=resultDir+os.sep+BROKER_CPU
+ datedFile=resultDir+os.sep+BROKER_CPU_DATED
+
+ start = extractTime(ACCESS, logfile+".stat")
+
+ pid = getPID(BROKER_PID)
+
+ topRate = getFirstLine(_brokerLogs+os.sep+"top.rate")
+
+ #
+ # Calulate addition required per process line output
+ #
+ if topRate.find(".") == -1:
+ second = topRate
+ millis = 0
+ else:
+ split = topRate.split('.')
+ seconds = split[0]
+ # Convert
+ millis = float("0."+split[1]) * 1000
+
+ offset = timedelta(seconds=int(seconds),milliseconds=int(millis))
+
+ #
+ # Process the CPU log file and make a file of format:
+ # datetime <CPU% usage> <MEM% usage>
+ #
+ # Open log CPU file for reading
+ logfile = open(logfile, "r")
+
+ # Open the output file, erasing any existing version
+ output= open(datedFile, "w")
+ for line in logfile:
+ if line.find(pid) != -1:
+ # Split line on whitespace
+ data = line.split()
+
+ #
+ # Data format
+ # 0 1 2 3 4 5 6 7 8 9 10 11
+ # PID USER PR NI %CPU TIME+ %MEM VIRT RES SHR S COMMAND
+ #
+
+ #Write out the date time (ISO-8601 format)
+ output.write(str(start))
+ # Output the %CPU value
+ output.write(" "+str(data[4]))
+ # Output the %MEM value
+ output.write(" "+str(data[5]))
+ output.write('\n')
+
+ # Add the offset based on the logging rate
+ start = start + offset
+
+ # Close the files
+ logfile.close
+ output.close
+
+ log("Pre Process of CPU Log file '"+BROKER_CPU+"' complete")
+
+
+#
+# Give an known process type get the recorded PID.
+#
+def getPID(process):
+ return getFirstLine(_brokerLogs+os.sep+process)
+
+#
+# Get the first line of the file without EOL chars.
+# NOTE: this will load the entire file into memory to do it.
+#
+def getFirstLine(fileName):
+ f = open(fileName,"r")
+ line = f.read().splitlines()[0]
+ f.close
+ return line
+
+
+#
+# Walk the directory given and process all csv test results
+#
+def processTestResults(resultDir):
+ for root, dirs, files in os.walk(resultDir, topdown=False):
+ if len(files) == 0:
+ exitError("Test result directory is empty:" + resultDir)
+ for file in files:
+ if file.endswith(".csv"):
+ processTestResult(root , file)
+
+def processTestResult(root, resultFile):
+ # Open stat file and extract test times, we determine:
+ # -start time based on the 'Access' value
+ # -end time based on the 'Modify' value 'Change' would also work
+
+ statFile=root+os.sep+resultFile+".stat"
+
+ if not os.path.exists(statFile):
+ log("Unable to process : Unable to open stat file:" + statFile)
+ return
+
+
+ createResultSetPackage(root, resultFile)
+
+
+def extractTime(field, statFile):
+ stats = open(statFile, "r")
+ for line in stats:
+ if line.startswith(field):
+ if line.find("(") == -1:
+ dt = lineToDate(" ".join(line.split()[1:]))
+
+ #
+ # TODO We need to handle time time zone issues as I'm sure we will have issues with the
+ # log4j matching.
+
+ stats.close
+ return dt
+
+#
+# Given a text line in ISO format convert it to a date object
+#
+def lineToDate(line):
+ #2009-06-22 17:04:44,320
+ #2009-06-22 17:04:44.320
+ pattern = re.compile(r'(?P<year>^[0-9][0-9][0-9][0-9])-(?P<month>[0-9][0-9])-(?P<day>[0-9][0-9]) (?P<hour>[0-9][0-9]):(?P<minute>[0-9][0-9]):(?P<seconds>[0-9][0-9])')
+
+
+ m = pattern.match(line)
+ if m:
+ year = int(m.group('year'))
+ month = int(m.group('month'))
+ day = int(m.group('day'))
+ hour = int(m.group('hour'))
+ minute = int(m.group('minute'))
+ seconds = int(m.group('seconds'))
+
+ pattern = re.compile(r'(?P<year>^[0-9][0-9][0-9][0-9])-(?P<month>[0-9][0-9])-(?P<day>[0-9][0-9]) (?P<hour>[0-9][0-9]):(?P<minute>[0-9][0-9]):(?P<seconds>[0-9][0-9])[.|,](?P<micro>[0-9]+)')
+ m = pattern.match(line)
+ micro = None
+ if m:
+ micro = m.group('micro')
+
+ if micro == None:
+ micro = 0
+
+ return datetime(year,month,day,hour,minute,seconds,int(micro))
+ else:
+ # Error we shouldn't get here
+ return null
+
+def createResultSetPackage(root, resultFile):
+ # Get the Name of the test to make a directory with said name
+ testName = resultFile.split(".csv")[0]
+ resultDir = root+ os.sep + testName
+
+ log("Processing Result set for:"+ testName)
+
+ mkdir(resultDir)
+
+ # Move result file to new directory
+ shutil.move(root + os.sep + resultFile, resultDir)
+
+ # Move stat file to new directory
+ shutil.move(root + os.sep + resultFile + ".stat", resultDir)
+
+ statFile=resultDir + os.sep + resultFile + ".stat"
+
+ #
+ # Get start and end time for test run
+ #
+ start = extractTime(ACCESS, statFile)
+ end = extractTime(MODIFY, statFile)
+
+ sliceBrokerLogs(resultDir, start, end)
+ createGraphData(resultDir, testName)
+
+ log("Created Result Package for:"+ testName)
+
+def sliceBrokerLogs(resultDir, start, end):
+ sliceCPULog(resultDir, start, end)
+ sliceLog4j(resultDir, start, end)
+ sliceGCLog(resultDir, start, end)
+
+
+def sliceCPULog(resultDir, start, end):
+ global _brokerLogs
+ logfilePath=_brokerLogs+os.sep+BROKER_CPU_DATED
+ cpuSliceFile=resultDir+os.sep+BROKER_CPU
+
+ # Process the CPU log file and make a file of format:
+ # datetime <CPU% usage> <MEM% usage>
+ #
+ # Open log CPU file for reading
+ logFile = open(logfilePath, "r")
+
+ #
+ # Create outputfile
+ #
+ cpuslice = open(cpuSliceFile,"w")
+
+ for line in logFile:
+ data = line.split()
+ #
+ # //fixme remove tz addition.
+ #
+ lineTime = lineToDate(" ".join(data[0:2])+" +0000")
+
+ if lineTime > start:
+ if lineTime < end:
+ cpuslice.writelines(line)
+
+ logFile.close()
+ cpuslice.close()
+ log("Sliced CPU log")
+
+def sliceGCLog(resultDir, start, end):
+ global _brokerLogs
+ logfilePath=_brokerLogs+os.sep+BROKER_GC
+ sliceFile=resultDir+os.sep+BROKER_GC
+
+ gcstart = extractTime(ACCESS, logfilePath+".stat")
+
+ # Open log GC file for reading
+ logFile = open(logfilePath, "r")
+
+ # Open the output file, erasing any existing version
+ output= open(sliceFile, "w")
+
+ # Use a regular expression to pull out the Seconds.Millis values from the
+ # Start of the gc log line.
+ pattern = re.compile(r'(?P<seconds>^[0-9]+)\.(?P<millis>[0-9]+):')
+
+ for line in logFile:
+ m = pattern.match(line)
+
+ if m:
+ seconds = m.group('seconds');
+ millis = m.group('millis');
+
+ offset = timedelta(seconds=int(seconds),milliseconds=int(millis))
+
+ lineTime = gcstart + offset
+
+ if lineTime > start:
+ if lineTime < end:
+ output.writelines(line)
+
+ # Close the files
+ logFile.close
+ output.close()
+ log("Sliced gc log")
+
+
+def sliceLog4j(resultDir, start, end):
+ global _brokerLogs
+ logfilePath=_brokerLogs+os.sep+BROKER_LOG
+ log4jSliceFile=resultDir+os.sep+BROKER_LOG
+
+ log4jstart = extractTime(ACCESS, logfilePath+".stat")
+
+ #
+ # Say that first line is the start of the file,
+ # This value will give a time value to the initial
+ # logging before Log4j kicks in.
+ #
+ lineTime = log4jstart
+
+ # Process the broker log4j file
+ # Open log CPU file for reading
+ logFile = open(logfilePath, "r")
+
+ #
+ # Create outputfile
+ #
+ log4jslice = open(log4jSliceFile,"w")
+
+ for line in logFile:
+ data = line.split()
+
+ #
+ # If the line has a time at the start then process it
+ # otherwise use the previous time. This means if there is
+ # a stack trace in the middle of the log file then it will
+ # be copied over to the split file as long as it is in the
+ # split time.
+ #
+ if (hasTime(data)):
+ #
+ # //fixme remove tz addition.
+ #
+ lineTime = lineToDate(" ".join(data[0:2])+" +0000")
+
+ if lineTime > start:
+ if lineTime < end:
+ print line
+ log4jslice.writelines(line)
+
+ logFile.close()
+ log4jslice.close()
+ log("Sliced broker log")
+
+
+#
+# Check the first two entries of data can make a datetime object
+#
+def hasTime(data):
+ date = data[0]
+ time = data[1]
+
+ # Examples:
+ # 2009-06-22 17:04:44,246
+ # 2009-06-22 17:04:44.2464
+ # 2009-06-22 17:04:44
+
+ # ISO-8601 '-' format date
+ dateRE = re.compile('[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]')
+
+ #
+ # Check for times with/out millis
+ # e.g.
+ # 10:00:00,000 - log4j
+ # 10:00:00.0000 - generated in script for cpu time
+ #
+ timeRE = re.compile('[0-9][0-9]:[0-9][0-9]:[0-9][0-9]?[0-9]*')
+
+ return dateRE.match(date) and timeRE.match(time)
+
+
+def createGraphData(resultDir, testName):
+ # Create graph.data file for process.sh
+ # Format two lines : Title and filename
+ # $version $type : $volume% volume
+ # $version-$brokerState-$type-$volume
+ version=getBrokerVersion()
+
+ test= extractTestValue("n",resultDir, testName)
+ volume = int(float(extractTestResult("Test * Size Throughput", resultDir, testName)) * 1000)
+ messageSize = extractTestValue("messageSize",resultDir, testName)
+ ackMode = ackModeToString(extractTestValue("consAckMode",resultDir, testName))
+
+ graphDataFile=resultDir+os.sep+GRAPH_DATA
+
+ graphData = open(graphDataFile, "w")
+
+ #
+ # Write Title
+ graphData.write(version+":"+test+":"+str(messageSize)+"kb x "+str(volume)+" msg/sec using "+ackMode)
+ graphData.write('\n')
+
+ #
+ # Write FileName
+ graphData.writelines(version+"-"+testName)
+ graphData.write('\n')
+ graphData.close
+ log("Created graph.data")
+
+
+def getBrokerVersion():
+ global _brokerLogs
+ READY = "Qpid Broker Ready"
+ brokerLogFile = _brokerLogs + os.sep + BROKER_LOG
+
+ log = open(brokerLogFile, "r")
+
+ dataLine = ""
+ for line in log:
+ if line.find(READY) != -1:
+ dataLine = line
+ break
+
+ # Log Entry
+ #2009-06-19 17:04:02,493 INFO [main] server.Main (Main.java:456) - Qpid Broker Ready :2.3.0.1 build: 727403M
+ # Split on READY
+ data = dataLine.split(READY)
+
+ # So [1] should be
+ # :2.3.0.1 build: 727403M
+ readyEntries = data[1].split()
+
+ # so spliting on white space should give us ':version'
+ # and a quick split on ':' will give us the version
+ version = readyEntries[0].split(':')[1]
+
+ # Strip to ensure we have no whitespace
+ return version.strip()
+
+
+def extractTestValue(property,resultDir,testName):
+ return extractTestData(property,resultDir,testName," =")
+
+def extractTestResult(property,resultDir,testName):
+ return extractTestData(property,resultDir,testName,":")
+
+def extractTestData(property,resultDir,testName,type):
+ resultFile = resultDir + os.sep + testName+".csv"
+
+ results = open(resultFile, "r")
+
+ dataLine = ""
+ for line in results:
+ if line.find("Total Tests:") == 0:
+ dataLine = line
+
+ results.close()
+
+ # Data is CSV
+ data = dataLine.split(',')
+
+ found = False
+ result = ""
+ searchProperty = property+type
+
+ for entry in data:
+ if found:
+ result = entry
+ break
+ if entry.strip() == searchProperty:
+ found=True
+
+ return result.strip()
+
+
+def ackModeToString(ackMode):
+ if ackMode == '0':
+ return "Transacted"
+ elif ackMode == '1':
+ return "AutoAck"
+ elif ackMode == '2':
+ return "ClientAck"
+ elif ackMode == '3':
+ return "DupsOK"
+ elif ackMode == '257':
+ return "NoAck"
+ elif ackMode == '258':
+ return "PreAck"
+ else:
+ return str(ackMode)
+
+
+
+def debug(msg):
+ global _debug
+ if _debug:
+ log(msg)
+
+def log(msg):
+ print msg
+
+def mkdir(dir):
+ if not os.path.exists(dir):
+ os.mkdir(dir)
+
+if __name__ == "__main__":
+ main()
diff --git a/java/perftests/bin/topicListener.sh b/java/perftests/bin/topicListener.sh
index a728592cd7..3a925910ad 100755
--- a/java/perftests/bin/topicListener.sh
+++ b/java/perftests/bin/topicListener.sh
@@ -20,14 +20,13 @@
# XXX -Xmx512m -Xms512m -XX:NewSize=150m
-QPID_LIBS=$QPID_HOME/lib/qpid-incubating.jar
-TEST_JAR=$QPID_HOME/../../../../perftests/target/qpid-perftests-1.0-incubating-M2-SNAPSHOT.jar
+QPID_LIBS=$QPID_HOME/lib/qpid-all.jar
# Set other variables used by the qpid-run script before calling
export JAVA=java \
JAVA_VM=-server \
JAVA_MEM="-Xmx128m -Dlog4j.configuration=$HOME/log4j.properties" \
JAVA_GC="-XX:-UseConcMarkSweepGC -XX:+HeapDumpOnOutOfMemoryError" \
- QPID_CLASSPATH=$QPID_LIBS:$TEST_JAR
+ QPID_CLASSPATH=$QPID_LIBS
. qpid-run -Damqj.logging.level="INFO" org.apache.qpid.oldtopic.Listener $*
diff --git a/java/perftests/bin/topicPublisher.sh b/java/perftests/bin/topicPublisher.sh
index f9b6bc19fe..e4e9981a75 100755
--- a/java/perftests/bin/topicPublisher.sh
+++ b/java/perftests/bin/topicPublisher.sh
@@ -19,14 +19,13 @@
#
# XXX -Xmx512m -Xms512m -XX:NewSize=150m
-QPID_LIBS=$QPID_HOME/lib/qpid-incubating.jar
-TEST_JAR=$QPID_HOME/../../../../perftests/target/qpid-perftests-1.0-incubating-M2-SNAPSHOT.jar
+QPID_LIBS=$QPID_HOME/lib/qpid-all.jar
# Set other variables used by the qpid-run script before calling
export JAVA=java \
JAVA_VM=-server \
JAVA_MEM=-Xmx128m \
JAVA_GC="-XX:-UseConcMarkSweepGC -XX:+HeapDumpOnOutOfMemoryError" \
- QPID_CLASSPATH=$QPID_LIBS:$TEST_JAR
+ QPID_CLASSPATH=$QPID_LIBS
. qpid-run -Damqj.logging.level="INFO" org.apache.qpid.oldtopic.Publisher $*
diff --git a/java/perftests/build.xml b/java/perftests/build.xml
index 0288ef691e..b38201f5da 100644
--- a/java/perftests/build.xml
+++ b/java/perftests/build.xml
@@ -30,11 +30,23 @@
<property name="qpid.logging.level" value="-Damqj.logging.level=warn"/>
<property name="log4j.config" value="-Dlog4j.configuration=perftests.log4j"/>
<property name="properties" value="perftests.properties"/>
+ <property name="scripts.dir" value="${build.bin}/${module.name}"/>
<condition property="results" value="${result-path}/results" else="${project.root}/${module}/results">
<isset property="result-path"/>
</condition>
+ <target name="precompile">
+ <mkdir dir="${scripts.dir}"/>
+ <jython path="${mllib.dir}">
+ <args>
+ <arg value="generate-scripts"/>
+ <arg value="scripts.xml"/>
+ <arg value="${scripts.dir}"/>
+ </args>
+ </jython>
+ </target>
+
<target name="all-tests" depends="all-queue-tests,all-topic-tests"/>
<target name="all-queue-tests" depends="Queue-Duration-Persistent,Queue-Concurrent,
diff --git a/java/perftests/distribution/pom.xml b/java/perftests/distribution/pom.xml
deleted file mode 100644
index 739170ca75..0000000000
--- a/java/perftests/distribution/pom.xml
+++ /dev/null
@@ -1,131 +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.
- -->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-perftests-distribution</artifactId>
- <packaging>jar</packaging>
- <version>1.0-incubating-M2-SNAPSHOT</version>
- <name>Qpid Performance Tests Distribution</name>
- <url>http://cwiki.apache.org/confluence/display/qpid</url>
-
- <parent>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid</artifactId>
- <version>1.0-incubating-M2-SNAPSHOT</version>
- </parent>
-
- <properties>
- <topDirectoryLocation>..</topDirectoryLocation>
- <java.source.version>1.5</java.source.version>
- <qpid.version>${pom.version}</qpid.version>
- <qpid.targetDir>${project.build.directory}</qpid.targetDir>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-perftests</artifactId>
- <type>jar</type>
- <version>${pom.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-perftests</artifactId>
- <type>test-jar</type>
- <version>${pom.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>junit-toolkit</artifactId>
- <scope>runtime</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>junit-toolkit-maven-plugin</artifactId>
- <scope>runtime</scope>
- </dependency>
- </dependencies>
-
- <build>
- <pluginManagement>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>${java.source.version}</source>
- <target>${java.source.version}</target>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-assembly-plugin</artifactId>
- <version>${assembly.version}</version>
- <configuration>
- <descriptors>
- <descriptor>src/main/assembly/performance.xml</descriptor>
- </descriptors>
- <finalName>qpid-${pom.version}</finalName>
- <outputDirectory>${qpid.targetDir}</outputDirectory>
- <tarLongFileMode>gnu</tarLongFileMode>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <configuration>
- <finalName>qpid-performance</finalName>
- <archive>
- <manifest>
- <addClasspath>true</addClasspath>
- </manifest>
- </archive>
- </configuration>
- </plugin>
- </plugins>
- </pluginManagement>
-
- <plugins>
- <plugin>
- <artifactId>maven-assembly-plugin</artifactId>
- <executions>
- <execution>
- <id>distribution-package</id>
- <phase>package</phase>
- <goals>
- <goal>single</goal>
- </goals>
- <configuration>
- <descriptors>
- <descriptor>src/main/assembly/performance.xml</descriptor>
- </descriptors>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
-
- </build>
-
-</project>
diff --git a/java/perftests/distribution/src/main/assembly/performance.xml b/java/perftests/distribution/src/main/assembly/performance.xml
deleted file mode 100644
index a564261a24..0000000000
--- a/java/perftests/distribution/src/main/assembly/performance.xml
+++ /dev/null
@@ -1,103 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
--->
-<assembly>
- <id>performance-test-java</id>
- <includeBaseDirectory>false</includeBaseDirectory>
- <formats>
- <format>tar.gz</format>
- <format>zip</format>
- </formats>
-
- <fileSets>
- <!-- Apache Licensing -->
- <fileSet>
- <directory>../../resources</directory>
- <outputDirectory>qpid-${qpid.version}</outputDirectory>
- <includes>
- <include>DISCLAIMER</include>
- <include>LICENSE.txt</include>
- <include>NOTICE.txt</include>
- <include>README.txt</include>
- </includes>
- </fileSet>
-
- <fileSet>
- <directory>../../release-docs</directory>
- <outputDirectory>qpid-${qpid.version}/docs</outputDirectory>
- <includes>
- <include>RELEASE_NOTES.txt</include>
- </includes>
- </fileSet>
-
- <!-- Performance txt files-->
- <fileSet>
- <directory>..</directory>
- <outputDirectory>qpid-${qpid.version}</outputDirectory>
- <includes>
- <include>*.txt</include>
- </includes>
- </fileSet>
-
- <!-- Execution Scripts -->
- <fileSet>
- <directory>../bin</directory>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <includes>
- <include>*</include>
- </includes>
- <fileMode>777</fileMode>
- </fileSet>
-
- <!-- Provide Source in easy access location -->
- <fileSet>
- <directory>../src/main</directory>
- <outputDirectory>qpid-${qpid.version}/src</outputDirectory>
- <includes>
- <include>**/*.java</include>
- <include>**/*.log4j</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>../src/test</directory>
- <outputDirectory>qpid-${qpid.version}/src</outputDirectory>
- <includes>
- <include>**/*.java</include>
- </includes>
- </fileSet>
-
- <!-- Metadata Jar -->
- <fileSet>
- <directory>target</directory>
- <outputDirectory>qpid-${qpid.version}/lib</outputDirectory>
- <includes>
- <include>qpid-performance.jar</include>
- </includes>
- </fileSet>
- </fileSets>
- <dependencySets>
- <dependencySet>
- <outputDirectory>qpid-${qpid.version}/lib</outputDirectory>
- <unpack>false</unpack>
- <excludes>
- <exclude>org.apache.qpid:qpid-perftests-distribution</exclude>
- </excludes>
- </dependencySet>
- </dependencySets>
-</assembly>
diff --git a/java/perftests/etc/perftests.log4j b/java/perftests/etc/perftests.log4j
new file mode 100644
index 0000000000..af8c1b0784
--- /dev/null
+++ b/java/perftests/etc/perftests.log4j
@@ -0,0 +1,46 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+log4j.rootLogger=${root.logging.level}
+
+
+log4j.logger.org.apache.mina=${amqj.logging.level}
+
+log4j.logger.org.apache.qpid=${amqj.logging.level}, console
+log4j.additivity.org.apache.qpid=false
+
+log4j.logger.org.apache.qpid.requestreply=${amqj.test.logging.level}
+log4j.logger.org.apache.qpid.pingpong=${amqj.test.logging.level}
+log4j.logger.org.apache.qpid.ping=${amqj.test.logging.level}
+log4j.logger.org.apache.qpid.topic=${amqj.test.logging.level}
+
+log4j.logger.org.apache.qpid.junit.extensions=${badger.level}, console
+log4j.additivity.org.apache.qpid.junit.extensions=false
+
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.Threshold=all
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+
+log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n
+#log4j.appender.console.layout.ConversionPattern=%t %p [%c] %m%n
+
+log4j.appender.fileApp=org.apache.log4j.FileAppender
+log4j.appender.fileApp.file=${log.dir}/perftests.volumetest.log
+log4j.appender.fileApp.Threshold=info
+log4j.appender.fileApp.append=false
+log4j.appender.fileApp.layout=org.apache.log4j.PatternLayout
diff --git a/java/perftests/etc/scripts/Reliability.sh b/java/perftests/etc/scripts/Reliability.sh
index aa192743ed..9e5e508743 100755
--- a/java/perftests/etc/scripts/Reliability.sh
+++ b/java/perftests/etc/scripts/Reliability.sh
@@ -17,4 +17,4 @@
# specific language governing permissions and limitations
# under the License.
#
-find . -regex '.*R-Qpid-0[1-2].*\.sh' -exec {} -o results-Reliability/ --csv \; && for i in `seq 1 6` ; do find . -regex '.*R-Qpid-0[3-8].*\.sh' -exec {} -o results-Reliability/ --csv \; ; done
+find . -regex '.*R-Qpid-0[1-8].*\.sh' -exec {} -o results-Reliability/ --csv \;
diff --git a/java/perftests/etc/scripts/RunAll.sh b/java/perftests/etc/scripts/RunAll.sh
index 60c04e3ed7..8b0d8b6e7c 100755
--- a/java/perftests/etc/scripts/RunAll.sh
+++ b/java/perftests/etc/scripts/RunAll.sh
@@ -17,9 +17,7 @@
# specific language governing permissions and limitations
# under the License.
#
-Connections.sh && \
-JobQueue.sh && \
-Latency.sh && \
-MessageSize.sh && \
-Reliability.sh && \
-Throughput.sh
+./RunCore.sh
+./Connections.sh
+./JobQueue.sh
+./MessageSize.sh
diff --git a/java/perftests/etc/scripts/RunCore.sh b/java/perftests/etc/scripts/RunCore.sh
new file mode 100755
index 0000000000..fcc45aacf0
--- /dev/null
+++ b/java/perftests/etc/scripts/RunCore.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+./Throughput.sh
+./Latency.sh
+./Reliability.sh
diff --git a/java/perftests/etc/scripts/extractResults.sh b/java/perftests/etc/scripts/extractResults.sh
new file mode 100755
index 0000000000..95aff9edba
--- /dev/null
+++ b/java/perftests/etc/scripts/extractResults.sh
@@ -0,0 +1,13 @@
+#!/bin/bash +x
+#
+# Process a given directory (defaults to '.') and provide a list of the tests run so
+# identification of any failures can be seen.
+#
+
+if [ $# == 0 ] ; then
+ dir=.
+else
+ dir=$1
+fi
+
+grep 'Total Tests:' $dir/*Qpid* | sed -e 's/^.*\/\([A-Z\-]*-Qpid-[0-9]*\).*Total Tests:, \([0-9.]*\).*Total Passed:, \([0-9.]*\).*Total Failed:, \([0-9.]*\).*Total Error:, \([0-9.]*\).*$/\1, Total:\t\2,\tPassed:\t\3,\tFailed:\t\4,\tError:\t\5/'
diff --git a/java/perftests/etc/scripts/extractThroughputResults.sh b/java/perftests/etc/scripts/extractThroughputResults.sh
new file mode 100755
index 0000000000..e85286ea3e
--- /dev/null
+++ b/java/perftests/etc/scripts/extractThroughputResults.sh
@@ -0,0 +1,30 @@
+#!/bin/bash +x
+#
+# Process a given directory (defaults to '.') and provides the throughput results as
+# reported by the tests.
+#
+# if a second argument of -n is provided then it will only list the number output for
+# easy copy/paste
+#
+
+if [ $# == 0 ] ; then
+ dir=.
+else
+ dir=$1
+fi
+
+numeric=0
+if [ "$dir" == "-n" ] ; then
+ numeric=1
+ dir=.
+fi
+
+if [ "$2" == "-n" ] ; then
+ numeric=1
+fi
+
+if [ $numeric == 1 ] ; then
+ grep 'Total Tests:' $dir/*Qpid* | sed -e 's/^.*\/\([A-Z]*-[A-Z][A-Z]-Qpid-01\).*Size Throughput:, \([0-9.]*\).*$/\1, \2/' | sed -e 's/\.\([0-9][0-9][0-9]\)/\1\./' | sed -e 's/, 0/, /' | awk '{print $2}'
+else
+ grep 'Total Tests:' $dir/*Qpid* | sed -e 's/^.*\/\([A-Z]*-[A-Z][A-Z]-Qpid-01\).*Size Throughput:, \([0-9.]*\).*$/\1, \2/' | sed -e 's/\.\([0-9][0-9][0-9]\)/\1\./' | sed -e 's/, 0/, /'
+fi
diff --git a/java/perftests/generate-scripts b/java/perftests/generate-scripts
new file mode 100644
index 0000000000..3d12cc13c3
--- /dev/null
+++ b/java/perftests/generate-scripts
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import os, sys, mllib
+
+template = """#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+if [ -z "$QPID_HOME" ]; then
+ export QPID_HOME=$(dirname $(dirname $(dirname $(readlink -f $0))))
+ export PATH=${PATH}:${QPID_HOME}/bin
+fi
+
+# Parse arguements taking all - prefixed args as JAVA_OPTS
+for arg in "$@"; do
+ if [[ $arg == -java:* ]]; then
+ JAVA_OPTS="${JAVA_OPTS}-`echo $arg|cut -d ':' -f 2` "
+ else
+ ARGS="${ARGS}$arg "
+ fi
+done
+
+# Set classpath to include Qpid jar with all required jars in manifest
+QPID_LIBS=$QPID_HOME/lib/qpid-all.jar
+
+# Set other variables used by the qpid-run script before calling
+export JAVA=java \
+ JAVA_VM=-server \
+ JAVA_MEM=-Xmx1024m \
+ QPID_CLASSPATH=$QPID_LIBS
+
+. qpid-run -Xms256m -Dlog4j.configuration=file://${QPID_HOME}/etc/perftests.log4j -Dbadger.level=warn -Damqj.test.logging.level=info -Damqj.logging.level=warn org.apache.qpid.junit.extensions.TKTestRunner %s ${ARGS}
+"""
+
+doc = mllib.xml_parse(sys.argv[1])
+dir = sys.argv[2]
+for s in doc.query["scripts/script"]:
+ file = open(os.path.join(dir, "%s.sh" % s["@name"]), "w")
+ file.write(template % s.text())
+ file.close()
diff --git a/java/perftests/pom.xml b/java/perftests/pom.xml
deleted file mode 100644
index 44af699d99..0000000000
--- a/java/perftests/pom.xml
+++ /dev/null
@@ -1,562 +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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-perftests</artifactId>
- <packaging>jar</packaging>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <name>Qpid Performance Tests</name>
- <url>http://cwiki.apache.org/confluence/display/qpid</url>
-
- <parent>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid</artifactId>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <relativePath>../pom.xml</relativePath>
- </parent>
-
- <properties>
- <topDirectoryLocation>..</topDirectoryLocation>
- <log4j.perftests>perftests.log4j</log4j.perftests>
- </properties>
-
- <!-- Temporary local maven repo, whilst JUnit Toolkit is still reaching stable version to add to central maven repository. -->
- <repositories>
- <repository>
- <id>junit-toolkit.snapshots</id>
- <name>JUnit Toolkit SNAPSHOT Repository</name>
- <url>http://junit-toolkit.svn.sourceforge.net/svnroot/junit-toolkit/snapshots/</url>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- </repository>
- </repositories>
-
- <!-- Temporary local maven repo, whilst JUnit Toolkit is still reaching stable version to add to central maven repository. -->
- <pluginRepositories>
- <pluginRepository>
- <id>junit-toolkit-plugin.snapshots</id>
- <name>JUnit Toolkit SNAPSHOT Repository</name>
- <url>http://junit-toolkit.svn.sourceforge.net/svnroot/junit-toolkit/snapshots/</url>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- </pluginRepository>
- </pluginRepositories>
-
- <dependencies>
-
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-client</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-systests</artifactId>
- </dependency>
-
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>junit-toolkit</artifactId>
- </dependency>
-
- <!-- Test dependencies. -->
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>compile</scope>
- </dependency>
-
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.4.0</version>
- </dependency>
-
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-antrun-plugin</artifactId>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- </plugin>
-
- <!-- The JUnit Toolkit maven2 plugin is in the process of being added to the maven repository.
-
- Configures the toolkit test runner for performance testing. These can be run from within maven, or by using the generated
- scripts.
-
- To run from within maven:
-
- mvn org.apache.qpid:junit-toolkit-maven-plugin:tktest
-
- To run from the command line (after doing assembly:assembly goal):
-
- java -cp target/test_jar-jar-with-dependencies.jar org.apache.qpid.junit.extensions.TKTestRunner -s 1 -r 100000
- -o target org.apache.qpid.requestreply.PingPongTestPerf
-
- To generate the scripts do:
-
- mvn org.apache.qpid:junit-toolkit-maven-plugin:tkscriptgen
-
- Then to run the scripts, in the target directory do (after doing assembly:assembly goal):
-
- ./script_name.sh
-
- These scripts can find everything in the 'all test dependencies' jar created by the assembly:assembly goal.
- -->
- <plugin>
- <groupId>org.apache.qpid</groupId>
- <artifactId>junit-toolkit-maven-plugin</artifactId>
-
- <configuration>
- <scriptOutDirectory>target</scriptOutDirectory>
- <testJar>${project.build.finalName}.jar</testJar>
- <systemproperties>
- <property>
- <name>-Xms</name>
- <value>256m</value>
- </property>
- <property>
- <name>-Xmx</name>
- <value>1024m</value>
- </property>
- <property>
- <name>log4j.configuration</name>
- <value>${log4j.perftests}</value>
- </property>
- <property>
- <name>amqj.logging.level</name>
- <value>warn</value>
- </property>
- <property><!-- Turn off most logging messages from the junit-toolkit test tool itself. -->
- <name>badger.level</name>
- <value>warn</value>
- </property>
- <property>
- <name>amqj.test.logging.level</name>
- <value>info</value>
- </property>
- </systemproperties>
-
- <commands>
- <!-- Single pings. These can be scaled up by overriding the parameters when calling the test script. -->
- <Ping-Once>-n Ping-Once -s[1] -r 1 -t testPingOk -o . org.apache.qpid.ping.PingTestPerf</Ping-Once>
- <Ping-Once-Async>-n Ping-Once-Async -s[1] -r 1 -t testAsyncPingOk -o . org.apache.qpid.ping.PingAsyncTestPerf</Ping-Once-Async>
- <Ping-Latency>-n Ping-Latency -s[1000] -d10S -t testPingLatency -o . org.apache.qpid.ping.PingLatencyTestPerf rate=100 batchSize=100</Ping-Latency>
-
- <!-- More example Tests. These are examples to exercise all the features of the test harness. Can scale up with option overrides. -->
- <Ping-Tx>-n Ping-Tx -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf transacted=true</Ping-Tx>
- <Ping-Size>-n Ping-Size -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=512</Ping-Size>
- <Ping-Concurrent>-n Ping-Concurrent -s[100] -c [4] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf</Ping-Concurrent>
- <Ping-Many-Queues>-n Ping-Many-Queues -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf destinationCount=4</Ping-Many-Queues>
- <Ping-Duration>-n Ping-Duration -s[100] -d10S -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf</Ping-Duration>
- <Ping-Rate>-n Ping-Rate -s[100] -d10S -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf rate=500</Ping-Rate>
- <Ping-PubSub>-n Ping-PubSub -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true</Ping-PubSub>
- <Ping-Many-Topics>-n Ping-Many-Topics -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true destinationCount=4</Ping-Many-Topics>
- <Ping-Persistent>-n Ping-Persistent -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true</Ping-Persistent>
- <Ping-Batch-Logging>-n Ping-Batch-Logging -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf batchSize=10</Ping-Batch-Logging>
- <Ping-Failover-Before-Send>-n Ping-Failover-Before-Send -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf commitBatchSize=10 failBeforeSend=true</Ping-Failover-Before-Send>
- <Ping-Failover-After-Send>-n Ping-Failover-After-Send -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf commitBatchSize=10 failAfterSend=true</Ping-Failover-After-Send>
- <Ping-Failover-Before-Commit>-n Ping-Failover-Before-Commit -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf commitBatchSize=10 failBeforeCommit=true</Ping-Failover-Before-Commit>
- <Ping-Failover-After-Commit>-n Ping-Failover-After-Commit -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf commitBatchSize=10 failAfterCommit=true</Ping-Failover-After-Commit>
-
- <!--
- ***** If editing below, please use a non line wrapping mode and keep in columns, makes it easier to check for consistent
- ***** parameter setting accross all of the tests.
- -->
-
- <!--
- Reliability tests. The longer these tests can be run, the better.
- Tests 01 and 02 run for a short time. Use these to get an idea of the expected throughput.
- Tests 03 to 08 test all ack modes, transient/persistent, p2p/pubsub. There are 24 tests in total running for 1 hour each.
- This can be shortened or lengthened for the desired burn-in test time.
- -->
- <TQR-Qpid-01>-n TQR-Qpid-01 -d1M -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </TQR-Qpid-01>
- <TQR-Qpid-02>-n TQR-Qpid-02 -d1M -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </TQR-Qpid-02>
- <TTR-Qpid-01>-n TTR-Qpid-01 -d1M -s[100] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </TTR-Qpid-01>
- <TTR-Qpid-02>-n TTR-Qpid-02 -d1M -s[100] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </TTR-Qpid-02>
- <PQR-Qpid-01>-n PQR-Qpid-01 -d1M -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </PQR-Qpid-01>
- <PQR-Qpid-02>-n PQR-Qpid-02 -d1M -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </PQR-Qpid-02>
- <PTR-Qpid-01>-n PTR-Qpid-01 -d1M -s[100] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=8 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </PTR-Qpid-01>
- <PTR-Qpid-02>-n PTR-Qpid-02 -d1M -s[100] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </PTR-Qpid-02>
-
- <TQR-Qpid-03-TX>-n TQR-Qpid-03 -d1H -s[10000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </TQR-Qpid-03-TX>
- <TQR-Qpid-04-AUTOACK>-n TQR-Qpid-04 -d1H -s[10000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </TQR-Qpid-04-AUTOACK>
- <TQR-Qpid-05-CLIENTACK>-n TQR-Qpid-05 -d1H -s[10000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=2 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </TQR-Qpid-05-CLIENTACK>
- <TQR-Qpid-06-DUPSOKACK>-n TQR-Qpid-06 -d1H -s[10000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=3 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </TQR-Qpid-06-DUPSOKACK>
- <TQR-Qpid-07-NOACK>-n TQR-Qpid-07 -d1H -s[10000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=257 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </TQR-Qpid-07-NOACK>
- <TQR-Qpid-08-PREACK>-n TQR-Qpid-08 -d1H -s[10000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=258 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </TQR-Qpid-08-PREACK>
-
- <TTR-Qpid-03-TX>-n TTR-Qpid-03 -d1H -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </TTR-Qpid-03-TX>
- <TTR-Qpid-04-AUTOACK>-n TTR-Qpid-04 -d1H -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </TTR-Qpid-04-AUTOACK>
- <TTR-Qpid-05-CLIENTACK>-n TTR-Qpid-05 -d1H -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=2 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </TTR-Qpid-05-CLIENTACK>
- <TTR-Qpid-06-DUPSOKACK>-n TTR-Qpid-06 -d1H -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=3 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </TTR-Qpid-06-DUPSOKACK>
- <TTR-Qpid-07-NOACK>-n TTR-Qpid-07 -d1H -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=257 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </TTR-Qpid-07-NOACK>
- <TTR-Qpid-08-PREACK>-n TTR-Qpid-08 -d1H -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=258 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </TTR-Qpid-08-PREACK>
-
- <PQR-Qpid-03-TX>-n PQR-Qpid-03 -d1H -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </PQR-Qpid-03-TX>
- <PQR-Qpid-04-AUTOACK>-n PQR-Qpid-04 -d1H -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </PQR-Qpid-04-AUTOACK>
- <PQR-Qpid-05-CLIENTACK>-n PQR-Qpid-05 -d1H -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=2 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </PQR-Qpid-05-CLIENTACK>
- <PQR-Qpid-06-DUPSOKACK>-n PQR-Qpid-06 -d1H -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=3 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </PQR-Qpid-06-DUPSOKACK>
- <PQR-Qpid-07-NOACK>-n PQR-Qpid-07 -d1H -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=257 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </PQR-Qpid-07-NOACK>
- <PQR-Qpid-08-PREACK>-n PQR-Qpid-08 -d1H -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=258 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </PQR-Qpid-08-PREACK>
-
- <PTR-Qpid-03-TX>-n PTR-Qpid-03 -d1H -s[100] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=8 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </PTR-Qpid-03-TX>
- <PTR-Qpid-04-AUTOACK>-n PTR-Qpid-04 -d1H -s[100] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </PTR-Qpid-04-AUTOACK>
- <PTR-Qpid-05-CLIENTACK>-n PTR-Qpid-05 -d1H -s[100] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=2 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </PTR-Qpid-05-CLIENTACK>
- <PTR-Qpid-06-DUPSOKACK>-n PTR-Qpid-06 -d1H -s[100] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=3 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </PTR-Qpid-06-DUPSOKACK>
- <PTR-Qpid-07-NOACK>-n PTR-Qpid-07 -d1H -s[100] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=257 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </PTR-Qpid-07-NOACK>
- <PTR-Qpid-08-PREACK>-n PTR-Qpid-08 -d1H -s[100] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=258 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </PTR-Qpid-08-PREACK>
-
- <!-- Performance Tests. -->
-
- <!-- Transient, P2P Tests -->
- <!-- Concurrency Tests : What are the effects of increasing consumers from 1...30 consumers -->
- <TQCT-Qpid-01>-n TQCT-Qpid-01 -d1M -s[1000] -c[1:30]:samples=30 -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=2000 maxPending=2000000 </TQCT-Qpid-01>
- <TQCT-Qpid-02>-n TQCT-Qpid-02 -d1M -s[1000] -c[1:30]:samples=30 -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=2000 maxPending=2000000 </TQCT-Qpid-02>
- <!-- Latency Tests : What are the effects on latency of increasing consumers from 1...30 consumers -->
- <TQCL-Qpid-01>-n TQCL-Qpid-01 -d1M -s[1000] -c[1:30]:samples=30 -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=2000 maxPending=2000000 </TQCL-Qpid-01>
- <TQCL-Qpid-02>-n TQCL-Qpid-02 -d1M -s[1000] -c[1:30]:samples=30 -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=2000 maxPending=2000000 </TQCL-Qpid-02>
-
- <!-- <TQC-Qpid-05>-n TQC-Qpid-05 -d10M -s[10] -c[100] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=10 rate=0 maxPending=100000 </TQC-Qpid-05> -->
- <!-- <TQC-Qpid-06>-n TQC-Qpid-06 -d10M -s[10] -c[100] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=10 rate=0 maxPending=100000 </TQC-Qpid-06> -->
-
-
- <!-- Message Size Tests : Tests sending message from 512b upto 1M with Point to Point messaging -->
- <TQM-Qpid-01-512b>-n TQM-Qpid-01-512b -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=512 destinationCount=1 rate=0 maxPending=2000000 </TQM-Qpid-01-512b>
- <TQM-Qpid-02-512b>-n TQM-Qpid-02-512b -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=512 destinationCount=1 rate=0 maxPending=2000000 </TQM-Qpid-02-512b>
- <TQM-Qpid-01-1K>-n TQM-Qpid-01-1K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=1024 destinationCount=1 rate=0 maxPending=2000000 </TQM-Qpid-01-1K>
- <TQM-Qpid-02-1K>-n TQM-Qpid-02-1K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=1024 destinationCount=1 rate=0 maxPending=2000000 </TQM-Qpid-02-1K>
- <TQM-Qpid-01-5K>-n TQM-Qpid-01-5K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=5120 destinationCount=1 rate=0 maxPending=2000000 </TQM-Qpid-01-5K>
- <TQM-Qpid-02-5K>-n TQM-Qpid-02-5K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=5120 destinationCount=1 rate=0 maxPending=2000000 </TQM-Qpid-02-5K>
- <TQM-Qpid-01-10K>-n TQM-Qpid-01-10K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=10240 destinationCount=1 rate=0 maxPending=2000000 </TQM-Qpid-01-10K>
- <TQM-Qpid-02-10K>-n TQM-Qpid-02-10K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=10240 destinationCount=1 rate=0 maxPending=2000000 </TQM-Qpid-02-10K>
- <TQM-Qpid-01-50K>-n TQM-Qpid-01-50K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=51200 destinationCount=1 rate=0 maxPending=100000000</TQM-Qpid-01-50K>
- <TQM-Qpid-02-50K>-n TQM-Qpid-02-50K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=51200 destinationCount=1 rate=0 maxPending=100000000</TQM-Qpid-02-50K>
- <TQM-Qpid-01-100K>-n TQM-Qpid-01-100K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=102400 destinationCount=1 rate=0 maxPending=100000000</TQM-Qpid-01-100K>
- <TQM-Qpid-02-100K>-n TQM-Qpid-02-100K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=102400 destinationCount=1 rate=0 maxPending=100000000</TQM-Qpid-02-100K>
- <TQM-Qpid-01-500K>-n TQM-Qpid-01-500K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=512000 destinationCount=1 rate=0 maxPending=100000000</TQM-Qpid-01-500K>
- <TQM-Qpid-02-500K>-n TQM-Qpid-02-500K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=512000 destinationCount=1 rate=0 maxPending=100000000</TQM-Qpid-02-500K>
- <TQM-Qpid-01-1M>-n TQM-Qpid-01-1M -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=1048576 destinationCount=1 rate=0 maxPending=100000000</TQM-Qpid-01-1M>
- <TQM-Qpid-02-1M>-n TQM-Qpid-02-1M -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=1048576 destinationCount=1 rate=0 maxPending=100000000</TQM-Qpid-02-1M>
-
- <!-- Transient, Pub/Sub Tests -->
- <!-- Concurrency Tests : What are the effects of increasing consumers from 1...30 consumers -->
- <TTCT-Qpid-01>-n TTCT-Qpid-01 -d1M -s[10] -c[1:30]:samples=30 -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=40 maxPending=2000000 </TTCT-Qpid-01>
- <TTCT-Qpid-02>-n TTCT-Qpid-02 -d1M -s[10] -c[1:30]:samples=30 -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=40 maxPending=2000000 </TTCT-Qpid-02>
- <!-- Latency Tests : What are the effects on latency of increasing consumers from 1...30 consumers -->
- <TTCL-Qpid-01>-n TTCL-Qpid-01 -d1M -s[10] -c[1:30]:samples=30 -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=40 maxPending=2000000 </TTCL-Qpid-01>
- <TTCL-Qpid-02>-n TTCL-Qpid-02 -d1M -s[10] -c[1:30]:samples=30 -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=40 maxPending=2000000 </TTCL-Qpid-02>
-
- <!-- <TTC-Qpid-05>-n TTC-Qpid-05 -d10M -s[10] -c[100] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=10 rate=0 maxPending=100000 </TTC-Qpid-05> -->
- <!-- <TTC-Qpid-06>-n TTC-Qpid-06 -d10M -s[10] -c[100] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=10 rate=0 maxPending=100000 </TTC-Qpid-06> -->
-
- <!-- Message Size Tests : Tests sending message from 512b upto 1M with Point to Point messaging -->
- <TTM-Qpid-01-512b>-n TTM-Qpid-01-512b -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=512 destinationCount=1 rate=0 maxPending=2000000 </TTM-Qpid-01-512b>
- <TTM-Qpid-02-512b>-n TTM-Qpid-02-512b -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=512 destinationCount=1 rate=0 maxPending=2000000 </TTM-Qpid-02-512b>
- <TTM-Qpid-01-1K>-n TTM-Qpid-01-1K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=1024 destinationCount=1 rate=0 maxPending=2000000 </TTM-Qpid-01-1K>
- <TTM-Qpid-02-1K>-n TTM-Qpid-02-1K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=1024 destinationCount=1 rate=0 maxPending=2000000 </TTM-Qpid-02-1K>
- <TTM-Qpid-01-5K>-n TTM-Qpid-01-5K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=5120 destinationCount=1 rate=0 maxPending=2000000 </TTM-Qpid-01-5K>
- <TTM-Qpid-02-5K>-n TTM-Qpid-02-5K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=5120 destinationCount=1 rate=0 maxPending=2000000 </TTM-Qpid-02-5K>
- <TTM-Qpid-01-10K>-n TTM-Qpid-01-10K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=10240 destinationCount=1 rate=0 maxPending=2000000 </TTM-Qpid-01-10K>
- <TTM-Qpid-02-10K>-n TTM-Qpid-02-10K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=10240 destinationCount=1 rate=0 maxPending=2000000 </TTM-Qpid-02-10K>
- <TTM-Qpid-01-50K>-n TTM-Qpid-01-50K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=51200 destinationCount=1 rate=0 maxPending=20000000</TTM-Qpid-01-50K>
- <TTM-Qpid-02-50K>-n TTM-Qpid-02-50K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=51200 destinationCount=1 rate=0 maxPending=20000000</TTM-Qpid-02-50K>
- <TTM-Qpid-01-100K>-n TTM-Qpid-01-100K -d10M -s[40] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=102400 destinationCount=1 rate=0 maxPending=20000000</TTM-Qpid-01-100K>
- <TTM-Qpid-02-100K>-n TTM-Qpid-02-100K -d10M -s[40] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=102400 destinationCount=1 rate=0 maxPending=20000000</TTM-Qpid-02-100K>
- <TTM-Qpid-01-500K>-n TTM-Qpid-01-500K -d10M -s[8] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=512000 destinationCount=1 rate=0 maxPending=20000000</TTM-Qpid-01-500K>
- <TTM-Qpid-02-500K>-n TTM-Qpid-02-500K -d10M -s[8] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=512000 destinationCount=1 rate=0 maxPending=20000000</TTM-Qpid-02-500K>
- <TTM-Qpid-01-1M>-n TTM-Qpid-01-1M -d10M -s[4] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=1048576 destinationCount=1 rate=0 maxPending=20000000</TTM-Qpid-01-1M>
- <TTM-Qpid-02-1M>-n TTM-Qpid-02-1M -d10M -s[4] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=1048476 destinationCount=1 rate=0 maxPending=20000000</TTM-Qpid-02-1M>
-
- <!-- Persistent, P2P Tests -->
- <!-- Concurrency Tests : What are the effects of increasing consumers from 1...30 consumers -->
- <PQCT-Qpid-01>-n PQCT-Qpid-01 -d1M -s[1000] -c[1:30]:samples=30 -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=600 maxPending=2000000 </PQCT-Qpid-01>
- <PQCT-Qpid-02>-n PQCT-Qpid-02 -d1M -s[1000] -c[1:30]:samples=30 -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=100 maxPending=2000000 </PQCT-Qpid-02>
- <!-- Latency Tests : What are the effects on latency of increasing consumers from 1...30 consumers -->
- <PQCL-Qpid-01>-n PQCL-Qpid-01 -d1M -s[1000] -c[1:30]:samples=30 -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=600 maxPending=2000000 </PQCL-Qpid-01>
- <PQCL-Qpid-02>-n PQCL-Qpid-02 -d1M -s[1000] -c[1:30]:samples=30 -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=100 maxPending=2000000 </PQCL-Qpid-02>
-
- <!-- <PQC-Qpid-05>-n PQC-Qpid-05 -d10M -s[10] -c[100] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=10 rate=0 maxPending=100000 </PQC-Qpid-05> -->
- <!-- <PQC-Qpid-06>-n PQC-Qpid-06 -d10M -s[10] -c[100] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=10 rate=0 maxPending=100000 </PQC-Qpid-06> -->
-
- <!-- Message Size Tests : Tests sending message from 512b upto 1M with Point to Point messaging -->
- <PQM-Qpid-01-512b>-n PQM-Qpid-01-512b -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=512 destinationCount=1 rate=0 maxPending=2000000 </PQM-Qpid-01-512b>
- <PQM-Qpid-02-512b>-n PQM-Qpid-02-512b -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=512 destinationCount=1 rate=0 maxPending=2000000 </PQM-Qpid-02-512b>
- <PQM-Qpid-01-1K>-n PQM-Qpid-01-1K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=1024 destinationCount=1 rate=0 maxPending=2000000 </PQM-Qpid-01-1K>
- <PQM-Qpid-02-1K>-n PQM-Qpid-02-1K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=1024 destinationCount=1 rate=0 maxPending=2000000 </PQM-Qpid-02-1K>
- <PQM-Qpid-01-5K>-n PQM-Qpid-01-5K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=5120 destinationCount=1 rate=0 maxPending=2000000 </PQM-Qpid-01-5K>
- <PQM-Qpid-02-5K>-n PQM-Qpid-02-5K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=5120 destinationCount=1 rate=0 maxPending=2000000 </PQM-Qpid-02-5K>
- <PQM-Qpid-01-10K>-n PQM-Qpid-01-10K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=10240 destinationCount=1 rate=0 maxPending=2000000 </PQM-Qpid-01-10K>
- <PQM-Qpid-02-10K>-n PQM-Qpid-02-10K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=10240 destinationCount=1 rate=0 maxPending=2000000 </PQM-Qpid-02-10K>
- <PQM-Qpid-01-50K>-n PQM-Qpid-01-50K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=51200 destinationCount=1 rate=0 maxPending=20000000</PQM-Qpid-01-50K>
- <PQM-Qpid-02-50K>-n PQM-Qpid-02-50K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=51200 destinationCount=1 rate=0 maxPending=20000000</PQM-Qpid-02-50K>
- <PQM-Qpid-01-100K>-n PQM-Qpid-01-100K -d10M -s[40] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=102400 destinationCount=1 rate=0 maxPending=20000000</PQM-Qpid-01-100K>
- <PQM-Qpid-02-100K>-n PQM-Qpid-02-100K -d10M -s[40] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=102400 destinationCount=1 rate=0 maxPending=20000000</PQM-Qpid-02-100K>
- <PQM-Qpid-01-500K>-n PQM-Qpid-01-500K -d10M -s[8] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=512000 destinationCount=1 rate=0 maxPending=20000000</PQM-Qpid-01-500K>
- <PQM-Qpid-02-500K>-n PQM-Qpid-02-500K -d10M -s[8] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=512000 destinationCount=1 rate=0 maxPending=20000000</PQM-Qpid-02-500K>
- <PQM-Qpid-01-1M>-n PQM-Qpid-01-1M -d10M -s[4] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=1048576 destinationCount=1 rate=0 maxPending=20000000</PQM-Qpid-01-1M>
- <PQM-Qpid-02-1M>-n PQM-Qpid-02-1M -d10M -s[4] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=1048576 destinationCount=1 rate=0 maxPending=20000000</PQM-Qpid-02-1M>
-
- <!-- Persistent, Pub/Sub Tests -->
- <PTCT-Qpid-01>-n PTCT-Qpid-01 -d1M -s[1] -c[1:30]:samples=30 -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=1 maxPending=2000000 </PTCT-Qpid-01>
- <PTCT-Qpid-02>-n PTCT-Qpid-02 -d1M -s[1] -c[1:30]:samples=30 -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=1 maxPending=2000000 </PTCT-Qpid-02>
- <PTCL-Qpid-01>-n PTCL-Qpid-01 -d1M -s[1] -c[1:30]:samples=30 -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=1 maxPending=2000000 </PTCL-Qpid-01>
- <PTCL-Qpid-02>-n PTCL-Qpid-02 -d1M -s[1] -c[1:30]:samples=30 -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=1 maxPending=2000000 </PTCL-Qpid-02>
-
- <!-- <PTC-Qpid-05>-n PTC-Qpid-05 -d10M -s[10] -c[100] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=10 rate=0 maxPending=100000 </PTC-Qpid-05> -->
- <!-- <PTC-Qpid-06>-n PTC-Qpid-06 -d10M -s[10] -c[100] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=10 rate=0 maxPending=100000 </PTC-Qpid-06> -->
-
- <PTM-Qpid-01-512b>-n PTM-Qpid-01-512b -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=512 destinationCount=1 rate=0 maxPending=2000000 </PTM-Qpid-01-512b>
- <PTM-Qpid-02-512b>-n PTM-Qpid-02-512b -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=512 destinationCount=1 rate=0 maxPending=2000000 </PTM-Qpid-02-512b>
- <PTM-Qpid-01-1K>-n PTM-Qpid-01-1K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=1024 destinationCount=1 rate=0 maxPending=2000000 </PTM-Qpid-01-1K>
- <PTM-Qpid-02-1K>-n PTM-Qpid-02-1K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=1024 destinationCount=1 rate=0 maxPending=2000000 </PTM-Qpid-02-1K>
- <PTM-Qpid-01-5K>-n PTM-Qpid-01-5K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=5120 destinationCount=1 rate=0 maxPending=2000000 </PTM-Qpid-01-5K>
- <PTM-Qpid-02-5K>-n PTM-Qpid-02-5K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=5120 destinationCount=1 rate=0 maxPending=2000000 </PTM-Qpid-02-5K>
- <PTM-Qpid-01-10K>-n PTM-Qpid-01-10K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=10240 destinationCount=1 rate=0 maxPending=2000000 </PTM-Qpid-01-10K>
- <PTM-Qpid-02-10K>-n PTM-Qpid-02-10K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=10240 destinationCount=1 rate=0 maxPending=2000000 </PTM-Qpid-02-10K>
- <PTM-Qpid-01-50K>-n PTM-Qpid-01-50K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=51200 destinationCount=1 rate=0 maxPending=20000000</PTM-Qpid-01-50K>
- <PTM-Qpid-02-50K>-n PTM-Qpid-02-50K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=51200 destinationCount=1 rate=0 maxPending=20000000</PTM-Qpid-02-50K>
- <PTM-Qpid-01-100K>-n PTM-Qpid-01-100K -d10M -s[40] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=102400 destinationCount=1 rate=0 maxPending=20000000</PTM-Qpid-01-100K>
- <PTM-Qpid-02-100K>-n PTM-Qpid-02-100K -d10M -s[40] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=102400 destinationCount=1 rate=0 maxPending=20000000</PTM-Qpid-02-100K>
- <PTM-Qpid-01-500K>-n PTM-Qpid-01-500K -d10M -s[8] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=512000 destinationCount=1 rate=0 maxPending=20000000</PTM-Qpid-01-500K>
- <PTM-Qpid-02-500K>-n PTM-Qpid-02-500K -d10M -s[8] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=512000 destinationCount=1 rate=0 maxPending=20000000</PTM-Qpid-02-500K>
- <PTM-Qpid-01-1M>-n PTM-Qpid-01-1M -d10M -s[4] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=1048576 destinationCount=1 rate=0 maxPending=20000000</PTM-Qpid-01-1M>
- <PTM-Qpid-02-1M>-n PTM-Qpid-02-1M -d10M -s[4] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=1048476 destinationCount=1 rate=0 maxPending=20000000</PTM-Qpid-02-1M>
-
- <!-- Benchmarking tests. -->
- <!-- Throughput. -->
- <TQBT-TX-Qpid-01>-n TQBT-TX-Qpid-01 -d10M -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=1 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=2000000 </TQBT-TX-Qpid-01>
- <TQBT-AA-Qpid-01>-n TQBT-AA-Qpid-01 -d10M -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=2000000 </TQBT-AA-Qpid-01>
- <TQBT-NA-Qpid-01>-n TQBT-NA-Qpid-01 -d10M -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=2000000 </TQBT-NA-Qpid-01>
- <TTBT-TX-Qpid-01>-n TTBT-TX-Qpid-01 -d10M -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=true consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=2000000 </TTBT-TX-Qpid-01>
- <TTBT-AA-Qpid-01>-n TTBT-AA-Qpid-01 -d10M -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=2000000 </TTBT-AA-Qpid-01>
- <TTBT-NA-Qpid-01>-n TTBT-NA-Qpid-01 -d10M -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=2000000 </TTBT-NA-Qpid-01>
-
- <PQBT-TX-Qpid-01>-n PQBT-TX-Qpid-01 -d10M -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=1 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=2000000 </PQBT-TX-Qpid-01>
- <PQBT-AA-Qpid-01>-n PQBT-AA-Qpid-01 -d10M -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=2000000 </PQBT-AA-Qpid-01>
- <PTBT-TX-Qpid-01>-n PTBT-TX-Qpid-01 -d10M -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=8 transacted=true consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=2000000 </PTBT-TX-Qpid-01>
- <PTBT-AA-Qpid-01>-n PTBT-AA-Qpid-01 -d10M -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=2000000 </PTBT-AA-Qpid-01>
-
- <!-- Benchmark Latency testing-->
- <!-- Job Queueing. 1:10 -->
- <TQBL-AA-Qpid-02-01>-n TQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=1000 maxPending=2000000 </TQBL-AA-Qpid-02-01>
- <TQBL-AA-Qpid-02-02>-n TQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=2000 maxPending=2000000 </TQBL-AA-Qpid-02-02>
- <TQBL-AA-Qpid-02-03>-n TQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=3000 maxPending=2000000 </TQBL-AA-Qpid-02-03>
- <TQBL-AA-Qpid-02-04>-n TQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=4000 maxPending=2000000 </TQBL-AA-Qpid-02-04>
- <TQBL-AA-Qpid-02-05>-n TQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=5000 maxPending=2000000 </TQBL-AA-Qpid-02-05>
- <TQBL-AA-Qpid-02-06>-n TQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=6000 maxPending=2000000 </TQBL-AA-Qpid-02-06>
- <TQBL-AA-Qpid-02-07>-n TQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=7000 maxPending=2000000 </TQBL-AA-Qpid-02-07>
- <TQBL-AA-Qpid-02-08>-n TQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=8000 maxPending=2000000 </TQBL-AA-Qpid-02-08>
- <TQBL-AA-Qpid-02-09>-n TQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=9000 maxPending=2000000 </TQBL-AA-Qpid-02-09>
- <TQBL-AA-Qpid-02-10>-n TQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=10000 maxPending=2000000 </TQBL-AA-Qpid-02-10>
-
- <PQBL-AA-Qpid-02-01>-n PQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=100 maxPending=2000000 </PQBL-AA-Qpid-02-01>
- <PQBL-AA-Qpid-02-02>-n PQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=200 maxPending=2000000 </PQBL-AA-Qpid-02-02>
- <PQBL-AA-Qpid-02-03>-n PQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=300 maxPending=2000000 </PQBL-AA-Qpid-02-03>
- <PQBL-AA-Qpid-02-04>-n PQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=400 maxPending=2000000 </PQBL-AA-Qpid-02-04>
- <PQBL-AA-Qpid-02-05>-n PQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=500 maxPending=2000000 </PQBL-AA-Qpid-02-05>
- <PQBL-AA-Qpid-02-06>-n PQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=600 maxPending=2000000 </PQBL-AA-Qpid-02-06>
- <PQBL-AA-Qpid-02-07>-n PQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=700 maxPending=2000000 </PQBL-AA-Qpid-02-07>
- <PQBL-AA-Qpid-02-08>-n PQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=800 maxPending=2000000 </PQBL-AA-Qpid-02-08>
- <PQBL-AA-Qpid-02-09>-n PQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=900 maxPending=2000000 </PQBL-AA-Qpid-02-09>
- <PQBL-AA-Qpid-02-10>-n PQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=1000 maxPending=2000000 </PQBL-AA-Qpid-02-10>
-
- <!-- Broadcast of small sized time critical messages. Lowish rates. Transient/Persistent. 1:100, auto ack. -->
- <TTBL-AA-Qpid-03-01>-n TTBL-AA-Qpid-03 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=200 maxPending=2000000 </TTBL-AA-Qpid-03-01>
- <TTBL-AA-Qpid-03-02>-n TTBL-AA-Qpid-03 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=400 maxPending=2000000 </TTBL-AA-Qpid-03-02>
- <TTBL-AA-Qpid-03-03>-n TTBL-AA-Qpid-03 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=600 maxPending=2000000 </TTBL-AA-Qpid-03-03>
- <TTBL-AA-Qpid-03-04>-n TTBL-AA-Qpid-03 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=800 maxPending=2000000 </TTBL-AA-Qpid-03-04>
- <TTBL-AA-Qpid-03-05>-n TTBL-AA-Qpid-03 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=1000 maxPending=2000000 </TTBL-AA-Qpid-03-05>
- <TTBL-AA-Qpid-03-06>-n TTBL-AA-Qpid-03 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=1200 maxPending=2000000 </TTBL-AA-Qpid-03-06>
- <TTBL-AA-Qpid-03-07>-n TTBL-AA-Qpid-03 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=1400 maxPending=2000000 </TTBL-AA-Qpid-03-07>
- <TTBL-AA-Qpid-03-08>-n TTBL-AA-Qpid-03 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=1600 maxPending=2000000 </TTBL-AA-Qpid-03-08>
- <TTBL-AA-Qpid-03-09>-n TTBL-AA-Qpid-03 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=1800 maxPending=2000000 </TTBL-AA-Qpid-03-09>
- <TTBL-AA-Qpid-03-10>-n TTBL-AA-Qpid-03 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=2000 maxPending=2000000 </TTBL-AA-Qpid-03-10>
-
- <PTBL-AA-Qpid-03-01>-n PTBL-AA-Qpid-03 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=256 destinationCount=1 rate=10 maxPending=2000000 </PTBL-AA-Qpid-03-01>
- <PTBL-AA-Qpid-03-02>-n PTBL-AA-Qpid-03 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=256 destinationCount=1 rate=20 maxPending=2000000 </PTBL-AA-Qpid-03-02>
- <PTBL-AA-Qpid-03-03>-n PTBL-AA-Qpid-03 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=256 destinationCount=1 rate=30 maxPending=2000000 </PTBL-AA-Qpid-03-03>
- <PTBL-AA-Qpid-03-04>-n PTBL-AA-Qpid-03 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=256 destinationCount=1 rate=40 maxPending=2000000 </PTBL-AA-Qpid-03-04>
- <PTBL-AA-Qpid-03-05>-n PTBL-AA-Qpid-03 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=256 destinationCount=1 rate=50 maxPending=2000000 </PTBL-AA-Qpid-03-05>
- <PTBL-AA-Qpid-03-06>-n PTBL-AA-Qpid-03 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=256 destinationCount=1 rate=60 maxPending=2000000 </PTBL-AA-Qpid-03-06>
- <PTBL-AA-Qpid-03-07>-n PTBL-AA-Qpid-03 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=256 destinationCount=1 rate=70 maxPending=2000000 </PTBL-AA-Qpid-03-07>
- <PTBL-AA-Qpid-03-08>-n PTBL-AA-Qpid-03 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=256 destinationCount=1 rate=80 maxPending=2000000 </PTBL-AA-Qpid-03-08>
- <PTBL-AA-Qpid-03-09>-n PTBL-AA-Qpid-03 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=256 destinationCount=1 rate=90 maxPending=2000000 </PTBL-AA-Qpid-03-09>
- <PTBL-AA-Qpid-03-10>-n PTBL-AA-Qpid-03 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=256 destinationCount=1 rate=100 maxPending=2000000 </PTBL-AA-Qpid-03-10>
-
- <!-- Broadcast of medium sized time critical messages. Lowish rates. Transient/Persistent. 1:100, auto ack. -->
- <TTBL-AA-Qpid-04-01>-n TTBL-AA-Qpid-04 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=100 maxPending=2000000 </TTBL-AA-Qpid-04-01>
- <TTBL-AA-Qpid-04-02>-n TTBL-AA-Qpid-04 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=200 maxPending=2000000 </TTBL-AA-Qpid-04-02>
- <TTBL-AA-Qpid-04-03>-n TTBL-AA-Qpid-04 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=300 maxPending=2000000 </TTBL-AA-Qpid-04-03>
- <TTBL-AA-Qpid-04-04>-n TTBL-AA-Qpid-04 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=400 maxPending=2000000 </TTBL-AA-Qpid-04-04>
- <TTBL-AA-Qpid-04-05>-n TTBL-AA-Qpid-04 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=500 maxPending=2000000 </TTBL-AA-Qpid-04-05>
- <TTBL-AA-Qpid-04-06>-n TTBL-AA-Qpid-04 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=600 maxPending=2000000 </TTBL-AA-Qpid-04-06>
- <TTBL-AA-Qpid-04-07>-n TTBL-AA-Qpid-04 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=700 maxPending=2000000 </TTBL-AA-Qpid-04-07>
- <TTBL-AA-Qpid-04-08>-n TTBL-AA-Qpid-04 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=800 maxPending=2000000 </TTBL-AA-Qpid-04-08>
- <TTBL-AA-Qpid-04-09>-n TTBL-AA-Qpid-04 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=900 maxPending=2000000 </TTBL-AA-Qpid-04-09>
- <TTBL-AA-Qpid-04-10>-n TTBL-AA-Qpid-04 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=1000 maxPending=2000000 </TTBL-AA-Qpid-04-10>
-
- <PTBL-AA-Qpid-04-01>-n PTBL-AA-Qpid-04 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=5120 destinationCount=1 rate=10 maxPending=2000000 </PTBL-AA-Qpid-04-01>
- <PTBL-AA-Qpid-04-02>-n PTBL-AA-Qpid-04 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=5120 destinationCount=1 rate=20 maxPending=2000000 </PTBL-AA-Qpid-04-02>
- <PTBL-AA-Qpid-04-03>-n PTBL-AA-Qpid-04 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=5120 destinationCount=1 rate=30 maxPending=2000000 </PTBL-AA-Qpid-04-03>
- <PTBL-AA-Qpid-04-04>-n PTBL-AA-Qpid-04 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=5120 destinationCount=1 rate=40 maxPending=2000000 </PTBL-AA-Qpid-04-04>
- <PTBL-AA-Qpid-04-05>-n PTBL-AA-Qpid-04 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=5120 destinationCount=1 rate=50 maxPending=2000000 </PTBL-AA-Qpid-04-05>
- <PTBL-AA-Qpid-04-06>-n PTBL-AA-Qpid-04 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=5120 destinationCount=1 rate=60 maxPending=2000000 </PTBL-AA-Qpid-04-06>
- <PTBL-AA-Qpid-04-07>-n PTBL-AA-Qpid-04 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=5120 destinationCount=1 rate=70 maxPending=2000000 </PTBL-AA-Qpid-04-07>
- <PTBL-AA-Qpid-04-08>-n PTBL-AA-Qpid-04 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=5120 destinationCount=1 rate=80 maxPending=2000000 </PTBL-AA-Qpid-04-08>
- <PTBL-AA-Qpid-04-09>-n PTBL-AA-Qpid-04 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=5120 destinationCount=1 rate=90 maxPending=2000000 </PTBL-AA-Qpid-04-09>
- <PTBL-AA-Qpid-04-10>-n PTBL-AA-Qpid-04 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=5120 destinationCount=1 rate=100 maxPending=2000000 </PTBL-AA-Qpid-04-10>
-
- <!-- Low-latency broadcast of time sensitive events. Transient, no_ack. -->
- <TTBL-NA-Qpid-05-01>-n TTBL-NA-Qpid-05 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=400 maxPending=2000000 </TTBL-NA-Qpid-05-01>
- <TTBL-NA-Qpid-05-02>-n TTBL-NA-Qpid-05 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=800 maxPending=2000000 </TTBL-NA-Qpid-05-02>
- <TTBL-NA-Qpid-05-03>-n TTBL-NA-Qpid-05 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=1200 maxPending=2000000 </TTBL-NA-Qpid-05-03>
- <TTBL-NA-Qpid-05-04>-n TTBL-NA-Qpid-05 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=1600 maxPending=2000000 </TTBL-NA-Qpid-05-04>
- <TTBL-NA-Qpid-05-05>-n TTBL-NA-Qpid-05 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=2000 maxPending=2000000 </TTBL-NA-Qpid-05-05>
- <TTBL-NA-Qpid-05-06>-n TTBL-NA-Qpid-05 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=2400 maxPending=2000000 </TTBL-NA-Qpid-05-06>
- <TTBL-NA-Qpid-05-07>-n TTBL-NA-Qpid-05 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=2800 maxPending=2000000 </TTBL-NA-Qpid-05-07>
- <TTBL-NA-Qpid-05-08>-n TTBL-NA-Qpid-05 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=3200 maxPending=2000000 </TTBL-NA-Qpid-05-08>
- <TTBL-NA-Qpid-05-09>-n TTBL-NA-Qpid-05 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=3600 maxPending=2000000 </TTBL-NA-Qpid-05-09>
- <TTBL-NA-Qpid-05-10>-n TTBL-NA-Qpid-05 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=4000 maxPending=2000000 </TTBL-NA-Qpid-05-10>
-
- <!-- Low-latency broadcast of medium sized time sensitive events. Transient, no_ack. -->
- <TTBL-NA-Qpid-06-01>-n TTBL-NA-Qpid-06 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=100 maxPending=2000000 </TTBL-NA-Qpid-06-01>
- <TTBL-NA-Qpid-06-02>-n TTBL-NA-Qpid-06 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=200 maxPending=2000000 </TTBL-NA-Qpid-06-02>
- <TTBL-NA-Qpid-06-03>-n TTBL-NA-Qpid-06 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=300 maxPending=2000000 </TTBL-NA-Qpid-06-03>
- <TTBL-NA-Qpid-06-04>-n TTBL-NA-Qpid-06 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=400 maxPending=2000000 </TTBL-NA-Qpid-06-04>
- <TTBL-NA-Qpid-06-05>-n TTBL-NA-Qpid-06 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=500 maxPending=2000000 </TTBL-NA-Qpid-06-05>
- <TTBL-NA-Qpid-06-06>-n TTBL-NA-Qpid-06 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=600 maxPending=2000000 </TTBL-NA-Qpid-06-06>
- <TTBL-NA-Qpid-06-07>-n TTBL-NA-Qpid-06 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=700 maxPending=2000000 </TTBL-NA-Qpid-06-07>
- <TTBL-NA-Qpid-06-08>-n TTBL-NA-Qpid-06 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=800 maxPending=2000000 </TTBL-NA-Qpid-06-08>
- <TTBL-NA-Qpid-06-09>-n TTBL-NA-Qpid-06 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=900 maxPending=2000000 </TTBL-NA-Qpid-06-09>
- <TTBL-NA-Qpid-06-10>-n TTBL-NA-Qpid-06 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=1000 maxPending=2000000 </TTBL-NA-Qpid-06-10>
-
- <!-- Failover Tests. -->
- <FT-Qpid-01>-n FT-Qpid-01 -s[2500] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 batchSize=10000 transacted=true properties=failovertest.properties failBeforeSend=true -o $QPID_WORK/results</FT-Qpid-01>
- <FT-Qpid-02>-n FT-Qpid-02 -s[2500] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 batchSize=10000 transacted=true properties=failovertest.properties failAfterSend=true -o $QPID_WORK/results</FT-Qpid-02>
- <FT-Qpid-03>-n FT-Qpid-03 -s[2500] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 batchSize=1000 transacted=true properties=failovertest.properties failAfterCommit=true -o $QPID_WORK/results</FT-Qpid-03>
- <FT-Qpid-04>-n FT-Qpid-04 -s[2500] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 batchSize=1000 properties=failovertest.properties transacted=false failBeforeSend=true -o $QPID_WORK/results</FT-Qpid-04>
- <FT-Qpid-05>-n FT-Qpid-05 -s[2500] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 batchSize=1000 properties=failovertest.properties transacted=false failAfterSend=true -o $QPID_WORK/results</FT-Qpid-05>
- <FT-Qpid-01-P>-n FT-Qpid-01-P -s[2500] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 batchSize=1000 transacted=true properties=failovertest.properties failBeforeSend=true -o $QPID_WORK/results</FT-Qpid-01-P>
- <FT-Qpid-02-P>-n FT-Qpid-02-P -s[2500] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 batchSize=1000 transacted=true properties=failovertest.properties failAfterSend=true -o $QPID_WORK/results</FT-Qpid-02-P>
- <FT-Qpid-03-P>-n FT-Qpid-03-P -s[2500] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 batchSize=1000 transacted=true properties=failovertest.properties failAfterCommit=true -o $QPID_WORK/results</FT-Qpid-03-P>
- <FT-Qpid-04-P>-n FT-Qpid-04-P -s[250] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 batchSize=1000 properties=failovertest.properties transacted=false failBeforeSend=true -o $QPID_WORK/results</FT-Qpid-04-P>
- <FT-Qpid-05-P>-n FT-Qpid-05-P -s[250] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 batchSize=1000 properties=failovertest.properties transacted=false failAfterSend=true -o $QPID_WORK/results</FT-Qpid-05-P>
-
- </commands>
- </configuration>
-
- <executions>
- <execution>
- <phase>test</phase>
- </execution>
- </executions>
- </plugin>
-
- <!-- Bundles all the dependencies, fully expanded into a single jar, required to run the tests.
- Also builds all thescripts and this jar into distributable .zip and .tar.gz files.
-
- Usefull when bundling system, integration or performance tests into a convenient
- package to hand over to testers. To use it run:
-
- java -cp target/your_app_name-all-test-deps.jar path.to.your.Class
-
- or often:
-
- java -cp target/your_app_name-all-test-deps.jar junit.framework.textui.TestRunner path.to.your.test.Class
-
- or other JUnit test runner invocations.
- -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-assembly-plugin</artifactId>
- <version>2.2-SNAPSHOT</version>
- <configuration>
- <descriptors>
- <descriptor>jar-with-dependencies.xml</descriptor>
- <!--<descriptor>dist-zip.xml</descriptor>-->
- </descriptors>
- <outputDirectory>target</outputDirectory>
- <workDirectory>target/assembly/work</workDirectory>
- </configuration>
- </plugin>
-
- <!-- Build a manifest only jar with all the required jars for the broker in its classpath. -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <executions>
- <execution>
- <id>test_jar</id>
- <configuration>
- <archive>
- <manifest>
- <addClasspath>true</addClasspath>
- </manifest>
- </archive>
- </configuration>
- <goals>
- <goal>jar</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
-
- </plugins>
-
- <resources>
- <!-- Include source files in built jar -->
- <resource>
- <targetPath>src/</targetPath>
- <filtering>false</filtering>
- <directory>src/main/java</directory>
- <includes>
- <include>**/*.java</include>
- </includes>
- </resource>
- <!-- Include a log4j configuration in the jar at the root level (don't name this log4j.properties though as won't be able to override it). -->
- <resource>
- <targetPath>/</targetPath>
- <filtering>false</filtering>
- <directory>src/main/java</directory>
- <includes>
- <include>perftests.log4j</include>
- </includes>
- </resource>
- </resources>
- </build>
-
-</project>
diff --git a/java/perftests/scripts.xml b/java/perftests/scripts.xml
new file mode 100644
index 0000000000..9a5163c598
--- /dev/null
+++ b/java/perftests/scripts.xml
@@ -0,0 +1,328 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+
+<scripts>
+ <!-- Single pings. These can be scaled up by overriding the parameters when calling the test script. -->
+ <script name="Ping-Once">-n Ping-Once -s[1] -r 1 -t testPingOk -o . org.apache.qpid.ping.PingTestPerf</script>
+ <script name="Ping-Once-Async">-n Ping-Once-Async -s[1] -r 1 -t testAsyncPingOk -o . org.apache.qpid.ping.PingAsyncTestPerf</script>
+ <script name="Ping-Latency">-n Ping-Latency -s[1000] -d10S -t testPingLatency -o . org.apache.qpid.ping.PingLatencyTestPerf rate=100 batchSize=100</script>
+
+ <!-- More example Tests. These are examples to exercise all the features of the test harness. Can scale up with option overrides. -->
+ <script name="Ping-Tx">-n Ping-Tx -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf transacted=true</script>
+ <script name="Ping-Size">-n Ping-Size -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=512</script>
+ <script name="Ping-Concurrent">-n Ping-Concurrent -s[100] -c [4] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf</script>
+ <script name="Ping-Many-Queues">-n Ping-Many-Queues -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf destinationCount=4</script>
+ <script name="Ping-Duration">-n Ping-Duration -s[100] -d10S -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf</script>
+ <script name="Ping-Rate">-n Ping-Rate -s[100] -d10S -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf rate=500</script>
+ <script name="Ping-PubSub">-n Ping-PubSub -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true</script>
+ <script name="Ping-Many-Topics">-n Ping-Many-Topics -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true destinationCount=4</script>
+ <script name="Ping-Persistent">-n Ping-Persistent -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true</script>
+ <script name="Ping-Batch-Logging">-n Ping-Batch-Logging -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf batchSize=10</script>
+ <script name="Ping-Failover-Before-Send">-n Ping-Failover-Before-Send -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf commitBatchSize=10 failBeforeSend=true</script>
+ <script name="Ping-Failover-After-Send">-n Ping-Failover-After-Send -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf commitBatchSize=10 failAfterSend=true</script>
+ <script name="Ping-Failover-Before-Commit">-n Ping-Failover-Before-Commit -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf commitBatchSize=10 failBeforeCommit=true</script>
+ <script name="Ping-Failover-After-Commit">-n Ping-Failover-After-Commit -s[100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf commitBatchSize=10 failAfterCommit=true</script>
+
+ <!--
+ ***** If editing below, please use a non line wrapping mode and keep in columns, makes it easier to check for consistent
+ ***** parameter setting accross all of the tests.
+ -->
+
+ <!--
+ Reliability tests. The longer these tests can be run, the better.
+ Tests 01 and 02 run for a short time. Use these to get an idea of the expected throughput.
+ Tests 03 to 08 test all ack modes, transient/persistent, p2p/pubsub. There are 24 tests in total running for 1 hour each.
+ This can be shortened or lengthened for the desired burn-in test time.
+ -->
+ <script name="TQR-Qpid-01">-n TQR-Qpid-01 -d1M -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="TQR-Qpid-02">-n TQR-Qpid-02 -d1M -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="TTR-Qpid-01">-n TTR-Qpid-01 -d1M -s[100] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="TTR-Qpid-02">-n TTR-Qpid-02 -d1M -s[100] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="PQR-Qpid-01">-n PQR-Qpid-01 -d1M -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="PQR-Qpid-02">-n PQR-Qpid-02 -d1M -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="PTR-Qpid-01">-n PTR-Qpid-01 -d1M -s[100] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=8 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="PTR-Qpid-02">-n PTR-Qpid-02 -d1M -s[100] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+
+ <script name="TQR-Qpid-03-TX">-n TQR-Qpid-03 -d1H -s[10000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="TQR-Qpid-04-AUTOACK">-n TQR-Qpid-04 -d1H -s[10000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="TQR-Qpid-05-CLIENTACK">-n TQR-Qpid-05 -d1H -s[10000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=2 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="TQR-Qpid-06-DUPSOKACK">-n TQR-Qpid-06 -d1H -s[10000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=3 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="TQR-Qpid-07-NOACK">-n TQR-Qpid-07 -d1H -s[10000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=257 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="TQR-Qpid-08-PREACK">-n TQR-Qpid-08 -d1H -s[10000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=258 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+
+ <script name="TTR-Qpid-03-TX">-n TTR-Qpid-03 -d1H -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="TTR-Qpid-04-AUTOACK">-n TTR-Qpid-04 -d1H -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="TTR-Qpid-05-CLIENTACK">-n TTR-Qpid-05 -d1H -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=2 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="TTR-Qpid-06-DUPSOKACK">-n TTR-Qpid-06 -d1H -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=3 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="TTR-Qpid-07-NOACK">-n TTR-Qpid-07 -d1H -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=257 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="TTR-Qpid-08-PREACK">-n TTR-Qpid-08 -d1H -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=258 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+
+ <script name="PQR-Qpid-03-TX">-n PQR-Qpid-03 -d1H -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="PQR-Qpid-04-AUTOACK">-n PQR-Qpid-04 -d1H -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="PQR-Qpid-05-CLIENTACK">-n PQR-Qpid-05 -d1H -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=2 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="PQR-Qpid-06-DUPSOKACK">-n PQR-Qpid-06 -d1H -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=3 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="PQR-Qpid-07-NOACK">-n PQR-Qpid-07 -d1H -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=257 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="PQR-Qpid-08-PREACK">-n PQR-Qpid-08 -d1H -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=258 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+
+ <script name="PTR-Qpid-03-TX">-n PTR-Qpid-03 -d1H -s[100] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=8 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="PTR-Qpid-04-AUTOACK">-n PTR-Qpid-04 -d1H -s[100] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="PTR-Qpid-05-CLIENTACK">-n PTR-Qpid-05 -d1H -s[100] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=2 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="PTR-Qpid-06-DUPSOKACK">-n PTR-Qpid-06 -d1H -s[100] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=3 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="PTR-Qpid-07-NOACK">-n PTR-Qpid-07 -d1H -s[100] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=257 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+ <script name="PTR-Qpid-08-PREACK">-n PTR-Qpid-08 -d1H -s[100] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=258 commitBatchSize=10 batchSize=100000 messageSize=256 destinationCount=1 rate=0 maxPending=500000 </script>
+
+ <!-- Performance Tests. -->
+
+ <!-- Transient, P2P Tests -->
+ <!-- Concurrency Tests : What are the effects of increasing consumers from 1...30 consumers -->
+ <script name="TQCT-Qpid-01">-n TQCT-Qpid-01 -d1M -s[1000] -c[1:30]:samples=30 -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=2000 maxPending=2000000 </script>
+ <script name="TQCT-Qpid-02">-n TQCT-Qpid-02 -d1M -s[1000] -c[1:30]:samples=30 -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=2000 maxPending=2000000 </script>
+ <!-- Latency Tests : What are the effects on latency of increasing consumers from 1...30 consumers -->
+ <script name="TQCL-Qpid-01">-n TQCL-Qpid-01 -d1M -s[1000] -c[1:30]:samples=30 -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=2000 maxPending=2000000 </script>
+ <script name="TQCL-Qpid-02">-n TQCL-Qpid-02 -d1M -s[1000] -c[1:30]:samples=30 -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=2000 maxPending=2000000 </script>
+
+ <!-- <script name="TQC-Qpid-05">-n TQC-Qpid-05 -d10M -s[10] -c[100] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=10 rate=0 maxPending=100000 </script> -->
+ <!-- <script name="TQC-Qpid-06">-n TQC-Qpid-06 -d10M -s[10] -c[100] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=10 rate=0 maxPending=100000 </script> -->
+
+
+ <!-- Message Size Tests : Tests sending message from 512b upto 1M with Point to Point messaging -->
+ <script name="TQM-Qpid-01-512b">-n TQM-Qpid-01-512b -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=512 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="TQM-Qpid-02-512b">-n TQM-Qpid-02-512b -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=512 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="TQM-Qpid-01-1K">-n TQM-Qpid-01-1K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=1024 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="TQM-Qpid-02-1K">-n TQM-Qpid-02-1K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=1024 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="TQM-Qpid-01-5K">-n TQM-Qpid-01-5K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=5120 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="TQM-Qpid-02-5K">-n TQM-Qpid-02-5K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=5120 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="TQM-Qpid-01-10K">-n TQM-Qpid-01-10K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=10240 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="TQM-Qpid-02-10K">-n TQM-Qpid-02-10K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=10240 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="TQM-Qpid-01-50K">-n TQM-Qpid-01-50K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=51200 destinationCount=1 rate=0 maxPending=100000000</script>
+ <script name="TQM-Qpid-02-50K">-n TQM-Qpid-02-50K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=51200 destinationCount=1 rate=0 maxPending=100000000</script>
+ <script name="TQM-Qpid-01-100K">-n TQM-Qpid-01-100K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=102400 destinationCount=1 rate=0 maxPending=100000000</script>
+ <script name="TQM-Qpid-02-100K">-n TQM-Qpid-02-100K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=102400 destinationCount=1 rate=0 maxPending=100000000</script>
+ <script name="TQM-Qpid-01-500K">-n TQM-Qpid-01-500K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=512000 destinationCount=1 rate=0 maxPending=100000000</script>
+ <script name="TQM-Qpid-02-500K">-n TQM-Qpid-02-500K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=512000 destinationCount=1 rate=0 maxPending=100000000</script>
+ <script name="TQM-Qpid-01-1M">-n TQM-Qpid-01-1M -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=1048576 destinationCount=1 rate=0 maxPending=100000000</script>
+ <script name="TQM-Qpid-02-1M">-n TQM-Qpid-02-1M -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=1048576 destinationCount=1 rate=0 maxPending=100000000</script>
+
+ <!-- Transient, Pub/Sub Tests -->
+ <!-- Concurrency Tests : What are the effects of increasing consumers from 1...30 consumers -->
+ <script name="TTCT-Qpid-01">-n TTCT-Qpid-01 -d1M -s[10] -c[1:30]:samples=30 -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=40 maxPending=2000000 </script>
+ <script name="TTCT-Qpid-02">-n TTCT-Qpid-02 -d1M -s[10] -c[1:30]:samples=30 -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=40 maxPending=2000000 </script>
+ <!-- Latency Tests : What are the effects on latency of increasing consumers from 1...30 consumers -->
+ <script name="TTCL-Qpid-01">-n TTCL-Qpid-01 -d1M -s[10] -c[1:30]:samples=30 -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=40 maxPending=2000000 </script>
+ <script name="TTCL-Qpid-02">-n TTCL-Qpid-02 -d1M -s[10] -c[1:30]:samples=30 -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=40 maxPending=2000000 </script>
+
+ <!-- <script name="TTC-Qpid-05">-n TTC-Qpid-05 -d10M -s[10] -c[100] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=10 rate=0 maxPending=100000 </script> -->
+ <!-- <script name="TTC-Qpid-06">-n TTC-Qpid-06 -d10M -s[10] -c[100] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=10 rate=0 maxPending=100000 </script> -->
+
+ <!-- Message Size Tests : Tests sending message from 512b upto 1M with Point to Point messaging -->
+ <script name="TTM-Qpid-01-512b">-n TTM-Qpid-01-512b -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=512 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="TTM-Qpid-02-512b">-n TTM-Qpid-02-512b -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=512 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="TTM-Qpid-01-1K">-n TTM-Qpid-01-1K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=1024 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="TTM-Qpid-02-1K">-n TTM-Qpid-02-1K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=1024 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="TTM-Qpid-01-5K">-n TTM-Qpid-01-5K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=5120 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="TTM-Qpid-02-5K">-n TTM-Qpid-02-5K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=5120 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="TTM-Qpid-01-10K">-n TTM-Qpid-01-10K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=10240 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="TTM-Qpid-02-10K">-n TTM-Qpid-02-10K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=10240 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="TTM-Qpid-01-50K">-n TTM-Qpid-01-50K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=51200 destinationCount=1 rate=0 maxPending=20000000</script>
+ <script name="TTM-Qpid-02-50K">-n TTM-Qpid-02-50K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=51200 destinationCount=1 rate=0 maxPending=20000000</script>
+ <script name="TTM-Qpid-01-100K">-n TTM-Qpid-01-100K -d10M -s[40] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=102400 destinationCount=1 rate=0 maxPending=20000000</script>
+ <script name="TTM-Qpid-02-100K">-n TTM-Qpid-02-100K -d10M -s[40] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=102400 destinationCount=1 rate=0 maxPending=20000000</script>
+ <script name="TTM-Qpid-01-500K">-n TTM-Qpid-01-500K -d10M -s[8] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=512000 destinationCount=1 rate=0 maxPending=20000000</script>
+ <script name="TTM-Qpid-02-500K">-n TTM-Qpid-02-500K -d10M -s[8] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=512000 destinationCount=1 rate=0 maxPending=20000000</script>
+ <script name="TTM-Qpid-01-1M">-n TTM-Qpid-01-1M -d10M -s[4] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=1048576 destinationCount=1 rate=0 maxPending=20000000</script>
+ <script name="TTM-Qpid-02-1M">-n TTM-Qpid-02-1M -d10M -s[4] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=1048476 destinationCount=1 rate=0 maxPending=20000000</script>
+
+ <!-- Persistent, P2P Tests -->
+ <!-- Concurrency Tests : What are the effects of increasing consumers from 1...30 consumers -->
+ <script name="PQCT-Qpid-01">-n PQCT-Qpid-01 -d1M -s[1000] -c[1:30]:samples=30 -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=600 maxPending=2000000 </script>
+ <script name="PQCT-Qpid-02">-n PQCT-Qpid-02 -d1M -s[1000] -c[1:30]:samples=30 -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=100 maxPending=2000000 </script>
+ <!-- Latency Tests : What are the effects on latency of increasing consumers from 1...30 consumers -->
+ <script name="PQCL-Qpid-01">-n PQCL-Qpid-01 -d1M -s[1000] -c[1:30]:samples=30 -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=600 maxPending=2000000 </script>
+ <script name="PQCL-Qpid-02">-n PQCL-Qpid-02 -d1M -s[1000] -c[1:30]:samples=30 -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=100 maxPending=2000000 </script>
+
+ <!-- <script name="PQC-Qpid-05">-n PQC-Qpid-05 -d10M -s[10] -c[100] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=10 rate=0 maxPending=100000 </script> -->
+ <!-- <script name="PQC-Qpid-06">-n PQC-Qpid-06 -d10M -s[10] -c[100] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=10 rate=0 maxPending=100000 </script> -->
+
+ <!-- Message Size Tests : Tests sending message from 512b upto 1M with Point to Point messaging -->
+ <script name="PQM-Qpid-01-512b">-n PQM-Qpid-01-512b -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=512 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="PQM-Qpid-02-512b">-n PQM-Qpid-02-512b -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=512 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="PQM-Qpid-01-1K">-n PQM-Qpid-01-1K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=1024 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="PQM-Qpid-02-1K">-n PQM-Qpid-02-1K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=1024 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="PQM-Qpid-01-5K">-n PQM-Qpid-01-5K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=5120 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="PQM-Qpid-02-5K">-n PQM-Qpid-02-5K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=5120 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="PQM-Qpid-01-10K">-n PQM-Qpid-01-10K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=10240 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="PQM-Qpid-02-10K">-n PQM-Qpid-02-10K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=10240 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="PQM-Qpid-01-50K">-n PQM-Qpid-01-50K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=51200 destinationCount=1 rate=0 maxPending=20000000</script>
+ <script name="PQM-Qpid-02-50K">-n PQM-Qpid-02-50K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=51200 destinationCount=1 rate=0 maxPending=20000000</script>
+ <script name="PQM-Qpid-01-100K">-n PQM-Qpid-01-100K -d10M -s[40] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=102400 destinationCount=1 rate=0 maxPending=20000000</script>
+ <script name="PQM-Qpid-02-100K">-n PQM-Qpid-02-100K -d10M -s[40] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=102400 destinationCount=1 rate=0 maxPending=20000000</script>
+ <script name="PQM-Qpid-01-500K">-n PQM-Qpid-01-500K -d10M -s[8] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=512000 destinationCount=1 rate=0 maxPending=20000000</script>
+ <script name="PQM-Qpid-02-500K">-n PQM-Qpid-02-500K -d10M -s[8] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=512000 destinationCount=1 rate=0 maxPending=20000000</script>
+ <script name="PQM-Qpid-01-1M">-n PQM-Qpid-01-1M -d10M -s[4] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=1048576 destinationCount=1 rate=0 maxPending=20000000</script>
+ <script name="PQM-Qpid-02-1M">-n PQM-Qpid-02-1M -d10M -s[4] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=1048576 destinationCount=1 rate=0 maxPending=20000000</script>
+
+ <!-- Persistent, Pub/Sub Tests -->
+ <script name="PTCT-Qpid-01">-n PTCT-Qpid-01 -d1M -s[1] -c[1:30]:samples=30 -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=1 maxPending=2000000 </script>
+ <script name="PTCT-Qpid-02">-n PTCT-Qpid-02 -d1M -s[1] -c[1:30]:samples=30 -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=1 maxPending=2000000 </script>
+ <script name="PTCL-Qpid-01">-n PTCL-Qpid-01 -d1M -s[1] -c[1:30]:samples=30 -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=1 maxPending=2000000 </script>
+ <script name="PTCL-Qpid-02">-n PTCL-Qpid-02 -d1M -s[1] -c[1:30]:samples=30 -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=1 rate=1 maxPending=2000000 </script>
+
+ <!-- <script name="PTC-Qpid-05">-n PTC-Qpid-05 -d10M -s[10] -c[100] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=10 rate=0 maxPending=100000 </script> -->
+ <!-- <script name="PTC-Qpid-06">-n PTC-Qpid-06 -d10M -s[10] -c[100] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=256 destinationCount=10 rate=0 maxPending=100000 </script> -->
+
+ <script name="PTM-Qpid-01-512b">-n PTM-Qpid-01-512b -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=512 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="PTM-Qpid-02-512b">-n PTM-Qpid-02-512b -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=512 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="PTM-Qpid-01-1K">-n PTM-Qpid-01-1K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=1024 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="PTM-Qpid-02-1K">-n PTM-Qpid-02-1K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=1024 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="PTM-Qpid-01-5K">-n PTM-Qpid-01-5K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=5120 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="PTM-Qpid-02-5K">-n PTM-Qpid-02-5K -d10M -s[1000] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=5120 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="PTM-Qpid-01-10K">-n PTM-Qpid-01-10K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=10240 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="PTM-Qpid-02-10K">-n PTM-Qpid-02-10K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=10240 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="PTM-Qpid-01-50K">-n PTM-Qpid-01-50K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=51200 destinationCount=1 rate=0 maxPending=20000000</script>
+ <script name="PTM-Qpid-02-50K">-n PTM-Qpid-02-50K -d10M -s[100] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=51200 destinationCount=1 rate=0 maxPending=20000000</script>
+ <script name="PTM-Qpid-01-100K">-n PTM-Qpid-01-100K -d10M -s[40] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=102400 destinationCount=1 rate=0 maxPending=20000000</script>
+ <script name="PTM-Qpid-02-100K">-n PTM-Qpid-02-100K -d10M -s[40] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=102400 destinationCount=1 rate=0 maxPending=20000000</script>
+ <script name="PTM-Qpid-01-500K">-n PTM-Qpid-01-500K -d10M -s[8] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=512000 destinationCount=1 rate=0 maxPending=20000000</script>
+ <script name="PTM-Qpid-02-500K">-n PTM-Qpid-02-500K -d10M -s[8] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=512000 destinationCount=1 rate=0 maxPending=20000000</script>
+ <script name="PTM-Qpid-01-1M">-n PTM-Qpid-01-1M -d10M -s[4] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=10 batchSize=1000 messageSize=1048576 destinationCount=1 rate=0 maxPending=20000000</script>
+ <script name="PTM-Qpid-02-1M">-n PTM-Qpid-02-1M -d10M -s[4] -c[8] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=10 batchSize=1000 messageSize=1048476 destinationCount=1 rate=0 maxPending=20000000</script>
+
+ <!-- Benchmarking tests. -->
+ <!-- Throughput. -->
+ <script name="TQBT-TX-Qpid-01">-n TQBT-TX-Qpid-01 -d10M -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=1 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="TQBT-AA-Qpid-01">-n TQBT-AA-Qpid-01 -d10M -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="TQBT-NA-Qpid-01">-n TQBT-NA-Qpid-01 -d10M -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="TTBT-TX-Qpid-01">-n TTBT-TX-Qpid-01 -d10M -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=true consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="TTBT-AA-Qpid-01">-n TTBT-AA-Qpid-01 -d10M -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="TTBT-NA-Qpid-01">-n TTBT-NA-Qpid-01 -d10M -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=2000000 </script>
+
+ <script name="PQBT-TX-Qpid-01">-n PQBT-TX-Qpid-01 -d10M -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=true consTransacted=true consAckMode=0 commitBatchSize=1 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="PQBT-AA-Qpid-01">-n PQBT-AA-Qpid-01 -d10M -s[1000] -c[16] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=1 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="PTBT-TX-Qpid-01">-n PTBT-TX-Qpid-01 -d10M -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=8 transacted=true consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=2000000 </script>
+ <script name="PTBT-AA-Qpid-01">-n PTBT-AA-Qpid-01 -d10M -s[1000] -c[2] -o $QPID_WORK/results -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=8 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=256 destinationCount=1 rate=0 maxPending=2000000 </script>
+
+ <!-- Benchmark Latency testing-->
+ <!-- Job Queueing. 1:10 -->
+ <script name="TQBL-AA-Qpid-02-01">-n TQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=1000 maxPending=2000000 </script>
+ <script name="TQBL-AA-Qpid-02-02">-n TQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=2000 maxPending=2000000 </script>
+ <script name="TQBL-AA-Qpid-02-03">-n TQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=3000 maxPending=2000000 </script>
+ <script name="TQBL-AA-Qpid-02-04">-n TQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=4000 maxPending=2000000 </script>
+ <script name="TQBL-AA-Qpid-02-05">-n TQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=5000 maxPending=2000000 </script>
+ <script name="TQBL-AA-Qpid-02-06">-n TQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=6000 maxPending=2000000 </script>
+ <script name="TQBL-AA-Qpid-02-07">-n TQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=7000 maxPending=2000000 </script>
+ <script name="TQBL-AA-Qpid-02-08">-n TQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=8000 maxPending=2000000 </script>
+ <script name="TQBL-AA-Qpid-02-09">-n TQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=9000 maxPending=2000000 </script>
+ <script name="TQBL-AA-Qpid-02-10">-n TQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=10000 maxPending=2000000 </script>
+
+ <script name="PQBL-AA-Qpid-02-01">-n PQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=100 maxPending=2000000 </script>
+ <script name="PQBL-AA-Qpid-02-02">-n PQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=200 maxPending=2000000 </script>
+ <script name="PQBL-AA-Qpid-02-03">-n PQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=300 maxPending=2000000 </script>
+ <script name="PQBL-AA-Qpid-02-04">-n PQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=400 maxPending=2000000 </script>
+ <script name="PQBL-AA-Qpid-02-05">-n PQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=500 maxPending=2000000 </script>
+ <script name="PQBL-AA-Qpid-02-06">-n PQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=600 maxPending=2000000 </script>
+ <script name="PQBL-AA-Qpid-02-07">-n PQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=700 maxPending=2000000 </script>
+ <script name="PQBL-AA-Qpid-02-08">-n PQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=800 maxPending=2000000 </script>
+ <script name="PQBL-AA-Qpid-02-09">-n PQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=900 maxPending=2000000 </script>
+ <script name="PQBL-AA-Qpid-02-10">-n PQBL-AA-Qpid-02 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=false uniqueDests=true numConsumers=10 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1000 messageSize=5120 destinationCount=1 rate=1000 maxPending=2000000 </script>
+
+ <!-- Broadcast of small sized time critical messages. Lowish rates. Transient/Persistent. 1:100, auto ack. -->
+ <script name="TTBL-AA-Qpid-03-01">-n TTBL-AA-Qpid-03 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=200 maxPending=2000000 </script>
+ <script name="TTBL-AA-Qpid-03-02">-n TTBL-AA-Qpid-03 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=400 maxPending=2000000 </script>
+ <script name="TTBL-AA-Qpid-03-03">-n TTBL-AA-Qpid-03 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=600 maxPending=2000000 </script>
+ <script name="TTBL-AA-Qpid-03-04">-n TTBL-AA-Qpid-03 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=800 maxPending=2000000 </script>
+ <script name="TTBL-AA-Qpid-03-05">-n TTBL-AA-Qpid-03 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=1000 maxPending=2000000 </script>
+ <script name="TTBL-AA-Qpid-03-06">-n TTBL-AA-Qpid-03 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=1200 maxPending=2000000 </script>
+ <script name="TTBL-AA-Qpid-03-07">-n TTBL-AA-Qpid-03 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=1400 maxPending=2000000 </script>
+ <script name="TTBL-AA-Qpid-03-08">-n TTBL-AA-Qpid-03 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=1600 maxPending=2000000 </script>
+ <script name="TTBL-AA-Qpid-03-09">-n TTBL-AA-Qpid-03 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=1800 maxPending=2000000 </script>
+ <script name="TTBL-AA-Qpid-03-10">-n TTBL-AA-Qpid-03 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=2000 maxPending=2000000 </script>
+
+ <script name="PTBL-AA-Qpid-03-01">-n PTBL-AA-Qpid-03 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=256 destinationCount=1 rate=10 maxPending=2000000 </script>
+ <script name="PTBL-AA-Qpid-03-02">-n PTBL-AA-Qpid-03 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=256 destinationCount=1 rate=20 maxPending=2000000 </script>
+ <script name="PTBL-AA-Qpid-03-03">-n PTBL-AA-Qpid-03 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=256 destinationCount=1 rate=30 maxPending=2000000 </script>
+ <script name="PTBL-AA-Qpid-03-04">-n PTBL-AA-Qpid-03 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=256 destinationCount=1 rate=40 maxPending=2000000 </script>
+ <script name="PTBL-AA-Qpid-03-05">-n PTBL-AA-Qpid-03 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=256 destinationCount=1 rate=50 maxPending=2000000 </script>
+ <script name="PTBL-AA-Qpid-03-06">-n PTBL-AA-Qpid-03 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=256 destinationCount=1 rate=60 maxPending=2000000 </script>
+ <script name="PTBL-AA-Qpid-03-07">-n PTBL-AA-Qpid-03 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=256 destinationCount=1 rate=70 maxPending=2000000 </script>
+ <script name="PTBL-AA-Qpid-03-08">-n PTBL-AA-Qpid-03 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=256 destinationCount=1 rate=80 maxPending=2000000 </script>
+ <script name="PTBL-AA-Qpid-03-09">-n PTBL-AA-Qpid-03 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=256 destinationCount=1 rate=90 maxPending=2000000 </script>
+ <script name="PTBL-AA-Qpid-03-10">-n PTBL-AA-Qpid-03 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=256 destinationCount=1 rate=100 maxPending=2000000 </script>
+
+ <!-- Broadcast of medium sized time critical messages. Lowish rates. Transient/Persistent. 1:100, auto ack. -->
+ <script name="TTBL-AA-Qpid-04-01">-n TTBL-AA-Qpid-04 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=100 maxPending=2000000 </script>
+ <script name="TTBL-AA-Qpid-04-02">-n TTBL-AA-Qpid-04 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=200 maxPending=2000000 </script>
+ <script name="TTBL-AA-Qpid-04-03">-n TTBL-AA-Qpid-04 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=300 maxPending=2000000 </script>
+ <script name="TTBL-AA-Qpid-04-04">-n TTBL-AA-Qpid-04 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=400 maxPending=2000000 </script>
+ <script name="TTBL-AA-Qpid-04-05">-n TTBL-AA-Qpid-04 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=500 maxPending=2000000 </script>
+ <script name="TTBL-AA-Qpid-04-06">-n TTBL-AA-Qpid-04 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=600 maxPending=2000000 </script>
+ <script name="TTBL-AA-Qpid-04-07">-n TTBL-AA-Qpid-04 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=700 maxPending=2000000 </script>
+ <script name="TTBL-AA-Qpid-04-08">-n TTBL-AA-Qpid-04 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=800 maxPending=2000000 </script>
+ <script name="TTBL-AA-Qpid-04-09">-n TTBL-AA-Qpid-04 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=900 maxPending=2000000 </script>
+ <script name="TTBL-AA-Qpid-04-10">-n TTBL-AA-Qpid-04 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=1000 maxPending=2000000 </script>
+
+ <script name="PTBL-AA-Qpid-04-01">-n PTBL-AA-Qpid-04 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=5120 destinationCount=1 rate=10 maxPending=2000000 </script>
+ <script name="PTBL-AA-Qpid-04-02">-n PTBL-AA-Qpid-04 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=5120 destinationCount=1 rate=20 maxPending=2000000 </script>
+ <script name="PTBL-AA-Qpid-04-03">-n PTBL-AA-Qpid-04 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=5120 destinationCount=1 rate=30 maxPending=2000000 </script>
+ <script name="PTBL-AA-Qpid-04-04">-n PTBL-AA-Qpid-04 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=5120 destinationCount=1 rate=40 maxPending=2000000 </script>
+ <script name="PTBL-AA-Qpid-04-05">-n PTBL-AA-Qpid-04 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=5120 destinationCount=1 rate=50 maxPending=2000000 </script>
+ <script name="PTBL-AA-Qpid-04-06">-n PTBL-AA-Qpid-04 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=5120 destinationCount=1 rate=60 maxPending=2000000 </script>
+ <script name="PTBL-AA-Qpid-04-07">-n PTBL-AA-Qpid-04 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=5120 destinationCount=1 rate=70 maxPending=2000000 </script>
+ <script name="PTBL-AA-Qpid-04-08">-n PTBL-AA-Qpid-04 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=5120 destinationCount=1 rate=80 maxPending=2000000 </script>
+ <script name="PTBL-AA-Qpid-04-09">-n PTBL-AA-Qpid-04 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=5120 destinationCount=1 rate=90 maxPending=2000000 </script>
+ <script name="PTBL-AA-Qpid-04-10">-n PTBL-AA-Qpid-04 -d1M -s[100] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=true pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=1 commitBatchSize=1 batchSize=101 messageSize=5120 destinationCount=1 rate=100 maxPending=2000000 </script>
+
+ <!-- Low-latency broadcast of time sensitive events. Transient, no_ack. -->
+ <script name="TTBL-NA-Qpid-05-01">-n TTBL-NA-Qpid-05 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=400 maxPending=2000000 </script>
+ <script name="TTBL-NA-Qpid-05-02">-n TTBL-NA-Qpid-05 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=800 maxPending=2000000 </script>
+ <script name="TTBL-NA-Qpid-05-03">-n TTBL-NA-Qpid-05 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=1200 maxPending=2000000 </script>
+ <script name="TTBL-NA-Qpid-05-04">-n TTBL-NA-Qpid-05 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=1600 maxPending=2000000 </script>
+ <script name="TTBL-NA-Qpid-05-05">-n TTBL-NA-Qpid-05 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=2000 maxPending=2000000 </script>
+ <script name="TTBL-NA-Qpid-05-06">-n TTBL-NA-Qpid-05 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=2400 maxPending=2000000 </script>
+ <script name="TTBL-NA-Qpid-05-07">-n TTBL-NA-Qpid-05 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=2800 maxPending=2000000 </script>
+ <script name="TTBL-NA-Qpid-05-08">-n TTBL-NA-Qpid-05 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=3200 maxPending=2000000 </script>
+ <script name="TTBL-NA-Qpid-05-09">-n TTBL-NA-Qpid-05 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=3600 maxPending=2000000 </script>
+ <script name="TTBL-NA-Qpid-05-10">-n TTBL-NA-Qpid-05 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=256 destinationCount=1 rate=4000 maxPending=2000000 </script>
+
+ <!-- Low-latency broadcast of medium sized time sensitive events. Transient, no_ack. -->
+ <script name="TTBL-NA-Qpid-06-01">-n TTBL-NA-Qpid-06 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=100 maxPending=2000000 </script>
+ <script name="TTBL-NA-Qpid-06-02">-n TTBL-NA-Qpid-06 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=200 maxPending=2000000 </script>
+ <script name="TTBL-NA-Qpid-06-03">-n TTBL-NA-Qpid-06 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=300 maxPending=2000000 </script>
+ <script name="TTBL-NA-Qpid-06-04">-n TTBL-NA-Qpid-06 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=400 maxPending=2000000 </script>
+ <script name="TTBL-NA-Qpid-06-05">-n TTBL-NA-Qpid-06 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=500 maxPending=2000000 </script>
+ <script name="TTBL-NA-Qpid-06-06">-n TTBL-NA-Qpid-06 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=600 maxPending=2000000 </script>
+ <script name="TTBL-NA-Qpid-06-07">-n TTBL-NA-Qpid-06 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=700 maxPending=2000000 </script>
+ <script name="TTBL-NA-Qpid-06-08">-n TTBL-NA-Qpid-06 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=800 maxPending=2000000 </script>
+ <script name="TTBL-NA-Qpid-06-09">-n TTBL-NA-Qpid-06 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=900 maxPending=2000000 </script>
+ <script name="TTBL-NA-Qpid-06-10">-n TTBL-NA-Qpid-06 -d1M -s[1000] -c[1] -o $QPID_WORK/results -t testPingLatency org.apache.qpid.ping.PingLatencyTestPerf persistent=false pubsub=true uniqueDests=false numConsumers=50 transacted=false consTransacted=false consAckMode=257 commitBatchSize=1 batchSize=1001 messageSize=5120 destinationCount=1 rate=1000 maxPending=2000000 </script>
+
+ <!-- Failover Tests. -->
+ <script name="FT-Qpid-01">-n FT-Qpid-01 -s[2500] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 batchSize=10000 transacted=true properties=failovertest.properties failBeforeSend=true -o $QPID_WORK/results</script>
+ <script name="FT-Qpid-02">-n FT-Qpid-02 -s[2500] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 batchSize=10000 transacted=true properties=failovertest.properties failAfterSend=true -o $QPID_WORK/results</script>
+ <script name="FT-Qpid-03">-n FT-Qpid-03 -s[2500] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 batchSize=1000 transacted=true properties=failovertest.properties failAfterCommit=true -o $QPID_WORK/results</script>
+ <script name="FT-Qpid-04">-n FT-Qpid-04 -s[2500] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 batchSize=1000 properties=failovertest.properties transacted=false failBeforeSend=true -o $QPID_WORK/results</script>
+ <script name="FT-Qpid-05">-n FT-Qpid-05 -s[2500] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 batchSize=1000 properties=failovertest.properties transacted=false failAfterSend=true -o $QPID_WORK/results</script>
+ <script name="FT-Qpid-01-P">-n FT-Qpid-01-P -s[2500] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 batchSize=1000 transacted=true properties=failovertest.properties failBeforeSend=true -o $QPID_WORK/results</script>
+ <script name="FT-Qpid-02-P">-n FT-Qpid-02-P -s[2500] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 batchSize=1000 transacted=true properties=failovertest.properties failAfterSend=true -o $QPID_WORK/results</script>
+ <script name="FT-Qpid-03-P">-n FT-Qpid-03-P -s[2500] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 batchSize=1000 transacted=true properties=failovertest.properties failAfterCommit=true -o $QPID_WORK/results</script>
+ <script name="FT-Qpid-04-P">-n FT-Qpid-04-P -s[250] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 batchSize=1000 properties=failovertest.properties transacted=false failBeforeSend=true -o $QPID_WORK/results</script>
+ <script name="FT-Qpid-05-P">-n FT-Qpid-05-P -s[250] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 batchSize=1000 properties=failovertest.properties transacted=false failAfterSend=true -o $QPID_WORK/results</script>
+
+</scripts>
diff --git a/java/perftests/src/main/java/perftests.log4j b/java/perftests/src/main/java/perftests.log4j
deleted file mode 100644
index 3bd8c201f8..0000000000
--- a/java/perftests/src/main/java/perftests.log4j
+++ /dev/null
@@ -1,45 +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.
-#
-log4j.rootLogger=${root.logging.level}
-
-
-log4j.logger.org.apache.qpid=${amqj.logging.level}, console
-log4j.additivity.org.apache.qpid=false
-
-log4j.logger.org.apache.qpid.requestreply=${amqj.test.logging.level}
-log4j.logger.org.apache.qpid.pingpong=${amqj.test.logging.level}
-log4j.logger.org.apache.qpid.ping=${amqj.test.logging.level}
-log4j.logger.org.apache.qpid.topic=${amqj.test.logging.level}
-
-
-log4j.logger.uk.co.thebadgerset.junit.extensions=${badger.level}, console
-log4j.additivity.uk.co.thebadgerset.junit.extensions=false
-
-log4j.appender.console=org.apache.log4j.ConsoleAppender
-log4j.appender.console.Threshold=all
-log4j.appender.console.layout=org.apache.log4j.PatternLayout
-
-log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n
-#log4j.appender.console.layout.ConversionPattern=%t %p [%c] %m%n
-
-log4j.appender.fileApp=org.apache.log4j.FileAppender
-log4j.appender.fileApp.file=${log.dir}/perftests.volumetest.log
-log4j.appender.fileApp.Threshold=info
-log4j.appender.fileApp.append=false
-log4j.appender.fileApp.layout=org.apache.log4j.PatternLayout
diff --git a/java/plugins/pom.xml b/java/plugins/pom.xml
deleted file mode 100644
index 161656471f..0000000000
--- a/java/plugins/pom.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<project>
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.qpid</groupId>
- <artifactId>jython-plugin</artifactId>
- <packaging>maven-plugin</packaging>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <name>Jython Launcher</name>
-
- <parent>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid</artifactId>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <relativePath>../pom.xml</relativePath>
- </parent>
-
- <properties>
- <!-- This is an assembly/distribution pom so no test code exists -->
- <maven.test.skip>true</maven.test.skip>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.maven</groupId>
- <artifactId>maven-plugin-api</artifactId>
- <version>2.0</version>
- </dependency>
-
- <dependency>
- <groupId>org.python</groupId>
- <artifactId>jython</artifactId>
- <version>2.2-rc1</version>
- </dependency>
- </dependencies>
-</project>
diff --git a/java/plugins/src/main/java/org/apache/qpid/plugins/JythonMojo.java b/java/plugins/src/main/java/org/apache/qpid/plugins/JythonMojo.java
deleted file mode 100644
index 85dffeb4bf..0000000000
--- a/java/plugins/src/main/java/org/apache/qpid/plugins/JythonMojo.java
+++ /dev/null
@@ -1,100 +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.
- *
- */
-package org.apache.qpid.plugins;
-
-import java.io.File;
-import java.io.IOException;
-
-import org.apache.maven.plugin.AbstractMojo;
-import org.apache.maven.plugin.MojoExecutionException;
-
-import org.python.util.jython;
-
-
-/**
- * JythonMojo
- *
- * @author Rafael H. Schloming
- *
- * @goal jython
- */
-
-public class JythonMojo extends AbstractMojo
-{
-
- /**
- * Arguments to jython.
- *
- * @parameter
- */
- private String[] params = new String[0];
-
- /**
- * Source file.
- *
- * @parameter
- */
- private File[] sources;
-
- /**
- * Optional timestamp.
- *
- * @parameter
- */
- private File timestamp;
-
- public void execute() throws MojoExecutionException
- {
- boolean stale = true;
-
- if (sources != null && sources.length > 0 && timestamp != null)
- {
- stale = false;
- for (File source : sources)
- {
- if (source.lastModified() > timestamp.lastModified())
- {
- stale = true;
- break;
- }
- }
- }
-
- if (stale)
- {
- jython.main(params);
-
- if (timestamp != null)
- {
- try
- {
- timestamp.createNewFile();
- }
- catch (IOException e)
- {
- throw new MojoExecutionException("cannot create timestamp", e);
- }
- timestamp.setLastModified(System.currentTimeMillis());
- }
- }
- }
-
-}
diff --git a/java/pom.xml b/java/pom.xml
deleted file mode 100644
index 084358a6e8..0000000000
--- a/java/pom.xml
+++ /dev/null
@@ -1,787 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership. The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied. See the License for the
-specific language governing permissions and limitations
-under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid</artifactId>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <name>Qpid</name>
- <url>http://cwiki.apache.org/confluence/display/qpid</url>
-
- <packaging>pom</packaging>
-
- <scm>
- <connection>scm:svn:http://svn.apache.org/repos/asf/incubator/qpid/branches/M3/java</connection>
- <developerConnection>scm:svn:http://svn.apache.org/repos/asf/incubator/qpid/branches/M3/java</developerConnection>
- <url>http://svn.apache.org/viewvc/incubator/qpid/branches/M3/java</url>
- </scm>
-
- <prerequisites>
- <maven>2.0.4</maven>
- </prerequisites>
-
- <distributionManagement>
-
- <snapshotRepository>
- <id>apache.snapshots</id>
- <name>Apache SNAPSHOT Repository</name>
- <url>scp://people.apache.org/www/people.apache.org/repo/m2-snapshot-repository</url>
- </snapshotRepository>
-
- <repository>
- <id>apache.incubating</id>
- <name>Apache Incubating Repository</name>
- <url>scp://people.apache.org/www/people.apache.org/repo/m2-incubating-repository</url>
- </repository>
-
- <!--
- <snapshotRepository>
- <uniqueVersion>true</uniqueVersion>
- <id>snapshot-repo</id>
- <name>Local Snapshot Repository</name>
- <url>file://${basedir}/${topDirectoryLocation}/snapshots</url>
- <layout>default</layout>
- </snapshotRepository>
- -->
-
- <!-- Qpid has a Wiki site, maven generated site not used. This is just so that it can be created locally for viewing the reports. -->
- <site>
- <id>Qpid_Site</id>
- <name>Qpid Site</name>
- <url>file:/temp</url>
- </site>
-
- </distributionManagement>
-
- <inceptionYear>2006</inceptionYear>
- <mailingLists>
- <mailingList>
- <name>Qpid Developer List</name>
- <subscribe>qpid-dev-subscribe@incubator.apache.org</subscribe>
- <unsubscribe>qpid-dev-unsubscribe@incubator.apache.org</unsubscribe>
- <post>qpid-dev@incubator.apache.org</post>
- <archive>http://mail-archives.apache.org/mod_mbox/incubator-qpid-dev</archive>
- </mailingList>
- <mailingList>
- <name>Qpid Commits List</name>
- <subscribe>qpid-commits-subscribe@incubator.apache.org</subscribe>
- <unsubscribe>qpid-commits-unsubscribe@incubator.apache.org</unsubscribe>
- <post>qpid-commits@incubator.apache.org</post>
- <archive>http://mail-archives.apache.org/mod_mbox/incubator-qpid-commits</archive>
- </mailingList>
- </mailingLists>
-
- <licenses>
- <license>
- <name>The Apache Software License, Version 2.0</name>
- <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
- <distribution>repo</distribution>
- </license>
- </licenses>
-
- <organization>
- <name>Apache Software Foundation</name>
- <url>http://www.apache.org/</url>
- </organization>
-
- <properties>
- <topDirectoryLocation>.</topDirectoryLocation>
-
- <surefire.fork.mode>never</surefire.fork.mode>
- <surefire.format>brief</surefire.format>
- <surefire.usefile>true</surefire.usefile>
- <compile.forked>false</compile.forked>
- <java.source.version>1.5</java.source.version>
- <compile.flags>-Xlint:fallthrough,finally</compile.flags>
-
- <!--
- This should always point to a default minimal log4j configuration that all developers are happy with as a useable default. To use your own
- log4j preferences set up an alternative in your settings.xml and avoid corrupting the default with private preferences.
- -->
- <!--<log4j.configuration>file:/${topDirectoryLocation}/etc/log4j.xml</log4j.configuration>-->
- <amqj.logging.level>warn</amqj.logging.level> <!-- This is referenced in the default log4j.xml -->
-
- <!--Versions for various plugins and features -->
- <antrun.version>1.2-SNAPSHOT</antrun.version>
- <!--<assembly.version>2.2-SNAPSHOT</assembly.version>-->
- <assembly.version>2.1</assembly.version>
- <cobertura.version>2.0</cobertura.version>
- <compiler.version>2.0.1</compiler.version>
- <dependency.plugin.version>1.0</dependency.plugin.version>
- <eclipse.plugin.version>2.2</eclipse.plugin.version>
- <jar.version>2.0</jar.version>
- <javadoc.version>2.0</javadoc.version>
- <junit.version>3.8.1</junit.version>
- <jxr.version>2.0</jxr.version>
- <mprojectinfo.version>2.0</mprojectinfo.version>
- <resources.version>2.2</resources.version>
- <site.version>2.0-beta-5</site.version>
- <surefire-report.version>2.1-SNAPSHOT</surefire-report.version>
- <surefire.version>2.2</surefire.version>
- <retrotranslator.plugin.version>1.0-alpha-2-SNAPSHOT</retrotranslator.plugin.version>
- <build-helper.plugin.version>1.0</build-helper.plugin.version>
- <eclipse.workspace.dir>${basedir}/${topDirectoryLocation}/../workspace</eclipse.workspace.dir>
- <clover.license.pathname>/set/clover/license/path/here</clover.license.pathname>
-
- <!-- Override these in local settings.xml to perform verification. Cannot make assumptions about 1.4 Jdk location to turn this on by default. -->
- <retrotranslator.verify>false</retrotranslator.verify>
- <retrotranslator.1.4-rt-path>pathto/rt.jar</retrotranslator.1.4-rt-path>
- <retrotranslator.1.4-jce-path>pathto/jce.jar</retrotranslator.1.4-jce-path>
- <retrotranslator.1.4-jsse-path>pathto/jsse.jar</retrotranslator.1.4-jsse-path>
- <retrotranslator.1.4-sasl-path>pathto/sasl.jar</retrotranslator.1.4-sasl-path>
-
- </properties>
-
- <modules>
- <module>common</module>
- <module>broker</module>
- <module>client</module>
- <module>plugins</module>
- <module>systests</module>
- <module>perftests</module>
- <module>integrationtests</module>
- <module>management/eclipse-plugin</module>
- <module>client/example</module>
- <module>client-java14</module>
- <module>junit-toolkit</module>
- <module>junit-toolkit-maven-plugin</module>
- </modules>
-
- <build>
- <resources>
-
- <resource>
- <targetPath>META-INF/</targetPath>
- <filtering>false</filtering>
- <directory>../resources</directory>
- <includes>
- <include>DISCLAIMER</include>
- <include>LICENSE</include>
- <include>NOTICE</include>
- </includes>
- </resource>
-
- <resource>
- <directory>src/main/java</directory>
- <excludes>
- <exclude>**/*.java</exclude>
- <exclude>**/log4j.properties</exclude>
- </excludes>
- </resource>
- <resource>
- <directory>src/main/resources</directory>
- </resource>
- <resource>
- <directory>src/main/resources-filtered</directory>
- <filtering>true</filtering>
- </resource>
- <resource>
- <directory>target/generated/src/main/resources</directory>
- </resource>
- </resources>
-
- <testResources>
- <testResource>
- <targetPath>META-INF/</targetPath>
- <filtering>false</filtering>
- <directory>../resources</directory>
- <includes>
- <include>DISCLAIMER</include>
- <include>LICENSE</include>
- <include>NOTICE</include>
- </includes>
- </testResource>
-
- <testResource>
- <directory>src/test/java</directory>
- <excludes>
- <exclude>**/*.java</exclude>
- </excludes>
- </testResource>
- <testResource>
- <directory>src/test/resources</directory>
- </testResource>
- <testResource>
- <directory>src/test/java</directory>
- <excludes>
- <exclude>**/*.xml</exclude>
- </excludes>
- <filtering>true</filtering>
- </testResource>
- </testResources>
-
- <pluginManagement>
- <plugins>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-antrun-plugin</artifactId>
- <version>${antrun.version}</version>
- <dependencies>
- <dependency>
- <groupId>ant</groupId>
- <artifactId>ant-nodeps</artifactId>
- <version>1.6.5</version>
- </dependency>
- </dependencies>
-
- <executions>
-
- <!-- This Ant task writes the module name, version and the Subversion version information out to a properties file.
- The svnversion command must be available to run from the command line for this to work. The build will not fail if
- svnversion cannot be run though.
- This is done during the 'compile' phase to reflect the version of the currently compiled code and to ensure that
- these properties are up to date when running from a file system classpath. Consider moving this to, or running a second
- time, during the 'package' phase to capture the version of any resources added to jar files.
- This svnversion command is always run in the top directory to accurately reflect the svnversion range accross all modules
- at the time of the build.
- The properties are placed into a file 'qpidversion.properties' in the target/classes directory of any child module
- that runs this plugin.
- The 'qpidversion.properties' file is loaded by the org.apache.qpid.common.QpidProperties class.
- Be carefull of the possibility that the 'common' module may run this antrun plugin and recieve its own set of
- qpidversion.properties and then the client or broker being built against an older version of the common library ending
- up with the wrong version information. This is unlikely to happen because the client or broker should pick up its own
- properties from the classpath first. If this happens it will be obvious because the productName property will be
- 'Qpid Common Utilities'. If this is a problem then push this ant task down into the client and broker poms and remove it
- from here.
- -->
- <execution>
- <id>version_properties</id>
- <phase>compile</phase>
- <configuration>
- <tasks>
-
- <exec executable="svnversion" spawn="false" failifexecutionfails="false"
- dir="${topDirectoryLocation}" outputproperty="svnversion">
- <arg line="."/>
- </exec>
-
- <!-- Write the version.properties out. -->
- <propertyfile file="target/classes/qpidversion.properties">
- <entry key="qpid.svnversion" value="${svnversion}"/>
- <entry key="qpid.name" value="${project.name}"/>
- <entry key="qpid.version" value="${project.version}"/>
- </propertyfile>
-
- </tasks>
- </configuration>
- <goals>
- <goal>run</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
-
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>retrotranslator-maven-plugin</artifactId>
- <version>${retrotranslator.plugin.version}</version>
- </plugin>
-
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <version>${build-helper.plugin.version}</version>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <version>${jar.version}</version>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-resources-plugin</artifactId>
- <version>${resources.version}</version>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>${compiler.version}</version>
- <configuration>
- <source>${java.source.version}</source>
- <target>${java.source.version}</target>
- <fork>${compile.forked}</fork>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <version>${surefire.version}</version>
- <configuration>
- <excludes>
- <exclude>**/*$*</exclude>
- </excludes>
- <reportFormat>${surefire.format}</reportFormat>
- <useFile>${surefire.usefile}</useFile>
- <forkMode>${surefire.fork.mode}</forkMode>
- <childDelegation>false</childDelegation>
- <argLine>-ea</argLine>
- <systemProperties>
- <property>
- <name>amqj.logging.level</name>
- <value>${amqj.logging.level}</value>
- </property>
- <property>
- <name>log4j.configuration</name>
- <value>${log4j.configuration}</value>
- </property>
- </systemProperties>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-site-plugin</artifactId>
- <version>${site.version}</version>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-eclipse-plugin</artifactId>
- <version>${eclipse.plugin.version}</version>
- <configuration>
- <!--downloadSources>true</downloadSources-->
- <buildcommands>
- <java.lang.String>org.eclipse.jdt.core.javabuilder</java.lang.String>
- </buildcommands>
- <projectnatures>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </projectnatures>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-idea-plugin</artifactId>
- <configuration>
- <!--downloadSources>true</downloadSources-->
- <downloadJavadocs>true</downloadJavadocs>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-clover-plugin</artifactId>
- <version>2.3</version>
- <configuration>
- <licenseLocation>${clover.license.pathname}</licenseLocation>
- <jdk>${java.source.version}</jdk>
- </configuration>
- <executions>
- <execution>
- <phase>verify</phase>
- <goals>
- <goal>instrument</goal>
- <goal>aggregate</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
-
- <!--
- <plugin>
- <groupId>org.apache.qpid</groupId>
- <artifactId>junit-toolkit-maven-plugin</artifactId>
- <version>0.7.1-SNAPSHOT</version>
- </plugin>
- -->
- </plugins>
- </pluginManagement>
-
- <defaultGoal>install</defaultGoal>
-
- </build>
-
- <dependencyManagement>
- <dependencies>
-
- <!-- Comile time only dependencies. -->
- <dependency>
- <groupId>net.sf.retrotranslator</groupId>
- <artifactId>retrotranslator-runtime</artifactId>
- <version>1.2.1</version>
- <scope>provided</scope>
- </dependency>
-
- <!-- Compilation and run time dependecies. -->
- <dependency>
- <groupId>commons-cli</groupId>
- <artifactId>commons-cli</artifactId>
- <version>1.0</version>
- </dependency>
- <dependency>
- <groupId>commons-codec</groupId>
- <artifactId>commons-codec</artifactId>
- <version>1.3</version>
- </dependency>
- <dependency>
- <groupId>commons-collections</groupId>
- <artifactId>commons-collections</artifactId>
- <version>3.2</version>
- </dependency>
- <dependency>
- <groupId>commons-configuration</groupId>
- <artifactId>commons-configuration</artifactId>
- <version>1.2</version>
- </dependency>
- <dependency>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- <version>2.1</version>
- </dependency>
- <dependency>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- <version>1.0.4</version>
- </dependency>
- <dependency>
- <groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-jms_1.1_spec</artifactId>
- <version>1.0</version>
- </dependency>
- <dependency>
- <groupId>xml-resolver</groupId>
- <artifactId>xml-resolver</artifactId>
- <version>1.1</version>
- </dependency>
- <dependency>
- <groupId>net.sf.saxon</groupId>
- <artifactId>saxon</artifactId>
- <version>8.7</version>
- </dependency>
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.12</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-simple</artifactId>
- <version>1.4.0</version>
- </dependency>
- <dependency>
- <groupId>org.apache.mina</groupId>
- <artifactId>mina-core</artifactId>
- <version>1.0.1</version>
- </dependency>
- <dependency>
- <groupId>org.apache.mina</groupId>
- <artifactId>mina-filter-ssl</artifactId>
- <version>1.0.1</version>
- </dependency>
- <!--
- <dependency>
- <groupId>org.apache.derby</groupId>
- <artifactId>derby</artifactId>
- <version>10.3.2.1</version>
- </dependency>
- <dependency>
- <groupId>org.apache.mina</groupId>
- <artifactId>mina-java5</artifactId>
- <version>1.0.1</version>
- </dependency>
- -->
- <dependency>
- <groupId>backport-util-concurrent</groupId>
- <artifactId>backport-util-concurrent</artifactId>
- <version>2.2</version>
- </dependency>
-
- <!-- Test Dependencies -->
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>${junit.version}</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.easymock</groupId>
- <artifactId>easymockclassextension</artifactId>
- <version>2.2</version>
- <scope>test</scope>
- </dependency>
-
- <!--
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>junit-toolkit</artifactId>
- <version>0.7.1-SNAPSHOT</version>
- <scope>compile</scope>
- </dependency>
- -->
-
- <!-- Qpid Version Dependencies -->
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-common</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-client</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-broker</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-perftests</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-systests</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-mgmt-core</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-mgmt-client</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>junit-toolkit</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>junit-toolkit-maven-plugin</artifactId>
- <version>${project.version}</version>
- </dependency>
- </dependencies>
- </dependencyManagement>
-
- <reporting>
- <plugins>
- <!--
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>cobertura-maven-plugin</artifactId>
- <version>${cobertura.version}</version>
- </plugin>
- -->
-
- <!-- Run the javadoc report. -->
- <!--
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-javadoc-plugin</artifactId>
- <configuration>
- <tags>
- <tag>
- <name>todo</name>
- <placement>a</placement>
- <head>To do:</head>
- </tag>
- </tags>
- </configuration>
- </plugin>
- -->
-
- <!-- Generate the clover coverage report. -->
- <!--
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-clover-plugin</artifactId>
- </plugin>
- -->
-
- <!-- Standard Maven project info reports. -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-project-info-reports-plugin</artifactId>
- <version>${mprojectinfo.version}</version>
- </plugin>
-
- <!-- Generate the surefire test report. -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-report-plugin</artifactId>
- <version>${surefire-report.version}</version>
- </plugin>
-
- <!-- Generate the TODO lists. -->
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>taglist-maven-plugin</artifactId>
- </plugin>
-
- <!-- Generate the source code cross reference. -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jxr-plugin</artifactId>
- </plugin>
-
- <!-- Minimal checkstyle rules. -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-checkstyle-plugin</artifactId>
- <configuration>
- <configLocation>${basedir}/${topDirectoryLocation}/etc/coding_standards.xml</configLocation>
- <headerLocation>${basedir}/${topDirectoryLocation}/etc/license_header.txt</headerLocation>
- </configuration>
- </plugin>
-
- <!-- Generate report on changed files. -->
- <!--
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-changelog-plugin</artifactId>
- </plugin>
- -->
-
- </plugins>
- </reporting>
-
- <repositories>
- <!-- not picking up any snapshots at the moment
- <repository>
- <id>apache.snapshots</id>
- <name>Apache SNAPSHOT Repository</name>
- <url>http://people.apache.org/repo/m2-snapshot-repository</url>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- </repository>
- -->
- <repository>
- <id>Codehaus Snapshots</id>
- <url>http://snapshots.repository.codehaus.org/</url>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- <releases>
- <enabled>false</enabled>
- </releases>
- </repository>
-
- <!--
- <repository>
- <id>junittoolkit.snapshots</id>
- <url>http://junit-toolkit.svn.sourceforge.net/svnroot/junit-toolkit/snapshots/</url>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- </repository>
- -->
-
- </repositories>
-
- <pluginRepositories>
- <pluginRepository>
- <id>apache.snapshots</id>
- <name>Apache SNAPSHOT Repository</name>
- <url>http://people.apache.org/repo/m2-snapshot-repository</url>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- </pluginRepository>
-
- <pluginRepository>
- <id>codehaus.snapshots</id>
- <name>Codehaus SNAPSHOT Repository</name>
- <url>http://snapshots.repository.codehaus.org</url>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- </pluginRepository>
-
- <!--
- <pluginRepository>
- <id>junittoolkit.plugin.snapshots</id>
- <url>http://junit-toolkit.svn.sourceforge.net/svnroot/junit-toolkit/snapshots/</url>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- </pluginRepository>
- -->
-
- </pluginRepositories>
-
- <profiles>
- <profile>
- <id>fastinstall</id>
- <properties>
- <maven.test.skip>true</maven.test.skip>
- <skip.python.tests>true</skip.python.tests>
- </properties>
- </profile>
-
- <profile>
- <id>nochecks</id>
- </profile>
-
- <profile>
- <id>setup.eclipse</id>
- <build>
- <defaultGoal>process-test-sources</defaultGoal>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-eclipse-plugin</artifactId>
- <executions>
- <execution>
- <id>setup.eclipse.project</id>
- <phase>process-test-sources</phase>
- <goals>
- <goal>eclipse</goal>
- </goals>
- </execution>
- <execution>
- <id>setup.eclipse.workspace</id>
- <phase>process-test-sources</phase>
- <goals>
- <goal>add-maven-repo</goal>
- </goals>
- <configuration>
- <workspace>${eclipse.workspace.dir}</workspace>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
- </profile>
-<!--- Build profile to ignore test failures. -->
-<profile>
-<id>ignore</id>
-<properties>
-<maven.test.failure.ignore>true</maven.test.failure.ignore>
-<maven.test.error.ignore>true</maven.test.error.ignore>
-</properties>
-</profile>
- </profiles>
-</project>
diff --git a/java/release-docs/RELEASE_NOTES.txt b/java/release-docs/RELEASE_NOTES.txt
index 1004ec62b4..690b04dfc0 100644
--- a/java/release-docs/RELEASE_NOTES.txt
+++ b/java/release-docs/RELEASE_NOTES.txt
@@ -1,105 +1,35 @@
-Apache Incubator Qpid Java M2 Release Notes
+Apache Qpid Incubating Java M4 Release Notes
-------------------------------------------
-The Qpid M2 release contains support the for AMQP 0-8 specification.
-You can access the 0-8 specification using the following link.
+The Qpid M4 release contains support for AMQP 0-8, 0-9 and 0-10. You
+can access the specifications from
http://www.amqp.org/tikiwiki/tiki-index.php?page=Download
-For full details of Qpid capabilities, as they currently stand, see our
-detailed project documentation at:
+For full details of Apache Qpid's capabilities see our detailed
+project documentation at:
http://cwiki.apache.org/confluence/display/qpid/Qpid+Java+Documentation
From the link above you can access our Getting Started Guide, FAQ, Build How To
and detailed developer documentation.
+New features, Improvements and Bug fixes
+----------------------
-Known Issues/Outstanding Work
------------------------------
-
-You can view the outstanding task list for Qpid by visiting our JIRA:
-http://issues.apache.org/jira/browse/QPID
-
-These issues are moved to M3 release.
-
-Here is a filtered list for your convinience
----------------------------------------
-New Feature QPID-274 add connection configuratble timeout on waituntilStateHasChanged
-New Feature QPID-156 Implement persistence to disk for Qpid
-New Feature QPID-155 Add ability to configure (on/off) queue creation on demand
-New Feature QPID-43 Multiple-AMQP version support in the broker
-New Feature QPID-28 Allow user to select policy for undeliverable message handling
-New Feature QPID-27 Introduce user configurable redlivery delay
-New Feature QPID-22 Provide run scripts for clustered broker
-
-Improvement QPID-430 Message Age Alerting should not depend upon queue activity
-Improvement QPID-19 Add protocol logging capability to client and broker
-Improvement QPID-11 Move protocol literals from code to AMQConstant
-
-Bug QPID-539 HeadersExchange doesnot correctly implement isBound
-Bug QPID-517 Broker doesn't return NO_CONSUMERS code for an immediate message, when the consumer is disconnected.
-Bug QPID-469 Redelivered information is currently recorded per message it should be per message per queue.
-Bug QPID-463 Java client doesn't close connection gracefully when faced with broker with unsuported protocol version
-Bug QPID-462 Exclusive queues and with subscription that 'filtersMessages' will build up messages it doesn't hasInterest() in.
-
-Bug QPID-397 Client closeure can be processed before final message ack.
-Bug QPID-396 Broker OutOfMemory Error handling
-Bug QPID-377 NumberFormatException thrown by broker when running one performance test
-Bug QPID-293 setting MessageListener after connection has started can cause messages to be "lost" on a internal delivery queue.
+A security related problem was addressed. If Base64MD5 passwords are
+turned on on the broker and it has been configured to use JMXMP via
+the addition of jxmremote_optional.jar to the classpath, it is
+possible for an attacker to bypass the authentication on the JMX
+management interface due to a bug in password verification.
-Bug QPID-185 Amend Java Broker handling of ifUnused & ifEmpty flags
-Bug QPID-168 qpid-server.bat needs updated to support same arguments/features as qpid-server (via qpid-run) bash script
+A new command line management interface was added (qpid-cli)
+A full list of changes can be found at:
+https://issues.apache.org/jira/secure/ReleaseNote.jspa?version=12313279&styleName=Text&projectId=12310520
-M2 Tasks Completed
--------------------
-The set of JIRA tasks completed as part of the M2 effort is available at:
-https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12310520&styleName=Html&version=12312116
-
-
-Here is a filtered (by Java components) version of the JIRA items
-
-Task QPID-190 refactoring the java broker mbean classes
-Task QPID-125 Moving eclipse plugin for broker management to Maven
-Task QPID-93 Delete the old management modules (trunk\qpid\java\management)
-
-New Feature QPID-428 Add login functionality for a qpid server from the management console
-New Feature QPID-418 Add ability to save user preferences to Java Management Console
-New Feature QPID-170 Enhance Management features to support moving a message from one queue to another
-
-Improvement QPID-482 [Java] Small performance tweaks
-Improvement QPID-466 Create STRICT_AMQP System property to disable JMS extensions in Java client
-Improvement QPID-453 AMQShortString should implement Comparable
-Improvement QPID-422 Consolidate notification view to display all user configured notifications on one view
-Improvement QPID-421 Provide enumerated description for static constants including delivery mode
-Improvement QPID-420 Add client id to information displayed about connections on management console
-Improvement QPID-419 Introduce read-only and modify authorisation for all objects in a virtual host
-Improvement QPID-129 improving Broker MBeans
-
-Bug QPID-540 Transient Broker throws NullPointerException and locks up.
-Bug QPID-538 [Memory Leak] Connecting lots of consumers causes the broker memory to leak
-Bug QPID-537 Make AMQMessage.incrementReference public
-Bug QPID-531 [Memory Leak] Broker retains messages that are consumed with NO_ACK
-Bug QPID-527 encoding issue
-Bug QPID-508 [Memory Leak] Broker does not return mandatory messages sent outside of a transaction.
-Bug QPID-476 AMQProtocolSession channelId2SessionMap does not have sessions removed
-Bug QPID-472 Creation of TemporaryQueues will not guarantee unqiue queue names if created rapidly.
-Bug QPID-471 UserManagement panel lists all users but only after a View Users has been executed and is not updated on Create/Delete User
+Known Issues/Outstanding Work
+-----------------------------
-Bug QPID-467 Complete Interop Testing
-Bug QPID-465 Incorrect Exception thrown from send() method.
-Bug QPID-459 Broker doesn't correctly handle noLocal consumers when messages are pre-exisiting on queues.
-Bug QPID-458 Queue Browsing Broken
-Bug QPID-454 Message 'taken' notion is per message. But should be per message per queue
-Bug QPID-443 Abruptly disconnecting client on transaction publish causes error
-Bug QPID-440 Can create dangling transactions on unroutable messages.
-Bug QPID-436 topic exchange doesn't obey the mandatory flag
-Bug QPID-414 Authentication requires plain text passwords in password file
-Bug QPID-408 Queue Depth data incorrect
-Bug QPID-290 Java broker does not honor maximum number of channels threshold
-Bug QPID-276 Potential race condition in AMQChannel
-Bug QPID-200 set/get Destination not implemented in JMSMessage impl
-Bug QPID-166 Check for pre conditions to satisfy JMS spec requirments
-Bug QPID-162 over 600 warnings when building under Eclipse
-Bug QPID-159 The following Interface implementations do not throw Exceptions as required by the spec
+You can view the outstanding task list for Qpid by visiting our JIRA:
+http://issues.apache.org/jira/browse/QPID
diff --git a/java/release-docs/RELEASE_NOTES_M1.txt b/java/release-docs/RELEASE_NOTES_M1.txt
deleted file mode 100644
index 638f4c6f61..0000000000
--- a/java/release-docs/RELEASE_NOTES_M1.txt
+++ /dev/null
@@ -1,74 +0,0 @@
-Apache Incubator Qpid Java M1 Release Notes
--------------------------------------------
-
-The Qpid M1 release is intended to serve as a useful baseline release
-for the project, allowing interested users to use the current featureset.
-
-For full details of Qpid capabilities, as they currently stand, see our
-detailed project documentation at:
-
-http://cwiki.apache.org/confluence/display/qpid/Qpid+Java+Documentation
-
-From the link above you can access our Getting Started Guide, FAQ, Build How To
-and detailed developer documentation.
-
-
-Known Issues/OUtstanding Work
------------------------------
-
-You can view the outstanding task list for Qpid by visiting our JIRA:
-
-http://issues.apache.org/jira/browse/QPID
-
-
-M1 Tasks Completed
--------------------
-
-The set of JIRA tasks completed as part of the M1 effort is available at:
-
-http://cwiki.apache.org/confluence/display/qpid/Qpid+Java+M1+Release+Notes
-
-This list is copied below for convenience:
-
-Bugs
-----
-http://issues.apache.org/jira/browse/QPID-4 - Remove '/' and ':' from generated queue names
-http://issues.apache.org/jira/browse/QPID-7 - Occasionally messages are ack'd more than once
-http://issues.apache.org/jira/browse/QPID-10- Broker throughput falls off with transactions
-http://issues.apache.org/jira/browse/QPID-56 - AMQQueueMBean - MessageCount on the management interface is not correct.
-http://issues.apache.org/jira/browse/QPID-58 - Creating a QueueReceiver results in ClassCastException
-http://issues.apache.org/jira/browse/QPID-66 - AMQSession implementation of TopicSession and QueueSession interfaces not JMS compliant
-http://issues.apache.org/jira/browse/QPID-68 - Ant build system fails if the project path contains a space
-http://issues.apache.org/jira/browse/QPID-69 - Race condition in Delivery Manager
-
-Improvements
-------------
-http://issues.apache.org/jira/browse/QPID-36 - Add high and low watermark to flow control
-http://issues.apache.org/jira/browse/QPID-44 - Add high and low watermark to flow control
-http://issues.apache.org/jira/browse/QPID-57 - AMQQueueMBean - Message header attributes should be sent along with message content.
-
-
-New Features
-------------
-http://issues.apache.org/jira/browse/QPID-13 - Add option to include prefix and suffix in log file name for broker
-http://issues.apache.org/jira/browse/QPID-23 - Extend JNDI support provided to include initial context factory
-http://issues.apache.org/jira/browse/QPID-29 - Provide support for using Qpid JMX with Tivoli for application monitoring
-http://issues.apache.org/jira/browse/QPID-30 - Allow configuration of working/log directories written to by broker
-http://issues.apache.org/jira/browse/QPID-40 - Implement tx.select, tx.commit & tx.rollback from AMQP
-
-
-Tasks
------
-http://issues.apache.org/jira/browse/QPID-18 - Update Java client and broker to MINA 1.0 release
-http://issues.apache.org/jira/browse/QPID-73 - Create Build Artifacts for release process using ant/maven
-http://issues.apache.org/jira/browse/QPID-74 - Create source distribtuion using build system
-http://issues.apache.org/jira/browse/QPID-75 - Create Standard Binary distribution using build system
-
-
-
-
-
-
-
-
-
diff --git a/java/resources/DISCLAIMER b/java/resources/DISCLAIMER
deleted file mode 100644
index c321113c9e..0000000000
--- a/java/resources/DISCLAIMER
+++ /dev/null
@@ -1,5 +0,0 @@
-Apache Qpid is an effort undergoing incubation at the Apache Software Foundation (ASF), sponsored by the Apache Incubator PMC.
-
-Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects.
-
-While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF.
diff --git a/java/resources/LICENSE b/java/resources/LICENSE
index 6b0b1270ff..12d0eecaf2 100644
--- a/java/resources/LICENSE
+++ b/java/resources/LICENSE
@@ -1,3 +1,6 @@
+=========================================================================
+== Apache License ==
+=========================================================================
Apache License
Version 2.0, January 2004
@@ -201,3 +204,623 @@
See the License for the specific language governing permissions and
limitations under the License.
+
+=========================================================================
+== SL4Fj (MIT) License ==
+=========================================================================
+
+SLF4J source code and binaries are distributed under the following license.
+Copyright (c) 2004-2005 SLF4J.ORG
+Copyright (c) 2004-2005 QOS.ch
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, and/or sell copies of the Software, and to permit persons
+to whom the Software is furnished to do so, provided that the above
+copyright notice(s) and this permission notice appear in all copies of
+the Software and that both the above copyright notice(s) and this
+permission notice appear in supporting documentation.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY
+SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder
+shall not be used in advertising or otherwise to promote the sale, use
+or other dealings in this Software without prior written authorization
+of the copyright holder.
+
+=========================================================================
+== Public Domain License for Backport of JSR 166 ==
+=========================================================================
+
+Copyright-Only Dedication (based on United States law) or Public Domain Certification
+
+The person or persons who have associated work with this document (the "Dedicator" or "Certifier") hereby either (a) certifies that, to the best of his knowledge, the work of authorship identified is in the public domain of the country from which the work is published, or (b) hereby dedicates whatever copyright the dedicators holds in the work of authorship identified below (the "Work") to the public domain. A certifier, moreover, dedicates any copyright interest he may have in the associated work, and for these purposes, is described as a "dedicator" below.
+
+A certifier has taken reasonable steps to verify the copyright status of this work. Certifier recognizes that his good faith efforts may not shield him from liability if in fact the work certified is not in the public domain.
+
+Dedicator makes this dedication for the benefit of the public at large and to the detriment of the Dedicator's heirs and successors. Dedicator intends this dedication to be an overt act of relinquishment in perpetuity of all present and future rights under copyright law, whether vested or contingent, in the Work. Dedicator understands that such relinquishment of all rights includes the relinquishment of all rights to enforce (by lawsuit or otherwise) those copyrights in the Work.
+
+Dedicator recognizes that, once placed in the public domain, the Work may be freely reproduced, distributed, transmitted, used, modified, built upon, or otherwise exploited by anyone for any purpose, commercial or non-commercial, and in any way, including by methods that have not yet been invented or conceived.
+
+=========================================================================
+== Eclipse Public License ==
+=========================================================================
+
+Eclipse Public License - v 1.0
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
+b) in the case of each subsequent Contributor:
+
+i) changes to the Program, and
+
+ii) additions to the Program;
+
+where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.
+
+"Contributor" means any person or entity that distributes the Program.
+
+"Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.
+
+"Program" means the Contributions distributed in accordance with this Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.
+
+2. GRANT OF RIGHTS
+
+a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.
+
+b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
+
+c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
+
+d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
+
+3. REQUIREMENTS
+
+A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:
+
+a) it complies with the terms and conditions of this Agreement; and
+
+b) its license agreement:
+
+i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
+
+ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
+
+iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and
+
+iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.
+
+When the Program is made available in source code form:
+
+a) it must be made available under this Agreement; and
+
+b) a copy of this Agreement must be included with each copy of the Program.
+
+Contributors may not remove or alter any copyright notices contained within the Program.
+
+Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.
+
+For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED 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. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.
+
+
+
+=========================================================================
+== ICU License ==
+=========================================================================
+ICU License - ICU 1.8.1 and later
+
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright (c) 1995-2006 International Business Machines Corporation and others
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, provided that the above copyright notice(s) and this permission notice appear in all copies of the Software and that both the above copyright notice(s) and this permission notice appear in supporting documentation.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder.
+
+All trademarks and registered trademarks mentioned herein are the property of their respective owners.
+
+
+=========================================================================
+== AMQP License ==
+=========================================================================
+Copyright Notice
+ ================
+ (c) Copyright JPMorgan Chase Bank & Co., Cisco Systems, Inc., Envoy Technologies Inc.,
+ iMatix Corporation, IONA\ufffd Technologies, Red Hat, Inc.,
+ TWIST Process Innovations, and 29West Inc. 2006. All rights reserved.
+
+ License
+ =======
+ JPMorgan Chase Bank & Co., Cisco Systems, Inc., Envoy Technologies Inc., iMatix
+ Corporation, IONA Technologies, Red Hat, Inc., TWIST Process Innovations, and
+ 29West Inc. (collectively, the "Authors") each hereby grants to you a worldwide,
+ perpetual, royalty-free, nontransferable, nonexclusive license to
+ (i) copy, display, distribute and implement the Advanced Messaging Queue Protocol
+ ("AMQP") Specification and (ii) the Licensed Claims that are held by
+ the Authors, all for the purpose of implementing the Advanced Messaging
+ Queue Protocol Specification. Your license and any rights under this
+ Agreement will terminate immediately without notice from
+ any Author if you bring any claim, suit, demand, or action related to
+ the Advanced Messaging Queue Protocol Specification against any Author.
+ Upon termination, you shall destroy all copies of the Advanced Messaging
+ Queue Protocol Specification in your possession or control.
+
+ As used hereunder, "Licensed Claims" means those claims of a patent or
+ patent application, throughout the world, excluding design patents and
+ design registrations, owned or controlled, or that can be sublicensed
+ without fee and in compliance with the requirements of this
+ Agreement, by an Author or its affiliates now or at any
+ future time and which would necessarily be infringed by implementation
+ of the Advanced Messaging Queue Protocol Specification. A claim is
+ necessarily infringed hereunder only when it is not possible to avoid
+ infringing it because there is no plausible non-infringing alternative
+ for implementing the required portions of the Advanced Messaging Queue
+ Protocol Specification. Notwithstanding the foregoing, Licensed Claims
+ shall not include any claims other than as set forth above even if
+ contained in the same patent as Licensed Claims; or that read solely
+ on any implementations of any portion of the Advanced Messaging Queue
+ Protocol Specification that are not required by the Advanced Messaging
+ Queue Protocol Specification, or that, if licensed, would require a
+ payment of royalties by the licensor to unaffiliated third parties.
+ Moreover, Licensed Claims shall not include (i) any enabling technologies
+ that may be necessary to make or use any Licensed Product but are not
+ themselves expressly set forth in the Advanced Messaging Queue Protocol
+ Specification (e.g., semiconductor manufacturing technology, compiler
+ technology, object oriented technology, networking technology, operating
+ system technology, and the like); or (ii) the implementation of other
+ published standards developed elsewhere and merely referred to in the
+ body of the Advanced Messaging Queue Protocol Specification, or
+ (iii) any Licensed Product and any combinations thereof the purpose or
+ function of which is not required for compliance with the Advanced
+ Messaging Queue Protocol Specification. For purposes of this definition,
+ the Advanced Messaging Queue Protocol Specification shall be deemed to
+ include both architectural and interconnection requirements essential
+ for interoperability and may also include supporting source code artifacts
+ where such architectural, interconnection requirements and source code
+ artifacts are expressly identified as being required or documentation to
+ achieve compliance with the Advanced Messaging Queue Protocol Specification.
+
+ As used hereunder, "Licensed Products" means only those specific portions
+ of products (hardware, software or combinations thereof) that implement
+ and are compliant with all relevant portions of the Advanced Messaging
+ Queue Protocol Specification.
+
+ The following disclaimers, which you hereby also acknowledge as to any
+ use you may make of the Advanced Messaging Queue Protocol Specification:
+
+ THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION IS PROVIDED "AS IS,"
+ AND THE AUTHORS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+ IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE
+ CONTENTS OF THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION ARE
+ SUITABLE FOR ANY PURPOSE; NOR THAT THE IMPLEMENTATION OF THE ADVANCED
+ MESSAGING QUEUE PROTOCOL SPECIFICATION WILL NOT INFRINGE ANY THIRD PARTY
+ PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
+
+ THE AUTHORS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL,
+ INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO ANY
+ USE, IMPLEMENTATION OR DISTRIBUTION OF THE ADVANCED MESSAGING QUEUE
+ PROTOCOL SPECIFICATION.
+
+ The name and trademarks of the Authors may NOT be used in any manner,
+ including advertising or publicity pertaining to the Advanced Messaging
+ Queue Protocol Specification or its contents without specific, written
+ prior permission. Title to copyright in the Advanced Messaging Queue
+ Protocol Specification will at all times remain with the Authors.
+
+ No other rights are granted by implication, estoppel or otherwise.
+
+ Upon termination of your license or rights under this Agreement, you
+ shall destroy all copies of the Advanced Messaging Queue Protocol
+ Specification in your possession or control.
+
+ Trademarks
+ ==========
+ "JPMorgan", "JPMorgan Chase", "Chase", the JPMorgan Chase logo and the
+ Octagon Symbol are trademarks of JPMorgan Chase & Co.
+
+ IMATIX and the iMatix logo are trademarks of iMatix Corporation sprl.
+
+ IONA, IONA Technologies, and the IONA logos are trademarks of IONA
+ Technologies PLC and/or its subsidiaries.
+
+ LINUX is a trademark of Linus Torvalds. RED HAT and JBOSS are registered
+ trademarks of Red Hat, Inc. in the US and other countries.
+
+ Java, all Java-based trademarks and OpenOffice.org are trademarks of
+ Sun Microsystems, Inc. in the United States, other countries, or both.
+
+ Other company, product, or service names may be trademarks or service
+ marks of others.
+
+ Links to full AMQP specification:
+ =================================
+ http://www.envoytech.org/spec/amq/
+ http://www.iona.com/opensource/amqp/
+ http://www.redhat.com/solutions/specifications/amqp/
+ http://www.twiststandards.org/tiki-index.php?page=AMQ
+ http://www.imatix.com/amqp
+
+ JZlib 0.0.* were released under the GNU LGPL license. Later, we have switched
+ over to a BSD-style license.
+
+
+ =========================================================================
+ == JCraft License ==
+ =========================================================================
+
+ ------------------------------------------------------------------------------
+ Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+ INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+=============================================================================
+== JLine (BSD) License
+=============================================================================
+Copyright (c) 2008, Apache Software Foundation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ * Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+====================================
+== The Jython License
+====================================
+
+
+A. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING JYTHON
+==============================================================================================================
+
+PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
+----------------------------------------------------------------------------------------
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation
+("PSF"), and the Individual or Organization ("Licensee") accessing and
+otherwise using this software ("Jython") in source or binary form and
+its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF
+hereby grants Licensee a nonexclusive, royalty-free, world-wide
+license to reproduce, analyze, test, perform and/or display publicly,
+prepare derivative works, distribute, and otherwise use Jython alone
+or in any derivative version, provided, however, that PSF's License
+Agreement and PSF's notice of copyright, i.e., "Copyright (c) 2007
+Python Software Foundation; All Rights Reserved" are retained in
+Jython alone or in any derivative version prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates Jython or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Jython.
+
+4. PSF is making Jython available to Licensee on an "AS IS"
+basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF JYTHON WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF JYTHON
+FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING JYTHON,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+relationship of agency, partnership, or joint venture between PSF and
+Licensee. This License Agreement does not grant permission to use PSF
+trademarks or trade name in a trademark sense to endorse or promote
+products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using Jython, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+Jython 2.0, 2.1 License
+--------------------------------------------
+
+Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Jython Developers
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ - Neither the name of the Jython Developers nor the names of
+ its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+
+JPython 1.1.x Software License.
+______________________________________________________________________
+
+ 1. This LICENSE AGREEMENT is between the Corporation for National Research
+ Initiatives, having an office at 1895 Preston White Drive, Reston, VA
+ 20191 ("CNRI"), and the Individual or Organization ("Licensee")
+ accessing and using JPython version 1.1.x in source or binary form and
+ its associated documentation as provided herein ("Software").
+
+ 2. Subject to the terms and conditions of this License Agreement, CNRI
+ hereby grants Licensee a non-exclusive, non-transferable, royalty-free,
+ world-wide license to reproduce, analyze, test, perform and/or display
+ publicly, prepare derivative works, distribute, and otherwise use the
+ Software alone or in any derivative version, provided, however, that
+ CNRI's License Agreement and CNRI's notice of copyright, i.e.,
+ "Copyright ©1996-1999 Corporation for National Research Initiatives;
+ All Rights Reserved" are both retained in the Software, alone or in any
+ derivative version prepared by Licensee.
+
+ Alternatively, in lieu of CNRI's License Agreement, Licensee may
+ substitute the following text (omitting the quotes), provided, however,
+ that such text is displayed prominently in the Software alone or in any
+ derivative version prepared by Licensee: "JPython (Version 1.1.x) is
+ made available subject to the terms and conditions in CNRI's License
+ Agreement. This Agreement may be located on the Internet using the
+ following unique, persistent identifier (known as a handle):
+ 1895.22/1006. The License may also be obtained from a proxy server on
+ the Web using the following URL: http://hdl.handle.net/1895.22/1006."
+
+ 3. In the event Licensee prepares a derivative work that is based on or
+ incorporates the Software or any part thereof, and wants to make the
+ derivative work available to the public as provided herein, then
+ Licensee hereby agrees to indicate in any such work, in a prominently
+ visible way, the nature of the modifications made to CNRI's Software.
+
+ 4. Licensee may not use CNRI trademarks or trade name, including JPython
+ or CNRI, in a trademark sense to endorse or promote products or
+ services of Licensee, or any third party. Licensee may use the mark
+ JPython in connection with Licensee's derivative versions that are
+ based on or incorporate the Software, but only in the form
+ "JPython-based ___________________," or equivalent.
+
+ 5. CNRI is making the Software available to Licensee on an "AS IS" basis.
+ CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY
+ OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND DISCLAIMS ANY
+ REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY
+ PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE
+ ANY THIRD PARTY RIGHTS.
+
+ 6. CNRI SHALL NOT BE LIABLE TO LICENSEE OR OTHER USERS OF THE SOFTWARE FOR
+ ANY INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF
+ USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY DERIVATIVE
+ THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. SOME STATES DO NOT
+ ALLOW THE LIMITATION OR EXCLUSION OF LIABILITY SO THE ABOVE DISCLAIMER
+ MAY NOT APPLY TO LICENSEE.
+
+ 7. This License Agreement may be terminated by CNRI (i) immediately upon
+ written notice from CNRI of any material breach by the Licensee, if the
+ nature of the breach is such that it cannot be promptly remedied; or
+ (ii) sixty (60) days following notice from CNRI to Licensee of a
+ material remediable breach, if Licensee has not remedied such breach
+ within that sixty-day period.
+
+ 8. This License Agreement shall be governed by and interpreted in all
+ respects by the law of the State of Virginia, excluding conflict of law
+ provisions. Nothing in this Agreement shall be deemed to create any
+ relationship of agency, partnership, or joint venture between CNRI and
+ Licensee.
+
+ 9. By clicking on the "ACCEPT" button where indicated, or by installing,
+ copying or otherwise using the Software, Licensee agrees to be bound by
+ the terms and conditions of this License Agreement.
+
+ [ACCEPT BUTTON]
+
+=========================================================================
+== COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 1. ==
+=========================================================================
+Definitions.
+
+1.1. Contributor means each individual or entity that creates or contributes to the creation of Modifications.
+
+1.2. Contributor Version means the combination of the Original Software, prior Modifications used by a Contributor (if any), and the Modifications made by that particular Contributor.
+
+1.3. Covered Software means (a) the Original Software, or (b) Modifications, or (c) the combination of files containing Original Software with files containing Modifications, in each case including portions thereof.
+
+1.4. Executable means the Covered Software in any form other than Source Code.
+
+1.5. Initial Developer means the individual or entity that first makes Original Software available under this License.
+
+1.6. Larger Work means a work which combines Covered Software or portions thereof with code not governed by the terms of this License.
+
+1.7. License means this document.
+
+1.8. Licensable means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein.
+
+1.9. Modifications means the Source Code and Executable form of any of the following: A. Any file that results from an addition to, deletion from or modification of the contents of a file containing Original Software or previous Modifications; B. Any new file that contains any part of the Original Software or previous Modification; or C. Any new file that is contributed or otherwise made available under the terms of this License.
+
+1.10. Original Software means the Source Code and Executable form of computer software code that is originally released under this License.
+
+1.11. Patent Claims means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor.
+
+1.12. Source Code means (a) the common form of computer software code in which modifications are made and (b) associated documentation included in or with such code.
+
+1.13. You (or Your) means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, You includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, control means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity.
+
+2. License Grants.
+
+ 2.1. The Initial Developer Grant. Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer, to use, reproduce, modify, display, perform, sublicense and distribute the Original Software (or portions thereof), with or without Modifications, and/or as part of a Larger Work; and
+
+(b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof);
+
+(c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first distributes or otherwise makes the Original Software available to a third party under the terms of this License;
+
+(d) Notwithstanding Section 2.1(b) above, no patent license is granted: (1) for code that You delete from the Original Software, or (2) for infringements caused by: (i) the modification of the Original Software, or (ii) the combination of the Original Software with other software or devices.
+
+2.2. Contributor Grant. Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark) Licensable by Contributor to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof), either on an unmodified basis, with other Modifications, as Covered Software and/or as part of a Larger Work; and
+
+(b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: (1) Modifications made by that Contributor (or portions thereof); and (2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination).
+
+(c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first distributes or otherwise makes the Modifications available to a third party.
+
+(d) Notwithstanding Section 2.2(b) above, no patent license is granted: (1) for any code that Contributor has deleted from the Contributor Version; (2) for infringements caused by: (i) third party modifications of Contributor Version, or (ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or (3) under Patent Claims infringed by Covered Software in the absence of Modifications made by that Contributor.
+
+3. Distribution Obligations.
+
+3.1. Availability of Source Code. Any Covered Software that You distribute or otherwise make available in Executable form must also be made available in Source Code form and that Source Code form must be distributed only under the terms of this License. You must include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used for software exchange.
+
+3.2. Modifications. The Modifications that You create or to which You contribute are governed by the terms of this License. You represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to grant the rights conveyed by this License.
+
+3.3. Required Notices. You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification. You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer.
+
+3.4. Application of Additional Terms. You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the applicable version of this License or the recipients rights hereunder. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, you may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear that any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer.
+
+3.5. Distribution of Executable Versions. You may distribute the Executable form of the Covered Software under the terms of this License or under the terms of a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable form does not attempt to limit or alter the recipients rights in the Source Code form from the rights set forth in this License. If You distribute the Covered Software in Executable form under a different license, You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer.
+
+3.6. Larger Works. You may create a Larger Work by combining Covered Software with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Software.
+
+4. Versions of the License.
+
+4.1. New Versions. Sun Microsystems, Inc. is the initial license steward and may publish revised and/or new versions of this License from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3, no one other than the license steward has the right to modify this License.
+
+4.2. Effect of New Versions. You may always continue to use, distribute or otherwise make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. If the Initial Developer includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under any subsequent version of the License, You must distribute and make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. Otherwise, You may also choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version of the License published by the license steward.
+
+4.3. Modified Versions. When You are an Initial Developer and You want to create a new license for Your Original Software, You may create and use a modified version of this License if You: (a) rename the license and remove any references to the name of the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that the license contains terms which differ from this License.
+
+5. DISCLAIMER OF WARRANTY. COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN AS IS BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+6. TERMINATION.
+
+6.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive.
+
+6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as Participant) alleging that the Participant Software (meaning the Contributor Version where the Participant is a Contributor or the Original Software where the Participant is the Initial Developer) directly or indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant, the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement with Participant.
+
+6.3. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor) shall survive termination.
+
+7. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTYS NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+8. U.S. GOVERNMENT END USERS. The Covered Software is a commercial item, as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of commercial computer software (as that term is defined at 48 C.F.R. 252.227-7014(a)(1)) and commercial computer software documentation as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of, and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License.
+
+9. MISCELLANEOUS. This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any, provides otherwise), excluding such jurisdictions conflict-of-law provisions. Any litigation relating to this License shall be subject to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, with the losing party responsible for costs, including, without limitation, court costs and reasonable attorneys fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. You agree that You alone are responsible for compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use, distribute or otherwise make available any Covered Software.
+
+10. RESPONSIBILITY FOR CLAIMS. As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability.
+
+NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) The code released under the CDDL shall be governed by the laws of the State of California (excluding conflict-of-law provisions). Any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California and the state courts of the State of California, with venue lying in Santa Clara County, California.
+
+B. HISTORY OF THE SOFTWARE
+=======================================================
+
+JPython was created in late 1997 by Jim Hugunin. Jim was also the
+primary developer while he was at CNRI. In February 1999 Barry Warsaw
+took over as primary developer and released JPython version 1.1.
+
+In October 2000 Barry helped move the software to SourceForge
+where it was renamed to Jython. Jython 2.0 and 2.1 were developed
+under the Jython specific license below.
+
+From the 2.2 release on, Jython contributors have signed
+Python Software Foundation contributor agreements and releases are
+covered under the Python Software Foundation license version 2.
+
+The standard library is covered by the Python Software Foundation
+license as well. See the Lib/LICENSE file for details.
+
+The zxJDBC package was written by Brian Zimmer and originally licensed
+under the GNU Public License. The package is now covered by the Jython
+Software License.
+
+The command line interpreter is covered by the Apache Software
+License. See the org/apache/LICENSE file for details.
+
diff --git a/java/resources/LICENSE.txt b/java/resources/LICENSE.txt
deleted file mode 100755
index 6b0b1270ff..0000000000
--- a/java/resources/LICENSE.txt
+++ /dev/null
@@ -1,203 +0,0 @@
-
- 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/java/resources/META-INF/DISCLAIMER b/java/resources/META-INF/DISCLAIMER
deleted file mode 100644
index 1ca63e46e2..0000000000
--- a/java/resources/META-INF/DISCLAIMER
+++ /dev/null
@@ -1,10 +0,0 @@
-Apache Qpid is an effort undergoing incubation at the Apache Software
-Foundation (ASF), sponsored by the Apache Incubator PMC.
-
-Incubation is required of all newly accepted projects until a further review
-indicates that the infrastructure, communications, and decision making process
-have stabilized in a manner consistent with other successful ASF projects.
-
-While incubation status is not necessarily a reflection of the completeness
-or stability of the code, it does indicate that the project has yet to be
-fully endorsed by the ASF.
diff --git a/java/resources/META-INF/DISCLAIMER.txt b/java/resources/META-INF/DISCLAIMER.txt
deleted file mode 100644
index d33c54a807..0000000000
--- a/java/resources/META-INF/DISCLAIMER.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-Qpid is an effort undergoing incubation at the Apache Software Foundation
-(ASF). Incubation is required of all newly accepted projects until a further
-review indicates that the infrastructure, communications, and decision making
-process have stabilized in a manner consistent with other successful ASF
-projects. While incubation status is not necessarily a reflection of the
-completeness or stability of the code, it does indicate that the project
-has yet to be fully endorsed by the ASF. \ No newline at end of file
diff --git a/java/resources/META-INF/LICENSE b/java/resources/META-INF/LICENSE
deleted file mode 100644
index 6b0b1270ff..0000000000
--- a/java/resources/META-INF/LICENSE
+++ /dev/null
@@ -1,203 +0,0 @@
-
- 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/java/resources/META-INF/NOTICE b/java/resources/META-INF/NOTICE
deleted file mode 100644
index f62ec14896..0000000000
--- a/java/resources/META-INF/NOTICE
+++ /dev/null
@@ -1,105 +0,0 @@
-// ------------------------------------------------------------------
-// NOTICE file corresponding to the section 4d of The Apache License,
-// Version 2.0, in this case for Qpid Common Utilities
-// ------------------------------------------------------------------
-
-Apache Qpid
-Copyright 2006-2007 Apache Software Foundation
-
-This product includes software developed at
-Apache Software Foundation (http://www.apache.org/)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
-
-This product includes/uses software, Unnamed - relaxngDatatype:relaxngDatatype:jar:20020414 (http://sourceforge.net/projects/relaxng)
-License: BSD License (http://www.opensource.org/licenses/bsd-license.php)
-
-This product includes/uses software, Apache MINA Core API (http://directory.apache.org/projects/mina/)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
-
-This product includes/uses software, Unnamed - isorelax:isorelax:jar:20020414
-License: MIT license (http://www.opensource.org/licenses/mit-license.html)
-
-This product includes/uses software, SLF4J API Module (http://www.slf4j.org),
-developed by QOS.ch (http://www.qos.ch)
-License: MIT License (http://www.slf4j.org/license.html)
-
-This product includes/uses software, Commons Collections - commons-collections:commons-collections:jar:3.1,
-developed by Apache Software Foundation (http://www.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
-
-This product includes/uses software, Commons Digester - commons-digester:commons-digester:jar:1.6
-developed by Apache Software Foundation (http://www.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
-
-This product includes/uses software, Commons CLI - commons-cli:commons-cli:jar:1.0
-Ideveloped by Apache Software Foundation (http://www.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
-
-This product includes/uses software, Unnamed - msv:msv:jar:20020414
-developed by (https://msv.dev.java.net/)
-License:
-
-This product includes/uses software, Codec (http://jakarta.apache.org/commons/codec/),
-developed by The Apache Software Foundation (http://jakarta.apache.org)
-License: The Apache Software License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
-
-This product includes/uses software, Commons Logging - commons-logging:commons-logging:jar:1.0
-developed by Apache Software Foundation (http://www.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
-
-This product includes/uses software, Backport of JSR 166 (http://www.mathcs.emory.edu/dcl/util/backport-util-concurrent/),
-developed by Dawid Kurzyniec (http://www.mathcs.emory.edu/~dawidk/)
-License: Public Domain (http://creativecommons.org/licenses/publicdomain)
-
-This product includes/uses software, Commons Lang - commons-lang:commons-lang:jar:2.1
-developed by Apache Software Foundation (http://www.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
-
-This product includes/uses software, Apache MINA SSL Filter (http://directory.apache.org/subprojects/mina/mina-filter-ssl)
-developed by Apache Software Foundation (http://www.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
-
-This product includes/uses software, Unnamed - xerces:xercesImpl:jar:2.2.1
-developed by The Apache Software Foundation (http://jakarta.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
-
-This product includes/uses software, - javax.servlet:servlet-api:jar:2.3
-
-This product includes/uses software, Xalan - xalan:xalan:jar:2.7.0
-developed by Apache Software Foundation (http://www.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
-
-This product includes/uses software, Commons Configuration (http://jakarta.apache.org/commons/),
-developed by The Apache Software Foundation (http://jakarta.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
-
-This product includes/uses software, Apache MINA Java5 Extensions (http://directory.apache.org/subprojects/mina/mina-java5)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
-
-This product includes/uses software, Jaxen - jaxen:jaxen:jar:1.0-FCS
-License: Apache License (http://jaxen.org/faq.html)
-
-This product includes/uses software, BeanUtils (http://jakarta.apache.org/commons/beanutils/)
-developed by The Apache Software Foundation (http://jakarta.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
-
-This product includes/uses software, XML Commons External Components XML APIs (http://xml.apache.org/commons/#external),
-developed by Apache Software Foundation (http://www.apache.org/)
-License: The Apache Software License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0.txt)
-
-This product includes/uses software, Commons Beanutils Core - commons-beanutils:commons-beanutils-core:jar:1.7.0
-developed by The Apache Software Foundation (http://jakarta.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
-
-This product includes/uses software, Commons Logging API - commons-logging:commons-logging-api:jar:1.0.4
-developed by The Apache Software Foundation (http://jakarta.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
-
-This product includes/uses software, Dom4j - dom4j:dom4j:jar:1.4
-developed by MetaStuff, Ltd. (http://www.dom4j.org/)
-License: BSD License (http://www.dom4j.org/license.html)
-
-This product includes/uses software, Saxon - saxpath:saxpath:jar:1.0-FCS
-developed by Michael Kay (http://saxon.sourceforge.net/)
-License: Mozilla Public License v1.0, (http://www.opensource.org/licenses/mozilla1.0.php)
-
diff --git a/java/resources/NOTICE b/java/resources/NOTICE
index f62ec14896..607c1c1580 100644
--- a/java/resources/NOTICE
+++ b/java/resources/NOTICE
@@ -1,105 +1,113 @@
-// ------------------------------------------------------------------
-// NOTICE file corresponding to the section 4d of The Apache License,
-// Version 2.0, in this case for Qpid Common Utilities
-// ------------------------------------------------------------------
-
Apache Qpid
-Copyright 2006-2007 Apache Software Foundation
-
+Copyright 2006-2008 Apache Software Foundation
This product includes software developed at
Apache Software Foundation (http://www.apache.org/)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
-This product includes/uses software, Unnamed - relaxngDatatype:relaxngDatatype:jar:20020414 (http://sourceforge.net/projects/relaxng)
-License: BSD License (http://www.opensource.org/licenses/bsd-license.php)
+Message logging is provided by the SLF4J library package,
+which is open source software, written by Ceki Gülcü, and
+copyright by SLF4J.ORG and QOS.ch. The original software is
+available from
+
+ http://www.slf4j.org/
+
+Concurrency utlitity classes are provided by the backport-util-concurrent
+library package, which is open source software, written by
+Dawid Kurzyniec, and copyright by Distributed Computing Laboratory,
+Emory University. The original software is available from
-This product includes/uses software, Apache MINA Core API (http://directory.apache.org/projects/mina/)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
+ http://dcl.mathcs.emory.edu/util/backport-util-concurrent/
-This product includes/uses software, Unnamed - isorelax:isorelax:jar:20020414
-License: MIT license (http://www.opensource.org/licenses/mit-license.html)
+Data compression support is provided by the JZLib library package,
+which is open source software, written by JCraft, and copyright
+by JCraft. The original software is available from
-This product includes/uses software, SLF4J API Module (http://www.slf4j.org),
-developed by QOS.ch (http://www.qos.ch)
-License: MIT License (http://www.slf4j.org/license.html)
+ http://www.jcraft.com/jzlib/
-This product includes/uses software, Commons Collections - commons-collections:commons-collections:jar:3.1,
-developed by Apache Software Foundation (http://www.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
+Spring framework is provided by the Spring framework library
+package, which is open source software, written by Rod Johnson
+et al, and copyright by Springframework.org. The original
+software is available from
+
+ http://www.springframework.org/
+
+
+This product includes software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright 2006 The OSGi Alliance.
+Licensed under the Apache License 2.0.
-This product includes/uses software, Commons Digester - commons-digester:commons-digester:jar:1.6
-developed by Apache Software Foundation (http://www.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
+Handling console input is provided bye the Jline library package,
+JLine is a Java library for handling console input. It is similar
+in functionality to BSD editline and GNU readline.Original software is
+available from
-This product includes/uses software, Commons CLI - commons-cli:commons-cli:jar:1.0
-Ideveloped by Apache Software Foundation (http://www.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
+pphttp://jline.sourceforge.net/index.html
-This product includes/uses software, Unnamed - msv:msv:jar:20020414
-developed by (https://msv.dev.java.net/)
-License:
+Jython is used within ant scripts for generating code.
+Jython is hosted at http://www.jython.org
+The license for jython is located at http://www.jython.org/Project/license.txt
-This product includes/uses software, Codec (http://jakarta.apache.org/commons/codec/),
-developed by The Apache Software Foundation (http://jakarta.apache.org)
-License: The Apache Software License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+The Apache Muse Project is a Java-based implementation
+of the WS-ResourceFramework (WSRF), WS-BaseNotification (WSN),
+and WS-DistributedManagement (WSDM) specifications.
+It is licensed under the Apache License 2.0.
+The original software is available from
-This product includes/uses software, Commons Logging - commons-logging:commons-logging:jar:1.0
-developed by Apache Software Foundation (http://www.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
+http://ws.apache.org/muse/
-This product includes/uses software, Backport of JSR 166 (http://www.mathcs.emory.edu/dcl/util/backport-util-concurrent/),
-developed by Dawid Kurzyniec (http://www.mathcs.emory.edu/~dawidk/)
-License: Public Domain (http://creativecommons.org/licenses/publicdomain)
+The Web Services Description Language for Java Toolkit (WSDL4J) allows
+the creation, representation, and manipulation of WSDL documents
+It is licensed under the Common Public License 1.0
+The original software is available from
-This product includes/uses software, Commons Lang - commons-lang:commons-lang:jar:2.1
-developed by Apache Software Foundation (http://www.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
+http://sourceforge.net/projects/wsdl4j
-This product includes/uses software, Apache MINA SSL Filter (http://directory.apache.org/subprojects/mina/mina-filter-ssl)
-developed by Apache Software Foundation (http://www.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
+Xml manipulation and all related xml common utilities are provider by the
+xml-apis library, which is an open source software.
+It is licensed under the Apache License 2.0 and is available from :
-This product includes/uses software, Unnamed - xerces:xercesImpl:jar:2.2.1
-developed by The Apache Software Foundation (http://jakarta.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
+http://xml.apache.org/commons/
-This product includes/uses software, - javax.servlet:servlet-api:jar:2.3
+Xerces Java is a library for parsing, validating and manipulating XML documents.
+It is licensed under the Apache License 2.0 and is available from :
-This product includes/uses software, Xalan - xalan:xalan:jar:2.7.0
-developed by Apache Software Foundation (http://www.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
+http://xerces.apache.org/
-This product includes/uses software, Commons Configuration (http://jakarta.apache.org/commons/),
-developed by The Apache Software Foundation (http://jakarta.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
+Xalan is an XSLT processor for transforming XML documents into HTML,
+text, or other XML document types.
+It is licensed under the Apache License 2.0.
+The original software is available from :
-This product includes/uses software, Apache MINA Java5 Extensions (http://directory.apache.org/subprojects/mina/mina-java5)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
+http://xml.apache.org/xalan-j/
-This product includes/uses software, Jaxen - jaxen:jaxen:jar:1.0-FCS
-License: Apache License (http://jaxen.org/faq.html)
+Jetty is an open-source, standards-based, full-featured web server
+implemented entirely in Java. It is used as a web server / servlet engine
+on WS-DM adapter.
+Licensed under the Apache License 2.0.
+The original software is available from :
-This product includes/uses software, BeanUtils (http://jakarta.apache.org/commons/beanutils/)
-developed by The Apache Software Foundation (http://jakarta.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
+http://www.mortbay.org/jetty/
-This product includes/uses software, XML Commons External Components XML APIs (http://xml.apache.org/commons/#external),
-developed by Apache Software Foundation (http://www.apache.org/)
-License: The Apache Software License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0.txt)
+Javassist is a load-time reflective system for Java. It is a class library
+for editing bytecodes in Java;
+Licensend under MPL or LGPL.
+The original software is available from :
-This product includes/uses software, Commons Beanutils Core - commons-beanutils:commons-beanutils-core:jar:1.7.0
-developed by The Apache Software Foundation (http://jakarta.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
+http://www.jboss.org/javassist/
-This product includes/uses software, Commons Logging API - commons-logging:commons-logging-api:jar:1.0.4
-developed by The Apache Software Foundation (http://jakarta.apache.org)
-License: Apache 2.0 License (http://www.apache.org/licenses/LICENSE-2.0)
+The core library is an eclipse plugin that contains a bytecode disassembler
+("Disassembler") that can produce a listing of the Java assembler mnemonics ("Assembler Mnemonics")
+for a Java method. It is needed in order to enable JSP support in Jetty.
+It is licensed under Eclipse Public License Version 1.0
-This product includes/uses software, Dom4j - dom4j:dom4j:jar:1.4
-developed by MetaStuff, Ltd. (http://www.dom4j.org/)
-License: BSD License (http://www.dom4j.org/license.html)
+The JSP implementation library is used for QMan admin console that is a web application running
+on Jetty.
+It is licensed under Common Development and Distribution license version 1.0. License information
+is available from :
-This product includes/uses software, Saxon - saxpath:saxpath:jar:1.0-FCS
-developed by Michael Kay (http://saxon.sourceforge.net/)
-License: Mozilla Public License v1.0, (http://www.opensource.org/licenses/mozilla1.0.php)
+https://glassfish.dev.java.net/public/CDDLv1.0.html
+The JSP API library is used is used for QMan admin console that is a web application running
+on Jetty.
+It is licensed under Apache License Version 2.0.
+
diff --git a/java/resources/NOTICE.txt b/java/resources/NOTICE.txt
deleted file mode 100644
index 82d3dbc632..0000000000
--- a/java/resources/NOTICE.txt
+++ /dev/null
@@ -1,36 +0,0 @@
-=========================================================================
-== NOTICE file corresponding to the section 4 d of ==
-== the Apache License, Version 2.0, ==
-== in this case for the Apache Qpid distribution. ==
-=========================================================================
-
-This product includes software developed by the Apache Software Foundation
-(http://www.apache.org/).
-
-Please read the LICENSE.txt file present in the root directory of this
-distribution.
-
-
-Aside from contributions to the Apache Qpid project, this software also
-includes (binary only):
-
- - The SAXON XSLT Processor from Michael Kay distributed under the
- Mozilla Public License v1.0, which is available for download at
- http://saxon.sourceforge.net/
-
- - The JUnit regression testing framework written by Erich Gamma
- and Kent Beck and distributed under the Common Public License v1.0.
- JUnit is available for download at
- http://sourceforge.net/projects/junit/
-
- - The Simple Logging Facade For Java (slf4j), Copyright (c)
- 2004-2005 SLF4J.ORG, Copyright (c) 2004-2005 QOS.ch. slf4j is
- licensed under identical terms to the MIT/X11 license and
- available for download at http://www.slf4j.org/
-
- - Software from the Eclipse project. The binaries from this project are
- distributed under the Eclipse Public License and can be donwloaded
- from http://www.eclipse.org/
-
-
-
diff --git a/java/resources/README.txt b/java/resources/README.txt
deleted file mode 100644
index 1d52d487fb..0000000000
--- a/java/resources/README.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-
-Documentation
---------------
-All of our user documentation for the Qpid Java components can be accessed on our wiki at:
-
-http://cwiki.apache.org/confluence/display/qpid/Qpid+Java+Documentation
-
-This includes a Getting Started Guide and FAQ as well as detailed developer documentation.
-However, here's a VERY quick guide to running the installed Qpid broker, once you have installed it somewhere !
-
-
-Running the Broker
-------------------
-
-To run the broker, set the QPID_HOME environment variable to
-distribution directory and add $QPID_HOME/bin to your PATH. Then run
-the qpid-server shell script or qpid-server.bat batch file to start
-the broker. By default, the broker will use $QPID_HOME/etc to find
-the configuration files. You can supply a custom configuration using
-the -c argument.
-
-For example:
-
-qpid-server -c ~/etc/config.xml
-
-You can get a list of all command line arguments by using the -h argument.
-
-
-Developing
-----------
-
-In order to build Qpid you need Ant 1.6.5. Use ant -p to list the
-available targets. The default ant target, build, creates a working
-development-mode distribution in the build directory. To run the
-scripts in build/bin set QPID_HOME to the build directory and put
-${QPID_HOME}/bin on your PATH. The scripts in that directory include
-the standard ones in the distribution and a number of testing scripts.
-
-
-
diff --git a/java/systests/build.xml b/java/systests/build.xml
index 4eb7275e73..34a360ecad 100644
--- a/java/systests/build.xml
+++ b/java/systests/build.xml
@@ -20,7 +20,7 @@ nn - or more contributor license agreements. See the NOTICE file
-->
<project name="System Tests" default="build">
- <property name="module.depends" value="client broker common junit-toolkit"/>
+ <property name="module.depends" value="client management/tools/qpid-cli management/eclipse-plugin management/common broker broker/test common common/test nt junit-toolkit"/>
<property name="module.test.src" location="src/main/java"/>
<property name="module.test.excludes"
value="**/TTLTest.java,**/DropInTest.java,**/TestClientControlledTest.java"/>
diff --git a/java/systests/distribution/pom.xml b/java/systests/distribution/pom.xml
deleted file mode 100644
index 619a9325c4..0000000000
--- a/java/systests/distribution/pom.xml
+++ /dev/null
@@ -1,112 +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.
- -->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-systests-distribution</artifactId>
- <packaging>jar</packaging>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <name>Qpid System Tests Distribution</name>
- <url>http://cwiki.apache.org/confluence/display/qpid</url>
-
- <parent>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid</artifactId>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <relativePath>../../pom.xml</relativePath>
- </parent>
-
- <properties>
- <topDirectoryLocation>..</topDirectoryLocation>
- <java.source.version>1.5</java.source.version>
- <qpid.version>${pom.version}</qpid.version>
- <qpid.targetDir>${project.build.directory}</qpid.targetDir>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-systests</artifactId>
- </dependency>
- </dependencies>
-
- <build>
- <pluginManagement>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>${java.source.version}</source>
- <target>${java.source.version}</target>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-assembly-plugin</artifactId>
- <version>${assembly.version}</version>
- <configuration>
- <finalName>qpid-${pom.version}</finalName>
- <outputDirectory>${qpid.targetDir}</outputDirectory>
- <tarLongFileMode>gnu</tarLongFileMode>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <configuration>
- <finalName>qpid-systests</finalName>
- <archive>
- <manifest>
- <addClasspath>true</addClasspath>
- </manifest>
- </archive>
- </configuration>
- </plugin>
-
- </plugins>
- </pluginManagement>
-
- <plugins>
- <plugin>
- <artifactId>maven-assembly-plugin</artifactId>
- <executions>
- <execution>
- <id>distribution-package</id>
- <phase>package</phase>
- <goals>
- <goal>single</goal>
- </goals>
- <configuration>
- <descriptors>
- <descriptor>src/main/assembly/systests.xml</descriptor>
- </descriptors>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
-
- </build>
-
-</project>
diff --git a/java/systests/distribution/src/main/assembly/systests.xml b/java/systests/distribution/src/main/assembly/systests.xml
deleted file mode 100644
index 2d6a6d8572..0000000000
--- a/java/systests/distribution/src/main/assembly/systests.xml
+++ /dev/null
@@ -1,91 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
--->
-<assembly>
- <id>system-test-java</id>
- <includeBaseDirectory>false</includeBaseDirectory>
- <formats>
- <format>tar.gz</format>
- <format>zip</format>
- </formats>
-
-<fileSets>
- <!-- Apache Licensing Details-->
- <fileSet>
- <directory>../../resources</directory>
- <outputDirectory>qpid-${qpid.version}</outputDirectory>
- <includes>
- <include>DISCLAIMER</include>
- <include>LICENSE.txt</include>
- <include>NOTICE.txt</include>
- <include>README.txt</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>..</directory>
- <outputDirectory>qpid-${qpid.version}</outputDirectory>
- <includes>
- <include>*.txt</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>../../release-docs</directory>
- <outputDirectory>qpid-${qpid.version}/docs</outputDirectory>
- <includes>
- <include>RELEASE_NOTES.txt</include>
- </includes>
- </fileSet>
-
- <!-- Scripts to run the system tests-->
- <fileSet>
- <directory>../bin</directory>
- <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
- <includes>
- <include>*</include>
- </includes>
- </fileSet>
-
- <!-- Include source files in easy access form -->
- <fileSet>
- <directory>../src/main</directory>
- <outputDirectory>qpid-${qpid.version}/src</outputDirectory>
- <includes>
- <include>**/*.java</include>
- <include>**/*.log4j</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>target</directory>
- <outputDirectory>qpid-${qpid.version}/lib</outputDirectory>
- <includes>
- <include>qpid-systests.jar</include>
- </includes>
- </fileSet>
- </fileSets>
-
- <dependencySets>
- <dependencySet>
- <outputDirectory>qpid-${qpid.version}/lib</outputDirectory>
- <unpack>false</unpack>
- <excludes>
- <exclude>org.apache.qpid:qpid-systests-distribution</exclude>
- </excludes>
- </dependencySet>
- </dependencySets>
-</assembly>
diff --git a/java/systests/etc/config-systests-ServerConfigurationTest-New.xml b/java/systests/etc/config-systests-ServerConfigurationTest-New.xml
new file mode 100644
index 0000000000..33cc90b895
--- /dev/null
+++ b/java/systests/etc/config-systests-ServerConfigurationTest-New.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+
+ This is an example config using the BDBMessageStore available from
+ the Red Hat Messaging project at etp.108.redhat.com and distributed under GPL.
+ -->
+
+<broker>
+ <work>${QPID_WORK}</work>
+ <conf>${QPID_HOME}/etc</conf>
+ <passwordDir>${conf}</passwordDir>
+ <connector>
+ <transport>nio</transport>
+ <port>5672</port>
+ <socketReceiveBuffer>32768</socketReceiveBuffer>
+ <socketSendBuffer>32768</socketSendBuffer>
+ </connector>
+ <management>
+ <enabled>false</enabled>
+ <jmxport>8999</jmxport>
+ </management>
+ <advanced>
+ <filterchain enableExecutorPool="true"/>
+ <enablePooledAllocator>false</enablePooledAllocator>
+ <enableDirectBuffers>false</enableDirectBuffers>
+ <framesize>65535</framesize>
+ <compressBufferOnQueue>false</compressBufferOnQueue>
+ </advanced>
+
+ <security>
+ <principal-databases>
+ <principal-database>
+ <name>passwordfile</name>
+ <class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>
+ <attributes>
+ <attribute>
+ <name>passwordFile</name>
+ <value>${passwordDir}/passwd</value>
+ </attribute>
+ </attributes>
+ </principal-database>
+ </principal-databases>
+
+ <access>
+ <class>org.apache.qpid.server.security.access.plugins.AllowAll</class>
+ </access>
+ <jmx>
+ <access>${passwordDir}/jmxremote.access</access>
+ <principal-database>passwordfile</principal-database>
+ </jmx>
+ </security>
+
+ <virtualhosts>
+ <virtualhost>
+ <name>dev-only</name>
+ <dev-only>
+ <store>
+ <class>org.apache.qpid.server.store.MemoryMessageStore</class>
+ <environment-path>${work}/bdbstore/dev-only-store</environment-path>
+ </store>
+ </dev-only>
+ </virtualhost>
+ </virtualhosts>
+ <heartbeat>
+ <delay>0</delay>
+ <timeoutFactor>2.0</timeoutFactor>
+ </heartbeat>
+ <queue>
+ <auto_register>true</auto_register>
+ </queue>
+
+ <virtualhosts>${conf}/virtualhosts-ServerConfigurationTest-New.xml</virtualhosts>
+</broker>
+
+
diff --git a/java/systests/etc/config-systests-ServerConfigurationTest-Old.xml b/java/systests/etc/config-systests-ServerConfigurationTest-Old.xml
new file mode 100644
index 0000000000..67e0702c41
--- /dev/null
+++ b/java/systests/etc/config-systests-ServerConfigurationTest-Old.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+<work>${QPID_WORK}</work>
+<conf>${QPID_HOME}/etc</conf>
+<passwordDir>${conf}</passwordDir>
+<connector>
+<transport>nio</transport>
+<port>5672</port>
+<socketReceiveBuffer>32768</socketReceiveBuffer>
+<socketSendBuffer>32768</socketSendBuffer>
+</connector>
+<management>
+<enabled>false</enabled>
+<jmxport>8999</jmxport>
+</management>
+<advanced>
+<filterchain enableExecutorPool="true"/>
+<enablePooledAllocator>false</enablePooledAllocator>
+<enableDirectBuffers>false</enableDirectBuffers>
+<framesize>65535</framesize>
+<compressBufferOnQueue>false</compressBufferOnQueue>
+</advanced>
+<security>
+<principal-databases>
+<principal-database>
+<name>passwordfile</name>
+<class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>
+<attributes>
+<attribute>
+<name>passwordFile</name>
+<value>${passwordDir}/passwd</value>
+</attribute>
+</attributes>
+</principal-database>
+</principal-databases>
+<access>
+<class>org.apache.qpid.server.security.access.plugins.AllowAll</class>
+</access>
+<jmx>
+<access>${passwordDir}/jmxremote.access</access>
+<principal-database>passwordfile</principal-database>
+</jmx>
+</security>
+<virtualhosts>${conf}/virtualhosts-ServerConfigurationTest-New.xml
+<default>dev-only</default>
+<virtualhost>
+<name>dev-only</name>
+<dev-only>
+<store>
+<class>org.apache.qpid.server.store.MemoryMessageStore</class>
+<environment-path>${work}/bdbstore/dev-only-store</environment-path>
+</store>
+<queues>
+<exchange>amq.direct</exchange>
+<maximumQueueDepth>102400</maximumQueueDepth>
+<maximumMessageSize>20480</maximumMessageSize>
+<maximumMessageAge>60000</maximumMessageAge>
+<queue>
+<name>dev-queue</name>
+</queue>
+</queues>
+</dev-only>
+</virtualhost>
+</virtualhosts>
+<heartbeat>
+<delay>0</delay>
+<timeoutFactor>2.0</timeoutFactor>
+</heartbeat>
+<queue>
+<auto_register>true</auto_register>
+</queue>
+</configuration>
diff --git a/java/systests/etc/config-systests-acl-settings.xml b/java/systests/etc/config-systests-acl-settings.xml
new file mode 100644
index 0000000000..d7c1ef70df
--- /dev/null
+++ b/java/systests/etc/config-systests-acl-settings.xml
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<broker>
+
+ <virtualhosts>
+
+ <virtualhost>
+ <name>test</name>
+ <test>
+ <queues>
+ <exchange>amq.direct</exchange>
+ <!-- 4Mb -->
+ <maximumQueueDepth>4235264</maximumQueueDepth>
+ <!-- 2Mb -->
+ <maximumMessageSize>2117632</maximumMessageSize>
+ <!-- 10 mins -->
+ <maximumMessageAge>600000</maximumMessageAge>
+ </queues>
+
+
+ <security>
+ <access>
+ <class>org.apache.qpid.server.security.access.plugins.SimpleXML</class>
+ </access>
+ <access_control_list>
+ <!-- This section grants pubish rights to an exchange + routing key pair -->
+ <publish>
+ <exchanges>
+ <exchange>
+ <name>amq.direct</name>
+ <routing_keys>
+
+ <!-- Allow clients to publish requests -->
+ <routing_key>
+ <value>example.RequestQueue</value>
+ <users>
+ <user>client</user>
+ </users>
+ </routing_key>
+
+ <!-- Allow the processor to respond to a client on their Temporary Topic -->
+ <routing_key>
+ <value>tmp_*</value>
+ <users>
+ <user>server</user>
+ </users>
+ </routing_key>
+ <routing_key>
+ <value>TempQueue*</value>
+ <users>
+ <user>server</user>
+ </users>
+ </routing_key>
+ </routing_keys>
+
+ </exchange>
+ </exchanges>
+ </publish>
+
+ <!-- This section grants users the ability to consume from the broker -->
+ <consume>
+ <queues>
+ <temporary>
+ <users>
+ <user>client</user>
+ </users>
+ </temporary>
+
+ <!-- Only allow the server to consume from the Request Queue-->
+ <queue>
+ <name>example.RequestQueue</name>
+ <users>
+ <user>server</user>
+ </users>
+ </queue>
+
+
+ </queues>
+ </consume>
+
+ <!-- This section grants users the ability to create queues and exchanges -->
+ <create>
+ <queues>
+ <temporary>
+ <users>
+ <user>client</user>
+ </users>
+ </temporary>
+
+ <!-- Allow clients to create queue on this exchange-->
+ <queue>
+ <exchanges>
+ <exchange>
+ <name>amq.direct</name>
+ <users>
+ <user>client</user>
+ </users>
+ </exchange>
+ </exchanges>
+ </queue>
+ <!-- Allow the server to create the Request Queue-->
+ <queue>
+ <name>example.RequestQueue</name>
+ <users>
+ <user>server</user>
+ </users>
+ </queue>
+
+ </queues>
+ </create>
+
+
+ </access_control_list>
+
+ </security>
+ </test>
+ </virtualhost>
+
+ <virtualhost>
+ <name>test2</name>
+ <test2>
+ <security>
+ <access>
+ <class>org.apache.qpid.server.security.access.plugins.SimpleXML</class>
+ </access>
+
+ <access_control_list>
+ <!-- This section grants specific users full permissions to all artifacts in this virtualhost -->
+ <access>
+ <users>
+ <user>guest</user>
+ </users>
+ </access>
+ </access_control_list>
+ </security>
+ </test2>
+ </virtualhost>
+ </virtualhosts>
+</broker>
+
+
diff --git a/java/systests/etc/config-systests-acl.xml b/java/systests/etc/config-systests-acl.xml
new file mode 100644
index 0000000000..34104dbe6b
--- /dev/null
+++ b/java/systests/etc/config-systests-acl.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<configuration>
+ <system/>
+ <override>
+ <xml fileName="${test.config}" config-optional="true"/>
+ <xml fileName="${QPID_HOME}/etc/config-systests-acl-settings.xml"/>
+ <xml fileName="${QPID_HOME}/etc/config-systests-settings.xml"/>
+ <xml fileName="${QPID_HOME}/etc/config.xml"/>
+ </override>
+</configuration>
diff --git a/java/systests/etc/config-systests-derby-settings.xml b/java/systests/etc/config-systests-derby-settings.xml
new file mode 100644
index 0000000000..9c25b5682e
--- /dev/null
+++ b/java/systests/etc/config-systests-derby-settings.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<broker>
+ <virtualhosts>
+ <directory>${conf}/virtualhosts</directory>
+
+ <virtualhost>
+ <name>localhost</name>
+ <localhost>
+ <store>
+ <class>org.apache.qpid.server.store.DerbyMessageStore</class>
+ <environment-path>${work}/derbyDB/localhost-store</environment-path>
+ </store>
+
+ <housekeeping>
+ <expiredMessageCheckPeriod>20000</expiredMessageCheckPeriod>
+ </housekeeping>
+
+ </localhost>
+ </virtualhost>
+
+ <virtualhost>
+ <name>development</name>
+ <development>
+ <store>
+ <class>org.apache.qpid.server.store.DerbyMessageStore</class>
+ <environment-path>${work}/derbyDB/development-store</environment-path>
+ </store>
+ </development>
+ </virtualhost>
+
+ <virtualhost>
+ <name>test</name>
+ <test>
+ <store>
+ <class>org.apache.qpid.server.store.DerbyMessageStore</class>
+ <environment-path>${work}/derbyDB/test-store</environment-path>
+ </store>
+ </test>
+ </virtualhost>
+
+ </virtualhosts>
+</broker>
+
+
diff --git a/java/systests/etc/config-systests-derby.xml b/java/systests/etc/config-systests-derby.xml
new file mode 100644
index 0000000000..18ba0c4ad9
--- /dev/null
+++ b/java/systests/etc/config-systests-derby.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<configuration>
+ <system/>
+ <override>
+ <xml fileName="${test.config}" config-optional="true"/>
+ <xml fileName="${QPID_HOME}/etc/config-systests-derby-settings.xml"/>
+ <xml fileName="${QPID_HOME}/etc/config-systests-settings.xml"/>
+ <xml fileName="${QPID_HOME}/etc/config.xml"/>
+ </override>
+</configuration>
diff --git a/java/systests/etc/config-systests-firewall-2.xml b/java/systests/etc/config-systests-firewall-2.xml
new file mode 100644
index 0000000000..1c560d751d
--- /dev/null
+++ b/java/systests/etc/config-systests-firewall-2.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<broker>
+ <prefix>${QPID_HOME}</prefix>
+ <work>${QPID_WORK}</work>
+ <conf>${prefix}/etc</conf>
+ <connector>
+ <!-- To enable SSL edit the keystorePath and keystorePassword
+ and set enabled to true.
+ To disasble Non-SSL port set sslOnly to true -->
+ <ssl>
+ <enabled>false</enabled>
+ <sslOnly>false</sslOnly>
+ <keystorePath>/path/to/keystore.ks</keystorePath>
+ <keystorePassword>keystorepass</keystorePassword>
+ </ssl>
+ <qpidnio>false</qpidnio>
+ <protectio>
+ <enabled>false</enabled>
+ <readBufferLimitSize>262144</readBufferLimitSize>
+ <writeBufferLimitSize>262144</writeBufferLimitSize>
+ </protectio>
+ <transport>nio</transport>
+ <port>5672</port>
+ <sslport>8672</sslport>
+ <socketReceiveBuffer>32768</socketReceiveBuffer>
+ <socketSendBuffer>32768</socketSendBuffer>
+ </connector>
+ <management>
+ <enabled>false</enabled>
+ <jmxport>8999</jmxport>
+ <ssl>
+ <enabled>false</enabled>
+ <!-- Update below path to your keystore location, eg ${conf}/qpid.keystore -->
+ <keyStorePath>${prefix}/../test-profiles/test_resources/ssl/keystore.jks</keyStorePath>
+ <keyStorePassword>password</keyStorePassword>
+ </ssl>
+ </management>
+ <advanced>
+ <filterchain enableExecutorPool="true"/>
+ <enablePooledAllocator>false</enablePooledAllocator>
+ <enableDirectBuffers>false</enableDirectBuffers>
+ <framesize>65535</framesize>
+ <compressBufferOnQueue>false</compressBufferOnQueue>
+ <enableJMSXUserID>false</enableJMSXUserID>
+ <locale>en_US</locale>
+ </advanced>
+
+ <security>
+ <principal-databases>
+ <!-- Example use of Base64 encoded MD5 hashes for authentication via CRAM-MD5-Hashed -->
+ <principal-database>
+ <name>passwordfile</name>
+ <class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>
+ <attributes>
+ <attribute>
+ <name>passwordFile</name>
+ <value>${conf}/passwd</value>
+ </attribute>
+ </attributes>
+ </principal-database>
+ </principal-databases>
+
+ <access>
+ <class>org.apache.qpid.server.security.access.plugins.AllowAll</class>
+ </access>
+
+ <msg-auth>false</msg-auth>
+
+ <jmx>
+ <access>${conf}/jmxremote.access</access>
+ <principal-database>passwordfile</principal-database>
+ </jmx>
+
+ <firewall default-action="allow">
+ <rule access="deny" network="127.0.0.1"/>
+ </firewall>
+ </security>
+
+ <virtualhosts>
+ <default>test</default>
+
+ <virtualhost>
+ <name>test</name>
+ <test>
+ <store>
+ <class>org.apache.qpid.server.store.MemoryMessageStore
+ </class>
+ </store>
+ <security>
+ <firewall default-action="allow"/>
+ </security>
+ </test>
+ </virtualhost>
+
+ <virtualhost>
+ <name>test2</name>
+ <test2>
+ <store>
+ <class>org.apache.qpid.server.store.MemoryMessageStore
+ </class>
+ </store>
+ </test2>
+ </virtualhost>
+ </virtualhosts>
+ <heartbeat>
+ <delay>0</delay>
+ <timeoutFactor>2.0</timeoutFactor>
+ </heartbeat>
+ <queue>
+ <auto_register>true</auto_register>
+ </queue>
+
+ <status-updates>ON</status-updates>
+
+</broker>
+
+
diff --git a/java/systests/etc/config-systests-firewall-3.xml b/java/systests/etc/config-systests-firewall-3.xml
new file mode 100644
index 0000000000..05c4df6069
--- /dev/null
+++ b/java/systests/etc/config-systests-firewall-3.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<broker>
+ <prefix>${QPID_HOME}</prefix>
+ <work>${QPID_WORK}</work>
+ <conf>${prefix}/etc</conf>
+ <connector>
+ <!-- To enable SSL edit the keystorePath and keystorePassword
+ and set enabled to true.
+ To disasble Non-SSL port set sslOnly to true -->
+ <ssl>
+ <enabled>false</enabled>
+ <sslOnly>false</sslOnly>
+ <keystorePath>/path/to/keystore.ks</keystorePath>
+ <keystorePassword>keystorepass</keystorePassword>
+ </ssl>
+ <qpidnio>false</qpidnio>
+ <protectio>
+ <enabled>false</enabled>
+ <readBufferLimitSize>262144</readBufferLimitSize>
+ <writeBufferLimitSize>262144</writeBufferLimitSize>
+ </protectio>
+ <transport>nio</transport>
+ <port>5672</port>
+ <sslport>8672</sslport>
+ <socketReceiveBuffer>32768</socketReceiveBuffer>
+ <socketSendBuffer>32768</socketSendBuffer>
+ </connector>
+ <management>
+ <enabled>false</enabled>
+ <jmxport>8999</jmxport>
+ <ssl>
+ <enabled>false</enabled>
+ <!-- Update below path to your keystore location, eg ${conf}/qpid.keystore -->
+ <keyStorePath>${prefix}/../test-profiles/test_resources/ssl/keystore.jks</keyStorePath>
+ <keyStorePassword>password</keyStorePassword>
+ </ssl>
+ </management>
+ <advanced>
+ <filterchain enableExecutorPool="true"/>
+ <enablePooledAllocator>false</enablePooledAllocator>
+ <enableDirectBuffers>false</enableDirectBuffers>
+ <framesize>65535</framesize>
+ <compressBufferOnQueue>false</compressBufferOnQueue>
+ <enableJMSXUserID>false</enableJMSXUserID>
+ <locale>en_US</locale>
+ </advanced>
+
+ <security>
+ <principal-databases>
+ <!-- Example use of Base64 encoded MD5 hashes for authentication via CRAM-MD5-Hashed -->
+ <principal-database>
+ <name>passwordfile</name>
+ <class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>
+ <attributes>
+ <attribute>
+ <name>passwordFile</name>
+ <value>${conf}/passwd</value>
+ </attribute>
+ </attributes>
+ </principal-database>
+ </principal-databases>
+
+ <access>
+ <class>org.apache.qpid.server.security.access.plugins.AllowAll</class>
+ </access>
+
+ <msg-auth>false</msg-auth>
+
+ <jmx>
+ <access>${conf}/jmxremote.access</access>
+ <principal-database>passwordfile</principal-database>
+ </jmx>
+
+ <firewall default-action="deny">
+ <rule access="allow" network="127.0.0.1"/>
+ </firewall>
+ </security>
+
+ <virtualhosts>
+ <default>test</default>
+
+ <virtualhost>
+ <name>test</name>
+ <test>
+ <store>
+ <class>org.apache.qpid.server.store.MemoryMessageStore
+ </class>
+ </store>
+ </test>
+ </virtualhost>
+
+ <virtualhost>
+ <name>test2</name>
+ <test2>
+ <store>
+ <class>org.apache.qpid.server.store.MemoryMessageStore
+ </class>
+ </store>
+ <security>
+ <firewall default-action="deny"/>
+ </security>
+ </test2>
+ </virtualhost>
+ </virtualhosts>
+ <heartbeat>
+ <delay>0</delay>
+ <timeoutFactor>2.0</timeoutFactor>
+ </heartbeat>
+ <queue>
+ <auto_register>true</auto_register>
+ </queue>
+
+ <status-updates>ON</status-updates>
+
+</broker>
+
+
diff --git a/java/systests/etc/config-systests-firewall-settings.xml b/java/systests/etc/config-systests-firewall-settings.xml
new file mode 100644
index 0000000000..d115e74663
--- /dev/null
+++ b/java/systests/etc/config-systests-firewall-settings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<broker>
+ <security>
+ <firewall>
+ <rule access="allow" network="127.0.0.1"/>
+ </firewall>
+ </security>
+</broker>
diff --git a/java/systests/etc/config-systests-firewall.xml b/java/systests/etc/config-systests-firewall.xml
new file mode 100644
index 0000000000..90773f5cc2
--- /dev/null
+++ b/java/systests/etc/config-systests-firewall.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<configuration>
+ <system/>
+ <override>
+ <xml fileName="${test.config}" config-optional="true"/>
+ <xml fileName="${QPID_FIREWALL_SETTINGS}"/>
+ <xml fileName="${QPID_HOME}/etc/config-systests-settings.xml"/>
+ <xml fileName="${QPID_HOME}/etc/config.xml"/>
+ </override>
+</configuration>
diff --git a/java/systests/etc/config-systests-settings.xml b/java/systests/etc/config-systests-settings.xml
new file mode 100644
index 0000000000..4e9c863fda
--- /dev/null
+++ b/java/systests/etc/config-systests-settings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<broker>
+ <management>
+ <enabled>false</enabled>
+ <ssl>
+ <enabled>false</enabled>
+ </ssl>
+ </management>
+</broker>
diff --git a/java/systests/etc/config-systests.xml b/java/systests/etc/config-systests.xml
new file mode 100644
index 0000000000..290c082a4f
--- /dev/null
+++ b/java/systests/etc/config-systests.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<configuration>
+ <system/>
+ <override>
+ <xml fileName="${test.config}" config-optional="true"/>
+ <xml fileName="${QPID_HOME}/etc/config-systests-settings.xml"/>
+ <xml fileName="${QPID_HOME}/etc/config.xml"/>
+ </override>
+</configuration>
diff --git a/java/systests/etc/virtualhosts-ServerConfigurationTest-New.xml b/java/systests/etc/virtualhosts-ServerConfigurationTest-New.xml
new file mode 100644
index 0000000000..168aa074da
--- /dev/null
+++ b/java/systests/etc/virtualhosts-ServerConfigurationTest-New.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<virtualhosts>
+ <default>dev-only</default>
+ <virtualhost>
+ <name>dev-only</name>
+ <dev-only>
+ <queues>
+ <exchange>amq.direct</exchange>
+ <!-- Small defaults for development -->
+ <maximumQueueDepth>102400</maximumQueueDepth> <!-- 100k -->
+ <maximumMessageSize>20480</maximumMessageSize> <!-- 20kb -->
+ <maximumMessageAge>60000</maximumMessageAge> <!-- 1 mins -->
+
+ <queue>
+ <name>dev-queue</name>
+ </queue>
+ </queues>
+ </dev-only>
+ </virtualhost>
+</virtualhosts>
diff --git a/java/systests/pom.xml b/java/systests/pom.xml
deleted file mode 100644
index 73c8fb7351..0000000000
--- a/java/systests/pom.xml
+++ /dev/null
@@ -1,201 +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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-systests</artifactId>
- <packaging>jar</packaging>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <name>Qpid System Tests</name>
- <url>http://cwiki.apache.org/confluence/display/qpid</url>
-
- <parent>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid</artifactId>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <relativePath>../pom.xml</relativePath>
- </parent>
-
- <properties>
- <topDirectoryLocation>..</topDirectoryLocation>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-client</artifactId>
- <type>jar</type>
- </dependency>
-
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-broker</artifactId>
- <type>jar</type>
- </dependency>
-
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>compile</scope>
- </dependency>
-
- <dependency>
- <groupId>org.apache.qpid</groupId>
- <artifactId>junit-toolkit</artifactId>
- </dependency>
-
- <!-- Test Dependencies -->
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.4.0</version>
- <scope>test</scope>
- </dependency>
-
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <testSourceDirectory>${basedir}/src/main</testSourceDirectory>
- <testClassesDirectory>target/classes</testClassesDirectory>
- <includes>
- <include>**/*Test.class</include>
- </includes>
-
- <systemProperties>
- <property>
- <name>example.plugin.target</name>
- <value>${basedir}/${topDirectoryLocation}/plugins/target</value>
- </property>
- <property>
- <name>QPID_EXAMPLE_HOME</name>
- <value>${basedir}/${topDirectoryLocation}/broker</value>
- </property>
- <property>
- <name>QPID_HOME</name>
- <value>${basedir}/${topDirectoryLocation}/broker</value>
- </property>
- </systemProperties>
-
- <excludes>
- <exclude>**/testcases/ImmediateMessageTest.class</exclude>
- <exclude>**/testcases/MandatoryMessageTest.class</exclude>
- <exclude>**/testcases/RollbackTest.class</exclude>
- <exclude>**/testcases/TTLTest.class</exclude>
- <exclude>**/testcases/FailoverTest.class</exclude>
- </excludes>
- </configuration>
- </plugin>
-
- <!-- Runs the framework based tests against an in-vm broker. -->
- <plugin>
- <groupId>org.apache.qpid</groupId>
- <artifactId>junit-toolkit-maven-plugin</artifactId>
-
- <configuration>
- <systemproperties>
- <property>
- <name>log4j.configuration</name>
- <value>${log4j.configuration}</value>
- </property>
- </systemproperties>
-
- <testrunner>org.apache.qpid.junit.extensions.TKTestRunner</testrunner>
-
- <testrunneroptions>
- <option>-X:decorators "org.apache.qpid.test.framework.qpid.InVMBrokerDecorator:org.apache.qpid.test.framework.qpid.AMQPFeatureDecorator"</option>
- <!--<option>-d30S</option>-->
- <option>-o ${basedir}/target/surefire-reports</option>
- <option>--xml</option>
- </testrunneroptions>
-
- <testrunnerproperties>
- <property>
- <name>notApplicableAssertion</name>
- <value>warn</value>
- </property>
- </testrunnerproperties>
-
- <commands>
- <AMQBrokerManagerMBeanTest>-n AMQBrokerManagerMBeanTest org.apache.qpid.server.AMQBrokerManagerMBeanTest </AMQBrokerManagerMBeanTest>
- <TxAckTest>-n TxAckTest org.apache.qpid.server.ack.TxAckTest </TxAckTest>
- <!--<HeadersExchangeTest>-n HeadersExchangeTest org.apache.qpid.server.exchange.HeadersExchangeTest </HeadersExchangeTest>-->
- <ReturnUnroutableMandatoryMessageTest>-n ReturnUnroutableMandatoryMessageTest org.apache.qpid.server.exchange.ReturnUnroutableMandatoryMessageTest </ReturnUnroutableMandatoryMessageTest>
- <!--<FailoverMethodTest>-n FailoverMethodTest org.apache.qpid.server.failover.FailoverMethodTest </FailoverMethodTest>-->
- <DeadlockTest>-n DeadlockTest org.apache.qpid.server.failure.DeadlockTest </DeadlockTest>
- <!--<PluginTest>-n PluginTest org.apache.qpid.server.plugins.PluginTest </PluginTest>-->
- <AMQProtocolSessionMBeanTest>-n AMQProtocolSessionMBeanTest org.apache.qpid.server.protocol.AMQProtocolSessionMBeanTest </AMQProtocolSessionMBeanTest>
- <MaxChannelsTest>-n MaxChannelsTest org.apache.qpid.server.protocol.MaxChannelsTest </MaxChannelsTest>
- <AckTest>-n AckTest org.apache.qpid.server.queue.AckTest </AckTest>
- <MessageReturnTest>-n MessageReturnTest org.apache.qpid.server.queue.MessageReturnTest </MessageReturnTest>
- <QueueDepthWithSelectorTest>-n QueueDepthWithSelectorTest org.apache.qpid.server.queue.QueueDepthWithSelectorTest </QueueDepthWithSelectorTest>
- <!--<SubscriptionManagerTest>-n SubscriptionManagerTest org.apache.qpid.server.queue.SubscriptionManagerTest </SubscriptionManagerTest>-->
- <TimeToLiveTest>-n TimeToLiveTest org.apache.qpid.server.queue.TimeToLiveTest </TimeToLiveTest>
- <TxnBufferTest>-n TxnBufferTest org.apache.qpid.server.txn.TxnBufferTest </TxnBufferTest>
- <!--<TxnTest>-n TxnTest org.apache.qpid.server.txn.TxnTest </TxnTest>-->
- <!--QueueBrowserTest>-n QueueBrowserTest org.apache.qpid.test.client.QueueBrowserTest </QueueBrowserTest-->
-
- <!--<Immediate-Message-Test>-n Immediate-Test -s[1] org.apache.qpid.test.testcases.ImmediateMessageTest</Immediate-Message-Test>-->
- <!--<Mandatory-Message-Test>-n Mandatory-Test -s[1] org.apache.qpid.test.testcases.MandatoryMessageTest</Mandatory-Message-Test>-->
- <!--<Rollback-Test>-n Rollback-Test -s[1] org.apache.qpid.test.testcases.RollbackTest</Rollback-Test>-->
- </commands>
-
- </configuration>
-
- <executions>
- <execution>
- <id>framework_tests</id>
- <phase>test</phase>
- <goals>
- <goal>tktest</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
-
- </plugins>
-
- <!-- Include source files in built jar -->
- <resources>
- <resource>
- <targetPath>src/</targetPath>
- <filtering>false</filtering>
- <directory>src/main/java</directory>
- <includes>
- <include>**/*.java</include>
- </includes>
- </resource>
- <resource>
- <targetPath>src/</targetPath>
- <filtering>false</filtering>
- <directory>src/main/java</directory>
- <includes>
- <include>systests.log4j</include>
- </includes>
- </resource>
- </resources>
- </build>
-</project>
-
-
diff --git a/java/systests/src/main/java/org/apache/qpid/client/AMQQueueDeferredOrderingTest.java b/java/systests/src/main/java/org/apache/qpid/client/AMQQueueDeferredOrderingTest.java
index fe418535d6..f261858fcd 100644
--- a/java/systests/src/main/java/org/apache/qpid/client/AMQQueueDeferredOrderingTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/client/AMQQueueDeferredOrderingTest.java
@@ -20,30 +20,26 @@
*/
package org.apache.qpid.client;
+import javax.jms.Connection;
+import javax.jms.Session;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.TextMessage;
-import junit.framework.TestCase;
-
import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.jms.Session;
+import org.apache.qpid.test.utils.QpidTestCase;
import org.apache.qpid.client.transport.TransportConnection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-/**
- * This class tests all the alerts an AMQQueue can throw based on threshold
- * values of different parameters
- */
-public class AMQQueueDeferredOrderingTest extends TestCase
+public class AMQQueueDeferredOrderingTest extends QpidTestCase
{
private static final int NUM_MESSAGES = 1000;
- private AMQConnection con;
+ private Connection con;
private Session session;
private AMQQueue queue;
private MessageConsumer consumer;
@@ -51,7 +47,6 @@ public class AMQQueueDeferredOrderingTest extends TestCase
private static final Logger _logger = LoggerFactory.getLogger(AMQQueueDeferredOrderingTest.class);
private ASyncProducer producerThread;
- private static final String BROKER = "vm://:1";
private class ASyncProducer extends Thread
{
@@ -92,14 +87,13 @@ public class AMQQueueDeferredOrderingTest extends TestCase
protected void setUp() throws Exception
{
super.setUp();
- TransportConnection.createVMBroker(1);
_logger.info("Create Connection");
- con = new AMQConnection(BROKER, "guest", "guest", "OrderingTest", "test");
+ con = getConnection();
_logger.info("Create Session");
session = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
_logger.info("Create Q");
- queue = new AMQQueue(session.getDefaultQueueExchangeName(), new AMQShortString("Q"), new AMQShortString("Q"),
+ queue = new AMQQueue(new AMQShortString("amq.direct"), new AMQShortString("Q"), new AMQShortString("Q"),
false, true);
_logger.info("Create Consumer of Q");
consumer = session.createConsumer(queue);
@@ -140,7 +134,6 @@ public class AMQQueueDeferredOrderingTest extends TestCase
_logger.info("Closing connection");
con.close();
- TransportConnection.killAllVMBrokers();
super.tearDown();
}
diff --git a/java/systests/src/main/java/org/apache/qpid/client/DispatcherTest.java b/java/systests/src/main/java/org/apache/qpid/client/DispatcherTest.java
index 7cca22de6c..6b638ced58 100644
--- a/java/systests/src/main/java/org/apache/qpid/client/DispatcherTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/client/DispatcherTest.java
@@ -20,13 +20,9 @@
*/
package org.apache.qpid.client;
-import junit.framework.TestCase;
-
-import org.apache.qpid.client.transport.TransportConnection;
-import org.apache.qpid.jndi.PropertiesFileInitialContextFactory;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.util.Hashtable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
@@ -40,9 +36,11 @@ import javax.jms.Session;
import javax.naming.Context;
import javax.naming.spi.InitialContextFactory;
-import java.util.Hashtable;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.jndi.PropertiesFileInitialContextFactory;
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* QPID-293 Setting MessageListener after connection has started can cause messages to be "lost" on a internal delivery queue
@@ -56,7 +54,7 @@ import java.util.concurrent.TimeUnit;
* When setting the message listener later the _synchronousQueue is just poll()'ed and the first message delivered
* the remaining messages will be left on the queue and lost, subsequent messages on the session will arrive first.
*/
-public class DispatcherTest extends TestCase
+public class DispatcherTest extends QpidTestCase
{
private static final Logger _logger = LoggerFactory.getLogger(DispatcherTest.class);
@@ -78,28 +76,21 @@ public class DispatcherTest extends TestCase
protected void setUp() throws Exception
{
super.setUp();
- TransportConnection.createVMBroker(1);
InitialContextFactory factory = new PropertiesFileInitialContextFactory();
Hashtable<String, String> env = new Hashtable<String, String>();
- env.put("connectionfactory.connection", "amqp://guest:guest@MLT_ID/test?brokerlist='vm://:1'");
- env.put("queue.queue", "MessageListenerTest");
-
- _context = factory.getInitialContext(env);
-
- Queue queue = (Queue) _context.lookup("queue");
-
// Create Client 1
- _clientConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection();
+ _clientConnection = getConnection();
_clientSession = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Queue queue = _clientSession.createQueue(this.getClass().getName());
_consumer = _clientSession.createConsumer(queue);
// Create Producer
- _producerConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection();
+ _producerConnection = getConnection();
_producerConnection.start();
@@ -120,7 +111,6 @@ public class DispatcherTest extends TestCase
_producerConnection.close();
super.tearDown();
- TransportConnection.killAllVMBrokers();
}
public void testAsynchronousRecieve()
diff --git a/java/systests/src/main/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java b/java/systests/src/main/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java
index b438304892..4c2fefb312 100644
--- a/java/systests/src/main/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java
@@ -36,6 +36,7 @@ import javax.naming.Context;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.UUID;
/**
* QPID-293 Setting MessageListener after connection has started can cause messages to be "lost" on a internal delivery
@@ -61,6 +62,7 @@ public class MessageListenerMultiConsumerTest extends QpidTestCase
private Session _clientSession1;
private Queue _queue;
private final CountDownLatch _allMessagesSent = new CountDownLatch(2); // all messages Sent Lock
+ private static final String QUEUE_NAME = "queue" + UUID.randomUUID().toString();
protected void setUp() throws Exception
{
@@ -73,7 +75,7 @@ public class MessageListenerMultiConsumerTest extends QpidTestCase
_clientSession1 = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
- _queue =_clientSession1.createQueue("queue");
+ _queue =_clientSession1.createQueue(QUEUE_NAME);
_consumer1 = _clientSession1.createConsumer(_queue);
@@ -113,12 +115,12 @@ public class MessageListenerMultiConsumerTest extends QpidTestCase
for (int loops = 0; (msg < MSG_COUNT) || (loops < MAX_LOOPS); loops++)
{
- if (_consumer1.receive(100) != null)
+ if (_consumer1.receive(1000) != null)
{
msg++;
}
- if (_consumer2.receive(100) != null)
+ if (_consumer2.receive(1000) != null)
{
msg++;
}
@@ -197,13 +199,15 @@ public class MessageListenerMultiConsumerTest extends QpidTestCase
{
_logger.info("Performing Receive only with two consumers on one session ");
- MessageConsumer consumer2 = _clientSession1.createConsumer(_queue);
+ //Create a new consumer on session one that we don't use
+ _clientSession1.createConsumer(_queue);
int msg;
for (msg = 0; msg < (MSG_COUNT / 2); msg++)
{
-
+ // Attempt to receive up to half the messages
+ // The other half may have gone to the consumer above
final Message message = _consumer1.receive(1000);
if(message == null)
{
@@ -213,8 +217,12 @@ public class MessageListenerMultiConsumerTest extends QpidTestCase
}
_consumer1.close();
+ // This will close the unused consumer above.
_clientSession1.close();
+
+ // msg will now have recorded the number received on session 1
+ // attempt to retrieve the rest on session 2
for (; msg < MSG_COUNT ; msg++)
{
assertTrue("Failed at msg id" + msg, _consumer2.receive(1000) != null);
diff --git a/java/systests/src/main/java/org/apache/qpid/client/MessageListenerTest.java b/java/systests/src/main/java/org/apache/qpid/client/MessageListenerTest.java
index 4c1d5ee9c1..ffec6c7a29 100644
--- a/java/systests/src/main/java/org/apache/qpid/client/MessageListenerTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/client/MessageListenerTest.java
@@ -106,6 +106,14 @@ public class MessageListenerTest extends QpidTestCase implements MessageListener
}
}
+ public void testSynchronousRecieveNoWait() throws Exception
+ {
+ for (int msg = 0; msg < MSG_COUNT; msg++)
+ {
+ assertTrue(_consumer.receiveNoWait() != null);
+ }
+ }
+
public void testAsynchronousRecieve() throws Exception
{
_consumer.setMessageListener(this);
diff --git a/java/systests/src/main/java/org/apache/qpid/client/MultipleJCAProviderRegistrationTest.java b/java/systests/src/main/java/org/apache/qpid/client/MultipleJCAProviderRegistrationTest.java
new file mode 100644
index 0000000000..61c1326ad5
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/client/MultipleJCAProviderRegistrationTest.java
@@ -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.
+ *
+ */
+package org.apache.qpid.client;
+
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.client.transport.TransportConnection;
+
+import java.io.File;
+import java.security.Provider;
+import java.security.Security;
+import java.util.List;
+import java.util.LinkedList;
+
+/**
+ * QPID-1394 : Test to ensure that the client can register their custom JCAProviders after the broker to ensure that
+ * the Qpid custom authentication SASL plugins are used.
+ */
+public class MultipleJCAProviderRegistrationTest extends QpidTestCase
+{
+
+ public void setUp() throws Exception
+ {
+ _broker = VM;
+
+ super.setUp();
+ }
+
+ public void test() throws Exception
+ {
+ // Get the providers before connection
+ Provider[] providers = Security.getProviders();
+
+ // Force the client to load the providers
+ getConnection();
+
+ Provider[] afterConnectionCreation = Security.getProviders();
+
+ // Find the additions
+ List additions = new LinkedList();
+ for (Provider afterCreation : afterConnectionCreation)
+ {
+ boolean found = false;
+ for (Provider provider : providers)
+ {
+ if (provider == afterCreation)
+ {
+ found=true;
+ break;
+ }
+ }
+
+ // Record added registies
+ if (!found)
+ {
+ additions.add(afterCreation);
+ }
+ }
+
+ assertTrue("Client did not register any providers", additions.size() > 0);
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/client/ResetMessageListenerTest.java b/java/systests/src/main/java/org/apache/qpid/client/ResetMessageListenerTest.java
index a0bb31192f..636fb714e0 100644
--- a/java/systests/src/main/java/org/apache/qpid/client/ResetMessageListenerTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/client/ResetMessageListenerTest.java
@@ -55,31 +55,20 @@ public class ResetMessageListenerTest extends QpidTestCase
Context _context;
private static final int MSG_COUNT = 6;
- private int receivedCount1ML1 = 0;
- private int receivedCount1ML2 = 0;
- private int receivedCount2 = 0;
private Connection _clientConnection, _producerConnection;
private MessageConsumer _consumer1;
- private MessageConsumer _consumer2;
MessageProducer _producer;
Session _clientSession, _producerSession;
- private final CountDownLatch _allFirstMessagesSent = new CountDownLatch(2); // all messages Sent Lock
- private final CountDownLatch _allSecondMessagesSent = new CountDownLatch(2); // all messages Sent Lock
- private final CountDownLatch _allFirstMessagesSent010 = new CountDownLatch(MSG_COUNT); // all messages Sent Lock
- private final CountDownLatch _allSecondMessagesSent010 = new CountDownLatch(MSG_COUNT); // all messages Sent Lock
-
- private String oldImmediatePrefetch;
+ private final CountDownLatch _allFirstMessagesSent = new CountDownLatch(MSG_COUNT); // all messages Sent Lock
+ private final CountDownLatch _allSecondMessagesSent = new CountDownLatch(MSG_COUNT); // all messages Sent Lock
protected void setUp() throws Exception
{
super.setUp();
- oldImmediatePrefetch = System.getProperty(AMQSession.IMMEDIATE_PREFETCH);
- System.setProperty(AMQSession.IMMEDIATE_PREFETCH, "true");
-
_clientConnection = getConnection("guest", "guest");
-
+ _clientConnection.start();
// Create Client 1
_clientSession = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
@@ -88,9 +77,6 @@ public class ResetMessageListenerTest extends QpidTestCase
_consumer1 = _clientSession.createConsumer(queue);
- // Create Client 2 on same session
- _consumer2 = _clientSession.createConsumer(queue);
-
// Create Producer
_producerConnection = getConnection("guest", "guest");
@@ -107,7 +93,6 @@ public class ResetMessageListenerTest extends QpidTestCase
m.setText("Message " + msg);
_producer.send(m);
}
-
}
protected void tearDown() throws Exception
@@ -115,268 +100,126 @@ public class ResetMessageListenerTest extends QpidTestCase
_clientConnection.close();
super.tearDown();
- if (oldImmediatePrefetch == null)
- {
- oldImmediatePrefetch = AMQSession.IMMEDIATE_PREFETCH_DEFAULT;
- }
- System.setProperty(AMQSession.IMMEDIATE_PREFETCH, oldImmediatePrefetch);
}
public void testAsynchronousRecieve()
{
_logger.info("Test Start");
- if (isBroker08())
+
+ try
{
- // Set default Message Listener
- try
+ _consumer1.setMessageListener(new MessageListener()
{
- _consumer1.setMessageListener(new MessageListener()
+ public void onMessage(Message message)
{
- public void onMessage(Message message)
+ try
{
- _logger.info("Client 1 ML 1 Received Message(" + receivedCount1ML1 + "):" + message);
-
- receivedCount1ML1++;
- if (receivedCount1ML1 == (MSG_COUNT / 2))
+ if (message.getStringProperty("rank").equals("first"))
{
_allFirstMessagesSent.countDown();
}
}
- });
- }
- catch (JMSException e)
- {
- _logger.error("Error Setting Default ML on consumer1");
- }
-
- try
- {
- _consumer2.setMessageListener(new MessageListener()
- {
- public void onMessage(Message message)
+ catch (JMSException e)
{
- _logger.info("Client 2 Received Message(" + receivedCount2 + "):" + message);
-
- receivedCount2++;
- if (receivedCount2 == (MSG_COUNT / 2))
- {
- _logger.info("Client 2 received all its messages1");
- _allFirstMessagesSent.countDown();
- }
-
- if (receivedCount2 == MSG_COUNT)
- {
- _logger.info("Client 2 received all its messages2");
- _allSecondMessagesSent.countDown();
- }
+ e.printStackTrace();
+ fail("error receiving message");
}
- });
-
- _clientConnection.start();
- }
- catch (JMSException e)
- {
- _logger.error("Error Setting Default ML on consumer2");
-
- }
-
- try
- {
- _allFirstMessagesSent.await(1000, TimeUnit.MILLISECONDS);
- _logger.info("Received first batch of messages");
- }
- catch (InterruptedException e)
- {
- // do nothing
- }
-
- try
- {
- _clientConnection.stop();
- }
- catch (JMSException e)
- {
- _logger.error("Error stopping connection");
- }
-
- _logger.info("Reset Message Listener to better listener while connection stopped, will restart session");
- try
- {
- _consumer1.setMessageListener(new MessageListener()
- {
- public void onMessage(Message message)
- {
- _logger.info("Client 1 ML2 Received Message(" + receivedCount1ML1 + "):" + message);
-
- receivedCount1ML2++;
- if (receivedCount1ML2 == (MSG_COUNT / 2))
- {
- _allSecondMessagesSent.countDown();
- }
- }
- });
-
- _clientConnection.start();
- }
- catch (javax.jms.IllegalStateException e)
- {
- _logger.error("Connection not stopped while setting ML", e);
- fail("Unable to change message listener:" + e.getCause());
- }
- catch (JMSException e)
- {
- _logger.error("Error Setting Better ML on consumer1", e);
- }
-
- try
- {
- _logger.info("Send additional messages");
-
- for (int msg = 0; msg < MSG_COUNT; msg++)
- {
- _producer.send(_producerSession.createTextMessage("Message " + msg));
}
- }
- catch (JMSException e)
- {
- _logger.error("Unable to send additional messages", e);
- }
-
- _logger.info("Waiting upto 2 seconds for messages");
+ });
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error Setting Default ML on consumer1");
+ }
+ try
+ {
+ assertTrue("Did not receive all first batch of messages",
+ _allFirstMessagesSent.await(1000, TimeUnit.MILLISECONDS));
+ _logger.info("Received first batch of messages");
+ }
+ catch (InterruptedException e)
+ {
+ // do nothing
+ }
- try
- {
- _allSecondMessagesSent.await(5000, TimeUnit.MILLISECONDS);
- }
- catch (InterruptedException e)
- {
- // do nothing
- }
- assertEquals("First batch of messages not received correctly", 0, _allFirstMessagesSent.getCount());
- assertEquals("Second batch of messages not received correctly", 0, _allSecondMessagesSent.getCount());
- assertEquals("Client 1 ML1 didn't get all messages", MSG_COUNT / 2, receivedCount1ML1);
- assertEquals("Client 2 didn't get all messages", MSG_COUNT, receivedCount2);
- assertEquals("Client 1 ML2 didn't get all messages", MSG_COUNT / 2, receivedCount1ML2);
+ try
+ {
+ _clientConnection.stop();
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error stopping connection");
}
- else
+
+ _logger.info("Reset Message Listener ");
+ try
{
- try
+ _consumer1.setMessageListener(new MessageListener()
{
- _consumer2.close();
- _consumer1.setMessageListener(new MessageListener()
+ public void onMessage(Message message)
{
- public void onMessage(Message message)
+ try
{
- _logger.info("Received Message(" + receivedCount1ML1 + "):" + message);
-
- try
+ if (message.getStringProperty("rank").equals("first"))
{
- if (message.getStringProperty("rank").equals("first"))
- {
- _allFirstMessagesSent010.countDown();
- }
+ // Something ugly will happen, it'll probably kill the dispatcher
+ fail("All first set of messages should have been received");
}
- catch (JMSException e)
+ else
{
- e.printStackTrace();
- fail("error receiving message");
+ _allSecondMessagesSent.countDown();
}
}
- });
- }
- catch (JMSException e)
- {
- _logger.error("Error Setting Default ML on consumer1");
- }
- try
- {
- _allFirstMessagesSent.await(1000, TimeUnit.MILLISECONDS);
- _logger.info("Received first batch of messages");
- }
- catch (InterruptedException e)
- {
- // do nothing
- }
-
- try
- {
- _clientConnection.stop();
- }
- catch (JMSException e)
- {
- _logger.error("Error stopping connection");
- }
-
- _logger.info("Reset Message Listener ");
- try
- {
- _consumer1.setMessageListener(new MessageListener()
- {
- public void onMessage(Message message)
+ catch (JMSException e)
{
- _logger.info("Received Message(" + receivedCount1ML1 + "):" + message);
-
- try
- {
- if (message.getStringProperty("rank").equals("first"))
- {
- _allFirstMessagesSent010.countDown();
- }
- else
- {
- _allSecondMessagesSent010.countDown();
- }
- }
- catch (JMSException e)
- {
- e.printStackTrace();
- fail("error receiving message");
- }
+ e.printStackTrace();
+ // Something ugly will happen, it'll probably kill the dispatcher
+ fail("error receiving message");
}
- });
+ }
+ });
- _clientConnection.start();
- }
- catch (javax.jms.IllegalStateException e)
- {
- _logger.error("Connection not stopped while setting ML", e);
- fail("Unable to change message listener:" + e.getCause());
- }
- catch (JMSException e)
- {
- _logger.error("Error Setting Better ML on consumer1", e);
- }
+ _clientConnection.start();
+ }
+ catch (javax.jms.IllegalStateException e)
+ {
+ _logger.error("Connection not stopped while setting ML", e);
+ fail("Unable to change message listener:" + e.getCause());
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error Setting Better ML on consumer1", e);
+ }
- try
- {
- _logger.info("Send additional messages");
- TextMessage m = _producerSession.createTextMessage();
- m.setStringProperty("rank", "second");
- for (int msg = 0; msg < MSG_COUNT; msg++)
- {
- m.setText("Message " + msg);
- _producer.send(m);
- }
- }
- catch (JMSException e)
+ try
+ {
+ _logger.info("Send additional messages");
+ TextMessage m = _producerSession.createTextMessage();
+ m.setStringProperty("rank", "second");
+ for (int msg = 0; msg < MSG_COUNT; msg++)
{
- _logger.error("Unable to send additional messages", e);
+ m.setText("Message " + msg);
+ _producer.send(m);
}
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Unable to send additional messages", e);
+ }
- _logger.info("Waiting upto 2 seconds for messages");
+ _logger.info("Waiting for messages");
- try
- {
- _allSecondMessagesSent.await(1000, TimeUnit.MILLISECONDS);
- }
- catch (InterruptedException e)
- {
- // do nothing
- }
- assertEquals("First batch of messages not received correctly", 0, _allFirstMessagesSent010.getCount());
- assertEquals("Second batch of messages not received correctly", 0, _allSecondMessagesSent010.getCount());
+ try
+ {
+ assertTrue(_allSecondMessagesSent.await(1000, TimeUnit.MILLISECONDS));
+ }
+ catch (InterruptedException e)
+ {
+ // do nothing
}
+ assertEquals("First batch of messages not received correctly", 0, _allFirstMessagesSent.getCount());
+ assertEquals("Second batch of messages not received correctly", 0, _allSecondMessagesSent.getCount());
}
public static junit.framework.Test suite()
diff --git a/java/systests/src/main/java/org/apache/qpid/client/SessionCreateTest.java b/java/systests/src/main/java/org/apache/qpid/client/SessionCreateTest.java
new file mode 100644
index 0000000000..1672c2a828
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/client/SessionCreateTest.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.client;
+
+import javax.jms.Connection;
+import javax.jms.Session;
+import javax.naming.Context;
+
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Class to check that session creation on a connection has no accidental limit
+ */
+public class SessionCreateTest extends QpidTestCase
+{
+ private static final Logger _logger = LoggerFactory.getLogger(MessageListenerTest.class);
+
+ Context _context;
+
+ private Connection _clientConnection;
+ protected int maxSessions = 65555;
+
+ public void testSessionCreationLimit() throws Exception
+ {
+ // Create Client
+ _clientConnection = getConnection("guest", "guest");
+
+ _clientConnection.start();
+
+ for (int i=0; i < maxSessions; i++)
+ {
+ Session sess = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ assertNotNull(sess);
+ sess.close();
+ System.out.println("created session: " + i);
+ }
+
+ _clientConnection.close();
+
+ }
+
+} \ No newline at end of file
diff --git a/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagementActorLoggingTest.java b/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagementActorLoggingTest.java
new file mode 100644
index 0000000000..2e107ada34
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagementActorLoggingTest.java
@@ -0,0 +1,530 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.jmx;
+
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedConnection;
+import org.apache.qpid.management.common.mbeans.ManagedExchange;
+import org.apache.qpid.server.logging.AbstractTestLogging;
+import org.apache.qpid.server.logging.subjects.AbstractTestLogSubject;
+import org.apache.qpid.test.utils.JMXTestUtils;
+
+import javax.jms.Connection;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.management.JMException;
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test class to test if any change in the broker JMX code is affesting the management console
+ * There are some hardcoding of management feature names and parameter names to create a customized
+ * look in the console.
+ */
+public class ManagementActorLoggingTest extends AbstractTestLogging
+{
+ private JMXTestUtils _jmxUtils;
+ private static final String USER = "admin";
+
+ @Override
+ public void setUp() throws Exception
+ {
+ _jmxUtils = new JMXTestUtils(this, USER, USER);
+ _jmxUtils.setUp();
+ super.setUp();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ _jmxUtils.close();
+ super.tearDown();
+ }
+
+ /**
+ * Description:
+ * When a JMX Management connection is made then this will be logged out.
+ *
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Connect Management client via JMX
+ * Output:
+ *
+ * <date> MNG-1007 : Open <user>
+ *
+ * Validation Steps:
+ * 1. The MNG ID is correct
+ * 2. The user is correct
+ *
+ * On connection close a MNG-1008 is expected
+ *
+ * * <date> MNG-1008 : Close
+ *
+ * Validation Steps:
+ * 1. The MNG ID is correct
+ *
+ * @throws java.io.IOException - if there is a problem reseting the log monitor
+ */
+ public void testJMXManagementConsoleConnection() throws IOException
+ {
+ List<String> results = _monitor.findMatches("MNG-1007");
+
+ assertEquals("Unexpected Management Connection count", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ validateMessageID("MNG-1007", log);
+
+ assertTrue("User not in log message:" + log, log.endsWith(USER));
+ // Extract the id from the log string
+ // MESSAGE [mng:1(rmi://169.24.29.116)] MNG-1007 : Open : User admin
+ int connectionID = Integer.parseInt(fromActor(getLog(results.get(0))).charAt(4) + "");
+
+ results = _monitor.findMatches("MNG-1008");
+
+ assertEquals("Unexpected Management Connection close count", 0, results.size());
+
+ _jmxUtils.close();
+
+ results = _monitor.findMatches("MNG-1008");
+
+ assertEquals("Unexpected Management Connection count", 1, results.size());
+
+ assertEquals("Close does not have same id as open,", connectionID,
+ Integer.parseInt(fromActor(getLog(results.get(0))).charAt(4) + ""));
+ }
+
+ /**
+ * Description:
+ * When a connected client has its connection closed via the Management Console this will be logged as a CON-1002 message.
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Connected Client
+ * 3. Connection is closed via Management Console
+ * Output:
+ *
+ * <date> CON-1002 : Close
+ *
+ * Validation Steps:
+ * 4. The CON ID is correct
+ * 5. This must be the last CON message for the Connection
+ * 6. It must be preceded by a CON-1001 for this Connection
+ *
+ * @throws Exception - {@see ManagedConnection.closeConnection and #getConnection}
+ * @throws java.io.IOException - if there is a problem reseting the log monitor
+ */
+ public void testConnectionCloseViaManagement() throws IOException, Exception
+ {
+ //Create a connection to the broker
+ Connection connection = getConnection();
+
+ // Monitor the connection for an exception being thrown
+ // this should be a DisconnectionException but it is not this tests
+ // job to valiate that. Only use the exception as a synchronisation
+ // to check the log file for the Close message
+ final CountDownLatch exceptionReceived = new CountDownLatch(1);
+ connection.setExceptionListener(new ExceptionListener()
+ {
+ public void onException(JMSException e)
+ {
+ //Failover being attempted.
+ exceptionReceived.countDown();
+ }
+ });
+
+ //Remove the connection close from any 0-10 connections
+ _monitor.reset();
+
+ // Get a managedConnection
+ ManagedConnection mangedConnection = _jmxUtils.getManagedObject(ManagedConnection.class, "org.apache.qpid:type=VirtualHost.Connection,*");
+
+ //Close the connection
+ mangedConnection.closeConnection();
+
+ //Wait for the connection to close
+ assertTrue("Timed out waiting for conneciton to report close",
+ exceptionReceived.await(2, TimeUnit.SECONDS));
+
+ //Validate results
+ List<String> results = _monitor.findMatches("CON-1002");
+
+ assertEquals("Unexpected Connection Close count", 1, results.size());
+ }
+
+ /**
+ * Description:
+ * Exchange creation is possible from the Management Console.
+ * When an exchanged is created in this way then a EXH-1001 create message
+ * is expected to be logged.
+ * Input:
+ *
+ * 1. Running broker
+ * 2. Connected Management Console
+ * 3. Exchange Created via Management Console
+ * Output:
+ *
+ * EXH-1001 : Create : [Durable] Type:<value> Name:<value>
+ *
+ * Validation Steps:
+ * 4. The EXH ID is correct
+ * 5. The correct tags are present in the message based on the create options
+ *
+ * @throws java.io.IOException - if there is a problem reseting the log monitor
+ * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.deleteQueue}
+ */
+ public void testCreateExchangeDirectTransientViaManagementConsole() throws IOException, JMException
+ {
+ _monitor.reset();
+
+ _jmxUtils.createExchange("test", "direct", null, false);
+
+ // Validate
+
+ //1 - ID is correct
+ List<String> results = _monitor.findMatches("EXH-1001");
+
+ assertEquals("More than one exchange creation found", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ // Validate correct exchange name
+ assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName()));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ }
+
+ public void testCreateExchangeTopicTransientViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous exchange declares
+ _monitor.reset();
+
+ _jmxUtils.createExchange("test", "topic", null, false);
+
+ // Validate
+
+ //1 - ID is correct
+ List<String> results = _monitor.findMatches("EXH-1001");
+
+ assertEquals("More than one exchange creation found", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ // Validate correct exchange name
+ assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName()));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+
+ }
+
+ public void testCreateExchangeFanoutTransientViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous exchange declares
+ _monitor.reset();
+
+ _jmxUtils.createExchange("test", "fanout", null, false);
+
+ // Validate
+
+ //1 - ID is correct
+ List<String> results = _monitor.findMatches("EXH-1001");
+
+ assertEquals("More than one exchange creation found", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ // Validate correct exchange name
+ assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName()));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+
+ }
+
+ public void testCreateExchangeHeadersTransientViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous exchange declares
+ _monitor.reset();
+
+ _jmxUtils.createExchange("test", "headers", null, false);
+
+ // Validate
+
+ //1 - ID is correct
+ List<String> results = _monitor.findMatches("EXH-1001");
+
+ assertEquals("More than one exchange creation found", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ // Validate correct exchange name
+ assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName()));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+
+ }
+
+ /**
+ * Description:
+ * Queue creation is possible from the Management Console. When a queue is created in this way then a QUE-1001 create message is expected to be logged.
+ * Input:
+ *
+ * 1. Running broker
+ * 2. Connected Management Console
+ * 3. Queue Created via Management Console
+ * Output:
+ *
+ * <date> QUE-1001 : Create : Transient Owner:<name>
+ *
+ * Validation Steps:
+ * 4. The QUE ID is correct
+ * 5. The correct tags are present in the message based on the create options
+ *
+ * @throws java.io.IOException - if there is a problem reseting the log monitor
+ * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.deleteQueue}
+ */
+ public void testCreateQueueTransientViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous queue declares
+ _monitor.reset();
+
+ _jmxUtils.createQueue("test", getName(), null, false);
+
+ // Validate
+
+ List<String> results = _monitor.findMatches("QUE-1001");
+
+ assertEquals("More than one queue creation found", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ // Validate correct queue name
+ String subject = fromSubject(log);
+ assertEquals("Incorrect queue name created", getName(), AbstractTestLogSubject.getSlice("qu", subject));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ }
+
+ /**
+ * Description:
+ * The ManagementConsole can be used to delete a queue. When this is done a QUE-1002 Deleted message must be logged.
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Queue created on the broker with no subscribers
+ * 3. Management Console connected
+ * 4. Queue is deleted via Management Console
+ * Output:
+ *
+ * <date> QUE-1002 : Deleted
+ *
+ * Validation Steps:
+ * 5. The QUE ID is correct
+ *
+ * @throws java.io.IOException - if there is a problem reseting the log monitor
+ * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.deleteQueue}
+ */
+ public void testQueueDeleteViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous queue declares
+ _monitor.reset();
+
+ _jmxUtils.createQueue("test", getName(), null, false);
+
+ ManagedBroker managedBroker = _jmxUtils.getManagedBroker("test");
+
+ managedBroker.deleteQueue(getName());
+
+ List<String> results = _monitor.findMatches("QUE-1002");
+
+ assertEquals("More than one queue deletion found", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ // Validate correct binding
+ String subject = fromSubject(log);
+ assertEquals("Incorrect queue named in delete", getName(), AbstractTestLogSubject.getSlice("qu", subject));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+
+ }
+
+ /**
+ * Description:
+ * The binding of a Queue and an Exchange is done via a Binding. When this Binding is created via the Management Console a BND-1001 Create message will be logged.
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Connected Management Console
+ * 3. Use Management Console to perform binding
+ * Output:
+ *
+ * <date> BND-1001 : Create
+ *
+ * Validation Steps:
+ * 4. The BND ID is correct
+ * 5. This will be the first message for the given binding
+ *
+ * @throws java.io.IOException - if there is a problem reseting the log monitor
+ * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.createNewBinding}
+ */
+ public void testBindingCreateOnDirectViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous queue declares
+ _monitor.reset();
+
+ _jmxUtils.createQueue("test", getName(), null, false);
+
+ ManagedExchange managedExchange = _jmxUtils.getManagedExchange("amq.direct");
+
+ managedExchange.createNewBinding(getName(), getName());
+
+ List<String> results = _monitor.findMatches("BND-1001");
+
+ assertEquals("More than one bind creation found", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ // Validate correct binding
+ String subject = fromSubject(log);
+ assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject));
+ assertEquals("Incorrect routing key in create", getName(), AbstractTestLogSubject.getSlice("rk", subject));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ }
+
+ public void testBindingCreateOnTopicViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous queue declares
+ _monitor.reset();
+
+ _jmxUtils.createQueue("test", getName(), null, false);
+
+ ManagedExchange managedExchange = _jmxUtils.getManagedExchange("amq.topic");
+
+ managedExchange.createNewBinding(getName(), getName());
+
+ List<String> results = _monitor.findMatches("BND-1001");
+
+ assertEquals("More than one bind creation found", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ // Validate correct binding
+ String subject = fromSubject(log);
+ assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject));
+ assertEquals("Incorrect routing key in create", getName(), AbstractTestLogSubject.getSlice("rk", subject));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ }
+
+ public void testBindingCreateOnFanoutViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous queue declares
+ _monitor.reset();
+
+ _jmxUtils.createQueue("test", getName(), null, false);
+
+ ManagedExchange managedExchange = _jmxUtils.getManagedExchange("amq.fanout");
+
+ managedExchange.createNewBinding(getName(), getName());
+
+ List<String> results = _monitor.findMatches("BND-1001");
+
+ assertEquals("More than one bind creation found", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ // Validate correct binding
+ String subject = fromSubject(log);
+ assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject));
+ assertEquals("Incorrect routing key in create", "*", AbstractTestLogSubject.getSlice("rk", subject));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ }
+
+ /**
+ * Description:
+ * Bindings can be deleted so that a queue can be rebound with a different set of values. This can be performed via the Management Console
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Management Console connected
+ * 3. Management Console is used to perform unbind.
+ * Output:
+ *
+ * <date> BND-1002 : Deleted
+ *
+ * Validation Steps:
+ * 4. The BND ID is correct
+ * 5. There must have been a BND-1001 Create message first.
+ * 6. This will be the last message for the given binding
+ *
+ * @throws java.io.IOException - if there is a problem reseting the log monitor or an issue with the JMX Connection
+ * @throws javax.management.JMException - {@see #createExchange and ManagedBroker.unregisterExchange}
+ */
+ public void testUnRegisterExchangeViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous queue declares
+ _monitor.reset();
+
+ _jmxUtils.createExchange("test", "direct", null, false);
+
+ ManagedBroker managedBroker = _jmxUtils.getManagedBroker("test");
+
+ managedBroker.unregisterExchange(getName());
+
+ List<String> results = _monitor.findMatches("EXH-1002");
+
+ assertEquals("More than one exchange deletion found", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ // Validate correct binding
+ String subject = fromSubject(log);
+ assertEquals("Incorrect exchange named in delete", "direct/" + getName(), AbstractTestLogSubject.getSlice("ex", subject));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java b/java/systests/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java
deleted file mode 100644
index b9b3168fcc..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java
+++ /dev/null
@@ -1,92 +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.
- *
- */
-package org.apache.qpid.server;
-
-import junit.framework.TestCase;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.exchange.ExchangeRegistry;
-import org.apache.qpid.server.management.ManagedBroker;
-import org.apache.qpid.server.queue.QueueRegistry;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.registry.IApplicationRegistry;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.client.transport.TransportConnection;
-
-public class AMQBrokerManagerMBeanTest extends TestCase
-{
- private QueueRegistry _queueRegistry;
- private ExchangeRegistry _exchangeRegistry;
-
- public void testExchangeOperations() throws Exception
- {
- String exchange1 = "testExchange1_" + System.currentTimeMillis();
- String exchange2 = "testExchange2_" + System.currentTimeMillis();
- String exchange3 = "testExchange3_" + System.currentTimeMillis();
-
- assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange1)) == null);
- assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange2)) == null);
- assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange3)) == null);
-
- VirtualHost vHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test");
-
- ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHost.VirtualHostMBean) vHost.getManagedObject());
- mbean.createNewExchange(exchange1, "direct", false);
- mbean.createNewExchange(exchange2, "topic", false);
- mbean.createNewExchange(exchange3, "headers", false);
-
- assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange1)) != null);
- assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange2)) != null);
- assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange3)) != null);
-
- mbean.unregisterExchange(exchange1);
- mbean.unregisterExchange(exchange2);
- mbean.unregisterExchange(exchange3);
-
- assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange1)) == null);
- assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange2)) == null);
- assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange3)) == null);
- }
-
- public void testQueueOperations() throws Exception
- {
- String queueName = "testQueue_" + System.currentTimeMillis();
- VirtualHost vHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test");
-
- ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHost.VirtualHostMBean) vHost.getManagedObject());
-
- assertTrue(_queueRegistry.getQueue(new AMQShortString(queueName)) == null);
-
- mbean.createNewQueue(queueName, "test", false);
- assertTrue(_queueRegistry.getQueue(new AMQShortString(queueName)) != null);
-
- mbean.deleteQueue(queueName);
- assertTrue(_queueRegistry.getQueue(new AMQShortString(queueName)) == null);
- }
-
- @Override
- protected void setUp() throws Exception
- {
- super.setUp();
- IApplicationRegistry appRegistry = ApplicationRegistry.getInstance();
- _queueRegistry = appRegistry.getVirtualHostRegistry().getVirtualHost("test").getQueueRegistry();
- _exchangeRegistry = appRegistry.getVirtualHostRegistry().getVirtualHost("test").getExchangeRegistry();
- }
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/BrokerStartupTest.java b/java/systests/src/main/java/org/apache/qpid/server/BrokerStartupTest.java
new file mode 100644
index 0000000000..e7975f8d24
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/BrokerStartupTest.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server;
+
+import org.apache.qpid.server.logging.AbstractTestLogging;
+import org.apache.qpid.util.LogMonitor;
+import org.apache.log4j.Logger;
+import org.apache.log4j.Level;
+
+import java.util.List;
+
+import junit.framework.AssertionFailedError;
+
+import javax.jms.Connection;
+import javax.jms.Session;
+import javax.jms.Queue;
+
+/**
+ * Series of tests to validate the external Java broker starts up as expected.
+ */
+public class BrokerStartupTest extends AbstractTestLogging
+{
+ public void setUp() throws Exception
+ {
+ // We either do this here or have a null check in tearDown.
+ // As when this test is run against profiles other than java it will NPE
+ _monitor = new LogMonitor(_outputFile);
+ //We explicitly do not call super.setUp as starting up the broker is
+ //part of the test case.
+ }
+
+
+ /**
+ * Description:
+ * Test that providing an invalid broker logging configuration file does not
+ * cause the broker to enable DEBUG logging that will seriously impair
+ * performance
+ * Input:
+ * -l value that does not exist
+ * <p/>
+ * Output:
+ * <p/>
+ * No DEBUG output
+ * <p/>
+ * Validation Steps:
+ * <p/>
+ * 1. Start the broker and verify no DEBUG output exists
+ *
+ * @throws Exception caused by broker startup
+ */
+ public void testInvalidLog4jConfigurationFile() throws Exception
+ {
+ // This logging startup code only occurs when you run a Java broker,
+ // that broker must be started via Main so not an InVM broker.
+ if (isJavaBroker() && isExternalBroker())
+ {
+ //Remove test Log4j config from the commandline
+ _broker = _broker.substring(0, _broker.indexOf("-l"));
+
+ // Add an invalid value
+ _broker += " -l invalid";
+
+ // The broker has a built in default log4j configuration set up
+ // so if the the broker cannot load the -l value it will use default
+ // use this default. Test that this is correctly loaded, by
+ // including -Dlog4j.debug so we can validate.
+ setBrokerEnvironment("QPID_OPTS", "-Dlog4j.debug");
+
+ // Disable all client logging so we can test for broker DEBUG only.
+ setLoggerLevel(Logger.getRootLogger(), Level.WARN);
+ setLoggerLevel(Logger.getLogger("qpid.protocol"), Level.WARN);
+ setLoggerLevel(Logger.getLogger("org.apache.qpid"), Level.WARN);
+
+ // Set the broker to use info level logging, which is the qpid-server
+ // default. Rather than debug which is the test default.
+ setBrokerOnlySystemProperty("amqj.server.logging.level", "info");
+ // Set the logging defaults to info for this test.
+ setBrokerOnlySystemProperty("amqj.logging.level", "info");
+ setBrokerOnlySystemProperty("root.logging.level", "info");
+
+ startBroker();
+
+ assertEquals("Log4j could not load desired configruation.",
+ 0, _monitor.findMatches("log4j:ERROR Could not read configuration file from URL").size());
+
+ assertEquals("Logging did not error as expected",
+ 1, _monitor.findMatches("Logging configuration error: unable to read file ").size());
+
+
+ // Perfom some action on the broker to ensure that we hit the DEBUG
+ // messages that we know are there. Though the current xml parsing
+ // will generate a LOT of DEBUG on startup.
+ Connection connection = getConnection();
+
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ Queue queue = session.createQueue(getTestQueueName());
+ session.createConsumer(queue).close();
+
+ int COUNT = 10;
+ sendMessage(session, queue, COUNT);
+
+ assertEquals(COUNT,drainQueue(queue));
+
+ List<String> results = _monitor.findMatches("DEBUG");
+ try
+ {
+ // Validation
+
+ assertEquals("DEBUG messages should not be logged", 0, results.size());
+ }
+ catch (AssertionFailedError afe)
+ {
+ System.err.println("Log Dump:");
+ for (String log : results)
+ {
+ System.err.println(log);
+ }
+
+ if (results.size() == 0)
+ {
+ System.err.println("Monitored file contents:");
+ System.err.println(_monitor.readFile());
+ }
+
+ throw afe;
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/java/systests/src/main/java/org/apache/qpid/server/ack/TxAckTest.java b/java/systests/src/main/java/org/apache/qpid/server/ack/TxAckTest.java
deleted file mode 100644
index aafddb810a..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/server/ack/TxAckTest.java
+++ /dev/null
@@ -1,262 +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.
- *
- */
-package org.apache.qpid.server.ack;
-
-import junit.framework.TestCase;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.ContentHeaderBody;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.server.RequiredDeliveryException;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.queue.MessageHandleFactory;
-import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.queue.AMQMessageHandle;
-import org.apache.qpid.server.queue.AMQQueueFactory;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.store.TestMemoryMessageStore;
-import org.apache.qpid.server.store.StoreContext;
-import org.apache.qpid.server.store.MemoryMessageStore;
-import org.apache.qpid.server.txn.NonTransactionalContext;
-import org.apache.qpid.server.txn.TransactionalContext;
-
-import java.util.*;
-
-public class TxAckTest extends TestCase
-{
- private Scenario individual;
- private Scenario multiple;
- private Scenario combined;
-
- protected void setUp() throws Exception
- {
- super.setUp();
-
- //ack only 5th msg
- individual = new Scenario(10, Arrays.asList(5l), Arrays.asList(1l, 2l, 3l, 4l, 6l, 7l, 8l, 9l, 10l));
- individual.update(5, false);
-
- //ack all up to and including 5th msg
- multiple = new Scenario(10, Arrays.asList(1l, 2l, 3l, 4l, 5l), Arrays.asList(6l, 7l, 8l, 9l, 10l));
- multiple.update(5, true);
-
- //leave only 8th and 9th unacked
- combined = new Scenario(10, Arrays.asList(1l, 2l, 3l, 4l, 5l, 6l, 7l, 10l), Arrays.asList(8l, 9l));
- combined.update(3, false);
- combined.update(5, true);
- combined.update(7, true);
- combined.update(2, true);//should be ignored
- combined.update(1, false);//should be ignored
- combined.update(10, false);
- }
-
- public void testPrepare() throws AMQException
- {
- individual.prepare();
- multiple.prepare();
- combined.prepare();
- }
-
- public void testUndoPrepare() throws AMQException
- {
- individual.undoPrepare();
- multiple.undoPrepare();
- combined.undoPrepare();
- }
-
- public void testCommit() throws AMQException
- {
- individual.commit();
- multiple.commit();
- combined.commit();
- }
-
- public static junit.framework.Test suite()
- {
- return new junit.framework.TestSuite(TxAckTest.class);
- }
-
- private class Scenario
- {
- private final UnacknowledgedMessageMap _map = new UnacknowledgedMessageMapImpl(5000);
- private final TxAck _op = new TxAck(_map);
- private final List<Long> _acked;
- private final List<Long> _unacked;
- private StoreContext _storeContext = new StoreContext();
-
- Scenario(int messageCount, List<Long> acked, List<Long> unacked) throws Exception
- {
- TransactionalContext txnContext = new NonTransactionalContext(new TestMemoryMessageStore(),
- _storeContext, null,
- new LinkedList<RequiredDeliveryException>()
- );
- AMQQueue queue =
- AMQQueueFactory.createAMQQueueImpl(new AMQShortString("test"), false, null, false, new VirtualHost("test", new MemoryMessageStore()),
- null);
-
- for (int i = 0; i < messageCount; i++)
- {
- long deliveryTag = i + 1;
-
- MessagePublishInfo info = new MessagePublishInfo()
- {
-
- public AMQShortString getExchange()
- {
- return null;
- }
-
- public void setExchange(AMQShortString exchange)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public boolean isImmediate()
- {
- return false;
- }
-
- public boolean isMandatory()
- {
- return false;
- }
-
- public AMQShortString getRoutingKey()
- {
- return null;
- }
- };
-
- TestMessage message = new TestMessage(deliveryTag, i, info, txnContext.getStoreContext());
- _map.add(deliveryTag, queue.enqueue(new StoreContext(), message));
- }
- _acked = acked;
- _unacked = unacked;
- }
-
- void update(long deliverytag, boolean multiple)
- {
- _op.update(deliverytag, multiple);
- }
-
- private void assertCount(List<Long> tags, int expected)
- {
- for (long tag : tags)
- {
- QueueEntry u = _map.get(tag);
- assertTrue("Message not found for tag " + tag, u != null);
- ((TestMessage) u.getMessage()).assertCountEquals(expected);
- }
- }
-
- void prepare() throws AMQException
- {
- _op.consolidate();
- _op.prepare(_storeContext);
-
- assertCount(_acked, -1);
- assertCount(_unacked, 0);
-
- }
-
- void undoPrepare()
- {
- _op.consolidate();
- _op.undoPrepare();
-
- assertCount(_acked, 1);
- assertCount(_unacked, 0);
- }
-
- void commit()
- {
- _op.consolidate();
- _op.commit(_storeContext);
-
- //check acked messages are removed from map
- Set<Long> keys = new HashSet<Long>(_map.getDeliveryTags());
- keys.retainAll(_acked);
- assertTrue("Expected messages with following tags to have been removed from map: " + keys, keys.isEmpty());
- //check unacked messages are still in map
- keys = new HashSet<Long>(_unacked);
- keys.removeAll(_map.getDeliveryTags());
- assertTrue("Expected messages with following tags to still be in map: " + keys, keys.isEmpty());
- }
- }
-
- private static AMQMessageHandle createMessageHandle(final long messageId, final MessagePublishInfo publishBody)
- {
- final AMQMessageHandle amqMessageHandle = (new MessageHandleFactory()).createMessageHandle(messageId,
- null,
- false);
- try
- {
- amqMessageHandle.setPublishAndContentHeaderBody(new StoreContext(),
- publishBody,
- new ContentHeaderBody()
- {
- public int getSize()
- {
- return 1;
- }
- });
- }
- catch (AMQException e)
- {
- // won't happen
- }
-
-
- return amqMessageHandle;
- }
-
-
- private class TestMessage extends AMQMessage
- {
- private final long _tag;
- private int _count;
-
- TestMessage(long tag, long messageId, MessagePublishInfo publishBody, StoreContext storeContext)
- throws AMQException
- {
- super(createMessageHandle(messageId, publishBody), storeContext, publishBody);
- _tag = tag;
- }
-
-
- public boolean incrementReference()
- {
- _count++;
- return true;
- }
-
- public void decrementReference(StoreContext context)
- {
- _count--;
- }
-
- void assertCountEquals(int expected)
- {
- assertEquals("Wrong count for message with tag " + _tag, expected, _count);
- }
- }
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/configuration/ServerConfigurationFileTest.java b/java/systests/src/main/java/org/apache/qpid/server/configuration/ServerConfigurationFileTest.java
new file mode 100644
index 0000000000..0a88ef391c
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/configuration/ServerConfigurationFileTest.java
@@ -0,0 +1,87 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.configuration;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+/**
+ * This system test ensures that when loading our default system-test
+ * configuration file the configuration is correctly loaded.
+ *
+ * All configuration values should be set in the systest config file so that
+ * the ability to load them can be validated.
+ */
+public class ServerConfigurationFileTest extends QpidTestCase
+{
+ ServerConfiguration _serverConfig;
+
+ public void setUp() throws ConfigurationException
+ {
+ if (!_configFile.exists())
+ {
+ fail("Unable to test without config file:" + _configFile);
+ }
+
+ saveTestConfiguration();
+ _serverConfig = new ServerConfiguration(_configFile);
+ }
+
+ /**
+ * This helper method ensures that when we attempt to read a value that is
+ * set in the configuration file we do actualy read a value and not
+ * simply get a defaulted value from the ServerConfiguration.get*() methods.
+ *
+ * @param property the propert to test
+ */
+ private void validatePropertyDefinedInFile(String property)
+ {
+ //Verify that we are not just picking up the the default value from the getBoolean
+ assertNotNull("The value set in the configuration file is not being read for property:" + property,
+ _serverConfig.getConfig().getProperty(property));
+ }
+
+ public void testProtectIOEnabled() throws ConfigurationException
+ {
+ validatePropertyDefinedInFile(ServerConfiguration.CONNECTOR_PROTECTIO_ENABLED);
+ }
+
+ public void testProtectIOReadBufferLimitSize() throws ConfigurationException
+ {
+ validatePropertyDefinedInFile(ServerConfiguration.CONNECTOR_PROTECTIO_READ_BUFFER_LIMIT_SIZE);
+ }
+
+ public void testProtectIOWriteBufferLimitSize() throws ConfigurationException
+ {
+ validatePropertyDefinedInFile(ServerConfiguration.CONNECTOR_PROTECTIO_WRITE_BUFFER_LIMIT_SIZE);
+ }
+
+ public void testStatusUpdates() throws ConfigurationException
+ {
+ validatePropertyDefinedInFile(ServerConfiguration.STATUS_UPDATES);
+ }
+
+ public void testLocale() throws ConfigurationException
+ {
+ validatePropertyDefinedInFile(ServerConfiguration.ADVANCED_LOCALE);
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java b/java/systests/src/main/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java
deleted file mode 100644
index adb7a7cd0c..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java
+++ /dev/null
@@ -1,561 +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.
- *
- */
-package org.apache.qpid.server.exchange;
-
-import junit.framework.TestCase;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.*;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.server.queue.*;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.SkeletonMessageStore;
-import org.apache.qpid.server.store.MemoryMessageStore;
-import org.apache.qpid.server.store.StoreContext;
-import org.apache.qpid.server.txn.NonTransactionalContext;
-import org.apache.qpid.server.txn.TransactionalContext;
-import org.apache.qpid.server.RequiredDeliveryException;
-import org.apache.qpid.server.subscription.Subscription;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.log4j.Logger;
-
-import java.util.*;
-
-public class AbstractHeadersExchangeTestBase extends TestCase
-{
- private static final Logger _log = Logger.getLogger(AbstractHeadersExchangeTestBase.class);
-
- private final HeadersExchange exchange = new HeadersExchange();
- protected final Set<TestQueue> queues = new HashSet<TestQueue>();
-
- /**
- * Not used in this test, just there to stub out the routing calls
- */
- private MessageStore _store = new MemoryMessageStore();
-
- private StoreContext _storeContext = new StoreContext();
-
- private MessageHandleFactory _handleFactory = new MessageHandleFactory();
-
- private int count;
-
- public void testDoNothing()
- {
- // this is here only to make junit under Eclipse happy
- }
-
- protected TestQueue bindDefault(String... bindings) throws AMQException
- {
- return bind("Queue" + (++count), bindings);
- }
-
- protected TestQueue bind(String queueName, String... bindings) throws AMQException
- {
- return bind(queueName, getHeaders(bindings));
- }
-
- protected TestQueue bind(String queue, FieldTable bindings) throws AMQException
- {
- return bind(new TestQueue(new AMQShortString(queue)), bindings);
- }
-
- protected TestQueue bind(TestQueue queue, String... bindings) throws AMQException
- {
- return bind(queue, getHeaders(bindings));
- }
-
- protected TestQueue bind(TestQueue queue, FieldTable bindings) throws AMQException
- {
- queues.add(queue);
- exchange.registerQueue(null, queue, bindings);
- return queue;
- }
-
-
- protected void route(Message m) throws AMQException
- {
- m.route(exchange);
- m.getIncomingMessage().routingComplete(_store, _handleFactory);
- if(m.getIncomingMessage().allContentReceived())
- {
- m.getIncomingMessage().deliverToQueues();
- }
- }
-
- protected void routeAndTest(Message m, TestQueue... expected) throws AMQException
- {
- routeAndTest(m, false, Arrays.asList(expected));
- }
-
- protected void routeAndTest(Message m, boolean expectReturn, TestQueue... expected) throws AMQException
- {
- routeAndTest(m, expectReturn, Arrays.asList(expected));
- }
-
- protected void routeAndTest(Message m, List<TestQueue> expected) throws AMQException
- {
- routeAndTest(m, false, expected);
- }
-
- protected void routeAndTest(Message m, boolean expectReturn, List<TestQueue> expected) throws AMQException
- {
- try
- {
- route(m);
- assertFalse("Expected "+m+" to be returned due to manadatory flag, and lack of routing",expectReturn);
- for (TestQueue q : queues)
- {
- if (expected.contains(q))
- {
- assertTrue("Expected " + m + " to be delivered to " + q, q.isInQueue(m));
- //assert m.isInQueue(q) : "Expected " + m + " to be delivered to " + q;
- }
- else
- {
- assertFalse("Did not expect " + m + " to be delivered to " + q, q.isInQueue(m));
- //assert !m.isInQueue(q) : "Did not expect " + m + " to be delivered to " + q;
- }
- }
- }
-
- catch (NoRouteException ex)
- {
- assertTrue("Expected "+m+" not to be returned",expectReturn);
- }
-
- }
-
- static FieldTable getHeaders(String... entries)
- {
- FieldTable headers = FieldTableFactory.newFieldTable();
- for (String s : entries)
- {
- String[] parts = s.split("=", 2);
- headers.setObject(parts[0], parts.length > 1 ? parts[1] : "");
- }
- return headers;
- }
-
-
- static final class MessagePublishInfoImpl implements MessagePublishInfo
- {
- private AMQShortString _exchange;
- private boolean _immediate;
- private boolean _mandatory;
- private AMQShortString _routingKey;
-
- public MessagePublishInfoImpl(AMQShortString routingKey)
- {
- _routingKey = routingKey;
- }
-
- public MessagePublishInfoImpl(AMQShortString exchange, boolean immediate, boolean mandatory, AMQShortString routingKey)
- {
- _exchange = exchange;
- _immediate = immediate;
- _mandatory = mandatory;
- _routingKey = routingKey;
- }
-
- public AMQShortString getExchange()
- {
- return _exchange;
- }
-
- public boolean isImmediate()
- {
- return _immediate;
-
- }
-
- public boolean isMandatory()
- {
- return _mandatory;
- }
-
- public AMQShortString getRoutingKey()
- {
- return _routingKey;
- }
-
-
- public void setExchange(AMQShortString exchange)
- {
- _exchange = exchange;
- }
-
- public void setImmediate(boolean immediate)
- {
- _immediate = immediate;
- }
-
- public void setMandatory(boolean mandatory)
- {
- _mandatory = mandatory;
- }
-
- public void setRoutingKey(AMQShortString routingKey)
- {
- _routingKey = routingKey;
- }
- }
-
- static MessagePublishInfo getPublishRequest(final String id)
- {
- return new MessagePublishInfoImpl(null, false, false, new AMQShortString(id));
- }
-
- static ContentHeaderBody getContentHeader(FieldTable headers)
- {
- ContentHeaderBody header = new ContentHeaderBody();
- header.properties = getProperties(headers);
- return header;
- }
-
- static BasicContentHeaderProperties getProperties(FieldTable headers)
- {
- BasicContentHeaderProperties properties = new BasicContentHeaderProperties();
- properties.setHeaders(headers);
- return properties;
- }
-
- static class TestQueue extends SimpleAMQQueue
- {
- final List<HeadersExchangeTest.Message> messages = new ArrayList<HeadersExchangeTest.Message>();
-
- public TestQueue(AMQShortString name) throws AMQException
- {
- super(name, false, new AMQShortString("test"), true, ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test"));
- }
-
- /**
- * We override this method so that the default behaviour, which attempts to use a delivery manager, is
- * not invoked. It is unnecessary since for this test we only care to know whether the message was
- * sent to the queue; the queue processing logic is not being tested.
- * @param msg
- * @throws AMQException
- */
- @Override
- public QueueEntry enqueue(StoreContext context, AMQMessage msg) throws AMQException
- {
- messages.add( new HeadersExchangeTest.Message(msg));
- return new QueueEntry()
- {
-
- public AMQQueue getQueue()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public AMQMessage getMessage()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public long getSize()
- {
- return 0; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public boolean getDeliveredToConsumer()
- {
- return false; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public boolean expired() throws AMQException
- {
- return false; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public boolean isAcquired()
- {
- return false; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public boolean acquire()
- {
- return false; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public boolean acquire(Subscription sub)
- {
- return false; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public boolean delete()
- {
- return false;
- }
-
- public boolean isDeleted()
- {
- return false;
- }
-
- public boolean acquiredBySubscription()
- {
- return false; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void setDeliveredToSubscription()
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void release()
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public String debugIdentity()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public boolean immediateAndNotDelivered()
- {
- return false; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void setRedelivered(boolean b)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public Subscription getDeliveredSubscription()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void reject()
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void reject(Subscription subscription)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public boolean isRejectedBy(Subscription subscription)
- {
- return false; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void requeue(StoreContext storeContext) throws AMQException
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void dequeue(final StoreContext storeContext) throws FailedDequeueException
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void dispose(final StoreContext storeContext) throws MessageCleanupException
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void restoreCredit()
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void discard(StoreContext storeContext) throws FailedDequeueException, MessageCleanupException
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public boolean isQueueDeleted()
- {
- return false; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void addStateChangeListener(StateChangeListener listener)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public boolean removeStateChangeListener(StateChangeListener listener)
- {
- return false; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public int compareTo(final QueueEntry o)
- {
- return 0; //To change body of implemented methods use File | Settings | File Templates.
- }
- };
- }
-
- boolean isInQueue(Message msg)
- {
- return messages.contains(msg);
- }
-
- }
-
- /**
- * Just add some extra utility methods to AMQMessage to aid testing.
- */
- static class Message extends AMQMessage
- {
- private class TestIncomingMessage extends IncomingMessage
- {
-
- public TestIncomingMessage(final long messageId,
- final MessagePublishInfo info,
- final TransactionalContext txnContext,
- final AMQProtocolSession publisher)
- {
- super(messageId, info, txnContext, publisher);
- }
-
-
- public AMQMessage getUnderlyingMessage()
- {
- return Message.this;
- }
-
-
- public ContentHeaderBody getContentHeaderBody()
- {
- try
- {
- return Message.this.getContentHeaderBody();
- }
- catch (AMQException e)
- {
- throw new RuntimeException(e);
- }
- }
- }
-
- private IncomingMessage _incoming;
-
- private static MessageStore _messageStore = new SkeletonMessageStore();
-
- private static StoreContext _storeContext = new StoreContext();
-
-
- private static TransactionalContext _txnContext = new NonTransactionalContext(_messageStore, _storeContext,
- null,
- new LinkedList<RequiredDeliveryException>()
- );
-
- Message(String id, String... headers) throws AMQException
- {
- this(id, getHeaders(headers));
- }
-
- Message(String id, FieldTable headers) throws AMQException
- {
- this(_messageStore.getNewMessageId(),getPublishRequest(id), getContentHeader(headers), null);
- }
-
- public IncomingMessage getIncomingMessage()
- {
- return _incoming;
- }
-
- private Message(long messageId,
- MessagePublishInfo publish,
- ContentHeaderBody header,
- List<ContentBody> bodies) throws AMQException
- {
- super(createMessageHandle(messageId, publish, header), _txnContext.getStoreContext(), publish);
-
-
-
- _incoming = new TestIncomingMessage(getMessageId(),publish,_txnContext,new MockProtocolSession(_messageStore));
- _incoming.setContentHeaderBody(header);
-
-
- }
-
- private static AMQMessageHandle createMessageHandle(final long messageId,
- final MessagePublishInfo publish,
- final ContentHeaderBody header)
- {
-
- final AMQMessageHandle amqMessageHandle = (new MessageHandleFactory()).createMessageHandle(messageId,
- _messageStore,
- true);
-
- try
- {
- amqMessageHandle.setPublishAndContentHeaderBody(new StoreContext(),publish,header);
- }
- catch (AMQException e)
- {
-
- }
- return amqMessageHandle;
- }
-
- private Message(AMQMessage msg) throws AMQException
- {
- super(msg);
- }
-
-
-
- void route(Exchange exchange) throws AMQException
- {
- exchange.route(_incoming);
- }
-
-
- public int hashCode()
- {
- return getKey().hashCode();
- }
-
- public boolean equals(Object o)
- {
- return o instanceof HeadersExchangeTest.Message && equals((HeadersExchangeTest.Message) o);
- }
-
- private boolean equals(HeadersExchangeTest.Message m)
- {
- return getKey().equals(m.getKey());
- }
-
- public String toString()
- {
- return getKey().toString();
- }
-
- private Object getKey()
- {
- try
- {
- return getMessagePublishInfo().getRoutingKey();
- }
- catch (AMQException e)
- {
- _log.error("Error getting routing key: " + e, e);
- return null;
- }
- }
- }
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeTest.java b/java/systests/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeTest.java
deleted file mode 100644
index fd11ddeae2..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeTest.java
+++ /dev/null
@@ -1,106 +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.
- *
- */
-package org.apache.qpid.server.exchange;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.util.NullApplicationRegistry;
-import org.apache.qpid.framing.BasicPublishBody;
-
-public class HeadersExchangeTest extends AbstractHeadersExchangeTestBase
-{
- protected void setUp() throws Exception
- {
- super.setUp();
- ApplicationRegistry.initialise(new NullApplicationRegistry(), 1);
- }
-
- protected void tearDown()
- {
- ApplicationRegistry.remove(1);
- }
-
- public void testSimple() throws AMQException
- {
- TestQueue q1 = bindDefault("F0000");
- TestQueue q2 = bindDefault("F0000=Aardvark");
- TestQueue q3 = bindDefault("F0001");
- TestQueue q4 = bindDefault("F0001=Bear");
- TestQueue q5 = bindDefault("F0000", "F0001");
- TestQueue q6 = bindDefault("F0000=Aardvark", "F0001=Bear");
- TestQueue q7 = bindDefault("F0000", "F0001=Bear");
- TestQueue q8 = bindDefault("F0000=Aardvark", "F0001");
-
- routeAndTest(new Message("Message1", "F0000"), q1);
- routeAndTest(new Message("Message2", "F0000=Aardvark"), q1, q2);
- routeAndTest(new Message("Message3", "F0000=Aardvark", "F0001"), q1, q2, q3, q5, q8);
- routeAndTest(new Message("Message4", "F0000", "F0001=Bear"), q1, q3, q4, q5, q7);
- routeAndTest(new Message("Message5", "F0000=Aardvark", "F0001=Bear"),
- q1, q2, q3, q4, q5, q6, q7, q8);
- routeAndTest(new Message("Message6", "F0002"));
-
- Message m7 = new Message("Message7", "XXXXX");
-
- MessagePublishInfoImpl pb7 = (MessagePublishInfoImpl) (m7.getMessagePublishInfo());
- pb7.setMandatory(true);
- routeAndTest(m7,true);
-
- Message m8 = new Message("Message8", "F0000");
- MessagePublishInfoImpl pb8 = (MessagePublishInfoImpl)(m8.getMessagePublishInfo());
- pb8.setMandatory(true);
- routeAndTest(m8,false,q1);
-
-
- }
-
- public void testAny() throws AMQException
- {
- TestQueue q1 = bindDefault("F0000", "F0001", "X-match=any");
- TestQueue q2 = bindDefault("F0000=Aardvark", "F0001=Bear", "X-match=any");
- TestQueue q3 = bindDefault("F0000", "F0001=Bear", "X-match=any");
- TestQueue q4 = bindDefault("F0000=Aardvark", "F0001", "X-match=any");
- TestQueue q6 = bindDefault("F0000=Apple", "F0001", "X-match=any");
-
- routeAndTest(new Message("Message1", "F0000"), q1, q3);
- routeAndTest(new Message("Message2", "F0000=Aardvark"), q1, q2, q3, q4);
- routeAndTest(new Message("Message3", "F0000=Aardvark", "F0001"), q1, q2, q3, q4, q6);
- routeAndTest(new Message("Message4", "F0000", "F0001=Bear"), q1, q2, q3, q4, q6);
- routeAndTest(new Message("Message5", "F0000=Aardvark", "F0001=Bear"), q1, q2, q3, q4, q6);
- routeAndTest(new Message("Message6", "F0002"));
- }
-
- public void testMandatory() throws AMQException
- {
- bindDefault("F0000");
- Message m1 = new Message("Message1", "XXXXX");
- Message m2 = new Message("Message2", "F0000");
- MessagePublishInfoImpl pb1 = (MessagePublishInfoImpl) (m1.getMessagePublishInfo());
- pb1.setMandatory(true);
- MessagePublishInfoImpl pb2 = (MessagePublishInfoImpl) (m2.getMessagePublishInfo());
- pb2.setMandatory(true);
- routeAndTest(m1,true);
- }
-
- public static junit.framework.Test suite()
- {
- return new junit.framework.TestSuite(HeadersExchangeTest.class);
- }
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/exchange/ReturnUnroutableMandatoryMessageTest.java b/java/systests/src/main/java/org/apache/qpid/server/exchange/ReturnUnroutableMandatoryMessageTest.java
index e14efe03a7..a08e870873 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/exchange/ReturnUnroutableMandatoryMessageTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/exchange/ReturnUnroutableMandatoryMessageTest.java
@@ -21,32 +21,37 @@
package org.apache.qpid.server.exchange;
-import junit.framework.TestCase;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.jms.Connection;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
import org.apache.log4j.Logger;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.util.NullApplicationRegistry;
-import org.apache.qpid.client.*;
-import org.apache.qpid.client.transport.TransportConnection;
-import org.apache.qpid.url.AMQBindingURL;
-import org.apache.qpid.url.BindingURL;
-import org.apache.qpid.url.URLSyntaxException;
+import org.apache.qpid.client.AMQHeadersExchange;
+import org.apache.qpid.client.AMQNoRouteException;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.client.configuration.ClientProperties;
import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.AMQException;
-
-import javax.jms.*;
-import java.util.List;
-import java.util.Collections;
-import java.util.ArrayList;
-import java.net.URISyntaxException;
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.url.AMQBindingURL;
+import org.apache.qpid.url.BindingURL;
-public class ReturnUnroutableMandatoryMessageTest extends TestCase implements ExceptionListener
+public class ReturnUnroutableMandatoryMessageTest extends QpidTestCase implements ExceptionListener
{
private static final Logger _logger = Logger.getLogger(ReturnUnroutableMandatoryMessageTest.class);
private final List<Message> _bouncedMessageList = Collections.synchronizedList(new ArrayList<Message>());
- private static final String VIRTUALHOST = "test";
- private static final String BROKER = "vm://:1";
static
{
@@ -57,21 +62,6 @@ public class ReturnUnroutableMandatoryMessageTest extends TestCase implements Ex
System.out.println("QPID_WORK not set using tmp directory: " + tempdir);
System.setProperty("QPID_WORK", tempdir);
}
-// DOMConfigurator.configure("../broker/etc/log4j.xml");
- }
-
- protected void setUp() throws Exception
- {
- super.setUp();
- TransportConnection.createVMBroker(1);
- ApplicationRegistry.initialise(new NullApplicationRegistry(), 1);
- }
-
- protected void tearDown() throws Exception
- {
- super.tearDown();
- TransportConnection.killAllVMBrokers();
- ApplicationRegistry.remove(1);
}
/**
@@ -79,7 +69,7 @@ public class ReturnUnroutableMandatoryMessageTest extends TestCase implements Ex
*
* @throws Exception
*/
- public void testReturnUnroutableMandatoryMessage_HEADERS() throws URISyntaxException, AMQException, JMSException
+ public void testReturnUnroutableMandatoryMessage_HEADERS() throws Exception
{
_bouncedMessageList.clear();
MessageConsumer consumer = null;
@@ -88,20 +78,20 @@ public class ReturnUnroutableMandatoryMessageTest extends TestCase implements Ex
Connection con=null, con2 = null;
try
{
- con = new AMQConnection(BROKER, "guest", "guest", "consumer1", VIRTUALHOST);
+ con = getConnection();
AMQSession consumerSession = (AMQSession) con.createSession(false, Session.CLIENT_ACKNOWLEDGE);
queue = new AMQHeadersExchange(new AMQBindingURL(ExchangeDefaults.HEADERS_EXCHANGE_CLASS + "://" + ExchangeDefaults.HEADERS_EXCHANGE_NAME + "/test/queue1?" + BindingURL.OPTION_ROUTING_KEY + "='F0000=1'"));
FieldTable ft = new FieldTable();
ft.setString("F1000", "1");
- consumer = consumerSession.createConsumer(queue, AMQSession.DEFAULT_PREFETCH_LOW_MARK, AMQSession.DEFAULT_PREFETCH_HIGH_MARK, false, false, (String) null, ft);
+ consumer = consumerSession.createConsumer(queue, Integer.parseInt(ClientProperties.MAX_PREFETCH_DEFAULT), Integer.parseInt(ClientProperties.MAX_PREFETCH_DEFAULT) /2 , false, false, (String) null, ft);
//force synch to ensure the consumer has resulted in a bound queue
//((AMQSession) consumerSession).declareExchangeSynch(ExchangeDefaults.HEADERS_EXCHANGE_NAME, ExchangeDefaults.HEADERS_EXCHANGE_CLASS);
// This is the default now
- con2 = new AMQConnection(BROKER, "guest", "guest", "producer1", VIRTUALHOST);
+ con2 = getConnection();
con2.setExceptionListener(this);
producerSession = (AMQSession) con2.createSession(false, Session.CLIENT_ACKNOWLEDGE);
@@ -168,7 +158,7 @@ public class ReturnUnroutableMandatoryMessageTest extends TestCase implements Ex
public void testReturnUnroutableMandatoryMessage_QUEUE() throws Exception
{
_bouncedMessageList.clear();
- Connection con = new AMQConnection(BROKER, "guest", "guest", "consumer1", VIRTUALHOST);
+ Connection con = getConnection();
AMQSession consumerSession = (AMQSession) con.createSession(false, Session.CLIENT_ACKNOWLEDGE);
@@ -180,7 +170,7 @@ public class ReturnUnroutableMandatoryMessageTest extends TestCase implements Ex
//((AMQSession) consumerSession).declareExchangeSynch(ExchangeDefaults.HEADERS_EXCHANGE_NAME, ExchangeDefaults.HEADERS_EXCHANGE_CLASS);
// This is the default now
- Connection con2 = new AMQConnection(BROKER, "guest", "guest", "producer1", VIRTUALHOST);
+ Connection con2 = getConnection();
con2.setExceptionListener(this);
AMQSession producerSession = (AMQSession) con2.createSession(false, Session.CLIENT_ACKNOWLEDGE);
@@ -229,7 +219,7 @@ public class ReturnUnroutableMandatoryMessageTest extends TestCase implements Ex
public void testReturnUnroutableMandatoryMessage_TOPIC() throws Exception
{
_bouncedMessageList.clear();
- Connection con = new AMQConnection(BROKER, "guest", "guest", "consumer1", VIRTUALHOST);
+ Connection con = getConnection();
AMQSession consumerSession = (AMQSession) con.createSession(false, Session.CLIENT_ACKNOWLEDGE);
@@ -241,7 +231,7 @@ public class ReturnUnroutableMandatoryMessageTest extends TestCase implements Ex
//((AMQSession) consumerSession).declareExchangeSynch(ExchangeDefaults.HEADERS_EXCHANGE_NAME, ExchangeDefaults.HEADERS_EXCHANGE_CLASS);
// This is the default now
- Connection con2 = new AMQConnection(BROKER, "guest", "guest", "producer1", VIRTUALHOST);
+ Connection con2 = getConnection();
con2.setExceptionListener(this);
AMQSession producerSession = (AMQSession) con2.createSession(false, Session.CLIENT_ACKNOWLEDGE);
diff --git a/java/systests/src/main/java/org/apache/qpid/server/failover/FailoverMethodTest.java b/java/systests/src/main/java/org/apache/qpid/server/failover/FailoverMethodTest.java
index 14c7f26fad..1683c5e3d6 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/failover/FailoverMethodTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/failover/FailoverMethodTest.java
@@ -23,13 +23,12 @@ package org.apache.qpid.server.failover;
import junit.framework.TestCase;
import org.apache.qpid.AMQDisconnectedException;
import org.apache.qpid.AMQException;
+import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.client.AMQConnection;
import org.apache.qpid.client.AMQConnectionURL;
import org.apache.qpid.client.transport.TransportConnection;
import org.apache.qpid.client.vmbroker.AMQVMBrokerCreationException;
import org.apache.qpid.url.URLSyntaxException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import javax.jms.ExceptionListener;
import javax.jms.JMSException;
@@ -41,12 +40,14 @@ public class FailoverMethodTest extends TestCase implements ExceptionListener
public void setUp() throws AMQVMBrokerCreationException
{
- TransportConnection.createVMBroker(1);
+ ApplicationRegistry.getInstance();
+ TransportConnection.createVMBroker(ApplicationRegistry.DEFAULT_INSTANCE);
}
- public void tearDown() throws AMQVMBrokerCreationException
+ public void tearDown()
{
- TransportConnection.killAllVMBrokers();
+ TransportConnection.killVMBroker(ApplicationRegistry.DEFAULT_INSTANCE);
+ ApplicationRegistry.remove();
}
/**
@@ -63,7 +64,8 @@ public class FailoverMethodTest extends TestCase implements ExceptionListener
//note: The VM broker has no connect delay and the default 1 retry
// while the tcp:localhost broker has 3 retries with a 2s connect delay
String connectionString = "amqp://guest:guest@/test?brokerlist=" +
- "'vm://:1;tcp://localhost:5670?connectdelay='2000',retries='3''";
+ "'vm://:" + ApplicationRegistry.DEFAULT_INSTANCE +
+ ";tcp://localhost:5670?connectdelay='2000',retries='3''";
AMQConnectionURL url = new AMQConnectionURL(connectionString);
@@ -74,7 +76,8 @@ public class FailoverMethodTest extends TestCase implements ExceptionListener
connection.setExceptionListener(this);
- TransportConnection.killAllVMBrokers();
+ TransportConnection.killVMBroker(ApplicationRegistry.DEFAULT_INSTANCE);
+ ApplicationRegistry.remove();
_failoverComplete.await();
@@ -117,7 +120,8 @@ public class FailoverMethodTest extends TestCase implements ExceptionListener
connection.setExceptionListener(this);
- TransportConnection.killAllVMBrokers();
+ TransportConnection.killVMBroker(ApplicationRegistry.DEFAULT_INSTANCE);
+ ApplicationRegistry.remove();
_failoverComplete.await();
@@ -151,4 +155,82 @@ public class FailoverMethodTest extends TestCase implements ExceptionListener
_failoverComplete.countDown();
}
}
+
+ public void testNoFailover() throws URLSyntaxException, AMQVMBrokerCreationException,
+ InterruptedException, JMSException
+ {
+ String connectionString = "amqp://guest:guest@/test?brokerlist='vm://:1?connectdelay='500',retries='3'',failover='nofailover'";
+
+ AMQConnectionURL url = new AMQConnectionURL(connectionString);
+
+ try
+ {
+ //Kill initial broker
+ TransportConnection.killVMBroker(ApplicationRegistry.DEFAULT_INSTANCE);
+ ApplicationRegistry.remove();
+
+ //Create a thread to start the broker asynchronously
+ Thread brokerStart = new Thread(new Runnable()
+ {
+ public void run()
+ {
+ try
+ {
+ //Wait before starting broker
+ // The wait should allow atleast 1 retries to fail before broker is ready
+ Thread.sleep(750);
+ ApplicationRegistry.getInstance();
+ TransportConnection.createVMBroker(ApplicationRegistry.DEFAULT_INSTANCE);
+ }
+ catch (Exception e)
+ {
+ System.err.println(e.getMessage());
+ e.printStackTrace();
+ }
+ }
+ });
+
+
+ brokerStart.start();
+ long start = System.currentTimeMillis();
+
+
+ //Start the connection so it will use the retries
+ AMQConnection connection = new AMQConnection(url, null);
+
+ long end = System.currentTimeMillis();
+
+ long duration = (end - start);
+
+ // Check that we actually had a delay had a delay in connection
+ assertTrue("Initial connection should be longer than 1 delay : 500 <:(" + duration + ")", duration > 500);
+
+
+ connection.setExceptionListener(this);
+
+ //Ensure we collect the brokerStart thread
+ brokerStart.join();
+
+ start = System.currentTimeMillis();
+
+ //Kill connection
+ TransportConnection.killVMBroker(ApplicationRegistry.DEFAULT_INSTANCE);
+ ApplicationRegistry.remove();
+
+ _failoverComplete.await();
+
+ end = System.currentTimeMillis();
+
+ duration = (end - start);
+
+ // Notification of the connection failure should be very quick as we are denying the ability to failover.
+ // It may not be as quick for Java profile tests so lets just make sure it is less than the connectiondelay
+ assertTrue("Notification of the connection failure took was : 100 >:(" + duration + ")", duration < 500);
+ }
+ catch (AMQException e)
+ {
+ fail(e.getMessage());
+ }
+ }
+
}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/failover/MessageDisappearWithIOExceptionTest.java b/java/systests/src/main/java/org/apache/qpid/server/failover/MessageDisappearWithIOExceptionTest.java
new file mode 100644
index 0000000000..863aa43d22
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/failover/MessageDisappearWithIOExceptionTest.java
@@ -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.
+ *
+ */
+package org.apache.qpid.server.failover;
+
+import org.apache.mina.common.WriteTimeoutException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.jms.ConnectionListener;
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.test.utils.FailoverBaseCase;
+import org.apache.qpid.AMQConnectionClosedException;
+
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test case based on user reported error.
+ *
+ * Summary:
+ * A user has reported message loss from their application. On bouncing of
+ * the broker the 'lost' messages are delivered to the broker.
+ *
+ * Note:
+ * The client was using Spring so that may influence the situation.
+ *
+ * Issue:
+ * The log files show 7 instances of the following which result in 7
+ * missing messages.
+ *
+ * The client log files show:
+ *
+ * The broker log file show:
+ *
+ *
+ * 7 missing messages have delivery tags 5-11. Which says that they are
+ * sequentially the next message from the broker.
+ *
+ * The only way for the 'without a handler' log to occur is if the consumer
+ * has been removed from the look up table of the dispatcher.
+ * And the only way for the 'null message' log to occur on the broker is is
+ * if the message does not exist in the unacked-map
+ *
+ * The consumer is only removed from the list during session
+ * closure and failover.
+ *
+ * If the session was closed then the broker would requeue the unacked
+ * messages so the potential exists to have an empty map but the broker
+ * will not send a message out after the unacked map has been cleared.
+ *
+ * When failover occurs the _consumer map is cleared and the consumers are
+ * resubscribed. This is down without first stopping any existing
+ * dispatcher so there exists the potential to receive a message after
+ * the _consumer map has been cleared which is how the 'without a handler'
+ * log statement occurs.
+ *
+ * Scenario:
+ *
+ * Looking over logs the sequence that best fits the events is as follows:
+ * - Something causes Mina to be delayed causing the WriteTimoutException.
+ * - This exception is recevied by AMQProtocolHandler#exceptionCaught
+ * - As the WriteTimeoutException is an IOException this will cause
+ * sessionClosed to be called to start failover.
+ * + This is potentially the issues here. All IOExceptions are treated
+ * as connection failure events.
+ * - Failover Runs
+ * + Failover assumes that the previous connection has been closed.
+ * + Failover binds the existing objects (AMQConnection/Session) to the
+ * new connection objects.
+ * - Everything is reported as being successfully failed over.
+ * However, what is neglected is that the original connection has not
+ * been closed.
+ * + So what occurs is that the broker sends a message to the consumer on
+ * the original connection, as it was not notified of the client
+ * failing over.
+ * As the client failover reuses the original AMQSession and Dispatcher
+ * the new messages the broker sends to the old consumer arrives at the
+ * client and is processed by the same AMQSession and Dispatcher.
+ * However, as the failover process cleared the _consumer map and
+ * resubscribe the consumers the Dispatcher does not recognise the
+ * delivery tag and so logs the 'without a handler' message.
+ * - The Dispatcher then attempts to reject the message, however,
+ * + The AMQSession/Dispatcher pair have been swapped to using a new Mina
+ * ProtocolSession as part of the failover process so the reject is
+ * sent down the second connection. The broker receives the Reject
+ * request but as the Message was sent on a different connection the
+ * unacknowledgemap is empty and a 'message is null' log message
+ * produced.
+ *
+ * Test Strategy:
+ *
+ * It should be easy to demonstrate if we can send an IOException to
+ * AMQProtocolHandler#exceptionCaught and then try sending a message.
+ *
+ * The current unknowns here are the type of consumers that are in use.
+ * If it was an exclusive queue(Durable Subscription) then why did the
+ * resubscribe not fail.
+ *
+ * If it was not exclusive then why did the messages not round robin?
+ */
+public class MessageDisappearWithIOExceptionTest extends FailoverBaseCase implements ConnectionListener
+{
+ private CountDownLatch _failoverOccured = new CountDownLatch(1);
+ AMQConnection _connection;
+ Session _session;
+ Queue _queue;
+ MessageConsumer _consumer;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ stopBroker(getFailingPort());
+
+ }
+
+ /**
+ * Test Summary:
+ *
+ * Create a queue consumer and send 10 messages to the broker.
+ *
+ * Consume the first message.
+ * This will pull the rest into the prefetch
+ *
+ * Send an IOException to the MinaProtocolHandler.
+ *
+ * This will force failover to occur.
+ *
+ * 9 messages would normally be expected but it is expected that none will
+ * arrive. As they are still in the prefetch of the first session.
+ *
+ * To free the messages we need to close all connections.
+ * - Simply doing connection.close() and retesting will not be enough as
+ * the original connection's IO layer will still exist and is nolonger
+ * connected to the connection object as a result of failover.
+ *
+ * - Test will need to retain a reference to the original connection IO so
+ * that it can be closed releasing the messages to validate that the
+ * messages have indeed been 'lost' on that sesssion.
+ */
+ public void test() throws Exception
+ {
+ initialiseConnection();
+
+ // Create Producer
+ // Send 10 messages
+ List<Message> messages = sendNumberedBytesMessage(_session, _queue, 10);
+
+ // Consume first messasge
+ Message received = _consumer.receive(2000);
+
+ // Verify received messages
+ assertNotNull("First message not received.", received);
+ assertEquals("Incorrect message Received",
+ messages.remove(0).getIntProperty("count"),
+ received.getIntProperty("count"));
+
+ // When the Exception is received by the underlying IO layer it will
+ // initiate failover. The first step of which is to ensure that the
+ // existing conection is closed. So in this situation the connection
+ // will be flushed casuing the above ACK to be sent to the broker.
+ //
+ // That said:
+ // when the socket close is detected on the server it will rise up the
+ // Mina filter chain and interrupt processing.
+ // this has been raised as QPID-2138
+ _session.createConsumer(_session.createTemporaryQueue()).close();
+
+ //Retain IO Layer
+ AMQProtocolSession protocolSession = _connection.getProtocolHandler().getProtocolSession();
+
+ // Send IO Exception - causing failover
+ _connection.getProtocolHandler().
+ exception(new WriteTimeoutException("WriteTimeoutException to cause failover."));
+
+ // Verify Failover occured through ConnectionListener
+ assertTrue("Failover did not occur",
+ _failoverOccured.await(4000, TimeUnit.MILLISECONDS));
+
+ /***********************************/
+ // This verifies that the bug has been resolved
+
+ // Attempt to consume again. Expect 9 messages
+ for (int count = 1; count < 10; count++)
+ {
+ received = _consumer.receive(2000);
+ assertNotNull("Expected message not received:" + count, received);
+ assertEquals(messages.remove(0).getIntProperty("count"),
+ received.getIntProperty("count"));
+ }
+
+ //Verify there are no more messages
+ received = _consumer.receive(1000);
+ assertNull("Message receieved when there should be none:" + received,
+ received);
+
+// /***********************************/
+// // This verifies that the bug exists
+//
+// // Attempt to consume remaining 9 messages.. Expecting NONE.
+// // receiving just one message should fail so no need to fail 9 times
+// received = _consumer.receive(1000);
+// assertNull("Message receieved when it should be null:" + received, received);
+//
+//// //Close the Connection which you would assume would free the messages
+//// _connection.close();
+////
+//// // Reconnect
+//// initialiseConnection();
+////
+//// // We should still be unable to receive messages
+//// received = _consumer.receive(1000);
+//// assertNull("Message receieved when it should be null:" + received, received);
+////
+//// _connection.close();
+//
+// // Close original IO layer. Expecting messages to be released
+// protocolSession.closeProtocolSession();
+//
+// // Reconnect and all should be good.
+//// initialiseConnection();
+//
+// // Attempt to consume again. Expect 9 messages
+// for (int count = 1; count < 10; count++)
+// {
+// received = _consumer.receive(2000);
+// assertNotNull("Expected message not received:" + count, received);
+// assertEquals(messages.remove(0).getIntProperty("count"),
+// received.getIntProperty("count"));
+// }
+//
+// //Verify there are no more messages
+// received = _consumer.receive(1000);
+// assertNull("Message receieved when there should be none:" + received,
+// received);
+ }
+
+ private void initialiseConnection()
+ throws Exception
+ {
+ //Create Connection using the default connection URL. i.e. not the Failover URL that would be used by default
+ _connection = (AMQConnection) getConnection(getConnectionFactory("default").getConnectionURL());
+ // The default connection does not have any retries configured so
+ // Allow this connection to retry so that we can block on the failover.
+ // The alternative would be to use the getConnection() default. However,
+ // this would add additional complexity in the logging as a second
+ // broker is defined in that url. We do not need it for this test.
+ _connection.getFailoverPolicy().getCurrentMethod().setRetries(1);
+ _connection.setConnectionListener(this);
+
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _queue = _session.createQueue(getTestQueueName());
+
+ // Create Consumer
+ _consumer = _session.createConsumer(_queue);
+
+ //Start connection
+ _connection.start();
+ }
+
+ /** QpidTestCase back port to this release */
+
+ // modified from QTC as sendMessage is not testable.
+ // - should be renamed sendBlankBytesMessage
+ // - should be renamed sendNumberedBytesMessage
+ public List<Message> sendNumberedBytesMessage(Session session, Destination destination,
+ int count) throws Exception
+ {
+ List<Message> messages = new ArrayList<Message>(count);
+
+ MessageProducer producer = session.createProducer(destination);
+
+ for (int i = 0; i < count; i++)
+ {
+ Message next = session.createMessage();
+
+ next.setIntProperty("count", i);
+
+ producer.send(next);
+
+ messages.add(next);
+ }
+
+ producer.close();
+ return messages;
+ }
+
+ public void bytesSent(long count)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void bytesReceived(long count)
+ {
+ }
+
+ public boolean preFailover(boolean redirect)
+ {
+ //Allow failover to occur
+ return true;
+ }
+
+ public boolean preResubscribe()
+ {
+ //Allow failover to occur
+ return true;
+ }
+
+ public void failoverComplete()
+ {
+ _failoverOccured.countDown();
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/logging/AbstractTestLogging.java b/java/systests/src/main/java/org/apache/qpid/server/logging/AbstractTestLogging.java
new file mode 100644
index 0000000000..e7d1c8b896
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/logging/AbstractTestLogging.java
@@ -0,0 +1,320 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging;
+
+import org.apache.qpid.server.logging.subjects.AbstractTestLogSubject;
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.util.LogMonitor;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+public class AbstractTestLogging extends QpidTestCase
+{
+ protected LogMonitor _monitor;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _monitor = new LogMonitor(_outputFile);
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ _monitor.close();
+ super.tearDown();
+ }
+
+ /**
+ * assert that the requested log message has not occured
+ *
+ * @param log
+ *
+ * @throws IOException
+ */
+ public void assertLoggingNotYetOccured(String log) throws IOException
+ {
+ // Ensure the alert has not occured yet
+ assertEquals("Message has already occured:" + log, 0,
+ _monitor.findMatches(log).size());
+ }
+
+ protected void validateMessageID(String id, String log)
+ {
+ assertEquals("Incorrect message", id, getMessageID(log));
+ }
+
+ protected String getMessageID(String log)
+ {
+ String message = fromMessage(log);
+
+ return message.substring(0, message.indexOf(" "));
+ }
+
+ /**
+ * Return the first channel id from the log string
+ * ' ch;X' if there is no channel id return -1.
+ *
+ * @param log the log string to search.
+ *
+ * @return channel id or -1 if no channel id exists.
+ */
+ protected int getChannelID(String log)
+ {
+ int start = log.indexOf("ch:") + 3;
+
+ // If we do a check for ] as the boundary we will get cases where log
+ // is presented with the bounding. If we don't match a ] then we can use
+ // the end of the string as the boundary.
+ int end = log.indexOf("]", start);
+ if (end == -1)
+ {
+ end = log.length();
+ }
+
+ try
+ {
+ return Integer.parseInt(log.substring(start, end));
+ }
+ catch (Exception e)
+ {
+ return -1;
+ }
+ }
+
+ protected String fromMessage(String log)
+ {
+ int startSubject = log.indexOf("]") + 1;
+ int start = log.indexOf("]", startSubject) + 1;
+
+ // If we don't have a subject then the second indexOf will return 0
+ // in which case we can use the end of the actor as the index.
+ if (start == 0)
+ {
+ start = startSubject;
+ }
+
+ return log.substring(start).trim();
+ }
+
+ /**
+ * Extract the Subject from the Log Message.
+ *
+ * The subject is the second block inclosed in brackets '[ ]'.
+ *
+ * If there is no Subject or the second block of brackets '[ ]' cannot be
+ * identified then an empty String ("") is returned.
+ *
+ * The brackets '[ ]' are not included in the returned String.
+ *
+ * @param log The log message to process
+ *
+ * @return the Subject string or the empty string ("") if the subject can't be identified.
+ */
+ protected String fromSubject(String log)
+ {
+ int start = log.indexOf("[") + 1;
+ // Take the second index
+ start = log.indexOf("[", start) + 1;
+
+ // There may not be a subject so in that case return nothing.
+ if (start == 0)
+ {
+ return "";
+ }
+
+ int end = log.indexOf("]", start);
+ try
+ {
+ return log.substring(start, end);
+ }
+ catch (IndexOutOfBoundsException iobe)
+ {
+ return "";
+ }
+ }
+
+ /**
+ * Extract the actor segment from the log message.
+ * The Actor segment is the first section enclosed in '[ ]'.
+ *
+ * No analysis is performed to ensure that the first '[ ]' section of the
+ * given log is really an Actor segment.
+ *
+ * The brackets '[ ]' are not included in the returned String.
+ *
+ * @param log the Log Message
+ *
+ * @return the Actor segment or "" if unable to locate '[ ]' section
+ */
+ protected String fromActor(String log)
+ {
+ int start = log.indexOf("[") + 1;
+ int end = log.indexOf("]", start);
+ try
+ {
+ return log.substring(start, end).trim();
+ }
+ catch (IndexOutOfBoundsException iobe)
+ {
+ return "";
+ }
+ }
+
+ /**
+ * Return the message String from the given message section
+ *
+ * @param log the Message Section
+ *
+ * @return the Message String.
+ */
+ protected String getMessageString(String log)
+ {
+ // Remove the Log ID from the returned String
+ int start = log.indexOf(":") + 1;
+
+ return log.substring(start).trim();
+ }
+
+ /**
+ * Given our log message extract the connection ID:
+ *
+ * The log string will contain the connectionID identified by 'con:'
+ *
+ * So extract the value shown here by X:
+ *
+ * 'con:X('
+ *
+ * Extract the value between the ':' and '(' and process it as an Integer
+ *
+ * If we are unable to find the right index or process the substring as an
+ * Integer then return -1.
+ *
+ * @param log the log String to process
+ *
+ * @return the connection ID or -1.
+ */
+ protected int getConnectionID(String log)
+ {
+ int conIDStart = log.indexOf("con:") + 4;
+ int conIDEnd = log.indexOf("(", conIDStart);
+ try
+ {
+ return Integer.parseInt(log.substring(conIDStart, conIDEnd));
+ }
+ catch (Exception e)
+ {
+ return -1;
+ }
+ }
+
+ /**
+ * Extract the log entry from the raw log line which will contain other
+ * log4j formatting.
+ *
+ * This formatting may impead our testing process so extract the log message
+ * as we know it to be formatted.
+ *
+ * This starts with the string MESSAGE
+ *
+ * @param rawLog the raw log
+ *
+ * @return the log we are expecting to be printed without the log4j prefixes
+ */
+ protected String getLog(String rawLog)
+ {
+ int start = rawLog.indexOf("MESSAGE");
+ return rawLog.substring(start);
+ }
+
+ /**
+ * Given a list of messages that have been pulled out of a log file
+ * Process the results splitting the log statements in to lists based on the
+ * actor's connection ID.
+ *
+ * So for each log entry extract the Connecition ID from the Actor of the log
+ *
+ * Then use that as a key to a HashMap storing the list of log messages for
+ * that connection.
+ *
+ * @param logMessages The list of mixed connection log messages
+ *
+ * @return Map indexed by connection id to a list of log messages just for that connection.
+ */
+ protected HashMap<Integer, List<String>> splitResultsOnConnectionID(List<String> logMessages)
+ {
+ HashMap<Integer, List<String>> connectionSplitList = new HashMap<Integer, List<String>>();
+
+ for (String log : logMessages)
+ {
+ // Get the connectionID from the Actor in the Message Log.
+ int cID = getConnectionID(fromActor(getLog(log)));
+
+ List<String> connectionData = connectionSplitList.get(cID);
+
+ // Create the initial List if we don't have one already
+ if (connectionData == null)
+ {
+ connectionData = new LinkedList<String>();
+ connectionSplitList.put(cID, connectionData);
+ }
+
+ // Store the log
+ connectionData.add(log);
+ }
+
+ return connectionSplitList;
+ }
+
+ /**
+ * Filter the give result set by the specficifed virtualhost.
+ * This is done using the getSlice to identify the virtualhost (vh) in the
+ * log message
+ *
+ * @param results full list of logs
+ * @param virtualHostName the virtualhostName to filter on
+ *
+ * @return the list of messages only for that virtualhost
+ */
+ protected List<String> filterResultsByVirtualHost(List<String> results, String virtualHostName)
+ {
+ List<String> filteredResults = new LinkedList<String>();
+ Iterator<String> iterator = results.iterator();
+
+ while (iterator.hasNext())
+ {
+ String log = iterator.next();
+
+ if (AbstractTestLogSubject.getSlice("vh", log).equals(virtualHostName))
+ {
+ filteredResults.add(log);
+ }
+ }
+
+ return filteredResults;
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/logging/AlertingTest.java b/java/systests/src/main/java/org/apache/qpid/server/logging/AlertingTest.java
new file mode 100644
index 0000000000..683abee4da
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/logging/AlertingTest.java
@@ -0,0 +1,209 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+package org.apache.qpid.server.logging;
+
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.util.FileUtils;
+import org.apache.qpid.util.LogMonitor;
+
+import javax.jms.Connection;
+import javax.jms.Queue;
+import javax.jms.Session;
+import java.io.File;
+
+public class AlertingTest extends AbstractTestLogging
+{
+ private String VIRTUALHOST = "test";
+ private Session _session;
+ private Connection _connection;
+ private Queue _destination;
+ private int _numMessages;
+
+ private static final int ALERT_LOG_WAIT_PERIOD = 5000;
+ private static final String MESSAGE_COUNT_ALERT = "MESSAGE_COUNT_ALERT";
+
+ public void setUp() throws Exception
+ {
+ // set QPID_WORK to be [QPID_WORK|io.tmpdir]/<testName>
+ // This ensures that each of these tests operate independantly.
+ setSystemProperty("QPID_WORK",
+ System.getProperty("QPID_WORK",
+ System.getProperty("java.io.tmpdir"))
+ + File.separator + getName());
+
+ // Update the configuration to make our virtualhost Persistent.
+ makeVirtualHostPersistent(VIRTUALHOST);
+
+ _numMessages = 50;
+
+ // Then we do the normal setup stuff like starting the broker, getting a connection etc.
+ super.setUp();
+
+ setupConnection();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ // Ensure queue is clean for next run.
+ drainQueue(_destination);
+ super.tearDown();
+ }
+
+
+ /**
+ * Create a new connection and ensure taht our destination queue is created
+ * and bound.
+ *
+ * Note that the tests here that restart the broker rely on persistence.
+ * However, the queue creation here is transient. So the queue will not be
+ * rebound on restart. Hence the consumer creation here rather than just the
+ * once.
+ *
+ * The persistent messages will recreate the queue but not bind it (as it
+ * was not a durable queue) However, the consumer creation here will ensure
+ * that the queue is correctly bound and can receive new messages.
+ *
+ * @throws Exception
+ */
+ private void setupConnection()
+ throws Exception
+ {
+ _connection = getConnection();
+ _session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+ _destination = _session.createQueue(getTestQueueName());
+
+ // Consumer is only used to actually create the destination
+ _session.createConsumer(_destination).close();
+ }
+
+ /**
+ * Checks the log file for MESSAGE_COUNT_ALERT, fails() the test if it's not found and
+ * places the entire contents in the message to help debug cruise control failures.
+ *
+ * @throws Exception
+ */
+ private void wasAlertFired() throws Exception
+ {
+ if (!_monitor.waitForMessage(MESSAGE_COUNT_ALERT, ALERT_LOG_WAIT_PERIOD))
+ {
+ StringBuffer message = new StringBuffer("Could not find 'MESSAGE_COUNT_ALERT' in log file: " + _monitor.getMonitoredFile().getAbsolutePath());
+ message.append("\n");
+
+ // Add the current contents of the log file to test output
+ message.append(_monitor.readFile());
+
+ // Write the test config file to test output
+ message.append("Server configuration overrides in use:\n");
+ message.append(FileUtils.readFileAsString(getTestConfigFile()));
+
+ message.append("\nVirtualhost maxMessageCount:\n");
+ message.append((new ServerConfiguration(_configFile)).getConfig().getString("virtualhosts.virtualhost." + VIRTUALHOST + ".queues.maximumMessageCount"));
+
+ fail(message.toString());
+ }
+ }
+
+ public void testAlertingReallyWorks() throws Exception
+ {
+ // Send 5 messages, make sure that the alert was fired properly.
+ sendMessage(_session, _destination, _numMessages + 1);
+ _session.commit();
+ wasAlertFired();
+ }
+
+ public void testAlertingReallyWorksWithRestart() throws Exception
+ {
+ sendMessage(_session, _destination, _numMessages + 1);
+ _session.commit();
+ stopBroker();
+
+ // Rest the monitoring clearing the current output file.
+ _monitor.reset();
+ startBroker();
+ wasAlertFired();
+ }
+
+ /**
+ * Test that if the alert value is change from the previous value we can
+ * still get alerts.
+ *
+ * Test sends two messages to the broker then restarts the broker with new
+ * configuration.
+ *
+ * If the test is running inVM the test validates that the new configuration
+ * has been applied.
+ *
+ * Validates that we only have two messages on the queue and then sends
+ * enough messages to trigger the alert.
+ *
+ * The alert is then validate.
+ *
+ *
+ * @throws Exception
+ */
+ public void testAlertingReallyWorksWithChanges() throws Exception
+ {
+ // send some messages and nuke the logs
+ sendMessage(_session, _destination, 2);
+ _session.commit();
+ // To prevent any failover/retry/connection dropped errors
+ _connection.close();
+
+ stopBroker();
+
+ _monitor.reset();
+
+ // Change max message count to 5, start broker and make sure that that's triggered at the right time
+ setConfigurationProperty("virtualhosts.virtualhost." + VIRTUALHOST + ".queues.maximumMessageCount", "5");
+
+ startBroker();
+
+ if (!isExternalBroker())
+ {
+ assertEquals("Alert Max Msg Count is not correct", 5, ApplicationRegistry.getInstance().getVirtualHostRegistry().
+ getVirtualHost(VIRTUALHOST).getQueueRegistry().getQueue(new AMQShortString(_destination.getQueueName())).
+ getMaximumMessageCount());
+ }
+
+ setupConnection();
+
+ // Validate the queue depth is as expected
+ long messageCount = ((AMQSession) _session).getQueueDepth((AMQDestination) _destination);
+ assertEquals("Broker has invalid message count for test", 2, messageCount);
+
+ // Ensure the alert has not occured yet
+ assertLoggingNotYetOccured(MESSAGE_COUNT_ALERT);
+
+ // Trigger the new value
+ sendMessage(_session, _destination, 3);
+ _session.commit();
+
+ // Validate that the alert occured.
+ wasAlertFired();
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/logging/BindingLoggingTest.java b/java/systests/src/main/java/org/apache/qpid/server/logging/BindingLoggingTest.java
new file mode 100644
index 0000000000..266cb42ad7
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/logging/BindingLoggingTest.java
@@ -0,0 +1,279 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging;
+
+import org.apache.qpid.server.logging.subjects.AbstractTestLogSubject;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.Topic;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Binding
+ *
+ * The Binding test suite validates that the follow log messages as specified in the Functional Specification.
+ *
+ * This suite of tests validate that the Binding messages occur correctly and according to the following format:
+ *
+ * BND-1001 : Create [: Arguments : <key=value>]
+ * BND-1002 : Deleted
+ */
+public class BindingLoggingTest extends AbstractTestLogging
+{
+
+ static final String BND_PREFIX = "BND-";
+
+ Connection _connection;
+ Session _session;
+ Queue _queue;
+ Topic _topic;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ //Ignore broker startup messages
+ _monitor.reset();
+
+ _connection = getConnection();
+
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _queue = _session.createQueue(getName());
+ _topic = (Topic) getInitialContext().lookup(TOPIC);
+ }
+
+ private void validateLogMessage(String log, String messageID, String exchange, String message)
+ {
+ validateMessageID(messageID, log);
+
+ String subject = fromSubject(log);
+
+ assertEquals("Queue not correct.", getName(),
+ AbstractTestLogSubject.getSlice("qu", subject));
+ assertEquals("Routing Key not correct.", getName(),
+ AbstractTestLogSubject.getSlice("rk", subject));
+ assertEquals("Virtualhost not correct.", "/test",
+ AbstractTestLogSubject.getSlice("vh", subject));
+ assertEquals("Exchange not correct.", exchange,
+ AbstractTestLogSubject.getSlice("ex", subject));
+
+ assertEquals("Log Message not as expected", message, getMessageString(fromMessage(log)));
+ }
+
+ /**
+ * testBindingCreate
+ *
+ * Description:
+ * The binding of a Queue and an Exchange is done via a Binding. When this Binding is created a BND-1001 Create message will be logged.
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. New Client requests that a Queue is bound to a new exchange.
+ * Output:
+ *
+ * <date> BND-1001 : Create
+ *
+ * Validation Steps:
+ * 3. The BND ID is correct
+ * 4. This will be the first message for the given binding
+ */
+ public void testBindingCreate() throws JMSException, IOException
+ {
+ _session.createConsumer(_queue).close();
+
+ List<String> results = _monitor.findMatches(BND_PREFIX);
+
+ // We will have two binds as we bind all queues to the default exchange
+ assertEquals("Result set larger than expected.", 2, results.size());
+
+ String exchange = "direct/<<default>>";
+ String messageID = "BND-1001";
+ String message = "Create";
+
+ validateLogMessage(getLog(results.get(0)), messageID, exchange, message);
+
+ exchange = "direct/amq.direct";
+ validateLogMessage(getLog(results.get(1)), messageID, exchange, message);
+ }
+
+ /**
+ * Description:
+ * A Binding can be made with a set of arguments. When this occurs we logged the key,value pairs as part of the Binding log message. When the subscriber with a JMS Selector consumes from an exclusive queue such as a topic. The binding is made with the JMS Selector as an argument.
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Java Client consumes from a topic with a JMS selector.
+ * Output:
+ *
+ * <date> BND-1001 : Create : Arguments : <key=value>
+ *
+ * Validation Steps:
+ * 3. The BND ID is correct
+ * 4. The JMS Selector argument is present in the message
+ * 5. This will be the first message for the given binding
+ */
+ public void testBindingCreateWithArguments() throws JMSException, IOException
+ {
+ final String SELECTOR = "Selector='True'";
+
+ _session.createDurableSubscriber(_topic, getName(), SELECTOR, false).close();
+
+ List<String> results = _monitor.findMatches(BND_PREFIX);
+
+ // We will have two binds as we bind all queues to the default exchange
+ assertEquals("Result set larger than expected.", 2, results.size());
+
+ String log = getLog(results.get(0));
+
+ //Verify the first entry is the default binding
+ validateMessageID("BND-1001", log);
+
+ String subject = fromSubject(log);
+
+ assertEquals("Queue not correct.", "clientid:" + getName(),
+ AbstractTestLogSubject.getSlice("qu", subject));
+ // NOTE default binding is the queue name
+ assertEquals("Routing Key not correct.", "clientid:" + getName(),
+ AbstractTestLogSubject.getSlice("rk", subject));
+ assertEquals("Virtualhost not correct.", "/test",
+ AbstractTestLogSubject.getSlice("vh", subject));
+ assertEquals("Exchange not correct.", "direct/<<default>>",
+ AbstractTestLogSubject.getSlice("ex", fromSubject(log)));
+
+ String message = getMessageString(log);
+
+ //Default binding will be without the selector
+ assertTrue("JMSSelector identified in binding:"+message, !message.contains("jms-selector"));
+
+ // Perform full testing on the second non default binding
+ log = getLog(results.get(1));
+ validateMessageID("BND-1001", log);
+
+ subject = fromSubject(log);
+
+ assertEquals("Queue not correct.", "clientid:" + getName(),
+ AbstractTestLogSubject.getSlice("qu", subject));
+ assertEquals("Routing Key not correct.", "topic",
+ AbstractTestLogSubject.getSlice("rk", subject));
+ assertEquals("Virtualhost not correct.", "/test",
+ AbstractTestLogSubject.getSlice("vh", subject));
+ assertEquals("Exchange not correct.", "topic/amq.topic",
+ AbstractTestLogSubject.getSlice("ex", subject));
+
+ message = getMessageString(log);
+
+ assertTrue("JMSSelector not identified in binding:"+message, message.contains("jms-selector"));
+ assertTrue("Selector not part of binding.:"+message, message.contains(SELECTOR));
+
+ }
+
+ /**
+ * Description:
+ * Bindings can be deleted so that a queue can be rebound with a different set of values.
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. AMQP UnBind Request is made
+ * Output:
+ *
+ * <date> BND-1002 : Deleted
+ *
+ * Validation Steps:
+ * 3. The BND ID is correct
+ * 4. There must have been a BND-1001 Create message first.
+ * 5. This will be the last message for the given binding
+ */
+ public void testBindingDelete() throws JMSException, IOException
+ {
+ //Closing a consumer on a temporary queue will cause it to autodelete
+ // and so unbind.
+ _session.createConsumer(_session.createTemporaryQueue()).close();
+
+ List<String> results = _monitor.findMatches(BND_PREFIX);
+
+ // We will have two binds as we bind all queues to the default exchange
+ assertEquals("Result not as expected." + results, 4, results.size());
+
+
+ String messageID = "BND-1001";
+ String message = "Create";
+
+ String log = getLog(results.get(0));
+ validateMessageID(messageID, log);
+ assertEquals("Log Message not as expected", message, getMessageString(fromMessage(log)));
+
+ log = getLog(results.get(1));
+ validateMessageID(messageID, log);
+ assertEquals("Log Message not as expected", message, getMessageString(fromMessage(log)));
+
+
+ String DEFAULT = "direct/<<default>>";
+ String DIRECT = "direct/amq.direct";
+
+ messageID = "BND-1002";
+ message = "Deleted";
+
+ log = getLog(results.get(2));
+ validateMessageID(messageID, log);
+
+ String subject = fromSubject(log);
+
+ assertTrue("Routing Key does not start with TempQueue:"+AbstractTestLogSubject.getSlice("rk", subject),
+ AbstractTestLogSubject.getSlice("rk", subject).startsWith("TempQueue"));
+ assertEquals("Virtualhost not correct.", "/test",
+ AbstractTestLogSubject.getSlice("vh", subject));
+
+ boolean defaultFirst = DEFAULT.equals(AbstractTestLogSubject.getSlice("ex", subject));
+ boolean directFirst = DIRECT.equals(AbstractTestLogSubject.getSlice("ex", subject));
+
+ assertEquals("Log Message not as expected", message, getMessageString(fromMessage(log)));
+
+ log = getLog(results.get(3));
+
+ validateMessageID(messageID, log);
+
+ subject = fromSubject(log);
+
+ assertTrue("Routing Key does not start with TempQueue:"+AbstractTestLogSubject.getSlice("rk", subject),
+ AbstractTestLogSubject.getSlice("rk", subject).startsWith("TempQueue"));
+ assertEquals("Virtualhost not correct.", "/test",
+ AbstractTestLogSubject.getSlice("vh", subject));
+
+ if (!defaultFirst)
+ {
+ assertEquals(DEFAULT, AbstractTestLogSubject.getSlice("ex", subject));
+ assertTrue("First Exchange Log was not a direct exchange delete",directFirst);
+ }
+ else
+ {
+ assertEquals(DIRECT, AbstractTestLogSubject.getSlice("ex", subject));
+ assertTrue("First Exchange Log was not a default exchange delete",defaultFirst);
+ }
+
+ assertEquals("Log Message not as expected", message, getMessageString(fromMessage(log)));
+
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/logging/BrokerLoggingTest.java b/java/systests/src/main/java/org/apache/qpid/server/logging/BrokerLoggingTest.java
new file mode 100644
index 0000000000..b00a71315e
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/logging/BrokerLoggingTest.java
@@ -0,0 +1,1015 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+package org.apache.qpid.server.logging;
+
+import junit.framework.AssertionFailedError;
+import org.apache.qpid.server.Main;
+import org.apache.qpid.transport.ConnectionException;
+import org.apache.qpid.util.LogMonitor;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.Socket;
+import java.util.List;
+
+/**
+ * Broker Test Suite
+ *
+ * The Broker test suite validates that the follow log messages as specified in the Functional Specification.
+ *
+ * BRK-1001 : Startup : Version: <Version> Build: <Build>
+ * BRK-1002 : Starting : Listening on <Transport> port <Port>
+ * BRK-1003 : Shuting down : <Transport> port <Port>
+ * BRK-1004 : Ready
+ * BRK-1005 : Stopped
+ * BRK-1006 : Using configuration : <path>
+ * BRK-1007 : Using logging configuration : <path>
+ *
+ * These messages should only occur during startup. The tests need to verify the order of messages. In the case of the BRK-1002 and BRK-1003 the respective ports should only be available between the two log messages.
+ */
+public class BrokerLoggingTest extends AbstractTestLogging
+{
+ public void setUp() throws Exception
+ {
+ // We either do this here or have a null check in tearDown.
+ // As when this test is run against profiles other than java it will NPE
+ _monitor = new LogMonitor(_outputFile);
+ //We explicitly do not call super.setUp as starting up the broker is
+ //part of the test case.
+ }
+
+ /**
+ * Description:
+ * On startup the broker must report the active configuration file. The
+ * logging system must output this so that we can know what configuration
+ * is being used for this broker instance.
+ *
+ * Input:
+ * The value of -c specified on the command line.
+ * Output:
+ * <date> MESSAGE BRK-1006 : Using configuration : <config file>
+ * Constraints:
+ * This MUST BE the first BRK log message.
+ *
+ * Validation Steps:
+ * 1. This is first BRK log message.
+ * 2. The BRK ID is correct
+ * 3. The config file is the full path to the file specified on
+ * the commandline.
+ *
+ * @throws Exception caused by broker startup
+ */
+ public void testBrokerStartupConfiguration() throws Exception
+ {
+ // This logging startup code only occurs when you run a Java broker,
+ // that broker must be started via Main so not an InVM broker.
+ if (isJavaBroker() && isExternalBroker())
+ {
+ startBroker();
+
+ // Now we can create the monitor as _outputFile will now be defined
+ _monitor = new LogMonitor(_outputFile);
+
+
+ String configFilePath = _configFile.toString();
+
+ List<String> results = _monitor.findMatches("BRK-");
+ try
+ {
+ // Validation
+
+ assertTrue("BRKer message not logged", results.size() > 0);
+
+ String log = getLog(results.get(0));
+
+ //1
+ validateMessageID("BRK-1006", log);
+
+ //2
+ results = _monitor.findMatches("BRK-1006");
+ assertEquals("More than one configuration message found.",
+ 1, results.size());
+
+ //3
+ assertTrue("Config file details not correctly logged",
+ log.endsWith(configFilePath));
+ }
+ catch (AssertionFailedError afe)
+ {
+ System.err.println("Log Dump:");
+ for (String log : results)
+ {
+ System.err.println(log);
+ }
+ throw afe;
+ }
+ }
+ }
+
+ /**
+ * Description:
+ * On startup the broker must report correctly report the log4j file in use. This is important as it can help diagnose why logging messages are not being reported.
+ * Input:
+ * No custom -l value should be provided on the command line so that the default value is correctly reported.
+ * Output:
+ *
+ * <date> MESSAGE BRK-1007 : Using logging configuration : <$QPID_HOME>/etc/log4j.xml
+ *
+ * Validation Steps:
+ *
+ * 1. The BRK ID is correct
+ * 2. This occurs before the BRK-1001 startup message.
+ * 3. The log4j file is the full path to the file specified on the commandline.
+ *
+ * @throws Exception caused by broker startup
+ */
+ public void testBrokerStartupDefaultLog4j() throws Exception
+ {
+ // This logging startup code only occurs when you run a Java broker,
+ // that broker must be started via Main so not an InVM broker.
+ if (isJavaBroker() && isExternalBroker())
+ {
+ String TESTID = "BRK-1007";
+
+ //Remove test Log4j config from the commandline
+ _broker = _broker.substring(0, _broker.indexOf("-l"));
+
+ // As a result of removing the test log4j config
+ // we will pick up the broker default and will write
+ // data to the standard qpid.log file. Which means that the start
+ // broker process will not be monitoring the right file for startup
+ // messages. Therefore:
+
+ // Set the broker.ready string to check for the _log4j default that
+ // is still present on standard out.
+ setTestClientSystemProperty(BROKER_READY, "Qpid Broker Ready");
+
+ startBroker();
+
+ // Now we can create the monitor as _outputFile will now be defined
+ _monitor = new LogMonitor(_outputFile);
+
+ // Ensure broker has fully started up.
+ getConnection();
+
+ List<String> results = _monitor.findMatches("BRK-");
+ try
+ {
+ // Validation
+
+ assertTrue("BRKer message not logged", results.size() > 0);
+
+ boolean validation = false;
+ for (String rawLog : results)
+ {
+ // We don't care about messages after we have our log config
+ if (validation)
+ {
+ break;
+ }
+
+ String log = getLog(rawLog);
+
+ // Ensure we do not have a BRK-1001 message before
+ if (!getMessageID(log).equals(TESTID))
+ {
+ assertFalse(getMessageID(log).equals("BRK-1001"));
+ continue;
+ }
+
+ //1
+ validateMessageID(TESTID, log);
+
+ //2
+ assertEquals("More than one log4j configuration message found.",
+ 1, _monitor.findMatches(TESTID).size());
+
+ //3
+ String defaultLog4j = _configFile.getParent() + "/" + Main.DEFAULT_LOG_CONFIG_FILENAME;
+ assertTrue("Log4j file(" + defaultLog4j + ") details not correctly logged:" + getMessageString(log),
+ getMessageString(log).endsWith(defaultLog4j));
+
+ validation = true;
+ }
+
+ assertTrue("Validation not performed: " + TESTID + " not logged", validation);
+ }
+ catch (AssertionFailedError afe)
+ {
+ System.err.println("Log Dump:");
+ for (String log : results)
+ {
+ System.err.println(log);
+ }
+
+ if (results.size() == 0)
+ {
+ System.err.println("Monitored file contents:");
+ System.err.println(_monitor.readFile());
+ }
+
+ throw afe;
+ }
+ }
+ }
+
+ /**
+ * Description:
+ * On startup the broker must report correctly report the log4j file in use. This is important as it can help diagnose why logging messages are not being reported. The broker must also be capable of correctly recognising the command line property to specify the custom logging configuration.
+ * Input:
+ * The value of -l specified on the command line.
+ * Output:
+ *
+ * <date> MESSAGE BRK-1007 : Using logging configuration : <log4j file>
+ *
+ * Validation Steps:
+ *
+ * 1. The BRK ID is correct
+ * 2. This should occur before the BRK-1001 : Startup message
+ * 3. The log4j file is the full path to the file specified on the commandline.
+ *
+ * @throws Exception caused by broker startup
+ */
+ public void testBrokerStartupCustomLog4j() throws Exception
+ {
+ // This logging startup code only occurs when you run a Java broker,
+ // that broker must be started via Main so not an InVM broker.
+ if (isJavaBroker() && isExternalBroker())
+ {
+ // Get custom -l value used during testing for the broker startup
+ String customLog4j = _broker.substring(_broker.indexOf("-l") + 2);
+
+ String TESTID = "BRK-1007";
+
+ startBroker();
+
+ // Now we can create the monitor as _outputFile will now be defined
+ _monitor = new LogMonitor(_outputFile);
+
+
+ // Ensure broker has fully started up.
+ getConnection();
+
+ List<String> results = _monitor.findMatches("BRK-");
+ try
+ {
+ // Validation
+
+ assertTrue("BRKer message not logged", results.size() > 0);
+
+ boolean validation = false;
+ for (String rawLog : results)
+ {
+ // We don't care about messages after we have our log config
+ if (validation)
+ {
+ break;
+ }
+ String log = getLog(rawLog);
+
+ // Ensure we do not have a BRK-1001 message before
+ if (!getMessageID(log).equals(TESTID))
+ {
+ assertFalse(getMessageID(log).equals("BRK-1001"));
+ continue;
+ }
+
+ //1
+ validateMessageID(TESTID, log);
+
+ //2
+ assertEquals("More than one log4j configuration message found.",
+ 1, _monitor.findMatches(TESTID).size());
+
+ //3
+ assertTrue("Log4j file details not correctly logged:" + getMessageString(log),
+ getMessageString(log).endsWith(customLog4j));
+
+ validation = true;
+ }
+
+ assertTrue("Validation not performed: " + TESTID + " not logged", validation);
+ }
+ catch (AssertionFailedError afe)
+ {
+ System.err.println("Log Dump:");
+ for (String log : results)
+ {
+ System.err.println(log);
+ }
+
+ if (results.size() == 0)
+ {
+ System.err.println("Monitored file contents:");
+ System.err.println(_monitor.readFile());
+ }
+
+ throw afe;
+ }
+ }
+ }
+
+ /**
+ * Description: On startup the broker reports the broker version number and svn build revision. This information is retrieved from the resource 'qpidversion.properties' which is located via the classloader.
+ * Input: The 'qpidversion.properties' file located on the classpath.
+ * Output:
+ *
+ * <date> MESSAGE BRK-1001 : Startup : qpid Version: 0.6 Build: 767150
+ *
+ * Validation Steps:
+ *
+ * 1. The BRK ID is correct
+ * 2. This occurs before any BRK-1002 listening messages are reported.
+ *
+ * @throws Exception caused by broker startup
+ */
+ public void testBrokerStartupStartup() throws Exception
+ {
+ // This logging startup code only occurs when you run a Java broker,
+ // that broker must be started via Main so not an InVM broker.
+ if (isJavaBroker() && isExternalBroker())
+ {
+ String TESTID = "BRK-1001";
+
+ startBroker();
+
+ // Now we can create the monitor as _outputFile will now be defined
+ _monitor = new LogMonitor(_outputFile);
+
+ List<String> results = _monitor.findMatches("BRK-");
+ try
+ {
+ // Validation
+
+ assertTrue("BRKer message not logged", results.size() > 0);
+
+ boolean validation = false;
+ for (String rawLog : results)
+ {
+ if (validation)
+ {
+ //Stop checking once we have got to our startup test
+ break;
+ }
+ String log = getLog(rawLog);
+
+ // Ensure we do not have a BRK-1002 message
+ if (!getMessageID(log).equals(TESTID))
+ {
+ assertFalse(getMessageID(log).equals("BRK-1002"));
+ continue;
+ }
+
+ //1
+ validateMessageID(TESTID, log);
+
+ //2
+ assertEquals("More than one startup message found.",
+ 1, _monitor.findMatches(TESTID).size());
+
+ validation = true;
+ }
+
+ assertTrue("Validation not performed: " + TESTID + " not logged", validation);
+ }
+ catch (AssertionFailedError afe)
+ {
+ System.err.println("Log Dump:");
+ for (String log : results)
+ {
+ System.err.println(log);
+ }
+ throw afe;
+ }
+ }
+ }
+
+ /**
+ * Description:
+ * On startup the broker may listen on a number of ports and protocols. Each of these must be reported as they are made available.
+ * Input:
+ * The default configuration with no SSL
+ * Output:
+ *
+ * <date> MESSAGE BRK-1002 : Starting : Listening on TCP port 5672
+ *
+ * Constraints:
+ * Additional broker configuration will occur between the Startup(BRK-1001) and Starting(BRK-1002) messages depending on what VirtualHosts are configured.
+ * Validation Steps:
+ *
+ * 1. The BRK ID is correct
+ * 2. This occurs after the BRK-1001 startup message
+ * 3. Using the default configuration a single BRK-1002 will be printed showing values TCP / 5672
+ *
+ * @throws Exception caused by broker startup
+ */
+ public void testBrokerStartupListeningTCPDefault() throws Exception
+ {
+ // This logging startup code only occurs when you run a Java broker,
+ // that broker must be started via Main so not an InVM broker.
+ if (isJavaBroker() && isExternalBroker())
+ {
+ String TESTID = "BRK-1002";
+
+ startBroker();
+
+ // Now we can create the monitor as _outputFile will now be defined
+ _monitor = new LogMonitor(_outputFile);
+
+ // Ensure broker has fully started up.
+ getConnection();
+
+ List<String> results = _monitor.findMatches("BRK-");
+ try
+ {
+ // Validation
+
+ assertTrue("BRKer message not logged", results.size() > 0);
+
+ boolean validation = false;
+ boolean foundBRK1001 = false;
+ for (String rawLog : results)
+ {
+ String log = getLog(rawLog);
+
+ // Ensure we do not have a BRK-1002 message
+ if (!getMessageID(log).equals(TESTID))
+ {
+ if (getMessageID(log).equals("BRK-1001"))
+ {
+ foundBRK1001 = true;
+ }
+ continue;
+ }
+
+ assertTrue("BRK-1001 not logged before this message", foundBRK1001);
+
+ //1
+ validateMessageID(TESTID, log);
+
+ //2
+ assertEquals("More than one listen message found.",
+ 1, _monitor.findMatches(TESTID).size());
+
+ //3
+ String message = getMessageString(log);
+ assertTrue("Expected Listen log not correct" + message,
+ message.endsWith("Listening on TCP port " + getPort()));
+
+ validation = true;
+ }
+
+ assertTrue("Validation not performed: " + TESTID + " not logged", validation);
+ }
+ catch (AssertionFailedError afe)
+ {
+ System.err.println("Log Dump:");
+ for (String log : results)
+ {
+ System.err.println(log);
+ }
+ throw afe;
+ }
+ }
+ }
+
+ /**
+ * Description:
+ * On startup the broker may listen on a number of ports and protocols. Each of these must be reported as they are made available.
+ * Input:
+ * The default configuration with SSL enabled
+ * Output:
+ *
+ * <date> MESSAGE BRK-1002 : Starting : Listening on TCP port 5672
+ * <date> MESSAGE BRK-1002 : Starting : Listening on TCP/SSL port 8672
+ *
+ * Constraints:
+ * Additional broker configuration will occur between the Startup(BRK-1001) and Starting(BRK-1002) messages depending on what VirtualHosts are configured.
+ * Validation Steps:
+ *
+ * 1. The BRK ID is correct
+ * 2. This occurs after the BRK-1001 startup message
+ * 3. With SSL enabled in the configuration two BRK-1002 will be printed (order is not specified)
+ * 1. One showing values TCP / 5672
+ * 2. One showing values TCP/SSL / 5672
+ *
+ * @throws Exception caused by broker startup
+ */
+ public void testBrokerStartupListeningTCPSSL() throws Exception
+ {
+ // This logging startup code only occurs when you run a Java broker,
+ // that broker must be started via Main so not an InVM broker.
+ if (isJavaBroker() && isExternalBroker())
+ {
+ String TESTID = "BRK-1002";
+
+ // Enable SSL on the connection
+ setConfigurationProperty("connector.ssl.enabled", "true");
+ setConfigurationProperty("connector.ssl.sslOnly", "false");
+ setConfigurationProperty("connector.ssl.keyStorePath", getConfigurationStringProperty("management.ssl.keyStorePath"));
+ setConfigurationProperty("connector.ssl.keyStorePassword", getConfigurationStringProperty("management.ssl.keyStorePassword"));
+
+ Integer sslPort = Integer.parseInt(getConfigurationStringProperty("connector.sslport"));
+
+ startBroker();
+
+ // Now we can create the monitor as _outputFile will now be defined
+ _monitor = new LogMonitor(_outputFile);
+
+ // Ensure broker has fully started up.
+ getConnection();
+
+ List<String> results = _monitor.findMatches("BRK-");
+ try
+ {
+ // Validation
+
+ assertTrue("BRKer message not logged", results.size() > 0);
+
+ boolean validation = false;
+ boolean foundBRK1001 = false;
+ for (String rawLog : results)
+ {
+ String log = getLog(rawLog);
+
+ // Ensure we do not have a BRK-1002 message
+ if (!getMessageID(log).equals(TESTID))
+ {
+ if (getMessageID(log).equals("BRK-1001"))
+ {
+ foundBRK1001 = true;
+ }
+ continue;
+ }
+
+ assertTrue("BRK-1001 not logged before this message", foundBRK1001);
+
+ //1
+ validateMessageID(TESTID, log);
+
+ //2
+ List<String> listenMessages = _monitor.findMatches(TESTID);
+ assertEquals("Two listen messages should be found.",
+ 2, listenMessages .size());
+
+ //3
+ String message = getMessageString(getLog(listenMessages .get(0)));
+ assertTrue("Expected Listen log not correct" + message,
+ message.endsWith("Listening on TCP port " + getPort()));
+
+ // Check second, ssl, listen.
+ message = getMessageString(getLog(listenMessages .get(1)));
+ assertTrue("Expected Listen log not correct" + message,
+ message.endsWith("Listening on TCP/SSL port " + sslPort));
+
+ //4 Test ports open
+ testSocketOpen(getPort());
+ testSocketOpen(sslPort);
+
+ validation = true;
+ }
+
+ assertTrue("Validation not performed: " + TESTID + " not logged", validation);
+ }
+ catch (AssertionFailedError afe)
+ {
+ System.err.println("Log Dump:");
+ for (String log : results)
+ {
+ System.err.println(log);
+ }
+ throw afe;
+ }
+ }
+ }
+
+ /**
+ * Description:
+ * The final message the broker will print when it has performed all initialisation and listener startups will be to log the BRK-1004 Ready message
+ * Input:
+ * No input, all successful broker startups will show BRK-1004 messages.
+ * Output:
+ *
+ * 2009-07-09 15:50:20 +0100 MESSAGE BRK-1004 : Ready
+ *
+ * Validation Steps:
+ *
+ * 1. The BRK ID is correct
+ * 2. This occurs after the BRK-1001 startup message
+ * 3. This must be the last message the broker prints after startup. Currently, if there is no further interaction with the broker then there should be no more logging.
+ *
+ * @throws Exception caused by broker startup
+ */
+ public void testBrokerStartupReady() throws Exception
+ {
+ // This logging startup code only occurs when you run a Java broker,
+ // that broker must be started via Main so not an InVM broker.
+ if (isJavaBroker() && isExternalBroker())
+ {
+ String TESTID = "BRK-1004";
+
+ startBroker();
+
+ //Ensure the broker has fully started up.
+ getConnection();
+
+ List<String> results = _monitor.findMatches("BRK-");
+ try
+ {
+ // Validation
+
+ assertTrue("BRKer message not logged", results.size() > 0);
+
+ boolean validation = false;
+ boolean foundBRK1001 = false;
+ for (String rawLog : results)
+ {
+ assertFalse("More broker log statements present after ready message", validation);
+ String log = getLog(rawLog);
+
+ // Ensure we do not have a BRK-1002 message
+ if (!getMessageID(log).equals(TESTID))
+ {
+ if (getMessageID(log).equals("BRK-1001"))
+ {
+ foundBRK1001 = true;
+ }
+ continue;
+ }
+
+ assertTrue("BRK-1001 not logged before this message", foundBRK1001);
+
+ //1
+ validateMessageID(TESTID, log);
+
+ //2
+ assertEquals("More than one ready message found.",
+ 1, _monitor.findMatches(TESTID).size());
+
+ //3
+ assertEquals("Ready message not present", "Ready", getMessageString(log));
+
+ validation = true;
+ }
+
+ assertTrue("Validation not performed: " + TESTID + " not logged", validation);
+ }
+ catch (AssertionFailedError afe)
+ {
+ System.err.println("Log Dump:");
+ for (String log : results)
+ {
+ System.err.println(log);
+ }
+ throw afe;
+ }
+ }
+ }
+
+ /**
+ * Description:
+ * On startup the broker may listen on a number of ports and protocols. Each of these must then report a shutting down message as they stop listening.
+ * Input:
+ * The default configuration with no SSL
+ * Output:
+ *
+ * <date> MESSAGE BRK-1003 : Shutting down : TCP port 5672
+ *
+ * Validation Steps:
+ *
+ * 1. The BRK ID is correct
+ * 2. Only TCP is reported with the default configuration with no SSL.
+ * 3. The default port is correct
+ * 4. The port is not accessible after this message
+ *
+ * @throws Exception caused by broker startup
+ */
+ public void testBrokerShutdownListeningTCPDefault() throws Exception
+ {
+ // This logging startup code only occurs when you run a Java broker,
+ // that broker must be started via Main so not an InVM broker.
+ if (isJavaBroker() && isExternalBroker())
+ {
+ String TESTID = "BRK-1003";
+
+ startBroker();
+
+ // Now we can create the monitor as _outputFile will now be defined
+ _monitor = new LogMonitor(_outputFile);
+
+ stopBroker();
+
+ //Give broker time to shutdown and flush log
+ checkSocketClosed(getPort());
+
+ List<String> results = _monitor.findMatches("BRK-");
+ try
+ {
+ // Validation
+
+ assertTrue("BRKer message not logged", results.size() > 0);
+
+ boolean validation = false;
+ boolean foundBRK1001 = false;
+ for (String rawLog : results)
+ {
+ String log = getLog(rawLog);
+
+ // Ensure we do not have a BRK-1002 message
+ if (!getMessageID(log).equals(TESTID))
+ {
+ if (getMessageID(log).equals("BRK-1001"))
+ {
+ foundBRK1001 = true;
+ }
+ continue;
+ }
+
+ assertTrue("BRK-1001 not logged before this message", foundBRK1001);
+
+ //1
+ validateMessageID(TESTID, log);
+
+ //2
+ assertEquals("More than one listen message found.",
+ 1, _monitor.findMatches(TESTID).size());
+
+ //3
+ String message = getMessageString(log);
+ assertTrue("Expected shutdown log not correct" + message,
+ message.endsWith("TCP port " + getPort()));
+
+ //4
+ checkSocketClosed(getPort());
+
+ validation = true;
+ }
+
+ assertTrue("Validation not performed: " + TESTID + " not logged", validation);
+ }
+ catch (AssertionFailedError afe)
+ {
+ System.err.println("Log Dump:");
+ for (String log : results)
+ {
+ System.err.println(log);
+ }
+ throw afe;
+ }
+ }
+ }
+
+ /**
+ * Description:
+ * On startup the broker may listen on a number of ports and protocols. Each of these must be reported as they are made available.
+ * Input:
+ * The default configuration with SSL enabled
+ * Output:
+ *
+ * <date> MESSAGE BRK-1002 : Starting : Listening on TCP port 5672
+ * <date> MESSAGE BRK-1002 : Starting : Listening on TCP/SSL port 8672
+ *
+ * Constraints:
+ * Additional broker configuration will occur between the Startup(BRK-1001) and Starting(BRK-1002) messages depending on what VirtualHosts are configured.
+ * Validation Steps:
+ *
+ * 1. The BRK ID is correct
+ * 2. This occurs after the BRK-1001 startup message
+ * 3. With SSL enabled in the configuration two BRK-1002 will be printed (order is not specified)
+ * 1. One showing values TCP / 5672
+ * 2. One showing values TCP/SSL / 5672
+ *
+ * @throws Exception caused by broker startup
+ */
+ public void testBrokerShutdownListeningTCPSSL() throws Exception
+ {
+ // This logging startup code only occurs when you run a Java broker,
+ // that broker must be started via Main so not an InVM broker.
+ if (isJavaBroker() && isExternalBroker())
+ {
+ String TESTID = "BRK-1003";
+
+ // Enable SSL on the connection
+ setConfigurationProperty("connector.ssl.enabled", "true");
+ setConfigurationProperty("connector.ssl.keyStorePath", getConfigurationStringProperty("management.ssl.keyStorePath"));
+ setConfigurationProperty("connector.ssl.keyStorePassword", getConfigurationStringProperty("management.ssl.keyStorePassword"));
+
+ Integer sslPort = Integer.parseInt(getConfigurationStringProperty("connector.sslport"));
+
+ startBroker();
+
+ // Now we can create the monitor as _outputFile will now be defined
+ _monitor = new LogMonitor(_outputFile);
+
+
+// //Clear any startup messages as we don't need them for validation
+// _monitor.reset();
+ //Stop the broker to get the log messages for testing
+ stopBroker();
+
+ //Give broker time to shutdown and flush log
+ checkSocketClosed(getPort());
+
+ List<String> results = _monitor.findMatches(TESTID);
+ try
+ {
+ // Validation
+
+ assertTrue(TESTID + " messages not logged", results.size() > 0);
+
+ String log = getLog(results.get(0));
+
+ //1
+ validateMessageID(TESTID, log);
+
+ //2
+ List<String> listenMessages = _monitor.findMatches(TESTID);
+ assertEquals("Two shutdown messages should be found.",
+ 2, listenMessages.size());
+
+ //3
+ String message = getMessageString(getLog(listenMessages.get(0)));
+ assertTrue("Expected shutdown log not correct" + message,
+ message.endsWith("TCP port " + getPort()));
+
+ // Check second, ssl, listen.
+ message = getMessageString(getLog(listenMessages.get(1)));
+ assertTrue("Expected shutdown log not correct" + message,
+ message.endsWith("TCP/SSL port " + sslPort));
+
+ //4
+ //Test Port closed
+ checkSocketClosed(getPort());
+ //Test SSL Port closed
+ checkSocketClosed(sslPort);
+ }
+ catch (AssertionFailedError afe)
+ {
+ System.err.println("Log Dump:");
+ for (String log : results)
+ {
+ System.err.println(log);
+ }
+ throw afe;
+ }
+ }
+ }
+
+ /**
+ * Description:
+ * Input:
+ * No input, all clean broker shutdowns will show BRK-1005 messages.
+ * Output:
+ *
+ * <date> MESSAGE BRK-1005 : Stopped
+ *
+ * Constraints:
+ * This is the LAST message the broker will log.
+ * Validation Steps:
+ *
+ * 1. The BRK ID is correct
+ * 2. This is the last message the broker will log.
+ *
+ * @throws Exception caused by broker startup
+ */
+ public void testBrokerShutdownStopped() throws Exception
+ {
+ // This logging startup code only occurs when you run a Java broker,
+ // that broker must be started via Main so not an InVM broker.
+ if (isJavaBroker() && isExternalBroker())
+ {
+ String TESTID = "BRK-1005";
+
+ startBroker();
+
+ // Now we can create the monitor as _outputFile will now be defined
+ _monitor = new LogMonitor(_outputFile);
+
+ getConnection().close();
+
+ stopBroker();
+
+ // Ensure the broker has shutdown before retreving results
+ checkSocketClosed(getPort());
+
+ List<String> results = _monitor.findMatches("BRK-");
+ try
+ {
+ // Validation
+
+ assertTrue("BRKer message not logged", results.size() > 0);
+
+ boolean validation = false;
+ for (String rawLog : results)
+ {
+ assertFalse("More broker log statements present after ready message", validation);
+ String log = getLog(rawLog);
+
+ // Ignore all logs until we get to the test id.
+ if (!getMessageID(log).equals(TESTID))
+ {
+ continue;
+ }
+
+ //1
+ validateMessageID(TESTID, log);
+
+ //2
+ assertEquals("More than one ready message found.",
+ 1, _monitor.findMatches(TESTID).size());
+
+ //3
+ assertEquals("Stopped message not present", "Stopped", getMessageString(log));
+
+ validation = true;
+ }
+
+ assertTrue("Validation not performed: " + TESTID + " not logged", validation);
+ }
+ catch (AssertionFailedError afe)
+ {
+ System.err.println("Log Dump:");
+ for (String log : results)
+ {
+ System.err.println(log);
+ }
+
+ System.err.println("Monitored file contents:");
+ System.err.println(_monitor.readFile());
+
+ throw afe;
+ }
+ }
+ }
+
+ /**
+ * Test that a socket on the given port is closed.
+ *
+ * Does this by attempting to connect to the port and expecting a
+ * ConnectionRefused IOException or a ConnectionException
+ *
+ * @param port the port number
+ */
+ private void checkSocketClosed(int port)
+ {
+ try
+ {
+ Socket socket = new Socket((String) null, port);
+ fail("Socket not closed on port:" + port);
+ }
+ catch (ConnectionException e)
+ {
+ //normal path
+ }
+ catch (IOException e)
+ {
+ if (!e.getMessage().equals("Connection refused"))
+ {
+ fail("Socket not closed on port:" + port + ":" + e.getMessage());
+ // Keep stack trace for diagnosis.
+ e.printStackTrace(System.err);
+ }
+ }
+ }
+
+ /**
+ * Test that a socket on the given port is open.
+ *
+ * Does this by attempting to connect to the port and expecting a
+ * The connection to succeed.
+ * It then closes the socket and expects that to work cleanly.
+ *
+ * @param port the port number
+ */
+ private void testSocketOpen(int port)
+ {
+ try
+ {
+ Socket socket = new Socket((String) null, port);
+ socket.close();
+ }
+ catch (IOException e)
+ {
+ fail("Unable to open and close socket to port:" + port
+ + ". Due to:" + e.getMessage());
+ }
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/logging/ChannelLoggingTest.java b/java/systests/src/main/java/org/apache/qpid/server/logging/ChannelLoggingTest.java
new file mode 100644
index 0000000000..ea0199570c
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/logging/ChannelLoggingTest.java
@@ -0,0 +1,301 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging;
+
+import org.apache.qpid.client.AMQConnection;
+
+import javax.jms.Connection;
+import javax.jms.MessageConsumer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import java.io.File;
+import java.util.List;
+
+public class ChannelLoggingTest extends AbstractTestLogging
+{
+ private static final String CHANNEL_PREFIX = "CHN-";
+
+ public void setUp() throws Exception
+ {
+ // set QPID_WORK to be [QPID_WORK|io.tmpdir]/<testName>
+ setSystemProperty("QPID_WORK",
+ System.getProperty("QPID_WORK",
+ System.getProperty("java.io.tmpdir"))
+ + File.separator + getName());
+
+ //Start the broker
+ super.setUp();
+ }
+
+ /**
+ * Description:
+ * When a new Channel (JMS Session) is created this will be logged as a CHN-1001 Create message. The messages will contain the prefetch details about this new Channel.
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. New JMS Session/Channel creation
+ *
+ * Output:
+ * <date> CHN-1001 : Create
+ * <date> CHN-1004 : Prefetch Size (bytes) {0,number} : Count {1,number}
+ *
+ * Validation Steps:
+ * 1. The CHN ID is correct
+ * 2. The prefetch value matches that defined by the requesting client.
+ *
+ * @throws Exception - if an error occurs
+ */
+ public void testChannelCreate() throws Exception
+ {
+ assertLoggingNotYetOccured(CHANNEL_PREFIX);
+
+ Connection connection = getConnection();
+
+ int PREFETCH = 12;
+
+ // Test that calling session.close gives us the expected output
+ ((AMQConnection)connection).createSession(false, Session.AUTO_ACKNOWLEDGE,PREFETCH);
+
+ List<String> results = _monitor.findMatches(CHANNEL_PREFIX);
+
+ // Validation
+
+ assertEquals("CHN messages not logged", 2, results.size());
+
+ String log = getLog(results.get(0));
+ // MESSAGE [con:0(guest@anonymous(3273383)/test)/ch:1] CHN-1001 : Create
+ //1 & 2
+ validateMessageID("CHN-1001", log);
+ assertEquals("Incorrect Channel in actor:"+fromActor(log), 1, getChannelID(fromActor(log)));
+
+ log = getLog(results.get(1));
+ // MESSAGE [con:0(guest@anonymous(3273383)/test)/ch:1] CHN-1004 : Prefetch Size (bytes) {0,number} : Count {1,number}
+ //1 & 2
+ validateMessageID("CHN-1004", log);
+ assertEquals("Incorrect Channel in actor:"+fromActor(log), 1, getChannelID(fromActor(log)));
+ assertTrue("Prefetch Count not correct",getMessageString(fromMessage(log)).endsWith("Count "+PREFETCH));
+
+ connection.close();
+ }
+
+ /**
+ * Description:
+ * The Java Broker implements consumer flow control for all ack modes except
+ * No-Ack. When a client connects the session's flow is initially set to
+ * Stopped. Verify this message appears
+ *
+ * Input:
+ * 1. Running broker
+ * 2. Create consumer
+ * Output:
+ *
+ * <date> CHN-1002 : Flow Stopped
+ *
+ * Validation Steps:
+ * 4. The CHN ID is correct
+ *
+ * @throws Exception - if an error occurs
+ */
+
+ public void testChannelStartsFlowStopped() throws Exception
+ {
+ assertLoggingNotYetOccured(CHANNEL_PREFIX);
+
+ Connection connection = getConnection();
+
+ // Create a session to fill up
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ Queue queue = (Queue) getInitialContext().lookup(QUEUE);
+ MessageConsumer consumer = session.createConsumer(queue);
+
+ connection.start();
+
+ List<String> results = _monitor.findMatches(CHANNEL_PREFIX);
+
+ assertTrue("No CHN messages logged", results.size() > 0);
+
+ // The last channel message should be:
+ //
+ // INFO - MESSAGE [con:0(guest@anonymous(4205299)/test)/ch:1] [con:0(guest@anonymous(4205299)/test)/ch:1] CHN-1002 : Flow Off
+
+ // Verify
+ int resultSize = results.size();
+ String log = getLog(results.get(resultSize - 1));
+
+ validateMessageID("CHN-1002", log);
+ assertEquals("Message should be Flow Stopped", "Flow Stopped", getMessageString(fromMessage(log)));
+
+ }
+
+ /**
+ * Description:
+ * The Java Broker implements consumer flow control for all ack modes except
+ * No-Ack. When the client first attempts to receive a message then the Flow
+ * status of the Session is set to Started.
+ *
+ * Input:
+ * 1. Running broker
+ * 2. Create a consumer
+ * 3. Attempt to receive a message
+ * Output:
+ *
+ * <date> CHN-1002 : Flow Started
+ *
+ * Validation Steps:
+ * 4. The CHN ID is correct
+ *
+ * @throws Exception - if an error occurs
+ */
+
+ public void testChannelStartConsumerFlowStarted() throws Exception
+ {
+ assertLoggingNotYetOccured(CHANNEL_PREFIX);
+
+ Connection connection = getConnection();
+
+ // Create a session to fill up
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ Queue queue = (Queue) getInitialContext().lookup(QUEUE);
+ MessageConsumer consumer = session.createConsumer(queue);
+
+ connection.start();
+
+ //Call receive to send the Flow On message
+ consumer.receiveNoWait();
+
+ List<String> results = _monitor.findMatches(CHANNEL_PREFIX);
+
+ assertTrue("No CHN messages logged", results.size() > 0);
+
+ // The last two channel messages should be:
+ //
+ // INFO - MESSAGE [con:0(guest@anonymous(4205299)/test)/ch:1] [con:0(guest@anonymous(4205299)/test)/ch:1] CHN-1002 : Flow On
+
+ // Verify
+
+ int resultSize = results.size();
+ String log = getLog(results.get(resultSize - 1));
+
+ validateMessageID("CHN-1002", log);
+ assertEquals("Message should be Flow Started", "Flow Started", getMessageString(fromMessage(log)));
+
+ }
+
+ /**
+ * Description:
+ * When the client gracefully closes the Connection then a CHN-1003 Close
+ * message will be issued. This must be the last message logged for this
+ * Channel.
+ * Input:
+ * 1. Running Broker
+ * 2. Connected Client
+ * 3. Client then requests that the Connection is closed
+ * Output:
+ *
+ * <date> CHN-1003 : Close
+ *
+ * Validation Steps:
+ * 4. The MST ID is correct
+ * 5. This must be the last message logged for this Channel.
+ *
+ * @throws Exception - if an error occurs
+ */
+ public void testChannelCloseViaConnectionClose() throws Exception
+ {
+ assertLoggingNotYetOccured(CHANNEL_PREFIX);
+
+ Connection connection = getConnection();
+
+ // Create a session
+ connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Close the connection to verify the created session closing is logged.
+ connection.close();
+
+ List<String> results = _monitor.findMatches(CHANNEL_PREFIX);
+
+ assertTrue("No CHN messages logged", results.size() > 0);
+
+ // The last two channel messages should be:
+ //
+ // INFO - MESSAGE [con:0(guest@anonymous(4205299)/test)/ch:1] [con:0(guest@anonymous(4205299)/test)/ch:1] CHN-1002 : Flow On
+
+ // Verify
+
+ int resultSize = results.size();
+ String log = getLog(results.get(resultSize - 1));
+
+ validateMessageID("CHN-1003", log);
+ assertEquals("Message should be Close", "Close",getMessageString(fromMessage(log)));
+ assertEquals("Incorrect Channel ID closed.", 1, getChannelID(fromActor(log)));
+ assertEquals("Incorrect Channel ID closed.", 1, getChannelID(fromSubject(log)));
+ }
+
+ /**
+ * Description:
+ * When the client gracefully closes the Connection then a CHN-1003 Close
+ * message will be issued. This must be the last message logged for this
+ * Channel.
+ * Input:
+ * 1. Running Broker
+ * 2. Connected Client
+ * 3. Client then requests that the Channel is closed
+ * Output:
+ *
+ * <date> CHN-1003 : Close
+ *
+ * Validation Steps:
+ * 4. The MST ID is correct
+ * 5. This must be the last message logged for this Channel.
+ *
+ * @throws Exception - if an error occurs
+ */
+ public void testChannelCloseViaChannelClose() throws Exception
+ {
+ assertLoggingNotYetOccured(CHANNEL_PREFIX);
+
+ Connection connection = getConnection();
+
+ // Create a session and then close it
+ connection.createSession(false, Session.AUTO_ACKNOWLEDGE).close();
+
+ List<String> results = _monitor.findMatches(CHANNEL_PREFIX);
+
+ assertTrue("No CHN messages logged", results.size() > 0);
+
+ // The last two channel messages should be:
+ //
+ // INFO - MESSAGE [con:0(guest@anonymous(4205299)/test)/ch:1] [con:0(guest@anonymous(4205299)/test)/ch:1] CHN-1002 : Flow On
+
+ // Verify
+
+ int resultSize = results.size();
+ String log = getLog(results.get(resultSize - 1));
+
+ validateMessageID("CHN-1003", log);
+ assertEquals("Message should be Close", "Close",getMessageString(fromMessage(log)));
+ assertEquals("Incorrect Channel ID closed.", 1, getChannelID(fromActor(log)));
+ assertEquals("Incorrect Channel ID closed.", 1, getChannelID(fromSubject(log)));
+ }
+
+} \ No newline at end of file
diff --git a/java/systests/src/main/java/org/apache/qpid/server/logging/ConnectionLoggingTest.java b/java/systests/src/main/java/org/apache/qpid/server/logging/ConnectionLoggingTest.java
new file mode 100644
index 0000000000..503129072b
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/logging/ConnectionLoggingTest.java
@@ -0,0 +1,182 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+package org.apache.qpid.server.logging;
+
+import javax.jms.Connection;
+import java.io.File;
+import java.util.List;
+import java.util.HashMap;
+import java.util.TreeSet;
+
+public class ConnectionLoggingTest extends AbstractTestLogging
+{
+ private static final String CONNECTION_PREFIX = "CON-";
+
+ public void setUp() throws Exception
+ {
+ // set QPID_WORK to be [QPID_WORK|io.tmpdir]/<testName>
+ setSystemProperty("QPID_WORK",
+ System.getProperty("QPID_WORK",
+ System.getProperty("java.io.tmpdir"))
+ + File.separator + getName());
+
+ //Start the broker
+ super.setUp();
+ }
+
+ /**
+ * Description:
+ * When a new connection is made to the broker this must be logged.
+ *
+ * Input:
+ * 1. Running Broker
+ * 2. Connecting client
+ * Output:
+ * <date> CON-1001 : Open : Client ID {0}[ : Protocol Version : {1}] <version>
+ *
+ * Validation Steps:
+ * 1. The CON ID is correct
+ * 2. This is the first CON message for that Connection
+ *
+ * @throws Exception - if an error occurs
+ */
+ public void testConnectionOpen() throws Exception
+ {
+ assertLoggingNotYetOccured(CONNECTION_PREFIX);
+
+ Connection connection = getConnection();
+
+ List<String> results = _monitor.findMatches(CONNECTION_PREFIX);
+
+ assertTrue("No CON messages logged", results.size() > 0);
+
+ // Validation
+ // We should have at least three messages when running InVM but when running External
+ // we will get 0-10 negotiation on con:0 whcih may close at some random point
+ // MESSAGE [con:0(/127.0.0.1:46926)] CON-1001 : Open
+ // MESSAGE [con:0(/127.0.0.1:46926)] CON-1001 : Open : Protocol Version : 0-10
+ // MESSAGE [con:1(/127.0.0.1:46927)] CON-1001 : Open
+ // MESSAGE [con:1(/127.0.0.1:46927)] CON-1001 : Open : Protocol Version : 0-9
+ // MESSAGE [con:0(/127.0.0.1:46926)] CON-1002 : Close
+ // MESSAGE [con:1(/127.0.0.1:46927)] CON-1001 : Open : Client ID : clientid : Protocol Version : 0-9
+
+ //So check how many connections we have in the result set and extract the last one.
+ // When running InVM we will have con:0 and externally con:1
+
+ HashMap<Integer, List<String>> connectionData = splitResultsOnConnectionID(results);
+
+ // Get the last Integer from keySet of the ConnectionData
+ int connectionID = new TreeSet<Integer>(connectionData.keySet()).last();
+
+ //Use just the data from the last connection for the test
+ results = connectionData.get(connectionID);
+
+ // If we are running inVM we will get three open messagse, if running externally weN will also have
+ // open and close messages from the failed 0-10 negotiation
+ assertTrue("CON messages not logged:" + results.size(), results.size() >= 3);
+
+ String log = getLog(results.get(0));
+ // MESSAGE [con:1(/127.0.0.1:52540)] CON-1001 : Open
+ //1 & 2
+ validateMessageID("CON-1001",log);
+
+ //We get the size so that we can validate the last three CON- messages
+ int resultsSize = results.size();
+ // This is because when running externally we will also have logged the failed
+ // 0-10 negotiation messages
+
+ // 3 - Assert the options are correct
+ log = getLog(results.get(resultsSize - 1));
+ // MESSAGE [con:1(/127.0.0.1:52540)] CON-1001 : Open : Client ID : clientid : Protocol Version : 0-9
+ validateMessageID("CON-1001",log);
+ assertTrue("Client ID option is not present", fromMessage(log).contains("Client ID :"));
+ assertTrue("Client ID value is not present", fromMessage(log).contains(connection.getClientID()));
+
+ assertTrue("Protocol Version option is not present", fromMessage(log).contains("Protocol Version :"));
+ //fixme there is no way currently to find out the negotiated protocol version
+ // The delegate is the versioned class ((AMQConnection)connection)._delegate
+
+ log = getLog(results.get(resultsSize - 2));
+ // MESSAGE [con:1(/127.0.0.1:52540)] CON-1001 : Open : Protocol Version : 0-9
+ validateMessageID("CON-1001",log);
+ assertTrue("Protocol Version option is not present", fromMessage(log).contains("Protocol Version :"));
+ //fixme agani we should check the version
+ // Check that client ID is not present in log
+ assertTrue("Client ID option is present", !fromMessage(log).contains("Client ID :"));
+
+ log = getLog(results.get(resultsSize - 3));
+ validateMessageID("CON-1001",log);
+ // Check that PV is not present in log
+ assertTrue("Protocol Version option is present", !fromMessage(log).contains("Protocol Version :"));
+ // Check that client ID is not present in log
+ assertTrue("Client ID option is present", !fromMessage(log).contains("Client ID :"));
+
+ connection.close();
+ }
+
+ /**
+ * Description:
+ * When a connected client closes the connection this will be logged as a CON-1002 message.
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Connected Client
+ * Output:
+ *
+ * <date> CON-1002 : Close
+ *
+ * Validation Steps:
+ * 3. The CON ID is correct
+ * 4. This must be the last CON message for the Connection
+ * 5. It must be preceded by a CON-1001 for this Connection
+ */
+ public void testConnectionClose() throws Exception
+ {
+ assertLoggingNotYetOccured(CONNECTION_PREFIX);
+
+ // Open and then close the conneciton
+ getConnection().close();
+
+ List<String> results = _monitor.findMatches(CONNECTION_PREFIX);
+
+ // Validation
+
+ // We should have at least four messages
+ assertTrue("CON messages not logged:" + results.size(), results.size() >= 4);
+
+ //We get the size so that we can validate the last set of CON- messages
+ int resultsSize = results.size();
+
+ // Validate Close message occurs
+ String log = getLog(results.get(resultsSize - 1));
+ validateMessageID("CON-1002",log);
+ assertTrue("Message does not end with close:" + log, log.endsWith("Close"));
+
+ // Extract connection ID to validate there is a CON-1001 messasge for it
+ int connectionID = getConnectionID(log);
+
+ //Previous log message should be the open
+ log = getLog(results.get(resultsSize - 2));
+ // MESSAGE [con:1(/127.0.0.1:52540)] CON-1001 : Open : Client ID : clientid : Protocol Version : 0-9
+ validateMessageID("CON-1001",log);
+ assertEquals("Connection IDs do not match", connectionID, getConnectionID(fromActor(log)));
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/logging/DerbyMessageStoreLoggingTest.java b/java/systests/src/main/java/org/apache/qpid/server/logging/DerbyMessageStoreLoggingTest.java
new file mode 100644
index 0000000000..cc3993249c
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/logging/DerbyMessageStoreLoggingTest.java
@@ -0,0 +1,567 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.logging.subjects.AbstractTestLogSubject;
+
+import javax.jms.Connection;
+import javax.jms.Queue;
+import javax.jms.Session;
+import java.util.List;
+import java.io.File;
+
+/**
+ * The MessageStore test suite validates that the follow log messages as
+ * specified in the Functional Specification.
+ *
+ * This suite of tests validate that the MessageStore messages occur correctly
+ * and according to the following format:
+ *
+ * MST-1001 : Created : <name>
+ * MST-1003 : Closed
+ *
+ * NOTE: Only for Persistent Stores
+ * MST-1002 : Store location : <path>
+ * MST-1004 : Recovery Start [: <queue.name>]
+ * MST-1005 : Recovered <count> messages for queue <queue.name>
+ * MST-1006 : Recovery Complete [: <queue.name>]
+ */
+public class DerbyMessageStoreLoggingTest extends MemoryMessageStoreLoggingTest
+{
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ // MemoryMessageStoreLoggingTest setUp itself does not call super.setUp
+ //We call super.setUp but this will not start the broker as that is
+ //part of the test case.
+
+ // Load the default configuration file to get the list of defined vhosts
+ ServerConfiguration configuration = new ServerConfiguration(new File(_configFile.getParent() + "/config.xml"));
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
+
+ // Make them all persistent i.e. Use DerbyMessageStore and
+ // test that it logs correctly.
+ for (String vhost : vhosts)
+ {
+ makeVirtualHostPersistent(vhost);
+ }
+ }
+
+ /**
+ * Description:
+ * Persistent MessageStores will require space on disk to persist the data.
+ * This value will be logged on startup after the MessageStore has been
+ * created.
+ * Input:
+ * Default configuration
+ * Output:
+ *
+ * <date> MST-1002 : Store location : <path>
+ *
+ * Validation Steps:
+ *
+ * 1. The MST ID is correct
+ * 2. This must occur after MST-1001
+ */
+ public void testMessageStoreStoreLocation() throws Exception
+ {
+ assertLoggingNotYetOccured(MESSAGES_STORE_PREFIX);
+
+ startBroker();
+
+ List<String> results = _monitor.findMatches(MESSAGES_STORE_PREFIX);
+
+ // Validation
+
+ assertTrue("MST messages not logged", results.size() > 0);
+
+ // Load VirtualHost list from file.
+ ServerConfiguration configuration = new ServerConfiguration(_configFile);
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
+
+ //Validate each vhost logs a creation
+ results = _monitor.findMatches("MST-1002");
+
+ assertEquals("Each vhost did not close its store.", vhosts.size(), results.size());
+
+ for (int index = 0; index < results.size(); index++)
+ {
+ String result = getLog(results.get(index));
+
+ // getSlize will return extract the vhost from vh(/test) -> '/test'
+ // so remove the '/' to get the name
+ String vhostName = AbstractTestLogSubject.getSlice("vh", result).substring(1);
+
+ // To get the store class used in the configuration we need to know
+ // the virtualhost name, found above. AND
+ // the index that the virtualhost is within the configuration.
+ // we can retrive that from the vhosts list previously extracted.
+ String fullStoreName = configuration.getConfig().getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
+
+ // Get the Simple class name from the expected class name of o.a.q.s.s.MMS
+ String storeName = fullStoreName.substring(fullStoreName.lastIndexOf(".") + 1);
+
+ assertTrue("MST-1002 does not contain a store path" + getMessageString(result),
+ getMessageString(result).length() > 0);
+
+ assertEquals("The store name does not match expected value",
+ storeName, AbstractTestLogSubject.getSlice("ms", fromSubject(result)));
+ }
+ }
+
+ /**
+ * Description:
+ * Persistent message stores may have state on disk that they must recover
+ * during startup. As the MessageStore starts up it will report that it is
+ * about to start the recovery process by logging MST-1004. This message
+ * will always be logged for persistent MessageStores. If there is no data
+ * to recover then there will be no subsequent recovery messages.
+ * Input:
+ * Default persistent configuration
+ * Output:
+ * <date> MST-1004 : Recovery Start
+ *
+ * Validation Steps:
+ *
+ * 1. The MST ID is correct
+ * 2. The MessageStore must have first logged a creation event.
+ */
+ public void testMessageStoreRecoveryStart() throws Exception
+ {
+ assertLoggingNotYetOccured(MESSAGES_STORE_PREFIX);
+
+ startBroker();
+
+ List<String> results = _monitor.findMatches(MESSAGES_STORE_PREFIX);
+
+ // Validation
+
+ assertTrue("MST messages not logged", results.size() > 0);
+
+ // Load VirtualHost list from file.
+ ServerConfiguration configuration = new ServerConfiguration(_configFile);
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
+
+ //Validate each vhost logs a creation
+ results = _monitor.findMatches("MST-1004");
+
+ assertTrue("Each vhost did not close its store.", vhosts.size() <= results.size());
+
+ for (int index = 0; index < results.size(); index++)
+ {
+ String result = getLog(results.get(index));
+
+ if (getMessageString(result).contains("Recovery Start :"))
+ {
+ //Don't test queue start recoveries
+ continue;
+ }
+
+ // getSlize will return extract the vhost from vh(/test) -> '/test'
+ // so remove the '/' to get the name
+ String vhostName = AbstractTestLogSubject.getSlice("vh", result).substring(1);
+
+ // To get the store class used in the configuration we need to know
+ // the virtualhost name, found above. AND
+ // the index that the virtualhost is within the configuration.
+ // we can retrive that from the vhosts list previously extracted.
+ String fullStoreName = configuration.getConfig().getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
+
+ // Get the Simple class name from the expected class name of o.a.q.s.s.MMS
+ String storeName = fullStoreName.substring(fullStoreName.lastIndexOf(".") + 1);
+
+ assertEquals("MST-1004 does have expected message", "Recovery Start",
+ getMessageString(result));
+
+ assertEquals("The store name does not match expected value",
+ storeName, AbstractTestLogSubject.getSlice("ms", fromSubject(result)));
+ }
+ }
+
+ /**
+ * Description:
+ * Once all persistent queues have been recovered and the MessageStore has completed all recovery it must logged that the recovery process has completed.
+ * Input:
+ * Default persistent configuration
+ * Output:
+ *
+ * <date> MST-1006 : Recovery Complete
+ *
+ * Validation Steps:
+ *
+ * 1. The MST ID is correct
+ * 2. This is the last message from the MessageStore during startup.
+ * 3. This must be proceeded by a MST-1006 Recovery Start.
+ */
+ public void testMessageStoreRecoveryComplete() throws Exception
+ {
+ assertLoggingNotYetOccured(MESSAGES_STORE_PREFIX);
+
+ startBroker();
+
+ List<String> results = _monitor.findMatches(MESSAGES_STORE_PREFIX);
+
+ // Validation
+
+ assertTrue("MST messages not logged", results.size() > 0);
+
+ // Load VirtualHost list from file.
+ ServerConfiguration configuration = new ServerConfiguration(_configFile);
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
+
+ //Validate each vhost logs a creation
+ results = _monitor.findMatches("MST-1006");
+
+ assertTrue("Each vhost did not close its store.", vhosts.size() <= results.size());
+
+ for (int index = 0; index < results.size(); index++)
+ {
+ String result = getLog(results.get(index));
+
+ if (getMessageString(result).contains("Recovery Complete :"))
+ {
+ //Don't test queue start recoveries
+ continue;
+ }
+
+ // getSlize will return extract the vhost from vh(/test) -> '/test'
+ // so remove the '/' to get the name
+ String vhostName = AbstractTestLogSubject.getSlice("vh", result).substring(1);
+
+ // To get the store class used in the configuration we need to know
+ // the virtualhost name, found above. AND
+ // the index that the virtualhost is within the configuration.
+ // we can retrive that from the vhosts list previously extracted.
+ String fullStoreName = configuration.getConfig().getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
+
+ // Get the Simple class name from the expected class name of o.a.q.s.s.MMS
+ String storeName = fullStoreName.substring(fullStoreName.lastIndexOf(".") + 1);
+
+ assertEquals("MST-1006 does have expected message", "Recovery Complete",
+ getMessageString(result));
+
+ assertEquals("The store name does not match expected value",
+ storeName, AbstractTestLogSubject.getSlice("ms", fromSubject(result)));
+ }
+ }
+
+ /**
+ * Description:
+ * A persistent MessageStore may have data to recover from disk. The message store will use MST-1004 to report the start of recovery for a specific queue that it has previously persisted.
+ * Input:
+ * Default persistent configuration
+ * Output:
+ *
+ * <date> MST-1004 : Recovery Start : <queue.name>
+ *
+ * Validation Steps:
+ *
+ * 1. The MST ID is correct
+ * 2. This must occur after the recovery start MST-1004 has been logged.
+ */
+ public void testMessageStoreQueueRecoveryStart() throws Exception
+ {
+ assertLoggingNotYetOccured(MESSAGES_STORE_PREFIX);
+
+ startBroker();
+
+ List<String> results = _monitor.findMatches(MESSAGES_STORE_PREFIX);
+
+ // Validation
+
+ assertTrue("MST messages not logged", results.size() > 0);
+
+ // Load VirtualHost list from file.
+ ServerConfiguration configuration = new ServerConfiguration(_configFile);
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
+
+ //Validate each vhost logs a creation
+ results = _monitor.findMatches("MST-1004 : Recovery Start :");
+
+ // We are only looking for the default queue defined in local host being
+ // recovered. If other tests have made queues in test then we want to
+ // exclude them here.
+ results = filterResultsByVirtualHost(results, "/localhost");
+
+ assertEquals("Recovered test queue not found.", 1, results.size());
+
+ String result = getLog(results.get(0));
+
+ // getSlize will return extract the vhost from vh(/test) -> '/test'
+ // so remove the '/' to get the name
+ String vhostName = AbstractTestLogSubject.getSlice("vh", result).substring(1);
+
+ // To get the store class used in the configuration we need to know
+ // the virtualhost name, found above. AND
+ // the index that the virtualhost is within the configuration.
+ // we can retrive that from the vhosts list previously extracted.
+ String fullStoreName = configuration.getConfig().getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
+
+ // Get the Simple class name from the expected class name of o.a.q.s.s.MMS
+ String storeName = fullStoreName.substring(fullStoreName.lastIndexOf(".") + 1);
+
+ assertTrue("MST-1006 does end with queue 'test-queue':" + getMessageString(result),
+ getMessageString(result).endsWith("test-queue"));
+
+ assertEquals("The store name does not match expected value",
+ storeName, AbstractTestLogSubject.getSlice("ms", fromSubject(result)));
+
+ }
+
+ /**
+ * Description:
+ * After the queue has been recovered the store will log that recovery has been completed. The MessageStore must not report further status about the recovery of this queue after this message. In addition every MST-1004 queue recovery start message must be matched with a MST-1006 recovery complete.
+ * Input:
+ * Default persistent configuration
+ * Output:
+ *
+ * <date> MST-1006 : Recovery Complete : <queue.name>
+ *
+ * Validation Steps:
+ *
+ * 1. The MST ID is correct
+ * 2. This must occur after the queue recovery start MST-1004 has been logged.
+ * 3. The queue.name is non-empty
+ * 4. The queue.name correlates with a previous recovery start
+ */
+ public void testMessageStoreQueueRecoveryComplete() throws Exception
+ {
+ assertLoggingNotYetOccured(MESSAGES_STORE_PREFIX);
+
+ startBroker();
+
+ List<String> results = _monitor.findMatches(MESSAGES_STORE_PREFIX);
+
+ // Validation
+
+ assertTrue("MST messages not logged", results.size() > 0);
+
+ // Load VirtualHost list from file.
+ ServerConfiguration configuration = new ServerConfiguration(_configFile);
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
+
+ //Validate each vhost logs a creation
+ results = _monitor.findMatches("MST-1006 : Recovery Complete :");
+
+ // We are only looking for the default queue defined in local host being
+ // recovered. If other tests have made queues in test then we want to
+ // exclude them here.
+ results = filterResultsByVirtualHost(results, "/localhost");
+
+ assertEquals("Recovered test queue not found.", 1, results.size());
+
+ String result = getLog(results.get(0));
+
+ // getSlize will return extract the vhost from vh(/test) -> '/test'
+ // so remove the '/' to get the name
+ String vhostName = AbstractTestLogSubject.getSlice("vh", result).substring(1);
+
+ // To get the store class used in the configuration we need to know
+ // the virtualhost name, found above. AND
+ // the index that the virtualhost is within the configuration.
+ // we can retrive that from the vhosts list previously extracted.
+ String fullStoreName = configuration.getConfig().getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
+
+ // Get the Simple class name from the expected class name of o.a.q.s.s.MMS
+ String storeName = fullStoreName.substring(fullStoreName.lastIndexOf(".") + 1);
+
+ assertTrue("MST-1006 does end with queue 'test-queue':" + getMessageString(result),
+ getMessageString(result).endsWith("test-queue"));
+
+ assertEquals("The store name does not match expected value",
+ storeName, AbstractTestLogSubject.getSlice("ms", fromSubject(result)));
+
+ results = _monitor.findMatches("MST-1004 : Recovery Start : test-queue");
+
+ assertEquals("MST-1004 for test-queue not found", 1, results.size());
+ }
+
+ /**
+ * Description:
+ * A persistent queue must be persisted so that on recovery it can be restored independently of any messages that may be stored on it. This test verifies that the MessageStore will log that it has recovered 0 messages for persistent queues that do not have any messages.
+ * Input:
+ *
+ * 1. Default persistent configuration
+ * 2. Persistent queue with no messages enqueued
+ * Output:
+ *
+ * <date> MST-1005 : Recovered 0 messages for queue <queue.name>
+ *
+ * Validation Steps:
+ * 3. The MST ID is correct
+ * 4. This must occur after the queue recovery start MST-1004 has been logged.
+ * 5. The count is 0
+ * 6. 'messages' is correctly printed
+ * 7. The queue.name is non-empty
+ */
+ public void testMessageStoreQueueRecoveryCountEmpty() throws Exception
+ {
+ assertLoggingNotYetOccured(MESSAGES_STORE_PREFIX);
+
+ String queueName = getTestQueueName();
+
+ startBroker();
+ Connection connetion = getConnection();
+ Session session = connetion.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Queue queue = session.createQueue("direct://amq.direct/" + queueName + "/" + queueName + "?durable='true'");
+
+ session.createConsumer(queue).close();
+
+ // Stop the broker so that we can test recovery
+ stopBroker();
+
+ int COUNT = 0;
+ testDurableRecoveryCount(COUNT, queueName);
+ }
+
+ /**
+ * Description:
+ * On recovery all the persistent messages that are stored on disk must be returned to the queue. MST-1005 will report the number of messages that have been recovered from disk.
+ * Input:
+ *
+ * 1. Default persistent configuration
+ * 2. Persistent queue with multiple messages enqueued
+ * Output:
+ *
+ * <date> MST-1005 : Recovered <count> messages for queue <queue.name>
+ *
+ * Validation Steps:
+ * 3. The MST ID is correct
+ * 4. This must occur after the queue recovery start MST-1004 has been logged.
+ * 5. The count is > 1
+ * 6. 'messages' is correctly printed
+ * 7. The queue.name is non-empty
+ */
+ public void testMessageStoreQueueRecoveryCountPlural() throws Exception
+ {
+ assertLoggingNotYetOccured(MESSAGES_STORE_PREFIX);
+
+ String queueName = getTestQueueName();
+
+ int COUNT = 10;
+
+ testDurableRecoveryCount(COUNT, queueName);
+ }
+
+ /**
+ * Send a set number of messages to a new durable queue, as specified. Then
+ * restart the broker and validate that they are restored.
+ *
+ * @param COUNT - the count to send
+ * @param queueName - the new queue name
+ * @throws Exception - if a problem occured.
+ */
+ private void testDurableRecoveryCount(int COUNT, String queueName) throws Exception
+ {
+ startBroker();
+ Connection connetion = getConnection();
+ Session session = connetion.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Queue queue = session.createQueue("direct://amq.direct/" + queueName + "/" + queueName + "?durable='true'");
+
+ session.createConsumer(queue).close();
+
+ sendMessage(session, queue, COUNT);
+ try
+ {
+ connetion.close();
+
+ stopBroker();
+
+ // Clear our monitor
+ _monitor.reset();
+
+ startBroker();
+
+ List<String> results = _monitor.findMatches(MESSAGES_STORE_PREFIX);
+
+ // Validation
+
+ assertTrue("MST messages not logged", results.size() > 0);
+
+ // Load VirtualHost list from file.
+ ServerConfiguration configuration = new ServerConfiguration(_configFile);
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
+
+ //Validate each vhost logs a creation
+ results = _monitor.findMatches("MST-1004 : Recovery Start : " + queueName);
+
+ assertEquals("Recovered test queue not found.", 1, results.size());
+
+ String result = getLog(results.get(0));
+
+ validateMessageID("MST-1004", result);
+
+ assertTrue("MST-1004 does end with queue '" + queueName + "':" + getMessageString(result),
+ getMessageString(result).endsWith(queueName));
+
+ results = _monitor.findMatches("MST-1005");
+
+ assertTrue("Insufficient MST-1005 logged.", results.size()>0);
+
+ result = null;
+
+ // If the first message is not our queue the second one will be
+ for(String resultEntry : results)
+ {
+ // Look for first match and set that to result
+ if (resultEntry.contains(queueName))
+ {
+ result = getLog(resultEntry);
+ break;
+ }
+ }
+
+ assertNotNull("MST-1005 entry for queue:" + queueName + ". Not found", result);
+
+ // getSlize will return extract the vhost from vh(/test) -> '/test'
+ // so remove the '/' to get the name
+ String vhostName = AbstractTestLogSubject.getSlice("vh", result).substring(1);
+
+ // To get the store class used in the configuration we need to know
+ // the virtualhost name, found above. AND
+ // the index that the virtualhost is within the configuration.
+ // we can retrive that from the vhosts list previously extracted.
+ String fullStoreName = configuration.getConfig().getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
+
+ // Get the Simple class name from the expected class name of o.a.q.s.s.MMS
+ String storeName = fullStoreName.substring(fullStoreName.lastIndexOf(".") + 1);
+
+ assertTrue("MST-1005 does end with queue 'test-queue':" + getMessageString(result),
+ getMessageString(result).endsWith(queueName));
+
+ assertTrue("MST-1005 does end show correct count:" + getMessageString(result),
+ getMessageString(result).contains("Recovered " + COUNT + " messages"));
+
+ assertEquals("The store name does not match expected value",
+ storeName, AbstractTestLogSubject.getSlice("ms", fromSubject(result)));
+ }
+ finally
+ {
+ //Ensure we attempt to drain the queue.
+ assertEquals("Unable to drain queue", COUNT, drainQueue(queue));
+ }
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/logging/DurableQueueLoggingTest.java b/java/systests/src/main/java/org/apache/qpid/server/logging/DurableQueueLoggingTest.java
new file mode 100644
index 0000000000..6a4292ec2e
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/logging/DurableQueueLoggingTest.java
@@ -0,0 +1,357 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.framing.AMQShortString;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.naming.NamingException;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The Queue test suite validates that the follow log messages as specified in
+ * the Functional Specification.
+ *
+ * This suite of tests validate that the Queue messages occur correctly and
+ * according to the following format:
+ *
+ * QUE-1001 : Create : [AutoDelete] [Durable|Transient] [Priority:<levels>] [Owner:<name>]
+ */
+public class DurableQueueLoggingTest extends AbstractTestLogging
+{
+
+ protected String DURABLE = "Durable";
+ protected String TRANSIENT = "Transient";
+ protected boolean _durable;
+
+ protected Connection _connection;
+ protected Session _session;
+ private static final String QUEUE_PREFIX = "QUE-";
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ //Ensure we only have logs from our test
+ _monitor.reset();
+
+ _connection = getConnection();
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ _durable = true;
+ }
+
+ /**
+ * Description:
+ * When a simple transient queue is created then a QUE-1001 create message
+ * is expected to be logged.
+ * Input:
+ * 1. Running broker
+ * 2. Persistent Queue is created from a client
+ * Output:
+ *
+ * <date> QUE-1001 : Create : Owner: '<name>' Durable
+ *
+ * Validation Steps:
+ * 3. The QUE ID is correct
+ * 4. The Durable tag is present in the message
+ * 5. The Owner is as expected
+ *
+ * @throws javax.jms.JMSException
+ * @throws javax.naming.NamingException
+ * @throws java.io.IOException
+ */
+ public void testQueueCreateDurableExclusive() throws NamingException, JMSException, IOException
+ {
+ String queueName= getTestQueueName();
+ // To force a queue Creation Event we need to create a consumer.
+ Queue queue = (Queue) _session.createQueue("direct://amq.direct/" + queueName + "/" + queueName + "?durable='" + _durable + "'&exclusive='true'");
+
+ _session.createConsumer(queue);
+
+ // Validation
+ List<String> results = _monitor.findMatches(QUEUE_PREFIX);
+
+ // Only 1 Queue message should hav been logged
+ assertEquals("Result set size not as expected", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ // Message Should be a QUE-1001
+ validateMessageID("QUE-1001", log);
+
+ // Queue is Durable
+ assertEquals(DURABLE + " keyword not correct in log entry",
+ _durable, fromMessage(log).contains(DURABLE));
+
+ assertEquals(TRANSIENT + " keyword not correct in log entry.",
+ !_durable, fromMessage(log).contains(TRANSIENT));
+
+ assertTrue("Queue does not have correct owner value:" + fromMessage(log),
+ fromMessage(log).contains("Owner: " + _connection.getClientID()));
+ }
+
+ /**
+ * Description:
+ * When a simple transient queue is created then a QUE-1001 create message
+ * is expected to be logged.
+ * Input:
+ * 1. Running broker
+ * 2. Persistent Queue is created from a client
+ * Output:
+ *
+ * <date> QUE-1001 : Create : Owner: '<name>' Durable
+ *
+ * Validation Steps:
+ * 3. The QUE ID is correct
+ * 4. The Durable tag is present in the message
+ * 5. The Owner is as expected
+ *
+ * @throws javax.jms.JMSException
+ * @throws javax.naming.NamingException
+ * @throws java.io.IOException
+ */
+ public void testQueueCreateDurable() throws NamingException, JMSException, IOException
+ {
+ String queueName = getTestQueueName();
+
+ // To force a queue Creation Event we need to create a consumer.
+ Queue queue = (Queue) _session.createQueue("direct://amq.direct/" + queueName + "/" + queueName + "?durable='" + _durable + "'");
+
+ _session.createConsumer(queue);
+
+ // Validation
+ List<String> results = _monitor.findMatches(QUEUE_PREFIX);
+
+ // Only 1 Queue message should hav been logged
+ assertEquals("Result set size not as expected", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ // Message Should be a QUE-1001
+ validateMessageID("QUE-1001", log);
+
+ // Queue is Durable
+ assertEquals(DURABLE + " keyword not correct in log entry",
+ _durable, fromMessage(log).contains(DURABLE));
+
+ assertEquals(TRANSIENT + " keyword not correct in log entry.",
+ !_durable, fromMessage(log).contains(TRANSIENT));
+
+ assertFalse("Queue should not contain Owner tag:" + fromMessage(log),
+ fromMessage(log).contains("Owner"));
+ }
+
+ /**
+ * Description:
+ * When a simple transient queue is created then a QUE-1001 create message
+ * is expected to be logged.
+ * Input:
+ * 1. Running broker
+ * 2. AutoDelete Persistent Queue is created from a client
+ * Output:
+ *
+ * <date> QUE-1001 : Create : Owner: '<name>' AutoDelete Durable
+ *
+ * Validation Steps:
+ * 3. The QUE ID is correct
+ * 4. The Durable tag is present in the message
+ * 5. The Owner is as expected
+ * 6. The AutoDelete tag is present in the message
+ *
+ * @throws javax.jms.JMSException
+ * @throws javax.naming.NamingException
+ * @throws java.io.IOException
+ */
+ public void testQueueCreatePersistentAutoDelete() throws NamingException, JMSException, IOException
+ {
+ String queueName = getTestQueueName();
+ // To force a queue Creation Event we need to create a consumer.
+ Queue queue = (Queue) _session.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='"+_durable+"'&autodelete='true'");
+
+ _session.createConsumer(queue);
+
+ // Validation
+ List<String> results = _monitor.findMatches(QUEUE_PREFIX);
+
+ // Only 1 Queue message should hav been logged
+ assertEquals("Result set size not as expected", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ // Message Should be a QUE-1001
+ validateMessageID("QUE-1001", log);
+
+ // Queue is Durable
+ assertEquals(DURABLE + " keyword not correct in log entry",
+ _durable, fromMessage(log).contains(DURABLE));
+
+ assertEquals(TRANSIENT + " keyword not correct in log entry.",
+ !_durable, fromMessage(log).contains(TRANSIENT));
+
+ // Queue is AutoDelete
+ assertTrue("Queue does not have the AutoDelete keyword in log:" + fromMessage(log),
+ fromMessage(log).contains("AutoDelete"));
+
+ assertFalse("Queue should not contain Owner tag:" + fromMessage(log),
+ fromMessage(log).contains("Owner"));
+ }
+
+ /**
+ * Description:
+ * When a simple transient queue is created then a QUE-1001 create message
+ * is expected to be logged.
+ * Input:
+ * 1. Running broker
+ * 2. Persistent Queue is created from a client
+ * Output:
+ *
+ * <date> QUE-1001 : Create : Owner: '<name>' Durable Priority:<levels>
+ *
+ * Validation Steps:
+ * 3. The QUE ID is correct
+ * 4. The Durable tag is present in the message
+ * 5. The Owner is as expected
+ * 6. The Priority level is correctly set
+ *
+ * @throws javax.jms.JMSException
+ * @throws javax.naming.NamingException
+ * @throws java.io.IOException
+ */
+ public void testCreateQueuePersistentPriority() throws NamingException, JMSException, IOException, AMQException
+ {
+ // To Create a Priority queue we need to use AMQSession specific code
+ int PRIORITIES = 6;
+ final Map<String, Object> arguments = new HashMap<String, Object>();
+ arguments.put("x-qpid-priorities", PRIORITIES);
+ // Need to create a queue that does not exist so use test name
+ final String queueName = getTestQueueName();
+ ((AMQSession) _session).createQueue(new AMQShortString(queueName), false, _durable, false, arguments);
+
+ Queue queue = (Queue) _session.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='"+_durable+"'&autodelete='false'");
+
+
+ //Need to create a Consumer to ensure that the log has had time to write
+ // as the above Create is Asynchronous
+ _session.createConsumer(queue);
+
+ // Validation
+ List<String> results = _monitor.findMatches(QUEUE_PREFIX);
+
+ // Only 1 Queue message should hav been logged
+ assertEquals("Result set size not as expected", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ // Message Should be a QUE-1001
+ validateMessageID("QUE-1001", log);
+
+ // Queue is Durable
+ assertEquals(DURABLE + " keyword not correct in log entry",
+ _durable, fromMessage(log).contains(DURABLE));
+
+ assertEquals(TRANSIENT + " keyword not correct in log entry.",
+ !_durable, fromMessage(log).contains(TRANSIENT));
+
+ // Queue is AutoDelete
+ assertTrue("Queue does not have the right Priority value keyword in log:" + fromMessage(log),
+ fromMessage(log).contains("Priority: " + PRIORITIES));
+
+ assertFalse("Queue should not contain Owner tag:" + fromMessage(log),
+ fromMessage(log).contains("Owner"));
+ }
+
+ /**
+ * Description:
+ * When a simple transient queue is created then a QUE-1001 create message
+ * is expected to be logged.
+ * Input:
+ * 1. Running broker
+ * 2. AutoDelete Persistent Queue is created from a client
+ * Output:
+ *
+ * <date> QUE-1001 : Create : Owner: '<name>' Durable Priority:<levels>
+ *
+ * Validation Steps:
+ * 3. The QUE ID is correct
+ * 4. The Durable tag is present in the message
+ * 5. The Owner is as expected
+ * 6. The AutoDelete tag is present in the message
+ * 7. The Priority level is correctly set
+ *
+ * @throws javax.jms.JMSException
+ * @throws javax.naming.NamingException
+ * @throws java.io.IOException
+ */
+ public void testCreateQueuePersistentAutoDeletePriority() throws NamingException, JMSException, IOException, AMQException
+ {
+ // To Create a Priority queue we need to use AMQSession specific code
+ int PRIORITIES = 6;
+ final Map<String, Object> arguments = new HashMap<String, Object>();
+ arguments.put("x-qpid-priorities", PRIORITIES);
+ // Need to create a queue that does not exist so use test name
+ final String queueName = getTestQueueName() + "-autoDeletePriority";
+ ((AMQSession) _session).createQueue(new AMQShortString(queueName), true, _durable, false, arguments);
+
+ Queue queue = (Queue) _session.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='"+_durable+"'&autodelete='true'");
+
+
+ //Need to create a Consumer to ensure that the log has had time to write
+ // as the above Create is Asynchronous
+ _session.createConsumer(queue);
+
+ // Validation
+ List<String> results = _monitor.findMatches(QUEUE_PREFIX);
+
+ // Only 1 Queue message should hav been logged
+ assertEquals("Result set size not as expected", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ // Message Should be a QUE-1001
+ validateMessageID("QUE-1001", log);
+
+ // Queue is Durable
+ assertEquals(DURABLE + " keyword not correct in log entry",
+ _durable, fromMessage(log).contains(DURABLE));
+
+ assertEquals(TRANSIENT + " keyword not correct in log entry.",
+ !_durable, fromMessage(log).contains(TRANSIENT));
+
+ // Queue is AutoDelete
+ assertTrue("Queue does not have the right Priority value keyword in log:" + fromMessage(log),
+ fromMessage(log).contains("Priority: " + PRIORITIES));
+
+ // Queue is AutoDelete
+ assertTrue("Queue does not have the AutoDelete keyword in log:" + fromMessage(log),
+ fromMessage(log).contains("AutoDelete"));
+
+ assertFalse("Queue should not contain Owner tag:" + fromMessage(log),
+ fromMessage(log).contains("Owner"));
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/logging/ExchangeLoggingTest.java b/java/systests/src/main/java/org/apache/qpid/server/logging/ExchangeLoggingTest.java
new file mode 100644
index 0000000000..778201e3e4
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/logging/ExchangeLoggingTest.java
@@ -0,0 +1,203 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.framing.AMQFrame;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ExchangeDeleteBody;
+import org.apache.qpid.framing.ExchangeDeleteOkBody;
+import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.Session;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Exchange
+ *
+ * The Exchange test suite validates that the follow log messages as specified in the Functional Specification.
+ *
+ * This suite of tests validate that the Exchange messages occur correctly and according to the following format:
+ *
+ * EXH-1001 : Create : [Durable] Type:<value> Name:<value>
+ * EXH-1002 : Deleted
+ */
+public class ExchangeLoggingTest extends AbstractTestLogging
+{
+
+ static final String EXH_PREFIX = "EXH-";
+
+ Connection _connection;
+ Session _session;
+ Queue _queue;
+ String _name;
+ String _type;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+
+ _connection = getConnection();
+
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _type = "direct";
+ _name = "testName";
+
+ _queue = _session.createQueue(_type + "://" + _name + "/queue/queue");
+
+ }
+
+ /**
+ * Description:
+ * When a durable exchange is created an EXH-1001 message is logged with the Durable tag. This will be the first message from this exchange.
+ * Input:
+ *
+ * 1. Running broker
+ * 2. Client requests a durable exchange be created.
+ * Output:
+ *
+ * <date> EXH-1001 : Create : Durable Type:<value> Name:<value>
+ *
+ * Validation Steps:
+ * 3. The EXH ID is correct
+ * 4. The Durable tag is present in the message
+ */
+
+ public void testExchangeCreateDurable() throws JMSException, IOException
+ {
+ // The client cannot create durable exchanges lets just look at the
+ // ones the broker creates at startup.
+
+ // They should all be durable
+
+ List<String> results = _monitor.findMatches(EXH_PREFIX);
+
+ assertTrue("No Results found for Exchange.", results.size()>0);
+
+ String log = getLog(results.get(0));
+
+ validateMessageID("EXH-1001", log);
+
+ String message = getMessageString(fromMessage(log));
+ assertTrue("Log Message does not start with create:" + message,
+ message.startsWith("Create"));
+
+ assertTrue("Log Message does not contain Durable:" + message,
+ message.contains("Durable"));
+
+ }
+
+ /**
+ * Description:
+ * When an exchange is created an EXH-1001 message is logged. This will be the first message from this exchange.
+ * Input:
+ *
+ * 1. Running broker
+ * 2. Client requests an exchange be created.
+ * Output:
+ *
+ * <date> EXH-1001 : Create : Type:<value> Name:<value>
+ *
+ * Validation Steps:
+ * 3. The EXH ID is correct
+ */
+ public void testExchangeCreate() throws JMSException, IOException
+ {
+ //Ignore broker startup messages
+ _monitor.reset();
+
+ _session.createConsumer(_queue);
+
+ List<String> results = _monitor.findMatches(EXH_PREFIX);
+
+ assertEquals("Result set larger than expected.", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ validateMessageID("EXH-1001", log);
+
+ String message = getMessageString(fromMessage(log));
+ assertTrue("Log Message does not start with create:" + message,
+ message.startsWith("Create"));
+ assertTrue("Log Message does not contain Type:" + message,
+ message.contains("Type: " + _type));
+ assertTrue("Log Message does not contain Name:" + message,
+ message.contains("Name: " + _name));
+ }
+
+ /**
+ * Description:
+ * An Exchange can be deleted through an AMQP ExchangeDelete method. When this is successful an EXH-1002 Delete message will be logged. This will be the last message from this exchange.
+ * Input:
+ *
+ * 1. Running broker
+ * 2. A new Exchange has been created
+ * 3. Client requests that the new exchange be deleted.
+ * Output:
+ *
+ * <date> EXH-1002 : Deleted
+ *
+ * Validation Steps:
+ * 4. The EXH ID is correct
+ * 5. There is a corresponding EXH-1001 Create message logged.
+ */
+ public void testExchangeDelete() throws Exception, IOException
+ {
+ //Ignore broker startup messages
+ _monitor.reset();
+
+ _session.createConsumer(_queue);
+
+ MethodRegistry_8_0 registry = new MethodRegistry_8_0();
+
+ ExchangeDeleteBody body = registry.createExchangeDeleteBody(0, new AMQShortString(_name), false, true);
+
+ AMQFrame exchangeDeclare = body.generateFrame(0);
+
+ ((AMQConnection) _connection).getProtocolHandler().syncWrite(exchangeDeclare, ExchangeDeleteOkBody.class);
+
+ List<String> results = _monitor.findMatches(EXH_PREFIX);
+
+ assertEquals("Result set larger than expected.", 2, results.size());
+
+ String log = getLog(results.get(0));
+
+ validateMessageID("EXH-1001", log);
+
+ String message = getMessageString(fromMessage(log));
+ assertTrue("Log Message does start with Create",
+ message.startsWith("Create"));
+
+ log = getLog(results.get(1));
+ validateMessageID("EXH-1002", log);
+
+ message = getMessageString(fromMessage(log));
+ assertEquals("Log Message not as expected", "Deleted", message);
+
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/logging/ManagementLoggingTest.java b/java/systests/src/main/java/org/apache/qpid/server/logging/ManagementLoggingTest.java
new file mode 100644
index 0000000000..8b7c881a32
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/logging/ManagementLoggingTest.java
@@ -0,0 +1,327 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging;
+
+import junit.framework.AssertionFailedError;
+import org.apache.qpid.util.LogMonitor;
+
+import java.util.List;
+import java.io.File;
+
+/**
+ * Management Console Test Suite
+ *
+ * The Management Console test suite validates that the follow log messages as specified in the Functional Specification.
+ *
+ * This suite of tests validate that the management console messages occur correctly and according to the following format:
+ *
+ * MNG-1001 : Startup
+ * MNG-1002 : Starting : <service> : Listening on port <Port>
+ * MNG-1003 : Shutting down : <service> : port <Port>
+ * MNG-1004 : Ready
+ * MNG-1005 : Stopped
+ * MNG-1006 : Using SSL Keystore : <path>
+ */
+public class ManagementLoggingTest extends AbstractTestLogging
+{
+ private static final String MNG_PREFIX = "MNG-";
+
+ public void setUp() throws Exception
+ {
+ // We either do this here or have a null check in tearDown.
+ // As when this test is run against profiles other than java it will NPE
+ _monitor = new LogMonitor(_outputFile);
+ //We explicitly do not call super.setUp as starting up the broker is
+ //part of the test case.
+
+ }
+
+ /**
+ * Description:
+ * Using the startup configuration validate that the management startup
+ * message is logged correctly.
+ * Input:
+ * Standard configuration with management enabled
+ * Output:
+ *
+ * <date> MNG-1001 : Startup
+ *
+ * Constraints:
+ * This is the FIRST message logged by MNG
+ * Validation Steps:
+ *
+ * 1. The BRK ID is correct
+ * 2. This is the FIRST message logged by MNG
+ */
+ public void testManagementStartupEnabled() throws Exception
+ {
+ // This test only works on external java brokers due to the fact that
+ // Management is disabled on InVM brokers.
+ if (isJavaBroker() && isExternalBroker())
+ {
+ //Ensure management is on
+ setConfigurationProperty("management.enabled", "true");
+
+ startBroker();
+
+ // Now we can create the monitor as _outputFile will now be defined
+ _monitor = new LogMonitor(_outputFile);
+
+ List<String> results = _monitor.findMatches(MNG_PREFIX);
+ try
+ {
+ // Validation
+
+ assertTrue("MNGer message not logged", results.size() > 0);
+
+ String log = getLog(results.get(0));
+
+ //1
+ validateMessageID("MNG-1001", log);
+
+ //2
+ results = _monitor.findMatches("MNG-1001");
+ assertEquals("More than one startup message found.",
+ 1, results.size());
+
+ //3
+ assertEquals("Startup log message is not 'Startup'.", "Startup",
+ getMessageString(log));
+ }
+ catch (AssertionFailedError afe)
+ {
+ System.err.println("Log Dump:");
+ for (String log : results)
+ {
+ System.err.println(log);
+ }
+ throw afe;
+ }
+ }
+ }
+
+ /**
+ * Description:
+ * Verify that when management is disabled in the configuration file the
+ * startup message is not logged.
+ * Input:
+ * Standard configuration with management disabled
+ * Output:
+ * NO MNG messages
+ * Validation Steps:
+ *
+ * 1. Validate that no MNG messages are produced.
+ */
+ public void testManagementStartupDisabled() throws Exception
+ {
+ // This test only works on external java brokers due to the fact that
+ // Management is disabled on InVM brokers.
+ if (isJavaBroker() && isExternalBroker())
+ {
+ //Ensure management is off
+ setConfigurationProperty("management.enabled", "false");
+
+ startBroker();
+
+ // Now we can create the monitor as _outputFile will now be defined
+ _monitor = new LogMonitor(_outputFile);
+
+ List<String> results = _monitor.findMatches(MNG_PREFIX);
+ try
+ {
+ // Validation
+
+ assertEquals("MNGer messages logged", 0, results.size());
+ }
+ catch (AssertionFailedError afe)
+ {
+ System.err.println("Log Dump:");
+ for (String log : results)
+ {
+ System.err.println(log);
+ }
+ throw afe;
+ }
+ }
+ }
+
+ /**
+ * The two MNG-1002 messages are logged at the same time so lets test them
+ * at the same time.
+ *
+ * Description:
+ * Using the default configuration validate that the RMI Registry socket is
+ * correctly reported as being opened
+ *
+ * Input:
+ * The default configuration file
+ * Output:
+ *
+ * <date> MESSAGE MNG-1002 : Starting : RMI Registry : Listening on port 8999
+ *
+ * Constraints:
+ * The RMI ConnectorServer and Registry log messages do not have a prescribed order
+ * Validation Steps:
+ *
+ * 1. The MNG ID is correct
+ * 2. The specified port is the correct '8999'
+ *
+ * Description:
+ * Using the default configuration validate that the RMI ConnectorServer
+ * socket is correctly reported as being opened
+ *
+ * Input:
+ * The default configuration file
+ * Output:
+ *
+ * <date> MESSAGE MNG-1002 : Starting : RMI ConnectorServer : Listening on port 9099
+ *
+ * Constraints:
+ * The RMI ConnectorServer and Registry log messages do not have a prescribed order
+ * Validation Steps:
+ *
+ * 1. The MNG ID is correct
+ * 2. The specified port is the correct '9099'
+ */
+ public void testManagementStartupRMIEntries() throws Exception
+ {
+ // This test only works on external java brokers due to the fact that
+ // Management is disabled on InVM brokers.
+ if (isJavaBroker() && isExternalBroker())
+ {
+ //Ensure management is on
+ setConfigurationProperty("management.enabled", "true");
+
+ startBroker();
+
+ // Now we can create the monitor as _outputFile will now be defined
+ _monitor = new LogMonitor(_outputFile);
+
+ List<String> results = _monitor.findMatches("MNG-1002");
+ try
+ {
+ // Validation
+
+ assertEquals("MNGer message not logged expected message", 2, results.size());
+
+ String log = getLog(results.get(0));
+
+ //1
+ validateMessageID("MNG-1002", log);
+
+ // Validate we only have one MNG-1002
+ results = _monitor.findMatches("MNG-1002");
+ assertEquals("More than two RMI entries found.",
+ 2, results.size());
+
+ // We expect the RMI Server port to be 100 higher than
+ // the RMIConnector Server Port
+ int mPort = getPort() + (DEFAULT_MANAGEMENT_PORT - DEFAULT_PORT);
+ assertTrue("RMI Registry port not as expected(" + mPort + ").:" + getMessageString(log),
+ getMessageString(log).endsWith(String.valueOf(mPort)));
+
+ log = getLog(results.get(1));
+
+ //1
+ validateMessageID("MNG-1002", log);
+
+ // We expect the RMIConnector Server port to be 100 higher than
+ // the RMI Server Port
+ mPort = getPort() + (DEFAULT_MANAGEMENT_PORT - DEFAULT_PORT) + 100;
+ assertTrue("RMI ConnectorServer port not as expected(" + mPort + ").:" + getMessageString(log),
+ getMessageString(log).endsWith(String.valueOf(mPort)));
+ }
+ catch (AssertionFailedError afe)
+ {
+ System.err.println("Log Dump:");
+ for (String log : results)
+ {
+ System.err.println(log);
+ }
+ throw afe;
+ }
+ }
+ }
+ /**
+ * Description:
+ * Using the default configuration with SSL enabled for the management port the SSL Keystore path should be reported via MNG-1006
+ * Input:
+ * Management SSL enabled default configuration.
+ * Output:
+ *
+ * <date> MESSAGE MNG-1006 : Using SSL Keystore : test_resources/ssl/keystore.jks
+ *
+ * Validation Steps:
+ *
+ * 1. The MNG ID is correct
+ * 2. The keystore path is as specified in the configuration
+ */
+ public void testManagementStartupSSLKeystore() throws Exception
+ {
+ // This test only works on external java brokers due to the fact that
+ // Management is disabled on InVM brokers.
+ if (isJavaBroker() && isExternalBroker())
+ {
+ //Ensure management is on
+ setConfigurationProperty("management.enabled", "true");
+ // This test requires we have an ssl connection
+ setConfigurationProperty("management.ssl.enabled", "true");
+
+ startBroker();
+
+ // Now we can create the monitor as _outputFile will now be defined
+ _monitor = new LogMonitor(_outputFile);
+
+ List<String> results = _monitor.findMatches("MNG-1006");
+ try
+ {
+ // Validation
+
+ assertTrue("MNGer message not logged", results.size() > 0);
+
+ String log = getLog(results.get(0));
+
+ //1
+ validateMessageID("MNG-1006", log);
+
+ // Validate we only have one MNG-1002
+ results = _monitor.findMatches("MNG-1006");
+ assertEquals("More than one SSL Keystore entry found.",
+ 1, results.size());
+
+ // We expect the RMIConnector Server port to be 100 higher than
+ // the RMI Server Port
+ assertTrue("SSL Keystore entry expected.:" + getMessageString(log),
+ getMessageString(log).endsWith(new File(getConfigurationStringProperty("management.ssl.keyStorePath")).getName()));
+ }
+ catch (AssertionFailedError afe)
+ {
+ System.err.println("Log Dump:");
+ for (String log : results)
+ {
+ System.err.println(log);
+ }
+ throw afe;
+ }
+ }
+
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/logging/MemoryMessageStoreLoggingTest.java b/java/systests/src/main/java/org/apache/qpid/server/logging/MemoryMessageStoreLoggingTest.java
new file mode 100644
index 0000000000..2298ba4da0
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/logging/MemoryMessageStoreLoggingTest.java
@@ -0,0 +1,192 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+package org.apache.qpid.server.logging;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.logging.subjects.AbstractTestLogSubject;
+import org.apache.qpid.util.LogMonitor;
+
+import java.util.List;
+
+/**
+ * The MessageStore test suite validates that the follow log messages as
+ * specified in the Functional Specification.
+ *
+ * This suite of tests validate that the MessageStore messages occur correctly
+ * and according to the following format:
+ *
+ * MST-1001 : Created : <name>
+ * MST-1003 : Closed
+ *
+ * NOTE: Only for Persistent Stores
+ * MST-1002 : Store location : <path>
+ * MST-1004 : Recovery Start [: <queue.name>]
+ * MST-1005 : Recovered <count> messages for queue <queue.name>
+ * MST-1006 : Recovery Complete [: <queue.name>]
+ */
+public class MemoryMessageStoreLoggingTest extends AbstractTestLogging
+{
+ protected static final String MESSAGES_STORE_PREFIX = "MST-";
+
+ public void setUp() throws Exception
+ {
+ //We explicitly do not call super.setUp as starting up the broker is
+ //part of the test case.
+ // So we have to make the new Log Monitor here
+
+ _monitor = new LogMonitor(_outputFile);
+ }
+
+ /**
+ * Description:
+ * During Virtualhost startup a MessageStore will be created. The first MST
+ * message that must be logged is the MST-1001 MessageStore creation.
+ * Input:
+ * Default configuration
+ * Output:
+ * <date> MST-1001 : Created : <name>
+ *
+ * Validation Steps:
+ *
+ * 1. The MST ID is correct
+ * 2. The <name> is the correct MessageStore type as specified in the Default configuration
+ *
+ * @throws Exception caused by broker startup
+ */
+ public void testMessageStoreCreation() throws Exception
+ {
+ assertLoggingNotYetOccured(MESSAGES_STORE_PREFIX);
+
+ startBroker();
+
+ List<String> results = _monitor.findMatches(MESSAGES_STORE_PREFIX);
+
+ // Validation
+
+ assertTrue("MST messages not logged", results.size() > 0);
+
+ String log = getLog(results.get(0));
+ //1
+ assertEquals("MST-1001 is not the first MST message", "MST-1001", getMessageID(fromMessage(log)));
+
+ // Load VirtualHost list from file.
+ ServerConfiguration configuration = new ServerConfiguration(_configFile);
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
+
+ //Validate each vhost logs a creation
+ results = _monitor.findMatches("MST-1001");
+
+ assertEquals("Each vhost did not create a store.", vhosts.size(), results.size());
+
+ for (int index = 0; index < results.size(); index++)
+ {
+ String result = getLog(results.get(index));
+
+ // getSlize will return extract the vhost from vh(/test) -> '/test'
+ // so remove the '/' to get the name
+ String vhostName = AbstractTestLogSubject.getSlice("vh", result).substring(1);
+
+ // To get the store class used in the configuration we need to know
+ // the virtualhost name, found above. AND
+ // the index that the virtualhost is within the configuration.
+ // we can retrive that from the vhosts list previously extracted.
+ String fullStoreName = configuration.getConfig().getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
+
+ // Get the Simple class name from the expected class name of o.a.q.s.s.MMS
+ String storeName = fullStoreName.substring(fullStoreName.lastIndexOf(".") + 1);
+
+ assertTrue("MST-1001 does not contains correct store name:"
+ + storeName + ":" + result, getMessageString(result).endsWith(storeName));
+
+ assertEquals("The store name does not match expected value",
+ storeName, AbstractTestLogSubject.getSlice("ms", fromSubject(result)));
+ }
+ }
+
+ /**
+ * Description:
+ * During shutdown the MessageStore will also cleanly close. When this has
+ * completed a MST-1003 closed message will be logged. No further messages
+ * from this MessageStore will be logged after this message.
+ *
+ * Input:
+ * Default configuration
+ * Output:
+ * <date> MST-1003 : Closed
+ *
+ * Validation Steps:
+ *
+ * 1. The MST ID is correct
+ * 2. This is teh last log message from this MessageStore
+ *
+ * @throws Exception caused by broker startup
+ */
+ public void testMessageStoreClose() throws Exception
+ {
+ assertLoggingNotYetOccured(MESSAGES_STORE_PREFIX);
+
+ startBroker();
+
+ //Stop the broker so we get the close messages.
+ stopBroker();
+
+ List<String> results = _monitor.findMatches(MESSAGES_STORE_PREFIX);
+
+ // Validation
+
+ assertTrue("MST messages not logged", results.size() > 0);
+
+ // Load VirtualHost list from file.
+ ServerConfiguration configuration = new ServerConfiguration(_configFile);
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
+
+ //Validate each vhost logs a creation
+ results = _monitor.findMatches("MST-1003");
+
+ assertEquals("Each vhost did not close its store.", vhosts.size(), results.size());
+
+ for (int index = 0; index < results.size(); index++)
+ {
+ String result = getLog(results.get(index));
+
+ // getSlize will return extract the vhost from vh(/test) -> '/test'
+ // so remove the '/' to get the name
+ String vhostName = AbstractTestLogSubject.getSlice("vh", result).substring(1);
+
+ // To get the store class used in the configuration we need to know
+ // the virtualhost name, found above. AND
+ // the index that the virtualhost is within the configuration.
+ // we can retrive that from the vhosts list previously extracted.
+ String fullStoreName = configuration.getConfig().getString("virtualhosts.virtualhost(" + vhosts.indexOf(vhostName) + ")." + vhostName + ".store.class");
+
+ // Get the Simple class name from the expected class name of o.a.q.s.s.MMS
+ String storeName = fullStoreName.substring(fullStoreName.lastIndexOf(".") + 1);
+
+ assertEquals("MST-1003 does not close:",
+ "Closed", getMessageString(result));
+
+ assertEquals("The store name does not match expected value",
+ storeName, AbstractTestLogSubject.getSlice("ms", fromSubject(result)));
+ }
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/logging/QueueLoggingTest.java b/java/systests/src/main/java/org/apache/qpid/server/logging/QueueLoggingTest.java
new file mode 100644
index 0000000000..150f462d0f
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/logging/QueueLoggingTest.java
@@ -0,0 +1,171 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging;
+
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.failover.FailoverException;
+import org.apache.qpid.server.logging.subjects.AbstractTestLogSubject;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.AMQException;
+
+import javax.jms.Connection;
+import javax.jms.Session;
+import javax.jms.Queue;
+import javax.jms.JMSException;
+import javax.naming.NamingException;
+import java.util.List;
+import java.io.IOException;
+
+/**
+ * The Queue test suite validates that the follow log messages as specified in
+ * the Functional Specification.
+ *
+ * This suite of tests validate that the Queue messages occur correctly and
+ * according to the following format:
+ *
+ * QUE-1002 : Deleted
+ */
+public class QueueLoggingTest extends AbstractTestLogging
+{
+ protected Connection _connection;
+ protected Session _session;
+ private static final String QUEUE_PREFIX = "QUE-";
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ //Remove broker startup logging messages
+ _monitor.reset();
+
+ _connection = getConnection();
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ }
+
+ /**
+ * Description:
+ * An explict QueueDelete request must result in a QUE-1002 Deleted message
+ * being logged. This can be done via an explict AMQP QueueDelete method.
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Queue created on the broker with no subscribers
+ * 3. Client requests the queue be deleted via a QueueDelete
+ * Output:
+ *
+ * <date> QUE-1002 : Deleted
+ *
+ * Validation Steps:
+ *
+ * 4. The QUE ID is correct
+ *
+ * @throws java.io.IOException
+ * @throws javax.jms.JMSException
+ * @throws javax.naming.NamingException
+ */
+ public void testQueueDelete() throws NamingException, JMSException, IOException, FailoverException, AMQException
+ {
+ // To force a queue Creation Event we need to create a consumer.
+ Queue queue = _session.createQueue(getTestQueueName());
+
+ _session.createConsumer(queue);
+
+ // Delete Queue
+ ((AMQSession)_session).sendQueueDelete(new AMQShortString(queue.getQueueName()));
+
+ //Perform a synchronous action to ensure that the above log will be on disk
+ _session.close();
+
+ // Validation
+ List<String> results = _monitor.findMatches(QUEUE_PREFIX);
+
+ // Only 1 Queue message should hav been logged
+ assertEquals("Result set size not as expected", 2, results.size());
+
+ String log = getLog(results.get(0));
+
+ // Message Should be a QUE-1001
+ validateMessageID("QUE-1001", log);
+
+ String createdQueueName = AbstractTestLogSubject.getSlice("qu", fromSubject(log));
+
+ log = getLog(results.get(1));
+ // Message Should be a QUE-1002
+ validateMessageID("QUE-1002", log);
+
+ assertEquals("Log Message is incorrect ", "Deleted", getMessageString(fromMessage(log)));
+
+ assertEquals("Queue Delete not for created queue:", createdQueueName,
+ AbstractTestLogSubject.getSlice("qu", fromSubject(log)));
+ }
+
+
+ /**
+ * Description:
+ * An explict QueueDelete request must result in a QUE-1002 Deleted message
+ * being logged. This can be done via an explict AMQP QueueDelete method.
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Queue created on the broker with no subscribers
+ * 3. Client creates a temporary queue then disconnects
+ * Output:
+ *
+ * <date> QUE-1002 : Deleted
+ *
+ * Validation Steps:
+ *
+ * 4. The QUE ID is correct
+ *
+ * @throws java.io.IOException
+ * @throws javax.jms.JMSException
+ * @throws javax.naming.NamingException
+ */
+ public void testQueueAutoDelete() throws NamingException, JMSException, IOException
+ {
+ // Create a temporary queue so that when we consume from it and
+ // then close the consumer it will be autoDeleted.
+ _session.createConsumer(_session.createTemporaryQueue()).close();
+
+ // Validation
+ List<String> results = _monitor.findMatches(QUEUE_PREFIX);
+
+ // Only 1 Queue message should hav been logged
+ assertEquals("Result set size not as expected", 2, results.size());
+
+ String log = getLog(results.get(0));
+
+ // Message Should be a QUE-1001
+ validateMessageID("QUE-1001", log);
+
+ String createdQueueName = AbstractTestLogSubject.getSlice("qu", fromSubject(log));
+
+ log = getLog(results.get(1));
+ // Message Should be a QUE-1002
+ validateMessageID("QUE-1002", log);
+
+ assertEquals("Log Message is incorrect ", "Deleted", getMessageString(fromMessage(log)));
+
+ assertEquals("Queue Delete not for created queue:", createdQueueName,
+ AbstractTestLogSubject.getSlice("qu", fromSubject(log)));
+
+ }
+
+} \ No newline at end of file
diff --git a/java/systests/src/main/java/org/apache/qpid/server/logging/SubscriptionLoggingTest.java b/java/systests/src/main/java/org/apache/qpid/server/logging/SubscriptionLoggingTest.java
new file mode 100644
index 0000000000..5dd56fb0f9
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/logging/SubscriptionLoggingTest.java
@@ -0,0 +1,438 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging;
+
+import junit.framework.AssertionFailedError;
+import org.apache.qpid.client.AMQConnection;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.MessageConsumer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.jms.Message;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Subscription
+ *
+ * The Subscription test suite validates that the follow log messages as specified in the Functional Specification.
+ *
+ * This suite of tests validate that the Subscription messages occur correctly and according to the following format:
+ *
+ * SUB-1001 : Create : [Durable] [Arguments : <key=value>]
+ * SUB-1002 : Close
+ * SUB-1003 : State : <state>
+ */
+public class SubscriptionLoggingTest extends AbstractTestLogging
+{
+ static final String SUB_PREFIX = "SUB-";
+
+ Connection _connection;
+ Session _session;
+ Queue _queue;
+ Topic _topic;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ //Remove broker startup logging messages
+ _monitor.reset();
+
+ _connection = getConnection();
+
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _queue = (Queue) getInitialContext().lookup(QUEUE);
+ _topic = (Topic) getInitialContext().lookup(TOPIC);
+ }
+
+ /**
+ * Description:
+ * When a Subscription is created it will be logged. This test validates that Subscribing to a transient queue is correctly logged.
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Create a new Subscription to a transient queue/topic.
+ * Output: 6
+ *
+ * <date> SUB-1001 : Create
+ *
+ * Validation Steps:
+ * 3. The SUB ID is correct
+ *
+ * @throws java.io.IOException - if there is a problem getting the matches
+ * @throws javax.jms.JMSException - if there is a problem creating the consumer
+ */
+ public void testSubscriptionCreate() throws JMSException, IOException
+ {
+ _session.createConsumer(_queue);
+
+ //Validate
+
+ List<String> results = _monitor.findMatches(SUB_PREFIX);
+
+ assertEquals("Result set larger than expected.", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ validateMessageID("SUB-1001", log);
+
+ assertEquals("Log Message not as expected", "Create", getMessageString(fromMessage(log)));
+ }
+
+ /**
+ * Description:
+ * The creation of a Durable Subscription, such as a JMS DurableTopicSubscriber will result in an extra Durable tag being included in the Create log message
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Creation of a JMS DurableTopicSubiber
+ * Output:
+ *
+ * <date> SUB-1001 : Create : Durable
+ *
+ * Validation Steps:
+ * 3. The SUB ID is correct
+ * 4. The Durable tag is present in the message
+ * NOTE: A Subscription is not Durable, the queue it consumes from is.
+ *
+ * @throws java.io.IOException - if there is a problem getting the matches
+ * @throws javax.jms.JMSException - if there is a problem creating the consumer
+ */
+ public void testSubscriptionCreateDurable() throws JMSException, IOException
+ {
+ _session.createDurableSubscriber(_topic, getName());
+
+ //Validate
+
+ List<String> results = _monitor.findMatches(SUB_PREFIX);
+
+ assertEquals("Result set larger than expected.", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ validateMessageID("SUB-1001", log);
+
+ String message = getMessageString(fromMessage(log));
+ assertTrue("Durable not on log message:" + message, message.contains("Durable"));
+ }
+
+ /**
+ * Description:
+ * The creation of a QueueBrowser will provides a number arguments and so should form part of the SUB-1001 Create message.
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Java Client creates a QueueBroweser
+ * Output:
+ *
+ * <date> SUB-1001 : Create : Arguments : <key=value>
+ *
+ * Validation Steps:
+ * 3. The SUB ID is correct
+ * 4. The Arguments are present in the message
+ * 5. Arguments keys include AutoClose and Browser.
+ *
+ * @throws java.io.IOException - if there is a problem getting the matches
+ * @throws javax.jms.JMSException - if there is a problem creating the consumer
+ */
+ public void testSubscriptionCreateQueueBrowser() throws JMSException, IOException
+ {
+ _session.createBrowser(_queue);
+
+ //Validate
+ List<String> results = _monitor.findMatches(SUB_PREFIX);
+
+ assertEquals("Result set larger than expected.", 2, results.size());
+
+ String log = getLog(results.get(0));
+
+ validateMessageID("SUB-1001", log);
+
+ String message = getMessageString(fromMessage(log));
+ assertTrue("Browser not on log message:" + message, message.contains("Browser"));
+ assertTrue("AutoClose not on log message:" + message, message.contains("AutoClose"));
+
+ // Beacause it is an auto close and we have no messages on the queue we
+ // will get a close message
+ log = getLog(results.get(1));
+ validateMessageID("SUB-1002", log);
+
+ }
+
+ /**
+ * Description:
+ * The creation of a Subscriber with a JMS Selector will result in the Argument field being populated. These argument key/value pairs are then shown in the log message.
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Subscriber created with a JMS Selector.
+ * Output:
+ *
+ * <date> SUB-1001 : Create : Arguments : <key=value>
+ *
+ * Validation Steps:
+ * 3. The SUB ID is correct
+ * 4. Argument tag is present in the message
+ *
+ * @throws java.io.IOException - if there is a problem getting the matches
+ * @throws javax.jms.JMSException - if there is a problem creating the consumer
+ */
+ public void testSubscriptionCreateWithArguments() throws JMSException, IOException
+ {
+ final String SELECTOR = "Selector='True'";
+ _session.createConsumer(_queue, SELECTOR);
+
+ //Validate
+
+ List<String> results = _monitor.findMatches(SUB_PREFIX);
+
+ assertEquals("Result set larger than expected.", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ validateMessageID("SUB-1001", log);
+
+ String message = getMessageString(fromMessage(log));
+ assertTrue("Selector not on log message:" + message, message.contains(SELECTOR));
+ }
+
+ /**
+ * Description:
+ * The final combination of SUB-1001 Create messages involves the creation of a Durable Subscription that also contains a set of Arguments, such as those provided via a JMS Selector.
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Java Client creates a Durable Subscription with Selector
+ * Output:
+ *
+ * <date> SUB-1001 : Create : Durable Arguments : <key=value>
+ *
+ * Validation Steps:
+ * 3. The SUB ID is correct
+ * 4. The tag Durable is present in the message
+ * 5. The Arguments are present in the message
+ *
+ * @throws java.io.IOException - if there is a problem getting the matches
+ * @throws javax.jms.JMSException - if there is a problem creating the consumer
+ */
+ public void testSubscriptionCreateDurableWithArguments() throws JMSException, IOException
+ {
+ final String SELECTOR = "Selector='True'";
+ _session.createDurableSubscriber(_topic, getName(), SELECTOR, false);
+
+ //Validate
+
+ List<String> results = _monitor.findMatches(SUB_PREFIX);
+
+ assertEquals("Result set larger than expected.", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ validateMessageID("SUB-1001", log);
+
+ String message = getMessageString(fromMessage(log));
+ assertTrue("Durable not on log message:" + message, message.contains("Durable"));
+ assertTrue("Selector not on log message:" + message, message.contains(SELECTOR));
+ }
+
+ /**
+ * Description:
+ * When a Subscription is closed it will log this so that it can be correlated with the Create.
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Client with a subscription.
+ * 3. The subscription is then closed.
+ * Output:
+ *
+ * <date> SUB-1002 : Close
+ *
+ * Validation Steps:
+ * 1. The SUB ID is correct
+ * 2. There must be a SUB-1001 Create message preceding this message
+ * 3. This must be the last message from the given Subscription
+ *
+ * @throws java.io.IOException - if there is a problem getting the matches
+ * @throws javax.jms.JMSException - if there is a problem creating the consumer
+ */
+ public void testSubscriptionClose() throws JMSException, IOException
+ {
+ _session.createConsumer(_queue).close();
+
+ //Validate
+ List<String> results = _monitor.findMatches(SUB_PREFIX);
+
+ //3
+ assertEquals("Result set larger than expected.", 2, results.size());
+
+ // 2
+ String log = getLog(results.get(0));
+ validateMessageID("SUB-1001", log);
+ // 1
+ log = getLog(results.get(1));
+ validateMessageID("SUB-1002", log);
+
+ String message = getMessageString(fromMessage(log));
+ assertEquals("Log message is not close", "Close", message);
+
+ }
+
+ /**
+ * Description:
+ * When a Subscription fills its prefetch it will become suspended. This
+ * will be logged as a SUB-1003 message.
+ * Input:
+ *
+ * 1. Running broker
+ * 2. Message Producer to put more data on the queue than the client's prefetch
+ * 3. Client that ensures that its prefetch becomes full
+ * Output:
+ *
+ * <date> SUB-1003 : State : <state>
+ *
+ * Validation Steps:
+ * 1. The SUB ID is correct
+ * 2. The state is correct
+ *
+ * @throws java.io.IOException - if there is a problem getting the matches
+ * @throws javax.jms.JMSException - if there is a problem creating the consumer
+ */
+ public void testSubscriptionSuspend() throws Exception, IOException
+ {
+ //Close session with large prefetch
+ _connection.createSession(false, Session.AUTO_ACKNOWLEDGE).close();
+
+ int PREFETCH = 15;
+
+ //Create new session with small prefetch
+ _session = ((AMQConnection) _connection).createSession(true, Session.SESSION_TRANSACTED, PREFETCH);
+
+ MessageConsumer consumer = _session.createConsumer(_queue);
+
+ _connection.start();
+
+ //Start the dispatcher & Unflow the channel.
+ consumer.receiveNoWait();
+
+ //Fill the prefetch and two extra so that our receive bellow allows the
+ // subscription to become active
+ // Previously we set this to 17 so that it would return to a suspended
+ // state. However, testing has shown that the state change can occur
+ // sufficiently quickly that logging does not occur consistently enough
+ // for testing.
+ int SEND_COUNT = 16;
+ sendMessage(_session, _queue, SEND_COUNT);
+ _session.commit();
+ // Retreive the first message, and start the flow of messages
+ Message msg = consumer.receive(1000);
+ assertNotNull("First message not retreived", msg);
+ _session.commit();
+
+ // Drain the queue to ensure there is time for the ACTIVE log message
+ // Check that we can received all the messages
+ int receivedCount = 0;
+ while (msg != null)
+ {
+ receivedCount++;
+ msg = consumer.receive(1000);
+ _session.commit();
+ }
+
+ //Validate we received all the messages
+ assertEquals("Not all sent messages received.", SEND_COUNT, receivedCount);
+
+ // Fill the queue again to suspend the consumer
+ sendMessage(_session, _queue, SEND_COUNT);
+ _session.commit();
+
+ //Validate
+ List<String> results = _monitor.findMatches("SUB-1003");
+
+ try
+ {
+ // Validation expects three messages.
+ // The Actor can be any one of the following depending on the exactly what is going on on the broker.
+ // Ideally we would test that we can get all of them but setting up
+ // the timing to do this in a consistent way is not benefitial.
+ // Ensuring the State is as expected is sufficient.
+// INFO - MESSAGE [vh(/test)/qu(example.queue)] [sub:6(qu(example.queue))] SUB-1003 : State :
+// INFO - MESSAGE [con:6(guest@anonymous(26562441)/test)/ch:3] [sub:6(qu(example.queue))] SUB-1003 : State :
+// INFO - MESSAGE [sub:6(vh(test)/qu(example.queue))] [sub:6(qu(example.queue))] SUB-1003 : State :
+
+ assertEquals("Result set not expected size:", 3, results.size());
+
+ // Validate Initial Suspension
+ String expectedState = "SUSPENDED";
+ String log = getLog(results.get(0));
+ validateSubscriptionState(log, expectedState);
+
+ // After being suspended the subscription should become active.
+ expectedState = "ACTIVE";
+ log = getLog(results.get(1));
+ validateSubscriptionState(log, expectedState);
+
+ // Validate that it was re-suspended
+ expectedState = "SUSPENDED";
+ log = getLog(results.get(2));
+ validateSubscriptionState(log, expectedState);
+ // We only need validate the state.
+ }
+ catch (AssertionFailedError afe)
+ {
+ System.err.println("Log Dump:");
+ for (String log : results)
+ {
+ System.err.println(log);
+ }
+ throw afe;
+ }
+ _connection.close();
+
+ //Ensure the queue is drained before the test ends
+ drainQueue(_queue);
+
+ }
+
+ /**
+ * Validate that the given log statement is a well formatted SUB-1003
+ * message. That means the ID and expected state are correct.
+ *
+ * @param log the log to test
+ * @param expectedState the state that should be logged.
+ */
+ private void validateSubscriptionState(String log, String expectedState)
+ {
+ validateMessageID("SUB-1003", log);
+ String logMessage = getMessageString(fromMessage(log));
+ assertTrue("Log Message does not start with 'State'" + logMessage,
+ logMessage.startsWith("State"));
+
+ assertTrue("Log Message does not have expected State of '"
+ + expectedState + "'" + logMessage,
+ logMessage.endsWith(expectedState));
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/logging/TransientQueueLoggingTest.java b/java/systests/src/main/java/org/apache/qpid/server/logging/TransientQueueLoggingTest.java
new file mode 100644
index 0000000000..29f74c5818
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/logging/TransientQueueLoggingTest.java
@@ -0,0 +1,30 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.logging;
+
+public class TransientQueueLoggingTest extends DurableQueueLoggingTest
+{
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _durable = false;
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java b/java/systests/src/main/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java
new file mode 100644
index 0000000000..f4a0c8b27d
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+
+package org.apache.qpid.server.logging;
+
+import junit.framework.AssertionFailedError;
+import org.apache.commons.configuration.Configuration;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+
+import java.util.List;
+
+/**
+ * Virtualhost Test Cases
+ * The virtualhost test suite validates that the follow log messages as specified in the Functional Specification.
+ * <p/>
+ * This suite of tests validate that the management console messages occur correctly and according to the following format:
+ * <p/>
+ * VHT-1001 : Created : <name>
+ * VHT-1002 : Work directory : <path>
+ * VHT-1003 : Closed
+ */
+public class VirtualHostLoggingTest extends AbstractTestLogging
+{
+ private static final String VHT_PREFIX = "VHT-";
+
+ /**
+ * Description:
+ * Testing can be performed using the default configuration. The goal is to validate that for each virtualhost defined in the configuration file a VHT-1001 Created message is provided.
+ * Input:
+ * The default configuration file
+ * Output:
+ * <p/>
+ * <date> VHT-1001 : Created : <name>
+ * Validation Steps:
+ * <p/>
+ * The VHT ID is correct
+ * A VHT-1001 is printed for each virtualhost defined in the configuration file.
+ * This must be the first message for the specified virtualhost.
+ *
+ * @throws Exception caused by broker startup
+ */
+ public void testVirtualhostCreation() throws Exception
+ {
+
+ List<String> results = _monitor.findMatches(VHT_PREFIX);
+ try
+ {
+ // Validation
+ ServerConfiguration configuration = new ServerConfiguration(_configFile);
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
+
+ //Validate each vhost logs a creation
+ results = _monitor.findMatches("VHT-1001");
+
+ assertEquals("Each vhost did not create a store.", vhosts.size(), results.size());
+
+ for (int index = 0; index < results.size(); index++)
+ {
+ String result = getLog(results.get(index));
+
+ // Retrieve the vhostname from the log entry message 'Created : <vhostname>'
+ String vhostName = getMessageString(fromMessage(result)).split(" ")[2];
+
+ assertTrue("Virualhost named in log not found in config file:" + vhostName + ":" + vhosts, vhosts.contains(vhostName));
+ }
+ }
+ catch (AssertionFailedError afe)
+ {
+ System.err.println("Log Dump:");
+ for (String log : results)
+ {
+ System.err.println(log);
+ }
+ throw afe;
+ }
+ }
+
+ /**
+ * Description:
+ * Testing can be performed using the default configuration. During broker shutdown a VHT-1002 Closed message will be printed for each of the configured virtualhosts. For every virtualhost that was started a close must be logged. After the close message has been printed no further logging will be performed by this virtualhost.
+ * Input:
+ * The default configuration file
+ * Output:
+ * <p/>
+ * <date> VHT-1002 : Closed
+ * Validation Steps:
+ * <p/>
+ * The VHT ID is correct
+ * This is the last VHT message for the given virtualhost.
+ *
+ * @throws Exception caused by broker startup
+ */
+ public void testVirtualhostClosure() throws Exception
+ {
+ stopBroker();
+
+ List<String> results = _monitor.findMatches(VHT_PREFIX);
+ try
+ {
+ // Validation
+
+ ServerConfiguration configuration = new ServerConfiguration(_configFile);
+ List<String> vhosts = configuration.getConfig().getList("virtualhosts.virtualhost.name");
+
+ //Validate each vhost logs a creation
+ results = _monitor.findMatches("VHT-1002");
+
+ assertEquals("Each vhost did not create a store.", vhosts.size(), results.size());
+ }
+ catch (AssertionFailedError afe)
+ {
+ System.err.println("Log Dump:");
+ for (String log : results)
+ {
+ System.err.println(log);
+ }
+ throw afe;
+ }
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/persistent/NoLocalAfterRecoveryTest.java b/java/systests/src/main/java/org/apache/qpid/server/persistent/NoLocalAfterRecoveryTest.java
new file mode 100644
index 0000000000..dc34915a91
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/persistent/NoLocalAfterRecoveryTest.java
@@ -0,0 +1,246 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.persistent;
+
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.jms.ConnectionListener;
+import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.jms.ConnectionURL;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry;
+import org.apache.qpid.server.store.DerbyMessageStore;
+import org.apache.commons.configuration.XMLConfiguration;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.jms.TopicSubscriber;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import java.util.concurrent.CountDownLatch;
+import java.io.File;
+
+/**
+ * QPID-1813 : We do not store the client id with a message so on store restart
+ * that information is lost and we are unable to perform no local checks.
+ *
+ * QPID-1813 highlights the lack of testing here as the broker will NPE as it
+ * assumes that the client id of the publisher will always exist
+ */
+public class NoLocalAfterRecoveryTest extends QpidTestCase implements ConnectionListener
+{
+ protected final String MY_TOPIC_SUBSCRIPTION_NAME = this.getName();
+ protected static final int SEND_COUNT = 10;
+ private CountDownLatch _failoverComplete = new CountDownLatch(1);
+
+ protected ConnectionURL _connectionURL;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+
+ XMLConfiguration configuration = new XMLConfiguration(_configFile);
+ configuration.setProperty("virtualhosts.virtualhost.test.store.class", "org.apache.qpid.server.store.DerbyMessageStore");
+ configuration.setProperty("virtualhosts.virtualhost.test.store."+ DerbyMessageStore.ENVIRONMENT_PATH_PROPERTY,
+ System.getProperty("QPID_WORK", System.getProperty("java.io.tmpdir")) + File.separator + "derbyDB-NoLocalAfterRecoveryTest");
+
+ File tmpFile = File.createTempFile("configFile", "test");
+ tmpFile.deleteOnExit();
+ configuration.save(tmpFile);
+
+ _configFile = tmpFile;
+ _connectionURL = getConnectionURL();
+
+ BrokerDetails details = _connectionURL.getBrokerDetails(0);
+
+ // Due to the problem with SingleServer delaying on all connection
+ // attempts. So using a high retry value.
+ if (_broker.equals(VM))
+ {
+ // Local testing suggests InVM restart takes under a second
+ details.setProperty(BrokerDetails.OPTIONS_RETRY, "5");
+ details.setProperty(BrokerDetails.OPTIONS_CONNECT_DELAY, "200");
+ }
+ else
+ {
+ // This will attempt to failover for 3 seconds.
+ // Local testing suggests failover takes 2 seconds
+ details.setProperty(BrokerDetails.OPTIONS_RETRY, "10");
+ details.setProperty(BrokerDetails.OPTIONS_CONNECT_DELAY, "500");
+ }
+
+ super.setUp();
+ }
+
+ public void test() throws Exception
+ {
+
+ Connection connection = getConnection(_connectionURL);
+ Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+
+ Topic topic = (Topic) getInitialContext().lookup("topic");
+
+ TopicSubscriber noLocalSubscriber = session.
+ createDurableSubscriber(topic, MY_TOPIC_SUBSCRIPTION_NAME + "-NoLocal",
+ null, true);
+
+ TopicSubscriber normalSubscriber = session.
+ createDurableSubscriber(topic, MY_TOPIC_SUBSCRIPTION_NAME + "-Normal",
+ null, false);
+
+ List<Message> sent = sendMessage(session, topic, SEND_COUNT);
+
+ session.commit();
+
+ assertEquals("Incorrect number of messages sent",
+ SEND_COUNT, sent.size());
+
+
+ // Check messages can be received as expected.
+ connection.start();
+
+ assertTrue("No Local Subscriber is not a no-local subscriber",
+ noLocalSubscriber.getNoLocal());
+
+ assertFalse("Normal Subscriber is a no-local subscriber",
+ normalSubscriber.getNoLocal());
+
+
+ List<Message> received = receiveMessage(noLocalSubscriber, SEND_COUNT);
+ assertEquals("No Local Subscriber Received messages", 0, received.size());
+
+ received = receiveMessage(normalSubscriber, SEND_COUNT);
+ assertEquals("Normal Subscriber Received no messages",
+ SEND_COUNT, received.size());
+
+
+ ((AMQConnection)connection).setConnectionListener(this);
+
+ restartBroker();
+
+
+ //Await
+ if (!_failoverComplete.await(4000L, TimeUnit.MILLISECONDS))
+ {
+ fail("Failover Failed to compelete");
+ }
+
+ session.rollback();
+
+ //Failover will restablish our clients
+ assertTrue("No Local Subscriber is not a no-local subscriber",
+ noLocalSubscriber.getNoLocal());
+
+ assertFalse("Normal Subscriber is a no-local subscriber",
+ normalSubscriber.getNoLocal());
+
+
+ // NOTE : here that the NO-local subscriber actually now gets ALL the
+ // messages as the connection has failed and they are consuming on a
+ // different connnection to the one that was published on.
+ received = receiveMessage(noLocalSubscriber, SEND_COUNT);
+ assertEquals("No Local Subscriber Received messages", SEND_COUNT, received.size());
+
+ received = receiveMessage(normalSubscriber, SEND_COUNT);
+ assertEquals("Normal Subscriber Received no messages",
+ SEND_COUNT, received.size());
+
+ //leave the store in a clean state.
+ session.commit();
+ }
+
+ protected List<Message> assertReceiveMessage(MessageConsumer messageConsumer,
+ int count) throws JMSException
+ {
+
+ List<Message> receivedMessages = new ArrayList<Message>(count);
+ for (int i = 0; i < count; i++)
+ {
+ Message received = messageConsumer.receive(1000);
+
+ if (received != null)
+ {
+ receivedMessages.add(received);
+ }
+ else
+ {
+ fail("Only "
+ + receivedMessages.size() + "/" + count + " received.");
+ }
+ }
+
+ return receivedMessages;
+ }
+
+ protected List<Message> receiveMessage(MessageConsumer messageConsumer,
+ int count) throws JMSException
+ {
+
+ List<Message> receivedMessages = new ArrayList<Message>(count);
+ for (int i = 0; i < count; i++)
+ {
+ Message received = messageConsumer.receive(1000);
+
+ if (received != null)
+ {
+ receivedMessages.add(received);
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ return receivedMessages;
+ }
+
+ public void bytesSent(long count)
+ {
+
+ }
+
+ public void bytesReceived(long count)
+ {
+
+ }
+
+ public boolean preFailover(boolean redirect)
+ {
+ return true;
+ }
+
+ public boolean preResubscribe()
+ {
+ return true;
+ }
+
+ public void failoverComplete()
+ {
+ _failoverComplete.countDown();
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/plugins/PluginTest.java b/java/systests/src/main/java/org/apache/qpid/server/plugins/PluginTest.java
deleted file mode 100644
index 0762a7a561..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/server/plugins/PluginTest.java
+++ /dev/null
@@ -1,54 +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.
- *
- */
-
-package org.apache.qpid.server.plugins;
-
-import java.util.Map;
-
-import org.apache.qpid.server.exchange.ExchangeType;
-
-import junit.framework.TestCase;
-
-public class PluginTest extends TestCase
-{
-
- private static final String TEST_EXCHANGE_CLASS = "org.apache.qpid.extras.exchanges.example.TestExchangeType";
- private static final String PLUGIN_DIRECTORY = System.getProperty("example.plugin.target");
-
- public void testLoadExchanges() throws Exception
- {
- PluginManager manager = new PluginManager(PLUGIN_DIRECTORY);
- Map<String, ExchangeType<?>> exchanges = manager.getExchanges();
- assertNotNull("No exchanges found in "+PLUGIN_DIRECTORY, exchanges);
- assertEquals("Wrong number of exchanges found in "+PLUGIN_DIRECTORY,
- 2, exchanges.size());
- assertNotNull("Wrong exchange found in "+PLUGIN_DIRECTORY,
- exchanges.get(TEST_EXCHANGE_CLASS));
- }
-
- public void testNoExchanges() throws Exception
- {
- PluginManager manager = new PluginManager("/path/to/nowhere");
- Map<String, ExchangeType<?>> exchanges = manager.getExchanges();
- assertNull("Exchanges found", exchanges);
- }
-
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java b/java/systests/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java
deleted file mode 100644
index 8e7038eec3..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java
+++ /dev/null
@@ -1,124 +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.
- *
- */
-package org.apache.qpid.server.protocol;
-
-import junit.framework.TestCase;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.codec.AMQCodecFactory;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.queue.AMQQueueFactory;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.registry.IApplicationRegistry;
-import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.SkeletonMessageStore;
-
-import javax.management.JMException;
-
-/**
- * Test class to test MBean operations for AMQMinaProtocolSession.
- */
-public class AMQProtocolSessionMBeanTest extends TestCase
-{
- /** Used for debugging. */
- private static final Logger log = Logger.getLogger(AMQProtocolSessionMBeanTest.class);
-
- private MessageStore _messageStore = new SkeletonMessageStore();
- private AMQMinaProtocolSession _protocolSession;
- private AMQChannel _channel;
- private AMQProtocolSessionMBean _mbean;
-
- public void testChannels() throws Exception
- {
- // check the channel count is correct
- int channelCount = _mbean.channels().size();
- assertTrue(channelCount == 1);
- AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue_" + System.currentTimeMillis()),
- false,
- new AMQShortString("test"),
- true,
- _protocolSession.getVirtualHost(), null);
- AMQChannel channel = new AMQChannel(_protocolSession,2, _messageStore);
- channel.setDefaultQueue(queue);
- _protocolSession.addChannel(channel);
- channelCount = _mbean.channels().size();
- assertTrue(channelCount == 2);
-
- // general properties test
- _mbean.setMaximumNumberOfChannels(1000L);
- assertTrue(_mbean.getMaximumNumberOfChannels() == 1000L);
-
- // check APIs
- AMQChannel channel3 = new AMQChannel(_protocolSession, 3, _messageStore);
- channel3.setLocalTransactional();
- _protocolSession.addChannel(channel3);
- _mbean.rollbackTransactions(2);
- _mbean.rollbackTransactions(3);
- _mbean.commitTransactions(2);
- _mbean.commitTransactions(3);
-
- // This should throw exception, because the channel does't exist
- try
- {
- _mbean.commitTransactions(4);
- fail();
- }
- catch (JMException ex)
- {
- log.debug("expected exception is thrown :" + ex.getMessage());
- }
-
- // check if closing of session works
- _protocolSession.addChannel(new AMQChannel(_protocolSession, 5, _messageStore));
- _mbean.closeConnection();
- try
- {
- channelCount = _mbean.channels().size();
- assertTrue(channelCount == 0);
- // session is now closed so adding another channel should throw an exception
- _protocolSession.addChannel(new AMQChannel(_protocolSession, 6, _messageStore));
- fail();
- }
- catch (AMQException ex)
- {
- log.debug("expected exception is thrown :" + ex.getMessage());
- }
- }
-
- @Override
- protected void setUp() throws Exception
- {
- super.setUp();
-
- IApplicationRegistry appRegistry = ApplicationRegistry.getInstance();
- _protocolSession =
- new AMQMinaProtocolSession(new MockIoSession(), appRegistry.getVirtualHostRegistry(), new AMQCodecFactory(true),
- null);
- _protocolSession.setVirtualHost(appRegistry.getVirtualHostRegistry().getVirtualHost("test"));
- _channel = new AMQChannel(_protocolSession, 1, _messageStore);
- _protocolSession.addChannel(_channel);
- _mbean = (AMQProtocolSessionMBean) _protocolSession.getManagedObject();
- }
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/protocol/MaxChannelsTest.java b/java/systests/src/main/java/org/apache/qpid/server/protocol/MaxChannelsTest.java
deleted file mode 100644
index 62f5e0c6bf..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/server/protocol/MaxChannelsTest.java
+++ /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.
- *
- */
-package org.apache.qpid.server.protocol;
-
-import junit.framework.TestCase;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.codec.AMQCodecFactory;
-import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.registry.IApplicationRegistry;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.protocol.AMQConstant;
-
-/** Test class to test MBean operations for AMQMinaProtocolSession. */
-public class MaxChannelsTest extends TestCase
-{
-// private MessageStore _messageStore = new SkeletonMessageStore();
-
- public void testChannels() throws Exception
- {
- IApplicationRegistry appRegistry = ApplicationRegistry.getInstance();
- AMQMinaProtocolSession _protocolSession = new AMQMinaProtocolSession(new MockIoSession(),
- appRegistry.getVirtualHostRegistry(),
- new AMQCodecFactory(true),
- null);
- _protocolSession.setVirtualHost(appRegistry.getVirtualHostRegistry().getVirtualHost("test"));
-
- // check the channel count is correct
- int channelCount = _protocolSession.getChannels().size();
- assertEquals("Initial channel count wrong", 0, channelCount);
-
- long maxChannels = 10L;
- _protocolSession.setMaximumNumberOfChannels(maxChannels);
- assertEquals("Number of channels not correctly set.", new Long(maxChannels), _protocolSession.getMaximumNumberOfChannels());
-
-
- try
- {
- for (long currentChannel = 0L; currentChannel < maxChannels; currentChannel++)
- {
- _protocolSession.addChannel(new AMQChannel(_protocolSession, (int) currentChannel, null));
- }
- }
- catch (AMQException e)
- {
- assertEquals("Wrong exception recevied.", e.getErrorCode(), AMQConstant.NOT_ALLOWED);
- }
- assertEquals("Maximum number of channels not set.", new Long(maxChannels), new Long(_protocolSession.getChannels().size()));
- }
-
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/protocol/MockIoSession.java b/java/systests/src/main/java/org/apache/qpid/server/protocol/MockIoSession.java
deleted file mode 100644
index cf6366b513..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/server/protocol/MockIoSession.java
+++ /dev/null
@@ -1,297 +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.
- *
- */
-package org.apache.qpid.server.protocol;
-
-import org.apache.mina.common.*;
-import org.apache.mina.common.support.DefaultCloseFuture;
-import org.apache.mina.common.support.DefaultWriteFuture;
-
-import java.net.SocketAddress;
-import java.net.InetSocketAddress;
-import java.util.Set;
-
-public class MockIoSession implements IoSession
-{
- private AMQProtocolSession _protocolSession;
-
- /**
- * Stores the last response written
- */
- private Object _lastWrittenObject;
-
- private boolean _closing;
-
- public MockIoSession()
- {
- }
-
- public Object getLastWrittenObject()
- {
- return _lastWrittenObject;
- }
-
- public IoService getService()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public IoServiceConfig getServiceConfig()
- {
- return null;
- }
-
- public IoHandler getHandler()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public IoSessionConfig getConfig()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public IoFilterChain getFilterChain()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public WriteFuture write(Object message)
- {
- WriteFuture wf = new DefaultWriteFuture(null);
- _lastWrittenObject = message;
- return wf;
- }
-
- public CloseFuture close()
- {
- _closing = true;
- CloseFuture cf = new DefaultCloseFuture(null);
- cf.setClosed();
- return cf;
- }
-
- public Object getAttachment()
- {
- return _protocolSession;
- }
-
- public Object setAttachment(Object attachment)
- {
- Object current = _protocolSession;
- _protocolSession = (AMQProtocolSession) attachment;
- return current;
- }
-
- public Object getAttribute(String key)
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public Object setAttribute(String key, Object value)
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public Object setAttribute(String key)
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public Object removeAttribute(String key)
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public boolean containsAttribute(String key)
- {
- return false; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public Set getAttributeKeys()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public TransportType getTransportType()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public boolean isConnected()
- {
- return false; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public boolean isClosing()
- {
- return _closing;
- }
-
- public CloseFuture getCloseFuture()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public SocketAddress getRemoteAddress()
- {
- return new InetSocketAddress("127.0.0.1", 1234); //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public SocketAddress getLocalAddress()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public SocketAddress getServiceAddress()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public int getIdleTime(IdleStatus status)
- {
- return 0; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public long getIdleTimeInMillis(IdleStatus status)
- {
- return 0; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void setIdleTime(IdleStatus status, int idleTime)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public int getWriteTimeout()
- {
- return 0; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public long getWriteTimeoutInMillis()
- {
- return 0; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void setWriteTimeout(int writeTimeout)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public TrafficMask getTrafficMask()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void setTrafficMask(TrafficMask trafficMask)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void suspendRead()
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void suspendWrite()
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void resumeRead()
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void resumeWrite()
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public long getReadBytes()
- {
- return 0; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public long getWrittenBytes()
- {
- return 0; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public long getReadMessages()
- {
- return 0L;
- }
-
- public long getWrittenMessages()
- {
- return 0L;
- }
-
- public long getWrittenWriteRequests()
- {
- return 0; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public int getScheduledWriteRequests()
- {
- return 0; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public int getScheduledWriteBytes()
- {
- return 0; //TODO
- }
-
- public long getCreationTime()
- {
- return 0; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public long getLastIoTime()
- {
- return 0; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public long getLastReadTime()
- {
- return 0; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public long getLastWriteTime()
- {
- return 0; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public boolean isIdle(IdleStatus status)
- {
- return false; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public int getIdleCount(IdleStatus status)
- {
- return 0; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public long getLastIdleTime(IdleStatus status)
- {
- return 0; //To change body of implemented methods use File | Settings | File Templates.
- }
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/AckTest.java b/java/systests/src/main/java/org/apache/qpid/server/queue/AckTest.java
deleted file mode 100644
index 9c2932c5e2..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/server/queue/AckTest.java
+++ /dev/null
@@ -1,420 +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.
- *
- */
-package org.apache.qpid.server.queue;
-
-import junit.framework.TestCase;
-import org.apache.log4j.Logger;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.BasicContentHeaderProperties;
-import org.apache.qpid.framing.ContentHeaderBody;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.RequiredDeliveryException;
-import org.apache.qpid.server.subscription.Subscription;
-import org.apache.qpid.server.subscription.SubscriptionFactoryImpl;
-import org.apache.qpid.server.flow.LimitlessCreditManager;
-import org.apache.qpid.server.flow.Pre0_10CreditManager;
-import org.apache.qpid.server.ack.UnacknowledgedMessageMap;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.store.TestMemoryMessageStore;
-import org.apache.qpid.server.store.StoreContext;
-import org.apache.qpid.server.txn.NonTransactionalContext;
-import org.apache.qpid.server.txn.TransactionalContext;
-import org.apache.qpid.server.util.NullApplicationRegistry;
-
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.Set;
-import java.util.Collections;
-
-/**
- * Tests that acknowledgements are handled correctly.
- */
-public class AckTest extends TestCase
-{
- private static final Logger _log = Logger.getLogger(AckTest.class);
-
- private Subscription _subscription;
-
- private MockProtocolSession _protocolSession;
-
- private TestMemoryMessageStore _messageStore;
-
- private StoreContext _storeContext = new StoreContext();
-
- private AMQChannel _channel;
-
- private AMQQueue _queue;
-
- private static final AMQShortString DEFAULT_CONSUMER_TAG = new AMQShortString("conTag");
-
- protected void setUp() throws Exception
- {
- super.setUp();
- ApplicationRegistry.initialise(new NullApplicationRegistry(), 1);
-
- _messageStore = new TestMemoryMessageStore();
- _protocolSession = new MockProtocolSession(_messageStore);
- _channel = new AMQChannel(_protocolSession,5, _messageStore /*dont need exchange registry*/);
-
- _protocolSession.addChannel(_channel);
-
- _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("myQ"), false, new AMQShortString("guest"), true, ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test"),
- null);
- }
-
- protected void tearDown()
- {
- ApplicationRegistry.remove(1);
- }
-
- private void publishMessages(int count) throws AMQException
- {
- publishMessages(count, false);
- }
-
- private void publishMessages(int count, boolean persistent) throws AMQException
- {
- TransactionalContext txnContext = new NonTransactionalContext(_messageStore, _storeContext, null,
- new LinkedList<RequiredDeliveryException>()
- );
- _queue.registerSubscription(_subscription,false);
- MessageHandleFactory factory = new MessageHandleFactory();
- for (int i = 1; i <= count; i++)
- {
- // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0)
- // TODO: Establish some way to determine the version for the test.
- MessagePublishInfo publishBody = new MessagePublishInfo()
- {
-
- public AMQShortString getExchange()
- {
- return new AMQShortString("someExchange");
- }
-
- public void setExchange(AMQShortString exchange)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public boolean isImmediate()
- {
- return false;
- }
-
- public boolean isMandatory()
- {
- return false;
- }
-
- public AMQShortString getRoutingKey()
- {
- return new AMQShortString("rk");
- }
- };
- IncomingMessage msg = new IncomingMessage(_messageStore.getNewMessageId(), publishBody, txnContext,_protocolSession);
- //IncomingMessage msg2 = null;
- if (persistent)
- {
- BasicContentHeaderProperties b = new BasicContentHeaderProperties();
- //This is DeliveryMode.PERSISTENT
- b.setDeliveryMode((byte) 2);
- ContentHeaderBody cb = new ContentHeaderBody();
- cb.properties = b;
- msg.setContentHeaderBody(cb);
- }
- else
- {
- msg.setContentHeaderBody(new ContentHeaderBody());
- }
- // we increment the reference here since we are not delivering the messaging to any queues, which is where
- // the reference is normally incremented. The test is easier to construct if we have direct access to the
- // subscription
- ArrayList<AMQQueue> qs = new ArrayList<AMQQueue>();
- qs.add(_queue);
- msg.enqueue(qs);
- msg.routingComplete(_messageStore, factory);
- if(msg.allContentReceived())
- {
- msg.deliverToQueues();
- }
- // we manually send the message to the subscription
- //_subscription.send(new QueueEntry(_queue,msg), _queue);
- }
- }
-
- /**
- * Tests that the acknowledgements are correctly associated with a channel and
- * order is preserved when acks are enabled
- */
- public void testAckChannelAssociationTest() throws AMQException
- {
- _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true, null, false, new LimitlessCreditManager());
- final int msgCount = 10;
- publishMessages(msgCount, true);
-
- UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
- assertTrue(map.size() == msgCount);
- assertTrue(_messageStore.getMessageMetaDataMap().size() == msgCount);
-
- Set<Long> deliveryTagSet = map.getDeliveryTags();
- int i = 1;
- for (long deliveryTag : deliveryTagSet)
- {
- assertTrue(deliveryTag == i);
- i++;
- QueueEntry unackedMsg = map.get(deliveryTag);
- assertTrue(unackedMsg.getQueue() == _queue);
- }
-
- assertTrue(map.size() == msgCount);
- assertTrue(_messageStore.getMessageMetaDataMap().size() == msgCount);
- }
-
- /**
- * Tests that in no-ack mode no messages are retained
- */
- public void testNoAckMode() throws AMQException
- {
- // false arg means no acks expected
- _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, false, null, false, new LimitlessCreditManager());
- final int msgCount = 10;
- publishMessages(msgCount);
-
- UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
- assertTrue(map.size() == 0);
- assertTrue(_messageStore.getMessageMetaDataMap().size() == 0);
- assertTrue(_messageStore.getContentBodyMap().size() == 0);
-
- }
-
- /**
- * Tests that in no-ack mode no messages are retained
- */
- public void testPersistentNoAckMode() throws AMQException
- {
- // false arg means no acks expected
- _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, false,null,false, new LimitlessCreditManager());
- final int msgCount = 10;
- publishMessages(msgCount, true);
-
- UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
- assertTrue(map.size() == 0);
- assertTrue(_messageStore.getMessageMetaDataMap().size() == 0);
- assertTrue(_messageStore.getContentBodyMap().size() == 0);
-
- }
-
- /**
- * Tests that a single acknowledgement is handled correctly (i.e multiple flag not
- * set case)
- */
- public void testSingleAckReceivedTest() throws AMQException
- {
- _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true,null,false, new LimitlessCreditManager());
- final int msgCount = 10;
- publishMessages(msgCount);
-
- _channel.acknowledgeMessage(5, false);
- UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
- assertTrue(map.size() == msgCount - 1);
-
- Set<Long> deliveryTagSet = map.getDeliveryTags();
- int i = 1;
- for (long deliveryTag : deliveryTagSet)
- {
- assertTrue(deliveryTag == i);
- QueueEntry unackedMsg = map.get(deliveryTag);
- assertTrue(unackedMsg.getQueue() == _queue);
- // 5 is the delivery tag of the message that *should* be removed
- if (++i == 5)
- {
- ++i;
- }
- }
- }
-
- /**
- * Tests that a single acknowledgement is handled correctly (i.e multiple flag not
- * set case)
- */
- public void testMultiAckReceivedTest() throws AMQException
- {
- _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true,null,false, new LimitlessCreditManager());
- final int msgCount = 10;
- publishMessages(msgCount);
-
- _channel.acknowledgeMessage(5, true);
- UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
- assertTrue(map.size() == 5);
-
- Set<Long> deliveryTagSet = map.getDeliveryTags();
- int i = 1;
- for (long deliveryTag : deliveryTagSet)
- {
- assertTrue(deliveryTag == i + 5);
- QueueEntry unackedMsg = map.get(deliveryTag);
- assertTrue(unackedMsg.getQueue() == _queue);
- ++i;
- }
- }
-
- /**
- * Tests that a multiple acknowledgement is handled correctly. When ack'ing all pending msgs.
- */
- public void testMultiAckAllReceivedTest() throws AMQException
- {
- _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true,null,false, new LimitlessCreditManager());
- final int msgCount = 10;
- publishMessages(msgCount);
-
- _channel.acknowledgeMessage(0, true);
- UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
- assertTrue(map.size() == 0);
-
- Set<Long> deliveryTagSet = map.getDeliveryTags();
- int i = 1;
- for (long deliveryTag : deliveryTagSet)
- {
- assertTrue(deliveryTag == i + 5);
- QueueEntry unackedMsg = map.get(deliveryTag);
- assertTrue(unackedMsg.getQueue() == _queue);
- ++i;
- }
- }
-
- /**
- * A regression fixing QPID-1136 showed this up
- *
- * @throws Exception
- */
- public void testMessageDequeueRestoresCreditTest() throws Exception
- {
- // Send 10 messages
- Pre0_10CreditManager creditManager = new Pre0_10CreditManager(0l, 1);
-
- _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession,
- DEFAULT_CONSUMER_TAG, true, null, false, creditManager);
- final int msgCount = 1;
- publishMessages(msgCount);
-
- _queue.deliverAsync(_subscription);
-
- _channel.acknowledgeMessage(1, false);
-
- // Check credit available
- assertTrue("No credit available", creditManager.hasCredit());
-
- }
-
-
-/*
- public void testPrefetchHighLow() throws AMQException
- {
- int lowMark = 5;
- int highMark = 10;
-
- _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true,null,false, new LimitlessCreditManager());
- _channel.setPrefetchLowMarkCount(lowMark);
- _channel.setPrefetchHighMarkCount(highMark);
-
- assertTrue(_channel.getPrefetchLowMarkCount() == lowMark);
- assertTrue(_channel.getPrefetchHighMarkCount() == highMark);
-
- publishMessages(highMark);
-
- // at this point we should have sent out only highMark messages
- // which have not bee received so will be queued up in the channel
- // which should be suspended
- assertTrue(_subscription.isSuspended());
- UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
- assertTrue(map.size() == highMark);
-
- //acknowledge messages so we are just above lowMark
- _channel.acknowledgeMessage(lowMark - 1, true);
-
- //we should still be suspended
- assertTrue(_subscription.isSuspended());
- assertTrue(map.size() == lowMark + 1);
-
- //acknowledge one more message
- _channel.acknowledgeMessage(lowMark, true);
-
- //and suspension should be lifted
- assertTrue(!_subscription.isSuspended());
-
- //pubilsh more msgs so we are just below the limit
- publishMessages(lowMark - 1);
-
- //we should not be suspended
- assertTrue(!_subscription.isSuspended());
-
- //acknowledge all messages
- _channel.acknowledgeMessage(0, true);
- try
- {
- Thread.sleep(3000);
- }
- catch (InterruptedException e)
- {
- _log.error("Error: " + e, e);
- }
- //map will be empty
- assertTrue(map.size() == 0);
- }
-
-*/
-/*
- public void testPrefetch() throws AMQException
- {
- _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true,null,false, new LimitlessCreditManager());
- _channel.setMessageCredit(5);
-
- assertTrue(_channel.getPrefetchCount() == 5);
-
- final int msgCount = 5;
- publishMessages(msgCount);
-
- // at this point we should have sent out only 5 messages with a further 5 queued
- // up in the channel which should now be suspended
- assertTrue(_subscription.isSuspended());
- UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
- assertTrue(map.size() == 5);
- _channel.acknowledgeMessage(5, true);
- assertTrue(!_subscription.isSuspended());
- try
- {
- Thread.sleep(3000);
- }
- catch (InterruptedException e)
- {
- _log.error("Error: " + e, e);
- }
- assertTrue(map.size() == 0);
- }
-
-*/
- public static junit.framework.Test suite()
- {
- return new junit.framework.TestSuite(AckTest.class);
- }
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/DeepQueueConsumeWithSelector.java b/java/systests/src/main/java/org/apache/qpid/server/queue/DeepQueueConsumeWithSelector.java
new file mode 100644
index 0000000000..83f0f87bc5
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/queue/DeepQueueConsumeWithSelector.java
@@ -0,0 +1,159 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.client.AMQConnection;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.Queue;
+import javax.jms.Session;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test DeapQueueConsumerWithSelector
+ * Summary:
+ * Prior to M4 the broker had a different queue model which pre-processed the
+ * messages on the queue for any connecting subscription that had a selector.
+ *
+ * If the queue had a lot of data then this may take a long time to process
+ * to such an extent that the subscription creation may time out. During this
+ * pre-process phase the virtualhost would be come unresposive.
+ *
+ * Our solution was to allow the timeout to be adjusted QPID-1119, which allowed
+ * the subscription to connect but did not address the unresponsiveness.
+ *
+ * The new queue model introduced in M4 resolved this.
+ *
+ * This test is to validate that the new queueing model does indeed remove the
+ * long pre-processing phase and allow immediate subscription so that there is
+ * no unresponsive period.
+ *
+ * Test Strategy:
+ *
+ * Add 100k messages to the queue with a numberic header property that will
+ * allow later subscribers to use as in a selector.
+ *
+ * Connect the subscriber and time how long it takes to connect.
+ *
+ * Finally consume all the messages from the queue to clean up.
+ */
+public class DeepQueueConsumeWithSelector extends QpidTestCase implements MessageListener
+{
+
+ private static final int MESSAGE_COUNT = 10000;
+ private static final int BATCH_SIZE = MESSAGE_COUNT / 10;
+
+ private CountDownLatch _receviedLatch = new CountDownLatch(MESSAGE_COUNT);
+
+ protected long SYNC_WRITE_TIMEOUT = 120000L;
+
+
+ public void setUp() throws Exception
+ {
+ //Set the syncWrite timeout to be just larger than the delay on the commitTran.
+ setSystemProperty("amqj.default_syncwrite_timeout", String.valueOf(SYNC_WRITE_TIMEOUT));
+
+ super.setUp();
+ }
+
+ public void test() throws Exception
+ {
+ // Create Connection
+ Connection connection = getConnection();
+ Session session = ((AMQConnection)connection).createSession(true, Session.SESSION_TRANSACTED, 100000);
+
+ Queue queue = (Queue) getInitialContext().lookup("queue");
+
+ // Validate that the destination exists
+ session.createConsumer(queue).close();
+
+ // Send Messages
+ sendMessage(session, queue, MESSAGE_COUNT, BATCH_SIZE);
+
+ session.close();
+
+ session = ((AMQConnection) connection).createSession(false, Session.AUTO_ACKNOWLEDGE);//, 100000);
+
+
+ // Setup Selector to perform a few calculations which will slow it down
+ String selector = "((\"" + INDEX + "\" % 1) = 0) AND ('" + INDEX + "' IS NOT NULL) AND ('" + INDEX + "' <> -1)";
+
+ // Setup timing
+ long start = System.nanoTime();
+
+ System.err.println("Create Consumer");
+ // Connect Consumer
+ MessageConsumer consumer = session.createConsumer(queue, selector);
+ consumer.setMessageListener(this);
+
+ // Validate timing details
+ long end = System.nanoTime();
+
+ System.err.println("Subscription time took:" + (end - start));
+
+ // Consume Messages
+ connection.start();
+
+
+
+ assertTrue("Messages took to long to be received :"+_receviedLatch.getCount(),
+ _receviedLatch.await(SYNC_WRITE_TIMEOUT, TimeUnit.MILLISECONDS ));
+
+ }
+
+ @Override
+ public Message createNextMessage(Session session, int msgCount) throws JMSException
+ {
+ Message message = super.createNextMessage(session,msgCount);
+
+ if ((msgCount % BATCH_SIZE) == 0 )
+ {
+ System.err.println("Sent:"+msgCount);
+ }
+
+ return message;
+ }
+
+ public void onMessage(Message message)
+ {
+ _receviedLatch.countDown();
+ int msgCount = 0;
+ try
+ {
+ msgCount = message.getIntProperty(INDEX);
+ }
+ catch (JMSException e)
+ {
+ //ignore
+ }
+ if ((msgCount % BATCH_SIZE) == 0 )
+ {
+ System.err.println("Received:"+msgCount);
+ }
+
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/MessageTestHelper.java b/java/systests/src/main/java/org/apache/qpid/server/queue/MessageTestHelper.java
deleted file mode 100644
index b2a4216f8d..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/server/queue/MessageTestHelper.java
+++ /dev/null
@@ -1,102 +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.
- *
- */
-package org.apache.qpid.server.queue;
-
-import org.apache.qpid.framing.ContentHeaderBody;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.SkeletonMessageStore;
-import org.apache.qpid.server.store.StoreContext;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.util.NullApplicationRegistry;
-import org.apache.qpid.server.txn.TransactionalContext;
-import org.apache.qpid.server.txn.NonTransactionalContext;
-import org.apache.qpid.server.RequiredDeliveryException;
-import org.apache.qpid.AMQException;
-
-import junit.framework.TestCase;
-
-import java.util.LinkedList;
-
-class MessageTestHelper extends TestCase
-{
- private final MessageStore _messageStore = new SkeletonMessageStore();
-
- private final StoreContext _storeContext = new StoreContext();
-
- private final TransactionalContext _txnContext = new NonTransactionalContext(_messageStore, _storeContext, null,
- new LinkedList<RequiredDeliveryException>()
- );
-
- MessageTestHelper() throws Exception
- {
- ApplicationRegistry.initialise(new NullApplicationRegistry());
- }
-
- QueueEntryImpl message() throws AMQException
- {
- return message(false);
- }
-
- QueueEntryImpl message(final boolean immediate) throws AMQException
- {
- MessagePublishInfo publish = new MessagePublishInfo()
- {
-
- public AMQShortString getExchange()
- {
- return null;
- }
-
- public void setExchange(AMQShortString exchange)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public boolean isImmediate()
- {
- return immediate;
- }
-
- public boolean isMandatory()
- {
- return false;
- }
-
- public AMQShortString getRoutingKey()
- {
- return null;
- }
- };
-
- //public AMQMessage(Long messageId, AMQMessageHandle messageHandle , TransactionalContext txnConext, MessagePublishInfo info)
- long messageId = _messageStore.getNewMessageId();
- final AMQMessageHandle messageHandle =
- (new MessageHandleFactory()).createMessageHandle(messageId, _messageStore, false);
- messageHandle.setPublishAndContentHeaderBody(new StoreContext(),publish,new ContentHeaderBody());
- AMQMessage msg = new AMQMessage(messageHandle, _txnContext.getStoreContext(), publish);
-
-
- return new QueueEntryImpl(null,msg, Long.MIN_VALUE);
- }
-
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/MockProtocolSession.java b/java/systests/src/main/java/org/apache/qpid/server/queue/MockProtocolSession.java
deleted file mode 100644
index 99c88fac3e..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/server/queue/MockProtocolSession.java
+++ /dev/null
@@ -1,262 +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.
- *
- */
-package org.apache.qpid.server.queue;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.AMQConnectionException;
-import org.apache.qpid.framing.*;
-import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.output.ProtocolOutputConverter;
-import org.apache.qpid.server.output.ProtocolOutputConverterRegistry;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.transport.Sender;
-
-import javax.security.sasl.SaslServer;
-import java.util.HashMap;
-import java.util.Map;
-import java.security.Principal;
-
-/**
- * A protocol session that can be used for testing purposes.
- */
-public class MockProtocolSession implements AMQProtocolSession
-{
- private MessageStore _messageStore;
-
- private Map<Integer, AMQChannel> _channelMap = new HashMap<Integer, AMQChannel>();
-
- public MockProtocolSession(MessageStore messageStore)
- {
- _messageStore = messageStore;
- }
-
- public void dataBlockReceived(AMQDataBlock message) throws Exception
- {
- }
-
- public void writeFrame(AMQDataBlock frame)
- {
- }
-
- public AMQShortString getContextKey()
- {
- return null;
- }
-
- public void setContextKey(AMQShortString contextKey)
- {
- }
-
- public AMQChannel getChannel(int channelId)
- {
- AMQChannel channel = _channelMap.get(channelId);
- if (channel == null)
- {
- throw new IllegalArgumentException("Invalid channel id: " + channelId);
- }
- else
- {
- return channel;
- }
- }
-
- public void addChannel(AMQChannel channel)
- {
- if (channel == null)
- {
- throw new IllegalArgumentException("Channel must not be null");
- }
- else
- {
- _channelMap.put(channel.getChannelId(), channel);
- }
- }
-
- public void closeChannel(int channelId) throws AMQException
- {
- }
-
- public void closeChannelOk(int channelId)
- {
-
- }
-
- public boolean channelAwaitingClosure(int channelId)
- {
- return false;
- }
-
- public void removeChannel(int channelId)
- {
- _channelMap.remove(channelId);
- }
-
- public void initHeartbeats(int delay)
- {
- }
-
- public void closeSession() throws AMQException
- {
- }
-
- public void closeConnection(int channelId, AMQConnectionException e, boolean closeIoSession) throws AMQException
- {
- }
-
- public Object getKey()
- {
- return null;
- }
-
- public String getLocalFQDN()
- {
- return null;
- }
-
- public SaslServer getSaslServer()
- {
- return null;
- }
-
- public void setSaslServer(SaslServer saslServer)
- {
- }
-
- public FieldTable getClientProperties()
- {
- return null;
- }
-
- public void setClientProperties(FieldTable clientProperties)
- {
- }
-
- public Object getClientIdentifier()
- {
- return null;
- }
-
- public VirtualHost getVirtualHost()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void setVirtualHost(VirtualHost virtualHost)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void addSessionCloseTask(Task task)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void removeSessionCloseTask(Task task)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public ProtocolOutputConverter getProtocolOutputConverter()
- {
- return ProtocolOutputConverterRegistry.getConverter(this);
- }
-
- public void setAuthorizedID(Principal authorizedID)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public Principal getAuthorizedID()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public MethodRegistry getMethodRegistry()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void methodFrameReceived(int channelId, AMQMethodBody body)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void contentHeaderReceived(int channelId, ContentHeaderBody body)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void contentBodyReceived(int channelId, ContentBody body)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void heartbeatBodyReceived(int channelId, HeartbeatBody body)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public MethodDispatcher getMethodDispatcher()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public ProtocolSessionIdentifier getSessionIdentifier()
- {
- return null;
- }
-
- public byte getProtocolMajorVersion()
- {
- return getProtocolVersion().getMajorVersion();
- }
-
- public byte getProtocolMinorVersion()
- {
- return getProtocolVersion().getMinorVersion();
- }
-
-
- public ProtocolVersion getProtocolVersion()
- {
- return ProtocolVersion.getLatestSupportedVersion(); //To change body of implemented methods use File | Settings | File Templates.
- }
-
-
- public VersionSpecificRegistry getRegistry()
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void setSender(Sender<java.nio.ByteBuffer> sender)
- {
- // FIXME AS TODO
-
- }
-
- public void init()
- {
- // TODO Auto-generated method stub
-
- }
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/ModelTest.java b/java/systests/src/main/java/org/apache/qpid/server/queue/ModelTest.java
new file mode 100644
index 0000000000..078b8f43ce
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/queue/ModelTest.java
@@ -0,0 +1,299 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedQueue;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Session;
+import javax.management.JMException;
+import javax.management.MBeanException;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.UndeclaredThrowableException;
+
+/**
+ * This Test validates the Queue Model on the broker.
+ * Currently it has some basic queue creation / deletion tests.
+ * However, it should be expanded to include other tests that relate to the
+ * model. i.e.
+ *
+ * The Create and Delete tests should ensure that the requisite logging is
+ * performed.
+ *
+ * Additions to this suite would be to complete testing of creations, validating
+ * fields such as owner/exclusive, autodelete and priority are correctly set.
+ *
+ * Currently this test uses the JMX interface to validate that the queue has
+ * been declared as expected so these tests cannot run against a CPP broker.
+ *
+ *
+ * Tests should ensure that they clean up after themselves.
+ * e,g. Durable queue creation test should perform a queue delete.
+ */
+public class ModelTest extends QpidTestCase
+{
+
+ private static final String USER = "admin";
+ private JMXTestUtils _jmxUtils;
+ private static final String VIRTUALHOST_NAME = "test";
+
+ @Override
+ public void setUp() throws Exception
+ {
+ // Create a JMX Helper
+ _jmxUtils = new JMXTestUtils(this, USER, USER);
+ _jmxUtils.setUp();
+ super.setUp();
+
+ // Open the JMX Connection
+ _jmxUtils.open();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ // Close the JMX Connection
+ _jmxUtils.close();
+ super.tearDown();
+ }
+
+ /**
+ * Test that a transient queue can be created via AMQP.
+ *
+ * @throws Exception On unexpected error
+ */
+ public void testQueueCreationTransientViaAMQP() throws Exception
+ {
+ Connection connection = getConnection();
+
+ String queueName = getTestQueueName();
+ boolean durable = false;
+ boolean autoDelete = false;
+ boolean exclusive = false;
+
+ createViaAMQPandValidateViaJMX(connection, queueName, durable,
+ autoDelete, exclusive);
+ }
+
+ /**
+ * Test that a durable queue can be created via AMQP.
+ *
+ * @throws Exception On unexpected error
+ */
+
+ public void testQueueCreationDurableViaAMQP() throws Exception
+ {
+ Connection connection = getConnection();
+
+ String queueName = getTestQueueName();
+ boolean durable = true;
+ boolean autoDelete = false;
+ boolean exclusive = false;
+
+ createViaAMQPandValidateViaJMX(connection, queueName, durable,
+ autoDelete, exclusive);
+
+ // Clean up
+ ManagedBroker managedBroker =
+ _jmxUtils.getManagedBroker(VIRTUALHOST_NAME);
+ managedBroker.deleteQueue(queueName);
+ }
+
+ /**
+ * Test that a transient queue can be created via JMX.
+ *
+ * @throws IOException if there is a problem via the JMX connection
+ * @throws javax.management.JMException if there is a problem with the JMX command
+ */
+ public void testCreationTransientViaJMX() throws IOException, JMException
+ {
+ String name = getName();
+ String owner = null;
+ boolean durable = false;
+
+ createViaJMXandValidateViaJMX(name, owner, durable, durable);
+ }
+
+ /**
+ * Test that a durable queue can be created via JMX.
+ *
+ * @throws IOException if there is a problem via the JMX connection
+ * @throws javax.management.JMException if there is a problem with the JMX command
+ */
+ public void testCreationDurableViaJMX() throws IOException, JMException
+ {
+ String name = getName();
+ String owner = null;
+ boolean durable = true;
+
+ createViaJMXandValidateViaJMX(name, owner, durable, durable);
+
+ // Clean up
+ ManagedBroker managedBroker =
+ _jmxUtils.getManagedBroker(VIRTUALHOST_NAME);
+ managedBroker.deleteQueue(name);
+ }
+
+ /**
+ * Test that a transient queue can be deleted via JMX.
+ *
+ * @throws IOException if there is a problem via the JMX connection
+ * @throws javax.management.JMException if there is a problem with the JMX command
+ */
+ public void testDeletionTransientViaJMX() throws IOException, JMException
+ {
+ String name = getName();
+
+ _jmxUtils.createQueue(VIRTUALHOST_NAME, name, null, false);
+
+ ManagedBroker managedBroker = _jmxUtils.
+ getManagedBroker(VIRTUALHOST_NAME);
+
+ try
+ {
+ managedBroker.deleteQueue(name);
+ }
+ catch (UndeclaredThrowableException e)
+ {
+ fail(((MBeanException) ((InvocationTargetException)
+ e.getUndeclaredThrowable()).getTargetException()).getTargetException().getMessage());
+ }
+ }
+
+ /**
+ * Test that a durable queue can be created via JMX.
+ *
+ * @throws IOException if there is a problem via the JMX connection
+ * @throws javax.management.JMException if there is a problem with the JMX command
+ */
+ public void testDeletionDurableViaJMX() throws IOException, JMException
+ {
+ String name = getName();
+
+ _jmxUtils.createQueue(VIRTUALHOST_NAME, name, null, true);
+
+ ManagedBroker managedBroker = _jmxUtils.
+ getManagedBroker(VIRTUALHOST_NAME);
+
+ try
+ {
+ managedBroker.deleteQueue(name);
+ }
+ catch (UndeclaredThrowableException e)
+ {
+ fail(((MBeanException) ((InvocationTargetException)
+ e.getUndeclaredThrowable()).getTargetException()).getTargetException().getMessage());
+ }
+ }
+
+ /*
+ * Helper Methods
+ */
+
+ /**
+ * Using the provided JMS Connection create a queue using the AMQP extension
+ * with the given properties and then validate it was created correctly via
+ * the JMX Connection
+ *
+ * @param connection Qpid JMS Connection
+ * @param queueName String the desired QueueName
+ * @param durable boolean if the queue should be durable
+ * @param autoDelete boolean if the queue is an autoDelete queue
+ * @param exclusive boolean if the queue is exclusive
+ *
+ * @throws AMQException if there is a problem with the createQueue call
+ * @throws JMException if there is a problem with the JMX validatation
+ * @throws IOException if there is a problem with the JMX connection
+ * @throws JMSException if there is a problem creating the JMS Session
+ */
+ private void createViaAMQPandValidateViaJMX(Connection connection,
+ String queueName,
+ boolean durable,
+ boolean autoDelete,
+ boolean exclusive)
+ throws AMQException, JMException, IOException, JMSException
+ {
+ AMQSession session = (AMQSession) connection.createSession(false,
+ Session.AUTO_ACKNOWLEDGE);
+
+ session.createQueue(new AMQShortString(queueName),
+ autoDelete, durable, exclusive);
+
+ validateQueueViaJMX(queueName, exclusive ? ((AMQConnection) connection).
+ getUsername() : null, durable, autoDelete);
+ }
+
+ /**
+ * Use the JMX Helper to create a queue with the given properties and then
+ * validate it was created correctly via the JMX Connection
+ *
+ * @param queueName String the desired QueueName
+ * @param owner String the owner value that should be set
+ * @param durable boolean if the queue should be durable
+ * @param autoDelete boolean if the queue is an autoDelete queue
+ *
+ * @throws JMException if there is a problem with the JMX validatation
+ * @throws IOException if there is a problem with the JMX connection
+ */
+ private void createViaJMXandValidateViaJMX(String queueName, String owner,
+ boolean durable, boolean autoDelete)
+ throws JMException, IOException
+ {
+ _jmxUtils.createQueue(VIRTUALHOST_NAME, queueName, owner, durable);
+
+ validateQueueViaJMX(queueName, owner, durable, autoDelete);
+ }
+
+ /**
+ * Validate that a queue with the given properties exists on the broker
+ *
+ * @param queueName String the desired QueueName
+ * @param owner String the owner value that should be set
+ * @param durable boolean if the queue should be durable
+ * @param autoDelete boolean if the queue is an autoDelete queue
+ *
+ * @throws JMException if there is a problem with the JMX validatation
+ * @throws IOException if there is a problem with the JMX connection
+ */
+ private void validateQueueViaJMX(String queueName, String owner, boolean durable, boolean autoDelete)
+ throws JMException, IOException
+ {
+ ManagedQueue managedQueue = _jmxUtils.
+ getManagedObject(ManagedQueue.class,
+ _jmxUtils.getQueueObjectName(VIRTUALHOST_NAME,
+ queueName));
+
+ assertEquals(queueName, managedQueue.getName());
+ assertEquals(String.valueOf(owner), managedQueue.getOwner());
+ assertEquals(durable, managedQueue.isDurable());
+ assertEquals(autoDelete, managedQueue.isAutoDelete());
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/PriorityTest.java b/java/systests/src/main/java/org/apache/qpid/server/queue/PriorityTest.java
index 0dbf95052f..ca38807fb1 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/queue/PriorityTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/queue/PriorityTest.java
@@ -29,6 +29,7 @@ import org.apache.qpid.client.AMQSession;
import org.apache.qpid.client.AMQQueue;
import org.apache.qpid.client.AMQDestination;
import org.apache.qpid.jndi.PropertiesFileInitialContextFactory;
+import org.apache.qpid.test.utils.QpidTestCase;
import org.apache.qpid.url.URLSyntaxException;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
@@ -42,106 +43,71 @@ import java.util.Hashtable;
import java.util.HashMap;
import java.util.Map;
-/** Test Case provided by client Non-functional Test NF101: heap exhaustion behaviour */
-public class PriorityTest extends TestCase
+public class PriorityTest extends QpidTestCase
{
- private static final Logger _logger = Logger.getLogger(PriorityTest.class);
+ private static final int TIMEOUT = 1500;
- protected final String BROKER = "vm://:1";
- protected final String VHOST = "/test";
- protected final String QUEUE = "PriorityQueue";
+ private static final Logger _logger = Logger.getLogger(PriorityTest.class);
+ protected final String QUEUE = "PriorityQueue";
private static final int MSG_COUNT = 50;
+ private Connection producerConnection;
+ private MessageProducer producer;
+ private Session producerSession;
+ private Queue queue;
+ private Connection consumerConnection;
+ private Session consumerSession;
+
+
+ private MessageConsumer consumer;
+
protected void setUp() throws Exception
{
super.setUp();
- if (usingInVMBroker())
- {
- TransportConnection.createVMBroker(1);
- }
-
-
- }
+ producerConnection = getConnection();
+ producerSession = producerConnection.createSession(true, Session.AUTO_ACKNOWLEDGE);
- private boolean usingInVMBroker()
- {
- return BROKER.startsWith("vm://");
+ producerConnection.start();
+
+ consumerConnection = getConnection();
+ consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
}
protected void tearDown() throws Exception
{
- if (usingInVMBroker())
- {
- TransportConnection.killAllVMBrokers();
- }
+ producerConnection.close();
+ consumerConnection.close();
super.tearDown();
}
public void testPriority() throws JMSException, NamingException, AMQException
{
- InitialContextFactory factory = new PropertiesFileInitialContextFactory();
-
- Hashtable<String, String> env = new Hashtable<String, String>();
-
- env.put("connectionfactory.connection", "amqp://guest:guest@PRIORITY_TEST_ID" + VHOST + "?brokerlist='" + BROKER + "'");
- env.put("queue.queue", QUEUE);
-
- Context context = factory.getInitialContext(env);
-
- Connection producerConnection = ((ConnectionFactory) context.lookup("connection")).createConnection();
-
- Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
-
final Map<String,Object> arguments = new HashMap<String, Object>();
arguments.put("x-qpid-priorities",10);
-
((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments);
-
- Queue queue = new AMQQueue("amq.direct",QUEUE);
+ queue = (Queue) producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'");
((AMQSession) producerSession).declareAndBind((AMQDestination)queue);
-
-
-
-
-
-
- producerConnection.start();
-
-
- MessageProducer producer = producerSession.createProducer(queue);
-
-
-
-
+ producer = producerSession.createProducer(queue);
for (int msg = 0; msg < MSG_COUNT; msg++)
{
producer.setPriority(msg % 10);
producer.send(nextMessage(msg, false, producerSession, producer));
}
-
+ producerSession.commit();
producer.close();
producerSession.close();
producerConnection.close();
-
- Connection consumerConnection = ((ConnectionFactory) context.lookup("connection")).createConnection();
- Session consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
- MessageConsumer consumer = consumerSession.createConsumer(queue);
-
-
-
-
+ consumer = consumerSession.createConsumer(queue);
consumerConnection.start();
-
Message received;
- //Receive Message 0
- StringBuilder buf = new StringBuilder();
int receivedCount = 0;
Message previous = null;
int messageCount = 0;
@@ -158,10 +124,80 @@ public class PriorityTest extends TestCase
}
assertEquals("Incorrect number of message received", 50, receivedCount);
-
- producerSession.close();
- producer.close();
-
+ }
+
+ public void testOddOrdering() throws AMQException, JMSException
+ {
+ final Map<String,Object> arguments = new HashMap<String, Object>();
+ arguments.put("x-qpid-priorities",3);
+ ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments);
+ queue = producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'");
+
+ ((AMQSession) producerSession).declareAndBind((AMQDestination)queue);
+ producer = producerSession.createProducer(queue);
+
+ // In order ABC
+ producer.setPriority(9);
+ producer.send(nextMessage(1, false, producerSession, producer));
+ producer.setPriority(4);
+ producer.send(nextMessage(2, false, producerSession, producer));
+ producer.setPriority(1);
+ producer.send(nextMessage(3, false, producerSession, producer));
+
+ // Out of order BAC
+ producer.setPriority(4);
+ producer.send(nextMessage(4, false, producerSession, producer));
+ producer.setPriority(9);
+ producer.send(nextMessage(5, false, producerSession, producer));
+ producer.setPriority(1);
+ producer.send(nextMessage(6, false, producerSession, producer));
+
+ // Out of order BCA
+ producer.setPriority(4);
+ producer.send(nextMessage(7, false, producerSession, producer));
+ producer.setPriority(1);
+ producer.send(nextMessage(8, false, producerSession, producer));
+ producer.setPriority(9);
+ producer.send(nextMessage(9, false, producerSession, producer));
+
+ // Reverse order CBA
+ producer.setPriority(1);
+ producer.send(nextMessage(10, false, producerSession, producer));
+ producer.setPriority(4);
+ producer.send(nextMessage(11, false, producerSession, producer));
+ producer.setPriority(9);
+ producer.send(nextMessage(12, false, producerSession, producer));
+ producerSession.commit();
+
+ consumer = consumerSession.createConsumer(queue);
+ consumerConnection.start();
+
+ Message msg = consumer.receive(TIMEOUT);
+ assertEquals(1, msg.getIntProperty("msg"));
+ msg = consumer.receive(TIMEOUT);
+ assertEquals(5, msg.getIntProperty("msg"));
+ msg = consumer.receive(TIMEOUT);
+ assertEquals(9, msg.getIntProperty("msg"));
+ msg = consumer.receive(TIMEOUT);
+ assertEquals(12, msg.getIntProperty("msg"));
+
+ msg = consumer.receive(TIMEOUT);
+ assertEquals(2, msg.getIntProperty("msg"));
+ msg = consumer.receive(TIMEOUT);
+ assertEquals(4, msg.getIntProperty("msg"));
+ msg = consumer.receive(TIMEOUT);
+ assertEquals(7, msg.getIntProperty("msg"));
+ msg = consumer.receive(TIMEOUT);
+ assertEquals(11, msg.getIntProperty("msg"));
+
+ msg = consumer.receive(TIMEOUT);
+ assertEquals(3, msg.getIntProperty("msg"));
+ msg = consumer.receive(TIMEOUT);
+ assertEquals(6, msg.getIntProperty("msg"));
+ msg = consumer.receive(TIMEOUT);
+ assertEquals(8, msg.getIntProperty("msg"));
+ msg = consumer.receive(TIMEOUT);
+ assertEquals(10, msg.getIntProperty("msg"));
}
private Message nextMessage(int msg, boolean first, Session producerSession, MessageProducer producer) throws JMSException
diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java b/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java
new file mode 100644
index 0000000000..d139f8d8b4
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java
@@ -0,0 +1,498 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+package org.apache.qpid.server.queue;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.management.common.mbeans.ManagedQueue;
+import org.apache.qpid.server.logging.AbstractTestLogging;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.framing.AMQShortString;
+
+import javax.jms.*;
+import javax.naming.NamingException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.io.IOException;
+
+public class ProducerFlowControlTest extends AbstractTestLogging
+{
+ private static final int TIMEOUT = 1500;
+
+
+ private static final Logger _logger = Logger.getLogger(ProducerFlowControlTest.class);
+
+ private static final int MSG_COUNT = 50;
+
+ private Connection producerConnection;
+ private MessageProducer producer;
+ private Session producerSession;
+ private Queue queue;
+ private Connection consumerConnection;
+ private Session consumerSession;
+
+ private MessageConsumer consumer;
+ private final AtomicInteger _sentMessages = new AtomicInteger();
+
+ private JMXTestUtils _jmxUtils;
+ private boolean _jmxUtilConnected;
+ private static final String USER = "admin";
+
+ public void setUp() throws Exception
+ {
+ _jmxUtils = new JMXTestUtils(this, USER , USER);
+ _jmxUtils.setUp();
+ _jmxUtilConnected=false;
+ super.setUp();
+
+ _monitor.reset();
+
+ producerConnection = getConnection();
+ producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ producerConnection.start();
+
+ consumerConnection = getConnection();
+ consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ }
+
+ public void tearDown() throws Exception
+ {
+ if(_jmxUtilConnected)
+ {
+ try
+ {
+ _jmxUtils.close();
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ producerConnection.close();
+ consumerConnection.close();
+ super.tearDown();
+ }
+
+ public void testCapacityExceededCausesBlock()
+ throws JMSException, NamingException, AMQException, InterruptedException
+ {
+ String queueName = getTestQueueName();
+
+ final Map<String,Object> arguments = new HashMap<String, Object>();
+ arguments.put("x-qpid-capacity",1000);
+ arguments.put("x-qpid-flow-resume-capacity",800);
+ ((AMQSession) producerSession).createQueue(new AMQShortString(queueName), true, false, false, arguments);
+ queue = producerSession.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='false'&autodelete='true'");
+ ((AMQSession) producerSession).declareAndBind((AMQDestination)queue);
+ producer = producerSession.createProducer(queue);
+
+ _sentMessages.set(0);
+
+
+ // try to send 5 messages (should block after 4)
+ sendMessagesAsync(producer, producerSession, 5, 50L);
+
+ Thread.sleep(5000);
+
+ assertEquals("Incorrect number of message sent before blocking", 4, _sentMessages.get());
+
+ consumer = consumerSession.createConsumer(queue);
+ consumerConnection.start();
+
+
+ consumer.receive();
+
+ Thread.sleep(1000);
+
+ assertEquals("Message incorrectly sent after one message received", 4, _sentMessages.get());
+
+
+ consumer.receive();
+
+ Thread.sleep(1000);
+
+ assertEquals("Message not sent after two messages received", 5, _sentMessages.get());
+
+ }
+
+ public void testBrokerLogMessages()
+ throws JMSException, NamingException, AMQException, InterruptedException, IOException
+ {
+ String queueName = getTestQueueName();
+
+ final Map<String,Object> arguments = new HashMap<String, Object>();
+ arguments.put("x-qpid-capacity",1000);
+ arguments.put("x-qpid-flow-resume-capacity",800);
+ ((AMQSession) producerSession).createQueue(new AMQShortString(queueName), true, false, false, arguments);
+ queue = producerSession.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='false'&autodelete='true'");
+ ((AMQSession) producerSession).declareAndBind((AMQDestination)queue);
+ producer = producerSession.createProducer(queue);
+
+ _sentMessages.set(0);
+
+
+ // try to send 5 messages (should block after 4)
+ sendMessagesAsync(producer, producerSession, 5, 50L);
+
+ Thread.sleep(5000);
+ List<String> results = _monitor.findMatches("QUE-1003");
+
+ assertEquals("Did not find correct number of QUE-1003 queue overfull messages", 1, results.size());
+
+ consumer = consumerSession.createConsumer(queue);
+ consumerConnection.start();
+
+
+ while(consumer.receive(1000) != null);
+
+ results = _monitor.findMatches("QUE-1004");
+
+ assertEquals("Did not find correct number of QUE_UNDERFULL queue underfull messages", 1, results.size());
+
+
+
+ }
+
+
+ public void testClientLogMessages()
+ throws JMSException, NamingException, AMQException, InterruptedException, IOException
+ {
+ String queueName = getTestQueueName();
+
+ setTestClientSystemProperty("qpid.flow_control_wait_failure","3000");
+ setTestClientSystemProperty("qpid.flow_control_wait_notify_period","1000");
+
+ Session session = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+
+ final Map<String,Object> arguments = new HashMap<String, Object>();
+ arguments.put("x-qpid-capacity",1000);
+ arguments.put("x-qpid-flow-resume-capacity",800);
+ ((AMQSession) session).createQueue(new AMQShortString(queueName), true, false, false, arguments);
+ queue = producerSession.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='false'&autodelete='true'");
+ ((AMQSession) session).declareAndBind((AMQDestination)queue);
+ producer = session.createProducer(queue);
+
+ _sentMessages.set(0);
+
+
+ // try to send 5 messages (should block after 4)
+ MessageSender sender = sendMessagesAsync(producer, producerSession, 5, 50L);
+
+ Thread.sleep(10000);
+ List<String> results = _monitor.findMatches("Message send delayed by");
+ assertTrue("No delay messages logged by client",results.size()!=0);
+ results = _monitor.findMatches("Message send failed due to timeout waiting on broker enforced flow control");
+ assertEquals("Incorrect number of send failure messages logged by client",1,results.size());
+
+
+
+ }
+
+
+ public void testFlowControlOnCapacityResumeEqual()
+ throws JMSException, NamingException, AMQException, InterruptedException
+ {
+ String queueName = getTestQueueName();
+
+ final Map<String,Object> arguments = new HashMap<String, Object>();
+ arguments.put("x-qpid-capacity",1000);
+ arguments.put("x-qpid-flow-resume-capacity",1000);
+ ((AMQSession) producerSession).createQueue(new AMQShortString(queueName), true, false, false, arguments);
+ queue = producerSession.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='false'&autodelete='true'");
+ ((AMQSession) producerSession).declareAndBind((AMQDestination)queue);
+ producer = producerSession.createProducer(queue);
+
+ _sentMessages.set(0);
+
+ // try to send 5 messages (should block after 4)
+ sendMessagesAsync(producer, producerSession, 5, 50L);
+
+ Thread.sleep(5000);
+
+ assertEquals("Incorrect number of message sent before blocking", 4, _sentMessages.get());
+
+ consumer = consumerSession.createConsumer(queue);
+ consumerConnection.start();
+
+
+ consumer.receive();
+
+ Thread.sleep(1000);
+
+ assertEquals("Message incorrectly sent after one message received", 5, _sentMessages.get());
+
+
+ }
+
+
+ public void testFlowControlSoak()
+ throws Exception, NamingException, AMQException, InterruptedException
+ {
+ String queueName = getTestQueueName();
+
+ _sentMessages.set(0);
+ final int numProducers = 10;
+ final int numMessages = 100;
+
+ final Map<String,Object> arguments = new HashMap<String, Object>();
+ arguments.put("x-qpid-capacity",6000);
+ arguments.put("x-qpid-flow-resume-capacity",3000);
+
+ ((AMQSession) consumerSession).createQueue(new AMQShortString(queueName), false, false, false, arguments);
+
+ queue = producerSession.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='false'&autodelete='false'");
+ ((AMQSession) consumerSession).declareAndBind((AMQDestination)queue);
+ consumerConnection.start();
+
+ Connection[] producers = new Connection[numProducers];
+ for(int i = 0 ; i < numProducers; i ++)
+ {
+
+ producers[i] = getConnection();
+ producers[i].start();
+ Session session = producers[i].createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ MessageProducer myproducer = session.createProducer(queue);
+ MessageSender sender = sendMessagesAsync(myproducer, session, numMessages, 50L);
+ }
+
+ consumer = consumerSession.createConsumer(queue);
+ consumerConnection.start();
+
+ for(int j = 0; j < numProducers * numMessages; j++)
+ {
+
+ Message msg = consumer.receive(5000);
+ Thread.sleep(50L);
+ assertNotNull("Message not received("+j+"), sent: "+_sentMessages.get(), msg);
+
+ }
+
+
+
+ Message msg = consumer.receive(500);
+ assertNull("extra message received", msg);
+
+
+ for(int i = 0; i < numProducers; i++)
+ {
+ producers[i].close();
+ }
+
+ }
+
+
+
+ public void testSendTimeout()
+ throws JMSException, NamingException, AMQException, InterruptedException
+ {
+ String queueName = getTestQueueName();
+
+ setTestClientSystemProperty("qpid.flow_control_wait_failure","3000");
+ Session session = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+
+ final Map<String,Object> arguments = new HashMap<String, Object>();
+ arguments.put("x-qpid-capacity",1000);
+ arguments.put("x-qpid-flow-resume-capacity",800);
+ ((AMQSession) session).createQueue(new AMQShortString(queueName), true, false, false, arguments);
+ queue = producerSession.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='false'&autodelete='true'");
+ ((AMQSession) session).declareAndBind((AMQDestination)queue);
+ producer = session.createProducer(queue);
+
+ _sentMessages.set(0);
+
+
+ // try to send 5 messages (should block after 4)
+ MessageSender sender = sendMessagesAsync(producer, producerSession, 5, 50L);
+
+ Thread.sleep(10000);
+
+ Exception e = sender.getException();
+
+ assertNotNull("No timeout exception on sending", e);
+
+ }
+
+
+ public void testFlowControlAttributeModificationViaJMX()
+ throws JMSException, NamingException, AMQException, InterruptedException, Exception
+ {
+ _jmxUtils.open();
+ _jmxUtilConnected = true;
+
+ String queueName = getTestQueueName();
+
+ //create queue
+ final Map<String,Object> arguments = new HashMap<String, Object>();
+ arguments.put("x-qpid-capacity",0);
+ arguments.put("x-qpid-flow-resume-capacity",0);
+ ((AMQSession) producerSession).createQueue(new AMQShortString(queueName), true, false, false, arguments);
+
+ queue = producerSession.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='false'&autodelete='true'");
+
+ ((AMQSession) producerSession).declareAndBind((AMQDestination)queue);
+ producer = producerSession.createProducer(queue);
+
+ Thread.sleep(1000);
+
+ //Create a JMX MBean proxy for the queue
+ ManagedQueue queueMBean = _jmxUtils.getManagedObject(ManagedQueue.class, _jmxUtils.getQueueObjectName("test", queueName));
+ assertNotNull(queueMBean);
+
+ //check current attribute values are 0 as expected
+ assertTrue("Capacity was not the expected value", queueMBean.getCapacity() == 0L);
+ assertTrue("FlowResumeCapacity was not the expected value", queueMBean.getFlowResumeCapacity() == 0L);
+
+ //set new values that will cause flow control to be active, and the queue to become overfull after 1 message is sent
+ queueMBean.setCapacity(250L);
+ queueMBean.setFlowResumeCapacity(250L);
+ assertTrue("Capacity was not the expected value", queueMBean.getCapacity() == 250L);
+ assertTrue("FlowResumeCapacity was not the expected value", queueMBean.getFlowResumeCapacity() == 250L);
+ assertFalse("Queue should not be overfull", queueMBean.isFlowOverfull());
+
+ // try to send 2 messages (should block after 1)
+ _sentMessages.set(0);
+ sendMessagesAsync(producer, producerSession, 2, 50L);
+
+ Thread.sleep(2000);
+
+ //check only 1 message was sent, and queue is overfull
+ assertEquals("Incorrect number of message sent before blocking", 1, _sentMessages.get());
+ assertTrue("Queue should be overfull", queueMBean.isFlowOverfull());
+
+ //raise the attribute values, causing the queue to become underfull and allow the second message to be sent.
+ queueMBean.setCapacity(300L);
+ queueMBean.setFlowResumeCapacity(300L);
+
+ Thread.sleep(2000);
+
+ //check second message was sent, and caused the queue to become overfull again
+ assertEquals("Second message was not sent after lifting FlowResumeCapacity", 2, _sentMessages.get());
+ assertTrue("Queue should be overfull", queueMBean.isFlowOverfull());
+
+ //raise capacity above queue depth, check queue remains overfull as FlowResumeCapacity still exceeded
+ queueMBean.setCapacity(700L);
+ assertTrue("Queue should be overfull", queueMBean.isFlowOverfull());
+
+ //receive a message, check queue becomes underfull
+
+ consumer = consumerSession.createConsumer(queue);
+ consumerConnection.start();
+
+ consumer.receive();
+
+ //perform a synchronous op on the connection
+ ((AMQSession) consumerSession).declareExchange(
+ new AMQShortString("amq.direct"), new AMQShortString("direct"), false);
+
+ assertFalse("Queue should not be overfull", queueMBean.isFlowOverfull());
+
+ consumer.receive();
+ }
+
+ private MessageSender sendMessagesAsync(final MessageProducer producer,
+ final Session producerSession,
+ final int numMessages,
+ long sleepPeriod)
+ {
+ MessageSender sender = new MessageSender(producer, producerSession, numMessages,sleepPeriod);
+ new Thread(sender).start();
+ return sender;
+ }
+
+ private void sendMessages(MessageProducer producer, Session producerSession, int numMessages, long sleepPeriod)
+ throws JMSException
+ {
+
+ for (int msg = 0; msg < numMessages; msg++)
+ {
+ producer.send(nextMessage(msg, producerSession));
+ _sentMessages.incrementAndGet();
+
+ try
+ {
+ Thread.sleep(sleepPeriod);
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+ }
+
+ private static final byte[] BYTE_300 = new byte[300];
+
+
+ private Message nextMessage(int msg, Session producerSession) throws JMSException
+ {
+ BytesMessage send = producerSession.createBytesMessage();
+ send.writeBytes(BYTE_300);
+ send.setIntProperty("msg", msg);
+
+ return send;
+ }
+
+
+ private class MessageSender implements Runnable
+ {
+ private final MessageProducer _producer;
+ private final Session _producerSession;
+ private final int _numMessages;
+
+
+
+ private JMSException _exception;
+ private long _sleepPeriod;
+
+ public MessageSender(MessageProducer producer, Session producerSession, int numMessages, long sleepPeriod)
+ {
+ _producer = producer;
+ _producerSession = producerSession;
+ _numMessages = numMessages;
+ _sleepPeriod = sleepPeriod;
+ }
+
+ public void run()
+ {
+ try
+ {
+ sendMessages(_producer, _producerSession, _numMessages, _sleepPeriod);
+ }
+ catch (JMSException e)
+ {
+ _exception = e;
+ }
+ }
+
+ public JMSException getException()
+ {
+ return _exception;
+ }
+ }
+} \ No newline at end of file
diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java b/java/systests/src/main/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java
index 280d897852..ded2e0913b 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java
@@ -24,8 +24,8 @@ package org.apache.qpid.server.queue;
import junit.framework.TestCase;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
-import org.apache.log4j.PropertyConfigurator;
import org.apache.qpid.AMQException;
+import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.client.AMQDestination;
import org.apache.qpid.client.AMQSession;
import org.apache.qpid.client.transport.TransportConnection;
@@ -53,22 +53,26 @@ import java.util.Hashtable;
*/
public class QueueDepthWithSelectorTest extends TestCase
{
- private static final Logger _logger = Logger.getLogger(QueueDepthWithSelectorTest.class);
+ protected static final Logger _logger = Logger.getLogger(QueueDepthWithSelectorTest.class);
protected final String BROKER = "vm://:1";
protected final String VHOST = "test";
protected final String QUEUE = this.getClass().getName();
- private Context _context;
+ protected Context _context;
- private Connection _clientConnection, _producerConnection;
- private Session _clientSession, _producerSession;
- private MessageProducer _producer;
+ protected Connection _clientConnection;
+ protected Connection _producerConnection;
+ private Session _clientSession;
+ protected Session _producerSession;
+ protected MessageProducer _producer;
private MessageConsumer _consumer;
- private static final int MSG_COUNT = 50;
+ protected static int MSG_COUNT = 50;
- private Message[] _messages = new Message[MSG_COUNT];
+ protected Message[] _messages = new Message[MSG_COUNT];
+
+ protected Queue _queue;
protected void setUp() throws Exception
{
@@ -85,6 +89,7 @@ public class QueueDepthWithSelectorTest extends TestCase
if (BROKER.startsWith("vm://"))
{
+ ApplicationRegistry.getInstance(1);
TransportConnection.createVMBroker(1);
}
InitialContextFactory factory = new PropertiesFileInitialContextFactory();
@@ -96,6 +101,9 @@ public class QueueDepthWithSelectorTest extends TestCase
_context = factory.getInitialContext(env);
+ _messages = new Message[MSG_COUNT];
+ _queue = (Queue) _context.lookup("queue");
+ init();
}
protected void tearDown() throws Exception
@@ -114,14 +122,13 @@ public class QueueDepthWithSelectorTest extends TestCase
if (BROKER.startsWith("vm://"))
{
- TransportConnection.killAllVMBrokers();
+ TransportConnection.killVMBroker(1);
+ ApplicationRegistry.remove(1);
}
}
public void test() throws Exception
{
-
- init();
//Send messages
_logger.info("Starting to send messages");
for (int msg = 0; msg < MSG_COUNT; msg++)
@@ -134,34 +141,32 @@ public class QueueDepthWithSelectorTest extends TestCase
//Verify we get all the messages.
_logger.info("Verifying messages");
- verifyAllMessagesRecevied();
+ verifyAllMessagesRecevied(0);
//Close the connection.. .giving the broker time to clean up its state.
_clientConnection.close();
//Verify Broker state
_logger.info("Verifying broker state");
- verifyBrokerState();
+ verifyBrokerState(0);
}
- private void init() throws NamingException, JMSException
+ protected void init() throws NamingException, JMSException, AMQException
{
- _messages = new Message[MSG_COUNT];
-
//Create Producer
_producerConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection();
_producerConnection.start();
_producerSession = _producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
- _producer = _producerSession.createProducer((Queue) _context.lookup("queue"));
+ _producer = _producerSession.createProducer(_queue);
// Create consumer
_clientConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection();
_clientConnection.start();
_clientSession = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
- _consumer = _clientSession.createConsumer((Queue) _context.lookup("queue"), "key = 23");
+ _consumer = _clientSession.createConsumer(_queue, "key = 23");
}
- private void verifyBrokerState()
+ protected void verifyBrokerState(int expectedDepth)
{
try
{
@@ -177,17 +182,13 @@ public class QueueDepthWithSelectorTest extends TestCase
try
{
Thread.sleep(2000);
- long queueDepth = ((AMQSession) _clientSession).getQueueDepth((AMQDestination) _context.lookup("queue"));
- assertEquals("Session reports Queue depth not as expected", 0, queueDepth);
+ long queueDepth = ((AMQSession) _clientSession).getQueueDepth((AMQDestination) _queue);
+ assertEquals("Session reports Queue depth not as expected", expectedDepth, queueDepth);
}
catch (InterruptedException e)
{
fail(e.getMessage());
}
- catch (NamingException e)
- {
- fail(e.getMessage());
- }
catch (AMQException e)
{
fail(e.getMessage());
@@ -206,7 +207,7 @@ public class QueueDepthWithSelectorTest extends TestCase
}
- private void verifyAllMessagesRecevied() throws Exception
+ protected void verifyAllMessagesRecevied(int expectedDepth) throws Exception
{
boolean[] msgIdRecevied = new boolean[MSG_COUNT];
@@ -216,8 +217,9 @@ public class QueueDepthWithSelectorTest extends TestCase
_messages[i] = _consumer.receive(1000);
assertNotNull("should have received a message but didn't", _messages[i]);
}
- long queueDepth = ((AMQSession) _clientSession).getQueueDepth((AMQDestination) _context.lookup("queue"));
- assertEquals("Session reports Queue depth not as expected", 0, queueDepth);
+
+ long queueDepth = ((AMQSession) _clientSession).getQueueDepth((AMQDestination) _queue);
+ assertEquals("Session reports Queue depth not as expected", expectedDepth, queueDepth);
//Check received messages
int msgId = 0;
@@ -246,8 +248,7 @@ public class QueueDepthWithSelectorTest extends TestCase
*
* @throws JMSException
*/
-
- private Message nextMessage(int msgNo) throws JMSException
+ protected Message nextMessage(int msgNo) throws JMSException
{
Message send = _producerSession.createTextMessage("MessageReturnTest");
send.setIntProperty("ID", msgNo);
diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionTestHelper.java b/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionTestHelper.java
index eed60a1a7c..352f6ad119 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionTestHelper.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionTestHelper.java
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -21,6 +21,7 @@
package org.apache.qpid.server.queue;
import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.logging.LogActor;
import org.apache.qpid.server.subscription.Subscription;
import org.apache.qpid.framing.AMQShortString;
@@ -33,6 +34,7 @@ public class SubscriptionTestHelper implements Subscription
private final List<QueueEntry> messages;
private final Object key;
private boolean isSuspended;
+ private AMQQueue.Context _queueContext;
public SubscriptionTestHelper(Object key)
{
@@ -56,7 +58,12 @@ public class SubscriptionTestHelper implements Subscription
return messages;
}
- public void setQueue(AMQQueue queue)
+ public void setQueue(AMQQueue queue, boolean exclusive)
+ {
+
+ }
+
+ public void setNoLocal(boolean noLocal)
{
}
@@ -101,21 +108,36 @@ public class SubscriptionTestHelper implements Subscription
//To change body of implemented methods use File | Settings | File Templates.
}
- public void restoreCredit(final QueueEntry queueEntry)
+ public void onDequeue(final QueueEntry queueEntry)
{
}
+ public void restoreCredit(QueueEntry queueEntry)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
public void setStateListener(final StateListener listener)
{
//To change body of implemented methods use File | Settings | File Templates.
}
- public QueueEntry getLastSeenEntry()
+ public State getState()
{
return null; //To change body of implemented methods use File | Settings | File Templates.
}
+ public AMQQueue.Context getQueueContext()
+ {
+ return _queueContext;
+ }
+
+ public void setQueueContext(AMQQueue.Context queueContext)
+ {
+ _queueContext = queueContext;
+ }
+
public boolean setLastSeenEntry(QueueEntry expected, QueueEntry newValue)
{
return false; //To change body of implemented methods use File | Settings | File Templates.
@@ -125,7 +147,7 @@ public class SubscriptionTestHelper implements Subscription
{
return null;
}
-
+
public void start()
{
//no-op
@@ -136,11 +158,41 @@ public class SubscriptionTestHelper implements Subscription
return null; //To change body of implemented methods use File | Settings | File Templates.
}
+ public long getSubscriptionID()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
public boolean isActive()
{
return false; //To change body of implemented methods use File | Settings | File Templates.
}
+ public void confirmAutoClose()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void set(String key, Object value)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public Object get(String key)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public LogActor getLogActor()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isTransient()
+ {
+ return false;
+ }
+
public AMQQueue getQueue()
{
return null;
@@ -151,6 +203,11 @@ public class SubscriptionTestHelper implements Subscription
return null; //To change body of implemented methods use File | Settings | File Templates.
}
+ public QueueEntry.SubscriptionAssignedState getAssignedState()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
public void queueDeleted(AMQQueue queue)
{
}
@@ -200,6 +257,16 @@ public class SubscriptionTestHelper implements Subscription
return false;
}
+ public boolean acquires()
+ {
+ return true;
+ }
+
+ public boolean seesRequeues()
+ {
+ return true;
+ }
+
public boolean isBrowser()
{
return false;
diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/TimeToLiveTest.java b/java/systests/src/main/java/org/apache/qpid/server/queue/TimeToLiveTest.java
index c60748b5cb..5970d105eb 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/queue/TimeToLiveTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/queue/TimeToLiveTest.java
@@ -21,100 +21,58 @@
package org.apache.qpid.server.queue;
-import junit.framework.TestCase;
-import junit.framework.Assert;
-import org.apache.qpid.client.transport.TransportConnection;
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQDestination;
-import org.apache.qpid.jndi.PropertiesFileInitialContextFactory;
-import org.apache.qpid.url.URLSyntaxException;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.log4j.Logger;
-
+import javax.jms.Connection;
import javax.jms.JMSException;
-import javax.jms.Session;
+import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Queue;
-import javax.jms.ConnectionFactory;
-import javax.jms.Connection;
-import javax.jms.Message;
-import javax.naming.spi.InitialContextFactory;
-import javax.naming.Context;
-import javax.naming.NamingException;
-import java.util.Hashtable;
+import javax.jms.Session;
+import junit.framework.Assert;
-/** Test Case provided by client Non-functional Test NF101: heap exhaustion behaviour */
-public class TimeToLiveTest extends TestCase
+import org.apache.log4j.Logger;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.Condition;
+
+public class TimeToLiveTest extends QpidTestCase
{
private static final Logger _logger = Logger.getLogger(TimeToLiveTest.class);
-
- protected final String BROKER = "vm://:1";
- protected final String VHOST = "/test";
protected final String QUEUE = "TimeToLiveQueue";
- private final long TIME_TO_LIVE = 1000L;
+ private final long TIME_TO_LIVE = 100L;
private static final int MSG_COUNT = 50;
private static final long SERVER_TTL_TIMEOUT = 60000L;
- protected void setUp() throws Exception
- {
- super.setUp();
-
- if (usingInVMBroker())
- {
- TransportConnection.createVMBroker(1);
- }
-
-
- }
-
- private boolean usingInVMBroker()
- {
- return BROKER.startsWith("vm://");
- }
-
- protected void tearDown() throws Exception
+ public void testPassiveTTL() throws Exception
{
- if (usingInVMBroker())
- {
- TransportConnection.killVMBroker(1);
- ApplicationRegistry.remove(1);
- }
- super.tearDown();
- }
-
- public void testPassiveTTL() throws JMSException, NamingException
- {
- InitialContextFactory factory = new PropertiesFileInitialContextFactory();
-
- Hashtable<String, String> env = new Hashtable<String, String>();
-
- env.put("connectionfactory.connection", "amqp://guest:guest@TTL_TEST_ID" + VHOST + "?brokerlist='" + BROKER + "'");
- env.put("queue.queue", QUEUE);
-
- Context context = factory.getInitialContext(env);
-
- Queue queue = (Queue) context.lookup("queue");
-
//Create Client 1
- Connection clientConnection = ((ConnectionFactory) context.lookup("connection")).createConnection();
-
+ Connection clientConnection = getConnection();
+
Session clientSession = clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
-
+ Queue queue = clientSession.createQueue(QUEUE);
+
+ // Create then close the consumer so the queue is actually created
+ // Closing it then reopening it ensures that the consumer shouldn't get messages
+ // which should have expired and allows a shorter sleep period. See QPID-1418
+
MessageConsumer consumer = clientSession.createConsumer(queue);
+ consumer.close();
//Create Producer
- Connection producerConnection = ((ConnectionFactory) context.lookup("connection")).createConnection();
+ Connection producerConnection = getConnection();
producerConnection.start();
- Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ // Move to a Transacted session to ensure that all messages have been delivered to broker before
+ // we start waiting for TTL
+ Session producerSession = producerConnection.createSession(true, Session.SESSION_TRANSACTED);
MessageProducer producer = producerSession.createProducer(queue);
@@ -133,32 +91,53 @@ public class TimeToLiveTest extends TestCase
producer.setTimeToLive(0L);
producer.send(nextMessage(String.valueOf(msg), false, producerSession, producer));
- try
- {
- // Sleep to ensure TTL reached
- Thread.sleep(2000);
- }
- catch (InterruptedException e)
+ producerSession.commit();
+
+ consumer = clientSession.createConsumer(queue);
+
+ // Ensure we sleep the required amount of time.
+ ReentrantLock waitLock = new ReentrantLock();
+ Condition wait = waitLock.newCondition();
+ final long MILLIS = 1000000L;
+
+ long waitTime = TIME_TO_LIVE * MILLIS;
+ while (waitTime > 0)
{
+ try
+ {
+ waitLock.lock();
+
+ waitTime = wait.awaitNanos(waitTime);
+ }
+ catch (InterruptedException e)
+ {
+ //Stop if we are interrupted
+ fail(e.getMessage());
+ }
+ finally
+ {
+ waitLock.unlock();
+ }
}
clientConnection.start();
//Receive Message 0
- Message received = consumer.receive(1000);
- Assert.assertNotNull("First message not received", received);
- Assert.assertTrue("First message doesn't have first set.", received.getBooleanProperty("first"));
- Assert.assertEquals("First message has incorrect TTL.", 0L, received.getLongProperty("TTL"));
-
+ Message receivedFirst = consumer.receive(1000);
+ Message receivedSecond = consumer.receive(1000);
+ Message receivedThird = consumer.receive(1000);
+
+ // Only first and last messages sent should survive expiry
+ Assert.assertNull("More messages received", receivedThird);
- received = consumer.receive(1000);
- Assert.assertNotNull("Final message not received", received);
- Assert.assertFalse("Final message has first set.", received.getBooleanProperty("first"));
- Assert.assertEquals("Final message has incorrect TTL.", 0L, received.getLongProperty("TTL"));
+ Assert.assertNotNull("First message not received", receivedFirst);
+ Assert.assertTrue("First message doesn't have first set.", receivedFirst.getBooleanProperty("first"));
+ Assert.assertEquals("First message has incorrect TTL.", 0L, receivedFirst.getLongProperty("TTL"));
- received = consumer.receive(1000);
- Assert.assertNull("More messages received", received);
+ Assert.assertNotNull("Final message not received", receivedSecond);
+ Assert.assertFalse("Final message has first set.", receivedSecond.getBooleanProperty("first"));
+ Assert.assertEquals("Final message has incorrect TTL.", 0L, receivedSecond.getLongProperty("TTL"));
clientConnection.close();
@@ -176,10 +155,11 @@ public class TimeToLiveTest extends TestCase
/**
* Tests the expired messages get actively deleted even on queues which have no consumers
+ * @throws Exception
*/
- public void testActiveTTL() throws URLSyntaxException, AMQException, JMSException, InterruptedException
+ public void testActiveTTL() throws Exception
{
- Connection producerConnection = new AMQConnection(BROKER,"guest","guest","activeTTLtest","test");
+ Connection producerConnection = getConnection();
AMQSession producerSession = (AMQSession) producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = producerSession.createTemporaryQueue();
producerSession.declareAndBind((AMQDestination) queue);
diff --git a/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java b/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java
index db29b2d5f9..9487f72ac8 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java
@@ -4,7 +4,7 @@
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
+* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
@@ -21,65 +21,88 @@
package org.apache.qpid.server.security.acl;
-import junit.framework.TestCase;
-import org.apache.qpid.client.transport.TransportConnection;
-import org.apache.qpid.client.*;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry;
+import org.apache.commons.configuration.ConfigurationException;
import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQConnectionFailureException;
+import org.apache.qpid.client.AMQAuthenticationException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQConnectionURL;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.jms.ConnectionListener;
+import org.apache.qpid.jms.ConnectionURL;
+import org.apache.qpid.test.utils.QpidTestCase;
import org.apache.qpid.url.URLSyntaxException;
-import javax.jms.*;
+import javax.jms.Connection;
+import javax.jms.DeliveryMode;
+import javax.jms.ExceptionListener;
import javax.jms.IllegalStateException;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.NamingException;
import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
-public class SimpleACLTest extends TestCase implements ConnectionListener
+public class SimpleACLTest extends QpidTestCase implements ConnectionListener
{
- private String BROKER = "vm://:1";//"tcp://localhost:5672";
-
public void setUp() throws Exception
{
- // Initialise ACLs.
- final String QpidExampleHome = System.getProperty("QPID_EXAMPLE_HOME");
- final File defaultaclConfigFile = new File(QpidExampleHome, "etc/acl.config.xml");
+ //Performing setUp here would result in a broker with the default ACL test config
+
+ //Each test now calls the private setUpACLTest to allow them to make
+ //individual customisations to the base ACL settings
+ }
+
- if (!defaultaclConfigFile.exists())
+ public void tearDown() throws Exception
+ {
+ try
+ {
+ super.tearDown();
+ }
+ catch (JMSException e)
{
- System.err.println("Configuration file not found:" + defaultaclConfigFile);
- fail("Configuration file not found:" + defaultaclConfigFile);
+ //we're throwing this away as it can happen in this test as the state manager remembers exceptions
+ //that we provoked with authentication failures, where the test passes - we can ignore on con close
}
+ }
+
+ private void setUpACLTest() throws Exception
+ {
+ final String QPID_HOME = System.getProperty("QPID_HOME");
- if (System.getProperty("QPID_HOME") == null)
+ if (QPID_HOME == null)
{
fail("QPID_HOME not set");
}
- ConfigurationFileApplicationRegistry config = new ConfigurationFileApplicationRegistry(defaultaclConfigFile);
-
- ApplicationRegistry.initialise(config, 1);
-
- TransportConnection.createVMBroker(1);
- }
+ // Initialise ACLs.
+ _configFile = new File(QPID_HOME, "etc/config-systests-acl.xml");
- public void tearDown()
- {
- ApplicationRegistry.remove(1);
- TransportConnection.killAllVMBrokers();
+ super.setUp();
}
- public String createConnectionString(String username, String password, String broker)
+ public String createConnectionString(String username, String password)
{
- return "amqp://" + username + ":" + password + "@clientid/test?brokerlist='" + broker + "?retries='0''";
+ return "amqp://" + username + ":" + password + "@clientid/test?brokerlist='" + getBroker() + "?retries='0''";
}
- public void testAccessAuthorized() throws AMQException, URLSyntaxException
+ public void testAccessAuthorized() throws AMQException, URLSyntaxException, Exception
{
+ setUpACLTest();
+
try
{
- Connection conn = new AMQConnection(createConnectionString("client", "guest", BROKER));
+ Connection conn = getConnection("client", "guest");
Session sesh = conn.createSession(true, Session.SESSION_TRANSACTED);
@@ -92,37 +115,91 @@ public class SimpleACLTest extends TestCase implements ConnectionListener
}
catch (Exception e)
{
- fail("Connection was not created due to:" + e.getMessage());
+ fail("Connection was not created due to:" + e);
}
}
+
+ public void testAccessVhostAuthorisedGuest() throws IOException, Exception
+ {
+ //The 'guest' user has no access to the 'test' vhost, as tested below in testAccessNoRights(), and so
+ //is unable to perform actions such as connecting (and by extension, creating a queue, and consuming
+ //from a queue etc). In order to test the vhost-wide 'access' ACL right, the 'guest' user has been given
+ //this right in the 'test2' vhost.
+
+ setUpACLTest();
+
+ try
+ {
+ //get a connection to the 'test2' vhost using the guest user and perform various actions.
+ Connection conn = getConnection(new AMQConnectionURL(
+ "amqp://username:password@clientid/test2?brokerlist='" + getBroker() + "'"));
+
+ ((AMQConnection) conn).setConnectionListener(this);
+
+ Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ conn.start();
- public void testAccessNoRights() throws URLSyntaxException, JMSException
+ //create Queues and consumers for each
+ Queue namedQueue = sesh.createQueue("vhostAccessCreatedQueue" + getTestQueueName());
+ Queue tempQueue = sesh.createTemporaryQueue();
+ MessageConsumer consumer = sesh.createConsumer(namedQueue);
+ MessageConsumer tempConsumer = sesh.createConsumer(tempQueue);
+
+ //send a message to each queue (also causing an exchange declare)
+ MessageProducer sender = ((AMQSession)sesh).createProducer(null);
+ ((org.apache.qpid.jms.MessageProducer) sender).send(namedQueue, sesh.createTextMessage("test"),
+ DeliveryMode.NON_PERSISTENT, 0, 0L, false, false, true);
+ ((org.apache.qpid.jms.MessageProducer) sender).send(tempQueue, sesh.createTextMessage("test"),
+ DeliveryMode.NON_PERSISTENT, 0, 0L, false, false, true);
+
+ //consume the messages from the queues
+ consumer.receive(2000);
+ tempConsumer.receive(2000);
+
+ conn.close();
+ }
+ catch (Exception e)
+ {
+ fail("Test failed due to:" + e.getMessage());
+ }
+ }
+
+ public void testAccessNoRights() throws Exception
{
+ setUpACLTest();
+
try
{
- Connection conn = new AMQConnection(createConnectionString("guest", "guest", BROKER));
+ Connection conn = getConnection("guest", "guest");
//Attempt to do do things to test connection.
Session sesh = conn.createSession(true, Session.SESSION_TRANSACTED);
conn.start();
sesh.rollback();
- conn.close();
fail("Connection was created.");
}
- catch (AMQException amqe)
+ catch (JMSException jmse)
{
- Throwable cause = amqe.getCause();
- assertEquals("Exception was wrong type", AMQAuthenticationException.class, cause.getClass());
+ Throwable linkedException = jmse.getLinkedException();
+ assertNotNull("Cause was null", linkedException);
+
+ assertEquals("Linked Exception was wrong type", AMQConnectionFailureException.class, linkedException.getClass());
+
+ Throwable cause = linkedException.getCause();
+ assertEquals("Cause was wrong type", AMQAuthenticationException.class, cause.getClass());
assertEquals("Incorrect error code thrown", 403, ((AMQAuthenticationException) cause).getErrorCode().getCode());
}
}
- public void testClientConsumeFromTempQueueValid() throws AMQException, URLSyntaxException
+ public void testClientConsumeFromTempQueueValid() throws AMQException, URLSyntaxException, Exception
{
+ setUpACLTest();
+
try
{
- Connection conn = new AMQConnection(createConnectionString("client", "guest", BROKER));
+ Connection conn = getConnection("client", "guest");
Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
@@ -138,15 +215,29 @@ public class SimpleACLTest extends TestCase implements ConnectionListener
}
}
- public void testClientConsumeFromNamedQueueInvalid() throws AMQException, URLSyntaxException
+ public void testClientConsumeFromNamedQueueInvalid() throws NamingException, Exception
{
+ setUpACLTest();
+
+ //QPID-2081: use a latch to sync on exception causing connection close, to work
+ //around the connection close race during tearDown() causing sporadic failures
+ final CountDownLatch exceptionReceived = new CountDownLatch(1);
+
try
{
- Connection conn = new AMQConnection(createConnectionString("client", "guest", BROKER));
+ Connection conn = getConnection("client", "guest");
//Prevent Failover
((AMQConnection) conn).setConnectionListener(this);
+ conn.setExceptionListener(new ExceptionListener()
+ {
+ public void onException(JMSException e)
+ {
+ exceptionReceived.countDown();
+ }
+ });
+
Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
@@ -162,14 +253,21 @@ public class SimpleACLTest extends TestCase implements ConnectionListener
assertNotNull("There was no liked exception", cause);
assertEquals("Wrong linked exception type", AMQAuthenticationException.class, cause.getClass());
assertEquals("Incorrect error code received", 403, ((AMQAuthenticationException) cause).getErrorCode().getCode());
+
+ //use the latch to ensure the control thread waits long enough for the exception thread
+ //to have done enough to mark the connection closed before teardown commences
+ assertTrue("Timed out waiting for conneciton to report close",
+ exceptionReceived.await(2, TimeUnit.SECONDS));
}
}
- public void testClientCreateTemporaryQueue() throws JMSException, URLSyntaxException
+ public void testClientCreateTemporaryQueue() throws JMSException, URLSyntaxException, Exception
{
+ setUpACLTest();
+
try
{
- Connection conn = new AMQConnection(createConnectionString("client", "guest", BROKER));
+ Connection conn = getConnection("client", "guest");
Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
@@ -187,16 +285,30 @@ public class SimpleACLTest extends TestCase implements ConnectionListener
}
}
- public void testClientCreateNamedQueue() throws JMSException, URLSyntaxException, AMQException
+ public void testClientCreateNamedQueue() throws NamingException, JMSException, AMQException, Exception
{
+ setUpACLTest();
+
+ //QPID-2081: use a latch to sync on exception causing connection close, to work
+ //around the connection close race during tearDown() causing sporadic failures
+ final CountDownLatch exceptionReceived = new CountDownLatch(1);
+
try
{
- Connection conn = new AMQConnection(createConnectionString("client", "guest", BROKER));
+ Connection conn = getConnection("client", "guest");
Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
+ conn.setExceptionListener(new ExceptionListener()
+ {
+ public void onException(JMSException e)
+ {
+ exceptionReceived.countDown();
+ }
+ });
+
//Create a Named Queue
((AMQSession) sesh).createQueue(new AMQShortString("IllegalQueue"), false, false, false);
@@ -205,15 +317,23 @@ public class SimpleACLTest extends TestCase implements ConnectionListener
}
catch (AMQAuthenticationException amqe)
{
+ amqe.printStackTrace();
assertEquals("Incorrect error code thrown", 403, ((AMQAuthenticationException) amqe).getErrorCode().getCode());
+
+ //use the latch to ensure the control thread waits long enough for the exception thread
+ //to have done enough to mark the connection closed before teardown commences
+ assertTrue("Timed out waiting for conneciton to report close",
+ exceptionReceived.await(2, TimeUnit.SECONDS));
}
}
- public void testClientPublishUsingTransactionSuccess() throws AMQException, URLSyntaxException
+ public void testClientPublishUsingTransactionSuccess() throws AMQException, URLSyntaxException, Exception
{
+ setUpACLTest();
+
try
{
- Connection conn = new AMQConnection(createConnectionString("client", "guest", BROKER));
+ Connection conn = getConnection("client", "guest");
((AMQConnection) conn).setConnectionListener(this);
@@ -236,11 +356,13 @@ public class SimpleACLTest extends TestCase implements ConnectionListener
}
}
- public void testClientPublishValidQueueSuccess() throws AMQException, URLSyntaxException
+ public void testClientPublishValidQueueSuccess() throws AMQException, URLSyntaxException, Exception
{
+ setUpACLTest();
+
try
{
- Connection conn = new AMQConnection(createConnectionString("client", "guest", BROKER));
+ Connection conn = getConnection("client", "guest");
((AMQConnection) conn).setConnectionListener(this);
@@ -266,13 +388,27 @@ public class SimpleACLTest extends TestCase implements ConnectionListener
}
}
- public void testClientPublishInvalidQueueSuccess() throws AMQException, URLSyntaxException, JMSException
+ public void testClientPublishInvalidQueueSuccess() throws AMQException, URLSyntaxException, JMSException, NamingException, Exception
{
+ setUpACLTest();
+
+ //QPID-2081: use a latch to sync on exception causing connection close, to work
+ //around the connection close race during tearDown() causing sporadic failures
+ final CountDownLatch exceptionReceived = new CountDownLatch(1);
+
try
{
- Connection conn = new AMQConnection(createConnectionString("client", "guest", BROKER));
+ Connection conn = getConnection("client", "guest");
((AMQConnection) conn).setConnectionListener(this);
+
+ conn.setExceptionListener(new ExceptionListener()
+ {
+ public void onException(JMSException e)
+ {
+ exceptionReceived.countDown();
+ }
+ });
Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
@@ -290,7 +426,9 @@ public class SimpleACLTest extends TestCase implements ConnectionListener
// Test the connection with a valid consumer
// This may fail as the session may be closed before the queue or the consumer created.
- session.createConsumer(session.createTemporaryQueue()).close();
+ Queue temp = session.createTemporaryQueue();
+
+ session.createConsumer(temp).close();
//Connection should now be closed and will throw the exception caused by the above send
conn.close();
@@ -300,16 +438,27 @@ public class SimpleACLTest extends TestCase implements ConnectionListener
catch (JMSException e)
{
Throwable cause = e.getLinkedException();
+ if (!(cause instanceof AMQAuthenticationException))
+ {
+ e.printStackTrace();
+ }
assertEquals("Incorrect exception", AMQAuthenticationException.class, cause.getClass());
assertEquals("Incorrect error code thrown", 403, ((AMQAuthenticationException) cause).getErrorCode().getCode());
+
+ //use the latch to ensure the control thread waits long enough for the exception thread
+ //to have done enough to mark the connection closed before teardown commences
+ assertTrue("Timed out waiting for conneciton to report close",
+ exceptionReceived.await(2, TimeUnit.SECONDS));
}
}
- public void testServerConsumeFromNamedQueueValid() throws AMQException, URLSyntaxException
+ public void testServerConsumeFromNamedQueueValid() throws AMQException, URLSyntaxException, Exception
{
+ setUpACLTest();
+
try
{
- Connection conn = new AMQConnection(createConnectionString("server", "guest", BROKER));
+ Connection conn = getConnection("server", "guest");
Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
@@ -325,12 +474,26 @@ public class SimpleACLTest extends TestCase implements ConnectionListener
}
}
- public void testServerConsumeFromNamedQueueInvalid() throws AMQException, URLSyntaxException
+ public void testServerConsumeFromNamedQueueInvalid() throws AMQException, URLSyntaxException, NamingException, Exception
{
+ setUpACLTest();
+
+ //QPID-2081: use a latch to sync on exception causing connection close, to work
+ //around the connection close race during tearDown() causing sporadic failures
+ final CountDownLatch exceptionReceived = new CountDownLatch(1);
+
try
{
- Connection conn = new AMQConnection(createConnectionString("client", "guest", BROKER));
+ Connection conn = getConnection("client", "guest");
+ conn.setExceptionListener(new ExceptionListener()
+ {
+ public void onException(JMSException e)
+ {
+ exceptionReceived.countDown();
+ }
+ });
+
Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
@@ -347,18 +510,34 @@ public class SimpleACLTest extends TestCase implements ConnectionListener
assertNotNull("There was no liked exception", cause);
assertEquals("Wrong linked exception type", AMQAuthenticationException.class, cause.getClass());
assertEquals("Incorrect error code received", 403, ((AMQAuthenticationException) cause).getErrorCode().getCode());
+
+ //use the latch to ensure the control thread waits long enough for the exception thread
+ //to have done enough to mark the connection closed before teardown commences
+ assertTrue("Timed out waiting for conneciton to report close",
+ exceptionReceived.await(2, TimeUnit.SECONDS));
}
}
- public void testServerConsumeFromTemporaryQueue() throws AMQException, URLSyntaxException
+ public void testServerConsumeFromTemporaryQueue() throws AMQException, URLSyntaxException, NamingException, Exception
{
+ setUpACLTest();
+
+ //QPID-2081: use a latch to sync on exception causing connection close, to work
+ //around the connection close race during tearDown() causing sporadic failures
+ final CountDownLatch exceptionReceived = new CountDownLatch(1);
+
try
{
- Connection conn = new AMQConnection(createConnectionString("server", "guest", BROKER));
-
- //Prevent Failover
- ((AMQConnection) conn).setConnectionListener(this);
+ Connection conn = getConnection("server", "guest");
+ conn.setExceptionListener(new ExceptionListener()
+ {
+ public void onException(JMSException e)
+ {
+ exceptionReceived.countDown();
+ }
+ });
+
Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
@@ -374,14 +553,32 @@ public class SimpleACLTest extends TestCase implements ConnectionListener
assertNotNull("There was no liked exception", cause);
assertEquals("Wrong linked exception type", AMQAuthenticationException.class, cause.getClass());
assertEquals("Incorrect error code received", 403, ((AMQAuthenticationException) cause).getErrorCode().getCode());
+
+ //use the latch to ensure the control thread waits long enough for the exception thread
+ //to have done enough to mark the connection closed before teardown commences
+ assertTrue("Timed out waiting for conneciton to report close",
+ exceptionReceived.await(2, TimeUnit.SECONDS));
}
}
- public void testServerCreateNamedQueueValid() throws JMSException, URLSyntaxException
+ @Override
+ public Connection getConnection(String username, String password) throws NamingException, JMSException
{
+ AMQConnection connection = (AMQConnection) super.getConnection(username, password);
+
+ //Prevent Failover
+ connection.setConnectionListener(this);
+
+ return (Connection) connection;
+ }
+
+ public void testServerCreateNamedQueueValid() throws JMSException, URLSyntaxException, Exception
+ {
+ setUpACLTest();
+
try
{
- Connection conn = new AMQConnection(createConnectionString("server", "guest", BROKER));
+ Connection conn = getConnection("server", "guest");
Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
@@ -398,12 +595,26 @@ public class SimpleACLTest extends TestCase implements ConnectionListener
}
}
- public void testServerCreateNamedQueueInvalid() throws JMSException, URLSyntaxException, AMQException
+ public void testServerCreateNamedQueueInvalid() throws JMSException, URLSyntaxException, AMQException, NamingException, Exception
{
+ setUpACLTest();
+
+ //QPID-2081: use a latch to sync on exception causing connection close, to work
+ //around the connection close race during tearDown() causing sporadic failures
+ final CountDownLatch exceptionReceived = new CountDownLatch(1);
+
try
{
- Connection conn = new AMQConnection(createConnectionString("server", "guest", BROKER));
+ Connection conn = getConnection("server", "guest");
+ conn.setExceptionListener(new ExceptionListener()
+ {
+ public void onException(JMSException e)
+ {
+ exceptionReceived.countDown();
+ }
+ });
+
Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
@@ -417,28 +628,107 @@ public class SimpleACLTest extends TestCase implements ConnectionListener
catch (AMQAuthenticationException amqe)
{
assertEquals("Incorrect error code thrown", 403, amqe.getErrorCode().getCode());
+
+ //use the latch to ensure the control thread waits long enough for the exception thread
+ //to have done enough to mark the connection closed before teardown commences
+ assertTrue("Timed out waiting for conneciton to report close",
+ exceptionReceived.await(2, TimeUnit.SECONDS));
}
}
- public void testServerCreateTemporyQueueInvalid() throws JMSException, URLSyntaxException, AMQException
+ public void testServerCreateTemporaryQueueInvalid() throws NamingException, Exception
{
+ setUpACLTest();
+
+ //QPID-2081: use a latch to sync on exception causing connection close, to work
+ //around the connection close race during tearDown() causing sporadic failures
+ final CountDownLatch exceptionReceived = new CountDownLatch(1);
+
+ Connection conn = getConnection("server", "guest");
try
{
- Connection conn = new AMQConnection(createConnectionString("server", "guest", BROKER));
- Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ conn.setExceptionListener(new ExceptionListener()
+ {
+ public void onException(JMSException e)
+ {
+ exceptionReceived.countDown();
+ }
+ });
+
+ Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
- ((AMQSession) sesh).createQueue(new AMQShortString("again_ensure_auto_delete_queue_for_temporary"),
- true, false, false);
+ session.createTemporaryQueue();
fail("Test failed as creation succeded.");
- //conn will be automatically closed
+ }
+ catch (JMSException e)
+ {
+ Throwable cause = e.getLinkedException();
+
+ assertNotNull("There was no liked exception", cause);
+ assertEquals("Wrong linked exception type", AMQAuthenticationException.class, cause.getClass());
+ assertEquals("Incorrect error code received", 403, ((AMQAuthenticationException) cause).getErrorCode().getCode());
+
+ //use the latch to ensure the control thread waits long enough for the exception thread
+ //to have done enough to mark the connection closed before teardown commences
+ assertTrue("Timed out waiting for conneciton to report close",
+ exceptionReceived.await(2, TimeUnit.SECONDS));
+ }
+ finally
+ {
+ try
+ {
+ conn.close();
+ }
+ catch (Exception e)
+ {
+ // This normally fails because we are denied
+ }
+ }
+ }
+
+ public void testServerCreateAutoDeleteQueueInvalid() throws NamingException, JMSException, AMQException, Exception
+ {
+ setUpACLTest();
+
+ //QPID-2081: use a latch to sync on exception causing connection close, to work
+ //around the connection close race during tearDown() causing sporadic failures
+ final CountDownLatch exceptionReceived = new CountDownLatch(1);
+
+ Connection connection = null;
+ try
+ {
+ connection = getConnection("server", "guest");
+
+ connection.setExceptionListener(new ExceptionListener()
+ {
+ public void onException(JMSException e)
+ {
+ exceptionReceived.countDown();
+ }
+ });
+
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ connection.start();
+
+ ((AMQSession) session).createQueue(new AMQShortString("again_ensure_auto_delete_queue_for_temporary"),
+ true, false, false);
+
+ fail("Test failed as creation succeded.");
+ //connection will be automatically closed
}
catch (AMQAuthenticationException amqe)
{
assertEquals("Incorrect error code thrown", 403, amqe.getErrorCode().getCode());
+
+ //use the latch to ensure the control thread waits long enough for the exception thread
+ //to have done enough to mark the connection closed before teardown commences
+ assertTrue("Timed out waiting for conneciton to report close",
+ exceptionReceived.await(2, TimeUnit.SECONDS));
}
}
@@ -450,10 +740,12 @@ public class SimpleACLTest extends TestCase implements ConnectionListener
* @throws URLSyntaxException
* @throws JMSException
*/
- public void testServerPublishUsingTransactionSuccess() throws AMQException, URLSyntaxException, JMSException
+ public void testServerPublishUsingTransactionSuccess() throws AMQException, URLSyntaxException, JMSException, NamingException, Exception
{
+ setUpACLTest();
+
//Set up the Server
- Connection serverConnection = new AMQConnection(createConnectionString("server", "guest", BROKER));
+ Connection serverConnection = getConnection("server", "guest");
((AMQConnection) serverConnection).setConnectionListener(this);
@@ -466,7 +758,7 @@ public class SimpleACLTest extends TestCase implements ConnectionListener
serverConnection.start();
//Set up the consumer
- Connection clientConnection = new AMQConnection(createConnectionString("client", "guest", BROKER));
+ Connection clientConnection = getConnection("client", "guest");
//Send a test mesage
Session clientSession = clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
@@ -507,26 +799,48 @@ public class SimpleACLTest extends TestCase implements ConnectionListener
//Send the message using a transaction as this will allow us to retrieve any errors that occur on the broker.
serverSession.commit();
- serverConnection.close();
-
//Ensure Response is received.
Message clientResponseMsg = clientResponse.receive(2000);
assertNotNull("Client did not receive response message,", clientResponseMsg);
assertEquals("Incorrect message received", "Response", ((TextMessage) clientResponseMsg).getText());
- clientConnection.close();
}
catch (Exception e)
{
fail("Test publish failed:" + e);
}
+ finally
+ {
+ try
+ {
+ serverConnection.close();
+ }
+ finally
+ {
+ clientConnection.close();
+ }
+ }
}
- public void testServerPublishInvalidQueueSuccess() throws AMQException, URLSyntaxException, JMSException
+ public void testServerPublishInvalidQueueSuccess() throws AMQException, URLSyntaxException, JMSException, NamingException, Exception
{
+ setUpACLTest();
+
+ //QPID-2081: use a latch to sync on exception causing connection close, to work
+ //around the connection close race during tearDown() causing sporadic failures
+ final CountDownLatch exceptionReceived = new CountDownLatch(1);
+
try
{
- Connection conn = new AMQConnection(createConnectionString("server", "guest", BROKER));
+ Connection conn = getConnection("server", "guest");
+
+ conn.setExceptionListener(new ExceptionListener()
+ {
+ public void onException(JMSException e)
+ {
+ exceptionReceived.countDown();
+ }
+ });
((AMQConnection) conn).setConnectionListener(this);
@@ -559,8 +873,27 @@ public class SimpleACLTest extends TestCase implements ConnectionListener
{
Throwable cause = e.getLinkedException();
- assertEquals("Incorrect exception", AMQAuthenticationException.class, cause.getClass());
- assertEquals("Incorrect error code thrown", 403, ((AMQAuthenticationException) cause).getErrorCode().getCode());
+ if (cause == null)
+ {
+ e.printStackTrace(System.out);
+ fail("JMS Exception did not have cause");
+ }
+ else if (!(cause instanceof AMQAuthenticationException))
+ {
+ cause.printStackTrace(System.out);
+ assertEquals("Incorrect exception", IllegalStateException.class, cause.getClass());
+ System.out.println("QPID-1204 : Session became closed and we got that error rather than the authentication error.");
+ }
+ else
+ {
+ assertEquals("Incorrect exception", AMQAuthenticationException.class, cause.getClass());
+ assertEquals("Incorrect error code thrown", 403, ((AMQAuthenticationException) cause).getErrorCode().getCode());
+ }
+
+ //use the latch to ensure the control thread waits long enough for the exception thread
+ //to have done enough to mark the connection closed before teardown commences
+ assertTrue("Timed out waiting for conneciton to report close",
+ exceptionReceived.await(2, TimeUnit.SECONDS));
}
}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/security/firewall/FirewallConfigTest.java b/java/systests/src/main/java/org/apache/qpid/server/security/firewall/FirewallConfigTest.java
new file mode 100644
index 0000000000..cbdb310179
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/security/firewall/FirewallConfigTest.java
@@ -0,0 +1,246 @@
+package org.apache.qpid.server.security.firewall;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+
+import org.apache.qpid.client.AMQConnectionURL;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+public class FirewallConfigTest extends QpidTestCase
+{
+
+ private File tmpFile = null;
+ @Override
+ protected void setUp() throws Exception
+ {
+ // do setup
+ final String QPID_HOME = System.getProperty("QPID_HOME");
+
+ if (QPID_HOME == null)
+ {
+ fail("QPID_HOME not set");
+ }
+
+ // Setup initial config.
+ _configFile = new File(QPID_HOME, "etc/config-systests-firewall.xml");
+ tmpFile = File.createTempFile("config-systests-firewall", ".xml");
+ setSystemProperty("QPID_FIREWALL_SETTINGS", tmpFile.getAbsolutePath());
+ tmpFile.deleteOnExit();
+ }
+
+ private void writeFirewallFile(boolean allow, boolean inVhost) throws IOException
+ {
+ FileWriter out = new FileWriter(tmpFile);
+ String ipAddr = "127.0.0.1"; // FIXME: get this from InetAddress.getLocalHost().getAddress() ?
+ out.write("<broker>");
+ if (inVhost)
+ {
+ out.write("<virtualhosts><virtualhost><test>");
+ }
+ out.write("<security><firewall>");
+ out.write("<rule access=\""+((allow) ? "allow" : "deny")+"\" network=\""+ipAddr +"\"/>");
+ out.write("</firewall></security>");
+ if (inVhost)
+ {
+ out.write("</test></virtualhost></virtualhosts>");
+ }
+ out.write("</broker>");
+ out.close();
+ }
+
+ public void testVhostAllowBrokerDeny() throws Exception
+ {
+ if (_broker.equals(VM))
+ {
+ //No point running this test with an InVM broker as the
+ //firewall plugin only functions for TCP connections.
+ return;
+ }
+
+ _configFile = new File(System.getProperty("QPID_HOME"), "etc/config-systests-firewall-2.xml");
+
+ super.setUp();
+
+ Connection conn = null;
+ try
+ {
+ //Try to get a connection to the 'test2' vhost
+ //This is expected to fail as it is denied at the broker level
+ conn = getConnection(new AMQConnectionURL(
+ "amqp://username:password@clientid/test2?brokerlist='" + getBroker() + "'"));
+ fail("We expected the connection to fail");
+ }
+ catch (JMSException e)
+ {
+ //ignore
+ }
+
+ conn = null;
+ try
+ {
+ //Try to get a connection to the 'test' vhost
+ //This is expected to succeed as it is allowed at the vhost level
+ conn = getConnection();
+ }
+ catch (JMSException e)
+ {
+ e.getLinkedException().printStackTrace();
+ fail("The connection was expected to succeed: " + e.getMessage());
+ }
+ }
+
+ public void testVhostDenyBrokerAllow() throws Exception
+ {
+ if (_broker.equals(VM))
+ {
+ //No point running this test with an InVM broker as the
+ //firewall plugin only functions for TCP connections.
+ return;
+ }
+
+ _configFile = new File(System.getProperty("QPID_HOME"), "etc/config-systests-firewall-3.xml");
+
+ super.setUp();
+
+ Connection conn = null;
+ try
+ {
+ //Try to get a connection to the 'test2' vhost
+ //This is expected to fail as it is denied at the vhost level
+ conn = getConnection(new AMQConnectionURL(
+ "amqp://username:password@clientid/test2?brokerlist='" + getBroker() + "'"));
+ }
+ catch (JMSException e)
+ {
+ //ignore
+ }
+
+ conn = null;
+ try
+ {
+ //Try to get a connection to the 'test' vhost
+ //This is expected to succeed as it is allowed at the broker level
+ conn = getConnection();
+ }
+ catch (JMSException e)
+ {
+ e.getLinkedException().printStackTrace();
+ fail("The connection was expected to succeed: " + e.getMessage());
+ }
+ }
+
+ public void testDenyOnRestart() throws Exception
+ {
+ testDeny(false, new Runnable() {
+
+ public void run()
+ {
+ try
+ {
+ restartBroker();
+ } catch (Exception e)
+ {
+ fail(e.getMessage());
+ }
+ }
+ });
+ }
+
+ public void testDenyOnRestartInVhost() throws Exception
+ {
+ testDeny(true, new Runnable() {
+
+ public void run()
+ {
+ try
+ {
+ restartBroker();
+ } catch (Exception e)
+ {
+ fail(e.getMessage());
+ }
+ }
+ });
+ }
+
+ public void testDenyOnReload() throws Exception
+ {
+ testDeny(false, new Runnable() {
+
+ public void run()
+ {
+ try
+ {
+ reloadBroker();
+ } catch (Exception e)
+ {
+ fail(e.getMessage());
+ }
+ }
+ }
+ );
+ }
+
+ public void testDenyOnReloadInVhost() throws Exception
+ {
+ testDeny(true, new Runnable() {
+
+ public void run()
+ {
+ try
+ {
+ reloadBroker();
+ } catch (Exception e)
+ {
+ fail(e.getMessage());
+ }
+ }
+ }
+ );
+
+ }
+
+ private void testDeny(boolean inVhost, Runnable restartOrReload) throws Exception
+ {
+ if (_broker.equals(VM))
+ {
+ // No point running this test in a vm broker
+ return;
+ }
+
+ writeFirewallFile(false, inVhost);
+ super.setUp();
+
+ Exception exception = null;
+ Connection conn = null;
+ try
+ {
+ conn = getConnection();
+ }
+ catch (JMSException e)
+ {
+ exception = e;
+ }
+ assertNotNull(exception);
+
+ // Check we can get a connection
+
+ writeFirewallFile(true, inVhost);
+ restartOrReload.run();
+
+ exception = null;
+ try
+ {
+ conn = getConnection();
+ }
+ catch (JMSException e)
+ {
+ exception = e;
+ }
+ assertNull(exception);
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/store/PersistentStoreTest.java b/java/systests/src/main/java/org/apache/qpid/server/store/PersistentStoreTest.java
new file mode 100644
index 0000000000..65127e50ec
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/store/PersistentStoreTest.java
@@ -0,0 +1,183 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.store;
+
+import org.apache.qpid.test.utils.QpidTestCase;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import java.util.ArrayList;
+import java.util.List;
+
+public class PersistentStoreTest extends QpidTestCase
+{
+
+ private static final int NUM_MESSAGES = 100;
+ private Connection _con;
+ private Session _session;
+ private Queue _destination;
+ private MessageConsumer _consumer;
+
+ public void setUp() throws Exception, JMSException
+ {
+ super.setUp();
+ _con = getConnection();
+ _con.start();
+ _session = _con.createSession(true, Session.AUTO_ACKNOWLEDGE);
+ _destination = _session.createQueue(getTestQueueName());
+ _consumer = _session.createConsumer(_destination);
+ _consumer.close();
+
+ sendMessage(_session, _destination, NUM_MESSAGES);
+ _session.commit();
+ }
+
+ /** Checks that a new consumer on a new connection can get NUM_MESSAGES from _destination */
+ private void checkMessages() throws Exception, JMSException
+ {
+ _con = getConnection();
+ _session = _con.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ _con.start();
+ _consumer = _session.createConsumer(_destination);
+ for (int i = 0; i < NUM_MESSAGES; i++)
+ {
+ Message msg = _consumer.receive(RECEIVE_TIMEOUT);
+ assertNotNull("Message " + i + " not received", msg);
+ }
+ assertNull("No more messages should be received", _consumer.receive(100));
+ }
+
+// /**
+// * starts the server, sends 100 messages, restarts the server and gets 100 messages back
+// * the test formerly referred to as BDB-Qpid-1
+// * @throws Exception
+// */
+// public void testStartStop() throws Exception
+// {
+// restartBroker(); -- Not Currently a gracefull restart so not BDB-Qpid-1
+// checkMessages();
+// }
+
+ /**
+ * starts the server, sends 100 messages, nukes then starts the server and gets 100 messages back
+ * the test formerly referred to as BDB-Qpid-2
+ *
+ * @throws Exception
+ */
+ public void testForcibleStartStop() throws Exception
+ {
+ restartBroker();
+ checkMessages();
+ }
+
+// /**
+// * starts the server, sends 100 committed messages, 5 uncommited ones,
+// * restarts the server and gets 100 messages back
+// * the test formerly referred to as BDB-Qpid-5
+// * @throws Exception
+// */
+// public void testStartStopMidTransaction() throws Exception
+// {
+// sendMessage(_session, _destination, 5);
+// restartBroker(); -- Not Currently a gracefull restart so not BDB-Qpid-1
+// checkMessages();
+// }
+
+ /**
+ * starts the server, sends 100 committed messages, 5 uncommited ones,
+ * nukes and starts the server and gets 100 messages back
+ * the test formerly referred to as BDB-Qpid-6
+ *
+ * @throws Exception
+ */
+ public void testForcibleStartStopMidTransaction() throws Exception
+ {
+ sendMessage(_session, _destination, 5);
+ restartBroker();
+ checkMessages();
+ }
+
+ /**
+ * starts the server, sends 100 committed messages, 5 uncommited ones,
+ * restarts the client and gets 100 messages back.
+ * the test formerly referred to as BDB-Qpid-7
+ *
+ * FIXME: is this a PersistentStoreTest? Seems more like a transaction test to me.. aidan
+ *
+ * @throws Exception
+ */
+ public void testClientDeathMidTransaction() throws Exception
+ {
+ sendMessage(_session, _destination, 5);
+ _con.close();
+ checkMessages();
+ }
+
+// /**
+// * starts the server, sends 50 committed messages, copies $QPID_WORK to a new location,
+// * sends 10 messages, stops the server, nukes the store, restores the copy, starts the server
+// * checks that we get the first 50 back.
+// */
+// public void testHotBackup()
+// {
+// -- removing as this will leave 100msgs on a queue
+// }
+
+ /**
+ * This test requires that we can send messages without commiting.
+ * QTC always commits the messages sent via sendMessages.
+ *
+ * @param session the session to use for sending
+ * @param destination where to send them to
+ * @param count no. of messages to send
+ *
+ * @return the sent messges
+ *
+ * @throws Exception
+ */
+ @Override
+ public List<Message> sendMessage(Session session, Destination destination,
+ int count) throws Exception
+ {
+ List<Message> messages = new ArrayList<Message>(count);
+
+ MessageProducer producer = session.createProducer(destination);
+
+ for (int i = 0;i < (count); i++)
+ {
+ Message next = createNextMessage(session, i);
+
+ producer.send(next);
+
+ messages.add(next);
+ }
+
+ return messages;
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/store/SkeletonMessageStore.java b/java/systests/src/main/java/org/apache/qpid/server/store/SkeletonMessageStore.java
deleted file mode 100644
index f08a15a8a7..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/server/store/SkeletonMessageStore.java
+++ /dev/null
@@ -1,155 +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.
- *
- */
-package org.apache.qpid.server.store;
-
-import org.apache.commons.configuration.Configuration;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.framing.abstraction.ContentChunk;
-import org.apache.qpid.server.queue.MessageMetaData;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.exchange.Exchange;
-
-import java.util.List;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * A message store that does nothing. Designed to be used in tests that do not want to use any message store
- * functionality.
- */
-public class SkeletonMessageStore implements MessageStore
-{
- private final AtomicLong _messageId = new AtomicLong(1);
-
- public void configure(String base, Configuration config) throws Exception
- {
- }
-
- public void configure(VirtualHost virtualHost, String base, Configuration config) throws Exception
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void close() throws Exception
- {
- }
-
- public void removeMessage(StoreContext s, Long messageId)
- {
- }
-
- public void createExchange(Exchange exchange) throws AMQException
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void removeExchange(Exchange exchange) throws AMQException
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public void createQueue(AMQQueue queue) throws AMQException
- {
- }
-
- public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException
- {
- }
-
- public void beginTran(StoreContext s) throws AMQException
- {
- }
-
- public boolean inTran(StoreContext sc)
- {
- return false;
- }
-
- public void commitTran(StoreContext storeContext) throws AMQException
- {
- }
-
- public void abortTran(StoreContext storeContext) throws AMQException
- {
- }
-
- public List<AMQQueue> createQueues() throws AMQException
- {
- return null;
- }
-
- public Long getNewMessageId()
- {
- return _messageId.getAndIncrement();
- }
-
- public void storeContentBodyChunk(StoreContext sc, Long messageId, int index, ContentChunk contentBody, boolean lastContentBody) throws AMQException
- {
-
- }
-
- public void storeMessageMetaData(StoreContext sc, Long messageId, MessageMetaData messageMetaData) throws AMQException
- {
-
- }
-
- public MessageMetaData getMessageMetaData(StoreContext s,Long messageId) throws AMQException
- {
- return null;
- }
-
- public ContentChunk getContentBodyChunk(StoreContext s,Long messageId, int index) throws AMQException
- {
- return null;
- }
-
- public boolean isPersistent()
- {
- return false;
- }
-
- public void removeQueue(final AMQQueue queue) throws AMQException
- {
-
- }
-
- public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException
- {
-
- }
-
- public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException
- {
-
- }
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/store/SlowMessageStore.java b/java/systests/src/main/java/org/apache/qpid/server/store/SlowMessageStore.java
new file mode 100644
index 0000000000..b41aa661ea
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/store/SlowMessageStore.java
@@ -0,0 +1,313 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.store;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.log4j.Logger;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.logging.LogSubject;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.nio.ByteBuffer;
+
+public class SlowMessageStore implements MessageStore
+{
+ private static final Logger _logger = Logger.getLogger(SlowMessageStore.class);
+ private static final String DELAYS = "delays";
+ private HashMap<String, Long> _preDelays = new HashMap<String, Long>();
+ private HashMap<String, Long> _postDelays = new HashMap<String, Long>();
+ private long _defaultDelay = 0L;
+ private MessageStore _realStore = new MemoryMessageStore();
+ private static final String PRE = "pre";
+ private static final String POST = "post";
+ private String DEFAULT_DELAY = "default";
+
+ // ***** MessageStore Interface.
+
+ public void configureConfigStore(String name,
+ ConfigurationRecoveryHandler recoveryHandler,
+ Configuration config,
+ LogSubject logSubject) throws Exception
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+
+ _logger.info("Starting SlowMessageStore on Virtualhost:" + name);
+ Configuration delays = config.subset(DELAYS);
+
+ configureDelays(delays);
+
+ String messageStoreClass = config.getString("realStore");
+
+ if (delays.containsKey(DEFAULT_DELAY))
+ {
+ _defaultDelay = delays.getLong(DEFAULT_DELAY);
+ }
+
+ if (messageStoreClass != null)
+ {
+ Class clazz = Class.forName(messageStoreClass);
+
+ Object o = clazz.newInstance();
+
+ if (!(o instanceof MessageStore))
+ {
+ throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz +
+ " does not.");
+ }
+ _realStore = (MessageStore) o;
+ _realStore.configureConfigStore(name, recoveryHandler, config, logSubject);
+ }
+ else
+ {
+ _realStore.configureConfigStore(name, recoveryHandler, config, logSubject);
+ }
+ }
+
+ private void configureDelays(Configuration config)
+ {
+ Iterator delays = config.getKeys();
+
+ while (delays.hasNext())
+ {
+ String key = (String) delays.next();
+ if (key.endsWith(PRE))
+ {
+ _preDelays.put(key.substring(0, key.length() - PRE.length() - 1), config.getLong(key));
+ }
+ else if (key.endsWith(POST))
+ {
+ _postDelays.put(key.substring(0, key.length() - POST.length() - 1), config.getLong(key));
+ }
+ }
+ }
+
+ private void doPostDelay(String method)
+ {
+ long delay = lookupDelay(_postDelays, method);
+ doDelay(delay);
+ }
+
+ private void doPreDelay(String method)
+ {
+ long delay = lookupDelay(_preDelays, method);
+ doDelay(delay);
+ }
+
+ private long lookupDelay(HashMap<String, Long> delays, String method)
+ {
+ Long delay = delays.get(method);
+ return (delay == null) ? _defaultDelay : delay;
+ }
+
+ private void doDelay(long delay)
+ {
+ if (delay > 0)
+ {
+ long start = System.nanoTime();
+ try
+ {
+
+ Thread.sleep(delay);
+ }
+ catch (InterruptedException e)
+ {
+ _logger.warn("Interrupted : " + e);
+ }
+
+ long slept = (System.nanoTime() - start) / 1000000;
+
+ if (slept >= delay)
+ {
+ _logger.info("Done sleep for:" + slept+":"+delay);
+ }
+ else
+ {
+ _logger.info("Only sleep for:" + slept + " re-sleeping");
+ doDelay(delay - slept);
+ }
+ }
+ }
+
+
+ public void configureMessageStore(String name,
+ MessageStoreRecoveryHandler recoveryHandler,
+ Configuration config,
+ LogSubject logSubject) throws Exception
+ {
+ _realStore.configureMessageStore(name, recoveryHandler, config, logSubject);
+ }
+
+ public void close() throws Exception
+ {
+ doPreDelay("close");
+ _realStore.close();
+ doPostDelay("close");
+ }
+
+ public <M extends StorableMessageMetaData> StoredMessage<M> addMessage(M metaData)
+ {
+ return _realStore.addMessage(metaData);
+ }
+
+
+ public void createExchange(Exchange exchange) throws AMQException
+ {
+ doPreDelay("createExchange");
+ _realStore.createExchange(exchange);
+ doPostDelay("createExchange");
+ }
+
+ public void removeExchange(Exchange exchange) throws AMQException
+ {
+ doPreDelay("removeExchange");
+ _realStore.removeExchange(exchange);
+ doPostDelay("removeExchange");
+ }
+
+ public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException
+ {
+ doPreDelay("bindQueue");
+ _realStore.bindQueue(exchange, routingKey, queue, args);
+ doPostDelay("bindQueue");
+ }
+
+ public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException
+ {
+ doPreDelay("unbindQueue");
+ _realStore.unbindQueue(exchange, routingKey, queue, args);
+ doPostDelay("unbindQueue");
+ }
+
+ public void createQueue(AMQQueue queue) throws AMQException
+ {
+ createQueue(queue, null);
+ }
+
+ public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException
+ {
+ doPreDelay("createQueue");
+ _realStore.createQueue(queue, arguments);
+ doPostDelay("createQueue");
+ }
+
+ public void removeQueue(AMQQueue queue) throws AMQException
+ {
+ doPreDelay("removeQueue");
+ _realStore.removeQueue(queue);
+ doPostDelay("removeQueue");
+ }
+
+ public void configureTransactionLog(String name,
+ TransactionLogRecoveryHandler recoveryHandler,
+ Configuration storeConfiguration, LogSubject logSubject)
+ throws Exception
+ {
+ _realStore.configureTransactionLog(name, recoveryHandler, storeConfiguration, logSubject);
+ }
+
+ public Transaction newTransaction()
+ {
+ doPreDelay("beginTran");
+ Transaction txn = new SlowTransaction(_realStore.newTransaction());
+ doPostDelay("beginTran");
+ return txn;
+ }
+
+
+ public boolean isPersistent()
+ {
+ return _realStore.isPersistent();
+ }
+
+ public void storeMessageHeader(Long messageNumber, ServerMessage message)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void storeContent(Long messageNumber, long offset, ByteBuffer body)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public ServerMessage getMessage(Long messageNumber)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ private class SlowTransaction implements Transaction
+ {
+ private final Transaction _underlying;
+
+ private SlowTransaction(Transaction underlying)
+ {
+ _underlying = underlying;
+ }
+
+ public void enqueueMessage(TransactionLogResource queue, Long messageId)
+ throws AMQException
+ {
+ doPreDelay("enqueueMessage");
+ _underlying.enqueueMessage(queue, messageId);
+ doPostDelay("enqueueMessage");
+ }
+
+ public void dequeueMessage(TransactionLogResource queue, Long messageId)
+ throws AMQException
+ {
+ doPreDelay("dequeueMessage");
+ _underlying.dequeueMessage(queue, messageId);
+ doPostDelay("dequeueMessage");
+ }
+
+ public void commitTran()
+ throws AMQException
+ {
+ doPreDelay("commitTran");
+ _underlying.commitTran();
+ doPostDelay("commitTran");
+ }
+
+ public StoreFuture commitTranAsync()
+ throws AMQException
+ {
+ doPreDelay("commitTran");
+ StoreFuture future = _underlying.commitTranAsync();
+ doPostDelay("commitTran");
+ return future;
+ }
+
+ public void abortTran()
+ throws AMQException
+ {
+ doPreDelay("abortTran");
+ _underlying.abortTran();
+ doPostDelay("abortTran");
+ }
+ }
+
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/store/TestMemoryMessageStore.java b/java/systests/src/main/java/org/apache/qpid/server/store/TestMemoryMessageStore.java
deleted file mode 100644
index 4e48435962..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/server/store/TestMemoryMessageStore.java
+++ /dev/null
@@ -1,51 +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.
- *
- */
-package org.apache.qpid.server.store;
-
-import org.apache.qpid.server.queue.MessageMetaData;
-import org.apache.qpid.framing.ContentBody;
-import org.apache.qpid.framing.abstraction.ContentChunk;
-
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.List;
-
-/**
- * Adds some extra methods to the memory message store for testing purposes.
- */
-public class TestMemoryMessageStore extends MemoryMessageStore
-{
- public TestMemoryMessageStore()
- {
- _metaDataMap = new ConcurrentHashMap<Long, MessageMetaData>();
- _contentBodyMap = new ConcurrentHashMap<Long, List<ContentChunk>>();
- }
-
- public ConcurrentMap<Long, MessageMetaData> getMessageMetaDataMap()
- {
- return _metaDataMap;
- }
-
- public ConcurrentMap<Long, List<ContentChunk>> getContentBodyMap()
- {
- return _contentBodyMap;
- }
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/store/TestReferenceCounting.java b/java/systests/src/main/java/org/apache/qpid/server/store/TestReferenceCounting.java
deleted file mode 100644
index 2346660d25..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/server/store/TestReferenceCounting.java
+++ /dev/null
@@ -1,169 +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.
- *
- */
-package org.apache.qpid.server.store;
-
-import junit.framework.TestCase;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.BasicContentHeaderProperties;
-import org.apache.qpid.framing.ContentHeaderBody;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.queue.MessageHandleFactory;
-import org.apache.qpid.server.queue.AMQMessageHandle;
-
-/**
- * Tests that reference counting works correctly with AMQMessage and the message store
- */
-public class TestReferenceCounting extends TestCase
-{
- private TestMemoryMessageStore _store;
-
- private StoreContext _storeContext = new StoreContext();
-
-
- protected void setUp() throws Exception
- {
- super.setUp();
- _store = new TestMemoryMessageStore();
- }
-
- /**
- * Check that when the reference count is decremented the message removes itself from the store
- */
- public void testMessageGetsRemoved() throws AMQException
- {
- ContentHeaderBody chb = createPersistentContentHeader();
-
- MessagePublishInfo info = new MessagePublishInfo()
- {
-
- public AMQShortString getExchange()
- {
- return null;
- }
-
- public void setExchange(AMQShortString exchange)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public boolean isImmediate()
- {
- return false;
- }
-
- public boolean isMandatory()
- {
- return false;
- }
-
- public AMQShortString getRoutingKey()
- {
- return null;
- }
- };
-
-
- final long messageId = _store.getNewMessageId();
- AMQMessageHandle messageHandle = (new MessageHandleFactory()).createMessageHandle(messageId, _store, true);
- messageHandle.setPublishAndContentHeaderBody(_storeContext,info, chb);
- AMQMessage message = new AMQMessage(messageHandle,
- _storeContext,info);
-
- message = message.takeReference();
-
- // we call routing complete to set up the handle
- // message.routingComplete(_store, _storeContext, new MessageHandleFactory());
-
-
- assertEquals(1, _store.getMessageMetaDataMap().size());
- message.decrementReference(_storeContext);
- assertEquals(1, _store.getMessageMetaDataMap().size());
- }
-
- private ContentHeaderBody createPersistentContentHeader()
- {
- ContentHeaderBody chb = new ContentHeaderBody();
- BasicContentHeaderProperties bchp = new BasicContentHeaderProperties();
- bchp.setDeliveryMode((byte)2);
- chb.properties = bchp;
- return chb;
- }
-
- public void testMessageRemains() throws AMQException
- {
-
- MessagePublishInfo info = new MessagePublishInfo()
- {
-
- public AMQShortString getExchange()
- {
- return null;
- }
-
- public void setExchange(AMQShortString exchange)
- {
- //To change body of implemented methods use File | Settings | File Templates.
- }
-
- public boolean isImmediate()
- {
- return false;
- }
-
- public boolean isMandatory()
- {
- return false;
- }
-
- public AMQShortString getRoutingKey()
- {
- return null;
- }
- };
-
- final Long messageId = _store.getNewMessageId();
- final ContentHeaderBody chb = createPersistentContentHeader();
- AMQMessageHandle messageHandle = (new MessageHandleFactory()).createMessageHandle(messageId, _store, true);
- messageHandle.setPublishAndContentHeaderBody(_storeContext,info,chb);
- AMQMessage message = new AMQMessage(messageHandle,
- _storeContext,
- info);
-
-
- message = message.takeReference();
- // we call routing complete to set up the handle
- // message.routingComplete(_store, _storeContext, new MessageHandleFactory());
-
-
-
- assertEquals(1, _store.getMessageMetaDataMap().size());
- message = message.takeReference();
- message.decrementReference(_storeContext);
- assertEquals(1, _store.getMessageMetaDataMap().size());
- }
-
- public static junit.framework.Test suite()
- {
- return new junit.framework.TestSuite(TestReferenceCounting.class);
- }
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/txn/TxnBufferTest.java b/java/systests/src/main/java/org/apache/qpid/server/txn/TxnBufferTest.java
deleted file mode 100644
index 84d3d313d1..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/server/txn/TxnBufferTest.java
+++ /dev/null
@@ -1,306 +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.
- *
- */
-package org.apache.qpid.server.txn;
-
-import junit.framework.TestCase;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.TestMemoryMessageStore;
-import org.apache.qpid.server.store.StoreContext;
-
-import java.util.LinkedList;
-import java.util.NoSuchElementException;
-
-public class TxnBufferTest extends TestCase
-{
- private final LinkedList<MockOp> ops = new LinkedList<MockOp>();
-
- public void testCommit() throws AMQException
- {
- MockStore store = new MockStore();
-
- TxnBuffer buffer = new TxnBuffer();
- buffer.enlist(new MockOp().expectPrepare().expectCommit());
- //check relative ordering
- MockOp op = new MockOp().expectPrepare().expectPrepare().expectCommit().expectCommit();
- buffer.enlist(op);
- buffer.enlist(op);
- buffer.enlist(new MockOp().expectPrepare().expectCommit());
-
- buffer.commit(null);
-
- validateOps();
- store.validate();
- }
-
- public void testRollback() throws AMQException
- {
- MockStore store = new MockStore();
-
- TxnBuffer buffer = new TxnBuffer();
- buffer.enlist(new MockOp().expectRollback());
- buffer.enlist(new MockOp().expectRollback());
- buffer.enlist(new MockOp().expectRollback());
-
- buffer.rollback(null);
-
- validateOps();
- store.validate();
- }
-
- public void testCommitWithFailureDuringPrepare() throws AMQException
- {
- MockStore store = new MockStore();
- store.beginTran(null);
-
- TxnBuffer buffer = new TxnBuffer();
- buffer.enlist(new StoreMessageOperation(store));
- buffer.enlist(new MockOp().expectPrepare().expectUndoPrepare());
- buffer.enlist(new TxnTester(store));
- buffer.enlist(new MockOp().expectPrepare().expectUndoPrepare());
- buffer.enlist(new FailedPrepare());
- buffer.enlist(new MockOp());
-
- try
- {
- buffer.commit(null);
- }
- catch (NoSuchElementException e)
- {
-
- }
-
- validateOps();
- store.validate();
- }
-
- public void testCommitWithPersistance() throws AMQException
- {
- MockStore store = new MockStore();
- store.beginTran(null);
- store.expectCommit();
-
- TxnBuffer buffer = new TxnBuffer();
- buffer.enlist(new MockOp().expectPrepare().expectCommit());
- buffer.enlist(new MockOp().expectPrepare().expectCommit());
- buffer.enlist(new MockOp().expectPrepare().expectCommit());
- buffer.enlist(new StoreMessageOperation(store));
- buffer.enlist(new TxnTester(store));
-
- buffer.commit(null);
- validateOps();
- store.validate();
- }
-
- private void validateOps()
- {
- for (MockOp op : ops)
- {
- op.validate();
- }
- }
-
- public static junit.framework.Test suite()
- {
- return new junit.framework.TestSuite(TxnBufferTest.class);
- }
-
- class MockOp implements TxnOp
- {
- final Object PREPARE = "PREPARE";
- final Object COMMIT = "COMMIT";
- final Object UNDO_PREPARE = "UNDO_PREPARE";
- final Object ROLLBACK = "ROLLBACK";
-
- private final LinkedList expected = new LinkedList();
-
- MockOp()
- {
- ops.add(this);
- }
-
- public void prepare(StoreContext context)
- {
- assertEquals(expected.removeLast(), PREPARE);
- }
-
- public void commit(StoreContext context)
- {
- assertEquals(expected.removeLast(), COMMIT);
- }
-
- public void undoPrepare()
- {
- assertEquals(expected.removeLast(), UNDO_PREPARE);
- }
-
- public void rollback(StoreContext context)
- {
- assertEquals(expected.removeLast(), ROLLBACK);
- }
-
- private MockOp expect(Object optype)
- {
- expected.addFirst(optype);
- return this;
- }
-
- MockOp expectPrepare()
- {
- return expect(PREPARE);
- }
-
- MockOp expectCommit()
- {
- return expect(COMMIT);
- }
-
- MockOp expectUndoPrepare()
- {
- return expect(UNDO_PREPARE);
- }
-
- MockOp expectRollback()
- {
- return expect(ROLLBACK);
- }
-
- void validate()
- {
- assertEquals("Expected ops were not all invoked", new LinkedList(), expected);
- }
-
- void clear()
- {
- expected.clear();
- }
- }
-
- class MockStore extends TestMemoryMessageStore
- {
- final Object BEGIN = "BEGIN";
- final Object ABORT = "ABORT";
- final Object COMMIT = "COMMIT";
-
- private final LinkedList expected = new LinkedList();
- private boolean inTran;
-
- public void beginTran(StoreContext context) throws AMQException
- {
- inTran = true;
- }
-
- public void commitTran(StoreContext context) throws AMQException
- {
- assertEquals(expected.removeLast(), COMMIT);
- inTran = false;
- }
-
- public void abortTran(StoreContext context) throws AMQException
- {
- assertEquals(expected.removeLast(), ABORT);
- inTran = false;
- }
-
- public boolean inTran(StoreContext context)
- {
- return inTran;
- }
-
- private MockStore expect(Object optype)
- {
- expected.addFirst(optype);
- return this;
- }
-
- MockStore expectBegin()
- {
- return expect(BEGIN);
- }
-
- MockStore expectCommit()
- {
- return expect(COMMIT);
- }
-
- MockStore expectAbort()
- {
- return expect(ABORT);
- }
-
- void clear()
- {
- expected.clear();
- }
-
- void validate()
- {
- assertEquals("Expected ops were not all invoked", new LinkedList(), expected);
- }
- }
-
- class NullOp implements TxnOp
- {
- public void prepare(StoreContext context) throws AMQException
- {
- }
- public void commit(StoreContext context)
- {
- }
- public void undoPrepare()
- {
- }
- public void rollback(StoreContext context)
- {
- }
- }
-
- class FailedPrepare extends NullOp
- {
- public void prepare() throws AMQException
- {
- throw new AMQException(null, "Fail!", null);
- }
- }
-
- class TxnTester extends NullOp
- {
- private final MessageStore store;
-
- private final StoreContext context = new StoreContext();
-
- TxnTester(MessageStore store)
- {
- this.store = store;
- }
-
- public void prepare() throws AMQException
- {
- assertTrue("Expected prepare to be performed under txn", store.inTran(context));
- }
-
- public void commit()
- {
- assertTrue("Expected commit not to be performed under txn", !store.inTran(context));
- }
- }
-
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/CancelTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/CancelTest.java
index 25b9b0ba14..5ea203bda3 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/client/CancelTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/client/CancelTest.java
@@ -81,9 +81,14 @@ public class CancelTest extends QpidTestCase
assertTrue(e.hasMoreElements());
+ int i = 0;
while (e.hasMoreElements())
{
e.nextElement();
+ if(++i > 1)
+ {
+ fail("Two many elemnts to browse!");
+ }
}
browser.close();
diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java
index d1bcaa1bb8..eb0c539a6e 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java
@@ -79,7 +79,7 @@ public class DupsOkTest extends QpidTestCase
* This test sends x messages and receives them with an async consumer.
* Waits for all messages to be received or for 60 s
* and checks whether the queue is empty.
- *
+ *
* @throws Exception
*/
public void testDupsOK() throws Exception
@@ -93,7 +93,7 @@ public class DupsOkTest extends QpidTestCase
assertEquals("The queue should have msgs at start", MSG_COUNT, ((AMQSession) clientSession).getQueueDepth((AMQDestination) _queue));
- clientConnection.start();
+ clientConnection.start();
consumer.setMessageListener(new MessageListener()
{
@@ -110,7 +110,7 @@ public class DupsOkTest extends QpidTestCase
if (message instanceof TextMessage)
{
try
- {
+ {
if (message.getIntProperty("count") == MSG_COUNT)
{
try
@@ -156,7 +156,11 @@ public class DupsOkTest extends QpidTestCase
// before the dispatcher has sent the ack back to the broker.
consumer.close();
- assertEquals("The queue should have 0 msgs left", 0, ((AMQSession) clientSession).getQueueDepth((AMQDestination) _queue));
+ clientSession.close();
+
+ final Session clientSession2 = clientConnection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE);
+
+ assertEquals("The queue should have 0 msgs left", 0, ((AMQSession) clientSession2).getQueueDepth((AMQDestination) _queue));
clientConnection.close();
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/FlowControlTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/FlowControlTest.java
index 94096e412d..95808e454f 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/client/FlowControlTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/client/FlowControlTest.java
@@ -21,6 +21,7 @@
package org.apache.qpid.test.client;
import org.apache.qpid.client.AMQSession_0_8;
+import org.apache.qpid.client.message.AbstractJMSMessage;
import org.apache.qpid.test.utils.QpidTestCase;
import org.apache.log4j.Logger;
@@ -79,7 +80,7 @@ public class FlowControlTest extends QpidTestCase
Connection consumerConnection = getConnection();
Session consumerSession = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
- ((AMQSession_0_8) consumerSession).setPrefecthLimits(0, 256);
+ ((AMQSession_0_8) consumerSession).setPrefetchLimits(0, 256);
MessageConsumer recv = consumerSession.createConsumer(_queue);
consumerConnection.start();
@@ -91,25 +92,22 @@ public class FlowControlTest extends QpidTestCase
assertNotNull("Second message not received", r2);
assertEquals("Messages in wrong order", 2, r2.getIntProperty("msg"));
- Message r3 = recv.receiveNoWait();
+ Message r3 = recv.receive(RECEIVE_TIMEOUT);
assertNull("Third message incorrectly delivered", r3);
- r1.acknowledge();
+ ((AbstractJMSMessage)r1).acknowledgeThis();
- r3 = recv.receiveNoWait();
+ r3 = recv.receive(RECEIVE_TIMEOUT);
assertNull("Third message incorrectly delivered", r3);
- r2.acknowledge();
+ ((AbstractJMSMessage)r2).acknowledgeThis();
r3 = recv.receive(RECEIVE_TIMEOUT);
assertNotNull("Third message not received", r3);
assertEquals("Messages in wrong order", 3, r3.getIntProperty("msg"));
- r3.acknowledge();
- recv.close();
- consumerSession.close();
+ ((AbstractJMSMessage)r3).acknowledgeThis();
consumerConnection.close();
-
}
public void testTwoConsumersBytesFlowControl() throws Exception
@@ -152,7 +150,7 @@ public class FlowControlTest extends QpidTestCase
Connection consumerConnection = getConnection();
Session consumerSession1 = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
- ((AMQSession_0_8) consumerSession1).setPrefecthLimits(0, 256);
+ ((AMQSession_0_8) consumerSession1).setPrefetchLimits(0, 256);
MessageConsumer recv1 = consumerSession1.createConsumer(_queue);
consumerConnection.start();
@@ -161,21 +159,21 @@ public class FlowControlTest extends QpidTestCase
assertNotNull("First message not received", r1);
assertEquals("Messages in wrong order", 1, r1.getIntProperty("msg"));
- Message r2 = recv1.receiveNoWait();
+ Message r2 = recv1.receive(RECEIVE_TIMEOUT);
assertNull("Second message incorrectly delivered", r2);
Session consumerSession2 = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
- ((AMQSession_0_8) consumerSession2).setPrefecthLimits(0, 256);
+ ((AMQSession_0_8) consumerSession2).setPrefetchLimits(0, 256);
MessageConsumer recv2 = consumerSession2.createConsumer(_queue);
- r2 = recv2.receive(100000L);//RECEIVE_TIMEOUT);
+ r2 = recv2.receive(RECEIVE_TIMEOUT);
assertNotNull("Second message not received", r2);
assertEquals("Messages in wrong order", 2, r2.getIntProperty("msg"));
- Message r3 = recv2.receiveNoWait();
+ Message r3 = recv2.receive(RECEIVE_TIMEOUT);
assertNull("Third message incorrectly delivered", r3);
- r3 = recv1.receive(100000L);//RECEIVE_TIMEOUT);
+ r3 = recv1.receive(RECEIVE_TIMEOUT);
assertNotNull("Third message not received", r3);
assertEquals("Messages in wrong order", 3, r3.getIntProperty("msg"));
@@ -198,13 +196,17 @@ public class FlowControlTest extends QpidTestCase
{
System.err.println("Test Run:" + ++run);
Thread.sleep(1000);
-
- test.startBroker();
- test.testBasicBytesFlowControl();
-
- Thread.sleep(1000);
-
- test.stopBroker();
+ try
+ {
+ test.startBroker();
+ test.testBasicBytesFlowControl();
+
+ Thread.sleep(1000);
+ }
+ finally
+ {
+ test.stopBroker();
+ }
}
}
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java
index 9f3a8f3cb4..f9cf48a2b1 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java
@@ -47,12 +47,12 @@ public class QueueBrowserAutoAckTest extends FailoverBaseCase
protected Session _clientSession;
protected Queue _queue;
protected static final String MESSAGE_ID_PROPERTY = "MessageIDProperty";
+ protected boolean CLUSTERED = Boolean.getBoolean("profile.clustered");
public void setUp() throws Exception
{
super.setUp();
- _queue = (Queue) getInitialContext().lookup("queue");
//Create Client
_clientConnection = getConnection();
@@ -61,6 +61,9 @@ public class QueueBrowserAutoAckTest extends FailoverBaseCase
setupSession();
+ _queue = _clientSession.createQueue(getTestQueueName());
+ _clientSession.createConsumer(_queue).close();
+
//Ensure there are no messages on the queue to start with.
checkQueueDepth(0);
}
@@ -115,7 +118,7 @@ public class QueueBrowserAutoAckTest extends FailoverBaseCase
{
producerConnection.start();
- Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Session producerSession = producerConnection.createSession(true, Session.AUTO_ACKNOWLEDGE);
//Ensure _queue is created
producerSession.createConsumer(_queue).close();
@@ -128,6 +131,7 @@ public class QueueBrowserAutoAckTest extends FailoverBaseCase
textMsg.setIntProperty(MESSAGE_ID_PROPERTY, messsageID);
producer.send(textMsg);
}
+ producerSession.commit();
producerConnection.close();
}
@@ -452,7 +456,10 @@ public class QueueBrowserAutoAckTest extends FailoverBaseCase
sendMessages("connection1", messages);
- sendMessages("connection2", messages);
+ if (!CLUSTERED)
+ {
+ sendMessages("connection2", messages);
+ }
checkQueueDepth(messages);
@@ -490,7 +497,7 @@ public class QueueBrowserAutoAckTest extends FailoverBaseCase
if (msgCount == failPoint)
{
- failBroker();
+ failBroker(getFailingPort());
}
}
@@ -517,9 +524,12 @@ public class QueueBrowserAutoAckTest extends FailoverBaseCase
int messages = 50;
sendMessages("connection1", messages);
- sendMessages("connection2", messages);
+ if (!CLUSTERED)
+ {
+ sendMessages("connection2", messages);
+ }
- failBroker();
+ failBroker(getFailingPort());
checkQueueDepth(messages);
diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserClientAckTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserClientAckTest.java
index d346aa514c..f30b8043ad 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserClientAckTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserClientAckTest.java
@@ -29,9 +29,6 @@ public class QueueBrowserClientAckTest extends QueueBrowserAutoAckTest
protected void setupSession() throws Exception
{
_clientSession = _clientConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
-
- //Ensure _queue is created
- _clientSession.createConsumer(_queue).close();
}
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserDupsOkTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserDupsOkTest.java
index 37174258dd..b19809b8f2 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserDupsOkTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserDupsOkTest.java
@@ -27,8 +27,5 @@ public class QueueBrowserDupsOkTest extends QueueBrowserAutoAckTest
protected void setupSession() throws Exception
{
_clientSession = _clientConnection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE);
-
- //Ensure _queue is created
- _clientSession.createConsumer(_queue).close();
}
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserNoAckTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserNoAckTest.java
index 0ef788dae3..c97343464c 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserNoAckTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserNoAckTest.java
@@ -29,8 +29,5 @@ public class QueueBrowserNoAckTest extends QueueBrowserAutoAckTest
protected void setupSession() throws Exception
{
_clientSession = _clientConnection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
-
- //Ensure _queue is created
- _clientSession.createConsumer(_queue).close();
}
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserPreAckTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserPreAckTest.java
index 787c12dadb..bb1c0d3698 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserPreAckTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserPreAckTest.java
@@ -28,8 +28,5 @@ public class QueueBrowserPreAckTest extends QueueBrowserAutoAckTest
protected void setupSession() throws Exception
{
_clientSession = _clientConnection.createSession(false, AMQSession.PRE_ACKNOWLEDGE);
-
- //Ensure _queue is created
- _clientSession.createConsumer(_queue).close();
}
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserTransactedTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserTransactedTest.java
index 6e3d6fd890..d79788f017 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserTransactedTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserTransactedTest.java
@@ -27,8 +27,5 @@ public class QueueBrowserTransactedTest extends QueueBrowserAutoAckTest
protected void setupSession() throws Exception
{
_clientSession = _clientConnection.createSession(true, Session.SESSION_TRANSACTED);
-
- //Ensure _queue is created
- _clientSession.createConsumer(_queue).close();
}
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/RollbackOrderTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/RollbackOrderTest.java
new file mode 100644
index 0000000000..ff766c907d
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/client/RollbackOrderTest.java
@@ -0,0 +1,194 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.client;
+
+import org.apache.qpid.test.utils.*;
+import javax.jms.*;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import junit.framework.ComparisonFailure;
+import junit.framework.AssertionFailedError;
+
+/**
+ * RollbackOrderTest, QPID-1864, QPID-1871
+ *
+ * Description:
+ *
+ * The problem that this test is exposing is that the dispatcher used to be capable
+ * of holding on to a message when stopped. This ment that when the rollback was
+ * called and the dispatcher stopped it may have hold of a message. So after all
+ * the local queues(preDeliveryQueue, SynchronousQueue, PostDeliveryTagQueue)
+ * have been cleared the client still had a single message, the one the
+ * dispatcher was holding on to.
+ *
+ * As a result the TxRollback operation would run and then release the dispatcher.
+ * Whilst the dispatcher would then proceed to reject the message it was holiding
+ * the Broker would already have resent that message so the rejection would silently
+ * fail.
+ *
+ * And the client would receieve that single message 'early', depending on the
+ * number of messages already recevied when rollback was called.
+ *
+ *
+ * Aims:
+ *
+ * The tests puts 50 messages on to the queue.
+ *
+ * The test then tries to cause the dispatcher to stop whilst it is in the process
+ * of moving a message from the preDeliveryQueue to a consumers sychronousQueue.
+ *
+ * To exercise this path we have 50 message flowing to the client to give the
+ * dispatcher a bit of work to do moving messages.
+ *
+ * Then we loop - 10 times
+ * - Validating that the first message received is always message 1.
+ * - Receive a few more so that there are a few messages to reject.
+ * - call rollback, to try and catch the dispatcher mid process.
+ *
+ * Outcome:
+ *
+ * The hope is that we catch the dispatcher mid process and cause a BasicReject
+ * to fail. Which will be indicated in the log but will also cause that failed
+ * rejected message to be the next to be delivered which will not be message 1
+ * as expected.
+ *
+ * We are testing a race condition here but we can check through the log file if
+ * the race condition occured. However, performing that check will only validate
+ * the problem exists and will not be suitable as part of a system test.
+ *
+ */
+public class RollbackOrderTest extends QpidTestCase
+{
+
+ private Connection _connection;
+ private Queue _queue;
+ private Session _session;
+ private MessageConsumer _consumer;
+
+ @Override public void setUp() throws Exception
+ {
+ super.setUp();
+ _connection = getConnection();
+
+ _session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+ _queue = _session.createQueue(getTestQueueName());
+ _consumer = _session.createConsumer(_queue);
+
+ //Send more messages so it is more likely that the dispatcher is
+ // processing on rollback.
+ sendMessage(_session, _queue, 50);
+ _session.commit();
+
+ }
+
+ public void testOrderingAfterRollback() throws Exception
+ {
+ //Start the session now so we
+ _connection.start();
+
+ for (int i = 0; i < 20; i++)
+ {
+ Message msg = _consumer.receive();
+ assertEquals("Incorrect Message Received", 0, msg.getIntProperty(INDEX));
+
+ // Pull additional messages through so we have some reject work to do
+ for (int m=0; m < 5 ; m++)
+ {
+ _consumer.receive();
+ }
+
+ System.err.println("ROT-Rollback");
+ _logger.warn("ROT-Rollback");
+ _session.rollback();
+ }
+ }
+
+ public void testOrderingAfterRollbackOnMessage() throws Exception
+ {
+ final CountDownLatch count= new CountDownLatch(20);
+ final Exception exceptions[] = new Exception[20];
+ final AtomicBoolean failed = new AtomicBoolean(false);
+
+ _consumer.setMessageListener(new MessageListener()
+ {
+
+ public void onMessage(Message message)
+ {
+
+ Message msg = message;
+ try
+ {
+ count.countDown();
+ assertEquals("Incorrect Message Received", 0, msg.getIntProperty(INDEX));
+
+ _session.rollback();
+ }
+ catch (JMSException e)
+ {
+ System.out.println("Error:" + e.getMessage());
+ exceptions[(int)count.getCount()] = e;
+ }
+ catch (AssertionFailedError cf)
+ {
+ // End Test if Equality test fails
+ while (count.getCount() != 0)
+ {
+ count.countDown();
+ }
+
+ System.out.println("Error:" + cf.getMessage());
+ System.err.println(cf.getMessage());
+ cf.printStackTrace();
+ failed.set(true);
+ }
+ }
+ });
+ //Start the session now so we
+ _connection.start();
+
+ count.await();
+
+ for (Exception e : exceptions)
+ {
+ if (e != null)
+ {
+ System.err.println(e.getMessage());
+ e.printStackTrace();
+ failed.set(true);
+ }
+ }
+
+// _consumer.close();
+ _connection.close();
+
+ assertFalse("Exceptions thrown during test run, Check Std.err.", failed.get());
+ }
+
+ @Override public void tearDown() throws Exception
+ {
+
+ drainQueue(_queue);
+
+ super.tearDown();
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/failover/FailoverTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/failover/FailoverTest.java
index bf87e8e84f..c307176f3f 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/client/failover/FailoverTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/client/failover/FailoverTest.java
@@ -21,65 +21,70 @@
package org.apache.qpid.test.client.failover;
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQConnectionFactory;
-import org.apache.qpid.client.AMQConnectionURL;
-import org.apache.qpid.client.transport.TransportConnection;
-import org.apache.qpid.jms.ConnectionListener;
-import org.apache.qpid.jms.ConnectionURL;
-import org.apache.qpid.jms.BrokerDetails;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.test.utils.FailoverBaseCase;
-import org.apache.log4j.Logger;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
+import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
-import javax.jms.Queue;
import javax.naming.NamingException;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.jms.ConnectionListener;
+import org.apache.qpid.jms.ConnectionURL;
+import org.apache.qpid.test.utils.FailoverBaseCase;
public class FailoverTest extends FailoverBaseCase implements ConnectionListener
{
private static final Logger _logger = Logger.getLogger(FailoverTest.class);
private static final String QUEUE = "queue";
- private static final int NUM_MESSAGES = 10;
- private Connection connnection;
+ private static final int DEFAULT_NUM_MESSAGES = 10;
+ private static final int DEFAULT_SEED = 20080921;
+ protected int numMessages = 0;
+ protected Connection connection;
private Session producerSession;
private Queue queue;
private MessageProducer producer;
private Session consumerSession;
private MessageConsumer consumer;
- private static int usedBrokers = 0;
private CountDownLatch failoverComplete;
- private static final long DEFAULT_FAILOVER_TIME = 10000L;
+ private boolean CLUSTERED = Boolean.getBoolean("profile.clustered");
+ private int seed;
+ private Random rand;
+ private int _currentPort = getFailingPort();
@Override
protected void setUp() throws Exception
{
super.setUp();
-
- connnection = getConnection();
- ((AMQConnection) connnection).setConnectionListener(this);
- connnection.start();
+
+ numMessages = Integer.getInteger("profile.failoverMsgCount",DEFAULT_NUM_MESSAGES);
+ seed = Integer.getInteger("profile.failoverRandomSeed",DEFAULT_SEED);
+ rand = new Random(seed);
+
+ connection = getConnection();
+ ((AMQConnection) connection).setConnectionListener(this);
+ connection.start();
failoverComplete = new CountDownLatch(1);
}
- private void init(boolean transacted, int mode) throws JMSException, NamingException
+ protected void init(boolean transacted, int mode) throws JMSException, NamingException
{
- queue = (Queue) getInitialContext().lookup(QUEUE);
-
- consumerSession = connnection.createSession(transacted, mode);
+ consumerSession = connection.createSession(transacted, mode);
+ queue = consumerSession.createQueue(getName()+System.currentTimeMillis());
consumer = consumerSession.createConsumer(queue);
- producerSession = connnection.createSession(transacted, mode);
+ producerSession = connection.createSession(transacted, mode);
producer = producerSession.createProducer(queue);
}
@@ -88,7 +93,7 @@ public class FailoverTest extends FailoverBaseCase implements ConnectionListener
{
try
{
- connnection.close();
+ connection.close();
}
catch (Exception e)
{
@@ -98,26 +103,46 @@ public class FailoverTest extends FailoverBaseCase implements ConnectionListener
super.tearDown();
}
- private void consumeMessages(int toConsume, boolean transacted) throws JMSException
+ private void consumeMessages(int startIndex,int endIndex, boolean transacted) throws JMSException
{
Message msg;
- for (int i = 0; i < toConsume; i++)
+ _logger.debug("**************** Receive (Start: " + startIndex + ", End:" + endIndex + ")***********************");
+
+ for (int i = startIndex; i < endIndex; i++)
{
- msg = consumer.receive(1000);
+ msg = consumer.receive(1000);
assertNotNull("Message " + i + " was null!", msg);
- assertEquals("message " + i, ((TextMessage) msg).getText());
+
+ _logger.debug("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+ _logger.debug("Received : " + ((TextMessage) msg).getText());
+ _logger.debug("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+
+ assertEquals("Invalid message order","message " + i, ((TextMessage) msg).getText());
+
}
- if (transacted) {
+ _logger.debug("***********************************************************");
+
+ if (transacted)
+ {
consumerSession.commit();
}
}
- private void sendMessages(int totalMessages, boolean transacted) throws JMSException
+ private void sendMessages(int startIndex,int endIndex, boolean transacted) throws JMSException
{
- for (int i = 0; i < totalMessages; i++)
- {
+ _logger.debug("**************** Send (Start: " + startIndex + ", End:" + endIndex + ")***********************");
+
+ for (int i = startIndex; i < endIndex; i++)
+ {
producer.send(producerSession.createTextMessage("message " + i));
+
+ _logger.debug("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+ _logger.debug("Sending message"+i);
+ _logger.debug("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
}
+
+ _logger.debug("***********************************************************");
+
if (transacted)
{
producerSession.commit();
@@ -126,70 +151,122 @@ public class FailoverTest extends FailoverBaseCase implements ConnectionListener
public void testP2PFailover() throws Exception
{
- testP2PFailover(NUM_MESSAGES, true, false);
+ testP2PFailover(numMessages, true,true, false);
}
- public void testP2PFailoverWithMessagesLeft() throws Exception
+ public void testP2PFailoverWithMessagesLeftToConsumeAndProduce() throws Exception
{
- testP2PFailover(NUM_MESSAGES, false, false);
+ if (CLUSTERED)
+ {
+ testP2PFailover(numMessages, false,false, false);
+ }
}
-
+
+ public void testP2PFailoverWithMessagesLeftToConsume() throws Exception
+ {
+ if (CLUSTERED)
+ {
+ testP2PFailover(numMessages, false,true, false);
+ }
+ }
+
public void testP2PFailoverTransacted() throws Exception
{
- testP2PFailover(NUM_MESSAGES, true, false);
+ testP2PFailover(numMessages, true,true, false);
}
- private void testP2PFailover(int totalMessages, boolean consumeAll, boolean transacted) throws JMSException, NamingException
+ public void testP2PFailoverTransactedWithMessagesLeftToConsumeAndProduce() throws Exception
{
- Message msg = null;
+ // Currently the cluster does not support transactions that span a failover
+ if (CLUSTERED)
+ {
+ testP2PFailover(numMessages, false,false, false);
+ }
+ }
+
+ private void testP2PFailover(int totalMessages, boolean consumeAll, boolean produceAll , boolean transacted) throws JMSException, NamingException
+ {
init(transacted, Session.AUTO_ACKNOWLEDGE);
- sendMessages(totalMessages, transacted);
+ runP2PFailover(totalMessages,consumeAll, produceAll , transacted);
+ }
+
+ protected void runP2PFailover(int totalMessages, boolean consumeAll, boolean produceAll , boolean transacted) throws JMSException, NamingException
+ {
+ Message msg = null;
+ int toProduce = totalMessages;
+
+ _logger.debug("===================================================================");
+ _logger.debug("Total messages used for the test " + totalMessages + " messages");
+ _logger.debug("===================================================================");
+
+ if (!produceAll)
+ {
+ toProduce = totalMessages - rand.nextInt(totalMessages);
+ }
+
+ _logger.debug("==================");
+ _logger.debug("Sending " + toProduce + " messages");
+ _logger.debug("==================");
+
+ sendMessages(0,toProduce, transacted);
// Consume some messages
- int toConsume = totalMessages;
+ int toConsume = toProduce;
if (!consumeAll)
{
- toConsume = totalMessages / 2;
+ toConsume = toProduce - rand.nextInt(toProduce);
}
+
+ consumeMessages(0,toConsume, transacted);
- consumeMessages(toConsume, transacted);
-
+ _logger.debug("==================");
+ _logger.debug("Consuming " + toConsume + " messages");
+ _logger.debug("==================");
+
_logger.info("Failing over");
- causeFailure(DEFAULT_FAILOVER_TIME);
-
- msg = consumer.receive(500);
-
- assertNull("Should not have received message from new broker!", msg);
- // Check that messages still sent / received
- sendMessages(totalMessages, transacted);
- consumeMessages(totalMessages, transacted);
+ causeFailure(_currentPort, DEFAULT_FAILOVER_TIME);
+
+ // Check that you produce and consume the rest of messages.
+ _logger.debug("==================");
+ _logger.debug("Sending " + (totalMessages-toProduce) + " messages");
+ _logger.debug("==================");
+
+ sendMessages(toProduce,totalMessages, transacted);
+ consumeMessages(toConsume,totalMessages, transacted);
+
+ _logger.debug("==================");
+ _logger.debug("Consuming " + (totalMessages-toConsume) + " messages");
+ _logger.debug("==================");
}
- private void causeFailure(long delay)
+ private void causeFailure(int port, long delay)
{
- failBroker();
+ failBroker(port);
_logger.info("Awaiting Failover completion");
try
{
- failoverComplete.await(delay, TimeUnit.MILLISECONDS);
+ if (!failoverComplete.await(delay, TimeUnit.MILLISECONDS))
+ {
+ fail("failover did not complete");
+ }
}
catch (InterruptedException e)
{
//evil ignore IE.
}
}
-
+
public void testClientAckFailover() throws Exception
{
init(false, Session.CLIENT_ACKNOWLEDGE);
- sendMessages(1, false);
+ sendMessages(0,1, false);
Message msg = consumer.receive();
assertNotNull("Expected msgs not received", msg);
- causeFailure(DEFAULT_FAILOVER_TIME);
+ causeFailure(getFailingPort(), DEFAULT_FAILOVER_TIME);
Exception failure = null;
try
@@ -201,7 +278,7 @@ public class FailoverTest extends FailoverBaseCase implements ConnectionListener
failure = e;
}
assertNotNull("Exception should be thrown", failure);
- }
+ }
/**
* The client used to have a fixed timeout of 4 minutes after which failover would no longer work.
@@ -209,6 +286,7 @@ public class FailoverTest extends FailoverBaseCase implements ConnectionListener
*
* @throws Exception if something unexpected occurs in the test.
*/
+
public void test4MinuteFailover() throws Exception
{
ConnectionURL connectionURL = getConnectionFactory().getConnectionURL();
@@ -221,12 +299,12 @@ public class FailoverTest extends FailoverBaseCase implements ConnectionListener
details.setProperty(BrokerDetails.OPTIONS_RETRY, String.valueOf(RETRIES));
details.setProperty(BrokerDetails.OPTIONS_CONNECT_DELAY, String.valueOf(DELAY));
- connnection = new AMQConnection(connectionURL, null);
+ connection = new AMQConnection(connectionURL, null);
- ((AMQConnection) connnection).setConnectionListener(this);
+ ((AMQConnection) connection).setConnectionListener(this);
//Start the connection
- connnection.start();
+ connection.start();
long FAILOVER_DELAY = (RETRIES * DELAY);
@@ -234,12 +312,58 @@ public class FailoverTest extends FailoverBaseCase implements ConnectionListener
long failTime = System.nanoTime() + FAILOVER_DELAY * 1000000;
//Fail the first broker
- causeFailure(FAILOVER_DELAY + DEFAULT_FAILOVER_TIME);
+ causeFailure(getFailingPort(), FAILOVER_DELAY + DEFAULT_FAILOVER_TIME);
//Reconnection should occur
assertTrue("Failover did not take long enough", System.nanoTime() > failTime);
}
+
+ /**
+ * The idea is to run a failover test in a loop by failing over
+ * to the other broker each time.
+ */
+ public void testFailoverInALoop() throws Exception
+ {
+ if (!CLUSTERED)
+ {
+ return;
+ }
+
+ int iterations = Integer.getInteger("profile.failoverIterations",0);
+ boolean useAltPort = false;
+ int altPort = FAILING_PORT;
+ int stdPort = DEFAULT_PORT;
+ init(false, Session.AUTO_ACKNOWLEDGE);
+ for (int i=0; i < iterations; i++)
+ {
+ _logger.debug("===================================================================");
+ _logger.debug("Failover In a loop : iteration number " + i);
+ _logger.debug("===================================================================");
+
+ runP2PFailover(numMessages, false,false, false);
+ startBroker(_currentPort);
+ if (useAltPort)
+ {
+ _currentPort = altPort;
+ useAltPort = false;
+ }
+ else
+ {
+ _currentPort = stdPort;
+ useAltPort = true;
+ }
+
+ }
+ //To prevent any failover logic being initiated when we shutdown the brokers.
+ connection.close();
+
+ // Shutdown the brokers
+ stopBroker(altPort);
+ stopBroker(stdPort);
+
+ }
+
public void bytesSent(long count)
{
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/message/JMSDestinationTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/message/JMSDestinationTest.java
new file mode 100644
index 0000000000..60db1a25d7
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/client/message/JMSDestinationTest.java
@@ -0,0 +1,330 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.client.message;
+
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.client.CustomJMSXProperty;
+import org.apache.qpid.client.configuration.ClientProperties;
+import org.apache.qpid.management.common.mbeans.ManagedQueue;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.TabularData;
+import java.nio.BufferOverflowException;
+import java.util.Iterator;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * From the API Docs getJMSDestination:
+ *
+ * When a message is received, its JMSDestination value must be equivalent to
+ * the value assigned when it was sent.
+ */
+public class JMSDestinationTest extends QpidTestCase
+{
+
+ private Connection _connection;
+ private Session _session;
+
+ private static final String USER = "admin";
+ private CountDownLatch _receiveMessage;
+ private Message _message;
+
+ public void setUp() throws Exception
+ {
+ //Ensure JMX management is enabled for MovedToQueue test
+ setConfigurationProperty("management.enabled", "true");
+
+ super.setUp();
+
+ _connection = getConnection();
+
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ }
+
+ /**
+ * Test a message sent to a queue comes back with JMSDestination queue
+ *
+ * @throws Exception
+ */
+ public void testQueue() throws Exception
+ {
+
+ Queue queue = _session.createQueue(getTestQueueName());
+
+ MessageConsumer consumer = _session.createConsumer(queue);
+
+ sendMessage(_session, queue, 1);
+
+ _connection.start();
+
+ Message message = consumer.receive(10000);
+
+ assertNotNull("Message should not be null", message);
+
+ Destination destination = message.getJMSDestination();
+
+ assertNotNull("JMSDestination should not be null", destination);
+
+ assertEquals("Incorrect Destination type", queue.getClass(), destination.getClass());
+ }
+
+ /**
+ * Test a message sent to a topic comes back with JMSDestination topic
+ *
+ * @throws Exception
+ */
+ public void testTopic() throws Exception
+ {
+
+ Topic topic = _session.createTopic(getTestQueueName() + "Topic");
+
+ MessageConsumer consumer = _session.createConsumer(topic);
+
+ sendMessage(_session, topic, 1);
+
+ _connection.start();
+
+ Message message = consumer.receive(10000);
+
+ assertNotNull("Message should not be null", message);
+
+ Destination destination = message.getJMSDestination();
+
+ assertNotNull("JMSDestination should not be null", destination);
+
+ assertEquals("Incorrect Destination type", topic.getClass(), destination.getClass());
+ }
+
+ /**
+ * Test a message sent to a topic then moved on the broker
+ * comes back with JMSDestination queue.
+ *
+ * i.e. The client is not just setting the value to be the same as the
+ * current consumer destination.
+ *
+ * This test can only be run against the Java broker as it uses JMX to move
+ * messages between queues.
+ *
+ * @throws Exception
+ */
+ public void testMovedToQueue() throws Exception
+ {
+ // Setup JMXUtils
+ JMXTestUtils jmxUtils = new JMXTestUtils(this, USER, USER);
+ jmxUtils.setUp();
+ // Open the JMX Connection
+ jmxUtils.open();
+ try
+ {
+
+ Queue queue = _session.createQueue(getTestQueueName());
+
+ _session.createConsumer(queue).close();
+
+ sendMessage(_session, queue, 1);
+
+ Topic topic = _session.createTopic(getTestQueueName() + "Topic");
+
+ MessageConsumer consumer = _session.createConsumer(topic);
+
+ // Use Management to move message.
+
+ ManagedQueue managedQueue = jmxUtils.
+ getManagedObject(ManagedQueue.class,
+ jmxUtils.getQueueObjectName(getConnectionFactory().getVirtualPath().substring(1),
+ getTestQueueName()));
+
+ // Find the first message on the queue
+ TabularData data = managedQueue.viewMessages(1L, 2L);
+
+ Iterator values = data.values().iterator();
+ assertTrue("No Messages found via JMX", values.hasNext());
+
+ // Get its message ID
+ Long msgID = (Long) ((CompositeDataSupport) values.next()).get("AMQ MessageId");
+
+ // Start the connection and consume message that has been moved to the
+ // queue
+ _connection.start();
+
+ Message message = consumer.receive(1000);
+
+ //Validate we don't have a message on the queue before we start
+ assertNull("Message should be null", message);
+
+ // Move it to from the topic to the queue
+ managedQueue.moveMessages(msgID, msgID, ((AMQTopic) topic).getQueueName());
+
+ // Retrieve the newly moved message
+ message = consumer.receive(1000);
+
+ assertNotNull("Message should not be null", message);
+
+ Destination destination = message.getJMSDestination();
+
+ assertNotNull("JMSDestination should not be null", destination);
+
+ assertEquals("Incorrect Destination type", queue.getClass(), destination.getClass());
+
+ }
+ finally
+ {
+ jmxUtils.close();
+ }
+
+ }
+
+ /**
+ * Test a message sent to a queue comes back with JMSDestination queue
+ * when received via a message listener
+ *
+ * @throws Exception
+ */
+ public void testQueueAsync() throws Exception
+ {
+
+ Queue queue = _session.createQueue(getTestQueueName());
+
+ MessageConsumer consumer = _session.createConsumer(queue);
+
+ sendMessage(_session, queue, 1);
+
+ _connection.start();
+
+ _message = null;
+ _receiveMessage = new CountDownLatch(1);
+
+ consumer.setMessageListener(new MessageListener()
+ {
+ public void onMessage(Message message)
+ {
+ _message = message;
+ _receiveMessage.countDown();
+ }
+ });
+
+ assertTrue("Timed out waiting for message to be received ", _receiveMessage.await(1, TimeUnit.SECONDS));
+
+ assertNotNull("Message should not be null", _message);
+
+ Destination destination = _message.getJMSDestination();
+
+ assertNotNull("JMSDestination should not be null", destination);
+
+ assertEquals("Incorrect Destination type", queue.getClass(), destination.getClass());
+ }
+
+ /**
+ * Test a message received without the JMS_QPID_DESTTYPE can be resent
+ * and correctly have the property set.
+ *
+ * To do this we need to create a 0-10 connection and send a message
+ * which is then received by a 0-8/9 client.
+ *
+ * @throws Exception
+ */
+ public void testReceiveResend() throws Exception
+ {
+ // Create a 0-10 Connection and send message
+ setSystemProperty(ClientProperties.AMQP_VERSION, "0-10");
+
+ Connection connection010 = getConnection();
+
+ Session session010 = connection010.createSession(true, Session.SESSION_TRANSACTED);
+
+ // Create queue for testing
+ Queue queue = session010.createQueue(getTestQueueName());
+
+ // Ensure queue exists
+ session010.createConsumer(queue).close();
+
+ sendMessage(session010, queue, 1);
+
+ // Close the 010 connection
+ connection010.close();
+
+ // Create a 0-8 Connection and receive message
+ setSystemProperty(ClientProperties.AMQP_VERSION, "0-8");
+
+ Connection connection08 = getConnection();
+
+ Session session08 = connection08.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ MessageConsumer consumer = session08.createConsumer(queue);
+
+ connection08.start();
+
+ Message message = consumer.receive(1000);
+
+ assertNotNull("Didn't receive 0-10 message.", message);
+
+ // Validate that JMS_QPID_DESTTYPE is not set
+ try
+ {
+ message.getIntProperty(CustomJMSXProperty.JMS_QPID_DESTTYPE.toString());
+ fail("JMS_QPID_DESTTYPE should not be set, so should throw NumberFormatException");
+ }
+ catch (NumberFormatException nfe)
+ {
+
+ }
+
+ // Resend message back to queue and validate that
+ // a) getJMSDestination works without the JMS_QPID_DESTTYPE
+ // b) we can actually send without a BufferOverFlow.
+
+ MessageProducer producer = session08.createProducer(queue);
+
+ try
+ {
+ producer.send(message);
+ }
+ catch (BufferOverflowException bofe)
+ {
+ // Print the stack trace so we can validate where the execption occured.
+ bofe.printStackTrace();
+ fail("BufferOverflowException thrown during send");
+ }
+
+ message = consumer.receive(1000);
+
+ assertNotNull("Didn't receive recent 0-8 message.", message);
+
+ // Validate that JMS_QPID_DESTTYPE is not set
+ assertEquals("JMS_QPID_DESTTYPE should be set to a Queue", AMQDestination.QUEUE_TYPE,
+ message.getIntProperty(CustomJMSXProperty.JMS_QPID_DESTTYPE.toString()));
+
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/message/MessageToStringTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/message/MessageToStringTest.java
index 1744b92d62..39861bb2d5 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/client/message/MessageToStringTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/client/message/MessageToStringTest.java
@@ -21,7 +21,9 @@
package org.apache.qpid.test.client.message;
import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.framing.AMQShortString;
import javax.jms.BytesMessage;
import javax.jms.Connection;
@@ -57,12 +59,16 @@ public class MessageToStringTest extends QpidTestCase
//Create Producer put some messages on the queue
_connection = getConnection();
- //Create Queue
- _queue = new AMQQueue("amq.direct", "queue");
-
//Create Consumer
_session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ String queueName = getTestQueueName();
+
+ //Create Queue
+ ((AMQSession) _session).createQueue(new AMQShortString(queueName), true, false, false);
+ _queue = _session.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='false'&autodelete='true'");
+
+
_consumer = _session.createConsumer(_queue);
_connection.start();
diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/message/ObjectMessageTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/message/ObjectMessageTest.java
new file mode 100644
index 0000000000..f0bbcc7003
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/client/message/ObjectMessageTest.java
@@ -0,0 +1,141 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.client.message;
+
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.framing.AMQShortString;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.ObjectMessage;
+import javax.jms.Queue;
+import javax.jms.Session;
+import java.util.UUID;
+
+public class ObjectMessageTest extends QpidTestCase
+{
+ private Connection _connection;
+ private Session _session;
+ MessageConsumer _consumer;
+ MessageProducer _producer;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+
+ //Create Connection
+ _connection = getConnection();
+
+
+ //Create Session
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ //Create Queue
+ String queueName = getTestQueueName();
+ ((AMQSession) _session).createQueue(new AMQShortString(queueName), true, false, false);
+ Queue queue = _session.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='false'&autodelete='true'");
+
+ //Create Consumer
+ _consumer = _session.createConsumer(queue);
+
+ //Create Producer
+ _producer = _session.createProducer(queue);
+
+ _connection.start();
+ }
+
+ public void tearDown() throws Exception
+ {
+ //clean up
+ _connection.close();
+
+ super.tearDown();
+ }
+
+ public void testGetAndSend() throws JMSException
+ {
+ //Create Sample Message using UUIDs
+ UUID test = UUID.randomUUID();
+
+ ObjectMessage testMessage = _session.createObjectMessage(test);
+
+ Object o = testMessage.getObject();
+
+ assertNotNull("Object was null", o);
+
+ sendAndTest(testMessage, test);
+ }
+
+ public void testSend() throws JMSException
+ {
+ //Create Sample Message using UUIDs
+ UUID test = UUID.randomUUID();
+
+ ObjectMessage testMessage = _session.createObjectMessage(test);
+
+ sendAndTest(testMessage, test);
+ }
+
+ public void testTostringAndSend() throws JMSException
+ {
+ //Create Sample Message using UUIDs
+ UUID test = UUID.randomUUID();
+
+ ObjectMessage testMessage = _session.createObjectMessage(test);
+
+ assertNotNull("Object was null", testMessage.toString());
+
+ sendAndTest(testMessage, test);
+ }
+
+ public void testSendNull() throws JMSException
+ {
+
+ ObjectMessage testMessage = _session.createObjectMessage(null);
+
+ assertNotNull("Object was null", testMessage.toString());
+
+ sendAndTest(testMessage, null);
+ }
+
+ //***************** Helpers
+
+ private void sendAndTest(ObjectMessage message, Object sent) throws JMSException
+ {
+ _producer.send(message);
+
+ ObjectMessage receivedMessage = (ObjectMessage) _consumer.receive(1000);
+
+ assertNotNull("Message was not received.", receivedMessage);
+
+ UUID result = (UUID) receivedMessage.getObject();
+
+ assertEquals("First read: UUIDs were not equal", sent, result);
+
+ result = (UUID) receivedMessage.getObject();
+
+ assertEquals("Second read: UUIDs were not equal", sent, result);
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/message/SelectorTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/message/SelectorTest.java
new file mode 100644
index 0000000000..a09589b121
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/client/message/SelectorTest.java
@@ -0,0 +1,310 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.client.message;
+
+import java.util.concurrent.CountDownLatch;
+
+import javax.jms.DeliveryMode;
+import javax.jms.InvalidSelectorException;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+import junit.framework.Assert;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.BasicMessageProducer;
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SelectorTest extends QpidTestCase implements MessageListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(SelectorTest.class);
+
+ private AMQConnection _connection;
+ private AMQDestination _destination;
+ private int count;
+ public String _connectionString = "vm://:1";
+ private static final String INVALID_SELECTOR = "Cost LIKE 5";
+ CountDownLatch _responseLatch = new CountDownLatch(1);
+
+ private static final String BAD_MATHS_SELECTOR = " 1 % 5";
+
+ private static final long RECIEVE_TIMEOUT = 1000;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ init((AMQConnection) getConnection("guest", "guest"));
+ }
+
+ private void init(AMQConnection connection) throws JMSException
+ {
+ init(connection, new AMQQueue(connection, getTestQueueName(), true));
+ }
+
+ private void init(AMQConnection connection, AMQDestination destination) throws JMSException
+ {
+ _connection = connection;
+ _destination = destination;
+ connection.start();
+ }
+
+ public void onMessage(Message message)
+ {
+ count++;
+ _logger.info("Got Message:" + message);
+ _responseLatch.countDown();
+ }
+
+ public void testUsingOnMessage() throws Exception
+ {
+ String selector = "Cost = 2 AND \"property-with-hyphen\" = 'wibble'";
+ // selector = "JMSType = Special AND Cost = 2 AND AMQMessageID > 0 AND JMSDeliveryMode=" + DeliveryMode.NON_PERSISTENT;
+
+ Session session = (AMQSession) _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+ // _session.createConsumer(destination).setMessageListener(this);
+ session.createConsumer(_destination, selector).setMessageListener(this);
+
+ try
+ {
+ Message msg = session.createTextMessage("Message");
+ msg.setJMSPriority(1);
+ msg.setIntProperty("Cost", 2);
+ msg.setStringProperty("property-with-hyphen", "wibble");
+ msg.setJMSType("Special");
+
+ _logger.info("Sending Message:" + msg);
+
+ ((BasicMessageProducer) session.createProducer(_destination)).send(msg, DeliveryMode.NON_PERSISTENT);
+ _logger.info("Message sent, waiting for response...");
+
+ _responseLatch.await();
+
+ if (count > 0)
+ {
+ _logger.info("Got message");
+ }
+
+ if (count == 0)
+ {
+ fail("Did not get message!");
+ // throw new RuntimeException("Did not get message!");
+ }
+ }
+ catch (JMSException e)
+ {
+ _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
+ if (!(e instanceof InvalidSelectorException))
+ {
+ fail("Wrong exception:" + e.getMessage());
+ }
+ else
+ {
+ System.out.println("SUCCESS!!");
+ }
+ }
+ catch (InterruptedException e)
+ {
+ _logger.debug("IE :" + e.getClass().getSimpleName() + ":" + e.getMessage());
+ }
+
+ }
+
+ public void testUnparsableSelectors() throws Exception
+ {
+ AMQSession session = (AMQSession) _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+ boolean caught = false;
+
+ //Try Creating a Browser
+ try
+ {
+ session.createBrowser(session.createQueue("Ping"), INVALID_SELECTOR);
+ }
+ catch (JMSException e)
+ {
+ _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
+ if (!(e instanceof InvalidSelectorException))
+ {
+ fail("Wrong exception:" + e.getMessage());
+ }
+ caught = true;
+ }
+ assertTrue("No exception thrown!", caught);
+ caught = false;
+
+ //Try Creating a Consumer
+ try
+ {
+ session.createConsumer(session.createQueue("Ping"), INVALID_SELECTOR);
+ }
+ catch (JMSException e)
+ {
+ _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
+ if (!(e instanceof InvalidSelectorException))
+ {
+ fail("Wrong exception:" + e.getMessage());
+ }
+ caught = true;
+ }
+ assertTrue("No exception thrown!", caught);
+ caught = false;
+
+ //Try Creating a Receiever
+ try
+ {
+ session.createReceiver(session.createQueue("Ping"), INVALID_SELECTOR);
+ }
+ catch (JMSException e)
+ {
+ _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
+ if (!(e instanceof InvalidSelectorException))
+ {
+ fail("Wrong exception:" + e.getMessage());
+ }
+ caught = true;
+ }
+ assertTrue("No exception thrown!", caught);
+ caught = false;
+
+ try
+ {
+ session.createReceiver(session.createQueue("Ping"), BAD_MATHS_SELECTOR);
+ }
+ catch (JMSException e)
+ {
+ _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
+ if (!(e instanceof InvalidSelectorException))
+ {
+ fail("Wrong exception:" + e.getMessage());
+ }
+ caught = true;
+ }
+ assertTrue("No exception thrown!", caught);
+ caught = false;
+
+ }
+
+ public void testRuntimeSelectorError() throws JMSException
+ {
+ Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ MessageConsumer consumer = session.createConsumer(_destination , "testproperty % 5 = 1");
+ MessageProducer producer = session.createProducer(_destination);
+ Message sentMsg = session.createTextMessage();
+
+ sentMsg.setIntProperty("testproperty", 1); // 1 % 5
+ producer.send(sentMsg);
+ Message recvd = consumer.receive(RECIEVE_TIMEOUT);
+ assertNotNull(recvd);
+
+ sentMsg.setStringProperty("testproperty", "hello"); // "hello" % 5 makes no sense
+ producer.send(sentMsg);
+ try
+ {
+ recvd = consumer.receive(RECIEVE_TIMEOUT);
+ assertNull(recvd);
+ }
+ catch (Exception e)
+ {
+
+ }
+ assertTrue("Connection should be closed", _connection.isClosed());
+ }
+
+ public void testSelectorWithJMSMessageID() throws Exception
+ {
+ Session session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+
+ MessageProducer prod = session.createProducer(_destination);
+ MessageConsumer consumer = session.createConsumer(_destination,"JMSMessageID IS NOT NULL");
+
+ for (int i=0; i<2; i++)
+ {
+ Message msg = session.createTextMessage("Msg" + String.valueOf(i));
+ prod.send(msg);
+ }
+ session.commit();
+
+ Message msg1 = consumer.receive(1000);
+ Message msg2 = consumer.receive(1000);
+
+ Assert.assertNotNull("Msg1 should not be null", msg1);
+ Assert.assertNotNull("Msg2 should not be null", msg2);
+
+ session.commit();
+
+ prod.setDisableMessageID(true);
+
+ for (int i=0; i<2; i++)
+ {
+ Message msg = session.createTextMessage("Msg" + String.valueOf(i));
+ prod.send(msg);
+ }
+
+ session.commit();
+ Message msg3 = consumer.receive(1000);
+ Assert.assertNull("Msg3 should be null", msg3);
+ session.commit();
+ consumer = session.createConsumer(_destination,"JMSMessageID IS NULL");
+
+ Message msg4 = consumer.receive(1000);
+ Message msg5 = consumer.receive(1000);
+ session.commit();
+ Assert.assertNotNull("Msg4 should not be null", msg4);
+ Assert.assertNotNull("Msg5 should not be null", msg5);
+ }
+
+ public static void main(String[] argv) throws Exception
+ {
+ SelectorTest test = new SelectorTest();
+ test._connectionString = (argv.length == 0) ? "localhost:3000" : argv[0];
+
+ try
+ {
+ while (true)
+ {
+ if (test._connectionString.contains("vm://:1"))
+ {
+ test.setUp();
+ }
+ test.testUsingOnMessage();
+
+ if (test._connectionString.contains("vm://:1"))
+ {
+ test.tearDown();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ System.err.println(e.getMessage());
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/timeouts/SyncWaitDelayTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/timeouts/SyncWaitDelayTest.java
new file mode 100644
index 0000000000..a123fb290c
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/client/timeouts/SyncWaitDelayTest.java
@@ -0,0 +1,112 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.client.timeouts;
+
+import java.io.File;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry;
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This tests that when the commit takes a long time(due to POST_COMMIT_DELAY) that the commit does not timeout
+ * This test must be run in conjunction with SyncWaiteTimeoutDelay or be run with POST_COMMIT_DELAY > 30s to ensure
+ * that the default value is being replaced.
+ */
+public class SyncWaitDelayTest extends QpidTestCase
+{
+ protected static final Logger _logger = LoggerFactory.getLogger(SyncWaitDelayTest.class);
+
+ private String VIRTUALHOST = "test";
+ protected long POST_COMMIT_DELAY = 1000L;
+ protected long SYNC_WRITE_TIMEOUT = POST_COMMIT_DELAY + 1000;
+
+ protected Connection _connection;
+ protected Session _session;
+ protected Queue _queue;
+ protected MessageConsumer _consumer;
+
+ public void setUp() throws Exception
+ {
+
+ setConfigurationProperty("virtualhosts.virtualhost." + VIRTUALHOST+".store.class", "org.apache.qpid.server.store.SlowMessageStore");
+ setConfigurationProperty("virtualhosts.virtualhost." + VIRTUALHOST+".store.delays.commitTran.post", String.valueOf(POST_COMMIT_DELAY));
+ setConfigurationProperty("management.enabled", "false");
+
+
+ super.setUp();
+
+ //Set the syncWrite timeout to be just larger than the delay on the commitTran.
+ setSystemProperty("amqj.default_syncwrite_timeout", String.valueOf(SYNC_WRITE_TIMEOUT));
+
+ _connection = getConnection();
+
+ //Create Queue
+ _queue = (Queue) getInitialContext().lookup("queue");
+
+ //Create Consumer
+ _session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+
+ //Ensure Queue exists
+ _session.createConsumer(_queue).close();
+ }
+
+
+ public void test() throws JMSException
+ {
+ MessageProducer producer = _session.createProducer(_queue);
+
+ Message message = _session.createTextMessage("Message");
+
+ producer.send(message);
+
+ long start = System.nanoTime();
+
+ _logger.info("Calling Commit");
+
+ try
+ {
+ _session.commit();
+ long end = System.nanoTime();
+ long time = (end - start);
+ // As we are using Nano time ensure to multiply up the millis.
+ assertTrue("Commit was quickier than the built in delay:" + time, time > 1000000L * POST_COMMIT_DELAY);
+ assertFalse("Commit was slower than the built in default", time > 1000000L * 1000 * 30);
+ }
+ catch (JMSException e)
+ {
+ fail(e.getMessage());
+ }
+
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/timeouts/SyncWaitTimeoutDelayTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/timeouts/SyncWaitTimeoutDelayTest.java
new file mode 100644
index 0000000000..1a23eee8ab
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/client/timeouts/SyncWaitTimeoutDelayTest.java
@@ -0,0 +1,72 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.client.timeouts;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.qpid.AMQTimeoutException;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+
+/** This tests that when the syncWrite timeout is set that it will timeout on that time rather than the default 30s. */
+public class SyncWaitTimeoutDelayTest extends SyncWaitDelayTest
+{
+ protected static final Logger _logger = Logger.getLogger(SyncWaitTimeoutDelayTest.class);
+
+ public void setUp() throws Exception
+ {
+ POST_COMMIT_DELAY = 1000L;
+
+ //Set the syncWrite timeout to be less than the COMMIT Delay so we can validate that it is being applied
+ SYNC_WRITE_TIMEOUT = 500L;
+
+ super.setUp();
+ }
+
+ @Override
+ public void test() throws JMSException
+ {
+ MessageProducer producer = _session.createProducer(_queue);
+
+ Message message = _session.createTextMessage("Message");
+
+ producer.send(message);
+
+ _logger.info("Calling Commit");
+
+ long start = System.nanoTime();
+ try
+ {
+ _session.commit();
+ fail("Commit occured even though syncWait timeout is shorter than delay in commit");
+ }
+ catch (JMSException e)
+ {
+ assertTrue("Wrong exception type received.", e.getLinkedException() instanceof AMQTimeoutException);
+ assertTrue("Wrong message received on exception.", e.getMessage().startsWith("Failed to commit"));
+ // As we are using Nano time ensure to multiply up the millis.
+ assertTrue("Timeout was more than 30s default", (System.nanoTime() - start) < (1000000L * 1000 * 30));
+ }
+
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkBaseCase.java b/java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkBaseCase.java
index eb51a32166..5a76ff251b 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkBaseCase.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkBaseCase.java
@@ -189,6 +189,7 @@ public class FrameworkBaseCase extends QpidTestCase implements FrameworkTestCont
*/
protected void setUp() throws Exception
{
+ super.setUp();
NDC.push(getName());
testProps = TestContextProperties.getInstance(MessagingTestConfigProperties.defaults);
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/package.html b/java/systests/src/main/java/org/apache/qpid/test/framework/package.html
index 92fe40d529..ac4e30d312 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/framework/package.html
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/package.html
@@ -1,3 +1,24 @@
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
<html>
<body>
<p/>A framework for testing Qpid, built around a standard 'test circuit' design. The idea behind this framework is the
@@ -19,4 +40,4 @@ code locally. Where the receiving end is distributed accross one or more machine
test report gethered from all of the receivers. Test code will be written to the assertions making as few assumptions
as possible about the exact test topology.
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/qpid/InVMBrokerDecorator.java b/java/systests/src/main/java/org/apache/qpid/test/framework/qpid/InVMBrokerDecorator.java
index e0fddb10b7..b92a72a654 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/framework/qpid/InVMBrokerDecorator.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/framework/qpid/InVMBrokerDecorator.java
@@ -88,6 +88,7 @@ public class InVMBrokerDecorator extends WrappedSuiteTestDecorator
// Ensure that the in-vm broker is created.
try
{
+ ApplicationRegistry.getInstance(1);
TransportConnection.createVMBroker(1);
}
catch (AMQVMBrokerCreationException e)
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/ack/Acknowledge2ConsumersTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/ack/Acknowledge2ConsumersTest.java
new file mode 100644
index 0000000000..4b45a96c20
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/ack/Acknowledge2ConsumersTest.java
@@ -0,0 +1,193 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.test.unit.ack;
+
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.test.utils.FailoverBaseCase;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+public class Acknowledge2ConsumersTest extends FailoverBaseCase
+{
+ protected static int NUM_MESSAGES = 100;
+ protected Connection _con;
+ protected Queue _queue;
+ private Session _producerSession;
+ private Session _consumerSession;
+ private MessageConsumer _consumerA;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ _queue = (Queue) getInitialContext().lookup("queue");
+
+ //Create Producer put some messages on the queue
+ _con = getConnection();
+ }
+
+ private void init(boolean transacted, int mode) throws JMSException
+ {
+ _producerSession = _con.createSession(true, Session.SESSION_TRANSACTED);
+ _consumerSession = _con.createSession(transacted, mode);
+ _consumerA = _consumerSession.createConsumer(_queue);
+ _con.start();
+ }
+
+ /**
+ * Produces Messages that
+ *
+ * @param transacted
+ * @param mode
+ *
+ * @throws Exception
+ */
+ private void test2ConsumersAcking(boolean transacted, int mode) throws Exception
+ {
+ init(transacted, mode);
+
+ // These should all end up being prefetched by sessionA
+ sendMessage(_producerSession, _queue, NUM_MESSAGES / 2);
+
+ //Create a second consumer (consumerB) to consume some of the messages
+ MessageConsumer consumerB = _consumerSession.createConsumer(_queue);
+
+ // These messages should be roundrobined between A and B
+ sendMessage(_producerSession, _queue, NUM_MESSAGES / 2);
+
+ int count = 0;
+ //Use consumerB to receive messages it has
+ Message msg = consumerB.receive(1500);
+ while (msg != null)
+ {
+ if (mode == Session.CLIENT_ACKNOWLEDGE)
+ {
+ msg.acknowledge();
+ }
+ count++;
+ msg = consumerB.receive(1500);
+ }
+ if (transacted)
+ {
+ _consumerSession.commit();
+ }
+
+ // Close the consumers
+ _consumerA.close();
+ consumerB.close();
+
+ // and close the session to release any prefetched messages.
+ _consumerSession.close();
+ assertEquals("Wrong number of messages on queue", NUM_MESSAGES - count,
+ ((AMQSession) _producerSession).getQueueDepth((AMQDestination) _queue));
+
+ // Clean up messages that may be left on the queue
+ _consumerSession = _con.createSession(transacted, mode);
+ _consumerA = _consumerSession.createConsumer(_queue);
+ msg = _consumerA.receive(1500);
+ while (msg != null)
+ {
+ if (mode == Session.CLIENT_ACKNOWLEDGE)
+ {
+ msg.acknowledge();
+ }
+ msg = _consumerA.receive(1500);
+ }
+ _consumerA.close();
+ if (transacted)
+ {
+ _consumerSession.commit();
+ }
+ _consumerSession.close();
+ }
+
+ public void test2ConsumersAutoAck() throws Exception
+ {
+ test2ConsumersAcking(false, Session.AUTO_ACKNOWLEDGE);
+ }
+
+ public void test2ConsumersClientAck() throws Exception
+ {
+ test2ConsumersAcking(false, Session.CLIENT_ACKNOWLEDGE);
+ }
+
+ public void test2ConsumersTx() throws Exception
+ {
+ test2ConsumersAcking(true, Session.SESSION_TRANSACTED);
+ }
+
+
+
+//
+// /**
+// * Check that session level acknowledge does correctly ack all previous
+// * values. Send 3 messages(0,1,2) then ack 1 and 2. If session ack is
+// * working correctly then acking 1 will also ack 0. Acking 2 will not
+// * attempt to re-ack 0 and 1.
+// *
+// * @throws Exception
+// */
+// public void testSessionAck() throws Exception
+// {
+// init(false, Session.CLIENT_ACKNOWLEDGE);
+//
+// sendMessage(_producerSession, _queue, 3);
+// Message msg;
+//
+// // Drop msg 0
+// _consumerA.receive(RECEIVE_TIMEOUT);
+//
+// // Take msg 1
+// msg = _consumerA.receive(RECEIVE_TIMEOUT);
+//
+// assertNotNull("Message 1 not correctly received.", msg);
+// assertEquals("Incorrect message received", 1, msg.getIntProperty(INDEX));
+//
+// // This should also ack msg 0
+// msg.acknowledge();
+//
+// // Take msg 2
+// msg = _consumerA.receive(RECEIVE_TIMEOUT);
+//
+// assertNotNull("Message 2 not correctly received.", msg);
+// assertEquals("Incorrect message received", 2, msg.getIntProperty(INDEX));
+//
+// // This should just ack msg 2
+// msg.acknowledge();
+//
+// _consumerA.close();
+// _consumerSession.close();
+//
+// assertEquals("Queue not empty.", 0,
+// ((AMQSession) _producerSession).getQueueDepth((AMQDestination) _queue));
+// _con.close();
+//
+//
+// }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverOnMessageTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverOnMessageTest.java
new file mode 100644
index 0000000000..7c5db290c4
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverOnMessageTest.java
@@ -0,0 +1,356 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.ack;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.jms.ConnectionListener;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.Session;
+import javax.jms.TransactionRolledBackException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class AcknowledgeAfterFailoverOnMessageTest extends AcknowledgeOnMessageTest implements ConnectionListener
+{
+
+ protected CountDownLatch _failoverCompleted = new CountDownLatch(1);
+ private MessageListener _listener = null;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ NUM_MESSAGES = 10;
+ }
+
+ /**
+ * Override default init to add connectionListener so we can verify that
+ * failover took place
+ *
+ * @param transacted create a transacted session for this test
+ * @param mode if not transacted what ack mode to use for this test
+ *
+ * @throws Exception if a problem occured during test setup.
+ */
+ @Override
+ public void init(boolean transacted, int mode) throws Exception
+ {
+ super.init(transacted, mode);
+ ((AMQConnection) _connection).setConnectionListener(this);
+ // Override the listener for the dirtyAck testing.
+ if (_listener != null)
+ {
+ _consumer.setMessageListener(_listener);
+ }
+ }
+
+ protected void prepBroker(int count) throws Exception
+ {
+ //Stop the connection whilst we repopulate the broker, or the no_ack
+ // test will drain the msgs before we can check we put the right number
+ // back on again.
+// _connection.stop();
+
+ Connection connection = getConnection();
+ Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+ // ensure destination is created.
+ session.createConsumer(_queue).close();
+
+ sendMessage(session, _queue, count, NUM_MESSAGES - count, 0);
+
+ if (_consumerSession.getAcknowledgeMode() != AMQSession.NO_ACKNOWLEDGE)
+ {
+ assertEquals("Wrong number of messages on queue", count,
+ ((AMQSession) session).getQueueDepth((AMQDestination) _queue));
+ }
+
+ connection.close();
+
+// _connection.start();
+ }
+
+ @Override
+ public void doAcknowlegement(Message msg) throws JMSException
+ {
+ //Acknowledge current message
+ super.doAcknowlegement(msg);
+
+ int msgCount = msg.getIntProperty(INDEX);
+
+ if (msgCount % 2 == 0)
+ {
+ failBroker(getFailingPort());
+ }
+ else
+ {
+ failBroker(getPort());
+ }
+
+ try
+ {
+ prepBroker(NUM_MESSAGES - msgCount - 1);
+ }
+ catch (Exception e)
+ {
+ fail("Unable to prep new broker," + e.getMessage());
+ }
+
+ try
+ {
+
+ if (msgCount % 2 == 0)
+ {
+ startBroker(getFailingPort());
+ }
+ else
+ {
+ startBroker(getPort());
+ }
+ }
+ catch (Exception e)
+ {
+ fail("Unable to start failover broker," + e.getMessage());
+ }
+
+ }
+
+ int msgCount = 0;
+ boolean cleaned = false;
+
+ class DirtyAckingHandler implements MessageListener
+ {
+ /**
+ * Validate first message but do nothing with it.
+ *
+ * Failover
+ *
+ * The receive the message again
+ *
+ * @param message
+ */
+ public void onMessage(Message message)
+ {
+ // Stop processing if we have an error and had to stop running.
+ if (_receivedAll.getCount() == 0)
+ {
+ _logger.debug("Dumping msgs due to error(" + _causeOfFailure.get().getMessage() + "):" + message);
+ return;
+ }
+
+ try
+ {
+ // Check we have the next message as expected
+ assertNotNull("Message " + msgCount + " not correctly received.", message);
+ assertEquals("Incorrect message received", msgCount, message.getIntProperty(INDEX));
+
+ if (msgCount == 0 && _failoverCompleted.getCount() != 0)
+ {
+ // This is the first message we've received so lets fail the broker
+
+ failBroker(getFailingPort());
+
+ repopulateBroker();
+
+ _logger.error("Received first msg so failing over");
+
+ return;
+ }
+
+ msgCount++;
+
+ // Don't acknowlege the first message after failover so we can commit
+ // them together
+ if (msgCount == 1)
+ {
+ _logger.error("Received first msg after failover ignoring:" + msgCount);
+
+ // Acknowledge the first message if we are now on the cleaned pass
+ if (cleaned)
+ {
+ _receivedAll.countDown();
+ }
+
+ return;
+ }
+
+ if (_consumerSession.getTransacted())
+ {
+ try
+ {
+ _consumerSession.commit();
+ if (!cleaned)
+ {
+ fail("Session is dirty we should get an TransactionRolledBackException");
+ }
+ }
+ catch (TransactionRolledBackException trbe)
+ {
+ //expected path
+ }
+ }
+ else
+ {
+ try
+ {
+ message.acknowledge();
+ if (!cleaned)
+ {
+ fail("Session is dirty we should get an IllegalStateException");
+ }
+ }
+ catch (javax.jms.IllegalStateException ise)
+ {
+ assertEquals("Incorrect Exception thrown", "has failed over", ise.getMessage());
+ // Recover the sesion and try again.
+ _consumerSession.recover();
+ }
+ }
+
+ // Acknowledge the last message if we are in a clean state
+ // this will then trigger test teardown.
+ if (cleaned)
+ {
+ _receivedAll.countDown();
+ }
+
+ //Reset message count so we can try again.
+ msgCount = 0;
+ cleaned = true;
+ }
+ catch (Exception e)
+ {
+ // If something goes wrong stop and notifiy main thread.
+ fail(e);
+ }
+ }
+ }
+
+ /**
+ * Test that Acking/Committing a message received before failover causes
+ * an exception at commit/ack time.
+ *
+ * Expected behaviour is that in:
+ * * tx mode commit() throws a transacted RolledBackException
+ * * client ack mode throws an IllegalStateException
+ *
+ * @param transacted is this session trasacted
+ * @param mode What ack mode should be used if not trasacted
+ *
+ * @throws Exception if something goes wrong.
+ */
+ protected void testDirtyAcking(boolean transacted, int mode) throws Exception
+ {
+ NUM_MESSAGES = 2;
+ _listener = new DirtyAckingHandler();
+
+ super.testAcking(transacted, mode);
+ }
+
+ public void testDirtyClientAck() throws Exception
+ {
+ testDirtyAcking(false, Session.CLIENT_ACKNOWLEDGE);
+ }
+
+ public void testDirtyAckingTransacted() throws Exception
+ {
+ testDirtyAcking(true, Session.SESSION_TRANSACTED);
+ }
+
+ private void repopulateBroker() throws Exception
+ {
+ // Repopulate this new broker so we can test what happends after failover
+
+ //Get the connection to the first (main port) broker.
+ Connection connection = getConnection();
+ // Use a transaction to send messages so we can be sure they arrive.
+ Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+ // ensure destination is created.
+ session.createConsumer(_queue).close();
+
+ sendMessage(session, _queue, NUM_MESSAGES);
+
+ assertEquals("Wrong number of messages on queue", NUM_MESSAGES,
+ ((AMQSession) session).getQueueDepth((AMQDestination) _queue));
+
+ connection.close();
+ }
+
+ // AMQConnectionListener Interface.. used so we can validate that we
+ // actually failed over.
+
+ public void bytesSent(long count)
+ {
+ }
+
+ public void bytesReceived(long count)
+ {
+ }
+
+ public boolean preFailover(boolean redirect)
+ {
+ //Allow failover
+ return true;
+ }
+
+ public boolean preResubscribe()
+ {
+ //Allow failover
+ return true;
+ }
+
+ public void failoverComplete()
+ {
+ _failoverCompleted.countDown();
+ }
+
+ /**
+ * Override so we can block until failover has completd
+ *
+ * @param port
+ */
+ @Override
+ public void failBroker(int port)
+ {
+ super.failBroker(port);
+
+ try
+ {
+ if (!_failoverCompleted.await(DEFAULT_FAILOVER_TIME, TimeUnit.MILLISECONDS))
+ {
+ // Use an exception so that we use our local fail() that notifies the main thread of failure
+ throw new Exception("Failover did not occur in specified time:" + DEFAULT_FAILOVER_TIME);
+ }
+
+ }
+ catch (Exception e)
+ {
+ // Use an exception so that we use our local fail() that notifies the main thread of failure
+ fail(e);
+ }
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverTest.java
new file mode 100644
index 0000000000..ae7e30c231
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeAfterFailoverTest.java
@@ -0,0 +1,306 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.ack;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.jms.ConnectionListener;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TransactionRolledBackException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ *
+ */
+public class AcknowledgeAfterFailoverTest extends AcknowledgeTest implements ConnectionListener
+{
+
+ protected CountDownLatch _failoverCompleted = new CountDownLatch(1);
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ // This must be even for the test to run correctly.
+ // Otherwise we will kill the standby broker
+ // not the one we are connected to.
+ // The test will still pass but it will not be exactly
+ // as described.
+ NUM_MESSAGES = 6;
+ }
+
+ /**
+ * Override default init to add connectionListener so we can verify that
+ * failover took place
+ *
+ * @param transacted create a transacted session for this test
+ * @param mode if not transacted what ack mode to use for this test
+ * @throws Exception if a problem occured during test setup.
+ */
+ @Override
+ protected void init(boolean transacted, int mode) throws Exception
+ {
+ super.init(transacted, mode);
+ ((AMQConnection) _connection).setConnectionListener(this);
+ }
+
+ protected void prepBroker(int count) throws Exception
+ {
+ if (count % 2 == 1)
+ {
+ failBroker(getFailingPort());
+ }
+ else
+ {
+ failBroker(getPort());
+ }
+
+ Connection connection = getConnection();
+ Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+ // ensure destination is created.
+ session.createConsumer(_queue).close();
+
+ sendMessage(session, _queue, count, NUM_MESSAGES - count, 0);
+
+ if (_consumerSession.getAcknowledgeMode() != AMQSession.NO_ACKNOWLEDGE)
+ {
+ assertEquals("Wrong number of messages on queue", count,
+ ((AMQSession) session).getQueueDepth((AMQDestination) _queue));
+ }
+
+ connection.close();
+
+ try
+ {
+ if (count % 2 == 1)
+ {
+ startBroker(getFailingPort());
+ }
+ else
+ {
+ startBroker(getPort());
+ }
+ }
+ catch (Exception e)
+ {
+ fail("Unable to start failover broker," + e.getMessage());
+ }
+ }
+
+ @Override
+ public void doAcknowlegement(Message msg) throws JMSException
+ {
+ //Acknowledge current message
+ super.doAcknowlegement(msg);
+
+ try
+ {
+ prepBroker(NUM_MESSAGES - msg.getIntProperty(INDEX) - 1);
+ }
+ catch (Exception e)
+ {
+ fail("Unable to prep new broker," + e.getMessage());
+ }
+
+ }
+
+ /**
+ * Test that Acking/Committing a message received before failover causes
+ * an exception at commit/ack time.
+ *
+ * Expected behaviour is that in:
+ * * tx mode commit() throws a transacted RolledBackException
+ * * client ack mode throws an IllegalStateException
+ *
+ * @param transacted is this session trasacted
+ * @param mode What ack mode should be used if not trasacted
+ *
+ * @throws Exception if something goes wrong.
+ */
+ protected void testDirtyAcking(boolean transacted, int mode) throws Exception
+ {
+ NUM_MESSAGES = 2;
+ //Test Dirty Failover Fails
+ init(transacted, mode);
+
+ _connection.start();
+
+ Message msg = _consumer.receive(1500);
+
+ int count = 0;
+ assertNotNull("Message " + count + " not correctly received.", msg);
+ assertEquals("Incorrect message received", count, msg.getIntProperty(INDEX));
+
+ //Don't acknowledge just prep the next broker. Without changing count
+ // Prep the new broker to have all all the messages so we can validate
+ // that they can all be correctly received.
+ try
+ {
+
+ //Stop the connection so we can validate the number of message count
+ // on the queue is correct after failover
+ _connection.stop();
+ failBroker(getFailingPort());
+
+ //Get the connection to the first (main port) broker.
+ Connection connection = getConnection();//getConnectionFactory("connection1").getConnectionURL());
+ // Use a transaction to send messages so we can be sure they arrive.
+ Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+ // ensure destination is created.
+ session.createConsumer(_queue).close();
+
+ sendMessage(session, _queue, NUM_MESSAGES);
+
+ assertEquals("Wrong number of messages on queue", NUM_MESSAGES,
+ ((AMQSession) session).getQueueDepth((AMQDestination) _queue));
+
+ connection.close();
+
+ //restart connection
+ _connection.start();
+ }
+ catch (Exception e)
+ {
+ fail("Unable to prep new broker," + e.getMessage());
+ }
+
+ // Consume the next message - don't check what it is as a normal would
+ // assume it is msg 1 but as we've fallen over it is msg 0 again.
+ msg = _consumer.receive(1500);
+
+ if (_consumerSession.getTransacted())
+ {
+ try
+ {
+ _consumerSession.commit();
+ fail("Session is dirty we should get an TransactionRolledBackException");
+ }
+ catch (TransactionRolledBackException trbe)
+ {
+ //expected path
+ }
+ }
+ else
+ {
+ try
+ {
+ msg.acknowledge();
+ fail("Session is dirty we should get an IllegalStateException");
+ }
+ catch (javax.jms.IllegalStateException ise)
+ {
+ assertEquals("Incorrect Exception thrown", "has failed over", ise.getMessage());
+ // Recover the sesion and try again.
+ _consumerSession.recover();
+ }
+ }
+
+ msg = _consumer.receive(1500);
+ // Validate we now get the first message back
+ assertEquals(0, msg.getIntProperty(INDEX));
+
+ msg = _consumer.receive(1500);
+ // and the second message
+ assertEquals(1, msg.getIntProperty(INDEX));
+
+ // And now verify that we can now commit the clean session
+ if (_consumerSession.getTransacted())
+ {
+ _consumerSession.commit();
+ }
+ else
+ {
+ msg.acknowledge();
+ }
+
+ assertEquals("Wrong number of messages on queue", 0,
+ ((AMQSession) _consumerSession).getQueueDepth((AMQDestination) _queue));
+ }
+
+ public void testDirtyClientAck() throws Exception
+ {
+ testDirtyAcking(false, Session.CLIENT_ACKNOWLEDGE);
+ }
+
+ public void testDirtyAckingTransacted() throws Exception
+ {
+ testDirtyAcking(true, Session.SESSION_TRANSACTED);
+ }
+
+ // AMQConnectionListener Interface.. used so we can validate that we
+ // actually failed over.
+
+ public void bytesSent(long count)
+ {
+ }
+
+ public void bytesReceived(long count)
+ {
+ }
+
+ public boolean preFailover(boolean redirect)
+ {
+ //Allow failover
+ return true;
+ }
+
+ public boolean preResubscribe()
+ {
+ //Allow failover
+ return true;
+ }
+
+ public void failoverComplete()
+ {
+ _failoverCompleted.countDown();
+ }
+
+ /**
+ * Override so we can block until failover has completd
+ *
+ * @param port
+ */
+ @Override
+ public void failBroker(int port)
+ {
+ super.failBroker(port);
+
+ try
+ {
+ if (!_failoverCompleted.await(DEFAULT_FAILOVER_TIME, TimeUnit.MILLISECONDS))
+ {
+ fail("Failover did not occur in specified time:" + DEFAULT_FAILOVER_TIME);
+ }
+ }
+ catch (InterruptedException e)
+ {
+ fail("Failover was interrupted");
+ }
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeOnMessageTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeOnMessageTest.java
new file mode 100644
index 0000000000..a2703be298
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeOnMessageTest.java
@@ -0,0 +1,181 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.ack;
+
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.JMSAMQException;
+import org.apache.qpid.client.failover.FailoverException;
+
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.Session;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class AcknowledgeOnMessageTest extends AcknowledgeTest implements MessageListener
+{
+ protected CountDownLatch _receivedAll;
+ protected AtomicReference<Exception> _causeOfFailure = new AtomicReference<Exception>(null);
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ }
+
+ @Override
+ public void init(boolean transacted, int mode) throws Exception
+ {
+ _receivedAll = new CountDownLatch(NUM_MESSAGES);
+
+ super.init(transacted, mode);
+ _consumer.setMessageListener(this);
+ }
+
+ /**
+ * @param transacted
+ * @param mode
+ *
+ * @throws Exception
+ */
+ protected void testAcking(boolean transacted, int mode) throws Exception
+ {
+ init(transacted, mode);
+
+ _connection.start();
+
+ // Set the lastCount to NUM_MESSAGES, this ensures that the compare
+ // against the receviedAll count is accurate.
+ int lastCount = NUM_MESSAGES;
+
+ // Wait for messages to arrive
+ boolean complete = _receivedAll.await(5000L, TimeUnit.MILLISECONDS);
+
+ // If the messasges haven't arrived
+ while (!complete)
+ {
+ // Check how many we have received
+ int currentCount = (int) _receivedAll.getCount();
+
+ // make sure we have received a message in the last cycle.
+ if (lastCount == currentCount)
+ {
+ // If we didn't receive any messages then stop.
+ // Something must have gone wrong.
+ System.err.println("Giving up waiting as we didn't receive anything.");
+ break;
+ }
+ // Remember the currentCount as the lastCount for the next cycle.
+ // so we can exit if things get locked up.
+ lastCount = currentCount;
+
+ // Wait again for messages to arrive.
+ complete = _receivedAll.await(5000L, TimeUnit.MILLISECONDS);
+ }
+
+ // If we failed to receive all the messages then fail the test.
+ if (!complete)
+ {
+ // Check to see if we ended due to an exception in the onMessage handler
+ Exception cause = _causeOfFailure.get();
+ if (cause != null)
+ {
+ cause.printStackTrace();
+ fail(cause.getMessage());
+ }
+ else
+ {
+ fail("All messages not received missing:" + _receivedAll.getCount() + "/" + NUM_MESSAGES);
+ }
+ }
+
+ // Even if we received all the messages.
+ // Check to see if we ended due to an exception in the onMessage handler
+ Exception cause = _causeOfFailure.get();
+ if (cause != null)
+ {
+ cause.printStackTrace();
+ fail(cause.getMessage());
+ }
+
+ try
+ {
+ _consumer.close();
+ }
+ catch (JMSAMQException amqe)
+ {
+ if (amqe.getLinkedException() instanceof FailoverException)
+ {
+ fail("QPID-143 : Auto Ack can acknowledge message from previous session after failver. If failover occurs between deliver and ack.");
+ }
+ // else Rethrow for TestCase to catch.
+ throw amqe;
+ }
+
+ _consumerSession.close();
+
+ assertEquals("Wrong number of messages on queue", 0,
+ ((AMQSession) getConnection().createSession(false, Session.AUTO_ACKNOWLEDGE)).getQueueDepth((AMQDestination) _queue));
+ }
+
+ public void onMessage(Message message)
+ {
+ try
+ {
+ int count = NUM_MESSAGES - (int) _receivedAll.getCount();
+
+ assertEquals("Incorrect message received", count, message.getIntProperty(INDEX));
+
+ count++;
+ if (count < NUM_MESSAGES)
+ {
+ //Send the next message
+ _producer.send(createNextMessage(_consumerSession, count));
+ }
+
+ doAcknowlegement(message);
+
+ _receivedAll.countDown();
+ }
+ catch (Exception e)
+ {
+ // This will end the test run by counting down _receviedAll
+ fail(e);
+ }
+ }
+
+ /**
+ * Pass the given exception back to the waiting thread to fail the test run.
+ *
+ * @param e The exception that is causing the test to fail.
+ */
+ protected void fail(Exception e)
+ {
+ _causeOfFailure.set(e);
+ // End the test.
+ while (_receivedAll.getCount() != 0)
+ {
+ _receivedAll.countDown();
+ }
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java
index d0814ca5fc..7c9a77eb53 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java
@@ -1,7 +1,5 @@
-package org.apache.qpid.test.unit.ack;
-
/*
- *
+ *
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
@@ -21,124 +19,138 @@ package org.apache.qpid.test.unit.ack;
*
*/
+package org.apache.qpid.test.unit.ack;
+
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.test.utils.FailoverBaseCase;
+
import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
-import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
+import javax.jms.MessageProducer;
-import org.apache.qpid.client.AMQDestination;
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.test.utils.QpidTestCase;
-
-public class AcknowledgeTest extends QpidTestCase
+public class AcknowledgeTest extends FailoverBaseCase
{
- private static final int NUM_MESSAGES = 50;
- private Connection _con;
- private Queue _queue;
- private MessageProducer _producer;
- private Session _producerSession;
- private Session _consumerSession;
- private MessageConsumer _consumerA;
+ protected int NUM_MESSAGES;
+ protected Connection _connection;
+ protected Queue _queue;
+ protected Session _consumerSession;
+ protected MessageConsumer _consumer;
+ protected MessageProducer _producer;
@Override
protected void setUp() throws Exception
{
super.setUp();
- _queue = (Queue) getInitialContext().lookup("queue");
+ NUM_MESSAGES = 5;
+
+ _queue = getTestQueue();
//Create Producer put some messages on the queue
- _con = getConnection();
- _con.start();
+ _connection = getConnection();
}
- private void init(boolean transacted, int mode) throws JMSException {
- _producerSession = _con.createSession(false, Session.AUTO_ACKNOWLEDGE);
- _consumerSession = _con.createSession(transacted, mode);
- _producer = _producerSession.createProducer(_queue);
- _consumerA = _consumerSession.createConsumer(_queue);
- }
-
+ protected void init(boolean transacted, int mode) throws Exception
+ {
+ _consumerSession = _connection.createSession(transacted, mode);
+ _consumer = _consumerSession.createConsumer(_queue);
+ _producer = _consumerSession.createProducer(_queue);
+ // These should all end up being prefetched by session
+ sendMessage(_consumerSession, _queue, 1);
- private void sendMessages(int totalMessages) throws JMSException
- {
- for (int i = 0; i < totalMessages; i++)
- {
- _producer.send(_producerSession.createTextMessage("message " + i));
- }
+ assertEquals("Wrong number of messages on queue", 1,
+ ((AMQSession) _consumerSession).getQueueDepth((AMQDestination) _queue));
}
/**
- * Produces and consumes messages an either ack or commit the receipt of those messages
- *
* @param transacted
* @param mode
+ *
* @throws Exception
*/
- private void testMessageAck(boolean transacted, int mode) throws Exception
+ protected void testAcking(boolean transacted, int mode) throws Exception
{
- init(transacted, mode);
- sendMessages(NUM_MESSAGES/2);
- Thread.sleep(1500);
- MessageConsumer consumerB = _consumerSession.createConsumer(_queue);
- sendMessages(NUM_MESSAGES/2);
+ init(transacted, mode);
+
+ _connection.start();
+
+ Message msg = _consumer.receive(1500);
+
int count = 0;
- Message msg = consumerB.receive(1500);
- while (msg != null)
+ while (count < NUM_MESSAGES)
{
- if (mode == Session.CLIENT_ACKNOWLEDGE)
+ assertNotNull("Message " + count + " not correctly received.", msg);
+ assertEquals("Incorrect message received", count, msg.getIntProperty(INDEX));
+ count++;
+
+ if (count < NUM_MESSAGES)
{
- msg.acknowledge();
+ //Send the next message
+ _producer.send(createNextMessage(_consumerSession, count));
}
- count++;
- msg = consumerB.receive(1500);
+
+ doAcknowlegement(msg);
+
+ msg = _consumer.receive(1500);
}
- if (transacted)
- {
- _consumerSession.commit();
- }
- _consumerA.close();
- consumerB.close();
- _consumerSession.close();
- assertEquals("Wrong number of messages on queue", NUM_MESSAGES - count,
- ((AMQSession) _producerSession).getQueueDepth((AMQDestination) _queue));
-
- // Clean up messages that may be left on the queue
- _consumerSession = _con.createSession(transacted, mode);
- _consumerA = _consumerSession.createConsumer(_queue);
- msg = _consumerA.receive(1500);
- while (msg != null)
+
+ assertEquals("Wrong number of messages on queue", 0,
+ ((AMQSession) _consumerSession).getQueueDepth((AMQDestination) _queue));
+ }
+
+ /**
+ * Perform the acknowledgement of messages if additionally required.
+ *
+ * @param msg
+ *
+ * @throws JMSException
+ */
+ protected void doAcknowlegement(Message msg) throws JMSException
+ {
+ if (_consumerSession.getTransacted())
{
- if (mode == Session.CLIENT_ACKNOWLEDGE)
- {
- msg.acknowledge();
- }
- msg = _consumerA.receive(1500);
+ _consumerSession.commit();
}
- _consumerA.close();
- if (transacted)
+
+ if (_consumerSession.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE)
{
- _consumerSession.commit();
+ msg.acknowledge();
}
- _consumerSession.close();
}
-
- public void test2ConsumersAutoAck() throws Exception
+
+ public void testClientAck() throws Exception
{
- testMessageAck(false, Session.AUTO_ACKNOWLEDGE);
+ testAcking(false, Session.CLIENT_ACKNOWLEDGE);
}
- public void test2ConsumersClientAck() throws Exception
+ public void testAutoAck() throws Exception
{
- testMessageAck(true, Session.CLIENT_ACKNOWLEDGE);
+ testAcking(false, Session.AUTO_ACKNOWLEDGE);
}
-
- public void test2ConsumersTx() throws Exception
+
+ public void testTransacted() throws Exception
{
- testMessageAck(true, Session.AUTO_ACKNOWLEDGE);
+ testAcking(true, Session.SESSION_TRANSACTED);
}
-
+
+ public void testDupsOk() throws Exception
+ {
+ testAcking(false, Session.DUPS_OK_ACKNOWLEDGE);
+ }
+
+ public void testNoAck() throws Exception
+ {
+ testAcking(false, AMQSession.NO_ACKNOWLEDGE);
+ }
+
+ public void testPreAck() throws Exception
+ {
+ testAcking(false, AMQSession.PRE_ACKNOWLEDGE);
+ }
+
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/ack/FailoverBeforeConsumingRecoverTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/ack/FailoverBeforeConsumingRecoverTest.java
new file mode 100644
index 0000000000..834b17430b
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/ack/FailoverBeforeConsumingRecoverTest.java
@@ -0,0 +1,40 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.ack;
+
+import org.apache.qpid.jms.Session;
+
+import javax.jms.Message;
+import javax.jms.Queue;
+
+public class FailoverBeforeConsumingRecoverTest extends RecoverTest
+{
+
+ @Override
+ protected void initTest() throws Exception
+ {
+ super.initTest();
+ failBroker(getFailingPort());
+
+ Queue queue = _consumerSession.createQueue(getTestQueueName());
+ sendMessage(_connection.createSession(false, Session.AUTO_ACKNOWLEDGE), queue, SENT_COUNT);
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/ack/QuickAcking.java b/java/systests/src/main/java/org/apache/qpid/test/unit/ack/QuickAcking.java
new file mode 100644
index 0000000000..6c4b7ba01b
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/ack/QuickAcking.java
@@ -0,0 +1,148 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.ack;
+
+import edu.emory.mathcs.backport.java.util.concurrent.CountDownLatch;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.jms.ConnectionListener;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+/**
+ * This is a quick manual test to validate acking after failover with a
+ * transacted session.
+ *
+ * Start an external broker then run this test. Std Err will print.
+ * Sent Message: 1
+ * Received Message: 1
+ *
+ * You can then restart the external broker, which will cause failover, which
+ * will be complete when the following appears.
+ *
+ * Failover Complete
+ *
+ * A second message send/receive cycle is then done to validate that the
+ * connection/session are still working.
+ *
+ */
+public class QuickAcking extends QpidTestCase implements ConnectionListener
+{
+ protected AMQConnection _connection;
+ protected Queue _queue;
+ protected Session _session;
+ protected MessageConsumer _consumer;
+ private CountDownLatch _failedOver;
+ private static final String INDEX = "INDEX";
+ private int _count = 0;
+
+ public void setUp()
+ {
+ // Prevent broker startup. Broker must be run manually.
+ }
+
+ public void test() throws Exception
+ {
+ _failedOver = new CountDownLatch(1);
+
+ _connection = new AMQConnection("amqp://guest:guest@client/test?brokerlist='localhost?retries='20'&connectdelay='2000''");
+
+ _session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+ _queue = _session.createQueue("QAtest");
+ _consumer = _session.createConsumer(_queue);
+ _connection.setConnectionListener(this);
+ _connection.start();
+
+ sendAndReceive();
+
+ _failedOver.await();
+
+ sendAndReceive();
+
+ }
+
+ private void sendAndReceive()
+ throws Exception
+ {
+ sendMessage();
+
+ Message message = _consumer.receive();
+
+ if (message.getIntProperty(INDEX) != _count)
+ {
+ throw new Exception("Incorrect message recieved:" + _count);
+ }
+
+ if (_session.getTransacted())
+ {
+ _session.commit();
+ }
+ System.err.println("Recevied Message:" + _count);
+ }
+
+ private void sendMessage() throws JMSException
+ {
+ MessageProducer producer = _session.createProducer(_queue);
+ Message message = _session.createMessage();
+ _count++;
+ message.setIntProperty(INDEX, _count);
+
+ producer.send(message);
+ if (_session.getTransacted())
+ {
+ _session.commit();
+ }
+ producer.close();
+
+ System.err.println("Sent Message:" + _count);
+ }
+
+ public void bytesSent(long count)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void bytesReceived(long count)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean preFailover(boolean redirect)
+ {
+ return true;
+ }
+
+ public boolean preResubscribe()
+ {
+ return true;
+ }
+
+ public void failoverComplete()
+ {
+ System.err.println("Failover Complete");
+ _failedOver.countDown();
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java
index 7434fcbb30..4a123cb1dc 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java
@@ -23,8 +23,7 @@ import org.apache.qpid.client.AMQConnection;
import org.apache.qpid.client.AMQQueue;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.jms.Session;
-import org.apache.qpid.test.utils.QpidTestCase;
-
+import org.apache.qpid.test.utils.FailoverBaseCase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -35,16 +34,21 @@ import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.TextMessage;
-
import java.util.concurrent.atomic.AtomicInteger;
-public class RecoverTest extends QpidTestCase
+public class RecoverTest extends FailoverBaseCase
{
- private static final Logger _logger = LoggerFactory.getLogger(RecoverTest.class);
+ static final Logger _logger = LoggerFactory.getLogger(RecoverTest.class);
private Exception _error;
private AtomicInteger count;
+ protected AMQConnection _connection;
+ protected Session _consumerSession;
+ protected MessageConsumer _consumer;
+ static final int SENT_COUNT = 4;
+
+ @Override
protected void setUp() throws Exception
{
super.setUp();
@@ -52,134 +56,110 @@ public class RecoverTest extends QpidTestCase
count = new AtomicInteger();
}
- protected void tearDown() throws Exception
+ protected void initTest() throws Exception
{
- super.tearDown();
- count = null;
- }
+ _connection = (AMQConnection) getConnection("guest", "guest");
- public void testRecoverResendsMsgs() throws Exception
- {
- AMQConnection con = (AMQConnection) getConnection("guest", "guest");
-
- Session consumerSession = con.createSession(false, Session.CLIENT_ACKNOWLEDGE);
- Queue queue =
- new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("someQ"),
- new AMQShortString("someQ"), false, true);
- MessageConsumer consumer = consumerSession.createConsumer(queue);
- // force synch to ensure the consumer has resulted in a bound queue
- // ((AMQSession) consumerSession).declareExchangeSynch(ExchangeDefaults.DIRECT_EXCHANGE_NAME, ExchangeDefaults.DIRECT_EXCHANGE_CLASS);
- // This is the default now
+ _consumerSession = _connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+ Queue queue = _consumerSession.createQueue(getTestQueueName());
- AMQConnection con2 = (AMQConnection) getConnection("guest", "guest");
- Session producerSession = con2.createSession(false, Session.CLIENT_ACKNOWLEDGE);
- MessageProducer producer = producerSession.createProducer(queue);
+ _consumer = _consumerSession.createConsumer(queue);
_logger.info("Sending four messages");
- producer.send(producerSession.createTextMessage("msg1"));
- producer.send(producerSession.createTextMessage("msg2"));
- producer.send(producerSession.createTextMessage("msg3"));
- producer.send(producerSession.createTextMessage("msg4"));
-
- con2.close();
-
+ sendMessage(_connection.createSession(false, Session.AUTO_ACKNOWLEDGE), queue, SENT_COUNT);
_logger.info("Starting connection");
- con.start();
- TextMessage tm = (TextMessage) consumer.receive();
- tm.acknowledge();
- _logger.info("Received and acknowledged first message");
- consumer.receive();
- consumer.receive();
- consumer.receive();
- _logger.info("Received all four messages. Calling recover with three outstanding messages");
- // no ack for last three messages so when I call recover I expect to get three messages back
- consumerSession.recover();
- tm = (TextMessage) consumer.receive(3000);
- assertEquals("msg2", tm.getText());
+ _connection.start();
+ }
- tm = (TextMessage) consumer.receive(3000);
- assertEquals("msg3", tm.getText());
+ protected Message validateNextMessages(int nextCount, int startIndex) throws JMSException
+ {
+ Message message = null;
+ for (int index = 0; index < nextCount; index++)
+ {
+ message = _consumer.receive(3000);
+ assertEquals(startIndex + index, message.getIntProperty(INDEX));
+ }
+ return message;
+ }
- tm = (TextMessage) consumer.receive(3000);
- assertEquals("msg4", tm.getText());
+ protected void validateRemainingMessages(int remaining) throws JMSException
+ {
+ int index = SENT_COUNT - remaining;
- _logger.info("Received redelivery of three messages. Acknowledging last message");
- tm.acknowledge();
+ Message message = null;
+ while (index != SENT_COUNT)
+ {
+ message = _consumer.receive(3000);
+ assertEquals(index++, message.getIntProperty(INDEX));
+ }
+
+ if (message != null)
+ {
+ _logger.info("Received redelivery of three messages. Acknowledging last message");
+ message.acknowledge();
+ }
_logger.info("Calling acknowledge with no outstanding messages");
// all acked so no messages to be delivered
- consumerSession.recover();
+ _consumerSession.recover();
- tm = (TextMessage) consumer.receiveNoWait();
- assertNull(tm);
+ message = _consumer.receiveNoWait();
+ assertNull(message);
_logger.info("No messages redelivered as is expected");
-
- con.close();
}
- public void testRecoverResendsMsgsAckOnEarlier() throws Exception
+ public void testRecoverResendsMsgs() throws Exception
{
- AMQConnection con = (AMQConnection) getConnection("guest", "guest");
+ initTest();
- Session consumerSession = con.createSession(false, Session.CLIENT_ACKNOWLEDGE);
- Queue queue =
- new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("someQ"),
- new AMQShortString("someQ"), false, true);
- MessageConsumer consumer = consumerSession.createConsumer(queue);
- // force synch to ensure the consumer has resulted in a bound queue
- // ((AMQSession) consumerSession).declareExchangeSynch(ExchangeDefaults.DIRECT_EXCHANGE_NAME, ExchangeDefaults.DIRECT_EXCHANGE_CLASS);
- // This is the default now
+ Message message = validateNextMessages(1, 0);
+ message.acknowledge();
+ _logger.info("Received and acknowledged first message");
- AMQConnection con2 = (AMQConnection) getConnection("guest", "guest");
- Session producerSession = con2.createSession(false, Session.CLIENT_ACKNOWLEDGE);
- MessageProducer producer = producerSession.createProducer(queue);
+ _consumer.receive();
+ _consumer.receive();
+ _consumer.receive();
+ _logger.info("Received all four messages. Calling recover with three outstanding messages");
+ // no ack for last three messages so when I call recover I expect to get three messages back
- _logger.info("Sending four messages");
- producer.send(producerSession.createTextMessage("msg1"));
- producer.send(producerSession.createTextMessage("msg2"));
- producer.send(producerSession.createTextMessage("msg3"));
- producer.send(producerSession.createTextMessage("msg4"));
+ _consumerSession.recover();
- con2.close();
+ validateRemainingMessages(3);
+ }
- _logger.info("Starting connection");
- con.start();
- TextMessage tm = (TextMessage) consumer.receive();
- consumer.receive();
- tm.acknowledge();
+ public void testRecoverResendsMsgsAckOnEarlier() throws Exception
+ {
+ initTest();
+
+ Message message = validateNextMessages(2, 0);
+ message.acknowledge();
_logger.info("Received 2 messages, acknowledge() first message, should acknowledge both");
- consumer.receive();
- consumer.receive();
+ _consumer.receive();
+ _consumer.receive();
_logger.info("Received all four messages. Calling recover with two outstanding messages");
// no ack for last three messages so when I call recover I expect to get three messages back
- consumerSession.recover();
- TextMessage tm3 = (TextMessage) consumer.receive(3000);
- assertEquals("msg3", tm3.getText());
+ _consumerSession.recover();
+
+ Message message2 = _consumer.receive(3000);
+ assertEquals(2, message2.getIntProperty(INDEX));
- TextMessage tm4 = (TextMessage) consumer.receive(3000);
- assertEquals("msg4", tm4.getText());
+ Message message3 = _consumer.receive(3000);
+ assertEquals(3, message3.getIntProperty(INDEX));
_logger.info("Received redelivery of two messages. calling acknolwedgeThis() first of those message");
- ((org.apache.qpid.jms.Message) tm3).acknowledgeThis();
+ ((org.apache.qpid.jms.Message) message2).acknowledgeThis();
_logger.info("Calling recover");
// all acked so no messages to be delivered
- consumerSession.recover();
+ _consumerSession.recover();
- tm4 = (TextMessage) consumer.receive(3000);
- assertEquals("msg4", tm4.getText());
- ((org.apache.qpid.jms.Message) tm4).acknowledgeThis();
+ message3 = _consumer.receive(3000);
+ assertEquals(3, message3.getIntProperty(INDEX));
+ ((org.apache.qpid.jms.Message) message3).acknowledgeThis();
- _logger.info("Calling recover");
// all acked so no messages to be delivered
- consumerSession.recover();
-
- tm = (TextMessage) consumer.receiveNoWait();
- assertNull(tm);
- _logger.info("No messages redelivered as is expected");
-
- con.close();
+ validateRemainingMessages(0);
}
public void testAcknowledgePerConsumer() throws Exception
@@ -188,11 +168,11 @@ public class RecoverTest extends QpidTestCase
Session consumerSession = con.createSession(false, Session.CLIENT_ACKNOWLEDGE);
Queue queue =
- new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q1"), new AMQShortString("Q1"),
- false, true);
+ new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q1"), new AMQShortString("Q1"),
+ false, true);
Queue queue2 =
- new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q2"), new AMQShortString("Q2"),
- false, true);
+ new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q2"), new AMQShortString("Q2"),
+ false, true);
MessageConsumer consumer = consumerSession.createConsumer(queue);
MessageConsumer consumer2 = consumerSession.createConsumer(queue2);
@@ -231,8 +211,8 @@ public class RecoverTest extends QpidTestCase
final Session consumerSession = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue =
- new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q3"), new AMQShortString("Q3"),
- false, true);
+ new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q3"), new AMQShortString("Q3"),
+ false, true);
MessageConsumer consumer = consumerSession.createConsumer(queue);
MessageProducer producer = consumerSession.createProducer(queue);
producer.send(consumerSession.createTextMessage("hello"));
@@ -240,50 +220,50 @@ public class RecoverTest extends QpidTestCase
final Object lock = new Object();
consumer.setMessageListener(new MessageListener()
- {
+ {
- public void onMessage(Message message)
+ public void onMessage(Message message)
+ {
+ try
{
- try
+ count.incrementAndGet();
+ if (count.get() == 1)
{
- count.incrementAndGet();
- if (count.get() == 1)
+ if (message.getJMSRedelivered())
{
- if (message.getJMSRedelivered())
- {
- setError(
+ setError(
new Exception("Message marked as redilvered on what should be first delivery attempt"));
- }
-
- consumerSession.recover();
}
- else if (count.get() == 2)
+
+ consumerSession.recover();
+ }
+ else if (count.get() == 2)
+ {
+ if (!message.getJMSRedelivered())
{
- if (!message.getJMSRedelivered())
- {
- setError(
+ setError(
new Exception(
- "Message not marked as redilvered on what should be second delivery attempt"));
- }
- }
- else
- {
- System.err.println(message);
- fail("Message delivered too many times!: " + count);
+ "Message not marked as redilvered on what should be second delivery attempt"));
}
}
- catch (JMSException e)
+ else
{
- _logger.error("Error recovering session: " + e, e);
- setError(e);
+ System.err.println(message);
+ fail("Message delivered too many times!: " + count);
}
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error recovering session: " + e, e);
+ setError(e);
+ }
- synchronized (lock)
- {
- lock.notify();
- }
+ synchronized (lock)
+ {
+ lock.notify();
}
- });
+ }
+ });
con.start();
@@ -323,9 +303,4 @@ public class RecoverTest extends QpidTestCase
{
_error = e;
}
-
- public static junit.framework.Test suite()
- {
- return new junit.framework.TestSuite(RecoverTest.class);
- }
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java
index 9a7fe7c039..7db53ec50c 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java
@@ -29,6 +29,7 @@ import org.apache.qpid.client.AMQQueue;
import org.apache.qpid.client.AMQSession;
import org.apache.qpid.client.message.JMSBytesMessage;
import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.transport.util.Waiter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -131,9 +132,10 @@ public class BytesMessageTest extends QpidTestCase implements MessageListener
{
synchronized (received)
{
- while (received.size() < count)
+ Waiter w = new Waiter(received, 30000);
+ while (received.size() < count && w.hasTime())
{
- received.wait();
+ w.await();
}
}
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java
index 24fef48028..9558f23b89 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java
@@ -79,16 +79,22 @@ public class LargeMessageTest extends QpidTestCase
}
// Test boundary of 1 packet to 2 packets
- public void test64kminus1()
+ public void test64kminus9()
{
- checkLargeMessage((64 * 1024) - 1);
+ checkLargeMessage((64 * 1024) - 9);
}
- public void test64k()
+ public void test64kminus8()
{
- checkLargeMessage(64 * 1024);
+ checkLargeMessage((64 * 1024)-8);
}
+ public void test64kminus7()
+ {
+ checkLargeMessage((64 * 1024)-7);
+ }
+
+
public void test64kplus1()
{
checkLargeMessage((64 * 1024) + 1);
@@ -141,7 +147,7 @@ public class LargeMessageTest extends QpidTestCase
producer.send(_session.createTextMessage(_messageText));
- TextMessage result = (TextMessage) consumer.receive(1000);
+ TextMessage result = (TextMessage) consumer.receive(10000);
assertNotNull("Null message recevied", result);
assertEquals("Message Size", _messageText.length(), result.getText().length());
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java
index 658cf26135..4596878935 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java
@@ -126,7 +126,7 @@ public class MultipleConnectionTest extends QpidTestCase
while (expected > _count)
{
long timeLeft = maxWait - timeSince(start);
- if (timeLeft < 0)
+ if (timeLeft <= 0)
{
break;
}
@@ -148,18 +148,6 @@ public class MultipleConnectionTest extends QpidTestCase
}
}
- protected void setUp() throws Exception
- {
- super.setUp();
- TransportConnection.createVMBroker(1);
- }
-
- protected void tearDown() throws Exception
- {
- super.tearDown();
- TransportConnection.killAllVMBrokers();
- }
-
private static void waitForCompletion(int expected, long wait, Receiver[] receivers) throws InterruptedException
{
for (int i = 0; i < receivers.length; i++)
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/basic/SelectorTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/SelectorTest.java
deleted file mode 100644
index c42e4c7582..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/basic/SelectorTest.java
+++ /dev/null
@@ -1,306 +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.
- *
- */
-package org.apache.qpid.test.unit.basic;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.test.utils.QpidTestCase;
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQDestination;
-import org.apache.qpid.client.AMQQueue;
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.client.BasicMessageProducer;
-import org.apache.qpid.client.state.StateWaiter;
-import org.apache.qpid.url.URLSyntaxException;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.jms.Connection;
-import javax.jms.DeliveryMode;
-import javax.jms.InvalidSelectorException;
-import javax.jms.JMSException;
-import javax.jms.Message;
-import javax.jms.MessageListener;
-import java.util.concurrent.CountDownLatch;
-
-public class SelectorTest extends QpidTestCase implements MessageListener
-{
- private static final Logger _logger = LoggerFactory.getLogger(SelectorTest.class);
-
- private AMQConnection _connection;
- private AMQDestination _destination;
- private AMQSession _session;
- private int count;
- public String _connectionString = "vm://:1";
- private static final String INVALID_SELECTOR = "Cost LIKE 5";
- CountDownLatch _responseLatch = new CountDownLatch(1);
-
- protected void setUp() throws Exception
- {
- super.setUp();
- init((AMQConnection) getConnection("guest", "guest"));
- }
-
- protected void tearDown() throws Exception
- {
- super.tearDown();
- }
-
- private void init(AMQConnection connection) throws JMSException
- {
- init(connection, new AMQQueue(connection, randomize("SessionStartTest"), true));
- }
-
- private void init(AMQConnection connection, AMQDestination destination) throws JMSException
- {
- _connection = connection;
- _destination = destination;
- connection.start();
-
- String selector = null;
- selector = "Cost = 2 AND \"property-with-hyphen\" = 'wibble'";
- // selector = "JMSType = Special AND Cost = 2 AND AMQMessageID > 0 AND JMSDeliveryMode=" + DeliveryMode.NON_PERSISTENT;
-
- _session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
- // _session.createConsumer(destination).setMessageListener(this);
- _session.createConsumer(destination, selector).setMessageListener(this);
- }
-
- public void test() throws Exception
- {
- try
- {
-
- init((AMQConnection) getConnection("guest", "guest", randomize("Client")));
-
- Message msg = _session.createTextMessage("Message");
- msg.setJMSPriority(1);
- msg.setIntProperty("Cost", 2);
- msg.setStringProperty("property-with-hyphen", "wibble");
- msg.setJMSType("Special");
-
- _logger.info("Sending Message:" + msg);
-
- ((BasicMessageProducer) _session.createProducer(_destination)).send(msg, DeliveryMode.NON_PERSISTENT);
- _logger.info("Message sent, waiting for response...");
-
- _responseLatch.await();
-
- if (count > 0)
- {
- _logger.info("Got message");
- }
-
- if (count == 0)
- {
- fail("Did not get message!");
- // throw new RuntimeException("Did not get message!");
- }
- }
- catch (JMSException e)
- {
- _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
- if (!(e instanceof InvalidSelectorException))
- {
- fail("Wrong exception:" + e.getMessage());
- }
- else
- {
- System.out.println("SUCCESS!!");
- }
- }
- catch (InterruptedException e)
- {
- _logger.debug("IE :" + e.getClass().getSimpleName() + ":" + e.getMessage());
- }
- catch (URLSyntaxException e)
- {
- _logger.debug("URL:" + e.getClass().getSimpleName() + ":" + e.getMessage());
- fail("Wrong exception");
- }
- catch (AMQException e)
- {
- _logger.debug("AMQ:" + e.getClass().getSimpleName() + ":" + e.getMessage());
- fail("Wrong exception");
- }
-
- finally
- {
- if (_session != null)
- {
- _session.close();
- }
- if (_connection != null)
- {
- _connection.close();
- }
- }
- }
-
-
- public void testInvalidSelectors() throws Exception
- {
- Connection connection = null;
-
- try
- {
- connection = getConnection("guest", "guest", randomize("Client"));
- _session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
- }
- catch (JMSException e)
- {
- fail(e.getMessage());
- }
- catch (AMQException e)
- {
- fail(e.getMessage());
- }
- catch (URLSyntaxException e)
- {
- fail("Error:" + e.getMessage());
- }
-
- //Try Creating a Browser
- try
- {
- _session.createBrowser(_session.createQueue("Ping"), INVALID_SELECTOR);
- }
- catch (JMSException e)
- {
- _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
- if (!(e instanceof InvalidSelectorException))
- {
- fail("Wrong exception:" + e.getMessage());
- }
- else
- {
- _logger.debug("SUCCESS!!");
- }
- }
-
- //Try Creating a Consumer
- try
- {
- _session.createConsumer(_session.createQueue("Ping"), INVALID_SELECTOR);
- }
- catch (JMSException e)
- {
- _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
- if (!(e instanceof InvalidSelectorException))
- {
- fail("Wrong exception:" + e.getMessage());
- }
- else
- {
- _logger.debug("SUCCESS!!");
- }
- }
-
- //Try Creating a Receiever
- try
- {
- _session.createReceiver(_session.createQueue("Ping"), INVALID_SELECTOR);
- }
- catch (JMSException e)
- {
- _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage());
- if (!(e instanceof InvalidSelectorException))
- {
- fail("Wrong exception:" + e.getMessage());
- }
- else
- {
- _logger.debug("SUCCESS!!");
- }
- }
-
- finally
- {
- if (_session != null)
- {
- try
- {
- _session.close();
- }
- catch (JMSException e)
- {
- fail("Error cleaning up:" + e.getMessage());
- }
- }
- if (_connection != null)
- {
- try
- {
- _connection.close();
- }
- catch (JMSException e)
- {
- fail("Error cleaning up:" + e.getMessage());
- }
- }
- }
- }
-
- public void onMessage(Message message)
- {
- count++;
- _logger.info("Got Message:" + message);
- _responseLatch.countDown();
- }
-
- private static String randomize(String in)
- {
- return in + System.currentTimeMillis();
- }
-
- public static void main(String[] argv) throws Exception
- {
- SelectorTest test = new SelectorTest();
- test._connectionString = (argv.length == 0) ? "localhost:3000" : argv[0];
-
- try
- {
- while (true)
- {
- if (test._connectionString.contains("vm://:1"))
- {
- test.setUp();
- }
- test.test();
-
- if (test._connectionString.contains("vm://:1"))
- {
- test.tearDown();
- }
- }
- }
- catch (Exception e)
- {
- System.err.println(e.getMessage());
- e.printStackTrace();
- }
- }
-
- public static junit.framework.Test suite()
- {
- return new junit.framework.TestSuite(SelectorTest.class);
- }
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/basic/close/CloseTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/close/CloseTest.java
index 21eaad6d5b..89316b6511 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/basic/close/CloseTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/close/CloseTest.java
@@ -35,18 +35,6 @@ public class CloseTest extends QpidTestCase
{
private static final Logger _logger = LoggerFactory.getLogger(CloseTest.class);
- private static final String BROKER = "vm://:1";
-
- protected void setUp() throws Exception
- {
- super.setUp();
- }
-
- protected void tearDown() throws Exception
- {
- super.setUp();
- }
-
public void testCloseQueueReceiver() throws Exception
{
AMQConnection connection = (AMQConnection) getConnection("guest", "guest");
@@ -62,7 +50,7 @@ public class CloseTest extends QpidTestCase
_logger.info("About to close consumer");
- consumer.close();
+ consumer.close();
_logger.info("Closed Consumer");
connection.close();
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java
index c91c27e894..cbeb16f340 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java
@@ -21,13 +21,20 @@
package org.apache.qpid.test.unit.client;
import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
import javax.jms.QueueSession;
+import javax.jms.Session;
+import javax.jms.TextMessage;
import javax.jms.TopicSession;
import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQConnectionDelegate_0_10;
import org.apache.qpid.client.AMQQueue;
import org.apache.qpid.client.AMQSession;
import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.client.configuration.ClientProperties;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.test.utils.QpidTestCase;
@@ -187,6 +194,75 @@ public class AMQConnectionTest extends QpidTestCase
}
}
+ public void testPrefetchSystemProperty() throws Exception
+ {
+ String oldPrefetch = System.getProperty(ClientProperties.MAX_PREFETCH_PROP_NAME);
+ try
+ {
+ _connection.close();
+ System.setProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, new Integer(2).toString());
+ _connection = (AMQConnection) getConnection();
+ _connection.start();
+ // Create two consumers on different sessions
+ Session consSessA = _connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
+ MessageConsumer consumerA = consSessA.createConsumer(_queue);
+
+ Session producerSession = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ MessageProducer producer = producerSession.createProducer(_queue);
+
+ // Send 3 messages
+ for (int i = 0; i < 3; i++)
+ {
+ producer.send(producerSession.createTextMessage(new Integer(i).toString()));
+ }
+ Session consSessB = _connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
+ MessageConsumer consumerB = consSessB.createConsumer(_queue);
+
+ Message msg;
+ // Check that one consumer has 2 messages
+ for (int i = 0; i < 2; i++)
+ {
+ msg = consumerA.receive(1500);
+ assertNotNull(msg);
+ assertEquals(new Integer(i).toString(), ((TextMessage) msg).getText());
+ }
+
+ msg = consumerA.receive(1500);
+ assertNull(msg);
+
+ // Check that other consumer has last message
+ msg = consumerB.receive(1500);
+ assertNotNull(msg);
+ assertEquals(new Integer(2).toString(), ((TextMessage) msg).getText());
+ }
+ finally
+ {
+ if (oldPrefetch == null)
+ {
+ oldPrefetch = ClientProperties.MAX_PREFETCH_DEFAULT;
+ }
+ System.setProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, oldPrefetch);
+ }
+ }
+
+ public void testGetChannelID()
+ {
+ int maxChannelID = 65536;
+ if (isBroker010())
+ {
+ maxChannelID = Integer.MAX_VALUE+1;
+ }
+ for (int j = 0; j < 3; j++)
+ {
+ for (int i = 1; i < maxChannelID; i++)
+ {
+ int id = _connection.getNextChannelID();
+ assertEquals("On iterartion "+j, i, id);
+ _connection.deregisterSession(id);
+ }
+ }
+ }
+
public static junit.framework.Test suite()
{
return new junit.framework.TestSuite(AMQConnectionTest.class);
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/DynamicQueueExchangeCreateTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/DynamicQueueExchangeCreateTest.java
new file mode 100644
index 0000000000..c9810e7304
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/DynamicQueueExchangeCreateTest.java
@@ -0,0 +1,88 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.client;
+
+import org.apache.qpid.test.utils.QpidTestCase;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+/**
+ * QPID-155
+ *
+ * Test to validate that setting the respective qpid.declare_queues,
+ * qpid.declare_exchanges system properties functions as expected.
+ *
+ */
+public class DynamicQueueExchangeCreateTest extends QpidTestCase
+{
+
+ public void testQueueDeclare() throws Exception
+ {
+ setSystemProperty("qpid.declare_queues", "false");
+
+ Connection connection = getConnection();
+
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ Queue queue = session.createQueue(getTestQueueName());
+
+ try
+ {
+ session.createConsumer(queue);
+ fail("JMSException should be thrown as the queue does not exist");
+ }
+ catch (JMSException e)
+ {
+ assertTrue("Exception should be that the queue does not exist :" +
+ e.getMessage(),
+ e.getMessage().contains("does not exist"));
+
+ }
+ }
+
+ public void testExchangeDeclare() throws Exception
+ {
+ setSystemProperty("qpid.declare_exchanges", "false");
+
+ Connection connection = getConnection();
+
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ String EXCHANGE_TYPE = "test.direct";
+ Queue queue = session.createQueue("direct://" + EXCHANGE_TYPE + "/queue/queue");
+
+ try
+ {
+ session.createConsumer(queue);
+ fail("JMSException should be thrown as the exchange does not exist");
+ }
+ catch (JMSException e)
+ {
+ assertTrue("Exception should be that the exchange does not exist :" +
+ e.getMessage(),
+ e.getMessage().contains("Exchange " + EXCHANGE_TYPE + " does not exist"));
+ }
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseOkTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseOkTest.java
index b843f7c9c0..2710e7a08d 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseOkTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseOkTest.java
@@ -67,13 +67,11 @@ public class ChannelCloseOkTest extends QpidTestCase
private final List<Message> _received2 = new ArrayList<Message>();
private static final Logger _log = LoggerFactory.getLogger(ChannelCloseOkTest.class);
- public String _connectionString = "vm://:1";
protected void setUp() throws Exception
{
super.setUp();
- TransportConnection.createVMBroker(1);
_connection = (AMQConnection) getConnection("guest", "guest");
_destination1 = new AMQQueue(_connection, "q1", true);
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseTest.java
index d210f5e1a1..eb6adf9b39 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseTest.java
@@ -54,25 +54,13 @@ public class ChannelCloseTest extends QpidTestCase implements ExceptionListener,
private static final long SYNC_TIMEOUT = 500;
private int TEST = 0;
- protected void setUp() throws Exception
- {
- super.setUp();
- TransportConnection.createVMBroker(1);
- }
-
- protected void tearDown() throws Exception
- {
- super.tearDown();
- TransportConnection.killAllVMBrokers();
- }
-
/*
close channel, use chanel with same id ensure error.
*/
public void testReusingChannelAfterFullClosure() throws Exception
{
- // this is testing an 0.8 conneciton
- if(isBroker08())
+ // this is testing an inVM Connetion conneciton
+ if (isJavaBroker() && !isExternalBroker())
{
_connection=newConnection();
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/CloseAfterConnectionFailureTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/CloseAfterConnectionFailureTest.java
new file mode 100644
index 0000000000..f627d94419
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/CloseAfterConnectionFailureTest.java
@@ -0,0 +1,124 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.client.connection;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQConnectionURL;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.url.URLSyntaxException;
+
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.MessageConsumer;
+import javax.jms.Session;
+import java.util.concurrent.CountDownLatch;
+
+public class CloseAfterConnectionFailureTest extends QpidTestCase implements ExceptionListener
+{
+ private int sessionCount = 0;
+ AMQConnection connection;
+ Session session;
+ MessageConsumer consumer;
+ private CountDownLatch _latch = new CountDownLatch(1);
+ private JMSException _fail;
+
+ public void testNoFailover() throws URLSyntaxException, Exception,
+ InterruptedException, JMSException
+ {
+ //This test uses hard coded connection string so only runs on InVM case
+ if (!isExternalBroker())
+ {
+ String connectionString = "amqp://guest:guest@/test?brokerlist='vm://:1?connectdelay='500',retries='3'',failover='nofailover'";
+
+ AMQConnectionURL url = new AMQConnectionURL(connectionString);
+
+ try
+ {
+ //Start the connection so it will use the retries
+ connection = new AMQConnection(url, null);
+
+ connection.setExceptionListener(this);
+
+ session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ consumer = session.createConsumer(session.createQueue(this.getName()));
+
+ //Kill connection
+ stopBroker();
+
+ _latch.await();
+
+ if (_fail != null)
+ {
+ _fail.printStackTrace(System.out);
+ fail("Exception thrown:" + _fail.getMessage());
+ }
+ }
+ catch (AMQException e)
+ {
+ fail(e.getMessage());
+ }
+ }
+ }
+
+ public void onException(JMSException e)
+ {
+ System.out.println("Connection isClosed after connection Falure?:" + connection.isClosed());
+ try
+ {
+ consumer.close();
+ }
+ catch (JMSException jmse)
+ {
+ System.out.println("Consumer close failed with:" + jmse.getMessage());
+ _fail = jmse;
+ }
+ System.out.println("Connection isClosed after connection Falure?:" + connection.isClosed());
+ try
+ {
+ //Note that if we actually do session.close() we will lock up as the session will never receive a frame
+ // from the
+ ((AMQSession) session).close(10);
+ }
+ catch (JMSException jmse)
+ {
+ System.out.println("Session close failed with:" + jmse.getMessage());
+ _fail = jmse;
+ }
+ System.out.println("Connection isClosed after connection Falure?:" + connection.isClosed());
+
+ try
+ {
+ connection.close();
+ }
+ catch (JMSException jmse)
+ {
+ System.out.println("Session close failed with:" + jmse.getMessage());
+ _fail = jmse;
+ }
+ System.out.println("Connection isClosed after connection Falure?:" + connection.isClosed());
+
+ _latch.countDown();
+
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java
index b932b1d784..5d8ee785ec 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java
@@ -77,7 +77,7 @@ public class ConnectionCloseTest extends QpidTestCase
// This should leave the finalizer enough time to notify those threads
synchronized (this)
{
- this.wait(1000);
+ this.wait(10000);
}
Map<Thread,StackTraceElement[]> after = Thread.getAllStackTraces();
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java
index a6e8b80c9c..a892b3baad 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java
@@ -23,12 +23,19 @@ package org.apache.qpid.test.unit.client.connection;
import org.apache.qpid.AMQConnectionFailureException;
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQUnresolvedAddressException;
+import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.test.utils.QpidTestCase;
import org.apache.qpid.client.AMQAuthenticationException;
import org.apache.qpid.client.AMQConnection;
import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.client.AMQConnectionURL;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.jms.Session;
+import org.apache.qpid.jms.ConnectionURL;
+import org.apache.qpid.jms.BrokerDetails;
import javax.jms.Connection;
import javax.jms.QueueSession;
@@ -41,34 +48,12 @@ public class ConnectionTest extends QpidTestCase
String _broker_NotRunning = "vm://:2";
String _broker_BadDNS = "tcp://hg3sgaaw4lgihjs";
- public String getBroker()
- {
- try
- {
- if (getConnectionFactory().getConnectionURL().getBrokerCount() > 0)
- {
- return getConnectionFactory().getConnectionURL().getBrokerDetails(0).toString();
- }
- else
- {
- fail("No broker details are available.");
- }
- }
- catch (NamingException e)
- {
- fail(e.getMessage());
- }
-
- //keep compiler happy
- return null;
- }
-
public void testSimpleConnection() throws Exception
{
AMQConnection conn = null;
try
{
- conn = new AMQConnection(getBroker(), "guest", "guest", "fred", "test");
+ conn = new AMQConnection(getBroker().toString(), "guest", "guest", "fred", "test");
}
catch (Exception e)
{
@@ -85,13 +70,33 @@ public class ConnectionTest extends QpidTestCase
AMQConnection conn = null;
try
{
- conn = new AMQConnection("amqp://guest:guest@clientid/test?brokerlist='"
- + getBroker()
- + "?retries='1''&defaultQueueExchange='test.direct'"
+ BrokerDetails broker = getBroker();
+ broker.setProperty(BrokerDetails.OPTIONS_RETRY, "1");
+ ConnectionURL url = new AMQConnectionURL("amqp://guest:guest@clientid/test?brokerlist='"
+ + broker
+ + "'&defaultQueueExchange='test.direct'"
+ "&defaultTopicExchange='test.topic'"
+ "&temporaryQueueExchange='tmp.direct'"
+ "&temporaryTopicExchange='tmp.topic'");
+ System.err.println(url.toString());
+ conn = new AMQConnection(url, null);
+
+
+ AMQSession sess = (AMQSession) conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ sess.declareExchange(new AMQShortString("test.direct"),
+ ExchangeDefaults.DIRECT_EXCHANGE_CLASS, false);
+
+ sess.declareExchange(new AMQShortString("tmp.direct"),
+ ExchangeDefaults.DIRECT_EXCHANGE_CLASS, false);
+
+ sess.declareExchange(new AMQShortString("tmp.topic"),
+ ExchangeDefaults.TOPIC_EXCHANGE_CLASS, false);
+
+ sess.declareExchange(new AMQShortString("test.topic"),
+ ExchangeDefaults.TOPIC_EXCHANGE_CLASS, false);
+
QueueSession queueSession = conn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
AMQQueue queue = (AMQQueue) queueSession.createQueue("MyQueue");
@@ -105,7 +110,7 @@ public class ConnectionTest extends QpidTestCase
queueSession.close();
TopicSession topicSession = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
-
+
AMQTopic topic = (AMQTopic) topicSession.createTopic("silly.topic");
assertEquals(topic.getExchangeName().toString(), "test.topic");
@@ -132,7 +137,9 @@ public class ConnectionTest extends QpidTestCase
AMQConnection conn = null;
try
{
- conn = new AMQConnection("amqp://guest:rubbishpassword@clientid/test?brokerlist='" + getBroker() + "?retries='0''");
+ BrokerDetails broker = getBroker();
+ broker.setProperty(BrokerDetails.OPTIONS_RETRY, "0");
+ conn = new AMQConnection("amqp://guest:rubbishpassword@clientid/test?brokerlist='" + broker + "'");
fail("Connection should not be established password is wrong.");
}
catch (AMQConnectionFailureException amqe)
@@ -204,7 +211,9 @@ public class ConnectionTest extends QpidTestCase
AMQConnection conn = null;
try
{
- conn = new AMQConnection("amqp://guest:guest@clientid/rubbishhost?brokerlist='" + getBroker() + "?retries='0''");
+ BrokerDetails broker = getBroker();
+ broker.setProperty(BrokerDetails.OPTIONS_RETRY, "0");
+ conn = new AMQConnection("amqp://guest:guest@clientid/rubbishhost?brokerlist='" + broker + "'");
fail("Connection should not be established");
}
catch (AMQException amqe)
@@ -225,7 +234,7 @@ public class ConnectionTest extends QpidTestCase
public void testClientIdCannotBeChanged() throws Exception
{
- Connection connection = new AMQConnection(getBroker(), "guest", "guest",
+ Connection connection = new AMQConnection(getBroker().toString(), "guest", "guest",
"fred", "test");
try
{
@@ -247,7 +256,7 @@ public class ConnectionTest extends QpidTestCase
public void testClientIdIsPopulatedAutomatically() throws Exception
{
- Connection connection = new AMQConnection(getBroker(), "guest", "guest",
+ Connection connection = new AMQConnection(getBroker().toString(), "guest", "guest",
null, "test");
try
{
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/Client.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/Client.java
index 0be11011b4..d911bb33d7 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/Client.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/Client.java
@@ -29,6 +29,7 @@ import org.apache.qpid.test.utils.QpidTestCase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
@@ -62,7 +63,7 @@ public class Client implements MessageListener
{
_connection = connection;
_expected = expected;
- _session = (AMQSession) _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+ _session = (AMQSession) _connection.createSession(true, AMQSession.NO_ACKNOWLEDGE);
AMQQueue response =
new AMQQueue(_connection.getDefaultQueueExchangeName(), new AMQShortString("ResponseQueue"), true);
_session.createConsumer(response).setMessageListener(this);
@@ -73,6 +74,7 @@ public class Client implements MessageListener
request.setJMSReplyTo(response);
MessageProducer prod = _session.createProducer(service);
prod.send(request);
+ _session.commit();
}
void shutdownWhenComplete() throws Exception
@@ -90,6 +92,14 @@ public class Client implements MessageListener
notifyAll();
}
+ try
+ {
+ _session.commit();
+ }
+ catch (JMSException e)
+ {
+
+ }
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/Service.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/Service.java
index 9cd8b183af..ce50ceae19 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/Service.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/Service.java
@@ -55,7 +55,7 @@ public class Service implements MessageListener
{
_connection = connection;
//AMQQueue queue = new SpecialQueue(connection, "ServiceQueue");
- _session = (AMQSession) _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+ _session = (AMQSession) _connection.createSession(true, AMQSession.NO_ACKNOWLEDGE);
AMQQueue queue = (AMQQueue) _session.createQueue("ServiceQueue") ;
_session.createConsumer(queue).setMessageListener(this);
_connection.start();
@@ -68,6 +68,7 @@ public class Service implements MessageListener
Message response = _session.createTextMessage("Response!");
Destination replyTo = request.getJMSReplyTo();
_session.createProducer(replyTo).send(response);
+ _session.commit();
}
catch (Exception e)
{
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/protocol/AMQProtocolSessionTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/protocol/AMQProtocolSessionTest.java
index 91cb37e455..7a27925a36 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/client/protocol/AMQProtocolSessionTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/protocol/AMQProtocolSessionTest.java
@@ -20,27 +20,27 @@
*/
package org.apache.qpid.test.unit.client.protocol;
-import org.apache.mina.common.IoSession;
import org.apache.qpid.client.AMQConnection;
import org.apache.qpid.client.protocol.AMQProtocolHandler;
import org.apache.qpid.client.protocol.AMQProtocolSession;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.test.utils.QpidTestCase;
-import org.apache.qpid.test.utils.protocol.TestIoSession;
+import org.apache.qpid.transport.TestNetworkDriver;
+import org.apache.qpid.transport.NetworkDriver;
public class AMQProtocolSessionTest extends QpidTestCase
{
private static class AMQProtSession extends AMQProtocolSession
{
- public AMQProtSession(AMQProtocolHandler protocolHandler, IoSession protocolSession, AMQConnection connection)
+ public AMQProtSession(AMQProtocolHandler protocolHandler, AMQConnection connection)
{
- super(protocolHandler,protocolSession,connection);
+ super(protocolHandler,connection);
}
- public TestIoSession getMinaProtocolSession()
+ public TestNetworkDriver getNetworkDriver()
{
- return (TestIoSession) _minaProtocolSession;
+ return (TestNetworkDriver) _protocolHandler.getNetworkDriver();
}
public AMQShortString genQueueName()
@@ -63,8 +63,11 @@ public class AMQProtocolSessionTest extends QpidTestCase
{
super.setUp();
+ AMQConnection con = (AMQConnection) getConnection("guest", "guest");
+ AMQProtocolHandler protocolHandler = new AMQProtocolHandler(con);
+ protocolHandler.setNetworkDriver(new TestNetworkDriver());
//don't care about the values set here apart from the dummy IoSession
- _testSession = new AMQProtSession(null,new TestIoSession(), (AMQConnection) getConnection("guest", "guest"));
+ _testSession = new AMQProtSession(protocolHandler , con);
//initialise addresses for test and expected results
_port = 123;
@@ -81,20 +84,20 @@ public class AMQProtocolSessionTest extends QpidTestCase
AMQShortString testAddress;
//test address with / and ; chars which generateQueueName should removeKey
- _testSession.getMinaProtocolSession().setStringLocalAddress(_brokenAddress);
- _testSession.getMinaProtocolSession().setLocalPort(_port);
+ _testSession.getNetworkDriver().setLocalAddress(_brokenAddress);
+ _testSession.getNetworkDriver().setPort(_port);
testAddress = _testSession.genQueueName();
assertEquals("Failure when generating a queue exchange from an address with special chars",_generatedAddress,testAddress.toString());
//test empty address
- _testSession.getMinaProtocolSession().setStringLocalAddress(_emptyAddress);
+ _testSession.getNetworkDriver().setLocalAddress(_emptyAddress);
testAddress = _testSession.genQueueName();
assertEquals("Failure when generating a queue exchange from an empty address",_generatedAddress_2,testAddress.toString());
//test address with no special chars
- _testSession.getMinaProtocolSession().setStringLocalAddress(_validAddress);
+ _testSession.getNetworkDriver().setLocalAddress(_validAddress);
testAddress = _testSession.genQueueName();
assertEquals("Failure when generating a queue exchange from an address with no special chars",_generatedAddress_3,testAddress.toString());
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java
index 7a65b06dd4..1d48955461 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java
@@ -22,6 +22,7 @@
package org.apache.qpid.test.unit.client.temporaryqueue;
import javax.jms.Connection;
+import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
@@ -32,12 +33,16 @@ import junit.framework.Assert;
import org.apache.qpid.test.utils.QpidTestCase;
import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.jms.ConnectionListener;
+import java.util.ArrayList;
import java.util.List;
import java.util.LinkedList;
-public class TemporaryQueueTest extends QpidTestCase
+public class TemporaryQueueTest extends QpidTestCase implements ExceptionListener
{
+ private List<Exception> _exceptions = new ArrayList<Exception>();
+
protected void setUp() throws Exception
{
super.setUp();
@@ -53,7 +58,7 @@ public class TemporaryQueueTest extends QpidTestCase
return getConnection("guest", "guest");
}
- public void testTempoaryQueue() throws Exception
+ public void testTemporaryQueue() throws Exception
{
Connection conn = createConnection();
Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
@@ -212,9 +217,42 @@ public class TemporaryQueueTest extends QpidTestCase
}
}
-
+ public void testQPID1217() throws Exception
+ {
+ Connection conA = getConnection();
+ conA.setExceptionListener(this);
+ Session sessA = conA.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ TemporaryQueue temp = sessA.createTemporaryQueue();
+
+ MessageProducer prod = sessA.createProducer(temp);
+ prod.send(sessA.createTextMessage("hi"));
+
+ Thread.sleep(500);
+ assertTrue("Exception received", _exceptions.isEmpty());
+
+ Connection conB = getConnection();
+ Session sessB = conB.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ JMSException ex = null;
+ try
+ {
+ MessageConsumer consB = sessB.createConsumer(temp);
+ }
+ catch (JMSException e)
+ {
+ ex = e;
+ }
+ assertNotNull(ex);
+ }
+
public static junit.framework.Test suite()
{
return new junit.framework.TestSuite(TemporaryQueueTest.class);
}
+
+ public void onException(JMSException arg0)
+ {
+ _exceptions.add(arg0);
+ }
+
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/close/JavaServerCloseRaceConditionTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/close/JavaServerCloseRaceConditionTest.java
new file mode 100644
index 0000000000..3fb6cd3526
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/close/JavaServerCloseRaceConditionTest.java
@@ -0,0 +1,119 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.close;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.framing.AMQFrame;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ExchangeDeclareBody;
+import org.apache.qpid.framing.ExchangeDeclareOkBody;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+import javax.jms.Session;
+
+/** QPID-1809
+ *
+ * Race condition on error handling and close logic.
+ *
+ * See most often with SimpleACLTest as this test is the expects the server to
+ * shut the connection/channels. This sort of testing is not performed by many,
+ * if any, of the other system tests.
+ *
+ * The problem is that we have two threads
+ *
+ * MainThread Exception(Mina)Thread
+ * | |
+ * Performs |
+ * ACtion |
+ * | Receives Server
+ * | Close
+ * Blocks for |
+ * Response |
+ * | Starts To Notify
+ * | client
+ * | |
+ * | <----- Notify Main Thread
+ * Notification |
+ * wakes client |
+ * | |
+ * Client then |
+ * processes Error. |
+ * | |
+ * Potentially Attempting Close Channel/Connection
+ * Connection Close
+ *
+ * The two threads both attempt to close the connection but the main thread does
+ * so assuming that the connection is open and valid.
+ *
+ * The Exception thread must modify the connection so that no furter syncWait
+ * commands are performed.
+ *
+ * This test sends an ExchangeDeclare that is Asynchronous and will fail and
+ * so cause a ChannelClose error but we perform a syncWait so that we can be
+ * sure to test that the BlockingWaiter is correctly awoken.
+ *
+ */
+public class JavaServerCloseRaceConditionTest extends QpidTestCase
+{
+ private static final String EXCHANGE_NAME = "NewExchangeNametoFailLookup";
+
+ public void test() throws Exception
+ {
+
+ AMQConnection connection = (AMQConnection) getConnection();
+
+ AMQSession session = (AMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Set no wait true so that we block the connection
+ // Also set a different exchange class string so the attempt to declare
+ // the exchange causes an exchange.
+ ExchangeDeclareBody body = session.getMethodRegistry().createExchangeDeclareBody(session.getTicket(), new AMQShortString(EXCHANGE_NAME), null,
+ true, false, false, false, true, null);
+
+ AMQFrame exchangeDeclare = body.generateFrame(session.getChannelId());
+
+ try
+ {
+ // block our thread so that can times out
+ connection.getProtocolHandler().syncWrite(exchangeDeclare, ExchangeDeclareOkBody.class);
+ }
+ catch (Exception e)
+ {
+ assertTrue("Exception should say the exchange is not known.", e.getMessage().contains("Unknown exchange: " + EXCHANGE_NAME));
+ }
+
+ try
+ {
+ // Depending on if the notification thread has closed the connection
+ // or not we may get an exception here when we attempt to close the
+ // connection. If we do get one then it should be the same as above
+ // an AMQAuthenticationException.
+ connection.close();
+ }
+ catch (Exception e)
+ {
+ assertTrue("Exception should say the exchange is not known.", e.getMessage().contains("Unknown exchange: " + EXCHANGE_NAME));
+ }
+
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java
index ec23256f38..f1cac22f08 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java
@@ -50,7 +50,8 @@ public class MessageRequeueTest extends QpidTestCase
protected final String queue = "direct://amq.direct//message-requeue-test-queue";
protected String payload = "Message:";
- protected final String BROKER = "vm://:1";
+ //protected final String BROKER = "vm://:1";
+ protected final String BROKER = "tcp://127.0.0.1:5672";
private boolean testReception = true;
private long[] receieved = new long[numTestMessages + 1];
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/close/VerifyAckingOkDuringClose.java b/java/systests/src/main/java/org/apache/qpid/test/unit/close/VerifyAckingOkDuringClose.java
new file mode 100644
index 0000000000..3b30b7d63f
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/close/VerifyAckingOkDuringClose.java
@@ -0,0 +1,160 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.close;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.jndi.PropertiesFileInitialContextFactory;
+
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.naming.InitialContext;
+import java.util.ArrayList;
+
+/**
+ * QPID-1791
+ *
+ * The threading model in the Java broker (at least till 0.5) allows for the
+ * close to be handled immediately even if the broker is still processing state
+ * for that Session.
+ *
+ * This test verifys that QPID-1791 is has been handled.
+ *
+ * The problem was that the whilst the Session is busy processing Acks from the
+ * client the Close frame jumps in and clears the unAcknowledgeMap in an
+ * attempt to start processing them for closing the connection.
+ *
+ * If the session had a consumer consuming from a temporary queue. The closing
+ * thread dequeues and deletes the message that were on the uncknowledgedMap.
+ *
+ * However, the Acking thread currently does:
+ * queuEntry = unackedMap.get(messageID)
+ *
+ * dequeueAndDelete(queueEntry)
+ *
+ * unackedMap.remove(messageID)
+ *
+ * As a result the queueEntry is sitting in the unackedMap whilst it is being
+ * dequeuedAndDeleted which leaves the opportunity for the close thread to
+ * remove contents of the unackedMap for processing. The close thread will then
+ * dequeueAndDelete all these values one of which the acking thread is currently
+ * processing.
+ *
+ *
+ * Test Approach
+ *
+ * Send a lot of persistent messages (5000), the goal of which is to fill the
+ * pretch and to provide the broker with a lot of acks to process
+ *
+ * Using client ack and prefetch buffer of 5000 use receive to get 2500
+ * Use AMQMessage.acknowledgeThis() to send a single ack frame back to the
+ * broker per message so 2500 ack frames.
+ * This will give the broker a lot to process,
+ * Immediately send the consumer close after the acks are all gone.
+ * This will cause the remaining 2500 prefetched messages plus any that have
+ * not yet had their acks processed
+ * to be collected by the requeue() process potentially
+ */
+public class VerifyAckingOkDuringClose
+{
+
+ static final int MESSAGE_SENT = 5000;
+
+ public static void main(String[] args) throws Exception
+ {
+ //Check that we have the InitialContext Configured
+
+ if (System.getProperty(InitialContext.INITIAL_CONTEXT_FACTORY) == null)
+ {
+ System.setProperty(InitialContext.INITIAL_CONTEXT_FACTORY, PropertiesFileInitialContextFactory.class.getName());
+ }
+
+ if (System.getProperty(InitialContext.PROVIDER_URL) == null)
+ {
+ System.err.println(InitialContext.PROVIDER_URL + ": Is not set and is required to contain a 'default' ConnectionFactory.");
+ System.exit(1);
+ }
+
+ //Retreive the local factory from the properties file
+ // when used with perftest.properties this will be localhost:5672
+ AMQConnectionFactory factory = (AMQConnectionFactory) new InitialContext().lookup("default");
+
+ AMQConnection connection = (AMQConnection) factory.createConnection("guest", "guest");
+
+ //Use the AMQConnection Interface to set the prefetch to the number
+ // we are sending
+ Session session = connection.createSession(false,
+ Session.CLIENT_ACKNOWLEDGE,
+ MESSAGE_SENT);
+
+ Queue queue = session.createTemporaryQueue();
+
+ MessageConsumer consumer = session.createConsumer(queue);
+ connection.start();
+
+ MessageProducer producer = session.createProducer(queue);
+
+ Message message = session.createTextMessage("Close");
+
+ for (int i = 0; i < MESSAGE_SENT; i++)
+ {
+ message.setIntProperty("SequenceNumber", i);
+
+ producer.send(message);
+ }
+
+ // Put a reasonable about of data on the queue.
+
+ //Receive all the messags
+ ArrayList<Message> received = new ArrayList<Message>();
+
+ message = consumer.receive(2000);
+
+ while (message != null)
+ {
+ received.add(message);
+ message = consumer.receive(2000);
+ }
+
+ //Check we have all the messages
+ if (received.size() != MESSAGE_SENT)
+ {
+ System.err.println("Test Failed Not all the messages received:" + received.size());
+ System.exit(1);
+ }
+
+ //individually ack the first half then close
+ for (int i = 0; i < MESSAGE_SENT / 2; i++)
+ {
+ ((org.apache.qpid.jms.Message) received.get(i)).acknowledgeThis();
+ }
+
+ // Close the Session to force a requeue on the server of the unackedMsgs
+
+ System.out.println("Killing client to force requeue on broker");
+
+ System.exit(1);
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSDestinationTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSDestinationTest.java
deleted file mode 100644
index b30e3c1c1c..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSDestinationTest.java
+++ /dev/null
@@ -1,89 +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.
- *
- */
-
-package org.apache.qpid.test.unit.message;
-
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQQueue;
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.test.utils.QpidTestCase;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.jms.Connection;
-import javax.jms.MessageConsumer;
-import javax.jms.MessageProducer;
-import javax.jms.Queue;
-import javax.jms.Session;
-import javax.jms.TextMessage;
-
-/**
- * @author Apache Software Foundation
- */
-public class JMSDestinationTest extends QpidTestCase
-{
- private static final Logger _logger = LoggerFactory.getLogger(JMSDestinationTest.class);
-
-
- protected void setUp() throws Exception
- {
- super.setUp();
- }
-
- protected void tearDown() throws Exception
- {
- super.tearDown();
- }
-
- public void testJMSDestination() throws Exception
- {
- AMQConnection con = (AMQConnection) getConnection("guest", "guest");
- AMQSession consumerSession = (AMQSession) con.createSession(false, Session.CLIENT_ACKNOWLEDGE);
- Queue queue =
- new AMQQueue(con.getDefaultQueueExchangeName(), new AMQShortString("someQ"), new AMQShortString("someQ"), false,
- true);
- MessageConsumer consumer = consumerSession.createConsumer(queue);
-
- Connection con2 = (AMQConnection) getConnection("guest", "guest");
- Session producerSession = con2.createSession(false, Session.CLIENT_ACKNOWLEDGE);
- MessageProducer producer = producerSession.createProducer(queue);
-
- TextMessage sentMsg = producerSession.createTextMessage("hello");
- assertNull(sentMsg.getJMSDestination());
-
- producer.send(sentMsg);
-
- assertEquals(sentMsg.getJMSDestination(), queue);
-
- con2.close();
-
- con.start();
-
- TextMessage rm = (TextMessage) consumer.receive();
- assertNotNull(rm);
-
- assertEquals(rm.getJMSDestination(), queue);
- con.close();
- }
-
-}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java
index 1f90f1e29f..6b69ccab6c 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java
@@ -31,6 +31,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jms.Destination;
+import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
@@ -105,7 +106,8 @@ public class JMSPropertiesTest extends QpidTestCase
assertEquals("JMS Type mismatch", sentMsg.getJMSType(), rm.getJMSType());
assertEquals("JMS Reply To mismatch", sentMsg.getJMSReplyTo(), rm.getJMSReplyTo());
assertTrue("JMSMessageID Does not start ID:", rm.getJMSMessageID().startsWith("ID:"));
-
+ assertEquals("JMS Default priority should be 4",Message.DEFAULT_PRIORITY,rm.getJMSPriority());
+
//Validate that the JMSX values are correct
assertEquals("JMSXGroupID is not as expected:", JMSXGroupID_VALUE, rm.getStringProperty("JMSXGroupID"));
assertEquals("JMSXGroupSeq is not as expected:", JMSXGroupSeq_VALUE, rm.getIntProperty("JMSXGroupSeq"));
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/message/StreamMessageTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/message/StreamMessageTest.java
index 6fa0172ae3..7978e2c818 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/message/StreamMessageTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/message/StreamMessageTest.java
@@ -24,6 +24,7 @@ import org.apache.qpid.client.AMQConnection;
import org.apache.qpid.client.AMQHeadersExchange;
import org.apache.qpid.client.AMQQueue;
import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.configuration.ClientProperties;
import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
@@ -76,8 +77,7 @@ public class StreamMessageTest extends QpidTestCase
FieldTable ft = new FieldTable();
ft.setString("F1000", "1");
MessageConsumer consumer =
- consumerSession.createConsumer(queue, AMQSession.DEFAULT_PREFETCH_LOW_MARK,
- AMQSession.DEFAULT_PREFETCH_HIGH_MARK, false, false, (String) null, ft);
+ consumerSession.createConsumer(queue, Integer.parseInt(ClientProperties.MAX_PREFETCH_DEFAULT), Integer.parseInt(ClientProperties.MAX_PREFETCH_DEFAULT), false, false, (String) null, ft);
// force synch to ensure the consumer has resulted in a bound queue
// ((AMQSession) consumerSession).declareExchangeSynch(ExchangeDefaults.HEADERS_EXCHANGE_NAME, ExchangeDefaults.HEADERS_EXCHANGE_CLASS);
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8En b/java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8En
new file mode 100644
index 0000000000..c9734b1988
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8En
@@ -0,0 +1,4 @@
+exhangeName
+queueName
+routingkey
+data \ No newline at end of file
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8Jp b/java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8Jp
new file mode 100644
index 0000000000..ae10752dab
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8Jp
@@ -0,0 +1,4 @@
+設定がそのように構成されていなければな
+的某些更新没有出现在这个 README 中。你可以访问下面的
+的发行版本包括多张光盘,其中包括安装光盘和源码光盘
+目のインストール CD は、ほとんどの最近のシス \ No newline at end of file
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8Test.java b/java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8Test.java
new file mode 100644
index 0000000000..8a9aee94dd
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8Test.java
@@ -0,0 +1,122 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.message;
+
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.Session;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.naming.InitialContext;
+import javax.jms.*;
+import java.util.Properties;
+import java.io.*;
+
+
+/**
+ * @author Apache Software Foundation
+ * This test makes sure that utf8 characters can be used for
+ * specifying exchange, queue name and routing key.
+ *
+ * those tests are related to qpid-1384
+ */
+public class UTF8Test extends QpidTestCase
+{
+ private static final Logger _logger = LoggerFactory.getLogger(UTF8Test.class);
+
+
+ public void testPlainEn() throws Exception
+ {
+ invoke("UTF8En");
+ }
+
+
+ public void testUTF8Jp() throws Exception
+ {
+ invoke("UTF8Jp");
+ }
+
+
+ private void invoke(String name) throws Exception
+ {
+ String path = System.getProperties().getProperty("QPID_HOME");
+ path = path + "/../systests/src/main/java/org/apache/qpid/test/unit/message/" + name;
+ BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(path), "UTF8"));
+ runTest(in.readLine(), in.readLine(), in.readLine(), in.readLine());
+ in.close();
+ }
+ private void runTest(String exchangeName, String queueName, String routingKey, String data) throws Exception
+ {
+ _logger.info("Running test for exchange: " + exchangeName
+ + " queue Name: " + queueName
+ + " routing key: " + routingKey);
+ declareQueue(exchangeName, routingKey, queueName);
+
+ javax.jms.Connection con = getConnection();
+ javax.jms.Session sess = con.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
+ Destination dest = getDestination(exchangeName, routingKey, queueName);
+ // Send data
+ MessageProducer msgProd = sess.createProducer(dest);
+ TextMessage message = sess.createTextMessage(data);
+ msgProd.send(message);
+ // consume data
+ MessageConsumer msgCons = sess.createConsumer(dest);
+ con.start();
+ TextMessage m = (TextMessage) msgCons.receive(RECEIVE_TIMEOUT);
+ assertNotNull(m);
+ assertEquals(m.getText(), data);
+ }
+
+ private void declareQueue(String exch, String routkey, String qname) throws Exception
+ {
+ Connection conn = new Connection();
+ if (!_broker.equals(QpidTestCase.EXTERNAL) && !isBroker08())
+ {
+ conn.connect("localhost", QpidTestCase.DEFAULT_PORT, "test", "guest", "guest",false);
+ }
+ else
+ {
+ throw new Exception("unsupported test " +
+ "configuration. broker: " + _broker + " version > 0.10 "+ !isBroker08() + " This test must be run on a local broker using protocol 0.10 or higher.");
+ }
+ Session sess = conn.createSession(0);
+ sess.exchangeDeclare(exch, "direct", null, null);
+ sess.queueDeclare(qname, null, null);
+ sess.exchangeBind(qname, exch, routkey, null);
+ sess.sync();
+ conn.close();
+ }
+
+ private Destination getDestination(String exch, String routkey, String qname)
+ throws Exception
+ {
+ Properties props = new Properties();
+ props.setProperty("destination.directUTF8Queue",
+ "direct://" + exch + "//" + qname + "?autodelete='false'&durable='false'"
+ + "&routingkey='" + routkey + "'");
+
+ // Get our connection context
+ InitialContext ctx = new InitialContext(props);
+ return (Destination) ctx.lookup("directUTF8Queue");
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/publish/DirtyTrasactedPubilshTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/publish/DirtyTrasactedPubilshTest.java
new file mode 100644
index 0000000000..248042d2c4
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/publish/DirtyTrasactedPubilshTest.java
@@ -0,0 +1,403 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.publish;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.jms.ConnectionListener;
+import org.apache.qpid.test.utils.FailoverBaseCase;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TransactionRolledBackException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * QPID-1816 : Whilst testing Acknoledgement after failover this completes testing
+ * of the client after failover. When we have a dirty session we should receive
+ * an error if we attempt to publish. This test ensures that both in the synchronous
+ * and asynchronous message delivery paths we receive the expected exceptions at
+ * the expected time.
+ */
+public class DirtyTrasactedPubilshTest extends FailoverBaseCase implements ConnectionListener
+{
+ protected CountDownLatch _failoverCompleted = new CountDownLatch(1);
+
+ protected int NUM_MESSAGES;
+ protected Connection _connection;
+ protected Queue _queue;
+ protected Session _consumerSession;
+ protected MessageConsumer _consumer;
+ protected MessageProducer _producer;
+
+ private static final String MSG = "MSG";
+ private static final String SEND_FROM_ON_MESSAGE_TEXT = "sendFromOnMessage";
+ protected CountDownLatch _receviedAll;
+ protected AtomicReference<Exception> _causeOfFailure = new AtomicReference<Exception>(null);
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ NUM_MESSAGES = 10;
+
+ _queue = getTestQueue();
+
+ //Create Producer put some messages on the queue
+ _connection = getConnection();
+ }
+
+ /**
+ * Initialise the test variables
+ * @param transacted is this a transacted test
+ * @param mode if not trasacted then what ack mode to use
+ * @throws Exception if there is a setup issue.
+ */
+ protected void init(boolean transacted, int mode) throws Exception
+ {
+ _consumerSession = _connection.createSession(transacted, mode);
+ _consumer = _consumerSession.createConsumer(_queue);
+ _producer = _consumerSession.createProducer(_queue);
+
+ // These should all end up being prefetched by session
+ sendMessage(_consumerSession, _queue, 1);
+
+ assertEquals("Wrong number of messages on queue", 1,
+ ((AMQSession) _consumerSession).getQueueDepth((AMQDestination) _queue));
+ }
+
+ /**
+ * If a transacted session has failed over whilst it has uncommitted sent
+ * data then we need to throw a TransactedRolledbackException on commit()
+ *
+ * The alternative would be to maintain a replay buffer so that the message
+ * could be resent. This is not currently implemented
+ *
+ * @throws Exception if something goes wrong.
+ */
+ public void testDirtySendingSynchronousTransacted() throws Exception
+ {
+ Session producerSession = _connection.createSession(true, Session.SESSION_TRANSACTED);
+
+ // Ensure we get failover notifications
+ ((AMQConnection) _connection).setConnectionListener(this);
+
+ MessageProducer producer = producerSession.createProducer(_queue);
+
+ // Create and send message 0
+ Message msg = producerSession.createMessage();
+ msg.setIntProperty(INDEX, 0);
+ producer.send(msg);
+
+ // DON'T commit message .. fail connection
+
+ failBroker(getFailingPort());
+
+ // Ensure destination exists for sending
+ producerSession.createConsumer(_queue).close();
+
+ // Send the next message
+ msg.setIntProperty(INDEX, 1);
+ try
+ {
+ producer.send(msg);
+ fail("Should fail with Qpid as we provide early warning of the dirty session via a JMSException.");
+ }
+ catch (JMSException jmse)
+ {
+ assertEquals("Early warning of dirty session not correct",
+ "Failover has occurred and session is dirty so unable to send.", jmse.getMessage());
+ }
+
+ // Ignore that the session is dirty and attempt to commit to validate the
+ // exception is thrown. AND that the above failure notification did NOT
+ // clean up the session.
+
+ try
+ {
+ producerSession.commit();
+ fail("Session is dirty we should get an TransactionRolledBackException");
+ }
+ catch (TransactionRolledBackException trbe)
+ {
+ // Normal path.
+ }
+
+ // Resending of messages should now work ok as the commit was forcilbly rolledback
+ msg.setIntProperty(INDEX, 0);
+ producer.send(msg);
+ msg.setIntProperty(INDEX, 1);
+ producer.send(msg);
+
+ producerSession.commit();
+
+ assertEquals("Wrong number of messages on queue", 2,
+ ((AMQSession) producerSession).getQueueDepth((AMQDestination) _queue));
+ }
+
+ /**
+ * If a transacted session has failed over whilst it has uncommitted sent
+ * data then we need to throw a TransactedRolledbackException on commit()
+ *
+ * The alternative would be to maintain a replay buffer so that the message
+ * could be resent. This is not currently implemented
+ *
+ * @throws Exception if something goes wrong.
+ */
+ public void testDirtySendingOnMessageTransacted() throws Exception
+ {
+ NUM_MESSAGES = 1;
+ _receviedAll = new CountDownLatch(NUM_MESSAGES);
+ ((AMQConnection) _connection).setConnectionListener(this);
+
+ init(true, Session.SESSION_TRANSACTED);
+
+ _consumer.setMessageListener(new MessageListener()
+ {
+
+ public void onMessage(Message message)
+ {
+ try
+ {
+ // Create and send message 0
+ Message msg = _consumerSession.createMessage();
+ msg.setIntProperty(INDEX, 0);
+ _producer.send(msg);
+
+ // DON'T commit message .. fail connection
+
+ failBroker(getFailingPort());
+
+ // rep
+ repopulateBroker();
+
+ // Destination will exist as this failBroker will populate
+ // the queue with 1 message
+
+ // Send the next message
+ msg.setIntProperty(INDEX, 1);
+ try
+ {
+ _producer.send(msg);
+ fail("Should fail with Qpid as we provide early warning of the dirty session via a JMSException.");
+ }
+ catch (JMSException jmse)
+ {
+ assertEquals("Early warning of dirty session not correct",
+ "Failover has occurred and session is dirty so unable to send.", jmse.getMessage());
+ }
+
+ // Ignore that the session is dirty and attempt to commit to validate the
+ // exception is thrown. AND that the above failure notification did NOT
+ // clean up the session.
+
+ try
+ {
+ _consumerSession.commit();
+ fail("Session is dirty we should get an TransactionRolledBackException");
+ }
+ catch (TransactionRolledBackException trbe)
+ {
+ // Normal path.
+ }
+
+ // Resend messages
+ msg.setIntProperty(INDEX, 0);
+ msg.setStringProperty(MSG, SEND_FROM_ON_MESSAGE_TEXT);
+ _producer.send(msg);
+ msg.setIntProperty(INDEX, 1);
+ msg.setStringProperty(MSG, SEND_FROM_ON_MESSAGE_TEXT);
+ _producer.send(msg);
+
+ _consumerSession.commit();
+
+ // Stop this consumer .. can't do _consumer.stop == DEADLOCK
+ // this doesn't seem to stop dispatcher running
+ _connection.stop();
+
+ // Signal that the onMessage send part of test is complete
+ // main thread can validate that messages are correct
+ _receviedAll.countDown();
+
+ }
+ catch (Exception e)
+ {
+ fail(e);
+ }
+
+ }
+
+ });
+
+ _connection.start();
+
+ if (!_receviedAll.await(10000L, TimeUnit.MILLISECONDS))
+ {
+ // Check to see if we ended due to an exception in the onMessage handler
+ Exception cause = _causeOfFailure.get();
+ if (cause != null)
+ {
+ cause.printStackTrace();
+ fail(cause.getMessage());
+ }
+ else
+ {
+ fail("All messages not received:" + _receviedAll.getCount() + "/" + NUM_MESSAGES);
+ }
+ }
+
+ // Check to see if we ended due to an exception in the onMessage handler
+ Exception cause = _causeOfFailure.get();
+ if (cause != null)
+ {
+ cause.printStackTrace();
+ fail(cause.getMessage());
+ }
+
+ _consumer.close();
+ _consumerSession.close();
+
+ _consumerSession = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _connection.start();
+
+ // Validate that we could send the messages as expected.
+ assertEquals("Wrong number of messages on queue", 3,
+ ((AMQSession) _consumerSession).getQueueDepth((AMQDestination) _queue));
+
+ MessageConsumer consumer = _consumerSession.createConsumer(_queue);
+
+ //Validate the message sent to setup the failed over broker.
+ Message message = consumer.receive(1000);
+ assertNotNull("Message " + 0 + " not received.", message);
+ assertEquals("Incorrect message received", 0, message.getIntProperty(INDEX));
+
+ // Validate the two messages sent from within the onMessage
+ for (int index = 0; index <= 1; index++)
+ {
+ message = consumer.receive(1000);
+ assertNotNull("Message " + index + " not received.", message);
+ assertEquals("Incorrect message received", index, message.getIntProperty(INDEX));
+ assertEquals("Incorrect message text for message:" + index, SEND_FROM_ON_MESSAGE_TEXT, message.getStringProperty(MSG));
+ }
+
+ assertNull("Extra message received.", consumer.receiveNoWait());
+
+ _consumerSession.close();
+
+ assertEquals("Wrong number of messages on queue", 0,
+ ((AMQSession) getConnection().createSession(false, Session.AUTO_ACKNOWLEDGE)).getQueueDepth((AMQDestination) _queue));
+ }
+
+ private void repopulateBroker() throws Exception
+ {
+ // Repopulate this new broker so we can test what happends after failover
+
+ //Get the connection to the first (main port) broker.
+ Connection connection = getConnection();
+ // Use a transaction to send messages so we can be sure they arrive.
+ Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+ // ensure destination is created.
+ session.createConsumer(_queue).close();
+
+ sendMessage(session, _queue, NUM_MESSAGES);
+
+ assertEquals("Wrong number of messages on queue", NUM_MESSAGES,
+ ((AMQSession) session).getQueueDepth((AMQDestination) _queue));
+
+ connection.close();
+ }
+
+ // AMQConnectionListener Interface.. used so we can validate that we
+ // actually failed over.
+
+ public void bytesSent(long count)
+ {
+ }
+
+ public void bytesReceived(long count)
+ {
+ }
+
+ public boolean preFailover(boolean redirect)
+ {
+ //Allow failover
+ return true;
+ }
+
+ public boolean preResubscribe()
+ {
+ //Allow failover
+ return true;
+ }
+
+ public void failoverComplete()
+ {
+ _failoverCompleted.countDown();
+ }
+
+ /**
+ * Override so we can block until failover has completd
+ *
+ * @param port int the port of the broker to fail.
+ */
+ @Override
+ public void failBroker(int port)
+ {
+ super.failBroker(port);
+
+ try
+ {
+ if (!_failoverCompleted.await(DEFAULT_FAILOVER_TIME, TimeUnit.MILLISECONDS))
+ {
+ fail("Failover did not occur in specified time:" + DEFAULT_FAILOVER_TIME);
+ }
+ }
+ catch (InterruptedException e)
+ {
+ fail("Failover was interuppted");
+ }
+ }
+
+ /**
+ * Pass the given exception back to the waiting thread to fail the test run.
+ *
+ * @param e The exception that is causing the test to fail.
+ */
+ protected void fail(Exception e)
+ {
+ _causeOfFailure.set(e);
+ // End the test.
+ while (_receviedAll.getCount() != 0)
+ {
+ _receviedAll.countDown();
+ }
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java
index c6a953dbc2..2a44413ac8 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java
@@ -37,6 +37,7 @@ import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
+import javax.jms.Topic;
import javax.jms.TopicSubscriber;
/**
@@ -50,17 +51,13 @@ import javax.jms.TopicSubscriber;
public class DurableSubscriptionTest extends QpidTestCase
{
private static final Logger _logger = LoggerFactory.getLogger(DurableSubscriptionTest.class);
-
- protected void setUp() throws Exception
- {
- super.setUp();
- }
-
- protected void tearDown() throws Exception
- {
- super.tearDown();
- }
-
+
+ /** Timeout for receive() if we are expecting a message */
+ private static final long POSITIVE_RECEIVE_TIMEOUT = 2000;
+
+ /** Timeout for receive() if we are not expecting a message */
+ private static final long NEGATIVE_RECEIVE_TIMEOUT = 1000;
+
public void testUnsubscribe() throws Exception
{
AMQConnection con = (AMQConnection) getConnection("guest", "guest");
@@ -85,16 +82,18 @@ public class DurableSubscriptionTest extends QpidTestCase
Message msg;
_logger.info("Receive message on consumer 1:expecting A");
- msg = consumer1.receive();
+ msg = consumer1.receive(POSITIVE_RECEIVE_TIMEOUT);
+ assertNotNull("Message should have been received",msg);
assertEquals("A", ((TextMessage) msg).getText());
_logger.info("Receive message on consumer 1 :expecting null");
- msg = consumer1.receive(1000);
+ msg = consumer1.receive(NEGATIVE_RECEIVE_TIMEOUT);
assertEquals(null, msg);
- _logger.info("Receive message on consumer 1:expecting A");
- msg = consumer2.receive();
+ _logger.info("Receive message on consumer 2:expecting A");
+ msg = consumer2.receive(POSITIVE_RECEIVE_TIMEOUT);
+ assertNotNull("Message should have been received",msg);
assertEquals("A", ((TextMessage) msg).getText());
- msg = consumer2.receive(1000);
+ msg = consumer2.receive(NEGATIVE_RECEIVE_TIMEOUT);
_logger.info("Receive message on consumer 1 :expecting null");
assertEquals(null, msg);
@@ -105,14 +104,15 @@ public class DurableSubscriptionTest extends QpidTestCase
producer.send(session1.createTextMessage("B"));
_logger.info("Receive message on consumer 1 :expecting B");
- msg = consumer1.receive();
+ msg = consumer1.receive(POSITIVE_RECEIVE_TIMEOUT);
+ assertNotNull("Message should have been received",msg);
assertEquals("B", ((TextMessage) msg).getText());
_logger.info("Receive message on consumer 1 :expecting null");
- msg = consumer1.receive(1000);
+ msg = consumer1.receive(NEGATIVE_RECEIVE_TIMEOUT);
assertEquals(null, msg);
_logger.info("Receive message on consumer 2 :expecting null");
- msg = consumer2.receive(1000);
+ msg = consumer2.receive(NEGATIVE_RECEIVE_TIMEOUT);
assertEquals(null, msg);
_logger.info("Close connection");
@@ -152,14 +152,16 @@ public class DurableSubscriptionTest extends QpidTestCase
producer.send(session1.createTextMessage("A"));
Message msg;
- msg = consumer1.receive();
+ msg = consumer1.receive(POSITIVE_RECEIVE_TIMEOUT);
+ assertNotNull("Message should have been received",msg);
assertEquals("A", ((TextMessage) msg).getText());
- msg = consumer1.receive(1000);
+ msg = consumer1.receive(NEGATIVE_RECEIVE_TIMEOUT);
assertEquals(null, msg);
- msg = consumer2.receive();
+ msg = consumer2.receive(POSITIVE_RECEIVE_TIMEOUT);
+ assertNotNull("Message should have been received",msg);
assertEquals("A", ((TextMessage) msg).getText());
- msg = consumer2.receive(1000);
+ msg = consumer2.receive(NEGATIVE_RECEIVE_TIMEOUT);
assertEquals(null, msg);
consumer2.close();
@@ -229,8 +231,8 @@ public class DurableSubscriptionTest extends QpidTestCase
msg = consumer1.receive(500);
assertNull("There should be no more messages for consumption on consumer1.", msg);
- msg = consumer2.receive();
- assertNotNull(msg);
+ msg = consumer2.receive(POSITIVE_RECEIVE_TIMEOUT);
+ assertNotNull("Message should have been received",msg);
assertEquals("Consumer 2 should also received the first msg.", "A", ((TextMessage) msg).getText());
msg = consumer2.receive(500);
assertNull("There should be no more messages for consumption on consumer2.", msg);
@@ -244,10 +246,10 @@ public class DurableSubscriptionTest extends QpidTestCase
producer.send(session0.createTextMessage("B"));
_logger.info("Receive message on consumer 1 :expecting B");
- msg = consumer1.receive(1000);
+ msg = consumer1.receive(NEGATIVE_RECEIVE_TIMEOUT);
assertEquals("B", ((TextMessage) msg).getText());
_logger.info("Receive message on consumer 1 :expecting null");
- msg = consumer1.receive(1000);
+ msg = consumer1.receive(NEGATIVE_RECEIVE_TIMEOUT);
assertEquals(null, msg);
// Re-attach a new consumer to the durable subscription, and check that it gets the message that it missed.
@@ -305,7 +307,7 @@ public class DurableSubscriptionTest extends QpidTestCase
producer.send(session.createTextMessage("testDurableWithInvalidSelector2"));
- Message msg = liveSubscriber.receive();
+ Message msg = liveSubscriber.receive(POSITIVE_RECEIVE_TIMEOUT);
assertNotNull ("Message should have been received", msg);
assertEquals ("testDurableWithInvalidSelector2", ((TextMessage) msg).getText());
assertNull("Should not receive subsequent message", liveSubscriber.receive(200));
@@ -340,7 +342,7 @@ public class DurableSubscriptionTest extends QpidTestCase
assertNotNull("Subscriber should have been created", liveSubscriber);
producer.send(session.createTextMessage("testDurableWithInvalidSelector2"));
- Message msg = liveSubscriber.receive();
+ Message msg = liveSubscriber.receive(POSITIVE_RECEIVE_TIMEOUT);
assertNotNull ("Message should have been received", msg);
assertEquals ("testDurableWithInvalidSelector2", ((TextMessage) msg).getText());
assertNull("Should not receive subsequent message", liveSubscriber.receive(200));
@@ -369,13 +371,13 @@ public class DurableSubscriptionTest extends QpidTestCase
// Send 1 matching message and 1 non-matching message
sendMatchingAndNonMatchingMessage(session, producer);
- Message rMsg = subA.receive(1000);
+ Message rMsg = subA.receive(NEGATIVE_RECEIVE_TIMEOUT);
assertNotNull(rMsg);
assertEquals("Content was wrong",
"testResubscribeWithChangedSelector1",
((TextMessage) rMsg).getText());
- rMsg = subA.receive(1000);
+ rMsg = subA.receive(NEGATIVE_RECEIVE_TIMEOUT);
assertNull(rMsg);
// Disconnect subscriber
@@ -388,17 +390,43 @@ public class DurableSubscriptionTest extends QpidTestCase
// Check messages are recieved properly
sendMatchingAndNonMatchingMessage(session, producer);
- rMsg = subB.receive(1000);
+ rMsg = subB.receive(NEGATIVE_RECEIVE_TIMEOUT);
assertNotNull(rMsg);
assertEquals("Content was wrong",
"testResubscribeWithChangedSelector2",
((TextMessage) rMsg).getText());
- rMsg = subB.receive(1000);
+ rMsg = subB.receive(NEGATIVE_RECEIVE_TIMEOUT);
assertNull(rMsg);
session.unsubscribe("testResubscribeWithChangedSelector");
}
+ public void testDurableSubscribeWithTemporaryTopic() throws Exception
+ {
+ Connection conn = getConnection();
+ conn.start();
+ Session ssn = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Topic topic = ssn.createTemporaryTopic();
+ try
+ {
+ ssn.createDurableSubscriber(topic, "test");
+ fail("expected InvalidDestinationException");
+ }
+ catch (InvalidDestinationException ex)
+ {
+ // this is expected
+ }
+ try
+ {
+ ssn.createDurableSubscriber(topic, "test", null, false);
+ fail("expected InvalidDestinationException");
+ }
+ catch (InvalidDestinationException ex)
+ {
+ // this is expected
+ }
+ }
+
private void sendMatchingAndNonMatchingMessage(Session session, MessageProducer producer) throws JMSException
{
TextMessage msg = session.createTextMessage("testResubscribeWithChangedSelector1");
@@ -412,5 +440,5 @@ public class DurableSubscriptionTest extends QpidTestCase
public static junit.framework.Test suite()
{
return new junit.framework.TestSuite(DurableSubscriptionTest.class);
- }
+ }
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java
index 9f4c9e53aa..742e2ac518 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java
@@ -57,7 +57,7 @@ public class TopicSessionTest extends QpidTestCase
AMQConnection con = (AMQConnection) getConnection("guest", "guest");
AMQTopic topic = new AMQTopic(con.getDefaultTopicExchangeName(), "MyTopic");
- TopicSession session1 = con.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE);
+ TopicSession session1 = con.createTopicSession(true, AMQSession.NO_ACKNOWLEDGE);
TopicSubscriber sub = session1.createDurableSubscriber(topic, "subscription0");
TopicPublisher publisher = session1.createPublisher(topic);
@@ -65,10 +65,11 @@ public class TopicSessionTest extends QpidTestCase
TextMessage tm = session1.createTextMessage("Hello");
publisher.publish(tm);
+ session1.commit();
tm = (TextMessage) sub.receive(2000);
assertNotNull(tm);
-
+ session1.commit();
session1.unsubscribe("subscription0");
try
@@ -104,15 +105,17 @@ public class TopicSessionTest extends QpidTestCase
AMQTopic topic = new AMQTopic(con, "MyTopic1" + String.valueOf(shutdown));
AMQTopic topic2 = new AMQTopic(con, "MyOtherTopic1" + String.valueOf(shutdown));
- TopicSession session1 = con.createTopicSession(false, AMQSession.AUTO_ACKNOWLEDGE);
+ TopicSession session1 = con.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE);
TopicSubscriber sub = session1.createDurableSubscriber(topic, "subscription0");
TopicPublisher publisher = session1.createPublisher(null);
con.start();
publisher.publish(topic, session1.createTextMessage("hello"));
+ session1.commit();
TextMessage m = (TextMessage) sub.receive(2000);
assertNotNull(m);
+ session1.commit();
if (shutdown)
{
@@ -120,17 +123,20 @@ public class TopicSessionTest extends QpidTestCase
con.close();
con = (AMQConnection) getConnection("guest", "guest");
con.start();
- session1 = con.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE);
+ session1 = con.createTopicSession(true, AMQSession.NO_ACKNOWLEDGE);
publisher = session1.createPublisher(null);
}
TopicSubscriber sub2 = session1.createDurableSubscriber(topic2, "subscription0");
publisher.publish(topic, session1.createTextMessage("hello"));
+ session1.commit();
if (!shutdown)
{
m = (TextMessage) sub.receive(2000);
assertNull(m);
+ session1.commit();
}
publisher.publish(topic2, session1.createTextMessage("goodbye"));
+ session1.commit();
m = (TextMessage) sub2.receive(2000);
assertNotNull(m);
assertEquals("goodbye", m.getText());
@@ -143,25 +149,29 @@ public class TopicSessionTest extends QpidTestCase
AMQConnection con1 = (AMQConnection) getConnection("guest", "guest", "clientid");
AMQTopic topic = new AMQTopic(con1, "MyTopic3");
- TopicSession session1 = con1.createTopicSession(false, AMQSession.AUTO_ACKNOWLEDGE);
+ TopicSession session1 = con1.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE);
TopicPublisher publisher = session1.createPublisher(topic);
AMQConnection con2 = (AMQConnection) getConnection("guest", "guest", "clientid");
- TopicSession session2 = con2.createTopicSession(false, AMQSession.AUTO_ACKNOWLEDGE);
+ TopicSession session2 = con2.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE);
TopicSubscriber sub = session2.createDurableSubscriber(topic, "subscription0");
con2.start();
publisher.publish(session1.createTextMessage("Hello"));
+ session1.commit();
TextMessage tm = (TextMessage) sub.receive(2000);
+ session2.commit();
assertNotNull(tm);
con2.close();
publisher.publish(session1.createTextMessage("Hello2"));
+ session1.commit();
con2 = (AMQConnection) getConnection("guest", "guest", "clientid");
- session2 = con2.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE);
+ session2 = con2.createTopicSession(true, AMQSession.NO_ACKNOWLEDGE);
sub = session2.createDurableSubscriber(topic, "subscription0");
con2.start();
tm = (TextMessage) sub.receive(2000);
+ session2.commit();
assertNotNull(tm);
assertEquals("Hello2", tm.getText());
session2.unsubscribe("subscription0");
@@ -174,12 +184,13 @@ public class TopicSessionTest extends QpidTestCase
AMQConnection con = (AMQConnection) getConnection("guest", "guest");
AMQTopic topic = new AMQTopic(con, "MyTopic4");
- TopicSession session1 = con.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE);
+ TopicSession session1 = con.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE);
TopicPublisher publisher = session1.createPublisher(topic);
MessageConsumer consumer1 = session1.createConsumer(topic);
con.start();
TextMessage tm = session1.createTextMessage("Hello");
publisher.publish(tm);
+ session1.commit();
tm = (TextMessage) consumer1.receive(10000L);
assertNotNull(tm);
String msgText = tm.getText();
@@ -188,15 +199,19 @@ public class TopicSessionTest extends QpidTestCase
msgText = tm.getText();
assertNull(msgText);
publisher.publish(tm);
+ session1.commit();
tm = (TextMessage) consumer1.receive(10000L);
assertNotNull(tm);
+ session1.commit();
msgText = tm.getText();
assertNull(msgText);
tm.clearBody();
tm.setText("Now we are not null");
publisher.publish(tm);
+ session1.commit();
tm = (TextMessage) consumer1.receive(2000);
assertNotNull(tm);
+ session1.commit();
msgText = tm.getText();
assertEquals("Now we are not null", msgText);
@@ -204,7 +219,9 @@ public class TopicSessionTest extends QpidTestCase
msgText = tm.getText();
assertEquals("Empty string not returned", "", msgText);
publisher.publish(tm);
+ session1.commit();
tm = (TextMessage) consumer1.receive(2000);
+ session1.commit();
assertNotNull(tm);
assertEquals("Empty string not returned", "", msgText);
con.close();
@@ -213,7 +230,7 @@ public class TopicSessionTest extends QpidTestCase
public void testSendingSameMessage() throws Exception
{
AMQConnection conn = (AMQConnection) getConnection("guest", "guest");
- TopicSession session = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
+ TopicSession session = conn.createTopicSession(true, Session.AUTO_ACKNOWLEDGE);
TemporaryTopic topic = session.createTemporaryTopic();
assertNotNull(topic);
TopicPublisher producer = session.createPublisher(topic);
@@ -221,14 +238,16 @@ public class TopicSessionTest extends QpidTestCase
conn.start();
TextMessage sentMessage = session.createTextMessage("Test Message");
producer.send(sentMessage);
+ session.commit();
TextMessage receivedMessage = (TextMessage) consumer.receive(2000);
assertNotNull(receivedMessage);
assertEquals(sentMessage.getText(), receivedMessage.getText());
producer.send(sentMessage);
+ session.commit();
receivedMessage = (TextMessage) consumer.receive(2000);
assertNotNull(receivedMessage);
assertEquals(sentMessage.getText(), receivedMessage.getText());
-
+ session.commit();
conn.close();
}
@@ -236,17 +255,18 @@ public class TopicSessionTest extends QpidTestCase
public void testTemporaryTopic() throws Exception
{
AMQConnection conn = (AMQConnection) getConnection("guest", "guest");
- TopicSession session = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
+ TopicSession session = conn.createTopicSession(true, Session.AUTO_ACKNOWLEDGE);
TemporaryTopic topic = session.createTemporaryTopic();
assertNotNull(topic);
TopicPublisher producer = session.createPublisher(topic);
MessageConsumer consumer = session.createConsumer(topic);
conn.start();
producer.send(session.createTextMessage("hello"));
+ session.commit();
TextMessage tm = (TextMessage) consumer.receive(2000);
assertNotNull(tm);
assertEquals("hello", tm.getText());
-
+ session.commit();
try
{
topic.delete();
@@ -291,11 +311,13 @@ public class TopicSessionTest extends QpidTestCase
AMQTopic topic = new AMQTopic(con, "testNoLocal");
- TopicSession session1 = con.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE);
+ TopicSession session1 = con.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE);
TopicSubscriber noLocal = session1.createSubscriber(topic, "", true);
+
TopicSubscriber select = session1.createSubscriber(topic, "Selector = 'select'", false);
TopicSubscriber normal = session1.createSubscriber(topic);
+
TopicPublisher publisher = session1.createPublisher(topic);
con.start();
@@ -304,14 +326,16 @@ public class TopicSessionTest extends QpidTestCase
//send message to all consumers
publisher.publish(session1.createTextMessage("hello-new2"));
-
+ session1.commit();
//test normal subscriber gets message
m = (TextMessage) normal.receive(1000);
assertNotNull(m);
+ session1.commit();
//test selector subscriber doesn't message
m = (TextMessage) select.receive(1000);
assertNull(m);
+ session1.commit();
//test nolocal subscriber doesn't message
m = (TextMessage) noLocal.receive(1000);
@@ -326,21 +350,24 @@ public class TopicSessionTest extends QpidTestCase
message.setStringProperty("Selector", "select");
publisher.publish(message);
+ session1.commit();
//test normal subscriber gets message
m = (TextMessage) normal.receive(1000);
assertNotNull(m);
+ session1.commit();
//test selector subscriber does get message
m = (TextMessage) select.receive(1000);
assertNotNull(m);
+ session1.commit();
//test nolocal subscriber doesn't message
m = (TextMessage) noLocal.receive(100);
assertNull(m);
AMQConnection con2 = (AMQConnection) getConnection("guest", "guest", "foo");
- TopicSession session2 = con2.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE);
+ TopicSession session2 = con2.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE);
TopicPublisher publisher2 = session2.createPublisher(topic);
@@ -348,28 +375,31 @@ public class TopicSessionTest extends QpidTestCase
message.setStringProperty("Selector", "select");
publisher2.publish(message);
+ session2.commit();
//test normal subscriber gets message
m = (TextMessage) normal.receive(1000);
assertNotNull(m);
+ session1.commit();
//test selector subscriber does get message
m = (TextMessage) select.receive(1000);
assertNotNull(m);
+ session1.commit();
//test nolocal subscriber does message
- m = (TextMessage) noLocal.receive(100);
+ m = (TextMessage) noLocal.receive(1000);
assertNotNull(m);
con.close();
con2.close();
}
-
+
/**
* This tests QPID-1191, where messages which are sent to a topic but are not consumed by a subscriber
* due to a selector can be leaked.
- * @throws Exception
+ * @throws Exception
*/
public void testNonMatchingMessagesDoNotFillQueue() throws Exception
{
@@ -378,7 +408,7 @@ public class TopicSessionTest extends QpidTestCase
// Setup Topic
AMQTopic topic = new AMQTopic(con, "testNoLocal");
- TopicSession session = con.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE);
+ TopicSession session = con.createTopicSession(true, AMQSession.NO_ACKNOWLEDGE);
// Setup subscriber with selector
TopicSubscriber selector = session.createSubscriber(topic, "Selector = 'select'", false);
@@ -391,25 +421,28 @@ public class TopicSessionTest extends QpidTestCase
// Send non-matching message
message = session.createTextMessage("non-matching 1");
publisher.publish(message);
-
+ session.commit();
+
// Send and consume matching message
message = session.createTextMessage("hello");
message.setStringProperty("Selector", "select");
publisher.publish(message);
+ session.commit();
m = (TextMessage) selector.receive(1000);
assertNotNull("should have received message", m);
assertEquals("Message contents were wrong", "hello", m.getText());
-
+
// Send non-matching message
message = session.createTextMessage("non-matching 2");
publisher.publish(message);
+ session.commit();
// Assert queue count is 0
long depth = ((AMQTopicSessionAdaptor) session).getSession().getQueueDepth(topic);
assertEquals("Queue depth was wrong", 0, depth);
-
+
}
public static junit.framework.Test suite()
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java
index 9c755fcb41..b603455644 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java
@@ -479,7 +479,7 @@ public class CommitRollbackTest extends QpidTestCase
_publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT));
_pubSession.commit();
- assertNotNull(_consumer.receive(100));
+ assertNotNull(_consumer.receive(1000));
_publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT));
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/xa/FaultTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/xa/FaultTest.java
index 0adf39980b..1e5932b6db 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/xa/FaultTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/xa/FaultTest.java
@@ -1,4 +1,25 @@
package org.apache.qpid.test.unit.xa;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/java/systests/src/main/java/org/apache/qpid/test/utils/FailoverBaseCase.java b/java/systests/src/main/java/org/apache/qpid/test/utils/FailoverBaseCase.java
index 2fa6f4f417..b1d14721bd 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/utils/FailoverBaseCase.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/utils/FailoverBaseCase.java
@@ -20,70 +20,99 @@
*/
package org.apache.qpid.test.utils;
-import org.apache.qpid.client.transport.TransportConnection;
-import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.util.FileUtils;
-import javax.jms.Connection;
+import javax.naming.NamingException;
+import javax.jms.JMSException;
+import javax.naming.NamingException;
+
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class FailoverBaseCase extends QpidTestCase
{
- private boolean failedOver = true;
-
+ protected static final Logger _logger = LoggerFactory.getLogger(FailoverBaseCase.class);
- protected void setUp() throws java.lang.Exception
- {
- super.setUp();
+ public static int FAILING_VM_PORT = 2;
+ public static int FAILING_PORT = Integer.parseInt(System.getProperty("test.port.alt"));
+ public static final long DEFAULT_FAILOVER_TIME = 10000L;
- try
+ protected int failingPort;
+
+ protected int getFailingPort()
+ {
+ if (_broker.equals(VM))
{
- TransportConnection.createVMBroker(2);
+ return FAILING_VM_PORT;
}
- catch (Exception e)
+ else
{
- fail("Unable to create broker: " + e);
+ return FAILING_PORT;
}
+ }
+ protected void setUp() throws java.lang.Exception
+ {
+ super.setUp();
+ // Set QPID_WORK to $QPID_WORK/<getFailingPort()>
+ // or /tmp/<getFailingPort()> if QPID_WORK not set.
+ setSystemProperty("QPID_WORK", System.getProperty("QPID_WORK") + "/" + getFailingPort());
+ startBroker(getFailingPort());
}
/**
- * We are using failover factories, Note that 0.10 code path does not yet support failover.
+ * We are using failover factories
*
* @return a connection
* @throws Exception
*/
- public Connection getConnection() throws Exception
+ @Override
+ public AMQConnectionFactory getConnectionFactory() throws NamingException
{
- Connection conn;
- if( _broker.equals(VM) )
+ _logger.info("get ConnectionFactory");
+ if (_connectionFactory == null)
{
- conn = getConnectionFactory("vmfailover").createConnection("guest", "guest");
+ if (Boolean.getBoolean("profile.use_ssl"))
+ {
+ _connectionFactory = getConnectionFactory("failover.ssl");
+ }
+ else
+ {
+ _connectionFactory = getConnectionFactory("failover");
+ }
}
- else
- {
- conn = getConnectionFactory("failover").createConnection("guest", "guest");
- }
- _connections.add(conn);
- return conn;
+ return _connectionFactory;
}
+
public void tearDown() throws Exception
{
- if (!failedOver)
+ try
{
- TransportConnection.killVMBroker(2);
- ApplicationRegistry.remove(2);
+ super.tearDown();
+ }
+ finally
+ {
+ // Ensure we shutdown any secondary brokers, even if we are unable
+ // to cleanly tearDown the QTC.
+ stopBroker(getFailingPort());
+ FileUtils.deleteDirectory(System.getProperty("QPID_WORK") + "/" + getFailingPort());
}
- super.tearDown();
}
- /**
- * Only used of VM borker.
- */
- public void failBroker()
+ public void failBroker(int port)
{
- failedOver = true;
- TransportConnection.killVMBroker(2);
- ApplicationRegistry.remove(2);
+ try
+ {
+ stopBroker(port);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
}
+
+
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java b/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java
new file mode 100644
index 0000000000..ca59a0536b
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java
@@ -0,0 +1,212 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.utils;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.commands.objects.AllObjects;
+import org.apache.qpid.management.common.JMXConnnectionFactory;
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedExchange;
+
+import javax.management.JMException;
+import javax.management.MBeanException;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnector;
+import java.io.IOException;
+import java.util.Set;
+
+/**
+ *
+ */
+public class JMXTestUtils
+{
+ QpidTestCase _test;
+ MBeanServerConnection _mbsc;
+ JMXConnector _jmxc;
+
+ private String USER;
+ private String PASSWORD;
+
+ public JMXTestUtils(QpidTestCase test, String user, String password)
+ {
+ _test = test;
+ USER = user;
+ PASSWORD = password;
+ }
+
+ public void setUp() throws IOException, ConfigurationException, Exception
+ {
+ _test.setConfigurationProperty("management.enabled", "true");
+ }
+
+ public void open() throws Exception
+ {
+ _jmxc = JMXConnnectionFactory.getJMXConnection(
+ 5000, "127.0.0.1",
+ _test.getManagementPort(_test.getPort()), USER, PASSWORD);
+
+ _mbsc = _jmxc.getMBeanServerConnection();
+ }
+
+ public void close() throws IOException
+ {
+ _jmxc.close();
+ }
+
+ /**
+ * Create a non-durable test exchange with the current test name
+ *
+ * @throws javax.management.JMException - is thrown if a exchange with this testName already exists
+ * @throws java.io.IOException - if there is a problem with the JMX Connection
+ * @throws javax.management.MBeanException
+ * - if there is another problem creating the exchange
+ */
+ public void createExchange(String virtualHostName, String name, String type, boolean durable)
+ throws JMException, IOException, MBeanException
+ {
+ ManagedBroker managedBroker = getManagedBroker(virtualHostName);
+
+ managedBroker.createNewExchange(name, type, durable);
+ }
+
+ /**
+ * Create a non-durable queue (with no owner) that is named after the
+ * creating test.
+ *
+ * @throws JMException - is thrown if a queue with this testName already exists
+ * @throws IOException - if there is a problem with the JMX Connection
+ */
+ public void createQueue(String virtualHostName, String name, String owner, boolean durable)
+ throws JMException, IOException
+ {
+ ManagedBroker managedBroker = getManagedBroker(virtualHostName);
+
+ managedBroker.createNewQueue(name, owner, durable);
+ }
+
+ /**
+ * Retrive the ObjectName for the test Virtualhost.
+ *
+ * This is then use to create aproxy to the ManagedBroker MBean.
+ *
+ * @return the ObjectName for the 'test' VirtualHost.
+ */
+ public ObjectName getVirtualHostManagerObjectName(String vhostName)
+ {
+ // Get the name of the test manager
+ AllObjects allObject = new AllObjects(_mbsc);
+ allObject.querystring = "org.apache.qpid:type=VirtualHost.VirtualHostManager,VirtualHost=" + vhostName + ",*";
+
+ Set<ObjectName> objectNames = allObject.returnObjects();
+
+ _test.assertNotNull("Null ObjectName Set returned", objectNames);
+ _test.assertEquals("Incorrect number test vhosts returned", 1, objectNames.size());
+
+ // We have verified we have only one value in objectNames so return it
+ return objectNames.iterator().next();
+ }
+
+ /**
+ * Retrive the ObjectName for the given Exchange on the test Virtualhost.
+ *
+ * This is then use to create aproxy to the ManagedExchange MBean.
+ *
+ * @param queue The exchange to retireve e.g. 'direct'
+ *
+ * @return the ObjectName for the given exchange on the test VirtualHost.
+ */
+ public ObjectName getQueueObjectName(String virtualHostName, String queue)
+ {
+ // Get the name of the test manager
+ AllObjects allObject = new AllObjects(_mbsc);
+ allObject.querystring = "org.apache.qpid:type=VirtualHost.Queue,VirtualHost=" + virtualHostName + ",name=" + queue + ",*";
+
+ Set<ObjectName> objectNames = allObject.returnObjects();
+
+ _test.assertNotNull("Null ObjectName Set returned", objectNames);
+ _test.assertEquals("Incorrect number of queues with name '" + allObject.querystring +
+ "' returned", 1, objectNames.size());
+
+ // We have verified we have only one value in objectNames so return it
+ return objectNames.iterator().next();
+ }
+
+ /**
+ * Retrive the ObjectName for the given Exchange on the test Virtualhost.
+ *
+ * This is then use to create aproxy to the ManagedExchange MBean.
+ *
+ * @param virtualHostName
+ * @param exchange The exchange to retireve e.g. 'direct'
+ *
+ * @return the ObjectName for the given exchange on the test VirtualHost.
+ */
+ public ObjectName getExchangeObjectName(String virtualHostName, String exchange)
+ {
+ // Get the name of the test manager
+ AllObjects allObject = new AllObjects(_mbsc);
+ allObject.querystring = "org.apache.qpid:type=VirtualHost.Exchange,VirtualHost=" + virtualHostName + ",name=" + exchange + ",*";
+
+ Set<ObjectName> objectNames = allObject.returnObjects();
+
+ _test.assertNotNull("Null ObjectName Set returned", objectNames);
+ _test.assertEquals("Incorrect number of exchange with name '" + exchange +
+ "' returned", 1, objectNames.size());
+
+ // We have verified we have only one value in objectNames so return it
+ return objectNames.iterator().next();
+ }
+
+ public <T> T getManagedObject(Class<T> managedClass, String queryString)
+ {
+ AllObjects allObject = new AllObjects(_mbsc);
+ allObject.querystring = queryString;
+
+ Set<ObjectName> objectNames = allObject.returnObjects();
+
+ _test.assertNotNull("Null ObjectName Set returned", objectNames);
+ _test.assertEquals("More than one " + managedClass + " returned", 1, objectNames.size());
+
+ ObjectName objectName = objectNames.iterator().next();
+
+ return getManagedObject(managedClass, objectName);
+ }
+
+ public <T> T getManagedObject(Class<T> managedClass, ObjectName objectName)
+ {
+ return MBeanServerInvocationHandler.
+ newProxyInstance(_mbsc, objectName, managedClass, false);
+ }
+
+ public ManagedBroker getManagedBroker(String virtualHost)
+ {
+ return getManagedObject(ManagedBroker.class, getVirtualHostManagerObjectName(virtualHost).toString());
+ }
+
+ public ManagedExchange getManagedExchange(String exchangeName)
+ {
+ return MBeanServerInvocationHandler.
+ newProxyInstance(_mbsc, getExchangeObjectName("test", exchangeName),
+ ManagedExchange.class, false);
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java b/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java
index 65939e1fb7..5e209e69d6 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java
@@ -19,37 +19,76 @@ package org.apache.qpid.test.utils;
import junit.framework.TestCase;
import junit.framework.TestResult;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.jms.ConnectionURL;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry;
+import org.apache.qpid.server.store.DerbyMessageStore;
+import org.apache.qpid.url.URLSyntaxException;
+import org.apache.qpid.util.LogMonitor;
+import org.apache.log4j.Level;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
import javax.naming.InitialContext;
import javax.naming.NamingException;
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.io.PrintStream;
+import java.io.Reader;
+import java.net.MalformedURLException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
-import java.util.StringTokenizer;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import org.apache.qpid.client.transport.TransportConnection;
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQConnectionFactory;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
/**
*
*
*/
public class QpidTestCase extends TestCase
{
+ protected final String QpidHome = System.getProperty("QPID_HOME");
+ protected File _configFile = new File(System.getProperty("broker.config"));
- private static final Logger _logger = LoggerFactory.getLogger(QpidTestCase.class);
-
+ protected static final Logger _logger = LoggerFactory.getLogger(QpidTestCase.class);
+ protected static final int LOGMONITOR_TIMEOUT = 5000;
+
protected long RECEIVE_TIMEOUT = 1000l;
+ private Map<String, String> _propertiesSetForTestOnly = new HashMap<String, String>();
+ private Map<String, String> _propertiesSetForBroker = new HashMap<String, String>();
+ private Map<org.apache.log4j.Logger, Level> _loggerLevelSetForTest = new HashMap<org.apache.log4j.Logger, Level>();
+
+ private XMLConfiguration _testConfiguration = new XMLConfiguration();
+
+ protected static final String INDEX = "index";
+
/**
* Some tests are excluded when the property test.excludes is set to true.
* An exclusion list is either a file (prop test.excludesfile) which contains one test name
@@ -63,46 +102,46 @@ public class QpidTestCase extends TestCase
static
{
- if (Boolean.getBoolean("test.excludes"))
+ if (Boolean.getBoolean("test.exclude"))
{
_logger.info("Some tests should be excluded, building the exclude list");
- String exclusionListURI = System.getProperties().getProperty("test.excludesfile", "");
- String exclusionListString = System.getProperties().getProperty("test.excludeslist", "");
- File file = new File(exclusionListURI);
+ String exclusionListURIs = System.getProperties().getProperty("test.excludefiles", "");
+ String exclusionListString = System.getProperties().getProperty("test.excludelist", "");
List<String> exclusionList = new ArrayList<String>();
- if (file.exists())
+
+ for (String uri : exclusionListURIs.split("\\s+"))
{
- _logger.info("Using exclude file: " + exclusionListURI);
- try
+ File file = new File(uri);
+ if (file.exists())
{
- BufferedReader in = new BufferedReader(new FileReader(file));
- String excludedTest = in.readLine();
- do
+ _logger.info("Using exclude file: " + uri);
+ try
{
- exclusionList.add(excludedTest);
- excludedTest = in.readLine();
+ BufferedReader in = new BufferedReader(new FileReader(file));
+ String excludedTest = in.readLine();
+ do
+ {
+ exclusionList.add(excludedTest);
+ excludedTest = in.readLine();
+ }
+ while (excludedTest != null);
+ }
+ catch (IOException e)
+ {
+ _logger.warn("Exception when reading exclusion list", e);
}
- while (excludedTest != null);
- }
- catch (IOException e)
- {
- _logger.warn("Exception when reading exclusion list", e);
}
}
- else if (!exclusionListString.equals(""))
+
+ if (!exclusionListString.equals(""))
{
_logger.info("Using excludeslist: " + exclusionListString);
- // the exclusion list may be specified as a string
- StringTokenizer t = new StringTokenizer(exclusionListString, " ");
- while (t.hasMoreTokens())
+ for (String test : exclusionListString.split("\\s+"))
{
- exclusionList.add(t.nextToken());
+ exclusionList.add(test);
}
}
- else
- {
- throw new RuntimeException("Aborting test: Cannot find excludes file nor excludes list");
- }
+
_exclusionList = exclusionList;
}
@@ -117,33 +156,58 @@ public class QpidTestCase extends TestCase
private static List<String> _exclusionList;
// system properties
+ private static final String BROKER_LANGUAGE = "broker.language";
private static final String BROKER = "broker";
private static final String BROKER_CLEAN = "broker.clean";
+ private static final String BROKER_CLEAN_BETWEEN_TESTS = "broker.clean.between.tests";
private static final String BROKER_VERSION = "broker.version";
- private static final String BROKER_READY = "broker.ready";
+ protected static final String BROKER_READY = "broker.ready";
+ private static final String BROKER_STOPPED = "broker.stopped";
private static final String TEST_OUTPUT = "test.output";
-
+ private static final String BROKER_LOG_INTERLEAVE = "broker.log.interleave";
+ private static final String BROKER_LOG_PREFIX = "broker.log.prefix";
+
// values
+ protected static final String JAVA = "java";
+ protected static final String CPP = "cpp";
protected static final String VM = "vm";
- private static final String EXTERNAL = "external";
+ protected static final String EXTERNAL = "external";
private static final String VERSION_08 = "0-8";
private static final String VERSION_010 = "0-10";
- private static final String QPID_HOME = "QPID_HOME";
+ protected static final String QPID_HOME = "QPID_HOME";
+
+ protected static int DEFAULT_VM_PORT = 1;
+ protected static int DEFAULT_PORT = Integer.getInteger("test.port", 5672);
+ protected static int DEFAULT_MANAGEMENT_PORT = Integer.getInteger("test.mport", 8999);
+ protected String _brokerLanguage = System.getProperty(BROKER_LANGUAGE, JAVA);
protected String _broker = System.getProperty(BROKER, VM);
private String _brokerClean = System.getProperty(BROKER_CLEAN, null);
+ private Boolean _brokerCleanBetweenTests = Boolean.getBoolean(BROKER_CLEAN_BETWEEN_TESTS);
private String _brokerVersion = System.getProperty(BROKER_VERSION, VERSION_08);
private String _output = System.getProperty(TEST_OUTPUT);
-
- private Process _brokerProcess;
+
+ private static String _brokerLogPrefix = System.getProperty(BROKER_LOG_PREFIX,"BROKER: ");
+ protected static boolean _interleaveBrokerLog = Boolean.getBoolean(BROKER_LOG_INTERLEAVE);
+
+ protected File _outputFile;
+
+ protected PrintStream _brokerOutputStream;
+
+ private Map<Integer, Process> _brokers = new HashMap<Integer, Process>();
private InitialContext _initialContext;
- private AMQConnectionFactory _connectionFactory;
- private boolean _brokerStarted;
+ protected AMQConnectionFactory _connectionFactory;
+
+ private String _testName;
// the connections created for a given test
protected List<Connection> _connections = new ArrayList<Connection>();
+ public static final String QUEUE = "queue";
+ public static final String TOPIC = "topic";
+ /** Map to hold test defined environment properties */
+ private Map<String, String> _env;
public QpidTestCase(String name)
{
@@ -156,25 +220,39 @@ public class QpidTestCase extends TestCase
}
public void runBare() throws Throwable
- {
- String name = getClass().getSimpleName() + "." + getName();
+ {
+ _testName = getClass().getSimpleName() + "." + getName();
String qname = getClass().getName() + "." + getName();
+ // Initialize this for each test run
+ _env = new HashMap<String, String>();
+
PrintStream oldOut = System.out;
PrintStream oldErr = System.err;
PrintStream out = null;
PrintStream err = null;
+
boolean redirected = _output != null && _output.length() > 0;
if (redirected)
{
- out = new PrintStream(String.format("%s/TEST-%s.out", _output, qname));
+ _outputFile = new File(String.format("%s/TEST-%s.out", _output, qname));
+ out = new PrintStream(_outputFile);
err = new PrintStream(String.format("%s/TEST-%s.err", _output, qname));
System.setOut(out);
System.setErr(err);
+
+ if (_interleaveBrokerLog)
+ {
+ _brokerOutputStream = out;
+ }
+ else
+ {
+ _brokerOutputStream = new PrintStream(new FileOutputStream(String
+ .format("%s/TEST-%s.broker.out", _output, qname)), true);
+ }
}
- _logger.info("========== start " + name + " ==========");
- startBroker();
+ _logger.info("========== start " + _testName + " ==========");
try
{
super.runBare();
@@ -189,7 +267,20 @@ public class QpidTestCase extends TestCase
{
_logger.error("exception stopping broker", e);
}
- _logger.info("========== stop " + name + " ==========");
+
+ if(_brokerCleanBetweenTests)
+ {
+ try
+ {
+ cleanBroker();
+ }
+ catch (Exception e)
+ {
+ _logger.error("exception cleaning up broker", e);
+ }
+ }
+
+ _logger.info("========== stop " + _testName + " ==========");
if (redirected)
{
@@ -197,13 +288,29 @@ public class QpidTestCase extends TestCase
System.setOut(oldOut);
err.close();
out.close();
+ if (!_interleaveBrokerLog)
+ {
+ _brokerOutputStream.close();
+ }
}
}
}
+ @Override
+ protected void setUp() throws Exception
+ {
+ if (!_configFile.exists())
+ {
+ fail("Unable to test without config file:" + _configFile);
+ }
+
+ startBroker();
+ }
+
public void run(TestResult testResult)
{
- if (_exclusionList != null && (_exclusionList.contains(getClass().getName() + "#*") ||
+ if (_exclusionList != null && (_exclusionList.contains(getClass().getPackage().getName() + ".*") ||
+ _exclusionList.contains(getClass().getName() + "#*") ||
_exclusionList.contains(getClass().getName() + "#" + getName())))
{
_logger.info("Test: " + getName() + " is excluded");
@@ -219,13 +326,26 @@ public class QpidTestCase extends TestCase
{
private LineNumberReader in;
+ private PrintStream out;
private String ready;
private CountDownLatch latch;
+ private boolean seenReady;
+ private String stopped;
+ private String stopLine;
+
+ public Piper(InputStream in, PrintStream out, String ready)
+ {
+ this(in, out, ready, null);
+ }
- public Piper(InputStream in, String ready)
+ public Piper(InputStream in, PrintStream out, String ready, String stopped)
{
this.in = new LineNumberReader(new InputStreamReader(in));
+ this.out = out;
this.ready = ready;
+ this.stopped = stopped;
+ this.seenReady = false;
+
if (this.ready != null && !this.ready.equals(""))
{
this.latch = new CountDownLatch(1);
@@ -236,9 +356,9 @@ public class QpidTestCase extends TestCase
}
}
- public Piper(InputStream in)
+ public Piper(InputStream in, PrintStream out)
{
- this(in, null);
+ this(in, out, null);
}
public boolean await(long timeout, TimeUnit unit) throws InterruptedException
@@ -249,7 +369,8 @@ public class QpidTestCase extends TestCase
}
else
{
- return latch.await(timeout, unit);
+ latch.await(timeout, unit);
+ return seenReady;
}
}
@@ -259,12 +380,23 @@ public class QpidTestCase extends TestCase
{
String line;
while ((line = in.readLine()) != null)
- {
- System.out.println(line);
+ {
+ if (_interleaveBrokerLog)
+ {
+ line = _brokerLogPrefix + line;
+ }
+ out.println(line);
+
if (latch != null && line.contains(ready))
{
+ seenReady = true;
latch.countDown();
}
+
+ if (!seenReady && line.contains(stopped))
+ {
+ stopLine = line;
+ }
}
}
catch (IOException e)
@@ -280,19 +412,86 @@ public class QpidTestCase extends TestCase
}
}
}
+
+ public String getStopLine()
+ {
+ return stopLine;
+ }
}
public void startBroker() throws Exception
{
+ startBroker(0);
+ }
+
+ /**
+ * Return the management portin use by the broker on this main port
+ *
+ * @param mainPort the broker's main port.
+ *
+ * @return the management port that corresponds to the broker on the given port
+ */
+ protected int getManagementPort(int mainPort)
+ {
+ return mainPort + (DEFAULT_MANAGEMENT_PORT - DEFAULT_PORT);
+ }
+
+ /**
+ * Get the Port that is use by the current broker
+ *
+ * @return the current port
+ */
+ protected int getPort()
+ {
+ return getPort(0);
+ }
+
+ private int getPort(int port)
+ {
+ if (_broker.equals(VM))
+ {
+ return port == 0 ? DEFAULT_VM_PORT : port;
+ }
+ else if (!_broker.equals(EXTERNAL))
+ {
+ return port == 0 ? DEFAULT_PORT : port;
+ }
+ else
+ {
+ return port;
+ }
+ }
+
+ private String getBrokerCommand(int port) throws MalformedURLException
+ {
+ return _broker
+ .replace("@PORT", "" + port)
+ .replace("@SSL_PORT", "" + (port - 1))
+ .replace("@MPORT", "" + getManagementPort(port))
+ .replace("@CONFIG_FILE", _configFile.toString());
+ }
+
+ public void startBroker(int port) throws Exception
+ {
+ port = getPort(port);
+
+ // Save any configuratio changes that have been made
+ saveTestConfiguration();
+
+ Process process = null;
if (_broker.equals(VM))
{
+ setConfigurationProperty("management.jmxport", String.valueOf(getManagementPort(port)));
+ saveTestConfiguration();
// create an in_VM broker
- TransportConnection.createVMBroker(1);
+ ApplicationRegistry.initialise(new ConfigurationFileApplicationRegistry(_configFile), port);
+ TransportConnection.createVMBroker(port);
}
else if (!_broker.equals(EXTERNAL))
{
- _logger.info("starting broker: " + _broker);
- ProcessBuilder pb = new ProcessBuilder(_broker.split("\\s+"));
+ String cmd = getBrokerCommand(port);
+ _logger.info("starting broker: " + cmd);
+ ProcessBuilder pb = new ProcessBuilder(cmd.split("\\s+"));
pb.redirectErrorStream(true);
Map<String, String> env = pb.environment();
@@ -303,23 +502,84 @@ public class QpidTestCase extends TestCase
//Augment Path with bin directory in QPID_HOME.
env.put("PATH", env.get("PATH").concat(File.pathSeparator + qpidHome + "/bin"));
- _brokerProcess = pb.start();
+ //Add the test name to the broker run.
+ // DON'T change PNAME, qpid.stop needs this value.
+ env.put("QPID_PNAME", "-DPNAME=QPBRKR -DTNAME=\"" + _testName + "\"");
+ env.put("QPID_WORK", System.getProperty("QPID_WORK"));
+
+
+ // Use the environment variable to set amqj.logging.level for the broker
+ // The value used is a 'server' value in the test configuration to
+ // allow a differentiation between the client and broker logging levels.
+ if (System.getProperty("amqj.server.logging.level") != null)
+ {
+ setBrokerEnvironment("AMQJ_LOGGING_LEVEL", System.getProperty("amqj.server.logging.level"));
+ }
+
+ // Add all the environment settings the test requested
+ if (!_env.isEmpty())
+ {
+ for (Map.Entry<String, String> entry : _env.entrySet())
+ {
+ env.put(entry.getKey(), entry.getValue());
+ }
+ }
+
+
+ // Add default test logging levels that are used by the log4j-test
+ // Use the convenience methods to push the current logging setting
+ // in to the external broker's QPID_OPTS string.
+ if (System.getProperty("amqj.protocol.logging.level") != null)
+ {
+ setSystemProperty("amqj.protocol.logging.level");
+ }
+ if (System.getProperty("root.logging.level") != null)
+ {
+ setSystemProperty("root.logging.level");
+ }
+
- Piper p = new Piper(_brokerProcess.getInputStream(),
- System.getProperty(BROKER_READY));
+ String QPID_OPTS = " ";
+ // Add all the specified system properties to QPID_OPTS
+ if (!_propertiesSetForBroker.isEmpty())
+ {
+ for (String key : _propertiesSetForBroker.keySet())
+ {
+ QPID_OPTS += "-D" + key + "=" + _propertiesSetForBroker.get(key) + " ";
+ }
+
+ if (env.containsKey("QPID_OPTS"))
+ {
+ env.put("QPID_OPTS", env.get("QPID_OPTS") + QPID_OPTS);
+ }
+ else
+ {
+ env.put("QPID_OPTS", QPID_OPTS);
+ }
+ }
+
+ process = pb.start();
+
+ Piper p = new Piper(process.getInputStream(),
+ _brokerOutputStream,
+ System.getProperty(BROKER_READY),
+ System.getProperty(BROKER_STOPPED));
p.start();
if (!p.await(30, TimeUnit.SECONDS))
{
- _logger.info("broker failed to become ready");
+ _logger.info("broker failed to become ready (" + p.ready + "):" + p.getStopLine());
+ //Ensure broker has stopped
+ process.destroy();
cleanBroker();
- throw new RuntimeException("broker failed to become ready");
+ throw new RuntimeException("broker failed to become ready:"
+ + p.getStopLine());
}
try
{
- int exit = _brokerProcess.exitValue();
+ int exit = process.exitValue();
_logger.info("broker aborted: " + exit);
cleanBroker();
throw new RuntimeException("broker aborted: " + exit);
@@ -329,7 +589,29 @@ public class QpidTestCase extends TestCase
// this is expect if the broker started succesfully
}
}
- _brokerStarted = true;
+
+ _brokers.put(port, process);
+ }
+
+ public String getTestConfigFile()
+ {
+ String path = _output == null ? System.getProperty("java.io.tmpdir") : _output;
+ return path + "/" + getTestQueueName() + ".xml";
+ }
+
+ protected void saveTestConfiguration() throws ConfigurationException
+ {
+ String testConfig = getTestConfigFile();
+ //Specifiy the test configuration
+ setSystemProperty("test.config", testConfig);
+
+ // This is a work
+ if (_testConfiguration.isEmpty())
+ {
+ _testConfiguration.addProperty("test", getTestQueueName());
+ }
+
+ _testConfiguration.save(getTestConfigFile());
}
public void cleanBroker()
@@ -343,7 +625,7 @@ public class QpidTestCase extends TestCase
ProcessBuilder pb = new ProcessBuilder(_brokerClean.split("\\s+"));
pb.redirectErrorStream(true);
Process clean = pb.start();
- new Piper(clean.getInputStream()).start();
+ new Piper(clean.getInputStream(),_brokerOutputStream).start();
clean.waitFor();
@@ -362,20 +644,250 @@ public class QpidTestCase extends TestCase
public void stopBroker() throws Exception
{
- _logger.info("stopping broker: " + _broker);
- if (_brokerProcess != null)
+ stopBroker(0);
+ }
+
+ public void stopBroker(int port) throws Exception
+ {
+ port = getPort(port);
+
+ _logger.info("stopping broker: " + getBrokerCommand(port));
+ Process process = _brokers.remove(port);
+ if (process != null)
{
- _brokerProcess.destroy();
- _brokerProcess.waitFor();
- _logger.info("broker exited: " + _brokerProcess.exitValue());
- _brokerProcess = null;
+ process.destroy();
+ process.waitFor();
+ _logger.info("broker exited: " + process.exitValue());
}
else if (_broker.equals(VM))
{
- TransportConnection.killAllVMBrokers();
- ApplicationRegistry.removeAll();
+ TransportConnection.killVMBroker(port);
+ ApplicationRegistry.remove(port);
}
- _brokerStarted = false;
+ }
+
+ /**
+ * Attempt to set the Java Broker to use the BDBMessageStore for persistence
+ * Falling back to the DerbyMessageStore if
+ *
+ * @param virtualhost - The virtualhost to modify
+ *
+ * @throws ConfigurationException - when reading/writing existing configuration
+ * @throws IOException - When creating a temporary file.
+ */
+ protected void makeVirtualHostPersistent(String virtualhost)
+ throws ConfigurationException, IOException
+ {
+ Class storeClass = DerbyMessageStore.class;
+
+ Class bdb = null;
+ try
+ {
+ bdb = Class.forName("org.apache.qpid.server.store.berkeleydb.BDBMessageStore");
+ }
+ catch (ClassNotFoundException e)
+ {
+ // No BDB store, we'll use Derby instead.
+ }
+
+ if (bdb != null)
+ {
+ storeClass = bdb;
+ }
+
+
+ _testConfiguration.setProperty("virtualhosts.virtualhost." + virtualhost +
+ ".store.class", storeClass.getName());
+ _testConfiguration.setProperty("virtualhosts.virtualhost." + virtualhost +
+ ".store." + DerbyMessageStore.ENVIRONMENT_PATH_PROPERTY,
+ "${QPID_WORK}/" + virtualhost);
+ }
+
+ /**
+ * Get a property value from the current configuration file.
+ *
+ * @param property the property to lookup
+ *
+ * @return the requested String Value
+ *
+ * @throws org.apache.commons.configuration.ConfigurationException
+ *
+ */
+ protected String getConfigurationStringProperty(String property) throws ConfigurationException
+ {
+ // Call save Configuration to be sure we have saved the test specific
+ // file. As the optional status
+ saveTestConfiguration();
+
+ ServerConfiguration configuration = new ServerConfiguration(_configFile);
+ return configuration.getConfig().getString(property);
+ }
+
+ /**
+ * Set a configuration Property for this test run.
+ *
+ * This creates a new configuration based on the current configuration
+ * with the specified property change.
+ *
+ * Multiple calls to this method will result in multiple temporary
+ * configuration files being created.
+ *
+ * @param property the configuration property to set
+ * @param value the new value
+ *
+ * @throws ConfigurationException when loading the current config file
+ * @throws IOException when writing the new config file
+ */
+ protected void setConfigurationProperty(String property, String value)
+ throws ConfigurationException, IOException
+ {
+ //Write the value in to this configuration file which will override the
+ // defaults.
+ _testConfiguration.setProperty(property, value);
+ }
+
+ /**
+ * Set a System property that is to be applied only to the external test
+ * broker.
+ *
+ * This is a convenience method to enable the setting of a -Dproperty=value
+ * entry in QPID_OPTS
+ *
+ * This is only useful for the External Java Broker tests.
+ *
+ * @param property the property name
+ * @param value the value to set the property to
+ */
+ protected void setBrokerOnlySystemProperty(String property, String value)
+ {
+ if (!_propertiesSetForBroker.containsKey(property))
+ {
+ _propertiesSetForBroker.put(property, value);
+ }
+
+ }
+
+ /**
+ * Set a System (-D) property for this test run.
+ *
+ * This convenience method copies the current VMs System Property
+ * for the external VM Broker.
+ *
+ * @param property the System property to set
+ */
+ protected void setSystemProperty(String property)
+ {
+ setSystemProperty(property, System.getProperty(property));
+ }
+
+ /**
+ * Set a System property for the duration of this test.
+ *
+ * When the test run is complete the value will be reverted.
+ *
+ * The values set using this method will also be propogated to the external
+ * Java Broker via a -D value defined in QPID_OPTS.
+ *
+ * If the value should not be set on the broker then use
+ * setTestClientSystemProperty().
+ *
+ * @param property the property to set
+ * @param value the new value to use
+ */
+ protected void setSystemProperty(String property, String value)
+ {
+ // Record the value for the external broker
+ _propertiesSetForBroker.put(property, value);
+
+ //Set the value for the test client vm aswell.
+ setTestClientSystemProperty(property, value);
+ }
+
+ /**
+ * Set a System (-D) property for the external Broker of this test.
+ *
+ * @param property The property to set
+ * @param value the value to set it to.
+ */
+ protected void setTestClientSystemProperty(String property, String value)
+ {
+ if (!_propertiesSetForTestOnly.containsKey(property))
+ {
+ // Record the current value so we can revert it later.
+ _propertiesSetForTestOnly.put(property, System.getProperty(property));
+ }
+
+ System.setProperty(property, value);
+ }
+
+ /**
+ * Restore the System property values that were set before this test run.
+ */
+ protected void revertSystemProperties()
+ {
+ for (String key : _propertiesSetForTestOnly.keySet())
+ {
+ String value = _propertiesSetForTestOnly.get(key);
+ if (value != null)
+ {
+ System.setProperty(key, value);
+ }
+ else
+ {
+ System.clearProperty(key);
+ }
+ }
+
+ _propertiesSetForTestOnly.clear();
+
+ // We don't change the current VMs settings for Broker only properties
+ // so we can just clear this map
+ _propertiesSetForBroker.clear();
+ }
+
+ /**
+ * Add an environtmen variable for the external broker environment
+ *
+ * @param property the property to set
+ * @param value the value to set it to
+ */
+ protected void setBrokerEnvironment(String property, String value)
+ {
+ _env.put(property, value);
+ }
+
+ /**
+ * Adjust the VMs Log4j Settings just for this test run
+ *
+ * @param logger the logger to change
+ * @param level the level to set
+ */
+ protected void setLoggerLevel(org.apache.log4j.Logger logger, Level level)
+ {
+ assertNotNull("Cannot set level of null logger", logger);
+ assertNotNull("Cannot set Logger("+logger.getName()+") to null level.",level);
+
+ if (!_loggerLevelSetForTest.containsKey(logger))
+ {
+ // Record the current value so we can revert it later.
+ _loggerLevelSetForTest.put(logger, logger.getLevel());
+ }
+
+ logger.setLevel(level);
+ }
+
+ /**
+ * Restore the logging levels defined by this test.
+ */
+ protected void revertLoggingLevels()
+ {
+ for (org.apache.log4j.Logger logger : _loggerLevelSetForTest.keySet())
+ {
+ logger.setLevel(_loggerLevelSetForTest.get(logger));
+ }
+
+ _loggerLevelSetForTest.clear();
+
}
/**
@@ -393,10 +905,30 @@ public class QpidTestCase extends TestCase
return _brokerVersion.equals(VERSION_010);
}
+ protected boolean isJavaBroker()
+ {
+ return _brokerLanguage.equals("java") || _broker.equals("vm");
+ }
+
+ protected boolean isCppBroker()
+ {
+ return _brokerLanguage.equals("cpp");
+ }
+
+ protected boolean isExternalBroker()
+ {
+ return !_broker.equals("vm");
+ }
+
public void restartBroker() throws Exception
{
- stopBroker();
- startBroker();
+ restartBroker(0);
+ }
+
+ public void restartBroker(int port) throws Exception
+ {
+ stopBroker(port);
+ startBroker(port);
}
/**
@@ -431,13 +963,13 @@ public class QpidTestCase extends TestCase
_logger.info("get ConnectionFactory");
if (_connectionFactory == null)
{
- if (_broker.equals(VM))
+ if (Boolean.getBoolean("profile.use_ssl"))
{
- _connectionFactory = getConnectionFactory("vm");
+ _connectionFactory = getConnectionFactory("default.ssl");
}
else
{
- _connectionFactory = getConnectionFactory("local");
+ _connectionFactory = getConnectionFactory("default");
}
}
return _connectionFactory;
@@ -454,14 +986,28 @@ public class QpidTestCase extends TestCase
*/
public AMQConnectionFactory getConnectionFactory(String factoryName) throws NamingException
{
+ if (_broker.equals(VM))
+ {
+ factoryName += ".vm";
+ }
+
return (AMQConnectionFactory) getInitialContext().lookup(factoryName);
}
- public Connection getConnection() throws Exception
+ public Connection getConnection() throws JMSException, NamingException
{
return getConnection("guest", "guest");
}
+ public Connection getConnection(ConnectionURL url) throws JMSException
+ {
+ Connection connection = new AMQConnectionFactory(url).createConnection("guest", "guest");
+
+ _connections.add(connection);
+
+ return connection;
+ }
+
/**
* Get a connection (remote or in-VM)
*
@@ -472,7 +1018,7 @@ public class QpidTestCase extends TestCase
*
* @throws Exception if there is an error getting the connection
*/
- public Connection getConnection(String username, String password) throws Exception
+ public Connection getConnection(String username, String password) throws JMSException, NamingException
{
_logger.info("get Connection");
Connection con = getConnectionFactory().createConnection(username, password);
@@ -481,7 +1027,7 @@ public class QpidTestCase extends TestCase
return con;
}
- public Connection getConnection(String username, String password, String id) throws Exception
+ public Connection getConnection(String username, String password, String id) throws JMSException, URLSyntaxException, AMQException, NamingException
{
_logger.info("get Connection");
Connection con;
@@ -498,16 +1044,232 @@ public class QpidTestCase extends TestCase
return con;
}
+ /**
+ * Return a uniqueName for this test.
+ * In this case it returns a queue Named by the TestCase and TestName
+ *
+ * @return String name for a queue
+ */
+ protected String getTestQueueName()
+ {
+ return getClass().getSimpleName() + "-" + getName();
+ }
+
+ /**
+ * Return a Queue specific for this test.
+ * Uses getTestQueueName() as the name of the queue
+ * @return
+ */
+ public Queue getTestQueue()
+ {
+ return new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, getTestQueueName());
+ }
+
+
protected void tearDown() throws java.lang.Exception
{
- // close all the connections used by this test.
- if (_brokerStarted)
+ try
{
+ // close all the connections used by this test.
for (Connection c : _connections)
{
c.close();
}
}
+ finally{
+ // Ensure any problems with close does not interfer with property resets
+ revertSystemProperties();
+ revertLoggingLevels();
+ }
+ }
+
+ /**
+ * Consume all the messages in the specified queue. Helper to ensure
+ * persistent tests don't leave data behind.
+ *
+ * @param queue the queue to purge
+ *
+ * @return the count of messages drained
+ *
+ * @throws Exception if a problem occurs
+ */
+ protected int drainQueue(Queue queue) throws Exception
+ {
+ Connection connection = getConnection();
+
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ MessageConsumer consumer = session.createConsumer(queue);
+
+ connection.start();
+
+ int count = 0;
+ while (consumer.receive(1000) != null)
+ {
+ count++;
+ }
+
+ connection.close();
+
+ return count;
+ }
+
+ /**
+ * Send messages to the given destination.
+ *
+ * If session is transacted then messages will be commited before returning
+ *
+ * @param session the session to use for sending
+ * @param destination where to send them to
+ * @param count no. of messages to send
+ *
+ * @return the sent messges
+ *
+ * @throws Exception
+ */
+ public List<Message> sendMessage(Session session, Destination destination,
+ int count) throws Exception
+ {
+ return sendMessage(session, destination, count, 0, 0);
+ }
+
+ /**
+ * Send messages to the given destination.
+ *
+ * If session is transacted then messages will be commited before returning
+ *
+ * @param session the session to use for sending
+ * @param destination where to send them to
+ * @param count no. of messages to send
+ *
+ * @param batchSize the batchSize in which to commit, 0 means no batching,
+ * but a single commit at the end
+ * @return the sent messgse
+ *
+ * @throws Exception
+ */
+ public List<Message> sendMessage(Session session, Destination destination,
+ int count, int batchSize) throws Exception
+ {
+ return sendMessage(session, destination, count, 0, batchSize);
+ }
+
+ /**
+ * Send messages to the given destination.
+ *
+ * If session is transacted then messages will be commited before returning
+ *
+ * @param session the session to use for sending
+ * @param destination where to send them to
+ * @param count no. of messages to send
+ *
+ * @param offset offset allows the INDEX value of the message to be adjusted.
+ * @param batchSize the batchSize in which to commit, 0 means no batching,
+ * but a single commit at the end
+ * @return the sent messgse
+ *
+ * @throws Exception
+ */
+ public List<Message> sendMessage(Session session, Destination destination,
+ int count, int offset, int batchSize) throws Exception
+ {
+ List<Message> messages = new ArrayList<Message>(count);
+
+ MessageProducer producer = session.createProducer(destination);
+
+ for (int i = offset; i < (count + offset); i++)
+ {
+ Message next = createNextMessage(session, i);
+
+ producer.send(next);
+
+ if (session.getTransacted() && batchSize > 0)
+ {
+ if (i % batchSize == 0)
+ {
+ session.commit();
+ }
+
+ }
+
+ messages.add(next);
+ }
+
+ // Ensure we commit the last messages
+ // Commit the session if we are transacted and
+ // we have no batchSize or
+ // our count is not divible by batchSize.
+ if (session.getTransacted() &&
+ ( batchSize == 0 || count % batchSize != 0))
+ {
+ session.commit();
+ }
+
+ return messages;
+ }
+
+ public Message createNextMessage(Session session, int msgCount) throws JMSException
+ {
+ Message message = session.createMessage();
+ message.setIntProperty(INDEX, msgCount);
+
+ return message;
+
+ }
+
+ public ConnectionURL getConnectionURL() throws NamingException
+ {
+ return getConnectionFactory().getConnectionURL();
+ }
+
+ public BrokerDetails getBroker()
+ {
+ try
+ {
+ if (getConnectionFactory().getConnectionURL().getBrokerCount() > 0)
+ {
+ return getConnectionFactory().getConnectionURL().getBrokerDetails(0);
+ }
+ else
+ {
+ fail("No broker details are available.");
+ }
+ }
+ catch (NamingException e)
+ {
+ fail(e.getMessage());
+ }
+
+ //keep compiler happy
+ return null;
}
+ public void reloadBroker() throws ConfigurationException, IOException
+ {
+ reloadBroker(0);
+ }
+
+ public void reloadBroker(int port) throws ConfigurationException, IOException
+ {
+ if (_broker.equals(VM))
+ {
+ ApplicationRegistry.getInstance().getConfiguration().reparseConfigFileSecuritySections();
+ }
+ else // FIXME: should really use the JMX interface to do this
+ {
+ /*
+ * Sigh, this is going to get messy. grep for BRKR and the port number
+ */
+
+ Process p = Runtime.getRuntime().exec("/usr/bin/pgrep -f " + getPort(port));
+ BufferedReader reader = new BufferedReader (new InputStreamReader(p.getInputStream()));
+ String cmd = "/bin/kill -SIGHUP " + reader.readLine();
+ p = Runtime.getRuntime().exec(cmd);
+
+ LogMonitor _monitor = new LogMonitor(_outputFile);
+ assertTrue("The expected server security configuration reload did not occur",
+ _monitor.waitForMessage(ServerConfiguration.SECURITY_CONFIG_RELOADED, LOGMONITOR_TIMEOUT));
+
+ }
+ }
}
diff --git a/java/systests/src/main/java/org/apache/qpid/util/LogMonitor.java b/java/systests/src/main/java/org/apache/qpid/util/LogMonitor.java
new file mode 100644
index 0000000000..7d55c68b75
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/util/LogMonitor.java
@@ -0,0 +1,211 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.util;
+
+import org.apache.log4j.FileAppender;
+import org.apache.log4j.Logger;
+import org.apache.log4j.SimpleLayout;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utility to simplify the monitoring of Log4j file output
+ *
+ * Monitoring of a given log file can be done alternatively the Monitor will
+ * add a new log4j FileAppender to the root Logger to gather all the available
+ * logging for monitoring
+ */
+public class LogMonitor
+{
+ // The file that the log statements will be written to.
+ private File _logfile;
+
+ // The appender we added to the get messages
+ private FileAppender _appender;
+
+ /**
+ * Create a new LogMonitor that creates a new Log4j Appender and monitors
+ * all log4j output via the current configuration.
+ *
+ * @throws IOException if there is a problem creating the temporary file.
+ */
+ public LogMonitor() throws IOException
+ {
+ this(null);
+ }
+
+ /**
+ * Create a new LogMonitor on the specified file if the file does not exist
+ * or the value is null then a new Log4j appender will be added and
+ * monitoring set up on that appender.
+ *
+ * NOTE: for the appender to receive any value the RootLogger will need to
+ * have the level correctly configured.ng
+ *
+ * @param file the file to monitor
+ *
+ * @throws IOException if there is a problem creating a temporary file
+ */
+ public LogMonitor(File file) throws IOException
+ {
+ if (file != null && file.exists())
+ {
+ _logfile = file;
+ }
+ else
+ {
+ // This is mostly for running the test outside of the ant setup
+ _logfile = File.createTempFile("LogMonitor", ".log");
+ _appender = new FileAppender(new SimpleLayout(),
+ _logfile.getAbsolutePath());
+ _appender.setFile(_logfile.getAbsolutePath());
+ _appender.setImmediateFlush(true);
+ Logger.getRootLogger().addAppender(_appender);
+ }
+ }
+
+ /**
+ * Checks the log for instances of the search string.
+ *
+ * The pattern parameter can take any valid argument used in String.contains()
+ *
+ * {@see String.contains(CharSequences)}
+ *
+ * @param pattern the search string
+ *
+ * @return a list of matching lines from the log
+ *
+ * @throws IOException if there is a problem with the file
+ */
+ public List<String> findMatches(String pattern) throws IOException
+ {
+ return FileUtils.searchFile(_logfile, pattern);
+ }
+
+ /**
+ * Checks the log file for a given message to appear.
+ *
+ * @param message the message to wait for in the log
+ * @param wait the time in ms to wait for the message to occur
+ *
+ * @return true if the message was found
+ *
+ * @throws java.io.FileNotFoundException if the Log file can nolonger be found
+ * @throws IOException thrown when reading the log file
+ */
+ public boolean waitForMessage(String message, long wait, boolean printFileOnFailure)
+ throws FileNotFoundException, IOException
+ {
+ // Loop through alerts until we're done or wait ms seconds have passed,
+ // just in case the logfile takes a while to flush.
+ BufferedReader reader = new BufferedReader(new FileReader(_logfile));
+ boolean found = false;
+ long endtime = System.currentTimeMillis() + wait;
+ ArrayList<String> contents = new ArrayList<String>();
+ while (!found && System.currentTimeMillis() < endtime)
+ {
+ while (reader.ready())
+ {
+ String line = reader.readLine();
+ contents.add(line);
+ if (line.contains(message))
+ {
+ found = true;
+ }
+ }
+ }
+ if (!found && printFileOnFailure)
+ {
+ for (String line : contents)
+ {
+ System.out.println(line);
+ }
+ }
+ return found;
+ }
+
+
+ public boolean waitForMessage(String message, long alertLogWaitPeriod) throws FileNotFoundException, IOException
+ {
+ return waitForMessage(message, alertLogWaitPeriod, true);
+ }
+
+
+ /**
+ * Read the log file in to memory as a String
+ *
+ * @return the current contents of the log file
+ *
+ * @throws java.io.FileNotFoundException if the Log file can nolonger be found
+ * @throws IOException thrown when reading the log file
+ */
+ public String readFile() throws FileNotFoundException, IOException
+ {
+ return FileUtils.readFileAsString(_logfile);
+ }
+
+ /**
+ * Return a File reference to the monitored file
+ *
+ * @return the file being monitored
+ */
+ public File getMonitoredFile()
+ {
+ return _logfile;
+ }
+
+ /**
+ * Clears the log file and writes: 'Log Monitor Reset' at the start of the file
+ *
+ * @throws java.io.FileNotFoundException if the Log file can nolonger be found
+ * @throws IOException thrown if there is a problem with the log file
+ */
+ public void reset() throws FileNotFoundException, IOException
+ {
+ new FileOutputStream(_logfile).getChannel().truncate(0);
+ }
+
+ /**
+ * Stop monitoring this file.
+ *
+ * This is required to be called incase we added a new logger.
+ *
+ * If we don't call close then the new logger will continue to get log entries
+ * after our desired test has finished.
+ */
+ public void close()
+ {
+ //Remove the custom appender we added for this logger
+ if (_appender != null)
+ {
+ Logger.getRootLogger().removeAppender(_appender);
+ }
+ }
+
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/util/LogMonitorTest.java b/java/systests/src/main/java/org/apache/qpid/util/LogMonitorTest.java
new file mode 100644
index 0000000000..2b9fe8e039
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/util/LogMonitorTest.java
@@ -0,0 +1,275 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.util;
+
+import junit.framework.TestCase;
+import org.apache.log4j.Logger;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+public class LogMonitorTest extends TestCase
+{
+
+ private LogMonitor _monitor;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ _monitor = new LogMonitor();
+ _monitor.getMonitoredFile().deleteOnExit(); // Make sure we clean up
+ }
+
+ /**
+ * Test that a new file is created when attempting to set up a monitor with
+ * the default constructor.
+ */
+ public void testMonitor()
+ {
+ //Validate that the monitor is now running on a new file
+ assertTrue("New file does not have correct name:" + _monitor.
+ getMonitoredFile().getName(),
+ _monitor.getMonitoredFile().getName().contains("LogMonitor"));
+ }
+
+ /**
+ * Test that creation of a monitor on an existing file is possible
+ *
+ * This also tests taht getMonitoredFile works
+ *
+ * @throws IOException if there is a problem creating the temporary file
+ */
+ public void testMonitorNormalFile() throws IOException
+ {
+ File testFile = File.createTempFile("testMonitorFile", ".log");
+ testFile.deleteOnExit();
+
+ //Ensure that we can create a monitor on a file
+ try
+ {
+ _monitor = new LogMonitor(testFile);
+ assertEquals(testFile, _monitor.getMonitoredFile());
+ }
+ catch (IOException ioe)
+ {
+ fail("IOE thrown:" + ioe);
+ }
+
+ }
+
+ /**
+ * Test that a new file is created when attempting to set up a monitor on
+ * a null input value.
+ */
+ public void testMonitorNullFile()
+ {
+ // Validate that a NPE is thrown with null input
+ try
+ {
+ LogMonitor montior = new LogMonitor(null);
+ //Validte that the monitor is now running on a new file
+ assertTrue("New file does not have correct name:" + montior.
+ getMonitoredFile().getName(),
+ montior.getMonitoredFile().getName().contains("LogMonitor"));
+ }
+ catch (IOException ioe)
+ {
+ fail("IOE thrown:" + ioe);
+ }
+ }
+
+ /**
+ * Test that a new file is created when attempting to set up a monitor on
+ * a non existing file.
+ *
+ * @throws IOException if there is a problem setting up the nonexistent file
+ */
+ public void testMonitorNonExistentFile() throws IOException
+ {
+ //Validate that we get a FileNotFound if the file does not exist
+
+ File nonexist = File.createTempFile("nonexist", ".out");
+
+ assertTrue("Unable to delete file for our test", nonexist.delete());
+
+ assertFalse("Unable to test as our test file exists.", nonexist.exists());
+
+ try
+ {
+ LogMonitor montior = new LogMonitor(nonexist);
+ //Validte that the monitor is now running on a new file
+ assertTrue("New file does not have correct name:" + montior.
+ getMonitoredFile().getName(),
+ montior.getMonitoredFile().getName().contains("LogMonitor"));
+ }
+ catch (IOException ioe)
+ {
+ fail("IOE thrown:" + ioe);
+ }
+ }
+
+ /**
+ * Test that Log file matches logged messages.
+ *
+ * @throws java.io.IOException if there is a problem creating LogMontior
+ */
+ public void testFindMatches_Match() throws IOException
+ {
+
+ String message = getName() + ": Test Message";
+
+ Logger.getRootLogger().warn(message);
+
+ validateLogContainsMessage(_monitor, message);
+ }
+
+ /**
+ * Test that Log file does not match a message not logged.
+ *
+ * @throws java.io.IOException if there is a problem creating LogMontior
+ */
+ public void testFindMatches_NoMatch() throws IOException
+ {
+ String message = getName() + ": Test Message";
+
+ Logger.getRootLogger().warn(message);
+
+ String notLogged = "This text was not logged";
+
+ validateLogDoesNotContainsMessage(_monitor, notLogged);
+ }
+
+ public void testWaitForMessage_Timeout() throws IOException
+ {
+ String message = getName() + ": Test Message";
+
+ long TIME_OUT = 2000;
+
+ logMessageWithDelay(message, TIME_OUT);
+
+ // Verify that we can time out waiting for a message
+ assertFalse("Message was logged ",
+ _monitor.waitForMessage(message, TIME_OUT / 2, false));
+
+ // Verify that the message did eventually get logged.
+ assertTrue("Message was never logged.",
+ _monitor.waitForMessage(message, TIME_OUT));
+ }
+
+ public void testReset() throws IOException
+ {
+ String message = getName() + ": Test Message";
+
+ Logger.getRootLogger().warn(message);
+
+ validateLogContainsMessage(_monitor, message);
+
+ String LOG_RESET_TEXT = "Log Monitor Reset";
+
+ validateLogDoesNotContainsMessage(_monitor, LOG_RESET_TEXT);
+
+ _monitor.reset();
+
+ assertEquals("", _monitor.readFile());
+ }
+
+ public void testRead() throws IOException
+ {
+ String message = getName() + ": Test Message";
+
+ Logger.getRootLogger().warn(message);
+
+ String fileContents = _monitor.readFile();
+
+ assertTrue("Logged message not found when reading file.",
+ fileContents.contains(message));
+ }
+
+ /****************** Helpers ******************/
+
+ /**
+ * Validate that the LogMonitor does not match the given string in the log
+ *
+ * @param log The LogMonitor to check
+ * @param message The message to check for
+ *
+ * @throws IOException if a problems occurs
+ */
+ protected void validateLogDoesNotContainsMessage(LogMonitor log, String message)
+ throws IOException
+ {
+ List<String> results = log.findMatches(message);
+
+ assertNotNull("Null results returned.", results);
+
+ assertEquals("Incorrect result set size", 0, results.size());
+ }
+
+ /**
+ * Validate that the LogMonitor can match the given string in the log
+ *
+ * @param log The LogMonitor to check
+ * @param message The message to check for
+ *
+ * @throws IOException if a problems occurs
+ */
+ protected void validateLogContainsMessage(LogMonitor log, String message)
+ throws IOException
+ {
+ List<String> results = log.findMatches(message);
+
+ assertNotNull("Null results returned.", results);
+
+ assertEquals("Incorrect result set size", 1, results.size());
+
+ assertTrue("Logged Message'" + message + "' not present in results:"
+ + results.get(0), results.get(0).contains(message));
+ }
+
+ /**
+ * Create a new thread to log the given message after the set delay
+ *
+ * @param message the messasge to log
+ * @param delay the delay (ms) to wait before logging
+ */
+ private void logMessageWithDelay(final String message, final long delay)
+ {
+ new Thread(new Runnable()
+ {
+
+ public void run()
+ {
+ try
+ {
+ Thread.sleep(delay);
+ }
+ catch (InterruptedException e)
+ {
+ //ignore
+ }
+
+ Logger.getRootLogger().warn(message);
+ }
+ }).start();
+ }
+
+}
diff --git a/java/test-profiles/08StandaloneExcludes b/java/test-profiles/08StandaloneExcludes
new file mode 100644
index 0000000000..f06bfca1ac
--- /dev/null
+++ b/java/test-profiles/08StandaloneExcludes
@@ -0,0 +1,6 @@
+//======================================================================
+//Exclude the following from brokers defaulting to the 0-8 protocol
+//======================================================================
+
+// This test requires a broker capable of 0-8/9 and 0-10
+org.apache.qpid.test.client.message.JMSDestinationTest#testReceiveResend
diff --git a/java/test-profiles/CPPExcludes b/java/test-profiles/CPPExcludes
new file mode 100755
index 0000000000..cb72da2a88
--- /dev/null
+++ b/java/test-profiles/CPPExcludes
@@ -0,0 +1,111 @@
+org.apache.qpid.test.unit.client.channelclose.ChannelCloseTest#*
+org.apache.qpid.client.ResetMessageListenerTest#*
+
+//These tests are for the java broker
+org.apache.qpid.server.security.acl.SimpleACLTest#*
+org.apache.qpid.server.security.firewall.FirewallConfigTest#*
+org.apache.qpid.server.plugins.PluginTest#*
+org.apache.qpid.server.BrokerStartupTest#*
+
+// This test is not finished
+org.apache.qpid.test.testcases.TTLTest#*
+org.apache.qpid.test.client.failover.FailoverTest#test4MinuteFailover
+
+// Those tests are testing 0.8 specific semantics
+org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsConsumerDisconnectedNoTxP2P
+org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsConsumerDisconnectedTxP2P
+org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsNoRouteNoTxP2P
+org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsNoRouteTxP2P
+org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsConsumerDisconnectedNoTxPubSub
+org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsConsumerDisconnectedTxPubSub
+org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsNoRouteNoTxPubSub
+org.apache.qpid.test.testcases.ImmediateMessageTest#test_QPID_517_ImmediateFailsNoRouteTxPubSub
+org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFailsNoRouteNoTxP2P
+org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFailsNoRouteTxP2P
+org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFailsNoRouteNoTxPubSub
+org.apache.qpid.test.testcases.MandatoryMessageTest#test_QPID_508_MandatoryFailsNoRouteTxPubSub
+org.apache.qpid.test.client.FlowControlTest#*
+org.apache.qpid.test.unit.client.connection.ConnectionTest#testDefaultExchanges
+org.apache.qpid.test.unit.client.connection.ConnectionTest#testUnresolvedVirtualHostFailure
+
+// the 0.10 c++ broker does not implement forget
+org.apache.qpid.test.unit.xa.FaultTest#testForget
+
+// the 0-10 c++ broker does not implement priority / this test depends on a Java broker extension for queue creation
+org.apache.qpid.server.queue.PriorityTest
+
+//this test checks explicitly for 0-8 flow control semantics
+org.apache.qpid.test.client.FlowControlTest
+
+// 0-10 c++ broker doesn't implement virtual hosts, or those wackhy exchanges
+org.apache.qpid.test.unit.client.connection.ConnectionTest#testUnresolvedVirtualHostFailure
+org.apache.qpid.test.unit.client.connection.ConnectionTest#testDefaultExchanges
+
+// 0-10 c++ broker in cpp.testprofile is started with no auth so won't pass this test
+org.apache.qpid.test.unit.client.connection.ConnectionTest#testPasswordFailureConnection
+
+// c++ broker doesn't do selectors, so this will fail
+org.apache.qpid.test.unit.topic.TopicSessionTest#testNonMatchingMessagesDoNotFillQueue
+
+// InVM Broker tests
+org.apache.qpid.test.client.timeouts.SyncWaitDelayTest#*
+
+// QPID-1262, QPID-1119 : This test fails occasionally due to potential protocol issue.
+org.apache.qpid.test.client.timeouts.SyncWaitTimeoutDelayTest#*
+
+// c++ broker doesn't support priorities, TTL or message bouncing
+org.apache.qpid.server.exchange.ReturnUnroutableMandatoryMessageTest#*
+org.apache.qpid.server.queue.PriorityTest#*
+org.apache.qpid.server.queue.TimeToLiveTest#*
+
+// QPID-1727 , QPID-1726 :c++ broker does not support flow to disk on transient queues. Also it requries a persistent store impl. for Apache
+org.apache.qpid.test.client.QueueBrowsingFlowToDiskTest#*
+
+// This test currently does not pick up the runtime location of the nonVm queueBacking store.
+org.apache.qpid.test.unit.close.FlowToDiskBackingQueueDeleteTest#*
+
+// This test may use QpidTestCase but it is not using the getConnection and is hardwired to InVM
+org.apache.qpid.test.unit.client.connection.CloseAfterConnectionFailureTest#*
+
+//QPID-1818 : 0-10 Client code path does not correctly restore a transacted session after failover.
+org.apache.qpid.server.persistent.NoLocalAfterRecoveryTest#*
+
+// QPID-1730: the C++ server has a totally different logging mechanism. We should split this file differently
+org.apache.qpid.server.AlertingTest#*
+
+// The C++ server has a totally different persistence mechanism
+org.apache.qpid.server.store.PersistentStoreTest#*
+
+// CPP Broker does not follow the same Logging convention as the Java broker
+org.apache.qpid.server.logging.*
+
+// CPP Broker does not have a JMX interface to test
+org.apache.qpid.management.jmx.*
+// JMX is used in this test for validation
+org.apache.qpid.server.queue.ModelTest#*
+
+
+// 0-10 is not supported by the MethodRegistry
+org.apache.qpid.test.unit.close.JavaServerCloseRaceConditionTest#*
+
+// QPID-2084 : this test needs more work for 0-10
+org.apache.qpid.test.unit.client.DynamicQueueExchangeCreateTest#*
+
+// QPID-2118 : 0-10 Java client has differrent error handling to 0-8 code path
+org.apache.qpid.test.client.message.SelectorTest#testRuntimeSelectorError
+
+//QPID-942 : Implemented Channel.Flow based Producer Side flow control to the Java Broker (not in CPP Broker)
+org.apache.qpid.server.queue.ProducerFlowControlTest#*
+
+//QPID-1950 : Commit to test this failure. This is a MINA only failure so it cannot be tested when using 010.
+org.apache.qpid.server.failover.MessageDisappearWithIOExceptionTest#*
+
+// These are recent test additions that are failing with the c++ broker
+// Temporarily disabling until properly investigated.
+org.apache.qpid.test.unit.publish.DirtyTrasactedPubilshTest#*
+org.apache.qpid.test.unit.ack.FailoverBeforeConsumingRecoverTest#*
+org.apache.qpid.test.unit.ack.AcknowledgeAfterFailoverTest#*
+org.apache.qpid.test.unit.ack.AcknowledgeAfterFailoverOnMessageTest#*
+
+org.apache.qpid.test.client.RollbackOrderTest#testOrderingAfterRollbackOnMessage#*
+
diff --git a/java/test-profiles/CPPPrefetchExcludes b/java/test-profiles/CPPPrefetchExcludes
new file mode 100644
index 0000000000..6b0014b917
--- /dev/null
+++ b/java/test-profiles/CPPPrefetchExcludes
@@ -0,0 +1,4 @@
+// those tests should be run with prefetch off
+org.apache.qpid.client.MessageListenerMultiConsumerTest#testRecieveC2Only
+org.apache.qpid.client.MessageListenerMultiConsumerTest#testRecieveBoth
+org.apache.qpid.test.unit.xa.TopicTest#testMigrateDurableSubscriber
diff --git a/java/test-profiles/CPPTransientExcludes b/java/test-profiles/CPPTransientExcludes
new file mode 100644
index 0000000000..90b4251807
--- /dev/null
+++ b/java/test-profiles/CPPTransientExcludes
@@ -0,0 +1,10 @@
+// those tests need durable subscribe states to be persisted
+org.apache.qpid.test.unit.topic.DurableSubscriptionTest#testDurSubRestoredAfterNonPersistentMessageSent
+
+// those tests require broker recovery
+org.apache.qpid.test.unit.ct.DurableSubscriberTest#*
+org.apache.qpid.test.unit.xa.TopicTest#testDurSubCrash
+org.apache.qpid.test.unit.xa.TopicTest#testMultiMessagesDurSubCrash
+org.apache.qpid.test.unit.xa.TopicTest#testRecover
+org.apache.qpid.test.unit.xa.QueueTest#testRecover
+org.apache.qpid.test.unit.xa.QueueTest#testSendAndRecover
diff --git a/java/test-profiles/Excludes b/java/test-profiles/Excludes
new file mode 100644
index 0000000000..5c6308a2d2
--- /dev/null
+++ b/java/test-profiles/Excludes
@@ -0,0 +1,38 @@
+org.apache.qpid.client.MultipleJCAProviderRegistrationTest#test
+// QPID-1715, QPID-1715 : Client Error Handling on close is still broken
+org.apache.qpid.server.queue.QueueCreateTest#testCreatePriorityString
+org.apache.qpid.server.queue.QueueCreateTest#testCreateFlowToDiskValidNoSize
+org.apache.qpid.server.queue.QueueCreateTest#testCreateFlowToDiskInvalid
+org.apache.qpid.server.queue.QueueCreateTest#testCreateFlowToDiskInvalidSize
+
+//
+// QPID-2031 : Broker is not cleanly shutdown by QpidTestCase
+//
+org.apache.qpid.server.logging.BrokerLoggingTest#testBrokerShutdownListeningTCPDefault
+org.apache.qpid.server.logging.BrokerLoggingTest#testBrokerShutdownListeningTCPSSL
+org.apache.qpid.server.logging.BrokerLoggingTest#testBrokerShutdownStopped
+org.apache.qpid.server.logging.VirtualHostLoggingTest#testVirtualhostClosure
+org.apache.qpid.server.logging.MemoryMessageStoreLoggingTest#testMessageStoreClose
+
+// QPID-XXX : Test fails to start external broker due to Derby Exception.
+org.apache.qpid.server.logging.DerbyMessageStoreLoggingTest#*
+
+// QPID-1816 : Client Ack has not been addressed
+org.apache.qpid.test.unit.ack.AcknowledgeAfterFailoverOnMessageTest#testDirtyClientAck
+org.apache.qpid.test.unit.ack.AcknowledgeAfterFailoverOnMessageTest#testClientAck
+org.apache.qpid.test.unit.ack.AcknowledgeAfterFailoverTest#testDirtyClientAck
+org.apache.qpid.test.unit.ack.AcknowledgeAfterFailoverTest#testClientAck
+
+
+// QPID-143 : Failover can occur between receive and ack but we don't stop the ack.
+// Just fully disable both tests as they are highlighting to many Java Client race conditions
+org.apache.qpid.test.unit.ack.AcknowledgeAfterFailoverOnMessageTest#*
+org.apache.qpid.test.unit.ack.AcknowledgeAfterFailoverTest#*
+
+// The following tests exibit random failures and are temporarily excluded.
+// QPID-2224 Random Test failures - The test needs to be fixed.
+org.apache.qpid.transport.network.mina.MINANetworkDriverTest#*
+// QPID-2225 Random Test failures against the in-vm broker.
+org.apache.qpid.test.unit.ack.FailoverBeforeConsumingRecover#*
+// QPID-2262 Random test failures - The test needs to be fixed.
+org.apache.qpid.server.security.acl.SimpleACLTest#testClientPublishInvalidQueueSuccess
diff --git a/java/test-profiles/JavaExcludes b/java/test-profiles/JavaExcludes
new file mode 100644
index 0000000000..6f3898384d
--- /dev/null
+++ b/java/test-profiles/JavaExcludes
@@ -0,0 +1,20 @@
+org.apache.qpid.test.unit.ct.DurableSubscriberTests#*
+// Those tests are not finished
+org.apache.qpid.test.testcases.TTLTest#*
+org.apache.qpid.test.testcases.FailoverTest#*
+// This is a long running test so should exclude from normal runs
+org.apache.qpid.test.client.failover.FailoverTest#test4MinuteFailover
+// Those tests are written against the 0.10 path
+org.apache.qpid.test.unit.message.UTF8Test#*
+org.apache.qpid.client.MessageListenerTest#testSynchronousRecieveNoWait
+
+//QPID-1818 : Client code path does not correctly restore a transacted session after failover.
+org.apache.qpid.server.persistent.NoLocalAfterRecoveryTest#*
+
+// QPID-1823: this takes ages to run
+org.apache.qpid.client.SessionCreateTest#*
+
+// QPID-2097 exclude it from the InVM test runs until InVM JMX Interface is reliable
+org.apache.qpid.management.jmx.ManagementActorLoggingTest#*
+org.apache.qpid.server.queue.ModelTest#*
+
diff --git a/java/test-profiles/JavaInVMExcludes b/java/test-profiles/JavaInVMExcludes
new file mode 100644
index 0000000000..915c1ff0c2
--- /dev/null
+++ b/java/test-profiles/JavaInVMExcludes
@@ -0,0 +1,9 @@
+//======================================================================
+//Exclude the following tests when running the InVM default test profile
+//======================================================================
+
+// QPID-2097 exclude until InVM JMX test runs are reliable
+org.apache.qpid.server.queue.ProducerFlowControlTest#testFlowControlAttributeModificationViaJMX
+
+// This test requires a broker capable of 0-8/9 and 0-10
+org.apache.qpid.test.client.message.JMSDestinationTest#testReceiveResend
diff --git a/java/test-profiles/JavaStandaloneExcludes b/java/test-profiles/JavaStandaloneExcludes
new file mode 100644
index 0000000000..ed12973498
--- /dev/null
+++ b/java/test-profiles/JavaStandaloneExcludes
@@ -0,0 +1,44 @@
+org.apache.qpid.test.unit.ct.DurableSubscriberTests#*
+// Those tests are not finished
+org.apache.qpid.test.testcases.TTLTest#*
+org.apache.qpid.test.testcases.FailoverTest#*
+// This is a long running test so should exclude from normal runs
+org.apache.qpid.test.client.failover.FailoverTest#test4MinuteFailover
+// Those tests require failover support
+org.apache.qpid.test.client.QueueBrowserAutoAckTest#testFailoverAsQueueBrowserCreated
+org.apache.qpid.test.client.QueueBrowserAutoAckTest#testFailoverWithQueueBrowser
+org.apache.qpid.test.client.QueueBrowserClientAckTest#testFailoverAsQueueBrowserCreated
+org.apache.qpid.test.client.QueueBrowserClientAckTest#testFailoverWithQueueBrowser
+org.apache.qpid.test.client.QueueBrowserDupsOkTest#testFailoverAsQueueBrowserCreated
+org.apache.qpid.test.client.QueueBrowserDupsOkTest#testFailoverWithQueueBrowser
+org.apache.qpid.test.client.QueueBrowserNoAckTest#testFailoverAsQueueBrowserCreated
+org.apache.qpid.test.client.QueueBrowserNoAckTest#testFailoverWithQueueBrowser
+org.apache.qpid.test.client.QueueBrowserPreAckTest#testFailoverAsQueueBrowserCreated
+org.apache.qpid.test.client.QueueBrowserPreAckTest#testFailoverWithQueueBrowser
+org.apache.qpid.test.client.QueueBrowserTransactedTest#testFailoverAsQueueBrowserCreated
+org.apache.qpid.test.client.QueueBrowserTransactedTest#testFailoverWithQueueBrowser
+org.apache.qpid.test.testcases.FailoverTest#*
+org.apache.qpid.test.client.failover.FailoverTest#*
+
+// InVM Broker tests awaiting resolution of QPID-1103
+org.apache.qpid.test.client.timeouts.SyncWaitDelayTest#*
+org.apache.qpid.test.client.timeouts.SyncWaitTimeoutDelayTest#*
+
+// Those tests are written against the 0.10 path
+org.apache.qpid.test.unit.message.UTF8Test#*
+org.apache.qpid.client.MessageListenerTest#testSynchronousRecieveNoWait
+
+// This test currently does not pick up the runtime location of the nonVm queueBacking store.
+org.apache.qpid.test.unit.close.FlowToDiskBackingQueueDeleteTest#*
+
+// This test may use QpidTestCase but it is not using the getConnection and is hardwired to InVM
+org.apache.qpid.test.unit.client.connection.CloseAfterConnectionFailureTest#*
+//QPID-1818 : Client code path does not correctly restore a transacted session after failover.
+org.apache.qpid.server.persistent.NoLocalAfterRecoveryTest#*
+// QPID-1823: this takes ages to run
+org.apache.qpid.client.SessionCreateTest#*
+
+// This test requires the standard configuration file for validation.
+// Excluding here does not reduce test coverage.
+org.apache.qpid.server.configuration.ServerConfigurationFileTest#*
+
diff --git a/java/test-profiles/JavaTransientExcludes b/java/test-profiles/JavaTransientExcludes
new file mode 100644
index 0000000000..f81e9c213c
--- /dev/null
+++ b/java/test-profiles/JavaTransientExcludes
@@ -0,0 +1 @@
+org.apache.qpid.server.store.PersistentStoreTest#*
diff --git a/java/test-profiles/XAExcludes b/java/test-profiles/XAExcludes
new file mode 100644
index 0000000000..1bb26c5f27
--- /dev/null
+++ b/java/test-profiles/XAExcludes
@@ -0,0 +1,3 @@
+org.apache.qpid.test.unit.xa.QueueTest#*
+org.apache.qpid.test.unit.xa.TopicTest#*
+org.apache.qpid.test.unit.xa.FaultTest#*
diff --git a/java/test-profiles/clean-dir b/java/test-profiles/clean-dir
new file mode 100755
index 0000000000..4d6141b4ab
--- /dev/null
+++ b/java/test-profiles/clean-dir
@@ -0,0 +1,25 @@
+
+#!/bin/bash
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
+
+rm -rf $@; mkdir $@
diff --git a/java/test-profiles/cpp.async.excludes b/java/test-profiles/cpp.async.excludes
new file mode 100644
index 0000000000..72d79fb754
--- /dev/null
+++ b/java/test-profiles/cpp.async.excludes
@@ -0,0 +1,5 @@
+// the C++ broker doesn't implement selectors, so they are not persisted with the subscription
+org.apache.qpid.test.unit.ct.DurableSubscriberTest#testDurSubRestoresMessageSelector
+
+// the C++ broker doesn't guarantee the order of messages on recovery
+org.apache.qpid.test.unit.xa.TopicTest#testMultiMessagesDurSubCrash
diff --git a/java/test-profiles/cpp.async.testprofile b/java/test-profiles/cpp.async.testprofile
new file mode 100644
index 0000000000..ac8b98471e
--- /dev/null
+++ b/java/test-profiles/cpp.async.testprofile
@@ -0,0 +1,3 @@
+include=cpp
+profile.excludes=CPPPrefetchExcludes
+broker.modules=--load-module ${broker.module.store}
diff --git a/java/test-profiles/cpp.cluster.testprofile b/java/test-profiles/cpp.cluster.testprofile
new file mode 100644
index 0000000000..4bfd4f69a2
--- /dev/null
+++ b/java/test-profiles/cpp.cluster.testprofile
@@ -0,0 +1,10 @@
+include=cpp
+
+broker.modules=--load-module ${broker.module.cluster} --cluster-name cpp-java-test-cluster
+
+profile.excludes=XAExcludes CPPPrefetchExcludes CPPTransientExcludes
+
+profile.clustered=true
+profile.failoverMsgCount=10
+profile.failoverIterations=10
+profile.failoverRandomSeed=20080921
diff --git a/java/test-profiles/cpp.excludes b/java/test-profiles/cpp.excludes
new file mode 100644
index 0000000000..64417a0edc
--- /dev/null
+++ b/java/test-profiles/cpp.excludes
@@ -0,0 +1,10 @@
+//======================================================================
+//Exclude the following tests when running all cpp test profilies
+//======================================================================
+
+// This test requires JMX interface to move messages
+org.apache.qpid.test.client.message.JMSDestinationTest#testMovedToQueue
+
+// This test requires a broker capable of 0-8/9 and 0-10
+org.apache.qpid.test.client.message.JMSDestinationTest#testReceiveResend
+
diff --git a/java/test-profiles/cpp.noprefetch.testprofile b/java/test-profiles/cpp.noprefetch.testprofile
new file mode 100644
index 0000000000..304671a4a4
--- /dev/null
+++ b/java/test-profiles/cpp.noprefetch.testprofile
@@ -0,0 +1,3 @@
+include=cpp
+profile.excludes=CPPTransientExcludes
+max_prefetch=0
diff --git a/java/test-profiles/cpp.ssl.excludes b/java/test-profiles/cpp.ssl.excludes
new file mode 100644
index 0000000000..1828581d55
--- /dev/null
+++ b/java/test-profiles/cpp.ssl.excludes
@@ -0,0 +1 @@
+#org.apache.qpid.test.client.failover.FailoverTest#*
diff --git a/java/test-profiles/cpp.ssl.testprofile b/java/test-profiles/cpp.ssl.testprofile
new file mode 100644
index 0000000000..9f2581a83a
--- /dev/null
+++ b/java/test-profiles/cpp.ssl.testprofile
@@ -0,0 +1,11 @@
+include=cpp
+
+broker.modules=--load-module ${broker.module.ssl} --ssl-cert-name localhost.localdomain --ssl-cert-password-file ${test.profiles}/test_resources/ssl/pfile --ssl-cert-db ${test.profiles}/test_resources/ssl/server_db/ --ssl-require-client-authentication --ssl-port @SSL_PORT
+
+profile.use_ssl=true
+broker.ready= Listening for SSL connections
+
+javax.net.ssl.keyStore=${test.profiles}/test_resources/ssl/keystore.jks
+javax.net.ssl.keyStorePassword=password
+javax.net.ssl.trustStore=${test.profiles}/test_resources/ssl/certstore.jks
+javax.net.ssl.trustStorePassword=password
diff --git a/java/test-profiles/cpp.testprofile b/java/test-profiles/cpp.testprofile
new file mode 100644
index 0000000000..04407accc3
--- /dev/null
+++ b/java/test-profiles/cpp.testprofile
@@ -0,0 +1,19 @@
+broker.version=0-10
+
+broker.dir=${project.root}/../cpp/src
+module.dir=${broker.dir}/.libs
+store.module.dir=${project.root}/../../cppStore/cpp/lib/.libs
+
+broker.executable=${broker.dir}/qpidd
+broker.module.ssl=${module.dir}/ssl.so
+broker.module.cluster=${module.dir}/cluster.so
+broker.module.store=${store.module.dir}/msgstore.so
+broker.stopped=Exception constructed
+
+broker.modules=
+broker.args=
+
+broker=${broker.executable} -p @PORT --data-dir ${build.data}/@PORT -t --auth no --no-module-dir ${broker.modules} ${broker.args}
+
+profile.excludes=CPPPrefetchExcludes CPPTransientExcludes
+test.excludes=Excludes CPPExcludes ${profile}.excludes ${profile.excludes} cpp.excludes
diff --git a/java/test-profiles/default.testprofile b/java/test-profiles/default.testprofile
new file mode 100644
index 0000000000..91727304ae
--- /dev/null
+++ b/java/test-profiles/default.testprofile
@@ -0,0 +1,39 @@
+java.naming.factory.initial=org.apache.qpid.jndi.PropertiesFileInitialContextFactory
+java.naming.provider.url=${test.profiles}/test-provider.properties
+
+broker.version=0-8
+broker=vm
+broker.clean=${test.profiles}/clean-dir ${build.data} ${project.root}/build/work/derbyDB
+broker.ready=Listening on TCP port
+broker.config=${project.root}/build/etc/config-systests.xml
+
+max_prefetch=1000
+
+log=debug
+amqj.logging.level=${log}
+amqj.server.logging.level=${log}
+amqj.protocol.logging.level=${log}
+root.logging.level=warn
+log4j.configuration=file:///${test.profiles}/log4j-test.xml
+log4j.debug=false
+
+# Note test-provider.properties also has variables of same name.
+# Keep in sync
+test.port=15672
+test.mport=18999
+#Note : Management will start open second port on: mport + 100 : 19099
+test.port.ssl=15671
+test.port.alt=25672
+test.port.alt.ssl=25671
+
+test.exclude=true
+profile.excludes=JavaTransientExcludes JavaInVMExcludes
+test.excludes=Excludes XAExcludes JavaExcludes ${profile}.excludes ${profile.excludes}
+test.fork=no
+test.mem=512M
+test=*Test
+haltonfailure=no
+haltonerror=no
+exclude.modules=none
+
+profile.clustered=false
diff --git a/java/test-profiles/java-derby.testprofile b/java/test-profiles/java-derby.testprofile
new file mode 100644
index 0000000000..689b2b4357
--- /dev/null
+++ b/java/test-profiles/java-derby.testprofile
@@ -0,0 +1,8 @@
+broker.language=java
+broker=${project.root}/build/bin/qpid-server -p @PORT -m @MPORT --exclude-0-10 @PORT -c @CONFIG_FILE -l ${test.profiles}/log4j-test.xml
+broker.clean=${test.profiles}/clean-dir ${build.data} ${project.root}/build/work/derbyDB
+broker.ready=BRK-1004
+broker.stopped=Exception
+broker.config=${project.root}/build/etc/config-systests-derby.xml
+qpid.amqp.version=0-9
+profile.excludes=JavaStandaloneExcludes
diff --git a/java/test-profiles/java.0.10.testprofile b/java/test-profiles/java.0.10.testprofile
new file mode 100644
index 0000000000..64c184c0f6
--- /dev/null
+++ b/java/test-profiles/java.0.10.testprofile
@@ -0,0 +1,8 @@
+broker.language=java
+broker.version=0-10
+broker=${project.root}/build/bin/qpid-server -p @PORT -m @MPORT -c @CONFIG_FILE -l ${test.profiles}/log4j-test.xml
+broker.clean=${test.profiles}/clean-dir ${build.data} ${project.root}/build/work/derbyDB
+broker.ready=BRK-1004
+broker.stopped=Exception
+
+profile.excludes=JavaTransientExcludes JavaStandaloneExcludes CPPExcludes CPPTransientExcludes
diff --git a/java/test-profiles/java.testprofile b/java/test-profiles/java.testprofile
new file mode 100644
index 0000000000..a301fb1b65
--- /dev/null
+++ b/java/test-profiles/java.testprofile
@@ -0,0 +1,7 @@
+broker.language=java
+broker=${project.root}/build/bin/qpid-server -p @PORT -m @MPORT --exclude-0-10 @PORT -c @CONFIG_FILE -l ${test.profiles}/log4j-test.xml
+broker.clean=${test.profiles}/clean-dir ${build.data} ${project.root}/build/work/derbyDB
+broker.ready=BRK-1004
+broker.stopped=Exception
+qpid.amqp.version=0-9
+profile.excludes=JavaTransientExcludes JavaStandaloneExcludes 08StandaloneExcludes
diff --git a/java/test-profiles/log4j-test.xml b/java/test-profiles/log4j-test.xml
new file mode 100644
index 0000000000..2d77942a81
--- /dev/null
+++ b/java/test-profiles/log4j-test.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+
+<!-- ===================================================================== -->
+<!-- -->
+<!-- Log4j configuration for unit tests -->
+<!-- -->
+<!-- ===================================================================== -->
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+ <appender name="console" class="org.apache.log4j.ConsoleAppender">
+ <param name="Target" value="System.out"/>
+ <param name="ImmediateFlush" value="true"/>
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%t %d %p [%c{4}] %m%n"/>
+ </layout>
+ </appender>
+
+ <logger name="org.apache.qpid">
+ <level value="${amqj.logging.level}"/>
+ </logger>
+
+ <logger name="qpid.protocol">
+ <level value="${amqj.protocol.logging.level}"/>
+ </logger>
+
+ <logger name="org.apache.qpid.test.utils.QpidTestCase">
+ <level value="ALL"/>
+ </logger>
+
+ <logger name="org.apache.commons">
+ <level value="WARN"/>
+ </logger>
+
+ <root>
+ <level value="${root.logging.level}"/>
+ <appender-ref ref="console" />
+ </root>
+</log4j:configuration>
diff --git a/java/test-profiles/test-provider.properties b/java/test-profiles/test-provider.properties
new file mode 100644
index 0000000000..8cea012c1d
--- /dev/null
+++ b/java/test-profiles/test-provider.properties
@@ -0,0 +1,51 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
+# Copied from default.testprofile
+test.port=15672
+test.mport=18999
+#Note : Java Management will start open second port on: mport + 100 : 19099
+test.port.ssl=15671
+test.port.alt=25672
+test.port.alt.ssl=25671
+
+
+connectionfactory.default = amqp://username:password@clientid/test?brokerlist='tcp://localhost:${test.port}'
+connectionfactory.default.ssl = amqp://username:password@clientid/test?brokerlist='tcp://localhost:${test.port.ssl}?ssl='true''
+connectionfactory.default.vm = amqp://username:password@clientid/test?brokerlist='vm://:1'
+
+connectionfactory.failover = amqp://username:password@clientid/test?brokerlist='tcp://localhost:${test.port.alt};tcp://localhost:${test.port}'&sync_ack='true'&sync_publish='all'&failover='roundrobin?cyclecount='20''
+connectionfactory.failover.ssl = amqp://username:password@clientid/test?brokerlist='tcp://localhost:${test.port.alt.ssl}?ssl='true';tcp://localhost:${test.port.ssl}?ssl='true''&sync_ack='true'&sync_publish='all'&failover='roundrobin?cyclecount='20''
+connectionfactory.failover.vm = amqp://username:password@clientid/test?brokerlist='vm://:2;vm://:1'&failover='roundrobin?cyclecount='20''
+
+connectionfactory.connection1 = amqp://username:password@clientid/test?brokerlist='tcp://localhost:${test.port}'
+connectionfactory.connection2 = amqp://username:password@clientid/test?brokerlist='tcp://localhost:${test.port.alt}'
+connectionfactory.connection1.vm = amqp://username:password@clientid/test?brokerlist='vm://:1'
+connectionfactory.connection2.vm = amqp://username:password@clientid/test?brokerlist='vm://:2'
+
+
+queue.MyQueue = example.MyQueue
+queue.queue = example.queue
+queue.xaQueue = xaQueue
+
+topic.topic = topic
+topic.xaTopic = xaTopic
+topic.durableSubscriberTopic = durableSubscriberTopic
diff --git a/java/test-profiles/test_resources/ssl/certstore.jks b/java/test-profiles/test_resources/ssl/certstore.jks
new file mode 100644
index 0000000000..57460491fe
--- /dev/null
+++ b/java/test-profiles/test_resources/ssl/certstore.jks
Binary files differ
diff --git a/java/test-profiles/test_resources/ssl/keystore.jks b/java/test-profiles/test_resources/ssl/keystore.jks
new file mode 100644
index 0000000000..8e033ec932
--- /dev/null
+++ b/java/test-profiles/test_resources/ssl/keystore.jks
Binary files differ
diff --git a/java/test-profiles/test_resources/ssl/pfile b/java/test-profiles/test_resources/ssl/pfile
new file mode 100644
index 0000000000..f3097ab130
--- /dev/null
+++ b/java/test-profiles/test_resources/ssl/pfile
@@ -0,0 +1 @@
+password
diff --git a/java/test-profiles/test_resources/ssl/server_db/cert8.db b/java/test-profiles/test_resources/ssl/server_db/cert8.db
new file mode 100644
index 0000000000..3063a1fef3
--- /dev/null
+++ b/java/test-profiles/test_resources/ssl/server_db/cert8.db
Binary files differ
diff --git a/java/test-profiles/test_resources/ssl/server_db/key3.db b/java/test-profiles/test_resources/ssl/server_db/key3.db
new file mode 100644
index 0000000000..be86b4af4b
--- /dev/null
+++ b/java/test-profiles/test_resources/ssl/server_db/key3.db
Binary files differ
diff --git a/java/test-profiles/test_resources/ssl/server_db/secmod.db b/java/test-profiles/test_resources/ssl/server_db/secmod.db
new file mode 100644
index 0000000000..9c71db0abe
--- /dev/null
+++ b/java/test-profiles/test_resources/ssl/server_db/secmod.db
Binary files differ
diff --git a/java/test-profiles/test_resources/ssl/server_db/server.crt b/java/test-profiles/test_resources/ssl/server_db/server.crt
new file mode 100644
index 0000000000..eb9323ff34
--- /dev/null
+++ b/java/test-profiles/test_resources/ssl/server_db/server.crt
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIBuDCCASGgAwIBAgIFAIzxXHYwDQYJKoZIhvcNAQEEBQAwETEPMA0GA1UEAxMG
+Um9vdENBMB4XDTA5MDQxNDIxNTUyOVoXDTEyMDQxNDIxNTUyOVowIDEeMBwGA1UE
+AxMVbG9jYWxob3N0LmxvY2FsZG9tYWluMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
+iQKBgQDNyXKaIcdDsBrcfsTRhIIsCGPCPKRuzN4w24PjfL72G7v0eyvKuposWDLf
+Os9T5ijaimYkbCyR+evnxFII/lOBFXGtzorTUnfVPvdIr8CEqjdTjJlCjT/rxjd0
+08kiMC9V4ohefnglA3UMBxm1st3IP6JzlUXlZqZdrfq1LLnLqQIDAQABow0wCzAJ
+BgNVHRMEAjAAMA0GCSqGSIb3DQEBBAUAA4GBAKkbAt9ockhmcfLGpyILfTUTqVqU
+Ys2VrOSDaJIxuQEouWNx9bIngKyBV23AvDbQ2Nb9QI8cuzu7laydO//obPrLpvH1
+MbOyd3j+JNNml9mDZw2rR8QpOvC9YDzBVcZgmw8QnHbTHYYdjUIGbXtWvG93gWTj
+QYVlvktPF1aM3RrM
+-----END CERTIFICATE-----
diff --git a/java/test-profiles/test_resources/ssl/server_db/server.req b/java/test-profiles/test_resources/ssl/server_db/server.req
new file mode 100644
index 0000000000..a5a3fb2e35
--- /dev/null
+++ b/java/test-profiles/test_resources/ssl/server_db/server.req
@@ -0,0 +1,20 @@
+
+Certificate request generated by Netscape certutil
+Phone: (not specified)
+
+Common Name: localhost.localdomain
+Email: (not specified)
+Organization: (not specified)
+State: (not specified)
+Country: (not specified)
+
+-----BEGIN NEW CERTIFICATE REQUEST-----
+MIIBXzCByQIBADAgMR4wHAYDVQQDExVsb2NhbGhvc3QubG9jYWxkb21haW4wgZ8w
+DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM3Jcpohx0OwGtx+xNGEgiwIY8I8pG7M
+3jDbg+N8vvYbu/R7K8q6mixYMt86z1PmKNqKZiRsLJH56+fEUgj+U4EVca3OitNS
+d9U+90ivwISqN1OMmUKNP+vGN3TTySIwL1XiiF5+eCUDdQwHGbWy3cg/onOVReVm
+pl2t+rUsucupAgMBAAGgADANBgkqhkiG9w0BAQQFAAOBgQCD9+h4+q7Snw4F5E4i
+oCu9SvUgTpMs6ClZUoaCJzjVmkygZwyq38iZV0W6I94MXZ9PFbvyiZkKy0t2oMNk
+J33NOmaHoKOylYBkVlhHjknyYbvcL0Uwoj0/fyRbSZdllhAHUJgrjMBwPKks8+UJ
+0crBkyRYg2gSCLQaPwJPm4ddpw==
+-----END NEW CERTIFICATE REQUEST-----
diff --git a/java/test-provider.properties b/java/test-provider.properties
deleted file mode 100644
index 6babe6b6c8..0000000000
--- a/java/test-provider.properties
+++ /dev/null
@@ -1,15 +0,0 @@
-connectionfactory.local = amqp://username:password@clientid/test?brokerlist='tcp://localhost:5672'
-connectionfactory.vm = amqp://username:password@clientid/test?brokerlist='vm://:1'
-
-connectionfactory.failover = amqp://username:password@clientid/test?brokerlist='tcp://localhost:5672'
-connectionfactory.vmfailover = amqp://username:password@clientid/test?brokerlist='vm://:2;vm://:1'
-connectionfactory.connection1 = amqp://username:password@clientid/test?brokerlist='vm://:1'
-connectionfactory.connection2 = amqp://username:password@clientid/test?brokerlist='vm://:2'
-
-
-queue.MyQueue = example.MyQueue
-queue.queue = example.queue
-queue.xaQueue = xaQueue
-
-topic.xaTopic = xaTopic
-topic.durableSubscriberTopic = durableSubscriberTopic
diff --git a/java/testkit/bin/perf_report.sh b/java/testkit/bin/perf_report.sh
deleted file mode 100644
index 9e574cad7a..0000000000
--- a/java/testkit/bin/perf_report.sh
+++ /dev/null
@@ -1,100 +0,0 @@
-#!/bin/sh
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-# This will run the 8 use cases defined below and produce
-# a report in tabular format. Refer to the documentation
-# for more details.
-
-SUB_MEM=-Xmx1024M
-PUB_MEM=-Xmx1024M
-LOG_CONFIG=-Dlog4j.configuration="$QPID_TEST_HOME/etc/test.log4j"
-
-. setenv.sh
-
-waitfor() { until grep -a -l "$2" $1 >/dev/null 2>&1 ; do sleep 1 ; done ; }
-cleanup()
-{
- pids=`ps aux | grep java | grep Perf | awk '{print $2}'`
- if [ "$pids" != "" ]; then
- kill -3 $pids
- kill -9 $pids >/dev/null 2>&1
- fi
-}
-
-# $1 test name
-# $2 consumer options
-# $3 producer options
-run_testcase()
-{
- sh run_sub.sh $LOG_CONFIG $SUB_MEM $2 > sub.out &
- waitfor sub.out "Warming up"
- sh run_pub.sh $LOG_CONFIG $PUB_MEM $3 > pub.out &
- waitfor sub.out "Completed the test"
- waitfor pub.out "Consumer has completed the test"
- sleep 2 #give a grace period to shutdown
- print_result $1
-}
-
-print_result()
-{
- prod_rate=`cat pub.out | grep "Producer rate" | awk '{print $3}'`
- sys_rate=`cat sub.out | grep "System Throughput" | awk '{print $4}'`
- cons_rate=`cat sub.out | grep "Consumer rate" | awk '{print $4}'`
- avg_latency=`cat sub.out | grep "Avg Latency" | awk '{print $4}'`
- min_latency=`cat sub.out | grep "Min Latency" | awk '{print $4}'`
- max_latency=`cat sub.out | grep "Max Latency" | awk '{print $4}'`
-
- printf "|%-15s|%15.2f|%13.2f|%13.2f|%11.2f|%11d|%11d|\n" $1 $sys_rate $prod_rate $cons_rate $avg_latency $min_latency $max_latency
- echo "------------------------------------------------------------------------------------------------"
-}
-
-trap cleanup EXIT
-
-echo "Test report on " `date +%F`
-echo "================================================================================================"
-echo "|Test |System throuput|Producer rate|Consumer Rate|Avg Latency|Min Latency|Max Latency|"
-echo "------------------------------------------------------------------------------------------------"
-
-# Test 1 Trans Queue
-run_testcase "Trans_Queue" "" "-Dwarmup_count=1 -Dmsg_count=10"
-
-# Test 2 Dura Queue
-run_testcase "Dura_Queue" "-Ddurable=true" "-Ddurable=true -Dwarmup_count=1 -Dmsg_count=10"
-
-# Test 3 Dura Queue Sync
-run_testcase "Dura_Queue_Sync" "-Ddurable=true" "-Ddurable=true -Dwarmup_count=1 -Dmsg_count=10 -Dsync_persistence=true"
-
-# Test 4 Topic
-run_testcase "Topic" "-DtransDest=transientTopic" "-DtransDest=transientTopic -Dwarmup_count=1 -Dmsg_count=10"
-
-# Test 5 Durable Topic
-#run_testcase "Dura_Topic" "-Ddurable=true -DtransDest=durableTopic" "-Ddurable=true -DtransDest=durableTopic -Dwarmup_count=1 -Dmsg_count=10"
-
-# Test 6 Fanout
-run_testcase "Fanout" "-DtransDest=fanoutQueue" "-DtransDest=fanoutQueue -Dwarmup_count=1 -Dmsg_count=10"
-
-# Test 7 Small TX
-run_testcase "Small_Txs_2" "-Ddurable=true -Dtransacted=true -Dtrans_size=1" \
- "-Ddurable=true -Dwarmup_count=1 -Dmsg_count=10 -Dtransacted=true -Dtrans_size=1"
-
-# Test 8 Large TX
-run_testcase "Large_Txs_1000" "-Ddurable=true -Dtransacted=true -Dtrans_size=10" \
- "-Ddurable=true -Dwarmup_count=1 -Dmsg_count=10 -Dtransacted=true -Dtrans_size=10"
-
diff --git a/java/testkit/bin/qpid-python-testkit b/java/testkit/bin/qpid-python-testkit
new file mode 100755
index 0000000000..2c1d015281
--- /dev/null
+++ b/java/testkit/bin/qpid-python-testkit
@@ -0,0 +1,30 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# This is wrapper script to run the tests defined in testkit.py
+# via the python test runner. The defaults are set for a running
+# from an svn checkout
+
+. ./setenv.sh
+
+export PYTHONPATH=../:$PYTHONPATH
+rm -rf $OUTDIR
+$PYTHON_DIR/qpid-python-test -DOUTDIR=$OUTDIR -m testkit "$@"
+
diff --git a/java/testkit/bin/setenv.sh b/java/testkit/bin/setenv.sh
index 24135e711b..71bb219dcf 100644
--- a/java/testkit/bin/setenv.sh
+++ b/java/testkit/bin/setenv.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
@@ -18,32 +17,62 @@
# under the License.
#
-# Compiles the test classes and sets the CLASSPATH
+# If QPIDD_EXEC ..etc is not set, it will first check to see
+# if this is run from a qpid svn check out, if not it will look
+# for installed rpms.
-# check for QPID_TEST_HOME
-if [ "$QPID_TEST_HOME" = "" ] ; then
- echo "ERROR: Please set QPID_TEST_HOME ...."
- exit 1
-fi
+abs_path()
+{
+ D=`dirname "$1"`
+ B=`basename "$1"`
+ echo "`cd \"$D\" 2>/dev/null && pwd || echo \"$D\"`/$B"
+}
-# check for JAVA_HOME
-if [ "$JAVA_HOME" = "" ] ; then
- echo "ERROR: Please set JAVA_HOME ...."
- exit 1
-fi
+# Environment for python tests
+
+if [ -d ../../../python ] ; then
+ PYTHON_DIR=../../../python
+ PYTHONPATH=$PYTHON_DIR:$PYTHON_DIR/qpid
+elif [ -z `echo $PYTHONPATH | awk '$0 ~ /qpid/'` ]; then
+ echo "WARNING: skipping test, no qpid python scripts found ."; exit 0;
+fi
-# VENDOR_LIB path needs to be set
-# for Qpid set this to {qpid_checkout}/java/build/lib
-if [ "$VENDOR_LIB" = "" ] ; then
- echo "ERROR: Please set VENDOR_LIB path in the script ...."
- exit 1
-fi
+if [ "$QPIDD_EXEC" = "" ] ; then
+ if [ -x ../../../cpp/src/qpidd ]; then
+ QPIDD_EXEC=`abs_path "../../../cpp/src/qpidd"`
+ elif [ -n "$(which qpidd)" ] ; then
+ QPIDD_EXEC=$(which qpidd)
+ else
+ echo "WARNING: skipping test, QPIDD_EXEC not set and qpidd not found."; exit 0;
+ fi
+fi
-[ -d $QPID_TEST_HOME/classes ] || mkdir $QPID_TEST_HOME/classes
+if [ "$CLUSTER_LIB" = "" ] ; then
+ if [ -x ../../../cpp/src/.libs/cluster.so ]; then
+ CLUSTER_LIB=`abs_path "../../../cpp/src/.libs/cluster.so"`
+ elif [ -e /usr/lib64/qpid/daemon/cluster.so ] ; then
+ CLUSTER_LIB="/usr/lib64/qpid/daemon/cluster.so"
+ elif [ -e /usr/lib/qpid/daemon/cluster.so ] ; then
+ CLUSTER_LIB="/usr/lib/qpid/daemon/cluster.so"
+ else
+ echo "WARNING: skipping test, CLUSTER_LIB not set and cluster.so not found."; exit 0;
+ fi
+fi
-CLASSPATH=`find $VENDOR_LIB -name *.jar* | tr '\n' ":"`
-$JAVA_HOME/bin/javac -cp $CLASSPATH -d $QPID_TEST_HOME/classes -sourcepath $QPID_TEST_HOME/src `find $QPID_TEST_HOME/src -name '*.java'`
+if [ "$QP_CP" = "" ] ; then
+ if [ -d ../../build/lib/ ]; then
+ QP_JAR_PATH=`abs_path "../../build/lib/"`
+ elif [ -d /usr/share/java/qpid-deps ]; then
+ QP_JAR_PATH=`abs_path "/usr/share/java"`
+ else
+ "WARNING: skipping test, QP_CP not set and the Qpid jars are not present."; exit 0;
+ fi
+ QP_CP=`find $QP_JAR_PATH -name '*.jar' | tr '\n' ':'`
+fi
-export CLASSPATH=$QPID_TEST_HOME/classes:$CLASSPATH
+if [ "$OUTDIR" = "" ] ; then
+ OUTDIR=`abs_path "../output"`
+fi
+export PYTHONPATH PYTHON_DIR QPIDD_EXEC CLUSTER_LIB QP_CP OUTDIR
diff --git a/java/testkit/build.xml b/java/testkit/build.xml
index 94b97d270d..80a3373379 100644
--- a/java/testkit/build.xml
+++ b/java/testkit/build.xml
@@ -20,7 +20,7 @@
-->
<project name="Test Kit" default="build">
- <property name="module.depends" value="client broker common"/>
+ <property name="module.depends" value="client common tools"/>
<import file="../module.xml"/>
diff --git a/java/testkit/etc/jndi.properties b/java/testkit/etc/jndi.properties
index f535975844..7a8180477b 100644
--- a/java/testkit/etc/jndi.properties
+++ b/java/testkit/etc/jndi.properties
@@ -26,10 +26,10 @@ java.naming.factory.initial = org.apache.qpid.jndi.PropertiesFileInitialContextF
connectionfactory.connectionFactory = amqp://guest:guest@clientid/testpath?brokerlist='tcp://localhost:5672'
# Register an AMQP destination in JNDI
-destination.transientQueue = direct://amq.direct//testQueueT
-destination.durableQueue = direct://amq.direct//testQueueD?durable='true'
+destination.transientQueue = direct://amq.direct//testQueueT?autodelete='true'
+destination.durableQueue = direct://amq.direct//testQueueD?durable='true'&autodelete='true'
-destination.transientTopic = topic://amq.topic//testTopicT
-#destination.durableTopic = topic://amq.topic//testTopicD?durable='true'
+destination.transientTopic = topic://amq.topic//testTopicT?autodelete='true'
+destination.durableTopic = topic://amq.topic//testTopicD?durable='true'&autodelete='true'&clientid='test'&subscription='testQueueD'
-destination.fanoutQueue = fanout://amq.fanout//fanoutQueue \ No newline at end of file
+destination.fanoutQueue = fanout://amq.fanout//fanoutQueue?autodelete='true'
diff --git a/java/testkit/src/main/java/org/apache/qpid/testkit/Client.java b/java/testkit/src/main/java/org/apache/qpid/testkit/Client.java
new file mode 100644
index 0000000000..88d78ee78c
--- /dev/null
+++ b/java/testkit/src/main/java/org/apache/qpid/testkit/Client.java
@@ -0,0 +1,90 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.testkit;
+
+
+import java.text.DateFormat;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.text.SimpleDateFormat;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.Session;
+
+public abstract class Client
+{
+ protected Connection con;
+ protected Session ssn;
+ protected boolean durable = false;
+ protected boolean transacted = false;
+ protected int txSize = 10;
+ protected int ack_mode = Session.AUTO_ACKNOWLEDGE;
+ protected String contentType = "application/octet-stream";
+ protected Destination dest = null;
+
+ protected long reportFrequency = 60000; // every min
+ protected DateFormat df = new SimpleDateFormat("yyyy.MM.dd 'at' HH:mm:ss");
+ protected NumberFormat nf = new DecimalFormat("##.00");
+
+ protected long startTime = System.currentTimeMillis();
+ protected ErrorHandler errorHandler = null;
+
+ public Client(Connection con) throws Exception
+ {
+ this.con = con;
+ durable = Boolean.getBoolean("durable");
+ transacted = Boolean.getBoolean("transacted");
+ txSize = Integer.getInteger("tx_size",10);
+ contentType = System.getProperty("content_type","application/octet-stream");
+ reportFrequency = Long.getLong("report_frequency", 60000);
+ }
+
+ public void close()
+ {
+ try
+ {
+ con.close();
+ }
+ catch (Exception e)
+ {
+ handleError("Error closing connection",e);
+ }
+ }
+
+ public void setErrorHandler(ErrorHandler h)
+ {
+ this.errorHandler = h;
+ }
+
+ public void handleError(String msg,Exception e)
+ {
+ if (errorHandler != null)
+ {
+ errorHandler.handleError(msg, e);
+ }
+ else
+ {
+ System.err.println(msg);
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/java/testkit/src/main/java/org/apache/qpid/testkit/ErrorHandler.java b/java/testkit/src/main/java/org/apache/qpid/testkit/ErrorHandler.java
new file mode 100644
index 0000000000..a1add8e03f
--- /dev/null
+++ b/java/testkit/src/main/java/org/apache/qpid/testkit/ErrorHandler.java
@@ -0,0 +1,6 @@
+package org.apache.qpid.testkit;
+
+public interface ErrorHandler {
+
+ public void handleError(String msg,Exception e);
+}
diff --git a/java/testkit/src/main/java/org/apache/qpid/testkit/MessageFactory.java b/java/testkit/src/main/java/org/apache/qpid/testkit/MessageFactory.java
deleted file mode 100644
index f2784ef499..0000000000
--- a/java/testkit/src/main/java/org/apache/qpid/testkit/MessageFactory.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package org.apache.qpid.testkit;
-
-import javax.jms.BytesMessage;
-import javax.jms.JMSException;
-import javax.jms.Message;
-import javax.jms.Session;
-import javax.jms.TextMessage;
-
-public class MessageFactory
-{
- public static Message createBytesMessage(Session ssn, int size) throws JMSException
- {
- BytesMessage msg = ssn.createBytesMessage();
- msg.writeBytes(createMessagePayload(size).getBytes());
- return msg;
- }
-
- public static Message createTextMessage(Session ssn, int size) throws JMSException
- {
- TextMessage msg = ssn.createTextMessage();
- msg.setText(createMessagePayload(size));
- return msg;
- }
-
- public static String createMessagePayload(int size)
- {
- String msgData = "Qpid Test Message";
-
- StringBuffer buf = new StringBuffer(size);
- int count = 0;
- while (count <= (size - msgData.length()))
- {
- buf.append(msgData);
- count += msgData.length();
- }
- if (count < size)
- {
- buf.append(msgData, 0, size - count);
- }
-
- return buf.toString();
- }
-}
diff --git a/java/testkit/src/main/java/org/apache/qpid/testkit/Receiver.java b/java/testkit/src/main/java/org/apache/qpid/testkit/Receiver.java
new file mode 100644
index 0000000000..19ae325d4b
--- /dev/null
+++ b/java/testkit/src/main/java/org/apache/qpid/testkit/Receiver.java
@@ -0,0 +1,225 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.testkit;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.TextMessage;
+
+import org.apache.qpid.client.AMQConnection;
+
+/**
+ * A generic receiver which consumers a stream of messages
+ * from a given address in a broker (host/port)
+ * until told to stop by killing it.
+ *
+ * It participates in a feedback loop to ensure the producer
+ * doesn't fill up the queue. If it receives an "End" msg
+ * it sends a reply to the replyTo address in that msg.
+ *
+ * It doesn't check for correctness or measure anything
+ * leaving those concerns to another entity.
+ * However it prints a timestamp every x secs(-Dreport_frequency)
+ * as checkpoint to figure out how far the test has progressed if
+ * a failure occurred.
+ *
+ * It also takes in an optional Error handler to
+ * pass out any error in addition to writing them to std err.
+ *
+ * This is intended more as building block to create
+ * more complex test cases. However there is a main method
+ * provided to use this standalone.
+ *
+ * The following options are available and configurable
+ * via jvm args.
+ *
+ * sync_rcv - Whether to consume sync (instead of using a listener).
+ * report_frequency - how often a timestamp is printed
+ * durable
+ * transacted
+ * tx_size - size of transaction batch in # msgs.
+ */
+public class Receiver extends Client implements MessageListener
+{
+ // Until addressing is properly supported.
+ protected enum Reliability {
+ AT_MOST_ONCE, AT_LEAST_ONCE, EXACTLY_ONCE;
+
+ Reliability getReliability(String s)
+ {
+ if (s.equalsIgnoreCase("at_most_once"))
+ {
+ return AT_MOST_ONCE;
+ }
+ else if (s.equalsIgnoreCase("at_least_once"))
+ {
+ return AT_LEAST_ONCE;
+ }
+ else
+ {
+ return EXACTLY_ONCE;
+ }
+ }
+ };
+
+ long msg_count = 0;
+ int sequence = 0;
+ boolean sync_rcv = Boolean.getBoolean("sync_rcv");
+ boolean uniqueDests = Boolean.getBoolean("unique_dests");
+ Reliability reliability = Reliability.EXACTLY_ONCE;
+ MessageConsumer consumer;
+ List<Integer> duplicateMessages = new ArrayList<Integer>();
+
+ public Receiver(Connection con,Destination dest) throws Exception
+ {
+ super(con);
+ reliability = reliability.getReliability(System.getProperty("reliability","exactly_once"));
+ ssn = con.createSession(transacted,ack_mode);
+ consumer = ssn.createConsumer(dest);
+ if (!sync_rcv)
+ {
+ consumer.setMessageListener(this);
+ }
+
+ System.out.println("Operating in mode : " + reliability);
+ System.out.println("Receiving messages from : " + dest);
+ }
+
+ public void onMessage(Message msg)
+ {
+ handleMessage(msg);
+ }
+
+ public void run() throws Exception
+ {
+ while(true)
+ {
+ if(sync_rcv)
+ {
+ Message msg = consumer.receive();
+ handleMessage(msg);
+ }
+ Thread.sleep(reportFrequency);
+ System.out.println(df.format(System.currentTimeMillis())
+ + " - messages received : " + msg_count);
+ }
+ }
+
+ private void handleMessage(Message m)
+ {
+ try
+ {
+ if (m instanceof TextMessage && ((TextMessage) m).getText().equals("End"))
+ {
+ MessageProducer temp = ssn.createProducer(m.getJMSReplyTo());
+ Message controlMsg = ssn.createTextMessage();
+ temp.send(controlMsg);
+ if (transacted)
+ {
+ ssn.commit();
+ }
+ temp.close();
+ }
+ else
+ {
+
+ int seq = m.getIntProperty("sequence");
+ if (uniqueDests)
+ {
+ if (seq == 0)
+ {
+ sequence = 0; // wrap around for each iteration
+ }
+
+ if (seq < sequence)
+ {
+ duplicateMessages.add(seq);
+ if (reliability == Reliability.EXACTLY_ONCE)
+ {
+ throw new Exception(": Received a duplicate message (expected="
+ + sequence + ",received=" + seq + ")" );
+ }
+ }
+ else if (seq == sequence)
+ {
+ sequence++;
+ msg_count ++;
+ }
+ else
+ {
+ // Multiple publishers are not allowed in this test case.
+ // So out of order messages are not allowed.
+ throw new Exception(": Received an out of order message (expected="
+ + sequence + ",received=" + seq + ")" );
+ }
+ }
+ // Please note that this test case doesn't expect duplicates
+ // When testing for transactions.
+ if (transacted && msg_count % txSize == 0)
+ {
+ ssn.commit();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ handleError("Exception receiving messages",e);
+ }
+ }
+
+ // Receiver host port address
+ public static void main(String[] args) throws Exception
+ {
+ String host = "127.0.0.1";
+ int port = 5672;
+
+ if (args.length > 0)
+ {
+ host = args[0];
+ }
+ if (args.length > 1)
+ {
+ port = Integer.parseInt(args[1]);
+ }
+ // #3rd argument should be an address
+ // Any other properties is best configured via jvm args
+
+ AMQConnection con = new AMQConnection(
+ "amqp://username:password@topicClientid/test?brokerlist='tcp://"
+ + host + ":" + port + "'");
+
+ // FIXME Need to add support for the new address format
+ // Then it's trivial to add destination for that.
+ Receiver rcv = new Receiver(con,null);
+ rcv.run();
+ }
+
+}
diff --git a/java/testkit/src/main/java/org/apache/qpid/testkit/Sender.java b/java/testkit/src/main/java/org/apache/qpid/testkit/Sender.java
new file mode 100644
index 0000000000..4dbe278e33
--- /dev/null
+++ b/java/testkit/src/main/java/org/apache/qpid/testkit/Sender.java
@@ -0,0 +1,195 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.testkit;
+
+
+import java.text.DateFormat;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.text.SimpleDateFormat;
+import java.util.Random;
+
+import javax.jms.Connection;
+import javax.jms.DeliveryMode;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.tools.MessageFactory;
+
+/**
+ * A generic sender which sends a stream of messages
+ * to a given address in a broker (host/port)
+ * until told to stop by killing it.
+ *
+ * It has a feedback loop to ensure it doesn't fill
+ * up queues due to a slow consumer.
+ *
+ * It doesn't check for correctness or measure anything
+ * leaving those concerns to another entity.
+ * However it prints a timestamp every x secs(-Dreport_frequency)
+ * as checkpoint to figure out how far the test has progressed if
+ * a failure occurred.
+ *
+ * It also takes in an optional Error handler to
+ * pass out any error in addition to writing them to std err.
+ *
+ * This is intended more as building block to create
+ * more complex test cases. However there is a main method
+ * provided to use this standalone.
+ *
+ * The following options are available and configurable
+ * via jvm args.
+ *
+ * msg_size (256)
+ * msg_count (10) - # messages before waiting for feedback
+ * sleep_time (1000 ms) - sleep time btw each iteration
+ * report_frequency - how often a timestamp is printed
+ * durable
+ * transacted
+ * tx_size - size of transaction batch in # msgs.
+ */
+public class Sender extends Client
+{
+ protected int msg_size = 256;
+ protected int msg_count = 10;
+ protected int iterations = -1;
+ protected long sleep_time = 1000;
+
+ protected Destination dest = null;
+ protected Destination replyTo = null;
+ protected DateFormat df = new SimpleDateFormat("yyyy.MM.dd 'at' HH:mm:ss");
+ protected NumberFormat nf = new DecimalFormat("##.00");
+
+ protected MessageProducer producer;
+ Random gen = new Random(19770905);
+
+ public Sender(Connection con,Destination dest) throws Exception
+ {
+ super(con);
+ this.msg_size = Integer.getInteger("msg_size", 100);
+ this.msg_count = Integer.getInteger("msg_count", 10);
+ this.iterations = Integer.getInteger("iterations", -1);
+ this.sleep_time = Long.getLong("sleep_time", 1000);
+ this.ssn = con.createSession(transacted,Session.AUTO_ACKNOWLEDGE);
+ this.dest = dest;
+ this.producer = ssn.createProducer(dest);
+ this.replyTo = ssn.createTemporaryQueue();
+
+ System.out.println("Sending messages to : " + dest);
+ }
+
+ /*
+ * If msg_size not specified it generates a message
+ * between 500-1500 bytes.
+ */
+ protected Message getNextMessage() throws Exception
+ {
+ int s = msg_size == -1 ? 500 + gen.nextInt(1000) : msg_size;
+ Message msg = (contentType.equals("text/plain")) ?
+ MessageFactory.createTextMessage(ssn, s):
+ MessageFactory.createBytesMessage(ssn, s);
+
+ msg.setJMSDeliveryMode((durable) ? DeliveryMode.PERSISTENT
+ : DeliveryMode.NON_PERSISTENT);
+ return msg;
+ }
+
+ public void run()
+ {
+ try
+ {
+ boolean infinite = (iterations == -1);
+ for (int x=0; infinite || x < iterations; x++)
+ {
+ long now = System.currentTimeMillis();
+ if (now - startTime >= reportFrequency)
+ {
+ System.out.println(df.format(now) + " - iterations : " + x);
+ startTime = now;
+ }
+
+ for (int i = 0; i < msg_count; i++)
+ {
+ Message msg = getNextMessage();
+ msg.setIntProperty("sequence",i);
+ producer.send(msg);
+ if (transacted && msg_count % txSize == 0)
+ {
+ ssn.commit();
+ }
+ }
+ TextMessage m = ssn.createTextMessage("End");
+ m.setJMSReplyTo(replyTo);
+ producer.send(m);
+
+ if (transacted)
+ {
+ ssn.commit();
+ }
+
+ MessageConsumer feedbackConsumer = ssn.createConsumer(replyTo);
+ feedbackConsumer.receive();
+ feedbackConsumer.close();
+ if (transacted)
+ {
+ ssn.commit();
+ }
+ Thread.sleep(sleep_time);
+ }
+ }
+ catch (Exception e)
+ {
+ handleError("Exception sending messages",e);
+ }
+ }
+
+ // Receiver host port address
+ public static void main(String[] args) throws Exception
+ {
+ String host = "127.0.0.1";
+ int port = 5672;
+
+ if (args.length > 0)
+ {
+ host = args[0];
+ }
+ if (args.length > 1)
+ {
+ port = Integer.parseInt(args[1]);
+ }
+ // #3rd argument should be an address
+ // Any other properties is best configured via jvm args
+
+ AMQConnection con = new AMQConnection(
+ "amqp://username:password@topicClientid/test?brokerlist='tcp://"
+ + host + ":" + port + "'");
+
+ // FIXME Need to add support for the new address format
+ // Then it's trivial to add destination for that.
+ Sender sender = new Sender(con,null);
+ sender.run();
+ }
+}
diff --git a/java/testkit/src/main/java/org/apache/qpid/testkit/TestLauncher.java b/java/testkit/src/main/java/org/apache/qpid/testkit/TestLauncher.java
new file mode 100644
index 0000000000..b55afa7066
--- /dev/null
+++ b/java/testkit/src/main/java/org/apache/qpid/testkit/TestLauncher.java
@@ -0,0 +1,384 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.testkit;
+
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.text.DateFormat;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import org.apache.log4j.BasicConfigurator;
+import org.apache.log4j.ConsoleAppender;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.log4j.PatternLayout;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.thread.Threading;
+
+/**
+ * A basic test case class that could launch a Sender/Receiver
+ * or both, each on it's own separate thread.
+ *
+ * If con_count == ssn_count, then each entity created will have
+ * it's own Connection. Else if con_count < ssn_count, then
+ * a connection will be shared by ssn_count/con_count # of entities.
+ *
+ * The if both sender and receiver options are set, it will
+ * share a connection.
+ *
+ * The following options are available as jvm args
+ * host, port
+ * con_count,ssn_count
+ * con_idle_time - which determines heartbeat
+ * sender, receiver - booleans which indicate which entity to create.
+ * Setting them both is also a valid option.
+ */
+public class TestLauncher implements ErrorHandler
+{
+ protected String host = "127.0.0.1";
+ protected int port = 5672;
+ protected int session_count = 1;
+ protected int connection_count = 1;
+ protected long connection_idle_time = 5000;
+ protected boolean sender = false;
+ protected boolean receiver = false;
+ protected String url;
+
+ protected String queue_name = "message_queue";
+ protected String exchange_name = "amq.direct";
+ protected String routing_key = "routing_key";
+ protected boolean uniqueDests = false;
+ protected boolean durable = false;
+ protected String failover = "";
+ protected AMQConnection controlCon;
+ protected Destination controlDest = null;
+ protected Session controlSession = null;
+ protected MessageProducer statusSender;
+ protected List<AMQConnection> clients = new ArrayList<AMQConnection>();
+ protected DateFormat df = new SimpleDateFormat("yyyy.MM.dd 'at' HH:mm:ss");
+ protected NumberFormat nf = new DecimalFormat("##.00");
+ protected String testName;
+
+ public TestLauncher()
+ {
+ testName = System.getProperty("test_name","UNKNOWN");
+ host = System.getProperty("host", "127.0.0.1");
+ port = Integer.getInteger("port", 5672);
+ session_count = Integer.getInteger("ssn_count", 1);
+ connection_count = Integer.getInteger("con_count", 1);
+ connection_idle_time = Long.getLong("con_idle_time", 5000);
+ sender = Boolean.getBoolean("sender");
+ receiver = Boolean.getBoolean("receiver");
+
+ queue_name = System.getProperty("queue_name", "message_queue");
+ exchange_name = System.getProperty("exchange_name", "amq.direct");
+ routing_key = System.getProperty("routing_key", "routing_key");
+ failover = System.getProperty("failover", "");
+ uniqueDests = Boolean.getBoolean("unique_dests");
+ durable = Boolean.getBoolean("durable");
+
+ url = "amqp://username:password@topicClientid/test?brokerlist='tcp://"
+ + host + ":" + port + "?idle_timeout=" + connection_idle_time
+ + "'";
+
+ if (failover.equalsIgnoreCase("failover_exchange"))
+ {
+ url += "&failover='failover_exchange'";
+
+ System.out.println("Failover exchange " + url );
+ }
+
+ configureLogging();
+ }
+
+ protected void configureLogging()
+ {
+ PatternLayout layout = new PatternLayout();
+ layout.setConversionPattern("%t %d %p [%c{4}] %m%n");
+ BasicConfigurator.configure(new ConsoleAppender(layout));
+
+ String logLevel = System.getProperty("log.level","warn");
+ String logComponent = System.getProperty("log.comp","org.apache.qpid");
+
+ Logger logger = Logger.getLogger(logComponent);
+ logger.setLevel(Level.toLevel(logLevel, Level.WARN));
+
+ System.out.println("Level " + logger.getLevel());
+
+ }
+
+ public void setUpControlChannel()
+ {
+ try
+ {
+ controlCon = new AMQConnection(url);
+ controlCon.start();
+
+ controlDest = new AMQQueue(new AMQShortString(""),
+ new AMQShortString("control"),
+ new AMQShortString("control"),
+ false, //exclusive
+ false, //auto-delete
+ false); // durable
+
+ // Create the session to setup the messages
+ controlSession = controlCon.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ statusSender = controlSession.createProducer(controlDest);
+
+ }
+ catch (Exception e)
+ {
+ handleError("Error while setting up the test",e);
+ }
+ }
+
+ public void cleanup()
+ {
+ try
+ {
+ controlSession.close();
+ controlCon.close();
+ for (AMQConnection con : clients)
+ {
+ con.close();
+ }
+ }
+ catch (Exception e)
+ {
+ handleError("Error while tearing down the test",e);
+ }
+ }
+
+ public void start()
+ {
+ try
+ {
+
+ int ssn_per_con = session_count;
+ if (connection_count < session_count)
+ {
+ ssn_per_con = session_count/connection_count;
+ }
+
+ for (int i = 0; i< connection_count; i++)
+ {
+ AMQConnection con = new AMQConnection(url);
+ con.start();
+ clients.add(con);
+ for (int j = 0; j< ssn_per_con; j++)
+ {
+ String prefix = createPrefix(i,j);
+ Destination dest = createDest(prefix);
+ if (sender)
+ {
+ createSender(prefix,con,dest,this);
+ }
+
+ if (receiver)
+ {
+ createReceiver(prefix,con,dest,this);
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ handleError("Exception while setting up the test",e);
+ }
+
+ }
+
+ protected void createReceiver(String index,final AMQConnection con, final Destination dest, final ErrorHandler h)
+ {
+ Runnable r = new Runnable()
+ {
+ public void run()
+ {
+ try
+ {
+ Receiver rcv = new Receiver(con,dest);
+ rcv.setErrorHandler(h);
+ rcv.run();
+ }
+ catch (Exception e)
+ {
+ h.handleError("Error Starting Receiver", e);
+ }
+ }
+ };
+
+ Thread t = null;
+ try
+ {
+ t = Threading.getThreadFactory().createThread(r);
+ }
+ catch(Exception e)
+ {
+ handleError("Error creating Receive thread",e);
+ }
+
+ t.setName("ReceiverThread-" + index);
+ t.start();
+ }
+
+ protected void createSender(String index,final AMQConnection con, final Destination dest, final ErrorHandler h)
+ {
+ Runnable r = new Runnable()
+ {
+ public void run()
+ {
+ try
+ {
+ Sender sender = new Sender(con, dest);
+ sender.setErrorHandler(h);
+ sender.run();
+ }
+ catch (Exception e)
+ {
+ h.handleError("Error Starting Sender", e);
+ }
+ }
+ };
+
+ Thread t = null;
+ try
+ {
+ t = Threading.getThreadFactory().createThread(r);
+ }
+ catch(Exception e)
+ {
+ handleError("Error creating Sender thread",e);
+ }
+
+ t.setName("SenderThread-" + index);
+ t.start();
+ }
+
+ public void handleError(String msg,Exception e)
+ {
+ // In case sending the message fails
+ StringBuilder sb = new StringBuilder();
+ sb.append(msg);
+ sb.append(" @ ");
+ sb.append(df.format(new Date(System.currentTimeMillis())));
+ sb.append(" ");
+ sb.append(e.getMessage());
+ System.err.println(sb.toString());
+ e.printStackTrace();
+
+ try
+ {
+ TextMessage errorMsg = controlSession.createTextMessage();
+ errorMsg.setStringProperty("status", "error");
+ errorMsg.setStringProperty("desc", msg);
+ errorMsg.setStringProperty("time", df.format(new Date(System.currentTimeMillis())));
+ errorMsg.setStringProperty("exception-trace", serializeStackTrace(e));
+ synchronized (this)
+ {
+ statusSender.send(errorMsg);
+ }
+ } catch (JMSException e1) {
+ e1.printStackTrace();
+ }
+ }
+
+ private String serializeStackTrace(Exception e)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ PrintStream printStream = new PrintStream(bOut);
+ e.printStackTrace(printStream);
+ printStream.close();
+ return bOut.toString();
+ }
+
+ private String createPrefix(int i, int j)
+ {
+ return String.valueOf(i).concat(String.valueOf(j));
+ }
+
+ /**
+ * The following are supported.
+ *
+ * 1. A producer/consumer pair on a topic or a queue
+ * 2. A single producer with multiple consumers on topic/queue
+ *
+ * Multiple consumers on a topic will result in a private queue
+ * for each consumers.
+ *
+ * We want to avoid multiple producers on the same topic/queue
+ * as the queues will fill up in no time.
+ */
+ private Destination createDest(String prefix)
+ {
+ Destination dest = null;
+ if (exchange_name.equals("amq.topic"))
+ {
+ dest = new AMQTopic(
+ new AMQShortString(exchange_name),
+ new AMQShortString(uniqueDests ? prefix + routing_key :
+ routing_key),
+ false, //auto-delete
+ null, //queue name
+ durable);
+ }
+ else
+ {
+ dest = new AMQQueue(
+ new AMQShortString(exchange_name),
+ new AMQShortString(uniqueDests ? prefix + routing_key :
+ routing_key),
+ new AMQShortString(uniqueDests ? prefix + queue_name :
+ queue_name),
+ false, //exclusive
+ false, //auto-delete
+ durable);
+ }
+ return dest;
+ }
+
+ public static void main(String[] args)
+ {
+ final TestLauncher test = new TestLauncher();
+ test.setUpControlChannel();
+ test.start();
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ public void run() { test.cleanup(); }
+ });
+
+ }
+}
diff --git a/java/testkit/src/main/java/org/apache/qpid/testkit/perf/PerfBase.java b/java/testkit/src/main/java/org/apache/qpid/testkit/perf/PerfBase.java
deleted file mode 100644
index 95670f0507..0000000000
--- a/java/testkit/src/main/java/org/apache/qpid/testkit/perf/PerfBase.java
+++ /dev/null
@@ -1,102 +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.
- *
- */
-package org.apache.qpid.testkit.perf;
-
-import java.text.DecimalFormat;
-import java.util.Hashtable;
-
-import javax.jms.Connection;
-import javax.jms.ConnectionFactory;
-import javax.jms.Destination;
-import javax.jms.Session;
-import javax.naming.Context;
-import javax.naming.InitialContext;
-
-public class PerfBase
-{
- TestParams params;
- Connection con;
- Session session;
- Destination dest;
- Destination feedbackDest;
- DecimalFormat df = new DecimalFormat("###.##");
-
- public PerfBase()
- {
- params = new TestParams();
- }
-
- public void setUp() throws Exception
- {
- Hashtable<String,String> env = new Hashtable<String,String>();
- env.put(Context.INITIAL_CONTEXT_FACTORY, params.getInitialContextFactory());
- env.put(Context.PROVIDER_URL, params.getProviderURL());
-
- Context ctx = null;
- try
- {
- ctx = new InitialContext(env);
- }
- catch(Exception e)
- {
- throw new Exception("Error initializing JNDI",e);
-
- }
-
- ConnectionFactory conFac = null;
- try
- {
- conFac = (ConnectionFactory)ctx.lookup(params.getConnectionFactory());
- }
- catch(Exception e)
- {
- throw new Exception("Error looking up connection factory",e);
- }
-
- con = conFac.createConnection();
- con.start();
- session = con.createSession(params.isTransacted(),
- params.isTransacted()? Session.SESSION_TRANSACTED:params.getAckMode());
-
- try
- {
- dest = (Destination)ctx.lookup( params.isDurable()?
- params.getDurableDestination():
- params.getTransientDestination()
- );
- }
- catch(Exception e)
- {
- throw new Exception("Error looking up destination",e);
- }
- }
-
- public void handleError(Exception e,String msg)
- {
- StringBuilder sb = new StringBuilder();
- sb.append(msg);
- sb.append(" ");
- sb.append(e.getMessage());
- System.err.println(sb.toString());
- e.printStackTrace();
- }
-}
-
diff --git a/java/testkit/src/main/java/org/apache/qpid/testkit/perf/PerfConsumer.java b/java/testkit/src/main/java/org/apache/qpid/testkit/perf/PerfConsumer.java
deleted file mode 100644
index cd12c7010d..0000000000
--- a/java/testkit/src/main/java/org/apache/qpid/testkit/perf/PerfConsumer.java
+++ /dev/null
@@ -1,248 +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.
- *
- */
-package org.apache.qpid.testkit.perf;
-
-import javax.jms.Destination;
-import javax.jms.Message;
-import javax.jms.MessageConsumer;
-import javax.jms.MessageListener;
-import javax.jms.MessageProducer;
-import javax.jms.TextMessage;
-
-/**
- * PerfConsumer will receive x no of messages in warmup mode.
- * Once it receives the Start message it will then signal the PerfProducer.
- * It will start recording stats from the first message it receives after
- * the warmup mode is done.
- *
- * The following calculations are done.
- * The important numbers to look at is
- * a) Avg Latency
- * b) System throughput.
- *
- * Latency.
- * =========
- * Currently this test is written with the assumption that either
- * a) The Perf Producer and Consumer are on the same machine
- * b) They are on separate machines that have their time synced via a Time Server
- *
- * In order to calculate latency the producer inserts a timestamp
- * hen the message is sent. The consumer will note the current time the message is
- * received and will calculate the latency as follows
- * latency = rcvdTime - msg.getJMSTimestamp()
- *
- * Through out the test it will keep track of the max and min latency to show the
- * variance in latencies.
- *
- * Avg latency is measured by adding all latencies and dividing by the total msgs.
- * You can also compute this by (rcvdTime - testStartTime)/rcvdMsgCount
- *
- * Throughput
- * ===========
- * System throughput is calculated as follows
- * rcvdMsgCount/(rcvdTime - testStartTime)
- *
- * Consumer rate is calculated as
- * rcvdMsgCount/(rcvdTime - startTime)
- *
- * Note that the testStartTime referes to when the producer sent the first message
- * and startTime is when the consumer first received a message.
- *
- * rcvdTime keeps track of when the last message is received.
- *
- * All throughput rates are given as msg/sec so the rates are multiplied by 1000.
- *
- */
-
-public class PerfConsumer extends PerfBase implements MessageListener
-{
- MessageConsumer consumer;
- long maxLatency = 0;
- long minLatency = Long.MAX_VALUE;
- long totalLatency = 0; // to calculate avg latency.
- int rcvdMsgCount = 0;
- long testStartTime = 0; // to measure system throughput
- long startTime = 0; // to measure consumer throughput
- long rcvdTime = 0;
- boolean transacted = false;
- int transSize = 0;
-
- final Object lock = new Object();
-
- public PerfConsumer()
- {
- super();
- }
-
- public void setUp() throws Exception
- {
- super.setUp();
- consumer = session.createConsumer(dest);
-
- // Storing the following two for efficiency
- transacted = params.isTransacted();
- transSize = params.getTransactionSize();
- }
-
- public void warmup()throws Exception
- {
- System.out.println("Warming up......");
-
- boolean start = false;
- while (!start)
- {
- Message msg = consumer.receive();
- if (msg instanceof TextMessage)
- {
- if (((TextMessage)msg).getText().equals("End"))
- {
- start = true;
- MessageProducer temp = session.createProducer(msg.getJMSReplyTo());
- temp.send(session.createMessage());
- if (params.isTransacted())
- {
- session.commit();
- }
- temp.close();
- }
- }
- }
- }
-
- public void startTest() throws Exception
- {
- System.out.println("Starting test......");
- consumer.setMessageListener(this);
- }
-
- public void printResults() throws Exception
- {
- synchronized (lock)
- {
- lock.wait();
- }
-
- double avgLatency = (double)totalLatency/(double)rcvdMsgCount;
- double throughput = ((double)rcvdMsgCount/(double)(rcvdTime - testStartTime))*1000;
- double consRate = ((double)rcvdMsgCount/(double)(rcvdTime - startTime))*1000;
- System.out.println(new StringBuilder("Total Msgs Received : ").append(rcvdMsgCount).toString());
- System.out.println(new StringBuilder("Consumer rate : ").
- append(df.format(consRate)).
- append(" msg/sec").toString());
- System.out.println(new StringBuilder("System Throughput : ").
- append(df.format(throughput)).
- append(" msg/sec").toString());
- System.out.println(new StringBuilder("Avg Latency : ").
- append(df.format(avgLatency)).
- append(" ms").toString());
- System.out.println(new StringBuilder("Min Latency : ").
- append(minLatency).
- append(" ms").toString());
- System.out.println(new StringBuilder("Max Latency : ").
- append(maxLatency).
- append(" ms").toString());
- System.out.println("Completed the test......\n");
- }
-
- public void notifyCompletion(Destination replyTo) throws Exception
- {
- MessageProducer tmp = session.createProducer(replyTo);
- Message endMsg = session.createMessage();
- tmp.send(endMsg);
- if (params.isTransacted())
- {
- session.commit();
- }
- tmp.close();
- }
-
- public void tearDown() throws Exception
- {
- consumer.close();
- session.close();
- con.close();
- }
-
- public void onMessage(Message msg)
- {
- try
- {
- if (msg instanceof TextMessage && ((TextMessage)msg).getText().equals("End"))
- {
- notifyCompletion(msg.getJMSReplyTo());
-
- synchronized (lock)
- {
- lock.notifyAll();
- }
- }
- else
- {
- rcvdTime = System.currentTimeMillis();
- rcvdMsgCount ++;
-
- if (rcvdMsgCount == 1)
- {
- startTime = rcvdTime;
- testStartTime = msg.getJMSTimestamp();
- }
-
- if (transacted && (rcvdMsgCount % transSize == 0))
- {
- session.commit();
- }
-
- long latency = rcvdTime - msg.getJMSTimestamp();
- maxLatency = Math.max(maxLatency, latency);
- minLatency = Math.min(minLatency, latency);
- totalLatency = totalLatency + latency;
- }
-
- }
- catch(Exception e)
- {
- handleError(e,"Error when receiving messages");
- }
-
- }
-
- public void test()
- {
- try
- {
- setUp();
- warmup();
- startTest();
- printResults();
- tearDown();
- }
- catch(Exception e)
- {
- handleError(e,"Error when running test");
- }
- }
-
- public static void main(String[] args)
- {
- PerfConsumer cons = new PerfConsumer();
- cons.test();
- }
-} \ No newline at end of file
diff --git a/java/testkit/src/main/java/org/apache/qpid/testkit/perf/PerfProducer.java b/java/testkit/src/main/java/org/apache/qpid/testkit/perf/PerfProducer.java
deleted file mode 100644
index 757b1bfcda..0000000000
--- a/java/testkit/src/main/java/org/apache/qpid/testkit/perf/PerfProducer.java
+++ /dev/null
@@ -1,207 +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.
- *
- */
-package org.apache.qpid.testkit.perf;
-
-import javax.jms.BytesMessage;
-import javax.jms.DeliveryMode;
-import javax.jms.Message;
-import javax.jms.MessageConsumer;
-import javax.jms.MessageProducer;
-
-import org.apache.qpid.testkit.MessageFactory;
-
-/**
- * PerfProducer sends an x no of messages in warmup mode and wait for a confirmation
- * from the consumer that it has successfully consumed them and ready to start the
- * test. It will start sending y no of messages and each message will contain a time
- * stamp. This will be used at the receiving end to measure the latency.
- *
- * This is done with the assumption that both consumer and producer are running on
- * the same machine or different machines which have time synced using a time server.
- *
- * This test also calculates the producer rate as follows.
- * rate = msg_count/(time_before_sending_msgs - time_after_sending_msgs)
- *
- * All throughput rates are given as msg/sec so the rates are multiplied by 1000.
- *
- * Rajith - Producer rate is not an accurate perf metric IMO.
- * It is heavily inlfuenced by any in memory buffering.
- * System throughput and latencies calculated by the PerfConsumer are more realistic
- * numbers.
- *
- */
-public class PerfProducer extends PerfBase
-{
- MessageProducer producer;
- Message msg;
- byte[] payload;
-
- public PerfProducer()
- {
- super();
- }
-
- public void setUp() throws Exception
- {
- super.setUp();
- feedbackDest = session.createTemporaryQueue();
-
- // if message caching is enabled we pre create the message
- // else we pre create the payload
- if (params.isCacheMessage())
- {
- msg = MessageFactory.createBytesMessage(session, params.getMsgSize());
- msg.setJMSDeliveryMode(params.isDurable()?
- DeliveryMode.PERSISTENT :
- DeliveryMode.NON_PERSISTENT
- );
- }
- else
- {
- payload = MessageFactory.createMessagePayload(params.getMsgSize()).getBytes();
- }
-
- producer = session.createProducer(dest);
- producer.setDisableMessageID(params.isDisableMessageID());
- producer.setDisableMessageTimestamp(params.isDisableTimestamp());
- }
-
- protected Message getNextMessage() throws Exception
- {
- if (params.isCacheMessage())
- {
- return msg;
- }
- else
- {
- msg = session.createBytesMessage();
- ((BytesMessage)msg).writeBytes(payload);
- return msg;
- }
- }
-
- public void warmup()throws Exception
- {
- System.out.println("Warming up......");
- MessageConsumer tmp = session.createConsumer(feedbackDest);
-
- for (int i=0; i < params.getWarmupCount() -1; i++)
- {
- producer.send(getNextMessage());
- }
- Message msg = session.createTextMessage("End");
- msg.setJMSReplyTo(feedbackDest);
- producer.send(msg);
-
- if (params.isTransacted())
- {
- session.commit();
- }
-
- tmp.receive();
-
- if (params.isTransacted())
- {
- session.commit();
- }
-
- tmp.close();
- }
-
- public void startTest() throws Exception
- {
- System.out.println("Starting test......");
- int count = params.getMsgCount();
- boolean transacted = params.isTransacted();
- int tranSize = params.getTransactionSize();
-
- long start = System.currentTimeMillis();
- for(int i=0; i < count; i++ )
- {
- Message msg = getNextMessage();
- msg.setJMSTimestamp(System.currentTimeMillis());
- producer.send(msg);
- if ( transacted && ((i+1) % tranSize == 0))
- {
- session.commit();
- }
- }
- long time = System.currentTimeMillis() - start;
- double rate = ((double)count/(double)time)*1000;
- System.out.println(new StringBuilder("Producer rate: ").
- append(df.format(rate)).
- append(" msg/sec").
- toString());
- }
-
- public void waitForCompletion() throws Exception
- {
- MessageConsumer tmp = session.createConsumer(feedbackDest);
- Message msg = session.createTextMessage("End");
- msg.setJMSReplyTo(feedbackDest);
- producer.send(msg);
-
- if (params.isTransacted())
- {
- session.commit();
- }
-
- tmp.receive();
-
- if (params.isTransacted())
- {
- session.commit();
- }
-
- tmp.close();
- System.out.println("Consumer has completed the test......");
- }
-
- public void tearDown() throws Exception
- {
- producer.close();
- session.close();
- con.close();
- }
-
- public void test()
- {
- try
- {
- setUp();
- warmup();
- startTest();
- waitForCompletion();
- tearDown();
- }
- catch(Exception e)
- {
- handleError(e,"Error when running test");
- }
- }
-
-
- public static void main(String[] args)
- {
- PerfProducer prod = new PerfProducer();
- prod.test();
- }
-} \ No newline at end of file
diff --git a/java/testkit/src/main/java/org/apache/qpid/testkit/perf/TestParams.java b/java/testkit/src/main/java/org/apache/qpid/testkit/perf/TestParams.java
deleted file mode 100644
index 15142cfced..0000000000
--- a/java/testkit/src/main/java/org/apache/qpid/testkit/perf/TestParams.java
+++ /dev/null
@@ -1,160 +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.
- *
- */
-package org.apache.qpid.testkit.perf;
-
-import javax.jms.Session;
-
-public class TestParams
-{
- private String initialContextFactory = "org.apache.qpid.jndi.PropertiesFileInitialContextFactory";
-
- private String providerURL = System.getenv("QPID_TEST_HOME") + "/etc/jndi.properties";
-
- private String connectionFactory = "connectionFactory";
-
- private String transientDest = "transientQueue";
-
- private String durableDest = "durableQueue";
-
- private int msg_size = 512;
-
- private int msg_type = 1; // not used yet
-
- private boolean cacheMessage = true;
-
- private boolean disableMessageID = false;
-
- private boolean disableTimestamp = false;
-
- private boolean durable = false;
-
- private boolean transacted = false;
-
- private int transaction_size = 1000;
-
- private int ack_mode = Session.AUTO_ACKNOWLEDGE;
-
- private int msg_count = 10;
-
- private int warmup_count = 1;
-
- public TestParams()
- {
- initialContextFactory = System.getProperty("java.naming.factory.initial",initialContextFactory);
- providerURL = System.getProperty("java.naming.provider.url",providerURL);
-
- transientDest = System.getProperty("transDest",transientDest);
- durableDest = System.getProperty("durableDest",durableDest);
-
- msg_size = Integer.getInteger("msg_size", 512);
- msg_type = Integer.getInteger("msg_type",1);
- cacheMessage = Boolean.getBoolean("cache_msg");
- disableMessageID = Boolean.getBoolean("disableMessageID");
- disableTimestamp = Boolean.getBoolean("disableTimestamp");
- durable = Boolean.getBoolean("durable");
- transacted = Boolean.getBoolean("transacted");
- transaction_size = Integer.getInteger("trans_size",1000);
- ack_mode = Integer.getInteger("ack_mode",Session.AUTO_ACKNOWLEDGE);
- msg_count = Integer.getInteger("msg_count",msg_count);
- warmup_count = Integer.getInteger("warmup_count",warmup_count);
- }
-
- public int getAckMode()
- {
- return ack_mode;
- }
-
- public String getConnectionFactory()
- {
- return connectionFactory;
- }
-
- public String getTransientDestination()
- {
- return transientDest;
- }
-
- public String getDurableDestination()
- {
- return durableDest;
- }
-
- public String getInitialContextFactory()
- {
- return initialContextFactory;
- }
-
- public int getMsgCount()
- {
- return msg_count;
- }
-
- public int getMsgSize()
- {
- return msg_size;
- }
-
- public int getMsgType()
- {
- return msg_type;
- }
-
- public boolean isDurable()
- {
- return durable;
- }
-
- public String getProviderURL()
- {
- return providerURL;
- }
-
- public boolean isTransacted()
- {
- return transacted;
- }
-
- public int getTransactionSize()
- {
- return transaction_size;
- }
-
- public int getWarmupCount()
- {
- return warmup_count;
- }
-
- public boolean isCacheMessage()
- {
- return cacheMessage;
- }
-
- public boolean isDisableMessageID()
- {
- return disableMessageID;
- }
-
- public boolean isDisableTimestamp()
- {
- return disableTimestamp;
- }
-
-}
diff --git a/java/testkit/src/main/java/org/apache/qpid/testkit/soak/BaseTest.java b/java/testkit/src/main/java/org/apache/qpid/testkit/soak/BaseTest.java
deleted file mode 100644
index 0c3a17b3d8..0000000000
--- a/java/testkit/src/main/java/org/apache/qpid/testkit/soak/BaseTest.java
+++ /dev/null
@@ -1,152 +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.
- *
- */
-package org.apache.qpid.testkit.soak;
-
-
-import java.text.DateFormat;
-import java.text.DecimalFormat;
-import java.text.NumberFormat;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-import javax.jms.DeliveryMode;
-import javax.jms.Destination;
-import javax.jms.Message;
-import javax.jms.Session;
-
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQQueue;
-import org.apache.qpid.client.AMQTopic;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.testkit.MessageFactory;
-
-public class BaseTest
-{
- protected String host = "127.0.0.1";
- protected int msg_size = 100;
- protected int msg_count = 10;
- protected int session_count = 1;
- protected boolean durable = false;
- protected String queue_name = "message_queue";
- protected String exchange_name = "amq.direct";
- protected String routing_key = "routing_key";
- protected String contentType = "application/octet-stream";
- protected int port = 5672;
- protected String url;
- protected Message[] msgArray;
-
- protected AMQConnection con;
- protected Destination dest = null;
- protected DateFormat df = new SimpleDateFormat("yyyy.MM.dd 'at' HH:mm:ss");
- protected NumberFormat nf = new DecimalFormat("##.00");
-
- public BaseTest()
- {
- host = System.getProperty("host", "127.0.0.1");
- port = Integer.getInteger("port", 5672);
- msg_size = Integer.getInteger("msg_size", 100);
- msg_count = Integer.getInteger("msg_count", 10);
- session_count = Integer.getInteger("session_count", 1);
- durable = Boolean.getBoolean("durable");
- queue_name = System.getProperty("queue_name", "message_queue");
- exchange_name = System.getProperty("exchange_name", "amq.direct");
- routing_key = System.getProperty("routing_key", "routing_key");
- contentType = System.getProperty("content_type","application/octet-stream");
-
-
-
- url = "amqp://username:password@topicClientid/test?brokerlist='tcp://" + host + ":" + port + "'";
- }
-
- public void setUp()
- {
- try
- {
- con = new AMQConnection(url);
- con.start();
-
-
- if (exchange_name.equals("amq.topic"))
- {
- dest = new AMQTopic(new AMQShortString(exchange_name),
- new AMQShortString(routing_key),
- false, //auto-delete
- null, //queue name
- durable);
- }
- else
- {
- dest = new AMQQueue(new AMQShortString(exchange_name),
- new AMQShortString(routing_key),
- new AMQShortString(queue_name),
- false, //exclusive
- false, //auto-delete
- durable);
- }
-
- // Create the session to setup the messages
- Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
-
- if (msg_size == -1)
- {
- // This creates an array of 1000 messages from 500-1500 bytes
- // During the tests a message will be picked randomly
- msgArray = new Message[1000];
- for (int i = 0; i < 1000; i++)
- {
- Message msg = (contentType.equals("text/plain")) ?
- MessageFactory.createTextMessage(session,500 + i) :
- MessageFactory.createBytesMessage(session, 500 + i);
- msg.setJMSDeliveryMode((durable) ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
- msgArray[i] = msg;
- }
- }
- else
- {
- Message msg = (contentType.equals("text/plain")) ?
- MessageFactory.createTextMessage(session, msg_size):
- MessageFactory.createBytesMessage(session, msg_size);
- msg.setJMSDeliveryMode((durable) ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
- msgArray = new Message[]
- { msg };
- }
-
- session.close();
-
- }
- catch (Exception e)
- {
- handleError(e,"Error while setting up the test");
- }
- }
-
- public void handleError(Exception e,String msg)
- {
- StringBuilder sb = new StringBuilder();
- sb.append(msg);
- sb.append(" @ ");
- sb.append(df.format(new Date(System.currentTimeMillis())));
- sb.append(" ");
- sb.append(e.getMessage());
- System.err.println(sb.toString());
- e.printStackTrace();
- }
-}
diff --git a/java/testkit/src/main/java/org/apache/qpid/testkit/soak/MultiThreadedConsumer.java b/java/testkit/src/main/java/org/apache/qpid/testkit/soak/MultiThreadedConsumer.java
deleted file mode 100644
index a91d9e7e85..0000000000
--- a/java/testkit/src/main/java/org/apache/qpid/testkit/soak/MultiThreadedConsumer.java
+++ /dev/null
@@ -1,153 +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.
- *
- */
-package org.apache.qpid.testkit.soak;
-
-
-import javax.jms.JMSException;
-import javax.jms.Message;
-import javax.jms.MessageConsumer;
-import javax.jms.MessageListener;
-import javax.jms.MessageProducer;
-import javax.jms.Session;
-import javax.jms.TextMessage;
-
-/**
- * Test Description
- * ================
- * The difference between this test and the
- * LongDurationConsumer is that each Session runs
- * in it's own Thread and the ability to receive
- * messages transactionally.
- *
- * All consumers will still share the same destination.
- *
- */
-public class MultiThreadedConsumer extends BaseTest
-{
- protected final boolean transacted;
-
- public MultiThreadedConsumer()
- {
- super();
- transacted = Boolean.getBoolean("transacted");
- // needed only to calculate throughput.
- // If msg_count is different set it via -Dmsg_count
- msg_count = 10;
- }
-
- /**
- * Creates a Session and a consumer that runs in its
- * own thread.
- * It can also consume transactionally.
- *
- */
- public void test()
- {
- try
- {
- for (int i = 0; i < session_count; i++)
- {
-
- final Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
- Thread t = new Thread(new Runnable()
- {
- public void run()
- {
- try
- {
- MessageConsumer consumer = session.createConsumer(dest);
-
- consumer.setMessageListener(new MessageListener()
- {
-
- private boolean startIteration = true;
- private long startTime = 0;
- private long iterations = 0;
-
- public void onMessage(Message m)
- {
- try
- {
- long now = System.currentTimeMillis();
- if (startIteration)
- {
- startTime = m.getJMSTimestamp();
- startIteration = false;
- }
-
- if (m instanceof TextMessage && ((TextMessage) m).getText().equals("End"))
- {
- startIteration = true;
- long totalIterationTime = now - startTime;
- double throughput = ((double)msg_count/(double)totalIterationTime) * 1000;
- long latencySample = now - m.getJMSTimestamp();
- iterations++;
-
- StringBuilder sb = new StringBuilder();
- sb.append(iterations).append(",").
- append(nf.format(throughput)).append(",").append(latencySample);
-
- System.out.println(sb.toString());
-
- MessageProducer temp = session.createProducer(m.getJMSReplyTo());
- Message controlMsg = session.createTextMessage();
- temp.send(controlMsg);
- if (transacted)
- {
- session.commit();
- }
- temp.close();
- }
- }
- catch (JMSException e)
- {
- handleError(e,"Exception receiving messages");
- }
- }
- });
- }
- catch (Exception e)
- {
- handleError(e,"Exception creating a consumer");
- }
-
- }
-
- });
- t.setName("session-" + i);
- t.start();
- } // for loop
- }
- catch (Exception e)
- {
- handleError(e,"Exception while setting up the test");
- }
-
- }
-
- public static void main(String[] args)
- {
- MultiThreadedConsumer test = new MultiThreadedConsumer();
- test.setUp();
- test.test();
- }
-
-}
diff --git a/java/testkit/src/main/java/org/apache/qpid/testkit/soak/MultiThreadedProducer.java b/java/testkit/src/main/java/org/apache/qpid/testkit/soak/MultiThreadedProducer.java
deleted file mode 100644
index 279e5ea0bf..0000000000
--- a/java/testkit/src/main/java/org/apache/qpid/testkit/soak/MultiThreadedProducer.java
+++ /dev/null
@@ -1,166 +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.
- *
- */
-package org.apache.qpid.testkit.soak;
-
-
-import java.util.Random;
-import java.util.UUID;
-
-import javax.jms.Message;
-import javax.jms.MessageConsumer;
-import javax.jms.MessageProducer;
-import javax.jms.Session;
-import javax.jms.TextMessage;
-
-import org.apache.qpid.client.AMQQueue;
-import org.apache.qpid.framing.AMQShortString;
-
-/**
- * Test Description
- * ================
- *
- * This test creats x number of sessions, where each session
- * runs in it's own thread. Each session creates a producer
- * and it's own feedback queue.
- *
- * A producer will send n-1 messages, followed by the n-th
- * message which contains "End" in it's payload to signal
- * that this is the last message message in the sequence.
- * The end message has the feedback queue as it's replyTo.
- * It will then listen on the feedback queue waiting for the
- * confirmation and then sleeps for 1000 ms before proceeding
- * with the next n messages.
- *
- * This hand shaking mechanism ensures that all of the
- * messages sent are consumed by some consumer. This prevents
- * the producers from saturating the broker especially when
- * the consumers are slow.
- *
- * All producers send to a single destination
- * If using transactions it's best to use smaller message count
- * as the test only commits after sending all messages in a batch.
- *
- */
-
-public class MultiThreadedProducer extends SimpleProducer
-{
- protected final boolean transacted;
-
- public MultiThreadedProducer()
- {
- super();
- transacted = Boolean.getBoolean("transacted");
- }
-
- public void test()
- {
- try
- {
- final int msg_count_per_session = msg_count/session_count;
-
- for (int i = 0; i < session_count; i++)
- {
- final Session session = con.createSession(transacted, Session.AUTO_ACKNOWLEDGE);
- Thread t = new Thread(new Runnable()
- {
- private Random gen = new Random();
-
- private Message getNextMessage()
- {
- if (msg_size == -1)
- {
- int index = gen.nextInt(1000);
- return msgArray[index];
- }
- else
- {
- return msgArray[0];
- }
- }
-
- public void run()
- {
- try
- {
- MessageProducer prod = session.createProducer(dest);
- // this will ensure that the producer will not overun the consumer.
- feedbackQueue = new AMQQueue(new AMQShortString("amq.direct"), new AMQShortString(UUID
- .randomUUID().toString()), new AMQShortString("control"));
-
- MessageConsumer feedbackConsumer = session.createConsumer(feedbackQueue);
-
- while (true)
- {
- for (int i = 0; i < msg_count_per_session; i++)
- {
- Message msg = getNextMessage();
- msg.setJMSMessageID("ID:" + UUID.randomUUID());
- prod.send(msg);
- }
-
- TextMessage m = session.createTextMessage("End");
- m.setJMSReplyTo(feedbackQueue);
- prod.send(m);
-
- if (transacted)
- {
- session.commit();
- }
-
- System.out.println(df.format(System.currentTimeMillis()));
- feedbackConsumer.receive();
- if (transacted)
- {
- session.commit();
- }
- Thread.sleep(1000);
- }
-
- }
- catch (Exception e)
- {
- handleError(e,"Exception in producing message");
- }
-
- }
-
- });
- t.setName("session-" + i);
- t.start();
-
- }
-
- }
- catch (Exception e)
- {
- handleError(e,"Exception while setting up the test");
- }
-
- }
-
- public static void main(String[] args)
- {
- MultiThreadedProducer test = new MultiThreadedProducer();
- test.setUp();
- test.test();
- }
-
-}
diff --git a/java/testkit/src/main/java/org/apache/qpid/testkit/soak/ResourceLeakTest.java b/java/testkit/src/main/java/org/apache/qpid/testkit/soak/ResourceLeakTest.java
index c33f9ffbf2..c240ecdf2e 100644
--- a/java/testkit/src/main/java/org/apache/qpid/testkit/soak/ResourceLeakTest.java
+++ b/java/testkit/src/main/java/org/apache/qpid/testkit/soak/ResourceLeakTest.java
@@ -21,6 +21,8 @@
package org.apache.qpid.testkit.soak;
+import java.util.Random;
+
import javax.jms.BytesMessage;
import javax.jms.Destination;
import javax.jms.MessageConsumer;
@@ -29,15 +31,21 @@ import javax.jms.Session;
import org.apache.qpid.client.AMQConnection;
import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.BasicMessageConsumer;
+import org.apache.qpid.client.BasicMessageProducer;
import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.testkit.TestLauncher;
+import org.apache.qpid.thread.Threading;
/**
* Test Description
* ================
* This test will open x number of connections where each
* connection will create a session and a producer/consumer pair,
- * and then send configurable no of messages.
- * It will them sleep for configurable time interval and
+ * and then a randomly selected set of connections (about 1/4th)
+ * will send a configurable no of messages and try to receive them.
+ * It will then sleep for configurable time interval and
* tear down the connections/sessions/consumers.
* It will then repeat the process again until the test is stopped.
*
@@ -46,16 +54,14 @@ import org.apache.qpid.framing.AMQShortString;
* To find if the broker has leaks when cleaning resources.
* To find if the client has leaks with resources.
*/
-public class ResourceLeakTest extends BaseTest
+public class ResourceLeakTest extends TestLauncher
{
- protected int connection_count = 10;
- protected long connection_idle_time = 5000;
-
+ /* protected long connection_idle_time = 5000;
+ protected Random rand = new Random();
+
public ResourceLeakTest()
{
- super();
- connection_count = Integer.getInteger("con_count",10);
- connection_idle_time = Long.getLong("con_idle_time", 5000);
+ super();
}
public void test()
@@ -67,13 +73,7 @@ public class ResourceLeakTest extends BaseTest
Session[] sessions = new Session[connection_count];
MessageConsumer[] msgCons = new MessageConsumer[connection_count];
MessageProducer [] msgProds = new MessageProducer[connection_count];
- Destination dest = new AMQQueue(new AMQShortString(exchange_name),
- new AMQShortString(routing_key),
- new AMQShortString(queue_name),
- true, //exclusive
- true // auto delete
- );
-
+
while (true)
{
for (int i = 0; i < connection_count; i++)
@@ -83,23 +83,36 @@ public class ResourceLeakTest extends BaseTest
cons[i] = con;
Session ssn = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
sessions[i] = ssn;
+ Destination dest = new AMQQueue(new AMQShortString(exchange_name),
+ new AMQShortString(routing_key + i),
+ new AMQShortString(queue_name + i),
+ true, //exclusive
+ true // auto delete
+ );
MessageConsumer msgCon = ssn.createConsumer(dest);
msgCons[i] = msgCon;
MessageProducer msgProd = ssn.createProducer(dest);
msgProds[i] = msgProd;
-
- BytesMessage msg = ssn.createBytesMessage();
+ }
+
+ // Select some connections randomly and send/recv messages
+ // Exercise around quarter of the connections
+ for (int i=0; i < connection_count/4; i++)
+ {
+ int k = rand.nextInt(connection_count);
+
+ BytesMessage msg = sessions[k].createBytesMessage();
msg.writeBytes("Test Msg".getBytes());
for (int j = 0; j < msg_count;j++)
{
- msgProd.send(msg);
+ msgProds[k].send(msg);
}
int j = 0;
while (j < msg_count)
{
- msgCon.receive();
+ msgCons[k].receive();
j++;
}
}
@@ -110,10 +123,24 @@ public class ResourceLeakTest extends BaseTest
{
for (int i = 0; i < connection_count; i++)
{
- msgCons[i].close();
- msgProds[i].close();
- sessions[i].close();
- cons[i].close();
+ if (!((BasicMessageConsumer)msgCons[i]).isClosed())
+ {
+ msgCons[i].close();
+ }
+
+ if (!((BasicMessageProducer)msgProds[i]).isClosed())
+ {
+ msgProds[i].close();
+ }
+
+ if (!((AMQSession)sessions[i]).isClosed())
+ {
+ sessions[i].close();
+ }
+ if (!((AMQConnection)cons[i]).isClosed())
+ {
+ cons[i].close();
+ }
}
}
catch (Exception e)
@@ -131,8 +158,23 @@ public class ResourceLeakTest extends BaseTest
public static void main(String[] args)
{
- ResourceLeakTest test = new ResourceLeakTest();
- test.test();
- }
+ final ResourceLeakTest test = new ResourceLeakTest();
+ Runnable r = new Runnable(){
+ public void run()
+ {
+ test.test();
+ }
+ };
+
+ Thread t;
+ try
+ {
+ t = Threading.getThreadFactory().createThread(r);
+ }
+ catch(Exception e)
+ {
+ throw new Error("Error creating test thread",e);
+ }
+ }*/
}
diff --git a/java/testkit/src/main/java/org/apache/qpid/testkit/soak/SimpleConsumer.java b/java/testkit/src/main/java/org/apache/qpid/testkit/soak/SimpleConsumer.java
deleted file mode 100644
index b3eb97dafe..0000000000
--- a/java/testkit/src/main/java/org/apache/qpid/testkit/soak/SimpleConsumer.java
+++ /dev/null
@@ -1,134 +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.
- *
- */
-package org.apache.qpid.testkit.soak;
-
-
-import javax.jms.JMSException;
-import javax.jms.Message;
-import javax.jms.MessageConsumer;
-import javax.jms.MessageListener;
-import javax.jms.MessageProducer;
-import javax.jms.Session;
-import javax.jms.TextMessage;
-
-/**
- * Test Description
- * ================
- * This test will create x number of sessions.
- * Each session will have it's own consumer.
- * Once a consumer receives the "End" message it
- * will send a message to the destination indicated
- * by the replyTo field in the End message.
- * This will signal the producer that all the previous
- * messages have been consumed. The producer will
- * then start sending messages again.
- *
- * This prevents the producer from overruning the
- * consumer.
- * *
- * All consumers share a single destination
- *
- */
-
-public class SimpleConsumer extends BaseTest
-{
- public SimpleConsumer()
- {
- super();
- //needed only to calculate throughput.
- // If msg_count is different set it via -Dmsg_count
- msg_count = 10;
- }
-
- public void test()
- {
- try
- {
- final Session[] sessions = new Session[session_count];
- MessageConsumer[] cons = new MessageConsumer[session_count];
-
- for (int i = 0; i < session_count; i++)
- {
- sessions[i] = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
- cons[i] = sessions[i].createConsumer(dest);
- cons[i].setMessageListener(new MessageListener()
- {
-
- private boolean startIteration = true;
- private long startTime = 0;
- private long iterations = 0;
-
- public void onMessage(Message m)
- {
- try
- {
- long now = System.currentTimeMillis();
- if (startIteration)
- {
- startTime = m.getJMSTimestamp();
- startIteration = false;
- }
-
- if (m instanceof TextMessage && ((TextMessage) m).getText().equals("End"))
- {
-
- long totalIterationTime = now - startTime;
- startIteration = true;
- double throughput = ((double)msg_count/(double)totalIterationTime) * 1000;
- long latencySample = now - m.getJMSTimestamp();
- iterations++;
-
- StringBuilder sb = new StringBuilder();
- sb.append(iterations).append(",").
- append(nf.format(throughput)).append(",").append(latencySample);
-
- System.out.println(sb.toString());
-
- MessageProducer temp = sessions[0].createProducer(m.getJMSReplyTo());
- Message controlMsg = sessions[0].createTextMessage();
- temp.send(controlMsg);
- temp.close();
- }
- }
- catch (JMSException e)
- {
- handleError(e,"Exception when receiving the message");
- }
- }
- });
- }
-
- }
- catch (Exception e)
- {
- handleError(e,"Exception when setting up the consumers");
- }
-
- }
-
- public static void main(String[] args)
- {
- SimpleConsumer test = new SimpleConsumer();
- test.setUp();
- test.test();
- }
-
-}
diff --git a/java/testkit/src/main/java/org/apache/qpid/testkit/soak/SimpleProducer.java b/java/testkit/src/main/java/org/apache/qpid/testkit/soak/SimpleProducer.java
deleted file mode 100644
index 1080092536..0000000000
--- a/java/testkit/src/main/java/org/apache/qpid/testkit/soak/SimpleProducer.java
+++ /dev/null
@@ -1,146 +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.
- *
- */
-package org.apache.qpid.testkit.soak;
-
-
-import java.util.Random;
-import java.util.UUID;
-
-import javax.jms.Destination;
-import javax.jms.Message;
-import javax.jms.MessageConsumer;
-import javax.jms.MessageProducer;
-import javax.jms.Session;
-import javax.jms.TextMessage;
-
-import org.apache.qpid.client.AMQQueue;
-import org.apache.qpid.framing.AMQShortString;
-
-/**
- * Test Description
- * ================
- * This test will send n-1 messages, followed by the n-th
- * message which contains "End" in it's payload to signal
- * that this is the last message message in the sequence.
- * The end message has the feedback queue as it's replyTo.
- * It will then listen on the feedback queue waiting for the
- * confirmation and then sleeps for 1000 ms before proceeding
- * with the next n messages.
- *
- * This hand shaking mechanism ensures that all of the
- * messages sent are consumed by some consumer. This prevents
- * the producers from saturating the broker especially when
- * the consumers are slow.
- *
- * It creates a producer per session.
- * If session_count is > 1 it will round robin the messages
- * btw the producers.
- *
- * All producers send to a single destination
- *
- */
-
-public class SimpleProducer extends BaseTest
-{
- protected Destination feedbackQueue;
- Random gen = new Random();
-
- public SimpleProducer()
- {
- super();
- }
-
- protected Message getNextMessage()
- {
- if (msg_size == -1)
- {
- int index = gen.nextInt(1000);
- return msgArray[index];
- }
- else
- {
- return msgArray[0];
- }
- }
-
- public void test()
- {
- try
- {
- Session[] sessions = new Session[session_count];
- MessageProducer[] prods = new MessageProducer[session_count];
-
- for (int i = 0; i < session_count; i++)
- {
- sessions[i] = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
- prods[i] = sessions[i].createProducer(dest);
- }
-
- // this will ensure that the producer will not overun the consumer.
- feedbackQueue = new AMQQueue(new AMQShortString("amq.direct"),
- new AMQShortString(UUID.randomUUID().toString()),
- new AMQShortString("control"));
-
- MessageConsumer feedbackConsumer = sessions[0].createConsumer(feedbackQueue);
-
- int prod_pointer = 0;
- boolean multi_session = session_count > 1 ? true : false;
-
- while (true)
- {
- for (int i = 0; i < msg_count - 1; i++)
- {
- Message msg = getNextMessage();
- msg.setJMSTimestamp(System.currentTimeMillis());
- prods[prod_pointer].send(msg);
- if (multi_session)
- {
- prod_pointer++;
- if (prod_pointer == session_count)
- {
- prod_pointer = 0;
- }
- }
- }
-
- TextMessage m = sessions[0].createTextMessage("End");
- m.setJMSReplyTo(feedbackQueue);
- prods[prod_pointer].send(m);
- System.out.println(df.format(System.currentTimeMillis()));
- feedbackConsumer.receive();
- Thread.sleep(1000);
- }
- }
- catch (Exception e)
- {
- handleError(e,"Exception while setting up the producer");
- }
-
- }
-
- public static void main(String[] args)
- {
- SimpleProducer test = new SimpleProducer();
- test.setUp();
- test.test();
- }
-
-}
diff --git a/java/testkit/testkit.py b/java/testkit/testkit.py
new file mode 100755
index 0000000000..f0e49072bd
--- /dev/null
+++ b/java/testkit/testkit.py
@@ -0,0 +1,216 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import time, string, traceback
+from brokertest import *
+from qpid.messaging import *
+
+
+try:
+ import java.lang.System
+ _cp = java.lang.System.getProperty("java.class.path");
+except ImportError:
+ _cp = checkenv("QP_CP")
+
+# The base test case has support for launching the genric
+# receiver and sender through the TestLauncher with all the options.
+#
+class JavaClientTest(BrokerTest):
+ """Base Case for Java Test cases"""
+
+ client_class = "org.apache.qpid.testkit.TestLauncher"
+
+ # currently there is no transparent reconnection.
+ # temp hack: just creating the queue here and closing it.
+ def start_error_watcher(self,broker=None):
+ ssn = broker.connect().session()
+ err_watcher = ssn.receiver("control; {create:always}", capacity=1)
+ ssn.close()
+
+ def client(self,**options):
+ cmd = ["java","-cp",_cp]
+ cmd += ["-Dtest_name=" + options.get("test_name", "UNKNOWN")]
+ cmd += ["-Dhost=" + options.get("host","127.0.0.1")]
+ cmd += ["-Dport=" + str(options.get("port",5672))]
+ cmd += ["-Dcon_count=" + str(options.get("con_count",1))]
+ cmd += ["-Dssn_count=" + str(options.get("ssn_count",1))]
+ cmd += ["-Dqueue_name=" + options.get("queue_name","queue")]
+ cmd += ["-Dexchange_name=" + options.get("exchange_name","amq.direct")]
+ cmd += ["-Drouting_key=" + options.get("routing_key","routing_key")]
+ cmd += ["-Dunique_dests=" + str(options.get("unique_dests",True))]
+ cmd += ["-Ddurable=" + str(options.get("durable",False))]
+ cmd += ["-Dtransacted=" + str(options.get("transacted",False))]
+ cmd += ["-Dreceiver=" + str(options.get("receiver",False))]
+ cmd += ["-Dsync_rcv=" + str(options.get("sync_rcv",False))]
+ cmd += ["-Dsender=" + str(options.get("sender",False))]
+ cmd += ["-Dmsg_size=" + str(options.get("msg_size",256))]
+ cmd += ["-Dtx_size=" + str(options.get("tx_size",10))]
+ cmd += ["-Dmsg_count=" + str(options.get("msg_count",10))]
+ cmd += ["-Dsleep_time=" + str(options.get("sleep_time",1000))]
+ cmd += ["-Dfailover=" + options.get("failover", "failover_exchange")]
+ cmd += ["-Dreliability=" + options.get("reliability", "exactly_once")]
+ cmd += ["-Dlog.level=" + options.get("log.level", "warn")]
+ cmd += [self.client_class]
+
+ print str(options.get("port",5672))
+ return cmd
+
+ # currently there is no transparent reconnection.
+ # temp hack: just creating a receiver and closing session soon after.
+ def monitor_clients(self,broker=None,run_time=600,error_ck_freq=60):
+ ssn = broker.connect().session()
+ err_watcher = ssn.receiver("control; {create:always}", capacity=1)
+ i = run_time/error_ck_freq
+ for j in range(i):
+ try:
+ m = err_watcher.fetch(timeout=error_ck_freq)
+ print "Java process notified of an error"
+ print self.check_for_error(m)
+ except messaging.Empty, e:
+ pass # do nothing
+ ssn.close()
+
+ def check_for_error(self,msg):
+ raise Exception("Error:%s \nTime:%s\nTrace:%s\n" %
+ (msg.properties.get("desc"),
+ msg.properties.get("time"),
+ msg.properties.get("exception-trace")
+ ))
+
+ def terminate_and_capture_logs(self,popen, process_name):
+ if popen.is_running():
+ popen.terminate()
+ log = os.path.join(self.dir, process_name+".out")
+ f = open(log, 'w')
+ f.write(popen.stdout.read())
+ f.close()
+
+ log = os.path.join(self.dir, process_name+".err")
+ f = open(log, 'w')
+ f.write(popen.stderr.read())
+ f.close()
+
+ def verify(self, receiver,sender):
+ sender_running = receiver.is_running()
+ receiver_running = sender.is_running()
+
+ self.terminate_and_capture_logs(receiver,"receiver")
+ self.terminate_and_capture_logs(sender,"sender")
+
+ self.assertTrue(receiver_running,"Receiver has exited prematually")
+ self.assertTrue(sender_running,"Sender has exited prematually")
+
+
+class ConcurrencyTest(JavaClientTest):
+ """A concurrency test suite for the JMS client"""
+
+ def test_multiplexing_con(self):
+ """Tests multiple sessions on a single connection"""
+
+ cluster = Cluster(self, 2)
+ p = cluster[0].port()
+
+ self.start_error_watcher(broker=cluster[0])
+
+ receiver = self.popen(self.client(receiver=True,
+ ssn_count=25,
+ port=p,
+ test_name=self.id()),
+ expect=EXPECT_EXIT_FAIL)
+
+ sender = self.popen(self.client(sender=True,
+ ssn_count=25,
+ port=p,
+ test_name=self.id()),
+ expect=EXPECT_EXIT_FAIL)
+
+ self.monitor_clients(broker=cluster[0],run_time=60)
+ self.verify(receiver,sender)
+
+
+ def test_multiplexing_con_tx(self):
+ """Tests multiple transacted sessions on a single connection"""
+
+ cluster = Cluster(self,2)
+ ssn = cluster[0].connect().session()
+ p = cluster[0].port()
+
+ self.start_error_watcher(broker=cluster[0])
+
+ receiver = self.popen(self.client(receiver=True,
+ ssn_count=25,
+ port=p,
+ transacted=True,
+ test_name=self.id()),
+ expect=EXPECT_EXIT_FAIL)
+
+ sender = self.popen(self.client(sender=True,
+ ssn_count=25,
+ port=p,
+ transacted=True,
+ test_name=self.id()),
+ expect=EXPECT_EXIT_FAIL)
+
+ self.monitor_clients(broker=cluster[0],run_time=60)
+ ssn.close();
+ self.verify(receiver,sender)
+
+class SoakTest(JavaClientTest):
+ """A soak test suite for the JMS client"""
+
+ def test_failover(self):
+ cluster = self.cluster(4, expect=EXPECT_EXIT_FAIL)
+ p = cluster[0].port()
+ self.start_error_watcher(broker=cluster[0])
+ receiver = self.popen(self.client(receiver=True,
+ ssn_count=1,
+ port=p,
+ reliability="at_least_once",
+ test_name=self.id()),
+ expect=EXPECT_EXIT_FAIL)
+
+ sender = self.popen(self.client(sender=True,
+ ssn_count=1,
+ port=p,
+ reliability="at_least_once",
+ test_name=self.id()),
+ expect=EXPECT_EXIT_FAIL)
+
+ # grace period for java clients to get the failover properly setup.
+ time.sleep(30)
+ error_msg=None
+ # Kill original brokers, start new ones.
+ try:
+ for i in range(4):
+ cluster[i].kill()
+ b=cluster.start()
+ self.monitor_clients(broker=b,run_time=30,error_ck_freq=30)
+ except ConnectError, e1:
+ error_msg = "Unable to connect to new cluster node : " + traceback.format_exc(e1)
+
+ except SessionError, e2:
+ error_msg = "Session error while connected to new cluster node : " + traceback.format_exc(e2)
+
+ # verify also captures out/err streams
+ self.verify(receiver,sender)
+ if error_msg:
+ raise Exception(error_msg)
+
diff --git a/java/tools/bin/perf_report.sh b/java/tools/bin/perf_report.sh
new file mode 100755
index 0000000000..22c839e08c
--- /dev/null
+++ b/java/tools/bin/perf_report.sh
@@ -0,0 +1,131 @@
+#!/bin/sh
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# This will run the 8 use cases defined below and produce
+# a report in tabular format. Refer to the documentation
+# for more details.
+
+SUB_MEM=-Xmx1024M
+PUB_MEM=-Xmx1024M
+LOG_CONFIG="-Damqj.logging.level=WARN"
+
+. setenv.sh
+
+waitfor() { until grep -a -l "$2" $1 >/dev/null 2>&1 ; do sleep 1 ; done ; }
+cleanup()
+{
+ pids=`ps aux | grep java | grep Perf | awk '{print $2}'`
+ if [ "$pids" != "" ]; then
+ kill -3 $pids
+ kill -9 $pids >/dev/null 2>&1
+ fi
+}
+
+# $1 test name
+# $2 consumer options
+# $3 producer options
+run_testcase()
+{
+ sh run_sub.sh $LOG_CONFIG $SUB_MEM $2 > sub.out &
+ waitfor sub.out "Warming up"
+ sh run_pub.sh $LOG_CONFIG $PUB_MEM $3 > pub.out &
+ waitfor sub.out "Completed the test"
+ waitfor pub.out "Consumer has completed the test"
+ sleep 2 #give a grace period to shutdown
+ print_result $1
+}
+
+print_result()
+{
+ prod_rate=`cat pub.out | grep "Producer rate" | awk '{print $3}'`
+ sys_rate=`cat sub.out | grep "System Throughput" | awk '{print $4}'`
+ cons_rate=`cat sub.out | grep "Consumer rate" | awk '{print $4}'`
+ avg_latency=`cat sub.out | grep "Avg Latency" | awk '{print $4}'`
+ min_latency=`cat sub.out | grep "Min Latency" | awk '{print $4}'`
+ max_latency=`cat sub.out | grep "Max Latency" | awk '{print $4}'`
+
+ printf "|%-15s|%15.2f|%13.2f|%13.2f|%11.2f|%11d|%11d|\n" $1 $sys_rate $prod_rate $cons_rate $avg_latency $min_latency $max_latency
+ echo "------------------------------------------------------------------------------------------------"
+}
+
+trap cleanup EXIT
+
+echo "Test report on " `date +%F`
+echo "================================================================================================"
+echo "|Test |System throuput|Producer rate|Consumer Rate|Avg Latency|Min Latency|Max Latency|"
+echo "------------------------------------------------------------------------------------------------"
+
+# Test 1 Trans Queue
+run_testcase "Trans_Queue" "" "-Dwarmup_count=1 -Dmsg_count=10"
+
+# Test 2 Dura Queue
+run_testcase "Dura_Queue" "-Ddurable=true" "-Ddurable=true -Dwarmup_count=1 -Dmsg_count=10"
+
+# Test 3 Dura Queue Sync
+run_testcase "Dura_Queue_Sync" "-Ddurable=true" "-Ddurable=true -Dwarmup_count=1 -Dmsg_count=10 -Dsync_persistence=true"
+
+# Test 4 Dura Queue Sync Publish and Ack
+run_testcase "Dura_SyncPubAck" "-Ddurable=true -Dsync_ack=true" "-Ddurable=true -Dwarmup_count=1 -Dmsg_count=10 -Dsync_publish=persistent"
+
+# Test 5 Topic
+run_testcase "Topic" "-DtransDest=transientTopic" "-DtransDest=transientTopic -Dwarmup_count=1 -Dmsg_count=10"
+
+# Test 6 Durable Topic
+run_testcase "Dura_Topic" "-Ddurable=true -DtransDest=durableTopic" "-Ddurable=true -DtransDest=durableTopic -Dwarmup_count=1 -Dmsg_count=10"
+
+# Test 7 Fanout
+run_testcase "Fanout" "-DtransDest=fanoutQueue" "-DtransDest=fanoutQueue -Dwarmup_count=1 -Dmsg_count=10"
+
+# Test 8 Small TX
+run_testcase "Small_Txs_2" "-Ddurable=true -Dtransacted=true -Dtrans_size=1" \
+ "-Ddurable=true -Dwarmup_count=1 -Dmsg_count=10 -Dtransacted=true -Dtrans_size=1"
+
+# Test 9 Large TX
+run_testcase "Large_Txs_1000" "-Ddurable=true -Dtransacted=true -Dtrans_size=10" \
+ "-Ddurable=true -Dwarmup_count=1 -Dmsg_count=10 -Dtransacted=true -Dtrans_size=10"
+
+# Test 10 256 MSG
+run_testcase "Msg_256b" "" "-Dmsg_size=256 -Dwarmup_count=1 -Dmsg_count=10"
+
+# Test 11 512 MSG
+run_testcase "Msg_512b" "" "-Dmsg_size=512 -Dwarmup_count=1 -Dmsg_count=10"
+
+# Test 12 2048 MSG
+run_testcase "Msg_2048b" "" "-Dmsg_size=2048 -Dwarmup_count=1 -Dmsg_count=10"
+
+# Test 13 Random size MSG
+run_testcase "Random_Msg_Size" "" "-Drandom_msg_size=true -Dwarmup_count=1 -Dmsg_count=10"
+
+# Test 14 Random size MSG Durable
+run_testcase "Rand_Msg_Dura" "-Ddurable=true" "-Ddurable=true -Drandom_msg_size=true -Dwarmup_count=1 -Dmsg_count=10"
+
+# Test 15 64K MSG
+run_testcase "Msg_64K" "-Damqj.tcpNoDelay=true" "-Damqj.tcpNoDelay=true -Dmsg_size=64000 -Dwarmup_count=1 -Dmsg_count=10"
+
+# Test 16 Durable 64K MSG
+run_testcase "Msg_Durable_64K" "-Ddurable=true -Damqj.tcpNoDelay=true" \
+ "-Damqj.tcpNoDelay=true -Dmsg_size=64000 -Ddurable=true -Dwarmup_count=1 -Dmsg_count=10"
+
+# Test 17 500K MSG
+run_testcase "Msg_500K" "-Damqj.tcpNoDelay=true" "-Damqj.tcpNoDelay=true -Dmsg_size=500000 -Dwarmup_count=1 -Dmsg_count=10"
+
+# Test 18 Durable 500K MSG
+run_testcase "Msg_Dura_500K" "-Damqj.tcpNoDelay=true -Ddurable=true" \
+ "-Damqj.tcpNoDelay=true -Dmsg_size=500000 -Ddurable=true -Dwarmup_count=1 -Dmsg_count=10"
diff --git a/java/tools/bin/qpid-bench b/java/tools/bin/qpid-bench
index 21b092563a..c982e64efd 100644
--- a/java/tools/bin/qpid-bench
+++ b/java/tools/bin/qpid-bench
@@ -24,7 +24,7 @@ if [ -z "$QPID_HOME" ]; then
fi
# Set classpath to include Qpid jar with all required jars in manifest
-QPID_LIBS=$QPID_HOME/lib/qpid-incubating.jar
+QPID_LIBS=$QPID_HOME/lib/qpid-all.jar
# Set other variables used by the qpid-run script before calling
export JAVA=java \
diff --git a/java/testkit/bin/run_pub.sh b/java/tools/bin/run_pub.sh
index 0702a55de9..0702a55de9 100644
--- a/java/testkit/bin/run_pub.sh
+++ b/java/tools/bin/run_pub.sh
diff --git a/java/testkit/bin/run_sub.sh b/java/tools/bin/run_sub.sh
index f7e687de38..f7e687de38 100644
--- a/java/testkit/bin/run_sub.sh
+++ b/java/tools/bin/run_sub.sh
diff --git a/java/tools/bin/setenv.sh b/java/tools/bin/setenv.sh
new file mode 100644
index 0000000000..24135e711b
--- /dev/null
+++ b/java/tools/bin/setenv.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Compiles the test classes and sets the CLASSPATH
+
+# check for QPID_TEST_HOME
+if [ "$QPID_TEST_HOME" = "" ] ; then
+ echo "ERROR: Please set QPID_TEST_HOME ...."
+ exit 1
+fi
+
+# check for JAVA_HOME
+if [ "$JAVA_HOME" = "" ] ; then
+ echo "ERROR: Please set JAVA_HOME ...."
+ exit 1
+fi
+
+# VENDOR_LIB path needs to be set
+# for Qpid set this to {qpid_checkout}/java/build/lib
+if [ "$VENDOR_LIB" = "" ] ; then
+ echo "ERROR: Please set VENDOR_LIB path in the script ...."
+ exit 1
+fi
+
+
+[ -d $QPID_TEST_HOME/classes ] || mkdir $QPID_TEST_HOME/classes
+
+CLASSPATH=`find $VENDOR_LIB -name *.jar* | tr '\n' ":"`
+$JAVA_HOME/bin/javac -cp $CLASSPATH -d $QPID_TEST_HOME/classes -sourcepath $QPID_TEST_HOME/src `find $QPID_TEST_HOME/src -name '*.java'`
+
+export CLASSPATH=$QPID_TEST_HOME/classes:$CLASSPATH
+
diff --git a/java/tools/src/main/java/org/apache/qpid/tools/JNDICheck.java b/java/tools/src/main/java/org/apache/qpid/tools/JNDICheck.java
index 9ead0c19f2..2390516ef0 100644
--- a/java/tools/src/main/java/org/apache/qpid/tools/JNDICheck.java
+++ b/java/tools/src/main/java/org/apache/qpid/tools/JNDICheck.java
@@ -187,7 +187,7 @@ public class JNDICheck
print("ConnectionURL:");
print(factory.getConnectionURL().toString());
print("FailoverPolicy");
- print(new FailoverPolicy(factory.getConnectionURL()).toString());
+ print(new FailoverPolicy(factory.getConnectionURL(),null).toString());
print("");
}
}
diff --git a/java/tools/src/main/java/org/apache/qpid/tools/LatencyTest.java b/java/tools/src/main/java/org/apache/qpid/tools/LatencyTest.java
new file mode 100644
index 0000000000..b88b242e6d
--- /dev/null
+++ b/java/tools/src/main/java/org/apache/qpid/tools/LatencyTest.java
@@ -0,0 +1,349 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.tools;
+
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.jms.BytesMessage;
+import javax.jms.DeliveryMode;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.TextMessage;
+
+import org.apache.qpid.thread.Threading;
+
+/**
+ * Latency test sends an x number of messages in warmup mode and wait for a confirmation
+ * from the consumer that it has successfully consumed them and ready to start the
+ * test. It will start sending y number of messages and each message will contain a time
+ * stamp. This will be used at the receiving end to measure the latency.
+ *
+ * It is important to have a sufficiently large number for the warmup count to
+ * ensure the system is in steady state before the test is started.
+ *
+ * If you plan to plot the latencies then msg_count should be a smaller number (ex 500 or 1000)
+ * You also need to specify a file name using -Dfile=/home/rajith/latency.log.1
+ *
+ * The idea is to get a latency sample for the system once it achieves steady state.
+ *
+ */
+
+public class LatencyTest extends PerfBase implements MessageListener
+{
+ MessageProducer producer;
+ MessageConsumer consumer;
+ Message msg;
+ byte[] payload;
+ long maxLatency = 0;
+ long minLatency = Long.MAX_VALUE;
+ long totalLatency = 0; // to calculate avg latency.
+ int rcvdMsgCount = 0;
+ double stdDev = 0;
+ double avgLatency = 0;
+ boolean warmup_mode = true;
+ boolean transacted = false;
+ int transSize = 0;
+
+ final List<Long> latencies;
+ final Lock lock = new ReentrantLock();
+ final Condition warmedUp;
+ final Condition testCompleted;
+
+ public LatencyTest()
+ {
+ super();
+ warmedUp = lock.newCondition();
+ testCompleted = lock.newCondition();
+ // Storing the following two for efficiency
+ transacted = params.isTransacted();
+ transSize = params.getTransactionSize();
+ latencies = new ArrayList <Long>(params.getMsgCount());
+ }
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ consumer = session.createConsumer(dest);
+ consumer.setMessageListener(this);
+
+ // if message caching is enabled we pre create the message
+ // else we pre create the payload
+ if (params.isCacheMessage())
+ {
+ msg = MessageFactory.createBytesMessage(session, params.getMsgSize());
+ msg.setJMSDeliveryMode(params.isDurable()?
+ DeliveryMode.PERSISTENT :
+ DeliveryMode.NON_PERSISTENT
+ );
+ }
+ else
+ {
+ payload = MessageFactory.createMessagePayload(params.getMsgSize()).getBytes();
+ }
+
+ producer = session.createProducer(dest);
+ producer.setDisableMessageID(params.isDisableMessageID());
+ producer.setDisableMessageTimestamp(params.isDisableTimestamp());
+ }
+
+ protected Message getNextMessage() throws Exception
+ {
+ if (params.isCacheMessage())
+ {
+ return msg;
+ }
+ else
+ {
+ msg = session.createBytesMessage();
+ ((BytesMessage)msg).writeBytes(payload);
+ return msg;
+ }
+ }
+
+ public void warmup()throws Exception
+ {
+ System.out.println("Warming up......");
+ int count = params.getWarmupCount();
+ for (int i=0; i < count; i++)
+ {
+ producer.send(getNextMessage());
+ }
+ Message msg = session.createTextMessage("End");
+ producer.send(msg);
+
+ if (params.isTransacted())
+ {
+ session.commit();
+ }
+
+ try
+ {
+ lock.lock();
+ warmedUp.await();
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+
+ public void onMessage(Message msg)
+ {
+ try
+ {
+ if (msg instanceof TextMessage && ((TextMessage)msg).getText().equals("End"))
+ {
+ if (warmup_mode)
+ {
+ warmup_mode = false;
+ try
+ {
+ lock.lock();
+ warmedUp.signal();
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+ else
+ {
+ computeStats();
+ }
+ }
+ else if (!warmup_mode)
+ {
+ long time = System.currentTimeMillis();
+ rcvdMsgCount ++;
+
+ if (transacted && (rcvdMsgCount % transSize == 0))
+ {
+ session.commit();
+ }
+
+ long latency = time - msg.getJMSTimestamp();
+ latencies.add(latency);
+ totalLatency = totalLatency + latency;
+ }
+
+ }
+ catch(Exception e)
+ {
+ handleError(e,"Error when receiving messages");
+ }
+
+ }
+
+ private void computeStats()
+ {
+ avgLatency = (double)totalLatency/(double)rcvdMsgCount;
+ double sigma = 0;
+
+ for (long latency: latencies)
+ {
+ maxLatency = Math.max(maxLatency, latency);
+ minLatency = Math.min(minLatency, latency);
+ sigma = sigma + Math.pow(latency - avgLatency,2);
+ }
+
+ stdDev = Math.sqrt(sigma/(rcvdMsgCount -1));
+
+ try
+ {
+ lock.lock();
+ testCompleted.signal();
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+
+ public void writeToFile() throws Exception
+ {
+ String fileName = System.getProperty("file");
+ PrintWriter writer = new PrintWriter(new FileOutputStream(fileName));
+ for (long latency: latencies)
+ {
+ writer.println(String.valueOf(latency));
+ }
+ writer.flush();
+ writer.close();
+ }
+
+ public void printToConsole()
+ {
+ System.out.println(new StringBuilder("Total Msgs Received : ").append(rcvdMsgCount).toString());
+ System.out.println(new StringBuilder("Standard Deviation : ").
+ append(df.format(stdDev)).
+ append(" ms").toString());
+ System.out.println(new StringBuilder("Avg Latency : ").
+ append(df.format(avgLatency)).
+ append(" ms").toString());
+ System.out.println(new StringBuilder("Min Latency : ").
+ append(minLatency).
+ append(" ms").toString());
+ System.out.println(new StringBuilder("Max Latency : ").
+ append(maxLatency).
+ append(" ms").toString());
+ System.out.println("Completed the test......\n");
+ }
+
+ public void startTest() throws Exception
+ {
+ System.out.println("Starting test......");
+ int count = params.getMsgCount();
+
+ for(int i=0; i < count; i++ )
+ {
+ Message msg = getNextMessage();
+ msg.setJMSTimestamp(System.currentTimeMillis());
+ producer.send(msg);
+ if ( transacted && ((i+1) % transSize == 0))
+ {
+ session.commit();
+ }
+ }
+ Message msg = session.createTextMessage("End");
+ producer.send(msg);
+ if (params.isTransacted())
+ {
+ session.commit();
+ }
+ }
+
+ public void tearDown() throws Exception
+ {
+ try
+ {
+ lock.lock();
+ testCompleted.await();
+ }
+ finally
+ {
+ lock.unlock();
+ }
+
+ producer.close();
+ consumer.close();
+ session.close();
+ con.close();
+ }
+
+ public void test()
+ {
+ try
+ {
+ setUp();
+ warmup();
+ startTest();
+ tearDown();
+ }
+ catch(Exception e)
+ {
+ handleError(e,"Error when running test");
+ }
+ }
+
+
+ public static void main(String[] args)
+ {
+ final LatencyTest latencyTest = new LatencyTest();
+ Runnable r = new Runnable()
+ {
+ public void run()
+ {
+ latencyTest.test();
+ latencyTest.printToConsole();
+ if (System.getProperty("file") != null)
+ {
+ try
+ {
+ latencyTest.writeToFile();
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+ };
+
+ Thread t;
+ try
+ {
+ t = Threading.getThreadFactory().createThread(r);
+ }
+ catch(Exception e)
+ {
+ throw new Error("Error creating latency test thread",e);
+ }
+ t.start();
+ }
+} \ No newline at end of file
diff --git a/java/tools/src/main/java/org/apache/qpid/tools/MessageFactory.java b/java/tools/src/main/java/org/apache/qpid/tools/MessageFactory.java
new file mode 100644
index 0000000000..8ab1379fce
--- /dev/null
+++ b/java/tools/src/main/java/org/apache/qpid/tools/MessageFactory.java
@@ -0,0 +1,64 @@
+package org.apache.qpid.tools;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+import javax.jms.BytesMessage;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+public class MessageFactory
+{
+ public static Message createBytesMessage(Session ssn, int size) throws JMSException
+ {
+ BytesMessage msg = ssn.createBytesMessage();
+ msg.writeBytes(createMessagePayload(size).getBytes());
+ return msg;
+ }
+
+ public static Message createTextMessage(Session ssn, int size) throws JMSException
+ {
+ TextMessage msg = ssn.createTextMessage();
+ msg.setText(createMessagePayload(size));
+ return msg;
+ }
+
+ public static String createMessagePayload(int size)
+ {
+ String msgData = "Qpid Test Message";
+
+ StringBuffer buf = new StringBuffer(size);
+ int count = 0;
+ while (count <= (size - msgData.length()))
+ {
+ buf.append(msgData);
+ count += msgData.length();
+ }
+ if (count < size)
+ {
+ buf.append(msgData, 0, size - count);
+ }
+
+ return buf.toString();
+ }
+}
diff --git a/java/tools/src/main/java/org/apache/qpid/tools/PerfBase.java b/java/tools/src/main/java/org/apache/qpid/tools/PerfBase.java
new file mode 100644
index 0000000000..88e75fb6a9
--- /dev/null
+++ b/java/tools/src/main/java/org/apache/qpid/tools/PerfBase.java
@@ -0,0 +1,102 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.tools;
+
+import java.text.DecimalFormat;
+import java.util.Hashtable;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.Session;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+
+public class PerfBase
+{
+ TestParams params;
+ Connection con;
+ Session session;
+ Destination dest;
+ Destination feedbackDest;
+ DecimalFormat df = new DecimalFormat("###.##");
+
+ public PerfBase()
+ {
+ params = new TestParams();
+ }
+
+ public void setUp() throws Exception
+ {
+ Hashtable<String,String> env = new Hashtable<String,String>();
+ env.put(Context.INITIAL_CONTEXT_FACTORY, params.getInitialContextFactory());
+ env.put(Context.PROVIDER_URL, params.getProviderURL());
+
+ Context ctx = null;
+ try
+ {
+ ctx = new InitialContext(env);
+ }
+ catch(Exception e)
+ {
+ throw new Exception("Error initializing JNDI",e);
+
+ }
+
+ ConnectionFactory conFac = null;
+ try
+ {
+ conFac = (ConnectionFactory)ctx.lookup(params.getConnectionFactory());
+ }
+ catch(Exception e)
+ {
+ throw new Exception("Error looking up connection factory",e);
+ }
+
+ con = conFac.createConnection();
+ con.start();
+ session = con.createSession(params.isTransacted(),
+ params.isTransacted()? Session.SESSION_TRANSACTED:params.getAckMode());
+
+ try
+ {
+ dest = (Destination)ctx.lookup( params.isDurable()?
+ params.getDurableDestination():
+ params.getTransientDestination()
+ );
+ }
+ catch(Exception e)
+ {
+ throw new Exception("Error looking up destination",e);
+ }
+ }
+
+ public void handleError(Exception e,String msg)
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append(msg);
+ sb.append(" ");
+ sb.append(e.getMessage());
+ System.err.println(sb.toString());
+ e.printStackTrace();
+ }
+}
+
diff --git a/java/tools/src/main/java/org/apache/qpid/tools/PerfConsumer.java b/java/tools/src/main/java/org/apache/qpid/tools/PerfConsumer.java
new file mode 100644
index 0000000000..0ef0455a64
--- /dev/null
+++ b/java/tools/src/main/java/org/apache/qpid/tools/PerfConsumer.java
@@ -0,0 +1,267 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.tools;
+
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.TextMessage;
+
+import org.apache.qpid.thread.Threading;
+
+/**
+ * PerfConsumer will receive x no of messages in warmup mode.
+ * Once it receives the Start message it will then signal the PerfProducer.
+ * It will start recording stats from the first message it receives after
+ * the warmup mode is done.
+ *
+ * The following calculations are done.
+ * The important numbers to look at is
+ * a) Avg Latency
+ * b) System throughput.
+ *
+ * Latency.
+ * =========
+ * Currently this test is written with the assumption that either
+ * a) The Perf Producer and Consumer are on the same machine
+ * b) They are on separate machines that have their time synced via a Time Server
+ *
+ * In order to calculate latency the producer inserts a timestamp
+ * hen the message is sent. The consumer will note the current time the message is
+ * received and will calculate the latency as follows
+ * latency = rcvdTime - msg.getJMSTimestamp()
+ *
+ * Through out the test it will keep track of the max and min latency to show the
+ * variance in latencies.
+ *
+ * Avg latency is measured by adding all latencies and dividing by the total msgs.
+ * You can also compute this by (rcvdTime - testStartTime)/rcvdMsgCount
+ *
+ * Throughput
+ * ===========
+ * System throughput is calculated as follows
+ * rcvdMsgCount/(rcvdTime - testStartTime)
+ *
+ * Consumer rate is calculated as
+ * rcvdMsgCount/(rcvdTime - startTime)
+ *
+ * Note that the testStartTime referes to when the producer sent the first message
+ * and startTime is when the consumer first received a message.
+ *
+ * rcvdTime keeps track of when the last message is received.
+ *
+ * All throughput rates are given as msg/sec so the rates are multiplied by 1000.
+ *
+ */
+
+public class PerfConsumer extends PerfBase implements MessageListener
+{
+ MessageConsumer consumer;
+ long maxLatency = 0;
+ long minLatency = Long.MAX_VALUE;
+ long totalLatency = 0; // to calculate avg latency.
+ int rcvdMsgCount = 0;
+ long testStartTime = 0; // to measure system throughput
+ long startTime = 0; // to measure consumer throughput
+ long rcvdTime = 0;
+ boolean transacted = false;
+ int transSize = 0;
+
+ final Object lock = new Object();
+
+ public PerfConsumer()
+ {
+ super();
+ }
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ consumer = session.createConsumer(dest);
+
+ // Storing the following two for efficiency
+ transacted = params.isTransacted();
+ transSize = params.getTransactionSize();
+ }
+
+ public void warmup()throws Exception
+ {
+ System.out.println("Warming up......");
+
+ boolean start = false;
+ while (!start)
+ {
+ Message msg = consumer.receive();
+ if (msg instanceof TextMessage)
+ {
+ if (((TextMessage)msg).getText().equals("End"))
+ {
+ start = true;
+ MessageProducer temp = session.createProducer(msg.getJMSReplyTo());
+ temp.send(session.createMessage());
+ if (params.isTransacted())
+ {
+ session.commit();
+ }
+ temp.close();
+ }
+ }
+ }
+ }
+
+ public void startTest() throws Exception
+ {
+ System.out.println("Starting test......");
+ consumer.setMessageListener(this);
+ }
+
+ public void printResults() throws Exception
+ {
+ synchronized (lock)
+ {
+ lock.wait();
+ }
+
+ double avgLatency = (double)totalLatency/(double)rcvdMsgCount;
+ double throughput = ((double)rcvdMsgCount/(double)(rcvdTime - testStartTime))*1000;
+ double consRate = ((double)rcvdMsgCount/(double)(rcvdTime - startTime))*1000;
+ System.out.println(new StringBuilder("Total Msgs Received : ").append(rcvdMsgCount).toString());
+ System.out.println(new StringBuilder("Consumer rate : ").
+ append(df.format(consRate)).
+ append(" msg/sec").toString());
+ System.out.println(new StringBuilder("System Throughput : ").
+ append(df.format(throughput)).
+ append(" msg/sec").toString());
+ System.out.println(new StringBuilder("Avg Latency : ").
+ append(df.format(avgLatency)).
+ append(" ms").toString());
+ System.out.println(new StringBuilder("Min Latency : ").
+ append(minLatency).
+ append(" ms").toString());
+ System.out.println(new StringBuilder("Max Latency : ").
+ append(maxLatency).
+ append(" ms").toString());
+ System.out.println("Completed the test......\n");
+ }
+
+ public void notifyCompletion(Destination replyTo) throws Exception
+ {
+ MessageProducer tmp = session.createProducer(replyTo);
+ Message endMsg = session.createMessage();
+ tmp.send(endMsg);
+ if (params.isTransacted())
+ {
+ session.commit();
+ }
+ tmp.close();
+ }
+
+ public void tearDown() throws Exception
+ {
+ consumer.close();
+ session.close();
+ con.close();
+ }
+
+ public void onMessage(Message msg)
+ {
+ try
+ {
+ if (msg instanceof TextMessage && ((TextMessage)msg).getText().equals("End"))
+ {
+ notifyCompletion(msg.getJMSReplyTo());
+
+ synchronized (lock)
+ {
+ lock.notifyAll();
+ }
+ }
+ else
+ {
+ rcvdTime = System.currentTimeMillis();
+ rcvdMsgCount ++;
+
+ if (rcvdMsgCount == 1)
+ {
+ startTime = rcvdTime;
+ testStartTime = msg.getJMSTimestamp();
+ }
+
+ if (transacted && (rcvdMsgCount % transSize == 0))
+ {
+ session.commit();
+ }
+
+ long latency = rcvdTime - msg.getJMSTimestamp();
+ maxLatency = Math.max(maxLatency, latency);
+ minLatency = Math.min(minLatency, latency);
+ totalLatency = totalLatency + latency;
+ }
+
+ }
+ catch(Exception e)
+ {
+ handleError(e,"Error when receiving messages");
+ }
+
+ }
+
+ public void test()
+ {
+ try
+ {
+ setUp();
+ warmup();
+ startTest();
+ printResults();
+ tearDown();
+ }
+ catch(Exception e)
+ {
+ handleError(e,"Error when running test");
+ }
+ }
+
+ public static void main(String[] args)
+ {
+ final PerfConsumer cons = new PerfConsumer();
+ Runnable r = new Runnable()
+ {
+ public void run()
+ {
+ cons.test();
+ }
+ };
+
+ Thread t;
+ try
+ {
+ t = Threading.getThreadFactory().createThread(r);
+ }
+ catch(Exception e)
+ {
+ throw new Error("Error creating consumer thread",e);
+ }
+ t.start();
+ }
+} \ No newline at end of file
diff --git a/java/tools/src/main/java/org/apache/qpid/tools/PerfProducer.java b/java/tools/src/main/java/org/apache/qpid/tools/PerfProducer.java
new file mode 100644
index 0000000000..015d1e6205
--- /dev/null
+++ b/java/tools/src/main/java/org/apache/qpid/tools/PerfProducer.java
@@ -0,0 +1,262 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.tools;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import javax.jms.BytesMessage;
+import javax.jms.DeliveryMode;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+
+import org.apache.qpid.thread.Threading;
+
+/**
+ * PerfProducer sends an x no of messages in warmup mode and wait for a confirmation
+ * from the consumer that it has successfully consumed them and ready to start the
+ * test. It will start sending y no of messages and each message will contain a time
+ * stamp. This will be used at the receiving end to measure the latency.
+ *
+ * This is done with the assumption that both consumer and producer are running on
+ * the same machine or different machines which have time synced using a time server.
+ *
+ * This test also calculates the producer rate as follows.
+ * rate = msg_count/(time_before_sending_msgs - time_after_sending_msgs)
+ *
+ * All throughput rates are given as msg/sec so the rates are multiplied by 1000.
+ *
+ * Rajith - Producer rate is not an accurate perf metric IMO.
+ * It is heavily inlfuenced by any in memory buffering.
+ * System throughput and latencies calculated by the PerfConsumer are more realistic
+ * numbers.
+ *
+ */
+public class PerfProducer extends PerfBase
+{
+ MessageProducer producer;
+ Message msg;
+ byte[] payload;
+ List<byte[]> payloads;
+ boolean cacheMsg = false;
+ boolean randomMsgSize = false;
+ boolean durable = false;
+ Random random;
+ int msgSizeRange = 1024;
+
+ public PerfProducer()
+ {
+ super();
+ }
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ feedbackDest = session.createTemporaryQueue();
+
+ durable = params.isDurable();
+
+ // if message caching is enabled we pre create the message
+ // else we pre create the payload
+ if (params.isCacheMessage())
+ {
+ cacheMsg = true;
+
+ msg = MessageFactory.createBytesMessage(session, params.getMsgSize());
+ msg.setJMSDeliveryMode(durable?
+ DeliveryMode.PERSISTENT :
+ DeliveryMode.NON_PERSISTENT
+ );
+ }
+ else if (params.isRandomMsgSize())
+ {
+ random = new Random(20080921);
+ randomMsgSize = true;
+ msgSizeRange = params.getMsgSize();
+ payloads = new ArrayList<byte[]>(msgSizeRange);
+
+ for (int i=0; i < msgSizeRange; i++)
+ {
+ payloads.add(MessageFactory.createMessagePayload(i).getBytes());
+ }
+ }
+ else
+ {
+ payload = MessageFactory.createMessagePayload(params.getMsgSize()).getBytes();
+ }
+
+ producer = session.createProducer(dest);
+ producer.setDisableMessageID(params.isDisableMessageID());
+ producer.setDisableMessageTimestamp(params.isDisableTimestamp());
+ }
+
+ protected Message getNextMessage() throws Exception
+ {
+ if (cacheMsg)
+ {
+ return msg;
+ }
+ else
+ {
+ msg = session.createBytesMessage();
+
+ if (!randomMsgSize)
+ {
+ ((BytesMessage)msg).writeBytes(payload);
+ }
+ else
+ {
+ ((BytesMessage)msg).writeBytes(payloads.get(random.nextInt(msgSizeRange)));
+ }
+ msg.setJMSDeliveryMode(durable?
+ DeliveryMode.PERSISTENT :
+ DeliveryMode.NON_PERSISTENT
+ );
+ return msg;
+ }
+ }
+
+ public void warmup()throws Exception
+ {
+ System.out.println("Warming up......");
+ MessageConsumer tmp = session.createConsumer(feedbackDest);
+
+ for (int i=0; i < params.getWarmupCount() -1; i++)
+ {
+ producer.send(getNextMessage());
+ }
+ Message msg = session.createTextMessage("End");
+ msg.setJMSReplyTo(feedbackDest);
+ producer.send(msg);
+
+ if (params.isTransacted())
+ {
+ session.commit();
+ }
+
+ tmp.receive();
+
+ if (params.isTransacted())
+ {
+ session.commit();
+ }
+
+ tmp.close();
+ }
+
+ public void startTest() throws Exception
+ {
+ System.out.println("Starting test......");
+ int count = params.getMsgCount();
+ boolean transacted = params.isTransacted();
+ int tranSize = params.getTransactionSize();
+
+ long start = System.currentTimeMillis();
+ for(int i=0; i < count; i++ )
+ {
+ Message msg = getNextMessage();
+ msg.setJMSTimestamp(System.currentTimeMillis());
+ producer.send(msg);
+ if ( transacted && ((i+1) % tranSize == 0))
+ {
+ session.commit();
+ }
+ }
+ long time = System.currentTimeMillis() - start;
+ double rate = ((double)count/(double)time)*1000;
+ System.out.println(new StringBuilder("Producer rate: ").
+ append(df.format(rate)).
+ append(" msg/sec").
+ toString());
+ }
+
+ public void waitForCompletion() throws Exception
+ {
+ MessageConsumer tmp = session.createConsumer(feedbackDest);
+ Message msg = session.createTextMessage("End");
+ msg.setJMSReplyTo(feedbackDest);
+ producer.send(msg);
+
+ if (params.isTransacted())
+ {
+ session.commit();
+ }
+
+ tmp.receive();
+
+ if (params.isTransacted())
+ {
+ session.commit();
+ }
+
+ tmp.close();
+ System.out.println("Consumer has completed the test......");
+ }
+
+ public void tearDown() throws Exception
+ {
+ producer.close();
+ session.close();
+ con.close();
+ }
+
+ public void test()
+ {
+ try
+ {
+ setUp();
+ warmup();
+ startTest();
+ waitForCompletion();
+ tearDown();
+ }
+ catch(Exception e)
+ {
+ handleError(e,"Error when running test");
+ }
+ }
+
+
+ public static void main(String[] args)
+ {
+ final PerfProducer prod = new PerfProducer();
+ Runnable r = new Runnable()
+ {
+ public void run()
+ {
+ prod.test();
+ }
+ };
+
+ Thread t;
+ try
+ {
+ t = Threading.getThreadFactory().createThread(r);
+ }
+ catch(Exception e)
+ {
+ throw new Error("Error creating producer thread",e);
+ }
+ t.start();
+ }
+} \ No newline at end of file
diff --git a/java/tools/src/main/java/org/apache/qpid/tools/QpidBench.java b/java/tools/src/main/java/org/apache/qpid/tools/QpidBench.java
index 181cf427d1..602fcc6321 100644
--- a/java/tools/src/main/java/org/apache/qpid/tools/QpidBench.java
+++ b/java/tools/src/main/java/org/apache/qpid/tools/QpidBench.java
@@ -20,23 +20,45 @@
*/
package org.apache.qpid.tools;
-import java.lang.reflect.InvocationTargetException;
+import static org.apache.qpid.tools.QpidBench.Mode.BOTH;
+import static org.apache.qpid.tools.QpidBench.Mode.CONSUME;
+import static org.apache.qpid.tools.QpidBench.Mode.PUBLISH;
+
import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
-import java.util.UUID;
-import javax.jms.*;
+
+import javax.jms.DeliveryMode;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.TextMessage;
import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.transport.*;
-import org.apache.qpid.transport.network.io.IoTransport;
+import org.apache.qpid.thread.Threading;
+import org.apache.qpid.transport.DeliveryProperties;
+import org.apache.qpid.transport.ExchangeBind;
+import org.apache.qpid.transport.Header;
+import org.apache.qpid.transport.MessageAcceptMode;
+import org.apache.qpid.transport.MessageAcquireMode;
+import org.apache.qpid.transport.MessageCreditUnit;
+import org.apache.qpid.transport.MessageDeliveryMode;
+import org.apache.qpid.transport.MessageFlowMode;
+import org.apache.qpid.transport.MessageProperties;
+import org.apache.qpid.transport.MessageSubscribe;
+import org.apache.qpid.transport.MessageTransfer;
+import org.apache.qpid.transport.QueueDeclare;
+import org.apache.qpid.transport.SessionException;
+import org.apache.qpid.transport.SessionListener;
import org.apache.qpid.util.UUIDGen;
import org.apache.qpid.util.UUIDs;
-import static org.apache.qpid.tools.QpidBench.Mode.*;
-
/**
* QpidBench
*
@@ -412,7 +434,7 @@ public class QpidBench
{
case CONSUME:
case BOTH:
- new Thread()
+ Runnable r = new Runnable()
{
public void run()
{
@@ -431,8 +453,20 @@ public class QpidBench
{
throw new RuntimeException(e);
}
+ System.out.println("Consumer Completed");
}
- }.start();
+ };
+
+ Thread t;
+ try
+ {
+ t = Threading.getThreadFactory().createThread(r);
+ }
+ catch(Exception e)
+ {
+ throw new Error("Error creating consumer thread",e);
+ }
+ t.start();
break;
}
@@ -440,7 +474,7 @@ public class QpidBench
{
case PUBLISH:
case BOTH:
- new Thread()
+ Runnable r = new Runnable()
{
public void run()
{
@@ -459,8 +493,19 @@ public class QpidBench
{
throw new RuntimeException(e);
}
+ System.out.println("Producer Completed");
}
- }.start();
+ };
+ Thread t;
+ try
+ {
+ t = Threading.getThreadFactory().createThread(r);
+ }
+ catch(Exception e)
+ {
+ throw new Error("Error creating publisher thread",e);
+ }
+ t.start();
break;
}
}
@@ -640,71 +685,49 @@ public class QpidBench
}
private static final org.apache.qpid.transport.Connection getConnection
- (Options opts, final SessionDelegate delegate)
+ (Options opts)
{
- final Object lock = new Object();
org.apache.qpid.transport.Connection conn =
- IoTransport.connect(opts.broker, opts.port,
- new ClientDelegate()
- {
- public SessionDelegate getSessionDelegate()
- {
- return delegate;
- }
- public void exception(Throwable t)
- {
- t.printStackTrace();
- }
- public void closed() {}
- @Override public void connectionOpenOk(Channel ch,
- ConnectionOpenOk ok)
- {
- synchronized (lock)
- {
- lock.notify();
- }
- }
- });
- conn.send(new ProtocolHeader(1, 0, 10));
-
- synchronized (lock)
+ new org.apache.qpid.transport.Connection();
+ conn.connect(opts.broker, opts.port, null, "guest", "guest",false);
+ return conn;
+ }
+
+ private static abstract class NativeListener implements SessionListener
+ {
+
+ public void opened(org.apache.qpid.transport.Session ssn) {}
+
+ public void resumed(org.apache.qpid.transport.Session ssn) {}
+
+ public void exception(org.apache.qpid.transport.Session ssn,
+ SessionException exc)
{
- try
- {
- lock.wait();
- }
- catch (InterruptedException e)
- {
- throw new RuntimeException(e);
- }
+ exc.printStackTrace();
}
- return conn;
+ public void closed(org.apache.qpid.transport.Session ssn) {}
+
}
private static final void native_publisher(Options opts) throws Exception
{
final long[] echos = { 0 };
- org.apache.qpid.transport.Connection conn = getConnection
- (opts,
- new SessionDelegate() {
- @Override public void messageTransfer
- (org.apache.qpid.transport.Session ssn,
- MessageTransfer mt)
- {
- synchronized (echos)
- {
- echos[0]++;
- echos.notify();
- }
- ssn.processed(mt);
- }
- });
-
- Channel ch = conn.getChannel(0);
- org.apache.qpid.transport.Session ssn = new org.apache.qpid.transport.Session("spam-session".getBytes());
- ssn.attach(ch);
- ssn.sessionAttach(ssn.getName());
+ org.apache.qpid.transport.Connection conn = getConnection(opts);
+ org.apache.qpid.transport.Session ssn = conn.createSession();
+ ssn.setSessionListener(new NativeListener()
+ {
+ public void message(org.apache.qpid.transport.Session ssn,
+ MessageTransfer xfr)
+ {
+ synchronized (echos)
+ {
+ echos[0]++;
+ echos.notify();
+ }
+ ssn.processed(xfr);
+ }
+ });
ssn.invoke(new QueueDeclare().queue("test-queue").durable(false));
ssn.invoke(new QueueDeclare().queue("echo-queue").durable(false));
@@ -794,6 +817,7 @@ public class QpidBench
ssn.messageCancel("echo-queue");
ssn.sync();
+ ssn.close();
conn.close();
}
@@ -805,57 +829,51 @@ public class QpidBench
dp.setDeliveryMode(MessageDeliveryMode.NON_PERSISTENT);
final MessageProperties mp = new MessageProperties();
final Object done = new Object();
- org.apache.qpid.transport.Connection conn = getConnection
- (opts,
- new SessionDelegate() {
-
- private long count = 0;
- private long lastTime = 0;
- private long start;
-
- @Override public void messageTransfer
- (org.apache.qpid.transport.Session ssn,
- MessageTransfer mt)
- {
- if (count == 0)
- {
- start = System.currentTimeMillis();
- }
-
- boolean sample = opts.sample > 0 && (count % opts.sample) == 0;
- long time = sample ? System.currentTimeMillis() : 0;
-
- if (opts.window > 0 && (count % opts.window) == 0)
- {
- ssn.messageTransfer("amq.direct",
- MessageAcceptMode.NONE,
- MessageAcquireMode.PRE_ACQUIRED,
- new Header(dp, mp),
- echo);
- }
-
- if (sample)
- {
- sample(opts, Column.RIGHT, "NC", count, start, time, lastTime);
- lastTime = time;
- }
- ssn.processed(mt);
- count++;
-
- if (opts.count > 0 && count >= opts.count)
- {
- synchronized (done)
- {
- done.notify();
- }
- }
- }
- });
-
- Channel ch = conn.getChannel(0);
- org.apache.qpid.transport.Session ssn = new org.apache.qpid.transport.Session("listener-session".getBytes());
- ssn.attach(ch);
- ssn.sessionAttach(ssn.getName());
+ org.apache.qpid.transport.Connection conn = getConnection(opts);
+ org.apache.qpid.transport.Session ssn = conn.createSession();
+ ssn.setSessionListener(new NativeListener()
+ {
+ private long count = 0;
+ private long lastTime = 0;
+ private long start;
+
+ public void message(org.apache.qpid.transport.Session ssn,
+ MessageTransfer xfr)
+ {
+ if (count == 0)
+ {
+ start = System.currentTimeMillis();
+ }
+
+ boolean sample = opts.sample > 0 && (count % opts.sample) == 0;
+ long time = sample ? System.currentTimeMillis() : 0;
+
+ if (opts.window > 0 && (count % opts.window) == 0)
+ {
+ ssn.messageTransfer("amq.direct",
+ MessageAcceptMode.NONE,
+ MessageAcquireMode.PRE_ACQUIRED,
+ new Header(dp, mp),
+ echo);
+ }
+
+ if (sample)
+ {
+ sample(opts, Column.RIGHT, "NC", count, start, time, lastTime);
+ lastTime = time;
+ }
+ ssn.processed(xfr);
+ count++;
+
+ if (opts.count > 0 && count >= opts.count)
+ {
+ synchronized (done)
+ {
+ done.notify();
+ }
+ }
+ }
+ });
ssn.invoke(new QueueDeclare().queue("test-queue").durable(false));
ssn.invoke(new QueueDeclare().queue("echo-queue").durable(false));
@@ -879,6 +897,7 @@ public class QpidBench
ssn.messageCancel("test-queue");
ssn.sync();
+ ssn.close();
conn.close();
}
diff --git a/java/tools/src/main/java/org/apache/qpid/tools/TestParams.java b/java/tools/src/main/java/org/apache/qpid/tools/TestParams.java
new file mode 100644
index 0000000000..f1b682ff32
--- /dev/null
+++ b/java/tools/src/main/java/org/apache/qpid/tools/TestParams.java
@@ -0,0 +1,168 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.tools;
+
+import javax.jms.Session;
+
+public class TestParams
+{
+ private String initialContextFactory = "org.apache.qpid.jndi.PropertiesFileInitialContextFactory";
+
+ private String providerURL = System.getenv("QPID_TEST_HOME") + "/etc/jndi.properties";
+
+ private String connectionFactory = "connectionFactory";
+
+ private String transientDest = "transientQueue";
+
+ private String durableDest = "durableQueue";
+
+ private int msg_size = 1024;
+
+ private int msg_type = 1; // not used yet
+
+ private boolean cacheMessage = false;
+
+ private boolean disableMessageID = false;
+
+ private boolean disableTimestamp = false;
+
+ private boolean durable = false;
+
+ private boolean transacted = false;
+
+ private int transaction_size = 1000;
+
+ private int ack_mode = Session.AUTO_ACKNOWLEDGE;
+
+ private int msg_count = 10;
+
+ private int warmup_count = 1;
+
+ private boolean random_msg_size = false;
+
+ public TestParams()
+ {
+ initialContextFactory = System.getProperty("java.naming.factory.initial",initialContextFactory);
+ providerURL = System.getProperty("java.naming.provider.url",providerURL);
+
+ transientDest = System.getProperty("transDest",transientDest);
+ durableDest = System.getProperty("durableDest",durableDest);
+
+ msg_size = Integer.getInteger("msg_size", 1024);
+ msg_type = Integer.getInteger("msg_type",1);
+ cacheMessage = Boolean.getBoolean("cache_msg");
+ disableMessageID = Boolean.getBoolean("disableMessageID");
+ disableTimestamp = Boolean.getBoolean("disableTimestamp");
+ durable = Boolean.getBoolean("durable");
+ transacted = Boolean.getBoolean("transacted");
+ transaction_size = Integer.getInteger("trans_size",1000);
+ ack_mode = Integer.getInteger("ack_mode",Session.AUTO_ACKNOWLEDGE);
+ msg_count = Integer.getInteger("msg_count",msg_count);
+ warmup_count = Integer.getInteger("warmup_count",warmup_count);
+ random_msg_size = Boolean.getBoolean("random_msg_size");
+ }
+
+ public int getAckMode()
+ {
+ return ack_mode;
+ }
+
+ public String getConnectionFactory()
+ {
+ return connectionFactory;
+ }
+
+ public String getTransientDestination()
+ {
+ return transientDest;
+ }
+
+ public String getDurableDestination()
+ {
+ return durableDest;
+ }
+
+ public String getInitialContextFactory()
+ {
+ return initialContextFactory;
+ }
+
+ public int getMsgCount()
+ {
+ return msg_count;
+ }
+
+ public int getMsgSize()
+ {
+ return msg_size;
+ }
+
+ public int getMsgType()
+ {
+ return msg_type;
+ }
+
+ public boolean isDurable()
+ {
+ return durable;
+ }
+
+ public String getProviderURL()
+ {
+ return providerURL;
+ }
+
+ public boolean isTransacted()
+ {
+ return transacted;
+ }
+
+ public int getTransactionSize()
+ {
+ return transaction_size;
+ }
+
+ public int getWarmupCount()
+ {
+ return warmup_count;
+ }
+
+ public boolean isCacheMessage()
+ {
+ return cacheMessage;
+ }
+
+ public boolean isDisableMessageID()
+ {
+ return disableMessageID;
+ }
+
+ public boolean isDisableTimestamp()
+ {
+ return disableTimestamp;
+ }
+
+ public boolean isRandomMsgSize()
+ {
+ return random_msg_size;
+ }
+
+}
diff --git a/python/LICENSE.txt b/python/LICENSE.txt
index 6b0b1270ff..6b0b1270ff 100755..100644
--- a/python/LICENSE.txt
+++ b/python/LICENSE.txt
diff --git a/python/Makefile b/python/Makefile
new file mode 100644
index 0000000000..7f475adc09
--- /dev/null
+++ b/python/Makefile
@@ -0,0 +1,98 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+PREFIX=/usr/local
+EXEC_PREFIX=$(PREFIX)/bin
+DATA_DIR=$(PREFIX)/share
+
+PYTHON_LIB=$(shell python -c "from distutils.sysconfig import get_python_lib; print get_python_lib(prefix='$(PREFIX)')")
+PYTHON_VERSION=$(shell python -c "from distutils.sysconfig import get_python_version; print get_python_version()")
+
+ddfirst=$(shell ddir=$(DATA_DIR) && echo $${ddir:0:1})
+ifeq ($(ddfirst),/)
+AMQP_SPEC_DIR=$(DATA_DIR)/amqp
+else
+AMQP_SPEC_DIR=$(PWD)/$(DATA_DIR)/amqp
+endif
+
+DIRS=qmf qpid mllib models examples tests tests_0-8 tests_0-9 tests_0-10
+SRCS=$(shell find $(DIRS) -name "*.py") qpid_config.py
+BUILD=build
+TARGETS=$(SRCS:%.py=$(BUILD)/%.py)
+
+PYCC=python -O -c "import compileall; compileall.main()"
+
+all: build
+
+$(BUILD)/%.py: %.py
+ @mkdir -p $(shell dirname $@)
+ ./preppy $(PYTHON_VERSION) < $< > $@
+
+build: $(TARGETS)
+
+.PHONY: doc
+
+doc:
+ @mkdir -p $(BUILD)
+ PYTHONPATH=. epydoc qpid.messaging -o $(BUILD)/doc --no-private --no-sourcecode --include-log
+
+install: build
+ install -d $(PYTHON_LIB)
+
+ install -d $(PYTHON_LIB)/mllib
+ install -pm 0644 LICENSE.txt NOTICE.txt $(BUILD)/mllib/*.* $(PYTHON_LIB)/mllib
+ $(PYCC) $(PYTHON_LIB)/mllib
+
+ install -d $(PYTHON_LIB)/qpid
+ install -pm 0644 LICENSE.txt NOTICE.txt README.txt $(BUILD)/qpid/*.* $(PYTHON_LIB)/qpid
+ TDIR=$(shell mktemp -d) && \
+ sed s@AMQP_SPEC_DIR=.*@AMQP_SPEC_DIR='"$(AMQP_SPEC_DIR)"'@ \
+ $(BUILD)/qpid_config.py > $${TDIR}/qpid_config.py && \
+ install -pm 0644 $${TDIR}/qpid_config.py $(PYTHON_LIB) && \
+ rm -rf $${TDIR}
+
+ install -d $(PYTHON_LIB)/qpid/tests
+ install -pm 0644 $(BUILD)/qpid/tests/*.* $(PYTHON_LIB)/qpid/tests
+ $(PYCC) $(PYTHON_LIB)/qpid
+
+ install -d $(PYTHON_LIB)/qmf
+ install -pm 0644 LICENSE.txt NOTICE.txt qmf/*.* $(PYTHON_LIB)/qmf
+ $(PYCC) $(PYTHON_LIB)/qmf
+
+ install -d $(PYTHON_LIB)/tests
+ install -pm 0644 $(BUILD)/tests/*.* $(PYTHON_LIB)/tests
+ $(PYCC) $(PYTHON_LIB)/tests
+
+ install -d $(PYTHON_LIB)/tests_0-8
+ install -pm 0644 $(BUILD)/tests_0-8/*.* $(PYTHON_LIB)/tests_0-8
+ $(PYCC) $(PYTHON_LIB)/tests_0-8
+
+ install -d $(PYTHON_LIB)/tests_0-9
+ install -pm 0644 $(BUILD)/tests_0-9/*.* $(PYTHON_LIB)/tests_0-9
+ $(PYCC) $(PYTHON_LIB)/tests_0-9
+
+ install -d $(PYTHON_LIB)/tests_0-10
+ install -pm 0644 $(BUILD)/tests_0-10/*.* $(PYTHON_LIB)/tests_0-10
+ $(PYCC) $(PYTHON_LIB)/tests_0-10
+
+ install -d $(EXEC_PREFIX)
+ install -pm 0755 qpid-python-test commands/* $(EXEC_PREFIX)
+
+clean:
+ rm -rf $(BUILD)
diff --git a/python/README.txt b/python/README.txt
index e7bb5af408..772271cffe 100644
--- a/python/README.txt
+++ b/python/README.txt
@@ -1,32 +1,50 @@
-= RUNNING THE PYTHON TESTS =
+= INSTALLATION =
-The tests/ directory contains a collection of python unit tests to
-exercise functions of a broker.
+Extract the release archive into a directory of your choice and set
+your PYTHONPATH accordingly:
-Simplest way to run the tests:
+ tar -xzf qpid-python-<version>.tar.gz -C <install-prefix>
+ export PYTHONPATH=<install-prefix>/qpid-<version>/python
- * Run a broker on the default port
+= GETTING STARTED =
- * ./run-tests
+The python client includes a simple hello-world example that publishes
+and consumes a message:
-For additional options: ./run-tests --help
+ cp <install-prefix>/qpid-<version>/python/hello-world .
+ ./hello-world
+= EXAMPLES =
-== Expected failures ==
+More comprehensive examples can be found here:
-Until we complete functionality, tests may fail because the tested
-functionality is missing in the broker. To skip expected failures
-in the C++ or Java brokers:
+ cd <install-prefix>/qpid-<version>/python/examples
- ./run-tests -I <file_name>
+= RUNNING THE TESTS =
-=== File List ===
+The "tests" directory contains a collection of unit tests for the
+python client. The "tests_0-10", "tests_0-9", and "tests_0-8"
+directories contain protocol level conformance tests for AMQP brokers
+of the specified version.
-1. cpp_failing_0-10.txt
-2. cpp_failing_0-9.txt
-3. cpp_failing_0-8.txt
-4. java_failing_0-9.txt
-5. java_failing_0-8.txt
-6. cpp_failing_0-10_preview.txt -- will be depricated soon.
+The qpid-python-test script may be used to run these tests. It will by
+default run the python unit tests and the 0-10 conformance tests:
-If you fix a failure, please remove it from the corresponding list.
+ 1. Run a broker on the default port
+
+ 2. ./qpid-python-test
+
+If you wish to run the 0-8 or 0-9 conformence tests, they may be
+selected as follows:
+
+ 1. Run a broker on the default port
+
+ 2. ./qpid-python-test tests_0-8.*
+
+ -- or --
+
+ ./qpid-python-test tests_0-9.*
+
+See the qpid-python-test usage for for additional options:
+
+ ./qpid-python-test -h
diff --git a/python/RELEASE_NOTES b/python/RELEASE_NOTES
index 7005aa83cb..c0903df38e 100644
--- a/python/RELEASE_NOTES
+++ b/python/RELEASE_NOTES
@@ -1,25 +1,17 @@
-Apache Incubator Qpid Python M2 Release Notes
--------------------------------------------
+Apache Python M4 Release Notes
+------------------------------
-The Qpid M2 release contains support the for AMQP 0-8 specification.
-You can access the 0-8 specification using the following link.
-http://www.amqp.org/tikiwiki/tiki-index.php?page=Download
-
-For full details of Qpid capabilities, as they currently stand, see our
-detailed project documentation at:
-
-http://cwiki.apache.org/confluence/pages/viewpage.action?pageId=28284
-
-Please take time to go through the README file provided with the distro.
+The Qpid M4 release of the python client contains support the for both
+ 0-8 and 0-10 of the AMQP specification as well as support for the
+non-WIP portion of the 0-9 specification. You can access these
+specifications from:
+http://jira.amqp.org/confluence/display/AMQP/Download
-Known Issues/Outstanding Work
------------------------------
-
-There are no known issues for the Phyton client.
-
+For full details of Qpid capabilities, as they currently stand, see our
+project page at:
-M2 Tasks Completed
--------------------
+http://cwiki.apache.org/confluence/display/qpid/Index
-Bug QPID-467 Complete Interop Testing
+The README file provided contains some details on installing and using
+the python client that is included with this distribution.
diff --git a/python/amqp-doc b/python/amqp-doc
deleted file mode 100755
index 1f5910f942..0000000000
--- a/python/amqp-doc
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/usr/bin/env python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-import sys, re
-from qpid.spec import load, pythonize
-from getopt import gnu_getopt as getopt, GetoptError
-from fnmatch import fnmatchcase as fnmatch
-
-def die(msg):
- print >> sys.stderr, msg
- sys.exit(1)
-
-def usage(msg = ""):
- return ("""%s
-
-Usage %s [<options>] [<pattern_1> ... <pattern_n>]
-
-Options:
- -e, --regexp use regex instead of glob when matching
- -s, --spec <url> location of amqp.xml
-""" % (msg, sys.argv[0])).strip()
-
-try:
- opts, args = getopt(sys.argv[1:], "s:ea:", ["regexp", "spec=", "additional="])
-except GetoptError, e:
- die(str(e))
-
-regexp = False
-spec = "../specs/amqp.0-9.xml"
-errata = []
-for k, v in opts:
- if k == "-e" or k == "--regexp": regexp = True
- if k == "-s" or k == "--spec": spec = v
- if k == "-a" or k == "--additional": errata.append(v)
-
-if regexp:
- def match(pattern, value):
- try:
- return re.match(pattern, value)
- except Exception, e:
- die("error: '%s': %s" % (pattern, e))
-else:
- def match(pattern, value):
- return fnmatch(value, pattern)
-
-spec = load(spec, *errata)
-methods = {}
-patterns = args
-for pattern in patterns:
- for c in spec.classes:
- for m in c.methods:
- name = pythonize("%s_%s" % (c.name, m.name))
- if match(pattern, name):
- methods[name] = m.define_method(name)
-
-if patterns:
- if methods:
- AMQP = type("AMQP[%s]" % ", ".join(patterns), (), methods)
- else:
- die("no matches")
-else:
- AMQP = spec.define_class("AMQP")
-
-help(AMQP)
diff --git a/python/commands/qpid-cluster b/python/commands/qpid-cluster
new file mode 100755
index 0000000000..7afb7671b8
--- /dev/null
+++ b/python/commands/qpid-cluster
@@ -0,0 +1,328 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import os
+import getopt
+import sys
+import locale
+import socket
+import re
+from qmf.console import Session
+
+class Config:
+ def __init__(self):
+ self._host = "localhost"
+ self._connTimeout = 10
+ self._stopId = None
+ self._stopAll = False
+ self._force = False
+ self._numeric = False
+ self._showConn = False
+ self._delConn = None
+
+def usage ():
+ print "Usage: qpid-cluster [OPTIONS] [broker-addr]"
+ print
+ print " broker-addr is in the form: [username/password@] hostname | ip-address [:<port>]"
+ print " ex: localhost, 10.1.1.7:10000, broker-host:10000, guest/guest@localhost"
+ print
+ print "Options:"
+ print " --timeout seconds (10) Maximum time to wait for broker connection"
+ print " -C [--all-connections] View client connections to all cluster members"
+ print " -c [--connections] ID View client connections to specified member"
+ print " -d [--del-connection] HOST:PORT"
+ print " Disconnect a client connection"
+ print " -s [--stop] ID Stop one member of the cluster by its ID"
+ print " -k [--all-stop] Shut down the whole cluster"
+ print " -f [--force] Suppress the 'are-you-sure?' prompt"
+ print " -n [--numeric] Don't resolve names"
+ print
+
+class IpAddr:
+ def __init__(self, text):
+ if text.find("@") != -1:
+ tokens = text.split("@")
+ text = tokens[1]
+ if text.find(":") != -1:
+ tokens = text.split(":")
+ text = tokens[0]
+ self.port = int(tokens[1])
+ else:
+ self.port = 5672
+ self.dottedQuad = socket.gethostbyname(text)
+ nums = self.dottedQuad.split(".")
+ self.addr = (int(nums[0]) << 24) + (int(nums[1]) << 16) + (int(nums[2]) << 8) + int(nums[3])
+
+ def bestAddr(self, addrPortList):
+ bestDiff = 0xFFFFFFFFL
+ bestAddr = None
+ for addrPort in addrPortList:
+ diff = IpAddr(addrPort[0]).addr ^ self.addr
+ if diff < bestDiff:
+ bestDiff = diff
+ bestAddr = addrPort
+ return bestAddr
+
+class BrokerManager:
+ def __init__(self, config):
+ self.config = config
+ self.brokerName = None
+ self.qmf = None
+ self.broker = None
+
+ def SetBroker(self, brokerUrl):
+ self.url = brokerUrl
+ self.qmf = Session()
+ self.broker = self.qmf.addBroker(brokerUrl, self.config._connTimeout)
+ agents = self.qmf.getAgents()
+ for a in agents:
+ if a.getAgentBank() == 0:
+ self.brokerAgent = a
+
+ def Disconnect(self):
+ if self.broker:
+ self.qmf.delBroker(self.broker)
+
+ def _getClusters(self):
+ packages = self.qmf.getPackages()
+ if "org.apache.qpid.cluster" not in packages:
+ raise Exception("Clustering is not installed on the broker.")
+
+ clusters = self.qmf.getObjects(_class="cluster", _agent=self.brokerAgent)
+ if len(clusters) == 0:
+ raise Exception("Clustering is installed but not enabled on the broker.")
+
+ return clusters
+
+ def _getHostList(self, urlList):
+ hosts = []
+ hostAddr = IpAddr(self.config._host)
+ for url in urlList:
+ if url.find("amqp:") != 0:
+ raise Exception("Invalid URL 1")
+ url = url[5:]
+ addrs = str(url).split(",")
+ addrList = []
+ for addr in addrs:
+ tokens = addr.split(":")
+ if len(tokens) != 3:
+ raise Exception("Invalid URL 2")
+ addrList.append((tokens[1], tokens[2]))
+
+ # Find the address in the list that is most likely to be in the same subnet as the address
+ # with which we made the original QMF connection. This increases the probability that we will
+ # be able to reach the cluster member.
+
+ best = hostAddr.bestAddr(addrList)
+ bestUrl = best[0] + ":" + best[1]
+ hosts.append(bestUrl)
+ return hosts
+
+ def overview(self):
+ clusters = self._getClusters()
+ cluster = clusters[0]
+ memberList = cluster.members.split(";")
+ idList = cluster.memberIDs.split(";")
+
+ print " Cluster Name: %s" % cluster.clusterName
+ print "Cluster Status: %s" % cluster.status
+ print " Cluster Size: %d" % cluster.clusterSize
+ print " Members: ID=%s URL=%s" % (idList[0], memberList[0])
+ for idx in range(1,len(idList)):
+ print " : ID=%s URL=%s" % (idList[idx], memberList[idx])
+
+ def stopMember(self, id):
+ clusters = self._getClusters()
+ cluster = clusters[0]
+ idList = cluster.memberIDs.split(";")
+ if id not in idList:
+ raise Exception("No member with matching ID found")
+
+ if not self.config._force:
+ prompt = "Warning: "
+ if len(idList) == 1:
+ prompt += "This command will shut down the last running cluster member."
+ else:
+ prompt += "This command will shut down a cluster member."
+ prompt += " Are you sure? [N]: "
+
+ confirm = raw_input(prompt)
+ if len(confirm) == 0 or confirm[0].upper() != 'Y':
+ raise Exception("Operation canceled")
+
+ cluster.stopClusterNode(id)
+
+ def stopAll(self):
+ clusters = self._getClusters()
+ if not self.config._force:
+ prompt = "Warning: This command will shut down the entire cluster."
+ prompt += " Are you sure? [N]: "
+
+ confirm = raw_input(prompt)
+ if len(confirm) == 0 or confirm[0].upper() != 'Y':
+ raise Exception("Operation canceled")
+
+ cluster = clusters[0]
+ cluster.stopFullCluster()
+
+ def showConnections(self):
+ clusters = self._getClusters()
+ cluster = clusters[0]
+ memberList = cluster.members.split(";")
+ idList = cluster.memberIDs.split(";")
+ displayList = []
+ hostList = self._getHostList(memberList)
+ self.qmf.delBroker(self.broker)
+ self.broker = None
+ self.brokers = []
+ pattern = re.compile("^\\d+\\.\\d+\\.\\d+\\.\\d+:\\d+$")
+
+ idx = 0
+ for host in hostList:
+ if self.config._showConn == "all" or self.config._showConn == idList[idx] or self.config._delConn:
+ self.brokers.append(self.qmf.addBroker(host, self.config._connTimeout))
+ displayList.append(idList[idx])
+ idx += 1
+
+ idx = 0
+ found = False
+ for broker in self.brokers:
+ if not self.config._delConn:
+ print "Clients on Member: ID=%s:" % displayList[idx]
+ connList = self.qmf.getObjects(_class="connection", _package="org.apache.qpid.broker", _broker=broker)
+ for conn in connList:
+ if pattern.match(conn.address):
+ if self.config._numeric or self.config._delConn:
+ a = conn.address
+ else:
+ tokens = conn.address.split(":")
+ try:
+ hostList = socket.gethostbyaddr(tokens[0])
+ host = hostList[0]
+ except:
+ host = tokens[0]
+ a = host + ":" + tokens[1]
+ if self.config._delConn:
+ tokens = self.config._delConn.split(":")
+ ip = socket.gethostbyname(tokens[0])
+ toDelete = ip + ":" + tokens[1]
+ if a == toDelete:
+ print "Closing connection from client: %s" % a
+ conn.close()
+ found = True
+ else:
+ print " %s" % a
+ idx += 1
+ if not self.config._delConn:
+ print
+ if self.config._delConn and not found:
+ print "Client connection '%s' not found" % self.config._delConn
+
+ for broker in self.brokers:
+ self.qmf.delBroker(broker)
+
+
+def main(argv=None):
+ if argv is None: argv = sys.argv
+ try:
+ config = Config()
+ try:
+ longOpts = ("stop=", "all-stop", "force", "connections=", "all-connections" "del-connection=", "numeric", "timeout=")
+ (optlist, encArgs) = getopt.gnu_getopt(argv[1:], "s:kfCc:d:n", longOpts)
+ except:
+ usage()
+ return 1
+
+ try:
+ encoding = locale.getpreferredencoding()
+ cargs = [a.decode(encoding) for a in encArgs]
+ except:
+ cargs = encArgs
+
+ count = 0
+ for opt in optlist:
+ if opt[0] == "--timeout":
+ config._connTimeout = int(opt[1])
+ if config._connTimeout == 0:
+ config._connTimeout = None
+ if opt[0] == "-s" or opt[0] == "--stop":
+ config._stopId = opt[1]
+ if len(config._stopId.split(":")) != 2:
+ raise Exception("Member ID must be of form: <host or ip>:<number>")
+ count += 1
+ if opt[0] == "-k" or opt[0] == "--all-stop":
+ config._stopAll = True
+ count += 1
+ if opt[0] == "-f" or opt[0] == "--force":
+ config._force = True
+ if opt[0] == "-n" or opt[0] == "--numeric":
+ config._numeric = True
+ if opt[0] == "-C" or opt[0] == "--all-connections":
+ config._showConn = "all"
+ count += 1
+ if opt[0] == "-c" or opt[0] == "--connections":
+ config._showConn = opt[1]
+ if len(config._showConn.split(":")) != 2:
+ raise Exception("Member ID must be of form: <host or ip>:<number>")
+ count += 1
+ if opt[0] == "-d" or opt[0] == "--del-connection":
+ config._delConn = opt[1]
+ if len(config._delConn.split(":")) != 2:
+ raise Exception("Connection must be of form: <host or ip>:<port>")
+ count += 1
+
+ if count > 1:
+ print "Only one command option may be supplied"
+ print
+ usage()
+ return 1
+
+ nargs = len(cargs)
+ bm = BrokerManager(config)
+
+ if nargs == 1:
+ config._host = cargs[0]
+
+ try:
+ bm.SetBroker(config._host)
+ if config._stopId:
+ bm.stopMember(config._stopId)
+ elif config._stopAll:
+ bm.stopAll()
+ elif config._showConn or config._delConn:
+ bm.showConnections()
+ else:
+ bm.overview()
+ except KeyboardInterrupt:
+ print
+ except Exception,e:
+ if str(e).find("connection aborted") > 0:
+ # we expect this when asking the connected broker to shut down
+ return 0
+ raise Exception("Failed: %s - %s" % (e.__class__.__name__, e))
+
+ bm.Disconnect()
+ except Exception, e:
+ print str(e)
+ return 1
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/python/commands/qpid-config b/python/commands/qpid-config
index cc9315f7ea..39af67f39c 100755
--- a/python/commands/qpid-config
+++ b/python/commands/qpid-config
@@ -22,30 +22,39 @@
import os
import getopt
import sys
-import socket
-import qpid
-from threading import Condition
-from qpid.management import managementClient
-from qpid.managementdata import Broker
-from qpid.peer import Closed
-from qpid.connection import Connection, ConnectionFailed
-from qpid.datatypes import uuid4
-from qpid.util import connect
-from time import sleep
-
-_recursive = False
-_host = "localhost"
-_durable = False
-_fileCount = 8
-_fileSize = 24
-_maxQueueSize = None
-_maxQueueCount= None
-
+import locale
+from qmf.console import Session
+
+_recursive = False
+_host = "localhost"
+_connTimeout = 10
+_altern_ex = None
+_passive = False
+_durable = False
+_clusterDurable = False
+_if_empty = True
+_if_unused = True
+_fileCount = 8
+_fileSize = 24
+_maxQueueSize = None
+_maxQueueCount = None
+_limitPolicy = None
+_order = None
+_msgSequence = False
+_ive = False
+_eventGeneration = None
FILECOUNT = "qpid.file_count"
FILESIZE = "qpid.file_size"
MAX_QUEUE_SIZE = "qpid.max_size"
MAX_QUEUE_COUNT = "qpid.max_count"
+POLICY_TYPE = "qpid.policy_type"
+CLUSTER_DURABLE = "qpid.persist_last_node"
+LVQ = "qpid.last_value_queue"
+LVQNB = "qpid.last_value_queue_no_browse"
+MSG_SEQUENCE = "qpid.msg_sequence"
+IVE = "qpid.ive"
+QUEUE_EVENT_GENERATION = "qpid.queue_event_generation"
def Usage ():
print "Usage: qpid-config [OPTIONS]"
@@ -54,68 +63,99 @@ def Usage ():
print " qpid-config [OPTIONS] add exchange <type> <name> [AddExchangeOptions]"
print " qpid-config [OPTIONS] del exchange <name>"
print " qpid-config [OPTIONS] add queue <name> [AddQueueOptions]"
- print " qpid-config [OPTIONS] del queue <name>"
+ print " qpid-config [OPTIONS] del queue <name> [DelQueueOptions]"
print " qpid-config [OPTIONS] bind <exchange-name> <queue-name> [binding-key]"
print " qpid-config [OPTIONS] unbind <exchange-name> <queue-name> [binding-key]"
print
print "Options:"
+ print " --timeout seconds (10) Maximum time to wait for broker connection"
print " -b [ --bindings ] Show bindings in queue or exchange list"
print " -a [ --broker-addr ] Address (localhost) Address of qpidd broker"
print " broker-addr is in the form: [username/password@] hostname | ip-address [:<port>]"
print " ex: localhost, 10.1.1.7:10000, broker-host:10000, guest/guest@localhost"
print
print "Add Queue Options:"
- print " --durable Queue is durable"
- print " --file-count N (8) Number of files in queue's persistence journal"
- print " --file-size N (24) File size in pages (64Kib/page)"
- print " --max-queue-size N Maximum in-memory queue size as bytes"
- print " --max-queue-count N Maximum in-memory queue size as a number of messages"
+ print " --alternate-exchange [name of the alternate exchange]"
+ print " The alternate-exchange field specifies how messages on this queue should"
+ print " be treated when they are rejected by a subscriber, or when they are"
+ print " orphaned by queue deletion. When present, rejected or orphaned messages"
+ print " MUST be routed to the alternate-exchange. In all cases the messages MUST"
+ print " be removed from the queue."
+ print " --passive Do not actually change the broker state (queue will not be created)"
+ print " --durable Queue is durable"
+ print " --cluster-durable Queue becomes durable if there is only one functioning cluster node"
+ print " --file-count N (8) Number of files in queue's persistence journal"
+ print " --file-size N (24) File size in pages (64Kib/page)"
+ print " --max-queue-size N Maximum in-memory queue size as bytes"
+ print " --max-queue-count N Maximum in-memory queue size as a number of messages"
+ print " --limit-policy [none | reject | flow-to-disk | ring | ring-strict]"
+ print " Action taken when queue limit is reached:"
+ print " none (default) - Use broker's default policy"
+ print " reject - Reject enqueued messages"
+ print " flow-to-disk - Page messages to disk"
+ print " ring - Replace oldest unacquired message with new"
+ print " ring-strict - Replace oldest message, reject if oldest is acquired"
+ print " --order [fifo | lvq | lvq-no-browse]"
+ print " Set queue ordering policy:"
+ print " fifo (default) - First in, first out"
+ print " lvq - Last Value Queue ordering, allows queue browsing"
+ print " lvq-no-browse - Last Value Queue ordering, browsing clients may lose data"
+ print " --generate-queue-events N"
+ print " If set to 1, every enqueue will generate an event that can be processed by"
+ print " registered listeners (e.g. for replication). If set to 2, events will be"
+ print " generated for enqueues and dequeues"
+ print
+ print "Del Queue Options:"
+ print " --force Force delete of queue even if it's currently used or it's not empty"
+ print " --force-if-not-empty Force delete of queue even if it's not empty"
+ print " --force-if-used Force delete of queue even if it's currently used"
+ print
+ print "Add Exchange <type> values:"
+ print " direct Direct exchange for point-to-point communication"
+ print " fanout Fanout exchange for broadcast communication"
+ print " topic Topic exchange that routes messages using binding keys with wildcards"
+ print " headers Headers exchange that matches header fields against the binding keys"
print
print "Add Exchange Options:"
- print " --durable Exchange is durable"
+ print " --alternate-exchange [name of the alternate exchange]"
+ print " In the event that a message cannot be routed, this is the name of the exchange to"
+ print " which the message will be sent. Messages transferred using message.transfer will"
+ print " be routed to the alternate-exchange only if they are sent with the \"none\""
+ print " accept-mode, and the discard-unroutable delivery property is set to false, and"
+ print " there is no queue to route to for the given message according to the bindings"
+ print " on this exchange."
+ print " --passive Do not actually change the broker state (exchange will not be created)"
+ print " --durable Exchange is durable"
+ print " --sequence Exchange will insert a 'qpid.msg_sequence' field in the message header"
+ print " with a value that increments for each message forwarded."
+ print " --ive Exchange will behave as an 'initial-value-exchange', keeping a reference"
+ print " to the last message forwarded and enqueuing that message to newly bound"
+ print " queues."
print
sys.exit (1)
class BrokerManager:
def __init__ (self):
- self.dest = None
- self.src = None
- self.broker = None
-
- def SetBroker (self, broker):
- self.broker = broker
-
- def ConnectToBroker (self):
- try:
- self.sessionId = "%s.%d" % (os.uname()[1], os.getpid())
- self.conn = Connection (connect (self.broker.host, self.broker.port),
- username=self.broker.username, password=self.broker.password)
- self.conn.start ()
- self.session = self.conn.session (self.sessionId)
- self.mclient = managementClient (self.conn.spec)
- self.mchannel = self.mclient.addChannel (self.session)
- except socket.error, e:
- print "Socket Error %s - %s" % (e[0], e[1])
- sys.exit (1)
- except Closed, e:
- print "Connect Failed %d - %s" % (e[0], e[1])
- sys.exit (1)
- except ConnectionFailed, e:
- print "Connect Failed %d - %s" % (e[0], e[1])
- sys.exit(1)
-
- def Disconnect (self):
- self.mclient.removeChannel (self.mchannel)
- self.session.close(timeout=10)
- self.conn.close(timeout=10)
+ self.brokerName = None
+ self.qmf = None
+ self.broker = None
+
+ def SetBroker (self, brokerUrl):
+ self.url = brokerUrl
+ self.qmf = Session()
+ self.broker = self.qmf.addBroker(brokerUrl, _connTimeout)
+ agents = self.qmf.getAgents()
+ for a in agents:
+ if a.getAgentBank() == 0:
+ self.brokerAgent = a
+
+ def Disconnect(self):
+ if self.broker:
+ self.qmf.delBroker(self.broker)
def Overview (self):
- self.ConnectToBroker ()
- mc = self.mclient
- mch = self.mchannel
- mc.syncWaitForStable (mch)
- exchanges = mc.syncGetObjects (mch, "exchange")
- queues = mc.syncGetObjects (mch, "queue")
+ exchanges = self.qmf.getObjects(_class="exchange", _agent=self.brokerAgent)
+ queues = self.qmf.getObjects(_class="queue", _agent=self.brokerAgent)
print "Total Exchanges: %d" % len (exchanges)
etype = {}
for ex in exchanges:
@@ -136,30 +176,39 @@ class BrokerManager:
print " non-durable: %d" % (len (queues) - _durable)
def ExchangeList (self, filter):
- self.ConnectToBroker ()
- mc = self.mclient
- mch = self.mchannel
- mc.syncWaitForStable (mch)
- exchanges = mc.syncGetObjects (mch, "exchange")
- print "Durable Type Bindings Exchange Name"
- print "======================================================="
+ exchanges = self.qmf.getObjects(_class="exchange", _agent=self.brokerAgent)
+ caption1 = "Type "
+ caption2 = "Exchange Name"
+ maxNameLen = len(caption2)
+ for ex in exchanges:
+ if self.match(ex.name, filter):
+ if len(ex.name) > maxNameLen: maxNameLen = len(ex.name)
+ print "%s%-*s Attributes" % (caption1, maxNameLen, caption2)
+ line = ""
+ for i in range(((maxNameLen + len(caption1)) / 5) + 5):
+ line += "====="
+ print line
+
for ex in exchanges:
if self.match (ex.name, filter):
- print "%4c %-10s%5d %s" % (YN (ex.durable), ex.type, ex.bindingCount, ex.name)
+ print "%-10s%-*s " % (ex.type, maxNameLen, ex.name),
+ args = ex.arguments
+ if ex.durable: print "--durable",
+ if MSG_SEQUENCE in args and args[MSG_SEQUENCE] == 1: print "--sequence",
+ if IVE in args and args[IVE] == 1: print "--ive",
+ if ex.altExchange:
+ print "--alternate-exchange=%s" % ex._altExchange_.name,
+ print
def ExchangeListRecurse (self, filter):
- self.ConnectToBroker ()
- mc = self.mclient
- mch = self.mchannel
- mc.syncWaitForStable (mch)
- exchanges = mc.syncGetObjects (mch, "exchange")
- bindings = mc.syncGetObjects (mch, "binding")
- queues = mc.syncGetObjects (mch, "queue")
+ exchanges = self.qmf.getObjects(_class="exchange", _agent=self.brokerAgent)
+ bindings = self.qmf.getObjects(_class="binding", _agent=self.brokerAgent)
+ queues = self.qmf.getObjects(_class="queue", _agent=self.brokerAgent)
for ex in exchanges:
if self.match (ex.name, filter):
print "Exchange '%s' (%s)" % (ex.name, ex.type)
for bind in bindings:
- if bind.exchangeRef == ex.id:
+ if bind.exchangeRef == ex.getObjectId():
qname = "<unknown>"
queue = self.findById (queues, bind.queueRef)
if queue != None:
@@ -168,43 +217,48 @@ class BrokerManager:
def QueueList (self, filter):
- self.ConnectToBroker ()
- mc = self.mclient
- mch = self.mchannel
- mc.syncWaitForStable (mch)
- queues = mc.syncGetObjects (mch, "queue")
- journals = mc.syncGetObjects (mch, "journal")
- print " Store Size"
- print "Durable AutoDel Excl Bindings (files x file pages) Queue Name"
- print "==========================================================================================="
+ queues = self.qmf.getObjects(_class="queue", _agent=self.brokerAgent)
+
+ caption = "Queue Name"
+ maxNameLen = len(caption)
+ for q in queues:
+ if self.match (q.name, filter):
+ if len(q.name) > maxNameLen: maxNameLen = len(q.name)
+ print "%-*s Attributes" % (maxNameLen, caption)
+ line = ""
+ for i in range((maxNameLen / 5) + 5):
+ line += "====="
+ print line
+
for q in queues:
if self.match (q.name, filter):
+ print "%-*s " % (maxNameLen, q.name),
args = q.arguments
- if q.durable and FILESIZE in args and FILECOUNT in args:
- fs = int (args[FILESIZE])
- fc = int (args[FILECOUNT])
- print "%4c%9c%7c%10d%11dx%-14d%s" % \
- (YN (q.durable), YN (q.autoDelete),
- YN (q.exclusive), q.bindingCount, fc, fs, q.name)
- else:
- if not _durable:
- print "%4c%9c%7c%10d %s" % \
- (YN (q.durable), YN (q.autoDelete),
- YN (q.exclusive), q.bindingCount, q.name)
+ if q.durable: print "--durable",
+ if CLUSTER_DURABLE in args and args[CLUSTER_DURABLE] == 1: print "--cluster-durable",
+ if q.autoDelete: print "auto-del",
+ if q.exclusive: print "excl",
+ if FILESIZE in args: print "--file-size=%d" % args[FILESIZE],
+ if FILECOUNT in args: print "--file-count=%d" % args[FILECOUNT],
+ if MAX_QUEUE_SIZE in args: print "--max-queue-size=%d" % args[MAX_QUEUE_SIZE],
+ if MAX_QUEUE_COUNT in args: print "--max-queue-count=%d" % args[MAX_QUEUE_COUNT],
+ if POLICY_TYPE in args: print "--limit-policy=%s" % args[POLICY_TYPE].replace("_", "-"),
+ if LVQ in args and args[LVQ] == 1: print "--order lvq",
+ if LVQNB in args and args[LVQNB] == 1: print "--order lvq-no-browse",
+ if QUEUE_EVENT_GENERATION in args: print "--generate-queue-events=%d" % args[QUEUE_EVENT_GENERATION],
+ if q.altExchange:
+ print "--alternate-exchange=%s" % q._altExchange_.name,
+ print
def QueueListRecurse (self, filter):
- self.ConnectToBroker ()
- mc = self.mclient
- mch = self.mchannel
- mc.syncWaitForStable (mch)
- exchanges = mc.syncGetObjects (mch, "exchange")
- bindings = mc.syncGetObjects (mch, "binding")
- queues = mc.syncGetObjects (mch, "queue")
+ exchanges = self.qmf.getObjects(_class="exchange", _agent=self.brokerAgent)
+ bindings = self.qmf.getObjects(_class="binding", _agent=self.brokerAgent)
+ queues = self.qmf.getObjects(_class="queue", _agent=self.brokerAgent)
for queue in queues:
if self.match (queue.name, filter):
print "Queue '%s'" % queue.name
for bind in bindings:
- if bind.queueRef == queue.id:
+ if bind.queueRef == queue.getObjectId():
ename = "<unknown>"
ex = self.findById (exchanges, bind.exchangeRef)
if ex != None:
@@ -216,30 +270,27 @@ class BrokerManager:
def AddExchange (self, args):
if len (args) < 2:
Usage ()
- self.ConnectToBroker ()
etype = args[0]
ename = args[1]
-
- try:
- self.session.exchange_declare (exchange=ename, type=etype, durable=_durable)
- except Closed, e:
- print "Failed:", e
+ declArgs = {}
+ if _msgSequence:
+ declArgs[MSG_SEQUENCE] = 1
+ if _ive:
+ declArgs[IVE] = 1
+ if _altern_ex != None:
+ self.broker.getAmqpSession().exchange_declare (exchange=ename, type=etype, alternate_exchange=_altern_ex, passive=_passive, durable=_durable, arguments=declArgs)
+ else:
+ self.broker.getAmqpSession().exchange_declare (exchange=ename, type=etype, passive=_passive, durable=_durable, arguments=declArgs)
def DelExchange (self, args):
if len (args) < 1:
Usage ()
- self.ConnectToBroker ()
ename = args[0]
-
- try:
- self.session.exchange_delete (exchange=ename)
- except Closed, e:
- print "Failed:", e
+ self.broker.getAmqpSession().exchange_delete (exchange=ename)
def AddQueue (self, args):
if len (args) < 1:
Usage ()
- self.ConnectToBroker ()
qname = args[0]
declArgs = {}
if _durable:
@@ -250,56 +301,64 @@ class BrokerManager:
declArgs[MAX_QUEUE_SIZE] = _maxQueueSize
if _maxQueueCount:
declArgs[MAX_QUEUE_COUNT] = _maxQueueCount
-
- try:
- self.session.queue_declare (queue=qname, durable=_durable, arguments=declArgs)
- except Closed, e:
- print "Failed:", e
+ if _limitPolicy:
+ if _limitPolicy == "none":
+ pass
+ elif _limitPolicy == "reject":
+ declArgs[POLICY_TYPE] = "reject"
+ elif _limitPolicy == "flow-to-disk":
+ declArgs[POLICY_TYPE] = "flow_to_disk"
+ elif _limitPolicy == "ring":
+ declArgs[POLICY_TYPE] = "ring"
+ elif _limitPolicy == "ring-strict":
+ declArgs[POLICY_TYPE] = "ring_strict"
+
+ if _clusterDurable:
+ declArgs[CLUSTER_DURABLE] = 1
+ if _order:
+ if _order == "fifo":
+ pass
+ elif _order == "lvq":
+ declArgs[LVQ] = 1
+ elif _order == "lvq-no-browse":
+ declArgs[LVQNB] = 1
+ if _eventGeneration:
+ declArgs[QUEUE_EVENT_GENERATION] = _eventGeneration
+
+ if _altern_ex != None:
+ self.broker.getAmqpSession().queue_declare (queue=qname, alternate_exchange=_altern_ex, passive=_passive, durable=_durable, arguments=declArgs)
+ else:
+ self.broker.getAmqpSession().queue_declare (queue=qname, passive=_passive, durable=_durable, arguments=declArgs)
def DelQueue (self, args):
if len (args) < 1:
Usage ()
- self.ConnectToBroker ()
qname = args[0]
-
- try:
- self.session.queue_delete (queue=qname)
- except Closed, e:
- print "Failed:", e
+ self.broker.getAmqpSession().queue_delete (queue=qname, if_empty=_if_empty, if_unused=_if_unused)
def Bind (self, args):
if len (args) < 2:
Usage ()
- self.ConnectToBroker ()
ename = args[0]
qname = args[1]
key = ""
if len (args) > 2:
key = args[2]
-
- try:
- self.session.exchange_bind (queue=qname, exchange=ename, binding_key=key)
- except Closed, e:
- print "Failed:", e
+ self.broker.getAmqpSession().exchange_bind (queue=qname, exchange=ename, binding_key=key)
def Unbind (self, args):
if len (args) < 2:
Usage ()
- self.ConnectToBroker ()
ename = args[0]
qname = args[1]
key = ""
if len (args) > 2:
key = args[2]
-
- try:
- self.session.exchange_unbind (queue=qname, exchange=ename, binding_key=key)
- except Closed, e:
- print "Failed:", e
+ self.broker.getAmqpSession().exchange_unbind (queue=qname, exchange=ename, binding_key=key)
def findById (self, items, id):
for item in items:
- if item.id == id:
+ if item.getObjectId() == id:
return item
return None
@@ -315,23 +374,43 @@ def YN (bool):
return 'Y'
return 'N'
+
##
## Main Program
##
try:
- longOpts = ("durable", "bindings", "broker-addr=", "file-count=", "file-size=", "max-queue-size=", "max-queue-count=")
- (optlist, cargs) = getopt.gnu_getopt (sys.argv[1:], "a:b", longOpts)
+ longOpts = ("durable", "cluster-durable", "bindings", "broker-addr=", "file-count=",
+ "file-size=", "max-queue-size=", "max-queue-count=", "limit-policy=",
+ "order=", "sequence", "ive", "generate-queue-events=", "force", "force-if-not-empty",
+ "force_if_used", "alternate-exchange=", "passive", "timeout=")
+ (optlist, encArgs) = getopt.gnu_getopt (sys.argv[1:], "a:b", longOpts)
except:
Usage ()
+try:
+ encoding = locale.getpreferredencoding()
+ cargs = [a.decode(encoding) for a in encArgs]
+except:
+ cargs = encArgs
+
for opt in optlist:
if opt[0] == "-b" or opt[0] == "--bindings":
_recursive = True
if opt[0] == "-a" or opt[0] == "--broker-addr":
_host = opt[1]
+ if opt[0] == "--timeout":
+ _connTimeout = int(opt[1])
+ if _connTimeout == 0:
+ _connTimeout = None
+ if opt[0] == "--alternate-exchange":
+ _altern_ex = opt[1]
+ if opt[0] == "--passive":
+ _passive = True
if opt[0] == "--durable":
_durable = True
+ if opt[0] == "--cluster-durable":
+ _clusterDurable = True
if opt[0] == "--file-count":
_fileCount = int (opt[1])
if opt[0] == "--file-size":
@@ -340,46 +419,77 @@ for opt in optlist:
_maxQueueSize = int (opt[1])
if opt[0] == "--max-queue-count":
_maxQueueCount = int (opt[1])
+ if opt[0] == "--limit-policy":
+ _limitPolicy = opt[1]
+ if _limitPolicy not in ("none", "reject", "flow-to-disk", "ring", "ring-strict"):
+ print "Error: Invalid --limit-policy argument"
+ sys.exit(1)
+ if opt[0] == "--order":
+ _order = opt[1]
+ if _order not in ("fifo", "lvq", "lvq-no-browse"):
+ print "Error: Invalid --order argument"
+ sys.exit(1)
+ if opt[0] == "--sequence":
+ _msgSequence = True
+ if opt[0] == "--ive":
+ _ive = True
+ if opt[0] == "--generate-queue-events":
+ _eventGeneration = int (opt[1])
+ if opt[0] == "--force":
+ _if_empty = False
+ _if_unused = False
+ if opt[0] == "--force-if-not-empty":
+ _if_empty = False
+ if opt[0] == "--force-if-used":
+ _if_unused = False
+
nargs = len (cargs)
bm = BrokerManager ()
-bm.SetBroker (Broker (_host))
-
-if nargs == 0:
- bm.Overview ()
-else:
- cmd = cargs[0]
- modifier = ""
- if nargs > 1:
- modifier = cargs[1]
- if cmd[0] == 'e':
- if _recursive:
- bm.ExchangeListRecurse (modifier)
- else:
- bm.ExchangeList (modifier)
- elif cmd[0] == 'q':
- if _recursive:
- bm.QueueListRecurse (modifier)
- else:
- bm.QueueList (modifier)
- elif cmd == "add":
- if modifier == "exchange":
- bm.AddExchange (cargs[2:])
- elif modifier == "queue":
- bm.AddQueue (cargs[2:])
- else:
- Usage ()
- elif cmd == "del":
- if modifier == "exchange":
- bm.DelExchange (cargs[2:])
- elif modifier == "queue":
- bm.DelQueue (cargs[2:])
+
+try:
+ bm.SetBroker(_host)
+ if nargs == 0:
+ bm.Overview ()
+ else:
+ cmd = cargs[0]
+ modifier = ""
+ if nargs > 1:
+ modifier = cargs[1]
+ if cmd == "exchanges":
+ if _recursive:
+ bm.ExchangeListRecurse (modifier)
+ else:
+ bm.ExchangeList (modifier)
+ elif cmd == "queues":
+ if _recursive:
+ bm.QueueListRecurse (modifier)
+ else:
+ bm.QueueList (modifier)
+ elif cmd == "add":
+ if modifier == "exchange":
+ bm.AddExchange (cargs[2:])
+ elif modifier == "queue":
+ bm.AddQueue (cargs[2:])
+ else:
+ Usage ()
+ elif cmd == "del":
+ if modifier == "exchange":
+ bm.DelExchange (cargs[2:])
+ elif modifier == "queue":
+ bm.DelQueue (cargs[2:])
+ else:
+ Usage ()
+ elif cmd == "bind":
+ bm.Bind (cargs[1:])
+ elif cmd == "unbind":
+ bm.Unbind (cargs[1:])
else:
Usage ()
- elif cmd == "bind":
- bm.Bind (cargs[1:])
- elif cmd == "unbind":
- bm.Unbind (cargs[1:])
- else:
- Usage ()
+except KeyboardInterrupt:
+ print
+except Exception,e:
+ print "Failed: %s: %s" % (e.__class__.__name__, e)
+ sys.exit(1)
+
bm.Disconnect()
diff --git a/python/commands/qpid-printevents b/python/commands/qpid-printevents
new file mode 100755
index 0000000000..0c1b618a1f
--- /dev/null
+++ b/python/commands/qpid-printevents
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import os
+import optparse
+import sys
+import socket
+from time import time, strftime, gmtime, sleep
+from qmf.console import Console, Session
+
+class EventConsole(Console):
+ def event(self, broker, event):
+ print event
+
+ def brokerConnected(self, broker):
+ print strftime("%c", gmtime(time())), "NOTIC qpid-printevents:brokerConnected broker=%s" % broker.getUrl()
+
+ def brokerDisconnected(self, broker):
+ print strftime("%c", gmtime(time())), "NOTIC qpid-printevents:brokerDisconnected broker=%s" % broker.getUrl()
+
+
+##
+## Main Program
+##
+def main():
+ _usage = "%prog [options] [broker-addr]..."
+ _description = \
+"""Collect and print events from one or more Qpid message brokers. If no broker-addr is
+supplied, %prog will connect to 'localhost:5672'.
+broker-addr is of the form: [username/password@] hostname | ip-address [:<port>]
+ex: localhost, 10.1.1.7:10000, broker-host:10000, guest/guest@localhost
+"""
+ p = optparse.OptionParser(usage=_usage, description=_description)
+
+ options, arguments = p.parse_args()
+ if len(arguments) == 0:
+ arguments.append("localhost")
+
+ console = EventConsole()
+ session = Session(console, rcvObjects=False, rcvHeartbeats=False, manageConnections=True)
+ brokers = []
+ for host in arguments:
+ brokers.append(session.addBroker(host))
+
+ try:
+ while (True):
+ sleep(10)
+ except KeyboardInterrupt:
+ for broker in brokers:
+ session.delBroker(broker)
+ print
+ sys.exit(0)
+
+if __name__ == '__main__':
+ main()
+
diff --git a/python/commands/qpid-queue-stats b/python/commands/qpid-queue-stats
index 98dfa7580a..3b8a0dcb19 100755
--- a/python/commands/qpid-queue-stats
+++ b/python/commands/qpid-queue-stats
@@ -26,120 +26,100 @@ import re
import socket
import qpid
from threading import Condition
-from qpid.management import managementClient
-from qpid.managementdata import Broker
+from qmf.console import Session, Console
from qpid.peer import Closed
from qpid.connection import Connection, ConnectionFailed
-from qpid.util import connect
from time import sleep
-class mgmtObject (object):
- """ Generic object that holds the contents of a management object with its
- attributes set as object attributes. """
-
- def __init__ (self, classKey, timestamps, row):
- self.classKey = classKey
- self.timestamps = timestamps
- for cell in row:
- setattr (self, cell[0], cell[1])
-
-
-
-class BrokerManager:
- def __init__ (self):
- self.dest = None
- self.src = None
- self.broker = None
- self.objects = {}
- self.filter = None
-
- def SetBroker (self, broker):
- self.broker = broker
-
- def ConnectToBroker (self):
- try:
- self.sessionId = "%s.%d" % (os.uname()[1], os.getpid())
- self.conn = Connection (connect (self.broker.host, self.broker.port),
- username=self.broker.username, password=self.broker.password)
- self.conn.start ()
- self.session = self.conn.session(self.sessionId)
- self.mclient = managementClient (self.conn.spec, None, self.configCb, self.instCb)
- self.mchannel = self.mclient.addChannel (self.session)
- except socket.error, e:
- print "Socket Error %s - %s" % (e[0], e[1])
- sys.exit (1)
- except Closed, e:
- print "Connect Failed %d - %s" % (e[0], e[1])
- sys.exit (1)
- except ConnectionFailed, e:
- print "Connect Failed %d - %s" % (e[0], e[1])
- sys.exit(1)
-
- def setFilter(self,filter):
- self.filter = filter
-
- def Disconnect (self):
- self.mclient.removeChannel (self.mchannel)
- self.session.close(timeout=10)
- self.conn.close(timeout=10)
-
- def configCb (self, context, classKey, row, timestamps):
- className = classKey[1]
- if className != "queue":
- return
-
- obj = mgmtObject (classKey, timestamps, row)
- if obj.id not in self.objects:
- self.objects[obj.id] = (obj.name, None, None)
-
- def instCb (self, context, classKey, row, timestamps):
- className = classKey[1]
- if className != "queue":
- return
-
- obj = mgmtObject (classKey, timestamps, row)
- if obj.id not in self.objects:
- return
-
- (name, first, last) = self.objects[obj.id]
- if first == None:
- self.objects[obj.id] = (name, obj, None)
- return
-
- if len(self.filter) > 0 :
- match = False
-
- for x in self.filter:
- if x.match(name):
- match = True
- break
- if match == False:
- return
-
- if last == None:
- lastSample = first
- else:
- lastSample = last
-
- self.objects[obj.id] = (name, first, obj)
-
- deltaTime = float (obj.timestamps[0] - lastSample.timestamps[0])
- enqueueRate = float (obj.msgTotalEnqueues - lastSample.msgTotalEnqueues) / (deltaTime / 1000000000.0)
- dequeueRate = float (obj.msgTotalDequeues - lastSample.msgTotalDequeues) / (deltaTime / 1000000000.0)
- print "%-41s%10.2f%11d%13.2f%13.2f" % \
- (name, deltaTime / 1000000000, obj.msgDepth, enqueueRate, dequeueRate)
-
-
- def Display (self):
- self.ConnectToBroker ()
- print "Queue Name Sec Depth Enq Rate Deq Rate"
- print "========================================================================================"
- try:
- while True:
- sleep (1)
- except KeyboardInterrupt:
- pass
- self.Disconnect ()
+class BrokerManager(Console):
+ def __init__(self, host):
+ self.url = host
+ self.objects = {}
+ self.filter = None
+ self.session = Session(self, rcvEvents=False, rcvHeartbeats=False,
+ userBindings=True, manageConnections=True)
+ self.broker = self.session.addBroker(self.url)
+ self.firstError = True
+
+ def setFilter(self,filter):
+ self.filter = filter
+
+ def brokerConnected(self, broker):
+ if not self.firstError:
+ print "*** Broker connected"
+ self.firstError = False
+
+ def brokerDisconnected(self, broker):
+ print "*** Broker connection lost - %s, retrying..." % broker.getError()
+ self.firstError = False
+ self.objects.clear()
+
+ def objectProps(self, broker, record):
+ className = record.getClassKey().getClassName()
+ if className != "queue":
+ return
+
+ id = record.getObjectId().__repr__()
+ if id not in self.objects:
+ self.objects[id] = (record.name, None, None)
+
+ def objectStats(self, broker, record):
+ className = record.getClassKey().getClassName()
+ if className != "queue":
+ return
+
+ id = record.getObjectId().__repr__()
+ if id not in self.objects:
+ return
+
+ (name, first, last) = self.objects[id]
+ if first == None:
+ self.objects[id] = (name, record, None)
+ return
+
+ if len(self.filter) > 0 :
+ match = False
+
+ for x in self.filter:
+ if x.match(name):
+ match = True
+ break
+ if match == False:
+ return
+
+ if last == None:
+ lastSample = first
+ else:
+ lastSample = last
+
+ self.objects[id] = (name, first, record)
+
+ deltaTime = float (record.getTimestamps()[0] - lastSample.getTimestamps()[0])
+ if deltaTime < 1000000000.0:
+ return
+ enqueueRate = float (record.msgTotalEnqueues - lastSample.msgTotalEnqueues) / \
+ (deltaTime / 1000000000.0)
+ dequeueRate = float (record.msgTotalDequeues - lastSample.msgTotalDequeues) / \
+ (deltaTime / 1000000000.0)
+ print "%-41s%10.2f%11d%13.2f%13.2f" % \
+ (name, deltaTime / 1000000000, record.msgDepth, enqueueRate, dequeueRate)
+ sys.stdout.flush()
+
+
+ def Display (self):
+ self.session.bindClass("org.apache.qpid.broker", "queue")
+ print "Queue Name Sec Depth Enq Rate Deq Rate"
+ print "========================================================================================"
+ sys.stdout.flush()
+ try:
+ while True:
+ sleep (1)
+ if self.firstError and self.broker.getError():
+ self.firstError = False
+ print "*** Error: %s, retrying..." % self.broker.getError()
+ except KeyboardInterrupt:
+ print
+ self.session.delBroker(self.broker)
##
## Main Program
@@ -157,8 +137,7 @@ def main():
for s in options.filter.split(","):
filter.append(re.compile(s))
- bm = BrokerManager ()
- bm.SetBroker (Broker (host))
+ bm = BrokerManager(host)
bm.setFilter(filter)
bm.Display()
diff --git a/python/commands/qpid-route b/python/commands/qpid-route
index 3cd9109a6a..9965047000 100755
--- a/python/commands/qpid-route
+++ b/python/commands/qpid-route
@@ -22,280 +22,379 @@
import getopt
import sys
import socket
-import qpid
import os
-from qpid.management import managementClient
-from qpid.managementdata import Broker
-from qpid.peer import Closed
-from qpid.connection import Connection, ConnectionFailed
-from qpid.util import connect
-
-def Usage ():
- print "Usage: qpid-route [OPTIONS] link add <dest-broker> <src-broker>"
- print " qpid-route [OPTIONS] link del <dest-broker> <src-broker>"
- print " qpid-route [OPTIONS] link list [<dest-broker>]"
+import locale
+from qmf.console import Session, BrokerURL
+
+def Usage():
+ print "Usage: qpid-route [OPTIONS] dynamic add <dest-broker> <src-broker> <exchange> [tag] [exclude-list]"
+ print " qpid-route [OPTIONS] dynamic del <dest-broker> <src-broker> <exchange>"
print
print " qpid-route [OPTIONS] route add <dest-broker> <src-broker> <exchange> <routing-key> [tag] [exclude-list]"
print " qpid-route [OPTIONS] route del <dest-broker> <src-broker> <exchange> <routing-key>"
+ print " qpid-route [OPTIONS] queue add <dest-broker> <src-broker> <exchange> <queue>"
+ print " qpid-route [OPTIONS] queue del <dest-broker> <src-broker> <exchange> <queue>"
print " qpid-route [OPTIONS] route list [<dest-broker>]"
print " qpid-route [OPTIONS] route flush [<dest-broker>]"
+ print " qpid-route [OPTIONS] route map [<broker>]"
+ print
+ print " qpid-route [OPTIONS] link add <dest-broker> <src-broker>"
+ print " qpid-route [OPTIONS] link del <dest-broker> <src-broker>"
+ print " qpid-route [OPTIONS] link list [<dest-broker>]"
print
print "Options:"
+ print " --timeout seconds (10) Maximum time to wait for broker connection"
print " -v [ --verbose ] Verbose output"
print " -q [ --quiet ] Quiet output, don't print duplicate warnings"
print " -d [ --durable ] Added configuration shall be durable"
print " -e [ --del-empty-link ] Delete link after deleting last route on the link"
+ print " -s [ --src-local ] Make connection to source broker (push route)"
+ print " --ack N Acknowledge transfers over the bridge in batches of N"
+ print " -t <transport> [ --transport <transport>]"
+ print " Specify transport to use for links, defaults to tcp"
print
print " dest-broker and src-broker are in the form: [username/password@] hostname | ip-address [:<port>]"
print " ex: localhost, 10.1.1.7:10000, broker-host:10000, guest/guest@localhost"
print
- sys.exit (1)
+ sys.exit(1)
-_verbose = False
-_quiet = False
-_durable = False
-_dellink = False
+_verbose = False
+_quiet = False
+_durable = False
+_dellink = False
+_srclocal = False
+_transport = "tcp"
+_ack = 0
+_connTimeout = 10
class RouteManager:
- def __init__ (self, destBroker):
- self.dest = Broker (destBroker)
- self.src = None
+ def __init__(self, localBroker):
+ self.local = BrokerURL(localBroker)
+ self.remote = None
+ self.qmf = Session()
+ self.broker = self.qmf.addBroker(localBroker, _connTimeout)
- def ConnectToBroker (self):
- broker = self.dest
- if _verbose:
- print "Connecting to broker: %s:%d" % (broker.host, broker.port)
- try:
- self.sessionId = "%s.%d" % (os.uname()[1], os.getpid())
- self.conn = Connection (connect (broker.host, broker.port), \
- username=broker.username, password=broker.password)
- self.conn.start ()
- self.session = self.conn.session(self.sessionId)
- self.mclient = managementClient (self.conn.spec)
- self.mch = self.mclient.addChannel (self.session)
- self.mclient.syncWaitForStable (self.mch)
- except socket.error, e:
- print "Socket Error %s - %s" % (e[0], e[1])
- sys.exit (1)
- except Closed, e:
- print "Connect Failed %d - %s" % (e[0], e[1])
- sys.exit (1)
- except ConnectionFailed, e:
- print "Connect Failed %d - %s" % (e[0], e[1])
- sys.exit(1)
-
- def Disconnect (self):
- self.mclient.removeChannel (self.mch)
- self.session.close(timeout=10)
- self.conn.close(timeout=10)
-
- def getLink (self):
- links = self.mclient.syncGetObjects (self.mch, "link")
+ def disconnect(self):
+ self.qmf.delBroker(self.broker)
+
+ def getLink(self):
+ links = self.qmf.getObjects(_class="link")
for link in links:
- if "%s:%d" % (link.host, link.port) == self.src.name ():
+ if self.remote.match(link.host, link.port):
return link
return None
- def AddLink (self, srcBroker):
- self.src = Broker (srcBroker)
- mc = self.mclient
-
- if self.dest.name() == self.src.name():
- print "Linking broker to itself is not permitted"
- sys.exit(1)
+ def addLink(self, remoteBroker):
+ self.remote = BrokerURL(remoteBroker)
+ if self.local.match(self.remote.host, self.remote.port):
+ raise Exception("Linking broker to itself is not permitted")
- brokers = mc.syncGetObjects (self.mch, "broker")
+ brokers = self.qmf.getObjects(_class="broker")
broker = brokers[0]
link = self.getLink()
- if link != None:
- print "Link already exists"
- sys.exit(1)
-
- connectArgs = {}
- connectArgs["host"] = self.src.host
- connectArgs["port"] = self.src.port
- connectArgs["useSsl"] = False
- connectArgs["durable"] = _durable
- if self.src.username == "anonymous":
- connectArgs["authMechanism"] = "ANONYMOUS"
- else:
- connectArgs["authMechanism"] = "PLAIN"
- connectArgs["username"] = self.src.username
- connectArgs["password"] = self.src.password
- res = mc.syncCallMethod (self.mch, broker.id, broker.classKey, "connect", connectArgs)
- if _verbose:
- print "Connect method returned:", res.status, res.statusText
- link = self.getLink ()
-
- def DelLink (self, srcBroker):
- self.src = Broker (srcBroker)
- mc = self.mclient
+ if link == None:
+ if not self.remote.authName or self.remote.authName == "anonymous":
+ mech = "ANONYMOUS"
+ else:
+ mech = "PLAIN"
+ res = broker.connect(self.remote.host, self.remote.port, _durable,
+ mech, self.remote.authName or "", self.remote.authPass or "",
+ _transport)
+ if _verbose:
+ print "Connect method returned:", res.status, res.text
- brokers = mc.syncGetObjects (self.mch, "broker")
+ def delLink(self, remoteBroker):
+ self.remote = BrokerURL(remoteBroker)
+ brokers = self.qmf.getObjects(_class="broker")
broker = brokers[0]
link = self.getLink()
if link == None:
- print "Link not found"
- sys.exit(1)
+ raise Exception("Link not found")
- res = mc.syncCallMethod (self.mch, link.id, link.classKey, "close")
+ res = link.close()
if _verbose:
- print "Close method returned:", res.status, res.statusText
+ print "Close method returned:", res.status, res.text
- def ListLinks (self):
- mc = self.mclient
- links = mc.syncGetObjects (self.mch, "link")
+ def listLinks(self):
+ links = self.qmf.getObjects(_class="link")
if len(links) == 0:
print "No Links Found"
else:
print
- print "Host Port Durable State Last Error"
- print "==================================================================="
+ print "Host Port Transport Durable State Last Error"
+ print "============================================================================="
+ for link in links:
+ print "%-16s%-8d%-13s%c %-18s%s" % \
+ (link.host, link.port, link.transport, YN(link.durable), link.state, link.lastError)
+
+ def mapRoutes(self):
+ qmf = self.qmf
+ print
+ print "Finding Linked Brokers:"
+
+ brokerList = {}
+ brokerList[self.local.name()] = self.broker
+ print " %s... Ok" % self.local
+
+ added = True
+ while added:
+ added = False
+ links = qmf.getObjects(_class="link")
for link in links:
- print "%-16s%-8d %c %-18s%s" % (link.host, link.port, YN(link.durable), link.state, link.lastError)
+ url = BrokerURL("%s:%d" % (link.host, link.port))
+ if url.name() not in brokerList:
+ print " %s..." % url.name(),
+ try:
+ b = qmf.addBroker("%s:%d" % (link.host, link.port), _connTimeout)
+ brokerList[url.name()] = b
+ added = True
+ print "Ok"
+ except Exception, e:
+ print e
+
+ print
+ print "Dynamic Routes:"
+ bridges = qmf.getObjects(_class="bridge", dynamic=True)
+ fedExchanges = []
+ for bridge in bridges:
+ if bridge.src not in fedExchanges:
+ fedExchanges.append(bridge.src)
+ if len(fedExchanges) == 0:
+ print " none found"
+ print
+
+ for ex in fedExchanges:
+ print " Exchange %s:" % ex
+ pairs = []
+ for bridge in bridges:
+ if bridge.src == ex:
+ link = bridge._linkRef_
+ fromUrl = "%s:%s" % (link.host, link.port)
+ toUrl = bridge.getBroker().getUrl()
+ found = False
+ for pair in pairs:
+ if pair.matches(fromUrl, toUrl):
+ found = True
+ if not found:
+ pairs.append(RoutePair(fromUrl, toUrl))
+ for pair in pairs:
+ print " %s" % pair
+ print
- def AddRoute (self, srcBroker, exchange, routingKey, tag, excludes):
- self.src = Broker (srcBroker)
- mc = self.mclient
+ print "Static Routes:"
+ bridges = qmf.getObjects(_class="bridge", dynamic=False)
+ if len(bridges) == 0:
+ print " none found"
+ print
- if self.dest.name() == self.src.name():
- print "Linking broker to itself is not permitted"
- sys.exit(1)
+ for bridge in bridges:
+ link = bridge._linkRef_
+ fromUrl = "%s:%s" % (link.host, link.port)
+ toUrl = bridge.getBroker().getUrl()
+ leftType = "ex"
+ rightType = "ex"
+ if bridge.srcIsLocal:
+ arrow = "=>"
+ left = bridge.src
+ right = bridge.dest
+ if bridge.srcIsQueue:
+ leftType = "queue"
+ else:
+ arrow = "<="
+ left = bridge.dest
+ right = bridge.src
+ if bridge.srcIsQueue:
+ rightType = "queue"
+
+ if bridge.srcIsQueue:
+ print " %s(%s=%s) %s %s(%s=%s)" % \
+ (toUrl, leftType, left, arrow, fromUrl, rightType, right)
+ else:
+ print " %s(%s=%s) %s %s(%s=%s) key=%s" % \
+ (toUrl, leftType, left, arrow, fromUrl, rightType, right, bridge.key)
+ print
+
+ for broker in brokerList:
+ if broker != self.local.name():
+ qmf.delBroker(brokerList[broker])
- brokers = mc.syncGetObjects (self.mch, "broker")
- broker = brokers[0]
- link = self.getLink ()
+ def addRoute(self, remoteBroker, exchange, routingKey, tag, excludes, dynamic=False):
+ if dynamic and _srclocal:
+ raise Exception("--src-local is not permitted on dynamic routes")
+
+ self.addLink(remoteBroker)
+ link = self.getLink()
if link == None:
- if _verbose:
- print "Inter-broker link not found, creating..."
-
- connectArgs = {}
- connectArgs["host"] = self.src.host
- connectArgs["port"] = self.src.port
- connectArgs["useSsl"] = False
- connectArgs["durable"] = _durable
- if self.src.username == "anonymous":
- connectArgs["authMechanism"] = "ANONYMOUS"
- else:
- connectArgs["authMechanism"] = "PLAIN"
- connectArgs["username"] = self.src.username
- connectArgs["password"] = self.src.password
- res = mc.syncCallMethod (self.mch, broker.id, broker.classKey, "connect", connectArgs)
- if _verbose:
- print "Connect method returned:", res.status, res.statusText
- link = self.getLink ()
+ raise Exception("Link failed to create")
+ bridges = self.qmf.getObjects(_class="bridge")
+ for bridge in bridges:
+ if bridge.linkRef == link.getObjectId() and \
+ bridge.dest == exchange and bridge.key == routingKey and not bridge.srcIsQueue:
+ if not _quiet:
+ raise Exception("Duplicate Route - ignoring: %s(%s)" % (exchange, routingKey))
+ sys.exit(0)
+
+ if _verbose:
+ print "Creating inter-broker binding..."
+ res = link.bridge(_durable, exchange, exchange, routingKey, tag, excludes, False, _srclocal, dynamic, _ack)
+ if res.status != 0:
+ raise Exception(res.text)
+ if _verbose:
+ print "Bridge method returned:", res.status, res.text
+
+ def addQueueRoute(self, remoteBroker, exchange, queue):
+ self.addLink(remoteBroker)
+ link = self.getLink()
if link == None:
- print "Protocol Error - Missing link ID"
- sys.exit (1)
+ raise Exception("Link failed to create")
- bridges = mc.syncGetObjects (self.mch, "bridge")
+ bridges = self.qmf.getObjects(_class="bridge")
for bridge in bridges:
- if bridge.linkRef == link.id and bridge.dest == exchange and bridge.key == routingKey:
+ if bridge.linkRef == link.getObjectId() and \
+ bridge.dest == exchange and bridge.src == queue and bridge.srcIsQueue:
if not _quiet:
- print "Duplicate Route - ignoring: %s(%s)" % (exchange, routingKey)
- sys.exit (1)
- sys.exit (0)
+ raise Exception("Duplicate Route - ignoring: %s(%s)" % (exchange, queue))
+ sys.exit(0)
if _verbose:
print "Creating inter-broker binding..."
- bridgeArgs = {}
- bridgeArgs["durable"] = _durable
- bridgeArgs["src"] = exchange
- bridgeArgs["dest"] = exchange
- bridgeArgs["key"] = routingKey
- bridgeArgs["tag"] = tag
- bridgeArgs["excludes"] = excludes
- bridgeArgs["srcIsQueue"] = 0
- bridgeArgs["srcIsLocal"] = 0
- res = mc.syncCallMethod (self.mch, link.id, link.classKey, "bridge", bridgeArgs)
- if res.status == 4:
- print "Can't create a durable route on a non-durable link"
- sys.exit(1)
+ res = link.bridge(_durable, queue, exchange, "", "", "", True, _srclocal, False, _ack)
+ if res.status != 0:
+ raise Exception(res.text)
if _verbose:
- print "Bridge method returned:", res.status, res.statusText
+ print "Bridge method returned:", res.status, res.text
- def DelRoute (self, srcBroker, exchange, routingKey):
- self.src = Broker (srcBroker)
- mc = self.mclient
+ def delQueueRoute(self, remoteBroker, exchange, queue):
+ self.remote = BrokerURL(remoteBroker)
+ link = self.getLink()
+ if link == None:
+ if not _quiet:
+ raise Exception("No link found from %s to %s" % (self.remote.name(), self.local.name()))
+ sys.exit(0)
+
+ bridges = self.qmf.getObjects(_class="bridge")
+ for bridge in bridges:
+ if bridge.linkRef == link.getObjectId() and \
+ bridge.dest == exchange and bridge.src == queue and bridge.srcIsQueue:
+ if _verbose:
+ print "Closing bridge..."
+ res = bridge.close()
+ if res.status != 0:
+ raise Exception("Error closing bridge: %d - %s" % (res.status, res.text))
+ if len(bridges) == 1 and _dellink:
+ link = self.getLink()
+ if link == None:
+ sys.exit(0)
+ if _verbose:
+ print "Last bridge on link, closing link..."
+ res = link.close()
+ if res.status != 0:
+ raise Exception("Error closing link: %d - %s" % (res.status, res.text))
+ sys.exit(0)
+ if not _quiet:
+ raise Exception("Route not found")
- link = self.getLink ()
+ def delRoute(self, remoteBroker, exchange, routingKey, dynamic=False):
+ self.remote = BrokerURL(remoteBroker)
+ link = self.getLink()
if link == None:
if not _quiet:
- print "No link found from %s to %s" % (self.src.name(), self.dest.name())
- sys.exit (1)
- sys.exit (0)
+ raise Exception("No link found from %s to %s" % (self.remote.name(), self.local.name()))
+ sys.exit(0)
- bridges = mc.syncGetObjects (self.mch, "bridge")
+ bridges = self.qmf.getObjects(_class="bridge")
for bridge in bridges:
- if bridge.linkRef == link.id and bridge.dest == exchange and bridge.key == routingKey:
+ if bridge.linkRef == link.getObjectId() and bridge.dest == exchange and bridge.key == routingKey \
+ and bridge.dynamic == dynamic:
if _verbose:
print "Closing bridge..."
- res = mc.syncCallMethod (self.mch, bridge.id, bridge.classKey, "close")
+ res = bridge.close()
if res.status != 0:
- print "Error closing bridge: %d - %s" % (res.status, res.statusText)
- sys.exit (1)
- if len (bridges) == 1 and _dellink:
- link = self.getLink ()
+ raise Exception("Error closing bridge: %d - %s" % (res.status, res.text))
+ if len(bridges) == 1 and _dellink:
+ link = self.getLink()
if link == None:
- sys.exit (0)
+ sys.exit(0)
if _verbose:
print "Last bridge on link, closing link..."
- res = mc.syncCallMethod (self.mch, link.id, link.classKey, "close")
+ res = link.close()
if res.status != 0:
- print "Error closing link: %d - %s" % (res.status, res.statusText)
- sys.exit (1)
- sys.exit (0)
+ raise Exception("Error closing link: %d - %s" % (res.status, res.text))
+ sys.exit(0)
if not _quiet:
- print "Route not found"
- sys.exit (1)
+ raise Exception("Route not found")
- def ListRoutes (self):
- mc = self.mclient
- links = mc.syncGetObjects (self.mch, "link")
- bridges = mc.syncGetObjects (self.mch, "bridge")
+ def listRoutes(self):
+ links = self.qmf.getObjects(_class="link")
+ bridges = self.qmf.getObjects(_class="bridge")
for bridge in bridges:
myLink = None
for link in links:
- if bridge.linkRef == link.id:
+ if bridge.linkRef == link.getObjectId():
myLink = link
break
if myLink != None:
- print "%s %s:%d %s %s" % (self.dest.name(), myLink.host, myLink.port, bridge.dest, bridge.key)
+ if bridge.dynamic:
+ keyText = "<dynamic>"
+ else:
+ keyText = bridge.key
+ print "%s %s:%d %s %s" % (self.local.name(), myLink.host, myLink.port, bridge.dest, keyText)
- def ClearAllRoutes (self):
- mc = self.mclient
- links = mc.syncGetObjects (self.mch, "link")
- bridges = mc.syncGetObjects (self.mch, "bridge")
+ def clearAllRoutes(self):
+ links = self.qmf.getObjects(_class="link")
+ bridges = self.qmf.getObjects(_class="bridge")
for bridge in bridges:
if _verbose:
myLink = None
for link in links:
- if bridge.linkRef == link.id:
+ if bridge.linkRef == link.getObjectId():
myLink = link
break
if myLink != None:
print "Deleting Bridge: %s:%d %s %s... " % (myLink.host, myLink.port, bridge.dest, bridge.key),
- res = mc.syncCallMethod (self.mch, bridge.id, bridge.classKey, "close")
+ res = bridge.close()
if res.status != 0:
- print "Error: %d - %s" % (res.status, res.statusText)
+ print "Error: %d - %s" % (res.status, res.text)
elif _verbose:
print "Ok"
if _dellink:
- links = mc.syncGetObjects (self.mch, "link")
+ links = self.qmf.getObjects(_class="link")
for link in links:
if _verbose:
print "Deleting Link: %s:%d... " % (link.host, link.port),
- res = mc.syncCallMethod (self.mch, link.id, link.classKey, "close")
+ res = link.close()
if res.status != 0:
- print "Error: %d - %s" % (res.status, res.statusText)
+ print "Error: %d - %s" % (res.status, res.text)
elif _verbose:
print "Ok"
+class RoutePair:
+ def __init__(self, fromUrl, toUrl):
+ self.fromUrl = fromUrl
+ self.toUrl = toUrl
+ self.bidir = False
+
+ def __repr__(self):
+ if self.bidir:
+ delimit = "<=>"
+ else:
+ delimit = " =>"
+ return "%s %s %s" % (self.fromUrl, delimit, self.toUrl)
+
+ def matches(self, fromUrl, toUrl):
+ if fromUrl == self.fromUrl and toUrl == self.toUrl:
+ return True
+ if toUrl == self.fromUrl and fromUrl == self.toUrl:
+ self.bidir = True
+ return True
+ return False
+
+
def YN(val):
if val == 1:
return 'Y'
@@ -306,12 +405,22 @@ def YN(val):
##
try:
- longOpts = ("verbose", "quiet", "durable", "del-empty-link")
- (optlist, cargs) = getopt.gnu_getopt (sys.argv[1:], "vqde", longOpts)
+ longOpts = ("verbose", "quiet", "durable", "del-empty-link", "src-local", "transport=", "ack=", "timeout=")
+ (optlist, encArgs) = getopt.gnu_getopt(sys.argv[1:], "vqdest:", longOpts)
except:
- Usage ()
+ Usage()
+
+try:
+ encoding = locale.getpreferredencoding()
+ cargs = [a.decode(encoding) for a in encArgs]
+except:
+ cargs = encArgs
for opt in optlist:
+ if opt[0] == "--timeout":
+ _connTimeout = int(opt[1])
+ if _connTimeout == 0:
+ _connTimeout = None
if opt[0] == "-v" or opt[0] == "--verbose":
_verbose = True
if opt[0] == "-q" or opt[0] == "--quiet":
@@ -320,52 +429,96 @@ for opt in optlist:
_durable = True
if opt[0] == "-e" or opt[0] == "--del-empty-link":
_dellink = True
-
-nargs = len (cargs)
+ if opt[0] == "-s" or opt[0] == "--src-local":
+ _srclocal = True
+ if opt[0] == "-t" or opt[0] == "--transport":
+ _transport = opt[1]
+ if opt[0] == "--ack":
+ _ack = int(opt[1])
+
+nargs = len(cargs)
if nargs < 2:
- Usage ()
+ Usage()
if nargs == 2:
- destBroker = "localhost"
+ localBroker = "localhost"
else:
- destBroker = cargs[2]
+ if _srclocal:
+ localBroker = cargs[3]
+ remoteBroker = cargs[2]
+ else:
+ localBroker = cargs[2]
+ if nargs > 3:
+ remoteBroker = cargs[3]
group = cargs[0]
cmd = cargs[1]
-rm = RouteManager (destBroker)
-rm.ConnectToBroker ()
-if group == "link":
- if cmd == "add":
- if nargs != 4:
- Usage()
- rm.AddLink (cargs[3])
- elif cmd == "del":
- if nargs != 4:
- Usage()
- rm.DelLink (cargs[3])
- elif cmd == "list":
- rm.ListLinks ()
-
-elif group == "route":
- if cmd == "add":
- if nargs < 6 or nargs > 8:
- Usage ()
-
- tag = ""
- excludes = ""
- if nargs > 6: tag = cargs[6]
- if nargs > 7: excludes = cargs[7]
- rm.AddRoute (cargs[3], cargs[4], cargs[5], tag, excludes)
- elif cmd == "del":
- if nargs != 6:
- Usage ()
+try:
+ rm = RouteManager(localBroker)
+ if group == "link":
+ if cmd == "add":
+ if nargs != 4:
+ Usage()
+ rm.addLink(remoteBroker)
+ elif cmd == "del":
+ if nargs != 4:
+ Usage()
+ rm.delLink(remoteBroker)
+ elif cmd == "list":
+ rm.listLinks()
+
+ elif group == "dynamic":
+ if cmd == "add":
+ if nargs < 5 or nargs > 7:
+ Usage()
+
+ tag = ""
+ excludes = ""
+ if nargs > 5: tag = cargs[5]
+ if nargs > 6: excludes = cargs[6]
+ rm.addRoute(remoteBroker, cargs[4], "", tag, excludes, dynamic=True)
+ elif cmd == "del":
+ if nargs != 5:
+ Usage()
+ else:
+ rm.delRoute(remoteBroker, cargs[4], "", dynamic=True)
+
+ elif group == "route":
+ if cmd == "add":
+ if nargs < 6 or nargs > 8:
+ Usage()
+
+ tag = ""
+ excludes = ""
+ if nargs > 6: tag = cargs[6]
+ if nargs > 7: excludes = cargs[7]
+ rm.addRoute(remoteBroker, cargs[4], cargs[5], tag, excludes, dynamic=False)
+ elif cmd == "del":
+ if nargs != 6:
+ Usage()
+ rm.delRoute(remoteBroker, cargs[4], cargs[5], dynamic=False)
+ elif cmd == "map":
+ rm.mapRoutes()
else:
- rm.DelRoute (cargs[3], cargs[4], cargs[5])
- else:
- if cmd == "list":
- rm.ListRoutes ()
- elif cmd == "flush":
- rm.ClearAllRoutes ()
+ if cmd == "list":
+ rm.listRoutes()
+ elif cmd == "flush":
+ rm.clearAllRoutes()
+ else:
+ Usage()
+
+ elif group == "queue":
+ if nargs != 6:
+ Usage()
+ if cmd == "add":
+ rm.addQueueRoute(remoteBroker, exchange=cargs[4], queue=cargs[5])
+ elif cmd == "del":
+ rm.delQueueRoute(remoteBroker, exchange=cargs[4], queue=cargs[5])
else:
- Usage ()
-rm.Disconnect ()
+ Usage()
+
+except Exception,e:
+ print "Failed: %s - %s" % (e.__class__.__name__, e)
+ sys.exit(1)
+
+rm.disconnect()
diff --git a/python/commands/qpid-stat b/python/commands/qpid-stat
new file mode 100755
index 0000000000..29deeb2342
--- /dev/null
+++ b/python/commands/qpid-stat
@@ -0,0 +1,460 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import os
+import getopt
+import sys
+import locale
+import socket
+import re
+from qmf.console import Session, Console
+from qpid.disp import Display, Header, Sorter
+
+_host = "localhost"
+_connTimeout = 10
+_types = ""
+_limit = 50
+_increasing = False
+_sortcol = None
+pattern = re.compile("^\\d+\\.\\d+\\.\\d+\\.\\d+:\\d+$")
+
+def Usage ():
+ print "Usage: qpid-stat [OPTIONS] [broker-addr]"
+ print
+ print " broker-addr is in the form: [username/password@] hostname | ip-address [:<port>]"
+ print " ex: localhost, 10.1.1.7:10000, broker-host:10000, guest/guest@localhost"
+ print
+ print "General Options:"
+ print " --timeout seconds (10) Maximum time to wait for broker connection"
+# print " -n [--numeric] Don't resolve names"
+ print
+ print "Display Options:"
+ print
+ print " -b Show Brokers"
+ print " -c Show Connections"
+# print " -s Show Sessions"
+ print " -e Show Exchanges"
+ print " -q Show Queues"
+ print
+ print " -S [--sort-by] COLNAME Sort by column name"
+ print " -I [--increasing] Sort by increasing value (default = decreasing)"
+ print " -L [--limit] NUM Limit output to NUM rows (default = 50)"
+ print
+ sys.exit (1)
+
+class IpAddr:
+ def __init__(self, text):
+ if text.find("@") != -1:
+ tokens = text.split("@")
+ text = tokens[1]
+ if text.find(":") != -1:
+ tokens = text.split(":")
+ text = tokens[0]
+ self.port = int(tokens[1])
+ else:
+ self.port = 5672
+ self.dottedQuad = socket.gethostbyname(text)
+ nums = self.dottedQuad.split(".")
+ self.addr = (int(nums[0]) << 24) + (int(nums[1]) << 16) + (int(nums[2]) << 8) + int(nums[3])
+
+ def bestAddr(self, addrPortList):
+ bestDiff = 0xFFFFFFFFL
+ bestAddr = None
+ for addrPort in addrPortList:
+ diff = IpAddr(addrPort[0]).addr ^ self.addr
+ if diff < bestDiff:
+ bestDiff = diff
+ bestAddr = addrPort
+ return bestAddr
+
+class Broker(object):
+ def __init__(self, qmf, broker):
+ self.broker = broker
+
+ agents = qmf.getAgents()
+ for a in agents:
+ if a.getAgentBank() == 0:
+ self.brokerAgent = a
+
+ bobj = qmf.getObjects(_class="broker", _package="org.apache.qpid.broker", _agent=self.brokerAgent)[0]
+ self.currentTime = bobj.getTimestamps()[0]
+ try:
+ self.uptime = bobj.uptime
+ except:
+ self.uptime = 0
+ self.connections = {}
+ self.sessions = {}
+ self.exchanges = {}
+ self.queues = {}
+ package = "org.apache.qpid.broker"
+
+ list = qmf.getObjects(_class="connection", _package=package, _agent=self.brokerAgent)
+ for conn in list:
+ if pattern.match(conn.address):
+ self.connections[conn.getObjectId()] = conn
+
+ list = qmf.getObjects(_class="session", _package=package, _agent=self.brokerAgent)
+ for sess in list:
+ if sess.connectionRef in self.connections:
+ self.sessions[sess.getObjectId()] = sess
+
+ list = qmf.getObjects(_class="exchange", _package=package, _agent=self.brokerAgent)
+ for exchange in list:
+ self.exchanges[exchange.getObjectId()] = exchange
+
+ list = qmf.getObjects(_class="queue", _package=package, _agent=self.brokerAgent)
+ for queue in list:
+ self.queues[queue.getObjectId()] = queue
+
+ def getName(self):
+ return self.broker.getUrl()
+
+ def getCurrentTime(self):
+ return self.currentTime
+
+ def getUptime(self):
+ return self.uptime
+
+class BrokerManager(Console):
+ def __init__(self):
+ self.brokerName = None
+ self.qmf = None
+ self.broker = None
+ self.brokers = []
+ self.cluster = None
+
+ def SetBroker(self, brokerUrl):
+ self.url = brokerUrl
+ self.qmf = Session()
+ self.broker = self.qmf.addBroker(brokerUrl, _connTimeout)
+ agents = self.qmf.getAgents()
+ for a in agents:
+ if a.getAgentBank() == 0:
+ self.brokerAgent = a
+
+ def Disconnect(self):
+ if self.broker:
+ self.qmf.delBroker(self.broker)
+
+ def _getCluster(self):
+ packages = self.qmf.getPackages()
+ if "org.apache.qpid.cluster" not in packages:
+ return None
+
+ clusters = self.qmf.getObjects(_class="cluster", _agent=self.brokerAgent)
+ if len(clusters) == 0:
+ print "Clustering is installed but not enabled on the broker."
+ return None
+
+ self.cluster = clusters[0]
+
+ def _getHostList(self, urlList):
+ hosts = []
+ hostAddr = IpAddr(_host)
+ for url in urlList:
+ if url.find("amqp:") != 0:
+ raise Exception("Invalid URL 1")
+ url = url[5:]
+ addrs = str(url).split(",")
+ addrList = []
+ for addr in addrs:
+ tokens = addr.split(":")
+ if len(tokens) != 3:
+ raise Exception("Invalid URL 2")
+ addrList.append((tokens[1], tokens[2]))
+
+ # Find the address in the list that is most likely to be in the same subnet as the address
+ # with which we made the original QMF connection. This increases the probability that we will
+ # be able to reach the cluster member.
+
+ best = hostAddr.bestAddr(addrList)
+ bestUrl = best[0] + ":" + best[1]
+ hosts.append(bestUrl)
+ return hosts
+
+ def displaySubs(self, subs, indent, broker=None, conn=None, sess=None, exchange=None, queue=None):
+ if len(subs) == 0:
+ return
+ this = subs[0]
+ remaining = subs[1:]
+ newindent = indent + " "
+ if this == 'b':
+ pass
+ elif this == 'c':
+ if broker:
+ for oid in broker.connections:
+ iconn = broker.connections[oid]
+ self.printConnSub(indent, broker.getName(), iconn)
+ self.displaySubs(remaining, newindent, broker=broker, conn=iconn,
+ sess=sess, exchange=exchange, queue=queue)
+ elif this == 's':
+ pass
+ elif this == 'e':
+ pass
+ elif this == 'q':
+ pass
+ print
+
+ def displayBroker(self, subs):
+ disp = Display(prefix=" ")
+ heads = []
+ heads.append(Header('broker'))
+ heads.append(Header('cluster'))
+ heads.append(Header('uptime', Header.DURATION))
+ heads.append(Header('conn', Header.KMG))
+ heads.append(Header('sess', Header.KMG))
+ heads.append(Header('exch', Header.KMG))
+ heads.append(Header('queue', Header.KMG))
+ rows = []
+ for broker in self.brokers:
+ if self.cluster:
+ ctext = "%s(%s)" % (self.cluster.clusterName, self.cluster.status)
+ else:
+ ctext = "<standalone>"
+ row = (broker.getName(), ctext, broker.getUptime(),
+ len(broker.connections), len(broker.sessions),
+ len(broker.exchanges), len(broker.queues))
+ rows.append(row)
+ title = "Brokers"
+ if _sortcol:
+ sorter = Sorter(heads, rows, _sortcol, _limit, _increasing)
+ dispRows = sorter.getSorted()
+ else:
+ dispRows = rows
+ disp.formattedTable(title, heads, dispRows)
+
+ def displayConn(self, subs):
+ disp = Display(prefix=" ")
+ heads = []
+ if self.cluster:
+ heads.append(Header('broker'))
+ heads.append(Header('client-addr'))
+ heads.append(Header('cproc'))
+ heads.append(Header('cpid'))
+ heads.append(Header('auth'))
+ heads.append(Header('connected', Header.DURATION))
+ heads.append(Header('idle', Header.DURATION))
+ heads.append(Header('msgIn', Header.KMG))
+ heads.append(Header('msgOut', Header.KMG))
+ rows = []
+ for broker in self.brokers:
+ for oid in broker.connections:
+ conn = broker.connections[oid]
+ row = []
+ if self.cluster:
+ row.append(broker.getName())
+ row.append(conn.address)
+ row.append(conn.remoteProcessName)
+ row.append(conn.remotePid)
+ row.append(conn.authIdentity)
+ row.append(broker.getCurrentTime() - conn.getTimestamps()[1])
+ idle = broker.getCurrentTime() - conn.getTimestamps()[0]
+ row.append(broker.getCurrentTime() - conn.getTimestamps()[0])
+ row.append(conn.framesFromClient)
+ row.append(conn.framesToClient)
+ rows.append(row)
+ title = "Connections"
+ if self.cluster:
+ title += " for cluster '%s'" % self.cluster.clusterName
+ if _sortcol:
+ sorter = Sorter(heads, rows, _sortcol, _limit, _increasing)
+ dispRows = sorter.getSorted()
+ else:
+ dispRows = rows
+ disp.formattedTable(title, heads, dispRows)
+
+ def displaySession(self, subs):
+ disp = Display(prefix=" ")
+
+ def displayExchange(self, subs):
+ disp = Display(prefix=" ")
+ heads = []
+ if self.cluster:
+ heads.append(Header('broker'))
+ heads.append(Header("exchange"))
+ heads.append(Header("type"))
+ heads.append(Header("dur", Header.Y))
+ heads.append(Header("bind", Header.KMG))
+ heads.append(Header("msgIn", Header.KMG))
+ heads.append(Header("msgOut", Header.KMG))
+ heads.append(Header("msgDrop", Header.KMG))
+ heads.append(Header("byteIn", Header.KMG))
+ heads.append(Header("byteOut", Header.KMG))
+ heads.append(Header("byteDrop", Header.KMG))
+ rows = []
+ for broker in self.brokers:
+ for oid in broker.exchanges:
+ ex = broker.exchanges[oid]
+ row = []
+ if self.cluster:
+ row.append(broker.getName())
+ row.append(ex.name)
+ row.append(ex.type)
+ row.append(ex.durable)
+ row.append(ex.bindingCount)
+ row.append(ex.msgReceives)
+ row.append(ex.msgRoutes)
+ row.append(ex.msgDrops)
+ row.append(ex.byteReceives)
+ row.append(ex.byteRoutes)
+ row.append(ex.byteDrops)
+ rows.append(row)
+ title = "Exchanges"
+ if self.cluster:
+ title += " for cluster '%s'" % self.cluster.clusterName
+ if _sortcol:
+ sorter = Sorter(heads, rows, _sortcol, _limit, _increasing)
+ dispRows = sorter.getSorted()
+ else:
+ dispRows = rows
+ disp.formattedTable(title, heads, dispRows)
+
+ def displayQueue(self, subs):
+ disp = Display(prefix=" ")
+ heads = []
+ if self.cluster:
+ heads.append(Header('broker'))
+ heads.append(Header("queue"))
+ heads.append(Header("dur", Header.Y))
+ heads.append(Header("autoDel", Header.Y))
+ heads.append(Header("excl", Header.Y))
+ heads.append(Header("msg", Header.KMG))
+ heads.append(Header("msgIn", Header.KMG))
+ heads.append(Header("msgOut", Header.KMG))
+ heads.append(Header("bytes", Header.KMG))
+ heads.append(Header("bytesIn", Header.KMG))
+ heads.append(Header("bytesOut", Header.KMG))
+ heads.append(Header("cons", Header.KMG))
+ heads.append(Header("bind", Header.KMG))
+ rows = []
+ for broker in self.brokers:
+ for oid in broker.queues:
+ q = broker.queues[oid]
+ row = []
+ if self.cluster:
+ row.append(broker.getName())
+ row.append(q.name)
+ row.append(q.durable)
+ row.append(q.autoDelete)
+ row.append(q.exclusive)
+ row.append(q.msgDepth)
+ row.append(q.msgTotalEnqueues)
+ row.append(q.msgTotalDequeues)
+ row.append(q.byteDepth)
+ row.append(q.byteTotalEnqueues)
+ row.append(q.byteTotalDequeues)
+ row.append(q.consumerCount)
+ row.append(q.bindingCount)
+ rows.append(row)
+ title = "Queues"
+ if self.cluster:
+ title += " for cluster '%s'" % self.cluster.clusterName
+ if _sortcol:
+ sorter = Sorter(heads, rows, _sortcol, _limit, _increasing)
+ dispRows = sorter.getSorted()
+ else:
+ dispRows = rows
+ disp.formattedTable(title, heads, dispRows)
+
+ def displayMain(self, main, subs):
+ if main == 'b': self.displayBroker(subs)
+ elif main == 'c': self.displayConn(subs)
+ elif main == 's': self.displaySession(subs)
+ elif main == 'e': self.displayExchange(subs)
+ elif main == 'q': self.displayQueue(subs)
+
+ def display(self):
+ self._getCluster()
+ if self.cluster:
+ memberList = self.cluster.members.split(";")
+ hostList = self._getHostList(memberList)
+ self.qmf.delBroker(self.broker)
+ self.broker = None
+ if _host.find("@") > 0:
+ authString = _host.split("@")[0] + "@"
+ else:
+ authString = ""
+ for host in hostList:
+ b = self.qmf.addBroker(authString + host, _connTimeout)
+ self.brokers.append(Broker(self.qmf, b))
+ else:
+ self.brokers.append(Broker(self.qmf, self.broker))
+
+ self.displayMain(_types[0], _types[1:])
+
+
+##
+## Main Program
+##
+
+try:
+ longOpts = ("top", "numeric", "sort-by=", "limit=", "increasing", "timeout=")
+ (optlist, encArgs) = getopt.gnu_getopt(sys.argv[1:], "bceqS:L:I", longOpts)
+except:
+ Usage()
+
+try:
+ encoding = locale.getpreferredencoding()
+ cargs = [a.decode(encoding) for a in encArgs]
+except:
+ cargs = encArgs
+
+for opt in optlist:
+ if opt[0] == "--timeout":
+ _connTimeout = int(opt[1])
+ if _connTimeout == 0:
+ _connTimeout = None
+ elif opt[0] == "-n" or opt[0] == "--numeric":
+ _numeric = True
+ elif opt[0] == "-S" or opt[0] == "--sort-by":
+ _sortcol = opt[1]
+ elif opt[0] == "-I" or opt[0] == "--increasing":
+ _increasing = True
+ elif opt[0] == "-L" or opt[0] == "--limit":
+ _limit = int(opt[1])
+ elif len(opt[0]) == 2:
+ char = opt[0][1]
+ if "bcseq".find(char) != -1:
+ _types += char
+ else:
+ Usage()
+ else:
+ Usage()
+
+if len(_types) == 0:
+ Usage()
+
+nargs = len(cargs)
+bm = BrokerManager()
+
+if nargs == 1:
+ _host = cargs[0]
+
+try:
+ bm.SetBroker(_host)
+ bm.display()
+except KeyboardInterrupt:
+ print
+except Exception,e:
+ print "Failed: %s - %s" % (e.__class__.__name__, e)
+ sys.exit(1)
+
+bm.Disconnect()
diff --git a/python/commands/qpid-tool b/python/commands/qpid-tool
index 60535c253b..05afcc9732 100755
--- a/python/commands/qpid-tool
+++ b/python/commands/qpid-tool
@@ -24,7 +24,7 @@ import getopt
import sys
import socket
from cmd import Cmd
-from qpid.connection import ConnectionFailed
+from qpid.connection import ConnectionFailed, Timeout
from qpid.managementdata import ManagementData
from shlex import split
from qpid.disp import Display
@@ -148,7 +148,7 @@ class Mcli (Cmd):
self.dataObject.close ()
def Usage ():
- print "Usage: qpid-tool [<target-host[:<tcp-port>]]"
+ print "Usage: qpid-tool [[<username>/<password>@]<target-host>[:<tcp-port>]]"
print
sys.exit (1)
@@ -183,6 +183,8 @@ except ConnectionFailed, e:
except Exception, e:
if str(e).find ("Exchange not found") != -1:
print "Management not enabled on broker: Use '-m yes' option on broker startup."
+ else:
+ print "Failed: %s - %s" % (e.__class__.__name__, e)
sys.exit(1)
# Instantiate the CLI interpreter and launch it.
diff --git a/python/cpp_failing_0-10.txt b/python/cpp_failing_0-10.txt
deleted file mode 100644
index e69de29bb2..0000000000
--- a/python/cpp_failing_0-10.txt
+++ /dev/null
diff --git a/python/cpp_failing_0-8.txt b/python/cpp_failing_0-8.txt
deleted file mode 100644
index e69de29bb2..0000000000
--- a/python/cpp_failing_0-8.txt
+++ /dev/null
diff --git a/python/cpp_failing_0-9.txt b/python/cpp_failing_0-9.txt
deleted file mode 100644
index 06c31080fb..0000000000
--- a/python/cpp_failing_0-9.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-tests_0-9.message.MessageTests.test_checkpoint
-tests_0-9.message.MessageTests.test_reject
-tests_0-9.basic.BasicTests.test_get
-
diff --git a/python/doc/test-requirements.txt b/python/doc/test-requirements.txt
index a1ba414eb2..5089b49dbe 100644
--- a/python/doc/test-requirements.txt
+++ b/python/doc/test-requirements.txt
@@ -1,3 +1,22 @@
+###############################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+###############################################################################
+
* start and stop server, possibly in different configurations, should
at least be able to specify host and port
diff --git a/python/examples/README b/python/examples/README
new file mode 100644
index 0000000000..bd30b2a6f4
--- /dev/null
+++ b/python/examples/README
@@ -0,0 +1,319 @@
+Running the Python Examples
+============================
+
+
+Running the Direct Examples
+----------------------------
+
+To run the direct examples, do the following:
+
+1. Make sure that a qpidd broker is running:
+
+ $ ps -eaf | grep qpidd
+
+ If a broker is running, you should see the qpidd process in the output of the above command.
+
+2.Declare a message queue and bind it to an exchange by running declare_queues.py, as follows:
+
+ $ python declare_queues.py
+
+ This program has no output. After this program has been run, all messages sent to the amq.direct exchange using the routing key routing_key are sent to the queue named message_queue.
+
+3.Publish a series of messages to the amq.direct exchange by running direct_producer.py, as follows:
+
+ $ python direct_producer.py
+
+This program has no output; the messages are routed to the message queue, as instructed by the binding.
+
+4. Read the messages from the message queue using direct_consumer.py or listener.py, as follows:
+
+ $ python direct_consumer.py
+
+ or
+
+ $ python listener.py
+
+You should see the following output:
+
+message 0
+message 1
+message 2
+message 3
+message 4
+message 5
+message 6
+message 7
+message 8
+message 9
+That's all, folks!
+
+
+
+Running the Fanout Examples
+----------------------------
+
+To run the programs for the Fanout example, do the following:
+
+1. Make sure that a qpidd broker is running:
+
+ $ ps -eaf | grep qpidd
+
+If a broker is running, you should see the qpidd process in the output of the above command.
+
+2. In separate windows, start two or more fanout consumers or fanout listeners as follows:
+
+ $ python fanout_consumer.py
+
+ or
+
+ $ python listener.py
+
+These programs each create a private queue, bind it to the amq.fanout exchange, and wait for messages to arrive on their queue.
+
+3. In a separate window, publish a series of messages to the amq.fanout exchange by running fanout_producer.py, as follows:
+
+ $ python fanout_producer.py
+
+This program has no output; the messages are routed to the message queue, as instructed by the binding.
+
+4. Go to the windows where you are running consumers or listeners. You should see the following output for each listener or consumer:
+
+ message 0
+ message 1
+ message 2
+ message 3
+ message 4
+ message 5
+ message 6
+ message 7
+ message 8
+ message 9
+ That's all, folks!
+
+
+
+Running the Publish-Subscribe Examples
+---------------------------------------
+
+To run the programs for the Publish-Subscribe example, do the following:
+
+1. Make sure that a qpidd broker is running:
+
+ $ ps -eaf | grep qpidd
+
+If a broker is running, you should see the qpidd process in the output of the above command.
+
+2. In separate windows, start one or more topic subscribers by running topic_subscriber.py, as follows:
+
+ $ python topic_subscriber.py
+
+You will see output similar to this:
+
+ Queues created - please start the topic producer
+ Subscribing local queue 'local_news' to news-53408183-fcee-4b92-950b-90abb297e739'
+ Subscribing local queue 'local_weather' to weather-53408183-fcee-4b92-950b-90abb297e739'
+ Subscribing local queue 'local_usa' to usa-53408183-fcee-4b92-950b-90abb297e739'
+ Subscribing local queue 'local_europe' to europe-53408183-fcee-4b92-950b-90abb297e739'
+ Messages on 'news' queue:
+
+Each topic consumer creates a set of private queues, and binds each queue to the amq.topic exchange together with a binding that indicates which messages should be routed to the queue.
+
+3.In another window, start the topic publisher, which publishes messages to the amq.topic exchange, as follows:
+
+ $ python topic_publisher.py
+
+This program has no output; the messages are routed to the message queues for each topic_consumer as specified by the bindings the consumer created.
+
+4. Go back to the window for each topic consumer. You should see output like this:
+
+ Messages on 'news' queue:
+ usa.news 0
+ usa.news 1
+ usa.news 2
+ usa.news 3
+ usa.news 4
+ europe.news 0
+ europe.news 1
+ europe.news 2
+ europe.news 3
+ europe.news 4
+ That's all, folks!
+ Messages on 'weather' queue:
+ usa.weather 0
+ usa.weather 1
+ usa.weather 2
+ usa.weather 3
+ usa.weather 4
+ europe.weather 0
+ europe.weather 1
+ europe.weather 2
+ europe.weather 3
+ europe.weather 4
+ That's all, folks!
+ Messages on 'usa' queue:
+ usa.news 0
+ usa.news 1
+ usa.news 2
+ usa.news 3
+ usa.news 4
+ usa.weather 0
+ usa.weather 1
+ usa.weather 2
+ usa.weather 3
+ usa.weather 4
+ That's all, folks!
+ Messages on 'europe' queue:
+ europe.news 0
+ europe.news 1
+ europe.news 2
+ europe.news 3
+ europe.news 4
+ europe.weather 0
+ europe.weather 1
+ europe.weather 2
+ europe.weather 3
+ europe.weather 4
+ That's all, folks!
+
+
+Running the Request/Response Examples
+--------------------------------------
+
+To run the programs for the Request/Response example, do the following:
+
+1. Make sure that a qpidd broker is running:
+
+ $ ps -eaf | grep qpidd
+
+If a broker is running, you should see the qpidd process in the output of the above command.
+
+2. Run the server.
+
+ $ python server.py
+
+You should see the following output:
+
+ Request server running - run your client now.
+ (Times out after 100 seconds ...)
+
+3. In a separate window, start a client:
+
+ $ python client.py
+
+You should see the following output:
+
+ Request: Twas brillig, and the slithy toves
+ Request: Did gyre and gimble in the wabe.
+ Request: All mimsy were the borogroves,
+ Request: And the mome raths outgrabe.
+ Messages on queue: reply_to:db0f862e-6b36-4e0f-a4b2-ad049eb435ce
+ Response: TWAS BRILLIG, AND THE SLITHY TOVES
+ Response: DID GYRE AND GIMBLE IN THE WABE.
+ Response: ALL MIMSY WERE THE BOROGROVES,
+ Response: AND THE MOME RATHS OUTGRABE.
+ No more messages!
+
+
+Running the XML-based Routing Examples
+---------------------------------------
+
+To run the programs for the XML-based Routing example, do the following:
+
+1. Make sure that a qpidd broker is running:
+
+ $ ps -eaf | grep qpidd
+
+If a broker is running, you should see the qpidd process in the output of the above command.
+
+2. Declare an XML exchange and a message queue, then bind the queue to the exchange by running declare_queues.py, as follows:
+
+ $ python declare_queues.py
+
+This program has no output. After this program has been run, all messages sent to the xml exchange using the routing key weather are sent to the queue named message_queue if they satisfy the conditions specified in the following XQuery, which is used in the binding:
+
+ let $w := ./weather
+ return $w/station = 'Raleigh-Durham International Airport (KRDU)'
+ and $w/temperature_f > 50
+ and $w/temperature_f - $w/dewpoint > 5
+ and $w/wind_speed_mph > 7
+ and $w/wind_speed_mph < 20
+
+3. Publish a series of messages to the xml exchange by running xml_producer.py, as follows:
+
+ $ python xml_producer.py
+
+The messages are routed to the message queue, as prescribed by the binding. Each message represents a weather report, such as this one:
+
+ <weather>
+ <station>Raleigh-Durham International Airport (KRDU)</station>
+ <wind_speed_mph>16</wind_speed_mph>
+ <temperature_f>70</temperature_f>
+ <dewpoint>35</dewpoint>
+ </weather>
+
+4. Read the messages from the message queue using direct_consumer.py or listener.py, as follows:
+
+ $ python xml_consumer.py
+
+ or
+
+ $ python listener.py
+
+You should see the following output:
+
+<weather><station>Raleigh-Durham International Airport (KRDU)</station>
+<wind_speed_mph>16</wind_speed_mph><temperature_f>70</temperature_f>
+<dewpoint>35</dewpoint></weather>
+
+
+Running the Headers Examples
+-----------------------------
+
+To run the headers examples, do the following:
+
+1. Make sure that a qpidd broker is running:
+
+ $ ps -eaf | grep qpidd
+
+ If a broker is running, you should see the qpidd process in the output of the above command.
+
+2.Declare a message queues and bind them to an exchange by running declare_queues.py, as follows:
+
+ $ python declare_queues.py
+
+ This program has no output. After this program has been run, all messages sent to the amq.match exchange with an application-header of {'class': 'first'} will be routed to the queue named "first" and messages with an application-header of {'class': 'second'} will be routed to the queue named "second".
+
+3.Publish a series of messages to the amq.match exchange by running headers_producer.py, as follows:
+
+ $ python headers_producer.py
+
+This program has no output; the messages are routed to the message queues, as instructed by the bindings.
+
+4. Read the messages from the message queues using headers_consumer.py as follows:
+
+ $ python headers_consumer.py
+
+You should see the following output:
+
+message(first) 0
+message(first) 1
+message(first) 2
+message(first) 3
+message(first) 4
+message(first) 5
+message(first) 6
+message(first) 7
+message(first) 8
+message(first) 9
+That's all, folks!
+message(second) 0
+message(second) 1
+message(second) 2
+message(second) 3
+message(second) 4
+message(second) 5
+message(second) 6
+message(second) 7
+message(second) 8
+message(second) 9
+That's all, folks!
diff --git a/python/examples/api/drain b/python/examples/api/drain
new file mode 100755
index 0000000000..485985f16d
--- /dev/null
+++ b/python/examples/api/drain
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import optparse
+from qpid.messaging import *
+from qpid.util import URL
+
+parser = optparse.OptionParser(usage="usage: %prog [options] ADDRESS ...",
+ description="Drain messages from the supplied address.")
+parser.add_option("-b", "--broker", default="localhost",
+ help="connect to specified BROKER (default %default)")
+parser.add_option("-t", "--timeout", type=float, default=0,
+ help="timeout in seconds to wait before exiting (default %default)")
+parser.add_option("-f", "--forever", action="store_true",
+ help="ignore timeout and wait forever")
+
+opts, args = parser.parse_args()
+
+url = URL(opts.broker)
+if args:
+ addr = args.pop(0)
+else:
+ parser.error("address is required")
+if opts.forever:
+ timeout = None
+else:
+ timeout = opts.timeout
+
+# XXX: should make URL default the port for us
+conn = Connection.open(url.host, url.port or AMQP_PORT,
+ username=url.user, password=url.password)
+ssn = conn.session()
+rcv = ssn.receiver(addr)
+
+while True:
+ try:
+ print rcv.fetch(timeout=timeout)
+ ssn.acknowledge()
+ except Empty:
+ break
+ except ReceiveError, e:
+ print e
+ break
+
+conn.close()
diff --git a/python/examples/api/server b/python/examples/api/server
new file mode 100755
index 0000000000..adb2dcf792
--- /dev/null
+++ b/python/examples/api/server
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import optparse, sys, traceback
+from qpid.messaging import *
+from qpid.util import URL
+from subprocess import Popen, STDOUT, PIPE
+from qpid.log import enable, DEBUG, WARN
+
+parser = optparse.OptionParser(usage="usage: %prog [options] ADDRESS ...",
+ description="handle requests from the supplied address.")
+parser.add_option("-b", "--broker", default="localhost",
+ help="connect to specified BROKER (default %default)")
+parser.add_option("-v", dest="verbose", action="store_true", help="enable logging")
+
+opts, args = parser.parse_args()
+
+if opts.verbose:
+ enable("qpid", DEBUG)
+else:
+ enable("qpid", WARN)
+
+url = URL(opts.broker)
+if args:
+ addr = args.pop(0)
+else:
+ parser.error("address is required")
+
+# XXX: should make URL default the port for us
+conn = Connection.open(url.host, url.port or AMQP_PORT,
+ username=url.user, password=url.password)
+conn.reconnect = True
+ssn = conn.session()
+rcv = ssn.receiver(addr)
+
+def dispatch(msg):
+ msg_type = msg.properties.get("type")
+ if msg_type == "shell":
+ proc = Popen(msg.content, shell=True, stderr=STDOUT, stdin=PIPE, stdout=PIPE)
+ output, _ = proc.communicate()
+ result = Message(output)
+ result.properties["exit"] = proc.returncode
+ elif msg_type == "eval":
+ try:
+ content = eval(msg.content)
+ except:
+ content = traceback.format_exc()
+ result = Message(content)
+ else:
+ result = Message("unrecognized message type: %s" % msg_type)
+ return result
+
+while True:
+ try:
+ msg = rcv.fetch()
+ response = dispatch(msg)
+ snd = ssn.sender(msg.reply_to)
+ try:
+ snd.send(response)
+ except SendError, e:
+ print e
+ snd.close()
+ ssn.acknowledge()
+ except Empty:
+ break
+ except ReceiveError, e:
+ print e
+ break
+
+conn.close()
diff --git a/python/examples/api/spout b/python/examples/api/spout
new file mode 100755
index 0000000000..6a9b2b6e3d
--- /dev/null
+++ b/python/examples/api/spout
@@ -0,0 +1,103 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import optparse, time
+from qpid.messaging import *
+from qpid.util import URL
+
+def nameval(st):
+ idx = st.find("=")
+ if idx >= 0:
+ name = st[0:idx]
+ value = st[idx+1:]
+ else:
+ name = st
+ value = None
+ return name, value
+
+parser = optparse.OptionParser(usage="usage: %prog [options] ADDRESS [ CONTENT ... ]",
+ description="Send messages to the supplied address.")
+parser.add_option("-b", "--broker", default="localhost",
+ help="connect to specified BROKER (default %default)")
+parser.add_option("-c", "--count", type=int, default=1,
+ help="stop after count messages have been sent, zero disables (default %default)")
+parser.add_option("-t", "--timeout", type=float, default=None,
+ help="exit after the specified time")
+parser.add_option("-i", "--id", help="use the supplied id instead of generating one")
+parser.add_option("-r", "--reply-to", help="specify reply-to address")
+parser.add_option("-P", "--property", dest="properties", action="append", default=[],
+ help="specify message property")
+parser.add_option("-M", "--map", dest="entries", action="append", default=[],
+ help="specify map entry for message body")
+
+opts, args = parser.parse_args()
+
+url = URL(opts.broker)
+if opts.id is None:
+ spout_id = str(uuid4())
+else:
+ spout_id = opts.id
+if args:
+ addr = args.pop(0)
+else:
+ parser.error("address is required")
+
+content = None
+
+if args:
+ text = " ".join(args)
+else:
+ text = None
+
+if opts.entries:
+ content = {}
+ if text:
+ content["text"] = text
+ for e in opts.entries:
+ name, val = nameval(e)
+ content[name] = val
+else:
+ content = text
+
+# XXX: should make URL default the port for us
+conn = Connection.open(url.host, url.port or AMQP_PORT,
+ username=url.user, password=url.password)
+ssn = conn.session()
+snd = ssn.sender(addr)
+
+count = 0
+start = time.time()
+while (opts.count == 0 or count < opts.count) and \
+ (opts.timeout is None or time.time() - start < opts.timeout):
+ msg = Message(content, reply_to=opts.reply_to)
+ msg.properties["spout-id"] = "%s:%s" % (spout_id, count)
+ for p in opts.properties:
+ name, val = nameval(p)
+ msg.properties[name] = val
+
+ try:
+ snd.send(msg)
+ count += 1
+ print msg
+ except SendError, e:
+ print e
+ break
+
+conn.close()
diff --git a/python/examples/datatypes/client.py b/python/examples/datatypes/client.py
new file mode 100755
index 0000000000..088e529909
--- /dev/null
+++ b/python/examples/datatypes/client.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+"""
+ client.py
+
+ Client for testing use of Unicode and datatypes.
+
+ Both client and server will be written in C++ and Python.
+ Tests can run clients and servers written in different
+ languages, and they can be run on 32-bit and 64-bit architectures.
+
+"""
+
+import qpid
+import sys
+import os
+from qpid.util import connect
+from qpid.connection import Connection
+from qpid.datatypes import Message, RangedSet, uuid4
+from qpid.queue import Empty
+
+import testdata
+
+#----- Initialization --------------------------------------
+
+
+# Set parameters for login
+
+host="127.0.0.1"
+port=5672
+user="guest"
+password="guest"
+
+# If an alternate host or port has been specified, use that instead
+# (this is used in our unit tests)
+if len(sys.argv) > 1 :
+ host=sys.argv[1]
+if len(sys.argv) > 2 :
+ port=int(sys.argv[2])
+
+# Create a connection.
+socket = connect(host, port)
+connection = Connection (sock=socket, username=user, password=password)
+connection.start()
+session = connection.session(str(uuid4()))
+
+
+#----- Main Body -- ----------------------------------------
+
+# Create a response queue for the server to send responses to. Use the
+# same string as the name of the queue and the name of the routing
+# key.
+
+reply_to = "reply_to:" + session.name
+session.queue_declare(queue=reply_to, exclusive=True)
+session.exchange_bind(exchange="amq.direct", queue=reply_to, binding_key=reply_to)
+
+# Create a local queue and subscribe it to the response queue
+
+local_queue_name = "local_queue"
+queue = session.incoming(local_queue_name)
+
+# Call message_subscribe() to tell the broker to deliver messages from
+# the server's reply_to queue to our local client queue. The server
+# will start delivering messages as soon as message credit is
+# available.
+
+session.message_subscribe(queue=reply_to, destination=local_queue_name)
+queue.start()
+
+# Set up the properties. Perhaps a few application headers?
+
+delivery_properties = session.delivery_properties(routing_key="request")
+
+message_properties = session.message_properties()
+
+message_properties.content_encoding="text/plain; charset='utf-8'"
+
+testdata.set_application_headers(message_properties)
+message_properties.reply_to = session.reply_to("amq.direct", reply_to)
+
+# deliver the message - remember to encode the Unicode string!
+request = Message(message_properties, delivery_properties, testdata.String_Greek.encode("utf8"))
+session.message_transfer(destination="amq.direct", message=request)
+
+# Now see what messages the server sent to our reply_to queue
+
+try:
+ response = queue.get(timeout=10)
+ content = response.body
+ session.message_accept(RangedSet(response.id))
+ testdata.check_message(response)
+ print "Response: " + content
+except Empty:
+ print "No more messages!"
+ exit(1)
+except:
+ print "Unexpected exception!"
+ exit(1)
+
+#----- Cleanup ------------------------------------------------
+
+# Clean up before exiting so there are no open threads.
+
+session.close(timeout=10)
diff --git a/python/examples/datatypes/server.py b/python/examples/datatypes/server.py
new file mode 100755
index 0000000000..18e6fa4ad7
--- /dev/null
+++ b/python/examples/datatypes/server.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+"""
+ server.py
+
+ Server for testing use of Unicode and datatypes.
+
+ Both client and server will be written in C++ and Python.
+ Tests can run clients and servers written in different
+ languages, and they can be run on 32-bit and 64-bit architectures.
+"""
+
+import testdata
+
+import qpid
+import sys
+import os
+from qpid.util import connect
+from qpid.connection import Connection
+from qpid.datatypes import Message, RangedSet, uuid4
+from qpid.queue import Empty
+
+#----- Functions -------------------------------------------
+def respond(session, request):
+
+ # The routing key for the response is the request's reply-to
+ # property. The body for the response is the request's body,
+ # converted to upper case.
+
+ testdata.check_message(request)
+
+ message_properties = request.get("message_properties")
+ reply_to = message_properties.reply_to
+
+ testdata.set_application_headers(message_properties)
+
+ if reply_to == None:
+ raise Exception("This message is missing the 'reply_to' property, which is required")
+
+ delivery_properties = session.delivery_properties(routing_key=reply_to["routing_key"])
+ response = Message(delivery_properties, message_properties, testdata.String_Greek.encode("utf8"))
+ print "Sending response ..."
+ session.message_transfer(destination=reply_to["exchange"], message=response)
+
+#----- Initialization --------------------------------------
+
+
+# Set parameters for login
+
+host="127.0.0.1"
+port=5672
+user="guest"
+password="guest"
+
+# If an alternate host or port has been specified, use that instead
+# (this is used in our unit tests)
+if len(sys.argv) > 1 :
+ host=sys.argv[1]
+if len(sys.argv) > 2 :
+ port=int(sys.argv[2])
+
+socket = connect(host, port)
+connection = Connection (sock=socket, username=user, password=password)
+connection.start()
+session = connection.session(str(uuid4()))
+
+#----- Main Body -- ----------------------------------------
+
+# Create a request queue and subscribe to it
+
+session.queue_declare(queue="request", exclusive=True)
+session.exchange_bind(exchange="amq.direct", queue="request", binding_key="request")
+
+local_queue_name = "local_queue"
+
+session.message_subscribe(queue="request", destination=local_queue_name)
+
+queue = session.incoming(local_queue_name)
+queue.start()
+
+# Remind the user to start the client program
+
+print "Request server running - run your client now."
+print "(Times out after 100 seconds ...)"
+sys.stdout.flush()
+
+# Respond to each request
+
+# If we get a message, send it back to the user (as indicated in the
+# ReplyTo property)
+
+while True:
+ try:
+ request = queue.get(timeout=100)
+ session.message_accept(RangedSet(request.id))
+
+ respond(session, request)
+ except Empty:
+ print "No more messages!"
+ break;
+
+
+#----- Cleanup ------------------------------------------------
+
+# Clean up before exiting so there are no open threads.
+
+session.close(timeout=10)
diff --git a/python/examples/datatypes/testdata.py b/python/examples/datatypes/testdata.py
new file mode 100644
index 0000000000..cdf140d400
--- /dev/null
+++ b/python/examples/datatypes/testdata.py
@@ -0,0 +1,180 @@
+# -*- encoding: utf-8 -*-
+
+from qpid.datatypes import uuid4, timestamp
+
+#----- Some variables to test boundary conditions on various data types
+
+void = None
+boolean_true = True
+boolean_false = False
+Uint8_0 = 0
+Uint8_max = 255
+Uint16_0 = 0
+Uint16_max = 65535
+Uint32_0 = 0
+Uint32_max = 4294967295
+Uint64_0 = 0
+Uint64_max = 18446744073709551615
+Int8_min = -128
+Int8_0 = 0
+Int8_max = 127
+Int16_min = -32768
+Int16_0 = 0
+Int16_max = 32767
+Int32_min = -2147483648
+Int32_0 = 0
+Int32_max = 2147483647
+Int64_min = -9223372036854775808
+Int64_0 = 0
+Int64_max = 9223372036854775807
+
+Float_pi = 3.14159265
+Float_neg = -1E4
+Float_big = 1267.43233E12
+Float_small = 12.78e-12
+Float_neg0 = -0
+Float_pos0 = 0
+Float_INF = float('inf')
+Float_Negative_INF = float('-inf')
+
+Double_pi = 3.1415926535897932384626433832795
+Double_neg = -1E4
+Double_big = 1267.43233E12
+Double_small = 12.78e-2
+Double_neg0 = -0
+Double_pos0 = 0
+Double_INF = float('inf')
+Double_Negative_INF = float('-inf')
+
+char_1byte = u'0024' # $
+char_2byte = u'00A2' # ¢
+char_3byte = u'20AC' # €
+char_4byte = u'10ABCD'
+
+timestamp = timestamp()
+
+UUID = uuid4()
+
+String_Greek = u"ἐξίσταντο δὲ πάντες καὶ διηπόρουν, ἄλλος πρὸς ἄλλον λέγοντες, Τί θέλει τοῦτο εἶναι;"
+
+String_Empty = ""
+
+#----- A few functions ----------------------------------------------------------
+
+def near_enough(float1, float2, delta):
+ return abs(float1-float2) < delta
+
+def set_application_headers(message_properties):
+
+ message_properties.application_headers = {}
+ message_properties.application_headers["void"] = None
+ message_properties.application_headers["boolean_true"] = boolean_true
+ message_properties.application_headers["boolean_false"] = boolean_false
+ message_properties.application_headers["Uint8_0"] = Uint8_0
+ message_properties.application_headers["Uint8_max"] = Uint8_max
+ message_properties.application_headers["Uint16_0"] = Uint16_0
+ message_properties.application_headers["Uint16_max"] = Uint16_max
+ message_properties.application_headers["Uint32_0"] = Uint32_0
+ message_properties.application_headers["Uint32_max"] = Uint32_max
+ message_properties.application_headers["Uint64_0"] = Uint64_0
+# message_properties.application_headers["Uint64_max"] = Uint64_max
+ message_properties.application_headers["Int8_min"] = Int8_min
+ message_properties.application_headers["Int8_0"] = Int8_0
+ message_properties.application_headers["Int8_max"] = Int8_max
+ message_properties.application_headers["Int16_min"] = Int16_min
+ message_properties.application_headers["Int16_0"] = Int16_0
+ message_properties.application_headers["Int16_max"] = Int16_max
+ message_properties.application_headers["Int32_min"] = Int32_min
+ message_properties.application_headers["Int32_0"] = Int32_0
+ message_properties.application_headers["Int32_max"] = Int32_max
+ message_properties.application_headers["Int64_min"] = Int64_min
+ message_properties.application_headers["Int64_0"] = Int64_0
+ message_properties.application_headers["Int64_max"] = Int64_max
+
+ message_properties.application_headers["Float_pi"] = Float_pi
+ message_properties.application_headers["Float_neg"] = Float_neg
+ message_properties.application_headers["Float_big"] = Float_big
+ message_properties.application_headers["Float_small"] = Float_small
+ message_properties.application_headers["Float_neg0"] = Float_neg0
+ message_properties.application_headers["Float_pos0"] = Float_pos0
+ message_properties.application_headers["Float_INF"] = Float_INF
+ message_properties.application_headers["Float_Negative_INF"] = Float_Negative_INF
+
+ message_properties.application_headers["Double_pi"] = Double_pi
+ message_properties.application_headers["Double_neg"] = Double_neg
+ message_properties.application_headers["Double_big"] = Double_big
+ message_properties.application_headers["Double_small"] = Double_small
+ message_properties.application_headers["Double_neg0"] = Double_neg0
+ message_properties.application_headers["Double_pos0"] = Double_pos0
+ message_properties.application_headers["Double_INF"] = Double_INF
+ message_properties.application_headers["Double_Negative_INF"] = Double_Negative_INF
+
+ message_properties.application_headers["char_1byte"] = char_1byte
+ message_properties.application_headers["char_2byte"] = char_2byte
+ message_properties.application_headers["char_3byte"] = char_3byte
+ message_properties.application_headers["char_4byte"] = char_4byte
+
+ message_properties.application_headers["timestamp"] = timestamp
+ message_properties.application_headers["UUID"] = uuid4()
+ message_properties.application_headers["String_Greek"] = String_Greek
+ message_properties.application_headers["String_Empty"] = String_Empty
+
+def check_message(message):
+
+# message_properties = message.message_properties()
+ message_properties = message.get("message_properties")
+ assert message_properties.application_headers["void"] == None
+ assert message_properties.application_headers["boolean_true"] == boolean_true
+ assert message_properties.application_headers["boolean_false"] == boolean_false
+ assert message_properties.application_headers["Uint8_0"] == Uint8_0
+ assert message_properties.application_headers["Uint8_max"] == Uint8_max
+ assert message_properties.application_headers["Uint16_0"] == Uint16_0
+ assert message_properties.application_headers["Uint16_max"] == Uint16_max
+ assert message_properties.application_headers["Uint32_0"] == Uint32_0
+ assert message_properties.application_headers["Uint32_max"] == Uint32_max
+ assert message_properties.application_headers["Uint64_0"] == Uint64_0
+# assert message_properties.application_headers["Uint64_max"] == Uint64_max
+ assert message_properties.application_headers["Int8_min"] == Int8_min
+ assert message_properties.application_headers["Int8_0"] == Int8_0
+ assert message_properties.application_headers["Int8_max"] == Int8_max
+ assert message_properties.application_headers["Int16_min"] == Int16_min
+ assert message_properties.application_headers["Int16_0"] == Int16_0
+ assert message_properties.application_headers["Int16_max"] == Int16_max
+ assert message_properties.application_headers["Int32_min"] == Int32_min
+ assert message_properties.application_headers["Int32_0"] == Int32_0
+ assert message_properties.application_headers["Int32_max"] == Int32_max
+ assert message_properties.application_headers["Int64_min"] == Int64_min
+ assert message_properties.application_headers["Int64_0"] == Int64_0
+ assert message_properties.application_headers["Int64_max"] == Int64_max
+
+# Change floating point comparisons to allow inexactness
+
+ assert near_enough(message_properties.application_headers["Float_pi"], Float_pi, 0.00001)
+ assert near_enough(message_properties.application_headers["Float_neg"], Float_neg, 0.00001)
+ assert near_enough(message_properties.application_headers["Float_big"], Float_big, Float_big/1000000)
+ assert near_enough(message_properties.application_headers["Float_small"], Float_small, 0.00001)
+ assert message_properties.application_headers["Float_neg0"] == Float_neg0
+ assert message_properties.application_headers["Float_pos0"] == Float_pos0
+ assert message_properties.application_headers["Float_INF"] == Float_INF
+ assert message_properties.application_headers["Float_Negative_INF"] == Float_Negative_INF
+
+ assert near_enough(message_properties.application_headers["Double_pi"], Double_pi, 0.00001)
+ assert near_enough(message_properties.application_headers["Double_neg"], Double_neg, 0.00001)
+ assert near_enough(message_properties.application_headers["Double_big"], Double_big, Double_big/1000000)
+ assert near_enough(message_properties.application_headers["Double_small"], Double_small, 0.00001)
+ assert message_properties.application_headers["Double_neg0"] == Double_neg0
+ assert message_properties.application_headers["Double_pos0"] == Double_pos0
+ assert message_properties.application_headers["Double_INF"] == Double_INF
+ assert message_properties.application_headers["Double_Negative_INF"] == Double_Negative_INF
+
+ assert message_properties.application_headers["char_1byte"] == char_1byte
+ assert message_properties.application_headers["char_2byte"] == char_2byte
+ assert message_properties.application_headers["char_3byte"] == char_3byte
+ assert message_properties.application_headers["char_4byte"] == char_4byte
+
+# assert message_properties.application_headers["timestamp"] == timestamp
+# assert message_properties.application_headers["UUID"] == UUID
+ assert message_properties.application_headers["String_Greek"] == String_Greek
+ assert message_properties.application_headers["String_Empty"] == String_Empty
+
+
diff --git a/python/examples/direct/declare_queues.py b/python/examples/direct/declare_queues.py
index f0c34fa8c9..13818ee9d7 100755
--- a/python/examples/direct/declare_queues.py
+++ b/python/examples/direct/declare_queues.py
@@ -1,4 +1,22 @@
#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
"""
declare_queues.py
@@ -36,7 +54,7 @@ if len(sys.argv) > 2 :
# Create a connection.
socket = connect(host, port)
-connection = Connection (sock=socket)
+connection = Connection (sock=socket, username=user, password=password)
connection.start()
session = connection.session(str(uuid4()))
diff --git a/python/examples/direct/direct_consumer.py b/python/examples/direct/direct_consumer.py
index 23577e9f53..b07e53c5c7 100755
--- a/python/examples/direct/direct_consumer.py
+++ b/python/examples/direct/direct_consumer.py
@@ -1,4 +1,22 @@
#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
"""
direct_consumer.py
@@ -34,7 +52,7 @@ if len(sys.argv) > 2 :
# Create a connection.
socket = connect(host, port)
-connection = Connection (sock=socket)
+connection = Connection (sock=socket, username=user, password=password)
connection.start()
session = connection.session(str(uuid4()))
diff --git a/python/examples/direct/direct_producer.py b/python/examples/direct/direct_producer.py
index 870ce66e78..fcbb4675e4 100755
--- a/python/examples/direct/direct_producer.py
+++ b/python/examples/direct/direct_producer.py
@@ -1,4 +1,22 @@
#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
"""
direct_producer.py
@@ -34,7 +52,7 @@ if len(sys.argv) > 2 :
# Create a connection.
socket = connect(host, port)
-connection = Connection (sock=socket)
+connection = Connection (sock=socket, username=user, password=password)
connection.start()
session = connection.session(str(uuid4()))
diff --git a/python/examples/direct/listener.py b/python/examples/direct/listener.py
index 66927eca4b..9d06bd3929 100755
--- a/python/examples/direct/listener.py
+++ b/python/examples/direct/listener.py
@@ -1,4 +1,22 @@
#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
"""
listener.py
@@ -55,7 +73,7 @@ if len(sys.argv) > 2 :
# Create a connection.
socket = connect(host, port)
-connection = Connection (sock=socket)
+connection = Connection (sock=socket, username=user, password=password)
connection.start()
session = connection.session(str(uuid4()))
diff --git a/python/examples/direct/verify b/python/examples/direct/verify
index 01d81a18a1..92f87bf827 100644
--- a/python/examples/direct/verify
+++ b/python/examples/direct/verify
@@ -1,3 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
clients ./declare_queues.py ./direct_producer.py ./direct_consumer.py
outputs ./declare_queues.py.out ./direct_producer.py.out ./direct_consumer.py.out
diff --git a/python/examples/fanout/fanout_consumer.py b/python/examples/fanout/fanout_consumer.py
index a2b1b30141..0452baa8da 100755
--- a/python/examples/fanout/fanout_consumer.py
+++ b/python/examples/fanout/fanout_consumer.py
@@ -1,4 +1,22 @@
#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
"""
fanout_consumer.py
@@ -32,7 +50,7 @@ if len(sys.argv) > 2 :
# Create a connection.
socket = connect(host, port)
-connection = Connection (sock=socket)
+connection = Connection (sock=socket, username=user, password=password)
connection.start()
session = connection.session(str(uuid4()))
diff --git a/python/examples/fanout/fanout_producer.py b/python/examples/fanout/fanout_producer.py
index 3950ca6d2e..c4df252c70 100755
--- a/python/examples/fanout/fanout_producer.py
+++ b/python/examples/fanout/fanout_producer.py
@@ -1,4 +1,22 @@
#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
"""
fanout_producer.py
@@ -31,7 +49,7 @@ if len(sys.argv) > 2 :
# Create a connection.
socket = connect(host, port)
-connection = Connection (sock=socket)
+connection = Connection (sock=socket, username=user, password=password)
connection.start()
session = connection.session(str(uuid4()))
diff --git a/python/examples/fanout/listener.py b/python/examples/fanout/listener.py
index 74ae858127..29db402e9d 100755
--- a/python/examples/fanout/listener.py
+++ b/python/examples/fanout/listener.py
@@ -1,4 +1,22 @@
#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
"""
listener.py
@@ -52,7 +70,7 @@ if len(sys.argv) > 2 :
# Create a connection.
socket = connect(host, port)
-connection = Connection (sock=socket)
+connection = Connection (sock=socket, username=user, password=password)
connection.start()
session = connection.session(str(uuid4()))
diff --git a/python/examples/fanout/verify b/python/examples/fanout/verify
index 6a3132a94f..9e5c364bfa 100644
--- a/python/examples/fanout/verify
+++ b/python/examples/fanout/verify
@@ -1,3 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
background "Subscribed" ./fanout_consumer.py
background "Subscribed" ./fanout_consumer.py
diff --git a/python/examples/headers/declare_queues.py b/python/examples/headers/declare_queues.py
new file mode 100755
index 0000000000..b3d5c43fe5
--- /dev/null
+++ b/python/examples/headers/declare_queues.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+"""
+ declare_queues.py
+
+ Creates and binds a queue on an AMQP headers exchange.
+
+ All messages with an application header of {'class': 'first'} are sent to queue "first".
+ All messages with an application header of {'class': 'second'} are sent to queue "second".
+"""
+
+# Common includes
+
+import qpid
+import sys
+import os
+from qpid.util import connect
+from qpid.connection import Connection
+from qpid.datatypes import Message, RangedSet, uuid4
+from qpid.queue import Empty
+
+#----- Initialization -----------------------------------
+
+# Set parameters for login
+
+host="127.0.0.1"
+port=5672
+user="guest"
+password="guest"
+
+# If an alternate host or port has been specified, use that instead
+# (this is used in our unit tests)
+if len(sys.argv) > 1 :
+ host=sys.argv[1]
+if len(sys.argv) > 2 :
+ port=int(sys.argv[2])
+
+# Create a connection.
+socket = connect(host, port)
+connection = Connection (sock=socket, username=user, password=password)
+connection.start()
+session = connection.session(str(uuid4()))
+
+#----- Create queues -------------------------------------
+
+# queue_declare() creates an AMQP queue, which is held
+# on the broker. Published messages are sent to the AMQP queue,
+# from which messages are delivered to consumers.
+#
+# exchange_bind() determines which messages are routed to a queue.
+
+session.queue_declare(queue="first")
+session.exchange_bind(exchange="amq.match", queue="first", arguments={'x-match':'any', 'class':'first'})
+
+session.queue_declare(queue="second")
+session.exchange_bind(exchange="amq.match", queue="second", arguments={'x-match':'any', 'class':'second'})
+
+#----- Cleanup ---------------------------------------------
+
+session.close(timeout=10)
diff --git a/python/examples/headers/headers_consumer.py b/python/examples/headers/headers_consumer.py
new file mode 100755
index 0000000000..8f5ce3c5ff
--- /dev/null
+++ b/python/examples/headers/headers_consumer.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+"""
+ headers_consumer.py
+
+ This AMQP client reads messages from two message
+ queues named "first" and "second".
+"""
+
+import qpid
+import sys
+import os
+from random import randint
+from qpid.util import connect
+from qpid.connection import Connection
+from qpid.datatypes import Message, RangedSet, uuid4
+from qpid.queue import Empty
+
+
+#----- Initialization --------------------------------------
+
+# Set parameters for login
+
+host="127.0.0.1"
+port=5672
+user="guest"
+password="guest"
+
+# If an alternate host or port has been specified, use that instead
+# (this is used in our unit tests)
+if len(sys.argv) > 1 :
+ host=sys.argv[1]
+if len(sys.argv) > 2 :
+ port=int(sys.argv[2])
+
+# Create a connection.
+socket = connect(host, port)
+connection = Connection (sock=socket, username=user, password=password)
+connection.start()
+session = connection.session(str(uuid4()))
+
+#----- Read from queue --------------------------------------------
+
+# Now let's create two local client queues and tell them to read
+# incoming messages.
+
+# The consumer tag identifies the client-side queue.
+
+local_queue_name_first = "local_queue_first"
+local_queue_name_second = "local_queue_second"
+
+queue_first = session.incoming(local_queue_name_first)
+queue_second = session.incoming(local_queue_name_second)
+
+# Call message_subscribe() to tell the broker to deliver messages
+# from the AMQP queue to these local client queues. The broker will
+# start delivering messages as soon as credit is allocated using
+# queue.start().
+
+session.message_subscribe(queue="first", destination=local_queue_name_first)
+session.message_subscribe(queue="second", destination=local_queue_name_second)
+
+queue_first.start()
+queue_second.start()
+
+# Initialize 'final' and 'content', variables used to identify the last message.
+
+final = "That's all, folks!" # In a message body, signals the last message
+content = "" # Content of the last message read
+
+message = None
+while content != final:
+ message = queue_first.get(timeout=10)
+ content = message.body
+ session.message_accept(RangedSet(message.id))
+ print content
+
+content = ""
+while content != final:
+ message = queue_second.get(timeout=10)
+ content = message.body
+ session.message_accept(RangedSet(message.id))
+ print content
+
+#----- Cleanup ------------------------------------------------
+
+# Clean up before exiting so there are no open threads.
+#
+
+session.close(timeout=10)
diff --git a/python/examples/headers/headers_producer.py b/python/examples/headers/headers_producer.py
new file mode 100755
index 0000000000..43130d5993
--- /dev/null
+++ b/python/examples/headers/headers_producer.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+"""
+ headers_producer.py
+
+ Publishes messages to an AMQP headers exchange, using
+ various application header values.
+"""
+
+import qpid
+import sys
+import os
+from qpid.util import connect
+from qpid.connection import Connection
+from qpid.datatypes import Message
+from qpid.datatypes import uuid4
+from qpid.queue import Empty
+
+
+#----- Initialization -----------------------------------
+
+# Set parameters for login
+
+host="127.0.0.1"
+port=5672
+user="guest"
+password="guest"
+
+# If an alternate host or port has been specified, use that instead
+# (this is used in our unit tests)
+if len(sys.argv) > 1 :
+ host=sys.argv[1]
+if len(sys.argv) > 2 :
+ port=int(sys.argv[2])
+
+# Create a connection.
+socket = connect(host, port)
+connection = Connection (sock=socket, username=user, password=password)
+connection.start()
+session = connection.session(str(uuid4()))
+
+#----- Publish some messages ------------------------------
+
+# Create some messages and put them on the broker.
+props_first = session.message_properties(application_headers={'class':'first'})
+props_second = session.message_properties(application_headers={'class':'second'})
+props_third = session.message_properties(application_headers={'class':'third'})
+
+for i in range(10):
+ session.message_transfer(destination="amq.match", message=Message(props_first,"message(first) " + str(i)))
+ session.message_transfer(destination="amq.match", message=Message(props_second,"message(second) " + str(i)))
+ session.message_transfer(destination="amq.match", message=Message(props_third,"message(third) " + str(i)))
+
+session.message_transfer(destination="amq.match", message=Message(props_first,"That's all, folks!"))
+session.message_transfer(destination="amq.match", message=Message(props_second,"That's all, folks!"))
+session.message_transfer(destination="amq.match", message=Message(props_third,"That's all, folks!"))
+
+#----- Cleanup --------------------------------------------
+
+# Clean up before exiting so there are no open threads.
+
+session.close(timeout=10)
diff --git a/python/examples/headers/verify b/python/examples/headers/verify
new file mode 100644
index 0000000000..5fe96c5c23
--- /dev/null
+++ b/python/examples/headers/verify
@@ -0,0 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
+clients ./declare_queues.py ./headers_producer.py ./headers_consumer.py
+outputs ./declare_queues.py.out ./headers_producer.py.out ./headers_consumer.py.out
diff --git a/python/examples/headers/verify.in b/python/examples/headers/verify.in
new file mode 100644
index 0000000000..90ffd0a071
--- /dev/null
+++ b/python/examples/headers/verify.in
@@ -0,0 +1,25 @@
+==== declare_queues.py.out
+==== headers_producer.py.out
+==== headers_consumer.py.out
+message(first) 0
+message(first) 1
+message(first) 2
+message(first) 3
+message(first) 4
+message(first) 5
+message(first) 6
+message(first) 7
+message(first) 8
+message(first) 9
+That's all, folks!
+message(second) 0
+message(second) 1
+message(second) 2
+message(second) 3
+message(second) 4
+message(second) 5
+message(second) 6
+message(second) 7
+message(second) 8
+message(second) 9
+That's all, folks!
diff --git a/python/examples/pubsub/topic_publisher.py b/python/examples/pubsub/topic_publisher.py
index 8cf1b08644..b50d5fa8ca 100755
--- a/python/examples/pubsub/topic_publisher.py
+++ b/python/examples/pubsub/topic_publisher.py
@@ -1,4 +1,22 @@
#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
"""
topic_publisher.py
diff --git a/python/examples/pubsub/topic_subscriber.py b/python/examples/pubsub/topic_subscriber.py
index 039cc0c55b..489c7cbb19 100755
--- a/python/examples/pubsub/topic_subscriber.py
+++ b/python/examples/pubsub/topic_subscriber.py
@@ -1,4 +1,22 @@
#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
"""
topic_subscriber.py
@@ -63,7 +81,7 @@ if len(sys.argv) > 2 :
# Create a connection.
socket = connect(host, port)
-connection = Connection (sock=socket)
+connection = Connection (sock=socket, username=user, password=password)
connection.start()
session = connection.session(str(uuid4()))
diff --git a/python/examples/pubsub/verify b/python/examples/pubsub/verify
index 963d2e32e1..cf1bade62e 100644
--- a/python/examples/pubsub/verify
+++ b/python/examples/pubsub/verify
@@ -1,3 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
background "Queues created" ./topic_subscriber.py
clients ./topic_publisher.py
diff --git a/python/examples/request-response/client.py b/python/examples/request-response/client.py
index a9ecd5c78f..b29fcf3ea7 100755
--- a/python/examples/request-response/client.py
+++ b/python/examples/request-response/client.py
@@ -1,4 +1,22 @@
#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
"""
client.py
@@ -55,7 +73,7 @@ if len(sys.argv) > 2 :
# Create a connection.
socket = connect(host, port)
-connection = Connection (sock=socket)
+connection = Connection (sock=socket, username=user, password=password)
connection.start()
session = connection.session(str(uuid4()))
diff --git a/python/examples/request-response/server.py b/python/examples/request-response/server.py
index 05ee051c57..a80c4541e4 100755
--- a/python/examples/request-response/server.py
+++ b/python/examples/request-response/server.py
@@ -1,4 +1,22 @@
#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
"""
server.py
@@ -46,7 +64,7 @@ if len(sys.argv) > 2 :
port=int(sys.argv[2])
socket = connect(host, port)
-connection = Connection (sock=socket)
+connection = Connection (sock=socket, username=user, password=password)
connection.start()
session = connection.session(str(uuid4()))
diff --git a/python/examples/request-response/verify b/python/examples/request-response/verify
index cf8151d4e4..3c058febb2 100644
--- a/python/examples/request-response/verify
+++ b/python/examples/request-response/verify
@@ -1,3 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
background "Request server running" ./server.py
clients ./client.py
diff --git a/python/examples/xml-exchange/declare_queues.py b/python/examples/xml-exchange/declare_queues.py
index bd17da5013..ca40af5dc5 100755
--- a/python/examples/xml-exchange/declare_queues.py
+++ b/python/examples/xml-exchange/declare_queues.py
@@ -1,4 +1,22 @@
#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
"""
declare_queues.py
@@ -35,7 +53,7 @@ if len(sys.argv) > 2 :
# Create a connection.
socket = connect(host, port)
-connection = Connection (sock=socket)
+connection = Connection (sock=socket, username=user, password=password)
connection.start()
session = connection.session(str(uuid4()))
diff --git a/python/examples/xml-exchange/listener.py b/python/examples/xml-exchange/listener.py
index dec824dddf..a56f5d6018 100755
--- a/python/examples/xml-exchange/listener.py
+++ b/python/examples/xml-exchange/listener.py
@@ -1,4 +1,22 @@
#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
"""
listener.py
@@ -52,7 +70,7 @@ if len(sys.argv) > 2 :
# Create a connection.
socket = connect(host, port)
-connection = Connection (sock=socket)
+connection = Connection (sock=socket, username=user, password=password)
connection.start()
session = connection.session(str(uuid4()))
diff --git a/python/examples/xml-exchange/verify b/python/examples/xml-exchange/verify
index bf05463f1d..a93a32dc90 100644
--- a/python/examples/xml-exchange/verify
+++ b/python/examples/xml-exchange/verify
@@ -1,3 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
# See https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/bin/verify
clients ./declare_queues.py ./xml_producer.py ./xml_consumer.py
outputs ./declare_queues.py.out ./xml_producer.py.out ./xml_consumer.py.out
diff --git a/python/examples/xml-exchange/xml_consumer.py b/python/examples/xml-exchange/xml_consumer.py
index 0ab079e7a6..cd89110b05 100755
--- a/python/examples/xml-exchange/xml_consumer.py
+++ b/python/examples/xml-exchange/xml_consumer.py
@@ -1,4 +1,22 @@
#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
"""
direct_consumer.py
@@ -34,7 +52,7 @@ if len(sys.argv) > 2 :
# Create a connection.
socket = connect(host, port)
-connection = Connection (sock=socket)
+connection = Connection (sock=socket, username=user, password=password)
connection.start()
session = connection.session(str(uuid4()))
diff --git a/python/examples/xml-exchange/xml_producer.py b/python/examples/xml-exchange/xml_producer.py
index 72c5bdb53a..fa97cab4e1 100755
--- a/python/examples/xml-exchange/xml_producer.py
+++ b/python/examples/xml-exchange/xml_producer.py
@@ -1,4 +1,22 @@
#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
"""
xml_producer.py
@@ -52,7 +70,7 @@ if len(sys.argv) > 2 :
# Create a connection.
socket = connect(host, port)
-connection = Connection (sock=socket)
+connection = Connection (sock=socket, username=user, password=password)
connection.start()
session = connection.session(str(uuid4()))
diff --git a/python/hello-world b/python/hello-world
index 5d513cc57b..efee84059c 100755
--- a/python/hello-world
+++ b/python/hello-world
@@ -1,10 +1,39 @@
#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+import sys
from qpid.connection import Connection
from qpid.util import connect
from qpid.datatypes import uuid4, Message
+broker = "127.0.0.1"
+port = 5672
+
+if len(sys.argv) > 1: broker = sys.argv[1]
+if len(sys.argv) > 2: port = int(sys.argv[2])
+
+if len(sys.argv) > 3:
+ print >> sys.stderr, "usage: hello-world [ <broker> [ <port> ] ]"
+ sys.exit(1)
+
# connect to the server and start a session
-conn = Connection(connect("127.0.0.1", 5672))
+conn = Connection(connect(broker, port))
conn.start()
ssn = conn.session(str(uuid4()))
diff --git a/python/java_failing_0-8.txt b/python/java_failing_0-8.txt
deleted file mode 100644
index c13b40a42c..0000000000
--- a/python/java_failing_0-8.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-tests_0-8.exchange.RecommendedTypesRuleTests.testTopic
-tests_0-8.exchange.RequiredInstancesRuleTests.testAmqTopic
diff --git a/python/java_failing_0-9.txt b/python/java_failing_0-9.txt
deleted file mode 100644
index 7252d0f496..0000000000
--- a/python/java_failing_0-9.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-ntests.basic.BasicTests.test_qos_prefetch_count
-tests.basic.BasicTests.test_ack
-tests.basic.BasicTests.test_cancel
-tests.basic.BasicTests.test_consume_exclusive
-tests.basic.BasicTests.test_consume_no_local
-tests.basic.BasicTests.test_consume_queue_errors
-tests.basic.BasicTests.test_consume_unique_consumers
-tests.basic.BasicTests.test_get
-tests.basic.BasicTests.test_qos_prefetch_size
-tests.basic.BasicTests.test_recover_requeue
-
-tests.exchange.RecommendedTypesRuleTests.testTopic
-tests.exchange.RequiredInstancesRuleTests.testAmqTopic
-
-tests.message.MessageTests.test_checkpoint
-tests.message.MessageTests.test_reject
-
-tests.broker.BrokerTests.test_ping_pong
diff --git a/python/mllib/__init__.py b/python/mllib/__init__.py
index 39e9363614..9aa1e56e66 100644
--- a/python/mllib/__init__.py
+++ b/python/mllib/__init__.py
@@ -24,6 +24,8 @@ both SGML and XML.
import os, dom, transforms, parsers, sys
import xml.sax, types
+from xml.sax.handler import ErrorHandler
+from xml.sax.xmlreader import InputSource
from cStringIO import StringIO
def transform(node, *args):
@@ -49,15 +51,33 @@ def sgml_parse(source):
p.close()
return p.parser.tree
-def xml_parse(filename):
+class Resolver:
+
+ def __init__(self, path):
+ self.path = path
+
+ def resolveEntity(self, publicId, systemId):
+ for p in self.path:
+ fname = os.path.join(p, systemId)
+ if os.path.exists(fname):
+ source = InputSource(systemId)
+ source.setByteStream(open(fname))
+ return source
+ return InputSource(systemId)
+
+def xml_parse(filename, path=()):
if sys.version_info[0:2] == (2,3):
# XXX: this is for older versions of python
- source = "file://%s" % os.path.abspath(filename)
+ source = "file://%s" % os.path.abspath(filename)
else:
source = filename
- p = parsers.XMLParser()
- xml.sax.parse(source, p)
- return p.parser.tree
+ h = parsers.XMLParser()
+ p = xml.sax.make_parser()
+ p.setContentHandler(h)
+ p.setErrorHandler(ErrorHandler())
+ p.setEntityResolver(Resolver(path))
+ p.parse(source)
+ return h.parser.tree
def sexp(node):
s = transforms.Sexp()
diff --git a/python/mllib/dom.py b/python/mllib/dom.py
index df2b88322a..486f7082e1 100644
--- a/python/mllib/dom.py
+++ b/python/mllib/dom.py
@@ -148,6 +148,21 @@ class Tag(Node):
if name == k:
return v
+ def _idx(self, attr):
+ idx = 0
+ for k, v in self.attrs:
+ if k == attr:
+ return idx
+ idx += 1
+ return None
+
+ def set_attr(self, name, value):
+ idx = self._idx(name)
+ if idx is None:
+ self.attrs.append((name, value))
+ else:
+ self.attrs[idx] = (name, value)
+
def dispatch(self, f):
try:
attr = "do_" + self.name
diff --git a/python/models/fedsim/__init__.py b/python/models/fedsim/__init__.py
new file mode 100644
index 0000000000..63a3f41f28
--- /dev/null
+++ b/python/models/fedsim/__init__.py
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT 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/python/models/fedsim/fedsim.py b/python/models/fedsim/fedsim.py
new file mode 100644
index 0000000000..edb6c4c8ed
--- /dev/null
+++ b/python/models/fedsim/fedsim.py
@@ -0,0 +1,434 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+class Sim:
+ def __init__(self):
+ self.brokers = {}
+ self.clients = {}
+ self.errors = 0
+ self.warnings = 0
+
+ def error(self, text):
+ self.errors += 1
+ print "###### Error:", text
+
+ def warning(self, text):
+ self.warnings += 1
+ print "###### Warning:", text
+
+ def end(self):
+ print "========================"
+ print "Errors: %d, Warnings: %d" % (self.errors, self.warnings)
+ print "========================"
+
+ def dumpState(self):
+ print "============================"
+ print "===== Federation State ====="
+ print "============================"
+ for broker in self.brokers:
+ for exchange in self.brokers[broker].exchanges:
+ print "Exchange %s.%s" % (broker, exchange)
+ for key in self.brokers[broker].exchanges[exchange].keys:
+ print " Key %s" % key
+ for queue in self.brokers[broker].exchanges[exchange].keys[key]:
+ print " Queue %s origins=%s" % \
+ (queue.name, self.brokers[broker].exchanges[exchange].keys[key][queue].originList)
+
+ def addBroker(self, name):
+ if name in self.brokers:
+ raise Exception("Broker of same name already exists")
+ broker = Broker(self, name)
+ self.brokers[name] = broker
+ return broker
+
+ def addClient(self, name, broker):
+ if name in self.clients:
+ raise Exception("Client of same name already exists")
+ client = Client(self, name, broker)
+ self.clients[name] = client
+ return client
+
+ def link(self, left, right, bidir=True):
+ print "====== link %s to %s, bidir=%s" % (left.tag, right.tag, bidir)
+ l1 = left.createLink(right)
+ l1.bridge("amq.direct")
+ if bidir:
+ l2 = right.createLink(left)
+ l2.bridge("amq.direct")
+
+ def bind(self, client, key):
+ print "====== bind Client(%s): k=%s" % (client.name, key)
+ client.bind(key)
+
+ def unbind(self, client, key):
+ print "====== unbind Client(%s): k=%s" % (client.name, key)
+ client.unbind(key)
+
+ def sendMessage(self, key, broker, body="Message Body"):
+ print "====== sendMessage: broker=%s k=%s" % (broker.tag, key)
+ msg = Message(key, body)
+ exchange = broker.exchanges["amq.direct"]
+ for client in self.clients:
+ self.clients[client].expect(key);
+ exchange.receive(key, msg, True)
+ for client in self.clients:
+ self.clients[client].checkReception()
+
+
+class Destination:
+ def receive(self, key, msg, fromUser=False):
+ pass
+
+
+class Client(Destination):
+ def __init__(self, sim, name, broker):
+ self.sim = sim
+ self.name = name
+ self.broker = broker
+ self.broker.connect(self)
+ self.queue = self.broker.declare_queue(name)
+ self.subscription = self.broker.subscribe(self, name)
+ self.expected = None
+ self.boundKeys = []
+
+ def bind(self, key):
+ self.boundKeys.append(key)
+ self.broker.bind("amq.direct", self.name, key)
+
+ def unbind(self, key):
+ self.boundKeys.remove(key)
+ self.broker.unbind("amq.direct", self.name, key)
+
+ def receive(self, key, msg, fromUser=False):
+ print "Client(%s) received [%s]: %s" % (self.name, key, msg.body)
+ if self.expected == key:
+ self.expected = None
+ else:
+ self.sim.error("Client(%s) received unexpected message with key [%s]" % \
+ (self.name, self.expected))
+
+ def expect(self, key):
+ if key in self.boundKeys:
+ self.expected = key
+
+ def checkReception(self):
+ if self.expected:
+ self.sim.error("Client(%s) never received message with key [%s]" % \
+ (self.name, self.expected))
+
+class Broker(Client):
+ def __init__(self, sim, tag):
+ self.sim = sim
+ self.tag = tag
+ self.connections = {}
+ self.exchanges = {}
+ self.queues = {}
+ self.subscriptions = {}
+ self.links = {}
+ self.directExchange = self.declare_exchange("amq.direct")
+
+ def connect(self, client):
+ if client in self.connections:
+ raise Exception("Client already connected")
+ self.connections[client] = Connection(client)
+
+ def declare_queue(self, name, tag=None, exclude=None):
+ if name in self.queues:
+ raise Exception("Queue already exists")
+ self.queues[name] = Queue(self, name, tag, exclude)
+
+ def subscribe(self, dest, queueName):
+ if queueName not in self.queues:
+ raise Exception("Queue does not exist")
+ self.queues[queueName].setDest(dest)
+
+ def declare_exchange(self, name):
+ if name in self.exchanges:
+ return
+ exchange = Exchange(self, name)
+ self.exchanges[name] = exchange
+ return exchange
+
+ def bind(self, exchangeName, queueName, key, tagList=[], fedOp=None, origin=None):
+ if exchangeName not in self.exchanges:
+ raise Exception("Exchange not found")
+ if queueName not in self.queues:
+ raise Exception("Queue not found")
+ exchange = self.exchanges[exchangeName]
+ queue = self.queues[queueName]
+ exchange.bind(queue, key, tagList, fedOp, origin)
+
+ def unbind(self, exchangeName, queueName, key):
+ if exchangeName not in self.exchanges:
+ raise Exception("Exchange not found")
+ if queueName not in self.queues:
+ raise Exception("Queue not found")
+ exchange = self.exchanges[exchangeName]
+ queue = self.queues[queueName]
+ exchange.unbind(queue, key)
+
+ def createLink(self, other):
+ if other in self.links:
+ raise Exception("Peer broker already linked")
+ link = Link(self, other)
+ self.links[other] = link
+ return link
+
+
+class Connection:
+ def __init__(self, client):
+ self.client = client
+
+
+class Exchange(Destination):
+ def __init__(self, broker, name):
+ self.broker = broker
+ self.sim = broker.sim
+ self.name = name
+ self.keys = {}
+ self.bridges = []
+
+ def bind(self, queue, key, tagList, fedOp, origin):
+ if not fedOp: fedOp = "bind"
+ print "Exchange(%s.%s) bind q=%s, k=%s, tags=%s, op=%s, origin=%s" % \
+ (self.broker.tag, self.name, queue.name, key, tagList, fedOp, origin),
+
+ if self.broker.tag in tagList:
+ print "(tag ignored)"
+ return
+
+ if fedOp == "bind" or fedOp == "unbind":
+ if key not in self.keys:
+ self.keys[key] = {}
+ queueMap = self.keys[key]
+
+ if fedOp == "bind":
+ ##
+ ## Add local or federation binding case
+ ##
+ if queue in queueMap:
+ if origin and origin in queueMap[queue].originList:
+ print "(dup ignored)"
+ elif origin:
+ queueMap[queue].originList.append(origin)
+ print "(origin added)"
+ else:
+ binding = Binding(origin)
+ queueMap[queue] = binding
+ print "(binding added)"
+
+ elif fedOp == "unbind":
+ ##
+ ## Delete federation binding case
+ ##
+ if queue in queueMap:
+ binding = queueMap[queue]
+ if origin and origin in binding.originList:
+ binding.originList.remove(origin)
+ if len(binding.originList) == 0:
+ queueMap.pop(queue)
+ if len(queueMap) == 0:
+ self.keys.pop(key)
+ print "(last origin del)"
+ else:
+ print "(removed origin)"
+ else:
+ print "(origin not found)"
+ else:
+ print "(queue not found)"
+
+ elif fedOp == "reorigin":
+ print "(ok)"
+ self.reorigin()
+
+ elif fedOp == "hello":
+ print "(ok)"
+
+ else:
+ raise Exception("Unknown fed-opcode '%s'" % fedOp)
+
+ newTagList = []
+ newTagList.append(self.broker.tag)
+ for tag in tagList:
+ newTagList.append(tag)
+ if origin:
+ propOrigin = origin
+ else:
+ propOrigin = self.broker.tag
+
+ for bridge in self.bridges:
+ if bridge.isDynamic():
+ bridge.propagate(key, newTagList, fedOp, propOrigin)
+
+ def reorigin(self):
+ myTag = []
+ myTag.append(self.broker.tag)
+ for key in self.keys:
+ queueMap = self.keys[key]
+ found = False
+ for queue in queueMap:
+ binding = queueMap[queue]
+ if binding.isLocal():
+ found = True
+ if found:
+ for bridge in self.bridges:
+ if bridge.isDynamic():
+ bridge.propagate(key, myTag, "bind", self.broker.tag)
+
+ def unbind(self, queue, key):
+ print "Exchange(%s.%s) unbind q=%s, k=%s" % (self.broker.tag, self.name, queue.name, key),
+ if key not in self.keys:
+ print "(key not known)"
+ return
+ queueMap = self.keys[key]
+ if queue not in queueMap:
+ print "(queue not bound)"
+ return
+ queueMap.pop(queue)
+ if len(queueMap) == 0:
+ self.keys.pop(key)
+ print "(ok, remove bound-key)"
+ else:
+ print "(ok)"
+
+ count = 0
+ for queue in queueMap:
+ if len(queueMap[queue].originList) == 0:
+ count += 1
+
+ if count == 0:
+ myTag = []
+ myTag.append(self.broker.tag)
+ for bridge in self.bridges:
+ if bridge.isDynamic():
+ bridge.propagate(key, myTag, "unbind", self.broker.tag)
+
+ def receive(self, key, msg, fromUser=False):
+ sent = False
+ if key in self.keys:
+ queueMap = self.keys[key]
+ for queue in queueMap:
+ if queue.enqueue(msg):
+ sent = True
+ if not sent and not fromUser:
+ self.sim.warning("Exchange(%s.%s) received unroutable message: k=%s" % \
+ (self.broker.tag, self.name, key))
+
+ def addDynamicBridge(self, bridge):
+ if bridge in self.bridges:
+ raise Exception("Dynamic bridge already added to exchange")
+ self.bridges.append(bridge)
+
+ for b in self.bridges:
+ if b != bridge:
+ b.sendReorigin()
+ self.reorigin()
+
+class Queue:
+ def __init__(self, broker, name, tag=None, exclude=None):
+ self.broker = broker
+ self.name = name
+ self.tag = tag
+ self.exclude = exclude
+ self.dest = None
+
+ def setDest(self, dest):
+ self.dest = dest
+
+ def enqueue(self, msg):
+ print "Queue(%s.%s) rcvd k=%s, tags=%s" % (self.broker.tag, self.name, msg.key, msg.tags),
+ if self.dest == None:
+ print "(dropped, no dest)"
+ return False
+ if self.exclude and msg.tagFound(self.exclude):
+ print "(dropped, tag)"
+ return False
+ if self.tag:
+ msg.appendTag(self.tag)
+ print "(ok)"
+ self.dest.receive(msg.key, msg)
+ return True
+
+
+class Binding:
+ def __init__(self, origin):
+ self.originList = []
+ if origin:
+ self.originList.append(origin)
+
+ def isLocal(self):
+ return len(self.originList) == 0
+
+
+class Link:
+ def __init__(self, local, remote):
+ self.local = local
+ self.remote = remote
+ self.remote.connect(self)
+ self.bridges = []
+
+ def bridge(self, exchangeName):
+ bridge = Bridge(self, exchangeName)
+
+
+class Bridge:
+ def __init__(self, link, exchangeName):
+ self.link = link
+ self.exchangeName = exchangeName
+ if self.exchangeName not in link.local.exchanges:
+ raise Exception("Exchange not found")
+ self.exchange = link.local.exchanges[self.exchangeName]
+ self.queueName = "bridge." + link.local.tag
+ self.link.remote.declare_queue(self.queueName, self.link.remote.tag, self.link.local.tag)
+ self.link.remote.subscribe(self.exchange, self.queueName)
+ self.exchange.addDynamicBridge(self)
+
+ def isDynamic(self):
+ return True
+
+ def localTag(self):
+ return self.link.local.tag
+
+ def remoteTag(self):
+ return self.link.remote.tag
+
+ def propagate(self, key, tagList, fedOp, origin):
+ if self.link.remote.tag not in tagList:
+ self.link.remote.bind(self.exchangeName, self.queueName, key, tagList, fedOp, origin)
+
+ def sendReorigin(self):
+ myTag = []
+ myTag.append(self.link.local.tag)
+ self.link.remote.bind(self.exchangeName, self.queueName, "", myTag, "reorigin", "")
+
+
+class Message:
+ def __init__(self, key, body):
+ self.key = key
+ self.body = body
+ self.tags = []
+
+ def appendTag(self, tag):
+ if tag not in self.tags:
+ self.tags.append(tag)
+
+ def tagFound(self, tag):
+ return tag in self.tags
+
+
diff --git a/python/models/fedsim/testBig.py b/python/models/fedsim/testBig.py
new file mode 100644
index 0000000000..416a086983
--- /dev/null
+++ b/python/models/fedsim/testBig.py
@@ -0,0 +1,88 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from fedsim import Sim
+
+sim = Sim()
+b1 = sim.addBroker("B1")
+b2 = sim.addBroker("B2")
+b3 = sim.addBroker("B3")
+b4 = sim.addBroker("B4")
+b5 = sim.addBroker("B5")
+b6 = sim.addBroker("B6")
+b7 = sim.addBroker("B7")
+b8 = sim.addBroker("B8")
+
+c1 = sim.addClient("C1", b1)
+c3 = sim.addClient("C3", b3)
+c4 = sim.addClient("C4", b4)
+c5 = sim.addClient("C5", b5)
+c8 = sim.addClient("C8", b8)
+
+sim.link(b1, b2)
+sim.link(b3, b2)
+sim.link(b4, b2)
+sim.link(b5, b2)
+
+sim.link(b6, b7)
+sim.link(b6, b8)
+
+sim.bind(c1, "A")
+sim.bind(c3, "B")
+sim.bind(c8, "A")
+
+sim.link(b5, b6)
+
+sim.bind(c4, "A")
+
+sim.sendMessage("A", b1)
+sim.sendMessage("A", b2)
+sim.sendMessage("A", b3)
+sim.sendMessage("A", b4)
+sim.sendMessage("A", b5)
+sim.sendMessage("A", b6)
+sim.sendMessage("A", b7)
+sim.sendMessage("A", b8)
+
+sim.sendMessage("B", b1)
+sim.sendMessage("B", b2)
+sim.sendMessage("B", b3)
+sim.sendMessage("B", b4)
+sim.sendMessage("B", b5)
+sim.sendMessage("B", b6)
+sim.sendMessage("B", b7)
+sim.sendMessage("B", b8)
+
+sim.unbind(c1, "A")
+
+sim.sendMessage("A", b1)
+sim.sendMessage("A", b2)
+sim.sendMessage("A", b3)
+sim.sendMessage("A", b4)
+sim.sendMessage("A", b5)
+sim.sendMessage("A", b6)
+sim.sendMessage("A", b7)
+sim.sendMessage("A", b8)
+
+sim.unbind(c4, "A")
+sim.unbind(c3, "B")
+sim.unbind(c8, "A")
+
+sim.dumpState()
+sim.end()
diff --git a/python/models/fedsim/testRing.py b/python/models/fedsim/testRing.py
new file mode 100644
index 0000000000..c883b54993
--- /dev/null
+++ b/python/models/fedsim/testRing.py
@@ -0,0 +1,48 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from fedsim import Sim
+
+sim = Sim()
+b1 = sim.addBroker("B1")
+b2 = sim.addBroker("B2")
+b3 = sim.addBroker("B3")
+
+sim.link(b1, b2, False)
+sim.link(b2, b3, False)
+sim.link(b3, b1, False)
+
+c1 = sim.addClient("C1", b1)
+c2 = sim.addClient("C2", b2)
+c3 = sim.addClient("C3", b3)
+
+sim.bind(c1, "A")
+sim.bind(c2, "A")
+
+sim.sendMessage("A", b1)
+sim.sendMessage("A", b2)
+sim.sendMessage("A", b3)
+
+sim.unbind(c2, "A")
+
+sim.sendMessage("A", b1)
+sim.sendMessage("A", b2)
+sim.sendMessage("A", b3)
+
+sim.end()
diff --git a/python/models/fedsim/testStar.py b/python/models/fedsim/testStar.py
new file mode 100644
index 0000000000..e6b801446f
--- /dev/null
+++ b/python/models/fedsim/testStar.py
@@ -0,0 +1,65 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from fedsim import Sim
+
+sim = Sim()
+b1 = sim.addBroker("B1")
+b2 = sim.addBroker("B2")
+b3 = sim.addBroker("B3")
+bc = sim.addBroker("BC")
+
+sim.link(b1, bc)
+sim.link(b2, bc)
+sim.link(b3, bc)
+
+c1 = sim.addClient("C1", b1)
+c2 = sim.addClient("C2", b2)
+c3 = sim.addClient("C3", b3)
+cc = sim.addClient("CC", bc)
+
+sim.bind(c1, "A")
+
+sim.sendMessage("A", b1)
+sim.sendMessage("A", b2)
+sim.sendMessage("A", b3)
+sim.sendMessage("A", bc)
+
+sim.bind(c2, "A")
+
+sim.sendMessage("A", b1)
+sim.sendMessage("A", b2)
+sim.sendMessage("A", b3)
+sim.sendMessage("A", bc)
+
+sim.unbind(c1, "A")
+
+sim.sendMessage("A", b1)
+sim.sendMessage("A", b2)
+sim.sendMessage("A", b3)
+sim.sendMessage("A", bc)
+
+sim.unbind(c2, "A")
+
+sim.sendMessage("A", b1)
+sim.sendMessage("A", b2)
+sim.sendMessage("A", b3)
+sim.sendMessage("A", bc)
+
+sim.end()
diff --git a/python/models/fedsim/testStarAdd.py b/python/models/fedsim/testStarAdd.py
new file mode 100644
index 0000000000..e0eb44952a
--- /dev/null
+++ b/python/models/fedsim/testStarAdd.py
@@ -0,0 +1,56 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from fedsim import Sim
+
+sim = Sim()
+b1 = sim.addBroker("B1")
+b2 = sim.addBroker("B2")
+b3 = sim.addBroker("B3")
+bc = sim.addBroker("BC")
+
+sim.link(b1, bc)
+sim.link(b2, bc)
+
+c1 = sim.addClient("C1", b1)
+c2 = sim.addClient("C2", b2)
+c3 = sim.addClient("C3", b3)
+cc = sim.addClient("CC", bc)
+
+sim.bind(c1, "A")
+
+sim.sendMessage("A", b1)
+sim.sendMessage("A", b2)
+sim.sendMessage("A", bc)
+
+sim.bind(c2, "A")
+
+sim.sendMessage("A", b1)
+sim.sendMessage("A", b2)
+sim.sendMessage("A", bc)
+
+sim.bind(c3, "A")
+sim.link(b3, bc)
+
+sim.sendMessage("A", b1)
+sim.sendMessage("A", b2)
+sim.sendMessage("A", bc)
+
+sim.end()
+
diff --git a/python/pal2py b/python/pal2py
deleted file mode 100755
index 544151bf76..0000000000
--- a/python/pal2py
+++ /dev/null
@@ -1,274 +0,0 @@
-#!/usr/bin/env python
-
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-import sys, os, xml
-
-from qpid.spec import load, pythonize
-from textwrap import TextWrapper
-from xml.sax.handler import ContentHandler
-
-class Block:
-
- def __init__(self, children):
- self.children = children
-
- def emit(self, out):
- for child in self.children:
- if not hasattr(child, "emit"):
- raise ValueError(child)
- child.emit(out)
-
- if not self.children:
- out.line("pass")
-
-class If:
-
- def __init__(self, expr, cons, alt = None):
- self.expr = expr
- self.cons = cons
- self.alt = alt
-
- def emit(self, out):
- out.line("if ")
- self.expr.emit(out)
- out.write(":")
- out.level += 1
- self.cons.emit(out)
- out.level -= 1
- if self.alt:
- out.line("else:")
- out.level += 1
- self.alt.emit(out)
- out.level -= 1
-
-class Stmt:
-
- def __init__(self, code):
- self.code = code
-
- def emit(self, out):
- out.line(self.code)
-
-class Expr:
-
- def __init__(self, code):
- self.code = code
-
- def emit(self, out):
- out.write(self.code)
-
-class Abort:
-
- def __init__(self, expr):
- self.expr = expr
-
- def emit(self, out):
- out.line("assert False, ")
- self.expr.emit(out)
-
-WRAPPER = TextWrapper()
-
-def wrap(text):
- return WRAPPER.wrap(" ".join(text.split()))
-
-class Doc:
-
- def __init__(self, text):
- self.text = text
-
- def emit(self, out):
- out.line('"""')
- for line in wrap(self.text):
- out.line(line)
- out.line('"""')
-
-class Frame:
-
- def __init__(self, attrs):
- self.attrs = attrs
- self.children = []
- self.text = None
-
- def __getattr__(self, attr):
- return self.attrs[attr]
-
-def isunicode(s):
- if isinstance(s, str):
- return False
- for ch in s:
- if ord(ch) > 127:
- return True
- return False
-
-def string_literal(s):
- if s == None:
- return None
- if isunicode(s):
- return "%r" % s
- else:
- return "%r" % str(s)
-
-TRUTH = {
- "1": True,
- "0": False,
- "true": True,
- "false": False
- }
-
-LITERAL = {
- "shortstr": string_literal,
- "longstr": string_literal,
- "bit": lambda s: TRUTH[s.lower()],
- "longlong": lambda s: "%r" % long(s)
- }
-
-def literal(s, field):
- return LITERAL[field.type](s)
-
-def palexpr(s, field):
- if s.startswith("$"):
- return "msg.%s" % s[1:]
- else:
- return literal(s, field)
-
-class Translator(ContentHandler):
-
- def __init__(self, spec):
- self.spec = spec
- self.stack = []
- self.content = None
- self.root = Frame(None)
- self.push(self.root)
-
- def emit(self, out):
- blk = Block(self.root.children)
- blk.emit(out)
- out.write("\n")
-
- def peek(self):
- return self.stack[-1]
-
- def pop(self):
- return self.stack.pop()
-
- def push(self, frame):
- self.stack.append(frame)
-
- def startElement(self, name, attrs):
- self.push(Frame(attrs))
-
- def endElement(self, name):
- frame = self.pop()
- if hasattr(self, name):
- child = getattr(self, name)(frame)
- else:
- child = self.handle(name, frame)
-
- if child:
- self.peek().children.append(child)
-
- def characters(self, text):
- frame = self.peek()
- if frame.text:
- frame.text += text
- else:
- frame.text = text
-
- def handle(self, name, frame):
- for klass in self.spec.classes:
- pyklass = pythonize(klass.name)
- if name.startswith(pyklass):
- name = name[len(pyklass) + 1:]
- break
- else:
- raise ValueError("unknown class: %s" % name)
-
- for method in klass.methods:
- pymethod = pythonize(method.name)
- if name == pymethod:
- break
- else:
- raise ValueError("unknown method: %s" % name)
-
- args = ["%s = %s" % (key, palexpr(val, method.fields.bypyname[key]))
- for key, val in frame.attrs.items()]
- if method.content and self.content:
- args.append("content = %r" % string_literal(self.content))
- code = "ssn.%s_%s(%s)" % (pyklass, pymethod, ", ".join(args))
- if pymethod == "consume":
- code = "consumer_tag = %s.consumer_tag" % code
- return Stmt(code)
-
- def pal(self, frame):
- return Block([Doc(frame.text)] + frame.children)
-
- def include(self, frame):
- base, ext = os.path.splitext(frame.filename)
- return Stmt("from %s import *" % base)
-
- def session(self, frame):
- return Block([Stmt("cli = open()"), Stmt("ssn = cli.channel(0)"),
- Stmt("ssn.channel_open()")] + frame.children)
-
- def empty(self, frame):
- return If(Expr("msg == None"), Block(frame.children))
-
- def abort(self, frame):
- return Abort(Expr(string_literal(frame.text)))
-
- def wait(self, frame):
- return Stmt("msg = ssn.queue(consumer_tag).get(timeout=%r)" %
- (int(frame.timeout)/1000))
-
- def basic_arrived(self, frame):
- if frame.children:
- return If(Expr("msg != None"), Block(frame.children))
-
- def basic_content(self, frame):
- self.content = frame.text
-
-class Emitter:
-
- def __init__(self, out):
- self.out = out
- self.level = 0
-
- def write(self, code):
- self.out.write(code)
-
- def line(self, code):
- self.write("\n%s%s" % (" "*self.level, code))
-
- def flush(self):
- self.out.flush()
-
- def close(self):
- self.out.close()
-
-
-for f in sys.argv[2:]:
- base, ext = os.path.splitext(f)
- spec = load(sys.argv[1])
- t = Translator(spec)
- xml.sax.parse(f, t)
-# out = Emitter(open("%s.py" % base))
- out = Emitter(sys.stdout)
- t.emit(out)
- out.close()
diff --git a/python/perftest b/python/perftest
deleted file mode 100755
index 2e9148ce50..0000000000
--- a/python/perftest
+++ /dev/null
@@ -1,95 +0,0 @@
-#!/usr/bin/env python
-
-def publisher(n):
- import qpid
- import sys
- from qpid.client import Client
- from qpid.content import Content
- if len(sys.argv) >= 3:
- n = int(sys.argv[2])
- client = Client("127.0.0.1", 5672)
- client.start({"LOGIN": "guest", "PASSWORD": "guest"})
- channel = client.channel(1)
- channel.session_open()
- message = Content("message")
- message["routing_key"] = "message_queue"
- print "producing ", n, " messages"
- for i in range(n):
- channel.message_transfer(destination="amq.direct", content=message)
-
- print "producing final message"
- message = Content("That's done")
- message["routing_key"] = "message_queue"
- channel.message_transfer(destination="amq.direct", content=message)
-
- print "consuming sync message"
- consumer = "consumer"
- queue = client.queue(consumer)
- channel.message_subscribe(queue="sync_queue", destination=consumer)
- channel.message_flow(consumer, 0, 0xFFFFFFFF)
- channel.message_flow(consumer, 1, 0xFFFFFFFF)
- queue.get(block = True)
- print "done"
- channel.session_close()
-
-def consumer():
- import sys
- import qpid
- from qpid.client import Client
- from qpid.content import Content
- client = Client("127.0.0.1", 5672)
- client.start({"LOGIN": "guest", "PASSWORD": "guest"})
- channel = client.channel(1)
- channel.session_open()
- consumer = "consumer"
- queue = client.queue(consumer)
- channel.message_subscribe(queue="message_queue", destination=consumer)
- channel.message_flow(consumer, 0, 0xFFFFFFFF)
- channel.message_flow(consumer, 1, 0xFFFFFFFF)
- final = "That's done"
- content = ""
- message = None
- print "getting messages"
- while content != final:
- message = queue.get(block = True)
- content = message.content.body
- message.complete(cumulative=True)
-
- print "consumed all messages"
- message = Content("message")
- message["routing_key"] = "sync_queue"
- channel.message_transfer(destination="amq.direct", content=message)
- print "done"
- channel.session_close()
-
-if __name__=='__main__':
- import sys
- import qpid
- from timeit import Timer
- from qpid.client import Client
- from qpid.content import Content
- client = Client("127.0.0.1", 5672)
- client.start({"LOGIN": "guest", "PASSWORD": "guest"})
- channel = client.channel(1)
- channel.session_open()
- channel.queue_declare(queue="message_queue")
- channel.queue_bind(exchange="amq.direct", queue="message_queue", routing_key="message_queue")
- channel.queue_declare(queue="sync_queue")
- channel.queue_bind(exchange="amq.direct", queue="sync_queue", routing_key="sync_queue")
- channel.session_close()
-
- numMess = 100
- if len(sys.argv) >= 3:
- numMess = int(sys.argv[2])
- if len(sys.argv) == 1:
- print "error: please specify prod or cons"
- elif sys.argv[1] == 'prod':
- tprod = Timer("publisher(100)", "from __main__ import publisher")
- tp = tprod.timeit(1)
- print "produced and consumed" , numMess + 2 ,"messages in: ", tp
- elif sys.argv[1] == 'cons':
- tcons = Timer("consumer()", "from __main__ import consumer")
- tc = tcons.timeit(1)
- print "consumed " , numMess ," in: ", tc
- else:
- print "please specify prod or cons"
diff --git a/python/preppy b/python/preppy
new file mode 100755
index 0000000000..22893dad03
--- /dev/null
+++ b/python/preppy
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import os, re, sys
+
+ann = re.compile(r"([ \t]*)@([_a-zA-Z][_a-zA-Z0-9]*)([ \t\n\r]+def[ \t]+)([_a-zA-Z][_a-zA-Z0-9]*)")
+line = re.compile(r"\n([ \t]*)[^ \t\n#]+")
+
+if len(sys.argv) == 2:
+ major, minor = [int(p) for p in sys.argv[1].split(".")]
+elif len(sys.argv) == 1:
+ major, minor = sys.version_info[0:2]
+else:
+ print "usage: %s [ version ] < input.py > output.py" % sys.argv[0]
+ sys.exit(-1)
+
+if major <= 2 and minor <= 3:
+ def process(input):
+ output = ""
+ pos = 0
+ while True:
+ m = ann.search(input, pos)
+ if m:
+ indent, decorator, idef, function = m.groups()
+ output += input[pos:m.start()]
+ output += "%s#@%s%s%s" % (indent, decorator, idef, function)
+ pos = m.end()
+
+ subst = "\n%s%s = %s(%s)\n" % (indent, function, decorator, function)
+ npos = pos
+ while True:
+ n = line.search(input, npos)
+ if not n:
+ input += subst
+ break
+ if len(n.group(1)) <= len(indent):
+ idx = n.start()
+ input = input[:idx] + subst + input[idx:]
+ break
+ npos = n.end()
+ else:
+ break
+
+ output += input[pos:]
+ return output
+else:
+ def process(input):
+ return input
+
+sys.stdout.write(process(sys.stdin.read()))
diff --git a/python/qmf/__init__.py b/python/qmf/__init__.py
new file mode 100644
index 0000000000..31d5a2ef58
--- /dev/null
+++ b/python/qmf/__init__.py
@@ -0,0 +1,18 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT 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/python/qmf/console.py b/python/qmf/console.py
new file mode 100644
index 0000000000..5348904097
--- /dev/null
+++ b/python/qmf/console.py
@@ -0,0 +1,1970 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+""" Console API for Qpid Management Framework """
+
+import os
+import platform
+import qpid
+import struct
+import socket
+import re
+from qpid.datatypes import UUID
+from qpid.datatypes import timestamp
+from qpid.datatypes import datetime
+from qpid.peer import Closed
+from qpid.session import SessionDetached
+from qpid.connection import Connection, ConnectionFailed, Timeout
+from qpid.datatypes import Message, RangedSet, UUID
+from qpid.util import connect, ssl, URL
+from qpid.codec010 import StringCodec as Codec
+from threading import Lock, Condition, Thread
+from time import time, strftime, gmtime
+from cStringIO import StringIO
+
+#import qpid.log
+#qpid.log.enable(name="qpid.io.cmd", level=qpid.log.DEBUG)
+
+class Console:
+ """ To access the asynchronous operations, a class must be derived from
+ Console with overrides of any combination of the available methods. """
+
+ def brokerConnected(self, broker):
+ """ Invoked when a connection is established to a broker """
+ pass
+
+ def brokerDisconnected(self, broker):
+ """ Invoked when the connection to a broker is lost """
+ pass
+
+ def newPackage(self, name):
+ """ Invoked when a QMF package is discovered. """
+ pass
+
+ def newClass(self, kind, classKey):
+ """ Invoked when a new class is discovered. Session.getSchema can be
+ used to obtain details about the class."""
+ pass
+
+ def newAgent(self, agent):
+ """ Invoked when a QMF agent is discovered. """
+ pass
+
+ def delAgent(self, agent):
+ """ Invoked when a QMF agent disconects. """
+ pass
+
+ def objectProps(self, broker, record):
+ """ Invoked when an object is updated. """
+ pass
+
+ def objectStats(self, broker, record):
+ """ Invoked when an object is updated. """
+ pass
+
+ def event(self, broker, event):
+ """ Invoked when an event is raised. """
+ pass
+
+ def heartbeat(self, agent, timestamp):
+ """ Invoked when an agent heartbeat is received. """
+ pass
+
+ def brokerInfo(self, broker):
+ """ Invoked when the connection sequence reaches the point where broker information is available. """
+ pass
+
+ def methodResponse(self, broker, seq, response):
+ """ Invoked when a method response from an asynchronous method call is received. """
+ pass
+
+class BrokerURL(URL):
+ def __init__(self, text):
+ URL.__init__(self, text)
+ if self.port is None:
+ if self.scheme == URL.AMQPS:
+ self.port = 5671
+ else:
+ self.port = 5672
+ self.authName = None
+ self.authPass = None
+ if self.user:
+ self.authName = str(self.user)
+ if self.password:
+ self.authPass = str(self.password)
+
+ def name(self):
+ return self.host + ":" + str(self.port)
+
+ def match(self, host, port):
+ return socket.getaddrinfo(self.host, self.port)[0][4] == socket.getaddrinfo(host, port)[0][4]
+
+class Object(object):
+ """ This class defines a 'proxy' object representing a real managed object on an agent.
+ Actions taken on this proxy are remotely affected on the real managed object.
+ """
+ def __init__(self, session, broker, schema, codec, prop, stat, managed=True, kwargs={}):
+ self._session = session
+ self._broker = broker
+ self._schema = schema
+ self._managed = managed
+ if self._managed:
+ self._currentTime = codec.read_uint64()
+ self._createTime = codec.read_uint64()
+ self._deleteTime = codec.read_uint64()
+ self._objectId = ObjectId(codec)
+ else:
+ self._currentTime = None
+ self._createTime = None
+ self._deleteTime = None
+ self._objectId = None
+ self._properties = []
+ self._statistics = []
+ if codec:
+ if prop:
+ notPresent = self._parsePresenceMasks(codec, schema)
+ for property in schema.getProperties():
+ if property.name in notPresent:
+ self._properties.append((property, None))
+ else:
+ self._properties.append((property, self._session._decodeValue(codec, property.type, broker)))
+ if stat:
+ for statistic in schema.getStatistics():
+ self._statistics.append((statistic, self._session._decodeValue(codec, statistic.type, broker)))
+ else:
+ for property in schema.getProperties():
+ if property.optional:
+ self._properties.append((property, None))
+ else:
+ self._properties.append((property, self._session._defaultValue(property, broker, kwargs)))
+ for statistic in schema.getStatistics():
+ self._statistics.append((statistic, self._session._defaultValue(statistic, broker, kwargs)))
+
+ def getBroker(self):
+ """ Return the broker from which this object was sent """
+ return self._broker
+
+ def getObjectId(self):
+ """ Return the object identifier for this object """
+ return self._objectId
+
+ def getClassKey(self):
+ """ Return the class-key that references the schema describing this object. """
+ return self._schema.getKey()
+
+ def getSchema(self):
+ """ Return the schema that describes this object. """
+ return self._schema
+
+ def getMethods(self):
+ """ Return a list of methods available for this object. """
+ return self._schema.getMethods()
+
+ def getTimestamps(self):
+ """ Return the current, creation, and deletion times for this object. """
+ return self._currentTime, self._createTime, self._deleteTime
+
+ def isDeleted(self):
+ """ Return True iff this object has been deleted. """
+ return self._deleteTime != 0
+
+ def isManaged(self):
+ """ Return True iff this object is a proxy for a managed object on an agent. """
+ return self._managed
+
+ def getIndex(self):
+ """ Return a string describing this object's primary key. """
+ result = u""
+ for property, value in self._properties:
+ if property.index:
+ if result != u"":
+ result += u":"
+ try:
+ valstr = unicode(self._session._displayValue(value, property.type))
+ except:
+ valstr = u"<undecodable>"
+ result += valstr
+ return result
+
+ def getProperties(self):
+ """ Return a list of object properties """
+ return self._properties
+
+ def getStatistics(self):
+ """ Return a list of object statistics """
+ return self._statistics
+
+ def mergeUpdate(self, newer):
+ """ Replace properties and/or statistics with a newly received update """
+ if not self.isManaged():
+ raise Exception("Object is not managed")
+ if self._objectId != newer._objectId:
+ raise Exception("Objects with different object-ids")
+ if len(newer.getProperties()) > 0:
+ self._properties = newer.getProperties()
+ if len(newer.getStatistics()) > 0:
+ self._statistics = newer.getStatistics()
+
+ def update(self):
+ """ Contact the agent and retrieve the lastest property and statistic values for this object. """
+ if not self.isManaged():
+ raise Exception("Object is not managed")
+ obj = self._session.getObjects(_objectId = self._objectId, _broker=self._broker)
+ if obj:
+ self.mergeUpdate(obj[0])
+ else:
+ raise Exception("Underlying object no longer exists")
+
+ def __repr__(self):
+ if self.isManaged():
+ id = self.getObjectId().__repr__()
+ else:
+ id = "unmanaged"
+ key = self.getClassKey()
+ return key.getPackageName() + ":" + key.getClassName() +\
+ "[" + id + "] " + self.getIndex().encode("utf8")
+
+ def __getattr__(self, name):
+ for method in self._schema.getMethods():
+ if name == method.name:
+ return lambda *args, **kwargs : self._invoke(name, args, kwargs)
+ for property, value in self._properties:
+ if name == property.name:
+ return value
+ if name == "_" + property.name + "_" and property.type == 10: # Dereference references
+ deref = self._session.getObjects(_objectId=value, _broker=self._broker)
+ if len(deref) != 1:
+ return None
+ else:
+ return deref[0]
+ for statistic, value in self._statistics:
+ if name == statistic.name:
+ return value
+ raise Exception("Type Object has no attribute '%s'" % name)
+
+ def __setattr__(self, name, value):
+ if name[0] == '_':
+ super.__setattr__(self, name, value)
+ return
+
+ for prop, unusedValue in self._properties:
+ if name == prop.name:
+ newprop = (prop, value)
+ newlist = []
+ for old, val in self._properties:
+ if name == old.name:
+ newlist.append(newprop)
+ else:
+ newlist.append((old, val))
+ self._properties = newlist
+ return
+ super.__setattr__(self, name, value)
+
+ def _sendMethodRequest(self, name, args, kwargs, synchronous=False, timeWait=None):
+ for method in self._schema.getMethods():
+ if name == method.name:
+ aIdx = 0
+ sendCodec = Codec()
+ seq = self._session.seqMgr._reserve((method, synchronous))
+ self._broker._setHeader(sendCodec, 'M', seq)
+ self._objectId.encode(sendCodec)
+ self._schema.getKey().encode(sendCodec)
+ sendCodec.write_str8(name)
+
+ count = 0
+ for arg in method.arguments:
+ if arg.dir.find("I") != -1:
+ count += 1
+ if count != len(args):
+ raise Exception("Incorrect number of arguments: expected %d, got %d" % (count, len(args)))
+
+ for arg in method.arguments:
+ if arg.dir.find("I") != -1:
+ self._session._encodeValue(sendCodec, args[aIdx], arg.type)
+ aIdx += 1
+ if timeWait:
+ ttl = timeWait * 1000
+ else:
+ ttl = None
+ smsg = self._broker._message(sendCodec.encoded, "agent.%d.%d" %
+ (self._objectId.getBrokerBank(), self._objectId.getAgentBank()),
+ ttl=ttl)
+ if synchronous:
+ try:
+ self._broker.cv.acquire()
+ self._broker.syncInFlight = True
+ finally:
+ self._broker.cv.release()
+ self._broker._send(smsg)
+ return seq
+ return None
+
+ def _invoke(self, name, args, kwargs):
+ if not self.isManaged():
+ raise Exception("Object is not managed")
+ if "_timeout" in kwargs:
+ timeout = kwargs["_timeout"]
+ else:
+ timeout = self._broker.SYNC_TIME
+
+ if "_async" in kwargs and kwargs["_async"]:
+ sync = False
+ if "_timeout" not in kwargs:
+ timeout = None
+ else:
+ sync = True
+
+ seq = self._sendMethodRequest(name, args, kwargs, sync, timeout)
+ if seq:
+ if not sync:
+ return seq
+ try:
+ self._broker.cv.acquire()
+ starttime = time()
+ while self._broker.syncInFlight and self._broker.error == None:
+ self._broker.cv.wait(timeout)
+ if time() - starttime > timeout:
+ self._session.seqMgr._release(seq)
+ raise RuntimeError("Timed out waiting for method to respond")
+ finally:
+ self._broker.cv.release()
+ if self._broker.error != None:
+ errorText = self._broker.error
+ self._broker.error = None
+ raise Exception(errorText)
+ return self._broker.syncResult
+ raise Exception("Invalid Method (software defect) [%s]" % name)
+
+ def _encodeUnmanaged(self, codec):
+
+ codec.write_uint8(20)
+ codec.write_str8(self._schema.getKey().getPackageName())
+ codec.write_str8(self._schema.getKey().getClassName())
+ codec.write_bin128(self._schema.getKey().getHash())
+
+ # emit presence masks for optional properties
+ mask = 0
+ bit = 0
+ for prop, value in self._properties:
+ if prop.optional:
+ if bit == 0:
+ bit = 1
+ if value:
+ mask |= bit
+ bit = bit << 1
+ if bit == 256:
+ bit = 0
+ codec.write_uint8(mask)
+ mask = 0
+ if bit != 0:
+ codec.write_uint8(mask)
+
+ # encode properties
+ for prop, value in self._properties:
+ if value != None:
+ self._session._encodeValue(codec, value, prop.type)
+
+ # encode statistics
+ for stat, value in self._statistics:
+ self._session._encodeValue(codec, value, stat.type)
+
+ def _parsePresenceMasks(self, codec, schema):
+ excludeList = []
+ bit = 0
+ for property in schema.getProperties():
+ if property.optional:
+ if bit == 0:
+ mask = codec.read_uint8()
+ bit = 1
+ if (mask & bit) == 0:
+ excludeList.append(property.name)
+ bit *= 2
+ if bit == 256:
+ bit = 0
+ return excludeList
+
+class Session:
+ """
+ An instance of the Session class represents a console session running
+ against one or more QMF brokers. A single instance of Session is needed
+ to interact with the management framework as a console.
+ """
+ _CONTEXT_SYNC = 1
+ _CONTEXT_STARTUP = 2
+ _CONTEXT_MULTIGET = 3
+
+ DEFAULT_GET_WAIT_TIME = 60
+
+ ENCODINGS = {
+ str: 7,
+ timestamp: 8,
+ datetime: 8,
+ int: 9,
+ long: 9,
+ float: 13,
+ UUID: 14,
+ Object: 20,
+ list: 21
+ }
+
+ def __init__(self, console=None, rcvObjects=True, rcvEvents=True, rcvHeartbeats=True,
+ manageConnections=False, userBindings=False):
+ """
+ Initialize a session. If the console argument is provided, the
+ more advanced asynchronous features are available. If console is
+ defaulted, the session will operate in a simpler, synchronous manner.
+
+ The rcvObjects, rcvEvents, and rcvHeartbeats arguments are meaningful only if 'console'
+ is provided. They control whether object updates, events, and agent-heartbeats are
+ subscribed to. If the console is not interested in receiving one or more of the above,
+ setting the argument to False will reduce tha bandwidth used by the API.
+
+ If manageConnections is set to True, the Session object will manage connections to
+ the brokers. This means that if a broker is unreachable, it will retry until a connection
+ can be established. If a connection is lost, the Session will attempt to reconnect.
+
+ If manageConnections is set to False, the user is responsible for handing failures. In
+ this case, an unreachable broker will cause addBroker to raise an exception.
+
+ If userBindings is set to False (the default) and rcvObjects is True, the console will
+ receive data for all object classes. If userBindings is set to True, the user must select
+ which classes the console shall receive by invoking the bindPackage or bindClass methods.
+ This allows the console to be configured to receive only information that is relavant to
+ a particular application. If rcvObjects id False, userBindings has no meaning.
+ """
+ self.console = console
+ self.brokers = []
+ self.packages = {}
+ self.seqMgr = SequenceManager()
+ self.cv = Condition()
+ self.syncSequenceList = []
+ self.getResult = []
+ self.getSelect = []
+ self.error = None
+ self.rcvObjects = rcvObjects
+ self.rcvEvents = rcvEvents
+ self.rcvHeartbeats = rcvHeartbeats
+ self.userBindings = userBindings
+ if self.console == None:
+ self.rcvObjects = False
+ self.rcvEvents = False
+ self.rcvHeartbeats = False
+ self.bindingKeyList = self._bindingKeys()
+ self.manageConnections = manageConnections
+
+ if self.userBindings and not self.rcvObjects:
+ raise Exception("userBindings can't be set unless rcvObjects is set and a console is provided")
+
+ def __repr__(self):
+ return "QMF Console Session Manager (brokers: %d)" % len(self.brokers)
+
+ def addBroker(self, target="localhost", timeout=None, mechanisms=None):
+ """ Connect to a Qpid broker. Returns an object of type Broker. """
+ url = BrokerURL(target)
+ broker = Broker(self, url.host, url.port, mechanisms, url.authName, url.authPass,
+ ssl = url.scheme == URL.AMQPS, connTimeout=timeout)
+
+ self.brokers.append(broker)
+ if not self.manageConnections:
+ self.getObjects(broker=broker, _class="agent")
+ return broker
+
+ def delBroker(self, broker):
+ """ Disconnect from a broker. The 'broker' argument is the object
+ returned from the addBroker call """
+ if self.console:
+ for agent in broker.getAgents():
+ self.console.delAgent(agent)
+ broker._shutdown()
+ self.brokers.remove(broker)
+ del broker
+
+ def getPackages(self):
+ """ Get the list of known QMF packages """
+ for broker in self.brokers:
+ broker._waitForStable()
+ list = []
+ for package in self.packages:
+ list.append(package)
+ return list
+
+ def getClasses(self, packageName):
+ """ Get the list of known classes within a QMF package """
+ for broker in self.brokers:
+ broker._waitForStable()
+ list = []
+ if packageName in self.packages:
+ for pkey in self.packages[packageName]:
+ list.append(self.packages[packageName][pkey].getKey())
+ return list
+
+ def getSchema(self, classKey):
+ """ Get the schema for a QMF class """
+ for broker in self.brokers:
+ broker._waitForStable()
+ pname = classKey.getPackageName()
+ pkey = classKey.getPackageKey()
+ if pname in self.packages:
+ if pkey in self.packages[pname]:
+ return self.packages[pname][pkey]
+
+ def bindPackage(self, packageName):
+ """ Request object updates for all table classes within a package. """
+ if not self.userBindings or not self.rcvObjects:
+ raise Exception("userBindings option not set for Session")
+ key = "console.obj.*.*.%s.#" % packageName
+ self.bindingKeyList.append(key)
+ for broker in self.brokers:
+ if broker.isConnected():
+ broker.amqpSession.exchange_bind(exchange="qpid.management", queue=broker.topicName,
+ binding_key=key)
+
+ def bindClass(self, pname, cname):
+ """ Request object updates for a particular table class by package and class name. """
+ if not self.userBindings or not self.rcvObjects:
+ raise Exception("userBindings option not set for Session")
+ key = "console.obj.*.*.%s.%s.#" % (pname, cname)
+ self.bindingKeyList.append(key)
+ for broker in self.brokers:
+ if broker.isConnected():
+ broker.amqpSession.exchange_bind(exchange="qpid.management", queue=broker.topicName,
+ binding_key=key)
+
+ def bindClassKey(self, classKey):
+ """ Request object updates for a particular table class by class key. """
+ pname = classKey.getPackageName()
+ cname = classKey.getClassName()
+ self.bindClass(pname, cname)
+
+ def getAgents(self, broker=None):
+ """ Get a list of currently known agents """
+ brokerList = []
+ if broker == None:
+ for b in self.brokers:
+ brokerList.append(b)
+ else:
+ brokerList.append(broker)
+
+ for b in brokerList:
+ b._waitForStable()
+ agentList = []
+ for b in brokerList:
+ for a in b.getAgents():
+ agentList.append(a)
+ return agentList
+
+ def makeObject(self, classKey, broker=None, **kwargs):
+ """ Create a new, unmanaged object of the schema indicated by classKey """
+ schema = self.getSchema(classKey)
+ if schema == None:
+ raise Exception("Schema not found for classKey")
+ return Object(self, broker, schema, None, True, True, False, kwargs)
+
+ def getObjects(self, **kwargs):
+ """ Get a list of objects from QMF agents.
+ All arguments are passed by name(keyword).
+
+ The class for queried objects may be specified in one of the following ways:
+
+ _schema = <schema> - supply a schema object returned from getSchema.
+ _key = <key> - supply a classKey from the list returned by getClasses.
+ _class = <name> - supply a class name as a string. If the class name exists
+ in multiple packages, a _package argument may also be supplied.
+ _objectId = <id> - get the object referenced by the object-id
+
+ If objects should be obtained from only one agent, use the following argument.
+ Otherwise, the query will go to all agents.
+
+ _agent = <agent> - supply an agent from the list returned by getAgents.
+
+ If the get query is to be restricted to one broker (as opposed to all connected brokers),
+ add the following argument:
+
+ _broker = <broker> - supply a broker as returned by addBroker.
+
+ The default timeout for this synchronous operation is 60 seconds. To change the timeout,
+ use the following argument:
+
+ _timeout = <time in seconds>
+
+ If additional arguments are supplied, they are used as property selectors. For example,
+ if the argument name="test" is supplied, only objects whose "name" property is "test"
+ will be returned in the result.
+ """
+ if "_broker" in kwargs:
+ brokerList = []
+ brokerList.append(kwargs["_broker"])
+ else:
+ brokerList = self.brokers
+ for broker in brokerList:
+ broker._waitForStable()
+ if broker.isConnected():
+ if "_package" not in kwargs or "_class" not in kwargs or \
+ kwargs["_package"] != "org.apache.qpid.broker" or \
+ kwargs["_class"] != "agent":
+ self.getObjects(_package = "org.apache.qpid.broker", _class = "agent",
+ _agent = broker.getAgent(1,0))
+
+ agentList = []
+ if "_agent" in kwargs:
+ agent = kwargs["_agent"]
+ if agent.broker not in brokerList:
+ raise Exception("Supplied agent is not accessible through the supplied broker")
+ if agent.broker.isConnected():
+ agentList.append(agent)
+ else:
+ if "_objectId" in kwargs:
+ oid = kwargs["_objectId"]
+ for broker in brokerList:
+ for agent in broker.getAgents():
+ if agent.getBrokerBank() == oid.getBrokerBank() and agent.getAgentBank() == oid.getAgentBank():
+ agentList.append(agent)
+ else:
+ for broker in brokerList:
+ for agent in broker.getAgents():
+ if agent.broker.isConnected():
+ agentList.append(agent)
+
+ if len(agentList) == 0:
+ return []
+
+ pname = None
+ cname = None
+ hash = None
+ classKey = None
+ if "_schema" in kwargs: classKey = kwargs["_schema"].getKey()
+ elif "_key" in kwargs: classKey = kwargs["_key"]
+ elif "_class" in kwargs:
+ cname = kwargs["_class"]
+ if "_package" in kwargs:
+ pname = kwargs["_package"]
+ if cname == None and classKey == None and "_objectId" not in kwargs:
+ raise Exception("No class supplied, use '_schema', '_key', '_class', or '_objectId' argument")
+
+ map = {}
+ self.getSelect = []
+ if "_objectId" in kwargs:
+ map["_objectid"] = kwargs["_objectId"].__repr__()
+ else:
+ if cname == None:
+ cname = classKey.getClassName()
+ pname = classKey.getPackageName()
+ hash = classKey.getHash()
+ map["_class"] = cname
+ if pname != None: map["_package"] = pname
+ if hash != None: map["_hash"] = hash
+ for item in kwargs:
+ if item[0] != '_':
+ self.getSelect.append((item, kwargs[item]))
+
+ self.getResult = []
+ for agent in agentList:
+ broker = agent.broker
+ sendCodec = Codec()
+ try:
+ self.cv.acquire()
+ seq = self.seqMgr._reserve(self._CONTEXT_MULTIGET)
+ self.syncSequenceList.append(seq)
+ finally:
+ self.cv.release()
+ broker._setHeader(sendCodec, 'G', seq)
+ sendCodec.write_map(map)
+ smsg = broker._message(sendCodec.encoded, "agent.%d.%d" % (agent.brokerBank, agent.agentBank))
+ broker._send(smsg)
+
+ starttime = time()
+ timeout = False
+ if "_timeout" in kwargs:
+ waitTime = kwargs["_timeout"]
+ else:
+ waitTime = self.DEFAULT_GET_WAIT_TIME
+ try:
+ self.cv.acquire()
+ while len(self.syncSequenceList) > 0 and self.error == None:
+ self.cv.wait(waitTime)
+ if time() - starttime > waitTime:
+ for pendingSeq in self.syncSequenceList:
+ self.seqMgr._release(pendingSeq)
+ self.syncSequenceList = []
+ timeout = True
+ finally:
+ self.cv.release()
+
+ if self.error:
+ errorText = self.error
+ self.error = None
+ raise Exception(errorText)
+
+ if len(self.getResult) == 0 and timeout:
+ raise RuntimeError("No agent responded within timeout period")
+ return self.getResult
+
+ def setEventFilter(self, **kwargs):
+ """ """
+ pass
+
+ def _bindingKeys(self):
+ keyList = []
+ keyList.append("schema.#")
+ if self.rcvObjects and self.rcvEvents and self.rcvHeartbeats and not self.userBindings:
+ keyList.append("console.#")
+ else:
+ if self.rcvObjects and not self.userBindings:
+ keyList.append("console.obj.#")
+ else:
+ keyList.append("console.obj.*.*.org.apache.qpid.broker.agent")
+ if self.rcvEvents:
+ keyList.append("console.event.#")
+ if self.rcvHeartbeats:
+ keyList.append("console.heartbeat.#")
+ return keyList
+
+ def _handleBrokerConnect(self, broker):
+ if self.console:
+ for agent in broker.getAgents():
+ self.console.newAgent(agent)
+ self.console.brokerConnected(broker)
+
+ def _handleBrokerDisconnect(self, broker):
+ if self.console:
+ for agent in broker.getAgents():
+ self.console.delAgent(agent)
+ self.console.brokerDisconnected(broker)
+
+ def _handleBrokerResp(self, broker, codec, seq):
+ broker.brokerId = codec.read_uuid()
+ if self.console != None:
+ self.console.brokerInfo(broker)
+
+ # Send a package request
+ # (effectively inc and dec outstanding by not doing anything)
+ sendCodec = Codec()
+ seq = self.seqMgr._reserve(self._CONTEXT_STARTUP)
+ broker._setHeader(sendCodec, 'P', seq)
+ smsg = broker._message(sendCodec.encoded)
+ broker._send(smsg)
+
+ def _handlePackageInd(self, broker, codec, seq):
+ pname = str(codec.read_str8())
+ notify = False
+ try:
+ self.cv.acquire()
+ if pname not in self.packages:
+ self.packages[pname] = {}
+ notify = True
+ finally:
+ self.cv.release()
+ if notify and self.console != None:
+ self.console.newPackage(pname)
+
+ # Send a class request
+ broker._incOutstanding()
+ sendCodec = Codec()
+ seq = self.seqMgr._reserve(self._CONTEXT_STARTUP)
+ broker._setHeader(sendCodec, 'Q', seq)
+ sendCodec.write_str8(pname)
+ smsg = broker._message(sendCodec.encoded)
+ broker._send(smsg)
+
+ def _handleCommandComplete(self, broker, codec, seq):
+ code = codec.read_uint32()
+ text = codec.read_str8()
+ context = self.seqMgr._release(seq)
+ if context == self._CONTEXT_STARTUP:
+ broker._decOutstanding()
+ elif context == self._CONTEXT_SYNC and seq == broker.syncSequence:
+ try:
+ broker.cv.acquire()
+ broker.syncInFlight = False
+ broker.cv.notify()
+ finally:
+ broker.cv.release()
+ elif context == self._CONTEXT_MULTIGET and seq in self.syncSequenceList:
+ try:
+ self.cv.acquire()
+ self.syncSequenceList.remove(seq)
+ if len(self.syncSequenceList) == 0:
+ self.cv.notify()
+ finally:
+ self.cv.release()
+
+ def _handleClassInd(self, broker, codec, seq):
+ kind = codec.read_uint8()
+ classKey = ClassKey(codec)
+ unknown = False
+
+ try:
+ self.cv.acquire()
+ if classKey.getPackageName() in self.packages:
+ if classKey.getPackageKey() not in self.packages[classKey.getPackageName()]:
+ unknown = True
+ finally:
+ self.cv.release()
+
+ if unknown:
+ # Send a schema request for the unknown class
+ broker._incOutstanding()
+ sendCodec = Codec()
+ seq = self.seqMgr._reserve(self._CONTEXT_STARTUP)
+ broker._setHeader(sendCodec, 'S', seq)
+ classKey.encode(sendCodec)
+ smsg = broker._message(sendCodec.encoded)
+ broker._send(smsg)
+
+ def _handleMethodResp(self, broker, codec, seq):
+ code = codec.read_uint32()
+ text = codec.read_str16()
+ outArgs = {}
+ pair = self.seqMgr._release(seq)
+ if pair == None:
+ return
+ method, synchronous = pair
+ if code == 0:
+ for arg in method.arguments:
+ if arg.dir.find("O") != -1:
+ outArgs[arg.name] = self._decodeValue(codec, arg.type, broker)
+ result = MethodResult(code, text, outArgs)
+ if synchronous:
+ try:
+ broker.cv.acquire()
+ broker.syncResult = result
+ broker.syncInFlight = False
+ broker.cv.notify()
+ finally:
+ broker.cv.release()
+ else:
+ if self.console:
+ self.console.methodResponse(broker, seq, result)
+
+ def _handleHeartbeatInd(self, broker, codec, seq, msg):
+ brokerBank = 1
+ agentBank = 0
+ dp = msg.get("delivery_properties")
+ if dp:
+ key = dp["routing_key"]
+ keyElements = key.split(".")
+ if len(keyElements) == 4:
+ brokerBank = int(keyElements[2])
+ agentBank = int(keyElements[3])
+
+ agent = broker.getAgent(brokerBank, agentBank)
+ timestamp = codec.read_uint64()
+ if self.console != None and agent != None:
+ self.console.heartbeat(agent, timestamp)
+
+ def _handleEventInd(self, broker, codec, seq):
+ if self.console != None:
+ event = Event(self, broker, codec)
+ self.console.event(broker, event)
+
+ def _handleSchemaResp(self, broker, codec, seq):
+ kind = codec.read_uint8()
+ classKey = ClassKey(codec)
+ _class = SchemaClass(kind, classKey, codec, self)
+ try:
+ self.cv.acquire()
+ self.packages[classKey.getPackageName()][classKey.getPackageKey()] = _class
+ finally:
+ self.cv.release()
+
+ self.seqMgr._release(seq)
+ broker._decOutstanding()
+ if self.console != None:
+ self.console.newClass(kind, classKey)
+
+ def _handleContentInd(self, broker, codec, seq, prop=False, stat=False):
+ classKey = ClassKey(codec)
+ try:
+ self.cv.acquire()
+ pname = classKey.getPackageName()
+ if pname not in self.packages:
+ return
+ pkey = classKey.getPackageKey()
+ if pkey not in self.packages[pname]:
+ return
+ schema = self.packages[pname][pkey]
+ finally:
+ self.cv.release()
+
+ object = Object(self, broker, schema, codec, prop, stat)
+ if pname == "org.apache.qpid.broker" and classKey.getClassName() == "agent" and prop:
+ broker._updateAgent(object)
+
+ try:
+ self.cv.acquire()
+ if seq in self.syncSequenceList:
+ if object.getTimestamps()[2] == 0 and self._selectMatch(object):
+ self.getResult.append(object)
+ return
+ finally:
+ self.cv.release()
+
+ if self.console and self.rcvObjects:
+ if prop:
+ self.console.objectProps(broker, object)
+ if stat:
+ self.console.objectStats(broker, object)
+
+ def _handleError(self, error):
+ try:
+ self.cv.acquire()
+ if len(self.syncSequenceList) > 0:
+ self.error = error
+ self.syncSequenceList = []
+ self.cv.notify()
+ finally:
+ self.cv.release()
+
+ def _selectMatch(self, object):
+ """ Check the object against self.getSelect to check for a match """
+ for key, value in self.getSelect:
+ for prop, propval in object.getProperties():
+ if key == prop.name and value != propval:
+ return False
+ return True
+
+ def _decodeValue(self, codec, typecode, broker=None):
+ """ Decode, from the codec, a value based on its typecode. """
+ if typecode == 1: data = codec.read_uint8() # U8
+ elif typecode == 2: data = codec.read_uint16() # U16
+ elif typecode == 3: data = codec.read_uint32() # U32
+ elif typecode == 4: data = codec.read_uint64() # U64
+ elif typecode == 6: data = codec.read_str8() # SSTR
+ elif typecode == 7: data = codec.read_str16() # LSTR
+ elif typecode == 8: data = codec.read_int64() # ABSTIME
+ elif typecode == 9: data = codec.read_uint64() # DELTATIME
+ elif typecode == 10: data = ObjectId(codec) # REF
+ elif typecode == 11: data = codec.read_uint8() != 0 # BOOL
+ elif typecode == 12: data = codec.read_float() # FLOAT
+ elif typecode == 13: data = codec.read_double() # DOUBLE
+ elif typecode == 14: data = codec.read_uuid() # UUID
+ elif typecode == 16: data = codec.read_int8() # S8
+ elif typecode == 17: data = codec.read_int16() # S16
+ elif typecode == 18: data = codec.read_int32() # S32
+ elif typecode == 19: data = codec.read_int64() # S63
+ elif typecode == 15: data = codec.read_map() # FTABLE
+ elif typecode == 20: # OBJECT
+ # Peek at the type, and if it is still 20 pull it decode. If
+ # Not, call back into self.
+ inner_type_code = codec.read_uint8()
+ if inner_type_code == 20:
+ classKey = ClassKey(codec)
+ try:
+ self.cv.acquire()
+ pname = classKey.getPackageName()
+ if pname not in self.packages:
+ return None
+ pkey = classKey.getPackageKey()
+ if pkey not in self.packages[pname]:
+ return None
+ schema = self.packages[pname][pkey]
+ finally:
+ self.cv.release()
+ data = Object(self, broker, schema, codec, True, True, False)
+ else:
+ data = self._decodeValue(codec, inner_type_code, broker)
+ elif typecode == 21: # List
+ #taken from codec10.read_list
+ sc = Codec(codec.read_vbin32())
+ count = sc.read_uint32()
+ data = []
+ while count > 0:
+ type = sc.read_uint8()
+ data.append(self._decodeValue(sc,type,broker))
+ count -= 1
+ elif typecode == 22: #Array
+ #taken from codec10.read_array
+ sc = Codec(codec.read_vbin32())
+ count = sc.read_uint32()
+ type = sc.read_uint8()
+ data = []
+ while count > 0:
+ data.append(self._decodeValue(sc,type,broker))
+ count -= 1
+ else:
+ raise ValueError("Invalid type code: %d" % typecode)
+ return data
+
+ def _encodeValue(self, codec, value, typecode):
+ """ Encode, into the codec, a value based on its typecode. """
+ if typecode == 1: codec.write_uint8 (int(value)) # U8
+ elif typecode == 2: codec.write_uint16 (int(value)) # U16
+ elif typecode == 3: codec.write_uint32 (long(value)) # U32
+ elif typecode == 4: codec.write_uint64 (long(value)) # U64
+ elif typecode == 6: codec.write_str8 (value) # SSTR
+ elif typecode == 7: codec.write_str16 (value) # LSTR
+ elif typecode == 8: codec.write_int64 (long(value)) # ABSTIME
+ elif typecode == 9: codec.write_uint64 (long(value)) # DELTATIME
+ elif typecode == 10: value.encode (codec) # REF
+ elif typecode == 11: codec.write_uint8 (int(value)) # BOOL
+ elif typecode == 12: codec.write_float (float(value)) # FLOAT
+ elif typecode == 13: codec.write_double (float(value)) # DOUBLE
+ elif typecode == 14: codec.write_uuid (value.bytes) # UUID
+ elif typecode == 16: codec.write_int8 (int(value)) # S8
+ elif typecode == 17: codec.write_int16 (int(value)) # S16
+ elif typecode == 18: codec.write_int32 (int(value)) # S32
+ elif typecode == 19: codec.write_int64 (int(value)) # S64
+ elif typecode == 20: value._encodeUnmanaged(codec) # OBJECT
+ elif typecode == 15: codec.write_map (value) # FTABLE
+ elif typecode == 21: # List
+ sc = Codec()
+ self._encodeValue(sc, len(value), 3)
+ for o in value:
+ ltype=self.encoding(o)
+ self._encodeValue(sc,ltype,1)
+ self._encodeValue(sc, o, ltype)
+ codec.write_vbin32(sc.encoded)
+ elif typecode == 22: # Array
+ sc = Codec()
+ self._encodeValue(sc, len(value), 3)
+ if len(value) > 0:
+ ltype = self.encoding(value[0])
+ self._encodeValue(sc,ltype,1)
+ for o in value:
+ self._encodeValue(sc, o, ltype)
+ codec.write_vbin32(sc.encoded)
+ else:
+ raise ValueError ("Invalid type code: %d" % typecode)
+
+ def encoding(self, value):
+ return self._encoding(value.__class__)
+
+ def _encoding(self, klass):
+ if Session.ENCODINGS.has_key(klass):
+ return self.ENCODINGS[klass]
+ for base in klass.__bases__:
+ result = self._encoding(base, obj)
+ if result != None:
+ return result
+
+ def _displayValue(self, value, typecode):
+ """ """
+ if typecode == 1: return unicode(value)
+ elif typecode == 2: return unicode(value)
+ elif typecode == 3: return unicode(value)
+ elif typecode == 4: return unicode(value)
+ elif typecode == 6: return value
+ elif typecode == 7: return value
+ elif typecode == 8: return unicode(strftime("%c", gmtime(value / 1000000000)))
+ elif typecode == 9: return unicode(value)
+ elif typecode == 10: return unicode(value.__repr__())
+ elif typecode == 11:
+ if value: return u"T"
+ else: return u"F"
+ elif typecode == 12: return unicode(value)
+ elif typecode == 13: return unicode(value)
+ elif typecode == 14: return unicode(value.__repr__())
+ elif typecode == 15: return unicode(value.__repr__())
+ elif typecode == 16: return unicode(value)
+ elif typecode == 17: return unicode(value)
+ elif typecode == 18: return unicode(value)
+ elif typecode == 19: return unicode(value)
+ elif typecode == 20: return unicode(value.__repr__())
+ elif typecode == 21: return unicode(value.__repr__())
+ elif typecode == 22: return unicode(value.__repr__())
+ else:
+ raise ValueError ("Invalid type code: %d" % typecode)
+
+ def _defaultValue(self, stype, broker=None, kwargs={}):
+ """ """
+ typecode = stype.type
+ if typecode == 1: return 0
+ elif typecode == 2: return 0
+ elif typecode == 3: return 0
+ elif typecode == 4: return 0
+ elif typecode == 6: return ""
+ elif typecode == 7: return ""
+ elif typecode == 8: return 0
+ elif typecode == 9: return 0
+ elif typecode == 10: return ObjectId(None)
+ elif typecode == 11: return False
+ elif typecode == 12: return 0.0
+ elif typecode == 13: return 0.0
+ elif typecode == 14: return UUID([0 for i in range(16)])
+ elif typecode == 15: return {}
+ elif typecode == 16: return 0
+ elif typecode == 17: return 0
+ elif typecode == 18: return 0
+ elif typecode == 19: return 0
+ elif typecode == 21: return []
+ elif typecode == 22: return []
+ elif typecode == 20:
+ try:
+ if "classKeys" in kwargs:
+ keyList = kwargs["classKeys"]
+ else:
+ keyList = None
+ classKey = self._bestClassKey(stype.refPackage, stype.refClass, keyList)
+ if classKey:
+ return self.makeObject(classKey, broker, kwargs)
+ except:
+ pass
+ return None
+ else:
+ raise ValueError ("Invalid type code: %d" % typecode)
+
+ def _bestClassKey(self, pname, cname, preferredList):
+ """ """
+ if pname == None or cname == None:
+ if len(preferredList) == 0:
+ return None
+ return preferredList[0]
+ for p in preferredList:
+ if p.getPackageName() == pname and p.getClassName() == cname:
+ return p
+ clist = self.getClasses(pname)
+ for c in clist:
+ if c.getClassName() == cname:
+ return c
+ return None
+
+ def _sendMethodRequest(self, broker, schemaKey, objectId, name, argList):
+ """ This function can be used to send a method request to an object given only the
+ broker, schemaKey, and objectId. This is an uncommon usage pattern as methods are
+ normally invoked on the object itself.
+ """
+ schema = self.getSchema(schemaKey)
+ for method in schema.getMethods():
+ if name == method.name:
+ aIdx = 0
+ sendCodec = Codec()
+ seq = self.seqMgr._reserve((method, False))
+ broker._setHeader(sendCodec, 'M', seq)
+ objectId.encode(sendCodec)
+ schemaKey.encode(sendCodec)
+ sendCodec.write_str8(name)
+
+ count = 0
+ for arg in method.arguments:
+ if arg.dir.find("I") != -1:
+ count += 1
+ if count != len(argList):
+ raise Exception("Incorrect number of arguments: expected %d, got %d" % (count, len(argList)))
+
+ for arg in method.arguments:
+ if arg.dir.find("I") != -1:
+ self._encodeValue(sendCodec, argList[aIdx], arg.type)
+ aIdx += 1
+ smsg = broker._message(sendCodec.encoded, "agent.%d.%d" %
+ (objectId.getBrokerBank(), objectId.getAgentBank()))
+ broker._send(smsg)
+ return seq
+ return None
+
+class Package:
+ """ """
+ def __init__(self, name):
+ self.name = name
+
+class ClassKey:
+ """ A ClassKey uniquely identifies a class from the schema. """
+ def __init__(self, constructor):
+ if type(constructor) == str:
+ # construct from __repr__ string
+ try:
+ self.pname, cls = constructor.split(":")
+ self.cname, hsh = cls.split("(")
+ hsh = hsh.strip(")")
+ hexValues = hsh.split("-")
+ h0 = int(hexValues[0], 16)
+ h1 = int(hexValues[1], 16)
+ h2 = int(hexValues[2], 16)
+ h3 = int(hexValues[3], 16)
+ self.hash = struct.pack("!LLLL", h0, h1, h2, h3)
+ except:
+ raise Exception("Invalid ClassKey format")
+ else:
+ # construct from codec
+ codec = constructor
+ self.pname = str(codec.read_str8())
+ self.cname = str(codec.read_str8())
+ self.hash = codec.read_bin128()
+
+ def encode(self, codec):
+ codec.write_str8(self.pname)
+ codec.write_str8(self.cname)
+ codec.write_bin128(self.hash)
+
+ def getPackageName(self):
+ return self.pname
+
+ def getClassName(self):
+ return self.cname
+
+ def getHash(self):
+ return self.hash
+
+ def getHashString(self):
+ return "%08x-%08x-%08x-%08x" % struct.unpack ("!LLLL", self.hash)
+
+ def getPackageKey(self):
+ return (self.cname, self.hash)
+
+ def __repr__(self):
+ return self.pname + ":" + self.cname + "(" + self.getHashString() + ")"
+
+class SchemaClass:
+ """ """
+ CLASS_KIND_TABLE = 1
+ CLASS_KIND_EVENT = 2
+
+ def __init__(self, kind, key, codec, session):
+ self.kind = kind
+ self.classKey = key
+ self.properties = []
+ self.statistics = []
+ self.methods = []
+ self.arguments = []
+ self.session = session
+
+ hasSupertype = 0 #codec.read_uint8()
+ if self.kind == self.CLASS_KIND_TABLE:
+ propCount = codec.read_uint16()
+ statCount = codec.read_uint16()
+ methodCount = codec.read_uint16()
+ if hasSupertype == 1:
+ self.superTypeKey = ClassKey(codec)
+ else:
+ self.superTypeKey = None ;
+ for idx in range(propCount):
+ self.properties.append(SchemaProperty(codec))
+ for idx in range(statCount):
+ self.statistics.append(SchemaStatistic(codec))
+ for idx in range(methodCount):
+ self.methods.append(SchemaMethod(codec))
+
+ elif self.kind == self.CLASS_KIND_EVENT:
+ argCount = codec.read_uint16()
+ if (hasSupertype):
+ self.superTypeKey = ClassKey(codec)
+ else:
+ self.superTypeKey = None ;
+ for idx in range(argCount):
+ self.arguments.append(SchemaArgument(codec, methodArg=False))
+
+ def __repr__(self):
+ if self.kind == self.CLASS_KIND_TABLE:
+ kindStr = "Table"
+ elif self.kind == self.CLASS_KIND_EVENT:
+ kindStr = "Event"
+ else:
+ kindStr = "Unsupported"
+ result = "%s Class: %s " % (kindStr, self.classKey.__repr__())
+ return result
+
+ def getKey(self):
+ """ Return the class-key for this class. """
+ return self.classKey
+
+ def getProperties(self):
+ """ Return the list of properties for the class. """
+ if (self.superTypeKey == None):
+ return self.properties
+ else:
+ return self.properties + self.session.getSchema(self.superTypeKey).getProperties()
+
+ def getStatistics(self):
+ """ Return the list of statistics for the class. """
+ if (self.superTypeKey == None):
+ return self.statistics
+ else:
+ return self.statistics + self.session.getSchema(self.superTypeKey).getStatistics()
+
+ def getMethods(self):
+ """ Return the list of methods for the class. """
+ if (self.superTypeKey == None):
+ return self.methods
+ else:
+ return self.methods + self.session.getSchema(self.superTypeKey).getMethods()
+
+ def getArguments(self):
+ """ Return the list of events for the class. """
+ """ Return the list of methods for the class. """
+ if (self.superTypeKey == None):
+ return self.arguments
+ else:
+ return self.arguments + self.session.getSchema(self.superTypeKey).getArguments()
+
+class SchemaProperty:
+ """ """
+ def __init__(self, codec):
+ map = codec.read_map()
+ self.name = str(map["name"])
+ self.type = map["type"]
+ self.access = str(map["access"])
+ self.index = map["index"] != 0
+ self.optional = map["optional"] != 0
+ self.refPackage = None
+ self.refClass = None
+ self.unit = None
+ self.min = None
+ self.max = None
+ self.maxlen = None
+ self.desc = None
+
+ for key, value in map.items():
+ if key == "unit" : self.unit = value
+ elif key == "min" : self.min = value
+ elif key == "max" : self.max = value
+ elif key == "maxlen" : self.maxlen = value
+ elif key == "desc" : self.desc = value
+ elif key == "refPackage" : self.refPackage = value
+ elif key == "refClass" : self.refClass = value
+
+ def __repr__(self):
+ return self.name
+
+class SchemaStatistic:
+ """ """
+ def __init__(self, codec):
+ map = codec.read_map()
+ self.name = str(map["name"])
+ self.type = map["type"]
+ self.unit = None
+ self.desc = None
+
+ for key, value in map.items():
+ if key == "unit" : self.unit = value
+ elif key == "desc" : self.desc = value
+
+ def __repr__(self):
+ return self.name
+
+class SchemaMethod:
+ """ """
+ def __init__(self, codec):
+ map = codec.read_map()
+ self.name = str(map["name"])
+ argCount = map["argCount"]
+ if "desc" in map:
+ self.desc = map["desc"]
+ else:
+ self.desc = None
+ self.arguments = []
+
+ for idx in range(argCount):
+ self.arguments.append(SchemaArgument(codec, methodArg=True))
+
+ def __repr__(self):
+ result = self.name + "("
+ first = True
+ for arg in self.arguments:
+ if arg.dir.find("I") != -1:
+ if first:
+ first = False
+ else:
+ result += ", "
+ result += arg.name
+ result += ")"
+ return result
+
+class SchemaArgument:
+ """ """
+ def __init__(self, codec, methodArg):
+ map = codec.read_map()
+ self.name = str(map["name"])
+ self.type = map["type"]
+ if methodArg:
+ self.dir = str(map["dir"]).upper()
+ self.unit = None
+ self.min = None
+ self.max = None
+ self.maxlen = None
+ self.desc = None
+ self.default = None
+ self.refPackage = None
+ self.refClass = None
+
+ for key, value in map.items():
+ if key == "unit" : self.unit = value
+ elif key == "min" : self.min = value
+ elif key == "max" : self.max = value
+ elif key == "maxlen" : self.maxlen = value
+ elif key == "desc" : self.desc = value
+ elif key == "default" : self.default = value
+ elif key == "refPackage" : self.refPackage = value
+ elif key == "refClass" : self.refClass = value
+
+class ObjectId:
+ """ Object that represents QMF object identifiers """
+ def __init__(self, codec, first=0, second=0):
+ if codec:
+ self.first = codec.read_uint64()
+ self.second = codec.read_uint64()
+ else:
+ self.first = first
+ self.second = second
+
+ def __cmp__(self, other):
+ if other == None or not isinstance(other, ObjectId) :
+ return 1
+ if self.first < other.first:
+ return -1
+ if self.first > other.first:
+ return 1
+ if self.second < other.second:
+ return -1
+ if self.second > other.second:
+ return 1
+ return 0
+
+ def __repr__(self):
+ return "%d-%d-%d-%d-%d" % (self.getFlags(), self.getSequence(),
+ self.getBrokerBank(), self.getAgentBank(), self.getObject())
+
+ def index(self):
+ return (self.first, self.second)
+
+ def getFlags(self):
+ return (self.first & 0xF000000000000000) >> 60
+
+ def getSequence(self):
+ return (self.first & 0x0FFF000000000000) >> 48
+
+ def getBrokerBank(self):
+ return (self.first & 0x0000FFFFF0000000) >> 28
+
+ def getAgentBank(self):
+ return self.first & 0x000000000FFFFFFF
+
+ def getObject(self):
+ return self.second
+
+ def isDurable(self):
+ return self.getSequence() == 0
+
+ def encode(self, codec):
+ codec.write_uint64(self.first)
+ codec.write_uint64(self.second)
+
+ def __hash__(self):
+ return (self.first, self.second).__hash__()
+
+ def __eq__(self, other):
+ return (self.first, self.second).__eq__(other)
+
+class MethodResult(object):
+ """ """
+ def __init__(self, status, text, outArgs):
+ """ """
+ self.status = status
+ self.text = text
+ self.outArgs = outArgs
+
+ def __getattr__(self, name):
+ if name in self.outArgs:
+ return self.outArgs[name]
+
+ def __repr__(self):
+ return "%s (%d) - %s" % (self.text, self.status, self.outArgs)
+
+class ManagedConnection(Thread):
+ """ Thread class for managing a connection. """
+ DELAY_MIN = 1
+ DELAY_MAX = 128
+ DELAY_FACTOR = 2
+
+ def __init__(self, broker):
+ Thread.__init__(self)
+ self.broker = broker
+ self.cv = Condition()
+ self.canceled = False
+
+ def stop(self):
+ """ Tell this thread to stop running and return. """
+ try:
+ self.cv.acquire()
+ self.canceled = True
+ self.cv.notify()
+ finally:
+ self.cv.release()
+
+ def disconnected(self):
+ """ Notify the thread that the connection was lost. """
+ try:
+ self.cv.acquire()
+ self.cv.notify()
+ finally:
+ self.cv.release()
+
+ def run(self):
+ """ Main body of the running thread. """
+ delay = self.DELAY_MIN
+ while True:
+ try:
+ self.broker._tryToConnect()
+ try:
+ self.cv.acquire()
+ while (not self.canceled) and self.broker.connected:
+ self.cv.wait()
+ if self.canceled:
+ return
+ delay = self.DELAY_MIN
+ finally:
+ self.cv.release()
+ except socket.error:
+ if delay < self.DELAY_MAX:
+ delay *= self.DELAY_FACTOR
+ except SessionDetached:
+ if delay < self.DELAY_MAX:
+ delay *= self.DELAY_FACTOR
+ except Closed:
+ if delay < self.DELAY_MAX:
+ delay *= self.DELAY_FACTOR
+
+ try:
+ self.cv.acquire()
+ self.cv.wait(delay)
+ if self.canceled:
+ return
+ finally:
+ self.cv.release()
+
+class Broker:
+ """ This object represents a connection (or potential connection) to a QMF broker. """
+ SYNC_TIME = 60
+ nextSeq = 1
+
+ def __init__(self, session, host, port, authMechs, authUser, authPass, ssl=False, connTimeout=None):
+ self.session = session
+ self.host = host
+ self.port = port
+ self.mechanisms = authMechs
+ self.ssl = ssl
+ self.connTimeout = connTimeout
+ self.authUser = authUser
+ self.authPass = authPass
+ self.cv = Condition()
+ self.error = None
+ self.brokerId = None
+ self.connected = False
+ self.amqpSessionId = "%s.%d.%d" % (platform.uname()[1], os.getpid(), Broker.nextSeq)
+ Broker.nextSeq += 1
+ if self.session.manageConnections:
+ self.thread = ManagedConnection(self)
+ self.thread.start()
+ else:
+ self.thread = None
+ self._tryToConnect()
+
+ def isConnected(self):
+ """ Return True if there is an active connection to the broker. """
+ return self.connected
+
+ def getError(self):
+ """ Return the last error message seen while trying to connect to the broker. """
+ return self.error
+
+ def getBrokerId(self):
+ """ Get broker's unique identifier (UUID) """
+ return self.brokerId
+
+ def getBrokerBank(self):
+ """ Return the broker-bank value. This is the value that the broker assigns to
+ objects within its control. This value appears as a field in the ObjectId
+ of objects created by agents controlled by this broker. """
+ return 1
+
+ def getAgent(self, brokerBank, agentBank):
+ """ Return the agent object associated with a particular broker and agent bank value."""
+ bankKey = (brokerBank, agentBank)
+ if bankKey in self.agents:
+ return self.agents[bankKey]
+ return None
+
+ def getSessionId(self):
+ """ Get the identifier of the AMQP session to the broker """
+ return self.amqpSessionId
+
+ def getAgents(self):
+ """ Get the list of agents reachable via this broker """
+ return self.agents.values()
+
+ def getAmqpSession(self):
+ """ Get the AMQP session object for this connected broker. """
+ return self.amqpSession
+
+ def getUrl(self):
+ """ """
+ return "%s:%d" % (self.host, self.port)
+
+ def getFullUrl(self, noAuthIfGuestDefault=True):
+ """ """
+ ssl = ""
+ if self.ssl:
+ ssl = "s"
+ auth = "%s/%s@" % (self.authUser, self.authPass)
+ if self.authUser == "" or \
+ (noAuthIfGuestDefault and self.authUser == "guest" and self.authPass == "guest"):
+ auth = ""
+ return "amqp%s://%s%s:%d" % (ssl, auth, self.host, self.port or 5672)
+
+ def __repr__(self):
+ if self.connected:
+ return "Broker connected at: %s" % self.getUrl()
+ else:
+ return "Disconnected Broker"
+
+ def _tryToConnect(self):
+ try:
+ self.agents = {}
+ self.agents[(1,0)] = Agent(self, 0, "BrokerAgent")
+ self.topicBound = False
+ self.syncInFlight = False
+ self.syncRequest = 0
+ self.syncResult = None
+ self.reqsOutstanding = 1
+
+ sock = connect(self.host, self.port)
+ sock.settimeout(5)
+ oldTimeout = sock.gettimeout()
+ sock.settimeout(self.connTimeout)
+ if self.ssl:
+ connSock = ssl(sock)
+ else:
+ connSock = sock
+ self.conn = Connection(connSock, username=self.authUser, password=self.authPass,
+ mechanism = self.mechanisms, host=self.host, service="qpidd")
+ def aborted():
+ raise Timeout("Waiting for connection to be established with broker")
+ oldAborted = self.conn.aborted
+ self.conn.aborted = aborted
+ self.conn.start()
+ sock.settimeout(oldTimeout)
+ self.conn.aborted = oldAborted
+
+ self.replyName = "reply-%s" % self.amqpSessionId
+ self.amqpSession = self.conn.session(self.amqpSessionId)
+ self.amqpSession.auto_sync = True
+ self.amqpSession.queue_declare(queue=self.replyName, exclusive=True, auto_delete=True)
+ self.amqpSession.exchange_bind(exchange="amq.direct",
+ queue=self.replyName, binding_key=self.replyName)
+ self.amqpSession.message_subscribe(queue=self.replyName, destination="rdest",
+ accept_mode=self.amqpSession.accept_mode.none,
+ acquire_mode=self.amqpSession.acquire_mode.pre_acquired)
+ self.amqpSession.incoming("rdest").listen(self._replyCb, self._exceptionCb)
+ self.amqpSession.message_set_flow_mode(destination="rdest", flow_mode=1)
+ self.amqpSession.message_flow(destination="rdest", unit=0, value=0xFFFFFFFFL)
+ self.amqpSession.message_flow(destination="rdest", unit=1, value=0xFFFFFFFFL)
+
+ self.topicName = "topic-%s" % self.amqpSessionId
+ self.amqpSession.queue_declare(queue=self.topicName, exclusive=True, auto_delete=True)
+ self.amqpSession.message_subscribe(queue=self.topicName, destination="tdest",
+ accept_mode=self.amqpSession.accept_mode.none,
+ acquire_mode=self.amqpSession.acquire_mode.pre_acquired)
+ self.amqpSession.incoming("tdest").listen(self._replyCb)
+ self.amqpSession.message_set_flow_mode(destination="tdest", flow_mode=1)
+ self.amqpSession.message_flow(destination="tdest", unit=0, value=0xFFFFFFFFL)
+ self.amqpSession.message_flow(destination="tdest", unit=1, value=0xFFFFFFFFL)
+
+ self.connected = True
+ self.session._handleBrokerConnect(self)
+
+ codec = Codec()
+ self._setHeader(codec, 'B')
+ msg = self._message(codec.encoded)
+ self._send(msg)
+
+ except socket.error, e:
+ self.error = "Socket Error %s - %s" % (e.__class__.__name__, e)
+ raise
+ except Closed, e:
+ self.error = "Connect Failed %s - %s" % (e.__class__.__name__, e)
+ raise
+ except ConnectionFailed, e:
+ self.error = "Connect Failed %s - %s" % (e.__class__.__name__, e)
+ raise
+
+ def _updateAgent(self, obj):
+ bankKey = (obj.brokerBank, obj.agentBank)
+ if obj._deleteTime == 0:
+ if bankKey not in self.agents:
+ agent = Agent(self, obj.agentBank, obj.label)
+ self.agents[bankKey] = agent
+ if self.session.console != None:
+ self.session.console.newAgent(agent)
+ else:
+ agent = self.agents.pop(bankKey, None)
+ if agent != None and self.session.console != None:
+ self.session.console.delAgent(agent)
+
+ def _setHeader(self, codec, opcode, seq=0):
+ """ Compose the header of a management message. """
+ codec.write_uint8(ord('A'))
+ codec.write_uint8(ord('M'))
+ codec.write_uint8(ord('2'))
+ codec.write_uint8(ord(opcode))
+ codec.write_uint32(seq)
+
+ def _checkHeader(self, codec):
+ """ Check the header of a management message and extract the opcode and class. """
+ try:
+ octet = chr(codec.read_uint8())
+ if octet != 'A':
+ return None, None
+ octet = chr(codec.read_uint8())
+ if octet != 'M':
+ return None, None
+ octet = chr(codec.read_uint8())
+ if octet != '2':
+ return None, None
+ opcode = chr(codec.read_uint8())
+ seq = codec.read_uint32()
+ return opcode, seq
+ except:
+ return None, None
+
+ def _message (self, body, routing_key="broker", ttl=None):
+ dp = self.amqpSession.delivery_properties()
+ dp.routing_key = routing_key
+ if ttl:
+ dp.ttl = ttl
+ mp = self.amqpSession.message_properties()
+ mp.content_type = "x-application/qmf"
+ mp.user_id = self.authUser
+ mp.reply_to = self.amqpSession.reply_to("amq.direct", self.replyName)
+ return Message(dp, mp, body)
+
+ def _send(self, msg, dest="qpid.management"):
+ self.amqpSession.message_transfer(destination=dest, message=msg)
+
+ def _shutdown(self):
+ if self.thread:
+ self.thread.stop()
+ self.thread.join()
+ if self.connected:
+ self.amqpSession.incoming("rdest").stop()
+ if self.session.console != None:
+ self.amqpSession.incoming("tdest").stop()
+ self.amqpSession.close()
+ self.conn.close()
+ self.connected = False
+
+ def _waitForStable(self):
+ try:
+ self.cv.acquire()
+ if not self.connected:
+ return
+ if self.reqsOutstanding == 0:
+ return
+ self.syncInFlight = True
+ starttime = time()
+ while self.reqsOutstanding != 0:
+ self.cv.wait(self.SYNC_TIME)
+ if time() - starttime > self.SYNC_TIME:
+ raise RuntimeError("Timed out waiting for broker to synchronize")
+ finally:
+ self.cv.release()
+
+ def _incOutstanding(self):
+ try:
+ self.cv.acquire()
+ self.reqsOutstanding += 1
+ finally:
+ self.cv.release()
+
+ def _decOutstanding(self):
+ try:
+ self.cv.acquire()
+ self.reqsOutstanding -= 1
+ if self.reqsOutstanding == 0 and not self.topicBound:
+ self.topicBound = True
+ for key in self.session.bindingKeyList:
+ self.amqpSession.exchange_bind(exchange="qpid.management",
+ queue=self.topicName, binding_key=key)
+ if self.reqsOutstanding == 0 and self.syncInFlight:
+ self.syncInFlight = False
+ self.cv.notify()
+ finally:
+ self.cv.release()
+
+ def _replyCb(self, msg):
+ codec = Codec(msg.body)
+ while True:
+ opcode, seq = self._checkHeader(codec)
+ if opcode == None: return
+ if opcode == 'b': self.session._handleBrokerResp (self, codec, seq)
+ elif opcode == 'p': self.session._handlePackageInd (self, codec, seq)
+ elif opcode == 'z': self.session._handleCommandComplete (self, codec, seq)
+ elif opcode == 'q': self.session._handleClassInd (self, codec, seq)
+ elif opcode == 'm': self.session._handleMethodResp (self, codec, seq)
+ elif opcode == 'h': self.session._handleHeartbeatInd (self, codec, seq, msg)
+ elif opcode == 'e': self.session._handleEventInd (self, codec, seq)
+ elif opcode == 's': self.session._handleSchemaResp (self, codec, seq)
+ elif opcode == 'c': self.session._handleContentInd (self, codec, seq, prop=True)
+ elif opcode == 'i': self.session._handleContentInd (self, codec, seq, stat=True)
+ elif opcode == 'g': self.session._handleContentInd (self, codec, seq, prop=True, stat=True)
+
+ def _exceptionCb(self, data):
+ self.connected = False
+ self.error = data
+ try:
+ self.cv.acquire()
+ if self.syncInFlight:
+ self.cv.notify()
+ finally:
+ self.cv.release()
+ self.session._handleError(self.error)
+ self.session._handleBrokerDisconnect(self)
+ if self.thread:
+ self.thread.disconnected()
+
+class Agent:
+ """ """
+ def __init__(self, broker, agentBank, label):
+ self.broker = broker
+ self.brokerBank = broker.getBrokerBank()
+ self.agentBank = agentBank
+ self.label = label
+
+ def __repr__(self):
+ return "Agent at bank %d.%d (%s)" % (self.brokerBank, self.agentBank, self.label)
+
+ def getBroker(self):
+ return self.broker
+
+ def getBrokerBank(self):
+ return self.brokerBank
+
+ def getAgentBank(self):
+ return self.agentBank
+
+class Event:
+ """ """
+ def __init__(self, session, broker, codec):
+ self.session = session
+ self.broker = broker
+ self.classKey = ClassKey(codec)
+ self.timestamp = codec.read_int64()
+ self.severity = codec.read_uint8()
+ self.schema = None
+ pname = self.classKey.getPackageName()
+ pkey = self.classKey.getPackageKey()
+ if pname in session.packages:
+ if pkey in session.packages[pname]:
+ self.schema = session.packages[pname][pkey]
+ self.arguments = {}
+ for arg in self.schema.arguments:
+ self.arguments[arg.name] = session._decodeValue(codec, arg.type, broker)
+
+ def __repr__(self):
+ if self.schema == None:
+ return "<uninterpretable>"
+ out = strftime("%c", gmtime(self.timestamp / 1000000000))
+ out += " " + self._sevName() + " " + self.classKey.getPackageName() + ":" + self.classKey.getClassName()
+ out += " broker=" + self.broker.getUrl()
+ for arg in self.schema.arguments:
+ disp = self.session._displayValue(self.arguments[arg.name], arg.type).encode("utf8")
+ if " " in disp:
+ disp = "\"" + disp + "\""
+ out += " " + arg.name + "=" + disp
+ return out
+
+ def _sevName(self):
+ if self.severity == 0 : return "EMER "
+ if self.severity == 1 : return "ALERT"
+ if self.severity == 2 : return "CRIT "
+ if self.severity == 3 : return "ERROR"
+ if self.severity == 4 : return "WARN "
+ if self.severity == 5 : return "NOTIC"
+ if self.severity == 6 : return "INFO "
+ if self.severity == 7 : return "DEBUG"
+ return "INV-%d" % self.severity
+
+ def getClassKey(self):
+ return self.classKey
+
+ def getArguments(self):
+ return self.arguments
+
+ def getTimestamp(self):
+ return self.timestamp
+
+ def getName(self):
+ return self.name
+
+ def getSchema(self):
+ return self.schema
+
+class SequenceManager:
+ """ Manage sequence numbers for asynchronous method calls """
+ def __init__(self):
+ self.lock = Lock()
+ self.sequence = 0
+ self.pending = {}
+
+ def _reserve(self, data):
+ """ Reserve a unique sequence number """
+ try:
+ self.lock.acquire()
+ result = self.sequence
+ self.sequence = self.sequence + 1
+ self.pending[result] = data
+ finally:
+ self.lock.release()
+ return result
+
+ def _release(self, seq):
+ """ Release a reserved sequence number """
+ data = None
+ try:
+ self.lock.acquire()
+ if seq in self.pending:
+ data = self.pending[seq]
+ del self.pending[seq]
+ finally:
+ self.lock.release()
+ return data
+
+
+class DebugConsole(Console):
+ """ """
+ def brokerConnected(self, broker):
+ print "brokerConnected:", broker
+
+ def brokerDisconnected(self, broker):
+ print "brokerDisconnected:", broker
+
+ def newPackage(self, name):
+ print "newPackage:", name
+
+ def newClass(self, kind, classKey):
+ print "newClass:", kind, classKey
+
+ def newAgent(self, agent):
+ print "newAgent:", agent
+
+ def delAgent(self, agent):
+ print "delAgent:", agent
+
+ def objectProps(self, broker, record):
+ print "objectProps:", record
+
+ def objectStats(self, broker, record):
+ print "objectStats:", record
+
+ def event(self, broker, event):
+ print "event:", event
+
+ def heartbeat(self, agent, timestamp):
+ print "heartbeat:", agent
+
+ def brokerInfo(self, broker):
+ print "brokerInfo:", broker
+
diff --git a/python/qpid-python-test b/python/qpid-python-test
new file mode 100755
index 0000000000..b569020368
--- /dev/null
+++ b/python/qpid-python-test
@@ -0,0 +1,575 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# TODO: summarize, test harness preconditions (e.g. broker is alive)
+
+import logging, optparse, os, struct, sys, traceback, types
+from fnmatch import fnmatchcase as match
+from getopt import GetoptError
+from logging import getLogger, StreamHandler, Formatter, Filter, \
+ WARN, DEBUG, ERROR
+from qpid.harness import Skipped
+from qpid.util import URL
+
+levels = {
+ "DEBUG": DEBUG,
+ "WARN": WARN,
+ "ERROR": ERROR
+ }
+
+sorted_levels = [(v, k) for k, v in levels.items()]
+sorted_levels.sort()
+sorted_levels = [v for k, v in sorted_levels]
+
+parser = optparse.OptionParser(usage="usage: %prog [options] PATTERN ...",
+ description="Run tests matching the specified PATTERNs.")
+parser.add_option("-l", "--list", action="store_true", default=False,
+ help="list tests instead of executing them")
+parser.add_option("-b", "--broker", default="localhost",
+ help="run tests against BROKER (default %default)")
+parser.add_option("-f", "--log-file", metavar="FILE", help="log output to FILE")
+parser.add_option("-v", "--log-level", metavar="LEVEL", default="WARN",
+ help="only display log messages of LEVEL or higher severity: "
+ "%s (default %%default)" % ", ".join(sorted_levels))
+parser.add_option("-c", "--log-category", metavar="CATEGORY", action="append",
+ dest="log_categories", default=[],
+ help="log only categories matching CATEGORY pattern")
+parser.add_option("-m", "--module", action="append", default=[],
+ dest="modules", help="add module to test search path")
+parser.add_option("-i", "--ignore", action="append", default=[],
+ help="ignore tests matching IGNORE pattern")
+parser.add_option("-I", "--ignore-file", metavar="IFILE", action="append",
+ default=[],
+ help="ignore tests matching patterns in IFILE")
+parser.add_option("-H", "--halt-on-error", action="store_true", default=False,
+ dest="hoe", help="halt if an error is encountered")
+parser.add_option("-D", "--define", metavar="DEFINE", dest="defines",
+ action="append", default=[], help="define test parameters")
+
+class Config:
+
+ def __init__(self):
+ self.broker = URL("localhost")
+ self.defines = {}
+ self.log_file = None
+ self.log_level = WARN
+ self.log_categories = []
+
+opts, args = parser.parse_args()
+
+includes = []
+excludes = ["*__*__"]
+config = Config()
+list_only = opts.list
+config.broker = URL(opts.broker)
+for d in opts.defines:
+ try:
+ idx = d.index("=")
+ name = d[:idx]
+ value = d[idx+1:]
+ config.defines[name] = value
+ except ValueError:
+ config.defines[d] = None
+config.log_file = opts.log_file
+config.log_level = levels[opts.log_level.upper()]
+config.log_categories = opts.log_categories
+excludes.extend([v.strip() for v in opts.ignore])
+for v in opts.ignore_file:
+ f = open(v)
+ for line in f:
+ line = line.strip()
+ if line.startswith("#"):
+ continue
+ excludes.append(line)
+ f.close()
+
+for a in args:
+ includes.append(a.strip())
+
+if not includes:
+ if opts.modules:
+ includes.append("*")
+ else:
+ includes.extend(["qpid.tests.*", "tests.*", "tests_0-10.*"])
+
+def is_ignored(path):
+ for p in excludes:
+ if match(path, p):
+ return True
+ return False
+
+def is_included(path):
+ if is_ignored(path):
+ return False
+ for p in includes:
+ if match(path, p):
+ return True
+ return False
+
+def is_smart():
+ return sys.stdout.isatty() and os.environ.get("TERM", "dumb") != "dumb"
+
+try:
+ import fcntl, termios
+
+ def width():
+ if is_smart():
+ s = struct.pack("HHHH", 0, 0, 0, 0)
+ fd_stdout = sys.stdout.fileno()
+ x = fcntl.ioctl(fd_stdout, termios.TIOCGWINSZ, s)
+ rows, cols, xpx, ypx = struct.unpack("HHHH", x)
+ return cols
+ else:
+ try:
+ return int(os.environ.get("COLUMNS", "80"))
+ except ValueError:
+ return 80
+
+ WIDTH = width()
+
+ def resize(sig, frm):
+ global WIDTH
+ WIDTH = width()
+
+ import signal
+ signal.signal(signal.SIGWINCH, resize)
+
+except ImportError:
+ WIDTH = 80
+
+def vt100_attrs(*attrs):
+ return "\x1B[%sm" % ";".join(map(str, attrs))
+
+vt100_reset = vt100_attrs(0)
+
+KEYWORDS = {"pass": (32,),
+ "skip": (33,),
+ "fail": (31,),
+ "start": (34,),
+ "total": (34,),
+ "ignored": (33,),
+ "selected": (34,)}
+
+COLORIZE = is_smart()
+
+def colorize_word(word, text=None):
+ if text is None:
+ text = word
+ return colorize(text, *KEYWORDS.get(word, ()))
+
+def colorize(text, *attrs):
+ if attrs and COLORIZE:
+ return "%s%s%s" % (vt100_attrs(*attrs), text, vt100_reset)
+ else:
+ return text
+
+def indent(text):
+ lines = text.split("\n")
+ return " %s" % "\n ".join(lines)
+
+class Interceptor:
+
+ def __init__(self):
+ self.newline = False
+ self.indent = False
+ self.passthrough = True
+ self.dirty = False
+ self.last = None
+
+ def begin(self):
+ self.newline = True
+ self.indent = True
+ self.passthrough = False
+ self.dirty = False
+ self.last = None
+
+ def reset(self):
+ self.newline = False
+ self.indent = False
+ self.passthrough = True
+
+class StreamWrapper:
+
+ def __init__(self, interceptor, stream, prefix=" "):
+ self.interceptor = interceptor
+ self.stream = stream
+ self.prefix = prefix
+
+ def fileno(self):
+ return self.stream.fileno()
+
+ def isatty(self):
+ return self.stream.isatty()
+
+ def write(self, s):
+ if self.interceptor.passthrough:
+ self.stream.write(s)
+ return
+
+ if s:
+ self.interceptor.dirty = True
+
+ if self.interceptor.newline:
+ self.interceptor.newline = False
+ self.stream.write(" %s\n" % colorize_word("start"))
+ self.interceptor.indent = True
+ if self.interceptor.indent:
+ self.stream.write(self.prefix)
+ if s.endswith("\n"):
+ s = s.replace("\n", "\n%s" % self.prefix)[:-2]
+ self.interceptor.indent = True
+ else:
+ s = s.replace("\n", "\n%s" % self.prefix)
+ self.interceptor.indent = False
+ self.stream.write(s)
+
+ if s:
+ self.interceptor.last = s[-1]
+
+ def flush(self):
+ self.stream.flush()
+
+interceptor = Interceptor()
+
+out_wrp = StreamWrapper(interceptor, sys.stdout)
+err_wrp = StreamWrapper(interceptor, sys.stderr)
+
+out = sys.stdout
+err = sys.stderr
+sys.stdout = out_wrp
+sys.stderr = err_wrp
+
+class PatternFilter(Filter):
+
+ def __init__(self, *patterns):
+ Filter.__init__(self, patterns)
+ self.patterns = patterns
+
+ def filter(self, record):
+ if not self.patterns:
+ return True
+ for p in self.patterns:
+ if match(record.name, p):
+ return True
+ return False
+
+root = getLogger()
+handler = StreamHandler(sys.stdout)
+filter = PatternFilter(*config.log_categories)
+handler.addFilter(filter)
+handler.setFormatter(Formatter("%(asctime)s %(levelname)s %(message)s"))
+root.addHandler(handler)
+root.setLevel(WARN)
+
+log = getLogger("qpid.test")
+
+PASS = "pass"
+SKIP = "skip"
+FAIL = "fail"
+
+class Runner:
+
+ def __init__(self):
+ self.exceptions = []
+ self.skip = False
+
+ def passed(self):
+ return not self.exceptions
+
+ def skipped(self):
+ return self.skip
+
+ def failed(self):
+ return self.exceptions and not self.skip
+
+ def halt(self):
+ return self.exceptions or self.skip
+
+ def run(self, name, phase):
+ try:
+ phase()
+ except KeyboardInterrupt:
+ raise
+ except:
+ exi = sys.exc_info()
+ if issubclass(exi[0], Skipped):
+ self.skip = True
+ self.exceptions.append((name, exi))
+
+ def status(self):
+ if self.passed():
+ return PASS
+ elif self.skipped():
+ return SKIP
+ elif self.failed():
+ return FAIL
+ else:
+ return None
+
+ def print_exceptions(self):
+ for name, info in self.exceptions:
+ if issubclass(info[0], Skipped):
+ print indent("".join(traceback.format_exception_only(*info[:2]))).rstrip()
+ else:
+ print "Error during %s:" % name
+ print indent("".join(traceback.format_exception(*info))).rstrip()
+
+ST_WIDTH = 8
+
+def run_test(name, test, config):
+ patterns = filter.patterns
+ level = root.level
+ filter.patterns = config.log_categories
+ root.setLevel(config.log_level)
+
+ parts = name.split(".")
+ line = None
+ output = ""
+ for part in parts:
+ if line:
+ if len(line) + len(part) >= (WIDTH - ST_WIDTH - 1):
+ output += "%s. \\\n" % line
+ line = " %s" % part
+ else:
+ line = "%s.%s" % (line, part)
+ else:
+ line = part
+
+ if line:
+ output += "%s %s" % (line, (((WIDTH - ST_WIDTH) - len(line))*"."))
+ sys.stdout.write(output)
+ sys.stdout.flush()
+ interceptor.begin()
+ try:
+ runner = test()
+ finally:
+ interceptor.reset()
+ if interceptor.dirty:
+ if interceptor.last != "\n":
+ sys.stdout.write("\n")
+ sys.stdout.write(output)
+ print " %s" % colorize_word(runner.status())
+ if runner.failed() or runner.skipped():
+ runner.print_exceptions()
+ root.setLevel(level)
+ filter.patterns = patterns
+ return runner.status()
+
+class FunctionTest:
+
+ def __init__(self, test):
+ self.test = test
+
+ def name(self):
+ return "%s.%s" % (self.test.__module__, self.test.__name__)
+
+ def run(self):
+ return run_test(self.name(), self._run, config)
+
+ def _run(self):
+ runner = Runner()
+ runner.run("test", lambda: self.test(config))
+ return runner
+
+ def __repr__(self):
+ return "FunctionTest(%r)" % self.test
+
+class MethodTest:
+
+ def __init__(self, cls, method):
+ self.cls = cls
+ self.method = method
+
+ def name(self):
+ return "%s.%s.%s" % (self.cls.__module__, self.cls.__name__, self.method)
+
+ def run(self):
+ return run_test(self.name(), self._run, config)
+
+ def _run(self):
+ runner = Runner()
+ inst = self.cls(self.method)
+ test = getattr(inst, self.method)
+
+ if hasattr(inst, "configure"):
+ runner.run("configure", lambda: inst.configure(config))
+ if runner.halt(): return runner
+ if hasattr(inst, "setUp"):
+ runner.run("setup", inst.setUp)
+ if runner.halt(): return runner
+ elif hasattr(inst, "setup"):
+ runner.run("setup", inst.setup)
+ if runner.halt(): return runner
+
+ runner.run("test", test)
+
+ if hasattr(inst, "tearDown"):
+ runner.run("teardown", inst.tearDown)
+ elif hasattr(inst, "teardown"):
+ runner.run("teardown", inst.teardown)
+
+ return runner
+
+ def __repr__(self):
+ return "MethodTest(%r, %r)" % (self.cls, self.method)
+
+class PatternMatcher:
+
+ def __init__(self, *patterns):
+ self.patterns = patterns
+
+ def matches(self, name):
+ for p in self.patterns:
+ if match(name, p):
+ return True
+ return False
+
+class FunctionScanner(PatternMatcher):
+
+ def inspect(self, obj):
+ return type(obj) == types.FunctionType and self.matches(name)
+
+ def descend(self, func):
+ # the None is required for older versions of python
+ return; yield None
+
+ def extract(self, func):
+ yield FunctionTest(func)
+
+class ClassScanner(PatternMatcher):
+
+ def inspect(self, obj):
+ return type(obj) in (types.ClassType, types.TypeType) and self.matches(obj.__name__)
+
+ def descend(self, cls):
+ # the None is required for older versions of python
+ return; yield None
+
+ def extract(self, cls):
+ names = dir(cls)
+ names.sort()
+ for name in names:
+ obj = getattr(cls, name)
+ t = type(obj)
+ if t == types.MethodType and name.startswith("test"):
+ yield MethodTest(cls, name)
+
+class ModuleScanner:
+
+ def inspect(self, obj):
+ return type(obj) == types.ModuleType
+
+ def descend(self, obj):
+ names = dir(obj)
+ names.sort()
+ for name in names:
+ yield getattr(obj, name)
+
+ def extract(self, obj):
+ # the None is required for older versions of python
+ return; yield None
+
+class Harness:
+
+ def __init__(self):
+ self.scanners = [
+ ModuleScanner(),
+ ClassScanner("*Test", "*Tests", "*TestCase"),
+ FunctionScanner("test_*")
+ ]
+ self.tests = []
+ self.scanned = []
+
+ def scan(self, *roots):
+ objects = list(roots)
+
+ while objects:
+ obj = objects.pop(0)
+ for s in self.scanners:
+ if s.inspect(obj):
+ self.tests.extend(s.extract(obj))
+ for child in s.descend(obj):
+ if not (child in self.scanned or child in objects):
+ objects.append(child)
+ self.scanned.append(obj)
+
+modules = opts.modules
+if not modules:
+ modules.extend(["qpid.tests", "tests", "tests_0-8", "tests_0-9", "tests_0-10"])
+h = Harness()
+for name in modules:
+ m = __import__(name, None, None, ["dummy"])
+ h.scan(m)
+
+filtered = [t for t in h.tests if is_included(t.name())]
+ignored = [t for t in h.tests if is_ignored(t.name())]
+total = len(filtered) + len(ignored)
+
+passed = 0
+failed = 0
+skipped = 0
+for t in filtered:
+ if list_only:
+ print t.name()
+ else:
+ st = t.run()
+ if st == PASS:
+ passed += 1
+ elif st == SKIP:
+ skipped += 1
+ elif st == FAIL:
+ failed += 1
+ if opts.hoe:
+ break
+
+run = passed + failed
+
+if not list_only:
+ if passed:
+ _pass = "pass"
+ else:
+ _pass = "fail"
+ if failed:
+ outcome = "fail"
+ else:
+ outcome = "pass"
+ if ignored:
+ ign = "ignored"
+ else:
+ ign = "pass"
+ if skipped:
+ skip = "skip"
+ else:
+ skip = "pass"
+ print colorize("Totals:", 1), \
+ colorize_word("total", "%s tests" % total) + ",", \
+ colorize_word(_pass, "%s passed" % passed) + ",", \
+ colorize_word(skip, "%s skipped" % skipped) + ",", \
+ colorize_word(ign, "%s ignored" % len(ignored)) + ",", \
+ colorize_word(outcome, "%s failed" % failed),
+ if opts.hoe and failed > 0:
+ print " -- (halted after %s)" % run
+ else:
+ print
+
+if failed or skipped:
+ sys.exit(1)
+else:
+ sys.exit(0)
diff --git a/python/qpid/address.py b/python/qpid/address.py
new file mode 100644
index 0000000000..6228ac757b
--- /dev/null
+++ b/python/qpid/address.py
@@ -0,0 +1,161 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+import re
+from lexer import Lexicon, LexError
+from parser import Parser, ParseError
+
+l = Lexicon()
+
+LBRACE = l.define("LBRACE", r"\{")
+RBRACE = l.define("RBRACE", r"\}")
+LBRACK = l.define("LBRACK", r"\[")
+RBRACK = l.define("RBRACK", r"\]")
+COLON = l.define("COLON", r":")
+SEMI = l.define("SEMI", r";")
+SLASH = l.define("SLASH", r"/")
+COMMA = l.define("COMMA", r",")
+NUMBER = l.define("NUMBER", r'[+-]?[0-9]*\.?[0-9]+')
+ID = l.define("ID", r'[a-zA-Z_](?:[a-zA-Z0-9_-]*[a-zA-Z0-9_])?')
+STRING = l.define("STRING", r""""(?:[^\\"]|\\.)*"|'(?:[^\\']|\\.)*'""")
+ESC = l.define("ESC", r"\\[^ux]|\\x[0-9a-fA-F][0-9a-fA-F]|\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]")
+SYM = l.define("SYM", r"[.#*%@$^!+-]")
+WSPACE = l.define("WSPACE", r"[ \n\r\t]+")
+EOF = l.eof("EOF")
+
+LEXER = l.compile()
+
+def lex(st):
+ return LEXER.lex(st)
+
+def tok2str(tok):
+ if tok.type is STRING:
+ return eval(tok.value)
+ elif tok.type is ESC:
+ if tok.value[1] == "x":
+ return eval('"%s"' % tok.value)
+ elif tok.value[1] == "u":
+ return eval('u"%s"' % tok.value)
+ else:
+ return tok.value[1]
+ else:
+ return tok.value
+
+def tok2obj(tok):
+ if tok.type in (STRING, NUMBER):
+ return eval(tok.value)
+ else:
+ return tok.value
+
+def toks2str(toks):
+ if toks:
+ return "".join(map(tok2str, toks))
+ else:
+ return None
+
+class AddressParser(Parser):
+
+ def __init__(self, tokens):
+ Parser.__init__(self, [t for t in tokens if t.type is not WSPACE])
+
+ def parse(self):
+ result = self.address()
+ self.eat(EOF)
+ return result
+
+ def address(self):
+ name = toks2str(self.eat_until(SLASH, SEMI, EOF))
+
+ if name is None:
+ raise ParseError(self.next())
+
+ if self.matches(SLASH):
+ self.eat(SLASH)
+ subject = toks2str(self.eat_until(SEMI, EOF))
+ else:
+ subject = None
+
+ if self.matches(SEMI):
+ self.eat(SEMI)
+ options = self.map()
+ else:
+ options = None
+ return name, subject, options
+
+ def map(self):
+ self.eat(LBRACE)
+
+ result = {}
+ while True:
+ if self.matches(ID):
+ n, v = self.nameval()
+ result[n] = v
+ if self.matches(COMMA):
+ self.eat(COMMA)
+ elif self.matches(RBRACE):
+ break
+ else:
+ raise ParseError(self.next(), COMMA, RBRACE)
+ elif self.matches(RBRACE):
+ break
+ else:
+ raise ParseError(self.next(), ID, RBRACE)
+
+ self.eat(RBRACE)
+ return result
+
+ def nameval(self):
+ name = self.eat(ID).value
+ self.eat(COLON)
+ val = self.value()
+ return (name, val)
+
+ def value(self):
+ if self.matches(NUMBER, STRING, ID):
+ return tok2obj(self.eat())
+ elif self.matches(LBRACE):
+ return self.map()
+ elif self.matches(LBRACK):
+ return self.list()
+ else:
+ raise ParseError(self.next(), NUMBER, STRING, ID, LBRACE, LBRACK)
+
+ def list(self):
+ self.eat(LBRACK)
+
+ result = []
+
+ while True:
+ if self.matches(RBRACK):
+ break
+ else:
+ result.append(self.value())
+ if self.matches(COMMA):
+ self.eat(COMMA)
+ elif self.matches(RBRACK):
+ break
+ else:
+ raise ParseError(self.next(), COMMA, RBRACK)
+
+ self.eat(RBRACK)
+ return result
+
+def parse(addr):
+ return AddressParser(lex(addr)).parse()
+
+__all__ = ["parse", "ParseError"]
diff --git a/python/qpid/assembler.py b/python/qpid/assembler.py
deleted file mode 100644
index 92bb0aa0f8..0000000000
--- a/python/qpid/assembler.py
+++ /dev/null
@@ -1,118 +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.
-#
-
-from codec010 import StringCodec
-from framer import *
-from logging import getLogger
-
-log = getLogger("qpid.io.seg")
-
-class Segment:
-
- def __init__(self, first, last, type, track, channel, payload):
- self.id = None
- self.offset = None
- self.first = first
- self.last = last
- self.type = type
- self.track = track
- self.channel = channel
- self.payload = payload
-
- def decode(self, spec):
- segs = spec["segment_type"]
- choice = segs.choices[self.type]
- return getattr(self, "decode_%s" % choice.name)(spec)
-
- def decode_control(self, spec):
- sc = StringCodec(spec, self.payload)
- return sc.read_control()
-
- def decode_command(self, spec):
- sc = StringCodec(spec, self.payload)
- hdr, cmd = sc.read_command()
- cmd.id = self.id
- return hdr, cmd
-
- def decode_header(self, spec):
- sc = StringCodec(spec, self.payload)
- values = []
- while len(sc.encoded) > 0:
- values.append(sc.read_struct32())
- return values
-
- def decode_body(self, spec):
- return self.payload
-
- def __str__(self):
- return "%s%s %s %s %s %r" % (int(self.first), int(self.last), self.type,
- self.track, self.channel, self.payload)
-
- def __repr__(self):
- return str(self)
-
-class Assembler(Framer):
-
- def __init__(self, sock, max_payload = Frame.MAX_PAYLOAD):
- Framer.__init__(self, sock)
- self.max_payload = max_payload
- self.fragments = {}
-
- def read_segment(self):
- while True:
- frame = self.read_frame()
-
- key = (frame.channel, frame.track)
- seg = self.fragments.get(key)
- if seg == None:
- seg = Segment(frame.isFirstSegment(), frame.isLastSegment(),
- frame.type, frame.track, frame.channel, "")
- self.fragments[key] = seg
-
- seg.payload += frame.payload
-
- if frame.isLastFrame():
- self.fragments.pop(key)
- log.debug("RECV %s", seg)
- return seg
-
- def write_segment(self, segment):
- remaining = segment.payload
-
- first = True
- while first or remaining:
- payload = remaining[:self.max_payload]
- remaining = remaining[self.max_payload:]
-
- flags = 0
- if first:
- flags |= FIRST_FRM
- first = False
- if not remaining:
- flags |= LAST_FRM
- if segment.first:
- flags |= FIRST_SEG
- if segment.last:
- flags |= LAST_SEG
-
- frame = Frame(flags, segment.type, segment.track, segment.channel,
- payload)
- self.write_frame(frame)
-
- log.debug("SENT %s", segment)
diff --git a/python/qpid/brokertest.py b/python/qpid/brokertest.py
new file mode 100644
index 0000000000..83d6c44d84
--- /dev/null
+++ b/python/qpid/brokertest.py
@@ -0,0 +1,480 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Support library for tests that start multiple brokers, e.g. cluster
+# or federation
+
+import os, signal, string, tempfile, popen2, socket, threading, time, imp
+import qpid, traceback
+from qpid import connection, messaging, util
+from qpid.compat import format_exc
+from qpid.harness import Skipped
+from unittest import TestCase
+from copy import copy
+from threading import Thread, Lock, Condition
+from logging import getLogger
+
+log = getLogger("qpid.brokertest")
+
+# Values for expected outcome of process at end of test
+EXPECT_EXIT_OK=1 # Expect to exit with 0 status before end of test.
+EXPECT_EXIT_FAIL=2 # Expect to exit with non-0 status before end of test.
+EXPECT_RUNNING=3 # Expect to still be running at end of test
+
+def is_running(pid):
+ try:
+ os.kill(pid, 0)
+ return True
+ except:
+ return False
+
+class BadProcessStatus(Exception):
+ pass
+
+class ExceptionWrapper:
+ """Proxy object that adds a message to exceptions raised"""
+ def __init__(self, obj, msg):
+ self.obj = obj
+ self.msg = msg
+
+ def __getattr__(self, name):
+ func = getattr(self.obj, name)
+ return lambda *args, **kwargs: self._wrap(func, args, kwargs)
+
+ def _wrap(self, func, args, kwargs):
+ try:
+ return func(*args, **kwargs)
+ except Exception, e:
+ raise Exception("%s: %s" %(self.msg, str(e)))
+
+def error_line(f):
+ try:
+ lines = file(f).readlines()
+ if len(lines) > 0: return ": %s" % (lines[-1])
+ except: pass
+ return ""
+
+
+class Popen(popen2.Popen3):
+ """
+ Similar to subprocess.Popen but using popen2 classes for portability.
+ Can set and verify expectation of process status at end of test.
+ Dumps command line, stdout, stderr to data dir for debugging.
+ """
+
+ def __init__(self, cmd, expect=EXPECT_EXIT_OK):
+ if type(cmd) is type(""): cmd = [cmd] # Make it a list.
+ self.cmd = [ str(x) for x in cmd ]
+ popen2.Popen3.__init__(self, self.cmd, True)
+ self.expect = expect
+ self.pname = "%s-%d" % (os.path.split(self.cmd[0])[-1], self.pid)
+ msg = "Process %s" % self.pname
+ self.stdin = ExceptionWrapper(self.tochild, msg)
+ self.stdout = ExceptionWrapper(self.fromchild, msg)
+ self.stderr = ExceptionWrapper(self.childerr, msg)
+ self.dump(self.cmd_str(), "cmd")
+ log.debug("Started process %s" % self.pname)
+
+ def dump(self, str, ext):
+ name = "%s.%s" % (self.pname, ext)
+ f = file(name, "w")
+ f.write(str)
+ f.close()
+ return name
+
+ def unexpected(self,msg):
+ self.dump(self.stdout.read(), "out")
+ err = self.dump(self.stderr.read(), "err")
+ raise BadProcessStatus("%s %s%s" % (self.pname, msg, error_line(err)))
+
+ def stop(self): # Clean up at end of test.
+ if self.expect == EXPECT_RUNNING:
+ try:
+ self.kill()
+ except:
+ self.unexpected("expected running, exit code %d" % self.wait())
+ else:
+ # Give the process some time to exit.
+ delay = 0.1
+ while (self.poll() is None and delay < 1):
+ time.sleep(delay)
+ delay *= 2
+ if self.returncode is None: # Still haven't stopped
+ self.kill()
+ self.unexpected("still running")
+ elif self.expect == EXPECT_EXIT_OK and self.returncode != 0:
+ self.unexpected("exit code %d" % self.returncode)
+ elif self.expect == EXPECT_EXIT_FAIL and self.returncode == 0:
+ self.unexpected("expected error")
+
+ def communicate(self, input=None):
+ if input:
+ self.stdin.write(input)
+ self.stdin.close()
+ outerr = (self.stdout.read(), self.stderr.read())
+ self.wait()
+ return outerr
+
+ def is_running(self): return self.poll() is None
+
+ def assert_running(self):
+ if not self.is_running(): unexpected("Exit code %d" % self.returncode)
+
+ def poll(self):
+ self.returncode = popen2.Popen3.poll(self)
+ if (self.returncode == -1): self.returncode = None
+ return self.returncode
+
+ def wait(self):
+ self.returncode = popen2.Popen3.wait(self)
+ return self.returncode
+
+ def send_signal(self, sig):
+ os.kill(self.pid,sig)
+ self.wait()
+
+ def terminate(self): self.send_signal(signal.SIGTERM)
+ def kill(self): self.send_signal(signal.SIGKILL)
+
+ def cmd_str(self): return " ".join([str(s) for s in self.cmd])
+
+def checkenv(name):
+ value = os.getenv(name)
+ if not value: raise Exception("Environment variable %s is not set" % name)
+ return value
+
+class Broker(Popen):
+ "A broker process. Takes care of start, stop and logging."
+ _broker_count = 0
+
+ def __init__(self, test, args=[], name=None, expect=EXPECT_RUNNING):
+ """Start a broker daemon. name determines the data-dir and log
+ file names."""
+
+ self.test = test
+ self._port = None
+ cmd = [BrokerTest.qpidd_exec, "--port=0", "--no-module-dir", "--auth=no"] + args
+ if name: self.name = name
+ else:
+ self.name = "broker%d" % Broker._broker_count
+ Broker._broker_count += 1
+ self.log = self.name+".log"
+ cmd += ["--log-to-file", self.log, "--log-prefix", self.name]
+ cmd += ["--log-to-stderr=no"]
+ self.datadir = self.name
+ cmd += ["--data-dir", self.datadir]
+ Popen.__init__(self, cmd, expect)
+ test.cleanup_stop(self)
+ self.host = "localhost"
+ log.debug("Started broker %s (%s)" % (self.name, self.pname))
+
+ def port(self):
+ # Read port from broker process stdout if not already read.
+ if (self._port is None):
+ try: self._port = int(self.stdout.readline())
+ except ValueError, e:
+ raise Exception("Can't get port for broker %s (%s)%s" %
+ (self.name, self.pname, error_line(self.log)))
+ return self._port
+
+ def unexpected(self,msg):
+ raise BadProcessStatus("%s: %s (%s)" % (msg, self.name, self.pname))
+
+ def connect(self):
+ """New API connection to the broker."""
+ return messaging.Connection.open(self.host, self.port())
+
+ def connect_old(self):
+ """Old API connection to the broker."""
+ socket = qpid.util.connect(self.host,self.port())
+ connection = qpid.connection.Connection (sock=socket)
+ connection.start()
+ return connection;
+
+ def declare_queue(self, queue):
+ c = self.connect_old()
+ s = c.session(str(qpid.datatypes.uuid4()))
+ s.queue_declare(queue=queue)
+ c.close()
+
+ def send_message(self, queue, message):
+ s = self.connect().session()
+ s.sender(queue+"; {create:always}").send(message)
+ s.connection.close()
+
+ def send_messages(self, queue, messages):
+ s = self.connect().session()
+ sender = s.sender(queue+"; {create:always}")
+ for m in messages: sender.send(m)
+ s.connection.close()
+
+ def get_message(self, queue):
+ s = self.connect().session()
+ m = s.receiver(queue+"; {create:always}", capacity=1).fetch(timeout=1)
+ s.acknowledge()
+ s.connection.close()
+ return m
+
+ def get_messages(self, queue, n):
+ s = self.connect().session()
+ receiver = s.receiver(queue+"; {create:always}", capacity=n)
+ m = [receiver.fetch(timeout=1) for i in range(n)]
+ s.acknowledge()
+ s.connection.close()
+ return m
+
+ def host_port(self): return "%s:%s" % (self.host, self.port())
+
+
+class Cluster:
+ """A cluster of brokers in a test."""
+
+ _cluster_count = 0
+
+ def __init__(self, test, count=0, args=[], expect=EXPECT_RUNNING, wait=True):
+ self.test = test
+ self._brokers=[]
+ self.name = "cluster%d" % Cluster._cluster_count
+ Cluster._cluster_count += 1
+ # Use unique cluster name
+ self.args = copy(args)
+ self.args += [ "--cluster-name", "%s-%s:%d" % (self.name, socket.gethostname(), os.getpid()) ]
+ assert BrokerTest.cluster_lib
+ self.args += [ "--load-module", BrokerTest.cluster_lib ]
+ self.start_n(count, expect=expect, wait=wait)
+
+ def start(self, name=None, expect=EXPECT_RUNNING, wait=True, args=[]):
+ """Add a broker to the cluster. Returns the index of the new broker."""
+ if not name: name="%s-%d" % (self.name, len(self._brokers))
+ log.debug("Cluster %s starting member %s" % (self.name, name))
+ self._brokers.append(self.test.broker(self.args+args, name, expect, wait))
+ return self._brokers[-1]
+
+ def start_n(self, count, expect=EXPECT_RUNNING, wait=True, args=[]):
+ for i in range(count): self.start(expect=expect, wait=wait, args=args)
+
+ # Behave like a list of brokers.
+ def __len__(self): return len(self._brokers)
+ def __getitem__(self,index): return self._brokers[index]
+ def __iter__(self): return self._brokers.__iter__()
+
+class BrokerTest(TestCase):
+ """
+ Tracks processes started by test and kills at end of test.
+ Provides a well-known working directory for each test.
+ """
+
+ # Environment settings.
+ qpidd_exec = checkenv("QPIDD_EXEC")
+ cluster_lib = os.getenv("CLUSTER_LIB")
+ xml_lib = os.getenv("XML_LIB")
+ qpidConfig_exec = os.getenv("QPID_CONFIG_EXEC")
+ qpidRoute_exec = os.getenv("QPID_ROUTE_EXEC")
+ receiver_exec = os.getenv("RECEIVER_EXEC")
+ sender_exec = os.getenv("SENDER_EXEC")
+ store_lib = os.getenv("STORE_LIB")
+ test_store_lib = os.getenv("TEST_STORE_LIB")
+ rootdir = os.getcwd()
+
+ def configure(self, config): self.config=config
+
+ def setUp(self):
+ outdir = self.config.defines.get("OUTDIR") or "brokertest.tmp"
+ self.dir = os.path.join(self.rootdir, outdir, self.id())
+ os.makedirs(self.dir)
+ os.chdir(self.dir)
+ self.stopem = [] # things to stop at end of test
+
+ def tearDown(self):
+ err = []
+ for p in self.stopem:
+ try: p.stop()
+ except Exception, e: err.append(str(e))
+ if err: raise Exception("Unexpected process status:\n "+"\n ".join(err))
+
+ def cleanup_stop(self, stopable):
+ """Call thing.stop at end of test"""
+ self.stopem.append(stopable)
+
+ def popen(self, cmd, expect=EXPECT_EXIT_OK):
+ """Start a process that will be killed at end of test, in the test dir."""
+ os.chdir(self.dir)
+ p = Popen(cmd, expect)
+ self.cleanup_stop(p)
+ return p
+
+ def broker(self, args=[], name=None, expect=EXPECT_RUNNING,wait=True):
+ """Create and return a broker ready for use"""
+ b = Broker(self, args=args, name=name, expect=expect)
+ if (wait): b.connect().close()
+ return b
+
+ def cluster(self, count=0, args=[], expect=EXPECT_RUNNING, wait=True):
+ """Create and return a cluster ready for use"""
+ cluster = Cluster(self, count, args, expect=expect, wait=wait)
+ return cluster
+
+ def wait():
+ """Wait for all brokers in the cluster to be ready"""
+ for b in _brokers: b.connect().close()
+
+class RethrownException(Exception):
+ """Captures the original stack trace to be thrown later"""
+ def __init__(self, e, msg=""):
+ Exception.__init__(self, msg+"\n"+format_exc())
+
+class StoppableThread(Thread):
+ """
+ Base class for threads that do something in a loop and periodically check
+ to see if they have been stopped.
+ """
+ def __init__(self):
+ self.stopped = False
+ self.error = None
+ Thread.__init__(self)
+
+ def stop(self):
+ self.stopped = True
+ self.join()
+ if self.error: raise self.error
+
+class NumberedSender(Thread):
+ """
+ Thread to run a sender client and send numbered messages until stopped.
+ """
+
+ def __init__(self, broker, max_depth=None):
+ """
+ max_depth: enable flow control, ensure sent - received <= max_depth.
+ Requires self.received(n) to be called each time messages are received.
+ """
+ Thread.__init__(self)
+ self.sender = broker.test.popen(
+ [broker.test.sender_exec, "--port", broker.port()], expect=EXPECT_RUNNING)
+ self.condition = Condition()
+ self.max = max_depth
+ self.received = 0
+ self.stopped = False
+ self.error = None
+
+ def run(self):
+ try:
+ self.sent = 0
+ while not self.stopped:
+ if self.max:
+ self.condition.acquire()
+ while not self.stopped and self.sent - self.received > self.max:
+ self.condition.wait()
+ self.condition.release()
+ self.sender.stdin.write(str(self.sent)+"\n")
+ self.sender.stdin.flush()
+ self.sent += 1
+ except Exception, e: self.error = RethrownException(e, self.sender.pname)
+
+ def notify_received(self, count):
+ """Called by receiver to enable flow control. count = messages received so far."""
+ self.condition.acquire()
+ self.received = count
+ self.condition.notify()
+ self.condition.release()
+
+ def stop(self):
+ self.condition.acquire()
+ self.stopped = True
+ self.condition.notify()
+ self.condition.release()
+ self.join()
+ if self.error: raise self.error
+
+class NumberedReceiver(Thread):
+ """
+ Thread to run a receiver client and verify it receives
+ sequentially numbered messages.
+ """
+ def __init__(self, broker, sender = None):
+ """
+ sender: enable flow control. Call sender.received(n) for each message received.
+ """
+ Thread.__init__(self)
+ self.test = broker.test
+ self.receiver = self.test.popen(
+ [self.test.receiver_exec, "--port", broker.port()], expect=EXPECT_RUNNING)
+ self.stopat = None
+ self.lock = Lock()
+ self.error = None
+ self.sender = sender
+
+ def continue_test(self):
+ self.lock.acquire()
+ ret = self.stopat is None or self.received < self.stopat
+ self.lock.release()
+ return ret
+
+ def run(self):
+ try:
+ self.received = 0
+ while self.continue_test():
+ m = int(self.receiver.stdout.readline())
+ assert(m <= self.received) # Allow for duplicates
+ if (m == self.received):
+ self.received += 1
+ if self.sender:
+ self.sender.notify_received(self.received)
+ except Exception, e:
+ self.error = RethrownException(e, self.receiver.pname)
+
+ def stop(self, count):
+ """Returns when received >= count"""
+ self.lock.acquire()
+ self.stopat = count
+ self.lock.release()
+ self.join()
+ if self.error: raise self.error
+
+class ErrorGenerator(StoppableThread):
+ """
+ Thread that continuously generates errors by trying to consume from
+ a non-existent queue. For cluster regression tests, error handling
+ caused issues in the past.
+ """
+
+ def __init__(self, broker):
+ StoppableThread.__init__(self)
+ self.broker=broker
+ broker.test.cleanup_stop(self)
+ self.start()
+
+ def run(self):
+ c = self.broker.connect_old()
+ try:
+ while not self.stopped:
+ try:
+ c.session(str(qpid.datatypes.uuid4())).message_subscribe(
+ queue="non-existent-queue")
+ assert(False)
+ except qpid.session.SessionException: pass
+ except: pass # Normal if broker is killed.
+
+def import_script(path):
+ """
+ Import executable script at path as a module.
+ Requires some trickery as scripts are not in standard module format
+ """
+ name=os.path.split(path)[1].replace("-","_")
+ return imp.load_module(name, file(path), path, ("", "r", imp.PY_SOURCE))
diff --git a/python/qpid/client.py b/python/qpid/client.py
index 4605710de8..6107a4bc35 100644
--- a/python/qpid/client.py
+++ b/python/qpid/client.py
@@ -39,11 +39,8 @@ class Client:
if spec:
self.spec = spec
else:
- try:
- name = os.environ["AMQP_SPEC"]
- except KeyError:
- raise EnvironmentError("environment variable AMQP_SPEC must be set")
- self.spec = load(name)
+ from qpid_config import amqp_spec_0_9
+ self.spec = load(amqp_spec_0_9)
self.structs = StructFactory(self.spec)
self.sessions = {}
diff --git a/python/qpid/codec010.py b/python/qpid/codec010.py
index dac023e2bd..682743df19 100644
--- a/python/qpid/codec010.py
+++ b/python/qpid/codec010.py
@@ -17,25 +17,69 @@
# under the License.
#
+import datetime
from packer import Packer
-from datatypes import serial, RangedSet, Struct
+from datatypes import serial, timestamp, RangedSet, Struct, UUID
+from ops import Compound, PRIMITIVE, COMPOUND
class CodecException(Exception): pass
+def direct(t):
+ return lambda x: t
+
+def map_str(s):
+ for c in s:
+ if ord(c) >= 0x80:
+ return "vbin16"
+ return "str16"
+
class Codec(Packer):
- def __init__(self, spec):
- self.spec = spec
+ ENCODINGS = {
+ unicode: direct("str16"),
+ str: map_str,
+ buffer: direct("vbin32"),
+ int: direct("int64"),
+ long: direct("int64"),
+ float: direct("double"),
+ None.__class__: direct("void"),
+ list: direct("list"),
+ tuple: direct("list"),
+ dict: direct("map"),
+ timestamp: direct("datetime"),
+ datetime.datetime: direct("datetime"),
+ UUID: direct("uuid"),
+ Compound: direct("struct32")
+ }
+
+ def encoding(self, obj):
+ enc = self._encoding(obj.__class__, obj)
+ if enc is None:
+ raise CodecException("no encoding for %r" % obj)
+ return PRIMITIVE[enc]
+
+ def _encoding(self, klass, obj):
+ if self.ENCODINGS.has_key(klass):
+ return self.ENCODINGS[klass](obj)
+ for base in klass.__bases__:
+ result = self._encoding(base, obj)
+ if result != None:
+ return result
+
+ def read_primitive(self, type):
+ return getattr(self, "read_%s" % type.NAME)()
+ def write_primitive(self, type, v):
+ getattr(self, "write_%s" % type.NAME)(v)
- def write_void(self, v):
- assert v == None
def read_void(self):
return None
+ def write_void(self, v):
+ assert v == None
- def write_bit(self, b):
- if not b: raise ValueError(b)
def read_bit(self):
return True
+ def write_bit(self, b):
+ if not b: raise ValueError(b)
def read_uint8(self):
return self.unpack("!B")
@@ -68,7 +112,7 @@ class Codec(Packer):
def read_int16(self):
return self.unpack("!h")
def write_int16(self, n):
- return self.unpack("!h", n)
+ self.pack("!h", n)
def read_uint32(self):
@@ -103,9 +147,11 @@ class Codec(Packer):
self.pack("!q", n)
def read_datetime(self):
- return self.read_uint64()
- def write_datetime(self, n):
- self.write_uint64(n)
+ return timestamp(self.read_uint64())
+ def write_datetime(self, t):
+ if isinstance(t, datetime.datetime):
+ t = timestamp(t)
+ self.write_uint64(t)
def read_double(self):
return self.unpack("!d")
@@ -115,6 +161,8 @@ class Codec(Packer):
def read_vbin8(self):
return self.read(self.read_uint8())
def write_vbin8(self, b):
+ if isinstance(b, buffer):
+ b = str(b)
self.write_uint8(len(b))
self.write(b)
@@ -128,10 +176,17 @@ class Codec(Packer):
def write_str16(self, s):
self.write_vbin16(s.encode("utf8"))
+ def read_str16_latin(self):
+ return self.read_vbin16().decode("iso-8859-15")
+ def write_str16_latin(self, s):
+ self.write_vbin16(s.encode("iso-8859-15"))
+
def read_vbin16(self):
return self.read(self.read_uint16())
def write_vbin16(self, b):
+ if isinstance(b, buffer):
+ b = str(b)
self.write_uint16(len(b))
self.write(b)
@@ -155,23 +210,13 @@ class Codec(Packer):
def read_vbin32(self):
return self.read(self.read_uint32())
def write_vbin32(self, b):
+ if isinstance(b, buffer):
+ b = str(b)
self.write_uint32(len(b))
self.write(b)
- def write_map(self, m):
- sc = StringCodec(self.spec)
- if m is not None:
- sc.write_uint32(len(m))
- for k, v in m.items():
- type = self.spec.encoding(v.__class__)
- if type == None:
- raise CodecException("no encoding for %s" % v.__class__)
- sc.write_str8(k)
- sc.write_uint8(type.code)
- type.encode(sc, v)
- self.write_vbin32(sc.encoded)
def read_map(self):
- sc = StringCodec(self.spec, self.read_vbin32())
+ sc = StringCodec(self.read_vbin32())
if not sc.encoded:
return None
count = sc.read_uint32()
@@ -179,105 +224,146 @@ class Codec(Packer):
while sc.encoded:
k = sc.read_str8()
code = sc.read_uint8()
- type = self.spec.types[code]
- v = type.decode(sc)
+ type = PRIMITIVE[code]
+ v = sc.read_primitive(type)
result[k] = v
return result
+ def write_map(self, m):
+ sc = StringCodec()
+ if m is not None:
+ sc.write_uint32(len(m))
+ for k, v in m.items():
+ type = self.encoding(v)
+ sc.write_str8(k)
+ sc.write_uint8(type.CODE)
+ sc.write_primitive(type, v)
+ self.write_vbin32(sc.encoded)
+ def read_array(self):
+ sc = StringCodec(self.read_vbin32())
+ if not sc.encoded:
+ return None
+ type = PRIMITIVE[sc.read_uint8()]
+ count = sc.read_uint32()
+ result = []
+ while count > 0:
+ result.append(sc.read_primitive(type))
+ count -= 1
+ return result
def write_array(self, a):
- sc = StringCodec(self.spec)
+ sc = StringCodec()
if a is not None:
if len(a) > 0:
- type = self.spec.encoding(a[0].__class__)
+ type = self.encoding(a[0])
else:
- type = self.spec.encoding(None.__class__)
- sc.write_uint8(type.code)
+ type = self.encoding(None)
+ sc.write_uint8(type.CODE)
sc.write_uint32(len(a))
for o in a:
- type.encode(sc, o)
+ sc.write_primitive(type, o)
self.write_vbin32(sc.encoded)
- def read_array(self):
- sc = StringCodec(self.spec, self.read_vbin32())
+
+ def read_list(self):
+ sc = StringCodec(self.read_vbin32())
if not sc.encoded:
return None
- type = self.spec.types[sc.read_uint8()]
count = sc.read_uint32()
result = []
while count > 0:
- result.append(type.decode(sc))
+ type = PRIMITIVE[sc.read_uint8()]
+ result.append(sc.read_primitive(type))
count -= 1
return result
-
def write_list(self, l):
- sc = StringCodec(self.spec)
+ sc = StringCodec()
if l is not None:
sc.write_uint32(len(l))
for o in l:
- type = self.spec.encoding(o.__class__)
- sc.write_uint8(type.code)
- type.encode(sc, o)
+ type = self.encoding(o)
+ sc.write_uint8(type.CODE)
+ sc.write_primitive(type, o)
self.write_vbin32(sc.encoded)
- def read_list(self):
- sc = StringCodec(self.spec, self.read_vbin32())
- if not sc.encoded:
- return None
- count = sc.read_uint32()
- result = []
- while count > 0:
- type = self.spec.types[sc.read_uint8()]
- result.append(type.decode(sc))
- count -= 1
- return result
def read_struct32(self):
size = self.read_uint32()
code = self.read_uint16()
- type = self.spec.structs[code]
- fields = type.decode_fields(self)
- return Struct(type, **fields)
+ cls = COMPOUND[code]
+ op = cls()
+ self.read_fields(op)
+ return op
def write_struct32(self, value):
- sc = StringCodec(self.spec)
- sc.write_uint16(value._type.code)
- value._type.encode_fields(sc, value)
- self.write_vbin32(sc.encoded)
-
- def read_control(self):
- cntrl = self.spec.controls[self.read_uint16()]
- return Struct(cntrl, **cntrl.decode_fields(self))
- def write_control(self, ctrl):
- type = ctrl._type
- self.write_uint16(type.code)
- type.encode_fields(self, ctrl)
-
- def read_command(self):
- type = self.spec.commands[self.read_uint16()]
- hdr = self.spec["session.header"].decode(self)
- cmd = Struct(type, **type.decode_fields(self))
- return hdr, cmd
- def write_command(self, hdr, cmd):
- self.write_uint16(cmd._type.code)
- hdr._type.encode(self, hdr)
- cmd._type.encode_fields(self, cmd)
+ self.write_compound(value)
+
+ def read_compound(self, cls):
+ size = self.read_size(cls.SIZE)
+ if cls.CODE is not None:
+ code = self.read_uint16()
+ assert code == cls.CODE
+ op = cls()
+ self.read_fields(op)
+ return op
+ def write_compound(self, op):
+ sc = StringCodec()
+ if op.CODE is not None:
+ sc.write_uint16(op.CODE)
+ sc.write_fields(op)
+ self.write_size(op.SIZE, len(sc.encoded))
+ self.write(sc.encoded)
+
+ def read_fields(self, op):
+ flags = 0
+ for i in range(op.PACK):
+ flags |= (self.read_uint8() << 8*i)
+
+ for i in range(len(op.FIELDS)):
+ f = op.FIELDS[i]
+ if flags & (0x1 << i):
+ if COMPOUND.has_key(f.type):
+ value = self.read_compound(COMPOUND[f.type])
+ else:
+ value = getattr(self, "read_%s" % f.type)()
+ setattr(op, f.name, value)
+ def write_fields(self, op):
+ flags = 0
+ for i in range(len(op.FIELDS)):
+ f = op.FIELDS[i]
+ value = getattr(op, f.name)
+ if f.type == "bit":
+ present = value
+ else:
+ present = value != None
+ if present:
+ flags |= (0x1 << i)
+ for i in range(op.PACK):
+ self.write_uint8((flags >> 8*i) & 0xFF)
+ for i in range(len(op.FIELDS)):
+ f = op.FIELDS[i]
+ if flags & (0x1 << i):
+ if COMPOUND.has_key(f.type):
+ enc = self.write_compound
+ else:
+ enc = getattr(self, "write_%s" % f.type)
+ value = getattr(op, f.name)
+ enc(value)
def read_size(self, width):
if width > 0:
attr = "read_uint%d" % (width*8)
return getattr(self, attr)()
-
def write_size(self, width, n):
if width > 0:
attr = "write_uint%d" % (width*8)
getattr(self, attr)(n)
def read_uuid(self):
- return self.unpack("16s")
-
+ return UUID(self.unpack("16s"))
def write_uuid(self, s):
+ if isinstance(s, UUID):
+ s = s.bytes
self.pack("16s", s)
def read_bin128(self):
return self.unpack("16s")
-
def write_bin128(self, b):
self.pack("16s", b)
@@ -285,14 +371,13 @@ class Codec(Packer):
class StringCodec(Codec):
- def __init__(self, spec, encoded = ""):
- Codec.__init__(self, spec)
+ def __init__(self, encoded = ""):
self.encoded = encoded
- def write(self, s):
- self.encoded += s
-
def read(self, n):
result = self.encoded[:n]
self.encoded = self.encoded[n:]
return result
+
+ def write(self, s):
+ self.encoded += s
diff --git a/python/qpid/compat.py b/python/qpid/compat.py
index 26f60fb8aa..c2b668a5e9 100644
--- a/python/qpid/compat.py
+++ b/python/qpid/compat.py
@@ -17,6 +17,8 @@
# under the License.
#
+import sys
+
try:
set = set
except NameError:
@@ -26,3 +28,95 @@ try:
from socket import SHUT_RDWR
except ImportError:
SHUT_RDWR = 2
+
+try:
+ from traceback import format_exc
+except ImportError:
+ import traceback
+ def format_exc():
+ return "".join(traceback.format_exception(*sys.exc_info()))
+
+if tuple(sys.version_info[0:2]) < (2, 4):
+ from select import select as old_select
+ def select(rlist, wlist, xlist, timeout=None):
+ return old_select(list(rlist), list(wlist), list(xlist), timeout)
+else:
+ from select import select
+
+class BaseWaiter:
+
+ def wakeup(self):
+ self._do_write()
+
+ def wait(self, timeout=None):
+ if timeout is not None:
+ ready, _, _ = select([self], [], [], timeout)
+ else:
+ ready = True
+
+ if ready:
+ self._do_read()
+ return True
+ else:
+ return False
+
+ def reading(self):
+ return True
+
+ def readable(self):
+ self._do_read()
+
+if sys.platform in ('win32', 'cygwin'):
+ import socket
+
+ class SockWaiter(BaseWaiter):
+
+ def __init__(self, read_sock, write_sock):
+ self.read_sock = read_sock
+ self.write_sock = write_sock
+
+ def _do_write(self):
+ self.write_sock.send("\0")
+
+ def _do_read(self):
+ self.read_sock.recv(65536)
+
+ def fileno(self):
+ return self.read_sock.fileno()
+
+ def __repr__(self):
+ return "SockWaiter(%r, %r)" % (self.read_sock, self.write_sock)
+
+ def selectable_waiter():
+ listener = socket.socket()
+ listener.bind(('', 0))
+ listener.listen(1)
+ _, port = listener.getsockname()
+ write_sock = socket.socket()
+ write_sock.connect(("127.0.0.1", port))
+ read_sock, _ = listener.accept()
+ listener.close()
+ return SockWaiter(read_sock, write_sock)
+else:
+ import os
+
+ class PipeWaiter(BaseWaiter):
+
+ def __init__(self, read_fd, write_fd):
+ self.read_fd = read_fd
+ self.write_fd = write_fd
+
+ def _do_write(self):
+ os.write(self.write_fd, "\0")
+
+ def _do_read(self):
+ os.read(self.read_fd, 65536)
+
+ def fileno(self):
+ return self.read_fd
+
+ def __repr__(self):
+ return "PipeWaiter(%r, %r)" % (self.read_fd, self.write_fd)
+
+ def selectable_waiter():
+ return PipeWaiter(*os.pipe())
diff --git a/python/qpid/concurrency.py b/python/qpid/concurrency.py
new file mode 100644
index 0000000000..9837a3f0df
--- /dev/null
+++ b/python/qpid/concurrency.py
@@ -0,0 +1,100 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import compat, inspect, time
+
+def synchronized(meth):
+ args, vargs, kwargs, defs = inspect.getargspec(meth)
+ scope = {}
+ scope["meth"] = meth
+ exec """
+def %s%s:
+ %s
+ %s._lock.acquire()
+ try:
+ return meth%s
+ finally:
+ %s._lock.release()
+""" % (meth.__name__, inspect.formatargspec(args, vargs, kwargs, defs),
+ repr(inspect.getdoc(meth)), args[0],
+ inspect.formatargspec(args, vargs, kwargs, defs,
+ formatvalue=lambda x: ""),
+ args[0]) in scope
+ return scope[meth.__name__]
+
+class Waiter(object):
+
+ def __init__(self, condition):
+ self.condition = condition
+
+ def wait(self, predicate, timeout=None):
+ passed = 0
+ start = time.time()
+ while not predicate():
+ if timeout is None:
+ # XXX: this timed wait thing is not necessary for the fast
+ # condition from this module, only for the condition impl from
+ # the threading module
+
+ # using the timed wait prevents keyboard interrupts from being
+ # blocked while waiting
+ self.condition.wait(3)
+ elif passed < timeout:
+ self.condition.wait(timeout - passed)
+ else:
+ return bool(predicate())
+ passed = time.time() - start
+ return True
+
+ def notify(self):
+ self.condition.notify()
+
+ def notifyAll(self):
+ self.condition.notifyAll()
+
+class Condition:
+
+ def __init__(self, lock):
+ self.lock = lock
+ self.waiters = []
+ self.waiting = []
+
+ def notify(self):
+ assert self.lock._is_owned()
+ if self.waiting:
+ self.waiting[0].wakeup()
+
+ def notifyAll(self):
+ assert self.lock._is_owned()
+ for w in self.waiting:
+ w.wakeup()
+
+ def wait(self, timeout=None):
+ assert self.lock._is_owned()
+ if not self.waiters:
+ self.waiters.append(compat.selectable_waiter())
+ sw = self.waiters.pop(0)
+ self.waiting.append(sw)
+ try:
+ st = self.lock._release_save()
+ sw.wait(timeout)
+ finally:
+ self.lock._acquire_restore(st)
+ self.waiting.remove(sw)
+ self.waiters.append(sw)
diff --git a/python/qpid/connection.py b/python/qpid/connection.py
index ce27a74489..18eeb99de8 100644
--- a/python/qpid/connection.py
+++ b/python/qpid/connection.py
@@ -20,15 +20,14 @@
import datatypes, session
from threading import Thread, Condition, RLock
from util import wait, notify
-from assembler import Assembler, Segment
from codec010 import StringCodec
+from framing import *
from session import Session
-from invoker import Invoker
-from spec010 import Control, Command, load
-from spec import default
+from generator import control_invoker
+from spec import SPEC
from exceptions import *
from logging import getLogger
-import delegates
+import delegates, socket
class ChannelBusy(Exception): pass
@@ -44,28 +43,33 @@ def client(*args, **kwargs):
def server(*args, **kwargs):
return delegates.Server(*args, **kwargs)
-class Connection(Assembler):
+from framer import Framer
- def __init__(self, sock, spec=None, delegate=client, **args):
- Assembler.__init__(self, sock)
- if spec == None:
- spec = load(default())
- self.spec = spec
- self.track = self.spec["track"]
+class Connection(Framer):
+ def __init__(self, sock, delegate=client, **args):
+ Framer.__init__(self, sock)
self.lock = RLock()
self.attached = {}
self.sessions = {}
self.condition = Condition()
+ # XXX: we should combine this into a single comprehensive state
+ # model (whatever that means)
self.opened = False
self.failed = False
+ self.closed = False
self.close_code = (None, "connection aborted")
self.thread = Thread(target=self.run)
self.thread.setDaemon(True)
self.channel_max = 65535
+ self.user_id = None
+
+ self.op_enc = OpEncoder()
+ self.seg_enc = SegmentEncoder()
+ self.frame_enc = FrameEncoder()
self.delegate = delegate(self, **args)
@@ -79,7 +83,7 @@ class Connection(Assembler):
else:
ssn = self.sessions.get(name)
if ssn is None:
- ssn = Session(name, self.spec, delegate=delegate)
+ ssn = Session(name, delegate=delegate)
self.sessions[name] = ssn
elif ssn.channel is not None:
if force:
@@ -107,8 +111,7 @@ class Connection(Assembler):
self.lock.release()
def __channel(self):
- # XXX: ch 0?
- for i in xrange(self.channel_max):
+ for i in xrange(1, self.channel_max):
if not self.attached.has_key(i):
return i
else:
@@ -147,15 +150,45 @@ class Connection(Assembler):
raise ConnectionFailed(*self.close_code)
def run(self):
- # XXX: we don't really have a good way to exit this loop without
- # getting the other end to kill the socket
- while True:
+ frame_dec = FrameDecoder()
+ seg_dec = SegmentDecoder()
+ op_dec = OpDecoder()
+
+ while not self.closed:
try:
- seg = self.read_segment()
- except Closed:
+ data = self.sock.recv(64*1024)
+ if self.security_layer_rx and data:
+ status, data = self.security_layer_rx.decode(data)
+ if not data:
+ self.detach_all()
+ break
+ except socket.timeout:
+ if self.aborted():
+ self.detach_all()
+ raise Closed("connection timed out")
+ else:
+ continue
+ except socket.error, e:
self.detach_all()
- break
- self.delegate.received(seg)
+ raise Closed(e)
+ frame_dec.write(data)
+ seg_dec.write(*frame_dec.read())
+ op_dec.write(*seg_dec.read())
+ for op in op_dec.read():
+ self.delegate.received(op)
+ self.sock.close()
+
+ def write_op(self, op):
+ self.sock_lock.acquire()
+ try:
+ self.op_enc.write(op)
+ self.seg_enc.write(*self.op_enc.read())
+ self.frame_enc.write(*self.seg_enc.read())
+ bytes = self.frame_enc.read()
+ self.write(bytes)
+ self.flush()
+ finally:
+ self.sock_lock.release()
def close(self, timeout=None):
if not self.opened: return
@@ -172,26 +205,17 @@ class Connection(Assembler):
log = getLogger("qpid.io.ctl")
-class Channel(Invoker):
+class Channel(control_invoker()):
def __init__(self, connection, id):
self.connection = connection
self.id = id
self.session = None
- def resolve_method(self, name):
- inst = self.connection.spec.instructions.get(name)
- if inst is not None and isinstance(inst, Control):
- return self.METHOD, inst
- else:
- return self.ERROR, None
-
- def invoke(self, type, args, kwargs):
- ctl = type.new(args, kwargs)
- sc = StringCodec(self.connection.spec)
- sc.write_control(ctl)
- self.connection.write_segment(Segment(True, True, type.segment_type,
- type.track, self.id, sc.encoded))
+ def invoke(self, op, args, kwargs):
+ ctl = op(*args, **kwargs)
+ ctl.channel = self.id
+ self.connection.write_op(ctl)
log.debug("SENT %s", ctl)
def __str__(self):
diff --git a/python/qpid/connection08.py b/python/qpid/connection08.py
index 8f2eef4770..d34cfe2847 100644
--- a/python/qpid/connection08.py
+++ b/python/qpid/connection08.py
@@ -28,6 +28,7 @@ from cStringIO import StringIO
from spec import load
from codec import EOF
from compat import SHUT_RDWR
+from exceptions import VersionError
class SockIO:
@@ -73,6 +74,9 @@ def listen(host, port, predicate = lambda: True):
s, a = sock.accept()
yield SockIO(s)
+class FramingError(Exception):
+ pass
+
class Connection:
def __init__(self, io, spec):
@@ -107,7 +111,16 @@ class Connection:
def read_8_0(self):
c = self.codec
- type = self.spec.constants.byid[c.decode_octet()].name
+ tid = c.decode_octet()
+ try:
+ type = self.spec.constants.byid[tid].name
+ except KeyError:
+ if tid == ord('A') and c.unpack("!3s") == "MQP":
+ _, _, major, minor = c.unpack("4B")
+ raise VersionError("client: %s-%s, server: %s-%s" %
+ (self.spec.major, self.spec.minor, major, minor))
+ else:
+ raise FramingError("unknown frame type: %s" % tid)
channel = c.decode_short()
body = c.decode_longstr()
dec = codec.Codec(StringIO(body), self.spec)
@@ -122,6 +135,12 @@ class Connection:
raise "frame error: expected %r, got %r" % (self.FRAME_END, garbage)
return frame
+ def write_0_9(self, frame):
+ self.write_8_0(frame)
+
+ def read_0_9(self):
+ return self.read_8_0()
+
def write_0_10(self, frame):
c = self.codec
flags = 0
diff --git a/python/qpid/datatypes.py b/python/qpid/datatypes.py
index 7150caded2..61643715e4 100644
--- a/python/qpid/datatypes.py
+++ b/python/qpid/datatypes.py
@@ -17,7 +17,8 @@
# under the License.
#
-import threading, struct
+import threading, struct, datetime, time
+from exceptions import Timeout
class Struct:
@@ -83,7 +84,7 @@ class Message:
def get(self, name):
if self.headers:
for h in self.headers:
- if h._type.name == name:
+ if h.NAME == name:
return h
return None
@@ -92,7 +93,7 @@ class Message:
self.headers = []
idx = 0
while idx < len(self.headers):
- if self.headers[idx]._type == header._type:
+ if self.headers[idx].NAME == header.NAME:
self.headers[idx] = header
return
idx += 1
@@ -101,7 +102,7 @@ class Message:
def clear(self, name):
idx = 0
while idx < len(self.headers):
- if self.headers[idx]._type.name == name:
+ if self.headers[idx].NAME == name:
del self.headers[idx]
return
idx += 1
@@ -125,19 +126,19 @@ def serial(o):
class Serial:
def __init__(self, value):
- self.value = value & 0xFFFFFFFF
+ self.value = value & 0xFFFFFFFFL
def __hash__(self):
return hash(self.value)
def __cmp__(self, other):
- if other is None:
+ if other.__class__ not in (int, long, Serial):
return 1
other = serial(other)
- delta = (self.value - other.value) & 0xFFFFFFFF
- neg = delta & 0x80000000
+ delta = (self.value - other.value) & 0xFFFFFFFFL
+ neg = delta & 0x80000000L
mag = delta & 0x7FFFFFFF
if neg:
@@ -149,7 +150,10 @@ class Serial:
return Serial(self.value + other)
def __sub__(self, other):
- return Serial(self.value - other)
+ if isinstance(other, Serial):
+ return self.value - other.value
+ else:
+ return Serial(self.value - other)
def __repr__(self):
return "serial(%s)" % self.value
@@ -168,7 +172,7 @@ class Range:
def __contains__(self, n):
return self.lower <= n and n <= self.upper
-
+
def __iter__(self):
i = self.lower
while i <= self.upper:
@@ -229,7 +233,25 @@ class RangedSet:
def add(self, lower, upper = None):
self.add_range(Range(lower, upper))
-
+
+ def empty(self):
+ for r in self.ranges:
+ if r.lower <= r.upper:
+ return False
+ return True
+
+ def max(self):
+ if self.ranges:
+ return self.ranges[-1].upper
+ else:
+ return None
+
+ def min(self):
+ if self.ranges:
+ return self.ranges[0].lower
+ else:
+ return None
+
def __iter__(self):
return iter(self.ranges)
@@ -253,9 +275,12 @@ class Future:
def get(self, timeout=None):
self._set.wait(timeout)
- if self._error != None:
- raise self.exception(self._error)
- return self.value
+ if self._set.isSet():
+ if self._error != None:
+ raise self.exception(self._error)
+ return self.value
+ else:
+ raise Timeout()
def is_set(self):
return self._set.isSet()
@@ -289,10 +314,62 @@ class UUID:
def __cmp__(self, other):
if isinstance(other, UUID):
return cmp(self.bytes, other.bytes)
- raise NotImplemented()
+ else:
+ return -1
def __str__(self):
return "%08x-%04x-%04x-%04x-%04x%08x" % struct.unpack("!LHHHHL", self.bytes)
def __repr__(self):
return "UUID(%r)" % str(self)
+
+ def __hash__(self):
+ return self.bytes.__hash__()
+
+class timestamp(float):
+
+ def __new__(cls, obj=None):
+ if obj is None:
+ obj = time.time()
+ elif isinstance(obj, datetime.datetime):
+ obj = time.mktime(obj.timetuple()) + 1e-6 * obj.microsecond
+ return super(timestamp, cls).__new__(cls, obj)
+
+ def datetime(self):
+ return datetime.datetime.fromtimestamp(self)
+
+ def __add__(self, other):
+ if isinstance(other, datetime.timedelta):
+ return timestamp(self.datetime() + other)
+ else:
+ return timestamp(float(self) + other)
+
+ def __sub__(self, other):
+ if isinstance(other, datetime.timedelta):
+ return timestamp(self.datetime() - other)
+ else:
+ return timestamp(float(self) - other)
+
+ def __radd__(self, other):
+ if isinstance(other, datetime.timedelta):
+ return timestamp(self.datetime() + other)
+ else:
+ return timestamp(other + float(self))
+
+ def __rsub__(self, other):
+ if isinstance(other, datetime.timedelta):
+ return timestamp(self.datetime() - other)
+ else:
+ return timestamp(other - float(self))
+
+ def __neg__(self):
+ return timestamp(-float(self))
+
+ def __pos__(self):
+ return self
+
+ def __abs__(self):
+ return timestamp(abs(float(self)))
+
+ def __repr__(self):
+ return "timestamp(%r)" % float(self)
diff --git a/python/qpid/debug.py b/python/qpid/debug.py
new file mode 100644
index 0000000000..b5dbd4d9d9
--- /dev/null
+++ b/python/qpid/debug.py
@@ -0,0 +1,55 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import threading, traceback, signal, sys, time
+
+def stackdump(sig, frm):
+ code = []
+ for threadId, stack in sys._current_frames().items():
+ code.append("\n# ThreadID: %s" % threadId)
+ for filename, lineno, name, line in traceback.extract_stack(stack):
+ code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
+ if line:
+ code.append(" %s" % (line.strip()))
+ print "\n".join(code)
+
+signal.signal(signal.SIGQUIT, stackdump)
+
+class LoudLock:
+
+ def __init__(self):
+ self.lock = threading.RLock()
+
+ def acquire(self, blocking=1):
+ while not self.lock.acquire(blocking=0):
+ time.sleep(1)
+ print >> sys.out, "TRYING"
+ traceback.print_stack(None, None, out)
+ print >> sys.out, "TRYING"
+ print >> sys.out, "ACQUIRED"
+ traceback.print_stack(None, None, out)
+ print >> sys.out, "ACQUIRED"
+ return True
+
+ def _is_owned(self):
+ return self.lock._is_owned()
+
+ def release(self):
+ self.lock.release()
+
diff --git a/python/qpid/delegates.py b/python/qpid/delegates.py
index bf26553dda..4c41a6241f 100644
--- a/python/qpid/delegates.py
+++ b/python/qpid/delegates.py
@@ -20,7 +20,17 @@
import os, connection, session
from util import notify
from datatypes import RangedSet
+from exceptions import VersionError, Closed
from logging import getLogger
+from ops import Control
+import sys
+
+_have_sasl = None
+try:
+ import saslwrapper
+ _have_sasl = True
+except:
+ pass
log = getLogger("qpid.io.ctl")
@@ -28,26 +38,22 @@ class Delegate:
def __init__(self, connection, delegate=session.client):
self.connection = connection
- self.spec = connection.spec
self.delegate = delegate
- self.control = self.spec["track.control"].value
- def received(self, seg):
- ssn = self.connection.attached.get(seg.channel)
+ def received(self, op):
+ ssn = self.connection.attached.get(op.channel)
if ssn is None:
- ch = connection.Channel(self.connection, seg.channel)
+ ch = connection.Channel(self.connection, op.channel)
else:
ch = ssn.channel
- if seg.track == self.control:
- ctl = seg.decode(self.spec)
- log.debug("RECV %s", ctl)
- attr = ctl._type.qname.replace(".", "_")
- getattr(self, attr)(ch, ctl)
+ if isinstance(op, Control):
+ log.debug("RECV %s", op)
+ getattr(self, op.NAME)(ch, op)
elif ssn is None:
ch.session_detached()
else:
- ssn.received(seg)
+ ssn.received(op)
def connection_close(self, ch, close):
self.connection.close_code = (close.reply_code, close.reply_text)
@@ -59,8 +65,12 @@ class Delegate:
def connection_close_ok(self, ch, close_ok):
self.connection.opened = False
+ self.connection.closed = True
notify(self.connection.condition)
+ def connection_heartbeat(self, ch, hrt):
+ pass
+
def session_attach(self, ch, a):
try:
self.connection.attach(a.name, ch, self.delegate, a.force)
@@ -119,7 +129,8 @@ class Server(Delegate):
def start(self):
self.connection.read_header()
- self.connection.write_header(self.spec.major, self.spec.minor)
+ # XXX
+ self.connection.write_header(0, 10)
connection.Channel(self.connection, 0).connection_start(mechanisms=["ANONYMOUS"])
def connection_start_ok(self, ch, start_ok):
@@ -135,28 +146,101 @@ class Server(Delegate):
class Client(Delegate):
+ ppid = 0
+ try:
+ ppid = os.getppid()
+ except:
+ pass
+
PROPERTIES = {"product": "qpid python client",
"version": "development",
- "platform": os.name}
+ "platform": os.name,
+ "qpid.client_process": os.path.basename(sys.argv[0]),
+ "qpid.client_pid": os.getpid(),
+ "qpid.client_ppid": ppid}
- def __init__(self, connection, username="guest", password="guest", mechanism="PLAIN"):
+ def __init__(self, connection, username=None, password=None,
+ mechanism=None, heartbeat=None, **kwargs):
Delegate.__init__(self, connection)
- self.username = username
- self.password = password
- self.mechanism = mechanism
+
+ ##
+ ## self.acceptableMechanisms is the list of SASL mechanisms that the client is willing to
+ ## use. If it's None, then any mechanism is acceptable.
+ ##
+ self.acceptableMechanisms = None
+ if mechanism:
+ self.acceptableMechanisms = mechanism.split(" ")
+ self.heartbeat = heartbeat
+ self.username = username
+ self.password = password
+
+ if _have_sasl:
+ self.sasl = saslwrapper.Client()
+ if username and len(username) > 0:
+ self.sasl.setAttr("username", str(username))
+ if password and len(password) > 0:
+ self.sasl.setAttr("password", str(password))
+ if "service" in kwargs:
+ self.sasl.setAttr("service", str(kwargs["service"]))
+ if "host" in kwargs:
+ self.sasl.setAttr("host", str(kwargs["host"]))
+ if "min_ssf" in kwargs:
+ self.sasl.setAttr("minssf", kwargs["min_ssf"])
+ if "max_ssf" in kwargs:
+ self.sasl.setAttr("maxssf", kwargs["max_ssf"])
+ self.sasl.init()
def start(self):
- self.connection.write_header(self.spec.major, self.spec.minor)
- self.connection.read_header()
+ # XXX
+ cli_major = 0
+ cli_minor = 10
+ self.connection.write_header(cli_major, cli_minor)
+ magic, _, _, major, minor = self.connection.read_header()
+ if not (magic == "AMQP" and major == cli_major and minor == cli_minor):
+ raise VersionError("client: %s-%s, server: %s-%s" %
+ (cli_major, cli_minor, major, minor))
def connection_start(self, ch, start):
- r = "\0%s\0%s" % (self.username, self.password)
- ch.connection_start_ok(client_properties=Client.PROPERTIES, mechanism=self.mechanism, response=r)
+ mech_list = ""
+ for mech in start.mechanisms:
+ if (not self.acceptableMechanisms) or mech in self.acceptableMechanisms:
+ mech_list += str(mech) + " "
+ mech = None
+ initial = None
+ if _have_sasl:
+ status, mech, initial = self.sasl.start(mech_list)
+ if status == False:
+ raise Closed("SASL error: %s" % self.sasl.getError())
+ else:
+ if self.username and self.password and ("PLAIN" in mech_list):
+ mech = "PLAIN"
+ initial = "\0%s\0%s" % (self.username, self.password)
+ else:
+ mech = "ANONYMOUS"
+ if not mech in mech_list:
+ raise Closed("No acceptable SASL authentication mechanism available")
+ ch.connection_start_ok(client_properties=Client.PROPERTIES, mechanism=mech, response=initial)
+
+ def connection_secure(self, ch, secure):
+ resp = None
+ if _have_sasl:
+ status, resp = self.sasl.step(secure.challenge)
+ if status == False:
+ raise Closed("SASL error: %s" % self.sasl.getError())
+ ch.connection_secure_ok(response=resp)
def connection_tune(self, ch, tune):
- ch.connection_tune_ok()
+ ch.connection_tune_ok(heartbeat=self.heartbeat)
ch.connection_open()
+ if _have_sasl:
+ self.connection.user_id = self.sasl.getUserId()
+ self.connection.security_layer_tx = self.sasl
def connection_open_ok(self, ch, open_ok):
+ if _have_sasl:
+ self.connection.security_layer_rx = self.sasl
self.connection.opened = True
notify(self.connection.condition)
+
+ def connection_heartbeat(self, ch, hrt):
+ ch.connection_heartbeat()
diff --git a/python/qpid/disp.py b/python/qpid/disp.py
index d697cd0136..1b315c9d98 100644
--- a/python/qpid/disp.py
+++ b/python/qpid/disp.py
@@ -21,16 +21,115 @@
from time import strftime, gmtime
+class Header:
+ """ """
+ NONE = 1
+ KMG = 2
+ YN = 3
+ Y = 4
+ TIME_LONG = 5
+ TIME_SHORT = 6
+ DURATION = 7
+
+ def __init__(self, text, format=NONE):
+ self.text = text
+ self.format = format
+
+ def __repr__(self):
+ return self.text
+
+ def __str__(self):
+ return self.text
+
+ def formatted(self, value):
+ try:
+ if value == None:
+ return ''
+ if self.format == Header.NONE:
+ return value
+ if self.format == Header.KMG:
+ return self.num(value)
+ if self.format == Header.YN:
+ if value:
+ return 'Y'
+ return 'N'
+ if self.format == Header.Y:
+ if value:
+ return 'Y'
+ return ''
+ if self.format == Header.TIME_LONG:
+ return strftime("%c", gmtime(value / 1000000000))
+ if self.format == Header.TIME_SHORT:
+ return strftime("%X", gmtime(value / 1000000000))
+ if self.format == Header.DURATION:
+ if value < 0: value = 0
+ sec = value / 1000000000
+ min = sec / 60
+ hour = min / 60
+ day = hour / 24
+ result = ""
+ if day > 0:
+ result = "%dd " % day
+ if hour > 0 or result != "":
+ result += "%dh " % (hour % 24)
+ if min > 0 or result != "":
+ result += "%dm " % (min % 60)
+ result += "%ds" % (sec % 60)
+ return result
+ except:
+ return "?"
+
+ def numCell(self, value, tag):
+ fp = float(value) / 1000.
+ if fp < 10.0:
+ return "%1.2f%c" % (fp, tag)
+ if fp < 100.0:
+ return "%2.1f%c" % (fp, tag)
+ return "%4d%c" % (value / 1000, tag)
+
+ def num(self, value):
+ if value < 1000:
+ return "%4d" % value
+ if value < 1000000:
+ return self.numCell(value, 'k')
+ value /= 1000
+ if value < 1000000:
+ return self.numCell(value, 'm')
+ value /= 1000
+ return self.numCell(value, 'g')
+
+
class Display:
""" Display formatting for QPID Management CLI """
- def __init__ (self):
- self.tableSpacing = 2
- self.tablePrefix = " "
+ def __init__(self, spacing=2, prefix=" "):
+ self.tableSpacing = spacing
+ self.tablePrefix = prefix
self.timestampFormat = "%X"
- def table (self, title, heads, rows):
- """ Print a formatted table with autosized columns """
+ def formattedTable(self, title, heads, rows):
+ fRows = []
+ for row in rows:
+ fRow = []
+ col = 0
+ for cell in row:
+ fRow.append(heads[col].formatted(cell))
+ col += 1
+ fRows.append(fRow)
+ headtext = []
+ for head in heads:
+ headtext.append(head.text)
+ self.table(title, headtext, fRows)
+
+ def table(self, title, heads, rows):
+ """ Print a table with autosized columns """
+
+ # Pad the rows to the number of heads
+ for row in rows:
+ diff = len(heads) - len(row)
+ for idx in range(diff):
+ row.append("")
+
print title
if len (rows) == 0:
return
@@ -40,7 +139,7 @@ class Display:
for head in heads:
width = len (head)
for row in rows:
- cellWidth = len (str (row[col]))
+ cellWidth = len (unicode (row[col]))
if cellWidth > width:
width = cellWidth
colWidth.append (width + self.tableSpacing)
@@ -60,9 +159,9 @@ class Display:
line = self.tablePrefix
col = 0
for width in colWidth:
- line = line + str (row[col])
+ line = line + unicode (row[col])
if col < len (heads) - 1:
- for i in range (width - len (str (row[col]))):
+ for i in range (width - len (unicode (row[col]))):
line = line + " "
col = col + 1
print line
@@ -77,3 +176,59 @@ class Display:
def timestamp (self, nsec):
""" Format a nanosecond-since-the-epoch timestamp for printing """
return strftime (self.timestampFormat, gmtime (nsec / 1000000000))
+
+ def duration(self, nsec):
+ if nsec < 0: nsec = 0
+ sec = nsec / 1000000000
+ min = sec / 60
+ hour = min / 60
+ day = hour / 24
+ result = ""
+ if day > 0:
+ result = "%dd " % day
+ if hour > 0 or result != "":
+ result += "%dh " % (hour % 24)
+ if min > 0 or result != "":
+ result += "%dm " % (min % 60)
+ result += "%ds" % (sec % 60)
+ return result
+
+class Sortable:
+ """ """
+ def __init__(self, row, sortIndex):
+ self.row = row
+ self.sortIndex = sortIndex
+ if sortIndex >= len(row):
+ raise Exception("sort index exceeds row boundary")
+
+ def __cmp__(self, other):
+ return cmp(self.row[self.sortIndex], other.row[self.sortIndex])
+
+ def getRow(self):
+ return self.row
+
+class Sorter:
+ """ """
+ def __init__(self, heads, rows, sortCol, limit=0, inc=True):
+ col = 0
+ for head in heads:
+ if head.text == sortCol:
+ break
+ col += 1
+ if col == len(heads):
+ raise Exception("sortCol '%s', not found in headers" % sortCol)
+
+ list = []
+ for row in rows:
+ list.append(Sortable(row, col))
+ list.sort(reverse=not inc)
+ count = 0
+ self.sorted = []
+ for row in list:
+ self.sorted.append(row.getRow())
+ count += 1
+ if count == limit:
+ break
+
+ def getSorted(self):
+ return self.sorted
diff --git a/python/qpid/driver.py b/python/qpid/driver.py
new file mode 100644
index 0000000000..2851c3aad3
--- /dev/null
+++ b/python/qpid/driver.py
@@ -0,0 +1,859 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import address, compat, connection, socket, struct, sys, time
+from concurrency import synchronized
+from datatypes import RangedSet, Serial
+from exceptions import Timeout, VersionError
+from framing import OpEncoder, SegmentEncoder, FrameEncoder, FrameDecoder, SegmentDecoder, OpDecoder
+from logging import getLogger
+from messaging import get_codec, ConnectError, Message, Pattern, UNLIMITED
+from ops import *
+from selector import Selector
+from threading import Condition, Thread
+from util import connect
+
+log = getLogger("qpid.messaging")
+rawlog = getLogger("qpid.messaging.io.raw")
+opslog = getLogger("qpid.messaging.io.ops")
+
+def addr2reply_to(addr):
+ name, subject, options = address.parse(addr)
+ return ReplyTo(name, subject)
+
+def reply_to2addr(reply_to):
+ if reply_to.routing_key is None:
+ return reply_to.exchange
+ elif reply_to.exchange in (None, ""):
+ return reply_to.routing_key
+ else:
+ return "%s/%s" % (reply_to.exchange, reply_to.routing_key)
+
+class Attachment:
+
+ def __init__(self, target):
+ self.target = target
+
+# XXX
+
+DURABLE_DEFAULT=True
+
+# XXX
+
+FILTER_DEFAULTS = {
+ "topic": Pattern("*")
+ }
+
+# XXX
+ppid = 0
+try:
+ ppid = os.getppid()
+except:
+ pass
+
+CLIENT_PROPERTIES = {"product": "qpid python client",
+ "version": "development",
+ "platform": os.name,
+ "qpid.client_process": os.path.basename(sys.argv[0]),
+ "qpid.client_pid": os.getpid(),
+ "qpid.client_ppid": ppid}
+
+def noop(): pass
+
+class SessionState:
+
+ def __init__(self, driver, session, name, channel):
+ self.driver = driver
+ self.session = session
+ self.name = name
+ self.channel = channel
+ self.detached = False
+ self.committing = False
+ self.aborting = False
+
+ # sender state
+ self.sent = Serial(0)
+ self.acknowledged = RangedSet()
+ self.actions = {}
+ self.min_completion = self.sent
+ self.max_completion = self.sent
+ self.results = {}
+
+ # receiver state
+ self.received = None
+ self.executed = RangedSet()
+
+ # XXX: need to periodically exchange completion/known_completion
+
+ def write_query(self, query, handler):
+ id = self.sent
+ self.write_cmd(query, lambda: handler(self.results.pop(id)))
+
+ def write_cmd(self, cmd, action=noop):
+ if action != noop:
+ cmd.sync = True
+ if self.detached:
+ raise Exception("detached")
+ cmd.id = self.sent
+ self.sent += 1
+ self.actions[cmd.id] = action
+ self.max_completion = cmd.id
+ self.write_op(cmd)
+
+ def write_op(self, op):
+ op.channel = self.channel
+ self.driver.write_op(op)
+
+# XXX
+HEADER="!4s4B"
+
+EMPTY_DP = DeliveryProperties()
+EMPTY_MP = MessageProperties()
+
+SUBJECT = "qpid.subject"
+TO = "qpid.to"
+
+class Driver:
+
+ def __init__(self, connection):
+ self.connection = connection
+ self._lock = self.connection._lock
+
+ self._selector = Selector.default()
+ self.reset()
+
+ def reset(self):
+ self._opening = False
+ self._closing = False
+ self._connected = False
+ self._attachments = {}
+
+ self._channel_max = 65536
+ self._channels = 0
+ self._sessions = {}
+
+ self._socket = None
+ self._buf = ""
+ self._hdr = ""
+ self._op_enc = OpEncoder()
+ self._seg_enc = SegmentEncoder()
+ self._frame_enc = FrameEncoder()
+ self._frame_dec = FrameDecoder()
+ self._seg_dec = SegmentDecoder()
+ self._op_dec = OpDecoder()
+ self._timeout = None
+
+ for ssn in self.connection.sessions.values():
+ for m in ssn.acked + ssn.unacked + ssn.incoming:
+ m._transfer_id = None
+ for snd in ssn.senders:
+ snd.linked = False
+ for rcv in ssn.receivers:
+ rcv.impending = rcv.received
+ rcv.linked = False
+
+ @synchronized
+ def wakeup(self):
+ self.dispatch()
+ self._selector.wakeup()
+
+ def start(self):
+ self._selector.register(self)
+
+ def fileno(self):
+ return self._socket.fileno()
+
+ @synchronized
+ def reading(self):
+ return self._socket is not None
+
+ @synchronized
+ def writing(self):
+ return self._socket is not None and self._buf
+
+ @synchronized
+ def timing(self):
+ return self._timeout
+
+ @synchronized
+ def readable(self):
+ error = None
+ recoverable = False
+ try:
+ data = self._socket.recv(64*1024)
+ if data:
+ rawlog.debug("READ: %r", data)
+ else:
+ rawlog.debug("ABORTED: %s", self._socket.getpeername())
+ error = "connection aborted"
+ recoverable = True
+ except socket.error, e:
+ error = e
+ recoverable = True
+
+ if not error:
+ try:
+ if len(self._hdr) < 8:
+ r = 8 - len(self._hdr)
+ self._hdr += data[:r]
+ data = data[r:]
+
+ if len(self._hdr) == 8:
+ self.do_header(self._hdr)
+
+ self._frame_dec.write(data)
+ self._seg_dec.write(*self._frame_dec.read())
+ self._op_dec.write(*self._seg_dec.read())
+ for op in self._op_dec.read():
+ self.assign_id(op)
+ opslog.debug("RCVD: %r", op)
+ op.dispatch(self)
+ except VersionError, e:
+ error = e
+ except:
+ msg = compat.format_exc()
+ error = msg
+
+ if error:
+ self._error(error, recoverable)
+ else:
+ self.dispatch()
+
+ self.connection._waiter.notifyAll()
+
+ def assign_id(self, op):
+ if isinstance(op, Command):
+ sst = self.get_sst(op)
+ op.id = sst.received
+ sst.received += 1
+
+ @synchronized
+ def writeable(self):
+ try:
+ n = self._socket.send(self._buf)
+ rawlog.debug("SENT: %r", self._buf[:n])
+ self._buf = self._buf[n:]
+ except socket.error, e:
+ self._error(e, True)
+ self.connection._waiter.notifyAll()
+
+ @synchronized
+ def timeout(self):
+ log.warn("retrying ...")
+ self.dispatch()
+ self.connection._waiter.notifyAll()
+
+ def _error(self, err, recoverable):
+ if self._socket is not None:
+ self._socket.close()
+ self.reset()
+ if recoverable and self.connection.reconnect:
+ self._timeout = time.time() + 3
+ log.warn("recoverable error: %s" % err)
+ log.warn("sleeping 3 seconds")
+ else:
+ self.connection.error = (err,)
+
+ def write_op(self, op):
+ opslog.debug("SENT: %r", op)
+ self._op_enc.write(op)
+ self._seg_enc.write(*self._op_enc.read())
+ self._frame_enc.write(*self._seg_enc.read())
+ self._buf += self._frame_enc.read()
+
+ def do_header(self, hdr):
+ cli_major = 0; cli_minor = 10
+ magic, _, _, major, minor = struct.unpack(HEADER, hdr)
+ if major != cli_major or minor != cli_minor:
+ raise VersionError("client: %s-%s, server: %s-%s" %
+ (cli_major, cli_minor, major, minor))
+
+ def do_connection_start(self, start):
+ # XXX: should we use some sort of callback for this?
+ r = "\0%s\0%s" % (self.connection.username, self.connection.password)
+ m = self.connection.mechanism
+ self.write_op(ConnectionStartOk(client_properties=CLIENT_PROPERTIES,
+ mechanism=m, response=r))
+
+ def do_connection_tune(self, tune):
+ # XXX: is heartbeat protocol specific?
+ if tune.channel_max is not None:
+ self.channel_max = tune.channel_max
+ self.write_op(ConnectionTuneOk(heartbeat=self.connection.heartbeat,
+ channel_max=self.channel_max))
+ self.write_op(ConnectionOpen())
+
+ def do_connection_open_ok(self, open_ok):
+ self._connected = True
+
+ def connection_heartbeat(self, hrt):
+ self.write_op(ConnectionHeartbeat())
+
+ def do_connection_close(self, close):
+ self.write_op(ConnectionCloseOk())
+ if close.reply_code != close_code.normal:
+ self.connection.error = (close.reply_code, close.reply_text)
+ # XXX: should we do a half shutdown on the socket here?
+ # XXX: we really need to test this, we may end up reporting a
+ # connection abort after this, if we were to do a shutdown on read
+ # and stop reading, then we wouldn't report the abort, that's
+ # probably the right thing to do
+
+ def do_connection_close_ok(self, close_ok):
+ self._socket.close()
+ self.reset()
+
+ def do_session_attached(self, atc):
+ pass
+
+ def do_session_command_point(self, cp):
+ sst = self.get_sst(cp)
+ sst.received = cp.command_id
+
+ def do_session_completed(self, sc):
+ sst = self.get_sst(sc)
+ for r in sc.commands:
+ sst.acknowledged.add(r.lower, r.upper)
+
+ if not sc.commands.empty():
+ while sst.min_completion in sc.commands:
+ if sst.actions.has_key(sst.min_completion):
+ sst.actions.pop(sst.min_completion)()
+ sst.min_completion += 1
+
+ def session_known_completed(self, kcmp):
+ sst = self.get_sst(kcmp)
+ executed = RangedSet()
+ for e in sst.executed.ranges:
+ for ke in kcmp.ranges:
+ if e.lower in ke and e.upper in ke:
+ break
+ else:
+ executed.add_range(e)
+ sst.executed = completed
+
+ def do_session_flush(self, sf):
+ sst = self.get_sst(sf)
+ if sf.expected:
+ if sst.received is None:
+ exp = None
+ else:
+ exp = RangedSet(sst.received)
+ sst.write_op(SessionExpected(exp))
+ if sf.confirmed:
+ sst.write_op(SessionConfirmed(sst.executed))
+ if sf.completed:
+ sst.write_op(SessionCompleted(sst.executed))
+
+ def do_execution_result(self, er):
+ sst = self.get_sst(er)
+ sst.results[er.command_id] = er.value
+
+ def do_execution_exception(self, ex):
+ sst = self.get_sst(ex)
+ sst.session.error = (ex,)
+
+ def dispatch(self):
+ try:
+ if self._socket is None and self.connection._connected and not self._opening:
+ self.connect()
+ elif self._socket is not None and not self.connection._connected and not self._closing:
+ self.disconnect()
+
+ if self._connected and not self._closing:
+ for ssn in self.connection.sessions.values():
+ self.attach(ssn)
+ self.process(ssn)
+ except:
+ msg = compat.format_exc()
+ self.connection.error = (msg,)
+
+ def connect(self):
+ try:
+ # XXX: should make this non blocking
+ self._socket = connect(self.connection.host, self.connection.port)
+ self._timeout = None
+ except socket.error, e:
+ if self.connection.reconnect:
+ self._error(e, True)
+ return
+ else:
+ raise e
+ self._buf += struct.pack(HEADER, "AMQP", 1, 1, 0, 10)
+ self._opening = True
+
+ def disconnect(self):
+ self.write_op(ConnectionClose(close_code.normal))
+ self._closing = True
+
+ def attach(self, ssn):
+ sst = self._attachments.get(ssn)
+ if sst is None and not ssn.closed:
+ for i in xrange(0, self.channel_max):
+ if not self._sessions.has_key(i):
+ ch = i
+ break
+ else:
+ raise RuntimeError("all channels used")
+ sst = SessionState(self, ssn, ssn.name, ch)
+ sst.write_op(SessionAttach(name=ssn.name))
+ sst.write_op(SessionCommandPoint(sst.sent, 0))
+ sst.outgoing_idx = 0
+ sst.acked = []
+ if ssn.transactional:
+ sst.write_cmd(TxSelect())
+ self._attachments[ssn] = sst
+ self._sessions[sst.channel] = sst
+
+ for snd in ssn.senders:
+ self.link_out(snd)
+ for rcv in ssn.receivers:
+ self.link_in(rcv)
+
+ if sst is not None and ssn.closing and not sst.detached:
+ sst.detached = True
+ sst.write_op(SessionDetach(name=ssn.name))
+
+ def get_sst(self, op):
+ return self._sessions[op.channel]
+
+ def do_session_detached(self, dtc):
+ sst = self._sessions.pop(dtc.channel)
+ ssn = sst.session
+ del self._attachments[ssn]
+ ssn.closed = True
+
+ def do_session_detach(self, dtc):
+ sst = self.get_sst(dtc)
+ sst.write_op(SessionDetached(name=dtc.name))
+ self.do_session_detached(dtc)
+
+ def link_out(self, snd):
+ sst = self._attachments.get(snd.session)
+ _snd = self._attachments.get(snd)
+ if _snd is None and not snd.closing and not snd.closed:
+ _snd = Attachment(snd)
+ _snd.closing = False
+
+ if snd.target is None:
+ snd.error = ("target is None",)
+ snd.closed = True
+ return
+
+ try:
+ _snd.name, _snd.subject, _snd.options = address.parse(snd.target)
+ except address.LexError, e:
+ snd.error = (e,)
+ snd.closed = True
+ return
+ except address.ParseError, e:
+ snd.error = (e,)
+ snd.closed = True
+ return
+
+ # XXX: subject
+ if _snd.options is None:
+ _snd.options = {}
+
+ def do_link(type, subtype):
+ if type == "topic":
+ _snd._exchange = _snd.name
+ _snd._routing_key = _snd.subject
+ elif type == "queue":
+ _snd._exchange = ""
+ _snd._routing_key = _snd.name
+
+ snd.linked = True
+
+ self.resolve_declare(sst, _snd, "sender", do_link)
+ self._attachments[snd] = _snd
+
+ if snd.linked and snd.closing and not (snd.closed or _snd.closing):
+ _snd.closing = True
+ def do_unlink():
+ del self._attachments[snd]
+ snd.closed = True
+ if _snd.options.get("delete") in ("always", "sender"):
+ self.delete(sst, _snd.name, do_unlink)
+ else:
+ do_unlink()
+
+ def link_in(self, rcv):
+ sst = self._attachments.get(rcv.session)
+ _rcv = self._attachments.get(rcv)
+ if _rcv is None and not rcv.closing and not rcv.closed:
+ _rcv = Attachment(rcv)
+ _rcv.canceled = False
+ _rcv.draining = False
+
+ if rcv.source is None:
+ rcv.error = ("source is None",)
+ rcv.closed = True
+ return
+
+ try:
+ _rcv.name, _rcv.subject, _rcv.options = address.parse(rcv.source)
+ except address.LexError, e:
+ rcv.error = (e,)
+ rcv.closed = True
+ return
+ except address.ParseError, e:
+ rcv.error = (e,)
+ rcv.closed = True
+ return
+
+ # XXX: subject
+ if _rcv.options is None:
+ _rcv.options = {}
+
+ def do_link(type, subtype):
+ if type == "topic":
+ _rcv._queue = "%s.%s" % (rcv.session.name, rcv.destination)
+ sst.write_cmd(QueueDeclare(queue=_rcv._queue, durable=DURABLE_DEFAULT, exclusive=True, auto_delete=True))
+ filter = _rcv.options.get("filter")
+ if _rcv.subject is None and filter is None:
+ f = FILTER_DEFAULTS[subtype]
+ elif _rcv.subject and filter:
+ # XXX
+ raise Exception("can't supply both subject and filter")
+ elif _rcv.subject:
+ # XXX
+ from messaging import Pattern
+ f = Pattern(_rcv.subject)
+ else:
+ f = filter
+ f._bind(sst, _rcv.name, _rcv._queue)
+ elif type == "queue":
+ _rcv._queue = _rcv.name
+
+ sst.write_cmd(MessageSubscribe(queue=_rcv._queue, destination=rcv.destination))
+ sst.write_cmd(MessageSetFlowMode(rcv.destination, flow_mode.credit))
+ rcv.linked = True
+
+ self.resolve_declare(sst, _rcv, "receiver", do_link)
+ self._attachments[rcv] = _rcv
+
+ if rcv.linked and rcv.closing and not rcv.closed:
+ if not _rcv.canceled:
+ def do_unlink():
+ del self._attachments[rcv]
+ rcv.closed = True
+ if _rcv.options.get("delete") in ("always", "receiver"):
+ sst.write_cmd(MessageCancel(rcv.destination))
+ self.delete(sst, _rcv.name, do_unlink)
+ else:
+ sst.write_cmd(MessageCancel(rcv.destination), do_unlink)
+ _rcv.canceled = True
+
+ def resolve_declare(self, sst, lnk, dir, action):
+ def do_resolved(er, qr):
+ if er.not_found and not qr.queue:
+ if lnk.options.get("create") in ("always", dir):
+ err = self.declare(sst, lnk.name, lnk.options, action)
+ else:
+ err = ("no such queue: %s" % lnk.name,)
+
+ if err:
+ tgt = lnk.target
+ tgt.error = err
+ del self._attachments[tgt]
+ tgt.closed = True
+ return
+ elif qr.queue:
+ action("queue", None)
+ else:
+ action("topic", er.type)
+ self.resolve(sst, lnk.name, do_resolved)
+
+ def resolve(self, sst, name, action):
+ args = []
+ def do_result(r):
+ args.append(r)
+ def do_action(r):
+ do_result(r)
+ action(*args)
+ sst.write_query(ExchangeQuery(name), do_result)
+ sst.write_query(QueueQuery(name), do_action)
+
+ def declare(self, sst, name, options, action):
+ opts = dict(options)
+ props = dict(opts.pop("node-properties", {}))
+ durable = props.pop("durable", DURABLE_DEFAULT)
+ type = props.pop("type", "queue")
+ xprops = dict(props.pop("x-properties", {}))
+
+ if props:
+ return ("unrecognized option(s): %s" % "".join(props.keys()),)
+
+ if type == "topic":
+ cmd = ExchangeDeclare(exchange=name, durable=durable)
+ elif type == "queue":
+ cmd = QueueDeclare(queue=name, durable=durable)
+ bindings = xprops.pop("bindings", [])
+ else:
+ return ("unrecognized type, must be topic or queue: %s" % type,)
+
+ for f in cmd.FIELDS:
+ if f.name != "arguments" and xprops.has_key(f.name):
+ cmd[f.name] = xprops.pop(f.name)
+ if xprops:
+ cmd.arguments = xprops
+
+ if type == "topic":
+ if cmd.type is None:
+ cmd.type = "topic"
+ subtype = cmd.type
+ else:
+ subtype = None
+
+ cmds = [cmd]
+ if type == "queue":
+ for b in bindings:
+ try:
+ n, s, o = address.parse(b)
+ except address.ParseError, e:
+ return (e,)
+ cmds.append(ExchangeBind(name, n, s, o))
+
+ for c in cmds[:-1]:
+ sst.write_cmd(c)
+ def do_action():
+ action(type, subtype)
+ sst.write_cmd(cmds[-1], do_action)
+
+ def delete(self, sst, name, action):
+ def do_delete(er, qr):
+ if not er.not_found:
+ sst.write_cmd(ExchangeDelete(name), action)
+ elif qr.queue:
+ sst.write_cmd(QueueDelete(name), action)
+ else:
+ action()
+ self.resolve(sst, name, do_delete)
+
+ def process(self, ssn):
+ if ssn.closed or ssn.closing: return
+
+ sst = self._attachments[ssn]
+
+ while sst.outgoing_idx < len(ssn.outgoing):
+ msg = ssn.outgoing[sst.outgoing_idx]
+ snd = msg._sender
+ # XXX: should check for sender error here
+ _snd = self._attachments.get(snd)
+ if _snd and snd.linked:
+ self.send(snd, msg)
+ sst.outgoing_idx += 1
+ else:
+ break
+
+ for rcv in ssn.receivers:
+ self.process_receiver(rcv)
+
+ if ssn.acked:
+ messages = [m for m in ssn.acked if m not in sst.acked]
+ if messages:
+ # XXX: we're ignoring acks that get lost when disconnected,
+ # could we deal this via some message-id based purge?
+ ids = RangedSet(*[m._transfer_id for m in messages if m._transfer_id is not None])
+ for range in ids:
+ sst.executed.add_range(range)
+ sst.write_op(SessionCompleted(sst.executed))
+ def ack_ack():
+ for m in messages:
+ ssn.acked.remove(m)
+ if not ssn.transactional:
+ sst.acked.remove(m)
+ sst.write_cmd(MessageAccept(ids), ack_ack)
+ sst.acked.extend(messages)
+
+ if ssn.committing and not sst.committing:
+ def commit_ok():
+ del sst.acked[:]
+ ssn.committing = False
+ ssn.committed = True
+ ssn.aborting = False
+ ssn.aborted = False
+ sst.write_cmd(TxCommit(), commit_ok)
+ sst.committing = True
+
+ if ssn.aborting and not sst.aborting:
+ sst.aborting = True
+ def do_rb():
+ messages = sst.acked + ssn.unacked + ssn.incoming
+ ids = RangedSet(*[m._transfer_id for m in messages])
+ for range in ids:
+ sst.executed.add_range(range)
+ sst.write_op(SessionCompleted(sst.executed))
+ sst.write_cmd(MessageRelease(ids))
+ sst.write_cmd(TxRollback(), do_rb_ok)
+
+ def do_rb_ok():
+ del ssn.incoming[:]
+ del ssn.unacked[:]
+ del sst.acked[:]
+
+ for rcv in ssn.receivers:
+ rcv.impending = rcv.received
+ rcv.returned = rcv.received
+ # XXX: do we need to update granted here as well?
+
+ for rcv in ssn.receivers:
+ self.process_receiver(rcv)
+
+ ssn.aborting = False
+ ssn.aborted = True
+ ssn.committing = False
+ ssn.committed = False
+ sst.aborting = False
+
+ for rcv in ssn.receivers:
+ sst.write_cmd(MessageStop(rcv.destination))
+ sst.write_cmd(ExecutionSync(), do_rb)
+
+ def grant(self, rcv):
+ sst = self._attachments[rcv.session]
+ _rcv = self._attachments.get(rcv)
+ if _rcv is None or not rcv.linked or _rcv.canceled or _rcv.draining:
+ return
+
+ if rcv.granted is UNLIMITED:
+ if rcv.impending is UNLIMITED:
+ delta = 0
+ else:
+ delta = UNLIMITED
+ elif rcv.impending is UNLIMITED:
+ delta = -1
+ else:
+ delta = max(rcv.granted, rcv.received) - rcv.impending
+
+ if delta is UNLIMITED:
+ sst.write_cmd(MessageFlow(rcv.destination, credit_unit.byte, UNLIMITED.value))
+ sst.write_cmd(MessageFlow(rcv.destination, credit_unit.message, UNLIMITED.value))
+ rcv.impending = UNLIMITED
+ elif delta > 0:
+ sst.write_cmd(MessageFlow(rcv.destination, credit_unit.byte, UNLIMITED.value))
+ sst.write_cmd(MessageFlow(rcv.destination, credit_unit.message, delta))
+ rcv.impending += delta
+ elif delta < 0 and not rcv.draining:
+ _rcv.draining = True
+ def do_stop():
+ rcv.impending = rcv.received
+ _rcv.draining = False
+ self.grant(rcv)
+ sst.write_cmd(MessageStop(rcv.destination), do_stop)
+
+ if rcv.draining:
+ _rcv.draining = True
+ def do_flush():
+ rcv.impending = rcv.received
+ rcv.granted = rcv.impending
+ _rcv.draining = False
+ rcv.draining = False
+ sst.write_cmd(MessageFlush(rcv.destination), do_flush)
+
+
+ def process_receiver(self, rcv):
+ if rcv.closed: return
+ self.grant(rcv)
+
+ def send(self, snd, msg):
+ sst = self._attachments[snd.session]
+ _snd = self._attachments[snd]
+
+ # XXX: what if subject is specified for a normal queue?
+ if _snd._routing_key is None:
+ rk = msg.subject
+ else:
+ rk = _snd._routing_key
+ # XXX: do we need to query to figure out how to create the reply-to interoperably?
+ if msg.reply_to:
+ rt = addr2reply_to(msg.reply_to)
+ else:
+ rt = None
+ dp = DeliveryProperties(routing_key=rk)
+ mp = MessageProperties(message_id=msg.id,
+ user_id=msg.user_id,
+ reply_to=rt,
+ correlation_id=msg.correlation_id,
+ content_type=msg.content_type,
+ application_headers=msg.properties)
+ if msg.subject is not None:
+ if mp.application_headers is None:
+ mp.application_headers = {}
+ mp.application_headers[SUBJECT] = msg.subject
+ if msg.to is not None:
+ if mp.application_headers is None:
+ mp.application_headers = {}
+ mp.application_headers[TO] = msg.to
+ if msg.durable:
+ dp.delivery_mode = delivery_mode.persistent
+ enc, dec = get_codec(msg.content_type)
+ body = enc(msg.content)
+ def msg_acked():
+ # XXX: should we log the ack somehow too?
+ snd.acked += 1
+ m = snd.session.outgoing.pop(0)
+ sst.outgoing_idx -= 1
+ assert msg == m
+ sst.write_cmd(MessageTransfer(destination=_snd._exchange, headers=(dp, mp),
+ payload=body), msg_acked)
+
+ def do_message_transfer(self, xfr):
+ sst = self.get_sst(xfr)
+ ssn = sst.session
+
+ msg = self._decode(xfr)
+ rcv = ssn.receivers[int(xfr.destination)]
+ msg._receiver = rcv
+ if rcv.impending is not UNLIMITED:
+ assert rcv.received < rcv.impending, "%s, %s" % (rcv.received, rcv.impending)
+ rcv.received += 1
+ log.debug("RECV [%s] %s", ssn, msg)
+ ssn.incoming.append(msg)
+ self.connection._waiter.notifyAll()
+
+ def _decode(self, xfr):
+ dp = EMPTY_DP
+ mp = EMPTY_MP
+
+ for h in xfr.headers:
+ if isinstance(h, DeliveryProperties):
+ dp = h
+ elif isinstance(h, MessageProperties):
+ mp = h
+
+ ap = mp.application_headers
+ enc, dec = get_codec(mp.content_type)
+ content = dec(xfr.payload)
+ msg = Message(content)
+ msg.id = mp.message_id
+ if ap is not None:
+ msg.to = ap.get(TO)
+ msg.subject = ap.get(SUBJECT)
+ msg.user_id = mp.user_id
+ if mp.reply_to is not None:
+ msg.reply_to = reply_to2addr(mp.reply_to)
+ msg.correlation_id = mp.correlation_id
+ msg.durable = dp.delivery_mode == delivery_mode.persistent
+ msg.redelivered = dp.redelivered
+ msg.properties = mp.application_headers
+ msg.content_type = mp.content_type
+ msg._transfer_id = xfr.id
+ return msg
diff --git a/python/qpid/exceptions.py b/python/qpid/exceptions.py
index 7eaaf81ed4..2bd80b7ffe 100644
--- a/python/qpid/exceptions.py
+++ b/python/qpid/exceptions.py
@@ -19,3 +19,4 @@
class Closed(Exception): pass
class Timeout(Exception): pass
+class VersionError(Exception): pass
diff --git a/python/qpid/framer.py b/python/qpid/framer.py
index f6363b2291..47f57cf649 100644
--- a/python/qpid/framer.py
+++ b/python/qpid/framer.py
@@ -26,47 +26,6 @@ from logging import getLogger
raw = getLogger("qpid.io.raw")
frm = getLogger("qpid.io.frm")
-FIRST_SEG = 0x08
-LAST_SEG = 0x04
-FIRST_FRM = 0x02
-LAST_FRM = 0x01
-
-class Frame:
-
- HEADER = "!2BHxBH4x"
- MAX_PAYLOAD = 65535 - struct.calcsize(HEADER)
-
- def __init__(self, flags, type, track, channel, payload):
- if len(payload) > Frame.MAX_PAYLOAD:
- raise ValueError("max payload size exceeded: %s" % len(payload))
- self.flags = flags
- self.type = type
- self.track = track
- self.channel = channel
- self.payload = payload
-
- def isFirstSegment(self):
- return bool(FIRST_SEG & self.flags)
-
- def isLastSegment(self):
- return bool(LAST_SEG & self.flags)
-
- def isFirstFrame(self):
- return bool(FIRST_FRM & self.flags)
-
- def isLastFrame(self):
- return bool(LAST_FRM & self.flags)
-
- def __str__(self):
- return "%s%s%s%s %s %s %s %r" % (int(self.isFirstSegment()),
- int(self.isLastSegment()),
- int(self.isFirstFrame()),
- int(self.isLastFrame()),
- self.type,
- self.track,
- self.channel,
- self.payload)
-
class FramingError(Exception): pass
class Framer(Packer):
@@ -76,19 +35,29 @@ class Framer(Packer):
def __init__(self, sock):
self.sock = sock
self.sock_lock = RLock()
- self._buf = ""
+ self.tx_buf = ""
+ self.rx_buf = ""
+ self.security_layer_tx = None
+ self.security_layer_rx = None
+ self.maxbufsize = 65535
def aborted(self):
return False
def write(self, buf):
- self._buf += buf
+ self.tx_buf += buf
def flush(self):
self.sock_lock.acquire()
try:
- self._write(self._buf)
- self._buf = ""
+ if self.security_layer_tx:
+ status, cipher_buf = self.security_layer_tx.encode(self.tx_buf)
+ if status == False:
+ raise Closed(self.security_layer_tx.getError())
+ self._write(cipher_buf)
+ else:
+ self._write(self.tx_buf)
+ self.tx_buf = ""
frm.debug("FLUSHED")
finally:
self.sock_lock.release()
@@ -105,25 +74,42 @@ class Framer(Packer):
raw.debug("SENT %r", buf[:n])
buf = buf[n:]
+ ##
+ ## Implementation Note:
+ ##
+ ## This function was modified to use the SASL security layer for content
+ ## decryption. As such, the socket read should read in "self.maxbufsize"
+ ## instead of "n" (the requested number of octets). However, since this
+ ## is one of two places in the code where the socket is read, the read
+ ## size had to be left at "n". This is because this function is
+ ## apparently only used to read the first 8 octets from a TCP socket. If
+ ## we read beyond "n" octets, the remaing octets won't be processed and
+ ## the connection handshake will fail.
+ ##
def read(self, n):
- data = ""
- while len(data) < n:
+ while len(self.rx_buf) < n:
try:
- s = self.sock.recv(n - len(data))
+ s = self.sock.recv(n) # NOTE: instead of "n", arg should be "self.maxbufsize"
+ if self.security_layer_rx:
+ status, s = self.security_layer_rx.decode(s)
+ if status == False:
+ raise Closed(self.security_layer_tx.getError())
except socket.timeout:
if self.aborted():
raise Closed()
else:
continue
except socket.error, e:
- if data != "":
+ if self.rx_buf != "":
raise e
else:
raise Closed()
if len(s) == 0:
raise Closed()
- data += s
+ self.rx_buf += s
raw.debug("RECV %r", s)
+ data = self.rx_buf[0:n]
+ self.rx_buf = self.rx_buf[n:]
return data
def read_header(self):
@@ -136,24 +122,3 @@ class Framer(Packer):
self.flush()
finally:
self.sock_lock.release()
-
- def write_frame(self, frame):
- self.sock_lock.acquire()
- try:
- size = len(frame.payload) + struct.calcsize(Frame.HEADER)
- track = frame.track & 0x0F
- self.pack(Frame.HEADER, frame.flags, frame.type, size, track, frame.channel)
- self.write(frame.payload)
- if frame.isLastSegment() and frame.isLastFrame():
- self.flush()
- frm.debug("SENT %s", frame)
- finally:
- self.sock_lock.release()
-
- def read_frame(self):
- flags, type, size, track, channel = self.unpack(Frame.HEADER)
- if flags & 0xF0: raise FramingError()
- payload = self.read(size - struct.calcsize(Frame.HEADER))
- frame = Frame(flags, type, track, channel, payload)
- frm.debug("RECV %s", frame)
- return frame
diff --git a/python/qpid/framing.py b/python/qpid/framing.py
new file mode 100644
index 0000000000..0a8f26272c
--- /dev/null
+++ b/python/qpid/framing.py
@@ -0,0 +1,310 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import struct
+
+FIRST_SEG = 0x08
+LAST_SEG = 0x04
+FIRST_FRM = 0x02
+LAST_FRM = 0x01
+
+class Frame:
+
+ HEADER = "!2BHxBH4x"
+ HEADER_SIZE = struct.calcsize(HEADER)
+ MAX_PAYLOAD = 65535 - struct.calcsize(HEADER)
+
+ def __init__(self, flags, type, track, channel, payload):
+ if len(payload) > Frame.MAX_PAYLOAD:
+ raise ValueError("max payload size exceeded: %s" % len(payload))
+ self.flags = flags
+ self.type = type
+ self.track = track
+ self.channel = channel
+ self.payload = payload
+
+ def isFirstSegment(self):
+ return bool(FIRST_SEG & self.flags)
+
+ def isLastSegment(self):
+ return bool(LAST_SEG & self.flags)
+
+ def isFirstFrame(self):
+ return bool(FIRST_FRM & self.flags)
+
+ def isLastFrame(self):
+ return bool(LAST_FRM & self.flags)
+
+ def __repr__(self):
+ return "%s%s%s%s %s %s %s %r" % (int(self.isFirstSegment()),
+ int(self.isLastSegment()),
+ int(self.isFirstFrame()),
+ int(self.isLastFrame()),
+ self.type,
+ self.track,
+ self.channel,
+ self.payload)
+
+class Segment:
+
+ def __init__(self, first, last, type, track, channel, payload):
+ self.id = None
+ self.offset = None
+ self.first = first
+ self.last = last
+ self.type = type
+ self.track = track
+ self.channel = channel
+ self.payload = payload
+
+ def __repr__(self):
+ return "%s%s %s %s %s %r" % (int(self.first), int(self.last), self.type,
+ self.track, self.channel, self.payload)
+
+class FrameDecoder:
+
+ def __init__(self):
+ self.input = ""
+ self.output = []
+ self.parse = self.__frame_header
+
+ def write(self, bytes):
+ self.input += bytes
+ while True:
+ next = self.parse()
+ if next is None:
+ break
+ else:
+ self.parse = next
+
+ def __consume(self, n):
+ result = self.input[:n]
+ self.input = self.input[n:]
+ return result
+
+ def __frame_header(self):
+ if len(self.input) >= Frame.HEADER_SIZE:
+ st = self.__consume(Frame.HEADER_SIZE)
+ self.flags, self.type, self.size, self.track, self.channel = \
+ struct.unpack(Frame.HEADER, st)
+ return self.__frame_body
+
+ def __frame_body(self):
+ size = self.size - Frame.HEADER_SIZE
+ if len(self.input) >= size:
+ payload = self.__consume(size)
+ frame = Frame(self.flags, self.type, self.track, self.channel, payload)
+ self.output.append(frame)
+ return self.__frame_header
+
+ def read(self):
+ result = self.output
+ self.output = []
+ return result
+
+class FrameEncoder:
+
+ def __init__(self):
+ self.output = ""
+
+ def write(self, *frames):
+ for frame in frames:
+ size = len(frame.payload) + Frame.HEADER_SIZE
+ track = frame.track & 0x0F
+ self.output += struct.pack(Frame.HEADER, frame.flags, frame.type, size,
+ track, frame.channel)
+ self.output += frame.payload
+
+ def read(self):
+ result = self.output
+ self.output = ""
+ return result
+
+class SegmentDecoder:
+
+ def __init__(self):
+ self.fragments = {}
+ self.segments = []
+
+ def write(self, *frames):
+ for frm in frames:
+ key = (frm.channel, frm.track)
+ seg = self.fragments.get(key)
+
+ if seg == None:
+ seg = Segment(frm.isFirstSegment(), frm.isLastSegment(),
+ frm.type, frm.track, frm.channel, "")
+ self.fragments[key] = seg
+
+ seg.payload += frm.payload
+
+ if frm.isLastFrame():
+ self.fragments.pop(key)
+ self.segments.append(seg)
+
+ def read(self):
+ result = self.segments
+ self.segments = []
+ return result
+
+class SegmentEncoder:
+
+ def __init__(self, max_payload=Frame.MAX_PAYLOAD):
+ self.max_payload = max_payload
+ self.frames = []
+
+ def write(self, *segments):
+ for seg in segments:
+ remaining = seg.payload
+
+ first = True
+ while first or remaining:
+ payload = remaining[:self.max_payload]
+ remaining = remaining[self.max_payload:]
+
+ flags = 0
+ if first:
+ flags |= FIRST_FRM
+ first = False
+ if not remaining:
+ flags |= LAST_FRM
+ if seg.first:
+ flags |= FIRST_SEG
+ if seg.last:
+ flags |= LAST_SEG
+
+ frm = Frame(flags, seg.type, seg.track, seg.channel, payload)
+ self.frames.append(frm)
+
+ def read(self):
+ result = self.frames
+ self.frames = []
+ return result
+
+from ops import COMMANDS, CONTROLS, COMPOUND, Header, segment_type, track
+from spec import SPEC
+
+from codec010 import StringCodec
+
+class OpEncoder:
+
+ def __init__(self):
+ self.segments = []
+
+ def write(self, *ops):
+ for op in ops:
+ if COMMANDS.has_key(op.NAME):
+ seg_type = segment_type.command
+ seg_track = track.command
+ enc = self.encode_command(op)
+ elif CONTROLS.has_key(op.NAME):
+ seg_type = segment_type.control
+ seg_track = track.control
+ enc = self.encode_compound(op)
+ else:
+ raise ValueError(op)
+ seg = Segment(True, False, seg_type, seg_track, op.channel, enc)
+ self.segments.append(seg)
+ if hasattr(op, "headers") and op.headers is not None:
+ hdrs = ""
+ for h in op.headers:
+ hdrs += self.encode_compound(h)
+ seg = Segment(False, False, segment_type.header, seg_track, op.channel,
+ hdrs)
+ self.segments.append(seg)
+ if hasattr(op, "payload") and op.payload is not None:
+ self.segments.append(Segment(False, False, segment_type.body, seg_track,
+ op.channel, op.payload))
+ self.segments[-1].last = True
+
+ def encode_command(self, cmd):
+ sc = StringCodec()
+ sc.write_uint16(cmd.CODE)
+ sc.write_compound(Header(sync=cmd.sync))
+ sc.write_fields(cmd)
+ return sc.encoded
+
+ def encode_compound(self, op):
+ sc = StringCodec()
+ sc.write_compound(op)
+ return sc.encoded
+
+ def read(self):
+ result = self.segments
+ self.segments = []
+ return result
+
+class OpDecoder:
+
+ def __init__(self):
+ self.op = None
+ self.ops = []
+
+ def write(self, *segments):
+ for seg in segments:
+ if seg.first:
+ if seg.type == segment_type.command:
+ self.op = self.decode_command(seg.payload)
+ elif seg.type == segment_type.control:
+ self.op = self.decode_control(seg.payload)
+ else:
+ raise ValueError(seg)
+ self.op.channel = seg.channel
+ elif seg.type == segment_type.header:
+ if self.op.headers is None:
+ self.op.headers = []
+ self.op.headers.extend(self.decode_headers(seg.payload))
+ elif seg.type == segment_type.body:
+ if self.op.payload is None:
+ self.op.payload = seg.payload
+ else:
+ self.op.payload += seg.payload
+ if seg.last:
+ self.ops.append(self.op)
+ self.op = None
+
+ def decode_command(self, encoded):
+ sc = StringCodec(encoded)
+ code = sc.read_uint16()
+ cls = COMMANDS[code]
+ hdr = sc.read_compound(Header)
+ cmd = cls()
+ sc.read_fields(cmd)
+ cmd.sync = hdr.sync
+ return cmd
+
+ def decode_control(self, encoded):
+ sc = StringCodec(encoded)
+ code = sc.read_uint16()
+ cls = CONTROLS[code]
+ ctl = cls()
+ sc.read_fields(ctl)
+ return ctl
+
+ def decode_headers(self, encoded):
+ sc = StringCodec(encoded)
+ result = []
+ while sc.encoded:
+ result.append(sc.read_struct32())
+ return result
+
+ def read(self):
+ result = self.ops
+ self.ops = []
+ return result
diff --git a/python/qpid/generator.py b/python/qpid/generator.py
new file mode 100644
index 0000000000..02d11e5005
--- /dev/null
+++ b/python/qpid/generator.py
@@ -0,0 +1,56 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import sys
+
+from ops import *
+
+def METHOD(module, op):
+ method = lambda self, *args, **kwargs: self.invoke(op, args, kwargs)
+ if sys.version_info[:2] > (2, 3):
+ method.__name__ = op.__name__
+ method.__doc__ = op.__doc__
+ method.__module__ = module
+ return method
+
+def generate(module, operations):
+ dict = {}
+
+ for name, enum in ENUMS.items():
+ if isinstance(name, basestring):
+ dict[name] = enum
+
+ for name, op in COMPOUND.items():
+ if isinstance(name, basestring):
+ dict[name] = METHOD(module, op)
+
+ for name, op in operations.items():
+ if isinstance(name, basestring):
+ dict[name] = METHOD(module, op)
+
+ return dict
+
+def invoker(name, operations):
+ return type(name, (), generate(invoker.__module__, operations))
+
+def command_invoker():
+ return invoker("CommandInvoker", COMMANDS)
+
+def control_invoker():
+ return invoker("ControlInvoker", CONTROLS)
diff --git a/python/qpid/harness.py b/python/qpid/harness.py
new file mode 100644
index 0000000000..ce48481612
--- /dev/null
+++ b/python/qpid/harness.py
@@ -0,0 +1,20 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+class Skipped(Exception): pass
diff --git a/python/qpid/invoker.py b/python/qpid/invoker.py
deleted file mode 100644
index 635f3ee769..0000000000
--- a/python/qpid/invoker.py
+++ /dev/null
@@ -1,48 +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.
-#
-
-import sys
-
-# TODO: need a better naming for this class now that it does the value
-# stuff
-class Invoker:
-
- def METHOD(self, name, resolved):
- method = lambda *args, **kwargs: self.invoke(resolved, args, kwargs)
- if sys.version_info[:2] > (2, 3):
- method.__name__ = resolved.pyname
- method.__doc__ = resolved.pydoc
- method.__module__ = self.__class__.__module__
- self.__dict__[name] = method
- return method
-
- def VALUE(self, name, resolved):
- self.__dict__[name] = resolved
- return resolved
-
- def ERROR(self, name, resolved):
- raise AttributeError("%s instance has no attribute '%s'" %
- (self.__class__.__name__, name))
-
- def resolve_method(self, name):
- return ERROR, None
-
- def __getattr__(self, name):
- disp, resolved = self.resolve_method(name)
- return disp(name, resolved)
diff --git a/python/qpid/lexer.py b/python/qpid/lexer.py
new file mode 100644
index 0000000000..87845560eb
--- /dev/null
+++ b/python/qpid/lexer.py
@@ -0,0 +1,112 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+import re
+
+class Type:
+
+ def __init__(self, name, pattern=None):
+ self.name = name
+ self.pattern = pattern
+
+ def __repr__(self):
+ return self.name
+
+class Lexicon:
+
+ def __init__(self):
+ self.types = []
+ self._eof = None
+
+ def define(self, name, pattern):
+ t = Type(name, pattern)
+ self.types.append(t)
+ return t
+
+ def eof(self, name):
+ t = Type(name)
+ self._eof = t
+ return t
+
+ def compile(self):
+ types = self.types[:]
+ joined = "|".join(["(%s)" % t.pattern for t in types])
+ rexp = re.compile(joined)
+ return Lexer(types, self._eof, rexp)
+
+class Token:
+
+ def __init__(self, type, value, input, position):
+ self.type = type
+ self.value = value
+ self.input = input
+ self.position = position
+
+ def line_info(self):
+ return line_info(self.input, self.position)
+
+ def __repr__(self):
+ if self.value is None:
+ return repr(self.type)
+ else:
+ return "%s(%r)" % (self.type, self.value)
+
+
+class LexError(Exception):
+ pass
+
+def line_info(st, pos):
+ idx = 0
+ lineno = 1
+ column = 0
+ line_pos = 0
+ while idx < pos:
+ if st[idx] == "\n":
+ lineno += 1
+ column = 0
+ line_pos = idx
+ column += 1
+ idx += 1
+
+ end = st.find("\n", line_pos)
+ if end < 0:
+ end = len(st)
+ line = st[line_pos:end]
+
+ return line, lineno, column
+
+class Lexer:
+
+ def __init__(self, types, eof, rexp):
+ self.types = types
+ self.eof = eof
+ self.rexp = rexp
+
+ def lex(self, st):
+ pos = 0
+ while pos < len(st):
+ m = self.rexp.match(st, pos)
+ if m is None:
+ line, ln, col = line_info(st, pos)
+ raise LexError("unrecognized characters line:%s,%s: %s" % (ln, col, line))
+ else:
+ idx = m.lastindex
+ t = Token(self.types[idx - 1], m.group(idx), st, pos)
+ yield t
+ pos = m.end()
+ yield Token(self.eof, None, st, pos)
diff --git a/python/qpid/management.py b/python/qpid/management.py
index 83c29a78a5..325ab4903d 100644
--- a/python/qpid/management.py
+++ b/python/qpid/management.py
@@ -17,6 +17,10 @@
# under the License.
#
+###############################################################################
+## This file is being obsoleted by qmf/console.py
+###############################################################################
+
"""
Management API for Qpid
"""
@@ -69,6 +73,57 @@ class mgmtObject (object):
for cell in row:
setattr (self, cell[0], cell[1])
+class objectId(object):
+ """ Object that represents QMF object identifiers """
+
+ def __init__(self, codec, first=0, second=0):
+ if codec:
+ self.first = codec.read_uint64()
+ self.second = codec.read_uint64()
+ else:
+ self.first = first
+ self.second = second
+
+ def __cmp__(self, other):
+ if other == None:
+ return 1
+ if self.first < other.first:
+ return -1
+ if self.first > other.first:
+ return 1
+ if self.second < other.second:
+ return -1
+ if self.second > other.second:
+ return 1
+ return 0
+
+
+ def index(self):
+ return (self.first, self.second)
+
+ def getFlags(self):
+ return (self.first & 0xF000000000000000) >> 60
+
+ def getSequence(self):
+ return (self.first & 0x0FFF000000000000) >> 48
+
+ def getBroker(self):
+ return (self.first & 0x0000FFFFF0000000) >> 28
+
+ def getBank(self):
+ return self.first & 0x000000000FFFFFFF
+
+ def getObject(self):
+ return self.second
+
+ def isDurable(self):
+ return self.getSequence() == 0
+
+ def encode(self, codec):
+ codec.write_uint64(self.first)
+ codec.write_uint64(self.second)
+
+
class methodResult:
""" Object that contains the result of a method call """
@@ -111,19 +166,23 @@ class managementChannel:
ssn.exchange_bind (exchange="amq.direct",
queue=self.replyName, binding_key=self.replyName)
- ssn.message_subscribe (queue=self.topicName, destination="tdest")
- ssn.message_subscribe (queue=self.replyName, destination="rdest")
+ ssn.message_subscribe (queue=self.topicName, destination="tdest",
+ accept_mode=ssn.accept_mode.none,
+ acquire_mode=ssn.acquire_mode.pre_acquired)
+ ssn.message_subscribe (queue=self.replyName, destination="rdest",
+ accept_mode=ssn.accept_mode.none,
+ acquire_mode=ssn.acquire_mode.pre_acquired)
ssn.incoming ("tdest").listen (self.topicCb, self.exceptionCb)
ssn.incoming ("rdest").listen (self.replyCb)
ssn.message_set_flow_mode (destination="tdest", flow_mode=1)
- ssn.message_flow (destination="tdest", unit=0, value=0xFFFFFFFF)
- ssn.message_flow (destination="tdest", unit=1, value=0xFFFFFFFF)
+ ssn.message_flow (destination="tdest", unit=0, value=0xFFFFFFFFL)
+ ssn.message_flow (destination="tdest", unit=1, value=0xFFFFFFFFL)
ssn.message_set_flow_mode (destination="rdest", flow_mode=1)
- ssn.message_flow (destination="rdest", unit=0, value=0xFFFFFFFF)
- ssn.message_flow (destination="rdest", unit=1, value=0xFFFFFFFF)
+ ssn.message_flow (destination="rdest", unit=0, value=0xFFFFFFFFL)
+ ssn.message_flow (destination="rdest", unit=1, value=0xFFFFFFFFL)
def setBrokerInfo (self, data):
self.brokerInfo = data
@@ -151,9 +210,6 @@ class managementChannel:
if self.enabled:
self.qpidChannel.message_transfer (destination=exchange, message=msg)
- def accept (self, msg):
- self.qpidChannel.message_accept(RangedSet(msg.id))
-
def message (self, body, routing_key="broker"):
dp = self.qpidChannel.delivery_properties()
dp.routing_key = routing_key
@@ -178,8 +234,7 @@ class managementClient:
#========================================================
# User API - interacts with the class's user
#========================================================
- def __init__ (self, amqpSpec, ctrlCb=None, configCb=None, instCb=None, methodCb=None, closeCb=None):
- self.spec = amqpSpec
+ def __init__ (self, unused=None, ctrlCb=None, configCb=None, instCb=None, methodCb=None, closeCb=None):
self.ctrlCb = ctrlCb
self.configCb = configCb
self.instCb = instCb
@@ -212,7 +267,7 @@ class managementClient:
self.channels.append (mch)
self.incOutstanding (mch)
- codec = Codec (self.spec)
+ codec = Codec ()
self.setHeader (codec, ord ('B'))
msg = mch.message(codec.encoded)
mch.send ("qpid.management", msg)
@@ -229,12 +284,12 @@ class managementClient:
def getObjects (self, channel, userSequence, className, bank=0):
""" Request immediate content from broker """
- codec = Codec (self.spec)
+ codec = Codec ()
self.setHeader (codec, ord ('G'), userSequence)
ft = {}
ft["_class"] = className
codec.write_map (ft)
- msg = channel.message(codec.encoded, routing_key="agent.%d" % bank)
+ msg = channel.message(codec.encoded, routing_key="agent.1.%d" % bank)
channel.send ("qpid.management", msg)
def syncWaitForStable (self, channel):
@@ -297,27 +352,28 @@ class managementClient:
#========================================================
def topicCb (self, ch, msg):
""" Receive messages via the topic queue of a particular channel. """
- codec = Codec (self.spec, msg.body)
- hdr = self.checkHeader (codec)
- if hdr == None:
- raise ValueError ("outer header invalid");
+ codec = Codec (msg.body)
+ while True:
+ hdr = self.checkHeader (codec)
+ if hdr == None:
+ return
- if hdr[0] == 'p':
- self.handlePackageInd (ch, codec)
- elif hdr[0] == 'q':
- self.handleClassInd (ch, codec)
- elif hdr[0] == 'h':
- self.handleHeartbeat (ch, codec)
- else:
- self.parse (ch, codec, hdr[0], hdr[1])
- ch.accept(msg)
+ if hdr[0] == 'p':
+ self.handlePackageInd (ch, codec)
+ elif hdr[0] == 'q':
+ self.handleClassInd (ch, codec)
+ elif hdr[0] == 'h':
+ self.handleHeartbeat (ch, codec)
+ elif hdr[0] == 'e':
+ self.handleEvent (ch, codec)
+ else:
+ self.parse (ch, codec, hdr[0], hdr[1])
def replyCb (self, ch, msg):
""" Receive messages via the reply queue of a particular channel. """
- codec = Codec (self.spec, msg.body)
+ codec = Codec (msg.body)
hdr = self.checkHeader (codec)
if hdr == None:
- ch.accept(msg)
return
if hdr[0] == 'm':
@@ -332,7 +388,6 @@ class managementClient:
self.handleClassInd (ch, codec)
else:
self.parse (ch, codec, hdr[0], hdr[1])
- ch.accept(msg)
def exceptCb (self, ch, data):
if self.closeCb != None:
@@ -345,25 +400,27 @@ class managementClient:
""" Compose the header of a management message. """
codec.write_uint8 (ord ('A'))
codec.write_uint8 (ord ('M'))
- codec.write_uint8 (ord ('1'))
+ codec.write_uint8 (ord ('2'))
codec.write_uint8 (opcode)
codec.write_uint32 (seq)
def checkHeader (self, codec):
- """ Check the header of a management message and extract the opcode and
- class. """
- octet = chr (codec.read_uint8 ())
- if octet != 'A':
- return None
- octet = chr (codec.read_uint8 ())
- if octet != 'M':
+ """ Check the header of a management message and extract the opcode and class. """
+ try:
+ octet = chr (codec.read_uint8 ())
+ if octet != 'A':
+ return None
+ octet = chr (codec.read_uint8 ())
+ if octet != 'M':
+ return None
+ octet = chr (codec.read_uint8 ())
+ if octet != '2':
+ return None
+ opcode = chr (codec.read_uint8 ())
+ seq = codec.read_uint32 ()
+ return (opcode, seq)
+ except:
return None
- octet = chr (codec.read_uint8 ())
- if octet != '1':
- return None
- opcode = chr (codec.read_uint8 ())
- seq = codec.read_uint32 ()
- return (opcode, seq)
def encodeValue (self, codec, value, typecode):
""" Encode, into the codec, a value based on its typecode. """
@@ -380,19 +437,19 @@ class managementClient:
elif typecode == 6:
codec.write_str8 (value)
elif typecode == 7:
- codec.write_vbin32 (value)
+ codec.write_str16 (value)
elif typecode == 8: # ABSTIME
codec.write_uint64 (long (value))
elif typecode == 9: # DELTATIME
codec.write_uint64 (long (value))
elif typecode == 10: # REF
- codec.write_uint64 (long (value))
+ value.encode(codec)
elif typecode == 11: # BOOL
codec.write_uint8 (int (value))
elif typecode == 12: # FLOAT
codec.write_float (float (value))
elif typecode == 13: # DOUBLE
- codec.write_double (double (value))
+ codec.write_double (float (value))
elif typecode == 14: # UUID
codec.write_uuid (value)
elif typecode == 15: # FTABLE
@@ -421,15 +478,15 @@ class managementClient:
elif typecode == 5:
data = codec.read_uint8 ()
elif typecode == 6:
- data = str (codec.read_str8 ())
+ data = codec.read_str8 ()
elif typecode == 7:
- data = codec.read_vbin32 ()
+ data = codec.read_str16 ()
elif typecode == 8: # ABSTIME
data = codec.read_uint64 ()
elif typecode == 9: # DELTATIME
data = codec.read_uint64 ()
elif typecode == 10: # REF
- data = codec.read_uint64 ()
+ data = objectId(codec)
elif typecode == 11: # BOOL
data = codec.read_uint8 ()
elif typecode == 12: # FLOAT
@@ -469,12 +526,14 @@ class managementClient:
if self.ctrlCb != None:
self.ctrlCb (ch.context, self.CTRL_SCHEMA_LOADED, None)
ch.ssn.exchange_bind (exchange="qpid.management",
- queue=ch.topicName, binding_key="mgmt.#")
+ queue=ch.topicName, binding_key="console.#")
+ ch.ssn.exchange_bind (exchange="qpid.management",
+ queue=ch.topicName, binding_key="schema.#")
def handleMethodReply (self, ch, codec, sequence):
status = codec.read_uint32 ()
- sText = str (codec.read_str8 ())
+ sText = codec.read_str16 ()
data = self.seqMgr.release (sequence)
if data == None:
@@ -510,7 +569,7 @@ class managementClient:
def handleCommandComplete (self, ch, codec, seq):
code = codec.read_uint32 ()
- text = str (codec.read_str8 ())
+ text = codec.read_str8 ()
data = (seq, code, text)
context = self.seqMgr.release (seq)
if context == "outstanding":
@@ -530,19 +589,19 @@ class managementClient:
self.ctrlCb (ch.context, self.CTRL_BROKER_INFO, ch.brokerInfo)
# Send a package request
- sendCodec = Codec (self.spec)
+ sendCodec = Codec ()
seq = self.seqMgr.reserve ("outstanding")
self.setHeader (sendCodec, ord ('P'), seq)
smsg = ch.message(sendCodec.encoded)
ch.send ("qpid.management", smsg)
def handlePackageInd (self, ch, codec):
- pname = str (codec.read_str8 ())
+ pname = codec.read_str8 ()
if pname not in self.packages:
self.packages[pname] = {}
# Send a class request
- sendCodec = Codec (self.spec)
+ sendCodec = Codec ()
seq = self.seqMgr.reserve ("outstanding")
self.setHeader (sendCodec, ord ('Q'), seq)
self.incOutstanding (ch)
@@ -551,15 +610,18 @@ class managementClient:
ch.send ("qpid.management", smsg)
def handleClassInd (self, ch, codec):
- pname = str (codec.read_str8 ())
- cname = str (codec.read_str8 ())
- hash = codec.read_bin128 ()
+ kind = codec.read_uint8()
+ if kind != 1: # This API doesn't handle new-style events
+ return
+ pname = codec.read_str8()
+ cname = codec.read_str8()
+ hash = codec.read_bin128()
if pname not in self.packages:
return
if (cname, hash) not in self.packages[pname]:
# Send a schema request
- sendCodec = Codec (self.spec)
+ sendCodec = Codec ()
seq = self.seqMgr.reserve ("outstanding")
self.setHeader (sendCodec, ord ('S'), seq)
self.incOutstanding (ch)
@@ -574,16 +636,49 @@ class managementClient:
if self.ctrlCb != None:
self.ctrlCb (ch.context, self.CTRL_HEARTBEAT, timestamp)
+ def handleEvent (self, ch, codec):
+ if self.eventCb == None:
+ return
+ timestamp = codec.read_uint64()
+ objId = objectId(codec)
+ packageName = codec.read_str8()
+ className = codec.read_str8()
+ hash = codec.read_bin128()
+ name = codec.read_str8()
+ classKey = (packageName, className, hash)
+ if classKey not in self.schema:
+ return;
+ schemaClass = self.schema[classKey]
+ row = []
+ es = schemaClass['E']
+ arglist = None
+ for ename in es:
+ (edesc, eargs) = es[ename]
+ if ename == name:
+ arglist = eargs
+ if arglist == None:
+ return
+ for arg in arglist:
+ row.append((arg[0], self.decodeValue(codec, arg[1])))
+ self.eventCb(ch.context, classKey, objId, name, row)
+
def parseSchema (self, ch, codec):
""" Parse a received schema-description message. """
self.decOutstanding (ch)
- packageName = str (codec.read_str8 ())
- className = str (codec.read_str8 ())
+ kind = codec.read_uint8()
+ if kind != 1: # This API doesn't handle new-style events
+ return
+ packageName = codec.read_str8 ()
+ className = codec.read_str8 ()
hash = codec.read_bin128 ()
+ hasSupertype = 0 #codec.read_uint8()
configCount = codec.read_uint16 ()
instCount = codec.read_uint16 ()
methodCount = codec.read_uint16 ()
- eventCount = codec.read_uint16 ()
+ if hasSupertype != 0:
+ supertypePackage = codec.read_str8()
+ supertypeClass = codec.read_str8()
+ supertypeHash = codec.read_bin128()
if packageName not in self.packages:
return
@@ -597,22 +692,22 @@ class managementClient:
configs = []
insts = []
methods = {}
- events = []
configs.append (("id", 4, "", "", 1, 1, None, None, None, None, None))
insts.append (("id", 4, None, None))
for idx in range (configCount):
ft = codec.read_map ()
- name = str (ft["name"])
- type = ft["type"]
- access = ft["access"]
- index = ft["index"]
- unit = None
- min = None
- max = None
- maxlen = None
- desc = None
+ name = str (ft["name"])
+ type = ft["type"]
+ access = ft["access"]
+ index = ft["index"]
+ optional = ft["optional"]
+ unit = None
+ min = None
+ max = None
+ maxlen = None
+ desc = None
for key, value in ft.items ():
if key == "unit":
@@ -626,7 +721,7 @@ class managementClient:
elif key == "desc":
desc = str (value)
- config = (name, type, unit, desc, access, index, min, max, maxlen)
+ config = (name, type, unit, desc, access, index, min, max, maxlen, optional)
configs.append (config)
for idx in range (instCount):
@@ -689,11 +784,26 @@ class managementClient:
schemaClass['C'] = configs
schemaClass['I'] = insts
schemaClass['M'] = methods
- schemaClass['E'] = events
self.schema[classKey] = schemaClass
if self.schemaCb != None:
- self.schemaCb (ch.context, classKey, configs, insts, methods, events)
+ self.schemaCb (ch.context, classKey, configs, insts, methods, {})
+
+ def parsePresenceMasks(self, codec, schemaClass):
+ """ Generate a list of not-present properties """
+ excludeList = []
+ bit = 0
+ for element in schemaClass['C'][1:]:
+ if element[9] == 1:
+ if bit == 0:
+ mask = codec.read_uint8()
+ bit = 1
+ if (mask & bit) == 0:
+ excludeList.append(element[0])
+ bit = bit * 2
+ if bit == 256:
+ bit = 0
+ return excludeList
def parseContent (self, ch, cls, codec, seq=0):
""" Parse a received content message. """
@@ -702,8 +812,8 @@ class managementClient:
if cls == 'I' and self.instCb == None:
return
- packageName = str (codec.read_str8 ())
- className = str (codec.read_str8 ())
+ packageName = codec.read_str8 ()
+ className = codec.read_str8 ()
hash = codec.read_bin128 ()
classKey = (packageName, className, hash)
@@ -716,21 +826,26 @@ class managementClient:
timestamps.append (codec.read_uint64 ()) # Current Time
timestamps.append (codec.read_uint64 ()) # Create Time
timestamps.append (codec.read_uint64 ()) # Delete Time
-
+ objId = objectId(codec)
schemaClass = self.schema[classKey]
if cls == 'C' or cls == 'B':
- for element in schemaClass['C'][:]:
+ notPresent = self.parsePresenceMasks(codec, schemaClass)
+
+ if cls == 'C' or cls == 'B':
+ row.append(("id", objId))
+ for element in schemaClass['C'][1:]:
tc = element[1]
name = element[0]
- data = self.decodeValue (codec, tc)
- row.append ((name, data))
+ if name in notPresent:
+ row.append((name, None))
+ else:
+ data = self.decodeValue(codec, tc)
+ row.append((name, data))
if cls == 'I' or cls == 'B':
- if cls == 'B':
- start = 1
- else:
- start = 0
- for element in schemaClass['I'][start:]:
+ if cls == 'I':
+ row.append(("id", objId))
+ for element in schemaClass['I'][1:]:
tc = element[1]
name = element[0]
data = self.decodeValue (codec, tc)
@@ -760,12 +875,15 @@ class managementClient:
def method (self, channel, userSequence, objId, classId, methodName, args):
""" Invoke a method on an object """
- codec = Codec (self.spec)
+ codec = Codec ()
sequence = self.seqMgr.reserve ((userSequence, classId, methodName))
self.setHeader (codec, ord ('M'), sequence)
- codec.write_uint64 (objId) # ID of object
+ objId.encode(codec)
+ codec.write_str8 (classId[0])
+ codec.write_str8 (classId[1])
+ codec.write_bin128 (classId[2])
codec.write_str8 (methodName)
- bank = (objId & 0x0000FFFFFF000000) >> 24
+ bank = "%d.%d" % (objId.getBroker(), objId.getBank())
# Encode args according to schema
if classId not in self.schema:
@@ -795,5 +913,5 @@ class managementClient:
packageName = classId[0]
className = classId[1]
- msg = channel.message(codec.encoded, "agent." + str(bank))
+ msg = channel.message(codec.encoded, "agent." + bank)
channel.send ("qpid.management", msg)
diff --git a/python/qpid/managementdata.py b/python/qpid/managementdata.py
index fc9eb391b7..61cb10c134 100644
--- a/python/qpid/managementdata.py
+++ b/python/qpid/managementdata.py
@@ -19,11 +19,19 @@
# under the License.
#
+
+###############################################################################
+## This file is being obsoleted by qmf/console.py
+###############################################################################
+
import qpid
import re
import socket
import struct
import os
+import platform
+import locale
+from qpid.connection import Timeout
from qpid.management import managementChannel, managementClient
from threading import Lock
from disp import Display
@@ -40,9 +48,11 @@ class Broker:
if not match: raise ValueError("'%s' is not a valid broker url" % (text))
user, password, host, port = match.groups()
- self.host = socket.gethostbyname (host)
if port: self.port = int(port)
else: self.port = 5672
+ for addr in socket.getaddrinfo(host, self.port):
+ if addr[1] == socket.AF_INET:
+ self.host = addr[4][0]
self.username = user or "guest"
self.password = password or "guest"
@@ -71,14 +81,14 @@ class ManagementData:
#
def registerObjId (self, objId):
- if not objId in self.idBackMap:
- self.idBackMap[objId] = self.nextId
+ if not objId.index() in self.idBackMap:
+ self.idBackMap[objId.index()] = self.nextId
self.idMap[self.nextId] = objId
self.nextId += 1
- def displayObjId (self, objId):
- if objId in self.idBackMap:
- return self.idBackMap[objId]
+ def displayObjId (self, objIdIndex):
+ if objIdIndex in self.idBackMap:
+ return self.idBackMap[objIdIndex]
else:
return 0
@@ -86,11 +96,16 @@ class ManagementData:
if displayId in self.idMap:
return self.idMap[displayId]
else:
- return 0
+ return None
def displayClassName (self, cls):
(packageName, className, hash) = cls
- return packageName + "." + className
+ rev = self.schema[cls][4]
+ if rev == 0:
+ suffix = ""
+ else:
+ suffix = ".%d" % rev
+ return packageName + ":" + className + suffix
def dataHandler (self, context, className, list, timestamps):
""" Callback for configuration and instrumentation data updates """
@@ -102,19 +117,20 @@ class ManagementData:
self.tables[className] = {}
# Register the ID so a more friendly presentation can be displayed
- id = long (list[0][1])
- self.registerObjId (id)
+ objId = list[0][1]
+ oidx = objId.index()
+ self.registerObjId (objId)
# If this object hasn't been seen before, create a new object record with
# the timestamps and empty lists for configuration and instrumentation data.
- if id not in self.tables[className]:
- self.tables[className][id] = (timestamps, [], [])
+ if oidx not in self.tables[className]:
+ self.tables[className][oidx] = (timestamps, [], [])
- (unused, oldConf, oldInst) = self.tables[className][id]
+ (unused, oldConf, oldInst) = self.tables[className][oidx]
# For config updates, simply replace old config list with the new one.
if context == 0: #config
- self.tables[className][id] = (timestamps, list, oldInst)
+ self.tables[className][oidx] = (timestamps, list, oldInst)
# For instrumentation updates, carry the minimum and maximum values for
# "hi-lo" stats forward.
@@ -132,7 +148,7 @@ class ManagementData:
if oldInst[idx][1] < value:
value = oldInst[idx][1]
newInst.append ((key, value))
- self.tables[className][id] = (timestamps, oldConf, newInst)
+ self.tables[className][oidx] = (timestamps, oldConf, newInst)
finally:
self.lock.release ()
@@ -190,15 +206,25 @@ class ManagementData:
self.lastUnit = None
self.methodSeq = 1
self.methodsPending = {}
- self.sessionId = "%s.%d" % (os.uname()[1], os.getpid())
+ self.sessionId = "%s.%d" % (platform.uname()[1], os.getpid())
self.broker = Broker (host)
- self.conn = Connection (connect (self.broker.host, self.broker.port),
+ sock = connect (self.broker.host, self.broker.port)
+ oldTimeout = sock.gettimeout()
+ sock.settimeout(10)
+ self.conn = Connection (sock,
username=self.broker.username, password=self.broker.password)
- self.spec = self.conn.spec
+ def aborted():
+ raise Timeout("Waiting for connection to be established with broker")
+ oldAborted = self.conn.aborted
+ self.conn.aborted = aborted
+
self.conn.start ()
- self.mclient = managementClient (self.spec, self.ctrlHandler, self.configHandler,
+ sock.settimeout(oldTimeout)
+ self.conn.aborted = oldAborted
+
+ self.mclient = managementClient ("unused", self.ctrlHandler, self.configHandler,
self.instHandler, self.methodReply, self.closeHandler)
self.mclient.schemaListener (self.schemaHandler)
self.mch = self.mclient.addChannel (self.conn.session(self.sessionId))
@@ -211,11 +237,13 @@ class ManagementData:
pass
def refName (self, oid):
- if oid == 0:
+ if oid == None:
return "NULL"
- return str (self.displayObjId (oid))
+ return str (self.displayObjId (oid.index()))
def valueDisplay (self, classKey, key, value):
+ if value == None:
+ return "<NULL>"
for kind in range (2):
schema = self.schema[classKey][kind]
for item in schema:
@@ -248,7 +276,7 @@ class ManagementData:
else:
return "True"
elif typecode == 14:
- return "%08x-%04x-%04x-%04x-%04x%08x" % struct.unpack ("!LHHHHL", value)
+ return str (value)
elif typecode == 15:
return str (value)
return "*type-error*"
@@ -267,14 +295,21 @@ class ManagementData:
return result
def getClassKey (self, className):
- dotPos = className.find(".")
- if dotPos == -1:
+ delimPos = className.find(":")
+ if delimPos == -1:
+ schemaRev = 0
+ delim = className.find(".")
+ if delim != -1:
+ schemaRev = int(className[delim + 1:])
+ name = className[0:delim]
+ else:
+ name = className
for key in self.schema:
- if key[1] == className:
+ if key[1] == name and self.schema[key][4] == schemaRev:
return key
else:
- package = className[0:dotPos]
- name = className[dotPos + 1:]
+ package = className[0:delimPos]
+ name = className[delimPos + 1:]
schemaRev = 0
delim = name.find(".")
if delim != -1:
@@ -338,6 +373,12 @@ class ManagementData:
return "int32"
elif typecode == 19:
return "int64"
+ elif typecode == 20:
+ return "object"
+ elif typecode == 21:
+ return "list"
+ elif typecode == 22:
+ return "array"
else:
raise ValueError ("Invalid type code: %d" % typecode)
@@ -437,7 +478,7 @@ class ManagementData:
if classKey in self.tables:
ids = self.listOfIds(classKey, tokens[1:])
for objId in ids:
- (ts, config, inst) = self.tables[classKey][self.rawObjId(objId)]
+ (ts, config, inst) = self.tables[classKey][self.rawObjId(objId).index()]
createTime = self.disp.timestamp (ts[1])
destroyTime = "-"
if ts[2] > 0:
@@ -445,7 +486,7 @@ class ManagementData:
objIndex = self.getObjIndex (classKey, config)
row = (objId, createTime, destroyTime, objIndex)
rows.append (row)
- self.disp.table ("Objects of type %s.%s" % (classKey[0], classKey[1]),
+ self.disp.table ("Objects of type %s" % self.displayClassName(classKey),
("ID", "Created", "Destroyed", "Index"),
rows)
finally:
@@ -486,33 +527,33 @@ class ManagementData:
rows = []
timestamp = None
- config = self.tables[classKey][ids[0]][1]
+ config = self.tables[classKey][ids[0].index()][1]
for eIdx in range (len (config)):
key = config[eIdx][0]
if key != "id":
row = ("property", key)
for id in ids:
if timestamp == None or \
- timestamp < self.tables[classKey][id][0][0]:
- timestamp = self.tables[classKey][id][0][0]
- (key, value) = self.tables[classKey][id][1][eIdx]
+ timestamp < self.tables[classKey][id.index()][0][0]:
+ timestamp = self.tables[classKey][id.index()][0][0]
+ (key, value) = self.tables[classKey][id.index()][1][eIdx]
row = row + (self.valueDisplay (classKey, key, value),)
rows.append (row)
- inst = self.tables[classKey][ids[0]][2]
+ inst = self.tables[classKey][ids[0].index()][2]
for eIdx in range (len (inst)):
key = inst[eIdx][0]
if key != "id":
row = ("statistic", key)
for id in ids:
- (key, value) = self.tables[classKey][id][2][eIdx]
+ (key, value) = self.tables[classKey][id.index()][2][eIdx]
row = row + (self.valueDisplay (classKey, key, value),)
rows.append (row)
titleRow = ("Type", "Element")
for id in ids:
- titleRow = titleRow + (self.refName (id),)
- caption = "Object of type %s.%s:" % (classKey[0], classKey[1])
+ titleRow = titleRow + (self.refName(id),)
+ caption = "Object of type %s:" % self.displayClassName(classKey)
if timestamp != None:
caption = caption + " (last sample time: " + self.disp.timestamp (timestamp) + ")"
self.disp.table (caption, titleRow, rows)
@@ -530,15 +571,11 @@ class ManagementData:
sorted.sort ()
for classKey in sorted:
tuple = self.schema[classKey]
- if tuple[4] == 0:
- suffix = ""
- else:
- suffix = ".%d" % tuple[4]
- className = classKey[0] + "." + classKey[1] + suffix
- row = (className, len (tuple[0]), len (tuple[1]), len (tuple[2]), len (tuple[3]))
+ row = (self.displayClassName(classKey), len (tuple[0]), len (tuple[1]),
+ len (tuple[2]))
rows.append (row)
self.disp.table ("Classes in Schema:",
- ("Class", "Properties", "Statistics", "Methods", "Events"),
+ ("Class", "Properties", "Statistics", "Methods"),
rows)
finally:
self.lock.release ()
@@ -563,13 +600,15 @@ class ManagementData:
access = self.accessName (config[4])
extra = ""
if config[5] == 1:
- extra = extra + "index "
+ extra += "index "
if config[6] != None:
- extra = extra + "Min: " + str (config[6])
+ extra += "Min: " + str(config[6]) + " "
if config[7] != None:
- extra = extra + "Max: " + str (config[7])
+ extra += "Max: " + str(config[7]) + " "
if config[8] != None:
- extra = extra + "MaxLen: " + str (config[8])
+ extra += "MaxLen: " + str(config[8]) + " "
+ if config[9] == 1:
+ extra += "optional "
rows.append ((name, typename, unit, access, extra, desc))
for config in self.schema[classKey][1]:
@@ -581,7 +620,7 @@ class ManagementData:
rows.append ((name, typename, unit, "", "", desc))
titles = ("Element", "Type", "Unit", "Access", "Notes", "Description")
- self.disp.table ("Schema for class '%s.%s.%d':" % (classKey[0], classKey[1], schemaRev), titles, rows)
+ self.disp.table ("Schema for class '%s':" % self.displayClassName(classKey), titles, rows)
for mname in self.schema[classKey][2]:
(mdesc, args) = self.schema[classKey][2][mname]
@@ -606,14 +645,14 @@ class ManagementData:
titles = ("Argument", "Type", "Direction", "Unit", "Notes", "Description")
self.disp.table (caption, titles, rows)
- except:
+ except Exception,e:
pass
self.lock.release ()
def getClassForId (self, objId):
""" Given an object ID, return the class key for the referenced object """
for classKey in self.tables:
- if objId in self.tables[classKey]:
+ if objId.index() in self.tables[classKey]:
return classKey
return None
@@ -626,7 +665,7 @@ class ManagementData:
raise ValueError ()
if methodName not in self.schema[classKey][2]:
- print "Method '%s' not valid for class '%s.%s'" % (methodName, classKey[0], classKey[1])
+ print "Method '%s' not valid for class '%s'" % (methodName, self.displayClassName(classKey))
raise ValueError ()
schemaMethod = self.schema[classKey][2][methodName]
@@ -647,7 +686,7 @@ class ManagementData:
self.methodSeq = self.methodSeq + 1
self.methodsPending[self.methodSeq] = methodName
- except:
+ except Exception, e:
methodOk = False
self.lock.release ()
if methodOk:
@@ -659,14 +698,19 @@ class ManagementData:
def makeIdRow (self, displayId):
if displayId in self.idMap:
- rawId = self.idMap[displayId]
+ objId = self.idMap[displayId]
else:
return None
- return (displayId,
- rawId,
- (rawId & 0x7FFF000000000000) >> 48,
- (rawId & 0x0000FFFFFF000000) >> 24,
- (rawId & 0x0000000000FFFFFF))
+ if objId.getFlags() == 0:
+ flags = ""
+ else:
+ flags = str(objId.getFlags())
+ seq = objId.getSequence()
+ if seq == 0:
+ seqText = "<durable>"
+ else:
+ seqText = str(seq)
+ return (displayId, flags, seqText, objId.getBroker(), objId.getBank(), hex(objId.getObject()))
def listIds (self, select):
rows = []
@@ -683,7 +727,7 @@ class ManagementData:
return
rows.append(row)
self.disp.table("Translation of Display IDs:",
- ("DisplayID", "RawID", "BootSequence", "Bank", "Object"),
+ ("DisplayID", "Flags", "BootSequence", "Broker", "Bank", "Object"),
rows)
def do_list (self, data):
@@ -704,7 +748,11 @@ class ManagementData:
self.schemaTable (data)
def do_call (self, data):
- tokens = data.split ()
+ encTokens = data.split ()
+ try:
+ tokens = [a.decode(locale.getpreferredencoding()) for a in encArgs]
+ except:
+ tokens = encTokens
if len (tokens) < 2:
print "Not enough arguments supplied"
return
diff --git a/python/qpid/message.py b/python/qpid/message.py
index eb3ef5c03c..4d31da2846 100644
--- a/python/qpid/message.py
+++ b/python/qpid/message.py
@@ -17,7 +17,6 @@
# under the License.
#
from connection08 import Method, Request
-from sets import Set
class Message:
diff --git a/python/qpid/messaging.py b/python/qpid/messaging.py
new file mode 100644
index 0000000000..4f2c190ce2
--- /dev/null
+++ b/python/qpid/messaging.py
@@ -0,0 +1,822 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+"""
+A candidate high level messaging API for python.
+
+Areas that still need work:
+
+ - asynchronous send
+ - asynchronous error notification
+ - definition of the arguments for L{Session.sender} and L{Session.receiver}
+ - standard L{Message} properties
+ - L{Message} content encoding
+ - protocol negotiation/multiprotocol impl
+"""
+
+from codec010 import StringCodec
+from concurrency import synchronized, Waiter, Condition
+from datatypes import timestamp, uuid4, Serial
+from logging import getLogger
+from ops import PRIMITIVE
+from threading import Thread, RLock
+from util import default
+
+log = getLogger("qpid.messaging")
+
+static = staticmethod
+
+AMQP_PORT = 5672
+AMQPS_PORT = 5671
+
+class Constant:
+
+ def __init__(self, name, value=None):
+ self.name = name
+ self.value = value
+
+ def __repr__(self):
+ return self.name
+
+UNLIMITED = Constant("UNLIMITED", 0xFFFFFFFFL)
+
+class ConnectionError(Exception):
+ """
+ The base class for all connection related exceptions.
+ """
+ pass
+
+class ConnectError(ConnectionError):
+ """
+ Exception raised when there is an error connecting to the remote
+ peer.
+ """
+ pass
+
+class Connection:
+
+ """
+ A Connection manages a group of L{Sessions<Session>} and connects
+ them with a remote endpoint.
+ """
+
+ @static
+ def open(host, port=None, username="guest", password="guest",
+ mechanism="PLAIN", heartbeat=None, **options):
+ """
+ Creates an AMQP connection and connects it to the given host and port.
+
+ @type host: str
+ @param host: the name or ip address of the remote host
+ @type port: int
+ @param port: the port number of the remote host
+ @rtype: Connection
+ @return: a connected Connection
+ """
+ conn = Connection(host, port, username, password, mechanism, heartbeat, **options)
+ conn.connect()
+ return conn
+
+ def __init__(self, host, port=None, username="guest", password="guest",
+ mechanism="PLAIN", heartbeat=None, **options):
+ """
+ Creates a connection. A newly created connection must be connected
+ with the Connection.connect() method before it can be used.
+
+ @type host: str
+ @param host: the name or ip address of the remote host
+ @type port: int
+ @param port: the port number of the remote host
+ @rtype: Connection
+ @return: a disconnected Connection
+ """
+ self.host = host
+ self.port = default(port, AMQP_PORT)
+ self.username = username
+ self.password = password
+ self.mechanism = mechanism
+ self.heartbeat = heartbeat
+
+ self.id = str(uuid4())
+ self.session_counter = 0
+ self.sessions = {}
+ self.reconnect = options.get("reconnect", False)
+ self._connected = False
+ self._lock = RLock()
+ self._condition = Condition(self._lock)
+ self._waiter = Waiter(self._condition)
+ self._modcount = Serial(0)
+ self.error = None
+ from driver import Driver
+ self._driver = Driver(self)
+ self._driver.start()
+
+ def _wait(self, predicate, timeout=None):
+ return self._waiter.wait(predicate, timeout=timeout)
+
+ def _wakeup(self):
+ self._modcount += 1
+ self._driver.wakeup()
+
+ def _check_error(self, exc=ConnectionError):
+ if self.error:
+ raise exc(*self.error)
+
+ def _ewait(self, predicate, timeout=None, exc=ConnectionError):
+ result = self._wait(lambda: self.error or predicate(), timeout)
+ self._check_error(exc)
+ return result
+
+ @synchronized
+ def session(self, name=None, transactional=False):
+ """
+ Creates or retrieves the named session. If the name is omitted or
+ None, then a unique name is chosen based on a randomly generated
+ uuid.
+
+ @type name: str
+ @param name: the session name
+ @rtype: Session
+ @return: the named Session
+ """
+
+ if name is None:
+ name = "%s:%s" % (self.id, self.session_counter)
+ self.session_counter += 1
+ else:
+ name = "%s:%s" % (self.id, name)
+
+ if self.sessions.has_key(name):
+ return self.sessions[name]
+ else:
+ ssn = Session(self, name, transactional)
+ self.sessions[name] = ssn
+ self._wakeup()
+ return ssn
+
+ @synchronized
+ def _remove_session(self, ssn):
+ del self.sessions[ssn.name]
+
+ @synchronized
+ def connect(self):
+ """
+ Connect to the remote endpoint.
+ """
+ self._connected = True
+ self._wakeup()
+ self._ewait(lambda: self._driver._connected, exc=ConnectError)
+
+ @synchronized
+ def disconnect(self):
+ """
+ Disconnect from the remote endpoint.
+ """
+ self._connected = False
+ self._wakeup()
+ self._ewait(lambda: not self._driver._connected)
+
+ @synchronized
+ def connected(self):
+ """
+ Return true if the connection is connected, false otherwise.
+ """
+ return self._connected
+
+ @synchronized
+ def close(self):
+ """
+ Close the connection and all sessions.
+ """
+ for ssn in self.sessions.values():
+ ssn.close()
+ self.disconnect()
+
+class Pattern:
+ """
+ The pattern filter matches the supplied wildcard pattern against a
+ message subject.
+ """
+
+ def __init__(self, value):
+ self.value = value
+
+ # XXX: this should become part of the driver
+ def _bind(self, sst, exchange, queue):
+ from qpid.ops import ExchangeBind
+ sst.write_cmd(ExchangeBind(exchange=exchange, queue=queue,
+ binding_key=self.value.replace("*", "#")))
+
+class SessionError(Exception):
+ pass
+
+class Disconnected(SessionError):
+ """
+ Exception raised when an operation is attempted that is illegal when
+ disconnected.
+ """
+ pass
+
+class NontransactionalSession(SessionError):
+ """
+ Exception raised when commit or rollback is attempted on a non
+ transactional session.
+ """
+ pass
+
+class TransactionAborted(SessionError):
+ pass
+
+class Session:
+
+ """
+ Sessions provide a linear context for sending and receiving
+ messages, and manage various Senders and Receivers.
+ """
+
+ def __init__(self, connection, name, transactional):
+ self.connection = connection
+ self.name = name
+
+ self.transactional = transactional
+
+ self.committing = False
+ self.committed = True
+ self.aborting = False
+ self.aborted = False
+
+ self.senders = []
+ self.receivers = []
+ self.outgoing = []
+ self.incoming = []
+ self.unacked = []
+ self.acked = []
+ # XXX: I hate this name.
+ self.ack_capacity = UNLIMITED
+
+ self.error = None
+ self.closing = False
+ self.closed = False
+
+ self._lock = connection._lock
+
+ def __repr__(self):
+ return "<Session %s>" % self.name
+
+ def _wait(self, predicate, timeout=None):
+ return self.connection._wait(predicate, timeout=timeout)
+
+ def _wakeup(self):
+ self.connection._wakeup()
+
+ def _check_error(self, exc=SessionError):
+ self.connection._check_error(exc)
+ if self.error:
+ raise exc(*self.error)
+
+ def _ewait(self, predicate, timeout=None, exc=SessionError):
+ result = self.connection._ewait(lambda: self.error or predicate(), timeout, exc)
+ self._check_error(exc)
+ return result
+
+ @synchronized
+ def sender(self, target, **options):
+ """
+ Creates a L{Sender} that may be used to send L{Messages<Message>}
+ to the specified target.
+
+ @type target: str
+ @param target: the target to which messages will be sent
+ @rtype: Sender
+ @return: a new Sender for the specified target
+ """
+ sender = Sender(self, len(self.senders), target, options)
+ self.senders.append(sender)
+ self._wakeup()
+ # XXX: because of the lack of waiting here we can end up getting
+ # into the driver loop with messages sent for senders that haven't
+ # been linked yet, something similar can probably happen for
+ # receivers
+ return sender
+
+ @synchronized
+ def receiver(self, source, **options):
+ """
+ Creates a receiver that may be used to fetch L{Messages<Message>}
+ from the specified source.
+
+ @type source: str
+ @param source: the source of L{Messages<Message>}
+ @rtype: Receiver
+ @return: a new Receiver for the specified source
+ """
+ receiver = Receiver(self, len(self.receivers), source, options)
+ self.receivers.append(receiver)
+ self._wakeup()
+ return receiver
+
+ @synchronized
+ def _count(self, predicate):
+ result = 0
+ for msg in self.incoming:
+ if predicate(msg):
+ result += 1
+ return result
+
+ def _peek(self, predicate):
+ for msg in self.incoming:
+ if predicate(msg):
+ return msg
+
+ def _pop(self, predicate):
+ i = 0
+ while i < len(self.incoming):
+ msg = self.incoming[i]
+ if predicate(msg):
+ del self.incoming[i]
+ return msg
+ else:
+ i += 1
+
+ @synchronized
+ def _get(self, predicate, timeout=None):
+ if self._ewait(lambda: ((self._peek(predicate) is not None) or self.closing),
+ timeout):
+ msg = self._pop(predicate)
+ if msg is not None:
+ msg._receiver.returned += 1
+ self.unacked.append(msg)
+ log.debug("RETR [%s] %s", self, msg)
+ return msg
+ return None
+
+ @synchronized
+ def next_receiver(self, timeout=None):
+ if self._ewait(lambda: self.incoming, timeout):
+ return self.incoming[0]._receiver
+ else:
+ raise Empty
+
+ @synchronized
+ def acknowledge(self, message=None, sync=True):
+ """
+ Acknowledge the given L{Message}. If message is None, then all
+ unacknowledged messages on the session are acknowledged.
+
+ @type message: Message
+ @param message: the message to acknowledge or None
+ @type sync: boolean
+ @param sync: if true then block until the message(s) are acknowledged
+ """
+ if message is None:
+ messages = self.unacked[:]
+ else:
+ messages = [message]
+
+ for m in messages:
+ if self.ack_capacity is not UNLIMITED:
+ if self.ack_capacity <= 0:
+ # XXX: this is currently a SendError, maybe it should be a SessionError?
+ raise InsufficientCapacity("ack_capacity = %s" % self.ack_capacity)
+ self._wakeup()
+ self._ewait(lambda: len(self.acked) < self.ack_capacity)
+ self.unacked.remove(m)
+ self.acked.append(m)
+
+ self._wakeup()
+ if sync:
+ self._ewait(lambda: not [m for m in messages if m in self.acked])
+
+ @synchronized
+ def commit(self):
+ """
+ Commit outstanding transactional work. This consists of all
+ message sends and receives since the prior commit or rollback.
+ """
+ if not self.transactional:
+ raise NontransactionalSession()
+ self.committing = True
+ self._wakeup()
+ self._ewait(lambda: not self.committing)
+ if self.aborted:
+ raise TransactionAborted()
+ assert self.committed
+
+ @synchronized
+ def rollback(self):
+ """
+ Rollback outstanding transactional work. This consists of all
+ message sends and receives since the prior commit or rollback.
+ """
+ if not self.transactional:
+ raise NontransactionalSession()
+ self.aborting = True
+ self._wakeup()
+ self._ewait(lambda: not self.aborting)
+ assert self.aborted
+
+ @synchronized
+ def close(self):
+ """
+ Close the session.
+ """
+ # XXX: should be able to express this condition through API calls
+ self._ewait(lambda: not self.outgoing and not self.acked)
+
+ for link in self.receivers + self.senders:
+ link.close()
+
+ self.closing = True
+ self._wakeup()
+ self._ewait(lambda: self.closed)
+ self.connection._remove_session(self)
+
+class SendError(SessionError):
+ pass
+
+class InsufficientCapacity(SendError):
+ pass
+
+class Sender:
+
+ """
+ Sends outgoing messages.
+ """
+
+ def __init__(self, session, index, target, options):
+ self.session = session
+ self.index = index
+ self.target = target
+ self.options = options
+ self.capacity = options.get("capacity", UNLIMITED)
+ self.durable = options.get("durable")
+ self.queued = Serial(0)
+ self.acked = Serial(0)
+ self.error = None
+ self.linked = False
+ self.closing = False
+ self.closed = False
+ self._lock = self.session._lock
+
+ def _wakeup(self):
+ self.session._wakeup()
+
+ def _check_error(self, exc=SendError):
+ self.session._check_error(exc)
+ if self.error:
+ raise exc(*self.error)
+
+ def _ewait(self, predicate, timeout=None, exc=SendError):
+ result = self.session._ewait(lambda: self.error or predicate(), timeout, exc)
+ self._check_error(exc)
+ return result
+
+ @synchronized
+ def pending(self):
+ """
+ Returns the number of messages awaiting acknowledgment.
+ @rtype: int
+ @return: the number of unacknowledged messages
+ """
+ return self.queued - self.acked
+
+ @synchronized
+ def send(self, object, sync=True, timeout=None):
+ """
+ Send a message. If the object passed in is of type L{unicode},
+ L{str}, L{list}, or L{dict}, it will automatically be wrapped in a
+ L{Message} and sent. If it is of type L{Message}, it will be sent
+ directly. If the sender capacity is not L{UNLIMITED} then send
+ will block until there is available capacity to send the message.
+ If the timeout parameter is specified, then send will throw an
+ L{InsufficientCapacity} exception if capacity does not become
+ available within the specified time.
+
+ @type object: unicode, str, list, dict, Message
+ @param object: the message or content to send
+
+ @type sync: boolean
+ @param sync: if true then block until the message is sent
+
+ @type timeout: float
+ @param timeout: the time to wait for available capacity
+ """
+
+ if not self.session.connection._connected or self.session.closing:
+ raise Disconnected()
+
+ self._ewait(lambda: self.linked)
+
+ if isinstance(object, Message):
+ message = object
+ else:
+ message = Message(object)
+
+ if message.durable is None:
+ message.durable = self.durable
+
+ if self.capacity is not UNLIMITED:
+ if self.capacity <= 0:
+ raise InsufficientCapacity("capacity = %s" % self.capacity)
+ if not self._ewait(lambda: self.pending() < self.capacity, timeout=timeout):
+ raise InsufficientCapacity("capacity = %s" % self.capacity)
+
+ # XXX: what if we send the same message to multiple senders?
+ message._sender = self
+ self.session.outgoing.append(message)
+ self.queued += 1
+
+ self._wakeup()
+
+ if sync:
+ self.sync()
+ assert message not in self.session.outgoing
+
+ @synchronized
+ def sync(self):
+ mno = self.queued
+ self._ewait(lambda: self.acked >= mno)
+
+ @synchronized
+ def close(self):
+ """
+ Close the Sender.
+ """
+ self.closing = True
+ self._wakeup()
+ try:
+ self.session._ewait(lambda: self.closed)
+ finally:
+ self.session.senders.remove(self)
+
+class ReceiveError(SessionError):
+ pass
+
+class Empty(ReceiveError):
+ """
+ Exception raised by L{Receiver.fetch} when there is no message
+ available within the alloted time.
+ """
+ pass
+
+class Receiver(object):
+
+ """
+ Receives incoming messages from a remote source. Messages may be
+ fetched with L{fetch}.
+ """
+
+ def __init__(self, session, index, source, options):
+ self.session = session
+ self.index = index
+ self.destination = str(self.index)
+ self.source = source
+ self.options = options
+
+ self.granted = Serial(0)
+ self.draining = False
+ self.impending = Serial(0)
+ self.received = Serial(0)
+ self.returned = Serial(0)
+
+ self.error = None
+ self.linked = False
+ self.closing = False
+ self.closed = False
+ self._lock = self.session._lock
+ self._capacity = 0
+ self._set_capacity(options.get("capacity", 0), False)
+
+ @synchronized
+ def _set_capacity(self, c, wakeup=True):
+ if c is UNLIMITED:
+ self._capacity = c.value
+ else:
+ self._capacity = c
+ self._grant()
+ if wakeup:
+ self._wakeup()
+
+ def _get_capacity(self):
+ if self._capacity == UNLIMITED.value:
+ return UNLIMITED
+ else:
+ return self._capacity
+
+ capacity = property(_get_capacity, _set_capacity)
+
+ def _wakeup(self):
+ self.session._wakeup()
+
+ def _check_error(self, exc=ReceiveError):
+ self.session._check_error(exc)
+ if self.error:
+ raise exc(*self.error)
+
+ def _ewait(self, predicate, timeout=None, exc=ReceiveError):
+ result = self.session._ewait(lambda: self.error or predicate(), timeout, exc)
+ self._check_error(exc)
+ return result
+
+ @synchronized
+ def pending(self):
+ """
+ Returns the number of messages available to be fetched by the
+ application.
+
+ @rtype: int
+ @return: the number of available messages
+ """
+ return self.received - self.returned
+
+ def _pred(self, msg):
+ return msg._receiver == self
+
+ @synchronized
+ def fetch(self, timeout=None):
+ """
+ Fetch and return a single message. A timeout of None will block
+ forever waiting for a message to arrive, a timeout of zero will
+ return immediately if no messages are available.
+
+ @type timeout: float
+ @param timeout: the time to wait for a message to be available
+ """
+
+ self._ewait(lambda: self.linked)
+
+ if self._capacity == 0:
+ self.granted = self.returned + 1
+ self._wakeup()
+ self._ewait(lambda: self.impending >= self.granted)
+ msg = self.session._get(self._pred, timeout=timeout)
+ if msg is None:
+ self.draining = True
+ self._wakeup()
+ self._ewait(lambda: not self.draining)
+ self._grant()
+ self._wakeup()
+ msg = self.session._get(self._pred, timeout=0)
+ if msg is None:
+ raise Empty()
+ elif self._capacity not in (0, UNLIMITED.value):
+ self.granted += 1
+ self._wakeup()
+ return msg
+
+ def _grant(self):
+ if self._capacity == UNLIMITED.value:
+ self.granted = UNLIMITED
+ else:
+ self.granted = self.received + self._capacity
+
+ @synchronized
+ def close(self):
+ """
+ Close the receiver.
+ """
+ self.closing = True
+ self._wakeup()
+ try:
+ self.session._ewait(lambda: self.closed)
+ finally:
+ self.session.receivers.remove(self)
+
+def codec(name):
+ type = PRIMITIVE[name]
+
+ def encode(x):
+ sc = StringCodec()
+ sc.write_primitive(type, x)
+ return sc.encoded
+
+ def decode(x):
+ sc = StringCodec(x)
+ return sc.read_primitive(type)
+
+ return encode, decode
+
+# XXX: need to correctly parse the mime type and deal with
+# content-encoding header
+
+TYPE_MAPPINGS={
+ dict: "amqp/map",
+ list: "amqp/list",
+ unicode: "text/plain; charset=utf8",
+ unicode: "text/plain",
+ buffer: None,
+ str: None,
+ None.__class__: None
+ }
+
+TYPE_CODEC={
+ "amqp/map": codec("map"),
+ "amqp/list": codec("list"),
+ "text/plain; charset=utf8": (lambda x: x.encode("utf8"), lambda x: x.decode("utf8")),
+ "text/plain": (lambda x: x.encode("utf8"), lambda x: x.decode("utf8")),
+ "": (lambda x: x, lambda x: x),
+ None: (lambda x: x, lambda x: x)
+ }
+
+def get_type(content):
+ return TYPE_MAPPINGS[content.__class__]
+
+def get_codec(content_type):
+ return TYPE_CODEC[content_type]
+
+UNSPECIFIED = object()
+
+class Message:
+
+ """
+ A message consists of a standard set of fields, an application
+ defined set of properties, and some content.
+
+ @type id: str
+ @ivar id: the message id
+ @type user_id: ???
+ @ivar user_id: the user-id of the message producer
+ @type to: ???
+ @ivar to: ???
+ @type reply_to: ???
+ @ivar reply_to: ???
+ @type correlation_id: str
+ @ivar correlation_id: a correlation-id for the message
+ @type properties: dict
+ @ivar properties: application specific message properties
+ @type content_type: str
+ @ivar content_type: the content-type of the message
+ @type content: str, unicode, buffer, dict, list
+ @ivar content: the message content
+ """
+
+ def __init__(self, content=None, content_type=UNSPECIFIED, id=None,
+ subject=None, to=None, user_id=None, reply_to=None,
+ correlation_id=None, durable=None, properties=None):
+ """
+ Construct a new message with the supplied content. The
+ content-type of the message will be automatically inferred from
+ type of the content parameter.
+
+ @type content: str, unicode, buffer, dict, list
+ @param content: the message content
+
+ @type content_type: str
+ @param content_type: the content-type of the message
+ """
+ self.id = id
+ self.subject = subject
+ self.to = to
+ self.user_id = user_id
+ self.reply_to = reply_to
+ self.correlation_id = correlation_id
+ self.durable = durable
+ self.redelivered = False
+ if properties is None:
+ self.properties = {}
+ else:
+ self.properties = properties
+ if content_type is UNSPECIFIED:
+ self.content_type = get_type(content)
+ else:
+ self.content_type = content_type
+ self.content = content
+
+ def __repr__(self):
+ args = []
+ for name in ["id", "subject", "to", "user_id", "reply_to",
+ "correlation_id"]:
+ value = self.__dict__[name]
+ if value is not None: args.append("%s=%r" % (name, value))
+ for name in ["durable", "properties"]:
+ value = self.__dict__[name]
+ if value: args.append("%s=%r" % (name, value))
+ if self.content_type != get_type(self.content):
+ args.append("content_type=%r" % self.content_type)
+ if self.content is not None:
+ if args:
+ args.append("content=%r" % self.content)
+ else:
+ args.append(repr(self.content))
+ return "Message(%s)" % ", ".join(args)
+
+__all__ = ["Connection", "Session", "Sender", "Receiver", "Pattern", "Message",
+ "ConnectionError", "ConnectError", "SessionError", "Disconnected",
+ "SendError", "InsufficientCapacity", "ReceiveError", "Empty",
+ "timestamp", "uuid4", "UNLIMITED", "AMQP_PORT", "AMQPS_PORT"]
diff --git a/python/qpid/mimetype.py b/python/qpid/mimetype.py
new file mode 100644
index 0000000000..f512996b9f
--- /dev/null
+++ b/python/qpid/mimetype.py
@@ -0,0 +1,106 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+import re, rfc822
+from lexer import Lexicon, LexError
+from parser import Parser, ParseError
+
+l = Lexicon()
+
+LPAREN = l.define("LPAREN", r"\(")
+RPAREN = l.define("LPAREN", r"\)")
+SLASH = l.define("SLASH", r"/")
+SEMI = l.define("SEMI", r";")
+EQUAL = l.define("EQUAL", r"=")
+TOKEN = l.define("TOKEN", r'[^()<>@,;:\\"/\[\]?= ]+')
+STRING = l.define("STRING", r'"(?:[^\\"]|\\.)*"')
+WSPACE = l.define("WSPACE", r"[ \n\r\t]+")
+EOF = l.eof("EOF")
+
+LEXER = l.compile()
+
+def lex(st):
+ return LEXER.lex(st)
+
+class MimeTypeParser(Parser):
+
+ def __init__(self, tokens):
+ Parser.__init__(self, [t for t in tokens if t.type is not WSPACE])
+
+ def parse(self):
+ result = self.mimetype()
+ self.eat(EOF)
+ return result
+
+ def mimetype(self):
+ self.remove_comments()
+ self.reset()
+
+ type = self.eat(TOKEN).value.lower()
+ self.eat(SLASH)
+ subtype = self.eat(TOKEN).value.lower()
+
+ params = []
+ while True:
+ if self.matches(SEMI):
+ params.append(self.parameter())
+ else:
+ break
+
+ return type, subtype, params
+
+ def remove_comments(self):
+ while True:
+ self.eat_until(LPAREN, EOF)
+ if self.matches(LPAREN):
+ self.remove(*self.comment())
+ else:
+ break
+
+ def comment(self):
+ start = self.eat(LPAREN)
+
+ while True:
+ self.eat_until(LPAREN, RPAREN)
+ if self.matches(LPAREN):
+ self.comment()
+ else:
+ break
+
+ end = self.eat(RPAREN)
+ return start, end
+
+ def parameter(self):
+ self.eat(SEMI)
+ name = self.eat(TOKEN).value
+ self.eat(EQUAL)
+ value = self.value()
+ return name, value
+
+ def value(self):
+ if self.matches(TOKEN):
+ return self.eat().value
+ elif self.matches(STRING):
+ return rfc822.unquote(self.eat().value)
+ else:
+ raise ParseError(self.next(), TOKEN, STRING)
+
+def parse(addr):
+ return MimeTypeParser(lex(addr)).parse()
+
+__all__ = ["parse", "ParseError"]
diff --git a/python/qpid/ops.py b/python/qpid/ops.py
new file mode 100644
index 0000000000..a8ba826857
--- /dev/null
+++ b/python/qpid/ops.py
@@ -0,0 +1,280 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+import os, mllib, cPickle as pickle
+from util import fill
+
+class Primitive(object):
+ pass
+
+class Enum(object):
+ pass
+
+class Field:
+
+ def __init__(self, name, type, default=None):
+ self.name = name
+ self.type = type
+ self.default = default
+
+ def __repr__(self):
+ return "%s: %s" % (self.name, self.type)
+
+class Compound(object):
+
+ UNENCODED=[]
+
+ def __init__(self, *args, **kwargs):
+ args = list(args)
+ for f in self.ARGS:
+ if args:
+ a = args.pop(0)
+ else:
+ a = kwargs.pop(f.name, f.default)
+ setattr(self, f.name, a)
+ if args:
+ raise TypeError("%s takes at most %s arguments (%s given))" %
+ (self.__class__.__name__, len(self.ARGS),
+ len(self.ARGS) + len(args)))
+ if kwargs:
+ raise TypeError("got unexpected keyword argument '%s'" % kwargs.keys()[0])
+
+ def fields(self):
+ result = {}
+ for f in self.FIELDS:
+ result[f.name] = getattr(self, f.name)
+ return result
+
+ def args(self):
+ result = {}
+ for f in self.ARGS:
+ result[f.name] = getattr(self, f.name)
+ return result
+
+ def __getitem__(self, attr):
+ return getattr(self, attr)
+
+ def __setitem__(self, attr, value):
+ setattr(self, attr, value)
+
+ def dispatch(self, target, *args):
+ handler = "do_%s" % self.NAME
+ getattr(target, handler)(self, *args)
+
+ def __repr__(self, extras=()):
+ return "%s(%s)" % (self.__class__.__name__,
+ ", ".join(["%s=%r" % (f.name, getattr(self, f.name))
+ for f in self.ARGS
+ if getattr(self, f.name) != f.default]))
+
+class Command(Compound):
+ UNENCODED=[Field("channel", "uint16", 0),
+ Field("id", "sequence-no", None),
+ Field("sync", "bit", False),
+ Field("headers", None, None),
+ Field("payload", None, None)]
+
+class Control(Compound):
+ UNENCODED=[Field("channel", "uint16", 0)]
+
+def pythonize(st):
+ if st is None:
+ return None
+ else:
+ return str(st.replace("-", "_"))
+
+def pydoc(op, children=()):
+ doc = "\n\n".join([fill(p.text(), 0) for p in op.query["doc"]])
+ for ch in children:
+ doc += "\n\n " + pythonize(ch["@name"]) + " -- " + str(ch["@label"])
+ ch_descs ="\n\n".join([fill(p.text(), 4) for p in ch.query["doc"]])
+ if ch_descs:
+ doc += "\n\n" + ch_descs
+ return doc
+
+def studly(st):
+ return "".join([p.capitalize() for p in st.split("-")])
+
+def klass(nd):
+ while nd.parent is not None:
+ if hasattr(nd.parent, "name") and nd.parent.name == "class":
+ return nd.parent
+ else:
+ nd = nd.parent
+
+def included(nd):
+ cls = klass(nd)
+ if cls is None:
+ return True
+ else:
+ return cls["@name"] not in ("file", "stream")
+
+def num(s):
+ if s: return int(s, 0)
+
+def code(nd):
+ c = num(nd["@code"])
+ if c is None:
+ return None
+ else:
+ cls = klass(nd)
+ if cls is None:
+ return c
+ else:
+ return c | (num(cls["@code"]) << 8)
+
+def default(f):
+ if f["@type"] == "bit":
+ return False
+ else:
+ return None
+
+def make_compound(decl, base):
+ dict = {}
+ fields = decl.query["field"]
+ dict["__doc__"] = pydoc(decl, fields)
+ dict["NAME"] = pythonize(decl["@name"])
+ dict["SIZE"] = num(decl["@size"])
+ dict["CODE"] = code(decl)
+ dict["PACK"] = num(decl["@pack"])
+ dict["FIELDS"] = [Field(pythonize(f["@name"]), resolve(f), default(f)) for f in fields]
+ dict["ARGS"] = dict["FIELDS"] + base.UNENCODED
+ return str(studly(decl["@name"])), (base,), dict
+
+def make_restricted(decl):
+ name = pythonize(decl["@name"])
+ dict = {}
+ choices = decl.query["choice"]
+ dict["__doc__"] = pydoc(decl, choices)
+ dict["NAME"] = name
+ dict["TYPE"] = str(decl.parent["@type"])
+ values = []
+ for ch in choices:
+ val = int(ch["@value"], 0)
+ dict[pythonize(ch["@name"])] = val
+ values.append(val)
+ dict["VALUES"] = values
+ return name, (Enum,), dict
+
+def make_type(decl):
+ name = pythonize(decl["@name"])
+ dict = {}
+ dict["__doc__"] = pydoc(decl)
+ dict["NAME"] = name
+ dict["CODE"] = code(decl)
+ return str(studly(decl["@name"])), (Primitive,), dict
+
+def make_command(decl):
+ decl.set_attr("name", "%s-%s" % (decl.parent["@name"], decl["@name"]))
+ decl.set_attr("size", "0")
+ decl.set_attr("pack", "2")
+ name, bases, dict = make_compound(decl, Command)
+ dict["RESULT"] = pythonize(decl["result/@type"]) or pythonize(decl["result/struct/@name"])
+ return name, bases, dict
+
+def make_control(decl):
+ decl.set_attr("name", "%s-%s" % (decl.parent["@name"], decl["@name"]))
+ decl.set_attr("size", "0")
+ decl.set_attr("pack", "2")
+ return make_compound(decl, Control)
+
+def make_struct(decl):
+ return make_compound(decl, Compound)
+
+def make_enum(decl):
+ decl.set_attr("name", decl.parent["@name"])
+ return make_restricted(decl)
+
+
+vars = globals()
+
+def make(nd):
+ return vars["make_%s" % nd.name](nd)
+
+from qpid_config import amqp_spec as file
+pclfile = "%s.ops.pcl" % file
+
+if os.path.exists(pclfile) and \
+ os.path.getmtime(pclfile) > os.path.getmtime(file):
+ f = open(pclfile, "r")
+ types = pickle.load(f)
+ f.close()
+else:
+ spec = mllib.xml_parse(file)
+
+ def qualify(nd, field="@name"):
+ cls = klass(nd)
+ if cls is None:
+ return pythonize(nd[field])
+ else:
+ return pythonize("%s.%s" % (cls["@name"], nd[field]))
+
+ domains = dict([(qualify(d), pythonize(d["@type"]))
+ for d in spec.query["amqp/domain", included] + \
+ spec.query["amqp/class/domain", included]])
+
+ def resolve(nd):
+ candidates = qualify(nd, "@type"), pythonize(nd["@type"])
+ for c in candidates:
+ if domains.has_key(c):
+ while domains.has_key(c):
+ c = domains[c]
+ return c
+ else:
+ return c
+
+ type_decls = \
+ spec.query["amqp/class/command", included] + \
+ spec.query["amqp/class/control", included] + \
+ spec.query["amqp/class/command/result/struct", included] + \
+ spec.query["amqp/class/struct", included] + \
+ spec.query["amqp/class/domain/enum", included] + \
+ spec.query["amqp/domain/enum", included] + \
+ spec.query["amqp/type"]
+ types = [make(nd) for nd in type_decls]
+
+ if os.access(os.path.dirname(os.path.abspath(pclfile)), os.W_OK):
+ f = open(pclfile, "w")
+ pickle.dump(types, f)
+ f.close()
+
+ENUMS = {}
+PRIMITIVE = {}
+COMPOUND = {}
+COMMANDS = {}
+CONTROLS = {}
+
+for name, bases, _dict in types:
+ t = type(name, bases, _dict)
+ vars[name] = t
+
+ if issubclass(t, Command):
+ COMMANDS[t.NAME] = t
+ COMMANDS[t.CODE] = t
+ elif issubclass(t, Control):
+ CONTROLS[t.NAME] = t
+ CONTROLS[t.CODE] = t
+ elif issubclass(t, Compound):
+ COMPOUND[t.NAME] = t
+ if t.CODE is not None:
+ COMPOUND[t.CODE] = t
+ elif issubclass(t, Primitive):
+ PRIMITIVE[t.NAME] = t
+ PRIMITIVE[t.CODE] = t
+ elif issubclass(t, Enum):
+ ENUMS[t.NAME] = t
diff --git a/python/qpid/parser.py b/python/qpid/parser.py
new file mode 100644
index 0000000000..233f0a8469
--- /dev/null
+++ b/python/qpid/parser.py
@@ -0,0 +1,68 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+class ParseError(Exception):
+
+ def __init__(self, token, *expected):
+ line, ln, col = token.line_info()
+ exp = ", ".join(map(str, expected))
+ if len(expected) > 1:
+ exp = "(%s)" % exp
+ if expected:
+ msg = "expecting %s, got %s line:%s,%s:%s" % (exp, token, ln, col, line)
+ else:
+ msg = "unexpected token %s line:%s,%s:%s" % (token, ln, col, line)
+ Exception.__init__(self, msg)
+ self.token = token
+ self.expected = expected
+
+class Parser:
+
+ def __init__(self, tokens):
+ self.tokens = tokens
+ self.idx = 0
+
+ def next(self):
+ return self.tokens[self.idx]
+
+ def matches(self, *types):
+ return self.next().type in types
+
+ def eat(self, *types):
+ if types and not self.matches(*types):
+ raise ParseError(self.next(), *types)
+ else:
+ t = self.next()
+ self.idx += 1
+ return t
+
+ def eat_until(self, *types):
+ result = []
+ while not self.matches(*types):
+ result.append(self.eat())
+ return result
+
+ def remove(self, start, end):
+ start_idx = self.tokens.index(start)
+ end_idx = self.tokens.index(end) + 1
+ del self.tokens[start_idx:end_idx]
+ self.idx -= end_idx - start_idx
+
+ def reset(self):
+ self.idx = 0
diff --git a/python/qpid/peer.py b/python/qpid/peer.py
index 0932efeab3..2bc9844351 100644
--- a/python/qpid/peer.py
+++ b/python/qpid/peer.py
@@ -25,7 +25,7 @@ incoming method frames to a delegate.
"""
import thread, threading, traceback, socket, sys, logging
-from connection08 import EOF, Method, Header, Body, Request, Response
+from connection08 import EOF, Method, Header, Body, Request, Response, VersionError
from message import Message
from queue import Queue, Closed as QueueClosed
from content import Content
@@ -95,6 +95,8 @@ class Peer:
break
ch = self.channel(frame.channel)
ch.receive(frame, self.work)
+ except VersionError, e:
+ self.closed(e)
except:
self.fatal()
@@ -193,11 +195,7 @@ class Channel:
self.futures = {}
self.control_queue = Queue(0)#used for incoming methods that appas may want to handle themselves
- # Use reliable framing if version == 0-9.
- if spec.major == 0 and spec.minor == 9:
- self.invoker = self.invoke_reliable
- else:
- self.invoker = self.invoke_method
+ self.invoker = self.invoke_method
self.use_execution_layer = (spec.major == 0 and spec.minor == 10) or (spec.major == 99 and spec.minor == 0)
self.synchronous = True
@@ -464,6 +462,6 @@ class IncomingCompletion:
#TODO: record and manage the ranges properly
range = [mark, mark]
if (self.mark == -1):#hack until wraparound is implemented
- self.channel.execution_complete(cumulative_execution_mark=0xFFFFFFFF, ranged_execution_set=range)
+ self.channel.execution_complete(cumulative_execution_mark=0xFFFFFFFFL, ranged_execution_set=range)
else:
self.channel.execution_complete(cumulative_execution_mark=self.mark, ranged_execution_set=range)
diff --git a/python/qpid/queue.py b/python/qpid/queue.py
index c9f4d1d1d0..63a7684843 100644
--- a/python/qpid/queue.py
+++ b/python/qpid/queue.py
@@ -63,7 +63,9 @@ class Queue(BaseQueue):
if listener is None:
if self.thread is not None:
self.put(Queue.STOP)
- self.thread.join()
+ # loop and timed join permit keyboard interrupts to work
+ while self.thread.isAlive():
+ self.thread.join(3)
self.thread = None
self.listener = listener
diff --git a/python/qpid/selector.py b/python/qpid/selector.py
new file mode 100644
index 0000000000..ca5946c3f9
--- /dev/null
+++ b/python/qpid/selector.py
@@ -0,0 +1,139 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+import atexit, time
+from compat import select, set, selectable_waiter
+from threading import Thread, Lock
+
+class Acceptor:
+
+ def __init__(self, sock, handler):
+ self.sock = sock
+ self.handler = handler
+
+ def fileno(self):
+ return self.sock.fileno()
+
+ def reading(self):
+ return True
+
+ def writing(self):
+ return False
+
+ def readable(self):
+ sock, addr = self.sock.accept()
+ self.handler(sock)
+
+class Selector:
+
+ lock = Lock()
+ DEFAULT = None
+
+ @staticmethod
+ def default():
+ Selector.lock.acquire()
+ try:
+ if Selector.DEFAULT is None:
+ sel = Selector()
+ atexit.register(sel.stop)
+ sel.start()
+ Selector.DEFAULT = sel
+ return Selector.DEFAULT
+ finally:
+ Selector.lock.release()
+
+ def __init__(self):
+ self.selectables = set()
+ self.reading = set()
+ self.writing = set()
+ self.waiter = selectable_waiter()
+ self.reading.add(self.waiter)
+ self.stopped = False
+ self.thread = None
+
+ def wakeup(self):
+ self.waiter.wakeup()
+
+ def register(self, selectable):
+ self.selectables.add(selectable)
+ self.modify(selectable)
+
+ def _update(self, selectable):
+ if selectable.reading():
+ self.reading.add(selectable)
+ else:
+ self.reading.discard(selectable)
+ if selectable.writing():
+ self.writing.add(selectable)
+ else:
+ self.writing.discard(selectable)
+ return selectable.timing()
+
+ def modify(self, selectable):
+ self._update(selectable)
+ self.wakeup()
+
+ def unregister(self, selectable):
+ self.reading.discard(selectable)
+ self.writing.discard(selectable)
+ self.selectables.discard(selectable)
+ self.wakeup()
+
+ def start(self):
+ self.stopped = False
+ self.thread = Thread(target=self.run)
+ self.thread.setDaemon(True)
+ self.thread.start();
+
+ def run(self):
+ while not self.stopped:
+ wakeup = None
+ for sel in self.selectables.copy():
+ t = self._update(sel)
+ if t is not None:
+ if wakeup is None:
+ wakeup = t
+ else:
+ wakeup = min(wakeup, t)
+
+ if wakeup is None:
+ timeout = None
+ else:
+ timeout = max(0, wakeup - time.time())
+
+ rd, wr, ex = select(self.reading, self.writing, (), timeout)
+
+ for sel in wr:
+ if sel.writing():
+ sel.writeable()
+
+ for sel in rd:
+ if sel.reading():
+ sel.readable()
+
+ now = time.time()
+ for sel in self.selectables.copy():
+ w = sel.timing()
+ if w is not None and now > w:
+ sel.timeout()
+
+ def stop(self, timeout=None):
+ self.stopped = True
+ self.wakeup()
+ self.thread.join(timeout)
+ self.thread = None
diff --git a/python/qpid/session.py b/python/qpid/session.py
index 2f70461ab6..2f1bd81bd4 100644
--- a/python/qpid/session.py
+++ b/python/qpid/session.py
@@ -18,12 +18,13 @@
#
from threading import Condition, RLock, Lock, currentThread
-from invoker import Invoker
+from spec import SPEC
+from generator import command_invoker
from datatypes import RangedSet, Struct, Future
from codec010 import StringCodec
-from assembler import Segment
from queue import Queue
from datatypes import Message, serial
+from ops import Command, MessageTransfer
from util import wait, notify
from exceptions import *
from logging import getLogger
@@ -43,12 +44,12 @@ def server(*args):
INCOMPLETE = object()
-class Session(Invoker):
+class Session(command_invoker()):
- def __init__(self, name, spec, auto_sync=True, timeout=10, delegate=client):
+ def __init__(self, name, auto_sync=True, timeout=10, delegate=client):
self.name = name
- self.spec = spec
self.auto_sync = auto_sync
+ self.need_sync = True
self.timeout = timeout
self.channel = None
self.invoke_lock = Lock()
@@ -66,8 +67,6 @@ class Session(Invoker):
self.results = {}
self.exceptions = []
- self.assembly = None
-
self.delegate = delegate(self)
def incoming(self, destination):
@@ -94,7 +93,7 @@ class Session(Invoker):
ch = self.channel
if ch is not None and currentThread() == ch.connection.thread:
raise SessionException("deadlock detected")
- if not self.auto_sync:
+ if self.need_sync:
self.execution_sync(sync=True)
last = self.sender.next_id - 1
if not wait(self.condition, lambda:
@@ -133,82 +132,50 @@ class Session(Invoker):
finally:
self.lock.release()
- def resolve_method(self, name):
- cmd = self.spec.instructions.get(name)
- if cmd is not None and cmd.track == self.spec["track.command"].value:
- return self.METHOD, cmd
+ def invoke(self, op, args, kwargs):
+ if issubclass(op, Command):
+ self.invoke_lock.acquire()
+ try:
+ return self.do_invoke(op, args, kwargs)
+ finally:
+ self.invoke_lock.release()
else:
- # XXX
- for st in self.spec.structs.values():
- if st.name == name:
- return self.METHOD, st
- if self.spec.structs_by_name.has_key(name):
- return self.METHOD, self.spec.structs_by_name[name]
- if self.spec.enums.has_key(name):
- return self.VALUE, self.spec.enums[name]
- return self.ERROR, None
-
- def invoke(self, type, args, kwargs):
- # XXX
- if not hasattr(type, "track"):
- return type.new(args, kwargs)
-
- self.invoke_lock.acquire()
- try:
- return self.do_invoke(type, args, kwargs)
- finally:
- self.invoke_lock.release()
+ return op(*args, **kwargs)
- def do_invoke(self, type, args, kwargs):
+ def do_invoke(self, op, args, kwargs):
if self._closing:
raise SessionClosed()
- if self.channel == None:
+ ch = self.channel
+ if ch == None:
raise SessionDetached()
- if type.segments:
- if len(args) == len(type.fields) + 1:
+ if op == MessageTransfer:
+ if len(args) == len(op.FIELDS) + 1:
message = args[-1]
args = args[:-1]
else:
message = kwargs.pop("message", None)
- else:
- message = None
-
- hdr = Struct(self.spec["session.header"])
- hdr.sync = self.auto_sync or kwargs.pop("sync", False)
+ if message is not None:
+ kwargs["headers"] = message.headers
+ kwargs["payload"] = message.body
- cmd = type.new(args, kwargs)
- sc = StringCodec(self.spec)
- sc.write_command(hdr, cmd)
+ cmd = op(*args, **kwargs)
+ cmd.sync = self.auto_sync or cmd.sync
+ self.need_sync = not cmd.sync
+ cmd.channel = ch.id
- seg = Segment(True, (message == None or
- (message.headers == None and message.body == None)),
- type.segment_type, type.track, self.channel.id, sc.encoded)
-
- if type.result:
+ if op.RESULT:
result = Future(exception=SessionException)
self.results[self.sender.next_id] = result
- self.send(seg)
-
- log.debug("SENT %s %s %s", seg.id, hdr, cmd)
-
- if message != None:
- if message.headers != None:
- sc = StringCodec(self.spec)
- for st in message.headers:
- sc.write_struct32(st)
- seg = Segment(False, message.body == None, self.spec["segment_type.header"].value,
- type.track, self.channel.id, sc.encoded)
- self.send(seg)
- if message.body != None:
- seg = Segment(False, True, self.spec["segment_type.body"].value,
- type.track, self.channel.id, message.body)
- self.send(seg)
- msg.debug("SENT %s", message)
-
- if type.result:
+ self.send(cmd)
+
+ log.debug("SENT %s", cmd)
+ if op == MessageTransfer:
+ msg.debug("SENT %s", cmd)
+
+ if op.RESULT:
if self.auto_sync:
return result.get(self.timeout)
else:
@@ -216,81 +183,47 @@ class Session(Invoker):
elif self.auto_sync:
self.sync(self.timeout)
- def received(self, seg):
- self.receiver.received(seg)
- if seg.first:
- assert self.assembly == None
- self.assembly = []
- self.assembly.append(seg)
- if seg.last:
- self.dispatch(self.assembly)
- self.assembly = None
+ def received(self, cmd):
+ self.receiver.received(cmd)
+ self.dispatch(cmd)
- def dispatch(self, assembly):
- segments = assembly[:]
+ def dispatch(self, cmd):
+ log.debug("RECV %s", cmd)
- hdr, cmd = assembly.pop(0).decode(self.spec)
- log.debug("RECV %s %s %s", cmd.id, hdr, cmd)
-
- args = []
-
- for st in cmd._type.segments:
- if assembly:
- seg = assembly[0]
- if seg.type == st.segment_type:
- args.append(seg.decode(self.spec))
- assembly.pop(0)
- continue
- args.append(None)
-
- assert len(assembly) == 0
-
- attr = cmd._type.qname.replace(".", "_")
- result = getattr(self.delegate, attr)(cmd, *args)
-
- if cmd._type.result:
+ result = getattr(self.delegate, cmd.NAME)(cmd)
+ if result is INCOMPLETE:
+ return
+ elif result is not None:
self.execution_result(cmd.id, result)
- if result is not INCOMPLETE:
- for seg in segments:
- self.receiver.completed(seg)
- # XXX: don't forget to obey sync for manual completion as well
- if hdr.sync:
- self.channel.session_completed(self.receiver._completed)
+ self.receiver.completed(cmd)
+ # XXX: don't forget to obey sync for manual completion as well
+ if cmd.sync:
+ self.channel.session_completed(self.receiver._completed)
- def send(self, seg):
- self.sender.send(seg)
-
- def __str__(self):
- return '<Session: %s, %s>' % (self.name, self.channel)
+ def send(self, cmd):
+ self.sender.send(cmd)
def __repr__(self):
- return str(self)
+ return '<Session: %s, %s>' % (self.name, self.channel)
class Receiver:
def __init__(self, session):
self.session = session
self.next_id = None
- self.next_offset = None
self._completed = RangedSet()
- def received(self, seg):
- if self.next_id == None or self.next_offset == None:
+ def received(self, cmd):
+ if self.next_id == None:
raise Exception("todo")
- seg.id = self.next_id
- seg.offset = self.next_offset
- if seg.last:
- self.next_id += 1
- self.next_offset = 0
- else:
- self.next_offset += len(seg.payload)
+ cmd.id = self.next_id
+ self.next_id += 1
- def completed(self, seg):
- if seg.id == None:
- raise ValueError("cannot complete unidentified segment")
- if seg.last:
- self._completed.add(seg.id)
+ def completed(self, cmd):
+ if cmd.id == None:
+ raise ValueError("cannot complete unidentified command")
+ self._completed.add(cmd.id)
def known_completed(self, commands):
completed = RangedSet()
@@ -307,30 +240,27 @@ class Sender:
def __init__(self, session):
self.session = session
self.next_id = serial(0)
- self.next_offset = 0
- self.segments = []
+ self.commands = []
self._completed = RangedSet()
- def send(self, seg):
- seg.id = self.next_id
- seg.offset = self.next_offset
- if seg.last:
- self.next_id += 1
- self.next_offset = 0
- else:
- self.next_offset += len(seg.payload)
- self.segments.append(seg)
+ def send(self, cmd):
+ ch = self.session.channel
+ if ch is None:
+ raise SessionDetached()
+ cmd.id = self.next_id
+ self.next_id += 1
if self.session.send_id:
self.session.send_id = False
- self.session.channel.session_command_point(seg.id, seg.offset)
- self.session.channel.connection.write_segment(seg)
+ ch.session_command_point(cmd.id, 0)
+ self.commands.append(cmd)
+ ch.connection.write_op(cmd)
def completed(self, commands):
idx = 0
- while idx < len(self.segments):
- seg = self.segments[idx]
- if seg.id in commands:
- del self.segments[idx]
+ while idx < len(self.commands):
+ cmd = self.commands[idx]
+ if cmd.id in commands:
+ del self.commands[idx]
else:
idx += 1
for range in commands.ranges:
@@ -344,8 +274,9 @@ class Incoming(Queue):
self.destination = destination
def start(self):
- for unit in self.session.credit_unit.values():
- self.session.message_flow(self.destination, unit, 0xFFFFFFFF)
+ self.session.message_set_flow_mode(self.destination, self.session.flow_mode.credit)
+ for unit in self.session.credit_unit.VALUES:
+ self.session.message_flow(self.destination, unit, 0xFFFFFFFFL)
def stop(self):
self.session.message_cancel(self.destination)
@@ -368,9 +299,9 @@ class Delegate:
class Client(Delegate):
- def message_transfer(self, cmd, headers, body):
- m = Message(body)
- m.headers = headers
+ def message_transfer(self, cmd):
+ m = Message(cmd.payload)
+ m.headers = cmd.headers
m.id = cmd.id
messages = self.session.incoming(cmd.destination)
messages.put(m)
diff --git a/python/qpid/spec.py b/python/qpid/spec.py
index e6d914044c..e9bfef1fa6 100644
--- a/python/qpid/spec.py
+++ b/python/qpid/spec.py
@@ -29,7 +29,7 @@ class so that the generated code can be reused in a variety of
situations.
"""
-import os, mllib, spec08, spec010
+import os, mllib, spec08
def default():
try:
@@ -54,6 +54,8 @@ def load(specfile, *errata):
minor = doc["amqp/@minor"]
if major == "0" and minor == "10":
- return spec010.load(specfile, *errata)
+ return None
else:
return spec08.load(specfile, *errata)
+
+SPEC = load(default())
diff --git a/python/qpid/spec010.py b/python/qpid/spec010.py
deleted file mode 100644
index 23966e6176..0000000000
--- a/python/qpid/spec010.py
+++ /dev/null
@@ -1,691 +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.
-#
-
-import os, cPickle, datatypes
-from codec010 import StringCodec
-from util import mtime, fill
-
-class Node:
-
- def __init__(self, children):
- self.children = children
- self.named = {}
- self.docs = []
- self.rules = []
-
- def register(self):
- for ch in self.children:
- ch.register(self)
-
- def resolve(self):
- for ch in self.children:
- ch.resolve()
-
- def __getitem__(self, name):
- path = name.split(".", 1)
- nd = self.named
- for step in path:
- nd = nd[step]
- return nd
-
- def __iter__(self):
- return iter(self.children)
-
-class Anonymous:
-
- def __init__(self, children):
- self.children = children
-
- def register(self, node):
- for ch in self.children:
- ch.register(node)
-
- def resolve(self):
- for ch in self.children:
- ch.resolve()
-
-class Named:
-
- def __init__(self, name):
- self.name = name
- self.qname = None
-
- def register(self, node):
- self.spec = node.spec
- self.klass = node.klass
- node.named[self.name] = self
- if node.qname:
- self.qname = "%s.%s" % (node.qname, self.name)
- else:
- self.qname = self.name
-
- def __str__(self):
- return self.qname
-
- def __repr__(self):
- return str(self)
-
-class Lookup:
-
- def lookup(self, name):
- value = None
- if self.klass:
- try:
- value = self.klass[name]
- except KeyError:
- pass
- if not value:
- value = self.spec[name]
- return value
-
-class Coded:
-
- def __init__(self, code):
- self.code = code
-
-class Constant(Named, Node):
-
- def __init__(self, name, value, children):
- Named.__init__(self, name)
- Node.__init__(self, children)
- self.value = value
-
- def register(self, node):
- Named.register(self, node)
- node.constants.append(self)
- Node.register(self)
-
-class Type(Named, Node):
-
- def __init__(self, name, children):
- Named.__init__(self, name)
- Node.__init__(self, children)
-
- def is_present(self, value):
- return value != None
-
- def register(self, node):
- Named.register(self, node)
- Node.register(self)
-
-class Primitive(Coded, Type):
-
- def __init__(self, name, code, fixed, variable, children):
- Coded.__init__(self, code)
- Type.__init__(self, name, children)
- self.fixed = fixed
- self.variable = variable
-
- def register(self, node):
- Type.register(self, node)
- if self.code is not None:
- self.spec.types[self.code] = self
-
- def is_present(self, value):
- if self.fixed == 0:
- return value
- else:
- return Type.is_present(self, value)
-
- def encode(self, codec, value):
- getattr(codec, "write_%s" % self.name)(value)
-
- def decode(self, codec):
- return getattr(codec, "read_%s" % self.name)()
-
-class Domain(Type, Lookup):
-
- def __init__(self, name, type, children):
- Type.__init__(self, name, children)
- self.type = type
- self.choices = {}
-
- def resolve(self):
- self.type = self.lookup(self.type)
- Node.resolve(self)
-
- def encode(self, codec, value):
- self.type.encode(codec, value)
-
- def decode(self, codec):
- return self.type.decode(codec)
-
-class Enum:
-
- def __init__(self, name):
- self.name = name
- self._names = ()
- self._values = ()
-
- def values(self):
- return self._values
-
- def __repr__(self):
- return "%s(%s)" % (self.name, ", ".join(self._names))
-
-class Choice(Named, Node):
-
- def __init__(self, name, value, children):
- Named.__init__(self, name)
- Node.__init__(self, children)
- self.value = value
-
- def register(self, node):
- Named.register(self, node)
- node.choices[self.value] = self
- Node.register(self)
- try:
- enum = node.spec.enums[node.name]
- except KeyError:
- enum = Enum(node.name)
- node.spec.enums[node.name] = enum
- setattr(enum, self.name, self.value)
- enum._names += (self.name,)
- enum._values += (self.value,)
-
-class Composite(Type, Coded):
-
- def __init__(self, name, label, code, size, pack, children):
- Coded.__init__(self, code)
- Type.__init__(self, name, children)
- self.label = label
- self.fields = []
- self.size = size
- self.pack = pack
-
- def new(self, args, kwargs):
- return datatypes.Struct(self, *args, **kwargs)
-
- def decode(self, codec):
- codec.read_size(self.size)
- if self.code is not None:
- code = codec.read_uint16()
- assert self.code == code
- return datatypes.Struct(self, **self.decode_fields(codec))
-
- def decode_fields(self, codec):
- flags = 0
- for i in range(self.pack):
- flags |= (codec.read_uint8() << 8*i)
-
- result = {}
-
- for i in range(len(self.fields)):
- f = self.fields[i]
- if flags & (0x1 << i):
- result[f.name] = f.type.decode(codec)
- else:
- result[f.name] = None
- return result
-
- def encode(self, codec, value):
- sc = StringCodec(self.spec)
- if self.code is not None:
- sc.write_uint16(self.code)
- self.encode_fields(sc, value)
- codec.write_size(self.size, len(sc.encoded))
- codec.write(sc.encoded)
-
- def encode_fields(self, codec, values):
- flags = 0
- for i in range(len(self.fields)):
- f = self.fields[i]
- if f.type.is_present(values[f.name]):
- flags |= (0x1 << i)
- for i in range(self.pack):
- codec.write_uint8((flags >> 8*i) & 0xFF)
- for i in range(len(self.fields)):
- f = self.fields[i]
- if flags & (0x1 << i):
- f.type.encode(codec, values[f.name])
-
- def docstring(self):
- docs = []
- if self.label:
- docs.append(self.label)
- docs += [d.text for d in self.docs]
- s = "\n\n".join([fill(t, 2) for t in docs])
- for f in self.fields:
- fdocs = []
- if f.label:
- fdocs.append(f.label)
- else:
- fdocs.append("")
- fdocs += [d.text for d in f.docs]
- s += "\n\n" + "\n\n".join([fill(fdocs[0], 4, f.name)] +
- [fill(t, 4) for t in fdocs[1:]])
- return s
-
-
-class Field(Named, Node, Lookup):
-
- def __init__(self, name, label, type, children):
- Named.__init__(self, name)
- Node.__init__(self, children)
- self.label = label
- self.type = type
- self.exceptions = []
-
- def default(self):
- return None
-
- def register(self, node):
- Named.register(self, node)
- node.fields.append(self)
- Node.register(self)
-
- def resolve(self):
- self.type = self.lookup(self.type)
- Node.resolve(self)
-
- def __str__(self):
- return "%s: %s" % (self.qname, self.type.qname)
-
-class Struct(Composite):
-
- def register(self, node):
- Composite.register(self, node)
- if self.code is not None:
- self.spec.structs[self.code] = self
- self.spec.structs_by_name[self.name] = self
- self.pyname = self.name
- self.pydoc = self.docstring()
-
- def __str__(self):
- fields = ",\n ".join(["%s: %s" % (f.name, f.type.qname)
- for f in self.fields])
- return "%s {\n %s\n}" % (self.qname, fields)
-
-class Segment:
-
- def __init__(self):
- self.segment_type = None
-
- def register(self, node):
- self.spec = node.spec
- self.klass = node.klass
- node.segments.append(self)
- Node.register(self)
-
-class Instruction(Composite, Segment):
-
- def __init__(self, name, label, code, children):
- Composite.__init__(self, name, label, code, 0, 2, children)
- Segment.__init__(self)
- self.track = None
- self.handlers = []
-
- def __str__(self):
- return "%s(%s)" % (self.qname, ", ".join(["%s: %s" % (f.name, f.type.qname)
- for f in self.fields]))
-
- def register(self, node):
- Composite.register(self, node)
- self.pyname = self.qname.replace(".", "_")
- self.pydoc = self.docstring()
- self.spec.instructions[self.pyname] = self
-
-class Control(Instruction):
-
- def __init__(self, name, code, label, children):
- Instruction.__init__(self, name, code, label, children)
- self.response = None
-
- def register(self, node):
- Instruction.register(self, node)
- node.controls.append(self)
- self.spec.controls[self.code] = self
- self.segment_type = self.spec["segment_type.control"].value
- self.track = self.spec["track.control"].value
-
-class Command(Instruction):
-
- def __init__(self, name, label, code, children):
- Instruction.__init__(self, name, label, code, children)
- self.result = None
- self.exceptions = []
- self.segments = []
-
- def register(self, node):
- Instruction.register(self, node)
- node.commands.append(self)
- self.spec.commands[self.code] = self
- self.segment_type = self.spec["segment_type.command"].value
- self.track = self.spec["track.command"].value
-
-class Header(Segment, Node):
-
- def __init__(self, children):
- Segment.__init__(self)
- Node.__init__(self, children)
- self.entries = []
-
- def register(self, node):
- Segment.register(self, node)
- self.segment_type = self.spec["segment_type.header"].value
- Node.register(self)
-
-class Entry(Lookup):
-
- def __init__(self, type):
- self.type = type
-
- def register(self, node):
- self.spec = node.spec
- self.klass = node.klass
- node.entries.append(self)
-
- def resolve(self):
- self.type = self.lookup(self.type)
-
-class Body(Segment, Node):
-
- def __init__(self, children):
- Segment.__init__(self)
- Node.__init__(self, children)
-
- def register(self, node):
- Segment.register(self, node)
- self.segment_type = self.spec["segment_type.body"].value
- Node.register(self)
-
- def resolve(self): pass
-
-class Class(Named, Coded, Node):
-
- def __init__(self, name, code, children):
- Named.__init__(self, name)
- Coded.__init__(self, code)
- Node.__init__(self, children)
- self.controls = []
- self.commands = []
-
- def register(self, node):
- Named.register(self, node)
- self.klass = self
- node.classes.append(self)
- Node.register(self)
-
-class Doc:
-
- def __init__(self, type, title, text):
- self.type = type
- self.title = title
- self.text = text
-
- def register(self, node):
- node.docs.append(self)
-
- def resolve(self): pass
-
-class Role(Named, Node):
-
- def __init__(self, name, children):
- Named.__init__(self, name)
- Node.__init__(self, children)
-
- def register(self, node):
- Named.register(self, node)
- Node.register(self)
-
-class Rule(Named, Node):
-
- def __init__(self, name, children):
- Named.__init__(self, name)
- Node.__init__(self, children)
-
- def register(self, node):
- Named.register(self, node)
- node.rules.append(self)
- Node.register(self)
-
-class Exception(Named, Node):
-
- def __init__(self, name, error_code, children):
- Named.__init__(self, name)
- Node.__init__(self, children)
- self.error_code = error_code
-
- def register(self, node):
- Named.register(self, node)
- node.exceptions.append(self)
- Node.register(self)
-
-class Spec(Node):
-
- ENCODINGS = {
- basestring: "vbin16",
- int: "int64",
- long: "int64",
- float: "float",
- None.__class__: "void",
- list: "list",
- tuple: "list",
- dict: "map"
- }
-
- def __init__(self, major, minor, port, children):
- Node.__init__(self, children)
- self.major = major
- self.minor = minor
- self.port = port
- self.constants = []
- self.classes = []
- self.types = {}
- self.qname = None
- self.spec = self
- self.klass = None
- self.instructions = {}
- self.controls = {}
- self.commands = {}
- self.structs = {}
- self.structs_by_name = {}
- self.enums = {}
-
- def encoding(self, klass):
- if Spec.ENCODINGS.has_key(klass):
- return self.named[Spec.ENCODINGS[klass]]
- for base in klass.__bases__:
- result = self.encoding(base)
- if result != None:
- return result
-
-class Implement:
-
- def __init__(self, handle):
- self.handle = handle
-
- def register(self, node):
- node.handlers.append(self.handle)
-
- def resolve(self): pass
-
-class Response(Node):
-
- def __init__(self, name, children):
- Node.__init__(self, children)
- self.name = name
-
- def register(self, node):
- Node.register(self)
-
-class Result(Node, Lookup):
-
- def __init__(self, type, children):
- self.type = type
- Node.__init__(self, children)
-
- def register(self, node):
- node.result = self
- self.qname = node.qname
- self.klass = node.klass
- self.spec = node.spec
- Node.register(self)
-
- def resolve(self):
- self.type = self.lookup(self.type)
- Node.resolve(self)
-
-import mllib
-
-def num(s):
- if s: return int(s, 0)
-
-REPLACE = {" ": "_", "-": "_"}
-KEYWORDS = {"global": "global_",
- "return": "return_"}
-
-def id(name):
- name = str(name)
- for key, val in REPLACE.items():
- name = name.replace(key, val)
- try:
- name = KEYWORDS[name]
- except KeyError:
- pass
- return name
-
-class Loader:
-
- def __init__(self):
- self.class_code = 0
-
- def code(self, nd):
- c = num(nd["@code"])
- if c is None:
- return None
- else:
- return c | (self.class_code << 8)
-
- def list(self, q):
- result = []
- for nd in q:
- result.append(nd.dispatch(self))
- return result
-
- def children(self, n):
- return self.list(n.query["#tag"])
-
- def data(self, d):
- return d.data
-
- def do_amqp(self, a):
- return Spec(num(a["@major"]), num(a["@minor"]), num(a["@port"]),
- self.children(a))
-
- def do_type(self, t):
- return Primitive(id(t["@name"]), self.code(t), num(t["@fixed-width"]),
- num(t["@variable-width"]), self.children(t))
-
- def do_constant(self, c):
- return Constant(id(c["@name"]), num(c["@value"]), self.children(c))
-
- def do_domain(self, d):
- return Domain(id(d["@name"]), id(d["@type"]), self.children(d))
-
- def do_enum(self, e):
- return Anonymous(self.children(e))
-
- def do_choice(self, c):
- return Choice(id(c["@name"]), num(c["@value"]), self.children(c))
-
- def do_class(self, c):
- code = num(c["@code"])
- self.class_code = code
- children = self.children(c)
- children += self.list(c.query["command/result/struct"])
- self.class_code = 0
- return Class(id(c["@name"]), code, children)
-
- def do_doc(self, doc):
- text = reduce(lambda x, y: x + y, self.list(doc.children))
- return Doc(doc["@type"], doc["@title"], text)
-
- def do_xref(self, x):
- return x["@ref"]
-
- def do_role(self, r):
- return Role(id(r["@name"]), self.children(r))
-
- def do_control(self, c):
- return Control(id(c["@name"]), c["@label"], self.code(c), self.children(c))
-
- def do_rule(self, r):
- return Rule(id(r["@name"]), self.children(r))
-
- def do_implement(self, i):
- return Implement(id(i["@handle"]))
-
- def do_response(self, r):
- return Response(id(r["@name"]), self.children(r))
-
- def do_field(self, f):
- return Field(id(f["@name"]), f["@label"], id(f["@type"]), self.children(f))
-
- def do_struct(self, s):
- return Struct(id(s["@name"]), s["@label"], self.code(s), num(s["@size"]),
- num(s["@pack"]), self.children(s))
-
- def do_command(self, c):
- return Command(id(c["@name"]), c["@label"], self.code(c), self.children(c))
-
- def do_segments(self, s):
- return Anonymous(self.children(s))
-
- def do_header(self, h):
- return Header(self.children(h))
-
- def do_entry(self, e):
- return Entry(id(e["@type"]))
-
- def do_body(self, b):
- return Body(self.children(b))
-
- def do_result(self, r):
- type = r["@type"]
- if not type:
- type = r["struct/@name"]
- return Result(id(type), self.list(r.query["#tag", lambda x: x.name != "struct"]))
-
- def do_exception(self, e):
- return Exception(id(e["@name"]), id(e["@error-code"]), self.children(e))
-
-def load(xml):
- fname = xml + ".pcl"
-
- if os.path.exists(fname) and mtime(fname) > mtime(__file__):
- file = open(fname, "r")
- s = cPickle.load(file)
- file.close()
- else:
- doc = mllib.xml_parse(xml)
- s = doc["amqp"].dispatch(Loader())
- s.register()
- s.resolve()
-
- try:
- file = open(fname, "w")
- except IOError:
- file = None
-
- if file:
- cPickle.dump(s, file)
- file.close()
-
- return s
diff --git a/python/qpid/testlib.py b/python/qpid/testlib.py
index b5aa59f586..1439b892ea 100644
--- a/python/qpid/testlib.py
+++ b/python/qpid/testlib.py
@@ -21,191 +21,13 @@
# Support library for qpid python tests.
#
-import sys, re, unittest, os, random, logging, traceback
-import qpid.client, qpid.spec
+import unittest, traceback, socket
+import qpid.client, qmf.console
import Queue
-from fnmatch import fnmatch
-from getopt import getopt, GetoptError
from qpid.content import Content
from qpid.message import Message
-
-#0-10 support
-from qpid.connection import Connection
-from qpid.spec010 import load
-from qpid.util import connect
-
-def findmodules(root):
- """Find potential python modules under directory root"""
- found = []
- for dirpath, subdirs, files in os.walk(root):
- modpath = dirpath.replace(os.sep, '.')
- if not re.match(r'\.svn$', dirpath): # Avoid SVN directories
- for f in files:
- match = re.match(r'(.+)\.py$', f)
- if match and f != '__init__.py':
- found.append('.'.join([modpath, match.group(1)]))
- return found
-
-def default(value, default):
- if (value == None): return default
- else: return value
-
-class TestRunner:
-
- SPEC_FOLDER = "../specs"
-
- """Runs unit tests.
-
- Parses command line arguments, provides utility functions for tests,
- runs the selected test suite.
- """
-
- def _die(self, message = None):
- if message: print message
- print """
-run-tests [options] [test*]
-The name of a test is package.module.ClassName.testMethod
-Options:
- -?/-h/--help : this message
- -s/--spec <spec.xml> : URL of AMQP XML specification or one of these abbreviations:
- 0-8 - use the default 0-8 specification.
- 0-9 - use the default 0-9 specification.
- -e/--errata <errata.xml> : file containing amqp XML errata
- -b/--broker [<user>[/<password>]@]<host>[:<port>] : broker to connect to
- -v/--verbose : verbose - lists tests as they are run.
- -d/--debug : enable debug logging.
- -i/--ignore <test> : ignore the named test.
- -I/--ignore-file : file containing patterns to ignore.
- -S/--skip-self-test : skips the client self tests in the 'tests folder'
- -F/--spec-folder : folder that contains the specs to be loaded
- """
- sys.exit(1)
-
- def setBroker(self, broker):
- rex = re.compile(r"""
- # [ <user> [ / <password> ] @] <host> [ :<port> ]
- ^ (?: ([^/]*) (?: / ([^@]*) )? @)? ([^:]+) (?: :([0-9]+))?$""", re.X)
- match = rex.match(broker)
- if not match: self._die("'%s' is not a valid broker" % (broker))
- self.user, self.password, self.host, self.port = match.groups()
- self.port = int(default(self.port, 5672))
- self.user = default(self.user, "guest")
- self.password = default(self.password, "guest")
-
- def ignoreFile(self, filename):
- f = file(filename)
- for line in f.readlines(): self.ignore.append(line.strip())
- f.close()
-
- def use08spec(self):
- "True if we are running with the old 0-8 spec."
- # NB: AMQP 0-8 identifies itself as 8-0 for historical reasons.
- return self.spec.major==8 and self.spec.minor==0
-
- def _parseargs(self, args):
- # Defaults
- self.setBroker("localhost")
- self.verbose = 1
- self.ignore = []
- self.specfile = "0-8"
- self.errata = []
- self.skip_self_test = False
-
- try:
- opts, self.tests = getopt(args, "s:e:b:h?dvSi:I:F:",
- ["help", "spec", "errata=", "server",
- "verbose", "skip-self-test", "ignore",
- "ignore-file", "spec-folder"])
- except GetoptError, e:
- self._die(str(e))
- for opt, value in opts:
- if opt in ("-?", "-h", "--help"): self._die()
- if opt in ("-s", "--spec"): self.specfile = value
- if opt in ("-e", "--errata"): self.errata.append(value)
- if opt in ("-b", "--broker"): self.setBroker(value)
- if opt in ("-v", "--verbose"): self.verbose = 2
- if opt in ("-d", "--debug"): logging.basicConfig(level=logging.DEBUG)
- if opt in ("-i", "--ignore"): self.ignore.append(value)
- if opt in ("-I", "--ignore-file"): self.ignoreFile(value)
- if opt in ("-S", "--skip-self-test"): self.skip_self_test = True
- if opt in ("-F", "--spec-folder"): TestRunner.SPEC_FOLDER = value
- # Abbreviations for default settings.
- if (self.specfile == "0-10"):
- self.spec = load(self.get_spec_file("amqp.0-10.xml"))
- elif (self.specfile == "0-10-errata"):
- self.spec = load(self.get_spec_file("amqp.0-10-qpid-errata.xml"))
- else:
- if (self.specfile == "0-8"):
- self.specfile = self.get_spec_file("amqp.0-8.xml")
- elif (self.specfile == "0-9"):
- self.specfile = self.get_spec_file("amqp.0-9.xml")
- self.errata.append(self.get_spec_file("amqp-errata.0-9.xml"))
-
- if (self.specfile == None):
- self._die("No XML specification provided")
- print "Using specification from:", self.specfile
-
- self.spec = qpid.spec.load(self.specfile, *self.errata)
-
- if len(self.tests) == 0:
- if not self.skip_self_test:
- self.tests=findmodules("tests")
- if self.use08spec():
- self.tests+=findmodules("tests_0-8")
- elif (self.spec.major == 99 and self.spec.minor == 0):
- self.tests+=findmodules("tests_0-10_preview")
- elif (self.spec.major == 0 and self.spec.minor == 10):
- self.tests+=findmodules("tests_0-10")
- else:
- self.tests+=findmodules("tests_0-9")
-
- def testSuite(self):
- class IgnoringTestSuite(unittest.TestSuite):
- def addTest(self, test):
- if isinstance(test, unittest.TestCase):
- for pattern in testrunner.ignore:
- if fnmatch(test.id(), pattern):
- return
- unittest.TestSuite.addTest(self, test)
-
- # Use our IgnoringTestSuite in the test loader.
- unittest.TestLoader.suiteClass = IgnoringTestSuite
- return unittest.defaultTestLoader.loadTestsFromNames(self.tests)
-
- def run(self, args=sys.argv[1:]):
- self._parseargs(args)
- runner = unittest.TextTestRunner(descriptions=False,
- verbosity=self.verbose)
- result = runner.run(self.testSuite())
-
- if (self.ignore):
- print "======================================="
- print "NOTE: the following tests were ignored:"
- for t in self.ignore: print t
- print "======================================="
-
- return result.wasSuccessful()
-
- def connect(self, host=None, port=None, spec=None, user=None, password=None, tune_params=None):
- """Connect to the broker, returns a qpid.client.Client"""
- host = host or self.host
- port = port or self.port
- spec = spec or self.spec
- user = user or self.user
- password = password or self.password
- client = qpid.client.Client(host, port, spec)
- if self.use08spec():
- client.start({"LOGIN": user, "PASSWORD": password}, tune_params=tune_params)
- else:
- client.start("\x00" + user + "\x00" + password, mechanism="PLAIN", tune_params=tune_params)
- return client
-
- def get_spec_file(self, fname):
- return TestRunner.SPEC_FOLDER + os.sep + fname
-
-# Global instance for tests to call connect.
-testrunner = TestRunner()
-
+from qpid.harness import Skipped
+from qpid.exceptions import VersionError
class TestBase(unittest.TestCase):
"""Base class for Qpid test cases.
@@ -219,13 +41,16 @@ class TestBase(unittest.TestCase):
resources to clean up later.
"""
+ def configure(self, config):
+ self.config = config
+
def setUp(self):
self.queues = []
self.exchanges = []
self.client = self.connect()
self.channel = self.client.channel(1)
self.version = (self.client.spec.major, self.client.spec.minor)
- if self.version == (8, 0):
+ if self.version == (8, 0) or self.version == (0, 9):
self.channel.channel_open()
else:
self.channel.session_open()
@@ -245,9 +70,26 @@ class TestBase(unittest.TestCase):
else:
self.client.close()
- def connect(self, *args, **keys):
+ def connect(self, host=None, port=None, user=None, password=None, tune_params=None):
"""Create a new connction, return the Client object"""
- return testrunner.connect(*args, **keys)
+ host = host or self.config.broker.host
+ port = port or self.config.broker.port or 5672
+ user = user or "guest"
+ password = password or "guest"
+ client = qpid.client.Client(host, port)
+ try:
+ if client.spec.major == 8 and client.spec.minor == 0:
+ client.start({"LOGIN": user, "PASSWORD": password}, tune_params=tune_params)
+ else:
+ client.start("\x00" + user + "\x00" + password, mechanism="PLAIN", tune_params=tune_params)
+ except qpid.client.Closed, e:
+ if isinstance(e.args[0], VersionError):
+ raise Skipped(e.args[0])
+ else:
+ raise e
+ except socket.error, e:
+ raise Skipped(e)
+ return client
def queue_declare(self, channel=None, *args, **keys):
channel = channel or self.channel
@@ -271,24 +113,15 @@ class TestBase(unittest.TestCase):
def consume(self, queueName):
"""Consume from named queue returns the Queue object."""
- if testrunner.use08spec():
- reply = self.channel.basic_consume(queue=queueName, no_ack=True)
- return self.client.queue(reply.consumer_tag)
- else:
- if not "uniqueTag" in dir(self): self.uniqueTag = 1
- else: self.uniqueTag += 1
- consumer_tag = "tag" + str(self.uniqueTag)
- self.channel.message_subscribe(queue=queueName, destination=consumer_tag)
- self.channel.message_flow(destination=consumer_tag, unit=0, value=0xFFFFFFFF)
- self.channel.message_flow(destination=consumer_tag, unit=1, value=0xFFFFFFFF)
- return self.client.queue(consumer_tag)
+ reply = self.channel.basic_consume(queue=queueName, no_ack=True)
+ return self.client.queue(reply.consumer_tag)
def subscribe(self, channel=None, **keys):
channel = channel or self.channel
consumer_tag = keys["destination"]
channel.message_subscribe(**keys)
- channel.message_flow(destination=consumer_tag, unit=0, value=0xFFFFFFFF)
- channel.message_flow(destination=consumer_tag, unit=1, value=0xFFFFFFFF)
+ channel.message_flow(destination=consumer_tag, unit=0, value=0xFFFFFFFFL)
+ channel.message_flow(destination=consumer_tag, unit=1, value=0xFFFFFFFFL)
def assertEmpty(self, queue):
"""Assert that the queue is empty"""
@@ -302,24 +135,14 @@ class TestBase(unittest.TestCase):
Publish to exchange and assert queue.get() returns the same message.
"""
body = self.uniqueString()
- if testrunner.use08spec():
- self.channel.basic_publish(
- exchange=exchange,
- content=Content(body, properties=properties),
- routing_key=routing_key)
- else:
- self.channel.message_transfer(
- destination=exchange,
- content=Content(body, properties={'application_headers':properties,'routing_key':routing_key}))
+ self.channel.basic_publish(
+ exchange=exchange,
+ content=Content(body, properties=properties),
+ routing_key=routing_key)
msg = queue.get(timeout=1)
- if testrunner.use08spec():
- self.assertEqual(body, msg.content.body)
- if (properties):
- self.assertEqual(properties, msg.content.properties)
- else:
- self.assertEqual(body, msg.content.body)
- if (properties):
- self.assertEqual(properties, msg.content['application_headers'])
+ self.assertEqual(body, msg.content.body)
+ if (properties):
+ self.assertEqual(properties, msg.content.properties)
def assertPublishConsume(self, queue="", exchange="", routing_key="", properties=None):
"""
@@ -329,7 +152,7 @@ class TestBase(unittest.TestCase):
self.assertPublishGet(self.consume(queue), exchange, routing_key, properties)
def assertChannelException(self, expectedCode, message):
- if self.version == (8, 0): #or "transitional" in self.client.spec.file:
+ if self.version == (8, 0) or self.version == (0, 9):
if not isinstance(message, Message): self.fail("expected channel_close method, got %s" % (message))
self.assertEqual("channel", message.method.klass.name)
self.assertEqual("close", message.method.name)
@@ -346,31 +169,58 @@ class TestBase(unittest.TestCase):
self.assertEqual("close", message.method.name)
self.assertEqual(expectedCode, message.reply_code)
+#0-10 support
+from qpid.connection import Connection
+from qpid.util import connect, ssl, URL
+
class TestBase010(unittest.TestCase):
"""
Base class for Qpid test cases. using the final 0-10 spec
"""
+ def configure(self, config):
+ self.config = config
+ self.broker = config.broker
+ self.defines = self.config.defines
+
def setUp(self):
- spec = testrunner.spec
- self.conn = Connection(connect(testrunner.host, testrunner.port), spec,
- username=testrunner.user, password=testrunner.password)
- self.conn.start(timeout=10)
+ self.conn = self.connect()
self.session = self.conn.session("test-session", timeout=10)
+ self.qmf = None
+
+ def startQmf(self, handler=None):
+ self.qmf = qmf.console.Session(handler)
+ self.qmf_broker = self.qmf.addBroker(str(self.broker))
def connect(self, host=None, port=None):
- spec = testrunner.spec
- conn = Connection(connect(host or testrunner.host, port or testrunner.port), spec)
- conn.start(timeout=10)
+ url = self.broker
+ if url.scheme == URL.AMQPS:
+ default_port = 5671
+ else:
+ default_port = 5672
+ try:
+ sock = connect(host or url.host, port or url.port or default_port)
+ except socket.error, e:
+ raise Skipped(e)
+ if url.scheme == URL.AMQPS:
+ sock = ssl(sock)
+ conn = Connection(sock, username=url.user or "guest",
+ password=url.password or "guest")
+ try:
+ conn.start(timeout=10)
+ except VersionError, e:
+ raise Skipped(e)
return conn
def tearDown(self):
if not self.session.error(): self.session.close(timeout=10)
self.conn.close(timeout=10)
+ if self.qmf:
+ self.qmf.delBroker(self.qmf_broker)
def subscribe(self, session=None, **keys):
session = session or self.session
consumer_tag = keys["destination"]
session.message_subscribe(**keys)
- session.message_flow(destination=consumer_tag, unit=0, value=0xFFFFFFFF)
- session.message_flow(destination=consumer_tag, unit=1, value=0xFFFFFFFF)
+ session.message_flow(destination=consumer_tag, unit=0, value=0xFFFFFFFFL)
+ session.message_flow(destination=consumer_tag, unit=1, value=0xFFFFFFFFL)
diff --git a/python/qpid/tests/__init__.py b/python/qpid/tests/__init__.py
new file mode 100644
index 0000000000..2f0fcfdf67
--- /dev/null
+++ b/python/qpid/tests/__init__.py
@@ -0,0 +1,28 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+class Test:
+
+ def __init__(self, name):
+ self.name = name
+
+ def configure(self, config):
+ self.config = config
+
+import address, framing, mimetype, messaging
diff --git a/python/qpid/tests/address.py b/python/qpid/tests/address.py
new file mode 100644
index 0000000000..7c101eee5e
--- /dev/null
+++ b/python/qpid/tests/address.py
@@ -0,0 +1,199 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from qpid.tests import Test
+from qpid.address import lex, parse, ParseError, EOF, ID, NUMBER, SYM, WSPACE
+from parser import ParserBase
+
+class AddressTests(ParserBase, Test):
+
+ EXCLUDE = (WSPACE, EOF)
+
+ def do_lex(self, st):
+ return lex(st)
+
+ def do_parse(self, st):
+ return parse(st)
+
+ def valid(self, addr, name=None, subject=None, options=None):
+ ParserBase.valid(self, addr, (name, subject, options))
+
+ def testDashInId1(self):
+ self.lex("foo-bar", ID)
+
+ def testDashInId2(self):
+ self.lex("foo-3", ID)
+
+ def testDashAlone1(self):
+ self.lex("foo - bar", ID, SYM, ID)
+
+ def testDashAlone2(self):
+ self.lex("foo - 3", ID, SYM, NUMBER)
+
+ def testLeadingDash(self):
+ self.lex("-foo", SYM, ID)
+
+ def testTrailingDash(self):
+ self.lex("foo-", ID, SYM)
+
+ def testNegativeNum(self):
+ self.lex("-3", NUMBER)
+
+ def testHash(self):
+ self.valid("foo/bar.#", "foo", "bar.#")
+
+ def testStar(self):
+ self.valid("foo/bar.*", "foo", "bar.*")
+
+ def testColon(self):
+ self.valid("foo.bar/baz.qux:moo:arf", "foo.bar", "baz.qux:moo:arf")
+
+ def testOptions(self):
+ self.valid("foo.bar/baz.qux:moo:arf; {key: value}",
+ "foo.bar", "baz.qux:moo:arf", {"key": "value"})
+
+ def testOptionsTrailingComma(self):
+ self.valid("name/subject; {key: value,}", "name", "subject",
+ {"key": "value"})
+
+ def testSemiSubject(self):
+ self.valid("foo.bar/'baz.qux;moo:arf'; {key: value}",
+ "foo.bar", "baz.qux;moo:arf", {"key": "value"})
+
+ def testCommaSubject(self):
+ self.valid("foo.bar/baz.qux.{moo,arf}", "foo.bar", "baz.qux.{moo,arf}")
+
+ def testCommaSubjectOptions(self):
+ self.valid("foo.bar/baz.qux.{moo,arf}; {key: value}", "foo.bar",
+ "baz.qux.{moo,arf}", {"key": "value"})
+
+ def testUnbalanced(self):
+ self.valid("foo.bar/baz.qux.{moo,arf; {key: value}", "foo.bar",
+ "baz.qux.{moo,arf", {"key": "value"})
+
+ def testSlashQuote(self):
+ self.valid("foo.bar\\/baz.qux.{moo,arf; {key: value}",
+ "foo.bar/baz.qux.{moo,arf",
+ None, {"key": "value"})
+
+ def testSlashHexEsc1(self):
+ self.valid("foo.bar\\x00baz.qux.{moo,arf; {key: value}",
+ "foo.bar\x00baz.qux.{moo,arf",
+ None, {"key": "value"})
+
+ def testSlashHexEsc2(self):
+ self.valid("foo.bar\\xffbaz.qux.{moo,arf; {key: value}",
+ "foo.bar\xffbaz.qux.{moo,arf",
+ None, {"key": "value"})
+
+ def testSlashHexEsc3(self):
+ self.valid("foo.bar\\xFFbaz.qux.{moo,arf; {key: value}",
+ "foo.bar\xFFbaz.qux.{moo,arf",
+ None, {"key": "value"})
+
+ def testSlashUnicode1(self):
+ self.valid("foo.bar\\u1234baz.qux.{moo,arf; {key: value}",
+ u"foo.bar\u1234baz.qux.{moo,arf", None, {"key": "value"})
+
+ def testSlashUnicode2(self):
+ self.valid("foo.bar\\u0000baz.qux.{moo,arf; {key: value}",
+ u"foo.bar\u0000baz.qux.{moo,arf", None, {"key": "value"})
+
+ def testSlashUnicode3(self):
+ self.valid("foo.bar\\uffffbaz.qux.{moo,arf; {key: value}",
+ u"foo.bar\uffffbaz.qux.{moo,arf", None, {"key": "value"})
+
+ def testSlashUnicode4(self):
+ self.valid("foo.bar\\uFFFFbaz.qux.{moo,arf; {key: value}",
+ u"foo.bar\uFFFFbaz.qux.{moo,arf", None, {"key": "value"})
+
+ def testNoName(self):
+ self.invalid("; {key: value}",
+ "unexpected token SEMI(';') line:1,0:; {key: value}")
+
+ def testEmpty(self):
+ self.invalid("", "unexpected token EOF line:1,0:")
+
+ def testNoNameSlash(self):
+ self.invalid("/asdf; {key: value}",
+ "unexpected token SLASH('/') line:1,0:/asdf; {key: value}")
+
+ def testBadOptions1(self):
+ self.invalid("name/subject; {",
+ "expecting (ID, RBRACE), got EOF line:1,15:name/subject; {")
+
+ def testBadOptions2(self):
+ self.invalid("name/subject; { 3",
+ "expecting (ID, RBRACE), got NUMBER('3') "
+ "line:1,16:name/subject; { 3")
+
+ def testBadOptions3(self):
+ self.invalid("name/subject; { key:",
+ "expecting (NUMBER, STRING, ID, LBRACE, LBRACK), got EOF "
+ "line:1,20:name/subject; { key:")
+
+ def testBadOptions4(self):
+ self.invalid("name/subject; { key: value",
+ "expecting (COMMA, RBRACE), got EOF "
+ "line:1,26:name/subject; { key: value")
+
+ def testBadOptions5(self):
+ self.invalid("name/subject; { key: value asdf",
+ "expecting (COMMA, RBRACE), got ID('asdf') "
+ "line:1,27:name/subject; { key: value asdf")
+
+ def testBadOptions6(self):
+ self.invalid("name/subject; { key: value,",
+ "expecting (ID, RBRACE), got EOF "
+ "line:1,27:name/subject; { key: value,")
+
+ def testBadOptions7(self):
+ self.invalid("name/subject; { key: value } asdf",
+ "expecting EOF, got ID('asdf') "
+ "line:1,29:name/subject; { key: value } asdf")
+
+ def testList1(self):
+ self.valid("name/subject; { key: [] }", "name", "subject", {"key": []})
+
+ def testList2(self):
+ self.valid("name/subject; { key: ['one'] }", "name", "subject", {"key": ['one']})
+
+ def testList3(self):
+ self.valid("name/subject; { key: [1, 2, 3] }", "name", "subject",
+ {"key": [1, 2, 3]})
+
+ def testList4(self):
+ self.valid("name/subject; { key: [1, [2, 3], 4] }", "name", "subject",
+ {"key": [1, [2, 3], 4]})
+
+ def testBadList1(self):
+ self.invalid("name/subject; { key: [ }", "expecting (NUMBER, STRING, ID, LBRACE, LBRACK), "
+ "got RBRACE('}') line:1,23:name/subject; { key: [ }")
+
+ def testBadList2(self):
+ self.invalid("name/subject; { key: [ 1 }", "expecting (COMMA, RBRACK), "
+ "got RBRACE('}') line:1,25:name/subject; { key: [ 1 }")
+
+ def testBadList3(self):
+ self.invalid("name/subject; { key: [ 1 2 }", "expecting (COMMA, RBRACK), "
+ "got NUMBER('2') line:1,25:name/subject; { key: [ 1 2 }")
+
+ def testBadList4(self):
+ self.invalid("name/subject; { key: [ 1 2 ] }", "expecting (COMMA, RBRACK), "
+ "got NUMBER('2') line:1,25:name/subject; { key: [ 1 2 ] }")
diff --git a/python/qpid/tests/framing.py b/python/qpid/tests/framing.py
new file mode 100644
index 0000000000..0b33df8b9a
--- /dev/null
+++ b/python/qpid/tests/framing.py
@@ -0,0 +1,289 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# setup, usage, teardown, errors(sync), errors(async), stress, soak,
+# boundary-conditions, config
+
+from qpid.tests import Test
+from qpid.framing import *
+
+class Base(Test):
+
+ def cmp_frames(self, frm1, frm2):
+ assert frm1.flags == frm2.flags, "expected: %r, got %r" % (frm1, frm2)
+ assert frm1.type == frm2.type, "expected: %r, got %r" % (frm1, frm2)
+ assert frm1.track == frm2.track, "expected: %r, got %r" % (frm1, frm2)
+ assert frm1.channel == frm2.channel, "expected: %r, got %r" % (frm1, frm2)
+ assert frm1.payload == frm2.payload, "expected: %r, got %r" % (frm1, frm2)
+
+ def cmp_segments(self, seg1, seg2):
+ assert seg1.first == seg2.first, "expected: %r, got %r" % (seg1, seg2)
+ assert seg1.last == seg2.last, "expected: %r, got %r" % (seg1, seg2)
+ assert seg1.type == seg2.type, "expected: %r, got %r" % (seg1, seg2)
+ assert seg1.track == seg2.track, "expected: %r, got %r" % (seg1, seg2)
+ assert seg1.channel == seg2.channel, "expected: %r, got %r" % (seg1, seg2)
+ assert seg1.payload == seg2.payload, "expected: %r, got %r" % (seg1, seg2)
+
+ def cmp_list(self, l1, l2):
+ if l1 is None:
+ assert l2 is None
+ return
+
+ assert len(l1) == len(l2)
+ for v1, v2 in zip(l1, l2):
+ if isinstance(v1, Compound):
+ self.cmp_ops(v1, v2)
+ else:
+ assert v1 == v2
+
+ def cmp_ops(self, op1, op2):
+ if op1 is None:
+ assert op2 is None
+ return
+
+ assert op1.__class__ == op2.__class__
+ cls = op1.__class__
+ assert op1.NAME == op2.NAME
+ assert op1.CODE == op2.CODE
+ assert op1.FIELDS == op2.FIELDS
+ for f in cls.FIELDS:
+ v1 = getattr(op1, f.name)
+ v2 = getattr(op2, f.name)
+ if COMPOUND.has_key(f.type) or f.type == "struct32":
+ self.cmp_ops(v1, v2)
+ elif f.type in ("list", "array"):
+ self.cmp_list(v1, v2)
+ else:
+ assert v1 == v2, "expected: %r, got %r" % (v1, v2)
+
+ if issubclass(cls, Command) or issubclass(cls, Control):
+ assert op1.channel == op2.channel
+
+ if issubclass(cls, Command):
+ assert op1.sync == op2.sync, "expected: %r, got %r" % (op1.sync, op2.sync)
+ assert (op1.headers is None and op2.headers is None) or \
+ (op1.headers is not None and op2.headers is not None)
+ if op1.headers is not None:
+ assert len(op1.headers) == len(op2.headers)
+ for h1, h2 in zip(op1.headers, op2.headers):
+ self.cmp_ops(h1, h2)
+
+class FrameTest(Base):
+
+ def enc_dec(self, frames, encoded=None):
+ enc = FrameEncoder()
+ dec = FrameDecoder()
+
+ enc.write(*frames)
+ bytes = enc.read()
+ if encoded is not None:
+ assert bytes == encoded, "expected %r, got %r" % (encoded, bytes)
+ dec.write(bytes)
+ dframes = dec.read()
+
+ assert len(frames) == len(dframes)
+ for f, df, in zip(frames, dframes):
+ self.cmp_frames(f, df)
+
+ def testEmpty(self):
+ self.enc_dec([Frame(0, 0, 0, 0, "")],
+ "\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00")
+
+ def testSingle(self):
+ self.enc_dec([Frame(0, 0, 0, 1, "payload")],
+ "\x00\x00\x00\x13\x00\x00\x00\x01\x00\x00\x00\x00payload")
+
+ def testMaxChannel(self):
+ self.enc_dec([Frame(0, 0, 0, 65535, "max-channel")],
+ "\x00\x00\x00\x17\x00\x00\xff\xff\x00\x00\x00\x00max-channel")
+
+ def testMaxType(self):
+ self.enc_dec([Frame(0, 255, 0, 0, "max-type")],
+ "\x00\xff\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00max-type")
+
+ def testMaxTrack(self):
+ self.enc_dec([Frame(0, 0, 15, 0, "max-track")],
+ "\x00\x00\x00\x15\x00\x0f\x00\x00\x00\x00\x00\x00max-track")
+
+ def testSequence(self):
+ self.enc_dec([Frame(0, 0, 0, 0, "zero"),
+ Frame(0, 0, 0, 1, "one"),
+ Frame(0, 0, 1, 0, "two"),
+ Frame(0, 0, 1, 1, "three"),
+ Frame(0, 1, 0, 0, "four"),
+ Frame(0, 1, 0, 1, "five"),
+ Frame(0, 1, 1, 0, "six"),
+ Frame(0, 1, 1, 1, "seven"),
+ Frame(1, 0, 0, 0, "eight"),
+ Frame(1, 0, 0, 1, "nine"),
+ Frame(1, 0, 1, 0, "ten"),
+ Frame(1, 0, 1, 1, "eleven"),
+ Frame(1, 1, 0, 0, "twelve"),
+ Frame(1, 1, 0, 1, "thirteen"),
+ Frame(1, 1, 1, 0, "fourteen"),
+ Frame(1, 1, 1, 1, "fifteen")])
+
+class SegmentTest(Base):
+
+ def enc_dec(self, segments, frames=None, interleave=None, max_payload=Frame.MAX_PAYLOAD):
+ enc = SegmentEncoder(max_payload)
+ dec = SegmentDecoder()
+
+ enc.write(*segments)
+ frms = enc.read()
+ if frames is not None:
+ assert len(frames) == len(frms), "expected %s, got %s" % (frames, frms)
+ for f1, f2 in zip(frames, frms):
+ self.cmp_frames(f1, f2)
+ if interleave is not None:
+ ilvd = []
+ for f in frms:
+ ilvd.append(f)
+ if interleave:
+ ilvd.append(interleave.pop(0))
+ ilvd.extend(interleave)
+ dec.write(*ilvd)
+ else:
+ dec.write(*frms)
+ segs = dec.read()
+ assert len(segments) == len(segs)
+ for s1, s2 in zip(segments, segs):
+ self.cmp_segments(s1, s2)
+
+ def testEmpty(self):
+ self.enc_dec([Segment(True, True, 0, 0, 0, "")],
+ [Frame(FIRST_FRM | LAST_FRM | FIRST_SEG | LAST_SEG, 0, 0, 0,
+ "")])
+
+ def testSingle(self):
+ self.enc_dec([Segment(True, True, 0, 0, 0, "payload")],
+ [Frame(FIRST_FRM | LAST_FRM | FIRST_SEG | LAST_SEG, 0, 0, 0,
+ "payload")])
+
+ def testMaxChannel(self):
+ self.enc_dec([Segment(False, False, 0, 0, 65535, "max-channel")],
+ [Frame(FIRST_FRM | LAST_FRM, 0, 0, 65535, "max-channel")])
+
+ def testMaxType(self):
+ self.enc_dec([Segment(False, False, 255, 0, 0, "max-type")],
+ [Frame(FIRST_FRM | LAST_FRM, 255, 0, 0, "max-type")])
+
+ def testMaxTrack(self):
+ self.enc_dec([Segment(False, False, 0, 15, 0, "max-track")],
+ [Frame(FIRST_FRM | LAST_FRM, 0, 15, 0, "max-track")])
+
+ def testSequence(self):
+ self.enc_dec([Segment(True, False, 0, 0, 0, "one"),
+ Segment(False, False, 0, 0, 0, "two"),
+ Segment(False, True, 0, 0, 0, "three")],
+ [Frame(FIRST_FRM | LAST_FRM | FIRST_SEG, 0, 0, 0, "one"),
+ Frame(FIRST_FRM | LAST_FRM, 0, 0, 0, "two"),
+ Frame(FIRST_FRM | LAST_FRM | LAST_SEG, 0, 0, 0, "three")])
+
+ def testInterleaveChannel(self):
+ frames = [Frame(0, 0, 0, 0, chr(ord("a") + i)) for i in range(7)]
+ frames[0].flags |= FIRST_FRM
+ frames[-1].flags |= LAST_FRM
+
+ ilvd = [Frame(0, 0, 0, 1, chr(ord("a") + i)) for i in range(7)]
+
+ self.enc_dec([Segment(False, False, 0, 0, 0, "abcdefg")], frames, ilvd, max_payload=1)
+
+ def testInterleaveTrack(self):
+ frames = [Frame(0, 0, 0, 0, "%c%c" % (ord("a") + i, ord("a") + i + 1))
+ for i in range(0, 8, 2)]
+ frames[0].flags |= FIRST_FRM
+ frames[-1].flags |= LAST_FRM
+
+ ilvd = [Frame(0, 0, 1, 0, "%c%c" % (ord("a") + i, ord("a") + i + 1))
+ for i in range(0, 8, 2)]
+
+ self.enc_dec([Segment(False, False, 0, 0, 0, "abcdefgh")], frames, ilvd, max_payload=2)
+
+from qpid.ops import *
+
+class OpTest(Base):
+
+ def enc_dec(self, ops):
+ enc = OpEncoder()
+ dec = OpDecoder()
+ enc.write(*ops)
+ segs = enc.read()
+ dec.write(*segs)
+ dops = dec.read()
+ assert len(ops) == len(dops)
+ for op1, op2 in zip(ops, dops):
+ self.cmp_ops(op1, op2)
+
+ def testEmtpyMT(self):
+ self.enc_dec([MessageTransfer()])
+
+ def testEmptyMTSync(self):
+ self.enc_dec([MessageTransfer(sync=True)])
+
+ def testMT(self):
+ self.enc_dec([MessageTransfer(destination="asdf")])
+
+ def testSyncMT(self):
+ self.enc_dec([MessageTransfer(destination="asdf", sync=True)])
+
+ def testEmptyPayloadMT(self):
+ self.enc_dec([MessageTransfer(payload="")])
+
+ def testPayloadMT(self):
+ self.enc_dec([MessageTransfer(payload="test payload")])
+
+ def testHeadersEmptyPayloadMT(self):
+ self.enc_dec([MessageTransfer(headers=[DeliveryProperties()])])
+
+ def testHeadersPayloadMT(self):
+ self.enc_dec([MessageTransfer(headers=[DeliveryProperties()], payload="test payload")])
+
+ def testMultiHeadersEmptyPayloadMT(self):
+ self.enc_dec([MessageTransfer(headers=[DeliveryProperties(), MessageProperties()])])
+
+ def testMultiHeadersPayloadMT(self):
+ self.enc_dec([MessageTransfer(headers=[MessageProperties(), DeliveryProperties()], payload="test payload")])
+
+ def testContentTypeHeadersPayloadMT(self):
+ self.enc_dec([MessageTransfer(headers=[MessageProperties(content_type="text/plain")], payload="test payload")])
+
+ def testMulti(self):
+ self.enc_dec([MessageTransfer(),
+ MessageTransfer(sync=True),
+ MessageTransfer(destination="one"),
+ MessageTransfer(destination="two", sync=True),
+ MessageTransfer(destination="three", payload="test payload")])
+
+ def testControl(self):
+ self.enc_dec([SessionAttach(name="asdf")])
+
+ def testMixed(self):
+ self.enc_dec([SessionAttach(name="fdsa"), MessageTransfer(destination="test")])
+
+ def testChannel(self):
+ self.enc_dec([SessionAttach(name="asdf", channel=3), MessageTransfer(destination="test", channel=1)])
+
+ def testCompound(self):
+ self.enc_dec([MessageTransfer(headers=[MessageProperties(reply_to=ReplyTo(exchange="exch", routing_key="rk"))])])
+
+ def testListCompound(self):
+ self.enc_dec([ExecutionResult(value=RecoverResult(in_doubt=[Xid(global_id="one"),
+ Xid(global_id="two"),
+ Xid(global_id="three")]))])
diff --git a/python/qpid/tests/messaging.py b/python/qpid/tests/messaging.py
new file mode 100644
index 0000000000..f2a270192e
--- /dev/null
+++ b/python/qpid/tests/messaging.py
@@ -0,0 +1,929 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# setup, usage, teardown, errors(sync), errors(async), stress, soak,
+# boundary-conditions, config
+
+import time
+from qpid import compat
+from qpid.tests import Test
+from qpid.harness import Skipped
+from qpid.messaging import Connection, ConnectError, Disconnected, Empty, \
+ InsufficientCapacity, Message, ReceiveError, SendError, SessionError, \
+ UNLIMITED, uuid4
+from Queue import Queue, Empty as QueueEmpty
+
+class Base(Test):
+
+ def setup_connection(self):
+ return None
+
+ def setup_session(self):
+ return None
+
+ def setup_sender(self):
+ return None
+
+ def setup_receiver(self):
+ return None
+
+ def setup(self):
+ self.test_id = uuid4()
+ self.broker = self.config.broker
+ try:
+ self.conn = self.setup_connection()
+ except ConnectError, e:
+ raise Skipped(e)
+ self.ssn = self.setup_session()
+ self.snd = self.setup_sender()
+ if self.snd is not None:
+ self.snd.durable = self.durable()
+ self.rcv = self.setup_receiver()
+
+ def teardown(self):
+ if self.conn is not None and self.conn.connected():
+ self.conn.close()
+
+ def content(self, base, count = None):
+ if count is None:
+ return "%s[%s]" % (base, self.test_id)
+ else:
+ return "%s[%s, %s]" % (base, count, self.test_id)
+
+ def ping(self, ssn):
+ PING_Q = 'ping-queue; {create: always, delete: always}'
+ # send a message
+ sender = ssn.sender(PING_Q, durable=self.durable())
+ content = self.content("ping")
+ sender.send(content)
+ receiver = ssn.receiver(PING_Q)
+ msg = receiver.fetch(0)
+ ssn.acknowledge()
+ assert msg.content == content, "expected %r, got %r" % (content, msg.content)
+
+ def drain(self, rcv, limit=None, timeout=0, expected=None):
+ contents = []
+ try:
+ while limit is None or len(contents) < limit:
+ contents.append(rcv.fetch(timeout=timeout).content)
+ except Empty:
+ pass
+ if expected is not None:
+ assert expected == contents, "expected %s, got %s" % (expected, contents)
+ return contents
+
+ def assertEmpty(self, rcv):
+ contents = self.drain(rcv)
+ assert len(contents) == 0, "%s is supposed to be empty: %s" % (rcv, contents)
+
+ def assertPending(self, rcv, expected):
+ p = rcv.pending()
+ assert p == expected, "expected %s, got %s" % (expected, p)
+
+ def sleep(self):
+ time.sleep(self.delay())
+
+ def delay(self):
+ return float(self.config.defines.get("delay", "2"))
+
+ def get_bool(self, name):
+ return self.config.defines.get(name, "false").lower() in ("true", "yes", "1")
+
+ def durable(self):
+ return self.get_bool("durable")
+
+ def reconnect(self):
+ return self.get_bool("reconnect")
+
+class SetupTests(Base):
+
+ def testOpen(self):
+ # XXX: need to flesh out URL support/syntax
+ self.conn = Connection.open(self.broker.host, self.broker.port,
+ reconnect=self.reconnect())
+ self.ping(self.conn.session())
+
+ def testConnect(self):
+ # XXX: need to flesh out URL support/syntax
+ self.conn = Connection(self.broker.host, self.broker.port,
+ reconnect=self.reconnect())
+ self.conn.connect()
+ self.ping(self.conn.session())
+
+ def testConnectError(self):
+ try:
+ self.conn = Connection.open("localhost", 0)
+ assert False, "connect succeeded"
+ except ConnectError, e:
+ # XXX: should verify that e includes appropriate diagnostic info
+ pass
+
+class ConnectionTests(Base):
+
+ def setup_connection(self):
+ return Connection.open(self.broker.host, self.broker.port,
+ reconnect=self.reconnect())
+
+ def testSessionAnon(self):
+ ssn1 = self.conn.session()
+ ssn2 = self.conn.session()
+ self.ping(ssn1)
+ self.ping(ssn2)
+ assert ssn1 is not ssn2
+
+ def testSessionNamed(self):
+ ssn1 = self.conn.session("one")
+ ssn2 = self.conn.session("two")
+ self.ping(ssn1)
+ self.ping(ssn2)
+ assert ssn1 is not ssn2
+ assert ssn1 is self.conn.session("one")
+ assert ssn2 is self.conn.session("two")
+
+ def testDisconnect(self):
+ ssn = self.conn.session()
+ self.ping(ssn)
+ self.conn.disconnect()
+ try:
+ self.ping(ssn)
+ assert False, "ping succeeded"
+ except Disconnected:
+ # this is the expected failure when pinging on a disconnected
+ # connection
+ pass
+ self.conn.connect()
+ self.ping(ssn)
+
+ def testClose(self):
+ self.conn.close()
+ assert not self.conn.connected()
+
+ACK_QC = 'test-ack-queue; {create: always}'
+ACK_QD = 'test-ack-queue; {delete: always}'
+
+class SessionTests(Base):
+
+ def setup_connection(self):
+ return Connection.open(self.broker.host, self.broker.port,
+ reconnect=self.reconnect())
+
+ def setup_session(self):
+ return self.conn.session()
+
+ def testSender(self):
+ snd = self.ssn.sender('test-snd-queue; {create: sender, delete: receiver}',
+ durable=self.durable())
+ snd2 = self.ssn.sender(snd.target, durable=self.durable())
+ assert snd is not snd2
+ snd2.close()
+
+ content = self.content("testSender")
+ snd.send(content)
+ rcv = self.ssn.receiver(snd.target)
+ msg = rcv.fetch(0)
+ assert msg.content == content
+ self.ssn.acknowledge(msg)
+
+ def testReceiver(self):
+ rcv = self.ssn.receiver('test-rcv-queue; {create: always}')
+ rcv2 = self.ssn.receiver(rcv.source)
+ assert rcv is not rcv2
+ rcv2.close()
+
+ content = self.content("testReceiver")
+ snd = self.ssn.sender(rcv.source, durable=self.durable())
+ snd.send(content)
+ msg = rcv.fetch(0)
+ assert msg.content == content
+ self.ssn.acknowledge(msg)
+ snd2 = self.ssn.receiver('test-rcv-queue; {delete: always}')
+
+ def testNextReceiver(self):
+ ADDR = 'test-next-rcv-queue; {create: always, delete: always}'
+ rcv1 = self.ssn.receiver(ADDR, capacity=UNLIMITED)
+ rcv2 = self.ssn.receiver(ADDR, capacity=UNLIMITED)
+ rcv3 = self.ssn.receiver(ADDR, capacity=UNLIMITED)
+
+ snd = self.ssn.sender(ADDR)
+
+ msgs = []
+ for i in range(10):
+ content = self.content("testNextReceiver", i)
+ snd.send(content)
+ msgs.append(content)
+
+ fetched = []
+ try:
+ while True:
+ rcv = self.ssn.next_receiver(timeout=self.delay())
+ assert rcv in (rcv1, rcv2, rcv3)
+ assert rcv.pending() > 0
+ fetched.append(rcv.fetch().content)
+ except Empty:
+ pass
+ assert msgs == fetched, "expecting %s, got %s" % (msgs, fetched)
+ self.ssn.acknowledge()
+
+ # XXX, we need a convenient way to assert that required queues are
+ # empty on setup, and possibly also to drain queues on teardown
+ def ackTest(self, acker, ack_capacity=None):
+ # send a bunch of messages
+ snd = self.ssn.sender(ACK_QC, durable=self.durable())
+ contents = [self.content("ackTest", i) for i in range(15)]
+ for c in contents:
+ snd.send(c)
+
+ # drain the queue, verify the messages are there and then close
+ # without acking
+ rcv = self.ssn.receiver(ACK_QC)
+ self.drain(rcv, expected=contents)
+ self.ssn.close()
+
+ # drain the queue again, verify that they are all the messages
+ # were requeued, and ack this time before closing
+ self.ssn = self.conn.session()
+ if ack_capacity is not None:
+ self.ssn.ack_capacity = ack_capacity
+ rcv = self.ssn.receiver(ACK_QC)
+ self.drain(rcv, expected=contents)
+ acker(self.ssn)
+ self.ssn.close()
+
+ # drain the queue a final time and verify that the messages were
+ # dequeued
+ self.ssn = self.conn.session()
+ rcv = self.ssn.receiver(ACK_QD)
+ self.assertEmpty(rcv)
+
+ def testAcknowledge(self):
+ self.ackTest(lambda ssn: ssn.acknowledge())
+
+ def testAcknowledgeAsync(self):
+ self.ackTest(lambda ssn: ssn.acknowledge(sync=False))
+
+ def testAcknowledgeAsyncAckCap0(self):
+ try:
+ try:
+ self.ackTest(lambda ssn: ssn.acknowledge(sync=False), 0)
+ assert False, "acknowledge shouldn't succeed with ack_capacity of zero"
+ except InsufficientCapacity:
+ pass
+ finally:
+ self.ssn.ack_capacity = UNLIMITED
+ self.drain(self.ssn.receiver(ACK_QD))
+ self.ssn.acknowledge()
+
+ def testAcknowledgeAsyncAckCap1(self):
+ self.ackTest(lambda ssn: ssn.acknowledge(sync=False), 1)
+
+ def testAcknowledgeAsyncAckCap5(self):
+ self.ackTest(lambda ssn: ssn.acknowledge(sync=False), 5)
+
+ def testAcknowledgeAsyncAckCapUNLIMITED(self):
+ self.ackTest(lambda ssn: ssn.acknowledge(sync=False), UNLIMITED)
+
+ def send(self, ssn, queue, base, count=1):
+ snd = ssn.sender(queue, durable=self.durable())
+ contents = []
+ for i in range(count):
+ c = self.content(base, i)
+ snd.send(c)
+ contents.append(c)
+ snd.close()
+ return contents
+
+ def txTest(self, commit):
+ TX_Q = 'test-tx-queue; {create: sender, delete: receiver}'
+ TX_Q_COPY = 'test-tx-queue-copy; {create: always, delete: always}'
+ txssn = self.conn.session(transactional=True)
+ contents = self.send(self.ssn, TX_Q, "txTest", 3)
+ txrcv = txssn.receiver(TX_Q)
+ txsnd = txssn.sender(TX_Q_COPY, durable=self.durable())
+ rcv = self.ssn.receiver(txrcv.source)
+ copy_rcv = self.ssn.receiver(txsnd.target)
+ self.assertEmpty(copy_rcv)
+ for i in range(3):
+ m = txrcv.fetch(0)
+ txsnd.send(m)
+ self.assertEmpty(copy_rcv)
+ txssn.acknowledge()
+ if commit:
+ txssn.commit()
+ self.assertEmpty(rcv)
+ assert contents == self.drain(copy_rcv)
+ else:
+ txssn.rollback()
+ assert contents == self.drain(rcv)
+ self.assertEmpty(copy_rcv)
+ self.ssn.acknowledge()
+
+ def testCommit(self):
+ self.txTest(True)
+
+ def testRollback(self):
+ self.txTest(False)
+
+ def txTestSend(self, commit):
+ TX_SEND_Q = 'test-tx-send-queue; {create: sender, delete: receiver}'
+ txssn = self.conn.session(transactional=True)
+ contents = self.send(txssn, TX_SEND_Q, "txTestSend", 3)
+ rcv = self.ssn.receiver(TX_SEND_Q)
+ self.assertEmpty(rcv)
+
+ if commit:
+ txssn.commit()
+ assert contents == self.drain(rcv)
+ self.ssn.acknowledge()
+ else:
+ txssn.rollback()
+ self.assertEmpty(rcv)
+ txssn.commit()
+ self.assertEmpty(rcv)
+
+ def testCommitSend(self):
+ self.txTestSend(True)
+
+ def testRollbackSend(self):
+ self.txTestSend(False)
+
+ def txTestAck(self, commit):
+ TX_ACK_QC = 'test-tx-ack-queue; {create: always}'
+ TX_ACK_QD = 'test-tx-ack-queue; {delete: always}'
+ txssn = self.conn.session(transactional=True)
+ txrcv = txssn.receiver(TX_ACK_QC)
+ self.assertEmpty(txrcv)
+ contents = self.send(self.ssn, TX_ACK_QC, "txTestAck", 3)
+ assert contents == self.drain(txrcv)
+
+ if commit:
+ txssn.acknowledge()
+ else:
+ txssn.rollback()
+ drained = self.drain(txrcv)
+ assert contents == drained, "expected %s, got %s" % (contents, drained)
+ txssn.acknowledge()
+ txssn.rollback()
+ assert contents == self.drain(txrcv)
+ txssn.commit() # commit without ack
+ self.assertEmpty(txrcv)
+
+ txssn.close()
+
+ txssn = self.conn.session(transactional=True)
+ txrcv = txssn.receiver(TX_ACK_QC)
+ assert contents == self.drain(txrcv)
+ txssn.acknowledge()
+ txssn.commit()
+ rcv = self.ssn.receiver(TX_ACK_QD)
+ self.assertEmpty(rcv)
+ txssn.close()
+ self.assertEmpty(rcv)
+
+ def testCommitAck(self):
+ self.txTestAck(True)
+
+ def testRollbackAck(self):
+ self.txTestAck(False)
+
+ def testClose(self):
+ self.ssn.close()
+ try:
+ self.ping(self.ssn)
+ assert False, "ping succeeded"
+ except Disconnected:
+ pass
+
+RECEIVER_Q = 'test-receiver-queue; {create: always, delete: always}'
+
+class ReceiverTests(Base):
+
+ def setup_connection(self):
+ return Connection.open(self.broker.host, self.broker.port,
+ reconnect=self.reconnect())
+
+ def setup_session(self):
+ return self.conn.session()
+
+ def setup_sender(self):
+ return self.ssn.sender(RECEIVER_Q)
+
+ def setup_receiver(self):
+ return self.ssn.receiver(RECEIVER_Q)
+
+ def send(self, base, count = None):
+ content = self.content(base, count)
+ self.snd.send(content)
+ return content
+
+ def testFetch(self):
+ try:
+ msg = self.rcv.fetch(0)
+ assert False, "unexpected message: %s" % msg
+ except Empty:
+ pass
+ try:
+ start = time.time()
+ msg = self.rcv.fetch(self.delay())
+ assert False, "unexpected message: %s" % msg
+ except Empty:
+ elapsed = time.time() - start
+ assert elapsed >= self.delay()
+
+ one = self.send("testFetch", 1)
+ two = self.send("testFetch", 2)
+ three = self.send("testFetch", 3)
+ msg = self.rcv.fetch(0)
+ assert msg.content == one
+ msg = self.rcv.fetch(self.delay())
+ assert msg.content == two
+ msg = self.rcv.fetch()
+ assert msg.content == three
+ self.ssn.acknowledge()
+
+ def testCapacityIncrease(self):
+ content = self.send("testCapacityIncrease")
+ self.sleep()
+ assert self.rcv.pending() == 0
+ self.rcv.capacity = UNLIMITED
+ self.sleep()
+ assert self.rcv.pending() == 1
+ msg = self.rcv.fetch(0)
+ assert msg.content == content
+ assert self.rcv.pending() == 0
+ self.ssn.acknowledge()
+
+ def testCapacityDecrease(self):
+ self.rcv.capacity = UNLIMITED
+ one = self.send("testCapacityDecrease", 1)
+ self.sleep()
+ assert self.rcv.pending() == 1
+ msg = self.rcv.fetch(0)
+ assert msg.content == one
+
+ self.rcv.capacity = 0
+
+ two = self.send("testCapacityDecrease", 2)
+ self.sleep()
+ assert self.rcv.pending() == 0
+ msg = self.rcv.fetch(0)
+ assert msg.content == two
+
+ self.ssn.acknowledge()
+
+ def testCapacity(self):
+ self.rcv.capacity = 5
+ self.assertPending(self.rcv, 0)
+
+ for i in range(15):
+ self.send("testCapacity", i)
+ self.sleep()
+ self.assertPending(self.rcv, 5)
+
+ self.drain(self.rcv, limit = 5)
+ self.sleep()
+ self.assertPending(self.rcv, 5)
+
+ drained = self.drain(self.rcv)
+ assert len(drained) == 10, "%s, %s" % (len(drained), drained)
+ self.assertPending(self.rcv, 0)
+
+ self.ssn.acknowledge()
+
+ def testCapacityUNLIMITED(self):
+ self.rcv.capacity = UNLIMITED
+ self.assertPending(self.rcv, 0)
+
+ for i in range(10):
+ self.send("testCapacityUNLIMITED", i)
+ self.sleep()
+ self.assertPending(self.rcv, 10)
+
+ self.drain(self.rcv)
+ self.assertPending(self.rcv, 0)
+
+ self.ssn.acknowledge()
+
+ def testPending(self):
+ self.rcv.capacity = UNLIMITED
+ assert self.rcv.pending() == 0
+
+ for i in range(3):
+ self.send("testPending", i)
+ self.sleep()
+ assert self.rcv.pending() == 3
+
+ for i in range(3, 10):
+ self.send("testPending", i)
+ self.sleep()
+ assert self.rcv.pending() == 10
+
+ self.drain(self.rcv, limit=3)
+ assert self.rcv.pending() == 7
+
+ self.drain(self.rcv)
+ assert self.rcv.pending() == 0
+
+ self.ssn.acknowledge()
+
+ # XXX: need testClose
+
+class AddressTests(Base):
+
+ def setup_connection(self):
+ return Connection.open(self.broker.host, self.broker.port,
+ reconnect=self.reconnect())
+
+ def setup_session(self):
+ return self.conn.session()
+
+ def testBadOption(self):
+ snd = self.ssn.sender("test-bad-option; {create: always, node-properties: {this-property-does-not-exist: 3}}")
+ try:
+ snd.send("ping")
+ except SendError, e:
+ assert "unrecognized option" in str(e)
+
+ def testCreateQueue(self):
+ snd = self.ssn.sender("test-create-queue; {create: always, delete: always, "
+ "node-properties: {type: queue, durable: False, "
+ "x-properties: {auto_delete: true}}}")
+ content = self.content("testCreateQueue")
+ snd.send(content)
+ rcv = self.ssn.receiver("test-create-queue")
+ self.drain(rcv, expected=[content])
+
+ def createExchangeTest(self, props=""):
+ addr = """test-create-exchange; {
+ create: always,
+ delete: always,
+ node-properties: {
+ type: topic,
+ durable: False,
+ x-properties: {auto_delete: true, %s}
+ }
+ }""" % props
+ snd = self.ssn.sender(addr)
+ snd.send("ping")
+ rcv1 = self.ssn.receiver("test-create-exchange/first")
+ rcv2 = self.ssn.receiver("test-create-exchange/first")
+ rcv3 = self.ssn.receiver("test-create-exchange/second")
+ for r in (rcv1, rcv2, rcv3):
+ try:
+ r.fetch(0)
+ assert False
+ except Empty:
+ pass
+ msg1 = Message(self.content("testCreateExchange", 1), subject="first")
+ msg2 = Message(self.content("testCreateExchange", 2), subject="second")
+ snd.send(msg1)
+ snd.send(msg2)
+ self.drain(rcv1, expected=[msg1.content])
+ self.drain(rcv2, expected=[msg1.content])
+ self.drain(rcv3, expected=[msg2.content])
+
+ def testCreateExchange(self):
+ self.createExchangeTest()
+
+ def testCreateExchangeDirect(self):
+ self.createExchangeTest("type: direct")
+
+ def testCreateExchangeTopic(self):
+ self.createExchangeTest("type: topic")
+
+ def testDeleteBySender(self):
+ snd = self.ssn.sender("test-delete; {create: always}")
+ snd.send("ping")
+ snd.close()
+ snd = self.ssn.sender("test-delete; {delete: always}")
+ snd.send("ping")
+ snd.close()
+ snd = self.ssn.sender("test-delete")
+ try:
+ snd.send("ping")
+ except SendError, e:
+ assert "no such queue" in str(e)
+
+ def testDeleteByReceiver(self):
+ rcv = self.ssn.receiver("test-delete; {create: always, delete: always}")
+ try:
+ rcv.fetch(0)
+ except Empty:
+ pass
+ rcv.close()
+
+ try:
+ self.ssn.receiver("test-delete")
+ except SendError, e:
+ assert "no such queue" in str(e)
+
+ def testDeleteSpecial(self):
+ snd = self.ssn.sender("amq.topic; {delete: always}")
+ snd.send("asdf")
+ try:
+ snd.close()
+ except SessionError, e:
+ assert "Cannot delete default exchange" in str(e)
+ # XXX: need to figure out close after error
+ self.conn._remove_session(self.ssn)
+
+ def testBindings(self):
+ snd = self.ssn.sender("""
+test-bindings-queue; {
+ create: always,
+ delete: always,
+ node-properties: {
+ x-properties: {
+ bindings: ["amq.topic/a.#", "amq.direct/b", "amq.topic/c.*"]
+ }
+ }
+}
+""")
+ snd.send("one")
+ snd_a = self.ssn.sender("amq.topic/a.foo")
+ snd_b = self.ssn.sender("amq.direct/b")
+ snd_c = self.ssn.sender("amq.topic/c.bar")
+ snd_a.send("two")
+ snd_b.send("three")
+ snd_c.send("four")
+ rcv = self.ssn.receiver("test-bindings-queue")
+ self.drain(rcv, expected=["one", "two", "three", "four"])
+
+NOSUCH_Q = "this-queue-should-not-exist"
+UNPARSEABLE_ADDR = "name/subject; {bad options"
+UNLEXABLE_ADDR = "\0x0\0x1\0x2\0x3"
+
+class AddressErrorTests(Base):
+
+ def setup_connection(self):
+ return Connection.open(self.broker.host, self.broker.port,
+ reconnect=self.reconnect())
+
+ def setup_session(self):
+ return self.conn.session()
+
+ def sendErrorTest(self, addr, exc, check=lambda e: True):
+ snd = self.ssn.sender(addr, durable=self.durable())
+ try:
+ snd.send("hello")
+ assert False, "send succeeded"
+ except exc, e:
+ assert check(e), "unexpected error: %s" % compat.format_exc(e)
+ snd.close()
+
+ def fetchErrorTest(self, addr, exc, check=lambda e: True):
+ rcv = self.ssn.receiver(addr)
+ try:
+ rcv.fetch(timeout=0)
+ assert False, "fetch succeeded"
+ except exc, e:
+ assert check(e), "unexpected error: %s" % compat.format_exc(e)
+ rcv.close()
+
+ def testNoneTarget(self):
+ # XXX: should have specific exception for this
+ self.sendErrorTest(None, SendError)
+
+ def testNoneSource(self):
+ # XXX: should have specific exception for this
+ self.fetchErrorTest(None, ReceiveError)
+
+ def testNoTarget(self):
+ # XXX: should have specific exception for this
+ self.sendErrorTest(NOSUCH_Q, SendError, lambda e: NOSUCH_Q in str(e))
+
+ def testNoSource(self):
+ # XXX: should have specific exception for this
+ self.fetchErrorTest(NOSUCH_Q, ReceiveError, lambda e: NOSUCH_Q in str(e))
+
+ def testUnparseableTarget(self):
+ # XXX: should have specific exception for this
+ self.sendErrorTest(UNPARSEABLE_ADDR, SendError,
+ lambda e: "expecting COLON" in str(e))
+
+ def testUnparseableSource(self):
+ # XXX: should have specific exception for this
+ self.fetchErrorTest(UNPARSEABLE_ADDR, ReceiveError,
+ lambda e: "expecting COLON" in str(e))
+
+ def testUnlexableTarget(self):
+ # XXX: should have specific exception for this
+ self.sendErrorTest(UNLEXABLE_ADDR, SendError,
+ lambda e: "unrecognized characters" in str(e))
+
+ def testUnlexableSource(self):
+ # XXX: should have specific exception for this
+ self.fetchErrorTest(UNLEXABLE_ADDR, ReceiveError,
+ lambda e: "unrecognized characters" in str(e))
+
+SENDER_Q = 'test-sender-q; {create: always, delete: always}'
+
+class SenderTests(Base):
+
+ def setup_connection(self):
+ return Connection.open(self.broker.host, self.broker.port,
+ reconnect=self.reconnect())
+
+ def setup_session(self):
+ return self.conn.session()
+
+ def setup_sender(self):
+ return self.ssn.sender(SENDER_Q)
+
+ def setup_receiver(self):
+ return self.ssn.receiver(SENDER_Q)
+
+ def checkContent(self, content):
+ self.snd.send(content)
+ msg = self.rcv.fetch(0)
+ assert msg.content == content
+
+ out = Message(content)
+ self.snd.send(out)
+ echo = self.rcv.fetch(0)
+ assert out.content == echo.content
+ assert echo.content == msg.content
+ self.ssn.acknowledge()
+
+ def testSendString(self):
+ self.checkContent(self.content("testSendString"))
+
+ def testSendList(self):
+ self.checkContent(["testSendList", 1, 3.14, self.test_id])
+
+ def testSendMap(self):
+ self.checkContent({"testSendMap": self.test_id, "pie": "blueberry", "pi": 3.14})
+
+ def asyncTest(self, capacity):
+ self.snd.capacity = capacity
+ msgs = [self.content("asyncTest", i) for i in range(15)]
+ for m in msgs:
+ self.snd.send(m, sync=False)
+ drained = self.drain(self.rcv, timeout=self.delay())
+ assert msgs == drained, "expected %s, got %s" % (msgs, drained)
+ self.ssn.acknowledge()
+
+ def testSendAsyncCapacity0(self):
+ try:
+ self.asyncTest(0)
+ assert False, "send shouldn't succeed with zero capacity"
+ except InsufficientCapacity:
+ # this is expected
+ pass
+
+ def testSendAsyncCapacity1(self):
+ self.asyncTest(1)
+
+ def testSendAsyncCapacity5(self):
+ self.asyncTest(5)
+
+ def testSendAsyncCapacityUNLIMITED(self):
+ self.asyncTest(UNLIMITED)
+
+ def testCapacityTimeout(self):
+ self.snd.capacity = 1
+ msgs = []
+ caught = False
+ while len(msgs) < 100:
+ m = self.content("testCapacity", len(msgs))
+ try:
+ self.snd.send(m, sync=False, timeout=0)
+ msgs.append(m)
+ except InsufficientCapacity:
+ caught = True
+ break
+ self.snd.sync()
+ self.drain(self.rcv, expected=msgs)
+ self.ssn.acknowledge()
+ assert caught, "did not exceed capacity"
+
+class MessageTests(Base):
+
+ def testCreateString(self):
+ m = Message("string")
+ assert m.content == "string"
+ assert m.content_type is None
+
+ def testCreateUnicode(self):
+ m = Message(u"unicode")
+ assert m.content == u"unicode"
+ assert m.content_type == "text/plain"
+
+ def testCreateMap(self):
+ m = Message({})
+ assert m.content == {}
+ assert m.content_type == "amqp/map"
+
+ def testCreateList(self):
+ m = Message([])
+ assert m.content == []
+ assert m.content_type == "amqp/list"
+
+ def testContentTypeOverride(self):
+ m = Message()
+ m.content_type = "text/html; charset=utf8"
+ m.content = u"<html/>"
+ assert m.content_type == "text/html; charset=utf8"
+
+ECHO_Q = 'test-message-echo-queue; {create: always, delete: always}'
+
+class MessageEchoTests(Base):
+
+ def setup_connection(self):
+ return Connection.open(self.broker.host, self.broker.port,
+ reconnect=self.reconnect())
+
+ def setup_session(self):
+ return self.conn.session()
+
+ def setup_sender(self):
+ return self.ssn.sender(ECHO_Q)
+
+ def setup_receiver(self):
+ return self.ssn.receiver(ECHO_Q)
+
+ def check(self, msg):
+ self.snd.send(msg)
+ echo = self.rcv.fetch(0)
+
+ assert msg.id == echo.id
+ assert msg.subject == echo.subject
+ assert msg.user_id == echo.user_id
+ assert msg.to == echo.to
+ assert msg.reply_to == echo.reply_to
+ assert msg.correlation_id == echo.correlation_id
+ assert msg.properties == echo.properties
+ assert msg.content_type == echo.content_type
+ assert msg.content == echo.content, "%s, %s" % (msg, echo)
+
+ self.ssn.acknowledge(echo)
+
+ def testStringContent(self):
+ self.check(Message("string"))
+
+ def testUnicodeContent(self):
+ self.check(Message(u"unicode"))
+
+
+ TEST_MAP = {"key1": "string",
+ "key2": u"unicode",
+ "key3": 3,
+ "key4": -3,
+ "key5": 3.14,
+ "key6": -3.14,
+ "key7": ["one", 2, 3.14],
+ "key8": [],
+ "key9": {"sub-key0": 3}}
+
+ def testMapContent(self):
+ self.check(Message(MessageEchoTests.TEST_MAP))
+
+ def testListContent(self):
+ self.check(Message([]))
+ self.check(Message([1, 2, 3]))
+ self.check(Message(["one", 2, 3.14, {"four": 4}]))
+
+ def testProperties(self):
+ msg = Message()
+ msg.to = "to-address"
+ msg.subject = "subject"
+ msg.correlation_id = str(self.test_id)
+ msg.properties = MessageEchoTests.TEST_MAP
+ msg.reply_to = "reply-address"
+ self.check(msg)
+
+class TestTestsXXX(Test):
+
+ def testFoo(self):
+ print "this test has output"
+
+ def testBar(self):
+ print "this test "*8
+ print "has"*10
+ print "a"*75
+ print "lot of"*10
+ print "output"*10
+
+ def testQux(self):
+ import sys
+ sys.stdout.write("this test has output with no newline")
+
+ def testQuxFail(self):
+ import sys
+ sys.stdout.write("this test has output with no newline")
+ fdsa
diff --git a/python/qpid/tests/mimetype.py b/python/qpid/tests/mimetype.py
new file mode 100644
index 0000000000..22760316f0
--- /dev/null
+++ b/python/qpid/tests/mimetype.py
@@ -0,0 +1,56 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from qpid.tests import Test
+from qpid.mimetype import lex, parse, ParseError, EOF, WSPACE
+from parser import ParserBase
+
+class MimeTypeTests(ParserBase, Test):
+
+ EXCLUDE = (WSPACE, EOF)
+
+ def do_lex(self, st):
+ return lex(st)
+
+ def do_parse(self, st):
+ return parse(st)
+
+ def valid(self, addr, type=None, subtype=None, parameters=None):
+ ParserBase.valid(self, addr, (type, subtype, parameters))
+
+ def testTypeOnly(self):
+ self.invalid("type", "expecting SLASH, got EOF line:1,4:type")
+
+ def testTypeSubtype(self):
+ self.valid("type/subtype", "type", "subtype", [])
+
+ def testTypeSubtypeParam(self):
+ self.valid("type/subtype ; name=value",
+ "type", "subtype", [("name", "value")])
+
+ def testTypeSubtypeParamComment(self):
+ self.valid("type/subtype ; name(This is a comment.)=value",
+ "type", "subtype", [("name", "value")])
+
+ def testMultipleParams(self):
+ self.valid("type/subtype ; name1=value1 ; name2=value2",
+ "type", "subtype", [("name1", "value1"), ("name2", "value2")])
+
+ def testCaseInsensitivity(self):
+ self.valid("Type/Subtype", "type", "subtype", [])
diff --git a/python/qpid/tests/parser.py b/python/qpid/tests/parser.py
new file mode 100644
index 0000000000..a4865cc9fe
--- /dev/null
+++ b/python/qpid/tests/parser.py
@@ -0,0 +1,37 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from qpid.parser import ParseError
+
+class ParserBase:
+
+ def lex(self, addr, *types):
+ toks = [t.type for t in self.do_lex(addr) if t.type not in self.EXCLUDE]
+ assert list(types) == toks, "expected %s, got %s" % (types, toks)
+
+ def valid(self, addr, expected):
+ got = self.do_parse(addr)
+ assert expected == got, "expected %s, got %s" % (expected, got)
+
+ def invalid(self, addr, error=None):
+ try:
+ p = self.do_parse(addr)
+ assert False, "invalid address parsed: %s" % p
+ except ParseError, e:
+ assert error == str(e), "expected %r, got %r" % (error, str(e))
diff --git a/python/qpid/util.py b/python/qpid/util.py
index 1140cbe5ef..3409d777f9 100644
--- a/python/qpid/util.py
+++ b/python/qpid/util.py
@@ -17,7 +17,26 @@
# under the License.
#
-import os, socket, time, textwrap
+import os, socket, time, textwrap, re
+
+try:
+ from ssl import wrap_socket as ssl
+except ImportError:
+ from socket import ssl as wrap_socket
+ class ssl:
+
+ def __init__(self, sock):
+ self.sock = sock
+ self.ssl = wrap_socket(sock)
+
+ def recv(self, n):
+ return self.ssl.read(n)
+
+ def send(self, s):
+ return self.ssl.write(s)
+
+ def close(self):
+ self.sock.close()
def connect(host, port):
sock = socket.socket()
@@ -32,8 +51,8 @@ def listen(host, port, predicate = lambda: True, bound = lambda: None):
sock = socket.socket()
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((host, port))
- bound()
sock.listen(5)
+ bound()
while predicate():
s, a = sock.accept()
yield s
@@ -48,7 +67,9 @@ def wait(condition, predicate, timeout=None):
start = time.time()
while not predicate():
if timeout is None:
- condition.wait()
+ # using the timed wait prevents keyboard interrupts from being
+ # blocked while waiting
+ condition.wait(3)
elif passed < timeout:
condition.wait(timeout - passed)
else:
@@ -76,3 +97,46 @@ def fill(text, indent, heading = None):
init = sub
w = textwrap.TextWrapper(initial_indent = init, subsequent_indent = sub)
return w.fill(" ".join(text.split()))
+
+class URL:
+
+ RE = re.compile(r"""
+ # [ <scheme>:// ] [ <user> [ / <password> ] @] <host> [ :<port> ]
+ ^ (?: ([^:/@]+)://)? (?: ([^:/@]+) (?: / ([^:/@]+) )? @)? ([^@:/]+) (?: :([0-9]+))?$
+""", re.X)
+
+ AMQPS = "amqps"
+ AMQP = "amqp"
+
+ def __init__(self, s):
+ match = URL.RE.match(s)
+ if match is None:
+ raise ValueError(s)
+ self.scheme, self.user, self.password, self.host, port = match.groups()
+ if port is None:
+ self.port = None
+ else:
+ self.port = int(port)
+
+ def __repr__(self):
+ return "URL(%r)" % str(self)
+
+ def __str__(self):
+ s = ""
+ if self.scheme:
+ s += "%s://" % self.scheme
+ if self.user:
+ s += self.user
+ if self.password:
+ s += "/%s" % self.password
+ s += "@"
+ s += self.host
+ if self.port:
+ s += ":%s" % self.port
+ return s
+
+def default(value, default):
+ if value is None:
+ return default
+ else:
+ return value
diff --git a/python/qpid_config.py b/python/qpid_config.py
index 8f987e9962..d740a53dfe 100644
--- a/python/qpid_config.py
+++ b/python/qpid_config.py
@@ -19,5 +19,7 @@
import os
-qpid_home = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-amqp_spec = os.path.join(qpid_home, "specs", "amqp.0-10-qpid-errata.xml")
+AMQP_SPEC_DIR=os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "specs")
+amqp_spec = os.path.join(AMQP_SPEC_DIR, "amqp.0-10-qpid-errata.xml")
+amqp_spec_0_8 = os.path.join(AMQP_SPEC_DIR, "amqp.0-8.xml")
+amqp_spec_0_9 = os.path.join(AMQP_SPEC_DIR, "amqp.0-9.xml")
diff --git a/python/rule2test b/python/rule2test
deleted file mode 100755
index 10f151366e..0000000000
--- a/python/rule2test
+++ /dev/null
@@ -1,108 +0,0 @@
-#!/usr/bin/env python
-
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-#
-# Convert rules to tests
-#
-import sys, re, os.path
-from getopt import getopt, GetoptError
-from string import capitalize
-from xml import dom
-from xml.dom.minidom import parse
-
-def camelcase(s):
- """Convert 'string like this' to 'StringLikeThis'"""
- return "".join([capitalize(w) for w in re.split(re.compile("\W*"), s)])
-
-def uncapitalize(s): return s[0].lower()+s[1:]
-
-def ancestors(node):
- "Return iterator of ancestors from top-level element to node"
- def generator(node):
- while node and node.parentNode:
- yield node
- node = node.parentNode
- return reversed(list(generator(node)))
-
-def tagAndName(element):
- nameAttr = element.getAttribute("name");
- if (nameAttr) : return camelcase(nameAttr) + camelcase(element.tagName)
- else: return camelcase(element.tagName)
-
-def nodeText(n):
- """Recursively collect text from all text nodes under n"""
- if n.nodeType == dom.Node.TEXT_NODE:
- return n.data
- if n.childNodes:
- return reduce(lambda t, c: t + nodeText(c), n.childNodes, "")
- return ""
-
-def cleanup(docString, level=8):
- unindent = re.sub("\n[ \t]*", "\n", docString.strip())
- emptyLines = re.sub("\n\n\n", "\n\n", unindent)
- indented = re.sub("\n", "\n"+level*" ", emptyLines)
- return level*" " + indented
-
-def printTest(test, docstring):
- print "class %s(TestBase):" % test
- print ' """'
- print docstring
- print ' """'
- print
- print
-
-def printTests(doc, module):
- """Returns dictionary { classname : [ (methodname, docstring)* ] * }"""
- tests = {}
- rules = doc.getElementsByTagName("rule")
- for r in rules:
- path = list(ancestors(r))
- if module == path[1].getAttribute("name").lower():
- test = "".join(map(tagAndName, path[2:])) + "Tests"
- docstring = cleanup(nodeText(r), 4)
- printTest(test, docstring)
-
-def usage(message=None):
- if message: print >>sys.stderr, message
- print >>sys.stderr, """
-rule2test [options] <amqpclass>
-
-Print test classes for each rule for the amqpclass in amqp.xml.
-
-Options:
- -?/-h/--help : this message
- -s/--spec <spec.xml> : file containing amqp XML spec
-"""
- return 1
-
-def main(argv):
- try: opts, args = getopt(argv[1:], "h?s:", ["help", "spec="])
- except GetoptError, e: return usage(e)
- spec = "../specs/amqp.xml" # Default
- for opt, val in opts:
- if (opt in ("-h", "-?", "--help")): return usage()
- if (opt in ("-s", "--spec")): spec = val
- doc = parse(spec)
- if len(args) == 0: return usage()
- printTests(doc, args[0])
- return 0
-
-if (__name__ == "__main__"): sys.exit(main(sys.argv))
diff --git a/python/run-tests b/python/run-tests
deleted file mode 100755
index 84b76ebfc1..0000000000
--- a/python/run-tests
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-import sys, logging
-from qpid.testlib import testrunner
-from qpid.log import enable, WARN, DEBUG
-
-if "-vv" in sys.argv:
- level = DEBUG
-else:
- level = WARN
-
-enable("qpid", level)
-
-if not testrunner.run(): sys.exit(1)
-
-
-
diff --git a/python/server b/python/server
index 37416314e2..56edd38490 100755
--- a/python/server
+++ b/python/server
@@ -1,4 +1,22 @@
#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
import qpid
from qpid.connection import Connection, listen
from qpid.delegate import Delegate
diff --git a/python/server010 b/python/server010
index 0a75e2534e..8dfcd7a585 100755
--- a/python/server010
+++ b/python/server010
@@ -1,4 +1,22 @@
#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
from qpid import delegates
from qpid.connection010 import Connection
diff --git a/python/setup.py b/python/setup.py
index a49fa6ca51..be8c7c2a03 100644
--- a/python/setup.py
+++ b/python/setup.py
@@ -19,7 +19,7 @@
#
from distutils.core import setup
-setup(name="qpid", version="0.1", packages=["qpid"], scripts=["amqp-doc"],
- url="http://incubator.apache.org/qpid",
+setup(name="qpid", version="0.6", packages=["qpid", "mllib"], scripts=["amqp-doc"],
+ url="http://qpid.apache.org/",
license="Apache Software License",
description="Python language client implementation for Apache Qpid")
diff --git a/python/tests/__init__.py b/python/tests/__init__.py
index 8ad514fc2f..1e495f3af3 100644
--- a/python/tests/__init__.py
+++ b/python/tests/__init__.py
@@ -19,12 +19,4 @@
# under the License.
#
-from codec import *
-from queue import *
-from spec import *
-from framer import *
-from assembler import *
-from datatypes import *
-from connection import *
-from spec010 import *
-from codec010 import *
+import codec, queue, datatypes, connection, spec010, codec010
diff --git a/python/tests/assembler.py b/python/tests/assembler.py
deleted file mode 100644
index b76924e59d..0000000000
--- a/python/tests/assembler.py
+++ /dev/null
@@ -1,77 +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.
-#
-
-from threading import *
-from unittest import TestCase
-from qpid.util import connect, listen
-from qpid.assembler import *
-
-PORT = 1234
-
-class AssemblerTest(TestCase):
-
- def setUp(self):
- started = Event()
- self.running = True
-
- def run():
- running = True
- for s in listen("0.0.0.0", PORT, lambda: self.running, lambda: started.set()):
- asm = Assembler(s)
- try:
- asm.write_header(*asm.read_header()[-2:])
- while True:
- seg = asm.read_segment()
- asm.write_segment(seg)
- except Closed:
- pass
-
- self.server = Thread(target=run)
- self.server.setDaemon(True)
- self.server.start()
-
- started.wait(3)
-
- def tearDown(self):
- self.running = False
- self.server.join()
-
- def test(self):
- asm = Assembler(connect("0.0.0.0", PORT), max_payload = 1)
- asm.write_header(0, 10)
- asm.write_segment(Segment(True, False, 1, 2, 3, "TEST"))
- asm.write_segment(Segment(False, True, 1, 2, 3, "ING"))
-
- assert asm.read_header() == ("AMQP", 1, 1, 0, 10)
-
- seg = asm.read_segment()
- assert seg.first == True
- assert seg.last == False
- assert seg.type == 1
- assert seg.track == 2
- assert seg.channel == 3
- assert seg.payload == "TEST"
-
- seg = asm.read_segment()
- assert seg.first == False
- assert seg.last == True
- assert seg.type == 1
- assert seg.track == 2
- assert seg.channel == 3
- assert seg.payload == "ING"
diff --git a/python/tests/codec.py b/python/tests/codec.py
index 4bd3675af8..9b51b4713c 100644
--- a/python/tests/codec.py
+++ b/python/tests/codec.py
@@ -23,7 +23,6 @@ from qpid.codec import Codec
from qpid.spec import load
from cStringIO import StringIO
from qpid.reference import ReferenceId
-from qpid.testlib import testrunner
__doc__ = """
@@ -54,13 +53,8 @@ __doc__ = """
"""
-SPEC = None
-
-def spec():
- global SPEC
- if SPEC == None:
- SPEC = load(testrunner.get_spec_file("amqp.0-8.xml"))
- return SPEC
+from qpid_config import amqp_spec_0_8
+SPEC = load(amqp_spec_0_8)
# --------------------------------------
# --------------------------------------
@@ -76,7 +70,7 @@ class BaseDataTypes(unittest.TestCase):
"""
standard setUp for unitetest (refer unittest documentation for details)
"""
- self.codec = Codec(StringIO(), spec())
+ self.codec = Codec(StringIO(), SPEC)
# ------------------
def tearDown(self):
@@ -507,7 +501,7 @@ def test(type, value):
else:
values = [value]
stream = StringIO()
- codec = Codec(stream, spec())
+ codec = Codec(stream, SPEC)
for v in values:
codec.encode(type, v)
codec.flush()
diff --git a/python/tests/codec010.py b/python/tests/codec010.py
index 835966e103..787ebc146f 100644
--- a/python/tests/codec010.py
+++ b/python/tests/codec010.py
@@ -17,31 +17,54 @@
# under the License.
#
+import time
+
from unittest import TestCase
-from qpid.spec010 import load
from qpid.codec010 import StringCodec
-from qpid.testlib import testrunner
+from qpid.datatypes import timestamp, uuid4
+from qpid.ops import PRIMITIVE
class CodecTest(TestCase):
- def setUp(self):
- self.spec = load(testrunner.get_spec_file("amqp.0-10.xml"))
-
- def check(self, type, value):
- t = self.spec[type]
- sc = StringCodec(self.spec)
- t.encode(sc, value)
- decoded = t.decode(sc)
- assert decoded == value, "%s, %s" % (decoded, value)
+ def check(self, type, value, compare=True):
+ t = PRIMITIVE[type]
+ sc = StringCodec()
+ sc.write_primitive(t, value)
+ decoded = sc.read_primitive(t)
+ if compare:
+ assert decoded == value, "%s, %s" % (decoded, value)
+ return decoded
def testMapString(self):
self.check("map", {"string": "this is a test"})
+ def testMapUnicode(self):
+ self.check("map", {"unicode": u"this is a unicode test"})
+
+ def testMapBinary(self):
+ self.check("map", {"binary": "\x7f\xb4R^\xe5\xf0:\x89\x96E1\xf6\xfe\xb9\x1b\xf5"})
+
+ def testMapBuffer(self):
+ s = "\x7f\xb4R^\xe5\xf0:\x89\x96E1\xf6\xfe\xb9\x1b\xf5"
+ dec = self.check("map", {"buffer": buffer(s)}, False)
+ assert dec["buffer"] == s
+
def testMapInt(self):
self.check("map", {"int": 3})
def testMapLong(self):
self.check("map", {"long": 2**32})
+ self.check("map", {"long": 1 << 34})
+ self.check("map", {"long": -(1 << 34)})
+
+ def testMapTimestamp(self):
+ decoded = self.check("map", {"timestamp": timestamp(0)})
+ assert isinstance(decoded["timestamp"], timestamp)
+
+ def testMapDatetime(self):
+ decoded = self.check("map", {"datetime": timestamp(0).datetime()}, compare=False)
+ assert isinstance(decoded["datetime"], timestamp)
+ assert decoded["datetime"] == 0.0
def testMapNone(self):
self.check("map", {"none": None})
@@ -52,13 +75,21 @@ class CodecTest(TestCase):
def testMapList(self):
self.check("map", {"list": [1, "two", 3.0, -4]})
+ def testMapUUID(self):
+ self.check("map", {"uuid": uuid4()})
+
def testMapAll(self):
- self.check("map", {"string": "this is a test",
- "int": 3,
- "long": 2**32,
- "none": None,
- "map": {"string": "nested map"},
- "list": [1, "two", 3.0, -4]})
+ decoded = self.check("map", {"string": "this is a test",
+ "unicode": u"this is a unicode test",
+ "binary": "\x7f\xb4R^\xe5\xf0:\x89\x96E1\xf6\xfe\xb9\x1b\xf5",
+ "int": 3,
+ "long": 2**32,
+ "timestamp": timestamp(0),
+ "none": None,
+ "map": {"string": "nested map"},
+ "list": [1, "two", 3.0, -4],
+ "uuid": uuid4()})
+ assert isinstance(decoded["timestamp"], timestamp)
def testMapEmpty(self):
self.check("map", {})
@@ -86,3 +117,17 @@ class CodecTest(TestCase):
def testArrayNone(self):
self.check("array", None)
+
+ def testInt16(self):
+ self.check("int16", 3)
+ self.check("int16", -3)
+
+ def testInt64(self):
+ self.check("int64", 3)
+ self.check("int64", -3)
+ self.check("int64", 1<<34)
+ self.check("int64", -(1<<34))
+
+ def testDatetime(self):
+ self.check("datetime", timestamp(0))
+ self.check("datetime", timestamp(long(time.time())))
diff --git a/python/tests/connection.py b/python/tests/connection.py
index 23e0c937fb..8c00df56e1 100644
--- a/python/tests/connection.py
+++ b/python/tests/connection.py
@@ -22,11 +22,10 @@ from unittest import TestCase
from qpid.util import connect, listen
from qpid.connection import *
from qpid.datatypes import Message
-from qpid.testlib import testrunner
from qpid.delegates import Server
from qpid.queue import Queue
-from qpid.spec010 import load
from qpid.session import Delegate
+from qpid.ops import QueueQueryResult
PORT = 1234
@@ -52,23 +51,24 @@ class TestSession(Delegate):
pass
def queue_query(self, qq):
- return qq._type.result.type.new((qq.queue,), {})
+ return QueueQueryResult(qq.queue)
- def message_transfer(self, cmd, headers, body):
+ def message_transfer(self, cmd):
if cmd.destination == "echo":
- m = Message(body)
- m.headers = headers
+ m = Message(cmd.payload)
+ m.headers = cmd.headers
self.session.message_transfer(cmd.destination, cmd.accept_mode,
cmd.acquire_mode, m)
elif cmd.destination == "abort":
self.session.channel.connection.sock.close()
+ elif cmd.destination == "heartbeat":
+ self.session.channel.connection_heartbeat()
else:
- self.queue.put((cmd, headers, body))
+ self.queue.put(cmd)
class ConnectionTest(TestCase):
def setUp(self):
- self.spec = load(testrunner.get_spec_file("amqp.0-10.xml"))
self.queue = Queue()
self.running = True
started = Event()
@@ -76,7 +76,7 @@ class ConnectionTest(TestCase):
def run():
ts = TestServer(self.queue)
for s in listen("0.0.0.0", PORT, lambda: self.running, lambda: started.set()):
- conn = Connection(s, self.spec, ts.connection)
+ conn = Connection(s, delegate=ts.connection)
try:
conn.start(5)
except Closed:
@@ -87,14 +87,15 @@ class ConnectionTest(TestCase):
self.server.start()
started.wait(3)
+ assert started.isSet()
def tearDown(self):
self.running = False
- connect("0.0.0.0", PORT).close()
+ connect("127.0.0.1", PORT).close()
self.server.join(3)
- def connect(self):
- return Connection(connect("0.0.0.0", PORT), self.spec)
+ def connect(self, **kwargs):
+ return Connection(connect("127.0.0.1", PORT), **kwargs)
def test(self):
c = self.connect()
@@ -133,17 +134,17 @@ class ConnectionTest(TestCase):
ssn.message_transfer(d)
for d in destinations:
- cmd, header, body = self.queue.get(10)
+ cmd = self.queue.get(10)
assert cmd.destination == d
- assert header == None
- assert body == None
+ assert cmd.headers == None
+ assert cmd.payload == None
msg = Message("this is a test")
ssn.message_transfer("four", message=msg)
- cmd, header, body = self.queue.get(10)
+ cmd = self.queue.get(10)
assert cmd.destination == "four"
- assert header == None
- assert body == msg.body
+ assert cmd.headers == None
+ assert cmd.payload == msg.body
qq = ssn.queue_query("asdf")
assert qq.queue == "asdf"
@@ -212,3 +213,10 @@ class ConnectionTest(TestCase):
s.auto_sync = False
s.message_transfer("echo", message=Message("test"))
s.sync(10)
+
+ def testHeartbeat(self):
+ c = self.connect(heartbeat=10)
+ c.start(10)
+ s = c.session("test")
+ s.channel.connection_heartbeat()
+ s.message_transfer("heartbeat")
diff --git a/python/tests/datatypes.py b/python/tests/datatypes.py
index ef98e81da0..00e649d6cf 100644
--- a/python/tests/datatypes.py
+++ b/python/tests/datatypes.py
@@ -18,23 +18,22 @@
#
from unittest import TestCase
-from qpid.testlib import testrunner
-from qpid.spec010 import load
from qpid.datatypes import *
+from qpid.ops import DeliveryProperties, FragmentProperties, MessageProperties
class SerialTest(TestCase):
def test(self):
- for s in (serial(0), serial(0x8FFFFFFF), serial(0xFFFFFFFF)):
+ for s in (serial(0), serial(0x8FFFFFFFL), serial(0xFFFFFFFFL)):
assert s + 1 > s
assert s - 1 < s
assert s < s + 1
assert s > s - 1
- assert serial(0xFFFFFFFF) + 1 == serial(0)
+ assert serial(0xFFFFFFFFL) + 1 == serial(0)
- assert min(serial(0xFFFFFFFF), serial(0x0)) == serial(0xFFFFFFFF)
- assert max(serial(0xFFFFFFFF), serial(0x0)) == serial(0x0)
+ assert min(serial(0xFFFFFFFFL), serial(0x0)) == serial(0xFFFFFFFFL)
+ assert max(serial(0xFFFFFFFFL), serial(0x0)) == serial(0x0)
def testIncr(self):
s = serial(0)
@@ -44,7 +43,7 @@ class SerialTest(TestCase):
def testIn(self):
l = [serial(1), serial(2), serial(3), serial(4)]
assert serial(1) in l
- assert serial(0xFFFFFFFF + 2) in l
+ assert serial(0xFFFFFFFFL + 2) in l
assert 4 in l
def testNone(self):
@@ -55,6 +54,19 @@ class SerialTest(TestCase):
d[serial(0)] = "zero"
assert d[0] == "zero"
+ def testAdd(self):
+ assert serial(2) + 2 == serial(4)
+ assert serial(2) + 2 == 4
+
+ def testSub(self):
+ delta = serial(4) - serial(2)
+ assert isinstance(delta, int) or isinstance(delta, long)
+ assert delta == 2
+
+ delta = serial(4) - 2
+ assert isinstance(delta, Serial)
+ assert delta == serial(2)
+
class RangedSetTest(TestCase):
def check(self, ranges):
@@ -136,6 +148,34 @@ class RangedSetTest(TestCase):
assert range.lower == 0
assert range.upper == 8
+ def testEmpty(self):
+ s = RangedSet()
+ assert s.empty()
+ s.add(0, -1)
+ assert s.empty()
+ s.add(0, 0)
+ assert not s.empty()
+
+ def testMinMax(self):
+ s = RangedSet()
+ assert s.max() is None
+ assert s.min() is None
+ s.add(0, 10)
+ assert s.max() == 10
+ assert s.min() == 0
+ s.add(0, 5)
+ assert s.max() == 10
+ assert s.min() == 0
+ s.add(0, 11)
+ assert s.max() == 11
+ assert s.min() == 0
+ s.add(15, 20)
+ assert s.max() == 20
+ assert s.min() == 0
+ s.add(-10, -5)
+ assert s.max() == 20
+ assert s.min() == -10
+
class RangeTest(TestCase):
def testIntersect1(self):
@@ -176,10 +216,9 @@ class UUIDTest(TestCase):
class MessageTest(TestCase):
def setUp(self):
- self.spec = load(testrunner.get_spec_file("amqp.0-10-qpid-errata.xml"))
- self.mp = Struct(self.spec["message.message_properties"])
- self.dp = Struct(self.spec["message.delivery_properties"])
- self.fp = Struct(self.spec["message.fragment_properties"])
+ self.mp = MessageProperties()
+ self.dp = DeliveryProperties()
+ self.fp = FragmentProperties()
def testHas(self):
m = Message(self.mp, self.dp, self.fp, "body")
@@ -207,7 +246,7 @@ class MessageTest(TestCase):
def testSetReplace(self):
m = Message(self.mp, self.dp, self.fp, "body")
- dp = Struct(self.spec["message.delivery_properties"])
+ dp = DeliveryProperties()
assert m.get("delivery_properties") == self.dp
assert m.get("delivery_properties") != dp
m.set(dp)
@@ -223,3 +262,35 @@ class MessageTest(TestCase):
assert m.get("fragment_properties") is None
assert m.get("message_properties") == self.mp
assert m.get("delivery_properties") == self.dp
+
+class TimestampTest(TestCase):
+
+ def check(self, expected, *values):
+ for v in values:
+ assert isinstance(v, timestamp)
+ assert v == expected
+ assert v == timestamp(expected)
+
+ def testAdd(self):
+ self.check(4.0,
+ timestamp(2.0) + 2.0,
+ 2.0 + timestamp(2.0))
+
+ def testSub(self):
+ self.check(2.0,
+ timestamp(4.0) - 2.0,
+ 4.0 - timestamp(2.0))
+
+ def testNeg(self):
+ self.check(-4.0, -timestamp(4.0))
+
+ def testPos(self):
+ self.check(+4.0, +timestamp(4.0))
+
+ def testAbs(self):
+ self.check(4.0, abs(timestamp(-4.0)))
+
+ def testConversion(self):
+ dt = timestamp(0).datetime()
+ t = timestamp(dt)
+ assert t == 0
diff --git a/python/tests/framer.py b/python/tests/framer.py
deleted file mode 100644
index 05bb467bbe..0000000000
--- a/python/tests/framer.py
+++ /dev/null
@@ -1,94 +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.
-#
-
-from threading import *
-from unittest import TestCase
-from qpid.util import connect, listen
-from qpid.framer import *
-
-PORT = 1234
-
-class FramerTest(TestCase):
-
- def setUp(self):
- self.running = True
- started = Event()
- def run():
- for s in listen("0.0.0.0", PORT, lambda: self.running, lambda: started.set()):
- conn = Framer(s)
- try:
- conn.write_header(*conn.read_header()[-2:])
- while True:
- frame = conn.read_frame()
- conn.write_frame(frame)
- conn.flush()
- except Closed:
- pass
-
- self.server = Thread(target=run)
- self.server.setDaemon(True)
- self.server.start()
-
- started.wait(3)
-
- def tearDown(self):
- self.running = False
- self.server.join(3)
-
- def test(self):
- c = Framer(connect("0.0.0.0", PORT))
-
- c.write_header(0, 10)
- assert c.read_header() == ("AMQP", 1, 1, 0, 10)
-
- c.write_frame(Frame(FIRST_FRM, 1, 2, 3, "THIS"))
- c.write_frame(Frame(0, 1, 2, 3, "IS"))
- c.write_frame(Frame(0, 1, 2, 3, "A"))
- c.write_frame(Frame(LAST_FRM, 1, 2, 3, "TEST"))
- c.flush()
-
- f = c.read_frame()
- assert f.flags & FIRST_FRM
- assert not (f.flags & LAST_FRM)
- assert f.type == 1
- assert f.track == 2
- assert f.channel == 3
- assert f.payload == "THIS"
-
- f = c.read_frame()
- assert f.flags == 0
- assert f.type == 1
- assert f.track == 2
- assert f.channel == 3
- assert f.payload == "IS"
-
- f = c.read_frame()
- assert f.flags == 0
- assert f.type == 1
- assert f.track == 2
- assert f.channel == 3
- assert f.payload == "A"
-
- f = c.read_frame()
- assert f.flags & LAST_FRM
- assert not (f.flags & FIRST_FRM)
- assert f.type == 1
- assert f.track == 2
- assert f.channel == 3
- assert f.payload == "TEST"
diff --git a/python/tests/spec.py b/python/tests/spec.py
deleted file mode 100644
index ce03640493..0000000000
--- a/python/tests/spec.py
+++ /dev/null
@@ -1,56 +0,0 @@
-from unittest import TestCase
-from qpid.spec import load
-from qpid.testlib import testrunner
-
-class SpecTest(TestCase):
-
- def check_load(self, *urls):
- spec = load(*map(testrunner.get_spec_file, urls))
- qdecl = spec.method("queue_declare")
- assert qdecl != None
- assert not qdecl.content
-
- queue = qdecl.fields.byname["queue"]
- assert queue != None
- assert queue.domain.name == "queue_name"
- assert queue.type == "shortstr"
-
- qdecl_ok = spec.method("queue_declare_ok")
-
- # 0-8 is actually 8-0
- if (spec.major == 8 and spec.minor == 0 or
- spec.major == 0 and spec.minor == 9):
- assert qdecl_ok != None
-
- assert len(qdecl.responses) == 1
- assert qdecl_ok in qdecl.responses
-
- publish = spec.method("basic_publish")
- assert publish != None
- assert publish.content
-
- if (spec.major == 0 and spec.minor == 10):
- assert qdecl_ok == None
- reply_to = spec.domains.byname["reply_to"]
- assert reply_to.type.size == 2
- assert reply_to.type.pack == 2
- assert len(reply_to.type.fields) == 2
-
- qq = spec.method("queue_query")
- assert qq != None
- assert qq.result.size == 4
- assert qq.result.type != None
- args = qq.result.fields.byname["arguments"]
- assert args.type == "table"
-
- def test_load_0_8(self):
- self.check_load("amqp.0-8.xml")
-
- def test_load_0_9(self):
- self.check_load("amqp.0-9.xml")
-
- def test_load_0_9_errata(self):
- self.check_load("amqp.0-9.xml", "amqp-errata.0-9.xml")
-
- def test_load_0_10(self):
- self.check_load("amqp.0-10-preview.xml")
diff --git a/python/tests/spec010.py b/python/tests/spec010.py
index df9cb9590a..ac04e1ee02 100644
--- a/python/tests/spec010.py
+++ b/python/tests/spec010.py
@@ -19,66 +19,56 @@
import os, tempfile, shutil, stat
from unittest import TestCase
-from qpid.spec010 import load
from qpid.codec010 import Codec, StringCodec
-from qpid.testlib import testrunner
-from qpid.datatypes import Struct
+from qpid.ops import *
class SpecTest(TestCase):
- def setUp(self):
- self.spec = load(testrunner.get_spec_file("amqp.0-10-qpid-errata.xml"))
-
def testSessionHeader(self):
- hdr = self.spec["session.header"]
- sc = StringCodec(self.spec)
- hdr.encode(sc, Struct(hdr, sync=True))
+ sc = StringCodec()
+ sc.write_compound(Header(sync=True))
assert sc.encoded == "\x01\x01"
- sc = StringCodec(self.spec)
- hdr.encode(sc, Struct(hdr, sync=False))
+ sc = StringCodec()
+ sc.write_compound(Header(sync=False))
assert sc.encoded == "\x01\x00"
- def encdec(self, type, value):
- sc = StringCodec(self.spec)
- type.encode(sc, value)
- decoded = type.decode(sc)
+ def encdec(self, value):
+ sc = StringCodec()
+ sc.write_compound(value)
+ decoded = sc.read_compound(value.__class__)
return decoded
def testMessageProperties(self):
- mp = self.spec["message.message_properties"]
- rt = self.spec["message.reply_to"]
-
- props = Struct(mp, content_length=3735928559L,
- reply_to=Struct(rt, exchange="the exchange name",
- routing_key="the routing key"))
- dec = self.encdec(mp, props)
+ props = MessageProperties(content_length=3735928559L,
+ reply_to=ReplyTo(exchange="the exchange name",
+ routing_key="the routing key"))
+ dec = self.encdec(props)
assert props.content_length == dec.content_length
assert props.reply_to.exchange == dec.reply_to.exchange
assert props.reply_to.routing_key == dec.reply_to.routing_key
def testMessageSubscribe(self):
- ms = self.spec["message.subscribe"]
- cmd = Struct(ms, exclusive=True, destination="this is a test")
- dec = self.encdec(self.spec["message.subscribe"], cmd)
+ cmd = MessageSubscribe(exclusive=True, destination="this is a test")
+ dec = self.encdec(cmd)
assert cmd.exclusive == dec.exclusive
assert cmd.destination == dec.destination
def testXid(self):
- xid = self.spec["dtx.xid"]
- sc = StringCodec(self.spec)
- st = Struct(xid, format=0, global_id="gid", branch_id="bid")
- xid.encode(sc, st)
+ sc = StringCodec()
+ xid = Xid(format=0, global_id="gid", branch_id="bid")
+ sc.write_compound(xid)
assert sc.encoded == '\x00\x00\x00\x10\x06\x04\x07\x00\x00\x00\x00\x00\x03gid\x03bid'
- assert xid.decode(sc).__dict__ == st.__dict__
+ dec = sc.read_compound(Xid)
+ assert xid.__dict__ == dec.__dict__
- def testLoadReadOnly(self):
- spec = "amqp.0-10-qpid-errata.xml"
- f = testrunner.get_spec_file(spec)
- dest = tempfile.mkdtemp()
- shutil.copy(f, dest)
- shutil.copy(os.path.join(os.path.dirname(f), "amqp.0-10.dtd"), dest)
- os.chmod(dest, stat.S_IRUSR | stat.S_IXUSR)
- fname = os.path.join(dest, spec)
- load(fname)
- assert not os.path.exists("%s.pcl" % fname)
+# def testLoadReadOnly(self):
+# spec = "amqp.0-10-qpid-errata.xml"
+# f = testrunner.get_spec_file(spec)
+# dest = tempfile.mkdtemp()
+# shutil.copy(f, dest)
+# shutil.copy(os.path.join(os.path.dirname(f), "amqp.0-10.dtd"), dest)
+# os.chmod(dest, stat.S_IRUSR | stat.S_IXUSR)
+# fname = os.path.join(dest, spec)
+# load(fname)
+# assert not os.path.exists("%s.pcl" % fname)
diff --git a/python/tests_0-10/__init__.py b/python/tests_0-10/__init__.py
index 1fd7f72357..f9315a6f90 100644
--- a/python/tests_0-10/__init__.py
+++ b/python/tests_0-10/__init__.py
@@ -24,6 +24,7 @@ from broker import *
from dtx import *
from example import *
from exchange import *
+from management import *
from message import *
from query import *
from queue import *
diff --git a/python/tests_0-10/alternate_exchange.py b/python/tests_0-10/alternate_exchange.py
index aac8a5e15b..4d8617eb8e 100644
--- a/python/tests_0-10/alternate_exchange.py
+++ b/python/tests_0-10/alternate_exchange.py
@@ -41,16 +41,16 @@ class AlternateExchangeTests(TestBase010):
session.queue_declare(queue="returns", exclusive=True, auto_delete=True)
session.exchange_bind(queue="returns", exchange="secondary")
session.message_subscribe(destination="a", queue="returns")
- session.message_flow(destination="a", unit=session.credit_unit.message, value=0xFFFFFFFF)
- session.message_flow(destination="a", unit=session.credit_unit.byte, value=0xFFFFFFFF)
+ session.message_flow(destination="a", unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination="a", unit=session.credit_unit.byte, value=0xFFFFFFFFL)
returned = session.incoming("a")
#declare, bind (to the primary exchange) and consume from a queue for 'processed' messages
session.queue_declare(queue="processed", exclusive=True, auto_delete=True)
session.exchange_bind(queue="processed", exchange="primary", binding_key="my-key")
session.message_subscribe(destination="b", queue="processed")
- session.message_flow(destination="b", unit=session.credit_unit.message, value=0xFFFFFFFF)
- session.message_flow(destination="b", unit=session.credit_unit.byte, value=0xFFFFFFFF)
+ session.message_flow(destination="b", unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination="b", unit=session.credit_unit.byte, value=0xFFFFFFFFL)
processed = session.incoming("b")
#publish to the primary exchange
@@ -81,8 +81,8 @@ class AlternateExchangeTests(TestBase010):
session.queue_declare(queue="deleted", exclusive=True, auto_delete=True)
session.exchange_bind(exchange="dlq", queue="deleted")
session.message_subscribe(destination="dlq", queue="deleted")
- session.message_flow(destination="dlq", unit=session.credit_unit.message, value=0xFFFFFFFF)
- session.message_flow(destination="dlq", unit=session.credit_unit.byte, value=0xFFFFFFFF)
+ session.message_flow(destination="dlq", unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination="dlq", unit=session.credit_unit.byte, value=0xFFFFFFFFL)
dlq = session.incoming("dlq")
#create a queue using the dlq as its alternate exchange:
@@ -141,7 +141,61 @@ class AlternateExchangeTests(TestBase010):
session.exchange_delete(exchange="e")
session.exchange_delete(exchange="alternate")
self.assertEquals(530, e.args[0].error_code)
-
+
+
+ def test_modify_existing_exchange_alternate(self):
+ """
+ Ensure that attempting to modify an exhange to change
+ the alternate throws an exception
+ """
+ session = self.session
+ session.exchange_declare(exchange="alt1", type="direct")
+ session.exchange_declare(exchange="alt2", type="direct")
+ session.exchange_declare(exchange="onealternate", type="fanout", alternate_exchange="alt1")
+ try:
+ # attempt to change the alternate on an already existing exchange
+ session.exchange_declare(exchange="onealternate", type="fanout", alternate_exchange="alt2")
+ self.fail("Expected changing an alternate on an existing exchange to fail")
+ except SessionException, e:
+ self.assertEquals(530, e.args[0].error_code)
+ session = self.conn.session("alternate", 2)
+ session.exchange_delete(exchange="onealternate")
+ session.exchange_delete(exchange="alt2")
+ session.exchange_delete(exchange="alt1")
+
+
+ def test_add_alternate_to_exchange(self):
+ """
+ Ensure that attempting to modify an exhange by adding
+ an alternate throws an exception
+ """
+ session = self.session
+ session.exchange_declare(exchange="alt1", type="direct")
+ session.exchange_declare(exchange="noalternate", type="fanout")
+ try:
+ # attempt to add an alternate on an already existing exchange
+ session.exchange_declare(exchange="noalternate", type="fanout", alternate_exchange="alt1")
+ self.fail("Expected adding an alternate on an existing exchange to fail")
+ except SessionException, e:
+ self.assertEquals(530, e.args[0].error_code)
+ session = self.conn.session("alternate", 2)
+ session.exchange_delete(exchange="noalternate")
+ session.exchange_delete(exchange="alt1")
+
+
+ def test_del_alternate_to_exchange(self):
+ """
+ Ensure that attempting to modify an exhange by declaring
+ it again without an alternate does nothing
+ """
+ session = self.session
+ session.exchange_declare(exchange="alt1", type="direct")
+ session.exchange_declare(exchange="onealternate", type="fanout", alternate_exchange="alt1")
+ # attempt to re-declare without an alternate - silently ignore
+ session.exchange_declare(exchange="onealternate", type="fanout" )
+ session.exchange_delete(exchange="onealternate")
+ session.exchange_delete(exchange="alt1")
+
def assertEmpty(self, queue):
try:
diff --git a/python/tests_0-10/broker.py b/python/tests_0-10/broker.py
index d4aa57765c..81d723e322 100644
--- a/python/tests_0-10/broker.py
+++ b/python/tests_0-10/broker.py
@@ -36,8 +36,8 @@ class BrokerTests(TestBase010):
# No ack consumer
ctag = "tag1"
session.message_subscribe(queue = "myqueue", destination = ctag)
- session.message_flow(destination=ctag, unit=session.credit_unit.message, value=0xFFFFFFFF)
- session.message_flow(destination=ctag, unit=session.credit_unit.byte, value=0xFFFFFFFF)
+ session.message_flow(destination=ctag, unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination=ctag, unit=session.credit_unit.byte, value=0xFFFFFFFFL)
body = "test no-ack"
session.message_transfer(message=Message(session.delivery_properties(routing_key="myqueue"), body))
msg = session.incoming(ctag).get(timeout = 5)
@@ -47,8 +47,8 @@ class BrokerTests(TestBase010):
session.queue_declare(queue = "otherqueue", exclusive=True, auto_delete=True)
ctag = "tag2"
session.message_subscribe(queue = "otherqueue", destination = ctag, accept_mode = 1)
- session.message_flow(destination=ctag, unit=session.credit_unit.message, value=0xFFFFFFFF)
- session.message_flow(destination=ctag, unit=session.credit_unit.byte, value=0xFFFFFFFF)
+ session.message_flow(destination=ctag, unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination=ctag, unit=session.credit_unit.byte, value=0xFFFFFFFFL)
body = "test ack"
session.message_transfer(message=Message(session.delivery_properties(routing_key="otherqueue"), body))
msg = session.incoming(ctag).get(timeout = 5)
@@ -64,8 +64,8 @@ class BrokerTests(TestBase010):
session.exchange_bind(queue="test-queue", exchange="amq.fanout")
consumer_tag = "tag1"
session.message_subscribe(queue="test-queue", destination=consumer_tag)
- session.message_flow(unit = session.credit_unit.message, value = 0xFFFFFFFF, destination = consumer_tag)
- session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFF, destination = consumer_tag)
+ session.message_flow(unit = session.credit_unit.message, value = 0xFFFFFFFFL, destination = consumer_tag)
+ session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFFL, destination = consumer_tag)
queue = session.incoming(consumer_tag)
body = "Immediate Delivery"
@@ -86,8 +86,8 @@ class BrokerTests(TestBase010):
consumer_tag = "tag1"
session.message_subscribe(queue="test-queue", destination=consumer_tag)
- session.message_flow(unit = session.credit_unit.message, value = 0xFFFFFFFF, destination = consumer_tag)
- session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFF, destination = consumer_tag)
+ session.message_flow(unit = session.credit_unit.message, value = 0xFFFFFFFFL, destination = consumer_tag)
+ session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFFL, destination = consumer_tag)
queue = session.incoming(consumer_tag)
msg = queue.get(timeout=5)
self.assert_(msg.body == body)
diff --git a/python/tests_0-10/dtx.py b/python/tests_0-10/dtx.py
index 25c2defd3b..2823385a3b 100644
--- a/python/tests_0-10/dtx.py
+++ b/python/tests_0-10/dtx.py
@@ -575,7 +575,7 @@ class DtxTests(TestBase010):
session2.dtx_start(xid=tx)
session2.message_subscribe(queue="dummy", destination="dummy")
session2.message_flow(destination="dummy", unit=session2.credit_unit.message, value=1)
- session2.message_flow(destination="dummy", unit=session2.credit_unit.byte, value=0xFFFFFFFF)
+ session2.message_flow(destination="dummy", unit=session2.credit_unit.byte, value=0xFFFFFFFFL)
msg = session2.incoming("dummy").get(timeout=1)
session2.message_accept(RangedSet(msg.id))
session2.message_cancel(destination="dummy")
@@ -736,7 +736,7 @@ class DtxTests(TestBase010):
#consume from src:
session.message_subscribe(destination="temp-swap", queue=src)
session.message_flow(destination="temp-swap", unit=session.credit_unit.message, value=1)
- session.message_flow(destination="temp-swap", unit=session.credit_unit.byte, value=0xFFFFFFFF)
+ session.message_flow(destination="temp-swap", unit=session.credit_unit.byte, value=0xFFFFFFFFL)
msg = session.incoming("temp-swap").get(timeout=1)
session.message_cancel(destination="temp-swap")
session.message_accept(RangedSet(msg.id))
@@ -753,7 +753,7 @@ class DtxTests(TestBase010):
def assertMessageId(self, expected, queue):
self.session.message_subscribe(queue=queue, destination="results")
self.session.message_flow(destination="results", unit=self.session.credit_unit.message, value=1)
- self.session.message_flow(destination="results", unit=self.session.credit_unit.byte, value=0xFFFFFFFF)
+ self.session.message_flow(destination="results", unit=self.session.credit_unit.byte, value=0xFFFFFFFFL)
self.assertEqual(expected, self.getMessageProperty(self.session.incoming("results").get(timeout=1), 'correlation_id'))
self.session.message_cancel(destination="results")
diff --git a/python/tests_0-10/example.py b/python/tests_0-10/example.py
index 83d208192b..e36907d501 100644
--- a/python/tests_0-10/example.py
+++ b/python/tests_0-10/example.py
@@ -69,8 +69,8 @@ class ExampleTest (TestBase010):
# field that is filled if the reply includes content. In this case the
# interesting field is the consumer_tag.
session.message_subscribe(queue="test-queue", destination="consumer_tag")
- session.message_flow(destination="consumer_tag", unit=session.credit_unit.message, value=0xFFFFFFFF)
- session.message_flow(destination="consumer_tag", unit=session.credit_unit.byte, value=0xFFFFFFFF)
+ session.message_flow(destination="consumer_tag", unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination="consumer_tag", unit=session.credit_unit.byte, value=0xFFFFFFFFL)
# We can use the session.incoming(...) method to access the messages
# delivered for our consumer_tag.
diff --git a/python/tests_0-10/exchange.py b/python/tests_0-10/exchange.py
index 4b5dc78143..8d9713076d 100644
--- a/python/tests_0-10/exchange.py
+++ b/python/tests_0-10/exchange.py
@@ -108,8 +108,8 @@ class TestHelper(TestBase010):
else: self.uniqueTag += 1
consumer_tag = "tag" + str(self.uniqueTag)
self.session.message_subscribe(queue=queueName, destination=consumer_tag)
- self.session.message_flow(destination=consumer_tag, unit=self.session.credit_unit.message, value=0xFFFFFFFF)
- self.session.message_flow(destination=consumer_tag, unit=self.session.credit_unit.byte, value=0xFFFFFFFF)
+ self.session.message_flow(destination=consumer_tag, unit=self.session.credit_unit.message, value=0xFFFFFFFFL)
+ self.session.message_flow(destination=consumer_tag, unit=self.session.credit_unit.byte, value=0xFFFFFFFFL)
return self.session.incoming(consumer_tag)
@@ -269,8 +269,49 @@ class DeclareMethodExchangeFieldReservedRuleTests(TestHelper):
standardised exchanges. The client MUST NOT attempt to create an exchange
starting with "amq.".
-
+ Similarly, exchanges starting with "qpid." are reserved for Qpid
+ implementation-specific system exchanges (such as the management exchange).
+ The client must not attempt to create an exchange starting with the string
+ "qpid.".
"""
+ def template(self, reservedString, exchangeType):
+ try:
+ self.session.exchange_declare(exchange=reservedString, type=exchangeType)
+ self.fail("Expected not allowed error (530) for exchanges starting with \"" + reservedString + "\".")
+ except SessionException, e:
+ self.assertEquals(e.args[0].error_code, 530)
+ # connection closed, reopen it
+ self.tearDown()
+ self.setUp()
+ try:
+ self.session.exchange_declare(exchange=reservedString + "abc123", type=exchangeType)
+ self.fail("Expected not allowed error (530) for exchanges starting with \"" + reservedString + "\".")
+ except SessionException, e:
+ self.assertEquals(e.args[0].error_code, 530)
+ # connection closed, reopen it
+ self.tearDown()
+ self.setUp()
+ # The following should be legal:
+ self.session.exchange_declare(exchange=reservedString[:-1], type=exchangeType)
+ self.session.exchange_delete(exchange=reservedString[:-1])
+ self.session.exchange_declare(exchange=reservedString[1:], type=exchangeType)
+ self.session.exchange_delete(exchange=reservedString[1:])
+ self.session.exchange_declare(exchange="." + reservedString, type=exchangeType)
+ self.session.exchange_delete(exchange="." + reservedString)
+ self.session.exchange_declare(exchange="abc." + reservedString, type=exchangeType)
+ self.session.exchange_delete(exchange="abc." + reservedString)
+ self.session.exchange_declare(exchange="abc." + reservedString + "def", type=exchangeType)
+ self.session.exchange_delete(exchange="abc." + reservedString + "def")
+
+ def test_amq(self):
+ self.template("amq.", "direct")
+ self.template("amq.", "topic")
+ self.template("amq.", "fanout")
+
+ def test_qpid(self):
+ self.template("qpid.", "direct")
+ self.template("qpid.", "topic")
+ self.template("qpid.", "fanout")
class DeclareMethodTypeFieldTypedRuleTests(TestHelper):
diff --git a/python/tests_0-10/management.py b/python/tests_0-10/management.py
index f1360a1902..9dd03bbda4 100644
--- a/python/tests_0-10/management.py
+++ b/python/tests_0-10/management.py
@@ -20,19 +20,22 @@
from qpid.datatypes import Message, RangedSet
from qpid.testlib import TestBase010
from qpid.management import managementChannel, managementClient
+from threading import Condition
+from time import sleep
+import qmf.console
class ManagementTest (TestBase010):
"""
Tests for the management hooks
"""
- def test_broker_connectivity (self):
+ def test_broker_connectivity_oldAPI (self):
"""
Call the "echo" method on the broker to verify it is alive and talking.
"""
session = self.session
- mc = managementClient (session.spec)
+ mc = managementClient ()
mch = mc.addChannel (session)
mc.syncWaitForStable (mch)
@@ -52,40 +55,62 @@ class ManagementTest (TestBase010):
self.assertEqual (res.body, body)
mc.removeChannel (mch)
- def test_system_object (self):
+ def test_methods_sync (self):
+ """
+ Call the "echo" method on the broker to verify it is alive and talking.
+ """
session = self.session
+ self.startQmf()
- mc = managementClient (session.spec)
- mch = mc.addChannel (session)
+ brokers = self.qmf.getObjects(_class="broker")
+ self.assertEqual(len(brokers), 1)
+ broker = brokers[0]
- mc.syncWaitForStable (mch)
- systems = mc.syncGetObjects (mch, "system")
- self.assertEqual (len (systems), 1)
- mc.removeChannel (mch)
+ body = "Echo Message Body"
+ for seq in range(1, 20):
+ res = broker.echo(seq, body)
+ self.assertEqual(res.status, 0)
+ self.assertEqual(res.text, "OK")
+ self.assertEqual(res.sequence, seq)
+ self.assertEqual(res.body, body)
+
+ def test_get_objects(self):
+ self.startQmf()
+
+ # get the package list, verify that the qpid broker package is there
+ packages = self.qmf.getPackages()
+ assert 'org.apache.qpid.broker' in packages
+
+ # get the schema class keys for the broker, verify the broker table and link-down event
+ keys = self.qmf.getClasses('org.apache.qpid.broker')
+ broker = None
+ linkDown = None
+ for key in keys:
+ if key.getClassName() == "broker": broker = key
+ if key.getClassName() == "brokerLinkDown" : linkDown = key
+ assert broker
+ assert linkDown
+
+ brokerObjs = self.qmf.getObjects(_class="broker")
+ assert len(brokerObjs) == 1
+ brokerObjs = self.qmf.getObjects(_key=broker)
+ assert len(brokerObjs) == 1
def test_self_session_id (self):
- session = self.session
-
- mc = managementClient (session.spec)
- mch = mc.addChannel (session)
+ self.startQmf()
+ sessionId = self.qmf_broker.getSessionId()
+ brokerSessions = self.qmf.getObjects(_class="session")
- info = mc.syncWaitForStable (mch)
- brokerSessions = mc.syncGetObjects (mch, "session")
found = False
for bs in brokerSessions:
- if bs.name == info.sessionId:
+ if bs.name == sessionId:
found = True
self.assertEqual (found, True)
- mc.removeChannel (mch)
def test_standard_exchanges (self):
- session = self.session
-
- mc = managementClient (session.spec)
- mch = mc.addChannel (session)
+ self.startQmf()
- mc.syncWaitForStable (mch)
- exchanges = mc.syncGetObjects (mch, "exchange")
+ exchanges = self.qmf.getObjects(_class="exchange")
exchange = self.findExchange (exchanges, "")
self.assertEqual (exchange.type, "direct")
exchange = self.findExchange (exchanges, "amq.direct")
@@ -98,10 +123,276 @@ class ManagementTest (TestBase010):
self.assertEqual (exchange.type, "headers")
exchange = self.findExchange (exchanges, "qpid.management")
self.assertEqual (exchange.type, "topic")
- mc.removeChannel (mch)
def findExchange (self, exchanges, name):
for exchange in exchanges:
if exchange.name == name:
return exchange
return None
+
+ def test_move_queued_messages(self):
+ """
+ Test ability to move messages from the head of one queue to another.
+ Need to test moveing all and N messages.
+ """
+ self.startQmf()
+ session = self.session
+ "Set up source queue"
+ session.queue_declare(queue="src-queue", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="src-queue", exchange="amq.direct", binding_key="routing_key")
+
+ twenty = range(1,21)
+ props = session.delivery_properties(routing_key="routing_key")
+ for count in twenty:
+ body = "Move Message %d" % count
+ src_msg = Message(props, body)
+ session.message_transfer(destination="amq.direct", message=src_msg)
+
+ "Set up destination queue"
+ session.queue_declare(queue="dest-queue", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="dest-queue", exchange="amq.direct")
+
+ queues = self.qmf.getObjects(_class="queue")
+
+ "Move 10 messages from src-queue to dest-queue"
+ result = self.qmf.getObjects(_class="broker")[0].queueMoveMessages("src-queue", "dest-queue", 10)
+ self.assertEqual (result.status, 0)
+
+ sq = self.qmf.getObjects(_class="queue", name="src-queue")[0]
+ dq = self.qmf.getObjects(_class="queue", name="dest-queue")[0]
+
+ self.assertEqual (sq.msgDepth,10)
+ self.assertEqual (dq.msgDepth,10)
+
+ "Move all remaining messages to destination"
+ result = self.qmf.getObjects(_class="broker")[0].queueMoveMessages("src-queue", "dest-queue", 0)
+ self.assertEqual (result.status,0)
+
+ sq = self.qmf.getObjects(_class="queue", name="src-queue")[0]
+ dq = self.qmf.getObjects(_class="queue", name="dest-queue")[0]
+
+ self.assertEqual (sq.msgDepth,0)
+ self.assertEqual (dq.msgDepth,20)
+
+ "Use a bad source queue name"
+ result = self.qmf.getObjects(_class="broker")[0].queueMoveMessages("bad-src-queue", "dest-queue", 0)
+ self.assertEqual (result.status,4)
+
+ "Use a bad destination queue name"
+ result = self.qmf.getObjects(_class="broker")[0].queueMoveMessages("src-queue", "bad-dest-queue", 0)
+ self.assertEqual (result.status,4)
+
+ " Use a large qty (40) to move from dest-queue back to "
+ " src-queue- should move all "
+ result = self.qmf.getObjects(_class="broker")[0].queueMoveMessages("dest-queue", "src-queue", 40)
+ self.assertEqual (result.status,0)
+
+ sq = self.qmf.getObjects(_class="queue", name="src-queue")[0]
+ dq = self.qmf.getObjects(_class="queue", name="dest-queue")[0]
+
+ self.assertEqual (sq.msgDepth,20)
+ self.assertEqual (dq.msgDepth,0)
+
+ "Consume the messages of the queue and check they are all there in order"
+ session.message_subscribe(queue="src-queue", destination="tag")
+ session.message_flow(destination="tag", unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination="tag", unit=session.credit_unit.byte, value=0xFFFFFFFFL)
+ queue = session.incoming("tag")
+ for count in twenty:
+ consumed_msg = queue.get(timeout=1)
+ body = "Move Message %d" % count
+ self.assertEqual(body, consumed_msg.body)
+
+ def test_purge_queue(self):
+ """
+ Test ability to purge messages from the head of a queue.
+ Need to test moveing all, 1 (top message) and N messages.
+ """
+ self.startQmf()
+ session = self.session
+ "Set up purge queue"
+ session.queue_declare(queue="purge-queue", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="purge-queue", exchange="amq.direct", binding_key="routing_key")
+
+ twenty = range(1,21)
+ props = session.delivery_properties(routing_key="routing_key")
+ for count in twenty:
+ body = "Purge Message %d" % count
+ msg = Message(props, body)
+ session.message_transfer(destination="amq.direct", message=msg)
+
+ pq = self.qmf.getObjects(_class="queue", name="purge-queue")[0]
+
+ "Purge top message from purge-queue"
+ result = pq.purge(1)
+ self.assertEqual (result.status, 0)
+ pq = self.qmf.getObjects(_class="queue", name="purge-queue")[0]
+ self.assertEqual (pq.msgDepth,19)
+
+ "Purge top 9 messages from purge-queue"
+ result = pq.purge(9)
+ self.assertEqual (result.status, 0)
+ pq = self.qmf.getObjects(_class="queue", name="purge-queue")[0]
+ self.assertEqual (pq.msgDepth,10)
+
+ "Purge all messages from purge-queue"
+ result = pq.purge(0)
+ self.assertEqual (result.status, 0)
+ pq = self.qmf.getObjects(_class="queue", name="purge-queue")[0]
+ self.assertEqual (pq.msgDepth,0)
+
+ def test_methods_async (self):
+ """
+ """
+ class Handler (qmf.console.Console):
+ def __init__(self):
+ self.cv = Condition()
+ self.xmtList = {}
+ self.rcvList = {}
+
+ def methodResponse(self, broker, seq, response):
+ self.cv.acquire()
+ try:
+ self.rcvList[seq] = response
+ finally:
+ self.cv.release()
+
+ def request(self, broker, count):
+ self.count = count
+ for idx in range(count):
+ self.cv.acquire()
+ try:
+ seq = broker.echo(idx, "Echo Message", _async = True)
+ self.xmtList[seq] = idx
+ finally:
+ self.cv.release()
+
+ def check(self):
+ if self.count != len(self.xmtList):
+ return "fail (attempted send=%d, actual sent=%d)" % (self.count, len(self.xmtList))
+ lost = 0
+ mismatched = 0
+ for seq in self.xmtList:
+ value = self.xmtList[seq]
+ if seq in self.rcvList:
+ result = self.rcvList.pop(seq)
+ if result.sequence != value:
+ mismatched += 1
+ else:
+ lost += 1
+ spurious = len(self.rcvList)
+ if lost == 0 and mismatched == 0 and spurious == 0:
+ return "pass"
+ else:
+ return "fail (lost=%d, mismatch=%d, spurious=%d)" % (lost, mismatched, spurious)
+
+ handler = Handler()
+ self.startQmf(handler)
+ brokers = self.qmf.getObjects(_class="broker")
+ self.assertEqual(len(brokers), 1)
+ broker = brokers[0]
+ handler.request(broker, 20)
+ sleep(1)
+ self.assertEqual(handler.check(), "pass")
+
+ def test_connection_close(self):
+ """
+ Test management method for closing connection
+ """
+ self.startQmf()
+ conn = self.connect()
+ session = conn.session("my-named-session")
+
+ #using qmf find named session and close the corresponding connection:
+ qmf_ssn_object = self.qmf.getObjects(_class="session", name="my-named-session")[0]
+ qmf_ssn_object._connectionRef_.close()
+
+ #check that connection is closed
+ try:
+ conn.session("another-session")
+ self.fail("Expected failure from closed connection")
+ except: None
+
+ #make sure that the named session has been closed and the name can be re-used
+ conn = self.connect()
+ session = conn.session("my-named-session")
+ session.queue_declare(queue="whatever", exclusive=True, auto_delete=True)
+
+ def test_binding_count_on_queue(self):
+ self.startQmf()
+ conn = self.connect()
+ session = self.session
+
+ QUEUE = "binding_test_queue"
+ EX_DIR = "binding_test_exchange_direct"
+ EX_FAN = "binding_test_exchange_fanout"
+ EX_TOPIC = "binding_test_exchange_topic"
+ EX_HDR = "binding_test_exchange_headers"
+
+ #
+ # Create a test queue
+ #
+ session.queue_declare(queue=QUEUE, exclusive=True, auto_delete=True)
+ queue = self.qmf.getObjects(_class="queue", name=QUEUE)[0]
+ if not queue:
+ self.fail("Queue not found")
+ self.assertEqual(queue.bindingCount, 1, "wrong initial binding count")
+
+ #
+ # Create an exchange of each supported type
+ #
+ session.exchange_declare(exchange=EX_DIR, type="direct")
+ session.exchange_declare(exchange=EX_FAN, type="fanout")
+ session.exchange_declare(exchange=EX_TOPIC, type="topic")
+ session.exchange_declare(exchange=EX_HDR, type="headers")
+
+ #
+ # Bind each exchange to the test queue
+ #
+ match = {}
+ match['x-match'] = "all"
+ match['key'] = "value"
+ session.exchange_bind(exchange=EX_DIR, queue=QUEUE, binding_key="key1")
+ session.exchange_bind(exchange=EX_DIR, queue=QUEUE, binding_key="key2")
+ session.exchange_bind(exchange=EX_FAN, queue=QUEUE)
+ session.exchange_bind(exchange=EX_TOPIC, queue=QUEUE, binding_key="key1.#")
+ session.exchange_bind(exchange=EX_TOPIC, queue=QUEUE, binding_key="key2.#")
+ session.exchange_bind(exchange=EX_HDR, queue=QUEUE, binding_key="key1", arguments=match)
+ match['key2'] = "value2"
+ session.exchange_bind(exchange=EX_HDR, queue=QUEUE, binding_key="key2", arguments=match)
+
+ #
+ # Verify that the queue's binding count accounts for the new bindings
+ #
+ queue.update()
+ self.assertEqual(queue.bindingCount, 8,
+ "added bindings not accounted for (expected 8, got %d)" % queue.bindingCount)
+
+ #
+ # Remove some of the bindings
+ #
+ session.exchange_unbind(exchange=EX_DIR, queue=QUEUE, binding_key="key2")
+ session.exchange_unbind(exchange=EX_TOPIC, queue=QUEUE, binding_key="key2.#")
+ session.exchange_unbind(exchange=EX_HDR, queue=QUEUE, binding_key="key2")
+
+ #
+ # Verify that the queue's binding count accounts for the deleted bindings
+ #
+ queue.update()
+ self.assertEqual(queue.bindingCount, 5,
+ "deleted bindings not accounted for (expected 5, got %d)" % queue.bindingCount)
+ #
+ # Delete the exchanges
+ #
+ session.exchange_delete(exchange=EX_DIR)
+ session.exchange_delete(exchange=EX_FAN)
+ session.exchange_delete(exchange=EX_TOPIC)
+ session.exchange_delete(exchange=EX_HDR)
+
+ #
+ # Verify that the queue's binding count accounts for the lost bindings
+ #
+ queue.update()
+ self.assertEqual(queue.bindingCount, 1,
+ "deleted bindings not accounted for (expected 1, got %d)" % queue.bindingCount)
+
diff --git a/python/tests_0-10/message.py b/python/tests_0-10/message.py
index e4dc5566bd..e80333a1e6 100644
--- a/python/tests_0-10/message.py
+++ b/python/tests_0-10/message.py
@@ -23,7 +23,7 @@ from qpid.datatypes import Message, RangedSet
from qpid.session import SessionException
from qpid.content import Content
-
+from time import sleep
class MessageTests(TestBase010):
"""Tests for 'methods' on the amqp message 'class'"""
@@ -230,8 +230,8 @@ class MessageTests(TestBase010):
session.message_subscribe(destination="my-consumer", queue="test-queue-4")
myqueue = session.incoming("my-consumer")
- session.message_flow(destination="my-consumer", unit=session.credit_unit.message, value=0xFFFFFFFF)
- session.message_flow(destination="my-consumer", unit=session.credit_unit.byte, value=0xFFFFFFFF)
+ session.message_flow(destination="my-consumer", unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination="my-consumer", unit=session.credit_unit.byte, value=0xFFFFFFFFL)
#should flush here
@@ -258,8 +258,8 @@ class MessageTests(TestBase010):
session.queue_declare(queue="test-ack-queue", auto_delete=True)
session.message_subscribe(queue = "test-ack-queue", destination = "consumer")
- session.message_flow(destination="consumer", unit=session.credit_unit.message, value=0xFFFFFFFF)
- session.message_flow(destination="consumer", unit=session.credit_unit.byte, value=0xFFFFFFFF)
+ session.message_flow(destination="consumer", unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination="consumer", unit=session.credit_unit.byte, value=0xFFFFFFFFL)
queue = session.incoming("consumer")
delivery_properties = session.delivery_properties(routing_key="test-ack-queue")
@@ -289,8 +289,8 @@ class MessageTests(TestBase010):
session.close(timeout=10)
session = self.session
- session.message_flow(destination="checker", unit=session.credit_unit.message, value=0xFFFFFFFF)
- session.message_flow(destination="checker", unit=session.credit_unit.byte, value=0xFFFFFFFF)
+ session.message_flow(destination="checker", unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination="checker", unit=session.credit_unit.byte, value=0xFFFFFFFFL)
queue = session.incoming("checker")
msg3b = queue.get(timeout=1)
@@ -311,16 +311,16 @@ class MessageTests(TestBase010):
session.exchange_bind(queue = "r", exchange = "amq.fanout")
session.message_subscribe(queue = "q", destination = "consumer")
- session.message_flow(destination="consumer", unit=session.credit_unit.message, value=0xFFFFFFFF)
- session.message_flow(destination="consumer", unit=session.credit_unit.byte, value=0xFFFFFFFF)
+ session.message_flow(destination="consumer", unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination="consumer", unit=session.credit_unit.byte, value=0xFFFFFFFFL)
session.message_transfer(message=Message(session.delivery_properties(routing_key="q"), "blah, blah"))
msg = session.incoming("consumer").get(timeout = 1)
self.assertEquals(msg.body, "blah, blah")
session.message_reject(RangedSet(msg.id))
session.message_subscribe(queue = "r", destination = "checker")
- session.message_flow(destination="checker", unit=session.credit_unit.message, value=0xFFFFFFFF)
- session.message_flow(destination="checker", unit=session.credit_unit.byte, value=0xFFFFFFFF)
+ session.message_flow(destination="checker", unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination="checker", unit=session.credit_unit.byte, value=0xFFFFFFFFL)
msg = session.incoming("checker").get(timeout = 1)
self.assertEquals(msg.body, "blah, blah")
@@ -341,7 +341,7 @@ class MessageTests(TestBase010):
#set message credit to finite amount (less than enough for all messages)
session.message_flow(unit = session.credit_unit.message, value = 5, destination = "c")
#set infinite byte credit
- session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFF, destination = "c")
+ session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFFL, destination = "c")
#check that expected number were received
q = session.incoming("c")
for i in range(1, 6):
@@ -369,12 +369,12 @@ class MessageTests(TestBase010):
session.message_transfer(message=Message(session.delivery_properties(routing_key="q"), "abcdefgh"))
#each message is currently interpreted as requiring msg_size bytes of credit
- msg_size = 21
+ msg_size = 19
#set byte credit to finite amount (less than enough for all messages)
session.message_flow(unit = session.credit_unit.byte, value = msg_size*5, destination = "c")
#set infinite message credit
- session.message_flow(unit = session.credit_unit.message, value = 0xFFFFFFFF, destination = "c")
+ session.message_flow(unit = session.credit_unit.message, value = 0xFFFFFFFFL, destination = "c")
#check that expected number were received
q = session.incoming("c")
for i in range(5):
@@ -405,7 +405,7 @@ class MessageTests(TestBase010):
#set message credit to finite amount (less than enough for all messages)
session.message_flow(unit = session.credit_unit.message, value = 5, destination = "c")
#set infinite byte credit
- session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFF, destination = "c")
+ session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFFL, destination = "c")
#check that expected number were received
q = session.incoming("c")
for i in range(1, 6):
@@ -443,7 +443,7 @@ class MessageTests(TestBase010):
#set byte credit to finite amount (less than enough for all messages)
session.message_flow(unit = session.credit_unit.byte, value = msg_size*5, destination = "c")
#set infinite message credit
- session.message_flow(unit = session.credit_unit.message, value = 0xFFFFFFFF, destination = "c")
+ session.message_flow(unit = session.credit_unit.message, value = 0xFFFFFFFFL, destination = "c")
#check that expected number were received
q = session.incoming("c")
msgs = []
@@ -462,6 +462,42 @@ class MessageTests(TestBase010):
self.assertDataEquals(session, q.get(timeout = 1), "abcdefgh")
self.assertEmpty(q)
+ def test_window_flush_ack_flow(self):
+ """
+ Test basic window based flow control with unit = bytes
+ """
+ #declare an exclusive queue
+ ssn = self.session
+ ssn.queue_declare(queue = "q", exclusive=True, auto_delete=True)
+ #create consumer
+ ssn.message_subscribe(queue = "q", destination = "c",
+ accept_mode=ssn.accept_mode.explicit)
+ ssn.message_set_flow_mode(flow_mode = ssn.flow_mode.window, destination = "c")
+
+ #send message A
+ ssn.message_transfer(message=Message(ssn.delivery_properties(routing_key="q"), "A"))
+
+ for unit in ssn.credit_unit.VALUES:
+ ssn.message_flow("c", unit, 0xFFFFFFFFL)
+
+ q = ssn.incoming("c")
+ msgA = q.get(timeout=10)
+
+ ssn.message_flush(destination="c")
+
+ # XXX
+ ssn.receiver._completed.add(msgA.id)
+ ssn.channel.session_completed(ssn.receiver._completed)
+ ssn.message_accept(RangedSet(msgA.id))
+
+ for unit in ssn.credit_unit.VALUES:
+ ssn.message_flow("c", unit, 0xFFFFFFFFL)
+
+ #send message B
+ ssn.message_transfer(message=Message(ssn.delivery_properties(routing_key="q"), "B"))
+
+ msgB = q.get(timeout=10)
+
def test_subscribe_not_acquired(self):
"""
Test the not-acquired modes works as expected for a simple case
@@ -472,11 +508,11 @@ class MessageTests(TestBase010):
session.message_transfer(message=Message(session.delivery_properties(routing_key="q"), "Message %s" % i))
session.message_subscribe(queue = "q", destination = "a", acquire_mode = 1)
- session.message_flow(unit = session.credit_unit.message, value = 0xFFFFFFFF, destination = "a")
- session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFF, destination = "a")
+ session.message_flow(unit = session.credit_unit.message, value = 0xFFFFFFFFL, destination = "a")
+ session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFFL, destination = "a")
session.message_subscribe(queue = "q", destination = "b", acquire_mode = 1)
- session.message_flow(unit = session.credit_unit.message, value = 0xFFFFFFFF, destination = "b")
- session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFF, destination = "b")
+ session.message_flow(unit = session.credit_unit.message, value = 0xFFFFFFFFL, destination = "b")
+ session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFFL, destination = "b")
for i in range(6, 11):
session.message_transfer(message=Message(session.delivery_properties(routing_key="q"), "Message %s" % i))
@@ -508,8 +544,8 @@ class MessageTests(TestBase010):
session.message_subscribe(queue = "q", destination = "a", acquire_mode = 1, accept_mode = 1)
session.message_set_flow_mode(flow_mode = session.flow_mode.credit, destination = "a")
- session.message_flow(unit = session.credit_unit.message, value = 0xFFFFFFFF, destination = "a")
- session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFF, destination = "a")
+ session.message_flow(unit = session.credit_unit.message, value = 0xFFFFFFFFL, destination = "a")
+ session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFFL, destination = "a")
msg = session.incoming("a").get(timeout = 1)
self.assertEquals("acquire me", msg.body)
#message should still be on the queue:
@@ -532,8 +568,8 @@ class MessageTests(TestBase010):
session.message_transfer(message=Message(session.delivery_properties(routing_key="q"), "acquire me"))
session.message_subscribe(queue = "q", destination = "a", acquire_mode = 1)
- session.message_flow(destination="a", unit=session.credit_unit.message, value=0xFFFFFFFF)
- session.message_flow(destination="a", unit=session.credit_unit.byte, value=0xFFFFFFFF)
+ session.message_flow(destination="a", unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination="a", unit=session.credit_unit.byte, value=0xFFFFFFFFL)
msg = session.incoming("a").get(timeout = 1)
self.assertEquals("acquire me", msg.body)
#message should still be on the queue:
@@ -558,8 +594,8 @@ class MessageTests(TestBase010):
session.message_transfer(message=Message(session.delivery_properties(routing_key="q"), "release me"))
session.message_subscribe(queue = "q", destination = "a")
- session.message_flow(destination="a", unit=session.credit_unit.message, value=0xFFFFFFFF)
- session.message_flow(destination="a", unit=session.credit_unit.byte, value=0xFFFFFFFF)
+ session.message_flow(destination="a", unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination="a", unit=session.credit_unit.byte, value=0xFFFFFFFFL)
msg = session.incoming("a").get(timeout = 1)
self.assertEquals("release me", msg.body)
session.message_cancel(destination = "a")
@@ -579,7 +615,7 @@ class MessageTests(TestBase010):
session.message_subscribe(queue = "q", destination = "a")
session.message_flow(unit = session.credit_unit.message, value = 10, destination = "a")
- session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFF, destination = "a")
+ session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFFL, destination = "a")
queue = session.incoming("a")
first = queue.get(timeout = 1)
for i in range(2, 10):
@@ -612,7 +648,7 @@ class MessageTests(TestBase010):
session.message_subscribe(queue = "q", destination = "a")
session.message_flow(unit = session.credit_unit.message, value = 10, destination = "a")
- session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFF, destination = "a")
+ session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFFL, destination = "a")
queue = session.incoming("a")
ids = []
for i in range (1, 11):
@@ -637,8 +673,8 @@ class MessageTests(TestBase010):
session.close(timeout=10)
session = self.session
- session.message_flow(destination="checker", unit=session.credit_unit.message, value=0xFFFFFFFF)
- session.message_flow(destination="checker", unit=session.credit_unit.byte, value=0xFFFFFFFF)
+ session.message_flow(destination="checker", unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination="checker", unit=session.credit_unit.byte, value=0xFFFFFFFFL)
queue = session.incoming("checker")
self.assertEquals("message 4", queue.get(timeout = 1).body)
@@ -656,7 +692,7 @@ class MessageTests(TestBase010):
session.message_subscribe(queue = "q", destination = "a")
session.message_set_flow_mode(flow_mode = 0, destination = "a")
session.message_flow(unit = session.credit_unit.message, value = 5, destination = "a")
- session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFF, destination = "a")
+ session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFFL, destination = "a")
queue = session.incoming("a")
for i in range(1, 6):
@@ -671,7 +707,7 @@ class MessageTests(TestBase010):
#now create a not-acquired subscriber
session.message_subscribe(queue = "q", destination = "b", acquire_mode=1)
- session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFF, destination = "b")
+ session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFFL, destination = "b")
#check it gets those not consumed
queue = session.incoming("b")
@@ -699,7 +735,7 @@ class MessageTests(TestBase010):
#create a not-acquired subscriber
session.message_subscribe(queue = "q", destination = "a", acquire_mode=1)
- session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFF, destination = "a")
+ session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFFL, destination = "a")
session.message_flow(unit = session.credit_unit.message, value = 10, destination = "a")
#browse through messages
@@ -721,7 +757,7 @@ class MessageTests(TestBase010):
#create a second not-acquired subscriber
session.message_subscribe(queue = "q", destination = "b", acquire_mode=1)
- session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFF, destination = "b")
+ session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFFL, destination = "b")
session.message_flow(unit = session.credit_unit.message, value = 1, destination = "b")
#check it gets those not consumed
queue = session.incoming("b")
@@ -748,12 +784,12 @@ class MessageTests(TestBase010):
#create two 'browsers'
session.message_subscribe(queue = "q", destination = "a", acquire_mode=1)
- session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFF, destination = "a")
+ session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFFL, destination = "a")
session.message_flow(unit = session.credit_unit.message, value = 10, destination = "a")
queueA = session.incoming("a")
session.message_subscribe(queue = "q", destination = "b", acquire_mode=1)
- session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFF, destination = "b")
+ session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFFL, destination = "b")
session.message_flow(unit = session.credit_unit.message, value = 10, destination = "b")
queueB = session.incoming("b")
@@ -770,7 +806,7 @@ class MessageTests(TestBase010):
#create consumer
session.message_subscribe(queue = "q", destination = "c")
- session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFF, destination = "c")
+ session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFFL, destination = "c")
session.message_flow(unit = session.credit_unit.message, value = 10, destination = "c")
queueC = session.incoming("c")
#consume the message then ack it
@@ -779,6 +815,41 @@ class MessageTests(TestBase010):
#ensure there are no other messages
self.assertEmpty(queueC)
+ def test_release_order(self):
+ session = self.session
+
+ #create queue
+ session.queue_declare(queue = "q", exclusive=True, auto_delete=True)
+
+ #send messages
+ for i in range(1, 11):
+ session.message_transfer(message=Message(session.delivery_properties(routing_key="q"), "message-%d" % (i)))
+
+ #subscribe:
+ session.message_subscribe(queue="q", destination="a")
+ a = session.incoming("a")
+ session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFFL, destination = "a")
+ session.message_flow(unit = session.credit_unit.message, value = 10, destination = "a")
+
+ for i in range(1, 11):
+ msg = a.get(timeout = 1)
+ self.assertEquals("message-%d" % (i), msg.body)
+ if (i % 2):
+ #accept all odd messages
+ session.message_accept(RangedSet(msg.id))
+ else:
+ #release all even messages
+ session.message_release(RangedSet(msg.id))
+
+ #browse:
+ session.message_subscribe(queue="q", destination="b", acquire_mode=1)
+ b = session.incoming("b")
+ b.start()
+ for i in [2, 4, 6, 8, 10]:
+ msg = b.get(timeout = 1)
+ self.assertEquals("message-%d" % (i), msg.body)
+
+
def test_empty_body(self):
session = self.session
session.queue_declare(queue="xyz", exclusive=True, auto_delete=True)
@@ -787,8 +858,8 @@ class MessageTests(TestBase010):
consumer_tag = "tag1"
session.message_subscribe(queue="xyz", destination=consumer_tag)
- session.message_flow(unit = session.credit_unit.message, value = 0xFFFFFFFF, destination = consumer_tag)
- session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFF, destination = consumer_tag)
+ session.message_flow(unit = session.credit_unit.message, value = 0xFFFFFFFFL, destination = consumer_tag)
+ session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFFL, destination = consumer_tag)
queue = session.incoming(consumer_tag)
msg = queue.get(timeout=1)
self.assertEquals("", msg.body)
@@ -810,6 +881,28 @@ class MessageTests(TestBase010):
msg = messages.get()
assert msg.body == "test"
+ def test_ttl(self):
+ q = "test_ttl"
+ session = self.session
+
+ session.queue_declare(queue=q, exclusive=True, auto_delete=True)
+
+ dp = session.delivery_properties(routing_key=q, ttl=500)#expire in half a second
+ session.message_transfer(message=Message(dp, "first"))
+
+ dp = session.delivery_properties(routing_key=q, ttl=300000)#expire in fives minutes
+ session.message_transfer(message=Message(dp, "second"))
+
+ d = "msgs"
+ session.message_subscribe(queue=q, destination=d)
+ messages = session.incoming(d)
+ sleep(1)
+ session.message_flow(unit = session.credit_unit.message, value=2, destination=d)
+ session.message_flow(unit = session.credit_unit.byte, value=0xFFFFFFFFL, destination=d)
+ assert messages.get(timeout=1).body == "second"
+ self.assertEmpty(messages)
+
+
def assertDataEquals(self, session, msg, expected):
self.assertEquals(expected, msg.body)
diff --git a/python/tests_0-10/persistence.py b/python/tests_0-10/persistence.py
index 815ad1f3dc..e9cf9b7caa 100644
--- a/python/tests_0-10/persistence.py
+++ b/python/tests_0-10/persistence.py
@@ -17,7 +17,8 @@
# under the License.
#
from qpid.datatypes import Message, RangedSet
-from qpid.testlib import testrunner, TestBase010
+#from qpid.testlib import testrunner, TestBase010
+from qpid.testlib import TestBase010
class PersistenceTests(TestBase010):
def test_delete_queue_after_publish(self):
@@ -49,7 +50,7 @@ class PersistenceTests(TestBase010):
#create consumer
session.message_subscribe(queue = "q", destination = "a", accept_mode = 1, acquire_mode=0)
- session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFF, destination = "a")
+ session.message_flow(unit = session.credit_unit.byte, value = 0xFFFFFFFFL, destination = "a")
session.message_flow(unit = session.credit_unit.message, value = 10, destination = "a")
queue = session.incoming("a")
diff --git a/python/tests_0-10/query.py b/python/tests_0-10/query.py
index 311df84096..d57e964982 100644
--- a/python/tests_0-10/query.py
+++ b/python/tests_0-10/query.py
@@ -133,8 +133,20 @@ class QueryTests(TestBase010):
#test exchange not found
self.assertEqual(True, session.exchange_bound(exchange="unknown-exchange").exchange_not_found)
- #test queue not found
- self.assertEqual(True, session.exchange_bound(exchange=exchange_name, queue="unknown-queue").queue_not_found)
+ #test exchange found, queue not found
+ response = session.exchange_bound(exchange=exchange_name, queue="unknown-queue")
+ self.assertEqual(False, response.exchange_not_found)
+ self.assertEqual(True, response.queue_not_found)
+
+ #test exchange not found, queue found
+ response = session.exchange_bound(exchange="unknown-exchange", queue="used-queue")
+ self.assertEqual(True, response.exchange_not_found)
+ self.assertEqual(False, response.queue_not_found)
+
+ #test not exchange found, queue not found
+ response = session.exchange_bound(exchange="unknown-exchange", queue="unknown-queue")
+ self.assertEqual(True, response.exchange_not_found)
+ self.assertEqual(True, response.queue_not_found)
def test_exchange_bound_fanout(self):
diff --git a/python/tests_0-10/queue.py b/python/tests_0-10/queue.py
index a3b23a1c32..eb38965190 100644
--- a/python/tests_0-10/queue.py
+++ b/python/tests_0-10/queue.py
@@ -49,8 +49,8 @@ class QueueTests(TestBase010):
#send a further message and consume it, ensuring that the other messages are really gone
session.message_transfer(message=Message(session.delivery_properties(routing_key="test-queue"), "four"))
session.message_subscribe(queue="test-queue", destination="tag")
- session.message_flow(destination="tag", unit=session.credit_unit.message, value=0xFFFFFFFF)
- session.message_flow(destination="tag", unit=session.credit_unit.byte, value=0xFFFFFFFF)
+ session.message_flow(destination="tag", unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination="tag", unit=session.credit_unit.byte, value=0xFFFFFFFFL)
queue = session.incoming("tag")
msg = queue.get(timeout=1)
self.assertEqual("four", msg.body)
@@ -88,7 +88,7 @@ class QueueTests(TestBase010):
# TestBase.setUp has already opened session(1)
s1 = self.session
# Here we open a second separate connection:
- s2 = self.conn.session("other", 2)
+ s2 = self.conn.session("other")
#declare an exclusive queue:
s1.queue_declare(queue="exclusive-queue", exclusive=True, auto_delete=True)
@@ -98,6 +98,22 @@ class QueueTests(TestBase010):
self.fail("Expected second exclusive queue_declare to raise a channel exception")
except SessionException, e:
self.assertEquals(405, e.args[0].error_code)
+
+ s3 = self.conn.session("subscriber")
+ try:
+ #other connection should not be allowed to declare this:
+ s3.message_subscribe(queue="exclusive-queue")
+ self.fail("Expected message_subscribe on an exclusive queue to raise a channel exception")
+ except SessionException, e:
+ self.assertEquals(405, e.args[0].error_code)
+
+ s4 = self.conn.session("deleter")
+ try:
+ #other connection should not be allowed to declare this:
+ s4.queue_delete(queue="exclusive-queue")
+ self.fail("Expected queue_delete on an exclusive queue to raise a channel exception")
+ except SessionException, e:
+ self.assertEquals(405, e.args[0].error_code)
def test_declare_passive(self):
@@ -166,11 +182,11 @@ class QueueTests(TestBase010):
session.queue_declare(queue="queue-2", exclusive=True, auto_delete=True)
session.message_subscribe(queue="queue-1", destination="queue-1")
- session.message_flow(destination="queue-1", unit=session.credit_unit.message, value=0xFFFFFFFF)
- session.message_flow(destination="queue-1", unit=session.credit_unit.byte, value=0xFFFFFFFF)
+ session.message_flow(destination="queue-1", unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination="queue-1", unit=session.credit_unit.byte, value=0xFFFFFFFFL)
session.message_subscribe(queue="queue-2", destination="queue-2")
- session.message_flow(destination="queue-2", unit=session.credit_unit.message, value=0xFFFFFFFF)
- session.message_flow(destination="queue-2", unit=session.credit_unit.byte, value=0xFFFFFFFF)
+ session.message_flow(destination="queue-2", unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination="queue-2", unit=session.credit_unit.byte, value=0xFFFFFFFFL)
queue1 = session.incoming("queue-1")
queue2 = session.incoming("queue-2")
@@ -267,8 +283,8 @@ class QueueTests(TestBase010):
#empty queue:
session.message_subscribe(destination="consumer_tag", queue="delete-me-2")
- session.message_flow(destination="consumer_tag", unit=session.credit_unit.message, value=0xFFFFFFFF)
- session.message_flow(destination="consumer_tag", unit=session.credit_unit.byte, value=0xFFFFFFFF)
+ session.message_flow(destination="consumer_tag", unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination="consumer_tag", unit=session.credit_unit.byte, value=0xFFFFFFFFL)
queue = session.incoming("consumer_tag")
msg = queue.get(timeout=1)
self.assertEqual("message", msg.body)
diff --git a/python/tests_0-10/tx.py b/python/tests_0-10/tx.py
index da162d54ec..8cdc539a08 100644
--- a/python/tests_0-10/tx.py
+++ b/python/tests_0-10/tx.py
@@ -19,7 +19,7 @@
from qpid.client import Client, Closed
from qpid.queue import Empty
from qpid.datatypes import Message, RangedSet
-from qpid.testlib import testrunner, TestBase010
+from qpid.testlib import TestBase010
class TxTests(TestBase010):
"""
@@ -251,13 +251,13 @@ class TxTests(TestBase010):
session = session or self.session
consumer_tag = keys["destination"]
session.message_subscribe(**keys)
- session.message_flow(destination=consumer_tag, unit=session.credit_unit.message, value=0xFFFFFFFF)
- session.message_flow(destination=consumer_tag, unit=session.credit_unit.byte, value=0xFFFFFFFF)
+ session.message_flow(destination=consumer_tag, unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination=consumer_tag, unit=session.credit_unit.byte, value=0xFFFFFFFFL)
def enable_flow(self, tag, session=None):
session = session or self.session
- session.message_flow(destination=tag, unit=session.credit_unit.message, value=0xFFFFFFFF)
- session.message_flow(destination=tag, unit=session.credit_unit.byte, value=0xFFFFFFFF)
+ session.message_flow(destination=tag, unit=session.credit_unit.message, value=0xFFFFFFFFL)
+ session.message_flow(destination=tag, unit=session.credit_unit.byte, value=0xFFFFFFFFL)
def complete(self, session, msg):
session.receiver._completed.add(msg.id)#TODO: this may be done automatically
diff --git a/python/tests_0-8/__init__.py b/python/tests_0-8/__init__.py
index 9a09d2d04f..526f2452f8 100644
--- a/python/tests_0-8/__init__.py
+++ b/python/tests_0-8/__init__.py
@@ -18,3 +18,5 @@
# specific language governing permissions and limitations
# under the License.
#
+
+import basic, broker, example, exchange, queue, testlib, tx
diff --git a/python/tests_0-8/basic.py b/python/tests_0-8/basic.py
index 95ca0d7287..d5837fc19c 100644
--- a/python/tests_0-8/basic.py
+++ b/python/tests_0-8/basic.py
@@ -19,7 +19,7 @@
from qpid.client import Client, Closed
from qpid.queue import Empty
from qpid.content import Content
-from qpid.testlib import testrunner, TestBase
+from qpid.testlib import TestBase
class BasicTests(TestBase):
"""Tests for 'methods' on the amqp basic 'class'"""
@@ -219,10 +219,11 @@ class BasicTests(TestBase):
channel.basic_ack(delivery_tag=msg4.delivery_tag, multiple=False) #Four
channel.basic_cancel(consumer_tag=subscription.consumer_tag)
- subscription2 = channel.basic_consume(queue="test-requeue")
- queue2 = self.client.queue(subscription2.consumer_tag)
channel.basic_recover(requeue=True)
+
+ subscription2 = channel.basic_consume(queue="test-requeue")
+ queue2 = self.client.queue(subscription2.consumer_tag)
msg3b = queue2.get(timeout=1)
msg5b = queue2.get(timeout=1)
diff --git a/python/tests_0-8/broker.py b/python/tests_0-8/broker.py
index d9ac69c5e3..7f3fe7530e 100644
--- a/python/tests_0-8/broker.py
+++ b/python/tests_0-8/broker.py
@@ -19,15 +19,15 @@
from qpid.client import Closed
from qpid.queue import Empty
from qpid.content import Content
-from qpid.testlib import testrunner, TestBase
+from qpid.testlib import TestBase
class BrokerTests(TestBase):
"""Tests for basic Broker functionality"""
- def test_amqp_basic_13(self):
+ def test_ack_and_no_ack(self):
"""
First, this test tries to receive a message with a no-ack
- consumer. Second, this test tries to explicitely receive and
+ consumer. Second, this test tries to explicitly receive and
acknowledge a message with an acknowledging consumer.
"""
ch = self.channel
@@ -40,7 +40,7 @@ class BrokerTests(TestBase):
msg = self.client.queue(ctag).get(timeout = 5)
self.assert_(msg.content.body == body)
- # Acknowleding consumer
+ # Acknowledging consumer
self.queue_declare(ch, queue = "otherqueue")
ctag = ch.basic_consume(queue = "otherqueue", no_ack = False).consumer_tag
body = "test ack"
@@ -102,3 +102,19 @@ class BrokerTests(TestBase):
except Closed, e:
self.assertConnectionException(504, e.args[0])
+ def test_channel_flow(self):
+ channel = self.channel
+ channel.queue_declare(queue="flow_test_queue", exclusive=True)
+ ctag = channel.basic_consume(queue="flow_test_queue", no_ack=True).consumer_tag
+ incoming = self.client.queue(ctag)
+
+ channel.channel_flow(active=False)
+ channel.basic_publish(routing_key="flow_test_queue", content=Content("abcdefghijklmnopqrstuvwxyz"))
+ try:
+ incoming.get(timeout=1)
+ self.fail("Received message when flow turned off.")
+ except Empty: None
+
+ channel.channel_flow(active=True)
+ msg = incoming.get(timeout=1)
+ self.assertEqual("abcdefghijklmnopqrstuvwxyz", msg.content.body)
diff --git a/python/tests_0-8/example.py b/python/tests_0-8/example.py
index a1949ccb9f..d82bad1f61 100644
--- a/python/tests_0-8/example.py
+++ b/python/tests_0-8/example.py
@@ -18,7 +18,7 @@
#
from qpid.content import Content
-from qpid.testlib import testrunner, TestBase
+from qpid.testlib import TestBase
class ExampleTest (TestBase):
"""
diff --git a/python/tests_0-8/queue.py b/python/tests_0-8/queue.py
index 60ac4c3dfb..b7a41736ab 100644
--- a/python/tests_0-8/queue.py
+++ b/python/tests_0-8/queue.py
@@ -19,7 +19,7 @@
from qpid.client import Client, Closed
from qpid.queue import Empty
from qpid.content import Content
-from qpid.testlib import testrunner, TestBase
+from qpid.testlib import TestBase
class QueueTests(TestBase):
"""Tests for 'methods' on the amqp queue 'class'"""
diff --git a/python/tests_0-8/testlib.py b/python/tests_0-8/testlib.py
index cab07cc4ac..76f7e964a2 100644
--- a/python/tests_0-8/testlib.py
+++ b/python/tests_0-8/testlib.py
@@ -22,7 +22,7 @@
#
from qpid.content import Content
-from qpid.testlib import testrunner, TestBase
+from qpid.testlib import TestBase
from Queue import Empty
import sys
diff --git a/python/tests_0-8/tx.py b/python/tests_0-8/tx.py
index 054fb8d8b7..9faddb1110 100644
--- a/python/tests_0-8/tx.py
+++ b/python/tests_0-8/tx.py
@@ -19,7 +19,7 @@
from qpid.client import Client, Closed
from qpid.queue import Empty
from qpid.content import Content
-from qpid.testlib import testrunner, TestBase
+from qpid.testlib import TestBase
class TxTests(TestBase):
"""
diff --git a/python/tests_0-9/__init__.py b/python/tests_0-9/__init__.py
index 9a09d2d04f..d9f2ed7dbb 100644
--- a/python/tests_0-9/__init__.py
+++ b/python/tests_0-9/__init__.py
@@ -18,3 +18,5 @@
# specific language governing permissions and limitations
# under the License.
#
+
+import query, queue
diff --git a/python/tests_0-9/basic.py b/python/tests_0-9/basic.py
deleted file mode 100644
index 607ba26343..0000000000
--- a/python/tests_0-9/basic.py
+++ /dev/null
@@ -1,396 +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.
-#
-from qpid.client import Client, Closed
-from qpid.queue import Empty
-from qpid.content import Content
-from qpid.testlib import testrunner, TestBase
-
-class BasicTests(TestBase):
- """Tests for 'methods' on the amqp basic 'class'"""
-
- def test_consume_no_local(self):
- """
- Test that the no_local flag is honoured in the consume method
- """
- channel = self.channel
- #setup, declare two queues:
- channel.queue_declare(queue="test-queue-1a", exclusive=True)
- channel.queue_declare(queue="test-queue-1b", exclusive=True)
- #establish two consumers one of which excludes delivery of locally sent messages
- channel.basic_consume(consumer_tag="local_included", queue="test-queue-1a")
- channel.basic_consume(consumer_tag="local_excluded", queue="test-queue-1b", no_local=True)
-
- #send a message
- channel.basic_publish(routing_key="test-queue-1a", content=Content("consume_no_local"))
- channel.basic_publish(routing_key="test-queue-1b", content=Content("consume_no_local"))
-
- #check the queues of the two consumers
- excluded = self.client.queue("local_excluded")
- included = self.client.queue("local_included")
- msg = included.get(timeout=1)
- self.assertEqual("consume_no_local", msg.content.body)
- try:
- excluded.get(timeout=1)
- self.fail("Received locally published message though no_local=true")
- except Empty: None
-
-
- def test_consume_exclusive(self):
- """
- Test that the exclusive flag is honoured in the consume method
- """
- channel = self.channel
- #setup, declare a queue:
- channel.queue_declare(queue="test-queue-2", exclusive=True)
-
- #check that an exclusive consumer prevents other consumer being created:
- channel.basic_consume(consumer_tag="first", queue="test-queue-2", exclusive=True)
- try:
- channel.basic_consume(consumer_tag="second", queue="test-queue-2")
- self.fail("Expected consume request to fail due to previous exclusive consumer")
- except Closed, e:
- self.assertChannelException(403, e.args[0])
-
- #open new channel and cleanup last consumer:
- channel = self.client.channel(2)
- channel.channel_open()
-
- #check that an exclusive consumer cannot be created if a consumer already exists:
- channel.basic_consume(consumer_tag="first", queue="test-queue-2")
- try:
- channel.basic_consume(consumer_tag="second", queue="test-queue-2", exclusive=True)
- self.fail("Expected exclusive consume request to fail due to previous consumer")
- except Closed, e:
- self.assertChannelException(403, e.args[0])
-
- def test_consume_queue_errors(self):
- """
- Test error conditions associated with the queue field of the consume method:
- """
- channel = self.channel
- try:
- #queue specified but doesn't exist:
- channel.basic_consume(queue="invalid-queue")
- self.fail("Expected failure when consuming from non-existent queue")
- except Closed, e:
- self.assertChannelException(404, e.args[0])
-
- channel = self.client.channel(2)
- channel.channel_open()
- try:
- #queue not specified and none previously declared for channel:
- channel.basic_consume(queue="")
- self.fail("Expected failure when consuming from unspecified queue")
- except Closed, e:
- self.assertConnectionException(530, e.args[0])
-
- def test_consume_unique_consumers(self):
- """
- Ensure unique consumer tags are enforced
- """
- channel = self.channel
- #setup, declare a queue:
- channel.queue_declare(queue="test-queue-3", exclusive=True)
-
- #check that attempts to use duplicate tags are detected and prevented:
- channel.basic_consume(consumer_tag="first", queue="test-queue-3")
- try:
- channel.basic_consume(consumer_tag="first", queue="test-queue-3")
- self.fail("Expected consume request to fail due to non-unique tag")
- except Closed, e:
- self.assertConnectionException(530, e.args[0])
-
- def test_cancel(self):
- """
- Test compliance of the basic.cancel method
- """
- channel = self.channel
- #setup, declare a queue:
- channel.queue_declare(queue="test-queue-4", exclusive=True)
- channel.basic_consume(consumer_tag="my-consumer", queue="test-queue-4")
- channel.basic_publish(routing_key="test-queue-4", content=Content("One"))
-
- myqueue = self.client.queue("my-consumer")
- msg = myqueue.get(timeout=1)
- self.assertEqual("One", msg.content.body)
-
- #cancel should stop messages being delivered
- channel.basic_cancel(consumer_tag="my-consumer")
- channel.basic_publish(routing_key="test-queue-4", content=Content("Two"))
- try:
- msg = myqueue.get(timeout=1)
- self.fail("Got message after cancellation: " + msg)
- except Empty: None
-
- #cancellation of non-existant consumers should be handled without error
- channel.basic_cancel(consumer_tag="my-consumer")
- channel.basic_cancel(consumer_tag="this-never-existed")
-
-
- def test_ack(self):
- """
- Test basic ack/recover behaviour
- """
- channel = self.channel
- channel.queue_declare(queue="test-ack-queue", exclusive=True)
-
- reply = channel.basic_consume(queue="test-ack-queue", no_ack=False)
- queue = self.client.queue(reply.consumer_tag)
-
- channel.basic_publish(routing_key="test-ack-queue", content=Content("One"))
- channel.basic_publish(routing_key="test-ack-queue", content=Content("Two"))
- channel.basic_publish(routing_key="test-ack-queue", content=Content("Three"))
- channel.basic_publish(routing_key="test-ack-queue", content=Content("Four"))
- channel.basic_publish(routing_key="test-ack-queue", content=Content("Five"))
-
- msg1 = queue.get(timeout=1)
- msg2 = queue.get(timeout=1)
- msg3 = queue.get(timeout=1)
- msg4 = queue.get(timeout=1)
- msg5 = queue.get(timeout=1)
-
- self.assertEqual("One", msg1.content.body)
- self.assertEqual("Two", msg2.content.body)
- self.assertEqual("Three", msg3.content.body)
- self.assertEqual("Four", msg4.content.body)
- self.assertEqual("Five", msg5.content.body)
-
- channel.basic_ack(delivery_tag=msg2.delivery_tag, multiple=True) #One & Two
- channel.basic_ack(delivery_tag=msg4.delivery_tag, multiple=False) #Four
-
- channel.basic_recover(requeue=False)
-
- msg3b = queue.get(timeout=1)
- msg5b = queue.get(timeout=1)
-
- self.assertEqual("Three", msg3b.content.body)
- self.assertEqual("Five", msg5b.content.body)
-
- try:
- extra = queue.get(timeout=1)
- self.fail("Got unexpected message: " + extra.content.body)
- except Empty: None
-
- def test_recover_requeue(self):
- """
- Test requeing on recovery
- """
- channel = self.channel
- channel.queue_declare(queue="test-requeue", exclusive=True)
-
- subscription = channel.basic_consume(queue="test-requeue", no_ack=False)
- queue = self.client.queue(subscription.consumer_tag)
-
- channel.basic_publish(routing_key="test-requeue", content=Content("One"))
- channel.basic_publish(routing_key="test-requeue", content=Content("Two"))
- channel.basic_publish(routing_key="test-requeue", content=Content("Three"))
- channel.basic_publish(routing_key="test-requeue", content=Content("Four"))
- channel.basic_publish(routing_key="test-requeue", content=Content("Five"))
-
- msg1 = queue.get(timeout=1)
- msg2 = queue.get(timeout=1)
- msg3 = queue.get(timeout=1)
- msg4 = queue.get(timeout=1)
- msg5 = queue.get(timeout=1)
-
- self.assertEqual("One", msg1.content.body)
- self.assertEqual("Two", msg2.content.body)
- self.assertEqual("Three", msg3.content.body)
- self.assertEqual("Four", msg4.content.body)
- self.assertEqual("Five", msg5.content.body)
-
- channel.basic_ack(delivery_tag=msg2.delivery_tag, multiple=True) #One & Two
- channel.basic_ack(delivery_tag=msg4.delivery_tag, multiple=False) #Four
-
- channel.basic_cancel(consumer_tag=subscription.consumer_tag)
-
- channel.basic_recover(requeue=True)
-
- subscription2 = channel.basic_consume(queue="test-requeue")
- queue2 = self.client.queue(subscription2.consumer_tag)
-
- msg3b = queue2.get(timeout=1)
- msg5b = queue2.get(timeout=1)
-
- self.assertEqual("Three", msg3b.content.body)
- self.assertEqual("Five", msg5b.content.body)
-
- self.assertEqual(True, msg3b.redelivered)
- self.assertEqual(True, msg5b.redelivered)
-
- try:
- extra = queue2.get(timeout=1)
- self.fail("Got unexpected message in second queue: " + extra.content.body)
- except Empty: None
- try:
- extra = queue.get(timeout=1)
- self.fail("Got unexpected message in original queue: " + extra.content.body)
- except Empty: None
-
-
- def test_qos_prefetch_count(self):
- """
- Test that the prefetch count specified is honoured
- """
- #setup: declare queue and subscribe
- channel = self.channel
- channel.queue_declare(queue="test-prefetch-count", exclusive=True)
- subscription = channel.basic_consume(queue="test-prefetch-count", no_ack=False)
- queue = self.client.queue(subscription.consumer_tag)
-
- #set prefetch to 5:
- channel.basic_qos(prefetch_count=5)
-
- #publish 10 messages:
- for i in range(1, 11):
- channel.basic_publish(routing_key="test-prefetch-count", content=Content("Message %d" % i))
-
- #only 5 messages should have been delivered:
- for i in range(1, 6):
- msg = queue.get(timeout=1)
- self.assertEqual("Message %d" % i, msg.content.body)
- try:
- extra = queue.get(timeout=1)
- self.fail("Got unexpected 6th message in original queue: " + extra.content.body)
- except Empty: None
-
- #ack messages and check that the next set arrive ok:
- channel.basic_ack(delivery_tag=msg.delivery_tag, multiple=True)
-
- for i in range(6, 11):
- msg = queue.get(timeout=1)
- self.assertEqual("Message %d" % i, msg.content.body)
-
- channel.basic_ack(delivery_tag=msg.delivery_tag, multiple=True)
-
- try:
- extra = queue.get(timeout=1)
- self.fail("Got unexpected 11th message in original queue: " + extra.content.body)
- except Empty: None
-
-
-
- def test_qos_prefetch_size(self):
- """
- Test that the prefetch size specified is honoured
- """
- #setup: declare queue and subscribe
- channel = self.channel
- channel.queue_declare(queue="test-prefetch-size", exclusive=True)
- subscription = channel.basic_consume(queue="test-prefetch-size", no_ack=False)
- queue = self.client.queue(subscription.consumer_tag)
-
- #set prefetch to 50 bytes (each message is 9 or 10 bytes):
- channel.basic_qos(prefetch_size=50)
-
- #publish 10 messages:
- for i in range(1, 11):
- channel.basic_publish(routing_key="test-prefetch-size", content=Content("Message %d" % i))
-
- #only 5 messages should have been delivered (i.e. 45 bytes worth):
- for i in range(1, 6):
- msg = queue.get(timeout=1)
- self.assertEqual("Message %d" % i, msg.content.body)
-
- try:
- extra = queue.get(timeout=1)
- self.fail("Got unexpected 6th message in original queue: " + extra.content.body)
- except Empty: None
-
- #ack messages and check that the next set arrive ok:
- channel.basic_ack(delivery_tag=msg.delivery_tag, multiple=True)
-
- for i in range(6, 11):
- msg = queue.get(timeout=1)
- self.assertEqual("Message %d" % i, msg.content.body)
-
- channel.basic_ack(delivery_tag=msg.delivery_tag, multiple=True)
-
- try:
- extra = queue.get(timeout=1)
- self.fail("Got unexpected 11th message in original queue: " + extra.content.body)
- except Empty: None
-
- #make sure that a single oversized message still gets delivered
- large = "abcdefghijklmnopqrstuvwxyz"
- large = large + "-" + large;
- channel.basic_publish(routing_key="test-prefetch-size", content=Content(large))
- msg = queue.get(timeout=1)
- self.assertEqual(large, msg.content.body)
-
- def test_get(self):
- """
- Test basic_get method
- """
- channel = self.channel
- channel.queue_declare(queue="test-get", exclusive=True)
-
- #publish some messages (no_ack=True)
- for i in range(1, 11):
- channel.basic_publish(routing_key="test-get", content=Content("Message %d" % i))
-
- #use basic_get to read back the messages, and check that we get an empty at the end
- for i in range(1, 11):
- reply = channel.basic_get(no_ack=True)
- self.assertEqual(reply.method.klass.name, "basic")
- self.assertEqual(reply.method.name, "get_ok")
- self.assertEqual("Message %d" % i, reply.content.body)
-
- reply = channel.basic_get(no_ack=True)
- self.assertEqual(reply.method.klass.name, "basic")
- self.assertEqual(reply.method.name, "get_empty")
-
- #repeat for no_ack=False
- for i in range(11, 21):
- channel.basic_publish(routing_key="test-get", content=Content("Message %d" % i))
-
- for i in range(11, 21):
- reply = channel.basic_get(no_ack=False)
- self.assertEqual(reply.method.klass.name, "basic")
- self.assertEqual(reply.method.name, "get_ok")
- self.assertEqual("Message %d" % i, reply.content.body)
- if(i == 13):
- channel.basic_ack(delivery_tag=reply.delivery_tag, multiple=True)
- if(i in [15, 17, 19]):
- channel.basic_ack(delivery_tag=reply.delivery_tag)
-
- reply = channel.basic_get(no_ack=True)
- self.assertEqual(reply.method.klass.name, "basic")
- self.assertEqual(reply.method.name, "get_empty")
-
- #recover(requeue=True)
- channel.basic_recover(requeue=True)
-
- #get the unacked messages again (14, 16, 18, 20)
- for i in [14, 16, 18, 20]:
- reply = channel.basic_get(no_ack=False)
- self.assertEqual(reply.method.klass.name, "basic")
- self.assertEqual(reply.method.name, "get_ok")
- self.assertEqual("Message %d" % i, reply.content.body)
- channel.basic_ack(delivery_tag=reply.delivery_tag)
-
- reply = channel.basic_get(no_ack=True)
- self.assertEqual(reply.method.klass.name, "basic")
- self.assertEqual(reply.method.name, "get_empty")
-
- channel.basic_recover(requeue=True)
-
- reply = channel.basic_get(no_ack=True)
- self.assertEqual(reply.method.klass.name, "basic")
- self.assertEqual(reply.method.name, "get_empty")
diff --git a/python/tests_0-9/broker.py b/python/tests_0-9/broker.py
deleted file mode 100644
index 03b4132d3e..0000000000
--- a/python/tests_0-9/broker.py
+++ /dev/null
@@ -1,133 +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.
-#
-from qpid.client import Closed
-from qpid.queue import Empty
-from qpid.content import Content
-from qpid.testlib import testrunner, TestBase
-
-class BrokerTests(TestBase):
- """Tests for basic Broker functionality"""
-
- def test_ack_and_no_ack(self):
- """
- First, this test tries to receive a message with a no-ack
- consumer. Second, this test tries to explicitly receive and
- acknowledge a message with an acknowledging consumer.
- """
- ch = self.channel
- self.queue_declare(ch, queue = "myqueue")
-
- # No ack consumer
- ctag = "tag1"
- ch.message_consume(queue = "myqueue", destination = ctag, no_ack = True)
- body = "test no-ack"
- ch.message_transfer(routing_key = "myqueue", body = body)
- msg = self.client.queue(ctag).get(timeout = 5)
- self.assert_(msg.body == body)
-
- # Acknowledging consumer
- self.queue_declare(ch, queue = "otherqueue")
- ctag = "tag2"
- ch.message_consume(queue = "otherqueue", destination = ctag, no_ack = False)
- body = "test ack"
- ch.message_transfer(routing_key = "otherqueue", body = body)
- msg = self.client.queue(ctag).get(timeout = 5)
- msg.ok()
- self.assert_(msg.body == body)
-
- def test_simple_delivery_immediate(self):
- """
- Test simple message delivery where consume is issued before publish
- """
- channel = self.channel
- self.exchange_declare(channel, exchange="test-exchange", type="direct")
- self.queue_declare(channel, queue="test-queue")
- channel.queue_bind(queue="test-queue", exchange="test-exchange", routing_key="key")
- consumer_tag = "tag1"
- channel.message_consume(queue="test-queue", destination=consumer_tag, no_ack=True)
- queue = self.client.queue(consumer_tag)
-
- body = "Immediate Delivery"
- channel.message_transfer(destination="test-exchange", routing_key="key", body=body, immediate=True)
- msg = queue.get(timeout=5)
- self.assert_(msg.body == body)
-
- # TODO: Ensure we fail if immediate=True and there's no consumer.
-
-
- def test_simple_delivery_queued(self):
- """
- Test basic message delivery where publish is issued before consume
- (i.e. requires queueing of the message)
- """
- channel = self.channel
- self.exchange_declare(channel, exchange="test-exchange", type="direct")
- self.queue_declare(channel, queue="test-queue")
- channel.queue_bind(queue="test-queue", exchange="test-exchange", routing_key="key")
- body = "Queued Delivery"
- channel.message_transfer(destination="test-exchange", routing_key="key", body=body)
-
- consumer_tag = "tag1"
- channel.message_consume(queue="test-queue", destination=consumer_tag, no_ack=True)
- queue = self.client.queue(consumer_tag)
- msg = queue.get(timeout=5)
- self.assert_(msg.body == body)
-
- def test_invalid_channel(self):
- channel = self.client.channel(200)
- try:
- channel.queue_declare(exclusive=True)
- self.fail("Expected error on queue_declare for invalid channel")
- except Closed, e:
- self.assertConnectionException(504, e.args[0])
-
- def test_closed_channel(self):
- channel = self.client.channel(200)
- channel.channel_open()
- channel.channel_close()
- try:
- channel.queue_declare(exclusive=True)
- self.fail("Expected error on queue_declare for closed channel")
- except Closed, e:
- if isinstance(e.args[0], str): self.fail(e)
- self.assertConnectionException(504, e.args[0])
-
- def test_ping_pong(self):
- channel = self.channel
- reply = channel.channel_ping()
- self.assertEqual(reply.method.klass.name, "channel")
- self.assertEqual(reply.method.name, "ok")
- #todo: provide a way to get notified of incoming pongs...
-
- def test_channel_flow(self):
- channel = self.channel
- channel.queue_declare(queue="flow_test_queue", exclusive=True)
- channel.message_consume(destination="my-tag", queue="flow_test_queue")
- incoming = self.client.queue("my-tag")
-
- channel.channel_flow(active=False)
- channel.message_transfer(routing_key="flow_test_queue", body="abcdefghijklmnopqrstuvwxyz")
- try:
- incoming.get(timeout=1)
- self.fail("Received message when flow turned off.")
- except Empty: None
-
- channel.channel_flow(active=True)
- msg = incoming.get(timeout=1)
- self.assertEqual("abcdefghijklmnopqrstuvwxyz", msg.body)
diff --git a/python/tests_0-9/dtx.py b/python/tests_0-9/dtx.py
deleted file mode 100644
index bc268f4129..0000000000
--- a/python/tests_0-9/dtx.py
+++ /dev/null
@@ -1,587 +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.
-#
-from qpid.client import Client, Closed
-from qpid.queue import Empty
-from qpid.content import Content
-from qpid.testlib import testrunner, TestBase
-from struct import pack, unpack
-from time import sleep
-
-class DtxTests(TestBase):
- """
- Tests for the amqp dtx related classes.
-
- Tests of the form test_simple_xxx test the basic transactional
- behaviour. The approach here is to 'swap' a message from one queue
- to another by consuming and re-publishing in the same
- transaction. That transaction is then completed in different ways
- and the appropriate result verified.
-
- The other tests enforce more specific rules and behaviour on a
- per-method or per-field basis.
- """
-
- XA_RBROLLBACK = 1
- XA_RBTIMEOUT = 2
- XA_OK = 8
-
- def test_simple_commit(self):
- """
- Test basic one-phase commit behaviour.
- """
- channel = self.channel
- tx = self.xid("my-xid")
- self.txswap(tx, "commit")
-
- #neither queue should have any messages accessible
- self.assertMessageCount(0, "queue-a")
- self.assertMessageCount(0, "queue-b")
-
- #commit
- self.assertEqual(self.XA_OK, channel.dtx_coordination_commit(xid=tx, one_phase=True).flags)
-
- #check result
- self.assertMessageCount(0, "queue-a")
- self.assertMessageCount(1, "queue-b")
- self.assertMessageId("commit", "queue-b")
-
- def test_simple_prepare_commit(self):
- """
- Test basic two-phase commit behaviour.
- """
- channel = self.channel
- tx = self.xid("my-xid")
- self.txswap(tx, "prepare-commit")
-
- #prepare
- self.assertEqual(self.XA_OK, channel.dtx_coordination_prepare(xid=tx).flags)
-
- #neither queue should have any messages accessible
- self.assertMessageCount(0, "queue-a")
- self.assertMessageCount(0, "queue-b")
-
- #commit
- self.assertEqual(self.XA_OK, channel.dtx_coordination_commit(xid=tx, one_phase=False).flags)
-
- #check result
- self.assertMessageCount(0, "queue-a")
- self.assertMessageCount(1, "queue-b")
- self.assertMessageId("prepare-commit", "queue-b")
-
-
- def test_simple_rollback(self):
- """
- Test basic rollback behaviour.
- """
- channel = self.channel
- tx = self.xid("my-xid")
- self.txswap(tx, "rollback")
-
- #neither queue should have any messages accessible
- self.assertMessageCount(0, "queue-a")
- self.assertMessageCount(0, "queue-b")
-
- #rollback
- self.assertEqual(self.XA_OK, channel.dtx_coordination_rollback(xid=tx).flags)
-
- #check result
- self.assertMessageCount(1, "queue-a")
- self.assertMessageCount(0, "queue-b")
- self.assertMessageId("rollback", "queue-a")
-
- def test_simple_prepare_rollback(self):
- """
- Test basic rollback behaviour after the transaction has been prepared.
- """
- channel = self.channel
- tx = self.xid("my-xid")
- self.txswap(tx, "prepare-rollback")
-
- #prepare
- self.assertEqual(self.XA_OK, channel.dtx_coordination_prepare(xid=tx).flags)
-
- #neither queue should have any messages accessible
- self.assertMessageCount(0, "queue-a")
- self.assertMessageCount(0, "queue-b")
-
- #rollback
- self.assertEqual(self.XA_OK, channel.dtx_coordination_rollback(xid=tx).flags)
-
- #check result
- self.assertMessageCount(1, "queue-a")
- self.assertMessageCount(0, "queue-b")
- self.assertMessageId("prepare-rollback", "queue-a")
-
- def test_select_required(self):
- """
- check that an error is flagged if select is not issued before
- start or end
- """
- channel = self.channel
- tx = self.xid("dummy")
- try:
- channel.dtx_demarcation_start(xid=tx)
-
- #if we get here we have failed, but need to do some cleanup:
- channel.dtx_demarcation_end(xid=tx)
- channel.dtx_coordination_rollback(xid=tx)
- self.fail("Channel not selected for use with dtx, expected exception!")
- except Closed, e:
- self.assertConnectionException(503, e.args[0])
-
- def test_start_already_known(self):
- """
- Verify that an attempt to start an association with a
- transaction that is already known is not allowed (unless the
- join flag is set).
- """
- #create two channels on different connection & select them for use with dtx:
- channel1 = self.channel
- channel1.dtx_demarcation_select()
-
- other = self.connect()
- channel2 = other.channel(1)
- channel2.channel_open()
- channel2.dtx_demarcation_select()
-
- #create a xid
- tx = self.xid("dummy")
- #start work on one channel under that xid:
- channel1.dtx_demarcation_start(xid=tx)
- #then start on the other without the join set
- failed = False
- try:
- channel2.dtx_demarcation_start(xid=tx)
- except Closed, e:
- failed = True
- error = e
-
- #cleanup:
- if not failed:
- channel2.dtx_demarcation_end(xid=tx)
- other.close()
- channel1.dtx_demarcation_end(xid=tx)
- channel1.dtx_coordination_rollback(xid=tx)
-
- #verification:
- if failed: self.assertConnectionException(503, e.args[0])
- else: self.fail("Xid already known, expected exception!")
-
- def test_forget_xid_on_completion(self):
- """
- Verify that a xid is 'forgotten' - and can therefore be used
- again - once it is completed.
- """
- channel = self.channel
- #do some transactional work & complete the transaction
- self.test_simple_commit()
-
- #start association for the same xid as the previously completed txn
- tx = self.xid("my-xid")
- channel.dtx_demarcation_start(xid=tx)
- channel.dtx_demarcation_end(xid=tx)
- channel.dtx_coordination_rollback(xid=tx)
-
- def test_start_join_and_resume(self):
- """
- Ensure the correct error is signalled when both the join and
- resume flags are set on starting an association between a
- channel and a transcation.
- """
- channel = self.channel
- channel.dtx_demarcation_select()
- tx = self.xid("dummy")
- try:
- channel.dtx_demarcation_start(xid=tx, join=True, resume=True)
- #failed, but need some cleanup:
- channel.dtx_demarcation_end(xid=tx)
- channel.dtx_coordination_rollback(xid=tx)
- self.fail("Join and resume both set, expected exception!")
- except Closed, e:
- self.assertConnectionException(503, e.args[0])
-
- def test_start_join(self):
- """
- Verify 'join' behaviour, where a channel is associated with a
- transaction that is already associated with another channel.
- """
- #create two channels & select them for use with dtx:
- channel1 = self.channel
- channel1.dtx_demarcation_select()
-
- channel2 = self.client.channel(2)
- channel2.channel_open()
- channel2.dtx_demarcation_select()
-
- #setup
- channel1.queue_declare(queue="one", exclusive=True)
- channel1.queue_declare(queue="two", exclusive=True)
- channel1.message_transfer(routing_key="one", message_id="a", body="DtxMessage")
- channel1.message_transfer(routing_key="two", message_id="b", body="DtxMessage")
-
- #create a xid
- tx = self.xid("dummy")
- #start work on one channel under that xid:
- channel1.dtx_demarcation_start(xid=tx)
- #then start on the other with the join flag set
- channel2.dtx_demarcation_start(xid=tx, join=True)
-
- #do work through each channel
- self.swap(channel1, "one", "two")#swap 'a' from 'one' to 'two'
- self.swap(channel2, "two", "one")#swap 'b' from 'two' to 'one'
-
- #mark end on both channels
- channel1.dtx_demarcation_end(xid=tx)
- channel2.dtx_demarcation_end(xid=tx)
-
- #commit and check
- channel1.dtx_coordination_commit(xid=tx, one_phase=True)
- self.assertMessageCount(1, "one")
- self.assertMessageCount(1, "two")
- self.assertMessageId("a", "two")
- self.assertMessageId("b", "one")
-
-
- def test_suspend_resume(self):
- """
- Test suspension and resumption of an association
- """
- channel = self.channel
- channel.dtx_demarcation_select()
-
- #setup
- channel.queue_declare(queue="one", exclusive=True)
- channel.queue_declare(queue="two", exclusive=True)
- channel.message_transfer(routing_key="one", message_id="a", body="DtxMessage")
- channel.message_transfer(routing_key="two", message_id="b", body="DtxMessage")
-
- tx = self.xid("dummy")
-
- channel.dtx_demarcation_start(xid=tx)
- self.swap(channel, "one", "two")#swap 'a' from 'one' to 'two'
- channel.dtx_demarcation_end(xid=tx, suspend=True)
-
- channel.dtx_demarcation_start(xid=tx, resume=True)
- self.swap(channel, "two", "one")#swap 'b' from 'two' to 'one'
- channel.dtx_demarcation_end(xid=tx)
-
- #commit and check
- channel.dtx_coordination_commit(xid=tx, one_phase=True)
- self.assertMessageCount(1, "one")
- self.assertMessageCount(1, "two")
- self.assertMessageId("a", "two")
- self.assertMessageId("b", "one")
-
- def test_end_suspend_and_fail(self):
- """
- Verify that the correct error is signalled if the suspend and
- fail flag are both set when disassociating a transaction from
- the channel
- """
- channel = self.channel
- channel.dtx_demarcation_select()
- tx = self.xid("suspend_and_fail")
- channel.dtx_demarcation_start(xid=tx)
- try:
- channel.dtx_demarcation_end(xid=tx, suspend=True, fail=True)
- self.fail("Suspend and fail both set, expected exception!")
- except Closed, e:
- self.assertConnectionException(503, e.args[0])
-
- #cleanup
- other = self.connect()
- channel = other.channel(1)
- channel.channel_open()
- channel.dtx_coordination_rollback(xid=tx)
- channel.channel_close()
- other.close()
-
-
- def test_end_unknown_xid(self):
- """
- Verifies that the correct exception is thrown when an attempt
- is made to end the association for a xid not previously
- associated with the channel
- """
- channel = self.channel
- channel.dtx_demarcation_select()
- tx = self.xid("unknown-xid")
- try:
- channel.dtx_demarcation_end(xid=tx)
- self.fail("Attempted to end association with unknown xid, expected exception!")
- except Closed, e:
- #FYI: this is currently *not* the exception specified, but I think the spec is wrong! Confirming...
- self.assertConnectionException(503, e.args[0])
-
- def test_end(self):
- """
- Verify that the association is terminated by end and subsequent
- operations are non-transactional
- """
- channel = self.client.channel(2)
- channel.channel_open()
- channel.queue_declare(queue="tx-queue", exclusive=True)
-
- #publish a message under a transaction
- channel.dtx_demarcation_select()
- tx = self.xid("dummy")
- channel.dtx_demarcation_start(xid=tx)
- channel.message_transfer(routing_key="tx-queue", message_id="one", body="DtxMessage")
- channel.dtx_demarcation_end(xid=tx)
-
- #now that association with txn is ended, publish another message
- channel.message_transfer(routing_key="tx-queue", message_id="two", body="DtxMessage")
-
- #check the second message is available, but not the first
- self.assertMessageCount(1, "tx-queue")
- channel.message_consume(queue="tx-queue", destination="results", no_ack=False)
- msg = self.client.queue("results").get(timeout=1)
- self.assertEqual("two", msg.message_id)
- channel.message_cancel(destination="results")
- #ack the message then close the channel
- msg.ok()
- channel.channel_close()
-
- channel = self.channel
- #commit the transaction and check that the first message (and
- #only the first message) is then delivered
- channel.dtx_coordination_commit(xid=tx, one_phase=True)
- self.assertMessageCount(1, "tx-queue")
- self.assertMessageId("one", "tx-queue")
-
- def test_invalid_commit_one_phase_true(self):
- """
- Test that a commit with one_phase = True is rejected if the
- transaction in question has already been prepared.
- """
- other = self.connect()
- tester = other.channel(1)
- tester.channel_open()
- tester.queue_declare(queue="dummy", exclusive=True)
- tester.dtx_demarcation_select()
- tx = self.xid("dummy")
- tester.dtx_demarcation_start(xid=tx)
- tester.message_transfer(routing_key="dummy", body="whatever")
- tester.dtx_demarcation_end(xid=tx)
- tester.dtx_coordination_prepare(xid=tx)
- failed = False
- try:
- tester.dtx_coordination_commit(xid=tx, one_phase=True)
- except Closed, e:
- failed = True
- error = e
-
- if failed:
- self.channel.dtx_coordination_rollback(xid=tx)
- self.assertConnectionException(503, e.args[0])
- else:
- tester.channel_close()
- other.close()
- self.fail("Invalid use of one_phase=True, expected exception!")
-
- def test_invalid_commit_one_phase_false(self):
- """
- Test that a commit with one_phase = False is rejected if the
- transaction in question has not yet been prepared.
- """
- """
- Test that a commit with one_phase = True is rejected if the
- transaction in question has already been prepared.
- """
- other = self.connect()
- tester = other.channel(1)
- tester.channel_open()
- tester.queue_declare(queue="dummy", exclusive=True)
- tester.dtx_demarcation_select()
- tx = self.xid("dummy")
- tester.dtx_demarcation_start(xid=tx)
- tester.message_transfer(routing_key="dummy", body="whatever")
- tester.dtx_demarcation_end(xid=tx)
- failed = False
- try:
- tester.dtx_coordination_commit(xid=tx, one_phase=False)
- except Closed, e:
- failed = True
- error = e
-
- if failed:
- self.channel.dtx_coordination_rollback(xid=tx)
- self.assertConnectionException(503, e.args[0])
- else:
- tester.channel_close()
- other.close()
- self.fail("Invalid use of one_phase=False, expected exception!")
-
- def test_implicit_end(self):
- """
- Test that an association is implicitly ended when the channel
- is closed (whether by exception or explicit client request)
- and the transaction in question is marked as rollback only.
- """
- channel1 = self.channel
- channel2 = self.client.channel(2)
- channel2.channel_open()
-
- #setup:
- channel2.queue_declare(queue="dummy", exclusive=True)
- channel2.message_transfer(routing_key="dummy", body="whatever")
- tx = self.xid("dummy")
-
- channel2.dtx_demarcation_select()
- channel2.dtx_demarcation_start(xid=tx)
- channel2.message_get(queue="dummy", destination="dummy")
- self.client.queue("dummy").get(timeout=1).ok()
- channel2.message_transfer(routing_key="dummy", body="whatever")
- channel2.channel_close()
-
- self.assertEqual(self.XA_RBROLLBACK, channel1.dtx_coordination_prepare(xid=tx).flags)
- channel1.dtx_coordination_rollback(xid=tx)
-
- def test_get_timeout(self):
- """
- Check that get-timeout returns the correct value, (and that a
- transaction with a timeout can complete normally)
- """
- channel = self.channel
- tx = self.xid("dummy")
-
- channel.dtx_demarcation_select()
- channel.dtx_demarcation_start(xid=tx)
- self.assertEqual(0, channel.dtx_coordination_get_timeout(xid=tx).timeout)
- channel.dtx_coordination_set_timeout(xid=tx, timeout=60)
- self.assertEqual(60, channel.dtx_coordination_get_timeout(xid=tx).timeout)
- self.assertEqual(self.XA_OK, channel.dtx_demarcation_end(xid=tx).flags)
- self.assertEqual(self.XA_OK, channel.dtx_coordination_rollback(xid=tx).flags)
-
- def test_set_timeout(self):
- """
- Test the timeout of a transaction results in the expected
- behaviour
- """
- #open new channel to allow self.channel to be used in checking te queue
- channel = self.client.channel(2)
- channel.channel_open()
- #setup:
- tx = self.xid("dummy")
- channel.queue_declare(queue="queue-a", exclusive=True)
- channel.queue_declare(queue="queue-b", exclusive=True)
- channel.message_transfer(routing_key="queue-a", message_id="timeout", body="DtxMessage")
-
- channel.dtx_demarcation_select()
- channel.dtx_demarcation_start(xid=tx)
- self.swap(channel, "queue-a", "queue-b")
- channel.dtx_coordination_set_timeout(xid=tx, timeout=2)
- sleep(3)
- #check that the work has been rolled back already
- self.assertMessageCount(1, "queue-a")
- self.assertMessageCount(0, "queue-b")
- self.assertMessageId("timeout", "queue-a")
- #check the correct codes are returned when we try to complete the txn
- self.assertEqual(self.XA_RBTIMEOUT, channel.dtx_demarcation_end(xid=tx).flags)
- self.assertEqual(self.XA_RBTIMEOUT, channel.dtx_coordination_rollback(xid=tx).flags)
-
-
-
- def test_recover(self):
- """
- Test basic recover behaviour
- """
- channel = self.channel
-
- channel.dtx_demarcation_select()
- channel.queue_declare(queue="dummy", exclusive=True)
-
- prepared = []
- for i in range(1, 10):
- tx = self.xid("tx%s" % (i))
- channel.dtx_demarcation_start(xid=tx)
- channel.message_transfer(routing_key="dummy", body="message%s" % (i))
- channel.dtx_demarcation_end(xid=tx)
- if i in [2, 5, 6, 8]:
- channel.dtx_coordination_prepare(xid=tx)
- prepared.append(tx)
- else:
- channel.dtx_coordination_rollback(xid=tx)
-
- indoubt = channel.dtx_coordination_recover().xids
- #convert indoubt table to a list of xids (note: this will change for 0-10)
- data = indoubt["xids"]
- xids = []
- pos = 0
- while pos < len(data):
- size = unpack("!B", data[pos])[0]
- start = pos + 1
- end = start + size
- xid = data[start:end]
- xids.append(xid)
- pos = end
-
- #rollback the prepared transactions returned by recover
- for x in xids:
- channel.dtx_coordination_rollback(xid=x)
-
- #validate against the expected list of prepared transactions
- actual = set(xids)
- expected = set(prepared)
- intersection = actual.intersection(expected)
-
- if intersection != expected:
- missing = expected.difference(actual)
- extra = actual.difference(expected)
- for x in missing:
- channel.dtx_coordination_rollback(xid=x)
- self.fail("Recovered xids not as expected. missing: %s; extra: %s" % (missing, extra))
-
- def xid(self, txid, branchqual = ''):
- return pack('LBB', 0, len(txid), len(branchqual)) + txid + branchqual
-
- def txswap(self, tx, id):
- channel = self.channel
- #declare two queues:
- channel.queue_declare(queue="queue-a", exclusive=True)
- channel.queue_declare(queue="queue-b", exclusive=True)
- #put message with specified id on one queue:
- channel.message_transfer(routing_key="queue-a", message_id=id, body="DtxMessage")
-
- #start the transaction:
- channel.dtx_demarcation_select()
- self.assertEqual(self.XA_OK, self.channel.dtx_demarcation_start(xid=tx).flags)
-
- #'swap' the message from one queue to the other, under that transaction:
- self.swap(self.channel, "queue-a", "queue-b")
-
- #mark the end of the transactional work:
- self.assertEqual(self.XA_OK, self.channel.dtx_demarcation_end(xid=tx).flags)
-
- def swap(self, channel, src, dest):
- #consume from src:
- channel.message_get(destination="temp-swap", queue=src)
- msg = self.client.queue("temp-swap").get(timeout=1)
- msg.ok();
-
- #re-publish to dest
- channel.message_transfer(routing_key=dest, message_id=msg.message_id, body=msg.body)
-
- def assertMessageCount(self, expected, queue):
- self.assertEqual(expected, self.channel.queue_declare(queue=queue, passive=True).message_count)
-
- def assertMessageId(self, expected, queue):
- self.channel.message_consume(queue=queue, destination="results", no_ack=True)
- self.assertEqual(expected, self.client.queue("results").get(timeout=1).message_id)
- self.channel.message_cancel(destination="results")
diff --git a/python/tests_0-9/example.py b/python/tests_0-9/example.py
deleted file mode 100644
index 7ab4cc7d0a..0000000000
--- a/python/tests_0-9/example.py
+++ /dev/null
@@ -1,94 +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.
-#
-
-from qpid.content import Content
-from qpid.testlib import testrunner, TestBase
-
-class ExampleTest (TestBase):
- """
- An example Qpid test, illustrating the unittest frameowkr and the
- python Qpid client. The test class must inherit TestCase. The
- test code uses the Qpid client to interact with a qpid broker and
- verify it behaves as expected.
- """
-
- def test_example(self):
- """
- An example test. Note that test functions must start with 'test_'
- to be recognized by the test framework.
- """
-
- # By inheriting TestBase, self.client is automatically connected
- # and self.channel is automatically opened as channel(1)
- # Other channel methods mimic the protocol.
- channel = self.channel
-
- # Now we can send regular commands. If you want to see what the method
- # arguments mean or what other commands are available, you can use the
- # python builtin help() method. For example:
- #help(chan)
- #help(chan.exchange_declare)
-
- # If you want browse the available protocol methods without being
- # connected to a live server you can use the amqp-doc utility:
- #
- # Usage amqp-doc [<options>] <spec> [<pattern_1> ... <pattern_n>]
- #
- # Options:
- # -e, --regexp use regex instead of glob when matching
-
- # Now that we know what commands are available we can use them to
- # interact with the server.
-
- # Here we use ordinal arguments.
- self.exchange_declare(channel, 0, "test", "direct")
-
- # Here we use keyword arguments.
- self.queue_declare(channel, queue="test-queue")
- channel.queue_bind(queue="test-queue", exchange="test", routing_key="key")
-
- # Call Channel.basic_consume to register as a consumer.
- # All the protocol methods return a message object. The message object
- # has fields corresponding to the reply method fields, plus a content
- # field that is filled if the reply includes content. In this case the
- # interesting field is the consumer_tag.
- channel.message_consume(queue="test-queue", destination="consumer_tag")
-
- # We can use the Client.queue(...) method to access the queue
- # corresponding to our consumer_tag.
- queue = self.client.queue("consumer_tag")
-
- # Now lets publish a message and see if our consumer gets it. To do
- # this we need to import the Content class.
- body = "Hello World!"
- channel.message_transfer(destination="test",
- routing_key="key",
- body = body)
-
- # Now we'll wait for the message to arrive. We can use the timeout
- # argument in case the server hangs. By default queue.get() will wait
- # until a message arrives or the connection to the server dies.
- msg = queue.get(timeout=10)
-
- # And check that we got the right response with assertEqual
- self.assertEqual(body, msg.body)
-
- # Now acknowledge the message.
- msg.ok()
-
diff --git a/python/tests_0-9/exchange.py b/python/tests_0-9/exchange.py
deleted file mode 100644
index 3a47ffff8c..0000000000
--- a/python/tests_0-9/exchange.py
+++ /dev/null
@@ -1,327 +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.
-#
-
-"""
-Tests for exchange behaviour.
-
-Test classes ending in 'RuleTests' are derived from rules in amqp.xml.
-"""
-
-import Queue, logging
-from qpid.testlib import TestBase
-from qpid.content import Content
-from qpid.client import Closed
-
-
-class StandardExchangeVerifier:
- """Verifies standard exchange behavior.
-
- Used as base class for classes that test standard exchanges."""
-
- def verifyDirectExchange(self, ex):
- """Verify that ex behaves like a direct exchange."""
- self.queue_declare(queue="q")
- self.channel.queue_bind(queue="q", exchange=ex, routing_key="k")
- self.assertPublishConsume(exchange=ex, queue="q", routing_key="k")
- try:
- self.assertPublishConsume(exchange=ex, queue="q", routing_key="kk")
- self.fail("Expected Empty exception")
- except Queue.Empty: None # Expected
-
- def verifyFanOutExchange(self, ex):
- """Verify that ex behaves like a fanout exchange."""
- self.queue_declare(queue="q")
- self.channel.queue_bind(queue="q", exchange=ex)
- self.queue_declare(queue="p")
- self.channel.queue_bind(queue="p", exchange=ex)
- for qname in ["q", "p"]: self.assertPublishGet(self.consume(qname), ex)
-
- def verifyTopicExchange(self, ex):
- """Verify that ex behaves like a topic exchange"""
- self.queue_declare(queue="a")
- self.channel.queue_bind(queue="a", exchange=ex, routing_key="a.#.b.*")
- q = self.consume("a")
- self.assertPublishGet(q, ex, "a.b.x")
- self.assertPublishGet(q, ex, "a.x.b.x")
- self.assertPublishGet(q, ex, "a.x.x.b.x")
- # Shouldn't match
- self.channel.message_transfer(destination=ex, routing_key="a.b", body="")
- self.channel.message_transfer(destination=ex, routing_key="a.b.x.y", body="")
- self.channel.message_transfer(destination=ex, routing_key="x.a.b.x", body="")
- self.channel.message_transfer(destination=ex, routing_key="a.b", body="")
- self.assert_(q.empty())
-
- def verifyHeadersExchange(self, ex):
- """Verify that ex is a headers exchange"""
- self.queue_declare(queue="q")
- self.channel.queue_bind(queue="q", exchange=ex, arguments={ "x-match":"all", "name":"fred" , "age":3} )
- q = self.consume("q")
- headers = {"name":"fred", "age":3}
- self.assertPublishGet(q, exchange=ex, properties=headers)
- self.channel.message_transfer(destination=ex, body="") # No headers, won't deliver
- self.assertEmpty(q);
-
-
-class RecommendedTypesRuleTests(TestBase, StandardExchangeVerifier):
- """
- The server SHOULD implement these standard exchange types: topic, headers.
-
- Client attempts to declare an exchange with each of these standard types.
- """
-
- def testDirect(self):
- """Declare and test a direct exchange"""
- self.exchange_declare(0, exchange="d", type="direct")
- self.verifyDirectExchange("d")
-
- def testFanout(self):
- """Declare and test a fanout exchange"""
- self.exchange_declare(0, exchange="f", type="fanout")
- self.verifyFanOutExchange("f")
-
- def testTopic(self):
- """Declare and test a topic exchange"""
- self.exchange_declare(0, exchange="t", type="topic")
- self.verifyTopicExchange("t")
-
- def testHeaders(self):
- """Declare and test a headers exchange"""
- self.exchange_declare(0, exchange="h", type="headers")
- self.verifyHeadersExchange("h")
-
-
-class RequiredInstancesRuleTests(TestBase, StandardExchangeVerifier):
- """
- The server MUST, in each virtual host, pre-declare an exchange instance
- for each standard exchange type that it implements, where the name of the
- exchange instance is amq. followed by the exchange type name.
-
- Client creates a temporary queue and attempts to bind to each required
- exchange instance (amq.fanout, amq.direct, and amq.topic, amq.match if
- those types are defined).
- """
- def testAmqDirect(self): self.verifyDirectExchange("amq.direct")
-
- def testAmqFanOut(self): self.verifyFanOutExchange("amq.fanout")
-
- def testAmqTopic(self): self.verifyTopicExchange("amq.topic")
-
- def testAmqMatch(self): self.verifyHeadersExchange("amq.match")
-
-class DefaultExchangeRuleTests(TestBase, StandardExchangeVerifier):
- """
- The server MUST predeclare a direct exchange to act as the default exchange
- for content Publish methods and for default queue bindings.
-
- Client checks that the default exchange is active by specifying a queue
- binding with no exchange name, and publishing a message with a suitable
- routing key but without specifying the exchange name, then ensuring that
- the message arrives in the queue correctly.
- """
- def testDefaultExchange(self):
- # Test automatic binding by queue name.
- self.queue_declare(queue="d")
- self.assertPublishConsume(queue="d", routing_key="d")
- # Test explicit bind to default queue
- self.verifyDirectExchange("")
-
-
-# TODO aconway 2006-09-27: Fill in empty tests:
-
-class DefaultAccessRuleTests(TestBase):
- """
- The server MUST NOT allow clients to access the default exchange except
- by specifying an empty exchange name in the Queue.Bind and content Publish
- methods.
- """
-
-class ExtensionsRuleTests(TestBase):
- """
- The server MAY implement other exchange types as wanted.
- """
-
-
-class DeclareMethodMinimumRuleTests(TestBase):
- """
- The server SHOULD support a minimum of 16 exchanges per virtual host and
- ideally, impose no limit except as defined by available resources.
-
- The client creates as many exchanges as it can until the server reports
- an error; the number of exchanges successfuly created must be at least
- sixteen.
- """
-
-
-class DeclareMethodTicketFieldValidityRuleTests(TestBase):
- """
- The client MUST provide a valid access ticket giving "active" access to
- the realm in which the exchange exists or will be created, or "passive"
- access if the if-exists flag is set.
-
- Client creates access ticket with wrong access rights and attempts to use
- in this method.
- """
-
-
-class DeclareMethodExchangeFieldReservedRuleTests(TestBase):
- """
- Exchange names starting with "amq." are reserved for predeclared and
- standardised exchanges. The client MUST NOT attempt to create an exchange
- starting with "amq.".
-
-
- """
-
-
-class DeclareMethodTypeFieldTypedRuleTests(TestBase):
- """
- Exchanges cannot be redeclared with different types. The client MUST not
- attempt to redeclare an existing exchange with a different type than used
- in the original Exchange.Declare method.
-
-
- """
-
-
-class DeclareMethodTypeFieldSupportRuleTests(TestBase):
- """
- The client MUST NOT attempt to create an exchange with a type that the
- server does not support.
-
-
- """
-
-
-class DeclareMethodPassiveFieldNotFoundRuleTests(TestBase):
- """
- If set, and the exchange does not already exist, the server MUST raise a
- channel exception with reply code 404 (not found).
- """
- def test(self):
- try:
- self.channel.exchange_declare(exchange="humpty_dumpty", passive=True)
- self.fail("Expected 404 for passive declaration of unknown exchange.")
- except Closed, e:
- self.assertChannelException(404, e.args[0])
-
-
-class DeclareMethodDurableFieldSupportRuleTests(TestBase):
- """
- The server MUST support both durable and transient exchanges.
-
-
- """
-
-
-class DeclareMethodDurableFieldStickyRuleTests(TestBase):
- """
- The server MUST ignore the durable field if the exchange already exists.
-
-
- """
-
-
-class DeclareMethodAutoDeleteFieldStickyRuleTests(TestBase):
- """
- The server MUST ignore the auto-delete field if the exchange already
- exists.
-
-
- """
-
-
-class DeleteMethodTicketFieldValidityRuleTests(TestBase):
- """
- The client MUST provide a valid access ticket giving "active" access
- rights to the exchange's access realm.
-
- Client creates access ticket with wrong access rights and attempts to use
- in this method.
- """
-
-
-class DeleteMethodExchangeFieldExistsRuleTests(TestBase):
- """
- The client MUST NOT attempt to delete an exchange that does not exist.
- """
-
-
-class HeadersExchangeTests(TestBase):
- """
- Tests for headers exchange functionality.
- """
- def setUp(self):
- TestBase.setUp(self)
- self.queue_declare(queue="q")
- self.q = self.consume("q")
-
- def myAssertPublishGet(self, headers):
- self.assertPublishGet(self.q, exchange="amq.match", properties=headers)
-
- def myBasicPublish(self, headers):
- self.channel.message_transfer(destination="amq.match", body="foobar", application_headers=headers)
-
- def testMatchAll(self):
- self.channel.queue_bind(queue="q", exchange="amq.match", arguments={ 'x-match':'all', "name":"fred", "age":3})
- self.myAssertPublishGet({"name":"fred", "age":3})
- self.myAssertPublishGet({"name":"fred", "age":3, "extra":"ignoreme"})
-
- # None of these should match
- self.myBasicPublish({})
- self.myBasicPublish({"name":"barney"})
- self.myBasicPublish({"name":10})
- self.myBasicPublish({"name":"fred", "age":2})
- self.assertEmpty(self.q)
-
- def testMatchAny(self):
- self.channel.queue_bind(queue="q", exchange="amq.match", arguments={ 'x-match':'any', "name":"fred", "age":3})
- self.myAssertPublishGet({"name":"fred"})
- self.myAssertPublishGet({"name":"fred", "ignoreme":10})
- self.myAssertPublishGet({"ignoreme":10, "age":3})
-
- # Wont match
- self.myBasicPublish({})
- self.myBasicPublish({"irrelevant":0})
- self.assertEmpty(self.q)
-
-
-class MiscellaneousErrorsTests(TestBase):
- """
- Test some miscellaneous error conditions
- """
- def testTypeNotKnown(self):
- try:
- self.channel.exchange_declare(exchange="test_type_not_known_exchange", type="invalid_type")
- self.fail("Expected 503 for declaration of unknown exchange type.")
- except Closed, e:
- self.assertConnectionException(503, e.args[0])
-
- def testDifferentDeclaredType(self):
- self.channel.exchange_declare(exchange="test_different_declared_type_exchange", type="direct")
- try:
- self.channel.exchange_declare(exchange="test_different_declared_type_exchange", type="topic")
- self.fail("Expected 530 for redeclaration of exchange with different type.")
- except Closed, e:
- self.assertConnectionException(530, e.args[0])
- #cleanup
- other = self.connect()
- c2 = other.channel(1)
- c2.channel_open()
- c2.exchange_delete(exchange="test_different_declared_type_exchange")
-
diff --git a/python/tests_0-9/execution.py b/python/tests_0-9/execution.py
deleted file mode 100644
index f2facfe42b..0000000000
--- a/python/tests_0-9/execution.py
+++ /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.
-#
-
-from qpid.content import Content
-from qpid.testlib import testrunner, TestBase
-
-class ExecutionTests (TestBase):
- def test_flush(self):
- channel = self.channel
- for i in [1, 2, 3]:
- channel.basic_publish()
- channel.execution_flush()
- assert(channel.completion.wait(channel.completion.command_id, timeout=1))
diff --git a/python/tests_0-9/message.py b/python/tests_0-9/message.py
deleted file mode 100644
index b25016e680..0000000000
--- a/python/tests_0-9/message.py
+++ /dev/null
@@ -1,657 +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.
-#
-from qpid.client import Client, Closed
-from qpid.queue import Empty
-from qpid.content import Content
-from qpid.testlib import testrunner, TestBase
-from qpid.reference import Reference, ReferenceId
-
-class MessageTests(TestBase):
- """Tests for 'methods' on the amqp message 'class'"""
-
- def test_consume_no_local(self):
- """
- Test that the no_local flag is honoured in the consume method
- """
- channel = self.channel
- #setup, declare two queues:
- channel.queue_declare(queue="test-queue-1a", exclusive=True)
- channel.queue_declare(queue="test-queue-1b", exclusive=True)
- #establish two consumers one of which excludes delivery of locally sent messages
- channel.message_consume(destination="local_included", queue="test-queue-1a")
- channel.message_consume(destination="local_excluded", queue="test-queue-1b", no_local=True)
-
- #send a message
- channel.message_transfer(routing_key="test-queue-1a", body="consume_no_local")
- channel.message_transfer(routing_key="test-queue-1b", body="consume_no_local")
-
- #check the queues of the two consumers
- excluded = self.client.queue("local_excluded")
- included = self.client.queue("local_included")
- msg = included.get(timeout=1)
- self.assertEqual("consume_no_local", msg.body)
- try:
- excluded.get(timeout=1)
- self.fail("Received locally published message though no_local=true")
- except Empty: None
-
-
- def test_consume_exclusive(self):
- """
- Test that the exclusive flag is honoured in the consume method
- """
- channel = self.channel
- #setup, declare a queue:
- channel.queue_declare(queue="test-queue-2", exclusive=True)
-
- #check that an exclusive consumer prevents other consumer being created:
- channel.message_consume(destination="first", queue="test-queue-2", exclusive=True)
- try:
- channel.message_consume(destination="second", queue="test-queue-2")
- self.fail("Expected consume request to fail due to previous exclusive consumer")
- except Closed, e:
- self.assertChannelException(403, e.args[0])
-
- #open new channel and cleanup last consumer:
- channel = self.client.channel(2)
- channel.channel_open()
-
- #check that an exclusive consumer cannot be created if a consumer already exists:
- channel.message_consume(destination="first", queue="test-queue-2")
- try:
- channel.message_consume(destination="second", queue="test-queue-2", exclusive=True)
- self.fail("Expected exclusive consume request to fail due to previous consumer")
- except Closed, e:
- self.assertChannelException(403, e.args[0])
-
- def test_consume_queue_errors(self):
- """
- Test error conditions associated with the queue field of the consume method:
- """
- channel = self.channel
- try:
- #queue specified but doesn't exist:
- channel.message_consume(queue="invalid-queue")
- self.fail("Expected failure when consuming from non-existent queue")
- except Closed, e:
- self.assertChannelException(404, e.args[0])
-
- channel = self.client.channel(2)
- channel.channel_open()
- try:
- #queue not specified and none previously declared for channel:
- channel.message_consume(queue="")
- self.fail("Expected failure when consuming from unspecified queue")
- except Closed, e:
- self.assertConnectionException(530, e.args[0])
-
- def test_consume_unique_consumers(self):
- """
- Ensure unique consumer tags are enforced
- """
- channel = self.channel
- #setup, declare a queue:
- channel.queue_declare(queue="test-queue-3", exclusive=True)
-
- #check that attempts to use duplicate tags are detected and prevented:
- channel.message_consume(destination="first", queue="test-queue-3")
- try:
- channel.message_consume(destination="first", queue="test-queue-3")
- self.fail("Expected consume request to fail due to non-unique tag")
- except Closed, e:
- self.assertConnectionException(530, e.args[0])
-
- def test_cancel(self):
- """
- Test compliance of the basic.cancel method
- """
- channel = self.channel
- #setup, declare a queue:
- channel.queue_declare(queue="test-queue-4", exclusive=True)
- channel.message_consume(destination="my-consumer", queue="test-queue-4")
- channel.message_transfer(routing_key="test-queue-4", body="One")
-
- #cancel should stop messages being delivered
- channel.message_cancel(destination="my-consumer")
- channel.message_transfer(routing_key="test-queue-4", body="Two")
- myqueue = self.client.queue("my-consumer")
- msg = myqueue.get(timeout=1)
- self.assertEqual("One", msg.body)
- try:
- msg = myqueue.get(timeout=1)
- self.fail("Got message after cancellation: " + msg)
- except Empty: None
-
- #cancellation of non-existant consumers should be handled without error
- channel.message_cancel(destination="my-consumer")
- channel.message_cancel(destination="this-never-existed")
-
-
- def test_ack(self):
- """
- Test basic ack/recover behaviour
- """
- channel = self.channel
- channel.queue_declare(queue="test-ack-queue", exclusive=True)
-
- channel.message_consume(queue="test-ack-queue", destination="consumer_tag", no_ack=False)
- queue = self.client.queue("consumer_tag")
-
- channel.message_transfer(routing_key="test-ack-queue", body="One")
- channel.message_transfer(routing_key="test-ack-queue", body="Two")
- channel.message_transfer(routing_key="test-ack-queue", body="Three")
- channel.message_transfer(routing_key="test-ack-queue", body="Four")
- channel.message_transfer(routing_key="test-ack-queue", body="Five")
-
- msg1 = queue.get(timeout=1)
- msg2 = queue.get(timeout=1)
- msg3 = queue.get(timeout=1)
- msg4 = queue.get(timeout=1)
- msg5 = queue.get(timeout=1)
-
- self.assertEqual("One", msg1.body)
- self.assertEqual("Two", msg2.body)
- self.assertEqual("Three", msg3.body)
- self.assertEqual("Four", msg4.body)
- self.assertEqual("Five", msg5.body)
-
- msg1.ok(batchoffset=1)#One and Two
- msg4.ok()
-
- channel.message_recover(requeue=False)
-
- msg3b = queue.get(timeout=1)
- msg5b = queue.get(timeout=1)
-
- self.assertEqual("Three", msg3b.body)
- self.assertEqual("Five", msg5b.body)
-
- try:
- extra = queue.get(timeout=1)
- self.fail("Got unexpected message: " + extra.body)
- except Empty: None
-
- def test_recover_requeue(self):
- """
- Test requeing on recovery
- """
- channel = self.channel
- channel.queue_declare(queue="test-requeue", exclusive=True)
-
- channel.message_consume(queue="test-requeue", destination="consumer_tag", no_ack=False)
- queue = self.client.queue("consumer_tag")
-
- channel.message_transfer(routing_key="test-requeue", body="One")
- channel.message_transfer(routing_key="test-requeue", body="Two")
- channel.message_transfer(routing_key="test-requeue", body="Three")
- channel.message_transfer(routing_key="test-requeue", body="Four")
- channel.message_transfer(routing_key="test-requeue", body="Five")
-
- msg1 = queue.get(timeout=1)
- msg2 = queue.get(timeout=1)
- msg3 = queue.get(timeout=1)
- msg4 = queue.get(timeout=1)
- msg5 = queue.get(timeout=1)
-
- self.assertEqual("One", msg1.body)
- self.assertEqual("Two", msg2.body)
- self.assertEqual("Three", msg3.body)
- self.assertEqual("Four", msg4.body)
- self.assertEqual("Five", msg5.body)
-
- msg1.ok(batchoffset=1) #One and Two
- msg4.ok() #Four
-
- channel.message_cancel(destination="consumer_tag")
-
- #publish a new message
- channel.message_transfer(routing_key="test-requeue", body="Six")
- #requeue unacked messages (Three and Five)
- channel.message_recover(requeue=True)
-
- channel.message_consume(queue="test-requeue", destination="consumer_tag")
- queue2 = self.client.queue("consumer_tag")
-
- msg3b = queue2.get(timeout=1)
- msg5b = queue2.get(timeout=1)
-
- self.assertEqual("Three", msg3b.body)
- self.assertEqual("Five", msg5b.body)
-
- self.assertEqual(True, msg3b.redelivered)
- self.assertEqual(True, msg5b.redelivered)
-
- self.assertEqual("Six", queue2.get(timeout=1).body)
-
- try:
- extra = queue2.get(timeout=1)
- self.fail("Got unexpected message in second queue: " + extra.body)
- except Empty: None
- try:
- extra = queue.get(timeout=1)
- self.fail("Got unexpected message in original queue: " + extra.body)
- except Empty: None
-
-
- def test_qos_prefetch_count(self):
- """
- Test that the prefetch count specified is honoured
- """
- #setup: declare queue and subscribe
- channel = self.channel
- channel.queue_declare(queue="test-prefetch-count", exclusive=True)
- subscription = channel.message_consume(queue="test-prefetch-count", destination="consumer_tag", no_ack=False)
- queue = self.client.queue("consumer_tag")
-
- #set prefetch to 5:
- channel.message_qos(prefetch_count=5)
-
- #publish 10 messages:
- for i in range(1, 11):
- channel.message_transfer(routing_key="test-prefetch-count", body="Message %d" % i)
-
- #only 5 messages should have been delivered:
- for i in range(1, 6):
- msg = queue.get(timeout=1)
- self.assertEqual("Message %d" % i, msg.body)
- try:
- extra = queue.get(timeout=1)
- self.fail("Got unexpected 6th message in original queue: " + extra.body)
- except Empty: None
-
- #ack messages and check that the next set arrive ok:
- #todo: once batching is implmented, send a single response for all messages
- msg.ok(batchoffset=-4)#1-5
-
- for i in range(6, 11):
- msg = queue.get(timeout=1)
- self.assertEqual("Message %d" % i, msg.body)
-
- msg.ok(batchoffset=-4)#6-10
-
- try:
- extra = queue.get(timeout=1)
- self.fail("Got unexpected 11th message in original queue: " + extra.body)
- except Empty: None
-
-
-
- def test_qos_prefetch_size(self):
- """
- Test that the prefetch size specified is honoured
- """
- #setup: declare queue and subscribe
- channel = self.channel
- channel.queue_declare(queue="test-prefetch-size", exclusive=True)
- subscription = channel.message_consume(queue="test-prefetch-size", destination="consumer_tag", no_ack=False)
- queue = self.client.queue("consumer_tag")
-
- #set prefetch to 50 bytes (each message is 9 or 10 bytes):
- channel.message_qos(prefetch_size=50)
-
- #publish 10 messages:
- for i in range(1, 11):
- channel.message_transfer(routing_key="test-prefetch-size", body="Message %d" % i)
-
- #only 5 messages should have been delivered (i.e. 45 bytes worth):
- for i in range(1, 6):
- msg = queue.get(timeout=1)
- self.assertEqual("Message %d" % i, msg.body)
-
- try:
- extra = queue.get(timeout=1)
- self.fail("Got unexpected 6th message in original queue: " + extra.body)
- except Empty: None
-
- #ack messages and check that the next set arrive ok:
- msg.ok(batchoffset=-4)#1-5
-
- for i in range(6, 11):
- msg = queue.get(timeout=1)
- self.assertEqual("Message %d" % i, msg.body)
-
- msg.ok(batchoffset=-4)#6-10
-
- try:
- extra = queue.get(timeout=1)
- self.fail("Got unexpected 11th message in original queue: " + extra.body)
- except Empty: None
-
- #make sure that a single oversized message still gets delivered
- large = "abcdefghijklmnopqrstuvwxyz"
- large = large + "-" + large;
- channel.message_transfer(routing_key="test-prefetch-size", body=large)
- msg = queue.get(timeout=1)
- self.assertEqual(large, msg.body)
-
- def test_get(self):
- """
- Test message_get method
- """
- channel = self.channel
- channel.queue_declare(queue="test-get", exclusive=True)
-
- #publish some messages (no_ack=True)
- for i in range(1, 11):
- channel.message_transfer(routing_key="test-get", body="Message %d" % i)
-
- #use message_get to read back the messages, and check that we get an empty at the end
- for i in range(1, 11):
- tag = "queue %d" % i
- reply = channel.message_get(no_ack=True, queue="test-get", destination=tag)
- self.assertEqual(reply.method.klass.name, "message")
- self.assertEqual(reply.method.name, "ok")
- self.assertEqual("Message %d" % i, self.client.queue(tag).get(timeout=1).body)
-
- reply = channel.message_get(no_ack=True, queue="test-get")
- self.assertEqual(reply.method.klass.name, "message")
- self.assertEqual(reply.method.name, "empty")
-
- #repeat for no_ack=False
- for i in range(11, 21):
- channel.message_transfer(routing_key="test-get", body="Message %d" % i)
-
- for i in range(11, 21):
- tag = "queue %d" % i
- reply = channel.message_get(no_ack=False, queue="test-get", destination=tag)
- self.assertEqual(reply.method.klass.name, "message")
- self.assertEqual(reply.method.name, "ok")
- msg = self.client.queue(tag).get(timeout=1)
- self.assertEqual("Message %d" % i, msg.body)
-
- if (i==13):
- msg.ok(batchoffset=-2)#11, 12 & 13
- if(i in [15, 17, 19]):
- msg.ok()
-
- reply = channel.message_get(no_ack=True, queue="test-get")
- self.assertEqual(reply.method.klass.name, "message")
- self.assertEqual(reply.method.name, "empty")
-
- #recover(requeue=True)
- channel.message_recover(requeue=True)
-
- #get the unacked messages again (14, 16, 18, 20)
- for i in [14, 16, 18, 20]:
- tag = "queue %d" % i
- reply = channel.message_get(no_ack=False, queue="test-get", destination=tag)
- self.assertEqual(reply.method.klass.name, "message")
- self.assertEqual(reply.method.name, "ok")
- msg = self.client.queue(tag).get(timeout=1)
- self.assertEqual("Message %d" % i, msg.body)
- msg.ok()
- #channel.message_ack(delivery_tag=reply.delivery_tag)
-
- reply = channel.message_get(no_ack=True, queue="test-get")
- self.assertEqual(reply.method.klass.name, "message")
- self.assertEqual(reply.method.name, "empty")
-
- channel.message_recover(requeue=True)
-
- reply = channel.message_get(no_ack=True, queue="test-get")
- self.assertEqual(reply.method.klass.name, "message")
- self.assertEqual(reply.method.name, "empty")
-
- def test_reference_simple(self):
- """
- Test basic ability to handle references
- """
- channel = self.channel
- channel.queue_declare(queue="ref_queue", exclusive=True)
- channel.message_consume(queue="ref_queue", destination="c1")
- queue = self.client.queue("c1")
-
- refId = "myref"
- channel.message_open(reference=refId)
- channel.message_append(reference=refId, bytes="abcd")
- channel.synchronous = False
- ack = channel.message_transfer(routing_key="ref_queue", body=ReferenceId(refId))
- channel.synchronous = True
-
- channel.message_append(reference=refId, bytes="efgh")
- channel.message_append(reference=refId, bytes="ijkl")
- channel.message_close(reference=refId)
-
- #first, wait for the ok for the transfer
- ack.get_response(timeout=1)
-
- self.assertDataEquals(channel, queue.get(timeout=1), "abcdefghijkl")
-
-
- def test_reference_large(self):
- """
- Test basic ability to handle references whose content exceeds max frame size
- """
- channel = self.channel
- self.queue_declare(queue="ref_queue")
-
- #generate a big data string (> max frame size of consumer):
- data = "0123456789"
- for i in range(0, 10):
- data += data
- #send it inline
- channel.synchronous = False
- ack = channel.message_transfer(routing_key="ref_queue", body=data)
- channel.synchronous = True
- #first, wait for the ok for the transfer
- ack.get_response(timeout=1)
-
- #create a new connection for consumer, with specific max frame size (< data)
- other = self.connect(tune_params={"channel_max":10, "frame_max":5120, "heartbeat":0})
- ch2 = other.channel(1)
- ch2.channel_open()
- ch2.message_consume(queue="ref_queue", destination="c1")
- queue = other.queue("c1")
-
- msg = queue.get(timeout=1)
- self.assertTrue(isinstance(msg.body, ReferenceId))
- self.assertTrue(msg.reference)
- self.assertEquals(data, msg.reference.get_complete())
-
- def test_reference_completion(self):
- """
- Test that reference transfer are not deemed complete until
- closed (therefore are not acked or routed until that point)
- """
- channel = self.channel
- channel.queue_declare(queue="ref_queue", exclusive=True)
- channel.message_consume(queue="ref_queue", destination="c1")
- queue = self.client.queue("c1")
-
- refId = "myref"
- channel.message_open(reference=refId)
- channel.message_append(reference=refId, bytes="abcd")
- channel.synchronous = False
- ack = channel.message_transfer(routing_key="ref_queue", body=ReferenceId(refId))
- channel.synchronous = True
-
- try:
- msg = queue.get(timeout=1)
- self.fail("Got unexpected message on queue: " + msg)
- except Empty: None
-
- self.assertTrue(not ack.is_complete())
-
- channel.message_close(reference=refId)
-
- #first, wait for the ok for the transfer
- ack.get_response(timeout=1)
-
- self.assertDataEquals(channel, queue.get(timeout=1), "abcd")
-
- def test_reference_multi_transfer(self):
- """
- Test that multiple transfer requests for the same reference are
- correctly handled.
- """
- channel = self.channel
- #declare and consume from two queues
- channel.queue_declare(queue="q-one", exclusive=True)
- channel.queue_declare(queue="q-two", exclusive=True)
- channel.message_consume(queue="q-one", destination="q-one")
- channel.message_consume(queue="q-two", destination="q-two")
- queue1 = self.client.queue("q-one")
- queue2 = self.client.queue("q-two")
-
- #transfer a single ref to both queues (in separate commands)
- channel.message_open(reference="my-ref")
- channel.synchronous = False
- ack1 = channel.message_transfer(routing_key="q-one", body=ReferenceId("my-ref"))
- channel.message_append(reference="my-ref", bytes="my data")
- ack2 = channel.message_transfer(routing_key="q-two", body=ReferenceId("my-ref"))
- channel.synchronous = True
- channel.message_close(reference="my-ref")
-
- #check that both queues have the message
- self.assertDataEquals(channel, queue1.get(timeout=1), "my data")
- self.assertDataEquals(channel, queue2.get(timeout=1), "my data")
- self.assertEmpty(queue1)
- self.assertEmpty(queue2)
-
- #transfer a single ref to the same queue twice (in separate commands)
- channel.message_open(reference="my-ref")
- channel.synchronous = False
- ack1 = channel.message_transfer(routing_key="q-one", message_id="abc", body=ReferenceId("my-ref"))
- channel.message_append(reference="my-ref", bytes="second message")
- ack2 = channel.message_transfer(routing_key="q-one", message_id="xyz", body=ReferenceId("my-ref"))
- channel.synchronous = True
- channel.message_close(reference="my-ref")
-
- msg1 = queue1.get(timeout=1)
- msg2 = queue1.get(timeout=1)
- #order is undefined
- if msg1.message_id == "abc":
- self.assertEquals(msg2.message_id, "xyz")
- else:
- self.assertEquals(msg1.message_id, "xyz")
- self.assertEquals(msg2.message_id, "abc")
-
- #would be legal for the incoming messages to be transfered
- #inline or by reference in any combination
-
- if isinstance(msg1.body, ReferenceId):
- self.assertEquals("second message", msg1.reference.get_complete())
- if isinstance(msg2.body, ReferenceId):
- if msg1.body != msg2.body:
- self.assertEquals("second message", msg2.reference.get_complete())
- #else ok, as same ref as msg1
- else:
- self.assertEquals("second message", msg1.body)
- if isinstance(msg2.body, ReferenceId):
- self.assertEquals("second message", msg2.reference.get_complete())
- else:
- self.assertEquals("second message", msg2.body)
-
- self.assertEmpty(queue1)
-
- def test_reference_unopened_on_append_error(self):
- channel = self.channel
- try:
- channel.message_append(reference="unopened")
- except Closed, e:
- self.assertConnectionException(503, e.args[0])
-
- def test_reference_unopened_on_close_error(self):
- channel = self.channel
- try:
- channel.message_close(reference="unopened")
- except Closed, e:
- self.assertConnectionException(503, e.args[0])
-
- def test_reference_unopened_on_transfer_error(self):
- channel = self.channel
- try:
- channel.message_transfer(body=ReferenceId("unopened"))
- except Closed, e:
- self.assertConnectionException(503, e.args[0])
-
- def test_reference_already_opened_error(self):
- channel = self.channel
- channel.message_open(reference="a")
- try:
- channel.message_open(reference="a")
- except Closed, e:
- self.assertConnectionException(503, e.args[0])
-
- def test_empty_reference(self):
- channel = self.channel
- channel.queue_declare(queue="ref_queue", exclusive=True)
- channel.message_consume(queue="ref_queue", destination="c1")
- queue = self.client.queue("c1")
-
- refId = "myref"
- channel.message_open(reference=refId)
- channel.synchronous = False
- ack = channel.message_transfer(routing_key="ref_queue", message_id="empty-msg", body=ReferenceId(refId))
- channel.synchronous = True
- channel.message_close(reference=refId)
-
- #first, wait for the ok for the transfer
- ack.get_response(timeout=1)
-
- msg = queue.get(timeout=1)
- self.assertEquals(msg.message_id, "empty-msg")
- self.assertDataEquals(channel, msg, "")
-
- def test_reject(self):
- channel = self.channel
- channel.queue_declare(queue = "q", exclusive=True)
-
- channel.message_consume(queue = "q", destination = "consumer")
- channel.message_transfer(routing_key = "q", body="blah, blah")
- msg = self.client.queue("consumer").get(timeout = 1)
- self.assertEquals(msg.body, "blah, blah")
- channel.message_cancel(destination = "consumer")
- msg.reject()
-
- channel.message_consume(queue = "q", destination = "checker")
- msg = self.client.queue("checker").get(timeout = 1)
- self.assertEquals(msg.body, "blah, blah")
-
- def test_checkpoint(self):
- channel = self.channel
- channel.queue_declare(queue = "q", exclusive=True)
-
- channel.message_open(reference="my-ref")
- channel.message_append(reference="my-ref", bytes="abcdefgh")
- channel.message_append(reference="my-ref", bytes="ijklmnop")
- channel.message_checkpoint(reference="my-ref", identifier="my-checkpoint")
- channel.channel_close()
-
- channel = self.client.channel(2)
- channel.channel_open()
- channel.message_consume(queue = "q", destination = "consumer")
- offset = channel.message_resume(reference="my-ref", identifier="my-checkpoint").value
- self.assertTrue(offset<=16)
- channel.message_append(reference="my-ref", bytes="qrstuvwxyz")
- channel.synchronous = False
- channel.message_transfer(routing_key="q-one", message_id="abcd", body=ReferenceId("my-ref"))
- channel.synchronous = True
- channel.message_close(reference="my-ref")
-
- self.assertDataEquals(channel, self.client.queue("consumer").get(timeout = 1), "abcdefghijklmnopqrstuvwxyz")
- self.assertEmpty(self.client.queue("consumer"))
-
-
- def assertDataEquals(self, channel, msg, expected):
- if isinstance(msg.body, ReferenceId):
- data = msg.reference.get_complete()
- else:
- data = msg.body
- self.assertEquals(expected, data)
diff --git a/python/tests_0-9/query.py b/python/tests_0-9/query.py
index c2e08c003c..cb66d079e5 100644
--- a/python/tests_0-9/query.py
+++ b/python/tests_0-9/query.py
@@ -19,7 +19,7 @@
from qpid.client import Client, Closed
from qpid.queue import Empty
from qpid.content import Content
-from qpid.testlib import testrunner, TestBase
+from qpid.testlib import TestBase
class QueryTests(TestBase):
"""Tests for various query methods introduced in 0-10 and available in 0-9 for preview"""
diff --git a/python/tests_0-9/queue.py b/python/tests_0-9/queue.py
index e7fe0b3ed4..de1153307c 100644
--- a/python/tests_0-9/queue.py
+++ b/python/tests_0-9/queue.py
@@ -6,9 +6,9 @@
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -19,137 +19,11 @@
from qpid.client import Client, Closed
from qpid.queue import Empty
from qpid.content import Content
-from qpid.testlib import testrunner, TestBase
+from qpid.testlib import TestBase
class QueueTests(TestBase):
"""Tests for 'methods' on the amqp queue 'class'"""
- def test_purge(self):
- """
- Test that the purge method removes messages from the queue
- """
- channel = self.channel
- #setup, declare a queue and add some messages to it:
- channel.exchange_declare(exchange="test-exchange", type="direct")
- channel.queue_declare(queue="test-queue", exclusive=True)
- channel.queue_bind(queue="test-queue", exchange="test-exchange", routing_key="key")
- channel.message_transfer(destination="test-exchange", routing_key="key", body="one")
- channel.message_transfer(destination="test-exchange", routing_key="key", body="two")
- channel.message_transfer(destination="test-exchange", routing_key="key", body="three")
-
- #check that the queue now reports 3 messages:
- reply = channel.queue_declare(queue="test-queue")
- self.assertEqual(3, reply.message_count)
-
- #now do the purge, then test that three messages are purged and the count drops to 0
- reply = channel.queue_purge(queue="test-queue");
- self.assertEqual(3, reply.message_count)
- reply = channel.queue_declare(queue="test-queue")
- self.assertEqual(0, reply.message_count)
-
- #send a further message and consume it, ensuring that the other messages are really gone
- channel.message_transfer(destination="test-exchange", routing_key="key", body="four")
- channel.message_consume(queue="test-queue", destination="tag", no_ack=True)
- queue = self.client.queue("tag")
- msg = queue.get(timeout=1)
- self.assertEqual("four", msg.body)
-
- #check error conditions (use new channels):
- channel = self.client.channel(2)
- channel.channel_open()
- try:
- #queue specified but doesn't exist:
- channel.queue_purge(queue="invalid-queue")
- self.fail("Expected failure when purging non-existent queue")
- except Closed, e:
- self.assertChannelException(404, e.args[0])
-
- channel = self.client.channel(3)
- channel.channel_open()
- try:
- #queue not specified and none previously declared for channel:
- channel.queue_purge()
- self.fail("Expected failure when purging unspecified queue")
- except Closed, e:
- self.assertConnectionException(530, e.args[0])
-
- #cleanup
- other = self.connect()
- channel = other.channel(1)
- channel.channel_open()
- channel.exchange_delete(exchange="test-exchange")
-
- def test_declare_exclusive(self):
- """
- Test that the exclusive field is honoured in queue.declare
- """
- # TestBase.setUp has already opened channel(1)
- c1 = self.channel
- # Here we open a second separate connection:
- other = self.connect()
- c2 = other.channel(1)
- c2.channel_open()
-
- #declare an exclusive queue:
- c1.queue_declare(queue="exclusive-queue", exclusive="True")
- try:
- #other connection should not be allowed to declare this:
- c2.queue_declare(queue="exclusive-queue", exclusive="True")
- self.fail("Expected second exclusive queue_declare to raise a channel exception")
- except Closed, e:
- self.assertChannelException(405, e.args[0])
-
-
- def test_declare_passive(self):
- """
- Test that the passive field is honoured in queue.declare
- """
- channel = self.channel
- #declare an exclusive queue:
- channel.queue_declare(queue="passive-queue-1", exclusive="True")
- channel.queue_declare(queue="passive-queue-1", passive="True")
- try:
- #other connection should not be allowed to declare this:
- channel.queue_declare(queue="passive-queue-2", passive="True")
- self.fail("Expected passive declaration of non-existant queue to raise a channel exception")
- except Closed, e:
- self.assertChannelException(404, e.args[0])
-
-
- def test_bind(self):
- """
- Test various permutations of the queue.bind method
- """
- channel = self.channel
- channel.queue_declare(queue="queue-1", exclusive="True")
-
- #straightforward case, both exchange & queue exist so no errors expected:
- channel.queue_bind(queue="queue-1", exchange="amq.direct", routing_key="key1")
-
- #bind the default queue for the channel (i.e. last one declared):
- channel.queue_bind(exchange="amq.direct", routing_key="key2")
-
- #use the queue name where neither routing key nor queue are specified:
- channel.queue_bind(exchange="amq.direct")
-
- #try and bind to non-existant exchange
- try:
- channel.queue_bind(queue="queue-1", exchange="an-invalid-exchange", routing_key="key1")
- self.fail("Expected bind to non-existant exchange to fail")
- except Closed, e:
- self.assertChannelException(404, e.args[0])
-
- #need to reopen a channel:
- channel = self.client.channel(2)
- channel.channel_open()
-
- #try and bind non-existant queue:
- try:
- channel.queue_bind(queue="queue-2", exchange="amq.direct", routing_key="key1")
- self.fail("Expected bind of non-existant queue to fail")
- except Closed, e:
- self.assertChannelException(404, e.args[0])
-
def test_unbind_direct(self):
self.unbind_test(exchange="amq.direct", routing_key="key")
@@ -165,12 +39,12 @@ class QueueTests(TestBase):
def unbind_test(self, exchange, routing_key="", args=None, headers={}):
#bind two queues and consume from them
channel = self.channel
-
+
channel.queue_declare(queue="queue-1", exclusive="True")
channel.queue_declare(queue="queue-2", exclusive="True")
- channel.message_consume(queue="queue-1", destination="queue-1", no_ack=True)
- channel.message_consume(queue="queue-2", destination="queue-2", no_ack=True)
+ channel.basic_consume(queue="queue-1", consumer_tag="queue-1", no_ack=True)
+ channel.basic_consume(queue="queue-2", consumer_tag="queue-2", no_ack=True)
queue1 = self.client.queue("queue-1")
queue2 = self.client.queue("queue-2")
@@ -179,130 +53,29 @@ class QueueTests(TestBase):
channel.queue_bind(exchange=exchange, queue="queue-2", routing_key=routing_key, arguments=args)
#send a message that will match both bindings
- channel.message_transfer(destination=exchange, routing_key=routing_key, application_headers=headers, body="one")
-
+ channel.basic_publish(exchange=exchange, routing_key=routing_key,
+ content=Content("one", properties={"headers": headers}))
+
#unbind first queue
channel.queue_unbind(exchange=exchange, queue="queue-1", routing_key=routing_key, arguments=args)
-
+
#send another message
- channel.message_transfer(destination=exchange, routing_key=routing_key, application_headers=headers, body="two")
+ channel.basic_publish(exchange=exchange, routing_key=routing_key,
+ content=Content("two", properties={"headers": headers}))
#check one queue has both messages and the other has only one
- self.assertEquals("one", queue1.get(timeout=1).body)
+ self.assertEquals("one", queue1.get(timeout=1).content.body)
try:
msg = queue1.get(timeout=1)
self.fail("Got extra message: %s" % msg.body)
except Empty: pass
- self.assertEquals("one", queue2.get(timeout=1).body)
- self.assertEquals("two", queue2.get(timeout=1).body)
+ self.assertEquals("one", queue2.get(timeout=1).content.body)
+ self.assertEquals("two", queue2.get(timeout=1).content.body)
try:
msg = queue2.get(timeout=1)
self.fail("Got extra message: " + msg)
- except Empty: pass
-
-
- def test_delete_simple(self):
- """
- Test core queue deletion behaviour
- """
- channel = self.channel
-
- #straight-forward case:
- channel.queue_declare(queue="delete-me")
- channel.message_transfer(routing_key="delete-me", body="a")
- channel.message_transfer(routing_key="delete-me", body="b")
- channel.message_transfer(routing_key="delete-me", body="c")
- reply = channel.queue_delete(queue="delete-me")
- self.assertEqual(3, reply.message_count)
- #check that it has gone be declaring passively
- try:
- channel.queue_declare(queue="delete-me", passive="True")
- self.fail("Queue has not been deleted")
- except Closed, e:
- self.assertChannelException(404, e.args[0])
-
- #check attempted deletion of non-existant queue is handled correctly:
- channel = self.client.channel(2)
- channel.channel_open()
- try:
- channel.queue_delete(queue="i-dont-exist", if_empty="True")
- self.fail("Expected delete of non-existant queue to fail")
- except Closed, e:
- self.assertChannelException(404, e.args[0])
-
-
-
- def test_delete_ifempty(self):
- """
- Test that if_empty field of queue_delete is honoured
- """
- channel = self.channel
-
- #create a queue and add a message to it (use default binding):
- channel.queue_declare(queue="delete-me-2")
- channel.queue_declare(queue="delete-me-2", passive="True")
- channel.message_transfer(routing_key="delete-me-2", body="message")
-
- #try to delete, but only if empty:
- try:
- channel.queue_delete(queue="delete-me-2", if_empty="True")
- self.fail("Expected delete if_empty to fail for non-empty queue")
- except Closed, e:
- self.assertChannelException(406, e.args[0])
-
- #need new channel now:
- channel = self.client.channel(2)
- channel.channel_open()
-
- #empty queue:
- channel.message_consume(destination="consumer_tag", queue="delete-me-2", no_ack=True)
- queue = self.client.queue("consumer_tag")
- msg = queue.get(timeout=1)
- self.assertEqual("message", msg.body)
- channel.message_cancel(destination="consumer_tag")
-
- #retry deletion on empty queue:
- channel.queue_delete(queue="delete-me-2", if_empty="True")
-
- #check that it has gone by declaring passively:
- try:
- channel.queue_declare(queue="delete-me-2", passive="True")
- self.fail("Queue has not been deleted")
- except Closed, e:
- self.assertChannelException(404, e.args[0])
-
- def test_delete_ifunused(self):
- """
- Test that if_unused field of queue_delete is honoured
- """
- channel = self.channel
-
- #create a queue and register a consumer:
- channel.queue_declare(queue="delete-me-3")
- channel.queue_declare(queue="delete-me-3", passive="True")
- channel.message_consume(destination="consumer_tag", queue="delete-me-3", no_ack=True)
-
- #need new channel now:
- channel2 = self.client.channel(2)
- channel2.channel_open()
- #try to delete, but only if empty:
- try:
- channel2.queue_delete(queue="delete-me-3", if_unused="True")
- self.fail("Expected delete if_unused to fail for queue with existing consumer")
- except Closed, e:
- self.assertChannelException(406, e.args[0])
-
-
- channel.message_cancel(destination="consumer_tag")
- channel.queue_delete(queue="delete-me-3", if_unused="True")
- #check that it has gone by declaring passively:
- try:
- channel.queue_declare(queue="delete-me-3", passive="True")
- self.fail("Queue has not been deleted")
- except Closed, e:
- self.assertChannelException(404, e.args[0])
-
+ except Empty: pass
def test_autodelete_shared(self):
"""
@@ -336,5 +109,3 @@ class QueueTests(TestBase):
self.fail("Expected queue to have been deleted")
except Closed, e:
self.assertChannelException(404, e.args[0])
-
-
diff --git a/python/tests_0-9/testlib.py b/python/tests_0-9/testlib.py
deleted file mode 100644
index f345fbbd80..0000000000
--- a/python/tests_0-9/testlib.py
+++ /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.
-#
-
-#
-# Tests for the testlib itself.
-#
-
-from qpid.content import Content
-from qpid.testlib import testrunner, TestBase
-from Queue import Empty
-
-import sys
-from traceback import *
-
-def mytrace(frame, event, arg):
- print_stack(frame);
- print "===="
- return mytrace
-
-class TestBaseTest(TestBase):
- """Verify TestBase functions work as expected"""
-
- def testAssertEmptyPass(self):
- """Test assert empty works"""
- self.queue_declare(queue="empty")
- q = self.consume("empty")
- self.assertEmpty(q)
- try:
- q.get(timeout=1)
- self.fail("Queue is not empty.")
- except Empty: None # Ignore
-
- def testAssertEmptyFail(self):
- self.queue_declare(queue="full")
- q = self.consume("full")
- self.channel.message_transfer(routing_key="full", body="")
- try:
- self.assertEmpty(q);
- self.fail("assertEmpty did not assert on non-empty queue")
- except AssertionError: None # Ignore
-
- def testMessageProperties(self):
- """Verify properties are passed with message"""
- props={"x":1, "y":2}
- self.queue_declare(queue="q")
- q = self.consume("q")
- self.assertPublishGet(q, routing_key="q", properties=props)
-
-
-
diff --git a/python/tests_0-9/tx.py b/python/tests_0-9/tx.py
deleted file mode 100644
index 0f6b4f5cd1..0000000000
--- a/python/tests_0-9/tx.py
+++ /dev/null
@@ -1,188 +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.
-#
-from qpid.client import Client, Closed
-from qpid.queue import Empty
-from qpid.content import Content
-from qpid.testlib import testrunner, TestBase
-
-class TxTests(TestBase):
- """
- Tests for 'methods' on the amqp tx 'class'
- """
-
- def test_commit(self):
- """
- Test that commited publishes are delivered and commited acks are not re-delivered
- """
- channel = self.channel
- queue_a, queue_b, queue_c = self.perform_txn_work(channel, "tx-commit-a", "tx-commit-b", "tx-commit-c")
- channel.tx_commit()
-
- #check results
- for i in range(1, 5):
- msg = queue_c.get(timeout=1)
- self.assertEqual("TxMessage %d" % i, msg.body)
- msg.ok()
-
- msg = queue_b.get(timeout=1)
- self.assertEqual("TxMessage 6", msg.body)
- msg.ok()
-
- msg = queue_a.get(timeout=1)
- self.assertEqual("TxMessage 7", msg.body)
- msg.ok()
-
- for q in [queue_a, queue_b, queue_c]:
- try:
- extra = q.get(timeout=1)
- self.fail("Got unexpected message: " + extra.body)
- except Empty: None
-
- #cleanup
- channel.tx_commit()
-
- def test_auto_rollback(self):
- """
- Test that a channel closed with an open transaction is effectively rolled back
- """
- channel = self.channel
- queue_a, queue_b, queue_c = self.perform_txn_work(channel, "tx-autorollback-a", "tx-autorollback-b", "tx-autorollback-c")
-
- for q in [queue_a, queue_b, queue_c]:
- try:
- extra = q.get(timeout=1)
- self.fail("Got unexpected message: " + extra.body)
- except Empty: None
-
- channel.tx_rollback()
-
- #check results
- for i in range(1, 5):
- msg = queue_a.get(timeout=1)
- self.assertEqual("Message %d" % i, msg.body)
- msg.ok()
-
- msg = queue_b.get(timeout=1)
- self.assertEqual("Message 6", msg.body)
- msg.ok()
-
- msg = queue_c.get(timeout=1)
- self.assertEqual("Message 7", msg.body)
- msg.ok()
-
- for q in [queue_a, queue_b, queue_c]:
- try:
- extra = q.get(timeout=1)
- self.fail("Got unexpected message: " + extra.body)
- except Empty: None
-
- #cleanup
- channel.tx_commit()
-
- def test_rollback(self):
- """
- Test that rolled back publishes are not delivered and rolled back acks are re-delivered
- """
- channel = self.channel
- queue_a, queue_b, queue_c = self.perform_txn_work(channel, "tx-rollback-a", "tx-rollback-b", "tx-rollback-c")
-
- for q in [queue_a, queue_b, queue_c]:
- try:
- extra = q.get(timeout=1)
- self.fail("Got unexpected message: " + extra.body)
- except Empty: None
-
- channel.tx_rollback()
-
- #check results
- for i in range(1, 5):
- msg = queue_a.get(timeout=1)
- self.assertEqual("Message %d" % i, msg.body)
- msg.ok()
-
- msg = queue_b.get(timeout=1)
- self.assertEqual("Message 6", msg.body)
- msg.ok()
-
- msg = queue_c.get(timeout=1)
- self.assertEqual("Message 7", msg.body)
- msg.ok()
-
- for q in [queue_a, queue_b, queue_c]:
- try:
- extra = q.get(timeout=1)
- self.fail("Got unexpected message: " + extra.body)
- except Empty: None
-
- #cleanup
- channel.tx_commit()
-
- def perform_txn_work(self, channel, name_a, name_b, name_c):
- """
- Utility method that does some setup and some work under a transaction. Used for testing both
- commit and rollback
- """
- #setup:
- channel.queue_declare(queue=name_a, exclusive=True)
- channel.queue_declare(queue=name_b, exclusive=True)
- channel.queue_declare(queue=name_c, exclusive=True)
-
- key = "my_key_" + name_b
- topic = "my_topic_" + name_c
-
- channel.queue_bind(queue=name_b, exchange="amq.direct", routing_key=key)
- channel.queue_bind(queue=name_c, exchange="amq.topic", routing_key=topic)
-
- for i in range(1, 5):
- channel.message_transfer(routing_key=name_a, body="Message %d" % i)
-
- channel.message_transfer(routing_key=key, destination="amq.direct", body="Message 6")
- channel.message_transfer(routing_key=topic, destination="amq.topic", body="Message 7")
-
- channel.tx_select()
-
- #consume and ack messages
- channel.message_consume(queue=name_a, destination="sub_a", no_ack=False)
- queue_a = self.client.queue("sub_a")
- for i in range(1, 5):
- msg = queue_a.get(timeout=1)
- self.assertEqual("Message %d" % i, msg.body)
-
- msg.ok(batchoffset=-3)
-
- channel.message_consume(queue=name_b, destination="sub_b", no_ack=False)
- queue_b = self.client.queue("sub_b")
- msg = queue_b.get(timeout=1)
- self.assertEqual("Message 6", msg.body)
- msg.ok()
-
- sub_c = channel.message_consume(queue=name_c, destination="sub_c", no_ack=False)
- queue_c = self.client.queue("sub_c")
- msg = queue_c.get(timeout=1)
- self.assertEqual("Message 7", msg.body)
- msg.ok()
-
- #publish messages
- for i in range(1, 5):
- channel.message_transfer(routing_key=topic, destination="amq.topic", body="TxMessage %d" % i)
-
- channel.message_transfer(routing_key=key, destination="amq.direct", body="TxMessage 6")
- channel.message_transfer(routing_key=name_a, body="TxMessage 7")
-
- return queue_a, queue_b, queue_c
diff --git a/python/todo.txt b/python/todo.txt
new file mode 100644
index 0000000000..7b3ca90638
--- /dev/null
+++ b/python/todo.txt
@@ -0,0 +1,188 @@
+Key:
+ F = Functional
+ PF = Partially Functional
+ NR = Needs Additional Review
+ ND = Needs Additional Design
+ NF = Not Functional
+
+Connection:
+
+ variables/configuration:
+
+ - reconnect: F, NR, ND
+ + reconnect functionality is done and the API semantics provided
+ are ready for review
+ + reconnect policies need to be finished, there is currently
+ only one hardcoded reconnect policy (retry every three
+ seconds), we need to define the pre-canned policies that we
+ want to support and a means to configure them, as well as a
+ very simple plugin/callback for defining ad-hoc policies
+ + need to feed failover exchange into the reconnect policy
+ + acks can be lost on reconnect
+ + handle reconnect during commit/rollback
+
+ - timeout: NF
+ + some sort of timeout threshold for killing the connection
+
+ methods:
+
+ - open/__init__: F, ND
+ + need to support kerberos
+ + need a better way of supplying various kinds of configuration:
+ - authentication info
+ - transport specific configuration options, e.g
+ - heartbeat
+ - socket options
+ - tcp-nodelay
+ - multiple brokers
+
+ - session: F, NR
+
+ - connect: F, NR
+
+ - disconnect: F, NR
+
+ - connected: F, NR
+
+ - close: F, NR, ND
+ + currently there is no distinction between a "close" that does
+ a complete handshake with the remote broker, and a "close"
+ that reclaims resources, this means that close can fail with
+ an exception, I don't like this as it is unclear to the user
+ if there is a responsibility to do further cleanup in this
+ case
+
+ errors:
+
+ - ConnectionError: F, NR
+ + ConnectError F, NR
+ + Disconnected F, NR
+
+ - notification of disconnect?
+
+Session:
+
+ methods:
+
+ - sender: F, NR, ND
+ + need to detail address options
+ + need to define subject pattern semantics
+ + consider providing convenience for sender/receiver caching
+
+ - receiver: F, NR, ND
+ + need to detail address options
+ + need to define filter syntax/semantics
+ + consider providing convenience for sender/receiver caching
+
+ - acknowledge: F, NR
+
+ - reject: NF
+
+ - release: NF
+
+ - commit: F, NR
+
+ - rollback: F, NR
+
+ - next_receiver: F, NR
+
+ - close: F, ND
+ + see comment on Connection.close
+
+ errors:
+
+ - SessionError: F, NR, ND
+ + SendError: F, NR, ND
+ + ReceiveError: F, NR, ND
+ + should there be fatal/non fatal variants?
+
+Sender:
+
+ methods:
+
+ - pending: F, NR
+
+ - send: F, NR
+
+ - sync: F, NR, ND
+ + currently this blocks until pending == 0, I'm thinking of
+ renaming this to wait and adding a slightly richer interface
+ that would let you wait for something like pending < n
+
+ - close: F, NR
+
+ errors:
+
+ - SendError
+ + InsufficientCapacity
+ + need specific subhierarchy for certain conditions, e.g. no such queue
+
+Receiver:
+
+ methods:
+
+ - pending: F, NR
+
+ - listen: F, ND
+ + see comment on Session.fetch
+
+ - fetch: F, NR, ND
+ + explicit grant for receiver
+ + changing capacity/prefetch to issue credit on ack rather than
+ fetch return
+
+ - sync/wait: NF
+
+ - close: F, NR
+
+ errors:
+
+ - ReceiveError
+ + Empty
+ + need specific subhierarchy for certain conditions, e.g. no such queue
+
+Message:
+
+ - standard message properties: F, NR, ND
+
+ - map messages: F, NR
+ + needs interop testing: NF
+ + needs java impl: NF
+
+ - list messages: F, NR, NI
+ + needs interop testing: NF
+ + needs java impl: NF
+
+ - boxed types: NF
+
+Address:
+
+ - syntax: F, NR
+ - subject related changes, e.g. allowing patterns on both ends: NF
+ - creating/deleting queues/exchanges F, NR
+ + need to handle cleanup of temp queues/topics: F, NR
+ + passthrough options for creating exchanges/queues: F, NR
+ - integration with java: NF
+ - queue browsing: NF
+ - temporary queues: NF
+ - xquery: NF
+
+Testing:
+ - stress/soak testing for async: NF
+ - stress/soak testing for reconnect: NF
+ - interop testing: NF
+ - multi session and multi connection client tests: NF
+
+Documentation:
+ - api level docs largely present but need updating and elaboration
+ - tutorial: NF
+
+Examples:
+ - drain: F, NR
+ - spout: F, NR
+ - server: F, NR
+ - client: NF
+ - other examples, e.g. async?
+
+Miscellaneous:
+ - standard ping-like (drain/spout) utilities for all clients: NF
diff --git a/review/LICENSE b/review/LICENSE
new file mode 100644
index 0000000000..bc46b77047
--- /dev/null
+++ b/review/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/review/NOTICE b/review/NOTICE
new file mode 100644
index 0000000000..54c534c30b
--- /dev/null
+++ b/review/NOTICE
@@ -0,0 +1,8 @@
+// ------------------------------------------------------------------
+// NOTICE file corresponding to the section 4d of The Apache License,
+// Version 2.0, in this case for Qpid code review scripts
+// ------------------------------------------------------------------
+
+Apache Qpid
+Copyright 2006-2008 Apache Software Foundation
+
diff --git a/review/agenda.py b/review/agenda.py
index 22948e3ced..6ad20362cb 100755
--- a/review/agenda.py
+++ b/review/agenda.py
@@ -21,17 +21,36 @@
import sys, re
from popen2 import popen2, popen3
from optparse import OptionParser
+from xml.dom.minidom import parse, parseString
prereqs = ["tr", "svn", "xsltproc", "sed", "grep", "wget"]
-svncmd = "svn log https://svn.apache.org/repos/asf/incubator/qpid --xml -r %s:HEAD | tr '\\n\\r|' ' -' | xsltproc svnlog2wiki.xsl - | grep r | sed -e 's/^ *//' | sed -e 's/\\(QPID-[0-9]*\\)/\\[\\1 | https:\\/\\/issues.apache.org\\/jira\\/browse\\/\\1 \]/g'"
+svncmd = "svn log https://svn.apache.org/repos/asf/qpid/trunk/qpid/java --xml -r %s:HEAD | tr '\\n\\r|' ' -' | xsltproc svnlog2wiki.xsl - | grep r | sed -e 's/^ *//' | sed -e 's/\\(QPID-[0-9]*\\)/\\[\\1 | https:\\/\\/issues.apache.org\\/jira\\/browse\\/\\1 \]/g'"
jiracmd = "wget -q -O - http://issues.apache.org/jira/sr/jira.issueviews:searchrequest-xml/12312564/SearchRequest-12312564.xml?tempMax=1000 | tr '[]|' '()-' | xsltproc jiraRSS2wiki.xsl - | grep '|' | sed -e 's/^ *//'"
def get_commits(revision):
(stdout, stdin) = popen2(svncmd % revision)
- return stdout.read()
+ return add_jira_status(stdout.read())
+
+def add_jira_status(commits):
+ commit_lines = commits.split("\n")
+ new_commits = []
+ for commit in commit_lines:
+ if re.match(".*https://issues.apache.org/.*", commit):
+ jira = re.findall("QPID-[0-9]*", commit)[0]
+ jira_xml_url = "http://issues.apache.org/jira/si/jira.issueviews:issue-xml/%s/%s.xml" % (jira, jira)
+ (stdout, stdin) = popen2("wget -q -O - %s" % jira_xml_url)
+
+ jira_dom = parse(stdout)
+ status = jira_dom.getElementsByTagName("status")[0]
+ new_commits.append("%s %s | " % (commit, status.lastChild.data))
+ else:
+ new_commits.append(commit)
+
+ return "\n".join(new_commits)
+
def get_jiras():
(stdout, stdin) = popen2(jiracmd)
diff --git a/review/changeLogToWiki.py b/review/changeLogToWiki.py
new file mode 100755
index 0000000000..4054b135df
--- /dev/null
+++ b/review/changeLogToWiki.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import sys, re
+from popen2 import popen2, popen3
+from optparse import OptionParser
+from xml.dom.minidom import parse, parseString
+
+prereqs = ["tr", "svn", "xsltproc", "sed", "grep", "wget"]
+
+apacheSVN="https://svn.apache.org/repos/asf/qpid/trunk/qpid/java"
+
+svncmd = "svn log %s --xml -r %s:HEAD | tr '\\n\\r|' ' -' | xsltproc svnlog2wiki.xsl - | grep r | sed -e 's/^ *//' | sed -e 's/\\(QPID-[0-9]*\\)/\\[\\1 | https:\\/\\/issues.apache.org\\/jira\\/browse\\/\\1 \]/g'"
+
+
+def get_commits(revision):
+ (stdout, stdin) = popen2(svncmd % (options.repo,revision))
+ return add_jira_status(stdout.read())
+
+def add_jira_status(commits):
+ commit_lines = commits.split("\n")
+ new_commits = []
+ for commit in commit_lines:
+ if re.match(".*https://issues.apache.org/.*", commit):
+ jira = re.findall("QPID-[0-9]*", commit)[0]
+ jira_xml_url = "http://issues.apache.org/jira/si/jira.issueviews:issue-xml/%s/%s.xml" % (jira, jira)
+ (stdout, stdin) = popen2("wget -q -O - %s" % jira_xml_url)
+
+ jira_dom = parse(stdout)
+ status = jira_dom.getElementsByTagName("status")[0]
+ new_commits.append("%s %s | " % (commit, status.lastChild.data))
+ else:
+ new_commits.append(commit)
+
+ return "\n".join(new_commits)
+
+
+def main():
+ global options
+ parser = OptionParser()
+ parser.add_option("-r", "--revision", dest="revision", action="store",
+ type="string",
+ help="The first revision to generate logs for")
+
+ parser.add_option("-s", "--svn-repo", dest="repo", action="store",
+ default=apacheSVN,
+ type="string",
+ help="Provide a svn repository to process")
+
+
+ (options, args) = parser.parse_args()
+
+ # Check that we have what's necessary
+
+ notfound = re.compile('^which')
+ for cmd in prereqs:
+ (stdout, stdin, stderr) = popen3('which %s' % cmd)
+ if (notfound.match(stderr.read())):
+ parser.error ("Could not find command %s, try [apt-get|yum] install %s" %
+ (cmd, cmd))
+
+ if (options.revision == None):
+ parser.error("svn revision must be specified")
+
+ print(get_commits(options.revision))
+
+if __name__ == "__main__":
+ main()
diff --git a/review/jiraRSS2wiki.xsl b/review/jiraRSS2wiki.xsl
index 6ebc86d0de..bd4933cfb4 100644
--- a/review/jiraRSS2wiki.xsl
+++ b/review/jiraRSS2wiki.xsl
@@ -1,4 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"></xsl:output>
<xsl:template match="/">
diff --git a/review/svnlog2wiki.xsl b/review/svnlog2wiki.xsl
index 45fade4cda..8fe2fbf033 100644
--- a/review/svnlog2wiki.xsl
+++ b/review/svnlog2wiki.xsl
@@ -1,8 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"></xsl:output>
<xsl:template match="/">
-|| revision || committer || date || comment || review notes ||
+|| revision || committer || date || comment || review notes || jira status ||
<xsl:apply-templates select="log/logentry"></xsl:apply-templates>
</xsl:template>
<xsl:template match="logentry">
diff --git a/specs/LICENSE b/specs/LICENSE
new file mode 100644
index 0000000000..f8c0d5d1ba
--- /dev/null
+++ b/specs/LICENSE
@@ -0,0 +1,325 @@
+=========================================================================
+== 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.
+=========================================================================
+== AMQP License ==
+=========================================================================
+Copyright Notice
+ ================
+ (c) Copyright JPMorgan Chase Bank & Co., Cisco Systems, Inc., Envoy Technologies Inc.,
+ iMatix Corporation, IONA\ufffd Technologies, Red Hat, Inc.,
+ TWIST Process Innovations, and 29West Inc. 2006. All rights reserved.
+
+ License
+ =======
+ JPMorgan Chase Bank & Co., Cisco Systems, Inc., Envoy Technologies Inc., iMatix
+ Corporation, IONA Technologies, Red Hat, Inc., TWIST Process Innovations, and
+ 29West Inc. (collectively, the "Authors") each hereby grants to you a worldwide,
+ perpetual, royalty-free, nontransferable, nonexclusive license to
+ (i) copy, display, distribute and implement the Advanced Messaging Queue Protocol
+ ("AMQP") Specification and (ii) the Licensed Claims that are held by
+ the Authors, all for the purpose of implementing the Advanced Messaging
+ Queue Protocol Specification. Your license and any rights under this
+ Agreement will terminate immediately without notice from
+ any Author if you bring any claim, suit, demand, or action related to
+ the Advanced Messaging Queue Protocol Specification against any Author.
+ Upon termination, you shall destroy all copies of the Advanced Messaging
+ Queue Protocol Specification in your possession or control.
+
+ As used hereunder, "Licensed Claims" means those claims of a patent or
+ patent application, throughout the world, excluding design patents and
+ design registrations, owned or controlled, or that can be sublicensed
+ without fee and in compliance with the requirements of this
+ Agreement, by an Author or its affiliates now or at any
+ future time and which would necessarily be infringed by implementation
+ of the Advanced Messaging Queue Protocol Specification. A claim is
+ necessarily infringed hereunder only when it is not possible to avoid
+ infringing it because there is no plausible non-infringing alternative
+ for implementing the required portions of the Advanced Messaging Queue
+ Protocol Specification. Notwithstanding the foregoing, Licensed Claims
+ shall not include any claims other than as set forth above even if
+ contained in the same patent as Licensed Claims; or that read solely
+ on any implementations of any portion of the Advanced Messaging Queue
+ Protocol Specification that are not required by the Advanced Messaging
+ Queue Protocol Specification, or that, if licensed, would require a
+ payment of royalties by the licensor to unaffiliated third parties.
+ Moreover, Licensed Claims shall not include (i) any enabling technologies
+ that may be necessary to make or use any Licensed Product but are not
+ themselves expressly set forth in the Advanced Messaging Queue Protocol
+ Specification (e.g., semiconductor manufacturing technology, compiler
+ technology, object oriented technology, networking technology, operating
+ system technology, and the like); or (ii) the implementation of other
+ published standards developed elsewhere and merely referred to in the
+ body of the Advanced Messaging Queue Protocol Specification, or
+ (iii) any Licensed Product and any combinations thereof the purpose or
+ function of which is not required for compliance with the Advanced
+ Messaging Queue Protocol Specification. For purposes of this definition,
+ the Advanced Messaging Queue Protocol Specification shall be deemed to
+ include both architectural and interconnection requirements essential
+ for interoperability and may also include supporting source code artifacts
+ where such architectural, interconnection requirements and source code
+ artifacts are expressly identified as being required or documentation to
+ achieve compliance with the Advanced Messaging Queue Protocol Specification.
+
+ As used hereunder, "Licensed Products" means only those specific portions
+ of products (hardware, software or combinations thereof) that implement
+ and are compliant with all relevant portions of the Advanced Messaging
+ Queue Protocol Specification.
+
+ The following disclaimers, which you hereby also acknowledge as to any
+ use you may make of the Advanced Messaging Queue Protocol Specification:
+
+ THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION IS PROVIDED "AS IS,"
+ AND THE AUTHORS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+ IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE
+ CONTENTS OF THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION ARE
+ SUITABLE FOR ANY PURPOSE; NOR THAT THE IMPLEMENTATION OF THE ADVANCED
+ MESSAGING QUEUE PROTOCOL SPECIFICATION WILL NOT INFRINGE ANY THIRD PARTY
+ PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
+
+ THE AUTHORS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL,
+ INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO ANY
+ USE, IMPLEMENTATION OR DISTRIBUTION OF THE ADVANCED MESSAGING QUEUE
+ PROTOCOL SPECIFICATION.
+
+ The name and trademarks of the Authors may NOT be used in any manner,
+ including advertising or publicity pertaining to the Advanced Messaging
+ Queue Protocol Specification or its contents without specific, written
+ prior permission. Title to copyright in the Advanced Messaging Queue
+ Protocol Specification will at all times remain with the Authors.
+
+ No other rights are granted by implication, estoppel or otherwise.
+
+ Upon termination of your license or rights under this Agreement, you
+ shall destroy all copies of the Advanced Messaging Queue Protocol
+ Specification in your possession or control.
+
+ Trademarks
+ ==========
+ "JPMorgan", "JPMorgan Chase", "Chase", the JPMorgan Chase logo and the
+ Octagon Symbol are trademarks of JPMorgan Chase & Co.
+
+ IMATIX and the iMatix logo are trademarks of iMatix Corporation sprl.
+
+ IONA, IONA Technologies, and the IONA logos are trademarks of IONA
+ Technologies PLC and/or its subsidiaries.
+
+ LINUX is a trademark of Linus Torvalds. RED HAT and JBOSS are registered
+ trademarks of Red Hat, Inc. in the US and other countries.
+
+ Java, all Java-based trademarks and OpenOffice.org are trademarks of
+ Sun Microsystems, Inc. in the United States, other countries, or both.
+
+ Other company, product, or service names may be trademarks or service
+ marks of others.
+
+ Links to full AMQP specification:
+ =================================
+ http://www.envoytech.org/spec/amq/
+ http://www.iona.com/opensource/amqp/
+ http://www.redhat.com/solutions/specifications/amqp/
+ http://www.twiststandards.org/tiki-index.php?page=AMQ
+ http://www.imatix.com/amqp
diff --git a/specs/NOTICE b/specs/NOTICE
new file mode 100644
index 0000000000..0e59eb3131
--- /dev/null
+++ b/specs/NOTICE
@@ -0,0 +1,7 @@
+// ------------------------------------------------------------------
+// NOTICE file corresponding to the section 4d of The Apache License,
+// Version 2.0,
+// ------------------------------------------------------------------
+
+Apache Qpid
+Copyright 2006-2008 Apache Software Foundation
diff --git a/specs/amqp.0-10-qpid-errata.xml b/specs/amqp.0-10-qpid-errata.xml
index 1b15588a5e..365928ea4e 100644
--- a/specs/amqp.0-10-qpid-errata.xml
+++ b/specs/amqp.0-10-qpid-errata.xml
@@ -1912,6 +1912,8 @@
is idle. If a connection is idle for more than twice the negotiated heartbeat delay, the
peers MAY be considered disconnected.
</doc>
+ <implement role="client" handle="MAY" />
+ <implement role="server" handle="MAY" />
</control>
<!-- - Control: connection.close - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
diff --git a/specs/amqp.0-9.xml b/specs/amqp.0-9.xml
index 1615fea99d..73cace7015 100644
--- a/specs/amqp.0-9.xml
+++ b/specs/amqp.0-9.xml
@@ -1659,29 +1659,28 @@
<doc>This method confirms the deletion of an exchange.</doc>
<chassis name = "client" implement = "MUST" />
</method>
-
- <!-- RG : Added Exchange.bound and Exchange.bound-ok -->
- <method name="bound" synchronous="1" index="22">
- <chassis name="server" implement="SHOULD"/>
- <field name="exchange" domain="exchange-name"/>
- <field name = "routing-key" type = "shortstr">
- Message routing key
- <doc>
- Specifies the routing key for the message. The routing key is
- used for routing messages depending on the exchange configuration.
- </doc>
- </field>
- <field name = "queue" domain = "queue name"/>
+
+ <!-- RG : Added Exchange.bound and Exchange.bound-ok -->
+ <method name="bound" synchronous="1" index="22">
+ <chassis name="server" implement="SHOULD"/>
+ <response name="bound-ok"/>
+ <field name="exchange" domain="exchange-name"/>
+ <field name = "routing-key" type = "shortstr">
+ Message routing key
+ <doc>
+ Specifies the routing key for the message. The routing key is
+ used for routing messages depending on the exchange configuration.
+ </doc>
+ </field>
+ <field name = "queue" domain = "queue name"/>
</method>
<method name="bound-ok" synchronous="1" index="23">
- <field name="reply-code" domain="reply-code"/>
- <field name="reply-text" domain="reply-text"/>
- <chassis name="client" implement="SHOULD"/>
+ <field name="reply-code" domain="reply-code"/>
+ <field name="reply-text" domain="reply-text"/>
+ <chassis name="client" implement="SHOULD"/>
</method>
-
-
</class>
<!-- == QUEUE ============================================================ -->
diff --git a/specs/amqp.1-0-draft.dtd b/specs/amqp.1-0-draft.dtd
deleted file mode 100644
index 2be198525a..0000000000
--- a/specs/amqp.1-0-draft.dtd
+++ /dev/null
@@ -1,246 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
- Copyright Notice
- ================
- (c) Copyright Cisco Systems, Credit Suisse, Deutsche Börse Systems, Envoy Technologies, Inc.,
- Goldman Sachs, IONA Technologies PLC, iMatix Corporation sprl.,JPMorgan Chase Bank Inc. N.A,
- Novell, Rabbit Technologies Ltd., Red Hat, Inc., TWIST Process Innovations ltd, and 29West Inc
- 2006, 2007. All rights reserved.
-
- License
- =======
- JPMorgan Chase Bank & Co., Cisco Systems, Inc., Envoy Technologies Inc., iMatix Corporation, IONA
- Technologies, Red Hat, Inc., TWIST Process Innovations, and 29West Inc. (collectively, the
- "Authors") each hereby grants to you a worldwide, perpetual, royalty-free, nontransferable,
- nonexclusive license to (i) copy, display, distribute and implement the Advanced Messaging Queue
- Protocol ("AMQP") Specification and (ii) the Licensed Claims that are held by the Authors, all for
- the purpose of implementing the Advanced Messaging Queue Protocol Specification. Your license and
- any rights under this Agreement will terminate immediately without notice from any Author if you
- bring any claim, suit, demand, or action related to the Advanced Messaging Queue Protocol
- Specification against any Author. Upon termination, you shall destroy all copies of the Advanced
- Messaging Queue Protocol Specification in your possession or control.
-
- As used hereunder, "Licensed Claims" means those claims of a patent or patent application,
- throughout the world, excluding design patents and design registrations, owned or controlled, or
- that can be sublicensed without fee and in compliance with the requirements of this Agreement, by
- an Author or its affiliates now or at any future time and which would necessarily be infringed by
- implementation of the Advanced Messaging Queue Protocol Specification. A claim is necessarily
- infringed hereunder only when it is not possible to avoid infringing it because there is no
- plausible non-infringing alternative for implementing the required portions of the Advanced
- Messaging Queue Protocol Specification. Notwithstanding the foregoing, Licensed Claims shall not
- include any claims other than as set forth above even if contained in the same patent as Licensed
- Claims; or that read solely on any implementations of any portion of the Advanced Messaging Queue
- Protocol Specification that are not required by the Advanced Messaging Queue Protocol
- Specification, or that, if licensed, would require a payment of royalties by the licensor to
- unaffiliated third parties. Moreover, Licensed Claims shall not include (i) any enabling
- technologies that may be necessary to make or use any Licensed Product but are not themselves
- expressly set forth in the Advanced Messaging Queue Protocol Specification (e.g., semiconductor
- manufacturing technology, compiler technology, object oriented technology, networking technology,
- operating system technology, and the like); or (ii) the implementation of other published
- standards developed elsewhere and merely referred to in the body of the Advanced Messaging Queue
- Protocol Specification, or (iii) any Licensed Product and any combinations thereof the purpose or
- function of which is not required for compliance with the Advanced Messaging Queue Protocol
- Specification. For purposes of this definition, the Advanced Messaging Queue Protocol
- Specification shall be deemed to include both architectural and interconnection requirements
- essential for interoperability and may also include supporting source code artifacts where such
- architectural, interconnection requirements and source code artifacts are expressly identified as
- being required or documentation to achieve compliance with the Advanced Messaging Queue Protocol
- Specification.
-
- As used hereunder, "Licensed Products" means only those specific portions of products (hardware,
- software or combinations thereof) that implement and are compliant with all relevant portions of
- the Advanced Messaging Queue Protocol Specification.
-
- The following disclaimers, which you hereby also acknowledge as to any use you may make of the
- Advanced Messaging Queue Protocol Specification:
-
- THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION IS PROVIDED "AS IS," AND THE AUTHORS MAKE NO
- REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE CONTENTS
- OF THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION ARE SUITABLE FOR ANY PURPOSE; NOR THAT THE
- IMPLEMENTATION OF THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION WILL NOT INFRINGE ANY THIRD
- PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
-
- THE AUTHORS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
- DAMAGES ARISING OUT OF OR RELATING TO ANY USE, IMPLEMENTATION OR OF THE ADVANCED
- MESSAGING QUEUE PROTOCOL SPECIFICATION.
-
- The name and trademarks of the Authors may NOT be used in any manner, including advertising or
- publicity pertaining to the Advanced Messaging Queue Protocol Specification or its contents
- without specific, written prior permission. Title to copyright in the Advanced Messaging Queue
- Protocol Specification will at all times remain with the Authors.
-
- No other rights are granted by implication, estoppel or otherwise.
-
- Upon termination of your license or rights under this Agreement, you shall destroy all copies of
- the Advanced Messaging Queue Protocol Specification in your possession or control.
-
- Trademarks
- ==========
- "JPMorgan", "JPMorgan Chase", "Chase", the JPMorgan Chase logo and the Octagon Symbol are
- trademarks of JPMorgan Chase & Co.
-
- IMATIX and the iMatix logo are trademarks of iMatix Corporation sprl.
-
- IONA, IONA Technologies, and the IONA logos are trademarks of IONA Technologies PLC and/or its
- subsidiaries.
-
- LINUX is a trademark of Linus Torvalds. RED HAT and JBOSS are registered trademarks of Red Hat,
- Inc. in the US and other countries.
-
- Java, all Java-based trademarks and OpenOffice.org are trademarks of Sun Microsystems, Inc. in the
- United States, other countries, or both.
-
- Other company, product, or service names may be trademarks or service marks of others.
-
- Links to full AMQP specification:
- =================================
- http://www.envoytech.org/spec/amq/
- http://www.iona.com/opensource/amqp/
- http://www.redhat.com/solutions/specifications/amqp/
- http://www.twiststandards.org/tiki-index.php?page=AMQ
- http://www.imatix.com/amqp
--->
-
-<!ELEMENT amqp (doc|type|struct|domain|constant|class)*>
-<!ATTLIST amqp
- xmlns CDATA #IMPLIED
- major CDATA #REQUIRED
- minor CDATA #REQUIRED
- port CDATA #REQUIRED
- comment CDATA #IMPLIED
->
-
-<!ELEMENT constant (doc|rule)*>
-<!ATTLIST constant
- name CDATA #REQUIRED
- value CDATA #REQUIRED
- label CDATA #IMPLIED
->
-
-<!ELEMENT type (doc|rule)*>
-<!ATTLIST type
- name CDATA #REQUIRED
- label CDATA #IMPLIED
- code CDATA #IMPLIED
- fixed-width CDATA #IMPLIED
- variable-width CDATA #IMPLIED
->
-
-<!ELEMENT domain (doc|rule|enum)*>
-<!ATTLIST domain
- name CDATA #REQUIRED
- type CDATA #IMPLIED
- label CDATA #IMPLIED
->
-
-<!ELEMENT struct (field|doc|rule)*>
-<!ATTLIST struct
- name CDATA #REQUIRED
- label CDATA #IMPLIED
- size (0|1|2|4) #IMPLIED
- pack (0|1|2|4) #IMPLIED
- code CDATA #IMPLIED>
-
-<!ELEMENT enum (choice)*>
-
-<!ELEMENT choice (doc|rule)*>
-<!ATTLIST choice
- name CDATA #REQUIRED
- value CDATA #REQUIRED
->
-
-<!ELEMENT class (doc|role|rule|struct|domain|control|command)*>
-<!ATTLIST class
- name CDATA #REQUIRED
- code CDATA #REQUIRED
- label CDATA #IMPLIED
->
-
-<!ELEMENT role (doc|rule)*>
-<!ATTLIST role
- name CDATA #REQUIRED
- implement (MAY|SHOULD|MUST) #REQUIRED
->
-
-<!ELEMENT control (doc|implement|rule|field|response)*>
-<!ATTLIST control
- name CDATA #REQUIRED
- code CDATA #REQUIRED
- label CDATA #IMPLIED
->
-
-<!ELEMENT command ((doc|implement|rule|exception|field|response)*, result?, segments?)>
-<!ATTLIST command
- name CDATA #REQUIRED
- code CDATA #REQUIRED
- label CDATA #IMPLIED
->
-
-<!ELEMENT implement (doc|rule)*>
-<!ATTLIST implement
- role CDATA #REQUIRED
- handle (MAY|SHOULD|MUST) #REQUIRED
- send (MAY|SHOULD|MUST) #IMPLIED
->
-
-<!ELEMENT field (doc|rule|exception)*>
-<!ATTLIST field
- name CDATA #REQUIRED
- type CDATA #IMPLIED
- default CDATA #IMPLIED
- code CDATA #IMPLIED
- label CDATA #IMPLIED
- required CDATA #IMPLIED
->
-
-<!ELEMENT rule (doc*)>
-<!ATTLIST rule
- name CDATA #REQUIRED
- label CDATA #IMPLIED
->
-
-<!ELEMENT exception (doc*)>
-<!ATTLIST exception
- name CDATA #REQUIRED
- error-code CDATA #IMPLIED
- label CDATA #IMPLIED
->
-
-<!ELEMENT response (doc|rule)*>
-<!ATTLIST response
- name CDATA #IMPLIED
->
-
-<!ELEMENT result (doc|rule|struct)*>
-<!ATTLIST result
- type CDATA #IMPLIED
->
-
-<!ELEMENT segments (doc|rule|header|body)*>
-
-<!ELEMENT header (doc|rule|entry)*>
-<!ATTLIST header
- required (true|false) #IMPLIED
->
-
-<!ELEMENT entry (doc|rule)*>
-<!ATTLIST entry
- type CDATA #REQUIRED
->
-
-<!ELEMENT body (doc|rule)*>
-<!ATTLIST body
- required (true|false) #IMPLIED
->
-
-<!ELEMENT doc (#PCDATA|xref)*>
-<!ATTLIST doc
- type (grammar|scenario|picture|bnf|todo) #IMPLIED
- title CDATA #IMPLIED
->
-
-<!ELEMENT xref (#PCDATA)>
-<!ATTLIST xref
- ref CDATA #REQUIRED>
diff --git a/specs/amqp.1-0-draft.xml b/specs/amqp.1-0-draft.xml
deleted file mode 100644
index cdca7da05b..0000000000
--- a/specs/amqp.1-0-draft.xml
+++ /dev/null
@@ -1,5102 +0,0 @@
-<?xml version="1.0"?>
-
-<!--
- Copyright Notice
- ================
- (c) Copyright Cisco Systems, Credit Suisse, Deutsche Borse Systems, Envoy Technologies, Inc.,
- Goldman Sachs, IONA Technologies PLC, iMatix Corporation sprl.,JPMorgan Chase Bank Inc. N.A,
- Novell, Rabbit Technologies Ltd., Red Hat, Inc., TWIST Process Innovations ltd, and 29West Inc.
- 2006, 2007. All rights reserved.
-
- License
- =======
-
- Cisco Systems, Credit Suisse, Deutsche Borse Systems, Envoy Technologies, Inc.,Goldman Sachs,
- IONA Technologies PLC, iMatix Corporation sprl.,JPMorgan Chase Bank Inc. N.A, Novell, Rabbit
- Technologies Ltd., Red Hat, Inc., TWIST Process Innovations ltd, and 29West Inc. (collectively,
- the "Authors") each hereby grants to you a worldwide, perpetual, royalty-free, nontransferable,
- nonexclusive license to (i) copy, display, distribute and implement the Advanced Messaging Queue
- Protocol ("AMQP") Specification and (ii) the Licensed Claims that are held by the Authors, all for
- the purpose of implementing the Advanced Messaging Queue Protocol Specification. Your license and
- any rights under this Agreement will terminate immediately without notice from any Author if you
- bring any claim, suit, demand, or action related to the Advanced Messaging Queue Protocol
- Specification against any Author. Upon termination, you shall destroy all copies of the Advanced
- Messaging Queue Protocol Specification in your possession or control.
-
- As used hereunder, "Licensed Claims" means those claims of a patent or patent application,
- throughout the world, excluding design patents and design registrations, owned or controlled, or
- that can be sublicensed without fee and in compliance with the requirements of this Agreement, by
- an Author or its affiliates now or at any future time and which would necessarily be infringed by
- implementation of the Advanced Messaging Queue Protocol Specification. A claim is necessarily
- infringed hereunder only when it is not possible to avoid infringing it because there is no
- plausible non-infringing alternative for implementing the required portions of the Advanced
- Messaging Queue Protocol Specification. Notwithstanding the foregoing, Licensed Claims shall not
- include any claims other than as set forth above even if contained in the same patent as Licensed
- Claims; or that read solely on any implementations of any portion of the Advanced Messaging Queue
- Protocol Specification that are not required by the Advanced Messaging Queue Protocol
- Specification, or that, if licensed, would require a payment of royalties by the licensor to
- unaffiliated third parties. Moreover, Licensed Claims shall not include (i) any enabling
- technologies that may be necessary to make or use any Licensed Product but are not themselves
- expressly set forth in the Advanced Messaging Queue Protocol Specification (e.g., semiconductor
- manufacturing technology, compiler technology, object oriented technology, networking technology,
- operating system technology, and the like); or (ii) the implementation of other published
- standards developed elsewhere and merely referred to in the body of the Advanced Messaging Queue
- Protocol Specification, or (iii) any Licensed Product and any combinations thereof the purpose or
- function of which is not required for compliance with the Advanced Messaging Queue Protocol
- Specification. For purposes of this definition, the Advanced Messaging Queue Protocol
- Specification shall be deemed to include both architectural and interconnection requirements
- essential for interoperability and may also include supporting source code artifacts where such
- architectural, interconnection requirements and source code artifacts are expressly identified as
- being required or documentation to achieve compliance with the Advanced Messaging Queue Protocol
- Specification.
-
- As used hereunder, "Licensed Products" means only those specific portions of products (hardware,
- software or combinations thereof) that implement and are compliant with all relevant portions of
- the Advanced Messaging Queue Protocol Specification.
-
- The following disclaimers, which you hereby also acknowledge as to any use you may make of the
- Advanced Messaging Queue Protocol Specification:
-
- THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION IS PROVIDED "AS IS," AND THE AUTHORS MAKE NO
- REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE CONTENTS
- OF THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION ARE SUITABLE FOR ANY PURPOSE; NOR THAT THE
- IMPLEMENTATION OF THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION WILL NOT INFRINGE ANY THIRD
- PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
-
- THE AUTHORS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
- DAMAGES ARISING OUT OF OR RELATING TO ANY USE, IMPLEMENTATION OR DISTRIBUTION OF THE ADVANCED
- MESSAGING QUEUE PROTOCOL SPECIFICATION.
-
- The name and trademarks of the Authors may NOT be used in any manner, including advertising or
- publicity pertaining to the Advanced Messaging Queue Protocol Specification or its contents
- without specific, written prior permission. Title to copyright in the Advanced Messaging Queue
- Protocol Specification will at all times remain with the Authors.
-
- No other rights are granted by implication, estoppel or otherwise.
-
- Upon termination of your license or rights under this Agreement, you shall destroy all copies of
- the Advanced Messaging Queue Protocol Specification in your possession or control.
-
- Trademarks
- ==========
- "JPMorgan", "JPMorgan Chase", "Chase", the JPMorgan Chase logo and the Octagon Symbol are
- trademarks of JPMorgan Chase & Co.
-
- IMATIX and the iMatix logo are trademarks of iMatix Corporation sprl.
-
- IONA, IONA Technologies, and the IONA logos are trademarks of IONA Technologies PLC and/or its
- subsidiaries.
-
- LINUX is a trademark of Linus Torvalds. RED HAT and JBOSS are registered trademarks of Red Hat,
- Inc. in the US and other countries.
-
- Java, all Java-based trademarks and OpenOffice.org are trademarks of Sun Microsystems, Inc. in the
- United States, other countries, or both.
-
- Other company, product, or service names may be trademarks or service marks of others.
-
- Links to full AMQP specification:
- =================================
- http://www.envoytech.org/spec/amq/
- http://www.iona.com/opensource/amqp/
- http://www.redhat.com/solutions/specifications/amqp/
- http://www.twiststandards.org/tiki-index.php?page=AMQ
- http://www.imatix.com/amqp
--->
-
-<!--
- XML Notes
- =========
-
- We use entities to indicate repetition; attributes to indicate properties.
-
- We use the "name" attribute as an identifier, usually within the context of the surrounding
- entities.
-
- We use hyphens (minus char '-') to seperate words in names.
-
- We do not enforce any particular validation mechanism but we support all mechanisms. The protocol
- definition conforms to a formal grammar that is published seperately in several technologies.
-
--->
-
-<!DOCTYPE amqp SYSTEM "amqp.1-0-draft.dtd">
-
-<amqp xmlns="http://www.amqp.org/schema/amqp.xsd"
- major="99" minor="0" port="5672" comment="working version">
-
- <!--
- ====================== == type definitions == ======================
- -->
-
- <!--
- 0x00 - 0x0f: Fixed width, 1 octet
- -->
-
- <type name="bin8" code="0x00" fixed-width="1" label="octet of unspecified encoding">
- <doc>
- The bin8 type consists of exactly one octet of opaque binary data.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET
- +----------+
- | bin8 |
- +----------+
- </doc>
-
- <doc type="bnf">
- bin8 = OCTET
- </doc>
- </type>
-
- <type name="int8" code="0x01" fixed-width="1" label="8-bit signed integral value (-128 - 127)">
- <doc>
- The int8 type is a signed integral value encoded using an 8-bit two's complement
- representation.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET
- +----------+
- | int8 |
- +----------+
- </doc>
-
- <doc type="bnf">
- int8 = OCTET
- </doc>
- </type>
-
- <type name="uint8" code="0x02" fixed-width="1" label="8-bit unsigned integral value (0 - 255)">
- <doc>
- The uint8 type is an 8-bit unsigned integral value.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET
- +---------+
- | uint8 |
- +---------+
- </doc>
-
- <doc type="bnf">
- uint8 = OCTET
- </doc>
- </type>
-
- <type name="char" code="0x04" fixed-width="1" label="an iso-8859-15 character">
- <doc>
- The char type encodes a single character from the iso-8859-15 character set.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET
- +----------+
- | char |
- +----------+
- </doc>
-
- <doc type="bnf">
- char = OCTET
- </doc>
- </type>
-
- <type name="boolean" code="0x08" fixed-width="1"
- label="boolean value (zero represents false, nonzero represents true)">
- <doc>
- The boolean type is a single octet that encodes a true or false value. If the octet is zero,
- then the boolean is false. Any other value represents true.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET
- +---------+
- | boolean |
- +---------+
- </doc>
-
- <doc type="bnf">
- boolean = OCTET
- </doc>
- </type>
-
- <!--
- 0x10 - 0x1f: Fixed width, 2 octets
- -->
-
- <type name="bin16" code="0x10" fixed-width="2" label="two octets of unspecified binary encoding">
- <doc>
- The bin16 type consists of two consecutive octets of opaque binary data.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET 1 OCTET
- +-----------+-----------+
- | octet-one | octet-two |
- +-----------+-----------+
- </doc>
-
- <doc type="bnf">
- bin16 = 2 OCTET
- </doc>
- </type>
-
- <type name="int16" code="0x11" fixed-width="2" label="16-bit signed integral value">
- <doc>
- The int16 type is a signed integral value encoded using a 16-bit two's complement
- representation in network byte order.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET 1 OCTET
- +-----------+----------+
- | high-byte | low-byte |
- +-----------+----------+
- </doc>
-
- <doc type="bnf">
- int16 = high-byte low-byte
- high-byte = OCTET
- low-byte = OCTET
- </doc>
- </type>
-
- <type name="uint16" code="0x12" fixed-width="2" label="16-bit unsigned integer">
- <doc>
- The uint16 type is a 16-bit unsigned integral value encoded in network byte order.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET 1 OCTET
- +-----------+----------+
- | high-byte | low-byte |
- +-----------+----------+
- </doc>
-
- <doc type="bnf">
- uint16 = high-byte low-byte
- high-byte = OCTET
- low-byte = OCTET
- </doc>
- </type>
-
- <type name="channel" fixed-width="2" label="channel identifier">
- <doc>
- The channel type identifies both a direction and a 15 bit channel number packed into a 16 bit
- value. The channel number may be computed by treating the channel identifier as a uint16 and
- masking off the most significant bit. The most significant bit of the channel identifier
- indicates the direction of the channel. If this bit is zero, the channel identifier refers to
- a channel number where the initiator of the network connection (i.e. the network client) is
- the AMQP client. If this bit is one, the channel identifier refers to a channel number where
- the initiator of the network connection (i.e. the network client) is the AMQP server.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 BIT 15 BITs
- +-----------+----------------+
- | direction | channel-number |
- +-----------+----------------+
- MSB LSB
- </doc>
-
- <doc type="bnf">
- channel = direction channel-number
- direction = 1 BIT
- channel-number = 15 BIT
- </doc>
- </type>
-
- <!--
- 0x20 - 0x2f: Fixed width, 4 octets
- -->
-
- <type name="bin32" code="0x20" fixed-width="4" label="four octets of unspecified binary encoding">
- <doc>
- The bin32 type consists of 4 consecutive octets of opaque binary data.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET 1 OCTET 1 OCTET 1 OCTET
- +-----------+-----------+-------------+------------+
- | octet-one | octet-two | octet-three | octet-four |
- +-----------+-----------+-------------+------------+
- </doc>
-
- <doc type="bnf">
- bin32 = 4 OCTET
- </doc>
- </type>
-
- <type name="int32" code="0x21" fixed-width="4" label="32-bit signed integral value">
- <doc>
- The int32 type is a signed integral value encoded using a 32-bit two's complement
- representation in network byte order.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET 1 OCTET 1 OCTET 1 OCTET
- +-----------+------------+----------+----------+
- | byte-four | byte-three | byte-two | byte-one |
- +-----------+------------+----------+----------+
- MSB LSB
- </doc>
-
- <doc type="bnf">
- int32 = byte-four byte-three byte-two byte-one
- byte-four = OCTET ; most significant byte (MSB)
- byte-three = OCTET
- byte-two = OCTET
- byte-one = OCTET ; least significant byte (LSB)
- </doc>
- </type>
-
- <type name="uint32" code="0x22" fixed-width="4" label="32-bit unsigned integral value">
- <doc>
- The uint32 type is a 32-bit unsigned integral value encoded in network byte order.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET 1 OCTET 1 OCTET 1 OCTET
- +-----------+------------+----------+----------+
- | byte-four | byte-three | byte-two | byte-one |
- +-----------+------------+----------+----------+
- MSB LSB
- </doc>
-
- <doc type="bnf">
- uint32 = byte-four byte-three byte-two byte-one
- byte-four = OCTET ; most significant byte (MSB)
- byte-three = OCTET
- byte-two = OCTET
- byte-one = OCTET ; least significant byte (LSB)
- </doc>
- </type>
-
- <type name="float" code="0x23" fixed-width="4"
- label="single precision IEEE 754 32-bit floating point">
- <doc>
- The float type encodes a single precision 32-bit floating point number. The format and
- operations are defined by the IEEE 754 standard for 32-bit floating point numbers.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 4 OCTETs
- +-----------------------+
- | float |
- +-----------------------+
- IEEE 754 32-bit float
- </doc>
-
- <doc type="bnf">
- float = 4 OCTET ; IEEE 754 32-bit floating point number
- </doc>
- </type>
-
- <type name="char-utf32" code="0x27" fixed-width="4"
- label="single unicode character in UTF-32 encoding">
- <doc>
- The char-utf32 type consists of a single unicode character in the UTF-32 encoding.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 4 OCTETs
- +------------------+
- | char-utf32 |
- +------------------+
- UTF-32 character
- </doc>
-
- <doc type="bnf">
- char-utf32 = 4 OCTET ; single UTF-32 character
- </doc>
- </type>
-
- <type name="sequence-no" fixed-width="4" label="serial number defined in RFC-1982">
- <doc>
- The sequence-no type encodes, in network byte order, a serial number as defined in RFC-1982.
- The arithmetic, operators, and ranges for numbers of this type are defined by RFC-1982.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 4 OCTETs
- +------------------------+
- | sequence-no |
- +------------------------+
- RFC-1982 serial number
- </doc>
-
- <doc type="bnf">
- sequence-no = 4 OCTET ; RFC-1982 serial number
- </doc>
- </type>
-
- <!--
- 0x30 - 0x3f: Fixed width types - 8 octets
- -->
-
- <type name="bin64" code="0x30" fixed-width="8"
- label="eight octets of unspecified binary encoding">
- <doc>
- The bin64 type consists of eight consecutive octets of opaque binary data.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET 1 OCTET 1 OCTET 1 OCTET
- +-----------+-----------+-----+-------------+-------------+
- | octet-one | octet-two | ... | octet-seven | octet-eight |
- +-----------+-----------+-----+-------------+-------------+
- </doc>
-
- <doc type="bnf">
- bin64 = 8 OCTET
- </doc>
- </type>
-
- <type name="int64" code="0x31" fixed-width="8" label="64-bit signed integral value">
- <doc>
- The int64 type is a signed integral value encoded using a 64-bit two's complement
- representation in network byte order.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET 1 OCTET 1 OCTET 1 OCTET
- +------------+------------+-----+----------+----------+
- | byte-eight | byte-seven | ... | byte-two | byte-one |
- +------------+------------+-----+----------+----------+
- MSB LSB
- </doc>
-
- <doc type="bnf">
- int64 = byte-eight byte-seven byte-six byte-five
- byte-four byte-three byte-two byte-one
- byte-eight = 1 OCTET ; most significant byte (MSB)
- byte-seven = 1 OCTET
- byte-six = 1 OCTET
- byte-five = 1 OCTET
- byte-four = 1 OCTET
- byte-three = 1 OCTET
- byte-two = 1 OCTET
- byte-one = 1 OCTET ; least significant byte (LSB)
- </doc>
- </type>
-
- <type name="uint64" code="0x32" fixed-width="8" label="64-bit unsigned integral value">
- <doc>
- The uint64 type is a 64-bit unsigned integral value encoded in network byte order.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET 1 OCTET 1 OCTET 1 OCTET
- +------------+------------+-----+----------+----------+
- | byte-eight | byte-seven | ... | byte-two | byte-one |
- +------------+------------+-----+----------+----------+
- MSB LSB
- </doc>
-
- <doc type="bnf">
- uint64 = byte-eight byte-seven byte-six byte-five
- byte-four byte-three byte-two byte-one
- byte-eight = 1 OCTET ; most significant byte (MSB)
- byte-seven = 1 OCTET
- byte-six = 1 OCTET
- byte-five = 1 OCTET
- byte-four = 1 OCTET
- byte-three = 1 OCTET
- byte-two = 1 OCTET
- byte-one = 1 OCTET ; least significant byte (LSB)
- </doc>
- </type>
-
- <type name="double" code="0x33" fixed-width="8" label="double precision IEEE 754 floating point">
- <doc>
- The double type encodes a double precision 64-bit floating point number. The format and
- operations are defined by the IEEE 754 standard for 64-bit double precision floating point
- numbers.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 8 OCTETs
- +-----------------------+
- | double |
- +-----------------------+
- IEEE 754 64-bit float
- </doc>
-
- <doc type="bnf">
- double = 8 OCTET ; double precision IEEE 754 floating point number
- </doc>
- </type>
-
- <type name="datetime" code="0x38" fixed-width="8" label="datetime in 64 bit POSIX time_t format">
- <doc>
- The datetime type encodes a date and time using the 64 bit POSIX time_t format.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 8 OCTETs
- +---------------------+
- | datetime |
- +---------------------+
- posix time_t format
- </doc>
-
- <doc type="bnf">
- datetime = 8 OCTET ; 64 bit posix time_t format
- </doc>
- </type>
-
- <!--
- 0x40 - 0x4f: Fixed width types - 16 octets
- -->
-
- <type name="bin128" code="0x40" fixed-width="16"
- label="sixteen octets of unspecified binary encoding">
- <doc>
- The bin128 type consists of 16 consecutive octets of opaque binary data.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET 1 OCTET 1 OCTET 1 OCTET
- +-----------+-----------+-----+---------------+---------------+
- | octet-one | octet-two | ... | octet-fifteen | octet-sixteen |
- +-----------+-----------+-----+---------------+---------------+
- </doc>
-
- <doc type="bnf">
- bin128 = 16 OCTET
- </doc>
- </type>
-
- <type name="uuid" code="0x48" fixed-width="16" label="UUID (RFC-4122 section 4.1.2) - 16 octets">
- <doc>
- The uuid type encodes a universally unique id as defined by RFC-4122. The format and
- operations for this type can be found in section 4.1.2 of RFC-4122.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 16 OCTETs
- +---------------+
- | uuid |
- +---------------+
- RFC-4122 UUID
- </doc>
-
- <doc type="bnf">
- uuid = 16 OCTET ; RFC-4122 section 4.1.2
- </doc>
- </type>
-
- <!--
- 0x50 - 0x5f: Fixed width types - 32 octets
- -->
-
- <type name="bin256" code="0x50" fixed-width="32"
- label="thirty two octets of unspecified binary encoding">
- <doc>
- The bin256 type consists of thirty two consecutive octets of opaque binary data.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET 1 OCTET 1 OCTET 1 OCTET
- +-----------+-----------+-----+------------------+------------------+
- | octet-one | octet-two | ... | octet-thirty-one | octet-thirty-two |
- +-----------+-----------+-----+------------------+------------------+
- </doc>
-
- <doc type="bnf">
- bin256 = 32 OCTET
- </doc>
- </type>
-
- <!--
- 0x60 - 0x6f: Fixed width types - 64 octets
- -->
-
- <type name="bin512" code="0x60" fixed-width="64"
- label="sixty four octets of unspecified binary encoding">
- <doc>
- The bin512 type consists of sixty four consecutive octets of opaque binary data.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET 1 OCTET 1 OCTET 1 OCTET
- +-----------+-----------+-----+-------------------+------------------+
- | octet-one | octet-two | ... | octet-sixty-three | octet-sixty-four |
- +-----------+-----------+-----+-------------------+------------------+
- </doc>
-
- <doc type="bnf">
- bin512 = 64 OCTET
- </doc>
- </type>
-
- <!--
- 0x70 - 0x7f: Fixed width types - 128 octets
- -->
-
- <type name="bin1024" code="0x70" fixed-width="128"
- label="one hundred and twenty eight octets of unspecified binary encoding">
- <doc>
- The bin1024 type consists of one hundred and twenty eight octets of opaque binary data.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET 1 OCTET 1 OCTET 1 OCTET
- +-----------+-----------+-----+------------------------+------------------------+
- | octet-one | octet-two | ... | octet-one-twenty-seven | octet-one-twenty-eight |
- +-----------+-----------+-----+------------------------+------------------------+
- </doc>
-
- <doc type="bnf">
- bin1024 = 128 OCTET
- </doc>
- </type>
-
- <!--
- 0x80 - 0x8f: Variable length - one byte length field (up to 255 octets)
- -->
-
- <type name="vbin8" code="0x80" variable-width="1" label="up to 255 octets of opaque binary data">
- <doc>
- The vbin8 type encodes up to 255 octets of opaque binary data. The number of octets is first
- encoded as an 8-bit unsigned integral value. This is followed by the actual data.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET size OCTETs
- +---------+-------------+
- | size | octets |
- +---------+-------------+
- uint8
- </doc>
-
- <doc type="bnf">
- vbin8 = size octets
- size = uint8
- octets = 0*255 OCTET ; size OCTETs
- </doc>
- </type>
-
- <type name="str8-latin" code="0x84" variable-width="1" label="up to 255 iso-8859-15 characters">
- <doc>
- The str8-latin type encodes up to 255 octets of iso-8859-15 characters. The number of octets
- is first encoded as an 8-bit unsigned integral value. This is followed by the actual
- characters.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET size OCTETs
- +---------+------------------------+
- | size | characters |
- +---------+------------------------+
- uint16 iso-8859-15 characters
- </doc>
-
- <doc type="bnf">
- str8-latin = size characters
- size = uint8
- characters = 0*255 OCTET ; size OCTETs
- </doc>
- </type>
-
- <type name="str8" code="0x85" variable-width="1" label="up to 255 octets worth of UTF-8 unicode">
- <doc>
- The str8 type encodes up to 255 octets worth of UTF-8 unicode. The number of octets of unicode
- is first encoded as an 8-bit unsigned integral value. This is followed by the actual UTF-8
- unicode. Note that the encoded size refers to the number of octets of unicode, not necessarily
- the number of characters since the UTF-8 unicode may include multi-byte character sequences.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET size OCTETs
- +---------+--------------+
- | size | utf8-unicode |
- +---------+--------------+
- uint8
- </doc>
-
- <doc type="bnf">
- str8 = size utf8-unicode
- size = uint8
- utf8-unicode = 0*255 OCTET ; size OCTETs
- </doc>
- </type>
-
- <type name="str8-utf16" code="0x86" variable-width="1"
- label="up to 255 octets worth of UTF-16 unicode">
- <doc>
- The str8-utf16 type encodes up to 255 octets worth of UTF-16 unicode. The number of octets of
- unicode is first encoded as an 8-bit unsigned integral value. This is followed by the actual
- UTF-16 unicode. Note that the encoded size refers to the number of octets of unicode, not the
- number of characters since the UTF-16 unicode will include at least two octets per unicode
- character.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET size OCTETs
- +---------+---------------+
- | size | utf16-unicode |
- +---------+---------------+
- uint8
- </doc>
-
- <doc type="bnf">
- str8-utf16 = size utf16-unicode
- size = uint8
- utf16-unicode = 0*255 OCTET ; size OCTETs
- </doc>
- </type>
-
- <!--
- 0x90 - 0x9f: Variable length types - two byte length field (up to 65535 octets)
- -->
-
- <type name="vbin16" code="0x90" variable-width="2"
- label="up to 65535 octets of opaque binary data">
- <doc>
- The vbin16 type encodes up to 65535 octets of opaque binary data. The number of octets is
- first encoded as a 16-bit unsigned integral value in network byte order. This is followed by
- the actual data.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 2 OCTETs size OCTETs
- +----------+-------------+
- | size | octets |
- +----------+-------------+
- uint16
- </doc>
-
- <doc type="bnf">
- vbin16 = size octets
- size = uint16
- octets = 0*65535 OCTET ; size OCTETs
- </doc>
- </type>
-
- <type name="str16-latin" code="0x94" variable-width="2"
- label="up to 65535 iso-8859-15 characters">
- <doc>
- The str16-latin type encodes up to 65535 octets of is-8859-15 characters. The number of octets
- is first encoded as a 16-bit unsigned integral value in network byte order. This is followed
- by the actual characters.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 2 OCTETs size OCTETs
- +----------+------------------------+
- | size | characters |
- +----------+------------------------+
- uint16 iso-8859-15 characters
- </doc>
-
- <doc type="bnf">
- str16-latin = size characters
- size = uint16
- characters = 0*65535 OCTET ; size OCTETs
- </doc>
- </type>
-
- <type name="str16" code="0x95" variable-width="2"
- label="up to 65535 octets worth of UTF-8 unicode">
- <doc>
- The str16 type encodes up to 65535 octets worth of UTF-8 unicode. The number of octets is
- first encoded as a 16-bit unsigned integral value in network byte order. This is followed by
- the actual UTF-8 unicode. Note that the encoded size refers to the number of octets of
- unicode, not necessarily the number of unicode characters since the UTF-8 unicode may include
- multi-byte character sequences.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 2 OCTETs size OCTETs
- +----------+--------------+
- | size | utf8-unicode |
- +----------+--------------+
- uint16
- </doc>
-
- <doc type="bnf">
- str16 = size utf8-unicode
- size = uint16
- utf8-unicode = 0*65535 OCTET ; size OCTETs
- </doc>
- </type>
-
- <type name="str16-utf16" code="0x96" variable-width="2"
- label="up to 65535 octets worth of UTF-16 unicode">
- <doc>
- The str16-utf16 type encodes up to 65535 octets worth of UTF-16 unicode. The number of octets
- is first encoded as a 16-bit unsigned integral value in network byte order. This is followed
- by the actual UTF-16 unicode. Note that the encoded size refers to the number of octets of
- unicode, not the number of unicode characters since the UTF-16 unicode will include at least
- two octets per unicode character.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 2 OCTETs size OCTETs
- +----------+---------------+
- | size | utf16-unicode |
- +----------+---------------+
- uint16
- </doc>
-
- <doc type="bnf">
- str16-utf16 = size utf16-unicode
- size = uint16
- utf16-unicode = 0*65535 OCTET ; size OCTETs
- </doc>
- </type>
-
- <type name="sequence-set" variable-width="2" label="ranged set representation">
- <doc>
- The sequence-set type is a set of pairs of RFC-1982 numbers representing a discontinuous range
- within an RFC-1982 sequence. Each pair represents a closed interval within the list.
- </doc>
-
- <doc>
- Sequence-sets can be represented as lists of pairs of positive 32-bit numbers, each pair
- representing a closed interval that does not overlap or touch with any other interval in the
- list. For example, a set containing words 0, 1, 2, 5, 6, and 15 can be represented:
- </doc>
-
- <doc type="picture">
- [(0, 2), (5, 6), (15, 15)]
- </doc>
-
- <doc>
- 1) The list-of-pairs representation is sorted ascending (as defined by RFC 1982
- (http://www.ietf.org/rfc/rfc1982.txt) ) by the first elements of each pair.
- </doc>
-
- <doc>
- 2) The list-of-pairs is flattened into a list-of-words.
- </doc>
-
- <doc>
- 3) Each word in the list is packed into ascending locations in memory with network byte
- ordering.
- </doc>
-
- <doc>
- 4) The size in bytes, represented as a 16-bit network-byte-order unsigned value, is prepended.
- </doc>
-
- <doc>
- For instance, the example from above would be encoded:
- </doc>
-
- <doc type="picture">
- [(0, 2), (5, 6), (15, 15)] -- already sorted.
- [0, 2, 5, 6, 15, 15] -- flattened.
- 000000000000000200000005000000060000000F0000000F -- bytes in hex
- 0018000000000000000200000005000000060000000F0000000F -- bytes in hex,
- length (24) prepended
- </doc>
-
- <doc type="picture" title="Wire Format">
- +----= size OCTETs =----+
- | |
- 2 OCTETs | 8 OCTETs |
- +----------+-----+-----------+-----+
- | size | .../| range |\... |
- +----------+---/ +-----------+ \---+
- uint16 / / \ \
- / / \ \
- / / \ \
- / / \ \
- / 4 OCTETs 4 OCTETs \
- +-------------+-------------+
- | lower | upper |
- +-------------+-------------+
- sequence-no sequence-no
- </doc>
-
- <doc type="bnf">
- sequence-set = size *range
- size = uint16 ; length of variable portion in bytes
-
- range = lower upper ; inclusive
- lower = sequence-no
- upper = sequence-no
- </doc>
- </type>
-
- <!--
- 0xa0 - 0xaf: Variable length types - four byte length field (up to 4294967295 octets)
- -->
-
- <type name="vbin32" code="0xa0" variable-width="4"
- label="up to 4294967295 octets of opaque binary data">
- <doc>
- The vbin32 type encodes up to 4294967295 octets of opaque binary data. The number of octets is
- first encoded as a 32-bit unsigned integral value in network byte order. This is followed by
- the actual data.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 4 OCTETs size OCTETs
- +----------+-------------+
- | size | octets |
- +----------+-------------+
- uint32
- </doc>
-
- <doc type="bnf">
- vbin32 = size octets
- size = uint32
- octets = 0*4294967295 OCTET ; size OCTETs
- </doc>
- </type>
-
- <type name="map" code="0xa8" variable-width="4" label="a mapping of keys to typed values">
- <doc>
- A map is a set of distinct keys where each key has an associated (type,value) pair. The triple
- of the key, type, and value, form an entry within a map. Each entry within a given map MUST
- have a distinct key. A map is encoded as a size in octets, a count of the number of entries,
- followed by the encoded entries themselves.
- </doc>
-
- <doc>
- An encoded map may contain up to (4294967295 - 4) octets worth of encoded entries. The size is
- encoded as a 32-bit unsigned integral value in network byte order equal to the number of
- octets worth of encoded entries plus 4. (The extra 4 octets is added for the entry count.) The
- size is then followed by the number of entries encoded as a 32-bit unsigned integral value in
- network byte order. Finally the entries are encoded sequentially.
- </doc>
-
- <doc>
- An entry is encoded as the key, followed by the type, and then the value. The key is always a
- string encoded as a str8. The type is a single octet that may contain any valid AMQP type
- code. The value is encoded according to the rules defined by the type code for that entry.
- </doc>
-
- <doc type="picture" title="Wire Format">
- +------------= size OCTETs =-----------+
- | |
- 4 OCTETs | 4 OCTETs |
- +----------+----------+-----+---------------+-----+
- | size | count | .../| entry |\... |
- +----------+----------+---/ +---------------+ \---+
- uint32 uint32 / / \ \
- / / \ \
- / / \ \
- / / \ \
- / / \ \
- / k OCTETs 1 OCTET n OCTETs \
- +-----------+---------+-----------+
- | key | type | value |
- +-----------+---------+-----------+
- str8 *type*
- </doc>
-
- <doc type="bnf">
- map = size count *entry
-
- size = uint32 ; size of count and entries in octets
- count = uint32 ; number of entries in the map
-
- entry = key type value
- key = str8
- type = OCTET ; type code of the value
- value = *OCTET ; the encoded value
- </doc>
- </type>
-
- <type name="list" code="0xa9" variable-width="4" label="a series of consecutive type-value pairs">
- <doc>
- A list is an ordered sequence of (type, value) pairs. The (type, value) pair forms an item
- within the list. The list may contain items of many distinct types. A list is encoded as a
- size in octets, followed by a count of the number of items, followed by the items themselves
- encoded in their defined order.
- </doc>
-
- <doc>
- An encoded list may contain up to (4294967295 - 4) octets worth of encoded items. The size is
- encoded as a 32-bit unsigned integral value in network byte order equal to the number of
- octets worth of encoded items plus 4. (The extra 4 octets is added for the item count.) The
- size is then followed by the number of items encoded as a 32-bit unsigned integral value in
- network byte order. Finally the items are encoded sequentially in their defined order.
- </doc>
-
- <doc>
- An item is encoded as the type followed by the value. The type is a single octet that may
- contain any valid AMQP type code. The value is encoded according to the rules defined by the
- type code for that item.
- </doc>
-
- <doc type="picture" title="Wire Format">
- +---------= size OCTETs =---------+
- | |
- 4 OCTETs | 4 OCTETs |
- +----------+----------+-----+----------+-----+
- | size | count | .../| item |\... |
- +----------+----------+---/ +----------+ \---+
- uint32 uint32 / / \ \
- / / \ \
- / 1 OCTET n OCTETs \
- +----------+-----------+
- | type | value |
- +----------+-----------+
- *type*
- </doc>
-
- <doc type="bnf">
- list = size count *item
-
- size = uint32 ; size of count and items in octets
- count = uint32 ; number of items in the list
-
- item = type value
- type = OCTET ; type code of the value
- value = *OCTET ; the encoded value
- </doc>
- </type>
-
- <type name="array" code="0xaa" variable-width="4"
- label="a defined length collection of values of a single type">
- <doc>
- An array is an ordered sequence of values of the same type. The array is encoded in as a size
- in octets, followed by a type code, then a count of the number values in the array, and
- finally the values encoded in their defined order.
- </doc>
-
- <doc>
- An encoded array may contain up to (4294967295 - 5) octets worth of encoded values. The size
- is encoded as a 32-bit unsigned integral value in network byte order equal to the number of
- octets worth of encoded values plus 5. (The extra 5 octets consist of 4 octets for the count
- of the number of values, and one octet to hold the type code for the items in the array.) The
- size is then followed by a single octet that may contain any valid AMQP type code. The type
- code is then followed by the number of values encoded as a 32-bit unsigned integral value in
- network byte order. Finally the values are encoded sequentially in their defined order
- according to the rules defined by the type code for the array.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 4 OCTETs 1 OCTET 4 OCTETs (size - 5) OCTETs
- +----------+---------+----------+-------------------------+
- | size | type | count | values |
- +----------+---------+----------+-------------------------+
- uint32 uint32 *count* encoded *types*
- </doc>
-
- <doc type="bnf">
- array = size type count values
-
- size = uint32 ; size of type, count, and values in octets
- type = OCTET ; the type of the encoded values
- count = uint32 ; number of items in the array
-
- values = 0*4294967290 OCTET ; (size - 5) OCTETs
- </doc>
- </type>
-
- <type name="struct32" code="0xab" variable-width="4" label="a coded struct with a 32-bit size">
- <doc>
- The struct32 type describes any coded struct with a 32-bit (4 octet) size. The type is
- restricted to be only coded structs with a 32-bit size, consequently the first six octets of
- any encoded value for this type MUST always contain the size, class-code, and struct-code in
- that order.
- </doc>
-
- <doc>
- The size is encoded as a 32-bit unsigned integral value in network byte order that is equal to
- the size of the encoded field-data, packing-flags, class-code, and struct-code. The class-code
- is a single octet that may be set to any valid class code. The struct-code is a single octet
- that may be set to any valid struct code within the given class-code.
- </doc>
-
- <doc>
- The first six octets are then followed by the packing flags and encoded field data. The
- presence and quantity of packing-flags, as well as the specific fields are determined by the
- struct definition identified with the encoded class-code and struct-code.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 4 OCTETs 1 OCTET 1 OCTET pack-width OCTETs n OCTETs
- +----------+------------+-------------+-------------------+------------+
- | size | class-code | struct-code | packing-flags | field-data |
- +----------+------------+-------------+-------------------+------------+
- uint32
-
- n = (size - 2 - pack-width)
- </doc>
-
- <doc type="bnf">
- struct32 = size class-code struct-code packing-flags field-data
-
- size = uint32
-
- class-code = OCTET ; zero for top-level structs
- struct-code = OCTET ; together with class-code identifies the struct
- ; definition which determines the pack-width and
- ; fields
-
- packing-flags = 0*4 OCTET ; pack-width OCTETs
-
- field-data = *OCTET ; (size - 2 - pack-width) OCTETs
- </doc>
- </type>
-
- <!--
- 0xb0 - 0xbf: Reserved
- -->
-
- <!--
- 0xc0 - 0xcf:Fixed width types - 5 octets
- -->
-
- <type name="bin40" code="0xc0" fixed-width="5" label="five octets of unspecified binary encoding">
- <doc>
- The bin40 type consists of five consecutive octets of opaque binary data.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET 1 OCTET 1 OCTET 1 OCTET 1 OCTET
- +-----------+-----------+-------------+------------+------------+
- | octet-one | octet-two | octet-three | octet-four | octet-five |
- +-----------+-----------+-------------+------------+------------+
- </doc>
-
- <doc type="bnf">
- bin40 = 5 OCTET
- </doc>
- </type>
-
- <type name="dec32" code="0xc8" fixed-width="5"
- label="32-bit decimal value (e.g. for use in financial values)">
- <doc>
- The dec32 type is decimal value with a variable number of digits following the decimal point.
- It is encoded as an 8-bit unsigned integral value representing the number of decimal places.
- This is followed by the signed integral value encoded using a 32-bit two's complement
- representation in network byte order.
- </doc>
-
- <doc>
- The former value is referred to as the exponent of the divisor. The latter value is the
- mantissa. The decimal value is given by: mantissa / 10^exponent.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET 4 OCTETs
- +----------+----------+
- | exponent | mantissa |
- +----------+----------+
- uint8 int32
- </doc>
-
- <doc type="bnf">
- dec32 = exponent mantissa
- exponent = uint8
- mantissa = int32
- </doc>
- </type>
-
- <!--
- 0xd0 - 0xdf: Fixed width types - 9 octets
- -->
-
- <type name="bin72" code="0xd0" fixed-width="9"
- label="nine octets of unspecified binary encoding">
- <doc>
- The bin72 type consists of nine consecutive octets of opaque binary data.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET 1 OCTET 1 OCTET 1 OCTET
- +-----------+-----------+-----+-------------+------------+
- | octet-one | octet-two | ... | octet-eight | octet-nine |
- +-----------+-----------+-----+-------------+------------+
- </doc>
-
- <doc type="bnf">
- bin64 = 9 OCTET
- </doc>
- </type>
-
- <type name="dec64" code="0xd8" fixed-width="9"
- label="64-bit decimal value (e.g. for use in financial values)">
- <doc>
- The dec64 type is decimal value with a variable number of digits following the decimal point.
- It is encoded as an 8-bit unsigned integral value representing the number of decimal places.
- This is followed by the signed integral value encoded using a 64-bit two's complement
- representation in network byte order.
- </doc>
-
- <doc>
- The former value is referred to as the exponent of the divisor. The latter value is the
- mantissa. The decimal value is given by: mantissa / 10^exponent.
- </doc>
-
- <doc type="picture" title="Wire Format">
- 1 OCTET 8 OCTETs
- +----------+----------+
- | exponent | mantissa |
- +----------+----------+
- uint8 int64
- </doc>
-
- <doc type="bnf">
- dec64 = exponent mantissa
- exponent = uint8
- mantissa = int64
- </doc>
- </type>
-
- <!--
- 0xe0 - 0xef: Reserved
- -->
-
- <!--
- 0xf0 - 0xff: Zero-length types
- -->
-
- <type name="void" code="0xf0" fixed-width="0" label="the void type">
- <doc>
- The void type is used within tagged data structures such as maps and lists to indicate an
- empty value. The void type has no value and is encoded as an empty sequence of octets.
- </doc>
- </type>
-
- <type name="bit" code="0xf1" fixed-width="0" label="presence indicator">
- <doc>
- The bit type is used to indicate that a packing flag within a packed struct is being used to
- represent a boolean value based on the presence of an empty value. The bit type has no value
- and is encoded as an empty sequence of octets.
- </doc>
- </type>
-
- <!--
- ======================================================
- == CONSTANTS
- ======================================================
- -->
-
- <!-- Protocol constants -->
-
- <constant name="MIN-MAX-FRAME-SIZE" value="4096" label="The minimum size (in bytes) which can be
- agreed upon as the maximum frame size.">
- <doc>
- During the initial connection negotiation, the two peers must agree upon a maximum frame size.
- This constant defines the minimum value to which the maximum frame size can be set. By
- defining this value, the peers can guarantee that they can send frames of up to this size
- until they have agreed a definitive maximum frame size for that connection.
- </doc>
- </constant>
-
- <!--
- ======================================================
- == DOMAIN TYPES
- ======================================================
- -->
-
- <!-- Segment types -->
-
- <domain name="segment-type" type="uint8" label="valid values for the frame type indicator.">
- <doc>
- Segments are defined in <xref ref="specification.transport.assemblies_segments_and_frames"/>.
- The segment domain defines the valid values that may be used for the segment indicator within
- the frame header.
- </doc>
-
- <enum>
- <choice name="control" value="0">
- <doc>
- The frame type indicator for Control segments (see <xref
- ref="specification.formal_notation.controls"/>).
- </doc>
- </choice>
- <choice name="command" value="1">
- <doc>
- The frame type indicator for Command segments (see <xref
- ref="specification.formal_notation.commands"/>).
- </doc>
- </choice>
- <choice name="header" value="2" >
- <doc>
- The frame type indicator for Header segments (see <xref
- ref="specification.formal_notation.segments.header"/>).
- </doc>
- </choice>
- <choice name="body" value="3" >
- <doc>
- The frame type indicator for Body segments (see <xref
- ref="specification.formal_notation.segments.body"/>).
- </doc>
- </choice>
- </enum>
- </domain>
-
-
- <domain name="str16-array" type="array" label="An array of values of type str16.">
- <doc>
- An array of values of type str16.
- </doc>
- </domain>
-
-
-
- <!-- == Class: connection ==================================================================== -->
-
- <class name="connection" code="0x1" label="work with connections">
- <doc>
- The connection class provides controls for two peers to establish a network connection, and
- for both peers to operate the connection thereafter. Either peer may operate in the server or
- client roles.
- </doc>
-
- <doc type="grammar">
- connection = open-connection
- *use-connection
- close-connection
- open-connection = C:protocol-header
- S:OPEN C:OPEN
- [ sasl-exchange ]
- sasl-exchange = C:SASL-INIT *( S:SASL-CHALLENGE C:SASL-RESPONSE ) C:SASL-DONE
- use-connection = *channel
- close-connection = S:CLOSE C:CLOSE
- </doc>
-
- <role name="server" implement="MUST" />
- <role name="client" implement="MUST" />
-
- <domain name="close-code" type="uint16" label="code used in the connection.close control to
- indicate reason for closure">
- <enum>
- <choice name="normal" value="200">
- <doc>
- The connection closed normally.
- </doc>
- </choice>
-
- <choice name="connection-forced" value="320">
- <doc>
- An operator intervened to close the connection for some reason. The client may retry at
- some later date.
- </doc>
- </choice>
-
- <choice name="authentication-failure" value="401">
- <doc>
- The SASL authentication exchange failed.
- </doc>
- </choice>
-
- <choice name="invalid-path" value="402">
- <doc>
- The client tried to work with an unknown virtual host.
- </doc>
- </choice>
-
- <choice name="framing-error" value="501">
- <doc>
- A valid frame header cannot be formed from the incoming byte stream.
- </doc>
- </choice>
- </enum>
- </domain>
-
- <domain name="amqp-host-url" type="str16" label="URL for identifying an AMQP Server">
- <doc>
- The amqp-url domain defines a format for identifying an AMQP Server. It is used to provide
- alternate hosts in the case where a client has to reconnect because of failure, or because
- the server requests the client to do so upon initial connection.
- </doc>
- <doc type="bnf"><![CDATA[
- amqp_url = "amqp:" prot_addr_list
- prot_addr_list = [prot_addr ","]* prot_addr
- prot_addr = tcp_prot_addr | tls_prot_addr
-
- tcp_prot_addr = tcp_id tcp_addr
- tcp_id = "tcp:" | ""
- tcp_addr = [host [":" port] ]
- host = <as per http://www.ietf.org/rfc/rfc3986.txt>
- port = number]]>
- </doc>
- </domain>
-
- <domain name="amqp-host-array" type="array" label="An array of values of type amqp-host-url">
- <doc>
- Used to provide a list of alternate hosts.
- </doc>
- </domain>
-
- <domain name="sasl-code" type="uint8" label="indicates the disposition of the sasl dialog">
- <enum>
- <choice name="ok" value="0">
- <doc>
- The connection was successfully authenticated.
- </doc>
- </choice>
- <choice name="authentication-failed" value="1">
- <doc>
- Connection authentication failed.
- </doc>
- </choice>
- </enum>
- </domain>
-
- <!-- - Control: connection.open - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <control name="open" code="0x1" label="open connection to a virtual host">
- <doc>
- This control opens a connection to a virtual host, which is a collection of resources, and
- acts to separate multiple application domains within a server. The server may apply
- arbitrary limits per virtual host, such as the number of each type of entity that may be
- used, per connection and/or in total.
- </doc>
-
- <implement role="server" handle="MUST" />
- <implement role="client" handle="MUST" />
-
- <rule name="protocol-name">
- <doc>
- If the server cannot support the protocol specified in the protocol header, it MUST close
- the socket connection without sending any response control.
- </doc>
- <doc type="scenario">
- The client sends a protocol header containing an invalid protocol name. The server must
- respond by closing the connection.
- </doc>
- </rule>
-
- <rule name="client-support">
- <doc>
- If the client cannot handle the protocol version suggested by the server it MUST close the
- socket connection.
- </doc>
- <doc type="scenario">
- The server sends a protocol version that is lower than any valid implementation, e.g. 0.1.
- The client must respond by closing the connection.
- </doc>
- </rule>
-
- <field name="virtual-host" type="str16" default="" label="virtual host name">
- <doc>
- The name of the virtual host to which the connection is being opened. The default virtual
- host is the virtual host with name of length zero. It is not mandatory to provide such a
- virtual host.
- </doc>
-
- <rule name="isolation">
- <doc>
- If the server supports multiple virtual hosts, it MUST enforce a full isolation of
- exchanges, queues, and all associated entities per virtual host. An application,
- connected to a specific virtual host, MUST NOT be able to access resources of another
- virtual host.
- </doc>
- </rule>
- </field>
-
- <field name="max-frame-size" type="uint16" label="proposed maximum frame size">
- <doc>
- The largest frame size that the peer proposes for the connection. If this is not set means
- that the server does not impose any specific limit.
- </doc>
-
- <rule name="established-max-frame-size">
- <doc>
- The max-frame-size established for the connection is the minimum of the two proposed
- values. If neither peer sets a max-frame-size the established max-frame-size is
- (2^16)-1.
- </doc>
- </rule>
-
- <rule name="minimum">
- <doc>
- Until the max-frame-size has been negotiated, both peers MUST accept frames of up to
- MIN-MAX-FRAME-SIZE octets large.
- </doc>
- </rule>
-
- <rule name="frame-size-limit">
- <doc>
- A peer MUST NOT send frames larger than the agreed-upon size. A peer that receives an
- oversized frame MUST close the connection with the framing-error close-code.
- </doc>
- </rule>
- </field>
-
- <field name="channel-max" type="uint16"
- label="the maximum number of channels available for session attachment">
- <doc>
- The maximum number of channels available for session attachment by the recipient. For a
- typical client this would be zero. For a typical server this would be the maximum number
- of supported channels.
- </doc>
-
- <rule name="upper-limit">
- <doc>
- The channel-max value may never exceed 2^15.
- </doc>
- </rule>
-
- <rule name="available-channels">
- <doc>
- If a peer advertises a channel-max of N channels, then the channels available for
- session attachment are precisely the channels numbered 0 to (N-1).
- </doc>
- </rule>
- </field>
-
- <field name="heartbeat-interval" type="uint16" label="proposed heartbeat interval">
- <doc>
- The proposed interval, in seconds, of the connection heartbeat desired by the sender. A
- value of zero means heartbeats are not supported. If the value is not set, the sender
- supports all heartbeat intervals.
- </doc>
-
- <rule name="established-heartbeat">
- <doc>
- The heartbeat-interval established is the minimum of the two proposed
- heartbeat-intervals. If neither value is set, there is no heartbeat.
- </doc>
- </rule>
- </field>
-
- <field name="sasl-server-mechanisms" type="str16-array" label="supported sasl mechanisms">
- <doc>
- A list of the sasl security mechanisms supported by the sending peer. If the sending peer
- does not require its partner to authenticate with it, this array may be empty or absent.
- The server mechanisms are ordered in decreasing level of preference.
- </doc>
- </field>
-
- <field name="supported-locales" type="str16-array" label="locales that are supported">
- <doc>
- A list of the locales that the peer supports. The locale defines the language in which the
- peer will send protocol level error messages. This includes connection close text, reject
- text, and session exception text. The default is the en_US locale.
- </doc>
-
- <rule name="required-support">
- <doc>
- The peer MUST support at least the en_US locale. Since this value is always supported,
- it need not be supplied in the supported-locales array.
- </doc>
- </rule>
- </field>
-
- <field name="preferred-locales" type="str16-array"
- label="acceptable locales in decreasing level of preference">
- <doc>
- A list of locales that the sending peer will accept. This list is ordered in decreasing
- level of preference. The receiving partner will chose the most preferred locale from its
- supported-locales list. If none of the preferred locales are supported, en_US will be
- chosen. Note that en_US need not be supplied in this list as it always the fallback.
- </doc>
- </field>
-
- <field name="client-properties" type="map" label="client properties">
- <rule name="required-fields">
- <!-- This rule is not testable from the client side -->
- <doc>
- The properties SHOULD contain at least these fields: "product", giving the name of the
- client product, "version", giving the name of the client version, "platform", giving the
- name of the operating system, "copyright", if appropriate, and "information", giving
- other general information.
- </doc>
- </rule>
- </field>
-
- <field name="server-properties" type="map" label="server properties">
- <rule name="required-fields">
- <doc>
- The properties SHOULD contain at least these fields: "host", specifying the server host
- name or address, "product", giving the name of the server product, "version", giving the
- name of the server version, "platform", giving the name of the operating system,
- "copyright", if appropriate, and "information", giving other general information.
- </doc>
- <doc type="scenario">
- Client connects to server and inspects the server properties. It checks for the presence
- of the required fields.
- </doc>
- </rule>
- </field>
- </control>
-
- <!-- - Control: connection.sasl-init - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <control name="sasl-init" code="0x2" label="initiate sasl exchange">
- <doc>
- Selects the sasl mechanism and provides the initial response if needed.
- </doc>
-
- <implement role="server" handle="MUST" />
-
- <field name="mechanism" type="str16" label="selected security mechanism" required="true">
- <doc>
- The name of the SASL mechanism used for the SASL exchange.
- </doc>
-
- <rule name="supported-mechanisms">
- <doc>
- The mechanism chosen must be the one of the supported mechanisms supplied by the peer.
- </doc>
- </rule>
-
- <rule name="security">
- <doc>
- The client SHOULD authenticate using the highest-level security profile it can handle
- from the list provided by the server.
- </doc>
- </rule>
-
- <rule name="validity">
- <doc>
- If the mechanism field does not contain one of the security mechanisms proposed by the
- server in the connection.open control, the server MUST close the connection without
- sending any further data.
- </doc>
- </rule>
- </field>
-
-
- <field name="initial-response" type="vbin32" label="security response data">
- <doc>
- A block of opaque data passed to the security mechanism. The contents of this data are
- defined by the SASL security mechanism.
- </doc>
- </field>
- </control>
-
- <!-- - Control: connection.sasl-challenge - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <control name="sasl-challenge" code="0x3" label="security mechanism challenge">
- <implement role="client" handle="MUST" />
-
- <response name="sasl-response" />
-
- <field name="challenge" type="vbin32" label="security challenge data" required="true">
- <doc>
- Challenge information, a block of opaque binary data passed to the security mechanism.
- </doc>
- </field>
- </control>
-
- <!-- - Control: connection.sasl-response - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <control name="sasl-response" code="0x4" label="security mechanism response">
- <doc>
- This control attempts to authenticate, passing a block of SASL data for the security
- mechanism at the server side.
- </doc>
-
- <implement role="server" handle="MUST" />
-
- <field name="response" type="vbin32" label="security response data" required="true">
- <doc>
- A block of opaque data passed to the security mechanism. The contents of this data are
- defined by the SASL security mechanism.
- </doc>
- </field>
- </control>
-
- <!-- - Control: connection.sasl-done - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <control name="sasl-done" code="0x5" label="terminate sasl dialog">
- <doc>
- This control terminates the sasl dialog.
- </doc>
-
- <implement role="client" handle="MUST" />
-
- <field name="code" type="sasl-code" label="indicates the disposition of the sasl dialog">
- <doc>
- A reply-code indicating the disposition of the sasl dialog.
- </doc>
- </field>
- </control>
-
- <!-- - Control: connection.heartbeat - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <control name="heartbeat" code="0x6" label="indicates connection is still alive">
- <doc>
- The heartbeat control may be used to generate artificial network traffic when a connection
- is idle. If a connection is idle for more than twice the negotiated heartbeat delay, the
- peers MAY be considered disconnected.
- </doc>
- </control>
-
- <!-- - Control: connection.close - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <control name="close" code="0x7" label="request a connection close">
- <doc>
- This control indicates that the sender wants to close the connection. The reason for close
- is indicated with the reply-code and reply-text. The channel this control is sent on MAY be
- used to indicate which channel caused the connection to close.
- </doc>
-
- <implement role="client" handle="MUST" />
- <implement role="server" handle="MUST" />
-
- <field name="reply-code" type="close-code" label="the numeric reply code"
- required="true">
- <doc>
- Indicates the reason for connection closure.
- </doc>
- </field>
- <field name="reply-text" type="str8" label="the localized reply text">
- <doc>
- This text can be logged as an aid to resolving issues.
- </doc>
- </field>
- </control>
- </class>
-
- <!-- == Class: session ======================================================================= -->
-
- <class name="session" code="0x2" label="session controls">
- <doc>
- A session is a named interaction between two peers. Session names are chosen by the upper
- layers and may be used indefinitely. The model layer may associate long-lived or durable state
- with a given session name. The session layer provides transport of commands associated with
- this interaction.
- </doc>
-
- <doc type="picture"><![CDATA[
- Sender: Receiver:
- |--in-flight--|
- +--------------+--------------------------+ +-----------------+-----------+
- | C1 C2 C3 | C4 C5 C6 C7 C8 C9 | ------> | C1 C2 C3 C4 | C5 C6 |
- +--------------+--------------------------+ +-----------------+-----------+
- complete replay queue complete work queue
-
- C1, C2, C3: completed at the receiver, known to be completed by the sender
- C4: completed at the receiver, *not* known to be completed by the sender
- C5, C6: received by the sender, but not yet completed
- C7, C8, C9: transmitted by the sender, but not yet received
-
- Sender state:
- last-completed: marks the tail of replay queue
- last-sent: marks the head of replay queue
-
- Receiver state:
- last-completed: marks the tail of the work queue
- last-received: marks the head of work queue
-
- State exchanged periodically between the two endpoints of a full
- duplex session. Each endpoint has both a sender and a receiver:
-
- (sender-completed, receiver-completed)
- /|\ /|\
- | |
- | allows the sender to shrink replay queue
- |
- allows the receiver to know that sender won't replay
-
- State exchanged between the two endpoints on open/resume:
-
- (last-sent, last-received)
- /|\ /|\
- | |
- | tells sender where to resume from
- | (null for open)
- |
- tells receiver where to start counting command-ids on open
- (null for resume)]]>
- </doc>
-
- <doc>
- The controls defined within this class are specified in terms of the "sender" of commands and
- the "receiver" of commands. Since both client and server send and receive commands, the
- overall session dialog is symmetric, however the semantics of the session controls are defined
- in terms of a single sender/receiver pair, and it is assumed that the client and server will
- each contain both a sender and receiver implementation.
- </doc>
-
- <rule name="attachment">
- <doc>
- The transport MUST be attached in order to use any control other than "attach", "attached",
- "detach", or "detached". A peer receiving any other control on a detached transport MUST
- discard it and send a session.detached with the "not-attached" reason code.
- </doc>
- </rule>
-
- <role name="server" implement="MUST" />
- <role name="client" implement="MUST" />
-
- <role name="sender" implement="MUST">
- <doc>
- The sender of commands.
- </doc>
- </role>
- <role name="receiver" implement="MUST">
- <doc>
- The receiver of commands.
- </doc>
- </role>
-
- <domain name="name" type="vbin16" label="opaque session name">
- <doc>
- The session name uniquely identifies an interaction between two peers. It is scoped to a
- given authentication principal.
- </doc>
- </domain>
-
- <domain name="detach-code" type="uint8" label="reason for detach">
- <enum>
- <choice name="normal" value="0">
- <doc>
- The session was detached by request.
- </doc>
- </choice>
- <choice name="session-busy" value="1">
- <doc>
- The session is currently attached to another transport.
- </doc>
- </choice>
- <choice name="transport-busy" value="2">
- <doc>
- The transport is currently attached to another session.
- </doc>
- </choice>
- <choice name="not-attached" value="3">
- <doc>
- The transport is not currently attached to any session.
- </doc>
- </choice>
- <choice name="unknown-ids" value="4">
- <doc>
- Command data was received prior to any use of the command-point control.
- </doc>
- </choice>
- </enum>
- </domain>
-
- <domain name="commands" type="sequence-set" label="identifies a set of commands">
- </domain>
-
- <struct name="exception" size="2" pack="2" label="notifies a peer of an execution error">
- <doc>
- This command informs a peer of an execution exception. The command-id, when given,
- correlates the error to a specific command.
- </doc>
-
- <field name="error-code" type="error-code" required="true" label="error code indicating the
- type of error"/>
- <field name="command-id" type="sequence-no" label="exceptional command">
- <doc>
- The command-id of the command which caused the exception. If the exception was not caused
- by a specific command, this value is not set.
- </doc>
- </field>
- <field name="class-code" type="uint8" label="the class code of the command whose execution
- gave rise to the error (if appropriate)"/>
- <field name="command-code" type="uint8" label="the class code of the command whose execution
- gave rise to the error (if appropriate)"/>
- <field name="field-index" type="uint8" label="index of the exceptional field">
- <doc>
- The zero based index of the exceptional field within the arguments to the exceptional
- command. If the exception was not caused by a specific field, this value is not set.
- </doc>
- </field>
- <field name="description" type="str16" label="descriptive text on the exception">
- <doc>
- The description provided is implementation defined, but MUST be in the language
- appropriate for the selected locale. The intention is that this description is suitable
- for logging or alerting output.
- </doc>
- </field>
- <field name="error-info" type="map" label="map to carry additional information about the
- error"/>
- </struct>
-
- <control name="attach" code="0x1" label="attach to the named session">
- <doc>
- Requests that the current transport be attached to the named session. Success or failure
- will be indicated with an attached or detached response. This control is idempotent.
- </doc>
-
- <rule name="one-transport-per-session">
- <doc>
- A session MUST NOT be attached to more than one transport at a time.
- </doc>
- </rule>
-
- <rule name="one-session-per-transport">
- <doc>
- A transport MUST NOT be attached to more than one session at a time.
- </doc>
- </rule>
-
- <rule name="idempotence">
- <doc>
- Attaching a session to its current transport MUST succeed and result in an attached
- response.
- </doc>
- </rule>
-
- <rule name="scoping">
- <doc>
- Attachment to the same session name from distinct authentication principals MUST succeed.
- </doc>
- </rule>
-
- <implement role="server" handle="MUST" />
- <implement role="client" handle="MUST" />
-
- <field name="name" type="name" label="the session name" required="true">
- <doc>
- Identifies the session to be attached to the current transport.
- </doc>
- </field>
-
- <field name="force" type="bit" label="force attachment to a busy session">
- <doc>
- If set then a busy session will be forcibly detached from its other transport and
- reattached to the current transport.
- </doc>
- </field>
-
- <field name="exists" type="bit" label="true iff the session exists at the endpoint"/>
-
- <field name="first-unsent" type="sequence-no">
-<!-- XXX
- <control name="command-point" code="0x7"
- label="the command id and byte offset of subsequent data">
- <doc>
- This control is sent by the sender of commands and handled by the receiver of commands. This
- establishes the sequence numbers associated with all subsequent command data sent from the
- sender to the receiver. The subsequent command data will be numbered starting with the
- values supplied in this control and proceeding sequentially. This must be used at least once
- prior to sending any command data on newly attached transports.
- </doc>
-
- <rule name="newly-attached-transports">
- <doc>
- If command data is sent on a newly attached transport the session MUST be detached with an
- "unknown-id" reason-code.
- </doc>
- </rule>
-
- <rule name="zero-offset">
- <doc>
- If the offset is zero, the next data frame MUST have the first-frame and first-segment
- flags set. Violation of this is a framing error.
- </doc>
- </rule>
-
- <rule name="nonzero-offset">
- <doc>
- If the offset is nonzero, the next data frame MUST NOT have both the first-frame and
- first-segment flag set. Violation of this is a framing error.
- </doc>
- </rule>
-
- <implement role="receiver" handle="MUST" />
-
- <field name="command-id" type="sequence-no" label="the command-id of the next command"
- required="true"/>
- </control>
--->
- </field>
-
- <field name="first-resendable" type="sequence-no">
- <doc>
- The id of the first command the peer can resend, this may be null.
- </doc>
- </field>
-
- <field name="last-received" type="sequence-no" label="the id of the last command received">
- <doc>
- This field carries the id of the last command received by this peer for the session. This
- field MUST be set if and only if the session has received commands.
- </doc>
- </field>
-
- <field name="requested-timeout" type="uint32" label="the requested timeout">
- <doc>
- The requested timeout for execution state in seconds. If not set, this control requests
- that execution state is preserved for the maximum duration permitted by the receiving
- peer.
- </doc>
-
-<!-- XXX
- <control name="request-timeout" code="0x5" label="requests the execution timeout be changed">
- <doc>
- This control may be sent by either the sender or receiver of commands. It requests that the
- execution timeout be changed. This is the minimum amount of time that a peer must preserve
- execution state for a detached session.
- </doc>
-
- <rule name="maximum-granted-timeout">
- <doc>
- The handler of this request MUST set his timeout to the maximum allowed value less than or
- equal to the requested timeout, and MUST convey the chosen timeout in the response.
- </doc>
- </rule>
-
- <implement role="sender" handle="MUST" />
- <implement role="receiver" handle="MUST" />
-
- <response name="timeout"/>
-
- <field name="timeout" type="uint32" label="the requested timeout">
- <doc>
- The requested timeout for execution state in seconds. If not set, this control requests
- that execution state is preserved indefinitely.
- </doc>
- </field>
- </control>
-
- <control name="timeout" code="0x6" label="the granted timeout">
- <doc>
- This control may be sent by the either the sender or receiver of commands. It is a
- one-to-one reply to the request-timeout control that indicates the granted timeout for
- execution state.
- </doc>
-
- <implement role="sender" handle="MUST" />
- <implement role="receiver" handle="MUST" />
-
- <field name="timeout" type="uint32" label="the execution timeout">
- <doc>
- The timeout for execution state. If not set, then execution state is preserved
- indefinitely.
- </doc>
- </field>
- </control>
--->
- </field>
- </control>
-
- <control name="detach" code="0x3" label="detach from the named session">
- <doc>
- Signals the end of communication on this channel for this session in this direction.
- </doc>
-
- <implement role="server" handle="MUST" />
- <implement role="client" handle="MUST" />
-
- <field name="name" type="name" label="the session name" required="true">
- <doc>
- Identifies the detached session.
- </doc>
- </field>
- <field name="code" type="detach-code" label="the reason for detach" required="true">
- <doc>
- Identifies the reason for detaching from the named session.
- </doc>
- </field>
- <field name="last-successful" type="sequence-no"/>
- <field name="exception" type="exception"/>
- </control>
-
- <!--
- Execution state is the set of completed incoming commands, as well as the set of outgoing
- in-doubt commands held for replay.
- -->
-
- <control name="state" code="0xa" label="carries periodic updates of session state between
- endpoints">
- <doc>
- This control carries ongoing session state between the two session endpoints.
- </doc>
-
- <implement role="sender" handle="MUST" />
- <implement role="receiver" handle="MUST" />
-
- <field name="flush" type="bit" label="requests that the peer send its state">
- <doc>
- If set, the peer must respond with the state if its own session endpoint.
- </doc>
- </field>
-
- <field name="receiver-completed" type="sequence-no" label="last incoming command completed">
- <doc>
- The id of the last incoming command completed by the receiver.
- </doc>
- </field>
-
- <field name="sender-completed" type="sequence-no" label="last outgoing command completed">
- <doc>
- The id of the last outgoing command known by the sender to be complete.
- </doc>
- </field>
- </control>
-
-<!-- </class> -->
-
- <!-- == Class: execution ===================================================================== -->
-
-<!-- <class name="execution" code="0x3" label="execution commands"> -->
- <doc>
- The execution class provides commands that carry execution information about other model level
- commands.
- </doc>
-
- <role name="server" implement="MUST"/>
- <role name="client" implement="MUST"/>
-
- <domain name="error-code" type="uint16">
- <enum>
- <choice name="unauthorized-access" value="403">
- <doc>
- The client attempted to work with a server entity to which it has no access due to
- security settings.
- </doc>
- </choice>
-
- <choice name="not-found" value="404">
- <doc>
- The client attempted to work with a server entity that does not exist.
- </doc>
- </choice>
-
- <choice name="resource-locked" value="405">
- <doc>
- The client attempted to work with a server entity to which it has no access because
- another client is working with it.
- </doc>
- </choice>
-
- <choice name="precondition-failed" value="406">
- <doc>
- The client requested a command that was not allowed because some precondition failed.
- </doc>
- </choice>
-
- <choice name="resource-deleted" value="408">
- <doc>
- A server entity the client is working with has been deleted.
- </doc>
- </choice>
-
- <choice name="illegal-state" value="409">
- <doc>
- The peer sent a command that is not permitted in the current state of the session.
- </doc>
- </choice>
-
- <choice name="command-invalid" value="503">
- <doc>
- The command segments could not be decoded.
- </doc>
- </choice>
-
- <choice name="resource-limit-exceeded" value="506">
- <doc>
- The client exceeded its resource allocation.
- </doc>
- </choice>
-
- <choice name="not-allowed" value="530">
- <doc>
- The peer tried to use a command a manner that is inconsistent with the rules described
- in the specification.
- </doc>
- </choice>
-
- <choice name="illegal-argument" value="531">
- <doc>
- The command argument is malformed, i.e. it does not fall within the specified domain.
- The illegal-argument exception can be raised on execution of any command which has
- domain valued fields.
- </doc>
- </choice>
-
- <choice name="not-implemented" value="540">
- <doc>
- The peer tried to use functionality that is not implemented in its partner.
- </doc>
- </choice>
-
- <choice name="internal-error" value="541">
- <doc>
- The peer could not complete the command because of an internal error. The peer may
- require intervention by an operator in order to resume normal operations.
- </doc>
- </choice>
-
- <choice name="invalid-argument" value="542">
- <doc>
- An invalid argument was passed to a command, and the operation could not
- proceed. An invalid argument is not illegal (see illegal-argument), i.e. it matches
- the domain definition; however the particular value is invalid in this context.
- </doc>
- </choice>
- </enum>
- </domain>
-
- <!-- - Command: execution.sync - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="sync" code="0xb" label="request notification of completion for issued commands">
- <doc>
- This command is complete when all prior commands are completed.
- </doc>
-
- <implement role="server" handle="MUST"/>
- <implement role="client" handle="MUST"/>
- </command>
-
- <!-- - Command: execution.result - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="result" code="0xc" label="carries execution results">
- <doc>
- This command carries data resulting from the execution of a command.
- </doc>
-
- <implement role="server" handle="MUST"/>
- <implement role="client" handle="MUST"/>
-
- <field name="command-id" type="sequence-no" required="true"/>
- <field name="value" type="struct32"/>
- </command>
-
- </class>
-
- <!-- == Class: message ======================================================================= -->
-
- <class name="message" code="0x4" label="message transfer">
- <doc>
- The message class provides commands that support an industry-standard messaging model.
- </doc>
-
- <doc type="picture" title="Transfer States">
- START:
-
- The message has yet to be sent to the recipient.
-
- NOT-ACQUIRED:
-
- The message has been sent to the recipient, but is not
- acquired by the recipient.
-
- ACQUIRED:
-
- The message has been sent to and acquired by the recipient.
-
- END:
-
- The transfer is complete.
- </doc>
-
- <doc type="picture" title="State Transitions"><![CDATA[
- *:TRANSFER (accept-mode=none) *:TRANSFER (acquire-mode=pre-acquired)
- +---------------------------------START------------------------------------------+
- | | |
- | | *:TRANSFER (acquire-mode=not-acquired) |
- | | |
- | R:RELEASE \|/ |
- | +-------------NOT-ACQUIRED<--+ |
- | | | | | R:ACQUIRE (if unavailable) |
- | | | +-----+ |
- | | | |
- | | | R:ACQUIRE (if available) |
- | | | |
- | | \|/ |
- | | ACQUIRED<-------------------------------------------+
- | | |
- | | | R:ACCEPT / R:REJECT / R:RELEASE
- | | |
- | | \|/
- | +------------->END
- | /|\
- | |
- +-------------------------------+]]>
- </doc>
-
- <doc type="grammar">
- message = *:TRANSFER [ R:ACQUIRE ] [ R:ACCEPT / R:REJECT / R:RELEASE ]
- / *:RESUME
- / *:SET-FLOW-MODE
- / *:FLOW
- / *:STOP
- / C:SUBSCRIBE
- / C:CANCEL
- / C:FLUSH
- </doc>
-
- <rule name="persistent-message">
- <doc>
- The server SHOULD respect the delivery-mode property of messages and SHOULD make a
- best-effort to hold persistent messages on a reliable storage mechanism.
- </doc>
- <doc type="scenario">
- Send a persistent message to queue, stop server, restart server and then verify whether
- message is still present. Assumes that queues are durable. Persistence without durable
- queues makes no sense.
- </doc>
- </rule>
-
- <rule name="no-persistent-message-discard">
- <doc>
- The server MUST NOT discard a persistent message in case of a queue overflow.
- </doc>
- <doc type="scenario">
- Create a queue overflow situation with persistent messages and verify that messages do not
- get lost (presumably the server will write them to disk).
- </doc>
- </rule>
-
- <rule name="throttling">
- <doc>
- The server MAY use the message.flow command to slow or stop a message publisher when
- necessary.
- </doc>
- </rule>
-
- <rule name="non-persistent-message-overflow">
- <doc>
- The server MAY overflow non-persistent messages to persistent storage.
- </doc>
- </rule>
-
- <rule name="non-persistent-message-discard">
- <doc>
- The server MAY discard or dead-letter non-persistent messages on a priority basis if the
- queue size exceeds some configured limit.
- </doc>
- </rule>
-
- <rule name="min-priority-levels">
- <doc>
- The server MUST implement at least 2 priority levels for messages, where priorities 0 and
- 9 are treated as two distinct levels.
- </doc>
- </rule>
-
- <rule name="priority-level-implementation">
- <doc>
- The server SHOULD implement distinct priority levels in the following manner:
- </doc>
- <doc>
- If the server implements n distinct priorities then priorities 0 to 5 - ceiling(n/2) should
- be treated equivalently and should be the lowest effective priority. The priorities 4 +
- floor(n/2) should be treated equivalently and should be the highest effective priority. The
- priorities (5 - ceiling(n/2)) to (4 + floor(n/2)) inclusive must be treated as distinct
- priorities.
- </doc>
- <doc>
- Thus, for example, if 2 distinct priorities are implemented, then levels 0 to 4 are
- equivalent, and levels 5 to 9 are equivalent and levels 4 and 5 are distinct. If 3 distinct
- priorities are implements the 0 to 3 are equivalent, 5 to 9 are equivalent and 3, 4 and 5
- are distinct.
- </doc>
- <doc>
- This scheme ensures that if two priorities are distinct for a server which implements m
- separate priority levels they are also distinct for a server which implements n different
- priority levels where n > m.
- </doc>
- </rule>
-
- <rule name="priority-delivery">
- <doc>
- The server MUST deliver messages of the same priority in order irrespective of their
- individual persistence.
- </doc>
- <doc type="scenario">
- Send a set of messages with the same priority but different persistence settings to a queue.
- Subscribe and verify that messages arrive in same order as originally published.
- </doc>
- </rule>
-
- <role name="server" implement="MUST" />
- <role name="client" implement="MUST" />
-
- <domain name="message-id" type="uuid" label="globally unique message id"/>
-
- <domain name="accept-mode" type="uint8" label="indicates a confirmation mode">
- <doc>
- Controls how the sender of messages is notified of successful transfer.
- </doc>
-
- <enum>
- <choice name="explicit" value="0">
- <doc>
- Successful transfer is signaled by message.accept. An acquired message (whether
- acquisition was implicit as in pre-acquired mode or explicit as in not-acquired mode) is
- not considered transferred until a message.accept that includes the transfer command is
- received.
- </doc>
- </choice>
-
- <choice name="none" value="1">
- <doc>
- Successful transfer is assumed when accept-mode is "pre-acquired". Messages transferred
- with an accept-mode of "not-acquired" cannot be acquired when accept-mode is "none".
- </doc>
- </choice>
- </enum>
- </domain>
-
- <domain name="acquire-mode" type="uint8" label="indicates the transfer mode">
- <doc>
- Indicates whether a transferred message can be considered as automatically acquired or
- whether an explicit request is necessary in order to acquire it.
- </doc>
-
- <enum>
- <choice name="pre-acquired" value="0">
- <doc>
- the message is acquired when the transfer starts
- </doc>
- </choice>
-
- <choice name="not-acquired" value="1">
- <doc>
- the message is not acquired when it arrives, and must be explicitly acquired by the
- recipient
- </doc>
- </choice>
- </enum>
- </domain>
-
- <domain name="reject-code" type="uint16" label="reject code for transfer">
- <doc>
- Code specifying the reason for a message reject.
- </doc>
- <enum>
- <choice name="unspecified" value="0">
- <doc>
- Rejected for an unspecified reason.
- </doc>
- </choice>
- <choice name="unroutable" value="1">
- <doc>
- Delivery was attempted but there were no queues which the message could be routed to.
- </doc>
- </choice>
- </enum>
- </domain>
-
-<!--
- <domain name="resume-id" type="str16">
- <doc>
- A resume-id serves to identify partially transferred message content. The id is chosen by
- the sender, and must be unique to a given user. A resume-id is not expected to be unique
- across users.
- </doc>
- </domain>
--->
-
- <domain name="delivery-mode" type="uint8"
- label="indicates whether a message should be treated as transient or durable">
- <doc>
-
- Used to set the reliability requirements for a message which is transferred to the server.
- </doc>
- <enum>
- <choice name="non-persistent" value="1">
- <doc>
- A non-persistent message may be lost in event of a failure, but the nature of the
- communication is such that an occasional message loss is tolerable. This is the lowest
- overhead mode. Non-persistent messages are delivered at most once only.
- </doc>
- </choice>
-
- <choice name="persistent" value="2">
- <doc>
- A persistent message is one which must be stored on a persistent medium (usually hard
- drive) at every stage of delivery so that it will not be lost in event of failure (other
- than of the medium itself). This is normally accomplished with some additional overhead.
- A persistent message may be delivered more than once if there is uncertainty about the
- state of its delivery after a failure and recovery.
- </doc>
- </choice>
- </enum>
- </domain>
-
- <domain name="delivery-priority" type="uint8"
- label="indicates the desired priority to assign to a message transfer">
- <doc>
- Used to assign a priority to a message transfer. Priorities range from 0 (lowest) to 9
- (highest).
- </doc>
- <enum>
- <choice name="lowest" value="0">
- <doc>
- Lowest possible priority message.
- </doc>
- </choice>
-
- <choice name="lower" value="1">
- <doc>
- Very low priority message
- </doc>
- </choice>
-
- <choice name="low" value="2">
- <doc>
- Low priority message.
- </doc>
- </choice>
-
- <choice name="below-average" value="3">
- <doc>
- Below average priority message.
- </doc>
- </choice>
-
- <choice name="medium" value="4">
- <doc>
- Medium priority message.
- </doc>
- </choice>
-
-
- <choice name="above-average" value="5">
- <doc>
- Above average priority message
- </doc>
- </choice>
-
-
- <choice name="high" value="6">
- <doc>
- High priority message
- </doc>
- </choice>
-
- <choice name="higher" value="7">
- <doc>
- Higher priority message
- </doc>
- </choice>
-
- <choice name="very-high" value="8">
- <doc>
- Very high priority message.
- </doc>
- </choice>
-
- <choice name="highest" value="9">
- <doc>
- Highest possible priority message.
- </doc>
- </choice>
- </enum>
- </domain>
-
- <struct name="delivery-properties" size="4" code="0x1" pack="2">
- <field name="accept-mode" type="accept-mode" required="true">
- <doc>
- Indicates whether message.accept, session.complete, or nothing at all is required to
- indicate successful transfer of the message.
- </doc>
- </field>
-
- <field name="acquire-mode" type="acquire-mode" required="true">
- <doc>
- Indicates whether or not the transferred message has been acquired.
- </doc>
- </field>
-
- <field name="discard-unroutable" type="bit" label="controls discard of unroutable messages">
- <doc>
- If set on a message that is not routable the broker can discard it. If not set, an
- unroutable message should be handled by reject when accept-mode is explicit; or by routing
- to the alternate-exchange if defined when accept-mode is none.
- </doc>
- </field>
-
- <field name="redelivered" type="bit" label="redelivery flag">
- <doc>
- This boolean flag indicates that the message may have been previously delivered to this
- or another client.
- </doc>
- <doc>
- If the redelivered flag is set on transfer to a Server, then any delivery of the message
- from that Server to a Client must also have the redelivered flag set to true.
- </doc>
- <rule name="implementation">
- <doc>
- The server MUST try to signal redelivered messages when it can. When redelivering a
- message that was not successfully accepted, the server SHOULD deliver it to the original
- client if possible.
- </doc>
- <doc type="scenario">
- Create a shared queue and publish a message to the queue. Subscribe using explicit
- accept-mode, but do not accept the message. Close the session, reconnect, and subscribe
- to the queue again. The message MUST arrive with the redelivered flag set.
- </doc>
- </rule>
- <rule name="hinting">
- <doc>
- The client should not rely on the redelivered field to detect duplicate messages where
- publishers may themselves produce duplicates. A fully robust client should be able to
- track duplicate received messages on non-transacted, and locally-transacted sessions.
- </doc>
- </rule>
- </field>
-
- <field name="priority" type="delivery-priority" label="message priority, 0 to 9"
- required="true">
- <doc> Message priority, which can be between 0 and 9. Messages with higher priorities may be
- delivered before those with lower priorities. </doc>
- </field>
-
- <field name="delivery-mode" type="delivery-mode" label="message persistence requirement"
- required="true">
- <doc> The delivery mode may be non-persistent or persistent. </doc>
- </field>
-
- <field name="ttl" type="uint64" label="time to live in ms">
- <doc> Duration in milliseconds for which the message should be considered "live". If this is
- set then a message expiration time will be computed based on the current time plus this
- value. Messages that live longer than their expiration time will be discarded (or dead
- lettered).</doc>
- <rule name="ttl-decrement">
- <doc>
- If a message is transferred between brokers before delivery to a final subscriber the
- ttl should be decremented before peer to peer transfer and both timestamp and expiration
- should be cleared.
- </doc>
- </rule>
- </field>
-
- <field name="timestamp" type="datetime" label="message timestamp">
- <doc>
- The timestamp is set by the broker on arrival of the message.
- </doc>
- </field>
-
- <field name="expiration" type="datetime" label="message expiration time">
- <doc>
- The expiration header assigned by the broker. After receiving the message the broker sets
- expiration to the sum of the ttl specified in the publish command and the current time.
- (ttl=expiration - timestamp)
- </doc>
- </field>
-
- <field name="exchange" type="exchange.name" label="originating exchange">
- <doc>
- Identifies the exchange specified in the destination field of the message.transfer used to
- publish the message. This MUST be set by the broker upon receipt of a message.
- </doc>
- </field>
-
- <field name="routing-key" type="str8" label="message routing key">
- <doc>
- The value of the key determines to which queue the exchange will send the message. The way
- in which keys are used to make this routing decision depends on the type of exchange to
- which the message is sent. For example, a direct exchange will route a message to a queue
- if that queue is bound to the exchange with a binding-key identical to the routing-key of
- the message.
- </doc>
- </field>
-
-<!--
- <field name="resume-id" type="resume-id" label="global id for message transfer">
- <doc>
- When a resume-id is provided the recipient MAY use it to retain message data should the
- session expire while the message transfer is still incomplete.
- </doc>
- </field>
--->
-
- <field name="resume-ttl" type="uint64" label="ttl in ms for interrupted message data">
- <doc>
- When a resume-ttl is provided the recipient MAY use it has a guideline for how long to
- retain the partially complete data.
- </doc>
- </field>
- </struct>
-
-<!-- XXX
- <struct name="reply-to" size="2" pack="2">
- <doc>The reply-to domain provides a simple address structure for replying to to a message to a
- destination within the same virtual-host.</doc>
- <field name="exchange" type="exchange.name" label="the name of the exchange to reply to"/>
- <field name="routing-key" type="str8" label="the routing-key to use when replying"/>
- </struct>
--->
-
- <struct name="message-properties" size="4" code="0x3" pack="2">
- <field name="content-length" type="uint64" label="length of the body segment in bytes">
- <doc>
- The length of the body segment in bytes.
- </doc>
- </field>
-
- <field name="message-id" type="message-id" label="application message identifier">
- <doc>
- Message-id is an optional property of UUID type which uniquely identifies a message within
- the message system. The message producer is usually responsible for setting the
- message-id. The server MAY discard a message as a duplicate if the value of the message-id
- matches that of a previously received message. Duplicate messages MUST still be accepted
- if transferred with an accept-mode of "explicit".
- </doc>
-
- <rule name="unique">
- <doc>
- A message-id MUST be unique within a given server instance. A message-id SHOULD be
- globally unique (i.e. across different systems).
- </doc>
- </rule>
-
- <rule name="immutable">
- <doc>
- A message ID is immutable. Once set, a message-id MUST NOT be changed or reassigned,
- even if the message is replicated, resent or sent to multiple queues.
- </doc>
- </rule>
- </field>
-
- <field name="correlation-id" type="vbin16" label="application correlation identifier">
- <doc>
- This is a client-specific id that may be used to mark or identify messages between
- clients. The server ignores this field.
- </doc>
- </field>
-
- <field name="reply-to" type="route.address" label="destination to reply to">
- <doc>
- The destination of any message that is sent in reply to this message.
- </doc>
- </field>
-
- <field name="content-type" type="str8" label="MIME content type">
- <doc>
- The RFC-2046 MIME type for the message content (such as "text/plain"). This is set by the
- originating client.
- </doc>
- </field>
-
- <field name="content-encoding" type="str8" label="MIME content encoding">
- <doc>
- The encoding for character-based message content. This is set by the originating client.
- Examples include UTF-8 and ISO-8859-15.
- </doc>
- </field>
-
- <field name="user-id" type="vbin16" label="creating user id">
- <doc>
- The identity of the user responsible for producing the message. The client sets this
- value, and it is authenticated by the broker.
- </doc>
-
- <rule name="authentication">
- <doc>
- The server MUST produce an unauthorized-access exception if the user-id field is set to
- a principle for which the client is not authenticated.
- </doc>
- </rule>
- </field>
-
- <field name="app-id" type="vbin16" label="creating application id">
- <doc>
- The identity of the client application responsible for producing the message.
- </doc>
- </field>
-
-<!-- XXX: moved to top level headers map
- <field name="application-headers" type="map" label="application specific headers table">
- <doc>
- This is a collection of user-defined headers or properties which may be set by the
- producing client and retrieved by the consuming client.
- </doc>
- </field>
--->
- </struct>
-
- <!-- - Command: message.transfer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="transfer" code="0x1" label="transfer a message">
- <doc>
- This command transfers a message between two peers. When a client uses this command to
- publish a message to a broker, the destination identifies a specific exchange. The message
- will then be routed to queues as defined by the exchange configuration.
-
- The client may request a broker to transfer messages to it, from a particular queue, by
- issuing a subscribe command. The subscribe command specifies the destination that the broker
- should use for any resulting transfers.
- </doc>
-
- <rule name="transactional-publish">
- <doc>
- If a transfer to an exchange occurs within a transaction, then it is not available from
- the queue until the transaction commits. It is not specified whether routing takes place
- when the transfer is received or when the transaction commits.
- </doc>
- </rule>
-
- <implement role="server" handle="MUST" />
- <implement role="client" handle="MUST" />
-
-
- <field name="route" type="uint64" label="handle for message route">
- <doc>
- Specifies the destination to which the message is to be transferred.
- </doc>
-
- <rule name="blank-destination">
- <doc>
- The server MUST accept a blank destination to mean the default exchange.
- </doc>
- </rule>
-
- <exception name="nonexistent-exchange" error-code="not-found">
- <doc>
- If the destination refers to an exchange that does not exist, the peer MUST raise a
- session exception.
- </doc>
- </exception>
- </field>
-
- <field name="more" type="bit" label="indicates that this message has more content"/>
-
- <field name="fragment-offset" type="uint64" label="the offset of payload within the message"/>
-
- <field name="headers" type="map" label="message headers">
- <doc type="picture" title="Standard Entries">
- "delivery-properties" -> delivery-properties
- "message-properties" -> message-properties
- "application-headers" -> map
- </doc>
- </field>
-
- <field name="payload" type="vbin32" label="message data"/>
- </command>
-
- <!-- - Command: message.accept - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="accept" code="0x2" label="reject a message">
- <doc>
- Accepts the message. Once a transfer is accepted, the command-id may no longer be referenced
- from other commands.
- </doc>
-
- <rule name="acquisition">
- <doc>
- The recipient MUST have acquired a message in order to accept it.
- </doc>
- </rule>
-
- <implement role="server" handle="MUST" />
- <implement role="client" handle="MUST" />
-
- <field name="transfers" type="session.commands" required="true">
- <doc>
- Identifies the messages previously transferred that should be accepted.
- </doc>
- </field>
- </command>
-
- <!-- - Command: message.reject - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="reject" code="0x3" label="reject a message">
- <doc>
- Indicates that the message transfers are unprocessable in some way. A server may reject a
- message if it is unroutable. A client may reject a message if it is invalid. A message may
- be rejected for other reasons as well. Once a transfer is rejected, the command-id may no
- longer be referenced from other commands.
- </doc>
-
- <rule name="alternate-exchange">
- <doc>
- When a client rejects a message, the server MUST deliver that message to the
- alternate-exchange on the queue from which it was delivered. If no alternate-exchange is
- defined for that queue the broker MAY discard the message.
- </doc>
- </rule>
-
- <rule name="acquisition">
- <doc>
- The recipient MUST have acquired a message in order to reject it. If the message is not
- acquired any reject MUST be ignored.
- </doc>
- </rule>
-
- <implement role="server" handle="MUST" />
- <implement role="client" handle="MUST" />
-
- <field name="transfers" type="session.commands" required="true">
- <doc>
- Identifies the messages previously transferred that should be rejected.
- </doc>
- </field>
- <field name="code" type="reject-code" required="true">
- <doc>
- Code describing the reason for rejection.
- </doc>
- </field>
- <field name="text" type="str8" label="informational text for message reject">
- <doc>
- Text describing the reason for rejection.
- </doc>
- </field>
- </command>
-
- <!-- - Command: message.release - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="release" code="0x4" label="release a message">
- <doc>
- Release previously transferred messages. When acquired messages are released, they become
- available for acquisition by any subscriber. Once a transfer is released, the command-id may
- no longer be referenced from other commands.
- </doc>
-
- <rule name="ordering">
- <doc>
- Acquired messages that have been released MAY subsequently be delivered out of order.
- Implementations SHOULD ensure that released messages keep their position with respect to
- undelivered messages of the same priority.
- </doc>
- </rule>
-
- <implement role="server" handle="MUST" />
- <implement role="client" handle="MAY" />
-
- <field name="transfers" type="session.commands" required="true">
- <doc>
- Indicates the messages to be released.
- </doc>
- </field>
- <field name="set-redelivered" type="bit" label="mark the released messages as redelivered">
- <doc>
- By setting set-redelivered to true, any acquired messages released to a queue with this
- command will be marked as redelivered on their next transfer from that queue. If this flag
- is not set, then an acquired message will retain its original redelivered status on the
- queue. Messages that are not acquired are unaffected by the value of this flag.
- </doc>
- </field>
- </command>
-
- <!-- - Command: message.acquire - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="acquire" code="0x5" label="acquire messages for consumption">
- <doc>
- Acquires previously transferred messages for consumption. The acquired ids (if any) are
- sent via message.acquired.
- </doc>
-
- <rule name="one-to-one">
- <doc>
- Each acquire MUST produce exactly one message.acquired even if it is empty.
- </doc>
- </rule>
-
- <implement role="server" handle="MUST" />
-
- <field name="transfers" type="session.commands" required="true">
- <doc>
- Indicates the messages to be acquired.
- </doc>
- </field>
-
- <result>
- <struct name="acquired" size="4" code="0x4" pack="2" label="indicates acquired messages">
- <doc>
- Identifies a set of previously transferred messages that have now been acquired.
- </doc>
-
- <field name="transfers" type="session.commands" required="true">
- <doc>
- Indicates the acquired messages.
- </doc>
- </field>
- </struct>
- </result>
- </command>
-
- </class>
-
- <!-- == Class: route ========================================================================= -->
-
- <class name="route" code="0xff" label="flow control routes">
-
- <role name="server" implement="MUST" />
- <role name="client" implement="MUST" />
-
- <domain name="address" type="str16" label="source or destination for a message">
- <doc>
- Specifies the source or destination to which the message is to be transferred to or from.
- </doc>
- </domain>
-
- <domain name="flow-mode" type="uint8" label="the flow-mode for allocating flow credit">
- <enum>
- <choice name="credit" value="0">
- <doc>
- Credit based flow control.
- </doc>
- </choice>
-
- <choice name="window" value="1">
- <doc>
- Window based flow control.
- </doc>
- </choice>
- </enum>
- </domain>
-
- <command name="open" code="0xfe" label="open a destination for transfer">
- <implement role="server" handle="MUST" />
-
- <field name="name" type="str8" label="the name of the route" required="true" />
-
- <field name="address" type="address" required="true">
- <exception name="destination-not-found" error-code="not-found">
- <doc>If the destination does not exist, the recipient MUST close the session.</doc>
- </exception>
- </field>
-
- <field name="durable" type="bit" label="indicates that the route is durable"/>
-
- <field name="read" type="bit" label="requests that messages be sent from the address"/>
-
- <field name="write" type="bit" label="indicates that messages will be sent to the address"/>
-
- <field name="resume-id" type="message.message-id">
- <doc>
- If present, indicates that the sender can resume transfer of the given message-id.
- </doc>
- </field>
- </command>
-
- <command name="close" code="0xff" label="notify of destination closure">
- <!-- XXX
- <doc>
- This command cancels a subscription. This does not affect already delivered messages, but
- it does mean the server will not send any more messages for that subscription. The client
- may receive an arbitrary number of messages in between sending the cancel command and
- receiving notification that the cancel command is complete.
- </doc>
- -->
-
- <field name="name" type="str8" required="true"/>
- <field name="read" type="bit" label="close for read"/>
- <field name="write" type="bit" label="close for write"/>
- </command>
-
- <!-- - Command: route.start - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="start" code="0x7" label="start a queue subscription">
- <doc>
- This command asks the server to start a "subscription", which is a request for messages from
- a specific queue. Subscriptions last as long as the session they were created on, or until
- the client cancels them.
- </doc>
-
- <rule name="simultaneous-subscriptions">
- <doc>
- The server SHOULD support at least 16 subscriptions per queue, and ideally, impose no
- limit except as defined by available resources.
- </doc>
- <doc type="scenario">
- Create a queue and create subscriptions on that queue until the server closes the
- connection. Verify that the number of subscriptions created was at least sixteen and
- report the total number.
- </doc>
- </rule>
-
- <rule name="default-flow-mode">
- <doc> The default flow mode for new subscriptions is window-mode. </doc>
- </rule>
-
- <exception name="queue-deletion" error-code="resource-deleted">
- <doc>
- If the queue for this subscription is deleted, any subscribing sessions MUST be closed.
- This exception may occur at any time after the subscription has been completed.
- </doc>
- </exception>
-
- <exception name="queue-not-found" error-code="not-found">
- <doc>
- If the queue for this subscription does not exist, then the subscribing session MUST be
- closed.
- </doc>
- </exception>
-
- <rule name="initial-credit">
- <doc>
- Immediately after a subscription is created, the initial byte and message credit for that
- destination is zero.
- </doc>
- </rule>
-
- <implement role="server" handle="MUST"/>
-
-<!-- XXX rolled into destination
- <field name="queue" type="queue.name" required="true">
- <doc>
- Specifies the name of the subscribed queue.
- </doc>
- </field>
--->
-
- <field name="name" type="str8" label="the route name">
- <doc> The client specified name for the subscription. This is used as the destination for
- all messages transferred from this subscription. The destination is scoped to the session.
- </doc>
-
- <exception name="unique-subscriber-destination" error-code="not-allowed">
- <doc>
- The client MUST NOT specify a destination that refers to an existing subscription on the
- same session.
- </doc>
- <doc type="scenario">
- Attempt to create two subscriptions on the same session with the same non-empty
- destination.
- </doc>
- </exception>
- </field>
-
- <field name="handle" type="uint64" label="route handle"/>
-
- <field name="accept-mode" type="message.accept-mode" required="true">
- <doc>
- The accept-mode to use for messages transferred from this subscription.
- </doc>
- </field>
-
- <field name="acquire-mode" type="message.acquire-mode" required="true">
- <doc>
- The acquire-mode to use for messages transferred from this subscription.
- </doc>
- </field>
-
- <field name="exclusive" type="bit" label="request exclusive access">
- <doc>
- Request an exclusive subscription. This prevents other subscribers from subscribing to the
- queue.
- </doc>
-
- <exception name="in-use" error-code="resource-locked">
- <doc>
- The server MUST NOT grant an exclusive subscription to a queue that already has
- subscribers.
- </doc>
- <doc type="scenario">
- Open two connections to a server, and in one connection create a shared (non-exclusive)
- queue and then subscribe to the queue. In the second connection attempt to subscribe to
- the same queue using the exclusive option.
- </doc>
- </exception>
- </field>
-
- <field name="resume-id" type="message.message-id">
- <doc>
- Requests that the sender resume the given message-id if it is still available.
- </doc>
- </field>
-
- <field name="resume-offset" type="uint64">
- <doc>
- Indicates the amount of data already transferred.
- </doc>
- </field>
-
- <field name="flow-mode" type="flow-mode" label="set the flow control mode" required="true">
- <doc>
- The new flow control mode.
- </doc>
-
- <doc>
- Sets the mode of flow control used for a given destination to either window or credit
- based flow control.
-
- With credit based flow control, the sender of messages continually maintains its current
- credit balance with the recipient. The credit balance consists of two values, a message
- count, and a byte count. Whenever message data is sent, both counts must be decremented.
- If either value reaches zero, the flow of message data must stop. Additional credit is
- received via the message.flow command.
-
- The sender MUST NOT send partial commands. This means that if there is not enough byte
- credit available to send a complete command, the sender must either wait or use message
- fragmentation (multiple message.transfer commands) to send the first part of the message
- data in a complete command.
-
- Window based flow control is identical to credit based flow control, however message
- transfer completion implicitly grants a single unit of message credit, and the size of the
- message in byte credits for each completed message transfer. Completion of the transfer
- command with session.completed is the only way credit is implicitly updated;
- message.accept, message.release, message.reject, tx.commit and tx.rollback have no effect
- on the outstanding credit balances.
- </doc>
-
- <rule name="byte-accounting">
- <doc>
- The byte count is decremented by the payload size of each transmitted frame with segment
- type header or body appearing within a message.transfer command. Note that the payload
- size is the frame size less the frame header size.
- </doc>
- </rule>
-
- <rule name="mode-switching">
- <doc>
- Mode switching may only occur if both the byte and message credit balance are zero.
- There are three ways for a recipient of messages to be sure that the sender's credit
- balances are zero:
-
- 1) The recipient may send a message.stop command to the sender. When the recipient
- receives notification of completion for the message.stop command, it knows that the
- sender's credit is zero.
-
- 2) The recipient may perform the same steps described in (1) with the message.fetch
- command substituted for the message.stop command.
-
- 3) Immediately after a subscription is created with message.subscribe, the credit for
- that destination is zero.
- </doc>
- </rule>
-
- <rule name="default-flow-mode">
- <doc>
- Prior to receiving an explicit set-flow-mode command, a peer MUST consider the flow-mode
- to be window.
- </doc>
- </rule>
- </field>
-
- <field name="initial-message-credit" type="uint32">
- <doc>
- If the value is not set then this indicates an infinite amount of credit.
- </doc>
- </field>
-
- <field name="initial-byte-credit" type="uint32">
- <doc>
- If the value is not set then this indicates an infinite amount of credit.
- </doc>
- </field>
-
- <field name="arguments" type="map" label="arguments for vendor extensions">
- <doc>
- The syntax and semantics of these arguments depends on the providers implementation.
- </doc>
- </field>
- </command>
-
- <!-- - Command: route.stop - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="stop" code="0x8" label="stop the sending of messages">
- <doc>
- On receipt of this command, a producer of messages MUST set his credit to zero for the
- given destination. When notifying of completion, credit MUST be zero and no further
- messages will be sent until such a time as further credit is received.
- </doc>
-
- <rule name="post-cancel-transfer-resolution">
- <doc>
- Canceling a subscription MUST NOT affect pending transfers. A transfer made prior to
- canceling transfers to the destination MUST be able to be accepted, released, acquired, or
- rejected after the subscription is canceled.
- </doc>
- </rule>
-
- <implement role="server" handle="MUST" />
-
- <field name="handle" type="uint64" required="true">
- <exception name="subscription-not-found" error-code="not-found">
- <doc>
- If the subscription specified by the destination is not found, the server MUST close the
- session.
- </doc>
- </exception>
- </field>
- </command>
-
- <!-- - Command: route.flow - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="flow" code="0xa" label="control message flow">
- <doc>
- This command controls the flow of message data to a given destination. It is used by the
- recipient of messages to dynamically match the incoming rate of message flow to its
- processing or forwarding capacity. Upon receipt of this command, the sender must add "value"
- number of the specified messages and bytes to the available credit balances for the
- specified destination. If a value is unset it indicates an infinite amount of credit. This
- disables any limit for the given unit until the credit balance is zeroed with message.stop
- or message.fetch.
- </doc>
-
- <!-- throws no-such-destination -->
-
- <implement role="server" handle="MUST" />
- <implement role="client" handle="MUST" />
-
- <field name="destination" type="uint64"/>
- <field name="messages" type="uint32">
- <doc>
- If the value is not set then this indicates an infinite amount of credit.
- </doc>
- </field>
- <field name="bytes" type="uint32">
- <doc>
- If the value is not set then this indicates an infinite amount of credit.
- </doc>
- </field>
- </command>
-
- <!-- - Command: route.fetch - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="fetch" code="0xb" label="force the sending of available messages">
- <doc>
- Forces the sender to exhaust his credit supply. The sender's credit will always be zero when
- this command completes. The command completes when immediately available message data has
- been transferred, or when the credit supply is exhausted.
- </doc>
-
- <implement role="server" handle="MUST" />
-
- <field name="destination" type="uint64"/>
- </command>
-
- </class>
-
- <!-- == Class: tx ============================================================================ -->
-
- <class name="tx" code="0x5" label="work with standard transactions">
- <doc>
- Standard transactions provide so-called "1.5 phase commit". We can ensure that work is never
- lost, but there is a chance of confirmations being lost, so that messages may be resent.
- Applications that use standard transactions must be able to detect and ignore duplicate
- messages.
- </doc>
-
- <doc type="grammar">
- tx = C:SELECT
- / C:COMMIT
- / C:ROLLBACK
- </doc>
-
- <!-- XXX: this isn't really a rule, as stated there is no way for
- a client library to implement this -->
- <rule name="duplicate-tracking">
- <doc>
- An client using standard transactions SHOULD be able to track all messages received within a
- reasonable period, and thus detect and reject duplicates of the same message. It SHOULD NOT
- pass these to the application layer.
- </doc>
- </rule>
-
- <role name="server" implement="SHOULD" />
-
- <!-- - Command: tx.select - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="select" code="0x1" label="select standard transaction mode">
- <doc>
- This command sets the session to use standard transactions. The client must use this command
- exactly once on a session before using the Commit or Rollback commands.
- </doc>
-
- <exception name="exactly-once" error-code="illegal-state">
- <doc>
- A client MUST NOT select standard transactions on a session that is already transactional.
- </doc>
- </exception>
-
- <exception name="no-dtx" error-code="illegal-state">
- <doc>
- A client MUST NOT select standard transactions on a session that is already enlisted in a
- distributed transaction.
- </doc>
- </exception>
-
- <exception name="explicit-accepts" error-code="not-allowed">
- <doc>
- On a session on which tx.select has been issued, a client MUST NOT issue a
- message.subscribe command with the accept-mode property set to any value other than
- explicit. Similarly a tx.select MUST NOT be issued on a session on which a there is a non
- cancelled subscriber with accept-mode of none.
- </doc>
- </exception>
-
- <implement role="server" handle="MUST" />
- </command>
-
- <!-- - Command: tx.commit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="commit" code="0x2" label="commit the current transaction">
- <doc>
- This command commits all messages published and accepted in the current transaction. A
- new transaction starts immediately after a commit.
- </doc>
- <doc>
- In more detail, the commit acts on all messages which have been transferred from the Client
- to the Server, and on all acceptances of messages sent from Server to Client. Since the
- commit acts on commands sent in the same direction as the commit command itself, there is no
- ambiguity on the scope of the commands being committed. Further, the commit will not be
- completed until all preceding commands which it affects have been completed.
- </doc>
- <doc>
- Since transactions act on explicit accept commands, the only valid accept-mode for message
- subscribers is explicit. For transferring messages from Client to Server (publishing) all
- accept-modes are permitted.
- </doc>
-
- <exception name="select-required" error-code="illegal-state">
- <doc>
- A client MUST NOT issue tx.commit on a session that has not been selected for standard
- transactions with tx.select.
- </doc>
- </exception>
-
-
-
- <implement role="server" handle="MUST" />
- </command>
-
- <!-- - Command: tx.rollback - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="rollback" code="0x3" label="abandon the current transaction">
- <doc>
- This command abandons the current transaction. In particular the transfers from Client to
- Server (publishes) and accepts of transfers from Server to Client which occurred in the
- current transaction are discarded. A new transaction starts immediately after a rollback.
- </doc>
- <doc>
- In more detail, when a rollback is issued, any the effects of transfers which occurred from
- Client to Server are discarded. The Server will issue completion notification for all such
- transfers prior to the completion of the rollback. Similarly the effects of any
- message.accept issued from Client to Server prior to the issuance of the tx.rollback will be
- discarded; and notification of completion for all such commands will be issued before the
- issuance of the completion for the rollback.
- </doc>
- <doc>
- After the completion of the rollback, the client will still hold the messages which it has
- not yet accepted (including those for which accepts were previously issued within the
- transaction); i.e. the messages remain "acquired". If the Client wishes to release those
- messages back to the Server, then appropriate message.release commands must be issued.
- </doc>
-
- <exception name="select-required" error-code="illegal-state">
- <doc>
- A client MUST NOT issue tx.rollback on a session that has not been selected for standard
- transactions with tx.select.
- </doc>
- </exception>
-
- <implement role="server" handle="MUST" />
- </command>
-
- </class>
-
- <!-- == Class: dtx =========================================================================== -->
-
- <class name="dtx" code="0x6" label="Demarcates dtx branches">
- <doc>
- This provides the X-Open XA distributed transaction protocol support. It allows a session
- to be selected for use with distributed transactions, the transactional boundaries for work on
- that session to be demarcated and allows the transaction manager to coordinate transaction
- outcomes.
- </doc>
-
- <doc type="grammar">
- dtx-demarcation = C:SELECT *demarcation
- demarcation = C:START C:END
- </doc>
-
- <doc type="grammar">
- dtx-coordination = *coordination
- coordination = command
- / outcome
- / recovery
- command = C:SET-TIMEOUT
- / C:GET-TIMEOUT
- outcome = one-phase-commit
- / one-phase-rollback
- / two-phase-commit
- / two-phase-rollback
- one-phase-commit = C:COMMIT
- one-phase-rollback = C:ROLLBACK
- two-phase-commit = C:PREPARE C:COMMIT
- two-phase-rollback = C:PREPARE C:ROLLBACK
- recovery = C:RECOVER *recovery-outcome
- recovery-outcome = one-phase-commit
- / one-phase-rollback
- / C:FORGET
-
- </doc>
-
- <rule name="transactionality">
- <doc>
- Enabling XA transaction support on a session requires that the server MUST manage
- transactions demarcated by start-end blocks. That is to say that on this XA-enabled session,
- work undergone within transactional blocks is performed on behalf a transaction branch
- whereas work performed outside of transactional blocks is NOT transactional.
- </doc>
- </rule>
-
- <role name="server" implement="MAY" />
- <role name="client" implement="MAY" />
-
- <!-- XA domains -->
-
- <domain name="xa-status" type="uint16" label="XA return codes">
- <enum>
- <choice name="xa-ok" value="0">
- <doc>
- Normal execution completion (no error).
- </doc>
- </choice>
-
- <choice name="xa-rbrollback" value="1">
- <doc>
- The rollback was caused for an unspecified reason.
- </doc>
- </choice>
-
- <choice name="xa-rbtimeout" value="2">
- <doc>
- A transaction branch took too long.
- </doc>
- </choice>
-
- <choice name="xa-heurhaz" value="3">
- <doc>
- The transaction branch may have been heuristically completed.
- </doc>
- </choice>
-
- <choice name="xa-heurcom" value="4">
- <doc>
- The transaction branch has been heuristically committed.
- </doc>
- </choice>
-
- <choice name="xa-heurrb" value="5">
- <doc>
- The transaction branch has been heuristically rolled back.
- </doc>
- </choice>
-
- <choice name="xa-heurmix" value="6">
- <doc>
- The transaction branch has been heuristically committed and rolled back.
- </doc>
- </choice>
-
- <choice name="xa-rdonly" value="7">
- <doc>
- The transaction branch was read-only and has been committed.
- </doc>
- </choice>
- </enum>
- </domain>
-
- <struct name="xa-result" size="4" code="0x1" pack="2">
- <field name="status" type="xa-status" required="true"/>
- </struct>
-
- <!-- Struct for xid -->
-
- <struct name="xid" size="2" pack="2" label="dtx branch identifier">
- <doc>
- An xid uniquely identifies a transaction branch.
- </doc>
-
- <field name="format" type="uint32" label="implementation specific format code"
- required="true"/>
- <field name="global-id" type="vbin8" label="global transaction id" required="true"/>
- <field name="branch-id" type="vbin8" label="branch qualifier" required="true"/>
- </struct>
-
- <!-- - Command: dtx.select - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="select" code="0x1" label="Select dtx mode">
- <doc>
- This command sets the session to use distributed transactions. The client must use this
- command at least once on a session before using XA demarcation operations.
- </doc>
-
- <implement role="server" handle="MAY" />
- </command>
-
- <!-- - Command: dtx.start - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="start" code="0x2" label="Start a dtx branch">
- <doc>
- This command is called when messages should be produced and consumed on behalf a transaction
- branch identified by xid.
- </doc>
-
- <exception name="illegal-state" error-code="illegal-state">
- <doc>
- If the command is invoked in an improper context (see class grammar) then the server MUST
- send a session exception.
- </doc>
- </exception>
-
- <exception name="already-known" error-code="not-allowed">
- <doc>
- If neither join nor resume is specified is specified and the transaction branch specified
- by xid has previously been seen then the server MUST raise an exception.
- </doc>
- </exception>
-
- <exception name="join-and-resume" error-code="not-allowed">
- <doc>
- If join and resume are specified then the server MUST raise an exception.
- </doc>
- </exception>
-
- <implement role="server" handle="MAY" />
-
- <field name="xid" type="xid" label="Transaction xid" required="true">
- <doc>
- Specifies the xid of the transaction branch to be started.
- </doc>
-
- <exception name="unknown-xid" error-code="not-allowed">
- <doc>
- If xid is already known by the broker then the server MUST raise an exception.
- </doc>
- </exception>
- </field>
-
- <field name="join" type="bit" label="Join with existing xid flag">
- <doc>
- Indicate whether this is joining an already associated xid. Indicate that the start
- applies to joining a transaction previously seen.
- </doc>
-
- <exception name="unsupported" error-code="not-implemented">
- <doc>
- If the broker does not support join the server MUST raise an exception.
- </doc>
- </exception>
- </field>
-
- <field name="resume" type="bit" label="Resume flag">
- <doc>
- Indicate that the start applies to resuming a suspended transaction branch specified.
- </doc>
- </field>
-
- <result type="xa-result">
- <doc>
- This confirms to the client that the transaction branch is started or specify the error
- condition.
-
- The value of this field may be one of the following constants:
-
- xa-ok: Normal execution.
-
- xa-rbrollback: The broker marked the transaction branch rollback-only for an unspecified
- reason.
-
- xa-rbtimeout: The work represented by this transaction branch took too long.
- </doc>
- </result>
- </command>
-
- <!-- - Command: dtx.end - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="end" code="0x3" label="End a dtx branch">
- <doc>
- This command is called when the work done on behalf a transaction branch finishes or needs
- to be suspended.
- </doc>
-
- <exception name="illegal-state" error-code="illegal-state">
- <doc>
- If the command is invoked in an improper context (see class grammar) then the server MUST
- raise an exception.
- </doc>
- </exception>
-
- <exception name="suspend-and-fail" error-code="not-allowed">
- <doc>
- If suspend and fail are specified then the server MUST raise an exception.
- </doc>
- </exception>
-
- <rule name="success">
- <doc>
- If neither fail nor suspend are specified then the portion of work has completed
- successfully.
- </doc>
- </rule>
-
- <rule name="session-closed">
- <doc>
- When a session is closed then the currently associated transaction branches MUST be marked
- rollback-only.
- </doc>
- </rule>
-
- <implement role="server" handle="MAY" />
-
- <field name="xid" type="xid" label="Transaction xid" required="true">
- <doc>
- Specifies the xid of the transaction branch to be ended.
- </doc>
-
- <exception name="not-associated" error-code="illegal-state">
- <doc>
- The session MUST be currently associated with the given xid (through an earlier start
- call with the same xid).
- </doc>
- </exception>
- </field>
-
- <field name="fail" type="bit" label="Failure flag">
- <doc>
- If set, indicates that this portion of work has failed; otherwise this portion of work has
- completed successfully.
- </doc>
-
- <rule name="failure">
- <doc>
- An implementation MAY elect to roll a transaction back if this failure notification is
- received. Should an implementation elect to implement this behavior, and this bit is
- set, then then the transaction branch SHOULD be marked as rollback-only and the end
- result SHOULD have the xa-rbrollback status set.
- </doc>
- </rule>
- </field>
-
- <field name="suspend" type="bit" label="Temporary suspension flag">
- <doc>
- Indicates that the transaction branch is temporarily suspended in an incomplete state.
- </doc>
-
- <rule name="resume">
- <doc>
- The transaction context is in a suspended state and must be resumed via the start
- command with resume specified.
- </doc>
- </rule>
-
- </field>
-
- <result type="xa-result">
- <doc>
- This command confirms to the client that the transaction branch is ended or specify the
- error condition.
-
- The value of this field may be one of the following constants:
-
- xa-ok: Normal execution.
-
- xa-rbrollback: The broker marked the transaction branch rollback-only for an unspecified
- reason. If an implementation chooses to implement rollback-on-failure behavior, then
- this value should be selected if the dtx.end.fail bit was set.
-
- xa-rbtimeout: The work represented by this transaction branch took too long.
- </doc>
- </result>
- </command>
-
- <!-- - Command: dtx.commit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="commit" code="0x4" label="Commit work on dtx branch">
- <doc>
- Commit the work done on behalf a transaction branch. This command commits the work
- associated with xid. Any produced messages are made available and any consumed messages are
- discarded.
- </doc>
-
- <exception name="illegal-state" error-code="illegal-state">
- <doc>
- If the command is invoked in an improper context (see class grammar) then the server MUST
- raise an exception.
- </doc>
- </exception>
-
- <implement role="server" handle="MAY" />
-
- <field name="xid" type="xid" label="Transaction xid" required="true">
- <doc>
- Specifies the xid of the transaction branch to be committed.
- </doc>
-
- <exception name="unknown-xid" error-code="not-found">
- <doc>
- If xid is unknown (the transaction branch has not been started or has already been
- ended) then the server MUST raise an exception.
- </doc>
- </exception>
-
- <exception name="not-disassociated" error-code="illegal-state">
- <doc>
- If this command is called when xid is still associated with a session then the server
- MUST raise an exception.
- </doc>
- </exception>
- </field>
-
- <field name="one-phase" type="bit" label="One-phase optimization flag">
- <doc>
- Used to indicate whether one-phase or two-phase commit is used.
- </doc>
-
- <exception name="one-phase" error-code="illegal-state">
- <doc>
- The one-phase bit MUST be set if a commit is sent without a preceding prepare.
- </doc>
- </exception>
-
- <exception name="two-phase" error-code="illegal-state">
- <doc>
- The one-phase bit MUST NOT be set if the commit has been preceded by prepare.
- </doc>
- </exception>
- </field>
-
- <result type="xa-result">
- <doc>
- This confirms to the client that the transaction branch is committed or specify the
- error condition.
-
- The value of this field may be one of the following constants:
-
- xa-ok: Normal execution
-
- xa-heurhaz: Due to some failure, the work done on behalf of the specified transaction
- branch may have been heuristically completed.
-
- xa-heurcom: Due to a heuristic decision, the work done on behalf of the specified
- transaction branch was committed.
-
- xa-heurrb: Due to a heuristic decision, the work done on behalf of the specified
- transaction branch was rolled back.
-
- xa-heurmix: Due to a heuristic decision, the work done on behalf of the specified
- transaction branch was partially committed and partially rolled back.
-
- xa-rbrollback: The broker marked the transaction branch rollback-only for an unspecified
- reason.
-
- xa-rbtimeout: The work represented by this transaction branch took too long.
- </doc>
- </result>
- </command>
-
- <!-- - Command: dtx.forget - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="forget" code="0x5" label="Discard dtx branch">
- <doc>
- This command is called to forget about a heuristically completed transaction branch.
- </doc>
-
- <exception name="illegal-state" error-code="illegal-state">
- <doc>
- If the command is invoked in an improper context (see class grammar) then the server MUST
- raise an exception.
- </doc>
- </exception>
-
- <implement role="server" handle="MAY" />
-
- <field name="xid" type="xid" label="Transaction xid" required="true">
- <doc>
- Specifies the xid of the transaction branch to be forgotten.
- </doc>
-
- <exception name="unknown-xid" error-code="not-found">
- <doc>
- If xid is unknown (the transaction branch has not been started or has already been
- ended) then the server MUST raise an exception.
- </doc>
- </exception>
-
- <exception name="not-disassociated" error-code="illegal-state">
- <doc>
- If this command is called when xid is still associated with a session then the server
- MUST raise an exception.
- </doc>
- </exception>
- </field>
- </command>
-
- <!-- - Command: dtx.get-timeout - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="get-timeout" code="0x6" label="Obtain dtx timeout in seconds">
- <doc>
- This command obtains the current transaction timeout value in seconds. If set-timeout was
- not used prior to invoking this command, the return value is the default timeout; otherwise,
- the value used in the previous set-timeout call is returned.
- </doc>
-
- <implement role="server" handle="MAY" />
-
- <field name="xid" type="xid" label="Transaction xid" required="true">
- <doc>
- Specifies the xid of the transaction branch for getting the timeout.
- </doc>
-
- <exception name="unknown-xid" error-code="not-found">
- <doc>
- If xid is unknown (the transaction branch has not been started or has already been
- ended) then the server MUST raise an exception.
- </doc>
- </exception>
- </field>
-
- <result>
- <struct name="get-timeout-result" size="4" code="0x2" pack="2">
- <doc> Returns the value of the timeout last specified through set-timeout. </doc>
-
- <field name="timeout" type="uint32" label="The current transaction timeout value"
- required="true">
- <doc> The current transaction timeout value in seconds. </doc>
- </field>
- </struct>
- </result>
- </command>
-
- <!-- - Command: dtx.prepare - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="prepare" code="0x7" label="Prepare a dtx branch">
- <doc>
- This command prepares for commitment any message produced or consumed on behalf of xid.
- </doc>
-
- <exception name="illegal-state" error-code="illegal-state">
- <doc>
- If the command is invoked in an improper context (see class grammar) then the server MUST
- raise an exception.
- </doc>
- </exception>
-
- <rule name="obligation-1">
- <doc>
- Once this command successfully returns it is guaranteed that the transaction branch may be
- either committed or rolled back regardless of failures.
- </doc>
- </rule>
-
- <rule name="obligation-2">
- <doc>
- The knowledge of xid cannot be erased before commit or rollback complete the branch.
- </doc>
- </rule>
-
- <implement role="server" handle="MAY" />
-
- <field name="xid" type="xid" label="Transaction xid" required="true">
- <doc>
- Specifies the xid of the transaction branch that can be prepared.
- </doc>
-
- <exception name="unknown-xid" error-code="not-found">
- <doc>
- If xid is unknown (the transaction branch has not been started or has already been
- ended) then the server MUST raise an exception.
- </doc>
- </exception>
-
- <exception name="not-disassociated" error-code="illegal-state">
- <doc>
- If this command is called when xid is still associated with a session then the server
- MUST raise an exception.
- </doc>
- </exception>
- </field>
-
- <result type="xa-result">
- <doc>
- This command confirms to the client that the transaction branch is prepared or specify the
- error condition.
-
- The value of this field may be one of the following constants:
-
- xa-ok: Normal execution.
-
- xa-rdonly: The transaction branch was read-only and has been committed.
-
- xa-rbrollback: The broker marked the transaction branch rollback-only for an unspecified
- reason.
-
- xa-rbtimeout: The work represented by this transaction branch took too long.
- </doc>
- </result>
- </command>
-
- <!-- - Command: dtx.recover - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="recover" code="0x8" label="Get prepared or completed xids">
- <doc>
- This command is called to obtain a list of transaction branches that are in a prepared or
- heuristically completed state.
- </doc>
-
- <implement role="server" handle="MAY" />
-
- <result>
- <struct name="recover-result" size="4" code="0x3" pack="2">
- <doc>
- Returns to the client a table with single item that is a sequence of transaction xids
- that are in a prepared or heuristically completed state.
- </doc>
-
- <field name="in-doubt" type="array" label="array of xids to be recovered" required="true">
- <doc> Array containing the xids to be recovered (xids that are in a prepared or
- heuristically completed state). </doc>
-
- </field>
- </struct>
- </result>
- </command>
-
- <!-- - Command: dtx.rollback - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="rollback" code="0x9" label="Rollback a dtx branch">
- <doc>
- This command rolls back the work associated with xid. Any produced messages are discarded
- and any consumed messages are re-enqueued.
- </doc>
-
- <exception name="illegal-state" error-code="illegal-state">
- <doc>
- If the command is invoked in an improper context (see class grammar) then the server MUST
- raise an exception.
- </doc>
- </exception>
-
- <implement role="server" handle="MAY" />
-
- <field name="xid" type="xid" label="Transaction xid" required="true">
- <doc>
- Specifies the xid of the transaction branch that can be rolled back.
- </doc>
-
- <exception name="unknown-xid" error-code="not-found">
- <doc>
- If xid is unknown (the transaction branch has not been started or has already been
- ended) then the server MUST raise an exception.
- </doc>
- </exception>
-
- <exception name="not-disassociated" error-code="illegal-state">
- <doc>
- If this command is called when xid is still associated with a session then the server
- MUST raise an exception.
- </doc>
- </exception>
- </field>
-
- <result type="xa-result">
- <doc>
- This command confirms to the client that the transaction branch is rolled back or specify
- the error condition.
-
- The value of this field may be one of the following constants:
-
- xa-ok: Normal execution
-
- xa-heurhaz: Due to some failure, the work done on behalf of the specified transaction
- branch may have been heuristically completed.
-
- xa-heurcom: Due to a heuristic decision, the work done on behalf of the specified
- transaction branch was committed.
-
- xa-heurrb: Due to a heuristic decision, the work done on behalf of the specified
- transaction branch was rolled back.
-
- xa-heurmix: Due to a heuristic decision, the work done on behalf of the specified
- transaction branch was partially committed and partially rolled back.
-
- xa-rbrollback: The broker marked the transaction branch rollback-only for an unspecified
- reason.
-
- xa-rbtimeout: The work represented by this transaction branch took too long.
- </doc>
- </result>
- </command>
-
- <!-- - Command: dtx.set-timeout - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="set-timeout" code="0xa" label="Set dtx timeout value">
- <doc>
- Sets the specified transaction branch timeout value in seconds.
- </doc>
-
- <rule name="effective">
- <doc>
- Once set, this timeout value is effective until this command is reinvoked with a different
- value.
- </doc>
- </rule>
-
- <rule name="reset">
- <doc>
- A value of zero resets the timeout value to the default value.
- </doc>
- </rule>
-
- <implement role="server" handle="MAY" />
-
- <field name="xid" type="xid" label="Transaction xid" required="true">
- <doc>
- Specifies the xid of the transaction branch for setting the timeout.
- </doc>
-
- <exception name="unknown-xid" error-code="not-found">
- <doc>
- If xid is unknown (the transaction branch has not been started or has already been
- ended) then the server MUST raise an exception.
- </doc>
- </exception>
-
- </field>
-
- <field name="timeout" type="uint32" label="Dtx timeout in seconds" required="true">
- <doc>
- The transaction timeout value in seconds.
- </doc>
- </field>
- </command>
-
- </class>
-
- <!-- == Class: exchange ====================================================================== -->
-
- <class name="exchange" code="0x7" label="work with exchanges">
- <doc>
- Exchanges match and distribute messages across queues. Exchanges can be configured in the
- server or created at runtime.
- </doc>
-
- <doc type="grammar">
- exchange = C:DECLARE
- / C:DELETE
- / C:QUERY
- </doc>
-
- <rule name="required-types">
- <doc>
- The server MUST implement these standard exchange types: fanout, direct.
- </doc>
- <doc type="scenario">
- Client attempts to declare an exchange with each of these standard types.
- </doc>
- </rule>
-
- <rule name="recommended-types">
- <doc>
- The server SHOULD implement these standard exchange types: topic, headers.
- </doc>
- <doc type="scenario">
- Client attempts to declare an exchange with each of these standard types.
- </doc>
- </rule>
-
- <rule name="required-instances">
- <doc>
- The server MUST, in each virtual host, pre-declare an exchange instance for each standard
- exchange type that it implements, where the name of the exchange instance, if defined, is
- "amq." followed by the exchange type name.
-
- The server MUST, in each virtual host, pre-declare at least two direct exchange instances:
- one named "amq.direct", the other with no public name that serves as a default exchange for
- publish commands (such as message.transfer).
- </doc>
- <doc type="scenario">
- Client creates a temporary queue and attempts to bind to each required exchange instance
- ("amq.fanout", "amq.direct", "amq.topic", and "amq.headers" if those types are defined).
- </doc>
- </rule>
-
- <rule name="default-exchange">
- <doc>
- The server MUST pre-declare a direct exchange with no public name to act as the default
- exchange for content publish commands (such as message.transfer) and for default queue
- bindings.
- </doc>
- <doc type="scenario">
- Client checks that the default exchange is active by publishing a message with a suitable
- routing key but without specifying the exchange name, then ensuring that the message arrives
- in the queue correctly.
- </doc>
- </rule>
-
- <rule name="default-access">
- <doc>
- The default exchange MUST NOT be accessible to the client except by specifying an empty
- exchange name in a content publish command (such as message.transfer). That is, the server
- must not let clients explicitly bind, unbind, delete, or make any other reference to this
- exchange.
- </doc>
- </rule>
-
- <rule name="extensions">
- <doc>
- The server MAY implement other exchange types as wanted.
- </doc>
- </rule>
-
- <role name="server" implement="MUST" />
- <role name="client" implement="MUST" />
-
- <domain name="name" type="str8" label="exchange name">
- <doc>
- The exchange name is a client-selected string that identifies the exchange for publish
- commands. Exchange names may consist of any mixture of digits, letters, and underscores.
- Exchange names are scoped by the virtual host.
- </doc>
- </domain>
-
- <!-- - Command: exchange.declare - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="declare" code="0x1" label="verify exchange exists, create if needed">
- <doc>
- This command creates an exchange if it does not already exist, and if the exchange exists,
- verifies that it is of the correct and expected class.
- </doc>
-
- <rule name="minimum">
- <doc>
- The server SHOULD support a minimum of 16 exchanges per virtual host and ideally, impose
- no limit except as defined by available resources.
- </doc>
- <doc type="scenario">
- The client creates as many exchanges as it can until the server reports an error; the
- number of exchanges successfully created must be at least sixteen.
- </doc>
- </rule>
-
- <implement role="server" handle="MUST" />
-
- <field name="exchange" type="name" required="true">
- <exception name="reserved-names" error-code="not-allowed">
- <doc>
- Exchange names starting with "amq." are reserved for pre-declared and standardized
- exchanges. The client MUST NOT attempt to create an exchange starting with "amq.".
- </doc>
- </exception>
-
- <exception name="exchange-name-required" error-code="invalid-argument">
- <doc>
- The name of the exchange MUST NOT be a blank or empty string.
- </doc>
- </exception>
- </field>
-
- <field name="type" type="str8" label="exchange type" required="true">
- <doc>
- Each exchange belongs to one of a set of exchange types implemented by the server. The
- exchange types define the functionality of the exchange - i.e. how messages are routed
- through it. It is not valid or meaningful to attempt to change the type of an existing
- exchange.
- </doc>
-
- <exception name="typed" error-code="not-allowed">
- <doc>
- Exchanges cannot be redeclared with different types. The client MUST NOT attempt to
- redeclare an existing exchange with a different type than used in the original
- exchange.declare command.
- </doc>
- </exception>
-
- <exception name="exchange-type-not-found" error-code="not-found">
- <doc>
- If the client attempts to create an exchange which the server does not recognize, an
- exception MUST be sent.
- </doc>
- </exception>
- </field>
-
- <field name="alternate-exchange" type="name" label= "exchange name for unroutable messages">
- <doc>
- In the event that a message cannot be routed, this is the name of the exchange to which
- the message will be sent. Messages transferred using message.transfer will be routed to
- the alternate-exchange only if they are sent with the "none" accept-mode, and the
- discard-unroutable delivery property is set to false, and there is no queue to route to
- for the given message according to the bindings on this exchange.
- </doc>
-
- <rule name="empty-name">
- <doc>
- If alternate-exchange is not set (its name is an empty string), unroutable messages
- that would be sent to the alternate-exchange MUST be dropped silently.
- </doc>
- </rule>
-
- <exception name="pre-existing-exchange" error-code="not-allowed">
- <doc>
- If the alternate-exchange is not empty and if the exchange already exists with a
- different alternate-exchange, then the declaration MUST result in an exception.
- </doc>
- </exception>
-
- <rule name="double-failure">
- <doc>
- A message which is being routed to a alternate exchange, MUST NOT be re-routed to a
- secondary alternate exchange if it fails to route in the primary alternate exchange.
- After such a failure, the message MUST be dropped. This prevents looping.
- </doc>
- </rule>
- </field>
-
- <field name="passive" type="bit" label="do not create exchange">
- <doc>
- If set, the server will not create the exchange. The client can use this to check whether
- an exchange exists without modifying the server state.
- </doc>
- <exception name="not-found" error-code="not-found">
- <doc>
- If set, and the exchange does not already exist, the server MUST raise an exception.
- </doc>
- </exception>
- </field>
-
- <field name="durable" type="bit" label="request a durable exchange">
- <doc>
- If set when creating a new exchange, the exchange will be marked as durable. Durable
- exchanges remain active when a server restarts. Non-durable exchanges (transient
- exchanges) are purged if/when a server restarts.
- </doc>
-
- <rule name="support">
- <doc>
- The server MUST support both durable and transient exchanges.
- </doc>
- </rule>
-
- <rule name="sticky">
- <doc>
- The server MUST ignore the durable field if the exchange already exists.
- </doc>
- </rule>
- </field>
-
- <field name="auto-delete" type="bit" label="auto-delete when unused">
- <doc>
- If set, the exchange is deleted automatically when there remain no bindings between the
- exchange and any queue. Such an exchange will not be automatically deleted until at least
- one binding has been made to prevent the immediate deletion of the exchange upon creation.
- </doc>
- <rule name="sticky">
- <doc>
- The server MUST ignore the auto-delete field if the exchange already exists.
- </doc>
- </rule>
- </field>
-
- <field name="arguments" type="map" label="arguments for declaration">
- <doc>
- A set of arguments for the declaration. The syntax and semantics of these arguments
- depends on the server implementation. This field is ignored if passive is 1.
- </doc>
-
- <exception name="unknown-argument" error-code="not-implemented">
- <doc>
- If the arguments field contains arguments which are not understood by the server,
- it MUST raise an exception.
- </doc>
- </exception>
- </field>
- </command>
-
- <!-- - Command: exchange.delete - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="delete" code="0x2" label="delete an exchange">
- <doc>
- This command deletes an exchange. When an exchange is deleted all queue bindings on the
- exchange are cancelled.
- </doc>
-
- <implement role="server" handle="MUST" />
-
- <field name="exchange" type="name" required="true">
- <exception name="exists" error-code="not-found">
- <doc>
- The client MUST NOT attempt to delete an exchange that does not exist.
- </doc>
- </exception>
-
- <exception name="exchange-name-required" error-code="invalid-argument">
- <doc>
- The name of the exchange MUST NOT be a missing or empty string.
- </doc>
- </exception>
-
- <exception name="used-as-alternate" error-code="not-allowed">
- <doc>
- An exchange MUST NOT be deleted if it is in use as an alternate-exchange by a queue or
- by another exchange.
- </doc>
- </exception>
-
- </field>
-
- <field name="if-unused" type="bit" label="delete only if unused">
- <doc>
- If set, the server will only delete the exchange if it has no queue bindings. If the
- exchange has queue bindings the server does not delete it but raises an exception
- instead.
- </doc>
- <exception name="exchange-in-use" error-code="precondition-failed">
- <doc>
- If the exchange has queue bindings, and the if-unused flag is set, the server MUST NOT
- delete the exchange, but MUST raise and exception.
- </doc>
- </exception>
- </field>
- </command>
-
- <!-- - Command: exchange.query - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="query" code="0x3" label="request information about an exchange">
- <doc>
- This command is used to request information on a particular exchange.
- </doc>
-
- <implement role="server" handle="MUST" />
-
- <field name="name" type="str8" label="the exchange name">
- <doc>
- The name of the exchange for which information is requested. If not specified explicitly
- the default exchange is implied.
- </doc>
- </field>
-
- <result>
- <struct name="exchange-query-result" size="4" code="0x1" pack="2">
- <doc>
- This is sent in response to a query request and conveys information on a particular
- exchange.
- </doc>
-
- <field name="type" type="str8" label="indicate the exchange type">
- <doc>
- The type of the exchange. Will be empty if the exchange is not found.
- </doc>
- </field>
-
- <field name="durable" type="bit" label="indicate the durability">
- <doc>
- The durability of the exchange, i.e. if set the exchange is durable. Will not be set
- if the exchange is not found.
- </doc>
- </field>
-
- <field name="not-found" type="bit" label="indicate an unknown exchange">
- <doc>
- If set, the exchange for which information was requested is not known.
- </doc>
- </field>
-
- <field name="arguments" type="map" label="other unspecified exchange properties">
- <doc>
- A set of properties of the exchange whose syntax and semantics depends on the server
- implementation. Will be empty if the exchange is not found.
- </doc>
- </field>
- </struct>
- </result>
- </command>
-
- <!-- - Command: exchange.bind - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="bind" code="0x4" label="bind queue to an exchange">
- <doc> This command binds a queue to an exchange. Until a queue is bound it will not receive
- any messages. In a classic messaging model, store-and-forward queues are bound to a direct
- exchange and subscription queues are bound to a topic exchange. </doc>
-
- <rule name="duplicates">
- <doc>
- A server MUST ignore duplicate bindings - that is, two or more bind commands with the
- same exchange, queue, and binding-key - without treating these as an error. The value of
- the arguments used for the binding MUST NOT be altered by subsequent binding requests.
- </doc>
- <doc type="scenario">
- A client binds a named queue to an exchange. The client then repeats the bind (with
- identical exchange, queue, and binding-key). The second binding should use a different
- value for the arguments field.
- </doc>
- </rule>
-
- <rule name="durable-exchange">
- <doc> Bindings between durable queues and durable exchanges are automatically durable and
- the server MUST restore such bindings after a server restart. </doc>
- <doc type="scenario"> A server creates a named durable queue and binds it to a durable
- exchange. The server is restarted. The client then attempts to use the queue/exchange
- combination. </doc>
- </rule>
-
- <rule name="binding-count">
- <doc> The server SHOULD support at least 4 bindings per queue, and ideally, impose no limit
- except as defined by available resources. </doc>
- <doc type="scenario"> A client creates a named queue and attempts to bind it to 4 different
- exchanges. </doc>
- </rule>
-
- <rule name="multiple-bindings">
- <doc> Where more than one binding exists between a particular exchange instance and a
- particular queue instance any given message published to that exchange should be delivered
- to that queue at most once, regardless of how many distinct bindings match. </doc>
- <doc type="scenario"> A client creates a named queue and binds it to the same topic exchange
- at least three times using intersecting binding-keys (for example, "animals.*",
- "animals.dogs.*", "animal.dogs.chihuahua"). Verify that a message matching all the
- bindings (using previous example, routing key = "animal.dogs.chihuahua") is delivered once
- only. </doc>
- </rule>
-
- <implement role="server" handle="MUST"/>
-
- <field name="queue" type="queue.name" required="true">
- <doc> Specifies the name of the queue to bind. </doc>
-
- <exception name="empty-queue" error-code="invalid-argument">
- <doc> A client MUST NOT be allowed to bind a non-existent and unnamed queue (i.e. empty
- queue name) to an exchange. </doc>
- <doc type="scenario"> A client attempts to bind with an unnamed (empty) queue name to an
- exchange. </doc>
- </exception>
-
- <exception name="queue-existence" error-code="not-found">
- <doc> A client MUST NOT be allowed to bind a non-existent queue (i.e. not previously
- declared) to an exchange. </doc>
- <doc type="scenario"> A client attempts to bind an undeclared queue name to an exchange.
- </doc>
- </exception>
- </field>
-
- <field name="exchange" type="name" label="name of the exchange to bind to" required="true">
- <exception name="exchange-existence" error-code="not-found">
- <doc> A client MUST NOT be allowed to bind a queue to a non-existent exchange. </doc>
- <doc type="scenario"> A client attempts to bind a named queue to a undeclared exchange.
- </doc>
- </exception>
-
- <exception name="exchange-name-required" error-code="invalid-argument">
- <doc> The name of the exchange MUST NOT be a blank or empty string. </doc>
- </exception>
- </field>
-
- <field name="binding-key" type="str8"
- label="identifies a binding between a given exchange and queue" required="true">
- <doc> The binding-key uniquely identifies a binding between a given (exchange, queue) pair.
- Depending on the exchange configuration, the binding key may be matched against the
- message routing key in order to make routing decisions. The match algorithm depends on the
- exchange type. Some exchange types may ignore the binding key when making routing
- decisions. Refer to the specific exchange type documentation. The meaning of an empty
- binding key depends on the exchange implementation. </doc>
- </field>
-
- <field name="arguments" type="map" label="arguments for binding">
- <doc> A set of arguments for the binding. The syntax and semantics of these arguments
- depends on the exchange class. </doc>
-
- <exception name="unknown-argument" error-code="not-implemented">
- <doc> If the arguments field contains arguments which are not understood by the server, it
- MUST raise an exception. </doc>
- </exception>
- </field>
- </command>
-
- <!-- - Command: exchange.unbind - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="unbind" code="0x5" label="unbind a queue from an exchange">
- <doc>
- This command unbinds a queue from an exchange.
- </doc>
-
- <implement role="server" handle="MUST" />
-
- <field name="queue" type="queue.name" required="true">
- <doc>
- Specifies the name of the queue to unbind.
- </doc>
- <exception name="non-existent-queue" error-code="not-found">
- <doc>
- If the queue does not exist the server MUST raise an exception.
- </doc>
- </exception>
- </field>
-
- <field name="exchange" type="name" required="true">
- <doc>
- The name of the exchange to unbind from.
- </doc>
-
- <exception name="non-existent-exchange" error-code="not-found">
- <doc>
- If the exchange does not exist the server MUST raise an exception.
- </doc>
- </exception>
-
- <exception name="exchange-name-required" error-code="invalid-argument">
- <doc>
- The name of the exchange MUST NOT be a blank or empty string.
- </doc>
- </exception>
- </field>
-
- <field name="binding-key" type="str8" label="the key of the binding" required="true">
- <doc>
- Specifies the binding-key of the binding to unbind.
- </doc>
-
- <exception name="non-existent-binding-key" error-code="not-found">
- <doc>
- If there is no matching binding-key the server MUST raise an exception.
- </doc>
- </exception>
- </field>
- </command>
-
- <!-- - Command: exchange.bound - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="bound" code="0x6" label="request information about bindings to an exchange">
- <doc>
- This command is used to request information on the bindings to a particular exchange.
- </doc>
-
- <implement role="server" handle="MUST" />
-
- <field name="exchange" type="str8" label="the exchange name">
- <doc>
- The name of the exchange for which binding information is being requested. If not
- specified explicitly the default exchange is implied.
- </doc>
- </field>
-
- <field name="queue" type="str8" label="a queue name" required="true">
- <doc>
- If populated then determine whether the given queue is bound to the exchange.
- </doc>
- </field>
-
- <field name="binding-key" type="str8" label="a binding-key">
- <doc>
- If populated defines the binding-key of the binding of interest, if not populated the
- request will ignore the binding-key on bindings when searching for a match.
- </doc>
- </field>
-
- <field name="arguments" type="map" label="a set of binding arguments">
- <doc>
- If populated defines the arguments of the binding of interest if not populated the request
- will ignore the arguments on bindings when searching for a match
- </doc>
- </field>
-
- <result>
- <struct name="exchange-bound-result" size="4" code="0x2" pack="2">
- <field name="exchange-not-found" type="bit" label="indicate an unknown exchange">
- <doc>
- If set, the exchange for which information was requested is not known.
- </doc>
- </field>
-
- <field name="queue-not-found" type="bit" label="indicate an unknown queue">
- <doc>
- If set, the queue specified is not known.
- </doc>
- </field>
-
- <field name="queue-not-matched" type="bit" label="indicate no matching queue">
- <doc>
- A bit which if set indicates that no binding was found from the specified exchange to
- the specified queue.
- </doc>
- </field>
-
- <field name="key-not-matched" type="bit" label="indicate no matching binding-key">
- <doc>
- A bit which if set indicates that no binding was found from the specified exchange
- with the specified binding-key.
- </doc>
- </field>
-
- <field name="args-not-matched" type="bit" label="indicate no matching arguments">
- <doc>
- A bit which if set indicates that no binding was found from the specified exchange
- with the specified arguments.
- </doc>
- </field>
- </struct>
- </result>
- </command>
-
- </class>
-
- <!-- == Class: queue ========================================================================= -->
-
- <class name="queue" code="0x8" label="work with queues">
- <doc>
- Queues store and forward messages. Queues can be configured in the server or created at
- runtime. Queues must be attached to at least one exchange in order to receive messages from
- publishers.
- </doc>
-
- <doc type="grammar">
- queue = C:DECLARE
- / C:BIND
- / C:PURGE
- / C:DELETE
- / C:QUERY
- / C:UNBIND
- </doc>
-
- <rule name="any-content">
- <doc>
- A server MUST allow any content class to be sent to any queue, in any mix, and queue and
- deliver these content classes independently. Note that all commands that fetch content off
- queues are specific to a given content class.
- </doc>
- <doc type="scenario">
- Client creates an exchange of each standard type and several queues that it binds to each
- exchange. It must then successfully send each of the standard content types to each of the
- available queues.
- </doc>
- </rule>
-
- <role name="server" implement="MUST" />
- <role name="client" implement="MUST" />
-
- <domain name="name" type="str8" label="queue name">
- <doc>
- The queue name identifies the queue within the virtual host. Queue names must have a length
- of between 1 and 255 characters inclusive, must start with a digit, letter or underscores
- ('_') character, and must be otherwise encoded in UTF-8.
- </doc>
- </domain>
-
- <!-- - Command: queue.declare - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="declare" code="0x1" label="declare queue">
- <doc>
- This command creates or checks a queue. When creating a new queue the client can specify
- various properties that control the durability of the queue and its contents, and the level
- of sharing for the queue.
- </doc>
-
- <rule name="default-binding">
- <doc>
- The server MUST create a default binding for a newly-created queue to the default
- exchange, which is an exchange of type 'direct' and use the queue name as the binding-key.
- </doc>
- <doc type="scenario">
- Client creates a new queue, and then without explicitly binding it to an exchange,
- attempts to send a message through the default exchange binding, i.e. publish a message to
- the empty exchange, with the queue name as binding-key.
- </doc>
- </rule>
-
- <rule name="minimum-queues">
- <doc>
- The server SHOULD support a minimum of 256 queues per virtual host and ideally, impose no
- limit except as defined by available resources.
- </doc>
- <doc type="scenario">
- Client attempts to create as many queues as it can until the server reports an error. The
- resulting count must at least be 256.
- </doc>
- </rule>
-
- <implement role="server" handle="MUST" />
-
- <field name="queue" type="name" required="true">
- <exception name="reserved-prefix" error-code="not-allowed">
- <doc>
- Queue names starting with "amq." are reserved for pre-declared and standardized server
- queues. A client MUST NOT attempt to declare a queue with a name that starts with "amq."
- and the passive option set to zero.
- </doc>
- <doc type="scenario">
- A client attempts to create a queue with a name starting with "amq." and with the
- passive option set to zero.
- </doc>
- </exception>
- </field>
-
- <field name="alternate-exchange" type="exchange.name"
- label= "exchange name for messages with exceptions">
- <doc>
- The alternate-exchange field specifies how messages on this queue should be treated when
- they are rejected by a subscriber, or when they are orphaned by queue deletion. When
- present, rejected or orphaned messages MUST be routed to the alternate-exchange. In all
- cases the messages MUST be removed from the queue.
- </doc>
-
- <exception name="pre-existing-exchange" error-code="not-allowed">
- <doc>
- If the alternate-exchange is not empty and if the queue already exists with a different
- alternate-exchange, then the declaration MUST result in an exception.
- </doc>
- </exception>
-
- <exception name="unknown-exchange" error-code="not-found">
- <doc>
- if the alternate-exchange does not match the name of any existing exchange on the
- server, then an exception must be raised.
- </doc>
- </exception>
- </field>
-
- <field name="passive" type="bit" label="do not create queue">
- <doc>
- If set, the server will not create the queue. This field allows the client to assert the
- presence of a queue without modifying the server state.
- </doc>
-
- <exception name="passive" error-code="not-found">
- <doc>
- The client MAY ask the server to assert that a queue exists without creating the queue
- if not. If the queue does not exist, the server treats this as a failure.
- </doc>
- <doc type="scenario">
- Client declares an existing queue with the passive option and expects the command to
- succeed. Client then attempts to declare a non-existent queue with the passive option,
- and the server must close the session with the correct exception.
- </doc>
- </exception>
- </field>
-
- <field name="durable" type="bit" label="request a durable queue">
- <doc>
- If set when creating a new queue, the queue will be marked as durable. Durable queues
- remain active when a server restarts. Non-durable queues (transient queues) are purged
- if/when a server restarts. Note that durable queues do not necessarily hold persistent
- messages, although it does not make sense to send persistent messages to a transient
- queue.
- </doc>
-
- <rule name="persistence">
- <doc>
- The queue definition MUST survive the server losing all transient memory, e.g. a
- machine restart.
- </doc>
- <doc type="scenario">
- Client creates a durable queue; server is then restarted. Client then attempts to send
- message to the queue. The message should be successfully delivered.
- </doc>
- </rule>
-
- <rule name="types">
- <doc>
- The server MUST support both durable and transient queues.
- </doc>
- <doc type="scenario">
- A client creates two named queues, one durable and one transient.
- </doc>
- </rule>
-
- <rule name="pre-existence">
- <doc>
- The server MUST ignore the durable field if the queue already exists.
- </doc>
- <doc type="scenario">
- A client creates two named queues, one durable and one transient. The client then
- attempts to declare the two queues using the same names again, but reversing the value
- of the durable flag in each case. Verify that the queues still exist with the original
- durable flag values.
- </doc>
- </rule>
- </field>
-
- <field name="exclusive" type="bit" label="request an exclusive queue">
- <doc>
- Exclusive queues can only be used from one session at a time. Once a session
- declares an exclusive queue, that queue cannot be used by any other session until the
- declaring session closes.
- </doc>
-
- <rule name="types">
- <doc>
- The server MUST support both exclusive (private) and non-exclusive (shared) queues.
- </doc>
- <doc type="scenario">
- A client creates two named queues, one exclusive and one non-exclusive.
- </doc>
- </rule>
-
- <exception name="in-use" error-code="resource-locked">
- <doc>
- If the server receives a declare, bind, consume or get request for a queue that has been
- declared as exclusive by an existing client session, it MUST raise an exception.
- </doc>
- <doc type="scenario">
- A client declares an exclusive named queue. A second client on a different session
- attempts to declare a queue of the same name.
- </doc>
- </exception>
- </field>
-
- <field name="auto-delete" type="bit" label="auto-delete queue when unused">
- <doc>
- If this field is set and the exclusive field is also set, then the queue MUST be deleted
- when the session closes.
-
- If this field is set and the exclusive field is not set the queue is deleted when all
- the consumers have finished using it. Last consumer can be cancelled either explicitly
- or because its session is closed. If there was no consumer ever on the queue, it won't
- be deleted.
- </doc>
-
- <rule name="pre-existence">
- <doc>
- The server MUST ignore the auto-delete field if the queue already exists.
- </doc>
- <doc type="scenario">
- A client creates two named queues, one as auto-delete and one explicit-delete. The
- client then attempts to declare the two queues using the same names again, but reversing
- the value of the auto-delete field in each case. Verify that the queues still exist with
- the original auto-delete flag values.
- </doc>
- </rule>
- </field>
-
- <field name="arguments" type="map" label="arguments for declaration">
- <doc>
- A set of arguments for the declaration. The syntax and semantics of these arguments
- depends on the server implementation. This field is ignored if passive is 1.
- </doc>
-
- <exception name="unknown-argument" error-code="not-implemented">
- <doc>
- If the arguments field contains arguments which are not understood by the server,
- it MUST raise an exception.
- </doc>
- </exception>
- </field>
- </command>
-
- <!-- - Command: queue.delete - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="delete" code="0x2" label="delete a queue">
- <doc>
- This command deletes a queue. When a queue is deleted any pending messages are sent to the
- alternate-exchange if defined, or discarded if it is not.
- </doc>
-
-
- <implement role="server" handle="MUST" />
-
- <field name="queue" type="name" required="true">
- <doc>
- Specifies the name of the queue to delete.
- </doc>
-
- <exception name="empty-name" error-code="invalid-argument">
- <doc>
- If the queue name in this command is empty, the server MUST raise an exception.
- </doc>
- </exception>
-
- <exception name="queue-exists" error-code="not-found">
- <doc>
- The queue must exist. If the client attempts to delete a non-existing queue the server
- MUST raise an exception.
- </doc>
- </exception>
- </field>
-
- <field name="if-unused" type="bit" label="delete only if unused">
- <doc>
- If set, the server will only delete the queue if it has no consumers. If the queue has
- consumers the server does does not delete it but raises an exception instead.
- </doc>
-
- <exception name="if-unused-flag" error-code="precondition-failed">
- <doc>
- The server MUST respect the if-unused flag when deleting a queue.
- </doc>
- </exception>
- </field>
-
- <field name="if-empty" type="bit" label="delete only if empty">
- <doc>
- If set, the server will only delete the queue if it has no messages.
- </doc>
- <exception name="not-empty" error-code="precondition-failed">
- <doc>
- If the queue is not empty the server MUST raise an exception.
- </doc>
- </exception>
- </field>
- </command>
-
- <!-- - Command: queue.purge - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="purge" code="0x3" label="purge a queue">
- <doc>
- This command removes all messages from a queue. It does not cancel subscribers. Purged
- messages are deleted without any formal "undo" mechanism.
- </doc>
-
- <rule name="empty">
- <doc>
- A call to purge MUST result in an empty queue.
- </doc>
- </rule>
-
- <rule name="pending-messages">
- <doc>
- The server MUST NOT purge messages that have already been sent to a client but not yet
- accepted.
- </doc>
- </rule>
-
- <rule name="purge-recovery">
- <doc>
- The server MAY implement a purge queue or log that allows system administrators to recover
- accidentally-purged messages. The server SHOULD NOT keep purged messages in the same
- storage spaces as the live messages since the volumes of purged messages may get very
- large.
- </doc>
- </rule>
-
- <implement role="server" handle="MUST" />
-
- <field name="queue" type="name" required="true">
- <doc>
- Specifies the name of the queue to purge.
- </doc>
-
- <exception name="empty-name" error-code="invalid-argument">
- <doc>
- If the the queue name in this command is empty, the server MUST raise an exception.
- </doc>
- </exception>
-
- <exception name="queue-exists" error-code="not-found">
- <doc>
- The queue MUST exist. Attempting to purge a non-existing queue MUST cause an exception.
- </doc>
- </exception>
- </field>
- </command>
-
- <!-- - Command: queue.query - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-
- <command name="query" code="0x4" label="request information about a queue">
- <doc>
- This command requests information about a queue.
- </doc>
-
- <implement role="server" handle="MUST" />
-
- <field name="queue" type="name" label="the queried queue" required="true"/>
-
- <result>
- <struct name="queue-query-result" size="4" code="0x1" pack="2">
- <doc>
- This is sent in response to queue.query, and conveys the requested information about a
- queue. If no queue with the specified name exists then none of the fields within the
- returned result struct will be populated.
- </doc>
-
- <field name="queue" type="name" required="true">
- <doc>
- Reports the name of the queue.
- </doc>
- </field>
-
- <field name="alternate-exchange" type="exchange.name" />
-
- <field name="durable" type="bit" />
-
- <field name="exclusive" type="bit" />
-
- <field name="auto-delete" type="bit" />
-
- <field name="arguments" type="map" />
-
- <field name="message-count" type="uint32" label="number of messages in queue"
- required="true">
- <doc> Reports the number of messages in the queue. </doc>
- </field>
-
- <field name="subscriber-count" type="uint32" label="number of subscribers"
- required="true">
- <doc>
- Reports the number of subscribers for the queue.
- </doc>
- </field>
- </struct>
- </result>
- </command>
-
- </class>
-
-</amqp>
diff --git a/specs/amqp0-9-1.stripped.xml b/specs/amqp0-9-1.stripped.xml
new file mode 100644
index 0000000000..ec55c8dd7a
--- /dev/null
+++ b/specs/amqp0-9-1.stripped.xml
@@ -0,0 +1,477 @@
+<?xml version="1.0"?>
+<!--
+Copyright (c) 2009 AMQP Working Group.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<amqp major="0" minor="91" port="5672">
+ <constant name="frame-method" value="1"/>
+ <constant name="frame-header" value="2"/>
+ <constant name="frame-body" value="3"/>
+ <constant name="frame-heartbeat" value="8"/>
+ <constant name="frame-min-size" value="4096"/>
+ <constant name="frame-end" value="206"/>
+ <constant name="reply-success" value="200"/>
+ <constant name="content-too-large" value="311" class="soft-error"/>
+ <constant name="no-consumers" value="313" class="soft-error"/>
+ <constant name="connection-forced" value="320" class="hard-error"/>
+ <constant name="invalid-path" value="402" class="hard-error"/>
+ <constant name="access-refused" value="403" class="soft-error"/>
+ <constant name="not-found" value="404" class="soft-error"/>
+ <constant name="resource-locked" value="405" class="soft-error"/>
+ <constant name="precondition-failed" value="406" class="soft-error"/>
+ <constant name="frame-error" value="501" class="hard-error"/>
+ <constant name="syntax-error" value="502" class="hard-error"/>
+ <constant name="command-invalid" value="503" class="hard-error"/>
+ <constant name="channel-error" value="504" class="hard-error"/>
+ <constant name="unexpected-frame" value="505" class="hard-error"/>
+ <constant name="resource-error" value="506" class="hard-error"/>
+ <constant name="not-allowed" value="530" class="hard-error"/>
+ <constant name="not-implemented" value="540" class="hard-error"/>
+ <constant name="internal-error" value="541" class="hard-error"/>
+ <domain name="class-id" type="short"/>
+ <domain name="consumer-tag" type="shortstr"/>
+ <domain name="delivery-tag" type="longlong"/>
+ <domain name="exchange-name" type="shortstr">
+ <assert check="length" value="127"/>
+ <assert check="regexp" value="^[a-zA-Z0-9-_.:]*$"/>
+ </domain>
+ <domain name="method-id" type="short"/>
+ <domain name="no-ack" type="bit"/>
+ <domain name="no-local" type="bit"/>
+ <domain name="nowait" type="bit"/>
+ <!-- Qpid: restore these so that the generation sees the methods aas the same -->
+ <domain name="known-hosts" type="shortstr"/>
+ <domain name="access-ticket" type="short"/>
+ <!-- end Qpid specific -->
+ <domain name="path" type="shortstr">
+ <assert check="notnull"/>
+ <assert check="length" value="127"/>
+ </domain>
+ <domain name="peer-properties" type="table"/>
+ <domain name="queue-name" type="shortstr">
+ <assert check="length" value="127"/>
+ <assert check="regexp" value="^[a-zA-Z0-9-_.:]*$"/>
+ </domain>
+ <domain name="redelivered" type="bit"/>
+ <domain name="message-count" type="long"/>
+ <domain name="reply-code" type="short">
+ <assert check="notnull"/>
+ </domain>
+ <domain name="reply-text" type="shortstr">
+ <assert check="notnull"/>
+ </domain>
+ <domain name="bit" type="bit"/>
+ <domain name="octet" type="octet"/>
+ <domain name="short" type="short"/>
+ <domain name="long" type="long"/>
+ <domain name="longlong" type="longlong"/>
+ <domain name="shortstr" type="shortstr"/>
+ <domain name="longstr" type="longstr"/>
+ <domain name="timestamp" type="timestamp"/>
+ <domain name="table" type="table"/>
+ <class name="connection" handler="connection" index="10">
+ <chassis name="server" implement="MUST"/>
+ <chassis name="client" implement="MUST"/>
+ <method name="start" synchronous="1" index="10">
+ <chassis name="client" implement="MUST"/>
+ <response name="start-ok"/>
+ <field name="version-major" domain="octet"/>
+ <field name="version-minor" domain="octet"/>
+ <field name="server-properties" domain="peer-properties"/>
+ <field name="mechanisms" domain="longstr">
+ <assert check="notnull"/>
+ </field>
+ <field name="locales" domain="longstr">
+ <assert check="notnull"/>
+ </field>
+ </method>
+ <method name="start-ok" synchronous="1" index="11">
+ <chassis name="server" implement="MUST"/>
+ <field name="client-properties" domain="peer-properties"/>
+ <field name="mechanism" domain="shortstr">
+ <assert check="notnull"/>
+ </field>
+ <field name="response" domain="longstr">
+ <assert check="notnull"/>
+ </field>
+ <field name="locale" domain="shortstr">
+ <assert check="notnull"/>
+ </field>
+ </method>
+ <method name="secure" synchronous="1" index="20">
+ <chassis name="client" implement="MUST"/>
+ <response name="secure-ok"/>
+ <field name="challenge" domain="longstr"/>
+ </method>
+ <method name="secure-ok" synchronous="1" index="21">
+ <chassis name="server" implement="MUST"/>
+ <field name="response" domain="longstr">
+ <assert check="notnull"/>
+ </field>
+ </method>
+ <method name="tune" synchronous="1" index="30">
+ <chassis name="client" implement="MUST"/>
+ <response name="tune-ok"/>
+ <field name="channel-max" domain="short"/>
+ <field name="frame-max" domain="long"/>
+ <field name="heartbeat" domain="short"/>
+ </method>
+ <method name="tune-ok" synchronous="1" index="31">
+ <chassis name="server" implement="MUST"/>
+ <field name="channel-max" domain="short">
+ <assert check="notnull"/>
+ <assert check="le" method="tune" field="channel-max"/>
+ </field>
+ <field name="frame-max" domain="long"/>
+ <field name="heartbeat" domain="short"/>
+ </method>
+ <method name="open" synchronous="1" index="40">
+ <chassis name="server" implement="MUST"/>
+ <response name="open-ok"/>
+ <field name="virtual-host" domain="path"/>
+ <field name="capabilities" type="shortstr" reserved="1"/>
+ <field name="insist" type="bit" reserved="1"/>
+ </method>
+ <method name="open-ok" synchronous="1" index="41">
+ <chassis name="client" implement="MUST"/>
+ <field name="known-hosts" domain="known-hosts" reserved="1"/>
+ </method>
+ <method name="close" synchronous="1" index="50">
+ <chassis name="client" implement="MUST"/>
+ <chassis name="server" implement="MUST"/>
+ <response name="close-ok"/>
+ <field name="reply-code" domain="reply-code"/>
+ <field name="reply-text" domain="reply-text"/>
+ <field name="class-id" domain="class-id"/>
+ <field name="method-id" domain="method-id"/>
+ </method>
+ <method name="close-ok" synchronous="1" index="51">
+ <chassis name="client" implement="MUST"/>
+ <chassis name="server" implement="MUST"/>
+ </method>
+ </class>
+ <class name="channel" handler="channel" index="20">
+ <chassis name="server" implement="MUST"/>
+ <chassis name="client" implement="MUST"/>
+ <method name="open" synchronous="1" index="10">
+ <chassis name="server" implement="MUST"/>
+ <response name="open-ok"/>
+ <field name="out-of-band" type="shortstr" reserved="1"/>
+ </method>
+ <method name="open-ok" synchronous="1" index="11">
+ <chassis name="client" implement="MUST"/>
+ <field name="channel-id" type="longstr" reserved="1"/>
+ </method>
+ <method name="flow" synchronous="1" index="20">
+ <chassis name="server" implement="MUST"/>
+ <chassis name="client" implement="MUST"/>
+ <response name="flow-ok"/>
+ <field name="active" domain="bit"/>
+ </method>
+ <method name="flow-ok" index="21">
+ <chassis name="server" implement="MUST"/>
+ <chassis name="client" implement="MUST"/>
+ <field name="active" domain="bit"/>
+ </method>
+ <method name="close" synchronous="1" index="40">
+ <chassis name="client" implement="MUST"/>
+ <chassis name="server" implement="MUST"/>
+ <response name="close-ok"/>
+ <field name="reply-code" domain="reply-code"/>
+ <field name="reply-text" domain="reply-text"/>
+ <field name="class-id" domain="class-id"/>
+ <field name="method-id" domain="method-id"/>
+ </method>
+ <method name="close-ok" synchronous="1" index="41">
+ <chassis name="client" implement="MUST"/>
+ <chassis name="server" implement="MUST"/>
+ </method>
+ </class>
+ <class name="exchange" handler="channel" index="40">
+ <chassis name="server" implement="MUST"/>
+ <chassis name="client" implement="MUST"/>
+ <method name="declare" synchronous="1" index="10">
+ <chassis name="server" implement="MUST"/>
+ <response name="declare-ok"/>
+ <field name="ticket" domain="access-ticket" reserved="1"/>
+ <field name="exchange" domain="exchange-name">
+ <assert check="notnull"/>
+ </field>
+ <field name="type" domain="shortstr"/>
+ <field name="passive" domain="bit"/>
+ <field name="durable" domain="bit"/>
+ <field name="auto-delete" type="bit" reserved="1"/>
+ <field name="internal" type="bit" reserved="1"/>
+ <field name="nowait" domain="bit"/>
+ <field name="arguments" domain="table"/>
+ </method>
+ <method name="declare-ok" synchronous="1" index="11">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ <method name="delete" synchronous="1" index="20">
+ <chassis name="server" implement="MUST"/>
+ <response name="delete-ok"/>
+ <field name="ticket" domain="access-ticket" reserved="1"/>
+ <field name="exchange" domain="exchange-name">
+ <assert check="notnull"/>
+ </field>
+ <field name="if-unused" domain="bit"/>
+ <field name="nowait" domain="bit"/>
+ </method>
+ <method name="delete-ok" synchronous="1" index="21">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ <!-- Qpid : Added Exchange.bound and Exchange.bound-ok -->
+ <method name="bound" synchronous="1" index="22">
+ <chassis name="server" implement="SHOULD"/>
+ <response name="bound-ok"/>
+ <field name="exchange" domain="exchange-name"/>
+ <field name = "routing-key" type = "shortstr"/>
+ <field name = "queue" domain = "queue name"/>
+ </method>
+ <method name="bound-ok" synchronous="1" index="23">
+ <field name="reply-code" domain="reply-code"/>
+ <field name="reply-text" domain="reply-text"/>
+ <chassis name="client" implement="SHOULD"/>
+ </method>
+ <!-- End Qpid addition -->
+ </class>
+ <class name="queue" handler="channel" index="50">
+ <chassis name="server" implement="MUST"/>
+ <chassis name="client" implement="MUST"/>
+ <method name="declare" synchronous="1" index="10">
+ <chassis name="server" implement="MUST"/>
+ <response name="declare-ok"/>
+ <field name="ticket" domain="access-ticket" reserved="1"/>
+ <field name="queue" domain="queue-name"/>
+ <field name="passive" domain="bit"/>
+ <field name="durable" domain="bit"/>
+ <field name="exclusive" domain="bit"/>
+ <field name="auto-delete" domain="bit"/>
+ <field name="nowait" domain="bit"/>
+ <field name="arguments" domain="table"/>
+ </method>
+ <method name="declare-ok" synchronous="1" index="11">
+ <chassis name="client" implement="MUST"/>
+ <field name="queue" domain="queue-name">
+ <assert check="notnull"/>
+ </field>
+ <field name="message-count" domain="long"/>
+ <field name="consumer-count" domain="long"/>
+ </method>
+ <method name="bind" synchronous="1" index="20">
+ <chassis name="server" implement="MUST"/>
+ <response name="bind-ok"/>
+ <field name="ticket" domain="access-ticket" reserved="1"/>
+ <field name="queue" domain="queue-name"/>
+ <field name="exchange" domain="exchange-name"/>
+ <field name="routing-key" domain="shortstr"/>
+ <field name="nowait" domain="bit"/>
+ <field name="arguments" domain="table"/>
+ </method>
+ <method name="bind-ok" synchronous="1" index="21">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ <method name="unbind" synchronous="1" index="50">
+ <chassis name="server" implement="MUST"/>
+ <response name="unbind-ok"/>
+ <field name="ticket" domain="access-ticket" reserved="1"/>
+ <field name="queue" domain="queue-name"/>
+ <field name="exchange" domain="exchange-name"/>
+ <field name="routing-key" domain="shortstr"/>
+ <field name="arguments" domain="table"/>
+ </method>
+ <method name="unbind-ok" synchronous="1" index="51">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ <method name="purge" synchronous="1" index="30">
+ <chassis name="server" implement="MUST"/>
+ <response name="purge-ok"/>
+ <field name="ticket" domain="access-ticket" reserved="1"/>
+ <field name="queue" domain="queue-name"/>
+ <field name="nowait" domain="bit"/>
+ </method>
+ <method name="purge-ok" synchronous="1" index="31">
+ <chassis name="client" implement="MUST"/>
+ <field name="message-count" domain="long"/>
+ </method>
+ <method name="delete" synchronous="1" index="40">
+ <chassis name="server" implement="MUST"/>
+ <response name="delete-ok"/>
+ <field name="ticket" domain="access-ticket" reserved="1"/>
+ <field name="queue" domain="queue-name"/>
+ <field name="if-unused" domain="bit"/>
+ <field name="if-empty" domain="bit"/>
+ <field name="nowait" domain="bit"/>
+ </method>
+ <method name="delete-ok" synchronous="1" index="41">
+ <chassis name="client" implement="MUST"/>
+ <field name="message-count" domain="long"/>
+ </method>
+ </class>
+ <class name="basic" handler="channel" index="60">
+ <chassis name="server" implement="MUST"/>
+ <chassis name="client" implement="MAY"/>
+ <field name="content-type" domain="shortstr"/>
+ <field name="content-encoding" domain="shortstr"/>
+ <field name="headers" domain="table"/>
+ <field name="delivery-mode" domain="octet"/>
+ <field name="priority" domain="octet"/>
+ <field name="correlation-id" domain="shortstr"/>
+ <field name="reply-to" domain="shortstr"/>
+ <field name="expiration" domain="shortstr"/>
+ <field name="message-id" domain="shortstr"/>
+ <field name="timestamp" domain="timestamp"/>
+ <field name="type" domain="shortstr"/>
+ <field name="user-id" domain="shortstr"/>
+ <field name="app-id" domain="shortstr"/>
+ <field name="reserved" domain="shortstr"/>
+ <method name="qos" synchronous="1" index="10">
+ <chassis name="server" implement="MUST"/>
+ <response name="qos-ok"/>
+ <field name="prefetch-size" domain="long"/>
+ <field name="prefetch-count" domain="short"/>
+ <field name="global" domain="bit"/>
+ </method>
+ <method name="qos-ok" synchronous="1" index="11">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ <method name="consume" synchronous="1" index="20">
+ <chassis name="server" implement="MUST"/>
+ <response name="consume-ok"/>
+ <field name="ticket" domain="access-ticket" reserved="1"/>
+ <field name="queue" domain="queue-name"/>
+ <field name="consumer-tag" domain="consumer-tag"/>
+ <field name="no-local" domain="no-local"/>
+ <field name="no-ack" domain="no-ack"/>
+ <field name="exclusive" domain="bit"/>
+ <field name="nowait" domain="bit"/>
+ <field name="arguments" domain="table"/>
+ </method>
+ <method name="consume-ok" synchronous="1" index="21">
+ <chassis name="client" implement="MUST"/>
+ <field name="consumer-tag" domain="consumer-tag"/>
+ </method>
+ <method name="cancel" synchronous="1" index="30">
+ <chassis name="server" implement="MUST"/>
+ <response name="cancel-ok"/>
+ <field name="consumer-tag" domain="consumer-tag"/>
+ <field name="nowait" domain="bit"/>
+ </method>
+ <method name="cancel-ok" synchronous="1" index="31">
+ <chassis name="client" implement="MUST"/>
+ <field name="consumer-tag" domain="consumer-tag"/>
+ </method>
+ <method name="publish" content="1" index="40">
+ <chassis name="server" implement="MUST"/>
+ <field name="ticket" domain="access-ticket" reserved="1"/>
+ <field name="exchange" domain="exchange-name"/>
+ <field name="routing-key" domain="shortstr"/>
+ <field name="mandatory" domain="bit"/>
+ <field name="immediate" domain="bit"/>
+ </method>
+ <method name="return" content="1" index="50">
+ <chassis name="client" implement="MUST"/>
+ <field name="reply-code" domain="reply-code"/>
+ <field name="reply-text" domain="reply-text"/>
+ <field name="exchange" domain="exchange-name"/>
+ <field name="routing-key" domain="shortstr"/>
+ </method>
+ <method name="deliver" content="1" index="60">
+ <chassis name="client" implement="MUST"/>
+ <field name="consumer-tag" domain="consumer-tag"/>
+ <field name="delivery-tag" domain="delivery-tag"/>
+ <field name="redelivered" domain="redelivered"/>
+ <field name="exchange" domain="exchange-name"/>
+ <field name="routing-key" domain="shortstr"/>
+ </method>
+ <method name="get" synchronous="1" index="70">
+ <response name="get-ok"/>
+ <response name="get-empty"/>
+ <chassis name="server" implement="MUST"/>
+ <field name="ticket" domain="access-ticket" reserved="1"/>
+ <field name="queue" domain="queue-name"/>
+ <field name="no-ack" domain="no-ack"/>
+ </method>
+ <method name="get-ok" synchronous="1" content="1" index="71">
+ <chassis name="client" implement="MAY"/>
+ <field name="delivery-tag" domain="delivery-tag"/>
+ <field name="redelivered" domain="redelivered"/>
+ <field name="exchange" domain="exchange-name"/>
+ <field name="routing-key" domain="shortstr"/>
+ <field name="message-count" domain="long"/>
+ </method>
+ <method name="get-empty" synchronous="1" index="72">
+ <chassis name="client" implement="MAY"/>
+ <field name="cluster-id" type="shortstr" reserved="1"/>
+ </method>
+ <method name="ack" index="80">
+ <chassis name="server" implement="MUST"/>
+ <field name="delivery-tag" domain="delivery-tag"/>
+ <field name="multiple" domain="bit"/>
+ </method>
+ <method name="reject" index="90">
+ <chassis name="server" implement="MUST"/>
+ <field name="delivery-tag" domain="delivery-tag"/>
+ <field name="requeue" domain="bit"/>
+ </method>
+ <method name="recover" index="100" deprecated="1">
+ <chassis name="server" implement="MAY"/>
+ <field name="requeue" domain="bit"/>
+ </method>
+ <method name="recover-sync" index="110">
+ <chassis name="server" implement="MUST"/>
+ <field name="requeue" domain="bit"/>
+ </method>
+ <method name="recover-sync-ok" synchronous="1" index="111">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ </class>
+ <class name="tx" handler="channel" index="90">
+ <chassis name="server" implement="SHOULD"/>
+ <chassis name="client" implement="MAY"/>
+ <method name="select" synchronous="1" index="10">
+ <chassis name="server" implement="MUST"/>
+ <response name="select-ok"/>
+ </method>
+ <method name="select-ok" synchronous="1" index="11">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ <method name="commit" synchronous="1" index="20">
+ <chassis name="server" implement="MUST"/>
+ <response name="commit-ok"/>
+ </method>
+ <method name="commit-ok" synchronous="1" index="21">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ <method name="rollback" synchronous="1" index="30">
+ <chassis name="server" implement="MUST"/>
+ <response name="rollback-ok"/>
+ </method>
+ <method name="rollback-ok" synchronous="1" index="31">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ </class>
+</amqp>
diff --git a/specs/management-schema.xml b/specs/management-schema.xml
index 850f9c62e6..1e345b5ea5 100644
--- a/specs/management-schema.xml
+++ b/specs/management-schema.xml
@@ -1,4 +1,4 @@
-<schema package="qpid">
+<schema package="org.apache.qpid.broker">
<!--
Licensed to the Apache Software Foundation (ASF) under one
@@ -61,24 +61,16 @@
===============================================================
-->
<class name="Broker">
- <property name="systemRef" type="objId" references="System" access="RC" index="y" desc="System ID" parentRef="y"/>
- <property name="port" type="uint16" access="RC" index="y" desc="TCP Port for AMQP Service"/>
- <property name="workerThreads" type="uint16" access="RO" desc="Thread pool size"/>
- <property name="maxConns" type="uint16" access="RO" desc="Maximum allowed connections"/>
- <property name="connBacklog" type="uint16" access="RO" desc="Connection backlog limit for listening socket"/>
- <property name="stagingThreshold" type="uint32" access="RO" desc="Broker stages messages over this size to disk"/>
- <property name="mgmtPubInterval" type="uint16" access="RW" unit="second" min="1" desc="Interval for management broadcasts"/>
- <property name="clusterName" type="sstr" access="RO"
- desc="Name of cluster this server is a member of"/>
- <property name="version" type="sstr" access="RO" desc="Running software version"/>
- <property name="dataDirEnabled" type="bool" access="RO" desc="Persistent configuration storage enabled"/>
- <property name="dataDir" type="sstr" access="RO" desc="Persistent configuration storage location"/>
-
- <method name="joinCluster">
- <arg name="clusterName" dir="I" type="sstr"/>
- </method>
-
- <method name="leaveCluster"/>
+ <property name="systemRef" type="objId" references="System" access="RC" index="y" desc="System ID" parentRef="y"/>
+ <property name="port" type="uint16" access="RC" index="y" desc="TCP Port for AMQP Service"/>
+ <property name="workerThreads" type="uint16" access="RO" desc="Thread pool size"/>
+ <property name="maxConns" type="uint16" access="RO" desc="Maximum allowed connections"/>
+ <property name="connBacklog" type="uint16" access="RO" desc="Connection backlog limit for listening socket"/>
+ <property name="stagingThreshold" type="uint32" access="RO" desc="Broker stages messages over this size to disk"/>
+ <property name="mgmtPubInterval" type="uint16" access="RW" unit="second" min="1" desc="Interval for management broadcasts"/>
+ <property name="version" type="sstr" access="RO" desc="Running software version"/>
+ <property name="dataDir" type="sstr" access="RO" optional="y" desc="Persistent configuration storage location"/>
+ <statistic name="uptime" type="deltaTime"/>
<method name="echo" desc="Request a response to test the path to the management broker">
<arg name="sequence" dir="IO" type="uint32" default="0"/>
@@ -88,12 +80,19 @@
<method name="connect" desc="Establish a connection to another broker">
<arg name="host" dir="I" type="sstr"/>
<arg name="port" dir="I" type="uint32"/>
- <arg name="useSsl" dir="I" type="bool"/>
<arg name="durable" dir="I" type="bool"/>
<arg name="authMechanism" dir="I" type="sstr"/>
<arg name="username" dir="I" type="sstr"/>
<arg name="password" dir="I" type="sstr"/>
+ <arg name="transport" dir="I" type="sstr"/>
</method>
+
+ <method name="queueMoveMessages" desc="Move messages from one queue to another">
+ <arg name="srcQueue" dir="I" type="sstr" desc="Source queue"/>
+ <arg name="destQueue" dir="I" type="sstr" desc="Destination queue"/>
+ <arg name="qty" dir="I" type="uint32" desc="# of messages to move. 0 means all messages"/>
+ </method>
+
</class>
<!--
@@ -106,7 +105,8 @@
<property name="label" type="sstr" access="RO" desc="Label for agent"/>
<property name="registeredTo" type="objId" references="Broker" access="RO" desc="Broker agent is registered to"/>
<property name="systemId" type="uuid" access="RO" desc="Identifier of system where agent resides"/>
- <property name="objectIdBank" type="uint32" access="RO" desc="Assigned object-id bank"/>
+ <property name="brokerBank" type="uint32" access="RO" desc="Assigned object-id broker bank"/>
+ <property name="agentBank" type="uint32" access="RO" desc="Assigned object-id agent bank"/>
</class>
<!--
@@ -115,8 +115,9 @@
===============================================================
-->
<class name="Vhost">
- <property name="brokerRef" type="objId" references="Broker" access="RC" index="y" parentRef="y"/>
- <property name="name" type="sstr" access="RC" index="y"/>
+ <property name="brokerRef" type="objId" references="Broker" access="RC" index="y" parentRef="y"/>
+ <property name="name" type="sstr" access="RC" index="y"/>
+ <property name="federationTag" type="sstr" access="RO"/>
</class>
<!--
@@ -128,10 +129,11 @@
<property name="vhostRef" type="objId" references="Vhost" access="RC" index="y" parentRef="y"/>
<property name="name" type="sstr" access="RC" index="y"/>
- <property name="durable" type="bool" access="RC"/>
- <property name="autoDelete" type="bool" access="RC"/>
- <property name="exclusive" type="bool" access="RC"/>
- <property name="arguments" type="map" access="RO" desc="Arguments supplied in queue.declare"/>
+ <property name="durable" type="bool" access="RC"/>
+ <property name="autoDelete" type="bool" access="RC"/>
+ <property name="exclusive" type="bool" access="RC"/>
+ <property name="arguments" type="map" access="RO" desc="Arguments supplied in queue.declare"/>
+ <property name="altExchange" type="objId" references="Exchange" access="RO" optional="y"/>
<statistic name="msgTotalEnqueues" type="count64" unit="message" desc="Total messages enqueued"/>
<statistic name="msgTotalDequeues" type="count64" unit="message" desc="Total messages dequeued"/>
@@ -147,14 +149,6 @@
<statistic name="byteTxnDequeues" type="count64" unit="octet" desc="Transactional messages dequeued"/>
<statistic name="bytePersistEnqueues" type="count64" unit="octet" desc="Persistent messages enqueued"/>
<statistic name="bytePersistDequeues" type="count64" unit="octet" desc="Persistent messages dequeued"/>
- <statistic name="enqueueTxnStarts" type="count64" unit="transaction" desc="Total enqueue transactions started "/>
- <statistic name="enqueueTxnCommits" type="count64" unit="transaction" desc="Total enqueue transactions committed"/>
- <statistic name="enqueueTxnRejects" type="count64" unit="transaction" desc="Total enqueue transactions rejected"/>
- <statistic name="enqueueTxnCount" type="count32" unit="transaction" desc="Current pending enqueue transactions"/>
- <statistic name="dequeueTxnStarts" type="count64" unit="transaction" desc="Total dequeue transactions started"/>
- <statistic name="dequeueTxnCommits" type="count64" unit="transaction" desc="Total dequeue transactions committed"/>
- <statistic name="dequeueTxnRejects" type="count64" unit="transaction" desc="Total dequeue transactions rejected"/>
- <statistic name="dequeueTxnCount" type="count32" unit="transaction" desc="Current pending dequeue transactions"/>
<statistic name="consumerCount" type="hilo32" unit="consumer" desc="Current consumers on queue"/>
<statistic name="bindingCount" type="hilo32" unit="binding" desc="Current bindings"/>
<statistic name="unackedMessages" type="hilo32" unit="message" desc="Messages consumed but not yet acked"/>
@@ -171,10 +165,13 @@
===============================================================
-->
<class name="Exchange">
- <property name="vhostRef" type="objId" references="Vhost" access="RC" index="y" parentRef="y"/>
- <property name="name" type="sstr" access="RC" index="y"/>
- <property name="type" type="sstr" access="RO"/>
- <property name="durable" type="bool" access="RC"/>
+ <property name="vhostRef" type="objId" references="Vhost" access="RC" index="y" parentRef="y"/>
+ <property name="name" type="sstr" access="RC" index="y"/>
+ <property name="type" type="sstr" access="RO"/>
+ <property name="durable" type="bool" access="RO"/>
+ <property name="autoDelete" type="bool" access="RO"/>
+ <property name="altExchange" type="objId" references="Exchange" access="RO" optional="y"/>
+ <property name="arguments" type="map" access="RO" desc="Arguments supplied in exchange.declare"/>
<statistic name="producerCount" type="hilo32" desc="Current producers on exchange"/>
<statistic name="bindingCount" type="hilo32" desc="Current bindings"/>
@@ -196,22 +193,44 @@
<property name="queueRef" type="objId" references="Queue" access="RC" index="y"/>
<property name="bindingKey" type="sstr" access="RC" index="y"/>
<property name="arguments" type="map" access="RC"/>
+ <property name="origin" type="sstr" access="RO" optional="y"/>
<statistic name="msgMatched" type="count64"/>
</class>
<!--
===============================================================
- Client
+ Subscription
+ ===============================================================
+ -->
+ <class name="Subscription">
+ <property name="sessionRef" type="objId" references="Session" access="RC" index="y" parentRef="y"/>
+ <property name="queueRef" type="objId" references="Queue" access="RC" index="y"/>
+ <property name="name" type="sstr" access="RC" index="y"/>
+ <property name="browsing" type="bool" access="RC"/>
+ <property name="acknowledged" type="bool" access="RC"/>
+ <property name="exclusive" type="bool" access="RC"/>
+ <property name="creditMode" type="sstr" access="RO" desc="WINDOW or CREDIT"/>
+ <property name="arguments" type="map" access="RC"/>
+ <statistic name="delivered" type="count64" unit="message" desc="Messages delivered"/>
+ </class>
+
+ <!--
+ ===============================================================
+ Connection
===============================================================
-->
<class name="Connection">
<property name="vhostRef" type="objId" references="Vhost" access="RC" index="y" parentRef="y"/>
<property name="address" type="sstr" access="RC" index="y"/>
<property name="incoming" type="bool" access="RC"/>
-
+ <property name="SystemConnection" type="bool" access="RC" desc="Infrastucture/ Inter-system connection (Cluster, Federation, ...)"/>
+ <property name="federationLink" type="bool" access="RO" desc="Is this a federation link"/>
+ <property name="authIdentity" type="sstr" access="RO" desc="authId of connection if authentication enabled"/>
+ <property name="remoteProcessName" type="sstr" access="RO" optional="y" desc="Name of executable running as remote client"/>
+ <property name="remotePid" type="uint32" access="RO" optional="y" desc="Process ID of remote client"/>
+ <property name="remoteParentPid" type="uint32" access="RO" optional="y" desc="Parent Process ID of remote client"/>
<statistic name="closing" type="bool" desc="This client is closing by management request"/>
- <statistic name="authIdentity" type="sstr"/>
<statistic name="framesFromClient" type="count64"/>
<statistic name="framesToClient" type="count64"/>
<statistic name="bytesFromClient" type="count64"/>
@@ -232,7 +251,7 @@
<property name="vhostRef" type="objId" references="Vhost" access="RC" index="y" parentRef="y"/>
<property name="host" type="sstr" access="RC" index="y"/>
<property name="port" type="uint16" access="RC" index="y"/>
- <property name="useSsl" type="bool" access="RC"/>
+ <property name="transport" type="sstr" access="RC"/>
<property name="durable" type="bool" access="RC"/>
<statistic name="state" type="sstr" desc="Operational state of the link"/>
@@ -244,11 +263,13 @@
<arg name="durable" dir="I" type="bool"/>
<arg name="src" dir="I" type="sstr"/>
<arg name="dest" dir="I" type="sstr"/>
- <arg name="key" dir="I" type="sstr" default=""/>
- <arg name="tag" dir="I" type="sstr" default=""/>
- <arg name="excludes" dir="I" type="sstr" default=""/>
- <arg name="srcIsQueue" dir="I" type="bool" default="0"/>
- <arg name="srcIsLocal" dir="I" type="bool" default="0"/>
+ <arg name="key" dir="I" type="sstr"/>
+ <arg name="tag" dir="I" type="sstr"/>
+ <arg name="excludes" dir="I" type="sstr"/>
+ <arg name="srcIsQueue" dir="I" type="bool"/>
+ <arg name="srcIsLocal" dir="I" type="bool"/>
+ <arg name="dynamic" dir="I" type="bool"/>
+ <arg name="sync" dir="I" type="uint16"/>
</method>
</class>
@@ -269,6 +290,8 @@
<property name="srcIsLocal" type="bool" access="RC"/>
<property name="tag" type="sstr" access="RC"/>
<property name="excludes" type="sstr" access="RC"/>
+ <property name="dynamic" type="bool" access="RC"/>
+ <property name="sync" type="uint16" access="RC"/>
<method name="close"/>
</class>
@@ -279,20 +302,59 @@
===============================================================
-->
<class name="Session">
- <property name="vhostRef" type="objId" references="Vhost" access="RC" index="y" parentRef="y"/>
- <property name="name" type="sstr" access="RC" index="y"/>
- <property name="channelId" type="uint16" access="RO"/>
- <property name="connectionRef" type="objId" references="Connection" access="RO"/>
- <property name="detachedLifespan" type="uint32" access="RO" unit="second"/>
-
- <statistic name="attached" type="bool"/>
- <statistic name="expireTime" type="absTime"/>
+ <property name="vhostRef" type="objId" references="Vhost" access="RC" index="y" parentRef="y"/>
+ <property name="name" type="sstr" access="RC" index="y"/>
+ <property name="channelId" type="uint16" access="RO"/>
+ <property name="connectionRef" type="objId" references="Connection" access="RO"/>
+ <property name="detachedLifespan" type="uint32" access="RO" unit="second"/>
+ <property name="attached" type="bool" access="RO"/>
+ <property name="expireTime" type="absTime" access="RO" optional="y"/>
+ <property name="maxClientRate" type="uint32" access="RO" unit="msgs/sec" optional="y"/>
+
<statistic name="framesOutstanding" type="count32"/>
+ <statistic name="TxnStarts" type="count64" unit="transaction" desc="Total transactions started "/>
+ <statistic name="TxnCommits" type="count64" unit="transaction" desc="Total transactions committed"/>
+ <statistic name="TxnRejects" type="count64" unit="transaction" desc="Total transactions rejected"/>
+ <statistic name="TxnCount" type="count32" unit="transaction" desc="Current pending transactions"/>
+
+ <statistic name="clientCredit" type="count32" unit="message" desc="Client message credit"/>
+
<method name="solicitAck"/>
<method name="detach"/>
<method name="resetLifespan"/>
<method name="close"/>
</class>
+
+ <eventArguments>
+ <arg name="altEx" type="sstr" desc="Name of the alternate exchange"/>
+ <arg name="args" type="map" desc="Supplemental arguments or parameters supplied"/>
+ <arg name="autoDel" type="bool" desc="Created object is automatically deleted when no longer in use"/>
+ <arg name="dest" type="sstr" desc="Destination tag for a subscription"/>
+ <arg name="disp" type="sstr" desc="Disposition of a declaration: 'created' if object was created, 'existing' if object already existed"/>
+ <arg name="durable" type="bool" desc="Created object is durable"/>
+ <arg name="exName" type="sstr" desc="Name of an exchange"/>
+ <arg name="exType" type="sstr" desc="Type of an exchange"/>
+ <arg name="excl" type="bool" desc="Created object is exclusive for the use of the owner only"/>
+ <arg name="key" type="lstr" desc="Key text used for routing or binding"/>
+ <arg name="qName" type="sstr" desc="Name of a queue"/>
+ <arg name="reason" type="lstr" desc="Reason for a failure"/>
+ <arg name="rhost" type="sstr" desc="Address (i.e. DNS name, IP address, etc.) of a remotely connected host"/>
+ <arg name="user" type="sstr" desc="Authentication identity"/>
+ </eventArguments>
+
+ <event name="clientConnect" sev="inform" args="rhost, user"/>
+ <event name="clientConnectFail" sev="warn" args="rhost, user, reason"/>
+ <event name="clientDisconnect" sev="inform" args="rhost, user"/>
+ <event name="brokerLinkUp" sev="inform" args="rhost"/>
+ <event name="brokerLinkDown" sev="warn" args="rhost"/>
+ <event name="queueDeclare" sev="inform" args="rhost, user, qName, durable, excl, autoDel, args, disp"/>
+ <event name="queueDelete" sev="inform" args="rhost, user, qName"/>
+ <event name="exchangeDeclare" sev="inform" args="rhost, user, exName, exType, altEx, durable, autoDel, args, disp"/>
+ <event name="exchangeDelete" sev="inform" args="rhost, user, exName"/>
+ <event name="bind" sev="inform" args="rhost, user, exName, qName, key, args"/>
+ <event name="unbind" sev="inform" args="rhost, user, exName, qName, key"/>
+ <event name="subscribe" sev="inform" args="rhost, user, qName, dest, excl, args"/>
+ <event name="unsubscribe" sev="inform" args="rhost, user, dest"/>
</schema>
diff --git a/specs/management-types.xml b/specs/management-types.xml
deleted file mode 100644
index 309c94c98b..0000000000
--- a/specs/management-types.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<schema-types>
-
-<!--
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
--->
-
-<type name="objId" base="REF" cpp="uint64_t" encode="@.putLongLong(#)" decode="# = @.getLongLong()" accessor="direct" init="0"/>
-<type name="uint8" base="U8" cpp="uint8_t" encode="@.putOctet(#)" decode="# = @.getOctet()" accessor="direct" init="0"/>
-<type name="uint16" base="U16" cpp="uint16_t" encode="@.putShort(#)" decode="# = @.getShort()" accessor="direct" init="0"/>
-<type name="uint32" base="U32" cpp="uint32_t" encode="@.putLong(#)" decode="# = @.getLong()" accessor="direct" init="0"/>
-<type name="uint64" base="U64" cpp="uint64_t" encode="@.putLongLong(#)" decode="# = @.getLongLong()" accessor="direct" init="0"/>
-<type name="int8" base="S8" cpp="int8_t" encode="@.putInt8(#)" decode="# = @.getInt8()" accessor="direct" init="0"/>
-<type name="int16" base="S16" cpp="int16_t" encode="@.putInt16(#)" decode="# = @.getInt16()" accessor="direct" init="0"/>
-<type name="int32" base="S32" cpp="int32_t" encode="@.putInt32(#)" decode="# = @.getInt32()" accessor="direct" init="0"/>
-<type name="int64" base="S46" cpp="int64_t" encode="@.putInt64(#)" decode="# = @.getInt64()" accessor="direct" init="0"/>
-<type name="bool" base="BOOL" cpp="uint8_t" encode="@.putOctet(#?1:0)" decode="# = @.getOctet()==1" accessor="direct" init="0"/>
-<type name="sstr" base="SSTR" cpp="std::string" encode="@.putShortString(#)" decode="@.getShortString(#)" accessor="direct" init='""'/>
-<type name="lstr" base="LSTR" cpp="std::string" encode="@.putLongString(#)" decode="@.getLongString(#)" accessor="direct" init='""'/>
-<type name="absTime" base="ABSTIME" cpp="uint64_t" encode="@.putLongLong(#)" decode="# = @.getLongLong()" accessor="direct" init="0"/>
-<type name="deltaTime" base="DELTATIME" cpp="uint64_t" encode="@.putLongLong(#)" decode="# = @.getLongLong()" accessor="direct" init="0"/>
-<type name="float" base="FLOAT" cpp="float" encode="@.putFloat(#)" decode="# = @.getFloat()" accessor="direct" init="0."/>
-<type name="double" base="DOUBLE" cpp="double" encode="@.putDouble(#)" decode="# = @.getDouble()" accessor="direct" init="0."/>
-<type name="uuid" base="UUID" cpp="framing::Uuid" encode="#.encode(@)" decode="#.decode(@)" accessor="direct"/>
-<type name="map" base="FTABLE" cpp="framing::FieldTable" encode="#.encode(@)" decode="#.decode(@)" accessor="direct"/>
-
-<type name="hilo8" base="U8" cpp="uint8_t" encode="@.putOctet(#)" decode="# = @.getOctet()" style="wm" accessor="counter" init="0"/>
-<type name="hilo16" base="U16" cpp="uint16_t" encode="@.putShort(#)" decode="# = @.getShort()" style="wm" accessor="counter" init="0"/>
-<type name="hilo32" base="U32" cpp="uint32_t" encode="@.putLong(#)" decode="# = @.getLong()" style="wm" accessor="counter" init="0"/>
-<type name="hilo64" base="U64" cpp="uint64_t" encode="@.putLongLong(#)" decode="# = @.getLongLong()" style="wm" accessor="counter" init="0"/>
-
-<type name="count8" base="U8" cpp="uint8_t" encode="@.putOctet(#)" decode="# = @.getOctet()" accessor="counter" init="0" perThread="y"/>
-<type name="count16" base="U16" cpp="uint16_t" encode="@.putShort(#)" decode="# = @.getShort()" accessor="counter" init="0" perThread="y"/>
-<type name="count32" base="U32" cpp="uint32_t" encode="@.putLong(#)" decode="# = @.getLong()" accessor="counter" init="0" perThread="y"/>
-<type name="count64" base="U64" cpp="uint64_t" encode="@.putLongLong(#)" decode="# = @.getLongLong()" accessor="counter" init="0" perThread="y"/>
-
-<!-- Min/Max/Average statistics -->
-<type name="mma32" base="U32" cpp="uint32_t" encode="@.putLong(#)" decode="# = @.getLong()" style="mma" accessor="direct" init="0" perThread="y"/>
-<type name="mma64" base="U64" cpp="uint64_t" encode="@.putLongLong(#)" decode="# = @.getLongLong()" style="mma" accessor="direct" init="0" perThread="y"/>
-<type name="mmaTime" base="DELTATIME" cpp="uint64_t" encode="@.putLongLong(#)" decode="# = @.getLongLong()" style="mma" accessor="direct" init="0" perThread="y"/>
-
-</schema-types>
diff --git a/wcf/QpidWcf.sln b/wcf/QpidWcf.sln
new file mode 100644
index 0000000000..9f83cf553a
--- /dev/null
+++ b/wcf/QpidWcf.sln
@@ -0,0 +1,79 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License
+#
+
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AmqpTypes", "src\Apache\Qpid\AmqpTypes\AmqpTypes.csproj", "{820BFC34-A40F-46BA-B86B-05334854CA17}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Interop", "src\Apache\Qpid\Interop\Interop.vcproj", "{C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}"
+ ProjectSection(ProjectDependencies) = postProject
+ {820BFC34-A40F-46BA-B86B-05334854CA17} = {820BFC34-A40F-46BA-B86B-05334854CA17}
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FunctionalTests", "test\Apache\Qpid\Test\Channel\Functional\FunctionalTests.csproj", "{E2D8C779-E417-40BA-BEE1-EE034268482F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Channel", "src\Apache\Qpid\Channel\Channel.csproj", "{8AABAB30-7D1E-4539-B7D1-05450262BAD2}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Debug|Win32.Build.0 = Debug|Any CPU
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Debug|x64.Build.0 = Debug|Any CPU
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Release|Win32.ActiveCfg = Release|Any CPU
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Release|Win32.Build.0 = Release|Any CPU
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Release|x64.ActiveCfg = Release|Any CPU
+ {820BFC34-A40F-46BA-B86B-05334854CA17}.Release|x64.Build.0 = Release|Any CPU
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Debug|Win32.Build.0 = Debug|Win32
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Debug|x64.ActiveCfg = Debug|x64
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Debug|x64.Build.0 = Debug|x64
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Release|Win32.ActiveCfg = Release|Win32
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Release|Win32.Build.0 = Release|Win32
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Release|x64.ActiveCfg = Release|x64
+ {C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}.Release|x64.Build.0 = Release|x64
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Debug|Win32.Build.0 = Debug|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Debug|x64.Build.0 = Debug|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Release|Win32.ActiveCfg = Release|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Release|Win32.Build.0 = Release|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Release|x64.ActiveCfg = Release|Any CPU
+ {E2D8C779-E417-40BA-BEE1-EE034268482F}.Release|x64.Build.0 = Release|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Debug|Win32.Build.0 = Debug|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Debug|x64.Build.0 = Debug|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Release|Win32.ActiveCfg = Release|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Release|Win32.Build.0 = Release|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Release|x64.ActiveCfg = Release|Any CPU
+ {8AABAB30-7D1E-4539-B7D1-05450262BAD2}.Release|x64.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/wcf/ReadMe.txt b/wcf/ReadMe.txt
new file mode 100644
index 0000000000..6f118ceac3
--- /dev/null
+++ b/wcf/ReadMe.txt
@@ -0,0 +1,162 @@
+1. WCF supported features
+=========================
+
+1. WCF service model programming using one way contracts
+2. WCF channel model programming using IInputChannel and IOutputChannel based factories
+3. Programmatic access to AMQP message properties on WCF messages
+4. AMQP version 0-10 (as provided by the Qpid C++ native client library)
+5. Shared connections for multiple channels based on binding parameters
+6. WCF to WCF applications (using SOAP message encoders)
+7. WCF to non-WCF applications (using raw content encoders)
+8. Rudimentary AMQP type support for headers (Int and String)
+9. Channel functional tests using NUnit
+10. Programming samples
+
+
+2. Planned features (not yet available)
+=======================================
+
+1. Full AMQP type support, including maps and arrays
+2. System.Transactions integration (local and distributed with dynamic escalation)
+3. Prefetch window for inbound messages
+4. Shared sessions
+5. Connection failover with AMQP broker clusters
+6. Temporary queues
+7. Broker management
+8. System logging and tracing
+9. CMake build system support
+10. Transport and message based security
+
+
+3. Prerequisites
+================
+
+1. Qpid C++ client and common libraries for Windows including BOOST
+Ensure the location of the Boost library (e.g. %BOOST_ROOT%\lib) is
+included in your PATH environment variable.
+
+2. .NET Framework 3.5 SP1
+Install the .NET Framework from http://www.microsoft.com/net/
+
+3. Windows SDK
+Install the Windows SDK for the version of Windows that you are using
+from http://msdn.microsoft.com/en-us/windows/bb980924.aspx
+
+4. NUnit
+Install NUnit from http://www.nunit.org
+
+NOTE: In the following instructions %QPID_ROOT% refers to the root of
+qpid source code location e.g. C:\trunk\qpid
+
+5. Build Qpid cpp
+Build at least the "qpidd", "qpidclient" and "qpidcommon" projects.
+Create an environment variable called QPID_BUILD_ROOT and store the
+path to the Qpid build directory in it.
+
+
+4. Building the solution file
+=============================
+
+Option 1: Using MSBuild
+
+1. %systemroot%\Microsoft.NET\Framework\v3.5\MSBuild.exe %QPID_ROOT%\wcf\QpidWcf.sln
+2. %systemroot%\Microsoft.NET\Framework\v3.5\MSBuild.exe %QPID_ROOT%\wcf\tools\QCreate\QCreate.sln
+
+
+Option 2: Using Visual Studio 2008 (the Professional Edition, Team
+System Development Edition, or Team System Team Suite SKU)
+
+1. Open the solution file QpidWcf.sln in Visual Studio.
+2. Make sure that the reference to 'nunit.framework.dll' by the 'FunctionalTests'
+ project is appropriately resolved.
+3. Select the Debug configuration.
+3. Right-click the solution file in the Solution Explorer and select 'Build Solution'.
+4. Follow the above steps to build %QPID_ROOT%\wcf\tools\QCreate.sln as well.
+
+
+5. Executing tests
+==================
+
+1. Make sure that the batch file
+ %QPID_ROOT%\wcf\test\Apache\Qpid\Test\Channel\Functional\RunTests.bat has the correct
+ values for the nunit_exe, qpid_dll_location and configuration_name variables as per
+ your installation.
+2. Start the qpid broker from the qpid build folder e.g. %QPID_BUILD_ROOT%\src\Debug.
+3. Execute RunTests.bat from its location e.g. %QPID_ROOT%\wcf\test\Apache\Qpid\Test\Channel\Functional.
+
+
+6. Building and executing samples
+=================================
+
+WCFToWCFDirect
+
+1. Copy the dlls Apache.Qpid.Channel.dll and Apache.Qpid.Interop.dll that you built
+ in step 2 to the %QPID_ROOT%\wcf\samples\Channel\WCFToWCFDirect folder.
+
+2. Build the solution WCFToWCFDirect.sln.
+
+3. Copy qpidclient.dll and qpidcommon.dll from the Qpid build folder
+ e.g. %QPID_ROOT%\cpp\build\src\Debug to the same location as the exe files
+ e.g. bin\Debug of each of the projects. These dlls are needed at runtime.
+
+4. Copy qpidclient.dll and qpidcommon.dll to %QPID_ROOT%\wcf\tools\QCreate\Debug folder.
+
+5. Start the qpid broker from the qpid build folder e.g. %QPID_ROOT%\cpp\build\src\Debug.
+
+6. Create queue required using the QCreate tool located at
+ %QPID_ROOT%\wcf\tools\QCreate\Debug. The syntax is QCreate %QPID_ROOT%. For
+ this sample you should do
+
+ QCreate amq.direct routing_key message_queue
+
+7. Start Service.exe from
+ %QPID_ROOT%\wcf\samples\Channel\WCFToWCFDirect\Service\bin\Debug.
+
+8. Start Client.exe from
+ %QPID_ROOT%\wcf\samples\Channel\WCFToWCFDirect\Client\bin\Debug.
+
+
+WCFToWCFPubSub
+
+1. Copy the dlls Apache.Qpid.Channel.dll and Apache.Qpid.Interop.dll that you built
+ in step 2 to the %QPID_ROOT%\wcf\samples\Channel\WCFToWCFPubSub folder.
+
+2. Build the solution WCFToWCFPubSub.sln.
+
+3. Copy qpidclient.dll and qpidcommon.dll from the Qpid build folder
+ e.g. %QPID_ROOT%\cpp\build\src\Debug to the same location as the exe files
+ e.g. bin\Debug of each of the projects. These dlls are needed at runtime.
+
+4. Copy qpidclient.dll and qpidcommon.dll to %QPID_ROOT%\wcf\tools\QCreate\Debug folder.
+
+5. Start the qpid broker from the qpid build folder e.g. %QPID_ROOT%\cpp\build\src\Debug.
+
+6. Create queues required using the QCreate tool located at
+ \wcf\tools\QCreate\Debug. The syntax is QCreate %QPID_ROOT%. For this sample you
+ should do
+
+ QCreate amq.topic usa.# usa
+ QCreate amq.topic #.news news
+
+7. Start Topic_Consumer.exe from
+ %QPID_ROOT%\wcf\samples\Channel\WCFToWCFPubSub\Topic_Consumer\bin\Debug.
+
+8. Start Another_Topic_Consumer.exe from
+ %QPID_ROOT%\wcf\samples\Channel\WCFToWCFPubSub\Another_Topic_Consumer\bin\Debug.
+
+9. Start Topic_Producer.exe from
+ %QPID_ROOT%\wcf\samples\Channel\WCFToWCFPubSub\Topic_Producer\bin\Debug.
+
+
+7. Known Issues
+===============
+
+1. The Release configuration of the build (specified using the
+ /p:Configuration=Release switch with MSBuild) fails.
+
+2. The AmqpChannelListener is limited to single threaded use and the async methods
+ throw NotImplementedException.
+
+3. The AmqpChannelListener can hang on close for 60 seconds.
+
+
diff --git a/wcf/samples/Channel/WCFToWCFDirect/Client/Client.cs b/wcf/samples/Channel/WCFToWCFDirect/Client/Client.cs
new file mode 100644
index 0000000000..93ac97bc66
--- /dev/null
+++ b/wcf/samples/Channel/WCFToWCFDirect/Client/Client.cs
@@ -0,0 +1,68 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+
+namespace Apache.Qpid.Samples.Channel.WCFToWCFDirect
+{
+ using System;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using Apache.Qpid.Channel;
+
+ class Client
+ {
+ static void Main(string[] args)
+ {
+ try
+ {
+ // Create binding for the service endpoint.
+ CustomBinding amqpBinding = new CustomBinding();
+ amqpBinding.Elements.Add(new BinaryMessageEncodingBindingElement());
+ amqpBinding.Elements.Add(new AmqpTransportBindingElement());
+
+ // Create endpoint address.
+ Uri amqpClientUri = new Uri("amqp:amq.direct?routingkey=routing_key");
+ EndpointAddress endpointAddress = new EndpointAddress(amqpClientUri);
+
+ // Create a client with given client endpoint configuration.
+ ChannelFactory<IHelloService> channelFactory = new ChannelFactory<IHelloService>(amqpBinding, endpointAddress);
+ IHelloService clientProxy = channelFactory.CreateChannel();
+
+ Console.WriteLine();
+
+ string name = "name";
+ for (int i = 0; i < 5; i++)
+ {
+ Console.WriteLine("Sending message: " + name + (i + 1));
+ clientProxy.SayHello(name + (i + 1));
+ }
+
+ Console.WriteLine();
+ Console.WriteLine("Press <ENTER> to terminate client.");
+ Console.ReadLine();
+
+ channelFactory.Close();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Exception: {0}", e);
+ }
+ }
+ }
+}
diff --git a/wcf/samples/Channel/WCFToWCFDirect/Client/Client.csproj b/wcf/samples/Channel/WCFToWCFDirect/Client/Client.csproj
new file mode 100644
index 0000000000..7e1d2d9f5d
--- /dev/null
+++ b/wcf/samples/Channel/WCFToWCFDirect/Client/Client.csproj
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{0CCD5711-2072-47B8-B902-07EC12C04159}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Client</RootNamespace>
+ <AssemblyName>Client</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Apache.Qpid.Channel, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\Apache.Qpid.Channel.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Client.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Service\Service.csproj">
+ <Project>{D0A46136-B4E3-4C50-AB6D-FB2BC6683D6E}</Project>
+ <Name>Service</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/wcf/samples/Channel/WCFToWCFDirect/Client/Properties/AssemblyInfo.cs b/wcf/samples/Channel/WCFToWCFDirect/Client/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..414a3b5858
--- /dev/null
+++ b/wcf/samples/Channel/WCFToWCFDirect/Client/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Client")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("MSIT")]
+[assembly: AssemblyProduct("Client")]
+[assembly: AssemblyCopyright("Copyright © MSIT 2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("c3743ce0-3054-4188-8cd7-3a22734ee313")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/wcf/samples/Channel/WCFToWCFDirect/Service/Properties/AssemblyInfo.cs b/wcf/samples/Channel/WCFToWCFDirect/Service/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..2b75210ce3
--- /dev/null
+++ b/wcf/samples/Channel/WCFToWCFDirect/Service/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Service")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("MSIT")]
+[assembly: AssemblyProduct("Service")]
+[assembly: AssemblyCopyright("Copyright © MSIT 2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("5447546e-8547-4b0c-981a-1757ab8d9ec5")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/wcf/samples/Channel/WCFToWCFDirect/Service/Service.cs b/wcf/samples/Channel/WCFToWCFDirect/Service/Service.cs
new file mode 100644
index 0000000000..0342097ed9
--- /dev/null
+++ b/wcf/samples/Channel/WCFToWCFDirect/Service/Service.cs
@@ -0,0 +1,83 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+
+namespace Apache.Qpid.Samples.Channel.WCFToWCFDirect
+{
+ using System;
+ using System.ServiceModel;
+ using System.ServiceModel.Description;
+ using Apache.Qpid.Channel;
+
+ // Define a service contract.
+ [ServiceContract]
+ public interface IHelloService
+ {
+ [OperationContract(IsOneWay = true, Action="*")]
+ void SayHello(string name);
+ }
+
+ // Service class which implements the service contract.
+ [ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]
+ public class HelloService : IHelloService
+ {
+ [OperationBehavior]
+ public void SayHello(string name)
+ {
+ Console.WriteLine("Hello " + name);
+ }
+ }
+
+ class Service
+ {
+ static void Main(string[] args)
+ {
+ // Create binding for the service endpoint.
+ AmqpBinding amqpBinding = new AmqpBinding();
+
+ // Create ServiceHost.
+ ServiceHost serviceHost = new ServiceHost(typeof(HelloService), new Uri[] { new Uri("http://localhost:8080/HelloService") });
+
+ // Add behavior for our MEX endpoint.
+ ServiceMetadataBehavior mexBehavior = new ServiceMetadataBehavior();
+ mexBehavior.HttpGetEnabled = true;
+ serviceHost.Description.Behaviors.Add(mexBehavior);
+
+ // Add MEX endpoint.
+ serviceHost.AddServiceEndpoint(typeof(IMetadataExchange), new BasicHttpBinding(), "MEX");
+
+ // Add AMQP endpoint.
+ Uri amqpUri = new Uri("amqp:message_queue");
+ serviceHost.AddServiceEndpoint(typeof(IHelloService), amqpBinding, amqpUri.ToString());
+
+ serviceHost.Open();
+
+ Console.WriteLine();
+ Console.WriteLine("The service is ready.");
+ Console.WriteLine("Press <ENTER> to terminate service.");
+ Console.WriteLine();
+ Console.ReadLine();
+
+ if (serviceHost.State != CommunicationState.Faulted)
+ {
+ serviceHost.Close();
+ }
+ }
+ }
+}
diff --git a/wcf/samples/Channel/WCFToWCFDirect/Service/Service.csproj b/wcf/samples/Channel/WCFToWCFDirect/Service/Service.csproj
new file mode 100644
index 0000000000..3252380c98
--- /dev/null
+++ b/wcf/samples/Channel/WCFToWCFDirect/Service/Service.csproj
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{D0A46136-B4E3-4C50-AB6D-FB2BC6683D6E}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Service</RootNamespace>
+ <AssemblyName>Service</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Apache.Qpid.Channel, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\Apache.Qpid.Channel.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Messaging" />
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Service.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/wcf/samples/Channel/WCFToWCFDirect/WCFToWCFDirect.sln b/wcf/samples/Channel/WCFToWCFDirect/WCFToWCFDirect.sln
new file mode 100644
index 0000000000..6f30a5e053
--- /dev/null
+++ b/wcf/samples/Channel/WCFToWCFDirect/WCFToWCFDirect.sln
@@ -0,0 +1,46 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License
+#
+
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client", "Client\Client.csproj", "{0CCD5711-2072-47B8-B902-07EC12C04159}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Service", "Service\Service.csproj", "{D0A46136-B4E3-4C50-AB6D-FB2BC6683D6E}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0CCD5711-2072-47B8-B902-07EC12C04159}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0CCD5711-2072-47B8-B902-07EC12C04159}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0CCD5711-2072-47B8-B902-07EC12C04159}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0CCD5711-2072-47B8-B902-07EC12C04159}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D0A46136-B4E3-4C50-AB6D-FB2BC6683D6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D0A46136-B4E3-4C50-AB6D-FB2BC6683D6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D0A46136-B4E3-4C50-AB6D-FB2BC6683D6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D0A46136-B4E3-4C50-AB6D-FB2BC6683D6E}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Another_Topic_Consumer.cs b/wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Another_Topic_Consumer.cs
new file mode 100644
index 0000000000..c1e3ebbc88
--- /dev/null
+++ b/wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Another_Topic_Consumer.cs
@@ -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.
+*/
+
+
+namespace Apache.Qpid.Samples.Channel.WCFToWCFPubSub
+{
+ using System;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.ServiceModel.Description;
+ using Apache.Qpid.Channel;
+
+ class Another_Topic_Consumer
+ {
+ static void Main(string[] args)
+ {
+ // Create binding for the service endpoint.
+ CustomBinding amqpBinding = new CustomBinding();
+ amqpBinding.Elements.Add(new BinaryMessageEncodingBindingElement());
+ amqpBinding.Elements.Add(new AmqpTransportBindingElement());
+
+ // Create ServiceHost.
+ ServiceHost serviceHost = new ServiceHost(typeof(HelloService), new Uri[] { new Uri("http://localhost:8080/HelloService2") });
+
+ // Add behavior for our MEX endpoint.
+ ServiceMetadataBehavior mexBehavior = new ServiceMetadataBehavior();
+ mexBehavior.HttpGetEnabled = true;
+ serviceHost.Description.Behaviors.Add(mexBehavior);
+
+ // Add MEX endpoint.
+ serviceHost.AddServiceEndpoint(typeof(IMetadataExchange), new BasicHttpBinding(), "MEX");
+
+ // Add AMQP endpoint.
+ Uri amqpUri = new Uri("amqp:news");
+ serviceHost.AddServiceEndpoint(typeof(IHelloService), amqpBinding, amqpUri.ToString());
+
+ serviceHost.Open();
+
+ Console.WriteLine();
+ Console.WriteLine("The consumer is now listening on the queue \"news\".");
+ Console.WriteLine("Press <ENTER> to terminate service.");
+ Console.WriteLine();
+ Console.ReadLine();
+
+ if (serviceHost.State != CommunicationState.Faulted)
+ {
+ serviceHost.Close();
+ }
+ }
+ }
+}
diff --git a/wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Another_Topic_Consumer.csproj b/wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Another_Topic_Consumer.csproj
new file mode 100644
index 0000000000..47769e086d
--- /dev/null
+++ b/wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Another_Topic_Consumer.csproj
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{6AC32E9D-EFB2-4DEF-81D7-F70A0D7A606F}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Another_Topic_Consumer</RootNamespace>
+ <AssemblyName>Another_Topic_Consumer</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Apache.Qpid.Channel, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\Apache.Qpid.Channel.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Another_Topic_Consumer.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Topic_Consumer\Topic_Consumer.csproj">
+ <Project>{248A3A0B-FDC4-4E70-8428-BE0AF5AB021B}</Project>
+ <Name>Topic_Consumer</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Properties/AssemblyInfo.cs b/wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..8c22cb6d1f
--- /dev/null
+++ b/wcf/samples/Channel/WCFToWCFPubSub/Another_Topic_Consumer/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Another_Topic_Consumer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("MSIT")]
+[assembly: AssemblyProduct("Another_Topic_Consumer")]
+[assembly: AssemblyCopyright("Copyright © MSIT 2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("ba584c88-26a8-4910-a9a1-b4632b9adf01")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Properties/AssemblyInfo.cs b/wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..19fea85618
--- /dev/null
+++ b/wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Topic_Consumer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("MSIT")]
+[assembly: AssemblyProduct("Topic_Consumer")]
+[assembly: AssemblyCopyright("Copyright © MSIT 2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("3facd6d1-f604-4ac9-ace3-7b7acff471eb")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Topic_Consumer.cs b/wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Topic_Consumer.cs
new file mode 100644
index 0000000000..c4dd1e2256
--- /dev/null
+++ b/wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Topic_Consumer.cs
@@ -0,0 +1,85 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+
+namespace Apache.Qpid.Samples.Channel.WCFToWCFPubSub
+{
+ using System;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.ServiceModel.Description;
+ using Apache.Qpid.Channel;
+
+ // Define a service contract.
+ [ServiceContract]
+ public interface IHelloService
+ {
+ [OperationContract(IsOneWay = true)]
+ void SayHello(string name);
+ }
+
+ // Service class which implements the service contract.
+ public class HelloService : IHelloService
+ {
+ [OperationBehavior]
+ public void SayHello(string name)
+ {
+ Console.WriteLine("Hello " + name);
+ }
+ }
+
+ class Consumer
+ {
+ static void Main(string[] args)
+ {
+ // Create binding for the service endpoint.
+ CustomBinding amqpBinding = new CustomBinding();
+ amqpBinding.Elements.Add(new BinaryMessageEncodingBindingElement());
+ amqpBinding.Elements.Add(new AmqpTransportBindingElement());
+
+ // Create ServiceHost.
+ ServiceHost serviceHost = new ServiceHost(typeof(HelloService), new Uri[] { new Uri("http://localhost:8080/HelloService1") });
+
+ // Add behavior for our MEX endpoint.
+ ServiceMetadataBehavior mexBehavior = new ServiceMetadataBehavior();
+ mexBehavior.HttpGetEnabled = true;
+ serviceHost.Description.Behaviors.Add(mexBehavior);
+
+ // Add MEX endpoint.
+ serviceHost.AddServiceEndpoint(typeof(IMetadataExchange), new BasicHttpBinding(), "MEX");
+
+ // Add AMQP endpoint.
+ Uri amqpUri = new Uri("amqp:usa");
+ serviceHost.AddServiceEndpoint(typeof(IHelloService), amqpBinding, amqpUri.ToString());
+
+ serviceHost.Open();
+
+ Console.WriteLine();
+ Console.WriteLine("The consumer is now listening on the queue \"usa\".");
+ Console.WriteLine("Press <ENTER> to terminate service.");
+ Console.WriteLine();
+ Console.ReadLine();
+
+ if (serviceHost.State != CommunicationState.Faulted)
+ {
+ serviceHost.Close();
+ }
+ }
+ }
+}
diff --git a/wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Topic_Consumer.csproj b/wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Topic_Consumer.csproj
new file mode 100644
index 0000000000..b2151c0631
--- /dev/null
+++ b/wcf/samples/Channel/WCFToWCFPubSub/Topic_Consumer/Topic_Consumer.csproj
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{248A3A0B-FDC4-4E70-8428-BE0AF5AB021B}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Topic_Consumer</RootNamespace>
+ <AssemblyName>Topic_Consumer</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Apache.Qpid.Channel, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\Apache.Qpid.Channel.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Topic_Consumer.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Properties/AssemblyInfo.cs b/wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..87310bf92a
--- /dev/null
+++ b/wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Topic_Producer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("MSIT")]
+[assembly: AssemblyProduct("Topic_Producer")]
+[assembly: AssemblyCopyright("Copyright © MSIT 2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("a70e852d-a510-4e00-af72-68bb8547696f")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Topic_Producer.cs b/wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Topic_Producer.cs
new file mode 100644
index 0000000000..e3850eb4c0
--- /dev/null
+++ b/wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Topic_Producer.cs
@@ -0,0 +1,68 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+
+namespace Apache.Qpid.Samples.Channel.WCFToWCFPubSub
+{
+ using System;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using Apache.Qpid.Channel;
+
+ class Topic_Producer
+ {
+ static void Main(string[] args)
+ {
+ try
+ {
+ // Create binding for the service endpoint.
+ CustomBinding amqpBinding = new CustomBinding();
+ amqpBinding.Elements.Add(new BinaryMessageEncodingBindingElement());
+ amqpBinding.Elements.Add(new AmqpTransportBindingElement());
+
+ // Create endpoint address.
+ Uri amqpClientUri = new Uri("amqp:amq.topic?routingkey=usa.news");
+ EndpointAddress endpointAddress = new EndpointAddress(amqpClientUri);
+
+ // Create a client with given client endpoint configuration.
+ ChannelFactory<IHelloService> channelFactory = new ChannelFactory<IHelloService>(amqpBinding, endpointAddress);
+ IHelloService clientProxy = channelFactory.CreateChannel();
+
+ Console.WriteLine();
+
+ string name = "name";
+ for (int i = 0; i < 5; i++)
+ {
+ Console.WriteLine("Sending message: " + name + (i + 1));
+ clientProxy.SayHello(name + (i+1));
+ }
+
+ Console.WriteLine();
+ Console.WriteLine("Press <ENTER> to terminate client.");
+ Console.ReadLine();
+
+ channelFactory.Close();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Exception: {0}", e);
+ }
+ }
+ }
+}
diff --git a/wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Topic_Producer.csproj b/wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Topic_Producer.csproj
new file mode 100644
index 0000000000..b4318ead3f
--- /dev/null
+++ b/wcf/samples/Channel/WCFToWCFPubSub/Topic_Producer/Topic_Producer.csproj
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{67B413EF-3B9C-4988-87DE-0386C209D368}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Topic_Producer</RootNamespace>
+ <AssemblyName>Topic_Producer</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Apache.Qpid.Channel, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\Apache.Qpid.Channel.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Topic_Producer.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Topic_Consumer\Topic_Consumer.csproj">
+ <Project>{248A3A0B-FDC4-4E70-8428-BE0AF5AB021B}</Project>
+ <Name>Topic_Consumer</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/wcf/samples/Channel/WCFToWCFPubSub/WCFToWCFPubSub.sln b/wcf/samples/Channel/WCFToWCFPubSub/WCFToWCFPubSub.sln
new file mode 100644
index 0000000000..d8a56ea8db
--- /dev/null
+++ b/wcf/samples/Channel/WCFToWCFPubSub/WCFToWCFPubSub.sln
@@ -0,0 +1,52 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License
+#
+
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Topic_Consumer", "Topic_Consumer\Topic_Consumer.csproj", "{248A3A0B-FDC4-4E70-8428-BE0AF5AB021B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Topic_Producer", "Topic_Producer\Topic_Producer.csproj", "{67B413EF-3B9C-4988-87DE-0386C209D368}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Another_Topic_Consumer", "Another_Topic_Consumer\Another_Topic_Consumer.csproj", "{6AC32E9D-EFB2-4DEF-81D7-F70A0D7A606F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {248A3A0B-FDC4-4E70-8428-BE0AF5AB021B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {248A3A0B-FDC4-4E70-8428-BE0AF5AB021B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {248A3A0B-FDC4-4E70-8428-BE0AF5AB021B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {248A3A0B-FDC4-4E70-8428-BE0AF5AB021B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {67B413EF-3B9C-4988-87DE-0386C209D368}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {67B413EF-3B9C-4988-87DE-0386C209D368}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {67B413EF-3B9C-4988-87DE-0386C209D368}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {67B413EF-3B9C-4988-87DE-0386C209D368}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6AC32E9D-EFB2-4DEF-81D7-F70A0D7A606F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6AC32E9D-EFB2-4DEF-81D7-F70A0D7A606F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6AC32E9D-EFB2-4DEF-81D7-F70A0D7A606F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6AC32E9D-EFB2-4DEF-81D7-F70A0D7A606F}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/wcf/src/Apache/Qpid/AmqpTypes/AmqpBoolean.cs b/wcf/src/Apache/Qpid/AmqpTypes/AmqpBoolean.cs
new file mode 100644
index 0000000000..980ae78361
--- /dev/null
+++ b/wcf/src/Apache/Qpid/AmqpTypes/AmqpBoolean.cs
@@ -0,0 +1,57 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.AmqpTypes
+{
+ using System;
+ using System.IO;
+ using System.Collections.Generic;
+ using System.Text;
+
+ public class AmqpBoolean : AmqpType
+ {
+ bool value;
+
+ public AmqpBoolean(bool i)
+ {
+ this.value = i;
+ }
+
+ public override void Encode(byte[] bufer, int offset, int count)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override int EncodedSize
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override AmqpType Clone()
+ {
+ return new AmqpBoolean(this.value);
+ }
+
+ public bool Value
+ {
+ get { return this.value; }
+ set { this.value = value; }
+ }
+ }
+}
diff --git a/wcf/src/Apache/Qpid/AmqpTypes/AmqpInt.cs b/wcf/src/Apache/Qpid/AmqpTypes/AmqpInt.cs
new file mode 100644
index 0000000000..c114e98a71
--- /dev/null
+++ b/wcf/src/Apache/Qpid/AmqpTypes/AmqpInt.cs
@@ -0,0 +1,57 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.AmqpTypes
+{
+ using System;
+ using System.IO;
+ using System.Collections.Generic;
+ using System.Text;
+
+ public class AmqpInt : AmqpType
+ {
+ int value;
+
+ public AmqpInt(int i)
+ {
+ this.value = i;
+ }
+
+ public override void Encode(byte[] bufer, int offset, int count)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override int EncodedSize
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override AmqpType Clone()
+ {
+ return new AmqpInt(this.value);
+ }
+
+ public int Value
+ {
+ get { return this.value; }
+ set { this.value = value; }
+ }
+ }
+}
diff --git a/wcf/src/Apache/Qpid/AmqpTypes/AmqpProperties.cs b/wcf/src/Apache/Qpid/AmqpTypes/AmqpProperties.cs
new file mode 100644
index 0000000000..0f649dcd36
--- /dev/null
+++ b/wcf/src/Apache/Qpid/AmqpTypes/AmqpProperties.cs
@@ -0,0 +1,292 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.AmqpTypes
+{
+ using System;
+ using System.IO;
+ using System.Collections.Generic;
+ using System.Text;
+
+ public class AmqpProperties
+ {
+ // AMQP 0-10 delivery properties
+ private bool durable;
+ private Nullable<TimeSpan> timeToLive;
+ private string routingKey;
+
+ // AMQP 0-10 message properties
+ private string replyToExchange;
+ private string replyToRoutingKey;
+ private byte[] userId;
+ private byte[] correlationId;
+ private string contentType;
+
+ // for application and vendor properties
+ Dictionary<String, AmqpType> propertyMap;
+
+ public AmqpProperties()
+ {
+ }
+
+ // AMQP 0-10 "message.delivery-properties
+ internal bool HasDeliveryProperties
+ {
+ get
+ {
+ return ((this.routingKey != null) || this.durable || this.timeToLive.HasValue);
+ }
+ }
+
+ internal bool HasMappedProperties
+ {
+ get
+ {
+ if (this.propertyMap != null)
+ {
+ if (this.propertyMap.Count > 0)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+
+ // AMQP 0-10 "message.message-properties"
+ internal bool HasMessageProperties
+ {
+ get
+ {
+ if ((this.replyToExchange != null) ||
+ (this.replyToRoutingKey != null) ||
+ (this.userId != null) ||
+ (this.correlationId != null) ||
+ (this.contentType != null))
+ {
+ return true;
+ }
+
+ if (this.propertyMap == null)
+ {
+ return false;
+ }
+
+ return (this.propertyMap.Count != 0);
+ }
+ }
+
+ public Dictionary<String, AmqpType> PropertyMap
+ {
+ get
+ {
+ if (this.propertyMap == null)
+ {
+ this.propertyMap = new Dictionary<string, AmqpType>();
+ }
+ return propertyMap;
+ }
+ set { this.propertyMap = value; }
+ }
+
+ internal bool Empty
+ {
+ get
+ {
+ if (this.HasDeliveryProperties || this.HasMessageProperties)
+ {
+ return true;
+ }
+ return false;
+ }
+ }
+
+ public string ContentType
+ {
+ get { return contentType; }
+ // TODO: validate
+ set { contentType = value; }
+ }
+
+ public byte[] CorrelationId
+ {
+ get { return correlationId; }
+ set
+ {
+ if (value != null)
+ {
+ if (value.Length > 65535)
+ {
+ throw new ArgumentException("CorrelationId too big");
+ }
+ }
+ correlationId = value;
+ }
+ }
+
+ public byte[] UserId
+ {
+ get { return userId; }
+ set
+ {
+ if (value != null)
+ {
+ if (value.Length > 65535)
+ {
+ throw new ArgumentException("UserId too big");
+ }
+ }
+ userId = value;
+ }
+ }
+
+ public TimeSpan? TimeToLive
+ {
+ get { return this.timeToLive; }
+ set { this.timeToLive = value; }
+ }
+
+ public string RoutingKey
+ {
+ get { return this.routingKey; }
+ set { this.routingKey = value; }
+ }
+
+ public string ReplyToExchange
+ {
+ get { return this.replyToExchange; }
+ }
+
+ public string ReplyToRoutingKey
+ {
+ get { return this.replyToRoutingKey; }
+ }
+
+ // this changes from 0-10 to 1.0
+ public void SetReplyTo(string exchange, string routingKey)
+ {
+ if ((exchange == null && routingKey == null))
+ {
+ throw new ArgumentNullException("SetReplyTo");
+ }
+
+ this.replyToExchange = exchange;
+ this.replyToRoutingKey = routingKey;
+ }
+
+ public bool Durable
+ {
+ get { return durable; }
+ set { durable = value; }
+ }
+
+ public void Clear()
+ {
+ this.timeToLive = null;
+ this.routingKey = null;
+ this.replyToRoutingKey = null;
+ this.replyToExchange = null;
+ this.durable = false;
+ this.contentType = null;
+ this.userId = null;
+ this.correlationId = null;
+ this.propertyMap = null;
+ }
+
+ public AmqpProperties Clone()
+ {
+ // memberwise clone ok for string, byte[], and value types
+ AmqpProperties clonedProps = (AmqpProperties)this.MemberwiseClone();
+
+ // deeper copy for the dictionary
+ if (this.propertyMap != null)
+ {
+ if (this.propertyMap.Count > 0)
+ {
+ Dictionary<string, AmqpType> clonedDictionary = new Dictionary<string, AmqpType>(this.propertyMap.Count);
+ foreach (KeyValuePair<string, AmqpType> original in this.propertyMap)
+ {
+ clonedDictionary.Add(original.Key, original.Value.Clone());
+ }
+
+ clonedProps.propertyMap = clonedDictionary;
+ }
+ else
+ {
+ clonedProps.propertyMap = null;
+ }
+ }
+ return clonedProps;
+ }
+
+ // adds/replaces from the other AmqpProperty object.
+ // just inserts references, i.e. provides shallow copy semantics (see Clone for deep copy)
+ public void MergeFrom(AmqpProperties other)
+ {
+ if (other.timeToLive.HasValue)
+ {
+ this.timeToLive = other.timeToLive;
+ }
+
+ if ((other.replyToRoutingKey != null) || (other.replyToExchange != null))
+ {
+ this.replyToExchange = other.replyToExchange;
+ this.replyToRoutingKey = other.replyToRoutingKey;
+ }
+
+ if (other.routingKey != null)
+ {
+ this.routingKey = other.routingKey;
+ }
+
+ if (other.durable)
+ {
+ this.durable = true;
+ }
+
+ if (other.contentType != null)
+ {
+ this.contentType = other.contentType;
+ }
+
+ if (other.correlationId != null)
+ {
+ this.correlationId = other.correlationId;
+ }
+
+ if (other.userId != null)
+ {
+ this.userId = other.userId;
+ }
+
+ if (other.propertyMap != null)
+ {
+ if (other.propertyMap.Count > 0)
+ {
+ Dictionary<string, AmqpType> thisMap = this.PropertyMap;
+ foreach (KeyValuePair<string, AmqpType> kvp in other.propertyMap)
+ {
+ thisMap[kvp.Key] = kvp.Value;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/wcf/src/Apache/Qpid/AmqpTypes/AmqpString.cs b/wcf/src/Apache/Qpid/AmqpTypes/AmqpString.cs
new file mode 100644
index 0000000000..87cebe878c
--- /dev/null
+++ b/wcf/src/Apache/Qpid/AmqpTypes/AmqpString.cs
@@ -0,0 +1,91 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.AmqpTypes
+{
+ using System;
+ using System.IO;
+ using System.Collections.Generic;
+ using System.Text;
+
+ // for big strings: str16 in 0-10 and str32 in 1.0
+
+ public class AmqpString : AmqpType
+ {
+ string value;
+ Encoding encoding;
+
+ public AmqpString(string s)
+ {
+ this.value = s;
+ this.encoding = Encoding.UTF8;
+ }
+
+ public AmqpString(string s, Encoding enc)
+ {
+ ValidateEncoding(enc);
+ this.value = s;
+ this.encoding = enc;
+ }
+
+ public Encoding Encoding
+ {
+ get { return encoding; }
+ set
+ {
+ ValidateEncoding(value);
+ encoding = value;
+ }
+ }
+
+ private void ValidateEncoding(Encoding enc)
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("Encoding");
+ }
+
+ if ((enc != Encoding.UTF8) && (enc != Encoding.Unicode))
+ {
+ throw new ArgumentException("Encoding not one of UTF8 or Unicode");
+ }
+ }
+
+ public override void Encode(byte[] bufer, int offset, int count)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override int EncodedSize
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override AmqpType Clone()
+ {
+ return new AmqpString(this.value);
+ }
+
+ public string Value
+ {
+ get { return this.value; }
+ set { this.value = value; }
+ }
+ }
+}
diff --git a/wcf/src/Apache/Qpid/AmqpTypes/AmqpType.cs b/wcf/src/Apache/Qpid/AmqpTypes/AmqpType.cs
new file mode 100644
index 0000000000..8cd3ac9e4a
--- /dev/null
+++ b/wcf/src/Apache/Qpid/AmqpTypes/AmqpType.cs
@@ -0,0 +1,33 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.AmqpTypes
+{
+ using System;
+ using System.IO;
+ using System.Collections.Generic;
+ using System.Text;
+
+ public abstract class AmqpType
+ {
+ public abstract void Encode(byte[] bufer, int offset, int count);
+ public abstract int EncodedSize { get; }
+ public abstract AmqpType Clone();
+ }
+}
diff --git a/wcf/src/Apache/Qpid/AmqpTypes/AmqpTypes.csproj b/wcf/src/Apache/Qpid/AmqpTypes/AmqpTypes.csproj
new file mode 100644
index 0000000000..2a544cf6d0
--- /dev/null
+++ b/wcf/src/Apache/Qpid/AmqpTypes/AmqpTypes.csproj
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{820BFC34-A40F-46BA-B86B-05334854CA17}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Apache.Qpid.AmqpTypes</RootNamespace>
+ <AssemblyName>Apache.Qpid.AmqpTypes</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
+ <SignAssembly>true</SignAssembly>
+ <AssemblyOriginatorKeyFile>..\..\..\wcfnet.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="AmqpBoolean.cs" />
+ <Compile Include="AmqpInt.cs" />
+ <Compile Include="AmqpProperties.cs" />
+ <Compile Include="AmqpString.cs" />
+ <Compile Include="AmqpType.cs" />
+ <Compile Include="AmqpUbyte.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="PropertyName.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\..\wcfnet.snk" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+<Message Text="yet another debug line" />
+ </Target>
+ <Target Name="AfterBuild"
+ >
+<Message Text="a debug line before banana.netmodule" />
+ <PropertyGroup Condition="('$(TargetFrameworkVersion)' != 'v1.0') and ('$(TargetFrameworkVersion)' != 'v1.1')">
+ <NoWarn>$(NoWarn);1701;1702</NoWarn>
+ </PropertyGroup>
+
+ <Csc
+ AdditionalLibPaths="$(AdditionalLibPaths)"
+ AddModules="@(AddModules)"
+ AllowUnsafeBlocks="$(AllowUnsafeBlocks)"
+ BaseAddress="$(BaseAddress)"
+ CheckForOverflowUnderflow="$(CheckForOverflowUnderflow)"
+ CodePage="$(CodePage)"
+ DebugType="$(DebugType)"
+ DefineConstants="$(DefineConstants)"
+ DelaySign="$(DelaySign)"
+ DisabledWarnings="$(NoWarn)"
+ DocumentationFile="@(DocFileItem)"
+ EmitDebugInformation="$(DebugSymbols)"
+ ErrorReport="$(ErrorReport)"
+ FileAlignment="$(FileAlignment)"
+ GenerateFullPaths="$(GenerateFullPaths)"
+ KeyContainer="$(KeyContainerName)"
+ KeyFile="$(KeyOriginatorFile)"
+ LangVersion="$(LangVersion)"
+ MainEntryPoint="$(StartupObject)"
+ ModuleAssemblyName="banana"
+ NoConfig="true"
+ NoLogo="$(NoLogo)"
+ NoStandardLib="$(NoStdLib)"
+ NoWin32Manifest="$(NoWin32Manifest)"
+ Optimize="$(Optimize)"
+ OutputAssembly="@(IntermediateAssembly)"
+ PdbFile="$(PdbFile)"
+ Platform="$(PlatformTarget)"
+ References="@(ReferencePath)"
+ Resources="@(_CoreCompileResourceInputs);@(CompiledLicenseFile)"
+ ResponseFiles="$(CompilerResponseFile)"
+ Sources="@(Compile)"
+ TargetType="module"
+ ToolExe="$(CscToolExe)"
+ ToolPath="$(CscToolPath)"
+ TreatWarningsAsErrors="$(TreatWarningsAsErrors)"
+ UseHostCompilerIfAvailable="$(UseHostCompilerIfAvailable)"
+ Utf8Output="$(Utf8Output)"
+ WarningLevel="$(WarningLevel)"
+ WarningsAsErrors="$(WarningsAsErrors)"
+ WarningsNotAsErrors="$(WarningsNotAsErrors)"
+ Win32Icon="$(ApplicationIcon)"
+ Win32Manifest="$(Win32Manifest)"
+ Win32Resource="$(Win32Resource)"
+ />
+
+ <ItemGroup>
+ <_CoreCompileResourceInputs Remove="@(_CoreCompileResourceInputs)" />
+ </ItemGroup>
+
+<Message Text="a debug line after banana.netmodule" />
+ </Target>
+ -->
+ <PropertyGroup>
+ <PostBuildEvent>cd "$(ProjectDir)bin\$(ConfigurationName)"
+del $(AssemblyName).dll
+del $(AssemblyName).pdb
+cd "$(ProjectDir)obj\$(ConfigurationName)"
+del $(AssemblyName).dll
+del $(AssemblyName).pdb
+cd "$(ProjectDir)"
+CreateNetModule.bat $(ConfigurationName)</PostBuildEvent>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/wcf/src/Apache/Qpid/AmqpTypes/AmqpUbyte.cs b/wcf/src/Apache/Qpid/AmqpTypes/AmqpUbyte.cs
new file mode 100644
index 0000000000..5ec8a732cf
--- /dev/null
+++ b/wcf/src/Apache/Qpid/AmqpTypes/AmqpUbyte.cs
@@ -0,0 +1,57 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.AmqpTypes
+{
+ using System;
+ using System.IO;
+ using System.Collections.Generic;
+ using System.Text;
+
+ public class AmqpUbyte : AmqpType
+ {
+ byte value;
+
+ public AmqpUbyte(byte i)
+ {
+ this.value = i;
+ }
+
+ public override void Encode(byte[] bufer, int offset, int count)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override int EncodedSize
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override AmqpType Clone()
+ {
+ return new AmqpUbyte(this.value);
+ }
+
+ public byte Value
+ {
+ get { return this.value; }
+ set { this.value = value; }
+ }
+ }
+}
diff --git a/wcf/src/Apache/Qpid/AmqpTypes/CreateNetModule.bat b/wcf/src/Apache/Qpid/AmqpTypes/CreateNetModule.bat
new file mode 100755
index 0000000000..d67e2119f9
--- /dev/null
+++ b/wcf/src/Apache/Qpid/AmqpTypes/CreateNetModule.bat
@@ -0,0 +1,33 @@
+
+REM Licensed to the Apache Software Foundation (ASF) under one
+REM or more contributor license agreements. See the NOTICE file
+REM distributed with this work for additional information
+REM regarding copyright ownership. The ASF licenses this file
+REM to you under the Apache License, Version 2.0 (the
+REM "License"); you may not use this file except in compliance
+REM with the License. You may obtain a copy of the License at
+REM
+REM http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM Unless required by applicable law or agreed to in writing,
+REM software distributed under the License is distributed on an
+REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+REM KIND, either express or implied. See the License for the
+REM specific language governing permissions and limitations
+REM under the License.
+
+if %1 == Release goto release
+
+echo generating Debug netmodule
+
+%systemroot%\Microsoft.NET\Framework\v3.5\Csc.exe /noconfig /nowarn:1701,1702 /errorreport:prompt /warn:4 /define:DEBUG;TRACE /reference:"%programfiles%\Reference Assemblies\Microsoft\Framework\v3.5\System.Core.dll" /reference:"%programfiles%\Reference Assemblies\Microsoft\Framework\v3.5\System.Data.DataSetExtensions.dll" /reference:%systemroot%\Microsoft.NET\Framework\v2.0.50727\System.Data.dll /reference:%systemroot%\Microsoft.NET\Framework\v2.0.50727\System.dll /reference:%systemroot%\Microsoft.NET\Framework\v2.0.50727\System.Xml.dll /reference:"%programfiles%\Reference Assemblies\Microsoft\Framework\v3.5\System.Xml.Linq.dll" /debug+ /debug:full /filealign:512 /optimize- /out:obj\Debug\Apache.Qpid.AmqpTypes.netmodule /target:module *.cs
+
+goto end
+
+:release
+
+echo generating Release netmodule
+
+%systemroot%\Microsoft.NET\Framework\v3.5\Csc.exe /noconfig /nowarn:1701,1702 /errorreport:prompt /warn:4 /define:TRACE /reference:"%programfiles%\Reference Assemblies\Microsoft\Framework\v3.5\System.Core.dll" /reference:"%programfiles%\Reference Assemblies\Microsoft\Framework\v3.5\System.Data.DataSetExtensions.dll" /reference:C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Data.dll /reference:C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.dll /reference:C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Xml.dll /reference:"%programfiles%\Reference Assemblies\Microsoft\Framework\v3.5\System.Xml.Linq.dll" /debug:pdbonly /filealign:512 /keyfile:..\..\..\wcfnet.snk /optimize+ /out:obj\Release\Apache.Qpid.AmqpTypes.netmodule /target:module *.cs
+
+:end \ No newline at end of file
diff --git a/wcf/src/Apache/Qpid/AmqpTypes/Properties/AssemblyInfo.cs b/wcf/src/Apache/Qpid/AmqpTypes/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..dffaee0d0d
--- /dev/null
+++ b/wcf/src/Apache/Qpid/AmqpTypes/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Apache.Qpid.AmqpTypes")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to true makes the types in this assembly visible
+// to COM components. This is required for this to be used by an
+// Excel RTD component.
+[assembly: ComVisible(true)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("79b8b5d9-047d-4f3b-8610-7fe112ce6416")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/wcf/src/Apache/Qpid/AmqpTypes/PropertyName.cs b/wcf/src/Apache/Qpid/AmqpTypes/PropertyName.cs
new file mode 100644
index 0000000000..b80f8b9e9e
--- /dev/null
+++ b/wcf/src/Apache/Qpid/AmqpTypes/PropertyName.cs
@@ -0,0 +1,35 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.AmqpTypes
+{
+ using System;
+ using System.IO;
+ using System.Collections.Generic;
+ using System.Text;
+
+ public sealed class PropertyName
+ {
+ public const string Priority = "amqpx.priority";
+ public const string ContentType = "amqp.content-type";
+ public const string ReplyTo = "amqp.reply-to";
+ public const string ReplyToExchange = "amqpx.qpid0-10.reply-to-exchange";
+ public const string RoutingKey = "amqpx.qpid0-10.routing-key";
+ }
+}
diff --git a/wcf/src/Apache/Qpid/Channel/AmqpBinaryBinding.cs b/wcf/src/Apache/Qpid/Channel/AmqpBinaryBinding.cs
new file mode 100644
index 0000000000..e207f2fe45
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Channel/AmqpBinaryBinding.cs
@@ -0,0 +1,60 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+ using System.Configuration;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.ServiceModel.Configuration;
+
+ using Apache.Qpid.AmqpTypes;
+
+ public class AmqpBinaryBinding : AmqpBinding
+ {
+ public AmqpBinaryBinding()
+: base (new RawMessageEncodingBindingElement())
+ {
+ }
+
+ public AmqpBinaryBinding(string configurationName)
+ : this()
+ {
+ ApplyConfiguration(configurationName);
+ }
+
+ private void ApplyConfiguration(string configurationName)
+ {
+ AmqpBinaryBindingCollectionElement section = (AmqpBinaryBindingCollectionElement)ConfigurationManager.GetSection(AmqpConstants.AmqpBinaryBindingSectionName);
+ AmqpBinaryBindingConfigurationElement element = section.Bindings[configurationName];
+ if (element == null)
+ {
+ throw new ConfigurationErrorsException(string.Format(System.Globalization.CultureInfo.CurrentCulture,
+ "There is no binding named {0} at {1}.", configurationName, section.BindingName));
+ }
+ else
+ {
+ element.ApplyConfiguration(this);
+ }
+ }
+ }
+}
diff --git a/wcf/src/Apache/Qpid/Channel/AmqpBinaryBindingCollectionElement.cs b/wcf/src/Apache/Qpid/Channel/AmqpBinaryBindingCollectionElement.cs
new file mode 100644
index 0000000000..de263bc4ef
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Channel/AmqpBinaryBindingCollectionElement.cs
@@ -0,0 +1,29 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ /// <summary>
+ /// Implement application configuration of bindingExtensions for AmqpBinaryBinding
+ /// </summary>
+ public class AmqpBinaryBindingCollectionElement
+ : System.ServiceModel.Configuration.StandardBindingCollectionElement<AmqpBinaryBinding, AmqpBinaryBindingConfigurationElement>
+ {
+ }
+}
diff --git a/wcf/src/Apache/Qpid/Channel/AmqpBinaryBindingConfigurationElement.cs b/wcf/src/Apache/Qpid/Channel/AmqpBinaryBindingConfigurationElement.cs
new file mode 100644
index 0000000000..a537a6c6c3
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Channel/AmqpBinaryBindingConfigurationElement.cs
@@ -0,0 +1,79 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+ using System.Configuration;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.ServiceModel.Configuration;
+ using Apache.Qpid.AmqpTypes;
+
+ public class AmqpBinaryBindingConfigurationElement : AmqpBindingConfigurationElement
+ {
+ public AmqpBinaryBindingConfigurationElement(string configurationName)
+ : base(configurationName)
+ {
+ }
+
+ public AmqpBinaryBindingConfigurationElement()
+ : this(null)
+ {
+ }
+
+ protected override Type BindingElementType
+ {
+ get { return typeof(AmqpBinaryBinding); }
+ }
+
+ protected override ConfigurationPropertyCollection Properties
+ {
+ get
+ {
+ ConfigurationPropertyCollection properties = base.Properties;
+
+ return properties;
+ }
+ }
+
+ protected override void InitializeFrom(Binding binding)
+ {
+ base.InitializeFrom(binding);
+ AmqpBinaryBinding amqpBinding = (AmqpBinaryBinding)binding;
+ }
+
+ protected override void OnApplyConfiguration(Binding binding)
+ {
+ if (binding == null)
+ throw new ArgumentNullException("binding");
+
+ if (binding.GetType() != typeof(AmqpBinaryBinding))
+ {
+ throw new ArgumentException(string.Format("Invalid type for configuring an AMQP binding. Expected type: {0}. Type passed in: {1}.",
+ typeof(AmqpBinaryBinding).AssemblyQualifiedName,
+ binding.GetType().AssemblyQualifiedName));
+ }
+
+ base.OnApplyConfiguration(binding);
+ }
+ }
+}
diff --git a/wcf/src/Apache/Qpid/Channel/AmqpBinding.cs b/wcf/src/Apache/Qpid/Channel/AmqpBinding.cs
new file mode 100644
index 0000000000..b0b71c87f3
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Channel/AmqpBinding.cs
@@ -0,0 +1,121 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+ using System.Configuration;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.ServiceModel.Configuration;
+
+ using Apache.Qpid.AmqpTypes;
+
+ public class AmqpBinding : Binding
+ {
+ protected AmqpTransportBindingElement transport;
+ protected MessageEncodingBindingElement encoding;
+
+ public AmqpBinding()
+ {
+ transport = new AmqpTransportBindingElement();
+ encoding = new BinaryMessageEncodingBindingElement();
+ }
+
+ protected AmqpBinding(MessageEncodingBindingElement encoding)
+ {
+ this.encoding = encoding;
+ transport = new AmqpTransportBindingElement();
+ }
+
+ public AmqpBinding(string configurationName)
+ : this()
+ {
+ ApplyConfiguration(configurationName);
+ }
+
+ public string BrokerHost
+ {
+ get { return transport.BrokerHost; }
+ set { transport.BrokerHost = value; }
+ }
+
+ public int BrokerPort
+ {
+ get { return transport.BrokerPort; }
+ set { transport.BrokerPort = value; }
+ }
+
+ public int PrefetchLimit
+ {
+ get { return transport.PrefetchLimit; }
+ set { transport.PrefetchLimit = value; }
+ }
+
+ public bool Shared
+ {
+ get { return transport.Shared; }
+ set { transport.Shared = value; }
+ }
+
+ public TransferMode TransferMode
+ {
+ get { return transport.TransferMode; }
+ set { transport.TransferMode = value; }
+ }
+
+ public AmqpProperties DefaultMessageProperties
+ {
+ get { return transport.DefaultMessageProperties; }
+ set { transport.DefaultMessageProperties = value; }
+ }
+
+ public override string Scheme
+ {
+ get { return AmqpConstants.Scheme; }
+ }
+
+ public override BindingElementCollection CreateBindingElements()
+ {
+ BindingElementCollection bindingElements = new BindingElementCollection();
+
+ bindingElements.Add(encoding);
+ bindingElements.Add(transport);
+
+ return bindingElements.Clone();
+ }
+
+ private void ApplyConfiguration(string configurationName)
+ {
+ AmqpBindingCollectionElement section = (AmqpBindingCollectionElement)ConfigurationManager.GetSection(AmqpConstants.AmqpBindingSectionName);
+ AmqpBindingConfigurationElement element = section.Bindings[configurationName];
+ if (element == null)
+ {
+ throw new ConfigurationErrorsException(string.Format(System.Globalization.CultureInfo.CurrentCulture,
+ "There is no binding named {0} at {1}.", configurationName, section.BindingName));
+ }
+ else
+ {
+ element.ApplyConfiguration(this);
+ }
+ }
+ }
+}
diff --git a/wcf/src/Apache/Qpid/Channel/AmqpBindingCollectionElement.cs b/wcf/src/Apache/Qpid/Channel/AmqpBindingCollectionElement.cs
new file mode 100644
index 0000000000..e8d3b6fad4
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Channel/AmqpBindingCollectionElement.cs
@@ -0,0 +1,29 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ /// <summary>
+ /// Implement application configuration of bindingExtensions for AmqpBinding
+ /// </summary>
+ public class AmqpBindingCollectionElement
+ : System.ServiceModel.Configuration.StandardBindingCollectionElement<AmqpBinding, AmqpBindingConfigurationElement>
+ {
+ }
+}
diff --git a/wcf/src/Apache/Qpid/Channel/AmqpBindingConfigurationElement.cs b/wcf/src/Apache/Qpid/Channel/AmqpBindingConfigurationElement.cs
new file mode 100644
index 0000000000..554824cea9
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Channel/AmqpBindingConfigurationElement.cs
@@ -0,0 +1,269 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+ using System.Configuration;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.ServiceModel.Configuration;
+ using Apache.Qpid.AmqpTypes;
+
+ public class AmqpBindingConfigurationElement : StandardBindingElement
+ {
+ // not regular config elements. See PostDeserialize
+ string brokerHost;
+ int brokerPort;
+
+ public AmqpBindingConfigurationElement(string configurationName)
+ : base(configurationName)
+ {
+ brokerHost = AmqpDefaults.BrokerHost;
+ brokerPort = AmqpDefaults.BrokerPort;
+ }
+
+ public AmqpBindingConfigurationElement()
+ : this(null)
+ {
+ }
+
+ protected override Type BindingElementType
+ {
+ get { return typeof(AmqpBinding); }
+ }
+
+ public string BrokerHost
+ {
+ get { return brokerHost; }
+ set { brokerHost = value; }
+ }
+
+ public int BrokerPort
+ {
+ get { return brokerPort; }
+ set { brokerPort = value; }
+ }
+
+ [ConfigurationProperty(AmqpConfigurationStrings.PrefetchLimit, DefaultValue = false)]
+ public int PrefetchLimit
+ {
+ get { return (int)base[AmqpConfigurationStrings.PrefetchLimit]; }
+ set { base[AmqpConfigurationStrings.PrefetchLimit] = value; }
+ }
+
+ [ConfigurationProperty(AmqpConfigurationStrings.Shared, DefaultValue = false)]
+ public bool Shared
+ {
+ get { return (bool)base[AmqpConfigurationStrings.Shared]; }
+ set { base[AmqpConfigurationStrings.Shared] = value; }
+ }
+
+ [ConfigurationProperty(AmqpConfigurationStrings.TransferMode, DefaultValue = AmqpDefaults.TransferMode)]
+ public TransferMode TransferMode
+ {
+ get { return (TransferMode)base[AmqpConfigurationStrings.TransferMode]; }
+ set { base[AmqpConfigurationStrings.TransferMode] = value; }
+ }
+
+ [ConfigurationProperty(AmqpConfigurationStrings.Brokers)]
+ public BrokerCollection Brokers
+ {
+ get
+ {
+ return (BrokerCollection)base[AmqpConfigurationStrings.Brokers];
+ }
+ set
+ {
+ base[AmqpConfigurationStrings.Brokers] = value;
+ }
+ }
+
+ protected override ConfigurationPropertyCollection Properties
+ {
+ get
+ {
+ ConfigurationPropertyCollection properties = base.Properties;
+ properties.Add(new ConfigurationProperty(AmqpConfigurationStrings.PrefetchLimit,
+ typeof(int), 0, null, null, ConfigurationPropertyOptions.None));
+ properties.Add(new ConfigurationProperty(AmqpConfigurationStrings.Shared,
+ typeof(bool), false, null, null, ConfigurationPropertyOptions.None));
+ properties.Add(new ConfigurationProperty(AmqpConfigurationStrings.TransferMode,
+ typeof(TransferMode), AmqpDefaults.TransferMode, null, null, ConfigurationPropertyOptions.None));
+ properties.Add(new ConfigurationProperty("brokers", typeof(BrokerCollection), null));
+ return properties;
+ }
+ }
+
+ protected override void InitializeFrom(Binding binding)
+ {
+ base.InitializeFrom(binding);
+ AmqpBinding amqpBinding = (AmqpBinding)binding;
+ this.BrokerHost = amqpBinding.BrokerHost;
+ this.BrokerPort = amqpBinding.BrokerPort;
+ this.TransferMode = amqpBinding.TransferMode;
+ this.Shared = amqpBinding.Shared;
+ this.PrefetchLimit = amqpBinding.PrefetchLimit;
+
+ AmqpProperties props = amqpBinding.DefaultMessageProperties;
+ }
+
+ protected override void OnApplyConfiguration(Binding binding)
+ {
+ if (binding == null)
+ throw new ArgumentNullException("binding");
+
+ if (!(binding is AmqpBinding))
+ {
+ throw new ArgumentException(string.Format("Invalid type for configuring an AMQP binding. Expected type: {0}. Type passed in: {1}.",
+ typeof(AmqpBinding).AssemblyQualifiedName,
+ binding.GetType().AssemblyQualifiedName));
+ }
+
+ AmqpBinding amqpBinding = (AmqpBinding)binding;
+ amqpBinding.BrokerHost = this.BrokerHost;
+ amqpBinding.BrokerPort = this.BrokerPort;
+ amqpBinding.TransferMode = this.TransferMode;
+ amqpBinding.Shared = this.Shared;
+ amqpBinding.PrefetchLimit = this.PrefetchLimit;
+ }
+
+ protected override void PostDeserialize()
+ {
+ base.PostDeserialize();
+
+ BrokerCollection brokers = Brokers;
+ if (brokers != null)
+ {
+ if (brokers.Count > 0)
+ {
+ // just grab the first element until failover is supported
+ System.Collections.IEnumerator brokersEnum = brokers.GetEnumerator();
+ // move to first element
+ brokersEnum.MoveNext();
+ BrokerElement be = (BrokerElement)brokersEnum.Current;
+ this.BrokerHost = be.Host;
+ this.BrokerPort = be.Port;
+ }
+ }
+ }
+ }
+
+ public class BrokerCollection : ConfigurationElementCollection
+ {
+ public BrokerCollection()
+ {
+ //this.AddElementName = "broker";
+ }
+
+ protected override ConfigurationElement CreateNewElement()
+ {
+ return new BrokerElement();
+ }
+
+ protected override void BaseAdd(ConfigurationElement element)
+ {
+ BrokerElement be = (BrokerElement)element;
+ if (this.BaseGet((Object)be.Key) != null)
+ {
+ throw new ConfigurationErrorsException("duplicate broker definition at line " + element.ElementInformation.LineNumber);
+ }
+ base.BaseAdd(element);
+ }
+
+ protected override Object GetElementKey(ConfigurationElement element)
+ {
+ BrokerElement be = (BrokerElement) element;
+ return be.Key;
+ }
+
+ protected override void PostDeserialize()
+ {
+ base.PostDeserialize();
+ if (this.Count == 0)
+ {
+ throw new ArgumentException("Brokers collection requires at least one broker");
+ }
+ if (this.Count > 1)
+ {
+ Console.WriteLine("Warning: multiple brokers not supported, selecting first instance");
+ }
+ BrokerElement be = (BrokerElement)this.BaseGet(0);
+ }
+
+ protected override string ElementName
+ {
+ get
+ {
+ return "broker";
+ }
+ }
+
+ public override ConfigurationElementCollectionType CollectionType
+ {
+ get
+ {
+ return ConfigurationElementCollectionType.BasicMap;
+ }
+ }
+ }
+
+ public class BrokerElement : ConfigurationElement
+ {
+ string key;
+
+ public BrokerElement()
+ {
+ Properties.Add(new ConfigurationProperty(AmqpConfigurationStrings.BrokerHost,
+ typeof(string), AmqpDefaults.BrokerHost, null, null, ConfigurationPropertyOptions.None));
+ Properties.Add(new ConfigurationProperty(AmqpConfigurationStrings.BrokerPort,
+ typeof(int), AmqpDefaults.BrokerPort, null, null, ConfigurationPropertyOptions.None));
+
+ }
+
+ [ConfigurationProperty(AmqpConfigurationStrings.BrokerHost, DefaultValue = AmqpDefaults.BrokerHost)]
+ public string Host
+ {
+ get { return (string)base[AmqpConfigurationStrings.BrokerHost]; }
+ set { base[AmqpConfigurationStrings.BrokerHost] = value; }
+ }
+
+ [ConfigurationProperty(AmqpConfigurationStrings.BrokerPort, DefaultValue = AmqpDefaults.BrokerPort)]
+ public int Port
+ {
+ get { return (int)base[AmqpConfigurationStrings.BrokerPort]; }
+ set { base[AmqpConfigurationStrings.BrokerPort] = value; }
+ }
+
+ public string Key
+ {
+ get
+ {
+ if (this.key == null)
+ {
+ this.key = this.Host + ':' + this.Port;
+ }
+ return this.key;
+ }
+ }
+
+ }
+}
diff --git a/wcf/src/Apache/Qpid/Channel/AmqpChannelFactory.cs b/wcf/src/Apache/Qpid/Channel/AmqpChannelFactory.cs
new file mode 100644
index 0000000000..5012c76d7e
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Channel/AmqpChannelFactory.cs
@@ -0,0 +1,137 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+
+ class AmqpChannelFactory<TChannel> : ChannelFactoryBase<TChannel>
+ {
+ MessageEncoderFactory messageEncoderFactory;
+ AmqpTransportBindingElement bindingElement;
+ AmqpChannelProperties channelProperties;
+ long maxBufferPoolSize;
+ bool shared;
+ int prefetchLimit;
+ List<AmqpTransportChannel> openChannels;
+
+ internal AmqpChannelFactory(AmqpTransportBindingElement bindingElement, BindingContext context)
+ : base(context.Binding)
+ {
+ this.bindingElement = bindingElement;
+ this.channelProperties = bindingElement.ChannelProperties.Clone();
+ this.shared = bindingElement.Shared;
+ this.prefetchLimit = bindingElement.PrefetchLimit;
+ this.maxBufferPoolSize = bindingElement.MaxBufferPoolSize;
+ Collection<MessageEncodingBindingElement> messageEncoderBindingElements
+ = context.BindingParameters.FindAll<MessageEncodingBindingElement>();
+
+ if (messageEncoderBindingElements.Count > 1)
+ {
+ throw new InvalidOperationException("More than one MessageEncodingBindingElement was found in the BindingParameters of the BindingContext");
+ }
+ else if (messageEncoderBindingElements.Count == 1)
+ {
+ this.messageEncoderFactory = messageEncoderBindingElements[0].CreateMessageEncoderFactory();
+ }
+ else
+ {
+ this.messageEncoderFactory = new TextMessageEncodingBindingElement().CreateMessageEncoderFactory();
+ }
+
+ openChannels = new List<AmqpTransportChannel>();
+ }
+
+
+ public override T GetProperty<T>()
+ {
+ T mep = messageEncoderFactory.Encoder.GetProperty<T>();
+ if (mep != null)
+ {
+ return mep;
+ }
+
+ if (typeof(T) == typeof(MessageVersion))
+ {
+ return (T)(object)messageEncoderFactory.Encoder.MessageVersion;
+ }
+
+ return base.GetProperty<T>();
+ }
+
+ protected override void OnOpen(TimeSpan timeout)
+ {
+ }
+
+ protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ throw new NotImplementedException("AmqpChannelFactory OnBeginOpen");
+ //// return null;
+ }
+
+ protected override void OnEndOpen(IAsyncResult result)
+ {
+ throw new NotImplementedException("AmqpChannelFactory OnEndOpen");
+ }
+
+ protected override TChannel OnCreateChannel(EndpointAddress remoteAddress, Uri via)
+ {
+ AmqpTransportChannel channel = new AmqpTransportChannel(this, this.channelProperties, remoteAddress, this.messageEncoderFactory.Encoder, this.maxBufferPoolSize, this.shared, this.prefetchLimit);
+ lock (openChannels)
+ {
+ channel.Closed += new EventHandler(channel_Closed);
+ openChannels.Add(channel);
+ }
+ return (TChannel)(object) channel;
+ }
+
+ void channel_Closed(object sender, EventArgs e)
+ {
+ if (this.State != CommunicationState.Opened)
+ {
+ return;
+ }
+
+ lock (openChannels)
+ {
+ AmqpTransportChannel channel = (AmqpTransportChannel)sender;
+ if (openChannels.Contains(channel))
+ {
+ openChannels.Remove(channel);
+ }
+ }
+ }
+
+ protected override void OnClose(TimeSpan timeout)
+ {
+ base.OnClose(timeout);
+ lock (openChannels)
+ {
+ foreach (AmqpTransportChannel channel in openChannels)
+ {
+ channel.Close(timeout);
+ }
+ }
+ }
+ }
+}
diff --git a/wcf/src/Apache/Qpid/Channel/AmqpChannelHelpers.cs b/wcf/src/Apache/Qpid/Channel/AmqpChannelHelpers.cs
new file mode 100644
index 0000000000..0853b3d6f3
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Channel/AmqpChannelHelpers.cs
@@ -0,0 +1,142 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.Net;
+ using System.Net.Sockets;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.Globalization;
+
+ using Apache.Qpid.AmqpTypes;
+
+ /// <summary>
+ /// Collection of constants used by the Amqp Channel classes
+ /// </summary>
+ static class AmqpConstants
+ {
+ internal const string Scheme = "amqp";
+ internal const string AmqpBindingSectionName = "system.serviceModel/bindings/amqpBinding";
+ internal const string AmqpBinaryBindingSectionName = "system.serviceModel/bindings/amqpBinaryBinding";
+ internal const string AmqpTransportSectionName = "amqpTransport";
+ }
+
+ static class AmqpConfigurationStrings
+ {
+ public const string BrokerHost = "host";
+ public const string BrokerPort = "port";
+ public const string TransferMode = "transferMode";
+ public const string Brokers = "brokers";
+ public const string Shared = "shared";
+ public const string PrefetchLimit = "prefetchLimit";
+ public const string MaxBufferPoolSize = "maxBufferPoolSize";
+ public const string MaxReceivedMessageSize = "maxReceivedMessageSize";
+ }
+
+ static class AmqpDefaults
+ {
+ internal const string BrokerHost = "localhost";
+ internal const int BrokerPort = 5672;
+ internal const TransferMode TransferMode = System.ServiceModel.TransferMode.Buffered;
+ internal const long MaxBufferPoolSize = 64 * 1024;
+ internal const int MaxReceivedMessageSize = 5 * 1024 * 1024; //64 * 1024;
+ }
+
+ // parking spot for properties that may be shared by separate channels on a single AMQP connection
+ internal class AmqpChannelProperties
+ {
+ string brokerHost;
+ int brokerPort;
+ TransferMode transferMode;
+ AmqpProperties defaultMessageProperties;
+
+ long maxBufferPoolSize;
+ int maxReceivedMessageSize;
+
+ internal AmqpChannelProperties()
+ {
+ this.brokerHost = AmqpDefaults.BrokerHost;
+ this.brokerPort = AmqpDefaults.BrokerPort;
+ this.transferMode = AmqpDefaults.TransferMode;
+ this.defaultMessageProperties = null;
+ this.maxBufferPoolSize = AmqpDefaults.MaxBufferPoolSize;
+ this.maxReceivedMessageSize = AmqpDefaults.MaxReceivedMessageSize;
+ }
+
+ public AmqpChannelProperties Clone()
+ {
+ AmqpChannelProperties props = (AmqpChannelProperties) this.MemberwiseClone();
+ if (this.defaultMessageProperties != null)
+ {
+ props.defaultMessageProperties = this.defaultMessageProperties.Clone();
+ }
+
+ return props;
+ }
+
+ internal string BrokerHost
+ {
+ get { return this.brokerHost; }
+ set { this.brokerHost = value; }
+ }
+
+ internal int BrokerPort
+ {
+ get { return this.brokerPort; }
+ set { this.brokerPort = value; }
+ }
+
+ internal TransferMode TransferMode
+ {
+ get { return this.transferMode; }
+ set { this.transferMode = value; }
+ }
+
+ internal AmqpProperties DefaultMessageProperties
+ {
+ get { return this.defaultMessageProperties; }
+ set { this.defaultMessageProperties = value; }
+ }
+
+ internal long MaxBufferPoolSize
+ {
+ get { return this.maxBufferPoolSize; }
+ set { this.maxBufferPoolSize = value; }
+ }
+
+ internal int MaxReceivedMessageSize
+ {
+ get { return this.maxReceivedMessageSize; }
+ set { this.maxReceivedMessageSize = value; }
+ }
+ }
+
+ static class AmqpChannelHelpers
+ {
+ internal static void ValidateTimeout(TimeSpan timeout)
+ {
+ if (timeout < TimeSpan.Zero)
+ {
+ throw new ArgumentOutOfRangeException("timeout", timeout, "Timeout must be greater than or equal to TimeSpan.Zero. To disable timeout, specify TimeSpan.MaxValue.");
+ }
+ }
+ }
+}
diff --git a/wcf/src/Apache/Qpid/Channel/AmqpChannelListener.cs b/wcf/src/Apache/Qpid/Channel/AmqpChannelListener.cs
new file mode 100644
index 0000000000..3d7801e7c6
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Channel/AmqpChannelListener.cs
@@ -0,0 +1,188 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.Threading;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+
+ class AmqpChannelListener : ChannelListenerBase<IInputChannel>
+ {
+ MessageEncoderFactory messageEncoderFactory;
+ AmqpTransportBindingElement bindingElement;
+ AmqpChannelProperties channelProperties;
+ bool shared;
+ int prefetchLimit;
+ long maxBufferPoolSize;
+ Uri uri;
+ AmqpTransportChannel amqpTransportChannel;
+ delegate IInputChannel AsyncOnAcceptCaller (TimeSpan timeout);
+ AsyncOnAcceptCaller asyncOnAcceptCaller;
+ ManualResetEvent acceptWaitEvent;
+
+ internal AmqpChannelListener(AmqpTransportBindingElement bindingElement, BindingContext context)
+ : base(context.Binding)
+ {
+ this.bindingElement = bindingElement;
+ this.channelProperties = bindingElement.ChannelProperties.Clone();
+ this.shared = bindingElement.Shared;
+ this.prefetchLimit = bindingElement.PrefetchLimit;
+
+ this.maxBufferPoolSize = bindingElement.MaxBufferPoolSize;
+
+ // TODO: review this. Should be unique hostname based
+ this.uri = context.ListenUriBaseAddress;
+ this.asyncOnAcceptCaller = new AsyncOnAcceptCaller(this.OnAcceptChannel);
+ this.acceptWaitEvent = new ManualResetEvent(false);
+
+ Collection<MessageEncodingBindingElement> messageEncoderBindingElements
+ = context.BindingParameters.FindAll<MessageEncodingBindingElement>();
+
+ if(messageEncoderBindingElements.Count > 1)
+ {
+ throw new InvalidOperationException("More than one MessageEncodingBindingElement was found in the BindingParameters of the BindingContext");
+ }
+ else if (messageEncoderBindingElements.Count == 1)
+ {
+ this.messageEncoderFactory = messageEncoderBindingElements[0].CreateMessageEncoderFactory();
+ }
+ else
+ {
+ this.messageEncoderFactory = new TextMessageEncodingBindingElement().CreateMessageEncoderFactory();
+ }
+ }
+
+ public override Uri Uri
+ {
+ get
+ {
+ return this.uri;
+ }
+ }
+
+
+
+ public override T GetProperty<T>()
+ {
+ T mep = messageEncoderFactory.Encoder.GetProperty<T>();
+ if (mep != null)
+ {
+ return mep;
+ }
+
+ if (typeof(T) == typeof(MessageVersion))
+ {
+ return (T)(object)messageEncoderFactory.Encoder.MessageVersion;
+ }
+
+ return base.GetProperty<T>();
+ }
+
+ protected override void OnOpen(TimeSpan timeout)
+ {
+ }
+
+ protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ throw new NotImplementedException("AmqpChannelListener OnBeginOpen");
+ //// return null;
+ }
+
+ protected override void OnEndOpen(IAsyncResult result)
+ {
+ throw new NotImplementedException("AmqpChannelListener OnEndOpen");
+ }
+
+ protected override bool OnWaitForChannel(TimeSpan timeout)
+ {
+ throw new NotImplementedException("AmqpChannelListener OnWaitForChannel");
+ }
+
+ protected override IAsyncResult OnBeginWaitForChannel(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ throw new NotImplementedException("AmqpChannelListener OnBeginWaitForChannel");
+ }
+
+ protected override bool OnEndWaitForChannel(IAsyncResult result)
+ {
+ throw new NotImplementedException("AmqpChannelListener OnEndWaitForChannel");
+ }
+
+ protected override IInputChannel OnAcceptChannel(TimeSpan timeout)
+ {
+ if (this.IsDisposed)
+ {
+ return null;
+ }
+
+ if (amqpTransportChannel == null)
+ {
+ // TODO: add timeout processing
+ amqpTransportChannel = new AmqpTransportChannel(this, this.channelProperties,
+ new EndpointAddress(uri), messageEncoderFactory.Encoder,
+ maxBufferPoolSize, this.shared, this.prefetchLimit);
+ return (IInputChannel)(object)amqpTransportChannel;
+ }
+
+ // Singleton channel. Subsequent Accepts wait until the listener is closed
+ acceptWaitEvent.WaitOne();
+ return null;
+ }
+
+ protected override IAsyncResult OnBeginAcceptChannel(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return asyncOnAcceptCaller.BeginInvoke(timeout, callback, state);
+ }
+
+ protected override IInputChannel OnEndAcceptChannel(IAsyncResult result)
+ {
+ return asyncOnAcceptCaller.EndInvoke(result);
+ }
+
+ protected override void OnClose(TimeSpan timeout)
+ {
+ if (amqpTransportChannel != null)
+ {
+ amqpTransportChannel.Close();
+ }
+ acceptWaitEvent.Set();
+ }
+
+ protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ throw new NotImplementedException("AmqpChannelListener OnBeginClose");
+ }
+
+ protected override void OnEndClose(IAsyncResult result)
+ {
+ throw new NotImplementedException("AmqpChannelListener OnEndClose");
+ }
+
+ protected override void OnAbort()
+ {
+ if (amqpTransportChannel != null)
+ amqpTransportChannel.Abort();
+ acceptWaitEvent.Set();
+ }
+ }
+}
diff --git a/wcf/src/Apache/Qpid/Channel/AmqpTransportBindingElement.cs b/wcf/src/Apache/Qpid/Channel/AmqpTransportBindingElement.cs
new file mode 100644
index 0000000000..7993252309
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Channel/AmqpTransportBindingElement.cs
@@ -0,0 +1,158 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.ServiceModel.Description;
+ using Apache.Qpid.AmqpTypes;
+
+ public class AmqpTransportBindingElement : TransportBindingElement, ITransactedBindingElement
+ {
+ AmqpChannelProperties channelProperties;
+ bool shared;
+ int prefetchLimit;
+
+ public AmqpTransportBindingElement()
+ {
+ // start with default properties
+ channelProperties = new AmqpChannelProperties();
+ }
+
+ protected AmqpTransportBindingElement(AmqpTransportBindingElement other)
+ : base(other)
+ {
+ this.channelProperties = other.channelProperties.Clone();
+ this.shared = other.shared;
+ this.prefetchLimit = other.prefetchLimit;
+ }
+
+ public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException("context");
+ }
+
+ return (IChannelFactory<TChannel>)(object)new AmqpChannelFactory<TChannel>(this, context);
+ }
+
+ public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException("context");
+ }
+
+ return (IChannelListener<TChannel>)(object)new AmqpChannelListener(this, context);
+ }
+
+
+
+ public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
+ {
+ return ((typeof(TChannel) == typeof(IOutputChannel)) ||
+ (typeof(TChannel) == typeof(IInputChannel)));
+ }
+
+ public override bool CanBuildChannelListener<TChannel>(BindingContext context)
+ {
+ return ((typeof(TChannel) == typeof(IInputChannel)));
+ }
+
+ public override BindingElement Clone()
+ {
+ return new AmqpTransportBindingElement(this);
+ }
+
+ internal AmqpChannelProperties ChannelProperties
+ {
+ get { return channelProperties; }
+ }
+
+ public string BrokerHost
+ {
+ get { return this.channelProperties.BrokerHost; }
+ set { this.channelProperties.BrokerHost = value; }
+ }
+
+ public int BrokerPort
+ {
+ get { return this.channelProperties.BrokerPort; }
+ set { this.channelProperties.BrokerPort = value; }
+ }
+
+ public int PrefetchLimit
+ {
+ get { return this.prefetchLimit; }
+ set { this.prefetchLimit = value; }
+ }
+
+ public bool Shared
+ {
+ get { return this.shared; }
+ set { this.shared = value; }
+ }
+
+ public bool TransactedReceiveEnabled
+ {
+ get { return true; }
+ }
+
+ public TransferMode TransferMode
+ {
+ get { return this.channelProperties.TransferMode; }
+ set { this.channelProperties.TransferMode = value; }
+ }
+
+ public AmqpProperties DefaultMessageProperties
+ {
+ get { return this.channelProperties.DefaultMessageProperties; }
+
+ set { this.channelProperties.DefaultMessageProperties = value; }
+ }
+
+ public override T GetProperty<T>(BindingContext context)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException("context");
+ }
+
+ if (typeof(T) == typeof(MessageVersion))
+ {
+ return (T)(object)MessageVersion.Default;
+ }
+
+
+ return context.GetInnerProperty<T>();
+ }
+
+ public override string Scheme
+ {
+ get
+ {
+ return AmqpConstants.Scheme;
+ }
+ }
+
+ }
+}
diff --git a/wcf/src/Apache/Qpid/Channel/AmqpTransportChannel.cs b/wcf/src/Apache/Qpid/Channel/AmqpTransportChannel.cs
new file mode 100644
index 0000000000..a6f6ee6800
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Channel/AmqpTransportChannel.cs
@@ -0,0 +1,595 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+// TODO: flow control
+// timeout handling
+// transactions
+// check if should split into separate input and output classes (little overlap)
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.Text;
+ using System.Threading;
+ using System.Globalization;
+ using System.Xml;
+
+ // the thin interop layer that provides access to the Qpid AMQP client libraries
+ using Apache.Qpid.Interop;
+ using Apache.Qpid.AmqpTypes;
+
+ /// <summary>
+ /// WCF client transport channel for accessing AMQP brokers using the Qpid C++ library
+ /// </summary>
+ public class AmqpTransportChannel : ChannelBase, IOutputChannel, IInputChannel
+ {
+ private static readonly EndpointAddress AnonymousAddress =
+ new EndpointAddress("http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous");
+
+ private EndpointAddress remoteAddress;
+ private MessageEncoder encoder;
+ private AmqpChannelProperties factoryChannelProperties;
+ private bool shared;
+ private int prefetchLimit;
+ private string encoderContentType;
+
+ // input = 0-10 queue, output = 0-10 exchange
+ private string queueName;
+
+ private String routingKey;
+ private BufferManager bufferManager;
+ private AmqpProperties outputMessageProperties;
+
+ private InputLink inputLink;
+ private OutputLink outputLink;
+
+ private bool isInputChannel;
+ private bool streamed;
+
+ private AsyncTimeSpanCaller asyncOpenCaller;
+ private AsyncTimeSpanCaller asyncCloseCaller;
+
+ internal AmqpTransportChannel(ChannelManagerBase factory, AmqpChannelProperties channelProperties, EndpointAddress remoteAddress, MessageEncoder msgEncoder, long maxBufferPoolSize, bool sharedConnection, int prefetchLimit)
+ : base(factory)
+ {
+ this.isInputChannel = (factory is ChannelListenerBase) || (factory is AmqpChannelFactory<IInputChannel>);
+
+ if (remoteAddress == null)
+ {
+ throw new ArgumentException("Null Endpoint Address");
+ }
+
+ this.factoryChannelProperties = channelProperties;
+ this.shared = sharedConnection;
+ this.prefetchLimit = prefetchLimit;
+ this.remoteAddress = remoteAddress;
+
+ // pull out host, port, queue, and connection arguments
+ this.ParseAmqpUri(remoteAddress.Uri);
+
+ this.encoder = msgEncoder;
+ string ct = String.Empty;
+ if (this.encoder != null)
+ {
+ ct = this.encoder.ContentType;
+ if (ct != null)
+ {
+ int pos = ct.IndexOf(';');
+ if (pos != -1)
+ {
+ ct = ct.Substring(0, pos).Trim();
+ }
+ }
+ else
+ {
+ ct = "application/octet-stream";
+ }
+ }
+
+ this.encoderContentType = ct;
+
+ if (this.factoryChannelProperties.TransferMode == TransferMode.Streamed)
+ {
+ this.streamed = true;
+ }
+ else
+ {
+ if (!(this.factoryChannelProperties.TransferMode == TransferMode.Buffered))
+ {
+ throw new ArgumentException("TransferMode mode must be \"Streamed\" or \"Buffered\"");
+ }
+
+ this.streamed = false;
+ }
+
+ this.bufferManager = BufferManager.CreateBufferManager(maxBufferPoolSize, int.MaxValue);
+
+ this.asyncOpenCaller = new AsyncTimeSpanCaller(this.OnOpen);
+ this.asyncCloseCaller = new AsyncTimeSpanCaller(this.OnClose);
+
+ if (this.isInputChannel)
+ {
+ this.inputLink = ConnectionManager.GetInputLink(this.factoryChannelProperties, shared, false, this.queueName);
+ this.inputLink.PrefetchLimit = this.prefetchLimit;
+ }
+ else
+ {
+ this.outputLink = ConnectionManager.GetOutputLink(this.factoryChannelProperties, shared, false, this.queueName);
+ }
+ }
+
+ private delegate bool AsyncTryReceiveCaller(TimeSpan timeout, out Message message);
+
+ private delegate void AsyncTimeSpanCaller(TimeSpan timeout);
+
+ EndpointAddress IOutputChannel.RemoteAddress
+ {
+ get
+ {
+ return this.remoteAddress;
+ }
+ }
+
+ // i.e what you would insert into a ReplyTo header to reach
+ // here. Presumably should be exchange/link and routing info,
+ // rather than the actual input queue name.
+ EndpointAddress IInputChannel.LocalAddress
+ {
+ get
+ {
+ // TODO: something better
+ return AnonymousAddress;
+ }
+ }
+
+ AmqpProperties OutputMessageProperties
+ {
+ get
+ {
+ if (this.outputMessageProperties == null)
+ {
+ this.outputMessageProperties = this.factoryChannelProperties.DefaultMessageProperties;
+ if (this.outputMessageProperties == null)
+ {
+ this.outputMessageProperties = new AmqpProperties();
+ }
+ }
+
+ return this.outputMessageProperties;
+ }
+ }
+
+ Uri IOutputChannel.Via
+ {
+ get
+ {
+ return this.remoteAddress.Uri;
+ }
+ }
+
+ public override T GetProperty<T>()
+ {
+ if (typeof(T) == typeof(IInputChannel))
+ {
+ if (this.isInputChannel)
+ {
+ return (T)(object)this;
+ }
+ }
+ else if (typeof(T) == typeof(IOutputChannel))
+ {
+ if (!this.isInputChannel)
+ {
+ return (T)(object)this;
+ }
+ }
+
+ return base.GetProperty<T>();
+ }
+
+ public void Send(Message message, TimeSpan timeout)
+ {
+ this.ThrowIfDisposedOrNotOpen();
+ AmqpChannelHelpers.ValidateTimeout(timeout);
+
+ try
+ {
+ using (AmqpMessage amqpMessage = this.WcfToQpid(message))
+ {
+ this.outputLink.Send(amqpMessage, timeout);
+ }
+ }
+ finally
+ {
+ message.Close();
+ }
+ }
+
+ public void Send(Message message)
+ {
+ this.Send(message, this.DefaultSendTimeout);
+ }
+
+ public IAsyncResult BeginSend(Message message, TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ this.ThrowIfDisposedOrNotOpen();
+ AmqpChannelHelpers.ValidateTimeout(timeout);
+
+ try
+ {
+ using (AmqpMessage amqpMessage = this.WcfToQpid(message))
+ {
+ return this.outputLink.BeginSend(amqpMessage, timeout, callback, state);
+ }
+ }
+ finally
+ {
+ message.Close();
+ }
+ }
+
+ public IAsyncResult BeginSend(Message message, AsyncCallback callback, object state)
+ {
+ return this.BeginSend(message, this.DefaultSendTimeout, callback, state);
+ }
+
+ public void EndSend(IAsyncResult result)
+ {
+ this.outputLink.EndSend(result);
+ }
+
+ public Message Receive(TimeSpan timeout)
+ {
+ Message message;
+ if (this.TryReceive(timeout, out message))
+ {
+ return message;
+ }
+ else
+ {
+ throw new TimeoutException("Receive");
+ }
+ }
+
+ public Message Receive()
+ {
+ return this.Receive(this.DefaultReceiveTimeout);
+ }
+
+ public bool TryReceive(TimeSpan timeout, out Message message)
+ {
+ AmqpMessage amqpMessage;
+ message = null;
+
+ if (this.inputLink.TryReceive(timeout, out amqpMessage))
+ {
+ message = this.QpidToWcf(amqpMessage);
+ return true;
+ }
+
+ return false;
+ }
+
+ public IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return this.inputLink.BeginTryReceive(timeout, callback, state);
+ }
+
+ public bool EndTryReceive(IAsyncResult result, out Message message)
+ {
+ AmqpMessage amqpMessage = null;
+ if (!this.inputLink.EndTryReceive(result, out amqpMessage))
+ {
+ message = null;
+ return false;
+ }
+ message = QpidToWcf(amqpMessage);
+ return true;
+ }
+
+ public bool WaitForMessage(TimeSpan timeout)
+ {
+ return this.inputLink.WaitForMessage(timeout);
+ }
+
+ public IAsyncResult BeginReceive(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return this.inputLink.BeginTryReceive(timeout, callback, state);
+ }
+
+ public IAsyncResult BeginReceive(AsyncCallback callback, object state)
+ {
+ return this.BeginReceive(this.DefaultReceiveTimeout, callback, state);
+ }
+
+ public IAsyncResult BeginWaitForMessage(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return this.inputLink.BeginWaitForMessage(timeout, callback, state);
+ }
+
+ public Message EndReceive(IAsyncResult result)
+ {
+ Message message;
+ if (this.EndTryReceive(result, out message))
+ {
+ return message;
+ }
+ else
+ {
+ throw new TimeoutException("EndReceive");
+ }
+ }
+
+ public bool EndWaitForMessage(IAsyncResult result)
+ {
+ return this.inputLink.EndWaitForMessage(result);
+ }
+
+ public void CloseEndPoint()
+ {
+ if (this.inputLink != null)
+ {
+ this.inputLink.Close();
+ }
+ if (this.outputLink != null)
+ {
+ this.outputLink.Close();
+ }
+ }
+
+ /// <summary>
+ /// Open connection to Broker
+ /// </summary>
+ protected override void OnOpen(TimeSpan timeout)
+ {
+ // TODO: move open logic to here from constructor
+ }
+
+ protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return this.asyncOpenCaller.BeginInvoke(timeout, callback, state);
+ }
+
+ protected override void OnEndOpen(IAsyncResult result)
+ {
+ this.asyncOpenCaller.EndInvoke(result);
+ }
+
+ protected override void OnAbort()
+ {
+ //// TODO: check for network-less qpid teardown or launch special thread
+ this.CloseEndPoint();
+ this.Cleanup();
+ }
+
+ /// <summary>
+ /// Shutdown gracefully
+ /// </summary>
+ protected override void OnClose(TimeSpan timeout)
+ {
+ this.CloseEndPoint();
+ this.Cleanup();
+ }
+
+ protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ return this.asyncCloseCaller.BeginInvoke(timeout, callback, state);
+ }
+
+ protected override void OnEndClose(IAsyncResult result)
+ {
+ this.asyncCloseCaller.EndInvoke(result);
+ }
+
+ private AmqpMessage WcfToQpid(Message wcfMessage)
+ {
+ object obj;
+ AmqpProperties applicationProperties = null;
+ bool success = false;
+ AmqpMessage amqpMessage = null;
+
+ if (wcfMessage.Properties.TryGetValue("AmqpProperties", out obj))
+ {
+ applicationProperties = obj as AmqpProperties;
+ }
+
+ try
+ {
+ AmqpProperties outgoingProperties = new AmqpProperties();
+
+ // Start with AMQP properties from the binding and the URI
+ if (this.factoryChannelProperties.DefaultMessageProperties != null)
+ {
+ outgoingProperties.MergeFrom(this.factoryChannelProperties.DefaultMessageProperties);
+ }
+
+ if (this.routingKey != null)
+ {
+ outgoingProperties.RoutingKey = this.routingKey;
+ }
+
+ // Add the Properties set by the application on this particular message.
+ // Application properties trump channel properties
+ if (applicationProperties != null)
+ {
+ outgoingProperties.MergeFrom(applicationProperties);
+ }
+
+ amqpMessage = this.outputLink.CreateMessage();
+ amqpMessage.Properties = outgoingProperties;
+
+ // copy the WCF message body to the AMQP message body
+ if (this.streamed)
+ {
+ this.encoder.WriteMessage(wcfMessage, amqpMessage.BodyStream);
+ }
+ else
+ {
+ ArraySegment<byte> encodedBody = this.encoder.WriteMessage(wcfMessage, int.MaxValue, this.bufferManager);
+ try
+ {
+ amqpMessage.BodyStream.Write(encodedBody.Array, encodedBody.Offset, encodedBody.Count);
+ }
+ finally
+ {
+ this.bufferManager.ReturnBuffer(encodedBody.Array);
+ }
+ }
+
+ success = true;
+ }
+ finally
+ {
+ if (!success && (amqpMessage != null))
+ {
+ amqpMessage.Dispose();
+ }
+ }
+ return amqpMessage;
+ }
+
+
+ private Message QpidToWcf(AmqpMessage amqpMessage)
+ {
+ if (amqpMessage == null)
+ {
+ return null;
+ }
+
+ Message wcfMessage = null;
+ byte[] managedBuffer = null;
+
+ try
+ {
+ if (this.streamed)
+ {
+ wcfMessage = this.encoder.ReadMessage(amqpMessage.BodyStream, int.MaxValue);
+ }
+ else
+ {
+ int count = (int)amqpMessage.BodyStream.Length;
+ managedBuffer = this.bufferManager.TakeBuffer(count);
+ int nr = amqpMessage.BodyStream.Read(managedBuffer, 0, count);
+ ArraySegment<byte> bufseg = new ArraySegment<byte>(managedBuffer, 0, count);
+
+ wcfMessage = this.encoder.ReadMessage(bufseg, this.bufferManager);
+
+ // set to null for finally{} block, since the encoder is now responsible for
+ // returning the BufferManager memory
+ managedBuffer = null;
+ }
+
+ // This message will be discarded unless the "To" header matches
+ // the WCF endpoint dispatcher's address filter (or the service is
+ // AddressFilterMode=AddressFilterMode.Any).
+
+ this.remoteAddress.ApplyTo(wcfMessage);
+
+ if (amqpMessage.Properties != null)
+ {
+ wcfMessage.Properties.Add("AmqpProperties", amqpMessage.Properties);
+ }
+ }
+ catch (XmlException xmlException)
+ {
+ throw new ProtocolException(
+ "There is a problem with the XML that was received from the network. See inner exception for more details.",
+ xmlException);
+ }
+ catch (Exception e)
+ {
+ // TODO: logging
+ Console.WriteLine("TX channel encoder exception " + e);
+ }
+ finally
+ {
+ // close the amqpMessage unless the body will be read at a later time.
+ if (!this.streamed || wcfMessage == null)
+ {
+ amqpMessage.Close();
+ }
+
+ // the handoff to the encoder failed
+ if (managedBuffer != null)
+ {
+ this.bufferManager.ReturnBuffer(managedBuffer);
+ }
+ }
+
+ return wcfMessage;
+ }
+
+ private void Cleanup()
+ {
+ this.bufferManager.Clear();
+ }
+
+ // "amqp:queue1" | "amqp:stocks@broker1.com" | "amqp:queue3?routingkey=key"
+ private void ParseAmqpUri(Uri uri)
+ {
+ if (uri.Scheme != AmqpConstants.Scheme)
+ {
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
+ "The scheme {0} specified in address is not supported.", uri.Scheme), "uri");
+ }
+
+ this.queueName = uri.LocalPath;
+
+ if ((this.queueName.IndexOf('@') != -1) && this.isInputChannel)
+ {
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
+ "Invalid input queue name: \"{0}\" specified.", this.queueName), "uri");
+ }
+
+ // search out session parameters in the query portion of the URI
+
+ string routingParseKey = "routingkey=";
+ char[] charSeparators = new char[] { '?', ';' };
+ string[] args = uri.Query.Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
+ foreach (string s in args)
+ {
+ if (s.StartsWith(routingParseKey))
+ {
+ this.routingKey = s.Substring(routingParseKey.Length);
+ }
+ }
+
+ if (this.queueName == String.Empty)
+ {
+ if (this.isInputChannel)
+ {
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
+ "Empty queue target specifier not allowed."), "uri");
+ }
+ else
+ {
+ if (this.routingKey == null)
+ {
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
+ "No target queue or routing key specified."), "uri");
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/wcf/src/Apache/Qpid/Channel/Channel.csproj b/wcf/src/Apache/Qpid/Channel/Channel.csproj
new file mode 100644
index 0000000000..ac90fb7d64
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Channel/Channel.csproj
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{8AABAB30-7D1E-4539-B7D1-05450262BAD2}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Apache.Qpid.Channel</RootNamespace>
+ <AssemblyName>Apache.Qpid.Channel</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <StartupObject>
+ </StartupObject>
+ <SignAssembly>true</SignAssembly>
+ <AssemblyOriginatorKeyFile>..\..\..\wcfnet.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+ <ItemGroup>
+ <Compile Include="AmqpBinaryBinding.cs" />
+ <Compile Include="AmqpBinaryBindingCollectionElement.cs" />
+ <Compile Include="AmqpBinaryBindingConfigurationElement.cs" />
+ <Compile Include="AmqpChannelFactory.cs" />
+ <Compile Include="AmqpChannelHelpers.cs" />
+ <Compile Include="AmqpChannelListener.cs" />
+ <Compile Include="AmqpBinding.cs" />
+ <Compile Include="AmqpBindingCollectionElement.cs" />
+ <Compile Include="AmqpBindingConfigurationElement.cs" />
+ <Compile Include="AmqpTransportBindingElement.cs" />
+ <Compile Include="AmqpTransportChannel.cs" />
+ <Compile Include="ConnectionManager.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="RawMessage.cs" />
+ <Compile Include="RawMessageEncoder.cs" />
+ <Compile Include="RawMessageEncoderFactory.cs" />
+ <Compile Include="RawMessageEncodingBindingElement.cs" />
+ <Compile Include="RawXmlReader.cs" />
+ <Compile Include="RawXmlWriter.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.configuration" />
+ <Reference Include="System.Runtime.Serialization">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Transactions" />
+ <Reference Include="System.XML" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Interop\Interop.vcproj">
+ <Project>{C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}</Project>
+ <Name>Interop</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\..\wcfnet.snk" />
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/wcf/src/Apache/Qpid/Channel/ConnectionManager.cs b/wcf/src/Apache/Qpid/Channel/ConnectionManager.cs
new file mode 100644
index 0000000000..a63e5333f4
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Channel/ConnectionManager.cs
@@ -0,0 +1,266 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Threading;
+
+ using Apache.Qpid.Interop;
+
+ // The ConnectionManager looks after a shareable pool of AmqpConnection and AmqpSession
+ // objects. If two connection requests could be shared (see MakeKey() properties), and
+ // are designated as shareable, then they will be paired up. Each shared connection is
+ // a separate instance of a ManagedConnection. All unshared connections use a single
+ // instance of ManagedConnection with locking turned off. The ManagedConnection object
+ // registers for notifictation when a connection goes idle (all grandchild InputLink and
+ // OutputLink objects have been closed), and closes the connection.
+
+ // TODO: the session sharing is roughed-in via comments but needs completing.
+
+ internal sealed class ConnectionManager
+ {
+ // A side effect of creating InputLinks and OutputLinks is that counters
+ // in the respective AmqpSession and AmqpConnection are updated, so care
+ // must be taken to hold the lock across acquiring a session and opening
+ // a link on it.
+
+ // one for each shared connection
+ private static Dictionary<string, ManagedConnection> sharedInstances;
+
+ // this one creates and releases connections that are not shared. No locking required.
+ private static ManagedConnection unsharedInstance;
+
+ // lock for finding or creating ManagedConnection instances
+ private static Object connectionLock;
+
+ static ConnectionManager()
+ {
+ unsharedInstance = null;
+ sharedInstances = new Dictionary<string, ManagedConnection>();
+ connectionLock = new Object();
+ }
+
+ private static string MakeKey(AmqpChannelProperties props)
+ {
+ return props.BrokerHost + ':' + props.BrokerPort + ':' + props.TransferMode;
+ }
+
+ private static ManagedConnection GetManagedConnection(AmqpChannelProperties channelProperties, bool connectionSharing)
+ {
+ if (connectionSharing)
+ {
+ string key = MakeKey(channelProperties);
+ lock (connectionLock)
+ {
+ ManagedConnection mc = null;
+ if (!sharedInstances.TryGetValue(key, out mc))
+ {
+ mc = new ManagedConnection(true);
+ sharedInstances.Add(key, mc);
+ }
+ return mc;
+ }
+ }
+ else
+ {
+ lock (connectionLock)
+ {
+ if (unsharedInstance == null)
+ {
+ unsharedInstance = new ManagedConnection(false);
+ }
+ return unsharedInstance;
+ }
+ }
+ }
+
+ public static OutputLink GetOutputLink(AmqpChannelProperties channelProperties, bool connectionSharing, bool sessionSharing, string qname)
+ {
+ ManagedConnection mc = GetManagedConnection(channelProperties, connectionSharing);
+ return (OutputLink)mc.GetLink(channelProperties, sessionSharing, null, qname);
+ }
+
+ public static InputLink GetInputLink(AmqpChannelProperties channelProperties, bool connectionSharing, bool sessionSharing, string qname)
+ {
+ ManagedConnection mc = GetManagedConnection(channelProperties, connectionSharing);
+ return (InputLink)mc.GetLink(channelProperties, sessionSharing, qname, null);
+ }
+
+
+
+ class ManagedConnection
+ {
+ private Boolean shared;
+ private AmqpConnection sharedConnection;
+ //private Dictionary<string, AmqpSession> sharedSessions;
+
+ public ManagedConnection(bool shared)
+ {
+ this.shared = shared;
+ }
+
+
+ public object GetLink(AmqpChannelProperties channelProperties, bool sessionSharing, string inputQueue, string outputQueue)
+ {
+ AmqpConnection connection = null;
+ AmqpSession session = null;
+ Object link = null;
+ bool newConnection = false;
+ //bool newSession = false;
+ bool success = false;
+
+ // when called in the non-shared case, only stack variables should be used for holding connections/sessions/links
+
+ if (this.shared)
+ {
+ Monitor.Enter(this); // lock
+ }
+
+ try
+ {
+ if (this.shared)
+ {
+ // TODO: check shared connection not closed (i.e. network drop) and refresh this instance if needed
+ if (sessionSharing)
+ {
+ throw new NotImplementedException("shared session");
+ /* * ... once we have a defined shared session config parameter:
+
+ // lazilly create
+ if (this.sharedSessions == null)
+ {
+ this.sharedSessions = new Dictionary<string, AmqpSession>();
+ }
+
+ alreadydeclaredstring sessionKey = channelProperties.name_of_key_goes_here;
+ this.sharedSessions.TryGetValue(sessionKey, out session);
+
+ * */
+ }
+
+ if (this.sharedConnection != null)
+ {
+ connection = this.sharedConnection;
+ }
+ }
+
+ if (connection == null)
+ {
+ connection = new AmqpConnection(channelProperties.BrokerHost, channelProperties.BrokerPort);
+ newConnection = true;
+ if (this.shared)
+ {
+ connection.OnConnectionIdle += new ConnectionIdleEventHandler(this.IdleConnectionHandler);
+ }
+ else
+ {
+ connection.OnConnectionIdle += new ConnectionIdleEventHandler(UnsharedIdleConnectionHandler);
+ }
+ }
+
+ if (session == null)
+ {
+ session = connection.CreateSession();
+ //newSession = true;
+ }
+
+ if (inputQueue != null)
+ {
+ link = session.CreateInputLink(inputQueue);
+ }
+ else
+ {
+ link = session.CreateOutputLink(outputQueue);
+ }
+
+ if (this.shared)
+ {
+ if (newConnection)
+ {
+ this.sharedConnection = connection;
+ }
+ /*
+ if (newSession)
+ {
+ sharedSessions.Add(foo, session);
+ }
+ * */
+ }
+
+ success = true;
+ }
+ finally
+ {
+ if (this.shared)
+ {
+ Monitor.Exit(this);
+ }
+ if (!success)
+ {
+ /*
+ if (newSession)
+ {
+ session.Close();
+ }
+ */
+ if (newConnection)
+ {
+ connection.Close();
+ }
+ }
+ }
+
+ return link;
+ }
+
+
+ static void UnsharedIdleConnectionHandler(Object sender, EventArgs empty)
+ {
+ if (sender is AmqpConnection)
+ {
+ AmqpConnection connection = (AmqpConnection)sender;
+ connection.Close();
+ }
+ }
+
+ void IdleConnectionHandler(Object sender, EventArgs empty)
+ {
+ lock (this)
+ {
+ if (sharedConnection != sender || sharedConnection == null)
+ {
+ return;
+ }
+ if (!sharedConnection.IsIdle)
+ {
+ // Another thread made the connection busy again.
+ // That's OK. Another idle event will come along later.
+ return;
+ }
+ sharedConnection.Close(); // also closes all child sessions
+ sharedConnection = null;
+ //sharedSessions = null;
+ }
+ }
+ }
+ }
+}
diff --git a/wcf/src/Apache/Qpid/Channel/Properties/AssemblyInfo.cs b/wcf/src/Apache/Qpid/Channel/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..edd9a056a7
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Channel/Properties/AssemblyInfo.cs
@@ -0,0 +1,52 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Apache.Qpid.Channel")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to true makes the types in this assembly visible
+// to COM components. This is required for this to be used by an
+// Excel RTD component.
+[assembly: ComVisible(true)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("ac02bbb0-2c19-43fb-a36c-b1b0a50eaf1a")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/wcf/src/Apache/Qpid/Channel/RawMessage.cs b/wcf/src/Apache/Qpid/Channel/RawMessage.cs
new file mode 100644
index 0000000000..5925fa47dc
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Channel/RawMessage.cs
@@ -0,0 +1,374 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.IO;
+ using System.ServiceModel.Channels;
+ using System.Xml;
+
+ // This incoming Message is backed either by a Stream (bodyStream) or a byte array (bodyBytes).
+ // If bodyBytes belongs to a BufferManager, we must return it when done.
+ // The pay-off is OnGetReaderAtBodyContents().
+ // Most of the complexity is dealing with the OnCreateBufferedCopy() machinery.
+ internal class RawMessage : Message
+ {
+ private MessageHeaders headers;
+ private MessageProperties properties;
+ private XmlDictionaryReaderQuotas readerQuotas;
+ private Stream bodyStream;
+ private byte[] bodyBytes;
+ private int index;
+ private int count;
+ private BufferManager bufferManager;
+
+ public RawMessage(byte[] buffer, int index, int count, BufferManager bufferManager, XmlDictionaryReaderQuotas quotas)
+ {
+ // this constructor supports MessageEncoder.ReadMessage(ArraySegment<byte> b, BufferManager mgr, string contentType)
+ if (quotas == null)
+ {
+ quotas = new XmlDictionaryReaderQuotas();
+ }
+
+ this.headers = new MessageHeaders(MessageVersion.None);
+ this.properties = new MessageProperties();
+ this.readerQuotas = quotas;
+ this.bodyBytes = buffer;
+ this.index = index;
+ this.count = count;
+ this.bufferManager = bufferManager;
+ }
+
+ public RawMessage(Stream stream, XmlDictionaryReaderQuotas quotas)
+ {
+ // this constructor supports MessageEncoder.ReadMessage(System.IO.Stream s, int max, string contentType)
+ if (quotas == null)
+ {
+ quotas = new XmlDictionaryReaderQuotas();
+ }
+
+ this.headers = new MessageHeaders(MessageVersion.None);
+ this.properties = new MessageProperties();
+ this.bodyStream = stream;
+ }
+
+ public RawMessage(MessageHeaders headers, MessageProperties properties, byte[] bytes, int index, int count, XmlDictionaryReaderQuotas quotas)
+ {
+ // this constructor supports internal needs for CreateBufferedCopy().CreateMessage()
+ this.headers = new MessageHeaders(headers);
+ this.properties = new MessageProperties(properties);
+ this.bodyBytes = bytes;
+ this.index = index;
+ this.count = count;
+ this.readerQuotas = quotas;
+ }
+
+ public override MessageHeaders Headers
+ {
+ get
+ {
+ if (this.IsDisposed)
+ {
+ throw new ObjectDisposedException("message");
+ }
+
+ return this.headers;
+ }
+ }
+
+ public override bool IsEmpty
+ {
+ get
+ {
+ if (this.IsDisposed)
+ {
+ throw new ObjectDisposedException("message");
+ }
+
+ return false;
+ }
+ }
+
+ public override bool IsFault
+ {
+ get
+ {
+ if (this.IsDisposed)
+ {
+ throw new ObjectDisposedException("message");
+ }
+
+ return false;
+ }
+ }
+
+ public override MessageProperties Properties
+ {
+ get
+ {
+ if (this.IsDisposed)
+ {
+ throw new ObjectDisposedException("message");
+ }
+
+ return this.properties;
+ }
+ }
+
+ public override MessageVersion Version
+ {
+ get
+ {
+ if (this.IsDisposed)
+ {
+ throw new ObjectDisposedException("message");
+ }
+
+ return MessageVersion.None;
+ }
+ }
+
+ protected override void OnBodyToString(XmlDictionaryWriter writer)
+ {
+ if (this.bodyStream != null)
+ {
+ writer.WriteString("Stream");
+ }
+ else
+ {
+ writer.WriteStartElement(RawMessageEncoder.StreamElementName, string.Empty);
+ writer.WriteBase64(this.bodyBytes, this.index, this.count);
+ writer.WriteEndElement();
+ }
+ }
+
+ protected override void OnClose()
+ {
+ Exception deferEx = null;
+ try
+ {
+ base.OnClose();
+ }
+ catch (Exception e)
+ {
+ deferEx = e;
+ }
+
+ try
+ {
+ if (this.properties != null)
+ {
+ this.properties.Dispose();
+ }
+ }
+ catch (Exception e)
+ {
+ if (deferEx == null)
+ {
+ deferEx = e;
+ }
+ }
+
+ try
+ {
+ if (this.bufferManager != null)
+ {
+ this.bufferManager.ReturnBuffer(this.bodyBytes);
+ this.bufferManager = null;
+ }
+ }
+ catch (Exception e)
+ {
+ if (deferEx == null)
+ {
+ deferEx = e;
+ }
+ }
+
+ if (deferEx != null)
+ {
+ throw deferEx;
+ }
+ }
+
+ protected override MessageBuffer OnCreateBufferedCopy(int maxBufferSize)
+ {
+ if (this.bodyStream != null)
+ {
+ int len = (int)this.bodyStream.Length;
+ byte[] buf = new byte[len];
+ this.bodyStream.Read(buf, 0, len);
+ this.bodyStream = null;
+ this.bodyBytes = buf;
+ this.count = len;
+ this.index = 0;
+ }
+ else
+ {
+ if (this.bufferManager != null)
+ {
+ // we could take steps to share the buffer among copies and release the memory
+ // after the last user finishes by a reference count or such, but we are already
+ // far from the intended optimized use. Make one GC managed memory copy that is
+ // shared by all.
+ byte[] buf = new byte[this.count];
+
+ Buffer.BlockCopy(this.bodyBytes, this.index, buf, 0, this.count);
+ this.bufferManager.ReturnBuffer(this.bodyBytes);
+ this.bufferManager = null;
+ this.bodyBytes = buf;
+ this.index = 0;
+ }
+ }
+
+ return new RawMessageBuffer(this.headers, this.properties, this.bodyBytes, this.index, this.count, this.readerQuotas);
+ }
+
+ protected override XmlDictionaryReader OnGetReaderAtBodyContents()
+ {
+ Stream readerStream = null;
+ bool ownsStream;
+
+ if (this.bodyStream != null)
+ {
+ readerStream = this.bodyStream;
+ ownsStream = false;
+ }
+ else
+ {
+ // create stream for duration of XmlReader.
+ ownsStream = true;
+ if (this.bufferManager != null)
+ {
+ readerStream = new RawMemoryStream(this.bodyBytes, this.index, this.count, this.bufferManager);
+ this.bufferManager = null;
+ }
+ else
+ {
+ readerStream = new MemoryStream(this.bodyBytes, this.index, this.count, false);
+ }
+ }
+
+ return new RawXmlReader(readerStream, this.readerQuotas, ownsStream);
+ }
+
+ protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
+ {
+ writer.WriteStartElement(RawMessageEncoder.StreamElementName, string.Empty);
+ if (this.bodyStream != null)
+ {
+ int len = (int)this.bodyStream.Length;
+ byte[] buf = new byte[len];
+ this.bodyStream.Read(buf, 0, len);
+ writer.WriteBase64(buf, 0, len);
+ }
+ else
+ {
+ writer.WriteBase64(this.bodyBytes, this.index, this.count);
+ }
+
+ writer.WriteEndElement();
+ }
+
+ private class RawMemoryStream : MemoryStream
+ {
+ private BufferManager bufferManager;
+ private byte[] buffer;
+
+ public RawMemoryStream(byte[] bytes, int index, int count, BufferManager mgr)
+ : base(bytes, index, count, false)
+ {
+ this.bufferManager = mgr;
+ this.buffer = bytes;
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (this.bufferManager != null)
+ {
+ try
+ {
+ this.bufferManager.ReturnBuffer(this.buffer);
+ }
+ finally
+ {
+ this.bufferManager = null;
+ base.Dispose(disposing);
+ }
+ }
+ }
+ }
+
+ private class RawMessageBuffer : MessageBuffer
+ {
+ private bool closed;
+ private MessageHeaders headers;
+ private MessageProperties properties;
+ private byte[] bodyBytes;
+ private int index;
+ private int count;
+ private XmlDictionaryReaderQuotas readerQuotas;
+
+ public RawMessageBuffer(MessageHeaders headers, MessageProperties properties, byte[] bytes, int index, int count, XmlDictionaryReaderQuotas quotas)
+ : base()
+ {
+ this.headers = new MessageHeaders(headers);
+ this.properties = new MessageProperties(properties);
+ this.bodyBytes = bytes;
+ this.index = index;
+ this.count = count;
+ this.readerQuotas = new XmlDictionaryReaderQuotas();
+ quotas.CopyTo(this.readerQuotas);
+ }
+
+ public override int BufferSize
+ {
+ get { return this.count; }
+ }
+
+ public override void Close()
+ {
+ if (!this.closed)
+ {
+ this.closed = true;
+ this.headers = null;
+ if (this.properties != null)
+ {
+ this.properties.Dispose();
+ this.properties = null;
+ }
+
+ this.bodyBytes = null;
+ this.readerQuotas = null;
+ }
+ }
+
+ public override Message CreateMessage()
+ {
+ if (this.closed)
+ {
+ throw new ObjectDisposedException("message");
+ }
+
+ return new RawMessage(this.headers, this.properties, this.bodyBytes, this.index, this.count, this.readerQuotas);
+ }
+ }
+ }
+}
diff --git a/wcf/src/Apache/Qpid/Channel/RawMessageEncoder.cs b/wcf/src/Apache/Qpid/Channel/RawMessageEncoder.cs
new file mode 100644
index 0000000000..76dae6f6c7
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Channel/RawMessageEncoder.cs
@@ -0,0 +1,113 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.IO;
+ using System.ServiceModel.Channels;
+ using System.ServiceModel;
+ using System.Xml;
+
+
+ class RawMessageEncoder : MessageEncoder
+ {
+ public const string StreamElementName = "Binary";
+
+ XmlDictionaryReaderQuotas readerQuotas;
+
+ public RawMessageEncoder(XmlDictionaryReaderQuotas quotas)
+ {
+ this.readerQuotas = new XmlDictionaryReaderQuotas();
+ if (quotas != null)
+ {
+ quotas.CopyTo(this.readerQuotas);
+ }
+ }
+
+ public override string ContentType
+ {
+ get { return null; }
+ }
+
+ public override bool IsContentTypeSupported(string contentType)
+ {
+ return true;
+ }
+
+ public override string MediaType
+ {
+ get { return null; }
+ }
+
+ public override MessageVersion MessageVersion
+ {
+ get { return MessageVersion.None; }
+ }
+
+ public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
+ {
+ RawMessage message = new RawMessage(buffer.Array, buffer.Offset, buffer.Count, bufferManager, readerQuotas);
+ message.Properties.Encoder = this;
+ return message;
+ }
+
+ public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
+ {
+ RawMessage message = new RawMessage(stream, readerQuotas);
+ message.Properties.Encoder = this;
+ return message;
+ }
+
+ private void CheckType(XmlDictionaryReader reader, XmlNodeType type)
+ {
+ if (reader.NodeType != type)
+ {
+ throw new System.IO.InvalidDataException(String.Format("RawMessageEncoder xml check {0} type should be {1}", type, reader.NodeType));
+ }
+ }
+
+ public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
+ {
+ MemoryStream tempStream = new MemoryStream();
+ this.WriteMessage(message, tempStream);
+ int len = messageOffset + (int)tempStream.Length;
+ byte[] buf = bufferManager.TakeBuffer(len);
+ MemoryStream targetStream = new MemoryStream(buf);
+ if (messageOffset > 0)
+ {
+ targetStream.Seek(messageOffset, SeekOrigin.Begin);
+ }
+
+ tempStream.WriteTo(targetStream);
+ targetStream.Close();
+
+ return new ArraySegment<byte>(buf, messageOffset, len - messageOffset);
+ }
+
+ public override void WriteMessage(Message message, Stream stream)
+ {
+ using (XmlWriter writer = new RawXmlWriter(stream))
+ {
+ message.WriteMessage(writer);
+ writer.Flush();
+ }
+ }
+ }
+}
diff --git a/wcf/src/Apache/Qpid/Channel/RawMessageEncoderFactory.cs b/wcf/src/Apache/Qpid/Channel/RawMessageEncoderFactory.cs
new file mode 100644
index 0000000000..5c015f9a1b
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Channel/RawMessageEncoderFactory.cs
@@ -0,0 +1,45 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.Xml;
+ using System.ServiceModel.Channels;
+
+ internal class RawMessageEncoderFactory : MessageEncoderFactory
+ {
+ RawMessageEncoder encoder;
+
+ public RawMessageEncoderFactory(XmlDictionaryReaderQuotas quotas)
+ {
+ this.encoder = new RawMessageEncoder(quotas);
+ }
+
+ public override MessageEncoder Encoder
+ {
+ get { return this.encoder; }
+ }
+
+ public override MessageVersion MessageVersion
+ {
+ get { return encoder.MessageVersion; }
+ }
+ }
+}
diff --git a/wcf/src/Apache/Qpid/Channel/RawMessageEncodingBindingElement.cs b/wcf/src/Apache/Qpid/Channel/RawMessageEncodingBindingElement.cs
new file mode 100644
index 0000000000..5ec10a976d
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Channel/RawMessageEncodingBindingElement.cs
@@ -0,0 +1,102 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.ServiceModel.Channels;
+
+ public class RawMessageEncodingBindingElement : MessageEncodingBindingElement
+ {
+
+ public RawMessageEncodingBindingElement()
+ : base()
+ {
+ }
+
+ RawMessageEncodingBindingElement(RawMessageEncodingBindingElement originalBindingElement)
+ {
+ }
+
+ public override MessageEncoderFactory CreateMessageEncoderFactory()
+ {
+ return new RawMessageEncoderFactory(null);
+ }
+
+
+ public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
+ {
+ if (context == null)
+ throw new ArgumentNullException("context");
+
+ context.BindingParameters.Add(this);
+ return context.BuildInnerChannelFactory<TChannel>();
+ }
+
+ public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
+ {
+ if (context == null)
+ throw new ArgumentNullException("context");
+
+ return context.CanBuildInnerChannelFactory<TChannel>();
+ }
+
+ public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
+ {
+ if (context == null)
+ throw new ArgumentNullException("context");
+
+ context.BindingParameters.Add(this);
+ return context.BuildInnerChannelListener<TChannel>();
+ }
+
+ public override bool CanBuildChannelListener<TChannel>(BindingContext context)
+ {
+ if (context == null)
+ throw new ArgumentNullException("context");
+
+ context.BindingParameters.Add(this);
+ return context.CanBuildInnerChannelListener<TChannel>();
+ }
+
+
+ public override BindingElement Clone()
+ {
+ return new RawMessageEncodingBindingElement(this);
+ }
+
+
+
+ public override MessageVersion MessageVersion
+ {
+ get
+ {
+ return MessageVersion.None;
+ }
+
+ set
+ {
+ if (value != MessageVersion.None)
+ throw new ArgumentException("Unsupported message version");
+ }
+ }
+
+
+ }
+}
diff --git a/wcf/src/Apache/Qpid/Channel/RawXmlReader.cs b/wcf/src/Apache/Qpid/Channel/RawXmlReader.cs
new file mode 100644
index 0000000000..8fadfce441
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Channel/RawXmlReader.cs
@@ -0,0 +1,353 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.IO;
+ using System.Xml;
+
+ internal class RawXmlReader : XmlDictionaryReader
+ {
+ ////this class presents a hardcoded XML InfoSet: "<rawtag>X</rawtag>" where X is the entire stream content
+
+ private Stream stream;
+ private bool closed;
+ private bool streamOwner;
+ private ReaderPosition position;
+ private string contentAsBase64;
+ private XmlNameTable xmlNameTable;
+ private XmlDictionaryReaderQuotas readerQuotas;
+
+ public RawXmlReader(Stream stream, XmlDictionaryReaderQuotas quotas, bool streamOwner)
+ {
+ this.stream = stream;
+ this.streamOwner = streamOwner;
+ if (quotas == null)
+ {
+ this.readerQuotas = new XmlDictionaryReaderQuotas();
+ }
+ else
+ {
+ this.readerQuotas = quotas;
+ }
+ }
+
+ private enum ReaderPosition
+ {
+ None,
+ StartElement,
+ Content,
+ EndElement,
+ EOF
+ }
+
+ public override int AttributeCount
+ {
+ get { return 0; }
+ }
+
+ public override string BaseURI
+ {
+ get { return string.Empty; }
+ }
+
+ public override int Depth
+ {
+ get { return (this.position == ReaderPosition.Content) ? 1 : 0; }
+ }
+
+ public override bool EOF
+ {
+ get { return this.position == ReaderPosition.EOF; }
+ }
+
+ public override bool HasAttributes
+ {
+ get { return false; }
+ }
+
+ public override bool HasValue
+ {
+ get { return this.position == ReaderPosition.Content; }
+ }
+
+ public override bool IsEmptyElement
+ {
+ get { return false; }
+ }
+
+ public override string LocalName
+ {
+ get
+ {
+ if (this.position == ReaderPosition.StartElement)
+ {
+ return RawMessageEncoder.StreamElementName;
+ }
+
+ return null;
+ }
+ }
+
+ public override string NamespaceURI
+ {
+ get { return string.Empty; }
+ }
+
+ public override XmlNameTable NameTable
+ {
+ get
+ {
+ if (this.xmlNameTable == null)
+ {
+ this.xmlNameTable = new NameTable();
+ this.xmlNameTable.Add(RawMessageEncoder.StreamElementName);
+ }
+
+ return this.xmlNameTable;
+ }
+ }
+
+ public override XmlNodeType NodeType
+ {
+ get
+ {
+ switch (this.position)
+ {
+ case ReaderPosition.StartElement:
+ return XmlNodeType.Element;
+ case ReaderPosition.Content:
+ return XmlNodeType.Text;
+ case ReaderPosition.EndElement:
+ return XmlNodeType.EndElement;
+ default:
+ // and StreamPosition.EOF
+ return XmlNodeType.None;
+ }
+ }
+ }
+
+ public override string Prefix
+ {
+ get { return string.Empty; }
+ }
+
+ public override ReadState ReadState
+ {
+ get
+ {
+ switch (this.position)
+ {
+ case ReaderPosition.None:
+ return ReadState.Initial;
+ case ReaderPosition.StartElement:
+ case ReaderPosition.Content:
+ case ReaderPosition.EndElement:
+ return ReadState.Interactive;
+ case ReaderPosition.EOF:
+ return ReadState.Closed;
+ default:
+ return ReadState.Error;
+ }
+ }
+ }
+
+ public override string Value
+ {
+ get
+ {
+ switch (this.position)
+ {
+ case ReaderPosition.Content:
+ if (this.contentAsBase64 == null)
+ {
+ this.contentAsBase64 = Convert.ToBase64String(this.ReadContentAsBase64());
+ }
+
+ return this.contentAsBase64;
+
+ default:
+ return string.Empty;
+ }
+ }
+ }
+
+ public override void Close()
+ {
+ if (!this.closed)
+ {
+ this.closed = true;
+ this.position = ReaderPosition.EOF;
+ this.readerQuotas = null;
+ if (this.streamOwner)
+ {
+ this.stream.Close();
+ }
+ }
+ }
+
+ public override string GetAttribute(int i)
+ {
+ throw new ArgumentOutOfRangeException("i", i, "Argument not in set of valid values");
+ }
+
+ public override string GetAttribute(string name, string namespaceURI)
+ {
+ return null;
+ }
+
+ public override string GetAttribute(string name)
+ {
+ return null;
+ }
+
+ public override string LookupNamespace(string prefix)
+ {
+ if (prefix == string.Empty)
+ {
+ return string.Empty;
+ }
+ else if (prefix == "xml")
+ {
+ return "http://www.w3.org/XML/1998/namespace";
+ }
+ else if (prefix == "xmlns")
+ {
+ return "http://www.w3.org/2000/xmlns/";
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public override bool MoveToAttribute(string name, string ns)
+ {
+ return false;
+ }
+
+ public override bool MoveToAttribute(string name)
+ {
+ return false;
+ }
+
+ public override bool MoveToElement()
+ {
+ if (this.position == ReaderPosition.None)
+ {
+ this.position = ReaderPosition.StartElement;
+ return true;
+ }
+
+ return false;
+ }
+
+ public override bool MoveToFirstAttribute()
+ {
+ return false;
+ }
+
+ public override bool MoveToNextAttribute()
+ {
+ return false;
+ }
+
+ public override bool Read()
+ {
+ switch (this.position)
+ {
+ case ReaderPosition.None:
+ this.position = ReaderPosition.StartElement;
+ return true;
+ case ReaderPosition.StartElement:
+ this.position = ReaderPosition.Content;
+ return true;
+ case ReaderPosition.Content:
+ this.position = ReaderPosition.EndElement;
+ return true;
+ case ReaderPosition.EndElement:
+ this.position = ReaderPosition.EOF;
+ return false;
+ case ReaderPosition.EOF:
+ return false;
+ default:
+ return false;
+ }
+ }
+
+ public override bool ReadAttributeValue()
+ {
+ return false;
+ }
+
+ public override int ReadContentAsBase64(byte[] buffer, int index, int count)
+ {
+ if (buffer == null)
+ {
+ throw new ArgumentNullException("buffer");
+ }
+
+ if (this.position != ReaderPosition.Content)
+ {
+ throw new InvalidOperationException("XML reader not in Element");
+ }
+
+ if (count == 0)
+ {
+ return 0;
+ }
+
+ int readCount = this.stream.Read(buffer, index, count);
+ if (readCount == 0)
+ {
+ this.position = ReaderPosition.EndElement;
+ }
+
+ return readCount;
+ }
+
+ public override int ReadContentAsBinHex(byte[] buffer, int index, int count)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void ResolveEntity()
+ {
+ throw new NotSupportedException();
+ }
+
+ public override bool TryGetBase64ContentLength(out int length)
+ {
+ // The whole stream is this one element
+ if (!this.closed && this.stream.CanSeek)
+ {
+ long streamLength = this.stream.Length;
+ if (streamLength <= int.MaxValue)
+ {
+ length = (int)streamLength;
+ return true;
+ }
+ }
+
+ length = -1;
+ return false;
+ }
+ }
+}
diff --git a/wcf/src/Apache/Qpid/Channel/RawXmlWriter.cs b/wcf/src/Apache/Qpid/Channel/RawXmlWriter.cs
new file mode 100644
index 0000000000..7d05b70807
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Channel/RawXmlWriter.cs
@@ -0,0 +1,221 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Channel
+{
+ using System;
+ using System.IO;
+ using System.Xml;
+
+ internal sealed class RawXmlWriter : XmlDictionaryWriter
+ {
+
+ WriteState state;
+ Stream stream;
+ bool closed;
+ bool rawWritingEnabled;
+
+ public RawXmlWriter(Stream stream)
+ {
+ if (stream == null)
+ {
+ throw new ArgumentNullException("Stream");
+ }
+
+ this.stream = stream;
+ this.state = WriteState.Start;
+ }
+
+ public override WriteState WriteState
+ {
+ get
+ {
+ return this.state;
+ }
+ }
+
+ public override void Close()
+ {
+ if (!this.closed)
+ {
+ this.closed = true;
+ this.state = WriteState.Closed;
+ this.rawWritingEnabled = false;
+ }
+ }
+
+ public override void Flush()
+ {
+ this.ThrowIfClosed();
+ this.stream.Flush();
+ }
+
+ public override string LookupPrefix(string ns)
+ {
+ return null;
+ }
+
+ public override void WriteBase64(byte[] buffer, int index, int count)
+ {
+ if (buffer == null)
+ {
+ throw new ArgumentNullException("buffer");
+ }
+
+ ThrowIfClosed();
+
+ if (!this.rawWritingEnabled)
+ {
+ throw new InvalidOperationException("XmlWriter not in Element");
+ }
+
+ this.stream.Write(buffer, index, count);
+ this.state = WriteState.Content;
+ }
+
+ public override void WriteStartElement(string prefix, string localName, string ns)
+ {
+ ThrowIfClosed();
+ if (this.state != WriteState.Start)
+ {
+ throw new InvalidOperationException("Start Element Already Called");
+ }
+
+ if (!string.IsNullOrEmpty(prefix) || !string.IsNullOrEmpty(ns) || localName != RawMessageEncoder.StreamElementName)
+ {
+ throw new XmlException("Wrong XML Start Element Name");
+ }
+ this.state = WriteState.Element;
+ this.rawWritingEnabled = true;
+ }
+
+ public override void WriteEndElement()
+ {
+ ThrowIfClosed();
+ if (!this.rawWritingEnabled)
+ {
+ throw new InvalidOperationException("Unexpected End Element");
+ }
+ this.rawWritingEnabled = false;
+ }
+
+ public override void WriteFullEndElement()
+ {
+ this.WriteEndElement();
+ }
+
+ public override void WriteEndDocument()
+ {
+ this.rawWritingEnabled = false;
+ this.ThrowIfClosed();
+ }
+
+ public override void WriteStartDocument()
+ {
+ this.rawWritingEnabled = false;
+ this.ThrowIfClosed();
+ }
+
+ public override void WriteStartDocument(bool standalone)
+ {
+ this.rawWritingEnabled = false;
+ this.ThrowIfClosed();
+ }
+
+ private void ThrowIfClosed()
+ {
+ if (this.closed)
+ {
+ throw new InvalidOperationException("XML Writer closed");
+ }
+ }
+
+
+ public override void WriteString(string text)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteCData(string text)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteCharEntity(char ch)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteChars(char[] buffer, int index, int count)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteComment(string text)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteDocType(string name, string pubid, string sysid, string subset)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteEndAttribute()
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteEntityRef(string name)
+ {
+ throw new NotSupportedException();
+ }
+
+
+ public override void WriteProcessingInstruction(string name, string text)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteRaw(string data)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteRaw(char[] buffer, int index, int count)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteStartAttribute(string prefix, string localName, string ns)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteSurrogateCharEntity(char lowChar, char highChar)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void WriteWhitespace(string ws)
+ {
+ throw new NotSupportedException();
+ }
+ }
+}
diff --git a/wcf/src/Apache/Qpid/DtcPlugin/DtcPlugin.cpp b/wcf/src/Apache/Qpid/DtcPlugin/DtcPlugin.cpp
new file mode 100644
index 0000000000..f9d8bd8521
--- /dev/null
+++ b/wcf/src/Apache/Qpid/DtcPlugin/DtcPlugin.cpp
@@ -0,0 +1,664 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+
+//
+// This module provides the backend recovery driver for Windows resource managers based on
+// the IDtcToXaHelperSinglePipe interface. The dll is loaded (LoadLibrary) directly into DTC
+// itself and runs at a different protection level from the resource manager instance, which
+// runs inside the application.
+//
+// The DTC dynamically loads this file, calls GetXaSwitch() to access the XA interface
+// implementation and unloads the dll when done.
+//
+// This DTC plugin is only called for registration and recovery. Each time the application
+// registers the Qpid resource manager with DTC, the plugin is loaded and a successful
+// connection via xa_open is confirmed before completing registration and saving the DSN
+// connection string in the DTC log for possible recovery. On recovery, the DSN is re-used to
+// restablish a new connection with the broker and perform recovery.
+//
+// Because this plugin is not involved in coordinating any active transactions it only needs to
+// partially implement the XA interface.
+//
+// For the same reason, the locking strategy is simple. A single global lock is used.
+// Whenever networking activity is about to take place, the lock is relinquished and retaken
+// soon thereafter.
+
+
+#include <windows.h>
+#include <transact.h>
+#include <xolehlp.h>
+#include <txdtc.h>
+#include <xa.h>
+
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/Connection.h"
+
+
+#include <map>
+#include <iostream>
+#include <fstream>
+
+namespace Apache {
+namespace Qpid {
+namespace DtcPlugin {
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace qpid::framing::dtx;
+
+class ResourceManager
+{
+private:
+ Connection qpidConnection;
+ Session qpidSession;
+ bool active;
+ std::string host;
+ int port;
+ int rmid;
+ std::vector<qpid::framing::Xid> inDoubtXids;
+ // current scan position, or -1 if no scan
+ int cursor;
+public:
+ ResourceManager(int id, std::string h, int p) : rmid(id), host(h), port(p), active(false), cursor(-1) {}
+ ~ResourceManager() {}
+ INT open();
+ INT close();
+ INT commit(XID *xid);
+ INT rollback(XID *xid);
+ INT recover(XID *xids, long count, long flags);
+};
+
+
+CRITICAL_SECTION rmLock;
+
+std::map<int, ResourceManager*> rmMap;
+HMODULE thisDll = NULL;
+bool memLocked = false;
+
+#define QPIDHMCHARS 512
+
+void pinDll() {
+ if (!memLocked) {
+ char thisDllName[QPIDHMCHARS];
+ HMODULE ignore;
+
+ DWORD nc = GetModuleFileName(thisDll, thisDllName, QPIDHMCHARS);
+ if ((nc > 0) && (nc < QPIDHMCHARS)) {
+ memLocked = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN, thisDllName, &ignore);
+ }
+ }
+}
+
+
+void XaToQpid(XID &winXid, Xid &qpidXid) {
+ // convert from XA defined structure XID to the Qpid framing structure
+ qpidXid.setFormat((uint32_t) winXid.formatID);
+ int bqualPos = 0;
+ if (winXid.gtrid_length > 0) {
+ qpidXid.setGlobalId(std::string(winXid.data, winXid.gtrid_length));
+ bqualPos = winXid.gtrid_length;
+ }
+ if (winXid.bqual_length > 0) {
+ qpidXid.setBranchId(std::string(winXid.data + bqualPos, winXid.bqual_length));
+ }
+}
+
+
+// this function assumes that the qpidXid has already been validated for the memory copy
+
+void QpidToXa(Xid &qpidXid, XID &winXid) {
+ // convert from the Qpid framing structure to the XA defined structure XID
+ winXid.formatID = qpidXid.getFormat();
+
+ const std::string& global_s = qpidXid.getGlobalId();
+ size_t gl = global_s.size();
+ winXid.gtrid_length = (long) gl;
+ if (gl > 0)
+ global_s.copy(winXid.data, gl);
+
+ const std::string branch_s = qpidXid.getBranchId();
+ size_t bl = branch_s.size();
+ winXid.bqual_length = (long) bl;
+ if (bl > 0)
+ branch_s.copy(winXid.data + gl, bl);
+}
+
+
+/* parse string from AmqpConnection.h
+
+ this info will eventually include authentication tokens
+
+ dataSourceName = String::Format("{0}.{1}..AMQP.{2}.{3}", port, host,
+ System::Diagnostics::Process::GetCurrentProcess()->Id,
+ AppDomain::CurrentDomain->Id);
+*/
+
+bool parseDsn (const char *dsn, std::string& host, int& port) {
+ if (dsn == NULL)
+ return false;
+
+ size_t len = strnlen(dsn, 1025);
+ if (len > 1024)
+ return false;
+
+ int firstDot = 0;
+ for (int i = 0; i < len; i++)
+ if (dsn[i] == '.') {
+ firstDot = i;
+ break;
+ }
+ if (!firstDot)
+ return false;
+
+ // look for 2 dots side by side to indicate end of the host
+ int doubleDot = 0;
+ for (int i = firstDot + 1; i < (len - 1); i++)
+ if ((dsn[i] == '.') && (dsn[i+1] == '.')) {
+ doubleDot = i;
+ break;
+ }
+ if (!doubleDot)
+ return false;
+
+ port = 0;
+ for (int i = 0; i < firstDot; i++) {
+ char c = dsn[i];
+ if ((c < '0') || (c > '9'))
+ return false;
+ port = (10 * port) + (c - '0');
+ }
+
+ host.assign(dsn + firstDot + 1, (doubleDot - firstDot) - 1);
+ return true;
+}
+
+
+INT ResourceManager::open() {
+ INT rv = XAER_RMERR; // placeholder until we successfully connect to resource
+ active = true;
+ LeaveCriticalSection(&rmLock);
+
+ try {
+ qpidConnection.open(host, port);
+ qpidSession = qpidConnection.newSession();
+ rv = XA_OK;
+/*
+TODO: logging
+ } catch (const qpid::Exception& error) {
+ // log it
+ } catch (const std::exception& e2) {
+ // log it
+*/
+ } catch (...) {
+ // TODO: log it
+ }
+
+ EnterCriticalSection(&rmLock);
+ active = false;
+ return rv;
+}
+
+
+INT ResourceManager::close() {
+ // should never be called when already sending other commands to broker
+ if (active)
+ return XAER_PROTO;
+
+ INT rv = XAER_RMERR; // placeholder until we successfully close resource
+ active = true;
+ LeaveCriticalSection(&rmLock);
+ try {
+ if (qpidSession.isValid()) {
+ qpidSession.close();
+ }
+ if (qpidConnection.isOpen()) {
+ qpidConnection.close();
+ }
+ } catch (...) {
+ // TODO: log it
+ }
+
+ EnterCriticalSection(&rmLock);
+ active = false;
+
+ if (!qpidConnection.isOpen()) {
+ rv = XA_OK;
+ }
+ return rv;
+}
+
+
+INT ResourceManager::commit(XID *xid) {
+ if (active)
+ return XAER_PROTO;
+
+ INT rv = XAER_RMFAIL;
+ active = true;
+ LeaveCriticalSection(&rmLock);
+
+ try {
+ qpid::framing::Xid qpidXid;
+ XaToQpid(*xid, qpidXid);
+
+ XaResult xaResult = qpidSession.dtxCommit(qpidXid, false, true);
+ if (xaResult.hasStatus()) {
+ uint16_t status = xaResult.getStatus();
+ switch ((XaStatus) status) {
+ case XA_STATUS_XA_OK:
+ case XA_STATUS_XA_RDONLY:
+ case XA_STATUS_XA_HEURCOM:
+ rv = XA_OK;
+ break;
+
+ default:
+ // commit failed and a retry won't fix
+ rv = XAER_RMERR;
+ break;
+ }
+
+ }
+ } catch (...) {
+ // TODO: log it
+ }
+
+ EnterCriticalSection(&rmLock);
+ active = false;
+ return rv;
+}
+
+
+INT ResourceManager::rollback(XID *xid) {
+ if (active)
+ return XAER_PROTO;
+
+ INT rv = XAER_RMFAIL;
+ active = true;
+ LeaveCriticalSection(&rmLock);
+
+ try {
+ qpid::framing::Xid qpidXid;
+ XaToQpid(*xid, qpidXid);
+
+ XaResult xaResult = qpidSession.dtxRollback(qpidXid, true);
+ if (xaResult.hasStatus()) {
+ uint16_t status = xaResult.getStatus();
+ switch ((XaStatus) status) {
+ case XA_STATUS_XA_OK:
+ case XA_STATUS_XA_HEURRB:
+ rv = XA_OK;
+ break;
+
+ default:
+ // RM internal error
+ rv = XA_RBPROTO;
+ break;
+ }
+ }
+ } catch (...) {
+ // TODO: log it
+ }
+
+ EnterCriticalSection(&rmLock);
+ active = false;
+ return rv;
+}
+
+
+INT ResourceManager::recover(XID *xids, long count, long flags) {
+ if (active)
+ return XAER_PROTO;
+
+ if ((xids == NULL) && (count != 0))
+ return XAER_INVAL;
+
+ if (count < 0)
+ return XAER_INVAL;
+
+ if (!(flags & TMSTARTRSCAN) && (cursor == -1))
+ // no existing scan and no scan requested
+ return XAER_INVAL;
+
+ INT status = XA_OK;
+
+ if (flags & TMSTARTRSCAN) {
+ // start a fresh scan
+ cursor = -1;
+ inDoubtXids.clear();
+ active = true;
+ LeaveCriticalSection(&rmLock);
+
+ try {
+ // status if we can't talk to the broker
+ status = XAER_RMFAIL;
+ std::vector<std::string> wireFormatXids;
+
+ DtxRecoverResult dtxrr = qpidSession.dtxRecover(true);
+
+ // status if we can't process the xids
+ status = XAER_RMERR;
+ dtxrr.getInDoubt().collect(wireFormatXids);
+ size_t nXids = wireFormatXids.size();
+
+ if (nXids > 0) {
+ StructHelper decoder;
+ Xid qpidXid;
+ for (int i = 0; i < nXids; i++) {
+ decoder.decode (qpidXid, wireFormatXids[i]);
+ inDoubtXids.push_back(qpidXid);
+ }
+
+ // if we got here the decoder validated the Xids
+ status = XA_OK;
+
+ // make sure none are too big, just in case
+
+ for (int i = 0; i < nXids; i++) {
+ Xid& xid = inDoubtXids[i];
+ size_t l1 = xid.hasGlobalId() ? xid.getGlobalId().size() : 0;
+ size_t l2 = xid.hasBranchId() ? xid.getBranchId().size() : 0;
+ if ((l1 > MAXGTRIDSIZE) || (l2 > MAXBQUALSIZE) ||
+ ((l1 + l2) > XIDDATASIZE)) {
+ status = XAER_RMERR;
+ break;
+ }
+ }
+ }
+ else {
+ // nXids == 0, the previously cleared inDoubtXids is correctly populated
+ status = XA_OK;
+ }
+
+ if (status == XA_OK)
+ cursor = 0;
+ } catch (...) {
+ // TODO: log it
+ }
+
+ EnterCriticalSection(&rmLock);
+ active = false;
+ }
+ else {
+ // TMSTARTRSCAN not set, is there an existing scan to work from?
+ if (cursor == -1)
+ return XAER_INVAL;
+ }
+
+ if (status != XA_OK)
+ return status;
+
+ INT actualCount = count;
+ if (count > 0) {
+ int nAvailable = (int) inDoubtXids.size() - cursor;
+ if (nAvailable < count)
+ actualCount = nAvailable;
+
+ for (int i = 0; i < actualCount; i++) {
+ Xid& qpidXid = inDoubtXids[i + cursor];
+ QpidToXa(qpidXid, xids[i]);
+ }
+ }
+
+ if (flags & TMENDRSCAN) {
+ cursor = -1;
+ inDoubtXids.clear();
+ }
+
+ return actualCount;
+}
+
+
+// Call with lock held
+
+ResourceManager* findRm(int rmid) {
+ if (rmMap.find(rmid) == rmMap.end()) {
+ return NULL;
+ }
+ return rmMap[rmid];
+}
+
+
+INT __cdecl xa_open (char *xa_info, int rmid, long flags) {
+ if (flags & TMASYNC)
+ return XAER_ASYNC;
+
+ INT rv = XAER_RMERR;
+ EnterCriticalSection(&rmLock);
+
+ ResourceManager* rmp = findRm(rmid);
+ if (rmp != NULL) {
+ // error: already in use
+ rv = XAER_PROTO;
+ }
+ else {
+ std::string brokerHost;
+ int brokerPort;
+ if (parseDsn(xa_info, brokerHost, brokerPort)) {
+
+ try {
+ rmp = new ResourceManager(rmid, brokerHost, brokerPort);
+
+ rv = rmp->open();
+ if (rv != XA_OK) {
+ delete (rmp);
+ }
+ else {
+ rmMap[rmid] = rmp;
+ }
+ } catch (...) {}
+ }
+ else {
+ rv = XAER_INVAL;
+ }
+ }
+
+ LeaveCriticalSection(&rmLock);
+ return rv;
+}
+
+
+INT __cdecl xa_close (char *xa_info, int rmid, long flags) {
+ if (flags & TMASYNC)
+ return XAER_ASYNC;
+
+ INT rv = XAER_RMERR;
+
+ EnterCriticalSection(&rmLock);
+ ResourceManager* rmp = findRm(rmid);
+
+ if (rmp == NULL) {
+ // can close multiple times
+ rv = XA_OK;
+ }
+ else {
+ rv = rmp->close();
+ rmMap.erase(rmid);
+ try {
+ delete (rmp);
+ } catch (...) {
+ // TODO: log it
+ }
+ }
+
+ LeaveCriticalSection(&rmLock);
+ return rv;
+}
+
+
+INT __cdecl xa_commit (XID *xid, int rmid, long flags) {
+ if (flags & TMASYNC)
+ return XAER_ASYNC;
+
+ INT rv = XAER_RMFAIL;
+
+ EnterCriticalSection(&rmLock);
+ ResourceManager* rmp = findRm(rmid);
+
+ if (rmp == NULL) {
+ rv = XAER_INVAL;
+ }
+ else {
+ rv = rmp->commit(xid);
+ }
+
+ LeaveCriticalSection(&rmLock);
+ return rv;
+}
+
+
+INT __cdecl xa_rollback (XID *xid, int rmid, long flags) {
+ if (flags & TMASYNC)
+ return XAER_ASYNC;
+
+ INT rv = XAER_RMFAIL;
+
+ EnterCriticalSection(&rmLock);
+ ResourceManager* rmp = findRm(rmid);
+
+ if (rmp == NULL) {
+ rv = XAER_INVAL;
+ }
+ else {
+ rv = rmp->rollback(xid);
+ }
+
+ LeaveCriticalSection(&rmLock);
+ return rv;
+}
+
+
+INT __cdecl xa_recover (XID *xids, long count, int rmid, long flags) {
+ INT rv = XAER_RMFAIL;
+
+ EnterCriticalSection(&rmLock);
+ ResourceManager* rmp = findRm(rmid);
+
+ if (rmp == NULL) {
+ rv = XAER_PROTO;
+ }
+ else {
+ rv = rmp->recover(xids, count, flags);
+ }
+
+ LeaveCriticalSection(&rmLock);
+ return rv;
+}
+
+
+INT __cdecl xa_start (XID *xid, int rmid, long flags) {
+ // not used in recovery
+ return XAER_PROTO;
+}
+
+
+INT __cdecl xa_end (XID *xid, int rmid, long flags) {
+ // not used in recovery
+ return XAER_PROTO;
+}
+
+
+INT __cdecl xa_prepare (XID *xid, int rmid, long flags) {
+ // not used in recovery
+ return XAER_PROTO;
+}
+
+
+INT __cdecl xa_forget (XID *xid, int rmid, long flags) {
+ // not used in recovery
+ return XAER_PROTO;
+}
+
+
+INT __cdecl xa_complete (int *handle, int *retval, int rmid, long flags) {
+ // not used in recovery
+ return XAER_PROTO;
+}
+
+
+
+xa_switch_t xaSwitch;
+
+HRESULT __cdecl GetQpidXaSwitch (DWORD XaSwitchFlags, xa_switch_t ** ppXaSwitch)
+{
+ // needed for now due to implicit use of FreeLibrary in WSACleanup() in qpid/cpp/src/qpid/sys/windows/Socket.cpp
+ pinDll();
+
+ if (xaSwitch.xa_open_entry != xa_open) {
+
+ xaSwitch.xa_open_entry = xa_open;
+ xaSwitch.xa_close_entry = xa_close;
+ xaSwitch.xa_start_entry = xa_start;
+ xaSwitch.xa_end_entry = xa_end;
+ xaSwitch.xa_prepare_entry = xa_prepare;
+ xaSwitch.xa_commit_entry = xa_commit;
+ xaSwitch.xa_rollback_entry = xa_rollback;
+ xaSwitch.xa_recover_entry = xa_recover;
+ xaSwitch.xa_forget_entry = xa_forget;
+ xaSwitch.xa_complete_entry = xa_complete;
+
+ strcpy_s(xaSwitch.name, RMNAMESZ, "qpidxarm");
+ xaSwitch.flags = TMNOMIGRATE;
+ xaSwitch.version = 0;
+ }
+ *ppXaSwitch = &xaSwitch;
+ return S_OK;
+}
+
+
+
+
+}}} // namespace Apache::Qpid::DtcPlugin
+
+
+// GetXaSwitch
+
+extern "C" {
+
+ __declspec(dllexport) HRESULT __cdecl GetXaSwitch (DWORD XaSwitchFlags, xa_switch_t ** ppXaSwitch)
+ {
+ return Apache::Qpid::DtcPlugin::GetQpidXaSwitch (XaSwitchFlags, ppXaSwitch);
+ }
+}
+
+
+// dllmain
+
+BOOL APIENTRY DllMain( HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved)
+{
+
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ InitializeCriticalSection(&Apache::Qpid::DtcPlugin::rmLock);
+ Apache::Qpid::DtcPlugin::thisDll = hModule;
+ break;
+
+ case DLL_PROCESS_DETACH:
+ DeleteCriticalSection(&Apache::Qpid::DtcPlugin::rmLock);
+ break;
+
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
diff --git a/wcf/src/Apache/Qpid/Interop/AmqpConnection.cpp b/wcf/src/Apache/Qpid/Interop/AmqpConnection.cpp
new file mode 100644
index 0000000000..c3afdf2280
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/AmqpConnection.cpp
@@ -0,0 +1,179 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#include <windows.h>
+#include <msclr\lock.h>
+#include <oletx2xa.h>
+
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/framing/FrameSet.h"
+
+#include "AmqpConnection.h"
+#include "AmqpSession.h"
+#include "QpidMarshal.h"
+#include "QpidException.h"
+#include "DtxResourceManager.h"
+#include "XaTransaction.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+using namespace msclr;
+
+using namespace qpid::client;
+using namespace std;
+
+
+// Note on locks: Use "this" for fast counting and idle/busy
+// notifications. Use the "sessions" list to serialize session
+// creation/reaping and overall tear down.
+// TODO: switch "this" lock to separate non-visible Object.
+
+
+AmqpConnection::AmqpConnection(String^ server, int port) :
+ connectionp(NULL),
+ busyCount(0),
+ disposed(false)
+{
+ bool success = false;
+ System::Exception^ openException = nullptr;
+ sessions = gcnew Collections::Generic::List<AmqpSession^>();
+
+ try {
+ connectionp = new Connection;
+ connectionp->open (QpidMarshal::ToNative(server), port);
+ // TODO: registerFailureCallback for failover
+ success = true;
+ const ConnectionSettings& settings = connectionp->getNegotiatedSettings();
+ this->maxFrameSize = settings.maxFrameSize;
+ this->host = server;
+ this->port = port;
+ this->isOpen = true;
+ } catch (const qpid::Exception& error) {
+ String^ errmsg = gcnew String(error.what());
+ openException = gcnew QpidException(errmsg);
+ } finally {
+ if (!success) {
+ Cleanup();
+ if (openException == nullptr) {
+ openException = gcnew QpidException ("unknown connection failure");
+ }
+ throw openException;
+ }
+ }
+}
+
+AmqpConnection^ AmqpConnection::Clone() {
+ if (disposed)
+ throw gcnew ObjectDisposedException("AmqpConnection.Clone");
+ return gcnew AmqpConnection (this->host, this->port);
+}
+
+void AmqpConnection::Cleanup()
+{
+ {
+ lock l(sessions);
+ if (disposed)
+ return;
+ disposed = true;
+ }
+
+ try {
+ // let the child sessions clean up
+
+ for each(AmqpSession^ s in sessions) {
+ s->ConnectionClosed();
+ }
+ }
+ finally
+ {
+ if (connectionp != NULL) {
+ isOpen = false;
+ connectionp->close();
+ delete connectionp;
+ connectionp = NULL;
+ }
+ }
+}
+
+AmqpConnection::~AmqpConnection()
+{
+ Cleanup();
+}
+
+AmqpConnection::!AmqpConnection()
+{
+ Cleanup();
+}
+
+void AmqpConnection::Close()
+{
+ // Simulate Dispose()...
+ Cleanup();
+ GC::SuppressFinalize(this);
+}
+
+AmqpSession^ AmqpConnection::CreateSession()
+{
+ lock l(sessions);
+ if (disposed) {
+ throw gcnew ObjectDisposedException("AmqpConnection");
+ }
+ AmqpSession^ session = gcnew AmqpSession(this, connectionp);
+ sessions->Add(session);
+ return session;
+}
+
+// called whenever a child session becomes newly busy (a first reader or writer since last idle)
+
+void AmqpConnection::NotifyBusy()
+{
+ bool changed = false;
+ {
+ lock l(this);
+ if (busyCount++ == 0)
+ changed = true;
+ }
+}
+
+// called whenever a child session becomes newly idle (a last reader or writer has closed)
+// The connection is idle when none of its child sessions are busy
+
+void AmqpConnection::NotifyIdle()
+{
+ bool connectionIdle = false;
+ {
+ lock l(this);
+ if (--busyCount == 0)
+ connectionIdle = true;
+ }
+ if (connectionIdle) {
+ OnConnectionIdle(this, System::EventArgs::Empty);
+ }
+}
+
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/wcf/src/Apache/Qpid/Interop/AmqpConnection.h b/wcf/src/Apache/Qpid/Interop/AmqpConnection.h
new file mode 100644
index 0000000000..6533185fa1
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/AmqpConnection.h
@@ -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.
+*/
+
+#pragma once
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace std;
+using namespace qpid::client;
+
+ref class AmqpSession;
+ref class DtxResourceManager;
+
+public delegate void ConnectionIdleEventHandler(Object^ sender, EventArgs^ eventArgs);
+
+public ref class AmqpConnection
+{
+private:
+ Connection* connectionp;
+ String^ host;
+ int port;
+ bool disposed;
+ Collections::Generic::List<AmqpSession^>^ sessions;
+ bool isOpen;
+ int busyCount;
+ int maxFrameSize;
+ DtxResourceManager^ dtxResourceManager;
+ void Cleanup();
+ // unique string used for distributed transactions
+ String^ dataSourceName;
+
+ internal:
+ void NotifyBusy();
+ void NotifyIdle();
+ AmqpConnection^ Clone();
+
+ property int MaxFrameSize {
+ int get () { return maxFrameSize; }
+ }
+
+ property DtxResourceManager^ CachedResourceManager {
+ DtxResourceManager^ get () { return dtxResourceManager; }
+ void set (DtxResourceManager^ value) { dtxResourceManager = value; }
+ }
+
+ property String^ DataSourceName {
+ // Note: any change to this format has to be reflected in the DTC plugin's xa_open()
+ String^ get() {
+ if (dataSourceName == nullptr) {
+ dataSourceName = String::Format("{0}.{1}..AMQP.{2}.{3}", port, host,
+ System::Diagnostics::Process::GetCurrentProcess()->Id,
+ AppDomain::CurrentDomain->Id);
+ }
+ return dataSourceName;
+ }
+ }
+
+public:
+ AmqpConnection(System::String^ server, int port);
+ ~AmqpConnection();
+ !AmqpConnection();
+ void Close();
+ AmqpSession^ CreateSession();
+ event ConnectionIdleEventHandler^ OnConnectionIdle;
+
+ property bool IsOpen {
+ bool get() { return isOpen; }
+ };
+
+ property bool IsIdle {
+ bool get() { return (busyCount == 0); }
+ }
+};
+
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/wcf/src/Apache/Qpid/Interop/AmqpMessage.cpp b/wcf/src/Apache/Qpid/Interop/AmqpMessage.cpp
new file mode 100644
index 0000000000..5c333aff60
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/AmqpMessage.cpp
@@ -0,0 +1,76 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#include <windows.h>
+#include <msclr\lock.h>
+
+#include "qpid/client/AsyncSession.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/framing/AMQFrame.h"
+
+#include "MessageBodyStream.h"
+#include "AmqpMessage.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Threading;
+using namespace msclr;
+
+using namespace Apache::Qpid::AmqpTypes;
+
+AmqpMessage::AmqpMessage(MessageBodyStream ^mbs) :
+ messageBodyStream(mbs),
+ disposed(false)
+{
+}
+
+void AmqpMessage::Cleanup()
+{
+ {
+ lock l(this);
+ if (disposed)
+ return;
+
+ disposed = true;
+ }
+
+ messageBodyStream->Close();
+}
+
+AmqpMessage::~AmqpMessage()
+{
+ Cleanup();
+}
+
+AmqpMessage::!AmqpMessage()
+{
+ Cleanup();
+}
+
+void AmqpMessage::Close()
+{
+ // Simulate Dispose()...
+ Cleanup();
+ GC::SuppressFinalize(this);
+}
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/wcf/src/Apache/Qpid/Interop/AmqpMessage.h b/wcf/src/Apache/Qpid/Interop/AmqpMessage.h
new file mode 100644
index 0000000000..f0801d30dc
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/AmqpMessage.h
@@ -0,0 +1,61 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+
+using namespace qpid::client;
+using namespace std;
+
+
+
+public ref class AmqpMessage
+{
+private:
+ MessageBodyStream^ messageBodyStream;
+ AmqpTypes::AmqpProperties^ amqpProperties;
+ bool disposed;
+ void Cleanup();
+
+internal:
+ AmqpMessage(MessageBodyStream ^bstream);
+
+public:
+ ~AmqpMessage();
+ !AmqpMessage();
+ void Close();
+
+ property AmqpTypes::AmqpProperties^ Properties {
+ AmqpTypes::AmqpProperties^ get () { return amqpProperties; }
+ void set(AmqpTypes::AmqpProperties^ p) { amqpProperties = p; }
+ }
+
+ property System::IO::Stream^ BodyStream {
+ System::IO::Stream^ get() { return messageBodyStream; }
+ }
+};
+
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/wcf/src/Apache/Qpid/Interop/AmqpSession.cpp b/wcf/src/Apache/Qpid/Interop/AmqpSession.cpp
new file mode 100644
index 0000000000..d2adb41205
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/AmqpSession.cpp
@@ -0,0 +1,612 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#include <windows.h>
+#include <msclr\lock.h>
+#include <oletx2xa.h>
+
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/SessionImpl.h"
+#include "qpid/client/SessionBase_0_10Access.h"
+#include "qpid/client/Message.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/client/Future.h"
+#include "qpid/framing/Xid.h"
+
+#include "AmqpConnection.h"
+#include "AmqpSession.h"
+#include "AmqpMessage.h"
+#include "MessageBodyStream.h"
+#include "InputLink.h"
+#include "OutputLink.h"
+#include "QpidMarshal.h"
+#include "QpidException.h"
+#include "XaTransaction.h"
+#include "DtxResourceManager.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+using namespace System::Transactions;
+using namespace msclr;
+
+using namespace qpid::client;
+using namespace std;
+
+
+AmqpSession::AmqpSession(AmqpConnection^ conn, qpid::client::Connection* qpidConnectionp) :
+ connection(conn),
+ sessionp(NULL),
+ sessionImplp(NULL),
+ subs_mgrp(NULL),
+ helperRunning(false),
+ openCount(0),
+ syncCount(0),
+ closing(false),
+ dtxEnabled(false)
+{
+ bool success = false;
+ try {
+ sessionp = new qpid::client::AsyncSession;
+ *sessionp = qpidConnectionp->newSession();
+ subs_mgrp = new SubscriptionManager (*sessionp);
+ waiters = gcnew Collections::Generic::List<CompletionWaiter^>();
+ sessionLock = waiters; // waiters convenient and not publicly visible
+ openCloseLock = gcnew Object();
+ success = true;
+ } finally {
+ if (!success) {
+ Cleanup();
+ // TODO: include inner exception information
+ throw gcnew QpidException ("session creation failure");
+ }
+ }
+}
+
+
+void AmqpSession::Cleanup()
+{
+ bool connected = connection->IsOpen;
+
+ if (subs_mgrp != NULL) {
+ if (connected)
+ subs_mgrp->stop();
+ delete subs_mgrp;
+ subs_mgrp = NULL;
+ }
+
+ if (sessionp != NULL) {
+ if (connected) {
+ sessionp->close();
+ }
+ delete sessionp;
+ sessionp = NULL;
+ sessionImplp = NULL;
+ }
+}
+
+
+static qpid::framing::Xid& getXid(XaTransaction^ xaTx)
+{
+ return *((qpid::framing::Xid *)xaTx->XidHandle.ToPointer());
+}
+
+
+void AmqpSession::CheckOpen()
+{
+ if (closing)
+ throw gcnew ObjectDisposedException("AmqpSession");
+}
+
+
+// Called by the parent AmqpConnection
+
+void AmqpSession::ConnectionClosed()
+{
+ lock l(sessionLock);
+
+ if (closing)
+ return;
+
+ closing = true;
+
+ if (connection->IsOpen) {
+ // send closing handshakes...
+
+ if (dtxEnabled) {
+ // session may close before all its transactions complete, at least force the phase 0 flush
+ if (pendingTransactions->Count > 0) {
+ array<XaTransaction^>^ txArray = pendingTransactions->ToArray();
+ l.release();
+ for each (XaTransaction^ xaTx in txArray) {
+ //xaTx->SessionClosing(this);
+ xaTx->WaitForCompletion();
+ }
+ l.acquire();
+ }
+ }
+
+ WaitLastSync (%l);
+ // Assert pendingTransactions->Count == 0
+
+ if (openXaTransaction != nullptr) {
+ // send final dtxend
+ sessionp->dtxEnd(getXid(openXaTransaction), false, true, false);
+ openXaTransaction = nullptr;
+ openSystemTransaction = nullptr;
+ // this operation will complete by the time Cleanup() returns
+ }
+ }
+
+ Cleanup();
+}
+
+InputLink^ AmqpSession::CreateInputLink(System::String^ sourceQueue)
+{
+ return CreateInputLink(sourceQueue, true, false, nullptr, nullptr);
+}
+
+InputLink^ AmqpSession::CreateInputLink(System::String^ sourceQueue, bool exclusive, bool temporary,
+ System::String^ filterKey, System::String^ exchange)
+{
+ lock ocl(openCloseLock);
+ lock l(sessionLock);
+ CheckOpen();
+
+ InputLink^ link = gcnew InputLink (this, sourceQueue, sessionp, subs_mgrp, exclusive, temporary, filterKey, exchange);
+ {
+ if (openCount == 0) {
+ l.release();
+ connection->NotifyBusy();
+ }
+ openCount++;
+ }
+ return link;
+}
+
+OutputLink^ AmqpSession::CreateOutputLink(System::String^ targetQueue)
+{
+ lock ocl(openCloseLock);
+ lock l(sessionLock);
+ CheckOpen();
+
+ OutputLink^ link = gcnew OutputLink (this, targetQueue);
+
+ if (sessionImplp == NULL) {
+ // not needed unless sending messages
+ SessionBase_0_10Access sa(*sessionp);
+ boost::shared_ptr<SessionImpl> sip = sa.get();
+ sessionImplp = sip.get();
+ }
+
+ if (openCount == 0) {
+ l.release();
+ connection->NotifyBusy();
+ }
+ openCount++;
+
+ return link;
+}
+
+
+// called whenever a child InputLink or OutputLink is closed or finalized
+void AmqpSession::NotifyClosed()
+{
+ lock ocl(openCloseLock);
+ openCount--;
+ if (openCount == 0) {
+ connection->NotifyIdle();
+ }
+}
+
+
+CompletionWaiter^ AmqpSession::SendMessage (System::String^ queue, MessageBodyStream ^mbody, TimeSpan timeout, bool async, AsyncCallback^ callback, Object^ state)
+{
+ lock l(sessionLock);
+
+ // delimit with session dtx commands depending on the transaction context
+ UpdateTransactionState(%l);
+
+ CheckOpen();
+
+ bool syncPending = false;
+
+ // create an AMQP message.transfer command to use with the partial frameset from the MessageBodyStream
+
+ std::string exname = QpidMarshal::ToNative(queue);
+ FrameSet *framesetp = (FrameSet *) mbody->GetFrameSet().ToPointer();
+ uint8_t acceptMode=1;
+ uint8_t acquireMode=0;
+ MessageTransferBody mtcmd(ProtocolVersion(0,10), exname, acceptMode, acquireMode);
+ // ask for a command completion
+ mtcmd.setSync(true);
+
+ //send it
+
+ Future *futurep = NULL;
+ try {
+ futurep = new Future(sessionImplp->send(mtcmd, *framesetp));
+
+ CompletionWaiter^ waiter = nullptr;
+ if (async || (timeout != TimeSpan::MaxValue)) {
+ waiter = gcnew CompletionWaiter(this, timeout, (IntPtr) futurep, callback, state);
+ // waiter is responsible for releasing the Future native resource
+ futurep = NULL;
+ addWaiter(waiter);
+ return waiter;
+ }
+
+ // synchronous send with no timeout: no need to involve the asyncHelper thread
+
+ IncrementSyncs();
+ syncPending = true;
+ l.release();
+ internalWaitForCompletion((IntPtr) futurep);
+ }
+ finally {
+ if (syncPending) {
+ if (!l.is_locked())
+ l.acquire();
+ DecrementSyncs();
+ }
+ if (futurep != NULL)
+ delete (futurep);
+ }
+ return nullptr;
+}
+
+
+void AmqpSession::Bind(System::String^ queue, System::String^ exchange, System::String^ filterKey)
+{
+ lock l(sessionLock);
+ CheckOpen();
+
+ sessionp->exchangeBind(arg::queue=QpidMarshal::ToNative(queue),
+ arg::exchange=QpidMarshal::ToNative(exchange),
+ arg::bindingKey=QpidMarshal::ToNative(filterKey));
+
+}
+
+
+void AmqpSession::internalWaitForCompletion(IntPtr fp)
+{
+ Debug::Assert(syncCount > 0, "sync counter mismatch");
+
+ // Qpid native lib call to wait for the command completion
+ ((Future *)fp.ToPointer())->wait(*sessionImplp);
+}
+
+// call with lock held
+void AmqpSession::addWaiter(CompletionWaiter^ waiter)
+{
+ IncrementSyncs();
+ waiters->Add(waiter);
+ if (!helperRunning) {
+ helperRunning = true;
+ ThreadPool::QueueUserWorkItem(gcnew WaitCallback(this, &AmqpSession::asyncHelper));
+ }
+}
+
+
+void AmqpSession::removeWaiter(CompletionWaiter^ waiter)
+{
+ // a waiter can be removed from anywhere in the list if timed out
+
+ lock l(sessionLock);
+ int idx = waiters->IndexOf(waiter);
+ if (idx == -1) {
+ // TODO: assert or log
+ }
+ else {
+ waiters->RemoveAt(idx);
+ DecrementSyncs();
+ }
+}
+
+
+// process CompletionWaiter list one at a time.
+
+void AmqpSession::asyncHelper(Object ^unused)
+{
+ lock l(sessionLock);
+
+ while (true) {
+ if (waiters->Count == 0) {
+ helperRunning = false;
+ return;
+ }
+
+ CompletionWaiter^ waiter = waiters[0];
+ l.release();
+ // can block, but for short time
+ // the waiter removes itself from the list, possibly as the timer thread on timeout
+ waiter->Run();
+ l.acquire();
+ }
+}
+
+bool AmqpSession::MessageStop(std::string &name)
+{
+ lock l(sessionLock);
+
+ if (closing)
+ return false;
+
+ sessionp->messageStop(name, true);
+ return true;
+}
+
+void AmqpSession::AcceptAndComplete(SequenceSet& transfers)
+{
+ lock l(sessionLock);
+
+ // delimit with session dtx commands depending on the transaction context
+ UpdateTransactionState(%l);
+
+ CheckOpen();
+
+ sessionp->markCompleted(transfers, false);
+ sessionp->messageAccept(transfers, false);
+}
+
+
+// call with session lock held
+
+void AmqpSession::UpdateTransactionState(lock^ slock)
+{
+ Transaction^ currentTx = Transaction::Current;
+ if ((currentTx == nullptr) && !dtxEnabled) {
+ // no transaction scope and no previous dtx work to monitor
+ return;
+ }
+
+ if (currentTx == openSystemTransaction) {
+ // no change
+ return;
+ }
+
+ if (!dtxEnabled) {
+ // AMQP requires that this be the first dtx-related command on the session
+ sessionp->dtxSelect(false);
+ dtxEnabled = true;
+ pendingTransactions = gcnew Collections::Generic::List<XaTransaction^>();
+ }
+
+ bool notify = false; // unless the System.Transaction is no longer active
+ XaTransaction^ oldXaTx = openXaTransaction;
+ if (openSystemTransaction != nullptr) {
+ // The application may start a new transaction before the phase0 on rollback
+ try {
+ if (openSystemTransaction->TransactionInformation->Status != TransactionStatus::Active) {
+ notify = true;
+ }
+ } catch (System::ObjectDisposedException^) {
+ notify = true;
+ }
+ }
+
+ slock->release();
+ // only use stack variables until lock re-acquired
+
+ if (notify) {
+ // will do call back to all enlisted sessions. call with session lock released.
+ // If NotifyPhase0() wins the race to start phase 0, openXaTransaction will be null
+ oldXaTx->NotifyPhase0();
+ }
+
+ XaTransaction^ newXaTx = nullptr;
+ if (currentTx != nullptr) {
+ // This must be called with locks released. The DTC and System.Transactions methods that
+ // will be called hold locks that interfere with the ITransactionResourceAsync callbacks.
+ newXaTx = DtxResourceManager::GetXaTransaction(this, currentTx);
+ }
+
+ slock->acquire();
+
+ if (closing)
+ return;
+
+ if (openSystemTransaction != nullptr) {
+ // some other transaction has the dtx window open
+ // close the XID window, suspend = true... in case it is used again
+ sessionp->dtxEnd(getXid(openXaTransaction), false, true, false);
+ openSystemTransaction = nullptr;
+ openXaTransaction = nullptr;
+ }
+
+
+ // Call enlist with session lock held. The XaTransaction will call DtxStart before returning.
+ if (newXaTx != nullptr) {
+ if (!pendingTransactions->Contains(newXaTx)) {
+ pendingTransactions->Add(newXaTx);
+ }
+
+ newXaTx->Enlist(this);
+ }
+
+ openXaTransaction = newXaTx;
+ openSystemTransaction = currentTx;
+}
+
+
+typedef TypedResult<qpid::framing::XaResult> XaResultCompletion;
+
+
+// send the required closing dtx.End before Phase 1
+
+IntPtr AmqpSession::BeginPhase0Flush(XaTransaction ^xaTx) {
+
+ lock l(sessionLock);
+ IntPtr completionp = IntPtr::Zero;
+ try {
+ if (sessionp != NULL) {
+
+ // proceed even if "closing == true", the phase 0 is part of the transition from closing to closed
+
+ if (xaTx != openXaTransaction) {
+ // a different transaction (or none) is in scope, so xaTx was previously suspended.
+ // must re-open it to close it properly
+ if (openXaTransaction != nullptr) {
+ // suspend the session's current pending transaction
+ // it wil be reopened in a future enlistment or phase 0 flush.
+ sessionp->dtxEnd(getXid(openXaTransaction), false, true, false);
+ }
+ // resuming
+ sessionp->dtxStart(getXid(xaTx), false, true, false);
+ }
+
+ // the closing (i.e. non-suspended) dtxEnd happens here (exactly once for a given transaction)
+ // set the sync bit since phase0 is a precondition to prepare or abort
+ completionp = (IntPtr) new XaResultCompletion(sessionp->dtxEnd(getXid(xaTx), false, false, true));
+ IncrementSyncs();
+ }
+ }
+ catch (System::Exception^ ) {
+ // all the caller wants to know is if completionp is non-null
+ }
+
+ openXaTransaction = nullptr;
+ openSystemTransaction = nullptr;
+ return completionp;
+}
+
+
+void AmqpSession::EndPhase0Flush(XaTransaction ^xaTx, IntPtr intptr) {
+ XaResultCompletion *completionp = (XaResultCompletion *) intptr.ToPointer();
+ lock l(sessionLock);
+
+ if (completionp != NULL) {
+ try {
+ l.release();
+ completionp->wait();
+ pendingTransactions->Remove(xaTx);
+ }
+ catch (System::Exception^) {
+ // connection closed or network drop
+ }
+ finally {
+ l.acquire();
+ DecrementSyncs();
+ delete completionp;
+ }
+ }
+}
+
+
+IntPtr AmqpSession::DtxStart(IntPtr ip, bool join, bool resume) {
+ // called with session lock held (as a callback from the Enlist())
+ // The XaTransaction knows if this should be the originating dtxStart, or a join/resume
+ IntPtr rv = IntPtr::Zero;
+ qpid::framing::Xid* xidp = (qpid::framing::Xid *) ip.ToPointer();
+ if (join || resume) {
+ sessionp->dtxStart(*xidp, join, resume, false);
+ }
+ else {
+ // The XaTransaction needs to track when the first dtxStart completes to safely request a join
+ IncrementSyncs(); // caller must use ReleaseCompletion() for corresponding DecrementSyncs
+ rv = (IntPtr) new XaResultCompletion(sessionp->dtxStart(*xidp, join, resume, false));
+ }
+
+ return rv;
+}
+
+
+IntPtr AmqpSession::DtxPrepare(IntPtr ip) {
+ qpid::framing::Xid* xidp = (qpid::framing::Xid *) ip.ToPointer();
+ lock l(sessionLock);
+
+ if (closing)
+ return IntPtr::Zero;
+
+ IncrementSyncs(); // caller must use ReleaseCompletion() for corresponding DecrementSyncs
+ return (IntPtr) new XaResultCompletion(sessionp->dtxPrepare(*xidp, true));
+}
+
+
+IntPtr AmqpSession::DtxCommit(IntPtr ip, bool onePhase) {
+ qpid::framing::Xid* xidp = (qpid::framing::Xid *) ip.ToPointer();
+ lock l(sessionLock);
+
+ if (closing)
+ return IntPtr::Zero;
+
+ IncrementSyncs(); // caller must use ReleaseCompletion() for corresponding DecrementSyncs
+ return (IntPtr) new XaResultCompletion(sessionp->dtxCommit(*xidp, onePhase, true));
+}
+
+
+IntPtr AmqpSession::DtxRollback(IntPtr ip) {
+ qpid::framing::Xid* xidp = (qpid::framing::Xid *) ip.ToPointer();
+ lock l(sessionLock);
+ if (closing)
+ return IntPtr::Zero;
+
+ IncrementSyncs(); // caller must use ReleaseCompletion() for corresponding DecrementSyncs
+
+ return (IntPtr) new XaResultCompletion(sessionp->dtxRollback(*xidp, true));
+}
+
+
+//call with lock held
+void AmqpSession::IncrementSyncs() {
+ syncCount++;
+}
+
+
+//call with lock held
+void AmqpSession::DecrementSyncs() {
+ syncCount--;
+ Debug::Assert(syncCount >= 0, "sync counter underrun");
+ if (syncCount == 0) {
+ if (closeWaitHandle != nullptr) {
+ // now OK to move from closing to closed
+ closeWaitHandle->Set();
+ }
+ }
+}
+
+
+// call with lock held
+void AmqpSession::WaitLastSync(lock ^l) {
+ if (syncCount == 0)
+ return;
+ if (AppDomain::CurrentDomain->IsFinalizingForUnload()) {
+ // a wait would be a hang. No more syncs coming
+ return;
+ }
+ if (closeWaitHandle == nullptr)
+ closeWaitHandle = gcnew ManualResetEvent(false);
+ l->release();
+ closeWaitHandle->WaitOne();
+ l->acquire();
+}
+
+
+void AmqpSession::ReleaseCompletion(IntPtr completion) {
+ lock l(sessionLock);
+ DecrementSyncs();
+ delete completion.ToPointer();
+}
+
+}}} // namespace Apache::Qpid::Cli
diff --git a/wcf/src/Apache/Qpid/Interop/AmqpSession.h b/wcf/src/Apache/Qpid/Interop/AmqpSession.h
new file mode 100644
index 0000000000..88ffd18dcc
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/AmqpSession.h
@@ -0,0 +1,107 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+#include "AmqpConnection.h"
+#include "MessageBodyStream.h"
+#include "CompletionWaiter.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+using namespace System::Transactions;
+using namespace System::Diagnostics;
+
+
+using namespace qpid::client;
+using namespace std;
+
+ref class InputLink;
+ref class OutputLink;
+ref class XaTransaction;
+
+public ref class AmqpSession
+{
+private:
+ Object^ sessionLock;
+ Object^ openCloseLock;
+ AmqpConnection^ connection;
+ AsyncSession* sessionp;
+ SessionImpl* sessionImplp;
+ SubscriptionManager* subs_mgrp;
+ Collections::Generic::List<CompletionWaiter^>^ waiters;
+ bool helperRunning;
+
+ // number of active InputLinks and OutputLinks
+ int openCount;
+
+ // the number of async commands sent to the broker that need completion confirmation
+ int syncCount;
+
+ bool closing;
+ ManualResetEvent^ closeWaitHandle;
+ bool dtxEnabled;
+ Transaction^ openSystemTransaction;
+ XaTransaction^ openXaTransaction;
+ Collections::Generic::List<XaTransaction^>^ pendingTransactions;
+
+ void Cleanup();
+ void CheckOpen();
+ void asyncHelper(Object ^);
+ void addWaiter(CompletionWaiter^ waiter);
+ void UpdateTransactionState(msclr::lock^ sessionLock);
+ void IncrementSyncs();
+ void DecrementSyncs();
+ void WaitLastSync(msclr::lock^ l);
+
+public:
+ OutputLink^ CreateOutputLink(System::String^ targetQueue);
+ InputLink^ CreateInputLink(System::String^ sourceQueue);
+
+ // 0-10 specific support
+ InputLink^ CreateInputLink(System::String^ sourceQueue, bool exclusive, bool temporary, System::String^ filterKey, System::String^ exchange);
+ void Bind(System::String^ queue, System::String^ exchange, System::String^ filterKey);
+
+internal:
+ AmqpSession(AmqpConnection^ connection, qpid::client::Connection* qpidConnection);
+ void NotifyClosed();
+ CompletionWaiter^ SendMessage (System::String^ queue, MessageBodyStream ^mbody, TimeSpan timeout, bool async, AsyncCallback^ callback, Object^ state);
+ void ConnectionClosed();
+ void internalWaitForCompletion(IntPtr future);
+ void removeWaiter(CompletionWaiter^ waiter);
+ bool MessageStop(std::string &name);
+ void AcceptAndComplete(SequenceSet& transfers);
+ IntPtr BeginPhase0Flush(XaTransaction^);
+ void EndPhase0Flush(XaTransaction^, IntPtr);
+ IntPtr DtxStart(IntPtr xidp, bool, bool);
+ IntPtr DtxPrepare(IntPtr xidp);
+ IntPtr DtxCommit(IntPtr xidp, bool onePhase);
+ IntPtr DtxRollback(IntPtr xidp);
+ void ReleaseCompletion(IntPtr completion);
+
+ property AmqpConnection^ Connection {
+ AmqpConnection^ get () { return connection; }
+ }
+};
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/wcf/src/Apache/Qpid/Interop/AssemblyInfo.cpp b/wcf/src/Apache/Qpid/Interop/AssemblyInfo.cpp
new file mode 100644
index 0000000000..91c23ae30a
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/AssemblyInfo.cpp
@@ -0,0 +1,57 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using namespace System;
+using namespace System::Reflection;
+using namespace System::Runtime::CompilerServices;
+using namespace System::Runtime::InteropServices;
+using namespace System::Security::Permissions;
+
+//
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly:AssemblyTitleAttribute("Apache.Qpid.Interop")];
+[assembly:AssemblyDescriptionAttribute("")];
+[assembly:AssemblyConfigurationAttribute("")];
+[assembly:AssemblyCompanyAttribute("")];
+[assembly:AssemblyProductAttribute("")];
+[assembly:AssemblyCopyrightAttribute("")];
+[assembly:AssemblyTrademarkAttribute("")];
+[assembly:AssemblyCultureAttribute("")];
+
+//
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the value or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+
+[assembly:AssemblyVersionAttribute("1.0.*")];
+
+[assembly:ComVisible(false)];
+
+[assembly:CLSCompliantAttribute(true)];
+
+[assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = true)];
diff --git a/wcf/src/Apache/Qpid/Interop/CompletionWaiter.cpp b/wcf/src/Apache/Qpid/Interop/CompletionWaiter.cpp
new file mode 100644
index 0000000000..e39ee1b1ae
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/CompletionWaiter.cpp
@@ -0,0 +1,145 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#include <windows.h>
+#include <msclr\lock.h>
+
+#include "qpid/client/AsyncSession.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/client/Demux.h"
+#include "qpid/client/SessionImpl.h"
+#include "qpid/client/SessionBase_0_10Access.h"
+
+#include "MessageBodyStream.h"
+#include "AmqpMessage.h"
+#include "AmqpSession.h"
+#include "InputLink.h"
+#include "CompletionWaiter.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Threading;
+using namespace msclr;
+
+// A class to provide IAsyncResult semantics for a qpid AsyncSession command (i.e. 0-10 messageTransfer)
+// when the client session receives a "Completion" notification from the Broker.
+
+
+CompletionWaiter::CompletionWaiter(AmqpSession^ parent, TimeSpan timeSpan, IntPtr future, AsyncCallback^ callback, Object^ state)
+{
+ this->qpidFuture = future;
+ this->asyncCallback = callback;
+ this->state = state;
+ this->parent = parent;
+ this->thisLock = gcnew Object();
+ // do this after the Completion Waiter is fully initialized, in case of
+ // very small timespan
+ if (timeSpan != TimeSpan::MaxValue) {
+ this->timer = gcnew Timer(timeoutCallback, this, timeSpan, TimeSpan::FromMilliseconds(-1));
+ }
+}
+
+
+void CompletionWaiter::WaitForCompletion()
+{
+ if (isCompleted)
+ return;
+
+ lock l(thisLock);
+ while (!isCompleted) {
+ Monitor::Wait(thisLock);
+ }
+}
+
+void CompletionWaiter::Run()
+{
+ // no locks required in this method
+ if (isCompleted)
+ return;
+
+ try {
+ // Wait for the arrival of the "AMQP Completion" indication from the Broker
+ parent->internalWaitForCompletion(qpidFuture);
+ }
+ catch (System::Exception^ e) {
+ runException = e;
+ }
+ finally {
+ delete(qpidFuture.ToPointer());
+ qpidFuture = (IntPtr) NULL;
+ }
+
+ if (timer != nullptr) {
+ timer->~Timer();
+ timer = nullptr;
+ }
+
+ Complete(false);
+}
+
+
+// "Complete" here means complete the AsyncResult, which may precede broker "command completion" if timed out
+
+void CompletionWaiter::Complete(bool isTimerThread)
+{
+ lock l(thisLock);
+ if (isCompleted)
+ return;
+
+ isCompleted = true;
+ if (isTimerThread)
+ timedOut = true;
+
+ Monitor::PulseAll(thisLock);
+
+ // do this check and signal while locked
+ if (asyncWaitHandle != nullptr)
+ asyncWaitHandle->Set();
+
+ l.release();
+
+ parent->removeWaiter(this);
+
+ if (asyncCallback != nullptr) {
+ // guard against application callback exception
+ try {
+ asyncCallback(this);
+ }
+ catch (System::Exception^) {
+ // log it?
+ }
+ }
+}
+
+
+void CompletionWaiter::TimeoutCallback(Object^ state)
+{
+ CompletionWaiter^ waiter = (CompletionWaiter^) state;
+ waiter->Complete(true);
+}
+
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/wcf/src/Apache/Qpid/Interop/CompletionWaiter.h b/wcf/src/Apache/Qpid/Interop/CompletionWaiter.h
new file mode 100644
index 0000000000..88880c3721
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/CompletionWaiter.h
@@ -0,0 +1,98 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Threading;
+
+public ref class CompletionWaiter : IAsyncResult
+{
+private:
+ bool timedOut;
+ // has an owner thread
+ bool assigned;
+ System::Exception^ runException;
+ AsyncCallback^ asyncCallback;
+ Threading::Timer ^timer;
+ bool isCompleted;
+ Object^ state;
+ Object^ thisLock;
+ ManualResetEvent^ asyncWaitHandle;
+ AmqpSession^ parent;
+ IntPtr qpidFuture;
+ void Complete(bool isTimerThread);
+ static void TimeoutCallback(Object^ state);
+ static TimerCallback^ timeoutCallback = gcnew TimerCallback(CompletionWaiter::TimeoutCallback);
+
+ internal:
+ CompletionWaiter(AmqpSession^ parent, TimeSpan timeSpan, IntPtr future, AsyncCallback ^callback, Object^ state);
+
+ void Run();
+ void WaitForCompletion();
+
+ property bool Assigned {
+ bool get () { return assigned; }
+ }
+
+ property bool TimedOut {
+ bool get () { return timedOut; }
+ }
+
+
+ public:
+
+ virtual property bool IsCompleted {
+ bool get () { return isCompleted; }
+ }
+
+ virtual property bool CompletedSynchronously {
+ bool get () { return false; }
+ }
+
+ virtual property WaitHandle^ AsyncWaitHandle {
+ WaitHandle^ get () {
+ if (asyncWaitHandle != nullptr) {
+ return asyncWaitHandle;
+ }
+
+ msclr::lock l(thisLock);
+ if (asyncWaitHandle == nullptr) {
+ asyncWaitHandle = gcnew ManualResetEvent(isCompleted);
+ }
+ return asyncWaitHandle;
+ }
+ }
+
+
+ virtual property Object^ AsyncState {
+ Object^ get () { return state; }
+ }
+
+
+
+
+};
+
+}}} // namespace Apache::Qpid::Interop
+
diff --git a/wcf/src/Apache/Qpid/Interop/DtxResourceManager.cpp b/wcf/src/Apache/Qpid/Interop/DtxResourceManager.cpp
new file mode 100644
index 0000000000..6ea31f8401
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/DtxResourceManager.cpp
@@ -0,0 +1,285 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#include <windows.h>
+#include <msclr\lock.h>
+#include <transact.h>
+#include <xolehlp.h>
+#include <txdtc.h>
+#include <oletx2xa.h>
+#include <iostream>
+#include <fstream>
+
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/framing/FrameSet.h"
+
+#include "AmqpConnection.h"
+#include "AmqpSession.h"
+#include "DtxResourceManager.h"
+#include "XaTransaction.h"
+#include "QpidException.h"
+#include "QpidMarshal.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+using namespace System::Transactions;
+using namespace msclr;
+
+
+/*
+ * There is one DtxResourceManager per broker and per application process.
+ *
+ * Each RM manages a collection of active XaTransaction objects. Participating AmqpSessions enlist
+ * (or re-enlist) with an XaTransaction indexed by the corresponding System.Transaction object. The
+ * RM maintains its own AmqpSession for sending 2PC commnds (dtxPrepare, dtxCommit etc.). The
+ * XaTransaction object works through the lifecycle of the Transaction, including prompting the
+ * enlisted sessions to send their delimiting dtxEnd commands.
+ *
+ * A separate DtcPlugin.cpp file provides the recovery logic when needed in a library named
+ * qpidxarm.dll. The MSDTC maintans recovery info in its log and tracks when there may be
+ * transactions in doubt. See the documentation for IDtcToXaHelperSinglePipe.
+ *
+ * To enable transaction support:
+ * DTC requires a registry key to find the plugin
+ * [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSDTC\XADLL] qpidxarm.dll -> [path to qpidxarm.dll]
+ * DTC needs to be configured for XA
+ * cmdprompt -> dcomcnfg -> Component services -> My Computer -> DTC -> Local DTC -> right click properties -> Security -> Enable XA Transactions
+ *
+ */
+
+// TODO: provide shutdown mechanism, perhaps callback from Connection Idle for enlisted connections.
+// But note that a new RM registration with the DTC is very expensive.
+
+
+DtxResourceManager::DtxResourceManager(AmqpConnection^ appConnection) {
+ dtcComp = NULL;
+ xaHelperp = NULL;
+ rmCookie = 0;
+ doubtCount = 0;
+ tmDown = false;
+ AmqpConnection^ clonedCon = appConnection->Clone();
+ dtxControlSession = clonedCon->CreateSession();
+ dataSourceName = clonedCon->DataSourceName;
+ transactionMap = gcnew Collections::Generic::Dictionary<Transaction^, XaTransaction^>();
+
+ HRESULT hr;
+
+ try {
+ // instead of pinning this instance, just use tmp stack variables for small stuff
+ IUnknown* tmp = NULL;
+ // request the default DTC
+ hr = DtcGetTransactionManager(NULL, NULL, IID_IUnknown, 0, 0, 0, (void **)&tmp);
+ if (hr != S_OK)
+ throw gcnew QpidException("connection failure to DTC service");
+ dtcComp = tmp;
+
+ IDtcToXaHelperSinglePipe *tmp2 = NULL;
+ hr = ((IUnknown *)dtcComp)->QueryInterface(IID_IDtcToXaHelperSinglePipe, (void**) &tmp2);
+ if (hr != S_OK)
+ throw gcnew QpidException("DTC XA unavailable");
+ xaHelperp = tmp2;
+
+ std::string native_dsn = QpidMarshal::ToNative(dataSourceName);
+ DWORD tmp3;
+
+ // This call doesn't return until the DTC has opened and closed a connection to the broker
+ // and written a recovery entry in its log.
+ hr = ((IDtcToXaHelperSinglePipe *) xaHelperp)->XARMCreate(const_cast<char *>(native_dsn.c_str()), "qpidxarm.dll", &tmp3);
+ if (hr != S_OK) {
+ switch (hr) {
+ case E_FAIL:
+ throw gcnew QpidException("Resource Manager DLL configuration error");
+ case E_INVALIDARG:
+ throw gcnew QpidException("Resource Manager internal error");
+ case E_OUTOFMEMORY:
+ throw gcnew QpidException("Resource Manager out of memory");
+ case E_UNEXPECTED:
+ throw gcnew QpidException("Resource Manager internal failure");
+ case XACT_E_TMNOTAVAILABLE:
+ case XACT_E_CONNECTION_DOWN:
+ throw gcnew QpidException("MSDTC unavailable");
+
+ default:
+ throw gcnew QpidException("Resource Manager Registration failed");
+ }
+ }
+
+ rmCookie = tmp3;
+ }
+ finally {
+ if (rmCookie == 0) {
+ // undo partial construction
+ Cleanup();
+ }
+ }
+}
+
+
+DtxResourceManager::!DtxResourceManager() {
+ Cleanup();
+}
+
+
+DtxResourceManager::~DtxResourceManager() {
+ GC::SuppressFinalize(this);
+ Cleanup();
+}
+
+
+// Called when the DTC COM proxy sends TMDOWN to a pending XaTransaction
+// called once for each outstanding tx
+
+void DtxResourceManager::TmDown() {
+ // this block is the only place where both locks are held
+ lock l1(transactionMap);
+ lock l2(resourceManagerMap);
+ if (tmDown)
+ return;
+
+ tmDown = true;
+ resourceManagerMap->Remove(this->dataSourceName);
+ // defer cleanup until last TmDown notification received
+}
+
+
+
+void DtxResourceManager::Cleanup() {
+ for each (Collections::Generic::KeyValuePair<Transaction^, XaTransaction^> kvp in transactionMap) {
+ XaTransaction^ xaTr = kvp.Value;
+ xaTr->ChildFinalize();
+ }
+
+ try {
+ if (rmCookie != 0) {
+ // implies no recovery needed
+ bool cleanSession = (doubtCount == 0) && (transactionMap->Count == 0);
+ ((IDtcToXaHelperSinglePipe *)xaHelperp)->ReleaseRMCookie(rmCookie, cleanSession);
+ rmCookie = 0;
+ }
+
+
+ if (xaHelperp != NULL) {
+ ((IDtcToXaHelperSinglePipe *) xaHelperp)->Release();
+ xaHelperp = NULL;
+ }
+
+ if (dtcComp != NULL) {
+ ((IUnknown *) dtcComp)->Release();
+ dtcComp = NULL;
+ }
+
+ if (dtxControlSession != nullptr) {
+ dtxControlSession->Connection->Close();
+ }
+
+ }
+ catch (Exception^) {}
+}
+
+
+XaTransaction^ DtxResourceManager::GetXaTransaction(AmqpSession^ appSession, Transaction^ transaction) {
+ // find or create the RM instance associated with the session's broker
+ AmqpConnection^ connection = appSession->Connection;
+ DtxResourceManager^ instance = connection->CachedResourceManager;
+
+ // try cached rm first
+ if (instance != nullptr) {
+ XaTransaction^ xaTx = instance->InternalGetXaTransaction(appSession, transaction);
+ if (xaTx != nullptr)
+ return xaTx;
+ else {
+ // cached version no longer available, force new rm creation
+ connection->CachedResourceManager = nullptr;
+ }
+ }
+
+ lock l(resourceManagerMap);
+ String^ dsn = connection->DataSourceName;
+ if (!resourceManagerMap->TryGetValue(dsn, instance)) {
+ instance = gcnew DtxResourceManager(connection->Clone());
+ resourceManagerMap->Add(dsn, instance);
+ connection->CachedResourceManager = instance;
+ }
+ l.release();
+
+ return instance->InternalGetXaTransaction(appSession, transaction);
+}
+
+
+XaTransaction^ DtxResourceManager::InternalGetXaTransaction(AmqpSession^ appSession, Transaction^ transaction) {
+ // find or create the tx proxy instance associated with the DTC transaction
+ lock l(transactionMap);
+ if (tmDown)
+ return nullptr;
+
+ XaTransaction^ xaTransaction = nullptr;
+ if (!transactionMap->TryGetValue(transaction, xaTransaction)) {
+ xaTransaction = gcnew XaTransaction(transaction, (IDtcToXaHelperSinglePipe *) xaHelperp, rmCookie, this);
+ transactionMap->Add(transaction, xaTransaction);
+ }
+
+ return xaTransaction;
+}
+
+void DtxResourceManager::Complete(Transaction ^tx) {
+ lock l(transactionMap);
+ transactionMap->Remove(tx);
+
+ if (tmDown && (transactionMap->Count == 0)) {
+ // no more activity on this instance
+ GC::SuppressFinalize(this);
+ Cleanup();
+ }
+}
+
+
+void DtxResourceManager::IncrementDoubt() {
+ Interlocked::Increment(doubtCount);
+}
+
+
+void DtxResourceManager::DecrementDoubt() {
+ Interlocked::Decrement(doubtCount);
+}
+
+
+#ifdef QPID_RECOVERY_TEST_HOOK
+void DtxResourceManager::ForceRecovery(Transaction ^tx) {
+ lock l(resourceManagerMap);
+ for each (Collections::Generic::KeyValuePair<System::String^, DtxResourceManager^> kvp in resourceManagerMap) {
+
+ Collections::Generic::Dictionary<Transaction^, XaTransaction^>^ txmap = kvp.Value->transactionMap;
+ XaTransaction^ xaTransaction = nullptr;
+ lock l2(txmap);
+ if (txmap->TryGetValue(tx, xaTransaction)) {
+ xaTransaction->ForceRecovery();
+ }
+ }
+}
+#endif
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/wcf/src/Apache/Qpid/Interop/DtxResourceManager.h b/wcf/src/Apache/Qpid/Interop/DtxResourceManager.h
new file mode 100644
index 0000000000..7df491eec2
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/DtxResourceManager.h
@@ -0,0 +1,76 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Threading;
+using namespace System::Transactions;
+
+ref class XaTransaction;
+
+public ref class DtxResourceManager
+{
+private:
+ // Receive() or WaitForMessage()
+ AmqpSession^ dtxControlSession;
+ String^ dataSourceName;
+ bool consumed;
+ DWORD rmCookie;
+ void* xaHelperp;
+ void* dtcComp;
+ int doubtCount;
+ DtxResourceManager(AmqpConnection^);
+ XaTransaction^ InternalGetXaTransaction (AmqpSession^ session, Transaction^ transaction);
+ bool tmDown;
+
+ // The active transactions
+ Collections::Generic::Dictionary<Transaction^, XaTransaction^>^ transactionMap;
+
+ // one resource manager per AMQP broker per process
+ static Collections::Generic::Dictionary<System::String^, DtxResourceManager^>^ resourceManagerMap =
+ gcnew Collections::Generic::Dictionary<System::String^, DtxResourceManager^>();
+
+ void Cleanup();
+ ~DtxResourceManager();
+ !DtxResourceManager();
+
+internal:
+ static XaTransaction^ GetXaTransaction (AmqpSession^ session, Transaction^ transaction);
+ void Complete(Transaction ^tx);
+ void TmDown();
+
+ property AmqpSession^ DtxControlSession {
+ AmqpSession^ get () { return dtxControlSession; }
+ }
+
+ void IncrementDoubt();
+ void DecrementDoubt();
+
+#ifdef QPID_RECOVERY_TEST_HOOK
+public:
+ static void ForceRecovery(Transaction ^tx);
+#endif
+};
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/wcf/src/Apache/Qpid/Interop/InputLink.cpp b/wcf/src/Apache/Qpid/Interop/InputLink.cpp
new file mode 100644
index 0000000000..3245cd3540
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/InputLink.cpp
@@ -0,0 +1,853 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#include <windows.h>
+#include <msclr\lock.h>
+
+#include "qpid/client/AsyncSession.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/client/Demux.h"
+#include "qpid/client/SessionImpl.h"
+#include "qpid/client/SessionBase_0_10Access.h"
+
+#include "MessageBodyStream.h"
+#include "AmqpMessage.h"
+#include "AmqpSession.h"
+#include "InputLink.h"
+#include "QpidMarshal.h"
+#include "QpidException.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+using namespace System::Threading;
+using namespace msclr;
+
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using namespace std;
+
+using namespace Apache::Qpid::AmqpTypes;
+
+// Scalability note: When using async methods, an async helper thread is created
+// to block on the Demux BlockingQueue. This design should be revised in line
+// with proposed changes to the native library to reduce the number of servicing
+// threads for large numbers of subscriptions.
+
+// synchronization is accomplished with locks, but also by ensuring that only one
+// MessageWaiter (the one at the front of the line) is ever active.
+// async threads to watch for: Close/finalizer, Timers, SyncCredit and the native Dispatch
+// thread (who deposits FrameSets into the local queue and is oblivious to the
+// managed space locks).
+
+
+// The folowing def must match the "Frames" private typedef.
+// TODO, make Qpid-cpp "Frames" definition visible.
+typedef qpid::InlineVector<AMQFrame, 4> FrameSetFrames;
+
+InputLink::InputLink(AmqpSession^ session, System::String^ sourceQueue,
+ qpid::client::AsyncSession *qpidSessionp, qpid::client::SubscriptionManager *qpidSubsMgrp,
+ bool exclusive,
+ bool temporary, System::String^ filterKey, System::String^ exchange) :
+ amqpSession(session),
+ subscriptionp(NULL),
+ localQueuep(NULL),
+ queuePtrp(NULL),
+ dequeuedFrameSetpp(NULL),
+ disposed(false),
+ finalizing(false)
+{
+ bool success = false;
+ System::Exception^ linkException = nullptr;
+
+ waiters = gcnew Collections::Generic::List<MessageWaiter^>();
+ linkLock = waiters; // private and available
+ subscriptionLock = gcnew Object();
+
+ try {
+ std::string qname = QpidMarshal::ToNative(sourceQueue);
+
+ if (temporary) {
+ qpidSessionp->queueDeclare(arg::queue=qname, arg::durable=false, arg::autoDelete=true, arg::exclusive=true);
+ qpidSessionp->exchangeBind(arg::exchange=QpidMarshal::ToNative(exchange),
+ arg::queue=qname, arg::bindingKey=QpidMarshal::ToNative(filterKey));
+ qpidSessionp->sync();
+ }
+
+ localQueuep = new LocalQueue;
+ SubscriptionSettings settings;
+ settings.flowControl = FlowControl::messageCredit(0);
+ settings.completionMode = CompletionMode::MANUAL_COMPLETION;
+
+ Subscription sub = qpidSubsMgrp->subscribe(*localQueuep, qname, settings);
+ subscriptionp = new Subscription (sub); // copy smart pointer for later IDisposable cleanup
+
+ // the roundabout way to obtain localQueuep->queue
+ SessionBase_0_10Access sa(*qpidSessionp);
+ boost::shared_ptr<SessionImpl> simpl = sa.get();
+ queuePtrp = new Demux::QueuePtr(simpl->getDemux().get(sub.getName()));
+
+ success = true;
+ } finally {
+ if (!success) {
+ Cleanup();
+ linkException = gcnew QpidException ("InputLink creation failure");
+ throw linkException;
+ }
+ }
+}
+
+// called with lock held
+void InputLink::ReleaseNative()
+{
+ // involves talking to the Broker unless the connection is broken
+
+ if ((subscriptionp != NULL) && !finalizing) {
+ // TODO: find boost time error on cleanup when in finalizer thread
+ try {
+ subscriptionp->cancel();
+ }
+ catch (const std::exception& error) {
+ // TODO: log this properly
+ std::cout << "shutdown error " << error.what() << std::endl;
+ }
+ }
+
+ // free native mem (or smart pointers) that we own
+ if (subscriptionp != NULL) {
+ delete subscriptionp;
+ subscriptionp = NULL;
+ }
+ if (queuePtrp != NULL) {
+ delete queuePtrp;
+ queuePtrp = NULL;
+ }
+ if (localQueuep != NULL) {
+ if (!finalizing) {
+ // TODO: find boost time error on cleanup when in finalizer thread
+ delete localQueuep;
+ localQueuep = NULL;
+ }
+ }
+ if (dequeuedFrameSetpp != NULL) {
+ delete dequeuedFrameSetpp;
+ dequeuedFrameSetpp = NULL;
+ }
+}
+
+void InputLink::Cleanup()
+{
+ {
+ lock l(linkLock);
+ if (disposed)
+ return;
+
+ disposed = true;
+
+ // if the asyncHelper exists and is idle, unblock it
+ if (asyncHelperWaitHandle != nullptr) {
+ asyncHelperWaitHandle->Set();
+ }
+
+ // wakeup anyone waiting for messages
+ if (queuePtrp != NULL)
+ (*queuePtrp)->close();
+
+ // wait for any sync operations on the subscription to complete before ReleaseNative
+ lock l2(subscriptionLock);
+
+ try {}
+ finally
+ {
+ ReleaseNative();
+ }
+
+ }
+ amqpSession->NotifyClosed();
+}
+
+InputLink::~InputLink()
+{
+ Cleanup();
+}
+
+InputLink::!InputLink()
+{
+ finalizing = true;
+ Cleanup();
+}
+
+void InputLink::Close()
+{
+ // Simulate Dispose()...
+ Cleanup();
+ GC::SuppressFinalize(this);
+}
+
+// call with lock held
+bool InputLink::haveMessage()
+{
+ if (dequeuedFrameSetpp != NULL)
+ return true;
+
+ if (queuePtrp != NULL) {
+ if ((*queuePtrp)->size() > 0)
+ return true;
+ }
+ return false;
+}
+
+IntPtr InputLink::nextLocalMessage()
+{
+ lock l(linkLock);
+
+ if (disposed)
+ return (IntPtr) NULL;
+
+ // A message already pulled off BlockingQueue?
+ if (dequeuedFrameSetpp != NULL) {
+ QpidFrameSetPtr* rv = dequeuedFrameSetpp;
+ dequeuedFrameSetpp = NULL;
+ return (IntPtr) rv;
+ }
+
+ if ((*queuePtrp)->empty())
+ return (IntPtr) NULL;
+
+ bool received = false;
+ QpidFrameSetPtr* frameSetpp = new QpidFrameSetPtr;
+
+ try {
+ received = (*queuePtrp)->pop(*frameSetpp, qpid::sys::TIME_INFINITE);
+ if (received) {
+ QpidFrameSetPtr* rv = frameSetpp;
+ // no need to free native in finally block
+ frameSetpp = NULL;
+ return (IntPtr) rv;
+ }
+ } catch(const std::exception& error) {
+ // should be no async tampering with queue since we hold the lock and have a
+ // smart pointer ref to the native LocalQueue, even if the network connection fails...
+ cout << "unknown exception in InputLink.nextLocalMessage() " << error.what() <<endl;
+ // TODO: log this
+ }
+ finally {
+ if (frameSetpp != NULL) {
+ delete frameSetpp;
+ }
+ }
+
+ return (IntPtr) NULL;
+}
+
+
+
+void InputLink::unblockWaiter()
+{
+ // to be followed by resetQueue() below
+ lock l(linkLock);
+ if (disposed)
+ return;
+ (*queuePtrp)->close();
+}
+
+
+
+// Set things right after unblockWaiter(). Closing and opening a Qpid BlockingQueue unsticks
+// a blocking thread without interefering with queue contents or the ability to push
+// new incoming messages.
+
+void InputLink::resetQueue()
+{
+ lock l(linkLock);
+ if (disposed)
+ return;
+ if ((*queuePtrp)->isClosed()) {
+ (*queuePtrp)->open();
+ }
+}
+
+
+// returns true if there is a message to consume, i.e. nextLocalMessage() won't block
+
+bool InputLink::internalWaitForMessage()
+{
+ Demux::QueuePtr demuxQueuePtr;
+
+ bool received = false;
+ QpidFrameSetPtr* frameSetpp = NULL;
+ try {
+ lock l(linkLock);
+ if (disposed)
+ return false;
+ if (haveMessage())
+ return true;
+
+ AdjustCredit();
+
+ // get a scoped smart ptr ref to guard against async close or hangup
+ demuxQueuePtr = *queuePtrp;
+ frameSetpp = new QpidFrameSetPtr;
+
+ l.release();
+ // Async cleanup is now possible. Only use demuxQueuePtr until lock reacquired.
+ received = demuxQueuePtr->pop(*frameSetpp, qpid::sys::TIME_INFINITE);
+ l.acquire();
+
+ if (received) {
+ dequeuedFrameSetpp = frameSetpp;
+ frameSetpp = NULL; // native will eventually be freed in Cleanup or MessageBodyStream
+ }
+
+ return true;
+ } catch(const std::exception& ) {
+ // timeout or connection closed
+ return false;
+ }
+ finally {
+ if (frameSetpp != NULL) {
+ delete frameSetpp;
+ }
+ }
+
+ return false;
+}
+
+
+// call with lock held
+void InputLink::addWaiter(MessageWaiter^ waiter)
+{
+ waiters->Add(waiter);
+ if (waiters->Count == 1) {
+ // mark this waiter as ready to run
+ // Only the waiter at the head of the queue is active.
+ waiter->Activate();
+ }
+
+ if (waiter->Assigned)
+ return;
+
+ if (asyncHelperWaitHandle == nullptr) {
+ asyncHelperWaitHandle = gcnew ManualResetEvent(false);
+ ThreadStart^ threadDelegate = gcnew ThreadStart(this, &InputLink::asyncHelper);
+ (gcnew Thread(threadDelegate))->Start();
+ }
+
+ if (waiters->Count == 1) {
+ // wake up the asyncHelper
+ asyncHelperWaitHandle->Set();
+ }
+}
+
+
+void InputLink::removeWaiter(MessageWaiter^ waiter) {
+ // a waiter can be removed from anywhere in the list if timed out
+
+ lock l(linkLock);
+ int idx = waiters->IndexOf(waiter);
+ if (idx == -1) {
+ // TODO: assert or log
+ if (asyncHelperWaitHandle != nullptr) {
+ // just in case.
+ asyncHelperWaitHandle->Set();
+ }
+ return;
+ }
+
+ waiters->RemoveAt(idx);
+ if (waiter->TimedOut) {
+ // may have to give back message if it arrives momentarily
+ AdjustCredit();
+ }
+
+ // let the next waiter know it's his turn.
+ if (waiters->Count > 0) {
+ MessageWaiter^ nextWaiter = waiters[0];
+
+ // wakeup the asyncHelper thread to help out if necessary.
+ if (!nextWaiter->Assigned) {
+ asyncHelperWaitHandle->Set();
+ }
+
+ l.release();
+ nextWaiter->Activate();
+ return;
+ }
+ else {
+ if (disposed && (asyncHelperWaitHandle != nullptr)) {
+ asyncHelperWaitHandle->Set();
+ }
+ }
+}
+
+
+void InputLink::asyncHelper()
+{
+ lock l(linkLock);
+
+ while (true) {
+ if (disposed && (waiters->Count == 0)) {
+ asyncHelperWaitHandle = nullptr;
+ return;
+ }
+
+ if (waiters->Count > 0) {
+ MessageWaiter^ waiter = waiters[0];
+
+ l.release();
+ if (waiter->AcceptForWork()) {
+ waiter->Run();
+ }
+ l.acquire();
+ }
+
+ // sleep if more work may be coming or it is currently someone else's turn
+ if (((waiters->Count == 0) && !disposed) || ((waiters->Count != 0) && waiters[0]->Assigned)) {
+ // wait for something to do
+ asyncHelperWaitHandle->Reset();
+ l.release();
+ asyncHelperWaitHandle->WaitOne();
+ l.acquire();
+ }
+ }
+}
+
+void InputLink::sync()
+{
+ // used by the MessageWaiter timeout thread to not run before fully initialized
+ lock l(linkLock);
+}
+
+
+void InputLink::PrefetchLimit::set(int value)
+{
+ lock l(linkLock);
+ prefetchLimit = value;
+
+ int delta = 0;
+
+ // rough rule of thumb to keep the flow, but reduce chatter.
+ // for small messages, the credit request is almost as expensive as the transfer itself.
+ // experience may suggest a better heuristic or require a property for the low water mark
+ if (prefetchLimit >= 3) {
+ delta = prefetchLimit / 3;
+ }
+ minWorkingCredit = prefetchLimit - delta;
+ AdjustCredit();
+}
+
+
+// call with lock held
+void InputLink::AdjustCredit()
+{
+ if (creditSyncPending || disposed)
+ return;
+
+ // low watermark check
+ if ((prefetchLimit != 0) &&
+ (workingCredit >= minWorkingCredit) &&
+ (workingCredit >= waiters->Count))
+ return;
+
+ // should have enough for all waiters or to satisfy the prefetch window
+ int targetCredit = waiters->Count;
+ if (targetCredit < prefetchLimit)
+ targetCredit = prefetchLimit;
+
+ if (targetCredit > workingCredit) {
+ subscriptionp->grantMessageCredit(targetCredit - workingCredit);
+ workingCredit = targetCredit;
+ return;
+ }
+ if (targetCredit < workingCredit) {
+ if ((targetCredit == 0) && (prefetchLimit == 0)) {
+ creditSyncPending = true;
+ ThreadPool::QueueUserWorkItem(gcnew WaitCallback(this, &InputLink::SyncCredit));
+ }
+ // TODO: also shrink credit when prefetchLimit != 0
+ }
+}
+
+void InputLink::SyncCredit(Object ^unused)
+{
+ lock l(linkLock);
+
+ try {
+ if (disposed)
+ return;
+
+ if (!amqpSession->MessageStop(subscriptionp->getName())) {
+ // connection closed
+ return;
+ }
+
+ l.release();
+ // use setFlowControl to re-enable credit flow on the broker.
+ // setFlowControl is a sync operation
+ {
+ lock l2(subscriptionLock);
+ if (subscriptionp != NULL) {
+ subscriptionp->setFlowControl(subscriptionp->getSettings().flowControl);
+ }
+ }
+ l.acquire();
+
+ if (disposed)
+ return;
+
+ // let existing waiters use up any messages that arrived.
+ // local queue size can only decrease until more credit is issued
+ while (true) {
+ if ((waiters->Count > 0) && ((*queuePtrp)->size() > 0)) {
+ l.release();
+ // a rare use case and not used in performance oriented code.
+ // optimization can wait until the qpid/messaging api is used
+ Thread::Sleep(10);
+ l.acquire();
+ if (disposed)
+ return;
+ }
+ else {
+ break;
+ }
+ }
+
+ // At this point, the lock is held and we are fully synced with the broker
+ // so we have a valid snapshot
+
+ if ((prefetchLimit == 0) && ((*queuePtrp)->size() > 0)) {
+ // can't be sure application will request a message again any time soon
+ QpidFrameSetPtr frameSetp;
+ while (!(*queuePtrp)->empty()) {
+ (*queuePtrp)->pop(frameSetp);
+ SequenceSet frameSetID(frameSetp->getId());
+ subscriptionp->release(frameSetID);
+ }
+
+ // don't touch dequeuedFrameSetpp. It is spoken for: explicitely from a
+ // MessageWaiter about to to get the nextLocalMessage(), or implicitely
+ // from a WaitForMessage().
+ }
+ // TODO: if prefetchLimit != 0, release messages from back of the queue that exceed targetCredit
+
+ workingCredit = (*queuePtrp)->size();
+ if (dequeuedFrameSetpp != NULL) {
+ workingCredit++;
+ }
+ }
+ finally {
+ creditSyncPending = false;
+ }
+
+ AdjustCredit();
+}
+
+
+AmqpMessage^ InputLink::createAmqpMessage(IntPtr msgp)
+{
+ QpidFrameSetPtr* fspp = (QpidFrameSetPtr*) msgp.ToPointer();
+ bool ownFrameSet = true;
+ bool haveProperties = false;
+
+ try {
+ MessageBodyStream^ mstream = gcnew MessageBodyStream(fspp);
+ ownFrameSet = false; // stream releases on close/dispose
+
+ AmqpMessage^ amqpMessage = gcnew AmqpMessage(mstream);
+
+ AMQHeaderBody* headerBodyp = (*fspp)->getHeaders();
+ uint64_t contentSize = (*fspp)->getContentSize();
+ SequenceSet frameSetID((*fspp)->getId());
+
+ // target managed representation
+ AmqpProperties^ amqpProperties = gcnew AmqpProperties();
+
+ // source native representation
+ const DeliveryProperties* deliveryProperties = headerBodyp->get<DeliveryProperties>();
+ const qpid::framing::MessageProperties* messageProperties = headerBodyp->get<qpid::framing::MessageProperties>();
+
+ if (deliveryProperties) {
+ if (deliveryProperties->hasRoutingKey()) {
+ haveProperties = true;
+
+ amqpProperties->RoutingKey = gcnew String(deliveryProperties->getRoutingKey().c_str());
+ }
+
+ if (deliveryProperties->hasDeliveryMode()) {
+ if (deliveryProperties->getDeliveryMode() == qpid::framing::PERSISTENT)
+ amqpProperties->Durable = true;
+ }
+
+ if (deliveryProperties->hasTtl()) {
+ long long ticks = deliveryProperties->getTtl() * TimeSpan::TicksPerMillisecond;
+ amqpProperties->TimeToLive = Nullable<TimeSpan>(TimeSpan::FromTicks(ticks));
+ }
+ }
+
+ if (messageProperties) {
+
+ if (messageProperties->hasReplyTo()) {
+ haveProperties = true;
+ const ReplyTo& rpto = messageProperties->getReplyTo();
+ String^ rk = nullptr;
+ String^ ex = nullptr;
+ if (rpto.hasRoutingKey()) {
+ rk = gcnew String(rpto.getRoutingKey().c_str());
+ }
+ if (rpto.hasExchange()) {
+ ex = gcnew String(rpto.getExchange().c_str());
+ }
+ amqpProperties->SetReplyTo(ex,rk);
+ }
+
+ if (messageProperties->hasContentType()) {
+ haveProperties = true;
+ amqpProperties->ContentType = gcnew String(messageProperties->getContentType().c_str());
+
+ if (messageProperties->hasContentEncoding()) {
+ String^ enc = gcnew String(messageProperties->getContentEncoding().c_str());
+ if (!String::IsNullOrEmpty(enc)) {
+ // TODO: properly assemble 1.0 style to 0-10 for all cases
+ amqpProperties->ContentType += "; charset=" + enc;
+ }
+ }
+ }
+
+ if (messageProperties->hasCorrelationId()) {
+ haveProperties = true;
+ const std::string& ncid = messageProperties->getCorrelationId();
+ int len = ncid.size();
+ array<unsigned char>^ mcid = gcnew array<unsigned char>(len);
+ Marshal::Copy ((IntPtr) (void *) ncid.data(), mcid, 0, len);
+ amqpProperties->CorrelationId = mcid;
+ }
+
+ if (messageProperties->hasUserId()) {
+ haveProperties = true;
+ const std::string& nuid = messageProperties->getUserId();
+ int len = nuid.size();
+ array<unsigned char>^ muid = gcnew array<unsigned char>(len);
+ Marshal::Copy ((IntPtr) (void *) nuid.data(), muid, 0, len);
+ amqpProperties->UserId = muid;
+ }
+
+ if (messageProperties->hasApplicationHeaders()) {
+ haveProperties = true;
+ const qpid::framing::FieldTable& fieldTable = messageProperties->getApplicationHeaders();
+ int count = fieldTable.count();
+
+ if (count > 0) {
+ haveProperties = true;
+ Collections::Generic::Dictionary<System::String^, AmqpType^>^ mmap =
+ gcnew Collections::Generic::Dictionary<System::String^, AmqpType^>(count);
+
+ for(qpid::framing::FieldTable::ValueMap::const_iterator i = fieldTable.begin(); i != fieldTable.end(); i++) {
+
+ qpid::framing::FieldValue::Data &data = i->second->getData();
+
+ // TODO: replace these generic int/string conversions with handler for each AMQP specific type:
+ // uint8_t dataType = i->second->getType();
+ // switch (dataType) { case TYPE_CODE_STR8: ... }
+
+ if (data.convertsToInt()) {
+ mmap->Add (gcnew String(i->first.data()), gcnew AmqpInt((int) i->second->getData().getInt()));
+ }
+ if (data.convertsToString()) {
+ std::string ns = data.getString();
+ String^ ms = gcnew String(ns.data(), 0, ns.size());
+ mmap->Add (gcnew String(i->first.data()), gcnew AmqpString(ms));
+ }
+ }
+
+ amqpProperties->PropertyMap = mmap;
+ }
+
+ }
+ }
+
+ if (haveProperties) {
+ amqpMessage->Properties = amqpProperties;
+ }
+
+ // We have a message we can return to the caller.
+ // Tell the broker we got it.
+
+ // subscriptionp->accept(frameSetID) is a slow sync operation in the native API
+ // so do it within the AsyncSession directly
+ amqpSession->AcceptAndComplete(frameSetID);
+
+ workingCredit--;
+ // check if more messages need to be requested from broker
+ AdjustCredit();
+
+ return amqpMessage;
+ }
+ finally {
+ if (ownFrameSet)
+ delete (fspp);
+ }
+}
+
+ // As for IInputChannel:
+ // if success, return true + amqpMessage
+ // elseif timeout, return false
+ // elseif closed/EOF, return true and amqpMessage = null
+ // else throw an Exception
+
+bool InputLink::TryReceive(TimeSpan timeout, [Out] AmqpMessage^% amqpMessage)
+{
+ lock l(linkLock);
+
+ if (waiters->Count == 0) {
+ // see if there is a message already available without blocking
+ IntPtr fspp = nextLocalMessage();
+ if (fspp.ToPointer() != NULL) {
+ amqpMessage = createAmqpMessage(fspp);
+ return true;
+ }
+ }
+
+ MessageWaiter^ waiter = gcnew MessageWaiter(this, timeout, true, false, nullptr, nullptr);
+ addWaiter(waiter);
+
+ l.release();
+ waiter->Run();
+ l.acquire();
+
+ if (waiter->TimedOut) {
+ return false;
+ }
+
+ IntPtr waiterMsg = waiter->Message;
+ if (waiterMsg.ToPointer() == NULL) {
+ if (disposed) {
+ // indicate normal EOF on channel
+ amqpMessage = nullptr;
+ return true;
+ }
+ }
+
+ amqpMessage = createAmqpMessage(waiterMsg);
+ return true;
+}
+
+IAsyncResult^ InputLink::BeginTryReceive(TimeSpan timeout, AsyncCallback^ callback, Object^ state)
+{
+
+ //TODO: if haveMessage() complete synchronously
+
+ lock l(linkLock);
+ MessageWaiter^ waiter = gcnew MessageWaiter(this, timeout, true, true, callback, state);
+ addWaiter(waiter);
+ return waiter;
+}
+
+bool InputLink::EndTryReceive(IAsyncResult^ result, [Out] AmqpMessage^% amqpMessage)
+{
+
+ // TODO: validate result
+
+ MessageWaiter^ waiter = (MessageWaiter ^) result;
+
+ waiter->WaitForCompletion();
+
+ if (waiter->RunException != nullptr)
+ throw waiter->RunException;
+
+ if (waiter->TimedOut) {
+ amqpMessage = nullptr;
+ return false;
+ }
+
+ IntPtr waiterMsg = waiter->Message;
+ if (waiterMsg.ToPointer() == NULL) {
+ if (disposed) {
+ // indicate normal EOF on channel
+ amqpMessage = nullptr;
+ return true;
+ }
+ }
+
+ amqpMessage = createAmqpMessage(waiterMsg);
+ return true;
+}
+
+
+bool InputLink::WaitForMessage(TimeSpan timeout)
+{
+ lock l(linkLock);
+
+ if (disposed)
+ return false;
+
+ if (waiters->Count == 0) {
+ // see if there is a message already available without blocking
+ if (haveMessage())
+ return true;
+ }
+
+ // Same as for TryReceive, except consuming = false
+ MessageWaiter^ waiter = gcnew MessageWaiter(this, timeout, false, false, nullptr, nullptr);
+ addWaiter(waiter);
+
+ l.release();
+ waiter->Run();
+ l.acquire();
+
+ if (waiter->TimedOut) {
+ return false;
+ }
+
+ return haveMessage();
+}
+
+IAsyncResult^ InputLink::BeginWaitForMessage(TimeSpan timeout, AsyncCallback^ callback, Object^ state)
+{
+ lock l(linkLock);
+
+ // Same as for BeginTryReceive, except consuming = false
+ MessageWaiter^ waiter = gcnew MessageWaiter(this, timeout, false, true, callback, state);
+ addWaiter(waiter);
+ return waiter;
+}
+
+bool InputLink::EndWaitForMessage(IAsyncResult^ result)
+{
+ MessageWaiter^ waiter = (MessageWaiter ^) result;
+
+ waiter->WaitForCompletion();
+
+ if (waiter->TimedOut) {
+ return false;
+ }
+
+ return haveMessage();
+}
+
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/wcf/src/Apache/Qpid/Interop/InputLink.h b/wcf/src/Apache/Qpid/Interop/InputLink.h
new file mode 100644
index 0000000000..2f96b91944
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/InputLink.h
@@ -0,0 +1,102 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+#include "MessageWaiter.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Threading;
+using namespace System::Runtime::InteropServices;
+
+using namespace qpid::client;
+using namespace std;
+
+// smart pointer to the low level AMQP 0-10 frames of the message
+typedef qpid::framing::FrameSet::shared_ptr QpidFrameSetPtr;
+
+public ref class InputLink
+{
+private:
+ AmqpSession^ amqpSession;
+ Subscription* subscriptionp;
+ LocalQueue* localQueuep;
+ Demux::QueuePtr* queuePtrp;
+ Collections::Generic::List<MessageWaiter^>^ waiters;
+ bool disposed;
+ bool finalizing;
+ Object^ linkLock;
+ Object^ subscriptionLock;
+ QpidFrameSetPtr* dequeuedFrameSetpp;
+ ManualResetEvent^ asyncHelperWaitHandle;
+ // number of messages to buffer locally for future consumption
+ int prefetchLimit;
+ // the number of messages requested and not yet processed
+ int workingCredit;
+ // stopping and restarting the message flow
+ bool creditSyncPending;
+ // working credit low water mark
+ int minWorkingCredit;
+
+ void Cleanup();
+ void ReleaseNative();
+ bool haveMessage();
+ void addWaiter(MessageWaiter^ waiter);
+ void asyncHelper();
+ AmqpMessage^ createAmqpMessage(IntPtr msgp);
+ void AdjustCredit();
+ void SyncCredit(Object ^);
+
+internal:
+ InputLink(AmqpSession^ session, System::String^ sourceQueue, qpid::client::AsyncSession *qpidSessionp,
+ qpid::client::SubscriptionManager *qpidSubsMgrp, bool exclusive, bool temporary, System::String^ filterKey,
+ System::String^ exchange);
+
+ bool internalWaitForMessage();
+ void unblockWaiter();
+ void resetQueue();
+ IntPtr nextLocalMessage();
+ void removeWaiter(MessageWaiter^ waiter);
+ void sync();
+
+public:
+ ~InputLink();
+ !InputLink();
+ void Close();
+
+ bool TryReceive(TimeSpan timeout, [Out] AmqpMessage ^% amqpMessage);
+ IAsyncResult^ BeginTryReceive(TimeSpan timeout, AsyncCallback^ callback, Object^ state);
+ bool EndTryReceive(IAsyncResult^ result, [Out] AmqpMessage^% amqpMessage);
+
+ bool WaitForMessage(TimeSpan timeout);
+ IAsyncResult^ BeginWaitForMessage(TimeSpan timeout, AsyncCallback^ callback, Object^ state);
+ bool EndWaitForMessage(IAsyncResult^ result);
+
+ property int PrefetchLimit {
+ int get () { return prefetchLimit; }
+ void set (int value);
+ }
+
+};
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/wcf/src/Apache/Qpid/Interop/Interop.vcproj b/wcf/src/Apache/Qpid/Interop/Interop.vcproj
new file mode 100644
index 0000000000..2056c97d57
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/Interop.vcproj
@@ -0,0 +1,493 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="Interop"
+ ProjectGUID="{C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}"
+ RootNamespace="Interop"
+ Keyword="ManagedCProj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(ProjectDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ ManagedExtensions="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ CommandLine="copy ..\AmqpTypes\obj\$(ConfigurationName)\Apache.Qpid.AmqpTypes.netmodule $(ConfigurationName)"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions=" /Zm1000 /wd4244 /wd4800 /wd4355 /FU $(ConfigurationName)\Apache.Qpid.AmqpTypes.netmodule"
+ Optimization="0"
+ AdditionalIncludeDirectories="&quot;$(QPID_BUILD_ROOT)\include&quot;;&quot;$(QPID_BUILD_ROOT)\src&quot;;..\..\..\..\..\cpp\include;..\..\..\..\..\cpp\src;&quot;$(BOOST_ROOT)&quot;"
+ PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,BOOST_ALL_DYN_LINK,_CRT_NONSTDC_NO_WARNINGS,NOMINMAX,WIN32_LEAN_AND_MEAN,_SCL_SECURE_NO_WARNINGS,HAVE_CONFIG_H"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions=" /STACK:10000000 /machine:I386 $(ConfigurationName)\Apache.Qpid.AmqpTypes.netmodule"
+ AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib xolehlp.lib $(QPID_BUILD_ROOT)\src\Debug\qpidclientd.lib $(QPID_BUILD_ROOT)\src\Debug\qpidcommond.lib rpcrt4.lib ws2_32.lib "
+ OutputFile="$(OutDir)\Apache.Qpid.Interop.dll"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="&quot;$(BOOST_ROOT)\lib&quot;"
+ GenerateDebugInformation="true"
+ AssemblyDebug="1"
+ TargetMachine="1"
+ KeyFile="$(SolutionDir)\src\wcfnet.snk"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(ProjectDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ ManagedExtensions="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ CommandLine="copy ..\AmqpTypes\obj\$(ConfigurationName)\Apache.Qpid.AmqpTypes.netmodule $(ConfigurationName)"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions=" /Zm1000 /wd4244 /wd4800 /wd4355 /FU $(ConfigurationName)\Apache.Qpid.AmqpTypes.netmodule"
+ AdditionalIncludeDirectories="&quot;$(QPID_BUILD_ROOT)\include&quot;;&quot;$(QPID_BUILD_ROOT)\src&quot;;..\..\..\..\..\cpp\include;..\..\..\..\..\cpp\src;&quot;$(BOOST_ROOT)&quot;"
+ PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,BOOST_ALL_DYN_LINK,_CRT_NONSTDC_NO_WARNINGS,NOMINMAX,WIN32_LEAN_AND_MEAN,_SCL_SECURE_NO_WARNINGS,HAVE_CONFIG_H"
+ Optimization="2"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions=" /STACK:10000000 /machine:I386 $(ConfigurationName)\Apache.Qpid.AmqpTypes.netmodule"
+ AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib xolehlp.lib $(QPID_BUILD_ROOT)\src\Release\qpidclient.lib $(QPID_BUILD_ROOT)\src\Release\qpidcommon.lib rpcrt4.lib ws2_32.lib "
+ LinkIncremental="2"
+ OutputFile="$(OutDir)\Apache.Qpid.Interop.dll"
+ AdditionalLibraryDirectories="&quot;$(BOOST_ROOT)\lib&quot;"
+ KeyFile="$(SolutionDir)\src\wcfnet.snk"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(ProjectDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ ManagedExtensions="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ CommandLine="copy ..\AmqpTypes\obj\$(ConfigurationName)\Apache.Qpid.AmqpTypes.netmodule $(PlatformName)\$(ConfigurationName)"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions=" /Zm1000 /wd4244 /wd4800 /wd4355 /FU $(PlatformName)\$(ConfigurationName)\Apache.Qpid.AmqpTypes.netmodule"
+ Optimization="0"
+ AdditionalIncludeDirectories="&quot;$(QPID_BUILD_ROOT)\include&quot;;&quot;$(QPID_BUILD_ROOT)\src&quot;;..\..\..\..\..\cpp\include;..\..\..\..\..\cpp\src;&quot;$(BOOST_ROOT)&quot;"
+ PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,BOOST_ALL_DYN_LINK,_CRT_NONSTDC_NO_WARNINGS,NOMINMAX,WIN32_LEAN_AND_MEAN,_SCL_SECURE_NO_WARNINGS,HAVE_CONFIG_H"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions=" /STACK:10000000 /machine:x64 /debug $(PlatformName)\$(ConfigurationName)\Apache.Qpid.AmqpTypes.netmodule"
+ AdditionalDependencies="$(NoInherit) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib rpcrt4.lib ws2_32.lib xolehlp.lib $(QPID_BUILD_ROOT)\src\Debug\qpidcommond.lib $(QPID_BUILD_ROOT)\src\Debug\qpidclientd.lib"
+ OutputFile="$(OutDir)\Apache.Qpid.Interop.dll"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="&quot;$(BOOST_ROOT)\lib&quot;"
+ GenerateDebugInformation="true"
+ AssemblyDebug="1"
+ TargetMachine="17"
+ KeyFile="$(SolutionDir)\src\wcfnet.snk"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(ProjectDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ ManagedExtensions="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ CommandLine="copy ..\AmqpTypes\obj\$(ConfigurationName)\Apache.Qpid.AmqpTypes.netmodule $(PlatformName)\$(ConfigurationName)"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions=" /Zm1000 /wd4244 /wd4800 /wd4355 /FU $(PlatformName)\$(ConfigurationName)\Apache.Qpid.AmqpTypes.netmodule"
+ AdditionalIncludeDirectories="&quot;$(QPID_BUILD_ROOT)\include&quot;;&quot;$(QPID_BUILD_ROOT)\src&quot;;..\..\..\..\..\cpp\include;..\..\..\..\..\cpp\src;&quot;$(BOOST_ROOT)&quot;"
+ PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,BOOST_ALL_DYN_LINK,_CRT_NONSTDC_NO_WARNINGS,NOMINMAX,WIN32_LEAN_AND_MEAN,_SCL_SECURE_NO_WARNINGS,HAVE_CONFIG_H"
+ InlineFunctionExpansion="2"
+ Optimization="2"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions=" /STACK:10000000 /machine:x64 $(PlatformName)\$(ConfigurationName)\Apache.Qpid.AmqpTypes.netmodule"
+ AdditionalDependencies="$(NoInherit) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib xolehlp.lib $(QPID_BUILD_ROOT)\src\Release\qpidclient.lib $(QPID_BUILD_ROOT)\src\Release\qpidcommon.lib rpcrt4.lib ws2_32.lib"
+ LinkIncremental="2"
+ OutputFile="$(OutDir)\Apache.Qpid.Interop.dll"
+ AdditionalLibraryDirectories="&quot;$(BOOST_ROOT)\lib&quot;"
+ KeyFile="$(SolutionDir)\src\wcfnet.snk"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ <AssemblyReference
+ RelativePath="System.dll"
+ AssemblyName="System, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"
+ MinFrameworkVersion="131072"
+ />
+ <AssemblyReference
+ RelativePath="System.Data.dll"
+ AssemblyName="System.Data, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=x86"
+ MinFrameworkVersion="131072"
+ />
+ <AssemblyReference
+ RelativePath="System.XML.dll"
+ AssemblyName="System.Xml, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"
+ MinFrameworkVersion="131072"
+ />
+ <AssemblyReference
+ RelativePath="System.Runtime.Serialization.dll"
+ AssemblyName="System.Runtime.Serialization, Version=3.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"
+ MinFrameworkVersion="196608"
+ />
+ <AssemblyReference
+ RelativePath="System.Transactions.dll"
+ AssemblyName="System.Transactions, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=x86"
+ MinFrameworkVersion="131072"
+ />
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\AmqpConnection.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\AmqpMessage.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\AmqpSession.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\AssemblyInfo.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\CompletionWaiter.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\InputLink.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\MessageBodyStream.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\MessageWaiter.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\OutputLink.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\DtxResourceManager.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\XaTransaction.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\AmqpConnection.h"
+ >
+ </File>
+ <File
+ RelativePath=".\AmqpMessage.h"
+ >
+ </File>
+ <File
+ RelativePath=".\AmqpSession.h"
+ >
+ </File>
+ <File
+ RelativePath=".\CompletionWaiter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\InputLink.h"
+ >
+ </File>
+ <File
+ RelativePath=".\MessageBodyStream.h"
+ >
+ </File>
+ <File
+ RelativePath=".\MessageWaiter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\OutputLink.h"
+ >
+ </File>
+ <File
+ RelativePath=".\QpidException.h"
+ >
+ </File>
+ <File
+ RelativePath=".\QpidMarshal.h"
+ >
+ </File>
+ <File
+ RelativePath=".\DtxResourceManager.h"
+ >
+ </File>
+ <File
+ RelativePath=".\XaTransaction.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/wcf/src/Apache/Qpid/Interop/MessageBodyStream.cpp b/wcf/src/Apache/Qpid/Interop/MessageBodyStream.cpp
new file mode 100644
index 0000000000..f2cb5740d3
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/MessageBodyStream.cpp
@@ -0,0 +1,337 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#include <windows.h>
+#include <msclr\lock.h>
+
+#include "qpid/client/AsyncSession.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/framing/AMQFrame.h"
+
+#include "MessageBodyStream.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+using namespace System::Threading;
+using namespace msclr;
+
+using namespace qpid::client;
+using namespace qpid::framing;
+
+// Thefolowing def must match "Frames" private typedef.
+// TODO: make "Frames" publicly visible.
+typedef qpid::InlineVector<AMQFrame, 4> FrameSetFrames;
+
+using namespace std;
+
+static void ThrowIfBadArgs (array<unsigned char>^ buffer, int offset, int count)
+{
+ if (buffer == nullptr)
+ throw gcnew ArgumentNullException("buffer");
+
+ if (offset < 0)
+ throw gcnew ArgumentOutOfRangeException("offset");
+
+ if (count < 0)
+ throw gcnew ArgumentOutOfRangeException("count");
+
+ if ((offset + count) > buffer->Length)
+ throw gcnew ArgumentException("offset + count");
+}
+
+
+// Input stream constructor
+
+MessageBodyStream::MessageBodyStream(FrameSet::shared_ptr *fspp)
+{
+ isInputStream = true;
+ frameSetpp = fspp;
+ fragmentCount = 0;
+ length = 0;
+ position = 0;
+ currentFramep = NULL;
+
+ const std::string *datap; // pointer to the fragment's string variable that holds the content
+
+ for(FrameSetFrames::const_iterator i = (*frameSetpp)->begin(); i != (*frameSetpp)->end(); i++) {
+ if (i->getBody()->type() == CONTENT_BODY) {
+ fragmentCount++;
+ datap = &(i->castBody<AMQContentBody>()->getData());
+ length += datap->size();
+ }
+ }
+
+ // fragmentCount can be zero for an empty message
+
+ fragmentIndex = 0;
+ fragmentPosition = 0;
+
+ if (fragmentCount == 0) {
+ currentFragment = NULL;
+ fragmentLength = 0;
+ }
+ else if (fragmentCount == 1) {
+ currentFragment = datap->data();
+ fragmentLength = (int) length;
+ }
+ else {
+ fragments = gcnew array<IntPtr>(fragmentCount);
+ fragmentIndex = 0;
+ for(FrameSetFrames::const_iterator i = (*frameSetpp)->begin(); i != (*frameSetpp)->end(); i++) {
+ if (i->getBody()->type() == CONTENT_BODY) {
+ datap = &(i->castBody<AMQContentBody>()->getData());
+ fragments[fragmentIndex++] = (IntPtr) (void *) datap;
+ }
+ }
+ fragmentIndex = 0;
+ datap = (const std::string *) fragments[0].ToPointer();
+ currentFragment = datap->data();
+ fragmentLength = datap->size();
+ }
+}
+
+
+int MessageBodyStream::Read(array<unsigned char>^ buffer, int offset, int count)
+{
+ if (!isInputStream)
+ throw gcnew NotSupportedException();
+ if (disposed)
+ throw gcnew ObjectDisposedException("Stream");
+ if (count == 0)
+ return 0;
+ ThrowIfBadArgs(buffer, offset, count);
+
+ int nRead = 0;
+ int remaining = count;
+
+ while (nRead < count) {
+ int fragAvail = fragmentLength - fragmentPosition;
+ int copyCount = min (fragAvail, remaining);
+ if (copyCount == 0) {
+ // no more to read
+ return nRead;
+ }
+
+ // copy from native space
+ IntPtr nativep = (IntPtr) (void *) (currentFragment + fragmentPosition);
+ Marshal::Copy (nativep, buffer, offset, copyCount);
+ nRead += copyCount;
+ remaining -= copyCount;
+ fragmentPosition += copyCount;
+ offset += copyCount;
+
+ // advance to next fragment?
+ if (fragmentPosition == fragmentLength) {
+ if (++fragmentIndex < fragmentCount) {
+ const std::string *datap = (const std::string *) fragments[fragmentIndex].ToPointer();
+ currentFragment = datap->data();
+ fragmentLength = datap->size();
+ fragmentPosition = 0;
+ }
+ }
+ }
+
+ return nRead;
+}
+
+
+void MessageBodyStream::pushCurrentFrame(bool lastFrame)
+{
+ // set flags as in SessionImpl::sendContent.
+ if (currentFramep->getBody()->type() == CONTENT_BODY) {
+
+ if ((fragmentCount == 1) && lastFrame) {
+ // only one content frame
+ currentFramep->setFirstSegment(false);
+ }
+ else {
+ currentFramep->setFirstSegment(false);
+ currentFramep->setLastSegment(true);
+ if (fragmentCount != 1) {
+ currentFramep->setFirstFrame(false);
+ }
+ if (!lastFrame) {
+ currentFramep->setLastFrame(false);
+ }
+ }
+ }
+ else {
+ // the header frame
+ currentFramep->setFirstSegment(false);
+ if (!lastFrame) {
+ // there will be at least one content frame
+ currentFramep->setLastSegment(false);
+ }
+ }
+
+ // add to frame set. This makes a copy and ref counts the body
+ (*frameSetpp)->append(*currentFramep);
+
+ delete currentFramep;
+
+ currentFramep = NULL;
+}
+
+
+IntPtr MessageBodyStream::GetFrameSet()
+{
+ if (currentFramep != NULL) {
+ // No more content. Tidy up the pending (possibly single header) frame.
+ pushCurrentFrame(true);
+ }
+
+ if (frameSetpp == NULL) {
+ return (IntPtr) NULL;
+ }
+
+ // shared_ptr.get()
+ return (IntPtr) (void *) (*frameSetpp).get();
+}
+
+IntPtr MessageBodyStream::GetHeader()
+{
+ return (IntPtr) headerBodyp;
+}
+
+
+// Ouput stream constructor
+
+MessageBodyStream::MessageBodyStream(int maxFrameSize)
+{
+ isInputStream = false;
+
+ maxFrameContentSize = maxFrameSize - AMQFrame::frameOverhead();
+ SequenceNumber unused; // only meaningful on incoming frames
+ frameSetpp = new FrameSet::shared_ptr(new FrameSet(unused));
+ fragmentCount = 0;
+ length = 0;
+ position = 0;
+
+ // header goes first in the outgoing frameset
+
+ boost::intrusive_ptr<AMQBody> headerBody(new AMQHeaderBody);
+ currentFramep = new AMQFrame(headerBody);
+ headerBodyp = static_cast<AMQHeaderBody*>(headerBody.get());
+
+ // mark this header frame as "full" to force the first write to create a new content frame
+ fragmentPosition = maxFrameContentSize;
+}
+
+void MessageBodyStream::Write(array<unsigned char>^ buffer, int offset, int count)
+{
+ if (isInputStream)
+ throw gcnew NotSupportedException();
+ if (disposed)
+ throw gcnew ObjectDisposedException("Stream");
+ if (count == 0)
+ return;
+ ThrowIfBadArgs(buffer, offset, count);
+
+ if (currentFramep == NULL) {
+ // GetFrameSet() has been called and we no longer exclusively own the underlying frames.
+ throw gcnew InvalidOperationException ("Mesage Body output already completed");
+ }
+
+ if (count <= 0)
+ return;
+
+ // keep GC memory movement at bay while copying to native space
+ pin_ptr<unsigned char> pinnedBuf = &buffer[0];
+
+ string *datap;
+
+ int remaining = count;
+ while (remaining > 0) {
+ if (fragmentPosition == maxFrameContentSize) {
+ // move to a new frame, but not until ready to add new content.
+ // zero content is valid, or the final write may exactly fill to maxFrameContentSize
+
+ pushCurrentFrame(false);
+
+ currentFramep = new AMQFrame(AMQContentBody());
+ fragmentPosition = 0;
+ fragmentCount++;
+ }
+
+ int copyCount = min (remaining, (maxFrameContentSize - fragmentPosition));
+ datap = &(currentFramep->castBody<AMQContentBody>()->getData());
+
+ char *outp = (char *) pinnedBuf + offset;
+ if (fragmentPosition == 0) {
+ datap->assign(outp, copyCount);
+ }
+ else {
+ datap->append(outp, copyCount);
+ }
+
+ position += copyCount;
+ fragmentPosition += copyCount;
+ remaining -= copyCount;
+ offset += copyCount;
+ }
+}
+
+
+void MessageBodyStream::Cleanup()
+{
+ {
+ lock l(this);
+ if (disposed)
+ return;
+
+ disposed = true;
+ }
+
+ try {}
+ finally
+ {
+ if (frameSetpp != NULL) {
+ delete frameSetpp;
+ frameSetpp = NULL;
+ }
+ if (currentFramep != NULL) {
+ delete currentFramep;
+ currentFramep = NULL;
+ }
+ }
+}
+
+MessageBodyStream::~MessageBodyStream()
+{
+ Cleanup();
+}
+
+MessageBodyStream::!MessageBodyStream()
+{
+ Cleanup();
+}
+
+void MessageBodyStream::Close()
+{
+ // Simulate Dispose()...
+ Cleanup();
+ GC::SuppressFinalize(this);
+}
+
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/wcf/src/Apache/Qpid/Interop/MessageBodyStream.h b/wcf/src/Apache/Qpid/Interop/MessageBodyStream.h
new file mode 100644
index 0000000000..fa8e3f6bde
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/MessageBodyStream.h
@@ -0,0 +1,131 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace std;
+
+
+// This class provides memory streaming of the message body contents
+// between native and managed space. To avoid additional memory copies
+// in native space, it reads and writes directly to the low level Qpid
+// frames.
+
+public ref class MessageBodyStream : System::IO::Stream
+{
+private:
+ bool isInputStream;
+ long long length;
+ long long position;
+
+ // the boost smart pointer that keeps the message body frames in memory
+ FrameSet::shared_ptr *frameSetpp;
+
+ int fragmentCount;
+ int fragmentIndex;
+ const char* currentFragment;
+ int fragmentPosition;
+ int fragmentLength;
+ array<IntPtr>^ fragments;
+
+ int maxFrameContentSize;
+ AMQFrame* currentFramep;
+ void* headerBodyp;
+ bool disposed;
+ bool finalizing;
+ void Cleanup();
+
+internal:
+ // incoming message
+ MessageBodyStream(FrameSet::shared_ptr *fspp);
+ // outgoing message
+ MessageBodyStream(int maxFrameSize);
+ void pushCurrentFrame(bool last);
+public:
+ ~MessageBodyStream();
+ !MessageBodyStream();
+ virtual void Close() override;
+ virtual int Read(
+ [InAttribute] [OutAttribute] array<unsigned char>^ buffer,
+ int offset,
+ int count) override;
+
+ virtual void Write(
+ array<unsigned char>^ buffer,
+ int offset,
+ int count) override;
+
+
+ IntPtr GetFrameSet();
+ IntPtr GetHeader();
+
+ virtual void Flush() override {} // noop
+
+
+ // TODO: see CanSeek below.
+ virtual long long Seek(
+ long long offset,
+ System::IO::SeekOrigin origin) override {throw gcnew System::NotSupportedException(); }
+
+ // TODO: see CanSeek below.
+ virtual void SetLength(
+ long long value) override {throw gcnew System::NotSupportedException(); }
+
+ virtual property long long Length {
+ long long get() override { return length; }
+ };
+
+ virtual property long long Position {
+ long long get() override { return position; }
+ void set(long long p) override { throw gcnew System::NotSupportedException(); }
+ };
+
+
+ virtual property bool CanRead {
+ bool get () override { return isInputStream; }
+ }
+
+ virtual property bool CanWrite {
+ bool get () override { return !isInputStream; }
+ }
+
+ // Note: this class must return true to signal that the Length property works.
+ // Required by the raw message encoder.
+ // "If a class derived from Stream does not support seeking, calls to Length,
+ // SetLength, Position, and Seek throw a NotSupportedException".
+
+ virtual property bool CanSeek {
+ bool get () override { return true; }
+ }
+
+ virtual property bool CanTimeout {
+ bool get () override { return isInputStream; }
+ }
+};
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/wcf/src/Apache/Qpid/Interop/MessageWaiter.cpp b/wcf/src/Apache/Qpid/Interop/MessageWaiter.cpp
new file mode 100644
index 0000000000..f7a28b0692
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/MessageWaiter.cpp
@@ -0,0 +1,251 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#include <windows.h>
+#include <msclr\lock.h>
+
+#include "qpid/client/AsyncSession.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/client/Demux.h"
+#include "qpid/client/SessionImpl.h"
+#include "qpid/client/SessionBase_0_10Access.h"
+
+#include "MessageBodyStream.h"
+#include "AmqpMessage.h"
+#include "AmqpSession.h"
+#include "InputLink.h"
+#include "MessageWaiter.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Threading;
+using namespace msclr;
+
+
+MessageWaiter::MessageWaiter(InputLink^ parent, TimeSpan timeSpan, bool consuming, bool async, AsyncCallback ^callback, Object^ state)
+{
+ this->consuming = consuming;
+ if (!consuming) {
+ GC::SuppressFinalize(this);
+ }
+
+ if (async) {
+ this->async = true;
+ this->asyncCallback = callback;
+ this->state = state;
+ }
+ else {
+ this->assigned = true;
+ }
+ this->parent = parent;
+ this->thisLock = gcnew Object();
+
+ // do this after the Message Waiter is fully initialized, in case of
+ // very small timespan
+ if (timeSpan != TimeSpan::MaxValue) {
+ this->timer = gcnew Timer(timeoutCallback, this, timeSpan, TimeSpan::FromMilliseconds(-1));
+ }
+}
+
+MessageWaiter::~MessageWaiter()
+{
+ if (message != IntPtr::Zero) {
+ try{}
+ finally {
+ delete message.ToPointer();
+ message = IntPtr::Zero;
+ }
+ }
+}
+
+MessageWaiter::!MessageWaiter()
+{
+ this->~MessageWaiter();
+}
+
+
+void MessageWaiter::WaitForCompletion()
+{
+ if (isCompleted)
+ return;
+
+ lock l(thisLock);
+ while (!isCompleted) {
+ Monitor::Wait(thisLock);
+ }
+}
+
+void MessageWaiter::Activate()
+{
+ if (activated)
+ return;
+
+ lock l(thisLock);
+ if (!activated) {
+ activated = true;
+ Monitor::PulseAll(thisLock);
+ }
+}
+
+
+void MessageWaiter::Run()
+{
+ lock l(thisLock);
+
+ // wait until Activate(), i.e. our turn in the waiter list or a timeout
+ while (!activated) {
+ Monitor::Wait(thisLock);
+ }
+ bool haveMessage = false;
+ bool mustReset = false;
+
+ if (!timedOut)
+ blocking = true;
+
+ if (blocking) {
+ l.release();
+
+ try {
+ haveMessage = parent->internalWaitForMessage();
+ }
+ catch (System::Exception^ e) {
+ runException = e;
+ }
+
+ l.acquire();
+ blocking = false;
+ if (timedOut) {
+ // TimeoutCallback() called parent->unblockWaiter()
+ mustReset = true;
+ // let the timer thread move past critical region
+ while (processingTimeout) {
+ Monitor::Wait(thisLock);
+ }
+ }
+ }
+
+ if (timer != nullptr) {
+ timer->~Timer();
+ timer = nullptr;
+ }
+
+ if (haveMessage) {
+ timedOut = false; // for the case timeout and message arrival are essentially tied
+ if (!consuming) {
+ // just waiting
+ haveMessage = false;
+ }
+ }
+
+ if (haveMessage || mustReset) {
+ l.release();
+ if (haveMessage) {
+ // hang on to it for when the async caller gets around to retrieving
+ message = parent->nextLocalMessage();
+ }
+ if (mustReset) {
+ parent->resetQueue();
+ }
+ l.acquire();
+ }
+
+ isCompleted = true;
+ Monitor::PulseAll(thisLock);
+
+ // do this check and signal while locked
+ if (asyncWaitHandle != nullptr)
+ asyncWaitHandle->Set();
+
+ l.release();
+ parent->removeWaiter(this);
+
+
+ if (asyncCallback != nullptr) {
+ // guard against application callback exception
+ try {
+ asyncCallback(this);
+ }
+ catch (System::Exception^) {
+ // log it?
+ }
+ }
+
+}
+
+bool MessageWaiter::AcceptForWork()
+{
+ lock l(thisLock);
+ if (!assigned) {
+ assigned = true;
+ return true;
+ }
+ return false;
+}
+
+void MessageWaiter::TimeoutCallback(Object^ state)
+{
+ MessageWaiter^ waiter = (MessageWaiter^) state;
+ if (waiter->isCompleted)
+ return;
+
+ // make sure parent has finished initializing us before we get going
+ waiter->parent->sync();
+
+ lock l(waiter->thisLock);
+ if (waiter->timer == nullptr) {
+ // the waiter is in the clean up phase and doesn't need a wakeup
+ return;
+ }
+
+ // timedOut, blocking and processingTimeout work as a unit
+ waiter->timedOut = true;
+ if (waiter->blocking) {
+ // let the waiter know that we are busy with an upcoming unblock operation
+ waiter->processingTimeout = true;
+ }
+
+ waiter->Activate();
+
+ if (waiter->processingTimeout) {
+ // call with lock off
+ l.release();
+ waiter->parent->unblockWaiter();
+
+ // synchronize with blocked thread
+ l.acquire();
+ waiter->processingTimeout = false;
+ Monitor::PulseAll(waiter->thisLock);
+ }
+
+ l.release();
+
+ // If waiter has no associated thread, we must move it to completion
+ if (waiter->AcceptForWork()) {
+ waiter->Run(); // does not block since timedOut == true
+ }
+}
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/wcf/src/Apache/Qpid/Interop/MessageWaiter.h b/wcf/src/Apache/Qpid/Interop/MessageWaiter.h
new file mode 100644
index 0000000000..3737430844
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/MessageWaiter.h
@@ -0,0 +1,125 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Threading;
+
+public ref class MessageWaiter : IAsyncResult
+{
+private:
+ // Receive() or WaitForMessage()
+ bool consuming;
+ bool consumed;
+ bool timedOut;
+ bool async;
+ // has an owner thread
+ bool assigned;
+ // can Run (i.e. earlier MessageWaiters in the queue have completed)
+ bool activated;
+ // is making a call to internalWaitForMessage() which (usually) blocks
+ bool blocking;
+ // the timeout timer thread is lurking
+ bool processingTimeout;
+ // the saved exception from within Run() for async delivery
+ System::Exception^ runException;
+ AsyncCallback^ asyncCallback;
+ Threading::Timer ^timer;
+ bool isCompleted;
+ bool completedSynchronously;
+ Object^ state;
+ Object^ thisLock;
+ ManualResetEvent^ asyncWaitHandle;
+ InputLink^ parent;
+ static void TimeoutCallback(Object^ state);
+ static TimerCallback^ timeoutCallback = gcnew TimerCallback(MessageWaiter::TimeoutCallback);
+ IntPtr message;
+ !MessageWaiter();
+ ~MessageWaiter();
+
+ internal:
+ MessageWaiter(InputLink^ parent, TimeSpan timeSpan, bool consuming, bool async, AsyncCallback ^callback, Object^ state);
+
+ void Run();
+ bool AcceptForWork();
+ void Activate();
+ void WaitForCompletion();
+
+
+ property IntPtr Message {
+ IntPtr get () {
+ if (!consuming || consumed)
+ throw gcnew InvalidOperationException("Message property");
+ consumed = true;
+ IntPtr v = message;
+ message = IntPtr::Zero;
+ GC::SuppressFinalize(this);
+ return v;
+ }
+ }
+
+ property bool Assigned {
+ bool get () { return assigned; }
+ }
+
+ property bool TimedOut {
+ bool get () { return timedOut; }
+ }
+
+ property System::Exception^ RunException {
+ System::Exception^ get() { return runException; }
+ }
+
+
+ public:
+
+ virtual property bool IsCompleted {
+ bool get () { return isCompleted; }
+ }
+
+ virtual property bool CompletedSynchronously {
+ bool get () { return completedSynchronously; }
+ }
+
+ virtual property WaitHandle^ AsyncWaitHandle {
+ WaitHandle^ get () {
+ if (asyncWaitHandle != nullptr) {
+ return asyncWaitHandle;
+ }
+
+ msclr::lock l(thisLock);
+ if (asyncWaitHandle == nullptr) {
+ asyncWaitHandle = gcnew ManualResetEvent(isCompleted);
+ }
+ return asyncWaitHandle;
+ }
+ }
+
+ virtual property Object^ AsyncState {
+ Object^ get () { return state; }
+ }
+};
+
+}}} // namespace Apache::Qpid::Interop
+
diff --git a/wcf/src/Apache/Qpid/Interop/OutputLink.cpp b/wcf/src/Apache/Qpid/Interop/OutputLink.cpp
new file mode 100644
index 0000000000..27725b8207
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/OutputLink.cpp
@@ -0,0 +1,251 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#include <windows.h>
+#include <msclr\lock.h>
+
+#include "qpid/client/AsyncSession.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/MessageListener.h"
+
+
+#include "AmqpSession.h"
+#include "AmqpMessage.h"
+#include "OutputLink.h"
+#include "QpidMarshal.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+using namespace System::Threading;
+using namespace msclr;
+
+using namespace qpid::client;
+using namespace std;
+
+using namespace Apache::Qpid::AmqpTypes;
+
+
+OutputLink::OutputLink(AmqpSession^ session, String^ defaultQueue) :
+ amqpSession(session),
+ queue(defaultQueue),
+ disposed(false),
+ maxFrameSize(session->Connection->MaxFrameSize),
+ finalizing(false)
+{
+}
+
+void OutputLink::Cleanup()
+{
+ {
+ lock l(this);
+ if (disposed)
+ return;
+
+ disposed = true;
+ }
+
+ amqpSession->NotifyClosed();
+}
+
+OutputLink::~OutputLink()
+{
+ Cleanup();
+}
+
+OutputLink::!OutputLink()
+{
+ Cleanup();
+}
+
+void OutputLink::Close()
+{
+ // Simulate Dispose()...
+ Cleanup();
+ GC::SuppressFinalize(this);
+}
+
+
+AmqpMessage^ OutputLink::CreateMessage()
+{
+ MessageBodyStream ^mbody = gcnew MessageBodyStream(maxFrameSize);
+ AmqpMessage ^amqpm = gcnew AmqpMessage(mbody);
+ return amqpm;
+}
+
+
+void OutputLink::ManagedToNative(AmqpMessage^ m)
+{
+ MessageBodyStream^ messageBodyStream = (MessageBodyStream^ ) m->BodyStream;
+
+ AmqpProperties^ mprops = m->Properties;
+
+ if (mprops != nullptr) {
+ AMQHeaderBody* bodyp = (AMQHeaderBody*) messageBodyStream->GetHeader().ToPointer();
+
+ if (mprops->HasDeliveryProperties) {
+ DeliveryProperties* deliveryPropertiesp = bodyp->get<DeliveryProperties>(true);
+
+ if (mprops->RoutingKey != nullptr) {
+ deliveryPropertiesp->setRoutingKey(QpidMarshal::ToNative(mprops->RoutingKey));
+ }
+
+ if (mprops->Durable) {
+ deliveryPropertiesp->setDeliveryMode(qpid::framing::PERSISTENT);
+ }
+
+ if (mprops->TimeToLive.HasValue) {
+ long long ttl = mprops->TimeToLive.Value.Ticks;
+ bool was_positive = (ttl > 0);
+ if (ttl < 0)
+ ttl = 0;
+ ttl = ttl / TimeSpan::TicksPerMillisecond;
+ if ((ttl == 0) && was_positive)
+ ttl = 1;
+ deliveryPropertiesp->setTtl(ttl);
+ }
+ }
+
+ if (mprops->HasMessageProperties) {
+ qpid::framing::MessageProperties* messagePropertiesp =
+ bodyp->get<qpid::framing::MessageProperties>(true);
+
+ String^ replyToExchange = mprops->ReplyToExchange;
+ String^ replyToRoutingKey = mprops->ReplyToRoutingKey;
+ if ((replyToExchange != nullptr) || (replyToRoutingKey != nullptr)) {
+ qpid::framing::ReplyTo nReplyTo;
+ if (replyToExchange != nullptr) {
+ nReplyTo.setExchange(QpidMarshal::ToNative(replyToExchange));
+ }
+ if (replyToRoutingKey != nullptr) {
+ nReplyTo.setRoutingKey(QpidMarshal::ToNative(replyToRoutingKey));
+ }
+ messagePropertiesp->setReplyTo(nReplyTo);
+ }
+
+ // TODO: properly split 1.0 style to 0-10 content type + encoding
+
+ String^ contentType = mprops->ContentType;
+ if (contentType != nullptr) {
+ String^ type = nullptr;
+ String^ enc = nullptr;
+ int idx = contentType->IndexOf(';');
+ if (idx == -1) {
+ type = contentType;
+ }
+ else {
+ type = contentType->Substring(0, idx);
+ contentType = contentType->Substring(idx + 1);
+ idx = contentType->IndexOf('=');
+ if (idx != -1) {
+ enc = contentType->Substring(idx + 1);
+ enc = enc->Trim();
+ }
+ }
+ if (!String::IsNullOrEmpty(type)) {
+ messagePropertiesp->setContentType(QpidMarshal::ToNative(type));
+ }
+ if (!String::IsNullOrEmpty(enc)) {
+ messagePropertiesp->setContentEncoding(QpidMarshal::ToNative(enc));
+ }
+ }
+
+
+ array<unsigned char>^ mbytes = mprops->CorrelationId;
+ if (mbytes != nullptr) {
+ pin_ptr<unsigned char> pinnedBuf = &mbytes[0];
+ std::string s((char *) pinnedBuf, mbytes->Length);
+ messagePropertiesp->setCorrelationId(s);
+ }
+
+ mbytes = mprops->UserId;
+ if (mbytes != nullptr) {
+ pin_ptr<unsigned char> pinnedBuf = &mbytes[0];
+ std::string s((char *) pinnedBuf, mbytes->Length);
+ messagePropertiesp->setUserId(s);
+ }
+
+ if (mprops->HasMappedProperties) {
+ qpid::framing::FieldTable fieldTable;
+ // TODO: add support for abitrary AMQP types
+ for each (Collections::Generic::KeyValuePair<System::String^, AmqpType^> kvp in mprops->PropertyMap) {
+ Type^ type = kvp.Value->GetType();
+ if (type == AmqpInt::typeid) {
+ fieldTable.setInt(QpidMarshal::ToNative(kvp.Key),
+ ((AmqpInt ^) kvp.Value)->Value);
+ }
+ else if (type == AmqpString::typeid) {
+ AmqpString^ str = (AmqpString ^) kvp.Value;
+ // For now, FieldTable supports a single string type
+ fieldTable.setString(QpidMarshal::ToNative(kvp.Key), QpidMarshal::ToNative(str->Value));
+ }
+ }
+
+ messagePropertiesp->setApplicationHeaders(fieldTable);
+ }
+ }
+ }
+}
+
+
+
+void OutputLink::Send(AmqpMessage^ amqpMessage, TimeSpan timeout)
+{
+ // copy properties from managed space to the native counterparts
+ ManagedToNative(amqpMessage);
+
+ MessageBodyStream^ messageBodyStream = (MessageBodyStream^ ) amqpMessage->BodyStream;
+ CompletionWaiter^ waiter = amqpSession->SendMessage(queue, messageBodyStream, timeout, false, nullptr, nullptr);
+
+ if (waiter != nullptr) {
+ waiter->WaitForCompletion();
+ if (waiter->TimedOut) {
+ throw gcnew TimeoutException("Receive");
+ }
+ }
+ // else: SendMessage() has already waited for the Completion
+
+}
+
+IAsyncResult^ OutputLink::BeginSend(AmqpMessage^ amqpMessage, TimeSpan timeout, AsyncCallback^ callback, Object^ state)
+{
+ ManagedToNative(amqpMessage);
+
+ MessageBodyStream^ messageBodyStream = (MessageBodyStream^ ) amqpMessage->BodyStream;
+ CompletionWaiter^ waiter = amqpSession->SendMessage(queue, messageBodyStream, timeout, true, callback, state);
+ return waiter;
+}
+
+void OutputLink::EndSend(IAsyncResult^ result)
+{
+ CompletionWaiter^ waiter = (CompletionWaiter ^) result;
+ waiter->WaitForCompletion();
+ if (waiter->TimedOut) {
+ throw gcnew TimeoutException("Receive");
+ }
+}
+
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/wcf/src/Apache/Qpid/Interop/OutputLink.h b/wcf/src/Apache/Qpid/Interop/OutputLink.h
new file mode 100644
index 0000000000..1f049a7412
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/OutputLink.h
@@ -0,0 +1,64 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+
+using namespace qpid::client;
+using namespace std;
+
+
+public ref class OutputLink
+{
+private:
+ AmqpSession^ amqpSession;
+ String^ queue;
+ bool disposed;
+ bool finalizing;
+ void Cleanup();
+ AmqpTypes::AmqpProperties^ defaultProperties;
+ void ManagedToNative(AmqpMessage^ m);
+ int maxFrameSize;
+
+internal:
+ OutputLink(AmqpSession^ session, String^ defaultQueue);
+
+public:
+ ~OutputLink();
+ !OutputLink();
+ void Close();
+ AmqpMessage^ CreateMessage();
+ void Send(AmqpMessage^ m, TimeSpan timeout);
+ IAsyncResult^ BeginSend(AmqpMessage^ amqpMessage, TimeSpan timeout, AsyncCallback^ callback, Object^ state);
+ void EndSend(IAsyncResult^ result);
+
+ property AmqpTypes::AmqpProperties^ DefaultProperties {
+ AmqpTypes::AmqpProperties^ get () { return defaultProperties; }
+ void set(AmqpTypes::AmqpProperties^ p) { defaultProperties = p; }
+ }
+};
+
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/wcf/src/Apache/Qpid/Interop/QpidException.h b/wcf/src/Apache/Qpid/Interop/QpidException.h
new file mode 100644
index 0000000000..91677a5e73
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/QpidException.h
@@ -0,0 +1,37 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+
+public ref class QpidException : System::Exception
+{
+ public:
+
+ QpidException() : System::Exception() {}
+ QpidException(String^ estring) : System::Exception(estring) {}
+
+};
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/wcf/src/Apache/Qpid/Interop/QpidMarshal.h b/wcf/src/Apache/Qpid/Interop/QpidMarshal.h
new file mode 100644
index 0000000000..3e22af7b39
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/QpidMarshal.h
@@ -0,0 +1,53 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Text;
+
+
+// Helper functions for marshaling.
+
+private ref class QpidMarshal
+{
+ public:
+
+ // marshal_as<T> not available in all Visual Studio editions.
+
+ static std::string ToNative (System::String^ managed) {
+ if (managed->Length == 0) {
+ return std::string();
+ }
+ array<unsigned char>^ mbytes = Encoding::UTF8->GetBytes(managed);
+ if (mbytes->Length == 0) {
+ return std::string();
+ }
+
+ pin_ptr<unsigned char> pinnedBuf = &mbytes[0];
+ std::string native((char *) pinnedBuf, mbytes->Length);
+ return native;
+ }
+};
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/wcf/src/Apache/Qpid/Interop/XaTransaction.cpp b/wcf/src/Apache/Qpid/Interop/XaTransaction.cpp
new file mode 100644
index 0000000000..23743316ff
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/XaTransaction.cpp
@@ -0,0 +1,525 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#include <windows.h>
+#include <msclr\lock.h>
+#include <transact.h>
+#include <xolehlp.h>
+#include <txdtc.h>
+#include <oletx2xa.h>
+#include <iostream>
+#include <fstream>
+
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/Connection.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/framing/Xid.h"
+
+#include "QpidException.h"
+#include "AmqpConnection.h"
+#include "AmqpSession.h"
+#include "DtxResourceManager.h"
+#include "XaTransaction.h"
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+using namespace System::Transactions;
+using namespace msclr;
+
+using namespace qpid::framing::dtx;
+
+// ------------------------------------------------------------------------
+// Start of a pure native code section
+#pragma unmanaged
+// ------------------------------------------------------------------------
+
+// This is the native COM object the DTC expects to talk to for coordination.
+// There is exactly one native instance of this for each managed XaTransaction object.
+
+
+class DtcCallbackHandler : public ITransactionResourceAsync
+{
+private:
+ long useCount;
+ DtcCallbackFp managedCallback;
+public:
+ ITransactionEnlistmentAsync *txHandle;
+ DtcCallbackHandler(DtcCallbackFp cbp) : managedCallback(cbp), useCount(0) {}
+ ~DtcCallbackHandler() {}
+ virtual HRESULT __stdcall PrepareRequest(BOOL unused, DWORD grfrm, BOOL unused2, BOOL singlePhase);
+ virtual HRESULT __stdcall CommitRequest(DWORD grfrm, XACTUOW *unused);
+ virtual HRESULT __stdcall AbortRequest(BOID *unused, BOOL unused2, XACTUOW *unused3);
+
+ virtual HRESULT __stdcall TMDown();
+ virtual HRESULT __stdcall DtcCallbackHandler::QueryInterface (REFIID riid, void **ppvObject);
+ virtual ULONG __stdcall DtcCallbackHandler::AddRef();
+ virtual ULONG __stdcall DtcCallbackHandler::Release();
+ void __stdcall AbortRequestDone();
+};
+
+
+HRESULT DtcCallbackHandler::PrepareRequest(BOOL unused, DWORD grfrm, BOOL unused2, BOOL singlePhase)
+{
+ if (singlePhase) {
+ return managedCallback(DTC_SINGLE_PHASE) ? S_OK : E_FAIL;
+ }
+
+ return managedCallback(DTC_PREPARE) ? S_OK : E_FAIL;
+}
+
+
+HRESULT DtcCallbackHandler::CommitRequest(DWORD grfrm, XACTUOW *unused)
+{
+ return managedCallback(DTC_COMMIT) ? S_OK : E_FAIL;
+}
+
+HRESULT DtcCallbackHandler::AbortRequest(BOID *unused, BOOL unused2, XACTUOW *unused3)
+{
+ return managedCallback(DTC_ABORT) ? S_OK : E_FAIL;
+}
+
+
+HRESULT DtcCallbackHandler::TMDown()
+{
+ return managedCallback(DTC_TMDOWN) ? S_OK : E_FAIL;
+}
+
+
+HRESULT DtcCallbackHandler::QueryInterface (REFIID riid, void **ppvObject)
+{
+ *ppvObject = NULL;
+
+ if ((riid == IID_IUnknown) || (riid == IID_IResourceManagerSink))
+ *ppvObject = this;
+ else
+ return ResultFromScode(E_NOINTERFACE);
+
+ this->AddRef();
+ return S_OK;
+}
+
+
+ULONG DtcCallbackHandler::AddRef()
+{
+ return InterlockedIncrement(&useCount);
+}
+
+
+ULONG DtcCallbackHandler::Release()
+{
+ long uc = InterlockedDecrement(&useCount);
+
+ if (uc)
+ return uc;
+
+ delete this;
+ return 0;
+}
+
+
+// ------------------------------------------------------------------------
+// End of pure native code section
+#pragma managed
+// ------------------------------------------------------------------------
+
+#ifdef QPID_RECOVERY_TEST_HOOK
+void XaTransaction::ForceRecovery() {
+ debugFailMode = true;
+}
+#endif
+
+// ------------------------------------------------------------------------
+// ------------------------------------------------------------------------
+
+
+XaTransaction::XaTransaction(Transaction^ t, IDtcToXaHelperSinglePipe *xaHelperp, DWORD rmCookie, DtxResourceManager^ rm) {
+ bool success = false;
+ xidp = NULL;
+ commandCompletionp = NULL;
+ firstDtxStartCompletionp = NULL;
+ nativeHandler = NULL;
+ resourceManager = rm;
+ controlSession = rm->DtxControlSession;
+ active = true;
+ preparing = false;
+ systemTransaction = t;
+ IntPtr comTxp = IntPtr::Zero;
+ completionHandle = gcnew ManualResetEvent(false);
+
+ try {
+ enlistedSessions = gcnew Collections::Generic::List<AmqpSession^>();
+
+ // take a System.Transactions.Transaction and obtain
+ // the corresponding DTC COM object.
+ IDtcTransaction^ dtcTransaction = TransactionInterop::GetDtcTransaction(t);
+ comTxp = Marshal::GetIUnknownForObject(dtcTransaction);
+ XID winXid;
+ HRESULT hr = xaHelperp->ConvertTridToXID((DWORD *)comTxp.ToPointer(), rmCookie, &winXid);
+ if (hr != S_OK)
+ throw gcnew QpidException("get XA XID");
+
+ // Convert the X/Open format to the internal Qpid format
+ xidp = new qpid::framing::Xid();
+ xidp->setFormat((uint32_t) winXid.formatID);
+ int bqualPos = 0;
+ if (winXid.gtrid_length > 0) {
+ xidp->setGlobalId(std::string(winXid.data, winXid.gtrid_length));
+ bqualPos = winXid.gtrid_length;
+ }
+ if (winXid.bqual_length > 0) {
+ xidp->setBranchId(std::string(winXid.data + bqualPos, winXid.bqual_length));
+ }
+
+ // create the callback chain: DTC proxy -> DtcCallbackHandler -> this
+ inboundDelegate = gcnew DtcCallbackDelegate(this, &XaTransaction::DtcCallback);
+ IntPtr ip = Marshal::GetFunctionPointerForDelegate(inboundDelegate);
+ nativeHandler = new DtcCallbackHandler(static_cast<DtcCallbackFp>(ip.ToPointer()));
+ // add myself for later smart pointer destruction
+ nativeHandler->AddRef();
+
+ hr = xaHelperp->EnlistWithRM(rmCookie, (ITransaction *)comTxp.ToPointer(), nativeHandler, &(nativeHandler->txHandle));
+
+ if (hr != S_OK)
+ throw gcnew QpidException("Enlist");
+
+ success = true;
+ }
+ finally {
+ if (!success)
+ Cleanup();
+ if (comTxp != IntPtr::Zero)
+ ((IUnknown *) comTxp.ToPointer())->Release();
+ }
+}
+
+
+void XaTransaction::Cleanup() {
+ if (firstDtxStartCompletionp != NULL) {
+ try {
+ firstEnlistedSession->ReleaseCompletion((IntPtr) firstDtxStartCompletionp);
+ }
+ catch (...) {
+ // TODO: log it?
+ }
+
+ firstDtxStartCompletionp = NULL;
+ }
+
+ if (nativeHandler != NULL) {
+ nativeHandler->Release();
+ nativeHandler = NULL;
+ }
+ if (xidp != NULL) {
+ delete xidp;
+ xidp = NULL;
+ }
+}
+
+
+XaTransaction^ XaTransaction::Enlist (AmqpSession ^session) {
+ lock l(enlistedSessions);
+ if (!active)
+ throw gcnew QpidException("transaction enlistment internal error");
+ if (!enlistedSessions->Contains(session)) {
+ enlistedSessions->Add(session);
+ if (firstEnlistedSession == nullptr) {
+ firstEnlistedSession = session;
+ IntPtr intptr = session->DtxStart((IntPtr) xidp, false, false);
+ firstDtxStartCompletionp = (TypedResult<qpid::framing::XaResult> *) intptr.ToPointer();
+ }
+ else {
+ // the broker must see the dtxStart as a join operation, and it must arrive
+ // at the broker after the first dtx start
+ if (firstDtxStartCompletionp != NULL)
+ firstDtxStartCompletionp->wait();
+ session->DtxStart((IntPtr) xidp, true, false);
+ }
+ }
+ else {
+ // already started once, so resume is true
+ session->DtxStart((IntPtr) xidp, false, true);
+ }
+ return this;
+}
+
+
+void XaTransaction::SessionClosing(AmqpSession^ session) {
+ lock l(enlistedSessions);
+ if (!enlistedSessions->Contains(session))
+ return;
+
+ enlistedSessions->Remove(session);
+ if (!active) {
+ // Phase0Flush already done on all sessions
+ l.release();
+ return;
+ }
+
+ IntPtr completion = session->BeginPhase0Flush(this);
+ session->EndPhase0Flush(this, completion);
+
+ if (session == firstEnlistedSession) {
+ // if we just completed the dtxEnd, we know the dtxStart completed before that
+ if (firstDtxStartCompletionp != NULL) {
+ firstEnlistedSession->ReleaseCompletion((IntPtr) firstDtxStartCompletionp);
+ firstDtxStartCompletionp = NULL;
+ }
+ }
+}
+
+
+void XaTransaction::Phase0Flush() {
+ // let each session delimit their transactional work with an AMQP dtx.end protocol frame
+ lock l(enlistedSessions);
+ if (!active)
+ return;
+
+ active = false; // no more enlistments
+ int scount = enlistedSessions->Count;
+
+ if (scount > 0) {
+ array<IntPtr> ^completions = gcnew array<IntPtr>(scount);
+ for (int i = 0; i < scount; i++) {
+
+ // TODO: skip phase0 flush for rollback case
+
+ completions[i] = enlistedSessions[i]->BeginPhase0Flush(this);
+ }
+
+ for (int i = 0; i < scount; i++) {
+ // without each session.sync(), session commands are queued up in the right order,
+ // but on their separate outbound channels, and destined for receipt at separate Broker inbound
+ // channels. It is not clear how to be sure Phase 0 dtx.End is processed in the
+ // correct order before commit on the broker without the sync.
+ enlistedSessions[i]->EndPhase0Flush(this, completions[i]);
+ }
+ }
+
+ // since all dtxEnds have completed, we know all starts have too
+ if (firstDtxStartCompletionp != NULL) {
+ try {
+ firstEnlistedSession->ReleaseCompletion((IntPtr) firstDtxStartCompletionp);
+ }
+ catch (...) {
+ // TODO: log it?
+ }
+
+ firstDtxStartCompletionp = NULL;
+ }
+}
+
+
+bool XaTransaction::DtcCallback (DtcCallbackType callback) {
+ // called by the DTC proxy thread. Be brief and don't block (but Phase0Flush?)
+
+ if (AppDomain::CurrentDomain->IsFinalizingForUnload())
+ return false;
+
+ IntPtr intptr = IntPtr::Zero;
+ currentCommand = callback;
+
+ try {
+ switch (callback) {
+ case DTC_PREPARE:
+ Phase0Flush();
+ try {
+ intptr = controlSession->DtxPrepare((IntPtr) xidp);
+ preparing = true;
+ resourceManager->IncrementDoubt();
+ }
+ catch (System::Exception^ ) {
+ // intptr remains nullptr
+ }
+ commandCompletionp = (TypedResult<qpid::framing::XaResult> *) intptr.ToPointer();
+ ThreadPool::QueueUserWorkItem(gcnew WaitCallback(this, &XaTransaction::AsyncCompleter));
+ break;
+
+ case DTC_COMMIT:
+#ifdef QPID_RECOVERY_TEST_HOOK
+ if (debugFailMode){ return; }
+#endif
+ // no phase 0 required. always preceded by a prepare
+ try {
+ intptr = controlSession->DtxCommit((IntPtr) xidp, false);
+ }
+ catch (System::Exception^ ) {
+ // intptr remains nullptr
+ }
+ commandCompletionp = (TypedResult<qpid::framing::XaResult> *) intptr.ToPointer();
+ ThreadPool::QueueUserWorkItem(gcnew WaitCallback(this, &XaTransaction::AsyncCompleter));
+ break;
+
+ case DTC_ABORT:
+ Phase0Flush();
+#ifdef QPID_RECOVERY_TEST_HOOK
+ if (debugFailMode){ return; }
+#endif
+ try {
+ intptr = controlSession->DtxRollback((IntPtr) xidp);
+ }
+ catch (System::Exception^ ) {
+ // intptr remains nullptr
+ }
+ commandCompletionp = (TypedResult<qpid::framing::XaResult> *) intptr.ToPointer();
+ ThreadPool::QueueUserWorkItem(gcnew WaitCallback(this, &XaTransaction::AsyncCompleter));
+ break;
+
+ case DTC_SINGLE_PHASE:
+ Phase0Flush();
+ try {
+ intptr = controlSession->DtxCommit((IntPtr) xidp, true);
+ }
+ catch (System::Exception^ ) {
+ // intptr remains nullptr
+ }
+ commandCompletionp = (TypedResult<qpid::framing::XaResult> *) intptr.ToPointer();
+ ThreadPool::QueueUserWorkItem(gcnew WaitCallback(this, &XaTransaction::AsyncCompleter));
+ break;
+
+ case DTC_TMDOWN:
+ commandCompletionp = NULL;
+ ThreadPool::QueueUserWorkItem(gcnew WaitCallback(this, &XaTransaction::AsyncCompleter));
+ break;
+ }
+ return true;
+ }
+ catch (System::Exception^ e) {
+ // TODO: log it
+ Console::WriteLine("Unexpected DtcCallback exception: {0}", e->ToString());
+ }
+ catch (...) {
+ // TODO: log it
+ }
+ return false;
+}
+
+
+// this handles the case where the application regains control for
+// a new transaction before we are notified (abort/rollback
+// optimization in DTC).
+
+void XaTransaction::NotifyPhase0() {
+ if (active)
+ Phase0Flush();
+}
+
+
+void XaTransaction::AsyncCompleter(Object ^unused) {
+ bool success = false;
+
+ if (commandCompletionp != NULL) {
+ try {
+ // waits for the AMQP broker's response and returns the decoded content
+ XaResult& xaResult = commandCompletionp->get();
+ if (xaResult.hasStatus()) {
+ if (xaResult.getStatus() == XaStatus::XA_STATUS_XA_OK) {
+ success = true;
+ }
+ }
+ }
+ catch (...) {
+ // TODO: log it?
+ }
+ try {
+ controlSession->ReleaseCompletion((IntPtr) commandCompletionp);
+ }
+ catch (...) {
+ // TODO: log it?
+ }
+
+ commandCompletionp = NULL;
+ }
+
+ ITransactionEnlistmentAsync *dtcTxHandle = nativeHandler->txHandle;
+
+ HRESULT hr = success ? S_OK : E_FAIL;
+
+ switch (currentCommand) {
+ case DTC_PREPARE:
+ dtcTxHandle->PrepareRequestDone(hr, NULL, NULL);
+ break;
+
+ case DTC_COMMIT:
+ dtcTxHandle->CommitRequestDone(hr);
+ if (success)
+ resourceManager->DecrementDoubt();
+ Complete();
+ break;
+
+ case DTC_ABORT:
+ dtcTxHandle->AbortRequestDone(hr);
+ if (success) {
+ if (preparing) {
+ preparing = false;
+ resourceManager->DecrementDoubt();
+ }
+ }
+ Complete();
+ break;
+
+ case DTC_SINGLE_PHASE:
+ if (success)
+ hr = XACT_S_SINGLEPHASE;
+ dtcTxHandle->PrepareRequestDone(hr, NULL, NULL);
+ Complete();
+ break;
+
+ case DTC_TMDOWN:
+ // Stop the RM from accepting new enlistments
+ resourceManager->TmDown();
+ Complete();
+ break;
+ }
+}
+
+
+void XaTransaction::Complete() {
+ Cleanup();
+ resourceManager->Complete(systemTransaction);
+ completionHandle->Set();
+}
+
+
+void XaTransaction::WaitForCompletion() {
+ completionHandle->WaitOne();
+}
+
+
+ /*
+void XaTransaction::WaitForFlush() {
+ isFlushedHandle->WaitOne();
+}
+ */
+
+// called from DtxResourceManager Finalize
+
+void XaTransaction::ChildFinalize() {
+ lock l(enlistedSessions);
+ Phase0Flush();
+ Cleanup();
+}
+
+
+
+}}} // namespace Apache::Qpid::Interop
diff --git a/wcf/src/Apache/Qpid/Interop/XaTransaction.h b/wcf/src/Apache/Qpid/Interop/XaTransaction.h
new file mode 100644
index 0000000000..8ff9f99893
--- /dev/null
+++ b/wcf/src/Apache/Qpid/Interop/XaTransaction.h
@@ -0,0 +1,96 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+namespace Apache {
+namespace Qpid {
+namespace Interop {
+
+using namespace System;
+using namespace System::Threading;
+using namespace System::Transactions;
+
+enum DtcCallbackType{
+ DTC_PREPARE,
+ DTC_COMMIT,
+ DTC_ABORT,
+ DTC_SINGLE_PHASE,
+ DTC_TMDOWN
+};
+
+
+ref class DtxResourceManager;
+class DtcCallbackHandler;
+
+// Function pointer declaratiom for managed space delegate
+typedef bool (__stdcall *DtcCallbackFp)(DtcCallbackType);
+
+// and the delegate with the same signature
+public delegate bool DtcCallbackDelegate(DtcCallbackType);
+
+
+
+public ref class XaTransaction
+{
+private:
+ bool active;
+ DtxResourceManager^ resourceManager;
+ Transaction^ systemTransaction;
+ AmqpSession^ controlSession;
+ Collections::Generic::List<AmqpSession^>^ enlistedSessions;
+ qpid::framing::Xid* xidp;
+ DtcCallbackHandler* nativeHandler;
+ bool preparing;
+ DtcCallbackDelegate^ inboundDelegate;
+ // the Qpid async result of the AMQP dtx prepare/commit commands
+ TypedResult<qpid::framing::XaResult>* commandCompletionp;
+ // the Qpid async result of the first session to do dtx start
+ TypedResult<qpid::framing::XaResult>* firstDtxStartCompletionp;
+ ManualResetEvent^ completionHandle;
+
+ AmqpSession^ firstEnlistedSession;
+ DtcCallbackType currentCommand;
+ void AsyncCompleter(Object ^);
+ void Phase0Flush();
+ void Cleanup();
+ void Complete();
+
+internal:
+ XaTransaction(Transaction^ t, IDtcToXaHelperSinglePipe *pXaHelper, DWORD rmCookie, DtxResourceManager^ rm);
+ XaTransaction^ Enlist (AmqpSession ^session);
+ bool DtcCallback (DtcCallbackType callback);
+ void NotifyPhase0();
+ void ChildFinalize();
+ void SessionClosing(AmqpSession^ session);
+ void WaitForCompletion();
+
+ property IntPtr XidHandle {
+ IntPtr get () { return (IntPtr) xidp; }
+ }
+
+#ifdef QPID_RECOVERY_TEST_HOOK
+ void ForceRecovery();
+ bool debugFailMode;
+#endif
+
+};
+
+}}} // namespace Apache::Qpid::Interop
+
diff --git a/wcf/src/wcfnet.snk b/wcf/src/wcfnet.snk
new file mode 100644
index 0000000000..d6456c8cf3
--- /dev/null
+++ b/wcf/src/wcfnet.snk
Binary files differ
diff --git a/wcf/test/Apache/Qpid/Test/Channel/Functional/AsyncTest.cs b/wcf/test/Apache/Qpid/Test/Channel/Functional/AsyncTest.cs
new file mode 100644
index 0000000000..bf20b5083d
--- /dev/null
+++ b/wcf/test/Apache/Qpid/Test/Channel/Functional/AsyncTest.cs
@@ -0,0 +1,190 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Test.Channel.Functional
+{
+ using System;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.Threading;
+ using NUnit.Framework;
+
+ [TestFixture]
+ public class AsyncTest
+ {
+ private const int MessageCount = 20;
+ private const string Queue = "amqp:amq.direct?routingkey=routing_key";
+ private Uri endpoint = new Uri("amqp:message_queue");
+ private TimeSpan standardTimeout = TimeSpan.FromSeconds(10.0); // seconds
+
+ [Test]
+ public void NonTryReceives()
+ {
+ this.SendMessages(this.standardTimeout, this.standardTimeout);
+ this.ReceiveNonTryMessages(this.standardTimeout, this.standardTimeout);
+ }
+
+ [Test]
+ public void TryReceives()
+ {
+ this.SendMessages(this.standardTimeout, this.standardTimeout);
+ this.ReceiveTryMessages(this.standardTimeout, this.standardTimeout);
+ }
+
+ [Test]
+ public void SmallTimeout()
+ {
+ // This code is commented out due to a bug in asynchronous channel open.
+ ////IChannelListener parentListener;
+ ////try
+ ////{
+ //// this.RetrieveAsyncChannel(new Uri("amqp:fake_queue_do_not_create"), TimeSpan.FromMilliseconds(10.0), out parentListener);
+ //// parentListener.Close();
+ //// Assert.Fail("Accepting the channel did not time out.");
+ ////}
+ ////catch (TimeoutException)
+ ////{
+ //// // Intended exception.
+ ////}
+
+ try
+ {
+ this.ReceiveNonTryMessages(this.standardTimeout, TimeSpan.FromMilliseconds(10.0));
+ Assert.Fail("Receiving a message did not time out.");
+ }
+ catch (TimeoutException)
+ {
+ // Intended exception.
+ }
+ }
+
+ private void SendMessages(TimeSpan channelTimeout, TimeSpan messageSendTimeout)
+ {
+ ChannelFactory<IOutputChannel> channelFactory =
+ new ChannelFactory<IOutputChannel>(Util.GetBinding(), Queue);
+ IOutputChannel proxy = channelFactory.CreateChannel();
+ IAsyncResult[] resultArray = new IAsyncResult[MessageCount];
+
+ for (int i = 0; i < MessageCount; i++)
+ {
+ Message toSend = Message.CreateMessage(MessageVersion.Default, string.Empty, i);
+ resultArray[i] = proxy.BeginSend(toSend, messageSendTimeout, null, null);
+ }
+
+ for (int j = 0; j < MessageCount; j++)
+ {
+ proxy.EndSend(resultArray[j]);
+ }
+
+ IAsyncResult iocCloseResult = proxy.BeginClose(channelTimeout, null, null);
+ Thread.Sleep(TimeSpan.FromMilliseconds(50.0)); // Dummy work
+ proxy.EndClose(iocCloseResult);
+
+ IAsyncResult chanFactCloseResult = channelFactory.BeginClose(channelTimeout, null, null);
+ Thread.Sleep(TimeSpan.FromMilliseconds(50.0)); // Dummy work
+ channelFactory.EndClose(chanFactCloseResult);
+ }
+
+ private void ReceiveNonTryMessages(TimeSpan channelTimeout, TimeSpan messageTimeout)
+ {
+ IChannelListener inputChannelParentListener;
+ IInputChannel inputChannel = this.RetrieveAsyncChannel(this.endpoint, channelTimeout, out inputChannelParentListener);
+
+ inputChannel.Open();
+
+ IAsyncResult[] resultArray = new IAsyncResult[MessageCount];
+ try
+ {
+ for (int i = 0; i < MessageCount; i++)
+ {
+ resultArray[i] = inputChannel.BeginReceive(messageTimeout, null, null);
+ }
+
+ for (int j = 0; j < MessageCount; j++)
+ {
+ inputChannel.EndReceive(resultArray[j]);
+ }
+ }
+ finally
+ {
+ IAsyncResult channelCloseResult = inputChannel.BeginClose(channelTimeout, null, null);
+ Thread.Sleep(TimeSpan.FromMilliseconds(50.0)); // Dummy work
+ inputChannel.EndClose(channelCloseResult);
+
+ // Asynchronous listener close has not been implemented.
+ ////IAsyncResult listenerCloseResult = inputChannelParentListener.BeginClose(channelTimeout, null, null);
+ ////Thread.Sleep(TimeSpan.FromMilliseconds(50.0)); // Dummy work
+ ////inputChannelParentListener.EndClose(listenerCloseResult);
+
+ inputChannelParentListener.Close();
+ }
+ }
+
+ private void ReceiveTryMessages(TimeSpan channelAcceptTimeout, TimeSpan messageReceiveTimeout)
+ {
+ IChannelListener<IInputChannel> listener = Util.GetBinding().BuildChannelListener<IInputChannel>(this.endpoint, new BindingParameterCollection());
+ listener.Open();
+ IInputChannel inputChannel = listener.AcceptChannel(channelAcceptTimeout);
+ IAsyncResult channelResult = inputChannel.BeginOpen(channelAcceptTimeout, null, null);
+ Thread.Sleep(TimeSpan.FromMilliseconds(50.0));
+ inputChannel.EndOpen(channelResult);
+
+ IAsyncResult[] resultArray = new IAsyncResult[MessageCount];
+
+ for (int i = 0; i < MessageCount; i++)
+ {
+ resultArray[i] = inputChannel.BeginTryReceive(messageReceiveTimeout, null, null);
+ }
+
+ for (int j = 0; j < MessageCount; j++)
+ {
+ Message tempMessage;
+ Assert.True(inputChannel.EndTryReceive(resultArray[j], out tempMessage), "Did not successfully receive message #{0}", j);
+ }
+
+ inputChannel.Close();
+ listener.Close();
+ }
+
+ private IInputChannel RetrieveAsyncChannel(Uri queue, TimeSpan timeout, out IChannelListener parentListener)
+ {
+ IChannelListener<IInputChannel> listener =
+ Util.GetBinding().BuildChannelListener<IInputChannel>(queue, new BindingParameterCollection());
+ listener.Open();
+ IInputChannel inputChannel;
+
+ try
+ {
+ IAsyncResult acceptResult = listener.BeginAcceptChannel(timeout, null, null);
+ Thread.Sleep(TimeSpan.FromMilliseconds(300.0)); // Dummy work
+ inputChannel = listener.EndAcceptChannel(acceptResult);
+ }
+ catch (TimeoutException e)
+ {
+ listener.Close();
+ throw e;
+ }
+ finally
+ {
+ parentListener = listener;
+ }
+ return inputChannel;
+ }
+ }
+}
diff --git a/wcf/test/Apache/Qpid/Test/Channel/Functional/CustomAmqpBindingTest.cs b/wcf/test/Apache/Qpid/Test/Channel/Functional/CustomAmqpBindingTest.cs
new file mode 100644
index 0000000000..45a926ce4d
--- /dev/null
+++ b/wcf/test/Apache/Qpid/Test/Channel/Functional/CustomAmqpBindingTest.cs
@@ -0,0 +1,77 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Test.Channel.Functional
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Reflection;
+ using System.ServiceModel;
+ using System.Threading;
+ using NUnit.Framework;
+
+ [TestFixture]
+ public class CustomAmqpBindingTest
+ {
+ private MessageClient client;
+
+ [SetUp]
+ public void Setup()
+ {
+ // Create client
+ this.client = new MessageClient();
+ this.client.NumberOfMessages = 3;
+ this.client.NumberOfIterations = 3;
+
+ // Setup and start service
+ MessageService.EndpointAddress = "amqp:message_queue";
+ MessageService.ContractTypes = new List<Type>();
+ MessageService.ContractTypes.Add(typeof(IInteropService));
+ MessageService.CompletionHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
+ MessageService.IntendedInvocationCount = this.client.NumberOfIterations * this.client.NumberOfMessages * MessageService.ContractTypes.Count;
+ MessageService.StartService(Util.GetCustomBinding());
+ }
+
+ [Test]
+ public void Run()
+ {
+ // Create the WCF AMQP channel and send messages
+ MethodInfo runClientMethod = this.client.GetType().GetMethod("RunInteropClient");
+ EndpointAddress address = new EndpointAddress("amqp:amq.direct?routingkey=routing_key");
+ foreach (Type contractType in MessageService.ContractTypes)
+ {
+ MethodInfo runClientT = runClientMethod.MakeGenericMethod(contractType);
+ runClientT.Invoke(this.client, new object[] { address });
+ }
+
+ // Allow the WCF service to process all the messages before validation
+ MessageService.CompletionHandle.WaitOne(TimeSpan.FromSeconds(10.0), false);
+
+ // Validation
+ int expectedMethodCallCount = this.client.NumberOfIterations * this.client.NumberOfMessages * MessageService.ContractTypes.Count;
+ Assert.AreEqual(expectedMethodCallCount, MessageService.TotalMethodCallCount);
+ }
+
+ [TearDown]
+ public void Cleanup()
+ {
+ MessageService.StopService();
+ }
+ }
+}
diff --git a/wcf/test/Apache/Qpid/Test/Channel/Functional/FunctionalTests.csproj b/wcf/test/Apache/Qpid/Test/Channel/Functional/FunctionalTests.csproj
new file mode 100644
index 0000000000..d01cd99ff5
--- /dev/null
+++ b/wcf/test/Apache/Qpid/Test/Channel/Functional/FunctionalTests.csproj
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{E2D8C779-E417-40BA-BEE1-EE034268482F}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Apache.Qpid.Test.Channel.Functional</RootNamespace>
+ <AssemblyName>Apache.Qpid.Test.Channel.Functional</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="nunit.framework, Version=2.5.2.9222, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Runtime.Serialization">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="AsyncTest.cs" />
+ <Compile Include="CustomAmqpBindingTest.cs" />
+ <Compile Include="IGenericObjectService.cs" />
+ <Compile Include="IInteropService.cs" />
+ <Compile Include="IQueuedDatagramService1.cs" />
+ <Compile Include="IQueuedDatagramService2.cs" />
+ <Compile Include="IQueuedDatagramService3.cs" />
+ <Compile Include="MessageBodyTest.cs" />
+ <Compile Include="MessagePropertiesTest.cs" />
+ <Compile Include="MultipleEndpointsSameQueueTest.cs" />
+ <Compile Include="MessageClient.cs" />
+ <Compile Include="MessageService.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Util.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\..\..\..\src\Apache\Qpid\Channel\Channel.csproj">
+ <Project>{8AABAB30-7D1E-4539-B7D1-05450262BAD2}</Project>
+ <Name>Channel</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\..\..\..\src\Apache\Qpid\Interop\Interop.vcproj">
+ <Project>{C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}</Project>
+ <Name>Interop</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+ <PropertyGroup>
+ <PostBuildEvent>
+ </PostBuildEvent>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/wcf/test/Apache/Qpid/Test/Channel/Functional/IGenericObjectService.cs b/wcf/test/Apache/Qpid/Test/Channel/Functional/IGenericObjectService.cs
new file mode 100644
index 0000000000..a1ffac50b3
--- /dev/null
+++ b/wcf/test/Apache/Qpid/Test/Channel/Functional/IGenericObjectService.cs
@@ -0,0 +1,30 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Test.Channel.Functional
+{
+ using System.ServiceModel;
+
+ [ServiceContract(SessionMode = SessionMode.NotAllowed)]
+ public interface IGenericObjectService
+ {
+ [OperationContract(IsOneWay = true)]
+ void SendObject(object message);
+ }
+}
diff --git a/wcf/test/Apache/Qpid/Test/Channel/Functional/IInteropService.cs b/wcf/test/Apache/Qpid/Test/Channel/Functional/IInteropService.cs
new file mode 100644
index 0000000000..25f7010a89
--- /dev/null
+++ b/wcf/test/Apache/Qpid/Test/Channel/Functional/IInteropService.cs
@@ -0,0 +1,31 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Test.Channel.Functional
+{
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+
+ [ServiceContract]
+ public interface IInteropService
+ {
+ [OperationContract(IsOneWay = true, Action = "*")]
+ void Hello(Message message);
+ }
+} \ No newline at end of file
diff --git a/wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService1.cs b/wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService1.cs
new file mode 100644
index 0000000000..bdbbb82f7e
--- /dev/null
+++ b/wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService1.cs
@@ -0,0 +1,34 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Test.Channel.Functional
+{
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+
+ [ServiceContract(SessionMode = SessionMode.NotAllowed)]
+ public interface IQueuedDatagramService1
+ {
+ [OperationContract(IsOneWay = true)]
+ void Hello(string message);
+
+ [OperationContract(IsOneWay = true)]
+ void Goodbye();
+ }
+} \ No newline at end of file
diff --git a/wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService2.cs b/wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService2.cs
new file mode 100644
index 0000000000..565f7aa27b
--- /dev/null
+++ b/wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService2.cs
@@ -0,0 +1,34 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Test.Channel.Functional
+{
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+
+ [ServiceContract(SessionMode = SessionMode.NotAllowed)]
+ public interface IQueuedDatagramService2
+ {
+ [OperationContract(IsOneWay = true)]
+ void Hello(string message);
+
+ [OperationContract(IsOneWay = true)]
+ void Goodbye();
+ }
+} \ No newline at end of file
diff --git a/wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService3.cs b/wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService3.cs
new file mode 100644
index 0000000000..3ff2085557
--- /dev/null
+++ b/wcf/test/Apache/Qpid/Test/Channel/Functional/IQueuedDatagramService3.cs
@@ -0,0 +1,33 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Test.Channel.Functional
+{
+ using System.ServiceModel;
+
+ [ServiceContract(SessionMode = SessionMode.NotAllowed)]
+ public interface IQueuedDatagramService3
+ {
+ [OperationContract(IsOneWay = true)]
+ void Hello(string message);
+
+ [OperationContract(IsOneWay = true)]
+ void Goodbye();
+ }
+} \ No newline at end of file
diff --git a/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageBodyTest.cs b/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageBodyTest.cs
new file mode 100644
index 0000000000..3fad6b336d
--- /dev/null
+++ b/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageBodyTest.cs
@@ -0,0 +1,135 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Test.Channel.Functional
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Runtime.Serialization;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using NUnit.Framework;
+
+ [TestFixture]
+ public class MessageBodyTest
+ {
+ private const string Queue = "amqp:amq.direct?routingkey=routing_key";
+
+ [Test]
+ public void DateVariation()
+ {
+ DateTime rightNow = DateTime.UtcNow;
+ this.SendMessage(rightNow);
+ this.ReceiveMessage<DateTime>(rightNow);
+ }
+
+ [Test]
+ public void EmptyStringVariation()
+ {
+ const string TestString = "";
+ this.SendMessage(TestString);
+ this.ReceiveMessage<string>(TestString);
+ }
+
+ [Test]
+ public void IntPrimitiveVariation()
+ {
+ const int TheAnswer = 42;
+ this.SendMessage(TheAnswer);
+ this.ReceiveMessage<int>(TheAnswer);
+ }
+
+ [Test]
+ public void MultipleIntVariation()
+ {
+ const int NumberOfMessages = 20;
+ int[] listOfNumbers = new int[NumberOfMessages];
+
+ for (int i = 0; i < NumberOfMessages; i++)
+ {
+ this.SendMessage(i);
+ listOfNumbers[i] = i;
+ }
+
+ Assert.True(listOfNumbers[NumberOfMessages - 1] != 0, "Not all messages were sent.");
+
+ for (int j = 0; j < NumberOfMessages; j++)
+ {
+ int receivedNumber = this.ReceiveMessage<int>();
+ Assert.True(listOfNumbers[j].Equals(receivedNumber), "Received {0} - this number is unknown or has been received more than once.", receivedNumber);
+ }
+ }
+
+ [Test]
+ public void StringVariation()
+ {
+ const string TestString = "The darkest of dim, dreary days dost draw deathly deeds. どーも";
+ this.SendMessage(TestString);
+ this.ReceiveMessage<string>(TestString);
+ }
+
+ private void SendMessage(object objectToSend)
+ {
+ IChannelFactory<IOutputChannel> channelFactory =
+ Util.GetBinding().BuildChannelFactory<IOutputChannel>();
+ channelFactory.Open();
+ IOutputChannel proxy = channelFactory.CreateChannel(new EndpointAddress(Queue));
+ proxy.Open();
+ Message toSend = Message.CreateMessage(MessageVersion.Default, string.Empty, objectToSend);
+ proxy.Send(toSend);
+ toSend.Close();
+ channelFactory.Close();
+ }
+
+ private TObjectType ReceiveMessage<TObjectType>()
+ {
+ Uri endpoint = new Uri("amqp:message_queue");
+ IChannelListener<IInputChannel> listener = Util.GetBinding().BuildChannelListener<IInputChannel>(endpoint, new BindingParameterCollection());
+ listener.Open();
+ IInputChannel service = listener.AcceptChannel(TimeSpan.FromSeconds(10));
+ service.Open();
+ Message receivedMessage = service.Receive(TimeSpan.FromSeconds(10));
+ Assert.NotNull(receivedMessage, "Message was not received");
+ try
+ {
+ TObjectType receivedObject = receivedMessage.GetBody<TObjectType>();
+ return receivedObject;
+ }
+ catch (SerializationException)
+ {
+ Assert.Fail("Deserialized object not of correct type");
+ }
+ finally
+ {
+ receivedMessage.Close();
+ service.Close();
+ listener.Close();
+ }
+
+ return default(TObjectType);
+ }
+
+ private TObjectType ReceiveMessage<TObjectType>(TObjectType objectToMatch)
+ {
+ TObjectType receivedObject = this.ReceiveMessage<TObjectType>();
+ Assert.True(objectToMatch.Equals(receivedObject), "Original and deserialized objects do not match");
+ return receivedObject;
+ }
+ }
+}
diff --git a/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageClient.cs b/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageClient.cs
new file mode 100644
index 0000000000..8f867551b1
--- /dev/null
+++ b/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageClient.cs
@@ -0,0 +1,101 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Test.Channel.Functional
+{
+ using System;
+ using System.Reflection;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+
+ public class MessageClient
+ {
+ public int NumberOfMessages
+ {
+ get;
+ set;
+ }
+
+ public int NumberOfIterations
+ {
+ get;
+ set;
+ }
+
+ public void RunClient<TServiceContract>(EndpointAddress address)
+ {
+ Binding amqpBinding = Util.GetBinding();
+ Type proxyType = typeof(TServiceContract);
+ MethodInfo helloMethod = proxyType.GetMethod("Hello");
+ MethodInfo goodbyeMethod = proxyType.GetMethod("Goodbye");
+
+ string[] messages = new string[this.NumberOfMessages];
+ for (int i = 0; i < this.NumberOfMessages; ++i)
+ {
+ messages[i] = "Message " + i;
+ }
+
+ for (int i = 0; i < this.NumberOfIterations; ++i)
+ {
+ this.CreateChannelAndSendMessages<TServiceContract>(address, amqpBinding, helloMethod, goodbyeMethod, messages);
+ }
+ }
+
+ public void RunInteropClient<TServiceContract>(EndpointAddress address)
+ {
+ Binding amqpBinding = Util.GetBinding();
+ Type proxyType = typeof(TServiceContract);
+ MethodInfo helloMethod = proxyType.GetMethod("Hello");
+
+ Message[] messages = new Message[this.NumberOfMessages];
+
+ for (int i = 0; i < this.NumberOfIterations; ++i)
+ {
+ this.CreateInteropChannelAndSendMessages<TServiceContract>(address, amqpBinding, helloMethod, this.NumberOfMessages);
+ }
+ }
+
+ private void CreateChannelAndSendMessages<TServiceContract>(EndpointAddress address, Binding amqpBinding, MethodInfo helloMethod, MethodInfo goodbyeMethod, object[] messages)
+ {
+ ChannelFactory<TServiceContract> channelFactory = new ChannelFactory<TServiceContract>(amqpBinding, address);
+ TServiceContract proxy = channelFactory.CreateChannel();
+
+ foreach (object message in messages)
+ {
+ helloMethod.Invoke(proxy, new object[] { message });
+ }
+
+ goodbyeMethod.Invoke(proxy, new object[0]);
+ channelFactory.Close();
+ }
+
+ private void CreateInteropChannelAndSendMessages<TServiceContract>(EndpointAddress address, Binding amqpBinding, MethodInfo helloMethod, int messageCount)
+ {
+ ChannelFactory<TServiceContract> channelFactory = new ChannelFactory<TServiceContract>(amqpBinding, address);
+ TServiceContract proxy = channelFactory.CreateChannel();
+
+ for (int i = 0; i < messageCount; i++)
+ {
+ helloMethod.Invoke(proxy, new object[] { Message.CreateMessage(MessageVersion.Soap12WSAddressing10, "*") });
+ }
+
+ channelFactory.Close();
+ }
+ }
+}
diff --git a/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageProperties.txt b/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageProperties.txt
new file mode 100644
index 0000000000..bd6459ccb9
--- /dev/null
+++ b/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageProperties.txt
@@ -0,0 +1,22 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+ContentType=Text
+Durable=true
+RoutingKey=routing_key
+TimeToLive=00:00:10 \ No newline at end of file
diff --git a/wcf/test/Apache/Qpid/Test/Channel/Functional/MessagePropertiesTest.cs b/wcf/test/Apache/Qpid/Test/Channel/Functional/MessagePropertiesTest.cs
new file mode 100644
index 0000000000..8e192e90f1
--- /dev/null
+++ b/wcf/test/Apache/Qpid/Test/Channel/Functional/MessagePropertiesTest.cs
@@ -0,0 +1,131 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Test.Channel.Functional
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Reflection;
+ using System.Runtime.Serialization;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using Apache.Qpid.AmqpTypes;
+ using NUnit.Framework;
+
+ [TestFixture]
+ public class MessagePropertiesTest
+ {
+ private const string RoutingKey = "routing_key";
+ private const string SendToUri = "amqp:amq.direct?routingkey=" + RoutingKey;
+
+ [Test]
+ public void DefaultAmqpProperties()
+ {
+ const string TestString = "Test Message";
+ AmqpProperties messageProperties = new AmqpProperties();
+
+ this.SendMessage(TestString, messageProperties);
+ this.ReceiveMessage<string>(TestString, messageProperties);
+ }
+
+ [Test]
+ public void NonDefaultAmqpProperties()
+ {
+ const string TestString = "Test Message";
+ AmqpProperties messageProperties = this.CreateMessageProperties();
+
+ this.SendMessage(TestString, messageProperties);
+ this.ReceiveMessage<string>(TestString, messageProperties);
+ }
+
+ private AmqpProperties CreateMessageProperties()
+ {
+ Dictionary<string, string> messageProperties = Util.GetProperties("..\\..\\MessageProperties.txt");
+
+ AmqpProperties amqpProperties = new AmqpProperties();
+ amqpProperties.ContentType = (string)messageProperties["ContentType"];
+ amqpProperties.Durable = Convert.ToBoolean((string)messageProperties["Durable"]);
+ amqpProperties.RoutingKey = (string)messageProperties["RoutingKey"];
+ amqpProperties.TimeToLive = TimeSpan.Parse((string)messageProperties["TimeToLive"]);
+
+ return amqpProperties;
+ }
+
+ private void SendMessage(object objectToSend, AmqpProperties propertiesToSend)
+ {
+ ChannelFactory<IOutputChannel> channelFactory =
+ new ChannelFactory<IOutputChannel>(Util.GetBinding(), SendToUri);
+ IOutputChannel proxy = channelFactory.CreateChannel();
+ proxy.Open();
+
+ Message toSend = Message.CreateMessage(MessageVersion.Default, string.Empty, objectToSend);
+ toSend.Properties["AmqpProperties"] = propertiesToSend;
+ proxy.Send(toSend);
+
+ toSend.Close();
+ proxy.Close();
+ channelFactory.Close();
+ }
+
+ private void ReceiveMessage<TObjectType>(TObjectType objectToMatch, AmqpProperties expectedProperties)
+ {
+ Uri receiveFromUri = new Uri("amqp:message_queue");
+ IChannelListener<IInputChannel> listener = Util.GetBinding().BuildChannelListener<IInputChannel>(receiveFromUri, new BindingParameterCollection());
+ listener.Open();
+ IInputChannel service = listener.AcceptChannel(TimeSpan.FromSeconds(10));
+ service.Open();
+ Message receivedMessage = service.Receive(TimeSpan.FromSeconds(10));
+ try
+ {
+ TObjectType receivedObject = receivedMessage.GetBody<TObjectType>();
+ Assert.True(receivedObject.Equals(objectToMatch), "Original and deserialized objects do not match");
+
+ AmqpProperties receivedProperties = (AmqpProperties)receivedMessage.Properties["AmqpProperties"];
+ PropertyInfo[] propInfo = typeof(AmqpProperties).GetProperties();
+
+ for (int i = 0; i < propInfo.Length; i++)
+ {
+ string propertyName = propInfo[i].Name;
+ if (propertyName.Equals("RoutingKey", StringComparison.InvariantCultureIgnoreCase))
+ {
+ Assert.AreEqual(RoutingKey, Convert.ToString(propInfo[i].GetValue(receivedProperties, null)));
+ }
+ else
+ {
+ Assert.AreEqual(Convert.ToString(propInfo[i].GetValue(expectedProperties, null)), Convert.ToString(propInfo[i].GetValue(receivedProperties, null)));
+ }
+ }
+ }
+ catch (NullReferenceException)
+ {
+ Assert.Fail("Message not received");
+ }
+ catch (SerializationException)
+ {
+ Assert.Fail("Deserialized object not of correct type");
+ }
+ finally
+ {
+ receivedMessage.Close();
+ service.Close();
+ listener.Close();
+ }
+ }
+ }
+}
diff --git a/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageService.cs b/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageService.cs
new file mode 100644
index 0000000000..a473cad986
--- /dev/null
+++ b/wcf/test/Apache/Qpid/Test/Channel/Functional/MessageService.cs
@@ -0,0 +1,158 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Test.Channel.Functional
+{
+ using System;
+ using System.Collections.Generic;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.Threading;
+
+ public class MessageService : IQueuedDatagramService1, IQueuedDatagramService2, IQueuedDatagramService3, IInteropService
+ {
+ private static Dictionary<string, int> methodCallCount = new Dictionary<string, int>();
+ private static ServiceHost serviceHost;
+
+ public static EventWaitHandle CompletionHandle
+ {
+ get;
+ set;
+ }
+
+ public static int IntendedInvocationCount
+ {
+ get;
+ set;
+ }
+
+ public static int TotalMethodCallCount
+ {
+ get;
+ set;
+ }
+
+ // The test must set these paramters
+ public static List<Type> ContractTypes
+ {
+ get;
+ set;
+ }
+
+ public static string EndpointAddress
+ {
+ get;
+ set;
+ }
+
+ public static void DisplayCounts()
+ {
+ Console.WriteLine("Method calls:");
+ foreach (string key in methodCallCount.Keys)
+ {
+ Console.WriteLine(" {0}: {1}", key, methodCallCount[key]);
+ }
+
+ Console.WriteLine("Total: {0}", TotalMethodCallCount);
+ }
+
+ public static void StartService(Binding amqpBinding)
+ {
+ MessageService.methodCallCount.Clear();
+ MessageService.TotalMethodCallCount = 0;
+
+ serviceHost = new ServiceHost(typeof(MessageService));
+
+ foreach (Type contractType in ContractTypes)
+ {
+ serviceHost.AddServiceEndpoint(contractType, amqpBinding, EndpointAddress);
+ }
+
+ serviceHost.Open();
+ }
+
+ public static void StopService()
+ {
+ if (serviceHost.State != CommunicationState.Faulted)
+ {
+ serviceHost.Close();
+ }
+ }
+
+ public void UpdateCounts(string method)
+ {
+ lock (methodCallCount)
+ {
+ if (!methodCallCount.ContainsKey(method))
+ {
+ methodCallCount[method] = 0;
+ }
+
+ ++methodCallCount[method];
+ ++TotalMethodCallCount;
+ if (TotalMethodCallCount >= IntendedInvocationCount && CompletionHandle != null)
+ {
+ CompletionHandle.Set();
+ }
+ }
+ }
+
+ [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
+ void IQueuedDatagramService1.Hello(string message)
+ {
+ this.UpdateCounts("IQueuedDatagramService1.Hello");
+ }
+
+ [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
+ void IQueuedDatagramService1.Goodbye()
+ {
+ this.UpdateCounts("IQueuedDatagramService1.Goodbye");
+ }
+
+ [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
+ void IQueuedDatagramService2.Hello(string message)
+ {
+ this.UpdateCounts("IQueuedDatagramService2.Hello");
+ }
+
+ [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
+ void IQueuedDatagramService2.Goodbye()
+ {
+ this.UpdateCounts("IQueuedDatagramService2.Goodbye");
+ }
+
+ [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
+ void IQueuedDatagramService3.Hello(string message)
+ {
+ this.UpdateCounts("IQueuedDatagramService3.Hello");
+ }
+
+ [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
+ void IQueuedDatagramService3.Goodbye()
+ {
+ this.UpdateCounts("IQueuedDatagramService3.Goodbye");
+ }
+
+ [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
+ void IInteropService.Hello(Message message)
+ {
+ this.UpdateCounts("IInteropService.Hello");
+ }
+ }
+}
diff --git a/wcf/test/Apache/Qpid/Test/Channel/Functional/MultipleEndpointsSameQueueTest.cs b/wcf/test/Apache/Qpid/Test/Channel/Functional/MultipleEndpointsSameQueueTest.cs
new file mode 100644
index 0000000000..d09832757a
--- /dev/null
+++ b/wcf/test/Apache/Qpid/Test/Channel/Functional/MultipleEndpointsSameQueueTest.cs
@@ -0,0 +1,83 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Test.Channel.Functional
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Reflection;
+ using System.ServiceModel;
+ using System.Threading;
+ using NUnit.Framework;
+
+ [TestFixture]
+ public class MultipleEndpointsSameQueueTest
+ {
+ private MessageClient client;
+
+ [SetUp]
+ public void Setup()
+ {
+ // Create client
+ this.client = new MessageClient();
+ this.client.NumberOfMessages = 3;
+ this.client.NumberOfIterations = 5;
+
+ // Setup and start service
+ MessageService.EndpointAddress = "amqp:message_queue";
+
+ MessageService.ContractTypes = new List<Type>();
+ MessageService.ContractTypes.Add(typeof(IQueuedDatagramService1));
+ MessageService.ContractTypes.Add(typeof(IQueuedDatagramService2));
+ MessageService.ContractTypes.Add(typeof(IQueuedDatagramService3));
+ MessageService.CompletionHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
+ MessageService.IntendedInvocationCount = this.client.NumberOfIterations * (this.client.NumberOfMessages + 1) * MessageService.ContractTypes.Count;
+
+ MessageService.StartService(Util.GetBinding());
+ }
+
+ [Test]
+ public void Run()
+ {
+ // Create wcf amqpchannel and send messages
+ MethodInfo runClientMethod = this.client.GetType().GetMethod("RunClient");
+ EndpointAddress address = new EndpointAddress("amqp:amq.direct?routingkey=routing_key");
+
+ foreach (Type contractType in MessageService.ContractTypes)
+ {
+ MethodInfo runClientT = runClientMethod.MakeGenericMethod(contractType);
+ runClientT.Invoke(this.client, new object[] { address });
+ }
+
+ // Allow the wcf service to process all the messages before validation
+ MessageService.CompletionHandle.WaitOne(TimeSpan.FromSeconds(10.0), false);
+
+ // Validation
+ int expectedMethodCallCount = this.client.NumberOfIterations * (this.client.NumberOfMessages + 1) * MessageService.ContractTypes.Count;
+
+ Assert.AreEqual(expectedMethodCallCount, MessageService.TotalMethodCallCount);
+ }
+
+ [TearDown]
+ public void Cleanup()
+ {
+ MessageService.StopService();
+ }
+ }
+}
diff --git a/wcf/test/Apache/Qpid/Test/Channel/Functional/Properties/AssemblyInfo.cs b/wcf/test/Apache/Qpid/Test/Channel/Functional/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..b47a25494f
--- /dev/null
+++ b/wcf/test/Apache/Qpid/Test/Channel/Functional/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Apache.Qpid.Test.Channel.Functional")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("552dca74-b5a3-4ad3-a718-4a1dd03db039")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/wcf/test/Apache/Qpid/Test/Channel/Functional/RunTests.bat b/wcf/test/Apache/Qpid/Test/Channel/Functional/RunTests.bat
new file mode 100755
index 0000000000..a5eed8839b
--- /dev/null
+++ b/wcf/test/Apache/Qpid/Test/Channel/Functional/RunTests.bat
@@ -0,0 +1,34 @@
+@echo OFF
+
+REM Licensed to the Apache Software Foundation (ASF) under one
+REM or more contributor license agreements. See the NOTICE file
+REM distributed with this work for additional information
+REM regarding copyright ownership. The ASF licenses this file
+REM to you under the Apache License, Version 2.0 (the
+REM "License"); you may not use this file except in compliance
+REM with the License. You may obtain a copy of the License at
+REM
+REM http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM Unless required by applicable law or agreed to in writing,
+REM software distributed under the License is distributed on an
+REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+REM KIND, either express or implied. See the License for the
+REM specific language governing permissions and limitations
+REM under the License.
+
+
+set nunit_exe=%programfiles%\NUnit 2.5.1\bin\net-2.0\nunit-console.exe
+set qpid_dll_location=%QPID_BUILD_ROOT%\src\Debug
+set configuration_name=bin\Debug
+set qcreate_location=..\..\..\..\..\..\tools\QCreate\Debug
+
+copy %qpid_dll_location%\qpidclientd.dll %configuration_name%
+copy %qpid_dll_location%\qpidcommond.dll %configuration_name%
+
+copy %qpid_dll_location%\qpidclientd.dll %qcreate_location%
+copy %qpid_dll_location%\qpidcommond.dll %qcreate_location%
+
+%qcreate_location%\QCreate.exe amq.direct routing_key message_queue
+
+"%nunit_exe%" %configuration_name%\Apache.Qpid.Test.Channel.Functional.dll
diff --git a/wcf/test/Apache/Qpid/Test/Channel/Functional/Util.cs b/wcf/test/Apache/Qpid/Test/Channel/Functional/Util.cs
new file mode 100644
index 0000000000..97be1fb925
--- /dev/null
+++ b/wcf/test/Apache/Qpid/Test/Channel/Functional/Util.cs
@@ -0,0 +1,74 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Test.Channel.Functional
+{
+ using System.Collections.Generic;
+ using System.IO;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using Apache.Qpid.Channel;
+
+ internal class Util
+ {
+ public static Dictionary<string, string> GetProperties(string path)
+ {
+ string fileData = string.Empty;
+ using (StreamReader sr = new StreamReader(path))
+ {
+ fileData = sr.ReadToEnd().Replace("\r", string.Empty);
+ }
+
+ Dictionary<string, string> properties = new Dictionary<string, string>();
+ string[] kvp;
+ string[] records = fileData.Split("\n".ToCharArray());
+ foreach (string record in records)
+ {
+ if (record[0] == '/' || record[0] == '*')
+ {
+ continue;
+ }
+
+ kvp = record.Split("=".ToCharArray());
+ properties.Add(kvp[0], kvp[1]);
+ }
+
+ return properties;
+ }
+
+ public static Binding GetBinding()
+ {
+ return new AmqpBinding();
+ }
+
+ public static Binding GetCustomBinding()
+ {
+ AmqpTransportBindingElement transportElement = new AmqpTransportBindingElement();
+ RawMessageEncodingBindingElement encodingElement = new RawMessageEncodingBindingElement();
+ transportElement.BrokerHost = "127.0.0.1";
+ transportElement.TransferMode = TransferMode.Streamed;
+
+ CustomBinding brokerBinding = new CustomBinding();
+ brokerBinding.Elements.Add(encodingElement);
+ brokerBinding.Elements.Add(transportElement);
+
+ return brokerBinding;
+ }
+ }
+}
diff --git a/wcf/test/Apache/Qpid/Test/Channel/WcfPerftest/RawBodyUtility.cs b/wcf/test/Apache/Qpid/Test/Channel/WcfPerftest/RawBodyUtility.cs
new file mode 100644
index 0000000000..55a01c790c
--- /dev/null
+++ b/wcf/test/Apache/Qpid/Test/Channel/WcfPerftest/RawBodyUtility.cs
@@ -0,0 +1,161 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Test.Channel.WcfPerftest
+{
+ using System;
+ using System.Collections;
+ using System.IO;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.ServiceModel.Description;
+ using System.Threading;
+ using System.Text;
+ using System.Xml;
+ using Apache.Qpid.Channel;
+
+
+ /// <summary>
+ /// A sample interface for populating and extracting message body content.
+ /// Just enough methods to handle basic Interop text and raw byte messages.
+ /// </summary>
+
+
+ public interface IRawBodyUtility
+ {
+ Message CreateMessage(byte[] body, int offset, int len);
+ Message CreateMessage(byte[] body);
+ byte[] GetBytes(Message m, byte[] recyclableBuffer);
+
+ Message CreateMessage(string body);
+ string GetText(Message m);
+ }
+
+ // an implementation of IRawBodyUtility that expects a RawMessageEncoder based channel
+
+ public class RawEncoderUtility : IRawBodyUtility
+ {
+ public Message CreateMessage(byte[] body, int offset, int count)
+ {
+ return Message.CreateMessage(MessageVersion.None, "", new RawEncoderBodyWriter(body, offset, count));
+ }
+
+ public Message CreateMessage(byte[] body)
+ {
+ return CreateMessage(body, 0, body.Length);
+ }
+
+ public byte[] GetBytes(Message message, byte[] recyclableBuffer)
+ {
+ XmlDictionaryReader reader = message.GetReaderAtBodyContents();
+ int length;
+
+ while (!reader.HasValue)
+ {
+ reader.Read();
+ if (reader.EOF)
+ {
+ throw new InvalidDataException("empty XmlDictionaryReader");
+ }
+ }
+
+ if (reader.TryGetBase64ContentLength(out length))
+ {
+ byte[] bytes = null;
+ if (recyclableBuffer != null)
+ {
+ if (recyclableBuffer.Length == length)
+ {
+ // reuse
+ bytes = recyclableBuffer;
+ }
+ }
+
+ if (bytes == null)
+ {
+ bytes = new byte[length];
+ }
+
+ // this is the single copy mechanism from native to managed space with no intervening
+ // buffers. One could also write a method GetBytes(msg, myBuf, offset)...
+ reader.ReadContentAsBase64(bytes, 0, length);
+ reader.Close();
+ return bytes;
+ }
+ else
+ {
+ // uses whatever default buffering mechanism is used by the base XmlDictionaryReader class
+ return reader.ReadContentAsBase64();
+ }
+ }
+
+ public Message CreateMessage(string body)
+ {
+ return Message.CreateMessage(MessageVersion.None, "", new RawEncoderBodyWriter(body));
+ }
+
+ public string GetText(Message message)
+ {
+ byte[] rawBuffer = GetBytes(message, null);
+ return Encoding.UTF8.GetString(rawBuffer, 0, rawBuffer.Length);
+ }
+
+ internal class RawEncoderBodyWriter : BodyWriter
+ {
+ // works only with the Raw Encoder; the "body" is either a single string or byte[] segment
+ String bodyAsString;
+ byte[] bodyAsBytes;
+ int offset;
+ int count;
+
+ public RawEncoderBodyWriter(string body)
+ : base(false) // isBuffered
+ {
+ this.bodyAsString = body;
+ }
+
+ public RawEncoderBodyWriter(byte[] body, int offset, int count)
+ : base(false) // isBuffered
+ {
+ this.bodyAsBytes = body;
+ this.offset = offset;
+ this.count = count;
+ }
+
+ protected override void OnWriteBodyContents(System.Xml.XmlDictionaryWriter writer)
+ {
+ // TODO: RawMessageEncoder.StreamElementName should be public.
+ writer.WriteStartElement("Binary"); // the expected Raw encoder "<Binary>" virtual xml tag
+
+ if (bodyAsString != null)
+ {
+ byte[] buf = Encoding.UTF8.GetBytes(bodyAsString);
+ writer.WriteBase64(buf, 0, buf.Length);
+ }
+ else
+ {
+ writer.WriteBase64(this.bodyAsBytes, this.offset, this.count);
+ }
+
+ writer.WriteEndElement();
+ }
+ }
+ }
+
+}
diff --git a/wcf/test/Apache/Qpid/Test/Channel/WcfPerftest/WcfPerftest.cs b/wcf/test/Apache/Qpid/Test/Channel/WcfPerftest/WcfPerftest.cs
new file mode 100644
index 0000000000..992d6e9bd2
--- /dev/null
+++ b/wcf/test/Apache/Qpid/Test/Channel/WcfPerftest/WcfPerftest.cs
@@ -0,0 +1,661 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace Apache.Qpid.Test.Channel.WcfPerftest
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.ComponentModel;
+ using System.Configuration;
+ using System.Diagnostics;
+ using System.IO;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.ServiceModel.Description;
+ using System.Threading;
+ using System.Transactions;
+ using System.Text;
+ using System.Xml;
+ using Apache.Qpid.AmqpTypes;
+ using Apache.Qpid.Channel;
+
+ // this program implements a subset of the functionality in qpid\cpp\src\tests\perftest.cpp
+
+ // for a given broker, create reader and writer channels to queues/exchanges
+ // lazilly creates binding and channel factories
+
+ public class QueueChannelFactory
+ {
+ private static AmqpBinding brokerBinding;
+ private static IChannelFactory<IInputChannel> readerFactory;
+ private static IChannelFactory<IOutputChannel> writerFactory;
+ private static string brokerAddr = "127.0.0.1";
+ private static int brokerPort = 5672;
+
+ public static void SetBroker(string addr, int port)
+ {
+ brokerAddr = addr;
+ brokerPort = port;
+ }
+
+ private static void InitializeBinding()
+ {
+ AmqpBinaryBinding binding = new AmqpBinaryBinding();
+ binding.BrokerHost = brokerAddr;
+ binding.BrokerPort = brokerPort;
+ binding.TransferMode = TransferMode.Streamed;
+ binding.PrefetchLimit = 5000;
+ binding.Shared = true;
+ brokerBinding = binding;
+ }
+
+ public static IInputChannel CreateReaderChannel(string queueName)
+ {
+ lock (typeof(QueueChannelFactory))
+ {
+ if (brokerBinding == null)
+ {
+ InitializeBinding();
+ }
+
+ if (readerFactory == null)
+ {
+ readerFactory = brokerBinding.BuildChannelFactory<IInputChannel>();
+ readerFactory.Open();
+ }
+
+ IInputChannel channel = readerFactory.CreateChannel(new EndpointAddress(
+ new Uri("amqp:" + queueName)));
+ channel.Open();
+
+ return channel;
+ }
+ }
+
+ public static IOutputChannel CreateWriterChannel(string exchangeName, string routingKey)
+ {
+ lock (typeof(QueueChannelFactory))
+ {
+ if (brokerBinding == null)
+ {
+ InitializeBinding();
+ }
+
+ if (writerFactory == null)
+ {
+ writerFactory = brokerBinding.BuildChannelFactory<IOutputChannel>();
+ writerFactory.Open();
+ }
+
+ IOutputChannel channel = writerFactory.CreateChannel(new EndpointAddress(
+ "amqp:" + exchangeName +
+ "?routingkey=" + routingKey));
+ channel.Open();
+
+ return channel;
+ }
+ }
+ }
+
+ public enum ClientType
+ {
+ Publisher,
+ Subscriber,
+ InteropDemo
+ }
+
+ public class Options
+ {
+ public string broker;
+ public int port;
+ public UInt64 messageCount;
+ public int messageSize;
+ public ClientType type;
+ public string baseName;
+ public int subTxSize;
+ public int pubTxSize;
+ public bool durable;
+
+ public Options()
+ {
+ this.broker = "127.0.0.1";
+ this.port = 5672;
+ this.messageCount = 500000;
+ this.messageSize = 1024;
+ this.type = ClientType.InteropDemo; // default: once as pub and once as sub
+ this.baseName = "perftest";
+ this.pubTxSize = 0;
+ this.subTxSize = 0;
+ this.durable = false;
+ }
+
+ public void Parse(string[] args)
+ {
+ int argCount = args.Length;
+ int current = 0;
+ bool typeSelected = false;
+
+ while (current < argCount)
+ {
+ string arg = args[current];
+ if (arg == "--publish")
+ {
+ if (typeSelected)
+ throw new ArgumentException("too many roles");
+
+ this.type = ClientType.Publisher;
+ typeSelected = true;
+ }
+ else if (arg == "--subscribe")
+ {
+ if (typeSelected)
+ throw new ArgumentException("too many roles");
+
+ this.type = ClientType.Subscriber;
+ typeSelected = true;
+ }
+ else if (arg == "--size")
+ {
+ arg = args[++current];
+ int i = int.Parse(arg);
+ if (i > 0)
+ {
+ this.messageSize = i;
+ }
+ }
+ else if (arg == "--count")
+ {
+ arg = args[++current];
+ UInt64 i = UInt64.Parse(arg);
+ if (i > 0)
+ {
+ this.messageCount = i;
+ }
+ }
+ else if (arg == "--broker")
+ {
+ this.broker = args[++current];
+ }
+ else if (arg == "--port")
+ {
+ arg = args[++current];
+ int i = int.Parse(arg);
+ if (i > 0)
+ {
+ this.port = i;
+ }
+ }
+ else if (arg == "--base-name")
+ {
+ this.baseName = args[++current];
+ }
+
+ else if (arg == "--tx")
+ {
+ arg = args[++current];
+ int i = int.Parse(arg);
+ if (i > 0)
+ {
+ this.subTxSize = i;
+ this.pubTxSize = i;
+ }
+ }
+
+ else if (arg == "--durable")
+ {
+ arg = args[++current];
+ if (arg.Equals("yes"))
+ {
+ this.durable = true;
+ }
+ }
+
+ current++;
+ }
+ }
+ }
+
+
+ public class Client
+ {
+ protected Options opts;
+
+ public static void Expect(string actual, string expect)
+ {
+ if (expect != actual)
+ {
+ throw new Exception("Expecting " + expect + " but received " + actual);
+ }
+ }
+
+ public static void Close(IChannel channel)
+ {
+ if (channel == null)
+ {
+ return;
+ }
+
+ try
+ {
+ channel.Close();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("channel close exception {0}", e);
+ }
+ }
+
+ public string Fqn(string name)
+ {
+ return opts.baseName + '_' + name;
+ }
+ }
+
+
+ public class WcfPerftest
+ {
+ static void WarmUpTransactionSubsystem(Options opts)
+ {
+ // see if any use of transactions is expected
+ if ((opts.type == ClientType.Publisher) && (opts.pubTxSize == 0))
+ return;
+
+ if ((opts.type == ClientType.Subscriber) && (opts.subTxSize == 0))
+ return;
+
+ if (opts.type == ClientType.InteropDemo)
+ {
+ if ((opts.subTxSize == 0) && (opts.pubTxSize == 0))
+ return;
+ }
+
+ Console.WriteLine("Initializing transactions");
+ IRawBodyUtility bodyUtil = new RawEncoderUtility();
+
+ // send a transacted message to nowhere to force the initial registration with MSDTC
+ IOutputChannel channel = QueueChannelFactory.CreateWriterChannel("", Guid.NewGuid().ToString());
+ Message msg = bodyUtil.CreateMessage("sacrificial transacted message from WcfPerftest");
+ using (TransactionScope ts = new TransactionScope())
+ {
+ channel.Send(msg);
+ // abort/rollback
+ ts.Dispose();
+ }
+ channel.Close();
+ Console.WriteLine("transaction resource manager ready");
+ }
+
+ static void InteropDemo(Options opts)
+ {
+ string perftest_cpp_exe = "perftest.exe";
+ string commonArgs = String.Format(" --count {0} --size {1}", opts.messageCount, opts.messageSize);
+
+ if (opts.durable)
+ {
+ commonArgs += " --durable yes";
+ }
+
+ Console.WriteLine("===== WCF Subscriber and C++ Publisher =====");
+
+ Process setup = new Process();
+ setup.StartInfo.FileName = perftest_cpp_exe;
+ setup.StartInfo.UseShellExecute = false;
+ setup.StartInfo.Arguments = "--setup" + commonArgs;
+ try
+ {
+ setup.Start();
+ }
+ catch (Win32Exception win32e)
+ {
+ Console.WriteLine("Cannot execute {0}: PATH not set?", perftest_cpp_exe);
+ Console.WriteLine(" Error: {0}", win32e.Message);
+ return;
+ }
+ setup.WaitForExit();
+
+ Process control = new Process();
+ control.StartInfo.FileName = perftest_cpp_exe;
+ control.StartInfo.UseShellExecute = false;
+ control.StartInfo.Arguments = "--control" + commonArgs;
+ control.Start();
+
+ Process publish = new Process();
+ publish.StartInfo.FileName = perftest_cpp_exe;
+ publish.StartInfo.UseShellExecute = false;
+ publish.StartInfo.Arguments = "--publish" + commonArgs;
+ publish.Start();
+
+ SubscribeThread subscribeWcf = new SubscribeThread(opts.baseName + "0", opts);
+ Thread subThread = new Thread(subscribeWcf.Run);
+ subThread.Start();
+
+ subThread.Join();
+ publish.WaitForExit();
+ control.WaitForExit();
+
+ Console.WriteLine();
+ Console.WriteLine("===== WCF Publisher and C++ Subscriber =====");
+
+ setup = new Process();
+ setup.StartInfo.FileName = perftest_cpp_exe;
+ setup.StartInfo.UseShellExecute = false;
+ setup.StartInfo.Arguments = "--setup" + commonArgs;
+ setup.Start();
+ setup.WaitForExit();
+
+ control = new Process();
+ control.StartInfo.FileName = perftest_cpp_exe;
+ control.StartInfo.UseShellExecute = false;
+ control.StartInfo.Arguments = "--control" + commonArgs;
+ control.Start();
+
+ PublishThread pub = new PublishThread(opts.baseName + "0", "", opts);
+ Thread pubThread = new Thread(pub.Run);
+ pubThread.Start();
+
+ Process subscribeCpp = new Process();
+ subscribeCpp.StartInfo.FileName = perftest_cpp_exe;
+ subscribeCpp.StartInfo.UseShellExecute = false;
+ subscribeCpp.StartInfo.Arguments = "--subscribe" + commonArgs;
+ subscribeCpp.Start();
+
+ subscribeCpp.WaitForExit();
+ pubThread.Join();
+ control.WaitForExit();
+ }
+
+ static void Main(string[] mainArgs)
+ {
+ Options opts = new Options();
+ opts.Parse(mainArgs);
+ QueueChannelFactory.SetBroker(opts.broker, opts.port);
+
+ WarmUpTransactionSubsystem(opts);
+
+ if (opts.type == ClientType.Publisher)
+ {
+ PublishThread pub = new PublishThread(opts.baseName + "0", "", opts);
+ Thread pubThread = new Thread(pub.Run);
+ pubThread.Start();
+ pubThread.Join();
+ }
+ else if (opts.type == ClientType.Subscriber)
+ {
+ SubscribeThread sub = new SubscribeThread(opts.baseName + "0", opts);
+ Thread subThread = new Thread(sub.Run);
+ subThread.Start();
+ subThread.Join();
+ }
+ else
+ {
+ InteropDemo(opts);
+ }
+
+ if (System.Diagnostics.Debugger.IsAttached)
+ {
+ Console.WriteLine("Hit return to continue...");
+ Console.ReadLine();
+ }
+ }
+ }
+
+ public class PublishThread : Client
+ {
+ string destination; // exchange/queue
+ string routingKey;
+ int msgSize;
+ UInt64 msgCount;
+ IOutputChannel publishQueue;
+
+ public PublishThread(string key, string q, Options opts)
+ {
+ this.routingKey = key;
+ this.destination = q;
+ this.msgSize = opts.messageSize;
+ this.msgCount = opts.messageCount;
+ this.opts = opts;
+ }
+
+ static void StampSequenceNo(byte[] data, UInt64 n)
+ {
+ int wordLen = IntPtr.Size; // mimic size_t in C++
+
+ if (data.Length < wordLen)
+ throw new ArgumentException("message size");
+ for (int i = 0; i < wordLen; i++)
+ {
+ data[i] = (byte) (n & 0xff);
+ n >>= 8;
+ }
+ }
+
+ public void Run()
+ {
+ IRawBodyUtility bodyUtil = new RawEncoderUtility();
+
+ IInputChannel startQueue = null;
+ IOutputChannel doneQueue = null;
+ UInt64 batchSize = (UInt64)opts.pubTxSize;
+ bool txPending = false;
+ AmqpProperties amqpProperties = null;
+
+ if (opts.durable)
+ {
+ amqpProperties = new AmqpProperties();
+ amqpProperties.Durable = true;
+ }
+
+ try
+ {
+ publishQueue = QueueChannelFactory.CreateWriterChannel(this.destination, this.routingKey);
+ doneQueue = QueueChannelFactory.CreateWriterChannel("", this.Fqn("pub_done"));
+ startQueue = QueueChannelFactory.CreateReaderChannel(this.Fqn("pub_start"));
+
+ // wait for our start signal
+ Message msg;
+ msg = startQueue.Receive(TimeSpan.MaxValue);
+ Expect(bodyUtil.GetText(msg), "start");
+ msg.Close();
+
+ Stopwatch stopwatch = new Stopwatch();
+ AsyncCallback sendCallback = new AsyncCallback(this.AsyncSendCB);
+
+ byte[] data = new byte[this.msgSize];
+ IAsyncResult sendResult = null;
+
+ Console.WriteLine("sending {0}", this.msgCount);
+ stopwatch.Start();
+
+ if (batchSize > 0)
+ {
+ Transaction.Current = new CommittableTransaction();
+ }
+
+ for (UInt64 i = 0; i < this.msgCount; i++)
+ {
+ StampSequenceNo(data, i);
+ msg = bodyUtil.CreateMessage(data);
+ if (amqpProperties != null)
+ {
+ msg.Properties.Add("AmqpProperties", amqpProperties);
+ }
+
+ sendResult = publishQueue.BeginSend(msg, TimeSpan.MaxValue, sendCallback, msg);
+
+ if (batchSize > 0)
+ {
+ txPending = true;
+ if (((i + 1) % batchSize) == 0)
+ {
+ ((CommittableTransaction)Transaction.Current).Commit();
+ txPending = false;
+ Transaction.Current = new CommittableTransaction();
+ }
+ }
+ }
+
+ if (txPending)
+ {
+ ((CommittableTransaction)Transaction.Current).Commit();
+ }
+
+ Transaction.Current = null;
+
+ sendResult.AsyncWaitHandle.WaitOne();
+ stopwatch.Stop();
+
+ double mps = (msgCount / stopwatch.Elapsed.TotalSeconds);
+
+ msg = bodyUtil.CreateMessage(String.Format("{0:0.##}", mps));
+ doneQueue.Send(msg, TimeSpan.MaxValue);
+ msg.Close();
+ }
+ finally
+ {
+ Close((IChannel)doneQueue);
+ Close((IChannel)publishQueue);
+ Close(startQueue);
+ }
+ }
+
+ void AsyncSendCB(IAsyncResult result)
+ {
+ publishQueue.EndSend(result);
+ ((Message)result.AsyncState).Close();
+ }
+ }
+
+ public class SubscribeThread : Client
+ {
+ string queue;
+ int msgSize;
+ UInt64 msgCount;
+ IInputChannel subscribeQueue;
+
+ public SubscribeThread(string q, Options opts)
+ {
+ this.queue = q;
+ this.msgSize = opts.messageSize;
+ this.msgCount = opts.messageCount;
+ this.opts = opts;
+ }
+
+ static UInt64 GetSequenceNumber(byte[] data)
+ {
+ int wordLen = IntPtr.Size; // mimic size_t in C++
+
+ if (data.Length < wordLen)
+ throw new ArgumentException("message size");
+ UInt64 n = 0;
+ for (int i = (wordLen - 1); i >= 0; i--)
+ {
+ n = (256 * n) + data[i];
+ }
+ return n;
+ }
+
+ public void Run()
+ {
+ IRawBodyUtility bodyUtil = new RawEncoderUtility();
+
+ IOutputChannel readyQueue = null;
+ IOutputChannel doneQueue = null;
+ UInt64 batchSize = (UInt64)opts.subTxSize;
+ bool txPending = false;
+ byte[] data = null;
+
+ try
+ {
+ this.subscribeQueue = QueueChannelFactory.CreateReaderChannel(this.queue);
+ readyQueue = QueueChannelFactory.CreateWriterChannel("", this.Fqn("sub_ready"));
+ doneQueue = QueueChannelFactory.CreateWriterChannel("", this.Fqn("sub_done"));
+
+ Message msg = bodyUtil.CreateMessage("ready");
+ readyQueue.Send(msg, TimeSpan.MaxValue);
+ msg.Close();
+
+
+ Stopwatch stopwatch = new Stopwatch();
+ stopwatch.Start();
+
+ Console.WriteLine("receiving {0}", this.msgCount);
+ UInt64 expect = 0;
+
+ if (batchSize > 0)
+ {
+ Transaction.Current = new CommittableTransaction();
+ }
+
+ for (UInt64 i = 0; i < this.msgCount; i++)
+ {
+ msg = subscribeQueue.Receive(TimeSpan.MaxValue);
+
+ data = bodyUtil.GetBytes(msg, data);
+ msg.Close();
+ if (data.Length != this.msgSize)
+ {
+ throw new Exception("subscribe message size mismatch");
+ }
+
+ UInt64 n = GetSequenceNumber(data);
+ if (n != expect)
+ {
+ throw new Exception(String.Format("message sequence error. expected {0} got {1}", expect, n));
+ }
+ expect = n + 1;
+
+ if (batchSize > 0)
+ {
+ txPending = true;
+ if (((i + 1) % batchSize) == 0)
+ {
+ ((CommittableTransaction)Transaction.Current).Commit();
+ txPending = false;
+ Transaction.Current = new CommittableTransaction();
+ }
+ }
+ }
+
+ if (txPending)
+ {
+ ((CommittableTransaction)Transaction.Current).Commit();
+ }
+
+ Transaction.Current = null;
+
+ stopwatch.Stop();
+
+ double mps = (msgCount / stopwatch.Elapsed.TotalSeconds);
+
+ msg = bodyUtil.CreateMessage(String.Format("{0:0.##}", mps));
+ doneQueue.Send(msg, TimeSpan.MaxValue);
+ msg.Close();
+
+ subscribeQueue.Close();
+ }
+ finally
+ {
+ Close((IChannel)doneQueue);
+ Close((IChannel)this.subscribeQueue);
+ Close(readyQueue);
+ }
+ }
+ }
+}
diff --git a/wcf/test/Apache/Qpid/Test/Channel/WcfPerftest/WcfPerftest.csproj b/wcf/test/Apache/Qpid/Test/Channel/WcfPerftest/WcfPerftest.csproj
new file mode 100644
index 0000000000..44ef998a24
--- /dev/null
+++ b/wcf/test/Apache/Qpid/Test/Channel/WcfPerftest/WcfPerftest.csproj
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{D0F8FDE4-7AC6-4CFF-986A-50D06F7FD733}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <RootNamespace>Apache.Qpid.Test.Channel.WcfPerftest</RootNamespace>
+ <AssemblyName>WcfPerftest</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Runtime.Serialization">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Transactions" />
+ <Reference Include="System.XML" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="WcfPerftest.cs" />
+ <Compile Include="RawBodyUtility.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\..\..\..\src\Apache\Qpid\Channel\Channel.csproj">
+ <Project>{8AABAB30-7D1E-4539-B7D1-05450262BAD2}</Project>
+ <Name>Channel</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\..\..\..\src\Apache\Qpid\Interop\Interop.vcproj">
+ <Project>{C9B6AC75-6332-47A4-B82B-0C20E0AF2D34}</Project>
+ <Name>Interop</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/wcf/tools/QCreate/QCreate.cpp b/wcf/tools/QCreate/QCreate.cpp
new file mode 100644
index 0000000000..7b0231f339
--- /dev/null
+++ b/wcf/tools/QCreate/QCreate.cpp
@@ -0,0 +1,65 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#include "stdafx.h"
+
+#include <qpid/client/Connection.h>
+#include <qpid/client/Session.h>
+
+#include <cstdlib>
+#include <iostream>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+
+
+int main(int argc, char** argv) {
+
+ std::string exchange = argc>1 ? argv[1] : "amq.direct";
+ std::string bindingKey = argc>2 ? argv[2] : "routing_key";
+ std::string queue = argc>3 ? argv[3] : "message_queue";
+
+ const char* host = "127.0.0.1";
+ int port = 5672;
+ Connection connection;
+
+ try {
+ connection.open(host, port);
+ Session session = connection.newSession();
+
+
+ //--------- Main body of program --------------------------------------------
+
+ // Create a queue and route all messages whose
+ // routing key is "routing_key" to this newly created queue.
+
+ session.queueDeclare(arg::queue=queue);
+ session.exchangeBind(arg::exchange=exchange, arg::queue=queue, arg::bindingKey=bindingKey);
+
+ //-----------------------------------------------------------------------------
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+
+}
+
diff --git a/wcf/tools/QCreate/QCreate.sln b/wcf/tools/QCreate/QCreate.sln
new file mode 100644
index 0000000000..c01675d53a
--- /dev/null
+++ b/wcf/tools/QCreate/QCreate.sln
@@ -0,0 +1,40 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual C++ Express 2008
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License
+#
+
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QCreate", "QCreate.vcproj", "{7CA88318-485A-4D95-A321-43DFBB6EA28B}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7CA88318-485A-4D95-A321-43DFBB6EA28B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7CA88318-485A-4D95-A321-43DFBB6EA28B}.Debug|Win32.Build.0 = Debug|Win32
+ {7CA88318-485A-4D95-A321-43DFBB6EA28B}.Release|Win32.ActiveCfg = Release|Win32
+ {7CA88318-485A-4D95-A321-43DFBB6EA28B}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/wcf/tools/QCreate/QCreate.vcproj b/wcf/tools/QCreate/QCreate.vcproj
new file mode 100644
index 0000000000..ba77952966
--- /dev/null
+++ b/wcf/tools/QCreate/QCreate.vcproj
@@ -0,0 +1,232 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="QCreate"
+ ProjectGUID="{7CA88318-485A-4D95-A321-43DFBB6EA28B}"
+ RootNamespace="QCreate"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="&quot;$(BOOST_ROOT)\include\$(BOOST_VERSION)&quot;;&quot;$(BOOST_ROOT)\.&quot;;..\..\..\cpp\include;&quot;$(QPID_BUILD_ROOT)\include&quot;"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="qpidcommond.lib qpidclientd.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories=".;&quot;$(BOOST_ROOT)\lib&quot;;&quot;$(QPID_BUILD_ROOT)\src\Debug&quot;"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\QCreate.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\stdafx.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\stdafx.h"
+ >
+ </File>
+ <File
+ RelativePath=".\targetver.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ <File
+ RelativePath=".\ReadMe.txt"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/wcf/tools/QCreate/ReadMe.txt b/wcf/tools/QCreate/ReadMe.txt
new file mode 100644
index 0000000000..b3efb84503
--- /dev/null
+++ b/wcf/tools/QCreate/ReadMe.txt
@@ -0,0 +1,52 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+========================================================================
+ CONSOLE APPLICATION : QCreate Project Overview
+========================================================================
+
+AppWizard has created this QCreate application for you.
+
+This file contains a summary of what you will find in each of the files that
+make up your QCreate application.
+
+
+QCreate.vcproj
+ This is the main project file for VC++ projects generated using an Application Wizard.
+ It contains information about the version of Visual C++ that generated the file, and
+ information about the platforms, configurations, and project features selected with the
+ Application Wizard.
+
+QCreate.cpp
+ This is the main application source file.
+
+/////////////////////////////////////////////////////////////////////////////
+Other standard files:
+
+StdAfx.h, StdAfx.cpp
+ These files are used to build a precompiled header (PCH) file
+ named QCreate.pch and a precompiled types file named StdAfx.obj.
+
+/////////////////////////////////////////////////////////////////////////////
+Other notes:
+
+AppWizard uses "TODO:" comments to indicate parts of the source code you
+should add to or customize.
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/wcf/tools/QCreate/stdafx.cpp b/wcf/tools/QCreate/stdafx.cpp
new file mode 100644
index 0000000000..568cd3b7d6
--- /dev/null
+++ b/wcf/tools/QCreate/stdafx.cpp
@@ -0,0 +1,27 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+// stdafx.cpp : source file that includes just the standard includes
+// QCreate.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/wcf/tools/QCreate/stdafx.h b/wcf/tools/QCreate/stdafx.h
new file mode 100644
index 0000000000..a516e19a10
--- /dev/null
+++ b/wcf/tools/QCreate/stdafx.h
@@ -0,0 +1,34 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#include "targetver.h"
+
+#include <stdio.h>
+#include <tchar.h>
+
+
+
+// TODO: reference additional headers your program requires here
diff --git a/wcf/tools/QCreate/targetver.h b/wcf/tools/QCreate/targetver.h
new file mode 100644
index 0000000000..9cfb78641b
--- /dev/null
+++ b/wcf/tools/QCreate/targetver.h
@@ -0,0 +1,32 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#pragma once
+
+// The following macros define the minimum required platform. The minimum required platform
+// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
+// your application. The macros work by enabling all features available on platform versions up to and
+// including the version specified.
+
+// Modify the following defines if you have to target a platform prior to the ones specified below.
+// Refer to MSDN for the latest info on corresponding values for different platforms.
+#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
+#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
+#endif
+